From 0b83862fc29012effdba3147a4b3eb6d1b40984c Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Tue, 28 Mar 2017 18:28:30 +0200 Subject: [PATCH 001/284] uplink proto --- .../MESSAGES/V2/controller_commands.proto | 11 +++++-- openair2/ENB_APP/MESSAGES/V2/flexran.proto | 13 ++++++-- .../ENB_APP/MESSAGES/V2/mac_primitives.proto | 31 +++++++++++++++++++ 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto b/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto index cbec332b30..98ca6b8bee 100644 --- a/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto +++ b/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto @@ -3,7 +3,7 @@ package protocol; import "mac_primitives.proto"; // -// Body of UE DL MAC scheduling configuration info +// Body of UE DL/UL MAC scheduling configuration info // message flex_dl_data { @@ -15,6 +15,13 @@ message flex_dl_data { optional uint32 act_deact_ce = 6; //Hex content of MAC CE for Activation/Deactivation in CA } + +message flex_ul_data { + optional uint32 rnti = 1; + optional flex_ul_dci dl_dci = 2; + +} + // // Body of the RAR scheduler configuration // @@ -55,4 +62,4 @@ message flex_pdcch_ofdm_sym_count { enum flex_broadcast_type { FLBT_BCCH = 0; FLBT_PCCH = 1; -} \ No newline at end of file +} diff --git a/openair2/ENB_APP/MESSAGES/V2/flexran.proto b/openair2/ENB_APP/MESSAGES/V2/flexran.proto index 3a1d40bca6..ffd58daaae 100644 --- a/openair2/ENB_APP/MESSAGES/V2/flexran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/flexran.proto @@ -25,9 +25,10 @@ message flexran_message { flex_lc_config_request lc_config_request_msg = 12; flex_lc_config_reply lc_config_reply_msg = 13; flex_dl_mac_config dl_mac_config_msg = 14; - flex_ue_state_change ue_state_change_msg = 15; - flex_control_delegation control_delegation_msg = 16; - flex_agent_reconfiguration agent_reconfiguration_msg = 17; + flex_ul_mac_config ul_mac_config_msg = 15 + flex_ue_state_change ue_state_change_msg = 16; + flex_control_delegation control_delegation_msg = 17; + flex_agent_reconfiguration agent_reconfiguration_msg = 18; } } @@ -163,6 +164,12 @@ message flex_dl_mac_config { repeated flex_pdcch_ofdm_sym_count ofdm_sym = 6; // OFDM symbol count for each CC } +message flex_ul_mac_config { + optional flex_header header = 1; + optional uint32 sfn_sf = 2; + repeated flex_ul_data ul_ue_data = 3; +} + // // UE state change message // diff --git a/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto b/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto index be7c72ab7b..3b3bc4e912 100644 --- a/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto +++ b/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto @@ -35,6 +35,37 @@ message flex_dl_dci { optional uint32 cif = 27; // CIF for cross-carrier scheduling } +message flex_ul_dci { + optional uint32 rnti = 1; + optional uint32 res_alloc = 2; // Type of resource allocation + optional uint32 rb_bitmap = 3; // Bitmap for RB allocation + optional uint32 rb_shift = 4; // See TS 36.214, section 7.1.6.2 + repeated uint32 tbs_size = 5; // The size of each TBS + repeated uint32 mcs = 6; // The MCS of each TB + repeated uint32 ndi = 7; // New data indicator of each TB + //repeated uint32 rv = 8; // Redundancy version of each TB + //optional uint32 cce_index = 9; // CCE index used to send the DCI + //optional uint32 aggr_level = 10; + //optional uint32 precoding_info = 11; // 2 antenna ports:0..6, + // 4 antenna ports:0..50 + optional uint32 format = 12; // DCI format. A FLDCIF_* value + optional uint32 tpc = 13; // TS 36.213, sec 5.1.1.1 + optional uint32 harq_process = 14; // HARQ process ID + optional uint32 dai = 15; // TDD only + //optional uint32 vrb_format = 16; // One of the FLVRBF_* values + optional uint32 tb_swap = 17; // Boolean. TB to codeword swap flag + //optional uint32 sps_release = 18; // Flag value + optional uint32 pdcch_order = 19; +// optional uint32 preamble_index = 20; // Only valid if pdcch_order = 1 + optional uint32 prach_mask_index = 21; // Only valid if pdcch_order = 1 + optional uint32 n_gap = 22; // One of the FLNGV_* values + optional uint32 tbs_idx = 23; // The TBS index for Format 1A + optional uint32 dl_power_offset = 24; // For format 1D +// optional uint32 pdcch_power_offset = 25; // DL PDCCH power boosting in dB +// optional uint32 cif_present = 26; // Boolean. Indication of CIF field +// optional uint32 cif = 27; // CIF for cross-carrier scheduling +} + // // Messages related to the creation of RLC PDUs // From 1a516df2db06892732fd6663e84abcbf6e18b195 Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Fri, 31 Mar 2017 16:40:26 +0200 Subject: [PATCH 002/284] proto uplink mac --- .../ENB_APP/MESSAGES/V2/mac_primitives.proto | 61 +++++++++++-------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto b/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto index 3b3bc4e912..ecc82f116c 100644 --- a/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto +++ b/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto @@ -36,34 +36,39 @@ message flex_dl_dci { } message flex_ul_dci { + optional uint32 handle = 1; + optional uint32 size = 2; // Size of the ULSCH PDU in bytes for UL Grant. optional uint32 rnti = 1; - optional uint32 res_alloc = 2; // Type of resource allocation + optional uint32 res_block_start = 2; // match DCI format 0 PDU optional uint32 rb_bitmap = 3; // Bitmap for RB allocation - optional uint32 rb_shift = 4; // See TS 36.214, section 7.1.6.2 - repeated uint32 tbs_size = 5; // The size of each TBS - repeated uint32 mcs = 6; // The MCS of each TB - repeated uint32 ndi = 7; // New data indicator of each TB - //repeated uint32 rv = 8; // Redundancy version of each TB - //optional uint32 cce_index = 9; // CCE index used to send the DCI - //optional uint32 aggr_level = 10; - //optional uint32 precoding_info = 11; // 2 antenna ports:0..6, - // 4 antenna ports:0..50 + optional uint32 modulation_t = 4; // A FLMOD_* Value + optional uint32 cyclic_shift2 = 5; // match DCI format 0/4 PDU + optional uint32 freq_hop_flag = 6; // 0 no hopping, 1 hoppping + optional uint32 freq_hop_map = 8; // match DCI format 0 PDU + optional uint32 ndi = 7; // New data indicator of each TB + optional uint32 rv = 8; // Redundancy version of each TB + optional uint32 harq_process_number = 14; // A FLHARQ_* value + optional uint32 ultx_mode = 14; // A FLULM_* value + repeated uint32 tbs_size = 5; // The size of each TBS + repeated uint32 current_harq = 9; // CCE index used to send the DCI + optional uint32 n_srs = 10; // Over lap indication with srs + optional uint32 res_alloc = 2; // Type of resource allocation optional uint32 format = 12; // DCI format. A FLDCIF_* value - optional uint32 tpc = 13; // TS 36.213, sec 5.1.1.1 - optional uint32 harq_process = 14; // HARQ process ID - optional uint32 dai = 15; // TDD only - //optional uint32 vrb_format = 16; // One of the FLVRBF_* values - optional uint32 tb_swap = 17; // Boolean. TB to codeword swap flag - //optional uint32 sps_release = 18; // Flag value - optional uint32 pdcch_order = 19; + + +// optional uint32 dai = 15; // TDD only + +// optional uint32 tb_swap = 17; // Boolean. TB to codeword swap flag + +// optional uint32 pdcch_order = 19; // optional uint32 preamble_index = 20; // Only valid if pdcch_order = 1 - optional uint32 prach_mask_index = 21; // Only valid if pdcch_order = 1 - optional uint32 n_gap = 22; // One of the FLNGV_* values - optional uint32 tbs_idx = 23; // The TBS index for Format 1A - optional uint32 dl_power_offset = 24; // For format 1D -// optional uint32 pdcch_power_offset = 25; // DL PDCCH power boosting in dB -// optional uint32 cif_present = 26; // Boolean. Indication of CIF field -// optional uint32 cif = 27; // CIF for cross-carrier scheduling +// optional uint32 prach_mask_index = 21; // Only valid if pdcch_order = 1 + +// optional uint32 tbs_idx = 23; // The TBS index for Format 1A + + + + } // @@ -104,4 +109,10 @@ enum flex_vrb_format { enum flex_ngap_val { FLNGV_1 = 0; FLNGV_2 = 1; -} \ No newline at end of file +} + +enum flex_mod_type { + FLMOD_QPSK = 2; + FLMOD_16QAM = 4; + FLMOD_64QAM = 6; +} From a08178fa0e53f45dc2002ee8036c81192555e5ce Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 4 Apr 2017 21:11:16 +0000 Subject: [PATCH 003/284] Made modifications to UL scheduling messages --- .../MESSAGES/V2/controller_commands.proto | 3 +- openair2/ENB_APP/MESSAGES/V2/flexran.proto | 12 +++---- .../ENB_APP/MESSAGES/V2/mac_primitives.proto | 34 ++++++++----------- 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto b/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto index 98ca6b8bee..252efc6aef 100644 --- a/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto +++ b/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto @@ -18,8 +18,7 @@ message flex_dl_data { message flex_ul_data { optional uint32 rnti = 1; - optional flex_ul_dci dl_dci = 2; - + optional flex_ul_dci ul_dci = 2; } // diff --git a/openair2/ENB_APP/MESSAGES/V2/flexran.proto b/openair2/ENB_APP/MESSAGES/V2/flexran.proto index ffd58daaae..f49b69f4ad 100644 --- a/openair2/ENB_APP/MESSAGES/V2/flexran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/flexran.proto @@ -25,10 +25,10 @@ message flexran_message { flex_lc_config_request lc_config_request_msg = 12; flex_lc_config_reply lc_config_reply_msg = 13; flex_dl_mac_config dl_mac_config_msg = 14; - flex_ul_mac_config ul_mac_config_msg = 15 - flex_ue_state_change ue_state_change_msg = 16; - flex_control_delegation control_delegation_msg = 17; - flex_agent_reconfiguration agent_reconfiguration_msg = 18; + flex_ul_mac_config ul_mac_config_msg = 18; + flex_ue_state_change ue_state_change_msg = 15; + flex_control_delegation control_delegation_msg = 16; + flex_agent_reconfiguration agent_reconfiguration_msg = 17; } } @@ -166,8 +166,8 @@ message flex_dl_mac_config { message flex_ul_mac_config { optional flex_header header = 1; - optional uint32 sfn_sf = 2; - repeated flex_ul_data ul_ue_data = 3; + optional uint32 sfn_sf = 2; + repeated flex_ul_data ul_ue_data = 3; } // diff --git a/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto b/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto index ecc82f116c..01f8799a17 100644 --- a/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto +++ b/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto @@ -36,27 +36,23 @@ message flex_dl_dci { } message flex_ul_dci { - optional uint32 handle = 1; - optional uint32 size = 2; // Size of the ULSCH PDU in bytes for UL Grant. optional uint32 rnti = 1; - optional uint32 res_block_start = 2; // match DCI format 0 PDU - optional uint32 rb_bitmap = 3; // Bitmap for RB allocation - optional uint32 modulation_t = 4; // A FLMOD_* Value - optional uint32 cyclic_shift2 = 5; // match DCI format 0/4 PDU - optional uint32 freq_hop_flag = 6; // 0 no hopping, 1 hoppping - optional uint32 freq_hop_map = 8; // match DCI format 0 PDU - optional uint32 ndi = 7; // New data indicator of each TB - optional uint32 rv = 8; // Redundancy version of each TB - optional uint32 harq_process_number = 14; // A FLHARQ_* value - optional uint32 ultx_mode = 14; // A FLULM_* value - repeated uint32 tbs_size = 5; // The size of each TBS - repeated uint32 current_harq = 9; // CCE index used to send the DCI - optional uint32 n_srs = 10; // Over lap indication with srs - optional uint32 res_alloc = 2; // Type of resource allocation - optional uint32 format = 12; // DCI format. A FLDCIF_* value + optional uint32 rb_start = 2; // The start RB allocated to the UE + optional uint32 rb_len = 3; // The number of RBs allocated to the UE + optional uint32 mcs = 4; // Modulation and coding scheme + optional uint32 cyclic_shift2 = 5; // match DCI format 0/4 PDU + optional uint32 freq_hop_flag = 6; // 0 no hopping, 1 hoppping + optional uint32 freq_hop_map = 7; // Frequency hopping bits (0..4) + optional uint32 ndi = 8; // New data indicator + optional uint32 rv = 9; // Redundancy version + optional uint32 harq_pid = 10; // The harq process id + optional uint32 ultx_mode = 11; // A FLULM_* value + optional uint32 tbs_size = 12; // The size of each TBS + optional uint32 n_srs = 13; // Overlap indication with srs + optional uint32 res_alloc = 14; // Type of resource allocation + optional uint32 size = 15; // Size of the ULSCH PDU in bytes for UL Grant. - -// optional uint32 dai = 15; // TDD only + optional uint32 dai = 16; // TDD only // optional uint32 tb_swap = 17; // Boolean. TB to codeword swap flag From 4cfa87b6b3854285359f4155f60b04d41ee20a07 Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Wed, 5 Apr 2017 10:38:36 +0200 Subject: [PATCH 004/284] downlink throughput enhancement --- cmake_targets/CMakeLists.txt | 4 + .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 1233 ++++++---------- .../CONTROL_MODULES/MAC/flexran_agent_mac.h | 44 +- .../MAC/flexran_agent_mac_internal.c | 10 +- .../CONTROL_MODULES/RRC/flexran_agent_rrc.c | 662 +++++++++ .../CONTROL_MODULES/RRC/flexran_agent_rrc.h | 74 + .../RRC/flexran_agent_rrc_defs.h | 62 + openair2/ENB_APP/MESSAGES/V2/flexran.proto | 8 + openair2/ENB_APP/MESSAGES/V2/header.proto | 2 + .../ENB_APP/MESSAGES/V2/stats_common.proto | 60 + .../ENB_APP/MESSAGES/V2/stats_messages.proto | 6 +- openair2/ENB_APP/enb_config.c | 81 +- openair2/ENB_APP/enb_config.h | 4 + openair2/ENB_APP/flexran_agent.c | 24 +- openair2/ENB_APP/flexran_agent.h | 12 +- openair2/ENB_APP/flexran_agent_common.c | 1296 +---------------- openair2/ENB_APP/flexran_agent_common.h | 395 +---- openair2/ENB_APP/flexran_agent_defs.h | 83 +- openair2/ENB_APP/flexran_agent_extern.h | 16 +- openair2/ENB_APP/flexran_agent_handler.c | 580 +++++++- openair2/ENB_APP/flexran_agent_ran_api.c | 929 ++++++++++++ openair2/ENB_APP/flexran_agent_ran_api.h | 290 ++++ openair2/ENB_APP/flexran_agent_timer.c | 217 +++ openair2/ENB_APP/flexran_agent_timer.h | 133 ++ openair2/LAYER2/MAC/eNB_scheduler.c | 20 +- .../LAYER2/MAC/eNB_scheduler_primitives.c | 10 + openair2/RRC/LITE/rrc_eNB.c | 665 ++++++++- 27 files changed, 4388 insertions(+), 2532 deletions(-) create mode 100644 openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c create mode 100644 openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h create mode 100644 openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h create mode 100644 openair2/ENB_APP/flexran_agent_ran_api.c create mode 100644 openair2/ENB_APP/flexran_agent_ran_api.h create mode 100644 openair2/ENB_APP/flexran_agent_timer.c create mode 100644 openair2/ENB_APP/flexran_agent_timer.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 94a88c095b..5413014fbf 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -820,6 +820,7 @@ include_directories("${OPENAIR_DIR}/targets/ARCH/EXMIMO/USERSPACE/LIB/") include_directories("${OPENAIR_DIR}/targets/ARCH/EXMIMO/DEFS") include_directories("${OPENAIR2_DIR}/ENB_APP") include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC") +include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC") include_directories("${OPENAIR2_DIR}/UTIL/OSA") include_directories("${OPENAIR2_DIR}/UTIL/LFDS/liblfds6.1.1/liblfds611/inc") include_directories("${OPENAIR2_DIR}/UTIL/LFDS/liblfds7.0.0/liblfds700/inc") @@ -905,8 +906,11 @@ if (FLEXRAN_AGENT_SB_IF) add_library(FLEXRAN_AGENT ${OPENAIR2_DIR}/ENB_APP/flexran_agent_handler.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent_common.c + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_ran_api.c + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_timer.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent_common_internal.c ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c + ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent_task_manager.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent_net_comm.c diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 1a43f203df..01df6248f1 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -31,6 +31,7 @@ #include "flexran_agent_common.h" #include "flexran_agent_mac_internal.h" #include "flexran_agent_net_comm.h" +#include "flexran_agent_timer.h" #include "LAYER2/MAC/proto.h" #include "LAYER2/MAC/flexran_agent_mac_proto.h" @@ -54,683 +55,497 @@ struct lfds700_ringbuffer_element *dl_mac_config_array[NUM_MAX_ENB]; struct lfds700_ringbuffer_state ringbuffer_state[NUM_MAX_ENB]; -int flexran_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg){ +int flexran_agent_mac_stats_reply(mid_t mod_id, + const report_config_t *report_config, + Protocol__FlexUeStatsReport **ue_report, + Protocol__FlexCellStatsReport **cell_report) { - // TODO: Must deal with sanitization of input - // TODO: Must check if RNTIs and cell ids of the request actually exist - // TODO: Must resolve conflicts among stats requests - int i; - err_code_t err_code; - xid_t xid; - uint32_t usec_interval, sec_interval; - - //TODO: We do not deal with multiple CCs at the moment and eNB id is 0 - int enb_id = mod_id; - - //eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; - //UE_list_t *eNB_UE_list= &eNB->UE_list; - - report_config_t report_config; - - uint32_t ue_flags = 0; - uint32_t c_flags = 0; - - Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; - - Protocol__FlexStatsRequest *stats_req = input->stats_request_msg; - xid = (stats_req->header)->xid; - - // Check the type of request that is made - switch(stats_req->body_case) { - case PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST: ; - Protocol__FlexCompleteStatsRequest *comp_req = stats_req->complete_stats_request; - if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_OFF) { - /*Disable both periodic and continuous updates*/ - flexran_agent_disable_cont_mac_stats_update(mod_id); - flexran_agent_destroy_timer_by_task_id(xid); - *msg = NULL; - return 0; - } else { //One-off, periodical or continuous reporting - //Set the proper flags - ue_flags = comp_req->ue_report_flags; - c_flags = comp_req->cell_report_flags; - //Create a list of all eNB RNTIs and cells - - //Set the number of UEs and create list with their RNTIs stats configs - report_config.nr_ue = flexran_get_num_ues(mod_id); //eNB_UE_list->num_UEs - report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t) * report_config.nr_ue); - if (report_config.ue_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - for (i = 0; i < report_config.nr_ue; i++) { - report_config.ue_report_type[i].ue_rnti = flexran_get_ue_crnti(enb_id, i); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].crnti; - report_config.ue_report_type[i].ue_report_flags = ue_flags; - } - //Set the number of CCs and create a list with the cell stats configs - report_config.nr_cc = MAX_NUM_CCs; - report_config.cc_report_type = (cc_report_type_t *) malloc(sizeof(cc_report_type_t) * report_config.nr_cc); - if (report_config.cc_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - for (i = 0; i < report_config.nr_cc; i++) { - //TODO: Must fill in the proper cell ids - report_config.cc_report_type[i].cc_id = i; - report_config.cc_report_type[i].cc_report_flags = c_flags; - } - /* Check if request was periodical */ - if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_PERIODICAL) { - /* Create a one off flexran message as an argument for the periodical task */ - Protocol__FlexranMessage *timer_msg; - stats_request_config_t request_config; - request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS; - request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE; - request_config.period = 0; - /* Need to make sure that the ue flags are saved (Bug) */ - if (report_config.nr_ue == 0) { - report_config.nr_ue = 1; - report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t)); - if (report_config.ue_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - report_config.ue_report_type[0].ue_rnti = 0; // Dummy value - report_config.ue_report_type[0].ue_report_flags = ue_flags; - } - request_config.config = &report_config; - flexran_agent_mac_stats_request(enb_id, xid, &request_config, &timer_msg); - /* Create a timer */ - long timer_id = 0; - flexran_agent_timer_args_t *timer_args; - timer_args = malloc(sizeof(flexran_agent_timer_args_t)); - memset (timer_args, 0, sizeof(flexran_agent_timer_args_t)); - timer_args->mod_id = enb_id; - timer_args->msg = timer_msg; - /*Convert subframes to usec time*/ - usec_interval = 1000*comp_req->sf; - sec_interval = 0; - /*add seconds if required*/ - if (usec_interval >= 1000*1000) { - sec_interval = usec_interval/(1000*1000); - usec_interval = usec_interval%(1000*1000); - } - flexran_agent_create_timer(sec_interval, usec_interval, FLEXRAN_AGENT_DEFAULT, enb_id, FLEXRAN_AGENT_TIMER_TYPE_PERIODIC, xid, flexran_agent_handle_timed_task,(void*) timer_args, &timer_id); - } else if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_CONTINUOUS) { - /*If request was for continuous updates, disable the previous configuration and - set up a new one*/ - flexran_agent_disable_cont_mac_stats_update(mod_id); - stats_request_config_t request_config; - request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS; - request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE; - request_config.period = 0; - /* Need to make sure that the ue flags are saved (Bug) */ - if (report_config.nr_ue == 0) { - report_config.nr_ue = 1; - report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t)); - if (report_config.ue_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - report_config.ue_report_type[0].ue_rnti = 0; // Dummy value - report_config.ue_report_type[0].ue_report_flags = ue_flags; - } - request_config.config = &report_config; - flexran_agent_enable_cont_mac_stats_update(enb_id, xid, &request_config); - } - } - break; - case PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST:; - Protocol__FlexCellStatsRequest *cell_req = stats_req->cell_stats_request; - // UE report config will be blank - report_config.nr_ue = 0; - report_config.ue_report_type = NULL; - report_config.nr_cc = cell_req->n_cell; - report_config.cc_report_type = (cc_report_type_t *) malloc(sizeof(cc_report_type_t) * report_config.nr_cc); - if (report_config.cc_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - for (i = 0; i < report_config.nr_cc; i++) { - //TODO: Must fill in the proper cell ids - report_config.cc_report_type[i].cc_id = cell_req->cell[i]; - report_config.cc_report_type[i].cc_report_flags = cell_req->flags; - } - break; - case PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST:; - Protocol__FlexUeStatsRequest *ue_req = stats_req->ue_stats_request; - // Cell report config will be blank - report_config.nr_cc = 0; - report_config.cc_report_type = NULL; - report_config.nr_ue = ue_req->n_rnti; - report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t) * report_config.nr_ue); - if (report_config.ue_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - for (i = 0; i < report_config.nr_ue; i++) { - report_config.ue_report_type[i].ue_rnti = ue_req->rnti[i]; - report_config.ue_report_type[i].ue_report_flags = ue_req->flags; - } - break; - default: - //TODO: Add appropriate error code - err_code = -100; - goto error; - } - - if (flexran_agent_mac_stats_reply(enb_id, xid, &report_config, msg) < 0 ){ - err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; - goto error; - } - - free(report_config.ue_report_type); - free(report_config.cc_report_type); - - return 0; - - error : - LOG_E(FLEXRAN_AGENT, "errno %d occured\n", err_code); - return err_code; -} - -int flexran_agent_mac_stats_request(mid_t mod_id, - xid_t xid, - const stats_request_config_t *report_config, - Protocol__FlexranMessage **msg) { - Protocol__FlexHeader *header; - int i; - - Protocol__FlexStatsRequest *stats_request_msg; - stats_request_msg = malloc(sizeof(Protocol__FlexStatsRequest)); - if(stats_request_msg == NULL) - goto error; - protocol__flex_stats_request__init(stats_request_msg); - - if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REQUEST, &header) != 0) - goto error; - - stats_request_msg->header = header; - - stats_request_msg->type = report_config->report_type; - stats_request_msg->has_type = 1; - - switch (report_config->report_type) { - case PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS: - stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST; - Protocol__FlexCompleteStatsRequest *complete_stats; - complete_stats = malloc(sizeof(Protocol__FlexCompleteStatsRequest)); - if(complete_stats == NULL) - goto error; - protocol__flex_complete_stats_request__init(complete_stats); - complete_stats->report_frequency = report_config->report_frequency; - complete_stats->has_report_frequency = 1; - complete_stats->sf = report_config->period; - complete_stats->has_sf = 1; - complete_stats->has_cell_report_flags = 1; - complete_stats->has_ue_report_flags = 1; - if (report_config->config->nr_cc > 0) { - complete_stats->cell_report_flags = report_config->config->cc_report_type[0].cc_report_flags; - } - if (report_config->config->nr_ue > 0) { - complete_stats->ue_report_flags = report_config->config->ue_report_type[0].ue_report_flags; - } - stats_request_msg->complete_stats_request = complete_stats; - break; - case PROTOCOL__FLEX_STATS_TYPE__FLST_CELL_STATS: - stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST; - Protocol__FlexCellStatsRequest *cell_stats; - cell_stats = malloc(sizeof(Protocol__FlexCellStatsRequest)); - if(cell_stats == NULL) - goto error; - protocol__flex_cell_stats_request__init(cell_stats); - cell_stats->n_cell = report_config->config->nr_cc; - cell_stats->has_flags = 1; - if (cell_stats->n_cell > 0) { - uint32_t *cells; - cells = (uint32_t *) malloc(sizeof(uint32_t)*cell_stats->n_cell); - for (i = 0; i < cell_stats->n_cell; i++) { - cells[i] = report_config->config->cc_report_type[i].cc_id; - } - cell_stats->cell = cells; - cell_stats->flags = report_config->config->cc_report_type[i].cc_report_flags; - } - stats_request_msg->cell_stats_request = cell_stats; - break; - case PROTOCOL__FLEX_STATS_TYPE__FLST_UE_STATS: - stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST; - Protocol__FlexUeStatsRequest *ue_stats; - ue_stats = malloc(sizeof(Protocol__FlexUeStatsRequest)); - if(ue_stats == NULL) - goto error; - protocol__flex_ue_stats_request__init(ue_stats); - ue_stats->n_rnti = report_config->config->nr_ue; - ue_stats->has_flags = 1; - if (ue_stats->n_rnti > 0) { - uint32_t *ues; - ues = (uint32_t *) malloc(sizeof(uint32_t)*ue_stats->n_rnti); - for (i = 0; i < ue_stats->n_rnti; i++) { - ues[i] = report_config->config->ue_report_type[i].ue_rnti; - } - ue_stats->rnti = ues; - ue_stats->flags = report_config->config->ue_report_type[i].ue_report_flags; - } - stats_request_msg->ue_stats_request = ue_stats; - break; - default: - goto error; - } - *msg = malloc(sizeof(Protocol__FlexranMessage)); - if(*msg == NULL) - goto error; - protocol__flexran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG; - (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; - (*msg)->stats_request_msg = stats_request_msg; - return 0; - - error: - // TODO: Need to make proper error handling - if (header != NULL) - free(header); - if (stats_request_msg != NULL) - free(stats_request_msg); - if(*msg != NULL) - free(*msg); - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); - return -1; -} - -int flexran_agent_mac_destroy_stats_request(Protocol__FlexranMessage *msg) { - if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG) - goto error; - free(msg->stats_request_msg->header); - if (msg->stats_request_msg->body_case == PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST) { - free(msg->stats_request_msg->cell_stats_request->cell); - } - if (msg->stats_request_msg->body_case == PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST) { - free(msg->stats_request_msg->ue_stats_request->rnti); - } - free(msg->stats_request_msg); - free(msg); - return 0; - - error: - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); - return -1; -} - -int flexran_agent_mac_stats_reply(mid_t mod_id, - xid_t xid, - const report_config_t *report_config, - Protocol__FlexranMessage **msg) { - Protocol__FlexHeader *header; + // Protocol__FlexHeader *header; int i, j, k; + int cc_id = 0; int enb_id = mod_id; - //eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; - //UE_list_t *eNB_UE_list= &eNB->UE_list; - - Protocol__FlexStatsReply *stats_reply_msg; - stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply)); - if (stats_reply_msg == NULL) - goto error; - protocol__flex_stats_reply__init(stats_reply_msg); - - if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) - goto error; - - stats_reply_msg->header = header; - - stats_reply_msg->n_ue_report = report_config->nr_ue; - stats_reply_msg->n_cell_report = report_config->nr_cc; - - Protocol__FlexUeStatsReport **ue_report; - Protocol__FlexCellStatsReport **cell_report; - /* Allocate memory for list of UE reports */ if (report_config->nr_ue > 0) { - ue_report = malloc(sizeof(Protocol__FlexUeStatsReport *) * report_config->nr_ue); - if (ue_report == NULL) - goto error; - for (i = 0; i < report_config->nr_ue; i++) { - ue_report[i] = malloc(sizeof(Protocol__FlexUeStatsReport)); - protocol__flex_ue_stats_report__init(ue_report[i]); - ue_report[i]->rnti = report_config->ue_report_type[i].ue_rnti; - ue_report[i]->has_rnti = 1; - ue_report[i]->flags = report_config->ue_report_type[i].ue_report_flags; - ue_report[i]->has_flags = 1; - /* Check the types of reports that need to be constructed based on flag values */ - /* Check flag for creation of buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_BSR) { - ue_report[i]->n_bsr = 4; - uint32_t *elem; - elem = (uint32_t *) malloc(sizeof(uint32_t)*ue_report[i]->n_bsr); - if (elem == NULL) - goto error; - for (j = 0; j < ue_report[i]->n_bsr; j++) { - // NN: we need to know the cc_id here, consider the first one - elem[j] = flexran_get_ue_bsr (enb_id, i, j); - } - ue_report[i]->bsr = elem; - } + + for (i = 0; i < report_config->nr_ue; i++) { - /* Check flag for creation of PRH report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PRH) { - ue_report[i]->phr = flexran_get_ue_phr (enb_id, i); // eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].phr_info; - ue_report[i]->has_phr = 1; - } - /* Check flag for creation of RLC buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RLC_BS) { - ue_report[i]->n_rlc_report = 3; // Set this to the number of LCs for this UE. This needs to be generalized for for LCs - Protocol__FlexRlcBsr ** rlc_reports; - rlc_reports = malloc(sizeof(Protocol__FlexRlcBsr *) * ue_report[i]->n_rlc_report); - if (rlc_reports == NULL) - goto error; - // NN: see LAYER2/openair2_proc.c for rlc status - for (j = 0; j < ue_report[i]->n_rlc_report; j++) { - rlc_reports[j] = malloc(sizeof(Protocol__FlexRlcBsr)); - if (rlc_reports[j] == NULL) - goto error; - protocol__flex_rlc_bsr__init(rlc_reports[j]); - rlc_reports[j]->lc_id = j + 1; - rlc_reports[j]->has_lc_id = 1; - rlc_reports[j]->tx_queue_size = flexran_get_tx_queue_size(enb_id,i,j + 1); - rlc_reports[j]->has_tx_queue_size = 1; - - //TODO:Set tx queue head of line delay in ms - rlc_reports[j]->tx_queue_hol_delay = flexran_get_hol_delay(enb_id, i, j+1); - rlc_reports[j]->has_tx_queue_hol_delay = 1; - //TODO:Set retransmission queue size in bytes - rlc_reports[j]->retransmission_queue_size = 10; - rlc_reports[j]->has_retransmission_queue_size = 0; - //TODO:Set retransmission queue head of line delay in ms - rlc_reports[j]->retransmission_queue_hol_delay = 100; - rlc_reports[j]->has_retransmission_queue_hol_delay = 0; - //TODO:Set current size of the pending message in bytes - rlc_reports[j]->status_pdu_size = 100; - rlc_reports[j]->has_status_pdu_size = 0; - } - // Add RLC buffer status reports to the full report - if (ue_report[i]->n_rlc_report > 0) - ue_report[i]->rlc_report = rlc_reports; - } + /* Check flag for creation of buffer status report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_BSR) { + //TODO should be automated + ue_report[i]->n_bsr = 4; + uint32_t *elem; + elem = (uint32_t *) malloc(sizeof(uint32_t)*ue_report[i]->n_bsr); + if (elem == NULL) + goto error; + for (j = 0; j < ue_report[i]->n_bsr; j++) { + // NN: we need to know the cc_id here, consider the first one + elem[j] = flexran_get_ue_bsr (enb_id, i, j); + } + + ue_report[i]->bsr = elem; + } + + /* Check flag for creation of PHR report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PHR) { + ue_report[i]->phr = flexran_get_ue_phr (enb_id, i); // eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].phr_info; + ue_report[i]->has_phr = 1; + + } - /* Check flag for creation of MAC CE buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_CE_BS) { - // TODO: Fill in the actual MAC CE buffer status report - ue_report[i]->pending_mac_ces = (flexran_get_MAC_CE_bitmap_TA(enb_id,i,0) | (0 << 1) | (0 << 2) | (0 << 3)) & 15; /* Use as bitmap. Set one or more of the - PROTOCOL__FLEX_CE_TYPE__FLPCET_ values - found in stats_common.pb-c.h. See - flex_ce_type in FlexRAN specification */ - ue_report[i]->has_pending_mac_ces = 1; - } + /* Check flag for creation of RLC buffer status report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RLC_BS) { + ue_report[i]->n_rlc_report = 3; // Set this to the number of LCs for this UE. This needs to be generalized for for LCs + Protocol__FlexRlcBsr ** rlc_reports; + rlc_reports = malloc(sizeof(Protocol__FlexRlcBsr *) * ue_report[i]->n_rlc_report); + if (rlc_reports == NULL) + goto error; - /* Check flag for creation of DL CQI report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_DL_CQI) { - // TODO: Fill in the actual DL CQI report for the UE based on its configuration - Protocol__FlexDlCqiReport * dl_report; - dl_report = malloc(sizeof(Protocol__FlexDlCqiReport)); - if (dl_report == NULL) - goto error; - protocol__flex_dl_cqi_report__init(dl_report); + // NN: see LAYER2/openair2_proc.c for rlc status + for (j = 0; j < ue_report[i]->n_rlc_report; j++) { - dl_report->sfn_sn = flexran_get_sfn_sf(enb_id); - dl_report->has_sfn_sn = 1; - //Set the number of DL CQI reports for this UE. One for each CC - dl_report->n_csi_report = flexran_get_active_CC(enb_id,i); + rlc_reports[j] = malloc(sizeof(Protocol__FlexRlcBsr)); + if (rlc_reports[j] == NULL) + goto error; + protocol__flex_rlc_bsr__init(rlc_reports[j]); + rlc_reports[j]->lc_id = j+1; + rlc_reports[j]->has_lc_id = 1; + rlc_reports[j]->tx_queue_size = flexran_get_tx_queue_size(enb_id, i, j + 1, "bytes_buffer"); + rlc_reports[j]->has_tx_queue_size = 1; - //Create the actual CSI reports. - Protocol__FlexDlCsi **csi_reports; - csi_reports = malloc(sizeof(Protocol__FlexDlCsi *)*dl_report->n_csi_report); - if (csi_reports == NULL) - goto error; - for (j = 0; j < dl_report->n_csi_report; j++) { - csi_reports[j] = malloc(sizeof(Protocol__FlexDlCsi)); - if (csi_reports[j] == NULL) - goto error; - protocol__flex_dl_csi__init(csi_reports[j]); - //The servCellIndex for this report - csi_reports[j]->serv_cell_index = j; - csi_reports[j]->has_serv_cell_index = 1; - //The rank indicator value for this cc - csi_reports[j]->ri = flexran_get_current_RI(enb_id,i,j); - csi_reports[j]->has_ri = 1; - //TODO: the type of CSI report based on the configuration of the UE - //For now we only support type P10, which only needs a wideband value - //The full set of types can be found in stats_common.pb-c.h and - //in the FlexRAN specifications - csi_reports[j]->type = PROTOCOL__FLEX_CSI_TYPE__FLCSIT_P10; - csi_reports[j]->has_type = 1; - csi_reports[j]->report_case = PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI; - if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI){ - Protocol__FlexCsiP10 *csi10; - csi10 = malloc(sizeof(Protocol__FlexCsiP10)); - if (csi10 == NULL) - goto error; - protocol__flex_csi_p10__init(csi10); - //TODO: set the wideband value - // NN: this is also depends on cc_id - csi10->wb_cqi = flexran_get_ue_wcqi (enb_id, i); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].dl_cqi; - csi10->has_wb_cqi = 1; - //Add the type of measurements to the csi report in the proper union type - csi_reports[j]->p10csi = csi10; - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P11CSI){ + //TODO:Set tx queue head of line delay in ms + rlc_reports[j]->tx_queue_hol_delay = flexran_get_tx_queue_size(enb_id, i, j + 1, "head_line"); + rlc_reports[j]->has_tx_queue_hol_delay = 1; + //TODO:Set retransmission queue size in bytes + rlc_reports[j]->retransmission_queue_size = 10; + rlc_reports[j]->has_retransmission_queue_size = 0; + //TODO:Set retransmission queue head of line delay in ms + rlc_reports[j]->retransmission_queue_hol_delay = 100; + rlc_reports[j]->has_retransmission_queue_hol_delay = 0; + //TODO DONE:Set current size of the pending message in bytes + rlc_reports[j]->status_pdu_size = flexran_get_hol_delay(enb_id, i, j + 1); + rlc_reports[j]->has_status_pdu_size = 1; - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P20CSI){ + } + // Add RLC buffer status reports to the full report + if (ue_report[i]->n_rlc_report > 0) + ue_report[i]->rlc_report = rlc_reports; - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P21CSI){ + + } - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A12CSI){ + /* Check flag for creation of MAC CE buffer status report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_CE_BS) { + // TODO: Fill in the actual MAC CE buffer status report + ue_report[i]->pending_mac_ces = (flexran_get_MAC_CE_bitmap_TA(enb_id,i,0) | (0 << 1) | (0 << 2) + | (0 << 3)) & 15; /* Use as bitmap. Set one or more of the; /* Use as bitmap. Set one or more of the + PROTOCOL__FLEX_CE_TYPE__FLPCET_ values + found in stats_common.pb-c.h. See + flex_ce_type in FlexRAN specification */ + ue_report[i]->has_pending_mac_ces = 1; + + } - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A22CSI){ + /* Check flag for creation of DL CQI report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_DL_CQI) { + // TODO: Fill in the actual DL CQI report for the UE based on its configuration + Protocol__FlexDlCqiReport * dl_report; + dl_report = malloc(sizeof(Protocol__FlexDlCqiReport)); + if (dl_report == NULL) + goto error; + protocol__flex_dl_cqi_report__init(dl_report); - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A20CSI){ + dl_report->sfn_sn = flexran_get_sfn_sf(enb_id); + dl_report->has_sfn_sn = 1; + //Set the number of DL CQI reports for this UE. One for each CC + dl_report->n_csi_report = flexran_get_active_CC(enb_id,i); + dl_report->n_csi_report = 1 ; + //Create the actual CSI reports. + Protocol__FlexDlCsi **csi_reports; + csi_reports = malloc(sizeof(Protocol__FlexDlCsi *)*dl_report->n_csi_report); + if (csi_reports == NULL) + goto error; + for (j = 0; j < dl_report->n_csi_report; j++) { - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A30CSI){ + csi_reports[j] = malloc(sizeof(Protocol__FlexDlCsi)); + if (csi_reports[j] == NULL) + goto error; + protocol__flex_dl_csi__init(csi_reports[j]); + //The servCellIndex for this report + csi_reports[j]->serv_cell_index = j; + csi_reports[j]->has_serv_cell_index = 1; + //The rank indicator value for this cc + csi_reports[j]->ri = flexran_get_current_RI(enb_id,i,j); + csi_reports[j]->has_ri = 1; + //TODO: the type of CSI report based on the configuration of the UE + //For now we only support type P10, which only needs a wideband value + //The full set of types can be found in stats_common.pb-c.h and + //in the FlexRAN specifications + csi_reports[j]->type = PROTOCOL__FLEX_CSI_TYPE__FLCSIT_P10; + csi_reports[j]->has_type = 1; + csi_reports[j]->report_case = PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI; - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A31CSI){ + if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI){ - } - } - //Add the csi reports to the full DL CQI report - dl_report->csi_report = csi_reports; - //Add the DL CQI report to the stats report - ue_report[i]->dl_cqi_report = dl_report; - } + Protocol__FlexCsiP10 *csi10; + csi10 = malloc(sizeof(Protocol__FlexCsiP10)); + if (csi10 == NULL) + goto error; + protocol__flex_csi_p10__init(csi10); + //TODO: set the wideband value + // NN: this is also depends on cc_id + csi10->wb_cqi = flexran_get_ue_wcqi (enb_id, i); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].dl_cqi; + csi10->has_wb_cqi = 1; + //Add the type of measurements to the csi report in the proper union type + csi_reports[j]->p10csi = csi10; + } - /* Check flag for creation of paging buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PBS) { - //TODO: Fill in the actual paging buffer status report. For this field to be valid, the RNTI - //set in the report must be a P-RNTI - Protocol__FlexPagingBufferReport *paging_report; - paging_report = malloc(sizeof(Protocol__FlexPagingBufferReport)); - if (paging_report == NULL) - goto error; - protocol__flex_paging_buffer_report__init(paging_report); - //Set the number of pending paging messages - paging_report->n_paging_info = 1; - //Provide a report for each pending paging message - Protocol__FlexPagingInfo **p_info; - p_info = malloc(sizeof(Protocol__FlexPagingInfo *) * paging_report->n_paging_info); - if (p_info == NULL) - goto error; - for (j = 0; j < paging_report->n_paging_info; j++) { - p_info[j] = malloc(sizeof(Protocol__FlexPagingInfo)); - if(p_info[j] == NULL) - goto error; - protocol__flex_paging_info__init(p_info[j]); - //TODO: Set paging index. This index is the same that will be used for the scheduling of the - //paging message by the controller - p_info[j]->paging_index = 10; - p_info[j]->has_paging_index = 0; - //TODO:Set the paging message size - p_info[j]->paging_message_size = 100; - p_info[j]->has_paging_message_size = 0; - //TODO: Set the paging subframe - p_info[j]->paging_subframe = 10; - p_info[j]->has_paging_subframe = 0; - //TODO: Set the carrier index for the pending paging message - p_info[j]->carrier_index = 0; - p_info[j]->has_carrier_index = 0; - } - //Add all paging info to the paging buffer rerport - paging_report->paging_info = p_info; - //Add the paging report to the UE report - ue_report[i]->pbr = paging_report; - } + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P11CSI){ - /* Check flag for creation of UL CQI report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_UL_CQI) { - //Fill in the full UL CQI report of the UE - Protocol__FlexUlCqiReport *full_ul_report; - full_ul_report = malloc(sizeof(Protocol__FlexUlCqiReport)); - if(full_ul_report == NULL) - goto error; - protocol__flex_ul_cqi_report__init(full_ul_report); - //TODO:Set the SFN and SF of the generated report - full_ul_report->sfn_sn = flexran_get_sfn_sf(enb_id); - full_ul_report->has_sfn_sn = 1; - //TODO:Set the number of UL measurement reports based on the types of measurements - //configured for this UE and on the servCellIndex - full_ul_report->n_cqi_meas = 1; - Protocol__FlexUlCqi **ul_report; - ul_report = malloc(sizeof(Protocol__FlexUlCqi *) * full_ul_report->n_cqi_meas); - if(ul_report == NULL) - goto error; - //Fill each UL report of the UE for each of the configured report types - for(j = 0; j < full_ul_report->n_cqi_meas; j++) { - ul_report[j] = malloc(sizeof(Protocol__FlexUlCqi)); - if(ul_report[j] == NULL) - goto error; - protocol__flex_ul_cqi__init(ul_report[j]); - //TODO: Set the type of the UL report. As an example set it to SRS UL report - // See enum flex_ul_cqi_type in FlexRAN specification for more details - ul_report[j]->type = PROTOCOL__FLEX_UL_CQI_TYPE__FLUCT_SRS; - ul_report[j]->has_type = 1; - //TODO:Set the number of SINR measurements based on the report type - //See struct flex_ul_cqi in FlexRAN specification for more details - ul_report[j]->n_sinr = 0; - uint32_t *sinr_meas; - sinr_meas = (uint32_t *) malloc(sizeof(uint32_t) * ul_report[j]->n_sinr); - if (sinr_meas == NULL) - goto error; - //TODO:Set the SINR measurements for the specified type - for (k = 0; k < ul_report[j]->n_sinr; k++) { - sinr_meas[k] = 10; - } - ul_report[j]->sinr = sinr_meas; - //TODO: Set the servCellIndex for this report - ul_report[j]->serv_cell_index = 0; - ul_report[j]->has_serv_cell_index = 1; - - //Set the list of UL reports of this UE to the full UL report - full_ul_report->cqi_meas = ul_report; - full_ul_report->n_pucch_dbm = MAX_NUM_CCs; - full_ul_report->pucch_dbm = malloc(sizeof(Protocol__FlexPucchDbm *) * full_ul_report->n_pucch_dbm); + Protocol__FlexCsiP11 *csi11; + csi11 = malloc(sizeof(Protocol__FlexCsiP11)); + if (csi11 == NULL) + goto error; + protocol__flex_csi_p11__init(csi11); + + csi11->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + // According To spec 36.213 + + if (flexran_get_antenna_ports(enb_id, j) == 2 && csi_reports[j]->ri == 1) { + // TODO PMI + csi11->wb_pmi = flexran_get_ue_pmi(enb_id); + csi11->has_wb_pmi = 1; - for (j = 0; j < MAX_NUM_CCs; j++) { - full_ul_report->pucch_dbm[j] = malloc(sizeof(Protocol__FlexPucchDbm)); - protocol__flex_pucch_dbm__init(full_ul_report->pucch_dbm[j]); - full_ul_report->pucch_dbm[j]->has_serv_cell_index = 1; - full_ul_report->pucch_dbm[j]->serv_cell_index = j; - if(flexran_get_p0_pucch_dbm(enb_id,i, j) != -1){ - full_ul_report->pucch_dbm[j]->p0_pucch_dbm = flexran_get_p0_pucch_dbm(enb_id,i,j); - full_ul_report->pucch_dbm[j]->has_p0_pucch_dbm = 1; - } - full_ul_report->pucch_dbm[j]->has_p0_pucch_updated = 1; - full_ul_report->pucch_dbm[j]->p0_pucch_updated = flexran_get_p0_pucch_status(enb_id, i, j); - } + } - //Add full UL CQI report to the UE report - ue_report[i]->ul_cqi_report = full_ul_report; - } - } - } - /* Add list of all UE reports to the message */ - stats_reply_msg->ue_report = ue_report; - } + else if (flexran_get_antenna_ports(enb_id, j) == 2 && csi_reports[j]->ri == 2){ + // TODO PMI + csi11->wb_pmi = flexran_get_ue_pmi(enb_id); + csi11->has_wb_pmi = 1; + + } + + else if (flexran_get_antenna_ports(enb_id, j) == 4 && csi_reports[j]->ri == 2){ + // TODO PMI + csi11->wb_pmi = flexran_get_ue_pmi(enb_id); + csi11->has_wb_pmi = 1; + + + } + + csi11->has_wb_pmi = 0; + + csi_reports[j]->p11csi = csi11; + + } + + + + + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P20CSI){ + + Protocol__FlexCsiP20 *csi20; + csi20 = malloc(sizeof(Protocol__FlexCsiP20)); + if (csi20 == NULL) + goto error; + protocol__flex_csi_p20__init(csi20); + + csi20->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + csi20->has_wb_cqi = 1; + + + csi20->bandwidth_part_index = 1 ;//TODO + csi20->has_bandwidth_part_index = 1; + + csi20->sb_index = 1 ;//TODO + csi20->has_sb_index = 1 ; + + + csi_reports[j]->p20csi = csi20; + + + } + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P21CSI){ + + // Protocol__FlexCsiP21 *csi21; + // csi21 = malloc(sizeof(Protocol__FlexCsiP21)); + // if (csi21 == NULL) + // goto error; + // protocol__flex_csi_p21__init(csi21); + + // csi21->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + + + // csi21->wb_pmi = flexran_get_ue_pmi(enb_id); //TDO inside + // csi21->has_wb_pmi = 1; + + // csi21->sb_cqi = 1; // TODO + + // csi21->bandwidth_part_index = 1 ; //TDO inside + // csi21->has_bandwidth_part_index = 1 ; + + // csi21->sb_index = 1 ;//TODO + // csi21->has_sb_index = 1 ; + + + // csi_reports[j]->p20csi = csi21; + + } + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A12CSI){ + + + // Protocol__FlexCsiA12 *csi12; + // csi12 = malloc(sizeof(Protocol__FlexCsiA12)); + // if (csi12 == NULL) + // goto error; + // protocol__flex_csi_a12__init(csi12); + + // csi12->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + + // csi12->sb_pmi = 1 ; //TODO inside + + // TODO continou + } + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A22CSI){ + + // Protocol__FlexCsiA22 *csi22; + // csi22 = malloc(sizeof(Protocol__FlexCsiA22)); + // if (csi22 == NULL) + // goto error; + // protocol__flex_csi_a22__init(csi22); + + // csi22->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + + // csi22->sb_cqi = 1 ; //TODO inside + + // csi22->wb_pmi = flexran_get_ue_wcqi (enb_id, i); + // csi22->has_wb_pmi = 1; + + // csi22->sb_pmi = 1 ; //TODO inside + // csi22->has_wb_pmi = 1; + + // csi22->sb_list = flexran_get_ue_wcqi (enb_id, i); + + + } + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A20CSI){ + + // Protocol__FlexCsiA20 *csi20; + // csi20 = malloc(sizeof(Protocol__FlexCsiA20)); + // if (csi20 == NULL) + // goto error; + // protocol__flex_csi_a20__init(csi20); + + // csi20->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + // csi20->has_wb_cqi = 1; + + // csi20>sb_cqi = 1 ; //TODO inside + // csi20>has_sb_cqi = 1 ; + + // csi20->sb_list = 1; // TODO inside + + + } + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A30CSI){ + + } + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A31CSI){ + + } + + } + //Add the csi reports to the full DL CQI report + dl_report->csi_report = csi_reports; + //Add the DL CQI report to the stats report + ue_report[i]->dl_cqi_report = dl_report; + + } + + /* Check flag for creation of paging buffer status report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PBS) { + //TODO: Fill in the actual paging buffer status report. For this field to be valid, the RNTI + //set in the report must be a P-RNTI + Protocol__FlexPagingBufferReport *paging_report; + paging_report = malloc(sizeof(Protocol__FlexPagingBufferReport)); + if (paging_report == NULL) + goto error; + protocol__flex_paging_buffer_report__init(paging_report); + //Set the number of pending paging messages + paging_report->n_paging_info = 1; + //Provide a report for each pending paging message + Protocol__FlexPagingInfo **p_info; + p_info = malloc(sizeof(Protocol__FlexPagingInfo *) * paging_report->n_paging_info); + if (p_info == NULL) + goto error; + + for (j = 0; j < paging_report->n_paging_info; j++) { + + p_info[j] = malloc(sizeof(Protocol__FlexPagingInfo)); + if(p_info[j] == NULL) + goto error; + protocol__flex_paging_info__init(p_info[j]); + //TODO: Set paging index. This index is the same that will be used for the scheduling of the + //paging message by the controller + p_info[j]->paging_index = 10; + p_info[j]->has_paging_index = 1; + //TODO:Set the paging message size + p_info[j]->paging_message_size = 100; + p_info[j]->has_paging_message_size = 1; + //TODO: Set the paging subframe + p_info[j]->paging_subframe = 10; + p_info[j]->has_paging_subframe = 1; + //TODO: Set the carrier index for the pending paging message + p_info[j]->carrier_index = 0; + p_info[j]->has_carrier_index = 1; + + } + //Add all paging info to the paging buffer rerport + paging_report->paging_info = p_info; + //Add the paging report to the UE report + ue_report[i]->pbr = paging_report; + } + + /* Check flag for creation of UL CQI report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_UL_CQI) { + + //Fill in the full UL CQI report of the UE + Protocol__FlexUlCqiReport *full_ul_report; + full_ul_report = malloc(sizeof(Protocol__FlexUlCqiReport)); + if(full_ul_report == NULL) + goto error; + protocol__flex_ul_cqi_report__init(full_ul_report); + //TODO:Set the SFN and SF of the generated report + full_ul_report->sfn_sn = flexran_get_sfn_sf(enb_id); + full_ul_report->has_sfn_sn = 1; + //TODO:Set the number of UL measurement reports based on the types of measurements + //configured for this UE and on the servCellIndex + full_ul_report->n_cqi_meas = 1; + Protocol__FlexUlCqi **ul_report; + ul_report = malloc(sizeof(Protocol__FlexUlCqi *) * full_ul_report->n_cqi_meas); + if(ul_report == NULL) + goto error; + //Fill each UL report of the UE for each of the configured report types + for(j = 0; j < full_ul_report->n_cqi_meas; j++) { + + ul_report[j] = malloc(sizeof(Protocol__FlexUlCqi)); + if(ul_report[j] == NULL) + goto error; + protocol__flex_ul_cqi__init(ul_report[j]); + //TODO: Set the type of the UL report. As an example set it to SRS UL report + // See enum flex_ul_cqi_type in FlexRAN specification for more details + ul_report[j]->type = PROTOCOL__FLEX_UL_CQI_TYPE__FLUCT_SRS; + ul_report[j]->has_type = 1; + //TODO:Set the number of SINR measurements based on the report type + //See struct flex_ul_cqi in FlexRAN specification for more details + ul_report[j]->n_sinr = 0; + uint32_t *sinr_meas; + sinr_meas = (uint32_t *) malloc(sizeof(uint32_t) * ul_report[j]->n_sinr); + if (sinr_meas == NULL) + goto error; + //TODO:Set the SINR measurements for the specified type + for (k = 0; k < ul_report[j]->n_sinr; k++) { + sinr_meas[k] = 10; + } + ul_report[j]->sinr = sinr_meas; + //TODO: Set the servCellIndex for this report + ul_report[j]->serv_cell_index = 0; + ul_report[j]->has_serv_cell_index = 1; + + //Set the list of UL reports of this UE to the full UL report + full_ul_report->cqi_meas = ul_report; + + full_ul_report->n_pucch_dbm = MAX_NUM_CCs; + full_ul_report->pucch_dbm = malloc(sizeof(Protocol__FlexPucchDbm *) * full_ul_report->n_pucch_dbm); + + for (j = 0; j < MAX_NUM_CCs; j++) { + + full_ul_report->pucch_dbm[j] = malloc(sizeof(Protocol__FlexPucchDbm)); + protocol__flex_pucch_dbm__init(full_ul_report->pucch_dbm[j]); + full_ul_report->pucch_dbm[j]->has_serv_cell_index = 1; + full_ul_report->pucch_dbm[j]->serv_cell_index = j; + + if(flexran_get_p0_pucch_dbm(enb_id,i, j) != -1){ + full_ul_report->pucch_dbm[j]->p0_pucch_dbm = flexran_get_p0_pucch_dbm(enb_id,i,j); + full_ul_report->pucch_dbm[j]->has_p0_pucch_dbm = 1; + } + } + + + } + // Add full UL CQI report to the UE report + ue_report[i]->ul_cqi_report = full_ul_report; + + + } + + + + + } + + + + + } /* Allocate memory for list of cell reports */ if (report_config->nr_cc > 0) { - cell_report = malloc(sizeof(Protocol__FlexCellStatsReport *) * report_config->nr_cc); - if (cell_report == NULL) - goto error; - // Fill in the Cell reports - for (i = 0; i < report_config->nr_cc; i++) { - cell_report[i] = malloc(sizeof(Protocol__FlexCellStatsReport)); - if(cell_report[i] == NULL) - goto error; - protocol__flex_cell_stats_report__init(cell_report[i]); - cell_report[i]->carrier_index = report_config->cc_report_type[i].cc_id; - cell_report[i]->has_carrier_index = 1; - cell_report[i]->flags = report_config->cc_report_type[i].cc_report_flags; - cell_report[i]->has_flags = 1; + + + // Fill in the Cell reports + for (i = 0; i < report_config->nr_cc; i++) { - /* Check flag for creation of noise and interference report */ - if(report_config->cc_report_type[i].cc_report_flags & PROTOCOL__FLEX_CELL_STATS_TYPE__FLCST_NOISE_INTERFERENCE) { - // TODO: Fill in the actual noise and interference report for this cell - Protocol__FlexNoiseInterferenceReport *ni_report; - ni_report = malloc(sizeof(Protocol__FlexNoiseInterferenceReport)); - if(ni_report == NULL) - goto error; - protocol__flex_noise_interference_report__init(ni_report); - // Current frame and subframe number - ni_report->sfn_sf = flexran_get_sfn_sf(enb_id); - ni_report->has_sfn_sf = 1; - //TODO:Received interference power in dbm - ni_report->rip = 0; - ni_report->has_rip = 0; - //TODO:Thermal noise power in dbm - ni_report->tnp = 0; - ni_report->has_tnp = 0; - ni_report->p0_nominal_pucch = flexran_get_p0_nominal_pucch(enb_id, 0); - ni_report->has_p0_nominal_pucch = 1; - cell_report[i]->noise_inter_report = ni_report; - } - } - /* Add list of all cell reports to the message */ - stats_reply_msg->cell_report = cell_report; + /* Check flag for creation of noise and interference report */ + if(report_config->cc_report_type[i].cc_report_flags & PROTOCOL__FLEX_CELL_STATS_TYPE__FLCST_NOISE_INTERFERENCE) { + // TODO: Fill in the actual noise and interference report for this cell + Protocol__FlexNoiseInterferenceReport *ni_report; + ni_report = malloc(sizeof(Protocol__FlexNoiseInterferenceReport)); + if(ni_report == NULL) + goto error; + protocol__flex_noise_interference_report__init(ni_report); + // Current frame and subframe number + ni_report->sfn_sf = flexran_get_sfn_sf(enb_id); + ni_report->has_sfn_sf = 1; + //TODO:Received interference power in dbm + ni_report->rip = 0; + ni_report->has_rip = 1; + //TODO:Thermal noise power in dbm + ni_report->tnp = 0; + ni_report->has_tnp = 1; + + ni_report->p0_nominal_pucch = flexran_get_p0_nominal_pucch(enb_id, 0); + ni_report->has_p0_nominal_pucch = 1; + cell_report[i]->noise_inter_report = ni_report; + } + } + + + + } - *msg = malloc(sizeof(Protocol__FlexranMessage)); - if(*msg == NULL) - goto error; - protocol__flexran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG; - (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; - (*msg)->stats_reply_msg = stats_reply_msg; return 0; error: - // TODO: Need to make proper error handling - if (header != NULL) - free(header); - if (stats_reply_msg != NULL) - free(stats_reply_msg); - if(*msg != NULL) - free(*msg); - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + + if (cell_report != NULL) + free(cell_report); + if (ue_report != NULL) + free(ue_report); + return -1; } @@ -1346,58 +1161,7 @@ void flexran_agent_send_sf_trigger(mid_t mod_id) { LOG_D(FLEXRAN_AGENT, "Could not send sf trigger message\n"); } -void flexran_agent_send_update_mac_stats(mid_t mod_id) { - Protocol__FlexranMessage *current_report = NULL; - void *data; - int size; - err_code_t err_code; - int priority = 0; - - if (pthread_mutex_lock(mac_stats_context[mod_id].mutex)) { - goto error; - } - - if (mac_stats_context[mod_id].cont_update == 1) { - - /*Create a fresh report with the required flags*/ - err_code = flexran_agent_mac_handle_stats(mod_id, (void *) mac_stats_context[mod_id].stats_req, ¤t_report); - if (err_code < 0) { - goto error; - } - } - /* /\*TODO:Check if a previous reports exists and if yes, generate a report */ - /* *that is the diff between the old and the new report, */ - /* *respecting the thresholds. Otherwise send the new report*\/ */ - /* if (mac_stats_context[mod_id].prev_stats_reply != NULL) { */ - - /* msg = flexran_agent_generate_diff_mac_stats_report(current_report, mac_stats_context[mod_id].prev_stats_reply); */ - - /* /\*Destroy the old stats*\/ */ - /* flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].prev_stats_reply); */ - /* } */ - /* /\*Use the current report for future comparissons*\/ */ - /* mac_stats_context[mod_id].prev_stats_reply = current_report; */ - - - if (pthread_mutex_unlock(mac_stats_context[mod_id].mutex)) { - goto error; - } - - if (current_report != NULL){ - data=flexran_agent_pack_message(current_report, &size); - /*Send any stats updates using the MAC channel of the eNB*/ - if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_MAC, data, size, priority)) { - err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; - goto error; - } - - LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); - return; - } - error: - LOG_D(FLEXRAN_AGENT, "Could not send sf trigger message\n"); -} int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { if (mac_agent_registered[mod_id]) { @@ -1408,11 +1172,10 @@ int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { //xface->agent_ctxt = &shared_ctxt[mod_id]; xface->flexran_agent_send_sr_info = flexran_agent_send_sr_info; xface->flexran_agent_send_sf_trigger = flexran_agent_send_sf_trigger; - xface->flexran_agent_send_update_mac_stats = flexran_agent_send_update_mac_stats; + //xface->flexran_agent_send_update_mac_stats = flexran_agent_send_update_mac_stats; xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_default; //xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_remote; xface->flexran_agent_get_pending_dl_mac_config = flexran_agent_get_pending_dl_mac_config; - xface->flexran_agent_notify_ue_state_change = flexran_agent_ue_state_change; xface->dl_scheduler_loaded_lib = NULL; @@ -1427,10 +1190,10 @@ int flexran_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { //xface->agent_ctxt = NULL; xface->flexran_agent_send_sr_info = NULL; xface->flexran_agent_send_sf_trigger = NULL; - xface->flexran_agent_send_update_mac_stats = NULL; + //xface->flexran_agent_send_update_mac_stats = NULL; xface->flexran_agent_schedule_ue_spec = NULL; xface->flexran_agent_get_pending_dl_mac_config = NULL; - xface->flexran_agent_notify_ue_state_change = NULL; + xface->dl_scheduler_loaded_lib = NULL; @@ -1441,89 +1204,7 @@ int flexran_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { } -/****************************************************** - *Implementations of flexran_agent_mac_internal.h functions - ******************************************************/ - -err_code_t flexran_agent_init_cont_mac_stats_update(mid_t mod_id) { - - /*Initialize the Mac stats update structure*/ - /*Initially the continuous update is set to false*/ - mac_stats_context[mod_id].cont_update = 0; - mac_stats_context[mod_id].is_initialized = 1; - mac_stats_context[mod_id].stats_req = NULL; - mac_stats_context[mod_id].prev_stats_reply = NULL; - mac_stats_context[mod_id].mutex = calloc(1, sizeof(pthread_mutex_t)); - if (mac_stats_context[mod_id].mutex == NULL) - goto error; - if (pthread_mutex_init(mac_stats_context[mod_id].mutex, NULL)) - goto error;; - - return 0; - - error: - return -1; -} - -err_code_t flexran_agent_destroy_cont_mac_stats_update(mid_t mod_id) { - /*Disable the continuous updates for the MAC*/ - mac_stats_context[mod_id].cont_update = 0; - mac_stats_context[mod_id].is_initialized = 0; - flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].stats_req); - flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].prev_stats_reply); - free(mac_stats_context[mod_id].mutex); - - mac_agent_registered[mod_id] = 0; - return 1; -} -err_code_t flexran_agent_enable_cont_mac_stats_update(mid_t mod_id, - xid_t xid, stats_request_config_t *stats_req) { - /*Enable the continuous updates for the MAC*/ - if (pthread_mutex_lock(mac_stats_context[mod_id].mutex)) { - goto error; - } - Protocol__FlexranMessage *req_msg; - flexran_agent_mac_stats_request(mod_id, xid, stats_req, &req_msg); - mac_stats_context[mod_id].stats_req = req_msg; - mac_stats_context[mod_id].prev_stats_reply = NULL; - - mac_stats_context[mod_id].cont_update = 1; - mac_stats_context[mod_id].xid = xid; - - if (pthread_mutex_unlock(mac_stats_context[mod_id].mutex)) { - goto error; - } - return 0; - - error: - LOG_E(FLEXRAN_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); - return -1; -} - -err_code_t flexran_agent_disable_cont_mac_stats_update(mid_t mod_id) { - /*Disable the continuous updates for the MAC*/ - if (pthread_mutex_lock(mac_stats_context[mod_id].mutex)) { - goto error; - } - mac_stats_context[mod_id].cont_update = 0; - mac_stats_context[mod_id].xid = 0; - if (mac_stats_context[mod_id].stats_req != NULL) { - flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].stats_req); - } - if (mac_stats_context[mod_id].prev_stats_reply != NULL) { - flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].prev_stats_reply); - } - if (pthread_mutex_unlock(mac_stats_context[mod_id].mutex)) { - goto error; - } - return 0; - - error: - LOG_E(FLEXRAN_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); - return -1; - -} diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h index e2378e9311..d2db860ce4 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h @@ -37,50 +37,10 @@ #include "flexran_agent_common.h" #include "flexran_agent_extern.h" -/* These types will be used to give - instructions for the type of stats reports - we need to create */ -typedef struct { - uint16_t ue_rnti; - uint32_t ue_report_flags; /* Indicates the report elements - required for this UE id. See - FlexRAN specification 1.2.4.2 */ -} ue_report_type_t; - -typedef struct { - uint16_t cc_id; - uint32_t cc_report_flags; /* Indicates the report elements - required for this CC index. See - FlexRAN specification 1.2.4.3 */ -} cc_report_type_t; - -typedef struct { - int nr_ue; - ue_report_type_t *ue_report_type; - int nr_cc; - cc_report_type_t *cc_report_type; -} report_config_t; - -typedef struct stats_request_config_s{ - uint8_t report_type; - uint8_t report_frequency; - uint16_t period; /*In number of subframes*/ - report_config_t *config; -} stats_request_config_t; /* Initialization function for the agent structures etc */ void flexran_agent_init_mac_agent(mid_t mod_id); -int flexran_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); - -/* Statistics request protocol message constructor and destructor */ -int flexran_agent_mac_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg); -int flexran_agent_mac_destroy_stats_request(Protocol__FlexranMessage *msg); - -/* Statistics reply protocol message constructor and destructor */ -int flexran_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg); -int flexran_agent_mac_destroy_stats_reply(Protocol__FlexranMessage *msg); - /* Scheduling request information protocol message constructor and estructor */ int flexran_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int flexran_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg); @@ -89,6 +49,10 @@ int flexran_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg); int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int flexran_agent_mac_destroy_sf_trigger(Protocol__FlexranMessage *msg); +/* Statistics reply protocol message constructor and destructor */ +int flexran_agent_mac_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report); +int flexran_agent_mac_destroy_stats_reply(Protocol__FlexranMessage *msg); + /* DL MAC scheduling decision protocol message constructor (empty command) and destructor */ int flexran_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__FlexranMessage **msg); int flexran_agent_mac_destroy_dl_config(Protocol__FlexranMessage *msg); diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c index 1fa9852487..66efafae55 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c @@ -180,10 +180,12 @@ Protocol__FlexUeStatsReport * copy_ue_stats_report(Protocol__FlexUeStatsReport * } } - if (copy->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PRH) { - copy->has_phr = original->has_phr; - copy->phr = original->phr; - } + + + if (copy->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PHR) { + copy->has_phr = original->has_phr; + copy->phr = original->phr; + } if (copy->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RLC_BS) { copy->n_rlc_report = original->n_rlc_report; diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c new file mode 100644 index 0000000000..9475b06643 --- /dev/null +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c @@ -0,0 +1,662 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file flexran_agent_mac.c + * \brief FlexRAN agent Control Module RRC + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + */ + +#include "flexran_agent_rrc.h" + + +#include "liblfds700.h" + +#include "log.h" + + +/*Flags showing if a rrc agent has already been registered*/ +unsigned int rrc_agent_registered[NUM_MAX_ENB]; + +/*Array containing the Agent-RRC interfaces*/ +AGENT_RRC_xface *agent_rrc_xface[NUM_MAX_ENB]; + +/* Ringbuffer related structs used for maintaining the dl rrc config messages */ +//message_queue_t *rrc_dl_config_queue; +struct lfds700_misc_prng_state rrc_ps[NUM_MAX_ENB]; +struct lfds700_ringbuffer_element *rrc_dl_config_array[NUM_MAX_ENB]; +struct lfds700_ringbuffer_state rrc_ringbuffer_state[NUM_MAX_ENB]; + + + +void flexran_agent_init_rrc_agent(mid_t mod_id) { + lfds700_misc_library_init_valid_on_current_logical_core(); + lfds700_misc_prng_init(&rrc_ps[mod_id]); + int num_elements = RINGBUFFER_SIZE + 1; + //Allow RINGBUFFER_SIZE messages to be stored in the ringbuffer at any time + rrc_dl_config_array[mod_id] = malloc( sizeof(struct lfds700_ringbuffer_element) * num_elements); + lfds700_ringbuffer_init_valid_on_current_logical_core( &rrc_ringbuffer_state[mod_id], rrc_dl_config_array[mod_id], num_elements, &rrc_ps[mod_id], NULL ); +} + + + + + +int flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { + int size; + Protocol__FlexranMessage *msg; + Protocol__FlexHeader *header; + void *data; + int priority; + err_code_t err_code; + + int xid = 0; + + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_UE_STATE_CHANGE, &header) != 0) + goto error; + + Protocol__FlexUeStateChange *ue_state_change_msg; + ue_state_change_msg = malloc(sizeof(Protocol__FlexUeStateChange)); + if(ue_state_change_msg == NULL) { + goto error; + } + protocol__flex_ue_state_change__init(ue_state_change_msg); + ue_state_change_msg->has_type = 1; + ue_state_change_msg->type = state_change; + + Protocol__FlexUeConfig *config; + config = malloc(sizeof(Protocol__FlexUeConfig)); + if (config == NULL) { + goto error; + } + protocol__flex_ue_config__init(config); + if (state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED) { + // Simply set the rnti of the UE + config->has_rnti = 1; + config->rnti = rnti; + } else if (state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_UPDATED + || state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_ACTIVATED) { + int i = find_UE_id(mod_id, rnti); + config->has_rnti = 1; + config->rnti = rnti; + if(flexran_get_time_alignment_timer(mod_id,i) != -1) { + config->time_alignment_timer = flexran_get_time_alignment_timer(mod_id,i); + config->has_time_alignment_timer = 1; + } + if(flexran_get_meas_gap_config(mod_id,i) != -1){ + config->meas_gap_config_pattern = flexran_get_meas_gap_config(mod_id,i); + config->has_meas_gap_config_pattern = 1; + } + if(config->has_meas_gap_config_pattern == 1 && + config->meas_gap_config_pattern != PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF) { + config->meas_gap_config_sf_offset = flexran_get_meas_gap_config_offset(mod_id,i); + config->has_meas_gap_config_sf_offset = 1; + } + //TODO: Set the SPS configuration (Optional) + //Not supported for now, so we do not set it + + //TODO: Set the SR configuration (Optional) + //We do not set it for now + + //TODO: Set the CQI configuration (Optional) + //We do not set it for now + + if(flexran_get_ue_transmission_mode(mod_id,i) != -1) { + config->transmission_mode = flexran_get_ue_transmission_mode(mod_id,i); + config->has_transmission_mode = 1; + } + + config->ue_aggregated_max_bitrate_ul = flexran_get_ue_aggregated_max_bitrate_ul(mod_id,i); + config->has_ue_aggregated_max_bitrate_ul = 1; + + config->ue_aggregated_max_bitrate_dl = flexran_get_ue_aggregated_max_bitrate_dl(mod_id,i); + config->has_ue_aggregated_max_bitrate_dl = 1; + + //TODO: Set the UE capabilities + Protocol__FlexUeCapabilities *c_capabilities; + c_capabilities = malloc(sizeof(Protocol__FlexUeCapabilities)); + protocol__flex_ue_capabilities__init(c_capabilities); + //TODO: Set half duplex (FDD operation) + c_capabilities->has_half_duplex = 0; + c_capabilities->half_duplex = 1;//flexran_get_half_duplex(i); + //TODO: Set intra-frame hopping flag + c_capabilities->has_intra_sf_hopping = 0; + c_capabilities->intra_sf_hopping = 1;//flexran_get_intra_sf_hopping(i); + //TODO: Set support for type 2 hopping with n_sb > 1 + c_capabilities->has_type2_sb_1 = 0; + c_capabilities->type2_sb_1 = 1;//flexran_get_type2_sb_1(i); + //TODO: Set ue category + c_capabilities->has_ue_category = 0; + c_capabilities->ue_category = 1;//flexran_get_ue_category(i); + //TODO: Set UE support for resource allocation type 1 + c_capabilities->has_res_alloc_type1 = 0; + c_capabilities->res_alloc_type1 = 1;//flexran_get_res_alloc_type1(i); + //Set the capabilites to the message + config->capabilities = c_capabilities; + + if(flexran_get_ue_transmission_antenna(mod_id,i) != -1) { + config->has_ue_transmission_antenna = 1; + config->ue_transmission_antenna = flexran_get_ue_transmission_antenna(mod_id,i); + } + + if(flexran_get_tti_bundling(mod_id,i) != -1) { + config->has_tti_bundling = 1; + config->tti_bundling = flexran_get_tti_bundling(mod_id,i); + } + + if(flexran_get_maxHARQ_TX(mod_id,i) != -1){ + config->has_max_harq_tx = 1; + config->max_harq_tx = flexran_get_maxHARQ_TX(mod_id,i); + } + + if(flexran_get_beta_offset_ack_index(mod_id,i) != -1) { + config->has_beta_offset_ack_index = 1; + config->beta_offset_ack_index = flexran_get_beta_offset_ack_index(mod_id,i); + } + + if(flexran_get_beta_offset_ri_index(mod_id,i) != -1) { + config->has_beta_offset_ri_index = 1; + config->beta_offset_ri_index = flexran_get_beta_offset_ri_index(mod_id,i); + } + + if(flexran_get_beta_offset_cqi_index(mod_id,i) != -1) { + config->has_beta_offset_cqi_index = 1; + config->beta_offset_cqi_index = flexran_get_beta_offset_cqi_index(mod_id,i); + } + + if(flexran_get_ack_nack_simultaneous_trans(mod_id,i) != -1) { + config->has_ack_nack_simultaneous_trans = 1; + config->ack_nack_simultaneous_trans = flexran_get_ack_nack_simultaneous_trans(mod_id,i); + } + + if(flexran_get_simultaneous_ack_nack_cqi(mod_id,i) != -1) { + config->has_simultaneous_ack_nack_cqi = 1; + config->simultaneous_ack_nack_cqi = flexran_get_simultaneous_ack_nack_cqi(mod_id,i); + } + + if(flexran_get_aperiodic_cqi_rep_mode(mod_id,i) != -1) { + config->has_aperiodic_cqi_rep_mode = 1; + int mode = flexran_get_aperiodic_cqi_rep_mode(mod_id,i); + if (mode > 4) { + config->aperiodic_cqi_rep_mode = PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_NONE; + } else { + config->aperiodic_cqi_rep_mode = mode; + } + } + + if(flexran_get_tdd_ack_nack_feedback(mod_id, i) != -1) { + config->has_tdd_ack_nack_feedback = 1; + config->tdd_ack_nack_feedback = flexran_get_tdd_ack_nack_feedback(mod_id,i); + } + + if(flexran_get_ack_nack_repetition_factor(mod_id, i) != -1) { + config->has_ack_nack_repetition_factor = 1; + config->ack_nack_repetition_factor = flexran_get_ack_nack_repetition_factor(mod_id,i); + } + + if(flexran_get_extended_bsr_size(mod_id, i) != -1) { + config->has_extended_bsr_size = 1; + config->extended_bsr_size = flexran_get_extended_bsr_size(mod_id,i); + } + + config->has_pcell_carrier_index = 1; + config->pcell_carrier_index = UE_PCCID(mod_id, i); + //TODO: Set carrier aggregation support (boolean) + config->has_ca_support = 0; + config->ca_support = 0; + if(config->has_ca_support){ + //TODO: Set cross carrier scheduling support (boolean) + config->has_cross_carrier_sched_support = 1; + config->cross_carrier_sched_support = 0; + //TODO: Set secondary cells configuration + // We do not set it for now. No carrier aggregation support + + //TODO: Set deactivation timer for secondary cell + config->has_scell_deactivation_timer = 0; + config->scell_deactivation_timer = 0; + } + } else if (state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_MOVED) { + // TODO: Not supported for now. Leave blank + } + + ue_state_change_msg->config = config; + msg = malloc(sizeof(Protocol__FlexranMessage)); + if (msg == NULL) { + goto error; + } + protocol__flexran_message__init(msg); + msg->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG; + msg->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; + msg->ue_state_change_msg = ue_state_change_msg; + + data = flexran_agent_pack_message(msg, &size); + /*Send sr info using the MAC channel of the eNB*/ + if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) { + err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; + goto error; + } + + LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); + return; + error: + LOG_D(FLEXRAN_AGENT, "Could not send UE state message\n"); +} + + + +int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg) { + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG) + goto error; + free(msg->ue_state_change_msg->header); + //TODO: Free the contents of the UE config structure + free(msg->ue_state_change_msg); + free(msg); + return 0; + + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +/* this is called by RRC as a part of rrc xface . The controller previously requested this*/ +int flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t* measResults) { + + // int i, m, k; + int priority; + void *data; + int size; + err_code_t err_code; + Protocol__FlexUeStatsReport **ue_report; + Protocol__FlexCellStatsReport **cell_report; + Protocol__FlexStatsReply *stats_reply_msg; + Protocol__FlexranMessage *msg; + + Protocol__FlexHeader *header; + int xid = 0; + int i; + + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) + goto error; + + + + stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply)); + + if (stats_reply_msg == NULL) + goto error; + + protocol__flex_stats_reply__init(stats_reply_msg); + stats_reply_msg->header = header; + stats_reply_msg->n_ue_report = 1; + stats_reply_msg->n_cell_report = 1; + +/****** LOCK ******************************************************************/ + // pthread_spin_lock(&rrc_meas_t_lock); + + // struct rrc_meas_trigg *ctxt; + // ctxt = rrc_meas_get_trigg(p->rnti, p->meas->measId); + + // pthread_spin_unlock(&rrc_meas_t_lock); +/****** UNLOCK ****************************************************************/ + + // if (ctxt == NULL) { + + // flexran_RRC_meas_reconf(p->rnti, -1, p->meas->measId, NULL, NULL); + // Free the measurement report received from UE. + // ASN_STRUCT_FREE(asn_DEF_MeasResults, p->meas); + // /* Free the params. */ + // free(p); + // return 0; + // } + + + /* Check here whether trigger is registered in agent and then proceed. + */ + // if (em_has_trigger(mod_id, ctxt->t_id, RRC_MEAS_TRIGGER) == 0) { + + // flexran_RRC_meas_reconf(p->rnti, -1, p->meas->measId, NULL, NULL); + // /* Trigger does not exist in agent so remove from wrapper as well. */ + // if (rrc_meas_rem_trigg(ctxt) < 0) { + // goto error; + // } + // } + + + + + /* Set the RNTI of the UE. */ + // repl->rnti = p->rnti; + /* Set the request status. */ + // if (p->reconfig_success == 0) { + // repl->status = STATS_REQ_STATUS__SREQS_FAILURE; + // goto error; + // } + /* Successful outcome. */ + // repl->status = STATS_REQ_STATUS__SREQS_SUCCESS; + /* Set the measurement ID of measurement. */ + // repl->has_measid = 1; + // repl->measid = measResults->measId; + /* Fill the Primary Cell RSRP and RSRQ. */ + // repl->has_pcell_rsrp = 1; + // repl->has_pcell_rsrq = 1; + // #ifdef Rel10 + // repl->has_pcell_rsrp = 1; + // repl->has_pcell_rsrq = 1; + // repl->pcell_rsrp = measResults2->measResultPCell.rsrpResult - 140; + // repl->pcell_rsrq = (measResults2->measResultPCell.rsrqResult)/2 - 20; + + ue_report = malloc(sizeof(Protocol__FlexUeStatsReport *) * 1); + if (ue_report == NULL) + goto error; + + for (i = 0; i < 1; i++) { + + ue_report[i] = malloc(sizeof(Protocol__FlexUeStatsReport)); + if(ue_report[i] == NULL) + goto error; + protocol__flex_ue_stats_report__init(ue_report[i]); + ue_report[i]->rnti = flexran_get_ue_crnti(mod_id, 0); + ue_report[i]->has_rnti = 1; + ue_report[i]->flags = 65536; + ue_report[i]->has_flags = 1; + + } + + cell_report = malloc(sizeof(Protocol__FlexCellStatsReport *) * 1); + if (cell_report == NULL) + goto error; + + for (i = 0; i < 1; i++) { + + cell_report[i] = malloc(sizeof(Protocol__FlexCellStatsReport)); + if(cell_report[i] == NULL) + goto error; + + protocol__flex_cell_stats_report__init(cell_report[i]); + cell_report[i]->carrier_index = 0; //report_config->cc_report_type[i].cc_id; + cell_report[i]->has_carrier_index = 1; + cell_report[i]->flags = 0; // report_config->cc_report_type[i].cc_report_flags; + cell_report[i]->has_flags = 1; + } + + + Protocol__FlexRrcMeasurements *rrc_measurements; + rrc_measurements = malloc(sizeof(Protocol__FlexRrcMeasurements)); + if (rrc_measurements == NULL) + goto error; + protocol__flex_rrc_measurements__init(rrc_measurements); + + rrc_measurements->measid = measResults->measId; + rrc_measurements->has_measid = 1; + + rrc_measurements->pcell_rsrp = measResults->measResultPCell.rsrpResult - 140; + rrc_measurements->has_pcell_rsrp = 1; + + rrc_measurements->pcell_rsrq = (measResults->measResultPCell.rsrqResult)/2 - 20; + rrc_measurements->has_pcell_rsrq = 1 ; + + ue_report[0]->rrc_measurements = rrc_measurements; + + + + + + // #else + // repl->has_pcell_rsrp = 1; + // repl->has_pcell_rsrq = 1; + // repl->pcell_rsrp = RSRP_meas_mapping[meas-> + // measResultServCell.rsrpResult]; + // repl->pcell_rsrq = RSRQ_meas_mapping[meas-> + // measResultServCell.rsrqResult]; + // #endif + + // repl->neigh_meas = NULL; + + // if (meas->measResultNeighCells != NULL) { + // /* + // * Neighboring cells measurements performed by UE. + // */ + // NeighCellsMeasurements *neigh_meas; + // neigh_meas = malloc(sizeof(NeighCellsMeasurements)); + // if (neigh_meas == NULL) + // goto error; + // neigh_cells_measurements__init(neigh_meas); + + // /* EUTRAN RRC Measurements. */ + // if (meas->measResultNeighCells->present == + // MeasResults__measResultNeighCells_PR_measResultListEUTRA) { + + // MeasResultListEUTRA_t meas_list = meas->measResultNeighCells-> + // choice.measResultListEUTRA; + // /* Set the number of EUTRAN measurements present in report. */ + // neigh_meas->n_eutra_meas = meas_list.list.count; + // if (neigh_meas->n_eutra_meas > 0) { + // /* Initialize EUTRAN measurements. */ + // EUTRAMeasurements **eutra_meas; + // eutra_meas = malloc(sizeof(EUTRAMeasurements *) * + // neigh_meas->n_eutra_meas); + // for (i = 0; i < neigh_meas->n_eutra_meas; i++) { + // eutra_meas[i] = malloc(sizeof(EUTRAMeasurements)); + // eutra_measurements__init(eutra_meas[i]); + // /* Fill in the physical cell identifier. */ + // eutra_meas[i]->has_phys_cell_id = 1; + // eutra_meas[i]->phys_cell_id = meas_list.list.array[i]-> + // physCellId; + // // log_i(agent,"PCI of Target %d", eutra_meas[i]->phys_cell_id); + // /* Check for Reference signal measurements. */ + // if (&(meas_list.list.array[i]->measResult)) { + // /* Initialize Ref. signal measurements. */ + // EUTRARefSignalMeas *meas_result; + // meas_result = malloc(sizeof(EUTRARefSignalMeas)); + // eutra_ref_signal_meas__init(meas_result); + + // if (meas_list.list.array[i]->measResult.rsrpResult) { + // meas_result->has_rsrp = 1; + // meas_result->rsrp = RSRP_meas_mapping[*(meas_list. + // list.array[i]->measResult.rsrpResult)]; + // // log_i(agent,"RSRP of Target %d", meas_result->rsrp); + // } + + // if (meas_list.list.array[i]->measResult.rsrqResult) { + // meas_result->has_rsrq = 1; + // meas_result->rsrq = RSRQ_meas_mapping[*(meas_list. + // list.array[i]->measResult.rsrqResult)]; + // // log_i(agent,"RSRQ of Target %d", meas_result->rsrq); + // } + // eutra_meas[i]->meas_result = meas_result; + // } + // /* Check for CGI measurements. */ + // if (meas_list.list.array[i]->cgi_Info) { + // /* Initialize CGI measurements. */ + // EUTRACgiMeasurements *cgi_meas; + // cgi_meas = malloc(sizeof(EUTRACgiMeasurements)); + // eutra_cgi_measurements__init(cgi_meas); + + // /* EUTRA Cell Global Identity (CGI). */ + // CellGlobalIdEUTRA *cgi; + // cgi = malloc(sizeof(CellGlobalIdEUTRA)); + // cell_global_id__eutra__init(cgi); + + // cgi->has_cell_id = 1; + // CellIdentity_t cId = meas_list.list.array[i]-> + // cgi_Info->cellGlobalId.cellIdentity; + // cgi->cell_id = (cId.buf[0] << 20) + (cId.buf[1] << 12) + + // (cId.buf[2] << 4) + (cId.buf[3] >> 4); + + // /* Public land mobile network identifier of neighbor + // * cell. + // */ + // PlmnIdentity *plmn_id; + // plmn_id = malloc(sizeof(PlmnIdentity)); + // plmn_identity__init(plmn_id); + + // MNC_t mnc = meas_list.list.array[i]-> + // cgi_Info->cellGlobalId.plmn_Identity.mnc; + + // plmn_id->has_mnc = 1; + // plmn_id->mnc = 0; + // for (m = 0; m < mnc.list.count; m++) { + // plmn_id->mnc += *mnc.list.array[m] * + // ((uint32_t) pow(10, mnc.list.count - m - 1)); + // } + + // MCC_t *mcc = meas_list.list.array[i]-> + // cgi_Info->cellGlobalId.plmn_Identity.mcc; + + // plmn_id->has_mcc = 1; + // plmn_id->mcc = 0; + // for (m = 0; m < mcc->list.count; m++) { + // plmn_id->mcc += *mcc->list.array[m] * + // ((uint32_t) pow(10, mcc->list.count - m - 1)); + // } + + // TrackingAreaCode_t tac = meas_list.list.array[i]-> + // cgi_Info->trackingAreaCode; + + // cgi_meas->has_tracking_area_code = 1; + // cgi_meas->tracking_area_code = (tac.buf[0] << 8) + + // (tac.buf[1]); + + // PLMN_IdentityList2_t *plmn_l = meas_list.list.array[i]-> + // cgi_Info->plmn_IdentityList; + + // cgi_meas->n_plmn_id = plmn_l->list.count; + // /* Set the PLMN ID list in CGI measurements. */ + // PlmnIdentity **plmn_id_l; + // plmn_id_l = malloc(sizeof(PlmnIdentity *) * + // cgi_meas->n_plmn_id); + + // MNC_t mnc2; + // MCC_t *mcc2; + // for (m = 0; m < cgi_meas->n_plmn_id; m++) { + // plmn_id_l[m] = malloc(sizeof(PlmnIdentity)); + // plmn_identity__init(plmn_id_l[m]); + + // mnc2 = plmn_l->list.array[m]->mnc; + // plmn_id_l[m]->has_mnc = 1; + // plmn_id_l[m]->mnc = 0; + // for (k = 0; k < mnc2.list.count; k++) { + // plmn_id_l[m]->mnc += *mnc2.list.array[k] * + // ((uint32_t) pow(10, mnc2.list.count - k - 1)); + // } + + // mcc2 = plmn_l->list.array[m]->mcc; + // plmn_id_l[m]->has_mcc = 1; + // plmn_id_l[m]->mcc = 0; + // for (k = 0; k < mcc2->list.count; k++) { + // plmn_id_l[m]->mcc += *mcc2->list.array[k] * + // ((uint32_t) pow(10, mcc2->list.count - k - 1)); + // } + // } + // cgi_meas->plmn_id = plmn_id_l; + // eutra_meas[i]->cgi_meas = cgi_meas; + // } + // } + // neigh_meas->eutra_meas = eutra_meas; + // } + // } + // repl->neigh_meas = neigh_meas; + // } + /* Attach the RRC measurement reply message to RRC measurements message. */ + // mrrc_meas->repl = repl; + /* Attach RRC measurement message to triggered event message. */ + // te->mrrc_meas = mrrc_meas; + // te->has_action = 0; + /* Attach the triggered event message to main message. */ + // reply->te = te; + + /* Send the report to controller. */ + // if (flexran_agent_msg_send(b_id, reply) < 0) { + // goto error; + // } + + /* Free the measurement report received from UE. */ + // ASN_STRUCT_FREE(asn_DEF_MeasResults, p->meas); + /* Free the params. */ + // free(p); + + + stats_reply_msg->cell_report = cell_report; + + stats_reply_msg->ue_report = ue_report; + + msg = malloc(sizeof(Protocol__FlexranMessage)); + if(msg == NULL) + goto error; + protocol__flexran_message__init(msg); + msg->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG; + msg->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; + msg->stats_reply_msg = stats_reply_msg; + + data = flexran_agent_pack_message(msg, &size); + + + if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) { + + err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; + goto error; + } + + LOG_I(FLEXRAN_AGENT,"RRC Trigger is done \n"); + + return 0; + + error: + + LOG_E(RRC, "Error triggering RRC measurements message!"); + /* Free the measurement report received from UE. */ + // ASN_STRUCT_FREE(asn_DEF_MeasResults, p->meas); + /* Free the params. */ + // free(p); + return -1; +} + + +int flexran_agent_register_rrc_xface(mid_t mod_id, AGENT_RRC_xface *xface) { + if (rrc_agent_registered[mod_id]) { + LOG_E(RRC, "RRC agent for eNB %d is already registered\n", mod_id); + return -1; + } + +// xface->flexran_agent_send_update_rrc_stats = flexran_agent_send_update_rrc_stats; + + xface->flexran_agent_notify_ue_state_change = flexran_agent_ue_state_change; + xface->flexran_trigger_rrc_measurements = flexran_trigger_rrc_measurements; + + rrc_agent_registered[mod_id] = 1; + agent_rrc_xface[mod_id] = xface; + + return 0; +} + +int flexran_agent_unregister_rrc_xface(mid_t mod_id, AGENT_RRC_xface *xface) { + + //xface->agent_ctxt = NULL; +// xface->flexran_agent_send_update_rrc_stats = NULL; + + xface->flexran_agent_notify_ue_state_change = NULL; + xface->flexran_trigger_rrc_measurements = NULL; + rrc_agent_registered[mod_id] = 0; + agent_rrc_xface[mod_id] = NULL; + + return 0; +} diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h new file mode 100644 index 0000000000..17b58dac93 --- /dev/null +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h @@ -0,0 +1,74 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2014 Eurecom + + OpenAirInterface is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + + OpenAirInterface 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OpenAirInterface.The full GNU General Public License is + included in this distribution in the file called "COPYING". If not, + see . + + Contact Information + OpenAirInterface Admin: openair_admin@eurecom.fr + OpenAirInterface Tech : openair_tech@eurecom.fr + OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr + + Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. + + *******************************************************************************/ + +/*! \file flexran_agent_rrc.h + * \brief FlexRAN agent Control Module RRC header + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + */ + +#ifndef FLEXRAN_AGENT_RRC_H_ +#define FLEXRAN_AGENT_RRC_H_ + +#include "header.pb-c.h" +#include "flexran.pb-c.h" +#include "stats_messages.pb-c.h" +#include "stats_common.pb-c.h" +#include "MeasResults.h" + +#include "flexran_agent_common.h" +#include "flexran_agent_rrc_defs.h" + + +/* Initialization function for the agent structures etc */ +void flexran_agent_init_rrc_agent(mid_t mod_id); + +/* UE state change message constructor and destructor */ +int flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change); +int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg); + + +/********************************** + * FlexRAN agent - technology RRC API + **********************************/ + +/* Send to the controller all the rrc stat updates that occured during this subframe*/ +// void flexran_agent_send_update_rrc_stats(mid_t mod_id); + +/* this is called by RRC as a part of rrc xface . The controller previously requested this*/ +int flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t *); + +/*Register technology specific interface callbacks*/ +int flexran_agent_register_rrc_xface(mid_t mod_id, AGENT_RRC_xface *xface); + +/*Unregister technology specific callbacks*/ +int flexran_agent_unregister_rrc_xface(mid_t mod_id, AGENT_RRC_xface*xface); + +#endif diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h new file mode 100644 index 0000000000..10fc4ba254 --- /dev/null +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h @@ -0,0 +1,62 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2016 Eurecom + + OpenAirInterface is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + + OpenAirInterface 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OpenAirInterface.The full GNU General Public License is + included in this distribution in the file called "COPYING". If not, + see . + + Contact Information + OpenAirInterface Admin: openair_admin@eurecom.fr + OpenAirInterface Tech : openair_tech@eurecom.fr + OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr + + Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. + + *******************************************************************************/ + +/*! \file flexran_agent_rrc_defs.h + * \brief FlexRAN agent - RRC interface primitives + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + * \mail + */ + +#ifndef __FLEXRAN_AGENT_RRC_PRIMITIVES_H__ +#define __FLEXRAN_AGENT_RRC_PRIMITIVES_H__ + +#include "flexran_agent_defs.h" +#include "flexran.pb-c.h" +#include "header.pb-c.h" + +#define RINGBUFFER_SIZE 100 + +/* FLEXRAN AGENT-RRC Interface */ +typedef struct { + + /// Inform the controller about the scheduling requests received during the subframe + //void (*flexran_agent_send_update_rrc_stats)(mid_t mod_id); + + /// Notify the controller for a state change of a particular UE, by sending the proper + /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) + void (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, + uint32_t state_change); + + void (*flexran_trigger_rrc_measurements)(mid_t mod_id, MeasResults_t* measResults) + +} AGENT_RRC_xface; + +#endif diff --git a/openair2/ENB_APP/MESSAGES/V2/flexran.proto b/openair2/ENB_APP/MESSAGES/V2/flexran.proto index 3a1d40bca6..7fb3a22df8 100644 --- a/openair2/ENB_APP/MESSAGES/V2/flexran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/flexran.proto @@ -28,6 +28,7 @@ message flexran_message { flex_ue_state_change ue_state_change_msg = 15; flex_control_delegation control_delegation_msg = 16; flex_agent_reconfiguration agent_reconfiguration_msg = 17; + flex_rrc_triggering rrc_triggering = 18; } } @@ -163,6 +164,13 @@ message flex_dl_mac_config { repeated flex_pdcch_ofdm_sym_count ofdm_sym = 6; // OFDM symbol count for each CC } +message flex_rrc_triggering { + + optional flex_header header = 1; + optional string rrc_trigger = 2; +} + + // // UE state change message // diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index dfd5ea6c99..468dcd201e 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -39,5 +39,7 @@ enum flex_type { // Control delegation messages FLPT_DELEGATE_CONTROL = 15; FLPT_RECONFIGURE_AGENT = 16; + FLPT_RRC_TRIGGERING = 17; + } diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto index 080883ea97..cce36df00a 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto @@ -181,3 +181,63 @@ message flex_noise_interference_report { optional int32 p0_nominal_pucch = 4; } +// +// RRC Primitives +// +message flex_rrc_measurements { + // Measurement identifier. + optional int32 measid = 1; + // Primary Cell Reference Signal Received Power (RSRP). + optional int32 pcell_rsrp = 2; + // Primary Cell Reference Signal Received Quality (RSRQ). + optional int32 pcell_rsrq = 3; + // Neighboring cells measurements performed by UE. + optional flex_neigh_cells_measurements neigh_meas = 4; +} + +message flex_neigh_cells_measurements { + // Neighboring EUTRA cells measurements. + repeated flex_eutra_measurements eutra_meas = 1; +} + +message flex_eutra_measurements { + // Physical Cell identifier. + optional int32 phys_cell_id = 1; + // EUTRA Cell Global Identity (CGI) measurement. + optional flex_eutra_cgi_measurements cgi_meas = 2; + // EUTRA nearby cell reference signal measurement. + optional flex_eutra_ref_signal_meas meas_result = 3; +} + +message flex_eutra_cgi_measurements { + // EUTRA Cell Global Identity (CGI). + optional flex_cell_global_eutra_id cgi = 1; + // Tracking area code of the neighbor cell. + optional uint32 tracking_area_code = 2; + // Public land mobile network identifiers of neighbor cell. + repeated flex_plmn_identity plmn_id = 3; +} + +message flex_cell_global_eutra_id { + // Public land mobile network identifier of neighbor cell. + optional flex_plmn_identity plmn_id = 1; + // Cell identifier of neighbor cell. + optional uint32 cell_id = 2; +} + +message flex_plmn_identity { + // Mobile Network Code (MNC). + repeated uint32 mnc = 1; + // Mobile Country Code (MCC). + repeated uint32 mcc = 2; + // tracking area code + repeated uint32 tac = 3; +} + +message flex_eutra_ref_signal_meas { + // Neighboring Cell Reference Signal Received Power (RSRP). + optional int32 rsrp = 1; + // Neighboring Cell Reference Signal Received Quality (RSRQ). + optional int32 rsrq = 2; + +} diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto index 1b1567dda1..48360f6f68 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto @@ -46,6 +46,7 @@ message flex_ue_stats_report { optional flex_dl_cqi_report dl_cqi_report = 7; optional flex_paging_buffer_report pbr = 8; optional flex_ul_cqi_report ul_cqi_report = 9; + optional flex_rrc_measurements rrc_measurements = 10; } // @@ -76,11 +77,12 @@ enum flex_cell_stats_type { // Flags for UE-related statistics enum flex_ue_stats_type { FLUST_BSR = 1; - FLUST_PRH = 2; + FLUST_PHR = 2; FLUST_RLC_BS = 4; FLUST_MAC_CE_BS = 8; FLUST_DL_CQI = 16; FLUST_PBS = 32; FLUST_UL_CQI = 64; // To be extended with more types of stats -} \ No newline at end of file + FLUST_RRC_MEASUREMENTS = 65536; +} diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index 153c89b3e2..09d7495a69 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -98,6 +98,8 @@ #define ENB_CONFIG_STRING_EUTRA_BAND "eutra_band" #define ENB_CONFIG_STRING_DOWNLINK_FREQUENCY "downlink_frequency" #define ENB_CONFIG_STRING_UPLINK_FREQUENCY_OFFSET "uplink_frequency_offset" +#define ENB_CONFIG_STRING_RRC_REPORT_CONFIG_AMOUNT "report_amount" +#define ENB_CONFIG_STRING_RRC_REPORT_CONFIG_INTERVAL "report_interval" #define ENB_CONFIG_STRING_NID_CELL "Nid_cell" #define ENB_CONFIG_STRING_N_RB_DL "N_RB_DL" @@ -165,7 +167,7 @@ #define ENB_CONFIG_STRING_UETIMERS_N310 "ue_TimersAndConstants_n310" #define ENB_CONFIG_STRING_UETIMERS_N311 "ue_TimersAndConstants_n311" #define ENB_CONFIG_STRING_UE_TRANSMISSION_MODE "ue_TransmissionMode" - +#define ENB_CONFIG_STRING_RRC_CONFIG "rrc_config" #define ENB_CONFIG_STRING_SRB1 "srb1_parameters" #define ENB_CONFIG_STRING_SRB1_TIMER_POLL_RETRANSMIT "timer_poll_retransmit" #define ENB_CONFIG_STRING_SRB1_TIMER_REORDERING "timer_reordering" @@ -456,6 +458,10 @@ void enb_config_display(void) printf( "\tue_TransmissionMode for CC %d:\t%ld:\n",j,enb_properties.properties[i]->ue_TransmissionMode[j]); + printf( "\n\tRRC Report Config: \n"); + printf( "\n\t Report interval \t%ld: ", enb_properties.properties[i]->rrc_report_interval); + printf( "\n\t Report amount \t%ld: \n", enb_properties.properties[i]->rrc_report_amount); + } for (j=0; j < enb_properties.properties[i]->num_otg_elements; j++) { @@ -545,6 +551,7 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) config_setting_t *setting_enb = NULL; config_setting_t *setting_otg = NULL; config_setting_t *subsetting_otg = NULL; + config_setting_t *setting_rrc = NULL; int parse_errors = 0; int num_enb_properties = 0; int enb_properties_index = 0; @@ -651,7 +658,8 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) libconfig_int srb1_max_retx_threshold = 0; libconfig_int my_int; - + const char* rrc_report_amount = NULL; + const char* rrc_report_interval = NULL; char* if_name = NULL; char* ipv4 = NULL; @@ -1968,6 +1976,75 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) } } + + setting_rrc = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_RRC_CONFIG); + if (setting_rrc != NULL) { + + if (!(config_setting_lookup_string(setting_rrc, ENB_CONFIG_STRING_RRC_REPORT_CONFIG_AMOUNT, &rrc_report_amount) + && config_setting_lookup_string(setting_rrc, ENB_CONFIG_STRING_RRC_REPORT_CONFIG_INTERVAL, &rrc_report_interval))) + AssertFatal (0, + "Failed to parse eNB configuration file %s, enb %d, rrc_report_amount and rrc_reporyt_interval !\n", + lib_config_file_name_pP, i); + + if (strcmp(rrc_report_amount, "r1") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r1; + } else if (strcmp(rrc_report_amount, "r2") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r2; + }else if (strcmp(rrc_report_amount, "r4") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r4; + }else if (strcmp(rrc_report_amount, "r8") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r8; + }else if (strcmp(rrc_report_amount, "r16") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r16; + }else if (strcmp(rrc_report_amount, "r32") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r32; + }else if (strcmp(rrc_report_amount, "r64") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r64; + }else if (strcmp(rrc_report_amount, "infinity") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_infinity; + }else{ + AssertFatal (0, + "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for report_amount choice: r1, r2, r4, r8, r16, r32, r64, infinity !\n", + lib_config_file_name_pP, i,rrc_report_amount); + } + + if (strcmp(rrc_report_interval, "120ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms120; + } else if (strcmp(rrc_report_interval, "240ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms240; + }else if (strcmp(rrc_report_interval, "480ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms480; + }else if (strcmp(rrc_report_interval, "640ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms640; + }else if (strcmp(rrc_report_interval, "1024ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms1024; + }else if (strcmp(rrc_report_interval, "2048ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms2048; + }else if (strcmp(rrc_report_interval, "5120ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms5120; + }else if (strcmp(rrc_report_interval, "10240ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms10240; + }else if (strcmp(rrc_report_interval, "1min") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_min1; + }else if (strcmp(rrc_report_interval, "6min") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_min6; + }else if (strcmp(rrc_report_interval, "12min") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_min12; + }else if (strcmp(rrc_report_interval, "30min") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_min30; + } else if (strcmp(rrc_report_interval, "60min") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_min60; + } else { + AssertFatal (0, + "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for report_interval choice: 120ms, 240ms, 480ms, 640ms, 1024ms, 2048ms, 5120ms, 10240ms, 1min, 6min, 12", + lib_config_file_name_pP, i,rrc_report_interval); + } + + } else { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms120; + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r1; + } + setting_srb1 = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_SRB1); if (setting_srb1 != NULL) { diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h index a508a82e1f..094360749b 100644 --- a/openair2/ENB_APP/enb_config.h +++ b/openair2/ENB_APP/enb_config.h @@ -214,6 +214,10 @@ typedef struct Enb_properties_s { long srb1_poll_pdu; long srb1_poll_byte; long srb1_max_retx_threshold; + + long rrc_report_amount; + long rrc_report_interval; + /* Nb of MME to connect to */ uint8_t nb_mme; /* List of MME to connect to */ diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c index 0dcacd4b81..d96076df83 100644 --- a/openair2/ENB_APP/flexran_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -21,27 +21,16 @@ /*! \file flexran_agent.h * \brief top level flexran agent receive thread and itti task - * \author Xenofon Foukas and Navid Nikaein - * \date 2016 + * \author Xenofon Foukas and Navid Nikaein and shahab SHARIAT BAGHERI + * \date 2017 * \version 0.1 */ -#include "flexran_agent_common.h" -#include "log.h" #include "flexran_agent.h" -#include "flexran_agent_mac_defs.h" -#include "flexran_agent_mac.h" -#include "flexran_agent_mac_internal.h" - -#include "flexran_agent_extern.h" - -#include "assertions.h" - -#include "flexran_agent_net_comm.h" -#include "flexran_agent_async.h" #include + //#define TEST_TIMER flexran_agent_instance_t flexran_agent[NUM_MAX_ENB]; @@ -264,8 +253,8 @@ int flexran_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properti *flexran_agent_register_channel(mod_id, channel, FLEXRAN_AGENT_MAC); */ - /*Initialize the continuous MAC stats update mechanism*/ - flexran_agent_init_cont_mac_stats_update(mod_id); + /*Initialize the continuous stats update mechanism*/ + flexran_agent_init_cont_stats_update(mod_id); new_thread(receive_thread, &flexran_agent[mod_id]); @@ -275,6 +264,9 @@ int flexran_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properti AGENT_MAC_xface *mac_agent_xface = (AGENT_MAC_xface *) malloc(sizeof(AGENT_MAC_xface)); flexran_agent_register_mac_xface(mod_id, mac_agent_xface); + AGENT_RRC_xface *rrc_agent_xface = (AGENT_MAC_xface *) malloc(sizeof(AGENT_MAC_xface)); + flexran_agent_register_rrc_xface(mod_id, rrc_agent_xface); + /* * initilize a timer */ diff --git a/openair2/ENB_APP/flexran_agent.h b/openair2/ENB_APP/flexran_agent.h index 21ea21aafc..aec4f004a8 100644 --- a/openair2/ENB_APP/flexran_agent.h +++ b/openair2/ENB_APP/flexran_agent.h @@ -22,15 +22,23 @@ /*! \file flexran_agent.h * \brief top level flexran agent * \author Navid Nikaein and Xenofon Foukas - * \date 2016 + * \date 2017 * \version 0.1 */ #ifndef FLEXRAN_AGENT_H_ #define FLEXRAN_AGENT_H_ -#include "enb_config.h" // for enb properties #include "flexran_agent_common.h" +#include "flexran_agent_async.h" +#include "flexran_agent_extern.h" +#include "flexran_agent_timer.h" +#include "flexran_agent_defs.h" + +#include "log.h" +#include "assertions.h" + +#include "enb_config.h" // for enb properties /* Initiation and termination of the eNodeB agent */ diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index f2d00145a0..7d9cfe685c 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -21,8 +21,8 @@ /*! \file flexran_agent_common.c * \brief common primitives for all agents - * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein - * \date 2016 + * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein, shahab SHARIAT BAGHERI + * \date 2017 * \version 0.1 */ @@ -41,10 +41,6 @@ #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" #include "rrc_eNB_UE_context.h" -void * enb[NUM_MAX_ENB]; -void * enb_ue[NUM_MAX_ENB]; -void * enb_rrc[NUM_MAX_ENB]; - /* * message primitives */ @@ -344,19 +340,6 @@ int flexran_agent_destroy_lc_config_reply(Protocol__FlexranMessage *msg) { return -1; } -int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg) { - if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG) - goto error; - free(msg->ue_state_change_msg->header); - //TODO: Free the contents of the UE config structure - free(msg->ue_state_change_msg); - free(msg); - return 0; - - error: - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); - return -1; -} int flexran_agent_destroy_enb_config_request(Protocol__FlexranMessage *msg) { if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG) @@ -442,1082 +425,6 @@ int flexran_agent_destroy_agent_reconfiguration(Protocol__FlexranMessage *msg) { } -/* - * get generic info from RAN - */ - -void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran){ - - switch (ran){ - case RAN_LTE_OAI : - enb[mod_id] = (void *)&eNB_mac_inst[mod_id]; - enb_ue[mod_id] = (void *)&eNB_mac_inst[mod_id].UE_list; - enb_rrc[mod_id] = (void *)&eNB_rrc_inst[mod_id]; - break; - default : - goto error; - } - - return; - - error: - LOG_E(FLEXRAN_AGENT, "unknown RAN name %d\n", ran); -} - -int flexran_get_current_time_ms (mid_t mod_id, int subframe_flag){ - - if (subframe_flag == 1){ - return ((eNB_MAC_INST *)enb[mod_id])->frame*10 + ((eNB_MAC_INST *)enb[mod_id])->subframe; - }else { - return ((eNB_MAC_INST *)enb[mod_id])->frame*10; - } - -} - -unsigned int flexran_get_current_frame (mid_t mod_id) { - - // #warning "SFN will not be in [0-1023] when oaisim is used" - return ((eNB_MAC_INST *)enb[mod_id])->frame; - -} - -unsigned int flexran_get_current_system_frame_num(mid_t mod_id) { - return (flexran_get_current_frame(mod_id) %1024); -} - -unsigned int flexran_get_current_subframe (mid_t mod_id) { - - return ((eNB_MAC_INST *)enb[mod_id])->subframe; - -} - -uint16_t flexran_get_sfn_sf (mid_t mod_id) { - - frame_t frame; - sub_frame_t subframe; - uint16_t sfn_sf, frame_mask, sf_mask; - - frame = (frame_t) flexran_get_current_system_frame_num(mod_id); - subframe = (sub_frame_t) flexran_get_current_subframe(mod_id); - frame_mask = ((1<<12) - 1); - sf_mask = ((1<<4) - 1); - sfn_sf = (subframe & sf_mask) | ((frame & frame_mask) << 4); - - return sfn_sf; -} - -uint16_t flexran_get_future_sfn_sf (mid_t mod_id, int ahead_of_time) { - - frame_t frame; - sub_frame_t subframe; - uint16_t sfn_sf, frame_mask, sf_mask; - - frame = (frame_t) flexran_get_current_system_frame_num(mod_id); - subframe = (sub_frame_t) flexran_get_current_subframe(mod_id); - - subframe = ((subframe + ahead_of_time) % 10); - - if (subframe < flexran_get_current_subframe(mod_id)) { - frame = (frame + 1) % 1024; - } - - int additional_frames = ahead_of_time / 10; - frame = (frame + additional_frames) % 1024; - - frame_mask = ((1<<12) - 1); - sf_mask = ((1<<4) - 1); - sfn_sf = (subframe & sf_mask) | ((frame & frame_mask) << 4); - - return sfn_sf; -} - -int flexran_get_num_ues (mid_t mod_id){ - - return ((UE_list_t *)enb_ue[mod_id])->num_UEs; -} - -int flexran_get_ue_crnti (mid_t mod_id, mid_t ue_id) { - - return UE_RNTI(mod_id, ue_id); -} - -int flexran_get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid) { - - return ((UE_list_t *)enb_ue[mod_id])->UE_template[UE_PCCID(mod_id,ue_id)][ue_id].bsr_info[lcid]; -} - -int flexran_get_ue_phr (mid_t mod_id, mid_t ue_id) { - - return ((UE_list_t *)enb_ue[mod_id])->UE_template[UE_PCCID(mod_id,ue_id)][ue_id].phr_info; -} - -int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, 0, UE_RNTI(mod_id, ue_id)); - return eNB_UE_stats->DL_cqi[0]; - - // return ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].dl_cqi; -} - -int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); - mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id,frame,ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0); - return rlc_status.bytes_in_buffer; -} - -int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); - mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, ENB_FLAG_YES, MBMS_FLAG_NO, channel_id, 0); - return rlc_status.head_sdu_creation_time; -} - -short flexran_get_TA(mid_t mod_id, mid_t ue_id, int CC_id) { - - UE_list_t *UE_list=&eNB_mac_inst[mod_id].UE_list; - int rnti; - - rnti = flexran_get_ue_crnti(mod_id, ue_id); - - LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - //ue_sched_ctl->ta_timer = 20; // wait 20 subframes before taking TA measurement from PHY - switch (PHY_vars_eNB_g[mod_id][CC_id]->frame_parms.N_RB_DL) { - case 6: - return eNB_UE_stats->timing_advance_update; - case 15: - return eNB_UE_stats->timing_advance_update/2; - case 25: - return eNB_UE_stats->timing_advance_update/4; - case 50: - return eNB_UE_stats->timing_advance_update/8; - case 75: - return eNB_UE_stats->timing_advance_update/12; - case 100: - if (PHY_vars_eNB_g[mod_id][CC_id]->frame_parms.threequarter_fs == 0) { - return eNB_UE_stats->timing_advance_update/16; - } else { - return eNB_UE_stats->timing_advance_update/12; - } - default: - return 0; - } -} - -void flexran_update_TA(mid_t mod_id, mid_t ue_id, int CC_id) { - - UE_list_t *UE_list=&eNB_mac_inst[mod_id].UE_list; - UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[ue_id]; - - if (ue_sched_ctl->ta_timer == 0) { - - // WE SHOULD PROTECT the eNB_UE_stats with a mutex here ... - // LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - //ue_sched_ctl->ta_timer = 20; // wait 20 subframes before taking TA measurement from PHY - ue_sched_ctl->ta_update = flexran_get_TA(mod_id, ue_id, CC_id); - - // clear the update in case PHY does not have a new measurement after timer expiry - // eNB_UE_stats->timing_advance_update = 0; - } else { - ue_sched_ctl->ta_timer--; - ue_sched_ctl->ta_update = 0; // don't trigger a timing advance command - } -} - -int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) { - - UE_list_t *UE_list = &eNB_mac_inst[mod_id].UE_list; - - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); - - if (eNB_UE_stats == NULL) { - return 0; - } - - if (flexran_get_TA(mod_id, ue_id, CC_id) != 0) { - return PROTOCOL__FLEX_CE_TYPE__FLPCET_TA; - } else { - return 0; - } - -} - -int flexran_get_active_CC(mid_t mod_id, mid_t ue_id) { - return ((UE_list_t *)enb_ue[mod_id])->numactiveCCs[ue_id]; -} - -int flexran_get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); - - if (eNB_UE_stats == NULL) { - return 0; - } - - return eNB_UE_stats[CC_id].rank; -} - -int flexran_get_tpc(mid_t mod_id, mid_t ue_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - int32_t normalized_rx_power, target_rx_power; - int tpc = 1; - - int pCCid = UE_PCCID(mod_id,ue_id); - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, pCCid, rnti); - - target_rx_power = mac_xface->get_target_pusch_rx_power(mod_id,pCCid); - - if (eNB_UE_stats == NULL) { - normalized_rx_power = target_rx_power; - } else if (eNB_UE_stats->UL_rssi != NULL) { - normalized_rx_power = eNB_UE_stats->UL_rssi[0]; - } else { - normalized_rx_power = target_rx_power; - } - - if (normalized_rx_power>(target_rx_power+1)) { - tpc = 0; //-1 - } else if (normalized_rx_power<(target_rx_power-1)) { - tpc = 2; //+1 - } else { - tpc = 1; //0 - } - return tpc; -} - -int flexran_get_harq(const mid_t mod_id, - const uint8_t CC_id, - const mid_t ue_id, - const int frame, - const uint8_t subframe, - uint8_t *id, - uint8_t *round) { //flag_id_status = 0 then id, else status - /*TODO: Add int TB in function parameters to get the status of the second TB. This can be done to by editing in - * get_ue_active_harq_pid function in line 272 file: phy_procedures_lte_eNB.c to add - * DLSCH_ptr = PHY_vars_eNB_g[Mod_id][CC_id]->dlsch_eNB[(uint32_t)UE_id][1];*/ - - uint8_t harq_pid; - uint8_t harq_round; - - - uint16_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&harq_round,openair_harq_DL); - - *id = harq_pid; - *round = harq_round; - /* if (round > 0) { */ - /* *status = 1; */ - /* } else { */ - /* *status = 0; */ - /* } */ - - /* return 0; */ - return *round; -} - -int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - - if (eNB_UE_stats == NULL) { - return -1; - } - - // if(eNB_UE_stats->Po_PUCCH_update == 1) { - return eNB_UE_stats->Po_PUCCH_dBm; - //} - //else - // return -1; -} - -int flexran_get_p0_nominal_pucch(mid_t mod_id, int CC_id) { - int32_t pucch_rx_received = mac_xface->get_target_pucch_rx_power(mod_id, CC_id); - return pucch_rx_received; -} - -int flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, int CC_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - return eNB_UE_stats->Po_PUCCH_update; -} - -int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - eNB_UE_stats->Po_PUCCH_update = 0; - - return 0; -} - - -/* - * ************************************ - * Get Messages for eNB Configuration Reply - * ************************************ - */ - -int flexran_get_hopping_offset(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pusch_config_common.pusch_HoppingOffset; -} - -int flexran_get_hopping_mode(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pusch_config_common.hoppingMode; -} - -int flexran_get_n_SB(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pusch_config_common.n_SB; -} - -int flexran_get_enable64QAM(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pusch_config_common.enable64QAM; -} - -int flexran_get_phich_duration(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->phich_config_common.phich_duration; -} - -int flexran_get_phich_resource(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - if(frame_parms->phich_config_common.phich_resource == oneSixth) - return 0; - else if(frame_parms->phich_config_common.phich_resource == half) - return 1; - else if(frame_parms->phich_config_common.phich_resource == one) - return 2; - else if(frame_parms->phich_config_common.phich_resource == two) - return 3; - - return -1; -} - -int flexran_get_n1pucch_an(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pucch_config_common.n1PUCCH_AN; -} - -int flexran_get_nRB_CQI(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pucch_config_common.nRB_CQI; -} - -int flexran_get_deltaPUCCH_Shift(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pucch_config_common.deltaPUCCH_Shift; -} - -int flexran_get_prach_ConfigIndex(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex; -} - -int flexran_get_prach_FreqOffset(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset; -} - -int flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->maxHARQ_Msg3Tx; -} - -int flexran_get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->Ncp_UL; -} - -int flexran_get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->Ncp; -} - -int flexran_get_cell_id(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->Nid_cell; -} - -int flexran_get_srs_BandwidthConfig(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->soundingrs_ul_config_common.srs_BandwidthConfig; -} - -int flexran_get_srs_SubframeConfig(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->soundingrs_ul_config_common.srs_SubframeConfig; -} - -int flexran_get_srs_MaxUpPts(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->soundingrs_ul_config_common.srs_MaxUpPts; -} - -int flexran_get_N_RB_DL(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->N_RB_DL; -} - -int flexran_get_N_RB_UL(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->N_RB_UL; -} - -int flexran_get_N_RBG(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->N_RBG; -} - -int flexran_get_subframe_assignment(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->tdd_config; -} - -int flexran_get_special_subframe_assignment(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->tdd_config_S; -} - -int flexran_get_ra_ResponseWindowSize(mid_t mod_id, int CC_id) { - return enb_config_get()->properties[mod_id]->rach_raResponseWindowSize[CC_id]; -} - -int flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id) { - return enb_config_get()->properties[mod_id]->rach_macContentionResolutionTimer[CC_id]; -} - -int flexran_get_duplex_mode(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - if(frame_parms->frame_type == TDD) - return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD; - else if (frame_parms->frame_type == FDD) - return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_FDD; - - return -1; -} - -long flexran_get_si_window_length(mid_t mod_id, int CC_id) { - return ((eNB_RRC_INST *)enb_rrc[mod_id])->carrier[CC_id].sib1->si_WindowLength; -} - -int flexran_get_sib1_length(mid_t mod_id, int CC_id) { - return ((eNB_RRC_INST *)enb_rrc[mod_id])->carrier[CC_id].sizeof_SIB1; -} - -int flexran_get_num_pdcch_symb(mid_t mod_id, int CC_id) { - /* TODO: This should return the number of PDCCH symbols initially used by the cell CC_id */ - return 0; - //(PHY_vars_UE_g[mod_id][CC_id]->lte_ue_pdcch_vars[mod_id]->num_pdcch_symbols); -} - - - -/* - * ************************************ - * Get Messages for UE Configuration Reply - * ************************************ - */ - - -int flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.mac_MainConfig != NULL) { - return ue_context_p->ue_context.mac_MainConfig->timeAlignmentTimerDedicated; - } else { - return -1; - } - } else { - return -1; - } -} - -int flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.measGapConfig != NULL) { - if(ue_context_p->ue_context.measGapConfig->present == MeasGapConfig_PR_setup) { - if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp0) { - return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP1; - } else if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp1) { - return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP2; - } else { - return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF; - } - } - } - } - return -1; -} - - -int flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.measGapConfig != NULL){ - if(ue_context_p->ue_context.measGapConfig->present == MeasGapConfig_PR_setup) { - if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp0) { - return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.choice.gp0; - } else if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp1) { - return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.choice.gp0; - } - } - } - } - return -1; -} - -int flexran_get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id) { - return ((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateDL; -} - -int flexran_get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id) { - return ((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateUL; -} - -int flexran_get_half_duplex(mid_t ue_id) { - // TODO - //int halfduplex = 0; - //int bands_to_scan = ((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.count; - //for (int i =0; i < bands_to_scan; i++){ - //if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.array[i]->halfDuplex > 0) - // halfduplex = 1; - //} - //return halfduplex; - return 0; -} - -int flexran_get_intra_sf_hopping(mid_t ue_id) { - //TODO:Get proper value - //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); - //return (0 & ( 1 << (31))); - return 0; -} - -int flexran_get_type2_sb_1(mid_t ue_id) { - //TODO:Get proper value - //uint8_t temp = 0; - //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); - //return (temp & ( 1 << (11))); - return 0; -} - -int flexran_get_ue_category(mid_t ue_id) { - //TODO:Get proper value - //return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->ue_Category); - return 0; -} - -int flexran_get_res_alloc_type1(mid_t ue_id) { - //TODO:Get proper value - //uint8_t temp = 0; - //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); - //return (temp & ( 1 << (30))); - return 0; -} - -int flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode; - } else { - return -1; - } - } else { - return -1; - } -} - -int flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.mac_MainConfig != NULL){ - return ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config->ttiBundling; - } else { - return -1; - } - } - else { - return -1; - } -} - -int flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.mac_MainConfig != NULL){ - return *ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config->maxHARQ_Tx; - } - } - return -1; -} - -int flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_ACK_Index; - } else { - return -1; - } - } else { - return -1; - } -} - -int flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index; - } else { - return -1; - } - } else { - return -1; - } -} - -int flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index; - } else { - return -1; - } - } - else { - return -1; - } -} - -int flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - if (ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic != NULL) { - return ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.simultaneousAckNackAndCQI; - } - } - } - return -1; -} - -int flexran_get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id) { - return (&eNB_rrc_inst[mod_id])->carrier[0].sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; -} - -int flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return *ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic; - } - } - return -1; -} - -int flexran_get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) { - // TODO: This needs fixing - return -1; - - /* struct rrc_eNB_ue_context_s* ue_context_p = NULL; */ - /* uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); */ - - /* ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); */ - - /* if(ue_context_p != NULL) { */ - /* if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ */ - /* return ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode; */ - /* } else { */ - /* return -1; */ - /* } */ - /* } else { */ - /* return -1; */ - /* } */ -} - -int flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->ackNackRepetition.choice.setup.repetitionFactor; - } else { - return -1; - } - } else { - return -1; - } -} - -int flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id) { - //TODO: need to double check - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.mac_MainConfig != NULL){ - if(ue_context_p->ue_context.mac_MainConfig->ext2 != NULL){ - long val = (*(ue_context_p->ue_context.mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10)); - if (val > 0) { - return 1; - } - } - } - } - return -1; -} - -int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - if(ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup == AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_closedLoop) { - return 2; - } else if(ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup == AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_openLoop) { - return 1; - } else { - return 0; - } - } else { - return -1; - } - } else { - return -1; - } -} - -int flexran_get_lcg(mid_t ue_id, mid_t lc_id) { - if (UE_mac_inst == NULL) { - return -1; - } - if(UE_mac_inst[ue_id].logicalChannelConfig[lc_id] != NULL) { - return *UE_mac_inst[ue_id].logicalChannelConfig[lc_id]->ul_SpecificParameters->logicalChannelGroup; - } else { - return -1; - } -} - -int flexran_get_direction(mid_t ue_id, mid_t lc_id) { - /*TODO: fill with the value for the rest of LCID*/ - if(lc_id == DCCH || lc_id == DCCH1) { - return 2; - } else if(lc_id == DTCH) { - return 1; - } else { - return -1; - } -} - -int flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { - int size; - Protocol__FlexranMessage *msg; - Protocol__FlexHeader *header; - void *data; - int priority = 0; - - int xid = 0; - - if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_UE_STATE_CHANGE, &header) != 0) - goto error; - - Protocol__FlexUeStateChange *ue_state_change_msg; - ue_state_change_msg = malloc(sizeof(Protocol__FlexUeStateChange)); - if(ue_state_change_msg == NULL) { - goto error; - } - protocol__flex_ue_state_change__init(ue_state_change_msg); - ue_state_change_msg->has_type = 1; - ue_state_change_msg->type = state_change; - - Protocol__FlexUeConfig *config; - config = malloc(sizeof(Protocol__FlexUeConfig)); - if (config == NULL) { - goto error; - } - protocol__flex_ue_config__init(config); - if (state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED) { - // Simply set the rnti of the UE - config->has_rnti = 1; - config->rnti = rnti; - } else if (state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_UPDATED - || state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_ACTIVATED) { - int i = find_UE_id(mod_id, rnti); - config->has_rnti = 1; - config->rnti = rnti; - if(flexran_get_time_alignment_timer(mod_id,i) != -1) { - config->time_alignment_timer = flexran_get_time_alignment_timer(mod_id,i); - config->has_time_alignment_timer = 1; - } - if(flexran_get_meas_gap_config(mod_id,i) != -1){ - config->meas_gap_config_pattern = flexran_get_meas_gap_config(mod_id,i); - config->has_meas_gap_config_pattern = 1; - } - if(config->has_meas_gap_config_pattern == 1 && - config->meas_gap_config_pattern != PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF) { - config->meas_gap_config_sf_offset = flexran_get_meas_gap_config_offset(mod_id,i); - config->has_meas_gap_config_sf_offset = 1; - } - //TODO: Set the SPS configuration (Optional) - //Not supported for now, so we do not set it - - //TODO: Set the SR configuration (Optional) - //We do not set it for now - - //TODO: Set the CQI configuration (Optional) - //We do not set it for now - - if(flexran_get_ue_transmission_mode(mod_id,i) != -1) { - config->transmission_mode = flexran_get_ue_transmission_mode(mod_id,i); - config->has_transmission_mode = 1; - } - - config->ue_aggregated_max_bitrate_ul = flexran_get_ue_aggregated_max_bitrate_ul(mod_id,i); - config->has_ue_aggregated_max_bitrate_ul = 1; - - config->ue_aggregated_max_bitrate_dl = flexran_get_ue_aggregated_max_bitrate_dl(mod_id,i); - config->has_ue_aggregated_max_bitrate_dl = 1; - - //TODO: Set the UE capabilities - Protocol__FlexUeCapabilities *c_capabilities; - c_capabilities = malloc(sizeof(Protocol__FlexUeCapabilities)); - protocol__flex_ue_capabilities__init(c_capabilities); - //TODO: Set half duplex (FDD operation) - c_capabilities->has_half_duplex = 0; - c_capabilities->half_duplex = 1;//flexran_get_half_duplex(i); - //TODO: Set intra-frame hopping flag - c_capabilities->has_intra_sf_hopping = 0; - c_capabilities->intra_sf_hopping = 1;//flexran_get_intra_sf_hopping(i); - //TODO: Set support for type 2 hopping with n_sb > 1 - c_capabilities->has_type2_sb_1 = 0; - c_capabilities->type2_sb_1 = 1;//flexran_get_type2_sb_1(i); - //TODO: Set ue category - c_capabilities->has_ue_category = 0; - c_capabilities->ue_category = 1;//flexran_get_ue_category(i); - //TODO: Set UE support for resource allocation type 1 - c_capabilities->has_res_alloc_type1 = 0; - c_capabilities->res_alloc_type1 = 1;//flexran_get_res_alloc_type1(i); - //Set the capabilites to the message - config->capabilities = c_capabilities; - - if(flexran_get_ue_transmission_antenna(mod_id,i) != -1) { - config->has_ue_transmission_antenna = 1; - config->ue_transmission_antenna = flexran_get_ue_transmission_antenna(mod_id,i); - } - - if(flexran_get_tti_bundling(mod_id,i) != -1) { - config->has_tti_bundling = 1; - config->tti_bundling = flexran_get_tti_bundling(mod_id,i); - } - - if(flexran_get_maxHARQ_TX(mod_id,i) != -1){ - config->has_max_harq_tx = 1; - config->max_harq_tx = flexran_get_maxHARQ_TX(mod_id,i); - } - - if(flexran_get_beta_offset_ack_index(mod_id,i) != -1) { - config->has_beta_offset_ack_index = 1; - config->beta_offset_ack_index = flexran_get_beta_offset_ack_index(mod_id,i); - } - - if(flexran_get_beta_offset_ri_index(mod_id,i) != -1) { - config->has_beta_offset_ri_index = 1; - config->beta_offset_ri_index = flexran_get_beta_offset_ri_index(mod_id,i); - } - - if(flexran_get_beta_offset_cqi_index(mod_id,i) != -1) { - config->has_beta_offset_cqi_index = 1; - config->beta_offset_cqi_index = flexran_get_beta_offset_cqi_index(mod_id,i); - } - - if(flexran_get_ack_nack_simultaneous_trans(mod_id,i) != -1) { - config->has_ack_nack_simultaneous_trans = 1; - config->ack_nack_simultaneous_trans = flexran_get_ack_nack_simultaneous_trans(mod_id,i); - } - - if(flexran_get_simultaneous_ack_nack_cqi(mod_id,i) != -1) { - config->has_simultaneous_ack_nack_cqi = 1; - config->simultaneous_ack_nack_cqi = flexran_get_simultaneous_ack_nack_cqi(mod_id,i); - } - - if(flexran_get_aperiodic_cqi_rep_mode(mod_id,i) != -1) { - config->has_aperiodic_cqi_rep_mode = 1; - int mode = flexran_get_aperiodic_cqi_rep_mode(mod_id,i); - if (mode > 4) { - config->aperiodic_cqi_rep_mode = PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_NONE; - } else { - config->aperiodic_cqi_rep_mode = mode; - } - } - - if(flexran_get_tdd_ack_nack_feedback(mod_id, i) != -1) { - config->has_tdd_ack_nack_feedback = 1; - config->tdd_ack_nack_feedback = flexran_get_tdd_ack_nack_feedback(mod_id,i); - } - - if(flexran_get_ack_nack_repetition_factor(mod_id, i) != -1) { - config->has_ack_nack_repetition_factor = 1; - config->ack_nack_repetition_factor = flexran_get_ack_nack_repetition_factor(mod_id,i); - } - - if(flexran_get_extended_bsr_size(mod_id, i) != -1) { - config->has_extended_bsr_size = 1; - config->extended_bsr_size = flexran_get_extended_bsr_size(mod_id,i); - } - - config->has_pcell_carrier_index = 1; - config->pcell_carrier_index = UE_PCCID(mod_id, i); - //TODO: Set carrier aggregation support (boolean) - config->has_ca_support = 0; - config->ca_support = 0; - if(config->has_ca_support){ - //TODO: Set cross carrier scheduling support (boolean) - config->has_cross_carrier_sched_support = 1; - config->cross_carrier_sched_support = 0; - //TODO: Set secondary cells configuration - // We do not set it for now. No carrier aggregation support - - //TODO: Set deactivation timer for secondary cell - config->has_scell_deactivation_timer = 0; - config->scell_deactivation_timer = 0; - } - } else if (state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_MOVED) { - // TODO: Not supported for now. Leave blank - } - - ue_state_change_msg->config = config; - msg = malloc(sizeof(Protocol__FlexranMessage)); - if (msg == NULL) { - goto error; - } - protocol__flexran_message__init(msg); - msg->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG; - msg->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; - msg->ue_state_change_msg = ue_state_change_msg; - - data = flexran_agent_pack_message(msg, &size); - /*Send sr info using the MAC channel of the eNB*/ - if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) { - goto error; - } - - LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); - return 0; - error: - LOG_D(FLEXRAN_AGENT, "Could not send UE state message\n"); - return -1; -} - - int flexran_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { @@ -2138,191 +1045,38 @@ int flexran_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__F } +int flexran_agent_rrc_measurement(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { -/* - * timer primitives - */ + protocol_ctxt_t ctxt; -//struct flexran_agent_map agent_map; -flexran_agent_timer_instance_t timer_instance; -int agent_timer_init = 0; -err_code_t flexran_agent_init_timer(void){ + Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; + Protocol__FlexRrcTriggering *triggering = input->rrc_triggering; + + agent_reconf_rrc *reconf_param = malloc(sizeof(agent_reconf_rrc)); - LOG_I(FLEXRAN_AGENT, "init RB tree\n"); - if (!agent_timer_init) { - RB_INIT(&timer_instance.flexran_agent_head); - agent_timer_init = 1; + + reconf_param->trigger_policy = triggering->rrc_trigger; + + struct rrc_eNB_ue_context_s *ue_context_p = NULL; + + RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(eNB_rrc_inst[mod_id].rrc_ue_head)){ + + + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, mod_id, ENB_FLAG_YES, ue_context_p->ue_context.rnti, flexran_get_current_frame(mod_id), flexran_get_current_subframe (mod_id), mod_id); + + flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(&ctxt, ue_context_p, 0, reconf_param); + } - - return PROTOCOL__FLEXRAN_ERR__NO_ERR; -} - -RB_GENERATE(flexran_agent_map, flexran_agent_timer_element_s, entry, flexran_agent_compare_timer); - -/* The timer_id might not be the best choice for the comparison */ -int flexran_agent_compare_timer(struct flexran_agent_timer_element_s *a, struct flexran_agent_timer_element_s *b){ - - if (a->timer_id < b->timer_id) return -1; - if (a->timer_id > b->timer_id) return 1; - - // equal timers + + + *msg = NULL; return 0; } -err_code_t flexran_agent_create_timer(uint32_t interval_sec, - uint32_t interval_usec, - agent_id_t agent_id, - instance_t instance, - uint32_t timer_type, - xid_t xid, - flexran_agent_timer_callback_t cb, - void* timer_args, - long *timer_id){ - - struct flexran_agent_timer_element_s *e = calloc(1, sizeof(*e)); - DevAssert(e != NULL); - -//uint32_t timer_id; - int ret=-1; - - if ((interval_sec == 0) && (interval_usec == 0 )) - return TIMER_NULL; - - if (timer_type >= FLEXRAN_AGENT_TIMER_TYPE_MAX) - return TIMER_TYPE_INVALIDE; - - if (timer_type == FLEXRAN_AGENT_TIMER_TYPE_ONESHOT){ - ret = timer_setup(interval_sec, - interval_usec, - TASK_FLEXRAN_AGENT, - instance, - TIMER_ONE_SHOT, - timer_args, - timer_id); + +int flexran_agent_destroy_rrc_measurement(Protocol__FlexranMessage *msg){ - e->type = TIMER_ONE_SHOT; - } - else if (timer_type == FLEXRAN_AGENT_TIMER_TYPE_PERIODIC ){ - ret = timer_setup(interval_sec, - interval_usec, - TASK_FLEXRAN_AGENT, - instance, - TIMER_PERIODIC, - timer_args, - timer_id); - - e->type = TIMER_PERIODIC; - } - - if (ret < 0 ) { - return TIMER_SETUP_FAILED; - } - - e->agent_id = agent_id; - e->instance = instance; - e->state = FLEXRAN_AGENT_TIMER_STATE_ACTIVE; - e->timer_id = *timer_id; - e->xid = xid; - e->timer_args = timer_args; - e->cb = cb; - /*element should be a real pointer*/ - RB_INSERT(flexran_agent_map, &timer_instance.flexran_agent_head, e); - - LOG_I(FLEXRAN_AGENT,"Created a new timer with id 0x%lx for agent %d, instance %d \n", - e->timer_id, e->agent_id, e->instance); - - return 0; -} - -err_code_t flexran_agent_destroy_timer(long timer_id){ - - struct flexran_agent_timer_element_s *e = get_timer_entry(timer_id); - - if (e != NULL ) { - RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); - flexran_agent_destroy_flexran_message(e->timer_args->msg); - free(e); - } - - if (timer_remove(timer_id) < 0 ) - goto error; - - return 0; - - error: - LOG_E(FLEXRAN_AGENT, "timer can't be removed\n"); - return TIMER_REMOVED_FAILED ; -} - -err_code_t flexran_agent_destroy_timer_by_task_id(xid_t xid) { - struct flexran_agent_timer_element_s *e = NULL; - long timer_id; - RB_FOREACH(e, flexran_agent_map, &timer_instance.flexran_agent_head) { - if (e->xid == xid) { - timer_id = e->timer_id; - RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); - flexran_agent_destroy_flexran_message(e->timer_args->msg); - free(e); - if (timer_remove(timer_id) < 0 ) { - goto error; - } - } - } - return 0; - - error: - LOG_E(FLEXRAN_AGENT, "timer can't be removed\n"); - return TIMER_REMOVED_FAILED ; -} - -err_code_t flexran_agent_destroy_timers(void){ - - struct flexran_agent_timer_element_s *e = NULL; - - RB_FOREACH(e, flexran_agent_map, &timer_instance.flexran_agent_head) { - RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); - timer_remove(e->timer_id); - flexran_agent_destroy_flexran_message(e->timer_args->msg); - free(e); - } - - return 0; - -} - -void flexran_agent_sleep_until(struct timespec *ts, int delay) { - ts->tv_nsec += delay; - if(ts->tv_nsec >= 1000*1000*1000){ - ts->tv_nsec -= 1000*1000*1000; - ts->tv_sec++; - } - clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts, NULL); } -err_code_t flexran_agent_stop_timer(long timer_id){ - - struct flexran_agent_timer_element_s *e=NULL; - struct flexran_agent_timer_element_s search; - memset(&search, 0, sizeof(struct flexran_agent_timer_element_s)); - search.timer_id = timer_id; - e = RB_FIND(flexran_agent_map, &timer_instance.flexran_agent_head, &search); - - if (e != NULL ) { - e->state = FLEXRAN_AGENT_TIMER_STATE_STOPPED; - } - - timer_remove(timer_id); - - return 0; -} - -struct flexran_agent_timer_element_s * get_timer_entry(long timer_id) { - - struct flexran_agent_timer_element_s search; - memset(&search, 0, sizeof(struct flexran_agent_timer_element_s)); - search.timer_id = timer_id; - - return RB_FIND(flexran_agent_map, &timer_instance.flexran_agent_head, &search); -} diff --git a/openair2/ENB_APP/flexran_agent_common.h b/openair2/ENB_APP/flexran_agent_common.h index abe5a05b44..4f2b9c71bb 100644 --- a/openair2/ENB_APP/flexran_agent_common.h +++ b/openair2/ENB_APP/flexran_agent_common.h @@ -21,8 +21,8 @@ /*! \file flexran_agent_common.h * \brief common message primitves and utilities - * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein - * \date 2016 + * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein and shahab SHARIAT BAGHERI + * \date 2017 * \version 0.1 */ @@ -60,6 +60,19 @@ typedef int (*flexran_agent_message_destruction_callback)( Protocol__FlexranMessage *msg ); +typedef struct { + + uint8_t is_initialized; + volatile uint8_t cont_update; + xid_t xid; + Protocol__FlexranMessage *stats_req; + Protocol__FlexranMessage *prev_stats_reply; + + pthread_mutex_t *mutex; +} stats_updates_context_t; + +stats_updates_context_t stats_context[NUM_MAX_ENB]; + /********************************** * FlexRAN protocol messages helper * functions and generic handlers @@ -116,10 +129,6 @@ int flexran_agent_destroy_ue_config_request(Protocol__FlexranMessage *msg); /* TODO: Need to define and implement destructor */ int flexran_agent_destroy_lc_config_request(Protocol__FlexranMessage *msg); -/* UE state change message constructor and destructor */ -int flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change); -int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg); - /* Control delegation message constructor and destructor */ int flexran_agent_control_delegation(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int flexran_agent_destroy_control_delegation(Protocol__FlexranMessage *msg); @@ -128,6 +137,11 @@ int flexran_agent_destroy_control_delegation(Protocol__FlexranMessage *msg); int flexran_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int flexran_agent_destroy_agent_reconfiguration(Protocol__FlexranMessage *msg); +/* rrc triggering measurement message constructor and destructor */ +int flexran_agent_rrc_measurement(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int flexran_agent_destroy_rrc_measurement(Protocol__FlexranMessage *msg); + + /* FlexRAN protocol message dispatcher function */ Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id, uint8_t *data, @@ -136,367 +150,22 @@ Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id, /* Function to be used to send a message to a dispatcher once the appropriate event is triggered. */ Protocol__FlexranMessage *flexran_agent_handle_timed_task(void *args); +/*Top level Statistics hanlder*/ +int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +/* Function to be used to handle reply message . */ +int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg); +/* Statistics request protocol message constructor and destructor */ +int flexran_agent_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg); +int flexran_agent_destroy_stats_request(Protocol__FlexranMessage *msg); -/**************************** - * get generic info from RAN - ****************************/ +int flexran_agent_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg); +int flexran_agent_destroy_stats_request(Protocol__FlexranMessage *msg); + +err_code_t flexran_agent_enable_cont_stats_update(mid_t mod_id, xid_t xid, stats_request_config_t *stats_req) ; -void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran); - -int flexran_get_current_time_ms (mid_t mod_id, int subframe_flag); - -/*Return the current frame number - *Could be using implementation specific numbering of frames - */ -unsigned int flexran_get_current_frame(mid_t mod_id); - -/*Return the current SFN (0-1023)*/ -unsigned int flexran_get_current_system_frame_num(mid_t mod_id); - -unsigned int flexran_get_current_subframe(mid_t mod_id); - -/*Return the frame and subframe number in compact 16-bit format. - Bits 0-3 subframe, rest for frame. Required by FlexRAN protocol*/ -uint16_t flexran_get_sfn_sf (mid_t mod_id); - -/* Return a future frame and subframe number that is ahead_of_time - subframes later in compact 16-bit format. Bits 0-3 subframe, - rest for frame */ -uint16_t flexran_get_future_sfn_sf(mid_t mod_id, int ahead_of_time); - -/* Return the number of attached UEs */ -int flexran_get_num_ues(mid_t mod_id); - -/* Get the rnti of a UE with id ue_id */ -int flexran_get_ue_crnti (mid_t mod_id, mid_t ue_id); - -/* Get the RLC buffer status report of a ue for a designated - logical channel id */ -int flexran_get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid); - -/* Get power headroom of UE with id ue_id */ -int flexran_get_ue_phr (mid_t mod_id, mid_t ue_id); - -/* Get the UE wideband CQI */ -int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id); - -/* Get the transmission queue size for a UE with a channel_id logical channel id */ -int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); - -/* Get the head of line delay for a UE with a channel_id logical channel id */ -int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); - -/* Check the status of the timing advance for a UE */ -short flexran_get_TA(mid_t mod_id, mid_t ue_id, int CC_id); - -/* Update the timing advance status (find out whether a timing advance command is required) */ -void flexran_update_TA(mid_t mod_id, mid_t ue_id, int CC_id); - -/* Return timing advance MAC control element for a designated cell and UE */ -int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id, int CC_id); - -/* Get the number of active component carriers for a specific UE */ -int flexran_get_active_CC(mid_t mod_id, mid_t ue_id); - -/* Get the rank indicator for a designated cell and UE */ -int flexran_get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id); - -/* See TS 36.213, section 10.1 */ -int flexran_get_n1pucch_an(mid_t mod_id, int CC_id); - -/* See TS 36.211, section 5.4 */ -int flexran_get_nRB_CQI(mid_t mod_id, int CC_id); - -/* See TS 36.211, section 5.4 */ -int flexran_get_deltaPUCCH_Shift(mid_t mod_id, int CC_id); - -/* See TS 36.211, section 5.7.1 */ -int flexran_get_prach_ConfigIndex(mid_t mod_id, int CC_id); - -/* See TS 36.211, section 5.7.1 */ -int flexran_get_prach_FreqOffset(mid_t mod_id, int CC_id); - -/* See TS 36.321 */ -int flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id); - -/* Get the length of the UL cyclic prefix */ -int flexran_get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id); - -/* Get the length of the DL cyclic prefix */ -int flexran_get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id); - -/* Get the physical cell id of a cell */ -int flexran_get_cell_id(mid_t mod_id, int CC_id); - -/* See TS 36.211, section 5.5.3.2 */ -int flexran_get_srs_BandwidthConfig(mid_t mod_id, int CC_id); - -/* See TS 36.211, table 5.5.3.3-1 and 2 */ -int flexran_get_srs_SubframeConfig(mid_t mod_id, int CC_id); - -/* Boolean value. See TS 36.211, - section 5.5.3.2. TDD only */ -int flexran_get_srs_MaxUpPts(mid_t mod_id, int CC_id); - -/* Get number of DL resource blocks */ -int flexran_get_N_RB_DL(mid_t mod_id, int CC_id); - -/* Get number of UL resource blocks */ -int flexran_get_N_RB_UL(mid_t mod_id, int CC_id); - -/* Get number of resource block groups */ -int flexran_get_N_RBG(mid_t mod_id, int CC_id); - -/* Get DL/UL subframe assignment. TDD only */ -int flexran_get_subframe_assignment(mid_t mod_id, int CC_id); - -/* TDD only. See TS 36.211, table 4.2.1 */ -int flexran_get_special_subframe_assignment(mid_t mod_id, int CC_id); - -/* Get the duration of the random access response window in subframes */ -int flexran_get_ra_ResponseWindowSize(mid_t mod_id, int CC_id); - -/* Get timer used for random access */ -int flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id); - -/* Get type of duplex mode (FDD/TDD) */ -int flexran_get_duplex_mode(mid_t mod_id, int CC_id); - -/* Get the SI window length */ -long flexran_get_si_window_length(mid_t mod_id, int CC_id); - -/* Get the number of PDCCH symbols configured for the cell */ -int flexran_get_num_pdcch_symb(mid_t mod_id, int CC_id); - -/* See TS 36.213, sec 5.1.1.1 */ -int flexran_get_tpc(mid_t mod_id, mid_t ue_id); - -/* Get the first available HARQ process for a specific cell and UE during - a designated frame and subframe. Returns 0 for success. The id and the - status of the HARQ process are stored in id and status respectively */ -int flexran_get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, - const int frame, const uint8_t subframe, unsigned char *id, unsigned char *round); - -/* Uplink power control management*/ -int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id); - -int flexran_get_p0_nominal_pucch(mid_t mod_id, int CC_id); - -int flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, int CC_id); - -int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id); - - -/* - * ************************************ - * Get Messages for UE Configuration Reply - * ************************************ - */ - -/* Get timer in subframes. Controls the synchronization - status of the UE, not the actual timing - advance procedure. See TS 36.321 */ -int flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id); - -/* Get measurement gap configuration. See TS 36.133 */ -int flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id); - -/* Get measurement gap configuration offset if applicable */ -int flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id); - -/* DL aggregated bit-rate of non-gbr bearer - per UE. See TS 36.413 */ -int flexran_get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id); - -/* UL aggregated bit-rate of non-gbr bearer - per UE. See TS 36.413 */ -int flexran_get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id); - -/* Only half-duplex support. FDD - operation. Boolean value */ -int flexran_get_half_duplex(mid_t ue_id); - -/* Support of intra-subframe hopping. - Boolean value */ -int flexran_get_intra_sf_hopping(mid_t ue_id); - -/* UE support for type 2 hopping with - n_sb>1 */ -int flexran_get_type2_sb_1(mid_t ue_id); - -/* Get the UE category */ -int flexran_get_ue_category(mid_t ue_id); - -/* UE support for resource allocation - type 1 */ -int flexran_get_res_alloc_type1(mid_t ue_id); - -/* Get UE transmission mode */ -int flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id); - -/* Boolean value. See TS 36.321 */ -int flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id); - -/* The max HARQ retransmission for UL. - See TS 36.321 */ -int flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id); - -/* See TS 36.213 */ -int flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id); - -/* See TS 36.213 */ -int flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id); - -/* See TS 36.213 */ -int flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id); - -/* Boolean. See TS36.213, Section 10.1 */ -int flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id); - -/* Boolean. See TS 36.213, Section 8.2 */ -int flexran_get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id); - -/* Get aperiodic CQI report mode */ -int flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id); - -/* Get ACK/NACK feedback mode. TDD only */ -int flexran_get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id); - -/* See TS36.213, section 10.1 */ -int flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id); - -/* Boolean. Extended buffer status report size */ -int flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id); - -/* Get number of UE transmission antennas */ -int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id); - -/* Get logical channel group of a channel with id lc_id */ -int flexran_get_lcg(mid_t ue_id, mid_t lc_id); - -/* Get direction of logical channel with id lc_id */ -int flexran_get_direction(mid_t ue_id, mid_t lc_id); - -/******************* - * timer primitves - *******************/ - -#define TIMER_NULL -1 -#define TIMER_TYPE_INVALIDE -2 -#define TIMER_SETUP_FAILED -3 -#define TIMER_REMOVED_FAILED -4 -#define TIMER_ELEMENT_NOT_FOUND -5 - - -/* Type of the callback executed when the timer expired */ -typedef Protocol__FlexranMessage *(*flexran_agent_timer_callback_t)(void*); - -typedef enum { - /* oneshot timer: */ - FLEXRAN_AGENT_TIMER_TYPE_ONESHOT = 0x0, - - /* periodic timer */ - FLEXRAN_AGENT_TIMER_TYPE_PERIODIC = 0x1, - - /* Inactive state: initial state for any timer. */ - FLEXRAN_AGENT_TIMER_TYPE_EVENT_DRIVEN = 0x2, - - /* Max number of states available */ - FLEXRAN_AGENT_TIMER_TYPE_MAX, -} flexran_agent_timer_type_t; - -typedef enum { - /* Inactive state: initial state for any timer. */ - FLEXRAN_AGENT_TIMER_STATE_INACTIVE = 0x0, - - /* Inactive state: initial state for any timer. */ - FLEXRAN_AGENT_TIMER_STATE_ACTIVE = 0x1, - - /* Inactive state: initial state for any timer. */ - FLEXRAN_AGENT_TIMER_STATE_STOPPED = 0x2, - - /* Max number of states available */ - FLEXRAN_AGENT_TIMER_STATE_MAX, -} flexran_agent_timer_state_t; - -typedef struct flexran_agent_timer_args_s{ - mid_t mod_id; - Protocol__FlexranMessage *msg; -} flexran_agent_timer_args_t; - - - -typedef struct flexran_agent_timer_element_s{ - RB_ENTRY(flexran_agent_timer_element_s) entry; - - agent_id_t agent_id; - instance_t instance; - - flexran_agent_timer_type_t type; - flexran_agent_timer_state_t state; - - uint32_t interval_sec; - uint32_t interval_usec; - - long timer_id; /* Timer id returned by the timer API*/ - xid_t xid; /*The id of the task as received by the controller - message*/ - - flexran_agent_timer_callback_t cb; - flexran_agent_timer_args_t *timer_args; - -} flexran_agent_timer_element_t; - -typedef struct flexran_agent_timer_instance_s{ - RB_HEAD(flexran_agent_map, flexran_agent_timer_element_s) flexran_agent_head; -}flexran_agent_timer_instance_t; - - -err_code_t flexran_agent_init_timer(void); - -/* Create a timer for some agent related event with id xid. Will store the id - of the generated timer in timer_id */ -err_code_t flexran_agent_create_timer(uint32_t interval_sec, - uint32_t interval_usec, - agent_id_t agent_id, - instance_t instance, - uint32_t timer_type, - xid_t xid, - flexran_agent_timer_callback_t cb, - void* timer_args, - long *timer_id); - -/* Destroy all existing timers */ -err_code_t flexran_agent_destroy_timers(void); - -/* Destroy the timer with the given timer_id */ -err_code_t flexran_agent_destroy_timer(long timer_id); - -/* Destroy the timer for task with id xid */ -err_code_t flexran_agent_destroy_timer_by_task_id(xid_t xid); - -/* Stop a timer */ -err_code_t flexran_agent_stop_timer(long timer_id); - -/* Restart the given timer */ -err_code_t flexran_agent_restart_timer(long *timer_id); - -/* Find the timer with the given timer_id */ -struct flexran_agent_timer_element_s * get_timer_entry(long timer_id); - -/* Obtain the protocol message stored in the given expired timer */ -Protocol__FlexranMessage * flexran_agent_process_timeout(long timer_id, void* timer_args); - -/* Comparator function comparing two timers. Decides the ordering of the timers */ -int flexran_agent_compare_timer(struct flexran_agent_timer_element_s *a, struct flexran_agent_timer_element_s *b); - -/*Specify a delay in nanoseconds to timespec and sleep until then*/ -void flexran_agent_sleep_until(struct timespec *ts, int delay); - -/* RB_PROTOTYPE is for .h files */ -RB_PROTOTYPE(flexran_agent_map, flexran_agent_timer_element_s, entry, flexran_agent_compare_timer); +int flexran_agent_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg); #endif diff --git a/openair2/ENB_APP/flexran_agent_defs.h b/openair2/ENB_APP/flexran_agent_defs.h index d60510b0c7..0b8822a949 100644 --- a/openair2/ENB_APP/flexran_agent_defs.h +++ b/openair2/ENB_APP/flexran_agent_defs.h @@ -21,8 +21,8 @@ /*! \file flexran_agent_defs.h * \brief FlexRAN agent common definitions - * \author Navid Nikaein and Xenofon Foukas - * \date 2016 + * \author Navid Nikaein and Xenofon Foukas and shahab SHARIAT BAGHERI + * \date 2017 * \version 0.1 */ #ifndef FLEXRAN_AGENT_DEFS_H_ @@ -102,6 +102,38 @@ typedef uint8_t lcid_t; typedef int32_t err_code_t; +/*---------Timer Enums --------- */ + +typedef enum { + /* oneshot timer: */ + FLEXRAN_AGENT_TIMER_TYPE_ONESHOT = 0, + + /* periodic timer */ + FLEXRAN_AGENT_TIMER_TYPE_PERIODIC = 1, + + /* Inactive state: initial state for any timer. */ + FLEXRAN_AGENT_TIMER_TYPE_EVENT_DRIVEN = 2, + + /* Max number of states available */ + FLEXRAN_AGENT_TIMER_TYPE_MAX, +} flexran_agent_timer_type_t; + + +typedef enum { + /* Inactive state: initial state for any timer. */ + FLEXRAN_AGENT_TIMER_STATE_INACTIVE = 0x0, + + /* Inactive state: initial state for any timer. */ + FLEXRAN_AGENT_TIMER_STATE_ACTIVE = 0x1, + + /* Inactive state: initial state for any timer. */ + FLEXRAN_AGENT_TIMER_STATE_STOPPED = 0x2, + + /* Max number of states available */ + FLEXRAN_AGENT_TIMER_STATE_MAX, +} flexran_agent_timer_state_t; + + typedef struct { /* general info */ @@ -116,6 +148,53 @@ typedef struct { } flexran_agent_info_t; + +/* +rrc triggering + */ + + +typedef struct { + char * trigger_policy; + uint32_t report_interval; + uint32_t report_amount; + +} agent_reconf_rrc; + + +/* These structs will be used to give + instructions for the type of stats reports + we need to create */ + + +typedef struct { + uint16_t ue_rnti; + uint32_t ue_report_flags; /* Indicates the report elements + required for this UE id. See + FlexRAN specification 1.2.4.2 */ +} ue_report_type_t; + +typedef struct { + uint16_t cc_id; + uint32_t cc_report_flags; /* Indicates the report elements + required for this CC index. See + FlexRAN specification 1.2.4.3 */ +} cc_report_type_t; + +typedef struct { + int nr_ue; + ue_report_type_t *ue_report_type; + int nr_cc; + cc_report_type_t *cc_report_type; +} report_config_t; + +typedef struct stats_request_config_s{ + uint8_t report_type; + uint8_t report_frequency; + uint16_t period; /*In number of subframes*/ + report_config_t *config; +} stats_request_config_t; + typedef struct { mid_t enb_id; flexran_agent_info_t agent_info; diff --git a/openair2/ENB_APP/flexran_agent_extern.h b/openair2/ENB_APP/flexran_agent_extern.h index 4a04d5d3a6..4df984e1a0 100644 --- a/openair2/ENB_APP/flexran_agent_extern.h +++ b/openair2/ENB_APP/flexran_agent_extern.h @@ -20,9 +20,9 @@ */ /*! \file ENB_APP/extern.h - * \brief FlexRAN agent - mac interface primitives - * \author Xenofon Foukas - * \date 2016 + * \brief FlexRAN agent - Extern VSF xfaces + * \author Xenofon Foukas and shahab SHARIAT BAGHERI + * \date 2017 * \version 0.1 * \mail x.foukas@sms.ed.ac.uk */ @@ -30,9 +30,9 @@ #ifndef __FLEXRAN_AGENT_EXTERN_H__ #define __FLEXRAN_AGENT_EXTERN_H__ -#include "flexran_agent_defs.h" +// #include "flexran_agent_defs.h" #include "flexran_agent_mac_defs.h" - +#include "flexran_agent_rrc_defs.h" //extern msg_context_t shared_ctxt[NUM_MAX_ENB][FLEXRAN_AGENT_MAX]; @@ -45,6 +45,12 @@ extern AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB]; /* Flag indicating whether the VSFs for the MAC control module have been registered */ extern unsigned int mac_agent_registered[NUM_MAX_ENB]; +/* Control module interface for the communication of the RRC Control Module with the agent */ +extern AGENT_RRC_xface *agent_rrc_xface[NUM_MAX_ENB]; + +/* Flag indicating whether the VSFs for the RRC control module have been registered */ +extern unsigned int rrc_agent_registered[NUM_MAX_ENB]; + /* Requried to know which UEs had a harq updated over some subframe */ extern int harq_pid_updated[NUMBER_OF_UE_MAX][8]; extern int harq_pid_round[NUMBER_OF_UE_MAX][8]; diff --git a/openair2/ENB_APP/flexran_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c index 29a1c1000c..b57039bec5 100644 --- a/openair2/ENB_APP/flexran_agent_handler.c +++ b/openair2/ENB_APP/flexran_agent_handler.c @@ -21,14 +21,16 @@ /*! \file flexran_agent_handler.c * \brief FlexRAN agent tx and rx message handler - * \author Xenofon Foukas and Navid Nikaein - * \date 2016 + * \author Xenofon Foukas and Navid Nikaein and shahab SHARIAT BAGHERI + * \date 2017 * \version 0.1 */ - +#include "flexran_agent_defs.h" #include "flexran_agent_common.h" #include "flexran_agent_mac.h" +#include "flexran_agent_rrc.h" +#include "flexran_agent_timer.h" #include "log.h" #include "assertions.h" @@ -37,7 +39,7 @@ flexran_agent_message_decoded_callback agent_messages_callback[][3] = { {flexran_agent_hello, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_HELLO_MSG*/ {flexran_agent_echo_reply, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_ECHO_REQUEST_MSG*/ {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_ECHO_REPLY_MSG*/ //Must add handler when receiving echo reply - {flexran_agent_mac_handle_stats, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG*/ + {flexran_agent_handle_stats, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG*/ {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG*/ {0, 0, 0}, /*PROTOCOK__FLEXRAN_MESSAGE__MSG_SF_TRIGGER_MSG*/ {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_UL_SR_INFO_MSG*/ @@ -51,13 +53,14 @@ flexran_agent_message_decoded_callback agent_messages_callback[][3] = { {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG*/ {flexran_agent_control_delegation, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_CONTROL_DELEGATION_MSG*/ {flexran_agent_reconfiguration, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_AGENT_RECONFIGURATION_MSG*/ + {flexran_agent_rrc_measurement, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_RRC_TRIGGERING_MSG*/ }; flexran_agent_message_destruction_callback message_destruction_callback[] = { flexran_agent_destroy_hello, flexran_agent_destroy_echo_request, flexran_agent_destroy_echo_reply, - flexran_agent_mac_destroy_stats_request, + flexran_agent_destroy_stats_request, flexran_agent_mac_destroy_stats_reply, flexran_agent_mac_destroy_sf_trigger, flexran_agent_mac_destroy_sr_info, @@ -93,7 +96,7 @@ Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id, err_code= PROTOCOL__FLEXRAN_ERR__MSG_DECODING; goto error; } - + printf("==================> %d %d \n", decoded_message->msg_case, decoded_message->msg_dir); if ((decoded_message->msg_case > sizeof(agent_messages_callback) / (3 * sizeof(flexran_agent_message_decoded_callback))) || (decoded_message->msg_dir > PROTOCOL__FLEXRAN_DIRECTION__UNSUCCESSFUL_OUTCOME)){ err_code= PROTOCOL__FLEXRAN_ERR__MSG_NOT_HANDLED; @@ -187,3 +190,568 @@ Protocol__FlexranMessage* flexran_agent_process_timeout(long timer_id, void* tim err_code_t flexran_agent_destroy_flexran_message(Protocol__FlexranMessage *msg) { return ((*message_destruction_callback[msg->msg_case-1])(msg)); } + + +/* + Top Level Statistics Report + + */ + + + +int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg){ + + // TODO: Must deal with sanitization of input + // TODO: Must check if RNTIs and cell ids of the request actually exist + // TODO: Must resolve conflicts among stats requests + + int i; + err_code_t err_code; + xid_t xid; + uint32_t usec_interval, sec_interval; + + //TODO: We do not deal with multiple CCs at the moment and eNB id is 0 + int enb_id = mod_id; + + //eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; + //UE_list_t *eNB_UE_list= &eNB->UE_list; + + report_config_t report_config; + + uint32_t ue_flags = 0; + uint32_t c_flags = 0; + + Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; + + Protocol__FlexStatsRequest *stats_req = input->stats_request_msg; + xid = (stats_req->header)->xid; + + // Check the type of request that is made + switch(stats_req->body_case) { + case PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST: ; + Protocol__FlexCompleteStatsRequest *comp_req = stats_req->complete_stats_request; + if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_OFF) { + /*Disable both periodic and continuous updates*/ + // flexran_agent_disable_cont_stats_update(mod_id); + flexran_agent_destroy_timer_by_task_id(xid); + *msg = NULL; + return 0; + } else { //One-off, periodical or continuous reporting + //Set the proper flags + ue_flags = comp_req->ue_report_flags; + c_flags = comp_req->cell_report_flags; + //Create a list of all eNB RNTIs and cells + + //Set the number of UEs and create list with their RNTIs stats configs + report_config.nr_ue = flexran_get_num_ues(mod_id); //eNB_UE_list->num_UEs + report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t) * report_config.nr_ue); + if (report_config.ue_report_type == NULL) { + // TODO: Add appropriate error code + err_code = -100; + goto error; + } + for (i = 0; i < report_config.nr_ue; i++) { + report_config.ue_report_type[i].ue_rnti = flexran_get_ue_crnti(enb_id, i); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].crnti; + report_config.ue_report_type[i].ue_report_flags = ue_flags; + } + //Set the number of CCs and create a list with the cell stats configs + report_config.nr_cc = MAX_NUM_CCs; + report_config.cc_report_type = (cc_report_type_t *) malloc(sizeof(cc_report_type_t) * report_config.nr_cc); + if (report_config.cc_report_type == NULL) { + // TODO: Add appropriate error code + err_code = -100; + goto error; + } + for (i = 0; i < report_config.nr_cc; i++) { + //TODO: Must fill in the proper cell ids + report_config.cc_report_type[i].cc_id = i; + report_config.cc_report_type[i].cc_report_flags = c_flags; + } + /* Check if request was periodical */ + if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_PERIODICAL) { + /* Create a one off flexran message as an argument for the periodical task */ + Protocol__FlexranMessage *timer_msg; + stats_request_config_t request_config; + request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS; + request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE; + request_config.period = 0; + /* Need to make sure that the ue flags are saved (Bug) */ + if (report_config.nr_ue == 0) { + report_config.nr_ue = 1; + report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t)); + if (report_config.ue_report_type == NULL) { + // TODO: Add appropriate error code + err_code = -100; + goto error; + } + report_config.ue_report_type[0].ue_rnti = 0; // Dummy value + report_config.ue_report_type[0].ue_report_flags = ue_flags; + } + request_config.config = &report_config; + flexran_agent_stats_request(enb_id, xid, &request_config, &timer_msg); + /* Create a timer */ + long timer_id = 0; + flexran_agent_timer_args_t *timer_args; + timer_args = malloc(sizeof(flexran_agent_timer_args_t)); + memset (timer_args, 0, sizeof(flexran_agent_timer_args_t)); + timer_args->mod_id = enb_id; + timer_args->msg = timer_msg; + /*Convert subframes to usec time*/ + usec_interval = 1000*comp_req->sf; + sec_interval = 0; + /*add seconds if required*/ + if (usec_interval >= 1000*1000) { + sec_interval = usec_interval/(1000*1000); + usec_interval = usec_interval%(1000*1000); + } + flexran_agent_create_timer(sec_interval, usec_interval, FLEXRAN_AGENT_DEFAULT, enb_id, FLEXRAN_AGENT_TIMER_TYPE_PERIODIC, xid, flexran_agent_handle_timed_task,(void*) timer_args, &timer_id); + } else if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_CONTINUOUS) { + /*If request was for continuous updates, disable the previous configuration and + set up a new one*/ + // flexran_agent_disable_cont_stats_update(mod_id); + stats_request_config_t request_config; + request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS; + request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE; + request_config.period = 0; + /* Need to make sure that the ue flags are saved (Bug) */ + if (report_config.nr_ue == 0) { + report_config.nr_ue = 1; + report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t)); + if (report_config.ue_report_type == NULL) { + // TODO: Add appropriate error code + err_code = -100; + goto error; + } + report_config.ue_report_type[0].ue_rnti = 0; // Dummy value + report_config.ue_report_type[0].ue_report_flags = ue_flags; + } + request_config.config = &report_config; + flexran_agent_enable_cont_stats_update(enb_id, xid, &request_config); + } + } + break; + case PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST:; + Protocol__FlexCellStatsRequest *cell_req = stats_req->cell_stats_request; + // UE report config will be blank + report_config.nr_ue = 0; + report_config.ue_report_type = NULL; + report_config.nr_cc = cell_req->n_cell; + report_config.cc_report_type = (cc_report_type_t *) malloc(sizeof(cc_report_type_t) * report_config.nr_cc); + if (report_config.cc_report_type == NULL) { + // TODO: Add appropriate error code + err_code = -100; + goto error; + } + for (i = 0; i < report_config.nr_cc; i++) { + //TODO: Must fill in the proper cell ids + report_config.cc_report_type[i].cc_id = cell_req->cell[i]; + report_config.cc_report_type[i].cc_report_flags = cell_req->flags; + } + break; + case PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST:; + Protocol__FlexUeStatsRequest *ue_req = stats_req->ue_stats_request; + // Cell report config will be blank + report_config.nr_cc = 0; + report_config.cc_report_type = NULL; + report_config.nr_ue = ue_req->n_rnti; + report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t) * report_config.nr_ue); + if (report_config.ue_report_type == NULL) { + // TODO: Add appropriate error code + err_code = -100; + goto error; + } + for (i = 0; i < report_config.nr_ue; i++) { + report_config.ue_report_type[i].ue_rnti = ue_req->rnti[i]; + report_config.ue_report_type[i].ue_report_flags = ue_req->flags; + } + break; + default: + //TODO: Add appropriate error code + err_code = -100; + goto error; + } + + if (flexran_agent_stats_reply(enb_id, xid, &report_config, msg )){ + err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; + goto error; + } + + free(report_config.ue_report_type); + free(report_config.cc_report_type); + + return 0; + + error : + LOG_E(FLEXRAN_AGENT, "errno %d occured\n", err_code); + return err_code; +} + +/* + Top level reply + */ + +int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg){ + + Protocol__FlexHeader *header; + err_code_t err_code; + int i; + + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) + goto error; + + + Protocol__FlexStatsReply *stats_reply_msg; + + stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply)); + + if (stats_reply_msg == NULL) + goto error; + + protocol__flex_stats_reply__init(stats_reply_msg); + stats_reply_msg->header = header; + + stats_reply_msg->n_ue_report = report_config->nr_ue; + stats_reply_msg->n_cell_report = report_config->nr_cc; + + // UE report + + Protocol__FlexUeStatsReport **ue_report; + + + ue_report = malloc(sizeof(Protocol__FlexUeStatsReport *) * report_config->nr_ue); + if (ue_report == NULL) + goto error; + + for (i = 0; i < report_config->nr_ue; i++) { + + ue_report[i] = malloc(sizeof(Protocol__FlexUeStatsReport)); + protocol__flex_ue_stats_report__init(ue_report[i]); + ue_report[i]->rnti = report_config->ue_report_type[i].ue_rnti; + ue_report[i]->has_rnti = 1; + ue_report[i]->flags = report_config->ue_report_type[i].ue_report_flags; + ue_report[i]->has_flags = 1; + + } + + // cell rpoert + + Protocol__FlexCellStatsReport **cell_report; + + + cell_report = malloc(sizeof(Protocol__FlexCellStatsReport *) * report_config->nr_cc); + if (cell_report == NULL) + goto error; + + for (i = 0; i < report_config->nr_cc; i++) { + + cell_report[i] = malloc(sizeof(Protocol__FlexCellStatsReport)); + if(cell_report[i] == NULL) + goto error; + + protocol__flex_cell_stats_report__init(cell_report[i]); + cell_report[i]->carrier_index = report_config->cc_report_type[i].cc_id; + cell_report[i]->has_carrier_index = 1; + cell_report[i]->flags = report_config->cc_report_type[i].cc_report_flags; + cell_report[i]->has_flags = 1; + + } + + /* + MAC reply split + */ + + + if (flexran_agent_mac_stats_reply(enb_id, report_config, ue_report, cell_report) < 0 ) { + err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; + goto error; + } + + + stats_reply_msg->cell_report = cell_report; + stats_reply_msg->ue_report = ue_report; + + *msg = malloc(sizeof(Protocol__FlexranMessage)); + if(*msg == NULL) + goto error; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; + (*msg)->stats_reply_msg = stats_reply_msg; + + return 0; + +error : + LOG_E(FLEXRAN_AGENT, "errno %d occured\n", err_code); + return err_code; + +} + +/* + Top Level Request + */ + +int flexran_agent_stats_request(mid_t mod_id, + xid_t xid, + const stats_request_config_t *report_config, + Protocol__FlexranMessage **msg) { + Protocol__FlexHeader *header; + int i; + + Protocol__FlexStatsRequest *stats_request_msg; + stats_request_msg = malloc(sizeof(Protocol__FlexStatsRequest)); + if(stats_request_msg == NULL) + goto error; + protocol__flex_stats_request__init(stats_request_msg); + + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REQUEST, &header) != 0) + goto error; + + stats_request_msg->header = header; + + stats_request_msg->type = report_config->report_type; + stats_request_msg->has_type = 1; + + switch (report_config->report_type) { + case PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS: + stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST; + Protocol__FlexCompleteStatsRequest *complete_stats; + complete_stats = malloc(sizeof(Protocol__FlexCompleteStatsRequest)); + if(complete_stats == NULL) + goto error; + protocol__flex_complete_stats_request__init(complete_stats); + complete_stats->report_frequency = report_config->report_frequency; + complete_stats->has_report_frequency = 1; + complete_stats->sf = report_config->period; + complete_stats->has_sf = 1; + complete_stats->has_cell_report_flags = 1; + complete_stats->has_ue_report_flags = 1; + if (report_config->config->nr_cc > 0) { + complete_stats->cell_report_flags = report_config->config->cc_report_type[0].cc_report_flags; + } + if (report_config->config->nr_ue > 0) { + complete_stats->ue_report_flags = report_config->config->ue_report_type[0].ue_report_flags; + } + stats_request_msg->complete_stats_request = complete_stats; + break; + case PROTOCOL__FLEX_STATS_TYPE__FLST_CELL_STATS: + stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST; + Protocol__FlexCellStatsRequest *cell_stats; + cell_stats = malloc(sizeof(Protocol__FlexCellStatsRequest)); + if(cell_stats == NULL) + goto error; + protocol__flex_cell_stats_request__init(cell_stats); + cell_stats->n_cell = report_config->config->nr_cc; + cell_stats->has_flags = 1; + if (cell_stats->n_cell > 0) { + uint32_t *cells; + cells = (uint32_t *) malloc(sizeof(uint32_t)*cell_stats->n_cell); + for (i = 0; i < cell_stats->n_cell; i++) { + cells[i] = report_config->config->cc_report_type[i].cc_id; + } + cell_stats->cell = cells; + cell_stats->flags = report_config->config->cc_report_type[i].cc_report_flags; + } + stats_request_msg->cell_stats_request = cell_stats; + break; + case PROTOCOL__FLEX_STATS_TYPE__FLST_UE_STATS: + stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST; + Protocol__FlexUeStatsRequest *ue_stats; + ue_stats = malloc(sizeof(Protocol__FlexUeStatsRequest)); + if(ue_stats == NULL) + goto error; + protocol__flex_ue_stats_request__init(ue_stats); + ue_stats->n_rnti = report_config->config->nr_ue; + ue_stats->has_flags = 1; + if (ue_stats->n_rnti > 0) { + uint32_t *ues; + ues = (uint32_t *) malloc(sizeof(uint32_t)*ue_stats->n_rnti); + for (i = 0; i < ue_stats->n_rnti; i++) { + ues[i] = report_config->config->ue_report_type[i].ue_rnti; + } + ue_stats->rnti = ues; + ue_stats->flags = report_config->config->ue_report_type[i].ue_report_flags; + } + stats_request_msg->ue_stats_request = ue_stats; + break; + default: + goto error; + } + *msg = malloc(sizeof(Protocol__FlexranMessage)); + if(*msg == NULL) + goto error; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; + (*msg)->stats_request_msg = stats_request_msg; + return 0; + + error: + // TODO: Need to make proper error handling + if (header != NULL) + free(header); + if (stats_request_msg != NULL) + free(stats_request_msg); + if(*msg != NULL) + free(*msg); + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +int flexran_agent_destroy_stats_request(Protocol__FlexranMessage *msg) { + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG) + goto error; + free(msg->stats_request_msg->header); + if (msg->stats_request_msg->body_case == PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST) { + free(msg->stats_request_msg->cell_stats_request->cell); + } + if (msg->stats_request_msg->body_case == PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST) { + free(msg->stats_request_msg->ue_stats_request->rnti); + } + free(msg->stats_request_msg); + free(msg); + return 0; + + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +/* + Top Level Update + */ + +void flexran_agent_send_update_stats(mid_t mod_id) { + + Protocol__FlexranMessage *current_report = NULL; + void *data; + int size; + err_code_t err_code; + int priority = 0; + + if (pthread_mutex_lock(stats_context[mod_id].mutex)) { + goto error; + } + + if (stats_context[mod_id].cont_update == 1) { + + /*Create a fresh report with the required flags*/ + err_code = flexran_agent_handle_stats(mod_id, (void *) stats_context[mod_id].stats_req, ¤t_report); + if (err_code < 0) { + goto error; + } + } + /* /\*TODO:Check if a previous reports exists and if yes, generate a report */ + /* *that is the diff between the old and the new report, */ + /* *respecting the thresholds. Otherwise send the new report*\/ */ + /* if (stats_context[mod_id].prev_stats_reply != NULL) { */ + + /* msg = flexran_agent_generate_diff_mac_stats_report(current_report, stats_context[mod_id].prev_stats_reply); */ + + /* /\*Destroy the old stats*\/ */ + /* flexran_agent_destroy_flexran_message(stats_context[mod_id].prev_stats_reply); */ + /* } */ + /* /\*Use the current report for future comparissons*\/ */ + /* stats_context[mod_id].prev_stats_reply = current_report; */ + + + if (pthread_mutex_unlock(stats_context[mod_id].mutex)) { + goto error; + } + + if (current_report != NULL){ + data=flexran_agent_pack_message(current_report, &size); + /*Send any stats updates using the MAC channel of the eNB*/ + if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_MAC, data, size, priority)) { + err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; + goto error; + } + + LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); + return; + } + error: + LOG_D(FLEXRAN_AGENT, "Could not send sf trigger message\n"); +} + +err_code_t flexran_agent_disable_cont_stats_update(mid_t mod_id) { + /*Disable the continuous updates for the MAC*/ + if (pthread_mutex_lock(stats_context[mod_id].mutex)) { + goto error; + } + stats_context[mod_id].cont_update = 0; + stats_context[mod_id].xid = 0; + if (stats_context[mod_id].stats_req != NULL) { + flexran_agent_destroy_flexran_message(stats_context[mod_id].stats_req); + } + if (stats_context[mod_id].prev_stats_reply != NULL) { + flexran_agent_destroy_flexran_message(stats_context[mod_id].prev_stats_reply); + } + if (pthread_mutex_unlock(stats_context[mod_id].mutex)) { + goto error; + } + return 0; + + error: + LOG_E(FLEXRAN_AGENT, "stats_context for eNB %d is not initialized\n", mod_id); + return -1; + +} + +err_code_t flexran_agent_enable_cont_stats_update(mid_t mod_id, + xid_t xid, stats_request_config_t *stats_req) { + + if (pthread_mutex_lock(stats_context[mod_id].mutex)) { + goto error; + } + + Protocol__FlexranMessage *req_msg; + + flexran_agent_stats_request(mod_id, xid, stats_req, &req_msg); + stats_context[mod_id].stats_req = req_msg; + stats_context[mod_id].prev_stats_reply = NULL; + + stats_context[mod_id].cont_update = 1; + stats_context[mod_id].xid = xid; + + if (pthread_mutex_unlock(stats_context[mod_id].mutex)) { + goto error; + } + return 0; + + error: + LOG_E(FLEXRAN_AGENT, "stats_context for eNB %d is not initialized\n", mod_id); + return -1; +} + + +err_code_t flexran_agent_init_cont_stats_update(mid_t mod_id) { + + + /*Initially the continuous update is set to false*/ + stats_context[mod_id].cont_update = 0; + stats_context[mod_id].is_initialized = 1; + stats_context[mod_id].stats_req = NULL; + stats_context[mod_id].prev_stats_reply = NULL; + stats_context[mod_id].mutex = calloc(1, sizeof(pthread_mutex_t)); + if (stats_context[mod_id].mutex == NULL) + goto error; + if (pthread_mutex_init(stats_context[mod_id].mutex, NULL)) + goto error;; + + return 0; + + error: + return -1; +} + +err_code_t flexran_agent_destroy_cont_stats_update(mid_t mod_id) { + + stats_context[mod_id].cont_update = 0; + stats_context[mod_id].is_initialized = 0; + flexran_agent_destroy_flexran_message(stats_context[mod_id].stats_req); + flexran_agent_destroy_flexran_message(stats_context[mod_id].prev_stats_reply); + free(stats_context[mod_id].mutex); + + // mac_agent_registered[mod_id] = 0; + return 1; +} \ No newline at end of file diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c new file mode 100644 index 0000000000..17a53c7eb0 --- /dev/null +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -0,0 +1,929 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file flexran_agent_ran_api.c + * \brief FlexRAN RAN API abstraction + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + */ + +#include "flexran_agent_ran_api.h" + + +/* + * get generic info from RAN + */ + + + +void * enb[NUM_MAX_ENB]; +void * enb_ue[NUM_MAX_ENB]; +void * enb_rrc[NUM_MAX_ENB]; + +void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran){ + + switch (ran){ + case RAN_LTE_OAI : + enb[mod_id] = (void *)&eNB_mac_inst[mod_id]; + enb_ue[mod_id] = (void *)&eNB_mac_inst[mod_id].UE_list; + enb_rrc[mod_id] = (void *)&eNB_rrc_inst[mod_id]; + break; + default : + goto error; + } + + return; + + error: + LOG_E(FLEXRAN_AGENT, "unknown RAN name %d\n", ran); +} + +int flexran_get_current_time_ms (mid_t mod_id, int subframe_flag){ + + if (subframe_flag == 1){ + return ((eNB_MAC_INST *)enb[mod_id])->frame*10 + ((eNB_MAC_INST *)enb[mod_id])->subframe; + }else { + return ((eNB_MAC_INST *)enb[mod_id])->frame*10; + } + +} + +unsigned int flexran_get_current_frame (mid_t mod_id) { + + // #warning "SFN will not be in [0-1023] when oaisim is used" + return ((eNB_MAC_INST *)enb[mod_id])->frame; + +} + +unsigned int flexran_get_current_system_frame_num(mid_t mod_id) { + return (flexran_get_current_frame(mod_id) %1024); +} + +unsigned int flexran_get_current_subframe (mid_t mod_id) { + + return ((eNB_MAC_INST *)enb[mod_id])->subframe; + +} + +uint16_t flexran_get_sfn_sf (mid_t mod_id) { + + frame_t frame; + sub_frame_t subframe; + uint16_t sfn_sf, frame_mask, sf_mask; + + frame = (frame_t) flexran_get_current_system_frame_num(mod_id); + subframe = (sub_frame_t) flexran_get_current_subframe(mod_id); + frame_mask = ((1<<12) - 1); + sf_mask = ((1<<4) - 1); + sfn_sf = (subframe & sf_mask) | ((frame & frame_mask) << 4); + + return sfn_sf; +} + +uint16_t flexran_get_future_sfn_sf (mid_t mod_id, int ahead_of_time) { + + frame_t frame; + sub_frame_t subframe; + uint16_t sfn_sf, frame_mask, sf_mask; + + frame = (frame_t) flexran_get_current_system_frame_num(mod_id); + subframe = (sub_frame_t) flexran_get_current_subframe(mod_id); + + subframe = ((subframe + ahead_of_time) % 10); + + if (subframe < flexran_get_current_subframe(mod_id)) { + frame = (frame + 1) % 1024; + } + + int additional_frames = ahead_of_time / 10; + frame = (frame + additional_frames) % 1024; + + frame_mask = ((1<<12) - 1); + sf_mask = ((1<<4) - 1); + sfn_sf = (subframe & sf_mask) | ((frame & frame_mask) << 4); + + return sfn_sf; +} + +int flexran_get_num_ues (mid_t mod_id){ + + return ((UE_list_t *)enb_ue[mod_id])->num_UEs; +} + +int flexran_get_ue_crnti (mid_t mod_id, mid_t ue_id) { + + return UE_RNTI(mod_id, ue_id); +} + +int flexran_get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid) { + + return ((UE_list_t *)enb_ue[mod_id])->UE_template[UE_PCCID(mod_id,ue_id)][ue_id].bsr_info[lcid]; +} + +int flexran_get_ue_phr (mid_t mod_id, mid_t ue_id) { + + return ((UE_list_t *)enb_ue[mod_id])->UE_template[UE_PCCID(mod_id,ue_id)][ue_id].phr_info; +} + +int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id) { + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, 0, UE_RNTI(mod_id, ue_id)); + return eNB_UE_stats->DL_cqi[0]; + + // return ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].dl_cqi; +} + +int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); + mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id,frame,ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0); + return rlc_status.bytes_in_buffer; +} + +int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); + mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, ENB_FLAG_YES, MBMS_FLAG_NO, channel_id, 0); + return rlc_status.head_sdu_creation_time; +} + +short flexran_get_TA(mid_t mod_id, mid_t ue_id, int CC_id) { + + UE_list_t *UE_list=&eNB_mac_inst[mod_id].UE_list; + int rnti; + + rnti = flexran_get_ue_crnti(mod_id, ue_id); + + LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + //ue_sched_ctl->ta_timer = 20; // wait 20 subframes before taking TA measurement from PHY + switch (PHY_vars_eNB_g[mod_id][CC_id]->frame_parms.N_RB_DL) { + case 6: + return eNB_UE_stats->timing_advance_update; + case 15: + return eNB_UE_stats->timing_advance_update/2; + case 25: + return eNB_UE_stats->timing_advance_update/4; + case 50: + return eNB_UE_stats->timing_advance_update/8; + case 75: + return eNB_UE_stats->timing_advance_update/12; + case 100: + if (PHY_vars_eNB_g[mod_id][CC_id]->frame_parms.threequarter_fs == 0) { + return eNB_UE_stats->timing_advance_update/16; + } else { + return eNB_UE_stats->timing_advance_update/12; + } + default: + return 0; + } +} + +int flexran_get_ue_pmi(mid_t mod_id){ + + /*Xenofon to check this*/ + + return 0; +} + + +void flexran_update_TA(mid_t mod_id, mid_t ue_id, int CC_id) { + + UE_list_t *UE_list=&eNB_mac_inst[mod_id].UE_list; + UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[ue_id]; + + if (ue_sched_ctl->ta_timer == 0) { + + // WE SHOULD PROTECT the eNB_UE_stats with a mutex here ... + // LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + //ue_sched_ctl->ta_timer = 20; // wait 20 subframes before taking TA measurement from PHY + ue_sched_ctl->ta_update = flexran_get_TA(mod_id, ue_id, CC_id); + + // clear the update in case PHY does not have a new measurement after timer expiry + // eNB_UE_stats->timing_advance_update = 0; + } else { + ue_sched_ctl->ta_timer--; + ue_sched_ctl->ta_update = 0; // don't trigger a timing advance command + } +} + +int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) { + + UE_list_t *UE_list = &eNB_mac_inst[mod_id].UE_list; + + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); + + if (eNB_UE_stats == NULL) { + return 0; + } + + if (flexran_get_TA(mod_id, ue_id, CC_id) != 0) { + return PROTOCOL__FLEX_CE_TYPE__FLPCET_TA; + } else { + return 0; + } + +} + +int flexran_get_active_CC(mid_t mod_id, mid_t ue_id) { + return ((UE_list_t *)enb_ue[mod_id])->numactiveCCs[ue_id]; +} + +int flexran_get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) { + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); + + if (eNB_UE_stats == NULL) { + return 0; + } + + return eNB_UE_stats[CC_id].rank; +} + +int flexran_get_tpc(mid_t mod_id, mid_t ue_id) { + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + int32_t normalized_rx_power, target_rx_power; + int tpc = 1; + + int pCCid = UE_PCCID(mod_id,ue_id); + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, pCCid, rnti); + + target_rx_power = mac_xface->get_target_pusch_rx_power(mod_id,pCCid); + + if (eNB_UE_stats == NULL) { + normalized_rx_power = target_rx_power; + } else if (eNB_UE_stats->UL_rssi != NULL) { + normalized_rx_power = eNB_UE_stats->UL_rssi[0]; + } else { + normalized_rx_power = target_rx_power; + } + + if (normalized_rx_power>(target_rx_power+1)) { + tpc = 0; //-1 + } else if (normalized_rx_power<(target_rx_power-1)) { + tpc = 2; //+1 + } else { + tpc = 1; //0 + } + return tpc; +} + +int flexran_get_harq(const mid_t mod_id, + const uint8_t CC_id, + const mid_t ue_id, + const int frame, + const uint8_t subframe, + uint8_t *id, + uint8_t *round) { //flag_id_status = 0 then id, else status + /*TODO: Add int TB in function parameters to get the status of the second TB. This can be done to by editing in + * get_ue_active_harq_pid function in line 272 file: phy_procedures_lte_eNB.c to add + * DLSCH_ptr = PHY_vars_eNB_g[Mod_id][CC_id]->dlsch_eNB[(uint32_t)UE_id][1];*/ + + uint8_t harq_pid; + uint8_t harq_round; + + + uint16_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + + mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&harq_round,openair_harq_DL); + + *id = harq_pid; + *round = harq_round; + /* if (round > 0) { */ + /* *status = 1; */ + /* } else { */ + /* *status = 0; */ + /* } */ + + /* return 0; */ + return *round; +} + +int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id) { + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + + if (eNB_UE_stats == NULL) { + return -1; + } + + // if(eNB_UE_stats->Po_PUCCH_update == 1) { + return eNB_UE_stats->Po_PUCCH_dBm; + //} + //else + // return -1; +} + +int flexran_get_p0_nominal_pucch(mid_t mod_id, int CC_id) { + int32_t pucch_rx_received = mac_xface->get_target_pucch_rx_power(mod_id, CC_id); + return pucch_rx_received; +} + +int flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, int CC_id) { + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + return eNB_UE_stats->Po_PUCCH_update; +} + +int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id) { + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + eNB_UE_stats->Po_PUCCH_update = 0; + + return 0; +} + + +/* + * ************************************ + * Get Messages for eNB Configuration Reply + * ************************************ + */ + +int flexran_get_hopping_offset(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->pusch_config_common.pusch_HoppingOffset; +} + +int flexran_get_hopping_mode(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->pusch_config_common.hoppingMode; +} + +int flexran_get_n_SB(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->pusch_config_common.n_SB; +} + +int flexran_get_enable64QAM(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->pusch_config_common.enable64QAM; +} + +int flexran_get_phich_duration(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->phich_config_common.phich_duration; +} + +int flexran_get_phich_resource(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + if(frame_parms->phich_config_common.phich_resource == oneSixth) + return 0; + else if(frame_parms->phich_config_common.phich_resource == half) + return 1; + else if(frame_parms->phich_config_common.phich_resource == one) + return 2; + else if(frame_parms->phich_config_common.phich_resource == two) + return 3; + + return -1; +} + +int flexran_get_n1pucch_an(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->pucch_config_common.n1PUCCH_AN; +} + +int flexran_get_nRB_CQI(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->pucch_config_common.nRB_CQI; +} + +int flexran_get_deltaPUCCH_Shift(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->pucch_config_common.deltaPUCCH_Shift; +} + +int flexran_get_prach_ConfigIndex(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex; +} + +int flexran_get_prach_FreqOffset(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset; +} + +int flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->maxHARQ_Msg3Tx; +} + +int flexran_get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->Ncp_UL; +} + +int flexran_get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->Ncp; +} + +int flexran_get_cell_id(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->Nid_cell; +} + +int flexran_get_srs_BandwidthConfig(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->soundingrs_ul_config_common.srs_BandwidthConfig; +} + +int flexran_get_srs_SubframeConfig(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->soundingrs_ul_config_common.srs_SubframeConfig; +} + +int flexran_get_srs_MaxUpPts(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->soundingrs_ul_config_common.srs_MaxUpPts; +} + +int flexran_get_N_RB_DL(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->N_RB_DL; +} + +int flexran_get_N_RB_UL(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->N_RB_UL; +} + +int flexran_get_N_RBG(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->N_RBG; +} + +int flexran_get_subframe_assignment(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->tdd_config; +} + +int flexran_get_special_subframe_assignment(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->tdd_config_S; +} + +int flexran_get_ra_ResponseWindowSize(mid_t mod_id, int CC_id) { + return enb_config_get()->properties[mod_id]->rach_raResponseWindowSize[CC_id]; +} + +int flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id) { + return enb_config_get()->properties[mod_id]->rach_macContentionResolutionTimer[CC_id]; +} + +int flexran_get_duplex_mode(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + if(frame_parms->frame_type == TDD) + return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD; + else if (frame_parms->frame_type == FDD) + return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_FDD; + + return -1; +} + +long flexran_get_si_window_length(mid_t mod_id, int CC_id) { + return ((eNB_RRC_INST *)enb_rrc[mod_id])->carrier[CC_id].sib1->si_WindowLength; +} + +int flexran_get_sib1_length(mid_t mod_id, int CC_id) { + return ((eNB_RRC_INST *)enb_rrc[mod_id])->carrier[CC_id].sizeof_SIB1; +} + +int flexran_get_num_pdcch_symb(mid_t mod_id, int CC_id) { + /* TODO: This should return the number of PDCCH symbols initially used by the cell CC_id */ + return 0; + //(PHY_vars_UE_g[mod_id][CC_id]->lte_ue_pdcch_vars[mod_id]->num_pdcch_symbols); +} + + + +/* + * ************************************ + * Get Messages for UE Configuration Reply + * ************************************ + */ + + +int flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.mac_MainConfig != NULL) { + return ue_context_p->ue_context.mac_MainConfig->timeAlignmentTimerDedicated; + } else { + return -1; + } + } else { + return -1; + } +} + +int flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.measGapConfig != NULL) { + if(ue_context_p->ue_context.measGapConfig->present == MeasGapConfig_PR_setup) { + if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp0) { + return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP1; + } else if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp1) { + return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP2; + } else { + return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF; + } + } + } + } + return -1; +} + + +int flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.measGapConfig != NULL){ + if(ue_context_p->ue_context.measGapConfig->present == MeasGapConfig_PR_setup) { + if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp0) { + return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.choice.gp0; + } else if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp1) { + return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.choice.gp0; + } + } + } + } + return -1; +} + +int flexran_get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id) { + return ((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateDL; +} + +int flexran_get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id) { + return ((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateUL; +} + +int flexran_get_half_duplex(mid_t ue_id) { + // TODO + //int halfduplex = 0; + //int bands_to_scan = ((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.count; + //for (int i =0; i < bands_to_scan; i++){ + //if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.array[i]->halfDuplex > 0) + // halfduplex = 1; + //} + //return halfduplex; + return 0; +} + +int flexran_get_intra_sf_hopping(mid_t ue_id) { + //TODO:Get proper value + //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); + //return (0 & ( 1 << (31))); + return 0; +} + +int flexran_get_type2_sb_1(mid_t ue_id) { + //TODO:Get proper value + //uint8_t temp = 0; + //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); + //return (temp & ( 1 << (11))); + return 0; +} + +int flexran_get_ue_category(mid_t ue_id) { + //TODO:Get proper value + //return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->ue_Category); + return 0; +} + +int flexran_get_res_alloc_type1(mid_t ue_id) { + //TODO:Get proper value + //uint8_t temp = 0; + //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); + //return (temp & ( 1 << (30))); + return 0; +} + +int flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + return ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode; + } else { + return -1; + } + } else { + return -1; + } +} + +int flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.mac_MainConfig != NULL){ + return ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config->ttiBundling; + } else { + return -1; + } + } + else { + return -1; + } +} + +int flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.mac_MainConfig != NULL){ + return *ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config->maxHARQ_Tx; + } + } + return -1; +} + +int flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_ACK_Index; + } else { + return -1; + } + } else { + return -1; + } +} + +int flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index; + } else { + return -1; + } + } else { + return -1; + } +} + +int flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index; + } else { + return -1; + } + } + else { + return -1; + } +} + +int flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + if (ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic != NULL) { + return ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.simultaneousAckNackAndCQI; + } + } + } + return -1; +} + +int flexran_get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id) { + return (&eNB_rrc_inst[mod_id])->carrier[0].sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; +} + +int flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + return *ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic; + } + } + return -1; +} + +int flexran_get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) { + // TODO: This needs fixing + return -1; + + /* struct rrc_eNB_ue_context_s* ue_context_p = NULL; */ + /* uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); */ + + /* ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); */ + + /* if(ue_context_p != NULL) { */ + /* if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ */ + /* return ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode; */ + /* } else { */ + /* return -1; */ + /* } */ + /* } else { */ + /* return -1; */ + /* } */ +} + +int flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + return ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->ackNackRepetition.choice.setup.repetitionFactor; + } else { + return -1; + } + } else { + return -1; + } +} + +int flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id) { + //TODO: need to double check + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.mac_MainConfig != NULL){ + if(ue_context_p->ue_context.mac_MainConfig->ext2 != NULL){ + long val = (*(ue_context_p->ue_context.mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10)); + if (val > 0) { + return 1; + } + } + } + } + return -1; +} + +int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + if(ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup == AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_closedLoop) { + return 2; + } else if(ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup == AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_openLoop) { + return 1; + } else { + return 0; + } + } else { + return -1; + } + } else { + return -1; + } +} + +int flexran_get_lcg(mid_t ue_id, mid_t lc_id) { + if (UE_mac_inst == NULL) { + return -1; + } + if(UE_mac_inst[ue_id].logicalChannelConfig[lc_id] != NULL) { + return *UE_mac_inst[ue_id].logicalChannelConfig[lc_id]->ul_SpecificParameters->logicalChannelGroup; + } else { + return -1; + } +} + +int flexran_get_direction(mid_t ue_id, mid_t lc_id) { + /*TODO: fill with the value for the rest of LCID*/ + if(lc_id == DCCH || lc_id == DCCH1) { + return 2; + } else if(lc_id == DTCH) { + return 1; + } else { + return -1; + } +} + +int flexran_get_antenna_ports(mid_t mod_id, int CC_id){ + + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->nb_antenna_ports_eNB; + +} \ No newline at end of file diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h new file mode 100644 index 0000000000..12962a1f9d --- /dev/null +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -0,0 +1,290 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file flexran_agent_ran_api.h + * \brief FlexRAN RAN API abstraction header + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + */ + +#include +#include + +#include "flexran_agent_common.h" +#include "flexran_agent_common_internal.h" +#include "flexran_agent_extern.h" +#include "flexran_agent_defs.h" + + +#include "enb_config.h" +#include "LAYER2/MAC/extern.h" +#include "LAYER2/RLC/rlc.h" +#include "SCHED/defs.h" +#include "RRC/LITE/extern.h" +#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" +#include "RRC/LITE/rrc_eNB_UE_context.h" +#include "PHY/extern.h" +#include "log.h" + +/**************************** + * get generic info from RAN + ****************************/ + +void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran); + +int flexran_get_current_time_ms (mid_t mod_id, int subframe_flag); + +/*Return the current frame number + *Could be using implementation specific numbering of frames + */ +unsigned int flexran_get_current_frame(mid_t mod_id); + +/*Return the current SFN (0-1023)*/ +unsigned int flexran_get_current_system_frame_num(mid_t mod_id); + +unsigned int flexran_get_current_subframe(mid_t mod_id); + +/*Return the frame and subframe number in compact 16-bit format. + Bits 0-3 subframe, rest for frame. Required by FlexRAN protocol*/ +uint16_t flexran_get_sfn_sf (mid_t mod_id); + +/* Return a future frame and subframe number that is ahead_of_time + subframes later in compact 16-bit format. Bits 0-3 subframe, + rest for frame */ +uint16_t flexran_get_future_sfn_sf(mid_t mod_id, int ahead_of_time); + +/* Return the number of attached UEs */ +int flexran_get_num_ues(mid_t mod_id); + +/* Get the rnti of a UE with id ue_id */ +int flexran_get_ue_crnti (mid_t mod_id, mid_t ue_id); + +/* Get the RLC buffer status report of a ue for a designated + logical channel id */ +int flexran_get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid); + +/* Get power headroom of UE with id ue_id */ +int flexran_get_ue_phr (mid_t mod_id, mid_t ue_id); + +/* Get the UE wideband CQI */ +int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id); + +/* Get the transmission queue size for a UE with a channel_id logical channel id */ +int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); + +/* Get the head of line delay for a UE with a channel_id logical channel id */ +int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); + +/* Check the status of the timing advance for a UE */ +short flexran_get_TA(mid_t mod_id, mid_t ue_id, int CC_id); + +/* Update the timing advance status (find out whether a timing advance command is required) */ +void flexran_update_TA(mid_t mod_id, mid_t ue_id, int CC_id); + +/* Return timing advance MAC control element for a designated cell and UE */ +int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id, int CC_id); + +/* Get the number of active component carriers for a specific UE */ +int flexran_get_active_CC(mid_t mod_id, mid_t ue_id); + +/* Get the rank indicator for a designated cell and UE */ +int flexran_get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id); + +/* See TS 36.213, section 10.1 */ +int flexran_get_n1pucch_an(mid_t mod_id, int CC_id); + +/* See TS 36.211, section 5.4 */ +int flexran_get_nRB_CQI(mid_t mod_id, int CC_id); + +/* See TS 36.211, section 5.4 */ +int flexran_get_deltaPUCCH_Shift(mid_t mod_id, int CC_id); + +/* See TS 36.211, section 5.7.1 */ +int flexran_get_prach_ConfigIndex(mid_t mod_id, int CC_id); + +/* See TS 36.211, section 5.7.1 */ +int flexran_get_prach_FreqOffset(mid_t mod_id, int CC_id); + +/* See TS 36.321 */ +int flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id); + +/* Get the length of the UL cyclic prefix */ +int flexran_get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id); + +/* Get the length of the DL cyclic prefix */ +int flexran_get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id); + +/* Get the physical cell id of a cell */ +int flexran_get_cell_id(mid_t mod_id, int CC_id); + +/* See TS 36.211, section 5.5.3.2 */ +int flexran_get_srs_BandwidthConfig(mid_t mod_id, int CC_id); + +/* See TS 36.211, table 5.5.3.3-1 and 2 */ +int flexran_get_srs_SubframeConfig(mid_t mod_id, int CC_id); + +/* Boolean value. See TS 36.211, + section 5.5.3.2. TDD only */ +int flexran_get_srs_MaxUpPts(mid_t mod_id, int CC_id); + +/* Get number of DL resource blocks */ +int flexran_get_N_RB_DL(mid_t mod_id, int CC_id); + +/* Get number of UL resource blocks */ +int flexran_get_N_RB_UL(mid_t mod_id, int CC_id); + +/* Get number of resource block groups */ +int flexran_get_N_RBG(mid_t mod_id, int CC_id); + +/* Get DL/UL subframe assignment. TDD only */ +int flexran_get_subframe_assignment(mid_t mod_id, int CC_id); + +/* TDD only. See TS 36.211, table 4.2.1 */ +int flexran_get_special_subframe_assignment(mid_t mod_id, int CC_id); + +/* Get the duration of the random access response window in subframes */ +int flexran_get_ra_ResponseWindowSize(mid_t mod_id, int CC_id); + +/* Get timer used for random access */ +int flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id); + +/* Get type of duplex mode (FDD/TDD) */ +int flexran_get_duplex_mode(mid_t mod_id, int CC_id); + +/* Get the SI window length */ +long flexran_get_si_window_length(mid_t mod_id, int CC_id); + +/* Get the number of PDCCH symbols configured for the cell */ +int flexran_get_num_pdcch_symb(mid_t mod_id, int CC_id); + +int flexran_get_antenna_ports(mid_t mod_id, int CC_id); + +/* See TS 36.213, sec 5.1.1.1 */ +int flexran_get_tpc(mid_t mod_id, mid_t ue_id); + +int flexran_get_ue_pmi(mid_t mod_id); + +/* Get the first available HARQ process for a specific cell and UE during + a designated frame and subframe. Returns 0 for success. The id and the + status of the HARQ process are stored in id and status respectively */ +int flexran_get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, + const int frame, const uint8_t subframe, unsigned char *id, unsigned char *round); + +/* Uplink power control management*/ +int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id); + +int flexran_get_p0_nominal_pucch(mid_t mod_id, int CC_id); + +int flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, int CC_id); + +int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id); + + +/* + * ************************************ + * Get Messages for UE Configuration Reply + * ************************************ + */ + +/* Get timer in subframes. Controls the synchronization + status of the UE, not the actual timing + advance procedure. See TS 36.321 */ +int flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id); + +/* Get measurement gap configuration. See TS 36.133 */ +int flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id); + +/* Get measurement gap configuration offset if applicable */ +int flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id); + +/* DL aggregated bit-rate of non-gbr bearer + per UE. See TS 36.413 */ +int flexran_get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id); + +/* UL aggregated bit-rate of non-gbr bearer + per UE. See TS 36.413 */ +int flexran_get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id); + +/* Only half-duplex support. FDD + operation. Boolean value */ +int flexran_get_half_duplex(mid_t ue_id); + +/* Support of intra-subframe hopping. + Boolean value */ +int flexran_get_intra_sf_hopping(mid_t ue_id); + +/* UE support for type 2 hopping with + n_sb>1 */ +int flexran_get_type2_sb_1(mid_t ue_id); + +/* Get the UE category */ +int flexran_get_ue_category(mid_t ue_id); + +/* UE support for resource allocation + type 1 */ +int flexran_get_res_alloc_type1(mid_t ue_id); + +/* Get UE transmission mode */ +int flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id); + +/* Boolean value. See TS 36.321 */ +int flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id); + +/* The max HARQ retransmission for UL. + See TS 36.321 */ +int flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id); + +/* See TS 36.213 */ +int flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id); + +/* See TS 36.213 */ +int flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id); + +/* See TS 36.213 */ +int flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id); + +/* Boolean. See TS36.213, Section 10.1 */ +int flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id); + +/* Boolean. See TS 36.213, Section 8.2 */ +int flexran_get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id); + +/* Get aperiodic CQI report mode */ +int flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id); + +/* Get ACK/NACK feedback mode. TDD only */ +int flexran_get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id); + +/* See TS36.213, section 10.1 */ +int flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id); + +/* Boolean. Extended buffer status report size */ +int flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id); + +/* Get number of UE transmission antennas */ +int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id); + +/* Get logical channel group of a channel with id lc_id */ +int flexran_get_lcg(mid_t ue_id, mid_t lc_id); + +/* Get direction of logical channel with id lc_id */ +int flexran_get_direction(mid_t ue_id, mid_t lc_id); \ No newline at end of file diff --git a/openair2/ENB_APP/flexran_agent_timer.c b/openair2/ENB_APP/flexran_agent_timer.c new file mode 100644 index 0000000000..f5436e4d01 --- /dev/null +++ b/openair2/ENB_APP/flexran_agent_timer.c @@ -0,0 +1,217 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file flexran_agent_timer.c + * \brief FlexRAN Timer + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + */ + +/* + * timer primitives + */ + +#include "flexran_agent_timer.h" + +//struct flexran_agent_map agent_map; +flexran_agent_timer_instance_t timer_instance; +int agent_timer_init = 0; +err_code_t flexran_agent_init_timer(void){ + + LOG_I(FLEXRAN_AGENT, "init RB tree\n"); + if (!agent_timer_init) { + RB_INIT(&timer_instance.flexran_agent_head); + agent_timer_init = 1; + } + + return PROTOCOL__FLEXRAN_ERR__NO_ERR; +} + +RB_GENERATE(flexran_agent_map, flexran_agent_timer_element_s, entry, flexran_agent_compare_timer); + +/* The timer_id might not be the best choice for the comparison */ +int flexran_agent_compare_timer(struct flexran_agent_timer_element_s *a, struct flexran_agent_timer_element_s *b){ + + if (a->timer_id < b->timer_id) return -1; + if (a->timer_id > b->timer_id) return 1; + + // equal timers + return 0; +} + +err_code_t flexran_agent_create_timer(uint32_t interval_sec, + uint32_t interval_usec, + agent_id_t agent_id, + instance_t instance, + uint32_t timer_type, + xid_t xid, + flexran_agent_timer_callback_t cb, + void* timer_args, + long *timer_id){ + + struct flexran_agent_timer_element_s *e = calloc(1, sizeof(*e)); + DevAssert(e != NULL); + +//uint32_t timer_id; + int ret=-1; + + if ((interval_sec == 0) && (interval_usec == 0 )) + return TIMER_NULL; + + if (timer_type >= FLEXRAN_AGENT_TIMER_TYPE_MAX) + return TIMER_TYPE_INVALIDE; + + if (timer_type == FLEXRAN_AGENT_TIMER_TYPE_ONESHOT){ + ret = timer_setup(interval_sec, + interval_usec, + TASK_FLEXRAN_AGENT, + instance, + TIMER_ONE_SHOT, + timer_args, + timer_id); + + e->type = TIMER_ONE_SHOT; + } + else if (timer_type == FLEXRAN_AGENT_TIMER_TYPE_PERIODIC ){ + ret = timer_setup(interval_sec, + interval_usec, + TASK_FLEXRAN_AGENT, + instance, + TIMER_PERIODIC, + timer_args, + timer_id); + + e->type = TIMER_PERIODIC; + } + + if (ret < 0 ) { + return TIMER_SETUP_FAILED; + } + + e->agent_id = agent_id; + e->instance = instance; + e->state = FLEXRAN_AGENT_TIMER_STATE_ACTIVE; + e->timer_id = *timer_id; + e->xid = xid; + e->timer_args = timer_args; + e->cb = cb; + /*element should be a real pointer*/ + RB_INSERT(flexran_agent_map, &timer_instance.flexran_agent_head, e); + + LOG_I(FLEXRAN_AGENT,"Created a new timer with id 0x%lx for agent %d, instance %d \n", + e->timer_id, e->agent_id, e->instance); + + return 0; +} + +err_code_t flexran_agent_destroy_timer(long timer_id){ + + struct flexran_agent_timer_element_s *e = get_timer_entry(timer_id); + + if (e != NULL ) { + RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); + flexran_agent_destroy_flexran_message(e->timer_args->msg); + free(e); + } + + if (timer_remove(timer_id) < 0 ) + goto error; + + return 0; + + error: + LOG_E(FLEXRAN_AGENT, "timer can't be removed\n"); + return TIMER_REMOVED_FAILED ; +} + +err_code_t flexran_agent_destroy_timer_by_task_id(xid_t xid) { + struct flexran_agent_timer_element_s *e = NULL; + long timer_id; + RB_FOREACH(e, flexran_agent_map, &timer_instance.flexran_agent_head) { + if (e->xid == xid) { + timer_id = e->timer_id; + RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); + flexran_agent_destroy_flexran_message(e->timer_args->msg); + free(e); + if (timer_remove(timer_id) < 0 ) { + goto error; + } + } + } + return 0; + + error: + LOG_E(FLEXRAN_AGENT, "timer can't be removed\n"); + return TIMER_REMOVED_FAILED ; +} + +err_code_t flexran_agent_destroy_timers(void){ + + struct flexran_agent_timer_element_s *e = NULL; + + RB_FOREACH(e, flexran_agent_map, &timer_instance.flexran_agent_head) { + RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); + timer_remove(e->timer_id); + flexran_agent_destroy_flexran_message(e->timer_args->msg); + free(e); + } + + return 0; + +} + +void flexran_agent_sleep_until(struct timespec *ts, int delay) { + ts->tv_nsec += delay; + if(ts->tv_nsec >= 1000*1000*1000){ + ts->tv_nsec -= 1000*1000*1000; + ts->tv_sec++; + } + clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts, NULL); +} + + +err_code_t flexran_agent_stop_timer(long timer_id){ + + struct flexran_agent_timer_element_s *e=NULL; + struct flexran_agent_timer_element_s search; + memset(&search, 0, sizeof(struct flexran_agent_timer_element_s)); + search.timer_id = timer_id; + + e = RB_FIND(flexran_agent_map, &timer_instance.flexran_agent_head, &search); + + if (e != NULL ) { + e->state = FLEXRAN_AGENT_TIMER_STATE_STOPPED; + } + + timer_remove(timer_id); + + return 0; +} + +struct flexran_agent_timer_element_s * get_timer_entry(long timer_id) { + + struct flexran_agent_timer_element_s search; + memset(&search, 0, sizeof(struct flexran_agent_timer_element_s)); + search.timer_id = timer_id; + + return RB_FIND(flexran_agent_map, &timer_instance.flexran_agent_head, &search); +} diff --git a/openair2/ENB_APP/flexran_agent_timer.h b/openair2/ENB_APP/flexran_agent_timer.h new file mode 100644 index 0000000000..86e0d07825 --- /dev/null +++ b/openair2/ENB_APP/flexran_agent_timer.h @@ -0,0 +1,133 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file flexran_agent_timer.h + * \brief FlexRAN Timer header + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + */ + +#include +#include + +#include "flexran_agent_common.h" +#include "flexran_agent_common_internal.h" +#include "flexran_agent_extern.h" +#include "flexran_agent_defs.h" + + +# include "tree.h" +# include "intertask_interface.h" +# include "timer.h" + + + +/******************* + * timer primitves + *******************/ + +#define TIMER_NULL -1 +#define TIMER_TYPE_INVALIDE -2 +#define TIMER_SETUP_FAILED -3 +#define TIMER_REMOVED_FAILED -4 +#define TIMER_ELEMENT_NOT_FOUND -5 + + +/* Type of the callback executed when the timer expired */ +typedef Protocol__FlexranMessage *(*flexran_agent_timer_callback_t)(void*); + + +typedef struct flexran_agent_timer_args_s{ + mid_t mod_id; + Protocol__FlexranMessage *msg; +} flexran_agent_timer_args_t; + + +typedef struct flexran_agent_timer_element_s{ + RB_ENTRY(flexran_agent_timer_element_s) entry; + + agent_id_t agent_id; + instance_t instance; + + flexran_agent_timer_type_t type; + flexran_agent_timer_state_t state; + + uint32_t interval_sec; + uint32_t interval_usec; + + long timer_id; /* Timer id returned by the timer API*/ + xid_t xid; /*The id of the task as received by the controller + message*/ + + flexran_agent_timer_callback_t cb; + flexran_agent_timer_args_t *timer_args; + +} flexran_agent_timer_element_t; + +typedef struct flexran_agent_timer_instance_s{ + RB_HEAD(flexran_agent_map, flexran_agent_timer_element_s) flexran_agent_head; +}flexran_agent_timer_instance_t; + + +err_code_t flexran_agent_init_timer(void); + +/* Create a timer for some agent related event with id xid. Will store the id + of the generated timer in timer_id */ +err_code_t flexran_agent_create_timer(uint32_t interval_sec, + uint32_t interval_usec, + agent_id_t agent_id, + instance_t instance, + uint32_t timer_type, + xid_t xid, + flexran_agent_timer_callback_t cb, + void* timer_args, + long *timer_id); + +/* Destroy all existing timers */ +err_code_t flexran_agent_destroy_timers(void); + +/* Destroy the timer with the given timer_id */ +err_code_t flexran_agent_destroy_timer(long timer_id); + +/* Destroy the timer for task with id xid */ +err_code_t flexran_agent_destroy_timer_by_task_id(xid_t xid); + +/* Stop a timer */ +err_code_t flexran_agent_stop_timer(long timer_id); + +/* Restart the given timer */ +err_code_t flexran_agent_restart_timer(long *timer_id); + +/* Find the timer with the given timer_id */ +struct flexran_agent_timer_element_s * get_timer_entry(long timer_id); + +/* Obtain the protocol message stored in the given expired timer */ +Protocol__FlexranMessage * flexran_agent_process_timeout(long timer_id, void* timer_args); + +/* Comparator function comparing two timers. Decides the ordering of the timers */ +int flexran_agent_compare_timer(struct flexran_agent_timer_element_s *a, struct flexran_agent_timer_element_s *b); + +/*Specify a delay in nanoseconds to timespec and sleep until then*/ +void flexran_agent_sleep_until(struct timespec *ts, int delay); + +/* RB_PROTOTYPE is for .h files */ +RB_PROTOTYPE(flexran_agent_map, flexran_agent_timer_element_s, entry, flexran_agent_compare_timer); diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 6509471124..b75a3e7e8e 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -158,8 +158,8 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, //mac_remove_ue(module_idP, i, frameP, subframeP); //Inform the controller about the UE deactivation. Should be moved to RRC agent in the future #if defined(FLEXRAN_AGENT_SB_IF) - if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->flexran_agent_notify_ue_state_change(module_idP, + if (rrc_agent_registered[module_idP]) { + agent_rrc_xface[module_idP]->flexran_agent_notify_ue_state_change(module_idP, rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); } @@ -1082,15 +1082,15 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, for (CC_id=0;CC_idflexran_agent_send_update_mac_stats(module_idP); - } -#endif -#endif - + // if (mac_agent_registered[module_idP]) { + // agent_mac_xface[module_idP]->flexran_agent_send_update_mac_stats(module_idP); + // } +// #endif +// #endif +flexran_agent_send_update_stats(module_idP); /* int dummy=0; for (i=0; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 56ede260e8..01edbb87cf 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -180,6 +180,10 @@ uint8_t find_active_UEs(module_id_t module_idP,int CC_id){ } */ +int UE_BSR (uint8_t mod_id, uint8_t ue_id, uint8_t lcid) { + + return eNB_mac_inst[mod_id].UE_list.UE_template[UE_PCCID(mod_id,ue_id)][ue_id].bsr_info[lcid]; +} // get aggregation (L) form phy for a give UE unsigned char get_aggregation (uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt) @@ -304,6 +308,12 @@ printf("MAC: cannot add new UE for rnti %x\n", rntiP); return(-1); } +int CC_id_rnti_downlink (uint8_t mod_id, int CC_index, uint16_t ue_rnti) { + + return eNB_mac_inst[mod_id].UE_list.ordered_CCids[CC_index][ue_rnti]; +} + + //------------------------------------------------------------------------------ int rrc_mac_remove_ue(module_id_t mod_idP,rnti_t rntiP) //------------------------------------------------------------------------------ diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index da9d93c19a..6247548bcc 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -1899,7 +1899,7 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* cons ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A1); - + if (ho_state == 1 /*HO_MEASURMENT */ ) { LOG_I(RRC, "[eNB %d] frame %d: requesting A2, A3, A4, A5, and A6 event reporting\n", ctxt_pP->module_id, ctxt_pP->frame); @@ -2159,6 +2159,598 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* cons } +//----------------------------------------------------------------------------- +void +flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + const uint8_t ho_state, + agent_reconf_rrc * trig_param + ) +//----------------------------------------------------------------------------- +{ + uint8_t buffer[RRC_BUF_SIZE]; + uint16_t size; + int i; + + // configure SRB1/SRB2, PhysicalConfigDedicated, MAC_MainConfig for UE + eNB_RRC_INST* rrc_inst = &eNB_rrc_inst[ctxt_pP->module_id]; + struct PhysicalConfigDedicated** physicalConfigDedicated = &ue_context_pP->ue_context.physicalConfigDedicated; + + struct SRB_ToAddMod *SRB2_config = NULL; + struct SRB_ToAddMod__rlc_Config *SRB2_rlc_config = NULL; + struct SRB_ToAddMod__logicalChannelConfig *SRB2_lchan_config = NULL; + struct LogicalChannelConfig__ul_SpecificParameters + *SRB2_ul_SpecificParameters = NULL; + SRB_ToAddModList_t* SRB_configList = ue_context_pP->ue_context.SRB_configList; + SRB_ToAddModList_t **SRB_configList2 = NULL; + + struct DRB_ToAddMod *DRB_config = NULL; + struct RLC_Config *DRB_rlc_config = NULL; + struct PDCP_Config *DRB_pdcp_config = NULL; + struct PDCP_Config__rlc_AM *PDCP_rlc_AM = NULL; + struct PDCP_Config__rlc_UM *PDCP_rlc_UM = NULL; + struct LogicalChannelConfig *DRB_lchan_config = NULL; + struct LogicalChannelConfig__ul_SpecificParameters + *DRB_ul_SpecificParameters = NULL; + DRB_ToAddModList_t** DRB_configList = &ue_context_pP->ue_context.DRB_configList; + DRB_ToAddModList_t** DRB_configList2 = NULL; + MAC_MainConfig_t *mac_MainConfig = NULL; + MeasObjectToAddModList_t *MeasObj_list = NULL; + MeasObjectToAddMod_t *MeasObj = NULL; + ReportConfigToAddModList_t *ReportConfig_list = NULL; + ReportConfigToAddMod_t *ReportConfig_per, *ReportConfig_A1, + *ReportConfig_A2, *ReportConfig_A3, *ReportConfig_A4, *ReportConfig_A5; + MeasIdToAddModList_t *MeasId_list = NULL; + MeasIdToAddMod_t *MeasId0, *MeasId1, *MeasId2, *MeasId3, *MeasId4, *MeasId5; +#if Rel10 + long *sr_ProhibitTimer_r9 = NULL; + // uint8_t sCellIndexToAdd = rrc_find_free_SCell_index(enb_mod_idP, ue_mod_idP, 1); + //uint8_t sCellIndexToAdd = 0; +#endif + + long *logicalchannelgroup, *logicalchannelgroup_drb; + long *maxHARQ_Tx, *periodicBSR_Timer; + + RSRP_Range_t *rsrp = NULL; + struct MeasConfig__speedStatePars *Sparams = NULL; + QuantityConfig_t *quantityConfig = NULL; + CellsToAddMod_t *CellToAdd = NULL; + CellsToAddModList_t *CellsToAddModList = NULL; + struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList *dedicatedInfoNASList = NULL; + DedicatedInfoNAS_t *dedicatedInfoNas = NULL; + /* for no gcc warnings */ + (void)dedicatedInfoNas; + + C_RNTI_t *cba_RNTI = NULL; + + uint8_t xid = rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id); //Transaction_id, + +#ifdef CBA + //struct PUSCH_CBAConfigDedicated_vlola *pusch_CBAConfigDedicated_vlola; + uint8_t *cba_RNTI_buf; + cba_RNTI = CALLOC(1, sizeof(C_RNTI_t)); + cba_RNTI_buf = CALLOC(1, 2 * sizeof(uint8_t)); + cba_RNTI->buf = cba_RNTI_buf; + cba_RNTI->size = 2; + cba_RNTI->bits_unused = 0; + + // associate UEs to the CBa groups as a function of their UE id + if (rrc_inst->num_active_cba_groups) { + cba_RNTI->buf[0] = rrc_inst->cba_rnti[ue_mod_idP % rrc_inst->num_active_cba_groups] & 0xff; + cba_RNTI->buf[1] = 0xff; + LOG_D(RRC, + "[eNB %d] Frame %d: cba_RNTI = %x in group %d is attribued to UE %d\n", + enb_mod_idP, frameP, + rrc_inst->cba_rnti[ue_mod_idP % rrc_inst->num_active_cba_groups], + ue_mod_idP % rrc_inst->num_active_cba_groups, ue_mod_idP); + } else { + cba_RNTI->buf[0] = 0x0; + cba_RNTI->buf[1] = 0x0; + LOG_D(RRC, "[eNB %d] Frame %d: no cba_RNTI is configured for UE %d\n", enb_mod_idP, frameP, ue_mod_idP); + } + +#endif + + T(T_ENB_RRC_CONNECTION_RECONFIGURATION, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + // Configure SRB2 + /// SRB2 + SRB_configList2=&ue_context_pP->ue_context.SRB_configList2[xid]; + if (*SRB_configList2) { + free(*SRB_configList2); + } + *SRB_configList2 = CALLOC(1, sizeof(**SRB_configList2)); + memset(*SRB_configList2, 0, sizeof(**SRB_configList2)); + SRB2_config = CALLOC(1, sizeof(*SRB2_config)); + + SRB2_config->srb_Identity = 2; + SRB2_rlc_config = CALLOC(1, sizeof(*SRB2_rlc_config)); + SRB2_config->rlc_Config = SRB2_rlc_config; + + SRB2_rlc_config->present = SRB_ToAddMod__rlc_Config_PR_explicitValue; + SRB2_rlc_config->choice.explicitValue.present = RLC_Config_PR_am; + SRB2_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.t_PollRetransmit = T_PollRetransmit_ms15; + SRB2_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollPDU = PollPDU_p8; + SRB2_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollByte = PollByte_kB1000; + SRB2_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.maxRetxThreshold = UL_AM_RLC__maxRetxThreshold_t32; + SRB2_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_Reordering = T_Reordering_ms35; + SRB2_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_StatusProhibit = T_StatusProhibit_ms10; + + SRB2_lchan_config = CALLOC(1, sizeof(*SRB2_lchan_config)); + SRB2_config->logicalChannelConfig = SRB2_lchan_config; + + SRB2_lchan_config->present = SRB_ToAddMod__logicalChannelConfig_PR_explicitValue; + + SRB2_ul_SpecificParameters = CALLOC(1, sizeof(*SRB2_ul_SpecificParameters)); + + SRB2_ul_SpecificParameters->priority = 3; // let some priority for SRB1 and dedicated DRBs + SRB2_ul_SpecificParameters->prioritisedBitRate = + LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity; + SRB2_ul_SpecificParameters->bucketSizeDuration = + LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50; + + // LCG for CCCH and DCCH is 0 as defined in 36331 + logicalchannelgroup = CALLOC(1, sizeof(long)); + *logicalchannelgroup = 0; + + SRB2_ul_SpecificParameters->logicalChannelGroup = logicalchannelgroup; + + SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters = SRB2_ul_SpecificParameters; + // this list has the configuration for SRB1 and SRB2 + ASN_SEQUENCE_ADD(&SRB_configList->list, SRB2_config); + // this list has only the configuration for SRB2 + ASN_SEQUENCE_ADD(&(*SRB_configList2)->list, SRB2_config); + + // Configure DRB + //*DRB_configList = CALLOC(1, sizeof(*DRB_configList)); + // list for all the configured DRB + if (*DRB_configList) { + free(*DRB_configList); + } + *DRB_configList = CALLOC(1, sizeof(**DRB_configList)); + memset(*DRB_configList, 0, sizeof(**DRB_configList)); + + // list for the configured DRB for a this xid + DRB_configList2=&ue_context_pP->ue_context.DRB_configList2[xid]; + if (*DRB_configList2) { + free(*DRB_configList2); + } + *DRB_configList2 = CALLOC(1, sizeof(**DRB_configList2)); + memset(*DRB_configList2, 0, sizeof(**DRB_configList2)); + + + /// DRB + DRB_config = CALLOC(1, sizeof(*DRB_config)); + + DRB_config->eps_BearerIdentity = CALLOC(1, sizeof(long)); + *(DRB_config->eps_BearerIdentity) = 5L; // LW set to first value, allowed value 5..15, value : x+4 + // DRB_config->drb_Identity = (DRB_Identity_t) 1; //allowed values 1..32 + // NN: this is the 1st DRB for this ue, so set it to 1 + DRB_config->drb_Identity = (DRB_Identity_t) 1; // (ue_mod_idP+1); //allowed values 1..32, value: x + DRB_config->logicalChannelIdentity = CALLOC(1, sizeof(long)); + *(DRB_config->logicalChannelIdentity) = (long)3; // value : x+2 + DRB_rlc_config = CALLOC(1, sizeof(*DRB_rlc_config)); + DRB_config->rlc_Config = DRB_rlc_config; + +#ifdef RRC_DEFAULT_RAB_IS_AM + DRB_rlc_config->present = RLC_Config_PR_am; + DRB_rlc_config->choice.am.ul_AM_RLC.t_PollRetransmit = T_PollRetransmit_ms50; + DRB_rlc_config->choice.am.ul_AM_RLC.pollPDU = PollPDU_p16; + DRB_rlc_config->choice.am.ul_AM_RLC.pollByte = PollByte_kBinfinity; + DRB_rlc_config->choice.am.ul_AM_RLC.maxRetxThreshold = UL_AM_RLC__maxRetxThreshold_t8; + DRB_rlc_config->choice.am.dl_AM_RLC.t_Reordering = T_Reordering_ms35; + DRB_rlc_config->choice.am.dl_AM_RLC.t_StatusProhibit = T_StatusProhibit_ms25; +#else + DRB_rlc_config->present = RLC_Config_PR_um_Bi_Directional; + DRB_rlc_config->choice.um_Bi_Directional.ul_UM_RLC.sn_FieldLength = SN_FieldLength_size10; + DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.sn_FieldLength = SN_FieldLength_size10; +#ifdef CBA + DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.t_Reordering = T_Reordering_ms5;//T_Reordering_ms25; +#else + DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.t_Reordering = T_Reordering_ms35; +#endif +#endif + + DRB_pdcp_config = CALLOC(1, sizeof(*DRB_pdcp_config)); + DRB_config->pdcp_Config = DRB_pdcp_config; + DRB_pdcp_config->discardTimer = CALLOC(1, sizeof(long)); + *DRB_pdcp_config->discardTimer = PDCP_Config__discardTimer_infinity; + DRB_pdcp_config->rlc_AM = NULL; + DRB_pdcp_config->rlc_UM = NULL; + + /* avoid gcc warnings */ + (void)PDCP_rlc_AM; + (void)PDCP_rlc_UM; + +#ifdef RRC_DEFAULT_RAB_IS_AM // EXMIMO_IOT + PDCP_rlc_AM = CALLOC(1, sizeof(*PDCP_rlc_AM)); + DRB_pdcp_config->rlc_AM = PDCP_rlc_AM; + PDCP_rlc_AM->statusReportRequired = FALSE; +#else + PDCP_rlc_UM = CALLOC(1, sizeof(*PDCP_rlc_UM)); + DRB_pdcp_config->rlc_UM = PDCP_rlc_UM; + PDCP_rlc_UM->pdcp_SN_Size = PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits; +#endif + DRB_pdcp_config->headerCompression.present = PDCP_Config__headerCompression_PR_notUsed; + + DRB_lchan_config = CALLOC(1, sizeof(*DRB_lchan_config)); + DRB_config->logicalChannelConfig = DRB_lchan_config; + DRB_ul_SpecificParameters = CALLOC(1, sizeof(*DRB_ul_SpecificParameters)); + DRB_lchan_config->ul_SpecificParameters = DRB_ul_SpecificParameters; + + DRB_ul_SpecificParameters->priority = 12; // lower priority than srb1, srb2 and other dedicated bearer + DRB_ul_SpecificParameters->prioritisedBitRate =LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8 ; + //LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity; + DRB_ul_SpecificParameters->bucketSizeDuration = + LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50; + + // LCG for DTCH can take the value from 1 to 3 as defined in 36331: normally controlled by upper layers (like RRM) + logicalchannelgroup_drb = CALLOC(1, sizeof(long)); + *logicalchannelgroup_drb = 1; + DRB_ul_SpecificParameters->logicalChannelGroup = logicalchannelgroup_drb; + + ASN_SEQUENCE_ADD(&(*DRB_configList)->list, DRB_config); + ASN_SEQUENCE_ADD(&(*DRB_configList2)->list, DRB_config); + + //ue_context_pP->ue_context.DRB_configList2[0] = &(*DRB_configList); + + mac_MainConfig = CALLOC(1, sizeof(*mac_MainConfig)); + // ue_context_pP->ue_context.mac_MainConfig = mac_MainConfig; + + mac_MainConfig->ul_SCH_Config = CALLOC(1, sizeof(*mac_MainConfig->ul_SCH_Config)); + + maxHARQ_Tx = CALLOC(1, sizeof(long)); + *maxHARQ_Tx = MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; + mac_MainConfig->ul_SCH_Config->maxHARQ_Tx = maxHARQ_Tx; + periodicBSR_Timer = CALLOC(1, sizeof(long)); + *periodicBSR_Timer = PeriodicBSR_Timer_r12_sf64; + mac_MainConfig->ul_SCH_Config->periodicBSR_Timer = periodicBSR_Timer; + mac_MainConfig->ul_SCH_Config->retxBSR_Timer = RetxBSR_Timer_r12_sf320; + mac_MainConfig->ul_SCH_Config->ttiBundling = 0; // FALSE + + mac_MainConfig->timeAlignmentTimerDedicated = TimeAlignmentTimer_infinity; + + mac_MainConfig->drx_Config = NULL; + + mac_MainConfig->phr_Config = CALLOC(1, sizeof(*mac_MainConfig->phr_Config)); + + mac_MainConfig->phr_Config->present = MAC_MainConfig__phr_Config_PR_setup; + mac_MainConfig->phr_Config->choice.setup.periodicPHR_Timer = MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20; // sf20 = 20 subframes + + mac_MainConfig->phr_Config->choice.setup.prohibitPHR_Timer = MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20; // sf20 = 20 subframes + + mac_MainConfig->phr_Config->choice.setup.dl_PathlossChange = MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1; // Value dB1 =1 dB, dB3 = 3 dB + +#ifdef Rel10 + sr_ProhibitTimer_r9 = CALLOC(1, sizeof(long)); + *sr_ProhibitTimer_r9 = 0; // SR tx on PUCCH, Value in number of SR period(s). Value 0 = no timer for SR, Value 2= 2*SR + mac_MainConfig->ext1 = CALLOC(1, sizeof(struct MAC_MainConfig__ext1)); + mac_MainConfig->ext1->sr_ProhibitTimer_r9 = sr_ProhibitTimer_r9; + //sps_RA_ConfigList_rlola = NULL; +#endif + + //change the transmission mode for the primary component carrier + //TODO: add codebook subset restriction here + //TODO: change TM for secondary CC in SCelltoaddmodlist + if (*physicalConfigDedicated) { + if ((*physicalConfigDedicated)->antennaInfo) { + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.transmissionMode = rrc_inst->configuration.ue_TransmissionMode[0]; + LOG_D(RRC,"Setting transmission mode to %ld+1\n",rrc_inst->configuration.ue_TransmissionMode[0]); + if (rrc_inst->configuration.ue_TransmissionMode[0]==AntennaInfoDedicated__transmissionMode_tm3) { + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction= + CALLOC(1,sizeof(AntennaInfoDedicated__codebookSubsetRestriction_PR)); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->present = + AntennaInfoDedicated__codebookSubsetRestriction_PR_n2TxAntenna_tm3; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm3.buf= MALLOC(1); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm3.buf[0] = 0xc0; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm3.size=1; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm3.bits_unused=6; + } + else if (rrc_inst->configuration.ue_TransmissionMode[0]==AntennaInfoDedicated__transmissionMode_tm4) { + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction= + CALLOC(1,sizeof(AntennaInfoDedicated__codebookSubsetRestriction_PR)); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->present = + AntennaInfoDedicated__codebookSubsetRestriction_PR_n2TxAntenna_tm4; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm4.buf= MALLOC(1); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm4.buf[0] = 0xfc; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm4.size=1; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm4.bits_unused=2; + + } + else if (rrc_inst->configuration.ue_TransmissionMode[0]==AntennaInfoDedicated__transmissionMode_tm5) { + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction= + CALLOC(1,sizeof(AntennaInfoDedicated__codebookSubsetRestriction_PR)); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->present = + AntennaInfoDedicated__codebookSubsetRestriction_PR_n2TxAntenna_tm5; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm5.buf= MALLOC(1); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm5.buf[0] = 0xf0; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm5.size=1; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm5.bits_unused=4; + } + else if (rrc_inst->configuration.ue_TransmissionMode[0]==AntennaInfoDedicated__transmissionMode_tm6) { + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction= + CALLOC(1,sizeof(AntennaInfoDedicated__codebookSubsetRestriction_PR)); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->present = + AntennaInfoDedicated__codebookSubsetRestriction_PR_n2TxAntenna_tm6; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm6.buf= MALLOC(1); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm6.buf[0] = 0xf0; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm6.size=1; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm6.bits_unused=4; + } + } + else { + LOG_E(RRC,"antenna_info not present in physical_config_dedicated. Not reconfiguring!\n"); + } + if ((*physicalConfigDedicated)->cqi_ReportConfig) { + if ((rrc_inst->configuration.ue_TransmissionMode[0]==AntennaInfoDedicated__transmissionMode_tm4) || + (rrc_inst->configuration.ue_TransmissionMode[0]==AntennaInfoDedicated__transmissionMode_tm5) || + (rrc_inst->configuration.ue_TransmissionMode[0]==AntennaInfoDedicated__transmissionMode_tm6)) { + //feedback mode needs to be set as well + //TODO: I think this is taken into account in the PHY automatically based on the transmission mode variable + printf("setting cqi reporting mode to rm31\n"); +#if defined(Rel10) || defined(Rel14) + *((*physicalConfigDedicated)->cqi_ReportConfig->cqi_ReportModeAperiodic)=CQI_ReportModeAperiodic_rm31; +#else + *((*physicalConfigDedicated)->cqi_ReportConfig->cqi_ReportModeAperiodic)=CQI_ReportConfig__cqi_ReportModeAperiodic_rm31; // HLC CQI, no PMI +#endif + } + } + else { + LOG_E(RRC,"cqi_ReportConfig not present in physical_config_dedicated. Not reconfiguring!\n"); + } + } + else { + LOG_E(RRC,"physical_config_dedicated not present in RRCConnectionReconfiguration. Not reconfiguring!\n"); + } + + // Measurement ID list + MeasId_list = CALLOC(1, sizeof(*MeasId_list)); + memset((void *)MeasId_list, 0, sizeof(*MeasId_list)); + + MeasId0 = CALLOC(1, sizeof(*MeasId0)); + MeasId0->measId = 1; + MeasId0->measObjectId = 1; + MeasId0->reportConfigId = 1; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId0); + + /* + * Add one EUTRA Measurement Object + */ + + MeasObj_list = CALLOC(1, sizeof(*MeasObj_list)); + memset((void *)MeasObj_list, 0, sizeof(*MeasObj_list)); + + // Configure MeasObject + + MeasObj = CALLOC(1, sizeof(*MeasObj)); + memset((void *)MeasObj, 0, sizeof(*MeasObj)); + + MeasObj->measObjectId = 1; + MeasObj->measObject.present = MeasObjectToAddMod__measObject_PR_measObjectEUTRA; + MeasObj->measObject.choice.measObjectEUTRA.carrierFreq = 3350; //band 7, 2.68GHz + //MeasObj->measObject.choice.measObjectEUTRA.carrierFreq = 36090; //band 33, 1.909GHz + MeasObj->measObject.choice.measObjectEUTRA.allowedMeasBandwidth = AllowedMeasBandwidth_mbw25; + MeasObj->measObject.choice.measObjectEUTRA.presenceAntennaPort1 = 1; + MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.buf = CALLOC(1, sizeof(uint8_t)); + MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.buf[0] = 0; + MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.size = 1; + MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.bits_unused = 6; + MeasObj->measObject.choice.measObjectEUTRA.offsetFreq = NULL; // Default is 15 or 0dB + + MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList = + (CellsToAddModList_t *) CALLOC(1, sizeof(*CellsToAddModList)); + + CellsToAddModList = MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList; + + // Add adjacent cell lists (6 per eNB) + for (i = 0; i < 6; i++) { + CellToAdd = (CellsToAddMod_t *) CALLOC(1, sizeof(*CellToAdd)); + CellToAdd->cellIndex = i + 1; + CellToAdd->physCellId = get_adjacent_cell_id(ctxt_pP->module_id, i); + CellToAdd->cellIndividualOffset = Q_OffsetRange_dB0; + + ASN_SEQUENCE_ADD(&CellsToAddModList->list, CellToAdd); + } + + ASN_SEQUENCE_ADD(&MeasObj_list->list, MeasObj); + // rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measObjectToAddModList = MeasObj_list; + + // Report Configurations for periodical, A1-A5 events + + /* RRC Strategy Measurement */ + + + if (strcmp("one_shot", trig_param->trigger_policy) == 0){ + + trig_param->report_interval = 0; + trig_param->report_amount = 0; + + } + + else if (strcmp("event_driven", trig_param->trigger_policy) == 0){ + + trig_param->report_interval = 6; + trig_param->report_amount = 2; + + } + + else if (strcmp("periodical", trig_param->trigger_policy) == 0){ + + trig_param->report_interval = 1; + trig_param->report_amount = 7; + + } + + else { + + LOG_E(FLEXRAN_AGENT, "There is something wrong on RRC agent!"); + } + + + + ReportConfig_list = CALLOC(1, sizeof(*ReportConfig_list)); + + ReportConfig_per = CALLOC(1, sizeof(*ReportConfig_per)); + + // Periodical Measurement Report + + ReportConfig_per->reportConfigId = 1; + ReportConfig_per->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_periodical; + + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerType.choice.periodical.purpose = + ReportConfigEUTRA__triggerType__periodical__purpose_reportStrongestCells; + + // ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.timeToTrigger = TimeToTrigger_ms40; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerQuantity = ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportInterval = trig_param->report_interval ;//ReportInterval_ms2048; // RRC counter frame- ms1024 is 1ms + + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportAmount = trig_param->report_amount; //ReportConfigEUTRA__reportAmount_r2; // put r1 to see once, r2 for 2 times and ... + + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_per); + + + + quantityConfig = CALLOC(1, sizeof(*quantityConfig)); + memset((void *)quantityConfig, 0, sizeof(*quantityConfig)); + quantityConfig->quantityConfigEUTRA = CALLOC(1, sizeof(struct QuantityConfigEUTRA)); + memset((void *)quantityConfig->quantityConfigEUTRA, 0, sizeof(*quantityConfig->quantityConfigEUTRA)); + quantityConfig->quantityConfigCDMA2000 = NULL; + quantityConfig->quantityConfigGERAN = NULL; + quantityConfig->quantityConfigUTRA = NULL; + quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP = + CALLOC(1, sizeof(*(quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP))); + quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ = + CALLOC(1, sizeof(*(quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ))); + *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP = FilterCoefficient_fc4; + *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ = FilterCoefficient_fc4; + + +#if defined(ENABLE_ITTI) + /* Initialize NAS list */ + dedicatedInfoNASList = CALLOC(1, sizeof(struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList)); + + /* Add all NAS PDUs to the list */ + for (i = 0; i < ue_context_pP->ue_context.nb_of_e_rabs; i++) { + if (ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer != NULL) { + dedicatedInfoNas = CALLOC(1, sizeof(DedicatedInfoNAS_t)); + memset(dedicatedInfoNas, 0, sizeof(OCTET_STRING_t)); + OCTET_STRING_fromBuf(dedicatedInfoNas, + (char*)ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer, + ue_context_pP->ue_context.e_rab[i].param.nas_pdu.length); + ASN_SEQUENCE_ADD(&dedicatedInfoNASList->list, dedicatedInfoNas); + } + + /* TODO parameters yet to process ... */ + // { + // ue_context_pP->ue_context.e_rab[i].param.qos; + // ue_context_pP->ue_context.e_rab[i].param.sgw_addr; + // ue_context_pP->ue_context.e_rab[i].param.gtp_teid; + // } + + /* TODO should test if e RAB are Ok before! */ + ue_context_pP->ue_context.e_rab[i].status = E_RAB_STATUS_DONE; + LOG_D(RRC, "setting the status for the default DRB (index %d) to (%d,%s)\n", + i, ue_context_pP->ue_context.e_rab[i].status, "E_RAB_STATUS_DONE"); + } + + /* If list is empty free the list and reset the address */ + if (dedicatedInfoNASList->list.count == 0) { + free(dedicatedInfoNASList); + dedicatedInfoNASList = NULL; + } + +#endif + + memset(buffer, 0, RRC_BUF_SIZE); + + size = do_RRCConnectionReconfiguration(ctxt_pP, + buffer, + xid, //Transaction_id, + (SRB_ToAddModList_t*)NULL, // SRB_configList + (DRB_ToAddModList_t*)NULL, + (DRB_ToReleaseList_t*)NULL, // DRB2_list, + (struct SPS_Config*)NULL, // *sps_Config, + (struct PhysicalConfigDedicated*)*physicalConfigDedicated, +// #ifdef EXMIMO_IOT +// NULL, NULL, NULL,NULL, +// #else + (MeasObjectToAddModList_t*)MeasObj_list, + (ReportConfigToAddModList_t*)ReportConfig_list, + (QuantityConfig_t*)quantityConfig, + (MeasIdToAddModList_t*)MeasId_list, +// #endif + (MAC_MainConfig_t*)mac_MainConfig, + (MeasGapConfig_t*)NULL, + (MobilityControlInfo_t*)NULL, + (struct MeasConfig__speedStatePars*)Sparams, + (RSRP_Range_t*)rsrp, + (C_RNTI_t*)cba_RNTI, + (struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList*)dedicatedInfoNASList +#if defined(Rel10) || defined(Rel14) + , (SCellToAddMod_r10_t*)NULL +#endif + ); + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC Connection Reconfiguration\n"); + for (i = 0; i < size; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)buffer)[i]); + } + LOG_F(RRC,"\n"); + //////////////////////////////////////// +#endif + +#if defined(ENABLE_ITTI) + + /* Free all NAS PDUs */ + for (i = 0; i < ue_context_pP->ue_context.nb_of_e_rabs; i++) { + if (ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer != NULL) { + /* Free the NAS PDU buffer and invalidate it */ + free(ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer); + ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer = NULL; + } + } + +#endif + + LOG_I(RRC, + "[eNB %d] Frame %d, Logical Channel DL-DCCH, Generate RRCConnectionReconfiguration (bytes %d, UE id %x)\n", + ctxt_pP->module_id, ctxt_pP->frame, size, ue_context_pP->ue_context.rnti); + + LOG_D(RRC, + "[FRAME %05d][RRC_eNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcConnectionReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n", + ctxt_pP->frame, ctxt_pP->module_id, size, ue_context_pP->ue_context.rnti, rrc_eNB_mui, ctxt_pP->module_id, DCCH); + + MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + buffer, + size, + MSC_AS_TIME_FMT" rrcConnectionReconfiguration UE %x MUI %d size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_pP->ue_context.rnti, + rrc_eNB_mui, + size); + + rrc_data_req( + ctxt_pP, + DCCH, + rrc_eNB_mui++, + SDU_CONFIRM_NO, + size, + buffer, + PDCP_TRANSMISSION_MODE_CONTROL); +} + + + //----------------------------------------------------------------------------- int @@ -2246,41 +2838,41 @@ rrc_eNB_process_MeasurementReport( ) //----------------------------------------------------------------------------- { - T(T_ENB_RRC_MEASUREMENT_REPORT, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), - T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + // T(T_ENB_RRC_MEASUREMENT_REPORT, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + // T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); - LOG_I(RRC, "[eNB %d] Frame %d: Process Measurement Report From UE %x (Measurement Id %d)\n", - ctxt_pP->module_id, ctxt_pP->frame, ctxt_pP->rnti, (int)measResults2->measId); + // LOG_I(RRC, "[eNB %d] Frame %d: Process Measurement Report From UE %x (Measurement Id %d)\n", + // ctxt_pP->module_id, ctxt_pP->frame, ctxt_pP->rnti, (int)measResults2->measId); - if (measResults2->measResultNeighCells->choice.measResultListEUTRA.list.count > 0) { - LOG_I(RRC, "Physical Cell Id %d\n", - (int)measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]->physCellId); - LOG_I(RRC, "RSRP of Target %d\n", - (int)*(measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]-> - measResult.rsrpResult)); - LOG_I(RRC, "RSRQ of Target %d\n", - (int)*(measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]-> - measResult.rsrqResult)); - } + // if (measResults2->measResultNeighCells->choice.measResultListEUTRA.list.count > 0) { + // LOG_I(RRC, "Physical Cell Id %d\n", + // (int)measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]->physCellId); + // LOG_I(RRC, "RSRP of Target %d\n", + // (int)*(measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]-> + // measResult.rsrpResult)); + // LOG_I(RRC, "RSRQ of Target %d\n", + // (int)*(measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]-> + // measResult.rsrqResult)); + // } -#if defined(Rel10) || defined(Rel14) +// #if defined(Rel10) || defined(Rel14) LOG_I(RRC, "RSRP of Source %ld\n", measResults2->measResultPCell.rsrpResult); LOG_I(RRC, "RSRQ of Source %ld\n", measResults2->measResultPCell.rsrqResult); -#else - LOG_I(RRC, "RSRP of Source %d\n", measResults2->measResultServCell.rsrpResult); - LOG_I(RRC, "RSRQ of Source %d\n", measResults2->measResultServCell.rsrqResult); -#endif +// #else + // LOG_I(RRC, "RSRP of Source %d\n", measResults2->measResultServCell.rsrpResult); + // LOG_I(RRC, "RSRQ of Source %d\n", measResults2->measResultServCell.rsrqResult); +// #endif - if (ue_context_pP->ue_context.handover_info->ho_prepare != 0xF0) { - rrc_eNB_generate_HandoverPreparationInformation(ctxt_pP, - ue_context_pP, - measResults2->measResultNeighCells->choice. - measResultListEUTRA.list.array[0]->physCellId); - } else { - LOG_D(RRC, "[eNB %d] Frame %d: Ignoring MeasReport from UE %x as Handover is in progress... \n", ctxt_pP->module_id, ctxt_pP->frame, - ctxt_pP->rnti); - } + // if (ue_context_pP->ue_context.handover_info->ho_prepare != 0xF0) { + // rrc_eNB_generate_HandoverPreparationInformation(ctxt_pP, + // ue_context_pP, + // measResults2->measResultNeighCells->choice. + // measResultListEUTRA.list.array[0]->physCellId); + // } else { + // LOG_D(RRC, "[eNB %d] Frame %d: Ignoring MeasReport from UE %x as Handover is in progress... \n", ctxt_pP->module_id, ctxt_pP->frame, + // ctxt_pP->rnti); + // } //Look for IP address of the target eNB //Send Handover Request -> target eNB @@ -4501,6 +5093,13 @@ rrc_eNB_decode_dcch( ue_context_p, &ul_dcch_msg->message.choice.c1.choice.measurementReport. criticalExtensions.choice.c1.choice.measurementReport_r8.measResults); + #if defined(FLEXRAN_AGENT_SB_IF) + + if (rrc_agent_registered[ctxt_pP->module_id]) { + agent_rrc_xface[ctxt_pP->eNB_index]->flexran_trigger_rrc_measurements (ctxt_pP->module_id, &ul_dcch_msg->message.choice.c1.choice.measurementReport.criticalExtensions.choice.c1.choice.measurementReport_r8.measResults); + } +#endif + break; case UL_DCCH_MessageType__c1_PR_rrcConnectionReconfigurationComplete: @@ -4553,8 +5152,8 @@ rrc_eNB_decode_dcch( #if defined(FLEXRAN_AGENT_SB_IF) //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future - if (mac_agent_registered[ctxt_pP->module_id]) { - agent_mac_xface[ctxt_pP->eNB_index]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, + if (rrc_agent_registered[ctxt_pP->module_id]) { + agent_rrc_xface[ctxt_pP->eNB_index]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, ue_context_p->ue_id_rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_UPDATED); } @@ -4657,8 +5256,8 @@ rrc_eNB_decode_dcch( #if defined(FLEXRAN_AGENT_SB_IF) //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future - if (mac_agent_registered[ctxt_pP->module_id]) { - agent_mac_xface[ctxt_pP->eNB_index]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, + if (rrc_agent_registered[ctxt_pP->module_id]) { + agent_rrc_xface[ctxt_pP->eNB_index]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, ue_context_p->ue_id_rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_ACTIVATED); } From 714ad4d774a665bc288425d47dcf2ba2f9e2d7cc Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Wed, 5 Apr 2017 16:48:21 +0200 Subject: [PATCH 005/284] Warning Decreasing --- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 15 +++++++------- .../CONTROL_MODULES/RRC/flexran_agent_rrc.c | 16 +++++++-------- .../CONTROL_MODULES/RRC/flexran_agent_rrc.h | 6 +++--- .../RRC/flexran_agent_rrc_defs.h | 4 +++- openair2/ENB_APP/flexran_agent.c | 2 +- openair2/ENB_APP/flexran_agent.h | 5 ++++- openair2/ENB_APP/flexran_agent_common.c | 1 + openair2/ENB_APP/flexran_agent_common.h | 14 ++++++------- openair2/ENB_APP/flexran_agent_handler.c | 5 +++-- openair2/ENB_APP/flexran_agent_ran_api.c | 20 ++++++++++++++----- openair2/ENB_APP/flexran_agent_ran_api.h | 13 +++++++++++- .../MAC/flexran_agent_scheduler_dlsch_ue.c | 2 +- .../flexran_agent_scheduler_dlsch_ue_remote.c | 2 +- openair2/RRC/LITE/rrc_eNB.c | 6 +++--- 14 files changed, 70 insertions(+), 41 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 01df6248f1..ba69308553 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -32,6 +32,7 @@ #include "flexran_agent_mac_internal.h" #include "flexran_agent_net_comm.h" #include "flexran_agent_timer.h" +#include "flexran_agent_ran_api.h" #include "LAYER2/MAC/proto.h" #include "LAYER2/MAC/flexran_agent_mac_proto.h" @@ -63,7 +64,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, // Protocol__FlexHeader *header; int i, j, k; - int cc_id = 0; + // int cc_id = 0; int enb_id = mod_id; /* Allocate memory for list of UE reports */ @@ -141,11 +142,11 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, /* Check flag for creation of MAC CE buffer status report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_CE_BS) { // TODO: Fill in the actual MAC CE buffer status report - ue_report[i]->pending_mac_ces = (flexran_get_MAC_CE_bitmap_TA(enb_id,i,0) | (0 << 1) | (0 << 2) - | (0 << 3)) & 15; /* Use as bitmap. Set one or more of the; /* Use as bitmap. Set one or more of the - PROTOCOL__FLEX_CE_TYPE__FLPCET_ values - found in stats_common.pb-c.h. See - flex_ce_type in FlexRAN specification */ + ue_report[i]->pending_mac_ces = (flexran_get_MAC_CE_bitmap_TA(enb_id,i,0) | (0 << 1) | (0 << 2) | (0 << 3)) & 15; + // Use as bitmap. Set one or more of the; /* Use as bitmap. Set one or more of the + // PROTOCOL__FLEX_CE_TYPE__FLPCET_ values + // found in stats_common.pb-c.h. See + // flex_ce_type in FlexRAN specification ue_report[i]->has_pending_mac_ces = 1; } @@ -213,7 +214,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, goto error; protocol__flex_csi_p11__init(csi11); - csi11->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + csi11->wb_cqi = flexran_get_ue_wcqi (enb_id, i); // According To spec 36.213 if (flexran_get_antenna_ports(enb_id, j) == 2 && csi_reports[j]->ri == 1) { diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c index 9475b06643..d48d12d670 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c @@ -61,12 +61,12 @@ void flexran_agent_init_rrc_agent(mid_t mod_id) { -int flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { +void flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { int size; Protocol__FlexranMessage *msg; Protocol__FlexHeader *header; void *data; - int priority; + int priority = 0; err_code_t err_code; int xid = 0; @@ -258,7 +258,7 @@ int flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_cha LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); return; error: - LOG_D(FLEXRAN_AGENT, "Could not send UE state message\n"); + LOG_E(FLEXRAN_AGENT, "Could not send UE state message becasue of %d \n",err_code); } @@ -278,10 +278,10 @@ int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg) { } /* this is called by RRC as a part of rrc xface . The controller previously requested this*/ -int flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t* measResults) { +void flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t* measResults) { // int i, m, k; - int priority; + int priority = 0; // Warning Preventing void *data; int size; err_code_t err_code; @@ -618,16 +618,16 @@ int flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t* measResults) LOG_I(FLEXRAN_AGENT,"RRC Trigger is done \n"); - return 0; + return; error: - LOG_E(RRC, "Error triggering RRC measurements message!"); + LOG_E(FLEXRAN_AGENT, "Could not send UE state message becasue of %d \n",err_code); /* Free the measurement report received from UE. */ // ASN_STRUCT_FREE(asn_DEF_MeasResults, p->meas); /* Free the params. */ // free(p); - return -1; + // return -1; } diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h index 17b58dac93..aa210f9d41 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h @@ -41,7 +41,7 @@ #include "flexran.pb-c.h" #include "stats_messages.pb-c.h" #include "stats_common.pb-c.h" -#include "MeasResults.h" + #include "flexran_agent_common.h" #include "flexran_agent_rrc_defs.h" @@ -51,7 +51,7 @@ void flexran_agent_init_rrc_agent(mid_t mod_id); /* UE state change message constructor and destructor */ -int flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change); +void flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change); int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg); @@ -63,7 +63,7 @@ int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg); // void flexran_agent_send_update_rrc_stats(mid_t mod_id); /* this is called by RRC as a part of rrc xface . The controller previously requested this*/ -int flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t *); +void flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t *); /*Register technology specific interface callbacks*/ int flexran_agent_register_rrc_xface(mid_t mod_id, AGENT_RRC_xface *xface); diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h index 10fc4ba254..679bc4d623 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h @@ -38,9 +38,11 @@ #ifndef __FLEXRAN_AGENT_RRC_PRIMITIVES_H__ #define __FLEXRAN_AGENT_RRC_PRIMITIVES_H__ +#include "PHY/extern.h" #include "flexran_agent_defs.h" #include "flexran.pb-c.h" #include "header.pb-c.h" +#include "MeasResults.h" #define RINGBUFFER_SIZE 100 @@ -55,7 +57,7 @@ typedef struct { void (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, uint32_t state_change); - void (*flexran_trigger_rrc_measurements)(mid_t mod_id, MeasResults_t* measResults) + void (*flexran_trigger_rrc_measurements)(mid_t mod_id, MeasResults_t* measResults); } AGENT_RRC_xface; diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c index d96076df83..ec984cfa8b 100644 --- a/openair2/ENB_APP/flexran_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -264,7 +264,7 @@ int flexran_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properti AGENT_MAC_xface *mac_agent_xface = (AGENT_MAC_xface *) malloc(sizeof(AGENT_MAC_xface)); flexran_agent_register_mac_xface(mod_id, mac_agent_xface); - AGENT_RRC_xface *rrc_agent_xface = (AGENT_MAC_xface *) malloc(sizeof(AGENT_MAC_xface)); + AGENT_RRC_xface *rrc_agent_xface = (AGENT_RRC_xface *) malloc(sizeof(AGENT_RRC_xface)); flexran_agent_register_rrc_xface(mod_id, rrc_agent_xface); /* diff --git a/openair2/ENB_APP/flexran_agent.h b/openair2/ENB_APP/flexran_agent.h index aec4f004a8..0ef48e2105 100644 --- a/openair2/ENB_APP/flexran_agent.h +++ b/openair2/ENB_APP/flexran_agent.h @@ -34,7 +34,10 @@ #include "flexran_agent_extern.h" #include "flexran_agent_timer.h" #include "flexran_agent_defs.h" - +#include "flexran_agent_net_comm.h" +#include "flexran_agent_ran_api.h" +#include "flexran_agent_mac.h" +#include "flexran_agent_rrc.h" #include "log.h" #include "assertions.h" diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index 7d9cfe685c..27364a7eaa 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -33,6 +33,7 @@ #include "flexran_agent_common_internal.h" #include "flexran_agent_extern.h" #include "flexran_agent_net_comm.h" +#include "flexran_agent_ran_api.h" #include "PHY/extern.h" #include "log.h" diff --git a/openair2/ENB_APP/flexran_agent_common.h b/openair2/ENB_APP/flexran_agent_common.h index 4f2b9c71bb..d96712622f 100644 --- a/openair2/ENB_APP/flexran_agent_common.h +++ b/openair2/ENB_APP/flexran_agent_common.h @@ -37,7 +37,8 @@ #include "flexran.pb-c.h" #include "stats_messages.pb-c.h" #include "stats_common.pb-c.h" - +#include "flexran_agent_ran_api.h" +#include "flexran_agent_net_comm.h" #include "flexran_agent_defs.h" #include "enb_config.h" @@ -156,16 +157,15 @@ int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__Flexr /* Function to be used to handle reply message . */ int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg); -/* Statistics request protocol message constructor and destructor */ +/* Top level Statistics request protocol message constructor and destructor */ int flexran_agent_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg); int flexran_agent_destroy_stats_request(Protocol__FlexranMessage *msg); -int flexran_agent_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg); -int flexran_agent_destroy_stats_request(Protocol__FlexranMessage *msg); - +err_code_t flexran_agent_init_cont_stats_update(mid_t mod_id); + +void flexran_agent_send_update_stats(mid_t mod_id); + err_code_t flexran_agent_enable_cont_stats_update(mid_t mod_id, xid_t xid, stats_request_config_t *stats_req) ; -int flexran_agent_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg); - #endif diff --git a/openair2/ENB_APP/flexran_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c index b57039bec5..84948d1eee 100644 --- a/openair2/ENB_APP/flexran_agent_handler.c +++ b/openair2/ENB_APP/flexran_agent_handler.c @@ -31,6 +31,7 @@ #include "flexran_agent_mac.h" #include "flexran_agent_rrc.h" #include "flexran_agent_timer.h" +#include "flexran_agent_ran_api.h" #include "log.h" #include "assertions.h" @@ -96,7 +97,7 @@ Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id, err_code= PROTOCOL__FLEXRAN_ERR__MSG_DECODING; goto error; } - printf("==================> %d %d \n", decoded_message->msg_case, decoded_message->msg_dir); + //printf("==================> %d %d \n", decoded_message->msg_case, decoded_message->msg_dir); if ((decoded_message->msg_case > sizeof(agent_messages_callback) / (3 * sizeof(flexran_agent_message_decoded_callback))) || (decoded_message->msg_dir > PROTOCOL__FLEXRAN_DIRECTION__UNSUCCESSFUL_OUTCOME)){ err_code= PROTOCOL__FLEXRAN_ERR__MSG_NOT_HANDLED; @@ -754,4 +755,4 @@ err_code_t flexran_agent_destroy_cont_stats_update(mid_t mod_id) { // mac_agent_registered[mod_id] = 0; return 1; -} \ No newline at end of file +} diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 17a53c7eb0..dd3e8a4bcb 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -152,11 +152,21 @@ int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id) { // return ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].dl_cqi; } -int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { +int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id, char * buffer_status) { rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); - mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id,frame,ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0); - return rlc_status.bytes_in_buffer; + mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id,frame,ENB_FLAG_YES,MBMS_FLAG_NO,channel_id,0); + + if (strcmp(buffer_status, "bytes_buffer")){ + return rlc_status.bytes_in_buffer; + } else if(strcmp(buffer_status, "pdu_buffer")) { + return rlc_status.pdus_in_buffer; + } + /* else if (strcmp(buffer_status, "head_line")){ */ + + /* return rlc_status.head_sdu_remaining_size_to_send; */ + + /* } */ } int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { @@ -168,7 +178,7 @@ int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_i short flexran_get_TA(mid_t mod_id, mid_t ue_id, int CC_id) { - UE_list_t *UE_list=&eNB_mac_inst[mod_id].UE_list; + // UE_list_t *UE_list=&eNB_mac_inst[mod_id].UE_list; int rnti; rnti = flexran_get_ue_crnti(mod_id, ue_id); @@ -227,7 +237,7 @@ void flexran_update_TA(mid_t mod_id, mid_t ue_id, int CC_id) { int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) { - UE_list_t *UE_list = &eNB_mac_inst[mod_id].UE_list; + // UE_list_t *UE_list = &eNB_mac_inst[mod_id].UE_list; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 12962a1f9d..4a893a4c96 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -89,7 +89,7 @@ int flexran_get_ue_phr (mid_t mod_id, mid_t ue_id); int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id); /* Get the transmission queue size for a UE with a channel_id logical channel id */ -int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); +int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id, char * buffer_status); /* Get the head of line delay for a UE with a channel_id logical channel id */ int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); @@ -198,6 +198,17 @@ int flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, int CC_id); int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id); +int flexran_get_hopping_mode(mid_t mod_id, int CC_id); + +int flexran_get_hopping_offset(mid_t mod_id, int CC_id); + +int flexran_get_n_SB(mid_t mod_id, int CC_id); + +int flexran_get_phich_resource(mid_t mod_id, int CC_id); + +int flexran_get_enable64QAM(mid_t mod_id, int CC_id); + +int flexran_get_phich_duration(mid_t mod_id, int CC_id); /* * ************************************ diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index 00027f04ce..953de903c4 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -50,7 +50,7 @@ #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" #include "ENB_APP/flexran_agent_defs.h" - +#include "flexran_agent_ran_api.h" #include "pdcp.h" #include "header.pb-c.h" diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c index 7dec8d0c56..bff461acc7 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c @@ -30,7 +30,7 @@ */ #include "flexran_agent_common_internal.h" - +#include "flexran_agent_ran_api.h" #include "flexran_agent_scheduler_dlsch_ue_remote.h" #include "LAYER2/MAC/defs.h" diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 6247548bcc..1f2bf2d262 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -2198,10 +2198,10 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt MeasObjectToAddModList_t *MeasObj_list = NULL; MeasObjectToAddMod_t *MeasObj = NULL; ReportConfigToAddModList_t *ReportConfig_list = NULL; - ReportConfigToAddMod_t *ReportConfig_per, *ReportConfig_A1, - *ReportConfig_A2, *ReportConfig_A3, *ReportConfig_A4, *ReportConfig_A5; + ReportConfigToAddMod_t *ReportConfig_per;//, *ReportConfig_A1, + // *ReportConfig_A2, *ReportConfig_A3, *ReportConfig_A4, *ReportConfig_A5; MeasIdToAddModList_t *MeasId_list = NULL; - MeasIdToAddMod_t *MeasId0, *MeasId1, *MeasId2, *MeasId3, *MeasId4, *MeasId5; + MeasIdToAddMod_t *MeasId0; //, *MeasId1, *MeasId2, *MeasId3, *MeasId4, *MeasId5; #if Rel10 long *sr_ProhibitTimer_r9 = NULL; // uint8_t sCellIndexToAdd = rrc_find_free_SCell_index(enb_mod_idP, ue_mod_idP, 1); From 77c4d3742f884039d7d228b05cf36e5fc2ca269d Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Fri, 7 Apr 2017 11:28:51 +0200 Subject: [PATCH 006/284] Wanring Preventing remote-sch --- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 10 +++++----- .../CONTROL_MODULES/MAC/flexran_agent_mac_defs.h | 6 +++--- .../CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h | 2 +- openair2/ENB_APP/flexran_agent_common.h | 2 +- openair2/ENB_APP/flexran_agent_handler.c | 4 ++-- openair2/ENB_APP/flexran_agent_ran_api.c | 16 +++------------- openair2/ENB_APP/flexran_agent_ran_api.h | 2 +- 7 files changed, 16 insertions(+), 26 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index ba69308553..d22633a818 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -115,11 +115,11 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, protocol__flex_rlc_bsr__init(rlc_reports[j]); rlc_reports[j]->lc_id = j+1; rlc_reports[j]->has_lc_id = 1; - rlc_reports[j]->tx_queue_size = flexran_get_tx_queue_size(enb_id, i, j + 1, "bytes_buffer"); + rlc_reports[j]->tx_queue_size = flexran_get_tx_queue_size(enb_id, i, j + 1); rlc_reports[j]->has_tx_queue_size = 1; //TODO:Set tx queue head of line delay in ms - rlc_reports[j]->tx_queue_hol_delay = flexran_get_tx_queue_size(enb_id, i, j + 1, "head_line"); + rlc_reports[j]->tx_queue_hol_delay = flexran_get_hol_delay(enb_id, i, j + 1); rlc_reports[j]->has_tx_queue_hol_delay = 1; //TODO:Set retransmission queue size in bytes rlc_reports[j]->retransmission_queue_size = 10; @@ -128,7 +128,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, rlc_reports[j]->retransmission_queue_hol_delay = 100; rlc_reports[j]->has_retransmission_queue_hol_delay = 0; //TODO DONE:Set current size of the pending message in bytes - rlc_reports[j]->status_pdu_size = flexran_get_hol_delay(enb_id, i, j + 1); + rlc_reports[j]->status_pdu_size = flexran_get_tx_queue_size(enb_id, i, j + 1); rlc_reports[j]->has_status_pdu_size = 1; } @@ -1174,8 +1174,8 @@ int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->flexran_agent_send_sr_info = flexran_agent_send_sr_info; xface->flexran_agent_send_sf_trigger = flexran_agent_send_sf_trigger; //xface->flexran_agent_send_update_mac_stats = flexran_agent_send_update_mac_stats; - xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_default; - //xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_remote; + // xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_default; + xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_remote; xface->flexran_agent_get_pending_dl_mac_config = flexran_agent_get_pending_dl_mac_config; xface->dl_scheduler_loaded_lib = NULL; diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h index 9ec8594f88..8354223123 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h @@ -48,7 +48,7 @@ typedef struct { /// Send to the controller all the mac stat updates that occured during this subframe /// based on the stats request configuration - void (*flexran_agent_send_update_mac_stats)(mid_t mod_id); + // void (*flexran_agent_send_update_mac_stats)(mid_t mod_id); /// Provide to the scheduler a pending dl_mac_config message void (*flexran_agent_get_pending_dl_mac_config)(mid_t mod_id, @@ -63,8 +63,8 @@ typedef struct { /// Notify the controller for a state change of a particular UE, by sending the proper /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) - int (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, - uint8_t state_change); + // int (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, + // uint8_t state_change); void *dl_scheduler_loaded_lib; diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h index 679bc4d623..95fbf3bed0 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h @@ -54,7 +54,7 @@ typedef struct { /// Notify the controller for a state change of a particular UE, by sending the proper /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) - void (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, + int (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, uint32_t state_change); void (*flexran_trigger_rrc_measurements)(mid_t mod_id, MeasResults_t* measResults); diff --git a/openair2/ENB_APP/flexran_agent_common.h b/openair2/ENB_APP/flexran_agent_common.h index d96712622f..8fd62a0524 100644 --- a/openair2/ENB_APP/flexran_agent_common.h +++ b/openair2/ENB_APP/flexran_agent_common.h @@ -166,6 +166,6 @@ err_code_t flexran_agent_init_cont_stats_update(mid_t mod_id); void flexran_agent_send_update_stats(mid_t mod_id); err_code_t flexran_agent_enable_cont_stats_update(mid_t mod_id, xid_t xid, stats_request_config_t *stats_req) ; - +err_code_t flexran_agent_disable_cont_stats_update(mid_t mod_id); #endif diff --git a/openair2/ENB_APP/flexran_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c index 84948d1eee..fc2ed135c8 100644 --- a/openair2/ENB_APP/flexran_agent_handler.c +++ b/openair2/ENB_APP/flexran_agent_handler.c @@ -97,7 +97,7 @@ Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id, err_code= PROTOCOL__FLEXRAN_ERR__MSG_DECODING; goto error; } - //printf("==================> %d %d \n", decoded_message->msg_case, decoded_message->msg_dir); + // printf("==================> %d %d \n", decoded_message->msg_case, decoded_message->msg_dir); if ((decoded_message->msg_case > sizeof(agent_messages_callback) / (3 * sizeof(flexran_agent_message_decoded_callback))) || (decoded_message->msg_dir > PROTOCOL__FLEXRAN_DIRECTION__UNSUCCESSFUL_OUTCOME)){ err_code= PROTOCOL__FLEXRAN_ERR__MSG_NOT_HANDLED; @@ -309,7 +309,7 @@ int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__Flexr } else if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_CONTINUOUS) { /*If request was for continuous updates, disable the previous configuration and set up a new one*/ - // flexran_agent_disable_cont_stats_update(mod_id); + flexran_agent_disable_cont_stats_update(mod_id); stats_request_config_t request_config; request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS; request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE; diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index dd3e8a4bcb..59ccb67293 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -152,21 +152,11 @@ int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id) { // return ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].dl_cqi; } -int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id, char * buffer_status) { +int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); - mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id,frame,ENB_FLAG_YES,MBMS_FLAG_NO,channel_id,0); - - if (strcmp(buffer_status, "bytes_buffer")){ - return rlc_status.bytes_in_buffer; - } else if(strcmp(buffer_status, "pdu_buffer")) { - return rlc_status.pdus_in_buffer; - } - /* else if (strcmp(buffer_status, "head_line")){ */ - - /* return rlc_status.head_sdu_remaining_size_to_send; */ - - /* } */ + mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id,frame,ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0); + return rlc_status.bytes_in_buffer; } int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 4a893a4c96..8a7d6dbaf7 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -89,7 +89,7 @@ int flexran_get_ue_phr (mid_t mod_id, mid_t ue_id); int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id); /* Get the transmission queue size for a UE with a channel_id logical channel id */ -int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id, char * buffer_status); +int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); /* Get the head of line delay for a UE with a channel_id logical channel id */ int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); From 14fb9e2ba201790e3c741501594e930248e66e09 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 11 Apr 2017 08:58:20 +0000 Subject: [PATCH 007/284] Changed default scheduler to local --- openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index d22633a818..63dba00d7c 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -1174,8 +1174,8 @@ int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->flexran_agent_send_sr_info = flexran_agent_send_sr_info; xface->flexran_agent_send_sf_trigger = flexran_agent_send_sf_trigger; //xface->flexran_agent_send_update_mac_stats = flexran_agent_send_update_mac_stats; - // xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_default; - xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_remote; + xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_default; + //xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_remote; xface->flexran_agent_get_pending_dl_mac_config = flexran_agent_get_pending_dl_mac_config; xface->dl_scheduler_loaded_lib = NULL; From e36c5b6024d02e497c2196978a03025104db1a1e Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 11 Apr 2017 09:28:22 +0000 Subject: [PATCH 008/284] Fixed compilation errors when compiling without agent enabled --- openair2/LAYER2/MAC/eNB_scheduler.c | 11 ++++++----- openair2/RRC/LITE/rrc_eNB.c | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index b75a3e7e8e..2bea6e1f1f 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -1082,15 +1082,16 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, for (CC_id=0;CC_idflexran_agent_send_update_mac_stats(module_idP); // } -// #endif -// #endif -flexran_agent_send_update_stats(module_idP); +#endif +#endif + /* int dummy=0; for (i=0; diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 1f2bf2d262..53616d334d 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -2158,6 +2158,7 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* cons PDCP_TRANSMISSION_MODE_CONTROL); } +#if defined(FLEXRAN_AGENT_SB_IF) //----------------------------------------------------------------------------- void @@ -2749,7 +2750,7 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt PDCP_TRANSMISSION_MODE_CONTROL); } - +#endif //----------------------------------------------------------------------------- From e3df5d3de55f8966c7eba3c9c24e3438b228ea86 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 11 Apr 2017 11:46:34 +0000 Subject: [PATCH 009/284] Fixed warnings and bugs --- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 4 +++- .../RRC/flexran_agent_rrc_defs.h | 4 ++-- openair2/ENB_APP/flexran_agent_common.c | 3 ++- openair2/LAYER2/MAC/proto.h | 1 + openair2/RRC/LITE/proto.h | 17 +++++++++++++++++ openair2/RRC/LITE/rrc_eNB.c | 3 --- 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 63dba00d7c..73ae74a32f 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -214,7 +214,9 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, goto error; protocol__flex_csi_p11__init(csi11); - csi11->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + csi11->wb_cqi = malloc(sizeof(csi11->wb_cqi)); + csi11->n_wb_cqi = 1; + csi11->wb_cqi[0] = flexran_get_ue_wcqi (enb_id, i); // According To spec 36.213 if (flexran_get_antenna_ports(enb_id, j) == 2 && csi_reports[j]->ri == 1) { diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h index 95fbf3bed0..ad1375171e 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h @@ -54,8 +54,8 @@ typedef struct { /// Notify the controller for a state change of a particular UE, by sending the proper /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) - int (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, - uint32_t state_change); + void (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, + uint8_t state_change); void (*flexran_trigger_rrc_measurements)(mid_t mod_id, MeasResults_t* measResults); diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index d67eb8b6a7..78d3a75ec7 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -1075,7 +1075,8 @@ int flexran_agent_rrc_measurement(mid_t mod_id, const void *params, Protocol__Fl int flexran_agent_destroy_rrc_measurement(Protocol__FlexranMessage *msg){ - + // TODO + return 0; } diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index ea264f1bfd..16f2d186ea 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -539,6 +539,7 @@ void sort_ue_ul (module_id_t module_idP,int frameP, sub_frame_t subframeP); void assign_max_mcs_min_rb(module_id_t module_idP,int frameP, sub_frame_t subframeP,uint16_t *first_rb); void adjust_bsr_info(int buffer_occupancy, uint16_t TBS, UE_TEMPLATE *UE_template); int phy_stats_exist(module_id_t Mod_id, int rnti); +void sort_UEs (module_id_t Mod_idP, int frameP, sub_frame_t subframeP); /*! \fn UE_L2_state_t ue_scheduler(const module_id_t module_idP,const frame_t frameP, const sub_frame_t subframe, const lte_subframe_t direction,const uint8_t eNB_index) \brief UE scheduler where all the ue background tasks are done. This function performs the following: 1) Trigger PDCP every 5ms 2) Call RRC for link status return to PHY3) Perform SR/BSR procedures for scheduling feedback 4) Perform PHR procedures. diff --git a/openair2/RRC/LITE/proto.h b/openair2/RRC/LITE/proto.h index 8433980be4..20bc99ab79 100644 --- a/openair2/RRC/LITE/proto.h +++ b/openair2/RRC/LITE/proto.h @@ -33,6 +33,10 @@ #include "RRC/LITE/defs.h" +#if defined(FLEXRAN_AGENT_SB_IF) +#include "flexran_agent_extern.h" +#endif + //main.c int rrc_init_global_param(void); int L3_xface_init(void); @@ -254,6 +258,19 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration( const uint8_t ho_state ); + +#if defined(FLEXRAN_AGENT_SB_IF) + +void +flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + const uint8_t ho_state, + agent_reconf_rrc * trig_param + ); + +#endif + void rrc_eNB_generate_dedeicatedRRCConnectionReconfiguration( const protocol_ctxt_t* const ctxt_pP, diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 53616d334d..11628a80b6 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -93,9 +93,6 @@ #include "SIMULATION/TOOLS/defs.h" // for taus -#if defined(FLEXRAN_AGENT_SB_IF) -#include "flexran_agent_extern.h" -#endif //#define XER_PRINT #ifdef PHY_EMUL From 3bd3bedcd2d60bad25f79970bfc6f56b9f18f698 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 11 Apr 2017 13:25:08 +0000 Subject: [PATCH 010/284] Fixed ue state change notification functionality for deactivation of UEs --- openair2/RRC/LITE/L2_interface.c | 11 +++++++++++ openair2/RRC/LITE/rrc_eNB.c | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/openair2/RRC/LITE/L2_interface.c b/openair2/RRC/LITE/L2_interface.c index 64734cac9a..6a64d7811e 100644 --- a/openair2/RRC/LITE/L2_interface.c +++ b/openair2/RRC/LITE/L2_interface.c @@ -52,6 +52,10 @@ extern UE_MAC_INST *UE_mac_inst; # include "intertask_interface.h" #endif +#if defined(FLEXRAN_AGENT_SB_IF) +#include "flexran_agent_extern.h" +#endif + //#define RRC_DATA_REQ_DEBUG #define DEBUG_RRC 1 @@ -734,6 +738,13 @@ void mac_eNB_rrc_ul_failure(const module_id_t Mod_instP, else { LOG_W(RRC,"Frame %d, Subframe %d: UL failure: UE %x unknown \n",frameP,subframeP,rntiP); } +#if defined(FLEXRAN_AGENT_SB_IF) + if (rrc_agent_registered[Mod_instP]) { + agent_rrc_xface[Mod_instP]->flexran_agent_notify_ue_state_change(Mod_instP, + rntiP, + PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); + } +#endif rrc_mac_remove_ue(Mod_instP,rntiP); } diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 11628a80b6..6fbdd645ed 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -829,6 +829,15 @@ rrc_eNB_free_UE(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_s* #endif #endif +#if defined(FLEXRAN_AGENT_SB_IF) + if (rrc_agent_registered[enb_mod_idP]) { + agent_rrc_xface[enb_mod_idP]->flexran_agent_notify_ue_state_change(enb_mod_idP, + rnti, + PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); + } +#endif + + rrc_mac_remove_ue(enb_mod_idP,rnti); rrc_rlc_remove_ue(&ctxt); pdcp_remove_UE(&ctxt); @@ -4885,6 +4894,13 @@ rrc_eNB_decode_ccch( } else { // no context available +#if defined(FLEXRAN_AGENT_SB_IF) + if (rrc_agent_registered[ctxt_pP->module_id]) { + agent_rrc_xface[ctxt_pP->module_id]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, + ctxt_pP->rnti, + PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); + } +#endif LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Can't create new context for UE random UE identity (0x%" PRIx64 ")\n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), random_value); From 169f33464e91d43410447b34dc21f5fbd31ec241 Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Tue, 18 Apr 2017 18:13:42 +0200 Subject: [PATCH 011/284] Uplink Agent Mac function --- cmake_targets/CMakeLists.txt | 1 + .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 1 + .../MAC/flexran_agent_mac_defs.h | 4 + openair2/LAYER2/MAC/eNB_scheduler.c | 183 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 2 +- openair2/LAYER2/MAC/flexran_agent_mac_proto.h | 8 + .../MAC/flexran_agent_scheduler_ulsch_ue.c | 1673 +++++++++++++++++ 7 files changed, 1868 insertions(+), 4 deletions(-) create mode 100644 openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 5413014fbf..192590e20f 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1207,6 +1207,7 @@ if (FLEXRAN_AGENT_SB_IF) set (MAC_SRC ${MAC_SRC} ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue.c + ${MAC_DIR}/flexran_agent_scheduler_ulsch_ue.c ${MAC_DIR}/flexran_agent_scheduler_dataplane.c ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue_remote.c ) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 73ae74a32f..405837061a 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -1177,6 +1177,7 @@ int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->flexran_agent_send_sf_trigger = flexran_agent_send_sf_trigger; //xface->flexran_agent_send_update_mac_stats = flexran_agent_send_update_mac_stats; xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_default; + xface->flexran_agent_schedule_ul_spec = flexran_agent_schedule_ulsch_ue_spec; //xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_remote; xface->flexran_agent_get_pending_dl_mac_config = flexran_agent_get_pending_dl_mac_config; diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h index 8354223123..ab6bf57417 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h @@ -61,6 +61,10 @@ typedef struct { int *mbsfn_flag, Protocol__FlexranMessage **dl_info); + void (*flexran_agent_schedule_ul_spec)(mid_t module_idP, uint32_t frameP, unsigned char cooperation_flag, + uint32_t subframeP, + unsigned char sched_subframe); + /// Notify the controller for a state change of a particular UE, by sending the proper /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) // int (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 2bea6e1f1f..7250d66f07 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -382,11 +382,26 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, if (mac_xface->frame_parms->frame_type == FDD) { //FDD +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,0,4);//,calibration_flag); +#else + if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif + } else if ((mac_xface->frame_parms->tdd_config == 0) || //TDD (mac_xface->frame_parms->tdd_config == 3) || (mac_xface->frame_parms->tdd_config == 6)) { +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,4);//,calibration_flag); +#else + if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif } #ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); @@ -418,14 +433,31 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, switch (mac_xface->frame_parms->tdd_config) { case 0: case 1: - schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,7); +#ifndef FLEXRAN_AGENT_SB_IF + schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,7);//,calibration_flag); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif #ifndef FLEXRAN_AGENT_SB_IF fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #endif break; case 6: +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,8); +#else + + if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif + #ifndef FLEXRAN_AGENT_SB_IF fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #endif @@ -435,7 +467,16 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; } } else { //FDD +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,1,5); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif + #ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); @@ -465,7 +506,16 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // TDD, nothing // FDD, normal UL/DLSCH if (mac_xface->frame_parms->frame_type == FDD) { //FDD +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,2,6); +#else + + if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif + #ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); @@ -498,7 +548,15 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, if (mac_xface->frame_parms->frame_type == TDD) { switch (mac_xface->frame_parms->tdd_config) { case 2: +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,7); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif // no break here! case 5: @@ -528,8 +586,16 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; } } else { //FDD - +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,3,7); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif + #ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); @@ -563,7 +629,15 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, switch (mac_xface->frame_parms->tdd_config) { case 1: // schedule_RA(module_idP,frameP,subframeP); +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,8); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif // no break here! case 2: @@ -600,8 +674,16 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { if (mac_xface->frame_parms->frame_type == FDD) { //FDD - +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP, frameP, cooperation_flag, 4, 8); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif + #ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP, frameP, subframeP, mbsfn_status); fill_DLSCH_dci(module_idP, frameP, subframeP, mbsfn_status); @@ -637,7 +719,16 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, //schedule_RA(module_idP,frameP,subframeP,5); if (mac_xface->frame_parms->frame_type == FDD) { schedule_RA(module_idP,frameP,subframeP,1); +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,5,9); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif + #ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP, frameP, subframeP, mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); @@ -700,7 +791,15 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; case 1: +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,2); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif // schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); #ifndef FLEXRAN_AGENT_SB_IF fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); @@ -708,7 +807,15 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; case 6: +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif // schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); #ifndef FLEXRAN_AGENT_SB_IF fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); @@ -767,7 +874,16 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; } } else { //FDD +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,6,0); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif + #ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); @@ -850,7 +966,16 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; } } else { //FDD +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,7,1); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif + #ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); @@ -888,7 +1013,16 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 5: // schedule_RA(module_idP,subframeP); +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,2); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif + #ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); @@ -915,7 +1049,16 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; } } else { //FDD +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,8,2); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif + #ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); @@ -946,7 +1089,15 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, if (mac_xface->frame_parms->frame_type == TDD) { switch (mac_xface->frame_parms->tdd_config) { case 1: +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif schedule_RA(module_idP,frameP,subframeP,7); // 7 = Msg3 subframeP, not #ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); @@ -972,7 +1123,16 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 3: case 4: +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif + #ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); @@ -996,7 +1156,15 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; case 6: +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,4); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif //schedule_RA(module_idP,frameP,subframeP); #ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); @@ -1049,7 +1217,16 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; } } else { //FDD +#ifndef FLEXRAN_AGENT_SB_IF schedule_ulsch(module_idP,frameP,cooperation_flag,9,3); +#else + +if (mac_agent_registered[module_idP]){ + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + } + +#endif + #ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 6d0044b346..585d9c2c1c 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -885,7 +885,7 @@ abort(); rb_table_index=UE_template->pre_allocated_rb_table_index_ul; } else { mcs=10;//cmin (10, openair_daq_vars.target_ue_ul_mcs); - rb_table_index=5; // for PHR + rb_table_index=13; // for PHR } UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; diff --git a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h index a3ff3b6a4a..8a9d5971e3 100644 --- a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h +++ b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h @@ -168,6 +168,14 @@ void _dlsch_scheduler_pre_processor_allocate (module_id_t Mod_id, void flexran_schedule_ue_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, Protocol__FlexranMessage **dl_info); +/* + Uplink scheduler used by MAC agent +*/ + +void flexran_agent_schedule_ulsch_ue_spec(module_id_t module_idP, frame_t frameP, unsigned char cooperation_flag, + sub_frame_t subframeP, + unsigned char sched_subframe); + /* * Data plane function for applying the DL decisions of the scheduler */ diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c new file mode 100644 index 0000000000..2abd09024b --- /dev/null +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -0,0 +1,1673 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file eNB_scheduler_ulsch.c + * \brief FlexRAN eNB procedures for the ULSCH transport channel + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 1.0 + * @ingroup _mac + + */ + +#include "assertions.h" +#include "PHY/defs.h" +#include "PHY/extern.h" + +#include "SCHED/defs.h" +#include "SCHED/extern.h" + +#include "LAYER2/MAC/defs.h" +#include "LAYER2/MAC/proto.h" +#include "LAYER2/MAC/extern.h" +#include "UTIL/LOG/log.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" +#include "OCG.h" +#include "OCG_extern.h" + +#include "RRC/LITE/extern.h" +#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" + +//#include "LAYER2/MAC/pre_processor.c" +#include "pdcp.h" + +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +#endif + +#include "T.h" + +// #define ENABLE_MAC_PAYLOAD_DEBUG +// #define DEBUG_eNB_SCHEDULER 1 + +// // This table holds the allowable PRB sizes for ULSCH transmissions +// uint8_t rb_table[33] = {1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36,40,45,48,50,54,60,72,75,80,81,90,96,100}; + +// void rx_sdu(const module_id_t enb_mod_idP, +// const int CC_idP, +// const frame_t frameP, +// const sub_frame_t subframeP, +// const rnti_t rntiP, +// uint8_t *sduP, +// const uint16_t sdu_lenP, +// const int harq_pidP, +// uint8_t *msg3_flagP) +// { + +// unsigned char rx_ces[MAX_NUM_CE],num_ce,num_sdu,i,*payload_ptr; +// unsigned char rx_lcids[NB_RB_MAX]; +// unsigned short rx_lengths[NB_RB_MAX]; +// int UE_id = find_UE_id(enb_mod_idP,rntiP); +// int ii,j; +// eNB_MAC_INST *eNB = &eNB_mac_inst[enb_mod_idP]; +// UE_list_t *UE_list= &eNB->UE_list; +// int crnti_rx=0; +// int old_buffer_info; + +// start_meas(&eNB->rx_ulsch_sdu); + +// if ((UE_id > NUMBER_OF_UE_MAX) || (UE_id == -1) ) +// for(ii=0; iiUE_sched_ctrl[UE_id].ul_scheduled &= (~(1<UE_sched_ctrl[UE_id].ul_inactivity_timer=0; +// UE_list->UE_sched_ctrl[UE_id].ul_failure_timer =0; +// UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= (~(1<UE_sched_ctrl[UE_id].ul_out_of_sync > 0) { +// UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync=0; +// mac_eNB_rrc_ul_in_sync(enb_mod_idP,CC_idP,frameP,subframeP,UE_RNTI(enb_mod_idP,UE_id)); +// } +// } + + +// payload_ptr = parse_ulsch_header(sduP,&num_ce,&num_sdu,rx_ces,rx_lcids,rx_lengths,sdu_lenP); + +// T(T_ENB_MAC_UE_UL_PDU, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(rntiP), T_INT(frameP), T_INT(subframeP), +// T_INT(harq_pidP), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu)); +// T(T_ENB_MAC_UE_UL_PDU_WITH_DATA, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(rntiP), T_INT(frameP), T_INT(subframeP), +// T_INT(harq_pidP), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu), T_BUFFER(sduP, sdu_lenP)); + +// eNB->eNB_stats[CC_idP].ulsch_bytes_rx=sdu_lenP; +// eNB->eNB_stats[CC_idP].total_ulsch_bytes_rx+=sdu_lenP; +// eNB->eNB_stats[CC_idP].total_ulsch_pdus_rx+=1; +// // control element +// for (i=0; iUE_template[CC_idP][UE_id].phr_info = (payload_ptr[0] & 0x3f) - PHR_MAPPING_OFFSET; +// LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : Received PHR PH = %d (db)\n", +// enb_mod_idP, CC_idP, rx_ces[i], UE_list->UE_template[CC_idP][UE_id].phr_info); +// UE_list->UE_template[CC_idP][UE_id].phr_info_configured=1; +// UE_list->UE_sched_ctrl[UE_id].phr_received = 1; +// } +// payload_ptr+=sizeof(POWER_HEADROOM_CMD); +// break; + +// case CRNTI: +// UE_id = find_UE_id(enb_mod_idP,(((uint16_t)payload_ptr[0])<<8) + payload_ptr[1]); +// LOG_I(MAC, "[eNB %d] Frame %d, Subframe %d CC_id %d MAC CE_LCID %d (ce %d/%d): CRNTI %x (UE_id %d) in Msg3\n", +// frameP,subframeP,enb_mod_idP, CC_idP, rx_ces[i], i,num_ce,(((uint16_t)payload_ptr[0])<<8) + payload_ptr[1],UE_id); +// if (UE_id!=-1) { +// UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer=0; +// UE_list->UE_sched_ctrl[UE_id].ul_failure_timer=0; +// if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) { +// UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync=0; +// mac_eNB_rrc_ul_in_sync(enb_mod_idP,CC_idP,frameP,subframeP,(((uint16_t)payload_ptr[0])<<8) + payload_ptr[1]); +// } +// } +// crnti_rx=1; +// payload_ptr+=2; + +// if (msg3_flagP != NULL) { +// *msg3_flagP = 0; +// } +// break; + +// case TRUNCATED_BSR: +// case SHORT_BSR: { +// uint8_t lcgid; +// lcgid = (payload_ptr[0] >> 6); + +// LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", +// enb_mod_idP, CC_idP, rx_ces[i], lcgid, payload_ptr[0] & 0x3f); + +// if (crnti_rx==1) +// LOG_I(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", +// enb_mod_idP, CC_idP, rx_ces[i], lcgid, payload_ptr[0] & 0x3f); +// if (UE_id != -1) { + +// UE_list->UE_template[CC_idP][UE_id].bsr_info[lcgid] = (payload_ptr[0] & 0x3f); + +// // update buffer info + +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[lcgid]]; + +// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]; + +// PHY_vars_eNB_g[enb_mod_idP][CC_idP]->pusch_stats_bsr[UE_id][(frameP*10)+subframeP] = (payload_ptr[0] & 0x3f); +// if (UE_id == UE_list->head) +// VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR,PHY_vars_eNB_g[enb_mod_idP][CC_idP]->pusch_stats_bsr[UE_id][(frameP*10)+subframeP]); +// if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[lcgid] == 0 ) { +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[lcgid]=frameP; +// } +// if (mac_eNB_get_rrc_status(enb_mod_idP,UE_RNTI(enb_mod_idP,UE_id)) < RRC_CONNECTED) +// LOG_I(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : ul_total_buffer = %d (lcg increment %d)\n", +// enb_mod_idP, CC_idP, rx_ces[i], UE_list->UE_template[CC_idP][UE_id].ul_total_buffer, +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]); +// } +// else { + +// } +// payload_ptr += 1;//sizeof(SHORT_BSR); // fixme +// } +// break; + +// case LONG_BSR: +// if (UE_id != -1) { +// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0] = ((payload_ptr[0] & 0xFC) >> 2); +// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1] = +// ((payload_ptr[0] & 0x03) << 4) | ((payload_ptr[1] & 0xF0) >> 4); +// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2] = +// ((payload_ptr[1] & 0x0F) << 2) | ((payload_ptr[2] & 0xC0) >> 6); +// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] = (payload_ptr[2] & 0x3F); + +// // update buffer info +// old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]; +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0]]; + +// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]; +// if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) +// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; +// else +// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; + +// old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]; +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1]]; +// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]; +// if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) +// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; +// else +// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; + +// old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]; +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2]]; +// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]; +// if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) +// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; +// else +// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; + +// old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]; +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3]]; +// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]; +// if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) +// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; +// else +// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; + +// LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " +// "%u LCGID2 = %u LCGID3 = %u\n", +// enb_mod_idP, CC_idP, +// rx_ces[i], +// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0], +// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1], +// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2], +// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3]); +// if (crnti_rx==1) +// LOG_I(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " +// "%u LCGID2 = %u LCGID3 = %u\n", +// enb_mod_idP, CC_idP, +// rx_ces[i], +// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0], +// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1], +// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2], +// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3]); + +// if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0] == 0 ) { +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID0]=0; +// } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID0] == 0) { +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID0]=frameP; +// } + +// if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1] == 0 ) { +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID1]=0; +// } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID1] == 0) { +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID1]=frameP; +// } + +// if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2] == 0 ) { +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID2]=0; +// } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID2] == 0) { +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID2]=frameP; +// } + +// if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] == 0 ) { +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID3]= 0; +// } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID3] == 0) { +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID3]=frameP; + +// } +// } + +// payload_ptr += 3;////sizeof(LONG_BSR); +// break; + +// default: +// LOG_E(MAC, "[eNB %d] CC_id %d Received unknown MAC header (0x%02x)\n", enb_mod_idP, CC_idP, rx_ces[i]); +// break; +// } +// } + +// for (i=0; i CCCH_PAYLOAD_SIZE_MAX) { +// LOG_E(MAC, "[eNB %d/%d] frame %d received CCCH of size %d (too big, maximum allowed is %d), dropping packet\n", +// enb_mod_idP, CC_idP, frameP, rx_lengths[i], CCCH_PAYLOAD_SIZE_MAX); +// break; +// } +// LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, Received CCCH: %x.%x.%x.%x.%x.%x, Terminating RA procedure for UE rnti %x\n", +// enb_mod_idP,CC_idP,frameP, +// payload_ptr[0],payload_ptr[1],payload_ptr[2],payload_ptr[3],payload_ptr[4], payload_ptr[5], rntiP); +// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC,1); +// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC,0); +// for (ii=0; iicommon_channels[CC_idP].RA_template[ii].rnti, rntiP, +// eNB->common_channels[CC_idP].RA_template[ii].RA_active); + +// if ((eNB->common_channels[CC_idP].RA_template[ii].rnti==rntiP) && +// (eNB->common_channels[CC_idP].RA_template[ii].RA_active==TRUE)) { + +// //payload_ptr = parse_ulsch_header(msg3,&num_ce,&num_sdu,rx_ces,rx_lcids,rx_lengths,msg3_len); + +// if (UE_id < 0) { +// memcpy(&eNB->common_channels[CC_idP].RA_template[ii].cont_res_id[0],payload_ptr,6); +// LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3: length %d, offset %ld\n", +// enb_mod_idP,CC_idP,frameP,rx_lengths[i],payload_ptr-sduP); + +// if ((UE_id=add_new_ue(enb_mod_idP,CC_idP,eNB->common_channels[CC_idP].RA_template[ii].rnti,harq_pidP)) == -1 ) { +// mac_xface->macphy_exit("[MAC][eNB] Max user count reached\n"); +// // kill RA procedure +// } else +// LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d Added user with rnti %x => UE %d\n", +// enb_mod_idP,CC_idP,frameP,eNB->common_channels[CC_idP].RA_template[ii].rnti,UE_id); +// } else { +// LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3 from already registered UE %d: length %d, offset %ld\n", +// enb_mod_idP,CC_idP,frameP,UE_id,rx_lengths[i],payload_ptr-sduP); +// // kill RA procedure +// } + +// if (Is_rrc_registered == 1) +// mac_rrc_data_ind( +// enb_mod_idP, +// CC_idP, +// frameP,subframeP, +// rntiP, +// CCCH, +// (uint8_t*)payload_ptr, +// rx_lengths[i], +// ENB_FLAG_YES, +// enb_mod_idP, +// 0); + + +// if (num_ce >0) { // handle msg3 which is not RRCConnectionRequest +// // process_ra_message(msg3,num_ce,rx_lcids,rx_ces); +// } + +// eNB->common_channels[CC_idP].RA_template[ii].generate_Msg4 = 1; +// eNB->common_channels[CC_idP].RA_template[ii].wait_ack_Msg4 = 0; + +// } // if process is active +// } // loop on RA processes + +// break ; + +// case DCCH : +// case DCCH1 : +// // if(eNB_mac_inst[module_idP][CC_idP].Dcch_lchan[UE_id].Active==1){ + + +// #if defined(ENABLE_MAC_PAYLOAD_DEBUG) +// LOG_T(MAC,"offset: %d\n",(unsigned char)((unsigned char*)payload_ptr-sduP)); +// for (j=0; j<32; j++) { +// LOG_T(MAC,"%x ",payload_ptr[j]); +// } +// LOG_T(MAC,"\n"); +// #endif + +// if (UE_id != -1) { +// // adjust buffer occupancy of the correponding logical channel group +// if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] >= rx_lengths[i]) +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] -= rx_lengths[i]; +// else +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] = 0; + +// LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DCCH, received %d bytes form UE %d on LCID %d \n", +// enb_mod_idP,CC_idP,frameP, rx_lengths[i], UE_id, rx_lcids[i]); + +// mac_rlc_data_ind( +// enb_mod_idP, +// rntiP, +// enb_mod_idP, +// frameP, +// ENB_FLAG_YES, +// MBMS_FLAG_NO, +// rx_lcids[i], +// (char *)payload_ptr, +// rx_lengths[i], +// 1, +// NULL);//(unsigned int*)crc_status); +// UE_list->eNB_UE_stats[CC_idP][UE_id].num_pdu_rx[rx_lcids[i]]+=1; +// UE_list->eNB_UE_stats[CC_idP][UE_id].num_bytes_rx[rx_lcids[i]]+=rx_lengths[i]; +// } /* UE_id != -1 */ + +// // } +// break; + +// // all the DRBS +// case DTCH: +// default : + +// #if defined(ENABLE_MAC_PAYLOAD_DEBUG) +// LOG_T(MAC,"offset: %d\n",(unsigned char)((unsigned char*)payload_ptr-sduP)); +// for (j=0; j<32; j++) { +// LOG_T(MAC,"%x ",payload_ptr[j]); +// } +// LOG_T(MAC,"\n"); +// #endif +// if (rx_lcids[i] < NB_RB_MAX ) { +// LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d\n", +// enb_mod_idP,CC_idP,frameP, rx_lengths[i], UE_id, rx_lcids[i]); + +// if (UE_id != -1) { +// // adjust buffer occupancy of the correponding logical channel group +// LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d, removing from LCGID %ld, %d\n", +// enb_mod_idP,CC_idP,frameP, rx_lengths[i], UE_id,rx_lcids[i], +// UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]], +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]]); + +// if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] >= rx_lengths[i]) +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] -= rx_lengths[i]; +// else +// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] = 0; +// if ((rx_lengths[i] 0) ) { // MAX SIZE OF transport block +// mac_rlc_data_ind( +// enb_mod_idP, +// rntiP, +// enb_mod_idP, +// frameP, +// ENB_FLAG_YES, +// MBMS_FLAG_NO, +// rx_lcids[i], +// (char *)payload_ptr, +// rx_lengths[i], +// 1, +// NULL);//(unsigned int*)crc_status); + +// UE_list->eNB_UE_stats[CC_idP][UE_id].num_pdu_rx[rx_lcids[i]]+=1; +// UE_list->eNB_UE_stats[CC_idP][UE_id].num_bytes_rx[rx_lcids[i]]+=rx_lengths[i]; +// } +// else { /* rx_length[i] */ +// UE_list->eNB_UE_stats[CC_idP][UE_id].num_errors_rx+=1; +// LOG_E(MAC,"[eNB %d] CC_id %d Frame %d : Max size of transport block reached LCID %d from UE %d ", +// enb_mod_idP, CC_idP, frameP, rx_lcids[i], UE_id); +// } +// } +// else {/*(UE_id != -1*/ +// LOG_E(MAC,"[eNB %d] CC_id %d Frame %d : received unsupported or unknown LCID %d from UE %d ", +// enb_mod_idP, CC_idP, frameP, rx_lcids[i], UE_id); +// } +// } + +// break; +// } + +// payload_ptr+=rx_lengths[i]; +// } + +// /* NN--> FK: we could either check the payload, or use a phy helper to detect a false msg3 */ +// if ((num_sdu == 0) && (num_ce==0)) { +// if (UE_id != -1) +// UE_list->eNB_UE_stats[CC_idP][UE_id].total_num_errors_rx+=1; + +// if (msg3_flagP != NULL) { +// if( *msg3_flagP == 1 ) { +// LOG_N(MAC,"[eNB %d] CC_id %d frame %d : false msg3 detection: signal phy to canceling RA and remove the UE\n", enb_mod_idP, CC_idP, frameP); +// *msg3_flagP=0; +// } +// } +// } else { +// if (UE_id != -1) { +// UE_list->eNB_UE_stats[CC_idP][UE_id].pdu_bytes_rx=sdu_lenP; +// UE_list->eNB_UE_stats[CC_idP][UE_id].total_pdu_bytes_rx+=sdu_lenP; +// UE_list->eNB_UE_stats[CC_idP][UE_id].total_num_pdus_rx+=1; +// } +// } + +// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_SDU,0); +// stop_meas(&eNB->rx_ulsch_sdu); +// } + +void _ulsch_scheduler_pre_processor(module_id_t module_idP, + int frameP, + sub_frame_t subframeP, + uint16_t *first_rb) +{ + + int16_t i; + uint16_t UE_id,n,r; + uint8_t CC_id, round, harq_pid; + uint16_t nb_allocated_rbs[MAX_NUM_CCs][NUMBER_OF_UE_MAX],total_allocated_rbs[MAX_NUM_CCs],average_rbs_per_user[MAX_NUM_CCs]; + int16_t total_remaining_rbs[MAX_NUM_CCs]; + uint16_t max_num_ue_to_be_scheduled=0,total_ue_count=0; + rnti_t rnti= -1; + UE_list_t *UE_list = &eNB_mac_inst[module_idP].UE_list; + UE_TEMPLATE *UE_template = 0; + LTE_DL_FRAME_PARMS *frame_parms = 0; + + + //LOG_I(MAC,"assign max mcs min rb\n"); + // maximize MCS and then allocate required RB according to the buffer occupancy with the limit of max available UL RB + assign_max_mcs_min_rb(module_idP,frameP, subframeP, first_rb); + + //LOG_I(MAC,"sort ue \n"); + // sort ues + sort_ue_ul (module_idP,frameP, subframeP); + + + // we need to distribute RBs among UEs + // step1: reset the vars + for (CC_id=0; CC_idhead_ul; i>=0; i=UE_list->next_ul[i]) { + nb_allocated_rbs[CC_id][i]=0; + } + } + + //LOG_I(MAC,"step2 \n"); + // step 2: calculate the average rb per UE + total_ue_count =0; + max_num_ue_to_be_scheduled=0; + + for (i=UE_list->head_ul; i>=0; i=UE_list->next_ul[i]) { + + rnti = UE_RNTI(module_idP,i); + + if (rnti==NOT_A_RNTI) + continue; + + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + + if (!phy_stats_exist(module_idP, rnti)) + continue; + + UE_id = i; + + for (n=0; nnumactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; + UE_template = &UE_list->UE_template[CC_id][UE_id]; + average_rbs_per_user[CC_id]=0; + frame_parms = mac_xface->get_lte_frame_parms(module_idP,CC_id); + + if (UE_template->pre_allocated_nb_rb_ul > 0) { + total_ue_count+=1; + } + /* + if((mac_xface->get_nCCE_max(module_idP,CC_id,3,subframeP) - nCCE_to_be_used[CC_id]) > (1<N_RB_UL-first_rb[CC_id]+1; + } else if( (total_ue_count <= (frame_parms->N_RB_DL-first_rb[CC_id])) && + (total_ue_count <= max_num_ue_to_be_scheduled)) { + average_rbs_per_user[CC_id] = (uint16_t) floor((frame_parms->N_RB_UL-first_rb[CC_id])/total_ue_count); + } else if (max_num_ue_to_be_scheduled > 0 ) { + average_rbs_per_user[CC_id] = (uint16_t) floor((frame_parms->N_RB_UL-first_rb[CC_id])/max_num_ue_to_be_scheduled); + } else { + average_rbs_per_user[CC_id]=1; + LOG_W(MAC,"[eNB %d] frame %d subframe %d: UE %d CC %d: can't get average rb per user (should not be here)\n", + module_idP,frameP,subframeP,UE_id,CC_id); + } + } + } + if (total_ue_count > 0) + LOG_D(MAC,"[eNB %d] Frame %d subframe %d: total ue to be scheduled %d/%d\n", + module_idP, frameP, subframeP,total_ue_count, max_num_ue_to_be_scheduled); + + //LOG_D(MAC,"step3\n"); + + // step 3: assigne RBS + for (i=UE_list->head_ul; i>=0; i=UE_list->next_ul[i]) { + rnti = UE_RNTI(module_idP,i); + + if (rnti==NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + if (!phy_stats_exist(module_idP, rnti)) + continue; + + UE_id = i; + + for (n=0; nnumactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; + + mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL); + + if(round>0) { + nb_allocated_rbs[CC_id][UE_id] = UE_list->UE_template[CC_id][UE_id].nb_rb_ul[harq_pid]; + } else { + nb_allocated_rbs[CC_id][UE_id] = cmin(UE_list->UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul, average_rbs_per_user[CC_id]); + } + + total_allocated_rbs[CC_id]+= nb_allocated_rbs[CC_id][UE_id]; + + } + } + + // step 4: assigne the remaining RBs and set the pre_allocated rbs accordingly + for(r=0; r<2; r++) { + + for (i=UE_list->head_ul; i>=0; i=UE_list->next_ul[i]) { + rnti = UE_RNTI(module_idP,i); + + if (rnti==NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + if (!phy_stats_exist(module_idP, rnti)) + continue; + + UE_id = i; + + for (n=0; nnumactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; + UE_template = &UE_list->UE_template[CC_id][UE_id]; + frame_parms = mac_xface->get_lte_frame_parms(module_idP,CC_id); + total_remaining_rbs[CC_id]=frame_parms->N_RB_UL - first_rb[CC_id] - total_allocated_rbs[CC_id]; + + if (total_ue_count == 1 ) { + total_remaining_rbs[CC_id]+=1; + } + + if ( r == 0 ) { + while ( (UE_template->pre_allocated_nb_rb_ul > 0 ) && + (nb_allocated_rbs[CC_id][UE_id] < UE_template->pre_allocated_nb_rb_ul) && + (total_remaining_rbs[CC_id] > 0)) { + nb_allocated_rbs[CC_id][UE_id] = cmin(nb_allocated_rbs[CC_id][UE_id]+1,UE_template->pre_allocated_nb_rb_ul); + total_remaining_rbs[CC_id]--; + total_allocated_rbs[CC_id]++; + } + } else { + UE_template->pre_allocated_nb_rb_ul= nb_allocated_rbs[CC_id][UE_id]; + LOG_D(MAC,"******************UL Scheduling Information for UE%d CC_id %d ************************\n",UE_id, CC_id); + LOG_D(MAC,"[eNB %d] total RB allocated for UE%d CC_id %d = %d\n", module_idP, UE_id, CC_id, UE_template->pre_allocated_nb_rb_ul); + } + } + } + } + + for (CC_id=0; CC_idget_lte_frame_parms(module_idP,CC_id); + + if (total_allocated_rbs[CC_id]>0) { + LOG_D(MAC,"[eNB %d] total RB allocated for all UEs = %d/%d\n", module_idP, total_allocated_rbs[CC_id], frame_parms->N_RB_UL - first_rb[CC_id]); + } + } +} + + + +// uint32_t bytes_to_bsr_index(int32_t nbytes) +// { + +// uint32_t i=0; + +// if (nbytes<0) { +// return(0); +// } + +// while ((iE == 0) { +// not_done = 0; +// } + +// lcid = ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID; + +// if (lcid < EXTENDED_POWER_HEADROOM) { +// if (not_done==0) { // last MAC SDU, length is implicit +// mac_header_ptr++; +// length = tb_length-(mac_header_ptr-mac_header)-ce_len; + +// for (num_sdu_cnt=0; num_sdu_cnt < num_sdus ; num_sdu_cnt++) { +// length -= rx_lengths[num_sdu_cnt]; +// } +// } else { +// if (((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F == 0) { +// length = ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L; +// mac_header_ptr += 2;//sizeof(SCH_SUBHEADER_SHORT); +// } else { // F = 1 +// length = ((((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_MSB & 0x7f ) << 8 ) | (((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB & 0xff); +// mac_header_ptr += 3;//sizeof(SCH_SUBHEADER_LONG); +// } +// } + +// LOG_D(MAC,"[eNB] sdu %d lcid %d tb_length %d length %d (offset now %ld)\n", +// num_sdus,lcid,tb_length, length,mac_header_ptr-mac_header); +// rx_lcids[num_sdus] = lcid; +// rx_lengths[num_sdus] = length; +// num_sdus++; +// } else { // This is a control element subheader POWER_HEADROOM, BSR and CRNTI +// if (lcid == SHORT_PADDING) { +// mac_header_ptr++; +// } else { +// rx_ces[num_ces] = lcid; +// num_ces++; +// mac_header_ptr++; + +// if (lcid==LONG_BSR) { +// ce_len+=3; +// } else if (lcid==CRNTI) { +// ce_len+=2; +// } else if ((lcid==POWER_HEADROOM) || (lcid==TRUNCATED_BSR)|| (lcid== SHORT_BSR)) { +// ce_len++; +// } else { +// LOG_E(MAC,"unknown CE %d \n", lcid); +// mac_xface->macphy_exit("unknown CE"); +// } +// } +// } +// } + +// *num_ce = num_ces; +// *num_sdu = num_sdus; + +// return(mac_header_ptr); +// } + + +void flexran_agent_schedule_ulsch_ue_spec(module_id_t module_idP, + frame_t frameP, + unsigned char cooperation_flag, + sub_frame_t subframeP, + unsigned char sched_subframe) { + + + + uint16_t first_rb[MAX_NUM_CCs],i; + int CC_id; + eNB_MAC_INST *eNB=&eNB_mac_inst[module_idP]; + + start_meas(&eNB->schedule_ulsch); + + + for (CC_id=0; CC_idcommon_channels[CC_id].RA_template[i].RA_active == TRUE) && + (eNB->common_channels[CC_id].RA_template[i].generate_rar == 0) && + (eNB->common_channels[CC_id].RA_template[i].generate_Msg4 == 0) && + (eNB->common_channels[CC_id].RA_template[i].wait_ack_Msg4 == 0) && + (eNB->common_channels[CC_id].RA_template[i].Msg3_subframe == sched_subframe)) { + first_rb[CC_id]++; + eNB->common_channels[CC_id].RA_template[i].Msg3_subframe = -1; + break; + } + } + + /* + if (mac_xface->is_prach_subframe(&(mac_xface->lte_frame_parms),frameP,subframeP)) { + first_rb[CC_id] = (mac_xface->get_prach_prb_offset(&(mac_xface->lte_frame_parms), + */ + + } + + flexran_agent_schedule_ulsch_rnti(module_idP, cooperation_flag, frameP, subframeP, sched_subframe,first_rb); + +// #ifdef CBA + // schedule_ulsch_cba_rnti(module_idP, cooperation_flag, frameP, subframeP, sched_subframe, first_rb); +// #endif + + + stop_meas(&eNB->schedule_ulsch); + +} + + + +void flexran_agent_schedule_ulsch_rnti(module_id_t module_idP, + unsigned char cooperation_flag, + frame_t frameP, + sub_frame_t subframeP, + unsigned char sched_subframe, + uint16_t *first_rb) +{ + + int UE_id; + uint8_t aggregation = 2; + rnti_t rnti = -1; + uint8_t round = 0; + uint8_t harq_pid = 0; + void *ULSCH_dci = NULL; + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + DCI_PDU *DCI_pdu; + uint8_t status = 0; + uint8_t rb_table_index = -1; + uint16_t TBS = 0; + // int32_t buffer_occupancy=0; + uint32_t cqi_req,cshift,ndi,mcs=0,rballoc,tpc; + int32_t normalized_rx_power, target_rx_power=-90; + static int32_t tpc_accumulated=0; + + int n,CC_id = 0; + eNB_MAC_INST *eNB=&eNB_mac_inst[module_idP]; + UE_list_t *UE_list=&eNB->UE_list; + UE_TEMPLATE *UE_template; + UE_sched_ctrl *UE_sched_ctrl; + + // int rvidx_tab[4] = {0,2,3,1}; + LTE_DL_FRAME_PARMS *frame_parms; + int drop_ue=0; + + // LOG_I(MAC,"entering ulsch preprocesor\n"); + + _ulsch_scheduler_pre_processor(module_idP, + frameP, + subframeP, + first_rb); + + // LOG_I(MAC,"exiting ulsch preprocesor\n"); + + // loop over all active UEs + for (UE_id=UE_list->head_ul; UE_id>=0; UE_id=UE_list->next_ul[UE_id]) { + + // don't schedule if Msg4 is not received yet + if (UE_list->UE_template[UE_PCCID(module_idP,UE_id)][UE_id].configured==FALSE) { + LOG_I(MAC,"[eNB %d] frame %d subfarme %d, UE %d: not configured, skipping UE scheduling \n", + module_idP,frameP,subframeP,UE_id); + continue; + } + + rnti = UE_RNTI(module_idP,UE_id); + + if (rnti==NOT_A_RNTI) { + LOG_W(MAC,"[eNB %d] frame %d subfarme %d, UE %d: no RNTI \n", module_idP,frameP,subframeP,UE_id); + continue; + } + + /* let's drop the UE if get_eNB_UE_stats returns NULL when calling it with any of the UE's active UL CCs */ + /* TODO: refine? */ + drop_ue = 0; + for (n=0; nnumactiveULCCs[UE_id]; n++) { + CC_id = UE_list->ordered_ULCCids[n][UE_id]; + if (mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti) == NULL) { + LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: no PHY context\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id); + drop_ue = 1; + break; + } + } + if (drop_ue == 1) { +/* we can't come here, ulsch_scheduler_pre_processor won't put in the list a UE with no PHY context */ +abort(); + /* TODO: this is a hack. Sometimes the UE has no PHY context but + * is still present in the MAC with 'ul_failure_timer' = 0 and + * 'ul_out_of_sync' = 0. It seems wrong and the UE stays there forever. Let's + * start an UL out of sync procedure in this case. + * The root cause of this problem has to be found and corrected. + * In the meantime, this hack... + */ + if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 0 && + UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 0) { + LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: UE in weird state, let's put it 'out of sync'\n", + module_idP,frameP,subframeP,UE_id,rnti,CC_id); + // inform RRC of failure and clear timer + mac_eNB_rrc_ul_failure(module_idP,CC_id,frameP,subframeP,rnti); + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer=0; + UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync=1; + } + continue; + } + + // loop over all active UL CC_ids for this UE + for (n=0; nnumactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; + frame_parms = mac_xface->get_lte_frame_parms(module_idP,CC_id); + eNB_UE_stats = mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti); + + aggregation=get_aggregation(get_bw_index(module_idP,CC_id), + eNB_UE_stats->DL_cqi[0], + format0); + + if (CCE_allocation_infeasible(module_idP,CC_id,0,subframeP,aggregation,rnti)) { + LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: not enough nCCE\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id); + continue; // break; + } else{ + LOG_D(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d mode %s: aggregation level %d\n", + module_idP,frameP,subframeP,UE_id,rnti,CC_id, mode_string[eNB_UE_stats->mode], 1<mode == PUSCH) { // ue has a ulsch channel + + DCI_pdu = &eNB->common_channels[CC_id].DCI_pdu; + UE_template = &UE_list->UE_template[CC_id][UE_id]; + UE_sched_ctrl = &UE_list->UE_sched_ctrl[UE_id]; + + if (mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL) == -1 ) { + LOG_W(MAC,"[eNB %d] Scheduler Frame %d, subframeP %d: candidate harq_pid from PHY for UE %d CC %d RNTI %x\n", + module_idP,frameP,subframeP, UE_id, CC_id, rnti); + continue; + } else + LOG_T(MAC,"[eNB %d] Frame %d, subframeP %d, UE %d CC %d : got harq pid %d round %d (rnti %x,mode %s)\n", + module_idP,frameP,subframeP,UE_id,CC_id, harq_pid, round,rnti,mode_string[eNB_UE_stats->mode]); + + PHY_vars_eNB_g[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP*10)+subframeP] = UE_template->ul_total_buffer; + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BO,PHY_vars_eNB_g[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP*10)+subframeP]); + if (((UE_is_to_be_scheduled(module_idP,CC_id,UE_id)>0)) || (round>0))// || ((frameP%10)==0)) + // if there is information on bsr of DCCH, DTCH or if there is UL_SR, or if there is a packet to retransmit, or we want to schedule a periodic feedback every 10 frames + { + LOG_D(MAC,"[eNB %d][PUSCH] Frame %d subframe %d Scheduling UE %d/%x in round %d(SR %d,UL_inactivity timer %d,UL_failure timer %d)\n", + module_idP,frameP,subframeP,UE_id,rnti,round,UE_template->ul_SR, + UE_sched_ctrl->ul_inactivity_timer, + UE_sched_ctrl->ul_failure_timer); + // reset the scheduling request + UE_template->ul_SR = 0; + status = mac_eNB_get_rrc_status(module_idP,rnti); + if (status < RRC_CONNECTED) + cqi_req = 0; + else if (UE_sched_ctrl->cqi_req_timer>30) { + cqi_req = 1; + UE_sched_ctrl->cqi_req_timer=0; + } + else + cqi_req = 0; + + //power control + //compute the expected ULSCH RX power (for the stats) + + // this is the normalized RX power and this should be constant (regardless of mcs + normalized_rx_power = eNB_UE_stats->UL_rssi[0]; + target_rx_power = mac_xface->get_target_pusch_rx_power(module_idP,CC_id); + + // this assumes accumulated tpc + // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out + int32_t framex10psubframe = UE_template->pusch_tpc_tx_frame*10+UE_template->pusch_tpc_tx_subframe; + if (((framex10psubframe+10)<=(frameP*10+subframeP)) || //normal case + ((framex10psubframe>(frameP*10+subframeP)) && (((10240-framex10psubframe+frameP*10+subframeP)>=10)))) //frame wrap-around + { + UE_template->pusch_tpc_tx_frame=frameP; + UE_template->pusch_tpc_tx_subframe=subframeP; + if (normalized_rx_power>(target_rx_power+1)) { + tpc = 0; //-1 + tpc_accumulated--; + } else if (normalized_rx_power<(target_rx_power-1)) { + tpc = 2; //+1 + tpc_accumulated++; + } else { + tpc = 1; //0 + } + } else { + tpc = 1; //0 + } + + if (tpc!=1) { + LOG_D(MAC,"[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", + module_idP,frameP,subframeP,harq_pid,tpc, + tpc_accumulated,normalized_rx_power,target_rx_power); + } + + // new transmission + if (round==0) { + + ndi = 1-UE_template->oldNDI_UL[harq_pid]; + UE_template->oldNDI_UL[harq_pid]=ndi; + UE_list->eNB_UE_stats[CC_id][UE_id].normalized_rx_power=normalized_rx_power; + UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power=target_rx_power; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=UE_template->pre_assigned_mcs_ul; + mcs = UE_template->pre_assigned_mcs_ul;//cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS + if (UE_template->pre_allocated_rb_table_index_ul >=0) { + rb_table_index=UE_template->pre_allocated_rb_table_index_ul; + } else { + mcs=10;//cmin (10, openair_daq_vars.target_ue_ul_mcs); + rb_table_index=5; // for PHR + } + + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; + // buffer_occupancy = UE_template->ul_total_buffer; + + while (((rb_table[rb_table_index]>(frame_parms->N_RB_UL-1-first_rb[CC_id])) || + (rb_table[rb_table_index]>45)) && + (rb_table_index>0)) { + rb_table_index--; + } + + TBS = mac_xface->get_TBS_UL(mcs,rb_table[rb_table_index]); + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=rb_table[rb_table_index]; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_TBS=TBS; + // buffer_occupancy -= TBS; + rballoc = mac_xface->computeRIV(frame_parms->N_RB_UL, + first_rb[CC_id], + rb_table[rb_table_index]); + + T(T_ENB_MAC_UE_UL_SCHEDULE, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), + T_INT(subframeP), T_INT(harq_pid), T_INT(mcs), T_INT(first_rb[CC_id]), T_INT(rb_table[rb_table_index]), + T_INT(TBS), T_INT(ndi)); + + if (mac_eNB_get_rrc_status(module_idP,rnti) < RRC_CONNECTED) + LOG_I(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE %d (mcs %d, first rb %d, nb_rb %d, rb_table_index %d, TBS %d, harq_pid %d)\n", + module_idP,harq_pid,rnti,CC_id,frameP,subframeP,UE_id,mcs, + first_rb[CC_id],rb_table[rb_table_index], + rb_table_index,TBS,harq_pid); + + // bad indices : 20 (40 PRB), 21 (45 PRB), 22 (48 PRB) + // increment for next UE allocation + first_rb[CC_id]+=rb_table[rb_table_index]; + //store for possible retransmission + UE_template->nb_rb_ul[harq_pid] = rb_table[rb_table_index]; + UE_sched_ctrl->ul_scheduled |= (1<head) + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_SCHEDULED,UE_sched_ctrl->ul_scheduled); + + // adjust total UL buffer status by TBS, wait for UL sdus to do final update + LOG_D(MAC,"[eNB %d] CC_id %d UE %d/%x : adjusting ul_total_buffer, old %d, TBS %d\n", module_idP,CC_id,UE_id,rnti,UE_template->ul_total_buffer,TBS); + if (UE_template->ul_total_buffer > TBS) + UE_template->ul_total_buffer -= TBS; + else + UE_template->ul_total_buffer = 0; + LOG_D(MAC,"ul_total_buffer, new %d\n", UE_template->ul_total_buffer); + // Cyclic shift for DM RS + cshift = 0;// values from 0 to 7 can be used for mapping the cyclic shift (36.211 , Table 5.5.2.1.1-1) + + if (frame_parms->frame_type == TDD) { + switch (frame_parms->N_RB_UL) { + case 6: + ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; + + ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->type = 0; + ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->hopping = 0; + ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->rballoc = rballoc; + ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->mcs = mcs; + ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->ndi = ndi; + ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->TPC = tpc; + ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->cshift = cshift; + ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->padding = 0; + ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->dai = UE_template->DAI_ul[sched_subframe]; + ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->cqi_req = cqi_req; + + add_ue_spec_dci(DCI_pdu, + ULSCH_dci, + rnti, + sizeof(DCI0_1_5MHz_TDD_1_6_t), + aggregation, + sizeof_DCI0_1_5MHz_TDD_1_6_t, + format0, + 0); + break; + + default: + case 25: + ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; + + ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->type = 0; + ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->hopping = 0; + ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->rballoc = rballoc; + ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->mcs = mcs; + ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->ndi = ndi; + ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->TPC = tpc; + ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->cshift = cshift; + ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->padding = 0; + ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->dai = UE_template->DAI_ul[sched_subframe]; + ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->cqi_req = cqi_req; + + add_ue_spec_dci(DCI_pdu, + ULSCH_dci, + rnti, + sizeof(DCI0_5MHz_TDD_1_6_t), + aggregation, + sizeof_DCI0_5MHz_TDD_1_6_t, + format0, + 0); + break; + + case 50: + ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; + + ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->type = 0; + ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->hopping = 0; + ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->rballoc = rballoc; + ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->mcs = mcs; + ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->ndi = ndi; + ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->TPC = tpc; + ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->cshift = cshift; + ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->padding = 0; + ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->dai = UE_template->DAI_ul[sched_subframe]; + ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->cqi_req = cqi_req; + + add_ue_spec_dci(DCI_pdu, + ULSCH_dci, + rnti, + sizeof(DCI0_10MHz_TDD_1_6_t), + aggregation, + sizeof_DCI0_10MHz_TDD_1_6_t, + format0, + 0); + break; + + case 100: + ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; + + ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->type = 0; + ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->hopping = 0; + ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->rballoc = rballoc; + ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->mcs = mcs; + ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->ndi = ndi; + ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->TPC = tpc; + ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->cshift = cshift; + ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->padding = 0; + ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->dai = UE_template->DAI_ul[sched_subframe]; + ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->cqi_req = cqi_req; + + add_ue_spec_dci(DCI_pdu, + ULSCH_dci, + rnti, + sizeof(DCI0_20MHz_TDD_1_6_t), + aggregation, + sizeof_DCI0_20MHz_TDD_1_6_t, + format0, + 0); + break; + } + } // TDD + else { //FDD + switch (frame_parms->N_RB_UL) { + case 25: + default: + + ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; + + ((DCI0_5MHz_FDD_t *)ULSCH_dci)->type = 0; + ((DCI0_5MHz_FDD_t *)ULSCH_dci)->hopping = 0; + ((DCI0_5MHz_FDD_t *)ULSCH_dci)->rballoc = rballoc; + ((DCI0_5MHz_FDD_t *)ULSCH_dci)->mcs = mcs; + ((DCI0_5MHz_FDD_t *)ULSCH_dci)->ndi = ndi; + ((DCI0_5MHz_FDD_t *)ULSCH_dci)->TPC = tpc; + ((DCI0_5MHz_FDD_t *)ULSCH_dci)->cshift = cshift; + ((DCI0_5MHz_FDD_t *)ULSCH_dci)->padding = 0; + ((DCI0_5MHz_FDD_t *)ULSCH_dci)->cqi_req = cqi_req; + + add_ue_spec_dci(DCI_pdu, + ULSCH_dci, + rnti, + sizeof(DCI0_5MHz_FDD_t), + aggregation, + sizeof_DCI0_5MHz_FDD_t, + format0, + 0); + break; + + case 6: + ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; + + ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->type = 0; + ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->hopping = 0; + ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->rballoc = rballoc; + ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->mcs = mcs; + ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->ndi = ndi; + ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->TPC = tpc; + ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->cshift = cshift; + ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->padding = 0; + ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->cqi_req = cqi_req; + + add_ue_spec_dci(DCI_pdu, + ULSCH_dci, + rnti, + sizeof(DCI0_1_5MHz_FDD_t), + aggregation, + sizeof_DCI0_1_5MHz_FDD_t, + format0, + 0); + break; + + case 50: + ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; + + ((DCI0_10MHz_FDD_t *)ULSCH_dci)->type = 0; + ((DCI0_10MHz_FDD_t *)ULSCH_dci)->hopping = 0; + ((DCI0_10MHz_FDD_t *)ULSCH_dci)->rballoc = rballoc; + ((DCI0_10MHz_FDD_t *)ULSCH_dci)->mcs = mcs; + ((DCI0_10MHz_FDD_t *)ULSCH_dci)->ndi = ndi; + ((DCI0_10MHz_FDD_t *)ULSCH_dci)->TPC = tpc; + ((DCI0_10MHz_FDD_t *)ULSCH_dci)->padding = 0; + ((DCI0_10MHz_FDD_t *)ULSCH_dci)->cshift = cshift; + ((DCI0_10MHz_FDD_t *)ULSCH_dci)->cqi_req = cqi_req; + + add_ue_spec_dci(DCI_pdu, + ULSCH_dci, + rnti, + sizeof(DCI0_10MHz_FDD_t), + aggregation, + sizeof_DCI0_10MHz_FDD_t, + format0, + 0); + break; + + case 100: + ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; + + ((DCI0_20MHz_FDD_t *)ULSCH_dci)->type = 0; + ((DCI0_20MHz_FDD_t *)ULSCH_dci)->hopping = 0; + ((DCI0_20MHz_FDD_t *)ULSCH_dci)->rballoc = rballoc; + ((DCI0_20MHz_FDD_t *)ULSCH_dci)->mcs = mcs; + ((DCI0_20MHz_FDD_t *)ULSCH_dci)->ndi = ndi; + ((DCI0_20MHz_FDD_t *)ULSCH_dci)->TPC = tpc; + ((DCI0_20MHz_FDD_t *)ULSCH_dci)->padding = 0; + ((DCI0_20MHz_FDD_t *)ULSCH_dci)->cshift = cshift; + ((DCI0_20MHz_FDD_t *)ULSCH_dci)->cqi_req = cqi_req; + + add_ue_spec_dci(DCI_pdu, + ULSCH_dci, + rnti, + sizeof(DCI0_20MHz_FDD_t), + aggregation, + sizeof_DCI0_20MHz_FDD_t, + format0, + 0); + break; + + } + } + + + add_ue_ulsch_info(module_idP, + CC_id, + UE_id, + subframeP, + S_UL_SCHEDULED); + + LOG_D(MAC,"[eNB %d] CC_id %d Frame %d, subframeP %d: Generated ULSCH DCI for next UE_id %d, format 0\n", module_idP,CC_id,frameP,subframeP,UE_id); +#ifdef DEBUG + dump_dci(frame_parms, &DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci-1]); +#endif + + } + else { + T(T_ENB_MAC_UE_UL_SCHEDULE_RETRANSMISSION, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), + T_INT(subframeP), T_INT(harq_pid), T_INT(mcs), T_INT(first_rb[CC_id]), T_INT(rb_table[rb_table_index]), + T_INT(round)); + + LOG_D(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled (PHICH) UE %d (mcs %d, first rb %d, nb_rb %d, rb_table_index %d, TBS %d, harq_pid %d,round %d)\n", + module_idP,harq_pid,rnti,CC_id,frameP,subframeP,UE_id,mcs, + first_rb[CC_id],rb_table[rb_table_index], + rb_table_index,TBS,harq_pid,round); + }/* + else if (round > 0) { //we schedule a retransmission + + ndi = UE_template->oldNDI_UL[harq_pid]; + + if ((round&3)==0) { + mcs = openair_daq_vars.target_ue_ul_mcs; + } else { + mcs = rvidx_tab[round&3] + 28; //not correct for round==4! + + } + + LOG_I(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE retransmission (mcs %d, first rb %d, nb_rb %d, harq_pid %d, round %d)\n", + module_idP,UE_id,rnti,CC_id,frameP,subframeP,mcs, + first_rb[CC_id],UE_template->nb_rb_ul[harq_pid], + harq_pid, round); + + rballoc = mac_xface->computeRIV(frame_parms->N_RB_UL, + first_rb[CC_id], + UE_template->nb_rb_ul[harq_pid]); + first_rb[CC_id]+=UE_template->nb_rb_ul[harq_pid]; // increment for next UE allocation + + UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission_rx+=1; + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx_rx=UE_template->nb_rb_ul[harq_pid]; + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=UE_template->nb_rb_ul[harq_pid]; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=mcs; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; + } + */ + + } // UE_is_to_be_scheduled + } // UE is in PUSCH + } // loop over UE_id + } // loop of CC_id +} + +// #ifdef CBA +// void schedule_ulsch_cba_rnti(module_id_t module_idP, unsigned char cooperation_flag, frame_t frameP, sub_frame_t subframeP, unsigned char sched_subframe, uint16_t *first_rb) +// { + +// eNB_MAC_INST *eNB = &eNB_mac_inst[module_idP]; +// UE_list_t *UE_list=&eNB->UE_list; +// //UE_TEMPLATE *UE_template; +// void *ULSCH_dci = NULL; +// DCI_PDU *DCI_pdu; +// uint8_t CC_id=0; +// uint8_t rb_table_index=0, aggregation=2; +// uint32_t rballoc; +// uint8_t cba_group, cba_resources; +// uint8_t required_rbs[NUM_MAX_CBA_GROUP]; +// int8_t num_cba_resources[NUM_MAX_CBA_GROUP];// , weight[NUM_MAX_CBA_GROUP] +// // the following vars should become a vector [MAX_NUM_CCs] +// LTE_DL_FRAME_PARMS *frame_parms; +// int8_t available_rbs=0; +// uint8_t remaining_rbs=0; +// uint8_t allocated_rbs=0; +// uint8_t total_UEs=UE_list->num_UEs; +// uint8_t active_UEs[NUM_MAX_CBA_GROUP]; +// uint8_t total_groups=eNB_mac_inst[module_idP].common_channels[CC_id].num_active_cba_groups; +// int min_rb_unit=2; +// uint8_t cba_policy=CBA_ES; +// int UE_id; +// uint8_t mcs[NUM_MAX_CBA_GROUP]; +// uint32_t total_cba_resources=0; +// uint32_t total_rbs=0; +// // We compute the weight of each group and initialize some variables + +// // loop over all active UEs +// // for (UE_id=UE_list->head_ul;UE_id>=0;UE_id=UE_list->next_ul[UE_id]) { + +// for (cba_group=0; cba_groupget_lte_frame_parms(module_idP,CC_id); +// available_rbs=frame_parms->N_RB_DL-1-first_rb[CC_id]; +// remaining_rbs=available_rbs; +// total_groups=eNB_mac_inst[module_idP].common_channels[CC_id].num_active_cba_groups; +// min_rb_unit=get_min_rb_unit(module_idP,CC_id); + +// if (available_rbs < min_rb_unit ) +// continue; + +// // remove this condition later +// // cba group template uses the exisitng UE template, and thus if a UE +// // is scheduled, the correspodning group can't be used for CBA +// // this can be fixed later +// if (total_groups > 0) { +// DCI_pdu = &eNB_mac_inst[module_idP].common_channels[CC_id].DCI_pdu; + +// for (cba_group=0; +// (cba_group (1<head_ul; UE_id>=0; UE_id=UE_list->next_ul[UE_id]) { +// if (UE_RNTI(module_idP,UE_id)==NOT_A_RNTI) +// continue; + +// // simple UE identity based grouping +// if ((UE_id % total_groups) == cba_group) { // this could be simplifed to active_UEs[UE_id % total_groups]++; +// if ((mac_eNB_get_rrc_status(module_idP,rnti) > RRC_CONNECTED) && +// (UE_is_to_be_scheduled(module_idP,CC_id,UE_id) == 0)) { +// active_UEs[cba_group]++; +// } +// } + +// if (UE_list->UE_template[CC_id][UE_id].pre_assigned_mcs_ul <= 2) { +// mcs[cba_group]= 8; // apply fixed scheduling +// } else if ((UE_id % total_groups) == cba_group) { +// mcs[cba_group]= cmin(mcs[cba_group],UE_list->UE_template[CC_id][UE_id].pre_assigned_mcs_ul); +// } +// } + +// mcs[cba_group]= mcs[cba_group];//cmin(mcs[cba_group],openair_daq_vars.target_ue_ul_mcs); + +// if (available_rbs < min_rb_unit ) +// break; + +// // If the group needs some resource +// // determine the total number of allocations (one or multiple DCIs): to be refined +// if ((active_UEs[cba_group] > 0) && (eNB_mac_inst[module_idP].common_channels[CC_id].cba_rnti[cba_group] != 0)) { +// // to be refined in case of : total_UEs >> weight[cba_group]*available_rbs + +// switch(cba_policy) { +// case CBA_ES: +// required_rbs[cba_group] = (uint8_t)floor(available_rbs/total_groups); // allocate equally among groups +// num_cba_resources[cba_group]=1; +// break; + +// // can't have more than one allocation for the same group/UE +// /* case CBA_ES_S: +// required_rbs[cba_group] = (uint8_t)floor(available_rbs/total_groups); // allocate equally among groups +// if (required_rbs[cba_group] > min_rb_unit) +// num_cba_resources[cba_group]=(uint8_t)(required_rbs[cba_group]/ min_rb_unit); +// break;*/ +// case CBA_PF: +// required_rbs[cba_group] = (uint8_t)floor((active_UEs[cba_group]*available_rbs)/total_UEs); +// num_cba_resources[cba_group]=1; +// break; +// /* case CBA_PF_S: +// required_rbs[cba_group] = (uint8_t)ceil((active_UEs[cba_group]*available_rbs)/total_UEs); +// if (required_rbs[cba_group] > min_rb_unit) +// num_cba_resources[cba_group]=(uint8_t) floor(required_rbs[cba_group] / min_rb_unit); +// break;*/ + +// default: +// LOG_W(MAC,"unknown CBA policy\n"); +// break; +// } + +// total_cba_resources+=num_cba_resources[cba_group]; +// total_rbs+=required_rbs[cba_group]; + +// /* while ((remaining_rbs < required_rbs[cba_group]) && +// (required_rbs[cba_group] > 0) && +// (required_rbs[cba_group] < min_rb_unit )) +// required_rbs[cba_group]--; +// */ + +// /* +// while (rb_table[rb_table_index] < required_rbs[cba_group]) +// rb_table_index++; + +// while (rb_table[rb_table_index] > remaining_rbs ) +// rb_table_index--; + +// remaining_rbs-=rb_table[rb_table_index]; +// required_rbs[cba_group]=rb_table[rb_table_index]; +// */ +// // num_cba_resources[cba_group]=1; + +// } +// } + +// // phase 2 reduce the number of cba allocations among the groups +// cba_group=0; + +// if (total_cba_resources <= 0) { +// return; +// } + +// // increase rb if any left: to be done +// cba_group=0; + +// while (total_rbs < available_rbs - 1 ) { +// required_rbs[cba_group%total_groups]++; +// total_rbs++; +// cba_group++; +// } + +// // phase 3: +// for (cba_group=0; cba_group remaining_rbs ) { +// rb_table_index--; +// } + +// remaining_rbs-=rb_table[rb_table_index]; +// allocated_rbs=rb_table[rb_table_index]; + +// rballoc = mac_xface->computeRIV(mac_xface->lte_frame_parms->N_RB_UL, +// first_rb[CC_id], +// rb_table[rb_table_index]); + +// first_rb[CC_id]+=rb_table[rb_table_index]; +// LOG_N(MAC, +// "[eNB %d] CC_id %d Frame %d, subframeP %d: schedule CBA access %d rnti %x, total/required/allocated/remaining rbs (%d/%d/%d/%d), mcs %d, rballoc %d\n", +// module_idP, CC_id, frameP, subframeP, cba_group,eNB_mac_inst[module_idP].common_channels[CC_id].cba_rnti[cba_group], +// available_rbs, required_rbs[cba_group], allocated_rbs, remaining_rbs, +// mcs[cba_group],rballoc); + +// switch (frame_parms->N_RB_UL) { +// case 6: +// mac_xface->macphy_exit("[MAC][eNB] CBA RB=6 not supported \n"); +// break; + +// case 25: +// if (frame_parms->frame_type == TDD) { +// ULSCH_dci = UE_list->UE_template[CC_id][cba_group].ULSCH_DCI[0]; + +// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->type = 0; +// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->hopping = 0; +// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->rballoc = rballoc; +// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->mcs = mcs[cba_group]; +// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->ndi = 1; +// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->TPC = 1;//tpc; +// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->cshift = cba_group; +// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->dai = UE_list->UE_template[CC_id][cba_group].DAI_ul[sched_subframe]; +// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->cqi_req = 1; + +// //add_ue_spec_dci +// add_common_dci(DCI_pdu, +// ULSCH_dci, +// eNB_mac_inst[module_idP].common_channels[CC_id].cba_rnti[cba_group], +// sizeof(DCI0_5MHz_TDD_1_6_t), +// aggregation, +// sizeof_DCI0_5MHz_TDD_1_6_t, +// format0, +// 0); +// } else { +// ULSCH_dci = UE_list->UE_template[CC_id][cba_group].ULSCH_DCI[0]; + +// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->type = 0; +// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->hopping = 0; +// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->rballoc = rballoc; +// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->mcs = mcs[cba_group]; +// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->ndi = 1; +// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->TPC = 1;//tpc; +// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->cshift = cba_group; +// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->cqi_req = 1; + +// //add_ue_spec_dci +// add_common_dci(DCI_pdu, +// ULSCH_dci, +// eNB_mac_inst[module_idP].common_channels[CC_id].cba_rnti[cba_group], +// sizeof(DCI0_5MHz_FDD_t), +// aggregation, +// sizeof_DCI0_5MHz_FDD_t, +// format0, +// 0); +// } + +// LOG_D(MAC,"[eNB %d] CC_id %d Frame %d, subframeP %d: Generated ULSCH DCI for CBA group %d, RB 25 format 0\n", module_idP,CC_id,frameP,subframeP,cba_group); +// break; + +// case 50: +// if (frame_parms->frame_type == TDD) { +// ULSCH_dci = UE_list->UE_template[CC_id][cba_group].ULSCH_DCI[0]; + +// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->type = 0; +// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->hopping = 0; +// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->rballoc = rballoc; +// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->mcs = mcs[cba_group]; +// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->ndi = 1; +// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->TPC = 1;//tpc; +// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->cshift = cba_group; +// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->dai = UE_list->UE_template[CC_id][cba_group].DAI_ul[sched_subframe]; +// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->cqi_req = 1; + +// //add_ue_spec_dci +// add_common_dci(DCI_pdu, +// ULSCH_dci, +// eNB_mac_inst[module_idP].common_channels[CC_id].cba_rnti[cba_group], +// sizeof(DCI0_10MHz_TDD_1_6_t), +// aggregation, +// sizeof_DCI0_10MHz_TDD_1_6_t, +// format0, +// 0); +// } else { +// ULSCH_dci = UE_list->UE_template[CC_id][cba_group].ULSCH_DCI[0]; + +// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->type = 0; +// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->hopping = 0; +// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->rballoc = rballoc; +// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->mcs = mcs[cba_group]; +// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->ndi = 1; +// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->TPC = 1;//tpc; +// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->cshift = cba_group; +// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->cqi_req = 1; + +// //add_ue_spec_dci +// add_common_dci(DCI_pdu, +// ULSCH_dci, +// eNB_mac_inst[module_idP].common_channels[CC_id].cba_rnti[cba_group], +// sizeof(DCI0_10MHz_FDD_t), +// aggregation, +// sizeof_DCI0_10MHz_FDD_t, +// format0, +// 0); +// } + +// LOG_D(MAC,"[eNB %d] CC_id %d Frame %d, subframeP %d: Generated ULSCH DCI for CBA group %d, RB 50 format 0\n", module_idP,CC_id,frameP,subframeP,cba_group); +// break; + +// case 100: +// mac_xface->macphy_exit("[MAC][eNB] CBA RB=100 not supported \n"); +// break; + +// default: +// break; +// } + +// // break;// for the moment only schedule one +// } +// } +// } +// } +// } +// #endif From 5ce9858d63bf3c0f210816dd999b607aa37e57b3 Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Fri, 21 Apr 2017 13:22:20 +0200 Subject: [PATCH 012/284] uplink scheduling --- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 33 +++++++++++++++ openair2/ENB_APP/MESSAGES/V2/flexran.proto | 4 +- openair2/ENB_APP/MESSAGES/V2/header.proto | 11 ++--- openair2/LAYER2/MAC/eNB_scheduler.c | 40 +++++++++---------- .../MAC/flexran_agent_scheduler_ulsch_ue.c | 6 +++ 5 files changed, 67 insertions(+), 27 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 405837061a..cd81abca3f 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -1044,6 +1044,39 @@ int flexran_agent_mac_destroy_dl_config(Protocol__FlexranMessage *msg) { return -1; } +int flexran_agent_mac_create_empty_ul_config(mid_t mod_id, Protocol__FlexranMessage **msg) { + + int xid = 0; + Protocol__FlexHeader *header; + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_UL_MAC_CONFIG, &header) != 0) + goto error; + + Protocol__FlexUlMacConfig *ul_mac_config_msg; + ul_mac_config_msg = malloc(sizeof(Protocol__FlexUlMacConfig)); + if (ul_mac_config_msg == NULL) { + goto error; + } + protocol__flex_ul_mac_config__init(ul_mac_config_msg); + + ul_mac_config_msg->header = header; + ul_mac_config_msg->has_sfn_sf = 1; + ul_mac_config_msg->sfn_sf = flexran_get_sfn_sf(mod_id); + + *msg = malloc(sizeof(Protocol__FlexranMessage)); + if(*msg == NULL) + goto error; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_UL_MAC_CONFIG_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; + (*msg)->ul_mac_config_msg = ul_mac_config_msg; + + return 0; + + error: + return -1; +} + + void flexran_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__FlexranMessage **msg) { struct lfds700_misc_prng_state ls; diff --git a/openair2/ENB_APP/MESSAGES/V2/flexran.proto b/openair2/ENB_APP/MESSAGES/V2/flexran.proto index caee626a73..01728bb268 100644 --- a/openair2/ENB_APP/MESSAGES/V2/flexran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/flexran.proto @@ -24,12 +24,12 @@ message flexran_message { flex_ue_config_reply ue_config_reply_msg = 11; flex_lc_config_request lc_config_request_msg = 12; flex_lc_config_reply lc_config_reply_msg = 13; - flex_dl_mac_config dl_mac_config_msg = 14; - flex_ul_mac_config ul_mac_config_msg = 19; + flex_dl_mac_config dl_mac_config_msg = 14; flex_ue_state_change ue_state_change_msg = 15; flex_control_delegation control_delegation_msg = 16; flex_agent_reconfiguration agent_reconfiguration_msg = 17; flex_rrc_triggering rrc_triggering = 18; + flex_ul_mac_config ul_mac_config_msg = 19; } } diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index 468dcd201e..1650030e32 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -32,14 +32,15 @@ enum flex_type { //Controller command messages FLPT_DL_MAC_CONFIG = 13; - + FLPT_UL_MAC_CONFIG = 14 + ; // UE state change messages - FLPT_UE_STATE_CHANGE = 14; + FLPT_UE_STATE_CHANGE = 15; // Control delegation messages - FLPT_DELEGATE_CONTROL = 15; - FLPT_RECONFIGURE_AGENT = 16; - FLPT_RRC_TRIGGERING = 17; + FLPT_DELEGATE_CONTROL = 16; + FLPT_RECONFIGURE_AGENT = 17; + FLPT_RRC_TRIGGERING = 18; } diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 7250d66f07..56052b050a 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -398,7 +398,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,4);//,calibration_flag); #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,4); } #endif @@ -438,7 +438,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,7); } #endif @@ -453,7 +453,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,8); } #endif @@ -472,7 +472,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,1,5); } #endif @@ -511,7 +511,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,2,6); } #endif @@ -553,7 +553,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,7); } #endif @@ -591,7 +591,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,3,7); } #endif @@ -634,7 +634,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,8); } #endif @@ -679,7 +679,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,4,8); } #endif @@ -724,7 +724,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,5,9); } #endif @@ -796,7 +796,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,2); } #endif @@ -812,7 +812,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,3); } #endif @@ -879,7 +879,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,6,0); } #endif @@ -971,7 +971,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,7,1); } #endif @@ -1018,7 +1018,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,2); } #endif @@ -1054,7 +1054,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,8,2); } #endif @@ -1094,7 +1094,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,3); } #endif @@ -1128,7 +1128,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,3); } #endif @@ -1161,7 +1161,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,4); } #endif @@ -1222,7 +1222,7 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,9,3); } #endif diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index 2abd09024b..a45f81fdaa 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -790,6 +790,7 @@ void flexran_agent_schedule_ulsch_ue_spec(module_id_t module_idP, unsigned char sched_subframe) { +// flexran_agent_mac_create_empty_ul_config(module_idP, ul_info); uint16_t first_rb[MAX_NUM_CCs],i; int CC_id; @@ -884,6 +885,11 @@ void flexran_agent_schedule_ulsch_rnti(module_id_t module_idP, // LOG_I(MAC,"entering ulsch preprocesor\n"); + + + + + _ulsch_scheduler_pre_processor(module_idP, frameP, subframeP, From fdac4d178be4b250787a5779d2da700128627aa2 Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Sat, 22 Apr 2017 12:43:04 +0200 Subject: [PATCH 013/284] uplink harq api --- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 39 +++++ .../CONTROL_MODULES/MAC/flexran_agent_mac.h | 4 + .../MAC/flexran_agent_mac_defs.h | 2 +- openair2/ENB_APP/MESSAGES/V2/flexran.proto | 4 +- openair2/ENB_APP/MESSAGES/V2/header.proto | 13 +- openair2/ENB_APP/flexran_agent_ran_api.c | 20 ++- openair2/ENB_APP/flexran_agent_ran_api.h | 2 +- openair2/LAYER2/MAC/eNB_scheduler.c | 147 +++++++++++++----- openair2/LAYER2/MAC/flexran_agent_mac_proto.h | 4 +- .../MAC/flexran_agent_scheduler_dataplane.c | 12 +- .../MAC/flexran_agent_scheduler_dlsch_ue.c | 6 +- .../MAC/flexran_agent_scheduler_ulsch_ue.c | 13 +- 12 files changed, 191 insertions(+), 75 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index cd81abca3f..db9af62eac 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -1077,6 +1077,45 @@ int flexran_agent_mac_create_empty_ul_config(mid_t mod_id, Protocol__FlexranMess } +int flexran_agent_mac_destroy_ul_config(Protocol__FlexranMessage *msg) { + int i,j, k; + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_UL_MAC_CONFIG_MSG) + goto error; + + Protocol__FlexUlDci *ul_dci; + + free(msg->ul_mac_config_msg->header); + for (i = 0; i < msg->ul_mac_config_msg->n_ul_ue_data; i++) { + // TODO uplink rlc ... + // free(msg->ul_mac_config_msg->dl_ue_data[i]->ce_bitmap); + // for (j = 0; j < msg->ul_mac_config_msg->ul_ue_data[i]->n_rlc_pdu; j++) { + // for (k = 0; k < msg->ul_mac_config_msg->ul_ue_data[i]->rlc_pdu[j]->n_rlc_pdu_tb; k++) { + // free(msg->ul_mac_config_msg->dl_ue_data[i]->rlc_pdu[j]->rlc_pdu_tb[k]); + // } + // free(msg->ul_mac_config_msg->ul_ue_data[i]->rlc_pdu[j]->rlc_pdu_tb); + // free(msg->ul_mac_config_msg->ul_ue_data[i]->rlc_pdu[j]); + // } + // free(msg->ul_mac_config_msg->ul_ue_data[i]->rlc_pdu); + ul_dci = msg->ul_mac_config_msg->ul_ue_data[i]->ul_dci; + // free(dl_dci->tbs_size); + // free(ul_dci->mcs); + // free(ul_dci->ndi); + // free(ul_dci->rv); + // free(ul_dci); + free(msg->ul_mac_config_msg->ul_ue_data[i]); + } + free(msg->ul_mac_config_msg->ul_ue_data); + + free(msg->ul_mac_config_msg); + free(msg); + + return 0; + + error: + return -1; +} + + void flexran_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__FlexranMessage **msg) { struct lfds700_misc_prng_state ls; diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h index d2db860ce4..0dcee577f5 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h @@ -57,6 +57,10 @@ int flexran_agent_mac_destroy_stats_reply(Protocol__FlexranMessage *msg); int flexran_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__FlexranMessage **msg); int flexran_agent_mac_destroy_dl_config(Protocol__FlexranMessage *msg); +/* UL MAC scheduling decision protocol message constructor (empty command) and destructor */ +int flexran_agent_mac_create_empty_ul_config(mid_t mod_id, Protocol__FlexranMessage **msg); +int flexran_agent_mac_destroy_ul_config(Protocol__FlexranMessage *msg); + int flexran_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h index ab6bf57417..49ef7f0fb7 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h @@ -63,7 +63,7 @@ typedef struct { void (*flexran_agent_schedule_ul_spec)(mid_t module_idP, uint32_t frameP, unsigned char cooperation_flag, uint32_t subframeP, - unsigned char sched_subframe); + unsigned char sched_subframe, Protocol__FlexranMessage **ul_info); /// Notify the controller for a state change of a particular UE, by sending the proper /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) diff --git a/openair2/ENB_APP/MESSAGES/V2/flexran.proto b/openair2/ENB_APP/MESSAGES/V2/flexran.proto index 01728bb268..8ebfc7df8b 100644 --- a/openair2/ENB_APP/MESSAGES/V2/flexran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/flexran.proto @@ -168,8 +168,8 @@ message flex_dl_mac_config { message flex_ul_mac_config { optional flex_header header = 1; - optional uint32 sfn_sf = 2; - repeated flex_ul_data ul_ue_data = 3; + optional uint32 sfn_sf = 2; + repeated flex_ul_data ul_ue_data = 3; } diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index 1650030e32..79d541200c 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -32,15 +32,14 @@ enum flex_type { //Controller command messages FLPT_DL_MAC_CONFIG = 13; - FLPT_UL_MAC_CONFIG = 14 - ; + // UE state change messages - FLPT_UE_STATE_CHANGE = 15; + FLPT_UE_STATE_CHANGE = 14; // Control delegation messages - FLPT_DELEGATE_CONTROL = 16; - FLPT_RECONFIGURE_AGENT = 17; - FLPT_RRC_TRIGGERING = 18; - + FLPT_DELEGATE_CONTROL = 15; + FLPT_RECONFIGURE_AGENT = 16; + FLPT_RRC_TRIGGERING = 17; + FLPT_UL_MAC_CONFIG = 18; } diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 9602b041c3..334dd3cb9a 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -299,8 +299,9 @@ int flexran_get_harq(const mid_t mod_id, const mid_t ue_id, const int frame, const uint8_t subframe, - uint8_t *id, - uint8_t *round) { //flag_id_status = 0 then id, else status + uint8_t *pid, + uint8_t *round, + const uint8_t harq_flag) { //flag_id_status = 0 then id, else status /*TODO: Add int TB in function parameters to get the status of the second TB. This can be done to by editing in * get_ue_active_harq_pid function in line 272 file: phy_procedures_lte_eNB.c to add * DLSCH_ptr = PHY_vars_eNB_g[Mod_id][CC_id]->dlsch_eNB[(uint32_t)UE_id][1];*/ @@ -310,10 +311,21 @@ int flexran_get_harq(const mid_t mod_id, uint16_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + if (harq_flag == openair_harq_DL){ - mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&harq_round,openair_harq_DL); + mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&harq_round,openair_harq_DL); - *id = harq_pid; + } else if (harq_flag == openair_harq_UL){ + + mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&round,openair_harq_UL); + } + else { + + LOG_W(FLEXRAN_AGENT,"harq_flag is not recongnized"); + } + + + *pid = harq_pid; *round = harq_round; /* if (round > 0) { */ /* *status = 1; */ diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 8a7d6dbaf7..e80ed44ce9 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -187,7 +187,7 @@ int flexran_get_ue_pmi(mid_t mod_id); a designated frame and subframe. Returns 0 for success. The id and the status of the HARQ process are stored in id and status respectively */ int flexran_get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, - const int frame, const uint8_t subframe, unsigned char *id, unsigned char *round); + const int frame, const uint8_t subframe, unsigned char *id, unsigned char *round,const uint8_t harq_flag); /* Uplink power control management*/ int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id); diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 56052b050a..bf69d7c8ef 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -386,8 +386,10 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, schedule_ulsch(module_idP,frameP,cooperation_flag,0,4);//,calibration_flag); #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); #endif @@ -398,8 +400,10 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,4);//,calibration_flag); #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,4, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); #endif } @@ -415,7 +419,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -438,9 +442,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,7); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,7, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif #ifndef FLEXRAN_AGENT_SB_IF fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); @@ -453,9 +460,11 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,8); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,8, &msg); } + flexran_agent_mac_destroy_ul_config(msg); + #endif #ifndef FLEXRAN_AGENT_SB_IF @@ -472,9 +481,12 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,1,5); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,1,5, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif #ifndef FLEXRAN_AGENT_SB_IF @@ -489,7 +501,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -511,9 +523,13 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,2,6); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,2,6, &msg); } + + + flexran_agent_mac_destroy_ul_config(msg); + #endif #ifndef FLEXRAN_AGENT_SB_IF @@ -528,7 +544,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -553,9 +569,12 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,7); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,7, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif // no break here! @@ -572,7 +591,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -591,9 +610,13 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,3,7); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,3,7, &msg); } + + + flexran_agent_mac_destroy_ul_config(msg); + #endif #ifndef FLEXRAN_AGENT_SB_IF @@ -608,7 +631,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -634,9 +657,12 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,8); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,8, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif // no break here! @@ -659,7 +685,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -679,9 +705,12 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,4,8); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,4,8, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif #ifndef FLEXRAN_AGENT_SB_IF @@ -696,7 +725,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -724,9 +753,12 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,5,9); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,5,9, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif #ifndef FLEXRAN_AGENT_SB_IF @@ -741,7 +773,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -768,7 +800,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -796,9 +828,12 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,2); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,2, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif // schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); #ifndef FLEXRAN_AGENT_SB_IF @@ -812,9 +847,12 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,3); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,3, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif // schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); #ifndef FLEXRAN_AGENT_SB_IF @@ -836,7 +874,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -860,7 +898,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -879,9 +917,12 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,6,0); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,6,0, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif #ifndef FLEXRAN_AGENT_SB_IF @@ -896,7 +937,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -929,7 +970,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -952,7 +993,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -971,9 +1012,12 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,7,1); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,7,1, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif #ifndef FLEXRAN_AGENT_SB_IF @@ -988,7 +1032,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -1018,9 +1062,11 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,2); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,2, &msg); } + flexran_agent_mac_destroy_ul_config(msg); + #endif #ifndef FLEXRAN_AGENT_SB_IF @@ -1035,7 +1081,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -1054,9 +1100,12 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,8,2); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,8,2, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif #ifndef FLEXRAN_AGENT_SB_IF @@ -1071,7 +1120,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -1094,9 +1143,12 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,3); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,3, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif schedule_RA(module_idP,frameP,subframeP,7); // 7 = Msg3 subframeP, not #ifndef FLEXRAN_AGENT_SB_IF @@ -1111,7 +1163,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -1128,9 +1180,12 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,3); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,3, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif #ifndef FLEXRAN_AGENT_SB_IF @@ -1145,7 +1200,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -1161,9 +1216,12 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,4); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,subframeP,4, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif //schedule_RA(module_idP,frameP,subframeP); #ifndef FLEXRAN_AGENT_SB_IF @@ -1178,7 +1236,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -1203,7 +1261,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -1222,9 +1280,12 @@ if (mac_agent_registered[module_idP]){ #else if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,9,3); + agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,9,3, &msg); } + + flexran_agent_mac_destroy_ul_config(msg); + #endif #ifndef FLEXRAN_AGENT_SB_IF @@ -1239,7 +1300,7 @@ if (mac_agent_registered[module_idP]){ mbsfn_status, &msg); - flexran_apply_dl_scheduling_decisions(module_idP, + flexran_apply_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, diff --git a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h index 8a9d5971e3..7b5c402b61 100644 --- a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h +++ b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h @@ -174,12 +174,12 @@ void flexran_schedule_ue_spec_default(mid_t mod_id, uint32_t frame, uint32_t sub void flexran_agent_schedule_ulsch_ue_spec(module_id_t module_idP, frame_t frameP, unsigned char cooperation_flag, sub_frame_t subframeP, - unsigned char sched_subframe); + unsigned char sched_subframe, Protocol__FlexranMessage **ul_info); /* * Data plane function for applying the DL decisions of the scheduler */ -void flexran_apply_dl_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, +void flexran_apply_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, Protocol__FlexranMessage *dl_scheduling_info); /* diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c index 38f39e50e1..ba5aadcb5b 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c @@ -59,28 +59,28 @@ #include "SIMULATION/TOOLS/defs.h" // for taus -void flexran_apply_dl_scheduling_decisions(mid_t mod_id, +void flexran_apply_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, Protocol__FlexranMessage *dl_scheduling_info) { - Protocol__FlexDlMacConfig *mac_config = dl_scheduling_info->dl_mac_config_msg; + Protocol__FlexDlMacConfig *mac_dl_config = dl_scheduling_info->dl_mac_config_msg; // Check if there is anything to schedule for random access - if (mac_config->n_dl_rar > 0) { + if (mac_dl_config->n_dl_rar > 0) { /*TODO: call the random access data plane function*/ } // Check if there is anything to schedule for paging/broadcast - if (mac_config->n_dl_broadcast > 0) { + if (mac_dl_config->n_dl_broadcast > 0) { /*TODO: call the broadcast/paging data plane function*/ } // Check if there is anything to schedule for the UEs - if (mac_config->n_dl_ue_data > 0) { + if (mac_dl_config->n_dl_ue_data > 0) { flexran_apply_ue_spec_scheduling_decisions(mod_id, frame, subframe, mbsfn_flag, - mac_config->n_dl_ue_data, mac_config->dl_ue_data); + mac_dl_config->n_dl_ue_data, mac_dl_config->dl_ue_data); } } diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index 81c18a26c0..fc3906ab6f 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -526,7 +526,7 @@ void _dlsch_scheduler_pre_processor (module_id_t Mod_id, CC_id = UE_list->ordered_CCids[ii][UE_id]; ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; ue_sched_ctl->max_allowed_rbs[CC_id]=nb_rbs_allowed_slice[CC_id][slice_id]; - flexran_get_harq(Mod_id, CC_id, UE_id, frameP, subframeP, &harq_pid, &round); + flexran_get_harq(Mod_id, CC_id, UE_id, frameP, subframeP, &harq_pid, &round, openair_harq_DL); // if there is no available harq_process, skip the UE if (UE_list->UE_sched_ctrl[UE_id].harq_pid[CC_id]<0) @@ -640,7 +640,7 @@ void _dlsch_scheduler_pre_processor (module_id_t Mod_id, for (ii=0; iiordered_CCids[ii][UE_id]; ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - flexran_get_harq(Mod_id, CC_id, UE_id, frameP, subframeP, &harq_pid, &round); + flexran_get_harq(Mod_id, CC_id, UE_id, frameP, subframeP, &harq_pid, &round, openair_harq_DL); rnti = UE_RNTI(Mod_id,UE_id); // LOG_D(MAC,"UE %d rnti 0x\n", UE_id, rnti ); @@ -1096,7 +1096,7 @@ flexran_schedule_ue_spec_common(mid_t mod_id, dl_data[num_ues_added]->serv_cell_index = CC_id; nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; - flexran_get_harq(mod_id, CC_id, UE_id, frame, subframe, &harq_pid, &round); + flexran_get_harq(mod_id, CC_id, UE_id, frame, subframe, &harq_pid, &round, openair_harq_DL); sdu_length_total=0; mcs = cqi_to_mcs[flexran_get_ue_wcqi(mod_id, UE_id)]; // LOG_I(FLEXRAN_AGENT, "The MCS is %d\n", mcs); diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index a45f81fdaa..604a428d9c 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -615,8 +615,8 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, // This is the actual CC_id in the list CC_id = UE_list->ordered_ULCCids[n][UE_id]; - mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL); - + // mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL); + flexran_get_harq(module_idP, CC_id, UE_id, frameP, subframeP, &harq_pid, &round, openair_harq_UL); if(round>0) { nb_allocated_rbs[CC_id][UE_id] = UE_list->UE_template[CC_id][UE_id].nb_rb_ul[harq_pid]; } else { @@ -787,10 +787,11 @@ void flexran_agent_schedule_ulsch_ue_spec(module_id_t module_idP, frame_t frameP, unsigned char cooperation_flag, sub_frame_t subframeP, - unsigned char sched_subframe) { + unsigned char sched_subframe, + Protocol__FlexranMessage **ul_info) { -// flexran_agent_mac_create_empty_ul_config(module_idP, ul_info); +flexran_agent_mac_create_empty_ul_config(module_idP, ul_info); uint16_t first_rb[MAX_NUM_CCs],i; int CC_id; @@ -907,7 +908,7 @@ void flexran_agent_schedule_ulsch_rnti(module_id_t module_idP, continue; } - rnti = UE_RNTI(module_idP,UE_id); + rnti = flexran_get_ue_crnti(module_idP, UE_id); if (rnti==NOT_A_RNTI) { LOG_W(MAC,"[eNB %d] frame %d subfarme %d, UE %d: no RNTI \n", module_idP,frameP,subframeP,UE_id); @@ -973,7 +974,7 @@ abort(); UE_template = &UE_list->UE_template[CC_id][UE_id]; UE_sched_ctrl = &UE_list->UE_sched_ctrl[UE_id]; - if (mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL) == -1 ) { + if (flexran_get_harq(module_idP, CC_id, UE_id, frameP, subframeP, &harq_pid, &round, openair_harq_UL) == -1 ) { LOG_W(MAC,"[eNB %d] Scheduler Frame %d, subframeP %d: candidate harq_pid from PHY for UE %d CC %d RNTI %x\n", module_idP,frameP,subframeP, UE_id, CC_id, rnti); continue; From 57129bc0af65ac764741ca1042d916a74f56600a Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Tue, 25 Apr 2017 18:19:47 +0200 Subject: [PATCH 014/284] Uplink Slicing --- openair2/ENB_APP/flexran_agent_ran_api.c | 15 +++++++++ .../MAC/flexran_agent_scheduler_dlsch_ue.c | 12 +++++++ .../MAC/flexran_agent_scheduler_ulsch_ue.c | 31 +++++++++++++------ 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 334dd3cb9a..ae304d1e26 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -655,6 +655,21 @@ int flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) { return -1; } + +int flexran_get_rrc_status(const mid_t mod_id, const rnti_t rntiP){ + + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + + if (ue_context_p != NULL) { + return(ue_context_p->ue_context.Status); + } else { + return RRC_INACTIVE; + } + +} + int flexran_get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id) { return ((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateDL; } diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index fc3906ab6f..aec093e88a 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -742,7 +742,9 @@ flexran_schedule_ue_spec_default(mid_t mod_id, if ((n_active_slices > 0) && (n_active_slices <= MAX_NUM_SLICES)) { LOG_N(MAC,"[eNB %d]frame %d subframe %d: number of active slices has changed: %d-->%d\n", mod_id, frame, subframe, n_active_slices_current, n_active_slices); + n_active_slices_current = n_active_slices; + } else { LOG_W(MAC,"invalid number of slices %d, revert to the previous value %d\n",n_active_slices, n_active_slices_current); n_active_slices = n_active_slices_current; @@ -756,18 +758,22 @@ flexran_schedule_ue_spec_default(mid_t mod_id, total_slice_percentage=total_slice_percentage - slice_percentage_current[i] + slice_percentage[i]; LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: total percentage %f, slice RB percentage has changed: %f-->%f\n", mod_id, i, frame, subframe, total_slice_percentage, slice_percentage_current[i], slice_percentage[i]); + slice_percentage_current[i] = slice_percentage[i]; + } else { LOG_W(MAC,"[eNB %d][SLICE %d] invalid total RB share (%f->%f), revert the previous value (%f->%f)\n", mod_id,i, total_slice_percentage, total_slice_percentage - slice_percentage_current[i] + slice_percentage[i], slice_percentage[i],slice_percentage_current[i]); + slice_percentage[i]= slice_percentage_current[i]; } } else { LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice RB share, revert the previous value (%f->%f)\n",mod_id, i, slice_percentage[i],slice_percentage_current[i]); + slice_percentage[i]= slice_percentage_current[i]; } @@ -778,10 +784,14 @@ flexran_schedule_ue_spec_default(mid_t mod_id, if ((slice_maxmcs[i] >= 0) && (slice_maxmcs[i] < 29)){ LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: slice MAX MCS has changed: %d-->%d\n", mod_id, i, frame, subframe, slice_maxmcs_current[i], slice_maxmcs[i]); + slice_maxmcs_current[i] = slice_maxmcs[i]; + } else { LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice max mcs %d, revert the previous value %d\n",mod_id, i, slice_percentage[i],slice_percentage[i]); + slice_maxmcs[i]= slice_maxmcs_current[i]; + } } @@ -789,7 +799,9 @@ flexran_schedule_ue_spec_default(mid_t mod_id, if (update_dl_scheduler_current[i] != update_dl_scheduler[i]){ LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: DL scheduler for this slice is updated: %s \n", mod_id, i, frame, subframe, dl_scheduler_type[i]); + update_dl_scheduler_current[i] = update_dl_scheduler[i]; + } // Run each enabled slice-specific schedulers one by one diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index 604a428d9c..001f284938 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -59,6 +59,12 @@ // #define ENABLE_MAC_PAYLOAD_DEBUG // #define DEBUG_eNB_SCHEDULER 1 + +// RB share for each slice for past and current time +float slice_percentage_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; +float slice_percentage_current_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; + + // // This table holds the allowable PRB sizes for ULSCH transmissions // uint8_t rb_table[33] = {1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36,40,45,48,50,54,60,72,75,80,81,90,96,100}; @@ -500,6 +506,7 @@ // } void _ulsch_scheduler_pre_processor(module_id_t module_idP, + int slice_id, int frameP, sub_frame_t subframeP, uint16_t *first_rb) @@ -515,7 +522,8 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, UE_list_t *UE_list = &eNB_mac_inst[module_idP].UE_list; UE_TEMPLATE *UE_template = 0; LTE_DL_FRAME_PARMS *frame_parms = 0; - + + uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES]; //LOG_I(MAC,"assign max mcs min rb\n"); // maximize MCS and then allocate required RB according to the buffer occupancy with the limit of max available UL RB @@ -576,15 +584,17 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, max_num_ue_to_be_scheduled+=1; + nb_rbs_allowed_slice[CC_id][slice_id] = flexran_nb_rbs_allowed_slice(slice_percentage_uplink[slice_id], flexran_get_N_RB_UL(module_idP, CC_id)); + if (total_ue_count == 0) { average_rbs_per_user[CC_id] = 0; } else if (total_ue_count == 1 ) { // increase the available RBs, special case, - average_rbs_per_user[CC_id] = frame_parms->N_RB_UL-first_rb[CC_id]+1; - } else if( (total_ue_count <= (frame_parms->N_RB_DL-first_rb[CC_id])) && + average_rbs_per_user[CC_id] = nb_rbs_allowed_slice[CC_id][slice_id]-first_rb[CC_id]+1; + } else if( (total_ue_count <= (nb_rbs_allowed_slice[CC_id][slice_id]-first_rb[CC_id])) && (total_ue_count <= max_num_ue_to_be_scheduled)) { - average_rbs_per_user[CC_id] = (uint16_t) floor((frame_parms->N_RB_UL-first_rb[CC_id])/total_ue_count); + average_rbs_per_user[CC_id] = (uint16_t) floor((nb_rbs_allowed_slice[CC_id][slice_id]-first_rb[CC_id])/total_ue_count); } else if (max_num_ue_to_be_scheduled > 0 ) { - average_rbs_per_user[CC_id] = (uint16_t) floor((frame_parms->N_RB_UL-first_rb[CC_id])/max_num_ue_to_be_scheduled); + average_rbs_per_user[CC_id] = (uint16_t) floor((nb_rbs_allowed_slice[CC_id][slice_id]-first_rb[CC_id])/max_num_ue_to_be_scheduled); } else { average_rbs_per_user[CC_id]=1; LOG_W(MAC,"[eNB %d] frame %d subframe %d: UE %d CC %d: can't get average rb per user (should not be here)\n", @@ -648,7 +658,7 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, CC_id = UE_list->ordered_ULCCids[n][UE_id]; UE_template = &UE_list->UE_template[CC_id][UE_id]; frame_parms = mac_xface->get_lte_frame_parms(module_idP,CC_id); - total_remaining_rbs[CC_id]=frame_parms->N_RB_UL - first_rb[CC_id] - total_allocated_rbs[CC_id]; + total_remaining_rbs[CC_id]=nb_rbs_allowed_slice[CC_id][slice_id] - first_rb[CC_id] - total_allocated_rbs[CC_id]; if (total_ue_count == 1 ) { total_remaining_rbs[CC_id]+=1; @@ -675,7 +685,7 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, frame_parms= mac_xface->get_lte_frame_parms(module_idP,CC_id); if (total_allocated_rbs[CC_id]>0) { - LOG_D(MAC,"[eNB %d] total RB allocated for all UEs = %d/%d\n", module_idP, total_allocated_rbs[CC_id], frame_parms->N_RB_UL - first_rb[CC_id]); + LOG_D(MAC,"[eNB %d] total RB allocated for all UEs = %d/%d\n", module_idP, total_allocated_rbs[CC_id], nb_rbs_allowed_slice[CC_id][slice_id] - first_rb[CC_id]); } } } @@ -888,10 +898,11 @@ void flexran_agent_schedule_ulsch_rnti(module_id_t module_idP, - + int slice_id = 0; _ulsch_scheduler_pre_processor(module_idP, + slice_id, frameP, subframeP, first_rb); @@ -993,7 +1004,9 @@ abort(); UE_sched_ctrl->ul_failure_timer); // reset the scheduling request UE_template->ul_SR = 0; - status = mac_eNB_get_rrc_status(module_idP,rnti); + // status = mac_eNB_get_rrc_status(module_idP,rnti); + status = flexran_get_rrc_status(module_idP, rnti); + if (status < RRC_CONNECTED) cqi_req = 0; else if (UE_sched_ctrl->cqi_req_timer>30) { From 897c8da299615016c7e9ac6320883423465a0de0 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 26 Apr 2017 07:50:04 +0000 Subject: [PATCH 015/284] Fixed size of arrays for RSRP and RSRQ measurements --- openair2/RRC/LITE/extern.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/RRC/LITE/extern.h b/openair2/RRC/LITE/extern.h index d4c8192a95..7934690563 100644 --- a/openair2/RRC/LITE/extern.h +++ b/openair2/RRC/LITE/extern.h @@ -93,8 +93,8 @@ extern uint16_t N310[8]; extern uint16_t N311[8]; extern uint32_t T304[8]; extern uint32_t timeToTrigger_ms[16]; -extern float RSRP_meas_mapping[100]; -extern float RSRQ_meas_mapping[33]; +extern float RSRP_meas_mapping[98]; +extern float RSRQ_meas_mapping[35]; #endif From b9b45c4ac030ef54f210aa37c066e7ccb5ffac86 Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Wed, 26 Apr 2017 19:15:39 +0200 Subject: [PATCH 016/284] uplink primitives --- openair2/LAYER2/MAC/flexran_agent_mac_proto.h | 18 ++ .../MAC/flexran_agent_scheduler_ulsch_ue.c | 160 +++++++++++++++++- 2 files changed, 176 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h index 7b5c402b61..fbb8a11950 100644 --- a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h +++ b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h @@ -117,6 +117,8 @@ int flexran_slice_member(int UE_id, int flexran_slice_maxmcs(int slice_id) ; +/* Downlink Primitivies */ + void _store_dlsch_buffer (module_id_t Mod_id, int slice_id, frame_t frameP, @@ -131,6 +133,22 @@ void _assign_rbs_required (module_id_t Mod_id, uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES], int min_rb_unit[MAX_NUM_CCs]); + +/* Uplink Primitivies */ + +// void _sort_ue_ul (module_id_t module_idP,int frameP, sub_frame_t subframeP); + +void _assign_max_mcs_min_rb(module_id_t module_idP,int frameP, sub_frame_t subframeP, uint16_t *first_rb); + + +void _ulsch_scheduler_pre_processor(module_id_t module_idP, + int slice_id, + uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES], + int frameP, + sub_frame_t subframeP, + uint16_t *first_rb); + + void _dlsch_scheduler_pre_processor (module_id_t Mod_id, int slice_id, frame_t frameP, diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index 001f284938..849dc30869 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -65,6 +65,10 @@ float slice_percentage_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; float slice_percentage_current_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; +uint16_t flexran_nb_rbs_allowed_slice_uplink(float rb_percentage, int total_rbs){ + return (uint16_t) floor(rb_percentage * total_rbs); +} + // // This table holds the allowable PRB sizes for ULSCH transmissions // uint8_t rb_table[33] = {1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36,40,45,48,50,54,60,72,75,80,81,90,96,100}; @@ -505,6 +509,158 @@ float slice_percentage_current_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; // stop_meas(&eNB->rx_ulsch_sdu); // } + + +// void _sort_ue_ul (module_id_t module_idP,int frameP, sub_frame_t subframeP) +// { +// int i; +// int list[NUMBER_OF_UE_MAX]; +// int list_size = 0; +// int rnti; +// struct sort_ue_ul_params params = { module_idP, frameP, subframeP }; + +// UE_list_t *UE_list = &eNB_mac_inst[module_idP].UE_list; + +// for (i = 0; i < NUMBER_OF_UE_MAX; i++) { +// rnti = UE_RNTI(module_idP, i); +// if (rnti == NOT_A_RNTI) +// continue; +// if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) +// continue; +// if (!phy_stats_exist(module_idP, rnti)) +// continue; +// list[list_size] = i; +// list_size++; +// } + +// qsort_r(list, list_size, sizeof(int), ue_ul_compare, ¶ms); + +// if (list_size) { +// for (i = 0; i < list_size-1; i++) +// UE_list->next_ul[list[i]] = list[i+1]; +// UE_list->next_ul[list[list_size-1]] = -1; +// UE_list->head_ul = list[0]; +// } else { +// UE_list->head_ul = -1; +// } + +// } + + + +void _assign_max_mcs_min_rb(module_id_t module_idP,int frameP, sub_frame_t subframeP, uint16_t *first_rb) +{ + + int i; + uint16_t n,UE_id; + uint8_t CC_id; + rnti_t rnti = -1; + int mcs; + int rb_table_index=0,tbs,tx_power; + eNB_MAC_INST *eNB = &eNB_mac_inst[module_idP]; + UE_list_t *UE_list = &eNB->UE_list; + + UE_TEMPLATE *UE_template; + LTE_DL_FRAME_PARMS *frame_parms; + + + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (UE_list->active[i] != TRUE) continue; + + rnti = UE_RNTI(module_idP,i); + + if (rnti==NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + if (!phy_stats_exist(module_idP, rnti)) + continue; + + if (UE_list->UE_sched_ctrl[i].phr_received == 1) + mcs = 20; // if we've received the power headroom information the UE, we can go to maximum mcs + else + mcs = 10; // otherwise, limit to QPSK PUSCH + + UE_id = i; + + for (n=0; nnumactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; + + if (CC_id >= MAX_NUM_CCs) { + LOG_E( MAC, "CC_id %u should be < %u, loop n=%u < numactiveULCCs[%u]=%u", + CC_id, + MAX_NUM_CCs, + n, + UE_id, + UE_list->numactiveULCCs[UE_id]); + } + + AssertFatal( CC_id < MAX_NUM_CCs, "CC_id %u should be < %u, loop n=%u < numactiveULCCs[%u]=%u", + CC_id, + MAX_NUM_CCs, + n, + UE_id, + UE_list->numactiveULCCs[UE_id]); + frame_parms=mac_xface->get_lte_frame_parms(module_idP,CC_id); + UE_template = &UE_list->UE_template[CC_id][UE_id]; + + // if this UE has UL traffic + if (UE_template->ul_total_buffer > 0 ) { + + tbs = mac_xface->get_TBS_UL(mcs,3); // 1 or 2 PRB with cqi enabled does not work well! + // fixme: set use_srs flag + tx_power= mac_xface->estimate_ue_tx_power(tbs,rb_table[rb_table_index],0,frame_parms->Ncp,0); + + while ((((UE_template->phr_info - tx_power) < 0 ) || (tbs > UE_template->ul_total_buffer))&& + (mcs > 3)) { + // LOG_I(MAC,"UE_template->phr_info %d tx_power %d mcs %d\n", UE_template->phr_info,tx_power, mcs); + mcs--; + tbs = mac_xface->get_TBS_UL(mcs,rb_table[rb_table_index]); + tx_power = mac_xface->estimate_ue_tx_power(tbs,rb_table[rb_table_index],0,frame_parms->Ncp,0); // fixme: set use_srs + } + + while ((tbs < UE_template->ul_total_buffer) && + (rb_table[rb_table_index]<(frame_parms->N_RB_UL-first_rb[CC_id])) && + ((UE_template->phr_info - tx_power) > 0) && + (rb_table_index < 32 )) { + // LOG_I(MAC,"tbs %d ul buffer %d rb table %d max ul rb %d\n", tbs, UE_template->ul_total_buffer, rb_table[rb_table_index], frame_parms->N_RB_UL-first_rb[CC_id]); + rb_table_index++; + tbs = mac_xface->get_TBS_UL(mcs,rb_table[rb_table_index]); + tx_power = mac_xface->estimate_ue_tx_power(tbs,rb_table[rb_table_index],0,frame_parms->Ncp,0); + } + + UE_template->ue_tx_power = tx_power; + + if (rb_table[rb_table_index]>(frame_parms->N_RB_UL-first_rb[CC_id]-1)) { + rb_table_index--; + } + + // 1 or 2 PRB with cqi enabled does not work well! + if (rb_table[rb_table_index]<3) { + rb_table_index=2; //3PRB + } + + UE_template->pre_assigned_mcs_ul=mcs; + UE_template->pre_allocated_rb_table_index_ul=rb_table_index; + UE_template->pre_allocated_nb_rb_ul= rb_table[rb_table_index]; + LOG_D(MAC,"[eNB %d] frame %d subframe %d: for UE %d CC %d: pre-assigned mcs %d, pre-allocated rb_table[%d]=%d RBs (phr %d, tx power %d)\n", + module_idP, frameP, subframeP, UE_id, CC_id, + UE_template->pre_assigned_mcs_ul, + UE_template->pre_allocated_rb_table_index_ul, + UE_template->pre_allocated_nb_rb_ul, + UE_template->phr_info,tx_power); + } else { + UE_template->pre_allocated_rb_table_index_ul=-1; + UE_template->pre_allocated_nb_rb_ul=0; + } + } + } +} + + + + void _ulsch_scheduler_pre_processor(module_id_t module_idP, int slice_id, int frameP, @@ -527,7 +683,7 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, //LOG_I(MAC,"assign max mcs min rb\n"); // maximize MCS and then allocate required RB according to the buffer occupancy with the limit of max available UL RB - assign_max_mcs_min_rb(module_idP,frameP, subframeP, first_rb); + _assign_max_mcs_min_rb(module_idP,frameP, subframeP, first_rb); //LOG_I(MAC,"sort ue \n"); // sort ues @@ -584,7 +740,7 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, max_num_ue_to_be_scheduled+=1; - nb_rbs_allowed_slice[CC_id][slice_id] = flexran_nb_rbs_allowed_slice(slice_percentage_uplink[slice_id], flexran_get_N_RB_UL(module_idP, CC_id)); + nb_rbs_allowed_slice[CC_id][slice_id] = flexran_nb_rbs_allowed_slice_uplink(slice_percentage_uplink[slice_id], flexran_get_N_RB_UL(module_idP, CC_id)); if (total_ue_count == 0) { average_rbs_per_user[CC_id] = 0; From eee0c1b84b896a6085211a01927f13e4c1a4f1d9 Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Thu, 27 Apr 2017 09:29:00 +0200 Subject: [PATCH 017/284] uplink percentage --- openair2/LAYER2/MAC/flexran_agent_mac_proto.h | 5 ++--- .../MAC/flexran_agent_scheduler_ulsch_ue.c | 22 ++++++++++--------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h index fbb8a11950..186ccf1287 100644 --- a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h +++ b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h @@ -138,12 +138,11 @@ void _assign_rbs_required (module_id_t Mod_id, // void _sort_ue_ul (module_id_t module_idP,int frameP, sub_frame_t subframeP); -void _assign_max_mcs_min_rb(module_id_t module_idP,int frameP, sub_frame_t subframeP, uint16_t *first_rb); +void _assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, sub_frame_t subframeP, uint16_t *first_rb); void _ulsch_scheduler_pre_processor(module_id_t module_idP, - int slice_id, - uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES], + int slice_id, int frameP, sub_frame_t subframeP, uint16_t *first_rb); diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index 849dc30869..333cc275c2 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -65,6 +65,8 @@ float slice_percentage_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; float slice_percentage_current_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; + uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES]; + uint16_t flexran_nb_rbs_allowed_slice_uplink(float rb_percentage, int total_rbs){ return (uint16_t) floor(rb_percentage * total_rbs); } @@ -548,7 +550,7 @@ uint16_t flexran_nb_rbs_allowed_slice_uplink(float rb_percentage, int total_rbs) -void _assign_max_mcs_min_rb(module_id_t module_idP,int frameP, sub_frame_t subframeP, uint16_t *first_rb) +void _assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, sub_frame_t subframeP, uint16_t *first_rb) { int i; @@ -621,7 +623,7 @@ void _assign_max_mcs_min_rb(module_id_t module_idP,int frameP, sub_frame_t subfr } while ((tbs < UE_template->ul_total_buffer) && - (rb_table[rb_table_index]<(frame_parms->N_RB_UL-first_rb[CC_id])) && + (rb_table[rb_table_index]<(nb_rbs_allowed_slice[CC_id][slice_id]-first_rb[CC_id])) && ((UE_template->phr_info - tx_power) > 0) && (rb_table_index < 32 )) { // LOG_I(MAC,"tbs %d ul buffer %d rb table %d max ul rb %d\n", tbs, UE_template->ul_total_buffer, rb_table[rb_table_index], frame_parms->N_RB_UL-first_rb[CC_id]); @@ -632,7 +634,7 @@ void _assign_max_mcs_min_rb(module_id_t module_idP,int frameP, sub_frame_t subfr UE_template->ue_tx_power = tx_power; - if (rb_table[rb_table_index]>(frame_parms->N_RB_UL-first_rb[CC_id]-1)) { + if (rb_table[rb_table_index]>(nb_rbs_allowed_slice[CC_id][slice_id]-first_rb[CC_id]-1)) { rb_table_index--; } @@ -662,7 +664,7 @@ void _assign_max_mcs_min_rb(module_id_t module_idP,int frameP, sub_frame_t subfr void _ulsch_scheduler_pre_processor(module_id_t module_idP, - int slice_id, + int slice_id, int frameP, sub_frame_t subframeP, uint16_t *first_rb) @@ -679,11 +681,11 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, UE_TEMPLATE *UE_template = 0; LTE_DL_FRAME_PARMS *frame_parms = 0; - uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES]; + //LOG_I(MAC,"assign max mcs min rb\n"); // maximize MCS and then allocate required RB according to the buffer occupancy with the limit of max available UL RB - _assign_max_mcs_min_rb(module_idP,frameP, subframeP, first_rb); + _assign_max_mcs_min_rb(module_idP, slice_id, frameP, subframeP, first_rb); //LOG_I(MAC,"sort ue \n"); // sort ues @@ -1056,9 +1058,9 @@ void flexran_agent_schedule_ulsch_rnti(module_id_t module_idP, int slice_id = 0; - + _ulsch_scheduler_pre_processor(module_idP, - slice_id, + slice_id, frameP, subframeP, first_rb); @@ -1225,7 +1227,7 @@ abort(); UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; // buffer_occupancy = UE_template->ul_total_buffer; - while (((rb_table[rb_table_index]>(frame_parms->N_RB_UL-1-first_rb[CC_id])) || + while (((rb_table[rb_table_index]>(nb_rbs_allowed_slice[CC_id][slice_id]-1-first_rb[CC_id])) || (rb_table[rb_table_index]>45)) && (rb_table_index>0)) { rb_table_index--; @@ -1235,7 +1237,7 @@ abort(); UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=rb_table[rb_table_index]; UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_TBS=TBS; // buffer_occupancy -= TBS; - rballoc = mac_xface->computeRIV(frame_parms->N_RB_UL, + rballoc = mac_xface->computeRIV(nb_rbs_allowed_slice[CC_id][slice_id], first_rb[CC_id], rb_table[rb_table_index]); From 689eae92ee2f83d88f33d4f8393c8197f9e6fc63 Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Wed, 10 May 2017 13:11:09 +0200 Subject: [PATCH 018/284] Fix Bug dl scheduler --- openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index 81c18a26c0..0bde8c965b 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -284,7 +284,7 @@ void _assign_rbs_required (module_id_t Mod_id, nb_rbs_required[CC_id][UE_id] += min_rb_unit[CC_id]; if (nb_rbs_required[CC_id][UE_id] > nb_rbs_allowed_slice[CC_id][slice_id]) { - TBS = mac_xface->get_TBS_DL(flexran_get_ue_wcqi(Mod_id, UE_id), nb_rbs_allowed_slice[CC_id][slice_id]); + TBS = mac_xface->get_TBS_DL(cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)], nb_rbs_allowed_slice[CC_id][slice_id]); nb_rbs_required[CC_id][UE_id] = nb_rbs_allowed_slice[CC_id][slice_id]; break; } From 5de045b8027c6ac4f027bc8c6ad6f4ff2c8f7270 Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Thu, 18 May 2017 15:25:10 +0200 Subject: [PATCH 019/284] Uplink slices --- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 4 +- openair2/LAYER2/MAC/flexran_agent_mac_proto.h | 6 +- .../MAC/flexran_agent_scheduler_dlsch_ue.c | 14 +- .../MAC/flexran_agent_scheduler_ulsch_ue.c | 1052 ++--------------- 4 files changed, 141 insertions(+), 935 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index db9af62eac..f17fb9a1ba 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -1248,8 +1248,8 @@ int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->flexran_agent_send_sr_info = flexran_agent_send_sr_info; xface->flexran_agent_send_sf_trigger = flexran_agent_send_sf_trigger; //xface->flexran_agent_send_update_mac_stats = flexran_agent_send_update_mac_stats; - xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_default; - xface->flexran_agent_schedule_ul_spec = flexran_agent_schedule_ulsch_ue_spec; + xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_dl_spec_default; + xface->flexran_agent_schedule_ul_spec = flexran_schedule_ue_ul_spec_default; //xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_remote; xface->flexran_agent_get_pending_dl_mac_config = flexran_agent_get_pending_dl_mac_config; diff --git a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h index 186ccf1287..c2d28b33f7 100644 --- a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h +++ b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h @@ -51,7 +51,7 @@ typedef void (*slice_scheduler)(module_id_t mod_id, /* * top level flexran scheduler used by the eNB scheduler */ -void flexran_schedule_ue_spec_default(mid_t mod_id, +void flexran_schedule_ue_dl_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, @@ -102,7 +102,7 @@ flexran_schedule_ue_spec_be(mid_t mod_id, * common flexran scheduler function */ void -flexran_schedule_ue_spec_common(mid_t mod_id, +flexran_schedule_ue_dl_spec_common(mid_t mod_id, int slice_id, uint32_t frame, uint32_t subframe, @@ -182,7 +182,7 @@ void _dlsch_scheduler_pre_processor_allocate (module_id_t Mod_id, /* * Default scheduler used by the eNB agent */ -void flexran_schedule_ue_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, +void flexran_schedule_ue_dl_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, Protocol__FlexranMessage **dl_info); /* diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index aec093e88a..cfb14af641 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -709,12 +709,12 @@ void _dlsch_scheduler_pre_processor (module_id_t Mod_id, #define SF05_LIMIT 1 /* - * Main scheduling functions to support slicing + * Main Downlink Slicing * */ void -flexran_schedule_ue_spec_default(mid_t mod_id, +flexran_schedule_ue_dl_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, @@ -876,7 +876,7 @@ flexran_schedule_ue_spec_embb(mid_t mod_id, Protocol__FlexranMessage **dl_info) { - flexran_schedule_ue_spec_common(mod_id, + flexran_schedule_ue_dl_spec_common(mod_id, slice_id, frame, subframe, @@ -894,7 +894,7 @@ flexran_schedule_ue_spec_urllc(mid_t mod_id, Protocol__FlexranMessage **dl_info) { - flexran_schedule_ue_spec_common(mod_id, + flexran_schedule_ue_spec_dl_common(mod_id, slice_id, frame, subframe, @@ -913,7 +913,7 @@ flexran_schedule_ue_spec_mmtc(mid_t mod_id, { - flexran_schedule_ue_spec_common(mod_id, + flexran_schedule_ue_dl_spec_common(mod_id, slice_id, frame, subframe, @@ -932,7 +932,7 @@ flexran_schedule_ue_spec_be(mid_t mod_id, { - flexran_schedule_ue_spec_common(mod_id, + flexran_schedule_ue_dl_spec_common(mod_id, slice_id, frame, subframe, @@ -943,7 +943,7 @@ flexran_schedule_ue_spec_be(mid_t mod_id, //------------------------------------------------------------------------------ void -flexran_schedule_ue_spec_common(mid_t mod_id, +flexran_schedule_ue_dl_spec_common(mid_t mod_id, int slice_id, uint32_t frame, uint32_t subframe, diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index 333cc275c2..20e1c67366 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -67,488 +67,17 @@ float slice_percentage_current_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES]; +int update_ul_scheduler[MAX_NUM_SLICES] = {1, 1, 1, 1}; +int update_ul_scheduler_current[MAX_NUM_SLICES] = {1, 1, 1, 1}; + +// name of available scheduler +char *ul_scheduler_type[MAX_NUM_SLICES] = {"flexran_schedule_ue_ul_spec_embb"}; + + uint16_t flexran_nb_rbs_allowed_slice_uplink(float rb_percentage, int total_rbs){ return (uint16_t) floor(rb_percentage * total_rbs); } -// // This table holds the allowable PRB sizes for ULSCH transmissions -// uint8_t rb_table[33] = {1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36,40,45,48,50,54,60,72,75,80,81,90,96,100}; - -// void rx_sdu(const module_id_t enb_mod_idP, -// const int CC_idP, -// const frame_t frameP, -// const sub_frame_t subframeP, -// const rnti_t rntiP, -// uint8_t *sduP, -// const uint16_t sdu_lenP, -// const int harq_pidP, -// uint8_t *msg3_flagP) -// { - -// unsigned char rx_ces[MAX_NUM_CE],num_ce,num_sdu,i,*payload_ptr; -// unsigned char rx_lcids[NB_RB_MAX]; -// unsigned short rx_lengths[NB_RB_MAX]; -// int UE_id = find_UE_id(enb_mod_idP,rntiP); -// int ii,j; -// eNB_MAC_INST *eNB = &eNB_mac_inst[enb_mod_idP]; -// UE_list_t *UE_list= &eNB->UE_list; -// int crnti_rx=0; -// int old_buffer_info; - -// start_meas(&eNB->rx_ulsch_sdu); - -// if ((UE_id > NUMBER_OF_UE_MAX) || (UE_id == -1) ) -// for(ii=0; iiUE_sched_ctrl[UE_id].ul_scheduled &= (~(1<UE_sched_ctrl[UE_id].ul_inactivity_timer=0; -// UE_list->UE_sched_ctrl[UE_id].ul_failure_timer =0; -// UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= (~(1<UE_sched_ctrl[UE_id].ul_out_of_sync > 0) { -// UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync=0; -// mac_eNB_rrc_ul_in_sync(enb_mod_idP,CC_idP,frameP,subframeP,UE_RNTI(enb_mod_idP,UE_id)); -// } -// } - - -// payload_ptr = parse_ulsch_header(sduP,&num_ce,&num_sdu,rx_ces,rx_lcids,rx_lengths,sdu_lenP); - -// T(T_ENB_MAC_UE_UL_PDU, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(rntiP), T_INT(frameP), T_INT(subframeP), -// T_INT(harq_pidP), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu)); -// T(T_ENB_MAC_UE_UL_PDU_WITH_DATA, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(rntiP), T_INT(frameP), T_INT(subframeP), -// T_INT(harq_pidP), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu), T_BUFFER(sduP, sdu_lenP)); - -// eNB->eNB_stats[CC_idP].ulsch_bytes_rx=sdu_lenP; -// eNB->eNB_stats[CC_idP].total_ulsch_bytes_rx+=sdu_lenP; -// eNB->eNB_stats[CC_idP].total_ulsch_pdus_rx+=1; -// // control element -// for (i=0; iUE_template[CC_idP][UE_id].phr_info = (payload_ptr[0] & 0x3f) - PHR_MAPPING_OFFSET; -// LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : Received PHR PH = %d (db)\n", -// enb_mod_idP, CC_idP, rx_ces[i], UE_list->UE_template[CC_idP][UE_id].phr_info); -// UE_list->UE_template[CC_idP][UE_id].phr_info_configured=1; -// UE_list->UE_sched_ctrl[UE_id].phr_received = 1; -// } -// payload_ptr+=sizeof(POWER_HEADROOM_CMD); -// break; - -// case CRNTI: -// UE_id = find_UE_id(enb_mod_idP,(((uint16_t)payload_ptr[0])<<8) + payload_ptr[1]); -// LOG_I(MAC, "[eNB %d] Frame %d, Subframe %d CC_id %d MAC CE_LCID %d (ce %d/%d): CRNTI %x (UE_id %d) in Msg3\n", -// frameP,subframeP,enb_mod_idP, CC_idP, rx_ces[i], i,num_ce,(((uint16_t)payload_ptr[0])<<8) + payload_ptr[1],UE_id); -// if (UE_id!=-1) { -// UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer=0; -// UE_list->UE_sched_ctrl[UE_id].ul_failure_timer=0; -// if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) { -// UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync=0; -// mac_eNB_rrc_ul_in_sync(enb_mod_idP,CC_idP,frameP,subframeP,(((uint16_t)payload_ptr[0])<<8) + payload_ptr[1]); -// } -// } -// crnti_rx=1; -// payload_ptr+=2; - -// if (msg3_flagP != NULL) { -// *msg3_flagP = 0; -// } -// break; - -// case TRUNCATED_BSR: -// case SHORT_BSR: { -// uint8_t lcgid; -// lcgid = (payload_ptr[0] >> 6); - -// LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", -// enb_mod_idP, CC_idP, rx_ces[i], lcgid, payload_ptr[0] & 0x3f); - -// if (crnti_rx==1) -// LOG_I(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", -// enb_mod_idP, CC_idP, rx_ces[i], lcgid, payload_ptr[0] & 0x3f); -// if (UE_id != -1) { - -// UE_list->UE_template[CC_idP][UE_id].bsr_info[lcgid] = (payload_ptr[0] & 0x3f); - -// // update buffer info - -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[lcgid]]; - -// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]; - -// PHY_vars_eNB_g[enb_mod_idP][CC_idP]->pusch_stats_bsr[UE_id][(frameP*10)+subframeP] = (payload_ptr[0] & 0x3f); -// if (UE_id == UE_list->head) -// VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR,PHY_vars_eNB_g[enb_mod_idP][CC_idP]->pusch_stats_bsr[UE_id][(frameP*10)+subframeP]); -// if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[lcgid] == 0 ) { -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[lcgid]=frameP; -// } -// if (mac_eNB_get_rrc_status(enb_mod_idP,UE_RNTI(enb_mod_idP,UE_id)) < RRC_CONNECTED) -// LOG_I(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : ul_total_buffer = %d (lcg increment %d)\n", -// enb_mod_idP, CC_idP, rx_ces[i], UE_list->UE_template[CC_idP][UE_id].ul_total_buffer, -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]); -// } -// else { - -// } -// payload_ptr += 1;//sizeof(SHORT_BSR); // fixme -// } -// break; - -// case LONG_BSR: -// if (UE_id != -1) { -// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0] = ((payload_ptr[0] & 0xFC) >> 2); -// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1] = -// ((payload_ptr[0] & 0x03) << 4) | ((payload_ptr[1] & 0xF0) >> 4); -// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2] = -// ((payload_ptr[1] & 0x0F) << 2) | ((payload_ptr[2] & 0xC0) >> 6); -// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] = (payload_ptr[2] & 0x3F); - -// // update buffer info -// old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]; -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0]]; - -// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]; -// if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) -// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; -// else -// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; - -// old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]; -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1]]; -// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]; -// if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) -// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; -// else -// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; - -// old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]; -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2]]; -// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]; -// if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) -// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; -// else -// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; - -// old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]; -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3]]; -// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]; -// if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) -// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; -// else -// UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; - -// LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " -// "%u LCGID2 = %u LCGID3 = %u\n", -// enb_mod_idP, CC_idP, -// rx_ces[i], -// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0], -// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1], -// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2], -// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3]); -// if (crnti_rx==1) -// LOG_I(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " -// "%u LCGID2 = %u LCGID3 = %u\n", -// enb_mod_idP, CC_idP, -// rx_ces[i], -// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0], -// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1], -// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2], -// UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3]); - -// if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0] == 0 ) { -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID0]=0; -// } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID0] == 0) { -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID0]=frameP; -// } - -// if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1] == 0 ) { -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID1]=0; -// } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID1] == 0) { -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID1]=frameP; -// } - -// if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2] == 0 ) { -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID2]=0; -// } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID2] == 0) { -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID2]=frameP; -// } - -// if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] == 0 ) { -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID3]= 0; -// } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID3] == 0) { -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID3]=frameP; - -// } -// } - -// payload_ptr += 3;////sizeof(LONG_BSR); -// break; - -// default: -// LOG_E(MAC, "[eNB %d] CC_id %d Received unknown MAC header (0x%02x)\n", enb_mod_idP, CC_idP, rx_ces[i]); -// break; -// } -// } - -// for (i=0; i CCCH_PAYLOAD_SIZE_MAX) { -// LOG_E(MAC, "[eNB %d/%d] frame %d received CCCH of size %d (too big, maximum allowed is %d), dropping packet\n", -// enb_mod_idP, CC_idP, frameP, rx_lengths[i], CCCH_PAYLOAD_SIZE_MAX); -// break; -// } -// LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, Received CCCH: %x.%x.%x.%x.%x.%x, Terminating RA procedure for UE rnti %x\n", -// enb_mod_idP,CC_idP,frameP, -// payload_ptr[0],payload_ptr[1],payload_ptr[2],payload_ptr[3],payload_ptr[4], payload_ptr[5], rntiP); -// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC,1); -// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC,0); -// for (ii=0; iicommon_channels[CC_idP].RA_template[ii].rnti, rntiP, -// eNB->common_channels[CC_idP].RA_template[ii].RA_active); - -// if ((eNB->common_channels[CC_idP].RA_template[ii].rnti==rntiP) && -// (eNB->common_channels[CC_idP].RA_template[ii].RA_active==TRUE)) { - -// //payload_ptr = parse_ulsch_header(msg3,&num_ce,&num_sdu,rx_ces,rx_lcids,rx_lengths,msg3_len); - -// if (UE_id < 0) { -// memcpy(&eNB->common_channels[CC_idP].RA_template[ii].cont_res_id[0],payload_ptr,6); -// LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3: length %d, offset %ld\n", -// enb_mod_idP,CC_idP,frameP,rx_lengths[i],payload_ptr-sduP); - -// if ((UE_id=add_new_ue(enb_mod_idP,CC_idP,eNB->common_channels[CC_idP].RA_template[ii].rnti,harq_pidP)) == -1 ) { -// mac_xface->macphy_exit("[MAC][eNB] Max user count reached\n"); -// // kill RA procedure -// } else -// LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d Added user with rnti %x => UE %d\n", -// enb_mod_idP,CC_idP,frameP,eNB->common_channels[CC_idP].RA_template[ii].rnti,UE_id); -// } else { -// LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3 from already registered UE %d: length %d, offset %ld\n", -// enb_mod_idP,CC_idP,frameP,UE_id,rx_lengths[i],payload_ptr-sduP); -// // kill RA procedure -// } - -// if (Is_rrc_registered == 1) -// mac_rrc_data_ind( -// enb_mod_idP, -// CC_idP, -// frameP,subframeP, -// rntiP, -// CCCH, -// (uint8_t*)payload_ptr, -// rx_lengths[i], -// ENB_FLAG_YES, -// enb_mod_idP, -// 0); - - -// if (num_ce >0) { // handle msg3 which is not RRCConnectionRequest -// // process_ra_message(msg3,num_ce,rx_lcids,rx_ces); -// } - -// eNB->common_channels[CC_idP].RA_template[ii].generate_Msg4 = 1; -// eNB->common_channels[CC_idP].RA_template[ii].wait_ack_Msg4 = 0; - -// } // if process is active -// } // loop on RA processes - -// break ; - -// case DCCH : -// case DCCH1 : -// // if(eNB_mac_inst[module_idP][CC_idP].Dcch_lchan[UE_id].Active==1){ - - -// #if defined(ENABLE_MAC_PAYLOAD_DEBUG) -// LOG_T(MAC,"offset: %d\n",(unsigned char)((unsigned char*)payload_ptr-sduP)); -// for (j=0; j<32; j++) { -// LOG_T(MAC,"%x ",payload_ptr[j]); -// } -// LOG_T(MAC,"\n"); -// #endif - -// if (UE_id != -1) { -// // adjust buffer occupancy of the correponding logical channel group -// if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] >= rx_lengths[i]) -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] -= rx_lengths[i]; -// else -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] = 0; - -// LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DCCH, received %d bytes form UE %d on LCID %d \n", -// enb_mod_idP,CC_idP,frameP, rx_lengths[i], UE_id, rx_lcids[i]); - -// mac_rlc_data_ind( -// enb_mod_idP, -// rntiP, -// enb_mod_idP, -// frameP, -// ENB_FLAG_YES, -// MBMS_FLAG_NO, -// rx_lcids[i], -// (char *)payload_ptr, -// rx_lengths[i], -// 1, -// NULL);//(unsigned int*)crc_status); -// UE_list->eNB_UE_stats[CC_idP][UE_id].num_pdu_rx[rx_lcids[i]]+=1; -// UE_list->eNB_UE_stats[CC_idP][UE_id].num_bytes_rx[rx_lcids[i]]+=rx_lengths[i]; -// } /* UE_id != -1 */ - -// // } -// break; - -// // all the DRBS -// case DTCH: -// default : - -// #if defined(ENABLE_MAC_PAYLOAD_DEBUG) -// LOG_T(MAC,"offset: %d\n",(unsigned char)((unsigned char*)payload_ptr-sduP)); -// for (j=0; j<32; j++) { -// LOG_T(MAC,"%x ",payload_ptr[j]); -// } -// LOG_T(MAC,"\n"); -// #endif -// if (rx_lcids[i] < NB_RB_MAX ) { -// LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d\n", -// enb_mod_idP,CC_idP,frameP, rx_lengths[i], UE_id, rx_lcids[i]); - -// if (UE_id != -1) { -// // adjust buffer occupancy of the correponding logical channel group -// LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d, removing from LCGID %ld, %d\n", -// enb_mod_idP,CC_idP,frameP, rx_lengths[i], UE_id,rx_lcids[i], -// UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]], -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]]); - -// if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] >= rx_lengths[i]) -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] -= rx_lengths[i]; -// else -// UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] = 0; -// if ((rx_lengths[i] 0) ) { // MAX SIZE OF transport block -// mac_rlc_data_ind( -// enb_mod_idP, -// rntiP, -// enb_mod_idP, -// frameP, -// ENB_FLAG_YES, -// MBMS_FLAG_NO, -// rx_lcids[i], -// (char *)payload_ptr, -// rx_lengths[i], -// 1, -// NULL);//(unsigned int*)crc_status); - -// UE_list->eNB_UE_stats[CC_idP][UE_id].num_pdu_rx[rx_lcids[i]]+=1; -// UE_list->eNB_UE_stats[CC_idP][UE_id].num_bytes_rx[rx_lcids[i]]+=rx_lengths[i]; -// } -// else { /* rx_length[i] */ -// UE_list->eNB_UE_stats[CC_idP][UE_id].num_errors_rx+=1; -// LOG_E(MAC,"[eNB %d] CC_id %d Frame %d : Max size of transport block reached LCID %d from UE %d ", -// enb_mod_idP, CC_idP, frameP, rx_lcids[i], UE_id); -// } -// } -// else {/*(UE_id != -1*/ -// LOG_E(MAC,"[eNB %d] CC_id %d Frame %d : received unsupported or unknown LCID %d from UE %d ", -// enb_mod_idP, CC_idP, frameP, rx_lcids[i], UE_id); -// } -// } - -// break; -// } - -// payload_ptr+=rx_lengths[i]; -// } - -// /* NN--> FK: we could either check the payload, or use a phy helper to detect a false msg3 */ -// if ((num_sdu == 0) && (num_ce==0)) { -// if (UE_id != -1) -// UE_list->eNB_UE_stats[CC_idP][UE_id].total_num_errors_rx+=1; - -// if (msg3_flagP != NULL) { -// if( *msg3_flagP == 1 ) { -// LOG_N(MAC,"[eNB %d] CC_id %d frame %d : false msg3 detection: signal phy to canceling RA and remove the UE\n", enb_mod_idP, CC_idP, frameP); -// *msg3_flagP=0; -// } -// } -// } else { -// if (UE_id != -1) { -// UE_list->eNB_UE_stats[CC_idP][UE_id].pdu_bytes_rx=sdu_lenP; -// UE_list->eNB_UE_stats[CC_idP][UE_id].total_pdu_bytes_rx+=sdu_lenP; -// UE_list->eNB_UE_stats[CC_idP][UE_id].total_num_pdus_rx+=1; -// } -// } - -// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_SDU,0); -// stop_meas(&eNB->rx_ulsch_sdu); -// } - - - -// void _sort_ue_ul (module_id_t module_idP,int frameP, sub_frame_t subframeP) -// { -// int i; -// int list[NUMBER_OF_UE_MAX]; -// int list_size = 0; -// int rnti; -// struct sort_ue_ul_params params = { module_idP, frameP, subframeP }; - -// UE_list_t *UE_list = &eNB_mac_inst[module_idP].UE_list; - -// for (i = 0; i < NUMBER_OF_UE_MAX; i++) { -// rnti = UE_RNTI(module_idP, i); -// if (rnti == NOT_A_RNTI) -// continue; -// if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) -// continue; -// if (!phy_stats_exist(module_idP, rnti)) -// continue; -// list[list_size] = i; -// list_size++; -// } - -// qsort_r(list, list_size, sizeof(int), ue_ul_compare, ¶ms); - -// if (list_size) { -// for (i = 0; i < list_size-1; i++) -// UE_list->next_ul[list[i]] = list[i+1]; -// UE_list->next_ul[list[list_size-1]] = -1; -// UE_list->head_ul = list[0]; -// } else { -// UE_list->head_ul = -1; -// } - -// } - - void _assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, sub_frame_t subframeP, uint16_t *first_rb) { @@ -565,7 +94,7 @@ void _assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, su UE_TEMPLATE *UE_template; LTE_DL_FRAME_PARMS *frame_parms; - + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { if (UE_list->active[i] != TRUE) continue; @@ -606,7 +135,7 @@ void _assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, su UE_list->numactiveULCCs[UE_id]); frame_parms=mac_xface->get_lte_frame_parms(module_idP,CC_id); UE_template = &UE_list->UE_template[CC_id][UE_id]; - + nb_rbs_allowed_slice[CC_id][UE_id] = flexran_nb_rbs_allowed_slice_uplink(slice_percentage_uplink[UE_id], flexran_get_N_RB_UL(module_idP, CC_id)); // if this UE has UL traffic if (UE_template->ul_total_buffer > 0 ) { @@ -623,7 +152,7 @@ void _assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, su } while ((tbs < UE_template->ul_total_buffer) && - (rb_table[rb_table_index]<(nb_rbs_allowed_slice[CC_id][slice_id]-first_rb[CC_id])) && + (rb_table[rb_table_index]<(nb_rbs_allowed_slice[CC_id][UE_id]-first_rb[CC_id])) && ((UE_template->phr_info - tx_power) > 0) && (rb_table_index < 32 )) { // LOG_I(MAC,"tbs %d ul buffer %d rb table %d max ul rb %d\n", tbs, UE_template->ul_total_buffer, rb_table[rb_table_index], frame_parms->N_RB_UL-first_rb[CC_id]); @@ -634,7 +163,7 @@ void _assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, su UE_template->ue_tx_power = tx_power; - if (rb_table[rb_table_index]>(nb_rbs_allowed_slice[CC_id][slice_id]-first_rb[CC_id]-1)) { + if (rb_table[rb_table_index]>(nb_rbs_allowed_slice[CC_id][UE_id]-first_rb[CC_id]-1)) { rb_table_index--; } @@ -674,13 +203,14 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, uint16_t UE_id,n,r; uint8_t CC_id, round, harq_pid; uint16_t nb_allocated_rbs[MAX_NUM_CCs][NUMBER_OF_UE_MAX],total_allocated_rbs[MAX_NUM_CCs],average_rbs_per_user[MAX_NUM_CCs]; + uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES]; int16_t total_remaining_rbs[MAX_NUM_CCs]; uint16_t max_num_ue_to_be_scheduled=0,total_ue_count=0; rnti_t rnti= -1; UE_list_t *UE_list = &eNB_mac_inst[module_idP].UE_list; UE_TEMPLATE *UE_template = 0; LTE_DL_FRAME_PARMS *frame_parms = 0; - + UE_sched_ctrl *ue_sched_ctl; //LOG_I(MAC,"assign max mcs min rb\n"); @@ -742,15 +272,15 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, max_num_ue_to_be_scheduled+=1; - nb_rbs_allowed_slice[CC_id][slice_id] = flexran_nb_rbs_allowed_slice_uplink(slice_percentage_uplink[slice_id], flexran_get_N_RB_UL(module_idP, CC_id)); + nb_rbs_allowed_slice[CC_id][UE_id] = flexran_nb_rbs_allowed_slice_uplink(slice_percentage_uplink[UE_id], flexran_get_N_RB_UL(module_idP, CC_id)); if (total_ue_count == 0) { average_rbs_per_user[CC_id] = 0; } else if (total_ue_count == 1 ) { // increase the available RBs, special case, - average_rbs_per_user[CC_id] = nb_rbs_allowed_slice[CC_id][slice_id]-first_rb[CC_id]+1; - } else if( (total_ue_count <= (nb_rbs_allowed_slice[CC_id][slice_id]-first_rb[CC_id])) && + average_rbs_per_user[CC_id] = nb_rbs_allowed_slice[CC_id][i]-first_rb[CC_id]+1; + } else if( (total_ue_count <= (nb_rbs_allowed_slice[CC_id][i]-first_rb[CC_id])) && (total_ue_count <= max_num_ue_to_be_scheduled)) { - average_rbs_per_user[CC_id] = (uint16_t) floor((nb_rbs_allowed_slice[CC_id][slice_id]-first_rb[CC_id])/total_ue_count); + average_rbs_per_user[CC_id] = (uint16_t) floor((nb_rbs_allowed_slice[CC_id][i]-first_rb[CC_id])/total_ue_count); } else if (max_num_ue_to_be_scheduled > 0 ) { average_rbs_per_user[CC_id] = (uint16_t) floor((nb_rbs_allowed_slice[CC_id][slice_id]-first_rb[CC_id])/max_num_ue_to_be_scheduled); } else { @@ -782,7 +312,8 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, for (n=0; nnumactiveULCCs[UE_id]; n++) { // This is the actual CC_id in the list CC_id = UE_list->ordered_ULCCids[n][UE_id]; - + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + ue_sched_ctl->max_allowed_rbs[CC_id]=nb_rbs_allowed_slice[CC_id][UE_id]; // mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL); flexran_get_harq(module_idP, CC_id, UE_id, frameP, subframeP, &harq_pid, &round, openair_harq_UL); if(round>0) { @@ -814,9 +345,9 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, for (n=0; nnumactiveULCCs[UE_id]; n++) { // This is the actual CC_id in the list CC_id = UE_list->ordered_ULCCids[n][UE_id]; - UE_template = &UE_list->UE_template[CC_id][UE_id]; + UE_template = &UE_list->UE_template[CC_id][UE_id]; frame_parms = mac_xface->get_lte_frame_parms(module_idP,CC_id); - total_remaining_rbs[CC_id]=nb_rbs_allowed_slice[CC_id][slice_id] - first_rb[CC_id] - total_allocated_rbs[CC_id]; + total_remaining_rbs[CC_id]=nb_rbs_allowed_slice[CC_id][UE_id] - first_rb[CC_id] - total_allocated_rbs[CC_id]; if (total_ue_count == 1 ) { total_remaining_rbs[CC_id]+=1; @@ -848,110 +379,114 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, } } +/* + * Main Uplink Slicing + * + */ + +void +flexran_schedule_ue_ul_spec_default(mid_t mod_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage **dl_info) +//------------------------------------------------------------------------------ +{ + int i=0; + + flexran_agent_mac_create_empty_ul_config(module_idP, ul_info); + + for (i = 0; i < n_active_slices; i++) { + + // Load any updated functions + if (update_dl_scheduler[i] > 0 ) { + slice_sched[i] = dlsym(NULL, dl_scheduler_type[i]); + update_dl_scheduler[i] = 0; + update_dl_scheduler_current[i] = 0; + slice_percentage_current[i]= slice_percentage[i]; + total_slice_percentage+=slice_percentage[i]; + LOG_N(MAC,"update dl scheduler slice %d\n", i); + } + + // check if the number of slices has changed, and log + if (n_active_slices_current != n_active_slices ){ + if ((n_active_slices > 0) && (n_active_slices <= MAX_NUM_SLICES)) { + LOG_N(MAC,"[eNB %d]frame %d subframe %d: number of active slices has changed: %d-->%d\n", + mod_id, frame, subframe, n_active_slices_current, n_active_slices); + + n_active_slices_current = n_active_slices; + + } else { + LOG_W(MAC,"invalid number of slices %d, revert to the previous value %d\n",n_active_slices, n_active_slices_current); + n_active_slices = n_active_slices_current; + } + } + + // check if the slice rb share has changed, and log the console + if (slice_percentage_current[i] != slice_percentage[i]){ + if ((slice_percentage[i] >= 0.0) && (slice_percentage[i] <= 1.0)){ + if ((total_slice_percentage - slice_percentage_current[i] + slice_percentage[i]) <= 1.0) { + total_slice_percentage=total_slice_percentage - slice_percentage_current[i] + slice_percentage[i]; + LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: total percentage %f, slice RB percentage has changed: %f-->%f\n", + mod_id, i, frame, subframe, total_slice_percentage, slice_percentage_current[i], slice_percentage[i]); + + slice_percentage_current[i] = slice_percentage[i]; + + } else { + LOG_W(MAC,"[eNB %d][SLICE %d] invalid total RB share (%f->%f), revert the previous value (%f->%f)\n", + mod_id,i, + total_slice_percentage, + total_slice_percentage - slice_percentage_current[i] + slice_percentage[i], + slice_percentage[i],slice_percentage_current[i]); + + slice_percentage[i]= slice_percentage_current[i]; + + } + } else { + LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice RB share, revert the previous value (%f->%f)\n",mod_id, i, slice_percentage[i],slice_percentage_current[i]); + + slice_percentage[i]= slice_percentage_current[i]; + + } + } + + // check if a new scheduler, and log the console + if (update_dl_scheduler_current[i] != update_dl_scheduler[i]){ + LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: DL scheduler for this slice is updated: %s \n", + mod_id, i, frame, subframe, dl_scheduler_type[i]); + + update_dl_scheduler_current[i] = update_dl_scheduler[i]; + + } + + // Run each enabled slice-specific schedulers one by one + //LOG_N(MAC,"[eNB %d]frame %d subframe %d slice %d: calling the scheduler\n", mod_id, frame, subframe,i); + slice_sched[i](mod_id, i, frame, subframe, mbsfn_flag,dl_info); + + } + +} + +void +flexran_schedule_ue_ul_spec_embb(mid_t mod_id, + frame_t frameP, + unsigned char cooperation_flag, + uint32_t subframe, + unsigned char sched_subframe, + Protocol__FlexranMessage **ul_info) + +{ + flexran_agent_schedule_ulsch_ue_spec(mod_id, + frame, + cooperation_flag, + subframe, + sched_subframe, + ul_info); + +} -// uint32_t bytes_to_bsr_index(int32_t nbytes) -// { - -// uint32_t i=0; - -// if (nbytes<0) { -// return(0); -// } - -// while ((iE == 0) { -// not_done = 0; -// } - -// lcid = ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID; - -// if (lcid < EXTENDED_POWER_HEADROOM) { -// if (not_done==0) { // last MAC SDU, length is implicit -// mac_header_ptr++; -// length = tb_length-(mac_header_ptr-mac_header)-ce_len; - -// for (num_sdu_cnt=0; num_sdu_cnt < num_sdus ; num_sdu_cnt++) { -// length -= rx_lengths[num_sdu_cnt]; -// } -// } else { -// if (((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F == 0) { -// length = ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L; -// mac_header_ptr += 2;//sizeof(SCH_SUBHEADER_SHORT); -// } else { // F = 1 -// length = ((((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_MSB & 0x7f ) << 8 ) | (((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB & 0xff); -// mac_header_ptr += 3;//sizeof(SCH_SUBHEADER_LONG); -// } -// } - -// LOG_D(MAC,"[eNB] sdu %d lcid %d tb_length %d length %d (offset now %ld)\n", -// num_sdus,lcid,tb_length, length,mac_header_ptr-mac_header); -// rx_lcids[num_sdus] = lcid; -// rx_lengths[num_sdus] = length; -// num_sdus++; -// } else { // This is a control element subheader POWER_HEADROOM, BSR and CRNTI -// if (lcid == SHORT_PADDING) { -// mac_header_ptr++; -// } else { -// rx_ces[num_ces] = lcid; -// num_ces++; -// mac_header_ptr++; - -// if (lcid==LONG_BSR) { -// ce_len+=3; -// } else if (lcid==CRNTI) { -// ce_len+=2; -// } else if ((lcid==POWER_HEADROOM) || (lcid==TRUNCATED_BSR)|| (lcid== SHORT_BSR)) { -// ce_len++; -// } else { -// LOG_E(MAC,"unknown CE %d \n", lcid); -// mac_xface->macphy_exit("unknown CE"); -// } -// } -// } -// } - -// *num_ce = num_ces; -// *num_sdu = num_sdus; - -// return(mac_header_ptr); -// } - - -void flexran_agent_schedule_ulsch_ue_spec(module_id_t module_idP, +void flexran_agent_schedule_ulsch_ue_spec(mid_t module_idP, frame_t frameP, unsigned char cooperation_flag, sub_frame_t subframeP, @@ -959,8 +494,6 @@ void flexran_agent_schedule_ulsch_ue_spec(module_id_t module_idP, Protocol__FlexranMessage **ul_info) { -flexran_agent_mac_create_empty_ul_config(module_idP, ul_info); - uint16_t first_rb[MAX_NUM_CCs],i; int CC_id; eNB_MAC_INST *eNB=&eNB_mac_inst[module_idP]; @@ -1007,11 +540,6 @@ flexran_agent_mac_create_empty_ul_config(module_idP, ul_info); flexran_agent_schedule_ulsch_rnti(module_idP, cooperation_flag, frameP, subframeP, sched_subframe,first_rb); -// #ifdef CBA - // schedule_ulsch_cba_rnti(module_idP, cooperation_flag, frameP, subframeP, sched_subframe, first_rb); -// #endif - - stop_meas(&eNB->schedule_ulsch); } @@ -1227,7 +755,7 @@ abort(); UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; // buffer_occupancy = UE_template->ul_total_buffer; - while (((rb_table[rb_table_index]>(nb_rbs_allowed_slice[CC_id][slice_id]-1-first_rb[CC_id])) || + while (((rb_table[rb_table_index]>(nb_rbs_allowed_slice[CC_id][UE_id]-1-first_rb[CC_id])) || (rb_table[rb_table_index]>45)) && (rb_table_index>0)) { rb_table_index--; @@ -1237,7 +765,7 @@ abort(); UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=rb_table[rb_table_index]; UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_TBS=TBS; // buffer_occupancy -= TBS; - rballoc = mac_xface->computeRIV(nb_rbs_allowed_slice[CC_id][slice_id], + rballoc = mac_xface->computeRIV(frame_parms->N_RB_UL, first_rb[CC_id], rb_table[rb_table_index]); @@ -1527,325 +1055,3 @@ abort(); } // loop of CC_id } -// #ifdef CBA -// void schedule_ulsch_cba_rnti(module_id_t module_idP, unsigned char cooperation_flag, frame_t frameP, sub_frame_t subframeP, unsigned char sched_subframe, uint16_t *first_rb) -// { - -// eNB_MAC_INST *eNB = &eNB_mac_inst[module_idP]; -// UE_list_t *UE_list=&eNB->UE_list; -// //UE_TEMPLATE *UE_template; -// void *ULSCH_dci = NULL; -// DCI_PDU *DCI_pdu; -// uint8_t CC_id=0; -// uint8_t rb_table_index=0, aggregation=2; -// uint32_t rballoc; -// uint8_t cba_group, cba_resources; -// uint8_t required_rbs[NUM_MAX_CBA_GROUP]; -// int8_t num_cba_resources[NUM_MAX_CBA_GROUP];// , weight[NUM_MAX_CBA_GROUP] -// // the following vars should become a vector [MAX_NUM_CCs] -// LTE_DL_FRAME_PARMS *frame_parms; -// int8_t available_rbs=0; -// uint8_t remaining_rbs=0; -// uint8_t allocated_rbs=0; -// uint8_t total_UEs=UE_list->num_UEs; -// uint8_t active_UEs[NUM_MAX_CBA_GROUP]; -// uint8_t total_groups=eNB_mac_inst[module_idP].common_channels[CC_id].num_active_cba_groups; -// int min_rb_unit=2; -// uint8_t cba_policy=CBA_ES; -// int UE_id; -// uint8_t mcs[NUM_MAX_CBA_GROUP]; -// uint32_t total_cba_resources=0; -// uint32_t total_rbs=0; -// // We compute the weight of each group and initialize some variables - -// // loop over all active UEs -// // for (UE_id=UE_list->head_ul;UE_id>=0;UE_id=UE_list->next_ul[UE_id]) { - -// for (cba_group=0; cba_groupget_lte_frame_parms(module_idP,CC_id); -// available_rbs=frame_parms->N_RB_DL-1-first_rb[CC_id]; -// remaining_rbs=available_rbs; -// total_groups=eNB_mac_inst[module_idP].common_channels[CC_id].num_active_cba_groups; -// min_rb_unit=get_min_rb_unit(module_idP,CC_id); - -// if (available_rbs < min_rb_unit ) -// continue; - -// // remove this condition later -// // cba group template uses the exisitng UE template, and thus if a UE -// // is scheduled, the correspodning group can't be used for CBA -// // this can be fixed later -// if (total_groups > 0) { -// DCI_pdu = &eNB_mac_inst[module_idP].common_channels[CC_id].DCI_pdu; - -// for (cba_group=0; -// (cba_group (1<head_ul; UE_id>=0; UE_id=UE_list->next_ul[UE_id]) { -// if (UE_RNTI(module_idP,UE_id)==NOT_A_RNTI) -// continue; - -// // simple UE identity based grouping -// if ((UE_id % total_groups) == cba_group) { // this could be simplifed to active_UEs[UE_id % total_groups]++; -// if ((mac_eNB_get_rrc_status(module_idP,rnti) > RRC_CONNECTED) && -// (UE_is_to_be_scheduled(module_idP,CC_id,UE_id) == 0)) { -// active_UEs[cba_group]++; -// } -// } - -// if (UE_list->UE_template[CC_id][UE_id].pre_assigned_mcs_ul <= 2) { -// mcs[cba_group]= 8; // apply fixed scheduling -// } else if ((UE_id % total_groups) == cba_group) { -// mcs[cba_group]= cmin(mcs[cba_group],UE_list->UE_template[CC_id][UE_id].pre_assigned_mcs_ul); -// } -// } - -// mcs[cba_group]= mcs[cba_group];//cmin(mcs[cba_group],openair_daq_vars.target_ue_ul_mcs); - -// if (available_rbs < min_rb_unit ) -// break; - -// // If the group needs some resource -// // determine the total number of allocations (one or multiple DCIs): to be refined -// if ((active_UEs[cba_group] > 0) && (eNB_mac_inst[module_idP].common_channels[CC_id].cba_rnti[cba_group] != 0)) { -// // to be refined in case of : total_UEs >> weight[cba_group]*available_rbs - -// switch(cba_policy) { -// case CBA_ES: -// required_rbs[cba_group] = (uint8_t)floor(available_rbs/total_groups); // allocate equally among groups -// num_cba_resources[cba_group]=1; -// break; - -// // can't have more than one allocation for the same group/UE -// /* case CBA_ES_S: -// required_rbs[cba_group] = (uint8_t)floor(available_rbs/total_groups); // allocate equally among groups -// if (required_rbs[cba_group] > min_rb_unit) -// num_cba_resources[cba_group]=(uint8_t)(required_rbs[cba_group]/ min_rb_unit); -// break;*/ -// case CBA_PF: -// required_rbs[cba_group] = (uint8_t)floor((active_UEs[cba_group]*available_rbs)/total_UEs); -// num_cba_resources[cba_group]=1; -// break; -// /* case CBA_PF_S: -// required_rbs[cba_group] = (uint8_t)ceil((active_UEs[cba_group]*available_rbs)/total_UEs); -// if (required_rbs[cba_group] > min_rb_unit) -// num_cba_resources[cba_group]=(uint8_t) floor(required_rbs[cba_group] / min_rb_unit); -// break;*/ - -// default: -// LOG_W(MAC,"unknown CBA policy\n"); -// break; -// } - -// total_cba_resources+=num_cba_resources[cba_group]; -// total_rbs+=required_rbs[cba_group]; - -// /* while ((remaining_rbs < required_rbs[cba_group]) && -// (required_rbs[cba_group] > 0) && -// (required_rbs[cba_group] < min_rb_unit )) -// required_rbs[cba_group]--; -// */ - -// /* -// while (rb_table[rb_table_index] < required_rbs[cba_group]) -// rb_table_index++; - -// while (rb_table[rb_table_index] > remaining_rbs ) -// rb_table_index--; - -// remaining_rbs-=rb_table[rb_table_index]; -// required_rbs[cba_group]=rb_table[rb_table_index]; -// */ -// // num_cba_resources[cba_group]=1; - -// } -// } - -// // phase 2 reduce the number of cba allocations among the groups -// cba_group=0; - -// if (total_cba_resources <= 0) { -// return; -// } - -// // increase rb if any left: to be done -// cba_group=0; - -// while (total_rbs < available_rbs - 1 ) { -// required_rbs[cba_group%total_groups]++; -// total_rbs++; -// cba_group++; -// } - -// // phase 3: -// for (cba_group=0; cba_group remaining_rbs ) { -// rb_table_index--; -// } - -// remaining_rbs-=rb_table[rb_table_index]; -// allocated_rbs=rb_table[rb_table_index]; - -// rballoc = mac_xface->computeRIV(mac_xface->lte_frame_parms->N_RB_UL, -// first_rb[CC_id], -// rb_table[rb_table_index]); - -// first_rb[CC_id]+=rb_table[rb_table_index]; -// LOG_N(MAC, -// "[eNB %d] CC_id %d Frame %d, subframeP %d: schedule CBA access %d rnti %x, total/required/allocated/remaining rbs (%d/%d/%d/%d), mcs %d, rballoc %d\n", -// module_idP, CC_id, frameP, subframeP, cba_group,eNB_mac_inst[module_idP].common_channels[CC_id].cba_rnti[cba_group], -// available_rbs, required_rbs[cba_group], allocated_rbs, remaining_rbs, -// mcs[cba_group],rballoc); - -// switch (frame_parms->N_RB_UL) { -// case 6: -// mac_xface->macphy_exit("[MAC][eNB] CBA RB=6 not supported \n"); -// break; - -// case 25: -// if (frame_parms->frame_type == TDD) { -// ULSCH_dci = UE_list->UE_template[CC_id][cba_group].ULSCH_DCI[0]; - -// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->type = 0; -// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->hopping = 0; -// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->rballoc = rballoc; -// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->mcs = mcs[cba_group]; -// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->ndi = 1; -// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->TPC = 1;//tpc; -// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->cshift = cba_group; -// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->dai = UE_list->UE_template[CC_id][cba_group].DAI_ul[sched_subframe]; -// ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->cqi_req = 1; - -// //add_ue_spec_dci -// add_common_dci(DCI_pdu, -// ULSCH_dci, -// eNB_mac_inst[module_idP].common_channels[CC_id].cba_rnti[cba_group], -// sizeof(DCI0_5MHz_TDD_1_6_t), -// aggregation, -// sizeof_DCI0_5MHz_TDD_1_6_t, -// format0, -// 0); -// } else { -// ULSCH_dci = UE_list->UE_template[CC_id][cba_group].ULSCH_DCI[0]; - -// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->type = 0; -// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->hopping = 0; -// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->rballoc = rballoc; -// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->mcs = mcs[cba_group]; -// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->ndi = 1; -// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->TPC = 1;//tpc; -// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->cshift = cba_group; -// ((DCI0_5MHz_FDD_t *)ULSCH_dci)->cqi_req = 1; - -// //add_ue_spec_dci -// add_common_dci(DCI_pdu, -// ULSCH_dci, -// eNB_mac_inst[module_idP].common_channels[CC_id].cba_rnti[cba_group], -// sizeof(DCI0_5MHz_FDD_t), -// aggregation, -// sizeof_DCI0_5MHz_FDD_t, -// format0, -// 0); -// } - -// LOG_D(MAC,"[eNB %d] CC_id %d Frame %d, subframeP %d: Generated ULSCH DCI for CBA group %d, RB 25 format 0\n", module_idP,CC_id,frameP,subframeP,cba_group); -// break; - -// case 50: -// if (frame_parms->frame_type == TDD) { -// ULSCH_dci = UE_list->UE_template[CC_id][cba_group].ULSCH_DCI[0]; - -// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->type = 0; -// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->hopping = 0; -// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->rballoc = rballoc; -// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->mcs = mcs[cba_group]; -// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->ndi = 1; -// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->TPC = 1;//tpc; -// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->cshift = cba_group; -// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->dai = UE_list->UE_template[CC_id][cba_group].DAI_ul[sched_subframe]; -// ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->cqi_req = 1; - -// //add_ue_spec_dci -// add_common_dci(DCI_pdu, -// ULSCH_dci, -// eNB_mac_inst[module_idP].common_channels[CC_id].cba_rnti[cba_group], -// sizeof(DCI0_10MHz_TDD_1_6_t), -// aggregation, -// sizeof_DCI0_10MHz_TDD_1_6_t, -// format0, -// 0); -// } else { -// ULSCH_dci = UE_list->UE_template[CC_id][cba_group].ULSCH_DCI[0]; - -// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->type = 0; -// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->hopping = 0; -// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->rballoc = rballoc; -// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->mcs = mcs[cba_group]; -// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->ndi = 1; -// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->TPC = 1;//tpc; -// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->cshift = cba_group; -// ((DCI0_10MHz_FDD_t *)ULSCH_dci)->cqi_req = 1; - -// //add_ue_spec_dci -// add_common_dci(DCI_pdu, -// ULSCH_dci, -// eNB_mac_inst[module_idP].common_channels[CC_id].cba_rnti[cba_group], -// sizeof(DCI0_10MHz_FDD_t), -// aggregation, -// sizeof_DCI0_10MHz_FDD_t, -// format0, -// 0); -// } - -// LOG_D(MAC,"[eNB %d] CC_id %d Frame %d, subframeP %d: Generated ULSCH DCI for CBA group %d, RB 50 format 0\n", module_idP,CC_id,frameP,subframeP,cba_group); -// break; - -// case 100: -// mac_xface->macphy_exit("[MAC][eNB] CBA RB=100 not supported \n"); -// break; - -// default: -// break; -// } - -// // break;// for the moment only schedule one -// } -// } -// } -// } -// } -// #endif From 5c7377e1c090bd0e51cf53efde597e98f2c1008c Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Thu, 18 May 2017 17:21:07 +0200 Subject: [PATCH 020/284] Fix bug header --- openair2/LAYER2/MAC/flexran_agent_mac_proto.h | 17 +++- .../MAC/flexran_agent_scheduler_dlsch_ue.c | 12 +-- .../MAC/flexran_agent_scheduler_ulsch_ue.c | 88 +++++++++++-------- 3 files changed, 71 insertions(+), 46 deletions(-) diff --git a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h index c2d28b33f7..5fc53fece6 100644 --- a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h +++ b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h @@ -39,13 +39,19 @@ /* * slice specific scheduler */ -typedef void (*slice_scheduler)(module_id_t mod_id, +typedef void (*slice_scheduler_dl)(module_id_t mod_id, int slice_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, Protocol__FlexranMessage **dl_info); +typedef void (*slice_scheduler_ul)(module_id_t mod_id, + frame_t frame, + unsigned char cooperation_flag, + uint32_t subframe, + unsigned char sched_subframe, + Protocol__FlexranMessage **ul_info); /* @@ -109,6 +115,15 @@ flexran_schedule_ue_dl_spec_common(mid_t mod_id, int *mbsfn_flag, Protocol__FlexranMessage **dl_info); +void +flexran_schedule_ue_ul_spec_default(mid_t mod_id, + uint32_t frame, + uint32_t cooperation_flag, + int subframe, + unsigned char sched_subframe, + Protocol__FlexranMessage **ul_info); + + uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, int total_rbs); diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index cfb14af641..b30cb5f491 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -88,8 +88,8 @@ typedef enum { // number of active slices for past and current time -int n_active_slices = 1; -int n_active_slices_current = 1; +static int n_active_slices = 1; +static int n_active_slices_current = 1; // ue to slice mapping int slicing_strategy = UEID_TO_SLICEID; @@ -115,7 +115,7 @@ char *dl_scheduler_type[MAX_NUM_SLICES] = {"flexran_schedule_ue_spec_embb", }; // pointer to the slice specific scheduler -slice_scheduler slice_sched[MAX_NUM_SLICES] = {0}; +slice_scheduler_dl slice_sched_dl[MAX_NUM_SLICES] = {0}; /** @@ -729,7 +729,7 @@ flexran_schedule_ue_dl_spec_default(mid_t mod_id, // Load any updated functions if (update_dl_scheduler[i] > 0 ) { - slice_sched[i] = dlsym(NULL, dl_scheduler_type[i]); + slice_sched_dl[i] = dlsym(NULL, dl_scheduler_type[i]); update_dl_scheduler[i] = 0; update_dl_scheduler_current[i] = 0; slice_percentage_current[i]= slice_percentage[i]; @@ -806,7 +806,7 @@ flexran_schedule_ue_dl_spec_default(mid_t mod_id, // Run each enabled slice-specific schedulers one by one //LOG_N(MAC,"[eNB %d]frame %d subframe %d slice %d: calling the scheduler\n", mod_id, frame, subframe,i); - slice_sched[i](mod_id, i, frame, subframe, mbsfn_flag,dl_info); + slice_sched_dl[i](mod_id, i, frame, subframe, mbsfn_flag,dl_info); } @@ -894,7 +894,7 @@ flexran_schedule_ue_spec_urllc(mid_t mod_id, Protocol__FlexranMessage **dl_info) { - flexran_schedule_ue_spec_dl_common(mod_id, + flexran_schedule_ue_dl_spec_common(mod_id, slice_id, frame, subframe, diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index 20e1c67366..9a9ecbb1e5 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -35,6 +35,7 @@ #include "SCHED/defs.h" #include "SCHED/extern.h" +#include "LAYER2/MAC/flexran_agent_mac_proto.h" #include "LAYER2/MAC/defs.h" #include "LAYER2/MAC/proto.h" #include "LAYER2/MAC/extern.h" @@ -56,22 +57,30 @@ #include "T.h" -// #define ENABLE_MAC_PAYLOAD_DEBUG -// #define DEBUG_eNB_SCHEDULER 1 +/* number of active slices for past and current time*/ +static int n_active_slices = 1; +static int n_active_slices_current = 1; - -// RB share for each slice for past and current time -float slice_percentage_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; +/* RB share for each slice for past and current time*/ +float slice_percentage_uplink[MAX_NUM_SLICES] = {0.8, 0.2, 0.0, 0.0}; float slice_percentage_current_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; +float total_slice_percentage_uplink = 0; - - uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES]; - +/*resource blocks allowed*/ +static uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES]; +/*Slice Update */ int update_ul_scheduler[MAX_NUM_SLICES] = {1, 1, 1, 1}; int update_ul_scheduler_current[MAX_NUM_SLICES] = {1, 1, 1, 1}; -// name of available scheduler -char *ul_scheduler_type[MAX_NUM_SLICES] = {"flexran_schedule_ue_ul_spec_embb"}; + /* Slice Function Pointer */ +slice_scheduler_ul slice_sched_ul[MAX_NUM_SLICES] = {0}; + +/* name of available scheduler*/ +char *ul_scheduler_type[MAX_NUM_SLICES] = {"flexran_schedule_ue_ul_spec_embb", + "flexran_schedule_ue_ul_spec_urllc", + "flexran_schedule_ue_ul_spec_mmtc", + "flexran_schedule_ue_ul_spec_be" // best effort +}; uint16_t flexran_nb_rbs_allowed_slice_uplink(float rb_percentage, int total_rbs){ @@ -387,25 +396,26 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, void flexran_schedule_ue_ul_spec_default(mid_t mod_id, uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info) + uint32_t cooperation_flag, + int subframe, + unsigned char sched_subframe, + Protocol__FlexranMessage **ul_info) //------------------------------------------------------------------------------ { int i=0; - flexran_agent_mac_create_empty_ul_config(module_idP, ul_info); + flexran_agent_mac_create_empty_ul_config(mod_id, ul_info); for (i = 0; i < n_active_slices; i++) { // Load any updated functions - if (update_dl_scheduler[i] > 0 ) { - slice_sched[i] = dlsym(NULL, dl_scheduler_type[i]); - update_dl_scheduler[i] = 0; - update_dl_scheduler_current[i] = 0; - slice_percentage_current[i]= slice_percentage[i]; - total_slice_percentage+=slice_percentage[i]; - LOG_N(MAC,"update dl scheduler slice %d\n", i); + if (update_ul_scheduler[i] > 0 ) { + slice_sched_ul[i] = dlsym(NULL, ul_scheduler_type[i]); + update_ul_scheduler[i] = 0; + update_ul_scheduler_current[i] = 0; + slice_percentage_current_uplink[i]= slice_percentage_uplink[i]; + total_slice_percentage_uplink+=slice_percentage_uplink[i]; + LOG_N(MAC,"update ul scheduler slice %d\n", i); } // check if the number of slices has changed, and log @@ -423,45 +433,45 @@ flexran_schedule_ue_ul_spec_default(mid_t mod_id, } // check if the slice rb share has changed, and log the console - if (slice_percentage_current[i] != slice_percentage[i]){ - if ((slice_percentage[i] >= 0.0) && (slice_percentage[i] <= 1.0)){ - if ((total_slice_percentage - slice_percentage_current[i] + slice_percentage[i]) <= 1.0) { - total_slice_percentage=total_slice_percentage - slice_percentage_current[i] + slice_percentage[i]; + if (slice_percentage_current_uplink[i] != slice_percentage_uplink[i]){ + if ((slice_percentage_uplink[i] >= 0.0) && (slice_percentage_uplink[i] <= 1.0)){ + if ((total_slice_percentage_uplink - slice_percentage_current_uplink[i] + slice_percentage_uplink[i]) <= 1.0) { + total_slice_percentage_uplink=total_slice_percentage_uplink - slice_percentage_current_uplink[i] + slice_percentage_uplink[i]; LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: total percentage %f, slice RB percentage has changed: %f-->%f\n", - mod_id, i, frame, subframe, total_slice_percentage, slice_percentage_current[i], slice_percentage[i]); + mod_id, i, frame, subframe, total_slice_percentage_uplink, slice_percentage_current_uplink[i], slice_percentage_uplink[i]); - slice_percentage_current[i] = slice_percentage[i]; + slice_percentage_current_uplink[i] = slice_percentage_uplink[i]; } else { LOG_W(MAC,"[eNB %d][SLICE %d] invalid total RB share (%f->%f), revert the previous value (%f->%f)\n", mod_id,i, - total_slice_percentage, - total_slice_percentage - slice_percentage_current[i] + slice_percentage[i], - slice_percentage[i],slice_percentage_current[i]); + total_slice_percentage_uplink, + total_slice_percentage_uplink - slice_percentage_current_uplink[i] + slice_percentage_uplink[i], + slice_percentage_uplink[i],slice_percentage_current_uplink[i]); - slice_percentage[i]= slice_percentage_current[i]; + slice_percentage_uplink[i]= slice_percentage_current_uplink[i]; } } else { - LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice RB share, revert the previous value (%f->%f)\n",mod_id, i, slice_percentage[i],slice_percentage_current[i]); + LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice RB share, revert the previous value (%f->%f)\n",mod_id, i, slice_percentage_uplink[i],slice_percentage_current_uplink[i]); - slice_percentage[i]= slice_percentage_current[i]; + slice_percentage_uplink[i]= slice_percentage_current_uplink[i]; } } // check if a new scheduler, and log the console - if (update_dl_scheduler_current[i] != update_dl_scheduler[i]){ + if (update_ul_scheduler_current[i] != update_ul_scheduler[i]){ LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: DL scheduler for this slice is updated: %s \n", - mod_id, i, frame, subframe, dl_scheduler_type[i]); + mod_id, i, frame, subframe, ul_scheduler_type[i]); - update_dl_scheduler_current[i] = update_dl_scheduler[i]; + update_ul_scheduler_current[i] = update_ul_scheduler[i]; } // Run each enabled slice-specific schedulers one by one //LOG_N(MAC,"[eNB %d]frame %d subframe %d slice %d: calling the scheduler\n", mod_id, frame, subframe,i); - slice_sched[i](mod_id, i, frame, subframe, mbsfn_flag,dl_info); + slice_sched_ul[i](mod_id, frame, cooperation_flag, subframe, sched_subframe,ul_info); } @@ -469,7 +479,7 @@ flexran_schedule_ue_ul_spec_default(mid_t mod_id, void flexran_schedule_ue_ul_spec_embb(mid_t mod_id, - frame_t frameP, + frame_t frame, unsigned char cooperation_flag, uint32_t subframe, unsigned char sched_subframe, @@ -583,7 +593,7 @@ void flexran_agent_schedule_ulsch_rnti(module_id_t module_idP, // LOG_I(MAC,"entering ulsch preprocesor\n"); - + /*TODO*/ int slice_id = 0; From 042a16d1f60c18487990a1f8ade9f48a76f2bb9d Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Thu, 18 May 2017 17:26:08 +0200 Subject: [PATCH 021/284] Fix percentage --- openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index 9a9ecbb1e5..2abc6438c1 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -62,7 +62,7 @@ static int n_active_slices = 1; static int n_active_slices_current = 1; /* RB share for each slice for past and current time*/ -float slice_percentage_uplink[MAX_NUM_SLICES] = {0.8, 0.2, 0.0, 0.0}; +float slice_percentage_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; float slice_percentage_current_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; float total_slice_percentage_uplink = 0; From 2e2b07ef9e4a4517f32153d1e47a876ad6d26d97 Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Mon, 22 May 2017 19:19:28 +0200 Subject: [PATCH 022/284] push update load --- openair2/ENB_APP/flexran_agent_common.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index 78d3a75ec7..fe70a62ec8 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -26,8 +26,9 @@ * \version 0.1 */ -#include +#include #include +#include #include "flexran_agent_common.h" #include "flexran_agent_common_internal.h" @@ -386,13 +387,15 @@ int flexran_agent_control_delegation(mid_t mod_id, const void *params, Protocol_ Protocol__FlexControlDelegation *control_delegation_msg = input->control_delegation_msg; // struct timespec vartime = timer_start(); - + int status; //Write the payload lib into a file in the cache and load the lib char lib_name[120]; char target[512]; snprintf(lib_name, sizeof(lib_name), "/%s.so", control_delegation_msg->name); strcpy(target, local_cache); strcat(target, lib_name); + + status = mkdir(local_cache, S_IRWXU | S_IRWXG | S_IRWXO); FILE *f; f = fopen(target, "wb"); From 8458c8fcf82a401ceba3c9d58f8000d09f6cd8a0 Mon Sep 17 00:00:00 2001 From: shahab SHARIAT BAGHERI Date: Tue, 23 May 2017 23:46:31 +0200 Subject: [PATCH 023/284] uplink mac parser --- .../MAC/flexran_agent_mac_internal.c | 5 ++++- .../MAC/flexran_agent_scheduler_dlsch_ue.c | 4 ++-- .../MAC/flexran_agent_scheduler_ulsch_ue.c | 18 +++++++++--------- openair2/RRC/LITE/extern.h | 4 ++-- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c index 66efafae55..13b63b1494 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c @@ -607,7 +607,10 @@ int parse_mac_config(mid_t mod_id, yaml_parser_t *parser) { } else if (strcmp((char *) event.data.scalar.value, "ul_scheduler") == 0) { // Call the proper handler LOG_D(ENB_APP, "This is for the ul_scheduler subsystem\n"); - goto error; + if (parse_dl_scheduler_config(mod_id, parser) == -1) { + LOG_D(ENB_APP, "An error occured\n"); + goto error; + } // TODO } else if (strcmp((char *) event.data.scalar.value, "ra_scheduler") == 0) { // Call the proper handler diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index b30cb5f491..fce24223b5 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -88,8 +88,8 @@ typedef enum { // number of active slices for past and current time -static int n_active_slices = 1; -static int n_active_slices_current = 1; +int n_active_slices = 1; +int n_active_slices_current = 1; // ue to slice mapping int slicing_strategy = UEID_TO_SLICEID; diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index 2abc6438c1..d8f9fe8e63 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -58,8 +58,8 @@ #include "T.h" /* number of active slices for past and current time*/ -static int n_active_slices = 1; -static int n_active_slices_current = 1; +int n_active_slices_uplink = 1; +int n_active_slices_uplink_current = 1; /* RB share for each slice for past and current time*/ float slice_percentage_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; @@ -406,7 +406,7 @@ flexran_schedule_ue_ul_spec_default(mid_t mod_id, flexran_agent_mac_create_empty_ul_config(mod_id, ul_info); - for (i = 0; i < n_active_slices; i++) { + for (i = 0; i < n_active_slices_uplink; i++) { // Load any updated functions if (update_ul_scheduler[i] > 0 ) { @@ -419,16 +419,16 @@ flexran_schedule_ue_ul_spec_default(mid_t mod_id, } // check if the number of slices has changed, and log - if (n_active_slices_current != n_active_slices ){ - if ((n_active_slices > 0) && (n_active_slices <= MAX_NUM_SLICES)) { + if (n_active_slices_uplink_current != n_active_slices_uplink ){ + if ((n_active_slices_uplink > 0) && (n_active_slices_uplink <= MAX_NUM_SLICES)) { LOG_N(MAC,"[eNB %d]frame %d subframe %d: number of active slices has changed: %d-->%d\n", - mod_id, frame, subframe, n_active_slices_current, n_active_slices); + mod_id, frame, subframe, n_active_slices_uplink_current, n_active_slices_uplink); - n_active_slices_current = n_active_slices; + n_active_slices_uplink_current = n_active_slices_uplink; } else { - LOG_W(MAC,"invalid number of slices %d, revert to the previous value %d\n",n_active_slices, n_active_slices_current); - n_active_slices = n_active_slices_current; + LOG_W(MAC,"invalid number of slices %d, revert to the previous value %d\n",n_active_slices_uplink, n_active_slices_uplink_current); + n_active_slices_uplink = n_active_slices_uplink_current; } } diff --git a/openair2/RRC/LITE/extern.h b/openair2/RRC/LITE/extern.h index d4c8192a95..7934690563 100644 --- a/openair2/RRC/LITE/extern.h +++ b/openair2/RRC/LITE/extern.h @@ -93,8 +93,8 @@ extern uint16_t N310[8]; extern uint16_t N311[8]; extern uint32_t T304[8]; extern uint32_t timeToTrigger_ms[16]; -extern float RSRP_meas_mapping[100]; -extern float RSRQ_meas_mapping[33]; +extern float RSRP_meas_mapping[98]; +extern float RSRQ_meas_mapping[35]; #endif From 1ecdcba33a88c56f9eceb62621f094a93daac80d Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Thu, 8 Jun 2017 18:36:25 +0200 Subject: [PATCH 024/284] uplink VSF --- cmake_targets/CMakeLists.txt | 3 + .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 4 +- .../MAC/flexran_agent_mac_defs.h | 4 +- .../MAC/flexran_agent_mac_internal.c | 107 +++++++++++++++++- .../MAC/flexran_agent_mac_internal.h | 4 + .../MAC/flexran_agent_scheduler_dlsch_ue.c | 38 +++---- .../MAC/flexran_agent_scheduler_ulsch_ue.c | 72 ++++++------ 7 files changed, 174 insertions(+), 58 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 192590e20f..a04915bb53 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1231,6 +1231,9 @@ if (FLEXRAN_AGENT_SB_IF) add_library(default_sched SHARED ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue.c) add_library(remote_sched SHARED ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue_remote.c) +add_library(default_ul_sched SHARED ${MAC_DIR}/flexran_agent_scheduler_ulsch_ue.c) + + endif() # L3 Libs diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index f17fb9a1ba..512be68669 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -1254,7 +1254,7 @@ int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->flexran_agent_get_pending_dl_mac_config = flexran_agent_get_pending_dl_mac_config; xface->dl_scheduler_loaded_lib = NULL; - + xface->ul_scheduler_loaded_lib = NULL; mac_agent_registered[mod_id] = 1; agent_mac_xface[mod_id] = xface; @@ -1272,7 +1272,7 @@ int flexran_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->dl_scheduler_loaded_lib = NULL; - + xface->ul_scheduler_loaded_lib = NULL; mac_agent_registered[mod_id] = 0; agent_mac_xface[mod_id] = NULL; diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h index 49ef7f0fb7..362c50f13c 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h @@ -62,8 +62,7 @@ typedef struct { void (*flexran_agent_schedule_ul_spec)(mid_t module_idP, uint32_t frameP, unsigned char cooperation_flag, - uint32_t subframeP, - unsigned char sched_subframe, Protocol__FlexranMessage **ul_info); + uint32_t subframeP, unsigned char sched_subframe, Protocol__FlexranMessage **ul_info); /// Notify the controller for a state change of a particular UE, by sending the proper /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) @@ -72,6 +71,7 @@ typedef struct { void *dl_scheduler_loaded_lib; + void *ul_scheduler_loaded_lib; /*TODO: Fill in with the rest of the MAC layer technology specific callbacks (UL/DL scheduling, RACH info etc)*/ } AGENT_MAC_xface; diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c index 13b63b1494..68b82713e6 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c @@ -607,7 +607,7 @@ int parse_mac_config(mid_t mod_id, yaml_parser_t *parser) { } else if (strcmp((char *) event.data.scalar.value, "ul_scheduler") == 0) { // Call the proper handler LOG_D(ENB_APP, "This is for the ul_scheduler subsystem\n"); - if (parse_dl_scheduler_config(mod_id, parser) == -1) { + if (parse_ul_scheduler_config(mod_id, parser) == -1) { LOG_D(ENB_APP, "An error occured\n"); goto error; } @@ -703,6 +703,56 @@ int parse_dl_scheduler_config(mid_t mod_id, yaml_parser_t *parser) { return -1; } +int parse_ul_scheduler_config(mid_t mod_id, yaml_parser_t *parser) { + + yaml_event_t event; + + int done = 0; + int mapping_started = 0; + + while (!done) { + + if (!yaml_parser_parse(parser, &event)) + goto error; + + switch (event.type) { + // We are expecting a mapping (behavior and parameters) + case YAML_MAPPING_START_EVENT: + LOG_D(ENB_APP, "The mapping of the subsystem started\n"); + mapping_started = 1; + break; + case YAML_MAPPING_END_EVENT: + LOG_D(ENB_APP, "The mapping of the subsystem ended\n"); + mapping_started = 0; + break; + case YAML_SCALAR_EVENT: + if (!mapping_started) { + goto error; + } + // Check what key needs to be set + if (strcmp((char *) event.data.scalar.value, "parameters") == 0) { + LOG_D(ENB_APP, "Now it is time to set the parameters for this subsystem\n"); + if (parse_ul_scheduler_parameters(mod_id, parser) == -1) { + goto error; + } + } + break; + default: + goto error; + } + + done = (event.type == YAML_MAPPING_END_EVENT); + yaml_event_delete(&event); + } + + return 0; + + error: + yaml_event_delete(&event); + return -1; +} + + int parse_dl_scheduler_parameters(mid_t mod_id, yaml_parser_t *parser) { yaml_event_t event; @@ -758,6 +808,61 @@ int parse_dl_scheduler_parameters(mid_t mod_id, yaml_parser_t *parser) { return -1; } +int parse_ul_scheduler_parameters(mid_t mod_id, yaml_parser_t *parser) { + yaml_event_t event; + + void *param; + + int done = 0; + int mapping_started = 0; + + while (!done) { + + if (!yaml_parser_parse(parser, &event)) + goto error; + + switch (event.type) { + // We are expecting a mapping of parameters + case YAML_MAPPING_START_EVENT: + LOG_D(ENB_APP, "The mapping of the parameters started\n"); + mapping_started = 1; + break; + case YAML_MAPPING_END_EVENT: + LOG_D(ENB_APP, "The mapping of the parameters ended\n"); + mapping_started = 0; + break; + case YAML_SCALAR_EVENT: + if (!mapping_started) { + goto error; + } + // Check what key needs to be set + if (mac_agent_registered[mod_id]) { + LOG_D(ENB_APP, "Setting parameter %s\n", event.data.scalar.value); + param = dlsym(agent_mac_xface[mod_id]->ul_scheduler_loaded_lib, + (char *) event.data.scalar.value); + if (param == NULL) { + goto error; + } + apply_parameter_modification(param, parser); + } else { + goto error; + } + break; + default: + goto error; + } + + done = (event.type == YAML_MAPPING_END_EVENT); + yaml_event_delete(&event); + } + + return 0; + + error: + yaml_event_delete(&event); + return -1; +} + int load_dl_scheduler_function(mid_t mod_id, const char *function_name) { void *lib; diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h index 9a7d4a8555..95f6934e56 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h @@ -101,6 +101,10 @@ int parse_dl_scheduler_config(mid_t mod_id, yaml_parser_t *parser); int parse_dl_scheduler_parameters(mid_t mod_id, yaml_parser_t *parser); +int parse_ul_scheduler_config(mid_t mod_id, yaml_parser_t *parser); + +int parse_ul_scheduler_parameters(mid_t mod_id, yaml_parser_t *parser); + int load_dl_scheduler_function(mid_t mod_id, const char *function_name); #endif /*FLEXRAN_AGENT_MAC_INTERNAL_H_*/ diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index fce24223b5..ade4b77c14 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -88,16 +88,16 @@ typedef enum { // number of active slices for past and current time -int n_active_slices = 1; -int n_active_slices_current = 1; +int n_active_slices = 2; +int n_active_slices_current = 2; // ue to slice mapping int slicing_strategy = UEID_TO_SLICEID; int slicing_strategy_current = UEID_TO_SLICEID; // RB share for each slice for past and current time -float slice_percentage[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; -float slice_percentage_current[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; +float slice_percentage[MAX_NUM_SLICES] = {0.5, 0.5, 0.0, 0.0}; +float slice_percentage_current[MAX_NUM_SLICES] = {0.5, 0.5, 0.0, 0.0}; float total_slice_percentage = 0; // MAX MCS for each slice for past and current time @@ -753,30 +753,30 @@ flexran_schedule_ue_dl_spec_default(mid_t mod_id, // check if the slice rb share has changed, and log the console if (slice_percentage_current[i] != slice_percentage[i]){ - if ((slice_percentage[i] >= 0.0) && (slice_percentage[i] <= 1.0)){ - if ((total_slice_percentage - slice_percentage_current[i] + slice_percentage[i]) <= 1.0) { - total_slice_percentage=total_slice_percentage - slice_percentage_current[i] + slice_percentage[i]; + // if ((slice_percentage[i] >= 0.0) && (slice_percentage[i] <= 1.0)){ + // if ((total_slice_percentage - slice_percentage_current[i] + slice_percentage[i]) <= 1.0) { + // total_slice_percentage=total_slice_percentage - slice_percentage_current[i] + slice_percentage[i]; LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: total percentage %f, slice RB percentage has changed: %f-->%f\n", mod_id, i, frame, subframe, total_slice_percentage, slice_percentage_current[i], slice_percentage[i]); slice_percentage_current[i] = slice_percentage[i]; - } else { - LOG_W(MAC,"[eNB %d][SLICE %d] invalid total RB share (%f->%f), revert the previous value (%f->%f)\n", - mod_id,i, - total_slice_percentage, - total_slice_percentage - slice_percentage_current[i] + slice_percentage[i], - slice_percentage[i],slice_percentage_current[i]); + // } else { + // LOG_W(MAC,"[eNB %d][SLICE %d] invalid total RB share (%f->%f), revert the previous value (%f->%f)\n", + // mod_id,i, + // total_slice_percentage, + // total_slice_percentage - slice_percentage_current[i] + slice_percentage[i], + // slice_percentage[i],slice_percentage_current[i]); - slice_percentage[i]= slice_percentage_current[i]; + // slice_percentage[i]= slice_percentage_current[i]; - } - } else { - LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice RB share, revert the previous value (%f->%f)\n",mod_id, i, slice_percentage[i],slice_percentage_current[i]); + // } + // } else { + // LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice RB share, revert the previous value (%f->%f)\n",mod_id, i, slice_percentage[i],slice_percentage_current[i]); - slice_percentage[i]= slice_percentage_current[i]; + // slice_percentage[i]= slice_percentage_current[i]; - } + // } } // check if the slice max MCS, and log the console diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index d8f9fe8e63..b0e7272e9d 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -58,16 +58,16 @@ #include "T.h" /* number of active slices for past and current time*/ -int n_active_slices_uplink = 1; -int n_active_slices_uplink_current = 1; +int n_active_slices_uplink = 2; +int n_active_slices_uplink_current = 2; /* RB share for each slice for past and current time*/ -float slice_percentage_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; -float slice_percentage_current_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; +float slice_percentage_uplink[MAX_NUM_SLICES] = {0.5, 0.5, 0.0, 0.0}; +float slice_percentage_current_uplink[MAX_NUM_SLICES] = {0.5, 0.5, 0.0, 0.0}; float total_slice_percentage_uplink = 0; /*resource blocks allowed*/ -static uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES]; +uint16_t nb_rbs_allowed_slice_uplink[MAX_NUM_CCs][MAX_NUM_SLICES]; /*Slice Update */ int update_ul_scheduler[MAX_NUM_SLICES] = {1, 1, 1, 1}; int update_ul_scheduler_current[MAX_NUM_SLICES] = {1, 1, 1, 1}; @@ -144,7 +144,7 @@ void _assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, su UE_list->numactiveULCCs[UE_id]); frame_parms=mac_xface->get_lte_frame_parms(module_idP,CC_id); UE_template = &UE_list->UE_template[CC_id][UE_id]; - nb_rbs_allowed_slice[CC_id][UE_id] = flexran_nb_rbs_allowed_slice_uplink(slice_percentage_uplink[UE_id], flexran_get_N_RB_UL(module_idP, CC_id)); + nb_rbs_allowed_slice_uplink[CC_id][UE_id] = flexran_nb_rbs_allowed_slice_uplink(slice_percentage_uplink[UE_id], flexran_get_N_RB_UL(module_idP, CC_id)); // if this UE has UL traffic if (UE_template->ul_total_buffer > 0 ) { @@ -161,7 +161,7 @@ void _assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, su } while ((tbs < UE_template->ul_total_buffer) && - (rb_table[rb_table_index]<(nb_rbs_allowed_slice[CC_id][UE_id]-first_rb[CC_id])) && + (rb_table[rb_table_index]<(nb_rbs_allowed_slice_uplink[CC_id][UE_id]-first_rb[CC_id])) && ((UE_template->phr_info - tx_power) > 0) && (rb_table_index < 32 )) { // LOG_I(MAC,"tbs %d ul buffer %d rb table %d max ul rb %d\n", tbs, UE_template->ul_total_buffer, rb_table[rb_table_index], frame_parms->N_RB_UL-first_rb[CC_id]); @@ -172,7 +172,7 @@ void _assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, su UE_template->ue_tx_power = tx_power; - if (rb_table[rb_table_index]>(nb_rbs_allowed_slice[CC_id][UE_id]-first_rb[CC_id]-1)) { + if (rb_table[rb_table_index]>(nb_rbs_allowed_slice_uplink[CC_id][UE_id]-first_rb[CC_id]-1)) { rb_table_index--; } @@ -212,7 +212,7 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, uint16_t UE_id,n,r; uint8_t CC_id, round, harq_pid; uint16_t nb_allocated_rbs[MAX_NUM_CCs][NUMBER_OF_UE_MAX],total_allocated_rbs[MAX_NUM_CCs],average_rbs_per_user[MAX_NUM_CCs]; - uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES]; + uint16_t nb_rbs_allowed_slice_uplink[MAX_NUM_CCs][MAX_NUM_SLICES]; int16_t total_remaining_rbs[MAX_NUM_CCs]; uint16_t max_num_ue_to_be_scheduled=0,total_ue_count=0; rnti_t rnti= -1; @@ -281,17 +281,17 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, max_num_ue_to_be_scheduled+=1; - nb_rbs_allowed_slice[CC_id][UE_id] = flexran_nb_rbs_allowed_slice_uplink(slice_percentage_uplink[UE_id], flexran_get_N_RB_UL(module_idP, CC_id)); + nb_rbs_allowed_slice_uplink[CC_id][UE_id] = flexran_nb_rbs_allowed_slice_uplink(slice_percentage_uplink[UE_id], flexran_get_N_RB_UL(module_idP, CC_id)); if (total_ue_count == 0) { average_rbs_per_user[CC_id] = 0; } else if (total_ue_count == 1 ) { // increase the available RBs, special case, - average_rbs_per_user[CC_id] = nb_rbs_allowed_slice[CC_id][i]-first_rb[CC_id]+1; - } else if( (total_ue_count <= (nb_rbs_allowed_slice[CC_id][i]-first_rb[CC_id])) && + average_rbs_per_user[CC_id] = nb_rbs_allowed_slice_uplink[CC_id][i]-first_rb[CC_id]+1; + } else if( (total_ue_count <= (nb_rbs_allowed_slice_uplink[CC_id][i]-first_rb[CC_id])) && (total_ue_count <= max_num_ue_to_be_scheduled)) { - average_rbs_per_user[CC_id] = (uint16_t) floor((nb_rbs_allowed_slice[CC_id][i]-first_rb[CC_id])/total_ue_count); + average_rbs_per_user[CC_id] = (uint16_t) floor((nb_rbs_allowed_slice_uplink[CC_id][i]-first_rb[CC_id])/total_ue_count); } else if (max_num_ue_to_be_scheduled > 0 ) { - average_rbs_per_user[CC_id] = (uint16_t) floor((nb_rbs_allowed_slice[CC_id][slice_id]-first_rb[CC_id])/max_num_ue_to_be_scheduled); + average_rbs_per_user[CC_id] = (uint16_t) floor((nb_rbs_allowed_slice_uplink[CC_id][i]-first_rb[CC_id])/max_num_ue_to_be_scheduled); } else { average_rbs_per_user[CC_id]=1; LOG_W(MAC,"[eNB %d] frame %d subframe %d: UE %d CC %d: can't get average rb per user (should not be here)\n", @@ -322,7 +322,7 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, // This is the actual CC_id in the list CC_id = UE_list->ordered_ULCCids[n][UE_id]; ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - ue_sched_ctl->max_allowed_rbs[CC_id]=nb_rbs_allowed_slice[CC_id][UE_id]; + ue_sched_ctl->max_allowed_rbs[CC_id]=nb_rbs_allowed_slice_uplink[CC_id][UE_id]; // mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL); flexran_get_harq(module_idP, CC_id, UE_id, frameP, subframeP, &harq_pid, &round, openair_harq_UL); if(round>0) { @@ -356,7 +356,7 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, CC_id = UE_list->ordered_ULCCids[n][UE_id]; UE_template = &UE_list->UE_template[CC_id][UE_id]; frame_parms = mac_xface->get_lte_frame_parms(module_idP,CC_id); - total_remaining_rbs[CC_id]=nb_rbs_allowed_slice[CC_id][UE_id] - first_rb[CC_id] - total_allocated_rbs[CC_id]; + total_remaining_rbs[CC_id]=nb_rbs_allowed_slice_uplink[CC_id][UE_id] - first_rb[CC_id] - total_allocated_rbs[CC_id]; if (total_ue_count == 1 ) { total_remaining_rbs[CC_id]+=1; @@ -383,7 +383,7 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, frame_parms= mac_xface->get_lte_frame_parms(module_idP,CC_id); if (total_allocated_rbs[CC_id]>0) { - LOG_D(MAC,"[eNB %d] total RB allocated for all UEs = %d/%d\n", module_idP, total_allocated_rbs[CC_id], nb_rbs_allowed_slice[CC_id][slice_id] - first_rb[CC_id]); + LOG_D(MAC,"[eNB %d] total RB allocated for all UEs = %d/%d\n", module_idP, total_allocated_rbs[CC_id], nb_rbs_allowed_slice_uplink[CC_id][slice_id] - first_rb[CC_id]); } } } @@ -434,30 +434,30 @@ flexran_schedule_ue_ul_spec_default(mid_t mod_id, // check if the slice rb share has changed, and log the console if (slice_percentage_current_uplink[i] != slice_percentage_uplink[i]){ - if ((slice_percentage_uplink[i] >= 0.0) && (slice_percentage_uplink[i] <= 1.0)){ - if ((total_slice_percentage_uplink - slice_percentage_current_uplink[i] + slice_percentage_uplink[i]) <= 1.0) { - total_slice_percentage_uplink=total_slice_percentage_uplink - slice_percentage_current_uplink[i] + slice_percentage_uplink[i]; + // if ((slice_percentage_uplink[i] >= 0.0) && (slice_percentage_uplink[i] <= 1.0)){ + // if ((total_slice_percentage_uplink - slice_percentage_current_uplink[i] + slice_percentage_uplink[i]) <= 1.0) { + // total_slice_percentage_uplink=total_slice_percentage_uplink - slice_percentage_current_uplink[i] + slice_percentage_uplink[i]; LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: total percentage %f, slice RB percentage has changed: %f-->%f\n", mod_id, i, frame, subframe, total_slice_percentage_uplink, slice_percentage_current_uplink[i], slice_percentage_uplink[i]); slice_percentage_current_uplink[i] = slice_percentage_uplink[i]; - } else { - LOG_W(MAC,"[eNB %d][SLICE %d] invalid total RB share (%f->%f), revert the previous value (%f->%f)\n", - mod_id,i, - total_slice_percentage_uplink, - total_slice_percentage_uplink - slice_percentage_current_uplink[i] + slice_percentage_uplink[i], - slice_percentage_uplink[i],slice_percentage_current_uplink[i]); + // } else { + // LOG_W(MAC,"[eNB %d][SLICE %d] invalid total RB share (%f->%f), revert the previous value (%f->%f)\n", + // mod_id,i, + // total_slice_percentage_uplink, + // total_slice_percentage_uplink - slice_percentage_current_uplink[i] + slice_percentage_uplink[i], + // slice_percentage_uplink[i],slice_percentage_current_uplink[i]); - slice_percentage_uplink[i]= slice_percentage_current_uplink[i]; + // slice_percentage_uplink[i]= slice_percentage_current_uplink[i]; - } - } else { - LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice RB share, revert the previous value (%f->%f)\n",mod_id, i, slice_percentage_uplink[i],slice_percentage_current_uplink[i]); + // } + // } else { + // LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice RB share, revert the previous value (%f->%f)\n",mod_id, i, slice_percentage_uplink[i],slice_percentage_current_uplink[i]); - slice_percentage_uplink[i]= slice_percentage_current_uplink[i]; + // slice_percentage_uplink[i]= slice_percentage_current_uplink[i]; - } + // } } // check if a new scheduler, and log the console @@ -471,9 +471,13 @@ flexran_schedule_ue_ul_spec_default(mid_t mod_id, // Run each enabled slice-specific schedulers one by one //LOG_N(MAC,"[eNB %d]frame %d subframe %d slice %d: calling the scheduler\n", mod_id, frame, subframe,i); - slice_sched_ul[i](mod_id, frame, cooperation_flag, subframe, sched_subframe,ul_info); + + + } + + slice_sched_ul[0](mod_id, frame, cooperation_flag, subframe, sched_subframe,ul_info); } @@ -765,7 +769,7 @@ abort(); UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; // buffer_occupancy = UE_template->ul_total_buffer; - while (((rb_table[rb_table_index]>(nb_rbs_allowed_slice[CC_id][UE_id]-1-first_rb[CC_id])) || + while (((rb_table[rb_table_index]>(nb_rbs_allowed_slice_uplink[CC_id][UE_id]-1-first_rb[CC_id])) || (rb_table[rb_table_index]>45)) && (rb_table_index>0)) { rb_table_index--; From f7e376ed5f5e05c6f3e4f678520cee1982dc5a5b Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 14 Jul 2017 12:52:51 +0300 Subject: [PATCH 025/284] Added support of FlexRAN agent compilation for oaisim with S1 enabled --- cmake_targets/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 8f90141618..7c9855b29a 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1846,12 +1846,12 @@ add_executable(oaisim target_include_directories(oaisim PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim -Wl,-ldl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB GTPV1U SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} LIB_NAS_UE SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} + RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB GTPV1U SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} LIB_NAS_UE SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 -Wl,--end-group ) target_link_libraries (oaisim ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) target_link_libraries (oaisim pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp - ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${OPENPGM_LIBRARIES}) + ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${OPENPGM_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES}) #Force link with forms, regardless XFORMS option target_link_libraries (oaisim forms) target_link_libraries (oaisim ${T_LIB}) From e51d8d3fd73d35fff38fd5306c011d2a68b4f001 Mon Sep 17 00:00:00 2001 From: Anta Huang Date: Thu, 20 Jul 2017 13:24:16 +0200 Subject: [PATCH 026/284] Add the slice_maxmcs_uplink to flexran agent ulsch --- openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index b0e7272e9d..86bb2407b6 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -66,6 +66,10 @@ float slice_percentage_uplink[MAX_NUM_SLICES] = {0.5, 0.5, 0.0, 0.0}; float slice_percentage_current_uplink[MAX_NUM_SLICES] = {0.5, 0.5, 0.0, 0.0}; float total_slice_percentage_uplink = 0; +// MAX MCS for each slice for past and current time +int slice_maxmcs_uplink[MAX_NUM_SLICES] = {16, 16, 16, 16}; +int slice_maxmcs_current_uplink[MAX_NUM_SLICES] = {28, 28, 28, 28}; + /*resource blocks allowed*/ uint16_t nb_rbs_allowed_slice_uplink[MAX_NUM_CCs][MAX_NUM_SLICES]; /*Slice Update */ From 9e7e57de74fd06ac02023a4097435cd9c1be05a8 Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Tue, 25 Jul 2017 19:12:42 +0200 Subject: [PATCH 027/284] DL Fixed Bug get TBS --- .../MAC/flexran_agent_scheduler_dlsch_ue.c | 550 +++++++++--------- 1 file changed, 280 insertions(+), 270 deletions(-) diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index ade4b77c14..e47adc4fdb 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -284,7 +284,7 @@ void _assign_rbs_required (module_id_t Mod_id, nb_rbs_required[CC_id][UE_id] += min_rb_unit[CC_id]; if (nb_rbs_required[CC_id][UE_id] > nb_rbs_allowed_slice[CC_id][slice_id]) { - TBS = mac_xface->get_TBS_DL(flexran_get_ue_wcqi(Mod_id, UE_id), nb_rbs_allowed_slice[CC_id][slice_id]); + TBS = mac_xface->get_TBS_DL(cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)], nb_rbs_allowed_slice[CC_id][slice_id]); nb_rbs_required[CC_id][UE_id] = nb_rbs_allowed_slice[CC_id][slice_id]; break; } @@ -495,7 +495,7 @@ void _dlsch_scheduler_pre_processor (module_id_t Mod_id, } } - // Store the DLSCH buffer for each logical channel + /* Store the DLSCH buffer for each logical channel for each UE */ _store_dlsch_buffer (Mod_id,slice_id,frameP,subframeP); // Calculate the number of RBs required by each UE on the basis of logical channel's buffer @@ -1044,9 +1044,10 @@ flexran_schedule_ue_dl_spec_common(mid_t mod_id, ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; if (eNB_UE_stats==NULL) { - LOG_D(MAC,"[eNB] Cannot find eNB_UE_stats\n"); - // mac_xface->macphy_exit("[MAC][eNB] Cannot find eNB_UE_stats\n"); - continue; + + LOG_D(MAC,"[eNB] Cannot find eNB_UE_stats\n"); + // mac_xface->macphy_exit("[MAC][eNB] Cannot find eNB_UE_stats\n"); + continue; } if (flexran_slice_member(UE_id, slice_id) == 0) @@ -1062,28 +1063,29 @@ flexran_schedule_ue_dl_spec_common(mid_t mod_id, case 1: case 2: case 7: - aggregation = get_aggregation(get_bw_index(mod_id,CC_id), + aggregation = get_aggregation(get_bw_index(mod_id,CC_id), eNB_UE_stats->DL_cqi[0], format1); - break; + break; case 3: - aggregation = get_aggregation(get_bw_index(mod_id,CC_id), + aggregation = get_aggregation(get_bw_index(mod_id,CC_id), eNB_UE_stats->DL_cqi[0], format2A); - break; + break; default: - LOG_W(MAC,"Unsupported transmission mode %d\n", mac_xface->get_transmission_mode(mod_id,CC_id,rnti)); - aggregation = 2; + LOG_W(MAC,"Unsupported transmission mode %d\n", mac_xface->get_transmission_mode(mod_id,CC_id,rnti)); + aggregation = 2; } if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated CCE_allocation_infeasible(mod_id, CC_id, 0, subframe, aggregation, rnti)) { - LOG_D(MAC,"[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", - mod_id, frame, UE_id, CC_id); - //if(mac_xface->get_transmission_mode(module_idP,rnti)==5) - continue; //to next user (there might be rbs availiable for other UEs in TM5 - // else - // break; + + LOG_D(MAC,"[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", + mod_id, frame, UE_id, CC_id); + //if(mac_xface->get_transmission_mode(module_idP,rnti)==5) + continue; //to next user (there might be rbs availiable for other UEs in TM5 + // else + // break; } if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { @@ -1106,26 +1108,28 @@ flexran_schedule_ue_dl_spec_common(mid_t mod_id, dl_data[num_ues_added]->n_rlc_pdu = 0; dl_data[num_ues_added]->has_serv_cell_index = 1; dl_data[num_ues_added]->serv_cell_index = CC_id; - - nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; + flexran_get_harq(mod_id, CC_id, UE_id, frame, subframe, &harq_pid, &round, openair_harq_DL); sdu_length_total=0; mcs = cqi_to_mcs[flexran_get_ue_wcqi(mod_id, UE_id)]; // LOG_I(FLEXRAN_AGENT, "The MCS is %d\n", mcs); mcs = cmin(mcs,flexran_slice_maxmcs(slice_id)); -#ifdef EXMIMO +// #ifdef EXMIMO - if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti) == 5) { - mcs = cqi_to_mcs[flexran_get_ue_wcqi(mod_id, UE_id)]; - mcs = cmin(mcs,16); - } +// if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti) == 5) { +// mcs = cqi_to_mcs[flexran_get_ue_wcqi(mod_id, UE_id)]; +// mcs = cmin(mcs,16); +// } -#endif +// #endif + /*Get pre available resource blocks based on buffers*/ + nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; // initializing the rb allocation indicator for each UE for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0; - rballoc_sub[j] = 0; + + UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0; + rballoc_sub[j] = 0; } /* LOG_D(MAC,"[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n", */ @@ -1146,72 +1150,74 @@ flexran_schedule_ue_dl_spec_common(mid_t mod_id, /* process retransmission */ if (round > 0) { - LOG_D(FLEXRAN_AGENT, "There was a retransmission just now and the round was %d\n", round); + LOG_D(FLEXRAN_AGENT, "There was a retransmission just now and the round was %d\n", round); - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - UE_list->UE_template[CC_id][UE_id].DAI++; - update_ul_dci(mod_id, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); - LOG_D(MAC,"DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", - CC_id, subframe,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); - } + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + UE_list->UE_template[CC_id][UE_id].DAI++; + update_ul_dci(mod_id, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); + LOG_D(MAC,"DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", + CC_id, subframe,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); + } - mcs = UE_list->UE_template[CC_id][UE_id].mcs[harq_pid]; + mcs = UE_list->UE_template[CC_id][UE_id].mcs[harq_pid]; - // get freq_allocation - nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - - /*TODO: Must add this to FlexRAN agent API */ - dci_tbs = mac_xface->get_TBS_DL(mcs, nb_rb); + // get freq_allocation + nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + + /*TODO: Must add this to FlexRAN agent API */ + dci_tbs = mac_xface->get_TBS_DL(mcs, nb_rb); - if (nb_rb <= nb_available_rb) { - - if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { - for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { // for indicating the rballoc for each sub-band - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - } - } else { - nb_rb_temp = nb_rb; - j = 0; + if (nb_rb <= nb_available_rb) { + + if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { + for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { // for indicating the rballoc for each sub-band + UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + } + } else { + nb_rb_temp = nb_rb; + j = 0; - while((nb_rb_temp > 0) && (j < flexran_get_N_RBG(mod_id, CC_id))) { - if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - - if((j == flexran_get_N_RBG(mod_id, CC_id) - 1) && - ((flexran_get_N_RB_DL(mod_id, CC_id) == 25)|| - (flexran_get_N_RB_DL(mod_id, CC_id) == 50))) { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]+1; - } else { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; - } - } - j = j + 1; - } - } + while((nb_rb_temp > 0) && (j < flexran_get_N_RBG(mod_id, CC_id))) { + if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { + UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + + if((j == flexran_get_N_RBG(mod_id, CC_id) - 1) && + ((flexran_get_N_RB_DL(mod_id, CC_id) == 25)|| + (flexran_get_N_RB_DL(mod_id, CC_id) == 50))) { + nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]+1; + } else { + nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; + } + } + j = j + 1; + } + } - nb_available_rb -= nb_rb; - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; - - for(j=0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; - rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; - } + nb_available_rb -= nb_rb; + PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; + PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; + + for(j=0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { + PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; + rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; + } - // Keep the old NDI, do not toggle - ndi = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - tpc = UE_list->UE_template[CC_id][UE_id].oldTPC[harq_pid]; - UE_list->UE_template[CC_id][UE_id].mcs[harq_pid] = mcs; + // Keep the old NDI, do not toggle + ndi = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + tpc = UE_list->UE_template[CC_id][UE_id].oldTPC[harq_pid]; + UE_list->UE_template[CC_id][UE_id].mcs[harq_pid] = mcs; - ue_has_transmission = 1; - num_ues_added++; - } else { - LOG_D(MAC,"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", - mod_id, frame, CC_id, UE_id); - ue_has_transmission = 0; - } - //End of retransmission - } else { /* This is a potentially new SDU opportunity */ + ue_has_transmission = 1; + num_ues_added++; + } else { + LOG_D(MAC,"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", + mod_id, frame, CC_id, UE_id); + ue_has_transmission = 0; + } + //End of retransmission + } + + else { /* This is a potentially new SDU opportunity */ rlc_status.bytes_in_buffer = 0; // Now check RLC information to compute number of required RBs // get maximum TBS size for RLC request @@ -1265,11 +1271,14 @@ flexran_schedule_ue_dl_spec_common(mid_t mod_id, //Fill in as much as possible data_to_request = cmin(dci_tbs - ta_len - header_len - sdu_length_total, rlc_status.bytes_in_buffer); LOG_D(FLEXRAN_AGENT, "Will request %d bytes from channel %d\n", data_to_request, j); + if (data_to_request < 128) { //The header will be one byte less - header_len--; - header_len_last = 2; - } else { - header_len_last = 3; + header_len--; + header_len_last = 2; + } + else { + + header_len_last = 3; } /* if (j == 1 || j == 2) { data_to_request+=0; @@ -1364,7 +1373,8 @@ flexran_schedule_ue_dl_spec_common(mid_t mod_id, for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { // for indicating the rballoc for each sub-band UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; } - } else { + } + else { nb_rb_temp = nb_rb; j = 0; LOG_D(MAC, "[TEST]Will only partially fill the bitmap\n"); @@ -1412,12 +1422,12 @@ flexran_schedule_ue_dl_spec_common(mid_t mod_id, UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - UE_list->UE_template[CC_id][UE_id].DAI++; - // printf("DAI update: subframeP %d: UE %d, DAI %d\n",subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); + // if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + // UE_list->UE_template[CC_id][UE_id].DAI++; + // // printf("DAI update: subframeP %d: UE %d, DAI %d\n",subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); //#warning only for 5MHz channel - update_ul_dci(mod_id, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); - } + // update_ul_dci(mod_id, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); + // } // do PUCCH power control // this is the normalized RX power @@ -1475,189 +1485,189 @@ flexran_schedule_ue_dl_spec_common(mid_t mod_id, ue_has_transmission = 0; } } // End of new scheduling - + // If we has transmission or retransmission if (ue_has_transmission) { - switch (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)) { - case 1: - case 2: - default: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 1; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = ndi; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->n_tbs_size = 1; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - break; - case 3: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 2; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = ndi; - dl_dci->ndi[1] = ndi; - dl_dci->n_rv = 2; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->rv[1] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 2; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->mcs[1] = mcs; - dl_dci->n_tbs_size = 2; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - dl_dci->tbs_size[1] = dci_tbs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - break; - case 4: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 2; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = ndi; - dl_dci->ndi[1] = ndi; - dl_dci->n_rv = 2; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->rv[1] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 2; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->mcs[1] = mcs; - dl_dci->n_tbs_size = 2; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - dl_dci->tbs_size[1] = dci_tbs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - break; - case 5: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 1; - dl_dci->ndi[0] = ndi; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->n_tbs_size = 1; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - - if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { - ue_sched_ctl->dl_pow_off[CC_id] = 1; - } - - dl_dci->has_dl_power_offset = 1; - dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; - dl_dci->has_precoding_info = 1; - dl_dci->precoding_info = 5; // Is this right?? - - break; - case 6: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 1; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = ndi; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } + switch (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)) { + case 1: + case 2: + default: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = ndi; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->n_tbs_size = 1; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + } + break; + case 3: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 2; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = ndi; + dl_dci->ndi[1] = ndi; + dl_dci->n_rv = 2; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->rv[1] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 2; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->mcs[1] = mcs; + dl_dci->n_tbs_size = 2; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + dl_dci->tbs_size[1] = dci_tbs; + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + } + break; + case 4: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 2; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = ndi; + dl_dci->ndi[1] = ndi; + dl_dci->n_rv = 2; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->rv[1] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 2; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->mcs[1] = mcs; + dl_dci->n_tbs_size = 2; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + dl_dci->tbs_size[1] = dci_tbs; + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + } + break; + case 5: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi[0] = ndi; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->n_tbs_size = 1; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + } + + if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { + ue_sched_ctl->dl_pow_off[CC_id] = 1; + } + + dl_dci->has_dl_power_offset = 1; + dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; + dl_dci->has_precoding_info = 1; + dl_dci->precoding_info = 5; // Is this right?? + + break; + case 6: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = ndi; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + } - dl_dci->has_dl_power_offset = 1; - dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; - dl_dci->has_precoding_info = 1; - dl_dci->precoding_info = 5; // Is this right?? - break; - } + dl_dci->has_dl_power_offset = 1; + dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; + dl_dci->has_precoding_info = 1; + dl_dci->precoding_info = 5; // Is this right?? + break; + } } - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + // if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { /* TODO */ //set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe, frame_parms); - } + // } } // UE_id loop } // CC_id loop From 8e5b17404787e09decc13d2d649993610a394c7f Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Fri, 4 Aug 2017 16:02:17 +0200 Subject: [PATCH 028/284] merge to 68 --- .../LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c | 8 ++++---- .../LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index e47adc4fdb..02fe873144 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -88,16 +88,16 @@ typedef enum { // number of active slices for past and current time -int n_active_slices = 2; -int n_active_slices_current = 2; +int n_active_slices = 1; +int n_active_slices_current = 1; // ue to slice mapping int slicing_strategy = UEID_TO_SLICEID; int slicing_strategy_current = UEID_TO_SLICEID; // RB share for each slice for past and current time -float slice_percentage[MAX_NUM_SLICES] = {0.5, 0.5, 0.0, 0.0}; -float slice_percentage_current[MAX_NUM_SLICES] = {0.5, 0.5, 0.0, 0.0}; +float slice_percentage[MAX_NUM_SLICES] = {1.0, 1.0, 0.0, 0.0}; +float slice_percentage_current[MAX_NUM_SLICES] = {1.0, 1.0, 0.0, 0.0}; float total_slice_percentage = 0; // MAX MCS for each slice for past and current time diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index 86bb2407b6..4038ae518b 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -58,12 +58,12 @@ #include "T.h" /* number of active slices for past and current time*/ -int n_active_slices_uplink = 2; -int n_active_slices_uplink_current = 2; +int n_active_slices_uplink = 1; +int n_active_slices_uplink_current = 1; /* RB share for each slice for past and current time*/ -float slice_percentage_uplink[MAX_NUM_SLICES] = {0.5, 0.5, 0.0, 0.0}; -float slice_percentage_current_uplink[MAX_NUM_SLICES] = {0.5, 0.5, 0.0, 0.0}; +float slice_percentage_uplink[MAX_NUM_SLICES] = {1.0, 1.0, 0.0, 0.0}; +float slice_percentage_current_uplink[MAX_NUM_SLICES] = {1.0, 1.0, 0.0, 0.0}; float total_slice_percentage_uplink = 0; // MAX MCS for each slice for past and current time @@ -477,11 +477,11 @@ flexran_schedule_ue_ul_spec_default(mid_t mod_id, //LOG_N(MAC,"[eNB %d]frame %d subframe %d slice %d: calling the scheduler\n", mod_id, frame, subframe,i); - + slice_sched_ul[i](mod_id, frame, cooperation_flag, subframe, sched_subframe,ul_info); } - slice_sched_ul[0](mod_id, frame, cooperation_flag, subframe, sched_subframe,ul_info); + } From d12f55d2ed2c3b55d5dd140c130708fd5854a482 Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Fri, 4 Aug 2017 16:22:57 +0200 Subject: [PATCH 029/284] add operating downlink frequency --- openair2/ENB_APP/MESSAGES/V2/config_messages.proto | 1 + openair2/ENB_APP/flexran_agent_common.c | 4 ++++ openair2/ENB_APP/flexran_agent_ran_api.c | 8 ++++++++ openair2/ENB_APP/flexran_agent_ran_api.h | 5 ++++- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto index 441e193569..c21fee213b 100644 --- a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto +++ b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto @@ -38,6 +38,7 @@ message flex_cell_config { optional uint32 srs_mac_up_pts = 32; // Boolean value. See TS 36.211, section 5.5.3.2. TDD only optional uint32 enable_64QAM = 33; // One of the FLEQ_* enum values optional uint32 carrier_index = 34; // Carrier component index + optional uint32 op_dl_freq = 35; // operating downlink frequency } message flex_ue_config { diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index fe70a62ec8..4067145dfd 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -1013,6 +1013,10 @@ int flexran_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__F cell_conf[i]->srs_mac_up_pts = flexran_get_srs_MaxUpPts(enb_id,i); cell_conf[i]->has_srs_mac_up_pts = 1; + + cell_conf[i]->op_dl_freq = flexran_agent_get_operating_dl_freq (0); + cell_conf[i]->has_op_dl_freq = 1; + if (flexran_get_enable64QAM(enb_id,i) == 0) { cell_conf[i]->enable_64qam = PROTOCOL__FLEX_QAM__FLEQ_MOD_16QAM; } else if(flexran_get_enable64QAM(enb_id,i) == 1) { diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index ae304d1e26..685a3bf57e 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -956,3 +956,11 @@ int flexran_get_antenna_ports(mid_t mod_id, int CC_id){ return frame_parms->nb_antenna_ports_eNB; } + + +float flexran_agent_get_operating_dl_freq (mid_t cc_id) { + const Enb_properties_array_t* enb_properties = enb_config_get(); + return (enb_properties->properties[0]->downlink_frequency[cc_id] / 1000000); +} + + diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index e80ed44ce9..ed2a2a1fd5 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -298,4 +298,7 @@ int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id); int flexran_get_lcg(mid_t ue_id, mid_t lc_id); /* Get direction of logical channel with id lc_id */ -int flexran_get_direction(mid_t ue_id, mid_t lc_id); \ No newline at end of file +int flexran_get_direction(mid_t ue_id, mid_t lc_id); + +/*Gety downlink frequency*/ +float flexran_agent_get_operating_dl_freq (mid_t cc_id); \ No newline at end of file From 3cc3762ed9d63b6e5bec5c0ea3c29d1c852992be Mon Sep 17 00:00:00 2001 From: shahab SHARIATBAGHERI Date: Fri, 4 Aug 2017 16:27:15 +0200 Subject: [PATCH 030/284] carrier index --- openair2/ENB_APP/flexran_agent_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index 4067145dfd..df350e5d69 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -1014,7 +1014,7 @@ int flexran_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__F cell_conf[i]->has_srs_mac_up_pts = 1; - cell_conf[i]->op_dl_freq = flexran_agent_get_operating_dl_freq (0); + cell_conf[i]->op_dl_freq = flexran_agent_get_operating_dl_freq (i); cell_conf[i]->has_op_dl_freq = 1; if (flexran_get_enable64QAM(enb_id,i) == 0) { From 863e9404fcbe4610e53f6539ca444cf90320c51f Mon Sep 17 00:00:00 2001 From: Anta Huang Date: Fri, 4 Aug 2017 17:42:32 +0200 Subject: [PATCH 031/284] Add additional cell config info to flexran API and message --- .../ENB_APP/MESSAGES/V2/config_messages.proto | 4 ++++ openair2/ENB_APP/flexran_agent_common.c | 16 +++++++++++-- openair2/ENB_APP/flexran_agent_ran_api.c | 23 +++++++++++++++++-- openair2/ENB_APP/flexran_agent_ran_api.h | 16 +++++++++++-- 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto index c21fee213b..f19de4923f 100644 --- a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto +++ b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto @@ -39,6 +39,10 @@ message flex_cell_config { optional uint32 enable_64QAM = 33; // One of the FLEQ_* enum values optional uint32 carrier_index = 34; // Carrier component index optional uint32 op_dl_freq = 35; // operating downlink frequency + optional uint32 op_ul_freq = 36; // operating uplink frequency + optional uint32 op_eutra_band= 37; // operating band + optional int32 op_dl_pdsch_power = 38; // operating downlink power + optional int32 op_ul_pusch_power = 39; // operating uplink power } message flex_ue_config { diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index df350e5d69..d71e9496c8 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -1013,10 +1013,22 @@ int flexran_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__F cell_conf[i]->srs_mac_up_pts = flexran_get_srs_MaxUpPts(enb_id,i); cell_conf[i]->has_srs_mac_up_pts = 1; - - cell_conf[i]->op_dl_freq = flexran_agent_get_operating_dl_freq (i); + cell_conf[i]->op_dl_freq = flexran_agent_get_operating_dl_freq (enb_id,i); cell_conf[i]->has_op_dl_freq = 1; + cell_conf[i]->op_ul_freq = flexran_agent_get_operating_ul_freq (enb_id, i); + cell_conf[i]->has_op_ul_freq = 1; + + cell_conf[i]->op_eutra_band = flexran_agent_get_operating_eutra_band (enb_id,i); + cell_conf[i]->has_op_eutra_band = 1; + + cell_conf[i]->op_dl_pdsch_power = flexran_agent_get_operating_pdsch_refpower(enb_id, i); + cell_conf[i]->has_op_dl_pdsch_power = 1; + + cell_conf[i]->op_ul_pusch_power = flexran_agent_get_operating_pusch_p0 (enb_id,i); + cell_conf[i]->has_op_ul_pusch_power = 1; + + if (flexran_get_enable64QAM(enb_id,i) == 0) { cell_conf[i]->enable_64qam = PROTOCOL__FLEX_QAM__FLEQ_MOD_16QAM; } else if(flexran_get_enable64QAM(enb_id,i) == 1) { diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 685a3bf57e..10b667e916 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -958,9 +958,28 @@ int flexran_get_antenna_ports(mid_t mod_id, int CC_id){ } -float flexran_agent_get_operating_dl_freq (mid_t cc_id) { +float flexran_agent_get_operating_dl_freq (mid_t mod_id, int cc_id) { const Enb_properties_array_t* enb_properties = enb_config_get(); - return (enb_properties->properties[0]->downlink_frequency[cc_id] / 1000000); + return (enb_properties->properties[mod_id]->downlink_frequency[cc_id] / 1000000); +} + +float flexran_agent_get_operating_ul_freq (mid_t mod_id, int cc_id) { + const Enb_properties_array_t* enb_properties = enb_config_get(); + return ((enb_properties->properties[mod_id] ->downlink_frequency[cc_id] + enb_properties->properties[0]->uplink_frequency_offset[cc_id]) / 1000000); +} + +int flexran_agent_get_operating_eutra_band (mid_t mod_id, int cc_id) { + const Enb_properties_array_t* enb_properties = enb_config_get(); + return enb_properties->properties[mod_id]->eutra_band[cc_id]; +} +int flexran_agent_get_operating_pdsch_refpower (mid_t mod_id, int cc_id) { + const Enb_properties_array_t* enb_properties = enb_config_get(); + return enb_properties->properties[mod_id]->pdsch_referenceSignalPower[cc_id]; +} +int flexran_agent_get_operating_pusch_p0 (mid_t mod_id, int cc_id) { + const Enb_properties_array_t* enb_properties = enb_config_get(); + return enb_properties->properties[mod_id]->pusch_p0_Nominal[cc_id]; } + diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index ed2a2a1fd5..668c0e6ba0 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -300,5 +300,17 @@ int flexran_get_lcg(mid_t ue_id, mid_t lc_id); /* Get direction of logical channel with id lc_id */ int flexran_get_direction(mid_t ue_id, mid_t lc_id); -/*Gety downlink frequency*/ -float flexran_agent_get_operating_dl_freq (mid_t cc_id); \ No newline at end of file +/*Get downlink frequency*/ +float flexran_agent_get_operating_dl_freq (mid_t mod_id, int cc_id); + +/*Get uplink frequency*/ +float flexran_agent_get_operating_ul_freq (mid_t mod_id, int cc_id); + +/*Get eutra band*/ +int flexran_agent_get_operating_eutra_band (mid_t mod_id, int cc_id); + +/*Get downlink ref signal power*/ +int flexran_agent_get_operating_pdsch_refpower (mid_t mod_id, int cc_id); + +/*Get uplink power*/ +int flexran_agent_get_operating_pusch_p0 (mid_t mod_id, int cc_id); From 1e857d5ba5a22789a9e302487905dc908ffe5a71 Mon Sep 17 00:00:00 2001 From: Anta Huang Date: Fri, 4 Aug 2017 18:19:38 +0200 Subject: [PATCH 032/284] Update the naming of cell config parameters --- .../ENB_APP/MESSAGES/V2/config_messages.proto | 10 +++++----- openair2/ENB_APP/flexran_agent_common.c | 20 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto index f19de4923f..1be6f7f43a 100644 --- a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto +++ b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto @@ -38,11 +38,11 @@ message flex_cell_config { optional uint32 srs_mac_up_pts = 32; // Boolean value. See TS 36.211, section 5.5.3.2. TDD only optional uint32 enable_64QAM = 33; // One of the FLEQ_* enum values optional uint32 carrier_index = 34; // Carrier component index - optional uint32 op_dl_freq = 35; // operating downlink frequency - optional uint32 op_ul_freq = 36; // operating uplink frequency - optional uint32 op_eutra_band= 37; // operating band - optional int32 op_dl_pdsch_power = 38; // operating downlink power - optional int32 op_ul_pusch_power = 39; // operating uplink power + optional uint32 dl_freq = 35; // operating downlink frequency + optional uint32 ul_freq = 36; // operating uplink frequency + optional uint32 eutra_band= 37; // operating band + optional int32 dl_pdsch_power = 38; // operating downlink power + optional int32 ul_pusch_power = 39; // operating uplink power } message flex_ue_config { diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index d71e9496c8..e3f96c05dc 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -1013,20 +1013,20 @@ int flexran_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__F cell_conf[i]->srs_mac_up_pts = flexran_get_srs_MaxUpPts(enb_id,i); cell_conf[i]->has_srs_mac_up_pts = 1; - cell_conf[i]->op_dl_freq = flexran_agent_get_operating_dl_freq (enb_id,i); - cell_conf[i]->has_op_dl_freq = 1; + cell_conf[i]->dl_freq = flexran_agent_get_operating_dl_freq (enb_id,i); + cell_conf[i]->has_dl_freq = 1; - cell_conf[i]->op_ul_freq = flexran_agent_get_operating_ul_freq (enb_id, i); - cell_conf[i]->has_op_ul_freq = 1; + cell_conf[i]->ul_freq = flexran_agent_get_operating_ul_freq (enb_id, i); + cell_conf[i]->has_ul_freq = 1; - cell_conf[i]->op_eutra_band = flexran_agent_get_operating_eutra_band (enb_id,i); - cell_conf[i]->has_op_eutra_band = 1; + cell_conf[i]->eutra_band = flexran_agent_get_operating_eutra_band (enb_id,i); + cell_conf[i]->has_eutra_band = 1; - cell_conf[i]->op_dl_pdsch_power = flexran_agent_get_operating_pdsch_refpower(enb_id, i); - cell_conf[i]->has_op_dl_pdsch_power = 1; + cell_conf[i]->dl_pdsch_power = flexran_agent_get_operating_pdsch_refpower(enb_id, i); + cell_conf[i]->has_dl_pdsch_power = 1; - cell_conf[i]->op_ul_pusch_power = flexran_agent_get_operating_pusch_p0 (enb_id,i); - cell_conf[i]->has_op_ul_pusch_power = 1; + cell_conf[i]->ul_pusch_power = flexran_agent_get_operating_pusch_p0 (enb_id,i); + cell_conf[i]->has_ul_pusch_power = 1; if (flexran_get_enable64QAM(enb_id,i) == 0) { From 4d3689a56c0184d4f4697d443bbbca89172c3099 Mon Sep 17 00:00:00 2001 From: shahab SHARIAT BAGHERI Date: Wed, 9 Aug 2017 13:42:50 +0200 Subject: [PATCH 033/284] warning reducing --- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 10 +++++----- .../CONTROL_MODULES/MAC/flexran_agent_mac_defs.h | 7 ++++--- openair2/ENB_APP/flexran_agent_common.c | 5 +++++ openair2/ENB_APP/flexran_agent_ran_api.c | 2 +- openair2/ENB_APP/flexran_agent_ran_api.h | 3 +++ openair2/LAYER2/MAC/flexran_agent_mac_proto.h | 9 +++++++++ .../MAC/flexran_agent_scheduler_dlsch_ue.c | 4 ++-- .../MAC/flexran_agent_scheduler_ulsch_ue.c | 16 ++++++++++++---- 8 files changed, 41 insertions(+), 15 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 512be68669..60cdba76aa 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -1078,11 +1078,11 @@ int flexran_agent_mac_create_empty_ul_config(mid_t mod_id, Protocol__FlexranMess int flexran_agent_mac_destroy_ul_config(Protocol__FlexranMessage *msg) { - int i,j, k; + int i; //,j, k; if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_UL_MAC_CONFIG_MSG) goto error; - Protocol__FlexUlDci *ul_dci; + // Protocol__FlexUlDci *ul_dci; free(msg->ul_mac_config_msg->header); for (i = 0; i < msg->ul_mac_config_msg->n_ul_ue_data; i++) { @@ -1096,13 +1096,13 @@ int flexran_agent_mac_destroy_ul_config(Protocol__FlexranMessage *msg) { // free(msg->ul_mac_config_msg->ul_ue_data[i]->rlc_pdu[j]); // } // free(msg->ul_mac_config_msg->ul_ue_data[i]->rlc_pdu); - ul_dci = msg->ul_mac_config_msg->ul_ue_data[i]->ul_dci; + // ul_dci = msg->ul_mac_config_msg->ul_ue_data[i]->ul_dci; // free(dl_dci->tbs_size); // free(ul_dci->mcs); // free(ul_dci->ndi); // free(ul_dci->rv); // free(ul_dci); - free(msg->ul_mac_config_msg->ul_ue_data[i]); + // free(msg->ul_mac_config_msg->ul_ue_data[i]); } free(msg->ul_mac_config_msg->ul_ue_data); @@ -1269,7 +1269,7 @@ int flexran_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { //xface->flexran_agent_send_update_mac_stats = NULL; xface->flexran_agent_schedule_ue_spec = NULL; xface->flexran_agent_get_pending_dl_mac_config = NULL; - + xface->flexran_agent_schedule_ul_spec = NULL; xface->dl_scheduler_loaded_lib = NULL; xface->ul_scheduler_loaded_lib = NULL; diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h index 362c50f13c..10347f5587 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h @@ -60,9 +60,10 @@ typedef struct { void (*flexran_agent_schedule_ue_spec)(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, Protocol__FlexranMessage **dl_info); - - void (*flexran_agent_schedule_ul_spec)(mid_t module_idP, uint32_t frameP, unsigned char cooperation_flag, - uint32_t subframeP, unsigned char sched_subframe, Protocol__FlexranMessage **ul_info); + /// Run the UE UL scheduler and fill the Protocol__FlexranMessage. Assumes that + + void (*flexran_agent_schedule_ul_spec)(mid_t module_idP, uint32_t frameP, uint32_t cooperation_flag, + int subframeP, unsigned char sched_subframe, Protocol__FlexranMessage **ul_info); /// Notify the controller for a state change of a particular UE, by sending the proper /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index e3f96c05dc..e56ebdfd22 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -397,6 +397,11 @@ int flexran_agent_control_delegation(mid_t mod_id, const void *params, Protocol_ status = mkdir(local_cache, S_IRWXU | S_IRWXG | S_IRWXO); + if (status < 0){ + + LOG_W(ENB_APP, "Couldn't create local cache!"); + } + FILE *f; f = fopen(target, "wb"); fwrite(control_delegation_msg->payload.data, control_delegation_msg->payload.len, 1, f); diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 10b667e916..a22b6cb061 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -317,7 +317,7 @@ int flexran_get_harq(const mid_t mod_id, } else if (harq_flag == openair_harq_UL){ - mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&round,openair_harq_UL); + mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,round,openair_harq_UL); } else { diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 668c0e6ba0..33def5e09a 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -314,3 +314,6 @@ int flexran_agent_get_operating_pdsch_refpower (mid_t mod_id, int cc_id); /*Get uplink power*/ int flexran_agent_get_operating_pusch_p0 (mid_t mod_id, int cc_id); + +/*RRC status flexRAN*/ +int flexran_get_rrc_status(const mid_t mod_id, const rnti_t rntiP); \ No newline at end of file diff --git a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h index 5fc53fece6..59bef52dba 100644 --- a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h +++ b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h @@ -163,6 +163,15 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, uint16_t *first_rb); +void flexran_agent_schedule_ulsch_rnti(module_id_t module_idP, + unsigned char cooperation_flag, + frame_t frameP, + sub_frame_t subframeP, + unsigned char sched_subframe, + uint16_t *first_rb); + +/* Downlink Primitives */ + void _dlsch_scheduler_pre_processor (module_id_t Mod_id, int slice_id, frame_t frameP, diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index 02fe873144..601310d67a 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -788,7 +788,7 @@ flexran_schedule_ue_dl_spec_default(mid_t mod_id, slice_maxmcs_current[i] = slice_maxmcs[i]; } else { - LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice max mcs %d, revert the previous value %d\n",mod_id, i, slice_percentage[i],slice_percentage[i]); + // LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice max mcs %d, revert the previous value %d\n",mod_id, i, slice_maxmcs[i],slice_percentage[i]); slice_maxmcs[i]= slice_maxmcs_current[i]; @@ -1253,7 +1253,7 @@ flexran_schedule_ue_dl_spec_common(mid_t mod_id, header_len += 3; // Need to see if we have space for data from this channel if (dci_tbs - ta_len - header_len - sdu_length_total > 0) { - LOG_D(MAC, "[TEST]Requested %d bytes from RLC buffer on channel %d during first call\n", dci_tbs-ta_len-header_len); + LOG_D(MAC, "[TEST]Requested %d bytes from RLC buffer on channel %d during first call\n", dci_tbs-ta_len-header_len, j); //If we have space, we need to see how much data we can request at most (if any available) rlc_status = mac_rlc_status_ind(mod_id, rnti, diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index 4038ae518b..5b31c11681 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -49,14 +49,22 @@ #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" //#include "LAYER2/MAC/pre_processor.c" +#include "ENB_APP/flexran_agent_defs.h" +#include "flexran_agent_ran_api.h" #include "pdcp.h" +#include "header.pb-c.h" +#include "flexran.pb-c.h" +#include "flexran_agent_mac.h" + #if defined(ENABLE_ITTI) # include "intertask_interface.h" #endif #include "T.h" +#include + /* number of active slices for past and current time*/ int n_active_slices_uplink = 1; int n_active_slices_uplink_current = 1; @@ -222,7 +230,7 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, rnti_t rnti= -1; UE_list_t *UE_list = &eNB_mac_inst[module_idP].UE_list; UE_TEMPLATE *UE_template = 0; - LTE_DL_FRAME_PARMS *frame_parms = 0; + // LTE_DL_FRAME_PARMS *frame_parms; //Not used yet UE_sched_ctrl *ue_sched_ctl; @@ -272,7 +280,7 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, CC_id = UE_list->ordered_ULCCids[n][UE_id]; UE_template = &UE_list->UE_template[CC_id][UE_id]; average_rbs_per_user[CC_id]=0; - frame_parms = mac_xface->get_lte_frame_parms(module_idP,CC_id); + // frame_parms = mac_xface->get_lte_frame_parms(module_idP,CC_id); if (UE_template->pre_allocated_nb_rb_ul > 0) { total_ue_count+=1; @@ -359,7 +367,7 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, // This is the actual CC_id in the list CC_id = UE_list->ordered_ULCCids[n][UE_id]; UE_template = &UE_list->UE_template[CC_id][UE_id]; - frame_parms = mac_xface->get_lte_frame_parms(module_idP,CC_id); + // frame_parms = mac_xface->get_lte_frame_parms(module_idP,CC_id); total_remaining_rbs[CC_id]=nb_rbs_allowed_slice_uplink[CC_id][UE_id] - first_rb[CC_id] - total_allocated_rbs[CC_id]; if (total_ue_count == 1 ) { @@ -384,7 +392,7 @@ void _ulsch_scheduler_pre_processor(module_id_t module_idP, } for (CC_id=0; CC_idget_lte_frame_parms(module_idP,CC_id); + // frame_parms= mac_xface->get_lte_frame_parms(module_idP,CC_id); if (total_allocated_rbs[CC_id]>0) { LOG_D(MAC,"[eNB %d] total RB allocated for all UEs = %d/%d\n", module_idP, total_allocated_rbs[CC_id], nb_rbs_allowed_slice_uplink[CC_id][slice_id] - first_rb[CC_id]); From c3adbb954510cb0b9eb22e5c58ba4ab7558b6a1c Mon Sep 17 00:00:00 2001 From: shahab SHARIAT BAGHERI Date: Wed, 9 Aug 2017 22:46:42 +0200 Subject: [PATCH 034/284] warnings --- openair2/ENB_APP/flexran_agent_net_comm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/ENB_APP/flexran_agent_net_comm.c b/openair2/ENB_APP/flexran_agent_net_comm.c index 6e39d6089f..f8e350d6a9 100644 --- a/openair2/ENB_APP/flexran_agent_net_comm.c +++ b/openair2/ENB_APP/flexran_agent_net_comm.c @@ -118,7 +118,7 @@ int flexran_agent_create_channel(void *channel_info, /*element should be a real pointer*/ RB_INSERT(flexran_agent_channel_map, &channel_instance.flexran_agent_head, channel); - LOG_I(FLEXRAN_AGENT,"Created a new channel with id 0x%lx\n", channel->channel_id); + LOG_I(FLEXRAN_AGENT,"Created a new channel with id %d \n", channel->channel_id); return channel_id; } From ba11d72b63155821748c879c18ae03aba6416270 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 17 Oct 2017 12:26:43 +0200 Subject: [PATCH 035/284] minor: add some documentation for bandrich dongle and NetworkManager --- cmake_targets/autotests/v2/actions/bandrich.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cmake_targets/autotests/v2/actions/bandrich.txt b/cmake_targets/autotests/v2/actions/bandrich.txt index 8533750c5b..faa294465b 100644 --- a/cmake_targets/autotests/v2/actions/bandrich.txt +++ b/cmake_targets/autotests/v2/actions/bandrich.txt @@ -13,6 +13,16 @@ containing lines: SUBSYSTEM=="tty", ENV{ID_VENDOR_ID}=="1a8d", ENV{ID_MODEL_ID}=="100d", ENV{ID_SERIAL_SHORT}=="357473040068155", ENV{ID_USB_INTERFACE_NUM}=="00", SYMLINK+="bandrich.data", MODE="0666" SUBSYSTEM=="tty", ENV{ID_VENDOR_ID}=="1a8d", ENV{ID_MODEL_ID}=="100d", ENV{ID_SERIAL_SHORT}=="357473040068155", ENV{ID_USB_INTERFACE_NUM}=="02", SYMLINK+="bandrich.control", MODE="0666" +To avoid NetworkManager to play with the bandrich, add also the line: + + ENV{ID_VENDOR_ID}=="1a8d", ENV{ID_MM_DEVICE_IGNORE}="1" + +Maybe also add; , ENV{ID_MM_DEVICE_IGNORE}="1" +to the two other lines. + +Then run: udevadm control --reload-rules +And: service network-manager restart + Change vendor_id/model_id/serial/interface num to match yours. Use lsusb -v to find values. From ac54521aed853a5d19bb71be6c36d85ad527a0c2 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 17 Oct 2017 12:31:35 +0200 Subject: [PATCH 036/284] do not put random bits in DCI, put 0 instead (to avoid false DCI detections) --- openair1/PHY/LTE_TRANSPORT/dci.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index b06f69181f..3a42a4c5ea 100755 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -2257,11 +2257,18 @@ uint8_t generate_dci_top(uint8_t num_pdcch_symbols, y[0] = &yseq0[0]; y[1] = &yseq1[0]; +#if 0 // reset all bits to , here we set elements as 2 // memset(e, 2, DCI_BITS_MAX); // here we interpret NIL as a random QPSK sequence. That makes power estimation easier. for (i=0; i Date: Tue, 17 Oct 2017 13:16:44 +0200 Subject: [PATCH 037/284] T: add -rb option to enb tracer --- common/utils/T/tracer/enb.c | 57 ++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/common/utils/T/tracer/enb.c b/common/utils/T/tracer/enb.c index 80093eb848..fdc54e1c59 100644 --- a/common/utils/T/tracer/enb.c +++ b/common/utils/T/tracer/enb.c @@ -94,6 +94,7 @@ typedef struct { enb_gui *e; int ue; /* what UE is displayed in the UE specific views */ void *database; + int nb_rb; } enb_data; void is_on_changed(void *_d) @@ -121,27 +122,6 @@ connection_dies: if (pthread_mutex_unlock(&d->lock)) abort(); } -void usage(void) -{ - printf( -"options:\n" -" -d this option is mandatory\n" -" -on turn log ON for given GROUP or ID\n" -" -off turn log OFF for given GROUP or ID\n" -" -ON turn all logs ON\n" -" -OFF turn all logs OFF\n" -" note: you may pass several -on/-off/-ON/-OFF,\n" -" they will be processed in order\n" -" by default, all is off\n" -" -ip connect to given IP address (default %s)\n" -" -p connect to given port (default %d)\n" -" -debug-gui activate GUI debug logs\n", - DEFAULT_REMOTE_IP, - DEFAULT_REMOTE_PORT - ); - exit(1); -} - static void *gui_thread(void *_g) { gui *g = _g; @@ -314,14 +294,14 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database, input_signal_plot = new_xy_plot(g, 256, 55, "input signal", 20); widget_add_child(g, line, input_signal_plot, -1); - xy_plot_set_range(g, input_signal_plot, 0, 7680*10, 20, 70); + xy_plot_set_range(g, input_signal_plot, 0, 7680*10 * ed->nb_rb/25, 20, 70); input_signal_log = new_framelog(h, database, "ENB_PHY_INPUT_SIGNAL", "subframe", "rxdata"); /* a skip value of 10 means to process 1 frame over 10, that is * more or less 10 frames per second */ framelog_set_skip(input_signal_log, 10); - input_signal_view = new_view_xy(7680*10, 10, + input_signal_view = new_view_xy(7680*10 * ed->nb_rb/25, 10, g, input_signal_plot, new_color(g, "#0c0c72"), XY_LOOP_MODE); logger_add_view(input_signal_log, input_signal_view); @@ -661,6 +641,28 @@ void view_add_log(view *v, char *log, event_handler *h, void *database, on_off(database, log, is_on, 1); } +void usage(void) +{ + printf( +"options:\n" +" -d this option is mandatory\n" +" -rb setup for this number of RBs (default 25)\n" +" -on turn log ON for given GROUP or ID\n" +" -off turn log OFF for given GROUP or ID\n" +" -ON turn all logs ON\n" +" -OFF turn all logs OFF\n" +" note: you may pass several -on/-off/-ON/-OFF,\n" +" they will be processed in order\n" +" by default, all is off\n" +" -ip connect to given IP address (default %s)\n" +" -p connect to given port (default %d)\n" +" -debug-gui activate GUI debug logs\n", + DEFAULT_REMOTE_IP, + DEFAULT_REMOTE_PORT + ); + exit(1); +} + int main(int n, char **v) { extern int volatile gui_logd; @@ -681,6 +683,8 @@ int main(int n, char **v) reset_ue_ids(); + enb_data.nb_rb = 25; + /* write on a socket fails if the other end is closed and we get SIGPIPE */ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) abort(); @@ -691,6 +695,8 @@ int main(int n, char **v) if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage(); if (!strcmp(v[i], "-d")) { if (i > n-2) usage(); database_filename = v[++i]; continue; } + if (!strcmp(v[i], "-rb")) + { if (i > n-2) usage(); enb_data.nb_rb = atoi(v[++i]); continue; } if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; } if (!strcmp(v[i], "-p")) { if (i > n-2) usage(); port = atoi(v[++i]); continue; } @@ -706,6 +712,11 @@ int main(int n, char **v) usage(); } + switch (enb_data.nb_rb) { + case 25: case 50: case 100: break; + default: printf("ERROR, bad value for -rb (%d)\n", enb_data.nb_rb); exit(1); + } + if (database_filename == NULL) { printf("ERROR: provide a database file (-d)\n"); exit(1); From f1f31a7861c889dddf52fd671b7980a8e4ced906 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 17 Oct 2017 16:19:45 +0200 Subject: [PATCH 038/284] minor: cleanup spacing --- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 781 +++++++++++----------- 1 file changed, 376 insertions(+), 405 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 5b9c025442..6d52f3fc22 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -64,16 +64,15 @@ uint8_t rb_table[34] = {1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36,40,45,48,50,54,60,64,72,75,80,81,90,96,100}; void rx_sdu(const module_id_t enb_mod_idP, - const int CC_idP, - const frame_t frameP, - const sub_frame_t subframeP, - const rnti_t rntiP, - uint8_t *sduP, - const uint16_t sdu_lenP, - const uint16_t timing_advance, - const uint8_t ul_cqi) { - - + const int CC_idP, + const frame_t frameP, + const sub_frame_t subframeP, + const rnti_t rntiP, + uint8_t *sduP, + const uint16_t sdu_lenP, + const uint16_t timing_advance, + const uint8_t ul_cqi) +{ unsigned char rx_ces[MAX_NUM_CE],num_ce,num_sdu,i,*payload_ptr; unsigned char rx_lcids[NB_RB_MAX]; unsigned short rx_lengths[NB_RB_MAX]; @@ -82,7 +81,7 @@ void rx_sdu(const module_id_t enb_mod_idP, int ii,j; eNB_MAC_INST *eNB = RC.mac[enb_mod_idP]; int harq_pid = subframe2harqpid(&eNB->common_channels[CC_idP],frameP,subframeP); - + UE_list_t *UE_list= &eNB->UE_list; int crnti_rx=0; int old_buffer_info; @@ -100,18 +99,16 @@ void rx_sdu(const module_id_t enb_mod_idP, if (opt_enabled == 1) { trace_pdu(0, sduP,sdu_lenP, 0, 3, rntiP, frameP, subframeP, 0,0); LOG_D(OPT,"[eNB %d][ULSCH] Frame %d rnti %x with size %d\n", - enb_mod_idP, frameP, rntiP, sdu_lenP); + enb_mod_idP, frameP, rntiP, sdu_lenP); } - if (UE_id!=-1) { - LOG_D(MAC,"[eNB %d][PUSCH %d] CC_id %d Received ULSCH sdu round %d from PHY (rnti %x, UE_id %d) ul_cqi %d\n",enb_mod_idP,harq_pid,CC_idP, UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid], - rntiP,UE_id,ul_cqi); + rntiP,UE_id,ul_cqi); AssertFatal(UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] < 8, - "round >= 8\n"); - if (sduP!=NULL) { + "round >= 8\n"); + if (sduP!=NULL) { UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer = 0; UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= (~(1<UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid],ul_cqi); + UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid],ul_cqi); // AssertFatal(1==0,"ulsch in error\n"); if (UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] == 3) { - UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= (~(1<UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid]=0; - if (UE_list->UE_sched_ctrl[UE_id].ul_consecutive_errors++ == 10) + UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= (~(1<UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid]=0; + if (UE_list->UE_sched_ctrl[UE_id].ul_consecutive_errors++ == 10) UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 1; } else UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid]++; @@ -145,21 +142,21 @@ void rx_sdu(const module_id_t enb_mod_idP, } else if ((RA_id = find_RA_id(enb_mod_idP,CC_idP,rntiP))!=-1) { // Check if this is an RA process for the rnti AssertFatal(eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx>1, - "maxHARQ %d should be greater than 1\n", - (int)eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx); + "maxHARQ %d should be greater than 1\n", + (int)eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx); LOG_D(MAC,"[eNB %d][PUSCH %d] CC_id %d Received ULSCH sdu round %d from PHY (rnti %x, RA_id %d) ul_cqi %d\n",enb_mod_idP,harq_pid,CC_idP, RA_template[RA_id].msg3_round, rntiP,RA_id,ul_cqi); - first_rb = RA_template->msg3_first_rb; + first_rb = RA_template->msg3_first_rb; if (sduP==NULL) { // we've got an error on Msg3 LOG_D(MAC,"[eNB %d] CC_id %d, RA %d ULSCH in error in round %d/%d\n",enb_mod_idP,CC_idP,RA_id, - RA_template[RA_id].msg3_round, - (int)eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx); - if (RA_template[RA_id].msg3_round == eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx-1) { - cancel_ra_proc(enb_mod_idP,CC_idP,frameP,rntiP); + RA_template[RA_id].msg3_round, + (int)eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx); + if (RA_template[RA_id].msg3_round == eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx-1) { + cancel_ra_proc(enb_mod_idP,CC_idP,frameP,rntiP); } else { @@ -196,7 +193,7 @@ void rx_sdu(const module_id_t enb_mod_idP, T(T_ENB_MAC_UE_UL_CE, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(rntiP), T_INT(frameP), T_INT(subframeP), T_INT(rx_ces[i])); - + switch (rx_ces[i]) { // implement and process BSR + CRNTI + case POWER_HEADROOM: if (UE_id != -1) { @@ -204,7 +201,7 @@ void rx_sdu(const module_id_t enb_mod_idP, LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : Received PHR PH = %d (db)\n", enb_mod_idP, CC_idP, rx_ces[i], UE_list->UE_template[CC_idP][UE_id].phr_info); UE_list->UE_template[CC_idP][UE_id].phr_info_configured=1; - UE_list->UE_sched_ctrl[UE_id].phr_received = 1; + UE_list->UE_sched_ctrl[UE_id].phr_received = 1; } payload_ptr+=sizeof(POWER_HEADROOM_CMD); break; @@ -238,31 +235,31 @@ abort(); lcgid = (payload_ptr[0] >> 6); LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", - enb_mod_idP, CC_idP, rx_ces[i], lcgid, payload_ptr[0] & 0x3f); + enb_mod_idP, CC_idP, rx_ces[i], lcgid, payload_ptr[0] & 0x3f); if (crnti_rx==1) - LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", - enb_mod_idP, CC_idP, rx_ces[i], lcgid, payload_ptr[0] & 0x3f); + LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", + enb_mod_idP, CC_idP, rx_ces[i], lcgid, payload_ptr[0] & 0x3f); if (UE_id != -1) { UE_list->UE_template[CC_idP][UE_id].bsr_info[lcgid] = (payload_ptr[0] & 0x3f); - // update buffer info - - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[lcgid]]; + // update buffer info - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]; + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[lcgid]]; - RC.eNB[enb_mod_idP][CC_idP]->pusch_stats_bsr[UE_id][(frameP*10)+subframeP] = (payload_ptr[0] & 0x3f); - if (UE_id == UE_list->head) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR,RC.eNB[enb_mod_idP][CC_idP]->pusch_stats_bsr[UE_id][(frameP*10)+subframeP]); + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]; + + RC.eNB[enb_mod_idP][CC_idP]->pusch_stats_bsr[UE_id][(frameP*10)+subframeP] = (payload_ptr[0] & 0x3f); + if (UE_id == UE_list->head) + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR,RC.eNB[enb_mod_idP][CC_idP]->pusch_stats_bsr[UE_id][(frameP*10)+subframeP]); if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[lcgid] == 0 ) { UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[lcgid]=frameP; } - if (mac_eNB_get_rrc_status(enb_mod_idP,UE_RNTI(enb_mod_idP,UE_id)) < RRC_CONNECTED) - LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : ul_total_buffer = %d (lcg increment %d)\n", - enb_mod_idP, CC_idP, rx_ces[i], UE_list->UE_template[CC_idP][UE_id].ul_total_buffer, - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]); + if (mac_eNB_get_rrc_status(enb_mod_idP,UE_RNTI(enb_mod_idP,UE_id)) < RRC_CONNECTED) + LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : ul_total_buffer = %d (lcg increment %d)\n", + enb_mod_idP, CC_idP, rx_ces[i], UE_list->UE_template[CC_idP][UE_id].ul_total_buffer, + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]); } else { @@ -280,39 +277,39 @@ abort(); ((payload_ptr[1] & 0x0F) << 2) | ((payload_ptr[2] & 0xC0) >> 6); UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] = (payload_ptr[2] & 0x3F); - // update buffer info - old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]; - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0]]; + // update buffer info + old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]; + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0]]; - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]; + if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; + else + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; - old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]; - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1]]; - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; + old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]; + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1]]; + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]; + if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; + else + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; - old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]; - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2]]; - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; + old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]; + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2]]; + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]; + if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; + else + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; - old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]; - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3]]; - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; + old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]; + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3]]; + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]; + if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; + else + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " "%u LCGID2 = %u LCGID3 = %u\n", @@ -388,7 +385,7 @@ abort(); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC,1); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC,0); for (ii=0; iicommon_channels[CC_idP].RA_template[ii]; + RA_TEMPLATE *RA_template = &eNB->common_channels[CC_idP].RA_template[ii]; LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Checking proc %d : rnti (%x, %x), active %d\n", enb_mod_idP, CC_idP, ii, @@ -411,53 +408,53 @@ abort(); #endif )) == -1 ) { AssertFatal(1==0,"[MAC][eNB] Max user count reached\n"); - // kill RA procedure + // kill RA procedure } else LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d Added user with rnti %x => UE %d\n", enb_mod_idP,CC_idP,frameP,RA_template->rnti,UE_id); } else { LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3 from already registered UE %d: length %d, offset %ld\n", enb_mod_idP,CC_idP,frameP,UE_id,rx_lengths[i],payload_ptr-sduP); - // kill RA procedure + // kill RA procedure } - mac_rrc_data_ind( - enb_mod_idP, - CC_idP, - frameP,subframeP, - rntiP, - CCCH, - (uint8_t*)payload_ptr, - rx_lengths[i], - ENB_FLAG_YES, - enb_mod_idP, + mac_rrc_data_ind( + enb_mod_idP, + CC_idP, + frameP,subframeP, + rntiP, + CCCH, + (uint8_t*)payload_ptr, + rx_lengths[i], + ENB_FLAG_YES, + enb_mod_idP, 0 ); - - + + if (num_ce >0) { // handle msg3 which is not RRCConnectionRequest // process_ra_message(msg3,num_ce,rx_lcids,rx_ces); } - // prepare transmission of Msg4 + // prepare transmission of Msg4 RA_template->generate_Msg4 = 1; RA_template->wait_ack_Msg4 = 0; - // Program Msg4 PDCCH+DLSCH/MPDCCH transmission 4 subframes from now, // Check if this is ok for BL/CE, or if the rule is different - RA_template->Msg4_frame = frameP + ((subframeP>5) ? 1 : 0); - RA_template->Msg4_subframe = (subframeP+4)%10; - + // Program Msg4 PDCCH+DLSCH/MPDCCH transmission 4 subframes from now, // Check if this is ok for BL/CE, or if the rule is different + RA_template->Msg4_frame = frameP + ((subframeP>5) ? 1 : 0); + RA_template->Msg4_subframe = (subframeP+4)%10; + } // if process is active } // loop on RA processes - + break ; case DCCH : case DCCH1 : // if(eNB_mac_inst[module_idP][CC_idP].Dcch_lchan[UE_id].Active==1){ - + #if defined(ENABLE_MAC_PAYLOAD_DEBUG) LOG_T(MAC,"offset: %d\n",(unsigned char)((unsigned char*)payload_ptr-sduP)); @@ -468,35 +465,35 @@ abort(); #endif if (UE_id != -1) { - // adjust buffer occupancy of the correponding logical channel group - if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] >= rx_lengths[i]) - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] -= rx_lengths[i]; - else - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] = 0; + // adjust buffer occupancy of the correponding logical channel group + if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] >= rx_lengths[i]) + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] -= rx_lengths[i]; + else + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] = 0; LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DCCH, received %d bytes form UE %d on LCID %d \n", enb_mod_idP,CC_idP,frameP, rx_lengths[i], UE_id, rx_lcids[i]); mac_rlc_data_ind( - enb_mod_idP, - rntiP, - enb_mod_idP, - frameP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - rx_lcids[i], - (char *)payload_ptr, - rx_lengths[i], - 1, - NULL);//(unsigned int*)crc_status); + enb_mod_idP, + rntiP, + enb_mod_idP, + frameP, + ENB_FLAG_YES, + MBMS_FLAG_NO, + rx_lcids[i], + (char *)payload_ptr, + rx_lengths[i], + 1, + NULL);//(unsigned int*)crc_status); UE_list->eNB_UE_stats[CC_idP][UE_id].num_pdu_rx[rx_lcids[i]]+=1; UE_list->eNB_UE_stats[CC_idP][UE_id].num_bytes_rx[rx_lcids[i]]+=rx_lengths[i]; } /* UE_id != -1 */ - - // } + + // } break; // all the DRBS @@ -511,67 +508,67 @@ abort(); LOG_T(MAC,"\n"); #endif if (rx_lcids[i] < NB_RB_MAX ) { - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d\n", - enb_mod_idP,CC_idP,frameP, rx_lengths[i], UE_id, rx_lcids[i]); - - if (UE_id != -1) { - // adjust buffer occupancy of the correponding logical channel group - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d, removing from LCGID %ld, %d\n", - enb_mod_idP,CC_idP,frameP, rx_lengths[i], UE_id,rx_lcids[i], - UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]], - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]]); - - if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] >= rx_lengths[i]) - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] -= rx_lengths[i]; - else - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] = 0; - if ((rx_lengths[i] 0) ) { // MAX SIZE OF transport block - mac_rlc_data_ind( - enb_mod_idP, - rntiP, - enb_mod_idP, - frameP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - rx_lcids[i], - (char *)payload_ptr, - rx_lengths[i], - 1, - NULL);//(unsigned int*)crc_status); - - UE_list->eNB_UE_stats[CC_idP][UE_id].num_pdu_rx[rx_lcids[i]]+=1; - UE_list->eNB_UE_stats[CC_idP][UE_id].num_bytes_rx[rx_lcids[i]]+=rx_lengths[i]; - } - else { /* rx_length[i] */ - UE_list->eNB_UE_stats[CC_idP][UE_id].num_errors_rx+=1; - LOG_E(MAC,"[eNB %d] CC_id %d Frame %d : Max size of transport block reached LCID %d from UE %d ", - enb_mod_idP, CC_idP, frameP, rx_lcids[i], UE_id); - } - } - else {/*(UE_id != -1*/ - LOG_E(MAC,"[eNB %d] CC_id %d Frame %d : received unsupported or unknown LCID %d from UE %d ", - enb_mod_idP, CC_idP, frameP, rx_lcids[i], UE_id); - } + LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d\n", + enb_mod_idP,CC_idP,frameP, rx_lengths[i], UE_id, rx_lcids[i]); + + if (UE_id != -1) { + // adjust buffer occupancy of the correponding logical channel group + LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d, removing from LCGID %ld, %d\n", + enb_mod_idP,CC_idP,frameP, rx_lengths[i], UE_id,rx_lcids[i], + UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]], + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]]); + + if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] >= rx_lengths[i]) + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] -= rx_lengths[i]; + else + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] = 0; + if ((rx_lengths[i] 0) ) { // MAX SIZE OF transport block + mac_rlc_data_ind( + enb_mod_idP, + rntiP, + enb_mod_idP, + frameP, + ENB_FLAG_YES, + MBMS_FLAG_NO, + rx_lcids[i], + (char *)payload_ptr, + rx_lengths[i], + 1, + NULL);//(unsigned int*)crc_status); + + UE_list->eNB_UE_stats[CC_idP][UE_id].num_pdu_rx[rx_lcids[i]]+=1; + UE_list->eNB_UE_stats[CC_idP][UE_id].num_bytes_rx[rx_lcids[i]]+=rx_lengths[i]; + } + else { /* rx_length[i] */ + UE_list->eNB_UE_stats[CC_idP][UE_id].num_errors_rx+=1; + LOG_E(MAC,"[eNB %d] CC_id %d Frame %d : Max size of transport block reached LCID %d from UE %d ", + enb_mod_idP, CC_idP, frameP, rx_lcids[i], UE_id); + } + } + else {/*(UE_id != -1*/ + LOG_E(MAC,"[eNB %d] CC_id %d Frame %d : received unsupported or unknown LCID %d from UE %d ", + enb_mod_idP, CC_idP, frameP, rx_lcids[i], UE_id); + } } break; } - + payload_ptr+=rx_lengths[i]; } // Program ACK for PHICH LOG_D(MAC,"Programming PHICH ACK for rnti %x harq_pid %d (first_rb %d)\n",rntiP,harq_pid,first_rb); nfapi_hi_dci0_request_body_t *hi_dci0_req = &eNB->HI_DCI0_req[CC_idP].hi_dci0_request_body; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &hi_dci0_req->hi_dci0_pdu_list[hi_dci0_req->number_of_dci+hi_dci0_req->number_of_hi]; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &hi_dci0_req->hi_dci0_pdu_list[hi_dci0_req->number_of_dci+hi_dci0_req->number_of_hi]; memset((void*)hi_dci0_pdu,0,sizeof(nfapi_hi_dci0_request_pdu_t)); - hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; + hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; hi_dci0_pdu->pdu_size = 2+sizeof(nfapi_hi_dci0_hi_pdu); - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = first_rb; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = first_rb; hi_dci0_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = 0; hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 1; hi_dci0_req->number_of_hi++; - + /* NN--> FK: we could either check the payload, or use a phy helper to detect a false msg3 */ if ((num_sdu == 0) && (num_ce==0)) { if (UE_id != -1) @@ -595,10 +592,8 @@ abort(); stop_meas(&eNB->rx_ulsch_sdu); } - uint32_t bytes_to_bsr_index(int32_t nbytes) { - uint32_t i=0; if (nbytes<0) { @@ -615,13 +610,11 @@ uint32_t bytes_to_bsr_index(int32_t nbytes) void add_ue_ulsch_info(module_id_t module_idP, int CC_id, int UE_id, sub_frame_t subframeP, UE_ULSCH_STATUS status) { - eNB_ulsch_info[module_idP][CC_id][UE_id].rnti = UE_RNTI(module_idP,UE_id); eNB_ulsch_info[module_idP][CC_id][UE_id].subframe = subframeP; eNB_ulsch_info[module_idP][CC_id][UE_id].status = status; eNB_ulsch_info[module_idP][CC_id][UE_id].serving_num++; - } unsigned char *parse_ulsch_header(unsigned char *mac_header, @@ -632,7 +625,6 @@ unsigned char *parse_ulsch_header(unsigned char *mac_header, unsigned short *rx_lengths, unsigned short tb_length) { - unsigned char not_done=1,num_ces=0,num_sdus=0,lcid,num_sdu_cnt; unsigned char *mac_header_ptr = mac_header; unsigned short length, ce_len=0; @@ -721,14 +713,10 @@ void set_msg3_subframe(module_id_t Mod_id, } -void schedule_ulsch(module_id_t module_idP, - frame_t frameP, - sub_frame_t subframeP) { - - - - - +void schedule_ulsch(module_id_t module_idP, + frame_t frameP, + sub_frame_t subframeP) +{ uint16_t first_rb[MAX_NUM_CCs],i; int CC_id; eNB_MAC_INST *eNB=RC.mac[module_idP]; @@ -736,7 +724,6 @@ void schedule_ulsch(module_id_t module_idP, start_meas(&eNB->schedule_ulsch); - int sched_subframe = (subframeP+4)%10; cc = &eNB->common_channels[0]; @@ -747,13 +734,13 @@ void schedule_ulsch(module_id_t module_idP, switch (subframeP) { case 0: if ((tdd_sfa == 0)|| - (tdd_sfa == 3)|| - (tdd_sfa == 6)) sched_subframe = 4; + (tdd_sfa == 3)|| + (tdd_sfa == 6)) sched_subframe = 4; else return; break; case 1: if ((tdd_sfa==0)|| - (tdd_sfa==1)) sched_subframe = 7; + (tdd_sfa==1)) sched_subframe = 7; else if (tdd_sfa==6) sched_subframe = 8; break; default: @@ -812,7 +799,7 @@ void schedule_ulsch(module_id_t module_idP, // Msg3 is using 1 PRB so we need to increase first_rb accordingly // not sure about the break (can there be more than 1 active RA procedure?) - + for (i=0; iRA_template[i].RA_active == TRUE) && (cc->RA_template[i].generate_rar == 0) && @@ -820,7 +807,7 @@ void schedule_ulsch(module_id_t module_idP, (cc->RA_template[i].wait_ack_Msg4 == 0) && (cc->RA_template[i].Msg3_subframe == sched_subframe)) { first_rb[CC_id]++; - // cc->RA_template[i].Msg3_subframe = -1; + // cc->RA_template[i].Msg3_subframe = -1; break; } } @@ -829,24 +816,20 @@ void schedule_ulsch(module_id_t module_idP, schedule_ulsch_rnti(module_idP, frameP, subframeP, sched_subframe,first_rb); stop_meas(&eNB->schedule_ulsch); - } - - void schedule_ulsch_rnti(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP, unsigned char sched_subframeP, uint16_t *first_rb) { - int UE_id; uint8_t aggregation = 2; rnti_t rnti = -1; uint8_t round = 0; uint8_t harq_pid = 0; - uint8_t status = 0; + uint8_t status = 0; uint8_t rb_table_index = -1; uint32_t cqi_req,cshift,ndi,tpc; int32_t normalized_rx_power; @@ -872,11 +855,9 @@ void schedule_ulsch_rnti(module_id_t module_idP, nfapi_ul_config_request_pdu_t *ul_config_pdu; - - nfapi_ul_config_request_body_t *ul_req_tmp = &eNB->UL_req_tmp[CC_id][sched_subframeP].ul_config_request_body; - ul_config_pdu = &ul_req_tmp->ul_config_pdu_list[0]; + ul_config_pdu = &ul_req_tmp->ul_config_pdu_list[0]; LOG_D(MAC,"entering ulsch preprocesor\n"); @@ -889,14 +870,13 @@ void schedule_ulsch_rnti(module_id_t module_idP, eNB->HI_DCI0_req[CC_id].sfn_sf = (frameP<<4)+subframeP; - // loop over all active UEs for (UE_id=UE_list->head_ul; UE_id>=0; UE_id=UE_list->next_ul[UE_id]) { // don't schedule if Msg4 is not received yet if (UE_list->UE_template[UE_PCCID(module_idP,UE_id)][UE_id].configured==FALSE) { - LOG_D(MAC,"[eNB %d] frame %d subfarme %d, UE %d: not configured, skipping UE scheduling \n", - module_idP,frameP,subframeP,UE_id); + LOG_D(MAC,"[eNB %d] frame %d subfarme %d, UE %d: not configured, skipping UE scheduling \n", + module_idP,frameP,subframeP,UE_id); continue; } @@ -909,11 +889,11 @@ void schedule_ulsch_rnti(module_id_t module_idP, drop_ue = 0; /* let's drop the UE if get_eNB_UE_stats returns NULL when calling it with any of the UE's active UL CCs */ - /* TODO: refine? + /* TODO: refine? for (n=0; nnumactiveULCCs[UE_id]; n++) { CC_id = UE_list->ordered_ULCCids[n][UE_id]; - + if (mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti) == NULL) { LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: no PHY context\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id); drop_ue = 1; @@ -949,25 +929,23 @@ abort(); N_RB_UL = to_prb(cc[CC_id].ul_Bandwidth); /* - aggregation=get_aggregation(get_bw_index(module_idP,CC_id), - eNB_UE_stats->dl_cqi, - format0); + aggregation=get_aggregation(get_bw_index(module_idP,CC_id), + eNB_UE_stats->dl_cqi, + format0); */ if (CCE_allocation_infeasible(module_idP,CC_id,1,subframeP,aggregation,rnti)) { LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: not enough nCCE\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id); continue; // break; - } + } /* be sure that there are some free RBs */ if (first_rb[CC_id] >= N_RB_UL-1) { - LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: dropping, not enough RBs\n", - module_idP,frameP,subframeP,UE_id,rnti,CC_id); + LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: dropping, not enough RBs\n", + module_idP,frameP,subframeP,UE_id,rnti,CC_id); continue; } - - // if (eNB_UE_stats->mode == PUSCH) { // ue has a ulsch channel UE_template = &UE_list->UE_template[CC_id][UE_id]; @@ -975,261 +953,255 @@ abort(); harq_pid = subframe2harqpid(&cc[CC_id],sched_frame,sched_subframeP); round = UE_sched_ctrl->round_UL[CC_id][harq_pid]; AssertFatal(round<8,"round %d > 7 for UE %d/%x\n",round,UE_id,rnti); - LOG_D(MAC,"[eNB %d] frame %d subframe %d,Checking PUSCH %d for UE %d/%x CC %d : aggregation level %d, N_RB_UL %d\n", - module_idP,frameP,subframeP,harq_pid,UE_id,rnti,CC_id, aggregation,N_RB_UL); + LOG_D(MAC,"[eNB %d] frame %d subframe %d,Checking PUSCH %d for UE %d/%x CC %d : aggregation level %d, N_RB_UL %d\n", + module_idP,frameP,subframeP,harq_pid,UE_id,rnti,CC_id, aggregation,N_RB_UL); RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP*10)+subframeP] = UE_template->ul_total_buffer; - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BO,RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP*10)+subframeP]); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BO,RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP*10)+subframeP]); if (UE_is_to_be_scheduled(module_idP,CC_id,UE_id) > 0 || round > 0)// || ((frameP%10)==0)) - // if there is information on bsr of DCCH, DTCH or if there is UL_SR, or if there is a packet to retransmit, or we want to schedule a periodic feedback every 10 frames + // if there is information on bsr of DCCH, DTCH or if there is UL_SR, or if there is a packet to retransmit, or we want to schedule a periodic feedback every 10 frames { - LOG_D(MAC,"[eNB %d][PUSCH %d] Frame %d subframe %d Scheduling UE %d/%x in round %d(SR %d,UL_inactivity timer %d,UL_failure timer %d,cqi_req_timer %d)\n", - module_idP,harq_pid,frameP,subframeP,UE_id,rnti,round,UE_template->ul_SR, - UE_sched_ctrl->ul_inactivity_timer, + LOG_D(MAC,"[eNB %d][PUSCH %d] Frame %d subframe %d Scheduling UE %d/%x in round %d(SR %d,UL_inactivity timer %d,UL_failure timer %d,cqi_req_timer %d)\n", + module_idP,harq_pid,frameP,subframeP,UE_id,rnti,round,UE_template->ul_SR, + UE_sched_ctrl->ul_inactivity_timer, - UE_sched_ctrl->ul_failure_timer, + UE_sched_ctrl->ul_failure_timer, - UE_sched_ctrl->cqi_req_timer); + UE_sched_ctrl->cqi_req_timer); // reset the scheduling request UE_template->ul_SR = 0; status = mac_eNB_get_rrc_status(module_idP,rnti); - if (status < RRC_CONNECTED) - cqi_req = 0; - else if (UE_sched_ctrl->cqi_req_timer>30) { - cqi_req = 1; - UE_sched_ctrl->cqi_req_timer=0; - } - else - cqi_req = 0; - + if (status < RRC_CONNECTED) + cqi_req = 0; + else if (UE_sched_ctrl->cqi_req_timer>30) { + cqi_req = 1; + UE_sched_ctrl->cqi_req_timer=0; + } + else + cqi_req = 0; //power control //compute the expected ULSCH RX power (for the stats) - + // this is the normalized RX power and this should be constant (regardless of mcs normalized_rx_power = UE_sched_ctrl->pusch_snr[CC_id]; target_rx_power = 178; - + // this assumes accumulated tpc - // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out - int32_t framex10psubframe = UE_template->pusch_tpc_tx_frame*10+UE_template->pusch_tpc_tx_subframe; + // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out + int32_t framex10psubframe = UE_template->pusch_tpc_tx_frame*10+UE_template->pusch_tpc_tx_subframe; if (((framex10psubframe+10)<=(frameP*10+subframeP)) || //normal case - ((framex10psubframe>(frameP*10+subframeP)) && (((10240-framex10psubframe+frameP*10+subframeP)>=10)))) //frame wrap-around - { - UE_template->pusch_tpc_tx_frame=frameP; - UE_template->pusch_tpc_tx_subframe=subframeP; - if (normalized_rx_power>(target_rx_power+4)) { - tpc = 0; //-1 - tpc_accumulated--; - } else if (normalized_rx_power<(target_rx_power-4)) { - tpc = 2; //+1 - tpc_accumulated++; - } else { - tpc = 1; //0 - } - } else { + ((framex10psubframe>(frameP*10+subframeP)) && (((10240-framex10psubframe+frameP*10+subframeP)>=10)))) //frame wrap-around + { + UE_template->pusch_tpc_tx_frame=frameP; + UE_template->pusch_tpc_tx_subframe=subframeP; + if (normalized_rx_power>(target_rx_power+4)) { + tpc = 0; //-1 + tpc_accumulated--; + } else if (normalized_rx_power<(target_rx_power-4)) { + tpc = 2; //+1 + tpc_accumulated++; + } else { + tpc = 1; //0 + } + } else { tpc = 1; //0 } - //tpc = 1; - if (tpc!=1) { - LOG_D(MAC,"[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", - module_idP,frameP,subframeP,harq_pid,tpc, - tpc_accumulated,normalized_rx_power,target_rx_power); - } - + //tpc = 1; + if (tpc!=1) { + LOG_D(MAC,"[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", + module_idP,frameP,subframeP,harq_pid,tpc, + tpc_accumulated,normalized_rx_power,target_rx_power); + } + // new transmission if (round==0) { - + ndi = 1-UE_template->oldNDI_UL[harq_pid]; UE_template->oldNDI_UL[harq_pid]=ndi; - UE_list->eNB_UE_stats[CC_id][UE_id].normalized_rx_power=normalized_rx_power; - UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power=target_rx_power; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=UE_template->pre_assigned_mcs_ul; + UE_list->eNB_UE_stats[CC_id][UE_id].normalized_rx_power=normalized_rx_power; + UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power=target_rx_power; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=UE_template->pre_assigned_mcs_ul; UE_template->mcs_UL[harq_pid] = UE_template->pre_assigned_mcs_ul;//cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS if (UE_template->pre_allocated_rb_table_index_ul >=0) { rb_table_index=UE_template->pre_allocated_rb_table_index_ul; } else { - UE_template->mcs_UL[harq_pid]=10;//cmin (10, openair_daq_vars.target_ue_ul_mcs); + UE_template->mcs_UL[harq_pid]=10;//cmin (10, openair_daq_vars.target_ue_ul_mcs); rb_table_index=5; // for PHR - } - + } + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=UE_template->mcs_UL[harq_pid]; - // buffer_occupancy = UE_template->ul_total_buffer; + // buffer_occupancy = UE_template->ul_total_buffer; + - while (((rb_table[rb_table_index]>(N_RB_UL-1-first_rb[CC_id])) || - (rb_table[rb_table_index]>45)) && + (rb_table[rb_table_index]>45)) && (rb_table_index>0)) { rb_table_index--; } - + UE_template->TBS_UL[harq_pid] = get_TBS_UL(UE_template->mcs_UL[harq_pid],rb_table[rb_table_index]); - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=rb_table[rb_table_index]; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_TBS=UE_template->TBS_UL[harq_pid]; - // buffer_occupancy -= TBS; - + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=rb_table[rb_table_index]; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_TBS=UE_template->TBS_UL[harq_pid]; + // buffer_occupancy -= TBS; + T(T_ENB_MAC_UE_UL_SCHEDULE, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(UE_template->mcs_UL[harq_pid]), T_INT(first_rb[CC_id]), T_INT(rb_table[rb_table_index]), T_INT(UE_template->TBS_UL[harq_pid]), T_INT(ndi)); - - if (mac_eNB_get_rrc_status(module_idP,rnti) < RRC_CONNECTED) - LOG_D(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE %d (mcs %d, first rb %d, nb_rb %d, rb_table_index %d, TBS %d, harq_pid %d)\n", - module_idP,harq_pid,rnti,CC_id,frameP,subframeP,UE_id,UE_template->mcs_UL[harq_pid], - first_rb[CC_id],rb_table[rb_table_index], - rb_table_index,UE_template->TBS_UL[harq_pid],harq_pid); - - // bad indices : 20 (40 PRB), 21 (45 PRB), 22 (48 PRB) + + if (mac_eNB_get_rrc_status(module_idP,rnti) < RRC_CONNECTED) + LOG_D(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE %d (mcs %d, first rb %d, nb_rb %d, rb_table_index %d, TBS %d, harq_pid %d)\n", + module_idP,harq_pid,rnti,CC_id,frameP,subframeP,UE_id,UE_template->mcs_UL[harq_pid], + first_rb[CC_id],rb_table[rb_table_index], + rb_table_index,UE_template->TBS_UL[harq_pid],harq_pid); + + // bad indices : 20 (40 PRB), 21 (45 PRB), 22 (48 PRB) //store for possible retransmission UE_template->nb_rb_ul[harq_pid] = rb_table[rb_table_index]; UE_template->first_rb_ul[harq_pid] = first_rb[CC_id]; - - UE_sched_ctrl->ul_scheduled |= (1<head) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_SCHEDULED,UE_sched_ctrl->ul_scheduled); - - // adjust total UL buffer status by TBS, wait for UL sdus to do final update - LOG_D(MAC,"[eNB %d] CC_id %d UE %d/%x : adjusting ul_total_buffer, old %d, TBS %d\n", module_idP,CC_id,UE_id,rnti,UE_template->ul_total_buffer,UE_template->TBS_UL[harq_pid]); - if (UE_template->ul_total_buffer > UE_template->TBS_UL[harq_pid]) - UE_template->ul_total_buffer -= UE_template->TBS_UL[harq_pid]; - else - UE_template->ul_total_buffer = 0; - LOG_D(MAC,"ul_total_buffer, new %d\n", UE_template->ul_total_buffer); - // Cyclic shift for DM RS - cshift = 0;// values from 0 to 7 can be used for mapping the cyclic shift (36.211 , Table 5.5.2.1.1-1) - // save it for a potential retransmission - UE_template->cshift[harq_pid] = cshift; - hi_dci0_pdu = &hi_dci0_req->hi_dci0_pdu_list[eNB->HI_DCI0_req[CC_id].hi_dci0_request_body.number_of_dci+eNB->HI_DCI0_req[CC_id].hi_dci0_request_body.number_of_hi]; - memset((void*)hi_dci0_pdu,0,sizeof(nfapi_hi_dci0_request_pdu_t)); - hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE; - hi_dci0_pdu->pdu_size = 2+sizeof(nfapi_hi_dci0_dci_pdu); - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dci_format = NFAPI_UL_DCI_FORMAT_0; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level = aggregation; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti = rnti; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.transmission_power = 6000; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.resource_block_start = first_rb[CC_id]; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.number_of_resource_block = rb_table[rb_table_index]; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.mcs_1 = UE_template->mcs_UL[harq_pid]; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.cyclic_shift_2_for_drms = cshift; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.frequency_hopping_enabled_flag = 0; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.new_data_indication_1 = ndi; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tpc = tpc; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.cqi_csi_request = cqi_req; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dl_assignment_index = UE_template->DAI_ul[sched_subframeP]; + UE_sched_ctrl->ul_scheduled |= (1<head) + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_SCHEDULED,UE_sched_ctrl->ul_scheduled); - - eNB->HI_DCI0_req[CC_id].hi_dci0_request_body.number_of_dci++; - - LOG_D(MAC,"[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n", - harq_pid,frameP,subframeP,UE_id,rnti,sched_frame,sched_subframeP); - - // Add UL_config PDUs - fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], - cqi_req, - cc, - UE_template->physicalConfigDedicated, - get_tmode(module_idP,CC_id,UE_id), - eNB->ul_handle, - rnti, - first_rb[CC_id], // resource_block_start - rb_table[rb_table_index], // number_of_resource_blocks - UE_template->mcs_UL[harq_pid], - cshift, // cyclic_shift_2_for_drms - 0, // frequency_hopping_enabled_flag - 0, // frequency_hopping_bits - ndi, // new_data_indication - 0, // redundancy_version - harq_pid, // harq_process_number - 0, // ul_tx_mode - 0, // current_tx_nb - 0, // n_srs - get_TBS_UL(UE_template->mcs_UL[harq_pid], - rb_table[rb_table_index]) - ); + // adjust total UL buffer status by TBS, wait for UL sdus to do final update + LOG_D(MAC,"[eNB %d] CC_id %d UE %d/%x : adjusting ul_total_buffer, old %d, TBS %d\n", module_idP,CC_id,UE_id,rnti,UE_template->ul_total_buffer,UE_template->TBS_UL[harq_pid]); + if (UE_template->ul_total_buffer > UE_template->TBS_UL[harq_pid]) + UE_template->ul_total_buffer -= UE_template->TBS_UL[harq_pid]; + else + UE_template->ul_total_buffer = 0; + LOG_D(MAC,"ul_total_buffer, new %d\n", UE_template->ul_total_buffer); + // Cyclic shift for DM RS + cshift = 0;// values from 0 to 7 can be used for mapping the cyclic shift (36.211 , Table 5.5.2.1.1-1) + // save it for a potential retransmission + UE_template->cshift[harq_pid] = cshift; + + hi_dci0_pdu = &hi_dci0_req->hi_dci0_pdu_list[eNB->HI_DCI0_req[CC_id].hi_dci0_request_body.number_of_dci+eNB->HI_DCI0_req[CC_id].hi_dci0_request_body.number_of_hi]; + memset((void*)hi_dci0_pdu,0,sizeof(nfapi_hi_dci0_request_pdu_t)); + hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE; + hi_dci0_pdu->pdu_size = 2+sizeof(nfapi_hi_dci0_dci_pdu); + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dci_format = NFAPI_UL_DCI_FORMAT_0; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level = aggregation; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti = rnti; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.transmission_power = 6000; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.resource_block_start = first_rb[CC_id]; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.number_of_resource_block = rb_table[rb_table_index]; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.mcs_1 = UE_template->mcs_UL[harq_pid]; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.cyclic_shift_2_for_drms = cshift; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.frequency_hopping_enabled_flag = 0; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.new_data_indication_1 = ndi; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tpc = tpc; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.cqi_csi_request = cqi_req; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dl_assignment_index = UE_template->DAI_ul[sched_subframeP]; + + eNB->HI_DCI0_req[CC_id].hi_dci0_request_body.number_of_dci++; + + LOG_D(MAC,"[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n", + harq_pid,frameP,subframeP,UE_id,rnti,sched_frame,sched_subframeP); + + // Add UL_config PDUs + fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], + cqi_req, + cc, + UE_template->physicalConfigDedicated, + get_tmode(module_idP,CC_id,UE_id), + eNB->ul_handle, + rnti, + first_rb[CC_id], // resource_block_start + rb_table[rb_table_index], // number_of_resource_blocks + UE_template->mcs_UL[harq_pid], + cshift, // cyclic_shift_2_for_drms + 0, // frequency_hopping_enabled_flag + 0, // frequency_hopping_bits + ndi, // new_data_indication + 0, // redundancy_version + harq_pid, // harq_process_number + 0, // ul_tx_mode + 0, // current_tx_nb + 0, // n_srs + get_TBS_UL(UE_template->mcs_UL[harq_pid], + rb_table[rb_table_index]) + ); #ifdef Rel14 - if (UE_template->rach_resource_type>0) { // This is a BL/CE UE allocation - fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], - UE_template->rach_resource_type>2 ? 2 : 1, - 1, //total_number_of_repetitions - 1, //repetition_number - (frameP*10)+subframeP); - } + if (UE_template->rach_resource_type>0) { // This is a BL/CE UE allocation + fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], + UE_template->rach_resource_type>2 ? 2 : 1, + 1, //total_number_of_repetitions + 1, //repetition_number + (frameP*10)+subframeP); + } #endif - ul_req_tmp->number_of_pdus++; - eNB->ul_handle++; - - - - add_ue_ulsch_info(module_idP, - CC_id, - UE_id, - subframeP, - S_UL_SCHEDULED); - - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d, subframeP %d: Generated ULSCH DCI for next UE_id %d, format 0\n", module_idP,CC_id,frameP,subframeP,UE_id); + ul_req_tmp->number_of_pdus++; + eNB->ul_handle++; + add_ue_ulsch_info(module_idP, + CC_id, + UE_id, + subframeP, + S_UL_SCHEDULED); + + LOG_D(MAC,"[eNB %d] CC_id %d Frame %d, subframeP %d: Generated ULSCH DCI for next UE_id %d, format 0\n", module_idP,CC_id,frameP,subframeP,UE_id); // increment first rb for next UE allocation first_rb[CC_id]+=rb_table[rb_table_index]; - - } - else { // round > 0 => retransmission + } + else { // round > 0 => retransmission T(T_ENB_MAC_UE_UL_SCHEDULE_RETRANSMISSION, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(UE_template->mcs_UL[harq_pid]), T_INT(first_rb[CC_id]), T_INT(rb_table[rb_table_index]), T_INT(round)); - // fill in NAK information - - hi_dci0_pdu = &hi_dci0_req->hi_dci0_pdu_list[hi_dci0_req->number_of_dci+hi_dci0_req->number_of_hi]; - memset((void*)hi_dci0_pdu,0,sizeof(nfapi_hi_dci0_request_pdu_t)); - hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; - hi_dci0_pdu->pdu_size = 2+sizeof(nfapi_hi_dci0_hi_pdu); - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = UE_template->first_rb_ul[harq_pid]; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = UE_template->cshift[harq_pid]; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 0; - hi_dci0_req->number_of_hi++; + // fill in NAK information + + hi_dci0_pdu = &hi_dci0_req->hi_dci0_pdu_list[hi_dci0_req->number_of_dci+hi_dci0_req->number_of_hi]; + memset((void*)hi_dci0_pdu,0,sizeof(nfapi_hi_dci0_request_pdu_t)); + hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; + hi_dci0_pdu->pdu_size = 2+sizeof(nfapi_hi_dci0_hi_pdu); + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = UE_template->first_rb_ul[harq_pid]; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = UE_template->cshift[harq_pid]; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 0; + hi_dci0_req->number_of_hi++; LOG_D(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled (PHICH) UE %d (mcs %d, first rb %d, nb_rb %d, TBS %d, round %d)\n", module_idP,harq_pid,rnti,CC_id,frameP,subframeP,UE_id,UE_template->mcs_UL[harq_pid], UE_template->first_rb_ul[harq_pid], UE_template->nb_rb_ul[harq_pid], UE_template->TBS_UL[harq_pid],round); - // Add UL_config PDUs - LOG_D(MAC,"[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n", - harq_pid,frameP,subframeP,UE_id,rnti,sched_frame,sched_subframeP); - fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], - cqi_req, - cc, - UE_template->physicalConfigDedicated, - get_tmode(module_idP,CC_id,UE_id), - eNB->ul_handle, - rnti, - UE_template->first_rb_ul[harq_pid], // resource_block_start - UE_template->nb_rb_ul[harq_pid], // number_of_resource_blocks - UE_template->mcs_UL[harq_pid], - cshift, // cyclic_shift_2_for_drms - 0, // frequency_hopping_enabled_flag - 0, // frequency_hopping_bits - UE_template->oldNDI_UL[harq_pid], // new_data_indication - rvidx_tab[round&3], // redundancy_version - harq_pid, // harq_process_number - 0, // ul_tx_mode - 0, // current_tx_nb - 0, // n_srs - UE_template->TBS_UL[harq_pid] - ); + // Add UL_config PDUs + LOG_D(MAC,"[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n", + harq_pid,frameP,subframeP,UE_id,rnti,sched_frame,sched_subframeP); + fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], + cqi_req, + cc, + UE_template->physicalConfigDedicated, + get_tmode(module_idP,CC_id,UE_id), + eNB->ul_handle, + rnti, + UE_template->first_rb_ul[harq_pid], // resource_block_start + UE_template->nb_rb_ul[harq_pid], // number_of_resource_blocks + UE_template->mcs_UL[harq_pid], + cshift, // cyclic_shift_2_for_drms + 0, // frequency_hopping_enabled_flag + 0, // frequency_hopping_bits + UE_template->oldNDI_UL[harq_pid], // new_data_indication + rvidx_tab[round&3], // redundancy_version + harq_pid, // harq_process_number + 0, // ul_tx_mode + 0, // current_tx_nb + 0, // n_srs + UE_template->TBS_UL[harq_pid] + ); #ifdef Rel14 - if (UE_template->rach_resource_type>0) { // This is a BL/CE UE allocation - fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], - UE_template->rach_resource_type>2 ? 2 : 1, - 1, //total_number_of_repetitions - 1, //repetition_number - (frameP*10)+subframeP); - } + if (UE_template->rach_resource_type>0) { // This is a BL/CE UE allocation + fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], + UE_template->rach_resource_type>2 ? 2 : 1, + 1, //total_number_of_repetitions + 1, //repetition_number + (frameP*10)+subframeP); + } #endif - ul_req_tmp->number_of_pdus++; - eNB->ul_handle++; + ul_req_tmp->number_of_pdus++; + eNB->ul_handle++; - }/* - else if (round > 0) { //we schedule a retransmission + }/* + else if (round > 0) { //we schedule a retransmission ndi = UE_template->oldNDI_UL[harq_pid]; @@ -1243,23 +1215,22 @@ abort(); LOG_I(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE retransmission (mcs %d, first rb %d, nb_rb %d, harq_pid %d, round %d)\n", module_idP,UE_id,rnti,CC_id,frameP,subframeP,mcs, first_rb[CC_id],UE_template->nb_rb_ul[harq_pid], - harq_pid, round); + harq_pid, round); rballoc = mac_xface->computeRIV(frame_parms->N_RB_UL, first_rb[CC_id], UE_template->nb_rb_ul[harq_pid]); first_rb[CC_id]+=UE_template->nb_rb_ul[harq_pid]; // increment for next UE allocation - - UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission_rx+=1; - UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx_rx=UE_template->nb_rb_ul[harq_pid]; - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=UE_template->nb_rb_ul[harq_pid]; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=mcs; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; - } - */ - + + UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission_rx+=1; + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx_rx=UE_template->nb_rb_ul[harq_pid]; + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=UE_template->nb_rb_ul[harq_pid]; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=mcs; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; + } + */ + } // UE_is_to_be_scheduled } // loop over UE_id } // loop of CC_id } - From 599ba826a83b2c08fda3d8e3f96bd5fa2c095ef7 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 17 Oct 2017 16:50:40 +0200 Subject: [PATCH 039/284] add some debug tracing --- openair2/PHY_INTERFACE/IF_Module.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openair2/PHY_INTERFACE/IF_Module.c b/openair2/PHY_INTERFACE/IF_Module.c index 0fa5453fe3..b1014e8bde 100644 --- a/openair2/PHY_INTERFACE/IF_Module.c +++ b/openair2/PHY_INTERFACE/IF_Module.c @@ -366,6 +366,14 @@ static void dump_dl(Sched_Rsp_t *d) A("XXXX up tpc_bitmap %d\n", q->tpc_bitmap); A("XXXX up transmission_power %d\n", q->transmission_power); } + if (p->pdu_type == NFAPI_HI_DCI0_HI_PDU_TYPE) { + nfapi_hi_dci0_hi_pdu_rel8_t *q = &p->hi_pdu.hi_pdu_rel8; + A("XXXX up rb start %d\n", q->resource_block_start); + A("XXXX up cs2_drms %d\n", q->cyclic_shift_2_for_drms); + A("XXXX up ack %d\n", q->hi_value); + A("XXXX up i_phich %d\n", q->i_phich); + A("XXXX up power %d\n", q->transmission_power); + } } } From 256c5ab060305d7741330e584d44dfca76eb12ad Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 18 Oct 2017 09:56:29 +0200 Subject: [PATCH 040/284] improve crnti reception (still not correct, we need to reconfigure the UE) TODO: if the UE did random access (followed by a MAC uplink with CRNTI) because none of its scheduling request was granted, then according to 36.321 5.4.4 the UE's MAC will notify RRC to release PUCCH/SRS. According to 36.331 5.3.13 the UE will then apply default configuration for CQI reporting and scheduling requests, which basically means that the CQI requests won't work anymore and that the UE won't do any scheduling request anymore as long as the eNB doesn't reconfigure the UE. We have to take care of this. As the code is, nothing is done and the UE state in the eNB is wrong. --- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 86 +++++++++++++---------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 6d52f3fc22..ee5ae3b584 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -73,10 +73,11 @@ void rx_sdu(const module_id_t enb_mod_idP, const uint16_t timing_advance, const uint8_t ul_cqi) { + int current_rnti = rntiP; unsigned char rx_ces[MAX_NUM_CE],num_ce,num_sdu,i,*payload_ptr; unsigned char rx_lcids[NB_RB_MAX]; unsigned short rx_lengths[NB_RB_MAX]; - int UE_id = find_UE_id(enb_mod_idP,rntiP); + int UE_id = find_UE_id(enb_mod_idP, current_rnti); int RA_id; int ii,j; eNB_MAC_INST *eNB = RC.mac[enb_mod_idP]; @@ -97,14 +98,14 @@ void rx_sdu(const module_id_t enb_mod_idP, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_SDU,1); if (opt_enabled == 1) { - trace_pdu(0, sduP,sdu_lenP, 0, 3, rntiP, frameP, subframeP, 0,0); + trace_pdu(0, sduP,sdu_lenP, 0, 3, current_rnti, frameP, subframeP, 0,0); LOG_D(OPT,"[eNB %d][ULSCH] Frame %d rnti %x with size %d\n", - enb_mod_idP, frameP, rntiP, sdu_lenP); + enb_mod_idP, frameP, current_rnti, sdu_lenP); } if (UE_id!=-1) { LOG_D(MAC,"[eNB %d][PUSCH %d] CC_id %d Received ULSCH sdu round %d from PHY (rnti %x, UE_id %d) ul_cqi %d\n",enb_mod_idP,harq_pid,CC_idP, UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid], - rntiP,UE_id,ul_cqi); + current_rnti, UE_id,ul_cqi); AssertFatal(UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] < 8, "round >= 8\n"); @@ -140,14 +141,14 @@ void rx_sdu(const module_id_t enb_mod_idP, } } - else if ((RA_id = find_RA_id(enb_mod_idP,CC_idP,rntiP))!=-1) { // Check if this is an RA process for the rnti + else if ((RA_id = find_RA_id(enb_mod_idP,CC_idP,current_rnti))!=-1) { // Check if this is an RA process for the rnti AssertFatal(eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx>1, "maxHARQ %d should be greater than 1\n", (int)eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx); LOG_D(MAC,"[eNB %d][PUSCH %d] CC_id %d Received ULSCH sdu round %d from PHY (rnti %x, RA_id %d) ul_cqi %d\n",enb_mod_idP,harq_pid,CC_idP, RA_template[RA_id].msg3_round, - rntiP,RA_id,ul_cqi); + current_rnti,RA_id,ul_cqi); first_rb = RA_template->msg3_first_rb; @@ -156,7 +157,7 @@ void rx_sdu(const module_id_t enb_mod_idP, RA_template[RA_id].msg3_round, (int)eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx); if (RA_template[RA_id].msg3_round == eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx-1) { - cancel_ra_proc(enb_mod_idP,CC_idP,frameP,rntiP); + cancel_ra_proc(enb_mod_idP,CC_idP,frameP,current_rnti); } else { @@ -171,15 +172,14 @@ void rx_sdu(const module_id_t enb_mod_idP, } } else { - LOG_W(MAC,"Cannot find UE or RA corresponding to ULSCH rnti %x, dropping it\n", - rntiP); + LOG_W(MAC,"Cannot find UE or RA corresponding to ULSCH rnti %x, dropping it\n", current_rnti); return; } payload_ptr = parse_ulsch_header(sduP,&num_ce,&num_sdu,rx_ces,rx_lcids,rx_lengths,sdu_lenP); - T(T_ENB_MAC_UE_UL_PDU, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(rntiP), T_INT(frameP), T_INT(subframeP), + T(T_ENB_MAC_UE_UL_PDU, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu)); - T(T_ENB_MAC_UE_UL_PDU_WITH_DATA, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(rntiP), T_INT(frameP), T_INT(subframeP), + T(T_ENB_MAC_UE_UL_PDU_WITH_DATA, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu), T_BUFFER(sduP, sdu_lenP)); eNB->eNB_stats[CC_idP].ulsch_bytes_rx=sdu_lenP; @@ -191,7 +191,7 @@ void rx_sdu(const module_id_t enb_mod_idP, // control element for (i=0; iUE_sched_ctrl[UE_id].ul_inactivity_timer=0; - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer=0; - if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) { - UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync=0; - mac_eNB_rrc_ul_in_sync(enb_mod_idP,CC_idP,frameP,subframeP,(((uint16_t)payload_ptr[0])<<8) + payload_ptr[1]); - } -printf("TODO: deal with CRNTI\n"); -abort(); + enb_mod_idP, frameP, subframeP, CC_idP, rx_ces[i], i, num_ce, old_rnti, old_UE_id); + if (old_UE_id != -1) { + /* TODO: if the UE did random access (followed by a MAC uplink with + * CRNTI) because none of its scheduling request was granted, then + * according to 36.321 5.4.4 the UE's MAC will notify RRC to release + * PUCCH/SRS. According to 36.331 5.3.13 the UE will then apply + * default configuration for CQI reporting and scheduling requests, + * which basically means that the CQI requests won't work anymore and + * that the UE won't do any scheduling request anymore as long as the + * eNB doesn't reconfigure the UE. + * We have to take care of this. As the code is, nothing is done and + * the UE state in the eNB is wrong. + */ + UE_id = old_UE_id; + UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer = 0; + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; + if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) { + UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 0; + mac_eNB_rrc_ul_in_sync(enb_mod_idP, CC_idP, frameP, subframeP, old_rnti); + } + /* receiving CRNTI means that the current rnti has to go away */ + cancel_ra_proc(enb_mod_idP,CC_idP,frameP,current_rnti); + current_rnti = old_rnti; } crnti_rx=1; payload_ptr+=2; - /* - if (msg3_flagP != NULL) { - *msg3_flagP = 0; - }*/ - break; + } case TRUNCATED_BSR: case SHORT_BSR: { @@ -367,9 +377,9 @@ abort(); for (i=0; irnti, rntiP, + RA_template->rnti, current_rnti, RA_template->RA_active); - if ((RA_template->rnti==rntiP) && + if ((RA_template->rnti==current_rnti) && (RA_template->RA_active==TRUE)) { //payload_ptr = parse_ulsch_header(msg3,&num_ce,&num_sdu,rx_ces,rx_lcids,rx_lengths,msg3_len); @@ -422,7 +432,7 @@ abort(); enb_mod_idP, CC_idP, frameP,subframeP, - rntiP, + current_rnti, CCCH, (uint8_t*)payload_ptr, rx_lengths[i], @@ -476,7 +486,7 @@ abort(); mac_rlc_data_ind( enb_mod_idP, - rntiP, + current_rnti, enb_mod_idP, frameP, ENB_FLAG_YES, @@ -525,7 +535,7 @@ abort(); if ((rx_lengths[i] 0) ) { // MAX SIZE OF transport block mac_rlc_data_ind( enb_mod_idP, - rntiP, + current_rnti, enb_mod_idP, frameP, ENB_FLAG_YES, @@ -558,7 +568,7 @@ abort(); } // Program ACK for PHICH - LOG_D(MAC,"Programming PHICH ACK for rnti %x harq_pid %d (first_rb %d)\n",rntiP,harq_pid,first_rb); + LOG_D(MAC,"Programming PHICH ACK for rnti %x harq_pid %d (first_rb %d)\n",current_rnti,harq_pid,first_rb); nfapi_hi_dci0_request_body_t *hi_dci0_req = &eNB->HI_DCI0_req[CC_idP].hi_dci0_request_body; nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &hi_dci0_req->hi_dci0_pdu_list[hi_dci0_req->number_of_dci+hi_dci0_req->number_of_hi]; memset((void*)hi_dci0_pdu,0,sizeof(nfapi_hi_dci0_request_pdu_t)); From 0289b519696558ad944c7364b3c8bde89e0e484a Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 18 Oct 2017 10:26:43 +0200 Subject: [PATCH 041/284] set pucch_nRB_CQI to 0 in configuration files see commit 622b919b379e12923eeaaa0adcde0e310c97295f --- .../GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf | 2 +- .../GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf | 2 +- .../GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.conf | 2 +- .../GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.lo.conf | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf index 2e7e56589c..ff302811e9 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf @@ -50,7 +50,7 @@ eNBs = prach_zero_correlation = 1; prach_freq_offset = 2; pucch_delta_shift = 1; - pucch_nRB_CQI = 1; + pucch_nRB_CQI = 0; pucch_nCS_AN = 0; pucch_n1_AN = 32; pdsch_referenceSignalPower = -27; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf index 1e2cd12616..c9102b9b08 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf @@ -50,7 +50,7 @@ eNBs = prach_zero_correlation = 1; prach_freq_offset = 2; pucch_delta_shift = 1; - pucch_nRB_CQI = 1; + pucch_nRB_CQI = 0; pucch_nCS_AN = 0; pucch_n1_AN = 32; pdsch_referenceSignalPower = -27; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.conf index c3c9629bbc..772e13fe6f 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.conf @@ -53,7 +53,7 @@ eNBs = prach_zero_correlation = 1; prach_freq_offset = 2; pucch_delta_shift = 1; - pucch_nRB_CQI = 1; + pucch_nRB_CQI = 0; pucch_nCS_AN = 0; pucch_n1_AN = 32; pdsch_referenceSignalPower = -27; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.lo.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.lo.conf index e877e4d1dd..048f2fcc35 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.lo.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.lo.conf @@ -53,7 +53,7 @@ eNBs = prach_zero_correlation = 1; prach_freq_offset = 2; pucch_delta_shift = 1; - pucch_nRB_CQI = 1; + pucch_nRB_CQI = 0; pucch_nCS_AN = 0; pucch_n1_AN = 32; pdsch_referenceSignalPower = -27; From 6d3fb2dca03fd73b900e2582f3af5e4c20a67e22 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 18 Oct 2017 10:38:14 +0200 Subject: [PATCH 042/284] add some documentation for 3276 USB LTE dongle usage --- cmake_targets/autotests/v2/actions/3276.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 cmake_targets/autotests/v2/actions/3276.txt diff --git a/cmake_targets/autotests/v2/actions/3276.txt b/cmake_targets/autotests/v2/actions/3276.txt new file mode 100644 index 0000000000..1976ceb3f3 --- /dev/null +++ b/cmake_targets/autotests/v2/actions/3276.txt @@ -0,0 +1,13 @@ +When running lsusb, if you have: + + Bus 001 Device 002: ID 12d1:14fe Huawei Technologies Co., Ltd. Modem (Mass Storage Mode) + +You need to run: + + usb_modeswitch -v 12d1 -p 14fe -M '55534243123456780000000000000011062000000100000000000000000000' + +After what, running lsusb should give: + + Bus 001 Device 004: ID 12d1:1506 Huawei Technologies Co., Ltd. Modem/Networkcard + +Values of 'Bus' and 'Device' may differ of course. From 49f86b0aa933eed092aae9d032c400d8cdb9f9e4 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Wed, 18 Oct 2017 11:37:26 +0200 Subject: [PATCH 043/284] added LUT for finer-grain ULSCH power measurement compensation based on TBS. Still seems too high, to be checked some more. --- openair1/PHY/INIT/lte_init.c | 2 ++ openair1/PHY/LTE_TRANSPORT/proto.h | 2 ++ .../PHY/LTE_TRANSPORT/ulsch_demodulation.c | 27 ++++++++++++++----- targets/RT/USER/lte-enb.c | 1 - 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 9c9ab1a29b..4f11f79352 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1857,6 +1857,8 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, generate_ul_ref_sigs_rx(); + init_ulsch_power_LUT(); + // SRS for (UE_id=0; UE_idofdm_symbol_size*sizeof(int32_t)); diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 441cd5539a..3ee8df87e3 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -2109,6 +2109,8 @@ int32_t rx_pucch_emul(PHY_VARS_eNB *phy_vars_eNB, uint8_t *payload); +void init_ulsch_power_LUT(void); + /*! \brief Check for PRACH TXop in subframe @param frame_parms Pointer to LTE_DL_FRAME_PARMS diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c index 43c14bde1c..8e97a9af2e 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c @@ -1102,7 +1102,15 @@ void ulsch_channel_level(int32_t **drs_ch_estimates_ext, #endif } +int ulsch_power_LUT[750]; +void init_ulsch_power_LUT() { + + int i; + + for (i=0;i<750;i++) ulsch_power_LUT[i] = (int)ceil((pow(2.0,(double)i/100) - 1.0)); + +} void rx_ulsch(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, @@ -1166,19 +1174,26 @@ void rx_ulsch(PHY_VARS_eNB *eNB, int correction_factor = 1; int deltaMCS=1; - int MPR_times_Ks; + int MPR_times_100Ks; if (deltaMCS==1) { -// Note we're using TBS instead of sumKr, since didn't run segmentation yet! - MPR_times_Ks = 5*ulsch[UE_id]->harq_processes[harq_pid]->TBS/(ulsch[UE_id]->harq_processes[harq_pid]->nb_rb*12*4*ulsch[UE_id]->harq_processes[harq_pid]->Nsymb_pusch); - if (MPR_times_Ks > 0) correction_factor = (1<harq_processes[harq_pid]->TBS/(ulsch[UE_id]->harq_processes[harq_pid]->nb_rb*12*4*ulsch[UE_id]->harq_processes[harq_pid]->Nsymb_pusch); + + AssertFatal(MPR_times_100Ks < 750 && MPR_times_100Ks >= 0,"Impossible value for MPR_times_100Ks %d (TBS %d,Nre %d)\n", + MPR_times_100Ks,ulsch[UE_id]->harq_processes[harq_pid]->TBS, + (ulsch[UE_id]->harq_processes[harq_pid]->nb_rb*12*4*ulsch[UE_id]->harq_processes[harq_pid]->Nsymb_pusch)); + + if (MPR_times_100Ks > 0) correction_factor = ulsch_power_LUT[MPR_times_100Ks]; + } for (i=0; inb_antennas_rx; i++) { pusch_vars->ulsch_power[i] = signal_energy_nodc(pusch_vars->drs_ch_estimates[i], ulsch[UE_id]->harq_processes[harq_pid]->nb_rb*12)/correction_factor; -//printf("%4.4d.%d power harq_pid %d rb %2.2d TBS %2.2d (MPR_times_Ks %d correction %d) power %d dBtimes10\n", proc->frame_rx, proc->subframe_rx, harq_pid, ulsch[UE_id]->harq_processes[harq_pid]->nb_rb, ulsch[UE_id]->harq_processes[harq_pid]->TBS,MPR_times_Ks,correction_factor,dB_fixed_times10(pusch_vars->ulsch_power[i])); - + /* printf("%4.4d.%d power harq_pid %d rb %2.2d TBS %2.2d (MPR_times_Ks %d correction %d) power %d dBtimes10\n", proc->frame_rx, proc->subframe_rx, harq_pid, ulsch[UE_id]->harq_processes[harq_pid]->nb_rb, ulsch[UE_id]->harq_processes[harq_pid]->TBS,MPR_times_100Ks,correction_factor,dB_fixed_times10(pusch_vars->ulsch_power[i])); + */ } diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 8e476e06b7..c7cc203da6 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -577,7 +577,6 @@ static void* eNB_thread_prach_br( void* param ) { #endif -extern void init_fep_thread(PHY_VARS_eNB *, pthread_attr_t *); extern void init_td_thread(PHY_VARS_eNB *, pthread_attr_t *); extern void init_te_thread(PHY_VARS_eNB *, pthread_attr_t *); From 2516216d14faf3d074ef5f657f536536b5554cb4 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 18 Oct 2017 12:06:16 +0200 Subject: [PATCH 044/284] T tracer: improve a bit enb tracer - UE_id 0 is for rnti 65535 (sib) - UE_id 1 is for rnti 65534 (this is a hack) - UE_id 2 is for rnti 2 (RA RNTI as of today's code/config) - we start enb by displaying UE_id 3 - there was a bug: we need to lock when resetting UE ids (reset_ue_ids) --- common/utils/T/tracer/enb.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/common/utils/T/tracer/enb.c b/common/utils/T/tracer/enb.c index fdc54e1c59..f607743d15 100644 --- a/common/utils/T/tracer/enb.c +++ b/common/utils/T/tracer/enb.c @@ -31,7 +31,10 @@ void reset_ue_ids(void) int i; printf("resetting known UEs\n"); for (i = 0; i < 65536; i++) ue_id[i] = -1; - next_ue_id = 0; + ue_id[65535] = 0; + ue_id[65534] = 1; /* HACK: to be removed */ + ue_id[2] = 2; /* this supposes RA RNTI = 2, very openair specific */ + next_ue_id = 3; } int ue_id_from_rnti(void *_priv, int rnti) @@ -228,13 +231,15 @@ static void click(void *private, gui *g, enb_data *ed = private; enb_gui *e = ed->e; int ue = ed->ue; + int do_reset = 0; if (button != 1) return; if (w == e->prev_ue_button) { ue--; if (ue < 0) ue = 0; } if (w == e->next_ue_button) ue++; - if (w == e->current_ue_button) reset_ue_ids(); + if (w == e->current_ue_button) do_reset = 1; if (pthread_mutex_lock(&ed->lock)) abort(); + if (do_reset) reset_ue_ids(); if (ue != ed->ue) { set_current_ue(g, ed, ue); ed->ue = ue; @@ -619,7 +624,7 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database, container_set_child_growable(g, top_container, text, 1); e->legacy = new_view_textlist(10000, 10, g, text); - set_current_ue(g, ed, 0); + set_current_ue(g, ed, ed->ue); register_notifier(g, "click", e->current_ue_button, click, ed); register_notifier(g, "click", e->prev_ue_button, click, ed); register_notifier(g, "click", e->next_ue_button, click, ed); @@ -735,7 +740,7 @@ int main(int n, char **v) g = gui_init(); new_thread(gui_thread, g); - enb_data.ue = 0; + enb_data.ue = 3; enb_data.e = ⪚ enb_data.database = database; From f96491577ff6f9897d57a39016269cbe82975f9e Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 18 Oct 2017 16:28:40 +0200 Subject: [PATCH 045/284] bugfix: don't check /usr/include/uhd when compiling with -w USRP Compilation will fail if UHD is not installed, there is no need to check. Plus the test is wrong when you install UHD somewhere else. --- cmake_targets/build_oai | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 01d94da73e..19f3023009 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -856,11 +856,9 @@ function main() { ln -sf $dbin/liboai_exmimodevif.so.$REL $dbin/liboai_device.so echo_info "liboai_device.so is linked to EXMIMO device library" elif [ "$HW" == "OAI_USRP" ] ; then - if [ -d "/usr/include/uhd" ] ; then - compilations \ - $build_dir oai_usrpdevif \ - liboai_usrpdevif.so $dbin/liboai_usrpdevif.so.$REL - fi + compilations \ + $build_dir oai_usrpdevif \ + liboai_usrpdevif.so $dbin/liboai_usrpdevif.so.$REL ln -sf liboai_usrpdevif.so liboai_device.so ln -sf $dbin/liboai_usrpdevif.so.$REL $dbin/liboai_device.so From 1a04ba5bfcfce7f92dc200866e3c0ea71038d97e Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 18 Oct 2017 17:40:10 +0200 Subject: [PATCH 046/284] bugfix: do not modify dlsch structure at all in case of PDCCH order for RAPROC introduce a new function to deal with this special case --- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 164 +++++++++++++++++++++---- 1 file changed, 141 insertions(+), 23 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 8a3047b5b2..0b81370686 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -861,13 +861,152 @@ uint8_t get_transmission_mode(module_id_t Mod_id, uint8_t CC_id, rnti_t rnti) } */ -void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc,nfapi_dl_config_dci_dl_pdu *pdu) { +void fill_pdcch_order(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc,nfapi_dl_config_dci_dl_pdu *pdu) +{ + LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; + uint8_t *dci_pdu = &dci_alloc->dci_pdu[0]; + nfapi_dl_config_dci_dl_pdu_rel8_t *rel8 = &pdu->dci_dl_pdu_rel8; + dci_alloc->firstCCE = rel8->cce_idx; + dci_alloc->L = rel8->aggregation_level; + dci_alloc->rnti = rel8->rnti; + dci_alloc->harq_pid = rel8->harq_process; + dci_alloc->ra_flag = 0; + dci_alloc->format = format1A; + + LOG_D(PHY,"NFAPI: DCI format %d, nCCE %d, L %d, rnti %x,harq_pid %d\n", + rel8->dci_format,rel8->cce_idx,rel8->aggregation_level,rel8->rnti,rel8->harq_process); + + switch (fp->N_RB_DL) { + case 6: + if (fp->frame_type == TDD) { + dci_alloc->dci_length = sizeof_DCI1A_1_5MHz_TDD_1_6_t; + ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->type = 1; + ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->vrb_type = rel8->virtual_resource_block_assignment_flag; + ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->mcs = rel8->mcs_1; + ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->ndi = rel8->new_data_indicator_1; + ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->rballoc = rel8->resource_block_coding; + ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->rv = rel8->redundancy_version_1; + ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->TPC = rel8->tpc; + ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + } else { + dci_alloc->dci_length = sizeof_DCI1A_1_5MHz_FDD_t; + ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->type = 1; + ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->vrb_type = rel8->virtual_resource_block_assignment_flag; + ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->mcs = rel8->mcs_1; + ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->ndi = rel8->new_data_indicator_1; + ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->rballoc = rel8->resource_block_coding; + ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; + ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; + ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); + } + break; + case 25: + if (fp->frame_type == TDD) { + dci_alloc->dci_length = sizeof_DCI1A_5MHz_TDD_1_6_t; + ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->type = 1; + ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->vrb_type = rel8->virtual_resource_block_assignment_flag; + ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->mcs = rel8->mcs_1; + ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->ndi = rel8->new_data_indicator_1; + ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->rballoc = rel8->resource_block_coding; + ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->rv = rel8->redundancy_version_1; + ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->TPC = rel8->tpc; + ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + // printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); + } else { + dci_alloc->dci_length = sizeof_DCI1A_5MHz_FDD_t; + ((DCI1A_5MHz_FDD_t *)dci_pdu)->type = 1; + ((DCI1A_5MHz_FDD_t *)dci_pdu)->vrb_type = rel8->virtual_resource_block_assignment_flag; + ((DCI1A_5MHz_FDD_t *)dci_pdu)->mcs = rel8->mcs_1; + ((DCI1A_5MHz_FDD_t *)dci_pdu)->ndi = rel8->new_data_indicator_1; + ((DCI1A_5MHz_FDD_t *)dci_pdu)->rballoc = rel8->resource_block_coding; + ((DCI1A_5MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; + ((DCI1A_5MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; + ((DCI1A_5MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); + } + break; + case 50: + if (fp->frame_type == TDD) { + dci_alloc->dci_length = sizeof_DCI1A_10MHz_TDD_1_6_t; + ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->type = 1; + ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->vrb_type = rel8->virtual_resource_block_assignment_flag; + ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->mcs = rel8->mcs_1; + ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->ndi = rel8->new_data_indicator_1; + ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->rballoc = rel8->resource_block_coding; + ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->rv = rel8->redundancy_version_1; + ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->TPC = rel8->tpc; + ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + // printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); + } else { + dci_alloc->dci_length = sizeof_DCI1A_10MHz_FDD_t; + ((DCI1A_10MHz_FDD_t *)dci_pdu)->type = 1; + ((DCI1A_10MHz_FDD_t *)dci_pdu)->vrb_type = rel8->virtual_resource_block_assignment_flag; + ((DCI1A_10MHz_FDD_t *)dci_pdu)->mcs = rel8->mcs_1; + ((DCI1A_10MHz_FDD_t *)dci_pdu)->ndi = rel8->new_data_indicator_1; + ((DCI1A_10MHz_FDD_t *)dci_pdu)->rballoc = rel8->resource_block_coding; + ((DCI1A_10MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; + ((DCI1A_10MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; + ((DCI1A_10MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); + } + break; + case 100: + if (fp->frame_type == TDD) { + dci_alloc->dci_length = sizeof_DCI1A_20MHz_TDD_1_6_t; + ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->type = 1; + ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->vrb_type = rel8->virtual_resource_block_assignment_flag; + ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->mcs = rel8->mcs_1; + ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->ndi = rel8->new_data_indicator_1; + ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->rballoc = rel8->resource_block_coding; + ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->rv = rel8->redundancy_version_1; + ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->TPC = rel8->tpc; + ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + // printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); + } else { + dci_alloc->dci_length = sizeof_DCI1A_20MHz_FDD_t; + ((DCI1A_20MHz_FDD_t *)dci_pdu)->type = 1; + ((DCI1A_20MHz_FDD_t *)dci_pdu)->vrb_type = rel8->virtual_resource_block_assignment_flag; + ((DCI1A_20MHz_FDD_t *)dci_pdu)->mcs = rel8->mcs_1; + ((DCI1A_20MHz_FDD_t *)dci_pdu)->ndi = rel8->new_data_indicator_1; + ((DCI1A_20MHz_FDD_t *)dci_pdu)->rballoc = rel8->resource_block_coding; + ((DCI1A_20MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; + ((DCI1A_20MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; + ((DCI1A_20MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); + } + break; + } + + LOG_I(PHY,"%d.%d: DCI 1A: rnti %x, PDCCH order to do PRACH\n", + proc->frame_tx, proc->subframe_tx, rel8->rnti); +} + +void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc,nfapi_dl_config_dci_dl_pdu *pdu) +{ LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; - uint8_t *dci_pdu = &dci_alloc->dci_pdu[0]; nfapi_dl_config_dci_dl_pdu_rel8_t *rel8 = &pdu->dci_dl_pdu_rel8; + /* check if this is a DCI 1A PDCCH order for RAPROC */ + if (rel8->dci_format == NFAPI_DL_DCI_FORMAT_1A && rel8->rnti_type == 1) { + int full_rb; + switch (fp->N_RB_DL) { + case 6: full_rb = 63; break; + case 25: full_rb = 511; break; + case 50: full_rb = 2047; break; + case 100: full_rb = 8191; break; + default: abort(); + } + if (rel8->resource_block_coding == full_rb) + return fill_pdcch_order(eNB, proc, dci_alloc, pdu); + } + LTE_eNB_DLSCH_t *dlsch0=NULL,*dlsch1=NULL; LTE_DL_eNB_HARQ_t *dlsch0_harq=NULL,*dlsch1_harq=NULL; int beamforming_mode = 0; @@ -958,11 +1097,6 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } - // check if PDCCH order - if (rel8->resource_block_coding == 63) { - dlsch0->active = 0; - return; - } AssertFatal(rel8->virtual_resource_block_assignment_flag==LOCALIZED,"Distributed RB allocation not done yet\n"); dlsch0_harq->rb_alloc[0] = localRIV2alloc_LUT6[rel8->resource_block_coding]; dlsch0_harq->vrb_type = rel8->virtual_resource_block_assignment_flag; @@ -993,12 +1127,6 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1A_5MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } - - // check if PDCCH order - if (rel8->resource_block_coding == 511) { - dlsch0->active = 0; - return; - } AssertFatal(rel8->virtual_resource_block_assignment_flag==LOCALIZED,"Distributed RB allocation not done yet\n"); dlsch0_harq->rb_alloc[0] = localRIV2alloc_LUT25[rel8->resource_block_coding]; dlsch0_harq->vrb_type = rel8->virtual_resource_block_assignment_flag; @@ -1029,11 +1157,6 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1A_10MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } - // check if PDCCH order - if (rel8->resource_block_coding == 2047) { - dlsch0->active = 0; - return; - } AssertFatal(rel8->virtual_resource_block_assignment_flag==LOCALIZED,"Distributed RB allocation not done yet\n"); dlsch0_harq->rb_alloc[0] = localRIV2alloc_LUT50_0[rel8->resource_block_coding]; dlsch0_harq->rb_alloc[1] = localRIV2alloc_LUT50_1[rel8->resource_block_coding]; @@ -1065,11 +1188,6 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1A_20MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } - // check if PDCCH order - if (rel8->resource_block_coding == 8191) { - dlsch0->active = 0; - return; - } AssertFatal(rel8->virtual_resource_block_assignment_flag==LOCALIZED,"Distributed RB allocation not done yet\n"); dlsch0_harq->rb_alloc[0] = localRIV2alloc_LUT100_0[rel8->resource_block_coding]; dlsch0_harq->rb_alloc[1] = localRIV2alloc_LUT100_1[rel8->resource_block_coding]; From c78351c20efbb6adf5dfad95277bcfc62730deec Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 19 Oct 2017 10:24:50 +0200 Subject: [PATCH 047/284] bugfix: clear memory Old values valid for a previous UE have to be reset for the new UE. --- openair2/LAYER2/MAC/eNB_scheduler_primitives.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 3097a0c094..b11634ef5d 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -1707,6 +1707,7 @@ int add_new_ue(module_id_t mod_idP, int cc_idP, rnti_t rntiP,int harq_pidP for (i = 0; i < NUMBER_OF_UE_MAX; i++) { if (UE_list->active[i] == TRUE) continue; UE_id = i; + memset(&UE_list->UE_template[cc_idP][UE_id], 0, sizeof(UE_TEMPLATE)); UE_list->UE_template[cc_idP][UE_id].rnti = rntiP; UE_list->UE_template[cc_idP][UE_id].configured = FALSE; UE_list->numactiveCCs[UE_id] = 1; From 0ed42440ab5230a622252d2fc4e45075729dcde7 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 19 Oct 2017 10:54:04 +0200 Subject: [PATCH 048/284] bugfix: set max MCS to 10 when UL scheduling a UE with no known uplink data --- openair2/LAYER2/MAC/pre_processor.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 5337dcf657..1137fdf4f1 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -1370,11 +1370,14 @@ void assign_max_mcs_min_rb(module_id_t module_idP,int frameP, sub_frame_t subfra /* if UE has pending scheduling request then pre-allocate 3 RBs */ //if (UE_template->ul_active == 1 && UE_template->ul_SR == 1) { if (UE_is_to_be_scheduled(module_idP, CC_id, i)) { + /* use QPSK mcs */ + UE_template->pre_assigned_mcs_ul = 10; UE_template->pre_allocated_rb_table_index_ul = 2; UE_template->pre_allocated_nb_rb_ul = 3; } else { - UE_template->pre_allocated_rb_table_index_ul=-1; - UE_template->pre_allocated_nb_rb_ul=0; + UE_template->pre_assigned_mcs_ul = 0; + UE_template->pre_allocated_rb_table_index_ul = -1; + UE_template->pre_allocated_nb_rb_ul = 0; } } } From 311f439a6ab889685fd2b40f99c560acdbfeb86f Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 19 Oct 2017 12:05:16 +0200 Subject: [PATCH 049/284] T tracer: add uplink TBS (retransmissions not handled) --- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 0b81370686..fd2b3f96ec 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -2405,7 +2405,7 @@ void fill_dci0(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc, T_INT(mcs), T_INT(-1 /* TODO: remove round? */), T_INT(pdu->dci_pdu_rel8.resource_block_start), T_INT(pdu->dci_pdu_rel8.number_of_resource_block), - T_INT(-1 /* TODO: get TBS */), + T_INT(get_TBS_UL(mcs, pdu->dci_pdu_rel8.number_of_resource_block) * 8), T_INT(pdu->dci_pdu_rel8.aggregation_level), T_INT(pdu->dci_pdu_rel8.cce_index)); #endif From b09a281b091dfb7adb956aa203bb8ea6d71c758e Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 19 Oct 2017 12:25:51 +0200 Subject: [PATCH 050/284] modifications for TDD and IF4p5 (in particular TDD). Both in RRU and RAU components. Monolithic is unchanged. --- openair1/PHY/INIT/lte_init.c | 3 +- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 2 + openair1/PHY/LTE_TRANSPORT/if4_tools.c | 1 + openair1/PHY/LTE_TRANSPORT/phich.c | 34 ++++++------ openair1/PHY/LTE_TRANSPORT/prach.c | 2 +- openair1/PHY/defs.h | 4 ++ openair1/SCHED/fapi_l1.c | 13 ++--- openair1/SCHED/phy_procedures_lte_eNb.c | 54 +++++++++---------- openair1/SCHED/phy_procedures_lte_ue.c | 11 ---- targets/RT/USER/lte-ru.c | 69 ++++++++++++------------- targets/SIMU/USER/oaisim_functions.c | 2 +- 11 files changed, 95 insertions(+), 100 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 4f11f79352..e67dbbabe6 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1677,7 +1677,7 @@ int phy_init_RU(RU_t *ru) { int p; int re; - LOG_I(PHY,"Initializing RU signal buffers (if_south %s)\n",ru_if_types[ru->if_south]); + LOG_I(PHY,"Initializing RU signal buffers (if_south %s) nb_tx %d\n",ru_if_types[ru->if_south],ru->nb_tx); if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so allocate memory for time-domain signals // Time-domain signals @@ -1704,6 +1704,7 @@ int phy_init_RU(RU_t *ru) { } if (ru->function != NGFI_RRU_IF5) { // we need to do RX/TX RU processing + LOG_I(PHY,"nb_tx %d\n",ru->nb_tx); ru->common.rxdata_7_5kHz = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) ); for (i=0;inb_rx;i++) { ru->common.rxdata_7_5kHz[i] = (int32_t*)malloc16_clear( 2*fp->samples_per_tti*2*sizeof(int32_t) ); diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 8a3047b5b2..f578f02ab9 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -6374,6 +6374,8 @@ uint8_t pdcch_alloc2ul_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t n) else ul_subframe = ((n+4)%10); + if (subframe_select(frame_parms,ul_subframe) != SF_UL) return(255); + LOG_D(PHY, "subframe %d: PUSCH subframe = %d\n", n, ul_subframe); return ul_subframe; } diff --git a/openair1/PHY/LTE_TRANSPORT/if4_tools.c b/openair1/PHY/LTE_TRANSPORT/if4_tools.c index 6024f859c9..c3cd8d48b7 100644 --- a/openair1/PHY/LTE_TRANSPORT/if4_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/if4_tools.c @@ -72,6 +72,7 @@ void send_IF4p5(RU_t *ru, int frame, int subframe, uint16_t packet_type) { if (subframe_select(fp,subframe)==SF_S) nsym=fp->dl_symbols_in_S_subframe; + db_fulllength = 12*fp->N_RB_DL; db_halflength = (db_fulllength)>>1; slotoffsetF = 1;//(subframe)*(fp->ofdm_symbol_size)*((fp->Ncp==1) ? 12 : 14) + 1; diff --git a/openair1/PHY/LTE_TRANSPORT/phich.c b/openair1/PHY/LTE_TRANSPORT/phich.c index 0f6270956c..eacf4736cc 100644 --- a/openair1/PHY/LTE_TRANSPORT/phich.c +++ b/openair1/PHY/LTE_TRANSPORT/phich.c @@ -184,8 +184,8 @@ uint8_t phich_subframe2_pusch_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t s else if (subframe == 1) pusch_subframe = (7); else { - LOG_E(PHY, "phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n", - subframe,frame_parms->tdd_config); + AssertFatal(1==0,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n", + subframe,frame_parms->tdd_config); pusch_subframe = (0); } @@ -201,7 +201,7 @@ uint8_t phich_subframe2_pusch_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t s else if (subframe == 4) pusch_subframe = (8); else { - LOG_E(PHY,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n", + AssertFatal(1==0,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n", subframe,frame_parms->tdd_config); pusch_subframe = (0); } @@ -214,7 +214,7 @@ uint8_t phich_subframe2_pusch_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t s else if (subframe == 3) pusch_subframe = (7); else { - LOG_E(PHY,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n", + AssertFatal(1==0,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n", subframe,frame_parms->tdd_config); pusch_subframe = (0); } @@ -227,7 +227,7 @@ uint8_t phich_subframe2_pusch_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t s } else if (subframe==0) pusch_subframe = (4); else { - LOG_E(PHY,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n", + AssertFatal(1==0,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n", subframe,frame_parms->tdd_config); pusch_subframe = (0); } @@ -238,7 +238,7 @@ uint8_t phich_subframe2_pusch_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t s if ( (subframe == 8) || (subframe == 9) ) { pusch_subframe = (subframe-6); } else { - LOG_E(PHY,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n", + AssertFatal(1==0,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n", subframe,frame_parms->tdd_config); pusch_subframe = (0); } @@ -249,7 +249,7 @@ uint8_t phich_subframe2_pusch_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t s if (subframe == 8) { pusch_subframe = (2); } else { - LOG_E(PHY,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n", + AssertFatal(1==0,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n", subframe,frame_parms->tdd_config); pusch_subframe = (0); } @@ -268,7 +268,7 @@ uint8_t phich_subframe2_pusch_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t s } else if (subframe == 5) { pusch_subframe = (8); } else { - LOG_E(PHY,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n", + AssertFatal(1==0,"phich.c: phich_subframe2_pusch_subframe, illegal subframe %d for tdd_config %d\n", subframe,frame_parms->tdd_config); pusch_subframe = (0); } @@ -276,7 +276,7 @@ uint8_t phich_subframe2_pusch_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t s break; default: - LOG_E(PHY, "no implementation for TDD UL/DL-config = %d!\n", frame_parms->tdd_config); + AssertFatal(1==0, "no implementation for TDD UL/DL-config = %d!\n", frame_parms->tdd_config); pusch_subframe = (0); } @@ -560,7 +560,7 @@ void generate_phich(LTE_DL_FRAME_PARMS *frame_parms, break; default: - LOG_E(PHY,"phich_coding.c: Illegal PHICH Number\n"); + AssertFatal(1==0,"phich_coding.c: Illegal PHICH Number\n"); } // nseq_PHICH } @@ -858,7 +858,7 @@ void generate_phich(LTE_DL_FRAME_PARMS *frame_parms, break; default: - LOG_E(PHY,"phich_coding.c: Illegal PHICH Number\n"); + AssertFatal(1==0,"phich_coding.c: Illegal PHICH Number\n"); } @@ -1255,7 +1255,7 @@ void rx_phich(PHY_VARS_UE *ue, break; default: - LOG_E(PHY,"phich_coding.c: Illegal PHICH Number\n"); + AssertFatal(1==0,"phich_coding.c: Illegal PHICH Number\n"); } // nseq_PHICH } @@ -1342,7 +1342,7 @@ void rx_phich(PHY_VARS_UE *ue, break; default: - LOG_E(PHY,"phich_coding.c: Illegal PHICH Number\n"); + AssertFatal(1==0,"phich_coding.c: Illegal PHICH Number\n"); } } @@ -1527,9 +1527,11 @@ void generate_phich_top(PHY_VARS_eNB *eNB, if (frame_parms->Ncp == 1) NSF_PHICH = 2; - pusch_frame = phich_frame2_pusch_frame(frame_parms,proc->frame_tx,subframe); - pusch_subframe = phich_subframe2_pusch_subframe(frame_parms,subframe); - harq_pid = subframe2harq_pid(frame_parms,pusch_frame,pusch_subframe); + if (eNB->phich_vars[subframe&1].num_hi > 0) { + pusch_frame = phich_frame2_pusch_frame(frame_parms,proc->frame_tx,subframe); + pusch_subframe = phich_subframe2_pusch_subframe(frame_parms,subframe); + harq_pid = subframe2harq_pid(frame_parms,pusch_frame,pusch_subframe); + } for (i=0; iphich_vars[subframe&1].num_hi; i++) { diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c index 0282b780d9..753ed86d0a 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.c +++ b/openair1/PHY/LTE_TRANSPORT/prach.c @@ -575,7 +575,7 @@ int is_prach_subframe0(LTE_DL_FRAME_PARMS *frame_parms,uint8_t prach_ConfigIndex (((subframe>4)&&(t1_ra==1))))) { // PRACH is in 2nd half-frame if ((prach_ConfigIndex<48) && // PRACH only in normal UL subframe (((subframe%5)-2)==t2_ra)) prach_mask=1; - else if ((((subframe%5)-1)==t2_ra)) prach_mask=1; // PRACH can be in UpPTS + else if ((prach_ConfigIndex>47) && (((subframe%5)-1)==t2_ra)) prach_mask=1; // PRACH can be in UpPTS } } diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 6dd94bafcd..446c1f1575 100644 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -1498,6 +1498,10 @@ typedef struct RRU_config_s { uint8_t num_bands; /// EUTRA band list configured in RRU uint8_t band_list[MAX_BANDS_PER_RRU]; + /// TDD configuration (0-6) + uint8_t tdd_config[MAX_BANDS_PER_RRU]; + /// TDD special subframe configuration (0-10) + uint8_t tdd_config_S[MAX_BANDS_PER_RRU]; /// TX frequency uint32_t tx_freq[MAX_BANDS_PER_RRU]; /// RX frequency diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c index 11cd85d57d..8aff92d485 100644 --- a/openair1/SCHED/fapi_l1.c +++ b/openair1/SCHED/fapi_l1.c @@ -571,7 +571,7 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) frame_t frame = Sched_INFO->frame; sub_frame_t subframe = Sched_INFO->subframe; LTE_DL_FRAME_PARMS *fp; - int ul_subframe; + uint8_t ul_subframe; int ul_frame; int harq_pid; LTE_UL_eNB_HARQ_t *ulsch_harq; @@ -591,7 +591,7 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) uint8_t number_dl_pdu = DL_req->dl_config_request_body.number_pdu; uint8_t number_hi_dci0_pdu = HI_DCI0_req->hi_dci0_request_body.number_of_dci+HI_DCI0_req->hi_dci0_request_body.number_of_hi; - uint8_t number_ul_pdu = UL_req->ul_config_request_body.number_of_pdus; + uint8_t number_ul_pdu = UL_req!=NULL ? UL_req->ul_config_request_body.number_of_pdus : 0; nfapi_dl_config_request_pdu_t *dl_config_pdu; nfapi_hi_dci0_request_pdu_t *hi_dci0_req_pdu; @@ -603,12 +603,13 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) eNB->pdcch_vars[subframe&1].num_dci = 0; eNB->phich_vars[subframe&1].num_hi = 0; - LOG_D(PHY,"NFAPI: Frame %d, Subframe %d: received %d dl_pdu, %d tx_req, %d hi_dci0_config_req, %d UL_config \n", - frame,subframe,number_dl_pdu,TX_req->tx_request_body.number_of_pdus,number_hi_dci0_pdu,number_ul_pdu); + + LOG_D(PHY,"NFAPI: Frame %d, Subframe %d (ul_subframe %d): received %d dl_pdu, %d tx_req, %d hi_dci0_config_req, %d UL_config \n", + frame,subframe,ul_subframe,number_dl_pdu,TX_req->tx_request_body.number_of_pdus,number_hi_dci0_pdu,number_ul_pdu); - if ((subframe_select(fp,ul_subframe)==SF_UL) || - (fp->frame_type == FDD)) { + if (ul_subframe<10) { // This means that there is an ul_subframe that can be configured here + LOG_D(PHY,"NFAPI: Clearing dci allocations for potential UL\n"); harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); // clear DCI allocation maps for new subframe diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 8e5358da34..9659aa9e61 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -437,33 +437,33 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, } /* save old HARQ information needed for PHICH generation */ - for (i=0; iulsch[i]) { - ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid]; - - /* Store first_rb and n_DMRS for correct PHICH generation below. - * For PHICH generation we need "old" values of last scheduling - * for this HARQ process. 'generate_eNB_dlsch_params' below will - * overwrite first_rb and n_DMRS and 'generate_phich_top', done - * after 'generate_eNB_dlsch_params', would use the "new" values - * instead of the "old" ones. - * - * This has been tested for FDD only, may be wrong for TDD. - * - * TODO: maybe we should restructure the code to be sure it - * is done correctly. The main concern is if the code - * changes and first_rb and n_DMRS are modified before - * we reach here, then the PHICH processing will be wrong, - * using wrong first_rb and n_DMRS values to compute - * ngroup_PHICH and nseq_PHICH. - * - * TODO: check if that works with TDD. - */ - if ((subframe_select(fp,ul_subframe)==SF_UL) || - (fp->frame_type == FDD)) { - ulsch_harq->previous_first_rb = ulsch_harq->first_rb; - ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS; + if (ul_subframe < 10) { // This means that there is a potential UL subframe that will be scheduled here + for (i=0; iulsch[i]) { + ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid]; + + /* Store first_rb and n_DMRS for correct PHICH generation below. + * For PHICH generation we need "old" values of last scheduling + * for this HARQ process. 'generate_eNB_dlsch_params' below will + * overwrite first_rb and n_DMRS and 'generate_phich_top', done + * after 'generate_eNB_dlsch_params', would use the "new" values + * instead of the "old" ones. + * + * This has been tested for FDD only, may be wrong for TDD. + * + * TODO: maybe we should restructure the code to be sure it + * is done correctly. The main concern is if the code + * changes and first_rb and n_DMRS are modified before + * we reach here, then the PHICH processing will be wrong, + * using wrong first_rb and n_DMRS values to compute + * ngroup_PHICH and nseq_PHICH. + * + * TODO: check if that works with TDD. + */ + ulsch_harq->previous_first_rb = ulsch_harq->first_rb; + ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS; + } } } diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index ff2287fb1b..152a1c1fe4 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -3583,7 +3583,6 @@ void ue_dlsch_procedures(PHY_VARS_UE *ue, } } - if (abstraction_flag == 0) { // start turbo decode for CW 0 dlsch0->harq_processes[harq_pid]->G = get_G(&ue->frame_parms, @@ -3720,17 +3719,7 @@ void ue_dlsch_procedures(PHY_VARS_UE *ue, } LOG_D(PHY," ------ end turbo decoder for AbsSubframe %d.%d ------ \n", frame_rx, subframe_rx); - } - else { - LOG_D(PHY,"Calling dlsch_decoding_emul ...\n"); -#ifdef PHY_ABSTRACTION - ret = dlsch_decoding_emul(ue, - subframe_rx, - pdsch, - eNB_id); -#endif - } // Check CRC for CW 0 diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 21804817d6..4fa2352368 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -574,14 +574,10 @@ void fh_if5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { proc->first_tx = 0; } else { - if (subframe_tx != *subframe) { - LOG_E(PHY,"subframe_tx %d is not what we expect %d\n",subframe_tx,*subframe); - exit_fun("Exiting"); - } - if (frame_tx != *frame) { - LOG_E(PHY,"frame_tx %d is not what we expect %d\n",frame_tx,*frame); - exit_fun("Exiting"); - } + AssertFatal(subframe_tx == *subframe, + "subframe_tx %d is not what we expect %d\n",subframe_tx,*subframe); + AssertFatal(frame_tx == *frame, + "frame_tx %d is not what we expect %d\n",frame_tx,*frame); } } @@ -596,32 +592,26 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { symbol_number = 0; symbol_mask = 0; - symbol_mask_full = (1<symbols_per_tti)-1; - + symbol_mask_full = ((subframe_select(fp,*subframe) == SF_S) ? (1<dl_symbols_in_S_subframe) : (1<symbols_per_tti))-1; do { recv_IF4p5(ru, &frame_tx, &subframe_tx, &packet_type, &symbol_number); + LOG_D(PHY,"subframe %d (%d): frame %d, subframe %d, symbol %d\n", + *subframe,subframe_select(fp,*subframe),frame_tx,subframe_tx,symbol_number); if (proc->first_tx != 0) { *frame = frame_tx; *subframe = subframe_tx; proc->first_tx = 0; } else { - if (frame_tx != *frame) { - LOG_E(PHY,"frame_tx %d is not what we expect %d\n",frame_tx,*frame); - exit_fun("Exiting"); - } - if (subframe_tx != *subframe) { - LOG_E(PHY,"subframe_tx %d is not what we expect %d\n",subframe_tx,*subframe); - exit_fun("Exiting"); - } + AssertFatal(frame_tx == *frame, + "frame_tx %d is not what we expect %d\n",frame_tx,*frame); + AssertFatal(subframe_tx == *subframe, + "subframe_tx %d is not what we expect %d\n",subframe_tx,*subframe); } if (packet_type == IF4p5_PDLFFT) { symbol_mask = symbol_mask | (1<subframe_tx = subframe_tx; @@ -703,8 +693,8 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { proc->timestamp_rx = ts-ru->ts_offset; - if (rxs != fp->samples_per_tti) - LOG_E(PHY,"rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_tti,rxs); + AssertFatal(rxs == fp->samples_per_tti, + "rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_tti,rxs); if (proc->first_rx == 1) { ru->ts_offset = proc->timestamp_rx; @@ -823,11 +813,8 @@ void tx_rf(RU_t *ru) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); - - if (txs != fp->samples_per_tti) { - LOG_E(PHY,"TX : Timeout (sent %d/%d)\n",txs, fp->samples_per_tti); - exit_fun( "problem transmitting samples" ); - } + AssertFatal(txs == siglen,"TX : Timeout (sent %d/%d)\n",txs, siglen); + } } @@ -1461,7 +1448,6 @@ static void* ru_thread( void* param ) { // If this proc is to provide synchronization, do so wakeup_slaves(proc); - LOG_D(PHY,"RU %d/%d frame_tx %d, subframe_tx %d\n",0,ru->idx,proc->frame_tx,proc->subframe_tx); // wakeup all eNB processes waiting for this RU if (ru->num_eNB>0) wakeup_eNBs(ru); @@ -1746,6 +1732,10 @@ void configure_ru(int idx, AssertFatal((ret=check_capabilities(ru,capabilities)) == 0, "Cannot configure RRU %d, check_capabilities returned %d\n", idx,ret); + // take antenna capabilities of RRU + ru->nb_tx = capabilities->nb_tx[0]; + ru->nb_rx = capabilities->nb_rx[0]; + // Pass configuration to RRU LOG_I(PHY, "Using %s fronthaul (%d), band %d \n",ru_if_formats[ru->if_south],ru->if_south,ru->frame_parms.eutra_band); // wait for configuration @@ -1754,6 +1744,8 @@ void configure_ru(int idx, config->band_list[0] = ru->frame_parms.eutra_band; config->tx_freq[0] = ru->frame_parms.dl_CarrierFreq; config->rx_freq[0] = ru->frame_parms.ul_CarrierFreq; + config->tdd_config[0] = ru->frame_parms.tdd_config; + config->tdd_config_S[0] = ru->frame_parms.tdd_config_S; config->att_tx[0] = ru->att_tx; config->att_rx[0] = ru->att_rx; config->N_RB_DL[0] = ru->frame_parms.N_RB_DL; @@ -1773,10 +1765,6 @@ void configure_ru(int idx, } #endif } - // take antenna capabilities of RRU - ru->nb_tx = capabilities->nb_tx[0]; - ru->nb_rx = capabilities->nb_rx[0]; - init_frame_parms(&ru->frame_parms,1); phy_init_RU(ru); @@ -1791,6 +1779,13 @@ void configure_rru(int idx, ru->frame_parms.eutra_band = config->band_list[0]; ru->frame_parms.dl_CarrierFreq = config->tx_freq[0]; ru->frame_parms.ul_CarrierFreq = config->rx_freq[0]; + if (ru->frame_parms.dl_CarrierFreq == ru->frame_parms.ul_CarrierFreq) { + ru->frame_parms.frame_type = TDD; + ru->frame_parms.tdd_config = config->tdd_config[0]; + ru->frame_parms.tdd_config_S = config->tdd_config_S[0]; + } + else + ru->frame_parms.frame_type = FDD; ru->att_tx = config->att_tx[0]; ru->att_rx = config->att_rx[0]; ru->frame_parms.N_RB_DL = config->N_RB_DL[0]; @@ -1867,7 +1862,7 @@ void init_RU(char *rf_config_file) { // read in configuration file) printf("configuring RU from file\n"); RCconfig_RU(); - printf("number of L1 instances %d, number of RU %d\n",RC.nb_L1_inst,RC.nb_RU); + LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",RC.nb_L1_inst,RC.nb_RU,get_nprocs()); for (i=0;inum_RU=0; @@ -1927,8 +1922,8 @@ void init_RU(char *rf_config_file) { ru->fh_north_out = fh_if4p5_north_out; // send_IF4p5 on reception ru->fh_south_out = tx_rf; // send output to RF ru->fh_north_asynch_in = fh_if4p5_north_asynch_in; // TX packets come asynchronously - ru->feprx = (get_nprocs()<=4) ? fep_full :ru_fep_full_2thread; // RX DFTs - ru->feptx_ofdm = (get_nprocs()<=4) ? feptx_ofdm : feptx_ofdm_2thread; // this is fep with idft only (no precoding in RRU) + ru->feprx = (get_nprocs()<=2) ? fep_full :ru_fep_full_2thread; // RX DFTs + ru->feptx_ofdm = (get_nprocs()<=2) ? feptx_ofdm : feptx_ofdm_2thread; // this is fep with idft only (no precoding in RRU) ru->feptx_prec = NULL; ru->start_if = start_if; // need to start the if interface for if4p5 ru->ifdevice.host_type = RRU_HOST; diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index f916faed6e..4910e20a58 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -785,7 +785,7 @@ void get_simulation_options(int argc, char *argv[]) if (RC.config_file_name != NULL) { /* Read eNB configuration file */ - RCConfig(RC.config_file_name); + RCConfig(); printf("returned with %d eNBs, %d rus\n",RC.nb_inst,RC.nb_RU); oai_emulation.info.nb_enb_local = RC.nb_inst; oai_emulation.info.nb_ru_local = RC.nb_RU; From f1e8bff3ecd167df9a079cbae90b2e9c0156cfc1 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 19 Oct 2017 17:00:30 +0200 Subject: [PATCH 051/284] remove gcc warnings phy_init_lte_ue_signal was renamed init_lte_ue_signal in openair1/PHY/INIT/defs.h maybe it's the opposite that should have been done? Functions used in one file and defined in another may have been declared in the wrong header file. --- openair1/PHY/INIT/defs.h | 2 +- openair1/PHY/LTE_TRANSPORT/prach.c | 6 ++++-- openair1/SCHED/phy_procedures_lte_eNb.c | 6 ------ openair1/SCHED/ru_procedures.c | 4 +--- openair2/ENB_APP/enb_app.c | 9 --------- openair2/ENB_APP/enb_config.h | 5 +++++ openair2/LAYER2/MAC/config.c | 3 +-- openair2/LAYER2/MAC/eNB_scheduler_primitives.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 6 ------ openair2/LAYER2/MAC/proto.h | 6 +++++- openair2/LAYER2/MAC/ra_procedures.c | 1 + openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 1 + .../LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c | 4 ++-- openair2/RRC/LITE/proto.h | 8 ++++++++ openair2/RRC/LITE/rrc_UE.c | 4 ++-- openair2/UTIL/CLI/cli.c | 2 +- openair2/UTIL/CLI/cli_cmd.c | 2 +- openair2/UTIL/OTG/otg_rx.c | 3 ++- openair3/GTPV1-U/gtpv1u_eNB_defs.h | 2 ++ targets/RT/USER/lte-softmodem.h | 5 +++++ targets/RT/USER/rt_wrapper.c | 2 ++ 21 files changed, 45 insertions(+), 38 deletions(-) diff --git a/openair1/PHY/INIT/defs.h b/openair1/PHY/INIT/defs.h index 36d8aa00be..4fd8e10527 100644 --- a/openair1/PHY/INIT/defs.h +++ b/openair1/PHY/INIT/defs.h @@ -65,7 +65,7 @@ int phy_init_top(LTE_DL_FRAME_PARMS *frame_parms); @returns -1 if any memory allocation failed @note The current implementation will never return -1, but segfault. */ -int phy_init_lte_ue_signal(PHY_VARS_UE *phy_vars_ue, +int init_lte_ue_signal(PHY_VARS_UE *phy_vars_ue, int nb_connected_eNB, uint8_t abstraction_flag); diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c index 753ed86d0a..2a50488ad3 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.c +++ b/openair1/PHY/LTE_TRANSPORT/prach.c @@ -1151,7 +1151,9 @@ void rx_prach0(PHY_VARS_eNB *eNB, #ifdef PRACH_DEBUG int en0=0; #endif - int en; + + (void)frame; /* avoid gcc warnings */ + if (ru) { fp = &ru->frame_parms; nb_rx = ru->nb_rx; @@ -1472,8 +1474,8 @@ void rx_prach0(PHY_VARS_eNB *eNB, return; } else if (eNB!=NULL) { - en = dB_fixed(signal_energy((int32_t*)&rxsigF[0][0],840)); #ifdef PRACH_DEBUG + int en = dB_fixed(signal_energy((int32_t*)&rxsigF[0][0],840)); if ((en > 60)&&(br_flag==1)) LOG_I(PHY,"PRACH (br_flag %d,ce_level %d, n_ra_prb %d, k %d): Frame %d, Subframe %d => %d dB\n",br_flag,ce_level,n_ra_prb,k,eNB->proc.frame_rx,eNB->proc.subframe_rx,en); #endif diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 9659aa9e61..5862f27b71 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -555,7 +555,6 @@ void prach_procedures(PHY_VARS_eNB *eNB, uint16_t max_preamble[4],max_preamble_energy[4],max_preamble_delay[4]; uint16_t i; int frame,subframe; - LTE_eNB_PRACH *prach_vars=NULL; #ifdef Rel14 if (br_flag==1) { @@ -618,8 +617,6 @@ void prach_procedures(PHY_VARS_eNB *eNB, #ifdef Rel14 if (br_flag==1) { - - prach_vars = &eNB->prach_vars_br; int prach_mask; prach_mask = is_prach_subframe(&eNB->frame_parms,eNB->proc.frame_prach_br,eNB->proc.subframe_prach_br); @@ -679,9 +676,6 @@ void prach_procedures(PHY_VARS_eNB *eNB, T(T_ENB_PHY_INITIATE_RA_PROCEDURE, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(max_preamble[0]), T_INT(max_preamble_energy[0]), T_INT(max_preamble_delay[0])); - prach_vars = &eNB->prach_vars; - - pthread_mutex_lock(&eNB->UL_INFO_mutex); eNB->UL_INFO.rach_ind.number_of_preambles = 1; diff --git a/openair1/SCHED/ru_procedures.c b/openair1/SCHED/ru_procedures.c index 7e0ca4e76a..e5df2e0a6f 100644 --- a/openair1/SCHED/ru_procedures.c +++ b/openair1/SCHED/ru_procedures.c @@ -69,11 +69,9 @@ void feptx0(RU_t *ru,int slot) { //int dummy_tx_b[7680*2] __attribute__((aligned(32))); unsigned int aa,slot_offset; - int i,j, tx_offset; + int i, tx_offset; int slot_sizeF = (fp->ofdm_symbol_size)* ((fp->Ncp==1) ? 6 : 7); - int len,len2; - int16_t *txdata; int subframe = ru->proc.subframe_tx; slot_offset = subframe*fp->samples_per_tti + (slot*(fp->samples_per_tti>>1)); diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index 0ca8616fd9..b632196474 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -211,19 +211,11 @@ static void configure_rrc(uint32_t enb_id) static uint32_t eNB_app_register(uint32_t enb_id_start, uint32_t enb_id_end)//, const Enb_properties_array_t *enb_properties) { uint32_t enb_id; - uint32_t mme_id; MessageDef *msg_p; uint32_t register_enb_pending = 0; - char *str = NULL; - struct in_addr addr; - -# if defined(OAI_EMU) - -# endif for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { # if defined(OAI_EMU) - if (oai_emulation.info.cli_start_enb[enb_id] == 1) # endif { @@ -307,7 +299,6 @@ void *eNB_app_task(void *args_p) const char *msg_name = NULL; instance_t instance; int result; - int j; /* for no gcc warnings */ (void)instance; diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h index b41545bcec..038cac2559 100644 --- a/openair2/ENB_APP/enb_config.h +++ b/openair2/ENB_APP/enb_config.h @@ -46,6 +46,8 @@ #else #include "RRC/LITE/MESSAGES/SystemInformationBlockType2.h" #endif +#include "intertask_interface_types.h" +#include "RRC/LITE/defs.h" #define IPV4_STR_ADDR_TO_INT_NWBO(AdDr_StR,NwBo,MeSsAgE ) do {\ struct in_addr inp;\ @@ -100,5 +102,8 @@ extern void RCConfig(void); void enb_config_display(void); void ru_config_display(void); +int RCconfig_RRC(MessageDef *msg_p, uint32_t i, eNB_RRC_INST *rrc); +int RCconfig_S1(MessageDef *msg_p, uint32_t i); + #endif /* ENB_CONFIG_H_ */ /** @} */ diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index d74955438f..21d3a2fbb1 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -32,6 +32,7 @@ #include "COMMON/platform_types.h" #include "COMMON/platform_constants.h" +#include "SCHED/defs.h" #include "SystemInformationBlockType2.h" //#include "RadioResourceConfigCommonSIB.h" #include "RadioResourceConfigDedicated.h" @@ -710,8 +711,6 @@ rrc_mac_config_req_ue( int i; - int UE_id = -1; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN); LOG_I(MAC,"[CONFIG][UE %d] Configuring MAC/PHY from eNB %d\n",Mod_idP,eNB_index); diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index b11634ef5d..5a9805654a 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -3605,9 +3605,9 @@ void SR_indication(module_id_t mod_idP, int cc_idP, frame_t frameP, sub_frame_t if (mac_eNB_get_rrc_status(mod_idP,UE_RNTI(mod_idP,UE_id)) < RRC_CONNECTED) LOG_D(MAC,"[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d on CC_id %d\n",mod_idP,rntiP,frameP,subframeP, UE_id,cc_idP); +#if 0 UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; -#if 0 /* for the moment don't use ul_cqi from SR, value is too different from harq */ sched_ctl->pucch1_snr[cc_idP] = ul_cqi; sched_ctl->pucch1_cqi_update[cc_idP] = 1; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index ee5ae3b584..fee2002e4b 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -854,7 +854,6 @@ void schedule_ulsch_rnti(module_id_t module_idP, UE_list_t *UE_list=&eNB->UE_list; UE_TEMPLATE *UE_template; UE_sched_ctrl *UE_sched_ctrl; - int tmode; int sched_frame=frameP; int rvidx_tab[4] = {0,2,3,1}; @@ -863,13 +862,8 @@ void schedule_ulsch_rnti(module_id_t module_idP, nfapi_hi_dci0_request_body_t *hi_dci0_req = &eNB->HI_DCI0_req[CC_id].hi_dci0_request_body; nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu; - nfapi_ul_config_request_pdu_t *ul_config_pdu; - nfapi_ul_config_request_body_t *ul_req_tmp = &eNB->UL_req_tmp[CC_id][sched_subframeP].ul_config_request_body; - ul_config_pdu = &ul_req_tmp->ul_config_pdu_list[0]; - - LOG_D(MAC,"entering ulsch preprocesor\n"); ulsch_scheduler_pre_processor(module_idP, frameP, diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 2bad81d52c..a610c9b69f 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -1058,7 +1058,11 @@ int narrowband_to_first_rb(COMMON_channels_t *cc, int nb_index); int l2_init_eNB(void); - +void Msg1_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); +void Msg3_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); +uint32_t from_earfcn(int eutra_bandP,uint32_t dl_earfcn); +int32_t get_uldl_offset(int eutra_bandP); +int l2_init_ue(int eMBMS_active, char *uecap_xer,uint8_t cba_group_active, uint8_t HO_active); #endif /** @}*/ diff --git a/openair2/LAYER2/MAC/ra_procedures.c b/openair2/LAYER2/MAC/ra_procedures.c index b63acf76f8..f1f19a6931 100644 --- a/openair2/LAYER2/MAC/ra_procedures.c +++ b/openair2/LAYER2/MAC/ra_procedures.c @@ -35,6 +35,7 @@ #include "proto.h" #include "UTIL/LOG/vcd_signal_dumper.h" #include "PHY_INTERFACE/extern.h" +#include "SCHED/defs.h" #include "COMMON/mac_rrc_primitives.h" #include "RRC/LITE/extern.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index 046ba33e71..de15e26b9c 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -89,6 +89,7 @@ extern Packet_OTG_List_t *otg_pdcp_buffer; #if defined(LINK_ENB_PDCP_TO_GTPV1U) # include "gtpv1u_eNB_task.h" +# include "gtpv1u_eNB_defs.h" #endif /* Prevent de-queueing the same PDCP SDU from the queue twice diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c index 14ca1a62a9..f6d8e3f9f4 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c @@ -79,9 +79,9 @@ void config_req_rlc_um ( } //----------------------------------------------------------------------------- #if defined(Rel14) -const uint32_t const t_Reordering_tab[32] = {0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,110,120,130,140,150,160,170,180,190,200,1600}; +const uint32_t t_Reordering_tab[32] = {0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,110,120,130,140,150,160,170,180,190,200,1600}; #else -const uint32_t const t_Reordering_tab[T_Reordering_spare1] = {0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,110,120,130,140,150,160,170,180,190,200}; +const uint32_t t_Reordering_tab[T_Reordering_spare1] = {0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,110,120,130,140,150,160,170,180,190,200}; #endif void config_req_rlc_um_asn1 ( diff --git a/openair2/RRC/LITE/proto.h b/openair2/RRC/LITE/proto.h index b0179bad8e..41eb4a224f 100644 --- a/openair2/RRC/LITE/proto.h +++ b/openair2/RRC/LITE/proto.h @@ -462,4 +462,12 @@ long binary_search_int(int elements[], long numElem, int value); long binary_search_float(float elements[], long numElem, float value); void openair_rrc_top_init_eNB(int eMBMS_active,uint8_t HO_active); + +void openair_rrc_top_init_ue( + int eMBMS_active, + char* uecap_xer, + uint8_t cba_group_active, + uint8_t HO_active +); + /** @}*/ diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index 5cbc612b48..291539696d 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -2604,7 +2604,7 @@ static const char* SIB2mac_ContentionResolutionTimer( long value ) } static const char* SIB2modificationPeriodCoeff( long value ) { - static char temp[4] = {0}; + static char temp[32] = {0}; if (value < 0 || value > 3) return "ERR"; @@ -2614,7 +2614,7 @@ static const char* SIB2modificationPeriodCoeff( long value ) } static const char* SIB2defaultPagingCycle( long value ) { - static char temp[6] = {0}; + static char temp[32] = {0}; if (value < 0 || value > 3) return "ERR"; diff --git a/openair2/UTIL/CLI/cli.c b/openair2/UTIL/CLI/cli.c index bb193728c9..445b1f1c0a 100644 --- a/openair2/UTIL/CLI/cli.c +++ b/openair2/UTIL/CLI/cli.c @@ -215,7 +215,7 @@ int cli_login(const char *username, int maxnodes, int maxcmds) char *cli_prompt(void) { - static char promptstr[200]; + static char promptstr[256]; promptstr[0]='\0'; snprintf(promptstr, 200,"%s@%s",username, cli_cfg->prompt); return promptstr; diff --git a/openair2/UTIL/CLI/cli_cmd.c b/openair2/UTIL/CLI/cli_cmd.c index 366295bf1a..d1e210e438 100644 --- a/openair2/UTIL/CLI/cli_cmd.c +++ b/openair2/UTIL/CLI/cli_cmd.c @@ -103,7 +103,7 @@ int prompt (char *arg) return 0; if (!arg || !*arg) { // no arg is provided, run get func - snprintf(buffer,200,"%s\n", cli_cfg->prompt); + snprintf(buffer,256,"%s\n", cli_cfg->prompt); send(cli_cfg->cfd, buffer, strlen(buffer), 0); // send(cli_cfg->cfd, cli_cfg->prompt, strlen(cli_cfg->prompt), 0); } else {// set func diff --git a/openair2/UTIL/OTG/otg_rx.c b/openair2/UTIL/OTG/otg_rx.c index 824439e873..a5b26594eb 100644 --- a/openair2/UTIL/OTG/otg_rx.c +++ b/openair2/UTIL/OTG/otg_rx.c @@ -48,10 +48,11 @@ extern unsigned char NB_UE_INST; //#include "LAYER2/MAC/extern.h" +#undef MAX #define MAX(x,y) ((x)>(y)?(x):(y)) +#undef MIN #define MIN(x,y) ((x)<(y)?(x):(y)) - // Check if the packet is well received or not and extract data int otg_rx_pkt(const int dst_instanceP, const int ctime, const char * const buffer_tx, const unsigned int size) { diff --git a/openair3/GTPV1-U/gtpv1u_eNB_defs.h b/openair3/GTPV1-U/gtpv1u_eNB_defs.h index 91f045ace2..24334d5864 100644 --- a/openair3/GTPV1-U/gtpv1u_eNB_defs.h +++ b/openair3/GTPV1-U/gtpv1u_eNB_defs.h @@ -33,6 +33,8 @@ #ifndef GTPV1U_ENB_DEFS_H_ #define GTPV1U_ENB_DEFS_H_ +#include "NwGtpv1u.h" + #define GTPV1U_UDP_PORT (2152) #define GTPV1U_BEARER_OFFSET 3 diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index 28003f75db..0b6ce275ba 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -259,4 +259,9 @@ extern void init_fep_thread(PHY_VARS_eNB *, pthread_attr_t *); extern void init_td_thread(PHY_VARS_eNB *, pthread_attr_t *); extern void init_te_thread(PHY_VARS_eNB *, pthread_attr_t *); +PHY_VARS_UE* init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms, + uint8_t UE_id, + uint8_t abstraction_flag); +void init_eNB_afterRU(void); + #endif diff --git a/targets/RT/USER/rt_wrapper.c b/targets/RT/USER/rt_wrapper.c index e50b0ae34f..5a03204f1d 100644 --- a/targets/RT/USER/rt_wrapper.c +++ b/targets/RT/USER/rt_wrapper.c @@ -44,6 +44,8 @@ #include #include "rt_wrapper.h" +#include "openair1/PHY/defs.h" + static int latency_target_fd = -1; static int32_t latency_target_value = 0; /* Latency trick - taken from cyclictest.c From bf926e3546530aea5fbb54e85121ddaabd66d8f9 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 19 Oct 2017 17:21:21 +0200 Subject: [PATCH 052/284] bugfix/warning removal The warning was: /roux/ru/openairinterface5g/openair1/PHY/LTE_TRANSPORT/pucch.c: In function 'generate_pucch2x': /roux/ru/openairinterface5g/openair1/PHY/LTE_TRANSPORT/pucch.c:729:73: warning: array subscript is above array bounds [-Warray-bounds] AssertFatal(1==0,"Illegal modulation symbol %d for PUCCH %s\n",B2,pucch_format_string[fmt]); ^ /roux/ru/openairinterface5g/common/utils/./itti/assertions.h:52:53: note: in definition of macro '_Assert_' __FUNCTION__, __FILE__, __LINE__, ##aRGS); \ ^~~~ /roux/ru/openairinterface5g/openair1/PHY/LTE_TRANSPORT/pucch.c:729:7: note: in expansion of macro 'AssertFatal' AssertFatal(1==0,"Illegal modulation symbol %d for PUCCH %s\n",B2,pucch_format_string[fmt]); ^ The root cause was that the array pucch_format_string was not in sync with the structure. (This plus why force its size and put \0 in the string...) --- openair1/PHY/LTE_TRANSPORT/pucch.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/LTE_TRANSPORT/pucch.c b/openair1/PHY/LTE_TRANSPORT/pucch.c index ad9ed2c95d..05355c9992 100644 --- a/openair1/PHY/LTE_TRANSPORT/pucch.c +++ b/openair1/PHY/LTE_TRANSPORT/pucch.c @@ -113,7 +113,18 @@ int16_t W3_im[3][6] = {{0 ,0 ,0 }, {0 ,-28378, 28377} }; -char pucch_format_string[6][20] = {"format 1\0","format 1a\0","format 1b\0","format 2\0","format 2a\0","format 2b\0"}; +char *pucch_format_string[] = { + "format 1", + "format 1a", + "format 1b", + "pucch_format1b_csA2", + "pucch_format1b_csA3", + "pucch_format1b_csA4", + "format 2", + "format 2a", + "format 2b", + "pucch_format3" +}; /* PUCCH format3 >> */ #define D_I 0 From e3d39a0192d72ef188f7c6ef850ed729e1cb61b7 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 20 Oct 2017 12:08:43 +0200 Subject: [PATCH 053/284] bugfix/compilation warning removal (not sure if correct) basically the T_xx variables are int, not uint --- targets/RT/USER/lte-softmodem.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index 0b6ce275ba..c0cc6ba77c 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -198,9 +198,9 @@ extern int T_dont_fork; /* optname helpstr paramflags XXXptr defXXXval type numelt */ /*------------------------------------------------------------------------------------------------------------------------------------------*/ #define CMDLINE_TTRACEPARAMS_DESC { \ -{"T_port", CONFIG_HLP_TPORT, 0, uptr:&T_port, defuintval:0, TYPE_UINT, 0}, \ -{"T_nowait", CONFIG_HLP_NOTWAIT, PARAMFLAG_BOOL, uptr:&T_nowait, defuintval:0, TYPE_UINT, 0}, \ -{"T_dont_fork", CONFIG_HLP_TNOFORK, PARAMFLAG_BOOL, uptr:&T_dont_fork, defuintval:1, TYPE_UINT, 0}, \ +{"T_port", CONFIG_HLP_TPORT, 0, iptr:&T_port, defintval:0, TYPE_INT, 0}, \ +{"T_nowait", CONFIG_HLP_NOTWAIT, PARAMFLAG_BOOL, iptr:&T_nowait, defintval:0, TYPE_INT, 0}, \ +{"T_dont_fork", CONFIG_HLP_TNOFORK, PARAMFLAG_BOOL, iptr:&T_dont_fork, defintval:1, TYPE_INT, 0}, \ } From c090015741e93743bad4f85ed3800ef1f8041b03 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Fri, 20 Oct 2017 14:21:39 +0200 Subject: [PATCH 054/284] MTU tuning for IF4p5 fronthaul --- targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c index f5bc5ea767..e02e257334 100644 --- a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c +++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c @@ -116,8 +116,8 @@ int trx_eth_start(openair0_device *device) { */ /* adjust MTU wrt number of samples per packet */ - /*if(ethernet_tune (device,MTU_SIZE,UDP_IF4p5_PRACH_SIZE_BYTES)!=0) return -1; - */ + if(ethernet_tune (device,MTU_SIZE,UDP_IF4p5_PRACH_SIZE_BYTES)!=0) return -1; + From 5afc71f382049f30dddf61216db05f250ab47c00 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 20 Oct 2017 14:49:45 +0200 Subject: [PATCH 055/284] bugfix: fix featureGroup - allocate memory, memory on stack does not survive the function - avoid uint32_t, use a char buffer, for endianness neutrality --- openair2/RRC/LITE/MESSAGES/asn1_msg.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index c378e47663..74b2dabd5a 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -2577,18 +2577,17 @@ OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname) // UE_EUTRA_Capability->measParameters.bandListEUTRA.list.count = 0; // no measurements on other bands // UE_EUTRA_Capability->featureGroupIndicators // null - // featureGroup is mandatory for CMW tests - // featureGroup is filled only for usim-test mode - BIT_STRING_t *bit_string; - uint32_t featrG; - bit_string = CALLOC(1, sizeof(*bit_string)); - featrG = 0x04000800; if(usim_test == 1) { - bit_string->buf = &featrG; - bit_string->size = 4; - bit_string->bits_unused = 0; - UE_EUTRA_Capability->featureGroupIndicators = bit_string; + // featureGroup is mandatory for CMW tests + // featureGroup is filled only for usim-test mode + BIT_STRING_t *bit_string = CALLOC(1, sizeof(*bit_string)); + char featrG[4] = { 0x00, 0x08, 0x00, 0x04 }; + bit_string->buf = CALLOC(1, 4); + memcpy(bit_string->buf, featrG, 4); + bit_string->size = 4; + bit_string->bits_unused = 0; + UE_EUTRA_Capability->featureGroupIndicators = bit_string; } // UE_EUTRA_Capability->interRAT_Parameters // null From 6087ede004188408d2adb85d949f98a337662e4c Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 20 Oct 2017 14:52:42 +0200 Subject: [PATCH 056/284] fix asn1_msg.c - compile with warning enabled (changes in CMakeLists.txt) - remove warnings that were present --- cmake_targets/CMakeLists.txt | 4 +-- openair2/RRC/LITE/MESSAGES/asn1_msg.c | 40 +++++++++++++-------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index e34e627459..4afd48d3c2 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -312,11 +312,11 @@ if (NOT ${ret} STREQUAL 0) message(FATAL_ERROR "${fix_asn1c_call}: error") endif (NOT ${ret} STREQUAL 0) file(GLOB rrc_source ${RRC_FULL_DIR}/*.c) -set(rrc_source ${rrc_source} ${OPENAIR2_DIR}/RRC/LITE/MESSAGES/asn1_msg.c) file(GLOB rrc_h ${RRC_FULL_DIR}/*.h) set(rrc_h ${rrc_h} ${RRC_FULL_DIR}/asn1_constants.h) set_source_files_properties(${rrc_source} PROPERTIES COMPILE_FLAGS -w) # suppress warnings from generated code -add_library(RRC_LIB ${rrc_h} ${rrc_source}) +add_library(RRC_LIB ${rrc_h} ${rrc_source} + ${OPENAIR2_DIR}/RRC/LITE/MESSAGES/asn1_msg.c) include_directories ("${RRC_FULL_DIR}") # add the command to generate the source code diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index 74b2dabd5a..f1b6174c9e 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -158,11 +158,11 @@ int xer_sprint (char *string, size_t string_size, asn_TYPE_descriptor_t *td, voi er = xer_encode(td, sptr, XER_F_BASIC, xer__print2s, &string_buffer); if (er.encoded < 0) { - LOG_E(RRC, "xer_sprint encoding error (%d)!", er.encoded); + LOG_E(RRC, "xer_sprint encoding error (%zd)!", er.encoded); er.encoded = string_buffer.string_size; } else { if (er.encoded > string_buffer.string_size) { - LOG_E(RRC, "xer_sprint string buffer too small, got %d need %d!", string_buffer.string_size, er.encoded); + LOG_E(RRC, "xer_sprint string buffer too small, got %zd need %zd!", string_buffer.string_size, er.encoded); er.encoded = string_buffer.string_size; } } @@ -484,7 +484,7 @@ uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier, #endif #ifdef USER_MODE - LOG_D(RRC,"[eNB] SystemInformationBlockType1 Encoded %d bits (%d bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + LOG_D(RRC,"[eNB] SystemInformationBlockType1 Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); #endif if (enc_rval.encoded==-1) { @@ -1014,7 +1014,7 @@ uint8_t do_SIB23(uint8_t Mod_id, #endif #ifdef USER_MODE - LOG_D(RRC,"[eNB] SystemInformation Encoded %d bits (%d bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + LOG_D(RRC,"[eNB] SystemInformation Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); #endif if (enc_rval.encoded==-1) { @@ -1103,7 +1103,7 @@ uint8_t do_RRCConnectionRequest(uint8_t Mod_id, uint8_t *buffer,uint8_t *rv) #endif #ifdef USER_MODE - LOG_D(RRC,"[UE] RRCConnectionRequest Encoded %d bits (%d bytes), ecause %d\n",enc_rval.encoded,(enc_rval.encoded+7)/8,ecause); + LOG_D(RRC,"[UE] RRCConnectionRequest Encoded %zd bits (%zd bytes), ecause %d\n",enc_rval.encoded,(enc_rval.encoded+7)/8,ecause); #endif return((enc_rval.encoded+7)/8); @@ -1186,7 +1186,7 @@ uint8_t do_RRCConnectionSetupComplete(uint8_t Mod_id, uint8_t *buffer, const uin #endif #ifdef USER_MODE - LOG_D(RRC,"RRCConnectionSetupComplete Encoded %d bits (%d bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + LOG_D(RRC,"RRCConnectionSetupComplete Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); #endif return((enc_rval.encoded+7)/8); @@ -1248,7 +1248,7 @@ do_RRCConnectionReconfigurationComplete( #endif #ifdef USER_MODE - LOG_D(RRC,"RRCConnectionReconfigurationComplete Encoded %d bits (%d bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + LOG_D(RRC,"RRCConnectionReconfigurationComplete Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); #endif return((enc_rval.encoded+7)/8); @@ -1468,7 +1468,7 @@ do_RRCConnectionSetup( if (carrier->sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.present == SoundingRS_UL_ConfigCommon_PR_setup) if (carrier->sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig!=0) - LOG_W(RRC,"This code has been optimized for SRS Subframe Config 0, but current config is %d. Expect undefined behaviour!\n", + LOG_W(RRC,"This code has been optimized for SRS Subframe Config 0, but current config is %zd. Expect undefined behaviour!\n", carrier->sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig); if (ue_context_pP->local_uid >=20) LOG_W(RRC,"This code has been optimized for up to 10 UEs, but current UE_id is %d. Expect undefined behaviour!\n", @@ -1481,7 +1481,7 @@ do_RRCConnectionSetup( if (carrier->sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.present == SoundingRS_UL_ConfigCommon_PR_setup) if (carrier->sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig!=7) { - LOG_W(RRC,"This code has been optimized for SRS Subframe Config 7 and TDD config 3, but current configs are %d and %d. Expect undefined behaviour!\n", + LOG_W(RRC,"This code has been optimized for SRS Subframe Config 7 and TDD config 3, but current configs are %zd and %zd. Expect undefined behaviour!\n", carrier->sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig, carrier->sib1->tdd_Config->subframeAssignment); } @@ -1491,7 +1491,7 @@ do_RRCConnectionSetup( physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex=17+ue_context_pP->local_uid/2; physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb= ue_context_pP->local_uid%2; } - LOG_W(RRC,"local UID %d, srs ConfigIndex %d, TransmissionComb %d\n",ue_context_pP->local_uid, + LOG_W(RRC,"local UID %d, srs ConfigIndex %zd, TransmissionComb %zd\n",ue_context_pP->local_uid, physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex, physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb); @@ -1637,7 +1637,7 @@ do_RRCConnectionSetup( #endif #ifdef USER_MODE - LOG_D(RRC,"RRCConnectionSetup Encoded %d bits (%d bytes), ecause %d\n", + LOG_D(RRC,"RRCConnectionSetup Encoded %zd bits (%zd bytes), ecause %d\n", enc_rval.encoded,(enc_rval.encoded+7)/8,ecause); #endif @@ -1710,7 +1710,7 @@ do_SecurityModeCommand( #endif #ifdef USER_MODE - LOG_D(RRC,"[eNB %d] securityModeCommand for UE %x Encoded %d bits (%d bytes)\n", + LOG_D(RRC,"[eNB %d] securityModeCommand for UE %x Encoded %zd bits (%zd bytes)\n", ctxt_pP->module_id, ctxt_pP->rnti, enc_rval.encoded, @@ -1788,7 +1788,7 @@ do_UECapabilityEnquiry( #endif #ifdef USER_MODE - LOG_D(RRC,"[eNB %d] UECapabilityRequest for UE %x Encoded %d bits (%d bytes)\n", + LOG_D(RRC,"[eNB %d] UECapabilityRequest for UE %x Encoded %zd bits (%zd bytes)\n", ctxt_pP->module_id, ctxt_pP->rnti, enc_rval.encoded, @@ -1927,7 +1927,7 @@ do_RRCConnectionReconfiguration( (void*)&dl_dcch_msg, buffer, RRC_BUF_SIZE); - AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %l)!\n", + AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %zd)!\n", enc_rval.failed_type->name, enc_rval.encoded); #ifdef XER_PRINT @@ -1954,7 +1954,7 @@ do_RRCConnectionReconfiguration( #endif //#ifdef USER_MODE - LOG_I(RRC,"RRCConnectionReconfiguration Encoded %d bits (%d bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + LOG_I(RRC,"RRCConnectionReconfiguration Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); // for (i=0;i<30;i++) // msg("%x.",buffer[i]); // msg("\n"); @@ -2015,7 +2015,7 @@ do_RRCConnectionReestablishmentReject( #endif #ifdef USER_MODE - LOG_D(RRC,"RRCConnectionReestablishmentReject Encoded %d bits (%d bytes)\n", + LOG_D(RRC,"RRCConnectionReestablishmentReject Encoded %zd bits (%zd bytes)\n", enc_rval.encoded,(enc_rval.encoded+7)/8); #endif @@ -2076,7 +2076,7 @@ do_RRCConnectionReject( #endif #ifdef USER_MODE - LOG_D(RRC,"RRCConnectionReject Encoded %d bits (%d bytes)\n", + LOG_D(RRC,"RRCConnectionReject Encoded %zd bits (%zd bytes)\n", enc_rval.encoded,(enc_rval.encoded+7)/8); #endif @@ -2267,7 +2267,7 @@ uint8_t do_MBSFNAreaConfig(uint8_t Mod_id, #endif #ifdef USER_MODE - LOG_D(RRC,"[eNB] MCCH Message Encoded %d bits (%d bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + LOG_D(RRC,"[eNB] MCCH Message Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); #endif if (enc_rval.encoded==-1) { @@ -2490,7 +2490,7 @@ OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname) char UE_EUTRA_Capability_xer[8192]; size_t size; - LOG_I(RRC,"Allocating %u bytes for UE_EUTRA_Capability\n",sizeof(*UE_EUTRA_Capability)); + LOG_I(RRC,"Allocating %zu bytes for UE_EUTRA_Capability\n",sizeof(*UE_EUTRA_Capability)); UE_EUTRA_Capability = CALLOC(1, sizeof(*UE_EUTRA_Capability)); @@ -2648,7 +2648,7 @@ OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname) #endif UECapability.sdu_size = (enc_rval.encoded + 7) / 8; - LOG_I(PHY, "[RRC]UE Capability encoded, %d bytes (%d bits)\n", + LOG_I(PHY, "[RRC]UE Capability encoded, %d bytes (%zd bits)\n", UECapability.sdu_size, enc_rval.encoded + 7); { char *sdu; From 5fefa11234d55881f1de841d0005d88c3979155d Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Fri, 20 Oct 2017 15:02:25 +0200 Subject: [PATCH 057/284] TDD for RRU IF4p5, modifications and testing. --- openair1/PHY/LTE_TRANSPORT/if4_tools.c | 11 +++-- openair1/PHY/defs.h | 4 ++ openair1/SCHED/ru_procedures.c | 17 ++++++- targets/RT/USER/lte-ru.c | 62 ++++++++++++++------------ 4 files changed, 58 insertions(+), 36 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/if4_tools.c b/openair1/PHY/LTE_TRANSPORT/if4_tools.c index c3cd8d48b7..e5fe6e7591 100644 --- a/openair1/PHY/LTE_TRANSPORT/if4_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/if4_tools.c @@ -67,7 +67,7 @@ void send_IF4p5(RU_t *ru, int frame, int subframe, uint16_t packet_type) { if (ru->idx==0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF4, 1 ); if (packet_type == IF4p5_PDLFFT) { - LOG_D(PHY,"send DL_IF4p5: RU %d frame %d, subframe %d\n",ru->idx,frame,subframe); + //LOG_D(PHY,"send DL_IF4p5: RU %d frame %d, subframe %d\n",ru->idx,frame,subframe); if (subframe_select(fp,subframe)==SF_S) nsym=fp->dl_symbols_in_S_subframe; @@ -138,10 +138,9 @@ void send_IF4p5(RU_t *ru, int frame, int subframe, uint16_t packet_type) { if (packet_type == IF4p5_PULFFT) { - for (symbol_id=fp->symbols_per_tti-nsym; symbol_idsymbols_per_tti; symbol_id++) { VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF4_SYMBOL, symbol_id ); + for (symbol_id=fp->symbols_per_tti-nsym; symbol_idsymbols_per_tti; symbol_id++) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF4_SYMBOL, symbol_id ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_COMPR_IF, 1 ); - LOG_D(PHY,"IF4p5_PULFFT: frame %d, subframe %d, symbol %d: %d dB\n",frame,subframe,symbol_id, - dB_fixed(signal_energy((int32_t*)&rxdataF[0][blockoffsetF],db_halflength))); for (element_id=0; element_id %d dB\n",ru->idx,*frame,*subframe, - dB_fixed(signal_energy((int*)&prach_rxsigF[0][0],839))); + //LOG_D(PHY,"PRACH_IF4p5: CC_id %d : frame %d, subframe %d => %d dB\n",ru->idx,*frame,*subframe, + // dB_fixed(signal_energy((int*)&prach_rxsigF[0][0],839))); for (idx=0;idxnum_eNB;idx++) ru->wakeup_prach_eNB(ru->eNB_list[idx],ru,*frame,*subframe); } else if (*packet_type == IF4p5_PULTICK) { diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 446c1f1575..12ddcdeb70 100644 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -752,6 +752,10 @@ typedef struct RU_t_s{ time_stats_t ofdm_demod_stats; /// Timing statistics (TX) time_stats_t ofdm_mod_stats; + /// Timing statistics (RX Fronthaul + Compression) + time_stats_t rx_fhaul; + /// Timing statistics (TX Fronthaul + Compression) + time_stats_t tx_fhaul; /// RX and TX buffers for precoder output RU_COMMON common; /// beamforming weight vectors per eNB diff --git a/openair1/SCHED/ru_procedures.c b/openair1/SCHED/ru_procedures.c index 7e0ca4e76a..825caac325 100644 --- a/openair1/SCHED/ru_procedures.c +++ b/openair1/SCHED/ru_procedures.c @@ -175,6 +175,8 @@ void feptx_ofdm_2thread(RU_t *ru) { if (subframe_select(fp,subframe) == SF_UL) return; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 1 ); + if (subframe_select(fp,subframe)==SF_DL) { // If this is not an S-subframe if (pthread_mutex_timedlock(&proc->mutex_feptx,&wait) != 0) { @@ -206,6 +208,8 @@ void feptx_ofdm_2thread(RU_t *ru) { feptx0(ru,0); wait_on_busy_condition(&proc->mutex_feptx,&proc->cond_feptx,&proc->instance_cnt_feptx,"feptx thread"); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 0 ); + stop_meas(&ru->ofdm_mod_stats); } @@ -468,6 +472,13 @@ void ru_fep_full_2thread(RU_t *ru) { struct timespec wait; + LTE_DL_FRAME_PARMS *fp=&ru->frame_parms; + + if ((fp->frame_type == TDD) && + (subframe_select(fp,proc->subframe_rx) != SF_UL)) return; + + if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 ); + wait.tv_sec=0; wait.tv_nsec=5000000L; @@ -513,8 +524,11 @@ void fep_full(RU_t *ru) { int l; LTE_DL_FRAME_PARMS *fp=&ru->frame_parms; - start_meas(&ru->ofdm_demod_stats); + if ((fp->frame_type == TDD) && + (subframe_select(fp,proc->subframe_rx) != SF_UL)) return; + start_meas(&ru->ofdm_demod_stats); + if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 ); remove_7_5_kHz(ru,proc->subframe_rx<<1); remove_7_5_kHz(ru,1+(proc->subframe_rx<<1)); @@ -530,6 +544,7 @@ void fep_full(RU_t *ru) { 0 ); } + if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 0 ); stop_meas(&ru->ofdm_demod_stats); diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 4fa2352368..33dcf425ca 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -595,6 +595,7 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { symbol_mask_full = ((subframe_select(fp,*subframe) == SF_S) ? (1<dl_symbols_in_S_subframe) : (1<symbols_per_tti))-1; do { recv_IF4p5(ru, &frame_tx, &subframe_tx, &packet_type, &symbol_number); + if ((subframe_select(fp,*subframe) == SF_DL) && (symbol_number == 0)) start_meas(&ru->rx_fhaul); LOG_D(PHY,"subframe %d (%d): frame %d, subframe %d, symbol %d\n", *subframe,subframe_select(fp,*subframe),frame_tx,subframe_tx,symbol_number); if (proc->first_tx != 0) { @@ -614,6 +615,8 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { else AssertFatal(1==0,"Illegal IF4p5 packet type (should only be IF4p5_PDLFFT%d\n",packet_type); } while (symbol_mask != symbol_mask_full); + if (subframe_select(fp,*subframe) == SF_DL) stop_meas(&ru->rx_fhaul); + proc->subframe_tx = subframe_tx; proc->frame_tx = frame_tx; @@ -656,16 +659,11 @@ void fh_if4p5_north_out(RU_t *ru) { send_IF4p5(ru, proc->frame_rx, proc->subframe_rx, IF4p5_PULTICK); return; } - if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 ); - AssertFatal(ru->feprx!=NULL,"No northbound FEP function, exiting\n"); - if (ru->feprx) { - LOG_D(PHY,"Doing FEP/IF4p5 for frame %d, subframe %d\n",proc->frame_rx,proc->subframe_rx); - ru->feprx(ru); - send_IF4p5(ru, proc->frame_rx, proc->subframe_rx, IF4p5_PULFFT); - } + start_meas(&ru->tx_fhaul); + send_IF4p5(ru, proc->frame_rx, proc->subframe_rx, IF4p5_PULFFT); + stop_meas(&ru->tx_fhaul); - if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 0 ); } void rx_rf(RU_t *ru,int *frame,int *subframe) { @@ -772,11 +770,11 @@ void tx_rf(RU_t *ru) { lte_subframe_t SF_type = subframe_select(fp,proc->subframe_tx%10); lte_subframe_t prevSF_type = subframe_select(fp,(proc->subframe_tx+9)%10); lte_subframe_t nextSF_type = subframe_select(fp,(proc->subframe_tx+1)%10); + int sf_extension = 0; + if ((SF_type == SF_DL) || (SF_type == SF_S)) { - for (i=0; inb_tx; i++) - txp[i] = (void*)&ru->common.txdata[i][proc->subframe_tx*fp->samples_per_tti]; int siglen=fp->samples_per_tti,flags=1; @@ -787,24 +785,31 @@ void tx_rf(RU_t *ru) { if ((fp->frame_type == TDD) && (SF_type == SF_DL)&& (prevSF_type == SF_UL) && - (nextSF_type == SF_DL)) + (nextSF_type == SF_DL)) { flags = 2; // start of burst + sf_extension = ru->N_TA_offset<<1; + } if ((fp->frame_type == TDD) && (SF_type == SF_DL)&& (prevSF_type == SF_UL) && - (nextSF_type == SF_UL)) + (nextSF_type == SF_UL)) { flags = 4; // start of burst and end of burst (only one DL SF between two UL) - + sf_extension = ru->N_TA_offset<<1; + } + + for (i=0; inb_tx; i++) + txp[i] = (void*)&ru->common.txdata[i][(proc->subframe_tx*fp->samples_per_tti)-sf_extension]; + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (proc->timestamp_tx-ru->openair0_cfg.tx_sample_advance)&0xffffffff ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 ); // prepare tx buffer pointers txs = ru->rfdevice.trx_write_func(&ru->rfdevice, - proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance, + proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, txp, - siglen, + siglen+sf_extension, ru->nb_tx, flags); @@ -813,7 +818,7 @@ void tx_rf(RU_t *ru) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); - AssertFatal(txs == siglen,"TX : Timeout (sent %d/%d)\n",txs, siglen); + AssertFatal(txs == siglen+sf_extension,"TX : Timeout (sent %d/%d)\n",txs, siglen); } } @@ -1260,18 +1265,12 @@ int setup_RU_buffers(RU_t *ru) { return(-1); } - /* - if (frame_parms->frame_type == TDD) { - if (frame_parms->N_RB_DL == 100) - N_TA_offset = 624; - else if (frame_parms->N_RB_DL == 50) - N_TA_offset = 624/2; - else if (frame_parms->N_RB_DL == 25) - N_TA_offset = 624/4; - } - */ - + if (frame_parms->frame_type == TDD) { + if (frame_parms->N_RB_DL == 100) ru->N_TA_offset = 624; + else if (frame_parms->N_RB_DL == 50) ru->N_TA_offset = 624/2; + else if (frame_parms->N_RB_DL == 25) ru->N_TA_offset = 624/4; + } if (ru->openair0_cfg.mmapped_dma == 1) { // replace RX signal buffers with mmaped HW versions @@ -1321,6 +1320,9 @@ static void* ru_stats_thread(void* param) { if (opp_enabled == 1) { if (ru->feprx) print_meas(&ru->ofdm_demod_stats,"feprx",NULL,NULL); if (ru->feptx_ofdm) print_meas(&ru->ofdm_mod_stats,"feptx_ofdm",NULL,NULL); + if (ru->fh_north_asynch_in) print_meas(&ru->rx_fhaul,"rx_fhaul",NULL,NULL); + if (ru->fh_north_out) print_meas(&ru->tx_fhaul,"tx_fhaul",NULL,NULL); + } } return(NULL); @@ -1440,9 +1442,7 @@ static void* ru_thread( void* param ) { // do RX front-end processing (frequency-shift, dft) if needed - if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 ); if (ru->feprx) ru->feprx(ru); - if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 0 ); // At this point, all information for subframe has been received on FH interface // If this proc is to provide synchronization, do so @@ -1908,6 +1908,8 @@ void init_RU(char *rf_config_file) { ru->ifdevice.host_type = RRU_HOST; ru->rfdevice.host_type = RRU_HOST; ru->ifdevice.eth_params = &ru->eth_params; + reset_meas(&ru->rx_fhaul); + reset_meas(&ru->tx_fhaul); ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); printf("openair0_transport_init returns %d for ru_id %d\n",ret,ru_id); @@ -1929,6 +1931,8 @@ void init_RU(char *rf_config_file) { ru->ifdevice.host_type = RRU_HOST; ru->rfdevice.host_type = RRU_HOST; ru->ifdevice.eth_params = &ru->eth_params; + reset_meas(&ru->rx_fhaul); + reset_meas(&ru->tx_fhaul); ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); printf("openair0_transport_init returns %d for ru_id %d\n",ret,ru_id); From 26d4ad2bb611650afbd5036b92710afdac8fcb9f Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sun, 22 Oct 2017 17:28:50 +0200 Subject: [PATCH 058/284] don't call fronthaul write on RX in TDD. --- targets/RT/USER/lte-ru.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 33dcf425ca..45f69ca414 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -312,7 +312,8 @@ static inline void fh_if5_mobipass_south_out(RU_t *ru) { static inline void fh_if4p5_south_out(RU_t *ru) { if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.subframe_tx); - send_IF4p5(ru,ru->proc.frame_tx, ru->proc.subframe_tx, IF4p5_PDLFFT); + if (subframe_select(&ru->frame_parms,ru->proc.subframe_tx)!=SF_UL) + send_IF4p5(ru,ru->proc.frame_tx, ru->proc.subframe_tx, IF4p5_PDLFFT); } /*************************************************************/ From 8846260bdf11ab60b7b56e27ced2a5a4d0e921c0 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sun, 22 Oct 2017 21:58:31 +0200 Subject: [PATCH 059/284] Added prach background noise detection and threshold dependent on noise measurement. --- openair1/PHY/LTE_TRANSPORT/prach.c | 4 +-- openair1/PHY/defs.h | 7 ++-- openair1/SCHED/phy_procedures_lte_eNb.c | 46 ++++++++++++++----------- targets/RT/USER/lte-enb.c | 1 + 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c index 2a50488ad3..7f01ae32ba 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.c +++ b/openair1/PHY/LTE_TRANSPORT/prach.c @@ -1648,13 +1648,13 @@ void rx_prach0(PHY_VARS_eNB *eNB, idft1024(prachF,prach_ifft_tmp,1); // compute energy and accumulate over receive antennas and repetitions for BR for (i=0;i<2048;i++) - prach_ifft[i] += (prach_ifft_tmp[i<<1]*prach_ifft_tmp[i<<1] + prach_ifft_tmp[1+(i<<1)]*prach_ifft_tmp[1+(i<<1)])>>15; + prach_ifft[i] += (prach_ifft_tmp[i<<1]*prach_ifft_tmp[i<<1] + prach_ifft_tmp[1+(i<<1)]*prach_ifft_tmp[1+(i<<1)])>>10; } else { idft256(prachF,prach_ifft_tmp,1); log2_ifft_size = 8; // compute energy and accumulate over receive antennas and repetitions for BR for (i=0;i<256;i++) - prach_ifft[i] += (prach_ifft_tmp[i<<1]*prach_ifft_tmp[(i<<1)] + prach_ifft_tmp[1+(i<<1)]*prach_ifft_tmp[1+(i<<1)])>>15; + prach_ifft[i] += (prach_ifft_tmp[i<<1]*prach_ifft_tmp[(i<<1)] + prach_ifft_tmp[1+(i<<1)]*prach_ifft_tmp[1+(i<<1)])>>10; } #ifdef PRACH_DEBUG diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 12ddcdeb70..bdfc373144 100644 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -919,7 +919,8 @@ typedef struct { int subband_cqi_dB[NUMBER_OF_UE_MAX][MAX_NUM_RU_PER_eNB][100]; /// Total Subband CQI and RB int subband_cqi_tot_dB[NUMBER_OF_UE_MAX][100]; - + /// PRACH background noise level + int prach_I0; } PHY_MEASUREMENTS_eNB; @@ -1035,8 +1036,8 @@ typedef struct PHY_VARS_eNB_s { /// if ==0 enables phy only test mode int mac_enabled; - - + /// counter to average prach energh over first 100 prach opportunities + int prach_energy_counter; // PDSCH Varaibles PDSCH_CONFIG_DEDICATED pdsch_config_dedicated[NUMBER_OF_UE_MAX]; diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 5862f27b71..05a6dca09b 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -633,7 +633,8 @@ void prach_procedures(PHY_VARS_eNB *eNB, eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[ce_level])) { */ if (eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0]==1){ - if (max_preamble_energy[0] > 350) { + if ((eNB->prach_energy_counter == 100) && + (max_preamble_energy[0] > eNB->measurements.prach_I0 + 100)) { eNB->UL_INFO.rach_ind_br.number_of_preambles++; eNB->preamble_list_br[ind].preamble_rel8.timing_advance = max_preamble_delay[ind];// @@ -661,7 +662,8 @@ void prach_procedures(PHY_VARS_eNB *eNB, #endif { - if (max_preamble_energy[0] > 350) { + if ((eNB->prach_energy_counter == 100) && + (max_preamble_energy[0] > eNB->measurements.prach_I0+100)) { LOG_D(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", eNB->Mod_id, @@ -694,22 +696,13 @@ void prach_procedures(PHY_VARS_eNB *eNB, eNB->preamble_list[0].preamble_rel13.rach_resource_type); pthread_mutex_unlock(&eNB->UL_INFO_mutex); - } // max_preamble_energy > 350 + } // max_preamble_energy > prach_I0 + 100 + else { + eNB->measurements.prach_I0 = ((eNB->measurements.prach_I0*900)>>10) + ((max_preamble_energy[0]*124)>>10); + if (frame==0) LOG_I(PHY,"prach_I0 = %d.%d dB\n",eNB->measurements.prach_I0/10,eNB->measurements.prach_I0%10); + if (eNB->prach_energy_counter < 100) eNB->prach_energy_counter++; + } } // else br_flag - /* - mac_xface->initiate_ra_proc(eNB->Mod_id, - eNB->CC_id, - frame, - preamble_max, - preamble_delay_list[preamble_max]*update_TA/update_TA2, - 0,subframe,0);*/ - - - /* } else { - MSC_LOG_EVENT(MSC_PHY_ENB, "0 RA Failed add user, too many"); - LOG_I(PHY,"[eNB %d][RAPROC] frame %d, subframe %d: Unable to add user, max user count reached\n", - eNB->Mod_id,frame, subframe); - }*/ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0); } @@ -1952,16 +1945,27 @@ void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,const // Call SRS first since all others depend on presence of SRS or lack thereof srs_procedures(eNB,proc); - lte_eNB_I0_measurements(eNB, - subframe, - 0, - eNB->first_run_I0_measurements); eNB->first_run_I0_measurements = 0; uci_procedures(eNB,proc); pusch_procedures(eNB,proc); + lte_eNB_I0_measurements(eNB, + subframe, + 0, + eNB->first_run_I0_measurements); + + int min_I0=1000,max_I0=0; + if ((frame==0) && (subframe==6)) { + for (int i=0;iframe_parms.N_RB_UL;i++) { + if (i==(eNB->frame_parms.N_RB_UL>>1) - 1) i+=2; + + if (eNB->measurements.n0_subband_power_tot_dB[i]measurements.n0_subband_power_tot_dB[i]; + if (eNB->measurements.n0_subband_power_tot_dB[i]>max_I0) max_I0 = eNB->measurements.n0_subband_power_tot_dB[i]; + } + LOG_I(PHY,"max_I0 %d, min_I0 %d\n",max_I0,min_I0); + } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 0 ); diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index c7cc203da6..a457480c70 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -943,6 +943,7 @@ void init_eNB(int single_thread_flag,int wait_for_sync) { eNB->UL_INFO.harq_ind.harq_pdu_list = eNB->harq_pdu_list; eNB->UL_INFO.cqi_ind.cqi_pdu_list = eNB->cqi_pdu_list; eNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = eNB->cqi_raw_pdu_list; + eNB->prach_energy_counter = 0; } } From 5502026ae1d47fbe8d73c0a04227d9f723087a9a Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 23 Oct 2017 10:31:12 +0200 Subject: [PATCH 060/284] adjust prach detection level just a quick fix before merge, the real solution is to disable pusch scheduling in the prach, to be done later --- openair1/SCHED/phy_procedures_lte_eNb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 05a6dca09b..b3e330f656 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -663,7 +663,7 @@ void prach_procedures(PHY_VARS_eNB *eNB, { if ((eNB->prach_energy_counter == 100) && - (max_preamble_energy[0] > eNB->measurements.prach_I0+100)) { + (max_preamble_energy[0] > eNB->measurements.prach_I0+200)) { LOG_D(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", eNB->Mod_id, From 1b1f941e3c508f94932029c97716127b0a69c284 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 23 Oct 2017 12:22:13 +0200 Subject: [PATCH 061/284] upgrade license to version 1.1 --- LICENSE | 208 +++++++++++++----- cmake_targets/CMakeLists.txt | 2 +- cmake_targets/at_commands/CMakeLists.txt | 2 +- cmake_targets/autotests/core.py | 2 +- cmake_targets/autotests/log.py | 2 +- cmake_targets/autotests/openair.py | 2 +- .../autotests/run_compilation_autotests.bash | 2 +- .../autotests/run_exec_autotests.bash | 2 +- .../autotests/run_exec_lte-softmodem_tests.py | 2 +- .../tools/configure_cots_bandrich_ue.py | 2 +- .../tools/configure_cots_huaweiE398_ue.py | 2 +- .../configure_cots_sony_experia_m4_ue.py | 2 +- .../autotests/tools/configure_usrpb210.py | 2 +- .../autotests/tools/find_usb_path.bash | 2 +- cmake_targets/autotests/tools/free_mem.bash | 2 +- cmake_targets/autotests/tools/git-retry.sh | 2 +- cmake_targets/autotests/tools/iperf3_script | 2 +- .../autotests/tools/iperf3_script_phone | 2 +- cmake_targets/autotests/tools/iperf_script | 2 +- .../autotests/tools/iperf_script_phone | 2 +- cmake_targets/autotests/tools/lib_autotest.py | 2 +- cmake_targets/autotests/tools/run_gdb | 2 +- cmake_targets/autotests/tools/search_repl.py | 2 +- cmake_targets/build_oai | 2 +- cmake_targets/tools/asn1tostruct.py | 2 +- cmake_targets/tools/build_helper | 2 +- cmake_targets/tools/build_test_epc_tools | 2 +- .../tools/example_enb_exmimo_mme_hss.txt | 2 +- .../example_oaisim_enb_ue_mme_virtual.txt | 2 +- cmake_targets/tools/indent_source_code | 2 +- cmake_targets/tools/init_exmimo2 | 2 +- cmake_targets/tools/init_nas_nos1 | 2 +- cmake_targets/tools/init_nas_s1 | 2 +- cmake_targets/tools/perf_oai.bash | 2 +- cmake_targets/tools/run_enb_s1_exmimo | 2 +- cmake_targets/tools/run_enb_s1_usrp | 2 +- cmake_targets/tools/run_enb_ue_virt_noS1 | 2 +- cmake_targets/tools/run_enb_ue_virt_s1 | 2 +- cmake_targets/tools/stop_exmimo2 | 2 +- common/utils/asn1_conversions.h | 2 +- common/utils/assertions.h | 2 +- common/utils/hashtable/hashtable.c | 2 +- common/utils/hashtable/hashtable.h | 2 +- common/utils/hashtable/obj_hashtable.c | 2 +- common/utils/hashtable/obj_hashtable.h | 2 +- common/utils/itti/assertions.h | 2 +- common/utils/itti/backtrace.c | 2 +- common/utils/itti/backtrace.h | 2 +- common/utils/itti/intertask_interface.c | 2 +- common/utils/itti/intertask_interface.h | 2 +- common/utils/itti/intertask_interface_dump.c | 2 +- common/utils/itti/intertask_interface_dump.h | 2 +- common/utils/itti/intertask_interface_init.h | 2 +- common/utils/itti/intertask_interface_types.h | 2 +- common/utils/itti/intertask_messages_def.h | 2 +- common/utils/itti/intertask_messages_types.h | 2 +- common/utils/itti/itti_types.h | 2 +- common/utils/itti/memory_pools.c | 2 +- common/utils/itti/memory_pools.h | 2 +- common/utils/itti/messages_def.h | 2 +- common/utils/itti/messages_types.h | 2 +- common/utils/itti/signals.c | 2 +- common/utils/itti/signals.h | 2 +- common/utils/itti/tasks_def.h | 2 +- common/utils/itti/timer.c | 2 +- common/utils/itti/timer.h | 2 +- common/utils/itti/timer_messages_def.h | 2 +- common/utils/itti/timer_messages_types.h | 2 +- .../utils/itti_analyzer/common/itti_types.h | 2 +- common/utils/itti_analyzer/common/logs.h | 2 +- common/utils/itti_analyzer/common/rc.h | 2 +- common/utils/itti_analyzer/itti_analyzer.c | 2 +- .../utils/itti_analyzer/libbuffers/buffers.c | 2 +- .../utils/itti_analyzer/libbuffers/buffers.h | 2 +- common/utils/itti_analyzer/libbuffers/file.c | 2 +- common/utils/itti_analyzer/libbuffers/file.h | 2 +- .../utils/itti_analyzer/libbuffers/socket.c | 2 +- .../utils/itti_analyzer/libbuffers/socket.h | 2 +- .../itti_analyzer/libparser/array_type.c | 2 +- .../itti_analyzer/libparser/array_type.h | 2 +- .../utils/itti_analyzer/libparser/enum_type.c | 2 +- .../utils/itti_analyzer/libparser/enum_type.h | 2 +- .../itti_analyzer/libparser/enum_value_type.c | 2 +- .../itti_analyzer/libparser/enum_value_type.h | 2 +- .../itti_analyzer/libparser/field_type.c | 2 +- .../itti_analyzer/libparser/field_type.h | 2 +- .../utils/itti_analyzer/libparser/file_type.c | 2 +- .../utils/itti_analyzer/libparser/file_type.h | 2 +- .../libparser/fundamental_type.c | 2 +- .../libparser/fundamental_type.h | 2 +- .../libparser/intertask_contexts.h | 2 +- .../itti_analyzer/libparser/pointer_type.c | 2 +- .../itti_analyzer/libparser/pointer_type.h | 2 +- .../itti_analyzer/libparser/reference_type.c | 2 +- .../itti_analyzer/libparser/reference_type.h | 2 +- .../itti_analyzer/libparser/struct_type.c | 2 +- .../itti_analyzer/libparser/struct_type.h | 2 +- .../itti_analyzer/libparser/typedef_type.c | 2 +- .../itti_analyzer/libparser/typedef_type.h | 2 +- common/utils/itti_analyzer/libparser/types.c | 2 +- common/utils/itti_analyzer/libparser/types.h | 2 +- .../itti_analyzer/libparser/union_type.c | 2 +- .../itti_analyzer/libparser/union_type.h | 2 +- .../utils/itti_analyzer/libparser/xml_parse.c | 2 +- .../utils/itti_analyzer/libparser/xml_parse.h | 2 +- .../itti_analyzer/libresolver/locate_root.c | 2 +- .../itti_analyzer/libresolver/locate_root.h | 2 +- .../itti_analyzer/libresolver/resolvers.c | 2 +- .../itti_analyzer/libresolver/resolvers.h | 2 +- .../utils/itti_analyzer/libui/ui_callbacks.c | 2 +- .../utils/itti_analyzer/libui/ui_callbacks.h | 2 +- common/utils/itti_analyzer/libui/ui_filters.c | 2 +- common/utils/itti_analyzer/libui/ui_filters.h | 2 +- .../utils/itti_analyzer/libui/ui_interface.c | 2 +- .../utils/itti_analyzer/libui/ui_interface.h | 2 +- .../itti_analyzer/libui/ui_main_screen.c | 2 +- .../itti_analyzer/libui/ui_main_screen.h | 2 +- .../utils/itti_analyzer/libui/ui_menu_bar.c | 2 +- .../utils/itti_analyzer/libui/ui_menu_bar.h | 2 +- .../utils/itti_analyzer/libui/ui_notebook.c | 2 +- .../utils/itti_analyzer/libui/ui_notebook.h | 2 +- .../utils/itti_analyzer/libui/ui_notif_dlg.c | 2 +- .../utils/itti_analyzer/libui/ui_notif_dlg.h | 2 +- .../itti_analyzer/libui/ui_notifications.c | 2 +- .../itti_analyzer/libui/ui_notifications.h | 2 +- .../libui/ui_signal_dissect_view.c | 2 +- .../libui/ui_signal_dissect_view.h | 2 +- .../utils/itti_analyzer/libui/ui_tree_view.c | 2 +- .../utils/itti_analyzer/libui/ui_tree_view.h | 2 +- common/utils/msc/msc.c | 2 +- common/utils/msc/msc.h | 2 +- common/utils/system.c | 2 +- common/utils/system.h | 2 +- openair1/PHY/CODING/3gpplte.c | 2 +- openair1/PHY/CODING/3gpplte_sse.c | 2 +- openair1/PHY/CODING/3gpplte_turbo_decoder.c | 2 +- .../CODING/3gpplte_turbo_decoder_avx2_16bit.c | 2 +- .../PHY/CODING/3gpplte_turbo_decoder_sse.c | 2 +- .../CODING/3gpplte_turbo_decoder_sse_16bit.c | 2 +- .../CODING/3gpplte_turbo_decoder_sse_8bit.c | 2 +- openair1/PHY/CODING/TESTBENCH/ltetest.c | 2 +- openair1/PHY/CODING/TESTBENCH/pdcch_test.c | 2 +- openair1/PHY/CODING/TESTBENCH/viterbi_test.c | 2 +- openair1/PHY/CODING/ccoding_byte.c | 2 +- openair1/PHY/CODING/ccoding_byte_lte.c | 2 +- openair1/PHY/CODING/crc_byte.c | 2 +- openair1/PHY/CODING/defs.h | 2 +- openair1/PHY/CODING/extern.h | 2 +- openair1/PHY/CODING/extern_3GPPinterleaver.h | 2 +- openair1/PHY/CODING/lte_interleaver.h | 2 +- openair1/PHY/CODING/lte_interleaver2.h | 2 +- openair1/PHY/CODING/lte_interleaver_inline.h | 2 +- openair1/PHY/CODING/lte_rate_matching.c | 2 +- openair1/PHY/CODING/lte_segmentation.c | 2 +- openair1/PHY/CODING/rate_matching.c | 2 +- openair1/PHY/CODING/scrambler.h | 2 +- openair1/PHY/CODING/vars.h | 2 +- openair1/PHY/CODING/viterbi.c | 2 +- openair1/PHY/CODING/viterbi_lte.c | 2 +- openair1/PHY/INIT/defs.h | 2 +- openair1/PHY/INIT/extern.h | 2 +- openair1/PHY/INIT/init_top.c | 2 +- openair1/PHY/INIT/lte_init.c | 2 +- openair1/PHY/INIT/lte_param_init.c | 2 +- openair1/PHY/INIT/lte_parms.c | 2 +- openair1/PHY/INIT/vars.h | 2 +- openair1/PHY/LTE_ESTIMATION/adjust_gain.c | 2 +- openair1/PHY/LTE_ESTIMATION/defs.h | 2 +- openair1/PHY/LTE_ESTIMATION/extern.h | 2 +- openair1/PHY/LTE_ESTIMATION/filt96_32.h | 2 +- .../PHY/LTE_ESTIMATION/freq_equalization.c | 2 +- openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c | 2 +- .../lte_dl_bf_channel_estimation.c | 2 +- .../lte_dl_channel_estimation.c | 2 +- .../lte_dl_channel_estimation_emos.c | 2 +- .../lte_dl_mbsfn_channel_estimation.c | 2 +- .../PHY/LTE_ESTIMATION/lte_eNB_measurements.c | 2 +- .../PHY/LTE_ESTIMATION/lte_est_freq_offset.c | 2 +- openair1/PHY/LTE_ESTIMATION/lte_sync_time.c | 2 +- .../PHY/LTE_ESTIMATION/lte_sync_timefreq.c | 2 +- .../PHY/LTE_ESTIMATION/lte_ue_measurements.c | 2 +- .../lte_ul_channel_estimation.c | 2 +- openair1/PHY/LTE_ESTIMATION/pss6144.h | 2 +- openair1/PHY/LTE_ESTIMATION/vars.h | 2 +- openair1/PHY/LTE_REFSIG/defs.h | 2 +- openair1/PHY/LTE_REFSIG/lte_dl_cell_spec.c | 2 +- openair1/PHY/LTE_REFSIG/lte_dl_mbsfn.c | 2 +- openair1/PHY/LTE_REFSIG/lte_dl_uespec.c | 2 +- openair1/PHY/LTE_REFSIG/lte_gold.c | 2 +- openair1/PHY/LTE_REFSIG/lte_gold_mbsfn.c | 2 +- openair1/PHY/LTE_REFSIG/lte_ul_ref.c | 2 +- openair1/PHY/LTE_REFSIG/mod_table.h | 2 +- openair1/PHY/LTE_REFSIG/primary_synch.h | 2 +- openair1/PHY/LTE_TRANSPORT/dci.c | 2 +- openair1/PHY/LTE_TRANSPORT/dci.h | 2 +- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 2 +- openair1/PHY/LTE_TRANSPORT/defs.h | 2 +- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 2 +- openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c | 2 +- .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 2 +- .../PHY/LTE_TRANSPORT/dlsch_llr_computation.c | 2 +- .../dlsch_llr_computation_avx2.c | 2 +- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 2 +- openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c | 2 +- openair1/PHY/LTE_TRANSPORT/dlsch_tbs.h | 2 +- openair1/PHY/LTE_TRANSPORT/dlsch_tbs_full.h | 2 +- openair1/PHY/LTE_TRANSPORT/drs_modulation.c | 2 +- openair1/PHY/LTE_TRANSPORT/extern.h | 2 +- openair1/PHY/LTE_TRANSPORT/group_hopping.c | 2 +- openair1/PHY/LTE_TRANSPORT/if4_tools.c | 2 +- openair1/PHY/LTE_TRANSPORT/if4_tools.h | 2 +- openair1/PHY/LTE_TRANSPORT/if5_tools.c | 2 +- openair1/PHY/LTE_TRANSPORT/if5_tools.h | 2 +- openair1/PHY/LTE_TRANSPORT/initial_sync.c | 2 +- openair1/PHY/LTE_TRANSPORT/lte_mcs.c | 2 +- openair1/PHY/LTE_TRANSPORT/mcs_tbs_tools.h | 2 +- openair1/PHY/LTE_TRANSPORT/pbch.c | 2 +- openair1/PHY/LTE_TRANSPORT/pcfich.c | 2 +- openair1/PHY/LTE_TRANSPORT/pch.c | 2 +- openair1/PHY/LTE_TRANSPORT/phich.c | 2 +- openair1/PHY/LTE_TRANSPORT/pilots.c | 2 +- openair1/PHY/LTE_TRANSPORT/pilots_mbsfn.c | 2 +- openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c | 2 +- openair1/PHY/LTE_TRANSPORT/pmch.c | 2 +- openair1/PHY/LTE_TRANSPORT/power_control.c | 2 +- openair1/PHY/LTE_TRANSPORT/prach.c | 2 +- openair1/PHY/LTE_TRANSPORT/prach.h | 2 +- openair1/PHY/LTE_TRANSPORT/print_stats.c | 2 +- openair1/PHY/LTE_TRANSPORT/proto.h | 2 +- openair1/PHY/LTE_TRANSPORT/pss.c | 2 +- openair1/PHY/LTE_TRANSPORT/pucch.c | 2 +- openair1/PHY/LTE_TRANSPORT/rar_tools.c | 2 +- openair1/PHY/LTE_TRANSPORT/srs_modulation.c | 2 +- openair1/PHY/LTE_TRANSPORT/sss.c | 2 +- openair1/PHY/LTE_TRANSPORT/sss.h | 2 +- openair1/PHY/LTE_TRANSPORT/uci.h | 2 +- openair1/PHY/LTE_TRANSPORT/uci_tools.c | 2 +- openair1/PHY/LTE_TRANSPORT/ulsch_coding.c | 2 +- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 2 +- .../PHY/LTE_TRANSPORT/ulsch_demodulation.c | 2 +- openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c | 2 +- openair1/PHY/LTE_TRANSPORT/vars.h | 2 +- openair1/PHY/MODULATION/beamforming.c | 2 +- openair1/PHY/MODULATION/defs.h | 2 +- openair1/PHY/MODULATION/extern.h | 2 +- openair1/PHY/MODULATION/kHz_7_5.h | 2 +- openair1/PHY/MODULATION/ofdm_mod.c | 2 +- openair1/PHY/MODULATION/prach625Hz.h | 2 +- openair1/PHY/MODULATION/slot_fep.c | 2 +- openair1/PHY/MODULATION/slot_fep_mbsfn.c | 2 +- openair1/PHY/MODULATION/slot_fep_ul.c | 2 +- openair1/PHY/MODULATION/ul_7_5_kHz.c | 2 +- openair1/PHY/MODULATION/vars.h | 2 +- openair1/PHY/TOOLS/8bit_rxdemux.c | 2 +- openair1/PHY/TOOLS/8bit_txmux.c | 2 +- openair1/PHY/TOOLS/alaw_lut.h | 2 +- openair1/PHY/TOOLS/angle.c | 2 +- openair1/PHY/TOOLS/cadd_sv.c | 2 +- openair1/PHY/TOOLS/cadd_vv.c | 2 +- openair1/PHY/TOOLS/cdot_prod.c | 2 +- openair1/PHY/TOOLS/cmult_sv.c | 2 +- openair1/PHY/TOOLS/cmult_vv.c | 2 +- openair1/PHY/TOOLS/costable.h | 2 +- openair1/PHY/TOOLS/dB_routines.c | 2 +- openair1/PHY/TOOLS/dB_routines.h | 2 +- openair1/PHY/TOOLS/defs.h | 2 +- openair1/PHY/TOOLS/extern.h | 2 +- openair1/PHY/TOOLS/file_output.c | 2 +- openair1/PHY/TOOLS/invSqrt.c | 2 +- openair1/PHY/TOOLS/log2_approx.c | 2 +- openair1/PHY/TOOLS/lte_dfts.c | 2 +- openair1/PHY/TOOLS/lte_phy_scope.c | 2 +- openair1/PHY/TOOLS/lte_phy_scope.h | 2 +- openair1/PHY/TOOLS/lte_phy_scope_tm4.c | 2 +- openair1/PHY/TOOLS/lut.c | 2 +- openair1/PHY/TOOLS/memory_routines.c | 2 +- openair1/PHY/TOOLS/signal_energy.c | 2 +- openair1/PHY/TOOLS/smbv.c | 2 +- openair1/PHY/TOOLS/smbv.h | 2 +- openair1/PHY/TOOLS/sqrt.c | 2 +- openair1/PHY/TOOLS/time_meas.c | 2 +- openair1/PHY/TOOLS/time_meas.h | 2 +- openair1/PHY/TOOLS/twiddle12288.h | 2 +- openair1/PHY/TOOLS/twiddle1536.h | 2 +- openair1/PHY/TOOLS/twiddle18432.h | 2 +- openair1/PHY/TOOLS/twiddle24576.h | 2 +- openair1/PHY/TOOLS/twiddle6144.h | 2 +- openair1/PHY/TOOLS/twiddles4096.h | 2 +- openair1/PHY/TOOLS/twiddles8192.h | 2 +- openair1/PHY/TOOLS/vars.h | 2 +- openair1/PHY/defs.h | 2 +- openair1/PHY/extern.h | 2 +- openair1/PHY/impl_defs_lte.h | 2 +- openair1/PHY/impl_defs_top.h | 2 +- openair1/PHY/sse_intrin.h | 2 +- openair1/PHY/types.h | 2 +- openair1/PHY/vars.h | 2 +- openair1/SCHED/defs.h | 2 +- openair1/SCHED/extern.h | 2 +- openair1/SCHED/phy_mac_stub.c | 2 +- openair1/SCHED/phy_procedures_emos.h | 2 +- openair1/SCHED/phy_procedures_lte_common.c | 2 +- openair1/SCHED/phy_procedures_lte_eNb.c | 2 +- openair1/SCHED/phy_procedures_lte_ue.c | 2 +- openair1/SCHED/pucch_pc.c | 2 +- openair1/SCHED/pusch_pc.c | 2 +- openair1/SCHED/rt_compat.h | 2 +- openair1/SCHED/srs_pc.c | 2 +- openair1/SCHED/vars.h | 2 +- .../ETH_TRANSPORT/bypass_session_layer.c | 2 +- openair1/SIMULATION/ETH_TRANSPORT/defs.h | 2 +- .../SIMULATION/ETH_TRANSPORT/emu_transport.c | 2 +- openair1/SIMULATION/ETH_TRANSPORT/extern.h | 2 +- .../SIMULATION/ETH_TRANSPORT/multicast_link.c | 2 +- .../SIMULATION/ETH_TRANSPORT/multicast_link.h | 2 +- .../SIMULATION/ETH_TRANSPORT/netlink_init.c | 2 +- openair1/SIMULATION/ETH_TRANSPORT/pgm_link.c | 2 +- openair1/SIMULATION/ETH_TRANSPORT/pgm_link.h | 2 +- openair1/SIMULATION/ETH_TRANSPORT/proto.h | 2 +- openair1/SIMULATION/ETH_TRANSPORT/socket.c | 2 +- openair1/SIMULATION/ETH_TRANSPORT/socket.h | 2 +- openair1/SIMULATION/ETH_TRANSPORT/vars.h | 2 +- .../SIMULATION/LTE_PHY/LTE_Configuration.c | 2 +- .../SIMULATION/LTE_PHY/LTE_Configuration.h | 2 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 2 +- openair1/SIMULATION/LTE_PHY/dlsim_tm4.c | 2 +- openair1/SIMULATION/LTE_PHY/dlsim_tm7.c | 2 +- openair1/SIMULATION/LTE_PHY/framegen.c | 2 +- openair1/SIMULATION/LTE_PHY/gpib_send.c | 2 +- openair1/SIMULATION/LTE_PHY/gpib_send.h | 2 +- openair1/SIMULATION/LTE_PHY/mbmssim.c | 2 +- openair1/SIMULATION/LTE_PHY/pbchsim.c | 2 +- openair1/SIMULATION/LTE_PHY/pdcchsim.c | 2 +- openair1/SIMULATION/LTE_PHY/prachsim.c | 2 +- .../SIMULATION/LTE_PHY/pucchsignalgegerator.h | 2 +- .../SIMULATION/LTE_PHY/pucchsignalgenerator.c | 2 +- openair1/SIMULATION/LTE_PHY/pucchsim.c | 2 +- openair1/SIMULATION/LTE_PHY/scansim.c | 2 +- openair1/SIMULATION/LTE_PHY/signalanalyzer.c | 2 +- openair1/SIMULATION/LTE_PHY/signalanalyzer.h | 2 +- openair1/SIMULATION/LTE_PHY/syncsim.c | 2 +- openair1/SIMULATION/LTE_PHY/test.c | 2 +- .../SIMULATION/LTE_PHY/ulsignalgenerator.c | 2 +- .../SIMULATION/LTE_PHY/ulsignalgenerator.h | 2 +- openair1/SIMULATION/LTE_PHY/ulsim.c | 2 +- openair1/SIMULATION/LTE_PHY/ulsim2.c | 2 +- openair1/SIMULATION/LTE_PHY/unitary_defs.h | 2 +- openair1/SIMULATION/RF/adc.c | 2 +- openair1/SIMULATION/RF/dac.c | 2 +- openair1/SIMULATION/RF/defs.h | 2 +- openair1/SIMULATION/RF/rf.c | 2 +- openair1/SIMULATION/TOOLS/abstraction.c | 2 +- openair1/SIMULATION/TOOLS/ch_desc_proto.c | 2 +- openair1/SIMULATION/TOOLS/defs.h | 2 +- openair1/SIMULATION/TOOLS/gauss.c | 2 +- openair1/SIMULATION/TOOLS/llr_quantization.c | 2 +- openair1/SIMULATION/TOOLS/multipath_channel.c | 2 +- .../SIMULATION/TOOLS/multipath_tv_channel.c | 2 +- openair1/SIMULATION/TOOLS/random_channel.c | 2 +- openair1/SIMULATION/TOOLS/rangen_double.c | 2 +- openair1/SIMULATION/TOOLS/scm_corrmat.h | 2 +- openair1/SIMULATION/TOOLS/taus.c | 2 +- openair2/COMMON/as_message.h | 2 +- openair2/COMMON/commonDef.h | 2 +- openair2/COMMON/gtpv1_u_messages_def.h | 2 +- openair2/COMMON/gtpv1_u_messages_types.h | 2 +- openair2/COMMON/intertask_interface_conf.h | 2 +- openair2/COMMON/mac_messages_def.h | 2 +- openair2/COMMON/mac_messages_types.h | 2 +- openair2/COMMON/mac_primitives.h | 2 +- openair2/COMMON/mac_rlc_primitives.h | 2 +- openair2/COMMON/mac_rrc_primitives.h | 2 +- openair2/COMMON/messages_def.h | 2 +- openair2/COMMON/messages_types.h | 2 +- openair2/COMMON/nas_messages_def.h | 2 +- openair2/COMMON/nas_messages_types.h | 2 +- openair2/COMMON/networkDef.h | 2 +- openair2/COMMON/openair_defs.h | 2 +- openair2/COMMON/openair_types.h | 2 +- openair2/COMMON/pdcp_messages_def.h | 2 +- openair2/COMMON/pdcp_messages_types.h | 2 +- openair2/COMMON/phy_messages_def.h | 2 +- openair2/COMMON/phy_messages_types.h | 2 +- openair2/COMMON/platform_constants.h | 2 +- openair2/COMMON/platform_types.h | 2 +- openair2/COMMON/ral_messages_def.h | 2 +- openair2/COMMON/ral_messages_types.h | 2 +- openair2/COMMON/rlc_messages_def.h | 2 +- openair2/COMMON/rlc_messages_types.h | 2 +- openair2/COMMON/rrc_messages_def.h | 2 +- openair2/COMMON/rrc_messages_types.h | 2 +- openair2/COMMON/rrm_config_structs.h | 2 +- openair2/COMMON/rrm_constants.h | 2 +- openair2/COMMON/rtos_header.h | 2 +- openair2/COMMON/s1ap_messages_def.h | 2 +- openair2/COMMON/s1ap_messages_types.h | 2 +- openair2/COMMON/sctp_messages_def.h | 2 +- openair2/COMMON/sctp_messages_types.h | 2 +- openair2/COMMON/tasks_def.h | 2 +- openair2/COMMON/udp_messages_def.h | 2 +- openair2/COMMON/udp_messages_types.h | 2 +- openair2/COMMON/x2ap_messages_def.h | 2 +- openair2/COMMON/x2ap_messages_types.h | 2 +- openair2/DOCS/TEMPLATES/CODE/example_doxy.h | 2 +- openair2/DOCS/TEMPLATES/README/Readme.doxy | 2 +- openair2/DOCS/TEMPLATES/README/readme.txt | 2 +- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 2 +- .../CONTROL_MODULES/MAC/flexran_agent_mac.h | 2 +- .../MAC/flexran_agent_mac_defs.h | 2 +- .../MAC/flexran_agent_mac_internal.c | 2 +- .../MAC/flexran_agent_mac_internal.h | 2 +- openair2/ENB_APP/enb_app.c | 2 +- openair2/ENB_APP/enb_app.h | 2 +- openair2/ENB_APP/enb_config.c | 2 +- openair2/ENB_APP/enb_config.h | 2 +- openair2/ENB_APP/flexran_agent.c | 2 +- openair2/ENB_APP/flexran_agent.h | 2 +- openair2/ENB_APP/flexran_agent_async.c | 2 +- openair2/ENB_APP/flexran_agent_async.h | 2 +- openair2/ENB_APP/flexran_agent_common.c | 2 +- openair2/ENB_APP/flexran_agent_common.h | 2 +- .../ENB_APP/flexran_agent_common_internal.c | 2 +- .../ENB_APP/flexran_agent_common_internal.h | 2 +- openair2/ENB_APP/flexran_agent_defs.h | 2 +- openair2/ENB_APP/flexran_agent_extern.h | 2 +- openair2/ENB_APP/flexran_agent_handler.c | 2 +- openair2/ENB_APP/flexran_agent_net_comm.c | 2 +- openair2/ENB_APP/flexran_agent_net_comm.h | 2 +- openair2/ENB_APP/flexran_agent_task_manager.c | 2 +- openair2/ENB_APP/flexran_agent_task_manager.h | 2 +- openair2/LAYER2/MAC/config.c | 2 +- openair2/LAYER2/MAC/defs.h | 2 +- openair2/LAYER2/MAC/eNB_scheduler.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_RA.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_bch.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_mch.c | 2 +- .../LAYER2/MAC/eNB_scheduler_primitives.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 2 +- openair2/LAYER2/MAC/extern.h | 2 +- openair2/LAYER2/MAC/flexran_agent_mac_proto.h | 2 +- .../MAC/flexran_agent_scheduler_dataplane.c | 2 +- .../MAC/flexran_agent_scheduler_dlsch_ue.c | 2 +- .../flexran_agent_scheduler_dlsch_ue_remote.c | 2 +- .../flexran_agent_scheduler_dlsch_ue_remote.h | 2 +- openair2/LAYER2/MAC/flexran_dci_conversions.h | 2 +- openair2/LAYER2/MAC/l1_helpers.c | 2 +- openair2/LAYER2/MAC/lte_transport_init.c | 2 +- openair2/LAYER2/MAC/main.c | 2 +- openair2/LAYER2/MAC/openair2_proc.c | 2 +- openair2/LAYER2/MAC/pre_processor.c | 2 +- openair2/LAYER2/MAC/proto.h | 2 +- openair2/LAYER2/MAC/ra_procedures.c | 2 +- openair2/LAYER2/MAC/rar_tools.c | 2 +- openair2/LAYER2/MAC/ue_procedures.c | 2 +- openair2/LAYER2/MAC/vars.h | 2 +- openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 2 +- openair2/LAYER2/PDCP_v10.1.0/pdcp.h | 2 +- .../PDCP_v10.1.0/pdcp_control_primitive.c | 2 +- .../pdcp_control_primitives_proto_extern.h | 2 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 2 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c | 2 +- .../LAYER2/PDCP_v10.1.0/pdcp_primitives.c | 2 +- .../LAYER2/PDCP_v10.1.0/pdcp_primitives.h | 2 +- .../LAYER2/PDCP_v10.1.0/pdcp_proto_extern.h | 2 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c | 2 +- .../PDCP_v10.1.0/pdcp_sequence_manager.c | 2 +- .../PDCP_v10.1.0/pdcp_sequence_manager.h | 2 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_thread.c | 2 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_util.c | 2 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_util.h | 2 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 2 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h | 2 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h | 2 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c | 2 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.h | 2 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c | 2 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h | 2 +- .../RLC/AM_v9.3.0/rlc_am_proto_extern.h | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.h | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h | 2 +- .../RLC/AM_v9.3.0/rlc_am_segments_holes.c | 2 +- .../RLC/AM_v9.3.0/rlc_am_segments_holes.h | 2 +- .../RLC/AM_v9.3.0/rlc_am_status_report.c | 2 +- .../RLC/AM_v9.3.0/rlc_am_status_report.h | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h | 2 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c | 2 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.h | 2 +- .../AM_v9.3.0/rlc_am_timer_poll_retransmit.c | 2 +- .../AM_v9.3.0/rlc_am_timer_poll_retransmit.h | 2 +- .../RLC/AM_v9.3.0/rlc_am_timer_reordering.c | 2 +- .../RLC/AM_v9.3.0/rlc_am_timer_reordering.h | 2 +- .../AM_v9.3.0/rlc_am_timer_status_prohibit.c | 2 +- .../AM_v9.3.0/rlc_am_timer_status_prohibit.h | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_windows.c | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_windows.h | 2 +- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.c | 2 +- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.h | 2 +- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_entity.h | 2 +- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c | 2 +- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h | 2 +- .../LAYER2/RLC/TM_v9.3.0/rlc_tm_structs.h | 2 +- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c | 2 +- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h | 2 +- .../LAYER2/RLC/UM_v9.3.0/rlc_um_constants.h | 2 +- .../RLC/UM_v9.3.0/rlc_um_control_primitives.c | 2 +- .../RLC/UM_v9.3.0/rlc_um_control_primitives.h | 2 +- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_dar.c | 2 +- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_dar.h | 2 +- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_entity.h | 2 +- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_fsm.c | 2 +- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_fsm.h | 2 +- .../LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.c | 2 +- .../LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.h | 2 +- .../LAYER2/RLC/UM_v9.3.0/rlc_um_receiver.c | 2 +- .../LAYER2/RLC/UM_v9.3.0/rlc_um_receiver.h | 2 +- .../LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c | 2 +- .../LAYER2/RLC/UM_v9.3.0/rlc_um_segment.h | 2 +- .../LAYER2/RLC/UM_v9.3.0/rlc_um_structs.h | 2 +- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c | 2 +- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.h | 2 +- .../RLC/UM_v9.3.0/rlc_um_very_simple_test.c | 2 +- .../RLC/UM_v9.3.0/rlc_um_very_simple_test.h | 2 +- openair2/LAYER2/RLC/mac_primitives.h | 2 +- openair2/LAYER2/RLC/rlc.c | 2 +- openair2/LAYER2/RLC/rlc.h | 2 +- openair2/LAYER2/RLC/rlc_def.h | 2 +- openair2/LAYER2/RLC/rlc_def_lte.h | 2 +- openair2/LAYER2/RLC/rlc_mac.c | 2 +- openair2/LAYER2/RLC/rlc_mpls.c | 2 +- openair2/LAYER2/RLC/rlc_primitives.h | 2 +- openair2/LAYER2/RLC/rlc_rrc.c | 2 +- openair2/LAYER2/layer2_top.c | 2 +- openair2/LAYER2/openair2_proc.c | 2 +- openair2/LAYER2/register.c | 2 +- openair2/LAYER2/register.h | 2 +- openair2/Makefile | 2 +- .../DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.c | 2 +- .../DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.h | 2 +- .../DRIVER/CELLULAR/NASMT/nasmt_ascontrol.c | 2 +- .../DRIVER/CELLULAR/NASMT/nasmt_classifier.c | 2 +- .../NAS/DRIVER/CELLULAR/NASMT/nasmt_common.c | 2 +- .../DRIVER/CELLULAR/NASMT/nasmt_constant.h | 2 +- .../NAS/DRIVER/CELLULAR/NASMT/nasmt_device.c | 2 +- .../DRIVER/CELLULAR/NASMT/nasmt_iocontrol.c | 2 +- .../DRIVER/CELLULAR/NASMT/nasmt_iocontrol.h | 2 +- .../NAS/DRIVER/CELLULAR/NASMT/nasmt_netlink.c | 2 +- .../NAS/DRIVER/CELLULAR/NASMT/nasmt_proto.h | 2 +- .../NAS/DRIVER/CELLULAR/NASMT/nasmt_sap.h | 2 +- .../NAS/DRIVER/CELLULAR/NASMT/nasmt_tool.c | 2 +- .../DRIVER/CELLULAR/NASMT/nasmt_variables.h | 2 +- .../DRIVER/CELLULAR/NASRG/nasrg_ascontrol.c | 2 +- .../DRIVER/CELLULAR/NASRG/nasrg_classifier.c | 2 +- .../NAS/DRIVER/CELLULAR/NASRG/nasrg_common.c | 2 +- .../DRIVER/CELLULAR/NASRG/nasrg_constant.h | 2 +- .../NAS/DRIVER/CELLULAR/NASRG/nasrg_device.c | 2 +- .../DRIVER/CELLULAR/NASRG/nasrg_iocontrol.c | 2 +- .../DRIVER/CELLULAR/NASRG/nasrg_iocontrol.h | 2 +- .../NAS/DRIVER/CELLULAR/NASRG/nasrg_netlink.c | 2 +- .../NAS/DRIVER/CELLULAR/NASRG/nasrg_proto.h | 2 +- .../NAS/DRIVER/CELLULAR/NASRG/nasrg_sap.h | 2 +- .../NAS/DRIVER/CELLULAR/NASRG/nasrg_tool.c | 2 +- .../DRIVER/CELLULAR/NASRG/nasrg_variables.h | 2 +- .../NAS/DRIVER/CELLULAR/NETLTEST/netltest.c | 2 +- .../DRIVER/CELLULAR/NETLTEST/nettestPDCP.c | 2 +- openair2/NAS/SIMU_CELLULAR/nas_simu_proto.h | 2 +- openair2/NAS/SIMU_CELLULAR/nasrg_simu_meas.c | 2 +- .../NAS/SIMU_CELLULAR/rrm_fifo_standalone.c | 2 +- .../NETWORK_DRIVER/LITE/RB_TOOL/rb_tool.c | 2 +- openair2/NETWORK_DRIVER/LITE/classifier.c | 2 +- openair2/NETWORK_DRIVER/LITE/common.c | 2 +- openair2/NETWORK_DRIVER/LITE/constant.h | 2 +- openair2/NETWORK_DRIVER/LITE/device.c | 2 +- openair2/NETWORK_DRIVER/LITE/ioctl.c | 2 +- openair2/NETWORK_DRIVER/LITE/ioctl.h | 2 +- openair2/NETWORK_DRIVER/LITE/local.h | 2 +- openair2/NETWORK_DRIVER/LITE/netlink.c | 2 +- openair2/NETWORK_DRIVER/LITE/proto_extern.h | 2 +- openair2/NETWORK_DRIVER/LITE/sap.h | 2 +- openair2/NETWORK_DRIVER/LITE/tool.c | 2 +- .../NETWORK_DRIVER/MESH/RB_TOOL/rb_tool.c | 2 +- .../NETWORK_DRIVER/MESH/TESTBENCH/testbench.c | 2 +- openair2/NETWORK_DRIVER/MESH/classifier.c | 2 +- openair2/NETWORK_DRIVER/MESH/common.c | 2 +- openair2/NETWORK_DRIVER/MESH/constant.h | 2 +- openair2/NETWORK_DRIVER/MESH/device.c | 2 +- openair2/NETWORK_DRIVER/MESH/ioctl.c | 2 +- openair2/NETWORK_DRIVER/MESH/ioctl.h | 2 +- openair2/NETWORK_DRIVER/MESH/local.h | 2 +- openair2/NETWORK_DRIVER/MESH/mesh.c | 2 +- openair2/NETWORK_DRIVER/MESH/netlink.c | 2 +- openair2/NETWORK_DRIVER/MESH/proto_extern.h | 2 +- .../NETWORK_DRIVER/MESH/rrc_nas_primitives.h | 2 +- openair2/NETWORK_DRIVER/MESH/sap.h | 2 +- openair2/NETWORK_DRIVER/MESH/tool.c | 2 +- openair2/NETWORK_DRIVER/UE_IP/common.c | 2 +- openair2/NETWORK_DRIVER/UE_IP/constant.h | 2 +- openair2/NETWORK_DRIVER/UE_IP/device.c | 2 +- openair2/NETWORK_DRIVER/UE_IP/local.h | 2 +- openair2/NETWORK_DRIVER/UE_IP/netlink.c | 2 +- openair2/NETWORK_DRIVER/UE_IP/proto_extern.h | 2 +- openair2/NETWORK_DRIVER/UE_IP/sap.h | 2 +- openair2/PHY_INTERFACE/defs.h | 2 +- openair2/PHY_INTERFACE/extern.h | 2 +- openair2/PHY_INTERFACE/mac_phy_primitives.c | 2 +- openair2/PHY_INTERFACE/mac_phy_primitives.h | 2 +- openair2/PHY_INTERFACE/vars.h | 2 +- .../L2_INTERFACE/openair_rrc_L2_interface.c | 2 +- .../L2_INTERFACE/openair_rrc_L2_interface.h | 2 +- openair2/RRC/LITE/L2_interface.c | 2 +- openair2/RRC/LITE/MESSAGES/asn1_msg.c | 2 +- openair2/RRC/LITE/MESSAGES/asn1_msg.h | 2 +- openair2/RRC/LITE/MESSAGES/rtai_mem.c | 2 +- openair2/RRC/LITE/MESSAGES/rtai_mem.h | 2 +- openair2/RRC/LITE/defs.h | 2 +- openair2/RRC/LITE/extern.h | 2 +- openair2/RRC/LITE/mesh_top.c | 2 +- openair2/RRC/LITE/plmn_data.h | 2 +- openair2/RRC/LITE/proto.h | 2 +- openair2/RRC/LITE/rrc_2_rrm_msg.c | 2 +- openair2/RRC/LITE/rrc_UE.c | 2 +- openair2/RRC/LITE/rrc_UE_ral.c | 2 +- openair2/RRC/LITE/rrc_UE_ral.h | 2 +- openair2/RRC/LITE/rrc_common.c | 2 +- openair2/RRC/LITE/rrc_config.c | 2 +- openair2/RRC/LITE/rrc_eNB.c | 2 +- openair2/RRC/LITE/rrc_eNB_GTPV1U.c | 2 +- openair2/RRC/LITE/rrc_eNB_GTPV1U.h | 2 +- openair2/RRC/LITE/rrc_eNB_S1AP.c | 2 +- openair2/RRC/LITE/rrc_eNB_S1AP.h | 2 +- openair2/RRC/LITE/rrc_eNB_UE_context.c | 2 +- openair2/RRC/LITE/rrc_eNB_UE_context.h | 2 +- openair2/RRC/LITE/rrc_eNB_ral.c | 2 +- openair2/RRC/LITE/rrc_eNB_ral.h | 2 +- openair2/RRC/LITE/rrc_rrm_interface.c | 2 +- openair2/RRC/LITE/rrc_rrm_interface.h | 2 +- openair2/RRC/LITE/rrc_types.h | 2 +- openair2/RRC/LITE/rrm_2_rrc_msg.c | 2 +- openair2/RRC/LITE/utils.c | 2 +- openair2/RRC/LITE/vars.h | 2 +- openair2/RRC/NAS/nas_config.c | 2 +- openair2/RRC/NAS/nas_config.h | 2 +- openair2/RRC/NAS/rb_config.c | 2 +- openair2/RRC/NAS/rb_config.h | 2 +- openair2/UTIL/ASYNC_IF/link_manager.c | 2 +- openair2/UTIL/ASYNC_IF/link_manager.h | 2 +- openair2/UTIL/ASYNC_IF/message_queue.c | 2 +- openair2/UTIL/ASYNC_IF/message_queue.h | 2 +- openair2/UTIL/ASYNC_IF/ringbuffer_queue.c | 2 +- openair2/UTIL/ASYNC_IF/ringbuffer_queue.h | 2 +- openair2/UTIL/ASYNC_IF/socket_link.c | 2 +- openair2/UTIL/ASYNC_IF/socket_link.h | 2 +- openair2/UTIL/BIGPHYS/bigphys.c | 2 +- openair2/UTIL/BIGPHYS/defs.h | 2 +- openair2/UTIL/CLI/cli.c | 2 +- openair2/UTIL/CLI/cli.h | 2 +- openair2/UTIL/CLI/cli_cmd.c | 2 +- openair2/UTIL/CLI/cli_if.h | 2 +- openair2/UTIL/CLI/cli_server.c | 2 +- openair2/UTIL/FIFO/pad_list.c | 2 +- openair2/UTIL/FIFO/pad_list.h | 2 +- openair2/UTIL/FIFO/types.h | 2 +- openair2/UTIL/LISTS/list.c | 2 +- openair2/UTIL/LISTS/list.h | 2 +- openair2/UTIL/LISTS/list2.c | 2 +- openair2/UTIL/LOG/log.c | 2 +- openair2/UTIL/LOG/log.h | 2 +- openair2/UTIL/LOG/log_extern.h | 2 +- openair2/UTIL/LOG/log_if.h | 2 +- openair2/UTIL/LOG/vcd_signal_dumper.c | 2 +- openair2/UTIL/LOG/vcd_signal_dumper.h | 2 +- openair2/UTIL/MATH/crc_byte.c | 2 +- openair2/UTIL/MATH/oml.c | 2 +- openair2/UTIL/MATH/oml.h | 2 +- openair2/UTIL/MATH/random.c | 2 +- openair2/UTIL/MATH/random_proto_extern.h | 2 +- openair2/UTIL/MATH/taus.c | 2 +- openair2/UTIL/MEM/mem_block.c | 2 +- openair2/UTIL/MEM/mem_block.h | 2 +- openair2/UTIL/MEM/mem_mngt.c | 2 +- openair2/UTIL/MEM/mem_mngt_proto_extern.h | 2 +- openair2/UTIL/MEM/mem_pool.h | 2 +- openair2/UTIL/OCG/OCG.c | 2 +- openair2/UTIL/OCG/OCG.h | 2 +- openair2/UTIL/OCG/OCG_call_emu.c | 2 +- openair2/UTIL/OCG/OCG_call_emu.h | 2 +- openair2/UTIL/OCG/OCG_config_mobi.c | 2 +- openair2/UTIL/OCG/OCG_config_mobi.h | 2 +- openair2/UTIL/OCG/OCG_create_dir.c | 2 +- openair2/UTIL/OCG/OCG_create_dir.h | 2 +- openair2/UTIL/OCG/OCG_detect_file.c | 2 +- openair2/UTIL/OCG/OCG_detect_file.h | 2 +- openair2/UTIL/OCG/OCG_extern.h | 2 +- openair2/UTIL/OCG/OCG_generate_report.c | 2 +- openair2/UTIL/OCG/OCG_generate_report.h | 2 +- openair2/UTIL/OCG/OCG_get_opt.c | 2 +- openair2/UTIL/OCG/OCG_get_opt.h | 2 +- openair2/UTIL/OCG/OCG_if.h | 2 +- openair2/UTIL/OCG/OCG_parse_XML.c | 2 +- openair2/UTIL/OCG/OCG_parse_XML.h | 2 +- openair2/UTIL/OCG/OCG_parse_filename.c | 2 +- openair2/UTIL/OCG/OCG_parse_filename.h | 2 +- openair2/UTIL/OCG/OCG_save_XML.c | 2 +- openair2/UTIL/OCG/OCG_save_XML.h | 2 +- openair2/UTIL/OCG/OCG_vars.h | 2 +- openair2/UTIL/OCG/readme.txt | 2 +- openair2/UTIL/OMG/common.c | 2 +- openair2/UTIL/OMG/defs.h | 2 +- openair2/UTIL/OMG/grid.c | 2 +- openair2/UTIL/OMG/grid.h | 2 +- openair2/UTIL/OMG/job.c | 2 +- openair2/UTIL/OMG/mobility_parser.c | 2 +- openair2/UTIL/OMG/mobility_parser.h | 2 +- openair2/UTIL/OMG/omg.c | 2 +- openair2/UTIL/OMG/omg.h | 2 +- openair2/UTIL/OMG/omg_constants.h | 2 +- openair2/UTIL/OMG/omg_hashtable.c | 2 +- openair2/UTIL/OMG/omg_hashtable.h | 2 +- openair2/UTIL/OMG/omg_vars.h | 2 +- openair2/UTIL/OMG/rwalk.c | 2 +- openair2/UTIL/OMG/rwalk.h | 2 +- openair2/UTIL/OMG/rwp.c | 2 +- openair2/UTIL/OMG/rwp.h | 2 +- openair2/UTIL/OMG/static.c | 2 +- openair2/UTIL/OMG/static.h | 2 +- openair2/UTIL/OMG/steadystaterwp.c | 2 +- openair2/UTIL/OMG/steadystaterwp.h | 2 +- openair2/UTIL/OMG/trace.c | 2 +- openair2/UTIL/OMG/trace.h | 2 +- openair2/UTIL/OMG/trace_hashtable.c | 2 +- openair2/UTIL/OMG/trace_hashtable.h | 2 +- openair2/UTIL/OMV/communicationthread.cpp | 2 +- openair2/UTIL/OMV/communicationthread.h | 2 +- openair2/UTIL/OMV/mywindow.cpp | 2 +- openair2/UTIL/OMV/mywindow.h | 2 +- openair2/UTIL/OMV/omv.cpp | 2 +- openair2/UTIL/OMV/openglwidget.cpp | 2 +- openair2/UTIL/OMV/openglwidget.h | 2 +- openair2/UTIL/OMV/structures.h | 2 +- openair2/UTIL/OPT/opt.h | 2 +- openair2/UTIL/OPT/vars.h | 2 +- openair2/UTIL/OSA/osa_defs.h | 2 +- openair2/UTIL/OSA/osa_internal.h | 2 +- openair2/UTIL/OSA/osa_key_deriver.c | 2 +- openair2/UTIL/OSA/osa_rijndael.c | 2 +- openair2/UTIL/OSA/osa_rijndael.h | 2 +- openair2/UTIL/OSA/osa_snow3g.c | 2 +- openair2/UTIL/OSA/osa_snow3g.h | 2 +- openair2/UTIL/OSA/osa_stream_eea.c | 2 +- openair2/UTIL/OSA/osa_stream_eia.c | 2 +- openair2/UTIL/OSD/recep.php | 2 +- openair2/UTIL/OTG/main.c | 2 +- openair2/UTIL/OTG/otg.c | 2 +- openair2/UTIL/OTG/otg.h | 2 +- openair2/UTIL/OTG/otg_config.h | 2 +- openair2/UTIL/OTG/otg_defs.h | 2 +- openair2/UTIL/OTG/otg_externs.h | 2 +- openair2/UTIL/OTG/otg_form.c | 2 +- openair2/UTIL/OTG/otg_form.h | 2 +- openair2/UTIL/OTG/otg_kpi.c | 2 +- openair2/UTIL/OTG/otg_kpi.h | 2 +- openair2/UTIL/OTG/otg_models.c | 2 +- openair2/UTIL/OTG/otg_models.h | 2 +- openair2/UTIL/OTG/otg_rx.c | 2 +- openair2/UTIL/OTG/otg_rx.h | 2 +- openair2/UTIL/OTG/otg_rx_socket.c | 2 +- openair2/UTIL/OTG/otg_rx_socket.h | 2 +- openair2/UTIL/OTG/otg_tx.c | 2 +- openair2/UTIL/OTG/otg_tx.h | 2 +- openair2/UTIL/OTG/otg_tx_socket.c | 2 +- openair2/UTIL/OTG/otg_tx_socket.h | 2 +- openair2/UTIL/OTG/otg_vars.h | 2 +- openair2/UTIL/OTG/traffic_config.h | 2 +- openair2/UTIL/TIMER/umts_timer.c | 2 +- openair2/UTIL/TIMER/umts_timer.h | 2 +- openair2/UTIL/TIMER/umts_timer_proto_extern.h | 2 +- openair2/UTIL/TIMER/umts_timer_struct.h | 2 +- openair2/UTIL/TRACE/fifo_printf.c | 2 +- openair2/UTIL/TRACE/fifo_printf.h | 2 +- .../UTIL/TRACE/fifo_printf_proto_extern.h | 2 +- openair2/UTIL/TRACE/print.h | 2 +- openair2/X2AP/MESSAGES/ASN1/asn1tostruct.py | 2 +- openair2/X2AP/x2ap.c | 2 +- openair2/X2AP/x2ap.h | 2 +- openair2/X2AP/x2ap_common.c | 2 +- openair2/X2AP/x2ap_common.h | 2 +- openair3/COMMON/common_types.h | 2 +- openair3/COMMON/gtpv1_u_messages_def.h | 2 +- openair3/COMMON/gtpv1_u_messages_types.h | 2 +- openair3/COMMON/intertask_interface_conf.h | 2 +- openair3/COMMON/messages_def.h | 2 +- openair3/COMMON/messages_types.h | 2 +- openair3/COMMON/nas_messages_def.h | 2 +- openair3/COMMON/nas_messages_types.h | 2 +- openair3/COMMON/s1ap_messages_def.h | 2 +- openair3/COMMON/s1ap_messages_types.h | 2 +- openair3/COMMON/sctp_messages_def.h | 2 +- openair3/COMMON/sctp_messages_types.h | 2 +- openair3/COMMON/security_types.h | 2 +- openair3/COMMON/tasks_def.h | 2 +- openair3/COMMON/udp_messages_def.h | 2 +- openair3/COMMON/udp_messages_types.h | 2 +- openair3/DOCS/DOXYGEN/Makefile.am | 2 +- openair3/DOCS/Latex/EPC/Makefile | 2 +- openair3/DOCS/Makefile.am | 2 +- openair3/GTPV1-U/Makefile.am | 2 +- openair3/GTPV1-U/Makefile.eNB | 2 +- openair3/GTPV1-U/gtpv1u.h | 2 +- openair3/GTPV1-U/gtpv1u_eNB.c | 2 +- openair3/GTPV1-U/gtpv1u_eNB_defs.h | 2 +- openair3/GTPV1-U/gtpv1u_eNB_task.h | 2 +- openair3/GTPV1-U/gtpv1u_sgw_defs.h | 2 +- openair3/GTPV1-U/gtpv1u_task.c | 2 +- openair3/GTPV1-U/gtpv1u_teid_pool.c | 2 +- openair3/NAS/COMMON/API/NETWORK/as_message.c | 2 +- openair3/NAS/COMMON/API/NETWORK/l2_message.h | 2 +- openair3/NAS/COMMON/API/NETWORK/nas_message.c | 2 +- openair3/NAS/COMMON/API/NETWORK/nas_message.h | 2 +- openair3/NAS/COMMON/API/NETWORK/network_api.c | 2 +- openair3/NAS/COMMON/API/NETWORK/network_api.h | 2 +- openair3/NAS/COMMON/EMM/MSG/AttachAccept.c | 2 +- openair3/NAS/COMMON/EMM/MSG/AttachAccept.h | 2 +- openair3/NAS/COMMON/EMM/MSG/AttachComplete.c | 2 +- openair3/NAS/COMMON/EMM/MSG/AttachComplete.h | 2 +- openair3/NAS/COMMON/EMM/MSG/AttachReject.c | 2 +- openair3/NAS/COMMON/EMM/MSG/AttachReject.h | 2 +- openair3/NAS/COMMON/EMM/MSG/AttachRequest.c | 2 +- openair3/NAS/COMMON/EMM/MSG/AttachRequest.h | 2 +- .../COMMON/EMM/MSG/AuthenticationFailure.c | 2 +- .../COMMON/EMM/MSG/AuthenticationFailure.h | 2 +- .../NAS/COMMON/EMM/MSG/AuthenticationReject.c | 2 +- .../NAS/COMMON/EMM/MSG/AuthenticationReject.h | 2 +- .../COMMON/EMM/MSG/AuthenticationRequest.c | 2 +- .../COMMON/EMM/MSG/AuthenticationRequest.h | 2 +- .../COMMON/EMM/MSG/AuthenticationResponse.c | 2 +- .../COMMON/EMM/MSG/AuthenticationResponse.h | 2 +- .../COMMON/EMM/MSG/CsServiceNotification.c | 2 +- .../COMMON/EMM/MSG/CsServiceNotification.h | 2 +- openair3/NAS/COMMON/EMM/MSG/DetachAccept.c | 2 +- openair3/NAS/COMMON/EMM/MSG/DetachAccept.h | 2 +- openair3/NAS/COMMON/EMM/MSG/DetachRequest.c | 2 +- openair3/NAS/COMMON/EMM/MSG/DetachRequest.h | 2 +- .../NAS/COMMON/EMM/MSG/DownlinkNasTransport.c | 2 +- .../NAS/COMMON/EMM/MSG/DownlinkNasTransport.h | 2 +- openair3/NAS/COMMON/EMM/MSG/EmmInformation.c | 2 +- openair3/NAS/COMMON/EMM/MSG/EmmInformation.h | 2 +- openair3/NAS/COMMON/EMM/MSG/EmmStatus.c | 2 +- openair3/NAS/COMMON/EMM/MSG/EmmStatus.h | 2 +- .../COMMON/EMM/MSG/ExtendedServiceRequest.c | 2 +- .../COMMON/EMM/MSG/ExtendedServiceRequest.h | 2 +- .../COMMON/EMM/MSG/GutiReallocationCommand.c | 2 +- .../COMMON/EMM/MSG/GutiReallocationCommand.h | 2 +- .../COMMON/EMM/MSG/GutiReallocationComplete.c | 2 +- .../COMMON/EMM/MSG/GutiReallocationComplete.h | 2 +- openair3/NAS/COMMON/EMM/MSG/IdentityRequest.c | 2 +- openair3/NAS/COMMON/EMM/MSG/IdentityRequest.h | 2 +- .../NAS/COMMON/EMM/MSG/IdentityResponse.c | 2 +- .../NAS/COMMON/EMM/MSG/IdentityResponse.h | 2 +- .../COMMON/EMM/MSG/NASSecurityModeCommand.h | 2 +- .../COMMON/EMM/MSG/NASSecurityModeComplete.h | 2 +- .../NAS/COMMON/EMM/MSG/SecurityModeCommand.c | 2 +- .../NAS/COMMON/EMM/MSG/SecurityModeComplete.c | 2 +- .../NAS/COMMON/EMM/MSG/SecurityModeReject.c | 2 +- .../NAS/COMMON/EMM/MSG/SecurityModeReject.h | 2 +- openair3/NAS/COMMON/EMM/MSG/ServiceReject.c | 2 +- openair3/NAS/COMMON/EMM/MSG/ServiceReject.h | 2 +- openair3/NAS/COMMON/EMM/MSG/ServiceRequest.c | 2 +- openair3/NAS/COMMON/EMM/MSG/ServiceRequest.h | 2 +- .../COMMON/EMM/MSG/TrackingAreaUpdateAccept.c | 2 +- .../COMMON/EMM/MSG/TrackingAreaUpdateAccept.h | 2 +- .../EMM/MSG/TrackingAreaUpdateComplete.c | 2 +- .../EMM/MSG/TrackingAreaUpdateComplete.h | 2 +- .../COMMON/EMM/MSG/TrackingAreaUpdateReject.c | 2 +- .../COMMON/EMM/MSG/TrackingAreaUpdateReject.h | 2 +- .../EMM/MSG/TrackingAreaUpdateRequest.c | 2 +- .../EMM/MSG/TrackingAreaUpdateRequest.h | 2 +- .../NAS/COMMON/EMM/MSG/UplinkNasTransport.c | 2 +- .../NAS/COMMON/EMM/MSG/UplinkNasTransport.h | 2 +- openair3/NAS/COMMON/EMM/MSG/emm_cause.h | 2 +- openair3/NAS/COMMON/EMM/MSG/emm_msg.c | 2 +- openair3/NAS/COMMON/EMM/MSG/emm_msg.h | 2 +- openair3/NAS/COMMON/EMM/MSG/emm_msgDef.h | 2 +- .../ActivateDedicatedEpsBearerContextAccept.c | 2 +- .../ActivateDedicatedEpsBearerContextAccept.h | 2 +- .../ActivateDedicatedEpsBearerContextReject.c | 2 +- .../ActivateDedicatedEpsBearerContextReject.h | 2 +- ...ActivateDedicatedEpsBearerContextRequest.c | 2 +- ...ActivateDedicatedEpsBearerContextRequest.h | 2 +- .../ActivateDefaultEpsBearerContextAccept.c | 2 +- .../ActivateDefaultEpsBearerContextAccept.h | 2 +- .../ActivateDefaultEpsBearerContextReject.c | 2 +- .../ActivateDefaultEpsBearerContextReject.h | 2 +- .../ActivateDefaultEpsBearerContextRequest.c | 2 +- .../ActivateDefaultEpsBearerContextRequest.h | 2 +- .../ESM/MSG/BearerResourceAllocationReject.c | 2 +- .../ESM/MSG/BearerResourceAllocationReject.h | 2 +- .../ESM/MSG/BearerResourceAllocationRequest.c | 2 +- .../ESM/MSG/BearerResourceAllocationRequest.h | 2 +- .../MSG/BearerResourceModificationReject.c | 2 +- .../MSG/BearerResourceModificationReject.h | 2 +- .../MSG/BearerResourceModificationRequest.c | 2 +- .../MSG/BearerResourceModificationRequest.h | 2 +- .../MSG/DeactivateEpsBearerContextAccept.c | 2 +- .../MSG/DeactivateEpsBearerContextAccept.h | 2 +- .../MSG/DeactivateEpsBearerContextRequest.c | 2 +- .../MSG/DeactivateEpsBearerContextRequest.h | 2 +- .../COMMON/ESM/MSG/EsmInformationRequest.c | 2 +- .../COMMON/ESM/MSG/EsmInformationRequest.h | 2 +- .../COMMON/ESM/MSG/EsmInformationResponse.c | 2 +- .../COMMON/ESM/MSG/EsmInformationResponse.h | 2 +- openair3/NAS/COMMON/ESM/MSG/EsmStatus.c | 2 +- openair3/NAS/COMMON/ESM/MSG/EsmStatus.h | 2 +- .../ESM/MSG/ModifyEpsBearerContextAccept.c | 2 +- .../ESM/MSG/ModifyEpsBearerContextAccept.h | 2 +- .../ESM/MSG/ModifyEpsBearerContextReject.c | 2 +- .../ESM/MSG/ModifyEpsBearerContextReject.h | 2 +- .../ESM/MSG/ModifyEpsBearerContextRequest.c | 2 +- .../ESM/MSG/ModifyEpsBearerContextRequest.h | 2 +- .../COMMON/ESM/MSG/PdnConnectivityReject.c | 2 +- .../COMMON/ESM/MSG/PdnConnectivityReject.h | 2 +- .../COMMON/ESM/MSG/PdnConnectivityRequest.c | 2 +- .../COMMON/ESM/MSG/PdnConnectivityRequest.h | 2 +- .../NAS/COMMON/ESM/MSG/PdnDisconnectReject.c | 2 +- .../NAS/COMMON/ESM/MSG/PdnDisconnectReject.h | 2 +- .../NAS/COMMON/ESM/MSG/PdnDisconnectRequest.c | 2 +- .../NAS/COMMON/ESM/MSG/PdnDisconnectRequest.h | 2 +- openair3/NAS/COMMON/ESM/MSG/esm_cause.h | 2 +- openair3/NAS/COMMON/ESM/MSG/esm_msg.c | 2 +- openair3/NAS/COMMON/ESM/MSG/esm_msg.h | 2 +- openair3/NAS/COMMON/ESM/MSG/esm_msgDef.h | 2 +- openair3/NAS/COMMON/IES/AccessPointName.c | 2 +- openair3/NAS/COMMON/IES/AccessPointName.h | 2 +- .../NAS/COMMON/IES/AdditionalUpdateResult.c | 2 +- .../NAS/COMMON/IES/AdditionalUpdateResult.h | 2 +- .../NAS/COMMON/IES/AdditionalUpdateType.c | 2 +- .../NAS/COMMON/IES/AdditionalUpdateType.h | 2 +- .../COMMON/IES/ApnAggregateMaximumBitRate.c | 2 +- .../COMMON/IES/ApnAggregateMaximumBitRate.h | 2 +- .../IES/AuthenticationFailureParameter.c | 2 +- .../IES/AuthenticationFailureParameter.h | 2 +- .../COMMON/IES/AuthenticationParameterAutn.c | 2 +- .../COMMON/IES/AuthenticationParameterAutn.h | 2 +- .../COMMON/IES/AuthenticationParameterRand.c | 2 +- .../COMMON/IES/AuthenticationParameterRand.h | 2 +- .../IES/AuthenticationResponseParameter.c | 2 +- .../IES/AuthenticationResponseParameter.h | 2 +- .../COMMON/IES/CipheringKeySequenceNumber.c | 2 +- .../COMMON/IES/CipheringKeySequenceNumber.h | 2 +- openair3/NAS/COMMON/IES/Cli.c | 2 +- openair3/NAS/COMMON/IES/Cli.h | 2 +- openair3/NAS/COMMON/IES/CsfbResponse.c | 2 +- openair3/NAS/COMMON/IES/CsfbResponse.h | 2 +- openair3/NAS/COMMON/IES/DaylightSavingTime.c | 2 +- openair3/NAS/COMMON/IES/DaylightSavingTime.h | 2 +- openair3/NAS/COMMON/IES/DetachType.c | 2 +- openair3/NAS/COMMON/IES/DetachType.h | 2 +- openair3/NAS/COMMON/IES/DrxParameter.c | 2 +- openair3/NAS/COMMON/IES/DrxParameter.h | 2 +- openair3/NAS/COMMON/IES/EmergencyNumberList.c | 2 +- openair3/NAS/COMMON/IES/EmergencyNumberList.h | 2 +- openair3/NAS/COMMON/IES/EmmCause.c | 2 +- openair3/NAS/COMMON/IES/EmmCause.h | 2 +- openair3/NAS/COMMON/IES/EpsAttachResult.c | 2 +- openair3/NAS/COMMON/IES/EpsAttachResult.h | 2 +- openair3/NAS/COMMON/IES/EpsAttachType.c | 2 +- openair3/NAS/COMMON/IES/EpsAttachType.h | 2 +- .../NAS/COMMON/IES/EpsBearerContextStatus.c | 2 +- .../NAS/COMMON/IES/EpsBearerContextStatus.h | 2 +- openair3/NAS/COMMON/IES/EpsBearerIdentity.c | 2 +- openair3/NAS/COMMON/IES/EpsBearerIdentity.h | 2 +- openair3/NAS/COMMON/IES/EpsMobileIdentity.c | 2 +- openair3/NAS/COMMON/IES/EpsMobileIdentity.h | 2 +- .../NAS/COMMON/IES/EpsNetworkFeatureSupport.c | 2 +- .../NAS/COMMON/IES/EpsNetworkFeatureSupport.h | 2 +- openair3/NAS/COMMON/IES/EpsQualityOfService.c | 2 +- openair3/NAS/COMMON/IES/EpsQualityOfService.h | 2 +- openair3/NAS/COMMON/IES/EpsUpdateResult.c | 2 +- openair3/NAS/COMMON/IES/EpsUpdateResult.h | 2 +- openair3/NAS/COMMON/IES/EpsUpdateType.c | 2 +- openair3/NAS/COMMON/IES/EpsUpdateType.h | 2 +- openair3/NAS/COMMON/IES/EsmCause.c | 2 +- openair3/NAS/COMMON/IES/EsmCause.h | 2 +- .../COMMON/IES/EsmInformationTransferFlag.c | 2 +- .../COMMON/IES/EsmInformationTransferFlag.h | 2 +- openair3/NAS/COMMON/IES/EsmMessageContainer.c | 2 +- openair3/NAS/COMMON/IES/EsmMessageContainer.h | 2 +- openair3/NAS/COMMON/IES/GprsTimer.c | 2 +- openair3/NAS/COMMON/IES/GprsTimer.h | 2 +- openair3/NAS/COMMON/IES/GutiType.c | 2 +- openair3/NAS/COMMON/IES/GutiType.h | 2 +- openair3/NAS/COMMON/IES/IdentityType2.c | 2 +- openair3/NAS/COMMON/IES/IdentityType2.h | 2 +- openair3/NAS/COMMON/IES/ImeisvRequest.c | 2 +- openair3/NAS/COMMON/IES/ImeisvRequest.h | 2 +- .../NAS/COMMON/IES/KsiAndSequenceNumber.c | 2 +- .../NAS/COMMON/IES/KsiAndSequenceNumber.h | 2 +- openair3/NAS/COMMON/IES/LcsClientIdentity.c | 2 +- openair3/NAS/COMMON/IES/LcsClientIdentity.h | 2 +- openair3/NAS/COMMON/IES/LcsIndicator.c | 2 +- openair3/NAS/COMMON/IES/LcsIndicator.h | 2 +- .../NAS/COMMON/IES/LinkedEpsBearerIdentity.c | 2 +- .../NAS/COMMON/IES/LinkedEpsBearerIdentity.h | 2 +- .../IES/LlcServiceAccessPointIdentifier.c | 2 +- .../IES/LlcServiceAccessPointIdentifier.h | 2 +- .../COMMON/IES/LocationAreaIdentification.c | 2 +- .../COMMON/IES/LocationAreaIdentification.h | 2 +- openair3/NAS/COMMON/IES/MessageType.c | 2 +- openair3/NAS/COMMON/IES/MessageType.h | 2 +- openair3/NAS/COMMON/IES/MobileIdentity.c | 2 +- openair3/NAS/COMMON/IES/MobileIdentity.h | 2 +- .../NAS/COMMON/IES/MobileStationClassmark2.c | 2 +- .../NAS/COMMON/IES/MobileStationClassmark2.h | 2 +- .../NAS/COMMON/IES/MobileStationClassmark3.c | 2 +- .../NAS/COMMON/IES/MobileStationClassmark3.h | 2 +- openair3/NAS/COMMON/IES/MsNetworkCapability.c | 2 +- openair3/NAS/COMMON/IES/MsNetworkCapability.h | 2 +- .../NAS/COMMON/IES/MsNetworkFeatureSupport.c | 2 +- .../NAS/COMMON/IES/MsNetworkFeatureSupport.h | 2 +- openair3/NAS/COMMON/IES/NasKeySetIdentifier.c | 2 +- openair3/NAS/COMMON/IES/NasKeySetIdentifier.h | 2 +- openair3/NAS/COMMON/IES/NasMessageContainer.c | 2 +- openair3/NAS/COMMON/IES/NasMessageContainer.h | 2 +- openair3/NAS/COMMON/IES/NasRequestType.c | 2 +- openair3/NAS/COMMON/IES/NasRequestType.h | 2 +- .../NAS/COMMON/IES/NasSecurityAlgorithms.c | 2 +- .../NAS/COMMON/IES/NasSecurityAlgorithms.h | 2 +- openair3/NAS/COMMON/IES/NetworkName.c | 2 +- openair3/NAS/COMMON/IES/NetworkName.h | 2 +- openair3/NAS/COMMON/IES/Nonce.c | 2 +- openair3/NAS/COMMON/IES/Nonce.h | 2 +- openair3/NAS/COMMON/IES/PTmsiSignature.c | 2 +- openair3/NAS/COMMON/IES/PTmsiSignature.h | 2 +- .../NAS/COMMON/IES/PacketFlowIdentifier.c | 2 +- .../NAS/COMMON/IES/PacketFlowIdentifier.h | 2 +- openair3/NAS/COMMON/IES/PagingIdentity.c | 2 +- openair3/NAS/COMMON/IES/PagingIdentity.h | 2 +- openair3/NAS/COMMON/IES/PdnAddress.c | 2 +- openair3/NAS/COMMON/IES/PdnAddress.h | 2 +- openair3/NAS/COMMON/IES/PdnType.c | 2 +- openair3/NAS/COMMON/IES/PdnType.h | 2 +- openair3/NAS/COMMON/IES/PlmnList.c | 2 +- openair3/NAS/COMMON/IES/PlmnList.h | 2 +- .../COMMON/IES/ProcedureTransactionIdentity.c | 2 +- .../COMMON/IES/ProcedureTransactionIdentity.h | 2 +- .../COMMON/IES/ProtocolConfigurationOptions.c | 2 +- .../COMMON/IES/ProtocolConfigurationOptions.h | 2 +- .../NAS/COMMON/IES/ProtocolDiscriminator.c | 2 +- .../NAS/COMMON/IES/ProtocolDiscriminator.h | 2 +- openair3/NAS/COMMON/IES/QualityOfService.c | 2 +- openair3/NAS/COMMON/IES/QualityOfService.h | 2 +- openair3/NAS/COMMON/IES/RadioPriority.c | 2 +- openair3/NAS/COMMON/IES/RadioPriority.h | 2 +- openair3/NAS/COMMON/IES/SecurityHeaderType.c | 2 +- openair3/NAS/COMMON/IES/SecurityHeaderType.h | 2 +- openair3/NAS/COMMON/IES/ServiceType.c | 2 +- openair3/NAS/COMMON/IES/ServiceType.h | 2 +- openair3/NAS/COMMON/IES/ShortMac.c | 2 +- openair3/NAS/COMMON/IES/ShortMac.h | 2 +- openair3/NAS/COMMON/IES/SsCode.c | 2 +- openair3/NAS/COMMON/IES/SsCode.h | 2 +- openair3/NAS/COMMON/IES/SupportedCodecList.c | 2 +- openair3/NAS/COMMON/IES/SupportedCodecList.h | 2 +- openair3/NAS/COMMON/IES/TimeZone.c | 2 +- openair3/NAS/COMMON/IES/TimeZone.h | 2 +- openair3/NAS/COMMON/IES/TimeZoneAndTime.c | 2 +- openair3/NAS/COMMON/IES/TimeZoneAndTime.h | 2 +- openair3/NAS/COMMON/IES/TmsiStatus.c | 2 +- openair3/NAS/COMMON/IES/TmsiStatus.h | 2 +- .../NAS/COMMON/IES/TrackingAreaIdentity.c | 2 +- .../NAS/COMMON/IES/TrackingAreaIdentity.h | 2 +- .../NAS/COMMON/IES/TrackingAreaIdentityList.c | 2 +- .../NAS/COMMON/IES/TrackingAreaIdentityList.h | 2 +- .../IES/TrafficFlowAggregateDescription.c | 2 +- .../IES/TrafficFlowAggregateDescription.h | 2 +- openair3/NAS/COMMON/IES/TrafficFlowTemplate.c | 2 +- openair3/NAS/COMMON/IES/TrafficFlowTemplate.h | 2 +- .../NAS/COMMON/IES/TransactionIdentifier.c | 2 +- .../NAS/COMMON/IES/TransactionIdentifier.h | 2 +- openair3/NAS/COMMON/IES/UeNetworkCapability.c | 2 +- openair3/NAS/COMMON/IES/UeNetworkCapability.h | 2 +- ...UeRadioCapabilityInformationUpdateNeeded.c | 2 +- ...UeRadioCapabilityInformationUpdateNeeded.h | 2 +- .../NAS/COMMON/IES/UeSecurityCapability.c | 2 +- .../NAS/COMMON/IES/UeSecurityCapability.h | 2 +- .../VoiceDomainPreferenceAndUeUsageSetting.c | 2 +- .../VoiceDomainPreferenceAndUeUsageSetting.h | 2 +- openair3/NAS/COMMON/UTIL/OctetString.c | 2 +- openair3/NAS/COMMON/UTIL/OctetString.h | 2 +- openair3/NAS/COMMON/UTIL/TLVDecoder.c | 2 +- openair3/NAS/COMMON/UTIL/TLVDecoder.h | 2 +- openair3/NAS/COMMON/UTIL/TLVEncoder.c | 2 +- openair3/NAS/COMMON/UTIL/TLVEncoder.h | 2 +- openair3/NAS/COMMON/UTIL/device.c | 2 +- openair3/NAS/COMMON/UTIL/device.h | 2 +- openair3/NAS/COMMON/UTIL/memory.c | 2 +- openair3/NAS/COMMON/UTIL/memory.h | 2 +- openair3/NAS/COMMON/UTIL/nas_log.c | 2 +- openair3/NAS/COMMON/UTIL/nas_log.h | 2 +- openair3/NAS/COMMON/UTIL/nas_timer.c | 2 +- openair3/NAS/COMMON/UTIL/nas_timer.h | 2 +- openair3/NAS/COMMON/UTIL/parser.c | 2 +- openair3/NAS/COMMON/UTIL/parser.h | 2 +- openair3/NAS/COMMON/UTIL/socket.c | 2 +- openair3/NAS/COMMON/UTIL/socket.h | 2 +- openair3/NAS/COMMON/UTIL/stty.c | 2 +- openair3/NAS/COMMON/UTIL/tst/timer.c | 2 +- openair3/NAS/COMMON/securityDef.h | 2 +- openair3/NAS/COMMON/userDef.h | 2 +- openair3/NAS/TEST/AS_SIMULATOR/Makefile | 2 +- openair3/NAS/TEST/AS_SIMULATOR/as_data.c | 2 +- openair3/NAS/TEST/AS_SIMULATOR/as_data.h | 2 +- openair3/NAS/TEST/AS_SIMULATOR/as_process.c | 2 +- openair3/NAS/TEST/AS_SIMULATOR/as_process.h | 2 +- openair3/NAS/TEST/AS_SIMULATOR/as_simulator.c | 2 +- .../TEST/AS_SIMULATOR/as_simulator_parser.c | 2 +- .../TEST/AS_SIMULATOR/as_simulator_parser.h | 2 +- openair3/NAS/TEST/AS_SIMULATOR/nas_data.c | 2 +- openair3/NAS/TEST/AS_SIMULATOR/nas_data.h | 2 +- openair3/NAS/TEST/AS_SIMULATOR/nas_process.c | 2 +- openair3/NAS/TEST/AS_SIMULATOR/nas_process.h | 2 +- openair3/NAS/TEST/NETWORK/Makefile | 2 +- openair3/NAS/TEST/NETWORK/network_parser.c | 2 +- openair3/NAS/TEST/NETWORK/network_parser.h | 2 +- openair3/NAS/TEST/NETWORK/network_simulator.c | 2 +- openair3/NAS/TEST/USER/Makefile | 2 +- openair3/NAS/TEST/USER/user_parser.c | 2 +- openair3/NAS/TEST/USER/user_parser.h | 2 +- openair3/NAS/TEST/USER/user_simulator.c | 2 +- openair3/NAS/TOOLS/network.h | 2 +- openair3/NAS/TOOLS/nvram.c | 2 +- openair3/NAS/TOOLS/usim.c | 2 +- openair3/NAS/UE/API/USER/at_command.c | 2 +- openair3/NAS/UE/API/USER/at_command.h | 2 +- openair3/NAS/UE/API/USER/at_error.c | 2 +- openair3/NAS/UE/API/USER/at_error.h | 2 +- openair3/NAS/UE/API/USER/at_response.c | 2 +- openair3/NAS/UE/API/USER/at_response.h | 2 +- openair3/NAS/UE/API/USER/tst/at_parser.c | 2 +- openair3/NAS/UE/API/USER/user_api.c | 2 +- openair3/NAS/UE/API/USER/user_api.h | 2 +- openair3/NAS/UE/API/USER/user_indication.c | 2 +- openair3/NAS/UE/API/USER/user_indication.h | 2 +- openair3/NAS/UE/API/USIM/aka_functions.c | 2 +- openair3/NAS/UE/API/USIM/aka_functions.h | 2 +- openair3/NAS/UE/API/USIM/usim_api.c | 2 +- openair3/NAS/UE/API/USIM/usim_api.h | 2 +- openair3/NAS/UE/EMM/Attach.c | 2 +- openair3/NAS/UE/EMM/Authentication.c | 2 +- openair3/NAS/UE/EMM/Detach.c | 2 +- openair3/NAS/UE/EMM/EmmStatusHdl.c | 2 +- openair3/NAS/UE/EMM/Identification.c | 2 +- openair3/NAS/UE/EMM/IdleMode.c | 2 +- openair3/NAS/UE/EMM/IdleMode.h | 2 +- openair3/NAS/UE/EMM/LowerLayer.c | 2 +- openair3/NAS/UE/EMM/LowerLayer.h | 2 +- openair3/NAS/UE/EMM/SAP/EmmDeregistered.c | 2 +- .../UE/EMM/SAP/EmmDeregisteredAttachNeeded.c | 2 +- .../SAP/EmmDeregisteredAttemptingToAttach.c | 2 +- .../NAS/UE/EMM/SAP/EmmDeregisteredInitiated.c | 2 +- .../EMM/SAP/EmmDeregisteredLimitedService.c | 2 +- .../EMM/SAP/EmmDeregisteredNoCellAvailable.c | 2 +- .../NAS/UE/EMM/SAP/EmmDeregisteredNoImsi.c | 2 +- .../UE/EMM/SAP/EmmDeregisteredNormalService.c | 2 +- .../UE/EMM/SAP/EmmDeregisteredPlmnSearch.c | 2 +- openair3/NAS/UE/EMM/SAP/EmmNull.c | 2 +- openair3/NAS/UE/EMM/SAP/EmmRegistered.c | 2 +- .../EMM/SAP/EmmRegisteredAttemptingToUpdate.c | 2 +- .../SAP/EmmRegisteredImsiDetachInitiated.c | 2 +- .../NAS/UE/EMM/SAP/EmmRegisteredInitiated.c | 2 +- .../UE/EMM/SAP/EmmRegisteredLimitedService.c | 2 +- .../UE/EMM/SAP/EmmRegisteredNoCellAvailable.c | 2 +- .../UE/EMM/SAP/EmmRegisteredNormalService.c | 2 +- .../NAS/UE/EMM/SAP/EmmRegisteredPlmnSearch.c | 2 +- .../UE/EMM/SAP/EmmRegisteredUpdateNeeded.c | 2 +- .../UE/EMM/SAP/EmmServiceRequestInitiated.c | 2 +- .../SAP/EmmTrackingAreaUpdatingInitiated.c | 2 +- openair3/NAS/UE/EMM/SAP/emm_as.c | 2 +- openair3/NAS/UE/EMM/SAP/emm_as.h | 2 +- openair3/NAS/UE/EMM/SAP/emm_asDef.h | 2 +- openair3/NAS/UE/EMM/SAP/emm_esm.c | 2 +- openair3/NAS/UE/EMM/SAP/emm_esm.h | 2 +- openair3/NAS/UE/EMM/SAP/emm_esmDef.h | 2 +- openair3/NAS/UE/EMM/SAP/emm_fsm.c | 2 +- openair3/NAS/UE/EMM/SAP/emm_fsm.h | 2 +- openair3/NAS/UE/EMM/SAP/emm_recv.c | 2 +- openair3/NAS/UE/EMM/SAP/emm_recv.h | 2 +- openair3/NAS/UE/EMM/SAP/emm_reg.c | 2 +- openair3/NAS/UE/EMM/SAP/emm_reg.h | 2 +- openair3/NAS/UE/EMM/SAP/emm_regDef.h | 2 +- openair3/NAS/UE/EMM/SAP/emm_sap.c | 2 +- openair3/NAS/UE/EMM/SAP/emm_sap.h | 2 +- openair3/NAS/UE/EMM/SAP/emm_send.c | 2 +- openair3/NAS/UE/EMM/SAP/emm_send.h | 2 +- openair3/NAS/UE/EMM/SecurityModeControl.c | 2 +- openair3/NAS/UE/EMM/ServiceRequestHdl.c | 2 +- openair3/NAS/UE/EMM/TrackingAreaUpdate.c | 2 +- openair3/NAS/UE/EMM/emmData.h | 2 +- openair3/NAS/UE/EMM/emm_main.c | 2 +- openair3/NAS/UE/EMM/emm_main.h | 2 +- openair3/NAS/UE/EMM/emm_proc.h | 2 +- .../ESM/DedicatedEpsBearerContextActivation.c | 2 +- .../ESM/DefaultEpsBearerContextActivation.c | 2 +- .../NAS/UE/ESM/EpsBearerContextDeactivation.c | 2 +- openair3/NAS/UE/ESM/EsmStatusHdl.c | 2 +- openair3/NAS/UE/ESM/PdnConnectivity.c | 2 +- openair3/NAS/UE/ESM/PdnDisconnect.c | 2 +- openair3/NAS/UE/ESM/SAP/esm_recv.c | 2 +- openair3/NAS/UE/ESM/SAP/esm_recv.h | 2 +- openair3/NAS/UE/ESM/SAP/esm_sap.c | 2 +- openair3/NAS/UE/ESM/SAP/esm_sap.h | 2 +- openair3/NAS/UE/ESM/SAP/esm_sapDef.h | 2 +- openair3/NAS/UE/ESM/SAP/esm_send.c | 2 +- openair3/NAS/UE/ESM/SAP/esm_send.h | 2 +- openair3/NAS/UE/ESM/esmData.h | 2 +- openair3/NAS/UE/ESM/esm_ebr.c | 2 +- openair3/NAS/UE/ESM/esm_ebr.h | 2 +- openair3/NAS/UE/ESM/esm_ebr_context.c | 2 +- openair3/NAS/UE/ESM/esm_ebr_context.h | 2 +- openair3/NAS/UE/ESM/esm_ip.c | 2 +- openair3/NAS/UE/ESM/esm_main.c | 2 +- openair3/NAS/UE/ESM/esm_main.h | 2 +- openair3/NAS/UE/ESM/esm_proc.h | 2 +- openair3/NAS/UE/ESM/esm_pt.c | 2 +- openair3/NAS/UE/ESM/esm_pt.h | 2 +- openair3/NAS/UE/UEprocess.c | 2 +- openair3/NAS/UE/nas_itti_messaging.c | 2 +- openair3/NAS/UE/nas_itti_messaging.h | 2 +- openair3/NAS/UE/nas_network.c | 2 +- openair3/NAS/UE/nas_network.h | 2 +- openair3/NAS/UE/nas_parser.c | 2 +- openair3/NAS/UE/nas_parser.h | 2 +- openair3/NAS/UE/nas_proc.c | 2 +- openair3/NAS/UE/nas_proc.h | 2 +- openair3/NAS/UE/nas_ue_task.c | 2 +- openair3/NAS/UE/nas_ue_task.h | 2 +- openair3/NAS/UE/nas_user.c | 2 +- openair3/NAS/UE/nas_user.h | 2 +- openair3/NAS/UE/user_defs.h | 2 +- openair3/S1AP/MESSAGES/ASN1/asn1tostruct.py | 2 +- openair3/S1AP/s1ap_common.c | 2 +- openair3/S1AP/s1ap_common.h | 2 +- openair3/S1AP/s1ap_eNB.c | 2 +- openair3/S1AP/s1ap_eNB.h | 2 +- .../s1ap_eNB_context_management_procedures.c | 2 +- .../s1ap_eNB_context_management_procedures.h | 2 +- openair3/S1AP/s1ap_eNB_decoder.c | 2 +- openair3/S1AP/s1ap_eNB_decoder.h | 2 +- openair3/S1AP/s1ap_eNB_default_values.h | 2 +- openair3/S1AP/s1ap_eNB_defs.h | 2 +- openair3/S1AP/s1ap_eNB_encoder.c | 2 +- openair3/S1AP/s1ap_eNB_encoder.h | 2 +- openair3/S1AP/s1ap_eNB_handlers.c | 2 +- openair3/S1AP/s1ap_eNB_handlers.h | 2 +- openair3/S1AP/s1ap_eNB_itti_messaging.c | 2 +- openair3/S1AP/s1ap_eNB_itti_messaging.h | 2 +- .../S1AP/s1ap_eNB_management_procedures.c | 2 +- .../S1AP/s1ap_eNB_management_procedures.h | 2 +- openair3/S1AP/s1ap_eNB_nas_procedures.c | 2 +- openair3/S1AP/s1ap_eNB_nas_procedures.h | 2 +- openair3/S1AP/s1ap_eNB_nnsf.c | 2 +- openair3/S1AP/s1ap_eNB_nnsf.h | 2 +- openair3/S1AP/s1ap_eNB_overload.c | 2 +- openair3/S1AP/s1ap_eNB_overload.h | 2 +- openair3/S1AP/s1ap_eNB_trace.c | 2 +- openair3/S1AP/s1ap_eNB_trace.h | 2 +- openair3/S1AP/s1ap_eNB_ue_context.c | 2 +- openair3/S1AP/s1ap_eNB_ue_context.h | 2 +- openair3/SCTP/sctp_common.c | 2 +- openair3/SCTP/sctp_common.h | 2 +- openair3/SCTP/sctp_default_values.h | 2 +- openair3/SCTP/sctp_eNB_defs.h | 2 +- openair3/SCTP/sctp_eNB_itti_messaging.c | 2 +- openair3/SCTP/sctp_eNB_itti_messaging.h | 2 +- openair3/SCTP/sctp_eNB_task.c | 2 +- openair3/SCTP/sctp_eNB_task.h | 2 +- openair3/SCTP/sctp_primitives_client.c | 2 +- openair3/SCTP/sctp_primitives_client.h | 2 +- openair3/SECU/kdf.c | 2 +- openair3/SECU/key_nas_deriver.c | 2 +- openair3/SECU/key_nas_encryption.c | 2 +- openair3/SECU/nas_stream_eea1.c | 2 +- openair3/SECU/nas_stream_eea2.c | 2 +- openair3/SECU/nas_stream_eia1.c | 2 +- openair3/SECU/nas_stream_eia2.c | 2 +- openair3/SECU/rijndael.c | 2 +- openair3/SECU/rijndael.h | 2 +- openair3/SECU/secu_defs.h | 2 +- openair3/SECU/snow3g.c | 2 +- openair3/SECU/snow3g.h | 2 +- openair3/TEST/EPC_TEST/generate_scenario.c | 2 +- openair3/TEST/EPC_TEST/generate_scenario.h | 2 +- openair3/TEST/EPC_TEST/play_scenario.c | 2 +- openair3/TEST/EPC_TEST/play_scenario.h | 2 +- openair3/TEST/EPC_TEST/play_scenario_decode.c | 2 +- .../TEST/EPC_TEST/play_scenario_display.c | 2 +- openair3/TEST/EPC_TEST/play_scenario_fsm.c | 2 +- openair3/TEST/EPC_TEST/play_scenario_parse.c | 2 +- openair3/TEST/EPC_TEST/play_scenario_s1ap.c | 2 +- .../EPC_TEST/play_scenario_s1ap_compare_ie.c | 2 +- .../EPC_TEST/play_scenario_s1ap_eNB_defs.h | 2 +- openair3/TEST/EPC_TEST/play_scenario_sctp.c | 2 +- openair3/TEST/Makefile.am | 2 +- openair3/TEST/oaisim_mme_client_test.c | 2 +- openair3/TEST/oaisim_mme_itti_test.c | 2 +- openair3/TEST/oaisim_mme_list_benchmark.c | 2 +- openair3/TEST/oaisim_mme_s1ap_test.c | 2 +- openair3/TEST/oaisim_mme_sctp_test.c | 2 +- openair3/TEST/oaisim_mme_test_s1c.c | 2 +- openair3/TEST/oaisim_mme_test_s1c.h | 2 +- openair3/TEST/oaisim_mme_test_s1c_s1ap.c | 2 +- openair3/TEST/oaisim_mme_test_s1c_s1ap.h | 2 +- openair3/TEST/oaisim_mme_test_s1c_scenario.c | 2 +- openair3/TEST/oaisim_mme_test_s1c_scenario.h | 2 +- openair3/TEST/oaisim_mme_test_s1c_scenario1.c | 2 +- openair3/TEST/test_aes128_cmac_encrypt.c | 2 +- openair3/TEST/test_aes128_ctr_decrypt.c | 2 +- openair3/TEST/test_aes128_ctr_encrypt.c | 2 +- openair3/TEST/test_kdf.c | 2 +- openair3/TEST/test_s1ap.c | 2 +- openair3/TEST/test_secu.c | 2 +- openair3/TEST/test_secu_kenb.c | 2 +- openair3/TEST/test_secu_knas.c | 2 +- openair3/TEST/test_secu_knas_encrypt_eea1.c | 2 +- openair3/TEST/test_secu_knas_encrypt_eea2.c | 2 +- openair3/TEST/test_secu_knas_encrypt_eia1.c | 2 +- openair3/TEST/test_secu_knas_encrypt_eia2.c | 2 +- openair3/TEST/test_secu_knas_stream_int.c | 2 +- openair3/UDP/udp_eNB_task.c | 2 +- openair3/UDP/udp_eNB_task.h | 2 +- openair3/UTILS/conversions.c | 2 +- openair3/UTILS/conversions.h | 2 +- openair3/UTILS/enum_string.c | 2 +- openair3/UTILS/enum_string.h | 2 +- openair3/UTILS/log.c | 2 +- openair3/UTILS/log.h | 2 +- openair3/UTILS/mcc_mnc_itu.c | 2 +- openair3/UTILS/mcc_mnc_itu.h | 2 +- openair3/UTILS/mme_config.c | 2 +- openair3/UTILS/mme_config.h | 2 +- openair3/UTILS/mme_default_values.h | 2 +- .../ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c | 2 +- .../ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.h | 2 +- targets/ARCH/COMMON/common_lib.c | 2 +- targets/ARCH/COMMON/common_lib.h | 2 +- targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c | 2 +- targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c | 2 +- .../ETHERNET/USERSPACE/LIB/ethernet_lib.c | 2 +- .../ETHERNET/USERSPACE/LIB/ethernet_lib.h | 2 +- targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h | 2 +- targets/ARCH/EXMIMO/DEFS/openair_device.h | 2 +- targets/ARCH/EXMIMO/DEFS/pcie_interface.h | 2 +- targets/ARCH/EXMIMO/DRIVER/eurecom/defs.h | 2 +- .../ARCH/EXMIMO/DRIVER/eurecom/exmimo_fw.c | 2 +- targets/ARCH/EXMIMO/DRIVER/eurecom/extern.h | 2 +- targets/ARCH/EXMIMO/DRIVER/eurecom/fileops.c | 2 +- targets/ARCH/EXMIMO/DRIVER/eurecom/irq.c | 2 +- .../ARCH/EXMIMO/DRIVER/eurecom/module_main.c | 2 +- targets/ARCH/EXMIMO/DRIVER/eurecom/vars.h | 2 +- targets/ARCH/EXMIMO/DRIVER/exmimo3/defs.h | 2 +- .../ARCH/EXMIMO/DRIVER/exmimo3/exmimo_fw.c | 2 +- targets/ARCH/EXMIMO/DRIVER/exmimo3/extern.h | 2 +- targets/ARCH/EXMIMO/DRIVER/exmimo3/fileops.c | 2 +- targets/ARCH/EXMIMO/DRIVER/exmimo3/irq.c | 2 +- .../ARCH/EXMIMO/DRIVER/exmimo3/module_main.c | 2 +- targets/ARCH/EXMIMO/DRIVER/exmimo3/vars.h | 2 +- .../EXMIMO/DRIVER/telecomparistech/em1_dev.c | 2 +- .../EXMIMO/DRIVER/telecomparistech/em1_drv.c | 2 +- .../EXMIMO/DRIVER/telecomparistech/em1_drv.h | 2 +- .../DRIVER/telecomparistech/em1_fifos.c | 2 +- .../DRIVER/telecomparistech/em1_ioctl.c | 2 +- .../EXMIMO/DRIVER/telecomparistech/em1_mmap.c | 2 +- .../EXMIMO/DRIVER/telecomparistech/em1_rw.c | 2 +- targets/ARCH/EXMIMO/USERSPACE/LIB/example.c | 2 +- .../ARCH/EXMIMO/USERSPACE/LIB/gain_control.c | 2 +- .../ARCH/EXMIMO/USERSPACE/LIB/gain_control.h | 2 +- .../ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c | 2 +- .../ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.h | 2 +- .../EXMIMO/USERSPACE/OAI_FW_INIT/updatefw.c | 2 +- .../EXMIMO/USERSPACE/OAI_FW_INIT/updatefw.h | 2 +- .../ARCH/EXMIMO/USERSPACE/OCTAVE/gpib_send.cc | 2 +- targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf.h | 2 +- .../USERSPACE/OCTAVE/oarf_config_exmimo.cc | 2 +- .../EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc | 2 +- .../OCTAVE/oarf_get_num_detected_cards.cc | 2 +- .../USERSPACE/OCTAVE/oarf_send_frame.cc | 2 +- .../ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_stop.cc | 2 +- .../OCTAVE/oarf_stop_without_reset.cc | 2 +- targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp | 2 +- .../ARCH/LMSSDR/USERSPACE/LIB/sodera_lib.cpp | 2 +- targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp | 2 +- targets/ARCH/mobipass/interface.c | 2 +- targets/ARCH/mobipass/mobipass.c | 2 +- targets/ARCH/mobipass/mobipass.h | 2 +- targets/ARCH/mobipass/queues.c | 2 +- targets/ARCH/mobipass/queues.h | 2 +- targets/COMMON/create_tasks.c | 2 +- targets/COMMON/create_tasks.h | 2 +- targets/PROJECTS/E-MBMS/build_all.bash | 2 +- targets/PROJECTS/E-MBMS/start_enb.bash | 2 +- targets/PROJECTS/E-MBMS/start_ue.bash | 2 +- targets/PROJECTS/E-MBMS/utils.bash | 2 +- .../PROJECTS/GENERIC-LTE-EPC/interfaces.bash | 2 +- .../PROJECTS/GENERIC-LTE-EPC/networks.bash | 2 +- .../start_enb_and_ue_virt.bash | 2 +- .../PROJECTS/GENERIC-LTE-EPC/start_ue.bash | 2 +- targets/PROJECTS/GENERIC-LTE-EPC/utils.bash | 2 +- .../PROJECTS/GENERIC-LTE-EPC/virtual_box.bash | 2 +- targets/RT/USER/TOOLS/thread_ipc.c | 2 +- targets/RT/USER/TOOLS/thread_ipc.h | 2 +- targets/RT/USER/UE_transport_IQ.c | 2 +- targets/RT/USER/condtest.c | 2 +- targets/RT/USER/eNB_transport_IQ.c | 2 +- targets/RT/USER/emos-raw.c | 2 +- targets/RT/USER/lte-enb.c | 2 +- targets/RT/USER/lte-softmodem.c | 2 +- targets/RT/USER/lte-ue.c | 2 +- targets/RT/USER/msg_helper.c | 2 +- targets/RT/USER/msg_many.c | 2 +- targets/RT/USER/msg_many.h | 2 +- targets/RT/USER/rrh.c | 2 +- targets/RT/USER/rrh_gw.c | 2 +- targets/RT/USER/rrh_gw.h | 2 +- targets/RT/USER/rrh_gw_externs.h | 2 +- targets/RT/USER/rt_wrapper.c | 2 +- targets/RT/USER/rt_wrapper.h | 2 +- targets/RT/USER/sleeptest.c | 2 +- targets/RT/USER/stats.c | 2 +- targets/RT/USER/stats.h | 2 +- targets/RT/USER/synctest.c | 2 +- .../install_asn1c_0.9.24.modified.bash | 2 +- targets/SIMU/PROC/Process.c | 2 +- targets/SIMU/PROC/Process.h | 2 +- targets/SIMU/PROC/Tsync.h | 2 +- targets/SIMU/PROC/channel_sim_proc.c | 2 +- targets/SIMU/PROC/channel_sim_proc.h | 2 +- targets/SIMU/PROC/interface.h | 2 +- targets/SIMU/USER/channel_sim.c | 2 +- targets/SIMU/USER/cor_SF_sim.c | 2 +- targets/SIMU/USER/cor_SF_sim.h | 2 +- targets/SIMU/USER/event_handler.c | 2 +- targets/SIMU/USER/event_handler.h | 2 +- targets/SIMU/USER/init_lte.c | 2 +- targets/SIMU/USER/init_lte.h | 2 +- targets/SIMU/USER/oaisim.c | 2 +- targets/SIMU/USER/oaisim.h | 2 +- targets/SIMU/USER/oaisim_config.c | 2 +- targets/SIMU/USER/oaisim_config.h | 2 +- targets/SIMU/USER/oaisim_functions.c | 2 +- targets/SIMU/USER/oaisim_functions.h | 2 +- targets/SIMU/USER/oaisim_pad.c | 2 +- targets/SIMU/USER/phy_procedures_sim_form.c | 2 +- targets/SIMU/USER/phy_procedures_sim_form.h | 2 +- targets/SIMU/USER/sinr_sim.c | 2 +- targets/TEST/AT_COMMANDS/oaisim.c | 2 +- targets/TEST/OAI/case01.py | 2 +- targets/TEST/OAI/case02.py | 2 +- targets/TEST/OAI/case03.py | 2 +- targets/TEST/OAI/case04.py | 2 +- targets/TEST/OAI/case05.py | 2 +- targets/TEST/OAI/case11.py | 2 +- targets/TEST/OAI/case12.py | 2 +- targets/TEST/OAI/case13.py | 2 +- targets/TEST/OAI/core.py | 2 +- targets/TEST/OAI/log.py | 2 +- targets/TEST/OAI/openair.py | 2 +- targets/TEST/OAI/test01.py | 2 +- targets/TEST/OAI/test02.py | 2 +- targets/TEST/PACKET_TRACER/pt.c | 2 +- targets/TEST/PDCP/readme.txt | 2 +- targets/TEST/PDCP/test_pdcp.c | 2 +- targets/TEST/PDCP/test_pdcp.h | 2 +- targets/TEST/PDCP/test_util.h | 2 +- targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c | 2 +- targets/TEST/RLC_AM_V9.3.0/oaisim.c | 2 +- targets/TEST/RLC_UM_V9.3.0/oaisim.c | 2 +- .../TEST/ROHDE_SCHWARZ/EthernetRawCommand.cpp | 2 +- targets/TEST/ROHDE_SCHWARZ/TcpClient.cpp | 2 +- targets/TEST/ROHDE_SCHWARZ/TcpClient.h | 2 +- targets/build_helper.bash | 2 +- targets/build_oai.bash | 2 +- targets/perf_oai.bash | 2 +- 1490 files changed, 1646 insertions(+), 1540 deletions(-) diff --git a/LICENSE b/LICENSE index 05b42e7c30..44a9a405fb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,94 +1,200 @@ - OAI PUBLIC LICENSE V1.0 + The OpenAirInterface Software Alliance (OSA) + OAI Public License (Version 1.1) - Copyright (C) 2016 OpenAirInterface Software Alliance, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. +LICENSE TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION OF OPENAIR 5G SOFTWARE. -Definitions. -“License” shall mean the terms and conditions for use, reproduction, and distribution set forth in this document. +1. Definitions. + +“License” shall mean the terms and conditions for use, reproduction, and distribution set forth +in this document. “Licensor” shall mean the OpenAirInterface Software Alliance. -“Legal Entity” shall mean the union, at the time an acting entity joins the Alliance, of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, “control” means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. +“Legal Entity” shall mean the union, at the time an acting entity joins the Alliance, of the +acting entity and all other entities that control, are controlled by, or are under common control +with that entity. For the purposes of this definition, “control” means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) +beneficial ownership of such entity. -“You” (or “Your”) shall mean an individual or Legal Entity exercising permissions granted by this License. +“You” (or “Your”) shall mean an individual or Legal Entity exercising permissions granted by +this License. -“Source” form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. +“Source” form shall mean the preferred form for making modifications, including but not +limited to software source code, documentation source, and configuration files. -“Object” form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. +“Object” form shall mean any form resulting from mechanical transformation or translation of +a Source form, including but not limited to compiled object code, generated documentation, +and conversions to other media types. -“OpenAirInterface Software Alliance” shall mean the endowment fund established at the initiative of Eurecom, an educational and research establishment located at Campus Sophia Tech, 450 Route des Chappes, 06410 Biot, France, which statutes were signed on 18 November 2014. +“OpenAirInterface Software Alliance” shall mean the endowment fund established at the +initiative of Eurecom, an educational and research establishment located at Campus Sophia +Tech, 450 Route des Chappes, 06410 Biot, France, which statutes were signed on 18 +November 2014. -“ “Work” shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). +“Work” shall mean the work of authorship, whether in Source or Object form, made available +under the License, as indicated by a copyright notice that is included in or attached to the +work (an example is provided in the Appendix below). -“Derivative Works” shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. +“Derivative Works” shall mean any work, whether in Source or Object form, that is based on +(or derived from) the Work and for which the editorial revisions, annotations, elaborations, or +other modifications represent, as a whole, an original work of authorship. For the purposes of +this License, Derivative Works shall not include works that remain separable from, or merely +link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. -“Contribution” shall mean any work of authorship that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, “submitted” means any form of electronic, , or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work “Contributor License Agreement” shall mean the agreement signed by any Contributor setting forth the terms and conditions applicable to its Contribution. “Contributor” shall mean any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. +“Contribution” shall mean any work of authorship that is intentionally submitted to Licensor +for inclusion in the Work by the copyright owner or by an individual or Legal Entity +authorized to submit on behalf of the copyright owner. For the purposes of this definition, +“submitted” means any form of electronic, , or written communication sent to the Licensor or +its representatives, including but not limited to communication on electronic mailing lists, +source code control systems, and issue tracking systems that are managed by, or on behalf of, +the Licensor for the purpose of discussing and improving the Work -Grant of Copyright License. -Subject to the terms and conditions of this License, Licensor and each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form +“Contributor License Agreement” shall mean the agreement signed by any Contributor setting +forth the terms and conditions applicable to its Contribution. -3. Grant of Patent License. +“Contributor” shall mean any individual or Legal Entity on behalf of whom a Contribution +has been received by Licensor and subsequently incorporated within the Work. -3.1 Grant of Patent License for non-commercial purposes: +2. Grant of Copyright License. +Subject to the terms and conditions of this License, Licensor and each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, publicly display, publicly +perform, and distribute the Work and such Derivative Works in Source or Object form -Subject to the terms and conditions of this License, Licensor and each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, import, and otherwise transfer the Work, for non-commercial purposes, where such license applies only to those patent claims licensable by such Contributor or Licensor that are necessarily infringed by the Work and/or their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. +3. Grant of Patent License. -3.2 Grant of Patent License for commercial purposes: +3.1 Grant of Patent License for study, testing and research purposes: +Subject to the terms and conditions of this License, Licensor and each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, use, and otherwise +transfer (excluding selling) the Work, solely for study, testing and research purposes, where +such license applies only to those patent claims licensable by Licensor or such Contributor +that are necessarily infringed respectively by the Work and/or the said Contributor +Contribution(s) alone or by combination of their Contribution(s) with the Work to which +such Contribution(s) was submitted (“Essential Patents”). -For commercial purposes, and subject to the terms and conditions of this License, You commits to be prepared to negotiate a patent license with each Contributor and/or the Licensor on Fair, Reasonable and Non-Discriminatory (“FRAND”) terms and conditions for the Work or Contribution(s) incorporated within the Work. - -Licensor and/or each Contributor, by submitting a Contribution, will identify any patent it owns related to the Work and/or its Contribution. +3.2 Grant of Patent License for purposes other than study and research: +For purposes other than study, testing and research, and subject to the terms and conditions of +this License, You commit to be prepared to negotiate a non-exclusive, non-transferable, non- +assignable license of Essential Patents with each Contributor and/or the Licensor on Fair, +Reasonable and Non-Discriminatory (“FRAND”) terms and conditions for the use of the +Work or Contribution(s) incorporated within the Work. +Licensor and/or each Contributor, by submitting a Contribution, will identify any of its known +Essential Patent it owns related to the Work and/or its Contribution. 3.3 Patent Litigation +If You institute patent litigation against any entity making use of the Work solely for study, +testing and research purposes (including a cross-claim or counterclaim in a lawsuit) alleging +that the Work or a Contribution incorporated within the Work constitutes direct or +contributory patent infringement, then the patent licenses granted to You under section 3.1 of +this License for that Work shall terminate as of the date such litigation is filed. -If You institute patent litigation against any entity making non-commercial use of the Work (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. +4. Sublicensing +You may grant sublicenses under the licenses granted under sections 2 and 3.1 provided that +the sublicense is subject to and inclusive of all the terms of and rights under this License to +which the Work is or was distributed by the OpenAirInterface Software Alliance. -4. Redistibution +5. Redistribution +Subject to terms and conditions set forth in sections 2 and 3, You may reproduce and +distribute copies of the Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You meet the following +conditions: -Subject to terms and conditions set forth in articles 2 and 3, You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +1. You must give any other recipients of the Work or Derivative Works a copy of this +License; and +2. You must cause any modified files by You to carry prominent notices stating that You +changed the files; and +3. You must retain, in the Source form of any Derivative Works that You distribute, all +copyright, patent, trademark, and attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of the Derivative Works; and +4. If the Work includes a “NOTICE” text file as part of its distribution, then any Derivative +Works that You distribute must include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not pertain to any part of the +Derivative Works, in at least one of the following places: within a NOTICE text file +distributed as part of the Derivative Works; within the Source form or documentation, if +provided along with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of the +NOTICE file are for informational purposes only and do not modify the License. You may +add Your own attribution notices within Derivative Works that You distribute, alongside or as +an addendum to the NOTICE text from the Work, provided that such additional attribution +notices cannot be construed as modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or distribution of +Your modifications, or for any such Derivative Works as a whole, provided Your use, +reproduction, and distribution of the Work otherwise complies with the conditions stated in +this License. -1. You must give any other recipients of the Work or Derivative Works a copy of this License; and +6. Submission of Contributions. +Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be +under the terms and conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of any +separate license agreement such as the Contributor License Agreement You may have +executed with Licensor regarding such Contributions. -2. You must cause any modified files by You to carry prominent notices stating that You changed the files; and +7. Trademarks. +This License does not grant permission to use the trade names, trademarks, service marks, or +product names of the Licensor, except as required for reasonable and customary use in +describing the origin of the Work and reproducing the content of the NOTICE file. -3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +8. Disclaimer of Warranty. +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and +each Contributor provides its Contributions) on an “AS IS” BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, +without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, +MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely +responsible for determining the appropriateness of using or redistributing the Work and +assume any risks associated with your exercise of permissions under this License. -4. If the Work includes a “NOTICE” text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. +9. Limitation of Liability. +In no event and under no legal theory, whether in tort (including negligence), contract, or +otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or +agreed to in writing, shall Licensor and any Contributor, as such, be liable to You for +damages, including any direct, indirect, special, incidental, or consequential damages of any +character arising as a result of this License or out of Your use or inability to use the Work +(including but not limited to damages for loss of goodwill, work stoppage, computer failure or +malfunction, or any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. +10. Accepting Warranty or Additional Liability. +While redistributing the Work or Derivative Works thereof, You may choose to offer, and +charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations +and/or rights consistent with this License. However, in accepting such obligations, You may +act only on Your own behalf and on Your sole responsibility, not on behalf of any other +Contributor and/or the Licensor, and only if You agree to indemnify, defend, and hold each +Contributor and/or the Licensor harmless for any liability incurred by, or claims asserted +against, such Contributor and/or Licensor by reason of Your accepting any such warranty or +additional liability. -You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement such as the Contributor License Agreement You may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall Licensor and any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor and/or the Licensor,and only if You agree to indemnify, defend, and hold each Contributor and/or the Licensor harmless for any liability incurred by, or claims asserted against, such Contributor and/or Licensor by reason of Your accepting any such warranty or additional liability. - -10. Applicable law. The present license shall be governed by the laws of France. +11. Applicable law. +The present license shall be governed by the laws of France. END OF TERMS AND CONDITIONS -APPENDIX: How to apply the PRESENT OPENAIR 5G License to your work -To apply the present License to your work, attach the following boilerplate notice, with the fields enclosed by brackets “[]” replaced with your own identifying information. (Don’t include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same “printed page” as the copyright notice for easier identification within third-party archives. +1. APPENDIX: How to apply the PRESENT OPENAIR 5G License to your work +To apply the present License to your work, attach the following boilerplate notice, with the +fields enclosed by brackets “[]” replaced with your own identifying information. (Don’t +include the brackets!) The text should be enclosed in the appropriate comment syntax for the +file format. We also recommend that a file or class name and description of purpose be +included on the same “printed page” as the copyright notice for easier identification within +third-party archives. Copyright [yyyy] [name of copyright owner] -Licensed under the License terms and conditions for use, reproduction, and distribution of OPENAIR 5G software (the “License”); -you may not use this file except in compliance with the License.You may obtain a copy of the License at -Unless required by applicable law or agreed to in writing, software +Licensed under the License terms and conditions for use, reproduction, and distribution of +OPENAIR 5G software (the “License”); -distributed under the License is distributed on an “AS IS” BASIS, +you may not use this file except in compliance with the License. You may obtain a copy of +the License at + +Unless required by applicable law or agreed to in writing, software distributed under the +License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and +See the License for the specific language governing permissions and limitations under the +License. -limitations under the License. diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 50415c18bc..a8d1e8dc85 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/at_commands/CMakeLists.txt b/cmake_targets/at_commands/CMakeLists.txt index db49a9181d..54f369f977 100755 --- a/cmake_targets/at_commands/CMakeLists.txt +++ b/cmake_targets/at_commands/CMakeLists.txt @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/core.py b/cmake_targets/autotests/core.py index 2665e57372..09785df120 100644 --- a/cmake_targets/autotests/core.py +++ b/cmake_targets/autotests/core.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/log.py b/cmake_targets/autotests/log.py index 25eb2b5ffb..5a97b19cf2 100644 --- a/cmake_targets/autotests/log.py +++ b/cmake_targets/autotests/log.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/openair.py b/cmake_targets/autotests/openair.py index 7ad118ef1b..beb12cd2a2 100644 --- a/cmake_targets/autotests/openair.py +++ b/cmake_targets/autotests/openair.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/run_compilation_autotests.bash b/cmake_targets/autotests/run_compilation_autotests.bash index a6a861cb60..10e4caa04b 100755 --- a/cmake_targets/autotests/run_compilation_autotests.bash +++ b/cmake_targets/autotests/run_compilation_autotests.bash @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/run_exec_autotests.bash b/cmake_targets/autotests/run_exec_autotests.bash index 5551ede44d..ff38ae9d3c 100755 --- a/cmake_targets/autotests/run_exec_autotests.bash +++ b/cmake_targets/autotests/run_exec_autotests.bash @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/run_exec_lte-softmodem_tests.py b/cmake_targets/autotests/run_exec_lte-softmodem_tests.py index 9f08a00d1a..65bcfd5af8 100755 --- a/cmake_targets/autotests/run_exec_lte-softmodem_tests.py +++ b/cmake_targets/autotests/run_exec_lte-softmodem_tests.py @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py b/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py index f03facc7da..ee4f3f93bc 100755 --- a/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py +++ b/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/tools/configure_cots_huaweiE398_ue.py b/cmake_targets/autotests/tools/configure_cots_huaweiE398_ue.py index 52178a32a1..42e4b2ea9a 100755 --- a/cmake_targets/autotests/tools/configure_cots_huaweiE398_ue.py +++ b/cmake_targets/autotests/tools/configure_cots_huaweiE398_ue.py @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py b/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py index 42ed5fdeba..8c2c1dd7f2 100755 --- a/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py +++ b/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/tools/configure_usrpb210.py b/cmake_targets/autotests/tools/configure_usrpb210.py index 860a717d72..588bde9d33 100755 --- a/cmake_targets/autotests/tools/configure_usrpb210.py +++ b/cmake_targets/autotests/tools/configure_usrpb210.py @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/tools/find_usb_path.bash b/cmake_targets/autotests/tools/find_usb_path.bash index c115d7a9dc..91156012b7 100755 --- a/cmake_targets/autotests/tools/find_usb_path.bash +++ b/cmake_targets/autotests/tools/find_usb_path.bash @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/tools/free_mem.bash b/cmake_targets/autotests/tools/free_mem.bash index 8196bf3428..a5b2b00cb6 100755 --- a/cmake_targets/autotests/tools/free_mem.bash +++ b/cmake_targets/autotests/tools/free_mem.bash @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/tools/git-retry.sh b/cmake_targets/autotests/tools/git-retry.sh index 9f4d96af8d..f0366b2ae5 100755 --- a/cmake_targets/autotests/tools/git-retry.sh +++ b/cmake_targets/autotests/tools/git-retry.sh @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/tools/iperf3_script b/cmake_targets/autotests/tools/iperf3_script index bf506bbc65..93aa742bd3 100755 --- a/cmake_targets/autotests/tools/iperf3_script +++ b/cmake_targets/autotests/tools/iperf3_script @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/tools/iperf3_script_phone b/cmake_targets/autotests/tools/iperf3_script_phone index e4ccc38237..1d9e9322a1 100755 --- a/cmake_targets/autotests/tools/iperf3_script_phone +++ b/cmake_targets/autotests/tools/iperf3_script_phone @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/tools/iperf_script b/cmake_targets/autotests/tools/iperf_script index 28f239af09..d74462cbcc 100755 --- a/cmake_targets/autotests/tools/iperf_script +++ b/cmake_targets/autotests/tools/iperf_script @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/tools/iperf_script_phone b/cmake_targets/autotests/tools/iperf_script_phone index 0195ee9eb3..29c670f826 100755 --- a/cmake_targets/autotests/tools/iperf_script_phone +++ b/cmake_targets/autotests/tools/iperf_script_phone @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/tools/lib_autotest.py b/cmake_targets/autotests/tools/lib_autotest.py index 2e9a7df11f..54be808e1d 100644 --- a/cmake_targets/autotests/tools/lib_autotest.py +++ b/cmake_targets/autotests/tools/lib_autotest.py @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/tools/run_gdb b/cmake_targets/autotests/tools/run_gdb index 9dea2d350c..ace8e7a296 100755 --- a/cmake_targets/autotests/tools/run_gdb +++ b/cmake_targets/autotests/tools/run_gdb @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/autotests/tools/search_repl.py b/cmake_targets/autotests/tools/search_repl.py index c3e73ccde4..f34533cfd0 100755 --- a/cmake_targets/autotests/tools/search_repl.py +++ b/cmake_targets/autotests/tools/search_repl.py @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 267a370196..2e94c31837 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/tools/asn1tostruct.py b/cmake_targets/tools/asn1tostruct.py index e8ebb03d6d..8c0f7e8a16 100644 --- a/cmake_targets/tools/asn1tostruct.py +++ b/cmake_targets/tools/asn1tostruct.py @@ -38,7 +38,7 @@ def outputHeaderToFile(f, filename): * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index f6c51944d2..8cf0d22e91 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/tools/build_test_epc_tools b/cmake_targets/tools/build_test_epc_tools index f9d8057c93..dc2d016545 100755 --- a/cmake_targets/tools/build_test_epc_tools +++ b/cmake_targets/tools/build_test_epc_tools @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/tools/example_enb_exmimo_mme_hss.txt b/cmake_targets/tools/example_enb_exmimo_mme_hss.txt index 546ae1ba86..238554f8e2 100644 --- a/cmake_targets/tools/example_enb_exmimo_mme_hss.txt +++ b/cmake_targets/tools/example_enb_exmimo_mme_hss.txt @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/tools/example_oaisim_enb_ue_mme_virtual.txt b/cmake_targets/tools/example_oaisim_enb_ue_mme_virtual.txt index baccdbc288..9996a53e19 100644 --- a/cmake_targets/tools/example_oaisim_enb_ue_mme_virtual.txt +++ b/cmake_targets/tools/example_oaisim_enb_ue_mme_virtual.txt @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/tools/indent_source_code b/cmake_targets/tools/indent_source_code index 17a29fb073..a16914a91d 100755 --- a/cmake_targets/tools/indent_source_code +++ b/cmake_targets/tools/indent_source_code @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/tools/init_exmimo2 b/cmake_targets/tools/init_exmimo2 index 1ed65cf0e0..8e902a8433 100755 --- a/cmake_targets/tools/init_exmimo2 +++ b/cmake_targets/tools/init_exmimo2 @@ -5,7 +5,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/tools/init_nas_nos1 b/cmake_targets/tools/init_nas_nos1 index 3aaf547823..9bcaa0afb5 100755 --- a/cmake_targets/tools/init_nas_nos1 +++ b/cmake_targets/tools/init_nas_nos1 @@ -5,7 +5,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/tools/init_nas_s1 b/cmake_targets/tools/init_nas_s1 index 003a3ae600..cab4ad047b 100644 --- a/cmake_targets/tools/init_nas_s1 +++ b/cmake_targets/tools/init_nas_s1 @@ -8,7 +8,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/tools/perf_oai.bash b/cmake_targets/tools/perf_oai.bash index 44d9d1c74a..cd1ef5a400 100755 --- a/cmake_targets/tools/perf_oai.bash +++ b/cmake_targets/tools/perf_oai.bash @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/tools/run_enb_s1_exmimo b/cmake_targets/tools/run_enb_s1_exmimo index 028b492341..1bb6ce4425 100755 --- a/cmake_targets/tools/run_enb_s1_exmimo +++ b/cmake_targets/tools/run_enb_s1_exmimo @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/tools/run_enb_s1_usrp b/cmake_targets/tools/run_enb_s1_usrp index 3d49fe40bd..e119126683 100755 --- a/cmake_targets/tools/run_enb_s1_usrp +++ b/cmake_targets/tools/run_enb_s1_usrp @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/tools/run_enb_ue_virt_noS1 b/cmake_targets/tools/run_enb_ue_virt_noS1 index a5139d4b44..79d5bc35dc 100755 --- a/cmake_targets/tools/run_enb_ue_virt_noS1 +++ b/cmake_targets/tools/run_enb_ue_virt_noS1 @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/tools/run_enb_ue_virt_s1 b/cmake_targets/tools/run_enb_ue_virt_s1 index 8e717f393a..50fc819ec8 100755 --- a/cmake_targets/tools/run_enb_ue_virt_s1 +++ b/cmake_targets/tools/run_enb_ue_virt_s1 @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/cmake_targets/tools/stop_exmimo2 b/cmake_targets/tools/stop_exmimo2 index 85d9bec309..fdfe19425d 100755 --- a/cmake_targets/tools/stop_exmimo2 +++ b/cmake_targets/tools/stop_exmimo2 @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/common/utils/asn1_conversions.h b/common/utils/asn1_conversions.h index 8eed4faaad..050c065d9d 100644 --- a/common/utils/asn1_conversions.h +++ b/common/utils/asn1_conversions.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/assertions.h b/common/utils/assertions.h index 18675fb8fb..f6728caf7b 100644 --- a/common/utils/assertions.h +++ b/common/utils/assertions.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/hashtable/hashtable.c b/common/utils/hashtable/hashtable.c index b82affb4a3..6322b1dea6 100644 --- a/common/utils/hashtable/hashtable.c +++ b/common/utils/hashtable/hashtable.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/hashtable/hashtable.h b/common/utils/hashtable/hashtable.h index 2fd08e6625..62002fb60f 100644 --- a/common/utils/hashtable/hashtable.h +++ b/common/utils/hashtable/hashtable.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/hashtable/obj_hashtable.c b/common/utils/hashtable/obj_hashtable.c index caae391ae2..7fb68d1681 100644 --- a/common/utils/hashtable/obj_hashtable.c +++ b/common/utils/hashtable/obj_hashtable.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/hashtable/obj_hashtable.h b/common/utils/hashtable/obj_hashtable.h index 45f97a6baa..a43d472a47 100644 --- a/common/utils/hashtable/obj_hashtable.h +++ b/common/utils/hashtable/obj_hashtable.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/assertions.h b/common/utils/itti/assertions.h index a411bd5397..bb6c27cbab 100644 --- a/common/utils/itti/assertions.h +++ b/common/utils/itti/assertions.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/backtrace.c b/common/utils/itti/backtrace.c index ed7849ab4d..889e0d84d1 100644 --- a/common/utils/itti/backtrace.c +++ b/common/utils/itti/backtrace.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/backtrace.h b/common/utils/itti/backtrace.h index 701bc0ab0e..9a77767cf4 100644 --- a/common/utils/itti/backtrace.h +++ b/common/utils/itti/backtrace.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/intertask_interface.c b/common/utils/itti/intertask_interface.c index 28267900af..ba36d49a9e 100644 --- a/common/utils/itti/intertask_interface.c +++ b/common/utils/itti/intertask_interface.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/intertask_interface.h b/common/utils/itti/intertask_interface.h index a2137c119d..191d9199c3 100644 --- a/common/utils/itti/intertask_interface.h +++ b/common/utils/itti/intertask_interface.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/intertask_interface_dump.c b/common/utils/itti/intertask_interface_dump.c index 8f08475c6a..a06b97c63b 100644 --- a/common/utils/itti/intertask_interface_dump.c +++ b/common/utils/itti/intertask_interface_dump.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/intertask_interface_dump.h b/common/utils/itti/intertask_interface_dump.h index 14b3b4dbb6..a34dcecbf6 100644 --- a/common/utils/itti/intertask_interface_dump.h +++ b/common/utils/itti/intertask_interface_dump.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/intertask_interface_init.h b/common/utils/itti/intertask_interface_init.h index df87202955..333b0653d7 100644 --- a/common/utils/itti/intertask_interface_init.h +++ b/common/utils/itti/intertask_interface_init.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/intertask_interface_types.h b/common/utils/itti/intertask_interface_types.h index d7386b0b73..af1b4e9aa9 100644 --- a/common/utils/itti/intertask_interface_types.h +++ b/common/utils/itti/intertask_interface_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/intertask_messages_def.h b/common/utils/itti/intertask_messages_def.h index d75f927a92..57c344c813 100644 --- a/common/utils/itti/intertask_messages_def.h +++ b/common/utils/itti/intertask_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/intertask_messages_types.h b/common/utils/itti/intertask_messages_types.h index 2aa8545ee0..145f57648f 100644 --- a/common/utils/itti/intertask_messages_types.h +++ b/common/utils/itti/intertask_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/itti_types.h b/common/utils/itti/itti_types.h index e5bbf44830..7f01901712 100644 --- a/common/utils/itti/itti_types.h +++ b/common/utils/itti/itti_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/memory_pools.c b/common/utils/itti/memory_pools.c index 955e29440a..23c53b71ae 100644 --- a/common/utils/itti/memory_pools.c +++ b/common/utils/itti/memory_pools.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/memory_pools.h b/common/utils/itti/memory_pools.h index 6c6e5a5d80..1c1997f7f2 100644 --- a/common/utils/itti/memory_pools.h +++ b/common/utils/itti/memory_pools.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/messages_def.h b/common/utils/itti/messages_def.h index 0366cf8f50..f312669848 100644 --- a/common/utils/itti/messages_def.h +++ b/common/utils/itti/messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/messages_types.h b/common/utils/itti/messages_types.h index 0fbdf29ecc..d390bf0159 100644 --- a/common/utils/itti/messages_types.h +++ b/common/utils/itti/messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/signals.c b/common/utils/itti/signals.c index e495e301f8..9767ba3f67 100644 --- a/common/utils/itti/signals.c +++ b/common/utils/itti/signals.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/signals.h b/common/utils/itti/signals.h index efb25f34d8..5277e216a3 100644 --- a/common/utils/itti/signals.h +++ b/common/utils/itti/signals.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/tasks_def.h b/common/utils/itti/tasks_def.h index 18ac6ac5c9..d54d09a26a 100644 --- a/common/utils/itti/tasks_def.h +++ b/common/utils/itti/tasks_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/timer.c b/common/utils/itti/timer.c index c180cfcda4..6327aeacfb 100644 --- a/common/utils/itti/timer.c +++ b/common/utils/itti/timer.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/timer.h b/common/utils/itti/timer.h index 22d1d75d46..4f568a348c 100644 --- a/common/utils/itti/timer.h +++ b/common/utils/itti/timer.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/timer_messages_def.h b/common/utils/itti/timer_messages_def.h index 4cef672c13..761034730d 100644 --- a/common/utils/itti/timer_messages_def.h +++ b/common/utils/itti/timer_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti/timer_messages_types.h b/common/utils/itti/timer_messages_types.h index 4abf34605d..0d06e3eebf 100644 --- a/common/utils/itti/timer_messages_types.h +++ b/common/utils/itti/timer_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/common/itti_types.h b/common/utils/itti_analyzer/common/itti_types.h index a423458349..d405e48cbd 100644 --- a/common/utils/itti_analyzer/common/itti_types.h +++ b/common/utils/itti_analyzer/common/itti_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/common/logs.h b/common/utils/itti_analyzer/common/logs.h index 8d5c4876ff..bd901cc394 100644 --- a/common/utils/itti_analyzer/common/logs.h +++ b/common/utils/itti_analyzer/common/logs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/common/rc.h b/common/utils/itti_analyzer/common/rc.h index 9643d712eb..50786f460f 100644 --- a/common/utils/itti_analyzer/common/rc.h +++ b/common/utils/itti_analyzer/common/rc.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/itti_analyzer.c b/common/utils/itti_analyzer/itti_analyzer.c index e19b375798..d87deb46e2 100644 --- a/common/utils/itti_analyzer/itti_analyzer.c +++ b/common/utils/itti_analyzer/itti_analyzer.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libbuffers/buffers.c b/common/utils/itti_analyzer/libbuffers/buffers.c index a2d526d584..870c9cd40a 100644 --- a/common/utils/itti_analyzer/libbuffers/buffers.c +++ b/common/utils/itti_analyzer/libbuffers/buffers.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libbuffers/buffers.h b/common/utils/itti_analyzer/libbuffers/buffers.h index 7dd59b8067..34ecb355ab 100644 --- a/common/utils/itti_analyzer/libbuffers/buffers.h +++ b/common/utils/itti_analyzer/libbuffers/buffers.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libbuffers/file.c b/common/utils/itti_analyzer/libbuffers/file.c index ea429a66d1..291bf2d216 100644 --- a/common/utils/itti_analyzer/libbuffers/file.c +++ b/common/utils/itti_analyzer/libbuffers/file.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libbuffers/file.h b/common/utils/itti_analyzer/libbuffers/file.h index 36912a69ba..be0fa6ba2d 100644 --- a/common/utils/itti_analyzer/libbuffers/file.h +++ b/common/utils/itti_analyzer/libbuffers/file.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libbuffers/socket.c b/common/utils/itti_analyzer/libbuffers/socket.c index 0e1ad49e49..f732af70ec 100644 --- a/common/utils/itti_analyzer/libbuffers/socket.c +++ b/common/utils/itti_analyzer/libbuffers/socket.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libbuffers/socket.h b/common/utils/itti_analyzer/libbuffers/socket.h index d64fd46b91..8c2be2243e 100644 --- a/common/utils/itti_analyzer/libbuffers/socket.h +++ b/common/utils/itti_analyzer/libbuffers/socket.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/array_type.c b/common/utils/itti_analyzer/libparser/array_type.c index 028835e9d2..1d9f741281 100644 --- a/common/utils/itti_analyzer/libparser/array_type.c +++ b/common/utils/itti_analyzer/libparser/array_type.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/array_type.h b/common/utils/itti_analyzer/libparser/array_type.h index 9e13dec282..b336934dbb 100644 --- a/common/utils/itti_analyzer/libparser/array_type.h +++ b/common/utils/itti_analyzer/libparser/array_type.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/enum_type.c b/common/utils/itti_analyzer/libparser/enum_type.c index a00f654556..dbc99095bc 100644 --- a/common/utils/itti_analyzer/libparser/enum_type.c +++ b/common/utils/itti_analyzer/libparser/enum_type.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/enum_type.h b/common/utils/itti_analyzer/libparser/enum_type.h index 9faa21b79a..4538829e78 100644 --- a/common/utils/itti_analyzer/libparser/enum_type.h +++ b/common/utils/itti_analyzer/libparser/enum_type.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/enum_value_type.c b/common/utils/itti_analyzer/libparser/enum_value_type.c index 8035acb257..801317daaf 100644 --- a/common/utils/itti_analyzer/libparser/enum_value_type.c +++ b/common/utils/itti_analyzer/libparser/enum_value_type.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/enum_value_type.h b/common/utils/itti_analyzer/libparser/enum_value_type.h index d30e3a6706..997e6cc3fe 100644 --- a/common/utils/itti_analyzer/libparser/enum_value_type.h +++ b/common/utils/itti_analyzer/libparser/enum_value_type.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/field_type.c b/common/utils/itti_analyzer/libparser/field_type.c index 9415ad0eff..b64d3bd0c1 100644 --- a/common/utils/itti_analyzer/libparser/field_type.c +++ b/common/utils/itti_analyzer/libparser/field_type.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/field_type.h b/common/utils/itti_analyzer/libparser/field_type.h index f9bdd78cb7..329e90c3be 100644 --- a/common/utils/itti_analyzer/libparser/field_type.h +++ b/common/utils/itti_analyzer/libparser/field_type.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/file_type.c b/common/utils/itti_analyzer/libparser/file_type.c index 3e9bf697a6..04d66b7a08 100644 --- a/common/utils/itti_analyzer/libparser/file_type.c +++ b/common/utils/itti_analyzer/libparser/file_type.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/file_type.h b/common/utils/itti_analyzer/libparser/file_type.h index 7142f30d51..34ebea6745 100644 --- a/common/utils/itti_analyzer/libparser/file_type.h +++ b/common/utils/itti_analyzer/libparser/file_type.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/fundamental_type.c b/common/utils/itti_analyzer/libparser/fundamental_type.c index 9383431c84..92dd1c75cb 100644 --- a/common/utils/itti_analyzer/libparser/fundamental_type.c +++ b/common/utils/itti_analyzer/libparser/fundamental_type.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/fundamental_type.h b/common/utils/itti_analyzer/libparser/fundamental_type.h index 94e939e117..07ceb3b9ed 100644 --- a/common/utils/itti_analyzer/libparser/fundamental_type.h +++ b/common/utils/itti_analyzer/libparser/fundamental_type.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/intertask_contexts.h b/common/utils/itti_analyzer/libparser/intertask_contexts.h index a490064612..cfe8f59402 100644 --- a/common/utils/itti_analyzer/libparser/intertask_contexts.h +++ b/common/utils/itti_analyzer/libparser/intertask_contexts.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/pointer_type.c b/common/utils/itti_analyzer/libparser/pointer_type.c index 8b263f64a9..e4571f9f48 100644 --- a/common/utils/itti_analyzer/libparser/pointer_type.c +++ b/common/utils/itti_analyzer/libparser/pointer_type.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/pointer_type.h b/common/utils/itti_analyzer/libparser/pointer_type.h index 6f4f644e73..be2b6cc33c 100644 --- a/common/utils/itti_analyzer/libparser/pointer_type.h +++ b/common/utils/itti_analyzer/libparser/pointer_type.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/reference_type.c b/common/utils/itti_analyzer/libparser/reference_type.c index 7cd3b0a509..8d0fec4e61 100644 --- a/common/utils/itti_analyzer/libparser/reference_type.c +++ b/common/utils/itti_analyzer/libparser/reference_type.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/reference_type.h b/common/utils/itti_analyzer/libparser/reference_type.h index 5f9d0a0b88..da56e9f942 100644 --- a/common/utils/itti_analyzer/libparser/reference_type.h +++ b/common/utils/itti_analyzer/libparser/reference_type.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/struct_type.c b/common/utils/itti_analyzer/libparser/struct_type.c index 758851269d..09d5280ea5 100644 --- a/common/utils/itti_analyzer/libparser/struct_type.c +++ b/common/utils/itti_analyzer/libparser/struct_type.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/struct_type.h b/common/utils/itti_analyzer/libparser/struct_type.h index 1efa4ef324..29d4113b6f 100644 --- a/common/utils/itti_analyzer/libparser/struct_type.h +++ b/common/utils/itti_analyzer/libparser/struct_type.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/typedef_type.c b/common/utils/itti_analyzer/libparser/typedef_type.c index 6c7246b47c..e5cee1a1cf 100644 --- a/common/utils/itti_analyzer/libparser/typedef_type.c +++ b/common/utils/itti_analyzer/libparser/typedef_type.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/typedef_type.h b/common/utils/itti_analyzer/libparser/typedef_type.h index cad3436a63..b5710dbfcb 100644 --- a/common/utils/itti_analyzer/libparser/typedef_type.h +++ b/common/utils/itti_analyzer/libparser/typedef_type.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/types.c b/common/utils/itti_analyzer/libparser/types.c index 6f36089a7b..406db5249c 100644 --- a/common/utils/itti_analyzer/libparser/types.c +++ b/common/utils/itti_analyzer/libparser/types.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/types.h b/common/utils/itti_analyzer/libparser/types.h index 0f7812b84b..c449c445fd 100644 --- a/common/utils/itti_analyzer/libparser/types.h +++ b/common/utils/itti_analyzer/libparser/types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/union_type.c b/common/utils/itti_analyzer/libparser/union_type.c index f2518685c6..f38b7a1ccc 100644 --- a/common/utils/itti_analyzer/libparser/union_type.c +++ b/common/utils/itti_analyzer/libparser/union_type.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/union_type.h b/common/utils/itti_analyzer/libparser/union_type.h index e4552bf770..ed2dca73ba 100644 --- a/common/utils/itti_analyzer/libparser/union_type.h +++ b/common/utils/itti_analyzer/libparser/union_type.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/xml_parse.c b/common/utils/itti_analyzer/libparser/xml_parse.c index 651fcde2f7..352b10d616 100644 --- a/common/utils/itti_analyzer/libparser/xml_parse.c +++ b/common/utils/itti_analyzer/libparser/xml_parse.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libparser/xml_parse.h b/common/utils/itti_analyzer/libparser/xml_parse.h index 968fb96b68..f9624bc06b 100644 --- a/common/utils/itti_analyzer/libparser/xml_parse.h +++ b/common/utils/itti_analyzer/libparser/xml_parse.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libresolver/locate_root.c b/common/utils/itti_analyzer/libresolver/locate_root.c index f78674108c..dffd489944 100644 --- a/common/utils/itti_analyzer/libresolver/locate_root.c +++ b/common/utils/itti_analyzer/libresolver/locate_root.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libresolver/locate_root.h b/common/utils/itti_analyzer/libresolver/locate_root.h index 0e952d8f59..5cb2eb2588 100644 --- a/common/utils/itti_analyzer/libresolver/locate_root.h +++ b/common/utils/itti_analyzer/libresolver/locate_root.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libresolver/resolvers.c b/common/utils/itti_analyzer/libresolver/resolvers.c index 856a212396..8702c08942 100644 --- a/common/utils/itti_analyzer/libresolver/resolvers.c +++ b/common/utils/itti_analyzer/libresolver/resolvers.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libresolver/resolvers.h b/common/utils/itti_analyzer/libresolver/resolvers.h index 4d8a5c08d1..17e16462b4 100644 --- a/common/utils/itti_analyzer/libresolver/resolvers.h +++ b/common/utils/itti_analyzer/libresolver/resolvers.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_callbacks.c b/common/utils/itti_analyzer/libui/ui_callbacks.c index 3dd4218abc..6fc480e333 100644 --- a/common/utils/itti_analyzer/libui/ui_callbacks.c +++ b/common/utils/itti_analyzer/libui/ui_callbacks.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_callbacks.h b/common/utils/itti_analyzer/libui/ui_callbacks.h index e09abdbc7e..b3d4b31c60 100644 --- a/common/utils/itti_analyzer/libui/ui_callbacks.h +++ b/common/utils/itti_analyzer/libui/ui_callbacks.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_filters.c b/common/utils/itti_analyzer/libui/ui_filters.c index 38ab6ac909..8a6321a538 100644 --- a/common/utils/itti_analyzer/libui/ui_filters.c +++ b/common/utils/itti_analyzer/libui/ui_filters.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_filters.h b/common/utils/itti_analyzer/libui/ui_filters.h index 575a46b808..16bb38834b 100644 --- a/common/utils/itti_analyzer/libui/ui_filters.h +++ b/common/utils/itti_analyzer/libui/ui_filters.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_interface.c b/common/utils/itti_analyzer/libui/ui_interface.c index 4b8582ef97..56139a8c6b 100644 --- a/common/utils/itti_analyzer/libui/ui_interface.c +++ b/common/utils/itti_analyzer/libui/ui_interface.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_interface.h b/common/utils/itti_analyzer/libui/ui_interface.h index 7f219b68f7..f77ec144d1 100644 --- a/common/utils/itti_analyzer/libui/ui_interface.h +++ b/common/utils/itti_analyzer/libui/ui_interface.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_main_screen.c b/common/utils/itti_analyzer/libui/ui_main_screen.c index 7ae2485cb7..3d6ea266be 100644 --- a/common/utils/itti_analyzer/libui/ui_main_screen.c +++ b/common/utils/itti_analyzer/libui/ui_main_screen.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_main_screen.h b/common/utils/itti_analyzer/libui/ui_main_screen.h index 98a38ebbde..0411d687be 100644 --- a/common/utils/itti_analyzer/libui/ui_main_screen.h +++ b/common/utils/itti_analyzer/libui/ui_main_screen.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_menu_bar.c b/common/utils/itti_analyzer/libui/ui_menu_bar.c index da6b133a29..62b51b3b9f 100644 --- a/common/utils/itti_analyzer/libui/ui_menu_bar.c +++ b/common/utils/itti_analyzer/libui/ui_menu_bar.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_menu_bar.h b/common/utils/itti_analyzer/libui/ui_menu_bar.h index b66d4bf95a..037dc5edca 100644 --- a/common/utils/itti_analyzer/libui/ui_menu_bar.h +++ b/common/utils/itti_analyzer/libui/ui_menu_bar.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_notebook.c b/common/utils/itti_analyzer/libui/ui_notebook.c index f04cbb77ab..93a439335f 100644 --- a/common/utils/itti_analyzer/libui/ui_notebook.c +++ b/common/utils/itti_analyzer/libui/ui_notebook.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_notebook.h b/common/utils/itti_analyzer/libui/ui_notebook.h index 2b17be16a7..6f87856e84 100644 --- a/common/utils/itti_analyzer/libui/ui_notebook.h +++ b/common/utils/itti_analyzer/libui/ui_notebook.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_notif_dlg.c b/common/utils/itti_analyzer/libui/ui_notif_dlg.c index cf1f1b5eec..4be4aa52cf 100644 --- a/common/utils/itti_analyzer/libui/ui_notif_dlg.c +++ b/common/utils/itti_analyzer/libui/ui_notif_dlg.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_notif_dlg.h b/common/utils/itti_analyzer/libui/ui_notif_dlg.h index 51856e0487..361ec81850 100644 --- a/common/utils/itti_analyzer/libui/ui_notif_dlg.h +++ b/common/utils/itti_analyzer/libui/ui_notif_dlg.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_notifications.c b/common/utils/itti_analyzer/libui/ui_notifications.c index 99d6b8bc1c..6e7897c850 100644 --- a/common/utils/itti_analyzer/libui/ui_notifications.c +++ b/common/utils/itti_analyzer/libui/ui_notifications.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_notifications.h b/common/utils/itti_analyzer/libui/ui_notifications.h index 90f4c5909d..33ef0ff5c0 100644 --- a/common/utils/itti_analyzer/libui/ui_notifications.h +++ b/common/utils/itti_analyzer/libui/ui_notifications.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_signal_dissect_view.c b/common/utils/itti_analyzer/libui/ui_signal_dissect_view.c index dcf2acd8b2..859eb66b03 100644 --- a/common/utils/itti_analyzer/libui/ui_signal_dissect_view.c +++ b/common/utils/itti_analyzer/libui/ui_signal_dissect_view.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_signal_dissect_view.h b/common/utils/itti_analyzer/libui/ui_signal_dissect_view.h index 936d3ee27d..a5ccf6a9eb 100644 --- a/common/utils/itti_analyzer/libui/ui_signal_dissect_view.h +++ b/common/utils/itti_analyzer/libui/ui_signal_dissect_view.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_tree_view.c b/common/utils/itti_analyzer/libui/ui_tree_view.c index 0de6bde945..0396e24819 100644 --- a/common/utils/itti_analyzer/libui/ui_tree_view.c +++ b/common/utils/itti_analyzer/libui/ui_tree_view.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/itti_analyzer/libui/ui_tree_view.h b/common/utils/itti_analyzer/libui/ui_tree_view.h index d1eac10c60..88ab2fce71 100644 --- a/common/utils/itti_analyzer/libui/ui_tree_view.h +++ b/common/utils/itti_analyzer/libui/ui_tree_view.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/msc/msc.c b/common/utils/msc/msc.c index 7de2a47f98..307eeb30a5 100644 --- a/common/utils/msc/msc.c +++ b/common/utils/msc/msc.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/msc/msc.h b/common/utils/msc/msc.h index eccff79518..4493a5239a 100644 --- a/common/utils/msc/msc.h +++ b/common/utils/msc/msc.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/system.c b/common/utils/system.c index 52fb950e37..dcec681e2d 100644 --- a/common/utils/system.c +++ b/common/utils/system.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/system.h b/common/utils/system.h index 784c15fc9a..658c17adc1 100644 --- a/common/utils/system.h +++ b/common/utils/system.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/3gpplte.c b/openair1/PHY/CODING/3gpplte.c index 99b3923746..ca63857d72 100644 --- a/openair1/PHY/CODING/3gpplte.c +++ b/openair1/PHY/CODING/3gpplte.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/3gpplte_sse.c b/openair1/PHY/CODING/3gpplte_sse.c index aeec529562..5d87a60477 100644 --- a/openair1/PHY/CODING/3gpplte_sse.c +++ b/openair1/PHY/CODING/3gpplte_sse.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder.c b/openair1/PHY/CODING/3gpplte_turbo_decoder.c index c6976df164..4470ecca05 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c index 4efd366bed..616eed7446 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse.c index 085dbb723c..9ec25367d9 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c index a1e408dcda..cb4a4e1f84 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c index ff7e02a239..f00774567f 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/TESTBENCH/ltetest.c b/openair1/PHY/CODING/TESTBENCH/ltetest.c index 6bc5e25264..77e1f3f14f 100644 --- a/openair1/PHY/CODING/TESTBENCH/ltetest.c +++ b/openair1/PHY/CODING/TESTBENCH/ltetest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/TESTBENCH/pdcch_test.c b/openair1/PHY/CODING/TESTBENCH/pdcch_test.c index c083da85a7..9e055412f0 100644 --- a/openair1/PHY/CODING/TESTBENCH/pdcch_test.c +++ b/openair1/PHY/CODING/TESTBENCH/pdcch_test.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/TESTBENCH/viterbi_test.c b/openair1/PHY/CODING/TESTBENCH/viterbi_test.c index 907d7b6384..385910f680 100644 --- a/openair1/PHY/CODING/TESTBENCH/viterbi_test.c +++ b/openair1/PHY/CODING/TESTBENCH/viterbi_test.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/ccoding_byte.c b/openair1/PHY/CODING/ccoding_byte.c index 5595ee9af3..8511a5ea0f 100644 --- a/openair1/PHY/CODING/ccoding_byte.c +++ b/openair1/PHY/CODING/ccoding_byte.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/ccoding_byte_lte.c b/openair1/PHY/CODING/ccoding_byte_lte.c index ac3ff1cd7b..6eb654827b 100644 --- a/openair1/PHY/CODING/ccoding_byte_lte.c +++ b/openair1/PHY/CODING/ccoding_byte_lte.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/crc_byte.c b/openair1/PHY/CODING/crc_byte.c index 46d48e5d69..4f0dcf2196 100644 --- a/openair1/PHY/CODING/crc_byte.c +++ b/openair1/PHY/CODING/crc_byte.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/defs.h b/openair1/PHY/CODING/defs.h index 0cf444edc4..33e2471c15 100644 --- a/openair1/PHY/CODING/defs.h +++ b/openair1/PHY/CODING/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/extern.h b/openair1/PHY/CODING/extern.h index aed8e90d75..9c58920a10 100644 --- a/openair1/PHY/CODING/extern.h +++ b/openair1/PHY/CODING/extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/extern_3GPPinterleaver.h b/openair1/PHY/CODING/extern_3GPPinterleaver.h index e7134b5690..007c1fecc3 100644 --- a/openair1/PHY/CODING/extern_3GPPinterleaver.h +++ b/openair1/PHY/CODING/extern_3GPPinterleaver.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/lte_interleaver.h b/openair1/PHY/CODING/lte_interleaver.h index 165dcfac27..fbf26a8e1f 100644 --- a/openair1/PHY/CODING/lte_interleaver.h +++ b/openair1/PHY/CODING/lte_interleaver.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/lte_interleaver2.h b/openair1/PHY/CODING/lte_interleaver2.h index 74805922f9..60b2fa6d1f 100644 --- a/openair1/PHY/CODING/lte_interleaver2.h +++ b/openair1/PHY/CODING/lte_interleaver2.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/lte_interleaver_inline.h b/openair1/PHY/CODING/lte_interleaver_inline.h index 8dc56f869e..bf560128f0 100644 --- a/openair1/PHY/CODING/lte_interleaver_inline.h +++ b/openair1/PHY/CODING/lte_interleaver_inline.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/lte_rate_matching.c b/openair1/PHY/CODING/lte_rate_matching.c index e5a0fec027..bfb5897d5f 100644 --- a/openair1/PHY/CODING/lte_rate_matching.c +++ b/openair1/PHY/CODING/lte_rate_matching.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/lte_segmentation.c b/openair1/PHY/CODING/lte_segmentation.c index 04056c4c9e..0d8149d73f 100644 --- a/openair1/PHY/CODING/lte_segmentation.c +++ b/openair1/PHY/CODING/lte_segmentation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/rate_matching.c b/openair1/PHY/CODING/rate_matching.c index 51ee26ce28..db34d3e7a1 100644 --- a/openair1/PHY/CODING/rate_matching.c +++ b/openair1/PHY/CODING/rate_matching.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/scrambler.h b/openair1/PHY/CODING/scrambler.h index 06ff2d7663..3c1b1de0a7 100644 --- a/openair1/PHY/CODING/scrambler.h +++ b/openair1/PHY/CODING/scrambler.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/vars.h b/openair1/PHY/CODING/vars.h index 9c0cf66c3e..944ea08d0c 100644 --- a/openair1/PHY/CODING/vars.h +++ b/openair1/PHY/CODING/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/viterbi.c b/openair1/PHY/CODING/viterbi.c index b2ab26e91c..f44e2ebf8f 100644 --- a/openair1/PHY/CODING/viterbi.c +++ b/openair1/PHY/CODING/viterbi.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/viterbi_lte.c b/openair1/PHY/CODING/viterbi_lte.c index e1d3a99cbe..d112e7c109 100644 --- a/openair1/PHY/CODING/viterbi_lte.c +++ b/openair1/PHY/CODING/viterbi_lte.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/INIT/defs.h b/openair1/PHY/INIT/defs.h index 61cc063fb3..99fba034df 100644 --- a/openair1/PHY/INIT/defs.h +++ b/openair1/PHY/INIT/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/INIT/extern.h b/openair1/PHY/INIT/extern.h index f4f8a2eaae..4690bba42e 100644 --- a/openair1/PHY/INIT/extern.h +++ b/openair1/PHY/INIT/extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/INIT/init_top.c b/openair1/PHY/INIT/init_top.c index 33ff141203..c4d5850501 100644 --- a/openair1/PHY/INIT/init_top.c +++ b/openair1/PHY/INIT/init_top.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 04611f7b56..6ed3b7a3d3 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/INIT/lte_param_init.c b/openair1/PHY/INIT/lte_param_init.c index dbc8718dfa..e308ac0ae6 100644 --- a/openair1/PHY/INIT/lte_param_init.c +++ b/openair1/PHY/INIT/lte_param_init.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/INIT/lte_parms.c b/openair1/PHY/INIT/lte_parms.c index 730371dd61..1b5b89433d 100644 --- a/openair1/PHY/INIT/lte_parms.c +++ b/openair1/PHY/INIT/lte_parms.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/INIT/vars.h b/openair1/PHY/INIT/vars.h index f4f8a2eaae..4690bba42e 100644 --- a/openair1/PHY/INIT/vars.h +++ b/openair1/PHY/INIT/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/adjust_gain.c b/openair1/PHY/LTE_ESTIMATION/adjust_gain.c index 4f6763fa07..7272b7247d 100644 --- a/openair1/PHY/LTE_ESTIMATION/adjust_gain.c +++ b/openair1/PHY/LTE_ESTIMATION/adjust_gain.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/defs.h b/openair1/PHY/LTE_ESTIMATION/defs.h index f2cbf97f9d..b9e31bb710 100644 --- a/openair1/PHY/LTE_ESTIMATION/defs.h +++ b/openair1/PHY/LTE_ESTIMATION/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/extern.h b/openair1/PHY/LTE_ESTIMATION/extern.h index f4f8a2eaae..4690bba42e 100644 --- a/openair1/PHY/LTE_ESTIMATION/extern.h +++ b/openair1/PHY/LTE_ESTIMATION/extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/filt96_32.h b/openair1/PHY/LTE_ESTIMATION/filt96_32.h index 14f80ef1ee..929dfd4d85 100644 --- a/openair1/PHY/LTE_ESTIMATION/filt96_32.h +++ b/openair1/PHY/LTE_ESTIMATION/filt96_32.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/freq_equalization.c b/openair1/PHY/LTE_ESTIMATION/freq_equalization.c index 3e513d49fc..a5de515ae7 100644 --- a/openair1/PHY/LTE_ESTIMATION/freq_equalization.c +++ b/openair1/PHY/LTE_ESTIMATION/freq_equalization.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c index 6958666608..cc66e989b9 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c index 7f457c436a..2662e1fa30 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c index c737f7d635..4ef9c47fae 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation_emos.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation_emos.c index 331140de0a..a64aa797af 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation_emos.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation_emos.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_mbsfn_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_mbsfn_channel_estimation.c index e1ad291eec..f298f8738c 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_mbsfn_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_mbsfn_channel_estimation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/lte_eNB_measurements.c b/openair1/PHY/LTE_ESTIMATION/lte_eNB_measurements.c index a1d315dfed..8cc6cfd993 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_eNB_measurements.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_eNB_measurements.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/lte_est_freq_offset.c b/openair1/PHY/LTE_ESTIMATION/lte_est_freq_offset.c index d713cc0163..c29d7bc8bc 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_est_freq_offset.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_est_freq_offset.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c b/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c index 6ce10723c6..318383d233 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/lte_sync_timefreq.c b/openair1/PHY/LTE_ESTIMATION/lte_sync_timefreq.c index 64ff012d53..d428f8e6e6 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_sync_timefreq.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_sync_timefreq.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c b/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c index 49f440c886..069c28c677 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c index 22ed10ebb7..c6186adcd1 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/pss6144.h b/openair1/PHY/LTE_ESTIMATION/pss6144.h index 0fb5e1569d..d3d5ee0100 100644 --- a/openair1/PHY/LTE_ESTIMATION/pss6144.h +++ b/openair1/PHY/LTE_ESTIMATION/pss6144.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_ESTIMATION/vars.h b/openair1/PHY/LTE_ESTIMATION/vars.h index f4f8a2eaae..4690bba42e 100644 --- a/openair1/PHY/LTE_ESTIMATION/vars.h +++ b/openair1/PHY/LTE_ESTIMATION/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_REFSIG/defs.h b/openair1/PHY/LTE_REFSIG/defs.h index 9c12458ff0..838406b444 100644 --- a/openair1/PHY/LTE_REFSIG/defs.h +++ b/openair1/PHY/LTE_REFSIG/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_cell_spec.c b/openair1/PHY/LTE_REFSIG/lte_dl_cell_spec.c index 022e8bb373..b715b3ffa2 100644 --- a/openair1/PHY/LTE_REFSIG/lte_dl_cell_spec.c +++ b/openair1/PHY/LTE_REFSIG/lte_dl_cell_spec.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_mbsfn.c b/openair1/PHY/LTE_REFSIG/lte_dl_mbsfn.c index cb255d7896..3767f3a065 100644 --- a/openair1/PHY/LTE_REFSIG/lte_dl_mbsfn.c +++ b/openair1/PHY/LTE_REFSIG/lte_dl_mbsfn.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c b/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c index 3cf88fbb76..ed9ff1f5cd 100644 --- a/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c +++ b/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_REFSIG/lte_gold.c b/openair1/PHY/LTE_REFSIG/lte_gold.c index b15bc06cbd..c3a3f42456 100644 --- a/openair1/PHY/LTE_REFSIG/lte_gold.c +++ b/openair1/PHY/LTE_REFSIG/lte_gold.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_REFSIG/lte_gold_mbsfn.c b/openair1/PHY/LTE_REFSIG/lte_gold_mbsfn.c index f5c8095396..66d7fa8fb2 100644 --- a/openair1/PHY/LTE_REFSIG/lte_gold_mbsfn.c +++ b/openair1/PHY/LTE_REFSIG/lte_gold_mbsfn.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_REFSIG/lte_ul_ref.c b/openair1/PHY/LTE_REFSIG/lte_ul_ref.c index 52cd65fb92..cddb642b2b 100644 --- a/openair1/PHY/LTE_REFSIG/lte_ul_ref.c +++ b/openair1/PHY/LTE_REFSIG/lte_ul_ref.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_REFSIG/mod_table.h b/openair1/PHY/LTE_REFSIG/mod_table.h index 776ae8acf1..7bdc1f518f 100644 --- a/openair1/PHY/LTE_REFSIG/mod_table.h +++ b/openair1/PHY/LTE_REFSIG/mod_table.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_REFSIG/primary_synch.h b/openair1/PHY/LTE_REFSIG/primary_synch.h index f2b0affd88..8152722df3 100644 --- a/openair1/PHY/LTE_REFSIG/primary_synch.h +++ b/openair1/PHY/LTE_REFSIG/primary_synch.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index 4b6d1ac2fc..7d3de552b9 100755 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/dci.h b/openair1/PHY/LTE_TRANSPORT/dci.h index a9a5dda29e..66ec7a1a0f 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci.h +++ b/openair1/PHY/LTE_TRANSPORT/dci.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index a832d4bfb5..f20a5749ec 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/defs.h b/openair1/PHY/LTE_TRANSPORT/defs.h index 4c5eb8c06a..f2a8643ba3 100644 --- a/openair1/PHY/LTE_TRANSPORT/defs.h +++ b/openair1/PHY/LTE_TRANSPORT/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index 7d4bfc0593..515ed1518e 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c index 761f9f3603..67fb30bcf9 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index 77b72dae28..21eb12825e 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c index da69dc6a05..a258fdeab2 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation_avx2.c b/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation_avx2.c index cda5ad0f55..588adfbc55 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation_avx2.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation_avx2.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 051a3d5d83..f9f7667b60 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c b/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c index 079cfcbc52..93713bc612 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_tbs.h b/openair1/PHY/LTE_TRANSPORT/dlsch_tbs.h index 5428aa3f83..5480338728 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_tbs.h +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_tbs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_tbs_full.h b/openair1/PHY/LTE_TRANSPORT/dlsch_tbs_full.h index 10ac5f866b..9673ba15b5 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_tbs_full.h +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_tbs_full.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/drs_modulation.c b/openair1/PHY/LTE_TRANSPORT/drs_modulation.c index 861a25fabb..2a94d77b8e 100644 --- a/openair1/PHY/LTE_TRANSPORT/drs_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/drs_modulation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/extern.h b/openair1/PHY/LTE_TRANSPORT/extern.h index af4dc20df6..e791bec9a0 100644 --- a/openair1/PHY/LTE_TRANSPORT/extern.h +++ b/openair1/PHY/LTE_TRANSPORT/extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/group_hopping.c b/openair1/PHY/LTE_TRANSPORT/group_hopping.c index 9cbdfad39f..a7c8921c2c 100644 --- a/openair1/PHY/LTE_TRANSPORT/group_hopping.c +++ b/openair1/PHY/LTE_TRANSPORT/group_hopping.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/if4_tools.c b/openair1/PHY/LTE_TRANSPORT/if4_tools.c index b691717838..a38d12041b 100644 --- a/openair1/PHY/LTE_TRANSPORT/if4_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/if4_tools.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/if4_tools.h b/openair1/PHY/LTE_TRANSPORT/if4_tools.h index e2d4f1f7de..b7e974d134 100644 --- a/openair1/PHY/LTE_TRANSPORT/if4_tools.h +++ b/openair1/PHY/LTE_TRANSPORT/if4_tools.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/if5_tools.c b/openair1/PHY/LTE_TRANSPORT/if5_tools.c index 13f9ccbf90..48df5157c3 100644 --- a/openair1/PHY/LTE_TRANSPORT/if5_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/if5_tools.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/if5_tools.h b/openair1/PHY/LTE_TRANSPORT/if5_tools.h index 88852de58b..e0b1f292cb 100644 --- a/openair1/PHY/LTE_TRANSPORT/if5_tools.h +++ b/openair1/PHY/LTE_TRANSPORT/if5_tools.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_TRANSPORT/initial_sync.c index ec7cfff7a1..7ccdae6db0 100644 --- a/openair1/PHY/LTE_TRANSPORT/initial_sync.c +++ b/openair1/PHY/LTE_TRANSPORT/initial_sync.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/lte_mcs.c b/openair1/PHY/LTE_TRANSPORT/lte_mcs.c index 0abc1511ea..0baf3676f9 100644 --- a/openair1/PHY/LTE_TRANSPORT/lte_mcs.c +++ b/openair1/PHY/LTE_TRANSPORT/lte_mcs.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/mcs_tbs_tools.h b/openair1/PHY/LTE_TRANSPORT/mcs_tbs_tools.h index be7f6a7529..59959a90fd 100644 --- a/openair1/PHY/LTE_TRANSPORT/mcs_tbs_tools.h +++ b/openair1/PHY/LTE_TRANSPORT/mcs_tbs_tools.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/pbch.c b/openair1/PHY/LTE_TRANSPORT/pbch.c index e28e179b07..bbdd61b7fa 100644 --- a/openair1/PHY/LTE_TRANSPORT/pbch.c +++ b/openair1/PHY/LTE_TRANSPORT/pbch.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/pcfich.c b/openair1/PHY/LTE_TRANSPORT/pcfich.c index 3319cd0f78..a5a94dcd28 100644 --- a/openair1/PHY/LTE_TRANSPORT/pcfich.c +++ b/openair1/PHY/LTE_TRANSPORT/pcfich.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/pch.c b/openair1/PHY/LTE_TRANSPORT/pch.c index f3dd046373..600c5215bd 100644 --- a/openair1/PHY/LTE_TRANSPORT/pch.c +++ b/openair1/PHY/LTE_TRANSPORT/pch.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/phich.c b/openair1/PHY/LTE_TRANSPORT/phich.c index 3bbbaf6c71..48e4140744 100644 --- a/openair1/PHY/LTE_TRANSPORT/phich.c +++ b/openair1/PHY/LTE_TRANSPORT/phich.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/pilots.c b/openair1/PHY/LTE_TRANSPORT/pilots.c index a4d0fae259..487acb66c5 100644 --- a/openair1/PHY/LTE_TRANSPORT/pilots.c +++ b/openair1/PHY/LTE_TRANSPORT/pilots.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/pilots_mbsfn.c b/openair1/PHY/LTE_TRANSPORT/pilots_mbsfn.c index 0393a77f0c..4ebfa7ca59 100644 --- a/openair1/PHY/LTE_TRANSPORT/pilots_mbsfn.c +++ b/openair1/PHY/LTE_TRANSPORT/pilots_mbsfn.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c b/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c index b4199d9b60..63aac7f091 100644 --- a/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c +++ b/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/pmch.c b/openair1/PHY/LTE_TRANSPORT/pmch.c index 29717b6233..bd1c02c2da 100644 --- a/openair1/PHY/LTE_TRANSPORT/pmch.c +++ b/openair1/PHY/LTE_TRANSPORT/pmch.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/power_control.c b/openair1/PHY/LTE_TRANSPORT/power_control.c index 743c16b2f0..cb98afcae6 100644 --- a/openair1/PHY/LTE_TRANSPORT/power_control.c +++ b/openair1/PHY/LTE_TRANSPORT/power_control.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c index bffcd4b23a..1afe6e99f0 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.c +++ b/openair1/PHY/LTE_TRANSPORT/prach.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/prach.h b/openair1/PHY/LTE_TRANSPORT/prach.h index efdb257785..f135af6d81 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.h +++ b/openair1/PHY/LTE_TRANSPORT/prach.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/print_stats.c b/openair1/PHY/LTE_TRANSPORT/print_stats.c index 9e8fa931ad..9115abe146 100644 --- a/openair1/PHY/LTE_TRANSPORT/print_stats.c +++ b/openair1/PHY/LTE_TRANSPORT/print_stats.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index a7dc0f5187..17788b4506 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/pss.c b/openair1/PHY/LTE_TRANSPORT/pss.c index 44c7bffd9a..977bad9dc5 100644 --- a/openair1/PHY/LTE_TRANSPORT/pss.c +++ b/openair1/PHY/LTE_TRANSPORT/pss.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/pucch.c b/openair1/PHY/LTE_TRANSPORT/pucch.c index b46946c7dc..dc8489dda9 100644 --- a/openair1/PHY/LTE_TRANSPORT/pucch.c +++ b/openair1/PHY/LTE_TRANSPORT/pucch.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/rar_tools.c b/openair1/PHY/LTE_TRANSPORT/rar_tools.c index 2d29d8c13f..15287ced01 100644 --- a/openair1/PHY/LTE_TRANSPORT/rar_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/rar_tools.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/srs_modulation.c b/openair1/PHY/LTE_TRANSPORT/srs_modulation.c index 8381eca5e4..a360b35ff6 100644 --- a/openair1/PHY/LTE_TRANSPORT/srs_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/srs_modulation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/sss.c b/openair1/PHY/LTE_TRANSPORT/sss.c index bb12be9157..17a4680c54 100644 --- a/openair1/PHY/LTE_TRANSPORT/sss.c +++ b/openair1/PHY/LTE_TRANSPORT/sss.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/sss.h b/openair1/PHY/LTE_TRANSPORT/sss.h index 290e2453e2..6d42acaefc 100644 --- a/openair1/PHY/LTE_TRANSPORT/sss.h +++ b/openair1/PHY/LTE_TRANSPORT/sss.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/uci.h b/openair1/PHY/LTE_TRANSPORT/uci.h index 8b479ed9ba..c7741533da 100644 --- a/openair1/PHY/LTE_TRANSPORT/uci.h +++ b/openair1/PHY/LTE_TRANSPORT/uci.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/uci_tools.c b/openair1/PHY/LTE_TRANSPORT/uci_tools.c index fba5b0c0e3..035ef9a142 100644 --- a/openair1/PHY/LTE_TRANSPORT/uci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/uci_tools.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c index 5a9bacd527..818eb393c9 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index 59e8b5453f..f5392bfa9e 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c index 28d7cbbd01..bfad1a8d30 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c index 6dced43b5f..d1718f6e90 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/vars.h b/openair1/PHY/LTE_TRANSPORT/vars.h index 4845ab6925..4b6fa920ea 100644 --- a/openair1/PHY/LTE_TRANSPORT/vars.h +++ b/openair1/PHY/LTE_TRANSPORT/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/MODULATION/beamforming.c b/openair1/PHY/MODULATION/beamforming.c index 91489b83c5..206324516b 100644 --- a/openair1/PHY/MODULATION/beamforming.c +++ b/openair1/PHY/MODULATION/beamforming.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/MODULATION/defs.h b/openair1/PHY/MODULATION/defs.h index d68c157445..9fdff53cb5 100644 --- a/openair1/PHY/MODULATION/defs.h +++ b/openair1/PHY/MODULATION/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/MODULATION/extern.h b/openair1/PHY/MODULATION/extern.h index f4f8a2eaae..4690bba42e 100644 --- a/openair1/PHY/MODULATION/extern.h +++ b/openair1/PHY/MODULATION/extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/MODULATION/kHz_7_5.h b/openair1/PHY/MODULATION/kHz_7_5.h index c6d484143a..ce2f0d5f2c 100644 --- a/openair1/PHY/MODULATION/kHz_7_5.h +++ b/openair1/PHY/MODULATION/kHz_7_5.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index f6f0c1f618..8a7515d713 100644 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/MODULATION/prach625Hz.h b/openair1/PHY/MODULATION/prach625Hz.h index 63606ae57b..38b63b3b05 100644 --- a/openair1/PHY/MODULATION/prach625Hz.h +++ b/openair1/PHY/MODULATION/prach625Hz.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/MODULATION/slot_fep.c b/openair1/PHY/MODULATION/slot_fep.c index d97ffbc543..39ae90217f 100644 --- a/openair1/PHY/MODULATION/slot_fep.c +++ b/openair1/PHY/MODULATION/slot_fep.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/MODULATION/slot_fep_mbsfn.c b/openair1/PHY/MODULATION/slot_fep_mbsfn.c index 58e97be756..3f46287496 100644 --- a/openair1/PHY/MODULATION/slot_fep_mbsfn.c +++ b/openair1/PHY/MODULATION/slot_fep_mbsfn.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/MODULATION/slot_fep_ul.c b/openair1/PHY/MODULATION/slot_fep_ul.c index e05f5361de..150294589b 100644 --- a/openair1/PHY/MODULATION/slot_fep_ul.c +++ b/openair1/PHY/MODULATION/slot_fep_ul.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/MODULATION/ul_7_5_kHz.c b/openair1/PHY/MODULATION/ul_7_5_kHz.c index 21a3dc7c43..cbd8203aa1 100644 --- a/openair1/PHY/MODULATION/ul_7_5_kHz.c +++ b/openair1/PHY/MODULATION/ul_7_5_kHz.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/MODULATION/vars.h b/openair1/PHY/MODULATION/vars.h index adda18dffc..a05999afe1 100644 --- a/openair1/PHY/MODULATION/vars.h +++ b/openair1/PHY/MODULATION/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/8bit_rxdemux.c b/openair1/PHY/TOOLS/8bit_rxdemux.c index 47d7b27571..030be47b5d 100644 --- a/openair1/PHY/TOOLS/8bit_rxdemux.c +++ b/openair1/PHY/TOOLS/8bit_rxdemux.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/8bit_txmux.c b/openair1/PHY/TOOLS/8bit_txmux.c index 761f15c4f0..b103bc9c5c 100644 --- a/openair1/PHY/TOOLS/8bit_txmux.c +++ b/openair1/PHY/TOOLS/8bit_txmux.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/alaw_lut.h b/openair1/PHY/TOOLS/alaw_lut.h index abf4b142cb..4b5b97a953 100644 --- a/openair1/PHY/TOOLS/alaw_lut.h +++ b/openair1/PHY/TOOLS/alaw_lut.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/angle.c b/openair1/PHY/TOOLS/angle.c index 9ea714b4fc..a06640d1cf 100644 --- a/openair1/PHY/TOOLS/angle.c +++ b/openair1/PHY/TOOLS/angle.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/cadd_sv.c b/openair1/PHY/TOOLS/cadd_sv.c index b83f9e1fce..caa8d1cc04 100644 --- a/openair1/PHY/TOOLS/cadd_sv.c +++ b/openair1/PHY/TOOLS/cadd_sv.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/cadd_vv.c b/openair1/PHY/TOOLS/cadd_vv.c index a08564daf3..34808552fc 100644 --- a/openair1/PHY/TOOLS/cadd_vv.c +++ b/openair1/PHY/TOOLS/cadd_vv.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/cdot_prod.c b/openair1/PHY/TOOLS/cdot_prod.c index 7e73e58e5e..91ba246bdd 100644 --- a/openair1/PHY/TOOLS/cdot_prod.c +++ b/openair1/PHY/TOOLS/cdot_prod.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/cmult_sv.c b/openair1/PHY/TOOLS/cmult_sv.c index bc631bd6cc..61970ca2b6 100644 --- a/openair1/PHY/TOOLS/cmult_sv.c +++ b/openair1/PHY/TOOLS/cmult_sv.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/cmult_vv.c b/openair1/PHY/TOOLS/cmult_vv.c index f8caa0c6da..b5b551f008 100644 --- a/openair1/PHY/TOOLS/cmult_vv.c +++ b/openair1/PHY/TOOLS/cmult_vv.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/costable.h b/openair1/PHY/TOOLS/costable.h index 03682f84dc..b9d24c75b4 100644 --- a/openair1/PHY/TOOLS/costable.h +++ b/openair1/PHY/TOOLS/costable.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/dB_routines.c b/openair1/PHY/TOOLS/dB_routines.c index 1bcefbba03..c99703eaf3 100644 --- a/openair1/PHY/TOOLS/dB_routines.c +++ b/openair1/PHY/TOOLS/dB_routines.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/dB_routines.h b/openair1/PHY/TOOLS/dB_routines.h index 965caf76d7..c28184259f 100644 --- a/openair1/PHY/TOOLS/dB_routines.h +++ b/openair1/PHY/TOOLS/dB_routines.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/defs.h b/openair1/PHY/TOOLS/defs.h index a90a8b718c..41d7c9528a 100644 --- a/openair1/PHY/TOOLS/defs.h +++ b/openair1/PHY/TOOLS/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/extern.h b/openair1/PHY/TOOLS/extern.h index f4f8a2eaae..4690bba42e 100644 --- a/openair1/PHY/TOOLS/extern.h +++ b/openair1/PHY/TOOLS/extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/file_output.c b/openair1/PHY/TOOLS/file_output.c index 16b8b108d0..1a4adb04cd 100644 --- a/openair1/PHY/TOOLS/file_output.c +++ b/openair1/PHY/TOOLS/file_output.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/invSqrt.c b/openair1/PHY/TOOLS/invSqrt.c index 332cb63886..b3e0d9749a 100644 --- a/openair1/PHY/TOOLS/invSqrt.c +++ b/openair1/PHY/TOOLS/invSqrt.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/log2_approx.c b/openair1/PHY/TOOLS/log2_approx.c index bd4d5d04ab..acd1534857 100644 --- a/openair1/PHY/TOOLS/log2_approx.c +++ b/openair1/PHY/TOOLS/log2_approx.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/lte_dfts.c b/openair1/PHY/TOOLS/lte_dfts.c index 0aaea70d7d..dc4708ce6c 100644 --- a/openair1/PHY/TOOLS/lte_dfts.c +++ b/openair1/PHY/TOOLS/lte_dfts.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/lte_phy_scope.c b/openair1/PHY/TOOLS/lte_phy_scope.c index 0595c1bf04..92ba4e34e5 100644 --- a/openair1/PHY/TOOLS/lte_phy_scope.c +++ b/openair1/PHY/TOOLS/lte_phy_scope.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/lte_phy_scope.h b/openair1/PHY/TOOLS/lte_phy_scope.h index 2e8ca96c3a..1d2b2ea1ed 100644 --- a/openair1/PHY/TOOLS/lte_phy_scope.h +++ b/openair1/PHY/TOOLS/lte_phy_scope.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/lte_phy_scope_tm4.c b/openair1/PHY/TOOLS/lte_phy_scope_tm4.c index e5d667c3c2..8dd41548ab 100644 --- a/openair1/PHY/TOOLS/lte_phy_scope_tm4.c +++ b/openair1/PHY/TOOLS/lte_phy_scope_tm4.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/lut.c b/openair1/PHY/TOOLS/lut.c index ba9da904e3..f58a06c8ae 100644 --- a/openair1/PHY/TOOLS/lut.c +++ b/openair1/PHY/TOOLS/lut.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/memory_routines.c b/openair1/PHY/TOOLS/memory_routines.c index c7015ff46e..cef9928988 100644 --- a/openair1/PHY/TOOLS/memory_routines.c +++ b/openair1/PHY/TOOLS/memory_routines.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/signal_energy.c b/openair1/PHY/TOOLS/signal_energy.c index 2ae49ae87f..918d2e3ba0 100644 --- a/openair1/PHY/TOOLS/signal_energy.c +++ b/openair1/PHY/TOOLS/signal_energy.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/smbv.c b/openair1/PHY/TOOLS/smbv.c index adc512d7e5..e020ca0c52 100644 --- a/openair1/PHY/TOOLS/smbv.c +++ b/openair1/PHY/TOOLS/smbv.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/smbv.h b/openair1/PHY/TOOLS/smbv.h index 40a954d6e3..127cd3f7b9 100644 --- a/openair1/PHY/TOOLS/smbv.h +++ b/openair1/PHY/TOOLS/smbv.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/sqrt.c b/openair1/PHY/TOOLS/sqrt.c index b950f4b542..e6a4d9bb24 100644 --- a/openair1/PHY/TOOLS/sqrt.c +++ b/openair1/PHY/TOOLS/sqrt.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/time_meas.c b/openair1/PHY/TOOLS/time_meas.c index 19e9d64d1f..e6eb3ce08c 100644 --- a/openair1/PHY/TOOLS/time_meas.c +++ b/openair1/PHY/TOOLS/time_meas.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/time_meas.h b/openair1/PHY/TOOLS/time_meas.h index 233d16ebbe..32e6883d56 100644 --- a/openair1/PHY/TOOLS/time_meas.h +++ b/openair1/PHY/TOOLS/time_meas.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/twiddle12288.h b/openair1/PHY/TOOLS/twiddle12288.h index 8039b0b0ce..17fa92f4e9 100644 --- a/openair1/PHY/TOOLS/twiddle12288.h +++ b/openair1/PHY/TOOLS/twiddle12288.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/twiddle1536.h b/openair1/PHY/TOOLS/twiddle1536.h index c84724904e..304766caaf 100644 --- a/openair1/PHY/TOOLS/twiddle1536.h +++ b/openair1/PHY/TOOLS/twiddle1536.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/twiddle18432.h b/openair1/PHY/TOOLS/twiddle18432.h index 8c6c9822dc..696c7f37ae 100644 --- a/openair1/PHY/TOOLS/twiddle18432.h +++ b/openair1/PHY/TOOLS/twiddle18432.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/twiddle24576.h b/openair1/PHY/TOOLS/twiddle24576.h index 4ab699b9fd..34fc59d779 100644 --- a/openair1/PHY/TOOLS/twiddle24576.h +++ b/openair1/PHY/TOOLS/twiddle24576.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/twiddle6144.h b/openair1/PHY/TOOLS/twiddle6144.h index bc46647dbf..6fc18ebfbe 100644 --- a/openair1/PHY/TOOLS/twiddle6144.h +++ b/openair1/PHY/TOOLS/twiddle6144.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/twiddles4096.h b/openair1/PHY/TOOLS/twiddles4096.h index 3122e1fbb9..af2b6a8887 100644 --- a/openair1/PHY/TOOLS/twiddles4096.h +++ b/openair1/PHY/TOOLS/twiddles4096.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/twiddles8192.h b/openair1/PHY/TOOLS/twiddles8192.h index 344f5e3325..6b76619013 100644 --- a/openair1/PHY/TOOLS/twiddles8192.h +++ b/openair1/PHY/TOOLS/twiddles8192.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/TOOLS/vars.h b/openair1/PHY/TOOLS/vars.h index f4f8a2eaae..4690bba42e 100644 --- a/openair1/PHY/TOOLS/vars.h +++ b/openair1/PHY/TOOLS/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index d386a2ce98..2b47ded8fb 100644 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/extern.h b/openair1/PHY/extern.h index 0eb5dc6c97..98ccc037ad 100644 --- a/openair1/PHY/extern.h +++ b/openair1/PHY/extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h index d09fd8d915..535afc3eb1 100644 --- a/openair1/PHY/impl_defs_lte.h +++ b/openair1/PHY/impl_defs_lte.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/impl_defs_top.h b/openair1/PHY/impl_defs_top.h index be63ea00cc..639d040fe1 100644 --- a/openair1/PHY/impl_defs_top.h +++ b/openair1/PHY/impl_defs_top.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/sse_intrin.h b/openair1/PHY/sse_intrin.h index 8ae5de547a..da4d1db846 100644 --- a/openair1/PHY/sse_intrin.h +++ b/openair1/PHY/sse_intrin.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/types.h b/openair1/PHY/types.h index 61cafaefa9..be8ec7115a 100644 --- a/openair1/PHY/types.h +++ b/openair1/PHY/types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/vars.h b/openair1/PHY/vars.h index 17cdabc224..e8a207783a 100644 --- a/openair1/PHY/vars.h +++ b/openair1/PHY/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/defs.h b/openair1/SCHED/defs.h index 419dda4ea9..4722b7fbe4 100644 --- a/openair1/SCHED/defs.h +++ b/openair1/SCHED/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/extern.h b/openair1/SCHED/extern.h index 2c5ac12ca5..80a815dda7 100644 --- a/openair1/SCHED/extern.h +++ b/openair1/SCHED/extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/phy_mac_stub.c b/openair1/SCHED/phy_mac_stub.c index 835066748d..15c6fa7557 100644 --- a/openair1/SCHED/phy_mac_stub.c +++ b/openair1/SCHED/phy_mac_stub.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/phy_procedures_emos.h b/openair1/SCHED/phy_procedures_emos.h index 567ec7ec80..266a95b3c9 100644 --- a/openair1/SCHED/phy_procedures_emos.h +++ b/openair1/SCHED/phy_procedures_emos.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/phy_procedures_lte_common.c b/openair1/SCHED/phy_procedures_lte_common.c index e14a156018..3c08b84f3d 100644 --- a/openair1/SCHED/phy_procedures_lte_common.c +++ b/openair1/SCHED/phy_procedures_lte_common.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 4795b91363..08e424061c 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index dffb7fe2bd..def6f1cdc2 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/pucch_pc.c b/openair1/SCHED/pucch_pc.c index 274a25fb70..226c1fc5a5 100644 --- a/openair1/SCHED/pucch_pc.c +++ b/openair1/SCHED/pucch_pc.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/pusch_pc.c b/openair1/SCHED/pusch_pc.c index 4976889e64..578379f28d 100644 --- a/openair1/SCHED/pusch_pc.c +++ b/openair1/SCHED/pusch_pc.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/rt_compat.h b/openair1/SCHED/rt_compat.h index b220d6f06a..35e99098fa 100644 --- a/openair1/SCHED/rt_compat.h +++ b/openair1/SCHED/rt_compat.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/srs_pc.c b/openair1/SCHED/srs_pc.c index 98049b2ed0..04dacecc25 100644 --- a/openair1/SCHED/srs_pc.c +++ b/openair1/SCHED/srs_pc.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/vars.h b/openair1/SCHED/vars.h index 39eaf7f118..4dac375f18 100644 --- a/openair1/SCHED/vars.h +++ b/openair1/SCHED/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/ETH_TRANSPORT/bypass_session_layer.c b/openair1/SIMULATION/ETH_TRANSPORT/bypass_session_layer.c index c7815b087d..01bc8f4901 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/bypass_session_layer.c +++ b/openair1/SIMULATION/ETH_TRANSPORT/bypass_session_layer.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/ETH_TRANSPORT/defs.h b/openair1/SIMULATION/ETH_TRANSPORT/defs.h index 48531a2da6..3b744aa859 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/defs.h +++ b/openair1/SIMULATION/ETH_TRANSPORT/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/ETH_TRANSPORT/emu_transport.c b/openair1/SIMULATION/ETH_TRANSPORT/emu_transport.c index 76b72e321f..1647c60821 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/emu_transport.c +++ b/openair1/SIMULATION/ETH_TRANSPORT/emu_transport.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/ETH_TRANSPORT/extern.h b/openair1/SIMULATION/ETH_TRANSPORT/extern.h index 89cf38f15b..fafa7009f5 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/extern.h +++ b/openair1/SIMULATION/ETH_TRANSPORT/extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.c b/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.c index d161da6a74..f32823f3bb 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.c +++ b/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.h b/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.h index d4071e7ff2..3c072e0e3c 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.h +++ b/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/ETH_TRANSPORT/netlink_init.c b/openair1/SIMULATION/ETH_TRANSPORT/netlink_init.c index b0c01706fd..b578721a1a 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/netlink_init.c +++ b/openair1/SIMULATION/ETH_TRANSPORT/netlink_init.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/ETH_TRANSPORT/pgm_link.c b/openair1/SIMULATION/ETH_TRANSPORT/pgm_link.c index 9feeeca457..61bf940660 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/pgm_link.c +++ b/openair1/SIMULATION/ETH_TRANSPORT/pgm_link.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/ETH_TRANSPORT/pgm_link.h b/openair1/SIMULATION/ETH_TRANSPORT/pgm_link.h index b444d123bc..03fa6d4b48 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/pgm_link.h +++ b/openair1/SIMULATION/ETH_TRANSPORT/pgm_link.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/ETH_TRANSPORT/proto.h b/openair1/SIMULATION/ETH_TRANSPORT/proto.h index 5b43c86217..6a693085c9 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/proto.h +++ b/openair1/SIMULATION/ETH_TRANSPORT/proto.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/ETH_TRANSPORT/socket.c b/openair1/SIMULATION/ETH_TRANSPORT/socket.c index d8dd81ffdc..e288dcb378 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/socket.c +++ b/openair1/SIMULATION/ETH_TRANSPORT/socket.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/ETH_TRANSPORT/socket.h b/openair1/SIMULATION/ETH_TRANSPORT/socket.h index ede14f8db1..c7a2224375 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/socket.h +++ b/openair1/SIMULATION/ETH_TRANSPORT/socket.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/ETH_TRANSPORT/vars.h b/openair1/SIMULATION/ETH_TRANSPORT/vars.h index 09d9c94295..0ec38a8e90 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/vars.h +++ b/openair1/SIMULATION/ETH_TRANSPORT/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/LTE_Configuration.c b/openair1/SIMULATION/LTE_PHY/LTE_Configuration.c index 6507a656a1..c894e49e90 100644 --- a/openair1/SIMULATION/LTE_PHY/LTE_Configuration.c +++ b/openair1/SIMULATION/LTE_PHY/LTE_Configuration.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/LTE_Configuration.h b/openair1/SIMULATION/LTE_PHY/LTE_Configuration.h index ce8a3b994f..06b93650e7 100644 --- a/openair1/SIMULATION/LTE_PHY/LTE_Configuration.h +++ b/openair1/SIMULATION/LTE_PHY/LTE_Configuration.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 02591dcc8f..34055517b2 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/dlsim_tm4.c b/openair1/SIMULATION/LTE_PHY/dlsim_tm4.c index f493336e98..90ba1ec804 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim_tm4.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim_tm4.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/dlsim_tm7.c b/openair1/SIMULATION/LTE_PHY/dlsim_tm7.c index b257b1561b..3c4b3d0cd3 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim_tm7.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim_tm7.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/framegen.c b/openair1/SIMULATION/LTE_PHY/framegen.c index 9719aeb9e5..0adc07ff97 100644 --- a/openair1/SIMULATION/LTE_PHY/framegen.c +++ b/openair1/SIMULATION/LTE_PHY/framegen.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/gpib_send.c b/openair1/SIMULATION/LTE_PHY/gpib_send.c index 40bcfa8722..a8ae48cdfa 100644 --- a/openair1/SIMULATION/LTE_PHY/gpib_send.c +++ b/openair1/SIMULATION/LTE_PHY/gpib_send.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/gpib_send.h b/openair1/SIMULATION/LTE_PHY/gpib_send.h index 1f1f14e956..b83026296a 100644 --- a/openair1/SIMULATION/LTE_PHY/gpib_send.h +++ b/openair1/SIMULATION/LTE_PHY/gpib_send.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/mbmssim.c b/openair1/SIMULATION/LTE_PHY/mbmssim.c index 69de4aee9f..773ec57a3e 100644 --- a/openair1/SIMULATION/LTE_PHY/mbmssim.c +++ b/openair1/SIMULATION/LTE_PHY/mbmssim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/pbchsim.c b/openair1/SIMULATION/LTE_PHY/pbchsim.c index 687e7219e8..e240f88ce6 100644 --- a/openair1/SIMULATION/LTE_PHY/pbchsim.c +++ b/openair1/SIMULATION/LTE_PHY/pbchsim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/pdcchsim.c b/openair1/SIMULATION/LTE_PHY/pdcchsim.c index 1102d4be38..71e2f88172 100644 --- a/openair1/SIMULATION/LTE_PHY/pdcchsim.c +++ b/openair1/SIMULATION/LTE_PHY/pdcchsim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/prachsim.c b/openair1/SIMULATION/LTE_PHY/prachsim.c index 52339cdc5d..cab2ecb8fb 100644 --- a/openair1/SIMULATION/LTE_PHY/prachsim.c +++ b/openair1/SIMULATION/LTE_PHY/prachsim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/pucchsignalgegerator.h b/openair1/SIMULATION/LTE_PHY/pucchsignalgegerator.h index a17d708747..779b9ed423 100644 --- a/openair1/SIMULATION/LTE_PHY/pucchsignalgegerator.h +++ b/openair1/SIMULATION/LTE_PHY/pucchsignalgegerator.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/pucchsignalgenerator.c b/openair1/SIMULATION/LTE_PHY/pucchsignalgenerator.c index 20f044eb93..cf8e0b6d4a 100644 --- a/openair1/SIMULATION/LTE_PHY/pucchsignalgenerator.c +++ b/openair1/SIMULATION/LTE_PHY/pucchsignalgenerator.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/pucchsim.c b/openair1/SIMULATION/LTE_PHY/pucchsim.c index 9deff20d35..1e5f47e59e 100644 --- a/openair1/SIMULATION/LTE_PHY/pucchsim.c +++ b/openair1/SIMULATION/LTE_PHY/pucchsim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/scansim.c b/openair1/SIMULATION/LTE_PHY/scansim.c index ba355bbbeb..94bc991e3f 100644 --- a/openair1/SIMULATION/LTE_PHY/scansim.c +++ b/openair1/SIMULATION/LTE_PHY/scansim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/signalanalyzer.c b/openair1/SIMULATION/LTE_PHY/signalanalyzer.c index cf63bd8312..62b0f93624 100644 --- a/openair1/SIMULATION/LTE_PHY/signalanalyzer.c +++ b/openair1/SIMULATION/LTE_PHY/signalanalyzer.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/signalanalyzer.h b/openair1/SIMULATION/LTE_PHY/signalanalyzer.h index 8be2f1b6cb..e8aaddb493 100644 --- a/openair1/SIMULATION/LTE_PHY/signalanalyzer.h +++ b/openair1/SIMULATION/LTE_PHY/signalanalyzer.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/syncsim.c b/openair1/SIMULATION/LTE_PHY/syncsim.c index 58e96a9abe..acad27ca11 100644 --- a/openair1/SIMULATION/LTE_PHY/syncsim.c +++ b/openair1/SIMULATION/LTE_PHY/syncsim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/test.c b/openair1/SIMULATION/LTE_PHY/test.c index 16a7b636f5..b7781ce690 100644 --- a/openair1/SIMULATION/LTE_PHY/test.c +++ b/openair1/SIMULATION/LTE_PHY/test.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/ulsignalgenerator.c b/openair1/SIMULATION/LTE_PHY/ulsignalgenerator.c index 7c46d057e0..70bbda151c 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsignalgenerator.c +++ b/openair1/SIMULATION/LTE_PHY/ulsignalgenerator.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/ulsignalgenerator.h b/openair1/SIMULATION/LTE_PHY/ulsignalgenerator.h index 0a676be00f..81777ff958 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsignalgenerator.h +++ b/openair1/SIMULATION/LTE_PHY/ulsignalgenerator.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 03c736ecd3..cabe966491 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/ulsim2.c b/openair1/SIMULATION/LTE_PHY/ulsim2.c index 26cec52187..d91b35782c 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim2.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim2.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/LTE_PHY/unitary_defs.h b/openair1/SIMULATION/LTE_PHY/unitary_defs.h index 73d0bc0900..c33b72f649 100644 --- a/openair1/SIMULATION/LTE_PHY/unitary_defs.h +++ b/openair1/SIMULATION/LTE_PHY/unitary_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/RF/adc.c b/openair1/SIMULATION/RF/adc.c index 8bb32778fe..3bf70a203a 100644 --- a/openair1/SIMULATION/RF/adc.c +++ b/openair1/SIMULATION/RF/adc.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/RF/dac.c b/openair1/SIMULATION/RF/dac.c index 4bd006c476..034f1d4fa2 100644 --- a/openair1/SIMULATION/RF/dac.c +++ b/openair1/SIMULATION/RF/dac.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/RF/defs.h b/openair1/SIMULATION/RF/defs.h index b3d5e47e6b..bab2ae2647 100644 --- a/openair1/SIMULATION/RF/defs.h +++ b/openair1/SIMULATION/RF/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/RF/rf.c b/openair1/SIMULATION/RF/rf.c index cb2af38367..3cf770ac7c 100644 --- a/openair1/SIMULATION/RF/rf.c +++ b/openair1/SIMULATION/RF/rf.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/TOOLS/abstraction.c b/openair1/SIMULATION/TOOLS/abstraction.c index 88b3ce6406..7e99371c37 100644 --- a/openair1/SIMULATION/TOOLS/abstraction.c +++ b/openair1/SIMULATION/TOOLS/abstraction.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/TOOLS/ch_desc_proto.c b/openair1/SIMULATION/TOOLS/ch_desc_proto.c index e47ac81440..8b07a596a9 100644 --- a/openair1/SIMULATION/TOOLS/ch_desc_proto.c +++ b/openair1/SIMULATION/TOOLS/ch_desc_proto.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/TOOLS/defs.h b/openair1/SIMULATION/TOOLS/defs.h index 4378ca2da3..a958c6b4eb 100644 --- a/openair1/SIMULATION/TOOLS/defs.h +++ b/openair1/SIMULATION/TOOLS/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/TOOLS/gauss.c b/openair1/SIMULATION/TOOLS/gauss.c index ff3ff14e24..f69748270b 100644 --- a/openair1/SIMULATION/TOOLS/gauss.c +++ b/openair1/SIMULATION/TOOLS/gauss.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/TOOLS/llr_quantization.c b/openair1/SIMULATION/TOOLS/llr_quantization.c index 3cb221e675..57cb61e007 100644 --- a/openair1/SIMULATION/TOOLS/llr_quantization.c +++ b/openair1/SIMULATION/TOOLS/llr_quantization.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/TOOLS/multipath_channel.c b/openair1/SIMULATION/TOOLS/multipath_channel.c index 43af2efb87..757d5023de 100644 --- a/openair1/SIMULATION/TOOLS/multipath_channel.c +++ b/openair1/SIMULATION/TOOLS/multipath_channel.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/TOOLS/multipath_tv_channel.c b/openair1/SIMULATION/TOOLS/multipath_tv_channel.c index a75d432120..c2078b91d4 100644 --- a/openair1/SIMULATION/TOOLS/multipath_tv_channel.c +++ b/openair1/SIMULATION/TOOLS/multipath_tv_channel.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/TOOLS/random_channel.c b/openair1/SIMULATION/TOOLS/random_channel.c index 98988ea4cb..790353b21a 100644 --- a/openair1/SIMULATION/TOOLS/random_channel.c +++ b/openair1/SIMULATION/TOOLS/random_channel.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/TOOLS/rangen_double.c b/openair1/SIMULATION/TOOLS/rangen_double.c index 69f255bec3..2fce55c609 100644 --- a/openair1/SIMULATION/TOOLS/rangen_double.c +++ b/openair1/SIMULATION/TOOLS/rangen_double.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/TOOLS/scm_corrmat.h b/openair1/SIMULATION/TOOLS/scm_corrmat.h index ff89b2f33e..6ee6567ce9 100644 --- a/openair1/SIMULATION/TOOLS/scm_corrmat.h +++ b/openair1/SIMULATION/TOOLS/scm_corrmat.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SIMULATION/TOOLS/taus.c b/openair1/SIMULATION/TOOLS/taus.c index e8a13da076..a86be23aec 100644 --- a/openair1/SIMULATION/TOOLS/taus.c +++ b/openair1/SIMULATION/TOOLS/taus.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/as_message.h b/openair2/COMMON/as_message.h index acc9ae6ba1..829c3c9e33 100644 --- a/openair2/COMMON/as_message.h +++ b/openair2/COMMON/as_message.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/commonDef.h b/openair2/COMMON/commonDef.h index 37d05f3fda..b37230cdd4 100644 --- a/openair2/COMMON/commonDef.h +++ b/openair2/COMMON/commonDef.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/gtpv1_u_messages_def.h b/openair2/COMMON/gtpv1_u_messages_def.h index 4abbbf85b4..9cc41a70ea 100644 --- a/openair2/COMMON/gtpv1_u_messages_def.h +++ b/openair2/COMMON/gtpv1_u_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/gtpv1_u_messages_types.h b/openair2/COMMON/gtpv1_u_messages_types.h index c791b25cf7..c3c9c6b7c7 100644 --- a/openair2/COMMON/gtpv1_u_messages_types.h +++ b/openair2/COMMON/gtpv1_u_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/intertask_interface_conf.h b/openair2/COMMON/intertask_interface_conf.h index 2d4bebdee8..9c108f87e0 100644 --- a/openair2/COMMON/intertask_interface_conf.h +++ b/openair2/COMMON/intertask_interface_conf.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/mac_messages_def.h b/openair2/COMMON/mac_messages_def.h index 0aa9a6f909..c1135a34ae 100644 --- a/openair2/COMMON/mac_messages_def.h +++ b/openair2/COMMON/mac_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/mac_messages_types.h b/openair2/COMMON/mac_messages_types.h index 91c06b847a..5f27a0fe69 100644 --- a/openair2/COMMON/mac_messages_types.h +++ b/openair2/COMMON/mac_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/mac_primitives.h b/openair2/COMMON/mac_primitives.h index aa6bbd6cae..c901722d5d 100644 --- a/openair2/COMMON/mac_primitives.h +++ b/openair2/COMMON/mac_primitives.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/mac_rlc_primitives.h b/openair2/COMMON/mac_rlc_primitives.h index 0033e24499..4e3e22781c 100644 --- a/openair2/COMMON/mac_rlc_primitives.h +++ b/openair2/COMMON/mac_rlc_primitives.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/mac_rrc_primitives.h b/openair2/COMMON/mac_rrc_primitives.h index 9a8c363b02..07a81730a9 100644 --- a/openair2/COMMON/mac_rrc_primitives.h +++ b/openair2/COMMON/mac_rrc_primitives.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/messages_def.h b/openair2/COMMON/messages_def.h index fd3a4e9ea1..2434d15776 100644 --- a/openair2/COMMON/messages_def.h +++ b/openair2/COMMON/messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/messages_types.h b/openair2/COMMON/messages_types.h index a8bb0d8d7e..5e5fdadd2a 100644 --- a/openair2/COMMON/messages_types.h +++ b/openair2/COMMON/messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/nas_messages_def.h b/openair2/COMMON/nas_messages_def.h index db766fe99c..34d6d64a1f 100644 --- a/openair2/COMMON/nas_messages_def.h +++ b/openair2/COMMON/nas_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/nas_messages_types.h b/openair2/COMMON/nas_messages_types.h index 6d43324196..5cb1927aca 100644 --- a/openair2/COMMON/nas_messages_types.h +++ b/openair2/COMMON/nas_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/networkDef.h b/openair2/COMMON/networkDef.h index 42c812baad..89f8d5fc44 100644 --- a/openair2/COMMON/networkDef.h +++ b/openair2/COMMON/networkDef.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/openair_defs.h b/openair2/COMMON/openair_defs.h index 58be0e58e9..908f8f9813 100644 --- a/openair2/COMMON/openair_defs.h +++ b/openair2/COMMON/openair_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/openair_types.h b/openair2/COMMON/openair_types.h index 0971d7648f..d28380e752 100644 --- a/openair2/COMMON/openair_types.h +++ b/openair2/COMMON/openair_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/pdcp_messages_def.h b/openair2/COMMON/pdcp_messages_def.h index 9ac1e4e95a..da0d770def 100644 --- a/openair2/COMMON/pdcp_messages_def.h +++ b/openair2/COMMON/pdcp_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/pdcp_messages_types.h b/openair2/COMMON/pdcp_messages_types.h index ca5af05b18..033e73e86b 100644 --- a/openair2/COMMON/pdcp_messages_types.h +++ b/openair2/COMMON/pdcp_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/phy_messages_def.h b/openair2/COMMON/phy_messages_def.h index d0e2b83e3a..a2f16e64c8 100644 --- a/openair2/COMMON/phy_messages_def.h +++ b/openair2/COMMON/phy_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/phy_messages_types.h b/openair2/COMMON/phy_messages_types.h index 1742fac8d4..c425efa89c 100644 --- a/openair2/COMMON/phy_messages_types.h +++ b/openair2/COMMON/phy_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/platform_constants.h b/openair2/COMMON/platform_constants.h index 377773b642..533c5eaa2b 100644 --- a/openair2/COMMON/platform_constants.h +++ b/openair2/COMMON/platform_constants.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/platform_types.h b/openair2/COMMON/platform_types.h index 45d7774afa..3997d579bd 100644 --- a/openair2/COMMON/platform_types.h +++ b/openair2/COMMON/platform_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/ral_messages_def.h b/openair2/COMMON/ral_messages_def.h index b10c645362..7dd41b5db3 100644 --- a/openair2/COMMON/ral_messages_def.h +++ b/openair2/COMMON/ral_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/ral_messages_types.h b/openair2/COMMON/ral_messages_types.h index a9817a5550..22e3b5143f 100644 --- a/openair2/COMMON/ral_messages_types.h +++ b/openair2/COMMON/ral_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/rlc_messages_def.h b/openair2/COMMON/rlc_messages_def.h index 36ec94a773..af78f2d098 100644 --- a/openair2/COMMON/rlc_messages_def.h +++ b/openair2/COMMON/rlc_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/rlc_messages_types.h b/openair2/COMMON/rlc_messages_types.h index 127b686cf7..fe4614f3bc 100644 --- a/openair2/COMMON/rlc_messages_types.h +++ b/openair2/COMMON/rlc_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/rrc_messages_def.h b/openair2/COMMON/rrc_messages_def.h index 04b1182482..be3d18c996 100644 --- a/openair2/COMMON/rrc_messages_def.h +++ b/openair2/COMMON/rrc_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index 0e3cd844d9..316bc018ee 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/rrm_config_structs.h b/openair2/COMMON/rrm_config_structs.h index 73f5997932..9d060d102d 100644 --- a/openair2/COMMON/rrm_config_structs.h +++ b/openair2/COMMON/rrm_config_structs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/rrm_constants.h b/openair2/COMMON/rrm_constants.h index 9fe3a28d9b..5da8f773c3 100644 --- a/openair2/COMMON/rrm_constants.h +++ b/openair2/COMMON/rrm_constants.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/rtos_header.h b/openair2/COMMON/rtos_header.h index ed10ef4a10..63bc57d942 100644 --- a/openair2/COMMON/rtos_header.h +++ b/openair2/COMMON/rtos_header.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/s1ap_messages_def.h b/openair2/COMMON/s1ap_messages_def.h index 10c70439d2..d3d853c7e7 100644 --- a/openair2/COMMON/s1ap_messages_def.h +++ b/openair2/COMMON/s1ap_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/s1ap_messages_types.h b/openair2/COMMON/s1ap_messages_types.h index 4fc043f281..c17097d4ec 100644 --- a/openair2/COMMON/s1ap_messages_types.h +++ b/openair2/COMMON/s1ap_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/sctp_messages_def.h b/openair2/COMMON/sctp_messages_def.h index ffe13bae56..d4248b7bc3 100644 --- a/openair2/COMMON/sctp_messages_def.h +++ b/openair2/COMMON/sctp_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/sctp_messages_types.h b/openair2/COMMON/sctp_messages_types.h index 57e0f37e71..184e951acb 100644 --- a/openair2/COMMON/sctp_messages_types.h +++ b/openair2/COMMON/sctp_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/tasks_def.h b/openair2/COMMON/tasks_def.h index c9e210fd1f..530365828d 100644 --- a/openair2/COMMON/tasks_def.h +++ b/openair2/COMMON/tasks_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/udp_messages_def.h b/openair2/COMMON/udp_messages_def.h index 41b5e8aa52..35322f2450 100644 --- a/openair2/COMMON/udp_messages_def.h +++ b/openair2/COMMON/udp_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/udp_messages_types.h b/openair2/COMMON/udp_messages_types.h index 1ec878782a..7825a924d1 100644 --- a/openair2/COMMON/udp_messages_types.h +++ b/openair2/COMMON/udp_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/x2ap_messages_def.h b/openair2/COMMON/x2ap_messages_def.h index f4f8a2eaae..4690bba42e 100644 --- a/openair2/COMMON/x2ap_messages_def.h +++ b/openair2/COMMON/x2ap_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/COMMON/x2ap_messages_types.h b/openair2/COMMON/x2ap_messages_types.h index f4f8a2eaae..4690bba42e 100644 --- a/openair2/COMMON/x2ap_messages_types.h +++ b/openair2/COMMON/x2ap_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/DOCS/TEMPLATES/CODE/example_doxy.h b/openair2/DOCS/TEMPLATES/CODE/example_doxy.h index 27691f46f1..c51bdbccab 100644 --- a/openair2/DOCS/TEMPLATES/CODE/example_doxy.h +++ b/openair2/DOCS/TEMPLATES/CODE/example_doxy.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/DOCS/TEMPLATES/README/Readme.doxy b/openair2/DOCS/TEMPLATES/README/Readme.doxy index 099c51cdf4..c87289d678 100644 --- a/openair2/DOCS/TEMPLATES/README/Readme.doxy +++ b/openair2/DOCS/TEMPLATES/README/Readme.doxy @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/DOCS/TEMPLATES/README/readme.txt b/openair2/DOCS/TEMPLATES/README/readme.txt index 23ecdd5e91..f31f7cd30e 100644 --- a/openair2/DOCS/TEMPLATES/README/readme.txt +++ b/openair2/DOCS/TEMPLATES/README/readme.txt @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 1a43f203df..fcf9fb537c 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h index e2378e9311..090a599abe 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h index 9ec8594f88..70254bd7ba 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c index 1fa9852487..5c37ba8132 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h index 9a7d4a8555..263b85eb87 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index de0d0490aa..2ed2a69cf6 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/enb_app.h b/openair2/ENB_APP/enb_app.h index 8e3c28760b..52f63806e8 100644 --- a/openair2/ENB_APP/enb_app.h +++ b/openair2/ENB_APP/enb_app.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index 8001f909e7..cacf1cfd2e 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h index a508a82e1f..8df1b98a4f 100644 --- a/openair2/ENB_APP/enb_config.h +++ b/openair2/ENB_APP/enb_config.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c index 0dcacd4b81..4faa1f3624 100644 --- a/openair2/ENB_APP/flexran_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent.h b/openair2/ENB_APP/flexran_agent.h index 21ea21aafc..579bf3be23 100644 --- a/openair2/ENB_APP/flexran_agent.h +++ b/openair2/ENB_APP/flexran_agent.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_async.c b/openair2/ENB_APP/flexran_agent_async.c index 978b44929d..f1edc291c9 100644 --- a/openair2/ENB_APP/flexran_agent_async.c +++ b/openair2/ENB_APP/flexran_agent_async.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_async.h b/openair2/ENB_APP/flexran_agent_async.h index b097b15c25..03aebd0058 100644 --- a/openair2/ENB_APP/flexran_agent_async.h +++ b/openair2/ENB_APP/flexran_agent_async.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index 073bb8029c..69c786edb3 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_common.h b/openair2/ENB_APP/flexran_agent_common.h index abe5a05b44..7ab89acb4b 100644 --- a/openair2/ENB_APP/flexran_agent_common.h +++ b/openair2/ENB_APP/flexran_agent_common.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c index e735b2748b..240856b948 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.c +++ b/openair2/ENB_APP/flexran_agent_common_internal.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_common_internal.h b/openair2/ENB_APP/flexran_agent_common_internal.h index c8f78aafe9..d91c2dc7f6 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.h +++ b/openair2/ENB_APP/flexran_agent_common_internal.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_defs.h b/openair2/ENB_APP/flexran_agent_defs.h index d60510b0c7..12e3c56dff 100644 --- a/openair2/ENB_APP/flexran_agent_defs.h +++ b/openair2/ENB_APP/flexran_agent_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_extern.h b/openair2/ENB_APP/flexran_agent_extern.h index 4a04d5d3a6..6237f78367 100644 --- a/openair2/ENB_APP/flexran_agent_extern.h +++ b/openair2/ENB_APP/flexran_agent_extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c index 29a1c1000c..51188bea86 100644 --- a/openair2/ENB_APP/flexran_agent_handler.c +++ b/openair2/ENB_APP/flexran_agent_handler.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_net_comm.c b/openair2/ENB_APP/flexran_agent_net_comm.c index 6e39d6089f..e644251209 100644 --- a/openair2/ENB_APP/flexran_agent_net_comm.c +++ b/openair2/ENB_APP/flexran_agent_net_comm.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_net_comm.h b/openair2/ENB_APP/flexran_agent_net_comm.h index e4aa854c70..2f59b0f7a3 100644 --- a/openair2/ENB_APP/flexran_agent_net_comm.h +++ b/openair2/ENB_APP/flexran_agent_net_comm.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_task_manager.c b/openair2/ENB_APP/flexran_agent_task_manager.c index eaa6a58af8..088ec618c7 100644 --- a/openair2/ENB_APP/flexran_agent_task_manager.c +++ b/openair2/ENB_APP/flexran_agent_task_manager.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_task_manager.h b/openair2/ENB_APP/flexran_agent_task_manager.h index 1b14f1f6f6..165b9dda1c 100644 --- a/openair2/ENB_APP/flexran_agent_task_manager.h +++ b/openair2/ENB_APP/flexran_agent_task_manager.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index ecbe0b68ba..b019ffc6fa 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 45a11b8295..bdfeb295ce 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 4d327e350b..460446b42a 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c index 991f8bfbfa..3d3f327d71 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/eNB_scheduler_bch.c b/openair2/LAYER2/MAC/eNB_scheduler_bch.c index fb01532068..1d8d754f3e 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_bch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_bch.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 3dfe88d053..eb02703fa9 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/eNB_scheduler_mch.c b/openair2/LAYER2/MAC/eNB_scheduler_mch.c index 56582f936c..3ae1b424fc 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_mch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_mch.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index c3ee62e821..0ac1c562ff 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 6d3044813c..6bf60a8afc 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/extern.h b/openair2/LAYER2/MAC/extern.h index 1da6fe5a69..fd8a2a76c0 100644 --- a/openair2/LAYER2/MAC/extern.h +++ b/openair2/LAYER2/MAC/extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h index a3ff3b6a4a..5b152a1138 100644 --- a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h +++ b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c index 38f39e50e1..018d490f44 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index 5f1df67663..ee0e7c5582 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c index 7dec8d0c56..17424b2797 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h index 7a02ff2f1d..997b9d1d24 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/flexran_dci_conversions.h b/openair2/LAYER2/MAC/flexran_dci_conversions.h index a417c39d20..f52ae5b807 100644 --- a/openair2/LAYER2/MAC/flexran_dci_conversions.h +++ b/openair2/LAYER2/MAC/flexran_dci_conversions.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/l1_helpers.c b/openair2/LAYER2/MAC/l1_helpers.c index e5dcd5add5..1983c30020 100644 --- a/openair2/LAYER2/MAC/l1_helpers.c +++ b/openair2/LAYER2/MAC/l1_helpers.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/lte_transport_init.c b/openair2/LAYER2/MAC/lte_transport_init.c index 07aadc3715..1f67d8913c 100644 --- a/openair2/LAYER2/MAC/lte_transport_init.c +++ b/openair2/LAYER2/MAC/lte_transport_init.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/main.c b/openair2/LAYER2/MAC/main.c index e04d7c3b8a..d64ae7e72a 100644 --- a/openair2/LAYER2/MAC/main.c +++ b/openair2/LAYER2/MAC/main.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/openair2_proc.c b/openair2/LAYER2/MAC/openair2_proc.c index 4b63571277..05dd3cce85 100644 --- a/openair2/LAYER2/MAC/openair2_proc.c +++ b/openair2/LAYER2/MAC/openair2_proc.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 2f540edd36..2e5bde4e7c 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index ea264f1bfd..609fffe0a9 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/ra_procedures.c b/openair2/LAYER2/MAC/ra_procedures.c index d2d52383b0..1c96291354 100644 --- a/openair2/LAYER2/MAC/ra_procedures.c +++ b/openair2/LAYER2/MAC/ra_procedures.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/rar_tools.c b/openair2/LAYER2/MAC/rar_tools.c index 51900d8f3a..79003527eb 100644 --- a/openair2/LAYER2/MAC/rar_tools.c +++ b/openair2/LAYER2/MAC/rar_tools.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index d7e779c607..148b98a945 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/vars.h b/openair2/LAYER2/MAC/vars.h index 434a9e7c9c..56a4ccba9d 100644 --- a/openair2/LAYER2/MAC/vars.h +++ b/openair2/LAYER2/MAC/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 8dad83a90a..f3fc7a8b6c 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h index 94084273d1..d1d3d8233f 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_control_primitive.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_control_primitive.c index 795cb2e80a..abec97ddfd 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_control_primitive.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_control_primitive.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_control_primitives_proto_extern.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp_control_primitives_proto_extern.h index b7930ab1e1..6226dccc33 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_control_primitives_proto_extern.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_control_primitives_proto_extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index 2ebcf64cad..8e80189fb1 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c index 68cf6facde..eddd42c34b 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.c index 6cef21c493..7117a760b9 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h index cc86a1cd6a..8e57f84b0a 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_proto_extern.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp_proto_extern.h index 8bb383e615..afcc2fdd02 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_proto_extern.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_proto_extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c index 030505d9ac..d395f95981 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.c index 3eff6e335c..949858c1e5 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.h index 3faa001575..ec59a4b4fe 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_thread.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_thread.c index a4d6b7d112..0200ffdbf8 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_thread.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_thread.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.c index eac42cb129..ad2cbae847 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.h index 4934e0c635..7944049c3b 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index 03fabf47b3..0e21d5cfac 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h index 4619a07315..131d56e1f8 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h index 12af0279a8..674b8c244e 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h index 602e8e98c2..1b6d837565 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c index 4b5c173d4b..a133ce0992 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.h index c596bc671a..43503a1b3a 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c index 129d4ffb0f..f6dd0c5809 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h index d088f9f011..2ee7d040ab 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_proto_extern.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_proto_extern.h index f4f8a2eaae..4690bba42e 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_proto_extern.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_proto_extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c index 4202443a5a..addc949d35 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h index 4b780ce441..82148a4a37 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c index d2a5cc985e..b1facdfb02 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.h index fbc02474eb..9d2978b0f8 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index 06ad9a3b05..9e1db8a95b 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h index 7224d39bf9..60fefab84b 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index cad1a776a8..dc1ed21163 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h index e6e043dd0a..d2f0740b33 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c index 113ee7d048..afce72b455 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h index b52b3e5aaa..aa5cb6dceb 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c index 46a656e65a..1da5bbc441 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.h index 68200c0f99..7c22697ac4 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index a5c15a5262..092c7c65f1 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.h index 31afd6ae4b..e09189fcd6 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h index 2b75cb21a7..a6c340a165 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c index 86cafb89ce..ff969c0b6e 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.h index 6064f777cb..b42800e15f 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c index 3edb09d228..0b88e7c650 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.h index 1df0be62d9..c5d49268c4 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c index cec0dffd1d..b9383980a4 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.h index dcf27a1977..a2876d9169 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c index 65ea056120..13d4205c28 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.h index e6445b6d15..31ff985e41 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_windows.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_windows.c index 2c181b5d6c..f0cacc2874 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_windows.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_windows.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_windows.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_windows.h index 8274de2428..aff78a15c6 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_windows.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_windows.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.c b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.c index 6e495bceff..913858c45b 100644 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.c +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.h b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.h index 3c74470eba..a0049e4c2a 100644 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.h +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_entity.h b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_entity.h index 9c4e06efbc..1a13982df6 100644 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_entity.h +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_entity.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c index 8ddea705cd..faf7763e4f 100644 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h index 0e400a48ad..35e6c792ae 100644 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_structs.h b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_structs.h index 597fe0f04a..ee9d5268d4 100644 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_structs.h +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_structs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c index e3322d9410..2e1629f8c8 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h index 87cf2e2f37..c7754f587a 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_constants.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_constants.h index 34d97de59d..5f210dbe7b 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_constants.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_constants.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c index 14ca1a62a9..bb2a361f43 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.h index b6964f9f12..5847a8bb13 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_dar.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_dar.c index c00e87c4e0..fe71839231 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_dar.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_dar.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_dar.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_dar.h index 10816a372a..f62cddfbca 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_dar.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_dar.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_entity.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_entity.h index f4bfef2b14..3250ac85b8 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_entity.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_entity.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_fsm.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_fsm.c index c66df33872..8b2ef0b40b 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_fsm.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_fsm.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_fsm.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_fsm.h index 28fec3567a..1f7310803b 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_fsm.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_fsm.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.c index 0805d708ca..468a7d062a 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.h index d199409c57..95aac89623 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_receiver.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_receiver.c index 3f083a77a8..37608d4330 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_receiver.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_receiver.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_receiver.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_receiver.h index 882a29de7e..5e93f272fd 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_receiver.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_receiver.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c index bae9bd8d80..4d4362251e 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.h index 7f3d8d7e92..9794f9a502 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_structs.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_structs.h index 232450c5ac..a5425cb8a0 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_structs.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_structs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c index fced6efbf9..2c1fa9333f 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.h index 71030b639d..2c874b8d24 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_very_simple_test.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_very_simple_test.c index 9934fd3a58..91985e4800 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_very_simple_test.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_very_simple_test.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_very_simple_test.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_very_simple_test.h index 34cd0fea12..261183ad1d 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_very_simple_test.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_very_simple_test.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/mac_primitives.h b/openair2/LAYER2/RLC/mac_primitives.h index f4f8a2eaae..4690bba42e 100644 --- a/openair2/LAYER2/RLC/mac_primitives.h +++ b/openair2/LAYER2/RLC/mac_primitives.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/rlc.c b/openair2/LAYER2/RLC/rlc.c index 7aca1b9cc6..2d27319590 100644 --- a/openair2/LAYER2/RLC/rlc.c +++ b/openair2/LAYER2/RLC/rlc.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/rlc.h b/openair2/LAYER2/RLC/rlc.h index 3d6be20524..fca786b4d3 100644 --- a/openair2/LAYER2/RLC/rlc.h +++ b/openair2/LAYER2/RLC/rlc.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/rlc_def.h b/openair2/LAYER2/RLC/rlc_def.h index 929d66b70b..e7014043f7 100644 --- a/openair2/LAYER2/RLC/rlc_def.h +++ b/openair2/LAYER2/RLC/rlc_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/rlc_def_lte.h b/openair2/LAYER2/RLC/rlc_def_lte.h index 20a60c5d93..aa4dac79ae 100644 --- a/openair2/LAYER2/RLC/rlc_def_lte.h +++ b/openair2/LAYER2/RLC/rlc_def_lte.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/rlc_mac.c b/openair2/LAYER2/RLC/rlc_mac.c index b4061ad29f..6793e71c54 100644 --- a/openair2/LAYER2/RLC/rlc_mac.c +++ b/openair2/LAYER2/RLC/rlc_mac.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/rlc_mpls.c b/openair2/LAYER2/RLC/rlc_mpls.c index e508c3193f..34e4f028ae 100644 --- a/openair2/LAYER2/RLC/rlc_mpls.c +++ b/openair2/LAYER2/RLC/rlc_mpls.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/rlc_primitives.h b/openair2/LAYER2/RLC/rlc_primitives.h index 611c48ee4c..8d679ab9aa 100644 --- a/openair2/LAYER2/RLC/rlc_primitives.h +++ b/openair2/LAYER2/RLC/rlc_primitives.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/RLC/rlc_rrc.c b/openair2/LAYER2/RLC/rlc_rrc.c index a45838603e..68f5971bf1 100644 --- a/openair2/LAYER2/RLC/rlc_rrc.c +++ b/openair2/LAYER2/RLC/rlc_rrc.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/layer2_top.c b/openair2/LAYER2/layer2_top.c index 2837e25d7b..703094b961 100644 --- a/openair2/LAYER2/layer2_top.c +++ b/openair2/LAYER2/layer2_top.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/openair2_proc.c b/openair2/LAYER2/openair2_proc.c index 677d49bb65..a3e94c7914 100644 --- a/openair2/LAYER2/openair2_proc.c +++ b/openair2/LAYER2/openair2_proc.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/register.c b/openair2/LAYER2/register.c index 400020b8a5..964666875a 100644 --- a/openair2/LAYER2/register.c +++ b/openair2/LAYER2/register.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/register.h b/openair2/LAYER2/register.h index e65aa92361..8a4aeb5b12 100644 --- a/openair2/LAYER2/register.h +++ b/openair2/LAYER2/register.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/Makefile b/openair2/Makefile index 87b3108f1b..2fbeb193a6 100755 --- a/openair2/Makefile +++ b/openair2/Makefile @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.c b/openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.c index a15b4bf6af..0b520ed151 100644 --- a/openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.c +++ b/openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.h b/openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.h index ee4efd8c75..128503094f 100644 --- a/openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.h +++ b/openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_ascontrol.c b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_ascontrol.c index 8f34e93565..666cbb1a04 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_ascontrol.c +++ b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_ascontrol.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_classifier.c b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_classifier.c index 689b515843..3cc1ac0879 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_classifier.c +++ b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_classifier.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_common.c b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_common.c index 4782f13488..bbafa86ad1 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_common.c +++ b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_common.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_constant.h b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_constant.h index 0e77b3e44c..bdba11ff79 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_constant.h +++ b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_constant.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_device.c b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_device.c index 77b3c28165..efc8562bf9 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_device.c +++ b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_device.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.c b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.c index 14d598abb7..296ae78866 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.c +++ b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.h b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.h index 924f442341..40118d8368 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.h +++ b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_netlink.c b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_netlink.c index 13c50570b4..2f92b94717 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_netlink.c +++ b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_netlink.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_proto.h b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_proto.h index ec7f7ec2cc..3a6ffe4848 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_proto.h +++ b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_proto.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_sap.h b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_sap.h index 83874b375d..c0934f4622 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_sap.h +++ b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_sap.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_tool.c b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_tool.c index c4e8ed284c..4c5d3fcf6e 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_tool.c +++ b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_tool.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_variables.h b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_variables.h index 130488bca6..c5754e948e 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_variables.h +++ b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_variables.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_ascontrol.c b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_ascontrol.c index 1864406ce0..4a6ef0e275 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_ascontrol.c +++ b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_ascontrol.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_classifier.c b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_classifier.c index 1883b17eb0..4c0cf8aa1e 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_classifier.c +++ b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_classifier.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_common.c b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_common.c index e2819d075e..6bfd77a17d 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_common.c +++ b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_common.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_constant.h b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_constant.h index b346816e8f..7a0e69cc48 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_constant.h +++ b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_constant.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_device.c b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_device.c index 970600de21..8fe2d48e3f 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_device.c +++ b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_device.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.c b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.c index 86576500b7..3c8f5d3cc6 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.c +++ b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.h b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.h index 2104c6cac1..bd7baac3b6 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.h +++ b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_netlink.c b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_netlink.c index 9cccb7c226..d0a3516567 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_netlink.c +++ b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_netlink.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_proto.h b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_proto.h index 74eb226b05..9053c88a56 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_proto.h +++ b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_proto.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_sap.h b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_sap.h index 84f508cbc3..e2835adf7d 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_sap.h +++ b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_sap.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_tool.c b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_tool.c index 4891f5447f..54324cf63f 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_tool.c +++ b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_tool.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_variables.h b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_variables.h index a8677452bc..7c2b69459c 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_variables.h +++ b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_variables.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NETLTEST/netltest.c b/openair2/NAS/DRIVER/CELLULAR/NETLTEST/netltest.c index 9f33bf6ce0..84de51a68d 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NETLTEST/netltest.c +++ b/openair2/NAS/DRIVER/CELLULAR/NETLTEST/netltest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/DRIVER/CELLULAR/NETLTEST/nettestPDCP.c b/openair2/NAS/DRIVER/CELLULAR/NETLTEST/nettestPDCP.c index 172110fa9b..121d3bba8b 100644 --- a/openair2/NAS/DRIVER/CELLULAR/NETLTEST/nettestPDCP.c +++ b/openair2/NAS/DRIVER/CELLULAR/NETLTEST/nettestPDCP.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/SIMU_CELLULAR/nas_simu_proto.h b/openair2/NAS/SIMU_CELLULAR/nas_simu_proto.h index ef728f1b14..86ab7a1ec5 100644 --- a/openair2/NAS/SIMU_CELLULAR/nas_simu_proto.h +++ b/openair2/NAS/SIMU_CELLULAR/nas_simu_proto.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/SIMU_CELLULAR/nasrg_simu_meas.c b/openair2/NAS/SIMU_CELLULAR/nasrg_simu_meas.c index 37fbcb7756..a192b82d72 100644 --- a/openair2/NAS/SIMU_CELLULAR/nasrg_simu_meas.c +++ b/openair2/NAS/SIMU_CELLULAR/nasrg_simu_meas.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NAS/SIMU_CELLULAR/rrm_fifo_standalone.c b/openair2/NAS/SIMU_CELLULAR/rrm_fifo_standalone.c index 08a1940388..e9cefdd926 100644 --- a/openair2/NAS/SIMU_CELLULAR/rrm_fifo_standalone.c +++ b/openair2/NAS/SIMU_CELLULAR/rrm_fifo_standalone.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/LITE/RB_TOOL/rb_tool.c b/openair2/NETWORK_DRIVER/LITE/RB_TOOL/rb_tool.c index edf29dbee0..e918f209e3 100644 --- a/openair2/NETWORK_DRIVER/LITE/RB_TOOL/rb_tool.c +++ b/openair2/NETWORK_DRIVER/LITE/RB_TOOL/rb_tool.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/LITE/classifier.c b/openair2/NETWORK_DRIVER/LITE/classifier.c index 18dba87253..bc6888279b 100644 --- a/openair2/NETWORK_DRIVER/LITE/classifier.c +++ b/openair2/NETWORK_DRIVER/LITE/classifier.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/LITE/common.c b/openair2/NETWORK_DRIVER/LITE/common.c index 9749429201..0d616d5764 100644 --- a/openair2/NETWORK_DRIVER/LITE/common.c +++ b/openair2/NETWORK_DRIVER/LITE/common.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/LITE/constant.h b/openair2/NETWORK_DRIVER/LITE/constant.h index 1d8821dfdd..efeba0b86d 100644 --- a/openair2/NETWORK_DRIVER/LITE/constant.h +++ b/openair2/NETWORK_DRIVER/LITE/constant.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/LITE/device.c b/openair2/NETWORK_DRIVER/LITE/device.c index 616af5e145..fe60d82c15 100644 --- a/openair2/NETWORK_DRIVER/LITE/device.c +++ b/openair2/NETWORK_DRIVER/LITE/device.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/LITE/ioctl.c b/openair2/NETWORK_DRIVER/LITE/ioctl.c index 06309403d1..85c213c5ff 100644 --- a/openair2/NETWORK_DRIVER/LITE/ioctl.c +++ b/openair2/NETWORK_DRIVER/LITE/ioctl.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/LITE/ioctl.h b/openair2/NETWORK_DRIVER/LITE/ioctl.h index dcd26543de..d5bab2038c 100644 --- a/openair2/NETWORK_DRIVER/LITE/ioctl.h +++ b/openair2/NETWORK_DRIVER/LITE/ioctl.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/LITE/local.h b/openair2/NETWORK_DRIVER/LITE/local.h index f1d2a7bb3d..ea82dd9b85 100644 --- a/openair2/NETWORK_DRIVER/LITE/local.h +++ b/openair2/NETWORK_DRIVER/LITE/local.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/LITE/netlink.c b/openair2/NETWORK_DRIVER/LITE/netlink.c index b54ec4a987..2ad104b421 100644 --- a/openair2/NETWORK_DRIVER/LITE/netlink.c +++ b/openair2/NETWORK_DRIVER/LITE/netlink.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/LITE/proto_extern.h b/openair2/NETWORK_DRIVER/LITE/proto_extern.h index 57aa601a61..f07083921f 100644 --- a/openair2/NETWORK_DRIVER/LITE/proto_extern.h +++ b/openair2/NETWORK_DRIVER/LITE/proto_extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/LITE/sap.h b/openair2/NETWORK_DRIVER/LITE/sap.h index 1fff9744af..d72a1b10df 100644 --- a/openair2/NETWORK_DRIVER/LITE/sap.h +++ b/openair2/NETWORK_DRIVER/LITE/sap.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/LITE/tool.c b/openair2/NETWORK_DRIVER/LITE/tool.c index 089259458d..d8d0030dd9 100644 --- a/openair2/NETWORK_DRIVER/LITE/tool.c +++ b/openair2/NETWORK_DRIVER/LITE/tool.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/RB_TOOL/rb_tool.c b/openair2/NETWORK_DRIVER/MESH/RB_TOOL/rb_tool.c index 24dfcaf61e..8e231895d9 100644 --- a/openair2/NETWORK_DRIVER/MESH/RB_TOOL/rb_tool.c +++ b/openair2/NETWORK_DRIVER/MESH/RB_TOOL/rb_tool.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/TESTBENCH/testbench.c b/openair2/NETWORK_DRIVER/MESH/TESTBENCH/testbench.c index 172110fa9b..121d3bba8b 100644 --- a/openair2/NETWORK_DRIVER/MESH/TESTBENCH/testbench.c +++ b/openair2/NETWORK_DRIVER/MESH/TESTBENCH/testbench.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/classifier.c b/openair2/NETWORK_DRIVER/MESH/classifier.c index f47d63008c..985bab946e 100644 --- a/openair2/NETWORK_DRIVER/MESH/classifier.c +++ b/openair2/NETWORK_DRIVER/MESH/classifier.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/common.c b/openair2/NETWORK_DRIVER/MESH/common.c index 95e4cf1fc2..0eb7530ee6 100644 --- a/openair2/NETWORK_DRIVER/MESH/common.c +++ b/openair2/NETWORK_DRIVER/MESH/common.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/constant.h b/openair2/NETWORK_DRIVER/MESH/constant.h index fed132c61e..1c756765c6 100644 --- a/openair2/NETWORK_DRIVER/MESH/constant.h +++ b/openair2/NETWORK_DRIVER/MESH/constant.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/device.c b/openair2/NETWORK_DRIVER/MESH/device.c index 393fe9f9e0..f9bc592bce 100644 --- a/openair2/NETWORK_DRIVER/MESH/device.c +++ b/openair2/NETWORK_DRIVER/MESH/device.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/ioctl.c b/openair2/NETWORK_DRIVER/MESH/ioctl.c index 913fcc1e75..56dfb1cfe8 100644 --- a/openair2/NETWORK_DRIVER/MESH/ioctl.c +++ b/openair2/NETWORK_DRIVER/MESH/ioctl.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/ioctl.h b/openair2/NETWORK_DRIVER/MESH/ioctl.h index 9273d18651..ffa9b4e79b 100644 --- a/openair2/NETWORK_DRIVER/MESH/ioctl.h +++ b/openair2/NETWORK_DRIVER/MESH/ioctl.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/local.h b/openair2/NETWORK_DRIVER/MESH/local.h index 0e0a581cbc..e23188d357 100644 --- a/openair2/NETWORK_DRIVER/MESH/local.h +++ b/openair2/NETWORK_DRIVER/MESH/local.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/mesh.c b/openair2/NETWORK_DRIVER/MESH/mesh.c index e2cf3bcf0a..367e34cc4f 100644 --- a/openair2/NETWORK_DRIVER/MESH/mesh.c +++ b/openair2/NETWORK_DRIVER/MESH/mesh.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/netlink.c b/openair2/NETWORK_DRIVER/MESH/netlink.c index 8d40a9d965..9ac44453a9 100644 --- a/openair2/NETWORK_DRIVER/MESH/netlink.c +++ b/openair2/NETWORK_DRIVER/MESH/netlink.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/proto_extern.h b/openair2/NETWORK_DRIVER/MESH/proto_extern.h index a362876f83..844c5b41a4 100644 --- a/openair2/NETWORK_DRIVER/MESH/proto_extern.h +++ b/openair2/NETWORK_DRIVER/MESH/proto_extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/rrc_nas_primitives.h b/openair2/NETWORK_DRIVER/MESH/rrc_nas_primitives.h index cb4c00dcb9..193ce286cb 100644 --- a/openair2/NETWORK_DRIVER/MESH/rrc_nas_primitives.h +++ b/openair2/NETWORK_DRIVER/MESH/rrc_nas_primitives.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/sap.h b/openair2/NETWORK_DRIVER/MESH/sap.h index eb85437999..60b8fa11fb 100644 --- a/openair2/NETWORK_DRIVER/MESH/sap.h +++ b/openair2/NETWORK_DRIVER/MESH/sap.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/MESH/tool.c b/openair2/NETWORK_DRIVER/MESH/tool.c index 872a2583ce..2e8e68a17c 100644 --- a/openair2/NETWORK_DRIVER/MESH/tool.c +++ b/openair2/NETWORK_DRIVER/MESH/tool.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/UE_IP/common.c b/openair2/NETWORK_DRIVER/UE_IP/common.c index 8c3e4557d3..99712cc5d2 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/common.c +++ b/openair2/NETWORK_DRIVER/UE_IP/common.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/UE_IP/constant.h b/openair2/NETWORK_DRIVER/UE_IP/constant.h index 42fd0b6303..faff970dcd 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/constant.h +++ b/openair2/NETWORK_DRIVER/UE_IP/constant.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/UE_IP/device.c b/openair2/NETWORK_DRIVER/UE_IP/device.c index a4f714d4c5..a4398e9d9e 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/device.c +++ b/openair2/NETWORK_DRIVER/UE_IP/device.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/UE_IP/local.h b/openair2/NETWORK_DRIVER/UE_IP/local.h index 3c9c4c4295..ac3b040995 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/local.h +++ b/openair2/NETWORK_DRIVER/UE_IP/local.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/UE_IP/netlink.c b/openair2/NETWORK_DRIVER/UE_IP/netlink.c index 8ecd989f4d..e8e36619d1 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/netlink.c +++ b/openair2/NETWORK_DRIVER/UE_IP/netlink.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/UE_IP/proto_extern.h b/openair2/NETWORK_DRIVER/UE_IP/proto_extern.h index 459fbc0837..b335b019c1 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/proto_extern.h +++ b/openair2/NETWORK_DRIVER/UE_IP/proto_extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/NETWORK_DRIVER/UE_IP/sap.h b/openair2/NETWORK_DRIVER/UE_IP/sap.h index cfe4bf81b8..ad70386ed7 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/sap.h +++ b/openair2/NETWORK_DRIVER/UE_IP/sap.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/PHY_INTERFACE/defs.h b/openair2/PHY_INTERFACE/defs.h index effc4c7877..a889df4ed0 100644 --- a/openair2/PHY_INTERFACE/defs.h +++ b/openair2/PHY_INTERFACE/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/PHY_INTERFACE/extern.h b/openair2/PHY_INTERFACE/extern.h index f75d716b63..e6862b98fa 100644 --- a/openair2/PHY_INTERFACE/extern.h +++ b/openair2/PHY_INTERFACE/extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/PHY_INTERFACE/mac_phy_primitives.c b/openair2/PHY_INTERFACE/mac_phy_primitives.c index d9693e3d5e..3d42393d11 100644 --- a/openair2/PHY_INTERFACE/mac_phy_primitives.c +++ b/openair2/PHY_INTERFACE/mac_phy_primitives.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/PHY_INTERFACE/mac_phy_primitives.h b/openair2/PHY_INTERFACE/mac_phy_primitives.h index 02ff1fceac..889cb503dc 100644 --- a/openair2/PHY_INTERFACE/mac_phy_primitives.h +++ b/openair2/PHY_INTERFACE/mac_phy_primitives.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/PHY_INTERFACE/vars.h b/openair2/PHY_INTERFACE/vars.h index 810d073a23..736d6f89db 100644 --- a/openair2/PHY_INTERFACE/vars.h +++ b/openair2/PHY_INTERFACE/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.c b/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.c index 222b9f7b41..8d69b6e76b 100644 --- a/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.c +++ b/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.h b/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.h index c2325f99bd..b13d72f980 100644 --- a/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.h +++ b/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/L2_interface.c b/openair2/RRC/LITE/L2_interface.c index 64734cac9a..78089be273 100644 --- a/openair2/RRC/LITE/L2_interface.c +++ b/openair2/RRC/LITE/L2_interface.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index 8f4d1ba66d..0b5d818825 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.h b/openair2/RRC/LITE/MESSAGES/asn1_msg.h index 4466457075..47c1f661bd 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.h +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/MESSAGES/rtai_mem.c b/openair2/RRC/LITE/MESSAGES/rtai_mem.c index 0319baafc3..c522a1f0bf 100644 --- a/openair2/RRC/LITE/MESSAGES/rtai_mem.c +++ b/openair2/RRC/LITE/MESSAGES/rtai_mem.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/MESSAGES/rtai_mem.h b/openair2/RRC/LITE/MESSAGES/rtai_mem.h index 19ed4c1a69..9efc24851f 100644 --- a/openair2/RRC/LITE/MESSAGES/rtai_mem.h +++ b/openair2/RRC/LITE/MESSAGES/rtai_mem.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index 0a2043fd4e..3fb6e0254d 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/extern.h b/openair2/RRC/LITE/extern.h index d4c8192a95..8a8ff1d92f 100644 --- a/openair2/RRC/LITE/extern.h +++ b/openair2/RRC/LITE/extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/mesh_top.c b/openair2/RRC/LITE/mesh_top.c index 448d15bfae..16395e99c6 100644 --- a/openair2/RRC/LITE/mesh_top.c +++ b/openair2/RRC/LITE/mesh_top.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/plmn_data.h b/openair2/RRC/LITE/plmn_data.h index 3994a851fb..97dc94343b 100644 --- a/openair2/RRC/LITE/plmn_data.h +++ b/openair2/RRC/LITE/plmn_data.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/proto.h b/openair2/RRC/LITE/proto.h index 8433980be4..52c7afca27 100644 --- a/openair2/RRC/LITE/proto.h +++ b/openair2/RRC/LITE/proto.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_2_rrm_msg.c b/openair2/RRC/LITE/rrc_2_rrm_msg.c index 9a5c14f91e..87a0a3557b 100644 --- a/openair2/RRC/LITE/rrc_2_rrm_msg.c +++ b/openair2/RRC/LITE/rrc_2_rrm_msg.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index 6798212fb2..5f533b41b0 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_UE_ral.c b/openair2/RRC/LITE/rrc_UE_ral.c index be327551db..0cb0943fcb 100644 --- a/openair2/RRC/LITE/rrc_UE_ral.c +++ b/openair2/RRC/LITE/rrc_UE_ral.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_UE_ral.h b/openair2/RRC/LITE/rrc_UE_ral.h index d403ba112b..e2b4a3dadb 100644 --- a/openair2/RRC/LITE/rrc_UE_ral.h +++ b/openair2/RRC/LITE/rrc_UE_ral.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_common.c b/openair2/RRC/LITE/rrc_common.c index 3f7fa3067c..cfd53a996b 100644 --- a/openair2/RRC/LITE/rrc_common.c +++ b/openair2/RRC/LITE/rrc_common.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_config.c b/openair2/RRC/LITE/rrc_config.c index 518c011848..a627ba88e0 100644 --- a/openair2/RRC/LITE/rrc_config.c +++ b/openair2/RRC/LITE/rrc_config.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 659f1c57b0..3c6ee21041 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_eNB_GTPV1U.c b/openair2/RRC/LITE/rrc_eNB_GTPV1U.c index 8b1110475f..611ca72385 100644 --- a/openair2/RRC/LITE/rrc_eNB_GTPV1U.c +++ b/openair2/RRC/LITE/rrc_eNB_GTPV1U.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_eNB_GTPV1U.h b/openair2/RRC/LITE/rrc_eNB_GTPV1U.h index b0c713d6ef..981c3f8d3b 100644 --- a/openair2/RRC/LITE/rrc_eNB_GTPV1U.h +++ b/openair2/RRC/LITE/rrc_eNB_GTPV1U.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_eNB_S1AP.c b/openair2/RRC/LITE/rrc_eNB_S1AP.c index f3c22abeff..866c76a4ed 100644 --- a/openair2/RRC/LITE/rrc_eNB_S1AP.c +++ b/openair2/RRC/LITE/rrc_eNB_S1AP.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_eNB_S1AP.h b/openair2/RRC/LITE/rrc_eNB_S1AP.h index a57002010c..6b2de919bd 100644 --- a/openair2/RRC/LITE/rrc_eNB_S1AP.h +++ b/openair2/RRC/LITE/rrc_eNB_S1AP.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_eNB_UE_context.c b/openair2/RRC/LITE/rrc_eNB_UE_context.c index c0243ca6bf..1c0bf36fb2 100644 --- a/openair2/RRC/LITE/rrc_eNB_UE_context.c +++ b/openair2/RRC/LITE/rrc_eNB_UE_context.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_eNB_UE_context.h b/openair2/RRC/LITE/rrc_eNB_UE_context.h index 808628f67c..0e813cdee5 100644 --- a/openair2/RRC/LITE/rrc_eNB_UE_context.h +++ b/openair2/RRC/LITE/rrc_eNB_UE_context.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_eNB_ral.c b/openair2/RRC/LITE/rrc_eNB_ral.c index 32160d8c42..94e25a6eeb 100644 --- a/openair2/RRC/LITE/rrc_eNB_ral.c +++ b/openair2/RRC/LITE/rrc_eNB_ral.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_eNB_ral.h b/openair2/RRC/LITE/rrc_eNB_ral.h index 8501758ba3..143537e45c 100644 --- a/openair2/RRC/LITE/rrc_eNB_ral.h +++ b/openair2/RRC/LITE/rrc_eNB_ral.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_rrm_interface.c b/openair2/RRC/LITE/rrc_rrm_interface.c index 79d0c5eee8..822ce554af 100644 --- a/openair2/RRC/LITE/rrc_rrm_interface.c +++ b/openair2/RRC/LITE/rrc_rrm_interface.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_rrm_interface.h b/openair2/RRC/LITE/rrc_rrm_interface.h index 6a566f150d..d204ab2db6 100644 --- a/openair2/RRC/LITE/rrc_rrm_interface.h +++ b/openair2/RRC/LITE/rrc_rrm_interface.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_types.h b/openair2/RRC/LITE/rrc_types.h index 64d143a278..9c1e37494f 100644 --- a/openair2/RRC/LITE/rrc_types.h +++ b/openair2/RRC/LITE/rrc_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrm_2_rrc_msg.c b/openair2/RRC/LITE/rrm_2_rrc_msg.c index 738f2a70f6..3ef0bc2e0a 100644 --- a/openair2/RRC/LITE/rrm_2_rrc_msg.c +++ b/openair2/RRC/LITE/rrm_2_rrc_msg.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/utils.c b/openair2/RRC/LITE/utils.c index 832a61979a..fd37fdf65c 100644 --- a/openair2/RRC/LITE/utils.c +++ b/openair2/RRC/LITE/utils.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/vars.h b/openair2/RRC/LITE/vars.h index 71b00b278c..1b61cd462c 100644 --- a/openair2/RRC/LITE/vars.h +++ b/openair2/RRC/LITE/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/NAS/nas_config.c b/openair2/RRC/NAS/nas_config.c index 07d65312e5..3f825760da 100644 --- a/openair2/RRC/NAS/nas_config.c +++ b/openair2/RRC/NAS/nas_config.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/NAS/nas_config.h b/openair2/RRC/NAS/nas_config.h index 2276638581..4426ca9a1a 100644 --- a/openair2/RRC/NAS/nas_config.h +++ b/openair2/RRC/NAS/nas_config.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/NAS/rb_config.c b/openair2/RRC/NAS/rb_config.c index da80ea108d..3431137f74 100644 --- a/openair2/RRC/NAS/rb_config.c +++ b/openair2/RRC/NAS/rb_config.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/NAS/rb_config.h b/openair2/RRC/NAS/rb_config.h index a4525b2d65..6af42bac45 100644 --- a/openair2/RRC/NAS/rb_config.h +++ b/openair2/RRC/NAS/rb_config.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/ASYNC_IF/link_manager.c b/openair2/UTIL/ASYNC_IF/link_manager.c index 235acef247..52a4f90ce0 100644 --- a/openair2/UTIL/ASYNC_IF/link_manager.c +++ b/openair2/UTIL/ASYNC_IF/link_manager.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/ASYNC_IF/link_manager.h b/openair2/UTIL/ASYNC_IF/link_manager.h index a25c072b41..90ede6c3db 100644 --- a/openair2/UTIL/ASYNC_IF/link_manager.h +++ b/openair2/UTIL/ASYNC_IF/link_manager.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/ASYNC_IF/message_queue.c b/openair2/UTIL/ASYNC_IF/message_queue.c index ee6c92d852..55b7a104cd 100644 --- a/openair2/UTIL/ASYNC_IF/message_queue.c +++ b/openair2/UTIL/ASYNC_IF/message_queue.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/ASYNC_IF/message_queue.h b/openair2/UTIL/ASYNC_IF/message_queue.h index 4e46ec08d6..8fedddcc77 100644 --- a/openair2/UTIL/ASYNC_IF/message_queue.h +++ b/openair2/UTIL/ASYNC_IF/message_queue.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c index 047e3f716c..1a3701ed5c 100644 --- a/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c +++ b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h index 7dc4637404..185d23daf5 100644 --- a/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h +++ b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/ASYNC_IF/socket_link.c b/openair2/UTIL/ASYNC_IF/socket_link.c index 720a55398c..60b03d7d43 100644 --- a/openair2/UTIL/ASYNC_IF/socket_link.c +++ b/openair2/UTIL/ASYNC_IF/socket_link.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/ASYNC_IF/socket_link.h b/openair2/UTIL/ASYNC_IF/socket_link.h index 5b9f438c8a..dbe0a69370 100644 --- a/openair2/UTIL/ASYNC_IF/socket_link.h +++ b/openair2/UTIL/ASYNC_IF/socket_link.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/BIGPHYS/bigphys.c b/openair2/UTIL/BIGPHYS/bigphys.c index 92a0a8bef8..219a0c8d1b 100644 --- a/openair2/UTIL/BIGPHYS/bigphys.c +++ b/openair2/UTIL/BIGPHYS/bigphys.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/BIGPHYS/defs.h b/openair2/UTIL/BIGPHYS/defs.h index 01387cb001..69368a6d72 100644 --- a/openair2/UTIL/BIGPHYS/defs.h +++ b/openair2/UTIL/BIGPHYS/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/CLI/cli.c b/openair2/UTIL/CLI/cli.c index bb193728c9..27bb3c2146 100644 --- a/openair2/UTIL/CLI/cli.c +++ b/openair2/UTIL/CLI/cli.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/CLI/cli.h b/openair2/UTIL/CLI/cli.h index 70aab5c4da..c9052ead6f 100644 --- a/openair2/UTIL/CLI/cli.h +++ b/openair2/UTIL/CLI/cli.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/CLI/cli_cmd.c b/openair2/UTIL/CLI/cli_cmd.c index 366295bf1a..5945a2eae1 100644 --- a/openair2/UTIL/CLI/cli_cmd.c +++ b/openair2/UTIL/CLI/cli_cmd.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/CLI/cli_if.h b/openair2/UTIL/CLI/cli_if.h index 129176cd2c..539ecd465a 100644 --- a/openair2/UTIL/CLI/cli_if.h +++ b/openair2/UTIL/CLI/cli_if.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/CLI/cli_server.c b/openair2/UTIL/CLI/cli_server.c index 43ffac0a53..d4f97f15ba 100644 --- a/openair2/UTIL/CLI/cli_server.c +++ b/openair2/UTIL/CLI/cli_server.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/FIFO/pad_list.c b/openair2/UTIL/FIFO/pad_list.c index f60505f8ce..32a9f35196 100644 --- a/openair2/UTIL/FIFO/pad_list.c +++ b/openair2/UTIL/FIFO/pad_list.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/FIFO/pad_list.h b/openair2/UTIL/FIFO/pad_list.h index 4f755f9940..ecafed7cc4 100644 --- a/openair2/UTIL/FIFO/pad_list.h +++ b/openair2/UTIL/FIFO/pad_list.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/FIFO/types.h b/openair2/UTIL/FIFO/types.h index 23d69ff3a6..f949b2b72b 100644 --- a/openair2/UTIL/FIFO/types.h +++ b/openair2/UTIL/FIFO/types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/LISTS/list.c b/openair2/UTIL/LISTS/list.c index 7040aeeef7..65f70c0786 100644 --- a/openair2/UTIL/LISTS/list.c +++ b/openair2/UTIL/LISTS/list.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/LISTS/list.h b/openair2/UTIL/LISTS/list.h index 189de84aeb..864804c591 100644 --- a/openair2/UTIL/LISTS/list.h +++ b/openair2/UTIL/LISTS/list.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/LISTS/list2.c b/openair2/UTIL/LISTS/list2.c index 8daa19bfa4..875f5e2d2f 100644 --- a/openair2/UTIL/LISTS/list2.c +++ b/openair2/UTIL/LISTS/list2.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/LOG/log.c b/openair2/UTIL/LOG/log.c index 9c28c4b68d..3fa5b5cdf3 100644 --- a/openair2/UTIL/LOG/log.c +++ b/openair2/UTIL/LOG/log.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/LOG/log.h b/openair2/UTIL/LOG/log.h index 86abb5eab6..3fcc5fe444 100644 --- a/openair2/UTIL/LOG/log.h +++ b/openair2/UTIL/LOG/log.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/LOG/log_extern.h b/openair2/UTIL/LOG/log_extern.h index 39324de4e2..611487ffea 100644 --- a/openair2/UTIL/LOG/log_extern.h +++ b/openair2/UTIL/LOG/log_extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/LOG/log_if.h b/openair2/UTIL/LOG/log_if.h index 6338fab829..531b9df62e 100644 --- a/openair2/UTIL/LOG/log_if.h +++ b/openair2/UTIL/LOG/log_if.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.c b/openair2/UTIL/LOG/vcd_signal_dumper.c index 38d7d7a276..e4394c4091 100644 --- a/openair2/UTIL/LOG/vcd_signal_dumper.c +++ b/openair2/UTIL/LOG/vcd_signal_dumper.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.h b/openair2/UTIL/LOG/vcd_signal_dumper.h index 6a4cb6d75f..a6211e7e95 100644 --- a/openair2/UTIL/LOG/vcd_signal_dumper.h +++ b/openair2/UTIL/LOG/vcd_signal_dumper.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/MATH/crc_byte.c b/openair2/UTIL/MATH/crc_byte.c index b7e537163c..a3ff00fec1 100644 --- a/openair2/UTIL/MATH/crc_byte.c +++ b/openair2/UTIL/MATH/crc_byte.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/MATH/oml.c b/openair2/UTIL/MATH/oml.c index 5794b7876a..70e1a87cdc 100644 --- a/openair2/UTIL/MATH/oml.c +++ b/openair2/UTIL/MATH/oml.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/MATH/oml.h b/openair2/UTIL/MATH/oml.h index 2a057a93fc..70f677a559 100644 --- a/openair2/UTIL/MATH/oml.h +++ b/openair2/UTIL/MATH/oml.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/MATH/random.c b/openair2/UTIL/MATH/random.c index c2db287679..06caa3bc3c 100644 --- a/openair2/UTIL/MATH/random.c +++ b/openair2/UTIL/MATH/random.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/MATH/random_proto_extern.h b/openair2/UTIL/MATH/random_proto_extern.h index 17ea22e461..45db565217 100644 --- a/openair2/UTIL/MATH/random_proto_extern.h +++ b/openair2/UTIL/MATH/random_proto_extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/MATH/taus.c b/openair2/UTIL/MATH/taus.c index 1f3a64aa84..6e0fd84e66 100644 --- a/openair2/UTIL/MATH/taus.c +++ b/openair2/UTIL/MATH/taus.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/MEM/mem_block.c b/openair2/UTIL/MEM/mem_block.c index 150f19b71c..a589e9fd72 100644 --- a/openair2/UTIL/MEM/mem_block.c +++ b/openair2/UTIL/MEM/mem_block.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/MEM/mem_block.h b/openair2/UTIL/MEM/mem_block.h index c3a2f5dff2..b7e36bf5b3 100644 --- a/openair2/UTIL/MEM/mem_block.h +++ b/openair2/UTIL/MEM/mem_block.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/MEM/mem_mngt.c b/openair2/UTIL/MEM/mem_mngt.c index 9f4f57cdd2..49cd310ac9 100644 --- a/openair2/UTIL/MEM/mem_mngt.c +++ b/openair2/UTIL/MEM/mem_mngt.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/MEM/mem_mngt_proto_extern.h b/openair2/UTIL/MEM/mem_mngt_proto_extern.h index f4f8a2eaae..4690bba42e 100644 --- a/openair2/UTIL/MEM/mem_mngt_proto_extern.h +++ b/openair2/UTIL/MEM/mem_mngt_proto_extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/MEM/mem_pool.h b/openair2/UTIL/MEM/mem_pool.h index 0e943081b0..cc0face78c 100644 --- a/openair2/UTIL/MEM/mem_pool.h +++ b/openair2/UTIL/MEM/mem_pool.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG.c b/openair2/UTIL/OCG/OCG.c index a78b49dd84..c3665c93f5 100644 --- a/openair2/UTIL/OCG/OCG.c +++ b/openair2/UTIL/OCG/OCG.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG.h b/openair2/UTIL/OCG/OCG.h index bd53c179ff..4f5cd26cc2 100644 --- a/openair2/UTIL/OCG/OCG.h +++ b/openair2/UTIL/OCG/OCG.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_call_emu.c b/openair2/UTIL/OCG/OCG_call_emu.c index 2ce1818b12..b6a2c924bf 100644 --- a/openair2/UTIL/OCG/OCG_call_emu.c +++ b/openair2/UTIL/OCG/OCG_call_emu.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_call_emu.h b/openair2/UTIL/OCG/OCG_call_emu.h index c27f3c1b06..c7b2bb4327 100644 --- a/openair2/UTIL/OCG/OCG_call_emu.h +++ b/openair2/UTIL/OCG/OCG_call_emu.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_config_mobi.c b/openair2/UTIL/OCG/OCG_config_mobi.c index ae53b61955..cef4c5543b 100644 --- a/openair2/UTIL/OCG/OCG_config_mobi.c +++ b/openair2/UTIL/OCG/OCG_config_mobi.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_config_mobi.h b/openair2/UTIL/OCG/OCG_config_mobi.h index ab7048b2b0..fbaeb4b281 100644 --- a/openair2/UTIL/OCG/OCG_config_mobi.h +++ b/openair2/UTIL/OCG/OCG_config_mobi.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_create_dir.c b/openair2/UTIL/OCG/OCG_create_dir.c index cfbf26a21d..364887163b 100644 --- a/openair2/UTIL/OCG/OCG_create_dir.c +++ b/openair2/UTIL/OCG/OCG_create_dir.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_create_dir.h b/openair2/UTIL/OCG/OCG_create_dir.h index c8f3729c47..692f4b095e 100644 --- a/openair2/UTIL/OCG/OCG_create_dir.h +++ b/openair2/UTIL/OCG/OCG_create_dir.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_detect_file.c b/openair2/UTIL/OCG/OCG_detect_file.c index a7226a67db..034f173b77 100644 --- a/openair2/UTIL/OCG/OCG_detect_file.c +++ b/openair2/UTIL/OCG/OCG_detect_file.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_detect_file.h b/openair2/UTIL/OCG/OCG_detect_file.h index 43aa22040e..3a43b50552 100644 --- a/openair2/UTIL/OCG/OCG_detect_file.h +++ b/openair2/UTIL/OCG/OCG_detect_file.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_extern.h b/openair2/UTIL/OCG/OCG_extern.h index 58eac66263..25fea4e90e 100644 --- a/openair2/UTIL/OCG/OCG_extern.h +++ b/openair2/UTIL/OCG/OCG_extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_generate_report.c b/openair2/UTIL/OCG/OCG_generate_report.c index 320fa0c5df..fa1ed191e6 100644 --- a/openair2/UTIL/OCG/OCG_generate_report.c +++ b/openair2/UTIL/OCG/OCG_generate_report.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_generate_report.h b/openair2/UTIL/OCG/OCG_generate_report.h index c3fd5f9540..a67adf70c7 100644 --- a/openair2/UTIL/OCG/OCG_generate_report.h +++ b/openair2/UTIL/OCG/OCG_generate_report.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_get_opt.c b/openair2/UTIL/OCG/OCG_get_opt.c index 79bce055c6..0d52197d13 100644 --- a/openair2/UTIL/OCG/OCG_get_opt.c +++ b/openair2/UTIL/OCG/OCG_get_opt.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_get_opt.h b/openair2/UTIL/OCG/OCG_get_opt.h index 5ae9d51627..7fdab0c574 100644 --- a/openair2/UTIL/OCG/OCG_get_opt.h +++ b/openair2/UTIL/OCG/OCG_get_opt.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_if.h b/openair2/UTIL/OCG/OCG_if.h index 0635356a4d..c515d9746d 100644 --- a/openair2/UTIL/OCG/OCG_if.h +++ b/openair2/UTIL/OCG/OCG_if.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_parse_XML.c b/openair2/UTIL/OCG/OCG_parse_XML.c index ea35db7c8d..e52bf402db 100644 --- a/openair2/UTIL/OCG/OCG_parse_XML.c +++ b/openair2/UTIL/OCG/OCG_parse_XML.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_parse_XML.h b/openair2/UTIL/OCG/OCG_parse_XML.h index 3133f98a29..cb74a9fe1e 100644 --- a/openair2/UTIL/OCG/OCG_parse_XML.h +++ b/openair2/UTIL/OCG/OCG_parse_XML.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_parse_filename.c b/openair2/UTIL/OCG/OCG_parse_filename.c index 1ee3c18233..1ecad56e20 100644 --- a/openair2/UTIL/OCG/OCG_parse_filename.c +++ b/openair2/UTIL/OCG/OCG_parse_filename.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_parse_filename.h b/openair2/UTIL/OCG/OCG_parse_filename.h index 09ca9088b9..bcc8cd11ed 100644 --- a/openair2/UTIL/OCG/OCG_parse_filename.h +++ b/openair2/UTIL/OCG/OCG_parse_filename.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_save_XML.c b/openair2/UTIL/OCG/OCG_save_XML.c index a7f88d364a..2b0d907cdf 100644 --- a/openair2/UTIL/OCG/OCG_save_XML.c +++ b/openair2/UTIL/OCG/OCG_save_XML.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_save_XML.h b/openair2/UTIL/OCG/OCG_save_XML.h index b90b2b30f7..ba2d9240ca 100644 --- a/openair2/UTIL/OCG/OCG_save_XML.h +++ b/openair2/UTIL/OCG/OCG_save_XML.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/OCG_vars.h b/openair2/UTIL/OCG/OCG_vars.h index 383e4e2551..947a90715c 100644 --- a/openair2/UTIL/OCG/OCG_vars.h +++ b/openair2/UTIL/OCG/OCG_vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OCG/readme.txt b/openair2/UTIL/OCG/readme.txt index 88743539f8..35300aa39f 100644 --- a/openair2/UTIL/OCG/readme.txt +++ b/openair2/UTIL/OCG/readme.txt @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/common.c b/openair2/UTIL/OMG/common.c index f1c850e689..fa6e70df56 100644 --- a/openair2/UTIL/OMG/common.c +++ b/openair2/UTIL/OMG/common.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/defs.h b/openair2/UTIL/OMG/defs.h index 2a76d7dd6e..96700e6e9c 100644 --- a/openair2/UTIL/OMG/defs.h +++ b/openair2/UTIL/OMG/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/grid.c b/openair2/UTIL/OMG/grid.c index 4f2dbf24ef..6cfcde663b 100644 --- a/openair2/UTIL/OMG/grid.c +++ b/openair2/UTIL/OMG/grid.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/grid.h b/openair2/UTIL/OMG/grid.h index d7352491fe..55c4857801 100644 --- a/openair2/UTIL/OMG/grid.h +++ b/openair2/UTIL/OMG/grid.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/job.c b/openair2/UTIL/OMG/job.c index 82a3096c03..1df44cb2c0 100644 --- a/openair2/UTIL/OMG/job.c +++ b/openair2/UTIL/OMG/job.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/mobility_parser.c b/openair2/UTIL/OMG/mobility_parser.c index 1013d6302a..31496af956 100644 --- a/openair2/UTIL/OMG/mobility_parser.c +++ b/openair2/UTIL/OMG/mobility_parser.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/mobility_parser.h b/openair2/UTIL/OMG/mobility_parser.h index 84d40264f4..403d7886ce 100644 --- a/openair2/UTIL/OMG/mobility_parser.h +++ b/openair2/UTIL/OMG/mobility_parser.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/omg.c b/openair2/UTIL/OMG/omg.c index a6d4b74d17..83f38f13d5 100644 --- a/openair2/UTIL/OMG/omg.c +++ b/openair2/UTIL/OMG/omg.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/omg.h b/openair2/UTIL/OMG/omg.h index 9ff69730f0..07dbf1f750 100644 --- a/openair2/UTIL/OMG/omg.h +++ b/openair2/UTIL/OMG/omg.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/omg_constants.h b/openair2/UTIL/OMG/omg_constants.h index 0bee58db7a..1d70551b03 100644 --- a/openair2/UTIL/OMG/omg_constants.h +++ b/openair2/UTIL/OMG/omg_constants.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/omg_hashtable.c b/openair2/UTIL/OMG/omg_hashtable.c index b237676e71..32b3840af3 100644 --- a/openair2/UTIL/OMG/omg_hashtable.c +++ b/openair2/UTIL/OMG/omg_hashtable.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/omg_hashtable.h b/openair2/UTIL/OMG/omg_hashtable.h index 894a245efd..238be879fd 100644 --- a/openair2/UTIL/OMG/omg_hashtable.h +++ b/openair2/UTIL/OMG/omg_hashtable.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/omg_vars.h b/openair2/UTIL/OMG/omg_vars.h index 861395771f..bf0a13e5b5 100644 --- a/openair2/UTIL/OMG/omg_vars.h +++ b/openair2/UTIL/OMG/omg_vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/rwalk.c b/openair2/UTIL/OMG/rwalk.c index 6e758dbfa7..8c8840a91f 100644 --- a/openair2/UTIL/OMG/rwalk.c +++ b/openair2/UTIL/OMG/rwalk.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/rwalk.h b/openair2/UTIL/OMG/rwalk.h index 482cecd0c9..114f8a48f9 100644 --- a/openair2/UTIL/OMG/rwalk.h +++ b/openair2/UTIL/OMG/rwalk.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/rwp.c b/openair2/UTIL/OMG/rwp.c index 4a03dabc78..8e5ab43081 100644 --- a/openair2/UTIL/OMG/rwp.c +++ b/openair2/UTIL/OMG/rwp.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/rwp.h b/openair2/UTIL/OMG/rwp.h index 4d5695cc80..4a6c32cd56 100644 --- a/openair2/UTIL/OMG/rwp.h +++ b/openair2/UTIL/OMG/rwp.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/static.c b/openair2/UTIL/OMG/static.c index 8a94a74294..361fa969e9 100644 --- a/openair2/UTIL/OMG/static.c +++ b/openair2/UTIL/OMG/static.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/static.h b/openair2/UTIL/OMG/static.h index b2c8904e8a..b7fa800968 100644 --- a/openair2/UTIL/OMG/static.h +++ b/openair2/UTIL/OMG/static.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/steadystaterwp.c b/openair2/UTIL/OMG/steadystaterwp.c index 428ad7dce7..d4d2fde4e4 100644 --- a/openair2/UTIL/OMG/steadystaterwp.c +++ b/openair2/UTIL/OMG/steadystaterwp.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/steadystaterwp.h b/openair2/UTIL/OMG/steadystaterwp.h index b73c7b1593..08bca4d28e 100644 --- a/openair2/UTIL/OMG/steadystaterwp.h +++ b/openair2/UTIL/OMG/steadystaterwp.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/trace.c b/openair2/UTIL/OMG/trace.c index 4a71999fb9..e86d8102e5 100644 --- a/openair2/UTIL/OMG/trace.c +++ b/openair2/UTIL/OMG/trace.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/trace.h b/openair2/UTIL/OMG/trace.h index c7d0528d94..f1a4a4a274 100644 --- a/openair2/UTIL/OMG/trace.h +++ b/openair2/UTIL/OMG/trace.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/trace_hashtable.c b/openair2/UTIL/OMG/trace_hashtable.c index 0595a1d432..9a7a67feef 100644 --- a/openair2/UTIL/OMG/trace_hashtable.c +++ b/openair2/UTIL/OMG/trace_hashtable.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMG/trace_hashtable.h b/openair2/UTIL/OMG/trace_hashtable.h index d57e65956f..b842880e29 100644 --- a/openair2/UTIL/OMG/trace_hashtable.h +++ b/openair2/UTIL/OMG/trace_hashtable.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMV/communicationthread.cpp b/openair2/UTIL/OMV/communicationthread.cpp index 4b30e32b71..17bc932a55 100644 --- a/openair2/UTIL/OMV/communicationthread.cpp +++ b/openair2/UTIL/OMV/communicationthread.cpp @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMV/communicationthread.h b/openair2/UTIL/OMV/communicationthread.h index 19c1a242e5..b27f402435 100644 --- a/openair2/UTIL/OMV/communicationthread.h +++ b/openair2/UTIL/OMV/communicationthread.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMV/mywindow.cpp b/openair2/UTIL/OMV/mywindow.cpp index 4cbfbbacb1..5a1c082975 100644 --- a/openair2/UTIL/OMV/mywindow.cpp +++ b/openair2/UTIL/OMV/mywindow.cpp @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMV/mywindow.h b/openair2/UTIL/OMV/mywindow.h index a36beaf8c2..21cd001004 100644 --- a/openair2/UTIL/OMV/mywindow.h +++ b/openair2/UTIL/OMV/mywindow.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMV/omv.cpp b/openair2/UTIL/OMV/omv.cpp index c4fc586783..6d65d2a154 100644 --- a/openair2/UTIL/OMV/omv.cpp +++ b/openair2/UTIL/OMV/omv.cpp @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMV/openglwidget.cpp b/openair2/UTIL/OMV/openglwidget.cpp index d86767486d..ad0ce2b835 100644 --- a/openair2/UTIL/OMV/openglwidget.cpp +++ b/openair2/UTIL/OMV/openglwidget.cpp @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMV/openglwidget.h b/openair2/UTIL/OMV/openglwidget.h index b7069c63ea..a0e14b4db3 100644 --- a/openair2/UTIL/OMV/openglwidget.h +++ b/openair2/UTIL/OMV/openglwidget.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OMV/structures.h b/openair2/UTIL/OMV/structures.h index 434fa4c383..ee33632059 100644 --- a/openair2/UTIL/OMV/structures.h +++ b/openair2/UTIL/OMV/structures.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OPT/opt.h b/openair2/UTIL/OPT/opt.h index 0d2ab89e2a..b131d80539 100644 --- a/openair2/UTIL/OPT/opt.h +++ b/openair2/UTIL/OPT/opt.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OPT/vars.h b/openair2/UTIL/OPT/vars.h index e8ca8c5fc6..0da315aa8b 100644 --- a/openair2/UTIL/OPT/vars.h +++ b/openair2/UTIL/OPT/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OSA/osa_defs.h b/openair2/UTIL/OSA/osa_defs.h index ef714cdc0f..4812d82d91 100644 --- a/openair2/UTIL/OSA/osa_defs.h +++ b/openair2/UTIL/OSA/osa_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OSA/osa_internal.h b/openair2/UTIL/OSA/osa_internal.h index 867b537826..1f5aab5df8 100644 --- a/openair2/UTIL/OSA/osa_internal.h +++ b/openair2/UTIL/OSA/osa_internal.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OSA/osa_key_deriver.c b/openair2/UTIL/OSA/osa_key_deriver.c index 5bbaf5f17d..cf181b7a99 100644 --- a/openair2/UTIL/OSA/osa_key_deriver.c +++ b/openair2/UTIL/OSA/osa_key_deriver.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OSA/osa_rijndael.c b/openair2/UTIL/OSA/osa_rijndael.c index a460ac3568..cbcbdab5be 100644 --- a/openair2/UTIL/OSA/osa_rijndael.c +++ b/openair2/UTIL/OSA/osa_rijndael.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OSA/osa_rijndael.h b/openair2/UTIL/OSA/osa_rijndael.h index f8fcb13427..8c802b1247 100644 --- a/openair2/UTIL/OSA/osa_rijndael.h +++ b/openair2/UTIL/OSA/osa_rijndael.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OSA/osa_snow3g.c b/openair2/UTIL/OSA/osa_snow3g.c index 7d25c069fc..c69e80a1fb 100644 --- a/openair2/UTIL/OSA/osa_snow3g.c +++ b/openair2/UTIL/OSA/osa_snow3g.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OSA/osa_snow3g.h b/openair2/UTIL/OSA/osa_snow3g.h index 7107317084..5da81d23f3 100644 --- a/openair2/UTIL/OSA/osa_snow3g.h +++ b/openair2/UTIL/OSA/osa_snow3g.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OSA/osa_stream_eea.c b/openair2/UTIL/OSA/osa_stream_eea.c index 6aef6d2588..e922ed3c86 100644 --- a/openair2/UTIL/OSA/osa_stream_eea.c +++ b/openair2/UTIL/OSA/osa_stream_eea.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OSA/osa_stream_eia.c b/openair2/UTIL/OSA/osa_stream_eia.c index 9830541006..e58e280ef7 100644 --- a/openair2/UTIL/OSA/osa_stream_eia.c +++ b/openair2/UTIL/OSA/osa_stream_eia.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OSD/recep.php b/openair2/UTIL/OSD/recep.php index f824a327cf..eb1036acad 100644 --- a/openair2/UTIL/OSD/recep.php +++ b/openair2/UTIL/OSD/recep.php @@ -4,7 +4,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/main.c b/openair2/UTIL/OTG/main.c index 529755300a..1ee9b0edd7 100644 --- a/openair2/UTIL/OTG/main.c +++ b/openair2/UTIL/OTG/main.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg.c b/openair2/UTIL/OTG/otg.c index 2043eb1048..04e0463971 100644 --- a/openair2/UTIL/OTG/otg.c +++ b/openair2/UTIL/OTG/otg.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg.h b/openair2/UTIL/OTG/otg.h index 0cd64aeef2..7938a2a0d7 100644 --- a/openair2/UTIL/OTG/otg.h +++ b/openair2/UTIL/OTG/otg.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_config.h b/openair2/UTIL/OTG/otg_config.h index 880f69bf16..2302c71f00 100644 --- a/openair2/UTIL/OTG/otg_config.h +++ b/openair2/UTIL/OTG/otg_config.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_defs.h b/openair2/UTIL/OTG/otg_defs.h index ebb3f29989..fad0d9510e 100644 --- a/openair2/UTIL/OTG/otg_defs.h +++ b/openair2/UTIL/OTG/otg_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_externs.h b/openair2/UTIL/OTG/otg_externs.h index 053b8f55a1..ea5943888f 100644 --- a/openair2/UTIL/OTG/otg_externs.h +++ b/openair2/UTIL/OTG/otg_externs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_form.c b/openair2/UTIL/OTG/otg_form.c index 7eb83b8ce4..6994e65896 100644 --- a/openair2/UTIL/OTG/otg_form.c +++ b/openair2/UTIL/OTG/otg_form.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_form.h b/openair2/UTIL/OTG/otg_form.h index e073f41457..1292184bde 100644 --- a/openair2/UTIL/OTG/otg_form.h +++ b/openair2/UTIL/OTG/otg_form.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_kpi.c b/openair2/UTIL/OTG/otg_kpi.c index 3f24d01ce6..94a0a53d5c 100644 --- a/openair2/UTIL/OTG/otg_kpi.c +++ b/openair2/UTIL/OTG/otg_kpi.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_kpi.h b/openair2/UTIL/OTG/otg_kpi.h index d3e830fe12..2273d10c72 100644 --- a/openair2/UTIL/OTG/otg_kpi.h +++ b/openair2/UTIL/OTG/otg_kpi.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_models.c b/openair2/UTIL/OTG/otg_models.c index f60cf926fe..d866713ecb 100644 --- a/openair2/UTIL/OTG/otg_models.c +++ b/openair2/UTIL/OTG/otg_models.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_models.h b/openair2/UTIL/OTG/otg_models.h index 2e7351f400..03b139d658 100644 --- a/openair2/UTIL/OTG/otg_models.h +++ b/openair2/UTIL/OTG/otg_models.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_rx.c b/openair2/UTIL/OTG/otg_rx.c index 824439e873..a9af82b5c3 100644 --- a/openair2/UTIL/OTG/otg_rx.c +++ b/openair2/UTIL/OTG/otg_rx.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_rx.h b/openair2/UTIL/OTG/otg_rx.h index 2f92ab82ce..770d053ada 100644 --- a/openair2/UTIL/OTG/otg_rx.h +++ b/openair2/UTIL/OTG/otg_rx.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_rx_socket.c b/openair2/UTIL/OTG/otg_rx_socket.c index 98e03532a1..88ecd3e904 100644 --- a/openair2/UTIL/OTG/otg_rx_socket.c +++ b/openair2/UTIL/OTG/otg_rx_socket.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_rx_socket.h b/openair2/UTIL/OTG/otg_rx_socket.h index 5c64a79008..e7062aaf58 100644 --- a/openair2/UTIL/OTG/otg_rx_socket.h +++ b/openair2/UTIL/OTG/otg_rx_socket.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_tx.c b/openair2/UTIL/OTG/otg_tx.c index d1ad2b2ed3..ac3ffd0fb2 100644 --- a/openair2/UTIL/OTG/otg_tx.c +++ b/openair2/UTIL/OTG/otg_tx.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_tx.h b/openair2/UTIL/OTG/otg_tx.h index 51bcfdd41a..c5b0c01dfc 100644 --- a/openair2/UTIL/OTG/otg_tx.h +++ b/openair2/UTIL/OTG/otg_tx.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_tx_socket.c b/openair2/UTIL/OTG/otg_tx_socket.c index ae83339509..026dc3e8b8 100644 --- a/openair2/UTIL/OTG/otg_tx_socket.c +++ b/openair2/UTIL/OTG/otg_tx_socket.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_tx_socket.h b/openair2/UTIL/OTG/otg_tx_socket.h index 4d9981b802..17568244fa 100644 --- a/openair2/UTIL/OTG/otg_tx_socket.h +++ b/openair2/UTIL/OTG/otg_tx_socket.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/otg_vars.h b/openair2/UTIL/OTG/otg_vars.h index 1d50084c85..a6bb48af54 100644 --- a/openair2/UTIL/OTG/otg_vars.h +++ b/openair2/UTIL/OTG/otg_vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/OTG/traffic_config.h b/openair2/UTIL/OTG/traffic_config.h index 6f7df69e55..2f47682706 100644 --- a/openair2/UTIL/OTG/traffic_config.h +++ b/openair2/UTIL/OTG/traffic_config.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/TIMER/umts_timer.c b/openair2/UTIL/TIMER/umts_timer.c index 9978419fb8..9bbb6c2df9 100644 --- a/openair2/UTIL/TIMER/umts_timer.c +++ b/openair2/UTIL/TIMER/umts_timer.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/TIMER/umts_timer.h b/openair2/UTIL/TIMER/umts_timer.h index d179a471e5..077b55cf0c 100644 --- a/openair2/UTIL/TIMER/umts_timer.h +++ b/openair2/UTIL/TIMER/umts_timer.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/TIMER/umts_timer_proto_extern.h b/openair2/UTIL/TIMER/umts_timer_proto_extern.h index 807bba8a55..b43b347e46 100644 --- a/openair2/UTIL/TIMER/umts_timer_proto_extern.h +++ b/openair2/UTIL/TIMER/umts_timer_proto_extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/TIMER/umts_timer_struct.h b/openair2/UTIL/TIMER/umts_timer_struct.h index 490a80c4e0..c4886c7f80 100644 --- a/openair2/UTIL/TIMER/umts_timer_struct.h +++ b/openair2/UTIL/TIMER/umts_timer_struct.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/TRACE/fifo_printf.c b/openair2/UTIL/TRACE/fifo_printf.c index 4548eedd90..2dc4da0637 100644 --- a/openair2/UTIL/TRACE/fifo_printf.c +++ b/openair2/UTIL/TRACE/fifo_printf.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/TRACE/fifo_printf.h b/openair2/UTIL/TRACE/fifo_printf.h index 92b5ab42ce..ce2702b19a 100644 --- a/openair2/UTIL/TRACE/fifo_printf.h +++ b/openair2/UTIL/TRACE/fifo_printf.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/TRACE/fifo_printf_proto_extern.h b/openair2/UTIL/TRACE/fifo_printf_proto_extern.h index 641af7f224..0855a8da93 100644 --- a/openair2/UTIL/TRACE/fifo_printf_proto_extern.h +++ b/openair2/UTIL/TRACE/fifo_printf_proto_extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/UTIL/TRACE/print.h b/openair2/UTIL/TRACE/print.h index cd177111fb..5982d249fa 100644 --- a/openair2/UTIL/TRACE/print.h +++ b/openair2/UTIL/TRACE/print.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/X2AP/MESSAGES/ASN1/asn1tostruct.py b/openair2/X2AP/MESSAGES/ASN1/asn1tostruct.py index e8ebb03d6d..8c0f7e8a16 100644 --- a/openair2/X2AP/MESSAGES/ASN1/asn1tostruct.py +++ b/openair2/X2AP/MESSAGES/ASN1/asn1tostruct.py @@ -38,7 +38,7 @@ def outputHeaderToFile(f, filename): * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/X2AP/x2ap.c b/openair2/X2AP/x2ap.c index 699ad5ddbf..bde21c0dbe 100644 --- a/openair2/X2AP/x2ap.c +++ b/openair2/X2AP/x2ap.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/X2AP/x2ap.h b/openair2/X2AP/x2ap.h index 6ef98b9909..65529c7119 100644 --- a/openair2/X2AP/x2ap.h +++ b/openair2/X2AP/x2ap.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/X2AP/x2ap_common.c b/openair2/X2AP/x2ap_common.c index 2a59414ed9..d92f2c69bb 100644 --- a/openair2/X2AP/x2ap_common.c +++ b/openair2/X2AP/x2ap_common.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/X2AP/x2ap_common.h b/openair2/X2AP/x2ap_common.h index d2a2ca7137..b7c9361476 100644 --- a/openair2/X2AP/x2ap_common.h +++ b/openair2/X2AP/x2ap_common.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/common_types.h b/openair3/COMMON/common_types.h index 9036ee8c13..80cc20df63 100644 --- a/openair3/COMMON/common_types.h +++ b/openair3/COMMON/common_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/gtpv1_u_messages_def.h b/openair3/COMMON/gtpv1_u_messages_def.h index eddf95c62b..4308853515 100644 --- a/openair3/COMMON/gtpv1_u_messages_def.h +++ b/openair3/COMMON/gtpv1_u_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/gtpv1_u_messages_types.h b/openair3/COMMON/gtpv1_u_messages_types.h index f5358941e4..594325647b 100644 --- a/openair3/COMMON/gtpv1_u_messages_types.h +++ b/openair3/COMMON/gtpv1_u_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/intertask_interface_conf.h b/openair3/COMMON/intertask_interface_conf.h index eca0c5d501..6bb8a1edd5 100644 --- a/openair3/COMMON/intertask_interface_conf.h +++ b/openair3/COMMON/intertask_interface_conf.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/messages_def.h b/openair3/COMMON/messages_def.h index 9e87b26322..1c1cdbaf0f 100644 --- a/openair3/COMMON/messages_def.h +++ b/openair3/COMMON/messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/messages_types.h b/openair3/COMMON/messages_types.h index 8717f2ad4e..47d9d32f2b 100644 --- a/openair3/COMMON/messages_types.h +++ b/openair3/COMMON/messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/nas_messages_def.h b/openair3/COMMON/nas_messages_def.h index 679b997d60..5214a15171 100644 --- a/openair3/COMMON/nas_messages_def.h +++ b/openair3/COMMON/nas_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/nas_messages_types.h b/openair3/COMMON/nas_messages_types.h index 7b93e9c617..45de68840e 100644 --- a/openair3/COMMON/nas_messages_types.h +++ b/openair3/COMMON/nas_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/s1ap_messages_def.h b/openair3/COMMON/s1ap_messages_def.h index e129ecf950..f0d7ba086f 100644 --- a/openair3/COMMON/s1ap_messages_def.h +++ b/openair3/COMMON/s1ap_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/s1ap_messages_types.h b/openair3/COMMON/s1ap_messages_types.h index 0558c1711d..e6c3bba504 100644 --- a/openair3/COMMON/s1ap_messages_types.h +++ b/openair3/COMMON/s1ap_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/sctp_messages_def.h b/openair3/COMMON/sctp_messages_def.h index 937bf09dd3..c2d51c91eb 100644 --- a/openair3/COMMON/sctp_messages_def.h +++ b/openair3/COMMON/sctp_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/sctp_messages_types.h b/openair3/COMMON/sctp_messages_types.h index 459cff5d40..98a92c66b6 100644 --- a/openair3/COMMON/sctp_messages_types.h +++ b/openair3/COMMON/sctp_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/security_types.h b/openair3/COMMON/security_types.h index bc64e32ded..0eedc6201f 100644 --- a/openair3/COMMON/security_types.h +++ b/openair3/COMMON/security_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/tasks_def.h b/openair3/COMMON/tasks_def.h index 9124e0193c..d1b7b8d756 100644 --- a/openair3/COMMON/tasks_def.h +++ b/openair3/COMMON/tasks_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/udp_messages_def.h b/openair3/COMMON/udp_messages_def.h index 41b5e8aa52..35322f2450 100644 --- a/openair3/COMMON/udp_messages_def.h +++ b/openair3/COMMON/udp_messages_def.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/COMMON/udp_messages_types.h b/openair3/COMMON/udp_messages_types.h index 1ec878782a..7825a924d1 100644 --- a/openair3/COMMON/udp_messages_types.h +++ b/openair3/COMMON/udp_messages_types.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/DOCS/DOXYGEN/Makefile.am b/openair3/DOCS/DOXYGEN/Makefile.am index b35915324f..a291a8817e 100644 --- a/openair3/DOCS/DOXYGEN/Makefile.am +++ b/openair3/DOCS/DOXYGEN/Makefile.am @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/openair3/DOCS/Latex/EPC/Makefile b/openair3/DOCS/Latex/EPC/Makefile index 517bbe11f6..0f0e799384 100644 --- a/openair3/DOCS/Latex/EPC/Makefile +++ b/openair3/DOCS/Latex/EPC/Makefile @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/openair3/DOCS/Makefile.am b/openair3/DOCS/Makefile.am index 28a4220611..de8e4c619a 100644 --- a/openair3/DOCS/Makefile.am +++ b/openair3/DOCS/Makefile.am @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/openair3/GTPV1-U/Makefile.am b/openair3/GTPV1-U/Makefile.am index 25d5658148..30ea61d6c1 100644 --- a/openair3/GTPV1-U/Makefile.am +++ b/openair3/GTPV1-U/Makefile.am @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/openair3/GTPV1-U/Makefile.eNB b/openair3/GTPV1-U/Makefile.eNB index 6941959e81..b469dc756d 100644 --- a/openair3/GTPV1-U/Makefile.eNB +++ b/openair3/GTPV1-U/Makefile.eNB @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/openair3/GTPV1-U/gtpv1u.h b/openair3/GTPV1-U/gtpv1u.h index 9f2f65db9a..9466f024bc 100644 --- a/openair3/GTPV1-U/gtpv1u.h +++ b/openair3/GTPV1-U/gtpv1u.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/GTPV1-U/gtpv1u_eNB.c b/openair3/GTPV1-U/gtpv1u_eNB.c index e273ac0712..feaacfcd3f 100644 --- a/openair3/GTPV1-U/gtpv1u_eNB.c +++ b/openair3/GTPV1-U/gtpv1u_eNB.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/GTPV1-U/gtpv1u_eNB_defs.h b/openair3/GTPV1-U/gtpv1u_eNB_defs.h index 91f045ace2..c09dd4529b 100644 --- a/openair3/GTPV1-U/gtpv1u_eNB_defs.h +++ b/openair3/GTPV1-U/gtpv1u_eNB_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/GTPV1-U/gtpv1u_eNB_task.h b/openair3/GTPV1-U/gtpv1u_eNB_task.h index d69917aea3..ec1de8329c 100644 --- a/openair3/GTPV1-U/gtpv1u_eNB_task.h +++ b/openair3/GTPV1-U/gtpv1u_eNB_task.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/GTPV1-U/gtpv1u_sgw_defs.h b/openair3/GTPV1-U/gtpv1u_sgw_defs.h index 218d0df96f..1d62c18bf6 100644 --- a/openair3/GTPV1-U/gtpv1u_sgw_defs.h +++ b/openair3/GTPV1-U/gtpv1u_sgw_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/GTPV1-U/gtpv1u_task.c b/openair3/GTPV1-U/gtpv1u_task.c index f9397f21ca..a6dd6fa061 100644 --- a/openair3/GTPV1-U/gtpv1u_task.c +++ b/openair3/GTPV1-U/gtpv1u_task.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/GTPV1-U/gtpv1u_teid_pool.c b/openair3/GTPV1-U/gtpv1u_teid_pool.c index 6596a2b9a9..ff0ac6f183 100644 --- a/openair3/GTPV1-U/gtpv1u_teid_pool.c +++ b/openair3/GTPV1-U/gtpv1u_teid_pool.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/API/NETWORK/as_message.c b/openair3/NAS/COMMON/API/NETWORK/as_message.c index 201ed441f3..fd3f15cb4c 100644 --- a/openair3/NAS/COMMON/API/NETWORK/as_message.c +++ b/openair3/NAS/COMMON/API/NETWORK/as_message.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/API/NETWORK/l2_message.h b/openair3/NAS/COMMON/API/NETWORK/l2_message.h index 39a2d18905..9cf65b7736 100644 --- a/openair3/NAS/COMMON/API/NETWORK/l2_message.h +++ b/openair3/NAS/COMMON/API/NETWORK/l2_message.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/API/NETWORK/nas_message.c b/openair3/NAS/COMMON/API/NETWORK/nas_message.c index c61ad6532f..4eea2c4d6b 100644 --- a/openair3/NAS/COMMON/API/NETWORK/nas_message.c +++ b/openair3/NAS/COMMON/API/NETWORK/nas_message.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/API/NETWORK/nas_message.h b/openair3/NAS/COMMON/API/NETWORK/nas_message.h index 8094d31298..8fde6eb97d 100644 --- a/openair3/NAS/COMMON/API/NETWORK/nas_message.h +++ b/openair3/NAS/COMMON/API/NETWORK/nas_message.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/API/NETWORK/network_api.c b/openair3/NAS/COMMON/API/NETWORK/network_api.c index a9d5c48547..160eb78e17 100644 --- a/openair3/NAS/COMMON/API/NETWORK/network_api.c +++ b/openair3/NAS/COMMON/API/NETWORK/network_api.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/API/NETWORK/network_api.h b/openair3/NAS/COMMON/API/NETWORK/network_api.h index 22bf0f426e..57abb2c4f6 100644 --- a/openair3/NAS/COMMON/API/NETWORK/network_api.h +++ b/openair3/NAS/COMMON/API/NETWORK/network_api.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AttachAccept.c b/openair3/NAS/COMMON/EMM/MSG/AttachAccept.c index 727bacfa2d..8ac43cf7b1 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AttachAccept.c +++ b/openair3/NAS/COMMON/EMM/MSG/AttachAccept.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AttachAccept.h b/openair3/NAS/COMMON/EMM/MSG/AttachAccept.h index ced696afdb..3d944e8bfb 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AttachAccept.h +++ b/openair3/NAS/COMMON/EMM/MSG/AttachAccept.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AttachComplete.c b/openair3/NAS/COMMON/EMM/MSG/AttachComplete.c index 80479b58c3..26d4b6ddd7 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AttachComplete.c +++ b/openair3/NAS/COMMON/EMM/MSG/AttachComplete.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AttachComplete.h b/openair3/NAS/COMMON/EMM/MSG/AttachComplete.h index 309726b925..e11ad97156 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AttachComplete.h +++ b/openair3/NAS/COMMON/EMM/MSG/AttachComplete.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AttachReject.c b/openair3/NAS/COMMON/EMM/MSG/AttachReject.c index a15c6b624c..c0b3208ff9 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AttachReject.c +++ b/openair3/NAS/COMMON/EMM/MSG/AttachReject.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AttachReject.h b/openair3/NAS/COMMON/EMM/MSG/AttachReject.h index d5803baec2..5ab3b57308 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AttachReject.h +++ b/openair3/NAS/COMMON/EMM/MSG/AttachReject.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AttachRequest.c b/openair3/NAS/COMMON/EMM/MSG/AttachRequest.c index 7c50d2fcdd..7448a33419 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AttachRequest.c +++ b/openair3/NAS/COMMON/EMM/MSG/AttachRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AttachRequest.h b/openair3/NAS/COMMON/EMM/MSG/AttachRequest.h index caa19922ae..a7e4c1f17c 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AttachRequest.h +++ b/openair3/NAS/COMMON/EMM/MSG/AttachRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AuthenticationFailure.c b/openair3/NAS/COMMON/EMM/MSG/AuthenticationFailure.c index 7b01d0f5ab..89368d7523 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AuthenticationFailure.c +++ b/openair3/NAS/COMMON/EMM/MSG/AuthenticationFailure.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AuthenticationFailure.h b/openair3/NAS/COMMON/EMM/MSG/AuthenticationFailure.h index 384f51471c..5670b0a5c1 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AuthenticationFailure.h +++ b/openair3/NAS/COMMON/EMM/MSG/AuthenticationFailure.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AuthenticationReject.c b/openair3/NAS/COMMON/EMM/MSG/AuthenticationReject.c index dd848aef2e..5ca9b1a503 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AuthenticationReject.c +++ b/openair3/NAS/COMMON/EMM/MSG/AuthenticationReject.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AuthenticationReject.h b/openair3/NAS/COMMON/EMM/MSG/AuthenticationReject.h index 5b468dcf25..2a2ca7b7d2 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AuthenticationReject.h +++ b/openair3/NAS/COMMON/EMM/MSG/AuthenticationReject.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AuthenticationRequest.c b/openair3/NAS/COMMON/EMM/MSG/AuthenticationRequest.c index 3e0bffde2d..0914353478 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AuthenticationRequest.c +++ b/openair3/NAS/COMMON/EMM/MSG/AuthenticationRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AuthenticationRequest.h b/openair3/NAS/COMMON/EMM/MSG/AuthenticationRequest.h index e7cdc04017..306c8bb404 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AuthenticationRequest.h +++ b/openair3/NAS/COMMON/EMM/MSG/AuthenticationRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AuthenticationResponse.c b/openair3/NAS/COMMON/EMM/MSG/AuthenticationResponse.c index 4b870c6200..4834348595 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AuthenticationResponse.c +++ b/openair3/NAS/COMMON/EMM/MSG/AuthenticationResponse.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/AuthenticationResponse.h b/openair3/NAS/COMMON/EMM/MSG/AuthenticationResponse.h index 710a43f043..4d49518ba0 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AuthenticationResponse.h +++ b/openair3/NAS/COMMON/EMM/MSG/AuthenticationResponse.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/CsServiceNotification.c b/openair3/NAS/COMMON/EMM/MSG/CsServiceNotification.c index 0d5a336eef..20193ef0b6 100644 --- a/openair3/NAS/COMMON/EMM/MSG/CsServiceNotification.c +++ b/openair3/NAS/COMMON/EMM/MSG/CsServiceNotification.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/CsServiceNotification.h b/openair3/NAS/COMMON/EMM/MSG/CsServiceNotification.h index 48e6aaec75..c173d3b729 100644 --- a/openair3/NAS/COMMON/EMM/MSG/CsServiceNotification.h +++ b/openair3/NAS/COMMON/EMM/MSG/CsServiceNotification.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/DetachAccept.c b/openair3/NAS/COMMON/EMM/MSG/DetachAccept.c index c31550fdca..0ad1066c4c 100644 --- a/openair3/NAS/COMMON/EMM/MSG/DetachAccept.c +++ b/openair3/NAS/COMMON/EMM/MSG/DetachAccept.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/DetachAccept.h b/openair3/NAS/COMMON/EMM/MSG/DetachAccept.h index 48e8e674e9..73c4e8dcb6 100644 --- a/openair3/NAS/COMMON/EMM/MSG/DetachAccept.h +++ b/openair3/NAS/COMMON/EMM/MSG/DetachAccept.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/DetachRequest.c b/openair3/NAS/COMMON/EMM/MSG/DetachRequest.c index 6c84e7d4d3..1697ea17e2 100644 --- a/openair3/NAS/COMMON/EMM/MSG/DetachRequest.c +++ b/openair3/NAS/COMMON/EMM/MSG/DetachRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/DetachRequest.h b/openair3/NAS/COMMON/EMM/MSG/DetachRequest.h index 557d5117eb..93cdcab1ac 100644 --- a/openair3/NAS/COMMON/EMM/MSG/DetachRequest.h +++ b/openair3/NAS/COMMON/EMM/MSG/DetachRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/DownlinkNasTransport.c b/openair3/NAS/COMMON/EMM/MSG/DownlinkNasTransport.c index b020f77af3..5dbce59902 100644 --- a/openair3/NAS/COMMON/EMM/MSG/DownlinkNasTransport.c +++ b/openair3/NAS/COMMON/EMM/MSG/DownlinkNasTransport.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/DownlinkNasTransport.h b/openair3/NAS/COMMON/EMM/MSG/DownlinkNasTransport.h index a9d926bb05..f41ce23b0e 100644 --- a/openair3/NAS/COMMON/EMM/MSG/DownlinkNasTransport.h +++ b/openair3/NAS/COMMON/EMM/MSG/DownlinkNasTransport.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/EmmInformation.c b/openair3/NAS/COMMON/EMM/MSG/EmmInformation.c index e9d4400d5f..d18e115db9 100644 --- a/openair3/NAS/COMMON/EMM/MSG/EmmInformation.c +++ b/openair3/NAS/COMMON/EMM/MSG/EmmInformation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/EmmInformation.h b/openair3/NAS/COMMON/EMM/MSG/EmmInformation.h index cdbc22f201..79eec4ddce 100644 --- a/openair3/NAS/COMMON/EMM/MSG/EmmInformation.h +++ b/openair3/NAS/COMMON/EMM/MSG/EmmInformation.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/EmmStatus.c b/openair3/NAS/COMMON/EMM/MSG/EmmStatus.c index a46467e099..f283d64bc9 100644 --- a/openair3/NAS/COMMON/EMM/MSG/EmmStatus.c +++ b/openair3/NAS/COMMON/EMM/MSG/EmmStatus.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/EmmStatus.h b/openair3/NAS/COMMON/EMM/MSG/EmmStatus.h index 0fcd912218..dc860acec7 100644 --- a/openair3/NAS/COMMON/EMM/MSG/EmmStatus.h +++ b/openair3/NAS/COMMON/EMM/MSG/EmmStatus.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/ExtendedServiceRequest.c b/openair3/NAS/COMMON/EMM/MSG/ExtendedServiceRequest.c index 33e05d2b3b..a7ff89245b 100644 --- a/openair3/NAS/COMMON/EMM/MSG/ExtendedServiceRequest.c +++ b/openair3/NAS/COMMON/EMM/MSG/ExtendedServiceRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/ExtendedServiceRequest.h b/openair3/NAS/COMMON/EMM/MSG/ExtendedServiceRequest.h index 291d757996..defe200c0f 100644 --- a/openair3/NAS/COMMON/EMM/MSG/ExtendedServiceRequest.h +++ b/openair3/NAS/COMMON/EMM/MSG/ExtendedServiceRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/GutiReallocationCommand.c b/openair3/NAS/COMMON/EMM/MSG/GutiReallocationCommand.c index 624829b8aa..fac3ddbca9 100644 --- a/openair3/NAS/COMMON/EMM/MSG/GutiReallocationCommand.c +++ b/openair3/NAS/COMMON/EMM/MSG/GutiReallocationCommand.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/GutiReallocationCommand.h b/openair3/NAS/COMMON/EMM/MSG/GutiReallocationCommand.h index 3ab7bd9cea..11338ddc21 100644 --- a/openair3/NAS/COMMON/EMM/MSG/GutiReallocationCommand.h +++ b/openair3/NAS/COMMON/EMM/MSG/GutiReallocationCommand.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/GutiReallocationComplete.c b/openair3/NAS/COMMON/EMM/MSG/GutiReallocationComplete.c index 6c7db3a437..16083176ae 100644 --- a/openair3/NAS/COMMON/EMM/MSG/GutiReallocationComplete.c +++ b/openair3/NAS/COMMON/EMM/MSG/GutiReallocationComplete.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/GutiReallocationComplete.h b/openair3/NAS/COMMON/EMM/MSG/GutiReallocationComplete.h index 7c8393e2f5..f0c41a3ac9 100644 --- a/openair3/NAS/COMMON/EMM/MSG/GutiReallocationComplete.h +++ b/openair3/NAS/COMMON/EMM/MSG/GutiReallocationComplete.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/IdentityRequest.c b/openair3/NAS/COMMON/EMM/MSG/IdentityRequest.c index 1397dcaee7..17e1d26722 100644 --- a/openair3/NAS/COMMON/EMM/MSG/IdentityRequest.c +++ b/openair3/NAS/COMMON/EMM/MSG/IdentityRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/IdentityRequest.h b/openair3/NAS/COMMON/EMM/MSG/IdentityRequest.h index 81c01b24c9..ddd339e88d 100644 --- a/openair3/NAS/COMMON/EMM/MSG/IdentityRequest.h +++ b/openair3/NAS/COMMON/EMM/MSG/IdentityRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/IdentityResponse.c b/openair3/NAS/COMMON/EMM/MSG/IdentityResponse.c index 25b5933927..1743a29d20 100644 --- a/openair3/NAS/COMMON/EMM/MSG/IdentityResponse.c +++ b/openair3/NAS/COMMON/EMM/MSG/IdentityResponse.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/IdentityResponse.h b/openair3/NAS/COMMON/EMM/MSG/IdentityResponse.h index aeee34fe72..61842cc6c2 100644 --- a/openair3/NAS/COMMON/EMM/MSG/IdentityResponse.h +++ b/openair3/NAS/COMMON/EMM/MSG/IdentityResponse.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/NASSecurityModeCommand.h b/openair3/NAS/COMMON/EMM/MSG/NASSecurityModeCommand.h index b1b7fd81de..9016024af6 100644 --- a/openair3/NAS/COMMON/EMM/MSG/NASSecurityModeCommand.h +++ b/openair3/NAS/COMMON/EMM/MSG/NASSecurityModeCommand.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/NASSecurityModeComplete.h b/openair3/NAS/COMMON/EMM/MSG/NASSecurityModeComplete.h index a014e4d3bc..938bb9e371 100644 --- a/openair3/NAS/COMMON/EMM/MSG/NASSecurityModeComplete.h +++ b/openair3/NAS/COMMON/EMM/MSG/NASSecurityModeComplete.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/SecurityModeCommand.c b/openair3/NAS/COMMON/EMM/MSG/SecurityModeCommand.c index a1a34f9495..25181d8e79 100644 --- a/openair3/NAS/COMMON/EMM/MSG/SecurityModeCommand.c +++ b/openair3/NAS/COMMON/EMM/MSG/SecurityModeCommand.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/SecurityModeComplete.c b/openair3/NAS/COMMON/EMM/MSG/SecurityModeComplete.c index 3258134feb..8dd8b2e1b7 100644 --- a/openair3/NAS/COMMON/EMM/MSG/SecurityModeComplete.c +++ b/openair3/NAS/COMMON/EMM/MSG/SecurityModeComplete.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/SecurityModeReject.c b/openair3/NAS/COMMON/EMM/MSG/SecurityModeReject.c index 76fad512d0..5e49f4414d 100644 --- a/openair3/NAS/COMMON/EMM/MSG/SecurityModeReject.c +++ b/openair3/NAS/COMMON/EMM/MSG/SecurityModeReject.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/SecurityModeReject.h b/openair3/NAS/COMMON/EMM/MSG/SecurityModeReject.h index cef69ef61a..5f9cf5bcd2 100644 --- a/openair3/NAS/COMMON/EMM/MSG/SecurityModeReject.h +++ b/openair3/NAS/COMMON/EMM/MSG/SecurityModeReject.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/ServiceReject.c b/openair3/NAS/COMMON/EMM/MSG/ServiceReject.c index 0008a23720..0f703871ca 100644 --- a/openair3/NAS/COMMON/EMM/MSG/ServiceReject.c +++ b/openair3/NAS/COMMON/EMM/MSG/ServiceReject.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/ServiceReject.h b/openair3/NAS/COMMON/EMM/MSG/ServiceReject.h index 42929ac868..67a0317afd 100644 --- a/openair3/NAS/COMMON/EMM/MSG/ServiceReject.h +++ b/openair3/NAS/COMMON/EMM/MSG/ServiceReject.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/ServiceRequest.c b/openair3/NAS/COMMON/EMM/MSG/ServiceRequest.c index 944cffdb4c..9a2faf2178 100644 --- a/openair3/NAS/COMMON/EMM/MSG/ServiceRequest.c +++ b/openair3/NAS/COMMON/EMM/MSG/ServiceRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/ServiceRequest.h b/openair3/NAS/COMMON/EMM/MSG/ServiceRequest.h index 5ad605fa83..548eb933e3 100644 --- a/openair3/NAS/COMMON/EMM/MSG/ServiceRequest.h +++ b/openair3/NAS/COMMON/EMM/MSG/ServiceRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateAccept.c b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateAccept.c index 36894d1006..159175da1b 100644 --- a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateAccept.c +++ b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateAccept.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateAccept.h b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateAccept.h index 5a3dae34b3..8ce780aab1 100644 --- a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateAccept.h +++ b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateAccept.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateComplete.c b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateComplete.c index 5f504a503d..bf8b80d5f2 100644 --- a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateComplete.c +++ b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateComplete.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateComplete.h b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateComplete.h index c26f0508b6..1b5de76e2f 100644 --- a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateComplete.h +++ b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateComplete.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateReject.c b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateReject.c index 354262452b..c0fbdf711a 100644 --- a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateReject.c +++ b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateReject.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateReject.h b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateReject.h index 9b23b6fc1c..9066eb586a 100644 --- a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateReject.h +++ b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateReject.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateRequest.c b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateRequest.c index bc5bb351d8..49632057c0 100644 --- a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateRequest.c +++ b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateRequest.h b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateRequest.h index 2a5a36fc0a..6fe2726130 100644 --- a/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateRequest.h +++ b/openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/UplinkNasTransport.c b/openair3/NAS/COMMON/EMM/MSG/UplinkNasTransport.c index fe6244b942..0aaadc9316 100644 --- a/openair3/NAS/COMMON/EMM/MSG/UplinkNasTransport.c +++ b/openair3/NAS/COMMON/EMM/MSG/UplinkNasTransport.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/UplinkNasTransport.h b/openair3/NAS/COMMON/EMM/MSG/UplinkNasTransport.h index 3c2522f623..f2e7cd392a 100644 --- a/openair3/NAS/COMMON/EMM/MSG/UplinkNasTransport.h +++ b/openair3/NAS/COMMON/EMM/MSG/UplinkNasTransport.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/emm_cause.h b/openair3/NAS/COMMON/EMM/MSG/emm_cause.h index 2f65e2b11b..4b7796c95c 100644 --- a/openair3/NAS/COMMON/EMM/MSG/emm_cause.h +++ b/openair3/NAS/COMMON/EMM/MSG/emm_cause.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/emm_msg.c b/openair3/NAS/COMMON/EMM/MSG/emm_msg.c index c357e8784f..b9c9b93a9c 100644 --- a/openair3/NAS/COMMON/EMM/MSG/emm_msg.c +++ b/openair3/NAS/COMMON/EMM/MSG/emm_msg.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/emm_msg.h b/openair3/NAS/COMMON/EMM/MSG/emm_msg.h index 29f9975716..56985227ad 100644 --- a/openair3/NAS/COMMON/EMM/MSG/emm_msg.h +++ b/openair3/NAS/COMMON/EMM/MSG/emm_msg.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/EMM/MSG/emm_msgDef.h b/openair3/NAS/COMMON/EMM/MSG/emm_msgDef.h index a5f114184b..b95e140595 100644 --- a/openair3/NAS/COMMON/EMM/MSG/emm_msgDef.h +++ b/openair3/NAS/COMMON/EMM/MSG/emm_msgDef.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextAccept.c b/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextAccept.c index af2da7d1ba..e77e1d7749 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextAccept.c +++ b/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextAccept.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextAccept.h b/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextAccept.h index b248f2b9bd..2bb3e7e423 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextAccept.h +++ b/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextAccept.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextReject.c b/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextReject.c index 63552adcae..1a1d6ffbdb 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextReject.c +++ b/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextReject.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextReject.h b/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextReject.h index 7ff7b761cc..4b69cbc454 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextReject.h +++ b/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextReject.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextRequest.c b/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextRequest.c index 0797001e8a..f4f0a3343c 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextRequest.c +++ b/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextRequest.h b/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextRequest.h index 574a72a7c9..3bf2794e1d 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextRequest.h +++ b/openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextAccept.c b/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextAccept.c index 8b58c38b5f..d94c6f4652 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextAccept.c +++ b/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextAccept.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextAccept.h b/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextAccept.h index 574b258feb..045ef495af 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextAccept.h +++ b/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextAccept.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextReject.c b/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextReject.c index e9a902ca94..f5828ac87a 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextReject.c +++ b/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextReject.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextReject.h b/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextReject.h index 9c74a869ed..abfda25f63 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextReject.h +++ b/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextReject.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextRequest.c b/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextRequest.c index 02f293e9f0..068ee5db6a 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextRequest.c +++ b/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextRequest.h b/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextRequest.h index 56e305fb74..6931038bd8 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextRequest.h +++ b/openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationReject.c b/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationReject.c index a81a6325ce..c7b42cc9b4 100644 --- a/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationReject.c +++ b/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationReject.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationReject.h b/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationReject.h index d7cec7bfbe..321b0e4ff5 100644 --- a/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationReject.h +++ b/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationReject.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationRequest.c b/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationRequest.c index 3696012d7f..3fddc04983 100644 --- a/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationRequest.c +++ b/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationRequest.h b/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationRequest.h index 5428b03d51..17283167f6 100644 --- a/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationRequest.h +++ b/openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationReject.c b/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationReject.c index b0b143857b..8b1ace65b8 100644 --- a/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationReject.c +++ b/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationReject.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationReject.h b/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationReject.h index 26daab2c11..f437c70948 100644 --- a/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationReject.h +++ b/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationReject.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationRequest.c b/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationRequest.c index 2357006ef5..ff0a5294d9 100644 --- a/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationRequest.c +++ b/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationRequest.h b/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationRequest.h index fda843206f..90a3ec5928 100644 --- a/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationRequest.h +++ b/openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextAccept.c b/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextAccept.c index 6f958d1498..07ea8f7f68 100644 --- a/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextAccept.c +++ b/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextAccept.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextAccept.h b/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextAccept.h index c2aac073eb..446a59a085 100644 --- a/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextAccept.h +++ b/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextAccept.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextRequest.c b/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextRequest.c index 4854d2bd98..7a4647c57b 100644 --- a/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextRequest.c +++ b/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextRequest.h b/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextRequest.h index 4f86c50a6c..72b39113f9 100644 --- a/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextRequest.h +++ b/openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/EsmInformationRequest.c b/openair3/NAS/COMMON/ESM/MSG/EsmInformationRequest.c index 862046dc0e..622135c312 100644 --- a/openair3/NAS/COMMON/ESM/MSG/EsmInformationRequest.c +++ b/openair3/NAS/COMMON/ESM/MSG/EsmInformationRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/EsmInformationRequest.h b/openair3/NAS/COMMON/ESM/MSG/EsmInformationRequest.h index 20c668449b..8d2b6511fd 100644 --- a/openair3/NAS/COMMON/ESM/MSG/EsmInformationRequest.h +++ b/openair3/NAS/COMMON/ESM/MSG/EsmInformationRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/EsmInformationResponse.c b/openair3/NAS/COMMON/ESM/MSG/EsmInformationResponse.c index 287e3efcb2..e562d2a814 100644 --- a/openair3/NAS/COMMON/ESM/MSG/EsmInformationResponse.c +++ b/openair3/NAS/COMMON/ESM/MSG/EsmInformationResponse.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/EsmInformationResponse.h b/openair3/NAS/COMMON/ESM/MSG/EsmInformationResponse.h index fbb4954290..58751b54d3 100644 --- a/openair3/NAS/COMMON/ESM/MSG/EsmInformationResponse.h +++ b/openair3/NAS/COMMON/ESM/MSG/EsmInformationResponse.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/EsmStatus.c b/openair3/NAS/COMMON/ESM/MSG/EsmStatus.c index 0538722291..8c8bd62bd0 100644 --- a/openair3/NAS/COMMON/ESM/MSG/EsmStatus.c +++ b/openair3/NAS/COMMON/ESM/MSG/EsmStatus.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/EsmStatus.h b/openair3/NAS/COMMON/ESM/MSG/EsmStatus.h index 125a50305f..4f6e213ec8 100644 --- a/openair3/NAS/COMMON/ESM/MSG/EsmStatus.h +++ b/openair3/NAS/COMMON/ESM/MSG/EsmStatus.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextAccept.c b/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextAccept.c index 2fe1444d51..23a6ce5230 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextAccept.c +++ b/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextAccept.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextAccept.h b/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextAccept.h index 8891de5954..218c3cf874 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextAccept.h +++ b/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextAccept.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextReject.c b/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextReject.c index 6c76f6c52d..71e05c06e6 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextReject.c +++ b/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextReject.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextReject.h b/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextReject.h index 959fd2185d..b2d7cc56b7 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextReject.h +++ b/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextReject.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextRequest.c b/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextRequest.c index b9cbdefbb2..02b978b822 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextRequest.c +++ b/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextRequest.h b/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextRequest.h index 456d70d90f..2eb1ae8945 100644 --- a/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextRequest.h +++ b/openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityReject.c b/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityReject.c index 8658a85038..f7b1256f9d 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityReject.c +++ b/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityReject.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityReject.h b/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityReject.h index b595e14f21..fb2fe9fa19 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityReject.h +++ b/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityReject.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityRequest.c b/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityRequest.c index f5b8443064..957d813cf1 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityRequest.c +++ b/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityRequest.h b/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityRequest.h index ca28ea78b5..3cd791a5f8 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityRequest.h +++ b/openair3/NAS/COMMON/ESM/MSG/PdnConnectivityRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectReject.c b/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectReject.c index 668c34d872..9081ee885e 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectReject.c +++ b/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectReject.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectReject.h b/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectReject.h index c183e8ebe8..0c064617ee 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectReject.h +++ b/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectReject.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectRequest.c b/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectRequest.c index ee53ed7baa..506cb2959e 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectRequest.c +++ b/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectRequest.h b/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectRequest.h index c8913e1db0..94c2c2c3bf 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectRequest.h +++ b/openair3/NAS/COMMON/ESM/MSG/PdnDisconnectRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/esm_cause.h b/openair3/NAS/COMMON/ESM/MSG/esm_cause.h index 04ff141d2c..124663e05b 100644 --- a/openair3/NAS/COMMON/ESM/MSG/esm_cause.h +++ b/openair3/NAS/COMMON/ESM/MSG/esm_cause.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/esm_msg.c b/openair3/NAS/COMMON/ESM/MSG/esm_msg.c index e5bf603591..f4d3dd94dd 100644 --- a/openair3/NAS/COMMON/ESM/MSG/esm_msg.c +++ b/openair3/NAS/COMMON/ESM/MSG/esm_msg.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/esm_msg.h b/openair3/NAS/COMMON/ESM/MSG/esm_msg.h index 410460ca1c..ef8c05dd95 100644 --- a/openair3/NAS/COMMON/ESM/MSG/esm_msg.h +++ b/openair3/NAS/COMMON/ESM/MSG/esm_msg.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/ESM/MSG/esm_msgDef.h b/openair3/NAS/COMMON/ESM/MSG/esm_msgDef.h index 2dddfbfadd..48e6a18a90 100644 --- a/openair3/NAS/COMMON/ESM/MSG/esm_msgDef.h +++ b/openair3/NAS/COMMON/ESM/MSG/esm_msgDef.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/AccessPointName.c b/openair3/NAS/COMMON/IES/AccessPointName.c index 43446270c9..c63bb91222 100644 --- a/openair3/NAS/COMMON/IES/AccessPointName.c +++ b/openair3/NAS/COMMON/IES/AccessPointName.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/AccessPointName.h b/openair3/NAS/COMMON/IES/AccessPointName.h index f0d20d199b..6c10a942b5 100644 --- a/openair3/NAS/COMMON/IES/AccessPointName.h +++ b/openair3/NAS/COMMON/IES/AccessPointName.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/AdditionalUpdateResult.c b/openair3/NAS/COMMON/IES/AdditionalUpdateResult.c index f5208d3ff6..1869155aba 100644 --- a/openair3/NAS/COMMON/IES/AdditionalUpdateResult.c +++ b/openair3/NAS/COMMON/IES/AdditionalUpdateResult.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/AdditionalUpdateResult.h b/openair3/NAS/COMMON/IES/AdditionalUpdateResult.h index 448e7c3fe2..4f6cf5a4a0 100644 --- a/openair3/NAS/COMMON/IES/AdditionalUpdateResult.h +++ b/openair3/NAS/COMMON/IES/AdditionalUpdateResult.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/AdditionalUpdateType.c b/openair3/NAS/COMMON/IES/AdditionalUpdateType.c index 48e7fb5676..5bed4fdbb8 100644 --- a/openair3/NAS/COMMON/IES/AdditionalUpdateType.c +++ b/openair3/NAS/COMMON/IES/AdditionalUpdateType.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/AdditionalUpdateType.h b/openair3/NAS/COMMON/IES/AdditionalUpdateType.h index b5729f0c9d..57a2f0e075 100644 --- a/openair3/NAS/COMMON/IES/AdditionalUpdateType.h +++ b/openair3/NAS/COMMON/IES/AdditionalUpdateType.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/ApnAggregateMaximumBitRate.c b/openair3/NAS/COMMON/IES/ApnAggregateMaximumBitRate.c index cedc75b82c..4d01fc5b46 100644 --- a/openair3/NAS/COMMON/IES/ApnAggregateMaximumBitRate.c +++ b/openair3/NAS/COMMON/IES/ApnAggregateMaximumBitRate.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/ApnAggregateMaximumBitRate.h b/openair3/NAS/COMMON/IES/ApnAggregateMaximumBitRate.h index 24823b4006..82d3da4094 100644 --- a/openair3/NAS/COMMON/IES/ApnAggregateMaximumBitRate.h +++ b/openair3/NAS/COMMON/IES/ApnAggregateMaximumBitRate.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/AuthenticationFailureParameter.c b/openair3/NAS/COMMON/IES/AuthenticationFailureParameter.c index e0f016ba6a..4989ae27fe 100644 --- a/openair3/NAS/COMMON/IES/AuthenticationFailureParameter.c +++ b/openair3/NAS/COMMON/IES/AuthenticationFailureParameter.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/AuthenticationFailureParameter.h b/openair3/NAS/COMMON/IES/AuthenticationFailureParameter.h index 24624d3c8c..81b943afe4 100644 --- a/openair3/NAS/COMMON/IES/AuthenticationFailureParameter.h +++ b/openair3/NAS/COMMON/IES/AuthenticationFailureParameter.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/AuthenticationParameterAutn.c b/openair3/NAS/COMMON/IES/AuthenticationParameterAutn.c index 1cb31c9406..7de70359f7 100644 --- a/openair3/NAS/COMMON/IES/AuthenticationParameterAutn.c +++ b/openair3/NAS/COMMON/IES/AuthenticationParameterAutn.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/AuthenticationParameterAutn.h b/openair3/NAS/COMMON/IES/AuthenticationParameterAutn.h index 2e5e51461b..63866642eb 100644 --- a/openair3/NAS/COMMON/IES/AuthenticationParameterAutn.h +++ b/openair3/NAS/COMMON/IES/AuthenticationParameterAutn.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/AuthenticationParameterRand.c b/openair3/NAS/COMMON/IES/AuthenticationParameterRand.c index c355eb5469..a63a03bec1 100644 --- a/openair3/NAS/COMMON/IES/AuthenticationParameterRand.c +++ b/openair3/NAS/COMMON/IES/AuthenticationParameterRand.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/AuthenticationParameterRand.h b/openair3/NAS/COMMON/IES/AuthenticationParameterRand.h index 45aea0affc..bdea4e9eed 100644 --- a/openair3/NAS/COMMON/IES/AuthenticationParameterRand.h +++ b/openair3/NAS/COMMON/IES/AuthenticationParameterRand.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/AuthenticationResponseParameter.c b/openair3/NAS/COMMON/IES/AuthenticationResponseParameter.c index 46cda8adbc..3ac3e60a3d 100644 --- a/openair3/NAS/COMMON/IES/AuthenticationResponseParameter.c +++ b/openair3/NAS/COMMON/IES/AuthenticationResponseParameter.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/AuthenticationResponseParameter.h b/openair3/NAS/COMMON/IES/AuthenticationResponseParameter.h index 0ed254119b..4e3dd33d5b 100644 --- a/openair3/NAS/COMMON/IES/AuthenticationResponseParameter.h +++ b/openair3/NAS/COMMON/IES/AuthenticationResponseParameter.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/CipheringKeySequenceNumber.c b/openair3/NAS/COMMON/IES/CipheringKeySequenceNumber.c index dd59717b06..e10fe42a77 100644 --- a/openair3/NAS/COMMON/IES/CipheringKeySequenceNumber.c +++ b/openair3/NAS/COMMON/IES/CipheringKeySequenceNumber.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/CipheringKeySequenceNumber.h b/openair3/NAS/COMMON/IES/CipheringKeySequenceNumber.h index cbcde08fb5..18955204c5 100644 --- a/openair3/NAS/COMMON/IES/CipheringKeySequenceNumber.h +++ b/openair3/NAS/COMMON/IES/CipheringKeySequenceNumber.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/Cli.c b/openair3/NAS/COMMON/IES/Cli.c index 92ed87c020..e8878a2642 100644 --- a/openair3/NAS/COMMON/IES/Cli.c +++ b/openair3/NAS/COMMON/IES/Cli.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/Cli.h b/openair3/NAS/COMMON/IES/Cli.h index f1c8809c3c..47b9c35838 100644 --- a/openair3/NAS/COMMON/IES/Cli.h +++ b/openair3/NAS/COMMON/IES/Cli.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/CsfbResponse.c b/openair3/NAS/COMMON/IES/CsfbResponse.c index 3cb05e0e8a..b5ab64ce8d 100644 --- a/openair3/NAS/COMMON/IES/CsfbResponse.c +++ b/openair3/NAS/COMMON/IES/CsfbResponse.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/CsfbResponse.h b/openair3/NAS/COMMON/IES/CsfbResponse.h index 78d984bf5a..05aba3bf8f 100644 --- a/openair3/NAS/COMMON/IES/CsfbResponse.h +++ b/openair3/NAS/COMMON/IES/CsfbResponse.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/DaylightSavingTime.c b/openair3/NAS/COMMON/IES/DaylightSavingTime.c index 70fc1d199d..b5c242414d 100644 --- a/openair3/NAS/COMMON/IES/DaylightSavingTime.c +++ b/openair3/NAS/COMMON/IES/DaylightSavingTime.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/DaylightSavingTime.h b/openair3/NAS/COMMON/IES/DaylightSavingTime.h index 3830fdce3a..993065c958 100644 --- a/openair3/NAS/COMMON/IES/DaylightSavingTime.h +++ b/openair3/NAS/COMMON/IES/DaylightSavingTime.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/DetachType.c b/openair3/NAS/COMMON/IES/DetachType.c index 7ff9320008..8a925eb7b4 100644 --- a/openair3/NAS/COMMON/IES/DetachType.c +++ b/openair3/NAS/COMMON/IES/DetachType.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/DetachType.h b/openair3/NAS/COMMON/IES/DetachType.h index e84a57d19d..c1b1b2a37f 100644 --- a/openair3/NAS/COMMON/IES/DetachType.h +++ b/openair3/NAS/COMMON/IES/DetachType.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/DrxParameter.c b/openair3/NAS/COMMON/IES/DrxParameter.c index 9b607f0e79..3734f86976 100644 --- a/openair3/NAS/COMMON/IES/DrxParameter.c +++ b/openair3/NAS/COMMON/IES/DrxParameter.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/DrxParameter.h b/openair3/NAS/COMMON/IES/DrxParameter.h index e6d4aa284d..43af09f018 100644 --- a/openair3/NAS/COMMON/IES/DrxParameter.h +++ b/openair3/NAS/COMMON/IES/DrxParameter.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EmergencyNumberList.c b/openair3/NAS/COMMON/IES/EmergencyNumberList.c index 9330fdc312..ccf030b583 100644 --- a/openair3/NAS/COMMON/IES/EmergencyNumberList.c +++ b/openair3/NAS/COMMON/IES/EmergencyNumberList.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EmergencyNumberList.h b/openair3/NAS/COMMON/IES/EmergencyNumberList.h index ab47c1ff06..d8147eccde 100644 --- a/openair3/NAS/COMMON/IES/EmergencyNumberList.h +++ b/openair3/NAS/COMMON/IES/EmergencyNumberList.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EmmCause.c b/openair3/NAS/COMMON/IES/EmmCause.c index 21e52fe2cf..965f1e0f13 100644 --- a/openair3/NAS/COMMON/IES/EmmCause.c +++ b/openair3/NAS/COMMON/IES/EmmCause.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EmmCause.h b/openair3/NAS/COMMON/IES/EmmCause.h index 584c23d930..11ac2489b9 100644 --- a/openair3/NAS/COMMON/IES/EmmCause.h +++ b/openair3/NAS/COMMON/IES/EmmCause.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsAttachResult.c b/openair3/NAS/COMMON/IES/EpsAttachResult.c index b4d51663c9..b48b043ad3 100644 --- a/openair3/NAS/COMMON/IES/EpsAttachResult.c +++ b/openair3/NAS/COMMON/IES/EpsAttachResult.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsAttachResult.h b/openair3/NAS/COMMON/IES/EpsAttachResult.h index 78e04ccf65..500ce05399 100644 --- a/openair3/NAS/COMMON/IES/EpsAttachResult.h +++ b/openair3/NAS/COMMON/IES/EpsAttachResult.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsAttachType.c b/openair3/NAS/COMMON/IES/EpsAttachType.c index 8c9635ea6b..aa07d0ba89 100644 --- a/openair3/NAS/COMMON/IES/EpsAttachType.c +++ b/openair3/NAS/COMMON/IES/EpsAttachType.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsAttachType.h b/openair3/NAS/COMMON/IES/EpsAttachType.h index c6c9ffc236..7f57077a4d 100644 --- a/openair3/NAS/COMMON/IES/EpsAttachType.h +++ b/openair3/NAS/COMMON/IES/EpsAttachType.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsBearerContextStatus.c b/openair3/NAS/COMMON/IES/EpsBearerContextStatus.c index ff21a2dc4b..9984375dff 100644 --- a/openair3/NAS/COMMON/IES/EpsBearerContextStatus.c +++ b/openair3/NAS/COMMON/IES/EpsBearerContextStatus.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsBearerContextStatus.h b/openair3/NAS/COMMON/IES/EpsBearerContextStatus.h index 8c0b475559..fd29285cce 100644 --- a/openair3/NAS/COMMON/IES/EpsBearerContextStatus.h +++ b/openair3/NAS/COMMON/IES/EpsBearerContextStatus.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsBearerIdentity.c b/openair3/NAS/COMMON/IES/EpsBearerIdentity.c index 84d83ea09b..3ad83c1eaf 100644 --- a/openair3/NAS/COMMON/IES/EpsBearerIdentity.c +++ b/openair3/NAS/COMMON/IES/EpsBearerIdentity.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsBearerIdentity.h b/openair3/NAS/COMMON/IES/EpsBearerIdentity.h index 24f0c10608..d8f89751e0 100644 --- a/openair3/NAS/COMMON/IES/EpsBearerIdentity.h +++ b/openair3/NAS/COMMON/IES/EpsBearerIdentity.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsMobileIdentity.c b/openair3/NAS/COMMON/IES/EpsMobileIdentity.c index 3d40801fec..4437412b86 100644 --- a/openair3/NAS/COMMON/IES/EpsMobileIdentity.c +++ b/openair3/NAS/COMMON/IES/EpsMobileIdentity.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsMobileIdentity.h b/openair3/NAS/COMMON/IES/EpsMobileIdentity.h index 7a1ff393c5..d9b13f250c 100644 --- a/openair3/NAS/COMMON/IES/EpsMobileIdentity.h +++ b/openair3/NAS/COMMON/IES/EpsMobileIdentity.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsNetworkFeatureSupport.c b/openair3/NAS/COMMON/IES/EpsNetworkFeatureSupport.c index 5f018143b5..3a842406f0 100644 --- a/openair3/NAS/COMMON/IES/EpsNetworkFeatureSupport.c +++ b/openair3/NAS/COMMON/IES/EpsNetworkFeatureSupport.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsNetworkFeatureSupport.h b/openair3/NAS/COMMON/IES/EpsNetworkFeatureSupport.h index 59e84a323b..f367af6ac8 100644 --- a/openair3/NAS/COMMON/IES/EpsNetworkFeatureSupport.h +++ b/openair3/NAS/COMMON/IES/EpsNetworkFeatureSupport.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsQualityOfService.c b/openair3/NAS/COMMON/IES/EpsQualityOfService.c index b24e43e99c..ac45a9c0f5 100644 --- a/openair3/NAS/COMMON/IES/EpsQualityOfService.c +++ b/openair3/NAS/COMMON/IES/EpsQualityOfService.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsQualityOfService.h b/openair3/NAS/COMMON/IES/EpsQualityOfService.h index f4c5c5986e..ab8f752838 100644 --- a/openair3/NAS/COMMON/IES/EpsQualityOfService.h +++ b/openair3/NAS/COMMON/IES/EpsQualityOfService.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsUpdateResult.c b/openair3/NAS/COMMON/IES/EpsUpdateResult.c index feecb5e37d..a91da63985 100644 --- a/openair3/NAS/COMMON/IES/EpsUpdateResult.c +++ b/openair3/NAS/COMMON/IES/EpsUpdateResult.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsUpdateResult.h b/openair3/NAS/COMMON/IES/EpsUpdateResult.h index 019ac7a069..9f8b289248 100644 --- a/openair3/NAS/COMMON/IES/EpsUpdateResult.h +++ b/openair3/NAS/COMMON/IES/EpsUpdateResult.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsUpdateType.c b/openair3/NAS/COMMON/IES/EpsUpdateType.c index 7319cb5fe6..309031dcee 100644 --- a/openair3/NAS/COMMON/IES/EpsUpdateType.c +++ b/openair3/NAS/COMMON/IES/EpsUpdateType.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EpsUpdateType.h b/openair3/NAS/COMMON/IES/EpsUpdateType.h index 6bad9e064b..fff1171dbc 100644 --- a/openair3/NAS/COMMON/IES/EpsUpdateType.h +++ b/openair3/NAS/COMMON/IES/EpsUpdateType.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EsmCause.c b/openair3/NAS/COMMON/IES/EsmCause.c index ba75d7b564..e703438c17 100644 --- a/openair3/NAS/COMMON/IES/EsmCause.c +++ b/openair3/NAS/COMMON/IES/EsmCause.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EsmCause.h b/openair3/NAS/COMMON/IES/EsmCause.h index b405f6cd62..3590aaffec 100644 --- a/openair3/NAS/COMMON/IES/EsmCause.h +++ b/openair3/NAS/COMMON/IES/EsmCause.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EsmInformationTransferFlag.c b/openair3/NAS/COMMON/IES/EsmInformationTransferFlag.c index 4ec00315fe..5b4358499b 100644 --- a/openair3/NAS/COMMON/IES/EsmInformationTransferFlag.c +++ b/openair3/NAS/COMMON/IES/EsmInformationTransferFlag.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EsmInformationTransferFlag.h b/openair3/NAS/COMMON/IES/EsmInformationTransferFlag.h index c8ec26041f..1b932b1a99 100644 --- a/openair3/NAS/COMMON/IES/EsmInformationTransferFlag.h +++ b/openair3/NAS/COMMON/IES/EsmInformationTransferFlag.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EsmMessageContainer.c b/openair3/NAS/COMMON/IES/EsmMessageContainer.c index a223f36820..2268b657f0 100644 --- a/openair3/NAS/COMMON/IES/EsmMessageContainer.c +++ b/openair3/NAS/COMMON/IES/EsmMessageContainer.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/EsmMessageContainer.h b/openair3/NAS/COMMON/IES/EsmMessageContainer.h index c57f60a92b..c6fb827e13 100644 --- a/openair3/NAS/COMMON/IES/EsmMessageContainer.h +++ b/openair3/NAS/COMMON/IES/EsmMessageContainer.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/GprsTimer.c b/openair3/NAS/COMMON/IES/GprsTimer.c index e2bc6ca369..52c1df17ee 100644 --- a/openair3/NAS/COMMON/IES/GprsTimer.c +++ b/openair3/NAS/COMMON/IES/GprsTimer.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/GprsTimer.h b/openair3/NAS/COMMON/IES/GprsTimer.h index 104af63a16..c8bb686fa3 100644 --- a/openair3/NAS/COMMON/IES/GprsTimer.h +++ b/openair3/NAS/COMMON/IES/GprsTimer.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/GutiType.c b/openair3/NAS/COMMON/IES/GutiType.c index e5ecbdabcc..a9921eedd8 100644 --- a/openair3/NAS/COMMON/IES/GutiType.c +++ b/openair3/NAS/COMMON/IES/GutiType.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/GutiType.h b/openair3/NAS/COMMON/IES/GutiType.h index b4230ead52..ad434f5ca5 100644 --- a/openair3/NAS/COMMON/IES/GutiType.h +++ b/openair3/NAS/COMMON/IES/GutiType.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/IdentityType2.c b/openair3/NAS/COMMON/IES/IdentityType2.c index 96d1e5a8a0..9623b5e586 100644 --- a/openair3/NAS/COMMON/IES/IdentityType2.c +++ b/openair3/NAS/COMMON/IES/IdentityType2.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/IdentityType2.h b/openair3/NAS/COMMON/IES/IdentityType2.h index e7b8c80cc7..5e3a01b061 100644 --- a/openair3/NAS/COMMON/IES/IdentityType2.h +++ b/openair3/NAS/COMMON/IES/IdentityType2.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/ImeisvRequest.c b/openair3/NAS/COMMON/IES/ImeisvRequest.c index 208d417e8f..5c46b56f64 100644 --- a/openair3/NAS/COMMON/IES/ImeisvRequest.c +++ b/openair3/NAS/COMMON/IES/ImeisvRequest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/ImeisvRequest.h b/openair3/NAS/COMMON/IES/ImeisvRequest.h index 2819844ea8..e41beeb994 100644 --- a/openair3/NAS/COMMON/IES/ImeisvRequest.h +++ b/openair3/NAS/COMMON/IES/ImeisvRequest.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/KsiAndSequenceNumber.c b/openair3/NAS/COMMON/IES/KsiAndSequenceNumber.c index 640c24fc1d..4a9ed5c247 100644 --- a/openair3/NAS/COMMON/IES/KsiAndSequenceNumber.c +++ b/openair3/NAS/COMMON/IES/KsiAndSequenceNumber.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/KsiAndSequenceNumber.h b/openair3/NAS/COMMON/IES/KsiAndSequenceNumber.h index 7890e3f8f3..c739ca61e9 100644 --- a/openair3/NAS/COMMON/IES/KsiAndSequenceNumber.h +++ b/openair3/NAS/COMMON/IES/KsiAndSequenceNumber.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/LcsClientIdentity.c b/openair3/NAS/COMMON/IES/LcsClientIdentity.c index 62a7a82feb..89014ce46c 100644 --- a/openair3/NAS/COMMON/IES/LcsClientIdentity.c +++ b/openair3/NAS/COMMON/IES/LcsClientIdentity.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/LcsClientIdentity.h b/openair3/NAS/COMMON/IES/LcsClientIdentity.h index 72089b6b91..7a8348c806 100644 --- a/openair3/NAS/COMMON/IES/LcsClientIdentity.h +++ b/openair3/NAS/COMMON/IES/LcsClientIdentity.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/LcsIndicator.c b/openair3/NAS/COMMON/IES/LcsIndicator.c index 4d17629bff..ee9a75d8bb 100644 --- a/openair3/NAS/COMMON/IES/LcsIndicator.c +++ b/openair3/NAS/COMMON/IES/LcsIndicator.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/LcsIndicator.h b/openair3/NAS/COMMON/IES/LcsIndicator.h index b8c018127f..976d42eb13 100644 --- a/openair3/NAS/COMMON/IES/LcsIndicator.h +++ b/openair3/NAS/COMMON/IES/LcsIndicator.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/LinkedEpsBearerIdentity.c b/openair3/NAS/COMMON/IES/LinkedEpsBearerIdentity.c index d2acc5dffe..88b8ee4f7e 100644 --- a/openair3/NAS/COMMON/IES/LinkedEpsBearerIdentity.c +++ b/openair3/NAS/COMMON/IES/LinkedEpsBearerIdentity.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/LinkedEpsBearerIdentity.h b/openair3/NAS/COMMON/IES/LinkedEpsBearerIdentity.h index 4d8cb883e2..58bbf11d3c 100644 --- a/openair3/NAS/COMMON/IES/LinkedEpsBearerIdentity.h +++ b/openair3/NAS/COMMON/IES/LinkedEpsBearerIdentity.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/LlcServiceAccessPointIdentifier.c b/openair3/NAS/COMMON/IES/LlcServiceAccessPointIdentifier.c index 53b0e91cc3..51869784d9 100644 --- a/openair3/NAS/COMMON/IES/LlcServiceAccessPointIdentifier.c +++ b/openair3/NAS/COMMON/IES/LlcServiceAccessPointIdentifier.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/LlcServiceAccessPointIdentifier.h b/openair3/NAS/COMMON/IES/LlcServiceAccessPointIdentifier.h index 46cd6a4e24..35f1df710f 100644 --- a/openair3/NAS/COMMON/IES/LlcServiceAccessPointIdentifier.h +++ b/openair3/NAS/COMMON/IES/LlcServiceAccessPointIdentifier.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/LocationAreaIdentification.c b/openair3/NAS/COMMON/IES/LocationAreaIdentification.c index 17c1053559..27e31c3733 100644 --- a/openair3/NAS/COMMON/IES/LocationAreaIdentification.c +++ b/openair3/NAS/COMMON/IES/LocationAreaIdentification.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/LocationAreaIdentification.h b/openair3/NAS/COMMON/IES/LocationAreaIdentification.h index b3027d0d92..c09de9c987 100644 --- a/openair3/NAS/COMMON/IES/LocationAreaIdentification.h +++ b/openair3/NAS/COMMON/IES/LocationAreaIdentification.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/MessageType.c b/openair3/NAS/COMMON/IES/MessageType.c index 7874187dc3..83d134cdf5 100644 --- a/openair3/NAS/COMMON/IES/MessageType.c +++ b/openair3/NAS/COMMON/IES/MessageType.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/MessageType.h b/openair3/NAS/COMMON/IES/MessageType.h index 2af029093c..d926f09cdc 100644 --- a/openair3/NAS/COMMON/IES/MessageType.h +++ b/openair3/NAS/COMMON/IES/MessageType.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/MobileIdentity.c b/openair3/NAS/COMMON/IES/MobileIdentity.c index 4651fa0047..fbe6d93e47 100644 --- a/openair3/NAS/COMMON/IES/MobileIdentity.c +++ b/openair3/NAS/COMMON/IES/MobileIdentity.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/MobileIdentity.h b/openair3/NAS/COMMON/IES/MobileIdentity.h index 72abcb9ed4..37f4d4ac30 100644 --- a/openair3/NAS/COMMON/IES/MobileIdentity.h +++ b/openair3/NAS/COMMON/IES/MobileIdentity.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/MobileStationClassmark2.c b/openair3/NAS/COMMON/IES/MobileStationClassmark2.c index 3707bbd636..e3a165bf3a 100644 --- a/openair3/NAS/COMMON/IES/MobileStationClassmark2.c +++ b/openair3/NAS/COMMON/IES/MobileStationClassmark2.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/MobileStationClassmark2.h b/openair3/NAS/COMMON/IES/MobileStationClassmark2.h index 55c40474d1..5cf7b9c46e 100644 --- a/openair3/NAS/COMMON/IES/MobileStationClassmark2.h +++ b/openair3/NAS/COMMON/IES/MobileStationClassmark2.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/MobileStationClassmark3.c b/openair3/NAS/COMMON/IES/MobileStationClassmark3.c index c9d6e37d84..9bd439fdfd 100644 --- a/openair3/NAS/COMMON/IES/MobileStationClassmark3.c +++ b/openair3/NAS/COMMON/IES/MobileStationClassmark3.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/MobileStationClassmark3.h b/openair3/NAS/COMMON/IES/MobileStationClassmark3.h index c3f199b291..80c4d4e8e2 100644 --- a/openair3/NAS/COMMON/IES/MobileStationClassmark3.h +++ b/openair3/NAS/COMMON/IES/MobileStationClassmark3.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/MsNetworkCapability.c b/openair3/NAS/COMMON/IES/MsNetworkCapability.c index 770270934f..8c2955177e 100644 --- a/openair3/NAS/COMMON/IES/MsNetworkCapability.c +++ b/openair3/NAS/COMMON/IES/MsNetworkCapability.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/MsNetworkCapability.h b/openair3/NAS/COMMON/IES/MsNetworkCapability.h index 8572cc6d47..f379989241 100644 --- a/openair3/NAS/COMMON/IES/MsNetworkCapability.h +++ b/openair3/NAS/COMMON/IES/MsNetworkCapability.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/MsNetworkFeatureSupport.c b/openair3/NAS/COMMON/IES/MsNetworkFeatureSupport.c index e96537ab16..6de2a05474 100644 --- a/openair3/NAS/COMMON/IES/MsNetworkFeatureSupport.c +++ b/openair3/NAS/COMMON/IES/MsNetworkFeatureSupport.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/MsNetworkFeatureSupport.h b/openair3/NAS/COMMON/IES/MsNetworkFeatureSupport.h index 84f20ed65d..147c166beb 100644 --- a/openair3/NAS/COMMON/IES/MsNetworkFeatureSupport.h +++ b/openair3/NAS/COMMON/IES/MsNetworkFeatureSupport.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/NasKeySetIdentifier.c b/openair3/NAS/COMMON/IES/NasKeySetIdentifier.c index 276953e343..a547675675 100644 --- a/openair3/NAS/COMMON/IES/NasKeySetIdentifier.c +++ b/openair3/NAS/COMMON/IES/NasKeySetIdentifier.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/NasKeySetIdentifier.h b/openair3/NAS/COMMON/IES/NasKeySetIdentifier.h index 3206ef1e9b..09daf13a56 100644 --- a/openair3/NAS/COMMON/IES/NasKeySetIdentifier.h +++ b/openair3/NAS/COMMON/IES/NasKeySetIdentifier.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/NasMessageContainer.c b/openair3/NAS/COMMON/IES/NasMessageContainer.c index 8847023c42..cccb8f7543 100644 --- a/openair3/NAS/COMMON/IES/NasMessageContainer.c +++ b/openair3/NAS/COMMON/IES/NasMessageContainer.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/NasMessageContainer.h b/openair3/NAS/COMMON/IES/NasMessageContainer.h index 8f53a0a7e5..4e1ad971be 100644 --- a/openair3/NAS/COMMON/IES/NasMessageContainer.h +++ b/openair3/NAS/COMMON/IES/NasMessageContainer.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/NasRequestType.c b/openair3/NAS/COMMON/IES/NasRequestType.c index 0bbe9ff3a8..cb85a38851 100644 --- a/openair3/NAS/COMMON/IES/NasRequestType.c +++ b/openair3/NAS/COMMON/IES/NasRequestType.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/NasRequestType.h b/openair3/NAS/COMMON/IES/NasRequestType.h index 3f98a8ffd3..7eb98ff42b 100644 --- a/openair3/NAS/COMMON/IES/NasRequestType.h +++ b/openair3/NAS/COMMON/IES/NasRequestType.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/NasSecurityAlgorithms.c b/openair3/NAS/COMMON/IES/NasSecurityAlgorithms.c index 24e0d21f68..7b57aab6a8 100644 --- a/openair3/NAS/COMMON/IES/NasSecurityAlgorithms.c +++ b/openair3/NAS/COMMON/IES/NasSecurityAlgorithms.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/NasSecurityAlgorithms.h b/openair3/NAS/COMMON/IES/NasSecurityAlgorithms.h index 9008c023b1..69e5b3080a 100644 --- a/openair3/NAS/COMMON/IES/NasSecurityAlgorithms.h +++ b/openair3/NAS/COMMON/IES/NasSecurityAlgorithms.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/NetworkName.c b/openair3/NAS/COMMON/IES/NetworkName.c index 3516e5b739..d0d92dccbe 100644 --- a/openair3/NAS/COMMON/IES/NetworkName.c +++ b/openair3/NAS/COMMON/IES/NetworkName.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/NetworkName.h b/openair3/NAS/COMMON/IES/NetworkName.h index b403edc337..7acae1b728 100644 --- a/openair3/NAS/COMMON/IES/NetworkName.h +++ b/openair3/NAS/COMMON/IES/NetworkName.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/Nonce.c b/openair3/NAS/COMMON/IES/Nonce.c index 97b5c40010..d584346c56 100644 --- a/openair3/NAS/COMMON/IES/Nonce.c +++ b/openair3/NAS/COMMON/IES/Nonce.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/Nonce.h b/openair3/NAS/COMMON/IES/Nonce.h index d4df86b98b..5bf3047a24 100644 --- a/openair3/NAS/COMMON/IES/Nonce.h +++ b/openair3/NAS/COMMON/IES/Nonce.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/PTmsiSignature.c b/openair3/NAS/COMMON/IES/PTmsiSignature.c index be37f869d7..2781cb77f2 100644 --- a/openair3/NAS/COMMON/IES/PTmsiSignature.c +++ b/openair3/NAS/COMMON/IES/PTmsiSignature.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/PTmsiSignature.h b/openair3/NAS/COMMON/IES/PTmsiSignature.h index 70023fa92d..75abf9e487 100644 --- a/openair3/NAS/COMMON/IES/PTmsiSignature.h +++ b/openair3/NAS/COMMON/IES/PTmsiSignature.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/PacketFlowIdentifier.c b/openair3/NAS/COMMON/IES/PacketFlowIdentifier.c index f19ba0547b..fef2edd10d 100644 --- a/openair3/NAS/COMMON/IES/PacketFlowIdentifier.c +++ b/openair3/NAS/COMMON/IES/PacketFlowIdentifier.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/PacketFlowIdentifier.h b/openair3/NAS/COMMON/IES/PacketFlowIdentifier.h index ffdb70b321..7dff70c49c 100644 --- a/openair3/NAS/COMMON/IES/PacketFlowIdentifier.h +++ b/openair3/NAS/COMMON/IES/PacketFlowIdentifier.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/PagingIdentity.c b/openair3/NAS/COMMON/IES/PagingIdentity.c index e970f51d20..e485fdc18a 100644 --- a/openair3/NAS/COMMON/IES/PagingIdentity.c +++ b/openair3/NAS/COMMON/IES/PagingIdentity.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/PagingIdentity.h b/openair3/NAS/COMMON/IES/PagingIdentity.h index 4f104400d3..e94a6a803a 100644 --- a/openair3/NAS/COMMON/IES/PagingIdentity.h +++ b/openair3/NAS/COMMON/IES/PagingIdentity.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/PdnAddress.c b/openair3/NAS/COMMON/IES/PdnAddress.c index 797b9472d8..de64d410c5 100644 --- a/openair3/NAS/COMMON/IES/PdnAddress.c +++ b/openair3/NAS/COMMON/IES/PdnAddress.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/PdnAddress.h b/openair3/NAS/COMMON/IES/PdnAddress.h index ee4fcd7e98..20b6f1d690 100644 --- a/openair3/NAS/COMMON/IES/PdnAddress.h +++ b/openair3/NAS/COMMON/IES/PdnAddress.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/PdnType.c b/openair3/NAS/COMMON/IES/PdnType.c index c01baa1dd3..e9bbfb3b87 100644 --- a/openair3/NAS/COMMON/IES/PdnType.c +++ b/openair3/NAS/COMMON/IES/PdnType.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/PdnType.h b/openair3/NAS/COMMON/IES/PdnType.h index 30d82f4a6a..844b35f3c4 100644 --- a/openair3/NAS/COMMON/IES/PdnType.h +++ b/openair3/NAS/COMMON/IES/PdnType.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/PlmnList.c b/openair3/NAS/COMMON/IES/PlmnList.c index ebaf5465ac..e6a3cecf4d 100644 --- a/openair3/NAS/COMMON/IES/PlmnList.c +++ b/openair3/NAS/COMMON/IES/PlmnList.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/PlmnList.h b/openair3/NAS/COMMON/IES/PlmnList.h index aa95673f67..6e6ac850c2 100644 --- a/openair3/NAS/COMMON/IES/PlmnList.h +++ b/openair3/NAS/COMMON/IES/PlmnList.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/ProcedureTransactionIdentity.c b/openair3/NAS/COMMON/IES/ProcedureTransactionIdentity.c index 09d4cbe310..802c13a907 100644 --- a/openair3/NAS/COMMON/IES/ProcedureTransactionIdentity.c +++ b/openair3/NAS/COMMON/IES/ProcedureTransactionIdentity.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/ProcedureTransactionIdentity.h b/openair3/NAS/COMMON/IES/ProcedureTransactionIdentity.h index 7aea7adae1..0f56e764d4 100644 --- a/openair3/NAS/COMMON/IES/ProcedureTransactionIdentity.h +++ b/openair3/NAS/COMMON/IES/ProcedureTransactionIdentity.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/ProtocolConfigurationOptions.c b/openair3/NAS/COMMON/IES/ProtocolConfigurationOptions.c index 006aa61e8e..f4bd3e5e2c 100644 --- a/openair3/NAS/COMMON/IES/ProtocolConfigurationOptions.c +++ b/openair3/NAS/COMMON/IES/ProtocolConfigurationOptions.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/ProtocolConfigurationOptions.h b/openair3/NAS/COMMON/IES/ProtocolConfigurationOptions.h index 71f989992c..cbdeaaed0e 100644 --- a/openair3/NAS/COMMON/IES/ProtocolConfigurationOptions.h +++ b/openair3/NAS/COMMON/IES/ProtocolConfigurationOptions.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/ProtocolDiscriminator.c b/openair3/NAS/COMMON/IES/ProtocolDiscriminator.c index 6e1d6bd875..41d2ada7ae 100644 --- a/openair3/NAS/COMMON/IES/ProtocolDiscriminator.c +++ b/openair3/NAS/COMMON/IES/ProtocolDiscriminator.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/ProtocolDiscriminator.h b/openair3/NAS/COMMON/IES/ProtocolDiscriminator.h index 32cf11a28a..465baf21f4 100644 --- a/openair3/NAS/COMMON/IES/ProtocolDiscriminator.h +++ b/openair3/NAS/COMMON/IES/ProtocolDiscriminator.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/QualityOfService.c b/openair3/NAS/COMMON/IES/QualityOfService.c index fff8130082..02c4ceca29 100644 --- a/openair3/NAS/COMMON/IES/QualityOfService.c +++ b/openair3/NAS/COMMON/IES/QualityOfService.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/QualityOfService.h b/openair3/NAS/COMMON/IES/QualityOfService.h index 53f0e9e763..a7f455b237 100644 --- a/openair3/NAS/COMMON/IES/QualityOfService.h +++ b/openair3/NAS/COMMON/IES/QualityOfService.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/RadioPriority.c b/openair3/NAS/COMMON/IES/RadioPriority.c index c41b05cec9..31780b8e89 100644 --- a/openair3/NAS/COMMON/IES/RadioPriority.c +++ b/openair3/NAS/COMMON/IES/RadioPriority.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/RadioPriority.h b/openair3/NAS/COMMON/IES/RadioPriority.h index bbf3ac4450..0f53fdaa77 100644 --- a/openair3/NAS/COMMON/IES/RadioPriority.h +++ b/openair3/NAS/COMMON/IES/RadioPriority.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/SecurityHeaderType.c b/openair3/NAS/COMMON/IES/SecurityHeaderType.c index 75ae311db2..0137e8cb9b 100644 --- a/openair3/NAS/COMMON/IES/SecurityHeaderType.c +++ b/openair3/NAS/COMMON/IES/SecurityHeaderType.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/SecurityHeaderType.h b/openair3/NAS/COMMON/IES/SecurityHeaderType.h index ee7635b391..dcfaea6f8a 100644 --- a/openair3/NAS/COMMON/IES/SecurityHeaderType.h +++ b/openair3/NAS/COMMON/IES/SecurityHeaderType.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/ServiceType.c b/openair3/NAS/COMMON/IES/ServiceType.c index 6ced7364c8..23079a09eb 100644 --- a/openair3/NAS/COMMON/IES/ServiceType.c +++ b/openair3/NAS/COMMON/IES/ServiceType.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/ServiceType.h b/openair3/NAS/COMMON/IES/ServiceType.h index 40778f82a6..f6dab7733b 100644 --- a/openair3/NAS/COMMON/IES/ServiceType.h +++ b/openair3/NAS/COMMON/IES/ServiceType.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/ShortMac.c b/openair3/NAS/COMMON/IES/ShortMac.c index 4b7aff1a76..74bcd772c6 100644 --- a/openair3/NAS/COMMON/IES/ShortMac.c +++ b/openair3/NAS/COMMON/IES/ShortMac.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/ShortMac.h b/openair3/NAS/COMMON/IES/ShortMac.h index 67ff8adf60..f2b1c7032d 100644 --- a/openair3/NAS/COMMON/IES/ShortMac.h +++ b/openair3/NAS/COMMON/IES/ShortMac.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/SsCode.c b/openair3/NAS/COMMON/IES/SsCode.c index ab6d34a159..255af689e3 100644 --- a/openair3/NAS/COMMON/IES/SsCode.c +++ b/openair3/NAS/COMMON/IES/SsCode.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/SsCode.h b/openair3/NAS/COMMON/IES/SsCode.h index 6ba6fe377c..8e6ae3b411 100644 --- a/openair3/NAS/COMMON/IES/SsCode.h +++ b/openair3/NAS/COMMON/IES/SsCode.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/SupportedCodecList.c b/openair3/NAS/COMMON/IES/SupportedCodecList.c index 17a9284f5e..3a69eee366 100644 --- a/openair3/NAS/COMMON/IES/SupportedCodecList.c +++ b/openair3/NAS/COMMON/IES/SupportedCodecList.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/SupportedCodecList.h b/openair3/NAS/COMMON/IES/SupportedCodecList.h index 04445fdd10..c4b727cb94 100644 --- a/openair3/NAS/COMMON/IES/SupportedCodecList.h +++ b/openair3/NAS/COMMON/IES/SupportedCodecList.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TimeZone.c b/openair3/NAS/COMMON/IES/TimeZone.c index 7b0bb54e21..eb65ec9295 100644 --- a/openair3/NAS/COMMON/IES/TimeZone.c +++ b/openair3/NAS/COMMON/IES/TimeZone.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TimeZone.h b/openair3/NAS/COMMON/IES/TimeZone.h index 585e05bb1c..5da012b14e 100644 --- a/openair3/NAS/COMMON/IES/TimeZone.h +++ b/openair3/NAS/COMMON/IES/TimeZone.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TimeZoneAndTime.c b/openair3/NAS/COMMON/IES/TimeZoneAndTime.c index c986ecfc7c..6a26eeac78 100644 --- a/openair3/NAS/COMMON/IES/TimeZoneAndTime.c +++ b/openair3/NAS/COMMON/IES/TimeZoneAndTime.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TimeZoneAndTime.h b/openair3/NAS/COMMON/IES/TimeZoneAndTime.h index 6ddbf94ab8..71cce4e881 100644 --- a/openair3/NAS/COMMON/IES/TimeZoneAndTime.h +++ b/openair3/NAS/COMMON/IES/TimeZoneAndTime.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TmsiStatus.c b/openair3/NAS/COMMON/IES/TmsiStatus.c index c4c328316f..726e096c78 100644 --- a/openair3/NAS/COMMON/IES/TmsiStatus.c +++ b/openair3/NAS/COMMON/IES/TmsiStatus.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TmsiStatus.h b/openair3/NAS/COMMON/IES/TmsiStatus.h index dc7c3eaafd..48611f9a0c 100644 --- a/openair3/NAS/COMMON/IES/TmsiStatus.h +++ b/openair3/NAS/COMMON/IES/TmsiStatus.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TrackingAreaIdentity.c b/openair3/NAS/COMMON/IES/TrackingAreaIdentity.c index 20ade47268..a77419c80c 100644 --- a/openair3/NAS/COMMON/IES/TrackingAreaIdentity.c +++ b/openair3/NAS/COMMON/IES/TrackingAreaIdentity.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TrackingAreaIdentity.h b/openair3/NAS/COMMON/IES/TrackingAreaIdentity.h index 72d5d44f0d..bc5810c895 100644 --- a/openair3/NAS/COMMON/IES/TrackingAreaIdentity.h +++ b/openair3/NAS/COMMON/IES/TrackingAreaIdentity.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TrackingAreaIdentityList.c b/openair3/NAS/COMMON/IES/TrackingAreaIdentityList.c index 47269add10..2e700abbee 100644 --- a/openair3/NAS/COMMON/IES/TrackingAreaIdentityList.c +++ b/openair3/NAS/COMMON/IES/TrackingAreaIdentityList.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TrackingAreaIdentityList.h b/openair3/NAS/COMMON/IES/TrackingAreaIdentityList.h index 1c58afbcb5..d085e8436f 100644 --- a/openair3/NAS/COMMON/IES/TrackingAreaIdentityList.h +++ b/openair3/NAS/COMMON/IES/TrackingAreaIdentityList.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TrafficFlowAggregateDescription.c b/openair3/NAS/COMMON/IES/TrafficFlowAggregateDescription.c index 296ecbe6f1..ad7af4c6c1 100644 --- a/openair3/NAS/COMMON/IES/TrafficFlowAggregateDescription.c +++ b/openair3/NAS/COMMON/IES/TrafficFlowAggregateDescription.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TrafficFlowAggregateDescription.h b/openair3/NAS/COMMON/IES/TrafficFlowAggregateDescription.h index 09e9450d8d..ae013cf304 100644 --- a/openair3/NAS/COMMON/IES/TrafficFlowAggregateDescription.h +++ b/openair3/NAS/COMMON/IES/TrafficFlowAggregateDescription.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TrafficFlowTemplate.c b/openair3/NAS/COMMON/IES/TrafficFlowTemplate.c index 57f8d3ba00..d5ab249573 100644 --- a/openair3/NAS/COMMON/IES/TrafficFlowTemplate.c +++ b/openair3/NAS/COMMON/IES/TrafficFlowTemplate.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TrafficFlowTemplate.h b/openair3/NAS/COMMON/IES/TrafficFlowTemplate.h index 920caea056..651ec7ef5c 100644 --- a/openair3/NAS/COMMON/IES/TrafficFlowTemplate.h +++ b/openair3/NAS/COMMON/IES/TrafficFlowTemplate.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TransactionIdentifier.c b/openair3/NAS/COMMON/IES/TransactionIdentifier.c index dbc2c68cab..ce77d6ba34 100644 --- a/openair3/NAS/COMMON/IES/TransactionIdentifier.c +++ b/openair3/NAS/COMMON/IES/TransactionIdentifier.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/TransactionIdentifier.h b/openair3/NAS/COMMON/IES/TransactionIdentifier.h index aaa0836f38..cf19a2f6f5 100644 --- a/openair3/NAS/COMMON/IES/TransactionIdentifier.h +++ b/openair3/NAS/COMMON/IES/TransactionIdentifier.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/UeNetworkCapability.c b/openair3/NAS/COMMON/IES/UeNetworkCapability.c index 46d07a0fdf..6589075173 100644 --- a/openair3/NAS/COMMON/IES/UeNetworkCapability.c +++ b/openair3/NAS/COMMON/IES/UeNetworkCapability.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/UeNetworkCapability.h b/openair3/NAS/COMMON/IES/UeNetworkCapability.h index 5bf6035323..a93587c33c 100644 --- a/openair3/NAS/COMMON/IES/UeNetworkCapability.h +++ b/openair3/NAS/COMMON/IES/UeNetworkCapability.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/UeRadioCapabilityInformationUpdateNeeded.c b/openair3/NAS/COMMON/IES/UeRadioCapabilityInformationUpdateNeeded.c index 7d506881ee..a56400c54d 100644 --- a/openair3/NAS/COMMON/IES/UeRadioCapabilityInformationUpdateNeeded.c +++ b/openair3/NAS/COMMON/IES/UeRadioCapabilityInformationUpdateNeeded.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/UeRadioCapabilityInformationUpdateNeeded.h b/openair3/NAS/COMMON/IES/UeRadioCapabilityInformationUpdateNeeded.h index fb25c0808a..7ae83bd5ea 100644 --- a/openair3/NAS/COMMON/IES/UeRadioCapabilityInformationUpdateNeeded.h +++ b/openair3/NAS/COMMON/IES/UeRadioCapabilityInformationUpdateNeeded.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/UeSecurityCapability.c b/openair3/NAS/COMMON/IES/UeSecurityCapability.c index ee462594fd..9b40b1b85c 100644 --- a/openair3/NAS/COMMON/IES/UeSecurityCapability.c +++ b/openair3/NAS/COMMON/IES/UeSecurityCapability.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/UeSecurityCapability.h b/openair3/NAS/COMMON/IES/UeSecurityCapability.h index a15f74570d..d9726d76e0 100644 --- a/openair3/NAS/COMMON/IES/UeSecurityCapability.h +++ b/openair3/NAS/COMMON/IES/UeSecurityCapability.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/VoiceDomainPreferenceAndUeUsageSetting.c b/openair3/NAS/COMMON/IES/VoiceDomainPreferenceAndUeUsageSetting.c index 6c644dedf3..156c68d80f 100644 --- a/openair3/NAS/COMMON/IES/VoiceDomainPreferenceAndUeUsageSetting.c +++ b/openair3/NAS/COMMON/IES/VoiceDomainPreferenceAndUeUsageSetting.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/IES/VoiceDomainPreferenceAndUeUsageSetting.h b/openair3/NAS/COMMON/IES/VoiceDomainPreferenceAndUeUsageSetting.h index fd1353833d..b7dbe35de4 100644 --- a/openair3/NAS/COMMON/IES/VoiceDomainPreferenceAndUeUsageSetting.h +++ b/openair3/NAS/COMMON/IES/VoiceDomainPreferenceAndUeUsageSetting.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/OctetString.c b/openair3/NAS/COMMON/UTIL/OctetString.c index 2763006126..3083068585 100644 --- a/openair3/NAS/COMMON/UTIL/OctetString.c +++ b/openair3/NAS/COMMON/UTIL/OctetString.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/OctetString.h b/openair3/NAS/COMMON/UTIL/OctetString.h index c0c54fcb09..2223b67ece 100644 --- a/openair3/NAS/COMMON/UTIL/OctetString.h +++ b/openair3/NAS/COMMON/UTIL/OctetString.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/TLVDecoder.c b/openair3/NAS/COMMON/UTIL/TLVDecoder.c index 9c27452bec..353e16554d 100644 --- a/openair3/NAS/COMMON/UTIL/TLVDecoder.c +++ b/openair3/NAS/COMMON/UTIL/TLVDecoder.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/TLVDecoder.h b/openair3/NAS/COMMON/UTIL/TLVDecoder.h index 37834c5660..e8dce87d8d 100644 --- a/openair3/NAS/COMMON/UTIL/TLVDecoder.h +++ b/openair3/NAS/COMMON/UTIL/TLVDecoder.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/TLVEncoder.c b/openair3/NAS/COMMON/UTIL/TLVEncoder.c index 0facb0d5f7..9d3a144989 100644 --- a/openair3/NAS/COMMON/UTIL/TLVEncoder.c +++ b/openair3/NAS/COMMON/UTIL/TLVEncoder.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/TLVEncoder.h b/openair3/NAS/COMMON/UTIL/TLVEncoder.h index 976289f25b..df5b58a07f 100644 --- a/openair3/NAS/COMMON/UTIL/TLVEncoder.h +++ b/openair3/NAS/COMMON/UTIL/TLVEncoder.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/device.c b/openair3/NAS/COMMON/UTIL/device.c index 6643c6dfd9..7ad2879b90 100644 --- a/openair3/NAS/COMMON/UTIL/device.c +++ b/openair3/NAS/COMMON/UTIL/device.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/device.h b/openair3/NAS/COMMON/UTIL/device.h index fb0a9add13..975d7b1c8a 100644 --- a/openair3/NAS/COMMON/UTIL/device.h +++ b/openair3/NAS/COMMON/UTIL/device.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/memory.c b/openair3/NAS/COMMON/UTIL/memory.c index 3b3b6e7f9e..334cdc5eb6 100644 --- a/openair3/NAS/COMMON/UTIL/memory.c +++ b/openair3/NAS/COMMON/UTIL/memory.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/memory.h b/openair3/NAS/COMMON/UTIL/memory.h index f7f0733044..ec8406c932 100644 --- a/openair3/NAS/COMMON/UTIL/memory.h +++ b/openair3/NAS/COMMON/UTIL/memory.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/nas_log.c b/openair3/NAS/COMMON/UTIL/nas_log.c index a1568c49d8..6af90c4be8 100644 --- a/openair3/NAS/COMMON/UTIL/nas_log.c +++ b/openair3/NAS/COMMON/UTIL/nas_log.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/nas_log.h b/openair3/NAS/COMMON/UTIL/nas_log.h index c6e0fbcd80..47664c52d0 100644 --- a/openair3/NAS/COMMON/UTIL/nas_log.h +++ b/openair3/NAS/COMMON/UTIL/nas_log.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/nas_timer.c b/openair3/NAS/COMMON/UTIL/nas_timer.c index aa67c72b42..0b92ac4d9d 100644 --- a/openair3/NAS/COMMON/UTIL/nas_timer.c +++ b/openair3/NAS/COMMON/UTIL/nas_timer.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/nas_timer.h b/openair3/NAS/COMMON/UTIL/nas_timer.h index 007ea236b7..b1149f21c0 100644 --- a/openair3/NAS/COMMON/UTIL/nas_timer.h +++ b/openair3/NAS/COMMON/UTIL/nas_timer.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/parser.c b/openair3/NAS/COMMON/UTIL/parser.c index e60e7eca88..e27fb38199 100644 --- a/openair3/NAS/COMMON/UTIL/parser.c +++ b/openair3/NAS/COMMON/UTIL/parser.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/parser.h b/openair3/NAS/COMMON/UTIL/parser.h index 2061c7201d..ae454ce367 100644 --- a/openair3/NAS/COMMON/UTIL/parser.h +++ b/openair3/NAS/COMMON/UTIL/parser.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/socket.c b/openair3/NAS/COMMON/UTIL/socket.c index 6d27228415..8ec3227e20 100644 --- a/openair3/NAS/COMMON/UTIL/socket.c +++ b/openair3/NAS/COMMON/UTIL/socket.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/socket.h b/openair3/NAS/COMMON/UTIL/socket.h index ae198a489c..033046d98c 100644 --- a/openair3/NAS/COMMON/UTIL/socket.h +++ b/openair3/NAS/COMMON/UTIL/socket.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/stty.c b/openair3/NAS/COMMON/UTIL/stty.c index 88b66eb09b..eceb0b06b1 100644 --- a/openair3/NAS/COMMON/UTIL/stty.c +++ b/openair3/NAS/COMMON/UTIL/stty.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/UTIL/tst/timer.c b/openair3/NAS/COMMON/UTIL/tst/timer.c index 449c4d749b..701c878f4d 100644 --- a/openair3/NAS/COMMON/UTIL/tst/timer.c +++ b/openair3/NAS/COMMON/UTIL/tst/timer.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/securityDef.h b/openair3/NAS/COMMON/securityDef.h index ef39d5533c..30732f26f5 100644 --- a/openair3/NAS/COMMON/securityDef.h +++ b/openair3/NAS/COMMON/securityDef.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/COMMON/userDef.h b/openair3/NAS/COMMON/userDef.h index c5989c8e45..fdb8287b3b 100644 --- a/openair3/NAS/COMMON/userDef.h +++ b/openair3/NAS/COMMON/userDef.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/AS_SIMULATOR/Makefile b/openair3/NAS/TEST/AS_SIMULATOR/Makefile index 17710368e9..3d379c6d06 100644 --- a/openair3/NAS/TEST/AS_SIMULATOR/Makefile +++ b/openair3/NAS/TEST/AS_SIMULATOR/Makefile @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/openair3/NAS/TEST/AS_SIMULATOR/as_data.c b/openair3/NAS/TEST/AS_SIMULATOR/as_data.c index 9316546bd4..56b00125a4 100644 --- a/openair3/NAS/TEST/AS_SIMULATOR/as_data.c +++ b/openair3/NAS/TEST/AS_SIMULATOR/as_data.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/AS_SIMULATOR/as_data.h b/openair3/NAS/TEST/AS_SIMULATOR/as_data.h index c52ed83465..24c6473730 100644 --- a/openair3/NAS/TEST/AS_SIMULATOR/as_data.h +++ b/openair3/NAS/TEST/AS_SIMULATOR/as_data.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/AS_SIMULATOR/as_process.c b/openair3/NAS/TEST/AS_SIMULATOR/as_process.c index e0f031c45a..21e484e40a 100644 --- a/openair3/NAS/TEST/AS_SIMULATOR/as_process.c +++ b/openair3/NAS/TEST/AS_SIMULATOR/as_process.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/AS_SIMULATOR/as_process.h b/openair3/NAS/TEST/AS_SIMULATOR/as_process.h index 94053bdf9e..75df1f0d88 100644 --- a/openair3/NAS/TEST/AS_SIMULATOR/as_process.h +++ b/openair3/NAS/TEST/AS_SIMULATOR/as_process.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/AS_SIMULATOR/as_simulator.c b/openair3/NAS/TEST/AS_SIMULATOR/as_simulator.c index 370213bccd..efe2c1af72 100644 --- a/openair3/NAS/TEST/AS_SIMULATOR/as_simulator.c +++ b/openair3/NAS/TEST/AS_SIMULATOR/as_simulator.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/AS_SIMULATOR/as_simulator_parser.c b/openair3/NAS/TEST/AS_SIMULATOR/as_simulator_parser.c index 5f8743598b..ff6720da5f 100644 --- a/openair3/NAS/TEST/AS_SIMULATOR/as_simulator_parser.c +++ b/openair3/NAS/TEST/AS_SIMULATOR/as_simulator_parser.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/AS_SIMULATOR/as_simulator_parser.h b/openair3/NAS/TEST/AS_SIMULATOR/as_simulator_parser.h index c08021723f..b15bf8f29b 100644 --- a/openair3/NAS/TEST/AS_SIMULATOR/as_simulator_parser.h +++ b/openair3/NAS/TEST/AS_SIMULATOR/as_simulator_parser.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/AS_SIMULATOR/nas_data.c b/openair3/NAS/TEST/AS_SIMULATOR/nas_data.c index 0aa6a57126..990a856a9d 100644 --- a/openair3/NAS/TEST/AS_SIMULATOR/nas_data.c +++ b/openair3/NAS/TEST/AS_SIMULATOR/nas_data.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/AS_SIMULATOR/nas_data.h b/openair3/NAS/TEST/AS_SIMULATOR/nas_data.h index 471cd19957..ff55007014 100644 --- a/openair3/NAS/TEST/AS_SIMULATOR/nas_data.h +++ b/openair3/NAS/TEST/AS_SIMULATOR/nas_data.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/AS_SIMULATOR/nas_process.c b/openair3/NAS/TEST/AS_SIMULATOR/nas_process.c index 55c6c2494e..17ad99715b 100644 --- a/openair3/NAS/TEST/AS_SIMULATOR/nas_process.c +++ b/openair3/NAS/TEST/AS_SIMULATOR/nas_process.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/AS_SIMULATOR/nas_process.h b/openair3/NAS/TEST/AS_SIMULATOR/nas_process.h index 901e6ce45b..ae5baebafc 100644 --- a/openair3/NAS/TEST/AS_SIMULATOR/nas_process.h +++ b/openair3/NAS/TEST/AS_SIMULATOR/nas_process.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/NETWORK/Makefile b/openair3/NAS/TEST/NETWORK/Makefile index 00a74ec561..b0b5516801 100644 --- a/openair3/NAS/TEST/NETWORK/Makefile +++ b/openair3/NAS/TEST/NETWORK/Makefile @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/openair3/NAS/TEST/NETWORK/network_parser.c b/openair3/NAS/TEST/NETWORK/network_parser.c index 0e001e0aee..f540a8a99c 100644 --- a/openair3/NAS/TEST/NETWORK/network_parser.c +++ b/openair3/NAS/TEST/NETWORK/network_parser.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/NETWORK/network_parser.h b/openair3/NAS/TEST/NETWORK/network_parser.h index daaec64ffd..a20c313be3 100644 --- a/openair3/NAS/TEST/NETWORK/network_parser.h +++ b/openair3/NAS/TEST/NETWORK/network_parser.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/NETWORK/network_simulator.c b/openair3/NAS/TEST/NETWORK/network_simulator.c index ef335af2ec..294241a384 100644 --- a/openair3/NAS/TEST/NETWORK/network_simulator.c +++ b/openair3/NAS/TEST/NETWORK/network_simulator.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/USER/Makefile b/openair3/NAS/TEST/USER/Makefile index 69a2a67387..6f613b3cc9 100644 --- a/openair3/NAS/TEST/USER/Makefile +++ b/openair3/NAS/TEST/USER/Makefile @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/openair3/NAS/TEST/USER/user_parser.c b/openair3/NAS/TEST/USER/user_parser.c index ffa47a919c..2b7afd5d04 100644 --- a/openair3/NAS/TEST/USER/user_parser.c +++ b/openair3/NAS/TEST/USER/user_parser.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/USER/user_parser.h b/openair3/NAS/TEST/USER/user_parser.h index 40fa618270..d1972de028 100644 --- a/openair3/NAS/TEST/USER/user_parser.h +++ b/openair3/NAS/TEST/USER/user_parser.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TEST/USER/user_simulator.c b/openair3/NAS/TEST/USER/user_simulator.c index 2f0819f597..ec16b3453f 100644 --- a/openair3/NAS/TEST/USER/user_simulator.c +++ b/openair3/NAS/TEST/USER/user_simulator.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TOOLS/network.h b/openair3/NAS/TOOLS/network.h index d7044c8e51..cde82f4560 100644 --- a/openair3/NAS/TOOLS/network.h +++ b/openair3/NAS/TOOLS/network.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TOOLS/nvram.c b/openair3/NAS/TOOLS/nvram.c index b10511f2fc..80d8b34893 100644 --- a/openair3/NAS/TOOLS/nvram.c +++ b/openair3/NAS/TOOLS/nvram.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/TOOLS/usim.c b/openair3/NAS/TOOLS/usim.c index 242b30d655..84b4cfbdf8 100644 --- a/openair3/NAS/TOOLS/usim.c +++ b/openair3/NAS/TOOLS/usim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USER/at_command.c b/openair3/NAS/UE/API/USER/at_command.c index 8f40ba93c4..ab85b2d2fa 100644 --- a/openair3/NAS/UE/API/USER/at_command.c +++ b/openair3/NAS/UE/API/USER/at_command.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USER/at_command.h b/openair3/NAS/UE/API/USER/at_command.h index 97cdeeb3a1..b7bdb11b75 100644 --- a/openair3/NAS/UE/API/USER/at_command.h +++ b/openair3/NAS/UE/API/USER/at_command.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USER/at_error.c b/openair3/NAS/UE/API/USER/at_error.c index 7548fb513e..d004c89736 100644 --- a/openair3/NAS/UE/API/USER/at_error.c +++ b/openair3/NAS/UE/API/USER/at_error.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USER/at_error.h b/openair3/NAS/UE/API/USER/at_error.h index de9284e94c..a84875a43c 100644 --- a/openair3/NAS/UE/API/USER/at_error.h +++ b/openair3/NAS/UE/API/USER/at_error.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USER/at_response.c b/openair3/NAS/UE/API/USER/at_response.c index 5c1dcc1a96..a488aa78d9 100644 --- a/openair3/NAS/UE/API/USER/at_response.c +++ b/openair3/NAS/UE/API/USER/at_response.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USER/at_response.h b/openair3/NAS/UE/API/USER/at_response.h index 794af05090..b0303c5875 100644 --- a/openair3/NAS/UE/API/USER/at_response.h +++ b/openair3/NAS/UE/API/USER/at_response.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USER/tst/at_parser.c b/openair3/NAS/UE/API/USER/tst/at_parser.c index e580c99ec5..2039d81a63 100644 --- a/openair3/NAS/UE/API/USER/tst/at_parser.c +++ b/openair3/NAS/UE/API/USER/tst/at_parser.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USER/user_api.c b/openair3/NAS/UE/API/USER/user_api.c index a1300ea059..83839a90f3 100644 --- a/openair3/NAS/UE/API/USER/user_api.c +++ b/openair3/NAS/UE/API/USER/user_api.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USER/user_api.h b/openair3/NAS/UE/API/USER/user_api.h index 6536144165..e554b4ef0b 100644 --- a/openair3/NAS/UE/API/USER/user_api.h +++ b/openair3/NAS/UE/API/USER/user_api.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USER/user_indication.c b/openair3/NAS/UE/API/USER/user_indication.c index 620596005d..2c102c1d46 100644 --- a/openair3/NAS/UE/API/USER/user_indication.c +++ b/openair3/NAS/UE/API/USER/user_indication.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USER/user_indication.h b/openair3/NAS/UE/API/USER/user_indication.h index 39aba424e7..d86ab43dca 100644 --- a/openair3/NAS/UE/API/USER/user_indication.h +++ b/openair3/NAS/UE/API/USER/user_indication.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USIM/aka_functions.c b/openair3/NAS/UE/API/USIM/aka_functions.c index 4d8f4cd1d3..88a9415e08 100644 --- a/openair3/NAS/UE/API/USIM/aka_functions.c +++ b/openair3/NAS/UE/API/USIM/aka_functions.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USIM/aka_functions.h b/openair3/NAS/UE/API/USIM/aka_functions.h index 8c370bb76c..4e28ead86a 100644 --- a/openair3/NAS/UE/API/USIM/aka_functions.h +++ b/openair3/NAS/UE/API/USIM/aka_functions.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USIM/usim_api.c b/openair3/NAS/UE/API/USIM/usim_api.c index efb0383596..d8a3807ab3 100644 --- a/openair3/NAS/UE/API/USIM/usim_api.c +++ b/openair3/NAS/UE/API/USIM/usim_api.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/API/USIM/usim_api.h b/openair3/NAS/UE/API/USIM/usim_api.h index f2f80d610c..f332b5ffc8 100644 --- a/openair3/NAS/UE/API/USIM/usim_api.h +++ b/openair3/NAS/UE/API/USIM/usim_api.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/Attach.c b/openair3/NAS/UE/EMM/Attach.c index c0c82b9b4c..4029c8f702 100644 --- a/openair3/NAS/UE/EMM/Attach.c +++ b/openair3/NAS/UE/EMM/Attach.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/Authentication.c b/openair3/NAS/UE/EMM/Authentication.c index e49bdd2db7..5b10e60893 100644 --- a/openair3/NAS/UE/EMM/Authentication.c +++ b/openair3/NAS/UE/EMM/Authentication.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/Detach.c b/openair3/NAS/UE/EMM/Detach.c index fd2db1b617..c18dc0ad28 100644 --- a/openair3/NAS/UE/EMM/Detach.c +++ b/openair3/NAS/UE/EMM/Detach.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/EmmStatusHdl.c b/openair3/NAS/UE/EMM/EmmStatusHdl.c index 89dd50207f..367d0327f4 100644 --- a/openair3/NAS/UE/EMM/EmmStatusHdl.c +++ b/openair3/NAS/UE/EMM/EmmStatusHdl.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/Identification.c b/openair3/NAS/UE/EMM/Identification.c index 7cf2e765c6..0d2d6644a1 100644 --- a/openair3/NAS/UE/EMM/Identification.c +++ b/openair3/NAS/UE/EMM/Identification.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/IdleMode.c b/openair3/NAS/UE/EMM/IdleMode.c index 159a3b2a2c..362d5e5b4a 100644 --- a/openair3/NAS/UE/EMM/IdleMode.c +++ b/openair3/NAS/UE/EMM/IdleMode.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/IdleMode.h b/openair3/NAS/UE/EMM/IdleMode.h index e80b4f9134..4584877974 100644 --- a/openair3/NAS/UE/EMM/IdleMode.h +++ b/openair3/NAS/UE/EMM/IdleMode.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/LowerLayer.c b/openair3/NAS/UE/EMM/LowerLayer.c index b5555b2c2f..01b07fc356 100644 --- a/openair3/NAS/UE/EMM/LowerLayer.c +++ b/openair3/NAS/UE/EMM/LowerLayer.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/LowerLayer.h b/openair3/NAS/UE/EMM/LowerLayer.h index 00e271feaa..0d8eefc7f3 100644 --- a/openair3/NAS/UE/EMM/LowerLayer.h +++ b/openair3/NAS/UE/EMM/LowerLayer.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregistered.c b/openair3/NAS/UE/EMM/SAP/EmmDeregistered.c index a2a93c4d78..71e2c4a49c 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmDeregistered.c +++ b/openair3/NAS/UE/EMM/SAP/EmmDeregistered.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredAttachNeeded.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredAttachNeeded.c index cbdc470a0b..834311be74 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredAttachNeeded.c +++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredAttachNeeded.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredAttemptingToAttach.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredAttemptingToAttach.c index 7ddfac03db..f58cf4b9e0 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredAttemptingToAttach.c +++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredAttemptingToAttach.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredInitiated.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredInitiated.c index d18b66a316..a44438a3a8 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredInitiated.c +++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredInitiated.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredLimitedService.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredLimitedService.c index 3943254415..4310f963cd 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredLimitedService.c +++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredLimitedService.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNoCellAvailable.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNoCellAvailable.c index af9ab5e5be..84820568cc 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNoCellAvailable.c +++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNoCellAvailable.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNoImsi.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNoImsi.c index 0f883c8109..6dc1d3304a 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNoImsi.c +++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNoImsi.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c index 3ec7a96ba8..fe18a98d38 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c +++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredPlmnSearch.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredPlmnSearch.c index ed41362f2f..8560b2a4bb 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredPlmnSearch.c +++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredPlmnSearch.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmNull.c b/openair3/NAS/UE/EMM/SAP/EmmNull.c index 7b553f0a76..e2e45c99cc 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmNull.c +++ b/openair3/NAS/UE/EMM/SAP/EmmNull.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmRegistered.c b/openair3/NAS/UE/EMM/SAP/EmmRegistered.c index dbc51e5155..fbd3e1ce63 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmRegistered.c +++ b/openair3/NAS/UE/EMM/SAP/EmmRegistered.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmRegisteredAttemptingToUpdate.c b/openair3/NAS/UE/EMM/SAP/EmmRegisteredAttemptingToUpdate.c index 21654123d1..cf95cd3f56 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmRegisteredAttemptingToUpdate.c +++ b/openair3/NAS/UE/EMM/SAP/EmmRegisteredAttemptingToUpdate.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmRegisteredImsiDetachInitiated.c b/openair3/NAS/UE/EMM/SAP/EmmRegisteredImsiDetachInitiated.c index 6855843a25..26de1cd377 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmRegisteredImsiDetachInitiated.c +++ b/openair3/NAS/UE/EMM/SAP/EmmRegisteredImsiDetachInitiated.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmRegisteredInitiated.c b/openair3/NAS/UE/EMM/SAP/EmmRegisteredInitiated.c index d10f0d1053..36929fc4d7 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmRegisteredInitiated.c +++ b/openair3/NAS/UE/EMM/SAP/EmmRegisteredInitiated.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmRegisteredLimitedService.c b/openair3/NAS/UE/EMM/SAP/EmmRegisteredLimitedService.c index b4ea68f689..af60b566b8 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmRegisteredLimitedService.c +++ b/openair3/NAS/UE/EMM/SAP/EmmRegisteredLimitedService.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmRegisteredNoCellAvailable.c b/openair3/NAS/UE/EMM/SAP/EmmRegisteredNoCellAvailable.c index 0328ae8192..5aa408a8f9 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmRegisteredNoCellAvailable.c +++ b/openair3/NAS/UE/EMM/SAP/EmmRegisteredNoCellAvailable.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmRegisteredNormalService.c b/openair3/NAS/UE/EMM/SAP/EmmRegisteredNormalService.c index 8b1c8721f2..4ee503ab9f 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmRegisteredNormalService.c +++ b/openair3/NAS/UE/EMM/SAP/EmmRegisteredNormalService.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmRegisteredPlmnSearch.c b/openair3/NAS/UE/EMM/SAP/EmmRegisteredPlmnSearch.c index 8ee92c4454..e300ac58db 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmRegisteredPlmnSearch.c +++ b/openair3/NAS/UE/EMM/SAP/EmmRegisteredPlmnSearch.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmRegisteredUpdateNeeded.c b/openair3/NAS/UE/EMM/SAP/EmmRegisteredUpdateNeeded.c index 2a81b488dc..dceb0a87d1 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmRegisteredUpdateNeeded.c +++ b/openair3/NAS/UE/EMM/SAP/EmmRegisteredUpdateNeeded.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmServiceRequestInitiated.c b/openair3/NAS/UE/EMM/SAP/EmmServiceRequestInitiated.c index b556efb7f4..fa1944458e 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmServiceRequestInitiated.c +++ b/openair3/NAS/UE/EMM/SAP/EmmServiceRequestInitiated.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/EmmTrackingAreaUpdatingInitiated.c b/openair3/NAS/UE/EMM/SAP/EmmTrackingAreaUpdatingInitiated.c index 91bb660ee1..610eb13b36 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmTrackingAreaUpdatingInitiated.c +++ b/openair3/NAS/UE/EMM/SAP/EmmTrackingAreaUpdatingInitiated.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_as.c b/openair3/NAS/UE/EMM/SAP/emm_as.c index d833b5bba0..fbb54d548b 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_as.c +++ b/openair3/NAS/UE/EMM/SAP/emm_as.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_as.h b/openair3/NAS/UE/EMM/SAP/emm_as.h index 726a363d75..24ecef6926 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_as.h +++ b/openair3/NAS/UE/EMM/SAP/emm_as.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_asDef.h b/openair3/NAS/UE/EMM/SAP/emm_asDef.h index 69ea979b63..7bd464ec04 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_asDef.h +++ b/openair3/NAS/UE/EMM/SAP/emm_asDef.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_esm.c b/openair3/NAS/UE/EMM/SAP/emm_esm.c index 798e682b11..5d45da8591 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_esm.c +++ b/openair3/NAS/UE/EMM/SAP/emm_esm.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_esm.h b/openair3/NAS/UE/EMM/SAP/emm_esm.h index 11aa42213f..e74e1f7dc0 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_esm.h +++ b/openair3/NAS/UE/EMM/SAP/emm_esm.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_esmDef.h b/openair3/NAS/UE/EMM/SAP/emm_esmDef.h index 811580ab2a..aac37b46bf 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_esmDef.h +++ b/openair3/NAS/UE/EMM/SAP/emm_esmDef.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_fsm.c b/openair3/NAS/UE/EMM/SAP/emm_fsm.c index be1517a7cc..a2ede7ae17 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_fsm.c +++ b/openair3/NAS/UE/EMM/SAP/emm_fsm.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_fsm.h b/openair3/NAS/UE/EMM/SAP/emm_fsm.h index aba1ef327c..bc1faf2f85 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_fsm.h +++ b/openair3/NAS/UE/EMM/SAP/emm_fsm.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_recv.c b/openair3/NAS/UE/EMM/SAP/emm_recv.c index 5b7c6d7dda..2c901eb49b 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_recv.c +++ b/openair3/NAS/UE/EMM/SAP/emm_recv.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_recv.h b/openair3/NAS/UE/EMM/SAP/emm_recv.h index ead59e3851..ccfc8fd2a2 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_recv.h +++ b/openair3/NAS/UE/EMM/SAP/emm_recv.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_reg.c b/openair3/NAS/UE/EMM/SAP/emm_reg.c index 6cda066b58..87c1f1bbd1 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_reg.c +++ b/openair3/NAS/UE/EMM/SAP/emm_reg.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_reg.h b/openair3/NAS/UE/EMM/SAP/emm_reg.h index 9cd1132c7a..96a68f1fce 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_reg.h +++ b/openair3/NAS/UE/EMM/SAP/emm_reg.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_regDef.h b/openair3/NAS/UE/EMM/SAP/emm_regDef.h index de1b05b6a6..b66c0565ea 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_regDef.h +++ b/openair3/NAS/UE/EMM/SAP/emm_regDef.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_sap.c b/openair3/NAS/UE/EMM/SAP/emm_sap.c index 429518d475..3f48cf3d8f 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_sap.c +++ b/openair3/NAS/UE/EMM/SAP/emm_sap.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_sap.h b/openair3/NAS/UE/EMM/SAP/emm_sap.h index b84fd7808b..98088a66f3 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_sap.h +++ b/openair3/NAS/UE/EMM/SAP/emm_sap.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_send.c b/openair3/NAS/UE/EMM/SAP/emm_send.c index e3fc4fa7f9..56708eded3 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_send.c +++ b/openair3/NAS/UE/EMM/SAP/emm_send.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SAP/emm_send.h b/openair3/NAS/UE/EMM/SAP/emm_send.h index 1c04cd8dad..7cd4fb132f 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_send.h +++ b/openair3/NAS/UE/EMM/SAP/emm_send.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/SecurityModeControl.c b/openair3/NAS/UE/EMM/SecurityModeControl.c index 0991fb22bb..7bdd21572e 100644 --- a/openair3/NAS/UE/EMM/SecurityModeControl.c +++ b/openair3/NAS/UE/EMM/SecurityModeControl.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/ServiceRequestHdl.c b/openair3/NAS/UE/EMM/ServiceRequestHdl.c index 93e66efdbd..b305ee1690 100644 --- a/openair3/NAS/UE/EMM/ServiceRequestHdl.c +++ b/openair3/NAS/UE/EMM/ServiceRequestHdl.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/TrackingAreaUpdate.c b/openair3/NAS/UE/EMM/TrackingAreaUpdate.c index bafddaf317..b8632ef257 100644 --- a/openair3/NAS/UE/EMM/TrackingAreaUpdate.c +++ b/openair3/NAS/UE/EMM/TrackingAreaUpdate.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/emmData.h b/openair3/NAS/UE/EMM/emmData.h index 84e58bb963..dfdfb34e77 100644 --- a/openair3/NAS/UE/EMM/emmData.h +++ b/openair3/NAS/UE/EMM/emmData.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/emm_main.c b/openair3/NAS/UE/EMM/emm_main.c index 8f3ed17e4c..329b59fae6 100644 --- a/openair3/NAS/UE/EMM/emm_main.c +++ b/openair3/NAS/UE/EMM/emm_main.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/emm_main.h b/openair3/NAS/UE/EMM/emm_main.h index aa98965b04..055127b15d 100644 --- a/openair3/NAS/UE/EMM/emm_main.h +++ b/openair3/NAS/UE/EMM/emm_main.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/EMM/emm_proc.h b/openair3/NAS/UE/EMM/emm_proc.h index 4505257335..7d4024d9d6 100644 --- a/openair3/NAS/UE/EMM/emm_proc.h +++ b/openair3/NAS/UE/EMM/emm_proc.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/DedicatedEpsBearerContextActivation.c b/openair3/NAS/UE/ESM/DedicatedEpsBearerContextActivation.c index e213356332..21c3da3f19 100644 --- a/openair3/NAS/UE/ESM/DedicatedEpsBearerContextActivation.c +++ b/openair3/NAS/UE/ESM/DedicatedEpsBearerContextActivation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/DefaultEpsBearerContextActivation.c b/openair3/NAS/UE/ESM/DefaultEpsBearerContextActivation.c index a438d65ddb..7c528d7569 100644 --- a/openair3/NAS/UE/ESM/DefaultEpsBearerContextActivation.c +++ b/openair3/NAS/UE/ESM/DefaultEpsBearerContextActivation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/EpsBearerContextDeactivation.c b/openair3/NAS/UE/ESM/EpsBearerContextDeactivation.c index 6ba5e6e1cc..1a7328a81f 100644 --- a/openair3/NAS/UE/ESM/EpsBearerContextDeactivation.c +++ b/openair3/NAS/UE/ESM/EpsBearerContextDeactivation.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/EsmStatusHdl.c b/openair3/NAS/UE/ESM/EsmStatusHdl.c index 4c8e0aafc1..def498a89b 100644 --- a/openair3/NAS/UE/ESM/EsmStatusHdl.c +++ b/openair3/NAS/UE/ESM/EsmStatusHdl.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/PdnConnectivity.c b/openair3/NAS/UE/ESM/PdnConnectivity.c index f0a245e83e..2efed604f0 100644 --- a/openair3/NAS/UE/ESM/PdnConnectivity.c +++ b/openair3/NAS/UE/ESM/PdnConnectivity.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/PdnDisconnect.c b/openair3/NAS/UE/ESM/PdnDisconnect.c index 4b5c0f06e5..6665126e40 100644 --- a/openair3/NAS/UE/ESM/PdnDisconnect.c +++ b/openair3/NAS/UE/ESM/PdnDisconnect.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/SAP/esm_recv.c b/openair3/NAS/UE/ESM/SAP/esm_recv.c index 03a4215581..ca859f75f2 100644 --- a/openair3/NAS/UE/ESM/SAP/esm_recv.c +++ b/openair3/NAS/UE/ESM/SAP/esm_recv.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/SAP/esm_recv.h b/openair3/NAS/UE/ESM/SAP/esm_recv.h index ae36d650e3..29fcb47092 100644 --- a/openair3/NAS/UE/ESM/SAP/esm_recv.h +++ b/openair3/NAS/UE/ESM/SAP/esm_recv.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/SAP/esm_sap.c b/openair3/NAS/UE/ESM/SAP/esm_sap.c index 7ff1e57380..42deac629e 100644 --- a/openair3/NAS/UE/ESM/SAP/esm_sap.c +++ b/openair3/NAS/UE/ESM/SAP/esm_sap.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/SAP/esm_sap.h b/openair3/NAS/UE/ESM/SAP/esm_sap.h index b464e18900..28d6cda1db 100644 --- a/openair3/NAS/UE/ESM/SAP/esm_sap.h +++ b/openair3/NAS/UE/ESM/SAP/esm_sap.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/SAP/esm_sapDef.h b/openair3/NAS/UE/ESM/SAP/esm_sapDef.h index 4e1bed8bb5..4ff7c7e9dd 100644 --- a/openair3/NAS/UE/ESM/SAP/esm_sapDef.h +++ b/openair3/NAS/UE/ESM/SAP/esm_sapDef.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/SAP/esm_send.c b/openair3/NAS/UE/ESM/SAP/esm_send.c index eff200dc4e..020d9d89e3 100644 --- a/openair3/NAS/UE/ESM/SAP/esm_send.c +++ b/openair3/NAS/UE/ESM/SAP/esm_send.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/SAP/esm_send.h b/openair3/NAS/UE/ESM/SAP/esm_send.h index 1a5abc8695..f97454027a 100644 --- a/openair3/NAS/UE/ESM/SAP/esm_send.h +++ b/openair3/NAS/UE/ESM/SAP/esm_send.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/esmData.h b/openair3/NAS/UE/ESM/esmData.h index 7da659e801..16f4707a37 100644 --- a/openair3/NAS/UE/ESM/esmData.h +++ b/openair3/NAS/UE/ESM/esmData.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/esm_ebr.c b/openair3/NAS/UE/ESM/esm_ebr.c index 330da2fb23..a1d78bc62c 100644 --- a/openair3/NAS/UE/ESM/esm_ebr.c +++ b/openair3/NAS/UE/ESM/esm_ebr.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/esm_ebr.h b/openair3/NAS/UE/ESM/esm_ebr.h index 8e1eaee1a4..dece5c3645 100644 --- a/openair3/NAS/UE/ESM/esm_ebr.h +++ b/openair3/NAS/UE/ESM/esm_ebr.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/esm_ebr_context.c b/openair3/NAS/UE/ESM/esm_ebr_context.c index 4700187da1..e2a327f488 100644 --- a/openair3/NAS/UE/ESM/esm_ebr_context.c +++ b/openair3/NAS/UE/ESM/esm_ebr_context.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/esm_ebr_context.h b/openair3/NAS/UE/ESM/esm_ebr_context.h index a0016555a3..d7dfb1da70 100644 --- a/openair3/NAS/UE/ESM/esm_ebr_context.h +++ b/openair3/NAS/UE/ESM/esm_ebr_context.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/esm_ip.c b/openair3/NAS/UE/ESM/esm_ip.c index 0743307f6e..55be45d182 100644 --- a/openair3/NAS/UE/ESM/esm_ip.c +++ b/openair3/NAS/UE/ESM/esm_ip.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/esm_main.c b/openair3/NAS/UE/ESM/esm_main.c index 6c110abb52..288e748679 100644 --- a/openair3/NAS/UE/ESM/esm_main.c +++ b/openair3/NAS/UE/ESM/esm_main.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/esm_main.h b/openair3/NAS/UE/ESM/esm_main.h index 42381c8d5b..6e6ecc0db4 100644 --- a/openair3/NAS/UE/ESM/esm_main.h +++ b/openair3/NAS/UE/ESM/esm_main.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/esm_proc.h b/openair3/NAS/UE/ESM/esm_proc.h index 3d7260b83b..941cfa620d 100644 --- a/openair3/NAS/UE/ESM/esm_proc.h +++ b/openair3/NAS/UE/ESM/esm_proc.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/esm_pt.c b/openair3/NAS/UE/ESM/esm_pt.c index 9f8e948954..c372ad25f4 100644 --- a/openair3/NAS/UE/ESM/esm_pt.c +++ b/openair3/NAS/UE/ESM/esm_pt.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/ESM/esm_pt.h b/openair3/NAS/UE/ESM/esm_pt.h index 8b8693efda..3179e0f47b 100644 --- a/openair3/NAS/UE/ESM/esm_pt.h +++ b/openair3/NAS/UE/ESM/esm_pt.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/UEprocess.c b/openair3/NAS/UE/UEprocess.c index 35d1b86489..6a70911e21 100644 --- a/openair3/NAS/UE/UEprocess.c +++ b/openair3/NAS/UE/UEprocess.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/nas_itti_messaging.c b/openair3/NAS/UE/nas_itti_messaging.c index b6b2126dfb..0389106ec3 100644 --- a/openair3/NAS/UE/nas_itti_messaging.c +++ b/openair3/NAS/UE/nas_itti_messaging.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/nas_itti_messaging.h b/openair3/NAS/UE/nas_itti_messaging.h index f4f1f18414..d958317e5a 100644 --- a/openair3/NAS/UE/nas_itti_messaging.h +++ b/openair3/NAS/UE/nas_itti_messaging.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/nas_network.c b/openair3/NAS/UE/nas_network.c index 6ca4a34c7f..f7a292df3f 100644 --- a/openair3/NAS/UE/nas_network.c +++ b/openair3/NAS/UE/nas_network.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/nas_network.h b/openair3/NAS/UE/nas_network.h index fb05c8dd2a..1c13d67b63 100644 --- a/openair3/NAS/UE/nas_network.h +++ b/openair3/NAS/UE/nas_network.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/nas_parser.c b/openair3/NAS/UE/nas_parser.c index 148315eaa2..d62ebc3529 100644 --- a/openair3/NAS/UE/nas_parser.c +++ b/openair3/NAS/UE/nas_parser.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/nas_parser.h b/openair3/NAS/UE/nas_parser.h index b799f3a3f4..0924654e3f 100644 --- a/openair3/NAS/UE/nas_parser.h +++ b/openair3/NAS/UE/nas_parser.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/nas_proc.c b/openair3/NAS/UE/nas_proc.c index 97ecea8e5a..6312a7dc97 100644 --- a/openair3/NAS/UE/nas_proc.c +++ b/openair3/NAS/UE/nas_proc.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/nas_proc.h b/openair3/NAS/UE/nas_proc.h index bf8dec9e58..4e653549ae 100644 --- a/openair3/NAS/UE/nas_proc.h +++ b/openair3/NAS/UE/nas_proc.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/nas_ue_task.c b/openair3/NAS/UE/nas_ue_task.c index da9ae8879d..e41156d113 100644 --- a/openair3/NAS/UE/nas_ue_task.c +++ b/openair3/NAS/UE/nas_ue_task.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/nas_ue_task.h b/openair3/NAS/UE/nas_ue_task.h index 90ef26bd80..c9890719cb 100644 --- a/openair3/NAS/UE/nas_ue_task.h +++ b/openair3/NAS/UE/nas_ue_task.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/nas_user.c b/openair3/NAS/UE/nas_user.c index b698e4d682..d3467eddd5 100644 --- a/openair3/NAS/UE/nas_user.c +++ b/openair3/NAS/UE/nas_user.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/nas_user.h b/openair3/NAS/UE/nas_user.h index eb7f94a671..1ded438ddd 100644 --- a/openair3/NAS/UE/nas_user.h +++ b/openair3/NAS/UE/nas_user.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/NAS/UE/user_defs.h b/openair3/NAS/UE/user_defs.h index c27cf1320e..5143a939b0 100644 --- a/openair3/NAS/UE/user_defs.h +++ b/openair3/NAS/UE/user_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/MESSAGES/ASN1/asn1tostruct.py b/openair3/S1AP/MESSAGES/ASN1/asn1tostruct.py index 021e3f3cdb..4603e869a6 100644 --- a/openair3/S1AP/MESSAGES/ASN1/asn1tostruct.py +++ b/openair3/S1AP/MESSAGES/ASN1/asn1tostruct.py @@ -38,7 +38,7 @@ def outputHeaderToFile(f, filename): * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_common.c b/openair3/S1AP/s1ap_common.c index 2e4c31533d..0bd132a228 100644 --- a/openair3/S1AP/s1ap_common.c +++ b/openair3/S1AP/s1ap_common.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_common.h b/openair3/S1AP/s1ap_common.h index 8e5e5c0333..003bdd2d62 100644 --- a/openair3/S1AP/s1ap_common.h +++ b/openair3/S1AP/s1ap_common.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB.c b/openair3/S1AP/s1ap_eNB.c index 65b82055a3..08a18b629e 100644 --- a/openair3/S1AP/s1ap_eNB.c +++ b/openair3/S1AP/s1ap_eNB.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB.h b/openair3/S1AP/s1ap_eNB.h index eca28a4101..85bf00a4fa 100644 --- a/openair3/S1AP/s1ap_eNB.h +++ b/openair3/S1AP/s1ap_eNB.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_context_management_procedures.c b/openair3/S1AP/s1ap_eNB_context_management_procedures.c index 19aa8516b7..49c5ed28ac 100644 --- a/openair3/S1AP/s1ap_eNB_context_management_procedures.c +++ b/openair3/S1AP/s1ap_eNB_context_management_procedures.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_context_management_procedures.h b/openair3/S1AP/s1ap_eNB_context_management_procedures.h index 3e045a71ed..c8f7532023 100644 --- a/openair3/S1AP/s1ap_eNB_context_management_procedures.h +++ b/openair3/S1AP/s1ap_eNB_context_management_procedures.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_decoder.c b/openair3/S1AP/s1ap_eNB_decoder.c index c2cc3655d4..cd7b68bdc3 100644 --- a/openair3/S1AP/s1ap_eNB_decoder.c +++ b/openair3/S1AP/s1ap_eNB_decoder.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_decoder.h b/openair3/S1AP/s1ap_eNB_decoder.h index 1585dc2630..f321f8227f 100644 --- a/openair3/S1AP/s1ap_eNB_decoder.h +++ b/openair3/S1AP/s1ap_eNB_decoder.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_default_values.h b/openair3/S1AP/s1ap_eNB_default_values.h index 827f3a8083..44521e8dbf 100644 --- a/openair3/S1AP/s1ap_eNB_default_values.h +++ b/openair3/S1AP/s1ap_eNB_default_values.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_defs.h b/openair3/S1AP/s1ap_eNB_defs.h index 27a0209cc5..11e64703ec 100644 --- a/openair3/S1AP/s1ap_eNB_defs.h +++ b/openair3/S1AP/s1ap_eNB_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_encoder.c b/openair3/S1AP/s1ap_eNB_encoder.c index 17a5be7dc6..4ab2f1f317 100644 --- a/openair3/S1AP/s1ap_eNB_encoder.c +++ b/openair3/S1AP/s1ap_eNB_encoder.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_encoder.h b/openair3/S1AP/s1ap_eNB_encoder.h index 6231958101..5b135a3f76 100644 --- a/openair3/S1AP/s1ap_eNB_encoder.h +++ b/openair3/S1AP/s1ap_eNB_encoder.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_handlers.c b/openair3/S1AP/s1ap_eNB_handlers.c index 3896cf37ae..186f034644 100644 --- a/openair3/S1AP/s1ap_eNB_handlers.c +++ b/openair3/S1AP/s1ap_eNB_handlers.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_handlers.h b/openair3/S1AP/s1ap_eNB_handlers.h index ef36b908cc..d0e93faa4d 100644 --- a/openair3/S1AP/s1ap_eNB_handlers.h +++ b/openair3/S1AP/s1ap_eNB_handlers.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_itti_messaging.c b/openair3/S1AP/s1ap_eNB_itti_messaging.c index 352cb48d61..a0cdfd2dbc 100644 --- a/openair3/S1AP/s1ap_eNB_itti_messaging.c +++ b/openair3/S1AP/s1ap_eNB_itti_messaging.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_itti_messaging.h b/openair3/S1AP/s1ap_eNB_itti_messaging.h index d8572eef89..cd6b3cebcc 100644 --- a/openair3/S1AP/s1ap_eNB_itti_messaging.h +++ b/openair3/S1AP/s1ap_eNB_itti_messaging.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_management_procedures.c b/openair3/S1AP/s1ap_eNB_management_procedures.c index d5f321770d..fc7ae70e49 100644 --- a/openair3/S1AP/s1ap_eNB_management_procedures.c +++ b/openair3/S1AP/s1ap_eNB_management_procedures.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_management_procedures.h b/openair3/S1AP/s1ap_eNB_management_procedures.h index 73d8698c16..83df7f8919 100644 --- a/openair3/S1AP/s1ap_eNB_management_procedures.h +++ b/openair3/S1AP/s1ap_eNB_management_procedures.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_nas_procedures.c b/openair3/S1AP/s1ap_eNB_nas_procedures.c index 426f38004a..ea0dbcb70a 100644 --- a/openair3/S1AP/s1ap_eNB_nas_procedures.c +++ b/openair3/S1AP/s1ap_eNB_nas_procedures.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_nas_procedures.h b/openair3/S1AP/s1ap_eNB_nas_procedures.h index 6ac4b06111..2693872576 100644 --- a/openair3/S1AP/s1ap_eNB_nas_procedures.h +++ b/openair3/S1AP/s1ap_eNB_nas_procedures.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_nnsf.c b/openair3/S1AP/s1ap_eNB_nnsf.c index 3d4c96648d..8b7d65cb01 100644 --- a/openair3/S1AP/s1ap_eNB_nnsf.c +++ b/openair3/S1AP/s1ap_eNB_nnsf.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_nnsf.h b/openair3/S1AP/s1ap_eNB_nnsf.h index 38d93febd8..78405f34d1 100644 --- a/openair3/S1AP/s1ap_eNB_nnsf.h +++ b/openair3/S1AP/s1ap_eNB_nnsf.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_overload.c b/openair3/S1AP/s1ap_eNB_overload.c index a56242d363..82167bfeeb 100644 --- a/openair3/S1AP/s1ap_eNB_overload.c +++ b/openair3/S1AP/s1ap_eNB_overload.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_overload.h b/openair3/S1AP/s1ap_eNB_overload.h index e15b241b9d..1b0ee443de 100644 --- a/openair3/S1AP/s1ap_eNB_overload.h +++ b/openair3/S1AP/s1ap_eNB_overload.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_trace.c b/openair3/S1AP/s1ap_eNB_trace.c index 55ec5750f1..e640c9292a 100644 --- a/openair3/S1AP/s1ap_eNB_trace.c +++ b/openair3/S1AP/s1ap_eNB_trace.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_trace.h b/openair3/S1AP/s1ap_eNB_trace.h index fc321ce594..922197afb4 100644 --- a/openair3/S1AP/s1ap_eNB_trace.h +++ b/openair3/S1AP/s1ap_eNB_trace.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_ue_context.c b/openair3/S1AP/s1ap_eNB_ue_context.c index 8dc050ec8b..9cc8910ac5 100644 --- a/openair3/S1AP/s1ap_eNB_ue_context.c +++ b/openair3/S1AP/s1ap_eNB_ue_context.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/S1AP/s1ap_eNB_ue_context.h b/openair3/S1AP/s1ap_eNB_ue_context.h index 8c9ce6dea6..d78c6f7f1a 100644 --- a/openair3/S1AP/s1ap_eNB_ue_context.h +++ b/openair3/S1AP/s1ap_eNB_ue_context.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SCTP/sctp_common.c b/openair3/SCTP/sctp_common.c index f384d832ff..c467290b36 100644 --- a/openair3/SCTP/sctp_common.c +++ b/openair3/SCTP/sctp_common.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SCTP/sctp_common.h b/openair3/SCTP/sctp_common.h index dc0757d30f..f88c07730c 100644 --- a/openair3/SCTP/sctp_common.h +++ b/openair3/SCTP/sctp_common.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SCTP/sctp_default_values.h b/openair3/SCTP/sctp_default_values.h index d22d50605a..5008ea0b72 100644 --- a/openair3/SCTP/sctp_default_values.h +++ b/openair3/SCTP/sctp_default_values.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SCTP/sctp_eNB_defs.h b/openair3/SCTP/sctp_eNB_defs.h index 8e2347f80d..9d3b4119b5 100644 --- a/openair3/SCTP/sctp_eNB_defs.h +++ b/openair3/SCTP/sctp_eNB_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SCTP/sctp_eNB_itti_messaging.c b/openair3/SCTP/sctp_eNB_itti_messaging.c index 1725bb5fa7..3517c0597b 100644 --- a/openair3/SCTP/sctp_eNB_itti_messaging.c +++ b/openair3/SCTP/sctp_eNB_itti_messaging.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SCTP/sctp_eNB_itti_messaging.h b/openair3/SCTP/sctp_eNB_itti_messaging.h index 01c3b209e2..665c5f0e66 100644 --- a/openair3/SCTP/sctp_eNB_itti_messaging.h +++ b/openair3/SCTP/sctp_eNB_itti_messaging.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SCTP/sctp_eNB_task.c b/openair3/SCTP/sctp_eNB_task.c index 1f166af74c..7771cab712 100644 --- a/openair3/SCTP/sctp_eNB_task.c +++ b/openair3/SCTP/sctp_eNB_task.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SCTP/sctp_eNB_task.h b/openair3/SCTP/sctp_eNB_task.h index 333aa20f58..31cb683102 100644 --- a/openair3/SCTP/sctp_eNB_task.h +++ b/openair3/SCTP/sctp_eNB_task.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SCTP/sctp_primitives_client.c b/openair3/SCTP/sctp_primitives_client.c index 43ca200c5a..bb71a854e1 100644 --- a/openair3/SCTP/sctp_primitives_client.c +++ b/openair3/SCTP/sctp_primitives_client.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SCTP/sctp_primitives_client.h b/openair3/SCTP/sctp_primitives_client.h index a50a8f1de6..bec4d3ed95 100644 --- a/openair3/SCTP/sctp_primitives_client.h +++ b/openair3/SCTP/sctp_primitives_client.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SECU/kdf.c b/openair3/SECU/kdf.c index 98dfc55ae8..0717d17c59 100644 --- a/openair3/SECU/kdf.c +++ b/openair3/SECU/kdf.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SECU/key_nas_deriver.c b/openair3/SECU/key_nas_deriver.c index 6268c41d4b..59546be081 100644 --- a/openair3/SECU/key_nas_deriver.c +++ b/openair3/SECU/key_nas_deriver.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SECU/key_nas_encryption.c b/openair3/SECU/key_nas_encryption.c index 799aa020c1..aa641137ef 100644 --- a/openair3/SECU/key_nas_encryption.c +++ b/openair3/SECU/key_nas_encryption.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SECU/nas_stream_eea1.c b/openair3/SECU/nas_stream_eea1.c index 095838da37..efe924851f 100644 --- a/openair3/SECU/nas_stream_eea1.c +++ b/openair3/SECU/nas_stream_eea1.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SECU/nas_stream_eea2.c b/openair3/SECU/nas_stream_eea2.c index 37f2e298fb..0cd3d91761 100644 --- a/openair3/SECU/nas_stream_eea2.c +++ b/openair3/SECU/nas_stream_eea2.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SECU/nas_stream_eia1.c b/openair3/SECU/nas_stream_eia1.c index 6f4991d63d..629d40d612 100644 --- a/openair3/SECU/nas_stream_eia1.c +++ b/openair3/SECU/nas_stream_eia1.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SECU/nas_stream_eia2.c b/openair3/SECU/nas_stream_eia2.c index 0c31767022..a2ec6a6dd4 100644 --- a/openair3/SECU/nas_stream_eia2.c +++ b/openair3/SECU/nas_stream_eia2.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SECU/rijndael.c b/openair3/SECU/rijndael.c index facdced45a..c245af80f1 100644 --- a/openair3/SECU/rijndael.c +++ b/openair3/SECU/rijndael.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SECU/rijndael.h b/openair3/SECU/rijndael.h index c2146c85ff..f0c090cc3f 100644 --- a/openair3/SECU/rijndael.h +++ b/openair3/SECU/rijndael.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SECU/secu_defs.h b/openair3/SECU/secu_defs.h index 7f8aa20e17..4130098c99 100644 --- a/openair3/SECU/secu_defs.h +++ b/openair3/SECU/secu_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SECU/snow3g.c b/openair3/SECU/snow3g.c index 89304b4aab..faab013541 100644 --- a/openair3/SECU/snow3g.c +++ b/openair3/SECU/snow3g.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/SECU/snow3g.h b/openair3/SECU/snow3g.h index 26b70e2385..fcad5e9f8d 100644 --- a/openair3/SECU/snow3g.h +++ b/openair3/SECU/snow3g.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/EPC_TEST/generate_scenario.c b/openair3/TEST/EPC_TEST/generate_scenario.c index 097cf37563..b8d9d9c588 100644 --- a/openair3/TEST/EPC_TEST/generate_scenario.c +++ b/openair3/TEST/EPC_TEST/generate_scenario.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/EPC_TEST/generate_scenario.h b/openair3/TEST/EPC_TEST/generate_scenario.h index 96b2adc7a3..09fa5318ef 100644 --- a/openair3/TEST/EPC_TEST/generate_scenario.h +++ b/openair3/TEST/EPC_TEST/generate_scenario.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/EPC_TEST/play_scenario.c b/openair3/TEST/EPC_TEST/play_scenario.c index 05c99d96ee..edb4323d5f 100644 --- a/openair3/TEST/EPC_TEST/play_scenario.c +++ b/openair3/TEST/EPC_TEST/play_scenario.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/EPC_TEST/play_scenario.h b/openair3/TEST/EPC_TEST/play_scenario.h index a3a900cf7e..f9601fe904 100644 --- a/openair3/TEST/EPC_TEST/play_scenario.h +++ b/openair3/TEST/EPC_TEST/play_scenario.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/EPC_TEST/play_scenario_decode.c b/openair3/TEST/EPC_TEST/play_scenario_decode.c index ec5408e769..be63a171c5 100644 --- a/openair3/TEST/EPC_TEST/play_scenario_decode.c +++ b/openair3/TEST/EPC_TEST/play_scenario_decode.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/EPC_TEST/play_scenario_display.c b/openair3/TEST/EPC_TEST/play_scenario_display.c index 294f277e7d..e10cbdf9bf 100644 --- a/openair3/TEST/EPC_TEST/play_scenario_display.c +++ b/openair3/TEST/EPC_TEST/play_scenario_display.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/EPC_TEST/play_scenario_fsm.c b/openair3/TEST/EPC_TEST/play_scenario_fsm.c index ba8edc185f..1589b83cae 100644 --- a/openair3/TEST/EPC_TEST/play_scenario_fsm.c +++ b/openair3/TEST/EPC_TEST/play_scenario_fsm.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/EPC_TEST/play_scenario_parse.c b/openair3/TEST/EPC_TEST/play_scenario_parse.c index 8fb05cc912..040db30398 100644 --- a/openair3/TEST/EPC_TEST/play_scenario_parse.c +++ b/openair3/TEST/EPC_TEST/play_scenario_parse.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/EPC_TEST/play_scenario_s1ap.c b/openair3/TEST/EPC_TEST/play_scenario_s1ap.c index f1bbe393be..f10126d5b5 100644 --- a/openair3/TEST/EPC_TEST/play_scenario_s1ap.c +++ b/openair3/TEST/EPC_TEST/play_scenario_s1ap.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/EPC_TEST/play_scenario_s1ap_compare_ie.c b/openair3/TEST/EPC_TEST/play_scenario_s1ap_compare_ie.c index f99f0b0776..08f79ef206 100644 --- a/openair3/TEST/EPC_TEST/play_scenario_s1ap_compare_ie.c +++ b/openair3/TEST/EPC_TEST/play_scenario_s1ap_compare_ie.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/EPC_TEST/play_scenario_s1ap_eNB_defs.h b/openair3/TEST/EPC_TEST/play_scenario_s1ap_eNB_defs.h index d7c1899c51..532e14bb1d 100644 --- a/openair3/TEST/EPC_TEST/play_scenario_s1ap_eNB_defs.h +++ b/openair3/TEST/EPC_TEST/play_scenario_s1ap_eNB_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/EPC_TEST/play_scenario_sctp.c b/openair3/TEST/EPC_TEST/play_scenario_sctp.c index 5bc4f918be..8a9bc491c8 100644 --- a/openair3/TEST/EPC_TEST/play_scenario_sctp.c +++ b/openair3/TEST/EPC_TEST/play_scenario_sctp.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/Makefile.am b/openair3/TEST/Makefile.am index 55f7607585..211c7e62f2 100644 --- a/openair3/TEST/Makefile.am +++ b/openair3/TEST/Makefile.am @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/openair3/TEST/oaisim_mme_client_test.c b/openair3/TEST/oaisim_mme_client_test.c index 75d163de21..0e89511865 100644 --- a/openair3/TEST/oaisim_mme_client_test.c +++ b/openair3/TEST/oaisim_mme_client_test.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/oaisim_mme_itti_test.c b/openair3/TEST/oaisim_mme_itti_test.c index e8de70f8e6..243023e610 100644 --- a/openair3/TEST/oaisim_mme_itti_test.c +++ b/openair3/TEST/oaisim_mme_itti_test.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/oaisim_mme_list_benchmark.c b/openair3/TEST/oaisim_mme_list_benchmark.c index 0d5b8305b4..bfd9274b8a 100644 --- a/openair3/TEST/oaisim_mme_list_benchmark.c +++ b/openair3/TEST/oaisim_mme_list_benchmark.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/oaisim_mme_s1ap_test.c b/openair3/TEST/oaisim_mme_s1ap_test.c index 9680291918..1f7c1d3bbf 100644 --- a/openair3/TEST/oaisim_mme_s1ap_test.c +++ b/openair3/TEST/oaisim_mme_s1ap_test.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/oaisim_mme_sctp_test.c b/openair3/TEST/oaisim_mme_sctp_test.c index 7fb56940c4..d810f9ee8f 100644 --- a/openair3/TEST/oaisim_mme_sctp_test.c +++ b/openair3/TEST/oaisim_mme_sctp_test.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/oaisim_mme_test_s1c.c b/openair3/TEST/oaisim_mme_test_s1c.c index 93275ea9fe..1f130af0d3 100644 --- a/openair3/TEST/oaisim_mme_test_s1c.c +++ b/openair3/TEST/oaisim_mme_test_s1c.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/oaisim_mme_test_s1c.h b/openair3/TEST/oaisim_mme_test_s1c.h index 7075f75515..91e4472caf 100644 --- a/openair3/TEST/oaisim_mme_test_s1c.h +++ b/openair3/TEST/oaisim_mme_test_s1c.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/oaisim_mme_test_s1c_s1ap.c b/openair3/TEST/oaisim_mme_test_s1c_s1ap.c index 16a22d3cb1..993fad2f89 100644 --- a/openair3/TEST/oaisim_mme_test_s1c_s1ap.c +++ b/openair3/TEST/oaisim_mme_test_s1c_s1ap.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/oaisim_mme_test_s1c_s1ap.h b/openair3/TEST/oaisim_mme_test_s1c_s1ap.h index 72d808be9c..3633f11e86 100644 --- a/openair3/TEST/oaisim_mme_test_s1c_s1ap.h +++ b/openair3/TEST/oaisim_mme_test_s1c_s1ap.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/oaisim_mme_test_s1c_scenario.c b/openair3/TEST/oaisim_mme_test_s1c_scenario.c index 25698edd1f..60d74866c8 100644 --- a/openair3/TEST/oaisim_mme_test_s1c_scenario.c +++ b/openair3/TEST/oaisim_mme_test_s1c_scenario.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/oaisim_mme_test_s1c_scenario.h b/openair3/TEST/oaisim_mme_test_s1c_scenario.h index 82950a9355..8c33f45741 100644 --- a/openair3/TEST/oaisim_mme_test_s1c_scenario.h +++ b/openair3/TEST/oaisim_mme_test_s1c_scenario.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/oaisim_mme_test_s1c_scenario1.c b/openair3/TEST/oaisim_mme_test_s1c_scenario1.c index 4589b26191..87a63b876a 100644 --- a/openair3/TEST/oaisim_mme_test_s1c_scenario1.c +++ b/openair3/TEST/oaisim_mme_test_s1c_scenario1.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/test_aes128_cmac_encrypt.c b/openair3/TEST/test_aes128_cmac_encrypt.c index 085e000647..666271d4e0 100644 --- a/openair3/TEST/test_aes128_cmac_encrypt.c +++ b/openair3/TEST/test_aes128_cmac_encrypt.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/test_aes128_ctr_decrypt.c b/openair3/TEST/test_aes128_ctr_decrypt.c index a30dc6c2f2..928853c9ba 100644 --- a/openair3/TEST/test_aes128_ctr_decrypt.c +++ b/openair3/TEST/test_aes128_ctr_decrypt.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/test_aes128_ctr_encrypt.c b/openair3/TEST/test_aes128_ctr_encrypt.c index 6c264a98a6..071aa603a9 100644 --- a/openair3/TEST/test_aes128_ctr_encrypt.c +++ b/openair3/TEST/test_aes128_ctr_encrypt.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/test_kdf.c b/openair3/TEST/test_kdf.c index 42d91f48a5..50a2ad347a 100644 --- a/openair3/TEST/test_kdf.c +++ b/openair3/TEST/test_kdf.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/test_s1ap.c b/openair3/TEST/test_s1ap.c index dec21ee1b6..a366796f77 100644 --- a/openair3/TEST/test_s1ap.c +++ b/openair3/TEST/test_s1ap.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/test_secu.c b/openair3/TEST/test_secu.c index 2b1b101ae0..244999e9be 100644 --- a/openair3/TEST/test_secu.c +++ b/openair3/TEST/test_secu.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/test_secu_kenb.c b/openair3/TEST/test_secu_kenb.c index edab024549..9323062a1d 100644 --- a/openair3/TEST/test_secu_kenb.c +++ b/openair3/TEST/test_secu_kenb.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/test_secu_knas.c b/openair3/TEST/test_secu_knas.c index bcfac758ec..bc48eaaad1 100644 --- a/openair3/TEST/test_secu_knas.c +++ b/openair3/TEST/test_secu_knas.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/test_secu_knas_encrypt_eea1.c b/openair3/TEST/test_secu_knas_encrypt_eea1.c index 3335decb6e..aa1b57a6ba 100644 --- a/openair3/TEST/test_secu_knas_encrypt_eea1.c +++ b/openair3/TEST/test_secu_knas_encrypt_eea1.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/test_secu_knas_encrypt_eea2.c b/openair3/TEST/test_secu_knas_encrypt_eea2.c index e300b3b0ea..78a2b6fecc 100644 --- a/openair3/TEST/test_secu_knas_encrypt_eea2.c +++ b/openair3/TEST/test_secu_knas_encrypt_eea2.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/test_secu_knas_encrypt_eia1.c b/openair3/TEST/test_secu_knas_encrypt_eia1.c index fbfbc35b71..b28d4f9888 100644 --- a/openair3/TEST/test_secu_knas_encrypt_eia1.c +++ b/openair3/TEST/test_secu_knas_encrypt_eia1.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/test_secu_knas_encrypt_eia2.c b/openair3/TEST/test_secu_knas_encrypt_eia2.c index 7e7517be77..9a9b7e102e 100644 --- a/openair3/TEST/test_secu_knas_encrypt_eia2.c +++ b/openair3/TEST/test_secu_knas_encrypt_eia2.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/TEST/test_secu_knas_stream_int.c b/openair3/TEST/test_secu_knas_stream_int.c index 6773397085..2fdf5fc791 100644 --- a/openair3/TEST/test_secu_knas_stream_int.c +++ b/openair3/TEST/test_secu_knas_stream_int.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/UDP/udp_eNB_task.c b/openair3/UDP/udp_eNB_task.c index b8b6b897a7..b5d8fbdc00 100644 --- a/openair3/UDP/udp_eNB_task.c +++ b/openair3/UDP/udp_eNB_task.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/UDP/udp_eNB_task.h b/openair3/UDP/udp_eNB_task.h index d8a22417c0..a10e0c81b2 100644 --- a/openair3/UDP/udp_eNB_task.h +++ b/openair3/UDP/udp_eNB_task.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/UTILS/conversions.c b/openair3/UTILS/conversions.c index 3b926de259..2def84abb0 100644 --- a/openair3/UTILS/conversions.c +++ b/openair3/UTILS/conversions.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/UTILS/conversions.h b/openair3/UTILS/conversions.h index da8461b390..00287341b2 100644 --- a/openair3/UTILS/conversions.h +++ b/openair3/UTILS/conversions.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/UTILS/enum_string.c b/openair3/UTILS/enum_string.c index c4af7f9e0d..c2eccc7a9e 100644 --- a/openair3/UTILS/enum_string.c +++ b/openair3/UTILS/enum_string.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/UTILS/enum_string.h b/openair3/UTILS/enum_string.h index a16c33b71b..7b53ab31e3 100644 --- a/openair3/UTILS/enum_string.h +++ b/openair3/UTILS/enum_string.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/UTILS/log.c b/openair3/UTILS/log.c index 9c7fe79ef8..5ddebd415c 100644 --- a/openair3/UTILS/log.c +++ b/openair3/UTILS/log.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/UTILS/log.h b/openair3/UTILS/log.h index 729c12687a..7b712df755 100644 --- a/openair3/UTILS/log.h +++ b/openair3/UTILS/log.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/UTILS/mcc_mnc_itu.c b/openair3/UTILS/mcc_mnc_itu.c index 69ac1d9024..6b999c36df 100644 --- a/openair3/UTILS/mcc_mnc_itu.c +++ b/openair3/UTILS/mcc_mnc_itu.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/UTILS/mcc_mnc_itu.h b/openair3/UTILS/mcc_mnc_itu.h index 22531aef48..a6b7343b99 100644 --- a/openair3/UTILS/mcc_mnc_itu.h +++ b/openair3/UTILS/mcc_mnc_itu.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/UTILS/mme_config.c b/openair3/UTILS/mme_config.c index 6b97cc674e..d2c25af10a 100644 --- a/openair3/UTILS/mme_config.c +++ b/openair3/UTILS/mme_config.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/UTILS/mme_config.h b/openair3/UTILS/mme_config.h index 448de95920..37b7dff865 100644 --- a/openair3/UTILS/mme_config.h +++ b/openair3/UTILS/mme_config.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair3/UTILS/mme_default_values.h b/openair3/UTILS/mme_default_values.h index 5c9ad7d3ec..6965c7c57c 100644 --- a/openair3/UTILS/mme_default_values.h +++ b/openair3/UTILS/mme_default_values.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c b/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c index ccc559231c..5ded228f6b 100644 --- a/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c +++ b/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.h b/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.h index 11a4a98e57..31a7173630 100644 --- a/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.h +++ b/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c index 19036de204..dc074e1032 100644 --- a/targets/ARCH/COMMON/common_lib.c +++ b/targets/ARCH/COMMON/common_lib.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h index 129705c229..b64a57c5b6 100644 --- a/targets/ARCH/COMMON/common_lib.h +++ b/targets/ARCH/COMMON/common_lib.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c index 4cf04064b1..11a81fcddf 100644 --- a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c +++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c index 9f6c01afed..ef9b019ba6 100644 --- a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c +++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c index f22206eec8..ff8c02cb11 100644 --- a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c +++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h index 50a5738007..5e6db7c366 100644 --- a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h +++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h b/targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h index 6c51db64ce..b42f8405d5 100644 --- a/targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h +++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DEFS/openair_device.h b/targets/ARCH/EXMIMO/DEFS/openair_device.h index b22cf1879b..f2f20d38ff 100644 --- a/targets/ARCH/EXMIMO/DEFS/openair_device.h +++ b/targets/ARCH/EXMIMO/DEFS/openair_device.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DEFS/pcie_interface.h b/targets/ARCH/EXMIMO/DEFS/pcie_interface.h index 0485c154f9..cfc3934668 100644 --- a/targets/ARCH/EXMIMO/DEFS/pcie_interface.h +++ b/targets/ARCH/EXMIMO/DEFS/pcie_interface.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/eurecom/defs.h b/targets/ARCH/EXMIMO/DRIVER/eurecom/defs.h index 1665a76b08..c4adf28b82 100644 --- a/targets/ARCH/EXMIMO/DRIVER/eurecom/defs.h +++ b/targets/ARCH/EXMIMO/DRIVER/eurecom/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/eurecom/exmimo_fw.c b/targets/ARCH/EXMIMO/DRIVER/eurecom/exmimo_fw.c index 766bb6eb74..7cf5c95ecb 100644 --- a/targets/ARCH/EXMIMO/DRIVER/eurecom/exmimo_fw.c +++ b/targets/ARCH/EXMIMO/DRIVER/eurecom/exmimo_fw.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/eurecom/extern.h b/targets/ARCH/EXMIMO/DRIVER/eurecom/extern.h index 07e094b966..5fc557e400 100644 --- a/targets/ARCH/EXMIMO/DRIVER/eurecom/extern.h +++ b/targets/ARCH/EXMIMO/DRIVER/eurecom/extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/eurecom/fileops.c b/targets/ARCH/EXMIMO/DRIVER/eurecom/fileops.c index 5002cccc98..b5ef864b30 100644 --- a/targets/ARCH/EXMIMO/DRIVER/eurecom/fileops.c +++ b/targets/ARCH/EXMIMO/DRIVER/eurecom/fileops.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/eurecom/irq.c b/targets/ARCH/EXMIMO/DRIVER/eurecom/irq.c index 513adfaf96..cd21d94cb1 100644 --- a/targets/ARCH/EXMIMO/DRIVER/eurecom/irq.c +++ b/targets/ARCH/EXMIMO/DRIVER/eurecom/irq.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/eurecom/module_main.c b/targets/ARCH/EXMIMO/DRIVER/eurecom/module_main.c index 706246b96e..18dc9d846e 100644 --- a/targets/ARCH/EXMIMO/DRIVER/eurecom/module_main.c +++ b/targets/ARCH/EXMIMO/DRIVER/eurecom/module_main.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/eurecom/vars.h b/targets/ARCH/EXMIMO/DRIVER/eurecom/vars.h index 3cbaacfdca..7c21bc25fc 100644 --- a/targets/ARCH/EXMIMO/DRIVER/eurecom/vars.h +++ b/targets/ARCH/EXMIMO/DRIVER/eurecom/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/exmimo3/defs.h b/targets/ARCH/EXMIMO/DRIVER/exmimo3/defs.h index 1665a76b08..c4adf28b82 100644 --- a/targets/ARCH/EXMIMO/DRIVER/exmimo3/defs.h +++ b/targets/ARCH/EXMIMO/DRIVER/exmimo3/defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/exmimo3/exmimo_fw.c b/targets/ARCH/EXMIMO/DRIVER/exmimo3/exmimo_fw.c index 6ce753cba6..c6ffcb859b 100644 --- a/targets/ARCH/EXMIMO/DRIVER/exmimo3/exmimo_fw.c +++ b/targets/ARCH/EXMIMO/DRIVER/exmimo3/exmimo_fw.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/exmimo3/extern.h b/targets/ARCH/EXMIMO/DRIVER/exmimo3/extern.h index 07e094b966..5fc557e400 100644 --- a/targets/ARCH/EXMIMO/DRIVER/exmimo3/extern.h +++ b/targets/ARCH/EXMIMO/DRIVER/exmimo3/extern.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/exmimo3/fileops.c b/targets/ARCH/EXMIMO/DRIVER/exmimo3/fileops.c index 7e36b138e9..84bb838097 100644 --- a/targets/ARCH/EXMIMO/DRIVER/exmimo3/fileops.c +++ b/targets/ARCH/EXMIMO/DRIVER/exmimo3/fileops.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/exmimo3/irq.c b/targets/ARCH/EXMIMO/DRIVER/exmimo3/irq.c index 513adfaf96..cd21d94cb1 100644 --- a/targets/ARCH/EXMIMO/DRIVER/exmimo3/irq.c +++ b/targets/ARCH/EXMIMO/DRIVER/exmimo3/irq.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/exmimo3/module_main.c b/targets/ARCH/EXMIMO/DRIVER/exmimo3/module_main.c index afea3f707c..3bc6f73766 100644 --- a/targets/ARCH/EXMIMO/DRIVER/exmimo3/module_main.c +++ b/targets/ARCH/EXMIMO/DRIVER/exmimo3/module_main.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/exmimo3/vars.h b/targets/ARCH/EXMIMO/DRIVER/exmimo3/vars.h index 3cbaacfdca..7c21bc25fc 100644 --- a/targets/ARCH/EXMIMO/DRIVER/exmimo3/vars.h +++ b/targets/ARCH/EXMIMO/DRIVER/exmimo3/vars.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_dev.c b/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_dev.c index 93fe053ed1..e41b9bf6e9 100644 --- a/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_dev.c +++ b/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_dev.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_drv.c b/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_drv.c index 0187959fab..1abd44b019 100644 --- a/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_drv.c +++ b/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_drv.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_drv.h b/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_drv.h index 6cf700400a..82cb69baba 100644 --- a/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_drv.h +++ b/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_drv.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_fifos.c b/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_fifos.c index 69103db99b..6d5fa38ce4 100644 --- a/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_fifos.c +++ b/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_fifos.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_ioctl.c b/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_ioctl.c index 3f50766fcc..a2d4dccfb2 100644 --- a/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_ioctl.c +++ b/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_ioctl.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_mmap.c b/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_mmap.c index 065d8c9595..48b17bbf2f 100644 --- a/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_mmap.c +++ b/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_mmap.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_rw.c b/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_rw.c index d46ff92a70..bf1be1a68f 100644 --- a/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_rw.c +++ b/targets/ARCH/EXMIMO/DRIVER/telecomparistech/em1_rw.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/LIB/example.c b/targets/ARCH/EXMIMO/USERSPACE/LIB/example.c index 1e081ae2bb..46ad06f67e 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/LIB/example.c +++ b/targets/ARCH/EXMIMO/USERSPACE/LIB/example.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/LIB/gain_control.c b/targets/ARCH/EXMIMO/USERSPACE/LIB/gain_control.c index 0b2c6afaa5..449ac0a8e0 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/LIB/gain_control.c +++ b/targets/ARCH/EXMIMO/USERSPACE/LIB/gain_control.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/LIB/gain_control.h b/targets/ARCH/EXMIMO/USERSPACE/LIB/gain_control.h index 9524c912d7..78f6173f3b 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/LIB/gain_control.h +++ b/targets/ARCH/EXMIMO/USERSPACE/LIB/gain_control.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c b/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c index 8e07f7ac9e..7d23cdeb89 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c +++ b/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.h b/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.h index 7c0e63290b..9211e67ec5 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.h +++ b/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT/updatefw.c b/targets/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT/updatefw.c index 04c0ffebbc..1b2445fa72 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT/updatefw.c +++ b/targets/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT/updatefw.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT/updatefw.h b/targets/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT/updatefw.h index 1bcd2f99be..a167263969 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT/updatefw.h +++ b/targets/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT/updatefw.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/gpib_send.cc b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/gpib_send.cc index 64e795acc1..21bab68d95 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/gpib_send.cc +++ b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/gpib_send.cc @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf.h b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf.h index 204fca6afd..7b95444163 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf.h +++ b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_config_exmimo.cc b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_config_exmimo.cc index 73a655075c..ccfe306ef6 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_config_exmimo.cc +++ b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_config_exmimo.cc @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc index b8ed0e92e5..79facd431f 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc +++ b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_num_detected_cards.cc b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_num_detected_cards.cc index 1a92096249..2fa90ab6f2 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_num_detected_cards.cc +++ b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_num_detected_cards.cc @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_send_frame.cc b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_send_frame.cc index 5a425c9253..1ebe3aeb4e 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_send_frame.cc +++ b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_send_frame.cc @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_stop.cc b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_stop.cc index 608b5d1b9b..b2d73c8329 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_stop.cc +++ b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_stop.cc @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_stop_without_reset.cc b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_stop_without_reset.cc index 02ee33c840..05188405e6 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_stop_without_reset.cc +++ b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_stop_without_reset.cc @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp index 2dec4ff22d..13f2483a13 100644 --- a/targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp +++ b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/LMSSDR/USERSPACE/LIB/sodera_lib.cpp b/targets/ARCH/LMSSDR/USERSPACE/LIB/sodera_lib.cpp index f8401dc391..6f1afe47c0 100644 --- a/targets/ARCH/LMSSDR/USERSPACE/LIB/sodera_lib.cpp +++ b/targets/ARCH/LMSSDR/USERSPACE/LIB/sodera_lib.cpp @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index a4400ee056..711b2c6bc1 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/mobipass/interface.c b/targets/ARCH/mobipass/interface.c index 780dd4fbc3..db186a404c 100644 --- a/targets/ARCH/mobipass/interface.c +++ b/targets/ARCH/mobipass/interface.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/mobipass/mobipass.c b/targets/ARCH/mobipass/mobipass.c index b0a9d34522..2a91068788 100644 --- a/targets/ARCH/mobipass/mobipass.c +++ b/targets/ARCH/mobipass/mobipass.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/mobipass/mobipass.h b/targets/ARCH/mobipass/mobipass.h index aeaa94838b..2210824c13 100644 --- a/targets/ARCH/mobipass/mobipass.h +++ b/targets/ARCH/mobipass/mobipass.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/mobipass/queues.c b/targets/ARCH/mobipass/queues.c index d38969616f..27c9917084 100644 --- a/targets/ARCH/mobipass/queues.c +++ b/targets/ARCH/mobipass/queues.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/ARCH/mobipass/queues.h b/targets/ARCH/mobipass/queues.h index 714cf506e5..e47a622730 100644 --- a/targets/ARCH/mobipass/queues.h +++ b/targets/ARCH/mobipass/queues.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/COMMON/create_tasks.c b/targets/COMMON/create_tasks.c index c28b9e839c..181fdbb631 100644 --- a/targets/COMMON/create_tasks.c +++ b/targets/COMMON/create_tasks.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/COMMON/create_tasks.h b/targets/COMMON/create_tasks.h index 6545f4b9d9..493c441f59 100644 --- a/targets/COMMON/create_tasks.h +++ b/targets/COMMON/create_tasks.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/PROJECTS/E-MBMS/build_all.bash b/targets/PROJECTS/E-MBMS/build_all.bash index a4f00d49af..0cbece916e 100755 --- a/targets/PROJECTS/E-MBMS/build_all.bash +++ b/targets/PROJECTS/E-MBMS/build_all.bash @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/PROJECTS/E-MBMS/start_enb.bash b/targets/PROJECTS/E-MBMS/start_enb.bash index 5e8d8e4b45..8e62c8e09c 100755 --- a/targets/PROJECTS/E-MBMS/start_enb.bash +++ b/targets/PROJECTS/E-MBMS/start_enb.bash @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/PROJECTS/E-MBMS/start_ue.bash b/targets/PROJECTS/E-MBMS/start_ue.bash index 25e2816fcc..7e856a8ef4 100755 --- a/targets/PROJECTS/E-MBMS/start_ue.bash +++ b/targets/PROJECTS/E-MBMS/start_ue.bash @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/PROJECTS/E-MBMS/utils.bash b/targets/PROJECTS/E-MBMS/utils.bash index 0da6363a19..a2fe556c29 100755 --- a/targets/PROJECTS/E-MBMS/utils.bash +++ b/targets/PROJECTS/E-MBMS/utils.bash @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/interfaces.bash b/targets/PROJECTS/GENERIC-LTE-EPC/interfaces.bash index 4c753dc372..bfcae67e4a 100755 --- a/targets/PROJECTS/GENERIC-LTE-EPC/interfaces.bash +++ b/targets/PROJECTS/GENERIC-LTE-EPC/interfaces.bash @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/networks.bash b/targets/PROJECTS/GENERIC-LTE-EPC/networks.bash index 8e1538599f..6db4c9f580 100755 --- a/targets/PROJECTS/GENERIC-LTE-EPC/networks.bash +++ b/targets/PROJECTS/GENERIC-LTE-EPC/networks.bash @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/start_enb_and_ue_virt.bash b/targets/PROJECTS/GENERIC-LTE-EPC/start_enb_and_ue_virt.bash index 6ea2d5bb0a..1c6d87bc8f 100755 --- a/targets/PROJECTS/GENERIC-LTE-EPC/start_enb_and_ue_virt.bash +++ b/targets/PROJECTS/GENERIC-LTE-EPC/start_enb_and_ue_virt.bash @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/start_ue.bash b/targets/PROJECTS/GENERIC-LTE-EPC/start_ue.bash index ff16e27982..8b76dc9cc0 100755 --- a/targets/PROJECTS/GENERIC-LTE-EPC/start_ue.bash +++ b/targets/PROJECTS/GENERIC-LTE-EPC/start_ue.bash @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/utils.bash b/targets/PROJECTS/GENERIC-LTE-EPC/utils.bash index 23231f2fe6..93441ec9e9 100755 --- a/targets/PROJECTS/GENERIC-LTE-EPC/utils.bash +++ b/targets/PROJECTS/GENERIC-LTE-EPC/utils.bash @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/virtual_box.bash b/targets/PROJECTS/GENERIC-LTE-EPC/virtual_box.bash index 7813f4edea..72fcea2281 100755 --- a/targets/PROJECTS/GENERIC-LTE-EPC/virtual_box.bash +++ b/targets/PROJECTS/GENERIC-LTE-EPC/virtual_box.bash @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/RT/USER/TOOLS/thread_ipc.c b/targets/RT/USER/TOOLS/thread_ipc.c index 5e9adb0bcc..7eda3e8431 100644 --- a/targets/RT/USER/TOOLS/thread_ipc.c +++ b/targets/RT/USER/TOOLS/thread_ipc.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/TOOLS/thread_ipc.h b/targets/RT/USER/TOOLS/thread_ipc.h index a39f8d22fb..ec008c30df 100644 --- a/targets/RT/USER/TOOLS/thread_ipc.h +++ b/targets/RT/USER/TOOLS/thread_ipc.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/UE_transport_IQ.c b/targets/RT/USER/UE_transport_IQ.c index 05dd2bbf79..16f491263d 100644 --- a/targets/RT/USER/UE_transport_IQ.c +++ b/targets/RT/USER/UE_transport_IQ.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/condtest.c b/targets/RT/USER/condtest.c index 23b5d23a5b..b6f00e80b3 100644 --- a/targets/RT/USER/condtest.c +++ b/targets/RT/USER/condtest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/eNB_transport_IQ.c b/targets/RT/USER/eNB_transport_IQ.c index b57a201fb5..b822a5ea75 100644 --- a/targets/RT/USER/eNB_transport_IQ.c +++ b/targets/RT/USER/eNB_transport_IQ.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/emos-raw.c b/targets/RT/USER/emos-raw.c index 16709da7cf..2cf0e18c71 100644 --- a/targets/RT/USER/emos-raw.c +++ b/targets/RT/USER/emos-raw.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 30a203dd02..3fb068fe5c 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index d680a42464..92932189d8 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 3b84e8ea97..b01e13ed95 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/msg_helper.c b/targets/RT/USER/msg_helper.c index 32a0da6cd4..ac99e48ff7 100644 --- a/targets/RT/USER/msg_helper.c +++ b/targets/RT/USER/msg_helper.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/msg_many.c b/targets/RT/USER/msg_many.c index ec582558a4..17e03c6c5a 100644 --- a/targets/RT/USER/msg_many.c +++ b/targets/RT/USER/msg_many.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/msg_many.h b/targets/RT/USER/msg_many.h index ca5fd85b51..5b9d465e33 100644 --- a/targets/RT/USER/msg_many.h +++ b/targets/RT/USER/msg_many.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/rrh.c b/targets/RT/USER/rrh.c index f658e6b401..88bd3f644d 100644 --- a/targets/RT/USER/rrh.c +++ b/targets/RT/USER/rrh.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/rrh_gw.c b/targets/RT/USER/rrh_gw.c index e73c9ef4eb..7aea0484be 100644 --- a/targets/RT/USER/rrh_gw.c +++ b/targets/RT/USER/rrh_gw.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/rrh_gw.h b/targets/RT/USER/rrh_gw.h index 075cbf3c2b..97ffa5a893 100644 --- a/targets/RT/USER/rrh_gw.h +++ b/targets/RT/USER/rrh_gw.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/rrh_gw_externs.h b/targets/RT/USER/rrh_gw_externs.h index b85f0ae7a2..0786743399 100644 --- a/targets/RT/USER/rrh_gw_externs.h +++ b/targets/RT/USER/rrh_gw_externs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/rt_wrapper.c b/targets/RT/USER/rt_wrapper.c index 06a625d1ea..5c37b34ee6 100644 --- a/targets/RT/USER/rt_wrapper.c +++ b/targets/RT/USER/rt_wrapper.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/rt_wrapper.h b/targets/RT/USER/rt_wrapper.h index 28466524ac..63ea7e8148 100644 --- a/targets/RT/USER/rt_wrapper.h +++ b/targets/RT/USER/rt_wrapper.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/sleeptest.c b/targets/RT/USER/sleeptest.c index 593e62dfac..ba5cb0ce15 100644 --- a/targets/RT/USER/sleeptest.c +++ b/targets/RT/USER/sleeptest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/stats.c b/targets/RT/USER/stats.c index 4d9343f4bc..fa8ab38cb2 100644 --- a/targets/RT/USER/stats.c +++ b/targets/RT/USER/stats.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/stats.h b/targets/RT/USER/stats.h index 7be9380852..264c8f7af0 100644 --- a/targets/RT/USER/stats.h +++ b/targets/RT/USER/stats.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/RT/USER/synctest.c b/targets/RT/USER/synctest.c index 6122f67cd0..ff65231df1 100644 --- a/targets/RT/USER/synctest.c +++ b/targets/RT/USER/synctest.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SCRIPTS/install_asn1c_0.9.24.modified.bash b/targets/SCRIPTS/install_asn1c_0.9.24.modified.bash index bb45a82e13..9c4947d479 100755 --- a/targets/SCRIPTS/install_asn1c_0.9.24.modified.bash +++ b/targets/SCRIPTS/install_asn1c_0.9.24.modified.bash @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/SIMU/PROC/Process.c b/targets/SIMU/PROC/Process.c index 9d80c74d99..9b529fd593 100644 --- a/targets/SIMU/PROC/Process.c +++ b/targets/SIMU/PROC/Process.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/PROC/Process.h b/targets/SIMU/PROC/Process.h index 1ab2f3be15..71383f945f 100644 --- a/targets/SIMU/PROC/Process.h +++ b/targets/SIMU/PROC/Process.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/PROC/Tsync.h b/targets/SIMU/PROC/Tsync.h index a60501c13e..a6ffe11def 100644 --- a/targets/SIMU/PROC/Tsync.h +++ b/targets/SIMU/PROC/Tsync.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/PROC/channel_sim_proc.c b/targets/SIMU/PROC/channel_sim_proc.c index b54fe36460..dd0adec0d2 100644 --- a/targets/SIMU/PROC/channel_sim_proc.c +++ b/targets/SIMU/PROC/channel_sim_proc.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/PROC/channel_sim_proc.h b/targets/SIMU/PROC/channel_sim_proc.h index d95f3e7aab..1d5b53a189 100644 --- a/targets/SIMU/PROC/channel_sim_proc.h +++ b/targets/SIMU/PROC/channel_sim_proc.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/PROC/interface.h b/targets/SIMU/PROC/interface.h index 52b100f594..4c00d9d6f3 100644 --- a/targets/SIMU/PROC/interface.h +++ b/targets/SIMU/PROC/interface.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/channel_sim.c b/targets/SIMU/USER/channel_sim.c index 04d7e1d233..58601ee4ed 100644 --- a/targets/SIMU/USER/channel_sim.c +++ b/targets/SIMU/USER/channel_sim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/cor_SF_sim.c b/targets/SIMU/USER/cor_SF_sim.c index ea464a60dc..63f3be153e 100644 --- a/targets/SIMU/USER/cor_SF_sim.c +++ b/targets/SIMU/USER/cor_SF_sim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/cor_SF_sim.h b/targets/SIMU/USER/cor_SF_sim.h index 3e2933cc98..35b75564e8 100644 --- a/targets/SIMU/USER/cor_SF_sim.h +++ b/targets/SIMU/USER/cor_SF_sim.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/event_handler.c b/targets/SIMU/USER/event_handler.c index c140dab50b..942fef009a 100644 --- a/targets/SIMU/USER/event_handler.c +++ b/targets/SIMU/USER/event_handler.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/event_handler.h b/targets/SIMU/USER/event_handler.h index c315af4b89..d6579fd411 100644 --- a/targets/SIMU/USER/event_handler.h +++ b/targets/SIMU/USER/event_handler.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/init_lte.c b/targets/SIMU/USER/init_lte.c index a68567a6d2..8546b3bff2 100644 --- a/targets/SIMU/USER/init_lte.c +++ b/targets/SIMU/USER/init_lte.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/init_lte.h b/targets/SIMU/USER/init_lte.h index e49c24a15b..693891fe8b 100644 --- a/targets/SIMU/USER/init_lte.h +++ b/targets/SIMU/USER/init_lte.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index d8f9ae2738..cd45dbd23f 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/oaisim.h b/targets/SIMU/USER/oaisim.h index d68e34462e..d712211c70 100644 --- a/targets/SIMU/USER/oaisim.h +++ b/targets/SIMU/USER/oaisim.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/oaisim_config.c b/targets/SIMU/USER/oaisim_config.c index 70728875f5..8dfbdaaaa2 100644 --- a/targets/SIMU/USER/oaisim_config.c +++ b/targets/SIMU/USER/oaisim_config.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/oaisim_config.h b/targets/SIMU/USER/oaisim_config.h index 3d504a93eb..fe1309b7a4 100644 --- a/targets/SIMU/USER/oaisim_config.h +++ b/targets/SIMU/USER/oaisim_config.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index 2782620eab..0d1531e413 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/oaisim_functions.h b/targets/SIMU/USER/oaisim_functions.h index 14e449921d..8bbf90df36 100644 --- a/targets/SIMU/USER/oaisim_functions.h +++ b/targets/SIMU/USER/oaisim_functions.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/oaisim_pad.c b/targets/SIMU/USER/oaisim_pad.c index 58589ef8f7..1f251de581 100644 --- a/targets/SIMU/USER/oaisim_pad.c +++ b/targets/SIMU/USER/oaisim_pad.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/phy_procedures_sim_form.c b/targets/SIMU/USER/phy_procedures_sim_form.c index f6a4451a1c..bfc769413a 100644 --- a/targets/SIMU/USER/phy_procedures_sim_form.c +++ b/targets/SIMU/USER/phy_procedures_sim_form.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/phy_procedures_sim_form.h b/targets/SIMU/USER/phy_procedures_sim_form.h index 80e78ce2b1..df8f846f96 100644 --- a/targets/SIMU/USER/phy_procedures_sim_form.h +++ b/targets/SIMU/USER/phy_procedures_sim_form.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/SIMU/USER/sinr_sim.c b/targets/SIMU/USER/sinr_sim.c index fbd15abaae..0cd2a6cfbd 100644 --- a/targets/SIMU/USER/sinr_sim.c +++ b/targets/SIMU/USER/sinr_sim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/TEST/AT_COMMANDS/oaisim.c b/targets/TEST/AT_COMMANDS/oaisim.c index 2f478929cc..4420d583e3 100644 --- a/targets/TEST/AT_COMMANDS/oaisim.c +++ b/targets/TEST/AT_COMMANDS/oaisim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/TEST/OAI/case01.py b/targets/TEST/OAI/case01.py index 2d704a7d1f..cdc3bd9eb4 100644 --- a/targets/TEST/OAI/case01.py +++ b/targets/TEST/OAI/case01.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/TEST/OAI/case02.py b/targets/TEST/OAI/case02.py index dc7fcb7a4f..741c96cd76 100644 --- a/targets/TEST/OAI/case02.py +++ b/targets/TEST/OAI/case02.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/TEST/OAI/case03.py b/targets/TEST/OAI/case03.py index bfd0eda45b..e2a783e3ea 100644 --- a/targets/TEST/OAI/case03.py +++ b/targets/TEST/OAI/case03.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/TEST/OAI/case04.py b/targets/TEST/OAI/case04.py index 09bc88d688..eb77f72297 100644 --- a/targets/TEST/OAI/case04.py +++ b/targets/TEST/OAI/case04.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/TEST/OAI/case05.py b/targets/TEST/OAI/case05.py index c7186f466a..4f03368721 100644 --- a/targets/TEST/OAI/case05.py +++ b/targets/TEST/OAI/case05.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/TEST/OAI/case11.py b/targets/TEST/OAI/case11.py index 5d24bc3c02..9a74a1637e 100644 --- a/targets/TEST/OAI/case11.py +++ b/targets/TEST/OAI/case11.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/TEST/OAI/case12.py b/targets/TEST/OAI/case12.py index d9970eebc3..baa6a73367 100644 --- a/targets/TEST/OAI/case12.py +++ b/targets/TEST/OAI/case12.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/TEST/OAI/case13.py b/targets/TEST/OAI/case13.py index ea8f3ad15d..d6fcca1bc5 100644 --- a/targets/TEST/OAI/case13.py +++ b/targets/TEST/OAI/case13.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/TEST/OAI/core.py b/targets/TEST/OAI/core.py index d5275d29ca..acdd6c830c 100644 --- a/targets/TEST/OAI/core.py +++ b/targets/TEST/OAI/core.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/TEST/OAI/log.py b/targets/TEST/OAI/log.py index 25eb2b5ffb..5a97b19cf2 100644 --- a/targets/TEST/OAI/log.py +++ b/targets/TEST/OAI/log.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/TEST/OAI/openair.py b/targets/TEST/OAI/openair.py index 0e393ddbd7..e03188c11d 100644 --- a/targets/TEST/OAI/openair.py +++ b/targets/TEST/OAI/openair.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/TEST/OAI/test01.py b/targets/TEST/OAI/test01.py index b499c1381b..d923a8e27e 100644 --- a/targets/TEST/OAI/test01.py +++ b/targets/TEST/OAI/test01.py @@ -4,7 +4,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/TEST/OAI/test02.py b/targets/TEST/OAI/test02.py index 8175f3128c..c0c94b7d23 100644 --- a/targets/TEST/OAI/test02.py +++ b/targets/TEST/OAI/test02.py @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/TEST/PACKET_TRACER/pt.c b/targets/TEST/PACKET_TRACER/pt.c index 928c69f588..9e4077e274 100644 --- a/targets/TEST/PACKET_TRACER/pt.c +++ b/targets/TEST/PACKET_TRACER/pt.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/TEST/PDCP/readme.txt b/targets/TEST/PDCP/readme.txt index 1693d92d81..6e4f3eb054 100644 --- a/targets/TEST/PDCP/readme.txt +++ b/targets/TEST/PDCP/readme.txt @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/TEST/PDCP/test_pdcp.c b/targets/TEST/PDCP/test_pdcp.c index 952415f1ae..b07add73a6 100644 --- a/targets/TEST/PDCP/test_pdcp.c +++ b/targets/TEST/PDCP/test_pdcp.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/TEST/PDCP/test_pdcp.h b/targets/TEST/PDCP/test_pdcp.h index 5bbb73bdbf..0da174cc8c 100644 --- a/targets/TEST/PDCP/test_pdcp.h +++ b/targets/TEST/PDCP/test_pdcp.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/TEST/PDCP/test_util.h b/targets/TEST/PDCP/test_util.h index 3fa71b586a..834a955abf 100644 --- a/targets/TEST/PDCP/test_util.h +++ b/targets/TEST/PDCP/test_util.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c b/targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c index d64315fc25..1cadea3715 100644 --- a/targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c +++ b/targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/TEST/RLC_AM_V9.3.0/oaisim.c b/targets/TEST/RLC_AM_V9.3.0/oaisim.c index 5b7a911d83..dda91f0b1f 100644 --- a/targets/TEST/RLC_AM_V9.3.0/oaisim.c +++ b/targets/TEST/RLC_AM_V9.3.0/oaisim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/TEST/RLC_UM_V9.3.0/oaisim.c b/targets/TEST/RLC_UM_V9.3.0/oaisim.c index 1fb8f595d4..e1fce26a6f 100644 --- a/targets/TEST/RLC_UM_V9.3.0/oaisim.c +++ b/targets/TEST/RLC_UM_V9.3.0/oaisim.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/TEST/ROHDE_SCHWARZ/EthernetRawCommand.cpp b/targets/TEST/ROHDE_SCHWARZ/EthernetRawCommand.cpp index b5f5e2a961..110d499e06 100644 --- a/targets/TEST/ROHDE_SCHWARZ/EthernetRawCommand.cpp +++ b/targets/TEST/ROHDE_SCHWARZ/EthernetRawCommand.cpp @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/TEST/ROHDE_SCHWARZ/TcpClient.cpp b/targets/TEST/ROHDE_SCHWARZ/TcpClient.cpp index 67804c1e3e..70b4ad1f98 100644 --- a/targets/TEST/ROHDE_SCHWARZ/TcpClient.cpp +++ b/targets/TEST/ROHDE_SCHWARZ/TcpClient.cpp @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/TEST/ROHDE_SCHWARZ/TcpClient.h b/targets/TEST/ROHDE_SCHWARZ/TcpClient.h index b1cda37275..c53ff446c1 100644 --- a/targets/TEST/ROHDE_SCHWARZ/TcpClient.h +++ b/targets/TEST/ROHDE_SCHWARZ/TcpClient.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/targets/build_helper.bash b/targets/build_helper.bash index f161275c65..a3c57b8dce 100755 --- a/targets/build_helper.bash +++ b/targets/build_helper.bash @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/build_oai.bash b/targets/build_oai.bash index 7a6a179beb..cfe5e35d26 100755 --- a/targets/build_oai.bash +++ b/targets/build_oai.bash @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * diff --git a/targets/perf_oai.bash b/targets/perf_oai.bash index 4a9cb3951d..a5209ec7cb 100755 --- a/targets/perf_oai.bash +++ b/targets/perf_oai.bash @@ -3,7 +3,7 @@ # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. # * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.0 (the "License"); you may not use this file +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file # * except in compliance with the License. # * You may obtain a copy of the License at # * From 61234aae0526313af54c881bbda5da2773a2dc25 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 23 Oct 2017 15:15:56 +0200 Subject: [PATCH 062/284] update README for version 0.6.1. --- README.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/README.txt b/README.txt index bff09c7a2a..edd233830f 100644 --- a/README.txt +++ b/README.txt @@ -43,3 +43,4 @@ v0.5.2 -> Last version with old code for oaisim (abstraction mode works) v0.6 -> RRH functionality, UE greatly improved, better TDD support, a lot of bugs fixed. WARNING: oaisim in PHY abstraction mode does not work, you need to use v0.5.2 for that. +v0.6.1 -> Mostly bugfixes. This is the last version without NFAPI. From 4b9f58c085b7ad8894e1c5f48bf4635d48e08ca5 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 23 Oct 2017 17:40:32 +0200 Subject: [PATCH 063/284] T tracer: fix traces (add/remove to be in synch with VCD module) --- common/utils/T/T_defs.h | 4 +- common/utils/T/T_messages.txt | 80 +++++++++++++++++++++++++++++++---- 2 files changed, 74 insertions(+), 10 deletions(-) diff --git a/common/utils/T/T_defs.h b/common/utils/T/T_defs.h index 65f2430265..24845b6b9e 100644 --- a/common/utils/T/T_defs.h +++ b/common/utils/T/T_defs.h @@ -29,10 +29,10 @@ typedef struct { #define T_SHM_FILENAME "/T_shm_segment" /* number of VCD functions (to be kept up to date! see in T_messages.txt) */ -#define VCD_NUM_FUNCTIONS 172 +#define VCD_NUM_FUNCTIONS 178 /* number of VCD variables (to be kept up to date! see in T_messages.txt) */ -#define VCD_NUM_VARIABLES 118 +#define VCD_NUM_VARIABLES 128 /* first VCD function (to be kept up to date! see in T_messages.txt) */ #define VCD_FIRST_FUNCTION ((uintptr_t)T_VCD_FUNCTION_RT_SLEEP) diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index 0eef56505a..3e37b5ea15 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -958,6 +958,38 @@ ID = VCD_VARIABLE_SUBFRAME_NUMBER_RX1_ENB DESC = VCD variable SUBFRAME_NUMBER_RX1_ENB GROUP = ALL:VCD:ENB:VCD_VARIABLE FORMAT = ulong,value +ID = VCD_VARIABLE_FRAME_NUMBER_TX0_RU + DESC = VCD variable FRAME_NUMBER_TX0_RU + GROUP = ALL:VCD:ENB:VCD_VARIABLE + FORMAT = ulong,value +ID = VCD_VARIABLE_FRAME_NUMBER_TX1_RU + DESC = VCD variable FRAME_NUMBER_TX1_RU + GROUP = ALL:VCD:ENB:VCD_VARIABLE + FORMAT = ulong,value +ID = VCD_VARIABLE_FRAME_NUMBER_RX0_RU + DESC = VCD variable FRAME_NUMBER_RX0_RU + GROUP = ALL:VCD:ENB:VCD_VARIABLE + FORMAT = ulong,value +ID = VCD_VARIABLE_FRAME_NUMBER_RX1_RU + DESC = VCD variable FRAME_NUMBER_RX1_RU + GROUP = ALL:VCD:ENB:VCD_VARIABLE + FORMAT = ulong,value +ID = VCD_VARIABLE_SUBFRAME_NUMBER_TX0_RU + DESC = VCD variable SUBFRAME_NUMBER_TX0_RU + GROUP = ALL:VCD:ENB:VCD_VARIABLE + FORMAT = ulong,value +ID = VCD_VARIABLE_SUBFRAME_NUMBER_TX1_RU + DESC = VCD variable SUBFRAME_NUMBER_TX1_RU + GROUP = ALL:VCD:ENB:VCD_VARIABLE + FORMAT = ulong,value +ID = VCD_VARIABLE_SUBFRAME_NUMBER_RX0_RU + DESC = VCD variable SUBFRAME_NUMBER_RX0_RU + GROUP = ALL:VCD:ENB:VCD_VARIABLE + FORMAT = ulong,value +ID = VCD_VARIABLE_SUBFRAME_NUMBER_RX1_RU + DESC = VCD variable SUBFRAME_NUMBER_RX1_RU + GROUP = ALL:VCD:ENB:VCD_VARIABLE + FORMAT = ulong,value ID = VCD_VARIABLE_RUNTIME_TX_ENB DESC = VCD variable RUNTIME_TX_ENB GROUP = ALL:VCD:ENB:VCD_VARIABLE @@ -1050,6 +1082,14 @@ ID = VCD_VARIABLE_TRX_TST DESC = VCD variable TRX_TST GROUP = ALL:VCD:ENB:VCD_VARIABLE FORMAT = ulong,value +ID = VCD_VARIABLE_TRX_TS_UE + DESC = VCD variable TRX_TS_UE + GROUP = ALL:VCD:UE:VCD_VARIABLE + FORMAT = ulong,value +ID = VCD_VARIABLE_TRX_TST_UE + DESC = VCD variable TRX_TST_UE + GROUP = ALL:VCD:UE:VCD_VARIABLE + FORMAT = ulong,value ID = VCD_VARIABLE_TRX_WRITE_FLAGS DESC = VCD variable TRX_WRITE_FLAGS GROUP = ALL:VCD:ENB:VCD_VARIABLE @@ -1413,6 +1453,14 @@ ID = VCD_FUNCTION_TRX_WRITE DESC = VCD function TRX_WRITE GROUP = ALL:VCD:ENB:VCD_FUNCTION FORMAT = int,value +ID = VCD_FUNCTION_TRX_READ_UE + DESC = VCD function TRX_READ_UE + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_TRX_WRITE_UE + DESC = VCD function TRX_WRITE_UE + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value ID = VCD_FUNCTION_TRX_READ_IF DESC = VCD function TRX_READ_IF GROUP = ALL:VCD:ENB:VCD_FUNCTION @@ -1565,12 +1613,28 @@ ID = VCD_FUNCTION_PHY_PROCEDURES_ENB_TX1 DESC = VCD function PHY_PROCEDURES_ENB_TX1 GROUP = ALL:VCD:ENB:VCD_FUNCTION FORMAT = int,value -ID = VCD_FUNCTION_PHY_PROCEDURES_ENB_RX_COMMON - DESC = VCD function PHY_PROCEDURES_ENB_RX_COMMON +ID = VCD_FUNCTION_PHY_PROCEDURES_RU_FEPRX + DESC = VCD function PHY_PROCEDURES_RU_FEPRX GROUP = ALL:VCD:ENB:VCD_FUNCTION FORMAT = int,value -ID = VCD_FUNCTION_PHY_PROCEDURES_ENB_RX_COMMON1 - DESC = VCD function PHY_PROCEDURES_ENB_RX_COMMON1 +ID = VCD_FUNCTION_PHY_PROCEDURES_RU_FEPRX1 + DESC = VCD function PHY_PROCEDURES_RU_FEPRX1 + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PHY_PROCEDURES_RU_FEPTX_OFDM + DESC = VCD function PHY_PROCEDURES_RU_FEPTX_OFDM + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PHY_PROCEDURES_RU_FEPTX_OFDM1 + DESC = VCD function PHY_PROCEDURES_RU_FEPTX_OFDM1 + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PHY_PROCEDURES_RU_FEPTX_PREC + DESC = VCD function PHY_PROCEDURES_RU_FEPTX_PREC + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PHY_PROCEDURES_RU_FEPTX_PREC1 + DESC = VCD function PHY_PROCEDURES_RU_FEPTX_PREC1 GROUP = ALL:VCD:ENB:VCD_FUNCTION FORMAT = int,value ID = VCD_FUNCTION_PHY_PROCEDURES_ENB_RX_UESPEC @@ -1581,10 +1645,6 @@ ID = VCD_FUNCTION_PHY_PROCEDURES_ENB_RX_UESPEC1 DESC = VCD function PHY_PROCEDURES_ENB_RX_UESPEC1 GROUP = ALL:VCD:ENB:VCD_FUNCTION FORMAT = int,value -ID = VCD_FUNCTION_ENB_SLOT_FEP - DESC = VCD function ENB_SLOT_FEP - GROUP = ALL:VCD:ENB:VCD_FUNCTION - FORMAT = int,value ID = VCD_FUNCTION_PHY_PROCEDURES_UE_TX DESC = VCD function PHY_PROCEDURES_UE_TX GROUP = ALL:VCD:UE:VCD_FUNCTION @@ -1781,6 +1841,10 @@ ID = VCD_FUNCTION_PHY_ENB_PRACH_RX DESC = VCD function PHY_ENB_PRACH_RX GROUP = ALL:VCD:ENB:VCD_FUNCTION FORMAT = int,value +ID = VCD_FUNCTION_PHY_RU_PRACH_RX + DESC = VCD function PHY_RU_PRACH_RX + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value ID = VCD_FUNCTION_PHY_ENB_PDCCH_TX DESC = VCD function PHY_ENB_PDCCH_TX GROUP = ALL:VCD:ENB:VCD_FUNCTION From 2e5f0a07c7a1b55f0adf350930c7ce4c21279770 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 24 Oct 2017 10:21:57 +0200 Subject: [PATCH 064/284] minor: fix tracing utility (no malloc for it takes too long at startup) --- openair2/PHY_INTERFACE/IF_Module.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/openair2/PHY_INTERFACE/IF_Module.c b/openair2/PHY_INTERFACE/IF_Module.c index b1014e8bde..ab6551f61c 100644 --- a/openair2/PHY_INTERFACE/IF_Module.c +++ b/openair2/PHY_INTERFACE/IF_Module.c @@ -156,6 +156,9 @@ void handle_ulsch(UL_IND_t *UL_info) { #define C do { size = 0; put(0); } while (0) #define A(...) do { char t[4096]; sprintf(t, __VA_ARGS__); append_string(t); } while (0) +#if 0 + +/* eats lots of ms at startup, disrupts realtime */ static char *s; static int size; static int maxsize; @@ -169,6 +172,22 @@ static void put(char x) s[size++] = x; } +#else + +/* eats nothing at startup, but fixed size */ +#define SMAX 65536 +static char s[SMAX]; +static int size; +static int maxsize = SMAX; + +static void put(char x) +{ + if (size == maxsize) { printf("incrase SMAX\n"); exit(1); } + s[size++] = x; +} + +#endif + static void append_string(char *t) { size--; From 6da4265876c26b8c9f6792caebabb001c2542aac Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 25 Oct 2017 14:26:49 +0200 Subject: [PATCH 065/284] bugfix: fix timing advance - remove global variables in the function lte_est_timing_advance_pusch - do the smoothing logic that was in lte_est_timing_advance_pusch in rx_sdu (is it necessary? is it correct?) - put back the value 100 in prach_procedures for the test on prach energy - change the value of timing_advance_update it was: timing_advance_update = sync_pos - eNB->frame_parms.nb_prefix_samples/4; //to check it is now: timing_advance_update = sync_pos; // - eNB->frame_parms.nb_prefix_samples/4; //to check this should be checked somehow. The computation looked suspicious. Maybe the new one is wrong. --- openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c | 16 +++------------- openair1/SCHED/phy_procedures_lte_eNb.c | 4 ++-- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 10 +++++++--- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c index 30538d8298..cd032e688f 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c @@ -227,11 +227,8 @@ int lte_est_timing_advance(LTE_DL_FRAME_PARMS *frame_parms, int lte_est_timing_advance_pusch(PHY_VARS_eNB* eNB,uint8_t UE_id) { - static int first_run=1; - static int max_pos_fil2=0; int temp, i, aa, max_pos=0, max_val=0; - short Re,Im,coef=24576; - short ncoef = 32768 - coef; + short Re,Im; LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms; LTE_eNB_PUSCH *eNB_pusch_vars = eNB->pusch_vars[UE_id]; @@ -260,16 +257,9 @@ int lte_est_timing_advance_pusch(PHY_VARS_eNB* eNB,uint8_t UE_id) if (max_pos>frame_parms->ofdm_symbol_size/2) max_pos = max_pos-frame_parms->ofdm_symbol_size; - // filter position to reduce jitter - if (first_run == 1) { - first_run=0; - max_pos_fil2 = max_pos; - } else - max_pos_fil2 = ((max_pos_fil2 * coef) + (max_pos * ncoef)) >> 15; - //#ifdef DEBUG_PHY - LOG_D(PHY,"frame %d: max_pos = %d, max_pos_fil = %d, sync_pos=%d\n",eNB->proc.frame_rx,max_pos,max_pos_fil2,sync_pos); + LOG_D(PHY,"frame %d: max_pos = %d, sync_pos=%d\n",eNB->proc.frame_rx,max_pos,sync_pos); //#endif //DEBUG_PHY - return(max_pos_fil2-sync_pos); + return max_pos - sync_pos; } diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 5f31572513..c99776e7e5 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -663,7 +663,7 @@ void prach_procedures(PHY_VARS_eNB *eNB, { if ((eNB->prach_energy_counter == 100) && - (max_preamble_energy[0] > eNB->measurements.prach_I0+200)) { + (max_preamble_energy[0] > eNB->measurements.prach_I0+100)) { LOG_D(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", eNB->Mod_id, @@ -1524,7 +1524,7 @@ void fill_rx_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe) pdu->data = eNB->ulsch[UE_id]->harq_processes[harq_pid]->b; // estimate timing advance for MAC sync_pos = lte_est_timing_advance_pusch(eNB,UE_id); - timing_advance_update = sync_pos - eNB->frame_parms.nb_prefix_samples/4; //to check + timing_advance_update = sync_pos; // - eNB->frame_parms.nb_prefix_samples/4; //to check // if (timing_advance_update > 10) { dump_ulsch(eNB,frame,subframe,UE_id); exit(-1);} // if (timing_advance_update < -10) { dump_ulsch(eNB,frame,subframe,UE_id); exit(-1);} diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 96ffc8a761..1fcd07c1d3 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -113,9 +113,13 @@ void rx_sdu(const module_id_t enb_mod_idP, UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer = 0; UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= (~(1<UE_sched_ctrl[UE_id].ta_timer == 0) - UE_list->UE_sched_ctrl[UE_id].ta_update = timing_advance; + /* Update with smoothing: 3/4 of old value and 1/4 of new. + * This is the logic that was done in the function + * lte_est_timing_advance_pusch, maybe it's not necessary? + * maybe it's even not correct at all? + */ + UE_list->UE_sched_ctrl[UE_id].ta_update = + (UE_list->UE_sched_ctrl[UE_id].ta_update * 3 + timing_advance)/4; UE_list->UE_sched_ctrl[UE_id].pusch_snr[CC_idP] = ul_cqi; UE_list->UE_sched_ctrl[UE_id].ul_consecutive_errors = 0; first_rb = UE_list->UE_template[CC_idP][UE_id].first_rb_ul[harq_pid]; From 6322010e0aa0eed14c7ac0b313f5d31c1ea8c119 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 27 Oct 2017 16:01:33 +0200 Subject: [PATCH 066/284] T: add a tracer: extract This tracer extracts the content of a buffer field of an event that was previously saved using the tracer 'record'. For example, to extract the channel estimation done in frame 924 and subframe 2 as saved in the file input_record.raw and to store it in the file output.raw, do: ./extract -d ../T_messages.txt -o output.raw input_record.raw ENB_PHY_UL_CHANNEL_ESTIMATE chest_t -f frame 924 -f subframe 2 --- common/utils/T/.gitignore | 1 + common/utils/T/tracer/Makefile | 7 +- common/utils/T/tracer/extract.c | 124 ++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 common/utils/T/tracer/extract.c diff --git a/common/utils/T/.gitignore b/common/utils/T/.gitignore index f5724e6ff8..532e083e15 100644 --- a/common/utils/T/.gitignore +++ b/common/utils/T/.gitignore @@ -10,4 +10,5 @@ tracer/replay tracer/textlog tracer/vcd tracer/macpdu2wireshark +tracer/extract tracee/tracee diff --git a/common/utils/T/tracer/Makefile b/common/utils/T/tracer/Makefile index 6546345968..a7d3bf561b 100644 --- a/common/utils/T/tracer/Makefile +++ b/common/utils/T/tracer/Makefile @@ -6,7 +6,7 @@ CFLAGS=-Wall -g -pthread -DT_TRACER -I. LIBS=-lX11 -lm -lpng -lXft all: record replay extract_config textlog enb ue vcd macpdu2wireshark \ - extract_input_subframe + extract_input_subframe extract record: utils.o record.o database.o config.o $(CC) $(CFLAGS) -o record $^ $(LIBS) @@ -21,6 +21,9 @@ extract_input_subframe: extract_input_subframe.o database.o event.o utils.o \ config.o $(CC) $(CFLAGS) -o $@ $^ $(LIBS) +extract: extract.o database.o event.o utils.o config.o + $(CC) $(CFLAGS) -o $@ $^ $(LIBS) + textlog: utils.o textlog.o database.o event.o handler.o config.o \ event_selector.o view/view.a gui/gui.a logger/logger.a \ filter/filter.a @@ -64,7 +67,7 @@ filter/filter.a: clean: rm -f *.o core tracer_remote textlog enb ue vcd record replay - rm -f extract_config macpdu2wireshark extract_input_subframe + rm -f extract_config macpdu2wireshark extract_input_subframe extract cd gui && make clean cd view && make clean cd logger && make clean diff --git a/common/utils/T/tracer/extract.c b/common/utils/T/tracer/extract.c new file mode 100644 index 0000000000..b9fca959ed --- /dev/null +++ b/common/utils/T/tracer/extract.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include "database.h" +#include "event.h" +#include "config.h" + +void usage(void) +{ + printf( +"usage: [options] \n" +"options:\n" +" -d this option is mandatory\n" +" -o this option is mandatory\n" +" -f field 'name' of 'event' has to match 'value'\n" +" type of 'name' must be int\n" +" (you can use several -f options)\n" + ); + exit(1); +} + +int get_filter_arg(database_event_format *f, char *field, char *type) +{ + int i; + for (i = 0; i < f->count; i++) + if (!strcmp(f->name[i], field)) { + if (strcmp(f->type[i], type)) break; + return i; + } + printf("bad field %s, check that it exists and has type '%s'\n",field,type); + exit(1); +} + +int main(int n, char **v) +{ + char *database_filename = NULL; + void *database; + int i; + int input_event_id; + database_event_format f; + char *file = NULL; + char *output_file = NULL; + FILE *out; + int fd; + char *event_name = NULL; + char *buffer_name = NULL; + char *filter[n]; + int filter_arg[n]; + int filter_value[n]; + int filter_count = 0; + int buffer_arg; + int found; + + for (i = 1; i < n; i++) { + if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage(); + if (!strcmp(v[i], "-d")) + { if (i > n-2) usage(); database_filename = v[++i]; continue; } + if (!strcmp(v[i], "-o")) + { if (i > n-2) usage(); output_file = v[++i]; continue; } + if (!strcmp(v[i], "-f")) { if (i>n-3) usage(); + filter[filter_count] = v[++i]; + filter_value[filter_count++] = atoi(v[++i]); + continue; + } + if (file == NULL) { file = v[i]; continue; } + if (event_name == NULL) { event_name = v[i]; continue; } + if (buffer_name == NULL) { buffer_name = v[i]; continue; } + usage(); + } + if (file == NULL || event_name == NULL || buffer_name == NULL) usage(); + + if (database_filename == NULL) { + printf("ERROR: provide a database file (-d)\n"); + exit(1); + } + + if (output_file == NULL) { + printf("gimme -o , thanks\n"); + exit(1); + } + + out = fopen(output_file, "w"); if(out==NULL){perror(output_file);exit(1);} + + database = parse_database(database_filename); + + load_config_file(database_filename); + + input_event_id = event_id_from_name(database, event_name); + f = get_format(database, input_event_id); + + buffer_arg = get_filter_arg(&f, buffer_name, "buffer"); + + for (i = 0; i < filter_count; i++) + filter_arg[i] = get_filter_arg(&f, filter[i], "int"); + + fd = open(file, O_RDONLY); + if (fd == -1) { perror(file); exit(1); } + + found = 0; + + while (1) { + char v[T_BUFFER_MAX]; + event e; + e = get_event(fd, v, database); + if (e.type == -1) break; + if (e.type != input_event_id) continue; + for (i = 0; i < filter_count; i++) + if (filter_value[i] != e.e[filter_arg[i]].i) + break; + if (i != filter_count) + continue; + if (fwrite(e.e[buffer_arg].b, e.e[buffer_arg].bsize, 1, out) != 1) + { perror(output_file); exit(1); } + found = 1; + break; + } + + if (found == 0) printf("ERROR: event not found\n"); + + fclose(out); + + return 0; +} From 98b5faae4724911b55678ebd5f10eb565d38ac10 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 1 Sep 2017 12:33:40 +0200 Subject: [PATCH 067/284] RRC release 14.3 --- cmake_targets/CMakeLists.txt | 2 +- cmake_targets/tools/fix_asn1 | 2 +- .../ASN1_files/{RRC-e10.asn => RRC-e30.asn} | 2371 +++++++++++++++-- 3 files changed, 2086 insertions(+), 289 deletions(-) rename openair2/RRC/LITE/MESSAGES/asn1c/ASN1_files/{RRC-e10.asn => RRC-e30.asn} (83%) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index e7409d5503..3dbb61b5ae 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -291,7 +291,7 @@ elseif (${RRC_ASN1_VERSION} STREQUAL "CBA") elseif (${RRC_ASN1_VERSION} STREQUAL "Rel10") set (RRC_GRAMMAR ${OPENAIR2_DIR}/RRC/LITE/MESSAGES/asn1c/ASN1_files/EUTRA-RRC-Definitions-a20.asn) else() - set (RRC_GRAMMAR ${OPENAIR2_DIR}/RRC/LITE/MESSAGES/asn1c/ASN1_files/RRC-e10.asn) + set (RRC_GRAMMAR ${OPENAIR2_DIR}/RRC/LITE/MESSAGES/asn1c/ASN1_files/RRC-e30.asn) endif (${RRC_ASN1_VERSION} STREQUAL "Rel8") set (RRC_FULL_DIR ${asn1_generated_dir}/${RRC_ASN1_VERSION}) diff --git a/cmake_targets/tools/fix_asn1 b/cmake_targets/tools/fix_asn1 index 805a4ce66a..5cdab5ffd8 100755 --- a/cmake_targets/tools/fix_asn1 +++ b/cmake_targets/tools/fix_asn1 @@ -4,7 +4,7 @@ # RRC_Rel14=( - "SystemInformation-r8-IEs.h" 562e3c3aeb7c6d76d722f31bf24488a26e627f33 "fix_asn1.data/RRC.rel14/SystemInformation-r8-IEs.h.diff" + "SystemInformation-r8-IEs.h" 4df485c5ddf2540eca271876cdc512caa19b0890 "fix_asn1.data/RRC.rel14/SystemInformation-r8-IEs.h.diff" ) RRC_Rel10=( diff --git a/openair2/RRC/LITE/MESSAGES/asn1c/ASN1_files/RRC-e10.asn b/openair2/RRC/LITE/MESSAGES/asn1c/ASN1_files/RRC-e30.asn similarity index 83% rename from openair2/RRC/LITE/MESSAGES/asn1c/ASN1_files/RRC-e10.asn rename to openair2/RRC/LITE/MESSAGES/asn1c/ASN1_files/RRC-e30.asn index cb13f30c0e..2f02a8b4e5 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1c/ASN1_files/RRC-e10.asn +++ b/openair2/RRC/LITE/MESSAGES/asn1c/ASN1_files/RRC-e30.asn @@ -11,6 +11,13 @@ BCCH-BCH-Message ::= SEQUENCE { BCCH-BCH-MessageType ::= MasterInformationBlock +BCCH-BCH-Message-MBMS::= SEQUENCE { + message BCCH-BCH-MessageType-MBMS-r14 +} + +BCCH-BCH-MessageType-MBMS-r14 ::= MasterInformationBlock-MBMS-r14 + + BCCH-DL-SCH-Message ::= SEQUENCE { message BCCH-DL-SCH-MessageType } @@ -37,6 +44,19 @@ BCCH-DL-SCH-MessageType-BR-r13 ::= CHOICE { } +BCCH-DL-SCH-Message-MBMS ::= SEQUENCE { + message BCCH-DL-SCH-MessageType-MBMS-r14 +} + +BCCH-DL-SCH-MessageType-MBMS-r14 ::= CHOICE { + c1 CHOICE { + systemInformation-MBMS-r14 SystemInformation-MBMS-r14, + systemInformationBlockType1-MBMS-r14 SystemInformationBlockType1-MBMS-r14 + }, + messageClassExtension SEQUENCE {} +} + + MCCH-Message ::= SEQUENCE { message MCCH-MessageType } @@ -130,21 +150,21 @@ UL-DCCH-Message ::= SEQUENCE { UL-DCCH-MessageType ::= CHOICE { c1 CHOICE { - csfbParametersRequestCDMA2000 CSFBParametersRequestCDMA2000, - measurementReport MeasurementReport, - rrcConnectionReconfigurationComplete RRCConnectionReconfigurationComplete, - rrcConnectionReestablishmentComplete RRCConnectionReestablishmentComplete, + csfbParametersRequestCDMA2000 CSFBParametersRequestCDMA2000, + measurementReport MeasurementReport, + rrcConnectionReconfigurationComplete RRCConnectionReconfigurationComplete, + rrcConnectionReestablishmentComplete RRCConnectionReestablishmentComplete, rrcConnectionSetupComplete RRCConnectionSetupComplete, - securityModeComplete SecurityModeComplete, + securityModeComplete SecurityModeComplete, securityModeFailure SecurityModeFailure, ueCapabilityInformation UECapabilityInformation, - ulHandoverPreparationTransfer ULHandoverPreparationTransfer, - ulInformationTransfer ULInformationTransfer, - counterCheckResponse CounterCheckResponse, - ueInformationResponse-r9 UEInformationResponse-r9, + ulHandoverPreparationTransfer ULHandoverPreparationTransfer, + ulInformationTransfer ULInformationTransfer, + counterCheckResponse CounterCheckResponse, + ueInformationResponse-r9 UEInformationResponse-r9, proximityIndication-r9 ProximityIndication-r9, - rnReconfigurationComplete-r10 RNReconfigurationComplete-r10, - mbmsCountingResponse-r10 MBMSCountingResponse-r10, + rnReconfigurationComplete-r10 RNReconfigurationComplete-r10, + mbmsCountingResponse-r10 MBMSCountingResponse-r10, interFreqRSTDMeasurementIndication-r10 InterFreqRSTDMeasurementIndication-r10 }, messageClassExtension CHOICE { @@ -152,9 +172,9 @@ UL-DCCH-MessageType ::= CHOICE { ueAssistanceInformation-r11 UEAssistanceInformation-r11, inDeviceCoexIndication-r11 InDeviceCoexIndication-r11, mbmsInterestIndication-r11 MBMSInterestIndication-r11, - scgFailureInformation-r12 SCGFailureInformation-r12, - sidelinkUEInformation-r12 SidelinkUEInformation-r12, - wlanConnectionStatusReport-r13 WLANConnectionStatusReport-r13, + scgFailureInformation-r12 SCGFailureInformation-r12, + sidelinkUEInformation-r12 SidelinkUEInformation-r12, + wlanConnectionStatusReport-r13 WLANConnectionStatusReport-r13, rrcConnectionResumeComplete-r13 RRCConnectionResumeComplete-r13, spare9 NULL, spare8 NULL, spare7 NULL, spare6 NULL, spare5 NULL, spare4 NULL, @@ -174,7 +194,13 @@ SC-MCCH-MessageType-r13 ::= CHOICE { c1 CHOICE { scptmConfiguration-r13 SCPTMConfiguration-r13 }, - messageClassExtension SEQUENCE {} + messageClassExtension CHOICE { + c2 CHOICE { + scptmConfiguration-BR-r14 SCPTMConfiguration-BR-r14, + spare NULL + }, + messageClassExtensionFuture-r14 SEQUENCE {} + } } @@ -360,9 +386,14 @@ InDeviceCoexIndication-v11d0-IEs ::= SEQUENCE { } InDeviceCoexIndication-v1310-IEs ::= SEQUENCE { - affectedCarrierFreqList-v1310 AffectedCarrierFreqList-v1310 OPTIONAL, - affectedCarrierFreqCombList-r13 AffectedCarrierFreqCombList-r13 OPTIONAL, - nonCriticalExtension SEQUENCE {} OPTIONAL + affectedCarrierFreqList-v1310 AffectedCarrierFreqList-v1310 OPTIONAL, + affectedCarrierFreqCombList-r13 AffectedCarrierFreqCombList-r13 OPTIONAL, + nonCriticalExtension InDeviceCoexIndication-v1360-IEs OPTIONAL +} + +InDeviceCoexIndication-v1360-IEs ::= SEQUENCE { + hardwareSharingProblem-r13 ENUMERATED {true} OPTIONAL, + nonCriticalExtension SEQUENCE {} OPTIONAL } AffectedCarrierFreqList-r11 ::= SEQUENCE (SIZE (1..maxFreqIDC-r11)) OF AffectedCarrierFreq-r11 @@ -510,6 +541,15 @@ MasterInformationBlock ::= SEQUENCE { +MasterInformationBlock-MBMS-r14 ::= SEQUENCE { + dl-Bandwidth-MBMS-r14 ENUMERATED { + n6, n15, n25, n50, n75, n100}, + systemFrameNumber-r14 BIT STRING (SIZE (6)), + additionalNonMBSFNSubframes-r14 INTEGER (0..3), + spare BIT STRING (SIZE (13)) +} + + MBMSCountingRequest-r10 ::= SEQUENCE { countingRequestList-r10 CountingRequestList-r10, lateNonCriticalExtension OCTET STRING OPTIONAL, @@ -582,16 +622,23 @@ MBSFNAreaConfiguration-r9 ::= SEQUENCE { MBSFNAreaConfiguration-v930-IEs ::= SEQUENCE { lateNonCriticalExtension OCTET STRING OPTIONAL, - nonCriticalExtension MBSFNAreaConfiguration-v1250-IEs OPTIONAL + nonCriticalExtension MBSFNAreaConfiguration-v1250-IEs OPTIONAL } MBSFNAreaConfiguration-v1250-IEs ::= SEQUENCE { pmch-InfoListExt-r12 PMCH-InfoListExt-r12 OPTIONAL, -- Need OR + nonCriticalExtension MBSFNAreaConfiguration-v1430-IEs OPTIONAL +} + +MBSFNAreaConfiguration-v1430-IEs ::= SEQUENCE { + commonSF-Alloc-r14 CommonSF-AllocPatternList-r14, nonCriticalExtension SEQUENCE {} OPTIONAL } CommonSF-AllocPatternList-r9 ::= SEQUENCE (SIZE (1..maxMBSFN-Allocations)) OF MBSFN-SubframeConfig +CommonSF-AllocPatternList-r14 ::= SEQUENCE (SIZE (1..maxMBSFN-Allocations)) OF MBSFN-SubframeConfig-v1430 + MeasurementReport ::= SEQUENCE { criticalExtensions CHOICE { @@ -904,12 +951,14 @@ RRCConnectionReconfiguration-v1310-IEs ::= SEQUENCE { lwa-Configuration-r13 LWA-Configuration-r13 OPTIONAL, -- Need ON lwip-Configuration-r13 LWIP-Configuration-r13 OPTIONAL, -- Need ON rclwi-Configuration-r13 RCLWI-Configuration-r13 OPTIONAL, -- Need ON - nonCriticalExtension RRCConnectionReconfiguration-v14x0-IEs OPTIONAL + nonCriticalExtension RRCConnectionReconfiguration-v1430-IEs OPTIONAL } -RRCConnectionReconfiguration-v14x0-IEs ::= SEQUENCE { +RRCConnectionReconfiguration-v1430-IEs ::= SEQUENCE { sl-V2X-ConfigDedicated-r14 SL-V2X-ConfigDedicated-r14 OPTIONAL, -- Need ON - sCellToAddModListExt-v14xy SCellToAddModListExt-v14xy OPTIONAL, -- Need ON + sCellToAddModListExt-v1430 SCellToAddModListExt-v1430 OPTIONAL, -- Need ON + perCC-GapIndicationRequest-r14 ENUMERATED{true} OPTIONAL, -- Need ON + systemInformationBlockType2Dedicated-r14 OCTET STRING (CONTAINING SystemInformationBlockType2) OPTIONAL, -- Need ON nonCriticalExtension SEQUENCE {} OPTIONAL } @@ -942,7 +991,7 @@ SCellToAddModList-r10 ::= SEQUENCE (SIZE (1..maxSCell-r10)) OF SCellToAddM SCellToAddModListExt-r13 ::= SEQUENCE (SIZE (1..maxSCell-r13)) OF SCellToAddModExt-r13 -SCellToAddModListExt-v14xy ::= SEQUENCE (SIZE (1..maxSCell-r13)) OF SCellToAddModExt-v14xy +SCellToAddModListExt-v1430 ::= SEQUENCE (SIZE (1..maxSCell-r13)) OF SCellToAddModExt-v1430 SCellToAddMod-r10 ::= SEQUENCE { sCellIndex-r10 SCellIndex-r10, @@ -972,8 +1021,9 @@ SCellToAddModExt-r13 ::= SEQUENCE { antennaInfoDedicatedSCell-r13 AntennaInfoDedicated-v10i0 OPTIONAL -- Need ON } -SCellToAddModExt-v14xy ::= SEQUENCE { - srs-SwitchFromServCellIndex-r14 INTEGER (0.. 31) OPTIONAL -- Need ON +SCellToAddModExt-v1430 ::= SEQUENCE { + srs-SwitchFromServCellIndex-r14 INTEGER (0.. 31) OPTIONAL, -- Need ON + ... } SCellToReleaseList-r10 ::= SEQUENCE (SIZE (1..maxSCell-r10)) OF SCellIndex-r10 @@ -1053,6 +1103,13 @@ RRCConnectionReconfigurationComplete-v1130-IEs ::= SEQUENCE { RRCConnectionReconfigurationComplete-v1250-IEs ::= SEQUENCE { logMeasAvailableMBSFN-r12 ENUMERATED {true} OPTIONAL, + nonCriticalExtension RRCConnectionReconfigurationComplete-v1430-IEs OPTIONAL +} + +RRCConnectionReconfigurationComplete-v1430-IEs ::= SEQUENCE { + perCC-GapIndicationList-r14 PerCC-GapIndicationList-r14 OPTIONAL, + numFreqEffective-r14 INTEGER (1..12) OPTIONAL, + numFreqEffectiveReduced-r14 INTEGER (1..12) OPTIONAL, nonCriticalExtension SEQUENCE {} OPTIONAL } @@ -1417,8 +1474,8 @@ RRCConnectionResume-r13 ::= SEQUENCE { criticalExtensions CHOICE { c1 CHOICE { rrcConnectionResume-r13 RRCConnectionResume-r13-IEs, - spare3 NULL, - spare2 NULL, + spare3 NULL, + spare2 NULL, spare1 NULL }, criticalExtensionsFuture SEQUENCE {} @@ -1432,7 +1489,12 @@ RRCConnectionResume-r13-IEs ::= SEQUENCE { antennaInfoDedicatedPCell-r13 AntennaInfoDedicated-v10i0 OPTIONAL, -- Need ON drb-ContinueROHC-r13 ENUMERATED {true} OPTIONAL, -- Need OP lateNonCriticalExtension OCTET STRING OPTIONAL, - nonCriticalExtension SEQUENCE {} OPTIONAL + rrcConnectionResume-v1430-IEs RRCConnectionResume-v1430-IEs OPTIONAL +} + +RRCConnectionResume-v1430-IEs ::= SEQUENCE { + otherConfig-r14 OtherConfig-r9 OPTIONAL, -- Need ON + nonCriticalExtension SEQUENCE {} OPTIONAL } @@ -1549,17 +1611,22 @@ RRCConnectionSetupComplete-v1250-IEs ::= SEQUENCE { } RRCConnectionSetupComplete-v1320-IEs ::= SEQUENCE { - ce-ModeB-r13 ENUMERATED {supported} OPTIONAL, - s-TMSI-r13 S-TMSI OPTIONAL, - attachWithoutPDN-Connectivity-r13 ENUMERATED {true} OPTIONAL, - up-CIoT-EPS-Optimisation-r13 ENUMERATED {true} OPTIONAL, - cp-CIoT-EPS-Optimisation-r13 ENUMERATED {true} OPTIONAL, - nonCriticalExtension RRCConnectionSetupComplete-v1330-IEs OPTIONAL + ce-ModeB-r13 ENUMERATED {supported} OPTIONAL, + s-TMSI-r13 S-TMSI OPTIONAL, + attachWithoutPDN-Connectivity-r13 ENUMERATED {true} OPTIONAL, + up-CIoT-EPS-Optimisation-r13 ENUMERATED {true} OPTIONAL, + cp-CIoT-EPS-Optimisation-r13 ENUMERATED {true} OPTIONAL, + nonCriticalExtension RRCConnectionSetupComplete-v1330-IEs OPTIONAL } RRCConnectionSetupComplete-v1330-IEs ::= SEQUENCE { ue-CE-NeedULGaps-r13 ENUMERATED {true} OPTIONAL, - nonCriticalExtension SEQUENCE {} OPTIONAL + nonCriticalExtension RRCConnectionSetupComplete-v1430-IEs OPTIONAL +} + +RRCConnectionSetupComplete-v1430-IEs ::= SEQUENCE { + dcn-ID-r14 INTEGER (0..65535) OPTIONAL, + nonCriticalExtension SEQUENCE {} OPTIONAL } RegisteredMME ::= SEQUENCE { @@ -1585,10 +1652,16 @@ SCGFailureInformation-r12-IEs ::= SEQUENCE { } SCGFailureInformation-v1310-IEs ::= SEQUENCE { - lateNonCriticalExtension OCTET STRING OPTIONAL, + lateNonCriticalExtension OCTET STRING (CONTAINING SCGFailureInformation-v12d0-IEs) OPTIONAL, nonCriticalExtension SEQUENCE {} OPTIONAL } +-- Late non-critical extensions: +SCGFailureInformation-v12d0-IEs ::= SEQUENCE { + failureReportSCG-v12d0 FailureReportSCG-v12d0 OPTIONAL, nonCriticalExtension SEQUENCE {} OPTIONAL +} + +-- Regular non-critical extensions: FailureReportSCG-r12 ::= SEQUENCE { failureType-r12 ENUMERATED {t313-Expiry, randomAccessProblem, rlc-MaxNumRetx, scg-ChangeFailure }, @@ -1601,6 +1674,10 @@ FailureReportSCG-r12 ::= SEQUENCE { ]] } +FailureReportSCG-v12d0 ::= SEQUENCE { + measResultNeighCells-v12d0 MeasResultList2EUTRA-v9e0 OPTIONAL +} + SCPTMConfiguration-r13 ::= SEQUENCE { sc-mtch-InfoList-r13 SC-MTCH-InfoList-r13, @@ -1615,6 +1692,15 @@ SCPTMConfiguration-v1340 ::= SEQUENCE { } +SCPTMConfiguration-BR-r14 ::= SEQUENCE { + sc-mtch-InfoList-r14 SC-MTCH-InfoList-BR-r14, + scptm-NeighbourCellList-r14 SCPTM-NeighbourCellList-r13 OPTIONAL, -- Need OP + p-b-r14 INTEGER (0..3) OPTIONAL, -- Need OR + lateNonCriticalExtension OCTET STRING OPTIONAL, + nonCriticalExtension SEQUENCE {} OPTIONAL +} + + SecurityModeCommand ::= SEQUENCE { rrc-TransactionIdentifier RRC-TransactionIdentifier, criticalExtensions CHOICE { @@ -1712,12 +1798,13 @@ SidelinkUEInformation-v1310-IEs ::= SEQUENCE { discRxGapReq-r13 SL-GapRequest-r13 OPTIONAL, discTxGapReq-r13 SL-GapRequest-r13 OPTIONAL, discSysInfoReportFreqList-r13 SL-DiscSysInfoReportFreqList-r13 OPTIONAL, - nonCriticalExtension SidelinkUEInformation-v14x0-IEs OPTIONAL + nonCriticalExtension SidelinkUEInformation-v1430-IEs OPTIONAL } -SidelinkUEInformation-v14x0-IEs ::= SEQUENCE { - v2x-CommRxInterestedFreq-r14 INTEGER (0..maxFreq) OPTIONAL, - v2x-CommTxResourceReq-r14 V2X-CommTxResourceReq-r14 OPTIONAL, +SidelinkUEInformation-v1430-IEs ::= SEQUENCE { + v2x-CommRxInterestedFreqList-r14 SL-V2X-CommFreqList-r14 OPTIONAL, + p2x-CommTxType-r14 ENUMERATED {true} OPTIONAL, + v2x-CommTxResourceReq-r14 SL-V2X-CommTxFreqList-r14 OPTIONAL, nonCriticalExtension SEQUENCE {} OPTIONAL } @@ -1726,11 +1813,6 @@ SL-CommTxResourceReq-r12 ::= SEQUENCE { destinationInfoList-r12 SL-DestinationInfoList-r12 } -V2X-CommTxResourceReq-r14 ::= SEQUENCE { - v2x-CommTxFreq-r14 INTEGER (0..maxFreq) OPTIONAL, - v2x-DestinationInfoList-r14 SL-DestinationInfoList-r12 OPTIONAL -} - SL-DiscTxResourceReqPerFreqList-r13 ::= SEQUENCE (SIZE (1..maxFreq)) OF SL-DiscTxResourceReq-r13 SL-DiscTxResourceReq-r13 ::= SEQUENCE { @@ -1744,9 +1826,23 @@ SL-DestinationIdentity-r12 ::= BIT STRING (SIZE (24)) SL-DiscSysInfoReportFreqList-r13 ::= SEQUENCE (SIZE (1.. maxSL-DiscSysInfoReportFreq-r13)) OF SL-DiscSysInfoReport-r13 +SL-V2X-CommFreqList-r14 ::= SEQUENCE (SIZE (1..maxFreqV2X-r14)) OF INTEGER (0..maxFreqV2X-1-r14) + +SL-V2X-CommTxFreqList-r14 ::= SEQUENCE (SIZE (1..maxFreqV2X-r14)) OF SL-V2X-CommTxResourceReq-r14 + +SL-V2X-CommTxResourceReq-r14 ::= SEQUENCE { + carrierFreqCommTx-r14 INTEGER (0.. maxFreqV2X-1-r14) OPTIONAL, + v2x-TypeTxSync-r14 SL-TypeTxSync-r14 OPTIONAL, + v2x-DestinationInfoList-r14 SL-DestinationInfoList-r12 OPTIONAL +} + +SL-TypeTxSyncList-r14 ::= SEQUENCE (SIZE (1..maxFreqV2X-r14)) OF SL-TypeTxSync-r14 + SystemInformation-BR-r13 ::= SystemInformation +SystemInformation-MBMS-r14 ::= SystemInformation + SystemInformation ::= SEQUENCE { criticalExtensions CHOICE { systemInformation-r8 SystemInformation-r8-IEs, @@ -1775,7 +1871,7 @@ SystemInformation-r8-IEs ::= SEQUENCE { sib18-v1250 SystemInformationBlockType18-r12, sib19-v1250 SystemInformationBlockType19-r12, sib20-v1310 SystemInformationBlockType20-r13, - sib21-v14x0 SystemInformationBlockType21-r14 + sib21-v1430 SystemInformationBlockType21-r14 }, nonCriticalExtension SystemInformation-v8a0-IEs OPTIONAL } @@ -1895,11 +1991,24 @@ SystemInformationBlockType1-v1320-IEs ::= SEQUENCE { } OPTIONAL, -- Need OR mpdcch-pdsch-HoppingOffset-r13 INTEGER (1..maxAvailNarrowBands-r13) OPTIONAL -- Need OR } OPTIONAL, -- Cond Hopping - nonCriticalExtension SystemInformationBlockType1-v14xy-IEs OPTIONAL + nonCriticalExtension SystemInformationBlockType1-v1350-IEs OPTIONAL } -SystemInformationBlockType1-v14xy-IEs ::= SEQUENCE { +SystemInformationBlockType1-v1350-IEs ::= SEQUENCE { + cellSelectionInfoCE1-r13 CellSelectionInfoCE1-r13 OPTIONAL, -- Need OP + nonCriticalExtension SystemInformationBlockType1-v1360-IEs OPTIONAL +} + +SystemInformationBlockType1-v1360-IEs ::= SEQUENCE { + cellSelectionInfoCE1-v1360 CellSelectionInfoCE1-v1360 OPTIONAL, -- Cond QrxlevminCE1 + nonCriticalExtension SystemInformationBlockType1-v1430-IEs OPTIONAL +} + +SystemInformationBlockType1-v1430-IEs ::= SEQUENCE { eCallOverIMS-Support-r14 ENUMERATED {true} OPTIONAL, -- Need OR + tdd-Config-v1430 TDD-Config-v1430 OPTIONAL, -- Cond TDD-OR + cellAccessRelatedInfoList-r14 SEQUENCE (SIZE (1..maxPLMN-1-r14)) OF + CellAccessRelatedInfo-r14 OPTIONAL, -- Need OR nonCriticalExtension SEQUENCE {} OPTIONAL } @@ -1934,7 +2043,7 @@ SIB-Type ::= ENUMERATED { sibType11, sibType12-v920, sibType13-v920, sibType14-v1130, sibType15-v1130, sibType16-v1130, sibType17-v1250, sibType18-v1250, - ..., sibType19-v1250, sibType20-v1310, sibType21-v14x0} + ..., sibType19-v1250, sibType20-v1310, sibType21-v1430} SystemInfoValueTagList-r13 ::= SEQUENCE (SIZE (1..maxSI-Message)) OF SystemInfoValueTagSI-r13 @@ -1953,6 +2062,56 @@ CellSelectionInfo-v1250 ::= SEQUENCE { q-QualMinRSRQ-OnAllSymbols-r12 Q-QualMin-r9 } +CellAccessRelatedInfo-r14 ::= SEQUENCE { + plmn-IdentityList-r14 PLMN-IdentityList, + trackingAreaCode-r14 TrackingAreaCode, + cellIdentity-r14 CellIdentity +} + + +SystemInformationBlockType1-MBMS-r14 ::= SEQUENCE { + cellAccessRelatedInfo-r14 SEQUENCE { + plmn-IdentityList-r14 PLMN-IdentityList-MBMS-r14, + trackingAreaCode-r14 TrackingAreaCode, + cellIdentity-r14 CellIdentity + }, + freqBandIndicator-r14 FreqBandIndicator-r11, + multiBandInfoList-r14 MultiBandInfoList-r11 OPTIONAL, -- Need OR + schedulingInfoList-MBMS-r14 SchedulingInfoList-MBMS-r14, + si-WindowLength-r14 ENUMERATED { + ms1, ms2, ms5, ms10, ms15, ms20,ms40, ms80}, + systemInfoValueTag-r14 INTEGER (0..31), + nonMBSFN-SubframeConfig-r14 NonMBSFN-SubframeConfig-r14 OPTIONAL, --Need OR + pdsch-ConfigCommon-r14 PDSCH-ConfigCommon, + systemInformationBlockType13-r14 SystemInformationBlockType13-r9 OPTIONAL, --Need OR + cellAccessRelatedInfoList-r14 SEQUENCE (SIZE (1..maxPLMN-1-r14)) OF + CellAccessRelatedInfo-r14 OPTIONAL, -- Need OR + nonCriticalExtension SEQUENCE {} OPTIONAL +} + +PLMN-IdentityList-MBMS-r14 ::= SEQUENCE (SIZE (1..maxPLMN-r11)) OF PLMN-Identity + +SchedulingInfoList-MBMS-r14 ::= SEQUENCE (SIZE (1..maxSI-Message)) OF SchedulingInfo-MBMS-r14 + +SchedulingInfo-MBMS-r14 ::= SEQUENCE { + si-Periodicity-r14 ENUMERATED { + rf16, rf32, rf64, rf128, rf256, rf512}, + sib-MappingInfo-r14 SIB-MappingInfo-MBMS-r14 +} + +SIB-MappingInfo-MBMS-r14 ::= SEQUENCE (SIZE (0..maxSIB-1)) OF SIB-Type-MBMS-r14 + +SIB-Type-MBMS-r14 ::= ENUMERATED { + sibType10, sibType11, sibType12-v920, sibType13-v920, + sibType15-v1130, sibType16-v1130, ...} + + +NonMBSFN-SubframeConfig-r14 ::= SEQUENCE { + radioFrameAllocationPeriod-r14 ENUMERATED {rf4, rf8, rf16, rf32, rf64, rf128, rf512}, + radioFrameAllocationOffset-r14 INTEGER (0..7), + subframeAllocation-r14 BIT STRING (SIZE(9)) +} + UEAssistanceInformation-r11 ::= SEQUENCE { criticalExtensions CHOICE { @@ -1966,8 +2125,48 @@ UEAssistanceInformation-r11 ::= SEQUENCE { UEAssistanceInformation-r11-IEs ::= SEQUENCE { powerPrefIndication-r11 ENUMERATED {normal, lowPowerConsumption} OPTIONAL, - lateNonCriticalExtension OCTET STRING OPTIONAL, - nonCriticalExtension SEQUENCE {} OPTIONAL + lateNonCriticalExtension OCTET STRING OPTIONAL, + nonCriticalExtension UEAssistanceInformation-v1430-IEs OPTIONAL +} + +UEAssistanceInformation-v1430-IEs ::= SEQUENCE { + bw-Preference-r14 BW-Preference-r14 OPTIONAL, + sps-AssistanceInformation-r14 SEQUENCE { + trafficPatternInfoListSL-r14 TrafficPatternInfoList-r14 OPTIONAL, + trafficPatternInfoListUL-r14 TrafficPatternInfoList-r14 OPTIONAL + } OPTIONAL, + rlm-Report-r14 SEQUENCE { + rlm-Event-r14 ENUMERATED {earlyOutOfSync, earlyInSync}, + excessRep-MPDCCH-r14 ENUMERATED {excessRep1, excessRep2} OPTIONAL + } OPTIONAL, delayBudgetReport-r14 DelayBudgetReport-r14 OPTIONAL, + nonCriticalExtension SEQUENCE {} OPTIONAL +} + +BW-Preference-r14 ::= SEQUENCE { + dl-Preference-r14 ENUMERATED {mhz1dot4, mhz5, mhz20 } OPTIONAL, + ul-Preference-r14 ENUMERATED {mhz1dot4, mhz5} OPTIONAL +} + +TrafficPatternInfoList-r14 ::= SEQUENCE (SIZE (1..maxTrafficPattern-r14)) OF TrafficPatternInfo-r14 + +TrafficPatternInfo-r14 ::= SEQUENCE { + trafficPeriodicity-r14 ENUMERATED { + sf20, sf50, sf100, sf200, sf300, sf400, sf500, + sf600, sf700, sf800, sf900, sf1000}, + timingOffset-r14 INTEGER (0..10239), + priorityInfoSL-r14 SL-Priority-r13 OPTIONAL, + logicalChannelIdentityUL-r14 INTEGER (3..10) OPTIONAL, + messageSize-r14 BIT STRING (SIZE (6)) +} + +DelayBudgetReport-r14::= CHOICE { + type1 ENUMERATED { + msMinus1280, msMinus640, msMinus320, msMinus160, + msMinus80, msMinus60, msMinus40, msMinus20, ms0, ms20, ms40, ms60, ms80, ms160, ms320, ms640, ms1280}, + + type2 ENUMERATED { + msMinus192, msMinus168,msMinus144, msMinus120, + msMinus96, msMinus72, msMinus48, msMinus24, ms0, ms24, ms48, ms72, ms96, ms120, ms144, ms168, ms192} } @@ -2003,6 +2202,11 @@ UECapabilityEnquiry-v1310-IEs ::= SEQUENCE { requestedMaxCCsDL-r13 INTEGER (2..32) OPTIONAL, -- Need ON requestedMaxCCsUL-r13 INTEGER (2..32) OPTIONAL, -- Need ON requestReducedIntNonContComb-r13 ENUMERATED {true} OPTIONAL, -- Need ON + nonCriticalExtension UECapabilityEnquiry-v1430-IEs OPTIONAL +} + +UECapabilityEnquiry-v1430-IEs ::= SEQUENCE { + requestDiffFallbackCombList-r14 BandCombinationList-r14 OPTIONAL, -- Need ON nonCriticalExtension SEQUENCE {} OPTIONAL } @@ -2183,6 +2387,8 @@ RLF-Report-r9 ::= SEQUENCE { measResultListEUTRA-v1250 MeasResultList2EUTRA-v1250 OPTIONAL ]], [[ drb-EstablishedWithQCI-1-r13 ENUMERATED {qci1} OPTIONAL + ]], + [[ measResultLastServCell-v1360 RSRP-Range-v1360 OPTIONAL ]] } @@ -2258,6 +2464,8 @@ LogMeasInfo-r10 ::= SEQUENCE { measResultListEUTRA-v1250 MeasResultList2EUTRA-v1250 OPTIONAL ]], [[ inDeviceCoexDetected-r13 ENUMERATED {true} OPTIONAL + ]], + [[ measResultServCell-v1360 RSRP-Range-v1360 OPTIONAL ]] } @@ -2316,6 +2524,8 @@ ConnEstFailReport-r11 ::= SEQUENCE { [[ measResultFailedCell-v1250 RSRQ-Range-v1250 OPTIONAL, failedCellRSRQ-Type-r12 RSRQ-Type-r12 OPTIONAL, measResultListEUTRA-v1250 MeasResultList2EUTRA-v1250 OPTIONAL + ]], + [[ measResultFailedCell-v1360 RSRP-Range-v1360 OPTIONAL ]] } @@ -2387,6 +2597,11 @@ WLANConnectionStatusReport-r13 ::= SEQUENCE { WLANConnectionStatusReport-r13-IEs ::= SEQUENCE { wlan-Status-r13 WLAN-Status-r13, lateNonCriticalExtension OCTET STRING OPTIONAL, + nonCriticalExtension WLANConnectionStatusReport-v1430-IEs OPTIONAL +} + +WLANConnectionStatusReport-v1430-IEs ::= SEQUENCE { + wlan-Status-v1430 WLAN-Status-v1430, nonCriticalExtension SEQUENCE {} OPTIONAL } @@ -2425,10 +2640,15 @@ SystemInformationBlockType2 ::= SEQUENCE { acdc-BarringPerPLMN-List-r13 ACDC-BarringPerPLMN-List-r13 OPTIONAL -- Need OP ]], [[ - udt-RestrictingForCommon-r13 UDT-Restricting-r13 OPTIONAL, -- Need OR + udt-RestrictingForCommon-r13 UDT-Restricting-r13 OPTIONAL, -- Need OR udt-RestrictingPerPLMN-List-r13 UDT-RestrictingPerPLMN-List-r13 OPTIONAL, -- Need OR cIoT-EPS-OptimisationInfo-r13 CIOT-EPS-OptimisationInfo-r13 OPTIONAL, -- Need OP useFullResumeID-r13 ENUMERATED {true} OPTIONAL -- Need OP + ]], + [[ unicastFreqHoppingInd-r13 ENUMERATED {true} OPTIONAL -- Need OP + ]], + [[ mbsfn-SubframeConfigList-v1430 MBSFN-SubframeConfigList-v1430 OPTIONAL, -- Need OP + videoServiceCauseIndication-r14 ENUMERATED {true} OPTIONAL -- Need OP ]] } @@ -2453,6 +2673,8 @@ AC-BarringConfig ::= SEQUENCE { MBSFN-SubframeConfigList ::= SEQUENCE (SIZE (1..maxMBSFN-Allocations)) OF MBSFN-SubframeConfig +MBSFN-SubframeConfigList-v1430 ::= SEQUENCE (SIZE (1..maxMBSFN-Allocations)) OF MBSFN-SubframeConfig-v1430 + AC-BarringPerPLMN-List-r12 ::= SEQUENCE (SIZE (1.. maxPLMN-r11)) OF AC-BarringPerPLMN-r12 AC-BarringPerPLMN-r12 ::= SEQUENCE { @@ -2567,7 +2789,11 @@ SystemInformationBlockType3 ::= SEQUENCE { redistributionServingInfo-r13 RedistributionServingInfo-r13 OPTIONAL, --Need OR cellSelectionInfoCE-r13 CellSelectionInfoCE-r13 OPTIONAL, -- Need OP t-ReselectionEUTRA-CE-r13 T-ReselectionEUTRA-CE-r13 OPTIONAL -- Need OP - ]] + ]], + [[ cellSelectionInfoCE1-r13 CellSelectionInfoCE1-r13 OPTIONAL -- Need OP + ]], + [[ cellSelectionInfoCE1-v1360 CellSelectionInfoCE1-v1360 OPTIONAL -- Cond QrxlevminCE1 + ]] } RedistributionServingInfo-r13 ::= SEQUENCE { @@ -2620,6 +2846,13 @@ SystemInformationBlockType5 ::= SEQUENCE { ]], [[ interFreqCarrierFreqList-v1310 InterFreqCarrierFreqList-v1310 OPTIONAL, -- Need OR interFreqCarrierFreqListExt-v1310 InterFreqCarrierFreqListExt-v1310 OPTIONAL -- Need OR + ]], + [[ interFreqCarrierFreqList-v1350 InterFreqCarrierFreqList-v1350 OPTIONAL, -- Need OR + interFreqCarrierFreqListExt-v1350 InterFreqCarrierFreqListExt-v1350 OPTIONAL -- Need OR + ]], + [[ interFreqCarrierFreqListExt-v1360 InterFreqCarrierFreqListExt-v1360 OPTIONAL -- Need OR + ]], + [[ scptm-FreqOffset-r14 INTEGER (1..8) OPTIONAL -- Need OP ]] } @@ -2642,14 +2875,20 @@ InterFreqCarrierFreqList ::= SEQUENCE (SIZE (1..maxFreq)) OF InterFreqCar InterFreqCarrierFreqList-v1250 ::= SEQUENCE (SIZE (1.. maxFreq)) OF InterFreqCarrierFreqInfo-v1250 +InterFreqCarrierFreqList-v1310 ::= SEQUENCE (SIZE (1.. maxFreq)) OF InterFreqCarrierFreqInfo-v1310 + +InterFreqCarrierFreqList-v1350 ::= SEQUENCE (SIZE (1.. maxFreq)) OF InterFreqCarrierFreqInfo-v1350 + InterFreqCarrierFreqListExt-r12 ::= SEQUENCE (SIZE (1.. maxFreq)) OF InterFreqCarrierFreqInfo-r12 InterFreqCarrierFreqListExt-v1280 ::= SEQUENCE (SIZE (1.. maxFreq)) OF InterFreqCarrierFreqInfo-v10j0 -InterFreqCarrierFreqList-v1310 ::= SEQUENCE (SIZE (1.. maxFreq)) OF InterFreqCarrierFreqInfo-v1310 - InterFreqCarrierFreqListExt-v1310 ::= SEQUENCE (SIZE (1.. maxFreq)) OF InterFreqCarrierFreqInfo-v1310 +InterFreqCarrierFreqListExt-v1350 ::= SEQUENCE (SIZE (1.. maxFreq)) OF InterFreqCarrierFreqInfo-v1350 + +InterFreqCarrierFreqListExt-v1360 ::= SEQUENCE (SIZE (1..maxFreq)) OF InterFreqCarrierFreqInfo-v1360 + InterFreqCarrierFreqInfo ::= SEQUENCE { dl-CarrierFreq ARFCN-ValueEUTRA, q-RxLevMin Q-RxLevMin, @@ -2729,6 +2968,14 @@ InterFreqCarrierFreqInfo-v1310 ::= SEQUENCE { t-ReselectionEUTRA-CE-r13 T-ReselectionEUTRA-CE-r13 OPTIONAL -- Need OP } +InterFreqCarrierFreqInfo-v1350 ::= SEQUENCE { + cellSelectionInfoCE1-r13 CellSelectionInfoCE1-r13 OPTIONAL -- Need OP +} + +InterFreqCarrierFreqInfo-v1360 ::= SEQUENCE { + cellSelectionInfoCE1-v1360 CellSelectionInfoCE1-v1360 OPTIONAL -- Cond QrxlevminCE1 +} + InterFreqNeighCellList ::= SEQUENCE (SIZE (1..maxCellInter)) OF InterFreqNeighCellInfo InterFreqNeighCellInfo ::= SEQUENCE { @@ -3058,7 +3305,10 @@ SystemInformationBlockType13-r9 ::= SEQUENCE { mbsfn-AreaInfoList-r9 MBSFN-AreaInfoList-r9, notificationConfig-r9 MBMS-NotificationConfig-r9, lateNonCriticalExtension OCTET STRING OPTIONAL, - ... + ..., + [[ + notificationConfig-v1430 MBMS-NotificationConfig-v1430 OPTIONAL + ]] } @@ -3087,6 +3337,10 @@ SystemInformationBlockType15-r11 ::= SEQUENCE { lateNonCriticalExtension OCTET STRING OPTIONAL, ..., [[ mbms-SAI-InterFreqList-v1140 MBMS-SAI-InterFreqList-v1140 OPTIONAL -- Cond InterFreq + ]], + [[ mbms-IntraFreqCarrierType-r14 MBMS-CarrierType-r14 OPTIONAL, -- Need OR + mbms-InterFreqCarrierTypeList-r14 + MBMS-InterFreqCarrierTypeList-r14 OPTIONAL -- Need OR ]] } @@ -3107,6 +3361,12 @@ MBMS-SAI-InterFreq-v1140 ::= SEQUENCE { multiBandInfoList-r11 MultiBandInfoList-r11 OPTIONAL -- Need OR } +MBMS-InterFreqCarrierTypeList-r14 ::= SEQUENCE (SIZE (1..maxFreq)) OF MBMS-CarrierType-r14 + +MBMS-CarrierType-r14 ::= SEQUENCE { + carrierType-r14 ENUMERATED {mbms, fembmsMixed, fembmsDedicated}, + frameOffset-r14 INTEGER (0..3) OPTIONAL -- Need OR +} SystemInformationBlockType16-r11 ::= SEQUENCE { @@ -3251,40 +3511,96 @@ SL-ResourcesInterFreq-r13 ::= SEQUENCE { SystemInformationBlockType20-r13 ::= SEQUENCE { - sc-mcch-RepetionPeriod-r13 ENUMERATED {rf2, rf4, rf8, rf16, rf32, rf64, rf128, rf256}, + sc-mcch-RepetitionPeriod-r13 ENUMERATED {rf2, rf4, rf8, rf16, rf32, rf64, rf128, rf256}, sc-mcch-Offset-r13 INTEGER (0..10), sc-mcch-FirstSubframe-r13 INTEGER (0..9), sc-mcch-duration-r13 INTEGER (2..9) OPTIONAL, sc-mcch-ModificationPeriod-r13 ENUMERATED {rf2, rf4, rf8, rf16, rf32, rf64, rf128, rf256, rf512, rf1024, r2048, rf4096, rf8192, rf16384, rf32768, rf65536}, - lateNonCriticalExtension OCTET STRING OPTIONAL, + lateNonCriticalExtension OCTET STRING OPTIONAL, + ..., + [[ br-BCCH-Config-r14 SEQUENCE { + sc-mcch-RepetitionPeriod-v1430 ENUMERATED {rf1}, + sc-mcch-ModificationPeriod-v1430 ENUMERATED {rf1}, + mpdcch-Narrowband-SC-MCCH-r14 INTEGER (1..maxAvailNarrowBands-r13), + mpdcch-NumRepetition-SC-MCCH-r14 ENUMERATED {r1, r2, r4, r8, r16, + r32, r64, r128, r256}, + mpdcch-StartSF-SC-MCCH-r14 CHOICE { + fdd-r14 ENUMERATED {v1, v1dot5, v2, v2dot5, v4, + v5, v8, v10}, + tdd-r14 ENUMERATED {v1, v2, v4, v5, v8, v10, v20} + }, + mpdcch-PDSCH-HoppingConfig-SC-MCCH-r14 ENUMERATED {off, ce-ModeA, ce-ModeB}, + sc-mcch-CarrierFreq-r14 ARFCN-ValueEUTRA-r9, + sc-mcch-Offset-BR-r14 INTEGER (0..10), + sc-mcch-RepetitionPeriod-BR-r14 ENUMERATED {rf32, rf128, rf512, rf1024, + rf2048, rf4096, rf8192, rf16384}, + sc-mcch-ModificationPeriod-BR-r14 ENUMERATED { rf32, rf128, rf256, rf512, rf1024, + rf2048, rf4096, rf8192, rf16384, rf32768, + rf65536, rf131072, rf262144, rf524288, + rf1048576} + } OPTIONAL, -- Need OR + sc-mcch-SchedulingInfo-r14 SC-MCCH-SchedulingInfo-r14 OPTIONAL, -- Need OP + pdsch-maxNumRepetitionCEmodeA-SC-MTCH-r14 + ENUMERATED { r16, r32 } OPTIONAL, -- Need OR + pdsch-maxNumRepetitionCEmodeB-SC-MTCH-r14 + ENUMERATED { + r192, r256, r384, r512, r768, r1024, + r1536, r2048} OPTIONAL -- Need OR + ]] +} + +SC-MCCH-SchedulingInfo-r14::= SEQUENCE { + onDurationTimerSCPTM-r14 ENUMERATED {psf10, psf20, psf100, psf300, + psf500, psf1000, psf1200, psf1600}, + drx-InactivityTimerSCPTM-r14 ENUMERATED {psf0, psf1, psf2, psf4, psf8, psf16, + psf32, psf64, psf128, psf256, ps512, + psf1024, psf2048, psf4096, psf8192, psf16384}, + schedulingPeriodStartOffsetSCPTM-r14 CHOICE { + sf10 INTEGER(0..9), + sf20 INTEGER(0..19), + sf32 INTEGER(0..31), + sf40 INTEGER(0..39), + sf64 INTEGER(0..63), + sf80 INTEGER(0..79), + sf128 INTEGER(0..127), + sf160 INTEGER(0..159), + sf256 INTEGER(0..255), + sf320 INTEGER(0..319), + sf512 INTEGER(0..511), + sf640 INTEGER(0..639), + sf1024 INTEGER(0..1023), + sf2048 INTEGER(0..2047), + sf4096 INTEGER(0..4095), + sf8192 INTEGER(0..8191) + }, ... } SystemInformationBlockType21-r14 ::= SEQUENCE { - sl-V2X-ConfigCommon-r14 SL-V2X-ConfigCommon-r14 OPTIONAL, -- Need OR - lateNonCriticalExtension OCTET STRING OPTIONAL, + sl-V2X-ConfigCommon-r14 SL-V2X-ConfigCommon-r14 OPTIONAL, -- Need OR + lateNonCriticalExtension OCTET STRING OPTIONAL, ... } SL-V2X-ConfigCommon-r14 ::= SEQUENCE { v2x-CommRxPool-r14 SL-CommRxPoolListV2X-r14 OPTIONAL, -- Need OR v2x-CommTxPoolNormalCommon-r14 SL-CommTxPoolListV2X-r14 OPTIONAL, -- Need OR + p2x-CommTxPoolNormalCommon-r14 SL-CommTxPoolListV2X-r14 OPTIONAL, -- Need OR v2x-CommTxPoolExceptional-r14 SL-CommResourcePoolV2X-r14 OPTIONAL, -- Need OR v2x-SyncConfig-r14 SL-SyncConfigListV2X-r14 OPTIONAL, -- Need OR v2x-InterFreqInfoList-r14 SL-InterFreqInfoListV2X-r14 OPTIONAL, -- Need OR - v2x-ResourceSelectionConfig-r14 SL-CommTxPoolSensingConfig-r14 OPTIONAL, -- Need OR - zoneConfig-r14 SL-ZoneConfig-r14 OPTIONAL -- Need OR + v2x-ResourceSelectionConfig-r14 SL-CommTxPoolSensingConfig-r14 OPTIONAL, -- Need OR + zoneConfig-r14 SL-ZoneConfig-r14 OPTIONAL, -- Need OR + typeTxSync-r14 SL-TypeTxSync-r14 OPTIONAL, -- Need OR + thresSL-TxPrioritization-r14 SL-Priority-r13 OPTIONAL, -- Need OR + anchorCarrierFreqList-r14 SL-AnchorCarrierFreqList-V2X-r14 OPTIONAL, -- Need OR + offsetDFN-r14 INTEGER (0..1000) OPTIONAL, -- Need OR + cbr-CommonTxConfigList-r14 SL-CBR-CommonTxConfigList-r14 OPTIONAL -- Need OR } -SL-CommTxPoolSensingConfig-r14 ::= SEQUENCE { - pssch-TxConfigList-r14 SL-PSSCH-TxConfigList-r14, - thresPSSCH-RSRP-List-r14 SL-ThresPSSCH-RSRP-List-r14, - restrictResourceReservationPeriodList-r14 SL-RestrictResourceReservationPeriodList-r14 OPTIONAL, -- Need OR - probResourceKeep-r14 ENUMERATED {v0, v0dot2, v0dot4, v0dot6, v0dot8, - spare3,spare2, spare1} -} + AntennaInfoCommon ::= SEQUENCE { antennaPortsCount ENUMERATED {an1, an2, an4, spare1} @@ -3337,6 +3653,10 @@ AntennaInfoDedicated-v1250 ::= SEQUENCE { alternativeCodebookEnabledFor4TX-r12 BOOLEAN } +AntennaInfoDedicated-v1430 ::= SEQUENCE { + ce-UE-TxAntennaSelection-config-r14 ENUMERATED {on} OPTIONAL -- Need OR +} + AntennaInfoUL-r10 ::= SEQUENCE { transmissionModeUL-r10 ENUMERATED {tm1, tm2, spare6, spare5, @@ -3399,6 +3719,10 @@ CQI-ReportConfig-v1320 ::= SEQUENCE { cqi-ReportPeriodic-v1320 CQI-ReportPeriodic-v1320 OPTIONAL -- Need ON } +CQI-ReportConfig-v1430 ::= SEQUENCE { + cqi-ReportAperiodicHybrid-r14 CQI-ReportAperiodicHybrid-r14 OPTIONAL -- Need ON +} + CQI-ReportConfigSCell-r10 ::= SEQUENCE { cqi-ReportModeAperiodic-r10 CQI-ReportModeAperiodic OPTIONAL, -- Need OR nomPDSCH-RS-EPRE-Offset-r10 INTEGER (-1..6), @@ -3561,6 +3885,28 @@ CQI-ReportAperiodicProc-v1310 ::= SEQUENCE { trigger111-r13 BOOLEAN } +CQI-ReportAperiodicHybrid-r14 ::= SEQUENCE { + triggers-r14 CHOICE { + oneBit-r14 SEQUENCE { + trigger1-Indicator-r14 BIT STRING (SIZE (8)) + }, + twoBit-r14 SEQUENCE { + trigger01-Indicator-r14 BIT STRING (SIZE (8)), + trigger10-Indicator-r14 BIT STRING (SIZE (8)), + trigger11-Indicator-r14 BIT STRING (SIZE (8)) + }, + threeBit-r14 SEQUENCE { + trigger001-Indicator-r14 BIT STRING (SIZE (32)), + trigger010-Indicator-r14 BIT STRING (SIZE (32)), + trigger011-Indicator-r14 BIT STRING (SIZE (32)), + trigger100-Indicator-r14 BIT STRING (SIZE (32)), + trigger101-Indicator-r14 BIT STRING (SIZE (32)), + trigger110-Indicator-r14 BIT STRING (SIZE (32)), + trigger111-Indicator-r14 BIT STRING (SIZE (32)) + } + } OPTIONAL -- Need OR +} + CQI-ReportModeAperiodic ::= ENUMERATED { rm12, rm20, rm22, rm30, rm31, rm32-v1250, rm10-v1310, rm11-v1310 @@ -3699,6 +4045,10 @@ CSI-Process-r11 ::= SEQUENCE { setup CQI-ReportAperiodicProc-v1310 } OPTIONAL, -- Need ON eMIMO-Type-r13 CSI-RS-ConfigEMIMO-r13 OPTIONAL -- Need ON + ]], + [[ eMIMO-Type-v1430 CSI-RS-ConfigEMIMO-v1430 OPTIONAL, -- Need ON + eMIMO-Hybrid-r14 CSI-RS-ConfigEMIMO-Hybrid-r14 OPTIONAL, -- Need ON + advancedCodebookEnabled-r14 BOOLEAN OPTIONAL -- Need ON ]] } @@ -3733,6 +4083,12 @@ CSI-RS-Config-v1310 ::= SEQUENCE { eMIMO-Type-r13 CSI-RS-ConfigEMIMO-r13 OPTIONAL -- Need ON } +CSI-RS-Config-v1430 ::= SEQUENCE { + eMIMO-Type-v1430 CSI-RS-ConfigEMIMO-v1430 OPTIONAL, -- Need ON + eMIMO-Hybrid-r14 CSI-RS-ConfigEMIMO-Hybrid-r14 OPTIONAL, -- Need ON + advancedCodebookEnabled-r14 BOOLEAN OPTIONAL -- Need ON +} + ZeroTxPowerCSI-RS-Conf-r12 ::= CHOICE { release NULL, setup ZeroTxPowerCSI-RS-r12 @@ -3752,6 +4108,27 @@ CSI-RS-ConfigEMIMO-r13 ::= CHOICE { } } +CSI-RS-ConfigEMIMO-v1430 ::= CHOICE { + release NULL, + setup CHOICE { + nonPrecoded-v1430 CSI-RS-ConfigNonPrecoded-v1430, + beamformed-v1430 CSI-RS-ConfigBeamformed-v1430 + } +} + +CSI-RS-ConfigEMIMO2-r14 ::= CHOICE { + release NULL, + setup CSI-RS-ConfigBeamformed-r14 +} + +CSI-RS-ConfigEMIMO-Hybrid-r14 ::= CHOICE { + release NULL, + setup SEQUENCE { + periodicityOffsetIndex-r14 INTEGER (0..1023) OPTIONAL, -- Need OR + eMIMO-Type2-r14 CSI-RS-ConfigEMIMO2-r14 OPTIONAL -- Need ON + } +} + CSI-RS-ConfigNonPrecoded-r13 ::= SEQUENCE { p-C-AndCBSRList-r13 P-C-AndCBSR-Pair-r13 OPTIONAL, -- Need OR codebookConfigN1-r13 ENUMERATED {n1, n2, n3, n4, n8}, @@ -3763,6 +4140,13 @@ CSI-RS-ConfigNonPrecoded-r13 ::= SEQUENCE { csi-RS-ConfigNZP-EMIMO-r13 CSI-RS-ConfigNZP-EMIMO-r13 OPTIONAL -- Need ON } +CSI-RS-ConfigNonPrecoded-v1430::= SEQUENCE { + csi-RS-ConfigNZP-EMIMO-v1430 CSI-RS-ConfigNZP-EMIMO-v1430 OPTIONAL, -- Need ON + codebookConfigN1-v1430 ENUMERATED {n5, n6, n7, n10, n12, n14, n16}, + codebookConfigN2-r1430 ENUMERATED {n5, n6, n7 }, + nzp-ResourceConfigTM9-Original-v1430 CSI-RS-Config-NZP-v1430 +} + CSI-RS-ConfigBeamformed-r13 ::= SEQUENCE { csi-RS-ConfigNZPIdListExt-r13 SEQUENCE (SIZE (1..7)) OF CSI-RS-ConfigNZPId-r13 OPTIONAL, -- Need OR csi-IM-ConfigIdList-r13 SEQUENCE (SIZE (1..8)) OF CSI-IM-ConfigId-r13 OPTIONAL, -- Need OR @@ -3772,6 +4156,36 @@ CSI-RS-ConfigBeamformed-r13 ::= SEQUENCE { channelMeasRestriction-r13 ENUMERATED {on} OPTIONAL -- Need OR } +CSI-RS-ConfigBeamformed-r14 ::= SEQUENCE { + csi-RS-ConfigNZPIdListExt-r14 SEQUENCE (SIZE (1..7)) OF CSI-RS-ConfigNZPId-r13 OPTIONAL, -- Need OR + csi-IM-ConfigIdList-r14 SEQUENCE (SIZE (1..8)) OF CSI-IM-ConfigId-r13 OPTIONAL, -- Need OR + p-C-AndCBSR-PerResourceConfigList-r14 SEQUENCE (SIZE (1..8)) OF P-C-AndCBSR-Pair-r13 OPTIONAL, -- Need OR + ace-For4Tx-PerResourceConfigList-r14 SEQUENCE (SIZE (1..7)) OF BOOLEAN OPTIONAL, -- Need OR + alternativeCodebookEnabledBeamformed-r14 ENUMERATED {true} OPTIONAL, -- Need OR + channelMeasRestriction-r14 ENUMERATED {on} OPTIONAL, -- Need OR + csi-RS-ConfigNZP-ApList-r14 SEQUENCE (SIZE (1..8)) OF CSI-RS-ConfigNZP-r11 + OPTIONAL, -- Need OR + nzp-ResourceConfigOriginal-v1430 CSI-RS-Config-NZP-v1430 OPTIONAL, -- Need OR + csi-RS-NZP-Activation-r14 CSI-RS-ConfigNZP-Activation-r14 OPTIONAL -- Need OR +} + +CSI-RS-ConfigBeamformed-v1430::= SEQUENCE { + csi-RS-ConfigNZP-ApList-r14 SEQUENCE (SIZE (1..8)) OF CSI-RS-ConfigNZP-r11 + OPTIONAL, -- Need OR + nzp-ResourceConfigOriginal-v1430 CSI-RS-Config-NZP-v1430 OPTIONAL, -- Need OR + csi-RS-NZP-Activation-r14 CSI-RS-ConfigNZP-Activation-r14 OPTIONAL -- Need OR +} + +CSI-RS-Config-NZP-v1430::= SEQUENCE { + transmissionComb-r14 NZP-TransmissionComb-r14 OPTIONAL, -- Need OR + frequencyDensity-r14 NZP-FrequencyDensity-r14 OPTIONAL -- Need OR +} + +CSI-RS-ConfigNZP-Activation-r14::= SEQUENCE { + csi-RS-NZP-mode-r14 ENUMERATED {semiPersistent, aperiodic}, + activatedResources-r14 INTEGER (0..4) +} + CSI-RS-ConfigNZP-r11 ::= SEQUENCE { csi-RS-ConfigNZPId-r11 CSI-RS-ConfigNZPId-r11, @@ -3791,6 +4205,16 @@ CSI-RS-ConfigNZP-r11 ::= SEQUENCE { } OPTIONAL, -- Need OR ..., [[ csi-RS-ConfigNZPId-v1310 CSI-RS-ConfigNZPId-v1310 OPTIONAL -- Need ON + ]], + [[ transmissionComb-r14 NZP-TransmissionComb-r14 OPTIONAL, -- Need OR + frequencyDensity-r14 NZP-FrequencyDensity-r14 OPTIONAL -- Need OR + ]], + [[ mbsfn-SubframeConfigList-v1430 CHOICE { + release NULL, + setup SEQUENCE { + subframeConfigList-v1430 MBSFN-SubframeConfigList-v1430 + } + } OPTIONAL -- Need OP ]] } @@ -3802,13 +4226,25 @@ CSI-RS-ConfigNZP-EMIMO-r13 ::= CHOICE { } } +CSI-RS-ConfigNZP-EMIMO-v1430 ::= SEQUENCE { + -- All extensions are for Non-Precoded so could be grouped by setup/ release choice + nzp-resourceConfigListExt-r14 SEQUENCE (SIZE (0..4)) OF NZP-ResourceConfig-r13, + cdmType-v1430 ENUMERATED {cdm8 } OPTIONAL -- Need OR +} + NZP-ResourceConfig-r13 ::= SEQUENCE { resourceConfig-r13 ResourceConfig-r13, - ... + ..., + [[ transmissionComb-r14 NZP-TransmissionComb-r14 OPTIONAL, -- Need OR + frequencyDensity-r14 NZP-FrequencyDensity-r14 OPTIONAL -- Need OR + ]] } ResourceConfig-r13 ::= INTEGER (0..31) +NZP-TransmissionComb-r14 ::= INTEGER (0..2) +NZP-FrequencyDensity-r14 ::= ENUMERATED {d1, d2, d3} + CSI-RS-ConfigNZPId-r11 ::= INTEGER (1..maxCSI-RS-NZP-r11) CSI-RS-ConfigNZPId-v1310 ::= INTEGER (minCSI-RS-NZP-r13..maxCSI-RS-NZP-r13) @@ -3822,10 +4258,20 @@ CSI-RS-ConfigZP-r11 ::= SEQUENCE { ... } +CSI-RS-ConfigZP-ApList-r14 ::= CHOICE { + release NULL, + setup SEQUENCE (SIZE (1.. maxCSI-RS-ZP-r11)) OF CSI-RS-ConfigZP-r11 +} + CSI-RS-ConfigZPId-r11 ::= INTEGER (1..maxCSI-RS-ZP-r11) +DataInactivityTimer-r14 ::= ENUMERATED { + s1, s2, s3, s5, s7, s10, s15, s20, s40, s50, s60, + s80, s100, s120, s150, s180} + + DMRS-Config-r11 ::= CHOICE { release NULL, setup SEQUENCE { @@ -3916,7 +4362,7 @@ EIMTA-MainConfigServCell-r12 ::= CHOICE { release NULL, setup SEQUENCE { eimta-UL-DL-ConfigIndex-r12 INTEGER (1..5), - eimta-HARQ-ReferenceConfig-r12 ENUMERATED {sa2,sa4,sa5}, + eimta-HARQ-ReferenceConfig-r12 ENUMERATED {sa2, sa4, sa5}, mbsfn-SubframeConfigList-v1250 CHOICE { release NULL, setup SEQUENCE { @@ -3945,7 +4391,10 @@ LogicalChannelConfig ::= SEQUENCE { ]], [[ logicalChannelSR-Prohibit-r12 BOOLEAN OPTIONAL -- Need ON ]], - [[ laa-Allowed-r14 BOOLEAN OPTIONAL -- Need ON + [[ laa-UL-Allowed-r14 BOOLEAN OPTIONAL, -- Need ON + bitRateQueryProhibitTimer-r14 ENUMERATED { + s0, s0dot4, s0dot8, s1dot6, s3, s6, s12, + s30} OPTIONAL --Need OR ]] } @@ -3960,7 +4409,9 @@ LWA-Configuration-r13 ::= CHOICE { LWA-Config-r13 ::= SEQUENCE { lwa-MobilityConfig-r13 WLAN-MobilityConfig-r13 OPTIONAL, -- Need ON lwa-WT-Counter-r13 INTEGER (0..65535) OPTIONAL, -- Need ON - ... + ..., + [[ wt-MAC-Address-r14 OCTET STRING (SIZE (6)) OPTIONAL -- Need ON + ]] } @@ -4051,7 +4502,13 @@ MAC-MainConfig ::= SEQUENCE { skipUplinkTxSPS-r14 ENUMERATED {true} OPTIONAL, -- Need OR skipUplinkTxDynamic-r14 ENUMERATED {true} OPTIONAL -- Need OR } - } OPTIONAL -- Need ON + } OPTIONAL, -- Need ON + dataInactivityTimerConfig-r14 CHOICE { + release NULL, + setup SEQUENCE { + dataInactivityTimer-r14 DataInactivityTimer-r14 + } + } OPTIONAL -- Need ON ]] } @@ -4188,18 +4645,8 @@ PDCCH-ConfigSCell-r13 ::= SEQUENCE { } PDCCH-ConfigLAA-r14 ::= SEQUENCE { - enableMonitoringDCI-Format0B-r14 CHOICE { - release NULL, - setup SEQUENCE { - maxNumberOfSchedSubframes-Format0B-r14 ENUMERATED {sf2, sf3, sf4} - } - } OPTIONAL, -- Need ON - enableMonitoringDCI-Format4B-r14 CHOICE { - release NULL, - setup SEQUENCE { - maxNumberOfSchedSubframes-Format4B-r14 ENUMERATED {sf2, sf3, sf4} - } - } OPTIONAL, -- Need ON + maxNumberOfSchedSubframes-Format0B-r14 ENUMERATED {sf2, sf3, sf4} OPTIONAL, -- Need OR + maxNumberOfSchedSubframes-Format4B-r14 ENUMERATED {sf2, sf3, sf4} OPTIONAL, -- Need OR skipMonitoringDCI-Format0A-r14 ENUMERATED {true} OPTIONAL, -- Need OR skipMonitoringDCI-Format4A-r14 ENUMERATED {true} OPTIONAL, -- Need OR pdcch-CandidateReductions-Format0A-r14 @@ -4305,9 +4752,29 @@ PDCP-Config ::= SEQUENCE { ms1, ms2, ms5, ms10, ms25, ms50, ms100, ms250, ms500, ms2500, ms5000, ms25000} OPTIONAL -- Need ON } - } OPTIONAL -- Need ON + } OPTIONAL -- Need ON + ]], + [[ ul-LWA-Config-r14 CHOICE { + release NULL, + setup SEQUENCE { + ul-LWA-DRB-ViaWLAN-r14 BOOLEAN, + ul-LWA-DataSplitThreshold-r14 ENUMERATED { + b0, b100, b200, b400, b800, b1600, b3200, b6400, + b12800, b25600, b51200, b102400, b204800, b409600, + b819200 } OPTIONAL -- Need OR + } + } OPTIONAL, -- Need ON + uplinkOnlyHeaderCompression-r14 CHOICE { + notUsed-r14 NULL, + rohc-r14 SEQUENCE { + maxCID-r14 INTEGER (1..16383) DEFAULT 15, + profiles-r14 SEQUENCE { + profile0x0006-r14 BOOLEAN + }, + ... + } + } OPTIONAL -- Need ON ]] - } @@ -4345,6 +4812,18 @@ PDSCH-ConfigDedicated-v1310 ::= SEQUENCE { dmrs-ConfigPDSCH-v1310 DMRS-Config-v1310 OPTIONAL -- Need ON } +PDSCH-ConfigDedicated-v1430 ::= SEQUENCE { + ce-PDSCH-MaxBandwidth-r14 ENUMERATED {bw5, bw20} OPTIONAL, -- Need OP + ce-PDSCH-TenProcesses-r14 ENUMERATED {on} OPTIONAL, -- Need OR + ce-HARQ-AckBundling-r14 ENUMERATED {on} OPTIONAL, -- Need OR + ce-SchedulingEnhancement-r14 ENUMERATED {range1, range2} OPTIONAL, -- Need OR + tbsIndexAlt2-r14 ENUMERATED {b33} OPTIONAL -- Need OR +} + +PDSCH-ConfigDedicatedSCell-v1430 ::= SEQUENCE { + tbsIndexAlt2-r14 ENUMERATED {b33} OPTIONAL -- Need OR +} + RE-MappingQCLConfigToAddModList-r11 ::= SEQUENCE (SIZE (1..maxRE-MapQCL-r11)) OF PDSCH-RE-MappingQCL-Config-r11 RE-MappingQCLConfigToReleaseList-r11 ::= SEQUENCE (SIZE (1..maxRE-MapQCL-r11)) OF PDSCH-RE-MappingQCL-ConfigId-r11 @@ -4364,12 +4843,26 @@ PDSCH-RE-MappingQCL-Config-r11 ::= SEQUENCE { } OPTIONAL, -- Need OP csi-RS-ConfigZPId-r11 CSI-RS-ConfigZPId-r11, qcl-CSI-RS-ConfigNZPId-r11 CSI-RS-ConfigNZPId-r11 OPTIONAL, -- Need OR - ... + ..., + [[ mbsfn-SubframeConfigList-v1430 CHOICE { + release NULL, + setup SEQUENCE { + subframeConfigList-v1430 MBSFN-SubframeConfigList-v1430 + } + } OPTIONAL -- Need OP + ]] } PDSCH-RE-MappingQCL-ConfigId-r11 ::= INTEGER (1..maxRE-MapQCL-r11) +PerCC-GapIndicationList-r14 ::= SEQUENCE (SIZE (1..maxServCell-r13)) OF PerCC-GapIndication-r14 + +PerCC-GapIndication-r14 ::= SEQUENCE { + servCellId-r14 ServCellIndex-r13, + gapIndication-r14 ENUMERATED {gap, ncsg, nogap-noNcsg} +} + PHICH-Config ::= SEQUENCE { phich-Duration ENUMERATED {normal, extended}, @@ -4473,7 +4966,10 @@ PhysicalConfigDedicated ::= SEQUENCE { ]], [[ cqi-ReportConfig-v1320 CQI-ReportConfig-v1320 OPTIONAL -- Need ON ]], - [[ typeA-SRS-TPC-PDCCH-Group-r14 SEQUENCE (SIZE (1..32)) OF SRS-TPC-PDCCH-Config-r14 OPTIONAL, -- Need ON + [[ typeA-SRS-TPC-PDCCH-Group-r14 CHOICE { + release NULL, + setup SEQUENCE (SIZE (1..32)) OF SRS-TPC-PDCCH-Config-r14 + } OPTIONAL, -- Need ON must-Config-r14 CHOICE{ release NULL, setup SEQUENCE { @@ -4482,9 +4978,22 @@ PhysicalConfigDedicated ::= SEQUENCE { dB-6, dB-4dot77, dB-3, dB-1dot77, dB0, dB1, dB2, dB3} OPTIONAL -- Need ON } - } OPTIONAL -- Need ON + } OPTIONAL, -- Need ON + pusch-EnhancementsConfig-r14 PUSCH-EnhancementsConfig-r14 OPTIONAL, -- Need + ce-pdsch-pusch-EnhancementConfig-r14 ENUMERATED {on} OPTIONAL, -- Need OR + antennaInfo-v1430 AntennaInfoDedicated-v1430 OPTIONAL, -- Need ON + pucch-ConfigDedicated-v1430 PUCCH-ConfigDedicated-v1430 OPTIONAL, -- Need ON + pdsch-ConfigDedicated-v1430 PDSCH-ConfigDedicated-v1430 OPTIONAL, -- Need ON + pusch-ConfigDedicated-v1430 PUSCH-ConfigDedicated-v1430 OPTIONAL, -- Need ON + soundingRS-UL-PeriodicConfigDedicatedList-r14 SEQUENCE (SIZE (1..2)) OF SoundingRS-UL-ConfigDedicated OPTIONAL, -- Cond PeriodicSRSPCell + soundingRS-UL-PeriodicConfigDedicatedUpPTsExtList-r14 SEQUENCE (SIZE (1..4)) OF SoundingRS-UL-ConfigDedicatedUpPTsExt-r13 OPTIONAL, -- Cond PeriodicSRSExt + soundingRS-UL-AperiodicConfigDedicatedList-r14 SEQUENCE (SIZE (1..2)) OF SoundingRS-UL-ConfigDedicatedAperiodic-r10 OPTIONAL, -- Cond AperiodicSRS + soundingRS-UL-ConfigDedicatedApUpPTsExtList-r14 SEQUENCE (SIZE (1..4)) OF SoundingRS-UL-ConfigDedicatedAperiodicUpPTsExt-r13 OPTIONAL, -- Cond AperiodicSRSExt + csi-RS-Config-v1430 CSI-RS-Config-v1430 OPTIONAL, -- Need ON + csi-RS-ConfigZP-ApList-r14 CSI-RS-ConfigZP-ApList-r14 OPTIONAL, -- Need ON + cqi-ReportConfig-v1430 CQI-ReportConfig-v1430 OPTIONAL, -- Need ON + semiOpenLoop-r14 BOOLEAN OPTIONAL -- Need ON ]] - } PhysicalConfigDedicatedSCell-r10 ::= SEQUENCE { @@ -4575,18 +5084,17 @@ PhysicalConfigDedicatedSCell-r10 ::= SEQUENCE { csi-RS-ConfigNZPToAddModListExt-r13 CSI-RS-ConfigNZPToAddModListExt-r13 OPTIONAL, -- Need ON csi-RS-ConfigNZPToReleaseListExt-r13 CSI-RS-ConfigNZPToReleaseListExt-r13 OPTIONAL -- Need ON ]], - [[ cqi-ReportConfig-v1320 CQI-ReportConfig-v1320 OPTIONAL -- Need ON + [[ cqi-ReportConfig-v1320 CQI-ReportConfig-v1320 OPTIONAL -- Need ON ]], - [[ laa-SCellConfiguration-v14xy LAA-SCellConfiguration-v14xy OPTIONAL, -- Need ON - typeB-SRS-TPC-PDCCH-Config-r14 SRS-TPC-PDCCH-Config-r14 OPTIONAL, -- Need ON + [[ laa-SCellConfiguration-v1430 LAA-SCellConfiguration-v1430 + OPTIONAL, -- Need ON + typeB-SRS-TPC-PDCCH-Config-r14 SRS-TPC-PDCCH-Config-r14 OPTIONAL, -- Need ON - uplinkPUSCH-LessPowerControlDedicated-v14xy UplinkPUSCH-LessPowerControlDedicated-v14xy OPTIONAL, -- Need ON + uplinkPUSCH-LessPowerControlDedicated-v1430 UplinkPUSCH-LessPowerControlDedicated-v1430 OPTIONAL, -- Need ON soundingRS-UL-PeriodicConfigDedicatedList-r14 SEQUENCE (SIZE (1..2)) OF SoundingRS-UL-ConfigDedicated OPTIONAL, -- Cond PeriodicSRS soundingRS-UL-PeriodicConfigDedicatedUpPTsExtList-r14 SEQUENCE (SIZE (1..4)) OF SoundingRS-UL-ConfigDedicatedUpPTsExt-r13 OPTIONAL, -- Cond PeriodicSRSExt - - soundingRS-UL-AperiodicConfigDedicatedList-r14 SEQUENCE (SIZE (1..2)) OF SoundingRSAperiodicGroup-r14 OPTIONAL, -- Cond AperiodicSRS - soundingRS-UL-AperiodicConfigDedicatedUpPTsExtList-r14 SEQUENCE (SIZE (1..4)) OF SoundingRSAperiodicGroupUpPTsExt-r14 OPTIONAL, -- Cond AperiodicSRSExt - + soundingRS-UL-AperiodicConfigDedicatedList-r14 SEQUENCE (SIZE (1..2)) OF SoundingRS-AperiodicSet-r14 OPTIONAL, -- Cond AperiodicSRS + soundingRS-UL-ConfigDedicatedApUpPTsExtList-r14 SEQUENCE (SIZE (1..4)) OF SoundingRS-AperiodicSetUpPTsExt-r14 OPTIONAL, -- Cond AperiodicSRSExt must-Config-r14 CHOICE{ release NULL, setup SEQUENCE { @@ -4595,7 +5103,13 @@ PhysicalConfigDedicatedSCell-r10 ::= SEQUENCE { dB-6, dB-4dot77, dB-3, dB-1dot77, dB0, dB1, dB2, dB3} OPTIONAL -- Need ON } - } OPTIONAL -- Need ON + } OPTIONAL, -- Need ON + pusch-ConfigDedicated-v1430 PUSCH-ConfigDedicatedSCell-v1430 OPTIONAL, -- Need ON + csi-RS-Config-v1430 CSI-RS-Config-v1430 OPTIONAL, -- Need ON + csi-RS-ConfigZP-ApList-r14 CSI-RS-ConfigZP-ApList-r14 OPTIONAL, -- Need ON + cqi-ReportConfig-v1430 CQI-ReportConfig-v1430 OPTIONAL, -- Need ON + semiOpenLoop-r14 BOOLEAN OPTIONAL, -- Need ON + pdsch-ConfigDedicatedSCell-v1430 PDSCH-ConfigDedicatedSCell-v1430 OPTIONAL -- Need ON ]] } @@ -4604,7 +5118,7 @@ LAA-SCellConfiguration-r13 ::= SEQUENCE { laa-SCellSubframeConfig-r13 BIT STRING (SIZE(8)) } -LAA-SCellConfiguration-v14xy ::= SEQUENCE { +LAA-SCellConfiguration-v1430 ::= SEQUENCE { crossCarrierSchedulingConfig-UL-r14 CHOICE { release NULL, setup SEQUENCE { @@ -4614,8 +5128,8 @@ LAA-SCellConfiguration-v14xy ::= SEQUENCE { lbt-Config-r14 LBT-Config-r14 OPTIONAL, -- Need ON pdcch-ConfigLAA-r14 PDCCH-ConfigLAA-r14 OPTIONAL, -- Need ON absenceOfAnyOtherTechnology-r14 ENUMERATED {true} OPTIONAL, -- Need OR - soundingRS-UL-ConfigDedicatedAperiodic-v14xy - SoundingRS-UL-ConfigDedicatedAperiodic-v14xy OPTIONAL -- Need ON + soundingRS-UL-ConfigDedicatedAperiodic-v1430 + SoundingRS-UL-ConfigDedicatedAperiodic-v1430 OPTIONAL -- Need ON } LBT-Config-r14 ::= CHOICE{ @@ -4635,14 +5149,20 @@ CSI-RS-ConfigZPToAddModList-r11 ::= SEQUENCE (SIZE (1..maxCSI-RS-ZP-r11)) OF CSI CSI-RS-ConfigZPToReleaseList-r11 ::= SEQUENCE (SIZE (1..maxCSI-RS-ZP-r11)) OF CSI-RS-ConfigZPId-r11 -SoundingRSAperiodicGroup-r14 ::= SEQUENCE{ - srsCcGroupIndexList SEQUENCE (SIZE (1..4)) OF SrsCcGroupIndex OPTIONAL, -- Cond Srs-Trigger-TypeA - soundingRS-UL-ConfigDedicatedAperiodic-r10 SoundingRS-UL-ConfigDedicatedAperiodic-r10 +SoundingRS-AperiodicSet-r14 ::= SEQUENCE{ + srs-CC-SetIndexList-r14 + SEQUENCE (SIZE (1..4)) OF SRS-CC-SetIndex-r14 + OPTIONAL, -- Cond SRS-Trigger-TypeA + soundingRS-UL-ConfigDedicatedAperiodic-r14 + SoundingRS-UL-ConfigDedicatedAperiodic-r10 } -SoundingRSAperiodicGroupUpPTsExt-r14 ::= SEQUENCE{ - srsCcGroupIndexList SEQUENCE (SIZE (1..4)) OF SrsCcGroupIndex OPTIONAL, -- Cond Srs-Trigger-TypeA - soundingRS-UL-ConfigDedicatedAperiodicUpPTsExt-r13 SoundingRS-UL-ConfigDedicatedAperiodicUpPTsExt-r13 +SoundingRS-AperiodicSetUpPTsExt-r14 ::= SEQUENCE{ + srs-CC-SetIndexList-r14 + SEQUENCE (SIZE (1..4)) OF SRS-CC-SetIndex-r14 + OPTIONAL, -- Cond SRS-Trigger-TypeA + soundingRS-UL-ConfigDedicatedAperiodicUpPTsExt-r14 + SoundingRS-UL-ConfigDedicatedAperiodicUpPTsExt-r13 } @@ -4682,9 +5202,11 @@ PRACH-Config-v1310 ::= SEQUENCE { initial-CE-level-r13 INTEGER (0..3) OPTIONAL -- Need OR } -PRACH-Config-v14xy ::= SEQUENCE { +PRACH-Config-v1430 ::= SEQUENCE { rootSequenceIndexHighSpeed-r14 INTEGER (0..837), - zeroCorrelationZoneConfigHighSpeed-r14 INTEGER (0..12) + zeroCorrelationZoneConfigHighSpeed-r14 INTEGER (0..12), + prach-ConfigIndexHighSpeed-r14 INTEGER (0..63), + prach-FreqOffsetHighSpeed-r14 INTEGER (0..94) } PRACH-ConfigSCell-r10 ::= SEQUENCE { @@ -4736,6 +5258,10 @@ PUCCH-ConfigCommon-v1310 ::= SEQUENCE { pucch-NumRepetitionCE-Msg4-Level3-r13 ENUMERATED {n4, n8, n16, n32} OPTIONAL -- Need OR } +PUCCH-ConfigCommon-v1430 ::= SEQUENCE { + pucch-NumRepetitionCE-Msg4-Level3-r14 ENUMERATED {n64, n128} OPTIONAL -- Need OR +} + PUCCH-ConfigDedicated ::= SEQUENCE { ackNackRepetition CHOICE{ release NULL, @@ -4875,6 +5401,10 @@ PUCCH-ConfigDedicated-r13 ::= SEQUENCE { } OPTIONAL --Need ON } +PUCCH-ConfigDedicated-v1430 ::= SEQUENCE { + pucch-NumRepetitionCE-format1-r14 ENUMERATED {r64,r128} OPTIONAL -- Need OR +} + Format4-resource-r13 ::= SEQUENCE { startingPRB-format4-r13 INTEGER (0..109), numberOfPRB-format4-r13 INTEGER (0..7) @@ -4976,7 +5506,7 @@ PUSCH-ConfigDedicated-r13 ::= SEQUENCE { nPUSCH-Identity-r13 INTEGER (0..509), nDMRS-CSH-Identity-r13 INTEGER (0..509) } - } OPTIONAL, -- Need ON + } OPTIONAL, -- Need ON uciOnPUSCH CHOICE { release NULL, setup SEQUENCE { @@ -4995,11 +5525,58 @@ PUSCH-ConfigDedicated-r13 ::= SEQUENCE { pusch-HoppingConfig-r13 ENUMERATED {on} OPTIONAL -- Need OR } +PUSCH-ConfigDedicated-v1430 ::= SEQUENCE { + ce-PUSCH-NB-MaxTBS-r14 ENUMERATED {on} OPTIONAL, -- Need OR + ce-PUSCH-MaxBandwidth-r14 ENUMERATED {bw5} OPTIONAL, -- Need OP + tdd-PUSCH-UpPTS-r14 TDD-PUSCH-UpPTS-r14 OPTIONAL, -- Need ON + ul-DMRS-IFDMA-r14 BOOLEAN, + enable256QAM-r14 Enable256QAM-r14 OPTIONAL -- Need ON +} + PUSCH-ConfigDedicatedSCell-r10 ::= SEQUENCE { groupHoppingDisabled-r10 ENUMERATED {true} OPTIONAL, -- Need OR dmrs-WithOCC-Activated-r10 ENUMERATED {true} OPTIONAL -- Need OR } +PUSCH-ConfigDedicatedSCell-v1430 ::= SEQUENCE { + enable256QAM-r14 Enable256QAM-r14 OPTIONAL -- Need OR +} + +TDD-PUSCH-UpPTS-r14 ::= CHOICE { + release NULL, + setup SEQUENCE { + symPUSCH-UpPTS-r14 ENUMERATED {sym1, sym2, sym3, sym4, sym5, sym6} OPTIONAL, -- Need ON + dmrs-LessUpPTS-Config-r14 ENUMERATED {true} OPTIONAL -- Need OR + } +} + +Enable256QAM-r14 ::= CHOICE { + release NULL, + setup CHOICE { + tpc-SubframeSet-Configured-r14 SEQUENCE { + subframeSet1-DCI-Format0-r14 BOOLEAN, + subframeSet1-DCI-Format4-r14 BOOLEAN, + subframeSet2-DCI-Format0-r14 BOOLEAN, + subframeSet2-DCI-Format4-r14 BOOLEAN + }, + tpc-SubframeSet-NotConfigured-r14 SEQUENCE { + dci-Format0-r14 BOOLEAN, + dci-Format4-r14 BOOLEAN + } + } +} + +PUSCH-EnhancementsConfig-r14 ::= CHOICE { + release NULL, + setup SEQUENCE { + pusch-HoppingOffsetPUSCH-Enh-r14 INTEGER (1..100) OPTIONAL, -- Need ON + interval-ULHoppingPUSCH-Enh-r14 CHOICE { + interval-FDD-PUSCH-Enh-r14 ENUMERATED {int1, int2, int4, int8}, + interval-TDD-PUSCH-Enh-r14 ENUMERATED {int1, int5, int10, int20} + } OPTIONAL -- Need ON + } +} + UL-ReferenceSignalsPUSCH ::= SEQUENCE { groupHoppingEnabled BOOLEAN, groupAssignmentPUSCH INTEGER (0..29), @@ -5123,7 +5700,8 @@ RadioResourceConfigCommonSIB ::= SEQUENCE { pucch-ConfigCommon-v1310 PUCCH-ConfigCommon-v1310 OPTIONAL -- Need OR ]], [[ highSpeedConfig-r14 HighSpeedConfig-r14 OPTIONAL, -- Need OR - prach-Config-v14xy PRACH-Config-v14xy OPTIONAL -- Need OR + prach-Config-v1430 PRACH-Config-v1430 OPTIONAL, -- Need OR + pucch-ConfigCommon-v1430 PUCCH-ConfigCommon-v1430 OPTIONAL -- Need OR ]] } @@ -5156,7 +5734,9 @@ RadioResourceConfigCommon ::= SEQUENCE { uplinkPowerControlCommon-v1310 UplinkPowerControlCommon-v1310 OPTIONAL -- Need ON ]], [[ highSpeedConfig-r14 HighSpeedConfig-r14 OPTIONAL, -- Need OR - prach-Config-v14xy PRACH-Config-v14xy OPTIONAL -- Need OR + prach-Config-v1430 PRACH-Config-v1430 OPTIONAL, -- Need OR + pucch-ConfigCommon-v1430 PUCCH-ConfigCommon-v1430 OPTIONAL, -- Need OR + tdd-Config-v1430 TDD-Config-v1430 OPTIONAL -- Cond TDD3 ]] } @@ -5219,7 +5799,7 @@ RadioResourceConfigCommonSCell-r10 ::= SEQUENCE { UplinkPowerControlCommonSCell-v1310 OPTIONAL -- Cond UL ]], [[ highSpeedConfigSCell-r14 HighSpeedConfigSCell-r14 OPTIONAL, -- Need OR - prach-Config-v14xy PRACH-Config-v14xy OPTIONAL, -- Cond UL + prach-Config-v1430 PRACH-Config-v1430 OPTIONAL, -- Cond UL ul-Configuration-r14 SEQUENCE { ul-FreqInfo-r14 SEQUENCE { ul-CarrierFreq-r14 ARFCN-ValueEUTRA-r9 OPTIONAL, -- Need OP @@ -5231,11 +5811,13 @@ RadioResourceConfigCommonSCell-r10 ::= SEQUENCE { soundingRS-UL-ConfigCommon-r14 SoundingRS-UL-ConfigCommon, ul-CyclicPrefixLength-r14 UL-CyclicPrefixLength, prach-ConfigSCell-r14 PRACH-ConfigSCell-r10 OPTIONAL, -- Cond TDD-OR-NoR11 - uplinkPowerControlCommonPUSCH-LessCell-v14xy UplinkPowerControlCommonPUSCH-LessCell-v14xy OPTIONAL -- Need OR + uplinkPowerControlCommonPUSCH-LessCell-v1430 UplinkPowerControlCommonPUSCH-LessCell-v1430 OPTIONAL -- Need OR } OPTIONAL, -- Cond ULSRS harq-ReferenceConfig-r14 ENUMERATED {sa2,sa4,sa5} OPTIONAL, -- Need OR soundingRS-FlexibleTiming-r14 ENUMERATED {true} OPTIONAL -- Need OR - ]] + ]], + [[ mbsfn-SubframeConfigList-v1430 MBSFN-SubframeConfigList-v1430 OPTIONAL-- Need ON + ]] } BCCH-Config ::= SEQUENCE { @@ -5316,6 +5898,8 @@ RadioResourceConfigDedicated ::= SEQUENCE { ]], [[ neighCellsCRS-Info-r13 NeighCellsCRS-Info-r13 OPTIONAL, -- Cond CRSIM rlf-TimersAndConstants-r13 RLF-TimersAndConstants-r13 OPTIONAL -- Need ON + ]], + [[ sps-Config-v1430 SPS-Config-v1430 OPTIONAL -- Cond SPS ]] } @@ -5326,6 +5910,8 @@ RadioResourceConfigDedicatedPSCell-r12 ::= SEQUENCE { naics-Info-r12 NAICS-AssistanceInfo-r12 OPTIONAL, -- Need ON ..., [[ neighCellsCRS-InfoPSCell-r13 NeighCellsCRS-Info-r13 OPTIONAL -- Need ON + ]], + [[ sps-Config-v1430 SPS-Config-v1430 OPTIONAL -- Cond SPS2 ]] } @@ -5346,7 +5932,6 @@ RadioResourceConfigDedicatedSCell-r10 ::= SEQUENCE { ]], [[ neighCellsCRS-InfoSCell-r13 NeighCellsCRS-Info-r13 OPTIONAL -- Need ON ]] - } SRB-ToAddModList ::= SEQUENCE (SIZE (1..2)) OF SRB-ToAddMod @@ -5384,9 +5969,10 @@ DRB-ToAddMod ::= SEQUENCE { drb-TypeLWIP-r13 ENUMERATED {lwip, lwip-DL-only, lwip-UL-only, eutran} OPTIONAL -- Need ON ]], - [[ rlc-Config-v14xy RLC-Config-v14xy OPTIONAL, -- Need ON + [[ rlc-Config-v1430 RLC-Config-v1430 OPTIONAL, -- Need ON lwip-UL-Aggregation-r14 BOOLEAN OPTIONAL, -- Cond LWIP - lwip-DL-Aggregation-r14 BOOLEAN OPTIONAL -- Cond LWIP + lwip-DL-Aggregation-r14 BOOLEAN OPTIONAL, -- Cond LWIP + lwa-WLAN-AC-r14 ENUMERATED {ac-bk, ac-be, ac-vi, ac-vo} OPTIONAL -- Cond UL-LWA ]] } @@ -5404,7 +5990,7 @@ DRB-ToAddModSCG-r12 ::= SEQUENCE { logicalChannelIdentitySCG-r12 INTEGER (3..10) OPTIONAL, -- Cond DRB-SetupS logicalChannelConfigSCG-r12 LogicalChannelConfig OPTIONAL, -- Cond SetupS ..., - [[ rlc-Config-v14xy RLC-Config-v14xy OPTIONAL -- Need ON + [[ rlc-Config-v1430 RLC-Config-v1430 OPTIONAL -- Need ON ]] } @@ -5426,7 +6012,9 @@ CRS-AssistanceInfo-r11 ::= SEQUENCE { physCellId-r11 PhysCellId, antennaPortsCount-r11 ENUMERATED {an1, an2, an4, spare1}, mbsfn-SubframeConfigList-r11 MBSFN-SubframeConfigList, - ... + ..., + [[ mbsfn-SubframeConfigList-v1430 MBSFN-SubframeConfigList-v1430 OPTIONAL -- Need ON + ]] } NeighCellsCRS-Info-r13 ::= CHOICE { @@ -5439,8 +6027,10 @@ CRS-AssistanceInfoList-r13 ::= SEQUENCE (SIZE (1..maxCellReport)) OF CRS-Assist CRS-AssistanceInfo-r13 ::= SEQUENCE { physCellId-r13 PhysCellId, antennaPortsCount-r13 ENUMERATED {an1, an2, an4, spare1}, - mbsfn-SubframeConfigList-r13 MBSFN-SubframeConfigList OPTIONAL, -- Need ON - ... + mbsfn-SubframeConfigList-r13 MBSFN-SubframeConfigList OPTIONAL, -- Need ON + ..., + [[ mbsfn-SubframeConfigList-v1430 MBSFN-SubframeConfigList-v1430 OPTIONAL -- Need ON + ]] } NAICS-AssistanceInfo-r12 ::= CHOICE { @@ -5517,7 +6107,7 @@ RLC-Config-v1310 ::= SEQUENCE { pollPDU-v1310 PollPDU-v1310 OPTIONAL -- Need OR } -RLC-Config-v14xy ::= CHOICE { +RLC-Config-v1430 ::= CHOICE { release NULL, setup SEQUENCE { pollByte-r14 PollByte-r14 @@ -5826,7 +6416,7 @@ SoundingRS-UL-ConfigDedicatedAperiodicUpPTsExt-r13 ::= CHOICE{ } } -SoundingRS-UL-ConfigDedicatedAperiodic-v14xy ::= CHOICE{ +SoundingRS-UL-ConfigDedicatedAperiodic-v1430 ::= CHOICE{ release NULL, setup SEQUENCE { srs-SubframeIndication-r14 INTEGER (1..4) OPTIONAL -- Need ON @@ -5866,6 +6456,23 @@ SPS-Config ::= SEQUENCE { sps-ConfigUL SPS-ConfigUL OPTIONAL -- Need ON } +SPS-Config-v1430 ::= SEQUENCE { + ul-SPS-V-RNTI-r14 C-RNTI OPTIONAL, -- Need OR + sl-SPS-V-RNTI-r14 C-RNTI OPTIONAL, -- Need OR + sps-ConfigUL-ToAddModList-r14 SPS-ConfigUL-ToAddModList-r14 OPTIONAL, -- Need ON + sps-ConfigUL-ToReleaseList-r14 SPS-ConfigUL-ToReleaseList-r14 OPTIONAL, -- Need ON + sps-ConfigSL-ToAddModList-r14 SPS-ConfigSL-ToAddModList-r14 OPTIONAL, -- Need ON + sps-ConfigSL-ToReleaseList-r14 SPS-ConfigSL-ToReleaseList-r14 OPTIONAL -- Need ON +} + +SPS-ConfigUL-ToAddModList-r14 ::= SEQUENCE (SIZE (1..maxConfigSPS-r14)) OF SPS-ConfigUL + +SPS-ConfigUL-ToReleaseList-r14 ::= SEQUENCE (SIZE (1..maxConfigSPS-r14)) OF SPS-ConfigIndex-r14 + +SPS-ConfigSL-ToAddModList-r14 ::= SEQUENCE (SIZE (1..maxConfigSPS-r14)) OF SPS-ConfigSL-r14 + +SPS-ConfigSL-ToReleaseList-r14 ::= SEQUENCE (SIZE (1..maxConfigSPS-r14)) OF SPS-ConfigIndex-r14 + SPS-ConfigDL ::= CHOICE{ release NULL, setup SEQUENCE { @@ -5892,8 +6499,8 @@ SPS-ConfigUL ::= CHOICE { setup SEQUENCE { semiPersistSchedIntervalUL ENUMERATED { sf10, sf20, sf32, sf40, sf64, sf80, - sf128, sf160, sf320, sf640, sf1-v14xy, - sf2-v14xy, sf3-v14xy, sf4-v14xy, sf5-v14xy, + sf128, sf160, sf320, sf640, sf1-v1430, + sf2-v1430, sf3-v1430, sf4-v1430, sf5-v1430, spare1}, implicitReleaseAfter ENUMERATED {e2, e3, e4, e8}, p0-Persistent SEQUENCE { @@ -5912,11 +6519,27 @@ SPS-ConfigUL ::= CHOICE { ]], [[ numberOfConfUlSPS-Processes-r13 INTEGER (1..8) OPTIONAL -- Need OR ]], - [[ fixedRV-NonAdaptive-r14 ENUMERATED {true} OPTIONAL -- Need OR + [[ fixedRV-NonAdaptive-r14 ENUMERATED {true} OPTIONAL, -- Need OR + sps-ConfigIndex-r14 SPS-ConfigIndex-r14 OPTIONAL, -- Need OR + semiPersistSchedIntervalUL-v1430 ENUMERATED { + sf50, sf100, sf200, sf300, sf400, sf500, + sf600, sf700, sf800, sf900, sf1000, spare5, + spare4, spare3, spare2, spare1} OPTIONAL -- Need OR + ]] } } +SPS-ConfigSL-r14 ::= SEQUENCE { + sps-ConfigIndex-r14 SPS-ConfigIndex-r14, + semiPersistSchedIntervalSL-r14 ENUMERATED { + sf20, sf50, sf100, sf200, sf300, sf400, + sf500, sf600, sf700, sf800, sf900, sf1000, + spare4, spare3, spare2, spare1} +} + +SPS-ConfigIndex-r14 ::= INTEGER (1..maxConfigSPS-r14) + N1PUCCH-AN-PersistentList ::= SEQUENCE (SIZE (1..4)) OF INTEGER (0..2047) @@ -5925,12 +6548,16 @@ SRS-TPC-PDCCH-Config-r14 ::= CHOICE { setup SEQUENCE { srs-TPC-RNTI-r14 BIT STRING (SIZE (16)), startingBitOfFormat3B-r14 INTEGER (0..31), fieldTypeFormat3B-r14 INTEGER (1..4), - srsCcGroupIndexlist SEQUENCE (SIZE(1..4)) OF SrsCcGroupIndex OPTIONAL -- Cond Srs-Trigger-TypeA + srs-CC-SetIndexlist-r14 SEQUENCE (SIZE(1..4)) OF SRS-CC-SetIndex-r14 OPTIONAL -- Cond SRS-Trigger-TypeA } } -SrsCcGroupIndex ::= INTEGER (0..3) +SRS-CC-SetIndex-r14 ::= SEQUENCE { + cc-SetIndex-r14 INTEGER (0..3), + cc-IndexInOneCC-Set-r14 INTEGER (0..7) +} + TDD-Config ::= SEQUENCE { subframeAssignment ENUMERATED { @@ -5944,6 +6571,10 @@ TDD-Config-v1130 ::= SEQUENCE { specialSubframePatterns-v1130 ENUMERATED {ssp7,ssp9} } +TDD-Config-v1430 ::= SEQUENCE { + specialSubframePatterns-v1430 ENUMERATED {ssp10} +} + TDD-ConfigSL-r12 ::= SEQUENCE { subframeAssignmentSL-r12 ENUMERATED { none, sa0, sa1, sa2, sa3, sa4, sa5, sa6} @@ -6049,9 +6680,9 @@ UplinkPowerControlCommonSCell-v1310 ::= SEQUENCE { deltaF10, deltaF9, deltaF8, deltaF7, spare1} OPTIONAL -- Need OR } -UplinkPowerControlCommonPUSCH-LessCell-v14xy ::= SEQUENCE { - p0-Nominal-PeriodicSRS INTEGER (-126..24) OPTIONAL, -- Need OR - p0-Nominal-AperiodicSRS INTEGER (-126..24) OPTIONAL, -- Need OR +UplinkPowerControlCommonPUSCH-LessCell-v1430 ::= SEQUENCE { + p0-Nominal-PeriodicSRS-r14 INTEGER (-126..24) OPTIONAL, -- Need OR + p0-Nominal-AperiodicSRS-r14 INTEGER (-126..24) OPTIONAL, -- Need OR alpha-SRS-r14 Alpha-r12 OPTIONAL -- Need OR } @@ -6087,10 +6718,10 @@ UplinkPowerControlDedicated-v1250 ::= SEQUENCE { } } -UplinkPUSCH-LessPowerControlDedicated-v14xy ::= SEQUENCE { - p0-UE-PeriodicSRS INTEGER (-8..7) OPTIONAL, -- Need OR - p0-UE-AperiodicSRS INTEGER (-8..7) OPTIONAL, -- Need OR - accumulationEnabled BOOLEAN +UplinkPUSCH-LessPowerControlDedicated-v1430 ::= SEQUENCE { + p0-UE-PeriodicSRS-r14 INTEGER (-8..7) OPTIONAL, -- Need OR + p0-UE-AperiodicSRS-r14 INTEGER (-8..7) OPTIONAL, -- Need OR + accumulationEnabled-r14 BOOLEAN } UplinkPowerControlDedicatedSCell-r10 ::= SEQUENCE { @@ -6143,7 +6774,9 @@ WLAN-MobilityConfig-r13 ::= SEQUENCE { associationTimer-r13 ENUMERATED {s10, s30, s60, s120, s240} OPTIONAL, -- Need OR successReportRequested-r13 ENUMERATED {true} OPTIONAL, -- Need OR - ... + ..., + [[ wlan-SuspendConfig-r14 WLAN-SuspendConfig-r14 OPTIONAL -- Need ON + ]] } @@ -6246,6 +6879,15 @@ CellSelectionInfoCE-r13 ::= SEQUENCE { } +CellSelectionInfoCE1-r13 ::= SEQUENCE { + q-RxLevMinCE1-r13 Q-RxLevMin, + q-QualMinRSRQ-CE1-r13 Q-QualMin-r9 OPTIONAL -- Need OR +} + +CellSelectionInfoCE1-v1360 ::= SEQUENCE { + delta-RxLevMinCE1-v1360 INTEGER (-8..-1) +} + CellReselectionSubPriority-r13 ::= ENUMERATED {oDot2, oDot4, oDot6, oDot8} @@ -6334,7 +6976,11 @@ MobilityControlInfo ::= SEQUENCE { ]], [[ drb-ContinueROHC-r11 ENUMERATED {true} OPTIONAL -- Cond HO ]], - [[ mobilityControlInfoV2X-r14 MobilityControlInfoV2X-r14 OPTIONAL -- Need OR + [[ mobilityControlInfoV2X-r14 MobilityControlInfoV2X-r14 OPTIONAL, -- Need ON + handoverWithoutWT-Change-r14 ENUMERATED {keepLWA-Config, sendEndMarker} OPTIONAL, -- Cond HO + makeBeforeBreak-r14 ENUMERATED {true} OPTIONAL, -- Need OR + rach-Skip-r14 RACH-Skip-r14 OPTIONAL, -- Need OR + sameSFN-Indication-r14 ENUMERATED {true} OPTIONAL -- Cond HO-SFNsynced ]] } @@ -6345,13 +6991,17 @@ MobilityControlInfoSCG-r12 ::= SEQUENCE { ue-IdentitySCG-r12 C-RNTI OPTIONAL, -- Cond SCGEst, rach-ConfigDedicated-r12 RACH-ConfigDedicated OPTIONAL, -- Need OP cipheringAlgorithmSCG-r12 CipheringAlgorithm-r12 OPTIONAL, -- Need ON - ... + ..., + [[ makeBeforeBreakSCG-r14 ENUMERATED {true} OPTIONAL, -- Need OR + rach-SkipSCG-r14 RACH-Skip-r14 OPTIONAL -- Need OR + ]] } MobilityControlInfoV2X-r14 ::= SEQUENCE { v2x-CommTxPoolExceptional-r14 SL-CommResourcePoolV2X-r14 OPTIONAL, -- Need OR v2x-CommRxPool-r14 SL-CommRxPoolListV2X-r14 OPTIONAL, -- Need OR - v2x-CommSyncConfig-r14 SL-SyncConfigListV2X-r14 OPTIONAL -- Need OR + v2x-CommSyncConfig-r14 SL-SyncConfigListV2X-r14 OPTIONAL, -- Need OR + cbr-MobilityTxConfigList-r14 SL-CBR-CommonTxConfigList-r14 OPTIONAL -- Need OR } CarrierBandwidthEUTRA ::= SEQUENCE { @@ -6375,6 +7025,22 @@ CarrierFreqEUTRA-v9e0 ::= SEQUENCE { ul-CarrierFreq-v9e0 ARFCN-ValueEUTRA-r9 OPTIONAL -- Cond FDD } +RACH-Skip-r14 ::= SEQUENCE { + targetTA-r14 CHOICE { + ta0-r14 NULL, + ptag-r14 NULL, + pstag-r14 NULL, + mcg-STAG-r14 STAG-Id-r11, + scg-STAG-r14 STAG-Id-r11 + }, + ul-ConfigInfo-r14 SEQUENCE { + numberOfConfUL-Processes-r14 INTEGER (1..8), + ul-SchedInterval-r14 ENUMERATED {sf2, sf5, sf10}, + ul-StartSubframe-r14 INTEGER (0..9), + ul-Grant-r14 BIT STRING (SIZE (16)) + } OPTIONAL -- Need OR +} + MobilityParametersCDMA2000 ::= OCTET STRING @@ -6599,7 +7265,10 @@ MeasConfig ::= SEQUENCE { measObjectToRemoveListExt-r13 MeasObjectToRemoveListExt-r13 OPTIONAL, -- Need ON measObjectToAddModListExt-r13 MeasObjectToAddModListExt-r13 OPTIONAL, -- Need ON measIdToAddModList-v1310 MeasIdToAddModList-v1310 OPTIONAL, -- Need ON - measIdToAddModListExt-v1310 MeasIdToAddModListExt-v1310 OPTIONAL -- Need ON + measIdToAddModListExt-v1310 MeasIdToAddModListExt-v1310 OPTIONAL -- Need ON + ]], + [[ measGapConfigPerCC-List-r14 MeasGapConfigPerCC-List-r14 OPTIONAL, -- Need ON + measGapSharingConfig-r14 MeasGapSharingConfig-r14 OPTIONAL -- Need ON ]] } @@ -6656,12 +7325,50 @@ MeasGapConfig ::= CHOICE { gapOffset CHOICE { gp0 INTEGER (0..39), gp1 INTEGER (0..79), - ... + + ..., + gp2-r14 INTEGER (0..39), + gp3-r14 INTEGER (0..79), + gp-ncsg1-r14 INTEGER (0..39), + gp-ncsg2-r14 INTEGER (0..79), + gp-ncsg3-r14 INTEGER (0..39), + gp-ncsg4-r14 INTEGER (0..79), + gp-nonUniform1-r14 INTEGER (0..1279), + gp-nonUniform2-r14 INTEGER (0..2559), + gp-nonUniform3-r14 INTEGER (0..5119), + gp-nonUniform4-r14 INTEGER (0..10239) } } } + +MeasGapConfigPerCC-List-r14 ::= CHOICE { + release NULL, + setup SEQUENCE { + measGapConfigToRemoveList-r14 MeasGapConfigToRemoveList-r14 OPTIONAL, -- Need ON + measGapConfigToAddModList-r14 MeasGapConfigToAddModList-r14 OPTIONAL -- Need ON + } +} + +MeasGapConfigToRemoveList-r14 ::= SEQUENCE (SIZE (1..maxServCell-r13)) OF ServCellIndex-r13 + +MeasGapConfigToAddModList-r14 ::= SEQUENCE (SIZE (1..maxServCell-r13)) OF MeasGapConfigPerCC-r14 + +MeasGapConfigPerCC-r14 ::= SEQUENCE { + servCellId-r14 ServCellIndex-r13, + measGapConfigCC-r14 MeasGapConfig +} + + +MeasGapSharingConfig-r14 ::= CHOICE { + release NULL, + setup SEQUENCE { + measGapSharingScheme-r14 ENUMERATED {scheme00, scheme01, scheme10, scheme11} + } +} + + MeasId ::= INTEGER (1..maxMeasId) MeasId-v1250 ::= INTEGER (maxMeasId-Plus1..maxMeasId-r12) @@ -6745,6 +7452,11 @@ MeasObjectEUTRA ::= SEQUENCE { whiteCellsToAddModList-r13 WhiteCellsToAddModList-r13 OPTIONAL, -- Need ON rmtc-Config-r13 RMTC-Config-r13 OPTIONAL, -- Need ON carrierFreq-r13 ARFCN-ValueEUTRA-v9e0 OPTIONAL -- Need ON + ]], + [[ + tx-ResourcePoolToRemoveList-r14 Tx-ResourcePoolMeasList-r14 OPTIONAL, -- Need ON + tx-ResourcePoolToAddList-r14 Tx-ResourcePoolMeasList-r14 OPTIONAL, -- Need ON + fembms-MixedCarrier-r14 BOOLEAN OPTIONAL -- Need ON ]] } @@ -6804,6 +7516,8 @@ RMTC-Config-r13 ::= CHOICE { } } +Tx-ResourcePoolMeasList-r14 ::= SEQUENCE (SIZE (1..maxSL-PoolToMeasure-r14)) OF SL-V2X-TxPoolReportIdentity-r14 + MeasObjectGERAN ::= SEQUENCE { carrierFreqs CarrierFreqsGERAN, @@ -6903,7 +7617,7 @@ MeasObjectWLAN-r13 ::= SEQUENCE { ... } -WLAN-BandIndicator-r13 ::= ENUMERATED {band2dot4, band5, spare6, spare5, spare4, spare3, spare2, spare1, ...} +WLAN-BandIndicator-r13 ::= ENUMERATED {band2dot4, band5, band60-v1430, spare5, spare4, spare3, spare2, spare1, ...} MeasResults ::= SEQUENCE { @@ -6937,8 +7651,12 @@ MeasResults ::= SEQUENCE { } OPTIONAL, ul-PDCP-DelayResultList-r13 UL-PDCP-DelayResultList-r13 OPTIONAL, measResultListWLAN-r13 MeasResultListWLAN-r13 OPTIONAL + ]], + [[ measResultPCell-v1360 RSRP-Range-v1360 OPTIONAL + ]], + [[ measResultListCBR-r14 MeasResultListCBR-r14 OPTIONAL, + measResultListWLAN-r14 MeasResultListWLAN-r14 OPTIONAL ]] - } MeasResultListEUTRA ::= SEQUENCE (SIZE (1..maxCellReport)) OF MeasResultEUTRA @@ -6965,6 +7683,9 @@ MeasResultEUTRA ::= SEQUENCE { multiBandInfoList-r13 MultiBandInfoList-r11 OPTIONAL, freqBandIndicatorPriority-r13 ENUMERATED {true} OPTIONAL } OPTIONAL + ]], + [[ + measResult-v1360 RSRP-Range-v1360 OPTIONAL ]] } } @@ -7010,7 +7731,11 @@ MeasResultServFreq-r13 ::= SEQUENCE { rsrqResultNCell-r13 RSRQ-Range-r13, rs-sinr-Result-r13 RS-SINR-Range-r13 OPTIONAL } OPTIONAL, - ... + ..., + [[ measResultBestNeighCell-v1360 SEQUENCE { + rsrpResultNCell-v1360 RSRP-Range-v1360 + } OPTIONAL + ]] } MeasResultCSI-RS-List-r12 ::= SEQUENCE (SIZE (1..maxCellReport)) OF MeasResultCSI-RS-r12 @@ -7079,6 +7804,8 @@ MeasResultCDMA2000 ::= SEQUENCE { MeasResultListWLAN-r13 ::= SEQUENCE (SIZE (1..maxCellReport)) OF MeasResultWLAN-r13 +MeasResultListWLAN-r14 ::= SEQUENCE (SIZE (1..maxWLAN-Id-Report-r14)) OF MeasResultWLAN-r13 + MeasResultWLAN-r13 ::= SEQUENCE { wlan-Identifiers-r13 WLAN-Identifiers-r12, carrierInfoWLAN-r13 WLAN-CarrierInfo-r13 OPTIONAL, @@ -7093,6 +7820,14 @@ MeasResultWLAN-r13 ::= SEQUENCE { ... } +MeasResultListCBR-r14 ::= SEQUENCE (SIZE (1..maxCBR-Report-r14)) OF MeasResultCBR-r14 + +MeasResultCBR-r14 ::= SEQUENCE { + poolIdentity-r14 SL-V2X-TxPoolReportIdentity-r14, + cbr-PSSCH-r14 SL-CBR-r14, + cbr-PSCCH-r14 SL-CBR-r14 OPTIONAL +} + MeasResultForECID-r9 ::= SEQUENCE { ue-RxTxTimeDiffResult-r9 INTEGER (0..4095), currentSFN-r9 BIT STRING (SIZE (10)) @@ -7217,6 +7952,12 @@ ReportConfigEUTRA ::= SEQUENCE { c2-RefCSI-RS-r12 MeasCSI-RS-Id-r12, c2-Offset-r12 INTEGER (-30..30), c2-ReportOnLeave-r12 BOOLEAN + }, + eventV1-r14 SEQUENCE { + v1-Threshold-r14 SL-CBR-r14 + }, + eventV2-r14 SEQUENCE { + v2-Threshold-r14 SL-CBR-r14 } }, hysteresis Hysteresis, @@ -7267,6 +8008,10 @@ ReportConfigEUTRA ::= SEQUENCE { ul-DelayConfig-r13 UL-DelayConfig-r13 OPTIONAL -- Need ON ]], [[ ue-RxTxTimeDiffPeriodicalTDD-r13 BOOLEAN OPTIONAL -- Need ON + ]], + [[ + purpose-v1430 ENUMERATED {reportLocation, sidelink, spare2, spare1} + OPTIONAL -- Need ON ]] } @@ -7347,6 +8092,8 @@ ReportConfigInterRAT ::= SEQUENCE { } OPTIONAL -- Need ON ]], [[ reportQuantityWLAN-r13 ReportQuantityWLAN-r13 OPTIONAL -- Need ON + ]], + [[ reportAnyWLAN-r14 BOOLEAN OPTIONAL -- Need ON ]] } @@ -7362,11 +8109,11 @@ ThresholdCDMA2000 ::= INTEGER (0..63) ReportQuantityWLAN-r13 ::= SEQUENCE { bandRequestWLAN-r13 ENUMERATED {true} OPTIONAL, -- Need OR carrierInfoRequestWLAN-r13 ENUMERATED {true} OPTIONAL, -- Need OR - availableAdmissionCapacityRequestWLAN-r13 ENUMERATED {true} OPTIONAL, -- Need ON + availableAdmissionCapacityRequestWLAN-r13 ENUMERATED {true} OPTIONAL, -- Need OR backhaulDL-BandwidthRequestWLAN-r13 ENUMERATED {true} OPTIONAL, -- Need OR backhaulUL-BandwidthRequestWLAN-r13 ENUMERATED {true} OPTIONAL, -- Need OR channelUtilizationRequestWLAN-r13 ENUMERATED {true} OPTIONAL, -- Need OR - stationCountRequestWLAN-r13 ENUMERATED {true} OPTIONAL , -- Need OR + stationCountRequestWLAN-r13 ENUMERATED {true} OPTIONAL, -- Need OR ... } @@ -7390,6 +8137,8 @@ ReportInterval ::= ENUMERATED { RSRP-Range ::= INTEGER(0..97) +RSRP-Range-v1360 ::= INTEGER(-17..-1) + RSRP-RangeSL-r12 ::= INTEGER(0..13) RSRP-RangeSL2-r12 ::= INTEGER(0..7) @@ -7451,6 +8200,14 @@ WLAN-RSSI-Range-r13 ::= INTEGER(0..141) WLAN-Status-r13 ::= ENUMERATED {successfulAssociation, failureWlanRadioLink, failureWlanUnavailable, failureTimeout} +WLAN-Status-v1430 ::= ENUMERATED {suspended, resumed} + + +WLAN-SuspendConfig-r14 ::= SEQUENCE { + wlan-SuspendResumeAllowed-r14 BOOLEAN OPTIONAL, -- Need ON + wlan-SuspendTriggersStatusReport-r14 BOOLEAN OPTIONAL -- Need ON +} + AbsoluteTimeInfo-r10 ::= BIT STRING (SIZE (48)) @@ -7473,6 +8230,17 @@ TrackingAreaCodeList-v1130 ::= SEQUENCE { } +BandCombinationList-r14 ::= SEQUENCE (SIZE (1..maxBandComb-r13)) OF BandCombination-r14 + +BandCombination-r14 ::= SEQUENCE (SIZE (1..maxSimultaneousBands-r10)) OF BandIndication-r14 + +BandIndication-r14 ::= SEQUENCE { + bandEUTRA-r14 FreqBandIndicator-r11, + ca-BandwidthClassDL-r14 CA-BandwidthClass-r10, + ca-BandwidthClassUL-r14 CA-BandwidthClass-r10 OPTIONAL +} + + C-RNTI ::= BIT STRING (SIZE (16)) @@ -7521,11 +8289,32 @@ OtherConfig-r9 ::= SEQUENCE { [[ idc-Config-r11 IDC-Config-r11 OPTIONAL, -- Need ON powerPrefIndicationConfig-r11 PowerPrefIndicationConfig-r11 OPTIONAL, -- Need ON obtainLocationConfig-r11 ObtainLocationConfig-r11 OPTIONAL -- Need ON + ]], + [[ powerPrefIndicationTimer-r11 ENUMERATED {s0, s0dot5, s1, s2, s5, s10, s20, + s30, s60, s90, s120, s300, s600, spare3, + spare2, spare1} OPTIONAL, -- Need OR + sps-AssistanceInfoReport-r14 BOOLEAN OPTIONAL, -- Need ON + delayBudgetReportingConfig-r14 CHOICE{ + release NULL, + setup SEQUENCE{ + delayBudgetReportingProhibitTimer-r14 ENUMERATED { + s0, s0dot4, s0dot8, + s1dot6, s3, s6, s12, s30} + } + } OPTIONAL, -- Need ON + rlm-ReportConfig-r14 CHOICE { + release NULL, + setup SEQUENCE{ + rlmReportTimer-r14 ENUMERATED {s0, s0dot5, s1, s2, s5, s10, s20, s30, + s60, s90, s120, s300, s600, spare3, spare2, spare1}, + rlmReportRep-MPDCCH-r14 ENUMERATED {setup} OPTIONAL -- Need OR + } + } OPTIONAL -- Need ON ]] } IDC-Config-r11 ::= SEQUENCE { - idc-Indication-r11 ENUMERATED {setup} OPTIONAL, -- Need OR + idc-Indication-r11 ENUMERATED {setup} OPTIONAL, -- Need OR autonomousDenialParameters-r11 SEQUENCE { autonomousDenialSubframes-r11 ENUMERATED {n2, n5, n10, n15, n20, n30, spare2, spare1}, @@ -7534,12 +8323,14 @@ IDC-Config-r11 ::= SEQUENCE { spare4, spare3, spare2, spare1} } OPTIONAL, -- Need OR ..., - [[ idc-Indication-UL-CA-r11 ENUMERATED {setup} OPTIONAL -- Cond idc-Ind + [[ idc-Indication-UL-CA-r11 ENUMERATED {setup} OPTIONAL -- Cond idc-Ind + ]], + [[ idc-HardwareSharingIndication-r13 ENUMERATED {setup} OPTIONAL -- Need OR ]] } ObtainLocationConfig-r11 ::= SEQUENCE { - obtainLocation-r11 ENUMERATED {setup} OPTIONAL -- Need OR + obtainLocation-r11 ENUMERATED {setup} OPTIONAL -- Need OR } PowerPrefIndicationConfig-r11 ::= CHOICE{ @@ -7552,8 +8343,8 @@ PowerPrefIndicationConfig-r11 ::= CHOICE{ } ReportProximityConfig-r9 ::= SEQUENCE { - proximityIndicationEUTRA-r9 ENUMERATED {enabled} OPTIONAL, -- Need OR - proximityIndicationUTRA-r9 ENUMERATED {enabled} OPTIONAL -- Need OR + proximityIndicationEUTRA-r9 ENUMERATED {enabled} OPTIONAL, -- Need OR + proximityIndicationUTRA-r9 ENUMERATED {enabled} OPTIONAL -- Need OR } @@ -7830,14 +8621,44 @@ UE-EUTRA-Capability-v1330-IEs ::= SEQUENCE { UE-EUTRA-Capability-v1340-IEs ::= SEQUENCE { ue-CategoryUL-v1340 INTEGER (15) OPTIONAL, - nonCriticalExtension UE-EUTRA-Capability-v14xy-IEs OPTIONAL + nonCriticalExtension UE-EUTRA-Capability-v1350-IEs OPTIONAL } -UE-EUTRA-Capability-v14xy-IEs ::= SEQUENCE { - mac-Parameters-v14xy MAC-Parameters-v14xy OPTIONAL, - rlc-Parameters-v14xy RLC-Parameters-v14xy, - laa-Parameters-v14xy LAA-Parameters-v14xy OPTIONAL, - lwip-Parameters-v14xy LWIP-Parameters-v14xy OPTIONAL, +UE-EUTRA-Capability-v1350-IEs ::= SEQUENCE { + ue-CategoryDL-v1350 ENUMERATED {oneBis} OPTIONAL, + ue-CategoryUL-v1350 ENUMERATED {oneBis} OPTIONAL, + ce-Parameters-v1350 CE-Parameters-v1350, + nonCriticalExtension UE-EUTRA-Capability-v1360-IEs OPTIONAL +} + +UE-EUTRA-Capability-v1360-IEs ::= SEQUENCE { + other-Parameters-v1360 Other-Parameters-v1360 OPTIONAL, + nonCriticalExtension UE-EUTRA-Capability-v1430-IEs OPTIONAL +} + +UE-EUTRA-Capability-v1430-IEs ::= SEQUENCE { + phyLayerParameters-v1430 PhyLayerParameters-v1430, + ue-CategoryDL-v1430 ENUMERATED {m2} OPTIONAL, + ue-CategoryUL-v1430 ENUMERATED {n16, n17, n18, n19, n20, m2} OPTIONAL, + ue-CategoryUL-v1430b ENUMERATED {n21} OPTIONAL, + mac-Parameters-v1430 MAC-Parameters-v1430 OPTIONAL, + measParameters-v1430 MeasParameters-v1430 OPTIONAL, + pdcp-Parameters-v1430 PDCP-Parameters-v1430 OPTIONAL, + rlc-Parameters-v1430 RLC-Parameters-v1430, + rf-Parameters-v1430 RF-Parameters-v1430 OPTIONAL, + laa-Parameters-v1430 LAA-Parameters-v1430 OPTIONAL, + lwa-Parameters-v1430 LWA-Parameters-v1430 OPTIONAL, + lwip-Parameters-v1430 LWIP-Parameters-v1430 OPTIONAL, + otherParameters-v1430 Other-Parameters-v1430, + mmtel-Parameters-r14 MMTEL-Parameters-r14 OPTIONAL, + mobilityParameters-r14 MobilityParameters-r14 OPTIONAL, + ce-Parameters-v1430 CE-Parameters-v1430, + fdd-Add-UE-EUTRA-Capabilities-v1430 UE-EUTRA-CapabilityAddXDD-Mode-v1430 OPTIONAL, + tdd-Add-UE-EUTRA-Capabilities-v1430 UE-EUTRA-CapabilityAddXDD-Mode-v1430 OPTIONAL, + mbms-Parameters-v1430 MBMS-Parameters-v1430 OPTIONAL, + sl-Parameters-v1430 SL-Parameters-v1430 OPTIONAL, + ue-BasedNetwPerfMeasParameters-v1430 UE-BasedNetwPerfMeasParameters-v1430 OPTIONAL, + highSpeedEnhParameters-r14 HighSpeedEnhParameters-r14 OPTIONAL, nonCriticalExtension SEQUENCE {} OPTIONAL } @@ -7887,9 +8708,19 @@ UE-EUTRA-CapabilityAddXDD-Mode-v1320 ::= SEQUENCE { scptm-Parameters-r13 SCPTM-Parameters-r13 OPTIONAL } +UE-EUTRA-CapabilityAddXDD-Mode-v1430 ::= SEQUENCE { + phyLayerParameters-v1430 PhyLayerParameters-v1430 OPTIONAL, + mmtel-Parameters-r14 MMTEL-Parameters-r14 OPTIONAL +} + AccessStratumRelease ::= ENUMERATED { rel8, rel9, rel10, rel11, rel12, rel13, - spare2, spare1, ...} + rel14, spare1, ...} + +MobilityParameters-r14 ::= SEQUENCE { + makeBeforeBreak-r14 ENUMERATED {supported} OPTIONAL, + rach-Less-r14 ENUMERATED {supported} OPTIONAL +} DC-Parameters-r12 ::= SEQUENCE { drb-TypeSplit-r12 ENUMERATED {supported} OPTIONAL, @@ -7911,11 +8742,13 @@ MAC-Parameters-v1310 ::= SEQUENCE { extendedLongDRX-r13 ENUMERATED {supported} OPTIONAL } -MAC-Parameters-v14xy ::= SEQUENCE { +MAC-Parameters-v1430 ::= SEQUENCE { shortSPS-IntervalFDD-r14 ENUMERATED {supported} OPTIONAL, shortSPS-IntervalTDD-r14 ENUMERATED {supported} OPTIONAL, skipUplinkDynamic-r14 ENUMERATED {supported} OPTIONAL, - skipUplinkSPS-r14 ENUMERATED {supported} OPTIONAL + skipUplinkSPS-r14 ENUMERATED {supported} OPTIONAL, + multipleUplinkSPS-r14 ENUMERATED {supported} OPTIONAL, + dataInactMon-r14 ENUMERATED {supported} OPTIONAL } RLC-Parameters-r12 ::= SEQUENCE { @@ -7926,7 +8759,7 @@ RLC-Parameters-v1310 ::= SEQUENCE { extendedRLC-SN-SO-Field-r13 ENUMERATED {supported} OPTIONAL } -RLC-Parameters-v14xy ::= SEQUENCE { +RLC-Parameters-v1430 ::= SEQUENCE { extendedPollByte-r14 ENUMERATED {supported} OPTIONAL } @@ -7958,6 +8791,16 @@ PDCP-Parameters-v1310 ::= SEQUENCE { pdcp-SN-Extension-18bits-r13 ENUMERATED {supported} OPTIONAL } +PDCP-Parameters-v1430 ::= SEQUENCE { + supportedUplinkOnlyROHC-Profiles-r14 SEQUENCE { + profile0x0006-r14 BOOLEAN + }, + maxNumberROHC-ContextSessions-r14 ENUMERATED { + cs2, cs4, cs8, cs12, cs16, cs24, cs32, + cs48, cs64, cs128, cs256, cs512, cs1024, + cs16384, spare2, spare1} DEFAULT cs16 +} + PhyLayerParameters ::= SEQUENCE { ue-TxAntennaSelectionSupported BOOLEAN, ue-SpecificRefSigsSupported BOOLEAN @@ -8019,7 +8862,8 @@ PhyLayerParameters-v1310 ::= SEQUENCE { aperiodicCSI-Reporting-r13 BIT STRING (SIZE (2)) OPTIONAL, codebook-HARQ-ACK-r13 BIT STRING (SIZE (2)) OPTIONAL, crossCarrierScheduling-B5C-r13 ENUMERATED {supported} OPTIONAL, - fdd-HARQ-TimingTDD-r13 ENUMERATED {supported} OPTIONAL, maxNumberUpdatedCSI-Proc-r13 INTEGER(5..32) OPTIONAL, + fdd-HARQ-TimingTDD-r13 ENUMERATED {supported} OPTIONAL, + maxNumberUpdatedCSI-Proc-r13 INTEGER(5..32) OPTIONAL, pucch-Format4-r13 ENUMERATED {supported} OPTIONAL, pucch-Format5-r13 ENUMERATED {supported} OPTIONAL, pucch-SCell-r13 ENUMERATED {supported} OPTIONAL, @@ -8045,6 +8889,25 @@ PhyLayerParameters-v1330 ::= SEQUENCE { crs-InterfMitigationTM1toTM9-r13 INTEGER (1.. maxServCell-r13) OPTIONAL } +PhyLayerParameters-v1430 ::= SEQUENCE { + ce-PUSCH-NB-MaxTBS-r14 ENUMERATED {supported} OPTIONAL, + ce-PDSCH-PUSCH-MaxBandwidth-r14 ENUMERATED {bw5, bw20} OPTIONAL, + ce-HARQ-AckBundling-r14 ENUMERATED {supported} OPTIONAL, + ce-PDSCH-TenProcesses-r14 ENUMERATED {supported} OPTIONAL, + ce-RetuningSymbols-r14 ENUMERATED {n0, n1} OPTIONAL, + ce-PDSCH-PUSCH-Enhancement-r14 ENUMERATED {supported} OPTIONAL, + ce-SchedulingEnhancement-r14 ENUMERATED {supported} OPTIONAL, + ce-SRS-Enhancement-r14 ENUMERATED {supported} OPTIONAL, + ce-PUCCH-Enhancement-r14 ENUMERATED {supported} OPTIONAL, + ce-ClosedLoopTxAntennaSelection-r14 ENUMERATED {supported} OPTIONAL, + tdd-SpecialSubframe-r14 ENUMERATED {supported} OPTIONAL, + tdd-TTI-Bundling-r14 ENUMERATED {supported} OPTIONAL, + dmrs-LessUpPTS-r14 ENUMERATED {supported} OPTIONAL, + mimo-UE-Parameters-v1430 MIMO-UE-Parameters-v1430 OPTIONAL, + alternativeTBS-Index-r14 ENUMERATED {supported} OPTIONAL, + feMBMS-Unicast-Parameters-r14 FeMBMS-Unicast-Parameters-r14 OPTIONAL +} + MIMO-UE-Parameters-r13 ::= SEQUENCE { parametersTM9-r13 MIMO-UE-ParametersPerTM-r13 OPTIONAL, parametersTM10-r13 MIMO-UE-ParametersPerTM-r13 OPTIONAL, @@ -8053,25 +8916,58 @@ MIMO-UE-Parameters-r13 ::= SEQUENCE { interferenceMeasRestriction-r13 ENUMERATED {supported} OPTIONAL } +MIMO-UE-Parameters-v1430 ::= SEQUENCE { + parametersTM9-v1430 MIMO-UE-ParametersPerTM-v1430 OPTIONAL, + parametersTM10-v1430 MIMO-UE-ParametersPerTM-v1430 OPTIONAL +} + MIMO-UE-ParametersPerTM-r13 ::= SEQUENCE { nonPrecoded-r13 MIMO-NonPrecodedCapabilities-r13 OPTIONAL, - beamformed-r13 MIMO-UE-BeamformedCapabilities-r13 OPTIONAL, + beamformed-r13 MIMO-UE-BeamformedCapabilities-r13 OPTIONAL, channelMeasRestriction-r13 ENUMERATED {supported} OPTIONAL, dmrs-Enhancements-r13 ENUMERATED {supported} OPTIONAL, csi-RS-EnhancementsTDD-r13 ENUMERATED {supported} OPTIONAL } +MIMO-UE-ParametersPerTM-v1430 ::= SEQUENCE { + nzp-CSI-RS-AperiodicInfo-r14 SEQUENCE { + nMaxProc-r14 INTEGER(5..32), + nMaxResource-r14 ENUMERATED {ffs1, ffs2, ffs3, ffs4} + } OPTIONAL, + nzp-CSI-RS-PeriodicInfo-r14 SEQUENCE { + nMaxResource-r14 ENUMERATED {ffs1, ffs2, ffs3, ffs4} + } OPTIONAL, + zp-CSI-RS-AperiodicInfo-r14 ENUMERATED {supported} OPTIONAL, + ul-dmrs-Enhancements-r14 ENUMERATED {supported} OPTIONAL, + densityReductionNP-r14 ENUMERATED {supported} OPTIONAL, + densityReductionBF-r14 ENUMERATED {supported} OPTIONAL, + hybridCSI-r14 ENUMERATED {supported} OPTIONAL, + semiOL-r14 ENUMERATED {supported} OPTIONAL, + csi-ReportingNP-r14 ENUMERATED {supported} OPTIONAL, + csi-ReportingAdvanced-r14 ENUMERATED {supported} OPTIONAL +} + MIMO-CA-ParametersPerBoBC-r13 ::= SEQUENCE { parametersTM9-r13 MIMO-CA-ParametersPerBoBCPerTM-r13 OPTIONAL, parametersTM10-r13 MIMO-CA-ParametersPerBoBCPerTM-r13 OPTIONAL } +MIMO-CA-ParametersPerBoBC-v1430 ::= SEQUENCE { + parametersTM9-v1430 MIMO-CA-ParametersPerBoBCPerTM-v1430 OPTIONAL, + parametersTM10-v1430 MIMO-CA-ParametersPerBoBCPerTM-v1430 OPTIONAL +} + MIMO-CA-ParametersPerBoBCPerTM-r13 ::= SEQUENCE { nonPrecoded-r13 MIMO-NonPrecodedCapabilities-r13 OPTIONAL, beamformed-r13 MIMO-BeamformedCapabilityList-r13 OPTIONAL, dmrs-Enhancements-r13 ENUMERATED {different} OPTIONAL } +MIMO-CA-ParametersPerBoBCPerTM-v1430 ::= SEQUENCE { + csi-ReportingNP-r14 ENUMERATED {different} OPTIONAL, + csi-ReportingAdvanced-r14 ENUMERATED {different} OPTIONAL +} + MIMO-NonPrecodedCapabilities-r13 ::= SEQUENCE { config1-r13 ENUMERATED {supported} OPTIONAL, config2-r13 ENUMERATED {supported} OPTIONAL, @@ -8180,6 +9076,16 @@ RF-Parameters-v12b0 ::= SEQUENCE { maxLayersMIMO-Indication-r12 ENUMERATED {supported} OPTIONAL } +RF-Parameters-v1430 ::= SEQUENCE { + supportedBandCombination-v1430 SupportedBandCombination-v1430 OPTIONAL, + supportedBandCombinationAdd-v1430 SupportedBandCombinationAdd-v1430 OPTIONAL, + supportedBandCombinationReduced-v1430 SupportedBandCombinationReduced-v1430 OPTIONAL, + eNB-RequestedParameters-v1430 SEQUENCE { + requestedDiffFallbackCombList-r14 BandCombinationList-r14 + } OPTIONAL, + diffFallbackCombReport-r14 ENUMERATED {supported} OPTIONAL +} + SupportedBandCombination-r10 ::= SEQUENCE (SIZE (1..maxBandComb-r10)) OF BandCombinationParameters-r10 SupportedBandCombinationExt-r10 ::= SEQUENCE (SIZE (1..maxBandComb-r10)) OF BandCombinationParametersExt-r10 @@ -8196,6 +9102,8 @@ SupportedBandCombination-v1270 ::= SEQUENCE (SIZE (1..maxBandComb-r10)) OF BandC SupportedBandCombination-v1320 ::= SEQUENCE (SIZE (1..maxBandComb-r10)) OF BandCombinationParameters-v1320 +SupportedBandCombination-v1430 ::= SEQUENCE (SIZE (1..maxBandComb-r10)) OF BandCombinationParameters-v1430 + SupportedBandCombinationAdd-r11 ::= SEQUENCE (SIZE (1..maxBandComb-r11)) OF BandCombinationParameters-r11 SupportedBandCombinationAdd-v11d0 ::= SEQUENCE (SIZE (1..maxBandComb-r11)) OF BandCombinationParameters-v10i0 @@ -8206,10 +9114,14 @@ SupportedBandCombinationAdd-v1270 ::= SEQUENCE (SIZE (1..maxBandComb-r11)) OF Ba SupportedBandCombinationAdd-v1320 ::= SEQUENCE (SIZE (1..maxBandComb-r11)) OF BandCombinationParameters-v1320 +SupportedBandCombinationAdd-v1430 ::= SEQUENCE (SIZE (1..maxBandComb-r11)) OF BandCombinationParameters-v1430 + SupportedBandCombinationReduced-r13 ::= SEQUENCE (SIZE (1..maxBandComb-r13)) OF BandCombinationParameters-r13 SupportedBandCombinationReduced-v1320 ::= SEQUENCE (SIZE (1..maxBandComb-r13)) OF BandCombinationParameters-v1320 +SupportedBandCombinationReduced-v1430 ::= SEQUENCE (SIZE (1..maxBandComb-r13)) OF BandCombinationParameters-v1430 + BandCombinationParameters-r10 ::= SEQUENCE (SIZE (1..maxSimultaneousBands-r10)) OF BandParameters-r10 BandCombinationParametersExt-r10 ::= SEQUENCE { @@ -8284,6 +9196,12 @@ BandCombinationParameters-v1320 ::= SEQUENCE { additionalRx-Tx-PerformanceReq-r13 ENUMERATED {supported} OPTIONAL } +BandCombinationParameters-v1430 ::= SEQUENCE { + bandParameterList-v1430 SEQUENCE (SIZE (1..maxSimultaneousBands-r10)) OF + BandParameters-v1430 OPTIONAL, + v2x-SupportedTxBandCombListPerBC-r14 BIT STRING (SIZE (1.. maxBandComb-r13)) OPTIONAL, + v2x-SupportedRxBandCombListPerBC-r14 BIT STRING (SIZE (1.. maxBandComb-r13)) OPTIONAL} + SupportedBandwidthCombinationSet-r10 ::= BIT STRING (SIZE (1..maxBandwidthCombSet-r10)) BandParameters-r10 ::= SEQUENCE { @@ -8327,6 +9245,37 @@ BandParameters-v1320 ::= SEQUENCE { bandParametersDL-v1320 MIMO-CA-ParametersPerBoBC-r13 } +BandParameters-v1430 ::= SEQUENCE { + bandParametersDL-v1430 MIMO-CA-ParametersPerBoBC-v1430 OPTIONAL, + ul-256QAM-r14 ENUMERATED {supported} OPTIONAL, + ul-256QAM-perCC-InfoList-r14 SEQUENCE (SIZE (2..maxServCell-r13)) OF UL-256QAM-perCC-Info-r14 OPTIONAL, + retuningTimeInfoBandList-r14 SEQUENCE (SIZE (1..maxSimultaneousBands-r10)) OF + RetuningTimeInfo-r14 OPTIONAL +} + +V2X-BandParameters-r14 ::= SEQUENCE { + v2x-FreqBandEUTRA-r14 FreqBandIndicator-r11, + bandParametersTxSL-r14 BandParametersTxSL-r14 OPTIONAL, + bandParametersRxSL-r14 BandParametersRxSL-r14 OPTIONAL +} + +BandParametersTxSL-r14 ::= SEQUENCE { + v2x-BandwidthClassTxSL-r14 V2X-BandwidthClassSL-r14, + v2x-eNB-Scheduled-r14 ENUMERATED {supported} OPTIONAL, + v2x-HighPower-r14 ENUMERATED {supported} OPTIONAL +} + +BandParametersRxSL-r14 ::= SEQUENCE { + v2x-BandwidthClassRxSL-r14 V2X-BandwidthClassSL-r14, + v2x-HighReception-r14 ENUMERATED {supported} OPTIONAL +} + +V2X-BandwidthClassSL-r14 ::= SEQUENCE (SIZE (1..maxBandwidthClass-r10)) OF V2X-BandwidthClass-r14 + +UL-256QAM-perCC-Info-r14 ::= SEQUENCE { + ul-256QAM-perCC-r14 ENUMERATED {supported} OPTIONAL +} + BandParametersUL-r10 ::= SEQUENCE (SIZE (1..maxBandwidthClass-r10)) OF CA-MIMO-ParametersUL-r10 BandParametersUL-r13 ::= CA-MIMO-ParametersUL-r10 @@ -8369,6 +9318,8 @@ IntraBandContiguousCC-Info-r12 ::= SEQUENCE { CA-BandwidthClass-r10 ::= ENUMERATED {a, b, c, d, e, f, ...} +V2X-BandwidthClass-r14 ::= ENUMERATED {a, b, c, d, e, f, ...} + MIMO-CapabilityUL-r10 ::= ENUMERATED {twoLayers, fourLayers} MIMO-CapabilityDL-r10 ::= ENUMERATED {twoLayers, fourLayers, eightLayers} @@ -8443,6 +9394,14 @@ MeasParameters-v1310 ::= SEQUENCE { rssi-AndChannelOccupancyReporting-r13 ENUMERATED {supported} OPTIONAL } +MeasParameters-v1430 ::= SEQUENCE { + ceMeasurements-r14 ENUMERATED {supported} OPTIONAL, + ncsg-r14 ENUMERATED {supported} OPTIONAL, + shortMeasurementGap-r14 ENUMERATED {supported} OPTIONAL, + perServingCellMeasurementGap-r14 ENUMERATED {supported} OPTIONAL, + nonUniformGap-r14 ENUMERATED {supported} OPTIONAL +} + BandListEUTRA ::= SEQUENCE (SIZE (1..maxBands)) OF BandInfoEUTRA BandCombinationListEUTRA-r10 ::= SEQUENCE (SIZE (1..maxBandComb-r10)) OF BandInfoEUTRA @@ -8605,6 +9564,10 @@ UE-BasedNetwPerfMeasParameters-v1250 ::= SEQUENCE { loggedMBSFNMeasurements-r12 ENUMERATED {supported} } +UE-BasedNetwPerfMeasParameters-v1430 ::= SEQUENCE { + locationReport-r14 ENUMERATED {supported} OPTIONAL +} + OTDOA-PositioningCapabilities-r10 ::= SEQUENCE { otdoa-UE-Assisted-r10 ENUMERATED {supported}, interFreqRSTD-Measurement-r10 ENUMERATED {supported} OPTIONAL @@ -8620,6 +9583,15 @@ Other-Parameters-v11d0 ::= SEQUENCE { inDeviceCoexInd-UL-CA-r11 ENUMERATED {supported} OPTIONAL } +Other-Parameters-v1360 ::= SEQUENCE { + inDeviceCoexInd-HardwareSharingInd-r13 ENUMERATED {supported} OPTIONAL +} + +Other-Parameters-v1430 ::= SEQUENCE { + bwPrefInd-r14 ENUMERATED {supported} OPTIONAL, + rlm-ReportSupport-r14 ENUMERATED {supported} OPTIONAL +} + MBMS-Parameters-r11 ::= SEQUENCE { mbms-SCell-r11 ENUMERATED {supported} OPTIONAL, mbms-NonServingCell-r11 ENUMERATED {supported} OPTIONAL @@ -8629,6 +9601,18 @@ MBMS-Parameters-v1250 ::= SEQUENCE { mbms-AsyncDC-r12 ENUMERATED {supported} OPTIONAL } +MBMS-Parameters-v1430 ::= SEQUENCE { + fembmsDedicatedCell-r14 ENUMERATED {supported} OPTIONAL, + fembmsMixedCell-r14 ENUMERATED {supported} OPTIONAL, + subcarrierSpacingMBMS-khz7dot5-r14 ENUMERATED {supported} OPTIONAL, + subcarrierSpacingMBMS-khz1dot25-r14 ENUMERATED {supported} OPTIONAL +} + +FeMBMS-Unicast-Parameters-r14 ::= SEQUENCE { + unicast-fembmsMixedSCell-r14 ENUMERATED {supported} OPTIONAL, + emptyUnicastRegion-r14 ENUMERATED {supported} OPTIONAL +} + SCPTM-Parameters-r13 ::= SEQUENCE { scptm-ParallelReception-r13 ENUMERATED {supported} OPTIONAL, scptm-SCell-r13 ENUMERATED {supported} OPTIONAL, @@ -8648,6 +9632,14 @@ CE-Parameters-v1320 ::= SEQUENCE { intraFreqHO-CE-ModeB-r13 ENUMERATED {supported} OPTIONAL } +CE-Parameters-v1350 ::= SEQUENCE { + unicastFrequencyHopping-r13 ENUMERATED {supported} OPTIONAL +} + +CE-Parameters-v1430 ::= SEQUENCE { + ce-SwitchWithoutHO-r14 ENUMERATED {supported} OPTIONAL +} + LAA-Parameters-r13 ::= SEQUENCE { crossCarrierSchedulingLAA-DL-r13 ENUMERATED {supported} OPTIONAL, csi-RS-DRS-RRM-MeasurementsLAA-r13 ENUMERATED {supported} OPTIONAL, @@ -8658,10 +9650,13 @@ LAA-Parameters-r13 ::= SEQUENCE { tm10-LAA-r13 ENUMERATED {supported} OPTIONAL } -LAA-Parameters-v14xy ::= SEQUENCE { +LAA-Parameters-v1430 ::= SEQUENCE { crossCarrierSchedulingLAA-UL-r14 ENUMERATED {supported} OPTIONAL, uplinkLAA-r14 ENUMERATED {supported} OPTIONAL, - twoStepSchedulingTimingInfo-r14 ENUMERATED {nPlus1, nPlus2, nPlus3} OPTIONAL + twoStepSchedulingTimingInfo-r14 ENUMERATED {nPlus1, nPlus2, nPlus3} OPTIONAL, + uss-BlindDecodingAdjustment-r14 ENUMERATED {supported} OPTIONAL, + uss-BlindDecodingReduction-r14 ENUMERATED {supported} OPTIONAL, + outOfSequenceGrantHandling-r14 ENUMERATED {supported} OPTIONAL } WLAN-IW-Parameters-r12 ::= SEQUENCE { @@ -8676,6 +9671,14 @@ LWA-Parameters-r13 ::= SEQUENCE { lwa-BufferSize-r13 ENUMERATED {supported} OPTIONAL } +LWA-Parameters-v1430 ::= SEQUENCE { + lwa-HO-WithoutWT-Change-r14 ENUMERATED {supported} OPTIONAL, + lwa-UL-r14 ENUMERATED {supported} OPTIONAL, + wlan-PeriodicMeas-r14 ENUMERATED {supported} OPTIONAL, + wlan-ReportAnyWLAN-r14 ENUMERATED {supported} OPTIONAL, + wlan-SupportedDataRate-r14 INTEGER (1..2048) OPTIONAL +} + WLAN-IW-Parameters-v1310 ::= SEQUENCE { rclwi-r13 ENUMERATED {supported} OPTIONAL } @@ -8684,7 +9687,7 @@ LWIP-Parameters-r13 ::= SEQUENCE { lwip-r13 ENUMERATED {supported} OPTIONAL } -LWIP-Parameters-v14xy ::= SEQUENCE { +LWIP-Parameters-v1430 ::= SEQUENCE { lwip-Aggregation-DL-r14 ENUMERATED {supported} OPTIONAL, lwip-Aggregation-UL-r14 ENUMERATED {supported} OPTIONAL } @@ -8718,6 +9721,21 @@ SL-Parameters-v1310 ::= SEQUENCE { discPeriodicSLSS-r13 ENUMERATED {supported} OPTIONAL } +SL-Parameters-v1430 ::= SEQUENCE { + zoneBasedPoolSelection-r14 ENUMERATED {supported} OPTIONAL, + ue-AutonomousWithFullSensing-r14 ENUMERATED {supported} OPTIONAL, + ue-AutonomousWithPartialSensing-r14 ENUMERATED {supported} OPTIONAL, + sl-CongestionControl-r14 ENUMERATED {supported} OPTIONAL, + v2x-TxWithShortResvInterval-r14 ENUMERATED {supported} OPTIONAL, + v2x-numberTxRxTiming-r14 INTEGER(1..16) OPTIONAL, + v2x-nonAdjacentPSCCH-PSSCH-r14 ENUMERATED {supported} OPTIONAL, + slss-TxRx-r14 ENUMERATED {supported} OPTIONAL, + v2x-SupportedBandCombinationList-r14 V2X-SupportedBandCombination-r14 OPTIONAL +} + +V2X-SupportedBandCombination-r14 ::= SEQUENCE (SIZE (1..maxBandComb-r13)) OF V2X-BandCombinationParameters-r14 + +V2X-BandCombinationParameters-r14 ::= SEQUENCE (SIZE (1.. maxSimultaneousBands-r10)) OF V2X-BandParameters-r14 SupportedBandInfoList-r12 ::= SEQUENCE (SIZE (1..maxBands)) OF SupportedBandInfo-r12 @@ -8727,6 +9745,30 @@ SupportedBandInfo-r12 ::= SEQUENCE { FreqBandIndicatorListEUTRA-r12 ::= SEQUENCE (SIZE (1..maxBands)) OF FreqBandIndicator-r11 +MMTEL-Parameters-r14 ::= SEQUENCE { + delayBudgetReporting-r14 ENUMERATED {supported} OPTIONAL, + pusch-Enhancements-r14 ENUMERATED {supported} OPTIONAL, + recommendedBitRate-r14 ENUMERATED {supported} OPTIONAL, + recommendedBitRateQuery-r14 ENUMERATED {supported} OPTIONAL +} + +RetuningTimeInfo-r14 ::= SEQUENCE { + retuningInfo SEQUENCE { + rf-RetuningTimeDL-r14 ENUMERATED {n0, n0dot5, n1, n1dot5, n2, n2dot5, n3, + n3dot5, n4, n4dot5, n5, n5dot5, n6, n6dot5, + n7, spare1} OPTIONAL, + rf-RetuningTimeUL-r14 ENUMERATED {n0, n0dot5, n1, n1dot5, n2, n2dot5, n3, + n3dot5, n4, n4dot5, n5, n5dot5, n6, n6dot5, + n7, spare1} OPTIONAL + } +} + +HighSpeedEnhParameters-r14 ::= SEQUENCE { + measurementEnhancements-r14 ENUMERATED {supported} OPTIONAL, + demodulationEnhancements-r14 ENUMERATED {supported} OPTIONAL, + prach-Enhancements-r14 ENUMERATED {supported} OPTIONAL +} + UE-RadioPagingInfo-r12 ::= SEQUENCE { ue-Category-v1250 INTEGER (0) OPTIONAL, @@ -8839,6 +9881,10 @@ MBMS-NotificationConfig-r9 ::= SEQUENCE { notificationSF-Index-r9 INTEGER (1..6) } +MBMS-NotificationConfig-v1430 ::= SEQUENCE { + notificationSF-Index-v1430 INTEGER (7..10) +} + MBMS-ServiceList-r13 ::= SEQUENCE (SIZE (0..maxMBMS-ServiceListPerUE-r13)) OF MBMS-ServiceInfo-r13 @@ -8855,15 +9901,23 @@ MBSFN-AreaInfoList-r9 ::= SEQUENCE (SIZE(1..maxMBSFN-Area)) OF MBSFN-A MBSFN-AreaInfo-r9 ::= SEQUENCE { mbsfn-AreaId-r9 MBSFN-AreaId-r12, non-MBSFNregionLength ENUMERATED {s1, s2}, - notificationIndicator-r9 INTEGER (0..7), + notificationIndicator-r9 INTEGER (0..7), mcch-Config-r9 SEQUENCE { - mcch-RepetitionPeriod-r9 ENUMERATED {rf32, rf64, rf128, rf256}, - mcch-Offset-r9 INTEGER (0..10), - mcch-ModificationPeriod-r9 ENUMERATED {rf512, rf1024}, - sf-AllocInfo-r9 BIT STRING (SIZE(6)), - signallingMCS-r9 ENUMERATED {n2, n7, n13, n19} + mcch-RepetitionPeriod-r9 ENUMERATED {rf32, rf64, rf128, rf256}, + mcch-Offset-r9 INTEGER (0..10), + mcch-ModificationPeriod-r9 ENUMERATED {rf512, rf1024}, + sf-AllocInfo-r9 BIT STRING (SIZE(6)), + signallingMCS-r9 ENUMERATED {n2, n7, n13, n19} }, - ... + ..., + [[ mcch-Config-r14 SEQUENCE { + mcch-RepetitionPeriod-v1430 ENUMERATED {rf1, rf2, rf4, rf8, + rf16 } OPTIONAL, -- Need OR + mcch-ModificationPeriod-v1430 ENUMERATED {rf1, rf2, rf4, rf8, rf16, rf32, rf64, rf128, + rf256, spare7} OPTIONAL -- Need OR + } OPTIONAL, -- Need OR + subcarrierSpacingMBMS-r14 ENUMERATED {khz-7dot5, khz-1dot25} OPTIONAL -- Need OR + ]] } @@ -8876,6 +9930,14 @@ MBSFN-SubframeConfig ::= SEQUENCE { } } +MBSFN-SubframeConfig-v1430 ::= SEQUENCE { + subframeAllocation-v1430 CHOICE { + oneFrame-v1430 BIT STRING (SIZE(2)), + fourFrames-v1430 BIT STRING (SIZE(8)) + } +} + + PMCH-InfoList-r9 ::= SEQUENCE (SIZE (0..maxPMCH-PerMBSFN)) OF PMCH-Info-r9 PMCH-InfoListExt-r12 ::= SEQUENCE (SIZE (0..maxPMCH-PerMBSFN)) OF PMCH-InfoExt-r12 @@ -8917,7 +9979,9 @@ PMCH-Config-r12 ::= SEQUENCE { }, mch-SchedulingPeriod-r12 ENUMERATED { rf4, rf8, rf16, rf32, rf64, rf128, rf256, rf512, rf1024}, - ... + ..., + [[ mch-SchedulingPeriod-v1430 ENUMERATED {rf1, rf2} OPTIONAL -- Need OR + ]] } TMGI-r9 ::= SEQUENCE { @@ -8929,7 +9993,6 @@ TMGI-r9 ::= SEQUENCE { } - SC-MTCH-InfoList-r13 ::= SEQUENCE (SIZE (0..maxSC-MTCH-r13)) OF SC-MTCH-Info-r13 SC-MTCH-Info-r13 ::= SEQUENCE { @@ -8983,6 +10046,66 @@ SC-MTCH-SchedulingInfo-r13::= SEQUENCE { } +SC-MTCH-InfoList-BR-r14 ::= SEQUENCE (SIZE (0..maxSC-MTCH-BR-r14)) OF SC-MTCH-Info-BR-r14 + +SC-MTCH-Info-BR-r14 ::= SEQUENCE { + sc-mtch-CarrierFreq-r14 ARFCN-ValueEUTRA-r9, + mbmsSessionInfo-r14 MBMSSessionInfo-r13, + g-RNTI-r14 BIT STRING(SIZE(16)), + sc-mtch-schedulingInfo-r14 SC-MTCH-SchedulingInfo-BR-r14 OPTIONAL, -- Need OP + sc-mtch-neighbourCell-r14 BIT STRING (SIZE(maxNeighCell-SCPTM-r13)) OPTIONAL, -- Need OP + mpdcch-Narrowband-SC-MTCH-r14 INTEGER (1.. maxAvailNarrowBands-r13), + mpdcch-NumRepetition-SC-MTCH-r14 ENUMERATED {r1, r2, r4, r8, r16, + r32, r64, r128, r256}, + mpdcch-StartSF-SC-MTCH-r14 CHOICE { + fdd-r14 ENUMERATED {v1, v1dot5, v2, v2dot5, v4, + v5, v8, v10}, + tdd-r14 ENUMERATED {v1, v2, v4, v5, v8, v10, + v20} + }, + mpdcch-PDSCH-HoppingConfig-SC-MTCH-r14 ENUMERATED {on, off}, + mpdcch-PDSCH-CEmodeConfig-SC-MTCH-r14 ENUMERATED {ce-ModeA, ce-ModeB}, + mpdcch-PDSCH-MaxBandwidth-SC-MTCH-r14 ENUMERATED {bw1dot4, bw5}, + mpdcch-Offset-SC-MTCH-r14 ENUMERATED {zero, oneEighth, oneQuarter, + threeEighth, oneHalf, fiveEighth, + threeQuarter, sevenEighth}, + + p-a-r14 ENUMERATED { dB-6, dB-4dot77, dB-3, + dB-1dot77, dB0, dB1, dB2, + dB3} OPTIONAL,-- Need OR + ... +} + +SC-MTCH-SchedulingInfo-BR-r14::= SEQUENCE { + onDurationTimerSCPTM-r14 ENUMERATED { + psf300, psf400, psf500, psf600, + psf800, psf1000, psf1200, psf1600}, + drx-InactivityTimerSCPTM-r14 ENUMERATED { + psf0, psf1, psf2, psf4, psf8, psf16, + psf32, psf64, psf128, psf256, ps512, + psf1024, psf2048, psf4096, psf8192, psf16384}, + schedulingPeriodStartOffsetSCPTM-r14 CHOICE { + sf10 INTEGER(0..9), + sf20 INTEGER(0..19), + sf32 INTEGER(0..31), + sf40 INTEGER(0..39), + sf64 INTEGER(0..63), + sf80 INTEGER(0..79), + sf128 INTEGER(0..127), + sf160 INTEGER(0..159), + sf256 INTEGER(0..255), + sf320 INTEGER(0..319), + sf512 INTEGER(0..511), + sf640 INTEGER(0..639), + sf1024 INTEGER(0..1023), + sf2048 INTEGER(0..2047), + sf4096 INTEGER(0..4095), + sf8192 INTEGER(0..8191) + }, + ... +} + + SCPTM-NeighbourCellList-r13 ::= SEQUENCE (SIZE (1..maxNeighCell-SCPTM-r13)) OF PCI-ARFCN-r13 PCI-ARFCN-r13 ::= SEQUENCE { @@ -8991,6 +10114,37 @@ PCI-ARFCN-r13 ::= SEQUENCE { } +SL-AnchorCarrierFreqList-V2X-r14 ::= SEQUENCE (SIZE (1..maxFreqV2X-r14)) OF ARFCN-ValueEUTRA-r9 + + +SL-CBR-CommonTxConfigList-r14 ::= SEQUENCE { + cbr-RangeCommonConfigList-r14 SEQUENCE (SIZE (1..maxSL-V2X-CBRConfig-r14)) OF SL-CBR-Levels-Config-r14, + sl-CBR-PSSCH-TxConfigList-r14 SEQUENCE (SIZE (1..maxSL-V2X-TxConfig-r14)) OF SL-CBR-PSSCH-TxConfig-r14 +} + +SL-CBR-Levels-Config-r14 ::= SEQUENCE (SIZE (1..maxCBR-Level-r14)) OF SL-CBR-r14 + + +SL-CBR-PSSCH-TxConfig-r14 ::= SEQUENCE { + cr-Limit-r14 INTEGER(0..10000), + tx-Parameters-r14 SL-PSSCH-TxParameters-r14 +} + +SL-CBR-r14 ::= INTEGER(0..100) + + +SL-CBR-PPPP-TxConfigList-r14 ::= SEQUENCE (SIZE (1..8)) OF SL-PPPP-TxConfigIndex-r14 + +SL-PPPP-TxConfigIndex-r14 ::= SEQUENCE { + priorityThreshold-r14 SL-Priority-r13, + defaultTxConfigIndex-r14 INTEGER(0..maxCBR-Level-1-r14), + cbr-ConfigIndex-r14 INTEGER(0..maxSL-V2X-CBRConfig-1-r14), + tx-ConfigIndexList-r14 SEQUENCE (SIZE (1..maxCBR-Level-r14)) OF Tx-ConfigIndex-r14 +} + +Tx-ConfigIndex-r14 ::= INTEGER(0..maxSL-V2X-TxConfig-1-r14) + + SL-CommConfig-r12 ::= SEQUENCE { commTxResources-r12 CHOICE { release NULL, @@ -9095,7 +10249,7 @@ SL-CommResourcePoolV2X-r14 ::= SEQUENCE { n48, n50, n72, n75, n96, n100, spare13, spare12, spare11, spare10, spare9, spare8, spare7, spare6, spare5, spare4, spare3, spare2, spare1}, - numSubchannel-r14 ENUMERATED {n1, n3, n5, n10, n15, n20, spare2, spare1}, + numSubchannel-r14 ENUMERATED {n1, n3, n5, n8, n10, n15, n20, spare1}, startRB-Subchannel-r14 INTEGER (0..99), startRB-PSCCH-Pool-r14 INTEGER (0..99) OPTIONAL, -- Need OR rxParametersNCell-r14 SEQUENCE { @@ -9103,12 +10257,36 @@ SL-CommResourcePoolV2X-r14 ::= SEQUENCE { syncConfigIndex-r14 INTEGER (0..15) } OPTIONAL, -- Need OR dataTxParameters-r14 SL-TxParameters-r12 OPTIONAL, -- Cond Tx - zoneID-r14 INTEGER (0..7) OPTIONAL, -- Need OR, + zoneID-r14 INTEGER (0..7) OPTIONAL, -- Need OR + threshS-RSSI-CBR-r14 INTEGER (0..45) OPTIONAL, -- Need OR + poolReportId-r14 SL-V2X-TxPoolReportIdentity-r14 OPTIONAL, -- Need OR + cbr-pssch-TxConfigList-r14 SL-CBR-PPPP-TxConfigList-r14 OPTIONAL, -- Need OR + resourceSelectionConfigP2X-r14 SL-P2X-ResourceSelectionConfig-r14 OPTIONAL, -- Cond P2X + syncAllowed-r14 SL-SyncAllowed-r14 OPTIONAL, -- Need OR + restrictResourceReservationPeriod-r14 SL-RestrictResourceReservationPeriodList-r14 OPTIONAL, -- Need OR ... } SL-TRPT-Subset-r12 ::= BIT STRING (SIZE (3..5)) +SL-V2X-TxPoolReportIdentity-r14::= INTEGER (1..maxSL-PoolToMeasure-r14) + + +SL-CommTxPoolSensingConfig-r14 ::= SEQUENCE { + pssch-TxConfigList-r14 SL-PSSCH-TxConfigList-r14, + thresPSSCH-RSRP-List-r14 SL-ThresPSSCH-RSRP-List-r14, + restrictResourceReservationPeriod-r14 SL-RestrictResourceReservationPeriodList-r14 OPTIONAL, -- Need OR + probResourceKeep-r14 ENUMERATED {v0, v0dot2, v0dot4, v0dot6, v0dot8, + spare3,spare2, spare1}, + p2x-SensingConfig-r14 SEQUENCE { + minNumCandidateSF-r14 INTEGER (1..13), + gapCandidateSensing-r14 BIT STRING (SIZE (10)) + } OPTIONAL, -- Need OR + sl-ReselectAfter-r14 ENUMERATED {n1, n2, n3, n4, n5, n6, n7, n8, n9, + spare7, spare6, spare5, spare4, spare3, spare2, + spare1} OPTIONAL -- Need OR +} + SL-CP-Len-r12 ::= ENUMERATED {normal, extended} @@ -9301,6 +10479,38 @@ SL-PoolSelectionConfig-r12 ::= SEQUENCE { } +SL-DiscSysInfoReport-r13 ::= SEQUENCE { + plmn-IdentityList-r13 PLMN-IdentityList OPTIONAL, + cellIdentity-13 CellIdentity OPTIONAL, + carrierFreqInfo-13 ARFCN-ValueEUTRA-r9 OPTIONAL, + discRxResources-r13 SL-DiscRxPoolList-r12 OPTIONAL, + discTxPoolCommon-r13 SL-DiscTxPoolList-r12 OPTIONAL, + discTxPowerInfo-r13 SL-DiscTxPowerInfoList-r12 OPTIONAL, + discSyncConfig-r13 SL-SyncConfigNFreq-r13 OPTIONAL, + discCellSelectionInfo-r13 SEQUENCE { + q-RxLevMin-r13 Q-RxLevMin, + q-RxLevMinOffset-r13 INTEGER (1..8) OPTIONAL + } OPTIONAL, + cellReselectionInfo-r13 SEQUENCE { + q-Hyst-r13 ENUMERATED { + dB0, dB1, dB2, dB3, dB4, dB5, dB6, dB8, dB10, + dB12, dB14, dB16, dB18, dB20, dB22, dB24}, + q-RxLevMin-r13 Q-RxLevMin, + t-ReselectionEUTRA-r13 T-Reselection + } OPTIONAL, + tdd-Config-r13 TDD-Config OPTIONAL, + freqInfo-r13 SEQUENCE { + ul-CarrierFreq-r13 ARFCN-ValueEUTRA OPTIONAL, + ul-Bandwidth-r13 ENUMERATED {n6, n15, n25, n50, n75, n100} + OPTIONAL, + additionalSpectrumEmission-r13 AdditionalSpectrumEmission OPTIONAL + } OPTIONAL, + p-Max-r13 P-Max OPTIONAL, + referenceSignalPower-r13 INTEGER (-60..50) OPTIONAL, + ... +} + + SL-DiscTxPowerInfoList-r12 ::= SEQUENCE (SIZE (maxSL-DiscPowerClass-r12)) OF SL-DiscTxPowerInfo-r12 SL-DiscTxPowerInfo-r12 ::= SEQUENCE { @@ -9346,12 +10556,32 @@ SL-HoppingConfigDisc-r12 ::= SEQUENCE { } -SL-InterFreqInfoListV2X-r14 ::= SEQUENCE (SIZE (1..maxFreq)) OF SL-InterFreqInfoV2X-r14 +SL-InterFreqInfoListV2X-r14 ::= SEQUENCE (SIZE (0..maxFreqV2X-1-r14)) OF SL-InterFreqInfoV2X-r14 -SL-InterFreqInfoV2X-r14::= SEQUENCE { +SL-InterFreqInfoV2X-r14 ::= SEQUENCE { + plmn-IdentityList-r14 PLMN-IdentityList OPTIONAL, -- Need OP v2x-CommCarrierFreq-r14 ARFCN-ValueEUTRA-r9, - typeTxSync-r14 ENUMERATED {gnss, enb} OPTIONAL, -- Need OR + sl-MaxTxPower-r14 P-Max OPTIONAL, -- Need OR + sl-Bandwidth-r14 ENUMERATED {n6, n15, n25, n50, n75, n100} OPTIONAL, -- Need OR v2x-SchedulingPool-r14 SL-CommResourcePoolV2X-r14 OPTIONAL, -- Need OR + v2x-UE-ConfigList-r14 SL-V2X-UE-ConfigList-r14 OPTIONAL, -- Need OR + ... +} + + +SL-V2X-UE-ConfigList-r14 ::= SEQUENCE (SIZE (1.. maxCellIntra)) OF SL-V2X-InterFreqUE-Config-r14 + +SL-V2X-InterFreqUE-Config-r14 ::= SEQUENCE { + physCellIdList-r14 PhysCellIdList-r13 OPTIONAL, -- Need OR + typeTxSync-r14 SL-TypeTxSync-r14 OPTIONAL, -- Need OR + v2x-SyncConfig-r14 SL-SyncConfigListNFreqV2X-r14 OPTIONAL, -- Need OR + v2x-CommRxPool-r14 SL-CommRxPoolListV2X-r14 OPTIONAL, -- Need OR + v2x-CommTxPoolNormal-r14 SL-CommTxPoolListV2X-r14 OPTIONAL, -- Need OR + p2x-CommTxPoolNormal-r14 SL-CommTxPoolListV2X-r14 OPTIONAL, -- Need OR + v2x-CommTxPoolExceptional-r14 SL-CommResourcePoolV2X-r14 OPTIONAL, -- Need OR + v2x-ResourceSelectionConfig-r14 SL-CommTxPoolSensingConfig-r14 OPTIONAL, -- Need OR + zoneConfig-r14 SL-ZoneConfig-r14 OPTIONAL, -- Need OR + offsetDFN-r14 INTEGER (0..1000) OPTIONAL, -- Need OR ... } @@ -9363,7 +10593,15 @@ SL-OffsetIndicator-r12 ::= CHOICE { SL-OffsetIndicatorSync-r12 ::= INTEGER (0..39) -SL-OffsetIndicatorSync-v14xy ::= INTEGER (40..159) +SL-OffsetIndicatorSync-v1430 ::= INTEGER (40..159) + +SL-OffsetIndicatorSync-r14 ::= INTEGER (0..159) + + +SL-P2X-ResourceSelectionConfig-r14 ::= SEQUENCE { + partialSensing-r14 ENUMERATED {true} OPTIONAL, -- Need OR + randomSelection-r14 ENUMERATED {true} OPTIONAL -- Need OR +} SL-PeriodComm-r12 ::= ENUMERATED {sf40, sf60, sf70, sf80, sf120, sf140, @@ -9379,7 +10617,7 @@ SL-Priority-r13 ::= INTEGER (1..8) SL-PSSCH-TxConfigList-r14 ::= SEQUENCE (SIZE (1..maxPSSCH-TxConfig-r14)) OF SL-PSSCH-TxConfig-r14 SL-PSSCH-TxConfig-r14 ::= SEQUENCE { - typeTxSync-r14 ENUMERATED {gnss, enb, ue, spare1} OPTIONAL, -- Need OR + typeTxSync-r14 SL-TypeTxSync-r14 OPTIONAL, -- Need OR thresUE-Speed-r14 ENUMERATED {kmph60, kmph80, kmph100, kmph120, kmph140, kmph160, kmph180, kmph200}, parametersAboveThres-r14 SL-PSSCH-TxParameters-r14, @@ -9390,9 +10628,10 @@ SL-PSSCH-TxConfig-r14 ::= SEQUENCE { SL-PSSCH-TxParameters-r14 ::= SEQUENCE { minMCS-PSSCH-r14 INTEGER (0..31), maxMCS-PSSCH-r14 INTEGER (0..31), - minRB-NumberPSSCH-r14 INTEGER (1..100), - maxRB-NumberPSSCH-r14 INTEGER (1..100), - allowedRetxNumberPSSCH-r14 ENUMERATED {n0, n1, both, spare1} + minSubChannel-NumberPSSCH-r14 INTEGER (1..20), + maxSubchannel-NumberPSSCH-r14 INTEGER (1..20), + allowedRetxNumberPSSCH-r14 ENUMERATED {n0, n1, both, spare1}, + maxTxPower-r14 SL-TxPower-r14 OPTIONAL -- Cond CBR } @@ -9404,6 +10643,13 @@ SL-RestrictResourceReservationPeriod-r14 ::= ENUMERATED {v0dot2, v0dot5, SLSSID-r12 ::= INTEGER (0..167) +SL-SyncAllowed-r14 ::= SEQUENCE { + gnss-Sync-r14 ENUMERATED {true} OPTIONAL, -- Need OR + enb-Sync-r14 ENUMERATED {true} OPTIONAL, -- Need OR + ue-Sync-r14 ENUMERATED {true} OPTIONAL -- Need OR +} + + SL-SyncConfigList-r12 ::= SEQUENCE (SIZE (1..maxSL-SyncConfig-r12)) OF SL-SyncConfig-r12 SL-SyncConfigListV2X-r14 ::= SEQUENCE (SIZE (1.. maxSL-V2X-SyncConfig-r14)) OF SL-SyncConfig-r12 @@ -9424,12 +10670,15 @@ SL-SyncConfig-r12 ::= SEQUENCE { ..., [[ syncTxPeriodic-r13 ENUMERATED {true} OPTIONAL -- Need OR ]], - [[ syncOffsetIndicator-v14xy SL-OffsetIndicatorSync-v14xy OPTIONAL -- Need OR + [[ syncOffsetIndicator-v1430 SL-OffsetIndicatorSync-v1430 OPTIONAL, -- Need OR + gnss-Sync-r14 ENUMERATED {true} OPTIONAL -- Need OR ]] } SL-SyncConfigListNFreq-r13 ::= SEQUENCE (SIZE (1..maxSL-SyncConfig-r12)) OF SL-SyncConfigNFreq-r13 +SL-SyncConfigListNFreqV2X-r14 ::= SEQUENCE (SIZE (1..maxSL-V2X-SyncConfig-r14)) OF SL-SyncConfigNFreq-r13 + SL-SyncConfigNFreq-r13 ::= SEQUENCE { asyncParameters-r13 SEQUENCE { syncCP-Len-r13 SL-CP-Len-r12, @@ -9445,39 +10694,10 @@ SL-SyncConfigNFreq-r13 ::= SEQUENCE { rxParameters-r13 SEQUENCE { discSyncWindow-r13 ENUMERATED {w1, w2} } OPTIONAL, -- Need OR - ... -} - - -SL-DiscSysInfoReport-r13 ::= SEQUENCE { - plmn-IdentityList-r13 PLMN-IdentityList OPTIONAL, - cellIdentity-13 CellIdentity OPTIONAL, - carrierFreqInfo-13 ARFCN-ValueEUTRA-r9 OPTIONAL, - discRxResources-r13 SL-DiscRxPoolList-r12 OPTIONAL, - discTxPoolCommon-r13 SL-DiscTxPoolList-r12 OPTIONAL, - discTxPowerInfo-r13 SL-DiscTxPowerInfoList-r12 OPTIONAL, - discSyncConfig-r13 SL-SyncConfigNFreq-r13 OPTIONAL, - discCellSelectionInfo-r13 SEQUENCE { - q-RxLevMin-r13 Q-RxLevMin, - q-RxLevMinOffset-r13 INTEGER (1..8) OPTIONAL - } OPTIONAL, - cellReselectionInfo-r13 SEQUENCE { - q-Hyst-r13 ENUMERATED { - dB0, dB1, dB2, dB3, dB4, dB5, dB6, dB8, dB10, - dB12, dB14, dB16, dB18, dB20, dB22, dB24}, - q-RxLevMin-r13 Q-RxLevMin, - t-ReselectionEUTRA-r13 T-Reselection - } OPTIONAL, - tdd-Config-r13 TDD-Config OPTIONAL, - freqInfo-r13 SEQUENCE { - ul-CarrierFreq-r13 ARFCN-ValueEUTRA OPTIONAL, - ul-Bandwidth-r13 ENUMERATED {n6, n15, n25, n50, n75, n100} - OPTIONAL, - additionalSpectrumEmission-r13 AdditionalSpectrumEmission OPTIONAL - } OPTIONAL, - p-Max-r13 P-Max OPTIONAL, - referenceSignalPower-r13 INTEGER (-60..50) OPTIONAL, - ... + ..., + [[ syncOffsetIndicator-v1430 SL-OffsetIndicatorSync-v1430 OPTIONAL, -- Need OR + gnss-Sync-r14 ENUMERATED {true} OPTIONAL -- Need OR + ]] } @@ -9500,13 +10720,27 @@ SubframeBitmapSL-r12 ::= CHOICE { } SubframeBitmapSL-r14 ::= CHOICE { + bs10-r14 BIT STRING (SIZE (10)), bs16-r14 BIT STRING (SIZE (16)), bs20-r14 BIT STRING (SIZE (20)), + bs30-r14 BIT STRING (SIZE (30)), + bs40-r14 BIT STRING (SIZE (40)), + bs50-r14 BIT STRING (SIZE (50)), + bs60-r14 BIT STRING (SIZE (60)), bs100-r14 BIT STRING (SIZE (100)) } -SL-ThresPSSCH-RSRP-List-r14 ::= SEQUENCE (SIZE (1..64)) OF SL-ThresPSSCH-RSRP-r14 +SL-TxPower-r14 ::= CHOICE { + minusinfinity-r14 NULL, + txPower-r14 INTEGER (-41..31) +} + + +SL-TypeTxSync-r14 ::= ENUMERATED {gnss, enb, ue} + + +SL-ThresPSSCH-RSRP-List-r14 ::= SEQUENCE (SIZE (64)) OF SL-ThresPSSCH-RSRP-r14 SL-ThresPSSCH-RSRP-r14 ::= INTEGER (0..66) @@ -9536,17 +10770,17 @@ SL-V2X-ConfigDedicated-r14 ::= SEQUENCE { release NULL, setup CHOICE { scheduled-r14 SEQUENCE { - sl-D-RNTI-r14 C-RNTI, - mac-MainConfig-r14 MAC-MainConfigSL-r12 OPTIONAL, -- Need OP - v2x-SchedulingPool-r14 SL-CommResourcePoolV2X-r14 OPTIONAL, -- Need OP - mcs-r14 INTEGER (0..31) OPTIONAL, -- Need OP + sl-V-RNTI-r14 C-RNTI, + mac-MainConfig-r14 MAC-MainConfigSL-r12, + v2x-SchedulingPool-r14 SL-CommResourcePoolV2X-r14 OPTIONAL, -- Need ON + mcs-r14 INTEGER (0..31) OPTIONAL, -- Need OR logicalChGroupInfoList-r14 LogicalChGroupInfoList-r13 }, ue-Selected-r14 SEQUENCE { -- Pool for normal usage v2x-CommTxPoolNormalDedicated-r14 SEQUENCE { poolToReleaseList-r14 SL-TxPoolToReleaseListV2X-r14 OPTIONAL, -- Need ON - poolToAddModList-r14 SL-TxPoolToAddModListV2X-r14 OPTIONAL, -- Need ON + poolToAddModList-r14 SL-TxPoolToAddModListV2X-r14 OPTIONAL, -- Need ON v2x-CommTxPoolSensingConfig-r14 SL-CommTxPoolSensingConfig-r14 OPTIONAL -- Need ON } @@ -9554,10 +10788,15 @@ SL-V2X-ConfigDedicated-r14 ::= SEQUENCE { } } OPTIONAL, -- Need ON v2x-InterFreqInfoList-r14 SL-InterFreqInfoListV2X-r14 OPTIONAL, -- Need ON + thresSL-TxPrioritization-r14 SL-Priority-r13 OPTIONAL, -- Need OR + typeTxSync-r14 SL-TypeTxSync-r14 OPTIONAL, -- Need OR + cbr-DedicatedTxConfigList-r14 SL-CBR-CommonTxConfigList-r14 OPTIONAL, -- Need OR ... } -SL-TxPoolToAddModListV2X-r14 ::= SEQUENCE { +SL-TxPoolToAddModListV2X-r14 ::= SEQUENCE (SIZE (1.. maxSL-V2X-TxPool-r14)) OF SL-TxPoolToAddMod-r14 + +SL-TxPoolToAddMod-r14 ::= SEQUENCE { poolIdentity-r14 SL-V2X-TxPoolIdentity-r14, pool-r14 SL-CommResourcePoolV2X-r14 } @@ -9566,10 +10805,10 @@ SL-TxPoolToReleaseListV2X-r14 ::= SEQUENCE (SIZE (1.. maxSL-V2X-TxPool-r14)) O SL-ZoneConfig-r14 ::= SEQUENCE { - zoneLength-r14 ENUMERATED { m5, m10, m20, m50, m100, m200, m500, spare1} OPTIONAL, -- Need OR - zoneWidth-r14 ENUMERATED { m5, m10, m20, m50, m100, m200, m500, spare1} OPTIONAL, -- Need OR - zoneIdLongiMod-r14 INTEGER (1..4) OPTIONAL, -- Need OR - zoneIdLatiMod-r14 INTEGER (1..4) OPTIONAL -- Need OR + zoneLength-r14 ENUMERATED { m5, m10, m20, m50, m100, m200, m500, spare1}, + zoneWidth-r14 ENUMERATED { m5, m10, m20, m50, m100, m200, m500, spare1}, + zoneIdLongiMod-r14 INTEGER (1..4), + zoneIdLatiMod-r14 INTEGER (1..4) } @@ -9582,6 +10821,9 @@ maxBands INTEGER ::= 64 -- Maximum number of bands listed in maxBandwidthClass-r10 INTEGER ::= 16 -- Maximum number of supported CA BW classes per band maxBandwidthCombSet-r10 INTEGER ::= 32 -- Maximum number of bandwidth combination sets per -- supported band combination +maxCBR-Level-r14 INTEGER ::= 16 -- Maximum number of CBR levels +maxCBR-Level-1-r14 INTEGER ::= 15 +maxCBR-Report-r14 INTEGER ::= 72 -- Maximum number of CBR results in a report maxCDMA-BandClass INTEGER ::= 32 -- Maximum value of the CDMA band classes maxCE-Level-r13 INTEGER ::= 4 -- Maximum number of CE levels maxCellBlack INTEGER ::= 16 -- Maximum number of blacklisted physical cell identity @@ -9632,6 +10874,7 @@ maxCellListGERAN INTEGER ::= 3 -- Maximum number of lists of GERAN maxCellMeas INTEGER ::= 32 -- Maximum number of entries in each of the -- cell lists in a measurement object maxCellReport INTEGER ::= 8 -- Maximum number of reported cells/CSI-RS resources +maxConfigSPS-r14 INTEGER ::= 8 -- Maximum number of simultaneous SPS configurations maxCSI-RS-Meas-r12 INTEGER ::= 96 -- Maximum number of entries in the CSI-RS list -- in a measurement object maxDRB INTEGER ::= 11 -- Maximum number of Data Radio Bearers @@ -9651,6 +10894,9 @@ maxFreqIDC-r11 INTEGER ::= 32 -- Maximum number of carrier frequen -- affected by the IDC problems maxFreqMBMS-r11 INTEGER ::= 5 -- Maximum number of carrier frequencies for which an -- MBMS capable UE may indicate an interest +maxFreqV2X-r14 INTEGER ::= 8 -- Maximum number of carrier frequencies for which V2X + -- sidelink communication can be configured +maxFreqV2X-1-r14 INTEGER ::= 7 -- Highest index of frequencies maxGERAN-SI INTEGER ::= 10 -- Maximum number of GERAN SI blocks that can be -- provided as part of NACC information maxGNFG INTEGER ::= 16 -- Maximum number of GERAN neighbour freq groups @@ -9681,6 +10927,7 @@ maxP-a-PerNeighCell-r12 INTEGER ::= 3 -- Maximum number of power offsets f maxPageRec INTEGER ::= 16 -- maxPhysCellIdRange-r9 INTEGER ::= 4 -- Maximum number of physical cell identity ranges maxPLMN-r11 INTEGER ::= 6 -- Maximum number of PLMNs +maxPLMN-1-r14 INTEGER ::= 5 -- Maximum number of PLMNs minus one maxPNOffset INTEGER ::= 511 -- Maximum number of CDMA2000 PNOffsets maxPMCH-PerMBSFN INTEGER ::= 15 maxPSSCH-TxConfig-r14 INTEGER ::= 16 -- Maximum number of PSSCH TX configurations @@ -9690,7 +10937,7 @@ maxRE-MapQCL-r11 INTEGER ::= 4 -- Maximum number of PDSCH RE Mappin -- (per carrier frequency) maxReportConfigId INTEGER ::= 32 maxReservationPeriod-r14 INTEGER ::= 16 -- Maximum number of resource reservation periodicities - -- for sidelink V2X communications + -- for sidelink V2X communication maxRSTD-Freq-r10 INTEGER ::= 3 -- Maximum number of frequency layers for RSTD -- measurement maxSAI-MBMS-r11 INTEGER ::= 64 -- Maximum number of MBMS service area identities @@ -9698,6 +10945,7 @@ maxSAI-MBMS-r11 INTEGER ::= 64 -- Maximum number of MBMS service ar maxSCell-r10 INTEGER ::= 4 -- Maximum number of SCells maxSCell-r13 INTEGER ::= 31 -- Highest value of extended number range of SCells maxSC-MTCH-r13 INTEGER ::= 1023 -- Maximum number of SC-MTCHs in one cell +maxSC-MTCH-BR-r14 INTEGER ::= 128 -- Maximum number of SC-MTCHs in one cell for feMTC maxSL-CommRxPoolNFreq-r13 INTEGER ::= 32 -- Maximum number of individual sidelink communication -- Rx resource pools on neighbouring freq maxSL-CommRxPoolPreconf-v1310 INTEGER ::= 12 -- Maximum number of additional preconfigured @@ -9722,22 +10970,40 @@ maxSL-DiscTxPoolPreconf-r13 INTEGER ::= 4 -- Maximum number of preconfigur -- discovery Tx resource pool entries maxSL-GP-r13 INTEGER ::= 8 -- Maximum number of gap patterns that can be requested -- for a frequency or assigned +maxSL-PoolToMeasure-r14 INTEGER ::= 72 -- Maximum number of TX resource pools for CBR + -- measurement and report maxSL-Prio-r13 INTEGER ::= 8 -- Maximum number of entries in sidelink priority list maxSL-RxPool-r12 INTEGER ::= 16 -- Maximum number of individual sidelink Rx resource pools maxSL-SyncConfig-r12 INTEGER ::= 16 -- Maximum number of sidelink Sync configurations maxSL-TF-IndexPair-r12 INTEGER ::= 64 -- Maximum number of sidelink Time Freq resource index -- pairs maxSL-TxPool-r12 INTEGER ::= 4 -- Maximum number of individual sidelink Tx resource pools -maxSL-V2X-RxPool-r14 INTEGER ::= 16 -- Maximum number of RX resource pools for +maxSL-V2X-RxPool-r14 INTEGER ::= 16 -- Maximum number of RX resource pools for -- V2X sidelink communication -maxSL-V2X-RxPoolPreconf-r14 INTEGER ::= 16 -- Maximum number of RX resource pools for +maxSL-V2X-RxPoolPreconf-r14 INTEGER ::= 16 -- Maximum number of RX resource pools for -- V2X sidelink communication -maxSL-V2X-TxPool-r14 INTEGER ::= 8 -- Maximum number of TX resource pools for +maxSL-V2X-TxPool-r14 INTEGER ::= 8 -- Maximum number of TX resource pools for -- V2X sidelink communication -maxSL-V2X-TxPoolPreconf-r14 INTEGER ::= 8 -- Maximum number of TX resource pools for +maxSL-V2X-TxPoolPreconf-r14 INTEGER ::= 8 -- Maximum number of TX resource pools for -- V2X sidelink communication maxSL-V2X-SyncConfig-r14 INTEGER ::= 16 -- Maximum number of sidelink Sync configurations -- for V2X sidelink communication +maxSL-V2X-CBRConfig-r14 INTEGER ::= 4 -- Maximum number of CBR range configurations + -- for V2X sidelink communication congestion + -- control +maxSL-V2X-CBRConfig-1-r14 INTEGER ::= 3 +maxSL-V2X-TxConfig-r14 INTEGER ::= 64 -- Maximum number of TX parameter configurations + -- for V2X sidelink communication congestion + -- control +maxSL-V2X-TxConfig-1-r14 INTEGER ::= 63 +maxSL-V2X-CBRConfig2-r14 INTEGER ::= 8 -- Maximum number of CBR range configurations in + -- pre-configuration for V2X sidelink + -- communication congestion control +maxSL-V2X-CBRConfig2-1-r14 INTEGER ::= 7 +maxSL-V2X-TxConfig2-r14 INTEGER ::= 128 -- Maximum number of TX parameter + -- configurations in pre-configuration for V2X + -- sidelink communication congestion control +maxSL-V2X-TxConfig2-1-r14 INTEGER ::= 127 maxSTAG-r11 INTEGER ::= 3 -- Maximum number of STAGs maxServCell-r10 INTEGER ::= 5 -- Maximum number of Serving cells maxServCell-r13 INTEGER ::= 32 -- Highest value of extended number range of Serving cells @@ -9753,6 +11019,9 @@ maxSimultaneousBands-r10 INTEGER ::= 64 -- Maximum number of simultaneously maxSubframePatternIDC-r11 INTEGER ::= 8 -- Maximum number of subframe reservation patterns -- that the UE can simultaneously recommend to the -- E-UTRAN for use. +maxTrafficPattern-r14 INTEGER ::= 8 -- Maximum number of periodical traffic patterns + -- that the UE can simultaneously report to the + -- E-UTRAN. maxUTRA-FDD-Carrier INTEGER ::= 16 -- Maximum number of UTRA FDD carrier frequencies maxUTRA-TDD-Carrier INTEGER ::= 16 -- Maximum number of UTRA TDD carrier frequencies maxWLAN-Id-r12 INTEGER ::= 16 -- Maximum number of WLAN identifiers @@ -9761,6 +11030,7 @@ maxWLAN-Id-r13 INTEGER ::= 32 -- Maximum number of WLAN identifier maxWLAN-Channels-r13 INTEGER ::= 16 -- maximum number of WLAN channels used in -- WLAN-CarrierInfo maxWLAN-CarrierInfo-r13 INTEGER ::= 8 -- Maximum number of WLAN Carrier Information +maxWLAN-Id-Report-r14 INTEGER ::= 32 -- Maximum number of WLAN IDs to report END @@ -9782,6 +11052,13 @@ SBCCH-SL-BCH-Message ::= SEQUENCE { SBCCH-SL-BCH-MessageType ::= MasterInformationBlock-SL +SBCCH-SL-BCH-Message-V2X-r14 ::= SEQUENCE { + message SBCCH-SL-BCH-MessageType-V2X-r14 +} + +SBCCH-SL-BCH-MessageType-V2X-r14 ::= MasterInformationBlock-SL-V2X-r14 + + MasterInformationBlock-SL ::= SEQUENCE { sl-Bandwidth-r12 ENUMERATED { n6, n15, n25, n50, n75, n100}, @@ -9794,6 +11071,18 @@ MasterInformationBlock-SL ::= SEQUENCE { +MasterInformationBlock-SL-V2X-r14 ::= SEQUENCE { + sl-Bandwidth-r14 ENUMERATED { + n6, n15, n25, n50, n75, n100}, + tdd-ConfigSL-r14 TDD-ConfigSL-r12, + directFrameNumber-r14 BIT STRING (SIZE (10)), + directSubframeNumber-r14 INTEGER (0..9), + inCoverage-r14 BOOLEAN, + reserved-r14 BIT STRING (SIZE (27)) +} + + + END @@ -9822,8 +11111,12 @@ IMPORTS maxMultiBands, maxPageRec, maxPLMN-r11, + maxSAI-MBMS-r11, maxSIB, maxSIB-1, + MBMS-SAI-r11, + MBMS-SAI-List-r11, + MBMSSessionInfo-r13, NextHopChainingCount, PagingUE-Identity, PLMN-Identity, @@ -9844,8 +11137,12 @@ IMPORTS S-TMSI, SystemInformationBlockType16-r11, SystemInfoValueTagSI-r13, + T-Reordering, TimeAlignmentTimer, - TrackingAreaCode + TMGI-r9, + TrackingAreaCode, + DataInactivityTimer-r14 + FROM EUTRA-RRC-Definitions; @@ -9933,6 +11230,19 @@ UL-CCCH-MessageType-NB ::= CHOICE { } +SC-MCCH-Message-NB ::= SEQUENCE { + message SC-MCCH-MessageType-NB +} + + +SC-MCCH-MessageType-NB ::= CHOICE { + c1 CHOICE { + scptmConfiguration-r14 SCPTMConfiguration-NB-r14 + }, + messageClassExtension SEQUENCE {} +} + + UL-DCCH-Message-NB ::= SEQUENCE { message UL-DCCH-MessageType-NB } @@ -10076,7 +11386,12 @@ RRCConnectionReestablishment-NB-r13-IEs ::= SEQUENCE { radioResourceConfigDedicated-r13 RadioResourceConfigDedicated-NB-r13, nextHopChainingCount-r13 NextHopChainingCount, lateNonCriticalExtension OCTET STRING OPTIONAL, - nonCriticalExtension SEQUENCE {} OPTIONAL + nonCriticalExtension RRCConnectionReestablishment-NB-v1430-IEs OPTIONAL +} + +RRCConnectionReestablishment-NB-v1430-IEs ::= SEQUENCE { + dl-NAS-MAC BIT STRING (SIZE (16)), -- Cond Reestablish-CP + nonCriticalExtension SEQUENCE {} OPTIONAL } @@ -10098,21 +11413,36 @@ RRCConnectionReestablishmentRequest-NB ::= SEQUENCE { criticalExtensions CHOICE { rrcConnectionReestablishmentRequest-r13 RRCConnectionReestablishmentRequest-NB-r13-IEs, - criticalExtensionsFuture SEQUENCE {} + later CHOICE { + rrcConnectionReestablishmentRequest-r14 + RRCConnectionReestablishmentRequest-NB-r14-IEs, + criticalExtensionsFuture SEQUENCE {} + } } } RRCConnectionReestablishmentRequest-NB-r13-IEs ::= SEQUENCE { ue-Identity-r13 ReestabUE-Identity, - reestablishmentCause-r13 ReestablishmentCause-NB-r13, + reestablishmentCause-r13 ReestablishmentCause-NB-r13, spare BIT STRING (SIZE (25)) } +RRCConnectionReestablishmentRequest-NB-r14-IEs ::= SEQUENCE { + ue-Identity-r14 ReestabUE-Identity-CP-NB-r14, + reestablishmentCause-r14 ReestablishmentCause-NB-r13, + spare BIT STRING (SIZE (4)) +} ReestablishmentCause-NB-r13 ::= ENUMERATED { reconfigurationFailure, otherFailure, spare2, spare1} +ReestabUE-Identity-CP-NB-r14 ::= SEQUENCE { + s-TMSI-r14 S-TMSI, + ul-NAS-MAC-r14 BIT STRING (SIZE (16)), + ul-NAS-Count-r14 BIT STRING (SIZE (5)) +} + RRCConnectionReject-NB ::= SEQUENCE { criticalExtensions CHOICE { @@ -10149,15 +11479,29 @@ RRCConnectionRelease-NB-r13-IEs ::= SEQUENCE { extendedWaitTime-r13 INTEGER (1..1800) OPTIONAL, -- Need ON redirectedCarrierInfo-r13 RedirectedCarrierInfo-NB-r13 OPTIONAL, -- Need ON lateNonCriticalExtension OCTET STRING OPTIONAL, + nonCriticalExtension RRCConnectionRelease-NB-v1430-IEs OPTIONAL +} + +RRCConnectionRelease-NB-v1430-IEs ::= SEQUENCE { + redirectedCarrierInfo-v1430 RedirectedCarrierInfo-NB-v1430 OPTIONAL, -- Cond Redirection + extendedWaitTime-CPdata-r14 INTEGER (1..1800) OPTIONAL, -- Cond NoExtendedWaitTime nonCriticalExtension SEQUENCE {} OPTIONAL } - ReleaseCause-NB-r13 ::= ENUMERATED {loadBalancingTAUrequired, other, rrc-Suspend, spare1} - RedirectedCarrierInfo-NB-r13::= CarrierFreq-NB-r13 +RedirectedCarrierInfo-NB-v1430 ::= SEQUENCE { + redirectedCarrierOffsetDedicated-r14 ENUMERATED{ + dB1, dB2, dB3, dB4, dB5, dB6, dB8, dB10, + dB12, dB14, dB16, dB18, dB20, dB22, dB24, dB26}, + t322-r14 ENUMERATED{ + min5, min10, min20, min30, min60, min120, min180, + spare1} +} + + RRCConnectionRequest-NB ::= SEQUENCE { criticalExtensions CHOICE { rrcConnectionRequest-r13 RRCConnectionRequest-NB-r13-IEs, @@ -10259,7 +11603,21 @@ RRCConnectionSetupComplete-NB-r13-IEs ::= SEQUENCE { attachWithoutPDN-Connectivity-r13 ENUMERATED {true} OPTIONAL, up-CIoT-EPS-Optimisation-r13 ENUMERATED {true} OPTIONAL, lateNonCriticalExtension OCTET STRING OPTIONAL, - nonCriticalExtension SEQUENCE {} OPTIONAL + nonCriticalExtension RRCConnectionSetupComplete-NB-v1430-IEs OPTIONAL +} + +RRCConnectionSetupComplete-NB-v1430-IEs ::= SEQUENCE { + gummei-Type-r14 ENUMERATED { mapped} OPTIONAL, + dcn-ID-r14 INTEGER (0..65535) OPTIONAL, + nonCriticalExtension SEQUENCE {} OPTIONAL +} + + +SCPTMConfiguration-NB-r14 ::= SEQUENCE { + sc-mtch-InfoList-r14 SC-MTCH-InfoList-NB-r14, + scptm-NeighbourCellList-r14 SCPTM-NeighbourCellList-NB-r14 OPTIONAL, -- Need OP + lateNonCriticalExtension OCTET STRING OPTIONAL, + nonCriticalExtension SEQUENCE {} OPTIONAL } @@ -10277,7 +11635,10 @@ SystemInformation-NB-r13-IEs ::= SEQUENCE { sib5-r13 SystemInformationBlockType5-NB-r13, sib14-r13 SystemInformationBlockType14-NB-r13, sib16-r13 SystemInformationBlockType16-NB-r13, - ... + ..., + sib15-v1430 SystemInformationBlockType15-NB-r14, + sib20-v1430 SystemInformationBlockType20-NB-r14, + sib22-v1430 SystemInformationBlockType22-NB-r14 }, lateNonCriticalExtension OCTET STRING OPTIONAL, nonCriticalExtension SEQUENCE {} OPTIONAL @@ -10315,6 +11676,16 @@ SystemInformationBlockType1-NB ::= SEQUENCE { si-RadioFrameOffset-r13 INTEGER (1..15) OPTIONAL, -- Need OP systemInfoValueTagList-r13 SystemInfoValueTagList-NB-r13 OPTIONAL, -- Need OR lateNonCriticalExtension OCTET STRING OPTIONAL, + nonCriticalExtension SystemInformationBlockType1-NB-v1350 OPTIONAL +} + +SystemInformationBlockType1-NB-v1350 ::= SEQUENCE { + cellSelectionInfo-v1350 CellSelectionInfo-NB-v1350 OPTIONAL, -- Cond Qrxlevmin + nonCriticalExtension SystemInformationBlockType1-NB-v1430 OPTIONAL +} + +SystemInformationBlockType1-NB-v1430 ::= SEQUENCE { + cellSelectionInfo-v1430 CellSelectionInfo-NB-v1430 OPTIONAL, -- Need OR nonCriticalExtension SEQUENCE {} OPTIONAL } @@ -10344,8 +11715,17 @@ SIB-MappingInfo-NB-r13 ::= SEQUENCE (SIZE (0..maxSIB-1)) OF SIB-Type-NB SIB-Type-NB-r13 ::= ENUMERATED { sibType3-NB-r13, sibType4-NB-r13, sibType5-NB-r13, - sibType14-NB-r13, sibType16-NB-r13, spare3, spare2, spare1} + sibType14-NB-r13, sibType16-NB-r13, sibType15-NB-r14, sibType20-NB-r14, + sibType22-NB-r14} +CellSelectionInfo-NB-v1350 ::= SEQUENCE { + delta-RxLevMin-v1350 INTEGER (-8..-1) +} + +CellSelectionInfo-NB-v1430 ::= SEQUENCE { + powerClass14dBm-Offset-r14 ENUMERATED {dB-6, dB-3, dB3, dB6, dB9, dB12} OPTIONAL, -- Need OP + ce-authorisationOffset-r14 ENUMERATED {dB5, dB10, dB15, dB20, dB25, dB30, dB35} OPTIONAL -- Need OP +} UECapabilityEnquiry-NB ::= SEQUENCE { @@ -10399,13 +11779,15 @@ SystemInformationBlockType2-NB-r13 ::= SEQUENCE { radioResourceConfigCommon-r13 RadioResourceConfigCommonSIB-NB-r13, ue-TimersAndConstants-r13 UE-TimersAndConstants-NB-r13, freqInfo-r13 SEQUENCE { - ul-CarrierFreq-r13 CarrierFreq-NB-r13 OPTIONAL,-- Need OP + ul-CarrierFreq-r13 CarrierFreq-NB-r13 OPTIONAL, -- Need OP additionalSpectrumEmission-r13 AdditionalSpectrumEmission }, timeAlignmentTimerCommon-r13 TimeAlignmentTimer, - multiBandInfoList-r13 SEQUENCE (SIZE (1..maxMultiBands)) OF AdditionalSpectrumEmission OPTIONAL,-- Need OR + multiBandInfoList-r13 SEQUENCE (SIZE (1..maxMultiBands)) OF AdditionalSpectrumEmission OPTIONAL, -- Need OR lateNonCriticalExtension OCTET STRING OPTIONAL, - ... + ..., + [[ cp-Reestablishment-r14 ENUMERATED {true} OPTIONAL -- Need OP + ]] } @@ -10430,7 +11812,26 @@ SystemInformationBlockType3-NB-r13 ::= SEQUENCE { multiBandInfoList-r13 SEQUENCE (SIZE (1..maxMultiBands)) OF NS-PmaxList-NB-r13 OPTIONAL, -- Need OR lateNonCriticalExtension OCTET STRING OPTIONAL, - ... + ..., + [[ intraFreqCellReselectionInfo-v1350 IntraFreqCellReselectionInfo-NB-v1350 OPTIONAL -- Cond Qrxlevmin + ]], + [[ intraFreqCellReselectionInfo-v1360 IntraFreqCellReselectionInfo-NB-v1360 OPTIONAL -- Need OR + ]], + [[ intraFreqCellReselectionInfo-v1430 IntraFreqCellReselectionInfo-NB-v1430 OPTIONAL -- Need OR + ]] +} + +IntraFreqCellReselectionInfo-NB-v1350 ::= SEQUENCE { + delta-RxLevMin-v1350 INTEGER (-8..-1) +} + +IntraFreqCellReselectionInfo-NB-v1360 ::= SEQUENCE { + s-IntraSearchP-v1360 ReselectionThreshold-NB-v1360 +} + +IntraFreqCellReselectionInfo-NB-v1430 ::= SEQUENCE { + powerClass14dBm-Offset-r14 ENUMERATED {dB-6, dB-3, dB3, dB6, dB9, dB12} OPTIONAL, -- Need OP + ce-AuthorisationOffset-r14 ENUMERATED {dB5, dB10, dB15, dB20, dB25, dB30, dB35} OPTIONAL -- Need OP } @@ -10447,7 +11848,9 @@ SystemInformationBlockType5-NB-r13 ::= SEQUENCE { interFreqCarrierFreqList-r13 InterFreqCarrierFreqList-NB-r13, t-Reselection-r13 T-Reselection-NB-r13, lateNonCriticalExtension OCTET STRING OPTIONAL, - ... + ..., + [[ scptm-FreqOffset-r14 INTEGER (1..8) OPTIONAL -- Need OP + ]] } @@ -10463,7 +11866,13 @@ InterFreqCarrierFreqInfo-NB-r13 ::= SEQUENCE { interFreqNeighCellList-r13 InterFreqNeighCellList-NB-r13 OPTIONAL, -- Need OR interFreqBlackCellList-r13 InterFreqBlackCellList-NB-r13 OPTIONAL, -- Need OR multiBandInfoList-r13 MultiBandInfoList-NB-r13 OPTIONAL, -- Need OR - ... + ..., + [[ delta-RxLevMin-v1350 INTEGER (-8..-1) OPTIONAL -- Cond Qrxlevmin + ]], + [[ powerClass14dBm-Offset-r14 ENUMERATED {dB-6, dB-3, dB3, dB6, dB9, dB12} +OPTIONAL, -- Need OP + ce-AuthorisationOffset-r14 ENUMERATED {dB5, dB10, dB15, dB20, dB25, dB30, dB35} OPTIONAL -- Need OP + ]] } InterFreqNeighCellList-NB-r13 ::= SEQUENCE (SIZE (1..maxCellInter)) OF PhysCellId @@ -10489,14 +11898,176 @@ AB-ConfigPLMN-NB-r13 ::= SEQUENCE { AB-Config-NB-r13 ::= SEQUENCE { ab-Category-r13 ENUMERATED {a, b, c}, ab-BarringBitmap-r13 BIT STRING (SIZE(10)), - ab-BarringExceptionData-r13 ENUMERATED {true} OPTIONAL, -- Need OP + ab-BarringForExceptionData-r13 ENUMERATED {true} OPTIONAL, -- Need OP ab-BarringForSpecialAC-r13 BIT STRING (SIZE(5)) } +SystemInformationBlockType15-NB-r14 ::= SEQUENCE { + mbms-SAI-IntraFreq-r14 MBMS-SAI-List-r11 OPTIONAL, -- Need OR + mbms-SAI-InterFreqList-r14 MBMS-SAI-InterFreqList-NB-r14 OPTIONAL, -- Need OR + lateNonCriticalExtension OCTET STRING OPTIONAL, + ... +} + +MBMS-SAI-InterFreqList-NB-r14 ::= SEQUENCE (SIZE (1..maxFreq)) OF MBMS-SAI-InterFreq-NB-r14 + +MBMS-SAI-InterFreq-NB-r14 ::= SEQUENCE { + dl-CarrierFreq-r14 CarrierFreq-NB-r13, + mbms-SAI-List-r14 MBMS-SAI-List-r11, + multiBandInfoList-r14 AdditionalBandInfoList-NB-r14 OPTIONAL -- Need OR +} + + SystemInformationBlockType16-NB-r13 ::= SystemInformationBlockType16-r11 +SystemInformationBlockType20-NB-r14 ::= SEQUENCE { + npdcch-SC-MCCH-Config-r14 NPDCCH-SC-MCCH-Config-NB-r14, + sc-mcch-CarrierConfig-r14 CHOICE { + dl-CarrierConfig-r14 DL-CarrierConfigCommon-NB-r14, + dl-CarrierIndex-r14 INTEGER (0.. maxNonAnchorCarriers-NB-r14) + }, + sc-mcch-RepetitionPeriod-r14 ENUMERATED {rf32, rf128, rf512, rf1024, + rf2048, rf4096, rf8192, rf16384}, + sc-mcch-Offset-r14 INTEGER (0..10), + sc-mcch-ModificationPeriod-r14 ENUMERATED { rf32, rf128, rf256, rf512, rf1024, + rf2048, rf4096, rf8192, rf16384, rf32768, + rf65536, rf131072, rf262144, rf524288, + rf1048576, spare1}, + sc-mcch-SchedulingInfo-r14 SC-MCCH-SchedulingInfo-NB-r14 OPTIONAL, -- Need OP + lateNonCriticalExtension OCTET STRING OPTIONAL, + ... +} + +NPDCCH-SC-MCCH-Config-NB-r14 ::= SEQUENCE { + npdcch-NumRepetitions-SC-MCCH-r14 ENUMERATED {r1, r2, r4, r8, r16, + r32, r64, r128, r256, + r512, r1024, r2048}, + npdcch-StartSF-SC-MCCH-r14 ENUMERATED {v1dot5, v2, v4, v8, + v16, v32, v48, v64}, + npdcch-Offset-SC-MCCH-r14 ENUMERATED {zero, oneEighth, oneQuarter, + threeEighth, oneHalf, fiveEighth, + threeQuarter, sevenEighth} +} + +SC-MCCH-SchedulingInfo-NB-r14::= SEQUENCE { + onDurationTimerSCPTM-r14 ENUMERATED { + pp1, pp2, pp3, pp4, + pp8, pp16, pp32, spare}, + drx-InactivityTimerSCPTM-r14 ENUMERATED { + pp0, pp1, pp2, pp3, + pp4, pp8, pp16, pp32}, + schedulingPeriodStartOffsetSCPTM-r14 CHOICE { + sf10 INTEGER(0..9), + sf20 INTEGER(0..19), + sf32 INTEGER(0..31), + sf40 INTEGER(0..39), + sf64 INTEGER(0..63), + sf80 INTEGER(0..79), + sf128 INTEGER(0..127), + sf160 INTEGER(0..159), + sf256 INTEGER(0..255), + sf320 INTEGER(0..319), + sf512 INTEGER(0..511), + sf640 INTEGER(0..639), + sf1024 INTEGER(0..1023), + sf2048 INTEGER(0..2047), + sf4096 INTEGER(0..4095), + sf8192 INTEGER(0..8191) + }, + ... +} + + +SystemInformationBlockType22-NB-r14 ::= SEQUENCE { + dl-ConfigList-r14 DL-ConfigCommonList-NB-r14 OPTIONAL, -- Need OR + ul-ConfigList-r14 UL-ConfigCommonList-NB-r14 OPTIONAL, -- Need OR + pagingWeightAnchor-r14 PagingWeight-NB-r14 OPTIONAL, -- Cond pcch-config + nprach-ProbabilityAnchorList-r14 NPRACH-ProbabilityAnchorList-NB-r14 OPTIONAL, -- Cond nprach-config + lateNonCriticalExtension OCTET STRING OPTIONAL, + ... +} + +DL-ConfigCommonList-NB-r14 ::= SEQUENCE (SIZE (1.. maxNonAnchorCarriers-NB-r14)) OF + DL-ConfigCommon-NB-r14 + +UL-ConfigCommonList-NB-r14 ::= SEQUENCE (SIZE (1.. maxNonAnchorCarriers-NB-r14)) OF + UL-ConfigCommon-NB-r14 + + +DL-ConfigCommon-NB-r14 ::= SEQUENCE { + dl-CarrierConfig-r14 DL-CarrierConfigCommon-NB-r14, + pcch-Config-r14 PCCH-Config-NB-r14 OPTIONAL, -- Need OR + ... +} + +PCCH-Config-NB-r14 ::= SEQUENCE { + npdcch-NumRepetitionPaging-r14 ENUMERATED { + r1, r2, r4, r8, r16, r32, r64, r128, + r256, r512, r1024, r2048, + spare4, spare3, spare2, spare1} OPTIONAL, -- Need OP + pagingWeight-r14 PagingWeight-NB-r14 DEFAULT w1, + ... +} + +PagingWeight-NB-r14 ::= ENUMERATED {w1, w2, w3, w4, w5, w6, w7, w8, + w9, w10, w11, w12, w13, w14, w15, w16} + +UL-ConfigCommon-NB-r14 ::= SEQUENCE { + ul-CarrierFreq-r14 CarrierFreq-NB-r13, + nprach-ParametersList-r14 NPRACH-ParametersList-NB-r14 OPTIONAL, -- Need OR + ... +} + +NPRACH-ParametersList-NB-r14 ::= SEQUENCE (SIZE (1.. maxNPRACH-Resources-NB-r13)) OF + NPRACH-Parameters-NB-r14 + + +NPRACH-Parameters-NB-r14 ::= SEQUENCE { + nprach-Parameters-r14 SEQUENCE { + nprach-Periodicity-r14 ENUMERATED {ms40, ms80, ms160, ms240, + ms320, ms640, ms1280, ms2560} + OPTIONAL, -- NEED OP + nprach-StartTime-r14 ENUMERATED {ms8, ms16, ms32, ms64, + ms128, ms256, ms512, ms1024} + OPTIONAL, -- NEED OP + nprach-SubcarrierOffset-r14 ENUMERATED {n0, n12, n24, n36, n2, n18, n34, spare1} + OPTIONAL, -- NEED OP + nprach-NumSubcarriers-r14 ENUMERATED {n12, n24, n36, n48} + OPTIONAL, -- NEED OP + nprach-SubcarrierMSG3-RangeStart-r14 ENUMERATED {zero, oneThird, twoThird, one} + OPTIONAL, -- NEED OP + npdcch-NumRepetitions-RA-r14 ENUMERATED {r1, r2, r4, r8, r16, r32, r64, r128, + r256, r512, r1024, r2048, + spare4, spare3, spare2, spare1} + OPTIONAL, -- NEED OP + npdcch-StartSF-CSS-RA-r14 ENUMERATED {v1dot5, v2, v4, v8, v16, v32, v48, v64} + OPTIONAL, -- NEED OP + npdcch-Offset-RA-r14 ENUMERATED {zero, oneEighth, oneFourth, threeEighth} + OPTIONAL, -- NEED OP + nprach-NumCBRA-StartSubcarriers-r14 ENUMERATED {n8, n10, n11, n12, n20, n22, n23, n24, + n32, n34, n35, n36, n40, n44, n46, n48} + OPTIONAL, -- NEED OP + npdcch-CarrierIndex-r14 INTEGER (1..maxNonAnchorCarriers-NB-r14) + OPTIONAL, -- Need OP + ... + } OPTIONAL -- Need OR +} + +NPRACH-ProbabilityAnchorList-NB-r14 ::= SEQUENCE (SIZE (1.. maxNPRACH-Resources-NB-r13)) OF + NPRACH-ProbabilityAnchor-NB-r14 + +NPRACH-ProbabilityAnchor-NB-r14 ::= SEQUENCE { + nprach-ProbabilityAnchor-r14 ENUMERATED { + zero, oneSixteenth, oneFifteenth, oneFourteenth, + oneThirteenth, oneTwelfth, oneEleventh, oneTenth, + oneNinth, oneEightth, oneSeventh, oneSixth, + oneFifth, oneFourth, oneThird, oneHalf} + OPTIONAL -- Need OP +} + + CarrierConfigDedicated-NB-r13 ::= SEQUENCE { dl-CarrierConfig-r13 DL-CarrierConfigDedicated-NB-r13, ul-CarrierConfig-r13 UL-CarrierConfigDedicated-NB-r13 @@ -10555,6 +12126,35 @@ DL-Bitmap-NB-r13 ::= CHOICE { } +DL-CarrierConfigCommon-NB-r14 ::= SEQUENCE { + dl-CarrierFreq-r14 CarrierFreq-NB-r13, + downlinkBitmapNonAnchor-r14 CHOICE { + useNoBitmap-r14 NULL, + useAnchorBitmap-r14 NULL, + explicitBitmapConfiguration-r14 DL-Bitmap-NB-r13 + }, + dl-GapNonAnchor-r14 CHOICE { + useNoGap-r14 NULL, + useAnchorGapConfig-r14 NULL, + explicitGapConfiguration-r14 DL-GapConfig-NB-r13 + }, + inbandCarrierInfo-r14 SEQUENCE { + samePCI-Indicator-r14 CHOICE { + samePCI-r14 SEQUENCE { + indexToMidPRB-r14 INTEGER (-55..54) + }, + differentPCI-r14 SEQUENCE { + eutra-NumCRS-Ports-r14 ENUMERATED {same, four} + } + } OPTIONAL, -- Cond anchor-guardband + eutraControlRegionSize-r14 ENUMERATED {n1, n2, n3} + } OPTIONAL, -- Cond non-anchor-inband + nrs-PowerOffsetNonAnchor-r14 ENUMERATED {dB-12, dB-10, dB-8, dB-6, + dB-4, dB-2, dB0, dB3} DEFAULT dB0, + ... +} + + DL-GapConfig-NB-r13 ::= SEQUENCE { dl-GapThreshold-r13 ENUMERATED {n32, n64, n128, n256}, @@ -10585,7 +12185,19 @@ MAC-MainConfig-NB-r13 ::= SEQUENCE { pp1024, pp2048, spare} } } OPTIONAL, -- Need ON - ... + ..., + [[ rai-Activation-r14 ENUMERATED {true} OPTIONAL, -- Need OR + dataInactivityTimerConfig-r14 CHOICE { + release NULL, + setup SEQUENCE { + dataInactivityTimer-r14 DataInactivityTimer-r14 + } + } OPTIONAL -- Need ON + ]], + [[ drx-Cycle-v1430 ENUMERATED { + sf1280, sf2560, sf5120, sf10240} OPTIONAL -- Need ON + ]] + } PeriodicBSR-Timer-NB-r13 ::= ENUMERATED { @@ -10735,11 +12347,12 @@ PhysicalConfigDedicated-NB-r13 ::= SEQUENCE { npdcch-ConfigDedicated-r13 NPDCCH-ConfigDedicated-NB-r13 OPTIONAL, -- Need ON npusch-ConfigDedicated-r13 NPUSCH-ConfigDedicated-NB-r13 OPTIONAL, -- Need ON uplinkPowerControlDedicated-r13 UplinkPowerControlDedicated-NB-r13 OPTIONAL, -- Need ON - ... + ..., + [[ twoHARQ-ProcessesConfig-r14 ENUMERATED {true} OPTIONAL -- Need OR + ]] } - RACH-ConfigCommon-NB-r13 ::= SEQUENCE { preambleTransMax-CE-r13 PreambleTransMax, powerRampingParameters-r13 PowerRampingParameters, @@ -10815,7 +12428,9 @@ SRB-ToAddMod-NB-r13 ::= SEQUENCE { explicitValue LogicalChannelConfig-NB-r13, defaultValue NULL } OPTIONAL, -- Cond Setup - ... + ..., + [[ rlc-Config-v1430 RLC-Config-NB-v1430 OPTIONAL -- Need ON + ]] } DRB-ToAddModList-NB-r13 ::= SEQUENCE (SIZE (1..maxDRB-NB-r13)) OF DRB-ToAddMod-NB-r13 @@ -10827,7 +12442,9 @@ DRB-ToAddMod-NB-r13 ::= SEQUENCE { rlc-Config-r13 RLC-Config-NB-r13 OPTIONAL, -- Cond Setup logicalChannelIdentity-r13 INTEGER (3..10) OPTIONAL, -- Cond DRB-Setup logicalChannelConfig-r13 LogicalChannelConfig-NB-r13 OPTIONAL, -- Cond Setup - ... + ..., + [[ rlc-Config-v1430 RLC-Config-NB-v1430 OPTIONAL -- Need ON + ]] } DRB-ToReleaseList-NB-r13 ::= SEQUENCE (SIZE (1..maxDRB-NB-r13)) OF DRB-Identity @@ -10841,6 +12458,9 @@ RLC-Config-NB-r13 ::= CHOICE { ... } +RLC-Config-NB-v1430 ::= SEQUENCE { + t-Reordering-r14 T-Reordering OPTIONAL -- Cond twoHARQ +} UL-AM-RLC-NB-r13 ::= SEQUENCE { t-PollRetransmit-r13 T-PollRetransmit-NB-r13, @@ -10874,7 +12494,11 @@ RLF-TimersAndConstants-NB-r13 ::= CHOICE { ms20000, ms30000}, n311-r13 ENUMERATED { n1, n2, n3, n4, n5, n6, n8, n10}, - ... + ..., + [[ t311-v1350 ENUMERATED { + ms40000, ms60000, ms90000, ms120000} + OPTIONAL -- Need OR + ]] } } @@ -10891,6 +12515,9 @@ UplinkPowerControlDedicated-NB-r13 ::= SEQUENCE { } +AdditionalBandInfoList-NB-r14 ::= SEQUENCE (SIZE (1..maxMultiBands)) OF FreqBandIndicator-NB-r13 + + FreqBandIndicator-NB-r13 ::= INTEGER (1.. maxFBI2) @@ -10910,6 +12537,9 @@ NS-PmaxValue-NB-r13 ::= SEQUENCE { } +ReselectionThreshold-NB-v1360 ::= INTEGER (32..63) + + T-Reselection-NB-r13 ::= ENUMERATED {s0, s3, s6, s9, s12, s15, s18, s21} @@ -10925,10 +12555,17 @@ UE-Capability-NB-r13 ::= SEQUENCE { pdcp-Parameters-r13 PDCP-Parameters-NB-r13 OPTIONAL, phyLayerParameters-r13 PhyLayerParameters-NB-r13, rf-Parameters-r13 RF-Parameters-NB-r13, - nonCriticalExtension SEQUENCE {} OPTIONAL + nonCriticalExtension UE-Capability-NB-v1430-IEs OPTIONAL } -AccessStratumRelease-NB-r13 ::= ENUMERATED {rel13, spare7, spare6, spare5, spare4, spare3, spare2, spare1, ...} +UE-Capability-NB-v1430-IEs ::= SEQUENCE { + ue-Category-NB-r14 ENUMERATED {nb2} OPTIONAL, + mac-Parameters-r14 MAC-Parameters-NB-r14 OPTIONAL, phyLayerParameters-v1430 PhyLayerParameters-NB-v1430 OPTIONAL, + rf-Parameters-v1430 RF-Parameters-NB-v1430, + nonCriticalExtension SEQUENCE {} OPTIONAL +} + +AccessStratumRelease-NB-r13 ::= ENUMERATED {rel13, rel14, spare6, spare5, spare4, spare3, spare2, spare1, ...} PDCP-Parameters-NB-r13 ::= SEQUENCE { supportedROHC-Profiles-r13 SEQUENCE { @@ -10944,16 +12581,30 @@ PDCP-Parameters-NB-r13 ::= SEQUENCE { ... } +MAC-Parameters-NB-r14 ::= SEQUENCE { + dataInactMon-r14 ENUMERATED {supported} OPTIONAL, + rai-Support-r14 ENUMERATED {supported} OPTIONAL +} + PhyLayerParameters-NB-r13 ::= SEQUENCE { multiTone-r13 ENUMERATED {supported} OPTIONAL, multiCarrier-r13 ENUMERATED {supported} OPTIONAL } +PhyLayerParameters-NB-v1430 ::= SEQUENCE { + multiCarrier-NPRACH-r14 ENUMERATED {supported} OPTIONAL, + twoHARQ-Processes-r14 ENUMERATED {supported} OPTIONAL +} + RF-Parameters-NB-r13 ::= SEQUENCE { supportedBandList-r13 SupportedBandList-NB-r13, multiNS-Pmax-r13 ENUMERATED {supported} OPTIONAL } +RF-Parameters-NB-v1430 ::= SEQUENCE { + powerClassNB-14dBm-r14 ENUMERATED {supported} OPTIONAL +} + SupportedBandList-NB-r13 ::= SEQUENCE (SIZE (1..maxBands)) OF SupportedBand-NB-r13 SupportedBand-NB-r13 ::= SEQUENCE { @@ -10962,10 +12613,11 @@ SupportedBand-NB-r13 ::= SEQUENCE { } - UE-RadioPagingInfo-NB-r13 ::= SEQUENCE { ue-Category-NB-r13 ENUMERATED {nb1} OPTIONAL, - ... + ..., + [[ multiCarrierPaging-r14 ENUMERATED {true} OPTIONAL + ]] } @@ -10985,13 +12637,81 @@ UE-TimersAndConstants-NB-r13 ::= SEQUENCE { ms20000, ms30000}, n311-r13 ENUMERATED { n1, n2, n3, n4, n5, n6, n8, n10}, + ..., + [[ t311-v1350 ENUMERATED { + ms40000, ms60000, ms90000, ms120000} + OPTIONAL -- Need OR + ]] +} + + +SC-MTCH-InfoList-NB-r14 ::= SEQUENCE (SIZE (0.. maxSC-MTCH-NB-r14)) OF SC-MTCH-Info-NB-r14 + +SC-MTCH-Info-NB-r14 ::= SEQUENCE { + sc-mtch-CarrierConfig-r14 CHOICE { + dl-CarrierConfig-r14 DL-CarrierConfigCommon-NB-r14, + dl-CarrierIndex-r14 INTEGER (0.. maxNonAnchorCarriers-NB-r14) + }, + mbmsSessionInfo-r14 MBMSSessionInfo-r13, + g-RNTI-r14 BIT STRING(SIZE(16)), + sc-mtch-SchedulingInfo-r14 SC-MTCH-SchedulingInfo-NB-r14 OPTIONAL, -- Need OP + sc-mtch-NeighbourCell-r14 BIT STRING (SIZE(maxNeighCell-SCPTM-NB-r14)) OPTIONAL, -- Need OP + npdcch-NPDSCH-MaxTBS-SC-MTCH-r14 ENUMERATED {n680, n2536}, + npdcch-NumRepetitions-SC-MTCH-r14 ENUMERATED {r1, r2, r4, r8, r16, + r32, r64, r128, r256, + r512, r1024, r2048, spare4, + spare3, spare2, spare1}, + npdcch-StartSF-SC-MTCH-r14 ENUMERATED {v1dot5, v2, v4, v8, + v16, v32, v48, v64}, + npdcch-Offset-SC-MTCH-r14 ENUMERATED {zero, oneEight, oneQuarter, + threeEight, oneHalf, fiveEight, + threeQuarter, sevenEight}, + ... +} + +SC-MTCH-SchedulingInfo-NB-r14 ::= SEQUENCE { + onDurationTimerSCPTM-r14 ENUMERATED { + pp1, pp2, pp3, pp4, + pp8, pp16, pp32, spare}, + drx-InactivityTimerSCPTM-r14 ENUMERATED { + pp0, pp1, pp2, pp3, + pp4, pp8, pp16, pp32}, + schedulingPeriodStartOffsetSCPTM-r14 CHOICE { + sf10 INTEGER(0..9), + sf20 INTEGER(0..19), + sf32 INTEGER(0..31), + sf40 INTEGER(0..39), + sf64 INTEGER(0..63), + sf80 INTEGER(0..79), + sf128 INTEGER(0..127), + sf160 INTEGER(0..159), + sf256 INTEGER(0..255), + sf320 INTEGER(0..319), + sf512 INTEGER(0..511), + sf640 INTEGER(0..639), + sf1024 INTEGER(0..1023), + sf2048 INTEGER(0..2047), + sf4096 INTEGER(0..4095), + sf8192 INTEGER(0..8191) + }, ... } +SCPTM-NeighbourCellList-NB-r14 ::= SEQUENCE (SIZE (1..maxNeighCell-SCPTM-NB-r14)) OF PCI-ARFCN-NB-r14 + +PCI-ARFCN-NB-r14 ::= SEQUENCE { + physCellId-r14 PhysCellId, + carrierFreq-r14 CarrierFreq-NB-r13 OPTIONAL -- Need OP +} + + maxNPRACH-Resources-NB-r13 INTEGER ::= 3 -- Maximum number of NPRACH resources for NB-IoT +maxNonAnchorCarriers-NB-r14 INTEGER ::= 15 -- Maximum number of non-anchor carriers for NB-IoT maxDRB-NB-r13 INTEGER ::= 2 -- Maximum number of Data Radio Bearers for NB-IoT +maxNeighCell-SCPTM-NB-r14 INTEGER ::= 8 -- Maximum number of SCPTM neighbour cells maxNS-Pmax-NB-r13 INTEGER ::= 4 -- Maximum number of NS and P-Max values per band +maxSC-MTCH-NB-r14 INTEGER ::= 64 -- Maximum number of SC-MTCHs in one cell for NB-IoT maxSI-Message-NB-r13 INTEGER ::= 8 -- Maximum number of SI messages for NB-IoT @@ -11039,6 +12759,7 @@ IMPORTS RLF-Report-r9, TargetMBSFN-AreaList-r12, TraceReference-r10, + Tx-ResourcePoolMeasList-r14, VisitedCellInfoList-r12, maxCellMeas, maxCSI-RS-Meas-r12, @@ -11048,8 +12769,9 @@ IMPORTS WLAN-CarrierInfo-r13, WLAN-Identifiers-r12, WLAN-Id-List-r13, - WLAN-Status-r13 - + WLAN-Status-r13, + WLAN-Status-v1430, + WLAN-SuspendConfig-r14 FROM EUTRA-RRC-Definitions; @@ -11139,6 +12861,7 @@ VarMeasReport ::= SEQUENCE { measId-v1250 MeasId-v1250 OPTIONAL, cellsTriggeredList CellsTriggeredList OPTIONAL, csi-RS-TriggeredList-r12 CSI-RS-TriggeredList-r12 OPTIONAL, + poolsTriggeredList-r14 Tx-ResourcePoolMeasList-r14 OPTIONAL, numberOfReportsSent INTEGER } @@ -11178,6 +12901,7 @@ VarShortMAC-Input ::= SEQUENCE { c-RNTI C-RNTI } + VarShortResumeMAC-Input-r13 ::= SEQUENCE { cellIdentity-r13 CellIdentity, physCellId-r13 PhysCellId, @@ -11188,12 +12912,14 @@ VarShortResumeMAC-Input-r13 ::= SEQUENCE { VarWLAN-MobilityConfig ::= SEQUENCE { wlan-MobilitySet-r13 WLAN-Id-List-r13 OPTIONAL, - successReportRequested ENUMERATED {true} OPTIONAL + successReportRequested ENUMERATED {true} OPTIONAL, + wlan-SuspendConfig-r14 WLAN-SuspendConfig-r14 OPTIONAL } VarWLAN-Status-r13 ::= SEQUENCE { - status-r13 WLAN-Status-r13 + status-r13 WLAN-Status-r13, + status-r14 WLAN-Status-v1430 OPTIONAL } @@ -11219,7 +12945,6 @@ VarShortMAC-Input-NB-r13 ::= VarShortMAC-Input VarShortResumeMAC-Input-NB-r13 ::= VarShortResumeMAC-Input-r13 - END @@ -11231,22 +12956,32 @@ IMPORTS AdditionalSpectrumEmission, ARFCN-ValueEUTRA-r9, FilterCoefficient, + maxCBR-Level-r14, + maxCBR-Level-1-r14, maxFreq, + maxFreqV2X-r14, maxSL-TxPool-r12, maxSL-CommRxPoolPreconf-v1310, maxSL-CommTxPoolPreconf-v1310, maxSL-DiscRxPoolPreconf-r13, maxSL-DiscTxPoolPreconf-r13, + maxSL-V2X-CBRConfig2-r14, + maxSL-V2X-CBRConfig2-1-r14, maxSL-V2X-RxPoolPreconf-r14, + maxSL-V2X-TxConfig2-r14, + maxSL-V2X-TxConfig2-1-r14, maxSL-V2X-TxPoolPreconf-r14, P-Max, ReselectionInfoRelay-r13, + SL-AnchorCarrierFreqList-V2X-r14, + SL-CBR-Levels-Config-r14, + SL-CBR-PSSCH-TxConfig-r14, SL-CommTxPoolSensingConfig-r14, SL-CP-Len-r12, SL-HoppingConfigComm-r12, SL-OffsetIndicator-r12, SL-OffsetIndicatorSync-r12, - SL-OffsetIndicatorSync-v14xy, + SL-OffsetIndicatorSync-v1430, SL-PeriodComm-r12, RSRP-RangeSL3-r12, SL-PriorityList-r13, @@ -11256,7 +12991,12 @@ IMPORTS SL-ZoneConfig-r14, P0-SL-r12, TDD-ConfigSL-r12, - SubframeBitmapSL-r14 + SubframeBitmapSL-r14, + SL-P2X-ResourceSelectionConfig-r14, + SL-RestrictResourceReservationPeriodList-r14, + SL-SyncAllowed-r14, + SL-OffsetIndicatorSync-r14, + SL-Priority-r13 FROM EUTRA-RRC-Definitions; @@ -11310,9 +13050,6 @@ SL-PreconfigSync-r12 ::= SEQUENCE { syncRefDiffHyst-r12 ENUMERATED {dB0, dB3, dB6, dB9, dB12, dBinf}, ..., [[ syncTxPeriodic-r13 ENUMERATED {true} OPTIONAL - ]], - [[ syncOffsetIndicator1-v14xy SL-OffsetIndicatorSync-v14xy OPTIONAL, - syncOffsetIndicator2-v14xy SL-OffsetIndicatorSync-v14xy OPTIONAL ]] } @@ -11362,15 +13099,31 @@ SL-PreconfigRelay-r13 ::= SEQUENCE { } -SL-V2X-Preconfiguration-r14 ::= SEQUENCE (SIZE (1..maxFreq)) OF SL-V2X-PreconfigFreqInfo-r14 +SL-V2X-Preconfiguration-r14 ::= SEQUENCE { + v2x-PreconfigFreqList-r14 SL-V2X-PreconfigFreqList-r14, + anchorCarrierFreqList-r14 SL-AnchorCarrierFreqList-V2X-r14 OPTIONAL, + cbr-PreconfigList-r14 SL-CBR-PreconfigTxConfigList-r14 OPTIONAL, + ... +} + +SL-CBR-PreconfigTxConfigList-r14 ::= SEQUENCE { + cbr-RangeCommonConfigList-r14 SEQUENCE (SIZE (1..maxSL-V2X-CBRConfig2-r14)) OF SL-CBR-Levels-Config-r14, + sl-CBR-PSSCH-TxConfigList-r14 SEQUENCE (SIZE (1..maxSL-V2X-TxConfig2-r14)) OF SL-CBR-PSSCH-TxConfig-r14 +} + +SL-V2X-PreconfigFreqList-r14 ::= SEQUENCE (SIZE (1..maxFreqV2X-r14)) OF SL-V2X-PreconfigFreqInfo-r14 SL-V2X-PreconfigFreqInfo-r14 ::= SEQUENCE { v2x-CommPreconfigGeneral-r14 SL-PreconfigGeneral-r12, - v2x-CommPreconfigSync-r14 SL-PreconfigSync-r12, + v2x-CommPreconfigSync-r14 SL-PreconfigV2X-Sync-r14 OPTIONAL, v2x-CommRxPoolList-r14 SL-PreconfigV2X-RxPoolList-r14, v2x-CommTxPoolList-r14 SL-PreconfigV2X-TxPoolList-r14, + p2x-CommTxPoolList-r14 SL-PreconfigV2X-TxPoolList-r14, v2x-ResourceSelectionConfig-r14 SL-CommTxPoolSensingConfig-r14 OPTIONAL, - zoneConfig-r14 SL-ZoneConfig-r14 OPTIONAL, + zoneConfig-r14 SL-ZoneConfig-r14 OPTIONAL, + syncPriority-r14 ENUMERATED {gnss, enb}, + thresSL-TxPrioritization-r14 SL-Priority-r13 OPTIONAL, + offsetDFN-r14 INTEGER (0..1000) OPTIONAL, ... } @@ -11379,7 +13132,7 @@ SL-PreconfigV2X-RxPoolList-r14 ::= SEQUENCE (SIZE (1..maxSL-V2X-RxPoolPreconf-r SL-PreconfigV2X-TxPoolList-r14 ::= SEQUENCE (SIZE (1..maxSL-V2X-TxPoolPreconf-r14)) OF SL-V2X-PreconfigCommPool-r14 SL-V2X-PreconfigCommPool-r14 ::= SEQUENCE { --- This IE is same as SL-V2X-CommResourcePool with rxParametersNCell absent +-- This IE is same as SL-CommResourcePoolV2X with rxParametersNCell absent sl-OffsetIndicator-r14 SL-OffsetIndicator-r12 OPTIONAL, sl-Subframe-r14 SubframeBitmapSL-r14, adjacencyPSCCH-PSSCH-r14 BOOLEAN, @@ -11388,14 +13141,46 @@ SL-V2X-PreconfigCommPool-r14 ::= SEQUENCE { n48, n50, n72, n75, n96, n100, spare13, spare12, spare11, spare10, spare9, spare8, spare7, spare6, spare5, spare4, spare3, spare2, spare1}, - numSubchannel-r14 ENUMERATED {n1, n3, n5, n10, n15, n20, spare2, spare1}, + numSubchannel-r14 ENUMERATED {n1, n3, n5, n8, n10, n15, n20, spare1}, startRB-Subchannel-r14 INTEGER (0..99), startRB-PSCCH-Pool-r14 INTEGER (0..99) OPTIONAL, - dataTxParameters-r14 SL-TxParameters-r12 OPTIONAL, + dataTxParameters-r14 P0-SL-r12, zoneID-r14 INTEGER (0..7) OPTIONAL, + threshS-RSSI-CBR-r14 INTEGER (0..45) OPTIONAL, + cbr-pssch-TxConfigList-r14 SL-CBR-PPPP-TxPreconfigList-r14 OPTIONAL, + resourceSelectionConfigP2X-r14 SL-P2X-ResourceSelectionConfig-r14 OPTIONAL, + syncAllowed-r14 SL-SyncAllowed-r14 OPTIONAL, + restrictResourceReservationPeriod-r14 SL-RestrictResourceReservationPeriodList-r14 OPTIONAL, -- Need OR ... } +SL-PreconfigV2X-Sync-r14 ::= SEQUENCE { + syncOffsetIndicators-r14 SL-V2X-SyncOffsetIndicators-r14, + syncTxParameters-r14 P0-SL-r12, + syncTxThreshOoC-r14 RSRP-RangeSL3-r12, + filterCoefficient-r14 FilterCoefficient, + syncRefMinHyst-r14 ENUMERATED {dB0, dB3, dB6, dB9, dB12}, + syncRefDiffHyst-r14 ENUMERATED {dB0, dB3, dB6, dB9, dB12, dBinf}, + ... +} + +SL-V2X-SyncOffsetIndicators-r14 ::= SEQUENCE { + syncOffsetIndicator1-r14 SL-OffsetIndicatorSync-r14, + syncOffsetIndicator2-r14 SL-OffsetIndicatorSync-r14, + syncOffsetIndicator3-r14 SL-OffsetIndicatorSync-r14 OPTIONAL +} + +SL-CBR-PPPP-TxPreconfigList-r14 ::= SEQUENCE (SIZE (1..8)) OF SL-PPPP-TxPreconfigIndex-r14 + +SL-PPPP-TxPreconfigIndex-r14 ::= SEQUENCE { + priorityThreshold-r14 SL-Priority-r13, + defaultTxConfigIndex-r14 INTEGER(0..maxCBR-Level-1-r14), + cbr-ConfigIndex-r14 INTEGER(0..maxSL-V2X-CBRConfig2-1-r14), + tx-ConfigIndexList-r14 SEQUENCE (SIZE (1..maxCBR-Level-r14)) OF Tx-PreconfigIndex-r14 +} + +Tx-PreconfigIndex-r14 ::= INTEGER(0..maxSL-V2X-TxConfig2-1-r14) + END @@ -11416,6 +13201,7 @@ IMPORTS DRB-ToReleaseList, FreqBandIndicator-r11, InDeviceCoexIndication-r11, + LWA-Config-r13, MasterInformationBlock, maxBands, maxFreq, @@ -11427,7 +13213,9 @@ IMPORTS MBMSInterestIndication-r11, MeasConfig, MeasGapConfig, + MeasGapConfigPerCC-List-r14, MeasResultForRSSI-r13, + MeasResultListWLAN-r13, OtherConfig-r9, PhysCellId, P-Max, @@ -11507,7 +13295,7 @@ HandoverPreparationInformation-r8-IEs ::= SEQUENCE { HandoverPreparationInformation-v920-IEs ::= SEQUENCE { ue-ConfigRelease-r9 ENUMERATED { rel9, rel10, rel11, rel12, v10j0, v11e0, - v1280, rel13, ...} OPTIONAL, -- Cond HO2 + v1280, rel13, ..., rel14} OPTIONAL, -- Cond HO2 nonCriticalExtension HandoverPreparationInformation-v9d0-IEs OPTIONAL } @@ -11549,11 +13337,12 @@ HandoverPreparationInformation-v1250-IEs ::= SEQUENCE { HandoverPreparationInformation-v1320-IEs ::= SEQUENCE { as-Config-v1320 AS-Config-v1320 OPTIONAL, -- Cond HO2 as-Context-v1320 AS-Context-v1320 OPTIONAL, -- Cond HO2 - nonCriticalExtension HandoverPreparationInformation-v14x0-IEs OPTIONAL + nonCriticalExtension HandoverPreparationInformation-v1430-IEs OPTIONAL } -HandoverPreparationInformation-v14x0-IEs ::= SEQUENCE { - as-Config-v14x0 AS-Config-v14x0 OPTIONAL, -- Cond HO2 +HandoverPreparationInformation-v1430-IEs ::= SEQUENCE { + as-Config-v1430 AS-Config-v1430 OPTIONAL, -- Cond HO2 + makeBeforeBreakReq-r14 ENUMERATED {true} OPTIONAL, -- Cond HO2 nonCriticalExtension SEQUENCE {} OPTIONAL } @@ -11617,6 +13406,12 @@ SCG-ConfigInfo-v1310-IEs ::= SEQUENCE { SCG-ConfigInfo-v1330-IEs ::= SEQUENCE { measResultListRSSI-SCG-r13 MeasResultListRSSI-SCG-r13 OPTIONAL, + nonCriticalExtension SCG-ConfigInfo-v1430-IEs OPTIONAL +} + +SCG-ConfigInfo-v1430-IEs ::= SEQUENCE { + makeBeforeBreakSCG-Req-r14 ENUMERATED {true} OPTIONAL, + measGapConfigPerCC-List MeasGapConfigPerCC-List-r14 OPTIONAL, nonCriticalExtension SEQUENCE {} OPTIONAL } @@ -11787,8 +13582,10 @@ AS-Config-v1320 ::= SEQUENCE { sourceRCLWI-Configuration-r13 RCLWI-Configuration-r13 OPTIONAL } -AS-Config-v14x0 ::= SEQUENCE { - sourceSL-V2X-CommConfig-r14 SL-V2X-ConfigDedicated-r14 OPTIONAL +AS-Config-v1430 ::= SEQUENCE { + sourceSL-V2X-CommConfig-r14 SL-V2X-ConfigDedicated-r14 OPTIONAL, + sourceLWA-Config-r14 LWA-Config-r13 OPTIONAL, + sourceWLAN-MeasResult-r14 MeasResultListWLAN-r13 OPTIONAL } From 8dd3a2bdc49de99fe8ec1c6309225ef2b9378703 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 8 Sep 2017 13:07:51 +0200 Subject: [PATCH 068/284] T: add extract_output_subframe This tracer extracts output subframes generated by the eNodeB, so they can be analyzed with some external tools. --- common/utils/T/tracer/Makefile | 7 +- .../utils/T/tracer/extract_output_subframe.c | 158 ++++++++++++++++++ 2 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 common/utils/T/tracer/extract_output_subframe.c diff --git a/common/utils/T/tracer/Makefile b/common/utils/T/tracer/Makefile index 6546345968..dadc86745d 100644 --- a/common/utils/T/tracer/Makefile +++ b/common/utils/T/tracer/Makefile @@ -6,7 +6,7 @@ CFLAGS=-Wall -g -pthread -DT_TRACER -I. LIBS=-lX11 -lm -lpng -lXft all: record replay extract_config textlog enb ue vcd macpdu2wireshark \ - extract_input_subframe + extract_input_subframe extract_output_subframe record: utils.o record.o database.o config.o $(CC) $(CFLAGS) -o record $^ $(LIBS) @@ -21,6 +21,10 @@ extract_input_subframe: extract_input_subframe.o database.o event.o utils.o \ config.o $(CC) $(CFLAGS) -o $@ $^ $(LIBS) +extract_output_subframe: extract_output_subframe.o database.o event.o utils.o \ + config.o + $(CC) $(CFLAGS) -o $@ $^ $(LIBS) + textlog: utils.o textlog.o database.o event.o handler.o config.o \ event_selector.o view/view.a gui/gui.a logger/logger.a \ filter/filter.a @@ -65,6 +69,7 @@ filter/filter.a: clean: rm -f *.o core tracer_remote textlog enb ue vcd record replay rm -f extract_config macpdu2wireshark extract_input_subframe + rm -f extract_output_subframe cd gui && make clean cd view && make clean cd logger && make clean diff --git a/common/utils/T/tracer/extract_output_subframe.c b/common/utils/T/tracer/extract_output_subframe.c new file mode 100644 index 0000000000..b82ad0e766 --- /dev/null +++ b/common/utils/T/tracer/extract_output_subframe.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include "database.h" +#include "event.h" +#include "config.h" + +void usage(void) +{ + printf( +"usage: [options] \n" +" the program dumps 'number of subframes' subframes starting\n" +" at 'frame:suubframe'\n" +"options:\n" +" -d this option is mandatory\n" +" -o output to file (default: stdout)\n" +" -v verbose\n" + ); + exit(1); +} + +int main(int n, char **v) +{ + char *database_filename = NULL; + void *database; + int i; + int output_event_id; + database_event_format f; + char *file = NULL; + int fd; + int frame = -1, subframe = -1; + int number_of_subframes = -1; + int frame_arg, subframe_arg, buffer_arg; + int verbose = 0; + char *out_filename = NULL; + FILE *out; + + for (i = 1; i < n; i++) { + if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage(); + if (!strcmp(v[i], "-d")) + { if (i > n-2) usage(); database_filename = v[++i]; continue; } + if (!strcmp(v[i], "-o")) + { if (i > n-2) usage(); out_filename = v[++i]; continue; } + if (!strcmp(v[i], "-v")) { verbose = 1; continue; } + if (file == NULL) { file = v[i]; continue; } + if (frame == -1) { frame = atoi(v[i]); continue; } + if (subframe == -1) { subframe = atoi(v[i]); continue; } + if (number_of_subframes == -1) {number_of_subframes=atoi(v[i]);continue;} + usage(); + } + if (file == NULL || frame == -1 || subframe == -1 || + number_of_subframes == -1) usage(); + + if (database_filename == NULL) { + printf("ERROR: provide a database file (-d)\n"); + exit(1); + } + + if (out_filename == NULL) out = stdout; + else { + out = fopen(out_filename, "w"); + if (out == NULL) { perror(out_filename); exit(1); } + } + + database = parse_database(database_filename); + + load_config_file(database_filename); + + output_event_id = event_id_from_name(database, "ENB_PHY_OUTPUT_SIGNAL"); + f = get_format(database, output_event_id); + + frame_arg = subframe_arg = buffer_arg = -1; + for (i = 0; i < f.count; i++) { + if (!strcmp(f.name[i], "frame")) { + if (frame_arg != -1) goto err; + if (strcmp(f.type[i], "int")) goto err; + frame_arg = i; + } + if (!strcmp(f.name[i], "subframe")) { + if (subframe_arg != -1) goto err; + if (strcmp(f.type[i], "int")) goto err; + subframe_arg = i; + } + if (!strcmp(f.name[i], "txdata")) { + if (buffer_arg != -1) goto err; + if (strcmp(f.type[i], "buffer")) goto err; + buffer_arg = i; + } + continue; +err: + printf("cannot deal with ENB_PHY_OUTPUT_SIGNAL from database file\n"); + exit(1); + } + if (frame_arg == -1 || subframe_arg == -1 || buffer_arg == -1) goto err; + + fd = open(file, O_RDONLY); + if (fd == -1) { perror(file); exit(1); } + + int last_frame = -1; + int last_subframe = -1; + int subframe_written = 0; + while (1) { + char v[T_BUFFER_MAX]; + event e; + e = get_event(fd, v, database); + if (e.type == -1) break; + if (e.type != output_event_id) continue; + if (verbose) + printf("found output frame %d subframe %d size %d\n", + e.e[frame_arg].i, e.e[subframe_arg].i, e.e[buffer_arg].bsize); + if (!(last_frame != -1 || + (frame == e.e[frame_arg].i && subframe == e.e[subframe_arg].i))) + continue; + frame = e.e[frame_arg].i; + subframe = e.e[subframe_arg].i; + if (last_frame != -1) { + if (frame*10+subframe != (last_frame*10+last_subframe + 1) % 10240) { + printf("error: discontinuity, not what you want...\n"); + exit(1); + } + } + last_frame = frame; + last_subframe = subframe; +#if 0 +for (i = 0; i < e.e[buffer_arg].bsize/2; i++) { +short *x = e.e[buffer_arg].b; +x[i] *= 14; +} +#endif + if (verbose) + printf("save output frame %d subframe %d size %d\n", + e.e[frame_arg].i, e.e[subframe_arg].i, e.e[buffer_arg].bsize); + if (fwrite(e.e[buffer_arg].b, e.e[buffer_arg].bsize, 1, out) != 1) { + perror(out_filename); + exit(1); + } + subframe_written++; + if (subframe_written != number_of_subframes) + continue; + + /* done */ + fflush(out); + if (out_filename != NULL) { + if (fclose(out)) perror(out_filename); + } + if (verbose) + printf("%d subframes written\n", subframe_written); + return 0; + } + + printf("error with input file, %d subframe written\n", subframe_written); + fflush(out); + if (out_filename != NULL) { + if (fclose(out)) perror(out_filename); + } + return 1; +} From 2beac6fed7c5e1b4259076b8e8dcab4fef30aa35 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 8 Sep 2017 13:08:57 +0200 Subject: [PATCH 069/284] T: minor update of .gitignore --- common/utils/T/.gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/utils/T/.gitignore b/common/utils/T/.gitignore index f5724e6ff8..801e139794 100644 --- a/common/utils/T/.gitignore +++ b/common/utils/T/.gitignore @@ -10,4 +10,7 @@ tracer/replay tracer/textlog tracer/vcd tracer/macpdu2wireshark +tracer/ue +tracer/extract_input_subframe +tracer/extract_output_subframe tracee/tracee From 7e7fd3c4d5f27357d95188adc40c1a1d239bbc9b Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 18 Sep 2017 10:26:17 +0200 Subject: [PATCH 070/284] T tracer: add a tracer to dump to VCD file Later on, use this file with gtkwave. To be used to check realtime behaviour of the system. --- common/utils/T/.gitignore | 1 + common/utils/T/tracer/Makefile | 8 +- common/utils/T/tracer/to_vcd.c | 299 +++++++++++++++++++++++++++++++++ 3 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 common/utils/T/tracer/to_vcd.c diff --git a/common/utils/T/.gitignore b/common/utils/T/.gitignore index 801e139794..85ff166c1a 100644 --- a/common/utils/T/.gitignore +++ b/common/utils/T/.gitignore @@ -11,6 +11,7 @@ tracer/textlog tracer/vcd tracer/macpdu2wireshark tracer/ue +tracer/to_vcd tracer/extract_input_subframe tracer/extract_output_subframe tracee/tracee diff --git a/common/utils/T/tracer/Makefile b/common/utils/T/tracer/Makefile index dadc86745d..4797958be8 100644 --- a/common/utils/T/tracer/Makefile +++ b/common/utils/T/tracer/Makefile @@ -6,7 +6,7 @@ CFLAGS=-Wall -g -pthread -DT_TRACER -I. LIBS=-lX11 -lm -lpng -lXft all: record replay extract_config textlog enb ue vcd macpdu2wireshark \ - extract_input_subframe extract_output_subframe + extract_input_subframe extract_output_subframe to_vcd record: utils.o record.o database.o config.o $(CC) $(CFLAGS) -o record $^ $(LIBS) @@ -45,6 +45,10 @@ vcd: utils.o vcd.o database.o event.o handler.o config.o \ filter/filter.a $(CC) $(CFLAGS) -o vcd $^ $(LIBS) +to_vcd: to_vcd.o database.o event.o handler.o utils.o config.o \ + logger/logger.a filter/filter.a + $(CC) $(CFLAGS) -o to_vcd $^ -lm + macpdu2wireshark: macpdu2wireshark.o database.o utils.o handler.o event.o \ config.o $(CC) $(CFLAGS) -o $@ $^ $(LIBS) @@ -69,7 +73,7 @@ filter/filter.a: clean: rm -f *.o core tracer_remote textlog enb ue vcd record replay rm -f extract_config macpdu2wireshark extract_input_subframe - rm -f extract_output_subframe + rm -f extract_output_subframe to_vcd cd gui && make clean cd view && make clean cd logger && make clean diff --git a/common/utils/T/tracer/to_vcd.c b/common/utils/T/tracer/to_vcd.c new file mode 100644 index 0000000000..c7611162d2 --- /dev/null +++ b/common/utils/T/tracer/to_vcd.c @@ -0,0 +1,299 @@ +#include +#include +#include +#include +#include +#include +#include "database.h" +#include "utils.h" +#include "handler.h" +#include "config.h" +#include "logger/logger.h" +#include "view/view.h" + +typedef struct { + char *event; + char *arg; + char *vcd_name; + int boolean; +} vcd_vars; + +/****************************************************************************/ +/* VCD file handling begin */ +/****************************************************************************/ + +FILE *out; + +uint64_t start_time; +int start_time_inited; + +void vcd_init(char *file) +{ + out = fopen(file, "w"); if (out == NULL) { perror(file); exit(1); } +} + +void vcd_write_header(vcd_vars *v, int n) +{ + int i; + + if (fprintf(out, +"$date\n" +" January, 1, 1970.\n" +"$end\n" +"$version\n" +" to_vcd\n" +"$end\n" +"$timescale 1ns $end\n" +"$scope module logic $end\n") <= 0) abort(); + + for (i = 0; i < n; i++) + if (fprintf(out, "$var wire %d %s %s $end\n", + v[i].boolean ? 1 : 64, + v[i].vcd_name, v[i].vcd_name) <= 0) abort(); + + if (fprintf(out, +"$upscope $end\n" +"$enddefinitions $end\n" +"$dumpvars\n") <= 0) abort(); + + for (i = 0; i < n; i++) + if (v[i].boolean) { + if (fprintf(out, "0%s\n", v[i].vcd_name) <= 0) abort(); + } else { + if (fprintf(out, "b0 %s\n", v[i].vcd_name) <= 0) abort(); + } + + if (fprintf(out, +"$end\n") <= 0) abort(); + +} + +void vcd_end(void) +{ + if (fclose(out)) { perror("error closing VCD file"); exit(1); } +} + +char *b64(uint64_t val) +{ + static char v[65]; + char *s = &v[64]; + *s = 0; + if (val == 0) { s--; *s = '0'; return s; } + while (val) { + s--; + *s = val&1 ? '1' : '0'; + val >>= 1; + } + return s; +} + +void vcd_dump(char *v) +{ + uint64_t h, m, s, ns; + char t; + uint64_t val; + uint64_t time; + char var[256]; + if (sscanf(v, "%"SCNu64":%"SCNu64":%"SCNu64".%"SCNu64": %c %"SCNu64" %s", + &h, &m, &s, &ns, &t, &val, var) != 7) + goto err; + time = h*60*60*1000000000 + + m*60*1000000000 + + s*1000000000 + + ns; + if (!start_time_inited) { + start_time = time; + start_time_inited = 1; + } + if (fprintf(out, "#%"PRIu64"\n", time - start_time) <= 0) abort(); + switch (t) { + case 'b': if (fprintf(out, "%d%s\n", val!=0, var) <= 0) abort(); break; + case 'l': if (fprintf(out, "b%s %s\n", b64(val), var) <= 0) abort(); break; + default: goto err; + } + + return; + +err: + printf("bad vcd_dump line '%s'\n", v); + exit(1); +} + +/****************************************************************************/ +/* VCD file handling end */ +/****************************************************************************/ + + +/****************************************************************************/ +/* vcd view start */ +/****************************************************************************/ + +struct vcd_view { + view common; +}; + +static void vcd_view_clear(view *this) +{ + /* nothing */ +} + +static void vcd_view_append(view *_this, char *s) +{ + vcd_dump(s); +} + +static view *new_view_vcd(void) +{ + struct vcd_view *ret = calloc(1, sizeof(struct vcd_view)); + if (ret == NULL) abort(); + ret->common.clear = vcd_view_clear; + ret->common.append = (void (*)(view *, ...))vcd_view_append; + return (view *)ret; +} + +/****************************************************************************/ +/* vcd view end */ +/****************************************************************************/ + +void activate_traces(int socket, int number_of_events, int *is_on) +{ + char t = 1; + if (socket_send(socket, &t, 1) == -1 || + socket_send(socket, &number_of_events, sizeof(int)) == -1 || + socket_send(socket, is_on, number_of_events * sizeof(int)) == -1) + abort(); +} + +void usage(void) +{ + printf( +"options:\n" +" -d this option is mandatory\n" +" -o this option is mandatory\n" +" -ip connect to given IP address (default %s)\n" +" -p connect to given port (default %d)\n" +" -b trace as binary (0 off, anything else on)\n" +" -l trace as uint64_t\n", + DEFAULT_REMOTE_IP, + DEFAULT_REMOTE_PORT + ); + exit(1); +} + +int run = 1; + +void force_stop(int x) +{ + printf("\ngently quit...\n"); + run = 0; +} + +int main(int n, char **v) +{ + char *output_filename = NULL; + char *database_filename = NULL; + void *database; + char *ip = DEFAULT_REMOTE_IP; + int port = DEFAULT_REMOTE_PORT; + int *is_on; + int number_of_events; + int i; + int socket; + vcd_vars vars[n]; + int nvars = 0; + view *vcd_view; + event_handler *h; + logger *textlog; + + /* write on a socket fails if the other end is closed and we get SIGPIPE */ + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) abort(); + + for (i = 1; i < n; i++) { + if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage(); + if (!strcmp(v[i], "-d")) + { if (i > n-2) usage(); database_filename = v[++i]; continue; } + if (!strcmp(v[i], "-o")) + { if (i > n-2) usage(); output_filename = v[++i]; continue; } + if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; } + if (!strcmp(v[i], "-p")) + { if (i > n-2) usage(); port = atoi(v[++i]); continue; } + if (!strcmp(v[i], "-b")) { if(i>n-4)usage(); + vars[nvars].event = v[++i]; + vars[nvars].arg = v[++i]; + vars[nvars].vcd_name = v[++i]; + vars[nvars++].boolean = 1; + continue; + } + if (!strcmp(v[i], "-l")) { if(i>n-4)usage(); + vars[nvars].event = v[++i]; + vars[nvars].arg = v[++i]; + vars[nvars].vcd_name = v[++i]; + vars[nvars++].boolean = 0; + continue; + } + usage(); + } + + if (output_filename == NULL) { + printf("ERROR; provide an output file (-o)\n"); + exit(1); + } + + if (database_filename == NULL) { + printf("ERROR: provide a database file (-d)\n"); + exit(1); + } + + database = parse_database(database_filename); + + load_config_file(database_filename); + + number_of_events = number_of_ids(database); + is_on = calloc(number_of_events, sizeof(int)); + if (is_on == NULL) abort(); + + h = new_handler(database); + + /* create the view */ + vcd_view = new_view_vcd(); + + /* setup traces */ + for (i = 0; i < nvars; i++) { + char format[256]; + if (strlen(vars[i].arg) > 256-3) abort(); + if (strlen(vars[i].vcd_name) > 256-1) abort(); + sprintf(format, "%c [%s] %s", + vars[i].boolean ? 'b' : 'l', + vars[i].arg, + vars[i].vcd_name); + textlog = new_textlog(h, database, vars[i].event, format); + logger_add_view(textlog, vcd_view); + on_off(database, vars[i].event, is_on, 1); + } + + socket = connect_to(ip, port); + + /* activate selected traces */ + activate_traces(socket, number_of_events, is_on); + + vcd_init(output_filename); + vcd_write_header(vars, nvars); + + /* exit on ctrl+c and ctrl+z */ + if (signal(SIGQUIT, force_stop) == SIG_ERR) abort(); + if (signal(SIGINT, force_stop) == SIG_ERR) abort(); + if (signal(SIGTSTP, force_stop) == SIG_ERR) abort(); + + /* read messages */ + while (run) { + char v[T_BUFFER_MAX]; + event e; + e = get_event(socket, v, database); + if (e.type == -1) { printf("disconnected? let's quit gently\n"); break; } + handle_event(h, e); + } + + vcd_end(); + + return 0; +} From faae3c8cd5fc852e95a6e40f0b0518933872eb4e Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 18 Sep 2017 10:32:11 +0200 Subject: [PATCH 071/284] T: cleanup Do not link the X stuff for tracers not needing it. --- common/utils/T/tracer/Makefile | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/common/utils/T/tracer/Makefile b/common/utils/T/tracer/Makefile index 4797958be8..c1b0c682a0 100644 --- a/common/utils/T/tracer/Makefile +++ b/common/utils/T/tracer/Makefile @@ -3,7 +3,8 @@ CFLAGS=-Wall -g -pthread -DT_TRACER -I. #CFLAGS += -O3 -ffast-math -fomit-frame-pointer -LIBS=-lX11 -lm -lpng -lXft +LIBS=-lm +XLIBS=-lX11 -lpng -lXft all: record replay extract_config textlog enb ue vcd macpdu2wireshark \ extract_input_subframe extract_output_subframe to_vcd @@ -28,26 +29,26 @@ extract_output_subframe: extract_output_subframe.o database.o event.o utils.o \ textlog: utils.o textlog.o database.o event.o handler.o config.o \ event_selector.o view/view.a gui/gui.a logger/logger.a \ filter/filter.a - $(CC) $(CFLAGS) -o textlog $^ $(LIBS) + $(CC) $(CFLAGS) -o textlog $^ $(LIBS) $(XLIBS) enb: utils.o enb.o database.o event.o handler.o config.o \ event_selector.o view/view.a gui/gui.a logger/logger.a \ filter/filter.a - $(CC) $(CFLAGS) -o enb $^ $(LIBS) + $(CC) $(CFLAGS) -o enb $^ $(LIBS) $(XLIBS) ue: utils.o ue.o database.o event.o handler.o config.o \ event_selector.o view/view.a gui/gui.a logger/logger.a \ filter/filter.a - $(CC) $(CFLAGS) -o ue $^ $(LIBS) + $(CC) $(CFLAGS) -o ue $^ $(LIBS) $(XLIBS) vcd: utils.o vcd.o database.o event.o handler.o config.o \ event_selector.o view/view.a gui/gui.a logger/logger.a \ filter/filter.a - $(CC) $(CFLAGS) -o vcd $^ $(LIBS) + $(CC) $(CFLAGS) -o vcd $^ $(LIBS) $(XLIBS) to_vcd: to_vcd.o database.o event.o handler.o utils.o config.o \ logger/logger.a filter/filter.a - $(CC) $(CFLAGS) -o to_vcd $^ -lm + $(CC) $(CFLAGS) -o to_vcd $^ $(LIBS) macpdu2wireshark: macpdu2wireshark.o database.o utils.o handler.o event.o \ config.o From 4d1705e3a5cea72e15cb10e811e7c43b7b78ddf4 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 20 Sep 2017 09:52:53 +0200 Subject: [PATCH 072/284] T: minor: close socket Sometimes when the user does ctrl+c to quit, it may not quit if nothing comes on the socket. Closing the socket in the signal handler fixes this. --- common/utils/T/tracer/to_vcd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/common/utils/T/tracer/to_vcd.c b/common/utils/T/tracer/to_vcd.c index c7611162d2..82cd3393d7 100644 --- a/common/utils/T/tracer/to_vcd.c +++ b/common/utils/T/tracer/to_vcd.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "database.h" #include "utils.h" #include "handler.h" @@ -181,10 +182,13 @@ void usage(void) } int run = 1; +static int socket = -1; void force_stop(int x) { printf("\ngently quit...\n"); + close(socket); + socket = -1; run = 0; } @@ -198,7 +202,6 @@ int main(int n, char **v) int *is_on; int number_of_events; int i; - int socket; vcd_vars vars[n]; int nvars = 0; view *vcd_view; From 8f621c3ed7536b91cfbac20f7bf7142915876807 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sat, 4 Nov 2017 07:09:10 +0100 Subject: [PATCH 073/284] bugfixes for TDD in RRU (IF4p5) and timing statistics of fronthaul and compression. --- openair1/PHY/LTE_TRANSPORT/if4_tools.c | 62 +++++++++++++------ openair1/PHY/LTE_TRANSPORT/if4_tools.h | 10 +-- openair1/PHY/defs.h | 4 ++ targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c | 3 +- targets/RT/USER/lte-ru.c | 21 +++++-- 5 files changed, 71 insertions(+), 29 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/if4_tools.c b/openair1/PHY/LTE_TRANSPORT/if4_tools.c index 4528766676..38ced5d717 100644 --- a/openair1/PHY/LTE_TRANSPORT/if4_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/if4_tools.c @@ -58,7 +58,7 @@ void send_IF4p5(RU_t *ru, int frame, int subframe, uint16_t packet_type) { uint16_t db_fulllength, db_halflength; int slotoffsetF=0, blockoffsetF=0; - uint16_t *data_block=NULL, *i=NULL; + uint16_t *data_block=NULL, *i=NULL, *d=NULL; IF4p5_header_t *packet_header=NULL; eth_state_t *eth = (eth_state_t*) (ru->ifdevice.priv); @@ -138,23 +138,48 @@ void send_IF4p5(RU_t *ru, int frame, int subframe, uint16_t packet_type) { if (packet_type == IF4p5_PULFFT) { + uint16_t *rx0 = (uint16_t*) &rxdataF[0][blockoffsetF]; + uint16_t *rx1 = (uint16_t*) &rxdataF[0][slotoffsetF]; + + for (symbol_id=fp->symbols_per_tti-nsym; symbol_idsymbols_per_tti; symbol_id++) { VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF4_SYMBOL, symbol_id ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_COMPR_IF, 1 ); - for (element_id=0; element_idframe_status &= ~(0x000f<<26); - packet_header->frame_status |= (symbol_id&0x000f)<<26; + + start_meas(&ru->compression); + + for (element_id=0; element_idcompression); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_COMPR_IF, 0 ); + packet_header->frame_status &= ~(0x000f<<26); + packet_header->frame_status |= (symbol_id&0x000f)<<26; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF, 1 ); + start_meas(&ru->transport); if ((ru->ifdevice.trx_write_func(&ru->ifdevice, symbol_id, &tx_buffer, @@ -163,6 +188,7 @@ void send_IF4p5(RU_t *ru, int frame, int subframe, uint16_t packet_type) { IF4p5_PULFFT)) < 0) { perror("ETHERNET write for IF4p5_PULFFT\n"); } + stop_meas(&ru->transport); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF, 0 ); slotoffsetF += fp->ofdm_symbol_size; blockoffsetF += fp->ofdm_symbol_size; @@ -181,7 +207,7 @@ void send_IF4p5(RU_t *ru, int frame, int subframe, uint16_t packet_type) { } else if (packet_type >= IF4p5_PRACH && packet_type <= IF4p5_PRACH+4) { // FIX: hard coded prach samples length - LOG_D(PHY,"IF4p5_PRACH: frame %d, subframe %d\n",frame,subframe); + LOG_D(PHY,"IF4p5_PRACH: frame %d, subframe %d,packet type %x\n",frame,subframe,packet_type); db_fulllength = PRACH_NUM_SAMPLES; if (eth->flags == ETH_RAW_IF4p5_MODE) { @@ -222,6 +248,7 @@ void send_IF4p5(RU_t *ru, int frame, int subframe, uint16_t packet_type) { packet_type)) < 0) { perror("ETHERNET write for IF4p5_PRACH\n"); } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF, 0 ); } else { AssertFatal(1==0, "send_IF4p5 - Unknown packet_type %x", packet_type); @@ -283,7 +310,7 @@ void recv_IF4p5(RU_t *ru, int *frame, int *subframe, uint16_t *packet_type, uint *subframe = ((packet_header->frame_status)>>22)&0x000f; *packet_type = packet_header->sub_type; - + LOG_D(PHY,"recv_IF4p5: Frame %d, Subframe %d: packet_type %x\n",*frame,*subframe,*packet_type); if (*packet_type == IF4p5_PDLFFT) { *symbol_number = ((packet_header->frame_status)>>26)&0x000f; VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RECV_IF4_SYMBOL, *symbol_number ); @@ -313,7 +340,6 @@ void recv_IF4p5(RU_t *ru, int *frame, int *subframe, uint16_t *packet_type, uint slotoffsetF = (*symbol_number)*(fp->ofdm_symbol_size); blockoffsetF = slotoffsetF + fp->ofdm_symbol_size - db_halflength; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_DECOMPR_IF, 1 ); - if (ru->idx==0) LOG_D(PHY,"UL_IF4p5: CC_id %d : frame %d, subframe %d, symbol %d\n",ru->idx,*frame,*subframe,*symbol_number); for (element_id=0; element_id %d dB\n",ru->idx,*frame,*subframe, - // dB_fixed(signal_energy((int*)&prach_rxsigF[0][0],839))); + LOG_D(PHY,"PRACH_IF4p5: CC_id %d : frame %d, subframe %d => %d dB\n",ru->idx,*frame,*subframe, + dB_fixed(signal_energy((int*)&prach_rxsigF[0][0],839))); for (idx=0;idxnum_eNB;idx++) ru->wakeup_prach_eNB(ru->eNB_list[idx],ru,*frame,*subframe); } else if (*packet_type == IF4p5_PULTICK) { diff --git a/openair1/PHY/LTE_TRANSPORT/if4_tools.h b/openair1/PHY/LTE_TRANSPORT/if4_tools.h index a251c62d0d..0a95e60ead 100644 --- a/openair1/PHY/LTE_TRANSPORT/if4_tools.h +++ b/openair1/PHY/LTE_TRANSPORT/if4_tools.h @@ -39,11 +39,11 @@ #define IF4p5_PULFFT 0x0019 #define IF4p5_PDLFFT 0x0020 #define IF4p5_PRACH 0x0021 -#define IF4p5_PRACH_BR_CE0 0x0021 -#define IF4p5_PRACH_BR_CE1 0x0022 -#define IF4p5_PRACH_BR_CE2 0x0023 -#define IF4p5_PRACH_BR_CE3 0x0024 -#define IF4p5_PULTICK 0x0025 +#define IF4p5_PRACH_BR_CE0 0x0022 +#define IF4p5_PRACH_BR_CE1 0x0023 +#define IF4p5_PRACH_BR_CE2 0x0024 +#define IF4p5_PRACH_BR_CE3 0x0025 +#define IF4p5_PULTICK 0x0026 struct IF4p5_header { /// Type diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 24ea961b0e..0e44a7f8bd 100644 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -756,6 +756,10 @@ typedef struct RU_t_s{ time_stats_t rx_fhaul; /// Timing statistics (TX Fronthaul + Compression) time_stats_t tx_fhaul; + /// Timong statistics (Compression) + time_stats_t compression; + /// Timing statistics (Fronthaul transport) + time_stats_t transport; /// RX and TX buffers for precoder output RU_COMMON common; /// beamforming weight vectors per eNB diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c index e323a9d5bc..ad5bbda3fe 100644 --- a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c +++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c @@ -235,7 +235,8 @@ int trx_eth_write_udp_IF4p5(openair0_device *device, openair0_timestamp timestam packet_size = UDP_IF4p5_PULFFT_SIZE_BYTES(nblocks); } else if (flags == IF4p5_PULTICK) { packet_size = UDP_IF4p5_PULTICK_SIZE_BYTES; - } else if (flags == IF4p5_PRACH) { + } else if ((flags >= IF4p5_PRACH)&& + (flags <= (IF4p5_PRACH+4))) { packet_size = UDP_IF4p5_PRACH_SIZE_BYTES; } else { printf("trx_eth_write_udp_IF4p5: unknown flags %d\n",flags); diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 45f69ca414..54693f43c8 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -596,13 +596,14 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { symbol_mask_full = ((subframe_select(fp,*subframe) == SF_S) ? (1<dl_symbols_in_S_subframe) : (1<symbols_per_tti))-1; do { recv_IF4p5(ru, &frame_tx, &subframe_tx, &packet_type, &symbol_number); - if ((subframe_select(fp,*subframe) == SF_DL) && (symbol_number == 0)) start_meas(&ru->rx_fhaul); + if ((subframe_select(fp,subframe_tx) == SF_DL) && (symbol_number == 0)) start_meas(&ru->rx_fhaul); LOG_D(PHY,"subframe %d (%d): frame %d, subframe %d, symbol %d\n", *subframe,subframe_select(fp,*subframe),frame_tx,subframe_tx,symbol_number); if (proc->first_tx != 0) { *frame = frame_tx; *subframe = subframe_tx; proc->first_tx = 0; + symbol_mask_full = ((subframe_select(fp,*subframe) == SF_S) ? (1<dl_symbols_in_S_subframe) : (1<symbols_per_tti))-1; } else { AssertFatal(frame_tx == *frame, @@ -616,7 +617,7 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { else AssertFatal(1==0,"Illegal IF4p5 packet type (should only be IF4p5_PDLFFT%d\n",packet_type); } while (symbol_mask != symbol_mask_full); - if (subframe_select(fp,*subframe) == SF_DL) stop_meas(&ru->rx_fhaul); + if (subframe_select(fp,subframe_tx) == SF_DL) stop_meas(&ru->rx_fhaul); proc->subframe_tx = subframe_tx; proc->frame_tx = frame_tx; @@ -871,7 +872,10 @@ static void* ru_thread_asynch_rxtx( void* param ) { // asynchronous receive from south (Mobipass) if (ru->fh_south_asynch_in) ru->fh_south_asynch_in(ru,&frame,&subframe); // asynchronous receive from north (RRU IF4/IF5) - else if (ru->fh_north_asynch_in) ru->fh_north_asynch_in(ru,&frame,&subframe); + else if (ru->fh_north_asynch_in) { + if (subframe_select(&ru->frame_parms,subframe)!=SF_UL) + ru->fh_north_asynch_in(ru,&frame,&subframe); + } else AssertFatal(1==0,"Unknown function in ru_thread_asynch_rxtx\n"); } @@ -1322,8 +1326,11 @@ static void* ru_stats_thread(void* param) { if (ru->feprx) print_meas(&ru->ofdm_demod_stats,"feprx",NULL,NULL); if (ru->feptx_ofdm) print_meas(&ru->ofdm_mod_stats,"feptx_ofdm",NULL,NULL); if (ru->fh_north_asynch_in) print_meas(&ru->rx_fhaul,"rx_fhaul",NULL,NULL); - if (ru->fh_north_out) print_meas(&ru->tx_fhaul,"tx_fhaul",NULL,NULL); - + if (ru->fh_north_out) { + print_meas(&ru->tx_fhaul,"tx_fhaul",NULL,NULL); + print_meas(&ru->compression,"compression",NULL,NULL); + print_meas(&ru->transport,"transport",NULL,NULL); + } } } return(NULL); @@ -1911,6 +1918,8 @@ void init_RU(char *rf_config_file) { ru->ifdevice.eth_params = &ru->eth_params; reset_meas(&ru->rx_fhaul); reset_meas(&ru->tx_fhaul); + reset_meas(&ru->compression); + reset_meas(&ru->transport); ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); printf("openair0_transport_init returns %d for ru_id %d\n",ret,ru_id); @@ -1934,6 +1943,8 @@ void init_RU(char *rf_config_file) { ru->ifdevice.eth_params = &ru->eth_params; reset_meas(&ru->rx_fhaul); reset_meas(&ru->tx_fhaul); + reset_meas(&ru->compression); + reset_meas(&ru->transport); ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); printf("openair0_transport_init returns %d for ru_id %d\n",ret,ru_id); From d01aa2d08a8c32e53711fcdf4ee8b37f333d7df2 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sat, 4 Nov 2017 09:55:11 -0700 Subject: [PATCH 074/284] changing of notation for Random-Access procedure to match documentation. Function remains the same. Indentation (-kr) run on all files in LAYER2/MAC --- openair2/LAYER2/MAC/config.c | 2024 +++-- openair2/LAYER2/MAC/defs.h | 1781 +++-- openair2/LAYER2/MAC/eNB_scheduler.c | 1018 ++- openair2/LAYER2/MAC/eNB_scheduler_RA.c | 2721 ++++--- openair2/LAYER2/MAC/eNB_scheduler_bch.c | 1458 ++-- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 2651 ++++--- openair2/LAYER2/MAC/eNB_scheduler_mch.c | 1271 +-- .../LAYER2/MAC/eNB_scheduler_primitives.c | 6806 +++++++++-------- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 2420 +++--- openair2/LAYER2/MAC/extern.h | 34 +- openair2/LAYER2/MAC/flexran_agent_mac_proto.h | 212 +- .../MAC/flexran_agent_scheduler_dataplane.c | 937 +-- .../MAC/flexran_agent_scheduler_dlsch_ue.c | 3192 ++++---- .../flexran_agent_scheduler_dlsch_ue_remote.c | 282 +- .../flexran_agent_scheduler_dlsch_ue_remote.h | 11 +- openair2/LAYER2/MAC/flexran_dci_conversions.h | 4 +- openair2/LAYER2/MAC/l1_helpers.c | 36 +- openair2/LAYER2/MAC/lte_transport_init.c | 176 +- openair2/LAYER2/MAC/main.c | 405 +- openair2/LAYER2/MAC/openair2_proc.c | 405 - openair2/LAYER2/MAC/pre_processor.c | 2640 ++++--- openair2/LAYER2/MAC/proto.h | 771 +- openair2/LAYER2/MAC/ra_procedures.c | 974 +-- openair2/LAYER2/MAC/rar_tools.c | 399 +- openair2/LAYER2/MAC/ue_procedures.c | 4743 ++++++------ openair2/LAYER2/MAC/vars.h | 113 +- 26 files changed, 20388 insertions(+), 17096 deletions(-) delete mode 100644 openair2/LAYER2/MAC/openair2_proc.c diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index 6d5ebae7d4..764c762f6a 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -60,37 +60,37 @@ extern RAN_CONTEXT_t RC; /* sec 5.9, 36.321: MAC Reset Procedure */ -void ue_mac_reset(module_id_t module_idP,uint8_t eNB_index) +void ue_mac_reset(module_id_t module_idP, uint8_t eNB_index) { - //Resetting Bj - UE_mac_inst[module_idP].scheduling_info.Bj[0] = 0; - UE_mac_inst[module_idP].scheduling_info.Bj[1] = 0; - UE_mac_inst[module_idP].scheduling_info.Bj[2] = 0; + //Resetting Bj + UE_mac_inst[module_idP].scheduling_info.Bj[0] = 0; + UE_mac_inst[module_idP].scheduling_info.Bj[1] = 0; + UE_mac_inst[module_idP].scheduling_info.Bj[2] = 0; - //Stopping all timers + //Stopping all timers - //timeAlignmentTimer expires + //timeAlignmentTimer expires - // PHY changes for UE MAC reset - phy_reset_ue(module_idP,0,eNB_index); + // PHY changes for UE MAC reset + phy_reset_ue(module_idP, 0, eNB_index); - // notify RRC to relase PUCCH/SRS - // cancel all pending SRs - UE_mac_inst[module_idP].scheduling_info.SR_pending=0; - UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; + // notify RRC to relase PUCCH/SRS + // cancel all pending SRs + UE_mac_inst[module_idP].scheduling_info.SR_pending = 0; + UE_mac_inst[module_idP].scheduling_info.SR_COUNTER = 0; //Set BSR Trigger Bmp and remove timer flags - UE_mac_inst[module_idP].BSR_reporting_active = BSR_TRIGGER_NONE; + UE_mac_inst[module_idP].BSR_reporting_active = BSR_TRIGGER_NONE; - // stop ongoing RACH procedure + // stop ongoing RACH procedure - // discard explicitly signaled ra_PreambleIndex and ra_RACH_MaskIndex, if any - UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = 0; // check! - UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0; + // discard explicitly signaled ra_PreambleIndex and ra_RACH_MaskIndex, if any + UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = 0; // check! + UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0; - ue_init_mac(module_idP); //This will hopefully do the rest of the MAC reset procedure + ue_init_mac(module_idP); //This will hopefully do the rest of the MAC reset procedure } @@ -115,912 +115,1236 @@ typedef struct band_info_s { static const eutra_bandentry_t eutra_bandtable[] = { - { 1, 19200, 19800, 21100, 21700, 0}, - { 2, 18500, 19100, 19300, 19900, 6000}, - { 3, 17100, 17850, 18050, 18800, 12000}, - { 4, 17100, 17550, 21100, 21550, 19500}, - { 5, 8240, 8490, 8690, 8940, 24000}, - { 6, 8300, 8400, 8750, 8850, 26500}, - { 7, 25000, 25700, 26200, 26900, 27500}, - { 8, 8800, 9150 , 9250, 9600, 34500}, - { 9, 17499, 17849, 18449, 18799, 38000}, - {10, 17100, 17700, 21100, 21700, 41500}, - {11, 14279, 14529, 14759, 15009, 47500}, - {12, 6980, 7160, 7280, 7460, 50100}, - {13, 7770, 7870, 7460, 7560, 51800}, - {14, 7880, 7980, 7580, 7680, 52800}, - {17, 7040, 7160, 7340, 7460, 57300}, - {18, 8150, 9650, 8600, 10100, 58500}, - {19, 8300, 8450, 8750, 8900, 60000}, - {20, 8320, 8620, 7910, 8210, 61500}, - {21, 14479, 14629, 14959, 15109, 64500}, - {22, 34100, 34900, 35100, 35900, 66000}, - {23, 20000, 20200, 21800, 22000, 75000}, - {24, 16126, 16605, 15250, 15590, 77000}, - {25, 18500, 19150, 19300, 19950, 80400}, - {26, 8140 , 8490, 8590, 8940, 86900}, - {27, 8070 , 8240, 8520, 8690, 90400}, - {28, 7030 , 7580, 7580, 8130, 92100}, - {29, 0 , 0 , 7170, 7280, 96600}, - {30, 23050, 23250, 23500, 23600, 97700}, - {31, 45250, 34900, 46250, 35900, 98700}, - {32, 0 , 0 , 14520, 14960, 99200}, - {33, 19000, 19200, 19000, 19200, 36000}, - {34, 20100, 20250, 20100, 20250, 36200}, - {35, 18500, 19100, 18500, 19100, 36350}, - {36, 19300, 19900, 19300, 19900, 36950}, - {37, 19100, 19300, 19100, 19300, 37550}, - {38, 25700, 26200, 25700, 26300, 37750}, - {39, 18800, 19200, 18800, 19200, 38250}, - {40, 23000, 24000, 23000, 24000, 38650}, - {41, 24960, 26900, 24960, 26900, 39650}, - {42, 34000, 36000, 34000, 36000, 41590}, - {43, 36000, 38000, 36000, 38000, 43590}, - {44, 7030 , 8030, 7030, 8030, 45590}, - {45, 14470, 14670, 14470, 14670, 46590}, - {46, 51500, 59250, 51500, 59250, 46790}, - {65, 19200, 20100, 21100, 22000, 65536}, - {66, 17100, 18000, 21100, 22000, 66436}, - {67, 0 , 0 , 7380, 7580, 67336}, - {68, 6980 , 7280 , 7530, 7830, 67536}}; + {1, 19200, 19800, 21100, 21700, 0}, + {2, 18500, 19100, 19300, 19900, 6000}, + {3, 17100, 17850, 18050, 18800, 12000}, + {4, 17100, 17550, 21100, 21550, 19500}, + {5, 8240, 8490, 8690, 8940, 24000}, + {6, 8300, 8400, 8750, 8850, 26500}, + {7, 25000, 25700, 26200, 26900, 27500}, + {8, 8800, 9150, 9250, 9600, 34500}, + {9, 17499, 17849, 18449, 18799, 38000}, + {10, 17100, 17700, 21100, 21700, 41500}, + {11, 14279, 14529, 14759, 15009, 47500}, + {12, 6980, 7160, 7280, 7460, 50100}, + {13, 7770, 7870, 7460, 7560, 51800}, + {14, 7880, 7980, 7580, 7680, 52800}, + {17, 7040, 7160, 7340, 7460, 57300}, + {18, 8150, 9650, 8600, 10100, 58500}, + {19, 8300, 8450, 8750, 8900, 60000}, + {20, 8320, 8620, 7910, 8210, 61500}, + {21, 14479, 14629, 14959, 15109, 64500}, + {22, 34100, 34900, 35100, 35900, 66000}, + {23, 20000, 20200, 21800, 22000, 75000}, + {24, 16126, 16605, 15250, 15590, 77000}, + {25, 18500, 19150, 19300, 19950, 80400}, + {26, 8140, 8490, 8590, 8940, 86900}, + {27, 8070, 8240, 8520, 8690, 90400}, + {28, 7030, 7580, 7580, 8130, 92100}, + {29, 0, 0, 7170, 7280, 96600}, + {30, 23050, 23250, 23500, 23600, 97700}, + {31, 45250, 34900, 46250, 35900, 98700}, + {32, 0, 0, 14520, 14960, 99200}, + {33, 19000, 19200, 19000, 19200, 36000}, + {34, 20100, 20250, 20100, 20250, 36200}, + {35, 18500, 19100, 18500, 19100, 36350}, + {36, 19300, 19900, 19300, 19900, 36950}, + {37, 19100, 19300, 19100, 19300, 37550}, + {38, 25700, 26200, 25700, 26300, 37750}, + {39, 18800, 19200, 18800, 19200, 38250}, + {40, 23000, 24000, 23000, 24000, 38650}, + {41, 24960, 26900, 24960, 26900, 39650}, + {42, 34000, 36000, 34000, 36000, 41590}, + {43, 36000, 38000, 36000, 38000, 43590}, + {44, 7030, 8030, 7030, 8030, 45590}, + {45, 14470, 14670, 14470, 14670, 46590}, + {46, 51500, 59250, 51500, 59250, 46790}, + {65, 19200, 20100, 21100, 22000, 65536}, + {66, 17100, 18000, 21100, 22000, 66436}, + {67, 0, 0, 7380, 7580, 67336}, + {68, 6980, 7280, 7530, 7830, 67536} +}; -uint32_t to_earfcn(int eutra_bandP,uint32_t dl_CarrierFreq,uint32_t bw) { +uint32_t to_earfcn(int eutra_bandP, uint32_t dl_CarrierFreq, uint32_t bw) +{ - uint32_t dl_CarrierFreq_by_100k = dl_CarrierFreq/100000; - int bw_by_100 = bw/100; + uint32_t dl_CarrierFreq_by_100k = dl_CarrierFreq / 100000; + int bw_by_100 = bw / 100; - int i; + int i; - AssertFatal(eutra_bandP < 69,"eutra_band %d > 68\n",eutra_bandP); - for (i=0;i<69 && eutra_bandtable[i].band!=eutra_bandP;i++); + AssertFatal(eutra_bandP < 69, "eutra_band %d > 68\n", eutra_bandP); + for (i = 0; i < 69 && eutra_bandtable[i].band != eutra_bandP; i++); - AssertFatal(dl_CarrierFreq_by_100k>=eutra_bandtable[i].dl_min, - "Band %d, bw %u : DL carrier frequency %u Hz < %u\n", - eutra_bandP,bw,dl_CarrierFreq,eutra_bandtable[i].dl_min); - AssertFatal(dl_CarrierFreq_by_100k<=(eutra_bandtable[i].dl_max-bw_by_100), - "Band %d, bw %u: DL carrier frequency %u Hz > %d\n", - eutra_bandP,bw,dl_CarrierFreq,eutra_bandtable[i].dl_max-bw_by_100); + AssertFatal(dl_CarrierFreq_by_100k >= eutra_bandtable[i].dl_min, + "Band %d, bw %u : DL carrier frequency %u Hz < %u\n", + eutra_bandP, bw, dl_CarrierFreq, + eutra_bandtable[i].dl_min); + AssertFatal(dl_CarrierFreq_by_100k <= + (eutra_bandtable[i].dl_max - bw_by_100), + "Band %d, bw %u: DL carrier frequency %u Hz > %d\n", + eutra_bandP, bw, dl_CarrierFreq, + eutra_bandtable[i].dl_max - bw_by_100); - return(dl_CarrierFreq_by_100k - eutra_bandtable[i].dl_min + (eutra_bandtable[i].N_OFFs_DL/10)); + return (dl_CarrierFreq_by_100k - eutra_bandtable[i].dl_min + + (eutra_bandtable[i].N_OFFs_DL / 10)); } -uint32_t from_earfcn(int eutra_bandP,uint32_t dl_earfcn) { +uint32_t from_earfcn(int eutra_bandP, uint32_t dl_earfcn) +{ - int i; + int i; - AssertFatal(eutra_bandP < 69,"eutra_band %d > 68\n",eutra_bandP); - for (i=0;i<69 && eutra_bandtable[i].band!=eutra_bandP;i++); + AssertFatal(eutra_bandP < 69, "eutra_band %d > 68\n", eutra_bandP); + for (i = 0; i < 69 && eutra_bandtable[i].band != eutra_bandP; i++); - return(eutra_bandtable[i].dl_min + (dl_earfcn-(eutra_bandtable[i].N_OFFs_DL/10)))*100000; + return (eutra_bandtable[i].dl_min + + (dl_earfcn - (eutra_bandtable[i].N_OFFs_DL / 10))) * 100000; } -int32_t get_uldl_offset(int eutra_bandP) { - int i; +int32_t get_uldl_offset(int eutra_bandP) +{ + int i; - for (i=0;i<69 && eutra_bandtable[i].band!=eutra_bandP;i++); - return(eutra_bandtable[i].dl_min - eutra_bandtable[i].ul_min); + for (i = 0; i < 69 && eutra_bandtable[i].band != eutra_bandP; i++); + return (eutra_bandtable[i].dl_min - eutra_bandtable[i].ul_min); } -uint32_t bw_table[6] = {6*180,15*180,25*180,50*180,75*180,100*180}; +uint32_t bw_table[6] = + { 6 * 180, 15 * 180, 25 * 180, 50 * 180, 75 * 180, 100 * 180 }; -void config_mib(int Mod_idP, - int CC_idP, - int eutra_bandP, - int dl_BandwidthP, - PHICH_Config_t *phich_configP, - int Nid_cellP, - int NcpP, - int p_eNBP, - uint32_t dl_CarrierFreqP, - uint32_t ul_CarrierFreqP, - uint32_t pbch_repetitionP) { +void +config_mib(int Mod_idP, + int CC_idP, + int eutra_bandP, + int dl_BandwidthP, + PHICH_Config_t * phich_configP, + int Nid_cellP, + int NcpP, + int p_eNBP, + uint32_t dl_CarrierFreqP, + uint32_t ul_CarrierFreqP, uint32_t pbch_repetitionP) +{ - nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; - - cfg->subframe_config.pcfich_power_offset.value = 6000; // 0dB - cfg->subframe_config.dl_cyclic_prefix_type.value = NcpP; - cfg->subframe_config.ul_cyclic_prefix_type.value = NcpP; - - LOG_I(MAC,"Ncp %d,p_eNB %d\n",NcpP,p_eNBP); + nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; - cfg->rf_config.dl_channel_bandwidth.value = dl_BandwidthP; - cfg->rf_config.ul_channel_bandwidth.value = dl_BandwidthP; - cfg->rf_config.tx_antenna_ports.value = p_eNBP; - cfg->rf_config.rx_antenna_ports.value = 2; + cfg->subframe_config.pcfich_power_offset.value = 6000; // 0dB + cfg->subframe_config.dl_cyclic_prefix_type.value = NcpP; + cfg->subframe_config.ul_cyclic_prefix_type.value = NcpP; - cfg->nfapi_config.earfcn.value = to_earfcn(eutra_bandP,dl_CarrierFreqP,bw_table[dl_BandwidthP]/100); - cfg->nfapi_config.rf_bands.number_rf_bands = 1; - cfg->nfapi_config.rf_bands.rf_band[0] = eutra_bandP; - cfg->phich_config.phich_resource.value = phich_configP->phich_Resource; - cfg->phich_config.phich_duration.value = phich_configP->phich_Duration; - cfg->phich_config.phich_power_offset.value = 6000; // 0dB + LOG_I(MAC, "Ncp %d,p_eNB %d\n", NcpP, p_eNBP); - cfg->sch_config.primary_synchronization_signal_epre_eprers.value = 6000; // 0dB - cfg->sch_config.secondary_synchronization_signal_epre_eprers.value = 6000; // 0dB - cfg->sch_config.physical_cell_id.value = Nid_cellP; + cfg->rf_config.dl_channel_bandwidth.value = dl_BandwidthP; + cfg->rf_config.ul_channel_bandwidth.value = dl_BandwidthP; + cfg->rf_config.tx_antenna_ports.value = p_eNBP; + cfg->rf_config.rx_antenna_ports.value = 2; + + cfg->nfapi_config.earfcn.value = + to_earfcn(eutra_bandP, dl_CarrierFreqP, + bw_table[dl_BandwidthP] / 100); + cfg->nfapi_config.rf_bands.number_rf_bands = 1; + cfg->nfapi_config.rf_bands.rf_band[0] = eutra_bandP; + cfg->phich_config.phich_resource.value = phich_configP->phich_Resource; + cfg->phich_config.phich_duration.value = phich_configP->phich_Duration; + cfg->phich_config.phich_power_offset.value = 6000; // 0dB + + cfg->sch_config.primary_synchronization_signal_epre_eprers.value = 6000; // 0dB + cfg->sch_config.secondary_synchronization_signal_epre_eprers.value = 6000; // 0dB + cfg->sch_config.physical_cell_id.value = Nid_cellP; #ifdef Rel14 - cfg->emtc_config.pbch_repetitions_enable_r13.value = pbch_repetitionP; -#endif + cfg->emtc_config.pbch_repetitions_enable_r13.value = pbch_repetitionP; +#endif } -void config_sib1(int Mod_idP, +void config_sib1(int Mod_idP, int CC_idP, TDD_Config_t * tdd_ConfigP) +{ + + nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; + + if (tdd_ConfigP) { //TDD + cfg->subframe_config.duplex_mode.value = 0; + cfg->tdd_frame_structure_config.subframe_assignment.value = + tdd_ConfigP->subframeAssignment; + cfg->tdd_frame_structure_config.special_subframe_patterns.value = + tdd_ConfigP->specialSubframePatterns; + } else { // FDD + cfg->subframe_config.duplex_mode.value = 1; + // Note no half-duplex here + } + + +} + +int power_off_dB[6] = { 78, 118, 140, 170, 188, 200 }; + +void +config_sib2(int Mod_idP, + int CC_idP, + RadioResourceConfigCommonSIB_t * radioResourceConfigCommonP, +#ifdef Rel14 + RadioResourceConfigCommonSIB_t * radioResourceConfigCommon_BRP, +#endif + ARFCN_ValueEUTRA_t * ul_CArrierFreqP, + long *ul_BandwidthP, + AdditionalSpectrumEmission_t * + additionalSpectrumEmissionP, + struct MBSFN_SubframeConfigList *mbsfn_SubframeConfigListP) +{ + + nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; + + cfg->subframe_config.pb.value = + radioResourceConfigCommonP->pdsch_ConfigCommon.p_b; + cfg->rf_config.reference_signal_power.value = + radioResourceConfigCommonP->pdsch_ConfigCommon. + referenceSignalPower; + cfg->nfapi_config.max_transmit_power.value = + cfg->rf_config.reference_signal_power.value + + power_off_dB[cfg->rf_config.dl_channel_bandwidth.value]; + + cfg->prach_config.configuration_index.value = + radioResourceConfigCommonP->prach_Config. + prach_ConfigInfo.prach_ConfigIndex; + cfg->prach_config.root_sequence_index.value = + radioResourceConfigCommonP->prach_Config.rootSequenceIndex; + cfg->prach_config.zero_correlation_zone_configuration.value = + radioResourceConfigCommonP->prach_Config. + prach_ConfigInfo.zeroCorrelationZoneConfig; + cfg->prach_config.high_speed_flag.value = + radioResourceConfigCommonP->prach_Config.prach_ConfigInfo. + highSpeedFlag; + cfg->prach_config.frequency_offset.value = + radioResourceConfigCommonP->prach_Config. + prach_ConfigInfo.prach_FreqOffset; + + cfg->pusch_config.hopping_mode.value = + radioResourceConfigCommonP->pusch_ConfigCommon. + pusch_ConfigBasic.hoppingMode; + cfg->pusch_config.number_of_subbands.value = + radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic. + n_SB; + cfg->pusch_config.hopping_offset.value = + radioResourceConfigCommonP->pusch_ConfigCommon. + pusch_ConfigBasic.pusch_HoppingOffset; + + + + cfg->pucch_config.delta_pucch_shift.value = + radioResourceConfigCommonP->pucch_ConfigCommon.deltaPUCCH_Shift; + cfg->pucch_config.n_cqi_rb.value = + radioResourceConfigCommonP->pucch_ConfigCommon.nRB_CQI; + cfg->pucch_config.n_an_cs.value = + radioResourceConfigCommonP->pucch_ConfigCommon.nCS_AN; + cfg->pucch_config.n1_pucch_an.value = + radioResourceConfigCommonP->pucch_ConfigCommon.n1PUCCH_AN; + + if (radioResourceConfigCommonP-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled == + true) + cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 1; + else if (radioResourceConfigCommonP-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. + sequenceHoppingEnabled == true) + cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 2; + else // No hopping + cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 0; + + cfg->uplink_reference_signal_config.group_assignment.value = + radioResourceConfigCommonP-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH; + cfg->uplink_reference_signal_config.cyclic_shift_1_for_drms.value = + radioResourceConfigCommonP-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift; + + // how to enable/disable SRS? + if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.present == + SoundingRS_UL_ConfigCommon_PR_setup) { + cfg->srs_config.bandwidth_configuration.value = + radioResourceConfigCommonP->soundingRS_UL_ConfigCommon. + choice.setup.srs_BandwidthConfig; + cfg->srs_config.srs_subframe_configuration.value = + radioResourceConfigCommonP->soundingRS_UL_ConfigCommon. + choice.setup.srs_SubframeConfig; + cfg->srs_config.srs_acknack_srs_simultaneous_transmission.value = + radioResourceConfigCommonP->soundingRS_UL_ConfigCommon. + choice.setup.ackNackSRS_SimultaneousTransmission; + + if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon. + choice.setup.srs_MaxUpPts) + cfg->srs_config.max_up_pts.value = 1; + else + cfg->srs_config.max_up_pts.value = 0; + } +#ifdef Rel14 + if (RC.mac[Mod_idP]->common_channels[CC_idP].mib-> + message.schedulingInfoSIB1_BR_r13 > 0) { + AssertFatal(radioResourceConfigCommon_BRP != NULL, + "radioResource rou is missing\n"); + AssertFatal(radioResourceConfigCommon_BRP->ext4 != NULL, + "ext4 is missing\n"); + cfg->emtc_config.prach_catm_root_sequence_index.value = + radioResourceConfigCommon_BRP->prach_Config.rootSequenceIndex; + cfg->emtc_config.prach_catm_zero_correlation_zone_configuration. + value = + radioResourceConfigCommon_BRP->prach_Config. + prach_ConfigInfo.zeroCorrelationZoneConfig; + cfg->emtc_config.prach_catm_high_speed_flag.value = + radioResourceConfigCommon_BRP->prach_Config. + prach_ConfigInfo.highSpeedFlag; + + struct PRACH_ConfigSIB_v1310 *ext4_prach = + radioResourceConfigCommon_BRP->ext4->prach_ConfigCommon_v1310; + + PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13 = + &ext4_prach->prach_ParametersListCE_r13; + + PRACH_ParametersCE_r13_t *p; + cfg->emtc_config.prach_ce_level_0_enable.value = 0; + cfg->emtc_config.prach_ce_level_1_enable.value = 0; + cfg->emtc_config.prach_ce_level_2_enable.value = 0; + cfg->emtc_config.prach_ce_level_3_enable.value = 0; + switch (prach_ParametersListCE_r13->list.count) { + case 4: + p = prach_ParametersListCE_r13->list.array[3]; + cfg->emtc_config.prach_ce_level_3_enable.value = 1; + cfg->emtc_config.prach_ce_level_3_configuration_index.value = + p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_3_frequency_offset.value = + p->prach_FreqOffset_r13; + cfg-> + emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt. + value = p->numRepetitionPerPreambleAttempt_r13; + if (p->prach_StartingSubframe_r13) + cfg-> + emtc_config.prach_ce_level_3_starting_subframe_periodicity. + value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_3_hopping_enable.value = + p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_3_hopping_offset.value = + cfg->rf_config.ul_channel_bandwidth.value - 6; + case 3: + p = prach_ParametersListCE_r13->list.array[2]; + cfg->emtc_config.prach_ce_level_2_enable.value = 1; + cfg->emtc_config.prach_ce_level_2_configuration_index.value = + p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_2_frequency_offset.value = + p->prach_FreqOffset_r13; + cfg-> + emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt. + value = p->numRepetitionPerPreambleAttempt_r13; + if (p->prach_StartingSubframe_r13) + cfg-> + emtc_config.prach_ce_level_2_starting_subframe_periodicity. + value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_2_hopping_enable.value = + p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_2_hopping_offset.value = + cfg->rf_config.ul_channel_bandwidth.value - 6; + case 2: + p = prach_ParametersListCE_r13->list.array[1]; + cfg->emtc_config.prach_ce_level_1_enable.value = 1; + cfg->emtc_config.prach_ce_level_1_configuration_index.value = + p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_1_frequency_offset.value = + p->prach_FreqOffset_r13; + cfg-> + emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt. + value = p->numRepetitionPerPreambleAttempt_r13; + if (p->prach_StartingSubframe_r13) + cfg-> + emtc_config.prach_ce_level_1_starting_subframe_periodicity. + value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_1_hopping_enable.value = + p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_1_hopping_offset.value = + cfg->rf_config.ul_channel_bandwidth.value - 6; + case 1: + p = prach_ParametersListCE_r13->list.array[0]; + cfg->emtc_config.prach_ce_level_0_enable.value = 1; + cfg->emtc_config.prach_ce_level_0_configuration_index.value = + p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_0_frequency_offset.value = + p->prach_FreqOffset_r13; + cfg-> + emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt. + value = p->numRepetitionPerPreambleAttempt_r13; + if (p->prach_StartingSubframe_r13) + cfg-> + emtc_config.prach_ce_level_0_starting_subframe_periodicity. + value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_0_hopping_enable.value = + p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_0_hopping_offset.value = + cfg->rf_config.ul_channel_bandwidth.value - 6; + } + + struct FreqHoppingParameters_r13 *ext4_freqHoppingParameters = + radioResourceConfigCommonP->ext4->freqHoppingParameters_r13; + if ((ext4_freqHoppingParameters) + && + (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13)) + { + switch + (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13-> + present) { + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_NOTHING: /* No components present */ + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_FDD_r13: + cfg->emtc_config. + pucch_interval_ulhoppingconfigcommonmodea.value = + ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13-> + choice.interval_FDD_r13; + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_TDD_r13: + cfg->emtc_config. + pucch_interval_ulhoppingconfigcommonmodea.value = + ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13-> + choice.interval_TDD_r13; + break; + } + } + if ((ext4_freqHoppingParameters) && + (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13)) + { + switch + (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> + present) { + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_NOTHING: /* No components present */ + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_FDD_r13: + cfg->emtc_config. + pucch_interval_ulhoppingconfigcommonmodeb.value = + ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> + choice.interval_FDD_r13; + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_TDD_r13: + cfg->emtc_config. + pucch_interval_ulhoppingconfigcommonmodeb.value = + ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> + choice.interval_TDD_r13; + break; + } + } + } +#endif + +} + +void +config_dedicated(int Mod_idP, int CC_idP, - TDD_Config_t *tdd_ConfigP) { - - nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; - - if (tdd_ConfigP) { //TDD - cfg->subframe_config.duplex_mode.value = 0; - cfg->tdd_frame_structure_config.subframe_assignment.value = tdd_ConfigP->subframeAssignment; - cfg->tdd_frame_structure_config.special_subframe_patterns.value = tdd_ConfigP->specialSubframePatterns; - } - else { // FDD - cfg->subframe_config.duplex_mode.value = 1; - // Note no half-duplex here - } - - -} - -int power_off_dB[6] = {78,118,140,170,188,200}; - -void config_sib2(int Mod_idP, - int CC_idP, - RadioResourceConfigCommonSIB_t *radioResourceConfigCommonP, -#ifdef Rel14 - RadioResourceConfigCommonSIB_t *radioResourceConfigCommon_BRP, -#endif - ARFCN_ValueEUTRA_t *ul_CArrierFreqP, - long *ul_BandwidthP, - AdditionalSpectrumEmission_t *additionalSpectrumEmissionP, - struct MBSFN_SubframeConfigList *mbsfn_SubframeConfigListP) { - - nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; - - cfg->subframe_config.pb.value = radioResourceConfigCommonP->pdsch_ConfigCommon.p_b; - cfg->rf_config.reference_signal_power.value = radioResourceConfigCommonP->pdsch_ConfigCommon.referenceSignalPower; - cfg->nfapi_config.max_transmit_power.value = cfg->rf_config.reference_signal_power.value + power_off_dB[cfg->rf_config.dl_channel_bandwidth.value]; - - cfg->prach_config.configuration_index.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.prach_ConfigIndex; - cfg->prach_config.root_sequence_index.value = radioResourceConfigCommonP->prach_Config.rootSequenceIndex; - cfg->prach_config.zero_correlation_zone_configuration.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig; - cfg->prach_config.high_speed_flag.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.highSpeedFlag; - cfg->prach_config.frequency_offset.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.prach_FreqOffset; - - cfg->pusch_config.hopping_mode.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode; - cfg->pusch_config.number_of_subbands.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.n_SB; - cfg->pusch_config.hopping_offset.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset; - - - - cfg->pucch_config.delta_pucch_shift.value = radioResourceConfigCommonP->pucch_ConfigCommon.deltaPUCCH_Shift; - cfg->pucch_config.n_cqi_rb.value = radioResourceConfigCommonP->pucch_ConfigCommon.nRB_CQI; - cfg->pucch_config.n_an_cs.value = radioResourceConfigCommonP->pucch_ConfigCommon.nCS_AN; - cfg->pucch_config.n1_pucch_an.value = radioResourceConfigCommonP->pucch_ConfigCommon.n1PUCCH_AN; - - if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled == true) - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 1; - else if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled == true) - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 2; - else // No hopping - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 0; - - cfg->uplink_reference_signal_config.group_assignment.value = radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH; - cfg->uplink_reference_signal_config.cyclic_shift_1_for_drms.value = radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift; - - // how to enable/disable SRS? - if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.present==SoundingRS_UL_ConfigCommon_PR_setup) { - cfg->srs_config.bandwidth_configuration.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_BandwidthConfig; - cfg->srs_config.srs_subframe_configuration.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig; - cfg->srs_config.srs_acknack_srs_simultaneous_transmission.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; - - if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts) - cfg->srs_config.max_up_pts.value = 1; - else - cfg->srs_config.max_up_pts.value = 0; - } - -#ifdef Rel14 - if (RC.mac[Mod_idP]->common_channels[CC_idP].mib->message.schedulingInfoSIB1_BR_r13>0) { - AssertFatal(radioResourceConfigCommon_BRP!=NULL,"radioResource rou is missing\n"); - AssertFatal(radioResourceConfigCommon_BRP->ext4!=NULL,"ext4 is missing\n"); - cfg->emtc_config.prach_catm_root_sequence_index.value = radioResourceConfigCommon_BRP->prach_Config.rootSequenceIndex; - cfg->emtc_config.prach_catm_zero_correlation_zone_configuration.value = radioResourceConfigCommon_BRP->prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig; - cfg->emtc_config.prach_catm_high_speed_flag.value = radioResourceConfigCommon_BRP->prach_Config.prach_ConfigInfo.highSpeedFlag; - - struct PRACH_ConfigSIB_v1310 *ext4_prach=radioResourceConfigCommon_BRP->ext4->prach_ConfigCommon_v1310; - - PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13; - - PRACH_ParametersCE_r13_t *p; - cfg->emtc_config.prach_ce_level_0_enable.value=0; - cfg->emtc_config.prach_ce_level_1_enable.value=0; - cfg->emtc_config.prach_ce_level_2_enable.value=0; - cfg->emtc_config.prach_ce_level_3_enable.value=0; - switch (prach_ParametersListCE_r13->list.count) { - case 4: - p=prach_ParametersListCE_r13->list.array[3]; - cfg->emtc_config.prach_ce_level_3_enable.value = 1; - cfg->emtc_config.prach_ce_level_3_configuration_index.value = p->prach_ConfigIndex_r13; - cfg->emtc_config.prach_ce_level_3_frequency_offset.value = p->prach_FreqOffset_r13; - cfg->emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) - cfg->emtc_config.prach_ce_level_3_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; - cfg->emtc_config.prach_ce_level_3_hopping_enable.value = p->prach_HoppingConfig_r13; - cfg->emtc_config.prach_ce_level_3_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value-6; - case 3: - p=prach_ParametersListCE_r13->list.array[2]; - cfg->emtc_config.prach_ce_level_2_enable.value = 1; - cfg->emtc_config.prach_ce_level_2_configuration_index.value = p->prach_ConfigIndex_r13; - cfg->emtc_config.prach_ce_level_2_frequency_offset.value = p->prach_FreqOffset_r13; - cfg->emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) - cfg->emtc_config.prach_ce_level_2_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; - cfg->emtc_config.prach_ce_level_2_hopping_enable.value = p->prach_HoppingConfig_r13; - cfg->emtc_config.prach_ce_level_2_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value-6; - case 2: - p=prach_ParametersListCE_r13->list.array[1]; - cfg->emtc_config.prach_ce_level_1_enable.value = 1; - cfg->emtc_config.prach_ce_level_1_configuration_index.value = p->prach_ConfigIndex_r13; - cfg->emtc_config.prach_ce_level_1_frequency_offset.value = p->prach_FreqOffset_r13; - cfg->emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) - cfg->emtc_config.prach_ce_level_1_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; - cfg->emtc_config.prach_ce_level_1_hopping_enable.value = p->prach_HoppingConfig_r13; - cfg->emtc_config.prach_ce_level_1_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value-6; - case 1: - p=prach_ParametersListCE_r13->list.array[0]; - cfg->emtc_config.prach_ce_level_0_enable.value = 1; - cfg->emtc_config.prach_ce_level_0_configuration_index.value = p->prach_ConfigIndex_r13; - cfg->emtc_config.prach_ce_level_0_frequency_offset.value = p->prach_FreqOffset_r13; - cfg->emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) - cfg->emtc_config.prach_ce_level_0_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; - cfg->emtc_config.prach_ce_level_0_hopping_enable.value = p->prach_HoppingConfig_r13; - cfg->emtc_config.prach_ce_level_0_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value-6; - } - - struct FreqHoppingParameters_r13 *ext4_freqHoppingParameters = radioResourceConfigCommonP->ext4->freqHoppingParameters_r13; - if ((ext4_freqHoppingParameters) && - (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13)){ - switch(ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13->present) { - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_NOTHING: /* No components present */ - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_FDD_r13: - cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodea.value = ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13->choice.interval_FDD_r13; - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_TDD_r13: - cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodea.value = ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13->choice.interval_TDD_r13; - break; - } - } - if ((ext4_freqHoppingParameters) && - (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13)){ - switch(ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13->present) { - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_NOTHING: /* No components present */ - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_FDD_r13: - cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodeb.value = ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13->choice.interval_FDD_r13; - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_TDD_r13: - cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodeb.value = ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13->choice.interval_TDD_r13; - break; - } - } - } -#endif + uint16_t rnti, + struct PhysicalConfigDedicated *physicalConfigDedicated) +{ } -void config_dedicated(int Mod_idP, - int CC_idP, - uint16_t rnti, - struct PhysicalConfigDedicated *physicalConfigDedicated) { +void +config_dedicated_scell(int Mod_idP, + uint16_t rnti, + SCellToAddMod_r10_t * sCellToAddMod_r10) +{ } -void config_dedicated_scell(int Mod_idP, - uint16_t rnti, - SCellToAddMod_r10_t *sCellToAddMod_r10) { - -} - -int rrc_mac_config_req_eNB(module_id_t Mod_idP, - int CC_idP, - int physCellId, - int p_eNB, - int Ncp, - int eutra_band, - uint32_t dl_CarrierFreq, -#ifdef Rel14 - int pbch_repetition, -#endif - rnti_t rntiP, - BCCH_BCH_Message_t *mib, - RadioResourceConfigCommonSIB_t *radioResourceConfigCommon, -#ifdef Rel14 - RadioResourceConfigCommonSIB_t *radioResourceConfigCommon_BR, -#endif - struct PhysicalConfigDedicated *physicalConfigDedicated, -#if defined(Rel10) || defined(Rel14) - SCellToAddMod_r10_t *sCellToAddMod_r10, - //struct PhysicalConfigDedicatedSCell_r10 *physicalConfigDedicatedSCell_r10, -#endif - MeasObjectToAddMod_t **measObj, - MAC_MainConfig_t *mac_MainConfig, - long logicalChannelIdentity, - LogicalChannelConfig_t *logicalChannelConfig, - MeasGapConfig_t *measGapConfig, - TDD_Config_t *tdd_Config, - MobilityControlInfo_t *mobilityControlInfo, - SchedulingInfoList_t *schedulingInfoList, - uint32_t ul_CarrierFreq, - long *ul_Bandwidth, - AdditionalSpectrumEmission_t *additionalSpectrumEmission, - struct MBSFN_SubframeConfigList *mbsfn_SubframeConfigList -#if defined(Rel10) || defined(Rel14) - ,uint8_t MBMS_Flag, - MBSFN_AreaInfoList_r9_t *mbsfn_AreaInfoList, - PMCH_InfoList_r9_t *pmch_InfoList -#endif -#ifdef Rel14 - , - SystemInformationBlockType1_v1310_IEs_t *sib1_v13ext -#endif - ) { - - int i; - - int UE_id = -1; - eNB_MAC_INST *eNB = RC.mac[Mod_idP]; - UE_list_t *UE_list= &eNB->UE_list; - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN); - - - if (mib!=NULL) { - if (RC.mac == NULL) l2_init_eNB(); - - mac_top_init_eNB(); - - RC.mac[Mod_idP]->common_channels[CC_idP].mib = mib; - RC.mac[Mod_idP]->common_channels[CC_idP].physCellId = physCellId; - RC.mac[Mod_idP]->common_channels[CC_idP].p_eNB = p_eNB; - RC.mac[Mod_idP]->common_channels[CC_idP].Ncp = Ncp; - RC.mac[Mod_idP]->common_channels[CC_idP].eutra_band = eutra_band; - RC.mac[Mod_idP]->common_channels[CC_idP].dl_CarrierFreq = dl_CarrierFreq; - - LOG_I(MAC, - "Configuring MIB for instance %d, CCid %d : (band %d,N_RB_DL %d,Nid_cell %d,p %d,DL freq %u,phich_config.resource %d, phich_config.duration %d)\n", - Mod_idP, - CC_idP, - eutra_band, - to_prb((int)mib->message.dl_Bandwidth), - physCellId, - p_eNB, - dl_CarrierFreq, - (int)mib->message.phich_Config.phich_Resource, - (int)mib->message.phich_Config.phich_Duration); - - config_mib(Mod_idP,CC_idP, - eutra_band, - mib->message.dl_Bandwidth, - &mib->message.phich_Config, - physCellId, - Ncp, - p_eNB, - dl_CarrierFreq, - ul_CarrierFreq -#ifdef Rel14 - ,pbch_repetition -#endif - ); - - mac_init_cell_params(Mod_idP,CC_idP); - } - if (schedulingInfoList!=NULL) { - RC.mac[Mod_idP]->common_channels[CC_idP].tdd_Config = tdd_Config; - RC.mac[Mod_idP]->common_channels[CC_idP].schedulingInfoList = schedulingInfoList; - config_sib1(Mod_idP,CC_idP,tdd_Config); - } -#ifdef Rel14 - if (sib1_v13ext != NULL) { - RC.mac[Mod_idP]->common_channels[CC_idP].sib1_v13ext = sib1_v13ext; - } -#endif - if (radioResourceConfigCommon!=NULL) { - LOG_I(MAC,"[CONFIG]SIB2/3 Contents (partial)\n"); - LOG_I(MAC,"[CONFIG]pusch_config_common.n_SB = %ld\n",radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.n_SB); - LOG_I(MAC,"[CONFIG]pusch_config_common.hoppingMode = %ld\n",radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode); - LOG_I(MAC,"[CONFIG]pusch_config_common.pusch_HoppingOffset = %ld\n", radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset); - LOG_I(MAC,"[CONFIG]pusch_config_common.enable64QAM = %d\n",radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.enable64QAM); - LOG_I(MAC,"[CONFIG]pusch_config_common.groupHoppingEnabled = %d\n",radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled); - LOG_I(MAC,"[CONFIG]pusch_config_common.groupAssignmentPUSCH = %ld\n",radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH); - LOG_I(MAC,"[CONFIG]pusch_config_common.sequenceHoppingEnabled = %d\n",radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled); - LOG_I(MAC,"[CONFIG]pusch_config_common.cyclicShift = %ld\n",radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift); - - AssertFatal(radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx > 0, - "radioResourceconfigCommon %d == 0\n", - (int)radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx); - - RC.mac[Mod_idP]->common_channels[CC_idP].radioResourceConfigCommon = radioResourceConfigCommon; - if (ul_CarrierFreq>0) RC.mac[Mod_idP]->common_channels[CC_idP].ul_CarrierFreq = ul_CarrierFreq; - if (ul_Bandwidth) RC.mac[Mod_idP]->common_channels[CC_idP].ul_Bandwidth = *ul_Bandwidth; - else RC.mac[Mod_idP]->common_channels[CC_idP].ul_Bandwidth = RC.mac[Mod_idP]->common_channels[CC_idP].mib->message.dl_Bandwidth; - - config_sib2(Mod_idP, CC_idP, - radioResourceConfigCommon, -#ifdef Rel14 - radioResourceConfigCommon_BR, -#endif - NULL, ul_Bandwidth, additionalSpectrumEmission, mbsfn_SubframeConfigList); - - - } - - - // SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup - if (logicalChannelConfig!= NULL) { // check for eMTC specific things - UE_id = find_UE_id(Mod_idP, rntiP); - - if (UE_id == -1) { - LOG_E(MAC,"%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, __LINE__, __FUNCTION__); - } else { - if (logicalChannelConfig) - UE_list->UE_template[CC_idP][UE_id].lcgidmap[logicalChannelIdentity] = *logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup; - else - UE_list->UE_template[CC_idP][UE_id].lcgidmap[logicalChannelIdentity] = 0; - } - } - - - if (physicalConfigDedicated != NULL) { - UE_id = find_UE_id(Mod_idP, rntiP); - - if (UE_id == -1) - LOG_E(MAC,"%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, __LINE__, __FUNCTION__); - else - UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated=physicalConfigDedicated; - } - - - - -#if defined(Rel10) || defined(Rel14) - - if (sCellToAddMod_r10 != NULL) { - UE_id = find_UE_id(Mod_idP, rntiP); - if (UE_id == -1) - LOG_E(MAC,"%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, __LINE__, __FUNCTION__); - else - config_dedicated_scell(Mod_idP,rntiP,sCellToAddMod_r10); - - } - -#endif - - - - - if (mbsfn_SubframeConfigList != NULL) { - LOG_I(MAC,"[eNB %d][CONFIG] Received %d subframe allocation pattern for MBSFN\n", Mod_idP, mbsfn_SubframeConfigList->list.count); - RC.mac[Mod_idP]->common_channels[0].num_sf_allocation_pattern= mbsfn_SubframeConfigList->list.count; - - for (i=0; ilist.count; i++) { - RC.mac[Mod_idP]->common_channels[0].mbsfn_SubframeConfig[i] = mbsfn_SubframeConfigList->list.array[i]; - LOG_I(MAC, "[eNB %d][CONFIG] MBSFN_SubframeConfig[%d] pattern is %x\n", Mod_idP, i, - RC.mac[Mod_idP]->common_channels[0].mbsfn_SubframeConfig[i]->subframeAllocation.choice.oneFrame.buf[0]); - } - -#ifdef Rel10 - RC.mac[Mod_idP]->common_channels[0].MBMS_flag = MBMS_Flag; -#endif - } - -#if defined(Rel10) || defined(Rel14) - - if (mbsfn_AreaInfoList != NULL) { - // One eNB could be part of multiple mbsfn syc area, this could change over time so reset each time - LOG_I(MAC,"[eNB %d][CONFIG] Received %d MBSFN Area Info\n", Mod_idP, mbsfn_AreaInfoList->list.count); - RC.mac[Mod_idP]->common_channels[0].num_active_mbsfn_area = mbsfn_AreaInfoList->list.count; - - for (i =0; i< mbsfn_AreaInfoList->list.count; i++) { - RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i] = mbsfn_AreaInfoList->list.array[i]; - LOG_I(MAC,"[eNB %d][CONFIG] MBSFN_AreaInfo[%d]: MCCH Repetition Period = %ld\n", Mod_idP,i, - RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_RepetitionPeriod_r9); - // config_sib13(Mod_idP,0,i,RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i]->mbsfn_AreaId_r9); - } - } - - if (pmch_InfoList != NULL) { - - // LOG_I(MAC,"DUY: lcid when entering rrc_mac config_req is %02d\n",(pmch_InfoList->list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9)); - - LOG_I(MAC, "[CONFIG] Number of PMCH in this MBSFN Area %d\n", pmch_InfoList->list.count); - - for (i =0; i< pmch_InfoList->list.count; i++) { - RC.mac[Mod_idP]->common_channels[0].pmch_Config[i] = &pmch_InfoList->list.array[i]->pmch_Config_r9; - - LOG_I(MAC, "[CONFIG] PMCH[%d]: This PMCH stop (sf_AllocEnd_r9) at subframe %ldth\n", i, - RC.mac[Mod_idP]->common_channels[0].pmch_Config[i]->sf_AllocEnd_r9); - LOG_I(MAC, "[CONFIG] PMCH[%d]: mch_Scheduling_Period = %ld\n", i, - RC.mac[Mod_idP]->common_channels[0].pmch_Config[i]->mch_SchedulingPeriod_r9); - LOG_I(MAC, "[CONFIG] PMCH[%d]: dataMCS = %ld\n", i, - RC.mac[Mod_idP]->common_channels[0].pmch_Config[i]->dataMCS_r9); - - // MBMS session info list in each MCH - RC.mac[Mod_idP]->common_channels[0].mbms_SessionList[i] = &pmch_InfoList->list.array[i]->mbms_SessionInfoList_r9; - LOG_I(MAC, "PMCH[%d] Number of session (MTCH) is: %d\n",i, RC.mac[Mod_idP]->common_channels[0].mbms_SessionList[i]->list.count); - } - } - -#endif - - if (radioResourceConfigCommon!=NULL) { - AssertFatal(RC.mac[Mod_idP]->if_inst->PHY_config_req != NULL,"if_inst->phy_config_request is null\n"); - PHY_Config_t phycfg; - phycfg.Mod_id = Mod_idP; - phycfg.CC_id = CC_idP; - phycfg.cfg = &RC.mac[Mod_idP]->config[CC_idP]; - - if (RC.mac[Mod_idP]->if_inst->PHY_config_req) RC.mac[Mod_idP]->if_inst->PHY_config_req(&phycfg); - } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); - - return(0); -} - int -rrc_mac_config_req_ue( - module_id_t Mod_idP, - int CC_idP, - uint8_t eNB_index, - RadioResourceConfigCommonSIB_t *radioResourceConfigCommon, - struct PhysicalConfigDedicated *physicalConfigDedicated, +rrc_mac_config_req_eNB(module_id_t Mod_idP, + int CC_idP, + int physCellId, + int p_eNB, + int Ncp, int eutra_band, uint32_t dl_CarrierFreq, +#ifdef Rel14 + int pbch_repetition, +#endif + rnti_t rntiP, + BCCH_BCH_Message_t * mib, + RadioResourceConfigCommonSIB_t * + radioResourceConfigCommon, +#ifdef Rel14 + RadioResourceConfigCommonSIB_t * + radioResourceConfigCommon_BR, +#endif + struct PhysicalConfigDedicated + *physicalConfigDedicated, #if defined(Rel10) || defined(Rel14) - SCellToAddMod_r10_t *sCellToAddMod_r10, - //struct PhysicalConfigDedicatedSCell_r10 *physicalConfigDedicatedSCell_r10, + SCellToAddMod_r10_t * sCellToAddMod_r10, + //struct PhysicalConfigDedicatedSCell_r10 *physicalConfigDedicatedSCell_r10, #endif - MeasObjectToAddMod_t **measObj, - MAC_MainConfig_t *mac_MainConfig, - long logicalChannelIdentity, - LogicalChannelConfig_t *logicalChannelConfig, - MeasGapConfig_t *measGapConfig, - TDD_Config_t *tdd_Config, - MobilityControlInfo_t *mobilityControlInfo, - uint8_t *SIwindowsize, - uint16_t *SIperiod, - ARFCN_ValueEUTRA_t *ul_CarrierFreq, - long *ul_Bandwidth, - AdditionalSpectrumEmission_t *additionalSpectrumEmission, - struct MBSFN_SubframeConfigList *mbsfn_SubframeConfigList + MeasObjectToAddMod_t ** measObj, + MAC_MainConfig_t * mac_MainConfig, + long logicalChannelIdentity, + LogicalChannelConfig_t * logicalChannelConfig, + MeasGapConfig_t * measGapConfig, + TDD_Config_t * tdd_Config, + MobilityControlInfo_t * mobilityControlInfo, + SchedulingInfoList_t * schedulingInfoList, + uint32_t ul_CarrierFreq, + long *ul_Bandwidth, + AdditionalSpectrumEmission_t * + additionalSpectrumEmission, + struct MBSFN_SubframeConfigList + *mbsfn_SubframeConfigList #if defined(Rel10) || defined(Rel14) - ,uint8_t MBMS_Flag, - MBSFN_AreaInfoList_r9_t *mbsfn_AreaInfoList, - PMCH_InfoList_r9_t *pmch_InfoList + , uint8_t MBMS_Flag, + MBSFN_AreaInfoList_r9_t * mbsfn_AreaInfoList, + PMCH_InfoList_r9_t * pmch_InfoList #endif -#ifdef CBA - ,uint8_t num_active_cba_groups, - uint16_t cba_rnti +#ifdef Rel14 + , + SystemInformationBlockType1_v1310_IEs_t * + sib1_v13ext #endif - ) + ) { - int i; + int i; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN); + int UE_id = -1; + eNB_MAC_INST *eNB = RC.mac[Mod_idP]; + UE_list_t *UE_list = &eNB->UE_list; - LOG_I(MAC,"[CONFIG][UE %d] Configuring MAC/PHY from eNB %d\n",Mod_idP,eNB_index); - - if (tdd_Config != NULL) { - UE_mac_inst[Mod_idP].tdd_Config = tdd_Config; - } - + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN); - if (tdd_Config && SIwindowsize && SIperiod) { - phy_config_sib1_ue(Mod_idP,0,eNB_index,tdd_Config,*SIwindowsize,*SIperiod); - } - if (radioResourceConfigCommon!=NULL) { - UE_mac_inst[Mod_idP].radioResourceConfigCommon = radioResourceConfigCommon; - phy_config_sib2_ue(Mod_idP,0,eNB_index,radioResourceConfigCommon,ul_CarrierFreq,ul_Bandwidth,additionalSpectrumEmission,mbsfn_SubframeConfigList); - } + if (mib != NULL) { + if (RC.mac == NULL) + l2_init_eNB(); - // SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup - if (logicalChannelConfig!= NULL) { - LOG_I(MAC,"[CONFIG][UE %d] Applying RRC logicalChannelConfig from eNB%d\n",Mod_idP,eNB_index); - UE_mac_inst[Mod_idP].logicalChannelConfig[logicalChannelIdentity]=logicalChannelConfig; - UE_mac_inst[Mod_idP].scheduling_info.Bj[logicalChannelIdentity]=0; // initilize the bucket for this lcid - - AssertFatal(logicalChannelConfig->ul_SpecificParameters!=NULL, - "[UE %d] LCID %ld NULL ul_SpecificParameters\n", - Mod_idP,logicalChannelIdentity); - UE_mac_inst[Mod_idP].scheduling_info.bucket_size[logicalChannelIdentity]=logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate * - logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration; // set the max bucket size - if (logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup != NULL) { - UE_mac_inst[Mod_idP].scheduling_info.LCGID[logicalChannelIdentity]=*logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup; - LOG_D(MAC,"[CONFIG][UE %d] LCID %ld is attached to the LCGID %ld\n",Mod_idP,logicalChannelIdentity,*logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup); + mac_top_init_eNB(); + + RC.mac[Mod_idP]->common_channels[CC_idP].mib = mib; + RC.mac[Mod_idP]->common_channels[CC_idP].physCellId = physCellId; + RC.mac[Mod_idP]->common_channels[CC_idP].p_eNB = p_eNB; + RC.mac[Mod_idP]->common_channels[CC_idP].Ncp = Ncp; + RC.mac[Mod_idP]->common_channels[CC_idP].eutra_band = eutra_band; + RC.mac[Mod_idP]->common_channels[CC_idP].dl_CarrierFreq = + dl_CarrierFreq; + + LOG_I(MAC, + "Configuring MIB for instance %d, CCid %d : (band %d,N_RB_DL %d,Nid_cell %d,p %d,DL freq %u,phich_config.resource %d, phich_config.duration %d)\n", + Mod_idP, + CC_idP, + eutra_band, + to_prb((int) mib->message.dl_Bandwidth), + physCellId, + p_eNB, + dl_CarrierFreq, + (int) mib->message.phich_Config.phich_Resource, + (int) mib->message.phich_Config.phich_Duration); + + config_mib(Mod_idP, CC_idP, + eutra_band, + mib->message.dl_Bandwidth, + &mib->message.phich_Config, + physCellId, Ncp, p_eNB, dl_CarrierFreq, ul_CarrierFreq +#ifdef Rel14 + , pbch_repetition +#endif + ); + + mac_init_cell_params(Mod_idP, CC_idP); } - else { - UE_mac_inst[Mod_idP].scheduling_info.LCGID[logicalChannelIdentity] = MAX_NUM_LCGID; + if (schedulingInfoList != NULL) { + RC.mac[Mod_idP]->common_channels[CC_idP].tdd_Config = tdd_Config; + RC.mac[Mod_idP]->common_channels[CC_idP].schedulingInfoList = + schedulingInfoList; + config_sib1(Mod_idP, CC_idP, tdd_Config); } - UE_mac_inst[Mod_idP].scheduling_info.LCID_buffer_remain[logicalChannelIdentity] = 0; - } +#ifdef Rel14 + if (sib1_v13ext != NULL) { + RC.mac[Mod_idP]->common_channels[CC_idP].sib1_v13ext = sib1_v13ext; + } +#endif + if (radioResourceConfigCommon != NULL) { + LOG_I(MAC, "[CONFIG]SIB2/3 Contents (partial)\n"); + LOG_I(MAC, "[CONFIG]pusch_config_common.n_SB = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.pusch_ConfigBasic.n_SB); + LOG_I(MAC, "[CONFIG]pusch_config_common.hoppingMode = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode); + LOG_I(MAC, + "[CONFIG]pusch_config_common.pusch_HoppingOffset = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset); + LOG_I(MAC, "[CONFIG]pusch_config_common.enable64QAM = %d\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.pusch_ConfigBasic.enable64QAM); + LOG_I(MAC, + "[CONFIG]pusch_config_common.groupHoppingEnabled = %d\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. + groupHoppingEnabled); + LOG_I(MAC, + "[CONFIG]pusch_config_common.groupAssignmentPUSCH = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. + groupAssignmentPUSCH); + LOG_I(MAC, + "[CONFIG]pusch_config_common.sequenceHoppingEnabled = %d\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. + sequenceHoppingEnabled); + LOG_I(MAC, "[CONFIG]pusch_config_common.cyclicShift = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift); - if (mac_MainConfig != NULL) { - LOG_I(MAC,"[CONFIG][UE%d] Applying RRC macMainConfig from eNB%d\n",Mod_idP,eNB_index); - UE_mac_inst[Mod_idP].macConfig=mac_MainConfig; - UE_mac_inst[Mod_idP].measGapConfig=measGapConfig; - - if (mac_MainConfig->ul_SCH_Config) { - - if (mac_MainConfig->ul_SCH_Config->periodicBSR_Timer) { - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer = (uint16_t) *mac_MainConfig->ul_SCH_Config->periodicBSR_Timer; - } else { - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer = + AssertFatal(radioResourceConfigCommon-> + rach_ConfigCommon.maxHARQ_Msg3Tx > 0, + "radioResourceconfigCommon %d == 0\n", + (int) radioResourceConfigCommon-> + rach_ConfigCommon.maxHARQ_Msg3Tx); + + RC.mac[Mod_idP]->common_channels[CC_idP]. + radioResourceConfigCommon = radioResourceConfigCommon; + if (ul_CarrierFreq > 0) + RC.mac[Mod_idP]->common_channels[CC_idP].ul_CarrierFreq = + ul_CarrierFreq; + if (ul_Bandwidth) + RC.mac[Mod_idP]->common_channels[CC_idP].ul_Bandwidth = + *ul_Bandwidth; + else + RC.mac[Mod_idP]->common_channels[CC_idP].ul_Bandwidth = + RC.mac[Mod_idP]->common_channels[CC_idP].mib->message. + dl_Bandwidth; + + config_sib2(Mod_idP, CC_idP, radioResourceConfigCommon, +#ifdef Rel14 + radioResourceConfigCommon_BR, +#endif + NULL, ul_Bandwidth, additionalSpectrumEmission, + mbsfn_SubframeConfigList); + + + } + // SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup + if (logicalChannelConfig != NULL) { // check for eMTC specific things + UE_id = find_UE_id(Mod_idP, rntiP); + + if (UE_id == -1) { + LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, + __LINE__, __FUNCTION__); + } else { + if (logicalChannelConfig) + UE_list-> + UE_template[CC_idP][UE_id].lcgidmap + [logicalChannelIdentity] = + *logicalChannelConfig-> + ul_SpecificParameters->logicalChannelGroup; + else + UE_list-> + UE_template[CC_idP][UE_id].lcgidmap + [logicalChannelIdentity] = 0; + } + } + + + if (physicalConfigDedicated != NULL) { + UE_id = find_UE_id(Mod_idP, rntiP); + + if (UE_id == -1) + LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, + __LINE__, __FUNCTION__); + else + UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated = + physicalConfigDedicated; + } + + +#if defined(Rel10) || defined(Rel14) + + if (sCellToAddMod_r10 != NULL) { + UE_id = find_UE_id(Mod_idP, rntiP); + if (UE_id == -1) + LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, + __LINE__, __FUNCTION__); + else + config_dedicated_scell(Mod_idP, rntiP, sCellToAddMod_r10); + + } +#endif + + + + + if (mbsfn_SubframeConfigList != NULL) { + LOG_I(MAC, + "[eNB %d][CONFIG] Received %d subframe allocation pattern for MBSFN\n", + Mod_idP, mbsfn_SubframeConfigList->list.count); + RC.mac[Mod_idP]->common_channels[0].num_sf_allocation_pattern = + mbsfn_SubframeConfigList->list.count; + + for (i = 0; i < mbsfn_SubframeConfigList->list.count; i++) { + RC.mac[Mod_idP]->common_channels[0].mbsfn_SubframeConfig[i] = + mbsfn_SubframeConfigList->list.array[i]; + LOG_I(MAC, + "[eNB %d][CONFIG] MBSFN_SubframeConfig[%d] pattern is %x\n", + Mod_idP, i, + RC.mac[Mod_idP]-> + common_channels[0].mbsfn_SubframeConfig[i]-> + subframeAllocation.choice.oneFrame.buf[0]); + } + +#ifdef Rel10 + RC.mac[Mod_idP]->common_channels[0].MBMS_flag = MBMS_Flag; +#endif + } +#if defined(Rel10) || defined(Rel14) + + if (mbsfn_AreaInfoList != NULL) { + // One eNB could be part of multiple mbsfn syc area, this could change over time so reset each time + LOG_I(MAC, "[eNB %d][CONFIG] Received %d MBSFN Area Info\n", + Mod_idP, mbsfn_AreaInfoList->list.count); + RC.mac[Mod_idP]->common_channels[0].num_active_mbsfn_area = + mbsfn_AreaInfoList->list.count; + + for (i = 0; i < mbsfn_AreaInfoList->list.count; i++) { + RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i] = + mbsfn_AreaInfoList->list.array[i]; + LOG_I(MAC, + "[eNB %d][CONFIG] MBSFN_AreaInfo[%d]: MCCH Repetition Period = %ld\n", + Mod_idP, i, + RC.mac[Mod_idP]->common_channels[0]. + mbsfn_AreaInfo[i]->mcch_Config_r9. + mcch_RepetitionPeriod_r9); + // config_sib13(Mod_idP,0,i,RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i]->mbsfn_AreaId_r9); + } + } + + if (pmch_InfoList != NULL) { + + // LOG_I(MAC,"DUY: lcid when entering rrc_mac config_req is %02d\n",(pmch_InfoList->list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9)); + + LOG_I(MAC, "[CONFIG] Number of PMCH in this MBSFN Area %d\n", + pmch_InfoList->list.count); + + for (i = 0; i < pmch_InfoList->list.count; i++) { + RC.mac[Mod_idP]->common_channels[0].pmch_Config[i] = + &pmch_InfoList->list.array[i]->pmch_Config_r9; + + LOG_I(MAC, + "[CONFIG] PMCH[%d]: This PMCH stop (sf_AllocEnd_r9) at subframe %ldth\n", + i, + RC.mac[Mod_idP]->common_channels[0]. + pmch_Config[i]->sf_AllocEnd_r9); + LOG_I(MAC, "[CONFIG] PMCH[%d]: mch_Scheduling_Period = %ld\n", + i, + RC.mac[Mod_idP]->common_channels[0]. + pmch_Config[i]->mch_SchedulingPeriod_r9); + LOG_I(MAC, "[CONFIG] PMCH[%d]: dataMCS = %ld\n", i, + RC.mac[Mod_idP]->common_channels[0]. + pmch_Config[i]->dataMCS_r9); + + // MBMS session info list in each MCH + RC.mac[Mod_idP]->common_channels[0].mbms_SessionList[i] = + &pmch_InfoList->list.array[i]->mbms_SessionInfoList_r9; + LOG_I(MAC, "PMCH[%d] Number of session (MTCH) is: %d\n", i, + RC.mac[Mod_idP]->common_channels[0]. + mbms_SessionList[i]->list.count); + } + } +#endif + + if (radioResourceConfigCommon != NULL) { + AssertFatal(RC.mac[Mod_idP]->if_inst->PHY_config_req != NULL, + "if_inst->phy_config_request is null\n"); + PHY_Config_t phycfg; + phycfg.Mod_id = Mod_idP; + phycfg.CC_id = CC_idP; + phycfg.cfg = &RC.mac[Mod_idP]->config[CC_idP]; + + if (RC.mac[Mod_idP]->if_inst->PHY_config_req) + RC.mac[Mod_idP]->if_inst->PHY_config_req(&phycfg); + } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); + + return (0); +} + +int +rrc_mac_config_req_ue(module_id_t Mod_idP, + int CC_idP, + uint8_t eNB_index, + RadioResourceConfigCommonSIB_t * + radioResourceConfigCommon, + struct PhysicalConfigDedicated + *physicalConfigDedicated, +#if defined(Rel10) || defined(Rel14) + SCellToAddMod_r10_t * sCellToAddMod_r10, + //struct PhysicalConfigDedicatedSCell_r10 *physicalConfigDedicatedSCell_r10, +#endif + MeasObjectToAddMod_t ** measObj, + MAC_MainConfig_t * mac_MainConfig, + long logicalChannelIdentity, + LogicalChannelConfig_t * logicalChannelConfig, + MeasGapConfig_t * measGapConfig, + TDD_Config_t * tdd_Config, + MobilityControlInfo_t * mobilityControlInfo, + uint8_t * SIwindowsize, + uint16_t * SIperiod, + ARFCN_ValueEUTRA_t * ul_CarrierFreq, + long *ul_Bandwidth, + AdditionalSpectrumEmission_t * + additionalSpectrumEmission, + struct MBSFN_SubframeConfigList + *mbsfn_SubframeConfigList +#if defined(Rel10) || defined(Rel14) + , uint8_t MBMS_Flag, + MBSFN_AreaInfoList_r9_t * mbsfn_AreaInfoList, + PMCH_InfoList_r9_t * pmch_InfoList +#endif +#ifdef CBA + , uint8_t num_active_cba_groups, uint16_t cba_rnti +#endif + ) +{ + + int i; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN); + + LOG_I(MAC, "[CONFIG][UE %d] Configuring MAC/PHY from eNB %d\n", + Mod_idP, eNB_index); + + if (tdd_Config != NULL) { + UE_mac_inst[Mod_idP].tdd_Config = tdd_Config; + } + + + if (tdd_Config && SIwindowsize && SIperiod) { + phy_config_sib1_ue(Mod_idP, 0, eNB_index, tdd_Config, + *SIwindowsize, *SIperiod); + } + + if (radioResourceConfigCommon != NULL) { + UE_mac_inst[Mod_idP].radioResourceConfigCommon = + radioResourceConfigCommon; + phy_config_sib2_ue(Mod_idP, 0, eNB_index, + radioResourceConfigCommon, ul_CarrierFreq, + ul_Bandwidth, additionalSpectrumEmission, + mbsfn_SubframeConfigList); + } + // SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup + if (logicalChannelConfig != NULL) { + LOG_I(MAC, + "[CONFIG][UE %d] Applying RRC logicalChannelConfig from eNB%d\n", + Mod_idP, eNB_index); + UE_mac_inst[Mod_idP].logicalChannelConfig[logicalChannelIdentity] = + logicalChannelConfig; + UE_mac_inst[Mod_idP].scheduling_info.Bj[logicalChannelIdentity] = 0; // initilize the bucket for this lcid + + AssertFatal(logicalChannelConfig->ul_SpecificParameters != NULL, + "[UE %d] LCID %ld NULL ul_SpecificParameters\n", + Mod_idP, logicalChannelIdentity); + UE_mac_inst[Mod_idP].scheduling_info.bucket_size[logicalChannelIdentity] = logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate * logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration; // set the max bucket size + if (logicalChannelConfig->ul_SpecificParameters-> + logicalChannelGroup != NULL) { + UE_mac_inst[Mod_idP].scheduling_info. + LCGID[logicalChannelIdentity] = + *logicalChannelConfig->ul_SpecificParameters-> + logicalChannelGroup; + LOG_D(MAC, + "[CONFIG][UE %d] LCID %ld is attached to the LCGID %ld\n", + Mod_idP, logicalChannelIdentity, + *logicalChannelConfig-> + ul_SpecificParameters->logicalChannelGroup); + } else { + UE_mac_inst[Mod_idP].scheduling_info. + LCGID[logicalChannelIdentity] = MAX_NUM_LCGID; + } + UE_mac_inst[Mod_idP]. + scheduling_info.LCID_buffer_remain[logicalChannelIdentity] = 0; + } + + if (mac_MainConfig != NULL) { + LOG_I(MAC, + "[CONFIG][UE%d] Applying RRC macMainConfig from eNB%d\n", + Mod_idP, eNB_index); + UE_mac_inst[Mod_idP].macConfig = mac_MainConfig; + UE_mac_inst[Mod_idP].measGapConfig = measGapConfig; + + if (mac_MainConfig->ul_SCH_Config) { + + if (mac_MainConfig->ul_SCH_Config->periodicBSR_Timer) { + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer = + (uint16_t) * + mac_MainConfig->ul_SCH_Config->periodicBSR_Timer; + } else { + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer = #ifndef Rel14 - (uint16_t) MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity + (uint16_t) + MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity #else - (uint16_t) PeriodicBSR_Timer_r12_infinity; + (uint16_t) PeriodicBSR_Timer_r12_infinity; #endif - ; - } - - if (mac_MainConfig->ul_SCH_Config->maxHARQ_Tx) { - UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx = (uint16_t) *mac_MainConfig->ul_SCH_Config->maxHARQ_Tx; - } else { - UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx = (uint16_t) MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; - } - phy_config_harq_ue(Mod_idP,0,eNB_index,UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx); - - if (mac_MainConfig->ul_SCH_Config->retxBSR_Timer) { - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = (uint16_t) mac_MainConfig->ul_SCH_Config->retxBSR_Timer; - } else { + ; + } + + if (mac_MainConfig->ul_SCH_Config->maxHARQ_Tx) { + UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx = + (uint16_t) * mac_MainConfig->ul_SCH_Config->maxHARQ_Tx; + } else { + UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx = + (uint16_t) + MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; + } + phy_config_harq_ue(Mod_idP, 0, eNB_index, + UE_mac_inst[Mod_idP]. + scheduling_info.maxHARQ_Tx); + + if (mac_MainConfig->ul_SCH_Config->retxBSR_Timer) { + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = + (uint16_t) mac_MainConfig->ul_SCH_Config-> + retxBSR_Timer; + } else { #ifndef Rel14 - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = (uint16_t)MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf2560; + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = + (uint16_t) + MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf2560; #else - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = (uint16_t)RetxBSR_Timer_r12_sf2560; + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = + (uint16_t) RetxBSR_Timer_r12_sf2560; #endif - } - } - - -#if defined(Rel10) || defined(Rel14) - - if (mac_MainConfig->ext1 && mac_MainConfig->ext1->sr_ProhibitTimer_r9) { - UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = (uint16_t) *mac_MainConfig->ext1->sr_ProhibitTimer_r9; - } else { - UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = 0; - } - - if (mac_MainConfig->ext2 && mac_MainConfig->ext2->mac_MainConfig_v1020) { - if (mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10) { - UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t) *mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10; - } else { - UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t)0; - } - if (mac_MainConfig->ext2->mac_MainConfig_v1020->extendedPHR_r10) { - UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t) *mac_MainConfig->ext2->mac_MainConfig_v1020->extendedPHR_r10; - } else { - UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t)0; - } - } else { - UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t)0; - UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t)0; - } -#endif - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; - - UE_mac_inst[Mod_idP].BSR_reporting_active = BSR_TRIGGER_NONE; - - LOG_D(MAC,"[UE %d]: periodic BSR %d (SF), retx BSR %d (SF)\n", - Mod_idP, - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF, - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF); - - UE_mac_inst[Mod_idP].scheduling_info.drx_config = mac_MainConfig->drx_Config; - UE_mac_inst[Mod_idP].scheduling_info.phr_config = mac_MainConfig->phr_Config; - - if (mac_MainConfig->phr_Config) { - UE_mac_inst[Mod_idP].PHR_state = mac_MainConfig->phr_Config->present; - UE_mac_inst[Mod_idP].PHR_reconfigured = 1; - UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer = mac_MainConfig->phr_Config->choice.setup.periodicPHR_Timer; - UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer = mac_MainConfig->phr_Config->choice.setup.prohibitPHR_Timer; - UE_mac_inst[Mod_idP].scheduling_info.PathlossChange = mac_MainConfig->phr_Config->choice.setup.dl_PathlossChange; - } else { - UE_mac_inst[Mod_idP].PHR_reconfigured = 0; - UE_mac_inst[Mod_idP].PHR_state = MAC_MainConfig__phr_Config_PR_setup; - UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer = MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20; - UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer = MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20; - UE_mac_inst[Mod_idP].scheduling_info.PathlossChange = MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1; - } - - UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer); - UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer); - UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db = get_db_dl_PathlossChange(UE_mac_inst[Mod_idP].scheduling_info.PathlossChange); - UE_mac_inst[Mod_idP].PHR_reporting_active = 0; - LOG_D(MAC,"[UE %d] config PHR (%d): periodic %d (SF) prohibit %d (SF) pathlosschange %d (db) \n", - Mod_idP, - (mac_MainConfig->phr_Config)?mac_MainConfig->phr_Config->present:-1, - UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF, - UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF, - UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db); - } - - - if (physicalConfigDedicated != NULL) { - phy_config_dedicated_ue(Mod_idP,0,eNB_index,physicalConfigDedicated); - UE_mac_inst[Mod_idP].physicalConfigDedicated=physicalConfigDedicated; // for SR proc - } - + } + } #if defined(Rel10) || defined(Rel14) - if (sCellToAddMod_r10 != NULL) { - - - phy_config_dedicated_scell_ue(Mod_idP,eNB_index,sCellToAddMod_r10,1); - UE_mac_inst[Mod_idP].physicalConfigDedicatedSCell_r10 = sCellToAddMod_r10->radioResourceConfigDedicatedSCell_r10->physicalConfigDedicatedSCell_r10; // using SCell index 0 - } - + if (mac_MainConfig->ext1 + && mac_MainConfig->ext1->sr_ProhibitTimer_r9) { + UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = + (uint16_t) * mac_MainConfig->ext1->sr_ProhibitTimer_r9; + } else { + UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = 0; + } + if (mac_MainConfig->ext2 + && mac_MainConfig->ext2->mac_MainConfig_v1020) { + if (mac_MainConfig->ext2-> + mac_MainConfig_v1020->extendedBSR_Sizes_r10) { + UE_mac_inst[Mod_idP].scheduling_info. + extendedBSR_Sizes_r10 = + (uint16_t) * + mac_MainConfig->ext2-> + mac_MainConfig_v1020->extendedBSR_Sizes_r10; + } else { + UE_mac_inst[Mod_idP].scheduling_info. + extendedBSR_Sizes_r10 = (uint16_t) 0; + } + if (mac_MainConfig->ext2->mac_MainConfig_v1020-> + extendedPHR_r10) { + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = + (uint16_t) * + mac_MainConfig->ext2->mac_MainConfig_v1020-> + extendedPHR_r10; + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = + (uint16_t) 0; + } + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = + (uint16_t) 0; + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = + (uint16_t) 0; + } #endif + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = + MAC_UE_BSR_TIMER_NOT_RUNNING; + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = + MAC_UE_BSR_TIMER_NOT_RUNNING; - if (measObj!= NULL) { - if (measObj[0]!= NULL) { - UE_mac_inst[Mod_idP].n_adj_cells = measObj[0]->measObject.choice.measObjectEUTRA.cellsToAddModList->list.count; - LOG_I(MAC,"Number of adjacent cells %d\n",UE_mac_inst[Mod_idP].n_adj_cells); - - for (i=0; imeasObject.choice.measObjectEUTRA.cellsToAddModList->list.array[i]->physCellId; - LOG_I(MAC,"Cell %d : Nid_cell %d\n",i,UE_mac_inst[Mod_idP].adj_cell_id[i]); - } - - phy_config_meas_ue(Mod_idP,0,eNB_index,UE_mac_inst[Mod_idP].n_adj_cells,UE_mac_inst[Mod_idP].adj_cell_id); + UE_mac_inst[Mod_idP].BSR_reporting_active = BSR_TRIGGER_NONE; + + LOG_D(MAC, "[UE %d]: periodic BSR %d (SF), retx BSR %d (SF)\n", + Mod_idP, + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF, + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF); + + UE_mac_inst[Mod_idP].scheduling_info.drx_config = + mac_MainConfig->drx_Config; + UE_mac_inst[Mod_idP].scheduling_info.phr_config = + mac_MainConfig->phr_Config; + + if (mac_MainConfig->phr_Config) { + UE_mac_inst[Mod_idP].PHR_state = + mac_MainConfig->phr_Config->present; + UE_mac_inst[Mod_idP].PHR_reconfigured = 1; + UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer = + mac_MainConfig->phr_Config->choice.setup.periodicPHR_Timer; + UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer = + mac_MainConfig->phr_Config->choice.setup.prohibitPHR_Timer; + UE_mac_inst[Mod_idP].scheduling_info.PathlossChange = + mac_MainConfig->phr_Config->choice.setup.dl_PathlossChange; + } else { + UE_mac_inst[Mod_idP].PHR_reconfigured = 0; + UE_mac_inst[Mod_idP].PHR_state = + MAC_MainConfig__phr_Config_PR_setup; + UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer = + MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20; + UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer = + MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20; + UE_mac_inst[Mod_idP].scheduling_info.PathlossChange = + MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1; + } + + UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF = + get_sf_perioidicPHR_Timer(UE_mac_inst[Mod_idP]. + scheduling_info.periodicPHR_Timer); + UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF = + get_sf_prohibitPHR_Timer(UE_mac_inst[Mod_idP]. + scheduling_info.prohibitPHR_Timer); + UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db = + get_db_dl_PathlossChange(UE_mac_inst[Mod_idP]. + scheduling_info.PathlossChange); + UE_mac_inst[Mod_idP].PHR_reporting_active = 0; + LOG_D(MAC, + "[UE %d] config PHR (%d): periodic %d (SF) prohibit %d (SF) pathlosschange %d (db) \n", + Mod_idP, + (mac_MainConfig->phr_Config) ? mac_MainConfig-> + phr_Config->present : -1, + UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF, + UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF, + UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db); } - } - if(mobilityControlInfo != NULL) { - - LOG_D(MAC,"[UE%d] MAC Reset procedure triggered by RRC eNB %d \n",Mod_idP,eNB_index); - ue_mac_reset(Mod_idP,eNB_index); - - if(mobilityControlInfo->radioResourceConfigCommon.rach_ConfigCommon) { - memcpy((void *)&UE_mac_inst[Mod_idP].radioResourceConfigCommon->rach_ConfigCommon, - (void *)mobilityControlInfo->radioResourceConfigCommon.rach_ConfigCommon, - sizeof(RACH_ConfigCommon_t)); + if (physicalConfigDedicated != NULL) { + phy_config_dedicated_ue(Mod_idP, 0, eNB_index, + physicalConfigDedicated); + UE_mac_inst[Mod_idP].physicalConfigDedicated = physicalConfigDedicated; // for SR proc } - - memcpy((void *)&UE_mac_inst[Mod_idP].radioResourceConfigCommon->prach_Config.prach_ConfigInfo, - (void *)mobilityControlInfo->radioResourceConfigCommon.prach_Config.prach_ConfigInfo, - sizeof(PRACH_ConfigInfo_t)); - UE_mac_inst[Mod_idP].radioResourceConfigCommon->prach_Config.rootSequenceIndex = mobilityControlInfo->radioResourceConfigCommon.prach_Config.rootSequenceIndex; - - if(mobilityControlInfo->radioResourceConfigCommon.pdsch_ConfigCommon) { - memcpy((void *)&UE_mac_inst[Mod_idP].radioResourceConfigCommon->pdsch_ConfigCommon, - (void *)mobilityControlInfo->radioResourceConfigCommon.pdsch_ConfigCommon, - sizeof(PDSCH_ConfigCommon_t)); - } - - // not a pointer: mobilityControlInfo->radioResourceConfigCommon.pusch_ConfigCommon - memcpy((void *)&UE_mac_inst[Mod_idP].radioResourceConfigCommon->pusch_ConfigCommon, - (void *)&mobilityControlInfo->radioResourceConfigCommon.pusch_ConfigCommon, - sizeof(PUSCH_ConfigCommon_t)); - - if(mobilityControlInfo->radioResourceConfigCommon.phich_Config) { - /* memcpy((void *)&UE_mac_inst[Mod_idP].radioResourceConfigCommon->phich_Config, - (void *)mobilityControlInfo->radioResourceConfigCommon.phich_Config, - sizeof(PHICH_Config_t)); */ - } - - if(mobilityControlInfo->radioResourceConfigCommon.pucch_ConfigCommon) { - memcpy((void *)&UE_mac_inst[Mod_idP].radioResourceConfigCommon->pucch_ConfigCommon, - (void *)mobilityControlInfo->radioResourceConfigCommon.pucch_ConfigCommon, - sizeof(PUCCH_ConfigCommon_t)); - } - - if(mobilityControlInfo->radioResourceConfigCommon.soundingRS_UL_ConfigCommon) { - memcpy((void *)&UE_mac_inst[Mod_idP].radioResourceConfigCommon->soundingRS_UL_ConfigCommon, - (void *)mobilityControlInfo->radioResourceConfigCommon.soundingRS_UL_ConfigCommon, - sizeof(SoundingRS_UL_ConfigCommon_t)); - } - - if(mobilityControlInfo->radioResourceConfigCommon.uplinkPowerControlCommon) { - memcpy((void *)&UE_mac_inst[Mod_idP].radioResourceConfigCommon->uplinkPowerControlCommon, - (void *)mobilityControlInfo->radioResourceConfigCommon.uplinkPowerControlCommon, - sizeof(UplinkPowerControlCommon_t)); - } - - //configure antennaInfoCommon somewhere here.. - if(mobilityControlInfo->radioResourceConfigCommon.p_Max) { - //to be configured - } - - if(mobilityControlInfo->radioResourceConfigCommon.tdd_Config) { - UE_mac_inst[Mod_idP].tdd_Config = mobilityControlInfo->radioResourceConfigCommon.tdd_Config; - } - - if(mobilityControlInfo->radioResourceConfigCommon.ul_CyclicPrefixLength) { - memcpy((void *)&UE_mac_inst[Mod_idP].radioResourceConfigCommon->ul_CyclicPrefixLength, - (void *)mobilityControlInfo->radioResourceConfigCommon.ul_CyclicPrefixLength, - sizeof(UL_CyclicPrefixLength_t)); - } - - // store the previous rnti in case of failure, and set thenew rnti - UE_mac_inst[Mod_idP].crnti_before_ho = UE_mac_inst[Mod_idP].crnti; - UE_mac_inst[Mod_idP].crnti = ((mobilityControlInfo->newUE_Identity.buf[0])|(mobilityControlInfo->newUE_Identity.buf[1]<<8)); - LOG_I(MAC,"[UE %d] Received new identity %x from %d\n", Mod_idP, UE_mac_inst[Mod_idP].crnti, eNB_index); - UE_mac_inst[Mod_idP].rach_ConfigDedicated = malloc(sizeof(*mobilityControlInfo->rach_ConfigDedicated)); - - if (mobilityControlInfo->rach_ConfigDedicated) { - memcpy((void*)UE_mac_inst[Mod_idP].rach_ConfigDedicated, - (void*)mobilityControlInfo->rach_ConfigDedicated, - sizeof(*mobilityControlInfo->rach_ConfigDedicated)); - } - - phy_config_afterHO_ue(Mod_idP,0,eNB_index,mobilityControlInfo,0); - } - - - if (mbsfn_SubframeConfigList != NULL) { - LOG_I(MAC,"[UE %d][CONFIG] Received %d subframe allocation pattern for MBSFN\n", Mod_idP, mbsfn_SubframeConfigList->list.count); - UE_mac_inst[Mod_idP].num_sf_allocation_pattern= mbsfn_SubframeConfigList->list.count; - - for (i=0; ilist.count; i++) { - LOG_I(MAC, "[UE %d] Configuring MBSFN_SubframeConfig %d from received SIB2 \n", Mod_idP, i); - UE_mac_inst[Mod_idP].mbsfn_SubframeConfig[i] = mbsfn_SubframeConfigList->list.array[i]; - // LOG_I("[UE %d] MBSFN_SubframeConfig[%d] pattern is %ld\n", Mod_idP, - // UE_mac_inst[Mod_idP].mbsfn_SubframeConfig[i]->subframeAllocation.choice.oneFrame.buf[0]); - } - } - - #if defined(Rel10) || defined(Rel14) - if (mbsfn_AreaInfoList != NULL) { - LOG_I(MAC,"[UE %d][CONFIG] Received %d MBSFN Area Info\n", Mod_idP, mbsfn_AreaInfoList->list.count); - UE_mac_inst[Mod_idP].num_active_mbsfn_area = mbsfn_AreaInfoList->list.count; - - for (i =0; i< mbsfn_AreaInfoList->list.count; i++) { - UE_mac_inst[Mod_idP].mbsfn_AreaInfo[i] = mbsfn_AreaInfoList->list.array[i]; - LOG_I(MAC,"[UE %d] MBSFN_AreaInfo[%d]: MCCH Repetition Period = %ld\n",Mod_idP, i, - UE_mac_inst[Mod_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_RepetitionPeriod_r9); - phy_config_sib13_ue(Mod_idP,0,eNB_index,i,UE_mac_inst[Mod_idP].mbsfn_AreaInfo[i]->mbsfn_AreaId_r9); + if (sCellToAddMod_r10 != NULL) { + + + phy_config_dedicated_scell_ue(Mod_idP, eNB_index, + sCellToAddMod_r10, 1); + UE_mac_inst[Mod_idP].physicalConfigDedicatedSCell_r10 = sCellToAddMod_r10->radioResourceConfigDedicatedSCell_r10->physicalConfigDedicatedSCell_r10; // using SCell index 0 } - } - - if (pmch_InfoList != NULL) { - - // LOG_I(MAC,"DUY: lcid when entering rrc_mac config_req is %02d\n",(pmch_InfoList->list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9)); +#endif - LOG_I(MAC, "[UE %d] Configuring PMCH_config from MCCH MESSAGE \n",Mod_idP); - - for (i =0; i< pmch_InfoList->list.count; i++) { - UE_mac_inst[Mod_idP].pmch_Config[i] = &pmch_InfoList->list.array[i]->pmch_Config_r9; - LOG_I(MAC, "[UE %d] PMCH[%d]: MCH_Scheduling_Period = %ld\n", Mod_idP, i, - UE_mac_inst[Mod_idP].pmch_Config[i]->mch_SchedulingPeriod_r9); + if (measObj != NULL) { + if (measObj[0] != NULL) { + UE_mac_inst[Mod_idP].n_adj_cells = + measObj[0]->measObject.choice. + measObjectEUTRA.cellsToAddModList->list.count; + LOG_I(MAC, "Number of adjacent cells %d\n", + UE_mac_inst[Mod_idP].n_adj_cells); + + for (i = 0; i < UE_mac_inst[Mod_idP].n_adj_cells; i++) { + UE_mac_inst[Mod_idP].adj_cell_id[i] = + measObj[0]->measObject.choice. + measObjectEUTRA.cellsToAddModList->list.array[i]-> + physCellId; + LOG_I(MAC, "Cell %d : Nid_cell %d\n", i, + UE_mac_inst[Mod_idP].adj_cell_id[i]); + } + + phy_config_meas_ue(Mod_idP, 0, eNB_index, + UE_mac_inst[Mod_idP].n_adj_cells, + UE_mac_inst[Mod_idP].adj_cell_id); + } } - - UE_mac_inst[Mod_idP].mcch_status = 1; - } + if (mobilityControlInfo != NULL) { + + LOG_D(MAC, "[UE%d] MAC Reset procedure triggered by RRC eNB %d \n", + Mod_idP, eNB_index); + ue_mac_reset(Mod_idP, eNB_index); + + if (mobilityControlInfo->radioResourceConfigCommon. + rach_ConfigCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + rach_ConfigCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.rach_ConfigCommon, + sizeof(RACH_ConfigCommon_t)); + } + + memcpy((void *) &UE_mac_inst[Mod_idP]. + radioResourceConfigCommon->prach_Config.prach_ConfigInfo, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.prach_Config.prach_ConfigInfo, + sizeof(PRACH_ConfigInfo_t)); + UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + prach_Config.rootSequenceIndex = + mobilityControlInfo->radioResourceConfigCommon. + prach_Config.rootSequenceIndex; + + if (mobilityControlInfo->radioResourceConfigCommon. + pdsch_ConfigCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + pdsch_ConfigCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.pdsch_ConfigCommon, + sizeof(PDSCH_ConfigCommon_t)); + } + // not a pointer: mobilityControlInfo->radioResourceConfigCommon.pusch_ConfigCommon + memcpy((void *) &UE_mac_inst[Mod_idP]. + radioResourceConfigCommon->pusch_ConfigCommon, + (void *) &mobilityControlInfo-> + radioResourceConfigCommon.pusch_ConfigCommon, + sizeof(PUSCH_ConfigCommon_t)); + + if (mobilityControlInfo->radioResourceConfigCommon.phich_Config) { + /* memcpy((void *)&UE_mac_inst[Mod_idP].radioResourceConfigCommon->phich_Config, + (void *)mobilityControlInfo->radioResourceConfigCommon.phich_Config, + sizeof(PHICH_Config_t)); */ + } + + if (mobilityControlInfo->radioResourceConfigCommon. + pucch_ConfigCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + pucch_ConfigCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.pucch_ConfigCommon, + sizeof(PUCCH_ConfigCommon_t)); + } + + if (mobilityControlInfo-> + radioResourceConfigCommon.soundingRS_UL_ConfigCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + soundingRS_UL_ConfigCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.soundingRS_UL_ConfigCommon, + sizeof(SoundingRS_UL_ConfigCommon_t)); + } + + if (mobilityControlInfo-> + radioResourceConfigCommon.uplinkPowerControlCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + uplinkPowerControlCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.uplinkPowerControlCommon, + sizeof(UplinkPowerControlCommon_t)); + } + //configure antennaInfoCommon somewhere here.. + if (mobilityControlInfo->radioResourceConfigCommon.p_Max) { + //to be configured + } + + if (mobilityControlInfo->radioResourceConfigCommon.tdd_Config) { + UE_mac_inst[Mod_idP].tdd_Config = + mobilityControlInfo->radioResourceConfigCommon.tdd_Config; + } + + if (mobilityControlInfo-> + radioResourceConfigCommon.ul_CyclicPrefixLength) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + ul_CyclicPrefixLength, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.ul_CyclicPrefixLength, + sizeof(UL_CyclicPrefixLength_t)); + } + // store the previous rnti in case of failure, and set thenew rnti + UE_mac_inst[Mod_idP].crnti_before_ho = UE_mac_inst[Mod_idP].crnti; + UE_mac_inst[Mod_idP].crnti = + ((mobilityControlInfo-> + newUE_Identity.buf[0]) | (mobilityControlInfo-> + newUE_Identity.buf[1] << 8)); + LOG_I(MAC, "[UE %d] Received new identity %x from %d\n", Mod_idP, + UE_mac_inst[Mod_idP].crnti, eNB_index); + UE_mac_inst[Mod_idP].rach_ConfigDedicated = + malloc(sizeof(*mobilityControlInfo->rach_ConfigDedicated)); + + if (mobilityControlInfo->rach_ConfigDedicated) { + memcpy((void *) UE_mac_inst[Mod_idP].rach_ConfigDedicated, + (void *) mobilityControlInfo->rach_ConfigDedicated, + sizeof(*mobilityControlInfo->rach_ConfigDedicated)); + } + + phy_config_afterHO_ue(Mod_idP, 0, eNB_index, mobilityControlInfo, + 0); + } + + + if (mbsfn_SubframeConfigList != NULL) { + LOG_I(MAC, + "[UE %d][CONFIG] Received %d subframe allocation pattern for MBSFN\n", + Mod_idP, mbsfn_SubframeConfigList->list.count); + UE_mac_inst[Mod_idP].num_sf_allocation_pattern = + mbsfn_SubframeConfigList->list.count; + + for (i = 0; i < mbsfn_SubframeConfigList->list.count; i++) { + LOG_I(MAC, + "[UE %d] Configuring MBSFN_SubframeConfig %d from received SIB2 \n", + Mod_idP, i); + UE_mac_inst[Mod_idP].mbsfn_SubframeConfig[i] = + mbsfn_SubframeConfigList->list.array[i]; + // LOG_I("[UE %d] MBSFN_SubframeConfig[%d] pattern is %ld\n", Mod_idP, + // UE_mac_inst[Mod_idP].mbsfn_SubframeConfig[i]->subframeAllocation.choice.oneFrame.buf[0]); + } + } +#if defined(Rel10) || defined(Rel14) + + if (mbsfn_AreaInfoList != NULL) { + LOG_I(MAC, "[UE %d][CONFIG] Received %d MBSFN Area Info\n", + Mod_idP, mbsfn_AreaInfoList->list.count); + UE_mac_inst[Mod_idP].num_active_mbsfn_area = + mbsfn_AreaInfoList->list.count; + + for (i = 0; i < mbsfn_AreaInfoList->list.count; i++) { + UE_mac_inst[Mod_idP].mbsfn_AreaInfo[i] = + mbsfn_AreaInfoList->list.array[i]; + LOG_I(MAC, + "[UE %d] MBSFN_AreaInfo[%d]: MCCH Repetition Period = %ld\n", + Mod_idP, i, + UE_mac_inst[Mod_idP].mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_RepetitionPeriod_r9); + phy_config_sib13_ue(Mod_idP, 0, eNB_index, i, + UE_mac_inst[Mod_idP]. + mbsfn_AreaInfo[i]->mbsfn_AreaId_r9); + } + } + + if (pmch_InfoList != NULL) { + + // LOG_I(MAC,"DUY: lcid when entering rrc_mac config_req is %02d\n",(pmch_InfoList->list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9)); + + LOG_I(MAC, "[UE %d] Configuring PMCH_config from MCCH MESSAGE \n", + Mod_idP); + + for (i = 0; i < pmch_InfoList->list.count; i++) { + UE_mac_inst[Mod_idP].pmch_Config[i] = + &pmch_InfoList->list.array[i]->pmch_Config_r9; + LOG_I(MAC, "[UE %d] PMCH[%d]: MCH_Scheduling_Period = %ld\n", + Mod_idP, i, + UE_mac_inst[Mod_idP]. + pmch_Config[i]->mch_SchedulingPeriod_r9); + } + + UE_mac_inst[Mod_idP].mcch_status = 1; + } #endif #ifdef CBA - if (cba_rnti) { - UE_mac_inst[Mod_idP].cba_rnti[num_active_cba_groups-1] = cba_rnti; - LOG_D(MAC,"[UE %d] configure CBA group %d RNTI %x for eNB %d (total active cba group %d)\n", - Mod_idP,Mod_idP%num_active_cba_groups, cba_rnti,eNB_index,num_active_cba_groups); - phy_config_cba_rnti(Mod_idP,CC_idP,eNB_flagP,eNB_index,cba_rnti,num_active_cba_groups-1, num_active_cba_groups); - } + if (cba_rnti) { + UE_mac_inst[Mod_idP].cba_rnti[num_active_cba_groups - 1] = + cba_rnti; + LOG_D(MAC, + "[UE %d] configure CBA group %d RNTI %x for eNB %d (total active cba group %d)\n", + Mod_idP, Mod_idP % num_active_cba_groups, cba_rnti, + eNB_index, num_active_cba_groups); + phy_config_cba_rnti(Mod_idP, CC_idP, eNB_flagP, eNB_index, + cba_rnti, num_active_cba_groups - 1, + num_active_cba_groups); + } #endif - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); - return(0); + return (0); } - diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index ba02a35694..65e090e370 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -90,12 +90,12 @@ #if defined(Rel10) || defined(Rel14) // Mask for identifying subframe for MBMS -#define MBSFN_TDD_SF3 0x80// for TDD +#define MBSFN_TDD_SF3 0x80 // for TDD #define MBSFN_TDD_SF4 0x40 #define MBSFN_TDD_SF7 0x20 #define MBSFN_TDD_SF8 0x10 #define MBSFN_TDD_SF9 0x08 -#define MBSFN_FDD_SF1 0x80// for FDD +#define MBSFN_FDD_SF1 0x80 // for FDD #define MBSFN_FDD_SF2 0x40 #define MBSFN_FDD_SF3 0x20 #define MBSFN_FDD_SF6 0x10 @@ -111,7 +111,7 @@ #ifdef USER_MODE #define printk printf -#endif //USER_MODE +#endif //USER_MODE /*!\brief Maximum number of logical channl group IDs */ #define MAX_NUM_LCGID 4 @@ -132,17 +132,17 @@ /*!\brief size of buffer status report table */ #define BSR_TABLE_SIZE 64 /*!\brief The power headroom reporting range is from -23 ...+40 dB and beyond, with step 1 */ -#define PHR_MAPPING_OFFSET 23 // if ( x>= -23 ) val = floor (x + 23) +#define PHR_MAPPING_OFFSET 23 // if ( x>= -23 ) val = floor (x + 23) /*!\brief maximum number of resource block groups */ -#define N_RBG_MAX 25 // for 20MHz channel BW +#define N_RBG_MAX 25 // for 20MHz channel BW /*!\brief minimum value for channel quality indicator */ #define MIN_CQI_VALUE 0 /*!\brief maximum value for channel quality indicator */ #define MAX_CQI_VALUE 15 /*!\briefmaximum number of supported bandwidth (1.4, 5, 10, 20 MHz) */ -#define MAX_SUPPORTED_BW 4 +#define MAX_SUPPORTED_BW 4 /*!\brief CQI values range from 1 to 15 (4 bits) */ -#define CQI_VALUE_RANGE 16 +#define CQI_VALUE_RANGE 16 /*!\brief value for indicating BSR Timer is not running */ #define MAC_UE_BSR_TIMER_NOT_RUNNING (0xFFFF) @@ -157,30 +157,30 @@ #define MIN_MAC_HDR_RLC_SIZE (1 + MIN_RLC_PDU_SIZE) /*!\brief maximum number of slices / groups */ -#define MAX_NUM_SLICES 4 +#define MAX_NUM_SLICES 4 /* * eNB part - */ + */ /* * UE/ENB common part - */ + */ /*!\brief MAC header of Random Access Response for Random access preamble identifier (RAPID) */ typedef struct { - uint8_t RAPID:6; - uint8_t T:1; - uint8_t E:1; -} __attribute__((__packed__))RA_HEADER_RAPID; + uint8_t RAPID:6; + uint8_t T:1; + uint8_t E:1; +} __attribute__ ((__packed__)) RA_HEADER_RAPID; /*!\brief MAC header of Random Access Response for backoff indicator (BI)*/ typedef struct { - uint8_t BI:4; - uint8_t R:2; - uint8_t T:1; - uint8_t E:1; -} __attribute__((__packed__))RA_HEADER_BI; + uint8_t BI:4; + uint8_t R:2; + uint8_t T:1; + uint8_t E:1; +} __attribute__ ((__packed__)) RA_HEADER_BI; /* typedef struct { uint64_t padding:16; @@ -212,124 +212,124 @@ typedef struct { */ /*!\brief MAC subheader short with 7bit Length field */ typedef struct { - uint8_t LCID:5; // octet 1 LSB - uint8_t E:1; - uint8_t R:2; // octet 1 MSB - uint8_t L:7; // octet 2 LSB - uint8_t F:1; // octet 2 MSB -} __attribute__((__packed__))SCH_SUBHEADER_SHORT; + uint8_t LCID:5; // octet 1 LSB + uint8_t E:1; + uint8_t R:2; // octet 1 MSB + uint8_t L:7; // octet 2 LSB + uint8_t F:1; // octet 2 MSB +} __attribute__ ((__packed__)) SCH_SUBHEADER_SHORT; /*!\brief MAC subheader long with 15bit Length field */ typedef struct { - uint8_t LCID:5; // octet 1 LSB - uint8_t E:1; - uint8_t R:2; // octet 1 MSB - uint8_t L_MSB:7; - uint8_t F:1; // octet 2 MSB - uint8_t L_LSB:8; - uint8_t padding; -} __attribute__((__packed__))SCH_SUBHEADER_LONG; + uint8_t LCID:5; // octet 1 LSB + uint8_t E:1; + uint8_t R:2; // octet 1 MSB + uint8_t L_MSB:7; + uint8_t F:1; // octet 2 MSB + uint8_t L_LSB:8; + uint8_t padding; +} __attribute__ ((__packed__)) SCH_SUBHEADER_LONG; /*!\brief MAC subheader short without length field */ typedef struct { - uint8_t LCID:5; - uint8_t E:1; - uint8_t R:2; -} __attribute__((__packed__))SCH_SUBHEADER_FIXED; + uint8_t LCID:5; + uint8_t E:1; + uint8_t R:2; +} __attribute__ ((__packed__)) SCH_SUBHEADER_FIXED; /*!\brief mac control element: short buffer status report for a specific logical channel group ID*/ typedef struct { - uint8_t Buffer_size:6; // octet 1 LSB - uint8_t LCGID:2; // octet 1 MSB -} __attribute__((__packed__))BSR_SHORT; + uint8_t Buffer_size:6; // octet 1 LSB + uint8_t LCGID:2; // octet 1 MSB +} __attribute__ ((__packed__)) BSR_SHORT; typedef BSR_SHORT BSR_TRUNCATED; /*!\brief mac control element: long buffer status report for all logical channel group ID*/ typedef struct { - uint8_t Buffer_size3:6; - uint8_t Buffer_size2:6; - uint8_t Buffer_size1:6; - uint8_t Buffer_size0:6; -} __attribute__((__packed__))BSR_LONG; + uint8_t Buffer_size3:6; + uint8_t Buffer_size2:6; + uint8_t Buffer_size1:6; + uint8_t Buffer_size0:6; +} __attribute__ ((__packed__)) BSR_LONG; #define BSR_LONG_SIZE (sizeof(BSR_LONG)) /*!\brief mac control element: timing advance */ typedef struct { - uint8_t TA:6; - uint8_t R:2; -} __attribute__((__packed__))TIMING_ADVANCE_CMD; + uint8_t TA:6; + uint8_t R:2; +} __attribute__ ((__packed__)) TIMING_ADVANCE_CMD; /*!\brief mac control element: power headroom report */ typedef struct { - uint8_t PH:6; - uint8_t R:2; -} __attribute__((__packed__))POWER_HEADROOM_CMD; + uint8_t PH:6; + uint8_t R:2; +} __attribute__ ((__packed__)) POWER_HEADROOM_CMD; /*! \brief MIB payload */ typedef struct { - uint8_t payload[3] ; -} __attribute__((__packed__))MIB_PDU; + uint8_t payload[3]; +} __attribute__ ((__packed__)) MIB_PDU; /*! \brief CCCH payload */ typedef struct { - uint8_t payload[CCCH_PAYLOAD_SIZE_MAX] ; -} __attribute__((__packed__))CCCH_PDU; + uint8_t payload[CCCH_PAYLOAD_SIZE_MAX]; +} __attribute__ ((__packed__)) CCCH_PDU; /*! \brief BCCH payload */ typedef struct { - uint8_t payload[BCCH_PAYLOAD_SIZE_MAX] ; -} __attribute__((__packed__))BCCH_PDU; + uint8_t payload[BCCH_PAYLOAD_SIZE_MAX]; +} __attribute__ ((__packed__)) BCCH_PDU; /*! \brief RAR payload */ typedef struct { - uint8_t payload[RAR_PAYLOAD_SIZE_MAX]; + uint8_t payload[RAR_PAYLOAD_SIZE_MAX]; } __attribute__ ((__packed__)) RAR_PDU; /*! \brief BCCH payload */ typedef struct { - uint8_t payload[PCCH_PAYLOAD_SIZE_MAX] ; -} __attribute__((__packed__))PCCH_PDU; + uint8_t payload[PCCH_PAYLOAD_SIZE_MAX]; +} __attribute__ ((__packed__)) PCCH_PDU; #if defined(Rel10) || defined(Rel14) /*! \brief MCCH payload */ typedef struct { - uint8_t payload[MCCH_PAYLOAD_SIZE_MAX] ; -} __attribute__((__packed__))MCCH_PDU; + uint8_t payload[MCCH_PAYLOAD_SIZE_MAX]; +} __attribute__ ((__packed__)) MCCH_PDU; /*!< \brief MAC control element for activation and deactivation of component carriers */ typedef struct { - uint8_t C7:1;/*!< \brief Component carrier 7 */ - uint8_t C6:1;/*!< \brief Component carrier 6 */ - uint8_t C5:1;/*!< \brief Component carrier 5 */ - uint8_t C4:1;/*!< \brief Component carrier 4 */ - uint8_t C3:1;/*!< \brief Component carrier 3 */ - uint8_t C2:1;/*!< \brief Component carrier 2 */ - uint8_t C1:1;/*!< \brief Component carrier 1 */ - uint8_t R:1;/*!< \brief Reserved */ -} __attribute__((__packed__))CC_ELEMENT; + uint8_t C7:1; /*!< \brief Component carrier 7 */ + uint8_t C6:1; /*!< \brief Component carrier 6 */ + uint8_t C5:1; /*!< \brief Component carrier 5 */ + uint8_t C4:1; /*!< \brief Component carrier 4 */ + uint8_t C3:1; /*!< \brief Component carrier 3 */ + uint8_t C2:1; /*!< \brief Component carrier 2 */ + uint8_t C1:1; /*!< \brief Component carrier 1 */ + uint8_t R:1; /*!< \brief Reserved */ +} __attribute__ ((__packed__)) CC_ELEMENT; /*! \brief MAC control element: MCH Scheduling Information */ typedef struct { - uint8_t stop_sf_MSB:3; // octet 1 LSB - uint8_t lcid:5; // octet 2 MSB - uint8_t stop_sf_LSB:8; -} __attribute__((__packed__))MSI_ELEMENT; + uint8_t stop_sf_MSB:3; // octet 1 LSB + uint8_t lcid:5; // octet 2 MSB + uint8_t stop_sf_LSB:8; +} __attribute__ ((__packed__)) MSI_ELEMENT; #endif -/*! \brief Values of CCCH LCID for DLSCH */ +/*! \brief Values of CCCH LCID for DLSCH */ #define CCCH_LCHANID 0 /*!\brief Values of BCCH logical channel (fake)*/ -#define BCCH 3 // SI +#define BCCH 3 // SI /*!\brief Values of PCCH logical channel (fake)*/ -#define PCCH 4 // Paging +#define PCCH 4 // Paging /*!\brief Values of PCCH logical channel (fake) */ -#define MIBCH 5 // MIB +#define MIBCH 5 // MIB /*!\brief Values of BCCH SIB1_BR logical channel (fake) */ -#define BCCH_SIB1_BR 6 // SIB1_BR +#define BCCH_SIB1_BR 6 // SIB1_BR /*!\brief Values of BCCH SIB_BR logical channel (fake) */ -#define BCCH_SI_BR 7 // SI-BR +#define BCCH_SI_BR 7 // SI-BR /*!\brief Value of CCCH / SRB0 logical channel */ -#define CCCH 0 // srb0 +#define CCCH 0 // srb0 /*!\brief DCCH / SRB1 logical channel */ -#define DCCH 1 // srb1 +#define DCCH 1 // srb1 /*!\brief DCCH1 / SRB2 logical channel */ -#define DCCH1 2 // srb2 +#define DCCH1 2 // srb2 /*!\brief DTCH DRB1 logical channel */ -#define DTCH 3 // LCID +#define DTCH 3 // LCID /*!\brief MCCH logical channel */ -#define MCCH 4 +#define MCCH 4 /*!\brief MTCH logical channel */ -#define MTCH 1 +#define MTCH 1 // DLSCH LCHAN ID /*!\brief LCID of UE contention resolution identity for DLSCH*/ #define UE_CONT_RES 28 @@ -364,972 +364,963 @@ typedef struct { /*!\brief LCID of long BSR for ULSCH */ #define LONG_BSR 30 /*!\bitmaps for BSR Triggers */ -#define BSR_TRIGGER_NONE (0) /* No BSR Trigger */ -#define BSR_TRIGGER_REGULAR (1) /* For Regular and ReTxBSR Expiry Triggers */ -#define BSR_TRIGGER_PERIODIC (2) /* For BSR Periodic Timer Expiry Trigger */ -#define BSR_TRIGGER_PADDING (4) /* For Padding BSR Trigger */ +#define BSR_TRIGGER_NONE (0) /* No BSR Trigger */ +#define BSR_TRIGGER_REGULAR (1) /* For Regular and ReTxBSR Expiry Triggers */ +#define BSR_TRIGGER_PERIODIC (2) /* For BSR Periodic Timer Expiry Trigger */ +#define BSR_TRIGGER_PADDING (4) /* For Padding BSR Trigger */ /*! \brief Downlink SCH PDU Structure */ typedef struct { - uint8_t payload[8][SCH_PAYLOAD_SIZE_MAX]; - uint16_t Pdu_size[8]; + uint8_t payload[8][SCH_PAYLOAD_SIZE_MAX]; + uint16_t Pdu_size[8]; } __attribute__ ((__packed__)) DLSCH_PDU; /*! \brief MCH PDU Structure */ typedef struct { - int8_t payload[SCH_PAYLOAD_SIZE_MAX]; - uint16_t Pdu_size; - uint8_t mcs; - uint8_t sync_area; - uint8_t msi_active; - uint8_t mcch_active; - uint8_t mtch_active; + int8_t payload[SCH_PAYLOAD_SIZE_MAX]; + uint16_t Pdu_size; + uint8_t mcs; + uint8_t sync_area; + uint8_t msi_active; + uint8_t mcch_active; + uint8_t mtch_active; } __attribute__ ((__packed__)) MCH_PDU; /*! \brief Uplink SCH PDU Structure */ typedef struct { - int8_t payload[SCH_PAYLOAD_SIZE_MAX]; /*!< \brief SACH payload */ - uint16_t Pdu_size; + int8_t payload[SCH_PAYLOAD_SIZE_MAX]; /*!< \brief SACH payload */ + uint16_t Pdu_size; } __attribute__ ((__packed__)) ULSCH_PDU; #include "PHY/impl_defs_top.h" +/*!\brief RA process state*/ +typedef enum { + IDLE = 0, + MSG2, + WAITMSG3, + MSG4, + WAITMSG4ACK +} RA_state; + /*!\brief UE ULSCH scheduling states*/ typedef enum { - S_UL_NONE =0, - S_UL_WAITING, - S_UL_SCHEDULED, - S_UL_BUFFERED, - S_UL_NUM_STATUS + S_UL_NONE = 0, + S_UL_WAITING, + S_UL_SCHEDULED, + S_UL_BUFFERED, + S_UL_NUM_STATUS } UE_ULSCH_STATUS; /*!\brief UE DLSCH scheduling states*/ typedef enum { - S_DL_NONE =0, - S_DL_WAITING, - S_DL_SCHEDULED, - S_DL_BUFFERED, - S_DL_NUM_STATUS + S_DL_NONE = 0, + S_DL_WAITING, + S_DL_SCHEDULED, + S_DL_BUFFERED, + S_DL_NUM_STATUS } UE_DLSCH_STATUS; /*!\brief scheduling policy for the contention-based access */ typedef enum { - CBA_ES=0, /// equal share of RB among groups w - CBA_ES_S, /// equal share of RB among groups with small allocation - CBA_PF, /// proportional fair (kind of) - CBA_PF_S, /// proportional fair (kind of) with small RB allocation - CBA_RS /// random allocation + CBA_ES = 0, /// equal share of RB among groups w + CBA_ES_S, /// equal share of RB among groups with small allocation + CBA_PF, /// proportional fair (kind of) + CBA_PF_S, /// proportional fair (kind of) with small RB allocation + CBA_RS /// random allocation } CBA_POLICY; /*! \brief temporary struct for ULSCH sched */ typedef struct { - rnti_t rnti; - uint16_t subframe; - uint16_t serving_num; - UE_ULSCH_STATUS status; + rnti_t rnti; + uint16_t subframe; + uint16_t serving_num; + UE_ULSCH_STATUS status; } eNB_ULSCH_INFO; /*! \brief temp struct for DLSCH sched */ typedef struct { - rnti_t rnti; - uint16_t weight; - uint16_t subframe; - uint16_t serving_num; - UE_DLSCH_STATUS status; + rnti_t rnti; + uint16_t weight; + uint16_t subframe; + uint16_t serving_num; + UE_DLSCH_STATUS status; } eNB_DLSCH_INFO; /*! \brief eNB overall statistics */ typedef struct { - /// num BCCH PDU per CC - uint32_t total_num_bcch_pdu; - /// BCCH buffer size - uint32_t bcch_buffer; - /// total BCCH buffer size - uint32_t total_bcch_buffer; - /// BCCH MCS - uint32_t bcch_mcs; + /// num BCCH PDU per CC + uint32_t total_num_bcch_pdu; + /// BCCH buffer size + uint32_t bcch_buffer; + /// total BCCH buffer size + uint32_t total_bcch_buffer; + /// BCCH MCS + uint32_t bcch_mcs; - /// num CCCH PDU per CC - uint32_t total_num_ccch_pdu; - /// BCCH buffer size - uint32_t ccch_buffer; - /// total BCCH buffer size - uint32_t total_ccch_buffer; - /// BCCH MCS - uint32_t ccch_mcs; + /// num CCCH PDU per CC + uint32_t total_num_ccch_pdu; + /// BCCH buffer size + uint32_t ccch_buffer; + /// total BCCH buffer size + uint32_t total_ccch_buffer; + /// BCCH MCS + uint32_t ccch_mcs; /// num active users - uint16_t num_dlactive_UEs; - /// available number of PRBs for a give SF - uint16_t available_prbs; - /// total number of PRB available for the user plane - uint32_t total_available_prbs; - /// aggregation - /// total avilable nccc : num control channel element - uint16_t available_ncces; - // only for a new transmission, should be extended for retransmission - // current dlsch bit rate for all transport channels - uint32_t dlsch_bitrate; - // - uint32_t dlsch_bytes_tx; - // - uint32_t dlsch_pdus_tx; - // - uint32_t total_dlsch_bitrate; - // - uint32_t total_dlsch_bytes_tx; - // - uint32_t total_dlsch_pdus_tx; - - // here for RX - // - uint32_t ulsch_bitrate; - // - uint32_t ulsch_bytes_rx; - // - uint64_t ulsch_pdus_rx; + uint16_t num_dlactive_UEs; + /// available number of PRBs for a give SF + uint16_t available_prbs; + /// total number of PRB available for the user plane + uint32_t total_available_prbs; + /// aggregation + /// total avilable nccc : num control channel element + uint16_t available_ncces; + // only for a new transmission, should be extended for retransmission + // current dlsch bit rate for all transport channels + uint32_t dlsch_bitrate; + // + uint32_t dlsch_bytes_tx; + // + uint32_t dlsch_pdus_tx; + // + uint32_t total_dlsch_bitrate; + // + uint32_t total_dlsch_bytes_tx; + // + uint32_t total_dlsch_pdus_tx; - uint32_t total_ulsch_bitrate; - // - uint32_t total_ulsch_bytes_rx; - // - uint32_t total_ulsch_pdus_rx; - - - /// MAC agent-related stats - /// total number of scheduling decisions - int sched_decisions; - /// missed deadlines - int missed_deadlines; + // here for RX + // + uint32_t ulsch_bitrate; + // + uint32_t ulsch_bytes_rx; + // + uint64_t ulsch_pdus_rx; + + uint32_t total_ulsch_bitrate; + // + uint32_t total_ulsch_bytes_rx; + // + uint32_t total_ulsch_pdus_rx; + + + /// MAC agent-related stats + /// total number of scheduling decisions + int sched_decisions; + /// missed deadlines + int missed_deadlines; } eNB_STATS; /*! \brief eNB statistics for the connected UEs*/ typedef struct { - /// CRNTI of UE - rnti_t crnti; ///user id (rnti) of connected UEs - // rrc status - uint8_t rrc_status; - /// harq pid - uint8_t harq_pid; - /// harq rounf - uint8_t harq_round; - /// total available number of PRBs for a new transmission - uint16_t rbs_used; - /// total available number of PRBs for a retransmission - uint16_t rbs_used_retx; - /// total nccc used for a new transmission: num control channel element - uint16_t ncce_used; - /// total avilable nccc for a retransmission: num control channel element - uint16_t ncce_used_retx; + /// CRNTI of UE + rnti_t crnti; ///user id (rnti) of connected UEs + // rrc status + uint8_t rrc_status; + /// harq pid + uint8_t harq_pid; + /// harq rounf + uint8_t harq_round; + /// total available number of PRBs for a new transmission + uint16_t rbs_used; + /// total available number of PRBs for a retransmission + uint16_t rbs_used_retx; + /// total nccc used for a new transmission: num control channel element + uint16_t ncce_used; + /// total avilable nccc for a retransmission: num control channel element + uint16_t ncce_used_retx; - // mcs1 before the rate adaptaion - uint8_t dlsch_mcs1; - /// Target mcs2 after rate-adaptation - uint8_t dlsch_mcs2; - // current TBS with mcs2 - uint32_t TBS; - // total TBS with mcs2 - // uint32_t total_TBS; - // total rb used for a new transmission - uint32_t total_rbs_used; - // total rb used for retransmission - uint32_t total_rbs_used_retx; + // mcs1 before the rate adaptaion + uint8_t dlsch_mcs1; + /// Target mcs2 after rate-adaptation + uint8_t dlsch_mcs2; + // current TBS with mcs2 + uint32_t TBS; + // total TBS with mcs2 + // uint32_t total_TBS; + // total rb used for a new transmission + uint32_t total_rbs_used; + // total rb used for retransmission + uint32_t total_rbs_used_retx; - /// TX - /// Num pkt - uint32_t num_pdu_tx[NB_RB_MAX]; - /// num bytes - uint32_t num_bytes_tx[NB_RB_MAX]; - /// num retransmission / harq - uint32_t num_retransmission; - /// instantaneous tx throughput for each TTI - // uint32_t tti_throughput[NB_RB_MAX]; + /// TX + /// Num pkt + uint32_t num_pdu_tx[NB_RB_MAX]; + /// num bytes + uint32_t num_bytes_tx[NB_RB_MAX]; + /// num retransmission / harq + uint32_t num_retransmission; + /// instantaneous tx throughput for each TTI + // uint32_t tti_throughput[NB_RB_MAX]; - /// overall - // - uint32_t dlsch_bitrate; - //total - uint32_t total_dlsch_bitrate; - /// headers+ CE + padding bytes for a MAC PDU - uint64_t overhead_bytes; - /// headers+ CE + padding bytes for a MAC PDU - uint64_t total_overhead_bytes; - /// headers+ CE + padding bytes for a MAC PDU - uint64_t avg_overhead_bytes; - // MAC multiplexed payload - uint64_t total_sdu_bytes; - // total MAC pdu bytes - uint64_t total_pdu_bytes; + /// overall + // + uint32_t dlsch_bitrate; + //total + uint32_t total_dlsch_bitrate; + /// headers+ CE + padding bytes for a MAC PDU + uint64_t overhead_bytes; + /// headers+ CE + padding bytes for a MAC PDU + uint64_t total_overhead_bytes; + /// headers+ CE + padding bytes for a MAC PDU + uint64_t avg_overhead_bytes; + // MAC multiplexed payload + uint64_t total_sdu_bytes; + // total MAC pdu bytes + uint64_t total_pdu_bytes; - // total num pdu - uint32_t total_num_pdus; - // - // uint32_t avg_pdu_size; + // total num pdu + uint32_t total_num_pdus; + // + // uint32_t avg_pdu_size; - /// RX + /// RX - /// PUCCH1a/b power (dBm) - int32_t Po_PUCCH_dBm; - /// Indicator that Po_PUCCH has been updated by PHY - int32_t Po_PUCCH_update; - /// Uplink measured RSSI - int32_t UL_rssi; - /// preassigned mcs after rate adaptation - uint8_t ulsch_mcs1; - /// adjusted mcs - uint8_t ulsch_mcs2; + /// PUCCH1a/b power (dBm) + int32_t Po_PUCCH_dBm; + /// Indicator that Po_PUCCH has been updated by PHY + int32_t Po_PUCCH_update; + /// Uplink measured RSSI + int32_t UL_rssi; + /// preassigned mcs after rate adaptation + uint8_t ulsch_mcs1; + /// adjusted mcs + uint8_t ulsch_mcs2; - /// estimated average pdu inter-departure time - uint32_t avg_pdu_idt; - /// estimated average pdu size - uint32_t avg_pdu_ps; - /// - uint32_t aggregated_pdu_size; - uint32_t aggregated_pdu_arrival; + /// estimated average pdu inter-departure time + uint32_t avg_pdu_idt; + /// estimated average pdu size + uint32_t avg_pdu_ps; + /// + uint32_t aggregated_pdu_size; + uint32_t aggregated_pdu_arrival; - /// uplink transport block size - uint32_t ulsch_TBS; + /// uplink transport block size + uint32_t ulsch_TBS; - /// total rb used for a new uplink transmission - uint32_t num_retransmission_rx; - /// total rb used for a new uplink transmission - uint32_t rbs_used_rx; - /// total rb used for a new uplink retransmission - uint32_t rbs_used_retx_rx; - /// total rb used for a new uplink transmission - uint32_t total_rbs_used_rx; - /// normalized rx power - int32_t normalized_rx_power; - /// target rx power - int32_t target_rx_power; + /// total rb used for a new uplink transmission + uint32_t num_retransmission_rx; + /// total rb used for a new uplink transmission + uint32_t rbs_used_rx; + /// total rb used for a new uplink retransmission + uint32_t rbs_used_retx_rx; + /// total rb used for a new uplink transmission + uint32_t total_rbs_used_rx; + /// normalized rx power + int32_t normalized_rx_power; + /// target rx power + int32_t target_rx_power; - /// num rx pdu - uint32_t num_pdu_rx[NB_RB_MAX]; - /// num bytes rx - uint32_t num_bytes_rx[NB_RB_MAX]; - /// instantaneous rx throughput for each TTI - // uint32_t tti_goodput[NB_RB_MAX]; - /// errors - uint32_t num_errors_rx; - - uint64_t overhead_bytes_rx; - /// headers+ CE + padding bytes for a MAC PDU - uint64_t total_overhead_bytes_rx; - /// headers+ CE + padding bytes for a MAC PDU - uint64_t avg_overhead_bytes_rx; - // - uint32_t ulsch_bitrate; - //total - uint32_t total_ulsch_bitrate; - /// overall - /// MAC pdu bytes - uint64_t pdu_bytes_rx; - /// total MAC pdu bytes - uint64_t total_pdu_bytes_rx; - /// total num pdu - uint32_t total_num_pdus_rx; - /// num of error pdus - uint32_t total_num_errors_rx; + /// num rx pdu + uint32_t num_pdu_rx[NB_RB_MAX]; + /// num bytes rx + uint32_t num_bytes_rx[NB_RB_MAX]; + /// instantaneous rx throughput for each TTI + // uint32_t tti_goodput[NB_RB_MAX]; + /// errors + uint32_t num_errors_rx; + + uint64_t overhead_bytes_rx; + /// headers+ CE + padding bytes for a MAC PDU + uint64_t total_overhead_bytes_rx; + /// headers+ CE + padding bytes for a MAC PDU + uint64_t avg_overhead_bytes_rx; + // + uint32_t ulsch_bitrate; + //total + uint32_t total_ulsch_bitrate; + /// overall + /// MAC pdu bytes + uint64_t pdu_bytes_rx; + /// total MAC pdu bytes + uint64_t total_pdu_bytes_rx; + /// total num pdu + uint32_t total_num_pdus_rx; + /// num of error pdus + uint32_t total_num_errors_rx; } eNB_UE_STATS; /*! \brief eNB template for UE context information */ typedef struct { - /// C-RNTI of UE - rnti_t rnti; - /// NDI from last scheduling - uint8_t oldNDI[8]; - /// mcs1 from last scheduling - uint8_t oldmcs1[8]; - /// mcs2 from last scheduling - uint8_t oldmcs2[8]; - /// NDI from last UL scheduling - uint8_t oldNDI_UL[8]; - /// mcs from last UL scheduling - uint8_t mcs_UL[8]; - /// TBS from last UL scheduling - uint8_t TBS_UL[8]; - /// Flag to indicate UL has been scheduled at least once - boolean_t ul_active; - /// Flag to indicate UE has been configured (ACK from RRCConnectionSetup received) - boolean_t configured; + /// C-RNTI of UE + rnti_t rnti; + /// NDI from last scheduling + uint8_t oldNDI[8]; + /// mcs1 from last scheduling + uint8_t oldmcs1[8]; + /// mcs2 from last scheduling + uint8_t oldmcs2[8]; + /// NDI from last UL scheduling + uint8_t oldNDI_UL[8]; + /// mcs from last UL scheduling + uint8_t mcs_UL[8]; + /// TBS from last UL scheduling + uint8_t TBS_UL[8]; + /// Flag to indicate UL has been scheduled at least once + boolean_t ul_active; + /// Flag to indicate UE has been configured (ACK from RRCConnectionSetup received) + boolean_t configured; - /// MCS from last scheduling - uint8_t mcs[8]; + /// MCS from last scheduling + uint8_t mcs[8]; - /// TPC from last scheduling - uint8_t oldTPC[8]; + /// TPC from last scheduling + uint8_t oldTPC[8]; - // PHY interface info + // PHY interface info - /// Number of Allocated RBs for DL after scheduling (prior to frequency allocation) - uint16_t nb_rb[8]; // num_max_harq + /// Number of Allocated RBs for DL after scheduling (prior to frequency allocation) + uint16_t nb_rb[8]; // num_max_harq - /// Number of Allocated RBs for UL after scheduling - uint16_t nb_rb_ul[8]; // num_max_harq + /// Number of Allocated RBs for UL after scheduling + uint16_t nb_rb_ul[8]; // num_max_harq - /// Number of Allocated RBs for UL after scheduling - uint16_t first_rb_ul[8]; // num_max_harq + /// Number of Allocated RBs for UL after scheduling + uint16_t first_rb_ul[8]; // num_max_harq - /// Cyclic shift for DMRS after scheduling - uint16_t cshift[8]; // num_max_harq + /// Cyclic shift for DMRS after scheduling + uint16_t cshift[8]; // num_max_harq - /// Number of Allocated RBs by the ulsch preprocessor - uint8_t pre_allocated_nb_rb_ul; + /// Number of Allocated RBs by the ulsch preprocessor + uint8_t pre_allocated_nb_rb_ul; - /// index of Allocated RBs by the ulsch preprocessor - int8_t pre_allocated_rb_table_index_ul; + /// index of Allocated RBs by the ulsch preprocessor + int8_t pre_allocated_rb_table_index_ul; - /// total allocated RBs - int8_t total_allocated_rbs; + /// total allocated RBs + int8_t total_allocated_rbs; - /// pre-assigned MCS by the ulsch preprocessor - uint8_t pre_assigned_mcs_ul; + /// pre-assigned MCS by the ulsch preprocessor + uint8_t pre_assigned_mcs_ul; - /// assigned MCS by the ulsch scheduler - uint8_t assigned_mcs_ul; + /// assigned MCS by the ulsch scheduler + uint8_t assigned_mcs_ul; - /// DL DAI - uint8_t DAI; + /// DL DAI + uint8_t DAI; - /// UL DAI - uint8_t DAI_ul[10]; + /// UL DAI + uint8_t DAI_ul[10]; - /// UL Scheduling Request Received - uint8_t ul_SR; + /// UL Scheduling Request Received + uint8_t ul_SR; - ///Resource Block indication for each sub-band in MU-MIMO - uint8_t rballoc_subband[8][50]; + ///Resource Block indication for each sub-band in MU-MIMO + uint8_t rballoc_subband[8][50]; - // Logical channel info for link with RLC + // Logical channel info for link with RLC - /// Last received UE BSR info for each logical channel group id - uint8_t bsr_info[MAX_NUM_LCGID]; + /// Last received UE BSR info for each logical channel group id + uint8_t bsr_info[MAX_NUM_LCGID]; - /// LCGID mapping - long lcgidmap[11]; + /// LCGID mapping + long lcgidmap[11]; - /// phr information - int8_t phr_info; + /// phr information + int8_t phr_info; - /// phr information - int8_t phr_info_configured; + /// phr information + int8_t phr_info_configured; - ///dl buffer info - uint32_t dl_buffer_info[MAX_NUM_LCID]; - /// total downlink buffer info - uint32_t dl_buffer_total; - /// total downlink pdus - uint32_t dl_pdus_total; - /// downlink pdus for each LCID - uint32_t dl_pdus_in_buffer[MAX_NUM_LCID]; - /// creation time of the downlink buffer head for each LCID - uint32_t dl_buffer_head_sdu_creation_time[MAX_NUM_LCID]; - /// maximum creation time of the downlink buffer head across all LCID - uint32_t dl_buffer_head_sdu_creation_time_max; - /// a flag indicating that the downlink head SDU is segmented - uint8_t dl_buffer_head_sdu_is_segmented[MAX_NUM_LCID]; - /// size of remaining size to send for the downlink head SDU - uint32_t dl_buffer_head_sdu_remaining_size_to_send[MAX_NUM_LCID]; + ///dl buffer info + uint32_t dl_buffer_info[MAX_NUM_LCID]; + /// total downlink buffer info + uint32_t dl_buffer_total; + /// total downlink pdus + uint32_t dl_pdus_total; + /// downlink pdus for each LCID + uint32_t dl_pdus_in_buffer[MAX_NUM_LCID]; + /// creation time of the downlink buffer head for each LCID + uint32_t dl_buffer_head_sdu_creation_time[MAX_NUM_LCID]; + /// maximum creation time of the downlink buffer head across all LCID + uint32_t dl_buffer_head_sdu_creation_time_max; + /// a flag indicating that the downlink head SDU is segmented + uint8_t dl_buffer_head_sdu_is_segmented[MAX_NUM_LCID]; + /// size of remaining size to send for the downlink head SDU + uint32_t dl_buffer_head_sdu_remaining_size_to_send[MAX_NUM_LCID]; - /// total uplink buffer size - uint32_t ul_total_buffer; - /// uplink buffer creation time for each LCID - uint32_t ul_buffer_creation_time[MAX_NUM_LCGID]; - /// maximum uplink buffer creation time across all the LCIDs - uint32_t ul_buffer_creation_time_max; - /// uplink buffer size per LCID - uint32_t ul_buffer_info[MAX_NUM_LCGID]; + /// total uplink buffer size + uint32_t ul_total_buffer; + /// uplink buffer creation time for each LCID + uint32_t ul_buffer_creation_time[MAX_NUM_LCGID]; + /// maximum uplink buffer creation time across all the LCIDs + uint32_t ul_buffer_creation_time_max; + /// uplink buffer size per LCID + uint32_t ul_buffer_info[MAX_NUM_LCGID]; - /// UE tx power - int32_t ue_tx_power; + /// UE tx power + int32_t ue_tx_power; - /// stores the frame where the last TPC was transmitted - uint32_t pusch_tpc_tx_frame; - uint32_t pusch_tpc_tx_subframe; - uint32_t pucch_tpc_tx_frame; - uint32_t pucch_tpc_tx_subframe; + /// stores the frame where the last TPC was transmitted + uint32_t pusch_tpc_tx_frame; + uint32_t pusch_tpc_tx_subframe; + uint32_t pucch_tpc_tx_frame; + uint32_t pucch_tpc_tx_subframe; #ifdef LOCALIZATION - eNB_UE_estimated_distances distance; + eNB_UE_estimated_distances distance; #endif #ifdef Rel14 - uint8_t rach_resource_type; - uint16_t mpdcch_repetition_cnt; - frame_t Msg2_frame; + uint8_t rach_resource_type; + uint16_t mpdcch_repetition_cnt; + frame_t Msg2_frame; #endif - sub_frame_t Msg2_subframe; + sub_frame_t Msg2_subframe; - PhysicalConfigDedicated_t *physicalConfigDedicated; + PhysicalConfigDedicated_t *physicalConfigDedicated; } UE_TEMPLATE; /*! \brief scheduling control information set through an API (not used)*/ typedef struct { - ///UL transmission bandwidth in RBs - uint8_t ul_bandwidth[MAX_NUM_LCID]; - ///DL transmission bandwidth in RBs - uint8_t dl_bandwidth[MAX_NUM_LCID]; + ///UL transmission bandwidth in RBs + uint8_t ul_bandwidth[MAX_NUM_LCID]; + ///DL transmission bandwidth in RBs + uint8_t dl_bandwidth[MAX_NUM_LCID]; - //To do GBR bearer - uint8_t min_ul_bandwidth[MAX_NUM_LCID]; + //To do GBR bearer + uint8_t min_ul_bandwidth[MAX_NUM_LCID]; - uint8_t min_dl_bandwidth[MAX_NUM_LCID]; + uint8_t min_dl_bandwidth[MAX_NUM_LCID]; - ///aggregated bit rate of non-gbr bearer per UE - uint64_t ue_AggregatedMaximumBitrateDL; - ///aggregated bit rate of non-gbr bearer per UE - uint64_t ue_AggregatedMaximumBitrateUL; - ///CQI scheduling interval in subframes. - uint16_t cqiSchedInterval; - ///Contention resolution timer used during random access - uint8_t mac_ContentionResolutionTimer; + ///aggregated bit rate of non-gbr bearer per UE + uint64_t ue_AggregatedMaximumBitrateDL; + ///aggregated bit rate of non-gbr bearer per UE + uint64_t ue_AggregatedMaximumBitrateUL; + ///CQI scheduling interval in subframes. + uint16_t cqiSchedInterval; + ///Contention resolution timer used during random access + uint8_t mac_ContentionResolutionTimer; - uint16_t max_allowed_rbs[MAX_NUM_LCID]; + uint16_t max_allowed_rbs[MAX_NUM_LCID]; - uint8_t max_mcs[MAX_NUM_LCID]; + uint8_t max_mcs[MAX_NUM_LCID]; - uint16_t priority[MAX_NUM_LCID]; + uint16_t priority[MAX_NUM_LCID]; - // resource scheduling information - - /// Current DL harq round per harq_pid on each CC - uint8_t round[MAX_NUM_CCs][10]; - /// Current Active TBs per harq_pid on each CC - uint8_t tbcnt[MAX_NUM_CCs][10]; - /// Current UL harq round per harq_pid on each CC - uint8_t round_UL[MAX_NUM_CCs][8]; - uint8_t dl_pow_off[MAX_NUM_CCs]; - uint16_t pre_nb_available_rbs[MAX_NUM_CCs]; - unsigned char rballoc_sub_UE[MAX_NUM_CCs][N_RBG_MAX]; - uint16_t ta_timer; - int16_t ta_update; - uint16_t ul_consecutive_errors; - int32_t context_active_timer; - int32_t cqi_req_timer; - int32_t ul_inactivity_timer; - int32_t ul_failure_timer; - int32_t ul_scheduled; - int32_t ra_pdcch_order_sent; - int32_t ul_out_of_sync; - int32_t phr_received; - uint8_t periodic_ri_received[NFAPI_CC_MAX]; - uint8_t aperiodic_ri_received[NFAPI_CC_MAX]; - uint8_t pucch1_cqi_update[NFAPI_CC_MAX]; - uint8_t pucch1_snr[NFAPI_CC_MAX]; - uint8_t pucch2_cqi_update[NFAPI_CC_MAX]; - uint8_t pucch2_snr[NFAPI_CC_MAX]; - uint8_t pucch3_cqi_update[NFAPI_CC_MAX]; - uint8_t pucch3_snr[NFAPI_CC_MAX]; - uint8_t pusch_snr[NFAPI_CC_MAX]; - uint16_t feedback_cnt[NFAPI_CC_MAX]; - uint16_t timing_advance; - uint16_t timing_advance_r9; - uint8_t periodic_wideband_cqi[NFAPI_CC_MAX]; - uint8_t periodic_wideband_spatial_diffcqi[NFAPI_CC_MAX]; - uint8_t periodic_wideband_pmi[NFAPI_CC_MAX]; - uint8_t periodic_subband_cqi[NFAPI_CC_MAX][16]; - uint8_t periodic_subband_spatial_diffcqi[NFAPI_CC_MAX][16]; - uint8_t aperiodic_subband_cqi0[NFAPI_CC_MAX][25]; - uint8_t aperiodic_subband_pmi[NFAPI_CC_MAX][25]; - uint8_t aperiodic_subband_diffcqi0[NFAPI_CC_MAX][25]; - uint8_t aperiodic_subband_cqi1[NFAPI_CC_MAX][25]; - uint8_t aperiodic_subband_diffcqi1[NFAPI_CC_MAX][25]; - uint8_t aperiodic_wideband_cqi0[NFAPI_CC_MAX]; - uint8_t aperiodic_wideband_pmi[NFAPI_CC_MAX]; - uint8_t aperiodic_wideband_cqi1[NFAPI_CC_MAX]; - uint8_t aperiodic_wideband_pmi1[NFAPI_CC_MAX]; - uint8_t dl_cqi[NFAPI_CC_MAX]; + // resource scheduling information + + /// Current DL harq round per harq_pid on each CC + uint8_t round[MAX_NUM_CCs][10]; + /// Current Active TBs per harq_pid on each CC + uint8_t tbcnt[MAX_NUM_CCs][10]; + /// Current UL harq round per harq_pid on each CC + uint8_t round_UL[MAX_NUM_CCs][8]; + uint8_t dl_pow_off[MAX_NUM_CCs]; + uint16_t pre_nb_available_rbs[MAX_NUM_CCs]; + unsigned char rballoc_sub_UE[MAX_NUM_CCs][N_RBG_MAX]; + uint16_t ta_timer; + int16_t ta_update; + uint16_t ul_consecutive_errors; + int32_t context_active_timer; + int32_t cqi_req_timer; + int32_t ul_inactivity_timer; + int32_t ul_failure_timer; + int32_t ul_scheduled; + int32_t ra_pdcch_order_sent; + int32_t ul_out_of_sync; + int32_t phr_received; + uint8_t periodic_ri_received[NFAPI_CC_MAX]; + uint8_t aperiodic_ri_received[NFAPI_CC_MAX]; + uint8_t pucch1_cqi_update[NFAPI_CC_MAX]; + uint8_t pucch1_snr[NFAPI_CC_MAX]; + uint8_t pucch2_cqi_update[NFAPI_CC_MAX]; + uint8_t pucch2_snr[NFAPI_CC_MAX]; + uint8_t pucch3_cqi_update[NFAPI_CC_MAX]; + uint8_t pucch3_snr[NFAPI_CC_MAX]; + uint8_t pusch_snr[NFAPI_CC_MAX]; + uint16_t feedback_cnt[NFAPI_CC_MAX]; + uint16_t timing_advance; + uint16_t timing_advance_r9; + uint8_t periodic_wideband_cqi[NFAPI_CC_MAX]; + uint8_t periodic_wideband_spatial_diffcqi[NFAPI_CC_MAX]; + uint8_t periodic_wideband_pmi[NFAPI_CC_MAX]; + uint8_t periodic_subband_cqi[NFAPI_CC_MAX][16]; + uint8_t periodic_subband_spatial_diffcqi[NFAPI_CC_MAX][16]; + uint8_t aperiodic_subband_cqi0[NFAPI_CC_MAX][25]; + uint8_t aperiodic_subband_pmi[NFAPI_CC_MAX][25]; + uint8_t aperiodic_subband_diffcqi0[NFAPI_CC_MAX][25]; + uint8_t aperiodic_subband_cqi1[NFAPI_CC_MAX][25]; + uint8_t aperiodic_subband_diffcqi1[NFAPI_CC_MAX][25]; + uint8_t aperiodic_wideband_cqi0[NFAPI_CC_MAX]; + uint8_t aperiodic_wideband_pmi[NFAPI_CC_MAX]; + uint8_t aperiodic_wideband_cqi1[NFAPI_CC_MAX]; + uint8_t aperiodic_wideband_pmi1[NFAPI_CC_MAX]; + uint8_t dl_cqi[NFAPI_CC_MAX]; } UE_sched_ctrl; /*! \brief eNB template for the Random access information */ typedef struct { - /// Flag to indicate this process is active - boolean_t RA_active; - /// Size of DCI for RA-Response (bytes) - uint8_t RA_dci_size_bytes1; - /// Size of DCI for RA-Response (bits) - uint8_t RA_dci_size_bits1; - /// Actual DCI to transmit for RA-Response - uint8_t RA_alloc_pdu1[(MAX_DCI_SIZE_BITS>>3)+1]; - /// DCI format for RA-Response (should be 1A) - uint8_t RA_dci_fmt1; - /// Size of DCI for Msg4/ContRes (bytes) - uint8_t RA_dci_size_bytes2; - /// Size of DCI for Msg4/ContRes (bits) - uint8_t RA_dci_size_bits2; - /// Actual DCI to transmit for Msg4/ContRes - uint8_t RA_alloc_pdu2[(MAX_DCI_SIZE_BITS>>3)+1]; - /// DCI format for Msg4/ContRes (should be 1A) - uint8_t RA_dci_fmt2; - /// Flag to indicate the eNB should generate RAR. This is triggered by detection of PRACH - uint8_t generate_rar; - /// Subframe where preamble was received - uint8_t preamble_subframe; - /// Subframe where Msg2 is to be sent - uint8_t Msg2_subframe; - /// Frame where Msg2 is to be sent - frame_t Msg2_frame; - /// Subframe where Msg3 is to be sent - sub_frame_t Msg3_subframe; - /// Frame where Msg3 is to be sent - frame_t Msg3_frame; - /// Subframe where Msg4 is to be sent - sub_frame_t Msg4_subframe; - /// Frame where Msg4 is to be sent - frame_t Msg4_frame; - /// Flag to indicate the eNB should generate Msg4 upon reception of SDU from RRC. This is triggered by first ULSCH reception at eNB for new user. - uint8_t generate_Msg4; - /// Flag to indicate that eNB is waiting for ACK that UE has received Msg3. - uint8_t wait_ack_Msg4; - /// harq_pid used for Msg4 transmission - uint8_t harq_pid; - /// UE RNTI allocated during RAR - rnti_t rnti; - /// RA RNTI allocated from received PRACH - uint16_t RA_rnti; - /// Received preamble_index - uint8_t preamble_index; - /// Received UE Contention Resolution Identifier - uint8_t cont_res_id[6]; - /// Timing offset indicated by PHY - int16_t timing_offset; - /// Timeout for RRC connection - int16_t RRC_timer; - /// Msg3 first RB - uint8_t msg3_first_rb; - /// Msg3 number of RB - uint8_t msg3_nb_rb; - /// Msg3 MCS - uint8_t msg3_mcs; - /// Msg3 TPC command - uint8_t msg3_TPC; - /// Msg3 ULdelay command - uint8_t msg3_ULdelay; - /// Msg3 cqireq command - uint8_t msg3_cqireq; - /// Round of Msg3 HARQ - uint8_t msg3_round; - /// TBS used for Msg4 - int msg4_TBsize; - /// MCS used for Msg4 - int msg4_mcs; + /// Flag to indicate this process is active + RA_state state; + /// Subframe where preamble was received + uint8_t preamble_subframe; + /// Subframe where Msg2 is to be sent + uint8_t Msg2_subframe; + /// Frame where Msg2 is to be sent + frame_t Msg2_frame; + /// Subframe where Msg3 is to be sent + sub_frame_t Msg3_subframe; + /// Frame where Msg3 is to be sent + frame_t Msg3_frame; + /// Subframe where Msg4 is to be sent + sub_frame_t Msg4_subframe; + /// Frame where Msg4 is to be sent + frame_t Msg4_frame; + /// harq_pid used for Msg4 transmission + uint8_t harq_pid; + /// UE RNTI allocated during RAR + rnti_t rnti; + /// RA RNTI allocated from received PRACH + uint16_t RA_rnti; + /// Received preamble_index + uint8_t preamble_index; + /// Received UE Contention Resolution Identifier + uint8_t cont_res_id[6]; + /// Timing offset indicated by PHY + int16_t timing_offset; + /// Timeout for RRC connection + int16_t RRC_timer; + /// Msg3 first RB + uint8_t msg3_first_rb; + /// Msg3 number of RB + uint8_t msg3_nb_rb; + /// Msg3 MCS + uint8_t msg3_mcs; + /// Msg3 TPC command + uint8_t msg3_TPC; + /// Msg3 ULdelay command + uint8_t msg3_ULdelay; + /// Msg3 cqireq command + uint8_t msg3_cqireq; + /// Round of Msg3 HARQ + uint8_t msg3_round; + /// TBS used for Msg4 + int msg4_TBsize; + /// MCS used for Msg4 + int msg4_mcs; #ifdef Rel14 - uint8_t rach_resource_type; - uint8_t msg2_mpdcch_repetition_cnt; - uint8_t msg4_mpdcch_repetition_cnt; - uint8_t msg2_narrowband; - uint8_t msg34_narrowband; + uint8_t rach_resource_type; + uint8_t msg2_mpdcch_repetition_cnt; + uint8_t msg4_mpdcch_repetition_cnt; + uint8_t msg2_narrowband; + uint8_t msg34_narrowband; #endif -} RA_TEMPLATE; +} RA_t; /*! \brief subband bitmap confguration (for ALU icic algo purpose), in test phase */ typedef struct { - uint8_t sbmap[NUMBER_OF_SUBBANDS_MAX]; //13 = number of SB MAX for 100 PRB - uint8_t periodicity; - uint8_t first_subframe; - uint8_t sb_size; - uint8_t nb_active_sb; + uint8_t sbmap[NUMBER_OF_SUBBANDS_MAX]; //13 = number of SB MAX for 100 PRB + uint8_t periodicity; + uint8_t first_subframe; + uint8_t sb_size; + uint8_t nb_active_sb; } SBMAP_CONF; -/*! \brief UE list used by eNB to order UEs/CC for scheduling*/ +/*! \brief UE list used by eNB to order UEs/CC for scheduling*/ typedef struct { - /// Dedicated information for UEs - struct PhysicalConfigDedicated *physicalConfigDedicated[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - /// DLSCH pdu - DLSCH_PDU DLSCH_pdu[MAX_NUM_CCs][2][NUMBER_OF_UE_MAX]; - /// DCI template and MAC connection parameters for UEs - UE_TEMPLATE UE_template[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - /// DCI template and MAC connection for RA processes - int pCC_id[NUMBER_OF_UE_MAX]; - /// sorted downlink component carrier for the scheduler - int ordered_CCids[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - /// number of downlink active component carrier - int numactiveCCs[NUMBER_OF_UE_MAX]; - /// sorted uplink component carrier for the scheduler - int ordered_ULCCids[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - /// number of uplink active component carrier - int numactiveULCCs[NUMBER_OF_UE_MAX]; - /// number of downlink active component carrier - uint8_t dl_CC_bitmap[NUMBER_OF_UE_MAX]; - /// eNB to UE statistics - eNB_UE_STATS eNB_UE_stats[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - /// scheduling control info - UE_sched_ctrl UE_sched_ctrl[NUMBER_OF_UE_MAX]; - int next[NUMBER_OF_UE_MAX]; - int head; - int next_ul[NUMBER_OF_UE_MAX]; - int head_ul; - int avail; - int num_UEs; - boolean_t active[NUMBER_OF_UE_MAX]; + /// Dedicated information for UEs + struct PhysicalConfigDedicated + *physicalConfigDedicated[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + /// DLSCH pdu + DLSCH_PDU DLSCH_pdu[MAX_NUM_CCs][2][NUMBER_OF_UE_MAX]; + /// DCI template and MAC connection parameters for UEs + UE_TEMPLATE UE_template[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + /// DCI template and MAC connection for RA processes + int pCC_id[NUMBER_OF_UE_MAX]; + /// sorted downlink component carrier for the scheduler + int ordered_CCids[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + /// number of downlink active component carrier + int numactiveCCs[NUMBER_OF_UE_MAX]; + /// sorted uplink component carrier for the scheduler + int ordered_ULCCids[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + /// number of uplink active component carrier + int numactiveULCCs[NUMBER_OF_UE_MAX]; + /// number of downlink active component carrier + uint8_t dl_CC_bitmap[NUMBER_OF_UE_MAX]; + /// eNB to UE statistics + eNB_UE_STATS eNB_UE_stats[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + /// scheduling control info + UE_sched_ctrl UE_sched_ctrl[NUMBER_OF_UE_MAX]; + int next[NUMBER_OF_UE_MAX]; + int head; + int next_ul[NUMBER_OF_UE_MAX]; + int head_ul; + int avail; + int num_UEs; + boolean_t active[NUMBER_OF_UE_MAX]; } UE_list_t; -/*! \brief eNB common channels */ +/*! \brief eNB common channels */ typedef struct { - int physCellId; - int p_eNB; - int Ncp; - int eutra_band; - uint32_t dl_CarrierFreq; - BCCH_BCH_Message_t *mib; - RadioResourceConfigCommonSIB_t *radioResourceConfigCommon; + int physCellId; + int p_eNB; + int Ncp; + int eutra_band; + uint32_t dl_CarrierFreq; + BCCH_BCH_Message_t *mib; + RadioResourceConfigCommonSIB_t *radioResourceConfigCommon; #ifdef Rel14 - RadioResourceConfigCommonSIB_t *radioResourceConfigCommon_BR; + RadioResourceConfigCommonSIB_t *radioResourceConfigCommon_BR; #endif - TDD_Config_t *tdd_Config; - SchedulingInfoList_t *schedulingInfoList; - ARFCN_ValueEUTRA_t ul_CarrierFreq; - long ul_Bandwidth; - /// Outgoing MIB PDU for PHY - MIB_PDU MIB_pdu; - /// Outgoing BCCH pdu for PHY - BCCH_PDU BCCH_pdu; - /// Outgoing BCCH DCI allocation - uint32_t BCCH_alloc_pdu; - /// Outgoing CCCH pdu for PHY - CCCH_PDU CCCH_pdu; - /// Outgoing RAR pdu for PHY - RAR_PDU RAR_pdu; - /// Template for RA computations - RA_TEMPLATE RA_template[NB_RA_PROC_MAX]; - /// VRB map for common channels - uint8_t vrb_map[100]; - /// VRB map for common channels and retransmissions by PHICH - uint8_t vrb_map_UL[100]; - /// MBSFN SubframeConfig - struct MBSFN_SubframeConfig *mbsfn_SubframeConfig[8]; - /// number of subframe allocation pattern available for MBSFN sync area - uint8_t num_sf_allocation_pattern; + TDD_Config_t *tdd_Config; + SchedulingInfoList_t *schedulingInfoList; + ARFCN_ValueEUTRA_t ul_CarrierFreq; + long ul_Bandwidth; + /// Outgoing MIB PDU for PHY + MIB_PDU MIB_pdu; + /// Outgoing BCCH pdu for PHY + BCCH_PDU BCCH_pdu; + /// Outgoing BCCH DCI allocation + uint32_t BCCH_alloc_pdu; + /// Outgoing CCCH pdu for PHY + CCCH_PDU CCCH_pdu; + /// Outgoing RAR pdu for PHY + RAR_PDU RAR_pdu; + /// Template for RA computations + RA_t ra[NB_RA_PROC_MAX]; + /// VRB map for common channels + uint8_t vrb_map[100]; + /// VRB map for common channels and retransmissions by PHICH + uint8_t vrb_map_UL[100]; + /// MBSFN SubframeConfig + struct MBSFN_SubframeConfig *mbsfn_SubframeConfig[8]; + /// number of subframe allocation pattern available for MBSFN sync area + uint8_t num_sf_allocation_pattern; #if defined(Rel10) || defined(Rel14) - /// MBMS Flag - uint8_t MBMS_flag; - /// Outgoing MCCH pdu for PHY - MCCH_PDU MCCH_pdu; - /// MCCH active flag - uint8_t msi_active; - /// MCCH active flag - uint8_t mcch_active; - /// MTCH active flag - uint8_t mtch_active; - /// number of active MBSFN area - uint8_t num_active_mbsfn_area; - /// MBSFN Area Info - struct MBSFN_AreaInfo_r9 *mbsfn_AreaInfo[MAX_MBSFN_AREA]; - /// PMCH Config - struct PMCH_Config_r9 *pmch_Config[MAX_PMCH_perMBSFN]; - /// MBMS session info list - struct MBMS_SessionInfoList_r9 *mbms_SessionList[MAX_PMCH_perMBSFN]; - /// Outgoing MCH pdu for PHY - MCH_PDU MCH_pdu; + /// MBMS Flag + uint8_t MBMS_flag; + /// Outgoing MCCH pdu for PHY + MCCH_PDU MCCH_pdu; + /// MCCH active flag + uint8_t msi_active; + /// MCCH active flag + uint8_t mcch_active; + /// MTCH active flag + uint8_t mtch_active; + /// number of active MBSFN area + uint8_t num_active_mbsfn_area; + /// MBSFN Area Info + struct MBSFN_AreaInfo_r9 *mbsfn_AreaInfo[MAX_MBSFN_AREA]; + /// PMCH Config + struct PMCH_Config_r9 *pmch_Config[MAX_PMCH_perMBSFN]; + /// MBMS session info list + struct MBMS_SessionInfoList_r9 *mbms_SessionList[MAX_PMCH_perMBSFN]; + /// Outgoing MCH pdu for PHY + MCH_PDU MCH_pdu; #endif #ifdef Rel14 - /// Rel13 parameters from SIB1 - SystemInformationBlockType1_v1310_IEs_t *sib1_v13ext; - /// Counter for SIB1-BR scheduling - int SIB1_BR_cnt; - /// Outgoing BCCH-BR pdu for PHY - BCCH_PDU BCCH_BR_pdu[20]; + /// Rel13 parameters from SIB1 + SystemInformationBlockType1_v1310_IEs_t *sib1_v13ext; + /// Counter for SIB1-BR scheduling + int SIB1_BR_cnt; + /// Outgoing BCCH-BR pdu for PHY + BCCH_PDU BCCH_BR_pdu[20]; #endif } COMMON_channels_t; -/*! \brief top level eNB MAC structure */ +/*! \brief top level eNB MAC structure */ typedef struct eNB_MAC_INST_s { - /// Ethernet parameters for northbound midhaul interface - eth_params_t eth_params_n; - /// Ethernet parameters for fronthaul interface - eth_params_t eth_params_s; - /// - module_id_t Mod_id; - /// frame counter - frame_t frame; - /// subframe counter - sub_frame_t subframe; - /// Pointer to IF module instance for PHY - IF_Module_t *if_inst; - /// Common cell resources - COMMON_channels_t common_channels[MAX_NUM_CCs]; - /// current PDU index (BCH,MCH,DLSCH) - uint16_t pdu_index[MAX_NUM_CCs]; + /// Ethernet parameters for northbound midhaul interface + eth_params_t eth_params_n; + /// Ethernet parameters for fronthaul interface + eth_params_t eth_params_s; + /// + module_id_t Mod_id; + /// frame counter + frame_t frame; + /// subframe counter + sub_frame_t subframe; + /// Pointer to IF module instance for PHY + IF_Module_t *if_inst; + /// Common cell resources + COMMON_channels_t common_channels[MAX_NUM_CCs]; + /// current PDU index (BCH,MCH,DLSCH) + uint16_t pdu_index[MAX_NUM_CCs]; - /// NFAPI Config Request Structure - nfapi_config_request_t config[MAX_NUM_CCs]; - /// Preallocated DL pdu list - nfapi_dl_config_request_pdu_t dl_config_pdu_list[MAX_NUM_CCs][MAX_NUM_DL_PDU]; - /// NFAPI DL Config Request Structure - nfapi_dl_config_request_t DL_req[MAX_NUM_CCs]; - /// Preallocated UL pdu list - nfapi_ul_config_request_pdu_t ul_config_pdu_list[MAX_NUM_CCs][MAX_NUM_UL_PDU]; - /// Preallocated UL pdu list for ULSCH (n+k delay) - nfapi_ul_config_request_pdu_t ul_config_pdu_list_tmp[MAX_NUM_CCs][10][MAX_NUM_UL_PDU]; - /// NFAPI UL Config Request Structure, send to L1 4 subframes before processing takes place - nfapi_ul_config_request_t UL_req[MAX_NUM_CCs]; - /// NFAPI "Temporary" UL Config Request Structure, holds future UL_config requests - nfapi_ul_config_request_t UL_req_tmp[MAX_NUM_CCs][10]; - /// Preallocated HI_DCI0 pdu list - nfapi_hi_dci0_request_pdu_t hi_dci0_pdu_list[MAX_NUM_CCs][MAX_NUM_HI_DCI0_PDU]; - /// NFAPI HI/DCI0 Config Request Structure - nfapi_hi_dci0_request_t HI_DCI0_req[MAX_NUM_CCs]; - /// Prealocated TX pdu list - nfapi_tx_request_pdu_t tx_request_pdu[MAX_NUM_CCs][MAX_NUM_TX_REQUEST_PDU]; - /// NFAPI DL PDU structure - nfapi_tx_request_t TX_req[MAX_NUM_CCs]; - /// UL handle - uint32_t ul_handle; - UE_list_t UE_list; + /// NFAPI Config Request Structure + nfapi_config_request_t config[MAX_NUM_CCs]; + /// Preallocated DL pdu list + nfapi_dl_config_request_pdu_t + dl_config_pdu_list[MAX_NUM_CCs][MAX_NUM_DL_PDU]; + /// NFAPI DL Config Request Structure + nfapi_dl_config_request_t DL_req[MAX_NUM_CCs]; + /// Preallocated UL pdu list + nfapi_ul_config_request_pdu_t + ul_config_pdu_list[MAX_NUM_CCs][MAX_NUM_UL_PDU]; + /// Preallocated UL pdu list for ULSCH (n+k delay) + nfapi_ul_config_request_pdu_t + ul_config_pdu_list_tmp[MAX_NUM_CCs][10][MAX_NUM_UL_PDU]; + /// NFAPI UL Config Request Structure, send to L1 4 subframes before processing takes place + nfapi_ul_config_request_t UL_req[MAX_NUM_CCs]; + /// NFAPI "Temporary" UL Config Request Structure, holds future UL_config requests + nfapi_ul_config_request_t UL_req_tmp[MAX_NUM_CCs][10]; + /// Preallocated HI_DCI0 pdu list + nfapi_hi_dci0_request_pdu_t + hi_dci0_pdu_list[MAX_NUM_CCs][MAX_NUM_HI_DCI0_PDU]; + /// NFAPI HI/DCI0 Config Request Structure + nfapi_hi_dci0_request_t HI_DCI0_req[MAX_NUM_CCs]; + /// Prealocated TX pdu list + nfapi_tx_request_pdu_t + tx_request_pdu[MAX_NUM_CCs][MAX_NUM_TX_REQUEST_PDU]; + /// NFAPI DL PDU structure + nfapi_tx_request_t TX_req[MAX_NUM_CCs]; + /// UL handle + uint32_t ul_handle; + UE_list_t UE_list; - ///subband bitmap configuration - SBMAP_CONF sbmap_conf; - /// CCE table used to build DCI scheduling information - int CCE_table[MAX_NUM_CCs][800]; - /// active flag for Other lcid - uint8_t lcid_active[NB_RB_MAX]; - /// eNB stats - eNB_STATS eNB_stats[MAX_NUM_CCs]; - // MAC function execution peformance profiler - /// processing time of eNB scheduler - time_stats_t eNB_scheduler; - /// processing time of eNB scheduler for SI - time_stats_t schedule_si; - /// processing time of eNB scheduler for Random access - time_stats_t schedule_ra; - /// processing time of eNB ULSCH scheduler - time_stats_t schedule_ulsch; - /// processing time of eNB DCI generation - time_stats_t fill_DLSCH_dci; - /// processing time of eNB MAC preprocessor - time_stats_t schedule_dlsch_preprocessor; - /// processing time of eNB DLSCH scheduler - time_stats_t schedule_dlsch; // include rlc_data_req + MAC header + preprocessor - /// processing time of eNB MCH scheduler - time_stats_t schedule_mch; - /// processing time of eNB ULSCH reception - time_stats_t rx_ulsch_sdu; // include rlc_data_ind + ///subband bitmap configuration + SBMAP_CONF sbmap_conf; + /// CCE table used to build DCI scheduling information + int CCE_table[MAX_NUM_CCs][800]; + /// active flag for Other lcid + uint8_t lcid_active[NB_RB_MAX]; + /// eNB stats + eNB_STATS eNB_stats[MAX_NUM_CCs]; + // MAC function execution peformance profiler + /// processing time of eNB scheduler + time_stats_t eNB_scheduler; + /// processing time of eNB scheduler for SI + time_stats_t schedule_si; + /// processing time of eNB scheduler for Random access + time_stats_t schedule_ra; + /// processing time of eNB ULSCH scheduler + time_stats_t schedule_ulsch; + /// processing time of eNB DCI generation + time_stats_t fill_DLSCH_dci; + /// processing time of eNB MAC preprocessor + time_stats_t schedule_dlsch_preprocessor; + /// processing time of eNB DLSCH scheduler + time_stats_t schedule_dlsch; // include rlc_data_req + MAC header + preprocessor + /// processing time of eNB MCH scheduler + time_stats_t schedule_mch; + /// processing time of eNB ULSCH reception + time_stats_t rx_ulsch_sdu; // include rlc_data_ind } eNB_MAC_INST; /* * UE part - */ + */ typedef enum { - TYPE0, - TYPE1, - TYPE1A, - TYPE2, - TYPE2A, - TYPEUESPEC + TYPE0, + TYPE1, + TYPE1A, + TYPE2, + TYPE2A, + TYPEUESPEC } MPDCCH_TYPES_t; /*!\brief UE layer 2 status */ typedef enum { - CONNECTION_OK=0, - CONNECTION_LOST, - PHY_RESYNCH, - PHY_HO_PRACH + CONNECTION_OK = 0, + CONNECTION_LOST, + PHY_RESYNCH, + PHY_HO_PRACH } UE_L2_STATE_t; /*!\brief UE scheduling info */ typedef struct { - /// buffer status for each lcgid - uint8_t BSR[MAX_NUM_LCGID]; // should be more for mesh topology - /// keep the number of bytes in rlc buffer for each lcgid - int32_t BSR_bytes[MAX_NUM_LCGID]; - /// after multiplexing buffer remain for each lcid - int32_t LCID_buffer_remain[MAX_NUM_LCID]; - /// sum of all lcid buffer size - uint16_t All_lcid_buffer_size_lastTTI; - /// buffer status for each lcid - uint8_t LCID_status[MAX_NUM_LCID]; - /// SR pending as defined in 36.321 - uint8_t SR_pending; - /// SR_COUNTER as defined in 36.321 - uint16_t SR_COUNTER; - /// logical channel group ide for each LCID - uint8_t LCGID[MAX_NUM_LCID]; - /// retxBSR-Timer, default value is sf2560 - uint16_t retxBSR_Timer; - /// retxBSR_SF, number of subframe before triggering a regular BSR - uint16_t retxBSR_SF; - /// periodicBSR-Timer, default to infinity - uint16_t periodicBSR_Timer; - /// periodicBSR_SF, number of subframe before triggering a periodic BSR - uint16_t periodicBSR_SF; - /// default value is 0: not configured - uint16_t sr_ProhibitTimer; - /// sr ProhibitTime running - uint8_t sr_ProhibitTimer_Running; - /// default value to n5 - uint16_t maxHARQ_Tx; - /// default value is false - uint16_t ttiBundling; - /// default value is release - struct DRX_Config *drx_config; - /// default value is release - struct MAC_MainConfig__phr_Config *phr_config; - ///timer before triggering a periodic PHR - uint16_t periodicPHR_Timer; - ///timer before triggering a prohibit PHR - uint16_t prohibitPHR_Timer; - ///DL Pathloss change value - uint16_t PathlossChange; - ///number of subframe before triggering a periodic PHR - int16_t periodicPHR_SF; - ///number of subframe before triggering a prohibit PHR - int16_t prohibitPHR_SF; - ///DL Pathloss Change in db - uint16_t PathlossChange_db; + /// buffer status for each lcgid + uint8_t BSR[MAX_NUM_LCGID]; // should be more for mesh topology + /// keep the number of bytes in rlc buffer for each lcgid + int32_t BSR_bytes[MAX_NUM_LCGID]; + /// after multiplexing buffer remain for each lcid + int32_t LCID_buffer_remain[MAX_NUM_LCID]; + /// sum of all lcid buffer size + uint16_t All_lcid_buffer_size_lastTTI; + /// buffer status for each lcid + uint8_t LCID_status[MAX_NUM_LCID]; + /// SR pending as defined in 36.321 + uint8_t SR_pending; + /// SR_COUNTER as defined in 36.321 + uint16_t SR_COUNTER; + /// logical channel group ide for each LCID + uint8_t LCGID[MAX_NUM_LCID]; + /// retxBSR-Timer, default value is sf2560 + uint16_t retxBSR_Timer; + /// retxBSR_SF, number of subframe before triggering a regular BSR + uint16_t retxBSR_SF; + /// periodicBSR-Timer, default to infinity + uint16_t periodicBSR_Timer; + /// periodicBSR_SF, number of subframe before triggering a periodic BSR + uint16_t periodicBSR_SF; + /// default value is 0: not configured + uint16_t sr_ProhibitTimer; + /// sr ProhibitTime running + uint8_t sr_ProhibitTimer_Running; + /// default value to n5 + uint16_t maxHARQ_Tx; + /// default value is false + uint16_t ttiBundling; + /// default value is release + struct DRX_Config *drx_config; + /// default value is release + struct MAC_MainConfig__phr_Config *phr_config; + ///timer before triggering a periodic PHR + uint16_t periodicPHR_Timer; + ///timer before triggering a prohibit PHR + uint16_t prohibitPHR_Timer; + ///DL Pathloss change value + uint16_t PathlossChange; + ///number of subframe before triggering a periodic PHR + int16_t periodicPHR_SF; + ///number of subframe before triggering a prohibit PHR + int16_t prohibitPHR_SF; + ///DL Pathloss Change in db + uint16_t PathlossChange_db; - /// default value is false - uint16_t extendedBSR_Sizes_r10; - /// default value is false - uint16_t extendedPHR_r10; + /// default value is false + uint16_t extendedBSR_Sizes_r10; + /// default value is false + uint16_t extendedPHR_r10; - //Bj bucket usage per lcid - int16_t Bj[MAX_NUM_LCID]; - // Bucket size per lcid - int16_t bucket_size[MAX_NUM_LCID]; + //Bj bucket usage per lcid + int16_t Bj[MAX_NUM_LCID]; + // Bucket size per lcid + int16_t bucket_size[MAX_NUM_LCID]; } UE_SCHEDULING_INFO; /*!\brief Top level UE MAC structure */ typedef struct { - uint16_t Node_id; - /// RX frame counter - frame_t rxFrame; - /// RX subframe counter - sub_frame_t rxSubframe; - /// TX frame counter - frame_t txFrame; - /// TX subframe counter - sub_frame_t txSubframe; - /// C-RNTI of UE - uint16_t crnti; - /// C-RNTI of UE before HO - rnti_t crnti_before_ho; ///user id (rnti) of connected UEs - /// uplink active flag - uint8_t ul_active; - /// pointer to RRC PHY configuration - RadioResourceConfigCommonSIB_t *radioResourceConfigCommon; - /// pointer to RACH_ConfigDedicated (NULL when not active, i.e. upon HO completion or T304 expiry) - struct RACH_ConfigDedicated *rach_ConfigDedicated; - /// pointer to RRC PHY configuration - struct PhysicalConfigDedicated *physicalConfigDedicated; + uint16_t Node_id; + /// RX frame counter + frame_t rxFrame; + /// RX subframe counter + sub_frame_t rxSubframe; + /// TX frame counter + frame_t txFrame; + /// TX subframe counter + sub_frame_t txSubframe; + /// C-RNTI of UE + uint16_t crnti; + /// C-RNTI of UE before HO + rnti_t crnti_before_ho; ///user id (rnti) of connected UEs + /// uplink active flag + uint8_t ul_active; + /// pointer to RRC PHY configuration + RadioResourceConfigCommonSIB_t *radioResourceConfigCommon; + /// pointer to RACH_ConfigDedicated (NULL when not active, i.e. upon HO completion or T304 expiry) + struct RACH_ConfigDedicated *rach_ConfigDedicated; + /// pointer to RRC PHY configuration + struct PhysicalConfigDedicated *physicalConfigDedicated; #if defined(Rel10) || defined(Rel14) - /// pointer to RRC PHY configuration SCEll - struct PhysicalConfigDedicatedSCell_r10 *physicalConfigDedicatedSCell_r10; + /// pointer to RRC PHY configuration SCEll + struct PhysicalConfigDedicatedSCell_r10 + *physicalConfigDedicatedSCell_r10; #endif - /// pointer to TDD Configuration (NULL for FDD) - TDD_Config_t *tdd_Config; - /// Number of adjacent cells to measure - uint8_t n_adj_cells; - /// Array of adjacent physical cell ids - uint32_t adj_cell_id[6]; - /// Pointer to RRC MAC configuration - MAC_MainConfig_t *macConfig; - /// Pointer to RRC Measurement gap configuration - MeasGapConfig_t *measGapConfig; - /// Pointers to LogicalChannelConfig indexed by LogicalChannelIdentity. Note NULL means LCHAN is inactive. - LogicalChannelConfig_t *logicalChannelConfig[MAX_NUM_LCID]; - /// Scheduling Information - UE_SCHEDULING_INFO scheduling_info; - /// Outgoing CCCH pdu for PHY - CCCH_PDU CCCH_pdu; - /// Outgoing RAR pdu for PHY - RAR_PDU RAR_pdu; - /// Incoming DLSCH pdu for PHY - DLSCH_PDU DLSCH_pdu[NUMBER_OF_UE_MAX][2]; - /// number of attempt for rach - uint8_t RA_attempt_number; - /// Random-access procedure flag - uint8_t RA_active; - /// Random-access window counter - int8_t RA_window_cnt; - /// Random-access Msg3 size in bytes - uint8_t RA_Msg3_size; - /// Random-access prachMaskIndex - uint8_t RA_prachMaskIndex; - /// Flag indicating Preamble set (A,B) used for first Msg3 transmission - uint8_t RA_usedGroupA; - /// Random-access Resources - PRACH_RESOURCES_t RA_prach_resources; - /// Random-access PREAMBLE_TRANSMISSION_COUNTER - uint8_t RA_PREAMBLE_TRANSMISSION_COUNTER; - /// Random-access backoff counter - int16_t RA_backoff_cnt; - /// Random-access variable for window calculation (frame of last change in window counter) - uint32_t RA_tx_frame; - /// Random-access variable for window calculation (subframe of last change in window counter) - uint8_t RA_tx_subframe; - /// Random-access Group B maximum path-loss - /// Random-access variable for backoff (frame of last change in backoff counter) - uint32_t RA_backoff_frame; - /// Random-access variable for backoff (subframe of last change in backoff counter) - uint8_t RA_backoff_subframe; - /// Random-access Group B maximum path-loss - uint16_t RA_maxPL; - /// Random-access Contention Resolution Timer active flag - uint8_t RA_contention_resolution_timer_active; - /// Random-access Contention Resolution Timer count value - uint8_t RA_contention_resolution_cnt; - /// power headroom reporitng reconfigured - uint8_t PHR_reconfigured; - /// power headroom state as configured by the higher layers - uint8_t PHR_state; - /// power backoff due to power management (as allowed by P-MPRc) for this cell - uint8_t PHR_reporting_active; - /// power backoff due to power management (as allowed by P-MPRc) for this cell - uint8_t power_backoff_db[NUMBER_OF_eNB_MAX]; - /// BSR report falg management - uint8_t BSR_reporting_active; - /// retxBSR-Timer expires flag - uint8_t retxBSRTimer_expires_flag; - /// periodBSR-Timer expires flag - uint8_t periodBSRTimer_expires_flag; + /// pointer to TDD Configuration (NULL for FDD) + TDD_Config_t *tdd_Config; + /// Number of adjacent cells to measure + uint8_t n_adj_cells; + /// Array of adjacent physical cell ids + uint32_t adj_cell_id[6]; + /// Pointer to RRC MAC configuration + MAC_MainConfig_t *macConfig; + /// Pointer to RRC Measurement gap configuration + MeasGapConfig_t *measGapConfig; + /// Pointers to LogicalChannelConfig indexed by LogicalChannelIdentity. Note NULL means LCHAN is inactive. + LogicalChannelConfig_t *logicalChannelConfig[MAX_NUM_LCID]; + /// Scheduling Information + UE_SCHEDULING_INFO scheduling_info; + /// Outgoing CCCH pdu for PHY + CCCH_PDU CCCH_pdu; + /// Outgoing RAR pdu for PHY + RAR_PDU RAR_pdu; + /// Incoming DLSCH pdu for PHY + DLSCH_PDU DLSCH_pdu[NUMBER_OF_UE_MAX][2]; + /// number of attempt for rach + uint8_t RA_attempt_number; + /// Random-access procedure flag + uint8_t RA_active; + /// Random-access window counter + int8_t RA_window_cnt; + /// Random-access Msg3 size in bytes + uint8_t RA_Msg3_size; + /// Random-access prachMaskIndex + uint8_t RA_prachMaskIndex; + /// Flag indicating Preamble set (A,B) used for first Msg3 transmission + uint8_t RA_usedGroupA; + /// Random-access Resources + PRACH_RESOURCES_t RA_prach_resources; + /// Random-access PREAMBLE_TRANSMISSION_COUNTER + uint8_t RA_PREAMBLE_TRANSMISSION_COUNTER; + /// Random-access backoff counter + int16_t RA_backoff_cnt; + /// Random-access variable for window calculation (frame of last change in window counter) + uint32_t RA_tx_frame; + /// Random-access variable for window calculation (subframe of last change in window counter) + uint8_t RA_tx_subframe; + /// Random-access Group B maximum path-loss + /// Random-access variable for backoff (frame of last change in backoff counter) + uint32_t RA_backoff_frame; + /// Random-access variable for backoff (subframe of last change in backoff counter) + uint8_t RA_backoff_subframe; + /// Random-access Group B maximum path-loss + uint16_t RA_maxPL; + /// Random-access Contention Resolution Timer active flag + uint8_t RA_contention_resolution_timer_active; + /// Random-access Contention Resolution Timer count value + uint8_t RA_contention_resolution_cnt; + /// power headroom reporitng reconfigured + uint8_t PHR_reconfigured; + /// power headroom state as configured by the higher layers + uint8_t PHR_state; + /// power backoff due to power management (as allowed by P-MPRc) for this cell + uint8_t PHR_reporting_active; + /// power backoff due to power management (as allowed by P-MPRc) for this cell + uint8_t power_backoff_db[NUMBER_OF_eNB_MAX]; + /// BSR report falg management + uint8_t BSR_reporting_active; + /// retxBSR-Timer expires flag + uint8_t retxBSRTimer_expires_flag; + /// periodBSR-Timer expires flag + uint8_t periodBSRTimer_expires_flag; - /// MBSFN_Subframe Configuration - struct MBSFN_SubframeConfig *mbsfn_SubframeConfig[8]; // FIXME replace 8 by MAX_MBSFN_AREA? - /// number of subframe allocation pattern available for MBSFN sync area - uint8_t num_sf_allocation_pattern; + /// MBSFN_Subframe Configuration + struct MBSFN_SubframeConfig *mbsfn_SubframeConfig[8]; // FIXME replace 8 by MAX_MBSFN_AREA? + /// number of subframe allocation pattern available for MBSFN sync area + uint8_t num_sf_allocation_pattern; #if defined(Rel10) || defined(Rel14) - /// number of active MBSFN area - uint8_t num_active_mbsfn_area; - /// MBSFN Area Info - struct MBSFN_AreaInfo_r9 *mbsfn_AreaInfo[MAX_MBSFN_AREA]; - /// PMCH Config - struct PMCH_Config_r9 *pmch_Config[MAX_PMCH_perMBSFN]; - /// MCCH status - uint8_t mcch_status; - /// MSI status - uint8_t msi_status;// could be an array if there are >1 MCH in one MBSFN area + /// number of active MBSFN area + uint8_t num_active_mbsfn_area; + /// MBSFN Area Info + struct MBSFN_AreaInfo_r9 *mbsfn_AreaInfo[MAX_MBSFN_AREA]; + /// PMCH Config + struct PMCH_Config_r9 *pmch_Config[MAX_PMCH_perMBSFN]; + /// MCCH status + uint8_t mcch_status; + /// MSI status + uint8_t msi_status; // could be an array if there are >1 MCH in one MBSFN area #endif - //#ifdef CBA - /// CBA RNTI for each group - uint16_t cba_rnti[NUM_MAX_CBA_GROUP]; - /// last SFN for CBA channel access - uint8_t cba_last_access[NUM_MAX_CBA_GROUP]; - //#endif - /// total UE scheduler processing time - time_stats_t ue_scheduler; // total - /// UE ULSCH tx processing time inlcuding RLC interface (rlc_data_req) and mac header generation - time_stats_t tx_ulsch_sdu; - /// UE DLSCH rx processing time inlcuding RLC interface (mac_rrc_data_ind or mac_rlc_status_ind+mac_rlc_data_ind) and mac header parser - time_stats_t rx_dlsch_sdu ; - /// UE query for MCH subframe processing time - time_stats_t ue_query_mch; - /// UE MCH rx processing time - time_stats_t rx_mch_sdu; - /// UE BCCH rx processing time including RLC interface (mac_rrc_data_ind) - time_stats_t rx_si; - /// UE PCCH rx processing time including RLC interface (mac_rrc_data_ind) - time_stats_t rx_p; + //#ifdef CBA + /// CBA RNTI for each group + uint16_t cba_rnti[NUM_MAX_CBA_GROUP]; + /// last SFN for CBA channel access + uint8_t cba_last_access[NUM_MAX_CBA_GROUP]; + //#endif + /// total UE scheduler processing time + time_stats_t ue_scheduler; // total + /// UE ULSCH tx processing time inlcuding RLC interface (rlc_data_req) and mac header generation + time_stats_t tx_ulsch_sdu; + /// UE DLSCH rx processing time inlcuding RLC interface (mac_rrc_data_ind or mac_rlc_status_ind+mac_rlc_data_ind) and mac header parser + time_stats_t rx_dlsch_sdu; + /// UE query for MCH subframe processing time + time_stats_t ue_query_mch; + /// UE MCH rx processing time + time_stats_t rx_mch_sdu; + /// UE BCCH rx processing time including RLC interface (mac_rrc_data_ind) + time_stats_t rx_si; + /// UE PCCH rx processing time including RLC interface (mac_rrc_data_ind) + time_stats_t rx_p; } UE_MAC_INST; /*! \brief ID of the neighboring cells used for HO*/ typedef struct { - uint16_t cell_ids[6]; - uint8_t n_adj_cells; + uint16_t cell_ids[6]; + uint8_t n_adj_cells; } neigh_cell_id_t; #include "proto.h" /*@}*/ #endif /*__LAYER2_MAC_DEFS_H__ */ - - - diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 6bcbc13106..f7c3f5829d 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -60,7 +60,7 @@ #endif #if defined(ENABLE_ITTI) -# include "intertask_interface.h" +#include "intertask_interface.h" #endif #define ENABLE_MAC_PAYLOAD_DEBUG @@ -68,481 +68,693 @@ extern RAN_CONTEXT_t RC; -uint16_t pdcch_order_table[6] = {31,31,511,2047,2047,8191}; +uint16_t pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 }; -void schedule_SRS(module_id_t module_idP,frame_t frameP,sub_frame_t subframeP) +void +schedule_SRS(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) { - eNB_MAC_INST *eNB = RC.mac[module_idP]; - UE_list_t *UE_list = &eNB->UE_list; - nfapi_ul_config_request_body_t *ul_req; - int CC_id,UE_id; - COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; - SoundingRS_UL_ConfigCommon_t *soundingRS_UL_ConfigCommon; - struct SoundingRS_UL_ConfigDedicated *soundingRS_UL_ConfigDedicated; - uint8_t TSFC; - uint16_t deltaTSFC; // bitmap - uint8_t srs_SubframeConfig; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + UE_list_t *UE_list = &eNB->UE_list; + nfapi_ul_config_request_body_t *ul_req; + int CC_id, UE_id; + COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; + SoundingRS_UL_ConfigCommon_t *soundingRS_UL_ConfigCommon; + struct SoundingRS_UL_ConfigDedicated *soundingRS_UL_ConfigDedicated; + uint8_t TSFC; + uint16_t deltaTSFC; // bitmap + uint8_t srs_SubframeConfig; - // table for TSFC (Period) and deltaSFC (offset) - const uint16_t deltaTSFCTabType1[15][2] = { {1,1},{1,2},{2,2},{1,5},{2,5},{4,5},{8,5},{3,5},{12,5},{1,10},{2,10},{4,10},{8,10},{351,10},{383,10} }; // Table 5.5.3.3-2 3GPP 36.211 FDD - const uint16_t deltaTSFCTabType2[14][2] = { {2,5},{6,5},{10,5},{18,5},{14,5},{22,5},{26,5},{30,5},{70,10},{74,10},{194,10},{326,10},{586,10},{210,10} }; // Table 5.5.3.3-2 3GPP 36.211 TDD + // table for TSFC (Period) and deltaSFC (offset) + const uint16_t deltaTSFCTabType1[15][2] = { {1, 1}, {1, 2}, {2, 2}, {1, 5}, {2, 5}, {4, 5}, {8, 5}, {3, 5}, {12, 5}, {1, 10}, {2, 10}, {4, 10}, {8, 10}, {351, 10}, {383, 10} }; // Table 5.5.3.3-2 3GPP 36.211 FDD + const uint16_t deltaTSFCTabType2[14][2] = { {2, 5}, {6, 5}, {10, 5}, {18, 5}, {14, 5}, {22, 5}, {26, 5}, {30, 5}, {70, 10}, {74, 10}, {194, 10}, {326, 10}, {586, 10}, {210, 10} }; // Table 5.5.3.3-2 3GPP 36.211 TDD - uint16_t srsPeriodicity,srsOffset; + uint16_t srsPeriodicity, srsOffset; - for (CC_id=0;CC_idsoundingRS_UL_ConfigCommon; - // check if SRS is enabled in this frame/subframe - if (soundingRS_UL_ConfigCommon) { - srs_SubframeConfig = soundingRS_UL_ConfigCommon->choice.setup.srs_SubframeConfig; - if (cc[CC_id].tdd_Config == NULL) { // FDD - deltaTSFC = deltaTSFCTabType1[srs_SubframeConfig][0]; - TSFC = deltaTSFCTabType1[srs_SubframeConfig][1]; - } - else { // TDD - deltaTSFC = deltaTSFCTabType2[srs_SubframeConfig][0]; - TSFC = deltaTSFCTabType2[srs_SubframeConfig][1]; - } - // Sounding reference signal subframes are the subframes satisfying ns/2 mod TSFC (- deltaTSFC - uint16_t tmp = (subframeP % TSFC); + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + soundingRS_UL_ConfigCommon = + &cc[CC_id].radioResourceConfigCommon-> + soundingRS_UL_ConfigCommon; + // check if SRS is enabled in this frame/subframe + if (soundingRS_UL_ConfigCommon) { + srs_SubframeConfig = + soundingRS_UL_ConfigCommon->choice.setup. + srs_SubframeConfig; + if (cc[CC_id].tdd_Config == NULL) { // FDD + deltaTSFC = deltaTSFCTabType1[srs_SubframeConfig][0]; + TSFC = deltaTSFCTabType1[srs_SubframeConfig][1]; + } else { // TDD + deltaTSFC = deltaTSFCTabType2[srs_SubframeConfig][0]; + TSFC = deltaTSFCTabType2[srs_SubframeConfig][1]; + } + // Sounding reference signal subframes are the subframes satisfying ns/2 mod TSFC (- deltaTSFC + uint16_t tmp = (subframeP % TSFC); - if((1<UE_list.active[UE_id]!=TRUE) continue; - ul_req = &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body; + if ((1 << tmp) & deltaTSFC) { + // This is an SRS subframe, loop over UEs + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { + if (RC.mac[module_idP]->UE_list.active[UE_id] != TRUE) + continue; + ul_req = + &RC.mac[module_idP]->UL_req[CC_id]. + ul_config_request_body; - // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet - if (mac_eNB_get_rrc_status(module_idP,UE_RNTI(module_idP,UE_id)) < RRC_CONNECTED) continue; + // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet + if (mac_eNB_get_rrc_status + (module_idP, + UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) + continue; - AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n",UE_id); + AssertFatal(UE_list->UE_template[CC_id] + [UE_id].physicalConfigDedicated != NULL, + "physicalConfigDedicated is null for UE %d\n", + UE_id); - if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated)!=NULL) { - if (soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) { - get_srs_pos(&cc[CC_id], soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex, &srsPeriodicity, &srsOffset); - if (((10*frameP+subframeP) % srsPeriodicity) == srsOffset) { - // Prorgram SRS - ul_req->srs_present = 1; - nfapi_ul_config_request_pdu_t* ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; - memset((void*)ul_config_pdu,0,sizeof(nfapi_ul_config_request_pdu_t)); - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_SRS_PDU_TYPE; - ul_config_pdu->pdu_size = 2+(uint8_t)(2+sizeof(nfapi_ul_config_srs_pdu)); - ul_config_pdu->srs_pdu.srs_pdu_rel8.size = (uint8_t)sizeof(nfapi_ul_config_srs_pdu);; - ul_config_pdu->srs_pdu.srs_pdu_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; - ul_config_pdu->srs_pdu.srs_pdu_rel8.srs_bandwidth = soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth; - ul_config_pdu->srs_pdu.srs_pdu_rel8.frequency_domain_position = soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition; - ul_config_pdu->srs_pdu.srs_pdu_rel8.srs_hopping_bandwidth = soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth;; - ul_config_pdu->srs_pdu.srs_pdu_rel8.transmission_comb = soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb; - ul_config_pdu->srs_pdu.srs_pdu_rel8.i_srs = soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex; - ul_config_pdu->srs_pdu.srs_pdu_rel8.sounding_reference_cyclic_shift = soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift; - // ul_config_pdu->srs_pdu.srs_pdu_rel10.antenna_port = ;// - // ul_config_pdu->srs_pdu.srs_pdu_rel13.number_of_combs = ;// - RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP<<4)+subframeP; + if ((soundingRS_UL_ConfigDedicated = + UE_list->UE_template[CC_id] + [UE_id]. + physicalConfigDedicated->soundingRS_UL_ConfigDedicated) + != NULL) { + if (soundingRS_UL_ConfigDedicated->present == + SoundingRS_UL_ConfigDedicated_PR_setup) { + get_srs_pos(&cc[CC_id], + soundingRS_UL_ConfigDedicated->choice. + setup.srs_ConfigIndex, + &srsPeriodicity, &srsOffset); + if (((10 * frameP + + subframeP) % srsPeriodicity) == + srsOffset) { + // Prorgram SRS + ul_req->srs_present = 1; + nfapi_ul_config_request_pdu_t + * ul_config_pdu = + &ul_req-> + ul_config_pdu_list + [ul_req->number_of_pdus]; + memset((void *) ul_config_pdu, 0, + sizeof + (nfapi_ul_config_request_pdu_t)); + ul_config_pdu->pdu_type = + NFAPI_UL_CONFIG_SRS_PDU_TYPE; + ul_config_pdu->pdu_size = + 2 + (uint8_t) (2 + + sizeof + (nfapi_ul_config_srs_pdu)); + ul_config_pdu->srs_pdu.srs_pdu_rel8.size = + (uint8_t) + sizeof(nfapi_ul_config_srs_pdu);; + ul_config_pdu->srs_pdu.srs_pdu_rel8.rnti = + UE_list->UE_template[CC_id][UE_id]. + rnti; + ul_config_pdu->srs_pdu. + srs_pdu_rel8.srs_bandwidth = + soundingRS_UL_ConfigDedicated-> + choice.setup.srs_Bandwidth; + ul_config_pdu->srs_pdu. + srs_pdu_rel8.frequency_domain_position + = + soundingRS_UL_ConfigDedicated-> + choice.setup.freqDomainPosition; + ul_config_pdu->srs_pdu. + srs_pdu_rel8.srs_hopping_bandwidth = + soundingRS_UL_ConfigDedicated-> + choice.setup.srs_HoppingBandwidth;; + ul_config_pdu->srs_pdu. + srs_pdu_rel8.transmission_comb = + soundingRS_UL_ConfigDedicated-> + choice.setup.transmissionComb; + ul_config_pdu->srs_pdu.srs_pdu_rel8.i_srs = + soundingRS_UL_ConfigDedicated-> + choice.setup.srs_ConfigIndex; + ul_config_pdu->srs_pdu. + srs_pdu_rel8.sounding_reference_cyclic_shift + = + soundingRS_UL_ConfigDedicated-> + choice.setup.cyclicShift; + // ul_config_pdu->srs_pdu.srs_pdu_rel10.antenna_port = ;// + // ul_config_pdu->srs_pdu.srs_pdu_rel13.number_of_combs = ;// + RC.mac[module_idP]->UL_req[CC_id].sfn_sf = + (frameP << 4) + subframeP; + ul_req->number_of_pdus++; + } // if (((10*frameP+subframeP) % srsPeriodicity) == srsOffset) + } // if (soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) + } // if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated)!=NULL) + } // for (UE_id ... + } // if((1<UE_list; + COMMON_channels_t *cc; + nfapi_ul_config_request_body_t *ul_req; + int CC_id, UE_id; + struct CQI_ReportPeriodic *cqi_ReportPeriodic; + uint16_t Npd, N_OFFSET_CQI; + int H; + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + + cc = &eNB->common_channels[CC_id]; + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { + if (UE_list->active[UE_id] != TRUE) + continue; + + ul_req = + &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body; + + // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet + if (mac_eNB_get_rrc_status + (module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) + continue; + + AssertFatal(UE_list-> + UE_template[CC_id][UE_id].physicalConfigDedicated + != NULL, + "physicalConfigDedicated is null for UE %d\n", + UE_id); + + if (UE_list-> + UE_template[CC_id][UE_id].physicalConfigDedicated-> + cqi_ReportConfig) { + if ((cqi_ReportPeriodic = + UE_list-> + UE_template[CC_id][UE_id].physicalConfigDedicated-> + cqi_ReportConfig->cqi_ReportPeriodic) != NULL + && (cqi_ReportPeriodic->present != + CQI_ReportPeriodic_PR_release)) { + //Rel8 Periodic CQI/PMI/RI reporting + + get_csi_params(cc, cqi_ReportPeriodic, &Npd, + &N_OFFSET_CQI, &H); + + if ((((frameP * 10) + subframeP) % Npd) == N_OFFSET_CQI) { // CQI opportunity + UE_list->UE_sched_ctrl[UE_id].feedback_cnt[CC_id] = + (((frameP * 10) + subframeP) / Npd) % H; + // Program CQI + nfapi_ul_config_request_pdu_t *ul_config_pdu = + &ul_req->ul_config_pdu_list[ul_req-> + number_of_pdus]; + memset((void *) ul_config_pdu, 0, + sizeof(nfapi_ul_config_request_pdu_t)); + ul_config_pdu->pdu_type = + NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; + ul_config_pdu->pdu_size = + 2 + (uint8_t) (2 + + sizeof + (nfapi_ul_config_uci_cqi_pdu)); + ul_config_pdu->uci_cqi_pdu. + ue_information.ue_information_rel8.rnti = + UE_list->UE_template[CC_id][UE_id].rnti; + ul_config_pdu->uci_cqi_pdu. + cqi_information.cqi_information_rel8. + pucch_index = + cqi_ReportPeriodic->choice. + setup.cqi_PUCCH_ResourceIndex; + ul_config_pdu->uci_cqi_pdu. + cqi_information.cqi_information_rel8. + dl_cqi_pmi_size = + get_rel8_dl_cqi_pmi_size + (&UE_list->UE_sched_ctrl[UE_id], CC_id, cc, + get_tmode(module_idP, CC_id, UE_id), + cqi_ReportPeriodic); + ul_req->number_of_pdus++; + +#if defined(Rel10) || defined(Rel14) + // PUT rel10-13 UCI options here +#endif + } else + if ((cqi_ReportPeriodic->choice.setup. + ri_ConfigIndex) + && ((((frameP * 10) + subframeP) % ((H * Npd) << (*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex / 161))) == N_OFFSET_CQI + (*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex % 161))) { // RI opportunity + // Program RI + nfapi_ul_config_request_pdu_t *ul_config_pdu = + &ul_req->ul_config_pdu_list[ul_req-> + number_of_pdus]; + memset((void *) ul_config_pdu, 0, + sizeof(nfapi_ul_config_request_pdu_t)); + ul_config_pdu->pdu_type = + NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; + ul_config_pdu->pdu_size = + 2 + (uint8_t) (2 + + sizeof + (nfapi_ul_config_uci_cqi_pdu)); + ul_config_pdu->uci_cqi_pdu. + ue_information.ue_information_rel8.rnti = + UE_list->UE_template[CC_id][UE_id].rnti; + ul_config_pdu->uci_cqi_pdu. + cqi_information.cqi_information_rel8. + pucch_index = + cqi_ReportPeriodic->choice. + setup.cqi_PUCCH_ResourceIndex; + ul_config_pdu->uci_cqi_pdu. + cqi_information.cqi_information_rel8. + dl_cqi_pmi_size = (cc->p_eNB == 2) ? 1 : 2; + RC.mac[module_idP]->UL_req[CC_id].sfn_sf = + (frameP << 4) + subframeP; + ul_req->number_of_pdus++; + } + + } // if ((cqi_ReportPeriodic = cqi_ReportConfig->cqi_ReportPeriodic)!=NULL) { + } // if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig) + } // for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { + } // for (CC_id=0; CC_idUE_list; + nfapi_ul_config_request_body_t *ul_req; + int CC_id; + int UE_id; + SchedulingRequestConfig_t *SRconfig; + int skip_ue; + int is_harq; + nfapi_ul_config_sr_information sr; + int i; + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + RC.mac[module_idP]->UL_req[CC_id].sfn_sf = + (frameP << 4) + subframeP; + + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { + if (RC.mac[module_idP]->UE_list.active[UE_id] != TRUE) + continue; + + ul_req = + &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body; + + AssertFatal(UE_list-> + UE_template[CC_id][UE_id].physicalConfigDedicated + != NULL, + "physicalConfigDedicated is null for UE %d\n", + UE_id); + + // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet + if (mac_eNB_get_rrc_status + (module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) + continue; + + if ((SRconfig = + UE_list-> + UE_template[CC_id][UE_id].physicalConfigDedicated-> + schedulingRequestConfig) != NULL) { + if (SRconfig->present == SchedulingRequestConfig_PR_setup) { + if (SRconfig->choice.setup.sr_ConfigIndex <= 4) { // 5 ms SR period + if ((subframeP % 5) != + SRconfig->choice.setup.sr_ConfigIndex) + continue; + } else if (SRconfig->choice.setup.sr_ConfigIndex <= 14) { // 10 ms SR period + if (subframeP != + (SRconfig->choice.setup.sr_ConfigIndex - 5)) + continue; + } else if (SRconfig->choice.setup.sr_ConfigIndex <= 34) { // 20 ms SR period + if ((10 * (frameP & 1) + subframeP) != + (SRconfig->choice.setup.sr_ConfigIndex - 15)) + continue; + } else if (SRconfig->choice.setup.sr_ConfigIndex <= 74) { // 40 ms SR period + if ((10 * (frameP & 3) + subframeP) != + (SRconfig->choice.setup.sr_ConfigIndex - 35)) + continue; + } else if (SRconfig->choice.setup.sr_ConfigIndex <= 154) { // 80 ms SR period + if ((10 * (frameP & 7) + subframeP) != + (SRconfig->choice.setup.sr_ConfigIndex - 75)) + continue; + } + } // SRconfig->present == SchedulingRequestConfig_PR_setup) + } // SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig)!=NULL) + + // if we get here there is some PUCCH1 reception to schedule for SR + + skip_ue = 0; + is_harq = 0; + // check that there is no existing UL grant for ULSCH which overrides the SR + for (i = 0; i < ul_req->number_of_pdus; i++) { + if (((ul_req->ul_config_pdu_list[i].pdu_type == + NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) + || (ul_req->ul_config_pdu_list[i].pdu_type == + NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE) + || (ul_req->ul_config_pdu_list[i].pdu_type == + NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) + || (ul_req->ul_config_pdu_list[i].pdu_type == + NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE)) + && (ul_req->ul_config_pdu_list[i]. + ulsch_pdu.ulsch_pdu_rel8.rnti == + UE_list->UE_template[CC_id][UE_id].rnti)) { + skip_ue = 1; + break; + } + /* if there is already an HARQ pdu, convert to SR_HARQ */ + else if ((ul_req->ul_config_pdu_list[i].pdu_type == + NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) + && (ul_req->ul_config_pdu_list[i]. + uci_harq_pdu.ue_information. + ue_information_rel8.rnti == + UE_list->UE_template[CC_id][UE_id].rnti)) { + is_harq = 1; + break; + } + } + + // drop the allocation because ULSCH with handle it with BSR + if (skip_ue == 1) + continue; + + LOG_D(MAC, + "Frame %d, Subframe %d : Scheduling SR for UE %d/%x\n", + frameP, subframeP, UE_id, + UE_list->UE_template[CC_id][UE_id].rnti); + + // check Rel10 or Rel8 SR +#if defined(Rel10) || defined(Rel14) + if ((UE_list-> + UE_template[CC_id][UE_id].physicalConfigDedicated->ext2) + && (UE_list-> + UE_template[CC_id][UE_id].physicalConfigDedicated-> + ext2->schedulingRequestConfig_v1020) + && (UE_list-> + UE_template[CC_id][UE_id].physicalConfigDedicated-> + ext2->schedulingRequestConfig_v1020)) { + sr.sr_information_rel10.number_of_pucch_resources = 1; + sr.sr_information_rel10.pucch_index_p1 = + *UE_list-> + UE_template[CC_id][UE_id].physicalConfigDedicated-> + ext2-> + schedulingRequestConfig_v1020->sr_PUCCH_ResourceIndexP1_r10; + } else +#endif + { + sr.sr_information_rel8.pucch_index = + UE_list-> + UE_template[CC_id][UE_id].physicalConfigDedicated-> + schedulingRequestConfig->choice.setup. + sr_PUCCH_ResourceIndex; + } + + /* if there is already an HARQ pdu, convert to SR_HARQ */ + if (is_harq) { + nfapi_ul_config_harq_information h = + ul_req->ul_config_pdu_list[i].uci_harq_pdu. + harq_information; + ul_req->ul_config_pdu_list[i].pdu_type = + NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; + ul_req->ul_config_pdu_list[i].uci_sr_harq_pdu. + sr_information = sr; + ul_req->ul_config_pdu_list[i].uci_sr_harq_pdu. + harq_information = h; + } else { + ul_req->ul_config_pdu_list[ul_req->number_of_pdus]. + pdu_type = NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE; + ul_req->ul_config_pdu_list[ul_req-> + number_of_pdus].uci_sr_pdu. + ue_information.ue_information_rel8.rnti = + UE_list->UE_template[CC_id][UE_id].rnti; + ul_req->ul_config_pdu_list[ul_req-> + number_of_pdus].uci_sr_pdu. + sr_information = sr; ul_req->number_of_pdus++; - } // if (((10*frameP+subframeP) % srsPeriodicity) == srsOffset) - } // if (soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) - } // if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated)!=NULL) - } // for (UE_id ... - } // if((1<head; UE_id>=0; UE_id=UE_list->next[UE_id]) + } // for (CC_id=0; CC_idUE_list; - COMMON_channels_t *cc; - nfapi_ul_config_request_body_t *ul_req; - int CC_id,UE_id; - struct CQI_ReportPeriodic *cqi_ReportPeriodic; - uint16_t Npd,N_OFFSET_CQI; - int H; + UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; + nfapi_dl_config_request_t *DL_req = &RC.mac[module_idP]->DL_req[0]; + uint16_t rnti = UE_RNTI(module_idP, UE_id); + COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; - for (CC_id=0; CC_idUE_sched_ctrl[UE_id].ul_failure_timer > 0) && + (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 0)) { + LOG_I(MAC, "UE %d rnti %x: UL Failure timer %d \n", UE_id, rnti, + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); + if (UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent == 0) { + UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 1; - cc = &eNB->common_channels[CC_id]; - for (UE_id=0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { - if (UE_list->active[UE_id] != TRUE) continue; + // add a format 1A dci for this UE to request an RA procedure (only one UE per subframe) + nfapi_dl_config_request_pdu_t *dl_config_pdu = + &DL_req[CC_id]. + dl_config_request_body.dl_config_pdu_list[DL_req[CC_id]. + dl_config_request_body.number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = + NFAPI_DL_DCI_FORMAT_1A; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = + get_aggregation(get_bw_index(module_idP, CC_id), + UE_list->UE_sched_ctrl[UE_id]. + dl_cqi[CC_id], format1A); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power - ul_req = &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body; + AssertFatal((cc[CC_id].mib->message.dl_Bandwidth >= 0) + && (cc[CC_id].mib->message.dl_Bandwidth < 6), + "illegal dl_Bandwidth %d\n", + (int) cc[CC_id].mib->message.dl_Bandwidth); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + resource_block_coding = + pdcch_order_table[cc[CC_id].mib->message.dl_Bandwidth]; + DL_req[CC_id].dl_config_request_body.number_dci++; + DL_req[CC_id].dl_config_request_body.number_pdu++; + LOG_I(MAC, + "UE %d rnti %x: sending PDCCH order for RAPROC (failure timer %d), resource_block_coding %d \n", + UE_id, rnti, + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer, + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.resource_block_coding); + } else { // ra_pdcch_sent==1 + LOG_I(MAC, + "UE %d rnti %x: sent PDCCH order for RAPROC waiting (failure timer %d) \n", + UE_id, rnti, + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); + if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer % 40) == 0) + UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 0; // resend every 4 frames + } - // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet - if (mac_eNB_get_rrc_status(module_idP,UE_RNTI(module_idP,UE_id)) < RRC_CONNECTED) continue; + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer++; + // check threshold + if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 200) { + // inform RRC of failure and clear timer + LOG_I(MAC, + "UE %d rnti %x: UL Failure after repeated PDCCH orders: Triggering RRC \n", + UE_id, rnti); + mac_eNB_rrc_ul_failure(module_idP, CC_id, frameP, subframeP, + rnti); + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; + UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 1; + } + } // ul_failure_timer>0 - AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n",UE_id); - - if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig) { - if ((cqi_ReportPeriodic = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic)!=NULL && - (cqi_ReportPeriodic->present!=CQI_ReportPeriodic_PR_release)) { - //Rel8 Periodic CQI/PMI/RI reporting - - get_csi_params(cc,cqi_ReportPeriodic,&Npd,&N_OFFSET_CQI,&H); - - if ((((frameP*10)+subframeP)%Npd) == N_OFFSET_CQI) { // CQI opportunity - UE_list->UE_sched_ctrl[UE_id].feedback_cnt[CC_id]=(((frameP*10)+subframeP)/Npd)%H; - // Program CQI - nfapi_ul_config_request_pdu_t* ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; - memset((void*)ul_config_pdu,0,sizeof(nfapi_ul_config_request_pdu_t)); - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; - ul_config_pdu->pdu_size = 2+(uint8_t)(2+sizeof(nfapi_ul_config_uci_cqi_pdu)); - ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; - ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.pucch_index = cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex; - ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = get_rel8_dl_cqi_pmi_size(&UE_list->UE_sched_ctrl[UE_id], - CC_id, - cc, - get_tmode(module_idP,CC_id,UE_id), - cqi_ReportPeriodic); - ul_req->number_of_pdus++; - -#if defined(Rel10) || defined(Rel14) - // PUT rel10-13 UCI options here -#endif - } - else if ((cqi_ReportPeriodic->choice.setup.ri_ConfigIndex) && - ((((frameP*10)+subframeP)%((H*Npd)<<(*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex/161)))== - N_OFFSET_CQI + (*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex%161))) { // RI opportunity - // Program RI - nfapi_ul_config_request_pdu_t* ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; - memset((void*)ul_config_pdu,0,sizeof(nfapi_ul_config_request_pdu_t)); - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; - ul_config_pdu->pdu_size = 2+(uint8_t)(2+sizeof(nfapi_ul_config_uci_cqi_pdu)); - ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; - ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.pucch_index = cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex; - ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = (cc->p_eNB==2)?1:2; - RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP<<4)+subframeP; - ul_req->number_of_pdus++; - } - - } // if ((cqi_ReportPeriodic = cqi_ReportConfig->cqi_ReportPeriodic)!=NULL) { - } // if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig) - } // for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { - } // for (CC_id=0; CC_idUE_list; - nfapi_ul_config_request_body_t *ul_req; - int CC_id; - int UE_id; - SchedulingRequestConfig_t *SRconfig; - int skip_ue; - int is_harq; - nfapi_ul_config_sr_information sr; - int i; + nfapi_dl_config_request_t *DL_req = &eNB->DL_req[0]; + nfapi_ul_config_request_t *UL_req = &eNB->UL_req[0]; + nfapi_hi_dci0_request_t *HI_DCI0_req = &eNB->HI_DCI0_req[0]; + nfapi_tx_request_t *TX_req = &eNB->TX_req[0]; - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; - for (UE_id = 0; UE_idUE_list.active[UE_id]!=TRUE) continue; + eNB->pdu_index[CC_idP] = 0; + DL_req[CC_idP].dl_config_request_body.number_pdcch_ofdm_symbols = 1; + DL_req[CC_idP].dl_config_request_body.number_dci = 0; + DL_req[CC_idP].dl_config_request_body.number_pdu = 0; + DL_req[CC_idP].dl_config_request_body.number_pdsch_rnti = 0; + DL_req[CC_idP].dl_config_request_body.transmission_power_pcfich = 6000; - ul_req = &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body; + HI_DCI0_req[CC_idP].hi_dci0_request_body.sfnsf = + subframeP + (frameP << 4); + HI_DCI0_req[CC_idP].hi_dci0_request_body.number_of_dci = 0; - AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n",UE_id); - // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet - if (mac_eNB_get_rrc_status(module_idP,UE_RNTI(module_idP,UE_id)) < RRC_CONNECTED) continue; + UL_req[CC_idP].ul_config_request_body.number_of_pdus = 0; + UL_req[CC_idP].ul_config_request_body.rach_prach_frequency_resources = 0; // ignored, handled by PHY for now + UL_req[CC_idP].ul_config_request_body.srs_present = 0; // ignored, handled by PHY for now - if ((SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig)!=NULL) { - if (SRconfig->present == SchedulingRequestConfig_PR_setup) { - if (SRconfig->choice.setup.sr_ConfigIndex <= 4) { // 5 ms SR period - if ((subframeP%5) != SRconfig->choice.setup.sr_ConfigIndex) - continue; - } else if (SRconfig->choice.setup.sr_ConfigIndex <= 14) { // 10 ms SR period - if (subframeP!=(SRconfig->choice.setup.sr_ConfigIndex-5)) - continue; - } else if (SRconfig->choice.setup.sr_ConfigIndex <= 34) { // 20 ms SR period - if ((10*(frameP&1)+subframeP) != (SRconfig->choice.setup.sr_ConfigIndex-15)) - continue; - } else if (SRconfig->choice.setup.sr_ConfigIndex <= 74) { // 40 ms SR period - if ((10*(frameP&3)+subframeP) != (SRconfig->choice.setup.sr_ConfigIndex-35)) - continue; - } else if (SRconfig->choice.setup.sr_ConfigIndex <= 154) { // 80 ms SR period - if ((10*(frameP&7)+subframeP) != (SRconfig->choice.setup.sr_ConfigIndex-75)) - continue; - } - } // SRconfig->present == SchedulingRequestConfig_PR_setup) - } // SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig)!=NULL) - // if we get here there is some PUCCH1 reception to schedule for SR + TX_req[CC_idP].tx_request_body.number_of_pdus = 0; - skip_ue=0; - is_harq = 0; - // check that there is no existing UL grant for ULSCH which overrides the SR - for (i = 0; i < ul_req->number_of_pdus; i++) { - if (((ul_req->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE)|| - (ul_req->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE)|| - (ul_req->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE)|| - (ul_req->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE))&& - (ul_req->ul_config_pdu_list[i].ulsch_pdu.ulsch_pdu_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) { - skip_ue=1; - break; - } - /* if there is already an HARQ pdu, convert to SR_HARQ */ - else if ((ul_req->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE)&& - (ul_req->ul_config_pdu_list[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) { - is_harq = 1; - break; - } - } - // drop the allocation because ULSCH with handle it with BSR - if (skip_ue==1) continue; - - LOG_D(MAC,"Frame %d, Subframe %d : Scheduling SR for UE %d/%x\n",frameP,subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].rnti); - - // check Rel10 or Rel8 SR -#if defined(Rel10) || defined(Rel14) - if ((UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2) && - (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020)&& - (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020)) { - sr.sr_information_rel10.number_of_pucch_resources = 1; - sr.sr_information_rel10.pucch_index_p1 = *UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020->sr_PUCCH_ResourceIndexP1_r10; - } else -#endif - { - sr.sr_information_rel8.pucch_index = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig->choice.setup.sr_PUCCH_ResourceIndex; - } - - /* if there is already an HARQ pdu, convert to SR_HARQ */ - if (is_harq) { - nfapi_ul_config_harq_information h = ul_req->ul_config_pdu_list[i].uci_harq_pdu.harq_information; - ul_req->ul_config_pdu_list[i].pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; - ul_req->ul_config_pdu_list[i].uci_sr_harq_pdu.sr_information = sr; - ul_req->ul_config_pdu_list[i].uci_sr_harq_pdu.harq_information = h; - } else { - ul_req->ul_config_pdu_list[ul_req->number_of_pdus].pdu_type = NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE; - ul_req->ul_config_pdu_list[ul_req->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; - ul_req->ul_config_pdu_list[ul_req->number_of_pdus].uci_sr_pdu.sr_information = sr; - ul_req->number_of_pdus++; - } /* if (is_harq) */ - } // for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) - } // for (CC_id=0; CC_idUE_list; - nfapi_dl_config_request_t *DL_req = &RC.mac[module_idP]->DL_req[0]; - uint16_t rnti = UE_RNTI(module_idP,UE_id); - COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; + int CC_id; + eNB_MAC_INST *eNB; + nfapi_ul_config_request_body_t *ul_req_tmp; + nfapi_ul_config_request_body_t *ul_req; - // check uplink failure - if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer>0)&& - (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync==0)) { - LOG_I(MAC,"UE %d rnti %x: UL Failure timer %d \n",UE_id,rnti,UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); - if (UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent==0) { - UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent=1; + eNB = RC.mac[module_idP]; - // add a format 1A dci for this UE to request an RA procedure (only one UE per subframe) - nfapi_dl_config_request_pdu_t* dl_config_pdu = &DL_req[CC_id].dl_config_request_body.dl_config_pdu_list[DL_req[CC_id].dl_config_request_body.number_pdu]; - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu)); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP,CC_id),UE_list->UE_sched_ctrl[UE_id].dl_cqi[CC_id],format1A); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + + ul_req_tmp = + &eNB->UL_req_tmp[CC_id][subframeP].ul_config_request_body; + ul_req = &eNB->UL_req[CC_id].ul_config_request_body; + + eNB->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; + ul_req->number_of_pdus = ul_req_tmp->number_of_pdus; + ul_req_tmp->number_of_pdus = 0; + + memcpy((void *) ul_req->ul_config_pdu_list, + (void *) ul_req_tmp->ul_config_pdu_list, + ul_req->number_of_pdus * + sizeof(nfapi_ul_config_request_pdu_t)); - AssertFatal((cc[CC_id].mib->message.dl_Bandwidth >=0) && (cc[CC_id].mib->message.dl_Bandwidth<6), - "illegal dl_Bandwidth %d\n",(int)cc[CC_id].mib->message.dl_Bandwidth); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = pdcch_order_table[cc[CC_id].mib->message.dl_Bandwidth]; - DL_req[CC_id].dl_config_request_body.number_dci++; - DL_req[CC_id].dl_config_request_body.number_pdu++; - LOG_I(MAC,"UE %d rnti %x: sending PDCCH order for RAPROC (failure timer %d), resource_block_coding %d \n",UE_id,rnti,UE_list->UE_sched_ctrl[UE_id].ul_failure_timer,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding); } - else { // ra_pdcch_sent==1 - LOG_I(MAC,"UE %d rnti %x: sent PDCCH order for RAPROC waiting (failure timer %d) \n",UE_id,rnti,UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); - if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer % 40) == 0) - UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent=0; // resend every 4 frames - } - - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer++; - // check threshold - if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 200) { - // inform RRC of failure and clear timer - LOG_I(MAC,"UE %d rnti %x: UL Failure after repeated PDCCH orders: Triggering RRC \n",UE_id,rnti); - mac_eNB_rrc_ul_failure(module_idP,CC_id,frameP,subframeP,rnti); - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer=0; - UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync=1; - } - } // ul_failure_timer>0 - } -void clear_nfapi_information(eNB_MAC_INST *eNB,int CC_idP,frame_t frameP,sub_frame_t subframeP) -{ - nfapi_dl_config_request_t *DL_req = &eNB->DL_req[0]; - nfapi_ul_config_request_t *UL_req = &eNB->UL_req[0]; - nfapi_hi_dci0_request_t *HI_DCI0_req = &eNB->HI_DCI0_req[0]; - nfapi_tx_request_t *TX_req = &eNB->TX_req[0]; - - - eNB->pdu_index[CC_idP] = 0; - DL_req[CC_idP].dl_config_request_body.number_pdcch_ofdm_symbols = 1; - DL_req[CC_idP].dl_config_request_body.number_dci = 0; - DL_req[CC_idP].dl_config_request_body.number_pdu = 0; - DL_req[CC_idP].dl_config_request_body.number_pdsch_rnti = 0; - DL_req[CC_idP].dl_config_request_body.transmission_power_pcfich = 6000; - - HI_DCI0_req[CC_idP].hi_dci0_request_body.sfnsf = subframeP + (frameP<<4); - HI_DCI0_req[CC_idP].hi_dci0_request_body.number_of_dci = 0; - - - UL_req[CC_idP].ul_config_request_body.number_of_pdus = 0; - UL_req[CC_idP].ul_config_request_body.rach_prach_frequency_resources = 0; // ignored, handled by PHY for now - UL_req[CC_idP].ul_config_request_body.srs_present = 0; // ignored, handled by PHY for now - - - TX_req[CC_idP].tx_request_body.number_of_pdus = 0; - - -} - -void copy_ulreq(module_id_t module_idP,frame_t frameP, sub_frame_t subframeP) -{ - int CC_id; - eNB_MAC_INST *eNB; - nfapi_ul_config_request_body_t *ul_req_tmp; - nfapi_ul_config_request_body_t *ul_req; - - eNB = RC.mac[module_idP]; - - for (CC_id=0;CC_idUL_req_tmp[CC_id][subframeP].ul_config_request_body; - ul_req = &eNB->UL_req[CC_id].ul_config_request_body; - - eNB->UL_req[CC_id].sfn_sf = (frameP<<4) + subframeP; - ul_req->number_of_pdus = ul_req_tmp->number_of_pdus; - ul_req_tmp->number_of_pdus = 0; - - memcpy((void*)ul_req->ul_config_pdu_list, - (void*)ul_req_tmp->ul_config_pdu_list, - ul_req->number_of_pdus*sizeof(nfapi_ul_config_request_pdu_t)); - - } -} - -void eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) +void +eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, + sub_frame_t subframeP) { - int mbsfn_status[MAX_NUM_CCs]; - protocol_ctxt_t ctxt; + int mbsfn_status[MAX_NUM_CCs]; + protocol_ctxt_t ctxt; - int CC_id,i; //,next_i; - UE_list_t *UE_list=&RC.mac[module_idP]->UE_list; - rnti_t rnti; + int CC_id, i; //,next_i; + UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; + rnti_t rnti; - COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; + COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; #if defined(FLEXRAN_AGENT_SB_IF) - Protocol__FlexranMessage *msg; + Protocol__FlexranMessage *msg; #endif - start_meas(&RC.mac[module_idP]->eNB_scheduler); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_IN); + start_meas(&RC.mac[module_idP]->eNB_scheduler); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, + VCD_FUNCTION_IN); - for (CC_id=0; CC_idframe = frameP; - RC.mac[module_idP]->subframe = subframeP; + RC.mac[module_idP]->frame = frameP; + RC.mac[module_idP]->subframe = subframeP; - clear_nfapi_information(RC.mac[module_idP],CC_id,frameP,subframeP); - } - - // refresh UE list based on UEs dropped by PHY in previous subframe - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i] != TRUE) continue; - - rnti = UE_RNTI(module_idP, i); - CC_id = UE_PCCID(module_idP, i); - - if ((frameP==0)&&(subframeP==0)) { - LOG_I(MAC,"UE rnti %x : %s, PHR %d dB DL CQI %d PUSCH SNR %d PUCCH SNR %d\n", rnti, - UE_list->UE_sched_ctrl[i].ul_out_of_sync==0 ? "in synch" : "out of sync", - UE_list->UE_template[CC_id][i].phr_info, - UE_list->UE_sched_ctrl[i].dl_cqi[CC_id], - (UE_list->UE_sched_ctrl[i].pusch_snr[CC_id]-128)/2, - (UE_list->UE_sched_ctrl[i].pucch1_snr[CC_id]-128)/2); + clear_nfapi_information(RC.mac[module_idP], CC_id, frameP, + subframeP); } - RC.eNB[module_idP][CC_id]->pusch_stats_bsr[i][(frameP*10)+subframeP]=-63; - if (i==UE_list->head) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR,RC.eNB[module_idP][CC_id]->pusch_stats_bsr[i][(frameP*10)+subframeP]); - // increment this, it is cleared when we receive an sdu - RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ul_inactivity_timer++; + // refresh UE list based on UEs dropped by PHY in previous subframe + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (UE_list->active[i] != TRUE) + continue; - RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer++; - LOG_D(MAC,"UE %d/%x : ul_inactivity %d, cqi_req %d\n",i,rnti, - RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ul_inactivity_timer, - RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer); - check_ul_failure(module_idP,CC_id,i,frameP,subframeP); + rnti = UE_RNTI(module_idP, i); + CC_id = UE_PCCID(module_idP, i); - } + if ((frameP == 0) && (subframeP == 0)) { + LOG_I(MAC, + "UE rnti %x : %s, PHR %d dB DL CQI %d PUSCH SNR %d PUCCH SNR %d\n", + rnti, + UE_list->UE_sched_ctrl[i].ul_out_of_sync == + 0 ? "in synch" : "out of sync", + UE_list->UE_template[CC_id][i].phr_info, + UE_list->UE_sched_ctrl[i].dl_cqi[CC_id], + (UE_list->UE_sched_ctrl[i].pusch_snr[CC_id] - 128) / 2, + (UE_list->UE_sched_ctrl[i].pucch1_snr[CC_id] - 128) / 2); + } - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, subframeP,module_idP); - pdcp_run(&ctxt); + RC.eNB[module_idP][CC_id]->pusch_stats_bsr[i][(frameP * 10) + + subframeP] = -63; + if (i == UE_list->head) + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME + (VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR, + RC.eNB[module_idP][CC_id]-> + pusch_stats_bsr[i][(frameP * 10) + subframeP]); + // increment this, it is cleared when we receive an sdu + RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ul_inactivity_timer++; - rrc_rx_tx(&ctxt, - 0, // eNB index, unused in eNB - CC_id); + RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer++; + LOG_D(MAC, "UE %d/%x : ul_inactivity %d, cqi_req %d\n", i, rnti, + RC.mac[module_idP]->UE_list.UE_sched_ctrl[i]. + ul_inactivity_timer, + RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer); + check_ul_failure(module_idP, CC_id, i, frameP, subframeP); + + } + + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, + NOT_A_RNTI, frameP, subframeP, + module_idP); + pdcp_run(&ctxt); + + rrc_rx_tx(&ctxt, 0, // eNB index, unused in eNB + CC_id); #if defined(Rel10) || defined(Rel14) - for (CC_id=0; CC_id0) { - start_meas(&RC.mac[module_idP]->schedule_mch); - mbsfn_status[CC_id] = schedule_MBMS(module_idP,CC_id,frameP,subframeP); - stop_meas(&RC.mac[module_idP]->schedule_mch); + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + if (cc[CC_id].MBMS_flag > 0) { + start_meas(&RC.mac[module_idP]->schedule_mch); + mbsfn_status[CC_id] = + schedule_MBMS(module_idP, CC_id, frameP, subframeP); + stop_meas(&RC.mac[module_idP]->schedule_mch); + } } - } #endif - // This schedules MIB - if ((subframeP==0) && (frameP&3) == 0) schedule_mib(module_idP,frameP,subframeP); - // This schedules SI for legacy LTE and eMTC starting in subframeP - schedule_SI(module_idP,frameP,subframeP); - // This schedules Random-Access for legacy LTE and eMTC starting in subframeP - schedule_RA(module_idP,frameP,subframeP); - // copy previously scheduled UL resources (ULSCH + HARQ) - copy_ulreq(module_idP,frameP,subframeP); - // This schedules SRS in subframeP - schedule_SRS(module_idP,frameP,subframeP); - // This schedules ULSCH in subframeP (dci0) - schedule_ulsch(module_idP,frameP,subframeP); - // This schedules UCI_SR in subframeP - schedule_SR(module_idP,frameP,subframeP); - // This schedules UCI_CSI in subframeP - schedule_CSI(module_idP, frameP, subframeP); + // This schedules MIB + if ((subframeP == 0) && (frameP & 3) == 0) + schedule_mib(module_idP, frameP, subframeP); + // This schedules SI for legacy LTE and eMTC starting in subframeP + schedule_SI(module_idP, frameP, subframeP); + // This schedules Random-Access for legacy LTE and eMTC starting in subframeP + schedule_RA(module_idP, frameP, subframeP); + // copy previously scheduled UL resources (ULSCH + HARQ) + copy_ulreq(module_idP, frameP, subframeP); + // This schedules SRS in subframeP + schedule_SRS(module_idP, frameP, subframeP); + // This schedules ULSCH in subframeP (dci0) + schedule_ulsch(module_idP, frameP, subframeP); + // This schedules UCI_SR in subframeP + schedule_SR(module_idP, frameP, subframeP); + // This schedules UCI_CSI in subframeP + schedule_CSI(module_idP, frameP, subframeP); - // This schedules DLSCH in subframeP - schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); + // This schedules DLSCH in subframeP + schedule_ue_spec(module_idP, frameP, subframeP, mbsfn_status); - // Allocate CCEs for good after scheduling is done + // Allocate CCEs for good after scheduling is done - for (CC_id=0;CC_ideNB_scheduler); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_OUT); + stop_meas(&RC.mac[module_idP]->eNB_scheduler); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, + VCD_FUNCTION_OUT); } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c index c6df031876..939f35f2eb 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c @@ -29,6 +29,9 @@ */ +/* indented with: indent -kr eNB_scheduler_RA.c */ + + #include "assertions.h" #include "platform_types.h" #include "PHY/defs.h" @@ -55,1240 +58,1578 @@ #include "pdcp.h" #if defined(ENABLE_ITTI) -# include "intertask_interface.h" +#include "intertask_interface.h" #endif -#include "SIMULATION/TOOLS/defs.h" // for taus +#include "SIMULATION/TOOLS/defs.h" // for taus #include "T.h" -void add_msg3(module_id_t module_idP,int CC_id, RA_TEMPLATE *RA_template, frame_t frameP, sub_frame_t subframeP) { +void +add_msg3(module_id_t module_idP, int CC_id, RA_t * ra, frame_t frameP, + sub_frame_t subframeP) +{ + eNB_MAC_INST *mac = RC.mac[module_idP]; + COMMON_channels_t *cc = &mac->common_channels[CC_id]; + uint8_t j; + nfapi_ul_config_request_t *ul_req; + nfapi_ul_config_request_pdu_t *ul_config_pdu; + nfapi_ul_config_request_body_t *ul_req_body; + nfapi_hi_dci0_request_body_t *hi_dci0_req; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = &eNB->common_channels[CC_id]; - uint8_t j; - nfapi_ul_config_request_t *ul_req; - nfapi_ul_config_request_pdu_t *ul_config_pdu; - nfapi_ul_config_request_body_t *ul_req_body; - nfapi_hi_dci0_request_body_t *hi_dci0_req; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu; - - uint8_t rvseq[4] = {0,2,3,1}; + uint8_t rvseq[4] = { 0, 2, 3, 1 }; - hi_dci0_req = &eNB->HI_DCI0_req[CC_id].hi_dci0_request_body; - ul_req = &eNB->UL_req_tmp[CC_id][RA_template->Msg3_subframe]; - ul_req_body = &ul_req->ul_config_request_body; - AssertFatal(RA_template->RA_active == TRUE,"RA is not active for RA %X\n",RA_template->rnti); + hi_dci0_req = &mac->HI_DCI0_req[CC_id].hi_dci0_request_body; + ul_req = &mac->UL_req_tmp[CC_id][ra->Msg3_subframe]; + ul_req_body = &ul_req->ul_config_request_body; + AssertFatal(ra->state != IDLE, "RA is not active for RA %X\n", + ra->rnti); #ifdef Rel14 - if (RA_template->rach_resource_type>0) { - LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d : CC_id %d CE level %d is active, Msg3 in (%d,%d)\n", - module_idP,frameP,subframeP,CC_id,RA_template->rach_resource_type-1, - RA_template->Msg3_frame,RA_template->Msg3_subframe); - LOG_D(MAC,"Frame %d, Subframe %d Adding Msg3 UL Config Request for (%d,%d) : (%d,%d)\n", - frameP,subframeP,RA_template->Msg3_frame,RA_template->Msg3_subframe,RA_template->msg3_nb_rb,RA_template->msg3_round); + if (ra->rach_resource_type > 0) { + LOG_D(MAC, + "[eNB %d][RAPROC] Frame %d, Subframe %d : CC_id %d CE level %d is active, Msg3 in (%d,%d)\n", + module_idP, frameP, subframeP, CC_id, + ra->rach_resource_type - 1, ra->Msg3_frame, + ra->Msg3_subframe); + LOG_D(MAC, + "Frame %d, Subframe %d Adding Msg3 UL Config Request for (%d,%d) : (%d,%d)\n", + frameP, subframeP, ra->Msg3_frame, ra->Msg3_subframe, + ra->msg3_nb_rb, ra->msg3_round); - ul_config_pdu = &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus]; - - memset((void*)ul_config_pdu,0,sizeof(nfapi_ul_config_request_pdu_t)); - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; - ul_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_ul_config_ulsch_pdu)); - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = eNB->ul_handle++; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = RA_template->rnti; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = narrowband_to_first_rb(cc,RA_template->msg34_narrowband)+RA_template->msg3_first_rb; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = RA_template->msg3_nb_rb; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 2; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_enabled_flag = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = rvseq[RA_template->msg3_round]; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = ((10*RA_template->Msg3_frame)+RA_template->Msg3_subframe)&7; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = 1; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = get_TBS_UL(RA_template->msg3_mcs, - RA_template->msg3_nb_rb); - // Re13 fields - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.ue_type = RA_template->rach_resource_type>2 ? 2 : 1; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.total_number_of_repetitions = 1; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.repetition_number = 1; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.initial_transmission_sf_io = (RA_template->Msg3_frame*10)+RA_template->Msg3_subframe; - ul_req_body->number_of_pdus++; - } // if (RA_template->rach_resource_type>0) { - else -#endif - { - LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d : CC_id %d RA is active, Msg3 in (%d,%d)\n", - module_idP,frameP,subframeP,CC_id,RA_template->Msg3_frame,RA_template->Msg3_subframe); - - LOG_D(MAC,"Frame %d, Subframe %d Adding Msg3 UL Config Request for (%d,%d) : (%d,%d,%d)\n", - frameP,subframeP,RA_template->Msg3_frame,RA_template->Msg3_subframe, - RA_template->msg3_nb_rb,RA_template->msg3_first_rb,RA_template->msg3_round); - - ul_config_pdu = &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus]; - - memset((void*)ul_config_pdu,0,sizeof(nfapi_ul_config_request_pdu_t)); - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; - ul_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_ul_config_ulsch_pdu)); - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = eNB->ul_handle++; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = RA_template->rnti; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = RA_template->msg3_first_rb; - AssertFatal(RA_template->msg3_nb_rb > 0, "nb_rb = 0\n"); - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = RA_template->msg3_nb_rb; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 2; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_enabled_flag = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = rvseq[RA_template->msg3_round]; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = subframe2harqpid(cc,RA_template->Msg3_frame,RA_template->Msg3_subframe); - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = 1; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = get_TBS_UL(10,RA_template->msg3_nb_rb); - ul_req_body->number_of_pdus++; - // save UL scheduling information for preprocessor - for (j=0;jmsg3_nb_rb;j++) cc->vrb_map_UL[RA_template->msg3_first_rb+j]=1; - - - if (RA_template->msg3_round != 0) { // program HI too - hi_dci0_pdu = &hi_dci0_req->hi_dci0_pdu_list[hi_dci0_req->number_of_dci+hi_dci0_req->number_of_hi]; - memset((void*)hi_dci0_pdu,0,sizeof(nfapi_hi_dci0_request_pdu_t)); - hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; - hi_dci0_pdu->pdu_size = 2+sizeof(nfapi_hi_dci0_hi_pdu); - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = RA_template->msg3_first_rb; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = 0; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 0; - hi_dci0_req->number_of_hi++; - // save UL scheduling information for preprocessor - for (j=0;jmsg3_nb_rb;j++) cc->vrb_map_UL[RA_template->msg3_first_rb+j]=1; - - LOG_D(MAC,"[eNB %d][PUSCH-RA %x] CC_id %d Frame %d subframeP %d Scheduled (PHICH) RA (mcs %d, first rb %d, nb_rb %d,round %d)\n", - module_idP,RA_template->rnti,CC_id,frameP,subframeP,10, - 1,1, - RA_template->msg3_round-1); - } // if (RA_template->msg3_round != 0) { // program HI too - } // non-BL/CE UE case -} + ul_config_pdu = + &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus]; -void generate_Msg2(module_id_t module_idP,int CC_idP,frame_t frameP,sub_frame_t subframeP,RA_TEMPLATE *RA_template) { - - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = eNB->common_channels; - - uint8_t *vrb_map; - int first_rb; - int N_RB_DL; - nfapi_dl_config_request_pdu_t *dl_config_pdu; - nfapi_tx_request_pdu_t *TX_req; - nfapi_dl_config_request_body_t *dl_req; - - vrb_map = cc[CC_idP].vrb_map; - dl_req = &eNB->DL_req[CC_idP].dl_config_request_body; - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - N_RB_DL = to_prb(cc[CC_idP].mib->message.dl_Bandwidth); - -#ifdef Rel14 - int rmax = 0; - int rep = 0; - int reps = 0; - int num_nb = 0; - - first_rb = 0; - struct PRACH_ConfigSIB_v1310 *ext4_prach; - PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13; - PRACH_ParametersCE_r13_t *p[4]={NULL,NULL,NULL,NULL}; - - uint16_t absSF = (10*frameP)+subframeP; - uint16_t absSF_Msg2 = (10*RA_template->Msg2_frame)+RA_template->Msg2_subframe; - - if (absSF>absSF_Msg2) return; // we're not ready yet, need to be to start == - - if (cc[CC_idP].radioResourceConfigCommon_BR) { - - ext4_prach = cc[CC_idP].radioResourceConfigCommon_BR->ext4->prach_ConfigCommon_v1310; - prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13; - - switch (prach_ParametersListCE_r13->list.count) { - case 4: - p[3]=prach_ParametersListCE_r13->list.array[3]; - case 3: - p[2]=prach_ParametersListCE_r13->list.array[2]; - case 2: - p[1]=prach_ParametersListCE_r13->list.array[1]; - case 1: - p[0]=prach_ParametersListCE_r13->list.array[0]; - break; - default: - AssertFatal(1==0,"Illegal count for prach_ParametersListCE_r13 %d\n",(int)prach_ParametersListCE_r13->list.count); - break; - } - } - - if (RA_template->rach_resource_type > 0) { - - // This uses an MPDCCH Type 2 common allocation according to Section 9.1.5 36-213 - // Parameters: - // p=2+4 PRB set (number of PRB pairs 3) - // rmax = mpdcch-NumRepetition-RA-r13 => Table 9.1.5-3 - // if CELevel = 0,1 => Table 9.1.5-1b for MPDCCH candidates - // if CELevel = 2,3 => Table 9.1.5-2b for MPDCCH candidates - // distributed transmission - - // rmax from SIB2 information - AssertFatal(rmax<9,"rmax>8!\n"); - rmax = 1<rach_resource_type-1]->mpdcch_NumRepetition_RA_r13; - // choose r1 by default for RAR (Table 9.1.5-5) - rep = 0; - // get actual repetition count from Table 9.1.5-3 - reps = (rmax<=8)?(1<>(3-rep)); - // get narrowband according to higher-layer config - num_nb = p[RA_template->rach_resource_type-1]->mpdcch_NarrowbandsToMonitor_r13.list.count; - RA_template->msg2_narrowband = *p[RA_template->rach_resource_type-1]->mpdcch_NarrowbandsToMonitor_r13.list.array[RA_template->preamble_index%num_nb]; - first_rb = narrowband_to_first_rb(&cc[CC_idP],RA_template->msg2_narrowband); - - if ((RA_template->msg2_mpdcch_repetition_cnt == 0) && - (mpdcch_sf_condition(eNB,CC_idP,frameP,subframeP,rmax,TYPE2,-1)>0)){ - // MPDCCH configuration for RAR - LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d : In generate_Msg2, Programming MPDCCH %d repetitions\n", - module_idP,frameP,subframeP,reps); - - - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_mpdcch_pdu)); - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = (RA_template->rach_resource_type > 1) ? 11 : 10; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = RA_template->msg2_narrowband; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_prb_pairs = 6; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment = 0; // Note: this can be dynamic - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_tansmission_type = 1; // imposed (9.1.5 in 213) for Type 2 Common search space - AssertFatal(cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13!=NULL, - "cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n"); - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol = cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ecce_index = 0; // Note: this should be dynamic - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level = 16; // OK for CEModeA r1-3 (9.1.5-1b) or CEModeB r1-4 - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti_type = 2; // RA-RNTI - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti = RA_template->RA_rnti; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = (RA_template->rach_resource_type < 3) ? 1 : 2; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.drms_scrambling_init = cc[CC_idP].physCellId; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.initial_transmission_sf_io = (frameP*10)+subframeP; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.transmission_power = 6000; // 0dB - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding = getRIV(6,0,6); // Note: still to be checked if it should not be (getRIV(N_RB_DL,first_rb,6)) : Check nFAPI specifications and what is done L1 with this parameter - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mcs = 4; // adjust according to size of RAR, 208 bits with N1A_PRB=3 - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels = 4; // fix to 4 for now - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_resource_offset = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_subframe_repetition_number = rep; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpc = 1;// N1A_PRB=3 (36.212); => 208 bits for mcs=4, choose mcs according t message size TBD - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index_length = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.allocate_prach_flag = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.preamble_index = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.srs_request = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.frequency_hopping_enabled_flag = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding = 0; // this is not needed by OAI L1, but should be filled in - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_tx_antenna_ports = 1; - RA_template->msg2_mpdcch_repetition_cnt++; - dl_req->number_pdu++; - RA_template->Msg2_subframe = (RA_template->Msg2_subframe+9)%10; - - } //repetition_count==0 && SF condition met - if (RA_template->msg2_mpdcch_repetition_cnt>0) { // we're in a stream of repetitions - LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d : In generate_Msg2, MPDCCH repetition %d\n", - module_idP,frameP,subframeP,RA_template->msg2_mpdcch_repetition_cnt); - - if (RA_template->msg2_mpdcch_repetition_cnt==reps) { // this is the last mpdcch repetition - if (cc[CC_idP].tdd_Config==NULL) { // FDD case - // wait 2 subframes for PDSCH transmission - if (subframeP>7) RA_template->Msg2_frame = (frameP+1)&1023; - else RA_template->Msg2_frame = frameP; - RA_template->Msg2_subframe = (subframeP+2)%10; // +2 is the "n+x" from Section 7.1.11 in 36.213 - } - else { - AssertFatal(1==0,"TDD case not done yet\n"); - } - }// mpdcch_repetition_count == reps - RA_template->msg2_mpdcch_repetition_cnt++; - - if ((RA_template->Msg2_frame == frameP) && (RA_template->Msg2_subframe == subframeP)) { - // Program PDSCH - LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d : In generate_Msg2, Programming PDSCH\n", - module_idP,frameP,subframeP); - RA_template->generate_rar = 0; - - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu)); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_idP]; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = RA_template->RA_rnti; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL,first_rb,6); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1;// first block - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB==1 ) ? 0 : 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB==1 ) ? 1 : 2; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; - - // Rel10 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; - // Rel13 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = (RA_template->rach_resource_type < 3) ? 1 : 2;; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not SI message - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = (10*frameP)+subframeP; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = 0; - dl_req->number_pdu++; - - // Program UL processing for Msg3, same as regular LTE - get_Msg3alloc(&cc[CC_idP],subframeP,frameP,&RA_template->Msg3_frame,&RA_template->Msg3_subframe); - add_msg3(module_idP,CC_idP, RA_template,frameP,subframeP); - fill_rar_br(eNB,CC_idP,RA_template,frameP,subframeP,cc[CC_idP].RAR_pdu.payload,RA_template->rach_resource_type-1); - // DL request - eNB->TX_req[CC_idP].sfn_sf = (frameP<<4)+subframeP; - TX_req = &eNB->TX_req[CC_idP].tx_request_body.tx_pdu_list[eNB->TX_req[CC_idP].tx_request_body.number_of_pdus]; - TX_req->pdu_length = 7; // This should be changed if we have more than 1 preamble - TX_req->pdu_index = eNB->pdu_index[CC_idP]++; - TX_req->num_segments = 1; - TX_req->segments[0].segment_length = 7; - TX_req->segments[0].segment_data = cc[CC_idP].RAR_pdu.payload; - eNB->TX_req[CC_idP].tx_request_body.number_of_pdus++; - } - } - - } - else -#endif - { - - if ((RA_template->Msg2_frame == frameP) && (RA_template->Msg2_subframe == subframeP)) { - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d, subframeP %d: Generating RAR DCI, RA_active %d format 1A (%d,%d))\n", - module_idP, CC_idP, frameP, subframeP, - RA_template->RA_active, - - RA_template->RA_dci_fmt1, - RA_template->RA_dci_size_bits1); - - // Allocate 4 PRBS starting in RB 0 - first_rb = 0; - vrb_map[first_rb] = 1; - vrb_map[first_rb+1] = 1; - vrb_map[first_rb+2] = 1; - vrb_map[first_rb+3] = 1; - - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu)); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = 4; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = RA_template->RA_rnti; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 2; // RA-RNTI : see Table 4-10 from SCF082 - nFAPI specifications - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power - - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = 0; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // no TPC - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = 1; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = 0; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = 0; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0; - - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = getRIV(N_RB_DL,first_rb,4); - - // This checks if the above DCI allocation is feasible in current subframe - if (!CCE_allocation_infeasible(module_idP,CC_idP,0,subframeP,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,RA_template->RA_rnti)) { - LOG_D(MAC,"Frame %d: Subframe %d : Adding common DCI for RA_RNTI %x\n", - frameP,subframeP,RA_template->RA_rnti); - dl_req->number_dci++; - dl_req->number_pdu++; - - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu)); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_idP]; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = RA_template->RA_rnti; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL,first_rb,4); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1;// first block - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB==1 ) ? 0 : 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB==1 ) ? 1 : 2; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; - dl_req->number_pdu++; - - // Program UL processing for Msg3 - get_Msg3alloc(&cc[CC_idP],subframeP,frameP,&RA_template->Msg3_frame,&RA_template->Msg3_subframe); - - LOG_D(MAC,"Frame %d, Subframe %d: Setting Msg3 reception for Frame %d Subframe %d\n", - frameP,subframeP,RA_template->Msg3_frame,RA_template->Msg3_subframe); - - fill_rar(module_idP,CC_idP,frameP,cc[CC_idP].RAR_pdu.payload,N_RB_DL,7); - add_msg3(module_idP,CC_idP, RA_template,frameP,subframeP); - - // DL request - eNB->TX_req[CC_idP].sfn_sf = (frameP<<4)+subframeP; - TX_req = &eNB->TX_req[CC_idP].tx_request_body.tx_pdu_list[eNB->TX_req[CC_idP].tx_request_body.number_of_pdus]; - TX_req->pdu_length = 7; // This should be changed if we have more than 1 preamble - TX_req->pdu_index = eNB->pdu_index[CC_idP]++; - TX_req->num_segments = 1; - TX_req->segments[0].segment_length = 7; - TX_req->segments[0].segment_data = cc[CC_idP].RAR_pdu.payload; - eNB->TX_req[CC_idP].tx_request_body.number_of_pdus++; - } // PDCCH CCE allocation is feasible - } // Msg2 frame/subframe condition - } // else BL/CE -} - -void generate_Msg4(module_id_t module_idP,int CC_idP,frame_t frameP,sub_frame_t subframeP,RA_TEMPLATE *RA_template){ - - - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = eNB->common_channels; - int16_t rrc_sdu_length; - int UE_id = -1; - uint16_t msg4_padding; - uint16_t msg4_post_padding; - uint16_t msg4_header; - - uint8_t *vrb_map; - int first_rb; - int N_RB_DL; - nfapi_dl_config_request_pdu_t *dl_config_pdu; - nfapi_ul_config_request_pdu_t *ul_config_pdu; - nfapi_tx_request_pdu_t *TX_req; - UE_list_t *UE_list=&eNB->UE_list; - nfapi_dl_config_request_body_t *dl_req; - nfapi_ul_config_request_body_t *ul_req; - uint8_t lcid; - uint8_t offset; - - -#ifdef Rel14 - int rmax = 0; - int rep = 0; - int reps = 0; - - - first_rb = 0; - struct PRACH_ConfigSIB_v1310 *ext4_prach; - struct PUCCH_ConfigCommon_v1310 *ext4_pucch; - PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13; - struct N1PUCCH_AN_InfoList_r13 *pucch_N1PUCCH_AN_InfoList_r13; - PRACH_ParametersCE_r13_t *p[4]={NULL,NULL,NULL,NULL}; - int pucchreps[4]={1,1,1,1}; - int n1pucchan[4]={0,0,0,0}; - - if (cc[CC_idP].radioResourceConfigCommon_BR) { - - ext4_prach = cc[CC_idP].radioResourceConfigCommon_BR->ext4->prach_ConfigCommon_v1310; - ext4_pucch = cc[CC_idP].radioResourceConfigCommon_BR->ext4->pucch_ConfigCommon_v1310; - prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13; - pucch_N1PUCCH_AN_InfoList_r13 = ext4_pucch->n1PUCCH_AN_InfoList_r13; - AssertFatal(prach_ParametersListCE_r13!=NULL,"prach_ParametersListCE_r13 is null\n"); - AssertFatal(pucch_N1PUCCH_AN_InfoList_r13!=NULL,"pucch_N1PUCCH_AN_InfoList_r13 is null\n"); - // check to verify CE-Level compatibility in SIB2_BR - AssertFatal(prach_ParametersListCE_r13->list.count == pucch_N1PUCCH_AN_InfoList_r13->list.count, - "prach_ParametersListCE_r13->list.count!= pucch_N1PUCCH_AN_InfoList_r13->list.count\n"); - - switch (prach_ParametersListCE_r13->list.count) { - case 4: - p[3] = prach_ParametersListCE_r13->list.array[3]; - n1pucchan[3] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[3]; - AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level3_r13!=NULL,"pucch_NumRepetitionCE_Msg4_Level3 shouldn't be NULL\n"); - pucchreps[3] = (int)(4<<*ext4_pucch->pucch_NumRepetitionCE_Msg4_Level3_r13); - - case 3: - p[2] = prach_ParametersListCE_r13->list.array[2]; - n1pucchan[2] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[2]; - AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13!=NULL,"pucch_NumRepetitionCE_Msg4_Level2 shouldn't be NULL\n"); - pucchreps[2] = (int)(4<<*ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13); - case 2: - p[1] =prach_ParametersListCE_r13->list.array[1]; - n1pucchan[1] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[1]; - AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13!=NULL,"pucch_NumRepetitionCE_Msg4_Level1 shouldn't be NULL\n"); - pucchreps[1] = (int)(1<<*ext4_pucch->pucch_NumRepetitionCE_Msg4_Level1_r13); - case 1: - p[0] = prach_ParametersListCE_r13->list.array[0]; - n1pucchan[0] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[0]; - AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13!=NULL,"pucch_NumRepetitionCE_Msg4_Level0 shouldn't be NULL\n"); - pucchreps[0] = (int)(1<<*ext4_pucch->pucch_NumRepetitionCE_Msg4_Level0_r13); - default: - AssertFatal(1==0,"Illegal count for prach_ParametersListCE_r13 %d\n",prach_ParametersListCE_r13->list.count); - } - } -#endif - - vrb_map = cc[CC_idP].vrb_map; - - dl_req = &eNB->DL_req[CC_idP].dl_config_request_body; - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - N_RB_DL = to_prb(cc[CC_idP].mib->message.dl_Bandwidth); - - UE_id = find_UE_id(module_idP,RA_template->rnti); - AssertFatal(UE_id>=0,"Can't find UE for t-crnti\n"); - - // set HARQ process round to 0 for this UE - - if (cc->tdd_Config) RA_template->harq_pid = ((frameP*10)+subframeP)%10; - else RA_template->harq_pid = ((frameP*10)+subframeP)&7; - - - // Get RRCConnectionSetup for Piggyback - rrc_sdu_length = mac_rrc_data_req(module_idP, - CC_idP, - frameP, - CCCH, - 1, // 1 transport block - &cc[CC_idP].CCCH_pdu.payload[0], - ENB_FLAG_YES, - module_idP, - 0); // not used in this case - - AssertFatal(rrc_sdu_length>0, - "[MAC][eNB Scheduler] CCCH not allocated\n"); - - - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: UE_id %d, rrc_sdu_length %d\n", - module_idP, CC_idP, frameP, subframeP,UE_id, rrc_sdu_length); - - -#ifdef Rel14 - if (RA_template->rach_resource_type>0) { - - // Generate DCI + repetitions first - // This uses an MPDCCH Type 2 allocation according to Section 9.1.5 36-213, Type2 common allocation according to Table 7.1-8 (36-213) - // Parameters: - // p=2+4 PRB set (number of PRB pairs 6) - // rmax = mpdcch-NumRepetition-RA-r13 => Table 9.1.5-3 - // if CELevel = 0,1 => Table 9.1.5-1b for MPDCCH candidates - // if CELevel = 2,3 => Table 9.1.5-2b for MPDCCH candidates - // distributed transmission - - // rmax from SIB2 information - rmax = p[RA_template->rach_resource_type-1]->mpdcch_NumRepetition_RA_r13; - AssertFatal(rmax>=4,"choose rmax>=4 for enough repeititions, or reduce rep to 1 or 2\n"); - - // choose r3 by default for Msg4 (this is ok from table 9.1.5-3 for rmax = >=4, if we choose rmax <4 it has to be less - rep = 2; - // get actual repetition count from Table 9.1.5-3 - reps = (rmax<=8)?(1<>(3-rep)); - // get first narrowband - first_rb = narrowband_to_first_rb(&cc[CC_idP],RA_template->msg34_narrowband); - - if ((RA_template->msg4_mpdcch_repetition_cnt == 0) && - (mpdcch_sf_condition(eNB,CC_idP,frameP,subframeP,rmax,TYPE2,-1)>0)){ - // MPDCCH configuration for RAR - - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_mpdcch_pdu)); - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = (RA_template->rach_resource_type > 1) ? 11 : 10; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = RA_template->msg34_narrowband; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_prb_pairs = 6; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment = 0; // Note: this can be dynamic - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_tansmission_type = 1; - AssertFatal(cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13!=NULL, - "cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n"); - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol = cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ecce_index = 0; // Note: this should be dynamic - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level = 16; // OK for CEModeA r1-3 (9.1.5-1b) or CEModeB r1-4 - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti_type = 0; // t-C-RNTI - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti = RA_template->RA_rnti; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = (RA_template->rach_resource_type < 3) ? 1 : 2; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.drms_scrambling_init = cc[CC_idP].physCellId; /// Check this is still N_id_cell for type2 common - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.initial_transmission_sf_io = (frameP*10)+subframeP; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.transmission_power = 6000; // 0dB - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding = getRIV(6,0,6);// check if not getRIV(N_RB_DL,first_rb,6); - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mcs = 4; // adjust according to size of Msg4, 208 bits with N1A_PRB=3 - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels = 4; // fix to 4 for now - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process = RA_template->harq_pid; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_resource_offset = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_subframe_repetition_number = rep; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpc = 1;// N1A_PRB=3; => 208 bits - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index_length = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.allocate_prach_flag = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.preamble_index = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.srs_request = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.frequency_hopping_enabled_flag = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding = 0; // this is not needed by OAI L1, but should be filled in - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_tx_antenna_ports = 1; - RA_template->msg4_mpdcch_repetition_cnt++; - dl_req->number_pdu++; - - } //repetition_count==0 && SF condition met - else if (RA_template->msg4_mpdcch_repetition_cnt>0) { // we're in a stream of repetitions - RA_template->msg4_mpdcch_repetition_cnt++; - if (RA_template->msg4_mpdcch_repetition_cnt==reps) { // this is the last mpdcch repetition - if (cc[CC_idP].tdd_Config==NULL) { // FDD case - // wait 2 subframes for PDSCH transmission - if (subframeP>7) RA_template->Msg4_frame = (frameP+1)&1023; - else RA_template->Msg4_frame = frameP; - RA_template->Msg4_subframe = (subframeP+2)%10; - } - else { - AssertFatal(1==0,"TDD case not done yet\n"); - } - } // mpdcch_repetition_count == reps - if ((RA_template->Msg4_frame == frameP) && (RA_template->Msg4_subframe == subframeP)) { - - // Program PDSCH - - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Generating Msg4 BR with RRC Piggyback (ce_level %d RNTI %x)\n", - module_idP, CC_idP, frameP, subframeP,RA_template->rach_resource_type-1,RA_template->rnti); - - AssertFatal(1==0,"Msg4 generation not finished for BL/CE UE\n"); - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu)); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_idP]; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = RA_template->rnti; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL,first_rb,6); // check that this isn't getRIV(6,0,6) - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1;// first block - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB==1 ) ? 0 : 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB==1 ) ? 1 : 2; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; - - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; - - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = (RA_template->rach_resource_type < 3) ? 1 : 2; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not SI message - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = (10*frameP)+subframeP; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = 0; - dl_req->number_pdu++; - - RA_template->generate_Msg4=0; - RA_template->wait_ack_Msg4=1; - - lcid=0; - - UE_list->UE_sched_ctrl[UE_id].round[CC_idP][RA_template->harq_pid] = 0; - msg4_header = 1+6+1; // CR header, CR CE, SDU header - - if ((RA_template->msg4_TBsize - rrc_sdu_length - msg4_header) <= 2) { - msg4_padding = RA_template->msg4_TBsize - rrc_sdu_length - msg4_header; - msg4_post_padding = 0; - } else { - msg4_padding = 0; - msg4_post_padding = RA_template->msg4_TBsize - rrc_sdu_length - msg4_header -1; - } - - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d subframeP %d Msg4 : TBS %d, sdu_len %d, msg4_header %d, msg4_padding %d, msg4_post_padding %d\n", - module_idP,CC_idP,frameP,subframeP,RA_template->msg4_TBsize,rrc_sdu_length,msg4_header,msg4_padding,msg4_post_padding); - DevAssert( UE_id != UE_INDEX_INVALID ); // FIXME not sure how to gracefully return - // CHECK THIS: &cc[CC_idP].CCCH_pdu.payload[0] - offset = generate_dlsch_header((unsigned char*)eNB->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0], - 1, //num_sdus - (unsigned short*)&rrc_sdu_length, // - &lcid, // sdu_lcid - 255, // no drx - 31, // no timing advance - RA_template->cont_res_id, // contention res id - msg4_padding, // no padding - msg4_post_padding); - - memcpy((void*)&eNB->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0][(unsigned char)offset], - &cc[CC_idP].CCCH_pdu.payload[0], - rrc_sdu_length); - - // DL request - eNB->TX_req[CC_idP].sfn_sf = (frameP<<4)+subframeP; - TX_req = &eNB->TX_req[CC_idP].tx_request_body.tx_pdu_list[eNB->TX_req[CC_idP].tx_request_body.number_of_pdus]; - TX_req->pdu_length = rrc_sdu_length; - TX_req->pdu_index = eNB->pdu_index[CC_idP]++; - TX_req->num_segments = 1; - TX_req->segments[0].segment_length = rrc_sdu_length; - TX_req->segments[0].segment_data = eNB->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0]; - eNB->TX_req[CC_idP].tx_request_body.number_of_pdus++; - - // Program ACK/NAK for Msg4 PDSCH - int absSF = (RA_template->Msg3_frame*10)+RA_template->Msg3_subframe; - // see Section 10.2 from 36.213 - int ackNAK_absSF = absSF + reps + 4; - AssertFatal(reps>2,"Have to handle programming of ACK when PDSCH repetitions is > 2\n"); - ul_req = &eNB->UL_req_tmp[CC_idP][ackNAK_absSF%10].ul_config_request_body; - ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; - - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE; - ul_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_ul_config_uci_harq_pdu)); - ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.handle = 0; // don't know how to use this - ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti = RA_template->rnti; - ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.ue_type = (RA_template->rach_resource_type < 3) ? 1 : 2; - ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.empty_symbols = 0; - ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.total_number_of_repetitions = pucchreps[RA_template->rach_resource_type-1]; - ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.repetition_number = 0; - // Note need to keep sending this across reptitions!!!! Not really for PUCCH, to ask small-cell forum, we'll see for the other messages, maybe parameters change across repetitions and FAPI has to provide for that - if (cc[CC_idP].tdd_Config==NULL) { // FDD case - ul_config_pdu->uci_harq_pdu.harq_information.harq_information_rel8_fdd.n_pucch_1_0 = n1pucchan[RA_template->rach_resource_type-1]; - // NOTE: How to fill in the rest of the n_pucch_1_0 information 213 Section 10.1.2.1 in the general case - // = N_ECCE_q + Delta_ARO + n1pucchan[ce_level] - // higher in the MPDCCH configuration, N_ECCE_q is hard-coded to 0, and harq resource offset to 0 => - // Delta_ARO = 0 from Table 10.1.2.1-1 - ul_config_pdu->uci_harq_pdu.harq_information.harq_information_rel8_fdd.harq_size = 1; // 1-bit ACK/NAK - } - else { - AssertFatal(1==0,"PUCCH configuration for ACK/NAK not handled yet for TDD BL/CE case\n"); - } - ul_req->number_of_pdus++; - T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_idP), T_INT(RA_template->rnti), T_INT(frameP), T_INT(subframeP), - T_INT(0 /*harq_pid always 0?*/), T_BUFFER(&eNB->UE_list.DLSCH_pdu[CC_idP][0][UE_id].payload[0], RA_template->msg4_TBsize)); - - if (opt_enabled==1) { - trace_pdu(1, (uint8_t *)eNB->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0], - rrc_sdu_length, UE_id, 3, UE_RNTI(module_idP, UE_id), - eNB->frame, eNB->subframe,0,0); - LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d trace pdu for rnti %x with size %d\n", - module_idP, CC_idP, frameP, UE_RNTI(module_idP,UE_id), rrc_sdu_length); - } - } // Msg4 frame/subframe - } // msg4_mpdcch_repetition_count - } // rach_resource_type > 0 - else -#endif - { // This is normal LTE case - if ((RA_template->Msg4_frame == frameP) && (RA_template->Msg4_subframe == subframeP)) { - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Generating Msg4 with RRC Piggyback (RNTI %x)\n", - module_idP, CC_idP, frameP, subframeP,RA_template->rnti); - - /// Choose first 4 RBs for Msg4, should really check that these are free! - first_rb=0; - - vrb_map[first_rb] = 1; - vrb_map[first_rb+1] = 1; - vrb_map[first_rb+2] = 1; - vrb_map[first_rb+3] = 1; - - - // Compute MCS/TBS for 3 PRB (coded on 4 vrb) - msg4_header = 1+6+1; // CR header, CR CE, SDU header - - if ((rrc_sdu_length+msg4_header) <= 22) { - RA_template->msg4_mcs = 4; - RA_template->msg4_TBsize = 22; - } else if ((rrc_sdu_length+msg4_header) <= 28) { - RA_template->msg4_mcs = 5; - RA_template->msg4_TBsize = 28; - } else if ((rrc_sdu_length+msg4_header) <= 32) { - RA_template->msg4_mcs = 6; - RA_template->msg4_TBsize = 32; - } else if ((rrc_sdu_length+msg4_header) <= 41) { - RA_template->msg4_mcs = 7; - RA_template->msg4_TBsize = 41; - } else if ((rrc_sdu_length+msg4_header) <= 49) { - RA_template->msg4_mcs = 8; - RA_template->msg4_TBsize = 49; - } else if ((rrc_sdu_length+msg4_header) <= 57) { - RA_template->msg4_mcs = 9; - RA_template->msg4_TBsize = 57; - } - - fill_nfapi_dl_dci_1A(dl_config_pdu, - 4, // aggregation_level - RA_template->rnti, // rnti - 1, // rnti_type, CRNTI - RA_template->harq_pid, // harq_process - 1, // tpc, none - getRIV(N_RB_DL,first_rb,4), // resource_block_coding - RA_template->msg4_mcs, // mcs - 1, // ndi - 0, // rv - 0); // vrb_flag - LOG_D(MAC,"Frame %d, subframe %d: Msg4 DCI pdu_num %d (rnti %x,rnti_type %d,harq_pid %d, resource_block_coding (%p) %d\n", - frameP, - subframeP, - dl_req->number_pdu, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process, - &dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding); - AssertFatal(dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding < 8192, - "resource_block_coding %u < 8192\n", - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding); - if (!CCE_allocation_infeasible(module_idP,CC_idP,1, - subframeP,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, - RA_template->rnti)) { - dl_req->number_dci++; - dl_req->number_pdu++; - - RA_template->generate_Msg4=0; - RA_template->wait_ack_Msg4=1; - - // increment Absolute subframe by 8 for Msg4 retransmission - LOG_D(MAC,"Frame %d, Subframe %d: Preparing for Msg4 retransmission currently %d.%d\n", - frameP,subframeP,RA_template->Msg4_frame,RA_template->Msg4_subframe); - if (RA_template->Msg4_subframe > 1) RA_template->Msg4_frame++; - RA_template->Msg4_frame&=1023; - RA_template->Msg4_subframe = (RA_template->Msg4_subframe+8)%10; - LOG_D(MAC,"Frame %d, Subframe %d: Msg4 retransmission in %d.%d\n", - frameP,subframeP,RA_template->Msg4_frame,RA_template->Msg4_subframe); - lcid=0; - - // put HARQ process round to 0 - if (cc->tdd_Config) RA_template->harq_pid = ((frameP*10)+subframeP)%10; - else RA_template->harq_pid = ((frameP*10)+subframeP)&7; - UE_list->UE_sched_ctrl[UE_id].round[CC_idP][RA_template->harq_pid] = 0; - - if ((RA_template->msg4_TBsize - rrc_sdu_length - msg4_header) <= 2) { - msg4_padding = RA_template->msg4_TBsize - rrc_sdu_length - msg4_header; - msg4_post_padding = 0; - } else { - msg4_padding = 0; - msg4_post_padding = RA_template->msg4_TBsize - rrc_sdu_length - msg4_header -1; - } - - LOG_D(MAC,"[eNB %d][RAPROC] CC_idP %d Frame %d subframeP %d Msg4 : TBS %d, sdu_len %d, msg4_header %d, msg4_padding %d, msg4_post_padding %d\n", - module_idP,CC_idP,frameP,subframeP,RA_template->msg4_TBsize,rrc_sdu_length,msg4_header,msg4_padding,msg4_post_padding); - DevAssert( UE_id != UE_INDEX_INVALID ); // FIXME not sure how to gracefully return - // CHECK THIS: &cc[CC_idP].CCCH_pdu.payload[0] - offset = generate_dlsch_header((unsigned char*)eNB->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0], - 1, //num_sdus - (unsigned short*)&rrc_sdu_length, // - &lcid, // sdu_lcid - 255, // no drx - 31, // no timing advance - RA_template->cont_res_id, // contention res id - msg4_padding, // no padding - msg4_post_padding); - - memcpy((void*)&eNB->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0][(unsigned char)offset], - &cc[CC_idP].CCCH_pdu.payload[0], - rrc_sdu_length); - - // DLSCH Config - fill_nfapi_dlsch_config(eNB, - dl_req, - RA_template->msg4_TBsize, - eNB->pdu_index[CC_idP], - RA_template->rnti, - 2, // resource_allocation_type : format 1A/1B/1D - 0, // virtual_resource_block_assignment_flag : localized - getRIV(N_RB_DL,first_rb,4), // resource_block_coding : RIV, 4 PRB - 2, // modulation: QPSK - 0, // redundancy version - 1, // transport_blocks - 0, // transport_block_to_codeword_swap_flag (0) - (cc->p_eNB==1 ) ? 0 : 1, // transmission_scheme - 1, // number of layers - 1, // number of subbands - //0, // codebook index - 1, // ue_category_capacity - 4, // pa: 0 dB - 0, // delta_power_offset_index - 0, // ngap - 1, // NPRB = 3 like in DCI - (cc->p_eNB==1 ) ? 1 : 2, // transmission mode - 1, // num_bf_prb_per_subband - 1); // num_bf_vector - LOG_D(MAC,"Filled DLSCH config, pdu number %d, non-dci pdu_index %d\n",dl_req->number_pdu,eNB->pdu_index[CC_idP]); - - // DL request - eNB->TX_req[CC_idP].sfn_sf = fill_nfapi_tx_req(&eNB->TX_req[CC_idP].tx_request_body, - (frameP*10)+subframeP, - rrc_sdu_length, - eNB->pdu_index[CC_idP], - eNB->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0]); - eNB->pdu_index[CC_idP]++; - - LOG_D(MAC,"Filling UCI ACK/NAK information, cce_idx %d\n",dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx); - // Program PUCCH1a for ACK/NAK - // Program ACK/NAK for Msg4 PDSCH - fill_nfapi_uci_acknak(module_idP, - CC_idP, - RA_template->rnti, - (frameP*10)+subframeP, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx); - - - T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_idP), T_INT(RA_template->rnti), T_INT(frameP), T_INT(subframeP), - T_INT(0 /*harq_pid always 0?*/), T_BUFFER(&eNB->UE_list.DLSCH_pdu[CC_idP][0][UE_id].payload[0], RA_template->msg4_TBsize)); - - if (opt_enabled==1) { - trace_pdu(1, (uint8_t *)eNB->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0], - rrc_sdu_length, UE_id, 3, UE_RNTI(module_idP, UE_id), - eNB->frame, eNB->subframe,0,0); - LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d trace pdu for rnti %x with size %d\n", - module_idP, CC_idP, frameP, UE_RNTI(module_idP,UE_id), rrc_sdu_length); - } - - } // CCE Allocation feasible - } // msg4 frame/subframe - } // else rach_resource_type -} - -void check_Msg4_retransmission(module_id_t module_idP,int CC_idP,frame_t frameP,sub_frame_t subframeP,RA_TEMPLATE *RA_template) { - - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = eNB->common_channels; - int UE_id = -1; - uint8_t *vrb_map; - int first_rb; - int N_RB_DL; - nfapi_dl_config_request_pdu_t *dl_config_pdu; - UE_list_t *UE_list=&eNB->UE_list; - nfapi_dl_config_request_body_t *dl_req; - - int round; - /* -#ifdef Rel14 - COMMON_channels_t *cc = eNB->common_channels; - - int rmax = 0; - int rep = 0; - int reps = 0; - - first_rb = 0; - struct PRACH_ConfigSIB_v1310 *ext4_prach; - PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13; - PRACH_ParametersCE_r13_t *p[4]; - - if (cc[CC_idP].radioResourceConfigCommon_BR) { - - ext4_prach = cc[CC_idP].radioResourceConfigCommon_BR->ext4->prach_ConfigCommon_v1310; - prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13; - - switch (prach_ParametersListCE_r13->list.count) { - case 4: - p[3]=prach_ParametersListCE_r13->list.array[3]; - case 3: - p[2]=prach_ParametersListCE_r13->list.array[2]; - case 2: - p[1]=prach_ParametersListCE_r13->list.array[1]; - case 1: - p[0]=prach_ParametersListCE_r13->list.array[0]; - default: - AssertFatal(1==0,"Illegal count for prach_ParametersListCE_r13 %d\n",prach_ParametersListCE_r13->list.count); - } - } -#endif - */ - - // check HARQ status and retransmit if necessary - - - UE_id = find_UE_id(module_idP,RA_template->rnti); - AssertFatal(UE_id>=0,"Can't find UE for t-crnti\n"); - - round = UE_list->UE_sched_ctrl[UE_id].round[CC_idP][RA_template->harq_pid]; - vrb_map = cc[CC_idP].vrb_map; - - dl_req = &eNB->DL_req[CC_idP].dl_config_request_body; - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - N_RB_DL = to_prb(cc[CC_idP].mib->message.dl_Bandwidth); - - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Checking if Msg4 for harq_pid %d was acknowledged (round %d)\n", - module_idP,CC_idP,frameP,subframeP,RA_template->harq_pid,round); - - if (round!=8) { - -#ifdef Rel14 - if (RA_template->rach_resource_type>0) { - AssertFatal(1==0,"Msg4 Retransmissions not handled yet for BL/CE UEs\n"); - } + memset((void *) ul_config_pdu, 0, + sizeof(nfapi_ul_config_request_pdu_t)); + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; + ul_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu)); + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = mac->ul_handle++; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = ra->rnti; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = + narrowband_to_first_rb(cc, + ra->msg34_narrowband) + + ra->msg3_first_rb; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = + ra->msg3_nb_rb; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 2; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = + 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8. + frequency_hopping_enabled_flag = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = + rvseq[ra->msg3_round]; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = + ((10 * ra->Msg3_frame) + ra->Msg3_subframe) & 7; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = 1; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = + get_TBS_UL(ra->msg3_mcs, ra->msg3_nb_rb); + // Re13 fields + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.ue_type = + ra->rach_resource_type > 2 ? 2 : 1; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13. + total_number_of_repetitions = 1; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.repetition_number = 1; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13. + initial_transmission_sf_io = + (ra->Msg3_frame * 10) + ra->Msg3_subframe; + ul_req_body->number_of_pdus++; + } // if (ra->rach_resource_type>0) { else -#endif - { - if ( (RA_template->Msg4_frame == frameP) && (RA_template->Msg4_subframe == subframeP)) { - - //RA_template->wait_ack_Msg4++; - // we have to schedule a retransmission - - first_rb=0; - vrb_map[first_rb] = 1; - vrb_map[first_rb+1] = 1; - vrb_map[first_rb+2] = 1; - vrb_map[first_rb+3] = 1; - - fill_nfapi_dl_dci_1A(dl_config_pdu, - 4, // aggregation_level - RA_template->rnti, // rnti - 1, // rnti_type, CRNTI - RA_template->harq_pid, // harq_process - 1, // tpc, none - getRIV(N_RB_DL,first_rb,4), // resource_block_coding - RA_template->msg4_mcs, // mcs - 1, // ndi - round&3, // rv - 0); // vrb_flag - - if (!CCE_allocation_infeasible(module_idP,CC_idP,1,subframeP,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,RA_template->rnti)) { - dl_req->number_dci++; - dl_req->number_pdu++; - - LOG_D(MAC,"msg4 retransmission for rnti %x (round %d) fsf %d/%d\n", RA_template->rnti, round, frameP, subframeP); - // DLSCH Config - fill_nfapi_dlsch_config(eNB, - dl_req, - RA_template->msg4_TBsize, - -1 /* retransmission, no pdu_index */, - RA_template->rnti, - 2, // resource_allocation_type : format 1A/1B/1D - 0, // virtual_resource_block_assignment_flag : localized - getRIV(N_RB_DL,first_rb,4), // resource_block_coding : RIV, 4 PRB - 2, // modulation: QPSK - round&3, // redundancy version - 1, // transport_blocks - 0, // transport_block_to_codeword_swap_flag (0) - (cc->p_eNB==1 ) ? 0 : 1, // transmission_scheme - 1, // number of layers - 1, // number of subbands - //0, // codebook index - 1, // ue_category_capacity - 4, // pa: 0 dB - 0, // delta_power_offset_index - 0, // ngap - 1, // NPRB = 3 like in DCI - (cc->p_eNB==1 ) ? 1 : 2, // transmission mode - 1, // num_bf_prb_per_subband - 1); // num_bf_vector - } - else - LOG_D(MAC,"msg4 retransmission for rnti %x (round %d) fsf %d/%d CCE allocation failed!\n", RA_template->rnti, round, frameP, subframeP); - - - // Program PUCCH1a for ACK/NAK - +#endif + { + LOG_D(MAC, + "[eNB %d][RAPROC] Frame %d, Subframe %d : CC_id %d RA is active, Msg3 in (%d,%d)\n", + module_idP, frameP, subframeP, CC_id, ra->Msg3_frame, + ra->Msg3_subframe); - fill_nfapi_uci_acknak(module_idP,CC_idP, - RA_template->rnti, - (frameP*10)+subframeP, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx); - - // prepare frame for retransmission - if (RA_template->Msg4_subframe>1) RA_template->Msg4_frame++; - RA_template->Msg4_frame&=1023; - RA_template->Msg4_subframe=(RA_template->Msg4_subframe+8)%10; + LOG_D(MAC, + "Frame %d, Subframe %d Adding Msg3 UL Config Request for (%d,%d) : (%d,%d,%d)\n", + frameP, subframeP, ra->Msg3_frame, ra->Msg3_subframe, + ra->msg3_nb_rb, ra->msg3_first_rb, ra->msg3_round); - LOG_W(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Msg4 not acknowledged, adding ue specific dci (rnti %x) for RA (Msg4 Retransmission round %d in %d.%d)\n", - module_idP,CC_idP,frameP,subframeP,RA_template->rnti,round,RA_template->Msg4_frame,RA_template->Msg4_subframe); + ul_config_pdu = + &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus]; - } // Msg4 frame/subframe - } // regular LTE case - } else { - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d : Msg4 acknowledged\n",module_idP,CC_idP,frameP,subframeP); - RA_template->wait_ack_Msg4=0; - RA_template->RA_active=FALSE; - UE_id = find_UE_id(module_idP,RA_template->rnti); - DevAssert( UE_id != -1 ); - eNB->UE_list.UE_template[UE_PCCID(module_idP,UE_id)][UE_id].configured=TRUE; - } -} + memset((void *) ul_config_pdu, 0, + sizeof(nfapi_ul_config_request_pdu_t)); + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; + ul_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu)); + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = mac->ul_handle++; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = ra->rnti; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = + ra->msg3_first_rb; + AssertFatal(ra->msg3_nb_rb > 0, "nb_rb = 0\n"); + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = + ra->msg3_nb_rb; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 2; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = + 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8. + frequency_hopping_enabled_flag = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = + rvseq[ra->msg3_round]; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = + subframe2harqpid(cc, ra->Msg3_frame, ra->Msg3_subframe); + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = 1; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = + get_TBS_UL(10, ra->msg3_nb_rb); + ul_req_body->number_of_pdus++; + // save UL scheduling information for preprocessor + for (j = 0; j < ra->msg3_nb_rb; j++) + cc->vrb_map_UL[ra->msg3_first_rb + j] = 1; -void schedule_RA(module_id_t module_idP,frame_t frameP, sub_frame_t subframeP) + + if (ra->msg3_round != 0) { // program HI too + hi_dci0_pdu = + &hi_dci0_req->hi_dci0_pdu_list[hi_dci0_req->number_of_dci + + hi_dci0_req->number_of_hi]; + memset((void *) hi_dci0_pdu, 0, + sizeof(nfapi_hi_dci0_request_pdu_t)); + hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; + hi_dci0_pdu->pdu_size = 2 + sizeof(nfapi_hi_dci0_hi_pdu); + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = + ra->msg3_first_rb; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = 0; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 0; + hi_dci0_req->number_of_hi++; + // save UL scheduling information for preprocessor + for (j = 0; j < ra->msg3_nb_rb; j++) + cc->vrb_map_UL[ra->msg3_first_rb + j] = 1; + + LOG_D(MAC, + "[eNB %d][PUSCH-RA %x] CC_id %d Frame %d subframeP %d Scheduled (PHICH) RA (mcs %d, first rb %d, nb_rb %d,round %d)\n", + module_idP, ra->rnti, CC_id, frameP, subframeP, 10, 1, 1, + ra->msg3_round - 1); + } // if (ra->msg3_round != 0) { // program HI too + } // non-BL/CE UE case +} + +void +generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, + sub_frame_t subframeP, RA_t * ra) { - int CC_id; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = eNB->common_channels; - RA_TEMPLATE *RA_template; - uint8_t i; + eNB_MAC_INST *mac = RC.mac[module_idP]; + COMMON_channels_t *cc = mac->common_channels; - start_meas(&eNB->schedule_ra); + uint8_t *vrb_map; + int first_rb; + int N_RB_DL; + nfapi_dl_config_request_pdu_t *dl_config_pdu; + nfapi_tx_request_pdu_t *TX_req; + nfapi_dl_config_request_body_t *dl_req; + + vrb_map = cc[CC_idP].vrb_map; + dl_req = &mac->DL_req[CC_idP].dl_config_request_body; + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + N_RB_DL = to_prb(cc[CC_idP].mib->message.dl_Bandwidth); + +#ifdef Rel14 + int rmax = 0; + int rep = 0; + int reps = 0; + int num_nb = 0; + + first_rb = 0; + struct PRACH_ConfigSIB_v1310 *ext4_prach; + PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13; + PRACH_ParametersCE_r13_t *p[4] = { NULL, NULL, NULL, NULL }; + + uint16_t absSF = (10 * frameP) + subframeP; + uint16_t absSF_Msg2 = (10 * ra->Msg2_frame) + ra->Msg2_subframe; + + if (absSF > absSF_Msg2) + return; // we're not ready yet, need to be to start == + + if (cc[CC_idP].radioResourceConfigCommon_BR) { + + ext4_prach = + cc[CC_idP].radioResourceConfigCommon_BR->ext4-> + prach_ConfigCommon_v1310; + prach_ParametersListCE_r13 = + &ext4_prach->prach_ParametersListCE_r13; + + switch (prach_ParametersListCE_r13->list.count) { + case 4: + p[3] = prach_ParametersListCE_r13->list.array[3]; + case 3: + p[2] = prach_ParametersListCE_r13->list.array[2]; + case 2: + p[1] = prach_ParametersListCE_r13->list.array[1]; + case 1: + p[0] = prach_ParametersListCE_r13->list.array[0]; + break; + default: + AssertFatal(1 == 0, + "Illegal count for prach_ParametersListCE_r13 %d\n", + (int) prach_ParametersListCE_r13->list.count); + break; + } + } + + if (ra->rach_resource_type > 0) { + + // This uses an MPDCCH Type 2 common allocation according to Section 9.1.5 36-213 + // Parameters: + // p=2+4 PRB set (number of PRB pairs 3) + // rmax = mpdcch-NumRepetition-RA-r13 => Table 9.1.5-3 + // if CELevel = 0,1 => Table 9.1.5-1b for MPDCCH candidates + // if CELevel = 2,3 => Table 9.1.5-2b for MPDCCH candidates + // distributed transmission + + // rmax from SIB2 information + AssertFatal(rmax < 9, "rmax>8!\n"); + rmax = + 1 << p[ra->rach_resource_type - + 1]->mpdcch_NumRepetition_RA_r13; + // choose r1 by default for RAR (Table 9.1.5-5) + rep = 0; + // get actual repetition count from Table 9.1.5-3 + reps = (rmax <= 8) ? (1 << rep) : (rmax >> (3 - rep)); + // get narrowband according to higher-layer config + num_nb = + p[ra->rach_resource_type - + 1]->mpdcch_NarrowbandsToMonitor_r13.list.count; + ra->msg2_narrowband = + *p[ra->rach_resource_type - + 1]->mpdcch_NarrowbandsToMonitor_r13.list.array[ra-> + preamble_index + % num_nb]; + first_rb = + narrowband_to_first_rb(&cc[CC_idP], ra->msg2_narrowband); + + if ((ra->msg2_mpdcch_repetition_cnt == 0) && + (mpdcch_sf_condition + (mac, CC_idP, frameP, subframeP, rmax, TYPE2, -1) > 0)) { + // MPDCCH configuration for RAR + LOG_D(MAC, + "[eNB %d][RAPROC] Frame %d, Subframe %d : In generate_Msg2, Programming MPDCCH %d repetitions\n", + module_idP, frameP, subframeP, reps); - for (CC_id=0; CC_idpdu_type = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_dl_config_mpdcch_pdu)); + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = + (ra->rach_resource_type > 1) ? 11 : 10; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = + ra->msg2_narrowband; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. + number_of_prb_pairs = 6; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment = 0; // Note: this can be dynamic + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_tansmission_type = 1; // imposed (9.1.5 in 213) for Type 2 Common search space + AssertFatal(cc[CC_idP]. + sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 + != NULL, + "cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n"); + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol = + cc[CC_idP].sib1_v13ext-> + bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ecce_index = 0; // Note: this should be dynamic + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level = 16; // OK for CEModeA r1-3 (9.1.5-1b) or CEModeB r1-4 + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti_type = 2; // RA-RNTI + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti = ra->RA_rnti; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = + (ra->rach_resource_type < 3) ? 1 : 2; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. + drms_scrambling_init = cc[CC_idP].physCellId; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. + initial_transmission_sf_io = (frameP * 10) + subframeP; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.transmission_power = 6000; // 0dB + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding = getRIV(6, 0, 6); // Note: still to be checked if it should not be (getRIV(N_RB_DL,first_rb,6)) : Check nFAPI specifications and what is done L1 with this parameter + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mcs = 4; // adjust according to size of RAR, 208 bits with N1A_PRB=3 + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels = 4; // fix to 4 for now + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version = + 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator = + 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. + harq_resource_offset = 0; + dl_config_pdu->mpdcch_pdu. + mpdcch_pdu_rel13.dci_subframe_repetition_number = rep; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpc = 1; // N1A_PRB=3 (36.212); => 208 bits for mcs=4, choose mcs according t message size TBD + dl_config_pdu->mpdcch_pdu. + mpdcch_pdu_rel13.downlink_assignment_index_length = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. + downlink_assignment_index = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. + allocate_prach_flag = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.preamble_index = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index = + 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level = + 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.srs_request = 0; + dl_config_pdu->mpdcch_pdu. + mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag + = 0; + dl_config_pdu->mpdcch_pdu. + mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity = 0; + dl_config_pdu->mpdcch_pdu. + mpdcch_pdu_rel13.frequency_hopping_enabled_flag = 0; + dl_config_pdu->mpdcch_pdu. + mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag + = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication = + 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding = 0; // this is not needed by OAI L1, but should be filled in + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. + number_of_tx_antenna_ports = 1; + ra->msg2_mpdcch_repetition_cnt++; + dl_req->number_pdu++; + ra->Msg2_subframe = (ra->Msg2_subframe + 9) % 10; + + } //repetition_count==0 && SF condition met + if (ra->msg2_mpdcch_repetition_cnt > 0) { // we're in a stream of repetitions + LOG_D(MAC, + "[eNB %d][RAPROC] Frame %d, Subframe %d : In generate_Msg2, MPDCCH repetition %d\n", + module_idP, frameP, subframeP, + ra->msg2_mpdcch_repetition_cnt); + + if (ra->msg2_mpdcch_repetition_cnt == reps) { // this is the last mpdcch repetition + if (cc[CC_idP].tdd_Config == NULL) { // FDD case + // wait 2 subframes for PDSCH transmission + if (subframeP > 7) + ra->Msg2_frame = (frameP + 1) & 1023; + else + ra->Msg2_frame = frameP; + ra->Msg2_subframe = (subframeP + 2) % 10; // +2 is the "n+x" from Section 7.1.11 in 36.213 + } else { + AssertFatal(1 == 0, "TDD case not done yet\n"); + } + } // mpdcch_repetition_count == reps + ra->msg2_mpdcch_repetition_cnt++; + + if ((ra->Msg2_frame == frameP) + && (ra->Msg2_subframe == subframeP)) { + // Program PDSCH + LOG_D(MAC, + "[eNB %d][RAPROC] Frame %d, Subframe %d : In generate_Msg2, Programming PDSCH\n", + module_idP, frameP, subframeP); + ra->state = WAITMSG3; + + dl_config_pdu = + &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = + mac->pdu_index[CC_idP]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = ra->RA_rnti; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + resource_allocation_type = 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + resource_block_coding = getRIV(N_RB_DL, first_rb, 6); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + redundancy_version = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = + 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = + 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + number_of_subbands = 1; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + ue_category_capacity = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + delta_power_offset_index = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = + (cc->p_eNB == 1) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + num_bf_prb_per_subband = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; + + // Rel10 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = + cc[CC_idP]. + sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13-> + startSymbolBR_r13; + // Rel13 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = + (ra->rach_resource_type < 3) ? 1 : 2;; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not SI message + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13. + initial_transmission_sf_io = (10 * frameP) + subframeP; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = + 0; + dl_req->number_pdu++; + + // Program UL processing for Msg3, same as regular LTE + get_Msg3alloc(&cc[CC_idP], subframeP, frameP, + &ra->Msg3_frame, &ra->Msg3_subframe); + add_msg3(module_idP, CC_idP, ra, frameP, subframeP); + fill_rar_br(mac, CC_idP, ra, frameP, subframeP, + cc[CC_idP].RAR_pdu.payload, + ra->rach_resource_type - 1); + // DL request + mac->TX_req[CC_idP].sfn_sf = (frameP << 4) + subframeP; + TX_req = + &mac->TX_req[CC_idP].tx_request_body.tx_pdu_list[mac-> + TX_req + [CC_idP]. + tx_request_body.number_of_pdus]; + TX_req->pdu_length = 7; // This should be changed if we have more than 1 preamble + TX_req->pdu_index = mac->pdu_index[CC_idP]++; + TX_req->num_segments = 1; + TX_req->segments[0].segment_length = 7; + TX_req->segments[0].segment_data = + cc[CC_idP].RAR_pdu.payload; + mac->TX_req[CC_idP].tx_request_body.number_of_pdus++; + } + } + + } else +#endif + { + + if ((ra->Msg2_frame == frameP) && (ra->Msg2_subframe == subframeP)) { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d, subframeP %d: Generating RAR DCI, state %d\n", + module_idP, CC_idP, frameP, subframeP, ra->state); + + // Allocate 4 PRBS starting in RB 0 + first_rb = 0; + vrb_map[first_rb] = 1; + vrb_map[first_rb + 1] = 1; + vrb_map[first_rb + 2] = 1; + vrb_map[first_rb + 3] = 1; + + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = + NFAPI_DL_DCI_FORMAT_1A; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = + 4; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = ra->RA_rnti; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 2; // RA-RNTI : see Table 4-10 from SCF082 - nFAPI specifications + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // no TPC + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + new_data_indicator_1 = 1; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + redundancy_version_1 = 0; + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0; + + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + resource_block_coding = getRIV(N_RB_DL, first_rb, 4); + + // This checks if the above DCI allocation is feasible in current subframe + if (!CCE_allocation_infeasible + (module_idP, CC_idP, 0, subframeP, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level, ra->RA_rnti)) { + LOG_D(MAC, + "Frame %d: Subframe %d : Adding common DCI for RA_RNTI %x\n", + frameP, subframeP, ra->RA_rnti); + dl_req->number_dci++; + dl_req->number_pdu++; + + dl_config_pdu = + &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = + mac->pdu_index[CC_idP]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = ra->RA_rnti; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + resource_block_coding = getRIV(N_RB_DL, first_rb, 4); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + redundancy_version = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = + 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = + 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + number_of_subbands = 1; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + ue_category_capacity = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + delta_power_offset_index = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = + (cc->p_eNB == 1) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + num_bf_prb_per_subband = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; + dl_req->number_pdu++; + + // Program UL processing for Msg3 + get_Msg3alloc(&cc[CC_idP], subframeP, frameP, + &ra->Msg3_frame, &ra->Msg3_subframe); + + LOG_D(MAC, + "Frame %d, Subframe %d: Setting Msg3 reception for Frame %d Subframe %d\n", + frameP, subframeP, ra->Msg3_frame, + ra->Msg3_subframe); + + fill_rar(module_idP, CC_idP, ra, frameP, + cc[CC_idP].RAR_pdu.payload, N_RB_DL, 7); + add_msg3(module_idP, CC_idP, ra, frameP, subframeP); + ra->state = WAITMSG3; + + // DL request + mac->TX_req[CC_idP].sfn_sf = (frameP << 4) + subframeP; + TX_req = + &mac->TX_req[CC_idP].tx_request_body.tx_pdu_list[mac-> + TX_req + [CC_idP]. + tx_request_body.number_of_pdus]; + TX_req->pdu_length = 7; // This should be changed if we have more than 1 preamble + TX_req->pdu_index = mac->pdu_index[CC_idP]++; + TX_req->num_segments = 1; + TX_req->segments[0].segment_length = 7; + TX_req->segments[0].segment_data = + cc[CC_idP].RAR_pdu.payload; + mac->TX_req[CC_idP].tx_request_body.number_of_pdus++; + } // PDCCH CCE allocation is feasible + } // Msg2 frame/subframe condition + } // else BL/CE +} + +void +generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, + sub_frame_t subframeP, RA_t * ra) +{ - for (i=0; icommon_channels; + int16_t rrc_sdu_length; + int UE_id = -1; + uint16_t msg4_padding; + uint16_t msg4_post_padding; + uint16_t msg4_header; - RA_template = (RA_TEMPLATE *)&cc[CC_id].RA_template[i]; - - if (RA_template->RA_active == TRUE) { - - LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d : CC_id %d RA %d is active (generate RAR %d, generate_Msg4 %d, wait_ack_Msg4 %d, rnti %x)\n", - module_idP,frameP,subframeP,CC_id,i,RA_template->generate_rar,RA_template->generate_Msg4,RA_template->wait_ack_Msg4, RA_template->rnti); - - if (RA_template->generate_rar == 1) generate_Msg2(module_idP,CC_id,frameP,subframeP,RA_template); - else if (RA_template->generate_Msg4 == 1) generate_Msg4(module_idP,CC_id,frameP,subframeP,RA_template); - else if (RA_template->wait_ack_Msg4==1) check_Msg4_retransmission(module_idP,CC_id,frameP,subframeP,RA_template); + uint8_t *vrb_map; + int first_rb; + int N_RB_DL; + nfapi_dl_config_request_pdu_t *dl_config_pdu; + nfapi_ul_config_request_pdu_t *ul_config_pdu; + nfapi_tx_request_pdu_t *TX_req; + UE_list_t *UE_list = &mac->UE_list; + nfapi_dl_config_request_body_t *dl_req; + nfapi_ul_config_request_body_t *ul_req; + uint8_t lcid; + uint8_t offset; - } // RA_active == TRUE - } // for i=0 .. N_RA_PROC-1 - } // CC_id - - stop_meas(&eNB->schedule_ra); +#ifdef Rel14 + int rmax = 0; + int rep = 0; + int reps = 0; + + + first_rb = 0; + struct PRACH_ConfigSIB_v1310 *ext4_prach; + struct PUCCH_ConfigCommon_v1310 *ext4_pucch; + PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13; + struct N1PUCCH_AN_InfoList_r13 *pucch_N1PUCCH_AN_InfoList_r13; + PRACH_ParametersCE_r13_t *p[4] = { NULL, NULL, NULL, NULL }; + int pucchreps[4] = { 1, 1, 1, 1 }; + int n1pucchan[4] = { 0, 0, 0, 0 }; + + if (cc[CC_idP].radioResourceConfigCommon_BR) { + + ext4_prach = + cc[CC_idP].radioResourceConfigCommon_BR->ext4-> + prach_ConfigCommon_v1310; + ext4_pucch = + cc[CC_idP].radioResourceConfigCommon_BR->ext4-> + pucch_ConfigCommon_v1310; + prach_ParametersListCE_r13 = + &ext4_prach->prach_ParametersListCE_r13; + pucch_N1PUCCH_AN_InfoList_r13 = + ext4_pucch->n1PUCCH_AN_InfoList_r13; + AssertFatal(prach_ParametersListCE_r13 != NULL, + "prach_ParametersListCE_r13 is null\n"); + AssertFatal(pucch_N1PUCCH_AN_InfoList_r13 != NULL, + "pucch_N1PUCCH_AN_InfoList_r13 is null\n"); + // check to verify CE-Level compatibility in SIB2_BR + AssertFatal(prach_ParametersListCE_r13->list.count == + pucch_N1PUCCH_AN_InfoList_r13->list.count, + "prach_ParametersListCE_r13->list.count!= pucch_N1PUCCH_AN_InfoList_r13->list.count\n"); + + switch (prach_ParametersListCE_r13->list.count) { + case 4: + p[3] = prach_ParametersListCE_r13->list.array[3]; + n1pucchan[3] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[3]; + AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level3_r13 + != NULL, + "pucch_NumRepetitionCE_Msg4_Level3 shouldn't be NULL\n"); + pucchreps[3] = + (int) (4 << *ext4_pucch-> + pucch_NumRepetitionCE_Msg4_Level3_r13); + + case 3: + p[2] = prach_ParametersListCE_r13->list.array[2]; + n1pucchan[2] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[2]; + AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13 + != NULL, + "pucch_NumRepetitionCE_Msg4_Level2 shouldn't be NULL\n"); + pucchreps[2] = + (int) (4 << *ext4_pucch-> + pucch_NumRepetitionCE_Msg4_Level2_r13); + case 2: + p[1] = prach_ParametersListCE_r13->list.array[1]; + n1pucchan[1] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[1]; + AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13 + != NULL, + "pucch_NumRepetitionCE_Msg4_Level1 shouldn't be NULL\n"); + pucchreps[1] = + (int) (1 << *ext4_pucch-> + pucch_NumRepetitionCE_Msg4_Level1_r13); + case 1: + p[0] = prach_ParametersListCE_r13->list.array[0]; + n1pucchan[0] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[0]; + AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13 + != NULL, + "pucch_NumRepetitionCE_Msg4_Level0 shouldn't be NULL\n"); + pucchreps[0] = + (int) (1 << *ext4_pucch-> + pucch_NumRepetitionCE_Msg4_Level0_r13); + default: + AssertFatal(1 == 0, + "Illegal count for prach_ParametersListCE_r13 %d\n", + prach_ParametersListCE_r13->list.count); + } + } +#endif + + vrb_map = cc[CC_idP].vrb_map; + + dl_req = &mac->DL_req[CC_idP].dl_config_request_body; + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + N_RB_DL = to_prb(cc[CC_idP].mib->message.dl_Bandwidth); + + UE_id = find_UE_id(module_idP, ra->rnti); + AssertFatal(UE_id >= 0, "Can't find UE for t-crnti\n"); + + // set HARQ process round to 0 for this UE + + if (cc->tdd_Config) + ra->harq_pid = ((frameP * 10) + subframeP) % 10; + else + ra->harq_pid = ((frameP * 10) + subframeP) & 7; + + + // Get RRCConnectionSetup for Piggyback + rrc_sdu_length = mac_rrc_data_req(module_idP, CC_idP, frameP, CCCH, 1, // 1 transport block + &cc[CC_idP].CCCH_pdu.payload[0], ENB_FLAG_YES, module_idP, 0); // not used in this case + + AssertFatal(rrc_sdu_length > 0, + "[MAC][eNB Scheduler] CCCH not allocated\n"); + + + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: UE_id %d, rrc_sdu_length %d\n", + module_idP, CC_idP, frameP, subframeP, UE_id, rrc_sdu_length); + + +#ifdef Rel14 + if (ra->rach_resource_type > 0) { + + // Generate DCI + repetitions first + // This uses an MPDCCH Type 2 allocation according to Section 9.1.5 36-213, Type2 common allocation according to Table 7.1-8 (36-213) + // Parameters: + // p=2+4 PRB set (number of PRB pairs 6) + // rmax = mpdcch-NumRepetition-RA-r13 => Table 9.1.5-3 + // if CELevel = 0,1 => Table 9.1.5-1b for MPDCCH candidates + // if CELevel = 2,3 => Table 9.1.5-2b for MPDCCH candidates + // distributed transmission + + // rmax from SIB2 information + rmax = p[ra->rach_resource_type - 1]->mpdcch_NumRepetition_RA_r13; + AssertFatal(rmax >= 4, + "choose rmax>=4 for enough repeititions, or reduce rep to 1 or 2\n"); + + // choose r3 by default for Msg4 (this is ok from table 9.1.5-3 for rmax = >=4, if we choose rmax <4 it has to be less + rep = 2; + // get actual repetition count from Table 9.1.5-3 + reps = (rmax <= 8) ? (1 << rep) : (rmax >> (3 - rep)); + // get first narrowband + first_rb = + narrowband_to_first_rb(&cc[CC_idP], ra->msg34_narrowband); + + if ((ra->msg4_mpdcch_repetition_cnt == 0) && + (mpdcch_sf_condition + (mac, CC_idP, frameP, subframeP, rmax, TYPE2, -1) > 0)) { + // MPDCCH configuration for RAR + + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_dl_config_mpdcch_pdu)); + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = + (ra->rach_resource_type > 1) ? 11 : 10; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = + ra->msg34_narrowband; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. + number_of_prb_pairs = 6; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment = 0; // Note: this can be dynamic + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. + mpdcch_tansmission_type = 1; + AssertFatal(cc[CC_idP]. + sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 + != NULL, + "cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n"); + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol = + cc[CC_idP].sib1_v13ext-> + bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ecce_index = 0; // Note: this should be dynamic + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level = 16; // OK for CEModeA r1-3 (9.1.5-1b) or CEModeB r1-4 + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti_type = 0; // t-C-RNTI + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti = ra->RA_rnti; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = + (ra->rach_resource_type < 3) ? 1 : 2; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.drms_scrambling_init = cc[CC_idP].physCellId; /// Check this is still N_id_cell for type2 common + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. + initial_transmission_sf_io = (frameP * 10) + subframeP; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.transmission_power = 6000; // 0dB + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding = getRIV(6, 0, 6); // check if not getRIV(N_RB_DL,first_rb,6); + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mcs = 4; // adjust according to size of Msg4, 208 bits with N1A_PRB=3 + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels = 4; // fix to 4 for now + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version = + 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator = + 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process = + ra->harq_pid; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. + harq_resource_offset = 0; + dl_config_pdu->mpdcch_pdu. + mpdcch_pdu_rel13.dci_subframe_repetition_number = rep; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpc = 1; // N1A_PRB=3; => 208 bits + dl_config_pdu->mpdcch_pdu. + mpdcch_pdu_rel13.downlink_assignment_index_length = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. + downlink_assignment_index = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. + allocate_prach_flag = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.preamble_index = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index = + 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level = + 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.srs_request = 0; + dl_config_pdu->mpdcch_pdu. + mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag + = 0; + dl_config_pdu->mpdcch_pdu. + mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity = 0; + dl_config_pdu->mpdcch_pdu. + mpdcch_pdu_rel13.frequency_hopping_enabled_flag = 0; + dl_config_pdu->mpdcch_pdu. + mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag + = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication = + 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding = 0; // this is not needed by OAI L1, but should be filled in + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. + number_of_tx_antenna_ports = 1; + ra->msg4_mpdcch_repetition_cnt++; + dl_req->number_pdu++; + + } //repetition_count==0 && SF condition met + else if (ra->msg4_mpdcch_repetition_cnt > 0) { // we're in a stream of repetitions + ra->msg4_mpdcch_repetition_cnt++; + if (ra->msg4_mpdcch_repetition_cnt == reps) { // this is the last mpdcch repetition + if (cc[CC_idP].tdd_Config == NULL) { // FDD case + // wait 2 subframes for PDSCH transmission + if (subframeP > 7) + ra->Msg4_frame = (frameP + 1) & 1023; + else + ra->Msg4_frame = frameP; + ra->Msg4_subframe = (subframeP + 2) % 10; + } else { + AssertFatal(1 == 0, "TDD case not done yet\n"); + } + } // mpdcch_repetition_count == reps + if ((ra->Msg4_frame == frameP) + && (ra->Msg4_subframe == subframeP)) { + + // Program PDSCH + + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Generating Msg4 BR with RRC Piggyback (ce_level %d RNTI %x)\n", + module_idP, CC_idP, frameP, subframeP, + ra->rach_resource_type - 1, ra->rnti); + + AssertFatal(1 == 0, + "Msg4 generation not finished for BL/CE UE\n"); + dl_config_pdu = + &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = + mac->pdu_index[CC_idP]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = ra->rnti; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 6); // check that this isn't getRIV(6,0,6) + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + redundancy_version = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = + 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = + 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + number_of_subbands = 1; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + ue_category_capacity = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + delta_power_offset_index = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = + (cc->p_eNB == 1) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + num_bf_prb_per_subband = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; + + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = + cc[CC_idP]. + sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13-> + startSymbolBR_r13; + + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = + (ra->rach_resource_type < 3) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not SI message + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13. + initial_transmission_sf_io = (10 * frameP) + subframeP; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = + 0; + dl_req->number_pdu++; + + ra->state = WAITMSG4ACK; + + lcid = 0; + + UE_list->UE_sched_ctrl[UE_id].round[CC_idP][ra->harq_pid] = + 0; + msg4_header = 1 + 6 + 1; // CR header, CR CE, SDU header + + if ((ra->msg4_TBsize - rrc_sdu_length - msg4_header) <= 2) { + msg4_padding = + ra->msg4_TBsize - rrc_sdu_length - msg4_header; + msg4_post_padding = 0; + } else { + msg4_padding = 0; + msg4_post_padding = + ra->msg4_TBsize - rrc_sdu_length - msg4_header - 1; + } + + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d subframeP %d Msg4 : TBS %d, sdu_len %d, msg4_header %d, msg4_padding %d, msg4_post_padding %d\n", + module_idP, CC_idP, frameP, subframeP, + ra->msg4_TBsize, rrc_sdu_length, msg4_header, + msg4_padding, msg4_post_padding); + DevAssert(UE_id != UE_INDEX_INVALID); // FIXME not sure how to gracefully return + // CHECK THIS: &cc[CC_idP].CCCH_pdu.payload[0] + offset = generate_dlsch_header((unsigned char *) mac->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0], 1, //num_sdus + (unsigned short *) &rrc_sdu_length, // + &lcid, // sdu_lcid + 255, // no drx + 31, // no timing advance + ra->cont_res_id, // contention res id + msg4_padding, // no padding + msg4_post_padding); + + memcpy((void *) &mac->UE_list. + DLSCH_pdu[CC_idP][0][(unsigned char) + UE_id].payload[0][(unsigned + char) + offset], + &cc[CC_idP].CCCH_pdu.payload[0], rrc_sdu_length); + + // DL request + mac->TX_req[CC_idP].sfn_sf = (frameP << 4) + subframeP; + TX_req = + &mac->TX_req[CC_idP].tx_request_body.tx_pdu_list[mac-> + TX_req + [CC_idP]. + tx_request_body.number_of_pdus]; + TX_req->pdu_length = rrc_sdu_length; + TX_req->pdu_index = mac->pdu_index[CC_idP]++; + TX_req->num_segments = 1; + TX_req->segments[0].segment_length = rrc_sdu_length; + TX_req->segments[0].segment_data = + mac->UE_list. + DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0]; + mac->TX_req[CC_idP].tx_request_body.number_of_pdus++; + + // Program ACK/NAK for Msg4 PDSCH + int absSF = (ra->Msg3_frame * 10) + ra->Msg3_subframe; + // see Section 10.2 from 36.213 + int ackNAK_absSF = absSF + reps + 4; + AssertFatal(reps > 2, + "Have to handle programming of ACK when PDSCH repetitions is > 2\n"); + ul_req = + &mac->UL_req_tmp[CC_idP][ackNAK_absSF % + 10].ul_config_request_body; + ul_config_pdu = + &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; + + ul_config_pdu->pdu_type = + NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE; + ul_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_ul_config_uci_harq_pdu)); + ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.handle = 0; // don't know how to use this + ul_config_pdu->uci_harq_pdu. + ue_information.ue_information_rel8.rnti = ra->rnti; + ul_config_pdu->uci_harq_pdu. + ue_information.ue_information_rel13.ue_type = + (ra->rach_resource_type < 3) ? 1 : 2; + ul_config_pdu->uci_harq_pdu. + ue_information.ue_information_rel13.empty_symbols = 0; + ul_config_pdu->uci_harq_pdu.ue_information. + ue_information_rel13.total_number_of_repetitions = + pucchreps[ra->rach_resource_type - 1]; + ul_config_pdu->uci_harq_pdu. + ue_information.ue_information_rel13.repetition_number = + 0; + // Note need to keep sending this across reptitions!!!! Not really for PUCCH, to ask small-cell forum, we'll see for the other messages, maybe parameters change across repetitions and FAPI has to provide for that + if (cc[CC_idP].tdd_Config == NULL) { // FDD case + ul_config_pdu->uci_harq_pdu. + harq_information.harq_information_rel8_fdd. + n_pucch_1_0 = + n1pucchan[ra->rach_resource_type - 1]; + // NOTE: How to fill in the rest of the n_pucch_1_0 information 213 Section 10.1.2.1 in the general case + // = N_ECCE_q + Delta_ARO + n1pucchan[ce_level] + // higher in the MPDCCH configuration, N_ECCE_q is hard-coded to 0, and harq resource offset to 0 => + // Delta_ARO = 0 from Table 10.1.2.1-1 + ul_config_pdu->uci_harq_pdu.harq_information.harq_information_rel8_fdd.harq_size = 1; // 1-bit ACK/NAK + } else { + AssertFatal(1 == 0, + "PUCCH configuration for ACK/NAK not handled yet for TDD BL/CE case\n"); + } + ul_req->number_of_pdus++; + T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), + T_INT(CC_idP), T_INT(ra->rnti), T_INT(frameP), + T_INT(subframeP), T_INT(0 /*harq_pid always 0? */ ), + T_BUFFER(&mac->UE_list.DLSCH_pdu[CC_idP][0][UE_id]. + payload[0], ra->msg4_TBsize)); + + if (opt_enabled == 1) { + trace_pdu(1, + (uint8_t *) mac-> + UE_list.DLSCH_pdu[CC_idP][0][(unsigned char) + UE_id].payload + [0], rrc_sdu_length, UE_id, 3, + UE_RNTI(module_idP, UE_id), mac->frame, + mac->subframe, 0, 0); + LOG_D(OPT, + "[eNB %d][DLSCH] CC_id %d Frame %d trace pdu for rnti %x with size %d\n", + module_idP, CC_idP, frameP, UE_RNTI(module_idP, + UE_id), + rrc_sdu_length); + } + } // Msg4 frame/subframe + } // msg4_mpdcch_repetition_count + } // rach_resource_type > 0 + else +#endif + { // This is normal LTE case + if ((ra->Msg4_frame == frameP) && (ra->Msg4_subframe == subframeP)) { + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Generating Msg4 with RRC Piggyback (RNTI %x)\n", + module_idP, CC_idP, frameP, subframeP, ra->rnti); + + /// Choose first 4 RBs for Msg4, should really check that these are free! + first_rb = 0; + + vrb_map[first_rb] = 1; + vrb_map[first_rb + 1] = 1; + vrb_map[first_rb + 2] = 1; + vrb_map[first_rb + 3] = 1; + + + // Compute MCS/TBS for 3 PRB (coded on 4 vrb) + msg4_header = 1 + 6 + 1; // CR header, CR CE, SDU header + + if ((rrc_sdu_length + msg4_header) <= 22) { + ra->msg4_mcs = 4; + ra->msg4_TBsize = 22; + } else if ((rrc_sdu_length + msg4_header) <= 28) { + ra->msg4_mcs = 5; + ra->msg4_TBsize = 28; + } else if ((rrc_sdu_length + msg4_header) <= 32) { + ra->msg4_mcs = 6; + ra->msg4_TBsize = 32; + } else if ((rrc_sdu_length + msg4_header) <= 41) { + ra->msg4_mcs = 7; + ra->msg4_TBsize = 41; + } else if ((rrc_sdu_length + msg4_header) <= 49) { + ra->msg4_mcs = 8; + ra->msg4_TBsize = 49; + } else if ((rrc_sdu_length + msg4_header) <= 57) { + ra->msg4_mcs = 9; + ra->msg4_TBsize = 57; + } + + fill_nfapi_dl_dci_1A(dl_config_pdu, 4, // aggregation_level + ra->rnti, // rnti + 1, // rnti_type, CRNTI + ra->harq_pid, // harq_process + 1, // tpc, none + getRIV(N_RB_DL, first_rb, 4), // resource_block_coding + ra->msg4_mcs, // mcs + 1, // ndi + 0, // rv + 0); // vrb_flag + LOG_D(MAC, + "Frame %d, subframe %d: Msg4 DCI pdu_num %d (rnti %x,rnti_type %d,harq_pid %d, resource_block_coding (%p) %d\n", + frameP, subframeP, dl_req->number_pdu, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process, + &dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + resource_block_coding, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + resource_block_coding); + AssertFatal(dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.resource_block_coding < 8192, + "resource_block_coding %u < 8192\n", + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.resource_block_coding); + if (!CCE_allocation_infeasible + (module_idP, CC_idP, 1, subframeP, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level, ra->rnti)) { + dl_req->number_dci++; + dl_req->number_pdu++; + + ra->state = WAITMSG4ACK; + + // increment Absolute subframe by 8 for Msg4 retransmission + LOG_D(MAC, + "Frame %d, Subframe %d: Preparing for Msg4 retransmission currently %d.%d\n", + frameP, subframeP, ra->Msg4_frame, + ra->Msg4_subframe); + if (ra->Msg4_subframe > 1) + ra->Msg4_frame++; + ra->Msg4_frame &= 1023; + ra->Msg4_subframe = (ra->Msg4_subframe + 8) % 10; + LOG_D(MAC, + "Frame %d, Subframe %d: Msg4 retransmission in %d.%d\n", + frameP, subframeP, ra->Msg4_frame, + ra->Msg4_subframe); + lcid = 0; + + // put HARQ process round to 0 + if (cc->tdd_Config) + ra->harq_pid = ((frameP * 10) + subframeP) % 10; + else + ra->harq_pid = ((frameP * 10) + subframeP) & 7; + UE_list->UE_sched_ctrl[UE_id].round[CC_idP][ra->harq_pid] = + 0; + + if ((ra->msg4_TBsize - rrc_sdu_length - msg4_header) <= 2) { + msg4_padding = + ra->msg4_TBsize - rrc_sdu_length - msg4_header; + msg4_post_padding = 0; + } else { + msg4_padding = 0; + msg4_post_padding = + ra->msg4_TBsize - rrc_sdu_length - msg4_header - 1; + } + + LOG_D(MAC, + "[eNB %d][RAPROC] CC_idP %d Frame %d subframeP %d Msg4 : TBS %d, sdu_len %d, msg4_header %d, msg4_padding %d, msg4_post_padding %d\n", + module_idP, CC_idP, frameP, subframeP, + ra->msg4_TBsize, rrc_sdu_length, msg4_header, + msg4_padding, msg4_post_padding); + DevAssert(UE_id != UE_INDEX_INVALID); // FIXME not sure how to gracefully return + // CHECK THIS: &cc[CC_idP].CCCH_pdu.payload[0] + offset = generate_dlsch_header((unsigned char *) mac->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0], 1, //num_sdus + (unsigned short *) &rrc_sdu_length, // + &lcid, // sdu_lcid + 255, // no drx + 31, // no timing advance + ra->cont_res_id, // contention res id + msg4_padding, // no padding + msg4_post_padding); + + memcpy((void *) &mac->UE_list. + DLSCH_pdu[CC_idP][0][(unsigned char) + UE_id].payload[0][(unsigned + char) + offset], + &cc[CC_idP].CCCH_pdu.payload[0], rrc_sdu_length); + + // DLSCH Config + fill_nfapi_dlsch_config(mac, dl_req, ra->msg4_TBsize, mac->pdu_index[CC_idP], ra->rnti, 2, // resource_allocation_type : format 1A/1B/1D + 0, // virtual_resource_block_assignment_flag : localized + getRIV(N_RB_DL, first_rb, 4), // resource_block_coding : RIV, 4 PRB + 2, // modulation: QPSK + 0, // redundancy version + 1, // transport_blocks + 0, // transport_block_to_codeword_swap_flag (0) + (cc->p_eNB == 1) ? 0 : 1, // transmission_scheme + 1, // number of layers + 1, // number of subbands + //0, // codebook index + 1, // ue_category_capacity + 4, // pa: 0 dB + 0, // delta_power_offset_index + 0, // ngap + 1, // NPRB = 3 like in DCI + (cc->p_eNB == 1) ? 1 : 2, // transmission mode + 1, // num_bf_prb_per_subband + 1); // num_bf_vector + LOG_D(MAC, + "Filled DLSCH config, pdu number %d, non-dci pdu_index %d\n", + dl_req->number_pdu, mac->pdu_index[CC_idP]); + + // DL request + mac->TX_req[CC_idP].sfn_sf = + fill_nfapi_tx_req(&mac->TX_req[CC_idP].tx_request_body, + (frameP * 10) + subframeP, + rrc_sdu_length, + mac->pdu_index[CC_idP], + mac->UE_list. + DLSCH_pdu[CC_idP][0][(unsigned char) + UE_id].payload + [0]); + mac->pdu_index[CC_idP]++; + + LOG_D(MAC, "Filling UCI ACK/NAK information, cce_idx %d\n", + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx); + // Program PUCCH1a for ACK/NAK + // Program ACK/NAK for Msg4 PDSCH + fill_nfapi_uci_acknak(module_idP, + CC_idP, + ra->rnti, + (frameP * 10) + subframeP, + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.cce_idx); + + + T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), + T_INT(CC_idP), T_INT(ra->rnti), T_INT(frameP), + T_INT(subframeP), T_INT(0 /*harq_pid always 0? */ ), + T_BUFFER(&mac->UE_list.DLSCH_pdu[CC_idP][0][UE_id]. + payload[0], ra->msg4_TBsize)); + + if (opt_enabled == 1) { + trace_pdu(1, + (uint8_t *) mac-> + UE_list.DLSCH_pdu[CC_idP][0][(unsigned char) + UE_id].payload + [0], rrc_sdu_length, UE_id, 3, + UE_RNTI(module_idP, UE_id), mac->frame, + mac->subframe, 0, 0); + LOG_D(OPT, + "[eNB %d][DLSCH] CC_id %d Frame %d trace pdu for rnti %x with size %d\n", + module_idP, CC_idP, frameP, UE_RNTI(module_idP, + UE_id), + rrc_sdu_length); + } + + } // CCE Allocation feasible + } // msg4 frame/subframe + } // else rach_resource_type +} + +void +check_Msg4_retransmission(module_id_t module_idP, int CC_idP, + frame_t frameP, sub_frame_t subframeP, RA_t * ra) +{ + + eNB_MAC_INST *mac = RC.mac[module_idP]; + COMMON_channels_t *cc = mac->common_channels; + int UE_id = -1; + uint8_t *vrb_map; + int first_rb; + int N_RB_DL; + nfapi_dl_config_request_pdu_t *dl_config_pdu; + UE_list_t *UE_list = &mac->UE_list; + nfapi_dl_config_request_body_t *dl_req; + + int round; + /* + #ifdef Rel14 + COMMON_channels_t *cc = mac->common_channels; + + int rmax = 0; + int rep = 0; + int reps = 0; + + first_rb = 0; + struct PRACH_ConfigSIB_v1310 *ext4_prach; + PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13; + PRACH_ParametersCE_r13_t *p[4]; + + if (cc[CC_idP].radioResourceConfigCommon_BR) { + + ext4_prach = cc[CC_idP].radioResourceConfigCommon_BR->ext4->prach_ConfigCommon_v1310; + prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13; + + switch (prach_ParametersListCE_r13->list.count) { + case 4: + p[3]=prach_ParametersListCE_r13->list.array[3]; + case 3: + p[2]=prach_ParametersListCE_r13->list.array[2]; + case 2: + p[1]=prach_ParametersListCE_r13->list.array[1]; + case 1: + p[0]=prach_ParametersListCE_r13->list.array[0]; + default: + AssertFatal(1==0,"Illegal count for prach_ParametersListCE_r13 %d\n",prach_ParametersListCE_r13->list.count); + } + } + #endif + */ + + // check HARQ status and retransmit if necessary + + + UE_id = find_UE_id(module_idP, ra->rnti); + AssertFatal(UE_id >= 0, "Can't find UE for t-crnti\n"); + + round = UE_list->UE_sched_ctrl[UE_id].round[CC_idP][ra->harq_pid]; + vrb_map = cc[CC_idP].vrb_map; + + dl_req = &mac->DL_req[CC_idP].dl_config_request_body; + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + N_RB_DL = to_prb(cc[CC_idP].mib->message.dl_Bandwidth); + + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Checking if Msg4 for harq_pid %d was acknowledged (round %d)\n", + module_idP, CC_idP, frameP, subframeP, ra->harq_pid, round); + + if (round != 8) { + +#ifdef Rel14 + if (ra->rach_resource_type > 0) { + AssertFatal(1 == 0, + "Msg4 Retransmissions not handled yet for BL/CE UEs\n"); + } else +#endif + { + if ((ra->Msg4_frame == frameP) + && (ra->Msg4_subframe == subframeP)) { + + //ra->wait_ack_Msg4++; + // we have to schedule a retransmission + + first_rb = 0; + vrb_map[first_rb] = 1; + vrb_map[first_rb + 1] = 1; + vrb_map[first_rb + 2] = 1; + vrb_map[first_rb + 3] = 1; + + fill_nfapi_dl_dci_1A(dl_config_pdu, 4, // aggregation_level + ra->rnti, // rnti + 1, // rnti_type, CRNTI + ra->harq_pid, // harq_process + 1, // tpc, none + getRIV(N_RB_DL, first_rb, 4), // resource_block_coding + ra->msg4_mcs, // mcs + 1, // ndi + round & 3, // rv + 0); // vrb_flag + + if (!CCE_allocation_infeasible + (module_idP, CC_idP, 1, subframeP, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level, ra->rnti)) { + dl_req->number_dci++; + dl_req->number_pdu++; + + LOG_D(MAC, + "msg4 retransmission for rnti %x (round %d) fsf %d/%d\n", + ra->rnti, round, frameP, subframeP); + // DLSCH Config + fill_nfapi_dlsch_config(mac, dl_req, ra->msg4_TBsize, + -1 + /* retransmission, no pdu_index */ + , ra->rnti, 2, // resource_allocation_type : format 1A/1B/1D + 0, // virtual_resource_block_assignment_flag : localized + getRIV(N_RB_DL, first_rb, 4), // resource_block_coding : RIV, 4 PRB + 2, // modulation: QPSK + round & 3, // redundancy version + 1, // transport_blocks + 0, // transport_block_to_codeword_swap_flag (0) + (cc->p_eNB == 1) ? 0 : 1, // transmission_scheme + 1, // number of layers + 1, // number of subbands + //0, // codebook index + 1, // ue_category_capacity + 4, // pa: 0 dB + 0, // delta_power_offset_index + 0, // ngap + 1, // NPRB = 3 like in DCI + (cc->p_eNB == 1) ? 1 : 2, // transmission mode + 1, // num_bf_prb_per_subband + 1); // num_bf_vector + } else + LOG_D(MAC, + "msg4 retransmission for rnti %x (round %d) fsf %d/%d CCE allocation failed!\n", + ra->rnti, round, frameP, subframeP); + + + // Program PUCCH1a for ACK/NAK + + + fill_nfapi_uci_acknak(module_idP, CC_idP, + ra->rnti, + (frameP * 10) + subframeP, + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.cce_idx); + + // prepare frame for retransmission + if (ra->Msg4_subframe > 1) + ra->Msg4_frame++; + ra->Msg4_frame &= 1023; + ra->Msg4_subframe = (ra->Msg4_subframe + 8) % 10; + + LOG_W(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Msg4 not acknowledged, adding ue specific dci (rnti %x) for RA (Msg4 Retransmission round %d in %d.%d)\n", + module_idP, CC_idP, frameP, subframeP, ra->rnti, + round, ra->Msg4_frame, ra->Msg4_subframe); + + } // Msg4 frame/subframe + } // regular LTE case + } else { + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d : Msg4 acknowledged\n", + module_idP, CC_idP, frameP, subframeP); + ra->state = IDLE; + UE_id = find_UE_id(module_idP, ra->rnti); + DevAssert(UE_id != -1); + mac->UE_list.UE_template[UE_PCCID(module_idP, UE_id)][UE_id]. + configured = TRUE; + } +} + +void +schedule_RA(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) +{ + + int CC_id; + eNB_MAC_INST *mac = RC.mac[module_idP]; + COMMON_channels_t *cc = mac->common_channels; + RA_t *ra; + uint8_t i; + + start_meas(&mac->schedule_ra); + + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + // skip UL component carriers if TDD + if (is_UL_sf(&cc[CC_id], subframeP) == 1) + continue; + + + for (i = 0; i < NB_RA_PROC_MAX; i++) { + + ra = (RA_t *) & cc[CC_id].ra[i]; + + if (ra->state == MSG2) + generate_Msg2(module_idP, CC_id, frameP, subframeP, ra); + else if (ra->state == MSG4) + generate_Msg4(module_idP, CC_id, frameP, subframeP, ra); + else if (ra->state == WAITMSG4ACK) + check_Msg4_retransmission(module_idP, CC_id, frameP, + subframeP, ra); + + } // for i=0 .. N_RA_PROC-1 + } // CC_id + + stop_meas(&mac->schedule_ra); } // handles the event of MSG1 reception -void initiate_ra_proc(module_id_t module_idP, - int CC_id, - frame_t frameP, - sub_frame_t subframeP, - uint16_t preamble_index, - int16_t timing_offset, - uint16_t ra_rnti +void +initiate_ra_proc(module_id_t module_idP, + int CC_id, + frame_t frameP, + sub_frame_t subframeP, + uint16_t preamble_index, + int16_t timing_offset, uint16_t ra_rnti #ifdef Rel14 - , - uint8_t rach_resource_type + , uint8_t rach_resource_type #endif - ) + ) { - uint8_t i; + uint8_t i; - COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_id]; - RA_TEMPLATE *RA_template = &cc->RA_template[0]; + COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_id]; + RA_t *ra = &cc->ra[0]; - struct PRACH_ConfigSIB_v1310 *ext4_prach = NULL; - PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13 = NULL; + struct PRACH_ConfigSIB_v1310 *ext4_prach = NULL; + PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13 = NULL; - if (cc->radioResourceConfigCommon_BR && cc->radioResourceConfigCommon_BR->ext4) { - ext4_prach=cc->radioResourceConfigCommon_BR->ext4->prach_ConfigCommon_v1310; - prach_ParametersListCE_r13= &ext4_prach->prach_ParametersListCE_r13; - } - LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, Subframe %d Initiating RA procedure for preamble index %d\n",module_idP,CC_id,frameP,subframeP,preamble_index); -#ifdef Rel14 - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, Subframe %d PRACH resource type %d\n",module_idP,CC_id,frameP,subframeP,rach_resource_type); -#endif - - if (prach_ParametersListCE_r13 && - prach_ParametersListCE_r13->list.countlist.count); - return; - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC,1); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC,0); - - for (i=0; i5)?1:0); - RA_template[i].Msg2_subframe = (subframeP+4)%10; - /* TODO: find better procedure to allocate RNTI */ - do { - RA_template[i].rnti = taus(); - loop++; - } while (loop != 100 && - /* TODO: this is not correct, the rnti may be in use without - * being in the MAC yet. To be refined. - */ - !(find_UE_id(module_idP, RA_template[i].rnti) == -1 && - /* 1024 and 60000 arbirarily chosen, not coming from standard */ - RA_template[i].rnti >= 1024 && RA_template[i].rnti < 60000)); - if (loop == 100) { printf("%s:%d:%s: FATAL ERROR! contact the authors\n", __FILE__, __LINE__, __FUNCTION__); abort(); } - RA_template[i].RA_rnti = ra_rnti; - RA_template[i].preamble_index = preamble_index; - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d Activating RAR generation in Frame %d, subframe %d for process %d, rnti %x, RA_active %d\n", - module_idP,CC_id,frameP, - RA_template[i].Msg2_frame, - RA_template[i].Msg2_subframe, - i,RA_template[i].rnti, - RA_template[i].RA_active); - - return; + if (cc->radioResourceConfigCommon_BR + && cc->radioResourceConfigCommon_BR->ext4) { + ext4_prach = + cc->radioResourceConfigCommon_BR->ext4-> + prach_ConfigCommon_v1310; + prach_ParametersListCE_r13 = + &ext4_prach->prach_ParametersListCE_r13; } - } + LOG_I(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d, Subframe %d Initiating RA procedure for preamble index %d\n", + module_idP, CC_id, frameP, subframeP, preamble_index); +#ifdef Rel14 + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d, Subframe %d PRACH resource type %d\n", + module_idP, CC_id, frameP, subframeP, rach_resource_type); +#endif - LOG_E(MAC,"[eNB %d][RAPROC] FAILURE: CC_id %d Frame %d Initiating RA procedure for preamble index %d\n",module_idP,CC_id,frameP,preamble_index); + if (prach_ParametersListCE_r13 && + prach_ParametersListCE_r13->list.count < rach_resource_type) { + LOG_E(MAC, + "[eNB %d][RAPROC] CC_id %d Received impossible PRACH resource type %d, only %d CE levels configured\n", + module_idP, CC_id, rach_resource_type, + (int) prach_ParametersListCE_r13->list.count); + return; + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 1); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 0); + + for (i = 0; i < NB_RA_PROC_MAX; i++) { + if (ra[i].state == IDLE) { + int loop = 0; + LOG_D(MAC, "Frame %d, Subframe %d: Activating RA process %d\n", + frameP, subframeP, i); + ra[i].state = MSG2; + ra[i].timing_offset = timing_offset; + ra[i].preamble_subframe = subframeP; +#ifdef Rel14 + ra[i].rach_resource_type = rach_resource_type; + ra[i].msg2_mpdcch_repetition_cnt = 0; + ra[i].msg4_mpdcch_repetition_cnt = 0; +#endif + ra[i].Msg2_frame = frameP + ((subframeP > 5) ? 1 : 0); + ra[i].Msg2_subframe = (subframeP + 4) % 10; + /* TODO: find better procedure to allocate RNTI */ + do { + ra[i].rnti = taus(); + loop++; + } + while (loop != 100 && + /* TODO: this is not correct, the rnti may be in use without + * being in the MAC yet. To be refined. + */ + !(find_UE_id(module_idP, ra[i].rnti) == -1 && + /* 1024 and 60000 arbirarily chosen, not coming from standard */ + ra[i].rnti >= 1024 && ra[i].rnti < 60000)); + if (loop == 100) { + printf("%s:%d:%s: FATAL ERROR! contact the authors\n", + __FILE__, __LINE__, __FUNCTION__); + abort(); + } + ra[i].RA_rnti = ra_rnti; + ra[i].preamble_index = preamble_index; + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d Activating RAR generation in Frame %d, subframe %d for process %d, rnti %x, state %d\n", + module_idP, CC_id, frameP, ra[i].Msg2_frame, + ra[i].Msg2_subframe, i, ra[i].rnti, ra[i].state); + + return; + } + } + + LOG_E(MAC, + "[eNB %d][RAPROC] FAILURE: CC_id %d Frame %d Initiating RA procedure for preamble index %d\n", + module_idP, CC_id, frameP, preamble_index); } -void cancel_ra_proc(module_id_t module_idP, int CC_id, frame_t frameP, rnti_t rnti) +void +cancel_ra_proc(module_id_t module_idP, int CC_id, frame_t frameP, + rnti_t rnti) { - unsigned char i; - RA_TEMPLATE *RA_template = (RA_TEMPLATE *)&RC.mac[module_idP]->common_channels[CC_id].RA_template[0]; + unsigned char i; + RA_t *ra = (RA_t *) & RC.mac[module_idP]->common_channels[CC_id].ra[0]; - MSC_LOG_EVENT(MSC_PHY_ENB, "RA Cancelling procedure ue %"PRIx16" ", rnti); - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d Cancelling RA procedure for UE rnti %x\n",module_idP,CC_id,frameP,rnti); + MSC_LOG_EVENT(MSC_PHY_ENB, "RA Cancelling procedure ue %" PRIx16 " ", + rnti); + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d Cancelling RA procedure for UE rnti %x\n", + module_idP, CC_id, frameP, rnti); - for (i=0; icommon_channels[CC_id]; - vrb_map = (void*)&cc->vrb_map; - N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); - dl_req = &eNB->DL_req[CC_id].dl_config_request_body; + cc = &eNB->common_channels[CC_id]; + vrb_map = (void *) &cc->vrb_map; + N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); + dl_req = &eNB->DL_req[CC_id].dl_config_request_body; - int foffset = cc->physCellId&1; - int sfoffset = (cc->tdd_Config==NULL) ? 0 : 1; + int foffset = cc->physCellId & 1; + int sfoffset = (cc->tdd_Config == NULL) ? 0 : 1; - // Time-domain scheduling - if (cc->mib->message.schedulingInfoSIB1_BR_r13==0) continue; - else - switch ((cc->mib->message.schedulingInfoSIB1_BR_r13-1)%3) { - case 0: // repetition 4 - k = (frameP>>1)&3; - if ((subframeP!=(4+sfoffset)) || ((frameP&1)!=foffset)) continue; - break; - case 1: // repetition 8 - k = frameP&3; - AssertFatal(N_RB_DL>15,"SIB1-BR repetition 8 not allowed for N_RB_DL= %d\n",N_RB_DL); - if ((foffset==0) && (subframeP!=(4+sfoffset))) continue; - else if ((foffset==1) && (subframeP!=((9+sfoffset)%10))) continue; - break; - case 2: // repetition 16 - k = ((10*frameP) + subframeP)&3; - AssertFatal(N_RB_DL>15,"SIB1-BR repetition 16 not allowed for N_RB_DL= %d\n",N_RB_DL); - if ((sfoffset == 1) && ((subframeP!=0)||(subframeP!=5))) continue; - else if ((sfoffset == 0) && (foffset==0) && (subframeP!=4) && (subframeP!=9)) continue; - else if ((sfoffset == 0) && (foffset==1) && (subframeP!=0) && (subframeP!=9)) continue; - break; - } - // if we get here we have to schedule SIB1_BR in this frame/subframe - - // keep counter of SIB1_BR repetitions in 8 frame period to choose narrowband on which to transmit - if ((frameP&7) == 0) cc->SIB1_BR_cnt=0; - else cc->SIB1_BR_cnt++; - - // Frequency-domain scheduling - switch (N_RB_DL) { - case 6: - case 15: - default: - m=1; - n_NB=0; - N_S_NB=0; - Sj=NULL; - break; - case 25: - m=2; - N_S_NB = 2; - Sj = Sj25; - break; - case 50: - m=2; - N_S_NB = 6; - Sj = Sj50; - break; - case 75: - m=4; - N_S_NB = 10; - Sj = Sj75; - break; - case 100: - m=4; - N_S_NB = 14; - Sj = Sj100; - break; - } - // Note: definition of k above and rvidx from 36.321 section 5.3.1 - rvidx = (((3*k)>>1) + (k&1))&3; - - i = cc->SIB1_BR_cnt & (m-1); - - n_NB = Sj[((cc->physCellId % N_S_NB) + (i*N_S_NB/m))%N_S_NB]; - - - bcch_sdu_length = mac_rrc_data_req(module_idP, - CC_id, - frameP, - BCCH_SIB1_BR,1, - &cc->BCCH_BR_pdu[0].payload[0], - 1, - module_idP, - 0); // not used in this case - - AssertFatal(cc->mib->message.schedulingInfoSIB1_BR_r13<19,"schedulingInfoSIB1_BR_r13 %d > 18\n", - (int)cc->mib->message.schedulingInfoSIB1_BR_r13); - - AssertFatal(bcch_sdu_length>0,"RRC returned 0 bytes for SIB1-BR\n"); - - TBS = SIB1_BR_TBS_table[(cc->mib->message.schedulingInfoSIB1_BR_r13-1)/3]>>3; - - AssertFatal(bcch_sdu_length <= TBS, "length returned by RRC %d is not compatible with the TBS %d from MIB\n",bcch_sdu_length,TBS); - - if ((frameP&1023) < 200) LOG_D(MAC,"[eNB %d] Frame %d Subframe %d: SIB1_BR->DLSCH CC_id %d, Received %d bytes, scheduling on NB %d (i %d,m %d,N_S_NB %d) rvidx %d\n",module_idP,frameP,subframeP,CC_id,bcch_sdu_length,n_NB,i,m,N_S_NB,rvidx); - - // allocate all 6 PRBs in narrowband for SIB1_BR - - first_rb = narrowband_to_first_rb(cc,n_NB); - - vrb_map[first_rb] = 1; - vrb_map[first_rb+1] = 1; - vrb_map[first_rb+2] = 1; - vrb_map[first_rb+3] = 1; - vrb_map[first_rb+4] = 1; - vrb_map[first_rb+5] = 1; - - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu)); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = TBS; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFF; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL,first_rb,6); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = rvidx; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1;// first block - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB==1 ) ? 0 : 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB==1 ) ? 1 : 2; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; - // Rel10 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = 3; - // Rel13 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 1; // CEModeA UE - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 0; // SIB1-BR - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = 0xFFFF; // absolute SFx - - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; - dl_req->number_pdu++; - - // Program TX Request - TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; - TX_req->pdu_length = bcch_sdu_length; - TX_req->pdu_index = eNB->pdu_index[CC_id]++; - TX_req->num_segments = 1; - TX_req->segments[0].segment_length = bcch_sdu_length; - TX_req->segments[0].segment_data = cc->BCCH_BR_pdu[0].payload; - eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; - - - - if (opt_enabled == 1) { - trace_pdu(1, - &cc->BCCH_BR_pdu[0].payload[0], - bcch_sdu_length, - 0xffff, - 4, - 0xffff, - eNB->frame, - eNB->subframe, - 0, - 0); - LOG_D(OPT,"[eNB %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", - module_idP, frameP, CC_id, 0xffff, bcch_sdu_length); - } - if (cc->tdd_Config!=NULL) { //TDD - LOG_D(MAC,"[eNB] Frame %d : Scheduling BCCH-BR 0->DLSCH (TDD) for CC_id %d SIB1-BR %d bytes\n", - frameP, - CC_id, - bcch_sdu_length); - } else { - LOG_D(MAC,"[eNB] Frame %d : Scheduling BCCH-BR 0->DLSCH (FDD) for CC_id %d SIB1-BR %d bytes\n", - frameP, - CC_id, - bcch_sdu_length); - } - - } - - return; -} - -int si_WindowLength_BR_r13tab[SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_spare] = - {20,40,60,80,120,160,200}; -int si_TBS_r13tab[SchedulingInfo_BR_r13__si_TBS_r13_b936+1] = {152,208,256,328,408,504,600,712,808,936}; - -//------------------------------------------------------------------------------ -void -schedule_SI_BR( - module_id_t module_idP, - frame_t frameP, - sub_frame_t subframeP) - -//------------------------------------------------------------------------------ -{ - - int8_t bcch_sdu_length; - int CC_id; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc; - uint8_t *vrb_map; - int first_rb = -1; - int N_RB_DL; - nfapi_dl_config_request_pdu_t *dl_config_pdu; - nfapi_tx_request_pdu_t *TX_req; - nfapi_dl_config_request_body_t *dl_req; - int i; - int rvidx; - int absSF = (frameP*10)+subframeP; - - - for (CC_id=0; CC_idcommon_channels[CC_id]; - vrb_map = (void*)&cc->vrb_map; - N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); - dl_req = &eNB->DL_req[CC_id].dl_config_request_body; - - // Time-domain scheduling - if (cc->mib->message.schedulingInfoSIB1_BR_r13==0) continue; - else { - - - AssertFatal(cc->sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13!=NULL, - "sib_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n"); - - SchedulingInfoList_BR_r13_t *schedulingInfoList_BR_r13 = cc->sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->schedulingInfoList_BR_r13; - AssertFatal(schedulingInfoList_BR_r13!=NULL, - "sib_v13ext->schedulingInfoList_BR_r13 is null\n"); - - SchedulingInfoList_t *schedulingInfoList = cc->schedulingInfoList; - AssertFatal(schedulingInfoList_BR_r13->list.count==schedulingInfoList->list.count, - "schedulingInfolist_BR.r13->list.count %d != schedulingInfoList.list.count %d\n", - schedulingInfoList_BR_r13->list.count,schedulingInfoList->list.count); - - AssertFatal(cc->sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13<=SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_ms200, - "si_WindowLength_BR_r13 %d > %d\n", - (int)cc->sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13, - SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_ms200); - - // check that SI frequency-hopping is disabled - AssertFatal(cc->sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_HoppingConfigCommon_r13==SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_HoppingConfigCommon_r13_off, - "Deactivate SI_HoppingConfigCommon_r13 in configuration file, not supported for now\n"); - long si_WindowLength_BR_r13 = si_WindowLength_BR_r13tab[cc->sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13]; - - long si_RepetitionPattern_r13 = cc->sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_RepetitionPattern_r13; - AssertFatal(si_RepetitionPattern_r13<=SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_RepetitionPattern_r13_every8thRF, - "si_RepetitionPattern_r13 %d > %d\n", - (int)si_RepetitionPattern_r13, - SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_RepetitionPattern_r13_every8thRF); - // cycle through SIB list - - for (i=0;ilist.count;i++) { - long si_Periodicity = schedulingInfoList->list.array[i]->si_Periodicity; - long si_Narrowband_r13 = schedulingInfoList_BR_r13->list.array[i]->si_Narrowband_r13; - long si_TBS_r13 = si_TBS_r13tab[schedulingInfoList_BR_r13->list.array[i]->si_TBS_r13]; - - // check if the SI is to be scheduled now - int period_in_sf = 80<>1) + (k&1))&3; - - if ((sf_mod_period < si_WindowLength_BR_r13) && - ((frameP&(((1<BCCH_BR_pdu[i+1].payload[0], - 1, - module_idP, - 0); // not used in this case - - AssertFatal(bcch_sdu_length>0,"RRC returned 0 bytes for SI-BR %d\n",i); - - if (bcch_sdu_length > 0) { - AssertFatal(bcch_sdu_length <= (si_TBS_r13>>3), - "RRC provided bcch with length %d > %d (si_TBS_r13 %d)\n", - bcch_sdu_length,(int)(si_TBS_r13>>3),(int)schedulingInfoList_BR_r13->list.array[i]->si_TBS_r13); - - // allocate all 6 PRBs in narrowband for SIB1_BR - - // check that SIB1 didn't take this narrowband - if (vrb_map[first_rb] > 0) continue; - - first_rb = narrowband_to_first_rb(cc,si_Narrowband_r13-1); - vrb_map[first_rb] = 1; - vrb_map[first_rb+1] = 1; - vrb_map[first_rb+2] = 1; - vrb_map[first_rb+4] = 1; - vrb_map[first_rb+5] = 1; - - if ((frameP&1023) < 200) LOG_D(MAC,"[eNB %d] Frame %d Subframe %d: SI_BR->DLSCH CC_id %d, Narrowband %d rvidx %d (sf_mod_period %d : si_WindowLength_BR_r13 %d : si_RepetitionPattern_r13 %d) bcch_sdu_length %d\n", - module_idP,frameP,subframeP,CC_id,(int)si_Narrowband_r13-1,rvidx, - sf_mod_period,(int)si_WindowLength_BR_r13,(int)si_RepetitionPattern_r13, - bcch_sdu_length); - - - - - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu)); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = si_TBS_r13>>3; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFF; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL,first_rb,6); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = rvidx; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1;// first block - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB==1 ) ? 0 : 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB==1 ) ? 1 : 2; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; - // Rel10 fields (for PDSCH starting symbol) - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; - // Rel13 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 1; // CEModeA UE - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 1; // SI-BR - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = absSF - sf_mod_period; - - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; - dl_req->number_pdu++; - - // Program TX Request - TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; - TX_req->pdu_length = bcch_sdu_length; - TX_req->pdu_index = eNB->pdu_index[CC_id]++; - TX_req->num_segments = 1; - TX_req->segments[0].segment_length = bcch_sdu_length; - TX_req->segments[0].segment_data = cc->BCCH_BR_pdu[i+1].payload; - eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; - - if (opt_enabled == 1) { - trace_pdu(1, - &cc->BCCH_BR_pdu[i+1].payload[0], - bcch_sdu_length, - 0xffff, - 4, - 0xffff, - eNB->frame, - eNB->subframe, - 0, - 0); - LOG_D(OPT,"[eNB %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", - module_idP, frameP, CC_id, 0xffff, bcch_sdu_length); + // Time-domain scheduling + if (cc->mib->message.schedulingInfoSIB1_BR_r13 == 0) + continue; + else + switch ((cc->mib->message.schedulingInfoSIB1_BR_r13 - 1) % 3) { + case 0: // repetition 4 + k = (frameP >> 1) & 3; + if ((subframeP != (4 + sfoffset)) + || ((frameP & 1) != foffset)) + continue; + break; + case 1: // repetition 8 + k = frameP & 3; + AssertFatal(N_RB_DL > 15, + "SIB1-BR repetition 8 not allowed for N_RB_DL= %d\n", + N_RB_DL); + if ((foffset == 0) && (subframeP != (4 + sfoffset))) + continue; + else if ((foffset == 1) + && (subframeP != ((9 + sfoffset) % 10))) + continue; + break; + case 2: // repetition 16 + k = ((10 * frameP) + subframeP) & 3; + AssertFatal(N_RB_DL > 15, + "SIB1-BR repetition 16 not allowed for N_RB_DL= %d\n", + N_RB_DL); + if ((sfoffset == 1) + && ((subframeP != 0) || (subframeP != 5))) + continue; + else if ((sfoffset == 0) && (foffset == 0) + && (subframeP != 4) && (subframeP != 9)) + continue; + else if ((sfoffset == 0) && (foffset == 1) + && (subframeP != 0) && (subframeP != 9)) + continue; + break; } - if (cc->tdd_Config!=NULL) { //TDD - LOG_D(MAC,"[eNB] Frame %d : Scheduling BCCH-BR %d->DLSCH (TDD) for CC_id %d SI-BR %d bytes\n", - frameP,i, - CC_id, - bcch_sdu_length); - } else { - LOG_D(MAC,"[eNB] Frame %d : Scheduling BCCH-BR %d->DLSCH (FDD) for CC_id %d SI-BR %d bytes\n", - frameP,i, - CC_id, - bcch_sdu_length); - } - } - } // scheduling in current frame/subframe - } //for SI List - } // eMTC is activated - } // CC_id - return; -} -#endif + // if we get here we have to schedule SIB1_BR in this frame/subframe -void schedule_mib(module_id_t module_idP, - frame_t frameP, - sub_frame_t subframeP) { + // keep counter of SIB1_BR repetitions in 8 frame period to choose narrowband on which to transmit + if ((frameP & 7) == 0) + cc->SIB1_BR_cnt = 0; + else + cc->SIB1_BR_cnt++; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc; - nfapi_dl_config_request_pdu_t *dl_config_pdu; - nfapi_tx_request_pdu_t *TX_req; - int mib_sdu_length; - int CC_id; - nfapi_dl_config_request_body_t *dl_req; - - AssertFatal(subframeP==0,"Subframe must be 0\n"); - AssertFatal((frameP&3)==0,"Frame must be a multiple of 4\n"); - - for (CC_id=0; CC_idDL_req[CC_id].dl_config_request_body; - cc = &eNB->common_channels[CC_id]; - - mib_sdu_length = mac_rrc_data_req(module_idP, - CC_id, - frameP, - MIBCH,1, - &cc->MIB_pdu.payload[0], - 1, - module_idP, - 0); // not used in this case - - LOG_D(MAC,"Frame %d, subframe %d: BCH PDU length %d\n", - frameP,subframeP,mib_sdu_length); - - if (mib_sdu_length > 0) { - - LOG_D(MAC,"Frame %d, subframe %d: Adding BCH PDU in position %d (length %d)\n", - frameP,subframeP,dl_req->number_pdu,mib_sdu_length); - - if ((frameP&1023) < 40) LOG_D(MAC,"[eNB %d] Frame %d : MIB->BCH CC_id %d, Received %d bytes (cc->mib->message.schedulingInfoSIB1_BR_r13 %d)\n",module_idP,frameP,CC_id,mib_sdu_length,(int)cc->mib->message.schedulingInfoSIB1_BR_r13); - - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_BCH_PDU_TYPE, - dl_config_pdu->pdu_size = 2+sizeof(nfapi_dl_config_bch_pdu); - dl_config_pdu->bch_pdu.bch_pdu_rel8.length = mib_sdu_length; - dl_config_pdu->bch_pdu.bch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; - dl_config_pdu->bch_pdu.bch_pdu_rel8.transmission_power = 6000; - dl_req->number_pdu++; - - LOG_D(MAC,"eNB->DL_req[0].number_pdu %d (%p)\n", - dl_req->number_pdu,&dl_req->number_pdu); - // DL request - - TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; - TX_req->pdu_length = 3; - TX_req->pdu_index = eNB->pdu_index[CC_id]++; - TX_req->num_segments = 1; - TX_req->segments[0].segment_length = 0; - TX_req->segments[0].segment_data = cc[CC_id].MIB_pdu.payload; - eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; - } - } -} - - -//------------------------------------------------------------------------------ -void -schedule_SI( - module_id_t module_idP, - frame_t frameP, - sub_frame_t subframeP) - -//------------------------------------------------------------------------------ -{ - - int8_t bcch_sdu_length; - int mcs = -1; - int CC_id; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc; - uint8_t *vrb_map; - int first_rb = -1; - int N_RB_DL; - nfapi_dl_config_request_pdu_t *dl_config_pdu; - nfapi_tx_request_pdu_t *TX_req; - nfapi_dl_config_request_body_t *dl_req; - - start_meas(&eNB->schedule_si); - - // Only schedule LTE System Information in subframe 5 - if (subframeP == 5) { - - for (CC_id=0; CC_idcommon_channels[CC_id]; - vrb_map = (void*)&cc->vrb_map; - N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); - dl_req = &eNB->DL_req[CC_id].dl_config_request_body; - - - bcch_sdu_length = mac_rrc_data_req(module_idP, - CC_id, - frameP, - BCCH,1, - &cc->BCCH_pdu.payload[0], - 1, - module_idP, - 0); // not used in this case - - if (bcch_sdu_length > 0) { - LOG_D(MAC,"[eNB %d] Frame %d : BCCH->DLSCH CC_id %d, Received %d bytes \n",module_idP,frameP,CC_id,bcch_sdu_length); - - // Allocate 4 PRBs in a random location - /* - while (1) { - first_rb = (unsigned char)(taus()%(PHY_vars_eNB_g[module_idP][CC_id]->frame_parms.N_RB_DL-4)); - if ((vrb_map[first_rb] != 1) && - (vrb_map[first_rb+1] != 1) && - (vrb_map[first_rb+2] != 1) && - (vrb_map[first_rb+3] != 1)) - break; - } - */ + // Frequency-domain scheduling switch (N_RB_DL) { case 6: - first_rb = 0; - break; case 15: - first_rb = 6; - break; + default: + m = 1; + n_NB = 0; + N_S_NB = 0; + Sj = NULL; + break; case 25: - first_rb = 11; - break; + m = 2; + N_S_NB = 2; + Sj = Sj25; + break; case 50: - first_rb = 23; - break; + m = 2; + N_S_NB = 6; + Sj = Sj50; + break; + case 75: + m = 4; + N_S_NB = 10; + Sj = Sj75; + break; case 100: - first_rb = 48; - break; + m = 4; + N_S_NB = 14; + Sj = Sj100; + break; } - + // Note: definition of k above and rvidx from 36.321 section 5.3.1 + rvidx = (((3 * k) >> 1) + (k & 1)) & 3; + + i = cc->SIB1_BR_cnt & (m - 1); + + n_NB = Sj[((cc->physCellId % N_S_NB) + (i * N_S_NB / m)) % N_S_NB]; + + + bcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, BCCH_SIB1_BR, 1, &cc->BCCH_BR_pdu[0].payload[0], 1, module_idP, 0); // not used in this case + + AssertFatal(cc->mib->message.schedulingInfoSIB1_BR_r13 < 19, + "schedulingInfoSIB1_BR_r13 %d > 18\n", + (int) cc->mib->message.schedulingInfoSIB1_BR_r13); + + AssertFatal(bcch_sdu_length > 0, + "RRC returned 0 bytes for SIB1-BR\n"); + + TBS = + SIB1_BR_TBS_table[(cc->mib->message.schedulingInfoSIB1_BR_r13 - + 1) / 3] >> 3; + + AssertFatal(bcch_sdu_length <= TBS, + "length returned by RRC %d is not compatible with the TBS %d from MIB\n", + bcch_sdu_length, TBS); + + if ((frameP & 1023) < 200) + LOG_D(MAC, + "[eNB %d] Frame %d Subframe %d: SIB1_BR->DLSCH CC_id %d, Received %d bytes, scheduling on NB %d (i %d,m %d,N_S_NB %d) rvidx %d\n", + module_idP, frameP, subframeP, CC_id, bcch_sdu_length, + n_NB, i, m, N_S_NB, rvidx); + + // allocate all 6 PRBs in narrowband for SIB1_BR + + first_rb = narrowband_to_first_rb(cc, n_NB); + vrb_map[first_rb] = 1; - vrb_map[first_rb+1] = 1; - vrb_map[first_rb+2] = 1; - vrb_map[first_rb+3] = 1; - - // Get MCS for length of SI, 3 PRBs - if (bcch_sdu_length <= 7) { - mcs=0; - } else if (bcch_sdu_length <= 11) { - mcs=1; - } else if (bcch_sdu_length <= 18) { - mcs=2; - } else if (bcch_sdu_length <= 22) { - mcs=3; - } else if (bcch_sdu_length <= 26) { - mcs=4; - } else if (bcch_sdu_length <= 28) { - mcs=5; - } else if (bcch_sdu_length <= 32) { - mcs=6; - } else if (bcch_sdu_length <= 41) { - mcs=7; - } else if (bcch_sdu_length <= 49) { - mcs=8; - } - - - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu)); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = 4; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = 0xFFFF; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 2; // S-RNTI : see Table 4-10 from SCF082 - nFAPI specifications - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power - - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = 0; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // no TPC - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = 0; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = 0; - - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = getRIV(N_RB_DL,first_rb,4); + vrb_map[first_rb + 1] = 1; + vrb_map[first_rb + 2] = 1; + vrb_map[first_rb + 3] = 1; + vrb_map[first_rb + 4] = 1; + vrb_map[first_rb + 5] = 1; + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = TBS; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = + eNB->pdu_index[CC_id]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFF; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = + getRIV(N_RB_DL, first_rb, 6); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = rvidx; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = + (cc->p_eNB == 1) ? 0 : 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = + 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = + (cc->p_eNB == 1) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; // Rel10 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = 3; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = 3; // Rel13 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 0; // regular UE - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not BR - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = 0xFFFF; // absolute SF + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 1; // CEModeA UE + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 0; // SIB1-BR + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = 0xFFFF; // absolute SFx + + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; + dl_req->number_pdu++; + + // Program TX Request + TX_req = + &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB-> + TX_req + [CC_id].tx_request_body.number_of_pdus]; + TX_req->pdu_length = bcch_sdu_length; + TX_req->pdu_index = eNB->pdu_index[CC_id]++; + TX_req->num_segments = 1; + TX_req->segments[0].segment_length = bcch_sdu_length; + TX_req->segments[0].segment_data = cc->BCCH_BR_pdu[0].payload; + eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; + + - if (!CCE_allocation_infeasible(module_idP,CC_id,0,subframeP, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,SI_RNTI)) { - LOG_D(MAC,"Frame %d: Subframe %d : Adding common DCI for S_RNTI\n", - frameP,subframeP); - dl_req->number_dci++; - dl_req->number_pdu++; - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu)); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFF; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL,first_rb,4); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1;// first block - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB==1 ) ? 0 : 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB==1 ) ? 1 : 2; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; - dl_req->number_pdu++; - - // Program TX Request - TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; - TX_req->pdu_length = bcch_sdu_length; - TX_req->pdu_index = eNB->pdu_index[CC_id]++; - TX_req->num_segments = 1; - TX_req->segments[0].segment_length = bcch_sdu_length; - TX_req->segments[0].segment_data = cc->BCCH_pdu.payload; - eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; - - } - else { - LOG_E(MAC,"[eNB %d] CCid %d Frame %d, subframe %d : Cannot add DCI 1A for SI\n",module_idP, CC_id,frameP,subframeP); - } - if (opt_enabled == 1) { - trace_pdu(1, - &cc->BCCH_pdu.payload[0], - bcch_sdu_length, - 0xffff, - 4, - 0xffff, - eNB->frame, - eNB->subframe, - 0, - 0); - LOG_D(OPT,"[eNB %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", - module_idP, frameP, CC_id, 0xffff, bcch_sdu_length); + trace_pdu(1, + &cc->BCCH_BR_pdu[0].payload[0], + bcch_sdu_length, + 0xffff, 4, 0xffff, eNB->frame, eNB->subframe, 0, 0); + LOG_D(OPT, + "[eNB %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", + module_idP, frameP, CC_id, 0xffff, bcch_sdu_length); } - if (cc->tdd_Config!=NULL) { //TDD - LOG_D(MAC,"[eNB] Frame %d : Scheduling BCCH->DLSCH (TDD) for CC_id %d SI %d bytes (mcs %d, rb 3)\n", - frameP, - CC_id, - bcch_sdu_length, - mcs); + if (cc->tdd_Config != NULL) { //TDD + LOG_D(MAC, + "[eNB] Frame %d : Scheduling BCCH-BR 0->DLSCH (TDD) for CC_id %d SIB1-BR %d bytes\n", + frameP, CC_id, bcch_sdu_length); } else { - LOG_D(MAC,"[eNB] Frame %d : Scheduling BCCH->DLSCH (FDD) for CC_id %d SI %d bytes (mcs %d, rb 3)\n", - frameP, - CC_id, - bcch_sdu_length, - mcs); + LOG_D(MAC, + "[eNB] Frame %d : Scheduling BCCH-BR 0->DLSCH (FDD) for CC_id %d SIB1-BR %d bytes\n", + frameP, CC_id, bcch_sdu_length); } - - - eNB->eNB_stats[CC_id].total_num_bcch_pdu+=1; - eNB->eNB_stats[CC_id].bcch_buffer=bcch_sdu_length; - eNB->eNB_stats[CC_id].total_bcch_buffer+=bcch_sdu_length; - eNB->eNB_stats[CC_id].bcch_mcs=mcs; - } else { - - //LOG_D(MAC,"[eNB %d] Frame %d : BCCH not active \n",Mod_id,frame); - } - } - } -#ifdef Rel14 - schedule_SIB1_BR(module_idP,frameP,subframeP); - schedule_SI_BR(module_idP,frameP,subframeP); + } + + return; +} + +int si_WindowLength_BR_r13tab + [SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_spare] += { 20, 40, 60, 80, 120, 160, 200 }; +int si_TBS_r13tab[SchedulingInfo_BR_r13__si_TBS_r13_b936 + 1] = + { 152, 208, 256, 328, 408, 504, 600, 712, 808, 936 }; + +//------------------------------------------------------------------------------ +void +schedule_SI_BR(module_id_t module_idP, frame_t frameP, + sub_frame_t subframeP) +//------------------------------------------------------------------------------ +{ + + int8_t bcch_sdu_length; + int CC_id; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc; + uint8_t *vrb_map; + int first_rb = -1; + int N_RB_DL; + nfapi_dl_config_request_pdu_t *dl_config_pdu; + nfapi_tx_request_pdu_t *TX_req; + nfapi_dl_config_request_body_t *dl_req; + int i; + int rvidx; + int absSF = (frameP * 10) + subframeP; + + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + + cc = &eNB->common_channels[CC_id]; + vrb_map = (void *) &cc->vrb_map; + N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); + dl_req = &eNB->DL_req[CC_id].dl_config_request_body; + + // Time-domain scheduling + if (cc->mib->message.schedulingInfoSIB1_BR_r13 == 0) + continue; + else { + + + AssertFatal(cc-> + sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 + != NULL, + "sib_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n"); + + SchedulingInfoList_BR_r13_t *schedulingInfoList_BR_r13 = + cc->sib1_v13ext-> + bandwidthReducedAccessRelatedInfo_r13->schedulingInfoList_BR_r13; + AssertFatal(schedulingInfoList_BR_r13 != NULL, + "sib_v13ext->schedulingInfoList_BR_r13 is null\n"); + + SchedulingInfoList_t *schedulingInfoList = + cc->schedulingInfoList; + AssertFatal(schedulingInfoList_BR_r13->list.count == + schedulingInfoList->list.count, + "schedulingInfolist_BR.r13->list.count %d != schedulingInfoList.list.count %d\n", + schedulingInfoList_BR_r13->list.count, + schedulingInfoList->list.count); + + AssertFatal(cc-> + sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13 + <= + SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_ms200, + "si_WindowLength_BR_r13 %d > %d\n", + (int) cc-> + sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13, + SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_ms200); + + // check that SI frequency-hopping is disabled + AssertFatal(cc-> + sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_HoppingConfigCommon_r13 + == + SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_HoppingConfigCommon_r13_off, + "Deactivate SI_HoppingConfigCommon_r13 in configuration file, not supported for now\n"); + long si_WindowLength_BR_r13 = + si_WindowLength_BR_r13tab[cc-> + sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13]; + + long si_RepetitionPattern_r13 = + cc->sib1_v13ext-> + bandwidthReducedAccessRelatedInfo_r13->si_RepetitionPattern_r13; + AssertFatal(si_RepetitionPattern_r13 <= + SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_RepetitionPattern_r13_every8thRF, + "si_RepetitionPattern_r13 %d > %d\n", + (int) si_RepetitionPattern_r13, + SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_RepetitionPattern_r13_every8thRF); + // cycle through SIB list + + for (i = 0; i < schedulingInfoList_BR_r13->list.count; i++) { + long si_Periodicity = + schedulingInfoList->list.array[i]->si_Periodicity; + long si_Narrowband_r13 = + schedulingInfoList_BR_r13->list.array[i]-> + si_Narrowband_r13; + long si_TBS_r13 = + si_TBS_r13tab[schedulingInfoList_BR_r13-> + list.array[i]->si_TBS_r13]; + + // check if the SI is to be scheduled now + int period_in_sf = 80 << si_Periodicity; // 2^i * 80 subframes, note: si_Periodicity is 2^i * 80ms + int sf_mod_period = absSF % period_in_sf; + int k = sf_mod_period & 3; + // Note: definition of k and rvidx from 36.321 section 5.3.1 + rvidx = (((3 * k) >> 1) + (k & 1)) & 3; + + if ((sf_mod_period < si_WindowLength_BR_r13) + && ((frameP & (((1 << si_RepetitionPattern_r13) - 1))) == 0)) { // this SIB is to be scheduled + + bcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, BCCH_SI_BR + i, 1, &cc->BCCH_BR_pdu[i + 1].payload[0], 1, module_idP, 0); // not used in this case + + AssertFatal(bcch_sdu_length > 0, + "RRC returned 0 bytes for SI-BR %d\n", i); + + if (bcch_sdu_length > 0) { + AssertFatal(bcch_sdu_length <= (si_TBS_r13 >> 3), + "RRC provided bcch with length %d > %d (si_TBS_r13 %d)\n", + bcch_sdu_length, + (int) (si_TBS_r13 >> 3), + (int) schedulingInfoList_BR_r13-> + list.array[i]->si_TBS_r13); + + // allocate all 6 PRBs in narrowband for SIB1_BR + + // check that SIB1 didn't take this narrowband + if (vrb_map[first_rb] > 0) + continue; + + first_rb = + narrowband_to_first_rb(cc, + si_Narrowband_r13 - 1); + vrb_map[first_rb] = 1; + vrb_map[first_rb + 1] = 1; + vrb_map[first_rb + 2] = 1; + vrb_map[first_rb + 4] = 1; + vrb_map[first_rb + 5] = 1; + + if ((frameP & 1023) < 200) + LOG_D(MAC, + "[eNB %d] Frame %d Subframe %d: SI_BR->DLSCH CC_id %d, Narrowband %d rvidx %d (sf_mod_period %d : si_WindowLength_BR_r13 %d : si_RepetitionPattern_r13 %d) bcch_sdu_length %d\n", + module_idP, frameP, subframeP, CC_id, + (int) si_Narrowband_r13 - 1, rvidx, + sf_mod_period, + (int) si_WindowLength_BR_r13, + (int) si_RepetitionPattern_r13, + bcch_sdu_length); + + + + + dl_config_pdu = + &dl_req->dl_config_pdu_list[dl_req-> + number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = + NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = + si_TBS_r13 >> 3; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = + eNB->pdu_index[CC_id]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = + 0xFFFF; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.resource_block_coding = + getRIV(N_RB_DL, first_rb, 6); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.redundancy_version = rvidx; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.transport_block_to_codeword_swap_flag + = 0; + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.transmission_scheme = + (cc->p_eNB == 1) ? 0 : 1; + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.number_of_layers = 1; + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.number_of_subbands = 1; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.ue_category_capacity = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.delta_power_offset_index = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.transmission_mode = + (cc->p_eNB == 1) ? 1 : 2; + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.num_bf_prb_per_subband = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + num_bf_vector = 1; + // Rel10 fields (for PDSCH starting symbol) + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10. + pdsch_start = + cc[CC_id]. + sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; + // Rel13 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 1; // CEModeA UE + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 1; // SI-BR + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel13.initial_transmission_sf_io = + absSF - sf_mod_period; + + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; + dl_req->number_pdu++; + + // Program TX Request + TX_req = + &eNB->TX_req[CC_id]. + tx_request_body.tx_pdu_list[eNB->TX_req[CC_id]. + tx_request_body.number_of_pdus]; + TX_req->pdu_length = bcch_sdu_length; + TX_req->pdu_index = eNB->pdu_index[CC_id]++; + TX_req->num_segments = 1; + TX_req->segments[0].segment_length = + bcch_sdu_length; + TX_req->segments[0].segment_data = + cc->BCCH_BR_pdu[i + 1].payload; + eNB->TX_req[CC_id].tx_request_body. + number_of_pdus++; + + if (opt_enabled == 1) { + trace_pdu(1, + &cc->BCCH_BR_pdu[i + 1].payload[0], + bcch_sdu_length, + 0xffff, + 4, + 0xffff, eNB->frame, eNB->subframe, 0, + 0); + LOG_D(OPT, + "[eNB %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", + module_idP, frameP, CC_id, 0xffff, + bcch_sdu_length); + } + if (cc->tdd_Config != NULL) { //TDD + LOG_D(MAC, + "[eNB] Frame %d : Scheduling BCCH-BR %d->DLSCH (TDD) for CC_id %d SI-BR %d bytes\n", + frameP, i, CC_id, bcch_sdu_length); + } else { + LOG_D(MAC, + "[eNB] Frame %d : Scheduling BCCH-BR %d->DLSCH (FDD) for CC_id %d SI-BR %d bytes\n", + frameP, i, CC_id, bcch_sdu_length); + } + } + } // scheduling in current frame/subframe + } //for SI List + } // eMTC is activated + } // CC_id + return; +} #endif - stop_meas(&eNB->schedule_si); - return; +void +schedule_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) +{ + + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc; + nfapi_dl_config_request_pdu_t *dl_config_pdu; + nfapi_tx_request_pdu_t *TX_req; + int mib_sdu_length; + int CC_id; + nfapi_dl_config_request_body_t *dl_req; + + AssertFatal(subframeP == 0, "Subframe must be 0\n"); + AssertFatal((frameP & 3) == 0, "Frame must be a multiple of 4\n"); + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + + dl_req = &eNB->DL_req[CC_id].dl_config_request_body; + cc = &eNB->common_channels[CC_id]; + + mib_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, MIBCH, 1, &cc->MIB_pdu.payload[0], 1, module_idP, 0); // not used in this case + + LOG_D(MAC, "Frame %d, subframe %d: BCH PDU length %d\n", + frameP, subframeP, mib_sdu_length); + + if (mib_sdu_length > 0) { + + LOG_D(MAC, + "Frame %d, subframe %d: Adding BCH PDU in position %d (length %d)\n", + frameP, subframeP, dl_req->number_pdu, mib_sdu_length); + + if ((frameP & 1023) < 40) + LOG_D(MAC, + "[eNB %d] Frame %d : MIB->BCH CC_id %d, Received %d bytes (cc->mib->message.schedulingInfoSIB1_BR_r13 %d)\n", + module_idP, frameP, CC_id, mib_sdu_length, + (int) cc->mib->message.schedulingInfoSIB1_BR_r13); + + dl_config_pdu = + &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = + NFAPI_DL_CONFIG_BCH_PDU_TYPE, dl_config_pdu->pdu_size = + 2 + sizeof(nfapi_dl_config_bch_pdu); + dl_config_pdu->bch_pdu.bch_pdu_rel8.length = mib_sdu_length; + dl_config_pdu->bch_pdu.bch_pdu_rel8.pdu_index = + eNB->pdu_index[CC_id]; + dl_config_pdu->bch_pdu.bch_pdu_rel8.transmission_power = 6000; + dl_req->number_pdu++; + + LOG_D(MAC, "eNB->DL_req[0].number_pdu %d (%p)\n", + dl_req->number_pdu, &dl_req->number_pdu); + // DL request + + TX_req = + &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req + [CC_id].tx_request_body.number_of_pdus]; + TX_req->pdu_length = 3; + TX_req->pdu_index = eNB->pdu_index[CC_id]++; + TX_req->num_segments = 1; + TX_req->segments[0].segment_length = 0; + TX_req->segments[0].segment_data = cc[CC_id].MIB_pdu.payload; + eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; + } + } +} + + +//------------------------------------------------------------------------------ +void +schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) +//------------------------------------------------------------------------------ +{ + + int8_t bcch_sdu_length; + int mcs = -1; + int CC_id; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc; + uint8_t *vrb_map; + int first_rb = -1; + int N_RB_DL; + nfapi_dl_config_request_pdu_t *dl_config_pdu; + nfapi_tx_request_pdu_t *TX_req; + nfapi_dl_config_request_body_t *dl_req; + + start_meas(&eNB->schedule_si); + + // Only schedule LTE System Information in subframe 5 + if (subframeP == 5) { + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + + cc = &eNB->common_channels[CC_id]; + vrb_map = (void *) &cc->vrb_map; + N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); + dl_req = &eNB->DL_req[CC_id].dl_config_request_body; + + + bcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, BCCH, 1, &cc->BCCH_pdu.payload[0], 1, module_idP, 0); // not used in this case + + if (bcch_sdu_length > 0) { + LOG_D(MAC, + "[eNB %d] Frame %d : BCCH->DLSCH CC_id %d, Received %d bytes \n", + module_idP, frameP, CC_id, bcch_sdu_length); + + // Allocate 4 PRBs in a random location + /* + while (1) { + first_rb = (unsigned char)(taus()%(PHY_vars_eNB_g[module_idP][CC_id]->frame_parms.N_RB_DL-4)); + if ((vrb_map[first_rb] != 1) && + (vrb_map[first_rb+1] != 1) && + (vrb_map[first_rb+2] != 1) && + (vrb_map[first_rb+3] != 1)) + break; + } + */ + switch (N_RB_DL) { + case 6: + first_rb = 0; + break; + case 15: + first_rb = 6; + break; + case 25: + first_rb = 11; + break; + case 50: + first_rb = 23; + break; + case 100: + first_rb = 48; + break; + } + + vrb_map[first_rb] = 1; + vrb_map[first_rb + 1] = 1; + vrb_map[first_rb + 2] = 1; + vrb_map[first_rb + 3] = 1; + + // Get MCS for length of SI, 3 PRBs + if (bcch_sdu_length <= 7) { + mcs = 0; + } else if (bcch_sdu_length <= 11) { + mcs = 1; + } else if (bcch_sdu_length <= 18) { + mcs = 2; + } else if (bcch_sdu_length <= 22) { + mcs = 3; + } else if (bcch_sdu_length <= 26) { + mcs = 4; + } else if (bcch_sdu_length <= 28) { + mcs = 5; + } else if (bcch_sdu_length <= 32) { + mcs = 6; + } else if (bcch_sdu_length <= 41) { + mcs = 7; + } else if (bcch_sdu_length <= 49) { + mcs = 8; + } + + + dl_config_pdu = + &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = + NFAPI_DL_DCI_FORMAT_1A; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level = 4; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = 0xFFFF; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 2; // S-RNTI : see Table 4-10 from SCF082 - nFAPI specifications + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // no TPC + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + new_data_indicator_1 = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + redundancy_version_1 = 0; + + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.resource_block_coding = + getRIV(N_RB_DL, first_rb, 4); + + // Rel10 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = 3; + // Rel13 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 0; // regular UE + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not BR + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = 0xFFFF; // absolute SF + + if (!CCE_allocation_infeasible + (module_idP, CC_id, 0, subframeP, + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level, SI_RNTI)) { + LOG_D(MAC, + "Frame %d: Subframe %d : Adding common DCI for S_RNTI\n", + frameP, subframeP); + dl_req->number_dci++; + dl_req->number_pdu++; + dl_config_pdu = + &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = + NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = + eNB->pdu_index[CC_id]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFF; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.resource_block_coding = + getRIV(N_RB_DL, first_rb, 4); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + redundancy_version = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.transport_block_to_codeword_swap_flag + = 0; + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.transmission_scheme = + (cc->p_eNB == 1) ? 0 : 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + number_of_layers = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + number_of_subbands = 1; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.ue_category_capacity = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.delta_power_offset_index = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + transmission_mode = (cc->p_eNB == 1) ? 1 : 2; + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.num_bf_prb_per_subband = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = + 1; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; + dl_req->number_pdu++; + + // Program TX Request + TX_req = + &eNB->TX_req[CC_id]. + tx_request_body.tx_pdu_list[eNB->TX_req[CC_id]. + tx_request_body.number_of_pdus]; + TX_req->pdu_length = bcch_sdu_length; + TX_req->pdu_index = eNB->pdu_index[CC_id]++; + TX_req->num_segments = 1; + TX_req->segments[0].segment_length = bcch_sdu_length; + TX_req->segments[0].segment_data = + cc->BCCH_pdu.payload; + eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; + + } else { + LOG_E(MAC, + "[eNB %d] CCid %d Frame %d, subframe %d : Cannot add DCI 1A for SI\n", + module_idP, CC_id, frameP, subframeP); + } + + if (opt_enabled == 1) { + trace_pdu(1, + &cc->BCCH_pdu.payload[0], + bcch_sdu_length, + 0xffff, + 4, 0xffff, eNB->frame, eNB->subframe, 0, 0); + LOG_D(OPT, + "[eNB %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", + module_idP, frameP, CC_id, 0xffff, + bcch_sdu_length); + } + if (cc->tdd_Config != NULL) { //TDD + LOG_D(MAC, + "[eNB] Frame %d : Scheduling BCCH->DLSCH (TDD) for CC_id %d SI %d bytes (mcs %d, rb 3)\n", + frameP, CC_id, bcch_sdu_length, mcs); + } else { + LOG_D(MAC, + "[eNB] Frame %d : Scheduling BCCH->DLSCH (FDD) for CC_id %d SI %d bytes (mcs %d, rb 3)\n", + frameP, CC_id, bcch_sdu_length, mcs); + } + + + eNB->eNB_stats[CC_id].total_num_bcch_pdu += 1; + eNB->eNB_stats[CC_id].bcch_buffer = bcch_sdu_length; + eNB->eNB_stats[CC_id].total_bcch_buffer += bcch_sdu_length; + eNB->eNB_stats[CC_id].bcch_mcs = mcs; + } else { + + //LOG_D(MAC,"[eNB %d] Frame %d : BCCH not active \n",Mod_id,frame); + } + } + } +#ifdef Rel14 + schedule_SIB1_BR(module_idP, frameP, subframeP); + schedule_SI_BR(module_idP, frameP, subframeP); +#endif + + stop_meas(&eNB->schedule_si); + return; } - diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 3e767ec516..9dbbb39d03 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -51,10 +51,10 @@ //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" -#include "SIMULATION/TOOLS/defs.h" // for taus +#include "SIMULATION/TOOLS/defs.h" // for taus #if defined(ENABLE_ITTI) -# include "intertask_interface.h" +#include "intertask_interface.h" #endif #include "T.h" @@ -66,347 +66,346 @@ extern RAN_CONTEXT_t RC; //------------------------------------------------------------------------------ void -add_ue_dlsch_info( - module_id_t module_idP, - int CC_id, - int UE_id, - sub_frame_t subframeP, - UE_DLSCH_STATUS status -) +add_ue_dlsch_info(module_id_t module_idP, + int CC_id, + int UE_id, sub_frame_t subframeP, UE_DLSCH_STATUS status) //------------------------------------------------------------------------------ { - eNB_dlsch_info[module_idP][CC_id][UE_id].rnti = UE_RNTI(module_idP,UE_id); - // eNB_dlsch_info[module_idP][CC_id][ue_mod_idP].weight = weight; - eNB_dlsch_info[module_idP][CC_id][UE_id].subframe = subframeP; - eNB_dlsch_info[module_idP][CC_id][UE_id].status = status; + eNB_dlsch_info[module_idP][CC_id][UE_id].rnti = + UE_RNTI(module_idP, UE_id); + // eNB_dlsch_info[module_idP][CC_id][ue_mod_idP].weight = weight; + eNB_dlsch_info[module_idP][CC_id][UE_id].subframe = subframeP; + eNB_dlsch_info[module_idP][CC_id][UE_id].status = status; - eNB_dlsch_info[module_idP][CC_id][UE_id].serving_num++; + eNB_dlsch_info[module_idP][CC_id][UE_id].serving_num++; } //------------------------------------------------------------------------------ int -schedule_next_dlue( - module_id_t module_idP, - int CC_id, - sub_frame_t subframeP -) +schedule_next_dlue(module_id_t module_idP, int CC_id, + sub_frame_t subframeP) //------------------------------------------------------------------------------ { - int next_ue; - UE_list_t *UE_list=&RC.mac[module_idP]->UE_list; + int next_ue; + UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; - for (next_ue=UE_list->head; next_ue>=0; next_ue=UE_list->next[next_ue] ) { - if (eNB_dlsch_info[module_idP][CC_id][next_ue].status == S_DL_WAITING) { - return next_ue; + for (next_ue = UE_list->head; next_ue >= 0; + next_ue = UE_list->next[next_ue]) { + if (eNB_dlsch_info[module_idP][CC_id][next_ue].status == + S_DL_WAITING) { + return next_ue; + } } - } - for (next_ue=UE_list->head; next_ue>=0; next_ue=UE_list->next[next_ue] ) { - if (eNB_dlsch_info[module_idP][CC_id][next_ue].status == S_DL_BUFFERED) { - eNB_dlsch_info[module_idP][CC_id][next_ue].status = S_DL_WAITING; + for (next_ue = UE_list->head; next_ue >= 0; + next_ue = UE_list->next[next_ue]) { + if (eNB_dlsch_info[module_idP][CC_id][next_ue].status == + S_DL_BUFFERED) { + eNB_dlsch_info[module_idP][CC_id][next_ue].status = + S_DL_WAITING; + } } - } - return(-1);//next_ue; + return (-1); //next_ue; } //------------------------------------------------------------------------------ unsigned char -generate_dlsch_header( - unsigned char* mac_header, - unsigned char num_sdus, - unsigned short *sdu_lengths, - unsigned char *sdu_lcids, - unsigned char drx_cmd, - unsigned short timing_advance_cmd, - unsigned char *ue_cont_res_id, - unsigned char short_padding, - unsigned short post_padding -) +generate_dlsch_header(unsigned char *mac_header, + unsigned char num_sdus, + unsigned short *sdu_lengths, + unsigned char *sdu_lcids, + unsigned char drx_cmd, + unsigned short timing_advance_cmd, + unsigned char *ue_cont_res_id, + unsigned char short_padding, + unsigned short post_padding) //------------------------------------------------------------------------------ { - SCH_SUBHEADER_FIXED *mac_header_ptr = (SCH_SUBHEADER_FIXED *)mac_header; - uint8_t first_element=0,last_size=0,i; - uint8_t mac_header_control_elements[16],*ce_ptr; + SCH_SUBHEADER_FIXED *mac_header_ptr = + (SCH_SUBHEADER_FIXED *) mac_header; + uint8_t first_element = 0, last_size = 0, i; + uint8_t mac_header_control_elements[16], *ce_ptr; - ce_ptr = &mac_header_control_elements[0]; + ce_ptr = &mac_header_control_elements[0]; - // compute header components + // compute header components - if ((short_padding == 1) || (short_padding == 2)) { - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = SHORT_PADDING; - first_element=1; - last_size=1; - } - - if (short_padding == 2) { - mac_header_ptr->E = 1; - mac_header_ptr++; - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = SHORT_PADDING; - last_size=1; - } - - if (drx_cmd != 255) { - if (first_element>0) { - mac_header_ptr->E = 1; - mac_header_ptr++; - } else { - first_element=1; + if ((short_padding == 1) || (short_padding == 2)) { + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = SHORT_PADDING; + first_element = 1; + last_size = 1; } - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = DRX_CMD; - last_size=1; - } - - if (timing_advance_cmd != 31) { - if (first_element>0) { - mac_header_ptr->E = 1; - mac_header_ptr++; - } else { - first_element=1; + if (short_padding == 2) { + mac_header_ptr->E = 1; + mac_header_ptr++; + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = SHORT_PADDING; + last_size = 1; } - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = TIMING_ADV_CMD; - last_size=1; - // msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); - ((TIMING_ADVANCE_CMD *)ce_ptr)->R=0; - AssertFatal(timing_advance_cmd < 64,"timing_advance_cmd %d > 63\n",timing_advance_cmd); - ((TIMING_ADVANCE_CMD *)ce_ptr)->TA=timing_advance_cmd;//(timing_advance_cmd+31)&0x3f; - LOG_D(MAC,"timing advance =%d (%d)\n",timing_advance_cmd,((TIMING_ADVANCE_CMD *)ce_ptr)->TA); - ce_ptr+=sizeof(TIMING_ADVANCE_CMD); - //msg("offset %d\n",ce_ptr-mac_header_control_elements); - } + if (drx_cmd != 255) { + if (first_element > 0) { + mac_header_ptr->E = 1; + mac_header_ptr++; + } else { + first_element = 1; + } - if (ue_cont_res_id) { - if (first_element>0) { - mac_header_ptr->E = 1; - /* - printf("[eNB][MAC] last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); - */ - mac_header_ptr++; - } else { - first_element=1; + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = DRX_CMD; + last_size = 1; } - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = UE_CONT_RES; - last_size=1; + if (timing_advance_cmd != 31) { + if (first_element > 0) { + mac_header_ptr->E = 1; + mac_header_ptr++; + } else { + first_element = 1; + } - LOG_T(MAC,"[eNB ][RAPROC] Generate contention resolution msg: %x.%x.%x.%x.%x.%x\n", - ue_cont_res_id[0], - ue_cont_res_id[1], - ue_cont_res_id[2], - ue_cont_res_id[3], - ue_cont_res_id[4], - ue_cont_res_id[5]); - - memcpy(ce_ptr,ue_cont_res_id,6); - ce_ptr+=6; - // msg("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements); - } - - //msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); - - for (i=0; i0) { - mac_header_ptr->E = 1; - /*msg("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); - */ - mac_header_ptr+=last_size; - //msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); - } else { - first_element=1; + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = TIMING_ADV_CMD; + last_size = 1; + // msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); + ((TIMING_ADVANCE_CMD *) ce_ptr)->R = 0; + AssertFatal(timing_advance_cmd < 64, + "timing_advance_cmd %d > 63\n", timing_advance_cmd); + ((TIMING_ADVANCE_CMD *) ce_ptr)->TA = timing_advance_cmd; //(timing_advance_cmd+31)&0x3f; + LOG_D(MAC, "timing advance =%d (%d)\n", timing_advance_cmd, + ((TIMING_ADVANCE_CMD *) ce_ptr)->TA); + ce_ptr += sizeof(TIMING_ADVANCE_CMD); + //msg("offset %d\n",ce_ptr-mac_header_control_elements); } - if (sdu_lengths[i] < 128) { - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R = 0; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->E = 0; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F = 0; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->LCID = sdu_lcids[i]; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L = (unsigned char)sdu_lengths[i]; - last_size=2; - } else { - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->R = 0; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->E = 0; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->F = 1; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->LCID = sdu_lcids[i]; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_MSB = ((unsigned short) sdu_lengths[i]>>8)&0x7f; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB = (unsigned short) sdu_lengths[i]&0xff; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->padding = 0x00; - last_size=3; + if (ue_cont_res_id) { + if (first_element > 0) { + mac_header_ptr->E = 1; + /* + printf("[eNB][MAC] last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); + */ + mac_header_ptr++; + } else { + first_element = 1; + } + + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = UE_CONT_RES; + last_size = 1; + + LOG_T(MAC, + "[eNB ][RAPROC] Generate contention resolution msg: %x.%x.%x.%x.%x.%x\n", + ue_cont_res_id[0], ue_cont_res_id[1], ue_cont_res_id[2], + ue_cont_res_id[3], ue_cont_res_id[4], ue_cont_res_id[5]); + + memcpy(ce_ptr, ue_cont_res_id, 6); + ce_ptr += 6; + // msg("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements); + } + //msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); + + for (i = 0; i < num_sdus; i++) { + LOG_T(MAC, "[eNB] Generate DLSCH header num sdu %d len sdu %d\n", + num_sdus, sdu_lengths[i]); + + if (first_element > 0) { + mac_header_ptr->E = 1; + /*msg("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); + */ + mac_header_ptr += last_size; + //msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); + } else { + first_element = 1; + } + + if (sdu_lengths[i] < 128) { + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->R = 0; + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->E = 0; + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->F = 0; + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->LCID = sdu_lcids[i]; + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->L = + (unsigned char) sdu_lengths[i]; + last_size = 2; + } else { + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->R = 0; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->E = 0; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->F = 1; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->LCID = sdu_lcids[i]; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB = + ((unsigned short) sdu_lengths[i] >> 8) & 0x7f; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_LSB = + (unsigned short) sdu_lengths[i] & 0xff; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->padding = 0x00; + last_size = 3; #ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[eNB] generate long sdu, size %x (MSB %x, LSB %x)\n", - sdu_lengths[i], - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_MSB, - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB); + LOG_D(MAC, + "[eNB] generate long sdu, size %x (MSB %x, LSB %x)\n", + sdu_lengths[i], + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB, + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_LSB); #endif + } } - } - /* + /* - printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); + printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); - printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); + printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); - if (((SCH_SUBHEADER_FIXED*)mac_header_ptr)->LCID < UE_CONT_RES) { - if (((SCH_SUBHEADER_SHORT*)mac_header_ptr)->F == 0) - printf("F = 0, sdu len (L field) %d\n",(((SCH_SUBHEADER_SHORT*)mac_header_ptr)->L)); - else - printf("F = 1, sdu len (L field) %d\n",(((SCH_SUBHEADER_LONG*)mac_header_ptr)->L)); + if (((SCH_SUBHEADER_FIXED*)mac_header_ptr)->LCID < UE_CONT_RES) { + if (((SCH_SUBHEADER_SHORT*)mac_header_ptr)->F == 0) + printf("F = 0, sdu len (L field) %d\n",(((SCH_SUBHEADER_SHORT*)mac_header_ptr)->L)); + else + printf("F = 1, sdu len (L field) %d\n",(((SCH_SUBHEADER_LONG*)mac_header_ptr)->L)); + } + */ + if (post_padding > 0) { // we have lots of padding at the end of the packet + mac_header_ptr->E = 1; + mac_header_ptr += last_size; + // add a padding element + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = SHORT_PADDING; + mac_header_ptr++; + } else { // no end of packet padding + // last SDU subhead is of fixed type (sdu length implicitly to be computed at UE) + mac_header_ptr++; } - */ - if (post_padding>0) {// we have lots of padding at the end of the packet - mac_header_ptr->E = 1; - mac_header_ptr+=last_size; - // add a padding element - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = SHORT_PADDING; - mac_header_ptr++; - } else { // no end of packet padding - // last SDU subhead is of fixed type (sdu length implicitly to be computed at UE) - mac_header_ptr++; - } - //msg("After subheaders %d\n",(uint8_t*)mac_header_ptr - mac_header); + //msg("After subheaders %d\n",(uint8_t*)mac_header_ptr - mac_header); - if ((ce_ptr-mac_header_control_elements) > 0) { - // printf("Copying %d bytes for control elements\n",ce_ptr-mac_header_control_elements); - memcpy((void*)mac_header_ptr,mac_header_control_elements,ce_ptr-mac_header_control_elements); - mac_header_ptr+=(unsigned char)(ce_ptr-mac_header_control_elements); - } + if ((ce_ptr - mac_header_control_elements) > 0) { + // printf("Copying %d bytes for control elements\n",ce_ptr-mac_header_control_elements); + memcpy((void *) mac_header_ptr, mac_header_control_elements, + ce_ptr - mac_header_control_elements); + mac_header_ptr += + (unsigned char) (ce_ptr - mac_header_control_elements); + } + //msg("After CEs %d\n",(uint8_t*)mac_header_ptr - mac_header); - //msg("After CEs %d\n",(uint8_t*)mac_header_ptr - mac_header); - - return((unsigned char*)mac_header_ptr - mac_header); + return ((unsigned char *) mac_header_ptr - mac_header); } //------------------------------------------------------------------------------ void -set_ul_DAI( - int module_idP, - int UE_idP, - int CC_idP, - int frameP, - int subframeP -) +set_ul_DAI(int module_idP, int UE_idP, int CC_idP, int frameP, + int subframeP) //------------------------------------------------------------------------------ { - eNB_MAC_INST *eNB = RC.mac[module_idP]; - UE_list_t *UE_list = &eNB->UE_list; - unsigned char DAI; - COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; - if (cc->tdd_Config != NULL) { //TDD - DAI = (UE_list->UE_template[CC_idP][UE_idP].DAI-1)&3; - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d, subframe %d: DAI %d for UE %d\n",module_idP,CC_idP,frameP,subframeP,DAI,UE_idP); - // Save DAI for Format 0 DCI + eNB_MAC_INST *eNB = RC.mac[module_idP]; + UE_list_t *UE_list = &eNB->UE_list; + unsigned char DAI; + COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; + if (cc->tdd_Config != NULL) { //TDD + DAI = (UE_list->UE_template[CC_idP][UE_idP].DAI - 1) & 3; + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d, subframe %d: DAI %d for UE %d\n", + module_idP, CC_idP, frameP, subframeP, DAI, UE_idP); + // Save DAI for Format 0 DCI - switch (cc->tdd_Config->subframeAssignment) { - case 0: - // if ((subframeP==0)||(subframeP==1)||(subframeP==5)||(subframeP==6)) - break; + switch (cc->tdd_Config->subframeAssignment) { + case 0: + // if ((subframeP==0)||(subframeP==1)||(subframeP==5)||(subframeP==6)) + break; - case 1: - switch (subframeP) { - case 1: - UE_list->UE_template[CC_idP][UE_idP].DAI_ul[7] = DAI; - break; + case 1: + switch (subframeP) { + case 1: + UE_list->UE_template[CC_idP][UE_idP].DAI_ul[7] = DAI; + break; - case 4: - UE_list->UE_template[CC_idP][UE_idP].DAI_ul[8] = DAI; - break; + case 4: + UE_list->UE_template[CC_idP][UE_idP].DAI_ul[8] = DAI; + break; - case 6: - UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI; - break; + case 6: + UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI; + break; - case 9: - UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI; - break; - } + case 9: + UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI; + break; + } - case 2: - // if ((subframeP==3)||(subframeP==8)) - // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; - break; + case 2: + // if ((subframeP==3)||(subframeP==8)) + // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; + break; - case 3: + case 3: - //if ((subframeP==6)||(subframeP==8)||(subframeP==0)) { - // LOG_D(MAC,"schedule_ue_spec: setting UL DAI to %d for subframeP %d => %d\n",DAI,subframeP, ((subframeP+8)%10)>>1); - // UE_list->UE_template[CC_idP][UE_idP].DAI_ul[((subframeP+8)%10)>>1] = DAI; - //} - switch (subframeP) { - case 5: - case 6: - case 1: - UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI; - break; + //if ((subframeP==6)||(subframeP==8)||(subframeP==0)) { + // LOG_D(MAC,"schedule_ue_spec: setting UL DAI to %d for subframeP %d => %d\n",DAI,subframeP, ((subframeP+8)%10)>>1); + // UE_list->UE_template[CC_idP][UE_idP].DAI_ul[((subframeP+8)%10)>>1] = DAI; + //} + switch (subframeP) { + case 5: + case 6: + case 1: + UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI; + break; - case 7: - case 8: - UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI; - break; + case 7: + case 8: + UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI; + break; - case 9: - case 0: - UE_list->UE_template[CC_idP][UE_idP].DAI_ul[4] = DAI; - break; + case 9: + case 0: + UE_list->UE_template[CC_idP][UE_idP].DAI_ul[4] = DAI; + break; - default: - break; - } + default: + break; + } - break; + break; - case 4: - // if ((subframeP==8)||(subframeP==9)) - // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; - break; + case 4: + // if ((subframeP==8)||(subframeP==9)) + // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; + break; - case 5: - // if (subframeP==8) - // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; - break; + case 5: + // if (subframeP==8) + // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; + break; - case 6: - // if ((subframeP==1)||(subframeP==4)||(subframeP==6)||(subframeP==9)) - // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; - break; + case 6: + // if ((subframeP==1)||(subframeP==4)||(subframeP==6)||(subframeP==9)) + // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; + break; - default: - break; + default: + break; + } } - } } @@ -414,1130 +413,1342 @@ set_ul_DAI( //------------------------------------------------------------------------------ void -schedule_ue_spec( - module_id_t module_idP, - frame_t frameP, - sub_frame_t subframeP, - int* mbsfn_flag -) +schedule_ue_spec(module_id_t module_idP, + frame_t frameP, sub_frame_t subframeP, int *mbsfn_flag) //------------------------------------------------------------------------------ { - uint8_t CC_id; - int UE_id; - unsigned char aggregation; - mac_rlc_status_resp_t rlc_status; - unsigned char header_len_dcch=0, header_len_dcch_tmp=0; - unsigned char header_len_dtch=0, header_len_dtch_tmp=0, header_len_dtch_last=0; - unsigned char ta_len=0; - unsigned char sdu_lcids[NB_RB_MAX],lcid,offset,num_sdus=0; - uint16_t nb_rb,nb_rb_temp,nb_available_rb; - uint16_t TBS,j,sdu_lengths[NB_RB_MAX],rnti,padding=0,post_padding=0; - unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; - unsigned char round = 0; - unsigned char harq_pid = 0; - eNB_UE_STATS *eNB_UE_stats = NULL; - uint16_t sdu_length_total = 0; + uint8_t CC_id; + int UE_id; + unsigned char aggregation; + mac_rlc_status_resp_t rlc_status; + unsigned char header_len_dcch = 0, header_len_dcch_tmp = 0; + unsigned char header_len_dtch = 0, header_len_dtch_tmp = + 0, header_len_dtch_last = 0; + unsigned char ta_len = 0; + unsigned char sdu_lcids[NB_RB_MAX], lcid, offset, num_sdus = 0; + uint16_t nb_rb, nb_rb_temp, nb_available_rb; + uint16_t TBS, j, sdu_lengths[NB_RB_MAX], rnti, padding = + 0, post_padding = 0; + unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; + unsigned char round = 0; + unsigned char harq_pid = 0; + eNB_UE_STATS *eNB_UE_stats = NULL; + uint16_t sdu_length_total = 0; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = eNB->common_channels; - UE_list_t *UE_list = &eNB->UE_list; - int continue_flag=0; - int32_t normalized_rx_power, target_rx_power; - int32_t tpc=1; - static int32_t tpc_accumulated=0; - UE_sched_ctrl *ue_sched_ctl; - int mcs; - int i; - int min_rb_unit[MAX_NUM_CCs]; - int N_RB_DL[MAX_NUM_CCs]; - int total_nb_available_rb[MAX_NUM_CCs]; - int N_RBG[MAX_NUM_CCs]; - nfapi_dl_config_request_body_t *dl_req; - nfapi_dl_config_request_pdu_t *dl_config_pdu; - int tdd_sfa; - int ta_update; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc = eNB->common_channels; + UE_list_t *UE_list = &eNB->UE_list; + int continue_flag = 0; + int32_t normalized_rx_power, target_rx_power; + int32_t tpc = 1; + static int32_t tpc_accumulated = 0; + UE_sched_ctrl *ue_sched_ctl; + int mcs; + int i; + int min_rb_unit[MAX_NUM_CCs]; + int N_RB_DL[MAX_NUM_CCs]; + int total_nb_available_rb[MAX_NUM_CCs]; + int N_RBG[MAX_NUM_CCs]; + nfapi_dl_config_request_body_t *dl_req; + nfapi_dl_config_request_pdu_t *dl_config_pdu; + int tdd_sfa; + int ta_update; #if 0 - if (UE_list->head==-1) { - return; - } + if (UE_list->head == -1) { + return; + } #endif - start_meas(&eNB->schedule_dlsch); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_IN); + start_meas(&eNB->schedule_dlsch); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_IN); - // for TDD: check that we have to act here, otherwise return - if (cc[0].tdd_Config) { - tdd_sfa = cc[0].tdd_Config->subframeAssignment; - switch (subframeP) { - case 0: - // always continue - break; - case 1: - return; - break; - case 2: - return; - break; - case 3: - if ((tdd_sfa!=2) && (tdd_sfa!=5)) return; - break; - case 4: - if ((tdd_sfa!=1)&&(tdd_sfa!=2)&&(tdd_sfa!=4)&&(tdd_sfa!=5)) return; - break; - case 5: - break; - case 6: - case 7: - if ((tdd_sfa!=1)&&(tdd_sfa!=2)&&(tdd_sfa!=4)&&(tdd_sfa!=5)) return; - break; - case 8: - if ((tdd_sfa!=2)&&(tdd_sfa!=3)&&(tdd_sfa!=4)&&(tdd_sfa!=5)) return; - break; - case 9: - if ((tdd_sfa!=1)&&(tdd_sfa!=3)&&(tdd_sfa!=4)&&(tdd_sfa!=6)) return; - break; - + // for TDD: check that we have to act here, otherwise return + if (cc[0].tdd_Config) { + tdd_sfa = cc[0].tdd_Config->subframeAssignment; + switch (subframeP) { + case 0: + // always continue + break; + case 1: + return; + break; + case 2: + return; + break; + case 3: + if ((tdd_sfa != 2) && (tdd_sfa != 5)) + return; + break; + case 4: + if ((tdd_sfa != 1) && (tdd_sfa != 2) && (tdd_sfa != 4) + && (tdd_sfa != 5)) + return; + break; + case 5: + break; + case 6: + case 7: + if ((tdd_sfa != 1) && (tdd_sfa != 2) && (tdd_sfa != 4) + && (tdd_sfa != 5)) + return; + break; + case 8: + if ((tdd_sfa != 2) && (tdd_sfa != 3) && (tdd_sfa != 4) + && (tdd_sfa != 5)) + return; + break; + case 9: + if ((tdd_sfa != 1) && (tdd_sfa != 3) && (tdd_sfa != 4) + && (tdd_sfa != 6)) + return; + break; + + } } - } + //weight = get_ue_weight(module_idP,UE_id); + aggregation = 2; + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + N_RB_DL[CC_id] = to_prb(cc[CC_id].mib->message.dl_Bandwidth); + min_rb_unit[CC_id] = get_min_rb_unit(module_idP, CC_id); + // get number of PRBs less those used by common channels + total_nb_available_rb[CC_id] = N_RB_DL[CC_id]; + for (i = 0; i < N_RB_DL[CC_id]; i++) + if (cc[CC_id].vrb_map[i] != 0) + total_nb_available_rb[CC_id]--; - //weight = get_ue_weight(module_idP,UE_id); - aggregation = 2; - for (CC_id=0; CC_idmessage.dl_Bandwidth); - min_rb_unit[CC_id]=get_min_rb_unit(module_idP,CC_id); - // get number of PRBs less those used by common channels - total_nb_available_rb[CC_id] = N_RB_DL[CC_id]; - for (i=0;imessage.dl_Bandwidth); - N_RBG[CC_id] = to_rbg(cc[CC_id].mib->message.dl_Bandwidth); + // store the global enb stats: + eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs; + eNB->eNB_stats[CC_id].available_prbs = + total_nb_available_rb[CC_id]; + eNB->eNB_stats[CC_id].total_available_prbs += + total_nb_available_rb[CC_id]; + eNB->eNB_stats[CC_id].dlsch_bytes_tx = 0; + eNB->eNB_stats[CC_id].dlsch_pdus_tx = 0; + } - // store the global enb stats: - eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs; - eNB->eNB_stats[CC_id].available_prbs = total_nb_available_rb[CC_id]; - eNB->eNB_stats[CC_id].total_available_prbs += total_nb_available_rb[CC_id]; - eNB->eNB_stats[CC_id].dlsch_bytes_tx = 0; - eNB->eNB_stats[CC_id].dlsch_pdus_tx = 0; - } + /// CALLING Pre_Processor for downlink scheduling (Returns estimation of RBs required by each UE and the allocation on sub-band) - /// CALLING Pre_Processor for downlink scheduling (Returns estimation of RBs required by each UE and the allocation on sub-band) + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_IN); + start_meas(&eNB->schedule_dlsch_preprocessor); + dlsch_scheduler_pre_processor(module_idP, + frameP, subframeP, N_RBG, mbsfn_flag); + stop_meas(&eNB->schedule_dlsch_preprocessor); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_OUT); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR,VCD_FUNCTION_IN); - start_meas(&eNB->schedule_dlsch_preprocessor); - dlsch_scheduler_pre_processor(module_idP, - frameP, - subframeP, - N_RBG, - mbsfn_flag); - stop_meas(&eNB->schedule_dlsch_preprocessor); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR,VCD_FUNCTION_OUT); + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n", CC_id); - for (CC_id=0; CC_idDL_req[CC_id].dl_config_request_body; - dl_req = &eNB->DL_req[CC_id].dl_config_request_body; + if (mbsfn_flag[CC_id] > 0) + continue; - if (mbsfn_flag[CC_id]>0) - continue; - - for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { - continue_flag=0; // reset the flag to allow allocation for the remaining UEs - rnti = UE_RNTI(module_idP,UE_id); - eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + for (UE_id = UE_list->head; UE_id >= 0; + UE_id = UE_list->next[UE_id]) { + continue_flag = 0; // reset the flag to allow allocation for the remaining UEs + rnti = UE_RNTI(module_idP, UE_id); + eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - if (rnti==NOT_A_RNTI) { - LOG_D(MAC,"Cannot find rnti for UE_id %d (num_UEs %d)\n",UE_id,UE_list->num_UEs); - continue_flag=1; - } + if (rnti == NOT_A_RNTI) { + LOG_D(MAC, "Cannot find rnti for UE_id %d (num_UEs %d)\n", + UE_id, UE_list->num_UEs); + continue_flag = 1; + } - if (eNB_UE_stats==NULL) { - LOG_D(MAC,"[eNB] Cannot find eNB_UE_stats\n"); - continue_flag=1; - } + if (eNB_UE_stats == NULL) { + LOG_D(MAC, "[eNB] Cannot find eNB_UE_stats\n"); + continue_flag = 1; + } - if (continue_flag != 1){ - switch(get_tmode(module_idP,CC_id,UE_id)){ - case 1: - case 2: - case 7: - aggregation = get_aggregation(get_bw_index(module_idP,CC_id), + if (continue_flag != 1) { + switch (get_tmode(module_idP, CC_id, UE_id)) { + case 1: + case 2: + case 7: + aggregation = + get_aggregation(get_bw_index(module_idP, CC_id), ue_sched_ctl->dl_cqi[CC_id], format1); - break; - case 3: - aggregation = get_aggregation(get_bw_index(module_idP,CC_id), + break; + case 3: + aggregation = + get_aggregation(get_bw_index(module_idP, CC_id), ue_sched_ctl->dl_cqi[CC_id], format2A); - break; - default: - LOG_W(MAC,"Unsupported transmission mode %d\n", get_tmode(module_idP,CC_id,UE_id)); - aggregation = 2; - } - } /* if (continue_flag != 1 */ + break; + default: + LOG_W(MAC, "Unsupported transmission mode %d\n", + get_tmode(module_idP, CC_id, UE_id)); + aggregation = 2; + } + } + /* if (continue_flag != 1 */ + if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated + CCE_allocation_infeasible(module_idP, CC_id, 1, subframeP, + aggregation, rnti)) { + LOG_D(MAC, + "[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", + module_idP, frameP, UE_id, CC_id); + continue_flag = 1; //to next user (there might be rbs availiable for other UEs in TM5 + } - if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated - CCE_allocation_infeasible(module_idP,CC_id,1,subframeP,aggregation,rnti) - ) { - LOG_D(MAC,"[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", - module_idP, frameP, UE_id, CC_id); - continue_flag=1; //to next user (there might be rbs availiable for other UEs in TM5 - } - - if (cc[CC_id].tdd_Config != NULL) { //TDD - set_ue_dai (subframeP, - UE_id, - CC_id, - cc[CC_id].tdd_Config->subframeAssignment, - UE_list); - // update UL DAI after DLSCH scheduling - set_ul_DAI(module_idP,UE_id,CC_id,frameP,subframeP); - } - - if (continue_flag == 1 ) { - add_ue_dlsch_info(module_idP, - CC_id, - UE_id, - subframeP, - S_DL_NONE); - continue; - } + if (cc[CC_id].tdd_Config != NULL) { //TDD + set_ue_dai(subframeP, + UE_id, + CC_id, + cc[CC_id].tdd_Config->subframeAssignment, + UE_list); + // update UL DAI after DLSCH scheduling + set_ul_DAI(module_idP, UE_id, CC_id, frameP, subframeP); + } + if (continue_flag == 1) { + add_ue_dlsch_info(module_idP, + CC_id, UE_id, subframeP, S_DL_NONE); + continue; + } #warning RK->CR This old API call has to be revisited for FAPI, or logic must be changed #if 0 - /* add "fake" DCI to have CCE_allocation_infeasible work properly for next allocations */ - /* if we don't add it, next allocations may succeed but overall allocations may fail */ - /* will be removed at the end of this function */ - add_ue_spec_dci(&eNB->common_channels[CC_id].DCI_pdu, - &(char[]){0}, - rnti, - 1, - aggregation, - 1, - format1, - 0); + /* add "fake" DCI to have CCE_allocation_infeasible work properly for next allocations */ + /* if we don't add it, next allocations may succeed but overall allocations may fail */ + /* will be removed at the end of this function */ + add_ue_spec_dci(&eNB->common_channels[CC_id].DCI_pdu, &(char[]) { + 0}, rnti, 1, aggregation, 1, format1, 0); #endif - nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; + nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; - if (cc->tdd_Config) harq_pid = ((frameP*10)+subframeP)%10; - else harq_pid = ((frameP*10)+subframeP)&7; + if (cc->tdd_Config) + harq_pid = ((frameP * 10) + subframeP) % 10; + else + harq_pid = ((frameP * 10) + subframeP) & 7; - round = ue_sched_ctl->round[CC_id][harq_pid]; + round = ue_sched_ctl->round[CC_id][harq_pid]; - UE_list->eNB_UE_stats[CC_id][UE_id].crnti= rnti; - UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status=mac_eNB_get_rrc_status(module_idP,rnti); - UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid; - UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round; + UE_list->eNB_UE_stats[CC_id][UE_id].crnti = rnti; + UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status = + mac_eNB_get_rrc_status(module_idP, rnti); + UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid; + UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round; - if (UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status < RRC_CONNECTED) continue; + if (UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status < + RRC_CONNECTED) + continue; - sdu_length_total=0; - num_sdus=0; + sdu_length_total = 0; + num_sdus = 0; - /* - DevCheck(((eNB_UE_stats->dl_cqi < MIN_CQI_VALUE) || (eNB_UE_stats->dl_cqi > MAX_CQI_VALUE)), - eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE); - */ - eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]]; - eNB_UE_stats->dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1;//cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); + /* + DevCheck(((eNB_UE_stats->dl_cqi < MIN_CQI_VALUE) || (eNB_UE_stats->dl_cqi > MAX_CQI_VALUE)), + eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE); + */ + eNB_UE_stats->dlsch_mcs1 = + cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]]; + eNB_UE_stats->dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1; //cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); - // store stats - //UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->dl_cqi; + // store stats + //UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->dl_cqi; - // initializing the rb allocation indicator for each UE - for(j=0; jUE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0; - } - - LOG_D(MAC,"[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n", - module_idP, frameP, UE_id,CC_id,rnti,harq_pid, round,nb_available_rb, - ue_sched_ctl->dl_cqi[CC_id], eNB_UE_stats->dlsch_mcs1, - UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); - - - - /* process retransmission */ - - if (round != 8) { - - // get freq_allocation - nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - TBS = get_TBS_DL(UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid],nb_rb); - - if (nb_rb <= nb_available_rb) { - if (cc[CC_id].tdd_Config != NULL) { - UE_list->UE_template[CC_id][UE_id].DAI++; - update_ul_dci(module_idP,CC_id,rnti,UE_list->UE_template[CC_id][UE_id].DAI); - LOG_D(MAC,"DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", CC_id,subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); - } - - if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { - for(j=0; jUE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - } - } else { - nb_rb_temp = nb_rb; - j = 0; - - while((nb_rb_temp > 0) && (jrballoc_sub_UE[CC_id][j] == 1) { - if (UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]) printf("WARN: rballoc_subband not free for retrans?\n"); - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - - if((j == N_RBG[CC_id]-1) && - ((N_RB_DL[CC_id] == 25)|| - (N_RB_DL[CC_id] == 50))) { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]+1; - } else { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; - } - } - - j = j+1; - } - } - - nb_available_rb -= nb_rb; - /* - eNB->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; - eNB->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; - - for(j=0; jmu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; - } - */ - - switch (get_tmode(module_idP,CC_id,UE_id)) { - case 1: - case 2: - case 7: - default: - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu)); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP,CC_id),ue_sched_ctl->dl_cqi[CC_id],format1); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power - - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = harq_pid; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // dont adjust power when retransmitting - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = round&3; - - if (cc[CC_id].tdd_Config != NULL) { //TDD - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.downlink_assignment_index = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d, mcs %d\n", - module_idP,CC_id,harq_pid,round, - (UE_list->UE_template[CC_id][UE_id].DAI-1), - UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]); - } else { - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, mcs %d\n", - module_idP,CC_id,harq_pid,round, - UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]); - + // initializing the rb allocation indicator for each UE + for (j = 0; j < N_RBG[CC_id]; j++) { + UE_list-> + UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] + = 0; } - if (!CCE_allocation_infeasible(module_idP,CC_id,1,subframeP, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, - rnti)) { - dl_req->number_dci++; - dl_req->number_pdu++; - fill_nfapi_dlsch_config(eNB,dl_req, - TBS, - -1 /* retransmission, no pdu_index */, - rnti, - 0, // type 0 allocation from 7.1.6 in 36.213 - 0, // virtual_resource_block_assignment_flag, unused here - 0, // resource_block_coding, to be filled in later - getQm(UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]), - round&3 , // redundancy version - 1, // transport blocks - 0, // transport block to codeword swap flag - cc[CC_id].p_eNB == 1 ? 0 : 1, // transmission_scheme - 1, // number of layers - 1, // number of subbands - // uint8_t codebook_index, - 4, // UE category capacity - UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated->p_a, - 0, // delta_power_offset for TM5 - 0, // ngap - 0, // nprb - cc[CC_id].p_eNB == 1 ? 1 : 2, // transmission mode - 0, //number of PRBs treated as one subband, not used here - 0 // number of beamforming vectors, not used here - ); - - LOG_D(MAC,"Filled NFAPI configuration for DCI/DLSCH %d, retransmission round %d\n",eNB->pdu_index[CC_id],round); - - program_dlsch_acknak(module_idP,CC_id,UE_id,frameP,subframeP,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx); - // No TX request for retransmission (check if null request for FAPI) - } - else { - LOG_W(MAC,"Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d\%x, infeasible CCE allocation\n", - frameP,subframeP,UE_id,rnti); - } - } + LOG_D(MAC, + "[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n", + module_idP, frameP, UE_id, CC_id, rnti, harq_pid, round, + nb_available_rb, ue_sched_ctl->dl_cqi[CC_id], + eNB_UE_stats->dlsch_mcs1, + UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); - add_ue_dlsch_info(module_idP, - CC_id, - UE_id, - subframeP, - S_DL_SCHEDULED); - - //eNB_UE_stats->dlsch_trials[round]++; - UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1; - UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=eNB_UE_stats->dlsch_mcs1; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=eNB_UE_stats->dlsch_mcs1; - } else { - LOG_D(MAC,"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", - module_idP, frameP, CC_id, UE_id); - } - } else { /* This is a potentially new SDU opportunity */ - - rlc_status.bytes_in_buffer = 0; - // Now check RLC information to compute number of required RBs - // get maximum TBS size for RLC request - TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_available_rb); - // check first for RLC data on DCCH - // add the length for all the control elements (timing adv, drx, etc) : header + payload - if (ue_sched_ctl->ta_timer == 0) { - ta_update = ue_sched_ctl->ta_update; - /* if we send TA then set timer to not send it for a while */ - if (ta_update != 31) - ue_sched_ctl->ta_timer = 20; - /* reset ta_update */ - ue_sched_ctl->ta_update = 31; - } else { - ta_update = 31; - } + /* process retransmission */ - ta_len = (ta_update != 31) ? 2 : 0; + if (round != 8) { - header_len_dcch = 2; // 2 bytes DCCH SDU subheader + // get freq_allocation + nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + TBS = + get_TBS_DL(UE_list-> + UE_template[CC_id][UE_id].oldmcs1[harq_pid], + nb_rb); - if ( TBS-ta_len-header_len_dcch > 0 ) { - rlc_status = mac_rlc_status_ind( - module_idP, - rnti, - module_idP, - frameP, - subframeP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - DCCH, - (TBS-ta_len-header_len_dcch)); // transport block set size + if (nb_rb <= nb_available_rb) { + if (cc[CC_id].tdd_Config != NULL) { + UE_list->UE_template[CC_id][UE_id].DAI++; + update_ul_dci(module_idP, CC_id, rnti, + UE_list->UE_template[CC_id][UE_id]. + DAI); + LOG_D(MAC, + "DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", + CC_id, subframeP, UE_id, + UE_list->UE_template[CC_id][UE_id].DAI); + } - sdu_lengths[0]=0; + if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { + for (j = 0; j < N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band + UE_list->UE_template[CC_id][UE_id]. + rballoc_subband[harq_pid][j] = + ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + } + } else { + nb_rb_temp = nb_rb; + j = 0; - if (rlc_status.bytes_in_buffer > 0) { // There is DCCH to transmit - LOG_D(MAC,"[eNB %d] Frame %d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n", - module_idP,frameP,CC_id,TBS-header_len_dcch); - sdu_lengths[0] = mac_rlc_data_req( - module_idP, - rnti, - module_idP, - frameP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - DCCH, - TBS, //not used - (char *)&dlsch_buffer[0]); + while ((nb_rb_temp > 0) && (j < N_RBG[CC_id])) { + if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == + 1) { + if (UE_list-> + UE_template[CC_id] + [UE_id].rballoc_subband[harq_pid][j]) + printf + ("WARN: rballoc_subband not free for retrans?\n"); + UE_list-> + UE_template[CC_id] + [UE_id].rballoc_subband[harq_pid][j] = + ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), - T_INT(harq_pid), T_INT(DCCH), T_INT(sdu_lengths[0])); + if ((j == N_RBG[CC_id] - 1) && + ((N_RB_DL[CC_id] == 25) || + (N_RB_DL[CC_id] == 50))) { + nb_rb_temp = + nb_rb_temp - min_rb_unit[CC_id] + + 1; + } else { + nb_rb_temp = + nb_rb_temp - min_rb_unit[CC_id]; + } + } - LOG_D(MAC,"[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n",module_idP,CC_id,sdu_lengths[0]); - sdu_length_total = sdu_lengths[0]; - sdu_lcids[0] = DCCH; - UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH]+=1; - UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH]+=sdu_lengths[0]; - num_sdus = 1; + j = j + 1; + } + } + + nb_available_rb -= nb_rb; + /* + eNB->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; + eNB->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; + + for(j=0; jmu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; + } + */ + + switch (get_tmode(module_idP, CC_id, UE_id)) { + case 1: + case 2: + case 7: + default: + dl_config_pdu = + &dl_req->dl_config_pdu_list[dl_req-> + number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = + NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + dci_format = NFAPI_DL_DCI_FORMAT_1; + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level = + get_aggregation(get_bw_index + (module_idP, CC_id), + ue_sched_ctl->dl_cqi[CC_id], + format1); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = + rnti; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + harq_process = harq_pid; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // dont adjust power when retransmitting + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.new_data_indicator_1 = + UE_list->UE_template[CC_id][UE_id]. + oldNDI[harq_pid]; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = + UE_list->UE_template[CC_id][UE_id]. + oldmcs1[harq_pid]; + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.redundancy_version_1 = + round & 3; + + if (cc[CC_id].tdd_Config != NULL) { //TDD + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.downlink_assignment_index = + (UE_list->UE_template[CC_id][UE_id].DAI - + 1) & 3; + LOG_D(MAC, + "[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d, mcs %d\n", + module_idP, CC_id, harq_pid, round, + (UE_list->UE_template[CC_id][UE_id].DAI - + 1), + UE_list-> + UE_template[CC_id][UE_id].oldmcs1 + [harq_pid]); + } else { + LOG_D(MAC, + "[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, mcs %d\n", + module_idP, CC_id, harq_pid, round, + UE_list-> + UE_template[CC_id][UE_id].oldmcs1 + [harq_pid]); + + } + if (!CCE_allocation_infeasible + (module_idP, CC_id, 1, subframeP, + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level, rnti)) { + dl_req->number_dci++; + dl_req->number_pdu++; + + fill_nfapi_dlsch_config(eNB, dl_req, TBS, -1 + /* retransmission, no pdu_index */ + , rnti, 0, // type 0 allocation from 7.1.6 in 36.213 + 0, // virtual_resource_block_assignment_flag, unused here + 0, // resource_block_coding, to be filled in later + getQm(UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]), round & 3, // redundancy version + 1, // transport blocks + 0, // transport block to codeword swap flag + cc[CC_id].p_eNB == 1 ? 0 : 1, // transmission_scheme + 1, // number of layers + 1, // number of subbands + // uint8_t codebook_index, + 4, // UE category capacity + UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated->p_a, 0, // delta_power_offset for TM5 + 0, // ngap + 0, // nprb + cc[CC_id].p_eNB == 1 ? 1 : 2, // transmission mode + 0, //number of PRBs treated as one subband, not used here + 0 // number of beamforming vectors, not used here + ); + + LOG_D(MAC, + "Filled NFAPI configuration for DCI/DLSCH %d, retransmission round %d\n", + eNB->pdu_index[CC_id], round); + + program_dlsch_acknak(module_idP, CC_id, UE_id, + frameP, subframeP, + dl_config_pdu-> + dci_dl_pdu.dci_dl_pdu_rel8. + cce_idx); + // No TX request for retransmission (check if null request for FAPI) + } else { + LOG_W(MAC, + "Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d\%x, infeasible CCE allocation\n", + frameP, subframeP, UE_id, rnti); + } + } + + + add_ue_dlsch_info(module_idP, + CC_id, UE_id, subframeP, + S_DL_SCHEDULED); + + //eNB_UE_stats->dlsch_trials[round]++; + UE_list->eNB_UE_stats[CC_id][UE_id]. + num_retransmission += 1; + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx = + nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id]. + total_rbs_used_retx += nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = + eNB_UE_stats->dlsch_mcs1; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = + eNB_UE_stats->dlsch_mcs1; + } else { + LOG_D(MAC, + "[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", + module_idP, frameP, CC_id, UE_id); + } + } else { /* This is a potentially new SDU opportunity */ + + rlc_status.bytes_in_buffer = 0; + // Now check RLC information to compute number of required RBs + // get maximum TBS size for RLC request + TBS = + get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb); + // check first for RLC data on DCCH + // add the length for all the control elements (timing adv, drx, etc) : header + payload + + if (ue_sched_ctl->ta_timer == 0) { + ta_update = ue_sched_ctl->ta_update; + /* if we send TA then set timer to not send it for a while */ + if (ta_update != 31) + ue_sched_ctl->ta_timer = 20; + /* reset ta_update */ + ue_sched_ctl->ta_update = 31; + } else { + ta_update = 31; + } + + ta_len = (ta_update != 31) ? 2 : 0; + + header_len_dcch = 2; // 2 bytes DCCH SDU subheader + + if (TBS - ta_len - header_len_dcch > 0) { + rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, (TBS - ta_len - header_len_dcch)); // transport block set size + + sdu_lengths[0] = 0; + + if (rlc_status.bytes_in_buffer > 0) { // There is DCCH to transmit + LOG_D(MAC, + "[eNB %d] Frame %d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n", + module_idP, frameP, CC_id, + TBS - header_len_dcch); + sdu_lengths[0] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, TBS, //not used + (char *) + &dlsch_buffer + [0]); + + T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), + T_INT(CC_id), T_INT(rnti), T_INT(frameP), + T_INT(subframeP), T_INT(harq_pid), T_INT(DCCH), + T_INT(sdu_lengths[0])); + + LOG_D(MAC, + "[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n", + module_idP, CC_id, sdu_lengths[0]); + sdu_length_total = sdu_lengths[0]; + sdu_lcids[0] = DCCH; + UE_list->eNB_UE_stats[CC_id][UE_id]. + num_pdu_tx[DCCH] += 1; + UE_list-> + eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH] + += sdu_lengths[0]; + num_sdus = 1; #ifdef DEBUG_eNB_SCHEDULER - LOG_T(MAC,"[eNB %d][DCCH] CC_id %d Got %d bytes :",module_idP,CC_id,sdu_lengths[0]); + LOG_T(MAC, + "[eNB %d][DCCH] CC_id %d Got %d bytes :", + module_idP, CC_id, sdu_lengths[0]); - for (j=0; j 0 ) { - rlc_status = mac_rlc_status_ind( - module_idP, - rnti, - module_idP, - frameP, - subframeP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - DCCH+1, - (TBS-ta_len-header_len_dcch-sdu_length_total)); // transport block set size less allocations for timing advance and - // DCCH SDU - sdu_lengths[num_sdus] = 0; + } else { + header_len_dcch = 0; + sdu_length_total = 0; + } + } + // check for DCCH1 and update header information (assume 2 byte sub-header) + if (TBS - ta_len - header_len_dcch - sdu_length_total > 0) { + rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, (TBS - ta_len - header_len_dcch - sdu_length_total)); // transport block set size less allocations for timing advance and + // DCCH SDU + sdu_lengths[num_sdus] = 0; - if (rlc_status.bytes_in_buffer > 0) { - LOG_D(MAC,"[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", - module_idP,frameP,CC_id,TBS-header_len_dcch-sdu_length_total); - sdu_lengths[num_sdus] += mac_rlc_data_req( - module_idP, - rnti, - module_idP, - frameP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - DCCH+1, - TBS, //not used - (char *)&dlsch_buffer[sdu_length_total]); + if (rlc_status.bytes_in_buffer > 0) { + LOG_D(MAC, + "[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", + module_idP, frameP, CC_id, + TBS - header_len_dcch - sdu_length_total); + sdu_lengths[num_sdus] += mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, TBS, //not used + (char *) + &dlsch_buffer + [sdu_length_total]); - T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), - T_INT(harq_pid), T_INT(DCCH+1), T_INT(sdu_lengths[num_sdus])); + T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), + T_INT(CC_id), T_INT(rnti), T_INT(frameP), + T_INT(subframeP), T_INT(harq_pid), + T_INT(DCCH + 1), T_INT(sdu_lengths[num_sdus])); - sdu_lcids[num_sdus] = DCCH1; - sdu_length_total += sdu_lengths[num_sdus]; - header_len_dcch += 2; - UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH1]+=1; - UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1]+=sdu_lengths[num_sdus]; - num_sdus++; + sdu_lcids[num_sdus] = DCCH1; + sdu_length_total += sdu_lengths[num_sdus]; + header_len_dcch += 2; + UE_list->eNB_UE_stats[CC_id][UE_id]. + num_pdu_tx[DCCH1] += 1; + UE_list-> + eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1] + += sdu_lengths[num_sdus]; + num_sdus++; #ifdef DEBUG_eNB_SCHEDULER - LOG_T(MAC,"[eNB %d][DCCH1] CC_id %d Got %d bytes :",module_idP,CC_id,sdu_lengths[num_sdus]); + LOG_T(MAC, + "[eNB %d][DCCH1] CC_id %d Got %d bytes :", + module_idP, CC_id, sdu_lengths[num_sdus]); - for (j=0; j= DTCH; lcid--) { + // TBD: check if the lcid is active - // assume the max dtch header size, and adjust it later - header_len_dtch=0; - header_len_dtch_last=0; // the header length of the last mac sdu - // lcid has to be sorted before the actual allocation (similar struct as ue_list). - for (lcid=NB_RB_MAX-1; lcid>=DTCH ; lcid--){ - // TBD: check if the lcid is active - - header_len_dtch+=3; - header_len_dtch_last=3; - LOG_D(MAC,"[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n", - module_idP,frameP,lcid,TBS, - TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); - - if (TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch > 0 ) { // NN: > 2 ? - rlc_status = mac_rlc_status_ind(module_idP, - rnti, - module_idP, - frameP, - subframeP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); - + header_len_dtch += 3; + header_len_dtch_last = 3; + LOG_D(MAC, + "[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n", + module_idP, frameP, lcid, TBS, + TBS - ta_len - header_len_dcch - + sdu_length_total - header_len_dtch); - if (rlc_status.bytes_in_buffer > 0) { - - LOG_D(MAC,"[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n", - module_idP,frameP,TBS-header_len_dcch-sdu_length_total-header_len_dtch,lcid, header_len_dtch); - sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, - rnti, - module_idP, - frameP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - TBS, //not used - (char*)&dlsch_buffer[sdu_length_total]); - T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), - T_INT(harq_pid), T_INT(lcid), T_INT(sdu_lengths[num_sdus])); + if (TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch > 0) { // NN: > 2 ? + rlc_status = mac_rlc_status_ind(module_idP, + rnti, + module_idP, + frameP, + subframeP, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + TBS - ta_len - + header_len_dcch - + sdu_length_total - + header_len_dtch); - LOG_D(MAC,"[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n",module_idP,sdu_lengths[num_sdus],lcid); - sdu_lcids[num_sdus] = lcid; - sdu_length_total += sdu_lengths[num_sdus]; - UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid]+=1; - UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[lcid]+=sdu_lengths[num_sdus]; - if (sdu_lengths[num_sdus] < 128) { - header_len_dtch--; - header_len_dtch_last--; - } - num_sdus++; - } // no data for this LCID - else { - header_len_dtch-=3; - } - } // no TBS left - else { - header_len_dtch-=3; - break; - } - } - if (header_len_dtch == 0 ) - header_len_dtch_last= 0; - // there is at least one SDU - // if (num_sdus > 0 ){ - if ((sdu_length_total + header_len_dcch + header_len_dtch )> 0) { - - // Now compute number of required RBs for total sdu length - // Assume RAH format 2 - // adjust header lengths - header_len_dcch_tmp = header_len_dcch; - header_len_dtch_tmp = header_len_dtch; - if (header_len_dtch==0) { - header_len_dcch = (header_len_dcch >0) ? 1 : 0;//header_len_dcch; // remove length field - } else { - header_len_dtch_last-=1; // now use it to find how many bytes has to be removed for the last MAC SDU - header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last :header_len_dtch; // remove length field for the last SDU - } - mcs = eNB_UE_stats->dlsch_mcs1; + if (rlc_status.bytes_in_buffer > 0) { - if (mcs==0) { - nb_rb = 4; // don't let the TBS get too small - } else { - nb_rb=min_rb_unit[CC_id]; - } + LOG_D(MAC, + "[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n", + module_idP, frameP, + TBS - header_len_dcch - + sdu_length_total - header_len_dtch, lcid, + header_len_dtch); + sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, TBS, //not used + (char + *) + &dlsch_buffer + [sdu_length_total]); + T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), + T_INT(CC_id), T_INT(rnti), T_INT(frameP), + T_INT(subframeP), T_INT(harq_pid), + T_INT(lcid), T_INT(sdu_lengths[num_sdus])); - TBS = get_TBS_DL(mcs,nb_rb); + LOG_D(MAC, + "[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n", + module_idP, sdu_lengths[num_sdus], lcid); + sdu_lcids[num_sdus] = lcid; + sdu_length_total += sdu_lengths[num_sdus]; + UE_list-> + eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid] + += 1; + UE_list-> + eNB_UE_stats[CC_id][UE_id].num_bytes_tx + [lcid] += sdu_lengths[num_sdus]; + if (sdu_lengths[num_sdus] < 128) { + header_len_dtch--; + header_len_dtch_last--; + } + num_sdus++; + } // no data for this LCID + else { + header_len_dtch -= 3; + } + } // no TBS left + else { + header_len_dtch -= 3; + break; + } + } + if (header_len_dtch == 0) + header_len_dtch_last = 0; + // there is at least one SDU + // if (num_sdus > 0 ){ + if ((sdu_length_total + header_len_dcch + + header_len_dtch) > 0) { - while (TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) { - nb_rb += min_rb_unit[CC_id]; // + // Now compute number of required RBs for total sdu length + // Assume RAH format 2 + // adjust header lengths + header_len_dcch_tmp = header_len_dcch; + header_len_dtch_tmp = header_len_dtch; + if (header_len_dtch == 0) { + header_len_dcch = (header_len_dcch > 0) ? 1 : 0; //header_len_dcch; // remove length field + } else { + header_len_dtch_last -= 1; // now use it to find how many bytes has to be removed for the last MAC SDU + header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last : header_len_dtch; // remove length field for the last SDU + } - if (nb_rb>nb_available_rb) { // if we've gone beyond the maximum number of RBs - // (can happen if N_RB_DL is odd) - TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_available_rb); - nb_rb = nb_available_rb; - break; - } + mcs = eNB_UE_stats->dlsch_mcs1; - TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_rb); - } + if (mcs == 0) { + nb_rb = 4; // don't let the TBS get too small + } else { + nb_rb = min_rb_unit[CC_id]; + } - if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { - for(j=0; jUE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - } - } else { - nb_rb_temp = nb_rb; - j = 0; + TBS = get_TBS_DL(mcs, nb_rb); - while((nb_rb_temp > 0) && (jrballoc_sub_UE[CC_id][j] == 1) { - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + while (TBS < + (sdu_length_total + header_len_dcch + + header_len_dtch + ta_len)) { + nb_rb += min_rb_unit[CC_id]; // - if ((j == N_RBG[CC_id]-1) && - ((N_RB_DL[CC_id] == 25)|| - (N_RB_DL[CC_id] == 50))) { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]+1; - } else { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; - } - } + if (nb_rb > nb_available_rb) { // if we've gone beyond the maximum number of RBs + // (can happen if N_RB_DL is odd) + TBS = + get_TBS_DL(eNB_UE_stats->dlsch_mcs1, + nb_available_rb); + nb_rb = nb_available_rb; + break; + } - j = j+1; - } - } + TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_rb); + } - // decrease mcs until TBS falls below required length - while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs>0)) { - mcs--; - TBS = get_TBS_DL(mcs,nb_rb); - } + if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { + for (j = 0; j < N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band + UE_list->UE_template[CC_id][UE_id]. + rballoc_subband[harq_pid][j] = + ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + } + } else { + nb_rb_temp = nb_rb; + j = 0; - // if we have decreased too much or we don't have enough RBs, increase MCS - while ((TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && ((( ue_sched_ctl->dl_pow_off[CC_id]>0) && (mcs<28)) - || ( (ue_sched_ctl->dl_pow_off[CC_id]==0) && (mcs<=15)))) { - mcs++; - TBS = get_TBS_DL(mcs,nb_rb); - } + while ((nb_rb_temp > 0) && (j < N_RBG[CC_id])) { + if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == + 1) { + UE_list-> + UE_template[CC_id] + [UE_id].rballoc_subband[harq_pid][j] = + ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - LOG_D(MAC,"dlsch_mcs before and after the rate matching = (%d, %d)\n",eNB_UE_stats->dlsch_mcs1, mcs); + if ((j == N_RBG[CC_id] - 1) && + ((N_RB_DL[CC_id] == 25) || + (N_RB_DL[CC_id] == 50))) { + nb_rb_temp = + nb_rb_temp - min_rb_unit[CC_id] + + 1; + } else { + nb_rb_temp = + nb_rb_temp - min_rb_unit[CC_id]; + } + } + + j = j + 1; + } + } + + // decrease mcs until TBS falls below required length + while ((TBS > + (sdu_length_total + header_len_dcch + + header_len_dtch + ta_len)) && (mcs > 0)) { + mcs--; + TBS = get_TBS_DL(mcs, nb_rb); + } + + // if we have decreased too much or we don't have enough RBs, increase MCS + while ((TBS < + (sdu_length_total + header_len_dcch + + header_len_dtch + ta_len)) + && (((ue_sched_ctl->dl_pow_off[CC_id] > 0) + && (mcs < 28)) + || ((ue_sched_ctl->dl_pow_off[CC_id] == 0) + && (mcs <= 15)))) { + mcs++; + TBS = get_TBS_DL(mcs, nb_rb); + } + + LOG_D(MAC, + "dlsch_mcs before and after the rate matching = (%d, %d)\n", + eNB_UE_stats->dlsch_mcs1, mcs); #ifdef DEBUG_eNB_SCHEDULER - LOG_D(MAC,"[eNB %d] CC_id %d Generated DLSCH header (mcs %d, TBS %d, nb_rb %d)\n", - module_idP,CC_id,mcs,TBS,nb_rb); - // msg("[MAC][eNB ] Reminder of DLSCH with random data %d %d %d %d \n", - // TBS, sdu_length_total, offset, TBS-sdu_length_total-offset); + LOG_D(MAC, + "[eNB %d] CC_id %d Generated DLSCH header (mcs %d, TBS %d, nb_rb %d)\n", + module_idP, CC_id, mcs, TBS, nb_rb); + // msg("[MAC][eNB ] Reminder of DLSCH with random data %d %d %d %d \n", + // TBS, sdu_length_total, offset, TBS-sdu_length_total-offset); #endif - if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2) { - padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); - post_padding = 0; - } else { - padding = 0; + if ((TBS - header_len_dcch - header_len_dtch - + sdu_length_total - ta_len) <= 2) { + padding = + (TBS - header_len_dcch - header_len_dtch - + sdu_length_total - ta_len); + post_padding = 0; + } else { + padding = 0; - // adjust the header len - if (header_len_dtch==0) { - header_len_dcch = header_len_dcch_tmp; - } else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2))) - header_len_dtch = header_len_dtch_tmp; - } + // adjust the header len + if (header_len_dtch == 0) { + header_len_dcch = header_len_dcch_tmp; + } else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2))) + header_len_dtch = header_len_dtch_tmp; + } - post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len ; // 1 is for the postpadding header - } + post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len; // 1 is for the postpadding header + } - offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], - num_sdus, //num_sdus - sdu_lengths, // - sdu_lcids, - 255, // no drx - ta_update, // timing advance - NULL, // contention res id - padding, - post_padding); + offset = generate_dlsch_header((unsigned char *) UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], num_sdus, //num_sdus + sdu_lengths, // + sdu_lcids, 255, // no drx + ta_update, // timing advance + NULL, // contention res id + padding, post_padding); - //#ifdef DEBUG_eNB_SCHEDULER - if (ta_update != 31) { - LOG_D(MAC, - "[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n", - module_idP,frameP, UE_id, CC_id, sdu_length_total,num_sdus,sdu_lengths[0],sdu_lcids[0],offset, - ta_update,padding,post_padding,mcs,TBS,nb_rb,header_len_dcch,header_len_dtch); - } - //#endif + //#ifdef DEBUG_eNB_SCHEDULER + if (ta_update != 31) { + LOG_D(MAC, + "[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n", + module_idP, frameP, UE_id, CC_id, + sdu_length_total, num_sdus, sdu_lengths[0], + sdu_lcids[0], offset, ta_update, padding, + post_padding, mcs, TBS, nb_rb, + header_len_dcch, header_len_dtch); + } + //#endif #ifdef DEBUG_eNB_SCHEDULER - LOG_T(MAC,"[eNB %d] First 16 bytes of DLSCH : \n"); + LOG_T(MAC, "[eNB %d] First 16 bytes of DLSCH : \n"); - for (i=0; i<16; i++) { - LOG_T(MAC,"%x.",dlsch_buffer[i]); - } + for (i = 0; i < 16; i++) { + LOG_T(MAC, "%x.", dlsch_buffer[i]); + } - LOG_T(MAC,"\n"); + LOG_T(MAC, "\n"); #endif - // cycle through SDUs and place in dlsch_buffer - memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset],dlsch_buffer,sdu_length_total); - // memcpy(RC.mac[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]); + // cycle through SDUs and place in dlsch_buffer + memcpy(&UE_list-> + DLSCH_pdu[CC_id][0][UE_id].payload[0][offset], + dlsch_buffer, sdu_length_total); + // memcpy(RC.mac[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]); - // fill remainder of DLSCH with random data - for (j=0; j<(TBS-sdu_length_total-offset); j++) { - UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset+sdu_length_total+j] = (char)(taus()&0xff); - } + // fill remainder of DLSCH with random data + for (j = 0; j < (TBS - sdu_length_total - offset); j++) { + UE_list->DLSCH_pdu[CC_id][0][UE_id]. + payload[0][offset + sdu_length_total + j] = + (char) (taus() & 0xff); + } - if (opt_enabled == 1) { - trace_pdu(1, (uint8_t *)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], - TBS, module_idP, 3, UE_RNTI(module_idP,UE_id), - eNB->frame, eNB->subframe,0,0); - LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n", - module_idP, CC_id, frameP, UE_RNTI(module_idP,UE_id), TBS); - } + if (opt_enabled == 1) { + trace_pdu(1, (uint8_t *) + UE_list->DLSCH_pdu[CC_id][0][UE_id]. + payload[0], TBS, module_idP, 3, + UE_RNTI(module_idP, UE_id), eNB->frame, + eNB->subframe, 0, 0); + LOG_D(OPT, + "[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n", + module_idP, CC_id, frameP, + UE_RNTI(module_idP, UE_id), TBS); + } - T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), - T_INT(harq_pid), T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], TBS)); + T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), + T_INT(CC_id), T_INT(rnti), T_INT(frameP), + T_INT(subframeP), T_INT(harq_pid), + T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id]. + payload[0], TBS)); - UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; + UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = + nb_rb; - add_ue_dlsch_info(module_idP, - CC_id, - UE_id, - subframeP, - S_DL_SCHEDULED); - // store stats - eNB->eNB_stats[CC_id].dlsch_bytes_tx+=sdu_length_total; - eNB->eNB_stats[CC_id].dlsch_pdus_tx+=1; + add_ue_dlsch_info(module_idP, + CC_id, UE_id, subframeP, + S_DL_SCHEDULED); + // store stats + eNB->eNB_stats[CC_id].dlsch_bytes_tx += + sdu_length_total; + eNB->eNB_stats[CC_id].dlsch_pdus_tx += 1; - UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=eNB_UE_stats->dlsch_mcs1; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=mcs; - UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += + nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = + eNB_UE_stats->dlsch_mcs1; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = mcs; + UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; - UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes= TBS- sdu_length_total; - UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes+= sdu_length_total; - UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes+= TBS; - UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus+=1; + UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes = + TBS - sdu_length_total; + UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes += + sdu_length_total; + UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes += + TBS; + UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus += + 1; - if (cc[CC_id].tdd_Config != NULL) { // TDD - UE_list->UE_template[CC_id][UE_id].DAI++; - update_ul_dci(module_idP,CC_id,rnti,UE_list->UE_template[CC_id][UE_id].DAI); - } + if (cc[CC_id].tdd_Config != NULL) { // TDD + UE_list->UE_template[CC_id][UE_id].DAI++; + update_ul_dci(module_idP, CC_id, rnti, + UE_list->UE_template[CC_id][UE_id]. + DAI); + } + // do PUCCH power control + // this is the normalized RX power + eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; - // do PUCCH power control - // this is the normalized RX power - eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; + /* TODO: fix how we deal with power, unit is not dBm, it's special from nfapi */ + normalized_rx_power = ue_sched_ctl->pucch1_snr[CC_id]; + target_rx_power = 208; - /* TODO: fix how we deal with power, unit is not dBm, it's special from nfapi */ - normalized_rx_power = ue_sched_ctl->pucch1_snr[CC_id]; - target_rx_power = 208; - - // this assumes accumulated tpc - // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out - int32_t framex10psubframe = UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame*10+UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe; - if (((framex10psubframe+10)<=(frameP*10+subframeP)) || //normal case - ((framex10psubframe>(frameP*10+subframeP)) && (((10240-framex10psubframe+frameP*10+subframeP)>=10)))) //frame wrap-around - if (ue_sched_ctl->pucch1_cqi_update[CC_id] == 1) { - ue_sched_ctl->pucch1_cqi_update[CC_id] = 0; + // this assumes accumulated tpc + // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out + int32_t framex10psubframe = + UE_list->UE_template[CC_id][UE_id]. + pucch_tpc_tx_frame * 10 + + UE_list->UE_template[CC_id][UE_id]. + pucch_tpc_tx_subframe; + if (((framex10psubframe + 10) <= (frameP * 10 + subframeP)) || //normal case + ((framex10psubframe > (frameP * 10 + subframeP)) && (((10240 - framex10psubframe + frameP * 10 + subframeP) >= 10)))) //frame wrap-around + if (ue_sched_ctl->pucch1_cqi_update[CC_id] == 1) { + ue_sched_ctl->pucch1_cqi_update[CC_id] = 0; - UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame=frameP; - UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe=subframeP; - - if (normalized_rx_power>(target_rx_power+4)) { - tpc = 0; //-1 - tpc_accumulated--; - } else if (normalized_rx_power<(target_rx_power-4)) { - tpc = 2; //+1 - tpc_accumulated++; - } else { - tpc = 1; //0 - } - - LOG_D(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", - module_idP,frameP, subframeP,harq_pid,tpc, - tpc_accumulated,normalized_rx_power,target_rx_power); + UE_list-> + UE_template[CC_id] + [UE_id].pucch_tpc_tx_frame = frameP; + UE_list-> + UE_template[CC_id] + [UE_id].pucch_tpc_tx_subframe = subframeP; - } // Po_PUCCH has been updated - else { - tpc = 1; //0 - } // time to do TPC update - else { - tpc = 1; //0 - } + if (normalized_rx_power > + (target_rx_power + 4)) { + tpc = 0; //-1 + tpc_accumulated--; + } else if (normalized_rx_power < + (target_rx_power - 4)) { + tpc = 2; //+1 + tpc_accumulated++; + } else { + tpc = 1; //0 + } - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu)); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP,CC_id),ue_sched_ctl->dl_cqi[CC_id],format1); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power - - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = harq_pid; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; // dont adjust power when retransmitting - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = 0; - //deactivate second codeword - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_2 = 0; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_2 = 1; - if (cc[CC_id].tdd_Config != NULL) { //TDD - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.downlink_assignment_index = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - LOG_D(MAC,"[eNB %d] Initial transmission CC_id %d : harq_pid %d, dai %d, mcs %d\n", - module_idP,CC_id,harq_pid, - (UE_list->UE_template[CC_id][UE_id].DAI-1), - mcs); - } else { - LOG_D(MAC,"[eNB %d] Initial transmission CC_id %d : harq_pid %d, mcs %d\n", - module_idP,CC_id,harq_pid,mcs); - - } - LOG_D(MAC,"Checking feasibility pdu %d (new sdu)\n",dl_req->number_pdu); - if (!CCE_allocation_infeasible(module_idP,CC_id,1,subframeP,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,rnti)) { + LOG_D(MAC, + "[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", + module_idP, frameP, subframeP, harq_pid, + tpc, tpc_accumulated, + normalized_rx_power, target_rx_power); + + } // Po_PUCCH has been updated + else { + tpc = 1; //0 + } // time to do TPC update + else { + tpc = 1; //0 + } + + dl_config_pdu = + &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = + NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = + NFAPI_DL_DCI_FORMAT_1; + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level = + get_aggregation(get_bw_index(module_idP, CC_id), + ue_sched_ctl->dl_cqi[CC_id], + format1); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + harq_process = harq_pid; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; // dont adjust power when retransmitting + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.new_data_indicator_1 = + 1 - + UE_list->UE_template[CC_id][UE_id]. + oldNDI[harq_pid]; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.redundancy_version_1 = 0; + //deactivate second codeword + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_2 = 0; + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.redundancy_version_2 = 1; + if (cc[CC_id].tdd_Config != NULL) { //TDD + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.downlink_assignment_index = + (UE_list->UE_template[CC_id][UE_id].DAI - + 1) & 3; + LOG_D(MAC, + "[eNB %d] Initial transmission CC_id %d : harq_pid %d, dai %d, mcs %d\n", + module_idP, CC_id, harq_pid, + (UE_list->UE_template[CC_id][UE_id].DAI - 1), + mcs); + } else { + LOG_D(MAC, + "[eNB %d] Initial transmission CC_id %d : harq_pid %d, mcs %d\n", + module_idP, CC_id, harq_pid, mcs); + + } + LOG_D(MAC, "Checking feasibility pdu %d (new sdu)\n", + dl_req->number_pdu); + if (!CCE_allocation_infeasible + (module_idP, CC_id, 1, subframeP, + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level, rnti)) { - ue_sched_ctl->round[CC_id][harq_pid] = 0; - dl_req->number_dci++; - dl_req->number_pdu++; - - // Toggle NDI for next time - LOG_D(MAC,"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", - CC_id, frameP,subframeP,UE_id, - rnti,harq_pid,UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]); - - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]=1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid] = mcs; - UE_list->UE_template[CC_id][UE_id].oldmcs2[harq_pid] = 0; - AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated!=NULL,"physicalConfigDedicated is NULL\n"); - AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated!=NULL,"physicalConfigDedicated->pdsch_ConfigDedicated is NULL\n"); - - fill_nfapi_dlsch_config(eNB,dl_req, - TBS, - eNB->pdu_index[CC_id], - rnti, - 0, // type 0 allocation from 7.1.6 in 36.213 - 0, // virtual_resource_block_assignment_flag, unused here - 0, // resource_block_coding, to be filled in later - getQm(mcs), - 0, // redundancy version - 1, // transport blocks - 0, // transport block to codeword swap flag - cc[CC_id].p_eNB == 1 ? 0 : 1, // transmission_scheme - 1, // number of layers - 1, // number of subbands - // uint8_t codebook_index, - 4, // UE category capacity - UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated->p_a, - 0, // delta_power_offset for TM5 - 0, // ngap - 0, // nprb - cc[CC_id].p_eNB == 1 ? 1 : 2, // transmission mode - 0, //number of PRBs treated as one subband, not used here - 0 // number of beamforming vectors, not used here - ); - eNB->TX_req[CC_id].sfn_sf = fill_nfapi_tx_req(&eNB->TX_req[CC_id].tx_request_body, - (frameP*10)+subframeP, - TBS, - eNB->pdu_index[CC_id], - eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0]); - - LOG_D(MAC,"Filled NFAPI configuration for DCI/DLSCH/TXREQ %d, new SDU\n",eNB->pdu_index[CC_id]); + ue_sched_ctl->round[CC_id][harq_pid] = 0; + dl_req->number_dci++; + dl_req->number_pdu++; - eNB->pdu_index[CC_id]++; - program_dlsch_acknak(module_idP,CC_id,UE_id,frameP,subframeP,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx); + // Toggle NDI for next time + LOG_D(MAC, + "CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", + CC_id, frameP, subframeP, UE_id, rnti, + harq_pid, + UE_list-> + UE_template[CC_id][UE_id].oldNDI[harq_pid]); - } - else { - LOG_W(MAC,"Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d/%x, infeasible CCE allocations\n", - frameP,subframeP,UE_id,rnti); - } - } else { // There is no data from RLC or MAC header, so don't schedule + UE_list->UE_template[CC_id][UE_id]. + oldNDI[harq_pid] = + 1 - + UE_list->UE_template[CC_id][UE_id]. + oldNDI[harq_pid]; + UE_list->UE_template[CC_id][UE_id]. + oldmcs1[harq_pid] = mcs; + UE_list->UE_template[CC_id][UE_id]. + oldmcs2[harq_pid] = 0; + AssertFatal(UE_list->UE_template[CC_id] + [UE_id].physicalConfigDedicated != + NULL, + "physicalConfigDedicated is NULL\n"); + AssertFatal(UE_list->UE_template[CC_id] + [UE_id]. + physicalConfigDedicated->pdsch_ConfigDedicated + != NULL, + "physicalConfigDedicated->pdsch_ConfigDedicated is NULL\n"); - } - } + fill_nfapi_dlsch_config(eNB, dl_req, TBS, eNB->pdu_index[CC_id], rnti, 0, // type 0 allocation from 7.1.6 in 36.213 + 0, // virtual_resource_block_assignment_flag, unused here + 0, // resource_block_coding, to be filled in later + getQm(mcs), 0, // redundancy version + 1, // transport blocks + 0, // transport block to codeword swap flag + cc[CC_id].p_eNB == 1 ? 0 : 1, // transmission_scheme + 1, // number of layers + 1, // number of subbands + // uint8_t codebook_index, + 4, // UE category capacity + UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated->p_a, 0, // delta_power_offset for TM5 + 0, // ngap + 0, // nprb + cc[CC_id].p_eNB == 1 ? 1 : 2, // transmission mode + 0, //number of PRBs treated as one subband, not used here + 0 // number of beamforming vectors, not used here + ); + eNB->TX_req[CC_id].sfn_sf = + fill_nfapi_tx_req(&eNB-> + TX_req + [CC_id].tx_request_body, + (frameP * 10) + subframeP, + TBS, eNB->pdu_index[CC_id], + eNB-> + UE_list.DLSCH_pdu[CC_id][0][(unsigned char) + UE_id].payload + [0]); - if (cc[CC_id].tdd_Config != NULL){ // TDD - set_ul_DAI(module_idP,UE_id,CC_id,frameP,subframeP); - } + LOG_D(MAC, + "Filled NFAPI configuration for DCI/DLSCH/TXREQ %d, new SDU\n", + eNB->pdu_index[CC_id]); - } // UE_id loop - } // CC_id loop + eNB->pdu_index[CC_id]++; + program_dlsch_acknak(module_idP, CC_id, UE_id, + frameP, subframeP, + dl_config_pdu-> + dci_dl_pdu.dci_dl_pdu_rel8. + cce_idx); + + } else { + LOG_W(MAC, + "Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d/%x, infeasible CCE allocations\n", + frameP, subframeP, UE_id, rnti); + } + } else { // There is no data from RLC or MAC header, so don't schedule + + } + } + + if (cc[CC_id].tdd_Config != NULL) { // TDD + set_ul_DAI(module_idP, UE_id, CC_id, frameP, subframeP); + } + + } // UE_id loop + } // CC_id loop - - fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_flag); - stop_meas(&eNB->schedule_dlsch); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_OUT); + fill_DLSCH_dci(module_idP, frameP, subframeP, mbsfn_flag); + + stop_meas(&eNB->schedule_dlsch); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_OUT); } //------------------------------------------------------------------------------ void -fill_DLSCH_dci( - module_id_t module_idP, - frame_t frameP, - sub_frame_t subframeP, - int* mbsfn_flagP - ) +fill_DLSCH_dci(module_id_t module_idP, + frame_t frameP, sub_frame_t subframeP, int *mbsfn_flagP) //------------------------------------------------------------------------------ { - // loop over all allocated UEs and compute frequency allocations for PDSCH - int UE_id = -1; - uint8_t /* first_rb, */ nb_rb=3; - rnti_t rnti; - //unsigned char *vrb_map; - uint8_t rballoc_sub[25]; - //uint8_t number_of_subbands=13; + // loop over all allocated UEs and compute frequency allocations for PDSCH + int UE_id = -1; + uint8_t /* first_rb, */ nb_rb = 3; + rnti_t rnti; + //unsigned char *vrb_map; + uint8_t rballoc_sub[25]; + //uint8_t number_of_subbands=13; - //unsigned char round; - unsigned char harq_pid; - int i; - int CC_id; - eNB_MAC_INST *eNB =RC.mac[module_idP]; - UE_list_t *UE_list = &eNB->UE_list; - int N_RBG; - int N_RB_DL; - COMMON_channels_t *cc; + //unsigned char round; + unsigned char harq_pid; + int i; + int CC_id; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + UE_list_t *UE_list = &eNB->UE_list; + int N_RBG; + int N_RB_DL; + COMMON_channels_t *cc; - start_meas(&eNB->fill_DLSCH_dci); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI,VCD_FUNCTION_IN); + start_meas(&eNB->fill_DLSCH_dci); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI, VCD_FUNCTION_IN); - for (CC_id=0; CC_id0) - continue; + if (mbsfn_flagP[CC_id] > 0) + continue; - cc = &eNB->common_channels[CC_id]; - N_RBG = to_rbg(cc->mib->message.dl_Bandwidth); - N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); + cc = &eNB->common_channels[CC_id]; + N_RBG = to_rbg(cc->mib->message.dl_Bandwidth); + N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); - // UE specific DCIs - for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { - LOG_T(MAC,"CC_id %d, UE_id: %d => status %d\n",CC_id,UE_id,eNB_dlsch_info[module_idP][CC_id][UE_id].status); + // UE specific DCIs + for (UE_id = UE_list->head; UE_id >= 0; + UE_id = UE_list->next[UE_id]) { + LOG_T(MAC, "CC_id %d, UE_id: %d => status %d\n", CC_id, UE_id, + eNB_dlsch_info[module_idP][CC_id][UE_id].status); - if (eNB_dlsch_info[module_idP][CC_id][UE_id].status == S_DL_SCHEDULED) { + if (eNB_dlsch_info[module_idP][CC_id][UE_id].status == + S_DL_SCHEDULED) { - // clear scheduling flag - eNB_dlsch_info[module_idP][CC_id][UE_id].status = S_DL_WAITING; - rnti = UE_RNTI(module_idP,UE_id); - if (cc->tdd_Config) harq_pid = ((frameP*10)+subframeP)%10; - else harq_pid = ((frameP*10)+subframeP)&7; - nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + // clear scheduling flag + eNB_dlsch_info[module_idP][CC_id][UE_id].status = + S_DL_WAITING; + rnti = UE_RNTI(module_idP, UE_id); + if (cc->tdd_Config) + harq_pid = ((frameP * 10) + subframeP) % 10; + else + harq_pid = ((frameP * 10) + subframeP) & 7; + nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - - /// Synchronizing rballoc with rballoc_sub - for(i=0; iUE_template[CC_id][UE_id].rballoc_subband[harq_pid][i]; - } - nfapi_dl_config_request_t *DL_req = &RC.mac[module_idP]->DL_req[0]; - nfapi_dl_config_request_pdu_t* dl_config_pdu; + /// Synchronizing rballoc with rballoc_sub + for (i = 0; i < N_RBG; i++) { + rballoc_sub[i] = + UE_list-> + UE_template[CC_id][UE_id].rballoc_subband[harq_pid] + [i]; + } - for (i=0;ipdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)&& - (dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti == rnti) && - (dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format != 1)) { - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = allocate_prbs_sub(nb_rb,N_RB_DL,N_RBG,rballoc_sub); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_allocation_type = 0; - } - else if ((dl_config_pdu->pdu_type == NFAPI_DL_CONFIG_DLSCH_PDU_TYPE)&& - (dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti == rnti) && - (dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type==0)) { - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = allocate_prbs_sub(nb_rb,N_RB_DL,N_RBG,rballoc_sub); - } + nfapi_dl_config_request_t *DL_req = + &RC.mac[module_idP]->DL_req[0]; + nfapi_dl_config_request_pdu_t *dl_config_pdu; + + for (i = 0; + i < DL_req[CC_id].dl_config_request_body.number_pdu; + i++) { + dl_config_pdu = + &DL_req[CC_id]. + dl_config_request_body.dl_config_pdu_list[i]; + if ((dl_config_pdu->pdu_type == + NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) + && (dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + rnti == rnti) + && (dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.dci_format != 1)) { + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.resource_block_coding = + allocate_prbs_sub(nb_rb, N_RB_DL, N_RBG, + rballoc_sub); + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.resource_allocation_type = 0; + } else + if ((dl_config_pdu->pdu_type == + NFAPI_DL_CONFIG_DLSCH_PDU_TYPE) + && (dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. + rnti == rnti) + && (dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.resource_allocation_type == + 0)) { + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.resource_block_coding = + allocate_prbs_sub(nb_rb, N_RB_DL, N_RBG, + rballoc_sub); + } + } + } } - } + } - } - - stop_meas(&eNB->fill_DLSCH_dci); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI,VCD_FUNCTION_OUT); + stop_meas(&eNB->fill_DLSCH_dci); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI, VCD_FUNCTION_OUT); } //------------------------------------------------------------------------------ -unsigned char* -get_dlsch_sdu( - module_id_t module_idP, - int CC_id, - frame_t frameP, - rnti_t rntiP, - uint8_t TBindex -) +unsigned char *get_dlsch_sdu(module_id_t module_idP, + int CC_id, frame_t frameP, rnti_t rntiP, + uint8_t TBindex) //------------------------------------------------------------------------------ { - int UE_id; - eNB_MAC_INST *eNB=RC.mac[module_idP]; + int UE_id; + eNB_MAC_INST *eNB = RC.mac[module_idP]; - if (rntiP==SI_RNTI) { - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d Get DLSCH sdu for BCCH \n", module_idP, CC_id, frameP); + if (rntiP == SI_RNTI) { + LOG_D(MAC, "[eNB %d] CC_id %d Frame %d Get DLSCH sdu for BCCH \n", + module_idP, CC_id, frameP); - return((unsigned char *)&eNB->common_channels[CC_id].BCCH_pdu.payload[0]); - } + return ((unsigned char *) &eNB->common_channels[CC_id]. + BCCH_pdu.payload[0]); + } - UE_id = find_UE_id(module_idP,rntiP); + UE_id = find_UE_id(module_idP, rntiP); - if (UE_id != -1) { - LOG_D(MAC,"[eNB %d] Frame %d: CC_id %d Get DLSCH sdu for rnti %x => UE_id %d\n",module_idP,frameP,CC_id,rntiP,UE_id); - return((unsigned char *)&eNB->UE_list.DLSCH_pdu[CC_id][TBindex][UE_id].payload[0]); - } else { - LOG_E(MAC,"[eNB %d] Frame %d: CC_id %d UE with RNTI %x does not exist\n", module_idP,frameP,CC_id,rntiP); - return NULL; - } + if (UE_id != -1) { + LOG_D(MAC, + "[eNB %d] Frame %d: CC_id %d Get DLSCH sdu for rnti %x => UE_id %d\n", + module_idP, frameP, CC_id, rntiP, UE_id); + return ((unsigned char *) &eNB-> + UE_list.DLSCH_pdu[CC_id][TBindex][UE_id].payload[0]); + } else { + LOG_E(MAC, + "[eNB %d] Frame %d: CC_id %d UE with RNTI %x does not exist\n", + module_idP, frameP, CC_id, rntiP); + return NULL; + } } //------------------------------------------------------------------------------ -void update_ul_dci(module_id_t module_idP, - uint8_t CC_idP, - rnti_t rntiP, - uint8_t daiP) +void +update_ul_dci(module_id_t module_idP, + uint8_t CC_idP, rnti_t rntiP, uint8_t daiP) //------------------------------------------------------------------------------ { - nfapi_hi_dci0_request_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP]; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_request_body.hi_dci0_pdu_list[0]; - COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_idP]; - int i; + nfapi_hi_dci0_request_t *HI_DCI0_req = + &RC.mac[module_idP]->HI_DCI0_req[CC_idP]; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = + &HI_DCI0_req->hi_dci0_request_body.hi_dci0_pdu_list[0]; + COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_idP]; + int i; - if (cc->tdd_Config != NULL) { // TDD - for (i=0; ihi_dci0_request_body.number_of_dci + HI_DCI0_req->hi_dci0_request_body.number_of_dci; i++) { + if (cc->tdd_Config != NULL) { // TDD + for (i = 0; + i < + HI_DCI0_req->hi_dci0_request_body.number_of_dci + + HI_DCI0_req->hi_dci0_request_body.number_of_dci; i++) { - if ((hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) && - (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti == rntiP)) - hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.dl_assignment_index = (daiP-1)&3; - + if ((hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) && + (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti == rntiP)) + hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.dl_assignment_index = + (daiP - 1) & 3; + + } } - } } //------------------------------------------------------------------------------ -void set_ue_dai( - sub_frame_t subframeP, - int UE_id, - uint8_t CC_id, - uint8_t tdd_config, - UE_list_t* UE_list -) +void +set_ue_dai(sub_frame_t subframeP, + int UE_id, uint8_t CC_id, uint8_t tdd_config, + UE_list_t * UE_list) //------------------------------------------------------------------------------ { - switch (tdd_config) { - case 0: - if ((subframeP==0)||(subframeP==1)||(subframeP==3)||(subframeP==5)||(subframeP==6)||(subframeP==8)) { - UE_list->UE_template[CC_id][UE_id].DAI = 0; + switch (tdd_config) { + case 0: + if ((subframeP == 0) || (subframeP == 1) || (subframeP == 3) + || (subframeP == 5) || (subframeP == 6) || (subframeP == 8)) { + UE_list->UE_template[CC_id][UE_id].DAI = 0; + } + + break; + + case 1: + if ((subframeP == 0) || (subframeP == 4) || (subframeP == 5) + || (subframeP == 9)) { + UE_list->UE_template[CC_id][UE_id].DAI = 0; + } + + break; + + case 2: + if ((subframeP == 4) || (subframeP == 5)) { + UE_list->UE_template[CC_id][UE_id].DAI = 0; + } + + break; + + case 3: + if ((subframeP == 5) || (subframeP == 7) || (subframeP == 9)) { + UE_list->UE_template[CC_id][UE_id].DAI = 0; + } + + break; + + case 4: + if ((subframeP == 0) || (subframeP == 6)) { + UE_list->UE_template[CC_id][UE_id].DAI = 0; + } + + break; + + case 5: + if (subframeP == 9) { + UE_list->UE_template[CC_id][UE_id].DAI = 0; + } + + break; + + case 6: + if ((subframeP == 0) || (subframeP == 1) || (subframeP == 5) + || (subframeP == 6) || (subframeP == 9)) { + UE_list->UE_template[CC_id][UE_id].DAI = 0; + } + + break; + + default: + UE_list->UE_template[CC_id][UE_id].DAI = 0; + LOG_N(MAC, "unknow TDD config %d\n", tdd_config); + break; } - - break; - - case 1: - if ((subframeP==0)||(subframeP==4)||(subframeP==5)||(subframeP==9)) { - UE_list->UE_template[CC_id][UE_id].DAI = 0; - } - - break; - - case 2: - if ((subframeP==4)||(subframeP==5)) { - UE_list->UE_template[CC_id][UE_id].DAI = 0; - } - - break; - - case 3: - if ((subframeP==5)||(subframeP==7)||(subframeP==9)) { - UE_list->UE_template[CC_id][UE_id].DAI = 0; - } - - break; - - case 4: - if ((subframeP==0)||(subframeP==6)) { - UE_list->UE_template[CC_id][UE_id].DAI = 0; - } - - break; - - case 5: - if (subframeP==9) { - UE_list->UE_template[CC_id][UE_id].DAI = 0; - } - - break; - - case 6: - if ((subframeP==0)||(subframeP==1)||(subframeP==5)||(subframeP==6)||(subframeP==9)) { - UE_list->UE_template[CC_id][UE_id].DAI = 0; - } - - break; - - default: - UE_list->UE_template[CC_id][UE_id].DAI = 0; - LOG_N(MAC,"unknow TDD config %d\n",tdd_config); - break; - } } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_mch.c b/openair2/LAYER2/MAC/eNB_scheduler_mch.c index 3b05850a1d..7ce5a5b12c 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_mch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_mch.c @@ -52,10 +52,10 @@ #include "pdcp.h" #if defined(ENABLE_ITTI) -# include "intertask_interface.h" +#include "intertask_interface.h" #endif -#include "SIMULATION/TOOLS/defs.h" // for taus +#include "SIMULATION/TOOLS/defs.h" // for taus #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_eNB_SCHEDULER 1 @@ -63,607 +63,746 @@ extern RAN_CONTEXT_t RC; #if defined(Rel10) || defined(Rel14) -int8_t get_mbsfn_sf_alloction (module_id_t module_idP, uint8_t CC_id, uint8_t mbsfn_sync_area) +int8_t +get_mbsfn_sf_alloction(module_id_t module_idP, uint8_t CC_id, + uint8_t mbsfn_sync_area) { - // currently there is one-to-one mapping between sf allocation pattern and sync area - if (mbsfn_sync_area > MAX_MBSFN_AREA) { - LOG_W(MAC,"[eNB %d] CC_id %d MBSFN synchronization area %d out of range\n ", module_idP, CC_id, mbsfn_sync_area); - return -1; - } else if (RC.mac[module_idP]->common_channels[CC_id].mbsfn_SubframeConfig[mbsfn_sync_area] != NULL) { - return mbsfn_sync_area; - } else { - LOG_W(MAC,"[eNB %d] CC_id %d MBSFN Subframe Config pattern %d not found \n ", module_idP, CC_id, mbsfn_sync_area); - return -1; - } + // currently there is one-to-one mapping between sf allocation pattern and sync area + if (mbsfn_sync_area > MAX_MBSFN_AREA) { + LOG_W(MAC, + "[eNB %d] CC_id %d MBSFN synchronization area %d out of range\n ", + module_idP, CC_id, mbsfn_sync_area); + return -1; + } else if (RC.mac[module_idP]-> + common_channels[CC_id].mbsfn_SubframeConfig[mbsfn_sync_area] + != NULL) { + return mbsfn_sync_area; + } else { + LOG_W(MAC, + "[eNB %d] CC_id %d MBSFN Subframe Config pattern %d not found \n ", + module_idP, CC_id, mbsfn_sync_area); + return -1; + } } -int schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP, sub_frame_t subframeP) +int +schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP, + sub_frame_t subframeP) { - int mcch_flag=0,mtch_flag=0, msi_flag=0; - int mbsfn_period =0;// 1<<(RC.mac[module_idP]->mbsfn_SubframeConfig[0]->radioframeAllocationPeriod); - int mcch_period = 0;//32<<(RC.mac[module_idP]->mbsfn_AreaInfo[0]->mcch_Config_r9.mcch_RepetitionPeriod_r9); - int mch_scheduling_period = 8<<(RC.mac[module_idP]->common_channels[CC_id].pmch_Config[0]->mch_SchedulingPeriod_r9); - unsigned char mcch_sdu_length; - unsigned char header_len_mcch=0,header_len_msi=0,header_len_mtch=0, header_len_mtch_temp=0, header_len_mcch_temp=0, header_len_msi_temp=0; - int ii=0, msi_pos=0; - int mcch_mcs = -1; - uint16_t TBS,j=-1,padding=0,post_padding=0; - mac_rlc_status_resp_t rlc_status; - int num_mtch; - int msi_length,i,k; - unsigned char sdu_lcids[11], num_sdus=0, offset=0; - uint16_t sdu_lengths[11], sdu_length_total=0; - unsigned char mch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; // check the max value, this is for dlsch only + int mcch_flag = 0, mtch_flag = 0, msi_flag = 0; + int mbsfn_period = 0; // 1<<(RC.mac[module_idP]->mbsfn_SubframeConfig[0]->radioframeAllocationPeriod); + int mcch_period = 0; //32<<(RC.mac[module_idP]->mbsfn_AreaInfo[0]->mcch_Config_r9.mcch_RepetitionPeriod_r9); + int mch_scheduling_period = + 8 << (RC.mac[module_idP]->common_channels[CC_id]. + pmch_Config[0]->mch_SchedulingPeriod_r9); + unsigned char mcch_sdu_length; + unsigned char header_len_mcch = 0, header_len_msi = + 0, header_len_mtch = 0, header_len_mtch_temp = + 0, header_len_mcch_temp = 0, header_len_msi_temp = 0; + int ii = 0, msi_pos = 0; + int mcch_mcs = -1; + uint16_t TBS, j = -1, padding = 0, post_padding = 0; + mac_rlc_status_resp_t rlc_status; + int num_mtch; + int msi_length, i, k; + unsigned char sdu_lcids[11], num_sdus = 0, offset = 0; + uint16_t sdu_lengths[11], sdu_length_total = 0; + unsigned char mch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; // check the max value, this is for dlsch only - COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_id]; + COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_id]; - cc->MCH_pdu.Pdu_size=0; + cc->MCH_pdu.Pdu_size = 0; - for (i=0; - i< cc->num_active_mbsfn_area; - i++ ) { - // assume, that there is always a mapping - if ((j=get_mbsfn_sf_alloction(module_idP,CC_id,i)) == -1) { - return 0; + for (i = 0; i < cc->num_active_mbsfn_area; i++) { + // assume, that there is always a mapping + if ((j = get_mbsfn_sf_alloction(module_idP, CC_id, i)) == -1) { + return 0; + } + + mbsfn_period = + 1 << (cc->mbsfn_SubframeConfig[j]->radioframeAllocationPeriod); + mcch_period = + 32 << (cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_RepetitionPeriod_r9); + msi_pos = 0; + ii = 0; + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d : Checking MBSFN Sync Area %d/%d with SF allocation %d/%d for MCCH and MTCH (mbsfn period %d, mcch period %d)\n", + module_idP, CC_id, frameP, subframeP, i, + cc->num_active_mbsfn_area, j, cc->num_sf_allocation_pattern, + mbsfn_period, mcch_period); + + + switch (cc->mbsfn_AreaInfo[i]->mcch_Config_r9.signallingMCS_r9) { + case 0: + mcch_mcs = 2; + break; + + case 1: + mcch_mcs = 7; + break; + + case 2: + mcch_mcs = 13; + break; + + case 3: + mcch_mcs = 19; + break; + } + + // 1st: Check the MBSFN subframes from SIB2 info (SF allocation pattern i, max 8 non-overlapping patterns exist) + if (frameP % mbsfn_period == cc->mbsfn_SubframeConfig[j]->radioframeAllocationOffset) { // MBSFN frameP + if (cc->mbsfn_SubframeConfig[j]->subframeAllocation.present == MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { // one-frameP format + + // Find the first subframeP in this MCH to transmit MSI + if (frameP % mch_scheduling_period == + cc->mbsfn_SubframeConfig[j]-> + radioframeAllocationOffset) { + while (ii == 0) { + ii = cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & (0x80 >> msi_pos); + msi_pos++; + } + + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d : sync area %d sf allocation pattern %d sf alloc %x msi pos is %d \n", + module_idP, CC_id, frameP, subframeP, i, j, + cc->mbsfn_SubframeConfig[j]-> + subframeAllocation.choice.oneFrame.buf[0], + msi_pos); + } + // Check if the subframeP is for MSI, MCCH or MTCHs and Set the correspoding flag to 1 + switch (subframeP) { + case 1: + if (cc->tdd_Config == NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF1) == + MBSFN_FDD_SF1) { + if (msi_pos == 1) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF1) == + MBSFN_FDD_SF1)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 2: + if (cc->tdd_Config == NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF2) == + MBSFN_FDD_SF2) { + if (msi_pos == 2) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF2) == + MBSFN_FDD_SF2)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 3: + if (cc->tdd_Config != NULL) { // TDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF3) == + MBSFN_TDD_SF3) { + if (msi_pos == 1) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF3) == + MBSFN_TDD_SF3)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } else { // FDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF3) == + MBSFN_FDD_SF3) { + if (msi_pos == 3) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF3) == + MBSFN_FDD_SF3)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 4: + if (cc->tdd_Config != NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF4) == + MBSFN_TDD_SF4) { + if (msi_pos == 2) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF4) == + MBSFN_TDD_SF4)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 6: + if (cc->tdd_Config == NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF6) == + MBSFN_FDD_SF6) { + if (msi_pos == 4) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF6) == + MBSFN_FDD_SF6)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 7: + if (cc->tdd_Config != NULL) { // TDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF7) == + MBSFN_TDD_SF7) { + if (msi_pos == 3) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF7) == + MBSFN_TDD_SF7)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } else { // FDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF7) == + MBSFN_FDD_SF7) { + if (msi_pos == 5) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF7) == + MBSFN_FDD_SF7)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 8: + if (cc->tdd_Config != NULL) { //TDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF8) == + MBSFN_TDD_SF8) { + if (msi_pos == 4) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF8) == + MBSFN_TDD_SF8)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } else { // FDD + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_FDD_SF8) == + MBSFN_FDD_SF8) { + if (msi_pos == 6) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF8) == + MBSFN_FDD_SF8)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 9: + if (cc->tdd_Config != NULL) { + if ((cc-> + mbsfn_SubframeConfig[j]->subframeAllocation. + choice.oneFrame.buf[0] & MBSFN_TDD_SF9) == + MBSFN_TDD_SF9) { + if (msi_pos == 5) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_Offset_r9) + && + ((cc->mbsfn_AreaInfo[i]-> + mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF9) == + MBSFN_TDD_SF9)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + } // end switch + + // sf allocation is non-overlapping + if ((msi_flag == 1) || (mcch_flag == 1) + || (mtch_flag == 1)) { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d Subframe %d: sync area %d SF alloc %d: msi flag %d, mcch flag %d, mtch flag %d\n", + module_idP, CC_id, frameP, subframeP, i, j, + msi_flag, mcch_flag, mtch_flag); + break; + } + } else { // four-frameP format + } + } + } // end of for loop + + cc->msi_active = 0; + cc->mcch_active = 0; + cc->mtch_active = 0; + + // Calculate the mcs + if ((msi_flag == 1) || (mcch_flag == 1)) { + cc->MCH_pdu.mcs = mcch_mcs; + } else if (mtch_flag == 1) { // only MTCH in this subframeP + cc->MCH_pdu.mcs = cc->pmch_Config[0]->dataMCS_r9; + } + // 2nd: Create MSI, get MCCH from RRC and MTCHs from RLC + + // there is MSI (MCH Scheduling Info) + if (msi_flag == 1) { + // Create MSI here + uint16_t msi_control_element[29], *msi_ptr; + + msi_ptr = &msi_control_element[0]; + ((MSI_ELEMENT *) msi_ptr)->lcid = MCCH_LCHANID; //MCCH + + if (mcch_flag == 1) { + ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0; + ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0; + } else { // no mcch for this MSP + ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0x7; // stop value is 2047 + ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0xff; + } + + msi_ptr += sizeof(MSI_ELEMENT); + + //Header for MTCHs + num_mtch = cc->mbms_SessionList[0]->list.count; + + for (k = 0; k < num_mtch; k++) { // loop for all session in this MCH (MCH[0]) at this moment + ((MSI_ELEMENT *) msi_ptr)->lcid = cc->mbms_SessionList[0]->list.array[k]->logicalChannelIdentity_r9; //mtch_lcid; + ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0; // last subframeP of this mtch (only one mtch now) + ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0xB; + msi_ptr += sizeof(MSI_ELEMENT); + } + + msi_length = msi_ptr - msi_control_element; + + if (msi_length < 128) { + header_len_msi = 2; + } else { + header_len_msi = 3; + } + + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d : MSI->MCH, length of MSI is %d bytes \n", + module_idP, CC_id, frameP, msi_length); + //LOG_D(MAC,"Scheduler: MSI is transmitted in this subframeP \n" ); + + // LOG_D(MAC,"Scheduler: MSI length is %d bytes\n",msi_length); + // Store MSI data to mch_buffer[0] + memcpy((char *) &mch_buffer[sdu_length_total], + msi_control_element, msi_length); + + sdu_lcids[num_sdus] = MCH_SCHDL_INFO; + sdu_lengths[num_sdus] = msi_length; + sdu_length_total += sdu_lengths[num_sdus]; + LOG_I(MAC, "[eNB %d] CC_id %d Create %d bytes for MSI\n", + module_idP, CC_id, sdu_lengths[num_sdus]); + num_sdus++; + cc->msi_active = 1; + } + // there is MCCH + if (mcch_flag == 1) { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d Subframe %d: Schedule MCCH MESSAGE (area %d, sfAlloc %d)\n", + module_idP, CC_id, frameP, subframeP, i, j); + + mcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, MCCH, 1, &cc->MCCH_pdu.payload[0], 1, // this is eNB + module_idP, // index + i); // this is the mbsfn sync area index + + if (mcch_sdu_length > 0) { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d : MCCH->MCH, Received %d bytes from RRC \n", + module_idP, CC_id, frameP, subframeP, mcch_sdu_length); + + header_len_mcch = 2; + + if (cc->tdd_Config != NULL) { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d: Scheduling MCCH->MCH (TDD) for MCCH message %d bytes (mcs %d )\n", + module_idP, CC_id, frameP, subframeP, + mcch_sdu_length, mcch_mcs); + } else { + LOG_I(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d: Scheduling MCCH->MCH (FDD) for MCCH message %d bytes (mcs %d)\n", + module_idP, CC_id, frameP, subframeP, + mcch_sdu_length, mcch_mcs); + } + + cc->mcch_active = 1; + + memcpy((char *) &mch_buffer[sdu_length_total], + &cc->MCCH_pdu.payload[0], mcch_sdu_length); + sdu_lcids[num_sdus] = MCCH_LCHANID; + sdu_lengths[num_sdus] = mcch_sdu_length; + + if (sdu_lengths[num_sdus] > 128) { + header_len_mcch = 3; + } + + sdu_length_total += sdu_lengths[num_sdus]; + LOG_D(MAC, + "[eNB %d] CC_id %d Got %d bytes for MCCH from RRC \n", + module_idP, CC_id, sdu_lengths[num_sdus]); + num_sdus++; + } } - mbsfn_period = 1<<(cc->mbsfn_SubframeConfig[j]->radioframeAllocationPeriod); - mcch_period = 32<<(cc->mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_RepetitionPeriod_r9); - msi_pos=0; - ii=0; - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframeP %d : Checking MBSFN Sync Area %d/%d with SF allocation %d/%d for MCCH and MTCH (mbsfn period %d, mcch period %d)\n", - module_idP, CC_id, frameP, subframeP,i,cc->num_active_mbsfn_area, - j,cc->num_sf_allocation_pattern,mbsfn_period,mcch_period); - - - switch (cc->mbsfn_AreaInfo[i]->mcch_Config_r9.signallingMCS_r9) { - case 0: - mcch_mcs = 2; - break; - - case 1: - mcch_mcs = 7; - break; - - case 2: - mcch_mcs = 13; - break; - - case 3: - mcch_mcs = 19; - break; - } - - // 1st: Check the MBSFN subframes from SIB2 info (SF allocation pattern i, max 8 non-overlapping patterns exist) - if (frameP % mbsfn_period == cc->mbsfn_SubframeConfig[j]->radioframeAllocationOffset) { // MBSFN frameP - if (cc->mbsfn_SubframeConfig[j]->subframeAllocation.present == MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { // one-frameP format - - // Find the first subframeP in this MCH to transmit MSI - if (frameP % mch_scheduling_period == cc->mbsfn_SubframeConfig[j]->radioframeAllocationOffset ) { - while (ii == 0) { - ii = cc->mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & (0x80>>msi_pos); - msi_pos++; - } - - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframeP %d : sync area %d sf allocation pattern %d sf alloc %x msi pos is %d \n", - module_idP, CC_id, frameP, subframeP,i,j, - cc->mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0], msi_pos); - } - - // Check if the subframeP is for MSI, MCCH or MTCHs and Set the correspoding flag to 1 - switch (subframeP) { - case 1: - if (cc->tdd_Config == NULL) { - if ((cc->mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF1) == MBSFN_FDD_SF1) { - if (msi_pos == 1) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == cc->mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((cc->mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF1) == MBSFN_FDD_SF1) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 2: - if (cc->tdd_Config == NULL) { - if ((cc->mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF2) == MBSFN_FDD_SF2) { - if (msi_pos == 2) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == cc->mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((cc->mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF2) == MBSFN_FDD_SF2) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 3: - if (cc->tdd_Config != NULL) { // TDD - if ((cc->mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF3) == MBSFN_TDD_SF3) { - if (msi_pos == 1) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == cc->mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((cc->mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF3) == MBSFN_TDD_SF3) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } else { // FDD - if ((cc->mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF3) == MBSFN_FDD_SF3) { - if (msi_pos == 3) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == cc->mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((cc->mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF3) == MBSFN_FDD_SF3) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 4: - if (cc->tdd_Config != NULL) { - if ((cc->mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF4) == MBSFN_TDD_SF4) { - if (msi_pos == 2) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == cc->mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((cc->mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF4) == MBSFN_TDD_SF4) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 6: - if (cc->tdd_Config == NULL) { - if ((cc->mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF6) == MBSFN_FDD_SF6) { - if (msi_pos == 4) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == cc->mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((cc->mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF6) == MBSFN_FDD_SF6) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 7: - if (cc->tdd_Config != NULL) { // TDD - if ((cc->mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF7) == MBSFN_TDD_SF7) { - if (msi_pos == 3) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == cc->mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((cc->mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF7) == MBSFN_TDD_SF7) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } else { // FDD - if ((cc->mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF7) == MBSFN_FDD_SF7) { - if (msi_pos == 5) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == cc->mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((cc->mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF7) == MBSFN_FDD_SF7) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 8: - if (cc->tdd_Config != NULL) { //TDD - if ((cc->mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF8) == MBSFN_TDD_SF8) { - if (msi_pos == 4) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == cc->mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((cc->mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF8) == MBSFN_TDD_SF8) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } else { // FDD - if ((cc->mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF8) == MBSFN_FDD_SF8) { - if (msi_pos == 6) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == cc->mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((cc->mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF8) == MBSFN_FDD_SF8) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 9: - if (cc->tdd_Config != NULL) { - if ((cc->mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF9) == MBSFN_TDD_SF9) { - if (msi_pos == 5) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == cc->mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((cc->mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF9) == MBSFN_TDD_SF9) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - }// end switch - - // sf allocation is non-overlapping - if ((msi_flag==1) || (mcch_flag==1) || (mtch_flag==1)) { - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d Subframe %d: sync area %d SF alloc %d: msi flag %d, mcch flag %d, mtch flag %d\n", - module_idP, CC_id, frameP, subframeP,i,j,msi_flag,mcch_flag,mtch_flag); - break; - } - } else { // four-frameP format - } - } - } // end of for loop - - cc->msi_active=0; - cc->mcch_active=0; - cc->mtch_active=0; - - // Calculate the mcs - if ((msi_flag==1) || (mcch_flag==1)) { - cc->MCH_pdu.mcs = mcch_mcs; - } else if (mtch_flag == 1) { // only MTCH in this subframeP - cc->MCH_pdu.mcs = cc->pmch_Config[0]->dataMCS_r9; - } - - - // 2nd: Create MSI, get MCCH from RRC and MTCHs from RLC - - // there is MSI (MCH Scheduling Info) - if (msi_flag == 1) { - // Create MSI here - uint16_t msi_control_element[29], *msi_ptr; - - msi_ptr = &msi_control_element[0]; - ((MSI_ELEMENT *) msi_ptr)->lcid = MCCH_LCHANID; //MCCH - - if (mcch_flag==1) { - ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0; - ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0; - } else { // no mcch for this MSP - ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0x7;// stop value is 2047 - ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0xff; - } - - msi_ptr+= sizeof(MSI_ELEMENT); - - //Header for MTCHs - num_mtch = cc->mbms_SessionList[0]->list.count; - - for (k=0; klcid = cc->mbms_SessionList[0]->list.array[k]->logicalChannelIdentity_r9;//mtch_lcid; - ((MSI_ELEMENT *) msi_ptr)->stop_sf_MSB = 0; // last subframeP of this mtch (only one mtch now) - ((MSI_ELEMENT *) msi_ptr)->stop_sf_LSB = 0xB; - msi_ptr+=sizeof(MSI_ELEMENT); - } - - msi_length = msi_ptr-msi_control_element; - - if (msi_length<128) { - header_len_msi = 2; - } else { - header_len_msi = 3; - } - - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : MSI->MCH, length of MSI is %d bytes \n", - module_idP,CC_id,frameP,msi_length); - //LOG_D(MAC,"Scheduler: MSI is transmitted in this subframeP \n" ); - - // LOG_D(MAC,"Scheduler: MSI length is %d bytes\n",msi_length); - // Store MSI data to mch_buffer[0] - memcpy((char *)&mch_buffer[sdu_length_total], - msi_control_element, - msi_length); - - sdu_lcids[num_sdus] = MCH_SCHDL_INFO; - sdu_lengths[num_sdus] = msi_length; - sdu_length_total += sdu_lengths[num_sdus]; - LOG_I(MAC,"[eNB %d] CC_id %d Create %d bytes for MSI\n", module_idP, CC_id, sdu_lengths[num_sdus]); - num_sdus++; - cc->msi_active=1; - } - - // there is MCCH - if (mcch_flag == 1) { - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d Subframe %d: Schedule MCCH MESSAGE (area %d, sfAlloc %d)\n", - module_idP, CC_id, frameP, subframeP, i, j); - - mcch_sdu_length = mac_rrc_data_req(module_idP, - CC_id, - frameP, - MCCH,1, - &cc->MCCH_pdu.payload[0], - 1,// this is eNB - module_idP, // index - i); // this is the mbsfn sync area index - - if (mcch_sdu_length > 0) { - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframeP %d : MCCH->MCH, Received %d bytes from RRC \n", - module_idP,CC_id,frameP,subframeP,mcch_sdu_length); - - header_len_mcch = 2; - - if (cc->tdd_Config != NULL) { - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframeP %d: Scheduling MCCH->MCH (TDD) for MCCH message %d bytes (mcs %d )\n", - module_idP, CC_id, - frameP,subframeP, - mcch_sdu_length, - mcch_mcs); - } else { - LOG_I(MAC,"[eNB %d] CC_id %d Frame %d subframeP %d: Scheduling MCCH->MCH (FDD) for MCCH message %d bytes (mcs %d)\n", - module_idP, CC_id, - frameP, subframeP, - mcch_sdu_length, - mcch_mcs); - } - - cc->mcch_active=1; - - memcpy((char *)&mch_buffer[sdu_length_total], - &cc->MCCH_pdu.payload[0], - mcch_sdu_length); - sdu_lcids[num_sdus] = MCCH_LCHANID; - sdu_lengths[num_sdus] = mcch_sdu_length; - - if (sdu_lengths[num_sdus]>128) { - header_len_mcch = 3; - } - - sdu_length_total += sdu_lengths[num_sdus]; - LOG_D(MAC,"[eNB %d] CC_id %d Got %d bytes for MCCH from RRC \n",module_idP,CC_id,sdu_lengths[num_sdus]); - num_sdus++; - } - } - - TBS = get_TBS_DL(cc->MCH_pdu.mcs, to_prb(cc->mib->message.dl_Bandwidth)); + TBS = + get_TBS_DL(cc->MCH_pdu.mcs, to_prb(cc->mib->message.dl_Bandwidth)); #if defined(Rel10) || defined(Rel14) - // do not let mcch and mtch multiplexing when relaying is active - // for sync area 1, so not transmit data - //if ((i == 0) && ((RC.mac[module_idP]->MBMS_flag != multicast_relay) || (RC.mac[module_idP]->mcch_active==0))) { + // do not let mcch and mtch multiplexing when relaying is active + // for sync area 1, so not transmit data + //if ((i == 0) && ((RC.mac[module_idP]->MBMS_flag != multicast_relay) || (RC.mac[module_idP]->mcch_active==0))) { #endif - // there is MTCHs, loop if there are more than 1 - if (mtch_flag == 1) { - // Calculate TBS - /* if ((msi_flag==1) || (mcch_flag==1)) { - TBS = mac_xface->get_TBS(mcch_mcs, mac_xface->frame_parms->N_RB_DL); - } - else { // only MTCH in this subframeP - TBS = mac_xface->get_TBS(RC.mac[module_idP]->pmch_Config[0]->dataMCS_r9, mac_xface->frame_parms->N_RB_DL); - } + // there is MTCHs, loop if there are more than 1 + if (mtch_flag == 1) { + // Calculate TBS + /* if ((msi_flag==1) || (mcch_flag==1)) { + TBS = mac_xface->get_TBS(mcch_mcs, mac_xface->frame_parms->N_RB_DL); + } + else { // only MTCH in this subframeP + TBS = mac_xface->get_TBS(RC.mac[module_idP]->pmch_Config[0]->dataMCS_r9, mac_xface->frame_parms->N_RB_DL); + } - // get MTCH data from RLC (like for DTCH) - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframe %d: Schedule MTCH (area %d, sfAlloc %d)\n",Mod_id,CC_id,frame,subframe,i,j); + // get MTCH data from RLC (like for DTCH) + LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframe %d: Schedule MTCH (area %d, sfAlloc %d)\n",Mod_id,CC_id,frame,subframe,i,j); - header_len_mtch = 3; - LOG_D(MAC,"[eNB %d], CC_id %d, Frame %d, MTCH->MCH, Checking RLC status (rab %d, tbs %d, len %d)\n", - Mod_id,CC_id,frame,MTCH,TBS, - TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); + header_len_mtch = 3; + LOG_D(MAC,"[eNB %d], CC_id %d, Frame %d, MTCH->MCH, Checking RLC status (rab %d, tbs %d, len %d)\n", + Mod_id,CC_id,frame,MTCH,TBS, + TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); - rlc_status = mac_rlc_status_ind(Mod_id,frame,1,RLC_MBMS_YES,MTCH+ (maxDRB + 3) * MAX_MOBILES_PER_RG, - TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); - printf("frame %d, subframe %d, rlc_status.bytes_in_buffer is %d\n",frame,subframe, rlc_status.bytes_in_buffer); + rlc_status = mac_rlc_status_ind(Mod_id,frame,1,RLC_MBMS_YES,MTCH+ (maxDRB + 3) * MAX_MOBILES_PER_RG, + TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); + printf("frame %d, subframe %d, rlc_status.bytes_in_buffer is %d\n",frame,subframe, rlc_status.bytes_in_buffer); - */ + */ - // get MTCH data from RLC (like for DTCH) - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d subframeP %d: Schedule MTCH (area %d, sfAlloc %d)\n",module_idP,CC_id,frameP,subframeP,i,j); + // get MTCH data from RLC (like for DTCH) + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d subframeP %d: Schedule MTCH (area %d, sfAlloc %d)\n", + module_idP, CC_id, frameP, subframeP, i, j); - header_len_mtch = 3; - LOG_D(MAC,"[eNB %d], CC_id %d, Frame %d, MTCH->MCH, Checking RLC status (rab %d, tbs %d, len %d)\n", - module_idP,CC_id,frameP,MTCH,TBS, - TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); + header_len_mtch = 3; + LOG_D(MAC, + "[eNB %d], CC_id %d, Frame %d, MTCH->MCH, Checking RLC status (rab %d, tbs %d, len %d)\n", + module_idP, CC_id, frameP, MTCH, TBS, + TBS - header_len_mcch - header_len_msi - sdu_length_total - + header_len_mtch); - rlc_status = mac_rlc_status_ind(module_idP,0,frameP,subframeP,module_idP,ENB_FLAG_YES,MBMS_FLAG_YES,MTCH, - TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); - LOG_D(MAC,"e-MBMS log channel %u frameP %d, subframeP %d, rlc_status.bytes_in_buffer is %d\n", - MTCH,frameP,subframeP, rlc_status.bytes_in_buffer); + rlc_status = + mac_rlc_status_ind(module_idP, 0, frameP, subframeP, + module_idP, ENB_FLAG_YES, MBMS_FLAG_YES, + MTCH, + TBS - header_len_mcch - header_len_msi - + sdu_length_total - header_len_mtch); + LOG_D(MAC, + "e-MBMS log channel %u frameP %d, subframeP %d, rlc_status.bytes_in_buffer is %d\n", + MTCH, frameP, subframeP, rlc_status.bytes_in_buffer); - if (rlc_status.bytes_in_buffer >0) { - LOG_I(MAC,"[eNB %d][MBMS USER-PLANE], CC_id %d, Frame %d, MTCH->MCH, Requesting %d bytes from RLC (header len mtch %d)\n", - module_idP,CC_id,frameP,TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch,header_len_mtch); + if (rlc_status.bytes_in_buffer > 0) { + LOG_I(MAC, + "[eNB %d][MBMS USER-PLANE], CC_id %d, Frame %d, MTCH->MCH, Requesting %d bytes from RLC (header len mtch %d)\n", + module_idP, CC_id, frameP, + TBS - header_len_mcch - header_len_msi - + sdu_length_total - header_len_mtch, header_len_mtch); - sdu_lengths[num_sdus] = mac_rlc_data_req( - module_idP, - 0, - module_idP, - frameP, - ENB_FLAG_YES, - MBMS_FLAG_YES, - MTCH, - 0, //not used - (char*)&mch_buffer[sdu_length_total]); - //sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,frameP, MBMS_FLAG_NO, MTCH+(MAX_NUM_RB*(NUMBER_OF_UE_MAX+1)), (char*)&mch_buffer[sdu_length_total]); - LOG_I(MAC,"[eNB %d][MBMS USER-PLANE] CC_id %d Got %d bytes for MTCH %d\n",module_idP,CC_id,sdu_lengths[num_sdus],MTCH); - cc->mtch_active=1; - sdu_lcids[num_sdus] = MTCH; - sdu_length_total += sdu_lengths[num_sdus]; + sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, 0, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_YES, MTCH, 0, //not used + (char *) + &mch_buffer + [sdu_length_total]); + //sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,frameP, MBMS_FLAG_NO, MTCH+(MAX_NUM_RB*(NUMBER_OF_UE_MAX+1)), (char*)&mch_buffer[sdu_length_total]); + LOG_I(MAC, + "[eNB %d][MBMS USER-PLANE] CC_id %d Got %d bytes for MTCH %d\n", + module_idP, CC_id, sdu_lengths[num_sdus], MTCH); + cc->mtch_active = 1; + sdu_lcids[num_sdus] = MTCH; + sdu_length_total += sdu_lengths[num_sdus]; - if (sdu_lengths[num_sdus] < 128) { - header_len_mtch = 2; - } + if (sdu_lengths[num_sdus] < 128) { + header_len_mtch = 2; + } - num_sdus++; - } else { - header_len_mtch = 0; + num_sdus++; + } else { + header_len_mtch = 0; + } } - } - #if defined(Rel10) || defined(Rel14) - // } + // } #endif - // FINAL STEP: Prepare and multiplexe MSI, MCCH and MTCHs - if ((sdu_length_total + header_len_msi + header_len_mcch + header_len_mtch) >0) { - // Adjust the last subheader - /* if ((msi_flag==1) || (mcch_flag==1)) { - RC.mac[module_idP]->MCH_pdu.mcs = mcch_mcs; - } - else if (mtch_flag == 1) { // only MTCH in this subframeP - RC.mac[module_idP]->MCH_pdu.mcs = RC.mac[module_idP]->pmch_Config[0]->dataMCS_r9; - } - */ - header_len_mtch_temp = header_len_mtch; - header_len_mcch_temp = header_len_mcch; - header_len_msi_temp = header_len_msi; + // FINAL STEP: Prepare and multiplexe MSI, MCCH and MTCHs + if ((sdu_length_total + header_len_msi + header_len_mcch + + header_len_mtch) > 0) { + // Adjust the last subheader + /* if ((msi_flag==1) || (mcch_flag==1)) { + RC.mac[module_idP]->MCH_pdu.mcs = mcch_mcs; + } + else if (mtch_flag == 1) { // only MTCH in this subframeP + RC.mac[module_idP]->MCH_pdu.mcs = RC.mac[module_idP]->pmch_Config[0]->dataMCS_r9; + } + */ + header_len_mtch_temp = header_len_mtch; + header_len_mcch_temp = header_len_mcch; + header_len_msi_temp = header_len_msi; - if (header_len_mtch>0) { - header_len_mtch=1; // remove Length field in the subheader for the last PDU - } else if (header_len_mcch>0) { - header_len_mcch=1; + if (header_len_mtch > 0) { + header_len_mtch = 1; // remove Length field in the subheader for the last PDU + } else if (header_len_mcch > 0) { + header_len_mcch = 1; + } else { + header_len_msi = 1; + } + + // Calculate the padding + if ((TBS - header_len_mtch - header_len_mcch - header_len_msi - + sdu_length_total) < 0) { + LOG_E(MAC, "Error in building MAC PDU, TBS %d < PDU %d \n", + TBS, + header_len_mtch + header_len_mcch + header_len_msi + + sdu_length_total); + return 0; + } else + if ((TBS - header_len_mtch - header_len_mcch - header_len_msi - + sdu_length_total) <= 2) { + padding = + (TBS - header_len_mtch - header_len_mcch - header_len_msi - + sdu_length_total); + post_padding = 0; + } else { // using post_padding, give back the Length field of subheader for the last PDU + padding = 0; + + if (header_len_mtch > 0) { + header_len_mtch = header_len_mtch_temp; + } else if (header_len_mcch > 0) { + header_len_mcch = header_len_mcch_temp; + } else { + header_len_msi = header_len_msi_temp; + } + + post_padding = + TBS - sdu_length_total - header_len_msi - header_len_mcch - + header_len_mtch; + } + + // Generate the MAC Header for MCH + // here we use the function for DLSCH because DLSCH & MCH have the same Header structure + offset = generate_dlsch_header((unsigned char *) cc->MCH_pdu.payload, num_sdus, sdu_lengths, sdu_lcids, 255, // no drx + 31, // no timing advance + NULL, // no contention res id + padding, post_padding); + + cc->MCH_pdu.Pdu_size = TBS; + cc->MCH_pdu.sync_area = i; + cc->MCH_pdu.msi_active = cc->msi_active; + cc->MCH_pdu.mcch_active = cc->mcch_active; + cc->MCH_pdu.mtch_active = cc->mtch_active; + LOG_D(MAC, + " MCS for this sf is %d (mcch active %d, mtch active %d)\n", + cc->MCH_pdu.mcs, cc->MCH_pdu.mcch_active, + cc->MCH_pdu.mtch_active); + LOG_I(MAC, + "[eNB %d][MBMS USER-PLANE ] CC_id %d Generate header : sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,padding %d,post_padding %d (mcs %d, TBS %d), header MTCH %d, header MCCH %d, header MSI %d\n", + module_idP, CC_id, sdu_length_total, num_sdus, + sdu_lengths[0], sdu_lcids[0], offset, padding, post_padding, + cc->MCH_pdu.mcs, TBS, header_len_mtch, header_len_mcch, + header_len_msi); + // copy SDU to mch_pdu after the MAC Header + memcpy(&cc->MCH_pdu.payload[offset], mch_buffer, sdu_length_total); + + // filling remainder of MCH with random data if necessery + for (j = 0; j < (TBS - sdu_length_total - offset); j++) { + cc->MCH_pdu.payload[offset + sdu_length_total + j] = + (char) (taus() & 0xff); + } + + /* Tracing of PDU is done on UE side */ + if (opt_enabled == 1) { + trace_pdu(1, (uint8_t *) cc->MCH_pdu.payload, TBS, module_idP, 6, 0xffff, // M_RNTI = 6 in wirehsark + RC.mac[module_idP]->frame, + RC.mac[module_idP]->subframe, 0, 0); + LOG_D(OPT, + "[eNB %d][MCH] CC_id %d Frame %d : MAC PDU with size %d\n", + module_idP, CC_id, frameP, TBS); + } + + /* + for (j=0;jMCH_pdu.payload[j+offset]); + printf(" \n"); */ + return 1; } else { - header_len_msi=1; - } - - // Calculate the padding - if ((TBS - header_len_mtch - header_len_mcch - header_len_msi - sdu_length_total) < 0) { - LOG_E(MAC,"Error in building MAC PDU, TBS %d < PDU %d \n", - TBS, header_len_mtch + header_len_mcch + header_len_msi + sdu_length_total); - return 0; - } else if ((TBS - header_len_mtch - header_len_mcch - header_len_msi - sdu_length_total) <= 2) { - padding = (TBS - header_len_mtch - header_len_mcch - header_len_msi - sdu_length_total); - post_padding = 0; - } else { // using post_padding, give back the Length field of subheader for the last PDU - padding = 0; - - if (header_len_mtch>0) { - header_len_mtch = header_len_mtch_temp; - } else if (header_len_mcch>0) { - header_len_mcch = header_len_mcch_temp; - } else { - header_len_msi = header_len_msi_temp; - } - - post_padding = TBS - sdu_length_total - header_len_msi - header_len_mcch - header_len_mtch; - } - - // Generate the MAC Header for MCH - // here we use the function for DLSCH because DLSCH & MCH have the same Header structure - offset = generate_dlsch_header((unsigned char*)cc->MCH_pdu.payload, - num_sdus, - sdu_lengths, - sdu_lcids, - 255, // no drx - 31, // no timing advance - NULL, // no contention res id - padding, - post_padding); - - cc->MCH_pdu.Pdu_size=TBS; - cc->MCH_pdu.sync_area=i; - cc->MCH_pdu.msi_active= cc->msi_active; - cc->MCH_pdu.mcch_active= cc->mcch_active; - cc->MCH_pdu.mtch_active= cc->mtch_active; - LOG_D(MAC," MCS for this sf is %d (mcch active %d, mtch active %d)\n", cc->MCH_pdu.mcs, - cc->MCH_pdu.mcch_active,cc->MCH_pdu.mtch_active ); - LOG_I(MAC, - "[eNB %d][MBMS USER-PLANE ] CC_id %d Generate header : sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,padding %d,post_padding %d (mcs %d, TBS %d), header MTCH %d, header MCCH %d, header MSI %d\n", - module_idP,CC_id,sdu_length_total,num_sdus,sdu_lengths[0],sdu_lcids[0],offset,padding,post_padding,cc->MCH_pdu.mcs,TBS, - header_len_mtch, header_len_mcch, header_len_msi); - // copy SDU to mch_pdu after the MAC Header - memcpy(&cc->MCH_pdu.payload[offset],mch_buffer,sdu_length_total); - - // filling remainder of MCH with random data if necessery - for (j=0; j<(TBS-sdu_length_total-offset); j++) { - cc->MCH_pdu.payload[offset+sdu_length_total+j] = (char)(taus()&0xff); - } - - /* Tracing of PDU is done on UE side */ - if (opt_enabled ==1 ) { - trace_pdu(1, (uint8_t *)cc->MCH_pdu.payload, - TBS, module_idP, 6, 0xffff, // M_RNTI = 6 in wirehsark - RC.mac[module_idP]->frame, RC.mac[module_idP]->subframe,0,0); - LOG_D(OPT,"[eNB %d][MCH] CC_id %d Frame %d : MAC PDU with size %d\n", - module_idP, CC_id, frameP, TBS); + cc->MCH_pdu.Pdu_size = 0; + cc->MCH_pdu.sync_area = 0; + cc->MCH_pdu.msi_active = 0; + cc->MCH_pdu.mcch_active = 0; + cc->MCH_pdu.mtch_active = 0; + // for testing purpose, fill with random data + //for (j=0;j<(TBS-sdu_length_total-offset);j++) + // RC.mac[module_idP]->MCH_pdu.payload[offset+sdu_length_total+j] = (char)(taus()&0xff); + return 0; } + //this is for testing /* - for (j=0;jMCH_pdu.payload[j+offset]); - printf(" \n");*/ - return 1; - } else { - cc->MCH_pdu.Pdu_size=0; - cc->MCH_pdu.sync_area=0; - cc->MCH_pdu.msi_active=0; - cc->MCH_pdu.mcch_active=0; - cc->MCH_pdu.mtch_active=0; - // for testing purpose, fill with random data - //for (j=0;j<(TBS-sdu_length_total-offset);j++) - // RC.mac[module_idP]->MCH_pdu.payload[offset+sdu_length_total+j] = (char)(taus()&0xff); - return 0; - } - - //this is for testing - /* - if (mtch_flag == 1) { - // LOG_D(MAC,"DUY: mch_buffer length so far is : %ld\n", &mch_buffer[sdu_length_total]-&mch_buffer[0]); - return 1; - } - else - return 0; - */ + if (mtch_flag == 1) { + // LOG_D(MAC,"DUY: mch_buffer length so far is : %ld\n", &mch_buffer[sdu_length_total]-&mch_buffer[0]); + return 1; + } + else + return 0; + */ } -MCH_PDU *get_mch_sdu(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t subframeP) +MCH_PDU *get_mch_sdu(module_id_t module_idP, int CC_id, frame_t frameP, + sub_frame_t subframeP) { - // RC.mac[module_idP]->MCH_pdu.mcs=0; - //LOG_D(MAC," MCH_pdu.mcs is %d\n", RC.mac[module_idP]->MCH_pdu.mcs); + // RC.mac[module_idP]->MCH_pdu.mcs=0; + //LOG_D(MAC," MCH_pdu.mcs is %d\n", RC.mac[module_idP]->MCH_pdu.mcs); //#warning "MCH pdu should take the CC_id index" - return(&RC.mac[module_idP]->common_channels[CC_id].MCH_pdu); + return (&RC.mac[module_idP]->common_channels[CC_id].MCH_pdu); } #endif diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 19ff3cf39f..42c50d8063 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -53,7 +53,7 @@ #include "pdcp.h" #if defined(ENABLE_ITTI) -# include "intertask_interface.h" +#include "intertask_interface.h" #endif #include "T.h" @@ -61,1449 +61,1781 @@ #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_eNB_SCHEDULER 1 -int choose(int n,int k) +int choose(int n, int k) { - int res = 1; - int res2 = 1; - int i; + int res = 1; + int res2 = 1; + int i; - if (k>n) return(0); - if (n==k) return(1); + if (k > n) + return (0); + if (n == k) + return (1); - for (i=n;i>k;i--) res*=i; - for (i=2;i<=(n-k);i++) res2*=i; + for (i = n; i > k; i--) + res *= i; + for (i = 2; i <= (n - k); i++) + res2 *= i; - return(res/res2); + return (res / res2); } // Patented algorithm from Yang et al, US Patent 2009, "Channel Quality Indexing and Reverse Indexing" -void reverse_index(int N,int M,int r,int *v) +void reverse_index(int N, int M, int r, int *v) { - int BaseValue=0; - int IncreaseValue,ThresholdValue; - int sumV; - int i; + int BaseValue = 0; + int IncreaseValue, ThresholdValue; + int sumV; + int i; - r = choose(N,M) - 1 - r; - memset((void*)v,0,M*sizeof(int)); + r = choose(N, M) - 1 - r; + memset((void *) v, 0, M * sizeof(int)); - sumV=0; - i=M; - while (i>0 && r>0) { - IncreaseValue = choose(N-M+1-sumV-v[i-1]+i-2,i-1); - ThresholdValue = BaseValue+IncreaseValue; - if (r>=ThresholdValue) { - v[i-1]++; - BaseValue=ThresholdValue; + sumV = 0; + i = M; + while (i > 0 && r > 0) { + IncreaseValue = choose(N - M + 1 - sumV - v[i - 1] + i - 2, i - 1); + ThresholdValue = BaseValue + IncreaseValue; + if (r >= ThresholdValue) { + v[i - 1]++; + BaseValue = ThresholdValue; + } else { + r = r - BaseValue; + sumV += v[i - 1]; + i--; + BaseValue = 0; + } } - else { - r=r-BaseValue; - sumV+=v[i-1]; - i--; - BaseValue=0; - } - } } int to_prb(int dl_Bandwidth) { - int prbmap[6] = {6,15,25,50,75,100}; + int prbmap[6] = { 6, 15, 25, 50, 75, 100 }; - AssertFatal(dl_Bandwidth < 6,"dl_Bandwidth is 0..5\n"); - return(prbmap[dl_Bandwidth]); + AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth is 0..5\n"); + return (prbmap[dl_Bandwidth]); } int to_rbg(int dl_Bandwidth) { - int rbgmap[6] = {6,8,13,17,19,25}; + int rbgmap[6] = { 6, 8, 13, 17, 19, 25 }; - AssertFatal(dl_Bandwidth < 6,"dl_Bandwidth is 0..5\n"); - return(rbgmap[dl_Bandwidth]); + AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth is 0..5\n"); + return (rbgmap[dl_Bandwidth]); } -int get_phich_resource_times6(COMMON_channels_t *cc) +int get_phich_resource_times6(COMMON_channels_t * cc) { - int phichmap[4] = {1,3,6,12}; - AssertFatal(cc!=NULL,"cc is null\n"); - AssertFatal(cc->mib!=NULL,"cc->mib is null\n"); - AssertFatal((cc->mib->message.phich_Config.phich_Resource>=0) && - (cc->mib->message.phich_Config.phich_Resource<4), - "phich_Resource %d not in 0..3\n",(int)cc->mib->message.phich_Config.phich_Resource); + int phichmap[4] = { 1, 3, 6, 12 }; + AssertFatal(cc != NULL, "cc is null\n"); + AssertFatal(cc->mib != NULL, "cc->mib is null\n"); + AssertFatal((cc->mib->message.phich_Config.phich_Resource >= 0) && + (cc->mib->message.phich_Config.phich_Resource < 4), + "phich_Resource %d not in 0..3\n", + (int) cc->mib->message.phich_Config.phich_Resource); - return(phichmap[cc->mib->message.phich_Config.phich_Resource]); + return (phichmap[cc->mib->message.phich_Config.phich_Resource]); } -uint16_t mac_computeRIV(uint16_t N_RB_DL,uint16_t RBstart,uint16_t Lcrbs) +uint16_t mac_computeRIV(uint16_t N_RB_DL, uint16_t RBstart, uint16_t Lcrbs) { - uint16_t RIV; + uint16_t RIV; - if (Lcrbs<=(1+(N_RB_DL>>1))) - RIV = (N_RB_DL*(Lcrbs-1)) + RBstart; - else - RIV = (N_RB_DL*(N_RB_DL+1-Lcrbs)) + (N_RB_DL-1-RBstart); + if (Lcrbs <= (1 + (N_RB_DL >> 1))) + RIV = (N_RB_DL * (Lcrbs - 1)) + RBstart; + else + RIV = (N_RB_DL * (N_RB_DL + 1 - Lcrbs)) + (N_RB_DL - 1 - RBstart); - return(RIV); + return (RIV); } uint8_t getQm(uint8_t mcs) { - if (mcs<10) return(2); - else if (mcs<17) return(4); - else return (6); -} - -void get_Msg3alloc(COMMON_channels_t *cc, - - sub_frame_t current_subframe, - frame_t current_frame, - frame_t *frame, - sub_frame_t *subframe) -{ - // Fill in other TDD Configuration!!!! - - if (cc->tdd_Config==NULL) { // FDD - *subframe = current_subframe+6; - - if (*subframe>9) { - *subframe = *subframe-10; - *frame = (current_frame+1) & 1023; - } else { - *frame=current_frame; - } - } else { // TDD - if (cc->tdd_Config->subframeAssignment == 1) { - switch (current_subframe) { - - case 0: - *subframe = 7; - *frame = current_frame; - break; - - case 4: - *subframe = 2; - *frame = (current_frame+1) & 1023; - break; - - case 5: - *subframe = 2; - *frame = (current_frame+1) & 1023; - break; - - case 9: - *subframe = 7; - *frame = (current_frame+1) & 1023; - break; - } - } else if (cc->tdd_Config->subframeAssignment == 3) { - switch (current_subframe) { - - case 0: - case 5: - case 6: - *subframe = 2; - *frame = (current_frame+1) & 1023; - break; - - case 7: - *subframe = 3; - *frame = (current_frame+1) & 1023; - break; - - case 8: - *subframe = 4; - *frame = (current_frame+1) & 1023; - break; - - case 9: - *subframe = 2; - *frame = (current_frame+2) & 1023; - break; - } - } else if (cc->tdd_Config->subframeAssignment == 4) { - switch (current_subframe) { - - case 0: - case 4: - case 5: - case 6: - *subframe = 2; - *frame = (current_frame+1) & 1023; - break; - - case 7: - *subframe = 3; - *frame = (current_frame+1) & 1023; - break; - - case 8: - case 9: - *subframe = 2; - *frame = (current_frame+2) & 1023; - break; - } - } else if (cc->tdd_Config->subframeAssignment == 5) { - switch (current_subframe) { - - case 0: - case 4: - case 5: - case 6: - *subframe = 2; - *frame = (current_frame+1) & 1023; - break; - - case 7: - case 8: - case 9: - *subframe = 2; - *frame = (current_frame+2) & 1023; - break; - } - } - } -} - - - -void get_Msg3allocret(COMMON_channels_t *cc, - sub_frame_t current_subframe, - frame_t current_frame, - frame_t *frame, - sub_frame_t *subframe) -{ - if (cc->tdd_Config == NULL) { //FDD - /* always retransmit in n+8 */ - *subframe = current_subframe + 8; - - if (*subframe > 9) { - *subframe = *subframe - 10; - *frame = (current_frame + 1) & 1023; - } else { - *frame = current_frame; - } - } else { - if (cc->tdd_Config->subframeAssignment == 1) { - // original PUSCH in 2, PHICH in 6 (S), ret in 2 - // original PUSCH in 3, PHICH in 9, ret in 3 - // original PUSCH in 7, PHICH in 1 (S), ret in 7 - // original PUSCH in 8, PHICH in 4, ret in 8 - *frame = (current_frame+1) & 1023; - } else if (cc->tdd_Config->subframeAssignment == 3) { - // original PUSCH in 2, PHICH in 8, ret in 2 next frame - // original PUSCH in 3, PHICH in 9, ret in 3 next frame - // original PUSCH in 4, PHICH in 0, ret in 4 next frame - *frame=(current_frame+1) & 1023; - } else if (cc->tdd_Config->subframeAssignment == 4) { - // original PUSCH in 2, PHICH in 8, ret in 2 next frame - // original PUSCH in 3, PHICH in 9, ret in 3 next frame - *frame=(current_frame+1) & 1023; - } else if (cc->tdd_Config->subframeAssignment == 5) { - // original PUSCH in 2, PHICH in 8, ret in 2 next frame - *frame=(current_frame+1) & 1023; - } - } -} - -uint8_t subframe2harqpid(COMMON_channels_t *cc,frame_t frame,sub_frame_t subframe) -{ - uint8_t ret = 255; - - AssertFatal(cc!=NULL,"cc is null\n"); - - if (cc->tdd_Config == NULL) { // FDD - ret = (((frame<<1)+subframe)&7); - } else { - switch (cc->tdd_Config->subframeAssignment) { - case 1: - if ((subframe==2) || - (subframe==3) || - (subframe==7) || - (subframe==8)) - switch (subframe) { - case 2: - case 3: - ret = (subframe-2); - break; - - case 7: - case 8: - ret = (subframe-5); - break; - - default: - AssertFatal(1==0,"subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframe,(int)cc->tdd_Config->subframeAssignment); - break; - } - - break; - - case 2: - AssertFatal((subframe==2) || (subframe==7), - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframe,(int)cc->tdd_Config->subframeAssignment); - - ret = (subframe/7); - break; - - case 3: - AssertFatal((subframe>1) && (subframe<5), - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframe,(int)cc->tdd_Config->subframeAssignment); - ret = (subframe-2); - break; - - case 4: - AssertFatal((subframe>1) && (subframe<4), - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframe,(int)cc->tdd_Config->subframeAssignment); - ret = (subframe-2); - break; - - case 5: - AssertFatal(subframe==2, - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframe,(int)cc->tdd_Config->subframeAssignment); - ret = (subframe-2); - break; - - default: - AssertFatal(1==0,"subframe2_harq_pid, Unsupported TDD mode %d\n",(int)cc->tdd_Config->subframeAssignment); - } - } - return ret; -} - -uint8_t get_Msg3harqpid(COMMON_channels_t *cc, - frame_t frame, - sub_frame_t current_subframe) -{ - uint8_t ul_subframe=0; - uint32_t ul_frame=0; - - if (cc->tdd_Config == NULL) { // FDD - ul_subframe = (current_subframe>3) ? (current_subframe-4) : (current_subframe+6); - ul_frame = (current_subframe>3) ? ((frame+1)&1023) : frame; - } else { - switch (cc->tdd_Config->subframeAssignment) { - case 1: - switch (current_subframe) { - case 9: - case 0: - ul_subframe = 7; - break; - - case 5: - case 7: - ul_subframe = 2; - break; - - } - - break; - - case 3: - switch (current_subframe) { - case 0: - case 5: - case 6: - ul_subframe = 2; - break; - - case 7: - ul_subframe = 3; - break; - - case 8: - ul_subframe = 4; - break; - - case 9: - ul_subframe = 2; - break; - } - - break; - - case 4: - switch (current_subframe) { - case 0: - case 5: - case 6: - case 8: - case 9: - ul_subframe = 2; - break; - - case 7: - ul_subframe = 3; - break; - } - - break; - - case 5: - ul_subframe =2; - break; - - default: - LOG_E(PHY,"get_Msg3_harq_pid: Unsupported TDD configuration %d\n",(int)cc->tdd_Config->subframeAssignment); - AssertFatal(1==0,"get_Msg3_harq_pid: Unsupported TDD configuration"); - break; - } - } - - return(subframe2harqpid(cc,ul_frame,ul_subframe)); -} - -uint32_t pdcchalloc2ulframe(COMMON_channels_t *ccP,uint32_t frame, uint8_t n) -{ - uint32_t ul_frame; - - if ((ccP->tdd_Config) && - (ccP->tdd_Config->subframeAssignment == 1) && - ((n==1)||(n==6))) // tdd_config 0,1 SF 1,5 - ul_frame = (frame + (n==1 ? 0 : 1)); - else if ((ccP->tdd_Config) && - (ccP->tdd_Config->subframeAssignment == 6) && - ((n==0)||(n==1)||(n==5)||(n==6))) - ul_frame = (frame + (n>=5 ? 1 : 0)); - else if ((ccP->tdd_Config) && - (ccP->tdd_Config->subframeAssignment == 6) && - (n==9)) // tdd_config 6 SF 9 - ul_frame = (frame+1); - else - ul_frame = (frame+(n>=6 ? 1 : 0)); - - LOG_D(PHY, "frame %d subframe %d: PUSCH frame = %d\n", frame, n, ul_frame); - return ul_frame; -} - -uint8_t pdcchalloc2ulsubframe(COMMON_channels_t *ccP,uint8_t n) -{ - uint8_t ul_subframe; - - if ((ccP->tdd_Config) && - (ccP->tdd_Config->subframeAssignment == 1) && - ((n==1)||(n==6))) // tdd_config 0,1 SF 1,5 - ul_subframe = ((n+6)%10); - else if ((ccP->tdd_Config) && - (ccP->tdd_Config->subframeAssignment == 6) && - ((n==0)||(n==1)||(n==5)||(n==6))) - ul_subframe = ((n+7)%10); - else if ((ccP->tdd_Config) && - (ccP->tdd_Config->subframeAssignment == 6) && - (n==9)) // tdd_config 6 SF 9 - ul_subframe = ((n+5)%10); - else - ul_subframe = ((n+4)%10); - - LOG_D(PHY, "subframe %d: PUSCH subframe = %d\n", n, ul_subframe); - return ul_subframe; -} - -int is_UL_sf(COMMON_channels_t *ccP,sub_frame_t subframeP) -{ - // if FDD return dummy value - if (ccP->tdd_Config == NULL) - return(0); - - switch (ccP->tdd_Config->subframeAssignment) { - case 1: - switch (subframeP) { - case 0: - case 4: - case 5: - case 9: - return(0); - break; - - case 2: - case 3: - case 7: - case 8: - return(1); - break; - - default: - return(0); - break; - } - break; - - case 3: - if ((subframeP<=1) || (subframeP>=5)) - return(0); - else if ((subframeP>1) && (subframeP < 5)) - return(1); - else AssertFatal(1==0,"Unknown subframe number\n"); - break; - - case 4: - if ((subframeP<=1) || (subframeP>=4)) - return(0); - else if ((subframeP>1) && (subframeP < 4)) - return(1); - else AssertFatal(1==0,"Unknown subframe number\n"); - break; - - case 5: - if ((subframeP<=1) || (subframeP>=3)) - return(0); - else if ((subframeP>1) && (subframeP < 3)) - return(1); - else AssertFatal(1==0,"Unknown subframe number\n"); - break; - - default: - AssertFatal(1==0,"subframe %d Unsupported TDD configuration %d\n", - subframeP,(int)ccP->tdd_Config->subframeAssignment); - break; - } -} - -uint16_t get_pucch1_absSF(COMMON_channels_t *cc,uint16_t dlsch_absSF) -{ - uint16_t sf,f,nextf; - - if (cc->tdd_Config==NULL) { //FDD n+4 - return((dlsch_absSF + 4)%10240); - } - else { - sf = dlsch_absSF%10; - f = dlsch_absSF/10; - nextf = (f+1)&1023; - - switch (cc->tdd_Config->subframeAssignment) { - case 0: - AssertFatal(1==0,"SFA 0 to be filled in now, :-)\n"); - break; - case 1: - if ((sf==5) || (sf==6)) return((10*nextf) + 2); // ACK/NAK in SF 2 next frame - else if (sf==9) return((10*nextf) + 3); // ACK/NAK in SF 3 next frame - else if ((sf==0) || (sf==1)) return((10*f) + 2); // ACK/NAK in SF 7 same frame - else AssertFatal(1==0,"Impossible dlsch subframe %d for TDD configuration 3\n",sf); - break; - case 2: - if ((sf==4) || (sf==5) || (sf==6) || (sf==8)) return((10*nextf) + 2); // ACK/NAK in SF 2 next frame - else if (sf==9) return((10*nextf) + 7); // ACK/NAK in SF 7 next frame - else if ((sf==0) || (sf==1) || (sf==3)) return((10*f) + 7); // ACK/NAK in SF 7 same frame - else AssertFatal(1==0,"Impossible dlsch subframe %d for TDD configuration 3\n",sf); - break; - case 3: - if ((sf==5) || (sf==6) || (sf==7) || (sf==8) || (sf==9)) return((10*nextf) + (sf>>1)); // ACK/NAK in 2,3,4 resp. next frame - else if (sf==1) return((10*nextf) + 2); // ACK/NAK in 2 next frame - else if (sf==0) return((10*f) + 4); // ACK/NAK in 4 same frame - else AssertFatal(1==0,"Impossible dlsch subframe %d for TDD configuration 3\n",sf); - break; - case 4: - if ((sf==6) || (sf==7) || (sf==8) || (sf==9)) return(((10*nextf) + 3)%10240); // ACK/NAK in SF 3 next frame - else if ((sf==0) || (sf==1) || (sf==4) || (sf==5)) return(((10*nextf) + 2)%10240); // ACK/NAK in SF 2 next frame - else AssertFatal(1==0,"Impossible dlsch subframe %d for TDD configuration 4\n",sf); - break; - case 5: - if ((sf==0) || (sf==1) || (sf==3) || (sf==4) || (sf==5) || (sf==6) || (sf==7) || (sf==8)) return(((10*nextf) + 2)%10240); // ACK/NAK in SF 3 next frame - else if (sf==9) return(((10*(1+nextf)) + 2)%10240); // ACK/NAK in SF 2 next frame - else AssertFatal(1==0,"Impossible dlsch subframe %d for TDD configuration 5\n",sf); - break; - case 6: - AssertFatal(1==0,"SFA 6 To be filled in now, :-)\n"); - break; - default: - AssertFatal(1==0,"Illegal TDD subframe Assigment %d\n",(int)cc->tdd_Config->subframeAssignment); - break; - } - } - AssertFatal(1==0,"Shouldn't get here\n"); -} - -void get_srs_pos(COMMON_channels_t *cc,uint16_t isrs,uint16_t *psrsPeriodicity,uint16_t *psrsOffset) -{ - if(cc->tdd_Config) { // TDD - AssertFatal(isrs>=10,"2 ms SRS periodicity not supported"); - - if ((isrs>9)&&(isrs<15)) { - *psrsPeriodicity=5; - *psrsOffset=isrs-10; - } - if ((isrs>14)&&(isrs<25)) { - *psrsPeriodicity=10; - *psrsOffset=isrs-15; - } - if ((isrs>24)&&(isrs<45)) { - *psrsPeriodicity=20; - *psrsOffset=isrs-25; - } - if ((isrs>44)&&(isrs<85)) { - *psrsPeriodicity=40; - *psrsOffset=isrs-45; - } - if ((isrs>84)&&(isrs<165)) { - *psrsPeriodicity=80; - *psrsOffset=isrs-85; - } - if ((isrs>164)&&(isrs<325)) { - *psrsPeriodicity=160; - *psrsOffset=isrs-165; - } - if ((isrs>324)&&(isrs<645)) { - *psrsPeriodicity=320; - *psrsOffset=isrs-325; - } - - AssertFatal(isrs<=644,"Isrs out of range %d>644\n",isrs); - } // TDD - else { // FDD - if (isrs<2) { - *psrsPeriodicity=2; - *psrsOffset=isrs; - } - if ((isrs>1)&&(isrs<7)) { - *psrsPeriodicity=5; - *psrsOffset=isrs-2; - } - if ((isrs>6)&&(isrs<17)) { - *psrsPeriodicity=10; - *psrsOffset=isrs-7; - } - if ((isrs>16)&&(isrs<37)) { - *psrsPeriodicity=20; - *psrsOffset=isrs-17; - } - if ((isrs>36)&&(isrs<77)) { - *psrsPeriodicity=40; - *psrsOffset=isrs-37; - } - if ((isrs>76)&&(isrs<157)) { - *psrsPeriodicity=80; - *psrsOffset=isrs-77; - } - if ((isrs>156)&&(isrs<317)) { - *psrsPeriodicity=160; - *psrsOffset=isrs-157; - } - if ((isrs>316)&&(isrs<637)) { - *psrsPeriodicity=320; - *psrsOffset=isrs-317; - } - AssertFatal(isrs<=636,"Isrs out of range %d>636\n",isrs); - } -} - -void get_csi_params(COMMON_channels_t *cc,struct CQI_ReportPeriodic *cqi_ReportPeriodic,uint16_t *Npd,uint16_t *N_OFFSET_CQI,int *H) -{ - uint16_t cqi_PMI_ConfigIndex = cqi_ReportPeriodic->choice.setup.cqi_pmi_ConfigIndex; - uint8_t Jtab[6] = {0,2,2,3,4,4}; - - AssertFatal(cqi_ReportPeriodic!=NULL,"cqi_ReportPeriodic is null!\n"); - - if (cc->tdd_Config==NULL) { //FDD - if (cqi_PMI_ConfigIndex <= 1) { // 2 ms CQI_PMI period - *Npd = 2; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex; - } else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period - *Npd = 5; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-2; - } else if (cqi_PMI_ConfigIndex <=16) { // 10ms CQI_PMI period - *Npd = 10; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-7; - } else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period - *Npd = 20; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-17; - } else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period - *Npd = 40; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-37; - } else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period - *Npd = 80; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-77; - } else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period - *Npd = 160; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-157; - } - else if (cqi_PMI_ConfigIndex > 317) { - - if (cqi_PMI_ConfigIndex <= 349) { // 32 ms CQI_PMI period - *Npd = 32; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-318; - } - else if (cqi_PMI_ConfigIndex <= 413) { // 64 ms CQI_PMI period - *Npd = 64; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-350; - } - else if (cqi_PMI_ConfigIndex <= 541) { // 128 ms CQI_PMI period - *Npd = 128; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-414; - } - } - } - else { // TDD - if (cqi_PMI_ConfigIndex == 0) { // all UL subframes - *Npd = 1; - *N_OFFSET_CQI = 0; - } else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period - *Npd = 5; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-1; - } else if (cqi_PMI_ConfigIndex <=16) { // 10ms CQI_PMI period - *Npd = 10; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-6; - } else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period - *Npd = 20; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-16; - } else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period - *Npd = 40; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-36; - } else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period - *Npd = 80; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-76; - } else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period - *Npd = 160; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex-156; - } - } - - // get H - if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) - *H = 1+(Jtab[cc->mib->message.dl_Bandwidth]*cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.choice.subbandCQI.k); - else - *H=1; -} - -uint8_t get_dl_cqi_pmi_size_pusch(COMMON_channels_t *cc,uint8_t tmode,uint8_t ri, CQI_ReportModeAperiodic_t *cqi_ReportModeAperiodic) -{ - int Ntab[6] = {0,4,7,9,10,13}; - int N = Ntab[cc->mib->message.dl_Bandwidth]; - int Ltab_uesel[6] = {0,6,9,13,15,18}; - int L = Ltab_uesel[cc->mib->message.dl_Bandwidth]; - - AssertFatal(cqi_ReportModeAperiodic != NULL,"cqi_ReportPeriodic is null!\n"); - - switch (*cqi_ReportModeAperiodic) { - case CQI_ReportModeAperiodic_rm12: - AssertFatal(tmode==4 || tmode==6 || tmode==8 || tmode==9 || tmode==10,"Illegal TM (%d) for CQI_ReportModeAperiodic_rm12\n",tmode); - AssertFatal(cc->p_eNB<=4,"only up to 4 antenna ports supported here\n"); - if (ri==1 && cc->p_eNB==2) return(4+(N<<1)); - else if (ri==2 && cc->p_eNB==2) return(8+N); - else if (ri==1 && cc->p_eNB==4) return(4+(N<<2)); - else if (ri>1 && cc->p_eNB==4) return(8+(N<<2)); - break; - case CQI_ReportModeAperiodic_rm20: - // Table 5.2.2.6.3-1 (36.212) - AssertFatal(tmode==1 || tmode==2 || tmode==3 || tmode==7 || tmode==9 || tmode==10,"Illegal TM (%d) for CQI_ReportModeAperiodic_rm20\n",tmode); - AssertFatal(tmode!=9 && tmode!=10,"TM9/10 will be handled later for CQI_ReportModeAperiodic_rm20\n"); - return(4+2+L); - break; - case CQI_ReportModeAperiodic_rm22: - // Table 5.2.2.6.3-2 (36.212) - AssertFatal(tmode==4 || tmode==6 || tmode==8 || tmode==9 || tmode==10,"Illegal TM (%d) for CQI_ReportModeAperiodic_rm22\n",tmode); - AssertFatal(tmode!=9 && tmode!=10,"TM9/10 will be handled later for CQI_ReportModeAperiodic_rm22\n"); - if (ri==1 && cc->p_eNB==2) return(4+2+0+0+L+4); - if (ri==2 && cc->p_eNB==2) return(4+2+4+2+L+2); - if (ri==1 && cc->p_eNB==4) return(4+2+0+0+L+8); - if (ri>=2 && cc->p_eNB==4) return(4+2+4+2+L+8); - break; - case CQI_ReportModeAperiodic_rm30: - // Table 5.2.2.6.2-1 (36.212) - AssertFatal(tmode==1 || tmode==2 || tmode==3 || tmode==7 || tmode==8 || tmode==9 || tmode==10,"Illegal TM (%d) for CQI_ReportModeAperiodic_rm30\n",tmode); - AssertFatal(tmode!=8 && tmode!=9 && tmode!=10,"TM8/9/10 will be handled later for CQI_ReportModeAperiodic_rm30\n"); - return(4+(N<<1)); - break; - case CQI_ReportModeAperiodic_rm31: - // Table 5.2.2.6.2-2 (36.212) - AssertFatal(tmode==4 || tmode==6 || tmode==8 || tmode==9 || tmode==10,"Illegal TM (%d) for CQI_ReportModeAperiodic_rm31\n",tmode); - AssertFatal(tmode!=8 && tmode!=9 && tmode!=10,"TM8/9/10 will be handled later for CQI_ReportModeAperiodic_rm31\n"); - if (ri==1 && cc->p_eNB==2) return(4+(N<<1)+0+0+2); - else if (ri==2 && cc->p_eNB==2) return(4+(N<<1)+4+(N<<1)+1); - else if (ri==1 && cc->p_eNB==4) return(4+(N<<1)+0+0+4); - else if (ri>=2 && cc->p_eNB==4) return(4+(N<<1)+4+(N<<1)+4); - break; - case CQI_ReportModeAperiodic_rm32_v1250: - AssertFatal(tmode==4 || tmode==6 || tmode==8 || tmode==9 || tmode==10,"Illegal TM (%d) for CQI_ReportModeAperiodic_rm32\n",tmode); - AssertFatal(1==0,"CQI_ReportModeAperiodic_rm32_v1250 not supported yet\n"); - break; - case CQI_ReportModeAperiodic_rm10_v1310: - // Table 5.2.2.6.1-1F/G (36.212) - if (ri==1) return(4); // F - else return(7); // G - break; - case CQI_ReportModeAperiodic_rm11_v1310: - // Table 5.2.2.6.1-1H (36.212) - AssertFatal(tmode==4 || tmode==6 || tmode==8 || tmode==9 || tmode==10,"Illegal TM (%d) for CQI_ReportModeAperiodic_rm11\n",tmode); - AssertFatal(cc->p_eNB<=4,"only up to 4 antenna ports supported here\n"); - if (ri==1 && cc->p_eNB==2) return(4+0+2); - else if (ri==2 && cc->p_eNB==2) return(4+4+1); - else if (ri==1 && cc->p_eNB==4) return(4+0+4); - else if (ri>1 && cc->p_eNB==4) return(4+4+4); - - break; - } - AssertFatal(1==0,"Shouldn't get here\n"); - return(0); -} - -uint8_t get_rel8_dl_cqi_pmi_size(UE_sched_ctrl *sched_ctl,int CC_idP,COMMON_channels_t *cc,uint8_t tmode, struct CQI_ReportPeriodic *cqi_ReportPeriodic) -{ - int no_pmi=0; - // Ltab[6] = {0,log2(15/4/2),log2(25/4/2),log2(50/6/3),log2(75/8/4),log2(100/8/4)}; - - uint8_t Ltab[6] = {0,1,2,2,2,2}; - uint8_t ri = sched_ctl->periodic_ri_received[CC_idP]; - - AssertFatal(cqi_ReportPeriodic != NULL,"cqi_ReportPeriodic is null!\n"); - AssertFatal(cqi_ReportPeriodic->present != CQI_ReportPeriodic_PR_NOTHING, - "cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n"); - AssertFatal(cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present != CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING, - "cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING!\n"); - - switch(tmode) { - case 1: - case 2: - case 5: - case 6: - case 7: - no_pmi=1; - break; - default: - no_pmi=0; - } - - if ((cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_widebandCQI) || - (sched_ctl->feedback_cnt[CC_idP] == 0)) { - // send wideband report every opportunity if wideband reporting mode is selected, else every H opportunities - if (no_pmi == 1) - return(4); - else if ((cc->p_eNB==2) && (ri==1)) return(6); - else if ((cc->p_eNB==2) && (ri==2)) return(8); - else if ((cc->p_eNB==4) && (ri==1)) return(8); - else if ((cc->p_eNB==4) && (ri==2)) return(11); - else AssertFatal(1==0,"illegal combination p %d, ri %d, no_pmi %d\n",cc->p_eNB,ri,no_pmi); - } - else if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) { - if ((no_pmi == 1)||ri==1) return(4+Ltab[cc->mib->message.dl_Bandwidth]); + if (mcs < 10) + return (2); + else if (mcs < 17) + return (4); else - return(7+Ltab[cc->mib->message.dl_Bandwidth]); - } - AssertFatal(1==0,"Shouldn't get here : cqi_ReportPeriodic->present %d\n",cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present); + return (6); } -void fill_nfapi_dl_dci_1A(nfapi_dl_config_request_pdu_t *dl_config_pdu, - uint8_t aggregation_level, - uint16_t rnti, - uint8_t rnti_type, - uint8_t harq_process, - uint8_t tpc, - uint16_t resource_block_coding, - uint8_t mcs, - uint8_t ndi, - uint8_t rv, - uint8_t vrb_flag) +void +get_Msg3alloc(COMMON_channels_t * cc, + sub_frame_t current_subframe, + frame_t current_frame, frame_t * frame, + sub_frame_t * subframe) { - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu)); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = aggregation_level; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = rnti_type; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = harq_process; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; // no TPC - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = resource_block_coding; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = ndi; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = rv; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = vrb_flag; + // Fill in other TDD Configuration!!!! + + if (cc->tdd_Config == NULL) { // FDD + *subframe = current_subframe + 6; + + if (*subframe > 9) { + *subframe = *subframe - 10; + *frame = (current_frame + 1) & 1023; + } else { + *frame = current_frame; + } + } else { // TDD + if (cc->tdd_Config->subframeAssignment == 1) { + switch (current_subframe) { + + case 0: + *subframe = 7; + *frame = current_frame; + break; + + case 4: + *subframe = 2; + *frame = (current_frame + 1) & 1023; + break; + + case 5: + *subframe = 2; + *frame = (current_frame + 1) & 1023; + break; + + case 9: + *subframe = 7; + *frame = (current_frame + 1) & 1023; + break; + } + } else if (cc->tdd_Config->subframeAssignment == 3) { + switch (current_subframe) { + + case 0: + case 5: + case 6: + *subframe = 2; + *frame = (current_frame + 1) & 1023; + break; + + case 7: + *subframe = 3; + *frame = (current_frame + 1) & 1023; + break; + + case 8: + *subframe = 4; + *frame = (current_frame + 1) & 1023; + break; + + case 9: + *subframe = 2; + *frame = (current_frame + 2) & 1023; + break; + } + } else if (cc->tdd_Config->subframeAssignment == 4) { + switch (current_subframe) { + + case 0: + case 4: + case 5: + case 6: + *subframe = 2; + *frame = (current_frame + 1) & 1023; + break; + + case 7: + *subframe = 3; + *frame = (current_frame + 1) & 1023; + break; + + case 8: + case 9: + *subframe = 2; + *frame = (current_frame + 2) & 1023; + break; + } + } else if (cc->tdd_Config->subframeAssignment == 5) { + switch (current_subframe) { + + case 0: + case 4: + case 5: + case 6: + *subframe = 2; + *frame = (current_frame + 1) & 1023; + break; + + case 7: + case 8: + case 9: + *subframe = 2; + *frame = (current_frame + 2) & 1023; + break; + } + } + } } -void program_dlsch_acknak(module_id_t module_idP, int CC_idP,int UE_idP, frame_t frameP, sub_frame_t subframeP,uint8_t cce_idx) -{ - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = eNB->common_channels; - UE_list_t *UE_list = &eNB->UE_list; - rnti_t rnti = UE_RNTI(module_idP,UE_idP); - nfapi_ul_config_request_body_t *ul_req; - nfapi_ul_config_request_pdu_t *ul_config_pdu; - int use_simultaneous_pucch_pusch=0; - nfapi_ul_config_ulsch_harq_information *ulsch_harq_information = NULL; - nfapi_ul_config_harq_information *harq_information = NULL; + +void +get_Msg3allocret(COMMON_channels_t * cc, + sub_frame_t current_subframe, + frame_t current_frame, + frame_t * frame, sub_frame_t * subframe) +{ + if (cc->tdd_Config == NULL) { //FDD + /* always retransmit in n+8 */ + *subframe = current_subframe + 8; + + if (*subframe > 9) { + *subframe = *subframe - 10; + *frame = (current_frame + 1) & 1023; + } else { + *frame = current_frame; + } + } else { + if (cc->tdd_Config->subframeAssignment == 1) { + // original PUSCH in 2, PHICH in 6 (S), ret in 2 + // original PUSCH in 3, PHICH in 9, ret in 3 + // original PUSCH in 7, PHICH in 1 (S), ret in 7 + // original PUSCH in 8, PHICH in 4, ret in 8 + *frame = (current_frame + 1) & 1023; + } else if (cc->tdd_Config->subframeAssignment == 3) { + // original PUSCH in 2, PHICH in 8, ret in 2 next frame + // original PUSCH in 3, PHICH in 9, ret in 3 next frame + // original PUSCH in 4, PHICH in 0, ret in 4 next frame + *frame = (current_frame + 1) & 1023; + } else if (cc->tdd_Config->subframeAssignment == 4) { + // original PUSCH in 2, PHICH in 8, ret in 2 next frame + // original PUSCH in 3, PHICH in 9, ret in 3 next frame + *frame = (current_frame + 1) & 1023; + } else if (cc->tdd_Config->subframeAssignment == 5) { + // original PUSCH in 2, PHICH in 8, ret in 2 next frame + *frame = (current_frame + 1) & 1023; + } + } +} + +uint8_t +subframe2harqpid(COMMON_channels_t * cc, frame_t frame, + sub_frame_t subframe) +{ + uint8_t ret = 255; + + AssertFatal(cc != NULL, "cc is null\n"); + + if (cc->tdd_Config == NULL) { // FDD + ret = (((frame << 1) + subframe) & 7); + } else { + switch (cc->tdd_Config->subframeAssignment) { + case 1: + if ((subframe == 2) || + (subframe == 3) || (subframe == 7) || (subframe == 8)) + switch (subframe) { + case 2: + case 3: + ret = (subframe - 2); + break; + + case 7: + case 8: + ret = (subframe - 5); + break; + + default: + AssertFatal(1 == 0, + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframe, + (int) cc->tdd_Config->subframeAssignment); + break; + } + + break; + + case 2: + AssertFatal((subframe == 2) || (subframe == 7), + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframe, + (int) cc->tdd_Config->subframeAssignment); + + ret = (subframe / 7); + break; + + case 3: + AssertFatal((subframe > 1) && (subframe < 5), + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframe, + (int) cc->tdd_Config->subframeAssignment); + ret = (subframe - 2); + break; + + case 4: + AssertFatal((subframe > 1) && (subframe < 4), + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframe, + (int) cc->tdd_Config->subframeAssignment); + ret = (subframe - 2); + break; + + case 5: + AssertFatal(subframe == 2, + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframe, + (int) cc->tdd_Config->subframeAssignment); + ret = (subframe - 2); + break; + + default: + AssertFatal(1 == 0, + "subframe2_harq_pid, Unsupported TDD mode %d\n", + (int) cc->tdd_Config->subframeAssignment); + } + } + return ret; +} + +uint8_t +get_Msg3harqpid(COMMON_channels_t * cc, + frame_t frame, sub_frame_t current_subframe) +{ + uint8_t ul_subframe = 0; + uint32_t ul_frame = 0; + + if (cc->tdd_Config == NULL) { // FDD + ul_subframe = + (current_subframe > + 3) ? (current_subframe - 4) : (current_subframe + 6); + ul_frame = (current_subframe > 3) ? ((frame + 1) & 1023) : frame; + } else { + switch (cc->tdd_Config->subframeAssignment) { + case 1: + switch (current_subframe) { + case 9: + case 0: + ul_subframe = 7; + break; + + case 5: + case 7: + ul_subframe = 2; + break; + + } + + break; + + case 3: + switch (current_subframe) { + case 0: + case 5: + case 6: + ul_subframe = 2; + break; + + case 7: + ul_subframe = 3; + break; + + case 8: + ul_subframe = 4; + break; + + case 9: + ul_subframe = 2; + break; + } + + break; + + case 4: + switch (current_subframe) { + case 0: + case 5: + case 6: + case 8: + case 9: + ul_subframe = 2; + break; + + case 7: + ul_subframe = 3; + break; + } + + break; + + case 5: + ul_subframe = 2; + break; + + default: + LOG_E(PHY, + "get_Msg3_harq_pid: Unsupported TDD configuration %d\n", + (int) cc->tdd_Config->subframeAssignment); + AssertFatal(1 == 0, + "get_Msg3_harq_pid: Unsupported TDD configuration"); + break; + } + } + + return (subframe2harqpid(cc, ul_frame, ul_subframe)); +} + +uint32_t +pdcchalloc2ulframe(COMMON_channels_t * ccP, uint32_t frame, uint8_t n) +{ + uint32_t ul_frame; + + if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 1) && ((n == 1) || (n == 6))) // tdd_config 0,1 SF 1,5 + ul_frame = (frame + (n == 1 ? 0 : 1)); + else if ((ccP->tdd_Config) && + (ccP->tdd_Config->subframeAssignment == 6) && + ((n == 0) || (n == 1) || (n == 5) || (n == 6))) + ul_frame = (frame + (n >= 5 ? 1 : 0)); + else if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 6) && (n == 9)) // tdd_config 6 SF 9 + ul_frame = (frame + 1); + else + ul_frame = (frame + (n >= 6 ? 1 : 0)); + + LOG_D(PHY, "frame %d subframe %d: PUSCH frame = %d\n", frame, n, + ul_frame); + return ul_frame; +} + +uint8_t pdcchalloc2ulsubframe(COMMON_channels_t * ccP, uint8_t n) +{ + uint8_t ul_subframe; + + if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 1) && ((n == 1) || (n == 6))) // tdd_config 0,1 SF 1,5 + ul_subframe = ((n + 6) % 10); + else if ((ccP->tdd_Config) && + (ccP->tdd_Config->subframeAssignment == 6) && + ((n == 0) || (n == 1) || (n == 5) || (n == 6))) + ul_subframe = ((n + 7) % 10); + else if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 6) && (n == 9)) // tdd_config 6 SF 9 + ul_subframe = ((n + 5) % 10); + else + ul_subframe = ((n + 4) % 10); + + LOG_D(PHY, "subframe %d: PUSCH subframe = %d\n", n, ul_subframe); + return ul_subframe; +} + +int is_UL_sf(COMMON_channels_t * ccP, sub_frame_t subframeP) +{ + // if FDD return dummy value + if (ccP->tdd_Config == NULL) + return (0); + + switch (ccP->tdd_Config->subframeAssignment) { + case 1: + switch (subframeP) { + case 0: + case 4: + case 5: + case 9: + return (0); + break; + + case 2: + case 3: + case 7: + case 8: + return (1); + break; + + default: + return (0); + break; + } + break; + + case 3: + if ((subframeP <= 1) || (subframeP >= 5)) + return (0); + else if ((subframeP > 1) && (subframeP < 5)) + return (1); + else + AssertFatal(1 == 0, "Unknown subframe number\n"); + break; + + case 4: + if ((subframeP <= 1) || (subframeP >= 4)) + return (0); + else if ((subframeP > 1) && (subframeP < 4)) + return (1); + else + AssertFatal(1 == 0, "Unknown subframe number\n"); + break; + + case 5: + if ((subframeP <= 1) || (subframeP >= 3)) + return (0); + else if ((subframeP > 1) && (subframeP < 3)) + return (1); + else + AssertFatal(1 == 0, "Unknown subframe number\n"); + break; + + default: + AssertFatal(1 == 0, + "subframe %d Unsupported TDD configuration %d\n", + subframeP, (int) ccP->tdd_Config->subframeAssignment); + break; + } +} + +uint16_t get_pucch1_absSF(COMMON_channels_t * cc, uint16_t dlsch_absSF) +{ + uint16_t sf, f, nextf; + + if (cc->tdd_Config == NULL) { //FDD n+4 + return ((dlsch_absSF + 4) % 10240); + } else { + sf = dlsch_absSF % 10; + f = dlsch_absSF / 10; + nextf = (f + 1) & 1023; + + switch (cc->tdd_Config->subframeAssignment) { + case 0: + AssertFatal(1 == 0, "SFA 0 to be filled in now, :-)\n"); + break; + case 1: + if ((sf == 5) || (sf == 6)) + return ((10 * nextf) + 2); // ACK/NAK in SF 2 next frame + else if (sf == 9) + return ((10 * nextf) + 3); // ACK/NAK in SF 3 next frame + else if ((sf == 0) || (sf == 1)) + return ((10 * f) + 2); // ACK/NAK in SF 7 same frame + else + AssertFatal(1 == 0, + "Impossible dlsch subframe %d for TDD configuration 3\n", + sf); + break; + case 2: + if ((sf == 4) || (sf == 5) || (sf == 6) || (sf == 8)) + return ((10 * nextf) + 2); // ACK/NAK in SF 2 next frame + else if (sf == 9) + return ((10 * nextf) + 7); // ACK/NAK in SF 7 next frame + else if ((sf == 0) || (sf == 1) || (sf == 3)) + return ((10 * f) + 7); // ACK/NAK in SF 7 same frame + else + AssertFatal(1 == 0, + "Impossible dlsch subframe %d for TDD configuration 3\n", + sf); + break; + case 3: + if ((sf == 5) || (sf == 6) || (sf == 7) || (sf == 8) + || (sf == 9)) + return ((10 * nextf) + (sf >> 1)); // ACK/NAK in 2,3,4 resp. next frame + else if (sf == 1) + return ((10 * nextf) + 2); // ACK/NAK in 2 next frame + else if (sf == 0) + return ((10 * f) + 4); // ACK/NAK in 4 same frame + else + AssertFatal(1 == 0, + "Impossible dlsch subframe %d for TDD configuration 3\n", + sf); + break; + case 4: + if ((sf == 6) || (sf == 7) || (sf == 8) || (sf == 9)) + return (((10 * nextf) + 3) % 10240); // ACK/NAK in SF 3 next frame + else if ((sf == 0) || (sf == 1) || (sf == 4) || (sf == 5)) + return (((10 * nextf) + 2) % 10240); // ACK/NAK in SF 2 next frame + else + AssertFatal(1 == 0, + "Impossible dlsch subframe %d for TDD configuration 4\n", + sf); + break; + case 5: + if ((sf == 0) || (sf == 1) || (sf == 3) || (sf == 4) + || (sf == 5) || (sf == 6) || (sf == 7) || (sf == 8)) + return (((10 * nextf) + 2) % 10240); // ACK/NAK in SF 3 next frame + else if (sf == 9) + return (((10 * (1 + nextf)) + 2) % 10240); // ACK/NAK in SF 2 next frame + else + AssertFatal(1 == 0, + "Impossible dlsch subframe %d for TDD configuration 5\n", + sf); + break; + case 6: + AssertFatal(1 == 0, "SFA 6 To be filled in now, :-)\n"); + break; + default: + AssertFatal(1 == 0, "Illegal TDD subframe Assigment %d\n", + (int) cc->tdd_Config->subframeAssignment); + break; + } + } + AssertFatal(1 == 0, "Shouldn't get here\n"); +} + +void +get_srs_pos(COMMON_channels_t * cc, uint16_t isrs, + uint16_t * psrsPeriodicity, uint16_t * psrsOffset) +{ + if (cc->tdd_Config) { // TDD + AssertFatal(isrs >= 10, "2 ms SRS periodicity not supported"); + + if ((isrs > 9) && (isrs < 15)) { + *psrsPeriodicity = 5; + *psrsOffset = isrs - 10; + } + if ((isrs > 14) && (isrs < 25)) { + *psrsPeriodicity = 10; + *psrsOffset = isrs - 15; + } + if ((isrs > 24) && (isrs < 45)) { + *psrsPeriodicity = 20; + *psrsOffset = isrs - 25; + } + if ((isrs > 44) && (isrs < 85)) { + *psrsPeriodicity = 40; + *psrsOffset = isrs - 45; + } + if ((isrs > 84) && (isrs < 165)) { + *psrsPeriodicity = 80; + *psrsOffset = isrs - 85; + } + if ((isrs > 164) && (isrs < 325)) { + *psrsPeriodicity = 160; + *psrsOffset = isrs - 165; + } + if ((isrs > 324) && (isrs < 645)) { + *psrsPeriodicity = 320; + *psrsOffset = isrs - 325; + } + + AssertFatal(isrs <= 644, "Isrs out of range %d>644\n", isrs); + } // TDD + else { // FDD + if (isrs < 2) { + *psrsPeriodicity = 2; + *psrsOffset = isrs; + } + if ((isrs > 1) && (isrs < 7)) { + *psrsPeriodicity = 5; + *psrsOffset = isrs - 2; + } + if ((isrs > 6) && (isrs < 17)) { + *psrsPeriodicity = 10; + *psrsOffset = isrs - 7; + } + if ((isrs > 16) && (isrs < 37)) { + *psrsPeriodicity = 20; + *psrsOffset = isrs - 17; + } + if ((isrs > 36) && (isrs < 77)) { + *psrsPeriodicity = 40; + *psrsOffset = isrs - 37; + } + if ((isrs > 76) && (isrs < 157)) { + *psrsPeriodicity = 80; + *psrsOffset = isrs - 77; + } + if ((isrs > 156) && (isrs < 317)) { + *psrsPeriodicity = 160; + *psrsOffset = isrs - 157; + } + if ((isrs > 316) && (isrs < 637)) { + *psrsPeriodicity = 320; + *psrsOffset = isrs - 317; + } + AssertFatal(isrs <= 636, "Isrs out of range %d>636\n", isrs); + } +} + +void +get_csi_params(COMMON_channels_t * cc, + struct CQI_ReportPeriodic *cqi_ReportPeriodic, + uint16_t * Npd, uint16_t * N_OFFSET_CQI, int *H) +{ + uint16_t cqi_PMI_ConfigIndex = + cqi_ReportPeriodic->choice.setup.cqi_pmi_ConfigIndex; + uint8_t Jtab[6] = { 0, 2, 2, 3, 4, 4 }; + + AssertFatal(cqi_ReportPeriodic != NULL, + "cqi_ReportPeriodic is null!\n"); + + if (cc->tdd_Config == NULL) { //FDD + if (cqi_PMI_ConfigIndex <= 1) { // 2 ms CQI_PMI period + *Npd = 2; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex; + } else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period + *Npd = 5; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 2; + } else if (cqi_PMI_ConfigIndex <= 16) { // 10ms CQI_PMI period + *Npd = 10; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 7; + } else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period + *Npd = 20; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 17; + } else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period + *Npd = 40; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 37; + } else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period + *Npd = 80; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 77; + } else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period + *Npd = 160; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 157; + } else if (cqi_PMI_ConfigIndex > 317) { + + if (cqi_PMI_ConfigIndex <= 349) { // 32 ms CQI_PMI period + *Npd = 32; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 318; + } else if (cqi_PMI_ConfigIndex <= 413) { // 64 ms CQI_PMI period + *Npd = 64; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 350; + } else if (cqi_PMI_ConfigIndex <= 541) { // 128 ms CQI_PMI period + *Npd = 128; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 414; + } + } + } else { // TDD + if (cqi_PMI_ConfigIndex == 0) { // all UL subframes + *Npd = 1; + *N_OFFSET_CQI = 0; + } else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period + *Npd = 5; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 1; + } else if (cqi_PMI_ConfigIndex <= 16) { // 10ms CQI_PMI period + *Npd = 10; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 6; + } else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period + *Npd = 20; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 16; + } else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period + *Npd = 40; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 36; + } else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period + *Npd = 80; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 76; + } else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period + *Npd = 160; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 156; + } + } + + // get H + if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic. + present == + CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) + *H = 1 + + (Jtab[cc->mib->message.dl_Bandwidth] * + cqi_ReportPeriodic->choice.setup. + cqi_FormatIndicatorPeriodic.choice.subbandCQI.k); + else + *H = 1; +} + +uint8_t +get_dl_cqi_pmi_size_pusch(COMMON_channels_t * cc, uint8_t tmode, + uint8_t ri, + CQI_ReportModeAperiodic_t * + cqi_ReportModeAperiodic) +{ + int Ntab[6] = { 0, 4, 7, 9, 10, 13 }; + int N = Ntab[cc->mib->message.dl_Bandwidth]; + int Ltab_uesel[6] = { 0, 6, 9, 13, 15, 18 }; + int L = Ltab_uesel[cc->mib->message.dl_Bandwidth]; + + AssertFatal(cqi_ReportModeAperiodic != NULL, + "cqi_ReportPeriodic is null!\n"); + + switch (*cqi_ReportModeAperiodic) { + case CQI_ReportModeAperiodic_rm12: + AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal TM (%d) for CQI_ReportModeAperiodic_rm12\n", + tmode); + AssertFatal(cc->p_eNB <= 4, + "only up to 4 antenna ports supported here\n"); + if (ri == 1 && cc->p_eNB == 2) + return (4 + (N << 1)); + else if (ri == 2 && cc->p_eNB == 2) + return (8 + N); + else if (ri == 1 && cc->p_eNB == 4) + return (4 + (N << 2)); + else if (ri > 1 && cc->p_eNB == 4) + return (8 + (N << 2)); + break; + case CQI_ReportModeAperiodic_rm20: + // Table 5.2.2.6.3-1 (36.212) + AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 || tmode == 7 + || tmode == 9 + || tmode == 10, + "Illegal TM (%d) for CQI_ReportModeAperiodic_rm20\n", + tmode); + AssertFatal(tmode != 9 + && tmode != 10, + "TM9/10 will be handled later for CQI_ReportModeAperiodic_rm20\n"); + return (4 + 2 + L); + break; + case CQI_ReportModeAperiodic_rm22: + // Table 5.2.2.6.3-2 (36.212) + AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal TM (%d) for CQI_ReportModeAperiodic_rm22\n", + tmode); + AssertFatal(tmode != 9 + && tmode != 10, + "TM9/10 will be handled later for CQI_ReportModeAperiodic_rm22\n"); + if (ri == 1 && cc->p_eNB == 2) + return (4 + 2 + 0 + 0 + L + 4); + if (ri == 2 && cc->p_eNB == 2) + return (4 + 2 + 4 + 2 + L + 2); + if (ri == 1 && cc->p_eNB == 4) + return (4 + 2 + 0 + 0 + L + 8); + if (ri >= 2 && cc->p_eNB == 4) + return (4 + 2 + 4 + 2 + L + 8); + break; + case CQI_ReportModeAperiodic_rm30: + // Table 5.2.2.6.2-1 (36.212) + AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 || tmode == 7 + || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal TM (%d) for CQI_ReportModeAperiodic_rm30\n", + tmode); + AssertFatal(tmode != 8 && tmode != 9 + && tmode != 10, + "TM8/9/10 will be handled later for CQI_ReportModeAperiodic_rm30\n"); + return (4 + (N << 1)); + break; + case CQI_ReportModeAperiodic_rm31: + // Table 5.2.2.6.2-2 (36.212) + AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal TM (%d) for CQI_ReportModeAperiodic_rm31\n", + tmode); + AssertFatal(tmode != 8 && tmode != 9 + && tmode != 10, + "TM8/9/10 will be handled later for CQI_ReportModeAperiodic_rm31\n"); + if (ri == 1 && cc->p_eNB == 2) + return (4 + (N << 1) + 0 + 0 + 2); + else if (ri == 2 && cc->p_eNB == 2) + return (4 + (N << 1) + 4 + (N << 1) + 1); + else if (ri == 1 && cc->p_eNB == 4) + return (4 + (N << 1) + 0 + 0 + 4); + else if (ri >= 2 && cc->p_eNB == 4) + return (4 + (N << 1) + 4 + (N << 1) + 4); + break; + case CQI_ReportModeAperiodic_rm32_v1250: + AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal TM (%d) for CQI_ReportModeAperiodic_rm32\n", + tmode); + AssertFatal(1 == 0, + "CQI_ReportModeAperiodic_rm32_v1250 not supported yet\n"); + break; + case CQI_ReportModeAperiodic_rm10_v1310: + // Table 5.2.2.6.1-1F/G (36.212) + if (ri == 1) + return (4); // F + else + return (7); // G + break; + case CQI_ReportModeAperiodic_rm11_v1310: + // Table 5.2.2.6.1-1H (36.212) + AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal TM (%d) for CQI_ReportModeAperiodic_rm11\n", + tmode); + AssertFatal(cc->p_eNB <= 4, + "only up to 4 antenna ports supported here\n"); + if (ri == 1 && cc->p_eNB == 2) + return (4 + 0 + 2); + else if (ri == 2 && cc->p_eNB == 2) + return (4 + 4 + 1); + else if (ri == 1 && cc->p_eNB == 4) + return (4 + 0 + 4); + else if (ri > 1 && cc->p_eNB == 4) + return (4 + 4 + 4); + + break; + } + AssertFatal(1 == 0, "Shouldn't get here\n"); + return (0); +} + +uint8_t +get_rel8_dl_cqi_pmi_size(UE_sched_ctrl * sched_ctl, int CC_idP, + COMMON_channels_t * cc, uint8_t tmode, + struct CQI_ReportPeriodic * cqi_ReportPeriodic) +{ + int no_pmi = 0; + // Ltab[6] = {0,log2(15/4/2),log2(25/4/2),log2(50/6/3),log2(75/8/4),log2(100/8/4)}; + + uint8_t Ltab[6] = { 0, 1, 2, 2, 2, 2 }; + uint8_t ri = sched_ctl->periodic_ri_received[CC_idP]; + + AssertFatal(cqi_ReportPeriodic != NULL, + "cqi_ReportPeriodic is null!\n"); + AssertFatal(cqi_ReportPeriodic->present != + CQI_ReportPeriodic_PR_NOTHING, + "cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n"); + AssertFatal(cqi_ReportPeriodic->choice. + setup.cqi_FormatIndicatorPeriodic.present != + CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING, + "cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING!\n"); + + switch (tmode) { + case 1: + case 2: + case 5: + case 6: + case 7: + no_pmi = 1; + break; + default: + no_pmi = 0; + } + + if ((cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic. + present == + CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_widebandCQI) + || (sched_ctl->feedback_cnt[CC_idP] == 0)) { + // send wideband report every opportunity if wideband reporting mode is selected, else every H opportunities + if (no_pmi == 1) + return (4); + else if ((cc->p_eNB == 2) && (ri == 1)) + return (6); + else if ((cc->p_eNB == 2) && (ri == 2)) + return (8); + else if ((cc->p_eNB == 4) && (ri == 1)) + return (8); + else if ((cc->p_eNB == 4) && (ri == 2)) + return (11); + else + AssertFatal(1 == 0, + "illegal combination p %d, ri %d, no_pmi %d\n", + cc->p_eNB, ri, no_pmi); + } else if (cqi_ReportPeriodic->choice. + setup.cqi_FormatIndicatorPeriodic.present == + CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) + { + if ((no_pmi == 1) || ri == 1) + return (4 + Ltab[cc->mib->message.dl_Bandwidth]); + else + return (7 + Ltab[cc->mib->message.dl_Bandwidth]); + } + AssertFatal(1 == 0, + "Shouldn't get here : cqi_ReportPeriodic->present %d\n", + cqi_ReportPeriodic->choice. + setup.cqi_FormatIndicatorPeriodic.present); +} + +void +fill_nfapi_dl_dci_1A(nfapi_dl_config_request_pdu_t * dl_config_pdu, + uint8_t aggregation_level, + uint16_t rnti, + uint8_t rnti_type, + uint8_t harq_process, + uint8_t tpc, + uint16_t resource_block_coding, + uint8_t mcs, uint8_t ndi, uint8_t rv, + uint8_t vrb_flag) +{ + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = + NFAPI_DL_DCI_FORMAT_1A; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = + aggregation_level; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = rnti_type; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = harq_process; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; // no TPC + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = + resource_block_coding; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = ndi; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = rv; + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = vrb_flag; +} + +void +program_dlsch_acknak(module_id_t module_idP, int CC_idP, int UE_idP, + frame_t frameP, sub_frame_t subframeP, + uint8_t cce_idx) +{ + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc = eNB->common_channels; + UE_list_t *UE_list = &eNB->UE_list; + rnti_t rnti = UE_RNTI(module_idP, UE_idP); + nfapi_ul_config_request_body_t *ul_req; + nfapi_ul_config_request_pdu_t *ul_config_pdu; + + int use_simultaneous_pucch_pusch = 0; + nfapi_ul_config_ulsch_harq_information *ulsch_harq_information = NULL; + nfapi_ul_config_harq_information *harq_information = NULL; #if defined(Rel10) || defined(Rel14) - if ((UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2) && - (UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020) && - (UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020->simultaneousPUCCH_PUSCH_r10) && - (*UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020->simultaneousPUCCH_PUSCH_r10 == - PUCCH_ConfigDedicated_v1020__simultaneousPUCCH_PUSCH_r10_true)) - use_simultaneous_pucch_pusch=1; + if ((UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated-> + ext2) + && (UE_list->UE_template[CC_idP][UE_idP]. + physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020) + && (UE_list->UE_template[CC_idP][UE_idP]. + physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020-> + simultaneousPUCCH_PUSCH_r10) + && (*UE_list->UE_template[CC_idP][UE_idP]. + physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020-> + simultaneousPUCCH_PUSCH_r10 == + PUCCH_ConfigDedicated_v1020__simultaneousPUCCH_PUSCH_r10_true)) + use_simultaneous_pucch_pusch = 1; #endif - // pucch1 and pusch feedback is similar, namely in n+k subframes from now - // This is used in the following "if/else" condition to check if there isn't or is already an UL grant in n+k - int16_t ul_absSF = get_pucch1_absSF(&cc[CC_idP],subframeP+(10*frameP)); + // pucch1 and pusch feedback is similar, namely in n+k subframes from now + // This is used in the following "if/else" condition to check if there isn't or is already an UL grant in n+k + int16_t ul_absSF = + get_pucch1_absSF(&cc[CC_idP], subframeP + (10 * frameP)); - if ((ul_config_pdu = has_ul_grant(module_idP,CC_idP, - ul_absSF, - rnti)) == NULL) { - // no UL grant so - // Program ACK/NAK alone Format 1a/b or 3 + if ((ul_config_pdu = has_ul_grant(module_idP, CC_idP, + ul_absSF, rnti)) == NULL) { + // no UL grant so + // Program ACK/NAK alone Format 1a/b or 3 - ul_req = &RC.mac[module_idP]->UL_req_tmp[CC_idP][ul_absSF%10].ul_config_request_body; - ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; - // Do PUCCH - fill_nfapi_uci_acknak(module_idP, - CC_idP, - rnti, - (frameP*10)+subframeP, - cce_idx); - } - else { - /* there is already an existing UL grant so update it if needed - * on top of some other UL resource (PUSCH,combined SR/CQI/HARQ on PUCCH, etc) - */ - switch(ul_config_pdu->pdu_type) { - - /* [ulsch] to [ulsch + harq] or [ulsch + harq on pucch] */ - - case NFAPI_UL_CONFIG_ULSCH_PDU_TYPE: - if (use_simultaneous_pucch_pusch==1) { - // Convert it to an NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE - harq_information = &ul_config_pdu->ulsch_uci_harq_pdu.harq_information; - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE; - LOG_D(MAC,"Frame %d, Subframe %d: Switched UCI HARQ to ULSCH UCI HARQ\n",frameP,subframeP); - } - else { - // Convert it to an NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE - ulsch_harq_information = &ul_config_pdu->ulsch_harq_pdu.harq_information; - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE; - ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial=0; // last symbol not punctured - ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks= - ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks; // we don't change the number of resource blocks across retransmissions yet - LOG_D(MAC,"Frame %d, Subframe %d: Switched UCI HARQ to ULSCH HARQ\n",frameP,subframeP); - } - break; - case NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE: - AssertFatal(use_simultaneous_pucch_pusch == 1, - "Cannot be NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE, simultaneous_pucch_pusch is active"); - break; - case NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE: - AssertFatal(use_simultaneous_pucch_pusch == 0, - "Cannot be NFAPI_UL_CONFIG_ULSCH_UCI_PDU_TYPE, simultaneous_pucch_pusch is inactive\n"); - break; - - /* [ulsch + cqi] to [ulsch + cqi + harq] */ - - case NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE: - // Convert it to an NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE - ulsch_harq_information = &ul_config_pdu->ulsch_cqi_harq_ri_pdu.harq_information; - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE; - /* TODO: check this - when converting from nfapi_ul_config_ulsch_cqi_ri_pdu to - * nfapi_ul_config_ulsch_cqi_harq_ri_pdu, shouldn't we copy initial_transmission_parameters - * from the one to the other? - * Those two types are not compatible. 'initial_transmission_parameters' is not at the - * place in both. - */ - ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial=0; // last symbol not punctured - ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks= - ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks; // we don't change the number of resource blocks across retransmissions yet - break; - case NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE: - AssertFatal(use_simultaneous_pucch_pusch == 0, - "Cannot be NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE, simultaneous_pucch_pusch is active\n"); - break; - - /* [ulsch + cqi on pucch] to [ulsch + cqi on pucch + harq on pucch] */ - - case NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE: - // convert it to an NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE - harq_information = &ul_config_pdu->ulsch_csi_uci_harq_pdu.harq_information; - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE; - break; - case NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE: - AssertFatal(use_simultaneous_pucch_pusch == 1, - "Cannot be NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE, simultaneous_pucch_pusch is inactive\n"); - break; - - /* [sr] to [sr + harq] */ - - case NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE: - // convert to NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; - harq_information = &ul_config_pdu->uci_sr_harq_pdu.harq_information; - break; - case NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE: - /* nothing to do */ - break; - - /* [cqi] to [cqi + harq] */ - - case NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE: - // convert to NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE; - harq_information = &ul_config_pdu->uci_cqi_harq_pdu.harq_information; - break; - case NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE: - /* nothing to do */ - break; - - /* [cqi + sr] to [cqr + sr + harq] */ - - case NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE: - // convert to NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE; - harq_information = &ul_config_pdu->uci_cqi_sr_harq_pdu.harq_information; - break; - case NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE: - /* nothing to do */ - break; - } - } - - if (ulsch_harq_information) fill_nfapi_ulsch_harq_information(module_idP,CC_idP, - rnti, - ulsch_harq_information); - - if (harq_information) fill_nfapi_harq_information(module_idP,CC_idP, - rnti, - (frameP*10)+subframeP, - harq_information, - cce_idx); -} - -uint8_t get_V_UL_DAI(module_id_t module_idP,int CC_idP,uint16_t rntiP) -{ - nfapi_hi_dci0_request_body_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[0]; - - for (int i=0;inumber_of_dci;i++) { - if ((hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE)&& - (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti == rntiP)) - return(hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.dl_assignment_index); - } - return(4); // this is rule from Section 7.3 in 36.213 -} - -void fill_nfapi_ulsch_harq_information(module_id_t module_idP, - int CC_idP, - uint16_t rntiP, - nfapi_ul_config_ulsch_harq_information *harq_information) -{ - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; - UE_list_t *UE_list = &eNB->UE_list; - - int UE_id = find_UE_id(module_idP,rntiP); - - PUSCH_ConfigDedicated_t *puschConfigDedicated; - // PUSCH_ConfigDedicated_v1020_t *puschConfigDedicated_v1020; - // PUSCH_ConfigDedicated_v1130_t *puschConfigDedicated_v1130; - // PUSCH_ConfigDedicated_v1250_t *puschConfigDedicated_v1250; - - AssertFatal(UE_id>=0,"UE_id cannot be found, impossible\n"); - AssertFatal(UE_list!=NULL,"UE_list is null\n"); - AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated!=NULL,"physicalConfigDedicated for rnti %x is null\n",rntiP); - AssertFatal((puschConfigDedicated = (PUSCH_ConfigDedicated_t *)UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pusch_ConfigDedicated)!=NULL,"physicalConfigDedicated->puschConfigDedicated for rnti %x is null\n",rntiP); -#if defined(Rel14) || defined(Rel14) - /* if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext2) puschConfigDedicated_v1020 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext2->pusch_ConfigDedicated_v1020; -#endif -#ifdef Rel14 - if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext4) puschConfigDedicated_v1130 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext4->pusch_ConfigDedicated_v1130; - if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext5) puschConfigDedicated_v1250 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext5->pusch_ConfigDedicated_v1250; - */ -#endif - harq_information->harq_information_rel10.delta_offset_harq = puschConfigDedicated->betaOffset_ACK_Index; - AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated!=NULL,"pucch_ConfigDedicated is null!\n"); - if ((UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode!=NULL)&& - (*UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode==PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) - harq_information->harq_information_rel10.ack_nack_mode = 1; // multiplexing - else - harq_information->harq_information_rel10.ack_nack_mode = 0; // bundling - - switch(get_tmode(module_idP,CC_idP,UE_id)) { - case 1: - case 2: - case 5: - case 6: - case 7: - if (cc->tdd_Config==NULL) // FDD - harq_information->harq_information_rel10.harq_size = 1; - else { - if (harq_information->harq_information_rel10.ack_nack_mode == 1) - harq_information->harq_information_rel10.harq_size = get_V_UL_DAI(module_idP,CC_idP,rntiP); - else - harq_information->harq_information_rel10.harq_size = 1; - } - break; - default: // for any other TM we need 2 bits harq - if (cc->tdd_Config==NULL) { - harq_information->harq_information_rel10.harq_size = 2; - } - else { - if (harq_information->harq_information_rel10.ack_nack_mode == 1) - harq_information->harq_information_rel10.harq_size = get_V_UL_DAI(module_idP,CC_idP,rntiP); - else - harq_information->harq_information_rel10.harq_size = 2; - } - break; - } // get Tmode -} - -void fill_nfapi_harq_information(module_id_t module_idP, - int CC_idP, - uint16_t rntiP, - uint16_t absSFP, - nfapi_ul_config_harq_information *harq_information, - uint8_t cce_idxP) -{ - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; - UE_list_t *UE_list = &eNB->UE_list; - - int UE_id = find_UE_id(module_idP,rntiP); - - AssertFatal(UE_id>=0,"UE_id cannot be found, impossible\n"); - AssertFatal(UE_list!=NULL,"UE_list is null\n"); - AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated!=NULL,"physicalConfigDedicated for rnti %x is null\n",rntiP); - - harq_information->harq_information_rel11.num_ant_ports = 1; - - switch(get_tmode(module_idP,CC_idP,UE_id)) { - case 1: - case 2: - case 5: - case 6: - case 7: - if (cc->tdd_Config!=NULL) { - AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated!=NULL, - "pucch_ConfigDedicated is null for TDD!\n"); - if ((UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode!=NULL)&& - (*UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode==PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) { - harq_information->harq_information_rel10_tdd.harq_size = 2; // 2-bit ACK/NAK - harq_information->harq_information_rel10_tdd.ack_nack_mode = 1; // multiplexing - } - else { - harq_information->harq_information_rel10_tdd.harq_size = 1; // 1-bit ACK/NAK - harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling - } - harq_information->harq_information_rel10_tdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP; - harq_information->harq_information_rel10_tdd.number_of_pucch_resources = 1; + ul_req = + &RC.mac[module_idP]->UL_req_tmp[CC_idP][ul_absSF % + 10]. + ul_config_request_body; + ul_config_pdu = + &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; + // Do PUCCH + fill_nfapi_uci_acknak(module_idP, + CC_idP, + rnti, (frameP * 10) + subframeP, cce_idx); } else { - harq_information->harq_information_rel9_fdd.number_of_pucch_resources = 1; - harq_information->harq_information_rel9_fdd.harq_size = 1; // 1-bit ACK/NAK - harq_information->harq_information_rel9_fdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP; + /* there is already an existing UL grant so update it if needed + * on top of some other UL resource (PUSCH,combined SR/CQI/HARQ on PUCCH, etc) + */ + switch (ul_config_pdu->pdu_type) { + + /* [ulsch] to [ulsch + harq] or [ulsch + harq on pucch] */ + + case NFAPI_UL_CONFIG_ULSCH_PDU_TYPE: + if (use_simultaneous_pucch_pusch == 1) { + // Convert it to an NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE + harq_information = + &ul_config_pdu->ulsch_uci_harq_pdu.harq_information; + ul_config_pdu->pdu_type = + NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE; + LOG_D(MAC, + "Frame %d, Subframe %d: Switched UCI HARQ to ULSCH UCI HARQ\n", + frameP, subframeP); + } else { + // Convert it to an NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE + ulsch_harq_information = + &ul_config_pdu->ulsch_harq_pdu.harq_information; + ul_config_pdu->pdu_type = + NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE; + ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial = 0; // last symbol not punctured + ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks = ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks; // we don't change the number of resource blocks across retransmissions yet + LOG_D(MAC, + "Frame %d, Subframe %d: Switched UCI HARQ to ULSCH HARQ\n", + frameP, subframeP); + } + break; + case NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE: + AssertFatal(use_simultaneous_pucch_pusch == 1, + "Cannot be NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE, simultaneous_pucch_pusch is active"); + break; + case NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE: + AssertFatal(use_simultaneous_pucch_pusch == 0, + "Cannot be NFAPI_UL_CONFIG_ULSCH_UCI_PDU_TYPE, simultaneous_pucch_pusch is inactive\n"); + break; + + /* [ulsch + cqi] to [ulsch + cqi + harq] */ + + case NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE: + // Convert it to an NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE + ulsch_harq_information = + &ul_config_pdu->ulsch_cqi_harq_ri_pdu.harq_information; + ul_config_pdu->pdu_type = + NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE; + /* TODO: check this - when converting from nfapi_ul_config_ulsch_cqi_ri_pdu to + * nfapi_ul_config_ulsch_cqi_harq_ri_pdu, shouldn't we copy initial_transmission_parameters + * from the one to the other? + * Those two types are not compatible. 'initial_transmission_parameters' is not at the + * place in both. + */ + ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial = 0; // last symbol not punctured + ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks = ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks; // we don't change the number of resource blocks across retransmissions yet + break; + case NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE: + AssertFatal(use_simultaneous_pucch_pusch == 0, + "Cannot be NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE, simultaneous_pucch_pusch is active\n"); + break; + + /* [ulsch + cqi on pucch] to [ulsch + cqi on pucch + harq on pucch] */ + + case NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE: + // convert it to an NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE + harq_information = + &ul_config_pdu->ulsch_csi_uci_harq_pdu.harq_information; + ul_config_pdu->pdu_type = + NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE; + break; + case NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE: + AssertFatal(use_simultaneous_pucch_pusch == 1, + "Cannot be NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE, simultaneous_pucch_pusch is inactive\n"); + break; + + /* [sr] to [sr + harq] */ + + case NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE: + // convert to NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; + harq_information = + &ul_config_pdu->uci_sr_harq_pdu.harq_information; + break; + case NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE: + /* nothing to do */ + break; + + /* [cqi] to [cqi + harq] */ + + case NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE: + // convert to NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE + ul_config_pdu->pdu_type = + NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE; + harq_information = + &ul_config_pdu->uci_cqi_harq_pdu.harq_information; + break; + case NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE: + /* nothing to do */ + break; + + /* [cqi + sr] to [cqr + sr + harq] */ + + case NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE: + // convert to NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE + ul_config_pdu->pdu_type = + NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE; + harq_information = + &ul_config_pdu->uci_cqi_sr_harq_pdu.harq_information; + break; + case NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE: + /* nothing to do */ + break; + } } - break; - default: // for any other TM we need 2 bits harq - if (cc->tdd_Config!=NULL) { - AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated!=NULL, - "pucch_ConfigDedicated is null for TDD!\n"); - if ((UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode!=NULL)&& - (*UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode==PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) { - harq_information->harq_information_rel10_tdd.ack_nack_mode = 1; // multiplexing - } - else { - harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling - } - harq_information->harq_information_rel10_tdd.harq_size = 2; - harq_information->harq_information_rel10_tdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP; - harq_information->harq_information_rel10_tdd.number_of_pucch_resources = 1; + + if (ulsch_harq_information) + fill_nfapi_ulsch_harq_information(module_idP, CC_idP, + rnti, ulsch_harq_information); + + if (harq_information) + fill_nfapi_harq_information(module_idP, CC_idP, + rnti, + (frameP * 10) + subframeP, + harq_information, cce_idx); +} + +uint8_t get_V_UL_DAI(module_id_t module_idP, int CC_idP, uint16_t rntiP) +{ + nfapi_hi_dci0_request_body_t *HI_DCI0_req = + &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = + &HI_DCI0_req->hi_dci0_pdu_list[0]; + + for (int i = 0; i < HI_DCI0_req->number_of_dci; i++) { + if ((hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) && + (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti == rntiP)) + return (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8. + dl_assignment_index); } - else { - harq_information->harq_information_rel9_fdd.number_of_pucch_resources = 1; - harq_information->harq_information_rel9_fdd.ack_nack_mode = 0; // 1a/b - harq_information->harq_information_rel9_fdd.harq_size = 2; - harq_information->harq_information_rel9_fdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP; + return (4); // this is rule from Section 7.3 in 36.213 +} + +void +fill_nfapi_ulsch_harq_information(module_id_t module_idP, + int CC_idP, + uint16_t rntiP, + nfapi_ul_config_ulsch_harq_information + * harq_information) +{ + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; + UE_list_t *UE_list = &eNB->UE_list; + + int UE_id = find_UE_id(module_idP, rntiP); + + PUSCH_ConfigDedicated_t *puschConfigDedicated; + // PUSCH_ConfigDedicated_v1020_t *puschConfigDedicated_v1020; + // PUSCH_ConfigDedicated_v1130_t *puschConfigDedicated_v1130; + // PUSCH_ConfigDedicated_v1250_t *puschConfigDedicated_v1250; + + AssertFatal(UE_id >= 0, "UE_id cannot be found, impossible\n"); + AssertFatal(UE_list != NULL, "UE_list is null\n"); + AssertFatal(UE_list->UE_template[CC_idP][UE_id]. + physicalConfigDedicated != NULL, + "physicalConfigDedicated for rnti %x is null\n", rntiP); + AssertFatal((puschConfigDedicated = (PUSCH_ConfigDedicated_t *) + UE_list->UE_template[CC_idP][UE_id]. + physicalConfigDedicated->pusch_ConfigDedicated) != NULL, + "physicalConfigDedicated->puschConfigDedicated for rnti %x is null\n", + rntiP); +#if defined(Rel14) || defined(Rel14) + /* if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext2) puschConfigDedicated_v1020 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext2->pusch_ConfigDedicated_v1020; + #endif + #ifdef Rel14 + if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext4) puschConfigDedicated_v1130 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext4->pusch_ConfigDedicated_v1130; + if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext5) puschConfigDedicated_v1250 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext5->pusch_ConfigDedicated_v1250; + */ +#endif + harq_information->harq_information_rel10.delta_offset_harq = + puschConfigDedicated->betaOffset_ACK_Index; + AssertFatal(UE_list-> + UE_template[CC_idP][UE_id].physicalConfigDedicated-> + pucch_ConfigDedicated != NULL, + "pucch_ConfigDedicated is null!\n"); + if ((UE_list->UE_template[CC_idP][UE_id]. + physicalConfigDedicated->pucch_ConfigDedicated-> + tdd_AckNackFeedbackMode != NULL) + && (*UE_list->UE_template[CC_idP][UE_id]. + physicalConfigDedicated->pucch_ConfigDedicated-> + tdd_AckNackFeedbackMode == + PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) + harq_information->harq_information_rel10.ack_nack_mode = 1; // multiplexing + else + harq_information->harq_information_rel10.ack_nack_mode = 0; // bundling + + switch (get_tmode(module_idP, CC_idP, UE_id)) { + case 1: + case 2: + case 5: + case 6: + case 7: + if (cc->tdd_Config == NULL) // FDD + harq_information->harq_information_rel10.harq_size = 1; + else { + if (harq_information->harq_information_rel10.ack_nack_mode == + 1) + harq_information->harq_information_rel10.harq_size = + get_V_UL_DAI(module_idP, CC_idP, rntiP); + else + harq_information->harq_information_rel10.harq_size = 1; + } + break; + default: // for any other TM we need 2 bits harq + if (cc->tdd_Config == NULL) { + harq_information->harq_information_rel10.harq_size = 2; + } else { + if (harq_information->harq_information_rel10.ack_nack_mode == + 1) + harq_information->harq_information_rel10.harq_size = + get_V_UL_DAI(module_idP, CC_idP, rntiP); + else + harq_information->harq_information_rel10.harq_size = 2; + } + break; + } // get Tmode +} + +void +fill_nfapi_harq_information(module_id_t module_idP, + int CC_idP, + uint16_t rntiP, + uint16_t absSFP, + nfapi_ul_config_harq_information * + harq_information, uint8_t cce_idxP) +{ + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; + UE_list_t *UE_list = &eNB->UE_list; + + int UE_id = find_UE_id(module_idP, rntiP); + + AssertFatal(UE_id >= 0, "UE_id cannot be found, impossible\n"); + AssertFatal(UE_list != NULL, "UE_list is null\n"); + AssertFatal(UE_list->UE_template[CC_idP][UE_id]. + physicalConfigDedicated != NULL, + "physicalConfigDedicated for rnti %x is null\n", rntiP); + + harq_information->harq_information_rel11.num_ant_ports = 1; + + switch (get_tmode(module_idP, CC_idP, UE_id)) { + case 1: + case 2: + case 5: + case 6: + case 7: + if (cc->tdd_Config != NULL) { + AssertFatal(UE_list-> + UE_template[CC_idP] + [UE_id].physicalConfigDedicated-> + pucch_ConfigDedicated != NULL, + "pucch_ConfigDedicated is null for TDD!\n"); + if ((UE_list-> + UE_template[CC_idP][UE_id].physicalConfigDedicated-> + pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL) + && (*UE_list-> + UE_template[CC_idP][UE_id].physicalConfigDedicated-> + pucch_ConfigDedicated->tdd_AckNackFeedbackMode == + PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) + { + harq_information->harq_information_rel10_tdd.harq_size = 2; // 2-bit ACK/NAK + harq_information->harq_information_rel10_tdd.ack_nack_mode = 1; // multiplexing + } else { + harq_information->harq_information_rel10_tdd.harq_size = 1; // 1-bit ACK/NAK + harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling + } + harq_information->harq_information_rel10_tdd.n_pucch_1_0 = + cc->radioResourceConfigCommon->pucch_ConfigCommon. + n1PUCCH_AN + cce_idxP; + harq_information-> + harq_information_rel10_tdd.number_of_pucch_resources = 1; + } else { + harq_information-> + harq_information_rel9_fdd.number_of_pucch_resources = 1; + harq_information->harq_information_rel9_fdd.harq_size = 1; // 1-bit ACK/NAK + harq_information->harq_information_rel9_fdd.n_pucch_1_0 = + cc->radioResourceConfigCommon->pucch_ConfigCommon. + n1PUCCH_AN + cce_idxP; + } + break; + default: // for any other TM we need 2 bits harq + if (cc->tdd_Config != NULL) { + AssertFatal(UE_list-> + UE_template[CC_idP] + [UE_id].physicalConfigDedicated-> + pucch_ConfigDedicated != NULL, + "pucch_ConfigDedicated is null for TDD!\n"); + if ((UE_list-> + UE_template[CC_idP][UE_id].physicalConfigDedicated-> + pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL) + && (*UE_list-> + UE_template[CC_idP][UE_id].physicalConfigDedicated-> + pucch_ConfigDedicated->tdd_AckNackFeedbackMode == + PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) + { + harq_information->harq_information_rel10_tdd.ack_nack_mode = 1; // multiplexing + } else { + harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling + } + harq_information->harq_information_rel10_tdd.harq_size = 2; + harq_information->harq_information_rel10_tdd.n_pucch_1_0 = + cc->radioResourceConfigCommon->pucch_ConfigCommon. + n1PUCCH_AN + cce_idxP; + harq_information-> + harq_information_rel10_tdd.number_of_pucch_resources = 1; + } else { + harq_information-> + harq_information_rel9_fdd.number_of_pucch_resources = 1; + harq_information->harq_information_rel9_fdd.ack_nack_mode = 0; // 1a/b + harq_information->harq_information_rel9_fdd.harq_size = 2; + harq_information->harq_information_rel9_fdd.n_pucch_1_0 = + cc->radioResourceConfigCommon->pucch_ConfigCommon. + n1PUCCH_AN + cce_idxP; + } + break; + } // get Tmode +} + +uint16_t +fill_nfapi_uci_acknak(module_id_t module_idP, + int CC_idP, + uint16_t rntiP, uint16_t absSFP, uint8_t cce_idxP) +{ + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; + + int ackNAK_absSF = get_pucch1_absSF(cc, absSFP); + nfapi_ul_config_request_body_t *ul_req = + &eNB->UL_req_tmp[CC_idP][ackNAK_absSF % 10].ul_config_request_body; + nfapi_ul_config_request_pdu_t *ul_config_pdu = + &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; + + memset((void *) ul_config_pdu, 0, + sizeof(nfapi_ul_config_request_pdu_t)); + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE; + ul_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_ul_config_uci_harq_pdu)); + ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.handle = 0; // don't know how to use this + ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti = + rntiP; + + fill_nfapi_harq_information(module_idP, CC_idP, + rntiP, + absSFP, + &ul_config_pdu->uci_harq_pdu. + harq_information, cce_idxP); + LOG_D(MAC, + "Filled in UCI HARQ request for rnti %x SF %d.%d acknakSF %d.%d, cce_idxP %d-> n1_pucch %d\n", + rntiP, absSFP / 10, absSFP % 10, ackNAK_absSF / 10, + ackNAK_absSF % 10, cce_idxP, + ul_config_pdu->uci_harq_pdu. + harq_information.harq_information_rel9_fdd.n_pucch_1_0); + + ul_req->number_of_pdus++; + + return (((ackNAK_absSF / 10) << 4) + (ackNAK_absSF % 10)); +} + +void +fill_nfapi_dlsch_config(eNB_MAC_INST * eNB, + nfapi_dl_config_request_body_t * dl_req, + uint16_t length, + uint16_t pdu_index, + uint16_t rnti, + uint8_t resource_allocation_type, + uint8_t + virtual_resource_block_assignment_flag, + uint16_t resource_block_coding, + uint8_t modulation, + uint8_t redundancy_version, + uint8_t transport_blocks, + uint8_t transport_block_to_codeword_swap_flag, + uint8_t transmission_scheme, + uint8_t number_of_layers, + uint8_t number_of_subbands, + // uint8_t codebook_index, + uint8_t ue_category_capacity, + uint8_t pa, + uint8_t delta_power_offset_index, + uint8_t ngap, + uint8_t nprb, + uint8_t transmission_mode, + uint8_t num_bf_prb_per_subband, + uint8_t num_bf_vector) +{ + nfapi_dl_config_request_pdu_t *dl_config_pdu = + &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = length; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = pdu_index; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = rnti; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = + resource_allocation_type; + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.virtual_resource_block_assignment_flag = + virtual_resource_block_assignment_flag; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = + resource_block_coding; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = modulation; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = + redundancy_version; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = + transport_blocks; + dl_config_pdu->dlsch_pdu. + dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = + transport_block_to_codeword_swap_flag; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = + transmission_scheme; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = + number_of_layers; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = + number_of_subbands; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = codebook_index; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = + ue_category_capacity; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = pa; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = + delta_power_offset_index; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = ngap; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = nprb; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = + transmission_mode; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = + num_bf_prb_per_subband; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = num_bf_vector; + dl_req->number_pdu++; +} + +uint16_t +fill_nfapi_tx_req(nfapi_tx_request_body_t * tx_req_body, + uint16_t absSF, uint16_t pdu_length, + uint16_t pdu_index, uint8_t * pdu) +{ + nfapi_tx_request_pdu_t *TX_req = + &tx_req_body->tx_pdu_list[tx_req_body->number_of_pdus]; + LOG_D(MAC, "Filling TX_req %d for pdu length %d\n", + tx_req_body->number_of_pdus, pdu_length); + TX_req->pdu_length = pdu_length; + TX_req->pdu_index = pdu_index; + TX_req->num_segments = 1; + TX_req->segments[0].segment_length = pdu_length; + TX_req->segments[0].segment_data = pdu; + tx_req_body->number_of_pdus++; + + return (((absSF / 10) << 4) + (absSF % 10)); +} + +void +fill_nfapi_ulsch_config_request_rel8(nfapi_ul_config_request_pdu_t * + ul_config_pdu, uint8_t cqi_req, + COMMON_channels_t * cc, + struct PhysicalConfigDedicated + *physicalConfigDedicated, + uint8_t tmode, uint32_t handle, + uint16_t rnti, + uint8_t resource_block_start, + uint8_t + number_of_resource_blocks, + uint8_t mcs, + uint8_t cyclic_shift_2_for_drms, + uint8_t + frequency_hopping_enabled_flag, + uint8_t frequency_hopping_bits, + uint8_t new_data_indication, + uint8_t redundancy_version, + uint8_t harq_process_number, + uint8_t ul_tx_mode, + uint8_t current_tx_nb, + uint8_t n_srs, uint16_t size) +{ + memset((void *) ul_config_pdu, 0, + sizeof(nfapi_ul_config_request_pdu_t)); + + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; + ul_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu)); + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = handle; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = rnti; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = + resource_block_start; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = + number_of_resource_blocks; + if (mcs < 11) + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 2; + else if (mcs < 21) + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 4; + else + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 6; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = + cyclic_shift_2_for_drms; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8. + frequency_hopping_enabled_flag = frequency_hopping_enabled_flag; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = + frequency_hopping_bits; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = + new_data_indication; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = + redundancy_version; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = + harq_process_number; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = ul_tx_mode; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = current_tx_nb; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = n_srs; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = size; + + if (cqi_req == 1) { + // Add CQI portion + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE; + ul_config_pdu->pdu_size = + (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_cqi_ri_pdu)); + ul_config_pdu->ulsch_cqi_ri_pdu. + cqi_ri_information.cqi_ri_information_rel9.report_type = 1; + ul_config_pdu->ulsch_cqi_ri_pdu. + cqi_ri_information.cqi_ri_information_rel9. + aperiodic_cqi_pmi_ri_report.number_of_cc = 1; + LOG_D(MAC, "report_type %d\n", + ul_config_pdu->ulsch_cqi_ri_pdu. + cqi_ri_information.cqi_ri_information_rel9.report_type); + + if (cc->p_eNB <= 2 + && (tmode == 3 || tmode == 4 || tmode == 8 || tmode == 9 + || tmode == 10)) + ul_config_pdu->ulsch_cqi_ri_pdu. + cqi_ri_information.cqi_ri_information_rel9. + aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 1; + else if (cc->p_eNB <= 2) + ul_config_pdu->ulsch_cqi_ri_pdu. + cqi_ri_information.cqi_ri_information_rel9. + aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 0; + else if (cc->p_eNB == 4) + ul_config_pdu->ulsch_cqi_ri_pdu. + cqi_ri_information.cqi_ri_information_rel9. + aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 2; + + AssertFatal(physicalConfigDedicated->cqi_ReportConfig != NULL, + "physicalConfigDedicated->cqi_ReportConfig is null!\n"); + AssertFatal(physicalConfigDedicated-> + cqi_ReportConfig->cqi_ReportModeAperiodic != NULL, + "physicalConfigDedicated->cqi_ReportModeAperiodic is null!\n"); + AssertFatal(physicalConfigDedicated->pusch_ConfigDedicated != NULL, + "physicalConfigDedicated->puschConfigDedicated is null!\n"); + + for (int ri = 0; + ri < + (1 << ul_config_pdu->ulsch_cqi_ri_pdu. + cqi_ri_information.cqi_ri_information_rel9. + aperiodic_cqi_pmi_ri_report.cc[0].ri_size); ri++) + ul_config_pdu->ulsch_cqi_ri_pdu. + cqi_ri_information.cqi_ri_information_rel9. + aperiodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[ri] = + get_dl_cqi_pmi_size_pusch(cc, tmode, 1 + ri, + physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic); + + ul_config_pdu->ulsch_cqi_ri_pdu. + cqi_ri_information.cqi_ri_information_rel9.delta_offset_cqi = + physicalConfigDedicated->pusch_ConfigDedicated-> + betaOffset_CQI_Index; + ul_config_pdu->ulsch_cqi_ri_pdu. + cqi_ri_information.cqi_ri_information_rel9.delta_offset_ri = + physicalConfigDedicated->pusch_ConfigDedicated-> + betaOffset_RI_Index; } - break; - } // get Tmode -} - -uint16_t fill_nfapi_uci_acknak(module_id_t module_idP, - int CC_idP, - uint16_t rntiP, - uint16_t absSFP, - uint8_t cce_idxP) -{ - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; - - int ackNAK_absSF = get_pucch1_absSF(cc,absSFP); - nfapi_ul_config_request_body_t *ul_req = &eNB->UL_req_tmp[CC_idP][ackNAK_absSF%10].ul_config_request_body; - nfapi_ul_config_request_pdu_t *ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; - - memset((void*)ul_config_pdu,0,sizeof(nfapi_ul_config_request_pdu_t)); - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE; - ul_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_ul_config_uci_harq_pdu)); - ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.handle = 0; // don't know how to use this - ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti = rntiP; - - fill_nfapi_harq_information(module_idP,CC_idP, - rntiP, - absSFP, - &ul_config_pdu->uci_harq_pdu.harq_information, - cce_idxP); - LOG_D(MAC,"Filled in UCI HARQ request for rnti %x SF %d.%d acknakSF %d.%d, cce_idxP %d-> n1_pucch %d\n",rntiP, - absSFP/10,absSFP%10,ackNAK_absSF/10,ackNAK_absSF%10,cce_idxP,ul_config_pdu->uci_harq_pdu.harq_information.harq_information_rel9_fdd.n_pucch_1_0); - - ul_req->number_of_pdus++; - - return(((ackNAK_absSF/10)<<4) + (ackNAK_absSF%10)); -} - -void fill_nfapi_dlsch_config(eNB_MAC_INST *eNB, - nfapi_dl_config_request_body_t *dl_req, - uint16_t length, - uint16_t pdu_index, - uint16_t rnti, - uint8_t resource_allocation_type, - uint8_t virtual_resource_block_assignment_flag, - uint16_t resource_block_coding, - uint8_t modulation, - uint8_t redundancy_version, - uint8_t transport_blocks, - uint8_t transport_block_to_codeword_swap_flag, - uint8_t transmission_scheme, - uint8_t number_of_layers, - uint8_t number_of_subbands, - // uint8_t codebook_index, - uint8_t ue_category_capacity, - uint8_t pa, - uint8_t delta_power_offset_index, - uint8_t ngap, - uint8_t nprb, - uint8_t transmission_mode, - uint8_t num_bf_prb_per_subband, - uint8_t num_bf_vector - ) -{ - nfapi_dl_config_request_pdu_t *dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu)); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = length; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = pdu_index; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = rnti; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = resource_allocation_type; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = virtual_resource_block_assignment_flag; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = resource_block_coding; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = modulation; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = redundancy_version; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = transport_blocks; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = transport_block_to_codeword_swap_flag; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = transmission_scheme; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = number_of_layers; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = number_of_subbands; - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = codebook_index; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = ue_category_capacity; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = pa; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = delta_power_offset_index; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = ngap; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = nprb; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = transmission_mode; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = num_bf_prb_per_subband; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = num_bf_vector; - dl_req->number_pdu++; -} - -uint16_t fill_nfapi_tx_req(nfapi_tx_request_body_t *tx_req_body,uint16_t absSF,uint16_t pdu_length, uint16_t pdu_index, uint8_t *pdu) -{ - nfapi_tx_request_pdu_t *TX_req = &tx_req_body->tx_pdu_list[tx_req_body->number_of_pdus]; - LOG_D(MAC,"Filling TX_req %d for pdu length %d\n",tx_req_body->number_of_pdus,pdu_length); - TX_req->pdu_length = pdu_length; - TX_req->pdu_index = pdu_index; - TX_req->num_segments = 1; - TX_req->segments[0].segment_length = pdu_length; - TX_req->segments[0].segment_data = pdu; - tx_req_body->number_of_pdus++; - - return(((absSF/10)<<4) + (absSF%10)); -} - -void fill_nfapi_ulsch_config_request_rel8(nfapi_ul_config_request_pdu_t *ul_config_pdu, - uint8_t cqi_req, - COMMON_channels_t *cc, - struct PhysicalConfigDedicated *physicalConfigDedicated, - uint8_t tmode, - uint32_t handle, - uint16_t rnti, - uint8_t resource_block_start, - uint8_t number_of_resource_blocks, - uint8_t mcs, - uint8_t cyclic_shift_2_for_drms, - uint8_t frequency_hopping_enabled_flag, - uint8_t frequency_hopping_bits, - uint8_t new_data_indication, - uint8_t redundancy_version, - uint8_t harq_process_number, - uint8_t ul_tx_mode, - uint8_t current_tx_nb, - uint8_t n_srs, - uint16_t size - ) -{ - memset((void*)ul_config_pdu,0,sizeof(nfapi_ul_config_request_pdu_t)); - - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; - ul_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_ul_config_ulsch_pdu)); - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = handle; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = rnti; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = resource_block_start; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = number_of_resource_blocks; - if (mcs<11) ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 2; - else if (mcs<21) ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 4; - else ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 6; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = cyclic_shift_2_for_drms; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_enabled_flag = frequency_hopping_enabled_flag; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = frequency_hopping_bits; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = new_data_indication; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = redundancy_version; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = harq_process_number; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = ul_tx_mode; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = current_tx_nb; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = n_srs; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = size; - - if (cqi_req == 1) { - // Add CQI portion - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE; - ul_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_ul_config_ulsch_cqi_ri_pdu)); - ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.report_type = 1; - ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.number_of_cc = 1; - LOG_D(MAC,"report_type %d\n",ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.report_type); - - if (cc->p_eNB<=2 && (tmode==3||tmode==4||tmode==8||tmode==9||tmode==10)) - ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 1; - else if (cc->p_eNB<=2) - ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 0; - else if (cc->p_eNB==4) - ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 2; - - AssertFatal(physicalConfigDedicated->cqi_ReportConfig!=NULL,"physicalConfigDedicated->cqi_ReportConfig is null!\n"); - AssertFatal(physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic!=NULL,"physicalConfigDedicated->cqi_ReportModeAperiodic is null!\n"); - AssertFatal(physicalConfigDedicated->pusch_ConfigDedicated!=NULL,"physicalConfigDedicated->puschConfigDedicated is null!\n"); - - for (int ri=0; - ri<(1<ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size); - ri++) - ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[ri] = - get_dl_cqi_pmi_size_pusch(cc, - tmode, - 1+ri, - physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic); - - ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.delta_offset_cqi = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index; - ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.delta_offset_ri = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index; - } } #ifdef Rel14 -void fill_nfapi_ulsch_config_request_emtc(nfapi_ul_config_request_pdu_t *ul_config_pdu, - uint8_t ue_type, - uint16_t total_number_of_repetitions, - uint16_t repetition_number, - uint16_t initial_transmission_sf_io) +void +fill_nfapi_ulsch_config_request_emtc(nfapi_ul_config_request_pdu_t * + ul_config_pdu, uint8_t ue_type, + uint16_t + total_number_of_repetitions, + uint16_t repetition_number, + uint16_t initial_transmission_sf_io) { - // Re13 fields + // Re13 fields - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.ue_type = ue_type; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.total_number_of_repetitions = total_number_of_repetitions; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.repetition_number = repetition_number; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.initial_transmission_sf_io = initial_transmission_sf_io; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.ue_type = ue_type; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.total_number_of_repetitions = + total_number_of_repetitions; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.repetition_number = + repetition_number; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.initial_transmission_sf_io = + initial_transmission_sf_io; } int get_numnarrowbands(long dl_Bandwidth) { - int nb_tab[6] = {1,2,4,8,12,16}; + int nb_tab[6] = { 1, 2, 4, 8, 12, 16 }; - AssertFatal(dl_Bandwidth<7 || dl_Bandwidth>=0,"dl_Bandwidth not in [0..6]\n"); - return(nb_tab[dl_Bandwidth]); + AssertFatal(dl_Bandwidth < 7 + || dl_Bandwidth >= 0, "dl_Bandwidth not in [0..6]\n"); + return (nb_tab[dl_Bandwidth]); } int get_numnarrowbandbits(long dl_Bandwidth) { - int nbbits_tab[6] = {0,1,2,3,4,4}; + int nbbits_tab[6] = { 0, 1, 2, 3, 4, 4 }; - AssertFatal(dl_Bandwidth<7 || dl_Bandwidth>=0,"dl_Bandwidth not in [0..6]\n"); - return(nbbits_tab[dl_Bandwidth]); + AssertFatal(dl_Bandwidth < 7 + || dl_Bandwidth >= 0, "dl_Bandwidth not in [0..6]\n"); + return (nbbits_tab[dl_Bandwidth]); } //This implements the frame/subframe condition for first subframe of MPDCCH transmission (Section 9.1.5 36.213, Rel 13/14) -int startSF_fdd_RA_times2[8] = {2,3,4,5,8,10,16,20}; -int startSF_tdd_RA[7] = {1,2,4,5,8,10,20}; +int startSF_fdd_RA_times2[8] = { 2, 3, 4, 5, 8, 10, 16, 20 }; +int startSF_tdd_RA[7] = { 1, 2, 4, 5, 8, 10, 20 }; -int mpdcch_sf_condition(eNB_MAC_INST *eNB,int CC_id, frame_t frameP,sub_frame_t subframeP,int rmax,MPDCCH_TYPES_t mpdcch_type,int UE_id) +int +mpdcch_sf_condition(eNB_MAC_INST * eNB, int CC_id, frame_t frameP, + sub_frame_t subframeP, int rmax, + MPDCCH_TYPES_t mpdcch_type, int UE_id) { - struct PRACH_ConfigSIB_v1310 *ext4_prach = eNB->common_channels[CC_id].radioResourceConfigCommon_BR->ext4->prach_ConfigCommon_v1310; + struct PRACH_ConfigSIB_v1310 *ext4_prach = + eNB->common_channels[CC_id].radioResourceConfigCommon_BR-> + ext4->prach_ConfigCommon_v1310; - int T; - EPDCCH_SetConfig_r11_t *epdcch_setconfig_r11; + int T; + EPDCCH_SetConfig_r11_t *epdcch_setconfig_r11; - switch (mpdcch_type) { - case TYPE0: - AssertFatal(1==0,"MPDCCH Type 0 not handled yet\n"); - break; - case TYPE1: - AssertFatal(1==0,"MPDCCH Type 1 not handled yet\n"); - break; - case TYPE1A: - AssertFatal(1==0,"MPDCCH Type 1A not handled yet\n"); - break; - case TYPE2: // RAR - AssertFatal(ext4_prach->mpdcch_startSF_CSS_RA_r13!=NULL, - "mpdcch_startSF_CSS_RA_r13 is null\n"); - AssertFatal(rmax>0,"rmax is 0!\b"); - if (eNB->common_channels[CC_id].tdd_Config==NULL) //FDD - T = rmax*startSF_fdd_RA_times2[ext4_prach->mpdcch_startSF_CSS_RA_r13->choice.fdd_r13]>>1; - else //TDD - T = rmax*startSF_tdd_RA[ext4_prach->mpdcch_startSF_CSS_RA_r13->choice.tdd_r13]; - break; - case TYPE2A: - AssertFatal(1==0,"MPDCCH Type 2A not handled yet\n"); - break; - case TYPEUESPEC: - epdcch_setconfig_r11= eNB->UE_list.UE_template[CC_id][UE_id].physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.setConfigToAddModList_r11->list.array[0] ; + switch (mpdcch_type) { + case TYPE0: + AssertFatal(1 == 0, "MPDCCH Type 0 not handled yet\n"); + break; + case TYPE1: + AssertFatal(1 == 0, "MPDCCH Type 1 not handled yet\n"); + break; + case TYPE1A: + AssertFatal(1 == 0, "MPDCCH Type 1A not handled yet\n"); + break; + case TYPE2: // RAR + AssertFatal(ext4_prach->mpdcch_startSF_CSS_RA_r13 != NULL, + "mpdcch_startSF_CSS_RA_r13 is null\n"); + AssertFatal(rmax > 0, "rmax is 0!\b"); + if (eNB->common_channels[CC_id].tdd_Config == NULL) //FDD + T = rmax * + startSF_fdd_RA_times2[ext4_prach-> + mpdcch_startSF_CSS_RA_r13-> + choice.fdd_r13] >> 1; + else //TDD + T = rmax * + startSF_tdd_RA[ext4_prach-> + mpdcch_startSF_CSS_RA_r13->choice.tdd_r13]; + break; + case TYPE2A: + AssertFatal(1 == 0, "MPDCCH Type 2A not handled yet\n"); + break; + case TYPEUESPEC: + epdcch_setconfig_r11 = + eNB->UE_list.UE_template[CC_id][UE_id]. + physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11. + choice.setup.setConfigToAddModList_r11->list.array[0]; - AssertFatal(epdcch_setconfig_r11 != NULL," epdcch_setconfig_r11 is null for UE specific \n"); - AssertFatal(epdcch_setconfig_r11->ext2 != NULL," ext2 doesn't exist in epdcch config ' \n"); + AssertFatal(epdcch_setconfig_r11 != NULL, + " epdcch_setconfig_r11 is null for UE specific \n"); + AssertFatal(epdcch_setconfig_r11->ext2 != NULL, + " ext2 doesn't exist in epdcch config ' \n"); - if (eNB->common_channels[CC_id].tdd_Config==NULL) //FDD - T = rmax*startSF_fdd_RA_times2[epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_StartSF_UESS_r13.choice.fdd_r13]>>1; - else //TDD - T = rmax*startSF_tdd_RA[epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_StartSF_UESS_r13.choice.tdd_r13]; + if (eNB->common_channels[CC_id].tdd_Config == NULL) //FDD + T = rmax * + startSF_fdd_RA_times2[epdcch_setconfig_r11-> + ext2->mpdcch_config_r13->choice. + setup.mpdcch_StartSF_UESS_r13.choice. + fdd_r13] >> 1; + else //TDD + T = rmax * + startSF_tdd_RA[epdcch_setconfig_r11-> + ext2->mpdcch_config_r13->choice. + setup.mpdcch_StartSF_UESS_r13.choice. + tdd_r13]; - break; - default: - return(0); - } + break; + default: + return (0); + } - AssertFatal(T>0,"T is 0!\n"); - if (((10*frameP) + subframeP)%T == 0) return(1); - else return(0); + AssertFatal(T > 0, "T is 0!\n"); + if (((10 * frameP) + subframeP) % T == 0) + return (1); + else + return (0); } -int narrowband_to_first_rb(COMMON_channels_t *cc, int nb_index) +int narrowband_to_first_rb(COMMON_channels_t * cc, int nb_index) { - switch (cc->mib->message.dl_Bandwidth) { - case 0: // 6 PRBs, N_NB=1, i_0=0 - return(0); - break; - case 3: // 50 PRBs, N_NB=8, i_0=1 - return((int)(1+(6*nb_index))); - break; - case 5: // 100 PRBs, N_NB=16, i_0=2 - return((int)(2+(6*nb_index))); - break; - case 1: // 15 PRBs N_NB=2, i_0=1 - if (nb_index>0) return(1); - else return(0); - break; - case 2: // 25 PRBs, N_NB=4, i_0=0 - if (nb_index>1) return(1+(6*nb_index)); - else return((6*nb_index)); - break; - case 4: // 75 PRBs, N_NB=12, i_0=1 - if (nb_index>5) return(2+(6*nb_index)); - else return(1+(6*nb_index)); - break; - default: - AssertFatal(1==0,"Impossible dl_Bandwidth %d\n",(int)cc->mib->message.dl_Bandwidth); - break; - } + switch (cc->mib->message.dl_Bandwidth) { + case 0: // 6 PRBs, N_NB=1, i_0=0 + return (0); + break; + case 3: // 50 PRBs, N_NB=8, i_0=1 + return ((int) (1 + (6 * nb_index))); + break; + case 5: // 100 PRBs, N_NB=16, i_0=2 + return ((int) (2 + (6 * nb_index))); + break; + case 1: // 15 PRBs N_NB=2, i_0=1 + if (nb_index > 0) + return (1); + else + return (0); + break; + case 2: // 25 PRBs, N_NB=4, i_0=0 + if (nb_index > 1) + return (1 + (6 * nb_index)); + else + return ((6 * nb_index)); + break; + case 4: // 75 PRBs, N_NB=12, i_0=1 + if (nb_index > 5) + return (2 + (6 * nb_index)); + else + return (1 + (6 * nb_index)); + break; + default: + AssertFatal(1 == 0, "Impossible dl_Bandwidth %d\n", + (int) cc->mib->message.dl_Bandwidth); + break; + } } #endif @@ -1511,23 +1843,23 @@ int narrowband_to_first_rb(COMMON_channels_t *cc, int nb_index) void init_ue_sched_info(void) //------------------------------------------------------------------------------ { - module_id_t i,j,k; + module_id_t i, j, k; - for (i=0; iUE_list; + int UE_id; + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { - if (UE_list->active[UE_id] != TRUE) continue; - if (UE_list->UE_template[UE_PCCID(mod_idP,UE_id)][UE_id].rnti==rntiP) { - return(UE_id); + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { + if (UE_list->active[UE_id] != TRUE) + continue; + if (UE_list->UE_template[UE_PCCID(mod_idP, UE_id)][UE_id].rnti == + rntiP) { + return (UE_id); + } } - } - return(-1); + return (-1); } //------------------------------------------------------------------------------ int find_RA_id(module_id_t mod_idP, int CC_idP, rnti_t rntiP) //------------------------------------------------------------------------------ { - int RA_id; - AssertFatal(RC.mac[mod_idP],"RC.mac[%d] is null\n",mod_idP); + int RA_id; + AssertFatal(RC.mac[mod_idP], "RC.mac[%d] is null\n", mod_idP); - RA_TEMPLATE *RA_template = (RA_TEMPLATE *)&RC.mac[mod_idP]->common_channels[CC_idP].RA_template[0]; + RA_t *ra = (RA_t *) & RC.mac[mod_idP]->common_channels[CC_idP].ra[0]; - for (RA_id = 0; RA_id < NB_RA_PROC_MAX; RA_id++) { - LOG_D(MAC,"Checking RA_id %d for %x : RA_active %d, wait_ack_Msg4 %d\n", - RA_id,rntiP, - RA_template[RA_id].RA_active, - RA_template[RA_id].wait_ack_Msg4); + for (RA_id = 0; RA_id < NB_RA_PROC_MAX; RA_id++) { + LOG_D(MAC, + "Checking RA_id %d for %x : state %d\n", + RA_id, rntiP, ra[RA_id].state); - if (RA_template[RA_id].RA_active==TRUE && - RA_template[RA_id].wait_ack_Msg4 == 0 && - RA_template[RA_id].rnti == rntiP) return(RA_id); - } - return(-1); + if (ra[RA_id].state != IDLE && + ra[RA_id].rnti == rntiP) + return (RA_id); + } + return (-1); } //------------------------------------------------------------------------------ -int UE_num_active_CC(UE_list_t *listP,int ue_idP) +int UE_num_active_CC(UE_list_t * listP, int ue_idP) //------------------------------------------------------------------------------ { - return(listP->numactiveCCs[ue_idP]); + return (listP->numactiveCCs[ue_idP]); } //------------------------------------------------------------------------------ -int UE_PCCID(module_id_t mod_idP,int ue_idP) +int UE_PCCID(module_id_t mod_idP, int ue_idP) //------------------------------------------------------------------------------ { - return(RC.mac[mod_idP]->UE_list.pCC_id[ue_idP]); + return (RC.mac[mod_idP]->UE_list.pCC_id[ue_idP]); } //------------------------------------------------------------------------------ rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP) //------------------------------------------------------------------------------ { - rnti_t rnti = RC.mac[mod_idP]->UE_list.UE_template[UE_PCCID(mod_idP,ue_idP)][ue_idP].rnti; + rnti_t rnti = + RC.mac[mod_idP]-> + UE_list.UE_template[UE_PCCID(mod_idP, ue_idP)][ue_idP].rnti; - if (rnti>0) { - return (rnti); - } + if (rnti > 0) { + return (rnti); + } - LOG_D(MAC,"[eNB %d] Couldn't find RNTI for UE %d\n",mod_idP,ue_idP); - //display_backtrace(); - return(NOT_A_RNTI); + LOG_D(MAC, "[eNB %d] Couldn't find RNTI for UE %d\n", mod_idP, ue_idP); + //display_backtrace(); + return (NOT_A_RNTI); } //------------------------------------------------------------------------------ boolean_t is_UE_active(module_id_t mod_idP, int ue_idP) //------------------------------------------------------------------------------ { - return(RC.mac[mod_idP]->UE_list.active[ue_idP]); + return (RC.mac[mod_idP]->UE_list.active[ue_idP]); } /* @@ -1639,317 +1974,333 @@ uint8_t find_active_UEs(module_id_t module_idP,int CC_id){ // get aggregation (L) form phy for a give UE -unsigned char get_aggregation (uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt) +unsigned char +get_aggregation(uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt) { - unsigned char aggregation=3; + unsigned char aggregation = 3; - switch (dci_fmt){ - case format0: - aggregation = cqi2fmt0_agg[bw_index][cqi]; - break; - case format1: - case format1A: - case format1B: - case format1D: - aggregation = cqi2fmt1x_agg[bw_index][cqi]; - break; - case format2: - case format2A: - case format2B: - case format2C: - case format2D: - aggregation = cqi2fmt2x_agg[bw_index][cqi]; - break; - case format1C: - case format1E_2A_M10PRB: - case format3: - case format3A: - case format4: - default: - LOG_W(MAC,"unsupported DCI format %d\n",dci_fmt); - } + switch (dci_fmt) { + case format0: + aggregation = cqi2fmt0_agg[bw_index][cqi]; + break; + case format1: + case format1A: + case format1B: + case format1D: + aggregation = cqi2fmt1x_agg[bw_index][cqi]; + break; + case format2: + case format2A: + case format2B: + case format2C: + case format2D: + aggregation = cqi2fmt2x_agg[bw_index][cqi]; + break; + case format1C: + case format1E_2A_M10PRB: + case format3: + case format3A: + case format4: + default: + LOG_W(MAC, "unsupported DCI format %d\n", dci_fmt); + } - LOG_D(MAC,"Aggregation level %d (cqi %d, bw_index %d, format %d)\n", - 1<head; j>=0; j=listP->next[j]) { - LOG_T(MAC,"node %d => %d\n",j,listP->next[j]); + if (ul_flag == 0) { + for (j = listP->head; j >= 0; j = listP->next[j]) { + LOG_T(MAC, "node %d => %d\n", j, listP->next[j]); + } + } else { + for (j = listP->head_ul; j >= 0; j = listP->next_ul[j]) { + LOG_T(MAC, "node %d => %d\n", j, listP->next_ul[j]); + } } - } else { - for (j=listP->head_ul; j>=0; j=listP->next_ul[j]) { - LOG_T(MAC,"node %d => %d\n",j,listP->next_ul[j]); - } - } } -int add_new_ue(module_id_t mod_idP, int cc_idP, rnti_t rntiP,int harq_pidP - #ifdef Rel14 - ,uint8_t rach_resource_type - #endif - ) +int add_new_ue(module_id_t mod_idP, int cc_idP, rnti_t rntiP, int harq_pidP +#ifdef Rel14 + , uint8_t rach_resource_type +#endif + ) { - int UE_id; - int i, j; + int UE_id; + int i, j; - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - LOG_D(MAC,"[eNB %d, CC_id %d] Adding UE with rnti %x (next avail %d, num_UEs %d)\n",mod_idP,cc_idP,rntiP,UE_list->avail,UE_list->num_UEs); - dump_ue_list(UE_list,0); + LOG_D(MAC, + "[eNB %d, CC_id %d] Adding UE with rnti %x (next avail %d, num_UEs %d)\n", + mod_idP, cc_idP, rntiP, UE_list->avail, UE_list->num_UEs); + dump_ue_list(UE_list, 0); - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i] == TRUE) continue; - UE_id = i; - memset(&UE_list->UE_template[cc_idP][UE_id], 0, sizeof(UE_TEMPLATE)); - UE_list->UE_template[cc_idP][UE_id].rnti = rntiP; - UE_list->UE_template[cc_idP][UE_id].configured = FALSE; - UE_list->numactiveCCs[UE_id] = 1; - UE_list->numactiveULCCs[UE_id] = 1; - UE_list->pCC_id[UE_id] = cc_idP; - UE_list->ordered_CCids[0][UE_id] = cc_idP; - UE_list->ordered_ULCCids[0][UE_id] = cc_idP; - UE_list->num_UEs++; - UE_list->active[UE_id] = TRUE; + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (UE_list->active[i] == TRUE) + continue; + UE_id = i; + memset(&UE_list->UE_template[cc_idP][UE_id], 0, + sizeof(UE_TEMPLATE)); + UE_list->UE_template[cc_idP][UE_id].rnti = rntiP; + UE_list->UE_template[cc_idP][UE_id].configured = FALSE; + UE_list->numactiveCCs[UE_id] = 1; + UE_list->numactiveULCCs[UE_id] = 1; + UE_list->pCC_id[UE_id] = cc_idP; + UE_list->ordered_CCids[0][UE_id] = cc_idP; + UE_list->ordered_ULCCids[0][UE_id] = cc_idP; + UE_list->num_UEs++; + UE_list->active[UE_id] = TRUE; #ifdef Rel14 - UE_list->UE_template[cc_idP][UE_id].rach_resource_type = rach_resource_type ; + UE_list->UE_template[cc_idP][UE_id].rach_resource_type = + rach_resource_type; #endif - memset((void*)&UE_list->UE_sched_ctrl[UE_id],0,sizeof(UE_sched_ctrl)); - memset((void*)&UE_list->eNB_UE_stats[cc_idP][UE_id],0,sizeof(eNB_UE_STATS)); + memset((void *) &UE_list->UE_sched_ctrl[UE_id], 0, + sizeof(UE_sched_ctrl)); + memset((void *) &UE_list->eNB_UE_stats[cc_idP][UE_id], 0, + sizeof(eNB_UE_STATS)); - UE_list->UE_sched_ctrl[UE_id].ta_update = 31; + UE_list->UE_sched_ctrl[UE_id].ta_update = 31; - for (j=0; j<8; j++) { - UE_list->UE_template[cc_idP][UE_id].oldNDI[j] = (j==0)?1:0; // 1 because first transmission is with format1A (Msg4) for harq_pid 0 - UE_list->UE_template[cc_idP][UE_id].oldNDI_UL[j] = (j==harq_pidP)?0:1; // 1st transmission is with Msg3; - UE_list->UE_sched_ctrl[UE_id].round[cc_idP][j] = 8; - UE_list->UE_sched_ctrl[UE_id].round_UL[cc_idP][j] = 0; + for (j = 0; j < 8; j++) { + UE_list->UE_template[cc_idP][UE_id].oldNDI[j] = (j == 0) ? 1 : 0; // 1 because first transmission is with format1A (Msg4) for harq_pid 0 + UE_list->UE_template[cc_idP][UE_id].oldNDI_UL[j] = (j == harq_pidP) ? 0 : 1; // 1st transmission is with Msg3; + UE_list->UE_sched_ctrl[UE_id].round[cc_idP][j] = 8; + UE_list->UE_sched_ctrl[UE_id].round_UL[cc_idP][j] = 0; + } + + eNB_ulsch_info[mod_idP][cc_idP][UE_id].status = S_UL_WAITING; + eNB_dlsch_info[mod_idP][cc_idP][UE_id].status = S_DL_WAITING; + LOG_D(MAC, "[eNB %d] Add UE_id %d on Primary CC_id %d: rnti %x\n", + mod_idP, UE_id, cc_idP, rntiP); + dump_ue_list(UE_list, 0); + return (UE_id); } - eNB_ulsch_info[mod_idP][cc_idP][UE_id].status = S_UL_WAITING; - eNB_dlsch_info[mod_idP][cc_idP][UE_id].status = S_DL_WAITING; - LOG_D(MAC,"[eNB %d] Add UE_id %d on Primary CC_id %d: rnti %x\n",mod_idP,UE_id,cc_idP,rntiP); - dump_ue_list(UE_list,0); - return(UE_id); - } - - printf("MAC: cannot add new UE for rnti %x\n", rntiP); - LOG_E(MAC,"error in add_new_ue(), could not find space in UE_list, Dumping UE list\n"); - dump_ue_list(UE_list,0); - return(-1); + printf("MAC: cannot add new UE for rnti %x\n", rntiP); + LOG_E(MAC, + "error in add_new_ue(), could not find space in UE_list, Dumping UE list\n"); + dump_ue_list(UE_list, 0); + return (-1); } //------------------------------------------------------------------------------ -int rrc_mac_remove_ue(module_id_t mod_idP,rnti_t rntiP) +int rrc_mac_remove_ue(module_id_t mod_idP, rnti_t rntiP) //------------------------------------------------------------------------------ { - int i; - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - int UE_id = find_UE_id(mod_idP,rntiP); - int pCC_id; + int i; + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + int UE_id = find_UE_id(mod_idP, rntiP); + int pCC_id; + + if (UE_id == -1) { + LOG_W(MAC, "rrc_mac_remove_ue: UE %x not found\n", rntiP); + return 0; + } + + pCC_id = UE_PCCID(mod_idP, UE_id); + + LOG_I(MAC, "Removing UE %d from Primary CC_id %d (rnti %x)\n", UE_id, + pCC_id, rntiP); + dump_ue_list(UE_list, 0); + + UE_list->active[UE_id] = FALSE; + UE_list->num_UEs--; + + if (UE_list->head == UE_id) + UE_list->head = UE_list->next[UE_id]; + else + UE_list->next[prev(UE_list, UE_id, 0)] = UE_list->next[UE_id]; + if (UE_list->head_ul == UE_id) + UE_list->head_ul = UE_list->next_ul[UE_id]; + else + UE_list->next_ul[prev(UE_list, UE_id, 0)] = + UE_list->next_ul[UE_id]; + + // clear all remaining pending transmissions + UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID0] = 0; + UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID1] = 0; + UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID2] = 0; + UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID3] = 0; + + UE_list->UE_template[pCC_id][UE_id].ul_SR = 0; + UE_list->UE_template[pCC_id][UE_id].rnti = NOT_A_RNTI; + UE_list->UE_template[pCC_id][UE_id].ul_active = FALSE; + eNB_ulsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI; + eNB_ulsch_info[mod_idP][pCC_id][UE_id].status = S_UL_NONE; + eNB_dlsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI; + eNB_dlsch_info[mod_idP][pCC_id][UE_id].status = S_DL_NONE; + + // check if this has an RA process active + RA_t *ra; + for (i = 0; i < NB_RA_PROC_MAX; i++) { + ra = (RA_t *) & RC.mac[mod_idP]->common_channels[pCC_id].ra[i]; + if (ra->rnti == rntiP) { + ra->state = IDLE; + ra->timing_offset = 0; + ra->RRC_timer = 20; + ra->rnti = 0; + //break; + } + } - if (UE_id == -1) { - LOG_W(MAC,"rrc_mac_remove_ue: UE %x not found\n", rntiP); return 0; - } - - pCC_id = UE_PCCID(mod_idP,UE_id); - - LOG_I(MAC,"Removing UE %d from Primary CC_id %d (rnti %x)\n",UE_id,pCC_id, rntiP); - dump_ue_list(UE_list,0); - - UE_list->active[UE_id] = FALSE; - UE_list->num_UEs--; - - if (UE_list->head == UE_id) UE_list->head=UE_list->next[UE_id]; - else UE_list->next[prev(UE_list,UE_id,0)]=UE_list->next[UE_id]; - if (UE_list->head_ul == UE_id) UE_list->head_ul=UE_list->next_ul[UE_id]; - else UE_list->next_ul[prev(UE_list,UE_id,0)]=UE_list->next_ul[UE_id]; - - // clear all remaining pending transmissions - UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID0] = 0; - UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID1] = 0; - UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID2] = 0; - UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID3] = 0; - - UE_list->UE_template[pCC_id][UE_id].ul_SR = 0; - UE_list->UE_template[pCC_id][UE_id].rnti = NOT_A_RNTI; - UE_list->UE_template[pCC_id][UE_id].ul_active = FALSE; - eNB_ulsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI; - eNB_ulsch_info[mod_idP][pCC_id][UE_id].status = S_UL_NONE; - eNB_dlsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI; - eNB_dlsch_info[mod_idP][pCC_id][UE_id].status = S_DL_NONE; - - // check if this has an RA process active - RA_TEMPLATE *RA_template; - for (i=0;icommon_channels[pCC_id].RA_template[i]; - if (RA_template->rnti == rntiP){ - RA_template->RA_active=FALSE; - RA_template->generate_rar=0; - RA_template->generate_Msg4=0; - RA_template->wait_ack_Msg4=0; - RA_template->timing_offset=0; - RA_template->RRC_timer=20; - RA_template->rnti = 0; - //break; - } - } - - return 0; } -int prev(UE_list_t *listP, int nodeP, int ul_flag) +int prev(UE_list_t * listP, int nodeP, int ul_flag) { - int j; + int j; - if (ul_flag == 0 ) { - if (nodeP==listP->head) { - return(nodeP); + if (ul_flag == 0) { + if (nodeP == listP->head) { + return (nodeP); + } + + for (j = listP->head; j >= 0; j = listP->next[j]) { + if (listP->next[j] == nodeP) { + return (j); + } + } + } else { + if (nodeP == listP->head_ul) { + return (nodeP); + } + + for (j = listP->head_ul; j >= 0; j = listP->next_ul[j]) { + if (listP->next_ul[j] == nodeP) { + return (j); + } + } } - for (j=listP->head; j>=0; j=listP->next[j]) { - if (listP->next[j]==nodeP) { - return(j); - } - } - } else { - if (nodeP==listP->head_ul) { - return(nodeP); - } + LOG_E(MAC, + "error in prev(), could not find previous to %d in UE_list %s, should never happen, Dumping UE list\n", + nodeP, (ul_flag == 0) ? "DL" : "UL"); + dump_ue_list(listP, ul_flag); - for (j=listP->head_ul; j>=0; j=listP->next_ul[j]) { - if (listP->next_ul[j]==nodeP) { - return(j); - } - } - } - - LOG_E(MAC,"error in prev(), could not find previous to %d in UE_list %s, should never happen, Dumping UE list\n", - nodeP, (ul_flag == 0)? "DL" : "UL"); - dump_ue_list(listP, ul_flag); - - return(-1); + return (-1); } -void swap_UEs(UE_list_t *listP,int nodeiP, int nodejP, int ul_flag) +void swap_UEs(UE_list_t * listP, int nodeiP, int nodejP, int ul_flag) { - int prev_i,prev_j,next_i,next_j; + int prev_i, prev_j, next_i, next_j; - LOG_T(MAC,"Swapping UE %d,%d\n",nodeiP,nodejP); - dump_ue_list(listP,ul_flag); + LOG_T(MAC, "Swapping UE %d,%d\n", nodeiP, nodejP); + dump_ue_list(listP, ul_flag); - prev_i = prev(listP,nodeiP,ul_flag); - prev_j = prev(listP,nodejP,ul_flag); + prev_i = prev(listP, nodeiP, ul_flag); + prev_j = prev(listP, nodejP, ul_flag); - AssertFatal((prev_i>=0) && (prev_j>=0), - "swap_UEs: problem"); + AssertFatal((prev_i >= 0) && (prev_j >= 0), "swap_UEs: problem"); - if (ul_flag == 0) { - next_i = listP->next[nodeiP]; - next_j = listP->next[nodejP]; - } else { - next_i = listP->next_ul[nodeiP]; - next_j = listP->next_ul[nodejP]; - } - - LOG_T(MAC,"[%s] next_i %d, next_i, next_j %d, head %d \n", - (ul_flag == 0)? "DL" : "UL", - next_i,next_j,listP->head); - - if (ul_flag == 0 ) { - - if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ... - LOG_T(MAC,"Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n"); - - listP->next[nodeiP] = next_j; - listP->next[nodejP] = nodeiP; - - if (nodeiP==listP->head) { // case i j n(j) - listP->head = nodejP; - } else { - listP->next[prev_i] = nodejP; - } - } else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ... - LOG_T(MAC,"Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n"); - listP->next[nodejP] = next_i; - listP->next[nodeiP] = nodejP; - - if (nodejP==listP->head) { // case j i n(i) - listP->head = nodeiP; - } else { - listP->next[prev_j] = nodeiP; - } - } else { // case ... p(i) i n(i) ... p(j) j n(j) ... - listP->next[nodejP] = next_i; - listP->next[nodeiP] = next_j; - - if (nodeiP==listP->head) { - LOG_T(MAC,"changing head to %d\n",nodejP); - listP->head=nodejP; - listP->next[prev_j] = nodeiP; - } else if (nodejP==listP->head) { - LOG_D(MAC,"changing head to %d\n",nodeiP); - listP->head=nodeiP; - listP->next[prev_i] = nodejP; - } else { - listP->next[prev_i] = nodejP; - listP->next[prev_j] = nodeiP; - } + if (ul_flag == 0) { + next_i = listP->next[nodeiP]; + next_j = listP->next[nodejP]; + } else { + next_i = listP->next_ul[nodeiP]; + next_j = listP->next_ul[nodejP]; } - } else { // ul_flag - if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ... - LOG_T(MAC,"[UL] Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n"); + LOG_T(MAC, "[%s] next_i %d, next_i, next_j %d, head %d \n", + (ul_flag == 0) ? "DL" : "UL", next_i, next_j, listP->head); - listP->next_ul[nodeiP] = next_j; - listP->next_ul[nodejP] = nodeiP; + if (ul_flag == 0) { - if (nodeiP==listP->head_ul) { // case i j n(j) - listP->head_ul = nodejP; - } else { - listP->next_ul[prev_i] = nodejP; - } - } else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ... - LOG_T(MAC,"[UL]Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n"); - listP->next_ul[nodejP] = next_i; - listP->next_ul[nodeiP] = nodejP; + if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ... + LOG_T(MAC, + "Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n"); - if (nodejP==listP->head_ul) { // case j i n(i) - listP->head_ul = nodeiP; - } else { - listP->next_ul[prev_j] = nodeiP; - } - } else { // case ... p(i) i n(i) ... p(j) j n(j) ... + listP->next[nodeiP] = next_j; + listP->next[nodejP] = nodeiP; - listP->next_ul[nodejP] = next_i; - listP->next_ul[nodeiP] = next_j; + if (nodeiP == listP->head) { // case i j n(j) + listP->head = nodejP; + } else { + listP->next[prev_i] = nodejP; + } + } else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ... + LOG_T(MAC, + "Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n"); + listP->next[nodejP] = next_i; + listP->next[nodeiP] = nodejP; - if (nodeiP==listP->head_ul) { - LOG_T(MAC,"[UL]changing head to %d\n",nodejP); - listP->head_ul=nodejP; - listP->next_ul[prev_j] = nodeiP; - } else if (nodejP==listP->head_ul) { - LOG_T(MAC,"[UL]changing head to %d\n",nodeiP); - listP->head_ul=nodeiP; - listP->next_ul[prev_i] = nodejP; - } else { - listP->next_ul[prev_i] = nodejP; - listP->next_ul[prev_j] = nodeiP; - } + if (nodejP == listP->head) { // case j i n(i) + listP->head = nodeiP; + } else { + listP->next[prev_j] = nodeiP; + } + } else { // case ... p(i) i n(i) ... p(j) j n(j) ... + listP->next[nodejP] = next_i; + listP->next[nodeiP] = next_j; + + if (nodeiP == listP->head) { + LOG_T(MAC, "changing head to %d\n", nodejP); + listP->head = nodejP; + listP->next[prev_j] = nodeiP; + } else if (nodejP == listP->head) { + LOG_D(MAC, "changing head to %d\n", nodeiP); + listP->head = nodeiP; + listP->next[prev_i] = nodejP; + } else { + listP->next[prev_i] = nodejP; + listP->next[prev_j] = nodeiP; + } + } + } else { // ul_flag + + if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ... + LOG_T(MAC, + "[UL] Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n"); + + listP->next_ul[nodeiP] = next_j; + listP->next_ul[nodejP] = nodeiP; + + if (nodeiP == listP->head_ul) { // case i j n(j) + listP->head_ul = nodejP; + } else { + listP->next_ul[prev_i] = nodejP; + } + } else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ... + LOG_T(MAC, + "[UL]Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n"); + listP->next_ul[nodejP] = next_i; + listP->next_ul[nodeiP] = nodejP; + + if (nodejP == listP->head_ul) { // case j i n(i) + listP->head_ul = nodeiP; + } else { + listP->next_ul[prev_j] = nodeiP; + } + } else { // case ... p(i) i n(i) ... p(j) j n(j) ... + + listP->next_ul[nodejP] = next_i; + listP->next_ul[nodeiP] = next_j; + + if (nodeiP == listP->head_ul) { + LOG_T(MAC, "[UL]changing head to %d\n", nodejP); + listP->head_ul = nodejP; + listP->next_ul[prev_j] = nodeiP; + } else if (nodejP == listP->head_ul) { + LOG_T(MAC, "[UL]changing head to %d\n", nodeiP); + listP->head_ul = nodeiP; + listP->next_ul[prev_i] = nodejP; + } else { + listP->next_ul[prev_i] = nodejP; + listP->next_ul[prev_j] = nodeiP; + } + } } - } - LOG_T(MAC,"After swap\n"); - dump_ue_list(listP,ul_flag); + LOG_T(MAC, "After swap\n"); + dump_ue_list(listP, ul_flag); } /* @@ -2066,818 +2417,959 @@ void swap_UEs(UE_list_t *listP,int nodeiP, int nodejP, int ul_flag) */ // This has to be updated to include BSR information -uint8_t UE_is_to_be_scheduled(module_id_t module_idP,int CC_id,uint8_t UE_id) +uint8_t +UE_is_to_be_scheduled(module_id_t module_idP, int CC_id, uint8_t UE_id) { - UE_TEMPLATE *UE_template = &RC.mac[module_idP]->UE_list.UE_template[CC_id][UE_id]; - UE_sched_ctrl *UE_sched_ctl = &RC.mac[module_idP]->UE_list.UE_sched_ctrl[UE_id]; + UE_TEMPLATE *UE_template = + &RC.mac[module_idP]->UE_list.UE_template[CC_id][UE_id]; + UE_sched_ctrl *UE_sched_ctl = + &RC.mac[module_idP]->UE_list.UE_sched_ctrl[UE_id]; - // do not schedule UE if UL is not working - if (UE_sched_ctl->ul_failure_timer>0) - return(0); - if (UE_sched_ctl->ul_out_of_sync>0) - return(0); + // do not schedule UE if UL is not working + if (UE_sched_ctl->ul_failure_timer > 0) + return (0); + if (UE_sched_ctl->ul_out_of_sync > 0) + return (0); - LOG_D(MAC,"[eNB %d][PUSCH] Checking UL requirements UE %d/%x\n",module_idP,UE_id,UE_RNTI(module_idP,UE_id)); + LOG_D(MAC, "[eNB %d][PUSCH] Checking UL requirements UE %d/%x\n", + module_idP, UE_id, UE_RNTI(module_idP, UE_id)); - if ((UE_template->bsr_info[LCGID0]>0) || - (UE_template->bsr_info[LCGID1]>0) || - (UE_template->bsr_info[LCGID2]>0) || - (UE_template->bsr_info[LCGID3]>0) || - (UE_template->ul_SR>0) || // uplink scheduling request - ((UE_sched_ctl->ul_inactivity_timer>20)&& - (UE_sched_ctl->ul_scheduled==0))|| // every 2 frames when RRC_CONNECTED - ((UE_sched_ctl->ul_inactivity_timer>10)&& - (UE_sched_ctl->ul_scheduled==0)&& - (mac_eNB_get_rrc_status(module_idP,UE_RNTI(module_idP,UE_id)) < RRC_CONNECTED))) // every Frame when not RRC_CONNECTED - { - LOG_D(MAC,"[eNB %d][PUSCH] UE %d/%x should be scheduled (BSR0 %d,SR %d)\n",module_idP,UE_id,UE_RNTI(module_idP,UE_id), - UE_template->bsr_info[LCGID0], - UE_template->ul_SR); - return(1); - } else { - return(0); - } + if ((UE_template->bsr_info[LCGID0] > 0) || (UE_template->bsr_info[LCGID1] > 0) || (UE_template->bsr_info[LCGID2] > 0) || (UE_template->bsr_info[LCGID3] > 0) || (UE_template->ul_SR > 0) || // uplink scheduling request + ((UE_sched_ctl->ul_inactivity_timer > 20) && (UE_sched_ctl->ul_scheduled == 0)) || // every 2 frames when RRC_CONNECTED + ((UE_sched_ctl->ul_inactivity_timer > 10) && (UE_sched_ctl->ul_scheduled == 0) && (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED))) // every Frame when not RRC_CONNECTED + { + LOG_D(MAC, + "[eNB %d][PUSCH] UE %d/%x should be scheduled (BSR0 %d,SR %d)\n", + module_idP, UE_id, UE_RNTI(module_idP, UE_id), + UE_template->bsr_info[LCGID0], UE_template->ul_SR); + return (1); + } else { + return (0); + } } -uint8_t get_tmode(module_id_t module_idP,int CC_idP,int UE_idP) +uint8_t get_tmode(module_id_t module_idP, int CC_idP, int UE_idP) { - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; - struct PhysicalConfigDedicated *physicalConfigDedicated = eNB->UE_list.physicalConfigDedicated[CC_idP][UE_idP]; + struct PhysicalConfigDedicated *physicalConfigDedicated = + eNB->UE_list.physicalConfigDedicated[CC_idP][UE_idP]; - if (physicalConfigDedicated == NULL ) { // RRCConnectionSetup not received by UE yet - AssertFatal(cc->p_eNB<=2,"p_eNB is %d, should be <2\n",cc->p_eNB); - return(cc->p_eNB); - } - else { - AssertFatal(physicalConfigDedicated->antennaInfo!=NULL, - "antennaInfo is null for CCId %d, UEid %d\n",CC_idP,UE_idP); + if (physicalConfigDedicated == NULL) { // RRCConnectionSetup not received by UE yet + AssertFatal(cc->p_eNB <= 2, "p_eNB is %d, should be <2\n", + cc->p_eNB); + return (cc->p_eNB); + } else { + AssertFatal(physicalConfigDedicated->antennaInfo != NULL, + "antennaInfo is null for CCId %d, UEid %d\n", CC_idP, + UE_idP); - AssertFatal(physicalConfigDedicated->antennaInfo->present != PhysicalConfigDedicated__antennaInfo_PR_NOTHING, - "antennaInfo (mod_id %d, CC_id %d) is set to NOTHING\n",module_idP,CC_idP); + AssertFatal(physicalConfigDedicated->antennaInfo->present != + PhysicalConfigDedicated__antennaInfo_PR_NOTHING, + "antennaInfo (mod_id %d, CC_id %d) is set to NOTHING\n", + module_idP, CC_idP); - if (physicalConfigDedicated->antennaInfo->present == PhysicalConfigDedicated__antennaInfo_PR_explicitValue) { - return(physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode); + if (physicalConfigDedicated->antennaInfo->present == + PhysicalConfigDedicated__antennaInfo_PR_explicitValue) { + return (physicalConfigDedicated->antennaInfo-> + choice.explicitValue.transmissionMode); + } else if (physicalConfigDedicated->antennaInfo->present == + PhysicalConfigDedicated__antennaInfo_PR_defaultValue) { + AssertFatal(cc->p_eNB <= 2, "p_eNB is %d, should be <2\n", + cc->p_eNB); + return (cc->p_eNB); + } else + AssertFatal(1 == 0, "Shouldn't be here\n"); } - else if (physicalConfigDedicated->antennaInfo->present == PhysicalConfigDedicated__antennaInfo_PR_defaultValue) { - AssertFatal(cc->p_eNB<=2,"p_eNB is %d, should be <2\n",cc->p_eNB); - return(cc->p_eNB); - } - else AssertFatal(1==0,"Shouldn't be here\n"); - } } -int8_t get_ULharq(module_id_t module_idP,int CC_idP,uint16_t frameP,uint8_t subframeP) +int8_t +get_ULharq(module_id_t module_idP, int CC_idP, uint16_t frameP, + uint8_t subframeP) { - uint8_t ret = -1; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; + uint8_t ret = -1; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; - if (cc->tdd_Config==NULL) { // FDD - ret = (((frameP<<1)+subframeP)&7); - } else { - switch (cc->tdd_Config->subframeAssignment) { - case 1: - if ((subframeP==2) || - (subframeP==3) || - (subframeP==7) || - (subframeP==8)) - switch (subframeP) { - case 2: - case 3: - ret = (subframeP-2); - break; + if (cc->tdd_Config == NULL) { // FDD + ret = (((frameP << 1) + subframeP) & 7); + } else { + switch (cc->tdd_Config->subframeAssignment) { + case 1: + if ((subframeP == 2) || + (subframeP == 3) || (subframeP == 7) || (subframeP == 8)) + switch (subframeP) { + case 2: + case 3: + ret = (subframeP - 2); + break; - case 7: - case 8: - ret = (subframeP-5); - break; + case 7: + case 8: + ret = (subframeP - 5); + break; - default: - AssertFatal(1==0,"subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframeP,(int)cc->tdd_Config->subframeAssignment); - break; - } + default: + AssertFatal(1 == 0, + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframeP, + (int) cc->tdd_Config->subframeAssignment); + break; + } - break; + break; - case 2: - AssertFatal((subframeP==2) || (subframeP==7), - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframeP,(int)cc->tdd_Config->subframeAssignment); - ret = (subframeP/7); - break; + case 2: + AssertFatal((subframeP == 2) || (subframeP == 7), + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframeP, + (int) cc->tdd_Config->subframeAssignment); + ret = (subframeP / 7); + break; - case 3: - AssertFatal((subframeP>1) && (subframeP<5), - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframeP,(int)cc->tdd_Config->subframeAssignment); - ret = (subframeP-2); - break; + case 3: + AssertFatal((subframeP > 1) && (subframeP < 5), + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframeP, + (int) cc->tdd_Config->subframeAssignment); + ret = (subframeP - 2); + break; - case 4: - AssertFatal((subframeP>1) && (subframeP<4), - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframeP,(int)cc->tdd_Config->subframeAssignment); - ret = (subframeP-2); - break; + case 4: + AssertFatal((subframeP > 1) && (subframeP < 4), + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframeP, + (int) cc->tdd_Config->subframeAssignment); + ret = (subframeP - 2); + break; - case 5: - AssertFatal(subframeP==2, - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframeP,(int)cc->tdd_Config->subframeAssignment); - ret = (subframeP-2); - break; + case 5: + AssertFatal(subframeP == 2, + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframeP, + (int) cc->tdd_Config->subframeAssignment); + ret = (subframeP - 2); + break; - default: - AssertFatal(1==0,"subframe2_harq_pid, Unsupported TDD mode %d\n",(int)cc->tdd_Config->subframeAssignment); - break; + default: + AssertFatal(1 == 0, + "subframe2_harq_pid, Unsupported TDD mode %d\n", + (int) cc->tdd_Config->subframeAssignment); + break; + } } - } - AssertFatal(ret!=-1, - "invalid harq_pid(%d) at SFN/SF = %d/%d\n", (int8_t)ret, frameP, subframeP); - return ret; + AssertFatal(ret != -1, + "invalid harq_pid(%d) at SFN/SF = %d/%d\n", (int8_t) ret, + frameP, subframeP); + return ret; } -uint16_t getRIV(uint16_t N_RB_DL,uint16_t RBstart,uint16_t Lcrbs) +uint16_t getRIV(uint16_t N_RB_DL, uint16_t RBstart, uint16_t Lcrbs) { - uint16_t RIV; + uint16_t RIV; - if (Lcrbs<=(1+(N_RB_DL>>1))) - RIV = (N_RB_DL*(Lcrbs-1)) + RBstart; - else - RIV = (N_RB_DL*(N_RB_DL+1-Lcrbs)) + (N_RB_DL-1-RBstart); + if (Lcrbs <= (1 + (N_RB_DL >> 1))) + RIV = (N_RB_DL * (Lcrbs - 1)) + RBstart; + else + RIV = (N_RB_DL * (N_RB_DL + 1 - Lcrbs)) + (N_RB_DL - 1 - RBstart); - return(RIV); + return (RIV); } -uint32_t allocate_prbs(int UE_id,unsigned char nb_rb, int N_RB_DL, uint32_t *rballoc) +uint32_t +allocate_prbs(int UE_id, unsigned char nb_rb, int N_RB_DL, + uint32_t * rballoc) { - int i; - uint32_t rballoc_dci=0; - unsigned char nb_rb_alloc=0; + int i; + uint32_t rballoc_dci = 0; + unsigned char nb_rb_alloc = 0; - for (i=0; i<(N_RB_DL-2); i+=2) { - if (((*rballoc>>i)&3)==0) { - *rballoc |= (3<>1)); - nb_rb_alloc+=2; + for (i = 0; i < (N_RB_DL - 2); i += 2) { + if (((*rballoc >> i) & 3) == 0) { + *rballoc |= (3 << i); + rballoc_dci |= (1 << ((12 - i) >> 1)); + nb_rb_alloc += 2; + } + + if (nb_rb_alloc == nb_rb) { + return (rballoc_dci); + } } - if (nb_rb_alloc==nb_rb) { - return(rballoc_dci); + if ((N_RB_DL & 1) == 1) { + if ((*rballoc >> (N_RB_DL - 1) & 1) == 0) { + *rballoc |= (1 << (N_RB_DL - 1)); + rballoc_dci |= 1; + } } - } - if ((N_RB_DL&1)==1) { - if ((*rballoc>>(N_RB_DL-1)&1)==0) { - *rballoc |= (1<<(N_RB_DL-1)); - rballoc_dci |= 1; - } - } - - return(rballoc_dci); + return (rballoc_dci); } int get_bw_index(module_id_t module_id, uint8_t CC_id) { - int bw_index=0; + int bw_index = 0; - int N_RB_DL = to_prb(RC.mac[module_id]->common_channels[CC_id].mib->message.dl_Bandwidth); + int N_RB_DL = + to_prb(RC.mac[module_id]->common_channels[CC_id].mib-> + message.dl_Bandwidth); - switch (N_RB_DL) { - case 6: // 1.4 MHz - bw_index=0; - break; + switch (N_RB_DL) { + case 6: // 1.4 MHz + bw_index = 0; + break; - case 25: // 5HMz - bw_index=1; - break; + case 25: // 5HMz + bw_index = 1; + break; - case 50: // 10HMz - bw_index=2; - break; + case 50: // 10HMz + bw_index = 2; + break; - case 100: // 20HMz - bw_index=3; - break; + case 100: // 20HMz + bw_index = 3; + break; - default: - bw_index=1; - LOG_W(MAC,"[eNB %d] N_RB_DL %d unknown for CC_id %d, setting bw_index to 1\n", module_id, N_RB_DL,CC_id); - break; - } + default: + bw_index = 1; + LOG_W(MAC, + "[eNB %d] N_RB_DL %d unknown for CC_id %d, setting bw_index to 1\n", + module_id, N_RB_DL, CC_id); + break; + } - return bw_index; + return bw_index; } int get_min_rb_unit(module_id_t module_id, uint8_t CC_id) { - int min_rb_unit=0; - int N_RB_DL = to_prb(RC.mac[module_id]->common_channels[CC_id].mib->message.dl_Bandwidth); + int min_rb_unit = 0; + int N_RB_DL = + to_prb(RC.mac[module_id]->common_channels[CC_id].mib-> + message.dl_Bandwidth); - switch (N_RB_DL) { - case 6: // 1.4 MHz - min_rb_unit=1; - break; + switch (N_RB_DL) { + case 6: // 1.4 MHz + min_rb_unit = 1; + break; - case 25: // 5HMz - min_rb_unit=2; - break; + case 25: // 5HMz + min_rb_unit = 2; + break; - case 50: // 10HMz - min_rb_unit=3; - break; + case 50: // 10HMz + min_rb_unit = 3; + break; - case 100: // 20HMz - min_rb_unit=4; - break; + case 100: // 20HMz + min_rb_unit = 4; + break; - default: - min_rb_unit=2; - LOG_W(MAC,"[eNB %d] N_DL_RB %d unknown for CC_id %d, setting min_rb_unit to 2\n", - module_id, N_RB_DL, CC_id); - break; - } - - return min_rb_unit; -} - -uint32_t allocate_prbs_sub(int nb_rb, int N_RB_DL, int N_RBG, uint8_t *rballoc) -{ - int check=0;//check1=0,check2=0; - uint32_t rballoc_dci=0; - //uint8_t number_of_subbands=13; - - LOG_T(MAC,"*****Check1RBALLOC****: %d%d%d%d (nb_rb %d,N_RBG %d)\n", - rballoc[3],rballoc[2],rballoc[1],rballoc[0],nb_rb,N_RBG); - - while((nb_rb >0) && (check < N_RBG)) { - //printf("rballoc[%d] %d\n",check,rballoc[check]); - if(rballoc[check] == 1) { - rballoc_dci |= (1<<((N_RBG-1)-check)); - - switch (N_RB_DL) { - case 6: - nb_rb--; - break; - - case 25: - if ((check == N_RBG-1)) { - nb_rb--; - } else { - nb_rb-=2; - } - - break; - - case 50: - if ((check == N_RBG-1)) { - nb_rb-=2; - } else { - nb_rb-=3; - } - - break; - - case 100: - nb_rb-=4; - break; - } + default: + min_rb_unit = 2; + LOG_W(MAC, + "[eNB %d] N_DL_RB %d unknown for CC_id %d, setting min_rb_unit to 2\n", + module_id, N_RB_DL, CC_id); + break; } - // printf("rb_alloc %x\n",rballoc_dci); - check = check+1; - // check1 = check1+2; - } + return min_rb_unit; +} - // rballoc_dci = (rballoc_dci)&(0x1fff); - LOG_T(MAC,"*********RBALLOC : %x\n",rballoc_dci); - // exit(-1); - return (rballoc_dci); +uint32_t +allocate_prbs_sub(int nb_rb, int N_RB_DL, int N_RBG, uint8_t * rballoc) +{ + int check = 0; //check1=0,check2=0; + uint32_t rballoc_dci = 0; + //uint8_t number_of_subbands=13; + + LOG_T(MAC, "*****Check1RBALLOC****: %d%d%d%d (nb_rb %d,N_RBG %d)\n", + rballoc[3], rballoc[2], rballoc[1], rballoc[0], nb_rb, N_RBG); + + while ((nb_rb > 0) && (check < N_RBG)) { + //printf("rballoc[%d] %d\n",check,rballoc[check]); + if (rballoc[check] == 1) { + rballoc_dci |= (1 << ((N_RBG - 1) - check)); + + switch (N_RB_DL) { + case 6: + nb_rb--; + break; + + case 25: + if ((check == N_RBG - 1)) { + nb_rb--; + } else { + nb_rb -= 2; + } + + break; + + case 50: + if ((check == N_RBG - 1)) { + nb_rb -= 2; + } else { + nb_rb -= 3; + } + + break; + + case 100: + nb_rb -= 4; + break; + } + } + // printf("rb_alloc %x\n",rballoc_dci); + check = check + 1; + // check1 = check1+2; + } + + // rballoc_dci = (rballoc_dci)&(0x1fff); + LOG_T(MAC, "*********RBALLOC : %x\n", rballoc_dci); + // exit(-1); + return (rballoc_dci); } int get_subbandsize(uint8_t dl_Bandwidth) { - uint8_t ss[6] = {6,4,4,6,8,8}; + uint8_t ss[6] = { 6, 4, 4, 6, 8, 8 }; - AssertFatal(dl_Bandwidth<6,"dl_Bandwidth %d is out of bounds\n",dl_Bandwidth); + AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth %d is out of bounds\n", + dl_Bandwidth); - return(ss[dl_Bandwidth]); + return (ss[dl_Bandwidth]); } int get_nb_subband(int N_RB_DL) { - int nb_sb=0; + int nb_sb = 0; - switch (N_RB_DL) { - case 6: - nb_sb=0; - break; + switch (N_RB_DL) { + case 6: + nb_sb = 0; + break; - case 15: - nb_sb = 4; // sb_size =4 + case 15: + nb_sb = 4; // sb_size =4 - case 25: - nb_sb = 7; // sb_size =4, 1 sb with 1PRB, 6 with 2 RBG, each has 2 PRBs - break; + case 25: + nb_sb = 7; // sb_size =4, 1 sb with 1PRB, 6 with 2 RBG, each has 2 PRBs + break; - case 50: // sb_size =6 - nb_sb = 9; - break; + case 50: // sb_size =6 + nb_sb = 9; + break; - case 75: // sb_size =8 - nb_sb = 10; - break; + case 75: // sb_size =8 + nb_sb = 10; + break; - case 100: // sb_size =8 , 1 sb with 1 RBG + 12 sb with 2RBG, each RBG has 4 PRBs - nb_sb = 13; - break; + case 100: // sb_size =8 , 1 sb with 1 RBG + 12 sb with 2RBG, each RBG has 4 PRBs + nb_sb = 13; + break; - default: - nb_sb=0; - break; - } - - return nb_sb; -} - -void init_CCE_table(int module_idP,int CC_idP) -{ - memset(RC.mac[module_idP]->CCE_table[CC_idP],0,800*sizeof(int)); -} - - -int get_nCCE_offset(int *CCE_table, - const unsigned char L, - const int nCCE, - const int common_dci, - const unsigned short rnti, - const unsigned char subframe) -{ - int search_space_free,m,nb_candidates = 0,l,i; - unsigned int Yk; - /* - printf("CCE Allocation: "); - for (i=0;i=0 ; m--) { - - search_space_free = 1; - for (l=0; lCCE_table[CC_idP], 0, 800 * sizeof(int)); +} - for (i=0; i<=subframe; i++) - Yk = (Yk*39827)%65537; - Yk = Yk % (nCCE/L); +int +get_nCCE_offset(int *CCE_table, + const unsigned char L, + const int nCCE, + const int common_dci, + const unsigned short rnti, const unsigned char subframe) +{ + int search_space_free, m, nb_candidates = 0, l, i; + unsigned int Yk; + /* + printf("CCE Allocation: "); + for (i=0;i= 0; m--) { + + search_space_free = 1; + for (l = 0; l < L; l++) { + + // printf("CCE_table[%d] %d\n",(m*L)+l,CCE_table[(m*L)+l]); + if (CCE_table[(m * L) + l] == 1) { + search_space_free = 0; + break; + } + } + + if (search_space_free == 1) { + + // printf("returning %d\n",m*L); + + for (l = 0; l < L; l++) + CCE_table[(m * L) + l] = 1; + return (m * L); + } + } + + return (-1); + + } else { // Find first available in ue specific search space + // according to procedure in Section 9.1.1 of 36.213 (v. 8.6) + // compute Yk + Yk = (unsigned int) rnti; + + for (i = 0; i <= subframe; i++) + Yk = (Yk * 39827) % 65537; + + Yk = Yk % (nCCE / L); + + switch (L) { + case 1: + case 2: + nb_candidates = 6; + break; + + case 4: + case 8: + nb_candidates = 2; + break; + + default: + DevParam(L, nCCE, rnti); + break; + } + + LOG_D(MAC, "rnti %x, Yk = %d, nCCE %d (nCCE/L %d),nb_cand %d\n", + rnti, Yk, nCCE, nCCE / L, nb_candidates); + + for (m = 0; m < nb_candidates; m++) { + search_space_free = 1; + + for (l = 0; l < L; l++) { + int cce = (((Yk + m) % (nCCE / L)) * L) + l; + if (cce >= nCCE || CCE_table[cce] == 1) { + search_space_free = 0; + break; + } + } + + if (search_space_free == 1) { + for (l = 0; l < L; l++) + CCE_table[(((Yk + m) % (nCCE / L)) * L) + l] = 1; + + return (((Yk + m) % (nCCE / L)) * L); + } + } + + return (-1); + } +} + +void +dump_CCE_table(int *CCE_table, const int nCCE, + const unsigned short rnti, const int subframe, int L) +{ + int nb_candidates = 0, i; + unsigned int Yk; + + printf("CCE 0: "); + for (i = 0; i < nCCE; i++) { + printf("%1d.", CCE_table[i]); + if ((i & 7) == 7) + printf("\n CCE %d: ", i); + } + + Yk = (unsigned int) rnti; + + for (i = 0; i <= subframe; i++) + Yk = (Yk * 39827) % 65537; + + Yk = Yk % (nCCE / L); switch (L) { case 1: case 2: - nb_candidates = 6; - break; + nb_candidates = 6; + break; case 4: case 8: - nb_candidates = 2; - break; + nb_candidates = 2; + break; default: - DevParam(L, nCCE, rnti); - break; + DevParam(L, nCCE, rnti); + break; } - LOG_D(MAC,"rnti %x, Yk = %d, nCCE %d (nCCE/L %d),nb_cand %d\n",rnti,Yk,nCCE,nCCE/L,nb_candidates); + printf("rnti %x, Yk*L = %d, nCCE %d (nCCE/L %d),nb_cand*L %d\n", rnti, + Yk * L, nCCE, nCCE / L, nb_candidates * L); +} - for (m = 0 ; m < nb_candidates ; m++) { - search_space_free = 1; +uint16_t +getnquad(COMMON_channels_t * cc, uint8_t num_pdcch_symbols, uint8_t mi) +{ + uint16_t Nreg = 0; - for (l=0; l= nCCE || CCE_table[cce] == 1) { - search_space_free = 0; - break; - } - } + AssertFatal(cc != NULL, "cc is null\n"); + AssertFatal(cc->mib != NULL, "cc->mib is null\n"); - if (search_space_free == 1) { - for (l=0; lmib->message.dl_Bandwidth); + int phich_resource = get_phich_resource_times6(cc); - return(((Yk+m)%(nCCE/L))*L); - } + uint8_t Ngroup_PHICH = (phich_resource * N_RB_DL) / 48; + + if (((phich_resource * N_RB_DL) % 48) > 0) + Ngroup_PHICH++; + + if (cc->Ncp == 1) { + Ngroup_PHICH <<= 1; } - return(-1); - } + Ngroup_PHICH *= mi; + + if ((num_pdcch_symbols > 0) && (num_pdcch_symbols < 4)) + switch (N_RB_DL) { + case 6: + Nreg = 12 + (num_pdcch_symbols - 1) * 18; + break; + + case 25: + Nreg = 50 + (num_pdcch_symbols - 1) * 75; + break; + + case 50: + Nreg = 100 + (num_pdcch_symbols - 1) * 150; + break; + + case 100: + Nreg = 200 + (num_pdcch_symbols - 1) * 300; + break; + + default: + return (0); + } + // printf("Nreg %d (%d)\n",Nreg,Nreg - 4 - (3*Ngroup_PHICH)); + return (Nreg - 4 - (3 * Ngroup_PHICH)); } -void dump_CCE_table(int *CCE_table,const int nCCE,const unsigned short rnti,const int subframe,int L) +uint16_t +getnCCE(COMMON_channels_t * cc, uint8_t num_pdcch_symbols, uint8_t mi) { - int nb_candidates = 0,i; - unsigned int Yk; - - printf("CCE 0: "); - for (i=0;imib!=NULL,"cc->mib is null\n"); + // for FDD + if (cc->tdd_Config == NULL) // FDD + return 1; - int N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); - int phich_resource = get_phich_resource_times6(cc); + // for TDD + switch (cc->tdd_Config->subframeAssignment) { + case 0: + if ((subframe == 0) || (subframe == 5)) + return (2); + else + return (1); - uint8_t Ngroup_PHICH = (phich_resource*N_RB_DL)/48; + break; - if (((phich_resource*N_RB_DL)%48) > 0) - Ngroup_PHICH++; + case 1: + if ((subframe == 0) || (subframe == 5)) + return (0); + else + return (1); - if (cc->Ncp == 1) { - Ngroup_PHICH<<=1; - } + break; - Ngroup_PHICH*=mi; + case 2: + if ((subframe == 3) || (subframe == 8)) + return (1); + else + return (0); + + break; + + case 3: + if ((subframe == 0) || (subframe == 8) || (subframe == 9)) + return (1); + else + return (0); + + break; + + case 4: + if ((subframe == 8) || (subframe == 9)) + return (1); + else + return (0); + + break; + + case 5: + if (subframe == 8) + return (1); + else + return (0); + + break; - if ((num_pdcch_symbols>0) && (num_pdcch_symbols<4)) - switch (N_RB_DL) { case 6: - Nreg=12+(num_pdcch_symbols-1)*18; - break; - - case 25: - Nreg=50+(num_pdcch_symbols-1)*75; - break; - - case 50: - Nreg=100+(num_pdcch_symbols-1)*150; - break; - - case 100: - Nreg=200+(num_pdcch_symbols-1)*300; - break; + return (1); + break; default: - return(0); + return (0); } - - // printf("Nreg %d (%d)\n",Nreg,Nreg - 4 - (3*Ngroup_PHICH)); - return(Nreg - 4 - (3*Ngroup_PHICH)); } -uint16_t getnCCE(COMMON_channels_t *cc, uint8_t num_pdcch_symbols, uint8_t mi) +uint16_t +get_nCCE_max(COMMON_channels_t * cc, int num_pdcch_symbols, int subframe) { - AssertFatal(cc!=NULL,"cc is null\n"); - return(getnquad(cc,num_pdcch_symbols,mi)/9); -} - -uint8_t getmi(COMMON_channels_t *cc,int subframe) -{ - AssertFatal(cc!=NULL,"cc is null\n"); - - // for FDD - if (cc->tdd_Config==NULL) // FDD - return 1; - - // for TDD - switch (cc->tdd_Config->subframeAssignment) { - case 0: - if ((subframe==0) || (subframe==5)) - return(2); - else return(1); - - break; - - case 1: - if ((subframe==0) || (subframe==5)) - return(0); - else return(1); - - break; - - case 2: - if ((subframe==3) || (subframe==8)) - return(1); - else return(0); - - break; - - case 3: - if ((subframe==0) || (subframe==8) || (subframe==9)) - return(1); - else return(0); - - break; - - case 4: - if ((subframe==8) || (subframe==9)) - return(1); - else return(0); - - break; - - case 5: - if (subframe==8) - return(1); - else return(0); - - break; - - case 6: - return(1); - break; - - default: - return(0); - } -} - -uint16_t get_nCCE_max(COMMON_channels_t *cc, int num_pdcch_symbols,int subframe) -{ - AssertFatal(cc!=NULL,"cc is null\n"); - return(getnCCE(cc,num_pdcch_symbols, - getmi(cc,subframe))); + AssertFatal(cc != NULL, "cc is null\n"); + return (getnCCE(cc, num_pdcch_symbols, getmi(cc, subframe))); } // Allocate the CCEs -int allocate_CCEs(int module_idP, - int CC_idP, - int subframeP, - int test_onlyP) +int +allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) { - int *CCE_table = RC.mac[module_idP]->CCE_table[CC_idP]; - nfapi_dl_config_request_body_t *DL_req = &RC.mac[module_idP]->DL_req[CC_idP].dl_config_request_body; - nfapi_hi_dci0_request_body_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; - nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req->dl_config_pdu_list[0]; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[0]; - int nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],1,subframeP); - int fCCE; - int i,j,idci; - int nCCE=0; + int *CCE_table = RC.mac[module_idP]->CCE_table[CC_idP]; + nfapi_dl_config_request_body_t *DL_req = + &RC.mac[module_idP]->DL_req[CC_idP].dl_config_request_body; + nfapi_hi_dci0_request_body_t *HI_DCI0_req = + &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; + nfapi_dl_config_request_pdu_t *dl_config_pdu = + &DL_req->dl_config_pdu_list[0]; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = + &HI_DCI0_req->hi_dci0_pdu_list[0]; + int nCCE_max = + get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP], 1, + subframeP); + int fCCE; + int i, j, idci; + int nCCE = 0; - LOG_D(MAC,"Allocate CCEs subframe %d, test %d : (DL PDU %d, DL DCI %d, UL %d)\n",subframeP,test_onlyP,DL_req->number_pdu,DL_req->number_dci,HI_DCI0_req->number_of_dci); - DL_req->number_pdcch_ofdm_symbols=1; + LOG_D(MAC, + "Allocate CCEs subframe %d, test %d : (DL PDU %d, DL DCI %d, UL %d)\n", + subframeP, test_onlyP, DL_req->number_pdu, DL_req->number_dci, + HI_DCI0_req->number_of_dci); + DL_req->number_pdcch_ofdm_symbols = 1; -try_again: - init_CCE_table(module_idP,CC_idP); - nCCE=0; + try_again: + init_CCE_table(module_idP, CC_idP); + nCCE = 0; - for (i=0,idci=0;inumber_pdu;i++) { - // allocate DL common DCIs first - if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)&& - (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type==2) - ) { - LOG_D(MAC,"Trying to allocate COMMON DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", - idci,DL_req->number_dci+HI_DCI0_req->number_of_dci, - DL_req->number_dci,HI_DCI0_req->number_of_dci, - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti, - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, - nCCE,nCCE_max, DL_req->number_pdcch_ofdm_symbols); + for (i = 0, idci = 0; i < DL_req->number_pdu; i++) { + // allocate DL common DCIs first + if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) + && (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type == + 2)) { + LOG_D(MAC, + "Trying to allocate COMMON DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", + idci, DL_req->number_dci + HI_DCI0_req->number_of_dci, + DL_req->number_dci, HI_DCI0_req->number_of_dci, + dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti, + dl_config_pdu[i].dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level, nCCE, nCCE_max, + DL_req->number_pdcch_ofdm_symbols); - if (nCCE + (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level) > nCCE_max) { - if (DL_req->number_pdcch_ofdm_symbols == 3) - goto failed; - LOG_D(MAC,"Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n",DL_req->number_pdcch_ofdm_symbols); - DL_req->number_pdcch_ofdm_symbols++; - nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],DL_req->number_pdcch_ofdm_symbols,subframeP); - goto try_again; - } + if (nCCE + + (dl_config_pdu[i].dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level) > nCCE_max) { + if (DL_req->number_pdcch_ofdm_symbols == 3) + goto failed; + LOG_D(MAC, + "Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n", + DL_req->number_pdcch_ofdm_symbols); + DL_req->number_pdcch_ofdm_symbols++; + nCCE_max = + get_nCCE_max(&RC.mac[module_idP]-> + common_channels[CC_idP], + DL_req->number_pdcch_ofdm_symbols, + subframeP); + goto try_again; + } + // number of CCEs left can potentially hold this allocation + fCCE = get_nCCE_offset(CCE_table, + dl_config_pdu[i]. + dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level, nCCE_max, 1, + dl_config_pdu[i]. + dci_dl_pdu.dci_dl_pdu_rel8.rnti, + subframeP); + if (fCCE == -1) { + if (DL_req->number_pdcch_ofdm_symbols == 3) { + LOG_D(MAC, + "subframe %d: Dropping Allocation for RNTI %x\n", + subframeP, + dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8. + rnti); + for (j = 0; j <= i; j++) { + if (dl_config_pdu[j].pdu_type == + NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) + LOG_D(MAC, + "DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", + j, + DL_req->number_dci + + HI_DCI0_req->number_of_dci, + DL_req->number_dci, + HI_DCI0_req->number_of_dci, + dl_config_pdu[j]. + dci_dl_pdu.dci_dl_pdu_rel8.rnti, + dl_config_pdu[j]. + dci_dl_pdu.dci_dl_pdu_rel8.dci_format, + dl_config_pdu[j]. + dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level, nCCE, nCCE_max, + DL_req->number_pdcch_ofdm_symbols); + } + //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<L); + goto failed; + } + LOG_D(MAC, + "Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n", + DL_req->number_pdcch_ofdm_symbols); - // number of CCEs left can potentially hold this allocation - fCCE = get_nCCE_offset(CCE_table, - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, - nCCE_max, - 1, - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti, - subframeP); - if (fCCE == -1) { - if (DL_req->number_pdcch_ofdm_symbols == 3) { - LOG_D(MAC,"subframe %d: Dropping Allocation for RNTI %x\n", - subframeP,dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti); - for (j=0;j<=i;j++){ - if (dl_config_pdu[j].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) - LOG_D(MAC,"DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", - j,DL_req->number_dci+HI_DCI0_req->number_of_dci, - DL_req->number_dci,HI_DCI0_req->number_of_dci, - dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.rnti, - dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.dci_format, - dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, - nCCE,nCCE_max,DL_req->number_pdcch_ofdm_symbols); - } - //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<L); - goto failed; - } - LOG_D(MAC,"Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n",DL_req->number_pdcch_ofdm_symbols); + DL_req->number_pdcch_ofdm_symbols++; + nCCE_max = + get_nCCE_max(&RC.mac[module_idP]-> + common_channels[CC_idP], + DL_req->number_pdcch_ofdm_symbols, + subframeP); + goto try_again; + } // fCCE==-1 - DL_req->number_pdcch_ofdm_symbols++; - nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],DL_req->number_pdcch_ofdm_symbols,subframeP); - goto try_again; - } // fCCE==-1 + // the allocation is feasible, rnti rule passes + nCCE += + dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level; + LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); + if (test_onlyP == 0) { + dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = fCCE; + LOG_D(MAC, + "Allocate COMMON DCI CCEs subframe %d, test %d => L %d fCCE %d\n", + subframeP, test_onlyP, + dl_config_pdu[i].dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level, fCCE); + } + idci++; + } + } // for i = 0 ... num_DL_DCIs - // the allocation is feasible, rnti rule passes - nCCE += dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level; - LOG_D(MAC,"Allocating at nCCE %d\n",fCCE); - if (test_onlyP == 0) { - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx=fCCE; - LOG_D(MAC,"Allocate COMMON DCI CCEs subframe %d, test %d => L %d fCCE %d\n",subframeP,test_onlyP,dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,fCCE); - } - idci++; - } - } // for i = 0 ... num_DL_DCIs + // no try to allocate UL DCIs + for (i = 0; i < HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi; + i++) { - // no try to allocate UL DCIs - for (i=0;inumber_of_dci+HI_DCI0_req->number_of_hi;i++) { + // allocate UL DCIs + if (hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) { - // allocate UL DCIs - if (hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) { + LOG_D(MAC, + "Trying to allocate format 0 DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", + idci, DL_req->number_dci + HI_DCI0_req->number_of_dci, + DL_req->number_dci, HI_DCI0_req->number_of_dci, + hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti, + hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level, + nCCE, nCCE_max, DL_req->number_pdcch_ofdm_symbols); - LOG_D(MAC,"Trying to allocate format 0 DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", - idci,DL_req->number_dci+HI_DCI0_req->number_of_dci, - DL_req->number_dci,HI_DCI0_req->number_of_dci, - hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti,hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level, - nCCE,nCCE_max, DL_req->number_pdcch_ofdm_symbols); + if (nCCE + + (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level) > + nCCE_max) { + if (DL_req->number_pdcch_ofdm_symbols == 3) + goto failed; + LOG_D(MAC, + "Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n", + DL_req->number_pdcch_ofdm_symbols); - if (nCCE + (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level) > nCCE_max) { - if (DL_req->number_pdcch_ofdm_symbols == 3) - goto failed; - LOG_D(MAC,"Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n",DL_req->number_pdcch_ofdm_symbols); + DL_req->number_pdcch_ofdm_symbols++; + nCCE_max = + get_nCCE_max(&RC.mac[module_idP]-> + common_channels[CC_idP], + DL_req->number_pdcch_ofdm_symbols, + subframeP); + goto try_again; + } + // number of CCEs left can potentially hold this allocation + fCCE = get_nCCE_offset(CCE_table, + hi_dci0_pdu[i].dci_pdu. + dci_pdu_rel8.aggregation_level, + nCCE_max, 0, + hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8. + rnti, subframeP); + if (fCCE == -1) { + if (DL_req->number_pdcch_ofdm_symbols == 3) { + LOG_D(MAC, + "subframe %d: Dropping Allocation for RNTI %x\n", + subframeP, + hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti); + for (j = 0; j <= i; j++) { + if (hi_dci0_pdu[j].pdu_type == + NFAPI_HI_DCI0_DCI_PDU_TYPE) + LOG_D(MAC, + "DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", + j, + DL_req->number_dci + + HI_DCI0_req->number_of_dci, + DL_req->number_dci, + HI_DCI0_req->number_of_dci, + hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8.rnti, + hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8. + dci_format, + hi_dci0_pdu[j].dci_pdu. + dci_pdu_rel8.aggregation_level, nCCE, + nCCE_max, + DL_req->number_pdcch_ofdm_symbols); + } + //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<L); + goto failed; + } + LOG_D(MAC, + "Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n", + DL_req->number_pdcch_ofdm_symbols); - DL_req->number_pdcch_ofdm_symbols++; - nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],DL_req->number_pdcch_ofdm_symbols,subframeP); - goto try_again; - } + DL_req->number_pdcch_ofdm_symbols++; + nCCE_max = + get_nCCE_max(&RC.mac[module_idP]-> + common_channels[CC_idP], + DL_req->number_pdcch_ofdm_symbols, + subframeP); + goto try_again; + } // fCCE==-1 - // number of CCEs left can potentially hold this allocation - fCCE = get_nCCE_offset(CCE_table, - hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level, - nCCE_max, - 0, - hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti, - subframeP); - if (fCCE == -1) { - if (DL_req->number_pdcch_ofdm_symbols == 3) { - LOG_D(MAC,"subframe %d: Dropping Allocation for RNTI %x\n", - subframeP,hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti); - for (j=0;j<=i;j++){ - if (hi_dci0_pdu[j].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) - LOG_D(MAC,"DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", - j,DL_req->number_dci+HI_DCI0_req->number_of_dci, - DL_req->number_dci,HI_DCI0_req->number_of_dci, - hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8.rnti, - hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8.dci_format, - hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8.aggregation_level, - nCCE,nCCE_max,DL_req->number_pdcch_ofdm_symbols); - } - //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<L); - goto failed; - } - LOG_D(MAC,"Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n",DL_req->number_pdcch_ofdm_symbols); + // the allocation is feasible, rnti rule passes + nCCE += hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level; + LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); + if (test_onlyP == 0) { + hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.cce_index = fCCE; + LOG_D(MAC, "Allocate CCEs subframe %d, test %d\n", + subframeP, test_onlyP); + } + idci++; + } + } // for i = 0 ... num_UL_DCIs - DL_req->number_pdcch_ofdm_symbols++; - nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],DL_req->number_pdcch_ofdm_symbols,subframeP); - goto try_again; - } // fCCE==-1 + for (i = 0; i < DL_req->number_pdu; i++) { + // allocate DL UE specific DCIs + if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) + && (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type == + 1)) { + LOG_D(MAC, + "Trying to allocate DL UE-SPECIFIC DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", + idci, DL_req->number_dci + HI_DCI0_req->number_of_dci, + DL_req->number_dci, HI_DCI0_req->number_of_dci, + dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti, + dl_config_pdu[i].dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level, nCCE, nCCE_max, + DL_req->number_pdcch_ofdm_symbols); - // the allocation is feasible, rnti rule passes - nCCE += hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level; - LOG_D(MAC,"Allocating at nCCE %d\n",fCCE); - if (test_onlyP == 0) { - hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.cce_index=fCCE; - LOG_D(MAC,"Allocate CCEs subframe %d, test %d\n",subframeP,test_onlyP); - } - idci++; - } - } // for i = 0 ... num_UL_DCIs + if (nCCE + + (dl_config_pdu[i].dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level) > nCCE_max) { + if (DL_req->number_pdcch_ofdm_symbols == 3) + goto failed; + LOG_D(MAC, + "Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n", + DL_req->number_pdcch_ofdm_symbols); - for (i=0;inumber_pdu;i++) { - // allocate DL UE specific DCIs - if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)&& - (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type==1)) { - LOG_D(MAC,"Trying to allocate DL UE-SPECIFIC DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", - idci,DL_req->number_dci+HI_DCI0_req->number_of_dci, - DL_req->number_dci,HI_DCI0_req->number_of_dci, - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti,dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, - nCCE,nCCE_max, DL_req->number_pdcch_ofdm_symbols); + DL_req->number_pdcch_ofdm_symbols++; + nCCE_max = + get_nCCE_max(&RC.mac[module_idP]-> + common_channels[CC_idP], + DL_req->number_pdcch_ofdm_symbols, + subframeP); + goto try_again; + } + // number of CCEs left can potentially hold this allocation + fCCE = get_nCCE_offset(CCE_table, + dl_config_pdu[i]. + dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level, nCCE_max, 0, + dl_config_pdu[i]. + dci_dl_pdu.dci_dl_pdu_rel8.rnti, + subframeP); + if (fCCE == -1) { + if (DL_req->number_pdcch_ofdm_symbols == 3) { + LOG_I(MAC, + "subframe %d: Dropping Allocation for RNTI %x\n", + subframeP, + dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8. + rnti); + for (j = 0; j <= i; j++) { + if (dl_config_pdu[j].pdu_type == + NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) + LOG_I(MAC, + "DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", + j, + DL_req->number_dci + + HI_DCI0_req->number_of_dci, + DL_req->number_dci, + HI_DCI0_req->number_of_dci, + dl_config_pdu[j]. + dci_dl_pdu.dci_dl_pdu_rel8.rnti, + dl_config_pdu[j]. + dci_dl_pdu.dci_dl_pdu_rel8.dci_format, + dl_config_pdu[j]. + dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level, nCCE, nCCE_max, + DL_req->number_pdcch_ofdm_symbols); + } + //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<L); + goto failed; + } + LOG_D(MAC, + "Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n", + DL_req->number_pdcch_ofdm_symbols); - if (nCCE + (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level) > nCCE_max) { - if (DL_req->number_pdcch_ofdm_symbols == 3) - goto failed; - LOG_D(MAC,"Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n",DL_req->number_pdcch_ofdm_symbols); + DL_req->number_pdcch_ofdm_symbols++; + nCCE_max = + get_nCCE_max(&RC.mac[module_idP]-> + common_channels[CC_idP], + DL_req->number_pdcch_ofdm_symbols, + subframeP); + goto try_again; + } // fCCE==-1 - DL_req->number_pdcch_ofdm_symbols++; - nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],DL_req->number_pdcch_ofdm_symbols,subframeP); - goto try_again; - } + // the allocation is feasible, rnti rule passes + nCCE += + dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level; + LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); + if (test_onlyP == 0) { + dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = fCCE; + LOG_D(MAC, "Allocate CCEs subframe %d, test %d\n", + subframeP, test_onlyP); + } + idci++; + } + } // for i = 0 ... num_DL_DCIs - // number of CCEs left can potentially hold this allocation - fCCE = get_nCCE_offset(CCE_table, - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, - nCCE_max, - 0, - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti, - subframeP); - if (fCCE == -1) { - if (DL_req->number_pdcch_ofdm_symbols == 3) { - LOG_I(MAC,"subframe %d: Dropping Allocation for RNTI %x\n", - subframeP,dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti); - for (j=0;j<=i;j++){ - if (dl_config_pdu[j].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) - LOG_I(MAC,"DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", - j,DL_req->number_dci+HI_DCI0_req->number_of_dci, - DL_req->number_dci,HI_DCI0_req->number_of_dci, - dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.rnti, - dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.dci_format, - dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, - nCCE,nCCE_max,DL_req->number_pdcch_ofdm_symbols); - } - //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<L); - goto failed; - } - LOG_D(MAC,"Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n",DL_req->number_pdcch_ofdm_symbols); + return 0; - DL_req->number_pdcch_ofdm_symbols++; - nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],DL_req->number_pdcch_ofdm_symbols,subframeP); - goto try_again; - } // fCCE==-1 - - // the allocation is feasible, rnti rule passes - nCCE += dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level; - LOG_D(MAC,"Allocating at nCCE %d\n",fCCE); - if (test_onlyP == 0) { - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx=fCCE; - LOG_D(MAC,"Allocate CCEs subframe %d, test %d\n",subframeP,test_onlyP); - } - idci++; - } - } // for i = 0 ... num_DL_DCIs - - return 0; - -failed: - return -1; + failed: + return -1; } /* @@ -2917,750 +3409,1046 @@ uint8_t get_ul_req_index(module_id_t module_idP, int CC_idP, sub_frame_t subfram } */ -nfapi_ul_config_request_pdu_t* has_ul_grant(module_id_t module_idP,int CC_idP,uint16_t absSFP,uint16_t rnti) +nfapi_ul_config_request_pdu_t *has_ul_grant(module_id_t module_idP, + int CC_idP, uint16_t absSFP, + uint16_t rnti) { - nfapi_ul_config_request_body_t *ul_req; - nfapi_ul_config_request_pdu_t *ul_config_pdu; + nfapi_ul_config_request_body_t *ul_req; + nfapi_ul_config_request_pdu_t *ul_config_pdu; - ul_req = &RC.mac[module_idP]->UL_req_tmp[CC_idP][absSFP%10].ul_config_request_body; - ul_config_pdu = &ul_req->ul_config_pdu_list[0]; - LOG_D(MAC,"Checking for rnti %x UL grant in subframeP %d (num pdu %d)\n",rnti,absSFP%10,ul_req->number_of_pdus); + ul_req = + &RC.mac[module_idP]->UL_req_tmp[CC_idP][absSFP % + 10].ul_config_request_body; + ul_config_pdu = &ul_req->ul_config_pdu_list[0]; + LOG_D(MAC, + "Checking for rnti %x UL grant in subframeP %d (num pdu %d)\n", + rnti, absSFP % 10, ul_req->number_of_pdus); - for (int i=0; inumber_of_pdus;i++){ - LOG_D(MAC,"PDU %d : type %d,rnti %x\n",i,ul_config_pdu[i].pdu_type,rnti); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE)&& - (ul_config_pdu[i].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) return(&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE)&& - (ul_config_pdu[i].ulsch_cqi_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) return(&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE)&& - (ul_config_pdu[i].ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) return(&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE)&& - (ul_config_pdu[i].ulsch_cqi_harq_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) return(&ul_config_pdu[i]); + for (int i = 0; i < ul_req->number_of_pdus; i++) { + LOG_D(MAC, "PDU %d : type %d,rnti %x\n", i, + ul_config_pdu[i].pdu_type, rnti); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) + && (ul_config_pdu[i].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == + NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) + && (ul_config_pdu[i].ulsch_cqi_ri_pdu.ulsch_pdu. + ulsch_pdu_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == + NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE) + && (ul_config_pdu[i].ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8. + rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == + NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE) + && (ul_config_pdu[i].ulsch_cqi_harq_ri_pdu. + ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE)&& - (ul_config_pdu[i].uci_cqi_pdu.ue_information.ue_information_rel8.rnti == rnti)) return(&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE)&& - (ul_config_pdu[i].uci_sr_pdu.ue_information.ue_information_rel8.rnti == rnti)) return(&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE)&& - (ul_config_pdu[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)) return(&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE)&& - (ul_config_pdu[i].uci_sr_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)) return(&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE)&& - (ul_config_pdu[i].uci_cqi_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)) return(&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE)&& - (ul_config_pdu[i].uci_cqi_sr_pdu.ue_information.ue_information_rel8.rnti == rnti)) return(&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE) && - (ul_config_pdu[i].uci_cqi_sr_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)) return(&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE) + && (ul_config_pdu[i].uci_cqi_pdu. + ue_information.ue_information_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE) + && (ul_config_pdu[i].uci_sr_pdu. + ue_information.ue_information_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == + NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) + && (ul_config_pdu[i].uci_harq_pdu. + ue_information.ue_information_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == + NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE) + && (ul_config_pdu[i].uci_sr_harq_pdu. + ue_information.ue_information_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == + NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE) + && (ul_config_pdu[i].uci_cqi_harq_pdu. + ue_information.ue_information_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == + NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE) + && (ul_config_pdu[i].uci_cqi_sr_pdu. + ue_information.ue_information_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == + NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE) + && (ul_config_pdu[i].uci_cqi_sr_harq_pdu. + ue_information.ue_information_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE)&& - (ul_config_pdu[i].ulsch_uci_csi_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) return(&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE)&& - (ul_config_pdu[i].ulsch_uci_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) return(&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE)&& - (ul_config_pdu[i].ulsch_csi_uci_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) return(&ul_config_pdu[i]); - } + if ((ul_config_pdu[i].pdu_type == + NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE) + && (ul_config_pdu[i].ulsch_uci_csi_pdu. + ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == + NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE) + && (ul_config_pdu[i].ulsch_uci_harq_pdu. + ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == + NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE) + && (ul_config_pdu[i].ulsch_csi_uci_harq_pdu. + ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + } - return(NULL); // no ul grant at all for this UE + return (NULL); // no ul grant at all for this UE } -boolean_t CCE_allocation_infeasible(int module_idP, - int CC_idP, - int format_flag, - int subframe, - int aggregation, - int rnti) +boolean_t +CCE_allocation_infeasible(int module_idP, + int CC_idP, + int format_flag, + int subframe, int aggregation, int rnti) { - nfapi_dl_config_request_body_t *DL_req = &RC.mac[module_idP]->DL_req[CC_idP].dl_config_request_body; - nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req->dl_config_pdu_list[DL_req->number_pdu]; - nfapi_hi_dci0_request_body_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[HI_DCI0_req->number_of_dci+HI_DCI0_req->number_of_hi]; - int ret; - boolean_t res = FALSE; + nfapi_dl_config_request_body_t *DL_req = + &RC.mac[module_idP]->DL_req[CC_idP].dl_config_request_body; + nfapi_dl_config_request_pdu_t *dl_config_pdu = + &DL_req->dl_config_pdu_list[DL_req->number_pdu]; + nfapi_hi_dci0_request_body_t *HI_DCI0_req = + &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = + &HI_DCI0_req->hi_dci0_pdu_list[HI_DCI0_req->number_of_dci + + HI_DCI0_req->number_of_hi]; + int ret; + boolean_t res = FALSE; - if (format_flag != 2) { // DL DCI - if (DL_req->number_pdu == MAX_NUM_DL_PDU) { - LOG_W(MAC, "Subframe %d: FAPI DL structure is full, skip scheduling UE %d\n", - subframe, rnti); - } else { - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = (format_flag == 0)?2:1; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = aggregation; - DL_req->number_pdu++; - LOG_D(MAC,"Subframe %d: Checking CCE feasibility format %d : (%x,%d) (%x,%d,%d)\n", - subframe,format_flag,rnti,aggregation, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type); - ret = allocate_CCEs(module_idP,CC_idP,subframe,0); - if (ret==-1) - res = TRUE; - DL_req->number_pdu--; + if (format_flag != 2) { // DL DCI + if (DL_req->number_pdu == MAX_NUM_DL_PDU) { + LOG_W(MAC, + "Subframe %d: FAPI DL structure is full, skip scheduling UE %d\n", + subframe, rnti); + } else { + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = + (format_flag == 0) ? 2 : 1; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = + aggregation; + DL_req->number_pdu++; + LOG_D(MAC, + "Subframe %d: Checking CCE feasibility format %d : (%x,%d) (%x,%d,%d)\n", + subframe, format_flag, rnti, aggregation, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type); + ret = allocate_CCEs(module_idP, CC_idP, subframe, 0); + if (ret == -1) + res = TRUE; + DL_req->number_pdu--; + } + } else { // ue-specific UL DCI + if (HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi == + MAX_NUM_HI_DCI0_PDU) { + LOG_W(MAC, + "Subframe %d: FAPI UL structure is full, skip scheduling UE %d\n", + subframe, rnti); + } else { + hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti = rnti; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level = + aggregation; + HI_DCI0_req->number_of_dci++; + ret = allocate_CCEs(module_idP, CC_idP, subframe, 0); + if (ret == -1) + res = TRUE; + HI_DCI0_req->number_of_dci--; + } } - } - else { // ue-specific UL DCI - if (HI_DCI0_req->number_of_dci+HI_DCI0_req->number_of_hi == MAX_NUM_HI_DCI0_PDU) { - LOG_W(MAC, "Subframe %d: FAPI UL structure is full, skip scheduling UE %d\n", - subframe, rnti); - } else { - hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti = rnti; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level = aggregation; - HI_DCI0_req->number_of_dci++; - ret = allocate_CCEs(module_idP,CC_idP,subframe,0); - if (ret==-1) - res = TRUE; - HI_DCI0_req->number_of_dci--; - } - } - return res; + return res; } -void extract_harq(module_id_t mod_idP,int CC_idP,int UE_id,frame_t frameP,sub_frame_t subframeP,void *harq_indication,int format) +void +extract_harq(module_id_t mod_idP, int CC_idP, int UE_id, + frame_t frameP, sub_frame_t subframeP, + void *harq_indication, int format) { - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - rnti_t rnti = UE_RNTI(mod_idP,UE_id); - COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; - nfapi_harq_indication_fdd_rel13_t *harq_indication_fdd; - nfapi_harq_indication_tdd_rel13_t *harq_indication_tdd; - uint16_t num_ack_nak; - int numCC = UE_list->numactiveCCs[UE_id]; - int pCCid = UE_list->pCC_id[UE_id]; - int spatial_bundling = 0; - int tmode[5]; - int i,j; - uint8_t *pdu; + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + rnti_t rnti = UE_RNTI(mod_idP, UE_id); + COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; + nfapi_harq_indication_fdd_rel13_t *harq_indication_fdd; + nfapi_harq_indication_tdd_rel13_t *harq_indication_tdd; + uint16_t num_ack_nak; + int numCC = UE_list->numactiveCCs[UE_id]; + int pCCid = UE_list->pCC_id[UE_id]; + int spatial_bundling = 0; + int tmode[5]; + int i, j; + uint8_t *pdu; #ifdef Rel14 - AssertFatal(UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->pucch_ConfigDedicated!=NULL,"pucch_ConfigDedicated is null!\n"); - if ((UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7) && - (UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13) && - (((UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13->spatialBundlingPUCCH_r13) && - (format==0)) || - ((UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13->spatialBundlingPUSCH_r13) && - (format==1)))) - spatial_bundling = 1; + AssertFatal(UE_list-> + UE_template[pCCid][UE_id].physicalConfigDedicated-> + pucch_ConfigDedicated != NULL, + "pucch_ConfigDedicated is null!\n"); + if ((UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7) + && (UE_list->UE_template[pCCid][UE_id]. + physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13) + && + (((UE_list->UE_template[pCCid][UE_id]. + physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13-> + spatialBundlingPUCCH_r13) + && (format == 0)) + || + ((UE_list->UE_template[pCCid][UE_id]. + physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13-> + spatialBundlingPUSCH_r13) + && (format == 1)))) + spatial_bundling = 1; #endif - for (i=0;itdd_Config) { - harq_indication_tdd = (nfapi_harq_indication_tdd_rel13_t *)harq_indication; - // pdu = &harq_indication_tdd->harq_tb_n[0]; + if (cc->tdd_Config) { + harq_indication_tdd = + (nfapi_harq_indication_tdd_rel13_t *) harq_indication; + // pdu = &harq_indication_tdd->harq_tb_n[0]; - num_ack_nak = harq_indication_tdd->number_of_ack_nack; + num_ack_nak = harq_indication_tdd->number_of_ack_nack; - switch (harq_indication_tdd->mode) { - case 0: // Format 1a/b - AssertFatal(numCC==1,"numCC %d > 1, should not be using Format1a/b\n",numCC); - break; - case 1: // Channel Selection - break; - case 2: // Format 3 - break; - case 3: // Format 4 - break; - case 4: // Format 5 - break; - } - } - else { - harq_indication_fdd = (nfapi_harq_indication_fdd_rel13_t *)harq_indication; - num_ack_nak = harq_indication_fdd->number_of_ack_nack; - pdu = &harq_indication_fdd->harq_tb_n[0]; + switch (harq_indication_tdd->mode) { + case 0: // Format 1a/b + AssertFatal(numCC == 1, + "numCC %d > 1, should not be using Format1a/b\n", + numCC); + break; + case 1: // Channel Selection + break; + case 2: // Format 3 + break; + case 3: // Format 4 + break; + case 4: // Format 5 + break; + } + } else { + harq_indication_fdd = + (nfapi_harq_indication_fdd_rel13_t *) harq_indication; + num_ack_nak = harq_indication_fdd->number_of_ack_nack; + pdu = &harq_indication_fdd->harq_tb_n[0]; - uint8_t harq_pid = ((10*frameP) + subframeP + 10236)&7; + uint8_t harq_pid = ((10 * frameP) + subframeP + 10236) & 7; - switch (harq_indication_fdd->mode) { - case 0: // Format 1a/b (10.1.2.1) - AssertFatal(numCC==1,"numCC %d > 1, should not be using Format1a/b\n",numCC); - if (tmode[0]==1 || tmode[0]==2 || tmode[0]==5 || tmode[0]==6 || tmode[0]==7) { // NOTE: have to handle the case of TM9-10 with 1 antenna port - // single ACK/NAK bit - AssertFatal(num_ack_nak==1,"num_ack_nak %d > 1 for 1 CC and single-layer transmission\n",num_ack_nak); - AssertFatal(sched_ctl->round[CC_idP][harq_pid]<8,"Got ACK/NAK for inactive harq_pid %d for UE %d/%x\n",harq_pid,UE_id,rnti); - AssertFatal(pdu[0] == 1 || pdu[0] == 2 || pdu[0] == 4, - "Received ACK/NAK %d which is not 1 or 2 for harq_pid %d from UE %d/%x\n",pdu[0],harq_pid,UE_id,rnti); - LOG_D(MAC,"Received %d for harq_pid %d\n",pdu[0],harq_pid); + switch (harq_indication_fdd->mode) { + case 0: // Format 1a/b (10.1.2.1) + AssertFatal(numCC == 1, + "numCC %d > 1, should not be using Format1a/b\n", + numCC); + if (tmode[0] == 1 || tmode[0] == 2 || tmode[0] == 5 || tmode[0] == 6 || tmode[0] == 7) { // NOTE: have to handle the case of TM9-10 with 1 antenna port + // single ACK/NAK bit + AssertFatal(num_ack_nak == 1, + "num_ack_nak %d > 1 for 1 CC and single-layer transmission\n", + num_ack_nak); + AssertFatal(sched_ctl->round[CC_idP][harq_pid] < 8, + "Got ACK/NAK for inactive harq_pid %d for UE %d/%x\n", + harq_pid, UE_id, rnti); + AssertFatal(pdu[0] == 1 || pdu[0] == 2 + || pdu[0] == 4, + "Received ACK/NAK %d which is not 1 or 2 for harq_pid %d from UE %d/%x\n", + pdu[0], harq_pid, UE_id, rnti); + LOG_D(MAC, "Received %d for harq_pid %d\n", pdu[0], + harq_pid); - if (pdu[0] == 1) { // ACK - sched_ctl->round[CC_idP][harq_pid]=8; // release HARQ process - sched_ctl->tbcnt[CC_idP][harq_pid]=0; - } - else if (pdu[0] == 2 || pdu[0] == 4) // NAK (treat DTX as NAK) - sched_ctl->round[CC_idP][harq_pid]++; // increment round - } - else { - // one or two ACK/NAK bits - AssertFatal(num_ack_nak>2,"num_ack_nak %d > 2 for 1 CC and TM3/4/8/9/10\n",num_ack_nak); - if ((num_ack_nak==2) && (sched_ctl->round[CC_idP][harq_pid]<8) && (sched_ctl->tbcnt[CC_idP][harq_pid]==1) && (pdu[0] == 1) && (pdu[1] == 1)) { - sched_ctl->round[CC_idP][harq_pid]=8; - sched_ctl->tbcnt[CC_idP][harq_pid]=0; - } - if ((num_ack_nak==2) && (sched_ctl->round[CC_idP][harq_pid]<8) && (sched_ctl->tbcnt[CC_idP][harq_pid]==1) && (pdu[0] == 2) && (pdu[1] == 2)) - sched_ctl->round[CC_idP][harq_pid]++; - else if (((num_ack_nak==2) && (sched_ctl->round[CC_idP][harq_pid]<8) && (sched_ctl->tbcnt[0][harq_pid]==2) && (pdu[0] == 1) && (pdu[1] == 2)) || - ((num_ack_nak==2) && (sched_ctl->round[CC_idP][harq_pid]<8) && (sched_ctl->tbcnt[CC_idP][harq_pid]==2) && (pdu[0] == 2) && (pdu[1] == 1))) { - sched_ctl->round[CC_idP][harq_pid]++; - sched_ctl->tbcnt[CC_idP][harq_pid]=1; - } - else if ((num_ack_nak==2) && (sched_ctl->round[CC_idP][harq_pid]<8) && (sched_ctl->tbcnt[CC_idP][harq_pid]==2) && (pdu[0] == 2) && (pdu[1] == 2)) - sched_ctl->round[CC_idP][harq_pid]++; - else AssertFatal(1==0,"Illegal ACK/NAK/round combination (%d,%d,%d,%d,%d) for harq_pid %d, UE %d/%x\n", - num_ack_nak,sched_ctl->round[CC_idP][harq_pid],sched_ctl->round[CC_idP][harq_pid],pdu[0],pdu[1], harq_pid,UE_id, - rnti); - } - break; - case 1: // FDD Channel Selection (10.1.2.2.1), must be received for 2 serving cells - AssertFatal(numCC==2,"Should not receive harq indication with channel selection with %d active CCs\n", - numCC); + if (pdu[0] == 1) { // ACK + sched_ctl->round[CC_idP][harq_pid] = 8; // release HARQ process + sched_ctl->tbcnt[CC_idP][harq_pid] = 0; + } else if (pdu[0] == 2 || pdu[0] == 4) // NAK (treat DTX as NAK) + sched_ctl->round[CC_idP][harq_pid]++; // increment round + } else { + // one or two ACK/NAK bits + AssertFatal(num_ack_nak > 2, + "num_ack_nak %d > 2 for 1 CC and TM3/4/8/9/10\n", + num_ack_nak); + if ((num_ack_nak == 2) + && (sched_ctl->round[CC_idP][harq_pid] < 8) + && (sched_ctl->tbcnt[CC_idP][harq_pid] == 1) + && (pdu[0] == 1) && (pdu[1] == 1)) { + sched_ctl->round[CC_idP][harq_pid] = 8; + sched_ctl->tbcnt[CC_idP][harq_pid] = 0; + } + if ((num_ack_nak == 2) + && (sched_ctl->round[CC_idP][harq_pid] < 8) + && (sched_ctl->tbcnt[CC_idP][harq_pid] == 1) + && (pdu[0] == 2) && (pdu[1] == 2)) + sched_ctl->round[CC_idP][harq_pid]++; + else if (((num_ack_nak == 2) + && (sched_ctl->round[CC_idP][harq_pid] < 8) + && (sched_ctl->tbcnt[0][harq_pid] == 2) + && (pdu[0] == 1) && (pdu[1] == 2)) + || ((num_ack_nak == 2) + && (sched_ctl->round[CC_idP][harq_pid] < 8) + && (sched_ctl->tbcnt[CC_idP][harq_pid] == 2) + && (pdu[0] == 2) && (pdu[1] == 1))) { + sched_ctl->round[CC_idP][harq_pid]++; + sched_ctl->tbcnt[CC_idP][harq_pid] = 1; + } else if ((num_ack_nak == 2) + && (sched_ctl->round[CC_idP][harq_pid] < 8) + && (sched_ctl->tbcnt[CC_idP][harq_pid] == 2) + && (pdu[0] == 2) && (pdu[1] == 2)) + sched_ctl->round[CC_idP][harq_pid]++; + else + AssertFatal(1 == 0, + "Illegal ACK/NAK/round combination (%d,%d,%d,%d,%d) for harq_pid %d, UE %d/%x\n", + num_ack_nak, + sched_ctl->round[CC_idP][harq_pid], + sched_ctl->round[CC_idP][harq_pid], pdu[0], + pdu[1], harq_pid, UE_id, rnti); + } + break; + case 1: // FDD Channel Selection (10.1.2.2.1), must be received for 2 serving cells + AssertFatal(numCC == 2, + "Should not receive harq indication with channel selection with %d active CCs\n", + numCC); - if ((num_ack_nak == 2) && (sched_ctl->round[pCCid][harq_pid]<8) && (sched_ctl->round[1-pCCid][harq_pid]<8) && (sched_ctl->tbcnt[pCCid][harq_pid]==1) && (sched_ctl->tbcnt[1-pCCid][harq_pid]==1)) { - AssertFatal(pdu[0]<=3,"pdu[0] %d is not ACK/NAK/DTX\n",pdu[0]); - AssertFatal(pdu[1]<=3,"pdu[1] %d is not ACK/NAK/DTX\n",pdu[1]); - if (pdu[0] == 1) sched_ctl->round[pCCid][harq_pid]=8; - else sched_ctl->round[pCCid][harq_pid]++; - if (pdu[1] == 1) sched_ctl->round[1-pCCid][harq_pid]=8; - else sched_ctl->round[1-pCCid][harq_pid]++; - } // A=2 - else if ((num_ack_nak == 3) && (sched_ctl->round[pCCid][harq_pid]<8) && (sched_ctl->tbcnt[pCCid][harq_pid]==2) && (sched_ctl->round[1-pCCid][harq_pid]<8) && (sched_ctl->tbcnt[1-pCCid][harq_pid]==1)) { - AssertFatal(pdu[0]<=3,"pdu[0] %d is not ACK/NAK/DTX\n",pdu[0]); - AssertFatal(pdu[1]<=3,"pdu[1] %d is not ACK/NAK/DTX\n",pdu[1]); - AssertFatal(pdu[2]<=3,"pdu[2] %d is not ACK/NAK/DTX\n",pdu[2]); - AssertFatal(sched_ctl->tbcnt[pCCid][harq_pid] == 2,"sched_ctl->tbcnt[%d][%d] != 2 for UE %d/%x\n",pCCid,harq_pid,UE_id,rnti); - AssertFatal(sched_ctl->tbcnt[1-pCCid][harq_pid] == 1,"sched_ctl->tbcnt[%d][%d] != 1 for UE %d/%x\n",1-pCCid,harq_pid,UE_id,rnti); - if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK - sched_ctl->round[pCCid][harq_pid]=8; - sched_ctl->tbcnt[pCCid][harq_pid]=0; - } - else if (((pdu[0] == 2) && (pdu[1] == 1))|| - ((pdu[0] == 1) && (pdu[1] == 2))){ - sched_ctl->round[pCCid][harq_pid]++; - sched_ctl->tbcnt[pCCid][harq_pid]=1; - } - else - sched_ctl->round[pCCid][harq_pid]++; + if ((num_ack_nak == 2) + && (sched_ctl->round[pCCid][harq_pid] < 8) + && (sched_ctl->round[1 - pCCid][harq_pid] < 8) + && (sched_ctl->tbcnt[pCCid][harq_pid] == 1) + && (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 1)) { + AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n", + pdu[0]); + AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n", + pdu[1]); + if (pdu[0] == 1) + sched_ctl->round[pCCid][harq_pid] = 8; + else + sched_ctl->round[pCCid][harq_pid]++; + if (pdu[1] == 1) + sched_ctl->round[1 - pCCid][harq_pid] = 8; + else + sched_ctl->round[1 - pCCid][harq_pid]++; + } // A=2 + else if ((num_ack_nak == 3) + && (sched_ctl->round[pCCid][harq_pid] < 8) + && (sched_ctl->tbcnt[pCCid][harq_pid] == 2) + && (sched_ctl->round[1 - pCCid][harq_pid] < 8) + && (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 1)) { + AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n", + pdu[0]); + AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n", + pdu[1]); + AssertFatal(pdu[2] <= 3, "pdu[2] %d is not ACK/NAK/DTX\n", + pdu[2]); + AssertFatal(sched_ctl->tbcnt[pCCid][harq_pid] == 2, + "sched_ctl->tbcnt[%d][%d] != 2 for UE %d/%x\n", + pCCid, harq_pid, UE_id, rnti); + AssertFatal(sched_ctl->tbcnt[1 - pCCid][harq_pid] == 1, + "sched_ctl->tbcnt[%d][%d] != 1 for UE %d/%x\n", + 1 - pCCid, harq_pid, UE_id, rnti); + if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK + sched_ctl->round[pCCid][harq_pid] = 8; + sched_ctl->tbcnt[pCCid][harq_pid] = 0; + } else if (((pdu[0] == 2) && (pdu[1] == 1)) || + ((pdu[0] == 1) && (pdu[1] == 2))) { + sched_ctl->round[pCCid][harq_pid]++; + sched_ctl->tbcnt[pCCid][harq_pid] = 1; + } else + sched_ctl->round[pCCid][harq_pid]++; - if (pdu[2] == 1) sched_ctl->round[1-pCCid][harq_pid]=8; - else sched_ctl->round[1-pCCid][harq_pid]++; - } // A=3 primary cell has 2 TBs - else if ((num_ack_nak == 3) && (sched_ctl->round[1-pCCid][harq_pid]<8) && (sched_ctl->round[pCCid][harq_pid]<8) && (sched_ctl->tbcnt[1-pCCid][harq_pid]==2) && (sched_ctl->tbcnt[pCCid][harq_pid]==1)) { - AssertFatal(pdu[0]<=3,"pdu[0] %d is not ACK/NAK/DTX\n",pdu[0]); - AssertFatal(pdu[1]<=3,"pdu[1] %d is not ACK/NAK/DTX\n",pdu[1]); - AssertFatal(pdu[2]<=3,"pdu[2] %d is not ACK/NAK/DTX\n",pdu[2]); - AssertFatal(sched_ctl->tbcnt[1-pCCid][harq_pid] == 2,"sched_ctl->tbcnt[%d][%d] != 2 for UE %d/%x\n",1-pCCid,harq_pid,UE_id,rnti); - AssertFatal(sched_ctl->tbcnt[pCCid][harq_pid] == 1,"sched_ctl->tbcnt[%d][%d] != 1 for UE %d/%x\n",pCCid,harq_pid,UE_id,rnti); - if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK - sched_ctl->round[1-pCCid][harq_pid]=8; - sched_ctl->tbcnt[1-pCCid][harq_pid]=0; - } - else if (((pdu[0] >= 2) && (pdu[1] == 1))|| - ((pdu[0] == 1) && (pdu[1] >= 2))){ // one ACK - sched_ctl->round[1-pCCid][harq_pid]++; - sched_ctl->tbcnt[1-pCCid][harq_pid]=1; - } - else // both NAK/DTX - sched_ctl->round[1-pCCid][harq_pid]++; + if (pdu[2] == 1) + sched_ctl->round[1 - pCCid][harq_pid] = 8; + else + sched_ctl->round[1 - pCCid][harq_pid]++; + } // A=3 primary cell has 2 TBs + else if ((num_ack_nak == 3) + && (sched_ctl->round[1 - pCCid][harq_pid] < 8) + && (sched_ctl->round[pCCid][harq_pid] < 8) + && (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 2) + && (sched_ctl->tbcnt[pCCid][harq_pid] == 1)) { + AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n", + pdu[0]); + AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n", + pdu[1]); + AssertFatal(pdu[2] <= 3, "pdu[2] %d is not ACK/NAK/DTX\n", + pdu[2]); + AssertFatal(sched_ctl->tbcnt[1 - pCCid][harq_pid] == 2, + "sched_ctl->tbcnt[%d][%d] != 2 for UE %d/%x\n", + 1 - pCCid, harq_pid, UE_id, rnti); + AssertFatal(sched_ctl->tbcnt[pCCid][harq_pid] == 1, + "sched_ctl->tbcnt[%d][%d] != 1 for UE %d/%x\n", + pCCid, harq_pid, UE_id, rnti); + if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK + sched_ctl->round[1 - pCCid][harq_pid] = 8; + sched_ctl->tbcnt[1 - pCCid][harq_pid] = 0; + } else if (((pdu[0] >= 2) && (pdu[1] == 1)) + || ((pdu[0] == 1) && (pdu[1] >= 2))) { // one ACK + sched_ctl->round[1 - pCCid][harq_pid]++; + sched_ctl->tbcnt[1 - pCCid][harq_pid] = 1; + } else // both NAK/DTX + sched_ctl->round[1 - pCCid][harq_pid]++; - if (pdu[2] == 1) sched_ctl->round[pCCid][harq_pid]=8; - else sched_ctl->round[pCCid][harq_pid]++; - } // A=3 secondary cell has 2 TBs + if (pdu[2] == 1) + sched_ctl->round[pCCid][harq_pid] = 8; + else + sched_ctl->round[pCCid][harq_pid]++; + } // A=3 secondary cell has 2 TBs #if MAX_NUM_CCs>1 - else if ((num_ack_nak == 4) && (sched_ctl->round[0][harq_pid]<8) && (sched_ctl->round[1][harq_pid]<8) && (sched_ctl->tbcnt[1-pCCid][harq_pid]==2) && (sched_ctl->tbcnt[pCCid][harq_pid]==2)) { - AssertFatal(pdu[0]<=3,"pdu[0] %d is not ACK/NAK/DTX\n",pdu[0]); - AssertFatal(pdu[1]<=3,"pdu[1] %d is not ACK/NAK/DTX\n",pdu[1]); - AssertFatal(pdu[2]<=3,"pdu[2] %d is not ACK/NAK/DTX\n",pdu[2]); - AssertFatal(pdu[3]<=3,"pdu[3] %d is not ACK/NAK/DTX\n",pdu[3]); - AssertFatal(sched_ctl->tbcnt[0][harq_pid] == 2,"sched_ctl->tbcnt[0][%d] != 2 for UE %d/%x\n",harq_pid,UE_id,rnti); - AssertFatal(sched_ctl->tbcnt[1][harq_pid] == 2,"sched_ctl->tbcnt[1][%d] != 2 for UE %d/%x\n",harq_pid,UE_id,rnti); - if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK - sched_ctl->round[0][harq_pid]=8; - sched_ctl->tbcnt[0][harq_pid]=0; - } - else if (((pdu[0] >= 2) && (pdu[1] == 1))|| - ((pdu[0] == 1) && (pdu[1] >= 2))){ // one ACK - sched_ctl->round[0][harq_pid]++; - sched_ctl->tbcnt[0][harq_pid]=1; - } - else // both NAK/DTX - sched_ctl->round[0][harq_pid]++; + else if ((num_ack_nak == 4) + && (sched_ctl->round[0][harq_pid] < 8) + && (sched_ctl->round[1][harq_pid] < 8) + && (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 2) + && (sched_ctl->tbcnt[pCCid][harq_pid] == 2)) { + AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n", + pdu[0]); + AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n", + pdu[1]); + AssertFatal(pdu[2] <= 3, "pdu[2] %d is not ACK/NAK/DTX\n", + pdu[2]); + AssertFatal(pdu[3] <= 3, "pdu[3] %d is not ACK/NAK/DTX\n", + pdu[3]); + AssertFatal(sched_ctl->tbcnt[0][harq_pid] == 2, + "sched_ctl->tbcnt[0][%d] != 2 for UE %d/%x\n", + harq_pid, UE_id, rnti); + AssertFatal(sched_ctl->tbcnt[1][harq_pid] == 2, + "sched_ctl->tbcnt[1][%d] != 2 for UE %d/%x\n", + harq_pid, UE_id, rnti); + if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK + sched_ctl->round[0][harq_pid] = 8; + sched_ctl->tbcnt[0][harq_pid] = 0; + } else if (((pdu[0] >= 2) && (pdu[1] == 1)) + || ((pdu[0] == 1) && (pdu[1] >= 2))) { // one ACK + sched_ctl->round[0][harq_pid]++; + sched_ctl->tbcnt[0][harq_pid] = 1; + } else // both NAK/DTX + sched_ctl->round[0][harq_pid]++; - if ((pdu[2] == 1) && (pdu[3] == 1)) { // both ACK - sched_ctl->round[1][harq_pid]=8; - sched_ctl->tbcnt[1][harq_pid]=0; - } - else if (((pdu[2] >= 2) && (pdu[3] == 1))|| - ((pdu[2] == 1) && (pdu[3] >= 2))){ // one ACK - sched_ctl->round[1][harq_pid]++; - sched_ctl->tbcnt[1][harq_pid]=1; - } - else // both NAK/DTX - sched_ctl->round[1][harq_pid]++; - } // A=4 both serving cells have 2 TBs + if ((pdu[2] == 1) && (pdu[3] == 1)) { // both ACK + sched_ctl->round[1][harq_pid] = 8; + sched_ctl->tbcnt[1][harq_pid] = 0; + } else if (((pdu[2] >= 2) && (pdu[3] == 1)) + || ((pdu[2] == 1) && (pdu[3] >= 2))) { // one ACK + sched_ctl->round[1][harq_pid]++; + sched_ctl->tbcnt[1][harq_pid] = 1; + } else // both NAK/DTX + sched_ctl->round[1][harq_pid]++; + } // A=4 both serving cells have 2 TBs #endif - break; - case 2: // Format 3 - AssertFatal(numCC>2,"Should not receive harq indication with FDD format 3 with %d < 3 active CCs\n", - numCC); - for (i=0,j=0;iround[i][harq_pid]<8)) { - if (tmode[i]==1 || tmode[i]==2 || tmode[0]==5 || tmode[0]==6 || tmode[0]==7) { - if (pdu[j] == 1) { - sched_ctl->round[i][harq_pid]=8; - sched_ctl->tbcnt[i][harq_pid]=0; - } - else if (pdu[j] == 2) sched_ctl->round[i][harq_pid]++; - else AssertFatal(1==0,"Illegal harq_ack value for CC %d harq_pid %d (%d) UE %d/%x\n", - i,harq_pid,pdu[j],UE_id,rnti); - j++; - } - else if (spatial_bundling == 0) { - if ((sched_ctl->tbcnt[i][harq_pid]==2) && (pdu[j] == 1) && (pdu[j+1]==1)) { - sched_ctl->round[i][harq_pid]=8; - sched_ctl->tbcnt[i][harq_pid]=0; - } - else if ((sched_ctl->tbcnt[i][harq_pid]==2) && (pdu[j] == 1) && (pdu[j+1]==2)) { - sched_ctl->round[i][harq_pid]++; - sched_ctl->tbcnt[i][harq_pid]=1; - } - else if ((sched_ctl->tbcnt[i][harq_pid]==2) && (pdu[j] == 2) && (pdu[j+1]==1)) { - sched_ctl->round[i][harq_pid]++; - sched_ctl->tbcnt[i][harq_pid]=1; - } - else if ((sched_ctl->tbcnt[i][harq_pid]==2) && (pdu[j] == 2) && (pdu[j+1]==2)) { - sched_ctl->round[i][harq_pid]++; - } - else AssertFatal(1==0,"Illegal combination for CC %d harq_pid %d (%d,%d,%d) UE %d/%x\n", - i,harq_pid,sched_ctl->tbcnt[i][harq_pid],pdu[j],pdu[j+1],UE_id,rnti); - j+=2; - } - else if (spatial_bundling == 1) { - if (pdu[j] == 1) { - sched_ctl->round[i][harq_pid]=8; - sched_ctl->tbcnt[i][harq_pid]=0; - } - else if (pdu[j] == 2) { - sched_ctl->round[i][harq_pid]++; - } - else AssertFatal(1==0,"Illegal hack_nak value %d for CC %d harq_pid %d UE %d/%x\n", - pdu[j],i,harq_pid,UE_id,rnti); - j++; - } - else AssertFatal(1==0,"Illegal value for spatial_bundling %d\n",spatial_bundling); - } - } - break; - case 3: // Format 4 - AssertFatal(1==0,"Should not receive harq indication with Format 4\n"); - break; - case 4: // Format 5 - AssertFatal(1==0,"Should not receive harq indication with Format 5\n"); - break; + break; + case 2: // Format 3 + AssertFatal(numCC > 2, + "Should not receive harq indication with FDD format 3 with %d < 3 active CCs\n", + numCC); + for (i = 0, j = 0; i < numCC; i++) { + if ((sched_ctl->round[i][harq_pid] < 8)) { + if (tmode[i] == 1 || tmode[i] == 2 || tmode[0] == 5 + || tmode[0] == 6 || tmode[0] == 7) { + if (pdu[j] == 1) { + sched_ctl->round[i][harq_pid] = 8; + sched_ctl->tbcnt[i][harq_pid] = 0; + } else if (pdu[j] == 2) + sched_ctl->round[i][harq_pid]++; + else + AssertFatal(1 == 0, + "Illegal harq_ack value for CC %d harq_pid %d (%d) UE %d/%x\n", + i, harq_pid, pdu[j], UE_id, rnti); + j++; + } else if (spatial_bundling == 0) { + if ((sched_ctl->tbcnt[i][harq_pid] == 2) + && (pdu[j] == 1) && (pdu[j + 1] == 1)) { + sched_ctl->round[i][harq_pid] = 8; + sched_ctl->tbcnt[i][harq_pid] = 0; + } else if ((sched_ctl->tbcnt[i][harq_pid] == 2) + && (pdu[j] == 1) && (pdu[j + 1] == 2)) { + sched_ctl->round[i][harq_pid]++; + sched_ctl->tbcnt[i][harq_pid] = 1; + } else if ((sched_ctl->tbcnt[i][harq_pid] == 2) + && (pdu[j] == 2) && (pdu[j + 1] == 1)) { + sched_ctl->round[i][harq_pid]++; + sched_ctl->tbcnt[i][harq_pid] = 1; + } else if ((sched_ctl->tbcnt[i][harq_pid] == 2) + && (pdu[j] == 2) && (pdu[j + 1] == 2)) { + sched_ctl->round[i][harq_pid]++; + } else + AssertFatal(1 == 0, + "Illegal combination for CC %d harq_pid %d (%d,%d,%d) UE %d/%x\n", + i, harq_pid, + sched_ctl->tbcnt[i][harq_pid], + pdu[j], pdu[j + 1], UE_id, rnti); + j += 2; + } else if (spatial_bundling == 1) { + if (pdu[j] == 1) { + sched_ctl->round[i][harq_pid] = 8; + sched_ctl->tbcnt[i][harq_pid] = 0; + } else if (pdu[j] == 2) { + sched_ctl->round[i][harq_pid]++; + } else + AssertFatal(1 == 0, + "Illegal hack_nak value %d for CC %d harq_pid %d UE %d/%x\n", + pdu[j], i, harq_pid, UE_id, rnti); + j++; + } else + AssertFatal(1 == 0, + "Illegal value for spatial_bundling %d\n", + spatial_bundling); + } + } + break; + case 3: // Format 4 + AssertFatal(1 == 0, + "Should not receive harq indication with Format 4\n"); + break; + case 4: // Format 5 + AssertFatal(1 == 0, + "Should not receive harq indication with Format 5\n"); + break; + } } - } } -void extract_pucch_csi(module_id_t mod_idP,int CC_idP,int UE_id, frame_t frameP,sub_frame_t subframeP,uint8_t *pdu, uint8_t length) +void +extract_pucch_csi(module_id_t mod_idP, int CC_idP, int UE_id, + frame_t frameP, sub_frame_t subframeP, + uint8_t * pdu, uint8_t length) { - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - COMMON_channels_t *cc=&RC.mac[mod_idP]->common_channels[CC_idP]; - struct CQI_ReportPeriodic *cqi_ReportPeriodic; - int no_pmi; - uint8_t Ltab[6] = {0,2,4,4,4,4}; - uint8_t Jtab[6] = {0,2,2,3,4,4}; - int feedback_cnt; + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; + struct CQI_ReportPeriodic *cqi_ReportPeriodic; + int no_pmi; + uint8_t Ltab[6] = { 0, 2, 4, 4, 4, 4 }; + uint8_t Jtab[6] = { 0, 2, 2, 3, 4, 4 }; + int feedback_cnt; - AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n",UE_id); - AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL,"cqi_ReportConfig is null for UE %d\n",UE_id); - AssertFatal((cqi_ReportPeriodic = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic)!=NULL, - "cqi_ReportPeriodic is null for UE %d\n",UE_id); + AssertFatal(UE_list->UE_template[CC_idP][UE_id]. + physicalConfigDedicated != NULL, + "physicalConfigDedicated is null for UE %d\n", UE_id); + AssertFatal(UE_list-> + UE_template[CC_idP][UE_id].physicalConfigDedicated-> + cqi_ReportConfig != NULL, + "cqi_ReportConfig is null for UE %d\n", UE_id); + AssertFatal((cqi_ReportPeriodic = + UE_list-> + UE_template[CC_idP][UE_id].physicalConfigDedicated-> + cqi_ReportConfig->cqi_ReportPeriodic) != NULL, + "cqi_ReportPeriodic is null for UE %d\n", UE_id); - // determine feedback mode - AssertFatal(cqi_ReportPeriodic->present != CQI_ReportPeriodic_PR_NOTHING, - "cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n"); - AssertFatal(cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present != CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING, - "cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING!\n"); + // determine feedback mode + AssertFatal(cqi_ReportPeriodic->present != + CQI_ReportPeriodic_PR_NOTHING, + "cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n"); + AssertFatal(cqi_ReportPeriodic->choice. + setup.cqi_FormatIndicatorPeriodic.present != + CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING, + "cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING!\n"); - uint16_t Npd,N_OFFSET_CQI; - int H,K,bandwidth_part,L,Lmask; - int ri = sched_ctl->periodic_ri_received[CC_idP]; + uint16_t Npd, N_OFFSET_CQI; + int H, K, bandwidth_part, L, Lmask; + int ri = sched_ctl->periodic_ri_received[CC_idP]; - get_csi_params(cc,cqi_ReportPeriodic,&Npd,&N_OFFSET_CQI,&H); - K =(H-1)/Jtab[cc->mib->message.dl_Bandwidth]; - L = Ltab[cc->mib->message.dl_Bandwidth]; - Lmask =L-1; - feedback_cnt = (((frameP*10)+subframeP)/Npd)%H; + get_csi_params(cc, cqi_ReportPeriodic, &Npd, &N_OFFSET_CQI, &H); + K = (H - 1) / Jtab[cc->mib->message.dl_Bandwidth]; + L = Ltab[cc->mib->message.dl_Bandwidth]; + Lmask = L - 1; + feedback_cnt = (((frameP * 10) + subframeP) / Npd) % H; - if (feedback_cnt>0) bandwidth_part = (feedback_cnt-1)%K; - else bandwidth_part = 0; + if (feedback_cnt > 0) + bandwidth_part = (feedback_cnt - 1) % K; + else + bandwidth_part = 0; - switch(get_tmode(mod_idP,CC_idP,UE_id)) { - case 1: - case 2: - case 3: - case 7: - no_pmi=1; - break; - case 4: - case 5: - case 6: - no_pmi=0; - break; - default: - // note: need to check TM8-10 without PMI/RI or with 1 antenna port (see Section 5.2.3.3.1 from 36.213) - no_pmi=0; - } - - if ((cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_widebandCQI) || - (feedback_cnt==0)){ - // Note: This implements only Tables: 5.3.3.1-1,5.3.3.1-1A and 5.3.3.1-2 from 36.213 (1,2,4 antenna ports Wideband CQI/PMI) - - if (no_pmi == 1) { // get spatial_diffcqi if needed - sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0]&0xF; - sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = (pdu[0]>>4)&7; + switch (get_tmode(mod_idP, CC_idP, UE_id)) { + case 1: + case 2: + case 3: + case 7: + no_pmi = 1; + break; + case 4: + case 5: + case 6: + no_pmi = 0; + break; + default: + // note: need to check TM8-10 without PMI/RI or with 1 antenna port (see Section 5.2.3.3.1 from 36.213) + no_pmi = 0; } - else if ((cc->p_eNB==2) && (ri==1)) { - // p=2 Rank 1 wideband CQI/PMI 6 bits - sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0]&0xF; - sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0]>>4)&3; - } - else if ((cc->p_eNB==2) && (ri>1)) { - // p=2 Rank 2 wideband CQI/PMI 8 bits - sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0]&0xF; - sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = (pdu[0]>>4)&7; - sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0]>>7)&1; - } - else if ((cc->p_eNB==4) && (ri==1)) { - // p=4 Rank 1 wideband CQI/PMI 8 bits - sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0]&0xF; - sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0]>>4)&0x0F; + if ((cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic. + present == + CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_widebandCQI) + || (feedback_cnt == 0)) { + // Note: This implements only Tables: 5.3.3.1-1,5.3.3.1-1A and 5.3.3.1-2 from 36.213 (1,2,4 antenna ports Wideband CQI/PMI) + + if (no_pmi == 1) { // get spatial_diffcqi if needed + sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; + sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = + (pdu[0] >> 4) & 7; + } else if ((cc->p_eNB == 2) && (ri == 1)) { + // p=2 Rank 1 wideband CQI/PMI 6 bits + sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; + sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 4) & 3; + } else if ((cc->p_eNB == 2) && (ri > 1)) { + // p=2 Rank 2 wideband CQI/PMI 8 bits + sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; + sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = + (pdu[0] >> 4) & 7; + sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 7) & 1; + } else if ((cc->p_eNB == 4) && (ri == 1)) { + // p=4 Rank 1 wideband CQI/PMI 8 bits + sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; + sched_ctl->periodic_wideband_pmi[CC_idP] = + (pdu[0] >> 4) & 0x0F; + + } else if ((cc->p_eNB == 4) && (ri > 1)) { + // p=4 Rank 2 wideband CQI/PMI 11 bits + sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; + sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = + (pdu[0] >> 4) & 7; + sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 7) & 0xF; + } else + AssertFatal(1 == 0, + "illegal combination p %d, ri %d, no_pmi %d\n", + cc->p_eNB, ri, no_pmi); + } else if (cqi_ReportPeriodic->choice. + setup.cqi_FormatIndicatorPeriodic.present == + CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) + { + // This is Table 5.2.3.3.2-2 for 36.213 + if (ri == 1) { + //4+Ltab[cc->mib->message.dl_Bandwidth] bits + sched_ctl->periodic_subband_cqi[CC_idP][(bandwidth_part * L) + + ((pdu[0] >> 4) & + Lmask)] = + pdu[0] & 0xF; + } else if (ri > 1) { + //7+Ltab[cc->mib->message.dl_Bandwidth] bits; + sched_ctl-> + periodic_subband_spatial_diffcqi[CC_idP][(bandwidth_part * + L) + + ((pdu[0] >> 7) & + Lmask)] = + (pdu[0] >> 4) & 7; + sched_ctl->periodic_subband_cqi[CC_idP][(bandwidth_part * L) + + ((pdu[0] >> 7) & + Lmask)] = + pdu[0] & 0xF; + } } - else if ((cc->p_eNB==4) && (ri>1)) { - // p=4 Rank 2 wideband CQI/PMI 11 bits - sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0]&0xF; - sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = (pdu[0]>>4)&7; - sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0]>>7)&0xF; - } - else AssertFatal(1==0,"illegal combination p %d, ri %d, no_pmi %d\n",cc->p_eNB,ri,no_pmi); - } - else if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) { - // This is Table 5.2.3.3.2-2 for 36.213 - if (ri==1) { - //4+Ltab[cc->mib->message.dl_Bandwidth] bits - sched_ctl->periodic_subband_cqi[CC_idP][(bandwidth_part*L)+((pdu[0]>>4)&Lmask)] = pdu[0]&0xF; - } - else if (ri>1) { - //7+Ltab[cc->mib->message.dl_Bandwidth] bits; - sched_ctl->periodic_subband_spatial_diffcqi[CC_idP][(bandwidth_part*L)+((pdu[0]>>7)&Lmask)] = (pdu[0]>>4)&7; - sched_ctl->periodic_subband_cqi[CC_idP][(bandwidth_part*L)+((pdu[0]>>7)&Lmask)] = pdu[0]&0xF; - } - } } -void extract_pusch_csi(module_id_t mod_idP,int CC_idP,int UE_id, frame_t frameP,sub_frame_t subframeP,uint8_t *pdu, uint8_t length) +void +extract_pusch_csi(module_id_t mod_idP, int CC_idP, int UE_id, + frame_t frameP, sub_frame_t subframeP, + uint8_t * pdu, uint8_t length) { - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; - UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - int Ntab[6] = {0,4,7,9,10,13}; - int Ntab_uesel[6] = {0,8,13,17,19,25}; - int Ltab_uesel[6] = {0,6,9,13,15,18}; - int Mtab_uesel[6] = {0,1,3,5,6,6}; - int v[6]; - int i; - uint64_t p = *(uint64_t*)pdu; - int curbyte, curbit; - CQI_ReportModeAperiodic_t *cqi_ReportModeAperiodic; + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; + UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + int Ntab[6] = { 0, 4, 7, 9, 10, 13 }; + int Ntab_uesel[6] = { 0, 8, 13, 17, 19, 25 }; + int Ltab_uesel[6] = { 0, 6, 9, 13, 15, 18 }; + int Mtab_uesel[6] = { 0, 1, 3, 5, 6, 6 }; + int v[6]; + int i; + uint64_t p = *(uint64_t *) pdu; + int curbyte, curbit; + CQI_ReportModeAperiodic_t *cqi_ReportModeAperiodic; - AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n",UE_id); - AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL,"cqi_ReportConfig is null for UE %d\n",UE_id); - AssertFatal((cqi_ReportModeAperiodic = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic)!=NULL, - "cqi_ReportModeAperiodic is null for UE %d\n",UE_id); + AssertFatal(UE_list->UE_template[CC_idP][UE_id]. + physicalConfigDedicated != NULL, + "physicalConfigDedicated is null for UE %d\n", UE_id); + AssertFatal(UE_list-> + UE_template[CC_idP][UE_id].physicalConfigDedicated-> + cqi_ReportConfig != NULL, + "cqi_ReportConfig is null for UE %d\n", UE_id); + AssertFatal((cqi_ReportModeAperiodic = + UE_list-> + UE_template[CC_idP][UE_id].physicalConfigDedicated-> + cqi_ReportConfig->cqi_ReportModeAperiodic) != NULL, + "cqi_ReportModeAperiodic is null for UE %d\n", UE_id); - int N = Ntab[cc->mib->message.dl_Bandwidth]; - int tmode = get_tmode(mod_idP,CC_idP,UE_id); - int ri = sched_ctl->aperiodic_ri_received[CC_idP]; - int r,diffcqi0=0,diffcqi1=0,pmi_uesel=0; - int bw = cc->mib->message.dl_Bandwidth; - int m; + int N = Ntab[cc->mib->message.dl_Bandwidth]; + int tmode = get_tmode(mod_idP, CC_idP, UE_id); + int ri = sched_ctl->aperiodic_ri_received[CC_idP]; + int r, diffcqi0 = 0, diffcqi1 = 0, pmi_uesel = 0; + int bw = cc->mib->message.dl_Bandwidth; + int m; - switch(*cqi_ReportModeAperiodic) { - case CQI_ReportModeAperiodic_rm12: - AssertFatal(0==1, "to be fixed, don't use p but pdu directly\n"); - // wideband multiple PMI (TM4/6), Table 5.2.2.6.1-1 (for TM4/6) - AssertFatal(tmode==4 || tmode==6 || tmode==8|| tmode==9 || tmode==10,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm12\n",tmode); - if (tmode <= 6) { //Table 5.2.2.6.1-1 36.213 - if ((ri==1) && (cc->p_eNB==2)) { - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - for (i=0;iaperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x03); - p>>=2; - } - } - if ((ri==2) && (cc->p_eNB==2)) { - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - for (i=0;iaperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x01); - p>>=1; - } - } - if ((ri==1) && (cc->p_eNB==4)) { - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - for (i=0;iaperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x03); - p>>=4; - } - } - if ((ri==2) && (cc->p_eNB==4)) { - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - for (i=0;iaperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x01); - p>>=4; - } - } - } // if (tmode <= 6) { //Table 5.2.2.6.1-1 36.213 - else { - AssertFatal(1==0,"support for TM 8-10 to be done\n"); - } + switch (*cqi_ReportModeAperiodic) { + case CQI_ReportModeAperiodic_rm12: + AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n"); + // wideband multiple PMI (TM4/6), Table 5.2.2.6.1-1 (for TM4/6) + AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm12\n", + tmode); + if (tmode <= 6) { //Table 5.2.2.6.1-1 36.213 + if ((ri == 1) && (cc->p_eNB == 2)) { + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = + (uint8_t) (p & 0x03); + p >>= 2; + } + } + if ((ri == 2) && (cc->p_eNB == 2)) { + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + sched_ctl->aperiodic_wideband_cqi1[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = + (uint8_t) (p & 0x01); + p >>= 1; + } + } + if ((ri == 1) && (cc->p_eNB == 4)) { + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = + (uint8_t) (p & 0x03); + p >>= 4; + } + } + if ((ri == 2) && (cc->p_eNB == 4)) { + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + sched_ctl->aperiodic_wideband_cqi1[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = + (uint8_t) (p & 0x01); + p >>= 4; + } + } + } // if (tmode <= 6) { //Table 5.2.2.6.1-1 36.213 + else { + AssertFatal(1 == 0, "support for TM 8-10 to be done\n"); + } - break; - case CQI_ReportModeAperiodic_rm20: - AssertFatal(0==1, "to be fixed, don't use p but pdu directly\n"); - // UE-selected subband CQI no PMI (TM1/2/3/7) , Table 5.2.2.6.3-1 from 36.213 - AssertFatal(tmode==1 || tmode==2 || tmode==3 || tmode==7,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm20\n",tmode); + break; + case CQI_ReportModeAperiodic_rm20: + AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n"); + // UE-selected subband CQI no PMI (TM1/2/3/7) , Table 5.2.2.6.3-1 from 36.213 + AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 + || tmode == 7, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm20\n", + tmode); - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - diffcqi0 = (uint8_t)(p&0x03); p>>=2; - r = (uint8_t)(p&((1>>Ltab_uesel[bw])-1)); - reverse_index(Ntab_uesel[bw],Mtab_uesel[bw],r,v); - for (m=0;maperiodic_subband_diffcqi0[CC_idP][v[m]] = diffcqi0; - break; - case CQI_ReportModeAperiodic_rm22: - AssertFatal(0==1, "to be fixed, don't use p but pdu directly\n"); - // UE-selected subband CQI multiple PMI (TM4/6) Table 5.2.2.6.3-2 from 36.213 + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F); + p >>= 4; + diffcqi0 = (uint8_t) (p & 0x03); + p >>= 2; + r = (uint8_t) (p & ((1 >> Ltab_uesel[bw]) - 1)); + reverse_index(Ntab_uesel[bw], Mtab_uesel[bw], r, v); + for (m = 0; m < Mtab_uesel[bw]; m++) + sched_ctl->aperiodic_subband_diffcqi0[CC_idP][v[m]] = diffcqi0; + break; + case CQI_ReportModeAperiodic_rm22: + AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n"); + // UE-selected subband CQI multiple PMI (TM4/6) Table 5.2.2.6.3-2 from 36.213 - AssertFatal(tmode==4 || tmode==6 || tmode==8|| tmode==9 || tmode==10,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm22\n",tmode); + AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm22\n", + tmode); - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - diffcqi0 = (uint8_t)(p&0x03); p>>=2; + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F); + p >>= 4; + diffcqi0 = (uint8_t) (p & 0x03); + p >>= 2; - if (ri>1) { - sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - diffcqi1 = (uint8_t)(p&0x03); p>>=2; - } - r = (uint8_t)(p&((1>>Ltab_uesel[bw])-1)); p>>=Ltab_uesel[bw]; - reverse_index(Ntab_uesel[bw],Mtab_uesel[bw],r,v); - if ((ri==1)&&(cc->p_eNB==2)) { - pmi_uesel = p&0x3; p>>=2; - sched_ctl->aperiodic_wideband_pmi[CC_idP] = p&0x3; - } - else if ((ri==2)&&(cc->p_eNB==2)) { - pmi_uesel = p&0x1; p>>=1; - sched_ctl->aperiodic_wideband_pmi[CC_idP] = p&0x1; - } - else if (cc->p_eNB==4) { - pmi_uesel = p&0x0F; p>>=4; - sched_ctl->aperiodic_wideband_pmi[CC_idP] = p&0x0F; - } - for (m=0;maperiodic_subband_diffcqi0[CC_idP][v[m]] = diffcqi0; - if (ri>1) sched_ctl->aperiodic_subband_diffcqi1[CC_idP][v[m]] = diffcqi1; - sched_ctl->aperiodic_subband_pmi[CC_idP][v[m]] = pmi_uesel; - } - break; - case CQI_ReportModeAperiodic_rm30: - //subband CQI no PMI (TM1/2/3/7) - AssertFatal(tmode==1 || tmode==2 || tmode==3 || tmode==7,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm30\n",tmode); - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = pdu[0]>>4; - curbyte = 0; - curbit = 3; - for (i=0;iaperiodic_subband_diffcqi0[CC_idP][i] = (pdu[curbyte] >> (curbit-1)) & 0x03; - curbit -= 2; - if (curbit < 0) { - curbit = 7; - curbyte++; - } - } - sched_ctl->dl_cqi[CC_idP] = sched_ctl->aperiodic_wideband_cqi0[CC_idP]; - break; - case CQI_ReportModeAperiodic_rm31: - AssertFatal(0==1, "to be fixed, don't use p but pdu directly\n"); - //subband CQI single PMI (TM4/5/6) - AssertFatal(tmode==4 || tmode==5 || tmode==6 || tmode==8|| tmode==9|| tmode==10,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm31\n",tmode); + if (ri > 1) { + sched_ctl->aperiodic_wideband_cqi1[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + diffcqi1 = (uint8_t) (p & 0x03); + p >>= 2; + } + r = (uint8_t) (p & ((1 >> Ltab_uesel[bw]) - 1)); + p >>= Ltab_uesel[bw]; + reverse_index(Ntab_uesel[bw], Mtab_uesel[bw], r, v); + if ((ri == 1) && (cc->p_eNB == 2)) { + pmi_uesel = p & 0x3; + p >>= 2; + sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x3; + } else if ((ri == 2) && (cc->p_eNB == 2)) { + pmi_uesel = p & 0x1; + p >>= 1; + sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x1; + } else if (cc->p_eNB == 4) { + pmi_uesel = p & 0x0F; + p >>= 4; + sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F; + } + for (m = 0; m < Mtab_uesel[bw]; m++) { + sched_ctl->aperiodic_subband_diffcqi0[CC_idP][v[m]] = diffcqi0; + if (ri > 1) + sched_ctl->aperiodic_subband_diffcqi1[CC_idP][v[m]] = + diffcqi1; + sched_ctl->aperiodic_subband_pmi[CC_idP][v[m]] = pmi_uesel; + } + break; + case CQI_ReportModeAperiodic_rm30: + //subband CQI no PMI (TM1/2/3/7) + AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 + || tmode == 7, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm30\n", + tmode); + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = pdu[0] >> 4; + curbyte = 0; + curbit = 3; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] = + (pdu[curbyte] >> (curbit - 1)) & 0x03; + curbit -= 2; + if (curbit < 0) { + curbit = 7; + curbyte++; + } + } + sched_ctl->dl_cqi[CC_idP] = + sched_ctl->aperiodic_wideband_cqi0[CC_idP]; + break; + case CQI_ReportModeAperiodic_rm31: + AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n"); + //subband CQI single PMI (TM4/5/6) + AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8 + || tmode == 9 + || tmode == 10, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm31\n", + tmode); - if ((ri==1) && (cc->p_eNB==2)) { - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - for (i=0;iaperiodic_subband_diffcqi0[CC_idP][i] = (uint8_t)(p&0x03); - p>>=2; - } - sched_ctl->aperiodic_wideband_pmi[CC_idP] = p&0x03; - } - if ((ri==2) && (cc->p_eNB==2)) { - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - for (i=0;iaperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x01); - p>>=1; - } - sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - for (i=0;iaperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x01); - p>>=1; - } - sched_ctl->aperiodic_wideband_pmi[CC_idP] = p&0x01; - } - if ((ri==1) && (cc->p_eNB==4)) { - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - for (i=0;iaperiodic_subband_diffcqi0[CC_idP][i] = (uint8_t)(p&0x03); - p>>=2; - } - sched_ctl->aperiodic_wideband_pmi[CC_idP] = p&0x0F; - } - if ((ri>1) && (cc->p_eNB==4)) { // Note : 64 bits for 20 MHz - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - for (i=0;iaperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x01); - p>>=1; - } - sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t)(p&0x0F); p>>=4; - for (i=0;iaperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x01); - p>>=2; - } - sched_ctl->aperiodic_wideband_pmi[CC_idP] = p&0x0F; - } + if ((ri == 1) && (cc->p_eNB == 2)) { + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] = + (uint8_t) (p & 0x03); + p >>= 2; + } + sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x03; + } + if ((ri == 2) && (cc->p_eNB == 2)) { + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = + (uint8_t) (p & 0x01); + p >>= 1; + } + sched_ctl->aperiodic_wideband_cqi1[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = + (uint8_t) (p & 0x01); + p >>= 1; + } + sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x01; + } + if ((ri == 1) && (cc->p_eNB == 4)) { + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] = + (uint8_t) (p & 0x03); + p >>= 2; + } + sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F; + } + if ((ri > 1) && (cc->p_eNB == 4)) { // Note : 64 bits for 20 MHz + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = + (uint8_t) (p & 0x01); + p >>= 1; + } + sched_ctl->aperiodic_wideband_cqi1[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = + (uint8_t) (p & 0x01); + p >>= 2; + } + sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F; + } - break; - case CQI_ReportModeAperiodic_rm32_v1250: - AssertFatal(tmode==4 || tmode==5 || tmode==6 || tmode==8|| tmode==9|| tmode==10,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm32\n",tmode); - AssertFatal(1==0,"CQI_ReportModeAperiodic_rm32 to be done\n"); - break; - case CQI_ReportModeAperiodic_rm10_v1310: - AssertFatal(tmode==1 || tmode==2 || tmode==3 || tmode==7,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm10\n",tmode); - AssertFatal(1==0,"CQI_ReportModeAperiodic_rm10 to be done\n"); - break; - case CQI_ReportModeAperiodic_rm11_v1310: - AssertFatal(tmode==4 || tmode==5 || tmode==6 || tmode==8|| tmode==9|| tmode==10,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm11\n",tmode); - AssertFatal(1==0,"CQI_ReportModeAperiodic_rm11 to be done\n"); - break; - } + break; + case CQI_ReportModeAperiodic_rm32_v1250: + AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8 + || tmode == 9 + || tmode == 10, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm32\n", + tmode); + AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm32 to be done\n"); + break; + case CQI_ReportModeAperiodic_rm10_v1310: + AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 + || tmode == 7, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm10\n", + tmode); + AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm10 to be done\n"); + break; + case CQI_ReportModeAperiodic_rm11_v1310: + AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8 + || tmode == 9 + || tmode == 10, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm11\n", + tmode); + AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm11 to be done\n"); + break; + } } -void cqi_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, sub_frame_t subframeP, rnti_t rntiP, - nfapi_cqi_indication_rel9_t *rel9,uint8_t *pdu, - nfapi_ul_cqi_information_t *ul_cqi_information) +void +cqi_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, + sub_frame_t subframeP, rnti_t rntiP, + nfapi_cqi_indication_rel9_t * rel9, uint8_t * pdu, + nfapi_ul_cqi_information_t * ul_cqi_information) { - int UE_id = find_UE_id(mod_idP, rntiP); - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - if (UE_id == -1) { - LOG_W(MAC, "cqi_indication: UE %x not found\n", rntiP); - return; - } - UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - - if (UE_id >= 0) { - - if (ul_cqi_information->channel == 0) { // PUCCH - - // extract pucch csi information before changing RI information - extract_pucch_csi(mod_idP,CC_idP,UE_id,frameP,subframeP,pdu,rel9->length); - - memcpy((void*)sched_ctl->periodic_ri_received, - (void*)rel9->ri, - rel9->number_of_cc_reported); - - // SNR for PUCCH2 - sched_ctl->pucch2_snr[CC_idP] = ul_cqi_information->ul_cqi; + int UE_id = find_UE_id(mod_idP, rntiP); + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + if (UE_id == -1) { + LOG_W(MAC, "cqi_indication: UE %x not found\n", rntiP); + return; } - else { //PUSCH - memcpy((void*)sched_ctl->aperiodic_ri_received, - (void*)rel9->ri, - rel9->number_of_cc_reported); - - extract_pusch_csi(mod_idP,CC_idP,UE_id,frameP,subframeP,pdu,rel9->length); - - } - - // timing advance - sched_ctl->timing_advance = rel9->timing_advance; - sched_ctl->timing_advance_r9 = rel9->timing_advance_r9; - } -} - -void SR_indication(module_id_t mod_idP, int cc_idP, frame_t frameP, sub_frame_t subframeP, rnti_t rntiP, uint8_t ul_cqi) -{ - T(T_ENB_MAC_SCHEDULING_REQUEST, T_INT(mod_idP), T_INT(cc_idP), T_INT(frameP), T_INT(subframeP), T_INT(rntiP)); - - int UE_id = find_UE_id(mod_idP, rntiP); - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - - if (UE_id != -1) { - if (mac_eNB_get_rrc_status(mod_idP,UE_RNTI(mod_idP,UE_id)) < RRC_CONNECTED) - LOG_D(MAC,"[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d on CC_id %d\n",mod_idP,rntiP,frameP,subframeP, UE_id,cc_idP); - -#if 0 UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - /* for the moment don't use ul_cqi from SR, value is too different from harq */ - sched_ctl->pucch1_snr[cc_idP] = ul_cqi; - sched_ctl->pucch1_cqi_update[cc_idP] = 1; + if (UE_id >= 0) { + + if (ul_cqi_information->channel == 0) { // PUCCH + + // extract pucch csi information before changing RI information + extract_pucch_csi(mod_idP, CC_idP, UE_id, frameP, subframeP, + pdu, rel9->length); + + memcpy((void *) sched_ctl->periodic_ri_received, + (void *) rel9->ri, rel9->number_of_cc_reported); + + // SNR for PUCCH2 + sched_ctl->pucch2_snr[CC_idP] = ul_cqi_information->ul_cqi; + } else { //PUSCH + memcpy((void *) sched_ctl->aperiodic_ri_received, + (void *) rel9->ri, rel9->number_of_cc_reported); + + extract_pusch_csi(mod_idP, CC_idP, UE_id, frameP, subframeP, + pdu, rel9->length); + + } + + // timing advance + sched_ctl->timing_advance = rel9->timing_advance; + sched_ctl->timing_advance_r9 = rel9->timing_advance_r9; + } +} + +void +SR_indication(module_id_t mod_idP, int cc_idP, frame_t frameP, + sub_frame_t subframeP, rnti_t rntiP, uint8_t ul_cqi) +{ + T(T_ENB_MAC_SCHEDULING_REQUEST, T_INT(mod_idP), T_INT(cc_idP), + T_INT(frameP), T_INT(subframeP), T_INT(rntiP)); + + int UE_id = find_UE_id(mod_idP, rntiP); + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + + if (UE_id != -1) { + if (mac_eNB_get_rrc_status(mod_idP, UE_RNTI(mod_idP, UE_id)) < + RRC_CONNECTED) + LOG_D(MAC, + "[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d on CC_id %d\n", + mod_idP, rntiP, frameP, subframeP, UE_id, cc_idP); + +#if 0 + UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + + /* for the moment don't use ul_cqi from SR, value is too different from harq */ + sched_ctl->pucch1_snr[cc_idP] = ul_cqi; + sched_ctl->pucch1_cqi_update[cc_idP] = 1; #endif - UE_list->UE_template[cc_idP][UE_id].ul_SR = 1; - UE_list->UE_template[cc_idP][UE_id].ul_active = TRUE; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION,1); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION,0); - } else { - // AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP); - // AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP); - LOG_D(MAC,"[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d (unknown UEid) on CC_id %d\n",mod_idP,rntiP,frameP,subframeP, UE_id,cc_idP); - } + UE_list->UE_template[cc_idP][UE_id].ul_SR = 1; + UE_list->UE_template[cc_idP][UE_id].ul_active = TRUE; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION, 1); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION, 0); + } else { + // AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP); + // AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP); + LOG_D(MAC, + "[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d (unknown UEid) on CC_id %d\n", + mod_idP, rntiP, frameP, subframeP, UE_id, cc_idP); + } } -void UL_failure_indication(module_id_t mod_idP, int cc_idP, frame_t frameP, rnti_t rntiP, sub_frame_t subframeP) +void +UL_failure_indication(module_id_t mod_idP, int cc_idP, frame_t frameP, + rnti_t rntiP, sub_frame_t subframeP) { - int UE_id = find_UE_id(mod_idP, rntiP); - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + int UE_id = find_UE_id(mod_idP, rntiP); + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - if (UE_id != -1) { - LOG_D(MAC,"[eNB %d][UE %d/%x] Frame %d subframeP %d Signaling UL Failure for UE %d on CC_id %d (timer %d)\n", - mod_idP,UE_id,rntiP,frameP,subframeP, UE_id,cc_idP, - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); - if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 0) - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer=1; - } else { - // AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP); - // AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP); - LOG_W(MAC,"[eNB %d][SR %x] Frame %d subframeP %d Signaling UL Failure for UE %d (unknown UEid) on CC_id %d\n",mod_idP,rntiP,frameP,subframeP, UE_id,cc_idP); - } + if (UE_id != -1) { + LOG_D(MAC, + "[eNB %d][UE %d/%x] Frame %d subframeP %d Signaling UL Failure for UE %d on CC_id %d (timer %d)\n", + mod_idP, UE_id, rntiP, frameP, subframeP, UE_id, cc_idP, + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); + if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 0) + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 1; + } else { + // AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP); + // AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP); + LOG_W(MAC, + "[eNB %d][SR %x] Frame %d subframeP %d Signaling UL Failure for UE %d (unknown UEid) on CC_id %d\n", + mod_idP, rntiP, frameP, subframeP, UE_id, cc_idP); + } } -void harq_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, sub_frame_t subframeP, nfapi_harq_indication_pdu_t *harq_pdu) +void +harq_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, + sub_frame_t subframeP, + nfapi_harq_indication_pdu_t * harq_pdu) { - rnti_t rnti = harq_pdu->rx_ue_information.rnti; - uint8_t ul_cqi = harq_pdu->ul_cqi_information.ul_cqi; - uint8_t channel = harq_pdu->ul_cqi_information.channel; - int UE_id = find_UE_id(mod_idP, rnti); - if (UE_id == -1) { - LOG_W(MAC, "harq_indication: UE %x not found\n", rnti); - return; - } - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; + rnti_t rnti = harq_pdu->rx_ue_information.rnti; + uint8_t ul_cqi = harq_pdu->ul_cqi_information.ul_cqi; + uint8_t channel = harq_pdu->ul_cqi_information.channel; + int UE_id = find_UE_id(mod_idP, rnti); + if (UE_id == -1) { + LOG_W(MAC, "harq_indication: UE %x not found\n", rnti); + return; + } + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; // extract HARQ Information - LOG_D(MAC,"Frame %d, subframe %d: Received harq indication (%d) from UE %d/%x, ul_cqi %d\n",frameP,subframeP,channel,UE_id,rnti,ul_cqi); - if (cc->tdd_Config) extract_harq(mod_idP,CC_idP,UE_id,frameP,subframeP,(void*)&harq_pdu->harq_indication_tdd_rel13,channel); - else extract_harq(mod_idP,CC_idP,UE_id,frameP,subframeP,(void*)&harq_pdu->harq_indication_fdd_rel13,channel); - if (channel == 0) { - sched_ctl->pucch1_snr[CC_idP] = ul_cqi; - sched_ctl->pucch1_cqi_update[CC_idP] = 1; - } + LOG_D(MAC, + "Frame %d, subframe %d: Received harq indication (%d) from UE %d/%x, ul_cqi %d\n", + frameP, subframeP, channel, UE_id, rnti, ul_cqi); + if (cc->tdd_Config) + extract_harq(mod_idP, CC_idP, UE_id, frameP, subframeP, + (void *) &harq_pdu->harq_indication_tdd_rel13, + channel); + else + extract_harq(mod_idP, CC_idP, UE_id, frameP, subframeP, + (void *) &harq_pdu->harq_indication_fdd_rel13, + channel); + if (channel == 0) { + sched_ctl->pucch1_snr[CC_idP] = ul_cqi; + sched_ctl->pucch1_cqi_update[CC_idP] = 1; + } } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 1fcd07c1d3..343d391538 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -29,6 +29,8 @@ */ +/* indented with: indent -kr eNB_scheduler_RA.c */ + #include "assertions.h" #include "PHY/defs.h" #include "PHY/extern.h" @@ -52,7 +54,7 @@ #include "pdcp.h" #if defined(ENABLE_ITTI) -# include "intertask_interface.h" +#include "intertask_interface.h" #endif #include "T.h" @@ -61,645 +63,838 @@ #define DEBUG_eNB_SCHEDULER 1 // This table holds the allowable PRB sizes for ULSCH transmissions -uint8_t rb_table[34] = {1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36,40,45,48,50,54,60,64,72,75,80,81,90,96,100}; +uint8_t rb_table[34] = + { 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, + 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100 +}; -void rx_sdu(const module_id_t enb_mod_idP, - const int CC_idP, - const frame_t frameP, - const sub_frame_t subframeP, - const rnti_t rntiP, - uint8_t *sduP, - const uint16_t sdu_lenP, - const uint16_t timing_advance, - const uint8_t ul_cqi) +void +rx_sdu(const module_id_t enb_mod_idP, + const int CC_idP, + const frame_t frameP, + const sub_frame_t subframeP, + const rnti_t rntiP, + uint8_t * sduP, + const uint16_t sdu_lenP, + const uint16_t timing_advance, const uint8_t ul_cqi) { - int current_rnti = rntiP; - unsigned char rx_ces[MAX_NUM_CE],num_ce,num_sdu,i,*payload_ptr; - unsigned char rx_lcids[NB_RB_MAX]; - unsigned short rx_lengths[NB_RB_MAX]; - int UE_id = find_UE_id(enb_mod_idP, current_rnti); - int RA_id; - int ii,j; - eNB_MAC_INST *eNB = RC.mac[enb_mod_idP]; - int harq_pid = subframe2harqpid(&eNB->common_channels[CC_idP],frameP,subframeP); + int current_rnti = rntiP; + unsigned char rx_ces[MAX_NUM_CE], num_ce, num_sdu, i, *payload_ptr; + unsigned char rx_lcids[NB_RB_MAX]; + unsigned short rx_lengths[NB_RB_MAX]; + int UE_id = find_UE_id(enb_mod_idP, current_rnti); + int RA_id; + int ii, j; + eNB_MAC_INST *mac = RC.mac[enb_mod_idP]; + int harq_pid = + subframe2harqpid(&mac->common_channels[CC_idP], frameP, subframeP); - UE_list_t *UE_list= &eNB->UE_list; - int crnti_rx=0; - int old_buffer_info; - RA_TEMPLATE *RA_template = (RA_TEMPLATE *)&RC.mac[enb_mod_idP]->common_channels[CC_idP].RA_template[0]; - int first_rb = 0; + UE_list_t *UE_list = &mac->UE_list; + int crnti_rx = 0; + int old_buffer_info; + RA_t *ra = + (RA_t *) & RC.mac[enb_mod_idP]->common_channels[CC_idP].ra[0]; + int first_rb = 0; - start_meas(&eNB->rx_ulsch_sdu); + start_meas(&mac->rx_ulsch_sdu); - if ((UE_id > NUMBER_OF_UE_MAX) || (UE_id == -1) ) - for(ii=0; ii NUMBER_OF_UE_MAX) || (UE_id == -1)) + for (ii = 0; ii < NB_RB_MAX; ii++) { + rx_lengths[ii] = 0; + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_RX_SDU, 1); + if (opt_enabled == 1) { + trace_pdu(0, sduP, sdu_lenP, 0, 3, current_rnti, frameP, subframeP, + 0, 0); + LOG_D(OPT, "[eNB %d][ULSCH] Frame %d rnti %x with size %d\n", + enb_mod_idP, frameP, current_rnti, sdu_lenP); } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_SDU,1); - if (opt_enabled == 1) { - trace_pdu(0, sduP,sdu_lenP, 0, 3, current_rnti, frameP, subframeP, 0,0); - LOG_D(OPT,"[eNB %d][ULSCH] Frame %d rnti %x with size %d\n", - enb_mod_idP, frameP, current_rnti, sdu_lenP); - } - - if (UE_id!=-1) { - LOG_D(MAC,"[eNB %d][PUSCH %d] CC_id %d Received ULSCH sdu round %d from PHY (rnti %x, UE_id %d) ul_cqi %d\n",enb_mod_idP,harq_pid,CC_idP, UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid], - current_rnti, UE_id,ul_cqi); - - AssertFatal(UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] < 8, - "round >= 8\n"); - if (sduP!=NULL) { - UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer = 0; - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; - UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= (~(1<UE_sched_ctrl[UE_id].ta_update = - (UE_list->UE_sched_ctrl[UE_id].ta_update * 3 + timing_advance)/4; - UE_list->UE_sched_ctrl[UE_id].pusch_snr[CC_idP] = ul_cqi; - UE_list->UE_sched_ctrl[UE_id].ul_consecutive_errors = 0; - first_rb = UE_list->UE_template[CC_idP][UE_id].first_rb_ul[harq_pid]; - - if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) { - UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync=0; - mac_eNB_rrc_ul_in_sync(enb_mod_idP,CC_idP,frameP,subframeP,UE_RNTI(enb_mod_idP,UE_id)); - } - } - else { // we've got an error - LOG_D(MAC,"[eNB %d][PUSCH %d] CC_id %d ULSCH in error in round %d, ul_cqi %d\n",enb_mod_idP,harq_pid,CC_idP, - UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid],ul_cqi); - - // AssertFatal(1==0,"ulsch in error\n"); - if (UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] == 3) { - UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= (~(1<UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid]=0; - if (UE_list->UE_sched_ctrl[UE_id].ul_consecutive_errors++ == 10) - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 1; - } - else UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid]++; - return; - - } - } - else if ((RA_id = find_RA_id(enb_mod_idP,CC_idP,current_rnti))!=-1) { // Check if this is an RA process for the rnti - AssertFatal(eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx>1, - "maxHARQ %d should be greater than 1\n", - (int)eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx); - - LOG_D(MAC,"[eNB %d][PUSCH %d] CC_id %d Received ULSCH sdu round %d from PHY (rnti %x, RA_id %d) ul_cqi %d\n",enb_mod_idP,harq_pid,CC_idP, - RA_template[RA_id].msg3_round, - current_rnti,RA_id,ul_cqi); - - first_rb = RA_template->msg3_first_rb; - - if (sduP==NULL) { // we've got an error on Msg3 - LOG_D(MAC,"[eNB %d] CC_id %d, RA %d ULSCH in error in round %d/%d\n",enb_mod_idP,CC_idP,RA_id, - RA_template[RA_id].msg3_round, - (int)eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx); - if (RA_template[RA_id].msg3_round == eNB->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx-1) { - cancel_ra_proc(enb_mod_idP,CC_idP,frameP,current_rnti); - } - - else { - first_rb = UE_list->UE_template[CC_idP][UE_id].first_rb_ul[harq_pid]; - RA_template[RA_id].msg3_round++; - // prepare handling of retransmission - RA_template[RA_id].Msg3_frame += ((RA_template[RA_id].Msg3_subframe>1) ? 1 : 0); - RA_template[RA_id].Msg3_subframe = (RA_template[RA_id].Msg3_subframe+8)%10; - add_msg3(enb_mod_idP,CC_idP, &RA_template[RA_id],frameP,subframeP); - } - return; - } - } - else { - LOG_W(MAC,"Cannot find UE or RA corresponding to ULSCH rnti %x, dropping it\n", current_rnti); - return; - } - payload_ptr = parse_ulsch_header(sduP,&num_ce,&num_sdu,rx_ces,rx_lcids,rx_lengths,sdu_lenP); - - T(T_ENB_MAC_UE_UL_PDU, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), - T_INT(harq_pid), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu)); - T(T_ENB_MAC_UE_UL_PDU_WITH_DATA, T_INT(enb_mod_idP), T_INT(CC_idP), T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), - T_INT(harq_pid), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu), T_BUFFER(sduP, sdu_lenP)); - - eNB->eNB_stats[CC_idP].ulsch_bytes_rx=sdu_lenP; - eNB->eNB_stats[CC_idP].total_ulsch_bytes_rx+=sdu_lenP; - eNB->eNB_stats[CC_idP].total_ulsch_pdus_rx+=1; - - UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] = 0; - - // control element - for (i=0; iUE_template[CC_idP][UE_id].phr_info = (payload_ptr[0] & 0x3f) - PHR_MAPPING_OFFSET; - LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : Received PHR PH = %d (db)\n", - enb_mod_idP, CC_idP, rx_ces[i], UE_list->UE_template[CC_idP][UE_id].phr_info); - UE_list->UE_template[CC_idP][UE_id].phr_info_configured=1; - UE_list->UE_sched_ctrl[UE_id].phr_received = 1; - } - payload_ptr+=sizeof(POWER_HEADROOM_CMD); - break; - - case CRNTI: { - int old_rnti = (((uint16_t)payload_ptr[0])<<8) + payload_ptr[1]; - int old_UE_id = find_UE_id(enb_mod_idP, old_rnti); - LOG_D(MAC, "[eNB %d] Frame %d, Subframe %d CC_id %d MAC CE_LCID %d (ce %d/%d): CRNTI %x (UE_id %d) in Msg3\n", - enb_mod_idP, frameP, subframeP, CC_idP, rx_ces[i], i, num_ce, old_rnti, old_UE_id); - if (old_UE_id != -1) { - /* TODO: if the UE did random access (followed by a MAC uplink with - * CRNTI) because none of its scheduling request was granted, then - * according to 36.321 5.4.4 the UE's MAC will notify RRC to release - * PUCCH/SRS. According to 36.331 5.3.13 the UE will then apply - * default configuration for CQI reporting and scheduling requests, - * which basically means that the CQI requests won't work anymore and - * that the UE won't do any scheduling request anymore as long as the - * eNB doesn't reconfigure the UE. - * We have to take care of this. As the code is, nothing is done and - * the UE state in the eNB is wrong. - */ - UE_id = old_UE_id; - UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer = 0; - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; - if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) { - UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 0; - mac_eNB_rrc_ul_in_sync(enb_mod_idP, CC_idP, frameP, subframeP, old_rnti); - } - /* receiving CRNTI means that the current rnti has to go away */ - cancel_ra_proc(enb_mod_idP,CC_idP,frameP,current_rnti); - current_rnti = old_rnti; - } - crnti_rx=1; - payload_ptr+=2; - break; - } - - case TRUNCATED_BSR: - case SHORT_BSR: { - uint8_t lcgid; - lcgid = (payload_ptr[0] >> 6); - - LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", - enb_mod_idP, CC_idP, rx_ces[i], lcgid, payload_ptr[0] & 0x3f); - - if (crnti_rx==1) - LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", - enb_mod_idP, CC_idP, rx_ces[i], lcgid, payload_ptr[0] & 0x3f); - if (UE_id != -1) { - - UE_list->UE_template[CC_idP][UE_id].bsr_info[lcgid] = (payload_ptr[0] & 0x3f); - - // update buffer info - - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[lcgid]]; - - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]; - - RC.eNB[enb_mod_idP][CC_idP]->pusch_stats_bsr[UE_id][(frameP*10)+subframeP] = (payload_ptr[0] & 0x3f); - if (UE_id == UE_list->head) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR,RC.eNB[enb_mod_idP][CC_idP]->pusch_stats_bsr[UE_id][(frameP*10)+subframeP]); - if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[lcgid] == 0 ) { - UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[lcgid]=frameP; - } - if (mac_eNB_get_rrc_status(enb_mod_idP,UE_RNTI(enb_mod_idP,UE_id)) < RRC_CONNECTED) - LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d : ul_total_buffer = %d (lcg increment %d)\n", - enb_mod_idP, CC_idP, rx_ces[i], UE_list->UE_template[CC_idP][UE_id].ul_total_buffer, - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]); - } - else { - - } - payload_ptr += 1;//sizeof(SHORT_BSR); // fixme - } - break; - - case LONG_BSR: - if (UE_id != -1) { - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0] = ((payload_ptr[0] & 0xFC) >> 2); - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1] = - ((payload_ptr[0] & 0x03) << 4) | ((payload_ptr[1] & 0xF0) >> 4); - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2] = - ((payload_ptr[1] & 0x0F) << 2) | ((payload_ptr[2] & 0xC0) >> 6); - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] = (payload_ptr[2] & 0x3F); - - // update buffer info - old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]; - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0]]; - - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; - - old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]; - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1]]; - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; - - old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]; - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2]]; - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; - - old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]; - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]=BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3]]; - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer+= UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; - - LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " - "%u LCGID2 = %u LCGID3 = %u\n", - enb_mod_idP, CC_idP, - rx_ces[i], - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0], - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1], - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2], - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3]); - if (crnti_rx==1) - LOG_D(MAC, "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " - "%u LCGID2 = %u LCGID3 = %u\n", - enb_mod_idP, CC_idP, - rx_ces[i], - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0], - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1], - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2], - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3]); - - if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0] == 0 ) { - UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID0]=0; - } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID0] == 0) { - UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID0]=frameP; - } - - if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1] == 0 ) { - UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID1]=0; - } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID1] == 0) { - UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID1]=frameP; - } - - if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2] == 0 ) { - UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID2]=0; - } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID2] == 0) { - UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID2]=frameP; - } - - if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] == 0 ) { - UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID3]= 0; - } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID3] == 0) { - UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID3]=frameP; - - } - } - - payload_ptr += 3;////sizeof(LONG_BSR); - break; - - default: - LOG_E(MAC, "[eNB %d] CC_id %d Received unknown MAC header (0x%02x)\n", enb_mod_idP, CC_idP, rx_ces[i]); - break; - } - } - - for (i=0; i CCCH_PAYLOAD_SIZE_MAX) { - LOG_E(MAC, "[eNB %d/%d] frame %d received CCCH of size %d (too big, maximum allowed is %d, sdu_len %d), dropping packet\n", - enb_mod_idP, CC_idP, frameP, rx_lengths[i], CCCH_PAYLOAD_SIZE_MAX,sdu_lenP); - break; - } - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, Received CCCH: %x.%x.%x.%x.%x.%x, Terminating RA procedure for UE rnti %x\n", - enb_mod_idP,CC_idP,frameP, - payload_ptr[0],payload_ptr[1],payload_ptr[2],payload_ptr[3],payload_ptr[4], payload_ptr[5], current_rnti); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC,1); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC,0); - for (ii=0; iicommon_channels[CC_idP].RA_template[ii]; - - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Checking proc %d : rnti (%x, %x), active %d\n", - enb_mod_idP, CC_idP, ii, - RA_template->rnti, current_rnti, - RA_template->RA_active); - - if ((RA_template->rnti==current_rnti) && - (RA_template->RA_active==TRUE)) { - - //payload_ptr = parse_ulsch_header(msg3,&num_ce,&num_sdu,rx_ces,rx_lcids,rx_lengths,msg3_len); - - if (UE_id < 0) { - memcpy(&RA_template->cont_res_id[0],payload_ptr,6); - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3: length %d, offset %ld\n", - enb_mod_idP,CC_idP,frameP,rx_lengths[i],payload_ptr-sduP); - - if ((UE_id=add_new_ue(enb_mod_idP,CC_idP,eNB->common_channels[CC_idP].RA_template[ii].rnti,harq_pid - #ifdef Rel14 - ,eNB->common_channels[CC_idP].RA_template[ii].rach_resource_type - #endif - )) == -1 ) { - AssertFatal(1==0,"[MAC][eNB] Max user count reached\n"); - // kill RA procedure - } else - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d Added user with rnti %x => UE %d\n", - enb_mod_idP,CC_idP,frameP,RA_template->rnti,UE_id); - } else { - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3 from already registered UE %d: length %d, offset %ld\n", - enb_mod_idP,CC_idP,frameP,UE_id,rx_lengths[i],payload_ptr-sduP); - // kill RA procedure - } - - mac_rrc_data_ind( - enb_mod_idP, - CC_idP, - frameP,subframeP, - current_rnti, - CCCH, - (uint8_t*)payload_ptr, - rx_lengths[i], - ENB_FLAG_YES, - enb_mod_idP, - 0 - ); - - - if (num_ce >0) { // handle msg3 which is not RRCConnectionRequest - // process_ra_message(msg3,num_ce,rx_lcids,rx_ces); - } - - // prepare transmission of Msg4 - RA_template->generate_Msg4 = 1; - RA_template->wait_ack_Msg4 = 0; - - - - // Program Msg4 PDCCH+DLSCH/MPDCCH transmission 4 subframes from now, // Check if this is ok for BL/CE, or if the rule is different - RA_template->Msg4_frame = frameP + ((subframeP>5) ? 1 : 0); - RA_template->Msg4_subframe = (subframeP+4)%10; - - } // if process is active - } // loop on RA processes - - break ; - - case DCCH : - case DCCH1 : - // if(eNB_mac_inst[module_idP][CC_idP].Dcch_lchan[UE_id].Active==1){ - - -#if defined(ENABLE_MAC_PAYLOAD_DEBUG) - LOG_T(MAC,"offset: %d\n",(unsigned char)((unsigned char*)payload_ptr-sduP)); - for (j=0; j<32; j++) { - LOG_T(MAC,"%x ",payload_ptr[j]); - } - LOG_T(MAC,"\n"); -#endif - - if (UE_id != -1) { - // adjust buffer occupancy of the correponding logical channel group - if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] >= rx_lengths[i]) - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] -= rx_lengths[i]; - else - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] = 0; - - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DCCH, received %d bytes form UE %d on LCID %d \n", - enb_mod_idP,CC_idP,frameP, rx_lengths[i], UE_id, rx_lcids[i]); - - mac_rlc_data_ind( - enb_mod_idP, - current_rnti, - enb_mod_idP, - frameP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - rx_lcids[i], - (char *)payload_ptr, - rx_lengths[i], - 1, - NULL);//(unsigned int*)crc_status); - UE_list->eNB_UE_stats[CC_idP][UE_id].num_pdu_rx[rx_lcids[i]]+=1; - UE_list->eNB_UE_stats[CC_idP][UE_id].num_bytes_rx[rx_lcids[i]]+=rx_lengths[i]; - - - } /* UE_id != -1 */ - - - // } - break; - - // all the DRBS - case DTCH: - default : - -#if defined(ENABLE_MAC_PAYLOAD_DEBUG) - LOG_T(MAC,"offset: %d\n",(unsigned char)((unsigned char*)payload_ptr-sduP)); - for (j=0; j<32; j++) { - LOG_T(MAC,"%x ",payload_ptr[j]); - } - LOG_T(MAC,"\n"); -#endif - if (rx_lcids[i] < NB_RB_MAX ) { - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d\n", - enb_mod_idP,CC_idP,frameP, rx_lengths[i], UE_id, rx_lcids[i]); - - if (UE_id != -1) { - // adjust buffer occupancy of the correponding logical channel group - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d, removing from LCGID %ld, %d\n", - enb_mod_idP,CC_idP,frameP, rx_lengths[i], UE_id,rx_lcids[i], - UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]], - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]]); - - if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] >= rx_lengths[i]) - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] -= rx_lengths[i]; - else - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] = 0; - if ((rx_lengths[i] 0) ) { // MAX SIZE OF transport block - mac_rlc_data_ind( - enb_mod_idP, - current_rnti, - enb_mod_idP, - frameP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - rx_lcids[i], - (char *)payload_ptr, - rx_lengths[i], - 1, - NULL);//(unsigned int*)crc_status); - - UE_list->eNB_UE_stats[CC_idP][UE_id].num_pdu_rx[rx_lcids[i]]+=1; - UE_list->eNB_UE_stats[CC_idP][UE_id].num_bytes_rx[rx_lcids[i]]+=rx_lengths[i]; - } - else { /* rx_length[i] */ - UE_list->eNB_UE_stats[CC_idP][UE_id].num_errors_rx+=1; - LOG_E(MAC,"[eNB %d] CC_id %d Frame %d : Max size of transport block reached LCID %d from UE %d ", - enb_mod_idP, CC_idP, frameP, rx_lcids[i], UE_id); - } - } - else {/*(UE_id != -1*/ - LOG_E(MAC,"[eNB %d] CC_id %d Frame %d : received unsupported or unknown LCID %d from UE %d ", - enb_mod_idP, CC_idP, frameP, rx_lcids[i], UE_id); - } - } - - break; - } - - payload_ptr+=rx_lengths[i]; - } - - // Program ACK for PHICH - LOG_D(MAC,"Programming PHICH ACK for rnti %x harq_pid %d (first_rb %d)\n",current_rnti,harq_pid,first_rb); - nfapi_hi_dci0_request_body_t *hi_dci0_req = &eNB->HI_DCI0_req[CC_idP].hi_dci0_request_body; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &hi_dci0_req->hi_dci0_pdu_list[hi_dci0_req->number_of_dci+hi_dci0_req->number_of_hi]; - memset((void*)hi_dci0_pdu,0,sizeof(nfapi_hi_dci0_request_pdu_t)); - hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; - hi_dci0_pdu->pdu_size = 2+sizeof(nfapi_hi_dci0_hi_pdu); - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = first_rb; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = 0; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 1; - hi_dci0_req->number_of_hi++; - - /* NN--> FK: we could either check the payload, or use a phy helper to detect a false msg3 */ - if ((num_sdu == 0) && (num_ce==0)) { - if (UE_id != -1) - UE_list->eNB_UE_stats[CC_idP][UE_id].total_num_errors_rx+=1; - /* - if (msg3_flagP != NULL) { - if( *msg3_flagP == 1 ) { - LOG_N(MAC,"[eNB %d] CC_id %d frame %d : false msg3 detection: signal phy to canceling RA and remove the UE\n", enb_mod_idP, CC_idP, frameP); - *msg3_flagP=0; - } - }*/ - } else { if (UE_id != -1) { - UE_list->eNB_UE_stats[CC_idP][UE_id].pdu_bytes_rx=sdu_lenP; - UE_list->eNB_UE_stats[CC_idP][UE_id].total_pdu_bytes_rx+=sdu_lenP; - UE_list->eNB_UE_stats[CC_idP][UE_id].total_num_pdus_rx+=1; - } - } + LOG_D(MAC, + "[eNB %d][PUSCH %d] CC_id %d Received ULSCH sdu round %d from PHY (rnti %x, UE_id %d) ul_cqi %d\n", + enb_mod_idP, harq_pid, CC_idP, + UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid], + current_rnti, UE_id, ul_cqi); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_SDU,0); - stop_meas(&eNB->rx_ulsch_sdu); + AssertFatal(UE_list->UE_sched_ctrl[UE_id]. + round_UL[CC_idP][harq_pid] < 8, "round >= 8\n"); + if (sduP != NULL) { + UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer = 0; + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; + UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= + (~(1 << harq_pid)); + /* Update with smoothing: 3/4 of old value and 1/4 of new. + * This is the logic that was done in the function + * lte_est_timing_advance_pusch, maybe it's not necessary? + * maybe it's even not correct at all? + */ + UE_list->UE_sched_ctrl[UE_id].ta_update = + (UE_list->UE_sched_ctrl[UE_id].ta_update * 3 + + timing_advance) / 4; + UE_list->UE_sched_ctrl[UE_id].pusch_snr[CC_idP] = ul_cqi; + UE_list->UE_sched_ctrl[UE_id].ul_consecutive_errors = 0; + first_rb = + UE_list->UE_template[CC_idP][UE_id].first_rb_ul[harq_pid]; + + if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) { + UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 0; + mac_eNB_rrc_ul_in_sync(enb_mod_idP, CC_idP, frameP, + subframeP, UE_RNTI(enb_mod_idP, + UE_id)); + } + } else { // we've got an error + LOG_D(MAC, + "[eNB %d][PUSCH %d] CC_id %d ULSCH in error in round %d, ul_cqi %d\n", + enb_mod_idP, harq_pid, CC_idP, + UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid], + ul_cqi); + + // AssertFatal(1==0,"ulsch in error\n"); + if (UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] == + 3) { + UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= + (~(1 << harq_pid)); + UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] = + 0; + if (UE_list->UE_sched_ctrl[UE_id]. + ul_consecutive_errors++ == 10) + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 1; + } else + UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid]++; + return; + + } + } else if ((RA_id = find_RA_id(enb_mod_idP, CC_idP, current_rnti)) != -1) { // Check if this is an RA process for the rnti + AssertFatal(mac->common_channels[CC_idP]. + radioResourceConfigCommon->rach_ConfigCommon. + maxHARQ_Msg3Tx > 1, + "maxHARQ %d should be greater than 1\n", + (int) mac->common_channels[CC_idP]. + radioResourceConfigCommon->rach_ConfigCommon. + maxHARQ_Msg3Tx); + + LOG_D(MAC, + "[eNB %d][PUSCH %d] CC_id %d Received ULSCH sdu round %d from PHY (rnti %x, RA_id %d) ul_cqi %d\n", + enb_mod_idP, harq_pid, CC_idP, ra[RA_id].msg3_round, + current_rnti, RA_id, ul_cqi); + + first_rb = ra->msg3_first_rb; + + if (sduP == NULL) { // we've got an error on Msg3 + LOG_D(MAC, + "[eNB %d] CC_id %d, RA %d ULSCH in error in round %d/%d\n", + enb_mod_idP, CC_idP, RA_id, + ra[RA_id].msg3_round, + (int) mac->common_channels[CC_idP]. + radioResourceConfigCommon->rach_ConfigCommon. + maxHARQ_Msg3Tx); + if (ra[RA_id].msg3_round == + mac->common_channels[CC_idP].radioResourceConfigCommon-> + rach_ConfigCommon.maxHARQ_Msg3Tx - 1) { + cancel_ra_proc(enb_mod_idP, CC_idP, frameP, current_rnti); + } + + else { + first_rb = + UE_list->UE_template[CC_idP][UE_id]. + first_rb_ul[harq_pid]; + ra[RA_id].msg3_round++; + // prepare handling of retransmission + ra[RA_id].Msg3_frame += + ((ra[RA_id].Msg3_subframe > 1) ? 1 : 0); + ra[RA_id].Msg3_subframe = + (ra[RA_id].Msg3_subframe + 8) % 10; + add_msg3(enb_mod_idP, CC_idP, &ra[RA_id], frameP, + subframeP); + } + return; + } + } else { + LOG_W(MAC, + "Cannot find UE or RA corresponding to ULSCH rnti %x, dropping it\n", + current_rnti); + return; + } + payload_ptr = + parse_ulsch_header(sduP, &num_ce, &num_sdu, rx_ces, rx_lcids, + rx_lengths, sdu_lenP); + + T(T_ENB_MAC_UE_UL_PDU, T_INT(enb_mod_idP), T_INT(CC_idP), + T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), + T_INT(harq_pid), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu)); + T(T_ENB_MAC_UE_UL_PDU_WITH_DATA, T_INT(enb_mod_idP), T_INT(CC_idP), + T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), + T_INT(harq_pid), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu), + T_BUFFER(sduP, sdu_lenP)); + + mac->eNB_stats[CC_idP].ulsch_bytes_rx = sdu_lenP; + mac->eNB_stats[CC_idP].total_ulsch_bytes_rx += sdu_lenP; + mac->eNB_stats[CC_idP].total_ulsch_pdus_rx += 1; + + UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] = 0; + + // control element + for (i = 0; i < num_ce; i++) { + + T(T_ENB_MAC_UE_UL_CE, T_INT(enb_mod_idP), T_INT(CC_idP), + T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), + T_INT(rx_ces[i])); + + switch (rx_ces[i]) { // implement and process BSR + CRNTI + + case POWER_HEADROOM: + if (UE_id != -1) { + UE_list->UE_template[CC_idP][UE_id].phr_info = + (payload_ptr[0] & 0x3f) - PHR_MAPPING_OFFSET; + LOG_D(MAC, + "[eNB %d] CC_id %d MAC CE_LCID %d : Received PHR PH = %d (db)\n", + enb_mod_idP, CC_idP, rx_ces[i], + UE_list->UE_template[CC_idP][UE_id].phr_info); + UE_list->UE_template[CC_idP][UE_id].phr_info_configured = + 1; + UE_list->UE_sched_ctrl[UE_id].phr_received = 1; + } + payload_ptr += sizeof(POWER_HEADROOM_CMD); + break; + + case CRNTI: + { + int old_rnti = + (((uint16_t) payload_ptr[0]) << 8) + payload_ptr[1]; + int old_UE_id = find_UE_id(enb_mod_idP, old_rnti); + LOG_D(MAC, + "[eNB %d] Frame %d, Subframe %d CC_id %d MAC CE_LCID %d (ce %d/%d): CRNTI %x (UE_id %d) in Msg3\n", + enb_mod_idP, frameP, subframeP, CC_idP, rx_ces[i], i, + num_ce, old_rnti, old_UE_id); + if (old_UE_id != -1) { + /* TODO: if the UE did random access (followed by a MAC uplink with + * CRNTI) because none of its scheduling request was granted, then + * according to 36.321 5.4.4 the UE's MAC will notify RRC to release + * PUCCH/SRS. According to 36.331 5.3.13 the UE will then apply + * default configuration for CQI reporting and scheduling requests, + * which basically means that the CQI requests won't work anymore and + * that the UE won't do any scheduling request anymore as long as the + * eNB doesn't reconfigure the UE. + * We have to take care of this. As the code is, nothing is done and + * the UE state in the eNB is wrong. + */ + UE_id = old_UE_id; + UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer = 0; + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; + if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) { + UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 0; + mac_eNB_rrc_ul_in_sync(enb_mod_idP, CC_idP, frameP, + subframeP, old_rnti); + } + /* receiving CRNTI means that the current rnti has to go away */ + cancel_ra_proc(enb_mod_idP, CC_idP, frameP, + current_rnti); + current_rnti = old_rnti; + } + crnti_rx = 1; + payload_ptr += 2; + break; + } + + case TRUNCATED_BSR: + case SHORT_BSR: + { + uint8_t lcgid; + lcgid = (payload_ptr[0] >> 6); + + LOG_D(MAC, + "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", + enb_mod_idP, CC_idP, rx_ces[i], lcgid, + payload_ptr[0] & 0x3f); + + if (crnti_rx == 1) + LOG_D(MAC, + "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", + enb_mod_idP, CC_idP, rx_ces[i], lcgid, + payload_ptr[0] & 0x3f); + if (UE_id != -1) { + + UE_list->UE_template[CC_idP][UE_id].bsr_info[lcgid] = + (payload_ptr[0] & 0x3f); + + // update buffer info + + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[lcgid] = + BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. + bsr_info[lcgid]]; + + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[lcgid]; + + RC.eNB[enb_mod_idP][CC_idP]-> + pusch_stats_bsr[UE_id][(frameP * 10) + subframeP] + = (payload_ptr[0] & 0x3f); + if (UE_id == UE_list->head) + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME + (VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR, + RC.eNB[enb_mod_idP][CC_idP]->pusch_stats_bsr + [UE_id][(frameP * 10) + subframeP]); + if (UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_creation_time[lcgid] + == 0) { + UE_list->UE_template[CC_idP] + [UE_id].ul_buffer_creation_time[lcgid] = + frameP; + } + if (mac_eNB_get_rrc_status + (enb_mod_idP, + UE_RNTI(enb_mod_idP, UE_id)) < RRC_CONNECTED) + LOG_D(MAC, + "[eNB %d] CC_id %d MAC CE_LCID %d : ul_total_buffer = %d (lcg increment %d)\n", + enb_mod_idP, CC_idP, rx_ces[i], + UE_list->UE_template[CC_idP][UE_id]. + ul_total_buffer, + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[lcgid]); + } else { + + } + payload_ptr += 1; //sizeof(SHORT_BSR); // fixme + } + break; + + case LONG_BSR: + if (UE_id != -1) { + UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0] = + ((payload_ptr[0] & 0xFC) >> 2); + UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1] = + ((payload_ptr[0] & 0x03) << 4) | + ((payload_ptr[1] & 0xF0) >> 4); + UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2] = + ((payload_ptr[1] & 0x0F) << 2) | + ((payload_ptr[2] & 0xC0) >> 6); + UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] = + (payload_ptr[2] & 0x3F); + + // update buffer info + old_buffer_info = + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[LCGID0]; + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[LCGID0] = + BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. + bsr_info[LCGID0]]; + + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[LCGID0]; + if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= + old_buffer_info) + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= + old_buffer_info; + else + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = + 0; + + old_buffer_info = + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[LCGID1]; + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[LCGID1] = + BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. + bsr_info[LCGID1]]; + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[LCGID1]; + if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= + old_buffer_info) + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= + old_buffer_info; + else + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = + 0; + + old_buffer_info = + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[LCGID2]; + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[LCGID2] = + BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. + bsr_info[LCGID2]]; + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[LCGID2]; + if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= + old_buffer_info) + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= + old_buffer_info; + else + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = + 0; + + old_buffer_info = + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[LCGID3]; + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[LCGID3] = + BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. + bsr_info[LCGID3]]; + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[LCGID3]; + if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= + old_buffer_info) + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= + old_buffer_info; + else + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = + 0; + + LOG_D(MAC, + "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " + "%u LCGID2 = %u LCGID3 = %u\n", enb_mod_idP, CC_idP, + rx_ces[i], + UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0], + UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1], + UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2], + UE_list->UE_template[CC_idP][UE_id]. + bsr_info[LCGID3]); + if (crnti_rx == 1) + LOG_D(MAC, + "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " + "%u LCGID2 = %u LCGID3 = %u\n", enb_mod_idP, + CC_idP, rx_ces[i], + UE_list->UE_template[CC_idP][UE_id]. + bsr_info[LCGID0], + UE_list->UE_template[CC_idP][UE_id]. + bsr_info[LCGID1], + UE_list->UE_template[CC_idP][UE_id]. + bsr_info[LCGID2], + UE_list->UE_template[CC_idP][UE_id]. + bsr_info[LCGID3]); + + if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0] == + 0) { + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_creation_time[LCGID0] = 0; + } else if (UE_list->UE_template[CC_idP] + [UE_id].ul_buffer_creation_time[LCGID0] == 0) { + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_creation_time[LCGID0] = frameP; + } + + if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1] == + 0) { + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_creation_time[LCGID1] = 0; + } else if (UE_list->UE_template[CC_idP] + [UE_id].ul_buffer_creation_time[LCGID1] == 0) { + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_creation_time[LCGID1] = frameP; + } + + if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2] == + 0) { + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_creation_time[LCGID2] = 0; + } else if (UE_list->UE_template[CC_idP] + [UE_id].ul_buffer_creation_time[LCGID2] == 0) { + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_creation_time[LCGID2] = frameP; + } + + if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] == + 0) { + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_creation_time[LCGID3] = 0; + } else if (UE_list->UE_template[CC_idP] + [UE_id].ul_buffer_creation_time[LCGID3] == 0) { + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_creation_time[LCGID3] = frameP; + + } + } + + payload_ptr += 3; ////sizeof(LONG_BSR); + break; + + default: + LOG_E(MAC, + "[eNB %d] CC_id %d Received unknown MAC header (0x%02x)\n", + enb_mod_idP, CC_idP, rx_ces[i]); + break; + } + } + + for (i = 0; i < num_sdu; i++) { + LOG_D(MAC, "SDU Number %d MAC Subheader SDU_LCID %d, length %d\n", + i, rx_lcids[i], rx_lengths[i]); + + T(T_ENB_MAC_UE_UL_SDU, T_INT(enb_mod_idP), T_INT(CC_idP), + T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), + T_INT(rx_lcids[i]), T_INT(rx_lengths[i])); + T(T_ENB_MAC_UE_UL_SDU_WITH_DATA, T_INT(enb_mod_idP), T_INT(CC_idP), + T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), + T_INT(rx_lcids[i]), T_INT(rx_lengths[i]), T_BUFFER(payload_ptr, + rx_lengths + [i])); + + switch (rx_lcids[i]) { + case CCCH: + if (rx_lengths[i] > CCCH_PAYLOAD_SIZE_MAX) { + LOG_E(MAC, + "[eNB %d/%d] frame %d received CCCH of size %d (too big, maximum allowed is %d, sdu_len %d), dropping packet\n", + enb_mod_idP, CC_idP, frameP, rx_lengths[i], + CCCH_PAYLOAD_SIZE_MAX, sdu_lenP); + break; + } + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d, Received CCCH: %x.%x.%x.%x.%x.%x, Terminating RA procedure for UE rnti %x\n", + enb_mod_idP, CC_idP, frameP, payload_ptr[0], + payload_ptr[1], payload_ptr[2], payload_ptr[3], + payload_ptr[4], payload_ptr[5], current_rnti); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC, 1); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC, 0); + for (ii = 0; ii < NB_RA_PROC_MAX; ii++) { + RA_t *ra = &mac->common_channels[CC_idP].ra[ii]; + + LOG_D(MAC, + "[mac %d][RAPROC] CC_id %d Checking proc %d : rnti (%x, %x), state %d\n", + enb_mod_idP, CC_idP, ii, ra->rnti, + current_rnti, ra->state); + + if ((ra->rnti == current_rnti) && (ra->state != IDLE)) { + + //payload_ptr = parse_ulsch_header(msg3,&num_ce,&num_sdu,rx_ces,rx_lcids,rx_lengths,msg3_len); + + if (UE_id < 0) { + memcpy(&ra->cont_res_id[0], payload_ptr, 6); + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3: length %d, offset %ld\n", + enb_mod_idP, CC_idP, frameP, rx_lengths[i], + payload_ptr - sduP); + + if ((UE_id = + add_new_ue(enb_mod_idP, CC_idP, + mac->common_channels[CC_idP]. + ra[ii].rnti, harq_pid +#ifdef Rel14 + , + mac->common_channels[CC_idP]. + ra[ii].rach_resource_type +#endif + )) == -1) { + AssertFatal(1 == 0, + "[MAC][eNB] Max user count reached\n"); + // kill RA procedure + } else + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d Added user with rnti %x => UE %d\n", + enb_mod_idP, CC_idP, frameP, ra->rnti, + UE_id); + } else { + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3 from already registered UE %d: length %d, offset %ld\n", + enb_mod_idP, CC_idP, frameP, UE_id, + rx_lengths[i], payload_ptr - sduP); + // kill RA procedure + } + + mac_rrc_data_ind(enb_mod_idP, + CC_idP, + frameP, subframeP, + current_rnti, + CCCH, + (uint8_t *) payload_ptr, + rx_lengths[i], + ENB_FLAG_YES, enb_mod_idP, 0); + + + if (num_ce > 0) { // handle msg3 which is not RRCConnectionRequest + // process_ra_message(msg3,num_ce,rx_lcids,rx_ces); + } + // prepare transmission of Msg4 + ra->state = MSG4; + + + + // Program Msg4 PDCCH+DLSCH/MPDCCH transmission 4 subframes from now, // Check if this is ok for BL/CE, or if the rule is different + ra->Msg4_frame = frameP + ((subframeP > 5) ? 1 : 0); + ra->Msg4_subframe = (subframeP + 4) % 10; + + } // if process is active + } // loop on RA processes + + break; + + case DCCH: + case DCCH1: + // if(eNB_mac_inst[module_idP][CC_idP].Dcch_lchan[UE_id].Active==1){ + + +#if defined(ENABLE_MAC_PAYLOAD_DEBUG) + LOG_T(MAC, "offset: %d\n", + (unsigned char) ((unsigned char *) payload_ptr - sduP)); + for (j = 0; j < 32; j++) { + LOG_T(MAC, "%x ", payload_ptr[j]); + } + LOG_T(MAC, "\n"); +#endif + + if (UE_id != -1) { + // adjust buffer occupancy of the correponding logical channel group + if (UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[UE_list->UE_template[CC_idP] + [UE_id].lcgidmap[rx_lcids[i]]] >= + rx_lengths[i]) + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[UE_list->UE_template[CC_idP] + [UE_id].lcgidmap[rx_lcids[i]]] -= + rx_lengths[i]; + else + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[UE_list->UE_template[CC_idP] + [UE_id].lcgidmap[rx_lcids[i]]] = 0; + + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DCCH, received %d bytes form UE %d on LCID %d \n", + enb_mod_idP, CC_idP, frameP, rx_lengths[i], UE_id, + rx_lcids[i]); + + mac_rlc_data_ind(enb_mod_idP, current_rnti, enb_mod_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, rx_lcids[i], (char *) payload_ptr, rx_lengths[i], 1, NULL); //(unsigned int*)crc_status); + UE_list->eNB_UE_stats[CC_idP][UE_id]. + num_pdu_rx[rx_lcids[i]] += 1; + UE_list->eNB_UE_stats[CC_idP][UE_id]. + num_bytes_rx[rx_lcids[i]] + += rx_lengths[i]; + + + } + + /* UE_id != -1 */ + // } + break; + + // all the DRBS + case DTCH: + default: + +#if defined(ENABLE_MAC_PAYLOAD_DEBUG) + LOG_T(MAC, "offset: %d\n", + (unsigned char) ((unsigned char *) payload_ptr - sduP)); + for (j = 0; j < 32; j++) { + LOG_T(MAC, "%x ", payload_ptr[j]); + } + LOG_T(MAC, "\n"); +#endif + if (rx_lcids[i] < NB_RB_MAX) { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d\n", + enb_mod_idP, CC_idP, frameP, rx_lengths[i], UE_id, + rx_lcids[i]); + + if (UE_id != -1) { + // adjust buffer occupancy of the correponding logical channel group + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d, removing from LCGID %ld, %d\n", + enb_mod_idP, CC_idP, frameP, rx_lengths[i], + UE_id, rx_lcids[i], + UE_list->UE_template[CC_idP][UE_id]. + lcgidmap[rx_lcids[i]], + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[UE_list->UE_template[CC_idP] + [UE_id].lcgidmap[rx_lcids[i]]]); + + if (UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[UE_list->UE_template[CC_idP] + [UE_id].lcgidmap[rx_lcids[i]]] + >= rx_lengths[i]) + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[UE_list->UE_template[CC_idP] + [UE_id].lcgidmap[rx_lcids[i]]] + -= rx_lengths[i]; + else + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info + [UE_list->UE_template[CC_idP][UE_id].lcgidmap + [rx_lcids[i]]] = 0; + if ((rx_lengths[i] < SCH_PAYLOAD_SIZE_MAX) + && (rx_lengths[i] > 0)) { // MAX SIZE OF transport block + mac_rlc_data_ind(enb_mod_idP, current_rnti, enb_mod_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, rx_lcids[i], (char *) payload_ptr, rx_lengths[i], 1, NULL); //(unsigned int*)crc_status); + + UE_list->eNB_UE_stats[CC_idP][UE_id]. + num_pdu_rx[rx_lcids[i]] += 1; + UE_list->eNB_UE_stats[CC_idP][UE_id]. + num_bytes_rx[rx_lcids[i]] += rx_lengths[i]; + } else { /* rx_length[i] */ + UE_list->eNB_UE_stats[CC_idP][UE_id]. + num_errors_rx += 1; + LOG_E(MAC, + "[eNB %d] CC_id %d Frame %d : Max size of transport block reached LCID %d from UE %d ", + enb_mod_idP, CC_idP, frameP, rx_lcids[i], + UE_id); + } + } else { /*(UE_id != -1 */ + LOG_E(MAC, + "[eNB %d] CC_id %d Frame %d : received unsupported or unknown LCID %d from UE %d ", + enb_mod_idP, CC_idP, frameP, rx_lcids[i], UE_id); + } + } + + break; + } + + payload_ptr += rx_lengths[i]; + } + + // Program ACK for PHICH + LOG_D(MAC, + "Programming PHICH ACK for rnti %x harq_pid %d (first_rb %d)\n", + current_rnti, harq_pid, first_rb); + nfapi_hi_dci0_request_body_t *hi_dci0_req = + &mac->HI_DCI0_req[CC_idP].hi_dci0_request_body; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = + &hi_dci0_req->hi_dci0_pdu_list[hi_dci0_req->number_of_dci + + hi_dci0_req->number_of_hi]; + memset((void *) hi_dci0_pdu, 0, sizeof(nfapi_hi_dci0_request_pdu_t)); + hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; + hi_dci0_pdu->pdu_size = 2 + sizeof(nfapi_hi_dci0_hi_pdu); + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = first_rb; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = 0; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 1; + hi_dci0_req->number_of_hi++; + + /* NN--> FK: we could either check the payload, or use a phy helper to detect a false msg3 */ + if ((num_sdu == 0) && (num_ce == 0)) { + if (UE_id != -1) + UE_list->eNB_UE_stats[CC_idP][UE_id].total_num_errors_rx += 1; + /* + if (msg3_flagP != NULL) { + if( *msg3_flagP == 1 ) { + LOG_N(MAC,"[eNB %d] CC_id %d frame %d : false msg3 detection: signal phy to canceling RA and remove the UE\n", enb_mod_idP, CC_idP, frameP); + *msg3_flagP=0; + } + } */ + } else { + if (UE_id != -1) { + UE_list->eNB_UE_stats[CC_idP][UE_id].pdu_bytes_rx = sdu_lenP; + UE_list->eNB_UE_stats[CC_idP][UE_id].total_pdu_bytes_rx += + sdu_lenP; + UE_list->eNB_UE_stats[CC_idP][UE_id].total_num_pdus_rx += 1; + } + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_RX_SDU, 0); + stop_meas(&mac->rx_ulsch_sdu); } uint32_t bytes_to_bsr_index(int32_t nbytes) { - uint32_t i=0; + uint32_t i = 0; - if (nbytes<0) { - return(0); - } + if (nbytes < 0) { + return (0); + } - while ((iE == 0) { - not_done = 0; + if (((SCH_SUBHEADER_FIXED *) mac_header_ptr)->E == 0) { + not_done = 0; + } + + lcid = ((SCH_SUBHEADER_FIXED *) mac_header_ptr)->LCID; + + if (lcid < EXTENDED_POWER_HEADROOM) { + if (not_done == 0) { // last MAC SDU, length is implicit + mac_header_ptr++; + length = + tb_length - (mac_header_ptr - mac_header) - ce_len; + + for (num_sdu_cnt = 0; num_sdu_cnt < num_sdus; + num_sdu_cnt++) { + length -= rx_lengths[num_sdu_cnt]; + } + } else { + if (((SCH_SUBHEADER_SHORT *) mac_header_ptr)->F == 0) { + length = ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->L; + mac_header_ptr += 2; //sizeof(SCH_SUBHEADER_SHORT); + } else { // F = 1 + length = + ((((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB & + 0x7f) << 8) | (((SCH_SUBHEADER_LONG *) + mac_header_ptr)->L_LSB & 0xff); + mac_header_ptr += 3; //sizeof(SCH_SUBHEADER_LONG); + } + } + + LOG_D(MAC, + "[eNB] sdu %d lcid %d tb_length %d length %d (offset now %ld)\n", + num_sdus, lcid, tb_length, length, + mac_header_ptr - mac_header); + rx_lcids[num_sdus] = lcid; + rx_lengths[num_sdus] = length; + num_sdus++; + } else { // This is a control element subheader POWER_HEADROOM, BSR and CRNTI + if (lcid == SHORT_PADDING) { + mac_header_ptr++; + } else { + rx_ces[num_ces] = lcid; + num_ces++; + mac_header_ptr++; + + if (lcid == LONG_BSR) { + ce_len += 3; + } else if (lcid == CRNTI) { + ce_len += 2; + } else if ((lcid == POWER_HEADROOM) + || (lcid == TRUNCATED_BSR) + || (lcid == SHORT_BSR)) { + ce_len++; + } else { + LOG_E(MAC, "unknown CE %d \n", lcid); + AssertFatal(1 == 0, "unknown CE"); + } + } + } } - lcid = ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID; + *num_ce = num_ces; + *num_sdu = num_sdus; - if (lcid < EXTENDED_POWER_HEADROOM) { - if (not_done==0) { // last MAC SDU, length is implicit - mac_header_ptr++; - length = tb_length-(mac_header_ptr-mac_header)-ce_len; - - for (num_sdu_cnt=0; num_sdu_cnt < num_sdus ; num_sdu_cnt++) { - length -= rx_lengths[num_sdu_cnt]; - } - } else { - if (((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F == 0) { - length = ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L; - mac_header_ptr += 2;//sizeof(SCH_SUBHEADER_SHORT); - } else { // F = 1 - length = ((((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_MSB & 0x7f ) << 8 ) | (((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB & 0xff); - mac_header_ptr += 3;//sizeof(SCH_SUBHEADER_LONG); - } - } - - LOG_D(MAC,"[eNB] sdu %d lcid %d tb_length %d length %d (offset now %ld)\n", - num_sdus,lcid,tb_length, length,mac_header_ptr-mac_header); - rx_lcids[num_sdus] = lcid; - rx_lengths[num_sdus] = length; - num_sdus++; - } else { // This is a control element subheader POWER_HEADROOM, BSR and CRNTI - if (lcid == SHORT_PADDING) { - mac_header_ptr++; - } else { - rx_ces[num_ces] = lcid; - num_ces++; - mac_header_ptr++; - - if (lcid==LONG_BSR) { - ce_len+=3; - } else if (lcid==CRNTI) { - ce_len+=2; - } else if ((lcid==POWER_HEADROOM) || (lcid==TRUNCATED_BSR)|| (lcid== SHORT_BSR)) { - ce_len++; - } else { - LOG_E(MAC,"unknown CE %d \n", lcid); - AssertFatal(1==0,"unknown CE"); - } - } - } - } - - *num_ce = num_ces; - *num_sdu = num_sdus; - - return(mac_header_ptr); + return (mac_header_ptr); } /* This function is called by PHY layer when it schedules some @@ -707,538 +902,629 @@ unsigned char *parse_ulsch_header(unsigned char *mac_header, * The MAC scheduler has to skip the RBs used by this message 3 * (done below in schedule_ulsch). */ -void set_msg3_subframe(module_id_t Mod_id, - int CC_id, - int frame, - int subframe, - int rnti, - int Msg3_frame, - int Msg3_subframe) +void +set_msg3_subframe(module_id_t Mod_id, + int CC_id, + int frame, + int subframe, int rnti, int Msg3_frame, + int Msg3_subframe) { - eNB_MAC_INST *eNB=RC.mac[Mod_id]; - int i; - for (i=0; icommon_channels[CC_id].RA_template[i].RA_active == TRUE && - eNB->common_channels[CC_id].RA_template[i].rnti == rnti) { - eNB->common_channels[CC_id].RA_template[i].Msg3_subframe = Msg3_subframe; - break; + eNB_MAC_INST *mac = RC.mac[Mod_id]; + int i; + for (i = 0; i < NB_RA_PROC_MAX; i++) { + if (mac->common_channels[CC_id].ra[i].state != IDLE && + mac->common_channels[CC_id].ra[i].rnti == rnti) { + mac->common_channels[CC_id].ra[i].Msg3_subframe = + Msg3_subframe; + break; + } } - } } -void schedule_ulsch(module_id_t module_idP, - frame_t frameP, - sub_frame_t subframeP) +void +schedule_ulsch(module_id_t module_idP, frame_t frameP, + sub_frame_t subframeP) { - uint16_t first_rb[MAX_NUM_CCs],i; - int CC_id; - eNB_MAC_INST *eNB=RC.mac[module_idP]; - COMMON_channels_t *cc; + uint16_t first_rb[MAX_NUM_CCs], i; + int CC_id; + eNB_MAC_INST *mac = RC.mac[module_idP]; + COMMON_channels_t *cc; - start_meas(&eNB->schedule_ulsch); + start_meas(&mac->schedule_ulsch); - int sched_subframe = (subframeP+4)%10; + int sched_subframe = (subframeP + 4) % 10; - cc = &eNB->common_channels[0]; - int tdd_sfa; - // for TDD: check subframes where we have to act and return if nothing should be done now - if (cc->tdd_Config) { - tdd_sfa = cc->tdd_Config->subframeAssignment; - switch (subframeP) { - case 0: - if ((tdd_sfa == 0)|| - (tdd_sfa == 3)|| - (tdd_sfa == 6)) sched_subframe = 4; - else return; - break; - case 1: - if ((tdd_sfa==0)|| - (tdd_sfa==1)) sched_subframe = 7; - else if (tdd_sfa==6) sched_subframe = 8; - break; - default: - return; + cc = &mac->common_channels[0]; + int tdd_sfa; + // for TDD: check subframes where we have to act and return if nothing should be done now + if (cc->tdd_Config) { + tdd_sfa = cc->tdd_Config->subframeAssignment; + switch (subframeP) { + case 0: + if ((tdd_sfa == 0) || (tdd_sfa == 3) || (tdd_sfa == 6)) + sched_subframe = 4; + else + return; + break; + case 1: + if ((tdd_sfa == 0) || (tdd_sfa == 1)) + sched_subframe = 7; + else if (tdd_sfa == 6) + sched_subframe = 8; + break; + default: + return; - case 2: // Don't schedule UL in subframe 2 for TDD - return; - case 3: - if (tdd_sfa==2) sched_subframe = 7; - else return; - break; - case 4: - if (tdd_sfa==1) sched_subframe = 8; - else return; - break; - case 5: - if (tdd_sfa==0) sched_subframe = 9; - else if (tdd_sfa==6) sched_subframe = 3; - else return; - break; - case 6: - if (tdd_sfa==1) sched_subframe = 2; - else if (tdd_sfa==6) sched_subframe = 3; - else return; - break; - case 7: - return; - case 8: - if ((tdd_sfa>=2) || (tdd_sfa<=5)) sched_subframe=2; - else return; - break; - case 9: - if ((tdd_sfa==1) || (tdd_sfa==3) || (tdd_sfa==4)) sched_subframe=3; - else if (tdd_sfa==6) sched_subframe=4; - else return; - break; + case 2: // Don't schedule UL in subframe 2 for TDD + return; + case 3: + if (tdd_sfa == 2) + sched_subframe = 7; + else + return; + break; + case 4: + if (tdd_sfa == 1) + sched_subframe = 8; + else + return; + break; + case 5: + if (tdd_sfa == 0) + sched_subframe = 9; + else if (tdd_sfa == 6) + sched_subframe = 3; + else + return; + break; + case 6: + if (tdd_sfa == 1) + sched_subframe = 2; + else if (tdd_sfa == 6) + sched_subframe = 3; + else + return; + break; + case 7: + return; + case 8: + if ((tdd_sfa >= 2) || (tdd_sfa <= 5)) + sched_subframe = 2; + else + return; + break; + case 9: + if ((tdd_sfa == 1) || (tdd_sfa == 3) || (tdd_sfa == 4)) + sched_subframe = 3; + else if (tdd_sfa == 6) + sched_subframe = 4; + else + return; + break; + } } - } - for (CC_id=0; CC_idRA_template[i].RA_active == TRUE) && - (cc->RA_template[i].generate_rar == 0) && - (cc->RA_template[i].generate_Msg4 == 0) && - (cc->RA_template[i].wait_ack_Msg4 == 0) && - (cc->RA_template[i].Msg3_subframe == sched_subframe)) { - first_rb[CC_id]++; - // cc->RA_template[i].Msg3_subframe = -1; - break; - } + for (i = 0; i < NB_RA_PROC_MAX; i++) { + if ((cc->ra[i].state == WAITMSG3) && + (cc->ra[i].Msg3_subframe == sched_subframe)) { + first_rb[CC_id]++; + // cc->ray[i].Msg3_subframe = -1; + break; + } + } } - } - schedule_ulsch_rnti(module_idP, frameP, subframeP, sched_subframe,first_rb); + schedule_ulsch_rnti(module_idP, frameP, subframeP, sched_subframe, + first_rb); - stop_meas(&eNB->schedule_ulsch); + stop_meas(&mac->schedule_ulsch); } -void schedule_ulsch_rnti(module_id_t module_idP, - frame_t frameP, - sub_frame_t subframeP, - unsigned char sched_subframeP, - uint16_t *first_rb) +void +schedule_ulsch_rnti(module_id_t module_idP, + frame_t frameP, + sub_frame_t subframeP, + unsigned char sched_subframeP, uint16_t * first_rb) { - int UE_id; - uint8_t aggregation = 2; - rnti_t rnti = -1; - uint8_t round = 0; - uint8_t harq_pid = 0; - uint8_t status = 0; - uint8_t rb_table_index = -1; - uint32_t cqi_req,cshift,ndi,tpc; - int32_t normalized_rx_power; - int32_t target_rx_power=-90; - static int32_t tpc_accumulated=0; - int n; - int CC_id = 0; - int drop_ue=0; - int N_RB_UL; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = eNB->common_channels; - UE_list_t *UE_list=&eNB->UE_list; - UE_TEMPLATE *UE_template; - UE_sched_ctrl *UE_sched_ctrl; - int sched_frame=frameP; - int rvidx_tab[4] = {0,2,3,1}; + int UE_id; + uint8_t aggregation = 2; + rnti_t rnti = -1; + uint8_t round = 0; + uint8_t harq_pid = 0; + uint8_t status = 0; + uint8_t rb_table_index = -1; + uint32_t cqi_req, cshift, ndi, tpc; + int32_t normalized_rx_power; + int32_t target_rx_power = -90; + static int32_t tpc_accumulated = 0; + int n; + int CC_id = 0; + int drop_ue = 0; + int N_RB_UL; + eNB_MAC_INST *mac = RC.mac[module_idP]; + COMMON_channels_t *cc = mac->common_channels; + UE_list_t *UE_list = &mac->UE_list; + UE_TEMPLATE *UE_template; + UE_sched_ctrl *UE_sched_ctrl; + int sched_frame = frameP; + int rvidx_tab[4] = { 0, 2, 3, 1 }; - if (sched_subframePHI_DCI0_req[CC_id].hi_dci0_request_body; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu; + nfapi_hi_dci0_request_body_t *hi_dci0_req = + &mac->HI_DCI0_req[CC_id].hi_dci0_request_body; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu; - nfapi_ul_config_request_body_t *ul_req_tmp = &eNB->UL_req_tmp[CC_id][sched_subframeP].ul_config_request_body; + nfapi_ul_config_request_body_t *ul_req_tmp = + &mac->UL_req_tmp[CC_id][sched_subframeP].ul_config_request_body; - LOG_D(MAC,"entering ulsch preprocesor\n"); - ulsch_scheduler_pre_processor(module_idP, - frameP, - subframeP, - first_rb); + LOG_D(MAC, "entering ulsch preprocesor\n"); + ulsch_scheduler_pre_processor(module_idP, frameP, subframeP, first_rb); - LOG_D(MAC,"exiting ulsch preprocesor\n"); + LOG_D(MAC, "exiting ulsch preprocesor\n"); - eNB->HI_DCI0_req[CC_id].sfn_sf = (frameP<<4)+subframeP; + mac->HI_DCI0_req[CC_id].sfn_sf = (frameP << 4) + subframeP; - // loop over all active UEs - for (UE_id=UE_list->head_ul; UE_id>=0; UE_id=UE_list->next_ul[UE_id]) { + // loop over all active UEs + for (UE_id = UE_list->head_ul; UE_id >= 0; + UE_id = UE_list->next_ul[UE_id]) { - // don't schedule if Msg4 is not received yet - if (UE_list->UE_template[UE_PCCID(module_idP,UE_id)][UE_id].configured==FALSE) { - LOG_D(MAC,"[eNB %d] frame %d subfarme %d, UE %d: not configured, skipping UE scheduling \n", - module_idP,frameP,subframeP,UE_id); - continue; - } + // don't schedule if Msg4 is not received yet + if (UE_list->UE_template[UE_PCCID(module_idP, UE_id)][UE_id]. + configured == FALSE) { + LOG_D(MAC, + "[eNB %d] frame %d subfarme %d, UE %d: not configured, skipping UE scheduling \n", + module_idP, frameP, subframeP, UE_id); + continue; + } - rnti = UE_RNTI(module_idP,UE_id); + rnti = UE_RNTI(module_idP, UE_id); - if (rnti==NOT_A_RNTI) { - LOG_W(MAC,"[eNB %d] frame %d subfarme %d, UE %d: no RNTI \n", module_idP,frameP,subframeP,UE_id); - continue; - } + if (rnti == NOT_A_RNTI) { + LOG_W(MAC, "[eNB %d] frame %d subfarme %d, UE %d: no RNTI \n", + module_idP, frameP, subframeP, UE_id); + continue; + } - drop_ue = 0; - /* let's drop the UE if get_eNB_UE_stats returns NULL when calling it with any of the UE's active UL CCs */ - /* TODO: refine? + drop_ue = 0; + /* let's drop the UE if get_eNB_UE_stats returns NULL when calling it with any of the UE's active UL CCs */ + /* TODO: refine? - for (n=0; nnumactiveULCCs[UE_id]; n++) { - CC_id = UE_list->ordered_ULCCids[n][UE_id]; + for (n=0; nnumactiveULCCs[UE_id]; n++) { + CC_id = UE_list->ordered_ULCCids[n][UE_id]; - if (mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti) == NULL) { - LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: no PHY context\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id); - drop_ue = 1; - break; - } - }*/ - if (drop_ue == 1) { + if (mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti) == NULL) { + LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: no PHY context\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id); + drop_ue = 1; + break; + } + } */ + if (drop_ue == 1) { /* we can't come here, ulsch_scheduler_pre_processor won't put in the list a UE with no PHY context */ -abort(); - /* TODO: this is a hack. Sometimes the UE has no PHY context but - * is still present in the MAC with 'ul_failure_timer' = 0 and - * 'ul_out_of_sync' = 0. It seems wrong and the UE stays there forever. Let's - * start an UL out of sync procedure in this case. - * The root cause of this problem has to be found and corrected. - * In the meantime, this hack... - */ - if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 0 && - UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 0) { - LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: UE in weird state, let's put it 'out of sync'\n", - module_idP,frameP,subframeP,UE_id,rnti,CC_id); - // inform RRC of failure and clear timer - mac_eNB_rrc_ul_failure(module_idP,CC_id,frameP,subframeP,rnti); - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer=0; - UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync=1; - } - continue; - } + abort(); + /* TODO: this is a hack. Sometimes the UE has no PHY context but + * is still present in the MAC with 'ul_failure_timer' = 0 and + * 'ul_out_of_sync' = 0. It seems wrong and the UE stays there forever. Let's + * start an UL out of sync procedure in this case. + * The root cause of this problem has to be found and corrected. + * In the meantime, this hack... + */ + if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 0 && + UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 0) { + LOG_W(MAC, + "[eNB %d] frame %d subframe %d, UE %d/%x CC %d: UE in weird state, let's put it 'out of sync'\n", + module_idP, frameP, subframeP, UE_id, rnti, CC_id); + // inform RRC of failure and clear timer + mac_eNB_rrc_ul_failure(module_idP, CC_id, frameP, + subframeP, rnti); + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; + UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 1; + } + continue; + } + // loop over all active UL CC_ids for this UE + for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; + N_RB_UL = to_prb(cc[CC_id].ul_Bandwidth); - // loop over all active UL CC_ids for this UE - for (n=0; nnumactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - N_RB_UL = to_prb(cc[CC_id].ul_Bandwidth); + /* + aggregation=get_aggregation(get_bw_index(module_idP,CC_id), + eNB_UE_stats->dl_cqi, + format0); + */ - /* - aggregation=get_aggregation(get_bw_index(module_idP,CC_id), - eNB_UE_stats->dl_cqi, - format0); - */ + if (CCE_allocation_infeasible + (module_idP, CC_id, 1, subframeP, aggregation, rnti)) { + LOG_W(MAC, + "[eNB %d] frame %d subframe %d, UE %d/%x CC %d: not enough nCCE\n", + module_idP, frameP, subframeP, UE_id, rnti, CC_id); + continue; // break; + } - if (CCE_allocation_infeasible(module_idP,CC_id,1,subframeP,aggregation,rnti)) { - LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: not enough nCCE\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id); - continue; // break; - } + /* be sure that there are some free RBs */ + if (first_rb[CC_id] >= N_RB_UL - 1) { + LOG_W(MAC, + "[eNB %d] frame %d subframe %d, UE %d/%x CC %d: dropping, not enough RBs\n", + module_idP, frameP, subframeP, UE_id, rnti, CC_id); + continue; + } + // if (eNB_UE_stats->mode == PUSCH) { // ue has a ulsch channel - /* be sure that there are some free RBs */ - if (first_rb[CC_id] >= N_RB_UL-1) { - LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: dropping, not enough RBs\n", - module_idP,frameP,subframeP,UE_id,rnti,CC_id); - continue; - } + UE_template = &UE_list->UE_template[CC_id][UE_id]; + UE_sched_ctrl = &UE_list->UE_sched_ctrl[UE_id]; + harq_pid = + subframe2harqpid(&cc[CC_id], sched_frame, sched_subframeP); + round = UE_sched_ctrl->round_UL[CC_id][harq_pid]; + AssertFatal(round < 8, "round %d > 7 for UE %d/%x\n", round, + UE_id, rnti); + LOG_D(MAC, + "[eNB %d] frame %d subframe %d,Checking PUSCH %d for UE %d/%x CC %d : aggregation level %d, N_RB_UL %d\n", + module_idP, frameP, subframeP, harq_pid, UE_id, rnti, + CC_id, aggregation, N_RB_UL); - // if (eNB_UE_stats->mode == PUSCH) { // ue has a ulsch channel + RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP * + 10) + + subframeP] = + UE_template->ul_total_buffer; + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME + (VCD_SIGNAL_DUMPER_VARIABLES_UE0_BO, + RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP * + 10) + + subframeP]); + if (UE_is_to_be_scheduled(module_idP, CC_id, UE_id) > 0 || round > 0) // || ((frameP%10)==0)) + // if there is information on bsr of DCCH, DTCH or if there is UL_SR, or if there is a packet to retransmit, or we want to schedule a periodic feedback every 10 frames + { + LOG_D(MAC, + "[eNB %d][PUSCH %d] Frame %d subframe %d Scheduling UE %d/%x in round %d(SR %d,UL_inactivity timer %d,UL_failure timer %d,cqi_req_timer %d)\n", + module_idP, harq_pid, frameP, subframeP, UE_id, rnti, + round, UE_template->ul_SR, + UE_sched_ctrl->ul_inactivity_timer, + UE_sched_ctrl->ul_failure_timer, + UE_sched_ctrl->cqi_req_timer); + // reset the scheduling request + UE_template->ul_SR = 0; + status = mac_eNB_get_rrc_status(module_idP, rnti); + if (status < RRC_CONNECTED) + cqi_req = 0; + else if (UE_sched_ctrl->cqi_req_timer > 30) { + cqi_req = 1; + UE_sched_ctrl->cqi_req_timer = 0; + } else + cqi_req = 0; - UE_template = &UE_list->UE_template[CC_id][UE_id]; - UE_sched_ctrl = &UE_list->UE_sched_ctrl[UE_id]; - harq_pid = subframe2harqpid(&cc[CC_id],sched_frame,sched_subframeP); - round = UE_sched_ctrl->round_UL[CC_id][harq_pid]; - AssertFatal(round<8,"round %d > 7 for UE %d/%x\n",round,UE_id,rnti); - LOG_D(MAC,"[eNB %d] frame %d subframe %d,Checking PUSCH %d for UE %d/%x CC %d : aggregation level %d, N_RB_UL %d\n", - module_idP,frameP,subframeP,harq_pid,UE_id,rnti,CC_id, aggregation,N_RB_UL); + //power control + //compute the expected ULSCH RX power (for the stats) - RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP*10)+subframeP] = UE_template->ul_total_buffer; - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BO,RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP*10)+subframeP]); - if (UE_is_to_be_scheduled(module_idP,CC_id,UE_id) > 0 || round > 0)// || ((frameP%10)==0)) - // if there is information on bsr of DCCH, DTCH or if there is UL_SR, or if there is a packet to retransmit, or we want to schedule a periodic feedback every 10 frames - { - LOG_D(MAC,"[eNB %d][PUSCH %d] Frame %d subframe %d Scheduling UE %d/%x in round %d(SR %d,UL_inactivity timer %d,UL_failure timer %d,cqi_req_timer %d)\n", - module_idP,harq_pid,frameP,subframeP,UE_id,rnti,round,UE_template->ul_SR, - UE_sched_ctrl->ul_inactivity_timer, + // this is the normalized RX power and this should be constant (regardless of mcs + normalized_rx_power = UE_sched_ctrl->pusch_snr[CC_id]; + target_rx_power = 178; - UE_sched_ctrl->ul_failure_timer, + // this assumes accumulated tpc + // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out + int32_t framex10psubframe = + UE_template->pusch_tpc_tx_frame * 10 + + UE_template->pusch_tpc_tx_subframe; + if (((framex10psubframe + 10) <= (frameP * 10 + subframeP)) || //normal case + ((framex10psubframe > (frameP * 10 + subframeP)) && (((10240 - framex10psubframe + frameP * 10 + subframeP) >= 10)))) //frame wrap-around + { + UE_template->pusch_tpc_tx_frame = frameP; + UE_template->pusch_tpc_tx_subframe = subframeP; + if (normalized_rx_power > (target_rx_power + 4)) { + tpc = 0; //-1 + tpc_accumulated--; + } else if (normalized_rx_power < (target_rx_power - 4)) { + tpc = 2; //+1 + tpc_accumulated++; + } else { + tpc = 1; //0 + } + } else { + tpc = 1; //0 + } + //tpc = 1; + if (tpc != 1) { + LOG_D(MAC, + "[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", + module_idP, frameP, subframeP, harq_pid, tpc, + tpc_accumulated, normalized_rx_power, + target_rx_power); + } + // new transmission + if (round == 0) { - UE_sched_ctrl->cqi_req_timer); - // reset the scheduling request - UE_template->ul_SR = 0; - status = mac_eNB_get_rrc_status(module_idP,rnti); - if (status < RRC_CONNECTED) - cqi_req = 0; - else if (UE_sched_ctrl->cqi_req_timer>30) { - cqi_req = 1; - UE_sched_ctrl->cqi_req_timer=0; - } - else - cqi_req = 0; + ndi = 1 - UE_template->oldNDI_UL[harq_pid]; + UE_template->oldNDI_UL[harq_pid] = ndi; + UE_list->eNB_UE_stats[CC_id][UE_id]. + normalized_rx_power = normalized_rx_power; + UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power = + target_rx_power; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1 = + UE_template->pre_assigned_mcs_ul; + UE_template->mcs_UL[harq_pid] = UE_template->pre_assigned_mcs_ul; //cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS + if (UE_template->pre_allocated_rb_table_index_ul >= 0) { + rb_table_index = + UE_template->pre_allocated_rb_table_index_ul; + } else { + UE_template->mcs_UL[harq_pid] = 10; //cmin (10, openair_daq_vars.target_ue_ul_mcs); + rb_table_index = 5; // for PHR + } - //power control - //compute the expected ULSCH RX power (for the stats) - - // this is the normalized RX power and this should be constant (regardless of mcs - normalized_rx_power = UE_sched_ctrl->pusch_snr[CC_id]; - target_rx_power = 178; - - // this assumes accumulated tpc - // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out - int32_t framex10psubframe = UE_template->pusch_tpc_tx_frame*10+UE_template->pusch_tpc_tx_subframe; - if (((framex10psubframe+10)<=(frameP*10+subframeP)) || //normal case - ((framex10psubframe>(frameP*10+subframeP)) && (((10240-framex10psubframe+frameP*10+subframeP)>=10)))) //frame wrap-around - { - UE_template->pusch_tpc_tx_frame=frameP; - UE_template->pusch_tpc_tx_subframe=subframeP; - if (normalized_rx_power>(target_rx_power+4)) { - tpc = 0; //-1 - tpc_accumulated--; - } else if (normalized_rx_power<(target_rx_power-4)) { - tpc = 2; //+1 - tpc_accumulated++; - } else { - tpc = 1; //0 - } - } else { - tpc = 1; //0 - } - //tpc = 1; - if (tpc!=1) { - LOG_D(MAC,"[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", - module_idP,frameP,subframeP,harq_pid,tpc, - tpc_accumulated,normalized_rx_power,target_rx_power); - } - - // new transmission - if (round==0) { - - ndi = 1-UE_template->oldNDI_UL[harq_pid]; - UE_template->oldNDI_UL[harq_pid]=ndi; - UE_list->eNB_UE_stats[CC_id][UE_id].normalized_rx_power=normalized_rx_power; - UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power=target_rx_power; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=UE_template->pre_assigned_mcs_ul; - UE_template->mcs_UL[harq_pid] = UE_template->pre_assigned_mcs_ul;//cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS - if (UE_template->pre_allocated_rb_table_index_ul >=0) { - rb_table_index=UE_template->pre_allocated_rb_table_index_ul; - } else { - UE_template->mcs_UL[harq_pid]=10;//cmin (10, openair_daq_vars.target_ue_ul_mcs); - rb_table_index=5; // for PHR - } - - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=UE_template->mcs_UL[harq_pid]; - // buffer_occupancy = UE_template->ul_total_buffer; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2 = + UE_template->mcs_UL[harq_pid]; + // buffer_occupancy = UE_template->ul_total_buffer; - while (((rb_table[rb_table_index]>(N_RB_UL-1-first_rb[CC_id])) || - (rb_table[rb_table_index]>45)) && - (rb_table_index>0)) { - rb_table_index--; - } + while (((rb_table[rb_table_index] > + (N_RB_UL - 1 - first_rb[CC_id])) + || (rb_table[rb_table_index] > 45)) + && (rb_table_index > 0)) { + rb_table_index--; + } - UE_template->TBS_UL[harq_pid] = get_TBS_UL(UE_template->mcs_UL[harq_pid],rb_table[rb_table_index]); - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=rb_table[rb_table_index]; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_TBS=UE_template->TBS_UL[harq_pid]; - // buffer_occupancy -= TBS; + UE_template->TBS_UL[harq_pid] = + get_TBS_UL(UE_template->mcs_UL[harq_pid], + rb_table[rb_table_index]); + UE_list->eNB_UE_stats[CC_id][UE_id]. + total_rbs_used_rx += rb_table[rb_table_index]; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_TBS = + UE_template->TBS_UL[harq_pid]; + // buffer_occupancy -= TBS; - T(T_ENB_MAC_UE_UL_SCHEDULE, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), - T_INT(subframeP), T_INT(harq_pid), T_INT(UE_template->mcs_UL[harq_pid]), T_INT(first_rb[CC_id]), T_INT(rb_table[rb_table_index]), - T_INT(UE_template->TBS_UL[harq_pid]), T_INT(ndi)); + T(T_ENB_MAC_UE_UL_SCHEDULE, T_INT(module_idP), + T_INT(CC_id), T_INT(rnti), T_INT(frameP), + T_INT(subframeP), T_INT(harq_pid), + T_INT(UE_template->mcs_UL[harq_pid]), + T_INT(first_rb[CC_id]), + T_INT(rb_table[rb_table_index]), + T_INT(UE_template->TBS_UL[harq_pid]), T_INT(ndi)); - if (mac_eNB_get_rrc_status(module_idP,rnti) < RRC_CONNECTED) - LOG_D(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE %d (mcs %d, first rb %d, nb_rb %d, rb_table_index %d, TBS %d, harq_pid %d)\n", - module_idP,harq_pid,rnti,CC_id,frameP,subframeP,UE_id,UE_template->mcs_UL[harq_pid], - first_rb[CC_id],rb_table[rb_table_index], - rb_table_index,UE_template->TBS_UL[harq_pid],harq_pid); + if (mac_eNB_get_rrc_status(module_idP, rnti) < + RRC_CONNECTED) + LOG_D(MAC, + "[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE %d (mcs %d, first rb %d, nb_rb %d, rb_table_index %d, TBS %d, harq_pid %d)\n", + module_idP, harq_pid, rnti, CC_id, frameP, + subframeP, UE_id, + UE_template->mcs_UL[harq_pid], + first_rb[CC_id], rb_table[rb_table_index], + rb_table_index, + UE_template->TBS_UL[harq_pid], harq_pid); - // bad indices : 20 (40 PRB), 21 (45 PRB), 22 (48 PRB) - //store for possible retransmission - UE_template->nb_rb_ul[harq_pid] = rb_table[rb_table_index]; - UE_template->first_rb_ul[harq_pid] = first_rb[CC_id]; + // bad indices : 20 (40 PRB), 21 (45 PRB), 22 (48 PRB) + //store for possible retransmission + UE_template->nb_rb_ul[harq_pid] = + rb_table[rb_table_index]; + UE_template->first_rb_ul[harq_pid] = first_rb[CC_id]; - UE_sched_ctrl->ul_scheduled |= (1<head) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_SCHEDULED,UE_sched_ctrl->ul_scheduled); + UE_sched_ctrl->ul_scheduled |= (1 << harq_pid); + if (UE_id == UE_list->head) + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME + (VCD_SIGNAL_DUMPER_VARIABLES_UE0_SCHEDULED, + UE_sched_ctrl->ul_scheduled); - // adjust total UL buffer status by TBS, wait for UL sdus to do final update - LOG_D(MAC,"[eNB %d] CC_id %d UE %d/%x : adjusting ul_total_buffer, old %d, TBS %d\n", module_idP,CC_id,UE_id,rnti,UE_template->ul_total_buffer,UE_template->TBS_UL[harq_pid]); - if (UE_template->ul_total_buffer > UE_template->TBS_UL[harq_pid]) - UE_template->ul_total_buffer -= UE_template->TBS_UL[harq_pid]; - else - UE_template->ul_total_buffer = 0; - LOG_D(MAC,"ul_total_buffer, new %d\n", UE_template->ul_total_buffer); - // Cyclic shift for DM RS - cshift = 0;// values from 0 to 7 can be used for mapping the cyclic shift (36.211 , Table 5.5.2.1.1-1) - // save it for a potential retransmission - UE_template->cshift[harq_pid] = cshift; + // adjust total UL buffer status by TBS, wait for UL sdus to do final update + LOG_D(MAC, + "[eNB %d] CC_id %d UE %d/%x : adjusting ul_total_buffer, old %d, TBS %d\n", + module_idP, CC_id, UE_id, rnti, + UE_template->ul_total_buffer, + UE_template->TBS_UL[harq_pid]); + if (UE_template->ul_total_buffer > + UE_template->TBS_UL[harq_pid]) + UE_template->ul_total_buffer -= + UE_template->TBS_UL[harq_pid]; + else + UE_template->ul_total_buffer = 0; + LOG_D(MAC, "ul_total_buffer, new %d\n", + UE_template->ul_total_buffer); + // Cyclic shift for DM RS + cshift = 0; // values from 0 to 7 can be used for mapping the cyclic shift (36.211 , Table 5.5.2.1.1-1) + // save it for a potential retransmission + UE_template->cshift[harq_pid] = cshift; - hi_dci0_pdu = &hi_dci0_req->hi_dci0_pdu_list[eNB->HI_DCI0_req[CC_id].hi_dci0_request_body.number_of_dci+eNB->HI_DCI0_req[CC_id].hi_dci0_request_body.number_of_hi]; - memset((void*)hi_dci0_pdu,0,sizeof(nfapi_hi_dci0_request_pdu_t)); - hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE; - hi_dci0_pdu->pdu_size = 2+sizeof(nfapi_hi_dci0_dci_pdu); - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dci_format = NFAPI_UL_DCI_FORMAT_0; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level = aggregation; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti = rnti; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.transmission_power = 6000; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.resource_block_start = first_rb[CC_id]; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.number_of_resource_block = rb_table[rb_table_index]; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.mcs_1 = UE_template->mcs_UL[harq_pid]; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.cyclic_shift_2_for_drms = cshift; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.frequency_hopping_enabled_flag = 0; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.new_data_indication_1 = ndi; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tpc = tpc; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.cqi_csi_request = cqi_req; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dl_assignment_index = UE_template->DAI_ul[sched_subframeP]; + hi_dci0_pdu = + &hi_dci0_req->hi_dci0_pdu_list[mac->HI_DCI0_req + [CC_id]. + hi_dci0_request_body. + number_of_dci + + mac->HI_DCI0_req + [CC_id]. + hi_dci0_request_body. + number_of_hi]; + memset((void *) hi_dci0_pdu, 0, + sizeof(nfapi_hi_dci0_request_pdu_t)); + hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE; + hi_dci0_pdu->pdu_size = + 2 + sizeof(nfapi_hi_dci0_dci_pdu); + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dci_format = + NFAPI_UL_DCI_FORMAT_0; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level = + aggregation; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti = rnti; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.transmission_power = + 6000; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8. + resource_block_start = first_rb[CC_id]; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8. + number_of_resource_block = + rb_table[rb_table_index]; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.mcs_1 = + UE_template->mcs_UL[harq_pid]; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8. + cyclic_shift_2_for_drms = cshift; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8. + frequency_hopping_enabled_flag = 0; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8. + new_data_indication_1 = ndi; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tpc = tpc; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.cqi_csi_request = + cqi_req; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dl_assignment_index = + UE_template->DAI_ul[sched_subframeP]; - eNB->HI_DCI0_req[CC_id].hi_dci0_request_body.number_of_dci++; + mac->HI_DCI0_req[CC_id].hi_dci0_request_body. + number_of_dci++; - LOG_D(MAC,"[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n", - harq_pid,frameP,subframeP,UE_id,rnti,sched_frame,sched_subframeP); + LOG_D(MAC, + "[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n", + harq_pid, frameP, subframeP, UE_id, rnti, + sched_frame, sched_subframeP); - // Add UL_config PDUs - fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], - cqi_req, - cc, - UE_template->physicalConfigDedicated, - get_tmode(module_idP,CC_id,UE_id), - eNB->ul_handle, - rnti, - first_rb[CC_id], // resource_block_start - rb_table[rb_table_index], // number_of_resource_blocks - UE_template->mcs_UL[harq_pid], - cshift, // cyclic_shift_2_for_drms - 0, // frequency_hopping_enabled_flag - 0, // frequency_hopping_bits - ndi, // new_data_indication - 0, // redundancy_version - harq_pid, // harq_process_number - 0, // ul_tx_mode - 0, // current_tx_nb - 0, // n_srs - get_TBS_UL(UE_template->mcs_UL[harq_pid], - rb_table[rb_table_index]) - ); + // Add UL_config PDUs + fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], cqi_req, cc, UE_template->physicalConfigDedicated, get_tmode(module_idP, CC_id, UE_id), mac->ul_handle, rnti, first_rb[CC_id], // resource_block_start + rb_table[rb_table_index], // number_of_resource_blocks + UE_template->mcs_UL[harq_pid], cshift, // cyclic_shift_2_for_drms + 0, // frequency_hopping_enabled_flag + 0, // frequency_hopping_bits + ndi, // new_data_indication + 0, // redundancy_version + harq_pid, // harq_process_number + 0, // ul_tx_mode + 0, // current_tx_nb + 0, // n_srs + get_TBS_UL + (UE_template-> + mcs_UL[harq_pid], + rb_table + [rb_table_index])); #ifdef Rel14 - if (UE_template->rach_resource_type>0) { // This is a BL/CE UE allocation - fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], - UE_template->rach_resource_type>2 ? 2 : 1, - 1, //total_number_of_repetitions - 1, //repetition_number - (frameP*10)+subframeP); - } + if (UE_template->rach_resource_type > 0) { // This is a BL/CE UE allocation + fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], UE_template->rach_resource_type > 2 ? 2 : 1, 1, //total_number_of_repetitions + 1, //repetition_number + (frameP * + 10) + + subframeP); + } #endif - ul_req_tmp->number_of_pdus++; - eNB->ul_handle++; + ul_req_tmp->number_of_pdus++; + mac->ul_handle++; - add_ue_ulsch_info(module_idP, - CC_id, - UE_id, - subframeP, - S_UL_SCHEDULED); + add_ue_ulsch_info(module_idP, + CC_id, UE_id, subframeP, + S_UL_SCHEDULED); - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d, subframeP %d: Generated ULSCH DCI for next UE_id %d, format 0\n", module_idP,CC_id,frameP,subframeP,UE_id); + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d, subframeP %d: Generated ULSCH DCI for next UE_id %d, format 0\n", + module_idP, CC_id, frameP, subframeP, UE_id); - // increment first rb for next UE allocation - first_rb[CC_id]+=rb_table[rb_table_index]; - } - else { // round > 0 => retransmission - T(T_ENB_MAC_UE_UL_SCHEDULE_RETRANSMISSION, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), - T_INT(subframeP), T_INT(harq_pid), T_INT(UE_template->mcs_UL[harq_pid]), T_INT(first_rb[CC_id]), T_INT(rb_table[rb_table_index]), - T_INT(round)); + // increment first rb for next UE allocation + first_rb[CC_id] += rb_table[rb_table_index]; + } else { // round > 0 => retransmission + T(T_ENB_MAC_UE_UL_SCHEDULE_RETRANSMISSION, + T_INT(module_idP), T_INT(CC_id), T_INT(rnti), + T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), + T_INT(UE_template->mcs_UL[harq_pid]), + T_INT(first_rb[CC_id]), + T_INT(rb_table[rb_table_index]), T_INT(round)); - // fill in NAK information + // fill in NAK information - hi_dci0_pdu = &hi_dci0_req->hi_dci0_pdu_list[hi_dci0_req->number_of_dci+hi_dci0_req->number_of_hi]; - memset((void*)hi_dci0_pdu,0,sizeof(nfapi_hi_dci0_request_pdu_t)); - hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; - hi_dci0_pdu->pdu_size = 2+sizeof(nfapi_hi_dci0_hi_pdu); - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = UE_template->first_rb_ul[harq_pid]; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = UE_template->cshift[harq_pid]; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 0; - hi_dci0_req->number_of_hi++; - LOG_D(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled (PHICH) UE %d (mcs %d, first rb %d, nb_rb %d, TBS %d, round %d)\n", - module_idP,harq_pid,rnti,CC_id,frameP,subframeP,UE_id,UE_template->mcs_UL[harq_pid], - UE_template->first_rb_ul[harq_pid], UE_template->nb_rb_ul[harq_pid], - UE_template->TBS_UL[harq_pid],round); - // Add UL_config PDUs - LOG_D(MAC,"[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n", - harq_pid,frameP,subframeP,UE_id,rnti,sched_frame,sched_subframeP); - fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], - cqi_req, - cc, - UE_template->physicalConfigDedicated, - get_tmode(module_idP,CC_id,UE_id), - eNB->ul_handle, - rnti, - UE_template->first_rb_ul[harq_pid], // resource_block_start - UE_template->nb_rb_ul[harq_pid], // number_of_resource_blocks - UE_template->mcs_UL[harq_pid], - cshift, // cyclic_shift_2_for_drms - 0, // frequency_hopping_enabled_flag - 0, // frequency_hopping_bits - UE_template->oldNDI_UL[harq_pid], // new_data_indication - rvidx_tab[round&3], // redundancy_version - harq_pid, // harq_process_number - 0, // ul_tx_mode - 0, // current_tx_nb - 0, // n_srs - UE_template->TBS_UL[harq_pid] - ); + hi_dci0_pdu = + &hi_dci0_req->hi_dci0_pdu_list[hi_dci0_req-> + number_of_dci + + hi_dci0_req-> + number_of_hi]; + memset((void *) hi_dci0_pdu, 0, + sizeof(nfapi_hi_dci0_request_pdu_t)); + hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; + hi_dci0_pdu->pdu_size = + 2 + sizeof(nfapi_hi_dci0_hi_pdu); + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = + UE_template->first_rb_ul[harq_pid]; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8. + cyclic_shift_2_for_drms = + UE_template->cshift[harq_pid]; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 0; + hi_dci0_req->number_of_hi++; + LOG_D(MAC, + "[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled (PHICH) UE %d (mcs %d, first rb %d, nb_rb %d, TBS %d, round %d)\n", + module_idP, harq_pid, rnti, CC_id, frameP, + subframeP, UE_id, UE_template->mcs_UL[harq_pid], + UE_template->first_rb_ul[harq_pid], + UE_template->nb_rb_ul[harq_pid], + UE_template->TBS_UL[harq_pid], round); + // Add UL_config PDUs + LOG_D(MAC, + "[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n", + harq_pid, frameP, subframeP, UE_id, rnti, + sched_frame, sched_subframeP); + fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], cqi_req, cc, UE_template->physicalConfigDedicated, get_tmode(module_idP, CC_id, UE_id), mac->ul_handle, rnti, UE_template->first_rb_ul[harq_pid], // resource_block_start + UE_template->nb_rb_ul[harq_pid], // number_of_resource_blocks + UE_template->mcs_UL[harq_pid], cshift, // cyclic_shift_2_for_drms + 0, // frequency_hopping_enabled_flag + 0, // frequency_hopping_bits + UE_template->oldNDI_UL[harq_pid], // new_data_indication + rvidx_tab[round & 3], // redundancy_version + harq_pid, // harq_process_number + 0, // ul_tx_mode + 0, // current_tx_nb + 0, // n_srs + UE_template-> + TBS_UL[harq_pid]); #ifdef Rel14 - if (UE_template->rach_resource_type>0) { // This is a BL/CE UE allocation - fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], - UE_template->rach_resource_type>2 ? 2 : 1, - 1, //total_number_of_repetitions - 1, //repetition_number - (frameP*10)+subframeP); - } + if (UE_template->rach_resource_type > 0) { // This is a BL/CE UE allocation + fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], UE_template->rach_resource_type > 2 ? 2 : 1, 1, //total_number_of_repetitions + 1, //repetition_number + (frameP * + 10) + + subframeP); + } #endif - ul_req_tmp->number_of_pdus++; - eNB->ul_handle++; + ul_req_tmp->number_of_pdus++; + mac->ul_handle++; - }/* - else if (round > 0) { //we schedule a retransmission + } /* + else if (round > 0) { //we schedule a retransmission - ndi = UE_template->oldNDI_UL[harq_pid]; + ndi = UE_template->oldNDI_UL[harq_pid]; - if ((round&3)==0) { - mcs = openair_daq_vars.target_ue_ul_mcs; - } else { - mcs = rvidx_tab[round&3] + 28; //not correct for round==4! + if ((round&3)==0) { + mcs = openair_daq_vars.target_ue_ul_mcs; + } else { + mcs = rvidx_tab[round&3] + 28; //not correct for round==4! - } + } - LOG_I(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE retransmission (mcs %d, first rb %d, nb_rb %d, harq_pid %d, round %d)\n", - module_idP,UE_id,rnti,CC_id,frameP,subframeP,mcs, - first_rb[CC_id],UE_template->nb_rb_ul[harq_pid], - harq_pid, round); + LOG_I(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE retransmission (mcs %d, first rb %d, nb_rb %d, harq_pid %d, round %d)\n", + module_idP,UE_id,rnti,CC_id,frameP,subframeP,mcs, + first_rb[CC_id],UE_template->nb_rb_ul[harq_pid], + harq_pid, round); - rballoc = mac_xface->computeRIV(frame_parms->N_RB_UL, - first_rb[CC_id], - UE_template->nb_rb_ul[harq_pid]); - first_rb[CC_id]+=UE_template->nb_rb_ul[harq_pid]; // increment for next UE allocation + rballoc = mac_xface->computeRIV(frame_parms->N_RB_UL, + first_rb[CC_id], + UE_template->nb_rb_ul[harq_pid]); + first_rb[CC_id]+=UE_template->nb_rb_ul[harq_pid]; // increment for next UE allocation - UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission_rx+=1; - UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx_rx=UE_template->nb_rb_ul[harq_pid]; - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=UE_template->nb_rb_ul[harq_pid]; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=mcs; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; - } - */ + UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission_rx+=1; + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx_rx=UE_template->nb_rb_ul[harq_pid]; + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=UE_template->nb_rb_ul[harq_pid]; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=mcs; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; + } + */ - } // UE_is_to_be_scheduled - } // loop over UE_id - } // loop of CC_id + } // UE_is_to_be_scheduled + } // loop over UE_id + } // loop of CC_id } diff --git a/openair2/LAYER2/MAC/extern.h b/openair2/LAYER2/MAC/extern.h index f192cd7e12..50ea5634b9 100644 --- a/openair2/LAYER2/MAC/extern.h +++ b/openair2/LAYER2/MAC/extern.h @@ -35,7 +35,7 @@ #ifdef USER_MODE //#include "stdio.h" -#endif //USER_MODE +#endif //USER_MODE #include "PHY/defs.h" #include "defs.h" @@ -56,8 +56,8 @@ extern UE_RRC_INST *UE_rrc_inst; extern UE_MAC_INST *UE_mac_inst; -extern eNB_ULSCH_INFO eNB_ulsch_info[NUMBER_OF_eNB_MAX][MAX_NUM_CCs][NUMBER_OF_UE_MAX]; // eNBxUE = 8x8 -extern eNB_DLSCH_INFO eNB_dlsch_info[NUMBER_OF_eNB_MAX][MAX_NUM_CCs][NUMBER_OF_UE_MAX]; // eNBxUE = 8x8 +extern eNB_ULSCH_INFO eNB_ulsch_info[NUMBER_OF_eNB_MAX][MAX_NUM_CCs][NUMBER_OF_UE_MAX]; // eNBxUE = 8x8 +extern eNB_DLSCH_INFO eNB_dlsch_info[NUMBER_OF_eNB_MAX][MAX_NUM_CCs][NUMBER_OF_UE_MAX]; // eNBxUE = 8x8 @@ -79,28 +79,26 @@ extern uint32_t RRC_CONNECTION_FLAG; extern uint8_t rb_table[34]; -extern DCI0_5MHz_TDD_1_6_t UL_alloc_pdu; +extern DCI0_5MHz_TDD_1_6_t UL_alloc_pdu; -extern DCI1A_5MHz_TDD_1_6_t RA_alloc_pdu; -extern DCI1A_5MHz_TDD_1_6_t DLSCH_alloc_pdu1A; -extern DCI1A_5MHz_TDD_1_6_t BCCH_alloc_pdu; +extern DCI1A_5MHz_TDD_1_6_t RA_alloc_pdu; +extern DCI1A_5MHz_TDD_1_6_t DLSCH_alloc_pdu1A; +extern DCI1A_5MHz_TDD_1_6_t BCCH_alloc_pdu; -extern DCI1A_5MHz_TDD_1_6_t CCCH_alloc_pdu; -extern DCI1_5MHz_TDD_t DLSCH_alloc_pdu; +extern DCI1A_5MHz_TDD_1_6_t CCCH_alloc_pdu; +extern DCI1_5MHz_TDD_t DLSCH_alloc_pdu; -extern DCI0_5MHz_FDD_t UL_alloc_pdu_fdd; +extern DCI0_5MHz_FDD_t UL_alloc_pdu_fdd; -extern DCI1A_5MHz_FDD_t DLSCH_alloc_pdu1A_fdd; -extern DCI1A_5MHz_FDD_t RA_alloc_pdu_fdd; -extern DCI1A_5MHz_FDD_t BCCH_alloc_pdu_fdd; +extern DCI1A_5MHz_FDD_t DLSCH_alloc_pdu1A_fdd; +extern DCI1A_5MHz_FDD_t RA_alloc_pdu_fdd; +extern DCI1A_5MHz_FDD_t BCCH_alloc_pdu_fdd; -extern DCI1A_5MHz_FDD_t CCCH_alloc_pdu_fdd; -extern DCI1_5MHz_FDD_t DLSCH_alloc_pdu_fdd; +extern DCI1A_5MHz_FDD_t CCCH_alloc_pdu_fdd; +extern DCI1_5MHz_FDD_t DLSCH_alloc_pdu_fdd; extern DCI2_5MHz_2A_TDD_t DLSCH_alloc_pdu1; extern DCI2_5MHz_2A_TDD_t DLSCH_alloc_pdu2; extern DCI1E_5MHz_2A_M10PRB_TDD_t DLSCH_alloc_pdu1E; -#endif //DEF_H - - +#endif //DEF_H diff --git a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h index 5b152a1138..d3170aaf91 100644 --- a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h +++ b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h @@ -17,7 +17,7 @@ *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org - */ + */ /*! \file flexran_agent_mac_proto.h * \brief MAC functions for FlexRAN agent @@ -39,150 +39,178 @@ /* * slice specific scheduler */ -typedef void (*slice_scheduler)(module_id_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info); +typedef void (*slice_scheduler) (module_id_t mod_id, + int slice_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info); /* * top level flexran scheduler used by the eNB scheduler */ -void flexran_schedule_ue_spec_default(mid_t mod_id, - uint32_t frame, +void flexran_schedule_ue_spec_default(mid_t mod_id, + uint32_t frame, uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info); + int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info); /* * slice specific scheduler for embb */ void -flexran_schedule_ue_spec_embb(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info); +flexran_schedule_ue_spec_embb(mid_t mod_id, + int slice_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info); /* * slice specific scheduler for urllc */ void -flexran_schedule_ue_spec_urllc(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info); +flexran_schedule_ue_spec_urllc(mid_t mod_id, + int slice_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info); /* * slice specific scheduler for mmtc */ void -flexran_schedule_ue_spec_mmtc(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info); +flexran_schedule_ue_spec_mmtc(mid_t mod_id, + int slice_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info); /* * slice specific scheduler for best effort traffic */ void -flexran_schedule_ue_spec_be(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info); +flexran_schedule_ue_spec_be(mid_t mod_id, + int slice_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info); /* * common flexran scheduler function */ void -flexran_schedule_ue_spec_common(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info); +flexran_schedule_ue_spec_common(mid_t mod_id, + int slice_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info); -uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, - int total_rbs); +uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, int total_rbs); -int flexran_slice_member(int UE_id, - int slice_id); +int flexran_slice_member(int UE_id, int slice_id); -int flexran_slice_maxmcs(int slice_id) ; +int flexran_slice_maxmcs(int slice_id); -void _store_dlsch_buffer (module_id_t Mod_id, - int slice_id, - frame_t frameP, - sub_frame_t subframeP); +void _store_dlsch_buffer(module_id_t Mod_id, + int slice_id, + frame_t frameP, sub_frame_t subframeP); -void _assign_rbs_required (module_id_t Mod_id, - int slice_id, - frame_t frameP, - sub_frame_t subframe, - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES], - int min_rb_unit[MAX_NUM_CCs]); +void _assign_rbs_required(module_id_t Mod_id, + int slice_id, + frame_t frameP, + sub_frame_t subframe, + uint16_t + nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], + uint16_t + nb_rbs_allowed_slice[MAX_NUM_CCs] + [MAX_NUM_SLICES], int min_rb_unit[MAX_NUM_CCs]); -void _dlsch_scheduler_pre_processor (module_id_t Mod_id, - int slice_id, - frame_t frameP, - sub_frame_t subframeP, - int N_RBG[MAX_NUM_CCs], - int *mbsfn_flag); +void _dlsch_scheduler_pre_processor(module_id_t Mod_id, + int slice_id, + frame_t frameP, + sub_frame_t subframeP, + int N_RBG[MAX_NUM_CCs], + int *mbsfn_flag); -void _dlsch_scheduler_pre_processor_reset (int module_idP, - int UE_id, - uint8_t CC_id, - int frameP, - int subframeP, - int N_RBG, - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES], - unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], - unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]); +void _dlsch_scheduler_pre_processor_reset(int module_idP, + int UE_id, + uint8_t CC_id, + int frameP, + int subframeP, + int N_RBG, + uint16_t + nb_rbs_required[MAX_NUM_CCs] + [NUMBER_OF_UE_MAX], + uint16_t + nb_rbs_required_remaining + [MAX_NUM_CCs][NUMBER_OF_UE_MAX], + uint16_t + nb_rbs_allowed_slice[MAX_NUM_CCs] + [MAX_NUM_SLICES], + unsigned char + rballoc_sub[MAX_NUM_CCs] + [N_RBG_MAX], + unsigned char + MIMO_mode_indicator[MAX_NUM_CCs] + [N_RBG_MAX]); -void _dlsch_scheduler_pre_processor_allocate (module_id_t Mod_id, - int UE_id, - uint8_t CC_id, - int N_RBG, - int transmission_mode, - int min_rb_unit, - uint8_t N_RB_DL, - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], - unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]); +void _dlsch_scheduler_pre_processor_allocate(module_id_t Mod_id, + int UE_id, + uint8_t CC_id, + int N_RBG, + int transmission_mode, + int min_rb_unit, + uint8_t N_RB_DL, + uint16_t + nb_rbs_required[MAX_NUM_CCs] + [NUMBER_OF_UE_MAX], + uint16_t + nb_rbs_required_remaining + [MAX_NUM_CCs] + [NUMBER_OF_UE_MAX], + unsigned char + rballoc_sub[MAX_NUM_CCs] + [N_RBG_MAX], + unsigned char + MIMO_mode_indicator + [MAX_NUM_CCs][N_RBG_MAX]); /* * Default scheduler used by the eNB agent */ -void flexran_schedule_ue_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__FlexranMessage **dl_info); +void flexran_schedule_ue_spec_default(mid_t mod_id, uint32_t frame, + uint32_t subframe, int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info); /* * Data plane function for applying the DL decisions of the scheduler */ -void flexran_apply_dl_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, - Protocol__FlexranMessage *dl_scheduling_info); +void flexran_apply_dl_scheduling_decisions(mid_t mod_id, uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage * + dl_scheduling_info); /* * Data plane function for applying the UE specific DL decisions of the scheduler */ -void flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, - uint32_t n_dl_ue_data, Protocol__FlexDlData **dl_ue_data); +void flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + uint32_t n_dl_ue_data, + Protocol__FlexDlData ** + dl_ue_data); /* * Data plane function for filling the DCI structure */ -void flexran_fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, Protocol__FlexDlDci *dl_dci); +void flexran_fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, + Protocol__FlexDlDci * dl_dci); #endif diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c index 018d490f44..44052a8749 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c @@ -17,7 +17,7 @@ *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org - */ + */ /*! \file flexran_agent_scheduler_dataplane.c * \brief data plane procedures related to eNB scheduling @@ -57,495 +57,532 @@ #include "flexran_agent_common.h" -#include "SIMULATION/TOOLS/defs.h" // for taus +#include "SIMULATION/TOOLS/defs.h" // for taus -void flexran_apply_dl_scheduling_decisions(mid_t mod_id, +void +flexran_apply_dl_scheduling_decisions(mid_t mod_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage * + dl_scheduling_info) +{ + + Protocol__FlexDlMacConfig *mac_config = + dl_scheduling_info->dl_mac_config_msg; + + // Check if there is anything to schedule for random access + if (mac_config->n_dl_rar > 0) { + /*TODO: call the random access data plane function */ + } + // Check if there is anything to schedule for paging/broadcast + if (mac_config->n_dl_broadcast > 0) { + /*TODO: call the broadcast/paging data plane function */ + } + // Check if there is anything to schedule for the UEs + if (mac_config->n_dl_ue_data > 0) { + flexran_apply_ue_spec_scheduling_decisions(mod_id, frame, subframe, + mbsfn_flag, + mac_config-> + n_dl_ue_data, + mac_config->dl_ue_data); + } + +} + + +void +flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, - Protocol__FlexranMessage *dl_scheduling_info) { + uint32_t n_dl_ue_data, + Protocol__FlexDlData ** + dl_ue_data) +{ - Protocol__FlexDlMacConfig *mac_config = dl_scheduling_info->dl_mac_config_msg; + uint8_t CC_id; + int UE_id; + mac_rlc_status_resp_t rlc_status; + unsigned char ta_len = 0; + unsigned char header_len = 0, header_len_tmp = 0; + unsigned char sdu_lcids[11], offset, num_sdus = 0; + uint16_t nb_rb; + uint16_t TBS, sdu_lengths[11], rnti, padding = 0, post_padding = 0; + unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; + uint8_t round = 0; + uint8_t harq_pid = 0; + // LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + uint16_t sdu_length_total = 0; + short ta_update = 0; + eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; + UE_list_t *UE_list = &eNB->UE_list; + // static int32_t tpc_accumulated=0; + UE_sched_ctrl *ue_sched_ctl; - // Check if there is anything to schedule for random access - if (mac_config->n_dl_rar > 0) { - /*TODO: call the random access data plane function*/ - } + int last_sdu_header_len = 0; - // Check if there is anything to schedule for paging/broadcast - if (mac_config->n_dl_broadcast > 0) { - /*TODO: call the broadcast/paging data plane function*/ - } + int i, j; - // Check if there is anything to schedule for the UEs - if (mac_config->n_dl_ue_data > 0) { - flexran_apply_ue_spec_scheduling_decisions(mod_id, frame, subframe, mbsfn_flag, - mac_config->n_dl_ue_data, mac_config->dl_ue_data); - } - -} + Protocol__FlexDlData *dl_data; + Protocol__FlexDlDci *dl_dci; + uint32_t rlc_size, n_lc, lcid; -void flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - uint32_t n_dl_ue_data, - Protocol__FlexDlData **dl_ue_data) { + // For each UE-related command + for (i = 0; i < n_dl_ue_data; i++) { - uint8_t CC_id; - int UE_id; - mac_rlc_status_resp_t rlc_status; - unsigned char ta_len=0; - unsigned char header_len = 0, header_len_tmp = 0; - unsigned char sdu_lcids[11],offset,num_sdus=0; - uint16_t nb_rb; - uint16_t TBS, sdu_lengths[11],rnti,padding=0,post_padding=0; - unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; - uint8_t round = 0; - uint8_t harq_pid = 0; - // LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - uint16_t sdu_length_total = 0; - short ta_update = 0; - eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; - UE_list_t *UE_list = &eNB->UE_list; - // static int32_t tpc_accumulated=0; - UE_sched_ctrl *ue_sched_ctl; + dl_data = dl_ue_data[i]; + dl_dci = dl_data->dl_dci; - int last_sdu_header_len = 0; + CC_id = dl_data->serv_cell_index; + // frame_parms[CC_id] = mac_xface->get_lte_frame_parms(mod_id, CC_id); - int i, j; + rnti = dl_data->rnti; + UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]); - Protocol__FlexDlData *dl_data; - Protocol__FlexDlDci *dl_dci; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - uint32_t rlc_size, n_lc, lcid; - - // For each UE-related command - for (i = 0; i < n_dl_ue_data; i++) { - - dl_data = dl_ue_data[i]; - dl_dci = dl_data->dl_dci; + round = dl_dci->rv[0]; + harq_pid = dl_dci->harq_process; - CC_id = dl_data->serv_cell_index; - // frame_parms[CC_id] = mac_xface->get_lte_frame_parms(mod_id, CC_id); - - rnti = dl_data->rnti; - UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]); + //LOG_I(FLEXRAN_AGENT, "[Frame %d][Subframe %d] Scheduling harq %d\n", frame, subframe, harq_pid); + // LOG_I(FLEXRAN_AGENT, "[Frame %d][Subframe %d]Now scheduling harq_pid %d (round %d)\n", frame, subframe, harq_pid, round); - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); - - round = dl_dci->rv[0]; - harq_pid = dl_dci->harq_process; - - //LOG_I(FLEXRAN_AGENT, "[Frame %d][Subframe %d] Scheduling harq %d\n", frame, subframe, harq_pid); - // LOG_I(FLEXRAN_AGENT, "[Frame %d][Subframe %d]Now scheduling harq_pid %d (round %d)\n", frame, subframe, harq_pid, round); + // If this is a new transmission + if (round == 0) { + // First we have to deal with the creation of the PDU based on the message instructions + rlc_status.bytes_in_buffer = 0; - // If this is a new transmission - if (round == 0) { - // First we have to deal with the creation of the PDU based on the message instructions - rlc_status.bytes_in_buffer = 0; - - TBS = dl_dci->tbs_size[0]; - - if (dl_data->n_ce_bitmap > 0) { - //Check if there is TA command and set the length appropriately - ta_len = (dl_data->ce_bitmap[0] & PROTOCOL__FLEX_CE_TYPE__FLPCET_TA) ? 2 : 0; - } + TBS = dl_dci->tbs_size[0]; - num_sdus = 0; - sdu_length_total = 0; - - n_lc = dl_data->n_rlc_pdu; - // Go through each one of the channel commands and create SDUs - header_len = 0; - last_sdu_header_len = 0; - for (j = 0; j < n_lc; j++) { - sdu_lengths[j] = 0; - lcid = dl_data->rlc_pdu[j]->rlc_pdu_tb[0]->logical_channel_id; - rlc_size = dl_data->rlc_pdu[j]->rlc_pdu_tb[0]->size; - LOG_D(MAC,"[TEST] [eNB %d] [Frame %d] [Subframe %d], LCID %d, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", - mod_id, frame, subframe, lcid, CC_id, rlc_size); - if (rlc_size > 0) { - - rlc_status = mac_rlc_status_ind(mod_id, - rnti, - mod_id, - frame, - subframe, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - 0); - - if (rlc_status.bytes_in_buffer > 0) { - - if (rlc_status.bytes_in_buffer < rlc_size) { - rlc_size = rlc_status.bytes_in_buffer; + if (dl_data->n_ce_bitmap > 0) { + //Check if there is TA command and set the length appropriately + ta_len = + (dl_data-> + ce_bitmap[0] & PROTOCOL__FLEX_CE_TYPE__FLPCET_TA) ? 2 + : 0; } - if (rlc_size <= 2) { - rlc_size = 3; - } + num_sdus = 0; + sdu_length_total = 0; - rlc_status = mac_rlc_status_ind(mod_id, - rnti, - mod_id, - frame, - subframe, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - rlc_size); // transport block set size - - LOG_D(MAC, "[TEST] RLC can give %d bytes for LCID %d during second call\n", rlc_status.bytes_in_buffer, lcid); - - if (rlc_status.bytes_in_buffer > 0) { - - sdu_lengths[j] = mac_rlc_data_req(mod_id, - rnti, - mod_id, - frame, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - rlc_size, //not used - (char *)&dlsch_buffer[sdu_length_total]); - - LOG_D(MAC,"[eNB %d][LCID %d] CC_id %d Got %d bytes from RLC\n",mod_id, lcid, CC_id, sdu_lengths[j]); - sdu_length_total += sdu_lengths[j]; - sdu_lcids[j] = lcid; - - UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid] += 1; - UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[lcid] += sdu_lengths[j]; - - if (sdu_lengths[j] < 128) { - header_len += 2; - last_sdu_header_len = 2; - } else { - header_len += 3; - last_sdu_header_len = 3; - } - num_sdus++; - } - } - } - } // SDU creation end - - - if (((sdu_length_total + header_len + ta_len) > 0)) { - - header_len_tmp = header_len; - - // If we have only a single SDU, header length becomes 1 - if ((num_sdus) == 1) { - //if (header_len == 2 || header_len == 3) { - header_len = 1; - } else { - header_len = (header_len - last_sdu_header_len) + 1; - } - - // If we need a 1 or 2 bit padding or no padding at all - if ((TBS - header_len - sdu_length_total - ta_len) <= 2 - || (TBS - header_len - sdu_length_total - ta_len) > TBS) { //protect from overflow - padding = (TBS - header_len - sdu_length_total - ta_len); - post_padding = 0; - } else { // The last sdu needs to have a length field, since we add padding - padding = 0; - header_len = header_len_tmp; - post_padding = TBS - sdu_length_total - header_len - ta_len; // 1 is for the postpadding header - } - - if (ta_len > 0) { - // Reset the measurement - ta_update = flexran_get_TA(mod_id, UE_id, CC_id); - ue_sched_ctl->ta_timer = 20; - eNB_UE_stats->timing_advance_update = 0; - } else { - ta_update = 0; - } + n_lc = dl_data->n_rlc_pdu; + // Go through each one of the channel commands and create SDUs + header_len = 0; + last_sdu_header_len = 0; + for (j = 0; j < n_lc; j++) { + sdu_lengths[j] = 0; + lcid = + dl_data->rlc_pdu[j]->rlc_pdu_tb[0]->logical_channel_id; + rlc_size = dl_data->rlc_pdu[j]->rlc_pdu_tb[0]->size; + LOG_D(MAC, + "[TEST] [eNB %d] [Frame %d] [Subframe %d], LCID %d, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", + mod_id, frame, subframe, lcid, CC_id, rlc_size); + if (rlc_size > 0) { + + rlc_status = mac_rlc_status_ind(mod_id, + rnti, + mod_id, + frame, + subframe, + ENB_FLAG_YES, + MBMS_FLAG_NO, lcid, 0); + + if (rlc_status.bytes_in_buffer > 0) { + + if (rlc_status.bytes_in_buffer < rlc_size) { + rlc_size = rlc_status.bytes_in_buffer; + } + + if (rlc_size <= 2) { + rlc_size = 3; + } + + rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, subframe, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, rlc_size); // transport block set size + + LOG_D(MAC, + "[TEST] RLC can give %d bytes for LCID %d during second call\n", + rlc_status.bytes_in_buffer, lcid); + + if (rlc_status.bytes_in_buffer > 0) { + + sdu_lengths[j] = mac_rlc_data_req(mod_id, rnti, mod_id, frame, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, rlc_size, //not used + (char *) + &dlsch_buffer + [sdu_length_total]); + + LOG_D(MAC, + "[eNB %d][LCID %d] CC_id %d Got %d bytes from RLC\n", + mod_id, lcid, CC_id, sdu_lengths[j]); + sdu_length_total += sdu_lengths[j]; + sdu_lcids[j] = lcid; + + UE_list-> + eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid] + += 1; + UE_list-> + eNB_UE_stats[CC_id][UE_id].num_bytes_tx + [lcid] += sdu_lengths[j]; + + if (sdu_lengths[j] < 128) { + header_len += 2; + last_sdu_header_len = 2; + } else { + header_len += 3; + last_sdu_header_len = 3; + } + num_sdus++; + } + } + } + } // SDU creation end + + + if (((sdu_length_total + header_len + ta_len) > 0)) { + + header_len_tmp = header_len; + + // If we have only a single SDU, header length becomes 1 + if ((num_sdus) == 1) { + //if (header_len == 2 || header_len == 3) { + header_len = 1; + } else { + header_len = (header_len - last_sdu_header_len) + 1; + } + + // If we need a 1 or 2 bit padding or no padding at all + if ((TBS - header_len - sdu_length_total - ta_len) <= 2 || (TBS - header_len - sdu_length_total - ta_len) > TBS) { //protect from overflow + padding = + (TBS - header_len - sdu_length_total - ta_len); + post_padding = 0; + } else { // The last sdu needs to have a length field, since we add padding + padding = 0; + header_len = header_len_tmp; + post_padding = TBS - sdu_length_total - header_len - ta_len; // 1 is for the postpadding header + } + + if (ta_len > 0) { + // Reset the measurement + ta_update = flexran_get_TA(mod_id, UE_id, CC_id); + ue_sched_ctl->ta_timer = 20; + eNB_UE_stats->timing_advance_update = 0; + } else { + ta_update = 0; + } + + // If there is nothing to schedule, just leave + if ((sdu_length_total) <= 0) { + harq_pid_updated[UE_id][harq_pid] = 1; + harq_pid_round[UE_id][harq_pid] = 0; + continue; + } + // LOG_I(FLEXRAN_AGENT, "[Frame %d][Subframe %d] TBS is %d and bytes are %d\n", frame, subframe, TBS, sdu_length_total); + + offset = generate_dlsch_header((unsigned char *) UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], num_sdus, //num_sdus + sdu_lengths, // + sdu_lcids, 255, // no drx + ta_update, // timing advance + NULL, // contention res id + padding, post_padding); - // If there is nothing to schedule, just leave - if ((sdu_length_total) <= 0) { - harq_pid_updated[UE_id][harq_pid] = 1; - harq_pid_round[UE_id][harq_pid] = 0; - continue; - } - // LOG_I(FLEXRAN_AGENT, "[Frame %d][Subframe %d] TBS is %d and bytes are %d\n", frame, subframe, TBS, sdu_length_total); - - offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], - num_sdus, //num_sdus - sdu_lengths, // - sdu_lcids, - 255, // no drx - ta_update, // timing advance - NULL, // contention res id - padding, - post_padding); - - #ifdef DEBUG_eNB_SCHEDULER - LOG_T(MAC,"[eNB %d] First 16 bytes of DLSCH : \n"); - - for (i=0; i<16; i++) { - LOG_T(MAC,"%x.",dlsch_buffer[i]); - } - - LOG_T(MAC,"\n"); + LOG_T(MAC, "[eNB %d] First 16 bytes of DLSCH : \n"); + + for (i = 0; i < 16; i++) { + LOG_T(MAC, "%x.", dlsch_buffer[i]); + } + + LOG_T(MAC, "\n"); #endif - // cycle through SDUs and place in dlsch_buffer - memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset],dlsch_buffer,sdu_length_total); - // memcpy(&eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]); - - // fill remainder of DLSCH with random data - for (j=0; j<(TBS-sdu_length_total-offset); j++) { - UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset+sdu_length_total+j] = (char)(taus()&0xff); - } - - //eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0][offset+sdu_lengths[0]+j] = (char)(taus()&0xff); - if (opt_enabled == 1) { - trace_pdu(1, (uint8_t *)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], - TBS, mod_id, 3, UE_RNTI(mod_id, UE_id), - eNB->frame, eNB->subframe,0,0); - LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n", - mod_id, CC_id, frame, UE_RNTI(mod_id,UE_id), TBS); - } - - // store stats - eNB->eNB_stats[CC_id].dlsch_bytes_tx+=sdu_length_total; - eNB->eNB_stats[CC_id].dlsch_pdus_tx+=1; - UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->DL_cqi[0]; - - UE_list->eNB_UE_stats[CC_id][UE_id].crnti= rnti; - UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status=mac_eNB_get_rrc_status(mod_id, rnti); - UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid; - UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round; - - //nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - //Find the number of resource blocks and set them to the template for retransmissions - nb_rb = get_min_rb_unit(mod_id, CC_id); - uint16_t stats_tbs = mac_xface->get_TBS_DL(dl_dci->mcs[0], nb_rb); + // cycle through SDUs and place in dlsch_buffer + memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id]. + payload[0][offset], dlsch_buffer, sdu_length_total); + // memcpy(&eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]); - while (stats_tbs < TBS) { - nb_rb += get_min_rb_unit(mod_id, CC_id); - stats_tbs = mac_xface->get_TBS_DL(dl_dci->mcs[0], nb_rb); + // fill remainder of DLSCH with random data + for (j = 0; j < (TBS - sdu_length_total - offset); j++) { + UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset + + sdu_length_total + + j] = + (char) (taus() & 0xff); + } + + //eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0][offset+sdu_lengths[0]+j] = (char)(taus()&0xff); + if (opt_enabled == 1) { + trace_pdu(1, + (uint8_t *) + UE_list->DLSCH_pdu[CC_id][0][UE_id]. + payload[0], TBS, mod_id, 3, UE_RNTI(mod_id, + UE_id), + eNB->frame, eNB->subframe, 0, 0); + LOG_D(OPT, + "[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n", + mod_id, CC_id, frame, UE_RNTI(mod_id, UE_id), + TBS); + } + // store stats + eNB->eNB_stats[CC_id].dlsch_bytes_tx += sdu_length_total; + eNB->eNB_stats[CC_id].dlsch_pdus_tx += 1; + UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi = + eNB_UE_stats->DL_cqi[0]; + + UE_list->eNB_UE_stats[CC_id][UE_id].crnti = rnti; + UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status = + mac_eNB_get_rrc_status(mod_id, rnti); + UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid; + UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round; + + //nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + //Find the number of resource blocks and set them to the template for retransmissions + nb_rb = get_min_rb_unit(mod_id, CC_id); + uint16_t stats_tbs = + mac_xface->get_TBS_DL(dl_dci->mcs[0], nb_rb); + + while (stats_tbs < TBS) { + nb_rb += get_min_rb_unit(mod_id, CC_id); + stats_tbs = + mac_xface->get_TBS_DL(dl_dci->mcs[0], nb_rb); + } + + // LOG_I(FLEXRAN_AGENT, "The MCS was %d\n", dl_dci->mcs[0]); + + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += + nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = + dl_dci->mcs[0]; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = + dl_dci->mcs[0]; + UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; + + UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes = + TBS - sdu_length_total; + UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes += + sdu_length_total; + UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes += TBS; + UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus += 1; + + //eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; + //eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); + } else { + LOG_D(FLEXRAN_AGENT, + "No need to schedule a dci after all. Just drop it\n"); + harq_pid_updated[UE_id][harq_pid] = 1; + harq_pid_round[UE_id][harq_pid] = 0; + continue; + } + } else { + // No need to create anything apart of DCI in case of retransmission + /*TODO: Must add these */ + // eNB_UE_stats->dlsch_trials[round]++; + //UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1; + //UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb; + //UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb; + //UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used_retx=nCCECC_id]; } - // LOG_I(FLEXRAN_AGENT, "The MCS was %d\n", dl_dci->mcs[0]); - - UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=dl_dci->mcs[0]; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=dl_dci->mcs[0]; - UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; - - UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes= TBS - sdu_length_total; - UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes+= sdu_length_total; - UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes+= TBS; - UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus+=1; - - //eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; - //eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); - } else { - LOG_D(FLEXRAN_AGENT, "No need to schedule a dci after all. Just drop it\n"); - harq_pid_updated[UE_id][harq_pid] = 1; - harq_pid_round[UE_id][harq_pid] = 0; - continue; - } - } else { - // No need to create anything apart of DCI in case of retransmission - /*TODO: Must add these */ - // eNB_UE_stats->dlsch_trials[round]++; - //UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1; - //UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb; - //UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb; - //UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used_retx=nCCECC_id]; + // UE_list->UE_template[CC_id][UE_id].oldNDI[dl_dci->harq_process] = dl_dci->ndi[0]; + // eNB_UE_stats->dlsch_mcs1 = dl_dci->mcs[0]; + + //Fill the proper DCI of OAI + flexran_fill_oai_dci(mod_id, CC_id, rnti, dl_dci); } - - // UE_list->UE_template[CC_id][UE_id].oldNDI[dl_dci->harq_process] = dl_dci->ndi[0]; - // eNB_UE_stats->dlsch_mcs1 = dl_dci->mcs[0]; - - //Fill the proper DCI of OAI - flexran_fill_oai_dci(mod_id, CC_id, rnti, dl_dci); - } } -void flexran_fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, - Protocol__FlexDlDci *dl_dci) { - void *DLSCH_dci = NULL; - DCI_PDU *DCI_pdu; +void +flexran_fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, + Protocol__FlexDlDci * dl_dci) +{ - unsigned char harq_pid = 0; - // unsigned char round = 0; - LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; - int size_bits = 0, size_bytes = 0; - eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; - UE_list_t *UE_list = &eNB->UE_list; - LTE_eNB_UE_stats *eNB_UE_stats = NULL; + void *DLSCH_dci = NULL; + DCI_PDU *DCI_pdu; - int UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]); + unsigned char harq_pid = 0; + // unsigned char round = 0; + LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; + int size_bits = 0, size_bytes = 0; + eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; + UE_list_t *UE_list = &eNB->UE_list; + LTE_eNB_UE_stats *eNB_UE_stats = NULL; - uint32_t format; + int UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]); - harq_pid = dl_dci->harq_process; - // round = dl_dci->rv[0]; - - // Note this code is for a specific DCI format - DLSCH_dci = (void *)UE_list->UE_template[CC_id][UE_id].DLSCH_DCI[harq_pid]; - DCI_pdu = &eNB->common_channels[CC_id].DCI_pdu; - - frame_parms[CC_id] = mac_xface->get_lte_frame_parms(mod_id, CC_id); + uint32_t format; - if (dl_dci->has_tpc == 1) { - // Check if tpc has been set and reset measurement */ - if ((dl_dci->tpc == 0) || (dl_dci->tpc == 2)) { - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - eNB_UE_stats->Po_PUCCH_update = 0; + harq_pid = dl_dci->harq_process; + // round = dl_dci->rv[0]; + + // Note this code is for a specific DCI format + DLSCH_dci = + (void *) UE_list->UE_template[CC_id][UE_id].DLSCH_DCI[harq_pid]; + DCI_pdu = &eNB->common_channels[CC_id].DCI_pdu; + + frame_parms[CC_id] = mac_xface->get_lte_frame_parms(mod_id, CC_id); + + if (dl_dci->has_tpc == 1) { + // Check if tpc has been set and reset measurement */ + if ((dl_dci->tpc == 0) || (dl_dci->tpc == 2)) { + eNB_UE_stats = + mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + eNB_UE_stats->Po_PUCCH_update = 0; + } } - } - - - switch (frame_parms[CC_id]->N_RB_DL) { - case 6: - if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_TDD_1(DCI1_1_5MHz_TDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_1_5MHz_TDD_t); - size_bits = sizeof_DCI1_1_5MHz_TDD_t; - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } else { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_FDD_1(DCI1_1_5MHz_FDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_1_5MHz_FDD_t); - size_bits = sizeof_DCI1_1_5MHz_FDD_t; - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } - break; - case 25: - if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_TDD_1(DCI1_5MHz_TDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_5MHz_TDD_t); - size_bits = sizeof_DCI1_5MHz_TDD_t; - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } else { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_FDD_1(DCI1_5MHz_FDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_5MHz_FDD_t); - size_bits = sizeof_DCI1_5MHz_FDD_t; - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } - break; - case 50: - if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_TDD_1(DCI1_10MHz_TDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_10MHz_TDD_t); - size_bits = sizeof_DCI1_10MHz_TDD_t; - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } else { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_FDD_1(DCI1_10MHz_FDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_10MHz_FDD_t); - size_bits = sizeof_DCI1_10MHz_FDD_t; - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } - break; - case 100: - if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_TDD_1(DCI1_20MHz_TDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_20MHz_TDD_t); - size_bits = sizeof_DCI1_20MHz_TDD_t; - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } else { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_FDD_1(DCI1_20MHz_FDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_20MHz_FDD_t); - size_bits = sizeof_DCI1_20MHz_FDD_t; - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } - break; - } - //Set format to the proper type - switch(dl_dci->format) { - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1: - format = format1; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1A: - format = format1A; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1B: - format = format1B; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1C: - format = format1C; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D: - format = format1E_2A_M10PRB; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2: - format = format2; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A: - format = format2A; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2B: - format = format2B; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_3: - format = 3; - break; - default: - /*TODO: Need to deal with unsupported DCI type*/ - return; - } - - add_ue_spec_dci(DCI_pdu, - DLSCH_dci, - rnti, - size_bytes, - dl_dci->aggr_level, - size_bits, - format, - 0); + + switch (frame_parms[CC_id]->N_RB_DL) { + case 6: + if (frame_parms[CC_id]->frame_type == TDD) { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { + FILL_DCI_TDD_1(DCI1_1_5MHz_TDD_t, DLSCH_dci, dl_dci); + size_bytes = sizeof(DCI1_1_5MHz_TDD_t); + size_bits = sizeof_DCI1_1_5MHz_TDD_t; + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { + //TODO + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { + //TODO + } + } else { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { + FILL_DCI_FDD_1(DCI1_1_5MHz_FDD_t, DLSCH_dci, dl_dci); + size_bytes = sizeof(DCI1_1_5MHz_FDD_t); + size_bits = sizeof_DCI1_1_5MHz_FDD_t; + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { + //TODO + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { + //TODO + } + } + break; + case 25: + if (frame_parms[CC_id]->frame_type == TDD) { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { + FILL_DCI_TDD_1(DCI1_5MHz_TDD_t, DLSCH_dci, dl_dci); + size_bytes = sizeof(DCI1_5MHz_TDD_t); + size_bits = sizeof_DCI1_5MHz_TDD_t; + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { + //TODO + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { + //TODO + } + } else { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { + FILL_DCI_FDD_1(DCI1_5MHz_FDD_t, DLSCH_dci, dl_dci); + size_bytes = sizeof(DCI1_5MHz_FDD_t); + size_bits = sizeof_DCI1_5MHz_FDD_t; + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { + //TODO + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { + //TODO + } + } + break; + case 50: + if (frame_parms[CC_id]->frame_type == TDD) { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { + FILL_DCI_TDD_1(DCI1_10MHz_TDD_t, DLSCH_dci, dl_dci); + size_bytes = sizeof(DCI1_10MHz_TDD_t); + size_bits = sizeof_DCI1_10MHz_TDD_t; + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { + //TODO + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { + //TODO + } + } else { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { + FILL_DCI_FDD_1(DCI1_10MHz_FDD_t, DLSCH_dci, dl_dci); + size_bytes = sizeof(DCI1_10MHz_FDD_t); + size_bits = sizeof_DCI1_10MHz_FDD_t; + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { + //TODO + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { + //TODO + } + } + break; + case 100: + if (frame_parms[CC_id]->frame_type == TDD) { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { + FILL_DCI_TDD_1(DCI1_20MHz_TDD_t, DLSCH_dci, dl_dci); + size_bytes = sizeof(DCI1_20MHz_TDD_t); + size_bits = sizeof_DCI1_20MHz_TDD_t; + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { + //TODO + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { + //TODO + } + } else { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { + FILL_DCI_FDD_1(DCI1_20MHz_FDD_t, DLSCH_dci, dl_dci); + size_bytes = sizeof(DCI1_20MHz_FDD_t); + size_bits = sizeof_DCI1_20MHz_FDD_t; + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { + //TODO + } else if (dl_dci->format == + PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { + //TODO + } + } + break; + } + + //Set format to the proper type + switch (dl_dci->format) { + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1: + format = format1; + break; + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1A: + format = format1A; + break; + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1B: + format = format1B; + break; + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1C: + format = format1C; + break; + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D: + format = format1E_2A_M10PRB; + break; + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2: + format = format2; + break; + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A: + format = format2A; + break; + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2B: + format = format2B; + break; + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_3: + format = 3; + break; + default: + /*TODO: Need to deal with unsupported DCI type */ + return; + } + + add_ue_spec_dci(DCI_pdu, + DLSCH_dci, + rnti, + size_bytes, dl_dci->aggr_level, size_bits, format, 0); } diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index ee0e7c5582..3a491bd7ea 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -17,7 +17,7 @@ *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org - */ + */ /*! \file flexran_agent_scheduler_dlsch_ue.c * \brief procedures related to eNB for the DLSCH transport channel @@ -58,10 +58,10 @@ #include "flexran_agent_mac.h" #include -#include "SIMULATION/TOOLS/defs.h" // for taus +#include "SIMULATION/TOOLS/defs.h" // for taus #if defined(ENABLE_ITTI) -# include "intertask_interface.h" +#include "intertask_interface.h" #endif #define ENABLE_MAC_PAYLOAD_DEBUG @@ -74,14 +74,14 @@ /*!\brief UE ULSCH scheduling states*/ typedef enum { - MIN_SLICE_STRATEGY = 0, - SLICE_MASK, - UEID_TO_SLICEID, - MAX_SLICE_STRATEGY + MIN_SLICE_STRATEGY = 0, + SLICE_MASK, + UEID_TO_SLICEID, + MAX_SLICE_STRATEGY } SLICING_STRATEGY; // this assumes a max of of 16 UE per eNB/CC -#define SLICE0_MASK 0x000f +#define SLICE0_MASK 0x000f #define SLICE1_MASK 0x00f0 #define SLICE2_MASK 0x0f00 #define SLICE3_MASK 0xf000 @@ -96,26 +96,28 @@ int slicing_strategy = UEID_TO_SLICEID; int slicing_strategy_current = UEID_TO_SLICEID; // RB share for each slice for past and current time -float slice_percentage[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; -float slice_percentage_current[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; +float slice_percentage[MAX_NUM_SLICES] = { 1.0, 0.0, 0.0, 0.0 }; +float slice_percentage_current[MAX_NUM_SLICES] = { 1.0, 0.0, 0.0, 0.0 }; + float total_slice_percentage = 0; // MAX MCS for each slice for past and current time -int slice_maxmcs[MAX_NUM_SLICES] = {28, 28, 28, 28}; -int slice_maxmcs_current[MAX_NUM_SLICES] = {28, 28, 28, 28}; +int slice_maxmcs[MAX_NUM_SLICES] = { 28, 28, 28, 28 }; +int slice_maxmcs_current[MAX_NUM_SLICES] = { 28, 28, 28, 28 }; -int update_dl_scheduler[MAX_NUM_SLICES] = {1, 1, 1, 1}; -int update_dl_scheduler_current[MAX_NUM_SLICES] = {1, 1, 1, 1}; +int update_dl_scheduler[MAX_NUM_SLICES] = { 1, 1, 1, 1 }; +int update_dl_scheduler_current[MAX_NUM_SLICES] = { 1, 1, 1, 1 }; // name of available scheduler -char *dl_scheduler_type[MAX_NUM_SLICES] = {"flexran_schedule_ue_spec_embb", - "flexran_schedule_ue_spec_urllc", - "flexran_schedule_ue_spec_mmtc", - "flexran_schedule_ue_spec_be" // best effort +char *dl_scheduler_type[MAX_NUM_SLICES] = + { "flexran_schedule_ue_spec_embb", + "flexran_schedule_ue_spec_urllc", + "flexran_schedule_ue_spec_mmtc", + "flexran_schedule_ue_spec_be" // best effort }; // pointer to the slice specific scheduler -slice_scheduler slice_sched[MAX_NUM_SLICES] = {0}; +slice_scheduler slice_sched[MAX_NUM_SLICES] = { 0 }; /** @@ -125,585 +127,695 @@ slice_scheduler slice_sched[MAX_NUM_SLICES] = {0}; // This function stores the downlink buffer for all the logical channels -void _store_dlsch_buffer (module_id_t Mod_id, - int slice_id, - frame_t frameP, - sub_frame_t subframeP) +void +_store_dlsch_buffer(module_id_t Mod_id, + int slice_id, frame_t frameP, sub_frame_t subframeP) { - int UE_id,i; - rnti_t rnti; - mac_rlc_status_resp_t rlc_status; - UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; - UE_TEMPLATE *UE_template; + int UE_id, i; + rnti_t rnti; + mac_rlc_status_resp_t rlc_status; + UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; + UE_TEMPLATE *UE_template; - for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { - if (UE_list->active[UE_id] != TRUE) continue; - - if (flexran_slice_member(UE_id, slice_id) == 0) - continue; - - UE_template = &UE_list->UE_template[UE_PCCID(Mod_id,UE_id)][UE_id]; + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { + if (UE_list->active[UE_id] != TRUE) + continue; - // clear logical channel interface variables - UE_template->dl_buffer_total = 0; - UE_template->dl_pdus_total = 0; + if (flexran_slice_member(UE_id, slice_id) == 0) + continue; - for(i=0; i< MAX_NUM_LCID; i++) { - UE_template->dl_buffer_info[i]=0; - UE_template->dl_pdus_in_buffer[i]=0; - UE_template->dl_buffer_head_sdu_creation_time[i]=0; - UE_template->dl_buffer_head_sdu_remaining_size_to_send[i]=0; - } + UE_template = + &UE_list->UE_template[UE_PCCID(Mod_id, UE_id)][UE_id]; - rnti = UE_RNTI(Mod_id,UE_id); + // clear logical channel interface variables + UE_template->dl_buffer_total = 0; + UE_template->dl_pdus_total = 0; - for(i=0; i< MAX_NUM_LCID; i++) { // loop over all the logical channels + for (i = 0; i < MAX_NUM_LCID; i++) { + UE_template->dl_buffer_info[i] = 0; + UE_template->dl_pdus_in_buffer[i] = 0; + UE_template->dl_buffer_head_sdu_creation_time[i] = 0; + UE_template->dl_buffer_head_sdu_remaining_size_to_send[i] = 0; + } - rlc_status = mac_rlc_status_ind(Mod_id,rnti, Mod_id,frameP,subframeP,ENB_FLAG_YES,MBMS_FLAG_NO,i,0 ); - UE_template->dl_buffer_info[i] = rlc_status.bytes_in_buffer; //storing the dlsch buffer for each logical channel - UE_template->dl_pdus_in_buffer[i] = rlc_status.pdus_in_buffer; - UE_template->dl_buffer_head_sdu_creation_time[i] = rlc_status.head_sdu_creation_time ; - UE_template->dl_buffer_head_sdu_creation_time_max = cmax(UE_template->dl_buffer_head_sdu_creation_time_max, - rlc_status.head_sdu_creation_time ); - UE_template->dl_buffer_head_sdu_remaining_size_to_send[i] = rlc_status.head_sdu_remaining_size_to_send; - UE_template->dl_buffer_head_sdu_is_segmented[i] = rlc_status.head_sdu_is_segmented; - UE_template->dl_buffer_total += UE_template->dl_buffer_info[i];//storing the total dlsch buffer - UE_template->dl_pdus_total += UE_template->dl_pdus_in_buffer[i]; + rnti = UE_RNTI(Mod_id, UE_id); + + for (i = 0; i < MAX_NUM_LCID; i++) { // loop over all the logical channels + + rlc_status = + mac_rlc_status_ind(Mod_id, rnti, Mod_id, frameP, subframeP, + ENB_FLAG_YES, MBMS_FLAG_NO, i, 0); + UE_template->dl_buffer_info[i] = rlc_status.bytes_in_buffer; //storing the dlsch buffer for each logical channel + UE_template->dl_pdus_in_buffer[i] = rlc_status.pdus_in_buffer; + UE_template->dl_buffer_head_sdu_creation_time[i] = + rlc_status.head_sdu_creation_time; + UE_template->dl_buffer_head_sdu_creation_time_max = + cmax(UE_template->dl_buffer_head_sdu_creation_time_max, + rlc_status.head_sdu_creation_time); + UE_template->dl_buffer_head_sdu_remaining_size_to_send[i] = + rlc_status.head_sdu_remaining_size_to_send; + UE_template->dl_buffer_head_sdu_is_segmented[i] = + rlc_status.head_sdu_is_segmented; + UE_template->dl_buffer_total += UE_template->dl_buffer_info[i]; //storing the total dlsch buffer + UE_template->dl_pdus_total += + UE_template->dl_pdus_in_buffer[i]; #ifdef DEBUG_eNB_SCHEDULER - /* note for dl_buffer_head_sdu_remaining_size_to_send[i] : - * 0 if head SDU has not been segmented (yet), else remaining size not already segmented and sent - */ - if (UE_template->dl_buffer_info[i]>0) - LOG_D(MAC, - "[eNB %d][SLICE %d] Frame %d Subframe %d : RLC status for UE %d in LCID%d: total of %d pdus and size %d, head sdu queuing time %d, remaining size %d, is segmeneted %d \n", - Mod_id, slice_id,frameP, subframeP, UE_id, - i, UE_template->dl_pdus_in_buffer[i],UE_template->dl_buffer_info[i], - UE_template->dl_buffer_head_sdu_creation_time[i], - UE_template->dl_buffer_head_sdu_remaining_size_to_send[i], - UE_template->dl_buffer_head_sdu_is_segmented[i] - ); + /* note for dl_buffer_head_sdu_remaining_size_to_send[i] : + * 0 if head SDU has not been segmented (yet), else remaining size not already segmented and sent + */ + if (UE_template->dl_buffer_info[i] > 0) + LOG_D(MAC, + "[eNB %d][SLICE %d] Frame %d Subframe %d : RLC status for UE %d in LCID%d: total of %d pdus and size %d, head sdu queuing time %d, remaining size %d, is segmeneted %d \n", + Mod_id, slice_id, frameP, subframeP, UE_id, + i, UE_template->dl_pdus_in_buffer[i], + UE_template->dl_buffer_info[i], + UE_template->dl_buffer_head_sdu_creation_time[i], + UE_template-> + dl_buffer_head_sdu_remaining_size_to_send[i], + UE_template->dl_buffer_head_sdu_is_segmented[i]); #endif + } + + //#ifdef DEBUG_eNB_SCHEDULER + if (UE_template->dl_buffer_total > 0) + LOG_D(MAC, + "[eNB %d] Frame %d Subframe %d : RLC status for UE %d : total DL buffer size %d and total number of pdu %d \n", + Mod_id, frameP, subframeP, UE_id, + UE_template->dl_buffer_total, + UE_template->dl_pdus_total); + + //#endif } - - //#ifdef DEBUG_eNB_SCHEDULER - if ( UE_template->dl_buffer_total>0) - LOG_D(MAC,"[eNB %d] Frame %d Subframe %d : RLC status for UE %d : total DL buffer size %d and total number of pdu %d \n", - Mod_id, frameP, subframeP, UE_id, - UE_template->dl_buffer_total, - UE_template->dl_pdus_total - ); - - //#endif - } } // This function returns the estimated number of RBs required by each UE for downlink scheduling -void _assign_rbs_required (module_id_t Mod_id, - int slice_id, - frame_t frameP, - sub_frame_t subframe, - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES], - int min_rb_unit[MAX_NUM_CCs]) +void +_assign_rbs_required(module_id_t Mod_id, + int slice_id, + frame_t frameP, + sub_frame_t subframe, + uint16_t + nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], + uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs] + [MAX_NUM_SLICES], int min_rb_unit[MAX_NUM_CCs]) { - rnti_t rnti; - uint16_t TBS = 0; - LTE_eNB_UE_stats *eNB_UE_stats[MAX_NUM_CCs]; - int UE_id,n,i,j,CC_id,pCCid,tmp; - UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; - // UE_TEMPLATE *UE_template; + rnti_t rnti; + uint16_t TBS = 0; + LTE_eNB_UE_stats *eNB_UE_stats[MAX_NUM_CCs]; + int UE_id, n, i, j, CC_id, pCCid, tmp; + UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; + // UE_TEMPLATE *UE_template; - // clear rb allocations across all CC_ids - for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { - if (UE_list->active[UE_id] != TRUE) continue; - - if (flexran_slice_member(UE_id, slice_id) == 0) - continue; - - pCCid = UE_PCCID(Mod_id,UE_id); - rnti = UE_list->UE_template[pCCid][UE_id].rnti; + // clear rb allocations across all CC_ids + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { + if (UE_list->active[UE_id] != TRUE) + continue; - /* skip UE not present in PHY (for any of its active CCs) */ - if (!phy_stats_exist(Mod_id, rnti)) - continue; + if (flexran_slice_member(UE_id, slice_id) == 0) + continue; - //update CQI information across component carriers - for (n=0; nnumactiveCCs[UE_id]; n++) { - CC_id = UE_list->ordered_CCids[n][UE_id]; - eNB_UE_stats[CC_id] = mac_xface->get_eNB_UE_stats(Mod_id,CC_id,rnti); - eNB_UE_stats[CC_id]->dlsch_mcs1 = cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)]; - } + pCCid = UE_PCCID(Mod_id, UE_id); + rnti = UE_list->UE_template[pCCid][UE_id].rnti; - // provide the list of CCs sorted according to MCS - for (i=0; inumactiveCCs[UE_id]; i++) { - for (j=i+1; jnumactiveCCs[UE_id]; j++) { - DevAssert( j < MAX_NUM_CCs ); + /* skip UE not present in PHY (for any of its active CCs) */ + if (!phy_stats_exist(Mod_id, rnti)) + continue; - if (eNB_UE_stats[UE_list->ordered_CCids[i][UE_id]]->dlsch_mcs1 > - eNB_UE_stats[UE_list->ordered_CCids[j][UE_id]]->dlsch_mcs1) { - tmp = UE_list->ordered_CCids[i][UE_id]; - UE_list->ordered_CCids[i][UE_id] = UE_list->ordered_CCids[j][UE_id]; - UE_list->ordered_CCids[j][UE_id] = tmp; - } - } - } + //update CQI information across component carriers + for (n = 0; n < UE_list->numactiveCCs[UE_id]; n++) { + CC_id = UE_list->ordered_CCids[n][UE_id]; + eNB_UE_stats[CC_id] = + mac_xface->get_eNB_UE_stats(Mod_id, CC_id, rnti); + eNB_UE_stats[CC_id]->dlsch_mcs1 = + cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)]; + } - /* NN --> RK - * check the index of UE_template" - */ - if (UE_list->UE_template[pCCid][UE_id].dl_buffer_total> 0) { - LOG_D(MAC,"[preprocessor] assign RB for UE %d\n",UE_id); + // provide the list of CCs sorted according to MCS + for (i = 0; i < UE_list->numactiveCCs[UE_id]; i++) { + for (j = i + 1; j < UE_list->numactiveCCs[UE_id]; j++) { + DevAssert(j < MAX_NUM_CCs); - for (i=0; inumactiveCCs[UE_id]; i++) { - CC_id = UE_list->ordered_CCids[i][UE_id]; - eNB_UE_stats[CC_id] = mac_xface->get_eNB_UE_stats(Mod_id,CC_id,rnti); - - if (cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)] == 0) {//eNB_UE_stats[CC_id]->dlsch_mcs1==0) { - nb_rbs_required[CC_id][UE_id] = 4; // don't let the TBS get too small - } else { - nb_rbs_required[CC_id][UE_id] = min_rb_unit[CC_id]; - } - - TBS = mac_xface->get_TBS_DL(cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)], nb_rbs_required[CC_id][UE_id]); - nb_rbs_allowed_slice[CC_id][slice_id] = flexran_nb_rbs_allowed_slice(slice_percentage[slice_id], - flexran_get_N_RB_DL(Mod_id, CC_id)); - LOG_D(MAC,"[preprocessor] start RB assignement for UE %d CC_id %d dl buffer %d (RB unit %d, MCS %d, TBS %d) \n", - UE_id, CC_id, UE_list->UE_template[pCCid][UE_id].dl_buffer_total, - nb_rbs_required[CC_id][UE_id], flexran_get_ue_wcqi(Mod_id, UE_id), TBS); - - /* calculating required number of RBs for each UE */ - while (TBS < UE_list->UE_template[pCCid][UE_id].dl_buffer_total) { - nb_rbs_required[CC_id][UE_id] += min_rb_unit[CC_id]; + if (eNB_UE_stats[UE_list->ordered_CCids[i][UE_id]]-> + dlsch_mcs1 > + eNB_UE_stats[UE_list->ordered_CCids[j][UE_id]]-> + dlsch_mcs1) { + tmp = UE_list->ordered_CCids[i][UE_id]; + UE_list->ordered_CCids[i][UE_id] = + UE_list->ordered_CCids[j][UE_id]; + UE_list->ordered_CCids[j][UE_id] = tmp; + } + } + } - if (nb_rbs_required[CC_id][UE_id] > nb_rbs_allowed_slice[CC_id][slice_id]) { - TBS = mac_xface->get_TBS_DL(flexran_get_ue_wcqi(Mod_id, UE_id), nb_rbs_allowed_slice[CC_id][slice_id]); - nb_rbs_required[CC_id][UE_id] = nb_rbs_allowed_slice[CC_id][slice_id]; - break; - } + /* NN --> RK + * check the index of UE_template" + */ + if (UE_list->UE_template[pCCid][UE_id].dl_buffer_total > 0) { + LOG_D(MAC, "[preprocessor] assign RB for UE %d\n", UE_id); - TBS = mac_xface->get_TBS_DL(cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)], nb_rbs_required[CC_id][UE_id]); - } // end of while + for (i = 0; i < UE_list->numactiveCCs[UE_id]; i++) { + CC_id = UE_list->ordered_CCids[i][UE_id]; + eNB_UE_stats[CC_id] = + mac_xface->get_eNB_UE_stats(Mod_id, CC_id, rnti); - LOG_D(MAC,"[eNB %d][SLICE %d] Frame %d: UE %d on CC %d: RB unit %d, nb_required RB %d (TBS %d, mcs %d)\n", - Mod_id, slice_id,frameP,UE_id, CC_id, min_rb_unit[CC_id], nb_rbs_required[CC_id][UE_id], TBS, cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)]); - } - } - } -} + if (cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)] == 0) { //eNB_UE_stats[CC_id]->dlsch_mcs1==0) { + nb_rbs_required[CC_id][UE_id] = 4; // don't let the TBS get too small + } else { + nb_rbs_required[CC_id][UE_id] = min_rb_unit[CC_id]; + } -void _dlsch_scheduler_pre_processor_allocate (module_id_t Mod_id, - int UE_id, - uint8_t CC_id, - int N_RBG, - int transmission_mode, - int min_rb_unit, - uint8_t N_RB_DL, - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], - unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]) { - int i; - UE_list_t *UE_list=&eNB_mac_inst[Mod_id].UE_list; - UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + TBS = + mac_xface->get_TBS_DL(cqi_to_mcs + [flexran_get_ue_wcqi + (Mod_id, UE_id)], + nb_rbs_required[CC_id][UE_id]); + nb_rbs_allowed_slice[CC_id][slice_id] = + flexran_nb_rbs_allowed_slice(slice_percentage + [slice_id], + flexran_get_N_RB_DL + (Mod_id, CC_id)); + LOG_D(MAC, + "[preprocessor] start RB assignement for UE %d CC_id %d dl buffer %d (RB unit %d, MCS %d, TBS %d) \n", + UE_id, CC_id, + UE_list->UE_template[pCCid][UE_id].dl_buffer_total, + nb_rbs_required[CC_id][UE_id], + flexran_get_ue_wcqi(Mod_id, UE_id), TBS); - for(i=0; iUE_template[pCCid][UE_id]. + dl_buffer_total) { + nb_rbs_required[CC_id][UE_id] += min_rb_unit[CC_id]; - if((rballoc_sub[CC_id][i] == 0) && - (ue_sched_ctl->rballoc_sub_UE[CC_id][i] == 0) && - (nb_rbs_required_remaining[CC_id][UE_id]>0) && - (ue_sched_ctl->pre_nb_available_rbs[CC_id] < nb_rbs_required[CC_id][UE_id])) { + if (nb_rbs_required[CC_id][UE_id] > + nb_rbs_allowed_slice[CC_id][slice_id]) { + TBS = + mac_xface->get_TBS_DL(flexran_get_ue_wcqi + (Mod_id, UE_id), + nb_rbs_allowed_slice + [CC_id] + [slice_id]); + nb_rbs_required[CC_id][UE_id] = + nb_rbs_allowed_slice[CC_id][slice_id]; + break; + } - // if this UE is not scheduled for TM5 - if (ue_sched_ctl->dl_pow_off[CC_id] != 0 ) { + TBS = + mac_xface->get_TBS_DL(cqi_to_mcs + [flexran_get_ue_wcqi + (Mod_id, UE_id)], + nb_rbs_required[CC_id] + [UE_id]); + } // end of while - if ((i == N_RBG-1) && ((N_RB_DL == 25) || (N_RB_DL == 50))) { - rballoc_sub[CC_id][i] = 1; - ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 1; - MIMO_mode_indicator[CC_id][i] = 1; - if (transmission_mode == 5 ) { - ue_sched_ctl->dl_pow_off[CC_id] = 1; - } - nb_rbs_required_remaining[CC_id][UE_id] = nb_rbs_required_remaining[CC_id][UE_id] - min_rb_unit+1; - ue_sched_ctl->pre_nb_available_rbs[CC_id] = ue_sched_ctl->pre_nb_available_rbs[CC_id] + min_rb_unit - 1; - } else { - if (nb_rbs_required_remaining[CC_id][UE_id] >= min_rb_unit){ - rballoc_sub[CC_id][i] = 1; - ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 1; - MIMO_mode_indicator[CC_id][i] = 1; - if (transmission_mode == 5 ) { - ue_sched_ctl->dl_pow_off[CC_id] = 1; + LOG_D(MAC, + "[eNB %d][SLICE %d] Frame %d: UE %d on CC %d: RB unit %d, nb_required RB %d (TBS %d, mcs %d)\n", + Mod_id, slice_id, frameP, UE_id, CC_id, + min_rb_unit[CC_id], nb_rbs_required[CC_id][UE_id], + TBS, cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)]); } - nb_rbs_required_remaining[CC_id][UE_id] = nb_rbs_required_remaining[CC_id][UE_id] - min_rb_unit; - ue_sched_ctl->pre_nb_available_rbs[CC_id] = ue_sched_ctl->pre_nb_available_rbs[CC_id] + min_rb_unit; - } } - } // dl_pow_off[CC_id][UE_id] ! = 0 } - } } -void _dlsch_scheduler_pre_processor_reset (int module_idP, - int UE_id, - uint8_t CC_id, - int frameP, - int subframeP, - int N_RBG, - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES], - unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], - unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]) { - int i,j; - UE_list_t *UE_list=&eNB_mac_inst[module_idP].UE_list; - UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - uint8_t *vrb_map = eNB_mac_inst[module_idP].common_channels[CC_id].vrb_map; - int RBGsize = PHY_vars_eNB_g[module_idP][CC_id]->frame_parms.N_RB_DL/N_RBG; -#ifdef SF05_LIMIT - //int subframe05_limit=0; - int sf05_upper=-1,sf05_lower=-1; -#endif - // LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti); - - flexran_update_TA(module_idP, UE_id, CC_id); +void +_dlsch_scheduler_pre_processor_allocate(module_id_t Mod_id, + int UE_id, + uint8_t CC_id, + int N_RBG, + int transmission_mode, + int min_rb_unit, + uint8_t N_RB_DL, + uint16_t + nb_rbs_required[MAX_NUM_CCs] + [NUMBER_OF_UE_MAX], + uint16_t + nb_rbs_required_remaining + [MAX_NUM_CCs] + [NUMBER_OF_UE_MAX], unsigned char + rballoc_sub[MAX_NUM_CCs] + [N_RBG_MAX], unsigned char + MIMO_mode_indicator + [MAX_NUM_CCs][N_RBG_MAX]) +{ + int i; + UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; + UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - if (UE_id==0) { - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_TIMING_ADVANCE,ue_sched_ctl->ta_update); - } - nb_rbs_required[CC_id][UE_id]=0; - ue_sched_ctl->pre_nb_available_rbs[CC_id] = 0; - ue_sched_ctl->dl_pow_off[CC_id] = 2; - nb_rbs_required_remaining[CC_id][UE_id] = 0; - for (i=0; irballoc_sub_UE[CC_id][i] = 0; - rballoc_sub[CC_id][i] = 0; -#ifdef SF05_LIMIT - // for avoiding 6+ PRBs around DC in subframe 0-5 (avoid excessive errors) + for (i = 0; i < N_RBG; i++) { - if ((subframeP==0 || subframeP==5) && - (i>=sf05_lower && i<=sf05_upper)) - rballoc_sub[CC_id][i]=1; + if ((rballoc_sub[CC_id][i] == 0) && + (ue_sched_ctl->rballoc_sub_UE[CC_id][i] == 0) && + (nb_rbs_required_remaining[CC_id][UE_id] > 0) && + (ue_sched_ctl->pre_nb_available_rbs[CC_id] < + nb_rbs_required[CC_id][UE_id])) { + + // if this UE is not scheduled for TM5 + if (ue_sched_ctl->dl_pow_off[CC_id] != 0) { + + if ((i == N_RBG - 1) + && ((N_RB_DL == 25) || (N_RB_DL == 50))) { + rballoc_sub[CC_id][i] = 1; + ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 1; + MIMO_mode_indicator[CC_id][i] = 1; + if (transmission_mode == 5) { + ue_sched_ctl->dl_pow_off[CC_id] = 1; + } + nb_rbs_required_remaining[CC_id][UE_id] = + nb_rbs_required_remaining[CC_id][UE_id] - + min_rb_unit + 1; + ue_sched_ctl->pre_nb_available_rbs[CC_id] = + ue_sched_ctl->pre_nb_available_rbs[CC_id] + + min_rb_unit - 1; + } else { + if (nb_rbs_required_remaining[CC_id][UE_id] >= + min_rb_unit) { + rballoc_sub[CC_id][i] = 1; + ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 1; + MIMO_mode_indicator[CC_id][i] = 1; + if (transmission_mode == 5) { + ue_sched_ctl->dl_pow_off[CC_id] = 1; + } + nb_rbs_required_remaining[CC_id][UE_id] = + nb_rbs_required_remaining[CC_id][UE_id] - + min_rb_unit; + ue_sched_ctl->pre_nb_available_rbs[CC_id] = + ue_sched_ctl->pre_nb_available_rbs[CC_id] + + min_rb_unit; + } + } + } // dl_pow_off[CC_id][UE_id] ! = 0 + } + } +} + +void +_dlsch_scheduler_pre_processor_reset(int module_idP, + int UE_id, + uint8_t CC_id, + int frameP, + int subframeP, + int N_RBG, + uint16_t nb_rbs_required[MAX_NUM_CCs] + [NUMBER_OF_UE_MAX], + uint16_t + nb_rbs_required_remaining + [MAX_NUM_CCs][NUMBER_OF_UE_MAX], + uint16_t + nb_rbs_allowed_slice[MAX_NUM_CCs] + [MAX_NUM_SLICES], unsigned char + rballoc_sub[MAX_NUM_CCs] + [N_RBG_MAX], unsigned char + MIMO_mode_indicator[MAX_NUM_CCs] + [N_RBG_MAX]) +{ + int i, j; + UE_list_t *UE_list = &eNB_mac_inst[module_idP].UE_list; + UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + uint8_t *vrb_map = + eNB_mac_inst[module_idP].common_channels[CC_id].vrb_map; + int RBGsize = + PHY_vars_eNB_g[module_idP][CC_id]->frame_parms.N_RB_DL / N_RBG; +#ifdef SF05_LIMIT + //int subframe05_limit=0; + int sf05_upper = -1, sf05_lower = -1; #endif - // for SI-RNTI,RA-RNTI and P-RNTI allocations - for (j=0;jget_eNB_UE_stats(module_idP,CC_id,rnti); + + flexran_update_TA(module_idP, UE_id, CC_id); + + if (UE_id == 0) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME + (VCD_SIGNAL_DUMPER_VARIABLES_UE0_TIMING_ADVANCE, + ue_sched_ctl->ta_update); + } + nb_rbs_required[CC_id][UE_id] = 0; + ue_sched_ctl->pre_nb_available_rbs[CC_id] = 0; + ue_sched_ctl->dl_pow_off[CC_id] = 2; + nb_rbs_required_remaining[CC_id][UE_id] = 0; + for (i = 0; i < n_active_slices; i++) + nb_rbs_allowed_slice[CC_id][i] = 0; +#ifdef SF05_LIMIT + switch (N_RBG) { + case 6: + sf05_lower = 0; + sf05_upper = 5; break; - } + case 8: + sf05_lower = 2; + sf05_upper = 5; + break; + case 13: + sf05_lower = 4; + sf05_upper = 7; + break; + case 17: + sf05_lower = 7; + sf05_upper = 9; + break; + case 25: + sf05_lower = 11; + sf05_upper = 13; + break; + } +#endif + // Initialize Subbands according to VRB map + for (i = 0; i < N_RBG; i++) { + ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 0; + rballoc_sub[CC_id][i] = 0; +#ifdef SF05_LIMIT + // for avoiding 6+ PRBs around DC in subframe 0-5 (avoid excessive errors) + + if ((subframeP == 0 || subframeP == 5) && + (i >= sf05_lower && i <= sf05_upper)) + rballoc_sub[CC_id][i] = 1; +#endif + // for SI-RNTI,RA-RNTI and P-RNTI allocations + for (j = 0; j < RBGsize; j++) { + if (vrb_map[j + (i * RBGsize)] != 0) { + rballoc_sub[CC_id][i] = 1; + LOG_D(MAC, "Frame %d, subframe %d : vrb %d allocated\n", + frameP, subframeP, j + (i * RBGsize)); + break; + } + } + LOG_D(MAC, "Frame %d Subframe %d CC_id %d RBG %i : rb_alloc %d\n", + frameP, subframeP, CC_id, i, rballoc_sub[CC_id][i]); + MIMO_mode_indicator[CC_id][i] = 2; } - LOG_D(MAC,"Frame %d Subframe %d CC_id %d RBG %i : rb_alloc %d\n",frameP,subframeP,CC_id,i,rballoc_sub[CC_id][i]); - MIMO_mode_indicator[CC_id][i] = 2; - } } // This function assigns pre-available RBS to each UE in specified sub-bands before scheduling is done -void _dlsch_scheduler_pre_processor (module_id_t Mod_id, - int slice_id, - frame_t frameP, - sub_frame_t subframeP, - int N_RBG[MAX_NUM_CCs], - int *mbsfn_flag) +void +_dlsch_scheduler_pre_processor(module_id_t Mod_id, + int slice_id, + frame_t frameP, + sub_frame_t subframeP, + int N_RBG[MAX_NUM_CCs], int *mbsfn_flag) { - unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], total_ue_count; - unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]; - int UE_id, i; - uint8_t round = 0; - uint8_t harq_pid = 0; - uint16_t ii,j; - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES]; - uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - uint16_t nb_rbs_required_remaining_1[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - uint16_t average_rbs_per_user[MAX_NUM_CCs] = {0}; - rnti_t rnti; - int min_rb_unit[MAX_NUM_CCs]; - uint16_t r1=0; - uint8_t CC_id; - UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; - LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs] = {0}; + unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], total_ue_count; + unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]; + int UE_id, i; + uint8_t round = 0; + uint8_t harq_pid = 0; + uint16_t ii, j; + uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES]; + uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + uint16_t nb_rbs_required_remaining_1[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + uint16_t average_rbs_per_user[MAX_NUM_CCs] = { 0 }; + rnti_t rnti; + int min_rb_unit[MAX_NUM_CCs]; + uint16_t r1 = 0; + uint8_t CC_id; + UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; + LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs] = { 0 }; - int transmission_mode = 0; - UE_sched_ctrl *ue_sched_ctl; - - - for (CC_id=0; CC_id0) // If this CC is allocated for MBSFN skip it here - continue; - - frame_parms[CC_id] = mac_xface->get_lte_frame_parms(Mod_id,CC_id); - - - min_rb_unit[CC_id]=get_min_rb_unit(Mod_id,CC_id); - - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i] != TRUE) continue; - - UE_id = i; - // Initialize scheduling information for all active UEs - - //if (flexran_slice_member(UE_id, slice_id) == 0) - //continue; - _dlsch_scheduler_pre_processor_reset(Mod_id, - UE_id, - CC_id, - frameP, - subframeP, - N_RBG[CC_id], - nb_rbs_required, - nb_rbs_required_remaining, - nb_rbs_allowed_slice, - rballoc_sub, - MIMO_mode_indicator); - - } - } - - // Store the DLSCH buffer for each logical channel - _store_dlsch_buffer (Mod_id,slice_id,frameP,subframeP); - - // Calculate the number of RBs required by each UE on the basis of logical channel's buffer - _assign_rbs_required (Mod_id,slice_id, frameP,subframeP,nb_rbs_required,nb_rbs_allowed_slice,min_rb_unit); - - // Sorts the user on the basis of dlsch logical channel buffer and CQI - sort_UEs (Mod_id,frameP,subframeP); - - total_ue_count = 0; - - // loop over all active UEs - for (i=UE_list->head; i>=0; i=UE_list->next[i]) { - rnti = flexran_get_ue_crnti(Mod_id, i); - if(rnti == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - - UE_id = i; - - if (flexran_slice_member(UE_id, slice_id) == 0) - continue; - - if (!phy_stats_exist(Mod_id, rnti)) - continue; - - for (ii=0; ii < UE_num_active_CC(UE_list,UE_id); ii++) { - CC_id = UE_list->ordered_CCids[ii][UE_id]; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - ue_sched_ctl->max_allowed_rbs[CC_id]=nb_rbs_allowed_slice[CC_id][slice_id]; - flexran_get_harq(Mod_id, CC_id, UE_id, frameP, subframeP, &harq_pid, &round); - - // if there is no available harq_process, skip the UE - if (UE_list->UE_sched_ctrl[UE_id].harq_pid[CC_id]<0) - continue; - - average_rbs_per_user[CC_id]=0; - - frame_parms[CC_id] = mac_xface->get_lte_frame_parms(Mod_id,CC_id); - - // mac_xface->get_ue_active_harq_pid(Mod_id,CC_id,rnti,frameP,subframeP,&harq_pid,&round,0); - - if(round>0) { - nb_rbs_required[CC_id][UE_id] = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - } - - //nb_rbs_required_remaining[UE_id] = nb_rbs_required[UE_id]; - if (nb_rbs_required[CC_id][UE_id] > 0) { - total_ue_count = total_ue_count + 1; - } + int transmission_mode = 0; + UE_sched_ctrl *ue_sched_ctl; - // hypotetical assignement - /* - * If schedule is enabled and if the priority of the UEs is modified - * The average rbs per logical channel per user will depend on the level of - * priority. Concerning the hypothetical assignement, we should assign more - * rbs to prioritized users. Maybe, we can do a mapping between the - * average rbs per user and the level of priority or multiply the average rbs - * per user by a coefficient which represents the degree of priority. - */ + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - if (total_ue_count == 0) { - average_rbs_per_user[CC_id] = 0; - } else if( (min_rb_unit[CC_id] * total_ue_count) <= nb_rbs_allowed_slice[CC_id][slice_id] ) { - average_rbs_per_user[CC_id] = (uint16_t) floor(nb_rbs_allowed_slice[CC_id][slice_id]/total_ue_count); - } else { - average_rbs_per_user[CC_id] = min_rb_unit[CC_id]; // consider the total number of use that can be scheduled UE - } - } - } - - // note: nb_rbs_required is assigned according to total_buffer_dl - // extend nb_rbs_required to capture per LCID RB required - for(i=UE_list->head; i>=0; i=UE_list->next[i]) { - rnti = UE_RNTI(Mod_id,i); - - if(rnti == NOT_A_RNTI) - continue; - - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - - if (!phy_stats_exist(Mod_id, rnti)) - continue; - - if (flexran_slice_member(i, slice_id) == 0) - continue; - - for (ii=0; iiordered_CCids[ii][i]; - - // control channel - if (mac_eNB_get_rrc_status(Mod_id,rnti) < RRC_RECONFIGURED) { - nb_rbs_required_remaining_1[CC_id][i] = nb_rbs_required[CC_id][i]; - } else { - nb_rbs_required_remaining_1[CC_id][i] = cmin(average_rbs_per_user[CC_id],nb_rbs_required[CC_id][i]); - - } - } - } - - //Allocation to UEs is done in 2 rounds, - // 1st stage: average number of RBs allocated to each UE - // 2nd stage: remaining RBs are allocated to high priority UEs - for(r1=0; r1<2; r1++) { - - for(i=UE_list->head; i>=0; i=UE_list->next[i]) { - - if (flexran_slice_member(i, slice_id) == 0) - continue; - - for (ii=0; iiordered_CCids[ii][i]; - - if(r1 == 0) { - nb_rbs_required_remaining[CC_id][i] = nb_rbs_required_remaining_1[CC_id][i]; - } else { // rb required based only on the buffer - rb allloctaed in the 1st round + extra reaming rb form the 1st round - nb_rbs_required_remaining[CC_id][i] = nb_rbs_required[CC_id][i]-nb_rbs_required_remaining_1[CC_id][i]+nb_rbs_required_remaining[CC_id][i]; - } - - if (nb_rbs_required[CC_id][i]> 0 ) - LOG_D(MAC,"round %d : nb_rbs_required_remaining[%d][%d]= %d (remaining_1 %d, required %d, pre_nb_available_rbs %d, N_RBG %d, rb_unit %d)\n", - r1, CC_id, i, - nb_rbs_required_remaining[CC_id][i], - nb_rbs_required_remaining_1[CC_id][i], - nb_rbs_required[CC_id][i], - UE_list->UE_sched_ctrl[i].pre_nb_available_rbs[CC_id], - N_RBG[CC_id], - min_rb_unit[CC_id]); - - } - } - - if (total_ue_count > 0 ) { - for(i=UE_list->head; i>=0; i=UE_list->next[i]) { - UE_id = i; - - if (flexran_slice_member(UE_id, slice_id) == 0) - continue; - - for (ii=0; iiordered_CCids[ii][UE_id]; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - flexran_get_harq(Mod_id, CC_id, UE_id, frameP, subframeP, &harq_pid, &round); - rnti = UE_RNTI(Mod_id,UE_id); - - // LOG_D(MAC,"UE %d rnti 0x\n", UE_id, rnti ); - if(rnti == NOT_A_RNTI) - continue; - - if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) + if (mbsfn_flag[CC_id] > 0) // If this CC is allocated for MBSFN skip it here continue; - if (!phy_stats_exist(Mod_id, rnti)) - continue; + frame_parms[CC_id] = mac_xface->get_lte_frame_parms(Mod_id, CC_id); - transmission_mode = mac_xface->get_transmission_mode(Mod_id,CC_id,rnti); - //rrc_status = mac_eNB_get_rrc_status(Mod_id,rnti); - /* 1st allocate for the retx */ - // retransmission in data channels - // control channel in the 1st transmission - // data channel for all TM - LOG_T(MAC,"calling dlsch_scheduler_pre_processor_allocate .. \n "); - _dlsch_scheduler_pre_processor_allocate (Mod_id, - UE_id, - CC_id, - N_RBG[CC_id], - transmission_mode, - min_rb_unit[CC_id], - frame_parms[CC_id]->N_RB_DL, - nb_rbs_required, - nb_rbs_required_remaining, - rballoc_sub, - MIMO_mode_indicator); - } - } - } // total_ue_count - } // end of for for r1 and r2 + min_rb_unit[CC_id] = get_min_rb_unit(Mod_id, CC_id); - for(i=UE_list->head; i>=0; i=UE_list->next[i]) { - UE_id = i; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - - if (flexran_slice_member(UE_id, slice_id) == 0) - continue; + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (UE_list->active[i] != TRUE) + continue; - for (ii=0; iiordered_CCids[ii][UE_id]; - //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].dl_pow_off = dl_pow_off[UE_id]; + UE_id = i; + // Initialize scheduling information for all active UEs - if (ue_sched_ctl->pre_nb_available_rbs[CC_id] > 0 ) { - LOG_D(MAC,"******************DL Scheduling Information for UE%d ************************\n",UE_id); - LOG_D(MAC,"dl power offset UE%d = %d \n",UE_id,ue_sched_ctl->dl_pow_off[CC_id]); - LOG_D(MAC,"***********RB Alloc for every subband for UE%d ***********\n",UE_id); + //if (flexran_slice_member(UE_id, slice_id) == 0) + //continue; + _dlsch_scheduler_pre_processor_reset(Mod_id, + UE_id, + CC_id, + frameP, + subframeP, + N_RBG[CC_id], + nb_rbs_required, + nb_rbs_required_remaining, + nb_rbs_allowed_slice, + rballoc_sub, + MIMO_mode_indicator); - for(j=0; jmu_mimo_mode[UE_id].rballoc_sub[i] = rballoc_sub_UE[CC_id][UE_id][i]; - LOG_D(MAC,"RB Alloc for UE%d and Subband%d = %d\n",UE_id,j,ue_sched_ctl->rballoc_sub_UE[CC_id][j]); - } - - //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = pre_nb_available_rbs[CC_id][UE_id]; - LOG_D(MAC,"[eNB %d][SLICE %d] Total RBs allocated for UE%d = %d\n", - Mod_id, slice_id, UE_id,ue_sched_ctl->pre_nb_available_rbs[CC_id]); - } + } + } + + // Store the DLSCH buffer for each logical channel + _store_dlsch_buffer(Mod_id, slice_id, frameP, subframeP); + + // Calculate the number of RBs required by each UE on the basis of logical channel's buffer + _assign_rbs_required(Mod_id, slice_id, frameP, subframeP, + nb_rbs_required, nb_rbs_allowed_slice, + min_rb_unit); + + // Sorts the user on the basis of dlsch logical channel buffer and CQI + sort_UEs(Mod_id, frameP, subframeP); + + total_ue_count = 0; + + // loop over all active UEs + for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { + rnti = flexran_get_ue_crnti(Mod_id, i); + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + + UE_id = i; + + if (flexran_slice_member(UE_id, slice_id) == 0) + continue; + + if (!phy_stats_exist(Mod_id, rnti)) + continue; + + for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { + CC_id = UE_list->ordered_CCids[ii][UE_id]; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + ue_sched_ctl->max_allowed_rbs[CC_id] = + nb_rbs_allowed_slice[CC_id][slice_id]; + flexran_get_harq(Mod_id, CC_id, UE_id, frameP, subframeP, + &harq_pid, &round); + + // if there is no available harq_process, skip the UE + if (UE_list->UE_sched_ctrl[UE_id].harq_pid[CC_id] < 0) + continue; + + average_rbs_per_user[CC_id] = 0; + + frame_parms[CC_id] = + mac_xface->get_lte_frame_parms(Mod_id, CC_id); + + // mac_xface->get_ue_active_harq_pid(Mod_id,CC_id,rnti,frameP,subframeP,&harq_pid,&round,0); + + if (round > 0) { + nb_rbs_required[CC_id][UE_id] = + UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + } + //nb_rbs_required_remaining[UE_id] = nb_rbs_required[UE_id]; + if (nb_rbs_required[CC_id][UE_id] > 0) { + total_ue_count = total_ue_count + 1; + } + // hypotetical assignement + /* + * If schedule is enabled and if the priority of the UEs is modified + * The average rbs per logical channel per user will depend on the level of + * priority. Concerning the hypothetical assignement, we should assign more + * rbs to prioritized users. Maybe, we can do a mapping between the + * average rbs per user and the level of priority or multiply the average rbs + * per user by a coefficient which represents the degree of priority. + */ + + if (total_ue_count == 0) { + average_rbs_per_user[CC_id] = 0; + } else if ((min_rb_unit[CC_id] * total_ue_count) <= + nb_rbs_allowed_slice[CC_id][slice_id]) { + average_rbs_per_user[CC_id] = + (uint16_t) floor(nb_rbs_allowed_slice[CC_id][slice_id] + / total_ue_count); + } else { + average_rbs_per_user[CC_id] = min_rb_unit[CC_id]; // consider the total number of use that can be scheduled UE + } + } + } + + // note: nb_rbs_required is assigned according to total_buffer_dl + // extend nb_rbs_required to capture per LCID RB required + for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { + rnti = UE_RNTI(Mod_id, i); + + if (rnti == NOT_A_RNTI) + continue; + + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + + if (!phy_stats_exist(Mod_id, rnti)) + continue; + + if (flexran_slice_member(i, slice_id) == 0) + continue; + + for (ii = 0; ii < UE_num_active_CC(UE_list, i); ii++) { + CC_id = UE_list->ordered_CCids[ii][i]; + + // control channel + if (mac_eNB_get_rrc_status(Mod_id, rnti) < RRC_RECONFIGURED) { + nb_rbs_required_remaining_1[CC_id][i] = + nb_rbs_required[CC_id][i]; + } else { + nb_rbs_required_remaining_1[CC_id][i] = + cmin(average_rbs_per_user[CC_id], + nb_rbs_required[CC_id][i]); + + } + } + } + + //Allocation to UEs is done in 2 rounds, + // 1st stage: average number of RBs allocated to each UE + // 2nd stage: remaining RBs are allocated to high priority UEs + for (r1 = 0; r1 < 2; r1++) { + + for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { + + if (flexran_slice_member(i, slice_id) == 0) + continue; + + for (ii = 0; ii < UE_num_active_CC(UE_list, i); ii++) { + CC_id = UE_list->ordered_CCids[ii][i]; + + if (r1 == 0) { + nb_rbs_required_remaining[CC_id][i] = + nb_rbs_required_remaining_1[CC_id][i]; + } else { // rb required based only on the buffer - rb allloctaed in the 1st round + extra reaming rb form the 1st round + nb_rbs_required_remaining[CC_id][i] = + nb_rbs_required[CC_id][i] - + nb_rbs_required_remaining_1[CC_id][i] + + nb_rbs_required_remaining[CC_id][i]; + } + + if (nb_rbs_required[CC_id][i] > 0) + LOG_D(MAC, + "round %d : nb_rbs_required_remaining[%d][%d]= %d (remaining_1 %d, required %d, pre_nb_available_rbs %d, N_RBG %d, rb_unit %d)\n", + r1, CC_id, i, + nb_rbs_required_remaining[CC_id][i], + nb_rbs_required_remaining_1[CC_id][i], + nb_rbs_required[CC_id][i], + UE_list->UE_sched_ctrl[i]. + pre_nb_available_rbs[CC_id], N_RBG[CC_id], + min_rb_unit[CC_id]); + + } + } + + if (total_ue_count > 0) { + for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { + UE_id = i; + + if (flexran_slice_member(UE_id, slice_id) == 0) + continue; + + for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { + CC_id = UE_list->ordered_CCids[ii][UE_id]; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + flexran_get_harq(Mod_id, CC_id, UE_id, frameP, + subframeP, &harq_pid, &round); + rnti = UE_RNTI(Mod_id, UE_id); + + // LOG_D(MAC,"UE %d rnti 0x\n", UE_id, rnti ); + if (rnti == NOT_A_RNTI) + continue; + + if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) + continue; + + if (!phy_stats_exist(Mod_id, rnti)) + continue; + + transmission_mode = + mac_xface->get_transmission_mode(Mod_id, CC_id, + rnti); + //rrc_status = mac_eNB_get_rrc_status(Mod_id,rnti); + /* 1st allocate for the retx */ + + // retransmission in data channels + // control channel in the 1st transmission + // data channel for all TM + LOG_T(MAC, + "calling dlsch_scheduler_pre_processor_allocate .. \n "); + _dlsch_scheduler_pre_processor_allocate(Mod_id, UE_id, + CC_id, + N_RBG[CC_id], + transmission_mode, + min_rb_unit + [CC_id], + frame_parms + [CC_id]-> + N_RB_DL, + nb_rbs_required, + nb_rbs_required_remaining, + rballoc_sub, + MIMO_mode_indicator); + } + } + } // total_ue_count + } // end of for for r1 and r2 + + for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { + UE_id = i; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + + if (flexran_slice_member(UE_id, slice_id) == 0) + continue; + + for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { + CC_id = UE_list->ordered_CCids[ii][UE_id]; + //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].dl_pow_off = dl_pow_off[UE_id]; + + if (ue_sched_ctl->pre_nb_available_rbs[CC_id] > 0) { + LOG_D(MAC, + "******************DL Scheduling Information for UE%d ************************\n", + UE_id); + LOG_D(MAC, "dl power offset UE%d = %d \n", UE_id, + ue_sched_ctl->dl_pow_off[CC_id]); + LOG_D(MAC, + "***********RB Alloc for every subband for UE%d ***********\n", + UE_id); + + for (j = 0; j < N_RBG[CC_id]; j++) { + //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].rballoc_sub[i] = rballoc_sub_UE[CC_id][UE_id][i]; + LOG_D(MAC, "RB Alloc for UE%d and Subband%d = %d\n", + UE_id, j, + ue_sched_ctl->rballoc_sub_UE[CC_id][j]); + } + + //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = pre_nb_available_rbs[CC_id][UE_id]; + LOG_D(MAC, + "[eNB %d][SLICE %d] Total RBs allocated for UE%d = %d\n", + Mod_id, slice_id, UE_id, + ue_sched_ctl->pre_nb_available_rbs[CC_id]); + } + } } - } } #define SF05_LIMIT 1 @@ -714,956 +826,1180 @@ void _dlsch_scheduler_pre_processor (module_id_t Mod_id, */ void -flexran_schedule_ue_spec_default(mid_t mod_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info) +flexran_schedule_ue_spec_default(mid_t mod_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info) //------------------------------------------------------------------------------ { - int i=0; - - flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); - - for (i = 0; i < n_active_slices; i++) { - - // Load any updated functions - if (update_dl_scheduler[i] > 0 ) { - slice_sched[i] = dlsym(NULL, dl_scheduler_type[i]); - update_dl_scheduler[i] = 0; - update_dl_scheduler_current[i] = 0; - slice_percentage_current[i]= slice_percentage[i]; - total_slice_percentage+=slice_percentage[i]; - LOG_N(MAC,"update dl scheduler slice %d\n", i); + int i = 0; + + flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); + + for (i = 0; i < n_active_slices; i++) { + + // Load any updated functions + if (update_dl_scheduler[i] > 0) { + slice_sched[i] = dlsym(NULL, dl_scheduler_type[i]); + update_dl_scheduler[i] = 0; + update_dl_scheduler_current[i] = 0; + slice_percentage_current[i] = slice_percentage[i]; + total_slice_percentage += slice_percentage[i]; + LOG_N(MAC, "update dl scheduler slice %d\n", i); + } + // check if the number of slices has changed, and log + if (n_active_slices_current != n_active_slices) { + if ((n_active_slices > 0) + && (n_active_slices <= MAX_NUM_SLICES)) { + LOG_N(MAC, + "[eNB %d]frame %d subframe %d: number of active slices has changed: %d-->%d\n", + mod_id, frame, subframe, n_active_slices_current, + n_active_slices); + n_active_slices_current = n_active_slices; + } else { + LOG_W(MAC, + "invalid number of slices %d, revert to the previous value %d\n", + n_active_slices, n_active_slices_current); + n_active_slices = n_active_slices_current; + } + } + // check if the slice rb share has changed, and log the console + if (slice_percentage_current[i] != slice_percentage[i]) { + if ((slice_percentage[i] >= 0.0) + && (slice_percentage[i] <= 1.0)) { + if ((total_slice_percentage - slice_percentage_current[i] + + slice_percentage[i]) <= 1.0) { + total_slice_percentage = + total_slice_percentage - + slice_percentage_current[i] + slice_percentage[i]; + LOG_N(MAC, + "[eNB %d][SLICE %d] frame %d subframe %d: total percentage %f, slice RB percentage has changed: %f-->%f\n", + mod_id, i, frame, subframe, + total_slice_percentage, + slice_percentage_current[i], + slice_percentage[i]); + slice_percentage_current[i] = slice_percentage[i]; + } else { + LOG_W(MAC, + "[eNB %d][SLICE %d] invalid total RB share (%f->%f), revert the previous value (%f->%f)\n", + mod_id, i, total_slice_percentage, + total_slice_percentage - + slice_percentage_current[i] + + slice_percentage[i], slice_percentage[i], + slice_percentage_current[i]); + slice_percentage[i] = slice_percentage_current[i]; + + } + } else { + LOG_W(MAC, + "[eNB %d][SLICE %d] invalid slice RB share, revert the previous value (%f->%f)\n", + mod_id, i, slice_percentage[i], + slice_percentage_current[i]); + slice_percentage[i] = slice_percentage_current[i]; + + } + } + // check if the slice max MCS, and log the console + if (slice_maxmcs_current[i] != slice_maxmcs[i]) { + if ((slice_maxmcs[i] >= 0) && (slice_maxmcs[i] < 29)) { + LOG_N(MAC, + "[eNB %d][SLICE %d] frame %d subframe %d: slice MAX MCS has changed: %d-->%d\n", + mod_id, i, frame, subframe, slice_maxmcs_current[i], + slice_maxmcs[i]); + slice_maxmcs_current[i] = slice_maxmcs[i]; + } else { + LOG_W(MAC, + "[eNB %d][SLICE %d] invalid slice max mcs %d, revert the previous value %d\n", + mod_id, i, slice_percentage[i], slice_percentage[i]); + slice_maxmcs[i] = slice_maxmcs_current[i]; + } + } + // check if a new scheduler, and log the console + if (update_dl_scheduler_current[i] != update_dl_scheduler[i]) { + LOG_N(MAC, + "[eNB %d][SLICE %d] frame %d subframe %d: DL scheduler for this slice is updated: %s \n", + mod_id, i, frame, subframe, dl_scheduler_type[i]); + update_dl_scheduler_current[i] = update_dl_scheduler[i]; + } + // Run each enabled slice-specific schedulers one by one + //LOG_N(MAC,"[eNB %d]frame %d subframe %d slice %d: calling the scheduler\n", mod_id, frame, subframe,i); + slice_sched[i] (mod_id, i, frame, subframe, mbsfn_flag, dl_info); + } - - // check if the number of slices has changed, and log - if (n_active_slices_current != n_active_slices ){ - if ((n_active_slices > 0) && (n_active_slices <= MAX_NUM_SLICES)) { - LOG_N(MAC,"[eNB %d]frame %d subframe %d: number of active slices has changed: %d-->%d\n", - mod_id, frame, subframe, n_active_slices_current, n_active_slices); - n_active_slices_current = n_active_slices; - } else { - LOG_W(MAC,"invalid number of slices %d, revert to the previous value %d\n",n_active_slices, n_active_slices_current); - n_active_slices = n_active_slices_current; - } - } - - // check if the slice rb share has changed, and log the console - if (slice_percentage_current[i] != slice_percentage[i]){ - if ((slice_percentage[i] >= 0.0) && (slice_percentage[i] <= 1.0)){ - if ((total_slice_percentage - slice_percentage_current[i] + slice_percentage[i]) <= 1.0) { - total_slice_percentage=total_slice_percentage - slice_percentage_current[i] + slice_percentage[i]; - LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: total percentage %f, slice RB percentage has changed: %f-->%f\n", - mod_id, i, frame, subframe, total_slice_percentage, slice_percentage_current[i], slice_percentage[i]); - slice_percentage_current[i] = slice_percentage[i]; - } else { - LOG_W(MAC,"[eNB %d][SLICE %d] invalid total RB share (%f->%f), revert the previous value (%f->%f)\n", - mod_id,i, - total_slice_percentage, - total_slice_percentage - slice_percentage_current[i] + slice_percentage[i], - slice_percentage[i],slice_percentage_current[i]); - slice_percentage[i]= slice_percentage_current[i]; + +} + +uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, int total_rbs) +{ + return (uint16_t) floor(rb_percentage * total_rbs); +} + +int flexran_slice_maxmcs(int slice_id) +{ + return slice_maxmcs[slice_id]; +} + +int flexran_slice_member(int UE_id, int slice_id) +{ + // group membership definition + int slice_member = 0; + + if ((slice_id < 0) || (slice_id > n_active_slices)) + LOG_W(MAC, "out of range slice id %d\n", slice_id); + + switch (slicing_strategy) { + case SLICE_MASK: + switch (slice_id) { + case 0: + if (SLICE0_MASK & UE_id) { + slice_member = 1; + } + break; + case 1: + if (SLICE1_MASK & UE_id) { + slice_member = 1; + } + break; + case 2: + if (SLICE2_MASK & UE_id) { + slice_member = 1; + } + break; + case 3: + if (SLICE3_MASK & UE_id) { + slice_member = 1; + } + break; + default: + LOG_W(MAC, "unknown slice_id %d\n", slice_id); + break; } - } else { - LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice RB share, revert the previous value (%f->%f)\n",mod_id, i, slice_percentage[i],slice_percentage_current[i]); - slice_percentage[i]= slice_percentage_current[i]; - - } - } - - // check if the slice max MCS, and log the console - if (slice_maxmcs_current[i] != slice_maxmcs[i]){ - if ((slice_maxmcs[i] >= 0) && (slice_maxmcs[i] < 29)){ - LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: slice MAX MCS has changed: %d-->%d\n", - mod_id, i, frame, subframe, slice_maxmcs_current[i], slice_maxmcs[i]); - slice_maxmcs_current[i] = slice_maxmcs[i]; - } else { - LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice max mcs %d, revert the previous value %d\n",mod_id, i, slice_percentage[i],slice_percentage[i]); - slice_maxmcs[i]= slice_maxmcs_current[i]; - } - } - - // check if a new scheduler, and log the console - if (update_dl_scheduler_current[i] != update_dl_scheduler[i]){ - LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: DL scheduler for this slice is updated: %s \n", - mod_id, i, frame, subframe, dl_scheduler_type[i]); - update_dl_scheduler_current[i] = update_dl_scheduler[i]; + break; + case UEID_TO_SLICEID: + default: + if ((UE_id % n_active_slices) == slice_id) { + slice_member = 1; // this ue is a member of this slice + } + break; } - // Run each enabled slice-specific schedulers one by one - //LOG_N(MAC,"[eNB %d]frame %d subframe %d slice %d: calling the scheduler\n", mod_id, frame, subframe,i); - slice_sched[i](mod_id, i, frame, subframe, mbsfn_flag,dl_info); - - } - + return slice_member; } -uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, int total_rbs){ - return (uint16_t) floor(rb_percentage * total_rbs); -} - -int flexran_slice_maxmcs(int slice_id) { - return slice_maxmcs[slice_id]; -} - -int flexran_slice_member(int UE_id, int slice_id){ - // group membership definition - int slice_member = 0 ; - - if ((slice_id < 0) || (slice_id > n_active_slices)) - LOG_W(MAC,"out of range slice id %d\n",slice_id); - - switch (slicing_strategy) { - case SLICE_MASK: - switch (slice_id){ - case 0: - if (SLICE0_MASK&UE_id){ - slice_member=1; - } - break; - case 1: - if (SLICE1_MASK&UE_id){ - slice_member=1; - } - break; - case 2: - if (SLICE2_MASK&UE_id){ - slice_member=1; - } - break; - case 3: - if (SLICE3_MASK&UE_id){ - slice_member=1; - } - break; - default : - LOG_W(MAC,"unknown slice_id %d\n", slice_id); - break; - - } - break; - case UEID_TO_SLICEID: - default: - if ((UE_id % n_active_slices) == slice_id){ - slice_member= 1; // this ue is a member of this slice - } - break; - } - - return slice_member; -} /* more aggressive rb and mcs allocation with medium priority and the traffic qci */ void -flexran_schedule_ue_spec_embb(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info) - +flexran_schedule_ue_spec_embb(mid_t mod_id, + int slice_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info) { - flexran_schedule_ue_spec_common(mod_id, - slice_id, - frame, - subframe, - mbsfn_flag, - dl_info); - + flexran_schedule_ue_spec_common(mod_id, + slice_id, + frame, subframe, mbsfn_flag, dl_info); + } + /* more conservative mcs allocation with high priority and the traffic qci */ void -flexran_schedule_ue_spec_urllc(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info) - +flexran_schedule_ue_spec_urllc(mid_t mod_id, + int slice_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info) { - flexran_schedule_ue_spec_common(mod_id, - slice_id, - frame, - subframe, - mbsfn_flag, - dl_info); - + flexran_schedule_ue_spec_common(mod_id, + slice_id, + frame, subframe, mbsfn_flag, dl_info); + } + /* constant rb allocation with low mcs with low priority and given the UE capabilities */ void -flexran_schedule_ue_spec_mmtc(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info) - +flexran_schedule_ue_spec_mmtc(mid_t mod_id, + int slice_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info) { - - flexran_schedule_ue_spec_common(mod_id, - slice_id, - frame, - subframe, - mbsfn_flag, - dl_info); - + + flexran_schedule_ue_spec_common(mod_id, + slice_id, + frame, subframe, mbsfn_flag, dl_info); + } + /* regular rb and mcs allocation with low priority */ void -flexran_schedule_ue_spec_be(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info) - +flexran_schedule_ue_spec_be(mid_t mod_id, + int slice_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info) { - - flexran_schedule_ue_spec_common(mod_id, - slice_id, - frame, - subframe, - mbsfn_flag, - dl_info); - + + flexran_schedule_ue_spec_common(mod_id, + slice_id, + frame, subframe, mbsfn_flag, dl_info); + } //------------------------------------------------------------------------------ void -flexran_schedule_ue_spec_common(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info) +flexran_schedule_ue_spec_common(mid_t mod_id, + int slice_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info) //------------------------------------------------------------------------------ { - uint8_t CC_id; - int UE_id; - int N_RBG[MAX_NUM_CCs]; - unsigned char aggregation; - mac_rlc_status_resp_t rlc_status; - unsigned char header_len = 0, header_len_last = 0, ta_len = 0; - uint16_t nb_rb, nb_rb_temp, total_nb_available_rb[MAX_NUM_CCs], nb_available_rb; - uint16_t TBS, j, rnti; - uint8_t round = 0; - uint8_t harq_pid = 0; - uint16_t sdu_length_total = 0; - int mcs, mcs_tmp; - uint16_t min_rb_unit[MAX_NUM_CCs]; - eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; - /* TODO: Must move the helper structs to scheduler implementation */ - UE_list_t *UE_list = &eNB->UE_list; - int32_t normalized_rx_power, target_rx_power; - int32_t tpc = 1; - static int32_t tpc_accumulated=0; - UE_sched_ctrl *ue_sched_ctl; - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - Protocol__FlexDlData *dl_data[NUM_MAX_UE]; - int num_ues_added = 0; - int channels_added = 0; + uint8_t CC_id; + int UE_id; + int N_RBG[MAX_NUM_CCs]; + unsigned char aggregation; + mac_rlc_status_resp_t rlc_status; + unsigned char header_len = 0, header_len_last = 0, ta_len = 0; + uint16_t nb_rb, nb_rb_temp, total_nb_available_rb[MAX_NUM_CCs], + nb_available_rb; + uint16_t TBS, j, rnti; + uint8_t round = 0; + uint8_t harq_pid = 0; + uint16_t sdu_length_total = 0; + int mcs, mcs_tmp; + uint16_t min_rb_unit[MAX_NUM_CCs]; + eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; + /* TODO: Must move the helper structs to scheduler implementation */ + UE_list_t *UE_list = &eNB->UE_list; + int32_t normalized_rx_power, target_rx_power; + int32_t tpc = 1; + static int32_t tpc_accumulated = 0; + UE_sched_ctrl *ue_sched_ctl; + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + Protocol__FlexDlData *dl_data[NUM_MAX_UE]; + int num_ues_added = 0; + int channels_added = 0; - Protocol__FlexDlDci *dl_dci; - Protocol__FlexRlcPdu *rlc_pdus[11]; - uint32_t ce_flags = 0; + Protocol__FlexDlDci *dl_dci; + Protocol__FlexRlcPdu *rlc_pdus[11]; + uint32_t ce_flags = 0; + + uint8_t rballoc_sub[25]; + int i; + uint32_t data_to_request; + uint32_t dci_tbs; + uint8_t ue_has_transmission = 0; + uint32_t ndi; - uint8_t rballoc_sub[25]; - int i; - uint32_t data_to_request; - uint32_t dci_tbs; - uint8_t ue_has_transmission = 0; - uint32_t ndi; - #if 0 - - if (UE_list->head==-1) { - return; - } - + + if (UE_list->head == -1) { + return; + } #endif - start_meas(&eNB->schedule_dlsch); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_IN); + start_meas(&eNB->schedule_dlsch); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_IN); - //weight = get_ue_weight(module_idP,UE_id); - aggregation = 1; // set to the maximum aggregation level + //weight = get_ue_weight(module_idP,UE_id); + aggregation = 1; // set to the maximum aggregation level - for (CC_id=0; CC_idcommon_channels[CC_id].vrb_map[i] != 0) - total_nb_available_rb[CC_id]--; - - N_RBG[CC_id] = flexran_get_N_RBG(mod_id, CC_id); + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + min_rb_unit[CC_id] = get_min_rb_unit(mod_id, CC_id); + // get number of PRBs less those used by common channels + total_nb_available_rb[CC_id] = flexran_get_N_RB_DL(mod_id, CC_id); + for (i = 0; i < flexran_get_N_RB_DL(mod_id, CC_id); i++) + if (eNB->common_channels[CC_id].vrb_map[i] != 0) + total_nb_available_rb[CC_id]--; - // store the global enb stats: - eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs; - eNB->eNB_stats[CC_id].available_prbs = total_nb_available_rb[CC_id]; - eNB->eNB_stats[CC_id].total_available_prbs += total_nb_available_rb[CC_id]; - eNB->eNB_stats[CC_id].dlsch_bytes_tx=0; - eNB->eNB_stats[CC_id].dlsch_pdus_tx=0; - } + N_RBG[CC_id] = flexran_get_N_RBG(mod_id, CC_id); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR,VCD_FUNCTION_IN); + // store the global enb stats: + eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs; + eNB->eNB_stats[CC_id].available_prbs = + total_nb_available_rb[CC_id]; + eNB->eNB_stats[CC_id].total_available_prbs += + total_nb_available_rb[CC_id]; + eNB->eNB_stats[CC_id].dlsch_bytes_tx = 0; + eNB->eNB_stats[CC_id].dlsch_pdus_tx = 0; + } - start_meas(&eNB->schedule_dlsch_preprocessor); - _dlsch_scheduler_pre_processor(mod_id, - slice_id, - frame, - subframe, - N_RBG, - mbsfn_flag); - stop_meas(&eNB->schedule_dlsch_preprocessor); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR,VCD_FUNCTION_OUT); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_IN); - for (CC_id=0; CC_idschedule_dlsch_preprocessor); + _dlsch_scheduler_pre_processor(mod_id, + slice_id, + frame, subframe, N_RBG, mbsfn_flag); + stop_meas(&eNB->schedule_dlsch_preprocessor); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_OUT); - if (mbsfn_flag[CC_id]>0) - continue; - - for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { - - rnti = flexran_get_ue_crnti(mod_id, UE_id); - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - - if (eNB_UE_stats==NULL) { - LOG_D(MAC,"[eNB] Cannot find eNB_UE_stats\n"); - // mac_xface->macphy_exit("[MAC][eNB] Cannot find eNB_UE_stats\n"); - continue; - } - - if (flexran_slice_member(UE_id, slice_id) == 0) - continue; - - if (rnti==NOT_A_RNTI) { - LOG_D(MAC,"Cannot find rnti for UE_id %d (num_UEs %d)\n", UE_id,UE_list->num_UEs); - // mac_xface->macphy_exit("Cannot find rnti for UE_id"); - continue; - } + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n", CC_id); - switch(mac_xface->get_transmission_mode(mod_id,CC_id,rnti)){ - case 1: - case 2: - case 7: - aggregation = get_aggregation(get_bw_index(mod_id,CC_id), - eNB_UE_stats->DL_cqi[0], - format1); - break; - case 3: - aggregation = get_aggregation(get_bw_index(mod_id,CC_id), - eNB_UE_stats->DL_cqi[0], - format2A); - break; - default: - LOG_W(MAC,"Unsupported transmission mode %d\n", mac_xface->get_transmission_mode(mod_id,CC_id,rnti)); - aggregation = 2; - } - - if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated - CCE_allocation_infeasible(mod_id, CC_id, 0, subframe, aggregation, rnti)) { - LOG_D(MAC,"[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", - mod_id, frame, UE_id, CC_id); - //if(mac_xface->get_transmission_mode(module_idP,rnti)==5) - continue; //to next user (there might be rbs availiable for other UEs in TM5 - // else - // break; - } + if (mbsfn_flag[CC_id] > 0) + continue; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - set_ue_dai (subframe, - flexran_get_subframe_assignment(mod_id, CC_id), - UE_id, - CC_id, - UE_list); - //TODO: update UL DAI after DLSCH scheduling - //set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe,frame_parms); - } + for (UE_id = UE_list->head; UE_id >= 0; + UE_id = UE_list->next[UE_id]) { - channels_added = 0; + rnti = flexran_get_ue_crnti(mod_id, UE_id); + eNB_UE_stats = + mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - // After this point all the UEs will be scheduled - dl_data[num_ues_added] = (Protocol__FlexDlData *) malloc(sizeof(Protocol__FlexDlData)); - protocol__flex_dl_data__init(dl_data[num_ues_added]); - dl_data[num_ues_added]->has_rnti = 1; - dl_data[num_ues_added]->rnti = rnti; - dl_data[num_ues_added]->n_rlc_pdu = 0; - dl_data[num_ues_added]->has_serv_cell_index = 1; - dl_data[num_ues_added]->serv_cell_index = CC_id; - - nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; - flexran_get_harq(mod_id, CC_id, UE_id, frame, subframe, &harq_pid, &round); - sdu_length_total=0; - mcs = cqi_to_mcs[flexran_get_ue_wcqi(mod_id, UE_id)]; - // LOG_I(FLEXRAN_AGENT, "The MCS is %d\n", mcs); - mcs = cmin(mcs,flexran_slice_maxmcs(slice_id)); + if (eNB_UE_stats == NULL) { + LOG_D(MAC, "[eNB] Cannot find eNB_UE_stats\n"); + // mac_xface->macphy_exit("[MAC][eNB] Cannot find eNB_UE_stats\n"); + continue; + } + + if (flexran_slice_member(UE_id, slice_id) == 0) + continue; + + if (rnti == NOT_A_RNTI) { + LOG_D(MAC, "Cannot find rnti for UE_id %d (num_UEs %d)\n", + UE_id, UE_list->num_UEs); + // mac_xface->macphy_exit("Cannot find rnti for UE_id"); + continue; + } + + switch (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)) { + case 1: + case 2: + case 7: + aggregation = get_aggregation(get_bw_index(mod_id, CC_id), + eNB_UE_stats->DL_cqi[0], + format1); + break; + case 3: + aggregation = get_aggregation(get_bw_index(mod_id, CC_id), + eNB_UE_stats->DL_cqi[0], + format2A); + break; + default: + LOG_W(MAC, "Unsupported transmission mode %d\n", + mac_xface->get_transmission_mode(mod_id, CC_id, + rnti)); + aggregation = 2; + } + + if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated + CCE_allocation_infeasible(mod_id, CC_id, 0, subframe, + aggregation, rnti)) { + LOG_D(MAC, + "[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", + mod_id, frame, UE_id, CC_id); + //if(mac_xface->get_transmission_mode(module_idP,rnti)==5) + continue; //to next user (there might be rbs availiable for other UEs in TM5 + // else + // break; + } + + if (flexran_get_duplex_mode(mod_id, CC_id) == + PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + set_ue_dai(subframe, + flexran_get_subframe_assignment(mod_id, CC_id), + UE_id, CC_id, UE_list); + //TODO: update UL DAI after DLSCH scheduling + //set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe,frame_parms); + } + + channels_added = 0; + + // After this point all the UEs will be scheduled + dl_data[num_ues_added] = + (Protocol__FlexDlData *) + malloc(sizeof(Protocol__FlexDlData)); + protocol__flex_dl_data__init(dl_data[num_ues_added]); + dl_data[num_ues_added]->has_rnti = 1; + dl_data[num_ues_added]->rnti = rnti; + dl_data[num_ues_added]->n_rlc_pdu = 0; + dl_data[num_ues_added]->has_serv_cell_index = 1; + dl_data[num_ues_added]->serv_cell_index = CC_id; + + nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; + flexran_get_harq(mod_id, CC_id, UE_id, frame, subframe, + &harq_pid, &round); + sdu_length_total = 0; + mcs = cqi_to_mcs[flexran_get_ue_wcqi(mod_id, UE_id)]; + // LOG_I(FLEXRAN_AGENT, "The MCS is %d\n", mcs); + mcs = cmin(mcs, flexran_slice_maxmcs(slice_id)); #ifdef EXMIMO - if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti) == 5) { - mcs = cqi_to_mcs[flexran_get_ue_wcqi(mod_id, UE_id)]; - mcs = cmin(mcs,16); - } - + if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti) == 5) { + mcs = cqi_to_mcs[flexran_get_ue_wcqi(mod_id, UE_id)]; + mcs = cmin(mcs, 16); + } #endif - // initializing the rb allocation indicator for each UE - for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0; - rballoc_sub[j] = 0; - } - - /* LOG_D(MAC,"[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n", */ - /* mod_id, frame, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb, */ - /* eNB_UE_stats->DL_cqi[0], mcs, */ - /* UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); */ - - dl_dci = (Protocol__FlexDlDci*) malloc(sizeof(Protocol__FlexDlDci)); - protocol__flex_dl_dci__init(dl_dci); - dl_data[num_ues_added]->dl_dci = dl_dci; - - - dl_dci->has_rnti = 1; - dl_dci->rnti = rnti; - dl_dci->has_harq_process = 1; - dl_dci->harq_process = harq_pid; - - /* process retransmission */ - if (round > 0) { - - LOG_D(FLEXRAN_AGENT, "There was a retransmission just now and the round was %d\n", round); - - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - UE_list->UE_template[CC_id][UE_id].DAI++; - update_ul_dci(mod_id, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); - LOG_D(MAC,"DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", - CC_id, subframe,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); - } - - mcs = UE_list->UE_template[CC_id][UE_id].mcs[harq_pid]; - - // get freq_allocation - nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - - /*TODO: Must add this to FlexRAN agent API */ - dci_tbs = mac_xface->get_TBS_DL(mcs, nb_rb); - - if (nb_rb <= nb_available_rb) { - - if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { - for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { // for indicating the rballoc for each sub-band - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - } - } else { - nb_rb_temp = nb_rb; - j = 0; - - while((nb_rb_temp > 0) && (j < flexran_get_N_RBG(mod_id, CC_id))) { - if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - - if((j == flexran_get_N_RBG(mod_id, CC_id) - 1) && - ((flexran_get_N_RB_DL(mod_id, CC_id) == 25)|| - (flexran_get_N_RB_DL(mod_id, CC_id) == 50))) { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]+1; - } else { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; - } - } - j = j + 1; + // initializing the rb allocation indicator for each UE + for (j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { + UE_list-> + UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] + = 0; + rballoc_sub[j] = 0; } - } - nb_available_rb -= nb_rb; - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; - - for(j=0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; - rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; - } + /* LOG_D(MAC,"[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n", */ + /* mod_id, frame, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb, */ + /* eNB_UE_stats->DL_cqi[0], mcs, */ + /* UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); */ - // Keep the old NDI, do not toggle - ndi = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - tpc = UE_list->UE_template[CC_id][UE_id].oldTPC[harq_pid]; - UE_list->UE_template[CC_id][UE_id].mcs[harq_pid] = mcs; + dl_dci = + (Protocol__FlexDlDci *) + malloc(sizeof(Protocol__FlexDlDci)); + protocol__flex_dl_dci__init(dl_dci); + dl_data[num_ues_added]->dl_dci = dl_dci; - ue_has_transmission = 1; - num_ues_added++; - } else { - LOG_D(MAC,"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", - mod_id, frame, CC_id, UE_id); - ue_has_transmission = 0; + + dl_dci->has_rnti = 1; + dl_dci->rnti = rnti; + dl_dci->has_harq_process = 1; + dl_dci->harq_process = harq_pid; + + /* process retransmission */ + if (round > 0) { + + LOG_D(FLEXRAN_AGENT, + "There was a retransmission just now and the round was %d\n", + round); + + if (flexran_get_duplex_mode(mod_id, CC_id) == + PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + UE_list->UE_template[CC_id][UE_id].DAI++; + update_ul_dci(mod_id, CC_id, rnti, + UE_list->UE_template[CC_id][UE_id].DAI); + LOG_D(MAC, + "DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", + CC_id, subframe, UE_id, + UE_list->UE_template[CC_id][UE_id].DAI); + } + + mcs = UE_list->UE_template[CC_id][UE_id].mcs[harq_pid]; + + // get freq_allocation + nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + + /*TODO: Must add this to FlexRAN agent API */ + dci_tbs = mac_xface->get_TBS_DL(mcs, nb_rb); + + if (nb_rb <= nb_available_rb) { + + if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { + for (j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { // for indicating the rballoc for each sub-band + UE_list->UE_template[CC_id][UE_id]. + rballoc_subband[harq_pid][j] = + ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + } + } else { + nb_rb_temp = nb_rb; + j = 0; + + while ((nb_rb_temp > 0) + && (j < flexran_get_N_RBG(mod_id, CC_id))) { + if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == + 1) { + UE_list-> + UE_template[CC_id] + [UE_id].rballoc_subband[harq_pid][j] = + ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + + if ((j == + flexran_get_N_RBG(mod_id, CC_id) - 1) + && + ((flexran_get_N_RB_DL(mod_id, CC_id) == + 25) + || (flexran_get_N_RB_DL(mod_id, CC_id) + == 50))) { + nb_rb_temp = + nb_rb_temp - min_rb_unit[CC_id] + + 1; + } else { + nb_rb_temp = + nb_rb_temp - min_rb_unit[CC_id]; + } + } + j = j + 1; + } + } + + nb_available_rb -= nb_rb; + PHY_vars_eNB_g[mod_id][CC_id]-> + mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; + PHY_vars_eNB_g[mod_id][CC_id]-> + mu_mimo_mode[UE_id].dl_pow_off = + ue_sched_ctl->dl_pow_off[CC_id]; + + for (j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { + PHY_vars_eNB_g[mod_id][CC_id]-> + mu_mimo_mode[UE_id].rballoc_sub[j] = + UE_list-> + UE_template[CC_id][UE_id].rballoc_subband + [harq_pid][j]; + rballoc_sub[j] = + UE_list-> + UE_template[CC_id][UE_id].rballoc_subband + [harq_pid][j]; + } + + // Keep the old NDI, do not toggle + ndi = + UE_list->UE_template[CC_id][UE_id]. + oldNDI[harq_pid]; + tpc = + UE_list->UE_template[CC_id][UE_id]. + oldTPC[harq_pid]; + UE_list->UE_template[CC_id][UE_id].mcs[harq_pid] = mcs; + + ue_has_transmission = 1; + num_ues_added++; + } else { + LOG_D(MAC, + "[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", + mod_id, frame, CC_id, UE_id); + ue_has_transmission = 0; + } + //End of retransmission + } else { /* This is a potentially new SDU opportunity */ + rlc_status.bytes_in_buffer = 0; + // Now check RLC information to compute number of required RBs + // get maximum TBS size for RLC request + //TBS = mac_xface->get_TBS(eNB_UE_stats->DL_cqi[0]<<1,nb_available_rb); + TBS = mac_xface->get_TBS_DL(mcs, nb_available_rb); + dci_tbs = TBS; + LOG_D(FLEXRAN_AGENT, "TBS is %d\n", TBS); + + // check first for RLC data on DCCH + // add the length for all the control elements (timing adv, drx, etc) : header + payload + + ta_len = (ue_sched_ctl->ta_update != 0) ? 2 : 0; + + dl_data[num_ues_added]->n_ce_bitmap = 2; + dl_data[num_ues_added]->ce_bitmap = + (uint32_t *) calloc(2, sizeof(uint32_t)); + + if (ta_len > 0) { + ce_flags |= PROTOCOL__FLEX_CE_TYPE__FLPCET_TA; + } + + /*TODO: Add other flags if DRX and other CE are required */ + + // Add the control element flags to the flexran message + dl_data[num_ues_added]->ce_bitmap[0] = ce_flags; + dl_data[num_ues_added]->ce_bitmap[1] = ce_flags; + + // TODO : Need to prioritize DRBs + // Loop through the UE logical channels (DCCH, DCCH1, DTCH for now) + header_len = 0; + header_len_last = 0; + sdu_length_total = 0; + for (j = 1; j < NB_RB_MAX; j++) { + header_len += 3; + // Need to see if we have space for data from this channel + if (dci_tbs - ta_len - header_len - sdu_length_total > + 0) { + LOG_D(MAC, + "[TEST]Requested %d bytes from RLC buffer on channel %d during first call\n", + dci_tbs - ta_len - header_len); + //If we have space, we need to see how much data we can request at most (if any available) + rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, subframe, ENB_FLAG_YES, MBMS_FLAG_NO, j, (dci_tbs - ta_len - header_len - sdu_length_total)); // transport block set size + + //If data are available in channel j + if (rlc_status.bytes_in_buffer > 0) { + LOG_D(MAC, + "[TEST]Have %d bytes in DCCH buffer during first call\n", + rlc_status.bytes_in_buffer); + //Fill in as much as possible + data_to_request = + cmin(dci_tbs - ta_len - header_len - + sdu_length_total, + rlc_status.bytes_in_buffer); + LOG_D(FLEXRAN_AGENT, + "Will request %d bytes from channel %d\n", + data_to_request, j); + if (data_to_request < 128) { //The header will be one byte less + header_len--; + header_len_last = 2; + } else { + header_len_last = 3; + } + /* if (j == 1 || j == 2) { + data_to_request+=0; + } */ + LOG_D(MAC, + "[TEST]Will request %d from channel %d\n", + data_to_request, j); + rlc_pdus[channels_added] = + (Protocol__FlexRlcPdu *) + malloc(sizeof(Protocol__FlexRlcPdu)); + protocol__flex_rlc_pdu__init(rlc_pdus + [channels_added]); + rlc_pdus[channels_added]->n_rlc_pdu_tb = 2; + rlc_pdus[channels_added]->rlc_pdu_tb = + (Protocol__FlexRlcPduTb **) + malloc(sizeof(Protocol__FlexRlcPduTb *) * + 2); + rlc_pdus[channels_added]->rlc_pdu_tb[0] = + (Protocol__FlexRlcPduTb *) + malloc(sizeof(Protocol__FlexRlcPduTb)); + protocol__flex_rlc_pdu_tb__init(rlc_pdus + [channels_added]->rlc_pdu_tb + [0]); + rlc_pdus[channels_added]-> + rlc_pdu_tb[0]->has_logical_channel_id = 1; + rlc_pdus[channels_added]-> + rlc_pdu_tb[0]->logical_channel_id = j; + rlc_pdus[channels_added]->rlc_pdu_tb[0]-> + has_size = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[0]->size = + data_to_request; + rlc_pdus[channels_added]->rlc_pdu_tb[1] = + (Protocol__FlexRlcPduTb *) + malloc(sizeof(Protocol__FlexRlcPduTb)); + protocol__flex_rlc_pdu_tb__init(rlc_pdus + [channels_added]->rlc_pdu_tb + [1]); + rlc_pdus[channels_added]-> + rlc_pdu_tb[1]->has_logical_channel_id = 1; + rlc_pdus[channels_added]-> + rlc_pdu_tb[1]->logical_channel_id = j; + rlc_pdus[channels_added]->rlc_pdu_tb[1]-> + has_size = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[1]->size = + data_to_request; + dl_data[num_ues_added]->n_rlc_pdu++; + channels_added++; + //Set this to the max value that we might request + sdu_length_total += data_to_request; + } else { + //Take back the assumption of a header for this channel + header_len -= 3; + } //End rlc_status.bytes_in_buffer <= 0 + } //end of if dci_tbs - ta_len - header_len > 0 + } // End of iterating the logical channels + + // Add rlc_pdus to the dl_data message + dl_data[num_ues_added]->rlc_pdu = (Protocol__FlexRlcPdu **) + malloc(sizeof(Protocol__FlexRlcPdu *) * + dl_data[num_ues_added]->n_rlc_pdu); + for (i = 0; i < dl_data[num_ues_added]->n_rlc_pdu; i++) { + dl_data[num_ues_added]->rlc_pdu[i] = rlc_pdus[i]; + } + + if (header_len == 0) { + LOG_D(FLEXRAN_AGENT, "Header was empty\n"); + header_len_last = 0; + } + // there is a payload + if ((dl_data[num_ues_added]->n_rlc_pdu > 0)) { + // Now compute number of required RBs for total sdu length + // Assume RAH format 2 + // adjust header lengths + LOG_D(FLEXRAN_AGENT, "We have %d bytes to transfer\n", + sdu_length_total); + if (header_len != 0) { + LOG_D(FLEXRAN_AGENT, "Header length was %d ", + header_len); + header_len_last--; + header_len -= header_len_last; + LOG_D(FLEXRAN_AGENT, "so we resized it to %d\n", + header_len); + } + + /* if (header_len == 2 || header_len == 3) { //Only one SDU, remove length field */ + /* header_len = 1; */ + /* } else { //Remove length field from the last SDU */ + /* header_len--; */ + /* } */ + + mcs_tmp = mcs; + if (mcs_tmp == 0) { + nb_rb = 4; // don't let the TBS get too small + } else { + nb_rb = min_rb_unit[CC_id]; + } + + LOG_D(MAC, + "[TEST]The initial number of resource blocks was %d\n", + nb_rb); + LOG_D(MAC, "[TEST] The initial mcs was %d\n", mcs_tmp); + + TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); + LOG_D(MAC, + "[TEST]The TBS during rate matching was %d\n", + TBS); + + while (TBS < (sdu_length_total + header_len + ta_len)) { + nb_rb += min_rb_unit[CC_id]; // + LOG_D(MAC, + "[TEST]Had to increase the number of RBs\n"); + if (nb_rb > nb_available_rb) { // if we've gone beyond the maximum number of RBs + // (can happen if N_RB_DL is odd) + TBS = + mac_xface->get_TBS_DL(mcs_tmp, + nb_available_rb); + nb_rb = nb_available_rb; + break; + } + + TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); + } + + if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { + LOG_D(MAC, + "[TEST]We had the exact number of rbs. Time to fill the rballoc subband\n"); + for (j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { // for indicating the rballoc for each sub-band + UE_list->UE_template[CC_id][UE_id]. + rballoc_subband[harq_pid][j] = + ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + } + } else { + nb_rb_temp = nb_rb; + j = 0; + LOG_D(MAC, + "[TEST]Will only partially fill the bitmap\n"); + while ((nb_rb_temp > 0) + && (j < flexran_get_N_RBG(mod_id, CC_id))) { + if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == + 1) { + UE_list-> + UE_template[CC_id] + [UE_id].rballoc_subband[harq_pid][j] = + ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + if ((j == + flexran_get_N_RBG(mod_id, CC_id) - 1) + && + ((flexran_get_N_RB_DL(mod_id, CC_id) == + 25) + || (flexran_get_N_RB_DL(mod_id, CC_id) + == 50))) { + nb_rb_temp = + nb_rb_temp - min_rb_unit[CC_id] + + 1; + } else { + nb_rb_temp = + nb_rb_temp - min_rb_unit[CC_id]; + } + } + j = j + 1; + } + } + + PHY_vars_eNB_g[mod_id][CC_id]-> + mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; + PHY_vars_eNB_g[mod_id][CC_id]-> + mu_mimo_mode[UE_id].dl_pow_off = + ue_sched_ctl->dl_pow_off[CC_id]; + + for (j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { + PHY_vars_eNB_g[mod_id][CC_id]-> + mu_mimo_mode[UE_id].rballoc_sub[j] = + UE_list-> + UE_template[CC_id][UE_id].rballoc_subband + [harq_pid][j]; + } + + // decrease mcs until TBS falls below required length + while ((TBS > (sdu_length_total + header_len + ta_len)) + && (mcs_tmp > 0)) { + mcs_tmp--; + TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); + } + + // if we have decreased too much or we don't have enough RBs, increase MCS + while ((TBS < (sdu_length_total + header_len + ta_len)) + && (((ue_sched_ctl->dl_pow_off[CC_id] > 0) + && (mcs_tmp < 28)) + || ((ue_sched_ctl->dl_pow_off[CC_id] == 0) + && (mcs_tmp <= 15)))) { + mcs_tmp++; + TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); + } + + dci_tbs = TBS; + mcs = mcs_tmp; + LOG_D(FLEXRAN_AGENT, "Final mcs was %d\n", mcs); + + dl_dci->has_aggr_level = 1; + dl_dci->aggr_level = aggregation; + + UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = + nb_rb; + + if (flexran_get_duplex_mode(mod_id, CC_id) == + PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + UE_list->UE_template[CC_id][UE_id].DAI++; + // printf("DAI update: subframeP %d: UE %d, DAI %d\n",subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); + //#warning only for 5MHz channel + update_ul_dci(mod_id, CC_id, rnti, + UE_list->UE_template[CC_id][UE_id]. + DAI); + } + // do PUCCH power control + // this is the normalized RX power + normalized_rx_power = flexran_get_p0_pucch_dbm(mod_id, UE_id, CC_id); //eNB_UE_stats->Po_PUCCH_dBm; + target_rx_power = flexran_get_p0_nominal_pucch(mod_id, CC_id) + 20; //mac_xface->get_target_pucch_rx_power(mod_id, CC_id) + 20; + // this assumes accumulated tpc + // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out + int32_t framex10psubframe = + UE_list->UE_template[CC_id][UE_id]. + pucch_tpc_tx_frame * 10 + + UE_list->UE_template[CC_id][UE_id]. + pucch_tpc_tx_subframe; + + if (((framex10psubframe + 10) <= (frame * 10 + subframe)) || //normal case + ((framex10psubframe > (frame * 10 + subframe)) && (((10240 - framex10psubframe + frame * 10 + subframe) >= 10)))) //frame wrap-around + if (flexran_get_p0_pucch_status + (mod_id, UE_id, CC_id) == 1) { + flexran_update_p0_pucch(mod_id, UE_id, CC_id); + + UE_list-> + UE_template[CC_id] + [UE_id].pucch_tpc_tx_frame = frame; + UE_list-> + UE_template[CC_id] + [UE_id].pucch_tpc_tx_subframe = subframe; + if (normalized_rx_power > + (target_rx_power + 1)) { + tpc = 0; //-1 + tpc_accumulated--; + } else if (normalized_rx_power < + (target_rx_power - 1)) { + tpc = 2; //+1 + tpc_accumulated++; + } else { + tpc = 1; //0 + } + LOG_D(MAC, + "[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", + mod_id, frame, subframe, harq_pid, tpc, + tpc_accumulated, normalized_rx_power, + target_rx_power); + } // Po_PUCCH has been updated + else { + tpc = 1; //0 + } // time to do TPC update + else { + tpc = 1; //0 + } + + for (i = 0; + i < + PHY_vars_eNB_g[mod_id][CC_id]->frame_parms.N_RBG; + i++) { + rballoc_sub[i] = + UE_list-> + UE_template[CC_id][UE_id].rballoc_subband + [harq_pid][i]; + } + + // Toggle NDI + LOG_D(MAC, + "CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", + CC_id, frame, subframe, UE_id, + UE_list->UE_template[CC_id][UE_id].rnti, + harq_pid, + UE_list->UE_template[CC_id][UE_id]. + oldNDI[harq_pid]); + UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid] = + 1 - + UE_list->UE_template[CC_id][UE_id]. + oldNDI[harq_pid]; + ndi = + UE_list->UE_template[CC_id][UE_id]. + oldNDI[harq_pid]; + + UE_list->UE_template[CC_id][UE_id].mcs[harq_pid] = mcs; + UE_list->UE_template[CC_id][UE_id].oldTPC[harq_pid] = + tpc; + + // Increase the pointer for the number of scheduled UEs + num_ues_added++; + ue_has_transmission = 1; + } else { // There is no data from RLC or MAC header, so don't schedule + ue_has_transmission = 0; + } + } // End of new scheduling + + // If we has transmission or retransmission + if (ue_has_transmission) { + switch (mac_xface-> + get_transmission_mode(mod_id, CC_id, rnti)) { + case 1: + case 2: + default: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = + PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = + allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_ndi); + dl_dci->ndi[0] = ndi; + dl_dci->n_rv = 1; + dl_dci->rv = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->n_tbs_size = 1; + dl_dci->tbs_size = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + if (flexran_get_duplex_mode(mod_id, CC_id) == + PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = + (UE_list->UE_template[CC_id][UE_id].DAI - + 1) & 3; + } + break; + case 3: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = + PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = + allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 2; + dl_dci->ndi = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_ndi); + dl_dci->ndi[0] = ndi; + dl_dci->ndi[1] = ndi; + dl_dci->n_rv = 2; + dl_dci->rv = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->rv[1] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 2; + dl_dci->mcs = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->mcs[1] = mcs; + dl_dci->n_tbs_size = 2; + dl_dci->tbs_size = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + dl_dci->tbs_size[1] = dci_tbs; + if (flexran_get_duplex_mode(mod_id, CC_id) == + PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = + (UE_list->UE_template[CC_id][UE_id].DAI - + 1) & 3; + } + break; + case 4: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = + PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = + allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 2; + dl_dci->ndi = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_ndi); + dl_dci->ndi[0] = ndi; + dl_dci->ndi[1] = ndi; + dl_dci->n_rv = 2; + dl_dci->rv = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->rv[1] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 2; + dl_dci->mcs = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->mcs[1] = mcs; + dl_dci->n_tbs_size = 2; + dl_dci->tbs_size = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + dl_dci->tbs_size[1] = dci_tbs; + if (flexran_get_duplex_mode(mod_id, CC_id) == + PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = + (UE_list->UE_template[CC_id][UE_id].DAI - + 1) & 3; + } + break; + case 5: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = + PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = + allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi[0] = ndi; + dl_dci->n_rv = 1; + dl_dci->rv = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->n_tbs_size = 1; + dl_dci->tbs_size = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + if (flexran_get_duplex_mode(mod_id, CC_id) == + PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = + (UE_list->UE_template[CC_id][UE_id].DAI - + 1) & 3; + } + + if (ue_sched_ctl->dl_pow_off[CC_id] == 2) { + ue_sched_ctl->dl_pow_off[CC_id] = 1; + } + + dl_dci->has_dl_power_offset = 1; + dl_dci->dl_power_offset = + ue_sched_ctl->dl_pow_off[CC_id]; + dl_dci->has_precoding_info = 1; + dl_dci->precoding_info = 5; // Is this right?? + + break; + case 6: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = + PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = + allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_ndi); + dl_dci->ndi[0] = ndi; + dl_dci->n_rv = 1; + dl_dci->rv = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = + (uint32_t *) malloc(sizeof(uint32_t) * + dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + if (flexran_get_duplex_mode(mod_id, CC_id) == + PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = + (UE_list->UE_template[CC_id][UE_id].DAI - + 1) & 3; + } + + dl_dci->has_dl_power_offset = 1; + dl_dci->dl_power_offset = + ue_sched_ctl->dl_pow_off[CC_id]; + dl_dci->has_precoding_info = 1; + dl_dci->precoding_info = 5; // Is this right?? + break; + } + } + + if (flexran_get_duplex_mode(mod_id, CC_id) == + PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + + /* TODO */ + //set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe, frame_parms); + } + } // UE_id loop + } // CC_id loop + + // Add all the dl_data elements to the flexran message + int offset = (*dl_info)->dl_mac_config_msg->n_dl_ue_data; + (*dl_info)->dl_mac_config_msg->n_dl_ue_data += num_ues_added; + if (num_ues_added > 0) { + (*dl_info)->dl_mac_config_msg->dl_ue_data = + (Protocol__FlexDlData **) + realloc((*dl_info)->dl_mac_config_msg->dl_ue_data, + sizeof(Protocol__FlexDlData *) * + ((*dl_info)->dl_mac_config_msg->n_dl_ue_data)); + if ((*dl_info)->dl_mac_config_msg->dl_ue_data == NULL) { + LOG_E(MAC, "Request for memory reallocation failed\n"); + return; } - //End of retransmission - } else { /* This is a potentially new SDU opportunity */ - rlc_status.bytes_in_buffer = 0; - // Now check RLC information to compute number of required RBs - // get maximum TBS size for RLC request - //TBS = mac_xface->get_TBS(eNB_UE_stats->DL_cqi[0]<<1,nb_available_rb); - TBS = mac_xface->get_TBS_DL(mcs, nb_available_rb); - dci_tbs = TBS; - LOG_D(FLEXRAN_AGENT, "TBS is %d\n", TBS); - - // check first for RLC data on DCCH - // add the length for all the control elements (timing adv, drx, etc) : header + payload - - ta_len = (ue_sched_ctl->ta_update != 0) ? 2 : 0; - - dl_data[num_ues_added]->n_ce_bitmap = 2; - dl_data[num_ues_added]->ce_bitmap = (uint32_t *) calloc(2, sizeof(uint32_t)); - - if (ta_len > 0) { - ce_flags |= PROTOCOL__FLEX_CE_TYPE__FLPCET_TA; + for (i = 0; i < num_ues_added; i++) { + (*dl_info)->dl_mac_config_msg->dl_ue_data[offset + i] = + dl_data[i]; } + } - /*TODO: Add other flags if DRX and other CE are required*/ - - // Add the control element flags to the flexran message - dl_data[num_ues_added]->ce_bitmap[0] = ce_flags; - dl_data[num_ues_added]->ce_bitmap[1] = ce_flags; - - // TODO : Need to prioritize DRBs - // Loop through the UE logical channels (DCCH, DCCH1, DTCH for now) - header_len = 0; - header_len_last = 0; - sdu_length_total = 0; - for (j = 1; j < NB_RB_MAX; j++) { - header_len += 3; - // Need to see if we have space for data from this channel - if (dci_tbs - ta_len - header_len - sdu_length_total > 0) { - LOG_D(MAC, "[TEST]Requested %d bytes from RLC buffer on channel %d during first call\n", dci_tbs-ta_len-header_len); - //If we have space, we need to see how much data we can request at most (if any available) - rlc_status = mac_rlc_status_ind(mod_id, - rnti, - mod_id, - frame, - subframe, - ENB_FLAG_YES, - MBMS_FLAG_NO, - j, - (dci_tbs - ta_len - header_len - sdu_length_total)); // transport block set size - - //If data are available in channel j - if (rlc_status.bytes_in_buffer > 0) { - LOG_D(MAC, "[TEST]Have %d bytes in DCCH buffer during first call\n", rlc_status.bytes_in_buffer); - //Fill in as much as possible - data_to_request = cmin(dci_tbs - ta_len - header_len - sdu_length_total, rlc_status.bytes_in_buffer); - LOG_D(FLEXRAN_AGENT, "Will request %d bytes from channel %d\n", data_to_request, j); - if (data_to_request < 128) { //The header will be one byte less - header_len--; - header_len_last = 2; - } else { - header_len_last = 3; - } - /* if (j == 1 || j == 2) { - data_to_request+=0; - } */ - LOG_D(MAC, "[TEST]Will request %d from channel %d\n", data_to_request, j); - rlc_pdus[channels_added] = (Protocol__FlexRlcPdu *) malloc(sizeof(Protocol__FlexRlcPdu)); - protocol__flex_rlc_pdu__init(rlc_pdus[channels_added]); - rlc_pdus[channels_added]->n_rlc_pdu_tb = 2; - rlc_pdus[channels_added]->rlc_pdu_tb = (Protocol__FlexRlcPduTb **) malloc(sizeof(Protocol__FlexRlcPduTb *) * 2); - rlc_pdus[channels_added]->rlc_pdu_tb[0] = (Protocol__FlexRlcPduTb *) malloc(sizeof(Protocol__FlexRlcPduTb)); - protocol__flex_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[0]); - rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_logical_channel_id = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->logical_channel_id = j; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_size = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->size = data_to_request; - rlc_pdus[channels_added]->rlc_pdu_tb[1] = (Protocol__FlexRlcPduTb *) malloc(sizeof(Protocol__FlexRlcPduTb)); - protocol__flex_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[1]); - rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_logical_channel_id = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->logical_channel_id = j; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_size = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->size = data_to_request; - dl_data[num_ues_added]->n_rlc_pdu++; - channels_added++; - //Set this to the max value that we might request - sdu_length_total += data_to_request; - } else { - //Take back the assumption of a header for this channel - header_len -= 3; - } //End rlc_status.bytes_in_buffer <= 0 - } //end of if dci_tbs - ta_len - header_len > 0 - } // End of iterating the logical channels - - // Add rlc_pdus to the dl_data message - dl_data[num_ues_added]->rlc_pdu = (Protocol__FlexRlcPdu **) malloc(sizeof(Protocol__FlexRlcPdu *) * - dl_data[num_ues_added]->n_rlc_pdu); - for (i = 0; i < dl_data[num_ues_added]->n_rlc_pdu; i++) { - dl_data[num_ues_added]->rlc_pdu[i] = rlc_pdus[i]; - } - - if (header_len == 0) { - LOG_D(FLEXRAN_AGENT, "Header was empty\n"); - header_len_last = 0; - } - - // there is a payload - if ((dl_data[num_ues_added]->n_rlc_pdu > 0)) { - // Now compute number of required RBs for total sdu length - // Assume RAH format 2 - // adjust header lengths - LOG_D(FLEXRAN_AGENT, "We have %d bytes to transfer\n", sdu_length_total); - if (header_len != 0) { - LOG_D(FLEXRAN_AGENT, "Header length was %d ", header_len); - header_len_last--; - header_len -= header_len_last; - LOG_D(FLEXRAN_AGENT, "so we resized it to %d\n", header_len); - } - - /* if (header_len == 2 || header_len == 3) { //Only one SDU, remove length field */ - /* header_len = 1; */ - /* } else { //Remove length field from the last SDU */ - /* header_len--; */ - /* } */ - - mcs_tmp = mcs; - if (mcs_tmp == 0) { - nb_rb = 4; // don't let the TBS get too small - } else { - nb_rb=min_rb_unit[CC_id]; - } - - LOG_D(MAC,"[TEST]The initial number of resource blocks was %d\n", nb_rb); - LOG_D(MAC,"[TEST] The initial mcs was %d\n", mcs_tmp); - - TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); - LOG_D(MAC,"[TEST]The TBS during rate matching was %d\n", TBS); - - while (TBS < (sdu_length_total + header_len + ta_len)) { - nb_rb += min_rb_unit[CC_id]; // - LOG_D(MAC, "[TEST]Had to increase the number of RBs\n"); - if (nb_rb > nb_available_rb) { // if we've gone beyond the maximum number of RBs - // (can happen if N_RB_DL is odd) - TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_available_rb); - nb_rb = nb_available_rb; - break; - } - - TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); - } - - if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { - LOG_D(MAC, "[TEST]We had the exact number of rbs. Time to fill the rballoc subband\n"); - for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { // for indicating the rballoc for each sub-band - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - } - } else { - nb_rb_temp = nb_rb; - j = 0; - LOG_D(MAC, "[TEST]Will only partially fill the bitmap\n"); - while((nb_rb_temp > 0) && (j < flexran_get_N_RBG(mod_id, CC_id))) { - if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - if ((j == flexran_get_N_RBG(mod_id, CC_id) - 1) && - ((flexran_get_N_RB_DL(mod_id, CC_id) == 25)|| - (flexran_get_N_RB_DL(mod_id, CC_id) == 50))) { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id] + 1; - } else { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; - } - } - j = j+1; - } - } - - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; - - for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; - } - - // decrease mcs until TBS falls below required length - while ((TBS > (sdu_length_total + header_len + ta_len)) && (mcs_tmp > 0)) { - mcs_tmp--; - TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); - } - - // if we have decreased too much or we don't have enough RBs, increase MCS - while ((TBS < (sdu_length_total + header_len + ta_len)) && - ((( ue_sched_ctl->dl_pow_off[CC_id] > 0) && (mcs_tmp < 28)) || ( (ue_sched_ctl->dl_pow_off[CC_id]==0) && (mcs_tmp <= 15)))) { - mcs_tmp++; - TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); - } - - dci_tbs = TBS; - mcs = mcs_tmp; - LOG_D(FLEXRAN_AGENT, "Final mcs was %d\n", mcs); - - dl_dci->has_aggr_level = 1; - dl_dci->aggr_level = aggregation; - - UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; - - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - UE_list->UE_template[CC_id][UE_id].DAI++; - // printf("DAI update: subframeP %d: UE %d, DAI %d\n",subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); - //#warning only for 5MHz channel - update_ul_dci(mod_id, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); - } - - // do PUCCH power control - // this is the normalized RX power - normalized_rx_power = flexran_get_p0_pucch_dbm(mod_id,UE_id, CC_id); //eNB_UE_stats->Po_PUCCH_dBm; - target_rx_power = flexran_get_p0_nominal_pucch(mod_id, CC_id) + 20; //mac_xface->get_target_pucch_rx_power(mod_id, CC_id) + 20; - // this assumes accumulated tpc - // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out - int32_t framex10psubframe = UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame*10+UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe; - - if (((framex10psubframe+10)<=(frame*10+subframe)) || //normal case - ((framex10psubframe>(frame*10+subframe)) && (((10240-framex10psubframe+frame*10+subframe)>=10)))) //frame wrap-around - if (flexran_get_p0_pucch_status(mod_id, UE_id, CC_id) == 1) { - flexran_update_p0_pucch(mod_id, UE_id, CC_id); - - UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame = frame; - UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe = subframe; - if (normalized_rx_power>(target_rx_power+1)) { - tpc = 0; //-1 - tpc_accumulated--; - } else if (normalized_rx_power<(target_rx_power-1)) { - tpc = 2; //+1 - tpc_accumulated++; - } else { - tpc = 1; //0 - } - LOG_D(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", - mod_id, frame, subframe, harq_pid, tpc, - tpc_accumulated, normalized_rx_power, target_rx_power); - } // Po_PUCCH has been updated - else { - tpc = 1; //0 - } // time to do TPC update - else { - tpc = 1; //0 - } - - for(i=0; iframe_parms.N_RBG; i++) { - rballoc_sub[i] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][i]; - } - - // Toggle NDI - LOG_D(MAC,"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", - CC_id, frame, subframe, UE_id, - UE_list->UE_template[CC_id][UE_id].rnti,harq_pid, UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]); - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]= 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - ndi = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - - UE_list->UE_template[CC_id][UE_id].mcs[harq_pid] = mcs; - UE_list->UE_template[CC_id][UE_id].oldTPC[harq_pid] = tpc; - - // Increase the pointer for the number of scheduled UEs - num_ues_added++; - ue_has_transmission = 1; - } else { // There is no data from RLC or MAC header, so don't schedule - ue_has_transmission = 0; - } - } // End of new scheduling - - // If we has transmission or retransmission - if (ue_has_transmission) { - switch (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)) { - case 1: - case 2: - default: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 1; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = ndi; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->n_tbs_size = 1; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - break; - case 3: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 2; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = ndi; - dl_dci->ndi[1] = ndi; - dl_dci->n_rv = 2; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->rv[1] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 2; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->mcs[1] = mcs; - dl_dci->n_tbs_size = 2; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - dl_dci->tbs_size[1] = dci_tbs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - break; - case 4: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 2; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = ndi; - dl_dci->ndi[1] = ndi; - dl_dci->n_rv = 2; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->rv[1] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 2; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->mcs[1] = mcs; - dl_dci->n_tbs_size = 2; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - dl_dci->tbs_size[1] = dci_tbs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - break; - case 5: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 1; - dl_dci->ndi[0] = ndi; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->n_tbs_size = 1; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - - if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { - ue_sched_ctl->dl_pow_off[CC_id] = 1; - } - - dl_dci->has_dl_power_offset = 1; - dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; - dl_dci->has_precoding_info = 1; - dl_dci->precoding_info = 5; // Is this right?? - - break; - case 6: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 1; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = ndi; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - - dl_dci->has_dl_power_offset = 1; - dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; - dl_dci->has_precoding_info = 1; - dl_dci->precoding_info = 5; // Is this right?? - break; - } - } - - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - - /* TODO */ - //set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe, frame_parms); - } - } // UE_id loop - } // CC_id loop - - // Add all the dl_data elements to the flexran message - int offset = (*dl_info)->dl_mac_config_msg->n_dl_ue_data; - (*dl_info)->dl_mac_config_msg->n_dl_ue_data += num_ues_added; - if ( num_ues_added > 0 ){ - (*dl_info)->dl_mac_config_msg->dl_ue_data = (Protocol__FlexDlData **) realloc( (*dl_info)->dl_mac_config_msg->dl_ue_data, - sizeof(Protocol__FlexDlData *) * ((*dl_info)->dl_mac_config_msg->n_dl_ue_data)); - if ((*dl_info)->dl_mac_config_msg->dl_ue_data == NULL ){ - LOG_E(MAC, "Request for memory reallocation failed\n"); - return; - } - for (i = 0; i < num_ues_added; i++) { - (*dl_info)->dl_mac_config_msg->dl_ue_data[offset+i] = dl_data[i]; - } - } - - stop_meas(&eNB->schedule_dlsch); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_OUT); + stop_meas(&eNB->schedule_dlsch); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_OUT); } diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c index 17424b2797..68c86f1da5 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c @@ -17,7 +17,7 @@ *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org - */ + */ /*! \file flexran_agent_scheduler_dlsch_ue_remote.c * \brief procedures related to remote scheduling in the DLSCH transport channel @@ -44,137 +44,159 @@ int queue_initialized = 0; //uint32_t period = 10; //uint32_t sched [] = {1, 2, 3}; -void flexran_schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__FlexranMessage **dl_info) { +void +flexran_schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, + uint32_t subframe, int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info) +{ - - //if ((subframe == skip_subframe) && (frame % period == 0)) { - // LOG_I(MAC, "Will skip subframe %d %d\n", subframe, frame); - // for (int i = 0; i < 3; i++) { - // LOG_I(MAC, "%d\n", sched[i]); - // } - //} - /* if (frame == 500 && subframe == 1) { */ - /* char policy[] = "rrc: \n - ul_scheduler: \n behavior : tester_function\n parameters:\n period: !!int 3\nmac: \n - dl_scheduler: \n parameters: \n period : !!int 40\n skip_subframe : !!int 3\n sched : [!!int 4, !!int 5, !!int 6]"; */ - /* apply_reconfiguration_policy(mod_id, policy, strlen(policy)); */ - /* } */ - - eNB_MAC_INST *eNB; - - if (!queue_initialized) { - TAILQ_INIT(&queue_head); - queue_initialized = 1; - } - - eNB = &eNB_mac_inst[mod_id]; - - dl_mac_config_element_t *dl_config_elem; - - int diff; - LOG_D(MAC, "[TEST] Current frame and subframe %d, %d\n", frame, subframe); - // First we check to see if we have a scheduling decision for this sfn_sf already in our queue - while(queue_head.tqh_first != NULL) { - dl_config_elem = queue_head.tqh_first; - - diff = get_sf_difference(mod_id, dl_config_elem->dl_info->dl_mac_config_msg->sfn_sf); - // Check if this decision is for now, for a later or a previous subframe - if ( diff == 0) { // Now - LOG_D(MAC, "Found a decision for this subframe in the queue. Let's use it!\n"); - TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs); - *dl_info = dl_config_elem->dl_info; - free(dl_config_elem); - eNB->eNB_stats[mod_id].sched_decisions++; - return; - } else if (diff < 0) { //previous subframe , delete message and free memory - LOG_D(MAC, "Found a decision for a previous subframe in the queue. Let's get rid of it\n"); - TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs); - flexran_agent_mac_destroy_dl_config(dl_config_elem->dl_info); - free(dl_config_elem); - eNB->eNB_stats[mod_id].sched_decisions++; - eNB->eNB_stats[mod_id].missed_deadlines++; - } else { // next subframe, nothing to do now - LOG_D(MAC, "Found a decision for a future subframe in the queue. Nothing to do now\n"); - flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); - return; - } - } - - //Done with the local cache. Now we need to check if something new arrived - flexran_agent_get_pending_dl_mac_config(mod_id, dl_info); - while (*dl_info != NULL) { - - diff = get_sf_difference(mod_id, (*dl_info)->dl_mac_config_msg->sfn_sf); - if (diff == 0) { // Got a command for this sfn_sf - LOG_D(MAC, "Found a decision for this subframe pending. Let's use it\n"); - eNB->eNB_stats[mod_id].sched_decisions++; - return; - } else if (diff < 0) { - LOG_D(MAC, "Found a decision for a previous subframe. Let's get rid of it\n"); - flexran_agent_mac_destroy_dl_config(*dl_info); - *dl_info = NULL; - flexran_agent_get_pending_dl_mac_config(mod_id, dl_info); - eNB->eNB_stats[mod_id].sched_decisions++; - eNB->eNB_stats[mod_id].missed_deadlines++; - } else { // Intended for future subframe. Store it in local cache - LOG_D(MAC, "Found a decision for a future subframe in the queue. Let's store it in the cache\n"); - dl_mac_config_element_t *e = malloc(sizeof(dl_mac_config_element_t)); - e->dl_info = *dl_info; - TAILQ_INSERT_TAIL(&queue_head, e, configs); - flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); - // No need to look for another. Messages arrive ordered - return; - } - } - - // We found no pending command, so we will simply pass an empty one - flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); -} - -int get_sf_difference(mid_t mod_id, uint32_t sfn_sf) { - int diff_in_subframes; - - uint16_t current_frame = flexran_get_current_system_frame_num(mod_id); - uint16_t current_subframe = flexran_get_current_subframe(mod_id); - uint32_t current_sfn_sf = flexran_get_sfn_sf(mod_id); - - if (sfn_sf == current_sfn_sf) { - return 0; - } - - uint16_t frame_mask = ((1<<12) - 1); - uint16_t frame = (sfn_sf & (frame_mask << 4)) >> 4; - - uint16_t sf_mask = ((1<<4) - 1); - uint16_t subframe = (sfn_sf & sf_mask); - - LOG_D(MAC, "[TEST] Target frame and subframe %d, %d\n", frame, subframe); - - if (frame == current_frame) { - return subframe - current_subframe; - } else if (frame > current_frame) { - diff_in_subframes = ((frame*10)+subframe) - ((current_frame*10)+current_subframe); - - // diff_in_subframes = 9 - current_subframe; - //diff_in_subframes += (subframe + 1); - //diff_in_subframes += (frame-2) * 10; - if (diff_in_subframes > SCHED_AHEAD_SUBFRAMES) { - return -1; - } else { - return 1; - } - } else { //frame < current_frame - //diff_in_subframes = 9 - current_subframe; - //diff_in_subframes += (subframe + 1); - //if (frame > 0) { - // diff_in_subframes += (frame - 1) * 10; + //if ((subframe == skip_subframe) && (frame % period == 0)) { + // LOG_I(MAC, "Will skip subframe %d %d\n", subframe, frame); + // for (int i = 0; i < 3; i++) { + // LOG_I(MAC, "%d\n", sched[i]); + // } //} - //diff_in_subframes += (1023 - current_frame) * 10; - diff_in_subframes = 10240 - ((current_frame*10)+current_subframe) + ((frame*10)+subframe); - if (diff_in_subframes > SCHED_AHEAD_SUBFRAMES) { - return -1; - } else { - return 1; + + /* if (frame == 500 && subframe == 1) { */ + /* char policy[] = "rrc: \n - ul_scheduler: \n behavior : tester_function\n parameters:\n period: !!int 3\nmac: \n - dl_scheduler: \n parameters: \n period : !!int 40\n skip_subframe : !!int 3\n sched : [!!int 4, !!int 5, !!int 6]"; */ + /* apply_reconfiguration_policy(mod_id, policy, strlen(policy)); */ + /* } */ + + eNB_MAC_INST *eNB; + + if (!queue_initialized) { + TAILQ_INIT(&queue_head); + queue_initialized = 1; + } + + eNB = &eNB_mac_inst[mod_id]; + + dl_mac_config_element_t *dl_config_elem; + + int diff; + LOG_D(MAC, "[TEST] Current frame and subframe %d, %d\n", frame, + subframe); + // First we check to see if we have a scheduling decision for this sfn_sf already in our queue + while (queue_head.tqh_first != NULL) { + dl_config_elem = queue_head.tqh_first; + + diff = + get_sf_difference(mod_id, + dl_config_elem->dl_info-> + dl_mac_config_msg->sfn_sf); + // Check if this decision is for now, for a later or a previous subframe + if (diff == 0) { // Now + LOG_D(MAC, + "Found a decision for this subframe in the queue. Let's use it!\n"); + TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs); + *dl_info = dl_config_elem->dl_info; + free(dl_config_elem); + eNB->eNB_stats[mod_id].sched_decisions++; + return; + } else if (diff < 0) { //previous subframe , delete message and free memory + LOG_D(MAC, + "Found a decision for a previous subframe in the queue. Let's get rid of it\n"); + TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs); + flexran_agent_mac_destroy_dl_config(dl_config_elem->dl_info); + free(dl_config_elem); + eNB->eNB_stats[mod_id].sched_decisions++; + eNB->eNB_stats[mod_id].missed_deadlines++; + } else { // next subframe, nothing to do now + LOG_D(MAC, + "Found a decision for a future subframe in the queue. Nothing to do now\n"); + flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); + return; + } + } + + //Done with the local cache. Now we need to check if something new arrived + flexran_agent_get_pending_dl_mac_config(mod_id, dl_info); + while (*dl_info != NULL) { + + diff = + get_sf_difference(mod_id, + (*dl_info)->dl_mac_config_msg->sfn_sf); + if (diff == 0) { // Got a command for this sfn_sf + LOG_D(MAC, + "Found a decision for this subframe pending. Let's use it\n"); + eNB->eNB_stats[mod_id].sched_decisions++; + return; + } else if (diff < 0) { + LOG_D(MAC, + "Found a decision for a previous subframe. Let's get rid of it\n"); + flexran_agent_mac_destroy_dl_config(*dl_info); + *dl_info = NULL; + flexran_agent_get_pending_dl_mac_config(mod_id, dl_info); + eNB->eNB_stats[mod_id].sched_decisions++; + eNB->eNB_stats[mod_id].missed_deadlines++; + } else { // Intended for future subframe. Store it in local cache + LOG_D(MAC, + "Found a decision for a future subframe in the queue. Let's store it in the cache\n"); + dl_mac_config_element_t *e = + malloc(sizeof(dl_mac_config_element_t)); + e->dl_info = *dl_info; + TAILQ_INSERT_TAIL(&queue_head, e, configs); + flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); + // No need to look for another. Messages arrive ordered + return; + } + } + + // We found no pending command, so we will simply pass an empty one + flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); +} + +int get_sf_difference(mid_t mod_id, uint32_t sfn_sf) +{ + int diff_in_subframes; + + uint16_t current_frame = flexran_get_current_system_frame_num(mod_id); + uint16_t current_subframe = flexran_get_current_subframe(mod_id); + uint32_t current_sfn_sf = flexran_get_sfn_sf(mod_id); + + if (sfn_sf == current_sfn_sf) { + return 0; + } + + uint16_t frame_mask = ((1 << 12) - 1); + uint16_t frame = (sfn_sf & (frame_mask << 4)) >> 4; + + uint16_t sf_mask = ((1 << 4) - 1); + uint16_t subframe = (sfn_sf & sf_mask); + + LOG_D(MAC, "[TEST] Target frame and subframe %d, %d\n", frame, + subframe); + + if (frame == current_frame) { + return subframe - current_subframe; + } else if (frame > current_frame) { + diff_in_subframes = + ((frame * 10) + subframe) - ((current_frame * 10) + + current_subframe); + + // diff_in_subframes = 9 - current_subframe; + //diff_in_subframes += (subframe + 1); + //diff_in_subframes += (frame-2) * 10; + if (diff_in_subframes > SCHED_AHEAD_SUBFRAMES) { + return -1; + } else { + return 1; + } + } else { //frame < current_frame + //diff_in_subframes = 9 - current_subframe; + //diff_in_subframes += (subframe + 1); + //if (frame > 0) { + // diff_in_subframes += (frame - 1) * 10; + //} + //diff_in_subframes += (1023 - current_frame) * 10; + diff_in_subframes = + 10240 - ((current_frame * 10) + current_subframe) + + ((frame * 10) + subframe); + if (diff_in_subframes > SCHED_AHEAD_SUBFRAMES) { + return -1; + } else { + return 1; + } } - } } diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h index 997b9d1d24..449ba1e8cd 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h @@ -17,7 +17,7 @@ *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org - */ + */ /*! \file flexran_agent_scheduler_dlsch_ue_remote.h * \brief Local stub for remote scheduler used by the controller @@ -46,8 +46,8 @@ #define SCHED_AHEAD_SUBFRAMES 20 typedef struct dl_mac_config_element_s { - Protocol__FlexranMessage *dl_info; - TAILQ_ENTRY(dl_mac_config_element_s) configs; + Protocol__FlexranMessage *dl_info; + TAILQ_ENTRY(dl_mac_config_element_s) configs; } dl_mac_config_element_t; TAILQ_HEAD(DlMacConfigHead, dl_mac_config_element_s); @@ -55,8 +55,9 @@ TAILQ_HEAD(DlMacConfigHead, dl_mac_config_element_s); /* * Default scheduler used by the eNB agent */ -void flexran_schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__FlexranMessage **dl_info); +void flexran_schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, + uint32_t subframe, int *mbsfn_flag, + Protocol__FlexranMessage ** dl_info); // Find the difference in subframes from the given subframe diff --git a/openair2/LAYER2/MAC/flexran_dci_conversions.h b/openair2/LAYER2/MAC/flexran_dci_conversions.h index f52ae5b807..5c18b43104 100644 --- a/openair2/LAYER2/MAC/flexran_dci_conversions.h +++ b/openair2/LAYER2/MAC/flexran_dci_conversions.h @@ -17,7 +17,7 @@ *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org - */ + */ /*! \file flexran_dci_conversions.h * \brief Conversion helpers from flexran messages to OAI formats DCI @@ -47,5 +47,5 @@ ((TYPE*)DCI)->mcs = FLEXRAN_DCI->mcs[0]; \ ((TYPE*)DCI)->TPC = FLEXRAN_DCI->tpc; \ ((TYPE*)DCI)->ndi = FLEXRAN_DCI->ndi[0]; - + #endif diff --git a/openair2/LAYER2/MAC/l1_helpers.c b/openair2/LAYER2/MAC/l1_helpers.c index 2b5a38eda7..6e71f66ec5 100644 --- a/openair2/LAYER2/MAC/l1_helpers.c +++ b/openair2/LAYER2/MAC/l1_helpers.c @@ -34,28 +34,36 @@ #include "UTIL/LOG/log.h" #include "proto.h" -int8_t get_Po_NOMINAL_PUSCH(module_id_t module_idP,uint8_t CC_id) +int8_t get_Po_NOMINAL_PUSCH(module_id_t module_idP, uint8_t CC_id) { - RACH_ConfigCommon_t *rach_ConfigCommon = NULL; + RACH_ConfigCommon_t *rach_ConfigCommon = NULL; - AssertFatal(CC_id==0, - "Transmission on secondary CCs is not supported yet\n"); - AssertFatal(UE_mac_inst[module_idP].radioResourceConfigCommon!=NULL, - "[UE %d] CCid %d FATAL radioResourceConfigCommon is NULL !!!\n",module_idP,CC_id); + AssertFatal(CC_id == 0, + "Transmission on secondary CCs is not supported yet\n"); + AssertFatal(UE_mac_inst[module_idP].radioResourceConfigCommon != NULL, + "[UE %d] CCid %d FATAL radioResourceConfigCommon is NULL !!!\n", + module_idP, CC_id); - rach_ConfigCommon = &UE_mac_inst[module_idP].radioResourceConfigCommon->rach_ConfigCommon; + rach_ConfigCommon = + &UE_mac_inst[module_idP].radioResourceConfigCommon-> + rach_ConfigCommon; - return(-120 + (rach_ConfigCommon->powerRampingParameters.preambleInitialReceivedTargetPower<<1) + - get_DELTA_PREAMBLE(module_idP,CC_id)); + return (-120 + + (rach_ConfigCommon-> + powerRampingParameters.preambleInitialReceivedTargetPower << + 1) + get_DELTA_PREAMBLE(module_idP, CC_id)); } -int8_t get_deltaP_rampup(module_id_t module_idP,uint8_t CC_id) +int8_t get_deltaP_rampup(module_id_t module_idP, uint8_t CC_id) { - AssertFatal(CC_id==0, - "Transmission on secondary CCs is not supported yet\n"); + AssertFatal(CC_id == 0, + "Transmission on secondary CCs is not supported yet\n"); - LOG_D(MAC,"[PUSCH]%d dB\n",UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER<<1); - return((int8_t)(UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER<<1)); + LOG_D(MAC, "[PUSCH]%d dB\n", + UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER << 1); + return ((int8_t) + (UE_mac_inst[module_idP]. + RA_PREAMBLE_TRANSMISSION_COUNTER << 1)); } diff --git a/openair2/LAYER2/MAC/lte_transport_init.c b/openair2/LAYER2/MAC/lte_transport_init.c index 1f67d8913c..e1f21f21e4 100644 --- a/openair2/LAYER2/MAC/lte_transport_init.c +++ b/openair2/LAYER2/MAC/lte_transport_init.c @@ -29,104 +29,104 @@ void init_transport_channels(unsigned char transmission_mode) { - // init DCI structures for testing + // init DCI structures for testing - UL_alloc_pdu.type = 0; - UL_alloc_pdu.hopping = 0; - UL_alloc_pdu.rballoc = UL_RB_ALLOC; - UL_alloc_pdu.mcs = 2; - UL_alloc_pdu.ndi = 1; - UL_alloc_pdu.TPC = 0; - UL_alloc_pdu.cqi_req = 1; + UL_alloc_pdu.type = 0; + UL_alloc_pdu.hopping = 0; + UL_alloc_pdu.rballoc = UL_RB_ALLOC; + UL_alloc_pdu.mcs = 2; + UL_alloc_pdu.ndi = 1; + UL_alloc_pdu.TPC = 0; + UL_alloc_pdu.cqi_req = 1; - /* - BCCH_alloc_pdu.type = 1; - BCCH_alloc_pdu.vrb_type = 0; - BCCH_alloc_pdu.rballoc = BCCH_RB_ALLOC; - BCCH_alloc_pdu.ndi = 1; - BCCH_alloc_pdu.rv = 1; - BCCH_alloc_pdu.mcs = 1; - BCCH_alloc_pdu.harq_pid = 0; - BCCH_alloc_pdu.TPC = 1; // set to 3 PRB + /* + BCCH_alloc_pdu.type = 1; + BCCH_alloc_pdu.vrb_type = 0; + BCCH_alloc_pdu.rballoc = BCCH_RB_ALLOC; + BCCH_alloc_pdu.ndi = 1; + BCCH_alloc_pdu.rv = 1; + BCCH_alloc_pdu.mcs = 1; + BCCH_alloc_pdu.harq_pid = 0; + BCCH_alloc_pdu.TPC = 1; // set to 3 PRB - // for FDD mode - BCCH_alloc_pdu_fdd.type = 1; - BCCH_alloc_pdu_fdd.vrb_type = 0; - BCCH_alloc_pdu_fdd.rballoc = BCCH_RB_ALLOC; - BCCH_alloc_pdu_fdd.ndi = 1; - BCCH_alloc_pdu_fdd.rv = 1; - BCCH_alloc_pdu_fdd.mcs = 1; - BCCH_alloc_pdu_fdd.harq_pid = 0; - BCCH_alloc_pdu_fdd.TPC = 1; // set to 3 PRB - */ + // for FDD mode + BCCH_alloc_pdu_fdd.type = 1; + BCCH_alloc_pdu_fdd.vrb_type = 0; + BCCH_alloc_pdu_fdd.rballoc = BCCH_RB_ALLOC; + BCCH_alloc_pdu_fdd.ndi = 1; + BCCH_alloc_pdu_fdd.rv = 1; + BCCH_alloc_pdu_fdd.mcs = 1; + BCCH_alloc_pdu_fdd.harq_pid = 0; + BCCH_alloc_pdu_fdd.TPC = 1; // set to 3 PRB + */ - DLSCH_alloc_pdu1A.type = 1; - DLSCH_alloc_pdu1A.vrb_type = 0; - DLSCH_alloc_pdu1A.rballoc = BCCH_RB_ALLOC; - DLSCH_alloc_pdu1A.ndi = 1; - DLSCH_alloc_pdu1A.rv = 1; - DLSCH_alloc_pdu1A.mcs = 2; - DLSCH_alloc_pdu1A.harq_pid = 0; - DLSCH_alloc_pdu1A.TPC = 1; // set to 3 PRB + DLSCH_alloc_pdu1A.type = 1; + DLSCH_alloc_pdu1A.vrb_type = 0; + DLSCH_alloc_pdu1A.rballoc = BCCH_RB_ALLOC; + DLSCH_alloc_pdu1A.ndi = 1; + DLSCH_alloc_pdu1A.rv = 1; + DLSCH_alloc_pdu1A.mcs = 2; + DLSCH_alloc_pdu1A.harq_pid = 0; + DLSCH_alloc_pdu1A.TPC = 1; // set to 3 PRB - DLSCH_alloc_pdu1A_fdd.type = 1; - DLSCH_alloc_pdu1A_fdd.vrb_type = 0; - DLSCH_alloc_pdu1A_fdd.rballoc = BCCH_RB_ALLOC; - DLSCH_alloc_pdu1A_fdd.ndi = 1; - DLSCH_alloc_pdu1A_fdd.rv = 1; - DLSCH_alloc_pdu1A_fdd.mcs = 2; - DLSCH_alloc_pdu1A_fdd.harq_pid = 0; - DLSCH_alloc_pdu1A_fdd.TPC = 1; // set to 3 PRB + DLSCH_alloc_pdu1A_fdd.type = 1; + DLSCH_alloc_pdu1A_fdd.vrb_type = 0; + DLSCH_alloc_pdu1A_fdd.rballoc = BCCH_RB_ALLOC; + DLSCH_alloc_pdu1A_fdd.ndi = 1; + DLSCH_alloc_pdu1A_fdd.rv = 1; + DLSCH_alloc_pdu1A_fdd.mcs = 2; + DLSCH_alloc_pdu1A_fdd.harq_pid = 0; + DLSCH_alloc_pdu1A_fdd.TPC = 1; // set to 3 PRB - RA_alloc_pdu.type = 1; - RA_alloc_pdu.vrb_type = 0; - RA_alloc_pdu.rballoc = RA_RB_ALLOC; - RA_alloc_pdu.ndi = 1; - RA_alloc_pdu.rv = 0; - RA_alloc_pdu.mcs = 0; - RA_alloc_pdu.harq_pid = 0; - RA_alloc_pdu.TPC = 1; + RA_alloc_pdu.type = 1; + RA_alloc_pdu.vrb_type = 0; + RA_alloc_pdu.rballoc = RA_RB_ALLOC; + RA_alloc_pdu.ndi = 1; + RA_alloc_pdu.rv = 0; + RA_alloc_pdu.mcs = 0; + RA_alloc_pdu.harq_pid = 0; + RA_alloc_pdu.TPC = 1; - RA_alloc_pdu_fdd.type = 1; - RA_alloc_pdu_fdd.vrb_type = 0; - RA_alloc_pdu_fdd.rballoc = RA_RB_ALLOC; - RA_alloc_pdu_fdd.ndi = 1; - RA_alloc_pdu_fdd.rv = 1; - RA_alloc_pdu_fdd.mcs = 1; - RA_alloc_pdu_fdd.harq_pid = 0; - RA_alloc_pdu_fdd.TPC = 1; + RA_alloc_pdu_fdd.type = 1; + RA_alloc_pdu_fdd.vrb_type = 0; + RA_alloc_pdu_fdd.rballoc = RA_RB_ALLOC; + RA_alloc_pdu_fdd.ndi = 1; + RA_alloc_pdu_fdd.rv = 1; + RA_alloc_pdu_fdd.mcs = 1; + RA_alloc_pdu_fdd.harq_pid = 0; + RA_alloc_pdu_fdd.TPC = 1; - DLSCH_alloc_pdu1.rballoc = 0xf; - DLSCH_alloc_pdu1.TPC = 0; - DLSCH_alloc_pdu1.dai = 0; - DLSCH_alloc_pdu1.harq_pid = 0; - DLSCH_alloc_pdu1.tb_swap = 0; - DLSCH_alloc_pdu1.mcs1 = 4; - DLSCH_alloc_pdu1.ndi1 = 1; - DLSCH_alloc_pdu1.rv1 = 0; + DLSCH_alloc_pdu1.rballoc = 0xf; + DLSCH_alloc_pdu1.TPC = 0; + DLSCH_alloc_pdu1.dai = 0; + DLSCH_alloc_pdu1.harq_pid = 0; + DLSCH_alloc_pdu1.tb_swap = 0; + DLSCH_alloc_pdu1.mcs1 = 4; + DLSCH_alloc_pdu1.ndi1 = 1; + DLSCH_alloc_pdu1.rv1 = 0; - // Forget second codeword - if (transmission_mode == 6) { - DLSCH_alloc_pdu1.tpmi = 5; // PUSCH_PRECODING0 - } else { - DLSCH_alloc_pdu1.tpmi = 0; - } + // Forget second codeword + if (transmission_mode == 6) { + DLSCH_alloc_pdu1.tpmi = 5; // PUSCH_PRECODING0 + } else { + DLSCH_alloc_pdu1.tpmi = 0; + } - DLSCH_alloc_pdu2.rah = 0; - DLSCH_alloc_pdu2.rballoc = DLSCH_RB_ALLOC; - DLSCH_alloc_pdu2.TPC = 0; - DLSCH_alloc_pdu2.dai = 0; - DLSCH_alloc_pdu2.harq_pid = 0; - DLSCH_alloc_pdu2.tb_swap = 0; - DLSCH_alloc_pdu2.mcs1 = 4; - DLSCH_alloc_pdu2.ndi1 = 1; - DLSCH_alloc_pdu2.rv1 = 0; + DLSCH_alloc_pdu2.rah = 0; + DLSCH_alloc_pdu2.rballoc = DLSCH_RB_ALLOC; + DLSCH_alloc_pdu2.TPC = 0; + DLSCH_alloc_pdu2.dai = 0; + DLSCH_alloc_pdu2.harq_pid = 0; + DLSCH_alloc_pdu2.tb_swap = 0; + DLSCH_alloc_pdu2.mcs1 = 4; + DLSCH_alloc_pdu2.ndi1 = 1; + DLSCH_alloc_pdu2.rv1 = 0; - // Forget second codeword - if (transmission_mode == 6) { - DLSCH_alloc_pdu2.tpmi = 5; // PUSCH_PRECODING0 - } else { - DLSCH_alloc_pdu2.tpmi = 0; - } + // Forget second codeword + if (transmission_mode == 6) { + DLSCH_alloc_pdu2.tpmi = 5; // PUSCH_PRECODING0 + } else { + DLSCH_alloc_pdu2.tpmi = 0; + } } diff --git a/openair2/LAYER2/MAC/main.c b/openair2/LAYER2/MAC/main.c index 83f639a89d..fcaab0b80b 100644 --- a/openair2/LAYER2/MAC/main.c +++ b/openair2/LAYER2/MAC/main.c @@ -48,66 +48,72 @@ extern RAN_CONTEXT_t RC; -void dl_phy_sync_success(module_id_t module_idP, - frame_t frameP, - unsigned char eNB_index, - uint8_t first_sync) //init as MR +void dl_phy_sync_success(module_id_t module_idP, frame_t frameP, unsigned char eNB_index, uint8_t first_sync) //init as MR { - LOG_D(MAC,"[UE %d] Frame %d: PHY Sync to eNB_index %d successful \n", module_idP, frameP, eNB_index); + LOG_D(MAC, "[UE %d] Frame %d: PHY Sync to eNB_index %d successful \n", + module_idP, frameP, eNB_index); #if defined(ENABLE_USE_MME) - int mme_enabled=1; + int mme_enabled = 1; #else - int mme_enabled=0; + int mme_enabled = 0; #endif - if (first_sync==1 && !(mme_enabled==1)) { - //layer2_init_UE(module_idP); - openair_rrc_ue_init(module_idP,eNB_index); - } else - { - rrc_in_sync_ind(module_idP,frameP,eNB_index); - } -} - -void mac_UE_out_of_sync_ind(module_id_t module_idP, frame_t frameP, uint16_t eNB_index) -{ - - // Mac_rlc_xface->mac_out_of_sync_ind(Mod_id, frameP, eNB_index); -} - - -int mac_top_init_ue(int eMBMS_active, char *uecap_xer, uint8_t cba_group_active, uint8_t HO_active) -{ - - int i; - - LOG_I(MAC,"[MAIN] Init function start:Nb_UE_INST=%d\n",NB_UE_INST); - - if (NB_UE_INST>0) { - UE_mac_inst = (UE_MAC_INST*)malloc16(NB_UE_INST*sizeof(UE_MAC_INST)); - - AssertFatal(UE_mac_inst!=NULL, - "[MAIN] Can't ALLOCATE %zu Bytes for %d UE_MAC_INST with size %zu \n",NB_UE_INST*sizeof(UE_MAC_INST),NB_UE_INST,sizeof(UE_MAC_INST)); - - LOG_D(MAC,"[MAIN] ALLOCATE %zu Bytes for %d UE_MAC_INST @ %p\n",NB_UE_INST*sizeof(UE_MAC_INST),NB_UE_INST,UE_mac_inst); - - bzero(UE_mac_inst,NB_UE_INST*sizeof(UE_MAC_INST)); - - for(i=0; imac_out_of_sync_ind(Mod_id, frameP, eNB_index); +} - LOG_I(MAC,"[MAIN] calling RRC\n"); - openair_rrc_top_init_ue(eMBMS_active, uecap_xer, cba_group_active,HO_active); +int +mac_top_init_ue(int eMBMS_active, char *uecap_xer, + uint8_t cba_group_active, uint8_t HO_active) +{ - - LOG_I(MAC,"[MAIN][INIT] Init function finished\n"); + int i; - return(0); + LOG_I(MAC, "[MAIN] Init function start:Nb_UE_INST=%d\n", NB_UE_INST); + + if (NB_UE_INST > 0) { + UE_mac_inst = + (UE_MAC_INST *) malloc16(NB_UE_INST * sizeof(UE_MAC_INST)); + + AssertFatal(UE_mac_inst != NULL, + "[MAIN] Can't ALLOCATE %zu Bytes for %d UE_MAC_INST with size %zu \n", + NB_UE_INST * sizeof(UE_MAC_INST), NB_UE_INST, + sizeof(UE_MAC_INST)); + + LOG_D(MAC, "[MAIN] ALLOCATE %zu Bytes for %d UE_MAC_INST @ %p\n", + NB_UE_INST * sizeof(UE_MAC_INST), NB_UE_INST, UE_mac_inst); + + bzero(UE_mac_inst, NB_UE_INST * sizeof(UE_MAC_INST)); + + for (i = 0; i < NB_UE_INST; i++) { + ue_init_mac(i); + } + } else { + UE_mac_inst = NULL; + } + + + LOG_I(MAC, "[MAIN] calling RRC\n"); + openair_rrc_top_init_ue(eMBMS_active, uecap_xer, cba_group_active, + HO_active); + + + LOG_I(MAC, "[MAIN][INIT] Init function finished\n"); + + return (0); } @@ -115,183 +121,107 @@ int mac_top_init_ue(int eMBMS_active, char *uecap_xer, uint8_t cba_group_active, void mac_top_init_eNB() { - module_id_t i,j; - int list_el; - UE_list_t *UE_list; - eNB_MAC_INST *mac; + module_id_t i, j; + int list_el; + UE_list_t *UE_list; + eNB_MAC_INST *mac; - LOG_I(MAC,"[MAIN] Init function start:nb_macrlc_inst=%d\n",RC.nb_macrlc_inst); + LOG_I(MAC, "[MAIN] Init function start:nb_macrlc_inst=%d\n", + RC.nb_macrlc_inst); - if (RC.nb_macrlc_inst>0) { - RC.mac = (eNB_MAC_INST**)malloc16(RC.nb_macrlc_inst*sizeof(eNB_MAC_INST*)); - AssertFatal(RC.mac != NULL,"can't ALLOCATE %zu Bytes for %d eNB_MAC_INST with size %zu \n", - RC.nb_macrlc_inst*sizeof(eNB_MAC_INST*), - RC.nb_macrlc_inst, - sizeof(eNB_MAC_INST)); - for (i=0;iMod_id = i; - for (j=0;jDL_req[j].dl_config_request_body.dl_config_pdu_list = RC.mac[i]->dl_config_pdu_list[j]; - RC.mac[i]->UL_req[j].ul_config_request_body.ul_config_pdu_list = RC.mac[i]->ul_config_pdu_list[j]; - for (int k=0;k<10;k++) RC.mac[i]->UL_req_tmp[j][k].ul_config_request_body.ul_config_pdu_list = RC.mac[i]->ul_config_pdu_list_tmp[j][k]; - RC.mac[i]->HI_DCI0_req[j].hi_dci0_request_body.hi_dci0_pdu_list = RC.mac[i]->hi_dci0_pdu_list[j]; - RC.mac[i]->TX_req[j].tx_request_body.tx_pdu_list = RC.mac[i]->tx_request_pdu[j]; - RC.mac[i]->ul_handle = 0; - } + if (RC.nb_macrlc_inst > 0) { + RC.mac = + (eNB_MAC_INST **) malloc16(RC.nb_macrlc_inst * + sizeof(eNB_MAC_INST *)); + AssertFatal(RC.mac != NULL, + "can't ALLOCATE %zu Bytes for %d eNB_MAC_INST with size %zu \n", + RC.nb_macrlc_inst * sizeof(eNB_MAC_INST *), + RC.nb_macrlc_inst, sizeof(eNB_MAC_INST)); + for (i = 0; i < RC.nb_macrlc_inst; i++) { + RC.mac[i] = (eNB_MAC_INST *) malloc16(sizeof(eNB_MAC_INST)); + AssertFatal(RC.mac != NULL, + "can't ALLOCATE %zu Bytes for %d eNB_MAC_INST with size %zu \n", + RC.nb_macrlc_inst * sizeof(eNB_MAC_INST *), + RC.nb_macrlc_inst, sizeof(eNB_MAC_INST)); + LOG_D(MAC, + "[MAIN] ALLOCATE %zu Bytes for %d eNB_MAC_INST @ %p\n", + sizeof(eNB_MAC_INST), RC.nb_macrlc_inst, RC.mac); + bzero(RC.mac[i], sizeof(eNB_MAC_INST)); + RC.mac[i]->Mod_id = i; + for (j = 0; j < MAX_NUM_CCs; j++) { + RC.mac[i]->DL_req[j].dl_config_request_body. + dl_config_pdu_list = RC.mac[i]->dl_config_pdu_list[j]; + RC.mac[i]->UL_req[j].ul_config_request_body. + ul_config_pdu_list = RC.mac[i]->ul_config_pdu_list[j]; + for (int k = 0; k < 10; k++) + RC.mac[i]->UL_req_tmp[j][k]. + ul_config_request_body.ul_config_pdu_list = + RC.mac[i]->ul_config_pdu_list_tmp[j][k]; + RC.mac[i]->HI_DCI0_req[j]. + hi_dci0_request_body.hi_dci0_pdu_list = + RC.mac[i]->hi_dci0_pdu_list[j]; + RC.mac[i]->TX_req[j].tx_request_body.tx_pdu_list = + RC.mac[i]->tx_request_pdu[j]; + RC.mac[i]->ul_handle = 0; + } + } + + AssertFatal(rlc_module_init() == 0, + "Could not initialize RLC layer\n"); + + // These should be out of here later + pdcp_layer_init(); + + rrc_init_global_param(); + + } else { + RC.mac = NULL; } - AssertFatal(rlc_module_init()==0,"Could not initialize RLC layer\n"); - - // These should be out of here later - pdcp_layer_init (); - - rrc_init_global_param(); - - } else { - RC.mac = NULL; - } - - // Initialize Linked-List for Active UEs - for(i=0; iif_inst = IF_Module_init(i); + mac->if_inst = IF_Module_init(i); - UE_list = &mac->UE_list; + UE_list = &mac->UE_list; - UE_list->num_UEs=0; - UE_list->head=-1; - UE_list->head_ul=-1; - UE_list->avail=0; + UE_list->num_UEs = 0; + UE_list->head = -1; + UE_list->head_ul = -1; + UE_list->avail = 0; - for (list_el=0; list_elnext[list_el]=list_el+1; - UE_list->next_ul[list_el]=list_el+1; + for (list_el = 0; list_el < NUMBER_OF_UE_MAX - 1; list_el++) { + UE_list->next[list_el] = list_el + 1; + UE_list->next_ul[list_el] = list_el + 1; + } + + UE_list->next[list_el] = -1; + UE_list->next_ul[list_el] = -1; } - UE_list->next[list_el]=-1; - UE_list->next_ul[list_el]=-1; - } - } -void mac_init_cell_params(int Mod_idP,int CC_idP) { +void mac_init_cell_params(int Mod_idP, int CC_idP) +{ - int j; - RA_TEMPLATE *RA_template; - UE_TEMPLATE *UE_template; - int size_bytes1,size_bytes2,size_bits1,size_bits2; + int j; + UE_TEMPLATE *UE_template; - LOG_D(MAC,"[MAIN][eNB %d] CC_id %d initializing RA_template\n",Mod_idP, CC_idP); - LOG_D(MAC, "[MSC_NEW][FRAME 00000][MAC_eNB][MOD %02d][]\n", Mod_idP); - COMMON_channels_t *cc = &RC.mac[Mod_idP]->common_channels[CC_idP]; + LOG_D(MAC, "[MSC_NEW][FRAME 00000][MAC_eNB][MOD %02d][]\n", Mod_idP); + COMMON_channels_t *cc = &RC.mac[Mod_idP]->common_channels[CC_idP]; - RA_template = (RA_TEMPLATE *)&cc->RA_template[0]; - - for (j=0; jtdd_Config != NULL) { - switch (cc->mib->message.dl_Bandwidth) { - case MasterInformationBlock__dl_Bandwidth_n6: - size_bytes1 = sizeof(DCI1A_1_5MHz_TDD_1_6_t); - size_bytes2 = sizeof(DCI1A_1_5MHz_TDD_1_6_t); - size_bits1 = sizeof_DCI1A_1_5MHz_TDD_1_6_t; - size_bits2 = sizeof_DCI1A_1_5MHz_TDD_1_6_t; - break; - - case MasterInformationBlock__dl_Bandwidth_n25: - size_bytes1 = sizeof(DCI1A_5MHz_TDD_1_6_t); - size_bytes2 = sizeof(DCI1A_5MHz_TDD_1_6_t); - size_bits1 = sizeof_DCI1A_5MHz_TDD_1_6_t; - size_bits2 = sizeof_DCI1A_5MHz_TDD_1_6_t; - break; - - case MasterInformationBlock__dl_Bandwidth_n50: - size_bytes1 = sizeof(DCI1A_10MHz_TDD_1_6_t); - size_bytes2 = sizeof(DCI1A_10MHz_TDD_1_6_t); - size_bits1 = sizeof_DCI1A_10MHz_TDD_1_6_t; - size_bits2 = sizeof_DCI1A_10MHz_TDD_1_6_t; - break; - - case MasterInformationBlock__dl_Bandwidth_n100: - size_bytes1 = sizeof(DCI1A_20MHz_TDD_1_6_t); - size_bytes2 = sizeof(DCI1A_20MHz_TDD_1_6_t); - size_bits1 = sizeof_DCI1A_20MHz_TDD_1_6_t; - size_bits2 = sizeof_DCI1A_20MHz_TDD_1_6_t; - break; - - default: - size_bytes1 = sizeof(DCI1A_1_5MHz_TDD_1_6_t); - size_bytes2 = sizeof(DCI1A_1_5MHz_TDD_1_6_t); - size_bits1 = sizeof_DCI1A_1_5MHz_TDD_1_6_t; - size_bits2 = sizeof_DCI1A_1_5MHz_TDD_1_6_t; - break; - } - - } else { - switch (cc->mib->message.dl_Bandwidth) { - case MasterInformationBlock__dl_Bandwidth_n6: - size_bytes1 = sizeof(DCI1A_1_5MHz_FDD_t); - size_bytes2 = sizeof(DCI1A_1_5MHz_FDD_t); - size_bits1 = sizeof_DCI1A_1_5MHz_FDD_t; - size_bits2 = sizeof_DCI1A_1_5MHz_FDD_t; - break; - - case MasterInformationBlock__dl_Bandwidth_n25: - size_bytes1 = sizeof(DCI1A_5MHz_FDD_t); - size_bytes2 = sizeof(DCI1A_5MHz_FDD_t); - size_bits1 = sizeof_DCI1A_5MHz_FDD_t; - size_bits2 = sizeof_DCI1A_5MHz_FDD_t; - break; - - case MasterInformationBlock__dl_Bandwidth_n50: - size_bytes1 = sizeof(DCI1A_10MHz_FDD_t); - size_bytes2 = sizeof(DCI1A_10MHz_FDD_t); - size_bits1 = sizeof_DCI1A_10MHz_FDD_t; - size_bits2 = sizeof_DCI1A_10MHz_FDD_t; - break; - - case MasterInformationBlock__dl_Bandwidth_n100: - size_bytes1 = sizeof(DCI1A_20MHz_FDD_t); - size_bytes2 = sizeof(DCI1A_20MHz_FDD_t); - size_bits1 = sizeof_DCI1A_20MHz_FDD_t; - size_bits2 = sizeof_DCI1A_20MHz_FDD_t; - break; - - default: - size_bytes1 = sizeof(DCI1A_1_5MHz_FDD_t); - size_bytes2 = sizeof(DCI1A_1_5MHz_FDD_t); - size_bits1 = sizeof_DCI1A_1_5MHz_FDD_t; - size_bits2 = sizeof_DCI1A_1_5MHz_FDD_t; - break; - } + memset(&RC.mac[Mod_idP]->eNB_stats, 0, sizeof(eNB_STATS)); + UE_template = + (UE_TEMPLATE *) & RC.mac[Mod_idP]->UE_list.UE_template[CC_idP][0]; + + for (j = 0; j < NUMBER_OF_UE_MAX; j++) { + UE_template[j].rnti = 0; + // initiallize the eNB to UE statistics + memset(&RC.mac[Mod_idP]->UE_list.eNB_UE_stats[CC_idP][j], 0, + sizeof(eNB_UE_STATS)); } - - memcpy((void *)&RA_template[j].RA_alloc_pdu1[0],(void *)&RA_alloc_pdu,size_bytes1); - memcpy((void *)&RA_template[j].RA_alloc_pdu2[0],(void *)&DLSCH_alloc_pdu1A,size_bytes2); - RA_template[j].RA_dci_size_bytes1 = size_bytes1; - RA_template[j].RA_dci_size_bytes2 = size_bytes2; - RA_template[j].RA_dci_size_bits1 = size_bits1; - RA_template[j].RA_dci_size_bits2 = size_bits2; - - RA_template[j].RA_dci_fmt1 = format1A; - RA_template[j].RA_dci_fmt2 = format1A; - } - - memset (&RC.mac[Mod_idP]->eNB_stats,0,sizeof(eNB_STATS)); - UE_template = (UE_TEMPLATE *)&RC.mac[Mod_idP]->UE_list.UE_template[CC_idP][0]; - - for (j=0; jUE_list.eNB_UE_stats[CC_idP][j],0,sizeof(eNB_UE_STATS)); - } } @@ -300,17 +230,17 @@ int rlcmac_init_global_param(void) { - LOG_I(MAC,"[MAIN] CALLING RLC_MODULE_INIT...\n"); + LOG_I(MAC, "[MAIN] CALLING RLC_MODULE_INIT...\n"); - if (rlc_module_init()!=0) { - return(-1); - } + if (rlc_module_init() != 0) { + return (-1); + } - pdcp_layer_init (); + pdcp_layer_init(); - LOG_I(MAC,"[MAIN] Init Global Param Done\n"); + LOG_I(MAC, "[MAIN] Init Global Param Done\n"); - return 0; + return 0; } @@ -318,29 +248,31 @@ void mac_top_cleanup(void) { #ifndef USER_MODE - pdcp_module_cleanup (); + pdcp_module_cleanup(); #endif - if (NB_UE_INST>0) { - free (UE_mac_inst); - } + if (NB_UE_INST > 0) { + free(UE_mac_inst); + } - if (RC.nb_macrlc_inst>0) { - free(RC.mac); - } + if (RC.nb_macrlc_inst > 0) { + free(RC.mac); + } } -int l2_init_ue(int eMBMS_active, char *uecap_xer,uint8_t cba_group_active, uint8_t HO_active) +int +l2_init_ue(int eMBMS_active, char *uecap_xer, uint8_t cba_group_active, + uint8_t HO_active) { - LOG_I(MAC,"[MAIN] MAC_INIT_GLOBAL_PARAM IN...\n"); - // NB_NODE=2; - // NB_INST=2; + LOG_I(MAC, "[MAIN] MAC_INIT_GLOBAL_PARAM IN...\n"); + // NB_NODE=2; + // NB_INST=2; - rlcmac_init_global_param(); - LOG_I(MAC,"[MAIN] init UE MAC functions \n"); - mac_top_init_ue(eMBMS_active,uecap_xer,cba_group_active,HO_active); - return(1); + rlcmac_init_global_param(); + LOG_I(MAC, "[MAIN] init UE MAC functions \n"); + mac_top_init_ue(eMBMS_active, uecap_xer, cba_group_active, HO_active); + return (1); } int l2_init_eNB() @@ -348,13 +280,12 @@ int l2_init_eNB() - LOG_I(MAC,"[MAIN] MAC_INIT_GLOBAL_PARAM IN...\n"); + LOG_I(MAC, "[MAIN] MAC_INIT_GLOBAL_PARAM IN...\n"); - rlcmac_init_global_param(); + rlcmac_init_global_param(); - LOG_D(MAC,"[MAIN] ALL INIT OK\n"); + LOG_D(MAC, "[MAIN] ALL INIT OK\n"); - return(1); + return (1); } - diff --git a/openair2/LAYER2/MAC/openair2_proc.c b/openair2/LAYER2/MAC/openair2_proc.c deleted file mode 100644 index ab78be3c61..0000000000 --- a/openair2/LAYER2/MAC/openair2_proc.c +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/* \file openair2_proc.c - \brief MAC layer online statistics - \author Navid Nikaein - \date 2013 - 2014 - \version 1.0 - @ingroup _mac -*/ - -#ifndef USER_MODE -#include -#include -#include - -#endif -#include "LAYER2/MAC/defs.h" -#include "LAYER2/MAC/extern.h" -//#include "RRC/LITE/extern.h" -//#include "LAYER2/PDCP/pdcp.h" -#include "proto.h" - -extern RAN_CONTEXT_t RC; - -int openair2_stats_read(char *buffer, char **my_buffer, off_t off, int length) - -{ - - int len = 0,fg,Overhead, Sign; - unsigned int i,j,k,kk; - unsigned int ue_id, eNB_id; - unsigned int Mod_id = 0,CH_index; - unsigned int stat_tx_pdcp_sdu; - unsigned int stat_tx_pdcp_bytes; - unsigned int stat_tx_pdcp_sdu_discarded; - unsigned int stat_tx_pdcp_bytes_discarded; - unsigned int stat_tx_data_pdu; - unsigned int stat_tx_data_bytes; - unsigned int stat_tx_retransmit_pdu_by_status; - unsigned int stat_tx_retransmit_bytes_by_status; - unsigned int stat_tx_retransmit_pdu; - unsigned int stat_tx_retransmit_bytes; - unsigned int stat_tx_control_pdu; - unsigned int stat_tx_control_bytes; - unsigned int stat_rx_pdcp_sdu; - unsigned int stat_rx_pdcp_bytes; - unsigned int stat_rx_data_pdus_duplicate; - unsigned int stat_rx_data_bytes_duplicate; - unsigned int stat_rx_data_pdu; - unsigned int stat_rx_data_bytes; - unsigned int stat_rx_data_pdu_dropped; - unsigned int stat_rx_data_bytes_dropped; - unsigned int stat_rx_data_pdu_out_of_window; - unsigned int stat_rx_data_bytes_out_of_window; - unsigned int stat_rx_control_pdu; - unsigned int stat_rx_control_bytes; - unsigned int stat_timer_reordering_timed_out; - unsigned int stat_timer_poll_retransmit_timed_out; - unsigned int stat_timer_status_prohibit_timed_out; - - // UE part - for (ue_id=0; ue_id RRC_CONNECTED) { - case RRC_RECONFIGURED : - case RRC_CONNECTED: - case RRC_SI_RECEIVED: - case RRC_IDLE: - break; - - if (mac_get_rrc_status(ue_id,0,enb_id) > RRC_CONNECTED) { - // if (UE_mac_inst[ue_id].Dcch_lchan[CH_index].Active==1) { - len+=sprintf(&buffer[len],"eNB %d: Wideband SINR %d dB---\n", - CH_index,UE_mac_inst[Mod_id].Def_meas[CH_index].Wideband_sinr); - len+=sprintf(&buffer[len],"CH %d: Subband SINR (dB) :", - CH_index); - - for (fg=0; fg>5, - UE_mac_inst[Mod_id].Dcch_lchan[CH_index].Lchan_info.NB_RX, - UE_mac_inst[Mod_id].Dcch_lchan[CH_index].Lchan_info.NB_RX_ERRORS); - - for(i=1; i>5, - Pdcp_stats_rx[k][CH_index][i], - Pdcp_stats_rx_rate[k][CH_index][i], - (10*Pdcp_stats_rx_rate[k][CH_index][i])>>5, - Sign*(10*Overhead)>>5); - - - int status = rlc_stat_req (k, - UE_mac_inst[Mod_id].Dtch_lchan[i][CH_index].Lchan_info.Lchan_id.Index, - &stat_tx_pdcp_sdu, - &stat_tx_pdcp_bytes, - &stat_tx_pdcp_sdu_discarded, - &stat_tx_pdcp_bytes_discarded, - &stat_tx_data_pdu, - &stat_tx_data_bytes, - &stat_tx_retransmit_pdu_by_status, - &stat_tx_retransmit_bytes_by_status, - &stat_tx_retransmit_pdu, - &stat_tx_retransmit_bytes, - &stat_tx_control_pdu, - &stat_tx_control_bytes, - &stat_rx_pdcp_sdu, - &stat_rx_pdcp_bytes, - &stat_rx_data_pdus_duplicate, - &stat_rx_data_bytes_duplicate, - &stat_rx_data_pdu, - &stat_rx_data_bytes, - &stat_rx_data_pdu_dropped, - &stat_rx_data_bytes_dropped, - &stat_rx_data_pdu_out_of_window, - &stat_rx_data_bytes_out_of_window, - &stat_rx_control_pdu, - &stat_rx_control_bytes, - &stat_timer_reordering_timed_out, - &stat_timer_poll_retransmit_timed_out, - &stat_timer_status_prohibit_timed_out) ; - - if (status == RLC_OP_STATUS_OK) { - len+=sprintf(&buffer[len],"RLC LCHAN %d, NB_SDU_TO_TX = %d\tNB_SDU_DISC %d\tNB_RX_SDU %d\n", - UE_mac_inst[Mod_id].Dtch_lchan[i][CH_index].Lchan_info.Lchan_id.Index, - tx_pdcp_sdu, - tx_pdcp_sdu_discarded, - rx_sdu); - len+=sprintf(&buffer[len],"RLC LCHAN %d, NB_TB_TX_DATA = %d\tNB_TB_TX_CONTROL %d\tNB_TX_TB_RETRANS %d", - UE_mac_inst[Mod_id].Dtch_lchan[i][CH_index].Lchan_info.Lchan_id.Index, - tx_data_pdu, - tx_control_pdu, - tx_retransmit_pdu); - len+=sprintf(&buffer[len],"\tRLC LCHAN %d, NB_TX_TB_RETRANS_BY_STATUS = %d\tNB_TX_TB_RETRANS_PADD %d\n", - UE_mac_inst[Mod_id].Dtch_lchan[i][CH_index].Lchan_info.Lchan_id.Index, - tx_retransmit_pdu_by_status, - tx_retransmit_pdu_unblock); - len+=sprintf(&buffer[len],"RLC LCHAN %d, NB_RX_DATA = %d\tNB_RX_TB_OUT_WIN %d\tNB_RX_TB_CORRUPT %d\n", - UE_mac_inst[Mod_id].Dtch_lchan[i][CH_index].Lchan_info.Lchan_id.Index, - rx_data_pdu, - rx_data_pdu_out_of_window, - rx_error_pdu); - } - - len+=sprintf(&buffer[len],"[MAC]: LCHAN %d, NB_TX_MAC = %d (%d bits/TTI, %d kbits/s), NB_RX_MAC = %d (%d errors)\n", - UE_mac_inst[Mod_id].Dtch_lchan[i][CH_index].Lchan_info.Lchan_id.Index, - UE_mac_inst[Mod_id].Dtch_lchan[i][CH_index].Lchan_info.NB_TX, - UE_mac_inst[Mod_id].Dtch_lchan[i][CH_index].Lchan_info.output_rate, - (10*UE_mac_inst[Mod_id].Dtch_lchan[i][CH_index].Lchan_info.output_rate)>>5, - UE_mac_inst[Mod_id].Dtch_lchan[i][CH_index].Lchan_info.NB_RX, - UE_mac_inst[Mod_id].Dtch_lchan[i][CH_index].Lchan_info.NB_RX_ERRORS); - len+=sprintf(&buffer[len]," TX per TB: "); - - for(kk=0; kkIs_cluster_head[k] ==1) { - - Mod_id=k; - len+=sprintf(&buffer[len], - "-------------------------------------------------------------------CH %d: TTI: %d------------------------------------------------------------------\n", - NODE_ID[Mod_id],Mac_rlc_xface->frame); - - for(i=1; i<=NB_CNX_CH; i++) { - if (CH_mac_inst[Mod_id].Dcch_lchan[i].Active==1) { - len+=sprintf(&buffer[len],"\nMR index %d: DL SINR (feedback) %d dB, CQI: %s\n\n", - i,//CH_rrc_inst[Mod_id].Info.UE_list[i].L2_id[0], - CH_mac_inst[Mod_id].Def_meas[i].Wideband_sinr); - //print_cqi(CH_mac_inst[Mod_id].Def_meas[i].cqi)); - - len+=sprintf(&buffer[len], - "[MAC] LCHAN %d (DCCH), NB_TX_MAC= %d (%d bits/TTI, %d kbits/s), NB_RX_MAC= %d (errors %d, sacch errors %d, sach errors %d, sach_missing %d)\n\n", - CH_mac_inst[Mod_id].Dcch_lchan[i].Lchan_info.Lchan_id.Index, - CH_mac_inst[Mod_id].Dcch_lchan[i].Lchan_info.NB_TX, - CH_mac_inst[Mod_id].Dcch_lchan[i].Lchan_info.output_rate, - (10*CH_mac_inst[Mod_id].Dcch_lchan[i].Lchan_info.output_rate)>>5, - CH_mac_inst[Mod_id].Dcch_lchan[i].Lchan_info.NB_RX, - CH_mac_inst[Mod_id].Dcch_lchan[i].Lchan_info.NB_RX_ERRORS, - CH_mac_inst[Mod_id].Dcch_lchan[i].Lchan_info.NB_RX_SACCH_ERRORS, - CH_mac_inst[Mod_id].Dcch_lchan[i].Lchan_info.NB_RX_SACH_ERRORS, - CH_mac_inst[Mod_id].Dcch_lchan[i].Lchan_info.NB_RX_SACH_MISSING); - - for(j=0; j>5, - Pdcp_stats_rx[k][i][j], - Pdcp_stats_rx_rate[k][i][j], - (10*Pdcp_stats_rx_rate[k][i][j])>>5, - Sign*(10*Overhead)>>5); - int status = rlc_stat_req (k, - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.Lchan_id.Index, - &tx_pdcp_sdu, - &tx_pdcp_sdu_discarded, - &tx_retransmit_pdu_unblock, - &tx_retransmit_pdu_by_status, - &tx_retransmit_pdu, - &tx_data_pdu, - &tx_control_pdu, - &rx_sdu, - &rx_error_pdu, - &rx_data_pdu, - &rx_data_pdu_out_of_window, - &rx_control_pdu) ; - /* - if (status == RLC_OP_STATUS_OK) { - len+=sprintf(&buffer[len],"\t[RLC] LCHAN %d, NB_SDU_TO_TX = %d\tNB_SDU_DISC %d\tNB_RX_SDU %d\n", - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.Lchan_id.Index, - tx_pdcp_sdu, - tx_pdcp_sdu_discarded, - rx_sdu); - len+=sprintf(&buffer[len],"\t[RLC] LCHAN %d, NB_TB_TX_DATA = %d\tNB_TB_TX_CONTROL %d\tNB_TX_TB_RETRANS %\n", - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.Lchan_id.Index, - tx_data_pdu, - tx_control_pdu, - tx_retransmit_pdu); - len+=sprintf(&buffer[len],"\t[RLC] LCHAN %d, NB_TX_TB_RETRANS_BY_STATUS = %d\tNB_TX_TB_RETRANS_PADD %d\n", - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.Lchan_id.Index, - tx_retransmit_pdu_by_status, - tx_retransmit_pdu_unblock); - len+=sprintf(&buffer[len],"\t[RLC] LCHAN %d, NB_RX_DATA = %d\tNB_RX_TB_OUT_WIN %d\tNB_RX_TB_CORRUPT %d\n", - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.Lchan_id.Index, - rx_data_pdu, - rx_data_pdu_out_of_window, - rx_error_pdu); - } - */ - len+=sprintf(&buffer[len], - "[MAC]LCHAN %d (CNX %d,RAB %d), NB_TX_MAC= %d (%d bits/TTI, %d kbit/s), NB_RX_MAC= %d (errors %d, sacch_errors %d, sach_errors %d, sach_missing %d)\n", - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.Lchan_id.Index, - i,j, - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.NB_TX, - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.output_rate, - (10*CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.output_rate)>>5, - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.NB_RX, - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.NB_RX_ERRORS, - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.NB_RX_SACCH_ERRORS, - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.NB_RX_SACH_ERRORS, - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.NB_RX_SACH_MISSING); - len+=sprintf(&buffer[len],"[MAC][SCHEDULER] TX Arrival Rate %d, TX Service Rate %d, RX Arrival rate %d, RX Service rate %d, NB_BW_REQ_RX %d\n\n", - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.Arrival_rate, - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.Tx_rate, - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.Req_rate, - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.Rx_rate, - CH_mac_inst[Mod_id].Dtch_lchan[j][i].Lchan_info.NB_BW_REQ_RX); - - /* - len+=sprintf(&buffer[len]," TX per TB: "); - for(kk=0;kkUE_list; - UE_TEMPLATE *UE_template; + int UE_id, i; + rnti_t rnti; + mac_rlc_status_resp_t rlc_status; + UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list; + UE_TEMPLATE *UE_template; - for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { - if (UE_list->active[UE_id] != TRUE) continue; + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { + if (UE_list->active[UE_id] != TRUE) + continue; - UE_template = &UE_list->UE_template[UE_PCCID(Mod_id,UE_id)][UE_id]; + UE_template = + &UE_list->UE_template[UE_PCCID(Mod_id, UE_id)][UE_id]; - // clear logical channel interface variables - UE_template->dl_buffer_total = 0; - UE_template->dl_pdus_total = 0; + // clear logical channel interface variables + UE_template->dl_buffer_total = 0; + UE_template->dl_pdus_total = 0; - for(i=0; i< MAX_NUM_LCID; i++) { - UE_template->dl_buffer_info[i]=0; - UE_template->dl_pdus_in_buffer[i]=0; - UE_template->dl_buffer_head_sdu_creation_time[i]=0; - UE_template->dl_buffer_head_sdu_remaining_size_to_send[i]=0; - } + for (i = 0; i < MAX_NUM_LCID; i++) { + UE_template->dl_buffer_info[i] = 0; + UE_template->dl_pdus_in_buffer[i] = 0; + UE_template->dl_buffer_head_sdu_creation_time[i] = 0; + UE_template->dl_buffer_head_sdu_remaining_size_to_send[i] = 0; + } - rnti = UE_RNTI(Mod_id,UE_id); + rnti = UE_RNTI(Mod_id, UE_id); - for(i=0; i< MAX_NUM_LCID; i++) { // loop over all the logical channels + for (i = 0; i < MAX_NUM_LCID; i++) { // loop over all the logical channels - rlc_status = mac_rlc_status_ind(Mod_id,rnti, Mod_id,frameP,subframeP,ENB_FLAG_YES,MBMS_FLAG_NO,i,0 ); - UE_template->dl_buffer_info[i] = rlc_status.bytes_in_buffer; //storing the dlsch buffer for each logical channel - UE_template->dl_pdus_in_buffer[i] = rlc_status.pdus_in_buffer; - UE_template->dl_buffer_head_sdu_creation_time[i] = rlc_status.head_sdu_creation_time ; - UE_template->dl_buffer_head_sdu_creation_time_max = cmax(UE_template->dl_buffer_head_sdu_creation_time_max, - rlc_status.head_sdu_creation_time ); - UE_template->dl_buffer_head_sdu_remaining_size_to_send[i] = rlc_status.head_sdu_remaining_size_to_send; - UE_template->dl_buffer_head_sdu_is_segmented[i] = rlc_status.head_sdu_is_segmented; - UE_template->dl_buffer_total += UE_template->dl_buffer_info[i];//storing the total dlsch buffer - UE_template->dl_pdus_total += UE_template->dl_pdus_in_buffer[i]; + rlc_status = + mac_rlc_status_ind(Mod_id, rnti, Mod_id, frameP, subframeP, + ENB_FLAG_YES, MBMS_FLAG_NO, i, 0); + UE_template->dl_buffer_info[i] = rlc_status.bytes_in_buffer; //storing the dlsch buffer for each logical channel + UE_template->dl_pdus_in_buffer[i] = rlc_status.pdus_in_buffer; + UE_template->dl_buffer_head_sdu_creation_time[i] = + rlc_status.head_sdu_creation_time; + UE_template->dl_buffer_head_sdu_creation_time_max = + cmax(UE_template->dl_buffer_head_sdu_creation_time_max, + rlc_status.head_sdu_creation_time); + UE_template->dl_buffer_head_sdu_remaining_size_to_send[i] = + rlc_status.head_sdu_remaining_size_to_send; + UE_template->dl_buffer_head_sdu_is_segmented[i] = + rlc_status.head_sdu_is_segmented; + UE_template->dl_buffer_total += UE_template->dl_buffer_info[i]; //storing the total dlsch buffer + UE_template->dl_pdus_total += + UE_template->dl_pdus_in_buffer[i]; #ifdef DEBUG_eNB_SCHEDULER - /* note for dl_buffer_head_sdu_remaining_size_to_send[i] : - * 0 if head SDU has not been segmented (yet), else remaining size not already segmented and sent - */ - if (UE_template->dl_buffer_info[i]>0) - LOG_D(MAC, - "[eNB %d] Frame %d Subframe %d : RLC status for UE %d in LCID%d: total of %d pdus and size %d, head sdu queuing time %d, remaining size %d, is segmeneted %d \n", - Mod_id, frameP, subframeP, UE_id, - i, UE_template->dl_pdus_in_buffer[i],UE_template->dl_buffer_info[i], - UE_template->dl_buffer_head_sdu_creation_time[i], - UE_template->dl_buffer_head_sdu_remaining_size_to_send[i], - UE_template->dl_buffer_head_sdu_is_segmented[i] - ); + /* note for dl_buffer_head_sdu_remaining_size_to_send[i] : + * 0 if head SDU has not been segmented (yet), else remaining size not already segmented and sent + */ + if (UE_template->dl_buffer_info[i] > 0) + LOG_D(MAC, + "[eNB %d] Frame %d Subframe %d : RLC status for UE %d in LCID%d: total of %d pdus and size %d, head sdu queuing time %d, remaining size %d, is segmeneted %d \n", + Mod_id, frameP, subframeP, UE_id, + i, UE_template->dl_pdus_in_buffer[i], + UE_template->dl_buffer_info[i], + UE_template->dl_buffer_head_sdu_creation_time[i], + UE_template-> + dl_buffer_head_sdu_remaining_size_to_send[i], + UE_template->dl_buffer_head_sdu_is_segmented[i]); #endif + } + + //#ifdef DEBUG_eNB_SCHEDULER + if (UE_template->dl_buffer_total > 0) + LOG_D(MAC, + "[eNB %d] Frame %d Subframe %d : RLC status for UE %d : total DL buffer size %d and total number of pdu %d \n", + Mod_id, frameP, subframeP, UE_id, + UE_template->dl_buffer_total, + UE_template->dl_pdus_total); + + //#endif } - - //#ifdef DEBUG_eNB_SCHEDULER - if ( UE_template->dl_buffer_total>0) - LOG_D(MAC,"[eNB %d] Frame %d Subframe %d : RLC status for UE %d : total DL buffer size %d and total number of pdu %d \n", - Mod_id, frameP, subframeP, UE_id, - UE_template->dl_buffer_total, - UE_template->dl_pdus_total - ); - - //#endif - } } // This function returns the estimated number of RBs required by each UE for downlink scheduling -void assign_rbs_required (module_id_t Mod_id, - frame_t frameP, - sub_frame_t subframe, - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - int min_rb_unit[MAX_NUM_CCs]) +void +assign_rbs_required(module_id_t Mod_id, + frame_t frameP, + sub_frame_t subframe, + uint16_t + nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], + int min_rb_unit[MAX_NUM_CCs]) { - uint16_t TBS = 0; + uint16_t TBS = 0; - int UE_id,n,i,j,CC_id,pCCid,tmp; - UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list; - eNB_UE_STATS *eNB_UE_stats,*eNB_UE_stats_i,*eNB_UE_stats_j; - int N_RB_DL; + int UE_id, n, i, j, CC_id, pCCid, tmp; + UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list; + eNB_UE_STATS *eNB_UE_stats, *eNB_UE_stats_i, *eNB_UE_stats_j; + int N_RB_DL; - // clear rb allocations across all CC_id - for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { - if (UE_list->active[UE_id] != TRUE) continue; + // clear rb allocations across all CC_id + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { + if (UE_list->active[UE_id] != TRUE) + continue; - pCCid = UE_PCCID(Mod_id,UE_id); + pCCid = UE_PCCID(Mod_id, UE_id); - //update CQI information across component carriers - for (n=0; nnumactiveCCs[UE_id]; n++) { + //update CQI information across component carriers + for (n = 0; n < UE_list->numactiveCCs[UE_id]; n++) { - CC_id = UE_list->ordered_CCids[n][UE_id]; - eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; + CC_id = UE_list->ordered_CCids[n][UE_id]; + eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; - eNB_UE_stats->dlsch_mcs1=cqi_to_mcs[UE_list->UE_sched_ctrl[UE_id].dl_cqi[CC_id]]; + eNB_UE_stats->dlsch_mcs1 = + cqi_to_mcs[UE_list->UE_sched_ctrl[UE_id].dl_cqi[CC_id]]; + } + + // provide the list of CCs sorted according to MCS + for (i = 0; i < UE_list->numactiveCCs[UE_id]; i++) { + eNB_UE_stats_i = + &UE_list->eNB_UE_stats[UE_list-> + ordered_CCids[i][UE_id]][UE_id]; + for (j = i + 1; j < UE_list->numactiveCCs[UE_id]; j++) { + DevAssert(j < MAX_NUM_CCs); + eNB_UE_stats_j = + &UE_list-> + eNB_UE_stats[UE_list->ordered_CCids[j][UE_id]][UE_id]; + if (eNB_UE_stats_j->dlsch_mcs1 > + eNB_UE_stats_i->dlsch_mcs1) { + tmp = UE_list->ordered_CCids[i][UE_id]; + UE_list->ordered_CCids[i][UE_id] = + UE_list->ordered_CCids[j][UE_id]; + UE_list->ordered_CCids[j][UE_id] = tmp; + } + } + } + + if (UE_list->UE_template[pCCid][UE_id].dl_buffer_total > 0) { + LOG_D(MAC, "[preprocessor] assign RB for UE %d\n", UE_id); + + for (i = 0; i < UE_list->numactiveCCs[UE_id]; i++) { + CC_id = UE_list->ordered_CCids[i][UE_id]; + eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; + + if (eNB_UE_stats->dlsch_mcs1 == 0) { + nb_rbs_required[CC_id][UE_id] = 4; // don't let the TBS get too small + } else { + nb_rbs_required[CC_id][UE_id] = min_rb_unit[CC_id]; + } + + TBS = + get_TBS_DL(eNB_UE_stats->dlsch_mcs1, + nb_rbs_required[CC_id][UE_id]); + + LOG_D(MAC, + "[preprocessor] start RB assignement for UE %d CC_id %d dl buffer %d (RB unit %d, MCS %d, TBS %d) \n", + UE_id, CC_id, + UE_list->UE_template[pCCid][UE_id].dl_buffer_total, + nb_rbs_required[CC_id][UE_id], + eNB_UE_stats->dlsch_mcs1, TBS); + + N_RB_DL = + to_prb(RC.mac[Mod_id]->common_channels[CC_id]. + mib->message.dl_Bandwidth); + + /* calculating required number of RBs for each UE */ + while (TBS < + UE_list->UE_template[pCCid][UE_id]. + dl_buffer_total) { + nb_rbs_required[CC_id][UE_id] += min_rb_unit[CC_id]; + + if (nb_rbs_required[CC_id][UE_id] > N_RB_DL) { + TBS = + get_TBS_DL(eNB_UE_stats->dlsch_mcs1, N_RB_DL); + nb_rbs_required[CC_id][UE_id] = N_RB_DL; + break; + } + + TBS = + get_TBS_DL(eNB_UE_stats->dlsch_mcs1, + nb_rbs_required[CC_id][UE_id]); + } // end of while + + LOG_D(MAC, + "[eNB %d] Frame %d: UE %d on CC %d: RB unit %d, nb_required RB %d (TBS %d, mcs %d)\n", + Mod_id, frameP, UE_id, CC_id, min_rb_unit[CC_id], + nb_rbs_required[CC_id][UE_id], TBS, + eNB_UE_stats->dlsch_mcs1); + } + } } - - // provide the list of CCs sorted according to MCS - for (i=0; inumactiveCCs[UE_id]; i++) { - eNB_UE_stats_i = &UE_list->eNB_UE_stats[UE_list->ordered_CCids[i][UE_id]][UE_id]; - for (j=i+1; jnumactiveCCs[UE_id]; j++) { - DevAssert( j < MAX_NUM_CCs ); - eNB_UE_stats_j = &UE_list->eNB_UE_stats[UE_list->ordered_CCids[j][UE_id]][UE_id]; - if (eNB_UE_stats_j->dlsch_mcs1 > - eNB_UE_stats_i->dlsch_mcs1) { - tmp = UE_list->ordered_CCids[i][UE_id]; - UE_list->ordered_CCids[i][UE_id] = UE_list->ordered_CCids[j][UE_id]; - UE_list->ordered_CCids[j][UE_id] = tmp; - } - } - } - - if (UE_list->UE_template[pCCid][UE_id].dl_buffer_total> 0) { - LOG_D(MAC,"[preprocessor] assign RB for UE %d\n",UE_id); - - for (i=0; inumactiveCCs[UE_id]; i++) { - CC_id = UE_list->ordered_CCids[i][UE_id]; - eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; - - if (eNB_UE_stats->dlsch_mcs1==0) { - nb_rbs_required[CC_id][UE_id] = 4; // don't let the TBS get too small - } else { - nb_rbs_required[CC_id][UE_id] = min_rb_unit[CC_id]; - } - - TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_rbs_required[CC_id][UE_id]); - - LOG_D(MAC,"[preprocessor] start RB assignement for UE %d CC_id %d dl buffer %d (RB unit %d, MCS %d, TBS %d) \n", - UE_id, CC_id, UE_list->UE_template[pCCid][UE_id].dl_buffer_total, - nb_rbs_required[CC_id][UE_id],eNB_UE_stats->dlsch_mcs1,TBS); - - N_RB_DL = to_prb(RC.mac[Mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth); - - /* calculating required number of RBs for each UE */ - while (TBS < UE_list->UE_template[pCCid][UE_id].dl_buffer_total) { - nb_rbs_required[CC_id][UE_id] += min_rb_unit[CC_id]; - - if (nb_rbs_required[CC_id][UE_id] > N_RB_DL) { - TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1,N_RB_DL); - nb_rbs_required[CC_id][UE_id] = N_RB_DL; - break; - } - - TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_rbs_required[CC_id][UE_id]); - } // end of while - - LOG_D(MAC,"[eNB %d] Frame %d: UE %d on CC %d: RB unit %d, nb_required RB %d (TBS %d, mcs %d)\n", - Mod_id, frameP,UE_id, CC_id, min_rb_unit[CC_id], nb_rbs_required[CC_id][UE_id], TBS, eNB_UE_stats->dlsch_mcs1); - } - } - } } // This function scans all CC_ids for a particular UE to find the maximum round index of its HARQ processes -int maxround(module_id_t Mod_id,uint16_t rnti,int frame,sub_frame_t subframe,uint8_t ul_flag ) +int +maxround(module_id_t Mod_id, uint16_t rnti, int frame, + sub_frame_t subframe, uint8_t ul_flag) { - uint8_t round,round_max=0,UE_id; - int CC_id,harq_pid; - UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list; - COMMON_channels_t *cc; + uint8_t round, round_max = 0, UE_id; + int CC_id, harq_pid; + UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list; + COMMON_channels_t *cc; - for (CC_id=0; CC_idcommon_channels[CC_id]; + cc = &RC.mac[Mod_id]->common_channels[CC_id]; - UE_id = find_UE_id(Mod_id,rnti); - if (cc->tdd_Config) harq_pid = ((frame*10)+subframe)%10; - else harq_pid = ((frame*10)+subframe)&7; + UE_id = find_UE_id(Mod_id, rnti); + if (cc->tdd_Config) + harq_pid = ((frame * 10) + subframe) % 10; + else + harq_pid = ((frame * 10) + subframe) & 7; - round = UE_list->UE_sched_ctrl[UE_id].round[CC_id][harq_pid]; - if (round > round_max) { - round_max = round; + round = UE_list->UE_sched_ctrl[UE_id].round[CC_id][harq_pid]; + if (round > round_max) { + round_max = round; + } } - } - return round_max; + return round_max; } // This function scans all CC_ids for a particular UE to find the maximum DL CQI // it returns -1 if the UE is not found in PHY layer (get_eNB_UE_stats gives NULL) -int maxcqi(module_id_t Mod_id,int32_t UE_id) +int maxcqi(module_id_t Mod_id, int32_t UE_id) { - UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list; - int CC_id,n; - int CQI = 0; + UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list; + int CC_id, n; + int CQI = 0; - for (n=0; nnumactiveCCs[UE_id]; n++) { - CC_id = UE_list->ordered_CCids[n][UE_id]; + for (n = 0; n < UE_list->numactiveCCs[UE_id]; n++) { + CC_id = UE_list->ordered_CCids[n][UE_id]; - if (UE_list->UE_sched_ctrl[UE_id].dl_cqi[CC_id] > CQI) { - CQI = UE_list->UE_sched_ctrl[UE_id].dl_cqi[CC_id]; + if (UE_list->UE_sched_ctrl[UE_id].dl_cqi[CC_id] > CQI) { + CQI = UE_list->UE_sched_ctrl[UE_id].dl_cqi[CC_id]; + } } - } - return CQI; + return CQI; } struct sort_ue_dl_params { - int Mod_idP; - int frameP; - int subframeP; + int Mod_idP; + int frameP; + int subframeP; }; static int ue_dl_compare(const void *_a, const void *_b, void *_params) { - struct sort_ue_dl_params *params = _params; - UE_list_t *UE_list = &RC.mac[params->Mod_idP]->UE_list; + struct sort_ue_dl_params *params = _params; + UE_list_t *UE_list = &RC.mac[params->Mod_idP]->UE_list; - int UE_id1 = *(const int *)_a; - int UE_id2 = *(const int *)_b; + int UE_id1 = *(const int *) _a; + int UE_id2 = *(const int *) _b; - int rnti1 = UE_RNTI(params->Mod_idP, UE_id1); - int pCC_id1 = UE_PCCID(params->Mod_idP, UE_id1); - int round1 = maxround(params->Mod_idP, rnti1, params->frameP, params->subframeP, 1); + int rnti1 = UE_RNTI(params->Mod_idP, UE_id1); + int pCC_id1 = UE_PCCID(params->Mod_idP, UE_id1); + int round1 = + maxround(params->Mod_idP, rnti1, params->frameP, params->subframeP, + 1); - int rnti2 = UE_RNTI(params->Mod_idP, UE_id2); - int pCC_id2 = UE_PCCID(params->Mod_idP, UE_id2); - int round2 = maxround(params->Mod_idP, rnti2, params->frameP, params->subframeP, 1); + int rnti2 = UE_RNTI(params->Mod_idP, UE_id2); + int pCC_id2 = UE_PCCID(params->Mod_idP, UE_id2); + int round2 = + maxround(params->Mod_idP, rnti2, params->frameP, params->subframeP, + 1); - int cqi1 = maxcqi(params->Mod_idP, UE_id1); - int cqi2 = maxcqi(params->Mod_idP, UE_id2); + int cqi1 = maxcqi(params->Mod_idP, UE_id1); + int cqi2 = maxcqi(params->Mod_idP, UE_id2); - if (round1 > round2) return -1; - if (round1 < round2) return 1; + if (round1 > round2) + return -1; + if (round1 < round2) + return 1; - if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[1] + UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[2] > - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[1] + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[2]) - return -1; - if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[1] + UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[2] < - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[1] + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[2]) - return 1; + if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[1] + + UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[2] > + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[1] + + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[2]) + return -1; + if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[1] + + UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[2] < + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[1] + + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[2]) + return 1; - if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_head_sdu_creation_time_max > - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_head_sdu_creation_time_max) - return -1; - if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_head_sdu_creation_time_max < - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_head_sdu_creation_time_max) - return 1; + if (UE_list-> + UE_template[pCC_id1][UE_id1].dl_buffer_head_sdu_creation_time_max > + UE_list-> + UE_template[pCC_id2][UE_id2].dl_buffer_head_sdu_creation_time_max) + return -1; + if (UE_list-> + UE_template[pCC_id1][UE_id1].dl_buffer_head_sdu_creation_time_max < + UE_list-> + UE_template[pCC_id2][UE_id2].dl_buffer_head_sdu_creation_time_max) + return 1; - if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_total > - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_total) - return -1; - if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_total < - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_total) - return 1; + if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_total > + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_total) + return -1; + if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_total < + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_total) + return 1; - if (cqi1 > cqi2) return -1; - if (cqi1 < cqi2) return 1; + if (cqi1 > cqi2) + return -1; + if (cqi1 < cqi2) + return 1; - return 0; + return 0; #if 0 - /* The above order derives from the following. */ - if(round2 > round1) { // Check first if one of the UEs has an active HARQ process which needs service and swap order - swap_UEs(UE_list,UE_id1,UE_id2,0); - } else if (round2 == round1) { - // RK->NN : I guess this is for fairness in the scheduling. This doesn't make sense unless all UEs have the same configuration of logical channels. This should be done on the sum of all information that has to be sent. And still it wouldn't ensure fairness. It should be based on throughput seen by each UE or maybe using the head_sdu_creation_time, i.e. swap UEs if one is waiting longer for service. - // for(j=0;j round1) { // Check first if one of the UEs has an active HARQ process which needs service and swap order + swap_UEs(UE_list, UE_id1, UE_id2, 0); + } else if (round2 == round1) { + // RK->NN : I guess this is for fairness in the scheduling. This doesn't make sense unless all UEs have the same configuration of logical channels. This should be done on the sum of all information that has to be sent. And still it wouldn't ensure fairness. It should be based on throughput seen by each UE or maybe using the head_sdu_creation_time, i.e. swap UEs if one is waiting longer for service. + // for(j=0;jUE_template[pCC_id1][UE_id1].dl_buffer_info[1] + UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[2]) < - (UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[1] + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[2]) ) { - swap_UEs(UE_list,UE_id1,UE_id2,0); - } else if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_head_sdu_creation_time_max < - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_head_sdu_creation_time_max ) { - swap_UEs(UE_list,UE_id1,UE_id2,0); - } else if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_total < - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_total ) { - swap_UEs(UE_list,UE_id1,UE_id2,0); - } else if (cqi1 < cqi2) { - swap_UEs(UE_list,UE_id1,UE_id2,0); - } - } + if ((UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[1] + + UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[2]) < + (UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[1] + + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[2])) { + swap_UEs(UE_list, UE_id1, UE_id2, 0); + } else if (UE_list->UE_template[pCC_id1] + [UE_id1].dl_buffer_head_sdu_creation_time_max < + UE_list->UE_template[pCC_id2] + [UE_id2].dl_buffer_head_sdu_creation_time_max) { + swap_UEs(UE_list, UE_id1, UE_id2, 0); + } else if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_total < + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_total) { + swap_UEs(UE_list, UE_id1, UE_id2, 0); + } else if (cqi1 < cqi2) { + swap_UEs(UE_list, UE_id1, UE_id2, 0); + } + } #endif } // This fuction sorts the UE in order their dlsch buffer and CQI -void sort_UEs (module_id_t Mod_idP, - int frameP, - sub_frame_t subframeP) +void sort_UEs(module_id_t Mod_idP, int frameP, sub_frame_t subframeP) { - int i; - int list[NUMBER_OF_UE_MAX]; - int list_size = 0; - int rnti; - struct sort_ue_dl_params params = { Mod_idP, frameP, subframeP }; + int i; + int list[NUMBER_OF_UE_MAX]; + int list_size = 0; + int rnti; + struct sort_ue_dl_params params = { Mod_idP, frameP, subframeP }; - UE_list_t *UE_list = &RC.mac[Mod_idP]->UE_list; + UE_list_t *UE_list = &RC.mac[Mod_idP]->UE_list; - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i]==FALSE) continue; - if ((rnti = UE_RNTI(Mod_idP, i)) == NOT_A_RNTI) continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) continue; + if (UE_list->active[i] == FALSE) + continue; + if ((rnti = UE_RNTI(Mod_idP, i)) == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; - list[list_size] = i; - list_size++; - } + list[list_size] = i; + list_size++; + } - qsort_r(list, list_size, sizeof(int), ue_dl_compare, ¶ms); + qsort_r(list, list_size, sizeof(int), ue_dl_compare, ¶ms); - if (list_size) { - for (i = 0; i < list_size-1; i++) - UE_list->next[list[i]] = list[i+1]; - UE_list->next[list[list_size-1]] = -1; - UE_list->head = list[0]; - } else { - UE_list->head = -1; - } + if (list_size) { + for (i = 0; i < list_size - 1; i++) + UE_list->next[list[i]] = list[i + 1]; + UE_list->next[list[list_size - 1]] = -1; + UE_list->head = list[0]; + } else { + UE_list->head = -1; + } #if 0 - int UE_id1,UE_id2; - int pCC_id1,pCC_id2; - int cqi1,cqi2,round1,round2; - int i=0,ii=0;//,j=0; - rnti_t rnti1,rnti2; + int UE_id1, UE_id2; + int pCC_id1, pCC_id2; + int cqi1, cqi2, round1, round2; + int i = 0, ii = 0; //,j=0; + rnti_t rnti1, rnti2; - UE_list_t *UE_list = &RC.mac[Mod_idP]->UE_list; + UE_list_t *UE_list = &RC.mac[Mod_idP]->UE_list; - for (i=UE_list->head; i>=0; i=UE_list->next[i]) { + for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { - for(ii=UE_list->next[i]; ii>=0; ii=UE_list->next[ii]) { + for (ii = UE_list->next[i]; ii >= 0; ii = UE_list->next[ii]) { - UE_id1 = i; - rnti1 = UE_RNTI(Mod_idP,UE_id1); - if(rnti1 == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[UE_id1].ul_out_of_sync == 1) - continue; - pCC_id1 = UE_PCCID(Mod_idP,UE_id1); - cqi1 = maxcqi(Mod_idP,UE_id1); // - round1 = maxround(Mod_idP,rnti1,frameP,subframeP,0); + UE_id1 = i; + rnti1 = UE_RNTI(Mod_idP, UE_id1); + if (rnti1 == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[UE_id1].ul_out_of_sync == 1) + continue; + pCC_id1 = UE_PCCID(Mod_idP, UE_id1); + cqi1 = maxcqi(Mod_idP, UE_id1); // + round1 = maxround(Mod_idP, rnti1, frameP, subframeP, 0); - UE_id2 = ii; - rnti2 = UE_RNTI(Mod_idP,UE_id2); - if(rnti2 == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[UE_id2].ul_out_of_sync == 1) - continue; - cqi2 = maxcqi(Mod_idP,UE_id2); - round2 = maxround(Mod_idP,rnti2,frameP,subframeP,0); //mac_xface->get_ue_active_harq_pid(Mod_id,rnti2,subframe,&harq_pid2,&round2,0); - pCC_id2 = UE_PCCID(Mod_idP,UE_id2); + UE_id2 = ii; + rnti2 = UE_RNTI(Mod_idP, UE_id2); + if (rnti2 == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[UE_id2].ul_out_of_sync == 1) + continue; + cqi2 = maxcqi(Mod_idP, UE_id2); + round2 = maxround(Mod_idP, rnti2, frameP, subframeP, 0); //mac_xface->get_ue_active_harq_pid(Mod_id,rnti2,subframe,&harq_pid2,&round2,0); + pCC_id2 = UE_PCCID(Mod_idP, UE_id2); - if(round2 > round1) { // Check first if one of the UEs has an active HARQ process which needs service and swap order - swap_UEs(UE_list,UE_id1,UE_id2,0); - } else if (round2 == round1) { - // RK->NN : I guess this is for fairness in the scheduling. This doesn't make sense unless all UEs have the same configuration of logical channels. This should be done on the sum of all information that has to be sent. And still it wouldn't ensure fairness. It should be based on throughput seen by each UE or maybe using the head_sdu_creation_time, i.e. swap UEs if one is waiting longer for service. - // for(j=0;j round1) { // Check first if one of the UEs has an active HARQ process which needs service and swap order + swap_UEs(UE_list, UE_id1, UE_id2, 0); + } else if (round2 == round1) { + // RK->NN : I guess this is for fairness in the scheduling. This doesn't make sense unless all UEs have the same configuration of logical channels. This should be done on the sum of all information that has to be sent. And still it wouldn't ensure fairness. It should be based on throughput seen by each UE or maybe using the head_sdu_creation_time, i.e. swap UEs if one is waiting longer for service. + // for(j=0;jUE_template[pCC_id1][UE_id1].dl_buffer_info[1] + UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[2]) < - (UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[1] + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[2]) ) { - swap_UEs(UE_list,UE_id1,UE_id2,0); - } else if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_head_sdu_creation_time_max < - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_head_sdu_creation_time_max ) { - swap_UEs(UE_list,UE_id1,UE_id2,0); - } else if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_total < - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_total ) { - swap_UEs(UE_list,UE_id1,UE_id2,0); - } else if (cqi1 < cqi2) { - swap_UEs(UE_list,UE_id1,UE_id2,0); - } - } + if ((UE_list->UE_template[pCC_id1][UE_id1]. + dl_buffer_info[1] + + UE_list->UE_template[pCC_id1][UE_id1]. + dl_buffer_info[2]) < + (UE_list->UE_template[pCC_id2][UE_id2]. + dl_buffer_info[1] + + UE_list->UE_template[pCC_id2][UE_id2]. + dl_buffer_info[2])) { + swap_UEs(UE_list, UE_id1, UE_id2, 0); + } else if (UE_list->UE_template[pCC_id1] + [UE_id1].dl_buffer_head_sdu_creation_time_max < + UE_list->UE_template[pCC_id2] + [UE_id2].dl_buffer_head_sdu_creation_time_max) { + swap_UEs(UE_list, UE_id1, UE_id2, 0); + } else if (UE_list->UE_template[pCC_id1][UE_id1]. + dl_buffer_total < + UE_list->UE_template[pCC_id2][UE_id2]. + dl_buffer_total) { + swap_UEs(UE_list, UE_id1, UE_id2, 0); + } else if (cqi1 < cqi2) { + swap_UEs(UE_list, UE_id1, UE_id2, 0); + } + } + } } - } #endif } @@ -485,1050 +554,1297 @@ void sort_UEs (module_id_t Mod_idP, // This function assigns pre-available RBS to each UE in specified sub-bands before scheduling is done -void dlsch_scheduler_pre_processor (module_id_t Mod_id, - frame_t frameP, - sub_frame_t subframeP, - int N_RBG[MAX_NUM_CCs], - int *mbsfn_flag) +void +dlsch_scheduler_pre_processor(module_id_t Mod_id, + frame_t frameP, + sub_frame_t subframeP, + int N_RBG[MAX_NUM_CCs], int *mbsfn_flag) { - unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX],harq_pid=0,round=0,total_ue_count; - unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]; - int UE_id, i; - uint16_t ii,j; - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - uint16_t nb_rbs_required_remaining_1[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - uint16_t average_rbs_per_user[MAX_NUM_CCs] = {0}; - rnti_t rnti; - int min_rb_unit[MAX_NUM_CCs]; - uint16_t r1=0; - uint8_t CC_id; - UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list; + unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], harq_pid = + 0, round = 0, total_ue_count; + unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]; + int UE_id, i; + uint16_t ii, j; + uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + uint16_t nb_rbs_required_remaining_1[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + uint16_t average_rbs_per_user[MAX_NUM_CCs] = { 0 }; + rnti_t rnti; + int min_rb_unit[MAX_NUM_CCs]; + uint16_t r1 = 0; + uint8_t CC_id; + UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list; - int N_RB_DL; - int transmission_mode = 0; - UE_sched_ctrl *ue_sched_ctl; - // int rrc_status = RRC_IDLE; - COMMON_channels_t *cc; + int N_RB_DL; + int transmission_mode = 0; + UE_sched_ctrl *ue_sched_ctl; + // int rrc_status = RRC_IDLE; + COMMON_channels_t *cc; #ifdef TM5 - int harq_pid1=0; - int round1=0,round2=0; - int UE_id2; - uint16_t i1,i2,i3; - rnti_t rnti1,rnti2; - LTE_eNB_UE_stats *eNB_UE_stats1 = NULL; - LTE_eNB_UE_stats *eNB_UE_stats2 = NULL; - UE_sched_ctrl *ue_sched_ctl1,*ue_sched_ctl2; + int harq_pid1 = 0; + int round1 = 0, round2 = 0; + int UE_id2; + uint16_t i1, i2, i3; + rnti_t rnti1, rnti2; + LTE_eNB_UE_stats *eNB_UE_stats1 = NULL; + LTE_eNB_UE_stats *eNB_UE_stats2 = NULL; + UE_sched_ctrl *ue_sched_ctl1, *ue_sched_ctl2; #endif - for (CC_id=0; CC_id0) // If this CC is allocated for MBSFN skip it here - continue; - - - - min_rb_unit[CC_id]=get_min_rb_unit(Mod_id,CC_id); - - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i] != TRUE) continue; - - UE_id = i; - // Initialize scheduling information for all active UEs - - - - dlsch_scheduler_pre_processor_reset(Mod_id, - UE_id, - CC_id, - frameP, - subframeP, - N_RBG[CC_id], - nb_rbs_required, - nb_rbs_required_remaining, - rballoc_sub, - MIMO_mode_indicator); - - } - } - - - // Store the DLSCH buffer for each logical channel - store_dlsch_buffer (Mod_id,frameP,subframeP); - - - - // Calculate the number of RBs required by each UE on the basis of logical channel's buffer - assign_rbs_required (Mod_id,frameP,subframeP,nb_rbs_required,min_rb_unit); - - - - // Sorts the user on the basis of dlsch logical channel buffer and CQI - sort_UEs (Mod_id,frameP,subframeP); - - - - total_ue_count =0; - - // loop over all active UEs - for (i=UE_list->head; i>=0; i=UE_list->next[i]) { - rnti = UE_RNTI(Mod_id,i); - - if(rnti == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - UE_id = i; - - for (ii=0; iiordered_CCids[ii][UE_id]; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - cc=&RC.mac[Mod_id]->common_channels[ii]; - if (cc->tdd_Config) harq_pid = ((frameP*10)+subframeP)%10; - else harq_pid = ((frameP*10)+subframeP)&7; - round = ue_sched_ctl->round[CC_id][harq_pid]; - - average_rbs_per_user[CC_id]=0; - - - if(round != 8) { - nb_rbs_required[CC_id][UE_id] = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - } - - //nb_rbs_required_remaining[UE_id] = nb_rbs_required[UE_id]; - if (nb_rbs_required[CC_id][UE_id] > 0) { - total_ue_count = total_ue_count + 1; - } - - - // hypothetical assignment - /* - * If schedule is enabled and if the priority of the UEs is modified - * The average rbs per logical channel per user will depend on the level of - * priority. Concerning the hypothetical assignement, we should assign more - * rbs to prioritized users. Maybe, we can do a mapping between the - * average rbs per user and the level of priority or multiply the average rbs - * per user by a coefficient which represents the degree of priority. - */ - - N_RB_DL = to_prb(RC.mac[Mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth); - - if (total_ue_count == 0) { - average_rbs_per_user[CC_id] = 0; - } else if( (min_rb_unit[CC_id] * total_ue_count) <= (N_RB_DL) ) { - average_rbs_per_user[CC_id] = (uint16_t) floor(N_RB_DL/total_ue_count); - } else { - average_rbs_per_user[CC_id] = min_rb_unit[CC_id]; // consider the total number of use that can be scheduled UE - } - } - } - - // note: nb_rbs_required is assigned according to total_buffer_dl - // extend nb_rbs_required to capture per LCID RB required - for(i=UE_list->head; i>=0; i=UE_list->next[i]) { - rnti = UE_RNTI(Mod_id,i); - - if(rnti == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - - for (ii=0; iiordered_CCids[ii][i]; - ue_sched_ctl = &UE_list->UE_sched_ctrl[i]; - round = ue_sched_ctl->round[CC_id][harq_pid]; - - // control channel or retransmission - /* TODO: do we have to check for retransmission? */ - if (mac_eNB_get_rrc_status(Mod_id,rnti) < RRC_RECONFIGURED || round > 0) { - nb_rbs_required_remaining_1[CC_id][i] = nb_rbs_required[CC_id][i]; - } else { - nb_rbs_required_remaining_1[CC_id][i] = cmin(average_rbs_per_user[CC_id],nb_rbs_required[CC_id][i]); - - } - } - } - - //Allocation to UEs is done in 2 rounds, - // 1st stage: average number of RBs allocated to each UE - // 2nd stage: remaining RBs are allocated to high priority UEs - for(r1=0; r1<2; r1++) { - - for(i=UE_list->head; i>=0; i=UE_list->next[i]) { - for (ii=0; iiordered_CCids[ii][i]; - - if(r1 == 0) { - nb_rbs_required_remaining[CC_id][i] = nb_rbs_required_remaining_1[CC_id][i]; - } else { // rb required based only on the buffer - rb allloctaed in the 1st round + extra reaming rb form the 1st round - nb_rbs_required_remaining[CC_id][i] = nb_rbs_required[CC_id][i]-nb_rbs_required_remaining_1[CC_id][i]+nb_rbs_required_remaining[CC_id][i]; -if (nb_rbs_required_remaining[CC_id][i]<0) abort(); - } - - if (nb_rbs_required[CC_id][i]> 0 ) - LOG_D(MAC,"round %d : nb_rbs_required_remaining[%d][%d]= %d (remaining_1 %d, required %d, pre_nb_available_rbs %d, N_RBG %d, rb_unit %d)\n", - r1, CC_id, i, - nb_rbs_required_remaining[CC_id][i], - nb_rbs_required_remaining_1[CC_id][i], - nb_rbs_required[CC_id][i], - UE_list->UE_sched_ctrl[i].pre_nb_available_rbs[CC_id], - N_RBG[CC_id], - min_rb_unit[CC_id]); - - } - } - - if (total_ue_count > 0 ) { - for(i=UE_list->head; i>=0; i=UE_list->next[i]) { - UE_id = i; - - for (ii=0; iiordered_CCids[ii][UE_id]; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - round = ue_sched_ctl->round[CC_id][harq_pid]; - - rnti = UE_RNTI(Mod_id,UE_id); - - // LOG_D(MAC,"UE %d rnti 0x\n", UE_id, rnti ); - if(rnti == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) + if (mbsfn_flag[CC_id] > 0) // If this CC is allocated for MBSFN skip it here continue; - transmission_mode = get_tmode(Mod_id,CC_id,UE_id); - // mac_xface->get_ue_active_harq_pid(Mod_id,CC_id,rnti,frameP,subframeP,&harq_pid,&round,0); - //rrc_status = mac_eNB_get_rrc_status(Mod_id,rnti); - /* 1st allocate for the retx */ - // retransmission in data channels - // control channel in the 1st transmission - // data channel for all TM - LOG_T(MAC,"calling dlsch_scheduler_pre_processor_allocate .. \n "); - dlsch_scheduler_pre_processor_allocate (Mod_id, - UE_id, - CC_id, - N_RBG[CC_id], - transmission_mode, - min_rb_unit[CC_id], - to_prb(RC.mac[Mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth), - nb_rbs_required, - nb_rbs_required_remaining, - rballoc_sub, - MIMO_mode_indicator); + + min_rb_unit[CC_id] = get_min_rb_unit(Mod_id, CC_id); + + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (UE_list->active[i] != TRUE) + continue; + + UE_id = i; + // Initialize scheduling information for all active UEs + + + + dlsch_scheduler_pre_processor_reset(Mod_id, + UE_id, + CC_id, + frameP, + subframeP, + N_RBG[CC_id], + nb_rbs_required, + nb_rbs_required_remaining, + rballoc_sub, + MIMO_mode_indicator); + + } + } + + + // Store the DLSCH buffer for each logical channel + store_dlsch_buffer(Mod_id, frameP, subframeP); + + + + // Calculate the number of RBs required by each UE on the basis of logical channel's buffer + assign_rbs_required(Mod_id, frameP, subframeP, nb_rbs_required, + min_rb_unit); + + + + // Sorts the user on the basis of dlsch logical channel buffer and CQI + sort_UEs(Mod_id, frameP, subframeP); + + + + total_ue_count = 0; + + // loop over all active UEs + for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { + rnti = UE_RNTI(Mod_id, i); + + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + UE_id = i; + + for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { + CC_id = UE_list->ordered_CCids[ii][UE_id]; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + cc = &RC.mac[Mod_id]->common_channels[ii]; + if (cc->tdd_Config) + harq_pid = ((frameP * 10) + subframeP) % 10; + else + harq_pid = ((frameP * 10) + subframeP) & 7; + round = ue_sched_ctl->round[CC_id][harq_pid]; + + average_rbs_per_user[CC_id] = 0; + + + if (round != 8) { + nb_rbs_required[CC_id][UE_id] = + UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + } + //nb_rbs_required_remaining[UE_id] = nb_rbs_required[UE_id]; + if (nb_rbs_required[CC_id][UE_id] > 0) { + total_ue_count = total_ue_count + 1; + } + // hypothetical assignment + /* + * If schedule is enabled and if the priority of the UEs is modified + * The average rbs per logical channel per user will depend on the level of + * priority. Concerning the hypothetical assignement, we should assign more + * rbs to prioritized users. Maybe, we can do a mapping between the + * average rbs per user and the level of priority or multiply the average rbs + * per user by a coefficient which represents the degree of priority. + */ + + N_RB_DL = + to_prb(RC.mac[Mod_id]->common_channels[CC_id].mib-> + message.dl_Bandwidth); + + if (total_ue_count == 0) { + average_rbs_per_user[CC_id] = 0; + } else if ((min_rb_unit[CC_id] * total_ue_count) <= (N_RB_DL)) { + average_rbs_per_user[CC_id] = + (uint16_t) floor(N_RB_DL / total_ue_count); + } else { + average_rbs_per_user[CC_id] = min_rb_unit[CC_id]; // consider the total number of use that can be scheduled UE + } + } + } + + // note: nb_rbs_required is assigned according to total_buffer_dl + // extend nb_rbs_required to capture per LCID RB required + for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { + rnti = UE_RNTI(Mod_id, i); + + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + + for (ii = 0; ii < UE_num_active_CC(UE_list, i); ii++) { + CC_id = UE_list->ordered_CCids[ii][i]; + ue_sched_ctl = &UE_list->UE_sched_ctrl[i]; + round = ue_sched_ctl->round[CC_id][harq_pid]; + + // control channel or retransmission + /* TODO: do we have to check for retransmission? */ + if (mac_eNB_get_rrc_status(Mod_id, rnti) < RRC_RECONFIGURED + || round > 0) { + nb_rbs_required_remaining_1[CC_id][i] = + nb_rbs_required[CC_id][i]; + } else { + nb_rbs_required_remaining_1[CC_id][i] = + cmin(average_rbs_per_user[CC_id], + nb_rbs_required[CC_id][i]); + + } + } + } + + //Allocation to UEs is done in 2 rounds, + // 1st stage: average number of RBs allocated to each UE + // 2nd stage: remaining RBs are allocated to high priority UEs + for (r1 = 0; r1 < 2; r1++) { + + for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { + for (ii = 0; ii < UE_num_active_CC(UE_list, i); ii++) { + CC_id = UE_list->ordered_CCids[ii][i]; + + if (r1 == 0) { + nb_rbs_required_remaining[CC_id][i] = + nb_rbs_required_remaining_1[CC_id][i]; + } else { // rb required based only on the buffer - rb allloctaed in the 1st round + extra reaming rb form the 1st round + nb_rbs_required_remaining[CC_id][i] = + nb_rbs_required[CC_id][i] - + nb_rbs_required_remaining_1[CC_id][i] + + nb_rbs_required_remaining[CC_id][i]; + if (nb_rbs_required_remaining[CC_id][i] < 0) + abort(); + } + + if (nb_rbs_required[CC_id][i] > 0) + LOG_D(MAC, + "round %d : nb_rbs_required_remaining[%d][%d]= %d (remaining_1 %d, required %d, pre_nb_available_rbs %d, N_RBG %d, rb_unit %d)\n", + r1, CC_id, i, + nb_rbs_required_remaining[CC_id][i], + nb_rbs_required_remaining_1[CC_id][i], + nb_rbs_required[CC_id][i], + UE_list->UE_sched_ctrl[i]. + pre_nb_available_rbs[CC_id], N_RBG[CC_id], + min_rb_unit[CC_id]); + + } + } + + if (total_ue_count > 0) { + for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { + UE_id = i; + + for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { + CC_id = UE_list->ordered_CCids[ii][UE_id]; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + round = ue_sched_ctl->round[CC_id][harq_pid]; + + rnti = UE_RNTI(Mod_id, UE_id); + + // LOG_D(MAC,"UE %d rnti 0x\n", UE_id, rnti ); + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) + continue; + + transmission_mode = get_tmode(Mod_id, CC_id, UE_id); + // mac_xface->get_ue_active_harq_pid(Mod_id,CC_id,rnti,frameP,subframeP,&harq_pid,&round,0); + //rrc_status = mac_eNB_get_rrc_status(Mod_id,rnti); + /* 1st allocate for the retx */ + + // retransmission in data channels + // control channel in the 1st transmission + // data channel for all TM + LOG_T(MAC, + "calling dlsch_scheduler_pre_processor_allocate .. \n "); + dlsch_scheduler_pre_processor_allocate(Mod_id, UE_id, + CC_id, + N_RBG[CC_id], + transmission_mode, + min_rb_unit + [CC_id], + to_prb(RC.mac + [Mod_id]->common_channels + [CC_id].mib->message.dl_Bandwidth), + nb_rbs_required, + nb_rbs_required_remaining, + rballoc_sub, + MIMO_mode_indicator); #ifdef TM5 - // data chanel TM5: to be revisted - if ((round == 0 ) && - (transmission_mode == 5) && - (ue_sched_ctl->dl_pow_off[CC_id] != 1)) { + // data chanel TM5: to be revisted + if ((round == 0) && + (transmission_mode == 5) && + (ue_sched_ctl->dl_pow_off[CC_id] != 1)) { - for(j=0; jrballoc_sub_UE[CC_id][j] == 0)) || - ((j < (N_RBG[CC_id]-1)) && (rballoc_sub[CC_id][j+1] == 0) && (ue_sched_ctl->rballoc_sub_UE[CC_id][j+1] == 0)) ) && - (nb_rbs_required_remaining[CC_id][UE_id]>0)) { + if ((((j == (N_RBG[CC_id] - 1)) + && (rballoc_sub[CC_id][j] == 0) + && (ue_sched_ctl-> + rballoc_sub_UE[CC_id][j] == 0)) + || ((j < (N_RBG[CC_id] - 1)) + && (rballoc_sub[CC_id][j + 1] == 0) + && + (ue_sched_ctl->rballoc_sub_UE + [CC_id][j + 1] == 0))) + && (nb_rbs_required_remaining[CC_id][UE_id] + > 0)) { - for (ii = UE_list->next[i+1]; ii >=0; ii=UE_list->next[ii]) { + for (ii = UE_list->next[i + 1]; ii >= 0; + ii = UE_list->next[ii]) { - UE_id2 = ii; - rnti2 = UE_RNTI(Mod_id,UE_id2); - ue_sched_ctl2 = &UE_list->UE_sched_ctrl[UE_id2]; - round2 = ue_sched_ctl2->round[CC_id]; - if(rnti2 == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[UE_id2].ul_out_of_sync == 1) - continue; + UE_id2 = ii; + rnti2 = UE_RNTI(Mod_id, UE_id2); + ue_sched_ctl2 = + &UE_list->UE_sched_ctrl[UE_id2]; + round2 = ue_sched_ctl2->round[CC_id]; + if (rnti2 == NOT_A_RNTI) + continue; + if (UE_list-> + UE_sched_ctrl + [UE_id2].ul_out_of_sync == 1) + continue; - eNB_UE_stats2 = UE_list->eNB_UE_stats[CC_id][UE_id2]; - //mac_xface->get_ue_active_harq_pid(Mod_id,CC_id,rnti2,frameP,subframeP,&harq_pid2,&round2,0); + eNB_UE_stats2 = + UE_list-> + eNB_UE_stats[CC_id][UE_id2]; + //mac_xface->get_ue_active_harq_pid(Mod_id,CC_id,rnti2,frameP,subframeP,&harq_pid2,&round2,0); - if ((mac_eNB_get_rrc_status(Mod_id,rnti2) >= RRC_RECONFIGURED) && - (round2==0) && - (get_tmode(Mod_id,CC_id,UE_id2)==5) && - (ue_sched_ctl->dl_pow_off[CC_id] != 1)) { + if ((mac_eNB_get_rrc_status + (Mod_id, + rnti2) >= RRC_RECONFIGURED) + && (round2 == 0) + && + (get_tmode(Mod_id, CC_id, UE_id2) + == 5) + && (ue_sched_ctl-> + dl_pow_off[CC_id] != 1)) { - if( (((j == (N_RBG[CC_id]-1)) && (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 0)) || - ((j < (N_RBG[CC_id]-1)) && (ue_sched_ctl->rballoc_sub_UE[CC_id][j+1] == 0)) ) && - (nb_rbs_required_remaining[CC_id][UE_id2]>0)) { + if ((((j == (N_RBG[CC_id] - 1)) + && + (ue_sched_ctl->rballoc_sub_UE + [CC_id][j] == 0)) + || ((j < (N_RBG[CC_id] - 1)) + && + (ue_sched_ctl-> + rballoc_sub_UE[CC_id][j + + 1] + == 0))) + && + (nb_rbs_required_remaining + [CC_id] + [UE_id2] > 0)) { - if((((eNB_UE_stats2->DL_pmi_single^eNB_UE_stats1->DL_pmi_single)<<(14-j))&0xc000)== 0x4000) { //MU-MIMO only for 25 RBs configuration + if ((((eNB_UE_stats2-> + DL_pmi_single ^ + eNB_UE_stats1-> + DL_pmi_single) + << (14 - j)) & 0xc000) == 0x4000) { //MU-MIMO only for 25 RBs configuration - rballoc_sub[CC_id][j] = 1; - ue_sched_ctl->rballoc_sub_UE[CC_id][j] = 1; - ue_sched_ctl2->rballoc_sub_UE[CC_id][j] = 1; - MIMO_mode_indicator[CC_id][j] = 0; + rballoc_sub[CC_id][j] = 1; + ue_sched_ctl-> + rballoc_sub_UE[CC_id] + [j] = 1; + ue_sched_ctl2-> + rballoc_sub_UE[CC_id] + [j] = 1; + MIMO_mode_indicator[CC_id] + [j] = 0; - if (j< N_RBG[CC_id]-1) { - rballoc_sub[CC_id][j+1] = 1; - ue_sched_ctl->rballoc_sub_UE[CC_id][j+1] = 1; - ue_sched_ctl2->rballoc_sub_UE[CC_id][j+1] = 1; - MIMO_mode_indicator[CC_id][j+1] = 0; - } + if (j < N_RBG[CC_id] - 1) { + rballoc_sub[CC_id][j + + 1] = + 1; + ue_sched_ctl-> + rballoc_sub_UE + [CC_id][j + 1] = 1; + ue_sched_ctl2->rballoc_sub_UE + [CC_id][j + 1] = 1; + MIMO_mode_indicator + [CC_id][j + 1] + = 0; + } - ue_sched_ctl->dl_pow_off[CC_id] = 0; - ue_sched_ctl2->dl_pow_off[CC_id] = 0; + ue_sched_ctl-> + dl_pow_off[CC_id] + = 0; + ue_sched_ctl2-> + dl_pow_off[CC_id] + = 0; - if ((j == N_RBG[CC_id]-1) && - ((N_RB_DL == 25) || - (N_RB_DL == 50))) { - - nb_rbs_required_remaining[CC_id][UE_id] = nb_rbs_required_remaining[CC_id][UE_id] - min_rb_unit[CC_id]+1; - ue_sched_ctl->pre_nb_available_rbs[CC_id] = ue_sched_ctl->pre_nb_available_rbs[CC_id] + min_rb_unit[CC_id]-1; - nb_rbs_required_remaining[CC_id][UE_id2] = nb_rbs_required_remaining[CC_id][UE_id2] - min_rb_unit[CC_id]+1; - ue_sched_ctl2->pre_nb_available_rbs[CC_id] = ue_sched_ctl2->pre_nb_available_rbs[CC_id] + min_rb_unit[CC_id]-1; - } else { - - nb_rbs_required_remaining[CC_id][UE_id] = nb_rbs_required_remaining[CC_id][UE_id] - 4; - ue_sched_ctl->pre_nb_available_rbs[CC_id] = ue_sched_ctl->pre_nb_available_rbs[CC_id] + 4; - nb_rbs_required_remaining[CC_id][UE_id2] = nb_rbs_required_remaining[CC_id][UE_id2] - 4; - ue_sched_ctl2->pre_nb_available_rbs[CC_id] = ue_sched_ctl2->pre_nb_available_rbs[CC_id] + 4; - } + if ((j == N_RBG[CC_id] - 1) + && ((N_RB_DL == 25) + || (N_RB_DL == + 50))) { - break; - } - } - } - } - } - } - } + nb_rbs_required_remaining + [CC_id][UE_id] = + nb_rbs_required_remaining + [CC_id][UE_id] - + min_rb_unit[CC_id] + + 1; + ue_sched_ctl->pre_nb_available_rbs + [CC_id] = + ue_sched_ctl->pre_nb_available_rbs + [CC_id] + + min_rb_unit[CC_id] + - 1; + nb_rbs_required_remaining + [CC_id][UE_id2] = + nb_rbs_required_remaining + [CC_id][UE_id2] - + min_rb_unit[CC_id] + + 1; + ue_sched_ctl2->pre_nb_available_rbs + [CC_id] = + ue_sched_ctl2->pre_nb_available_rbs + [CC_id] + + min_rb_unit[CC_id] + - 1; + } else { + nb_rbs_required_remaining + [CC_id][UE_id] = + nb_rbs_required_remaining + [CC_id][UE_id] - 4; + ue_sched_ctl->pre_nb_available_rbs + [CC_id] = + ue_sched_ctl->pre_nb_available_rbs + [CC_id] + 4; + nb_rbs_required_remaining + [CC_id][UE_id2] = + nb_rbs_required_remaining + [CC_id][UE_id2] - + 4; + ue_sched_ctl2->pre_nb_available_rbs + [CC_id] = + ue_sched_ctl2->pre_nb_available_rbs + [CC_id] + 4; + } + + break; + } + } + } + } + } + } + } #endif - } - } - } // total_ue_count - } // end of for for r1 and r2 + } + } + } // total_ue_count + } // end of for for r1 and r2 #ifdef TM5 - // This has to be revisited!!!! - for (CC_id=0; CC_id 0) && (i3 == 0)) { + PHY_vars_eNB_g[Mod_id][CC_id]->check_for_SUMIMO_transmissions = + PHY_vars_eNB_g[Mod_id][CC_id]-> + check_for_SUMIMO_transmissions + 1; + } + + if (i3 == N_RBG[CC_id] && i1 == 0 && i2 == 0) { + PHY_vars_eNB_g[Mod_id][CC_id]->FULL_MUMIMO_transmissions = + PHY_vars_eNB_g[Mod_id][CC_id]->FULL_MUMIMO_transmissions + + 1; + } + + if ((i1 < N_RBG[CC_id]) && (i3 > 0)) { + PHY_vars_eNB_g[Mod_id][CC_id]->check_for_MUMIMO_transmissions = + PHY_vars_eNB_g[Mod_id][CC_id]-> + check_for_MUMIMO_transmissions + 1; + } + + PHY_vars_eNB_g[Mod_id][CC_id]->check_for_total_transmissions = + PHY_vars_eNB_g[Mod_id][CC_id]->check_for_total_transmissions + + 1; - for (j=0; j0) && (i3==0)) { - PHY_vars_eNB_g[Mod_id][CC_id]->check_for_SUMIMO_transmissions = PHY_vars_eNB_g[Mod_id][CC_id]->check_for_SUMIMO_transmissions + 1; - } - - if(i3 == N_RBG[CC_id] && i1==0 && i2==0) { - PHY_vars_eNB_g[Mod_id][CC_id]->FULL_MUMIMO_transmissions = PHY_vars_eNB_g[Mod_id][CC_id]->FULL_MUMIMO_transmissions + 1; - } - - if((i1 < N_RBG[CC_id]) && (i3 > 0)) { - PHY_vars_eNB_g[Mod_id][CC_id]->check_for_MUMIMO_transmissions = PHY_vars_eNB_g[Mod_id][CC_id]->check_for_MUMIMO_transmissions + 1; - } - - PHY_vars_eNB_g[Mod_id][CC_id]->check_for_total_transmissions = PHY_vars_eNB_g[Mod_id][CC_id]->check_for_total_transmissions + 1; - - } - #endif - for(i=UE_list->head; i>=0; i=UE_list->next[i]) { - UE_id = i; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { + UE_id = i; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - for (ii=0; iiordered_CCids[ii][UE_id]; - //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].dl_pow_off = dl_pow_off[UE_id]; + for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { + CC_id = UE_list->ordered_CCids[ii][UE_id]; + //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].dl_pow_off = dl_pow_off[UE_id]; - if (ue_sched_ctl->pre_nb_available_rbs[CC_id] > 0 ) { - LOG_D(MAC,"******************DL Scheduling Information for UE%d ************************\n",UE_id); - LOG_D(MAC,"dl power offset UE%d = %d \n",UE_id,ue_sched_ctl->dl_pow_off[CC_id]); - LOG_D(MAC,"***********RB Alloc for every subband for UE%d ***********\n",UE_id); + if (ue_sched_ctl->pre_nb_available_rbs[CC_id] > 0) { + LOG_D(MAC, + "******************DL Scheduling Information for UE%d ************************\n", + UE_id); + LOG_D(MAC, "dl power offset UE%d = %d \n", UE_id, + ue_sched_ctl->dl_pow_off[CC_id]); + LOG_D(MAC, + "***********RB Alloc for every subband for UE%d ***********\n", + UE_id); - for(j=0; jmu_mimo_mode[UE_id].rballoc_sub[i] = rballoc_sub_UE[CC_id][UE_id][i]; - LOG_D(MAC,"RB Alloc for UE%d and Subband%d = %d\n",UE_id,j,ue_sched_ctl->rballoc_sub_UE[CC_id][j]); - } + for (j = 0; j < N_RBG[CC_id]; j++) { + //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].rballoc_sub[i] = rballoc_sub_UE[CC_id][UE_id][i]; + LOG_D(MAC, "RB Alloc for UE%d and Subband%d = %d\n", + UE_id, j, + ue_sched_ctl->rballoc_sub_UE[CC_id][j]); + } - //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = pre_nb_available_rbs[CC_id][UE_id]; - LOG_D(MAC,"Total RBs allocated for UE%d = %d\n",UE_id,ue_sched_ctl->pre_nb_available_rbs[CC_id]); - } + //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = pre_nb_available_rbs[CC_id][UE_id]; + LOG_D(MAC, "Total RBs allocated for UE%d = %d\n", UE_id, + ue_sched_ctl->pre_nb_available_rbs[CC_id]); + } + } } - } } #define SF0_LIMIT 1 -void dlsch_scheduler_pre_processor_reset (int module_idP, - int UE_id, - uint8_t CC_id, - int frameP, - int subframeP, - int N_RBG, - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], - unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]) - +void +dlsch_scheduler_pre_processor_reset(int module_idP, + int UE_id, + uint8_t CC_id, + int frameP, + int subframeP, + int N_RBG, + uint16_t nb_rbs_required[MAX_NUM_CCs] + [NUMBER_OF_UE_MAX], + uint16_t + nb_rbs_required_remaining + [MAX_NUM_CCs][NUMBER_OF_UE_MAX], + unsigned char + rballoc_sub[MAX_NUM_CCs] + [N_RBG_MAX], unsigned char + MIMO_mode_indicator[MAX_NUM_CCs] + [N_RBG_MAX]) { - int i,j; - UE_list_t *UE_list=&RC.mac[module_idP]->UE_list; - UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - rnti_t rnti = UE_RNTI(module_idP,UE_id); + int i, j; + UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; + UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + rnti_t rnti = UE_RNTI(module_idP, UE_id); - uint8_t *vrb_map = RC.mac[module_idP]->common_channels[CC_id].vrb_map; - int N_RB_DL = to_prb(RC.mac[module_idP]->common_channels[CC_id].mib->message.dl_Bandwidth); - int RBGsize = N_RB_DL/N_RBG,RBGsize_last; + uint8_t *vrb_map = RC.mac[module_idP]->common_channels[CC_id].vrb_map; + int N_RB_DL = + to_prb(RC.mac[module_idP]->common_channels[CC_id].mib-> + message.dl_Bandwidth); + int RBGsize = N_RB_DL / N_RBG, RBGsize_last; #ifdef SF0_LIMIT - int sf0_upper=-1,sf0_lower=-1; + int sf0_upper = -1, sf0_lower = -1; #endif - LOG_D(MAC,"Running preprocessor for UE %d (%x)\n",UE_id,rnti); - // initialize harq_pid and round + LOG_D(MAC, "Running preprocessor for UE %d (%x)\n", UE_id, rnti); + // initialize harq_pid and round - if (ue_sched_ctl->ta_timer) ue_sched_ctl->ta_timer--; + if (ue_sched_ctl->ta_timer) + ue_sched_ctl->ta_timer--; - /* - eNB_UE_stats *eNB_UE_stats; + /* + eNB_UE_stats *eNB_UE_stats; - if (eNB_UE_stats == NULL) - return; + if (eNB_UE_stats == NULL) + return; - - mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti, - frameP,subframeP, - &ue_sched_ctl->harq_pid[CC_id], - &ue_sched_ctl->round[CC_id], - openair_harq_DL); - - if (ue_sched_ctl->ta_timer == 0) { + mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti, + frameP,subframeP, + &ue_sched_ctl->harq_pid[CC_id], + &ue_sched_ctl->round[CC_id], + openair_harq_DL); - // WE SHOULD PROTECT the eNB_UE_stats with a mutex here ... - ue_sched_ctl->ta_timer = 20; // wait 20 subframes before taking TA measurement from PHY + if (ue_sched_ctl->ta_timer == 0) { + + // WE SHOULD PROTECT the eNB_UE_stats with a mutex here ... + + ue_sched_ctl->ta_timer = 20; // wait 20 subframes before taking TA measurement from PHY + switch (N_RB_DL) { + case 6: + ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update; + break; + + case 15: + ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/2; + break; + + case 25: + ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/4; + break; + + case 50: + ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/8; + break; + + case 75: + ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/12; + break; + + case 100: + ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/16; + break; + } + // clear the update in case PHY does not have a new measurement after timer expiry + eNB_UE_stats->timing_advance_update = 0; + } + else { + ue_sched_ctl->ta_timer--; + ue_sched_ctl->ta_update =0; // don't trigger a timing advance command + } + + + if (UE_id==0) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_TIMING_ADVANCE,ue_sched_ctl->ta_update); + } + */ + + nb_rbs_required[CC_id][UE_id] = 0; + ue_sched_ctl->pre_nb_available_rbs[CC_id] = 0; + ue_sched_ctl->dl_pow_off[CC_id] = 2; + nb_rbs_required_remaining[CC_id][UE_id] = 0; + switch (N_RB_DL) { case 6: - ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update; - break; - - case 15: - ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/2; - break; - - case 25: - ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/4; - break; - - case 50: - ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/8; - break; - - case 75: - ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/12; - break; - - case 100: - ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/16; - break; - } - // clear the update in case PHY does not have a new measurement after timer expiry - eNB_UE_stats->timing_advance_update = 0; - } - else { - ue_sched_ctl->ta_timer--; - ue_sched_ctl->ta_update =0; // don't trigger a timing advance command - } - - - if (UE_id==0) { - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_TIMING_ADVANCE,ue_sched_ctl->ta_update); - } - */ - - nb_rbs_required[CC_id][UE_id]=0; - ue_sched_ctl->pre_nb_available_rbs[CC_id] = 0; - ue_sched_ctl->dl_pow_off[CC_id] = 2; - nb_rbs_required_remaining[CC_id][UE_id] = 0; - - switch (N_RB_DL) { - case 6: RBGsize = 1; RBGsize_last = 1; break; - case 15: RBGsize = 2; RBGsize_last = 1; break; - case 25: RBGsize = 2; RBGsize_last = 1; break; - case 50: RBGsize = 3; RBGsize_last = 2; break; - case 75: RBGsize = 4; RBGsize_last = 3; break; - case 100: RBGsize = 4; RBGsize_last = 4; break; - default: AssertFatal(1==0,"unsupported RBs (%d)\n", N_RB_DL); - } - -#ifdef SF0_LIMIT - switch (N_RBG) { - case 6: - sf0_lower=0; - sf0_upper=5; - break; - case 8: - sf0_lower=2; - sf0_upper=5; - break; - case 13: - sf0_lower=4; - sf0_upper=7; - break; - case 17: - sf0_lower=7; - sf0_upper=9; - break; - case 25: - sf0_lower=11; - sf0_upper=13; - break; - default: AssertFatal(1==0,"unsupported RBs (%d)\n", N_RB_DL); - } -#endif - // Initialize Subbands according to VRB map - for (i=0; irballoc_sub_UE[CC_id][i] = 0; - rballoc_sub[CC_id][i] = 0; -#ifdef SF0_LIMIT - // for avoiding 6+ PRBs around DC in subframe 0 (avoid excessive errors) - /* TODO: make it proper - allocate those RBs, do not "protect" them, but - * compute number of available REs and limit MCS according to the - * TBS table 36.213 7.1.7.2.1-1 (can be done after pre-processor) - */ - if (subframeP==0 && - i >= sf0_lower && i <= sf0_upper) - rballoc_sub[CC_id][i]=1; -#endif - // for SI-RNTI,RA-RNTI and P-RNTI allocations - for (j = 0; j < rb_size; j++) { - if (vrb_map[j+(i*RBGsize)] != 0) { - rballoc_sub[CC_id][i] = 1; - LOG_D(MAC,"Frame %d, subframe %d : vrb %d allocated\n",frameP,subframeP,j+(i*RBGsize)); + RBGsize = 1; + RBGsize_last = 1; break; - } + case 15: + RBGsize = 2; + RBGsize_last = 1; + break; + case 25: + RBGsize = 2; + RBGsize_last = 1; + break; + case 50: + RBGsize = 3; + RBGsize_last = 2; + break; + case 75: + RBGsize = 4; + RBGsize_last = 3; + break; + case 100: + RBGsize = 4; + RBGsize_last = 4; + break; + default: + AssertFatal(1 == 0, "unsupported RBs (%d)\n", N_RB_DL); + } + +#ifdef SF0_LIMIT + switch (N_RBG) { + case 6: + sf0_lower = 0; + sf0_upper = 5; + break; + case 8: + sf0_lower = 2; + sf0_upper = 5; + break; + case 13: + sf0_lower = 4; + sf0_upper = 7; + break; + case 17: + sf0_lower = 7; + sf0_upper = 9; + break; + case 25: + sf0_lower = 11; + sf0_upper = 13; + break; + default: + AssertFatal(1 == 0, "unsupported RBs (%d)\n", N_RB_DL); + } +#endif + // Initialize Subbands according to VRB map + for (i = 0; i < N_RBG; i++) { + int rb_size = i == N_RBG - 1 ? RBGsize_last : RBGsize; + + ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 0; + rballoc_sub[CC_id][i] = 0; +#ifdef SF0_LIMIT + // for avoiding 6+ PRBs around DC in subframe 0 (avoid excessive errors) + /* TODO: make it proper - allocate those RBs, do not "protect" them, but + * compute number of available REs and limit MCS according to the + * TBS table 36.213 7.1.7.2.1-1 (can be done after pre-processor) + */ + if (subframeP == 0 && i >= sf0_lower && i <= sf0_upper) + rballoc_sub[CC_id][i] = 1; +#endif + // for SI-RNTI,RA-RNTI and P-RNTI allocations + for (j = 0; j < rb_size; j++) { + if (vrb_map[j + (i * RBGsize)] != 0) { + rballoc_sub[CC_id][i] = 1; + LOG_D(MAC, "Frame %d, subframe %d : vrb %d allocated\n", + frameP, subframeP, j + (i * RBGsize)); + break; + } + } + LOG_D(MAC, "Frame %d Subframe %d CC_id %d RBG %i : rb_alloc %d\n", + frameP, subframeP, CC_id, i, rballoc_sub[CC_id][i]); + MIMO_mode_indicator[CC_id][i] = 2; } - LOG_D(MAC,"Frame %d Subframe %d CC_id %d RBG %i : rb_alloc %d\n",frameP,subframeP,CC_id,i,rballoc_sub[CC_id][i]); - MIMO_mode_indicator[CC_id][i] = 2; - } } -void dlsch_scheduler_pre_processor_allocate (module_id_t Mod_id, - int UE_id, - uint8_t CC_id, - int N_RBG, - int transmission_mode, - int min_rb_unit, - uint8_t N_RB_DL, - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], - unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]) +void +dlsch_scheduler_pre_processor_allocate(module_id_t Mod_id, + int UE_id, + uint8_t CC_id, + int N_RBG, + int transmission_mode, + int min_rb_unit, + uint8_t N_RB_DL, + uint16_t + nb_rbs_required[MAX_NUM_CCs] + [NUMBER_OF_UE_MAX], + uint16_t + nb_rbs_required_remaining + [MAX_NUM_CCs] + [NUMBER_OF_UE_MAX], unsigned char + rballoc_sub[MAX_NUM_CCs] + [N_RBG_MAX], unsigned char + MIMO_mode_indicator + [MAX_NUM_CCs][N_RBG_MAX]) { - int i; - UE_list_t *UE_list=&RC.mac[Mod_id]->UE_list; - UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + int i; + UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list; + UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - for(i=0; irballoc_sub_UE[CC_id][i] == 0) && - (nb_rbs_required_remaining[CC_id][UE_id]>0) && - (ue_sched_ctl->pre_nb_available_rbs[CC_id] < nb_rbs_required[CC_id][UE_id])) { + if ((rballoc_sub[CC_id][i] == 0) && + (ue_sched_ctl->rballoc_sub_UE[CC_id][i] == 0) && + (nb_rbs_required_remaining[CC_id][UE_id] > 0) && + (ue_sched_ctl->pre_nb_available_rbs[CC_id] < + nb_rbs_required[CC_id][UE_id])) { - // if this UE is not scheduled for TM5 - if (ue_sched_ctl->dl_pow_off[CC_id] != 0 ) { + // if this UE is not scheduled for TM5 + if (ue_sched_ctl->dl_pow_off[CC_id] != 0) { - if ((i == N_RBG-1) && ((N_RB_DL == 25) || (N_RB_DL == 50))) { - if (nb_rbs_required_remaining[CC_id][UE_id] >= min_rb_unit-1){ - rballoc_sub[CC_id][i] = 1; - ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 1; - MIMO_mode_indicator[CC_id][i] = 1; - if (transmission_mode == 5 ) { - ue_sched_ctl->dl_pow_off[CC_id] = 1; - } - nb_rbs_required_remaining[CC_id][UE_id] = nb_rbs_required_remaining[CC_id][UE_id] - min_rb_unit+1; - ue_sched_ctl->pre_nb_available_rbs[CC_id] = ue_sched_ctl->pre_nb_available_rbs[CC_id] + min_rb_unit - 1; - } - } else { - if (nb_rbs_required_remaining[CC_id][UE_id] >= min_rb_unit){ - rballoc_sub[CC_id][i] = 1; - ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 1; - MIMO_mode_indicator[CC_id][i] = 1; - if (transmission_mode == 5 ) { - ue_sched_ctl->dl_pow_off[CC_id] = 1; - } - nb_rbs_required_remaining[CC_id][UE_id] = nb_rbs_required_remaining[CC_id][UE_id] - min_rb_unit; - ue_sched_ctl->pre_nb_available_rbs[CC_id] = ue_sched_ctl->pre_nb_available_rbs[CC_id] + min_rb_unit; - } + if ((i == N_RBG - 1) + && ((N_RB_DL == 25) || (N_RB_DL == 50))) { + if (nb_rbs_required_remaining[CC_id][UE_id] >= + min_rb_unit - 1) { + rballoc_sub[CC_id][i] = 1; + ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 1; + MIMO_mode_indicator[CC_id][i] = 1; + if (transmission_mode == 5) { + ue_sched_ctl->dl_pow_off[CC_id] = 1; + } + nb_rbs_required_remaining[CC_id][UE_id] = + nb_rbs_required_remaining[CC_id][UE_id] - + min_rb_unit + 1; + ue_sched_ctl->pre_nb_available_rbs[CC_id] = + ue_sched_ctl->pre_nb_available_rbs[CC_id] + + min_rb_unit - 1; + } + } else { + if (nb_rbs_required_remaining[CC_id][UE_id] >= + min_rb_unit) { + rballoc_sub[CC_id][i] = 1; + ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 1; + MIMO_mode_indicator[CC_id][i] = 1; + if (transmission_mode == 5) { + ue_sched_ctl->dl_pow_off[CC_id] = 1; + } + nb_rbs_required_remaining[CC_id][UE_id] = + nb_rbs_required_remaining[CC_id][UE_id] - + min_rb_unit; + ue_sched_ctl->pre_nb_available_rbs[CC_id] = + ue_sched_ctl->pre_nb_available_rbs[CC_id] + + min_rb_unit; + } + } + } // dl_pow_off[CC_id][UE_id] ! = 0 } - } // dl_pow_off[CC_id][UE_id] ! = 0 } - } } /// ULSCH PRE_PROCESSOR -void ulsch_scheduler_pre_processor(module_id_t module_idP, - int frameP, - sub_frame_t subframeP, - uint16_t *first_rb) +void +ulsch_scheduler_pre_processor(module_id_t module_idP, + int frameP, + sub_frame_t subframeP, uint16_t * first_rb) { - int16_t i; - uint16_t UE_id,n,r; - uint8_t CC_id, harq_pid; - uint16_t nb_allocated_rbs[MAX_NUM_CCs][NUMBER_OF_UE_MAX],total_allocated_rbs[MAX_NUM_CCs],average_rbs_per_user[MAX_NUM_CCs]; - int16_t total_remaining_rbs[MAX_NUM_CCs]; - uint16_t max_num_ue_to_be_scheduled = 0; - uint16_t total_ue_count = 0; - rnti_t rnti = -1; - UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; - UE_TEMPLATE *UE_template = 0; - int N_RB_DL; - int N_RB_UL; - LOG_D(MAC,"In ulsch_preprocessor: assign max mcs min rb\n"); - // maximize MCS and then allocate required RB according to the buffer occupancy with the limit of max available UL RB - assign_max_mcs_min_rb(module_idP,frameP, subframeP, first_rb); + int16_t i; + uint16_t UE_id, n, r; + uint8_t CC_id, harq_pid; + uint16_t nb_allocated_rbs[MAX_NUM_CCs][NUMBER_OF_UE_MAX], + total_allocated_rbs[MAX_NUM_CCs], + average_rbs_per_user[MAX_NUM_CCs]; + int16_t total_remaining_rbs[MAX_NUM_CCs]; + uint16_t max_num_ue_to_be_scheduled = 0; + uint16_t total_ue_count = 0; + rnti_t rnti = -1; + UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; + UE_TEMPLATE *UE_template = 0; + int N_RB_DL; + int N_RB_UL; + LOG_D(MAC, "In ulsch_preprocessor: assign max mcs min rb\n"); + // maximize MCS and then allocate required RB according to the buffer occupancy with the limit of max available UL RB + assign_max_mcs_min_rb(module_idP, frameP, subframeP, first_rb); - LOG_D(MAC,"In ulsch_preprocessor: sort ue \n"); - // sort ues - sort_ue_ul (module_idP,frameP, subframeP); + LOG_D(MAC, "In ulsch_preprocessor: sort ue \n"); + // sort ues + sort_ue_ul(module_idP, frameP, subframeP); - // we need to distribute RBs among UEs - // step1: reset the vars - for (CC_id=0; CC_idcommon_channels[CC_id].mib->message.dl_Bandwidth); - N_RB_UL = to_prb(RC.mac[module_idP]->common_channels[CC_id].ul_Bandwidth); - total_allocated_rbs[CC_id] = 0; - total_remaining_rbs[CC_id] = 0; - average_rbs_per_user[CC_id] = 0; + // we need to distribute RBs among UEs + // step1: reset the vars + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + N_RB_DL = + to_prb(RC.mac[module_idP]->common_channels[CC_id].mib-> + message.dl_Bandwidth); + N_RB_UL = + to_prb(RC.mac[module_idP]->common_channels[CC_id]. + ul_Bandwidth); + total_allocated_rbs[CC_id] = 0; + total_remaining_rbs[CC_id] = 0; + average_rbs_per_user[CC_id] = 0; - for (i=UE_list->head_ul; i>=0; i=UE_list->next_ul[i]) { - nb_allocated_rbs[CC_id][i]=0; + for (i = UE_list->head_ul; i >= 0; i = UE_list->next_ul[i]) { + nb_allocated_rbs[CC_id][i] = 0; + } } - } - LOG_D(MAC,"In ulsch_preprocessor: step2 \n"); - // step 2: calculate the average rb per UE - total_ue_count =0; - max_num_ue_to_be_scheduled=0; + LOG_D(MAC, "In ulsch_preprocessor: step2 \n"); + // step 2: calculate the average rb per UE + total_ue_count = 0; + max_num_ue_to_be_scheduled = 0; - for (i=UE_list->head_ul; i>=0; i=UE_list->next_ul[i]) { + for (i = UE_list->head_ul; i >= 0; i = UE_list->next_ul[i]) { - rnti = UE_RNTI(module_idP,i); + rnti = UE_RNTI(module_idP, i); - if (rnti==NOT_A_RNTI) - continue; + if (rnti == NOT_A_RNTI) + continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; - UE_id = i; + UE_id = i; - LOG_D(MAC,"In ulsch_preprocessor: handling UE %d/%x\n",UE_id,rnti); - for (n=0; nnumactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - LOG_D(MAC,"In ulsch_preprocessor: handling UE %d/%x CCid %d\n",UE_id,rnti,CC_id); - UE_template = &UE_list->UE_template[CC_id][UE_id]; - average_rbs_per_user[CC_id]=0; + LOG_D(MAC, "In ulsch_preprocessor: handling UE %d/%x\n", UE_id, + rnti); + for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; + LOG_D(MAC, + "In ulsch_preprocessor: handling UE %d/%x CCid %d\n", + UE_id, rnti, CC_id); + UE_template = &UE_list->UE_template[CC_id][UE_id]; + average_rbs_per_user[CC_id] = 0; - if (UE_template->pre_allocated_nb_rb_ul > 0) { - total_ue_count+=1; - } - /* - if((mac_xface->get_nCCE_max(module_idP,CC_id,3,subframeP) - nCCE_to_be_used[CC_id]) > (1<pre_allocated_nb_rb_ul > 0) { + total_ue_count += 1; + } + /* + if((mac_xface->get_nCCE_max(module_idP,CC_id,3,subframeP) - nCCE_to_be_used[CC_id]) > (1< 0 ) { - average_rbs_per_user[CC_id] = (uint16_t) floor((N_RB_UL-first_rb[CC_id])/max_num_ue_to_be_scheduled); - } else { - average_rbs_per_user[CC_id]=1; - LOG_W(MAC,"[eNB %d] frame %d subframe %d: UE %d CC %d: can't get average rb per user (should not be here)\n", - module_idP,frameP,subframeP,UE_id,CC_id); - } + if (total_ue_count == 0) { + average_rbs_per_user[CC_id] = 0; + } else if (total_ue_count == 1) { // increase the available RBs, special case, + average_rbs_per_user[CC_id] = + N_RB_UL - first_rb[CC_id] + 1; + } else if ((total_ue_count <= (N_RB_DL - first_rb[CC_id])) + && (total_ue_count <= max_num_ue_to_be_scheduled)) { + average_rbs_per_user[CC_id] = + (uint16_t) floor((N_RB_UL - first_rb[CC_id]) / + total_ue_count); + } else if (max_num_ue_to_be_scheduled > 0) { + average_rbs_per_user[CC_id] = + (uint16_t) floor((N_RB_UL - first_rb[CC_id]) / + max_num_ue_to_be_scheduled); + } else { + average_rbs_per_user[CC_id] = 1; + LOG_W(MAC, + "[eNB %d] frame %d subframe %d: UE %d CC %d: can't get average rb per user (should not be here)\n", + module_idP, frameP, subframeP, UE_id, CC_id); + } + } } - } - if (total_ue_count > 0) - LOG_D(MAC,"[eNB %d] Frame %d subframe %d: total ue to be scheduled %d/%d\n", - module_idP, frameP, subframeP,total_ue_count, max_num_ue_to_be_scheduled); + if (total_ue_count > 0) + LOG_D(MAC, + "[eNB %d] Frame %d subframe %d: total ue to be scheduled %d/%d\n", + module_idP, frameP, subframeP, total_ue_count, + max_num_ue_to_be_scheduled); - //LOG_D(MAC,"step3\n"); + //LOG_D(MAC,"step3\n"); - // step 3: assigne RBS - for (i=UE_list->head_ul; i>=0; i=UE_list->next_ul[i]) { - rnti = UE_RNTI(module_idP,i); + // step 3: assigne RBS + for (i = UE_list->head_ul; i >= 0; i = UE_list->next_ul[i]) { + rnti = UE_RNTI(module_idP, i); - if (rnti==NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; - UE_id = i; + UE_id = i; - for (n=0; nnumactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - harq_pid = subframe2harqpid(&RC.mac[module_idP]->common_channels[CC_id],frameP,subframeP); + for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; + harq_pid = + subframe2harqpid(&RC.mac[module_idP]-> + common_channels[CC_id], frameP, + subframeP); - // mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL); + // mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL); - if(UE_list->UE_sched_ctrl[UE_id].round_UL[CC_id]>0) { - nb_allocated_rbs[CC_id][UE_id] = UE_list->UE_template[CC_id][UE_id].nb_rb_ul[harq_pid]; - } else { - nb_allocated_rbs[CC_id][UE_id] = cmin(UE_list->UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul, average_rbs_per_user[CC_id]); - } + if (UE_list->UE_sched_ctrl[UE_id].round_UL[CC_id] > 0) { + nb_allocated_rbs[CC_id][UE_id] = + UE_list->UE_template[CC_id][UE_id].nb_rb_ul[harq_pid]; + } else { + nb_allocated_rbs[CC_id][UE_id] = + cmin(UE_list-> + UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul, + average_rbs_per_user[CC_id]); + } - total_allocated_rbs[CC_id]+= nb_allocated_rbs[CC_id][UE_id]; - LOG_D(MAC,"In ulsch_preprocessor: assigning %d RBs for UE %d/%x CCid %d, harq_pid %d\n",nb_allocated_rbs[CC_id][UE_id],UE_id,rnti,CC_id,harq_pid); + total_allocated_rbs[CC_id] += nb_allocated_rbs[CC_id][UE_id]; + LOG_D(MAC, + "In ulsch_preprocessor: assigning %d RBs for UE %d/%x CCid %d, harq_pid %d\n", + nb_allocated_rbs[CC_id][UE_id], UE_id, rnti, CC_id, + harq_pid); + } } - } - // step 4: assigne the remaining RBs and set the pre_allocated rbs accordingly - for(r=0; r<2; r++) { + // step 4: assigne the remaining RBs and set the pre_allocated rbs accordingly + for (r = 0; r < 2; r++) { - for (i=UE_list->head_ul; i>=0; i=UE_list->next_ul[i]) { - rnti = UE_RNTI(module_idP,i); + for (i = UE_list->head_ul; i >= 0; i = UE_list->next_ul[i]) { + rnti = UE_RNTI(module_idP, i); - if (rnti==NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - UE_id = i; + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + UE_id = i; - for (n=0; nnumactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - UE_template = &UE_list->UE_template[CC_id][UE_id]; - total_remaining_rbs[CC_id]=N_RB_UL - first_rb[CC_id] - total_allocated_rbs[CC_id]; + for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; + UE_template = &UE_list->UE_template[CC_id][UE_id]; + total_remaining_rbs[CC_id] = + N_RB_UL - first_rb[CC_id] - total_allocated_rbs[CC_id]; - if (total_ue_count == 1 ) { - total_remaining_rbs[CC_id]+=1; - } + if (total_ue_count == 1) { + total_remaining_rbs[CC_id] += 1; + } - if ( r == 0 ) { - while ( (UE_template->pre_allocated_nb_rb_ul > 0 ) && - (nb_allocated_rbs[CC_id][UE_id] < UE_template->pre_allocated_nb_rb_ul) && - (total_remaining_rbs[CC_id] > 0)) { - nb_allocated_rbs[CC_id][UE_id] = cmin(nb_allocated_rbs[CC_id][UE_id]+1,UE_template->pre_allocated_nb_rb_ul); - total_remaining_rbs[CC_id]--; - total_allocated_rbs[CC_id]++; - } - } else { - UE_template->pre_allocated_nb_rb_ul= nb_allocated_rbs[CC_id][UE_id]; - LOG_D(MAC,"******************UL Scheduling Information for UE%d CC_id %d ************************\n",UE_id, CC_id); - LOG_D(MAC,"[eNB %d] total RB allocated for UE%d CC_id %d = %d\n", module_idP, UE_id, CC_id, UE_template->pre_allocated_nb_rb_ul); - } - } + if (r == 0) { + while ((UE_template->pre_allocated_nb_rb_ul > 0) && + (nb_allocated_rbs[CC_id][UE_id] < + UE_template->pre_allocated_nb_rb_ul) + && (total_remaining_rbs[CC_id] > 0)) { + nb_allocated_rbs[CC_id][UE_id] = + cmin(nb_allocated_rbs[CC_id][UE_id] + 1, + UE_template->pre_allocated_nb_rb_ul); + total_remaining_rbs[CC_id]--; + total_allocated_rbs[CC_id]++; + } + } else { + UE_template->pre_allocated_nb_rb_ul = + nb_allocated_rbs[CC_id][UE_id]; + LOG_D(MAC, + "******************UL Scheduling Information for UE%d CC_id %d ************************\n", + UE_id, CC_id); + LOG_D(MAC, + "[eNB %d] total RB allocated for UE%d CC_id %d = %d\n", + module_idP, UE_id, CC_id, + UE_template->pre_allocated_nb_rb_ul); + } + } + } } - } - for (CC_id=0; CC_id0) { - LOG_D(MAC,"[eNB %d] total RB allocated for all UEs = %d/%d\n", module_idP, total_allocated_rbs[CC_id], N_RB_UL - first_rb[CC_id]); + if (total_allocated_rbs[CC_id] > 0) { + LOG_D(MAC, "[eNB %d] total RB allocated for all UEs = %d/%d\n", + module_idP, total_allocated_rbs[CC_id], + N_RB_UL - first_rb[CC_id]); + } } - } } -void assign_max_mcs_min_rb(module_id_t module_idP,int frameP, sub_frame_t subframeP, uint16_t *first_rb) +void +assign_max_mcs_min_rb(module_id_t module_idP, int frameP, + sub_frame_t subframeP, uint16_t * first_rb) { - int i; - uint16_t n,UE_id; - uint8_t CC_id; - rnti_t rnti = -1; - int mcs; - int rb_table_index=0,tbs,tx_power; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - UE_list_t *UE_list = &eNB->UE_list; + int i; + uint16_t n, UE_id; + uint8_t CC_id; + rnti_t rnti = -1; + int mcs; + int rb_table_index = 0, tbs, tx_power; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + UE_list_t *UE_list = &eNB->UE_list; - UE_TEMPLATE *UE_template; - int Ncp; - int N_RB_UL; + UE_TEMPLATE *UE_template; + int Ncp; + int N_RB_UL; - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i] != TRUE) continue; + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (UE_list->active[i] != TRUE) + continue; - rnti = UE_RNTI(module_idP,i); + rnti = UE_RNTI(module_idP, i); - if (rnti==NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; - if (UE_list->UE_sched_ctrl[i].phr_received == 1) - mcs = 20; // if we've received the power headroom information the UE, we can go to maximum mcs - else - mcs = 10; // otherwise, limit to QPSK PUSCH + if (UE_list->UE_sched_ctrl[i].phr_received == 1) + mcs = 20; // if we've received the power headroom information the UE, we can go to maximum mcs + else + mcs = 10; // otherwise, limit to QPSK PUSCH - UE_id = i; + UE_id = i; - for (n=0; nnumactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; + for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; - if (CC_id >= MAX_NUM_CCs) { - LOG_E( MAC, "CC_id %u should be < %u, loop n=%u < numactiveULCCs[%u]=%u", - CC_id, - MAX_NUM_CCs, - n, - UE_id, - UE_list->numactiveULCCs[UE_id]); - } + if (CC_id >= MAX_NUM_CCs) { + LOG_E(MAC, + "CC_id %u should be < %u, loop n=%u < numactiveULCCs[%u]=%u", + CC_id, MAX_NUM_CCs, n, UE_id, + UE_list->numactiveULCCs[UE_id]); + } - AssertFatal( CC_id < MAX_NUM_CCs, "CC_id %u should be < %u, loop n=%u < numactiveULCCs[%u]=%u", - CC_id, - MAX_NUM_CCs, - n, - UE_id, - UE_list->numactiveULCCs[UE_id]); + AssertFatal(CC_id < MAX_NUM_CCs, + "CC_id %u should be < %u, loop n=%u < numactiveULCCs[%u]=%u", + CC_id, MAX_NUM_CCs, n, UE_id, + UE_list->numactiveULCCs[UE_id]); - UE_template = &UE_list->UE_template[CC_id][UE_id]; + UE_template = &UE_list->UE_template[CC_id][UE_id]; - Ncp = RC.mac[module_idP]->common_channels[CC_id].Ncp; - N_RB_UL = to_prb(RC.mac[module_idP]->common_channels[CC_id].ul_Bandwidth); - // if this UE has UL traffic - if (UE_template->ul_total_buffer > 0 ) { + Ncp = RC.mac[module_idP]->common_channels[CC_id].Ncp; + N_RB_UL = + to_prb(RC.mac[module_idP]->common_channels[CC_id]. + ul_Bandwidth); + // if this UE has UL traffic + if (UE_template->ul_total_buffer > 0) { - tbs = get_TBS_UL(mcs,3)<<3; // 1 or 2 PRB with cqi enabled does not work well! - rb_table_index = 2; + tbs = get_TBS_UL(mcs, 3) << 3; // 1 or 2 PRB with cqi enabled does not work well! + rb_table_index = 2; - // fixme: set use_srs flag - tx_power= estimate_ue_tx_power(tbs,rb_table[rb_table_index],0,Ncp,0); + // fixme: set use_srs flag + tx_power = + estimate_ue_tx_power(tbs, rb_table[rb_table_index], 0, + Ncp, 0); - while ((((UE_template->phr_info - tx_power) < 0 ) || (tbs > UE_template->ul_total_buffer))&& - (mcs > 3)) { - // LOG_I(MAC,"UE_template->phr_info %d tx_power %d mcs %d\n", UE_template->phr_info,tx_power, mcs); - mcs--; - tbs = get_TBS_UL(mcs,rb_table[rb_table_index])<<3; - tx_power = estimate_ue_tx_power(tbs,rb_table[rb_table_index],0,Ncp,0); // fixme: set use_srs - } + while ((((UE_template->phr_info - tx_power) < 0) + || (tbs > UE_template->ul_total_buffer)) + && (mcs > 3)) { + // LOG_I(MAC,"UE_template->phr_info %d tx_power %d mcs %d\n", UE_template->phr_info,tx_power, mcs); + mcs--; + tbs = get_TBS_UL(mcs, rb_table[rb_table_index]) << 3; + tx_power = estimate_ue_tx_power(tbs, rb_table[rb_table_index], 0, Ncp, 0); // fixme: set use_srs + } - while ((tbs < UE_template->ul_total_buffer) && - (rb_table[rb_table_index]<(N_RB_UL-first_rb[CC_id])) && - ((UE_template->phr_info - tx_power) > 0) && - (rb_table_index < 32 )) { - - rb_table_index++; - tbs = get_TBS_UL(mcs,rb_table[rb_table_index])<<3; - tx_power = estimate_ue_tx_power(tbs,rb_table[rb_table_index],0,Ncp,0); - } + while ((tbs < UE_template->ul_total_buffer) && + (rb_table[rb_table_index] < + (N_RB_UL - first_rb[CC_id])) + && ((UE_template->phr_info - tx_power) > 0) + && (rb_table_index < 32)) { - UE_template->ue_tx_power = tx_power; + rb_table_index++; + tbs = get_TBS_UL(mcs, rb_table[rb_table_index]) << 3; + tx_power = + estimate_ue_tx_power(tbs, rb_table[rb_table_index], + 0, Ncp, 0); + } - if (rb_table[rb_table_index]>(N_RB_UL-first_rb[CC_id]-1)) { - rb_table_index--; - } + UE_template->ue_tx_power = tx_power; - // 1 or 2 PRB with cqi enabled does not work well - if (rb_table[rb_table_index]<3) { - rb_table_index=2; //3PRB - } + if (rb_table[rb_table_index] > + (N_RB_UL - first_rb[CC_id] - 1)) { + rb_table_index--; + } + // 1 or 2 PRB with cqi enabled does not work well + if (rb_table[rb_table_index] < 3) { + rb_table_index = 2; //3PRB + } - UE_template->pre_assigned_mcs_ul=mcs; - UE_template->pre_allocated_rb_table_index_ul=rb_table_index; - UE_template->pre_allocated_nb_rb_ul= rb_table[rb_table_index]; - LOG_D(MAC,"[eNB %d] frame %d subframe %d: for UE %d CC %d: pre-assigned mcs %d, pre-allocated rb_table[%d]=%d RBs (phr %d, tx power %d)\n", - module_idP, frameP, subframeP, UE_id, CC_id, - UE_template->pre_assigned_mcs_ul, - UE_template->pre_allocated_rb_table_index_ul, - UE_template->pre_allocated_nb_rb_ul, - UE_template->phr_info,tx_power); - } else { - /* if UE has pending scheduling request then pre-allocate 3 RBs */ - //if (UE_template->ul_active == 1 && UE_template->ul_SR == 1) { - if (UE_is_to_be_scheduled(module_idP, CC_id, i)) { - /* use QPSK mcs */ - UE_template->pre_assigned_mcs_ul = 10; - UE_template->pre_allocated_rb_table_index_ul = 2; - UE_template->pre_allocated_nb_rb_ul = 3; - } else { - UE_template->pre_assigned_mcs_ul = 0; - UE_template->pre_allocated_rb_table_index_ul = -1; - UE_template->pre_allocated_nb_rb_ul = 0; - } - } + UE_template->pre_assigned_mcs_ul = mcs; + UE_template->pre_allocated_rb_table_index_ul = + rb_table_index; + UE_template->pre_allocated_nb_rb_ul = + rb_table[rb_table_index]; + LOG_D(MAC, + "[eNB %d] frame %d subframe %d: for UE %d CC %d: pre-assigned mcs %d, pre-allocated rb_table[%d]=%d RBs (phr %d, tx power %d)\n", + module_idP, frameP, subframeP, UE_id, CC_id, + UE_template->pre_assigned_mcs_ul, + UE_template->pre_allocated_rb_table_index_ul, + UE_template->pre_allocated_nb_rb_ul, + UE_template->phr_info, tx_power); + } else { + /* if UE has pending scheduling request then pre-allocate 3 RBs */ + //if (UE_template->ul_active == 1 && UE_template->ul_SR == 1) { + if (UE_is_to_be_scheduled(module_idP, CC_id, i)) { + /* use QPSK mcs */ + UE_template->pre_assigned_mcs_ul = 10; + UE_template->pre_allocated_rb_table_index_ul = 2; + UE_template->pre_allocated_nb_rb_ul = 3; + } else { + UE_template->pre_assigned_mcs_ul = 0; + UE_template->pre_allocated_rb_table_index_ul = -1; + UE_template->pre_allocated_nb_rb_ul = 0; + } + } + } } - } } struct sort_ue_ul_params { - int module_idP; - int frameP; - int subframeP; + int module_idP; + int frameP; + int subframeP; }; static int ue_ul_compare(const void *_a, const void *_b, void *_params) { - struct sort_ue_ul_params *params = _params; - UE_list_t *UE_list = &RC.mac[params->module_idP]->UE_list; + struct sort_ue_ul_params *params = _params; + UE_list_t *UE_list = &RC.mac[params->module_idP]->UE_list; - int UE_id1 = *(const int *)_a; - int UE_id2 = *(const int *)_b; + int UE_id1 = *(const int *) _a; + int UE_id2 = *(const int *) _b; - int rnti1 = UE_RNTI(params->module_idP, UE_id1); - int pCCid1 = UE_PCCID(params->module_idP, UE_id1); - int round1 = maxround(params->module_idP, rnti1, params->frameP, params->subframeP, 1); + int rnti1 = UE_RNTI(params->module_idP, UE_id1); + int pCCid1 = UE_PCCID(params->module_idP, UE_id1); + int round1 = maxround(params->module_idP, rnti1, params->frameP, + params->subframeP, 1); - int rnti2 = UE_RNTI(params->module_idP, UE_id2); - int pCCid2 = UE_PCCID(params->module_idP, UE_id2); - int round2 = maxround(params->module_idP, rnti2, params->frameP, params->subframeP, 1); + int rnti2 = UE_RNTI(params->module_idP, UE_id2); + int pCCid2 = UE_PCCID(params->module_idP, UE_id2); + int round2 = maxround(params->module_idP, rnti2, params->frameP, + params->subframeP, 1); - if (round1 > round2) return -1; - if (round1 < round2) return 1; + if (round1 > round2) + return -1; + if (round1 < round2) + return 1; - if (UE_list->UE_template[pCCid1][UE_id1].ul_buffer_info[LCGID0] > UE_list->UE_template[pCCid2][UE_id2].ul_buffer_info[LCGID0]) - return -1; - if (UE_list->UE_template[pCCid1][UE_id1].ul_buffer_info[LCGID0] < UE_list->UE_template[pCCid2][UE_id2].ul_buffer_info[LCGID0]) - return 1; + if (UE_list->UE_template[pCCid1][UE_id1].ul_buffer_info[LCGID0] > + UE_list->UE_template[pCCid2][UE_id2].ul_buffer_info[LCGID0]) + return -1; + if (UE_list->UE_template[pCCid1][UE_id1].ul_buffer_info[LCGID0] < + UE_list->UE_template[pCCid2][UE_id2].ul_buffer_info[LCGID0]) + return 1; - if (UE_list->UE_template[pCCid1][UE_id1].ul_total_buffer > UE_list->UE_template[pCCid2][UE_id2].ul_total_buffer) - return -1; - if (UE_list->UE_template[pCCid1][UE_id1].ul_total_buffer < UE_list->UE_template[pCCid2][UE_id2].ul_total_buffer) - return 1; + if (UE_list->UE_template[pCCid1][UE_id1].ul_total_buffer > + UE_list->UE_template[pCCid2][UE_id2].ul_total_buffer) + return -1; + if (UE_list->UE_template[pCCid1][UE_id1].ul_total_buffer < + UE_list->UE_template[pCCid2][UE_id2].ul_total_buffer) + return 1; - if (UE_list->UE_template[pCCid1][UE_id1].pre_assigned_mcs_ul > UE_list->UE_template[pCCid2][UE_id2].pre_assigned_mcs_ul) - return -1; - if (UE_list->UE_template[pCCid1][UE_id1].pre_assigned_mcs_ul < UE_list->UE_template[pCCid2][UE_id2].pre_assigned_mcs_ul) - return 1; + if (UE_list->UE_template[pCCid1][UE_id1].pre_assigned_mcs_ul > + UE_list->UE_template[pCCid2][UE_id2].pre_assigned_mcs_ul) + return -1; + if (UE_list->UE_template[pCCid1][UE_id1].pre_assigned_mcs_ul < + UE_list->UE_template[pCCid2][UE_id2].pre_assigned_mcs_ul) + return 1; - return 0; + return 0; #if 0 - /* The above order derives from the following. - * The last case is not handled: "if (UE_list->UE_template[pCCid2][UE_id2].ul_total_buffer > 0 )" - * I don't think it makes a big difference. - */ - if(round2 > round1) { - swap_UEs(UE_list,UE_id1,UE_id2,1); - } else if (round2 == round1) { - if (UE_list->UE_template[pCCid1][UE_id1].ul_buffer_info[LCGID0] < UE_list->UE_template[pCCid2][UE_id2].ul_buffer_info[LCGID0]) { - swap_UEs(UE_list,UE_id1,UE_id2,1); - } else if (UE_list->UE_template[pCCid1][UE_id1].ul_total_buffer < UE_list->UE_template[pCCid2][UE_id2].ul_total_buffer) { - swap_UEs(UE_list,UE_id1,UE_id2,1); - } else if (UE_list->UE_template[pCCid1][UE_id1].pre_assigned_mcs_ul < UE_list->UE_template[pCCid2][UE_id2].pre_assigned_mcs_ul) { - if (UE_list->UE_template[pCCid2][UE_id2].ul_total_buffer > 0 ) { - swap_UEs(UE_list,UE_id1,UE_id2,1); - } - } - } + /* The above order derives from the following. + * The last case is not handled: "if (UE_list->UE_template[pCCid2][UE_id2].ul_total_buffer > 0 )" + * I don't think it makes a big difference. + */ + if (round2 > round1) { + swap_UEs(UE_list, UE_id1, UE_id2, 1); + } else if (round2 == round1) { + if (UE_list->UE_template[pCCid1][UE_id1].ul_buffer_info[LCGID0] < + UE_list->UE_template[pCCid2][UE_id2].ul_buffer_info[LCGID0]) { + swap_UEs(UE_list, UE_id1, UE_id2, 1); + } else if (UE_list->UE_template[pCCid1][UE_id1].ul_total_buffer < + UE_list->UE_template[pCCid2][UE_id2].ul_total_buffer) { + swap_UEs(UE_list, UE_id1, UE_id2, 1); + } else if (UE_list->UE_template[pCCid1][UE_id1]. + pre_assigned_mcs_ul < + UE_list->UE_template[pCCid2][UE_id2]. + pre_assigned_mcs_ul) { + if (UE_list->UE_template[pCCid2][UE_id2].ul_total_buffer > 0) { + swap_UEs(UE_list, UE_id1, UE_id2, 1); + } + } + } #endif } -void sort_ue_ul (module_id_t module_idP,int frameP, sub_frame_t subframeP) +void sort_ue_ul(module_id_t module_idP, int frameP, sub_frame_t subframeP) { - int i; - int list[NUMBER_OF_UE_MAX]; - int list_size = 0; - int rnti; - struct sort_ue_ul_params params = { module_idP, frameP, subframeP }; - - UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; - - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i] == FALSE) continue; - if ((rnti = UE_RNTI(module_idP, i)) == NOT_A_RNTI) continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) continue; - - list[list_size] = i; - list_size++; - } - - qsort_r(list, list_size, sizeof(int), ue_ul_compare, ¶ms); - - if (list_size) { - for (i = 0; i < list_size-1; i++) - UE_list->next_ul[list[i]] = list[i+1]; - UE_list->next_ul[list[list_size-1]] = -1; - UE_list->head_ul = list[0]; - } else { - UE_list->head_ul = -1; - } + int i; + int list[NUMBER_OF_UE_MAX]; + int list_size = 0; + int rnti; + struct sort_ue_ul_params params = { module_idP, frameP, subframeP }; + UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; + + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (UE_list->active[i] == FALSE) + continue; + if ((rnti = UE_RNTI(module_idP, i)) == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + + list[list_size] = i; + list_size++; + } + + qsort_r(list, list_size, sizeof(int), ue_ul_compare, ¶ms); + + if (list_size) { + for (i = 0; i < list_size - 1; i++) + UE_list->next_ul[list[i]] = list[i + 1]; + UE_list->next_ul[list[list_size - 1]] = -1; + UE_list->head_ul = list[0]; + } else { + UE_list->head_ul = -1; + } + #if 0 - int UE_id1,UE_id2; - int pCCid1,pCCid2; - int round1,round2; - int i=0,ii=0; - rnti_t rnti1,rnti2; - - UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; - - for (i=UE_list->head_ul; i>=0; i=UE_list->next_ul[i]) { - - //LOG_I(MAC,"sort ue ul i %d\n",i); - for (ii=UE_list->next_ul[i]; ii>=0; ii=UE_list->next_ul[ii]) { - //LOG_I(MAC,"sort ul ue 2 ii %d\n",ii); - - UE_id1 = i; - rnti1 = UE_RNTI(module_idP,UE_id1); - - if(rnti1 == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - - - pCCid1 = UE_PCCID(module_idP,UE_id1); - round1 = maxround(module_idP,rnti1,frameP,subframeP,1); - - UE_id2 = ii; - rnti2 = UE_RNTI(module_idP,UE_id2); - - if(rnti2 == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[UE_id2].ul_out_of_sync == 1) - continue; - - pCCid2 = UE_PCCID(module_idP,UE_id2); - round2 = maxround(module_idP,rnti2,frameP,subframeP,1); - - if(round2 > round1) { - swap_UEs(UE_list,UE_id1,UE_id2,1); - } else if (round2 == round1) { - if (UE_list->UE_template[pCCid1][UE_id1].ul_buffer_info[LCGID0] < UE_list->UE_template[pCCid2][UE_id2].ul_buffer_info[LCGID0]) { - swap_UEs(UE_list,UE_id1,UE_id2,1); - } else if (UE_list->UE_template[pCCid1][UE_id1].ul_total_buffer < UE_list->UE_template[pCCid2][UE_id2].ul_total_buffer) { - swap_UEs(UE_list,UE_id1,UE_id2,1); - } else if (UE_list->UE_template[pCCid1][UE_id1].pre_assigned_mcs_ul < UE_list->UE_template[pCCid2][UE_id2].pre_assigned_mcs_ul) { - if (UE_list->UE_template[pCCid2][UE_id2].ul_total_buffer > 0 ) { - swap_UEs(UE_list,UE_id1,UE_id2,1); - } - } - } + int UE_id1, UE_id2; + int pCCid1, pCCid2; + int round1, round2; + int i = 0, ii = 0; + rnti_t rnti1, rnti2; + + UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; + + for (i = UE_list->head_ul; i >= 0; i = UE_list->next_ul[i]) { + + //LOG_I(MAC,"sort ue ul i %d\n",i); + for (ii = UE_list->next_ul[i]; ii >= 0; ii = UE_list->next_ul[ii]) { + //LOG_I(MAC,"sort ul ue 2 ii %d\n",ii); + + UE_id1 = i; + rnti1 = UE_RNTI(module_idP, UE_id1); + + if (rnti1 == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + + + pCCid1 = UE_PCCID(module_idP, UE_id1); + round1 = maxround(module_idP, rnti1, frameP, subframeP, 1); + + UE_id2 = ii; + rnti2 = UE_RNTI(module_idP, UE_id2); + + if (rnti2 == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[UE_id2].ul_out_of_sync == 1) + continue; + + pCCid2 = UE_PCCID(module_idP, UE_id2); + round2 = maxround(module_idP, rnti2, frameP, subframeP, 1); + + if (round2 > round1) { + swap_UEs(UE_list, UE_id1, UE_id2, 1); + } else if (round2 == round1) { + if (UE_list-> + UE_template[pCCid1][UE_id1].ul_buffer_info[LCGID0] < + UE_list->UE_template[pCCid2][UE_id2]. + ul_buffer_info[LCGID0]) { + swap_UEs(UE_list, UE_id1, UE_id2, 1); + } else if (UE_list->UE_template[pCCid1][UE_id1]. + ul_total_buffer < + UE_list->UE_template[pCCid2][UE_id2]. + ul_total_buffer) { + swap_UEs(UE_list, UE_id1, UE_id2, 1); + } else if (UE_list-> + UE_template[pCCid1][UE_id1].pre_assigned_mcs_ul + < + UE_list-> + UE_template[pCCid2][UE_id2].pre_assigned_mcs_ul) + { + if (UE_list->UE_template[pCCid2][UE_id2]. + ul_total_buffer > 0) { + swap_UEs(UE_list, UE_id1, UE_id2, 1); + } + } + } + } } - } #endif } diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index b316cbfeeb..bbd6d6a36d 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -43,12 +43,11 @@ */ -void schedule_mib(module_id_t module_idP, - frame_t frameP, - sub_frame_t subframeP); +void schedule_mib(module_id_t module_idP, + frame_t frameP, sub_frame_t subframeP); /** \fn void schedule_RA(module_id_t module_idP,frame_t frameP,sub_frame_t subframe); -\brief First stage of Random-Access Scheduling. Loops over the RA_templates and checks if RAR, Msg3 or its retransmission are to be scheduled in the subframe. It returns the total number of PRB used for RA SDUs. For Msg3 it retrieves the L3msg from RRC and fills the appropriate buffers. For the others it just computes the number of PRBs. Each DCI uses 3 PRBs (format 1A) +\brief First stage of Random-Access Scheduling. Loops over the ras and checks if RAR, Msg3 or its retransmission are to be scheduled in the subframe. It returns the total number of PRB used for RA SDUs. For Msg3 it retrieves the L3msg from RRC and fills the appropriate buffers. For the others it just computes the number of PRBs. Each DCI uses 3 PRBs (format 1A) for the message. @param Mod_id Instance ID of eNB @param frame Frame index @@ -56,28 +55,32 @@ for the message. */ -void schedule_RA(module_id_t module_idP,frame_t frameP,sub_frame_t subframe); +void schedule_RA(module_id_t module_idP, frame_t frameP, + sub_frame_t subframe); /** \brief First stage of SI Scheduling. Gets a SI SDU from RRC if available and computes the MCS required to transport it as a function of the SDU length. It assumes a length less than or equal to 64 bytes (MCS 6, 3 PRBs). @param Mod_id Instance ID of eNB @param frame Frame index @param subframe Subframe number on which to act */ -void schedule_SI(module_id_t module_idP,frame_t frameP,sub_frame_t subframeP); +void schedule_SI(module_id_t module_idP, frame_t frameP, + sub_frame_t subframeP); /** \brief MBMS scheduling: Checking the position for MBSFN subframes. Create MSI, transfer MCCH from RRC to MAC, transfer MTCHs from RLC to MAC. Multiplexing MSI,MCCH&MTCHs. Return 1 if there are MBSFN data being allocated, otherwise return 0; @param Mod_id Instance ID of eNB @param frame Frame index @param subframe Subframe number on which to act */ -int schedule_MBMS(module_id_t module_idP,uint8_t CC_id, frame_t frameP, sub_frame_t subframe); +int schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP, + sub_frame_t subframe); /** \brief check the mapping between sf allocation and sync area, Currently only supports 1:1 mapping @param Mod_id Instance ID of eNB @param mbsfn_sync_area index of mbsfn sync area @param[out] index of sf pattern */ -int8_t get_mbsfn_sf_alloction (module_id_t module_idP, uint8_t CC_id, uint8_t mbsfn_sync_area); +int8_t get_mbsfn_sf_alloction(module_id_t module_idP, uint8_t CC_id, + uint8_t mbsfn_sync_area); /** \brief check the mapping between sf allocation and sync area, Currently only supports 1:1 mapping @param Mod_id Instance ID of eNB @@ -85,14 +88,17 @@ int8_t get_mbsfn_sf_alloction (module_id_t module_idP, uint8_t CC_id, uint8_t mb @param eNB_index index of eNB @param[out] index of sf pattern */ -int8_t ue_get_mbsfn_sf_alloction (module_id_t module_idP, uint8_t mbsfn_sync_area, unsigned char eNB_index); +int8_t ue_get_mbsfn_sf_alloction(module_id_t module_idP, + uint8_t mbsfn_sync_area, + unsigned char eNB_index); /** \brief top ULSCH Scheduling for TDD (config 1-6). @param Mod_id Instance ID of eNB @param frame Frame index @param subframe Subframe number on which to act */ -void schedule_ulsch(module_id_t module_idP,frame_t frameP,sub_frame_t subframe); +void schedule_ulsch(module_id_t module_idP, frame_t frameP, + sub_frame_t subframe); /** \brief ULSCH Scheduling per RNTI @param Mod_id Instance ID of eNB @@ -100,7 +106,10 @@ void schedule_ulsch(module_id_t module_idP,frame_t frameP,sub_frame_t subframe); @param subframe Subframe number on which to act @param sched_subframe Subframe number where PUSCH is transmitted (for DAI lookup) */ -void schedule_ulsch_rnti(module_id_t module_idP, frame_t frameP, sub_frame_t subframe, unsigned char sched_subframe, uint16_t *first_rb); +void schedule_ulsch_rnti(module_id_t module_idP, frame_t frameP, + sub_frame_t subframe, + unsigned char sched_subframe, + uint16_t * first_rb); /** \brief Second stage of DLSCH scheduling, after schedule_SI, schedule_RA and schedule_dlsch have been called. This routine first allocates random frequency assignments for SI and RA SDUs using distributed VRB allocations and adds the corresponding DCI SDU to the DCI buffer for PHY. It then loops over the UE specific DCIs previously allocated and fills in the remaining DCI fields related to frequency allocation. It assumes localized allocation of type 0 (DCI.rah=0). The allocation is done for tranmission modes 1,2,4. @param Mod_id Instance of eNB @@ -108,7 +117,8 @@ void schedule_ulsch_rnti(module_id_t module_idP, frame_t frameP, sub_frame_t sub @param subframe Index of subframe @param mbsfn_flag Indicates that this subframe is for MCH/MCCH */ -void fill_DLSCH_dci(module_id_t module_idP,frame_t frameP,sub_frame_t subframe,int *mbsfn_flag); +void fill_DLSCH_dci(module_id_t module_idP, frame_t frameP, + sub_frame_t subframe, int *mbsfn_flag); /** \brief UE specific DLSCH scheduling. Retrieves next ue to be schduled from round-robin scheduler and gets the appropriate harq_pid for the subframe from PHY. If the process is active and requires a retransmission, it schedules the retransmission with the same PRB count and MCS as the first transmission. Otherwise it consults RLC for DCCH/DTCH SDUs (status with maximum number of available PRBS), builds the MAC header (timing advance sent by default) and copies @param Mod_id Instance ID of eNB @@ -117,39 +127,43 @@ void fill_DLSCH_dci(module_id_t module_idP,frame_t frameP,sub_frame_t subframe,i @param mbsfn_flag Indicates that MCH/MCCH is in this subframe */ -void schedule_ue_spec(module_id_t module_idP,frame_t frameP,sub_frame_t subframe,int *mbsfn_flag); +void schedule_ue_spec(module_id_t module_idP, frame_t frameP, + sub_frame_t subframe, int *mbsfn_flag); /** \brief Function for UE/PHY to compute PUSCH transmit power in power-control procedure. @param Mod_id Module id of UE @returns Po_NOMINAL_PUSCH (PREAMBLE_RECEIVED_TARGET_POWER+DELTA_PREAMBLE */ -int8_t get_Po_NOMINAL_PUSCH(module_id_t module_idP,uint8_t CC_id); +int8_t get_Po_NOMINAL_PUSCH(module_id_t module_idP, uint8_t CC_id); /** \brief Function to compute DELTA_PREAMBLE from 36.321 (for RA power ramping procedure and Msg3 PUSCH power control policy) @param Mod_id Module id of UE @returns DELTA_PREAMBLE */ -int8_t get_DELTA_PREAMBLE(module_id_t module_idP,int CC_id); +int8_t get_DELTA_PREAMBLE(module_id_t module_idP, int CC_id); /** \brief Function for compute deltaP_rampup from 36.321 (for RA power ramping procedure and Msg3 PUSCH power control policy) @param Mod_id Module id of UE @param CC_id carrier component id of UE @returns deltaP_rampup */ -int8_t get_deltaP_rampup(module_id_t module_idP,uint8_t CC_id); +int8_t get_deltaP_rampup(module_id_t module_idP, uint8_t CC_id); -uint16_t mac_computeRIV(uint16_t N_RB_DL,uint16_t RBstart,uint16_t Lcrbs); +uint16_t mac_computeRIV(uint16_t N_RB_DL, uint16_t RBstart, + uint16_t Lcrbs); -void add_msg3(module_id_t module_idP,int CC_id, RA_TEMPLATE *RA_template, frame_t frameP, sub_frame_t subframeP); +void add_msg3(module_id_t module_idP, int CC_id, RA_t * ra, frame_t frameP, + sub_frame_t subframeP); //main.c -int mac_top_init(int eMBMS_active, char *uecap_xer,uint8_t cba_group_active, uint8_t HO_active); +int mac_top_init(int eMBMS_active, char *uecap_xer, + uint8_t cba_group_active, uint8_t HO_active); void mac_top_init_eNB(void); -void mac_init_cell_params(int Mod_idP,int CC_idP); +void mac_init_cell_params(int Mod_idP, int CC_idP); char layer2_init_UE(module_id_t module_idP); @@ -161,19 +175,29 @@ int mac_init_global_param(void); void mac_top_cleanup(void); -void mac_UE_out_of_sync_ind(module_id_t module_idP,frame_t frameP, uint16_t eNB_index); +void mac_UE_out_of_sync_ind(module_id_t module_idP, frame_t frameP, + uint16_t eNB_index); -void clear_nfapi_information(eNB_MAC_INST *eNB,int CC_idP,frame_t frameP,sub_frame_t subframeP); +void clear_nfapi_information(eNB_MAC_INST * eNB, int CC_idP, + frame_t frameP, sub_frame_t subframeP); -void dlsch_scheduler_pre_processor_reset (int module_idP,int UE_id, - uint8_t CC_id, - int frameP, - int subframeP, - int N_RBG, - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], - unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]); +void dlsch_scheduler_pre_processor_reset(int module_idP, int UE_id, + uint8_t CC_id, + int frameP, + int subframeP, + int N_RBG, + uint16_t + nb_rbs_required[MAX_NUM_CCs] + [NUMBER_OF_UE_MAX], + uint16_t + nb_rbs_required_remaining + [MAX_NUM_CCs][NUMBER_OF_UE_MAX], + unsigned char + rballoc_sub[MAX_NUM_CCs] + [N_RBG_MAX], + unsigned char + MIMO_mode_indicator[MAX_NUM_CCs] + [N_RBG_MAX]); // eNB functions /* \brief This function assigns pre-available RBS to each UE in specified sub-bands before scheduling is done @@ -184,24 +208,33 @@ void dlsch_scheduler_pre_processor_reset (int module_idP,int UE_id, */ -void dlsch_scheduler_pre_processor (module_id_t module_idP, - frame_t frameP, - sub_frame_t subframe, - int N_RBG[MAX_NUM_CCs], - int *mbsfn_flag); +void dlsch_scheduler_pre_processor(module_id_t module_idP, + frame_t frameP, + sub_frame_t subframe, + int N_RBG[MAX_NUM_CCs], + int *mbsfn_flag); -void dlsch_scheduler_pre_processor_allocate (module_id_t Mod_id, - int UE_id, - uint8_t CC_id, - int N_RBG, - int transmission_mode, - int min_rb_unit, - uint8_t N_RB_DL, - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], - unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]); +void dlsch_scheduler_pre_processor_allocate(module_id_t Mod_id, + int UE_id, + uint8_t CC_id, + int N_RBG, + int transmission_mode, + int min_rb_unit, + uint8_t N_RB_DL, + uint16_t + nb_rbs_required[MAX_NUM_CCs] + [NUMBER_OF_UE_MAX], + uint16_t + nb_rbs_required_remaining + [MAX_NUM_CCs] + [NUMBER_OF_UE_MAX], + unsigned char + rballoc_sub[MAX_NUM_CCs] + [N_RBG_MAX], + unsigned char + MIMO_mode_indicator + [MAX_NUM_CCs][N_RBG_MAX]); /* \brief Function to trigger the eNB scheduling procedure. It is called by PHY at the beginning of each subframe, \f$n$\f and generates all DLSCH allocations for subframe \f$n\f$ and ULSCH allocations for subframe \f$n+k$\f. @@ -209,7 +242,7 @@ void dlsch_scheduler_pre_processor_allocate (module_id_t Mod_id, @param subframe Index of current subframe @param calibration_flag Flag to indicate that eNB scheduler should schedule TDD auto-calibration PUSCH. */ -void eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP);//, int calibration_flag); +void eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP); //, int calibration_flag); /* \brief Function to indicate a received preamble on PRACH. It initiates the RA procedure. @param Mod_id Instance ID of eNB @@ -218,12 +251,13 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, sub_frame @param rnti RA rnti corresponding to this PRACH preamble @param rach_resource type (0=non BL/CE,1 CE level 0,2 CE level 1, 3 CE level 2,4 CE level 3) */ -void initiate_ra_proc(module_id_t module_idP,int CC_id,frame_t frameP, sub_frame_t subframeP, uint16_t preamble_index,int16_t timing_offset,uint16_t rnti +void initiate_ra_proc(module_id_t module_idP, int CC_id, frame_t frameP, + sub_frame_t subframeP, uint16_t preamble_index, + int16_t timing_offset, uint16_t rnti #ifdef Rel14 - , - uint8_t rach_resource_type + , uint8_t rach_resource_type #endif - ); + ); /* \brief Function in eNB to fill RAR pdu when requested by PHY. This provides a single RAR SDU for the moment and returns the t-CRNTI. @param Mod_id Instance ID of eNB @@ -231,31 +265,30 @@ void initiate_ra_proc(module_id_t module_idP,int CC_id,frame_t frameP, sub_frame @param N_RB_UL Number of UL resource blocks @returns t_CRNTI */ -unsigned short fill_rar( - const module_id_t module_idP, - const int CC_id, - const frame_t frameP, - uint8_t * const dlsch_buffer, - const uint16_t N_RB_UL, - const uint8_t input_buffer_length -); +unsigned short fill_rar(const module_id_t module_idP, + const int CC_id, + RA_t *ra, + const frame_t frameP, + uint8_t * const dlsch_buffer, + const uint16_t N_RB_UL, + const uint8_t input_buffer_length); #ifdef Rel14 -unsigned short fill_rar_br(eNB_MAC_INST *eNB, +unsigned short fill_rar_br(eNB_MAC_INST * eNB, int CC_id, - RA_TEMPLATE *RA_template, - const frame_t frameP, - const sub_frame_t subframeP, - uint8_t* const dlsch_buffer, - const uint8_t ce_level - ); + RA_t * ra, + const frame_t frameP, + const sub_frame_t subframeP, + uint8_t * const dlsch_buffer, + const uint8_t ce_level); #endif /* \brief Function to indicate a failed RA response. It removes all temporary variables related to the initial connection of a UE @param Mod_id Instance ID of eNB @param preamble_index index of the received RA request. */ -void cancel_ra_proc(module_id_t module_idP,int CC_id,frame_t frameP, uint16_t preamble_index); +void cancel_ra_proc(module_id_t module_idP, int CC_id, frame_t frameP, + uint16_t preamble_index); /* \brief Function used by PHY to inform MAC that an uplink is scheduled for Msg3 in given subframe. This is used so that the MAC @@ -269,12 +302,10 @@ void cancel_ra_proc(module_id_t module_idP,int CC_id,frame_t frameP, uint16_t pr @param Msg3_subframe subframe where scheduling takes place */ void set_msg3_subframe(module_id_t Mod_id, - int CC_id, - int frame, - int subframe, - int rnti, - int Msg3_frame, - int Msg3_subframe); + int CC_id, + int frame, + int subframe, + int rnti, int Msg3_frame, int Msg3_subframe); /* \brief Function to indicate a received SDU on ULSCH. @param Mod_id Instance ID of eNB @@ -286,14 +317,13 @@ void set_msg3_subframe(module_id_t Mod_id, @param ul_cqi Uplink CQI estimate after this pdu (SNR quantized to 8 bits, -64 ... 63.5 dB in .5dB steps) */ void rx_sdu(const module_id_t enb_mod_idP, - const int CC_idP, - const frame_t frameP, + const int CC_idP, + const frame_t frameP, const sub_frame_t subframeP, - const rnti_t rntiP, - uint8_t *sduP, - const uint16_t sdu_lenP, - const uint16_t timing_advance, - const uint8_t ul_cqi); + const rnti_t rntiP, + uint8_t * sduP, + const uint16_t sdu_lenP, + const uint16_t timing_advance, const uint8_t ul_cqi); /* \brief Function to indicate a scheduled schduling request (SR) was received by eNB. @@ -304,7 +334,8 @@ void rx_sdu(const module_id_t enb_mod_idP, @param rnti RNTI of UE transmitting the SR @param ul_cqi SNR measurement of PUCCH (SNR quantized to 8 bits, -64 ... 63.5 dB in .5dB steps) */ -void SR_indication(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subframe,rnti_t rnti,uint8_t ul_cqi); +void SR_indication(module_id_t module_idP, int CC_id, frame_t frameP, + sub_frame_t subframe, rnti_t rnti, uint8_t ul_cqi); /* \brief Function to indicate a UL failure was detected by eNB PHY. @param Mod_id Instance ID of eNB @@ -313,7 +344,8 @@ void SR_indication(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t s @param rnti RNTI of UE transmitting the SR @param subframe Index of subframe where SR was received */ -void UL_failure_indication(module_id_t Mod_id,int CC_id,frame_t frameP,rnti_t rnti,sub_frame_t subframe); +void UL_failure_indication(module_id_t Mod_id, int CC_id, frame_t frameP, + rnti_t rnti, sub_frame_t subframe); /* \brief Function to indicate an HARQ ACK/NAK. @param Mod_id Instance ID of eNB @@ -322,7 +354,9 @@ void UL_failure_indication(module_id_t Mod_id,int CC_id,frame_t frameP,rnti_t rn @param subframeP subframe index @param harq_pdu NFAPI HARQ PDU descriptor */ -void harq_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, sub_frame_t subframeP, nfapi_harq_indication_pdu_t *harq_pdu); +void harq_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, + sub_frame_t subframeP, + nfapi_harq_indication_pdu_t * harq_pdu); /* \brief Function to indicate a received CQI pdu @param Mod_id Instance ID of eNB @@ -332,11 +366,13 @@ void harq_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, sub_frame_ @param rntiP RNTI of incoming CQI information @param ul_cqi_information NFAPI UL CQI measurement */ -void cqi_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, sub_frame_t subframeP, rnti_t rntiP, - nfapi_cqi_indication_rel9_t *rel9,uint8_t *pdu, - nfapi_ul_cqi_information_t *ul_cqi_information); +void cqi_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, + sub_frame_t subframeP, rnti_t rntiP, + nfapi_cqi_indication_rel9_t * rel9, uint8_t * pdu, + nfapi_ul_cqi_information_t * ul_cqi_information); -uint8_t *get_dlsch_sdu(module_id_t module_idP,int CC_id,frame_t frameP,rnti_t rnti,uint8_t TBindex); +uint8_t *get_dlsch_sdu(module_id_t module_idP, int CC_id, frame_t frameP, + rnti_t rnti, uint8_t TBindex); /* \brief Function to retrieve MCH transport block and MCS used for MCH in this MBSFN subframe. Returns null if no MCH is to be transmitted @param Mod_id Instance ID of eNB @@ -345,69 +381,70 @@ uint8_t *get_dlsch_sdu(module_id_t module_idP,int CC_id,frame_t frameP,rnti_t rn @param mcs Pointer to mcs used by PHY (to be filled by MAC) @returns Pointer to MCH transport block and mcs for subframe */ -MCH_PDU *get_mch_sdu( module_id_t Mod_id, int CC_id, frame_t frame, sub_frame_t subframe); +MCH_PDU *get_mch_sdu(module_id_t Mod_id, int CC_id, frame_t frame, + sub_frame_t subframe); -void ue_mac_reset (module_id_t module_idP,uint8_t eNB_index); -void ue_init_mac (module_id_t module_idP); -void init_ue_sched_info(void); -void add_ue_ulsch_info (module_id_t module_idP, int CC_id, int UE_id, sub_frame_t subframe,UE_ULSCH_STATUS status); -void add_ue_dlsch_info (module_id_t module_idP, int CC_id,int UE_id, sub_frame_t subframe,UE_DLSCH_STATUS status); -int find_UE_id (module_id_t module_idP, rnti_t rnti) ; -int find_RA_id (module_id_t mod_idP, int CC_idP, rnti_t rntiP); -rnti_t UE_RNTI (module_id_t module_idP, int UE_id); -int UE_PCCID (module_id_t module_idP, int UE_id); -uint8_t find_active_UEs (module_id_t module_idP); -boolean_t is_UE_active (module_id_t module_idP, int UE_id); -uint8_t get_aggregation (uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt); +void ue_mac_reset(module_id_t module_idP, uint8_t eNB_index); +void ue_init_mac(module_id_t module_idP); +void init_ue_sched_info(void); +void add_ue_ulsch_info(module_id_t module_idP, int CC_id, int UE_id, + sub_frame_t subframe, UE_ULSCH_STATUS status); +void add_ue_dlsch_info(module_id_t module_idP, int CC_id, int UE_id, + sub_frame_t subframe, UE_DLSCH_STATUS status); +int find_UE_id(module_id_t module_idP, rnti_t rnti); +int find_RA_id(module_id_t mod_idP, int CC_idP, rnti_t rntiP); +rnti_t UE_RNTI(module_id_t module_idP, int UE_id); +int UE_PCCID(module_id_t module_idP, int UE_id); +uint8_t find_active_UEs(module_id_t module_idP); +boolean_t is_UE_active(module_id_t module_idP, int UE_id); +uint8_t get_aggregation(uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt); int8_t find_active_UEs_with_traffic(module_id_t module_idP); -void init_CCE_table(int module_idP,int CC_idP); +void init_CCE_table(int module_idP, int CC_idP); int get_nCCE_offset(int *CCE_table, - const unsigned char L, - const int nCCE, - const int common_dci, - const unsigned short rnti, + const unsigned char L, + const int nCCE, + const int common_dci, + const unsigned short rnti, const unsigned char subframe); -int allocate_CCEs(int module_idP, - int CC_idP, - int subframe, - int test_only); +int allocate_CCEs(int module_idP, int CC_idP, int subframe, int test_only); boolean_t CCE_allocation_infeasible(int module_idP, - int CC_idP, - int common_flag, - int subframe, - int aggregation, - int rnti); + int CC_idP, + int common_flag, + int subframe, + int aggregation, int rnti); -void set_ue_dai(sub_frame_t subframeP, - int UE_id, - uint8_t CC_id, - uint8_t tdd_config, - UE_list_t *UE_list); +void set_ue_dai(sub_frame_t subframeP, + int UE_id, + uint8_t CC_id, uint8_t tdd_config, UE_list_t * UE_list); -uint8_t find_num_active_UEs_in_cbagroup(module_id_t module_idP, unsigned char group_id); -uint8_t UE_is_to_be_scheduled(module_id_t module_idP,int CC_id,uint8_t UE_id); +uint8_t find_num_active_UEs_in_cbagroup(module_id_t module_idP, + unsigned char group_id); +uint8_t UE_is_to_be_scheduled(module_id_t module_idP, int CC_id, + uint8_t UE_id); /** \brief Round-robin scheduler for ULSCH traffic. @param Mod_id Instance ID for eNB @param subframe Subframe number on which to act @returns UE index that is to be scheduled if needed/room */ -module_id_t schedule_next_ulue(module_id_t module_idP, int UE_id,sub_frame_t subframe); +module_id_t schedule_next_ulue(module_id_t module_idP, int UE_id, + sub_frame_t subframe); /** \brief Round-robin scheduler for DLSCH traffic. @param Mod_id Instance ID for eNB @param subframe Subframe number on which to act @returns UE index that is to be scheduled if needed/room */ -int schedule_next_dlue(module_id_t module_idP, int CC_id, sub_frame_t subframe); +int schedule_next_dlue(module_id_t module_idP, int CC_id, + sub_frame_t subframe); /* \brief Allocates a set of PRBS for a particular UE. This is a simple function for the moment, later it should process frequency-domain CQI information and/or PMI information. Currently it just returns the first PRBS that are available in the subframe based on the number requested. @param UE_id Index of UE on which to act @@ -416,7 +453,8 @@ int schedule_next_dlue(module_id_t module_idP, int CC_id, sub_frame_t subframe); @param rballoc Pointer to bit-map of current PRB allocation given to previous users/control channels. This is updated for subsequent calls to the routine. @returns an rballoc bitmap for resource type 0 allocation (DCI). */ -uint32_t allocate_prbs(int UE_id,uint8_t nb_rb, int N_RB_DL, uint32_t *rballoc); +uint32_t allocate_prbs(int UE_id, uint8_t nb_rb, int N_RB_DL, + uint32_t * rballoc); /* \fn uint32_t req_new_ulsch(module_id_t module_idP) \brief check for a new transmission in any drb @@ -433,19 +471,25 @@ uint32_t req_new_ulsch(module_id_t module_idP); @param subframe subframe number @returns 0 for no SR, 1 for SR */ -uint32_t ue_get_SR(module_id_t module_idP, int CC_id,frame_t frameP, uint8_t eNB_id,rnti_t rnti,sub_frame_t subframe); +uint32_t ue_get_SR(module_id_t module_idP, int CC_id, frame_t frameP, + uint8_t eNB_id, rnti_t rnti, sub_frame_t subframe); uint8_t get_ue_weight(module_id_t module_idP, int CC_id, int UE_id); // UE functions -void mac_out_of_sync_ind(module_id_t module_idP, frame_t frameP, uint16_t CH_index); +void mac_out_of_sync_ind(module_id_t module_idP, frame_t frameP, + uint16_t CH_index); -void ue_decode_si(module_id_t module_idP, int CC_id,frame_t frame, uint8_t CH_index, void *pdu, uint16_t len); +void ue_decode_si(module_id_t module_idP, int CC_id, frame_t frame, + uint8_t CH_index, void *pdu, uint16_t len); -void ue_decode_p(module_id_t module_idP, int CC_id,frame_t frame, uint8_t CH_index, void *pdu, uint16_t len); +void ue_decode_p(module_id_t module_idP, int CC_id, frame_t frame, + uint8_t CH_index, void *pdu, uint16_t len); -void ue_send_sdu(module_id_t module_idP, uint8_t CC_id,frame_t frame, sub_frame_t subframe, uint8_t *sdu,uint16_t sdu_len,uint8_t CH_index); +void ue_send_sdu(module_id_t module_idP, uint8_t CC_id, frame_t frame, + sub_frame_t subframe, uint8_t * sdu, uint16_t sdu_len, + uint8_t CH_index); #if defined(Rel10) || defined(Rel14) @@ -457,7 +501,9 @@ void ue_send_sdu(module_id_t module_idP, uint8_t CC_id,frame_t frame, sub_frame_ @param eNB_index Index of attached eNB @param sync_area the index of MBSFN sync area */ -void ue_send_mch_sdu(module_id_t module_idP,uint8_t CC_id, frame_t frameP,uint8_t *sdu,uint16_t sdu_len,uint8_t eNB_index,uint8_t sync_area) ; +void ue_send_mch_sdu(module_id_t module_idP, uint8_t CC_id, frame_t frameP, + uint8_t * sdu, uint16_t sdu_len, uint8_t eNB_index, + uint8_t sync_area); /*\brief Function to check if UE PHY needs to decode MCH for MAC. @param Mod_id Index of protocol instance @@ -467,7 +513,9 @@ void ue_send_mch_sdu(module_id_t module_idP,uint8_t CC_id, frame_t frameP,uint8_ @param[out] sync_area return the sync area @param[out] mcch_active flag indicating whether this MCCH is active in this SF */ -int ue_query_mch(uint8_t Mod_id,uint8_t CC_id, uint32_t frame,sub_frame_t subframe, uint8_t eNB_index, uint8_t *sync_area, uint8_t *mcch_active); +int ue_query_mch(uint8_t Mod_id, uint8_t CC_id, uint32_t frame, + sub_frame_t subframe, uint8_t eNB_index, + uint8_t * sync_area, uint8_t * mcch_active); #endif @@ -478,7 +526,10 @@ int ue_query_mch(uint8_t Mod_id,uint8_t CC_id, uint32_t frame,sub_frame_t subfra @param subframe subframe number @returns 0 for no SR, 1 for SR */ -void ue_get_sdu(module_id_t module_idP, int CC_id,frame_t frameP, sub_frame_t subframe, uint8_t eNB_index,uint8_t *ulsch_buffer,uint16_t buflen,uint8_t *access_mode); +void ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP, + sub_frame_t subframe, uint8_t eNB_index, + uint8_t * ulsch_buffer, uint16_t buflen, + uint8_t * access_mode); /* \brief Function called by PHY to retrieve information to be transmitted using the RA procedure. If the UE is not in PUSCH mode for a particular eNB index, this is assumed to be an Msg3 and MAC attempts to retrieves the CCCH message from RRC. If the UE is in PUSCH mode for a particular eNB index and PUCCH format 0 (Scheduling Request) is not activated, the MAC may use this resource for random-access to transmit a BSR along with the C-RNTI control element (see 5.1.4 from 36.321) @param Mod_id Index of UE instance @@ -486,7 +537,9 @@ void ue_get_sdu(module_id_t module_idP, int CC_id,frame_t frameP, sub_frame_t su @param New_Msg3 Flag to indicate this call is for a new Msg3 @param subframe Index of subframe for PRACH transmission (0 ... 9) @returns A pointer to a PRACH_RESOURCES_t */ -PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP,uint8_t new_Msg3,sub_frame_t subframe); +PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP, int CC_id, + frame_t frameP, uint8_t new_Msg3, + sub_frame_t subframe); /* \brief Function called by PHY to process the received RAR. It checks that the preamble matches what was sent by the eNB and provides the timing advance and t-CRNTI. @param Mod_id Index of UE instance @@ -501,16 +554,14 @@ random-access procedure @returns timing advance or 0xffff if preamble doesn't match */ uint16_t -ue_process_rar( - const module_id_t module_idP, - const int CC_id, - const frame_t frameP, - const rnti_t ra_rnti, - uint8_t * const dlsch_buffer, - rnti_t * const t_crnti, - const uint8_t preamble_index, - uint8_t* selected_rar_buffer -); +ue_process_rar(const module_id_t module_idP, + const int CC_id, + const frame_t frameP, + const rnti_t ra_rnti, + uint8_t * const dlsch_buffer, + rnti_t * const t_crnti, + const uint8_t preamble_index, + uint8_t * selected_rar_buffer); /* \brief Generate header for UL-SCH. This function parses the desired control elements and sdus and generates the header as described @@ -529,17 +580,17 @@ in the ULSCH buffer. @param post_padding Number of bytes for padding at the end of MAC PDU @returns Number of bytes used for header */ -unsigned char generate_ulsch_header(uint8_t *mac_header, - uint8_t num_sdus, - uint8_t short_padding, - uint16_t *sdu_lengths, - uint8_t *sdu_lcids, - POWER_HEADROOM_CMD *power_headroom, - uint16_t *crnti, - BSR_SHORT *truncated_bsr, - BSR_SHORT *short_bsr, - BSR_LONG *long_bsr, - unsigned short post_padding); +unsigned char generate_ulsch_header(uint8_t * mac_header, + uint8_t num_sdus, + uint8_t short_padding, + uint16_t * sdu_lengths, + uint8_t * sdu_lcids, + POWER_HEADROOM_CMD * power_headroom, + uint16_t * crnti, + BSR_SHORT * truncated_bsr, + BSR_SHORT * short_bsr, + BSR_LONG * long_bsr, + unsigned short post_padding); /* \brief Parse header for UL-SCH. This function parses the received UL-SCH header as described in 36-321 MAC layer specifications. It returns the number of bytes used for the header to be used as an offset for the payload @@ -552,40 +603,46 @@ in the ULSCH buffer. @param rx_lengths Pointer to array of SDU lengths @returns Pointer to payload following header */ -uint8_t *parse_ulsch_header(uint8_t *mac_header, - uint8_t *num_ce, - uint8_t *num_sdu, - uint8_t *rx_ces, - uint8_t *rx_lcids, - uint16_t *rx_lengths, - uint16_t tx_lenght); +uint8_t *parse_ulsch_header(uint8_t * mac_header, + uint8_t * num_ce, + uint8_t * num_sdu, + uint8_t * rx_ces, + uint8_t * rx_lcids, + uint16_t * rx_lengths, uint16_t tx_lenght); int to_prb(int); int to_rbg(int); -int l2_init(LTE_DL_FRAME_PARMS *frame_parms,int eMBMS_active, char *uecap_xer, uint8_t cba_group_active, uint8_t HO_active); +int l2_init(LTE_DL_FRAME_PARMS * frame_parms, int eMBMS_active, + char *uecap_xer, uint8_t cba_group_active, uint8_t HO_active); int mac_init(void); -int add_new_ue(module_id_t Mod_id, int CC_id, rnti_t rnti,int harq_pid - #ifdef Rel14 - ,uint8_t rach_resource_type - #endif - ); +int add_new_ue(module_id_t Mod_id, int CC_id, rnti_t rnti, int harq_pid +#ifdef Rel14 + , uint8_t rach_resource_type +#endif + ); int rrc_mac_remove_ue(module_id_t Mod_id, rnti_t rntiP); -int maxround(module_id_t Mod_id,uint16_t rnti,int frame,sub_frame_t subframe,uint8_t ul_flag); -void swap_UEs(UE_list_t *listP,int nodeiP, int nodejP, int ul_flag); -int prev(UE_list_t *listP, int nodeP, int ul_flag); -void dump_ue_list(UE_list_t *listP, int ul_flag); -int UE_num_active_CC(UE_list_t *listP,int ue_idP); -int UE_PCCID(module_id_t mod_idP,int ue_idP); +int maxround(module_id_t Mod_id, uint16_t rnti, int frame, + sub_frame_t subframe, uint8_t ul_flag); +void swap_UEs(UE_list_t * listP, int nodeiP, int nodejP, int ul_flag); +int prev(UE_list_t * listP, int nodeP, int ul_flag); +void dump_ue_list(UE_list_t * listP, int ul_flag); +int UE_num_active_CC(UE_list_t * listP, int ue_idP); +int UE_PCCID(module_id_t mod_idP, int ue_idP); rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP); -void ulsch_scheduler_pre_processor(module_id_t module_idP, int frameP, sub_frame_t subframeP, uint16_t *first_rb); -void store_ulsch_buffer(module_id_t module_idP, int frameP, sub_frame_t subframeP); -void sort_ue_ul (module_id_t module_idP,int frameP, sub_frame_t subframeP); -void assign_max_mcs_min_rb(module_id_t module_idP,int frameP, sub_frame_t subframeP,uint16_t *first_rb); -void adjust_bsr_info(int buffer_occupancy, uint16_t TBS, UE_TEMPLATE *UE_template); +void ulsch_scheduler_pre_processor(module_id_t module_idP, int frameP, + sub_frame_t subframeP, + uint16_t * first_rb); +void store_ulsch_buffer(module_id_t module_idP, int frameP, + sub_frame_t subframeP); +void sort_ue_ul(module_id_t module_idP, int frameP, sub_frame_t subframeP); +void assign_max_mcs_min_rb(module_id_t module_idP, int frameP, + sub_frame_t subframeP, uint16_t * first_rb); +void adjust_bsr_info(int buffer_occupancy, uint16_t TBS, + UE_TEMPLATE * UE_template); int phy_stats_exist(module_id_t Mod_id, int rnti); /*! \fn UE_L2_state_t ue_scheduler(const module_id_t module_idP,const frame_t frameP, const sub_frame_t subframe, const lte_subframe_t direction,const uint8_t eNB_index) @@ -599,15 +656,13 @@ int phy_stats_exist(module_id_t Mod_id, int rnti); \param[in] eNB_index instance of eNB @returns L2 state (CONNETION_OK or CONNECTION_LOST or PHY_RESYNCH) */ -UE_L2_STATE_t ue_scheduler( - const module_id_t module_idP, - const frame_t rxFrameP, - const sub_frame_t rxSubframe, - const frame_t txFrameP, - const sub_frame_t txSubframe, - const lte_subframe_t direction, - const uint8_t eNB_index, - const int CC_id); +UE_L2_STATE_t ue_scheduler(const module_id_t module_idP, + const frame_t rxFrameP, + const sub_frame_t rxSubframe, + const frame_t txFrameP, + const sub_frame_t txSubframe, + const lte_subframe_t direction, + const uint8_t eNB_index, const int CC_id); /*! \fn int cba_access(module_id_t module_idP,frame_t frameP,sub_frame_t subframe, uint8_t eNB_index,uint16_t buflen); \brief determine whether to use cba resource to transmit or not @@ -617,7 +672,8 @@ UE_L2_STATE_t ue_scheduler( \param[in] eNB_index instance of eNB \param[out] access(1) or postpone (0) */ -int cba_access(module_id_t module_idP,frame_t frameP,sub_frame_t subframe, uint8_t eNB_index,uint16_t buflen); +int cba_access(module_id_t module_idP, frame_t frameP, + sub_frame_t subframe, uint8_t eNB_index, uint16_t buflen); /*! \fn BSR_SHORT * get_bsr_short(module_id_t module_idP, uint8_t bsr_len) \brief get short bsr level @@ -633,14 +689,15 @@ BSR_SHORT *get_bsr_short(module_id_t module_idP, uint8_t bsr_len); \param[in] bsr_len indicator for no, short, or long bsr \param[out] bsr_l pointer to long bsr */ -BSR_LONG * get_bsr_long(module_id_t module_idP, uint8_t bsr_len); +BSR_LONG *get_bsr_long(module_id_t module_idP, uint8_t bsr_len); /*! \fn boolean_t update_bsr(module_id_t module_idP, frame_t frameP,sub_frame_t subframeP) \brief get the rlc stats and update the bsr level for each lcid \param[in] Mod_id instance of the UE \param[in] frame Frame index */ -boolean_t update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP,eNB_index_t eNB_index); +boolean_t update_bsr(module_id_t module_idP, frame_t frameP, + sub_frame_t subframeP, eNB_index_t eNB_index); /*! \fn locate_BsrIndexByBufferSize (int *table, int size, int value) \brief locate the BSR level in the table as defined in 36.321. This function requires that he values in table to be monotonic, either increasing or decreasing. The returned value is not less than 0, nor greater than n-1, where n is the size of table. @@ -649,7 +706,8 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subfram \param[in] value Value of the buffer \return the index in the BSR_LEVEL table */ -uint8_t locate_BsrIndexByBufferSize (const uint32_t *table, int size, int value); +uint8_t locate_BsrIndexByBufferSize(const uint32_t * table, int size, + int value); /*! \fn int get_sf_periodicBSRTimer(uint8_t periodicBSR_Timer) @@ -700,7 +758,8 @@ int get_db_dl_PathlossChange(uint8_t dl_PathlossChange); \param[in] CC_id Component Carrier Index \return phr mapping */ -uint8_t get_phr_mapping (module_id_t module_idP, int CC_id, uint8_t eNB_index); +uint8_t get_phr_mapping(module_id_t module_idP, int CC_id, + uint8_t eNB_index); /*! \fn void update_phr (module_id_t module_idP) \brief update/reset the phr timers @@ -708,13 +767,14 @@ uint8_t get_phr_mapping (module_id_t module_idP, int CC_id, uint8_t eNB_index); \param[in] CC_id Component carrier index \return void */ -void update_phr (module_id_t module_idP,int CC_id); +void update_phr(module_id_t module_idP, int CC_id); /*! \brief Function to indicate Msg3 transmission/retransmission which initiates/reset Contention Resolution Timer \param[in] Mod_id Instance index of UE \param[in] eNB_id Index of eNB */ -void Msg3_tx(module_id_t module_idP,uint8_t CC_id,frame_t frameP,uint8_t eNB_id); +void Msg3_tx(module_id_t module_idP, uint8_t CC_id, frame_t frameP, + uint8_t eNB_id); /*! \brief Function to indicate the transmission of msg1/rach @@ -722,12 +782,12 @@ void Msg3_tx(module_id_t module_idP,uint8_t CC_id,frame_t frameP,uint8_t eNB_id) \param[in] eNB_id Index of eNB */ -void Msg1_tx(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); +void Msg1_tx(module_id_t module_idP, uint8_t CC_id, frame_t frameP, + uint8_t eNB_id); -void dl_phy_sync_success(module_id_t module_idP, - frame_t frameP, - unsigned char eNB_index, - uint8_t first_sync); +void dl_phy_sync_success(module_id_t module_idP, + frame_t frameP, + unsigned char eNB_index, uint8_t first_sync); int dump_eNB_l2_stats(char *buffer, int length); @@ -744,9 +804,11 @@ void add_common_dci(DCI_PDU *DCI_pdu, uint8_t ra_flag); */ -uint32_t allocate_prbs_sub(int nb_rb, int N_RB_DL, int N_RBG, uint8_t *rballoc); +uint32_t allocate_prbs_sub(int nb_rb, int N_RB_DL, int N_RBG, + uint8_t * rballoc); -void update_ul_dci(module_id_t module_idP,uint8_t CC_id,rnti_t rnti,uint8_t dai); +void update_ul_dci(module_id_t module_idP, uint8_t CC_id, rnti_t rnti, + uint8_t dai); int get_bw_index(module_id_t module_id, uint8_t CC_id); @@ -767,14 +829,14 @@ in the DLSCH buffer. @returns Number of bytes used for header */ unsigned char generate_dlsch_header(unsigned char *mac_header, - unsigned char num_sdus, - unsigned short *sdu_lengths, - unsigned char *sdu_lcids, - unsigned char drx_cmd, - unsigned short timing_advance_cmd, - unsigned char *ue_cont_res_id, - unsigned char short_padding, - unsigned short post_padding); + unsigned char num_sdus, + unsigned short *sdu_lengths, + unsigned char *sdu_lcids, + unsigned char drx_cmd, + unsigned short timing_advance_cmd, + unsigned char *ue_cont_res_id, + unsigned char short_padding, + unsigned short post_padding); /** \brief RRC eNB Configuration primitive for PHY/MAC. Allows configuration of PHY/MAC resources based on System Information (SI), RRCConnectionSetup and RRCConnectionReconfiguration messages. @param Mod_id Instance ID of eNB @@ -798,51 +860,55 @@ unsigned char generate_dlsch_header(unsigned char *mac_header, @param sib1_ext_r13 SI Scheduling information for SI-BR UEs */ -int rrc_mac_config_req_eNB(module_id_t module_idP, - int CC_id, - int physCellId, - int p_eNB, - int Ncp, - int eutra_band, - uint32_t dl_CarrierFreq, +int rrc_mac_config_req_eNB(module_id_t module_idP, + int CC_id, + int physCellId, + int p_eNB, + int Ncp, + int eutra_band, uint32_t dl_CarrierFreq, #ifdef Rel14 - int pbch_repetition, + int pbch_repetition, #endif - rnti_t rntiP, - BCCH_BCH_Message_t *mib, - RadioResourceConfigCommonSIB_t *radioResourceConfigCommon, + rnti_t rntiP, + BCCH_BCH_Message_t * mib, + RadioResourceConfigCommonSIB_t * + radioResourceConfigCommon, #ifdef Rel14 - RadioResourceConfigCommonSIB_t *radioResourceConfigCommon_BR, + RadioResourceConfigCommonSIB_t * + radioResourceConfigCommon_BR, #endif - struct PhysicalConfigDedicated *physicalConfigDedicated, + struct PhysicalConfigDedicated + *physicalConfigDedicated, #if defined(Rel10) || defined(Rel14) - SCellToAddMod_r10_t *sCellToAddMod_r10, + SCellToAddMod_r10_t * sCellToAddMod_r10, //struct PhysicalConfigDedicatedSCell_r10 *physicalConfigDedicatedSCell_r10, #endif - MeasObjectToAddMod_t **measObj, - MAC_MainConfig_t *mac_MainConfig, - long logicalChannelIdentity, - LogicalChannelConfig_t *logicalChannelConfig, - MeasGapConfig_t *measGapConfig, - TDD_Config_t *tdd_Config, - MobilityControlInfo_t *mobilityControlInfo, - SchedulingInfoList_t *schedulingInfoList, - uint32_t ul_CarrierFreq, - long *ul_Bandwidth, - AdditionalSpectrumEmission_t *additionalSpectrumEmission, - struct MBSFN_SubframeConfigList *mbsfn_SubframeConfigList + MeasObjectToAddMod_t ** measObj, + MAC_MainConfig_t * mac_MainConfig, + long logicalChannelIdentity, + LogicalChannelConfig_t * logicalChannelConfig, + MeasGapConfig_t * measGapConfig, + TDD_Config_t * tdd_Config, + MobilityControlInfo_t * mobilityControlInfo, + SchedulingInfoList_t * schedulingInfoList, + uint32_t ul_CarrierFreq, + long *ul_Bandwidth, + AdditionalSpectrumEmission_t * + additionalSpectrumEmission, + struct MBSFN_SubframeConfigList + *mbsfn_SubframeConfigList #if defined(Rel10) || defined(Rel14) , - uint8_t MBMS_Flag, - MBSFN_AreaInfoList_r9_t *mbsfn_AreaInfoList, - PMCH_InfoList_r9_t *pmch_InfoList - + uint8_t MBMS_Flag, + MBSFN_AreaInfoList_r9_t * mbsfn_AreaInfoList, + PMCH_InfoList_r9_t * pmch_InfoList #endif #ifdef Rel14 , - SystemInformationBlockType1_v1310_IEs_t *sib1_ext_r13 + SystemInformationBlockType1_v1310_IEs_t * + sib1_ext_r13 #endif - ); + ); /** \brief RRC eNB Configuration primitive for PHY/MAC. Allows configuration of PHY/MAC resources based on System Information (SI), RRCConnectionSetup and RRCConnectionReconfiguration messages. @param Mod_id Instance ID of ue @@ -864,132 +930,154 @@ int rrc_mac_config_req_eNB(module_id_t module_idP, @param mbsfn_AreaInfoList pointer to MBSFN Area Info list from SIB13 @param pmch_InfoList pointer to PMCH_InfoList from MBSFNAreaConfiguration Message (MCCH Message) */ -int rrc_mac_config_req_ue(module_id_t module_idP, - int CC_id, - uint8_t eNB_index, - RadioResourceConfigCommonSIB_t *radioResourceConfigCommon, - struct PhysicalConfigDedicated *physicalConfigDedicated, +int rrc_mac_config_req_ue(module_id_t module_idP, + int CC_id, + uint8_t eNB_index, + RadioResourceConfigCommonSIB_t * + radioResourceConfigCommon, + struct PhysicalConfigDedicated + *physicalConfigDedicated, #if defined(Rel10) || defined(Rel14) - SCellToAddMod_r10_t *sCellToAddMod_r10, + SCellToAddMod_r10_t * sCellToAddMod_r10, //struct PhysicalConfigDedicatedSCell_r10 *physicalConfigDedicatedSCell_r10, #endif - MeasObjectToAddMod_t **measObj, - MAC_MainConfig_t *mac_MainConfig, + MeasObjectToAddMod_t ** measObj, + MAC_MainConfig_t * mac_MainConfig, long logicalChannelIdentity, - LogicalChannelConfig_t *logicalChannelConfig, - MeasGapConfig_t *measGapConfig, - TDD_Config_t *tdd_Config, - MobilityControlInfo_t *mobilityControlInfo, - uint8_t *SIwindowsize, - uint16_t *SIperiod, - ARFCN_ValueEUTRA_t *ul_CarrierFreq, + LogicalChannelConfig_t * logicalChannelConfig, + MeasGapConfig_t * measGapConfig, + TDD_Config_t * tdd_Config, + MobilityControlInfo_t * mobilityControlInfo, + uint8_t * SIwindowsize, + uint16_t * SIperiod, + ARFCN_ValueEUTRA_t * ul_CarrierFreq, long *ul_Bandwidth, - AdditionalSpectrumEmission_t *additionalSpectrumEmission, - struct MBSFN_SubframeConfigList *mbsfn_SubframeConfigList + AdditionalSpectrumEmission_t * + additionalSpectrumEmission, + struct MBSFN_SubframeConfigList + *mbsfn_SubframeConfigList #if defined(Rel10) || defined(Rel14) , uint8_t MBMS_Flag, - MBSFN_AreaInfoList_r9_t *mbsfn_AreaInfoList, - PMCH_InfoList_r9_t *pmch_InfoList - + MBSFN_AreaInfoList_r9_t * mbsfn_AreaInfoList, + PMCH_InfoList_r9_t * pmch_InfoList #endif #ifdef CBA , - uint8_t num_active_cba_groups, - uint16_t cba_rnti + uint8_t num_active_cba_groups, uint16_t cba_rnti #endif - ); + ); -uint16_t getRIV(uint16_t N_RB_DL,uint16_t RBstart,uint16_t Lcrbs); +uint16_t getRIV(uint16_t N_RB_DL, uint16_t RBstart, uint16_t Lcrbs); int get_subbandsize(uint8_t dl_bandwidth); -void get_Msg3allocret(COMMON_channels_t *cc, +void get_Msg3allocret(COMMON_channels_t * cc, sub_frame_t current_subframe, frame_t current_frame, - frame_t *frame, - sub_frame_t *subframe); + frame_t * frame, sub_frame_t * subframe); -void get_Msg3alloc(COMMON_channels_t *cc, +void get_Msg3alloc(COMMON_channels_t * cc, sub_frame_t current_subframe, frame_t current_frame, - frame_t *frame, - sub_frame_t *subframe); + frame_t * frame, sub_frame_t * subframe); -uint16_t mac_computeRIV(uint16_t N_RB_DL,uint16_t RBstart,uint16_t Lcrbs); +uint16_t mac_computeRIV(uint16_t N_RB_DL, uint16_t RBstart, + uint16_t Lcrbs); -int get_phich_resource_times6(COMMON_channels_t *cc); +int get_phich_resource_times6(COMMON_channels_t * cc); int to_rbg(int dl_Bandwidth); int to_prb(int dl_Bandwidth); -uint8_t get_Msg3harqpid(COMMON_channels_t *cc, - frame_t frame, - sub_frame_t current_subframe); +uint8_t get_Msg3harqpid(COMMON_channels_t * cc, + frame_t frame, sub_frame_t current_subframe); -uint32_t pdcchalloc2ulframe(COMMON_channels_t *ccP,uint32_t frame, uint8_t n); +uint32_t pdcchalloc2ulframe(COMMON_channels_t * ccP, uint32_t frame, + uint8_t n); -uint8_t pdcchalloc2ulsubframe(COMMON_channels_t *ccP,uint8_t n); +uint8_t pdcchalloc2ulsubframe(COMMON_channels_t * ccP, uint8_t n); -int is_UL_sf(COMMON_channels_t *ccP,sub_frame_t subframeP); +int is_UL_sf(COMMON_channels_t * ccP, sub_frame_t subframeP); uint8_t getQm(uint8_t mcs); -uint8_t subframe2harqpid(COMMON_channels_t *cc,frame_t frame,sub_frame_t subframe); +uint8_t subframe2harqpid(COMMON_channels_t * cc, frame_t frame, + sub_frame_t subframe); -void get_srs_pos(COMMON_channels_t *cc,uint16_t isrs,uint16_t *psrsPeriodicity,uint16_t *psrsOffset); +void get_srs_pos(COMMON_channels_t * cc, uint16_t isrs, + uint16_t * psrsPeriodicity, uint16_t * psrsOffset); -void get_csi_params(COMMON_channels_t *cc,struct CQI_ReportPeriodic *cqi_PMI_ConfigIndex,uint16_t *Npd,uint16_t *N_OFFSET_CQI,int *H); +void get_csi_params(COMMON_channels_t * cc, + struct CQI_ReportPeriodic *cqi_PMI_ConfigIndex, + uint16_t * Npd, uint16_t * N_OFFSET_CQI, int *H); -uint8_t get_rel8_dl_cqi_pmi_size(UE_sched_ctrl *sched_ctl,int CC_idP,COMMON_channels_t *cc,uint8_t tmode, struct CQI_ReportPeriodic *cqi_ReportPeriodic); +uint8_t get_rel8_dl_cqi_pmi_size(UE_sched_ctrl * sched_ctl, int CC_idP, + COMMON_channels_t * cc, uint8_t tmode, + struct CQI_ReportPeriodic + *cqi_ReportPeriodic); -uint8_t get_dl_cqi_pmi_size_pusch(COMMON_channels_t *cc,uint8_t tmode, uint8_t ri, CQI_ReportModeAperiodic_t *cqi_ReportModeAperiodic); -void extract_pucch_csi(module_id_t mod_idP,int CC_idP,int UE_id, frame_t frameP,sub_frame_t subframeP, uint8_t *pdu, uint8_t length); +uint8_t get_dl_cqi_pmi_size_pusch(COMMON_channels_t * cc, uint8_t tmode, + uint8_t ri, + CQI_ReportModeAperiodic_t * + cqi_ReportModeAperiodic); +void extract_pucch_csi(module_id_t mod_idP, int CC_idP, int UE_id, + frame_t frameP, sub_frame_t subframeP, + uint8_t * pdu, uint8_t length); -void extract_pusch_csi(module_id_t mod_idP,int CC_idP,int UE_id, frame_t frameP,sub_frame_t subframeP,uint8_t *pdu, uint8_t length); +void extract_pusch_csi(module_id_t mod_idP, int CC_idP, int UE_id, + frame_t frameP, sub_frame_t subframeP, + uint8_t * pdu, uint8_t length); -uint16_t fill_nfapi_tx_req(nfapi_tx_request_body_t *tx_req_body,uint16_t absSF,uint16_t pdu_length, uint16_t pdu_index, uint8_t *pdu ); +uint16_t fill_nfapi_tx_req(nfapi_tx_request_body_t * tx_req_body, + uint16_t absSF, uint16_t pdu_length, + uint16_t pdu_index, uint8_t * pdu); -void fill_nfapi_ulsch_config_request_rel8(nfapi_ul_config_request_pdu_t *ul_config_pdu, - uint8_t cqi_req, - COMMON_channels_t *cc, - struct PhysicalConfigDedicated *physicalConfigDedicated, - uint8_t tmode, - uint32_t handle, - uint16_t rnti, - uint8_t resource_block_start, - uint8_t number_of_resource_blocks, - uint8_t mcs, - uint8_t cyclic_shift_2_for_drms, - uint8_t frequency_hopping_enabled_flag, - uint8_t frequency_hopping_bits, - uint8_t new_data_indication, - uint8_t redundancy_version, - uint8_t harq_process_number, - uint8_t ul_tx_mode, - uint8_t current_tx_nb, - uint8_t n_srs, - uint16_t size - ); +void fill_nfapi_ulsch_config_request_rel8(nfapi_ul_config_request_pdu_t * + ul_config_pdu, uint8_t cqi_req, + COMMON_channels_t * cc, + struct PhysicalConfigDedicated + *physicalConfigDedicated, + uint8_t tmode, uint32_t handle, + uint16_t rnti, + uint8_t resource_block_start, + uint8_t + number_of_resource_blocks, + uint8_t mcs, + uint8_t cyclic_shift_2_for_drms, + uint8_t + frequency_hopping_enabled_flag, + uint8_t frequency_hopping_bits, + uint8_t new_data_indication, + uint8_t redundancy_version, + uint8_t harq_process_number, + uint8_t ul_tx_mode, + uint8_t current_tx_nb, + uint8_t n_srs, uint16_t size); #ifdef Rel14 -void fill_nfapi_ulsch_config_request_emtc(nfapi_ul_config_request_pdu_t *ul_config_pdu, - uint8_t ue_type, - uint16_t total_number_of_repetitions, +void fill_nfapi_ulsch_config_request_emtc(nfapi_ul_config_request_pdu_t * + ul_config_pdu, uint8_t ue_type, + uint16_t + total_number_of_repetitions, uint16_t repetition_number, - uint16_t initial_transmission_sf_io); + uint16_t + initial_transmission_sf_io); #endif -void program_dlsch_acknak(module_id_t module_idP, int CC_idP,int UE_idP, frame_t frameP, sub_frame_t subframeP,uint8_t cce_idx); +void program_dlsch_acknak(module_id_t module_idP, int CC_idP, int UE_idP, + frame_t frameP, sub_frame_t subframeP, + uint8_t cce_idx); -void fill_nfapi_dlsch_config(eNB_MAC_INST *eNB, nfapi_dl_config_request_body_t *dl_req, - uint16_t length, - uint16_t pdu_index, +void fill_nfapi_dlsch_config(eNB_MAC_INST * eNB, + nfapi_dl_config_request_body_t * dl_req, + uint16_t length, uint16_t pdu_index, uint16_t rnti, uint8_t resource_allocation_type, - uint8_t virtual_resource_block_assignment_flag, + uint8_t + virtual_resource_block_assignment_flag, uint16_t resource_block_coding, uint8_t modulation, uint8_t redundancy_version, @@ -998,7 +1086,7 @@ void fill_nfapi_dlsch_config(eNB_MAC_INST *eNB, nfapi_dl_config_request_body_t * uint8_t transmission_scheme, uint8_t number_of_layers, uint8_t number_of_subbands, - // uint8_t codebook_index, + // uint8_t codebook_index, uint8_t ue_category_capacity, uint8_t pa, uint8_t delta_power_offset_index, @@ -1006,28 +1094,27 @@ void fill_nfapi_dlsch_config(eNB_MAC_INST *eNB, nfapi_dl_config_request_body_t * uint8_t nprb, uint8_t transmission_mode, uint8_t num_bf_prb_per_subband, - uint8_t num_bf_vector - ); + uint8_t num_bf_vector); void fill_nfapi_harq_information(module_id_t module_idP, int CC_idP, uint16_t rntiP, uint16_t absSFP, - nfapi_ul_config_harq_information *harq_information, - uint8_t cce_idxP); + nfapi_ul_config_harq_information * + harq_information, uint8_t cce_idxP); void fill_nfapi_ulsch_harq_information(module_id_t module_idP, int CC_idP, uint16_t rntiP, - nfapi_ul_config_ulsch_harq_information *harq_information); + nfapi_ul_config_ulsch_harq_information + * harq_information); uint16_t fill_nfapi_uci_acknak(module_id_t module_idP, int CC_idP, uint16_t rntiP, - uint16_t absSFP, - uint8_t cce_idxP); + uint16_t absSFP, uint8_t cce_idxP); -void fill_nfapi_dl_dci_1A(nfapi_dl_config_request_pdu_t *dl_config_pdu, +void fill_nfapi_dl_dci_1A(nfapi_dl_config_request_pdu_t * dl_config_pdu, uint8_t aggregation_level, uint16_t rnti, uint8_t rnti_type, @@ -1035,34 +1122,40 @@ void fill_nfapi_dl_dci_1A(nfapi_dl_config_request_pdu_t *dl_config_pdu, uint8_t tpc, uint16_t resource_block_coding, uint8_t mcs, - uint8_t ndi, - uint8_t rv, - uint8_t vrb_flag); + uint8_t ndi, uint8_t rv, uint8_t vrb_flag); -nfapi_ul_config_request_pdu_t* has_ul_grant(module_id_t module_idP,int CC_idP,uint16_t subframeP,uint16_t rnti); +nfapi_ul_config_request_pdu_t *has_ul_grant(module_id_t module_idP, + int CC_idP, uint16_t subframeP, + uint16_t rnti); -uint8_t get_tmode(module_id_t module_idP,int CC_idP,int UE_idP); +uint8_t get_tmode(module_id_t module_idP, int CC_idP, int UE_idP); -uint8_t get_ul_req_index(module_id_t module_idP, int CC_idP, sub_frame_t subframeP); +uint8_t get_ul_req_index(module_id_t module_idP, int CC_idP, + sub_frame_t subframeP); #ifdef Rel14 int get_numnarrowbandbits(long dl_Bandwidth); -int mpdcch_sf_condition(eNB_MAC_INST *eNB,int CC_id, frame_t frameP,sub_frame_t subframeP,int rmax,MPDCCH_TYPES_t mpdcch_type,int UE_id); +int mpdcch_sf_condition(eNB_MAC_INST * eNB, int CC_id, frame_t frameP, + sub_frame_t subframeP, int rmax, + MPDCCH_TYPES_t mpdcch_type, int UE_id); int get_numnarrowbands(long dl_Bandwidth); -int narrowband_to_first_rb(COMMON_channels_t *cc, int nb_index); +int narrowband_to_first_rb(COMMON_channels_t * cc, int nb_index); #endif int l2_init_eNB(void); -void Msg1_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); -void Msg3_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); -uint32_t from_earfcn(int eutra_bandP,uint32_t dl_earfcn); +void Msg1_transmitted(module_id_t module_idP, uint8_t CC_id, + frame_t frameP, uint8_t eNB_id); +void Msg3_transmitted(module_id_t module_idP, uint8_t CC_id, + frame_t frameP, uint8_t eNB_id); +uint32_t from_earfcn(int eutra_bandP, uint32_t dl_earfcn); int32_t get_uldl_offset(int eutra_bandP); -int l2_init_ue(int eMBMS_active, char *uecap_xer,uint8_t cba_group_active, uint8_t HO_active); +int l2_init_ue(int eMBMS_active, char *uecap_xer, uint8_t cba_group_active, + uint8_t HO_active); #endif /** @}*/ diff --git a/openair2/LAYER2/MAC/ra_procedures.c b/openair2/LAYER2/MAC/ra_procedures.c index f649acad1e..3f2df025c7 100644 --- a/openair2/LAYER2/MAC/ra_procedures.c +++ b/openair2/LAYER2/MAC/ra_procedures.c @@ -47,482 +47,604 @@ #include "SIMULATION/simulation_defs.h" #endif -#include "SIMULATION/TOOLS/defs.h" // for taus +#include "SIMULATION/TOOLS/defs.h" // for taus -int8_t get_DELTA_PREAMBLE(module_id_t module_idP,int CC_id) +int8_t get_DELTA_PREAMBLE(module_id_t module_idP, int CC_id) { - AssertFatal(CC_id==0, - "Transmission on secondary CCs is not supported yet\n"); - uint8_t prachConfigIndex = UE_mac_inst[module_idP].radioResourceConfigCommon->prach_Config.prach_ConfigInfo.prach_ConfigIndex; - uint8_t preambleformat; + AssertFatal(CC_id == 0, + "Transmission on secondary CCs is not supported yet\n"); + uint8_t prachConfigIndex = + UE_mac_inst[module_idP].radioResourceConfigCommon-> + prach_Config.prach_ConfigInfo.prach_ConfigIndex; + uint8_t preambleformat; - if (UE_mac_inst[module_idP].tdd_Config) { // TDD - if (prachConfigIndex < 20) { - preambleformat = 0; - } else if (prachConfigIndex < 30) { - preambleformat = 1; - } else if (prachConfigIndex < 40) { - preambleformat = 2; - } else if (prachConfigIndex < 48) { - preambleformat = 3; - } else { - preambleformat = 4; + if (UE_mac_inst[module_idP].tdd_Config) { // TDD + if (prachConfigIndex < 20) { + preambleformat = 0; + } else if (prachConfigIndex < 30) { + preambleformat = 1; + } else if (prachConfigIndex < 40) { + preambleformat = 2; + } else if (prachConfigIndex < 48) { + preambleformat = 3; + } else { + preambleformat = 4; + } + } else { // FDD + preambleformat = prachConfigIndex >> 2; } - } else { // FDD - preambleformat = prachConfigIndex>>2; - } - switch (preambleformat) { - case 0: - case 1: - return(0); + switch (preambleformat) { + case 0: + case 1: + return (0); - case 2: - case 3: - return(-3); + case 2: + case 3: + return (-3); - case 4: - return(8); + case 4: + return (8); - default: - AssertFatal(1==0,"[UE %d] ue_procedures.c: FATAL, Illegal preambleformat %d, prachConfigIndex %d\n", - module_idP, - preambleformat,prachConfigIndex); - } + default: + AssertFatal(1 == 0, + "[UE %d] ue_procedures.c: FATAL, Illegal preambleformat %d, prachConfigIndex %d\n", + module_idP, preambleformat, prachConfigIndex); + } } /// This routine implements Section 5.1.2 (UE Random Access Resource Selection) from 36.321 -void get_prach_resources(module_id_t module_idP, - int CC_id, - uint8_t eNB_index, - uint8_t t_id, - uint8_t first_Msg3, - RACH_ConfigDedicated_t *rach_ConfigDedicated) +void +get_prach_resources(module_id_t module_idP, + int CC_id, + uint8_t eNB_index, + uint8_t t_id, + uint8_t first_Msg3, + RACH_ConfigDedicated_t * rach_ConfigDedicated) { - uint8_t Msg3_size = UE_mac_inst[module_idP].RA_Msg3_size; - PRACH_RESOURCES_t *prach_resources = &UE_mac_inst[module_idP].RA_prach_resources; - RACH_ConfigCommon_t *rach_ConfigCommon = NULL; - uint8_t noGroupB = 0; - uint8_t f_id = 0,num_prach=0; - int numberOfRA_Preambles; - int messageSizeGroupA; - int sizeOfRA_PreamblesGroupA; - int messagePowerOffsetGroupB; - int PLThreshold; + uint8_t Msg3_size = UE_mac_inst[module_idP].RA_Msg3_size; + PRACH_RESOURCES_t *prach_resources = + &UE_mac_inst[module_idP].RA_prach_resources; + RACH_ConfigCommon_t *rach_ConfigCommon = NULL; + uint8_t noGroupB = 0; + uint8_t f_id = 0, num_prach = 0; + int numberOfRA_Preambles; + int messageSizeGroupA; + int sizeOfRA_PreamblesGroupA; + int messagePowerOffsetGroupB; + int PLThreshold; - AssertFatal(CC_id==0, - "Transmission on secondary CCs is not supported yet\n"); - AssertFatal(UE_mac_inst[module_idP].radioResourceConfigCommon!=NULL, - "[UE %d] FATAL radioResourceConfigCommon is NULL !!!\n",module_idP); + AssertFatal(CC_id == 0, + "Transmission on secondary CCs is not supported yet\n"); + AssertFatal(UE_mac_inst[module_idP].radioResourceConfigCommon != NULL, + "[UE %d] FATAL radioResourceConfigCommon is NULL !!!\n", + module_idP); - rach_ConfigCommon = &UE_mac_inst[module_idP].radioResourceConfigCommon->rach_ConfigCommon; - numberOfRA_Preambles = (1+rach_ConfigCommon->preambleInfo.numberOfRA_Preambles)<<2; + rach_ConfigCommon = + &UE_mac_inst[module_idP].radioResourceConfigCommon-> + rach_ConfigCommon; + numberOfRA_Preambles = + (1 + rach_ConfigCommon->preambleInfo.numberOfRA_Preambles) << 2; - if (rach_ConfigDedicated) { // This is for network controlled Mobility, later - if (rach_ConfigDedicated->ra_PRACH_MaskIndex != 0) { - prach_resources->ra_PreambleIndex = rach_ConfigDedicated->ra_PreambleIndex; - prach_resources->ra_RACH_MaskIndex = rach_ConfigDedicated->ra_PRACH_MaskIndex; - return; - } - } - - /* TODO: gcc warns if this variable is not always set, let's put -1 for no more warning */ - messageSizeGroupA = -1; - - if (!rach_ConfigCommon->preambleInfo.preamblesGroupAConfig) { - noGroupB = 1; - } else { - sizeOfRA_PreamblesGroupA = (rach_ConfigCommon->preambleInfo.preamblesGroupAConfig->sizeOfRA_PreamblesGroupA+1)<<2; - switch (rach_ConfigCommon->preambleInfo.preamblesGroupAConfig->messageSizeGroupA) { - case 0: - messageSizeGroupA = 56; - break; - case 1: - messageSizeGroupA = 144; - break; - case 2: - messageSizeGroupA = 208; - break; - case 3: - messageSizeGroupA = 256; - break; + if (rach_ConfigDedicated) { // This is for network controlled Mobility, later + if (rach_ConfigDedicated->ra_PRACH_MaskIndex != 0) { + prach_resources->ra_PreambleIndex = + rach_ConfigDedicated->ra_PreambleIndex; + prach_resources->ra_RACH_MaskIndex = + rach_ConfigDedicated->ra_PRACH_MaskIndex; + return; + } } - /* TODO: what value to use as default? */ - messagePowerOffsetGroupB = -9999; - switch (rach_ConfigCommon->preambleInfo.preamblesGroupAConfig->messagePowerOffsetGroupB) { - case 0: - messagePowerOffsetGroupB = -9999; - break; - case 1: - messagePowerOffsetGroupB = 0; - break; - case 2: - messagePowerOffsetGroupB = 5; - break; - case 3: - messagePowerOffsetGroupB = 8; - break; - case 4: - messagePowerOffsetGroupB = 10; - break; - case 5: - messagePowerOffsetGroupB = 12; - break; - case 6: - messagePowerOffsetGroupB = 15; - break; - case 7: - messagePowerOffsetGroupB = 18; - break; - } + /* TODO: gcc warns if this variable is not always set, let's put -1 for no more warning */ + messageSizeGroupA = -1; - PLThreshold = 0 - get_DELTA_PREAMBLE(module_idP,CC_id) - get_Po_NOMINAL_PUSCH(module_idP,CC_id) - messagePowerOffsetGroupB; - // Note Pcmax is set to 0 here, we have to fix this - - if (sizeOfRA_PreamblesGroupA == numberOfRA_Preambles) { - noGroupB = 1; - } - } - - if (first_Msg3 == 1) { - if (noGroupB == 1) { - // use Group A procedure - UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = (taus())%numberOfRA_Preambles; - UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0; - UE_mac_inst[module_idP].RA_usedGroupA = 1; - } else if ((Msg3_size PLThreshold)) { - // use Group A procedure - UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = (taus())%sizeOfRA_PreamblesGroupA; - UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0; - UE_mac_inst[module_idP].RA_usedGroupA = 1; - } else { // use Group B - UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = sizeOfRA_PreamblesGroupA + - (taus())%(numberOfRA_Preambles - sizeOfRA_PreamblesGroupA); - UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0; - UE_mac_inst[module_idP].RA_usedGroupA = 0; - } - - UE_mac_inst[module_idP].RA_prach_resources.ra_PREAMBLE_RECEIVED_TARGET_POWER = get_Po_NOMINAL_PUSCH(module_idP,CC_id); - } else { // Msg3 is being retransmitted - if (UE_mac_inst[module_idP].RA_usedGroupA == 1) { - if (rach_ConfigCommon->preambleInfo.preamblesGroupAConfig) { - UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = (taus())%rach_ConfigCommon->preambleInfo.preamblesGroupAConfig->sizeOfRA_PreamblesGroupA; - } else { - UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = (taus())&0x3f; - } - - UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0; + if (!rach_ConfigCommon->preambleInfo.preamblesGroupAConfig) { + noGroupB = 1; } else { - // FIXME rach_ConfigCommon->preambleInfo.preamblesGroupAConfig may be zero - UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = - rach_ConfigCommon->preambleInfo.preamblesGroupAConfig->sizeOfRA_PreamblesGroupA + - (taus())%(rach_ConfigCommon->preambleInfo.numberOfRA_Preambles - - rach_ConfigCommon->preambleInfo.preamblesGroupAConfig->sizeOfRA_PreamblesGroupA); - UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0; - } - } + sizeOfRA_PreamblesGroupA = + (rach_ConfigCommon->preambleInfo. + preamblesGroupAConfig->sizeOfRA_PreamblesGroupA + 1) << 2; + switch (rach_ConfigCommon->preambleInfo. + preamblesGroupAConfig->messageSizeGroupA) { + case 0: + messageSizeGroupA = 56; + break; + case 1: + messageSizeGroupA = 144; + break; + case 2: + messageSizeGroupA = 208; + break; + case 3: + messageSizeGroupA = 256; + break; + } - // choose random PRACH resource in TDD - if (UE_mac_inst[module_idP].tdd_Config) { - num_prach = get_num_prach_tdd(module_idP); + /* TODO: what value to use as default? */ + messagePowerOffsetGroupB = -9999; + switch (rach_ConfigCommon->preambleInfo. + preamblesGroupAConfig->messagePowerOffsetGroupB) { + case 0: + messagePowerOffsetGroupB = -9999; + break; + case 1: + messagePowerOffsetGroupB = 0; + break; + case 2: + messagePowerOffsetGroupB = 5; + break; + case 3: + messagePowerOffsetGroupB = 8; + break; + case 4: + messagePowerOffsetGroupB = 10; + break; + case 5: + messagePowerOffsetGroupB = 12; + break; + case 6: + messagePowerOffsetGroupB = 15; + break; + case 7: + messagePowerOffsetGroupB = 18; + break; + } - if ((num_prach>0) && (num_prach<6)) { - UE_mac_inst[module_idP].RA_prach_resources.ra_TDD_map_index = (taus()%num_prach); + PLThreshold = + 0 - get_DELTA_PREAMBLE(module_idP, + CC_id) - + get_Po_NOMINAL_PUSCH(module_idP, + CC_id) - messagePowerOffsetGroupB; + // Note Pcmax is set to 0 here, we have to fix this + + if (sizeOfRA_PreamblesGroupA == numberOfRA_Preambles) { + noGroupB = 1; + } } - f_id = get_fid_prach_tdd(module_idP, - UE_mac_inst[module_idP].RA_prach_resources.ra_TDD_map_index); - } + if (first_Msg3 == 1) { + if (noGroupB == 1) { + // use Group A procedure + UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = + (taus()) % numberOfRA_Preambles; + UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = + 0; + UE_mac_inst[module_idP].RA_usedGroupA = 1; + } else if ((Msg3_size < messageSizeGroupA) || + (get_PL(module_idP, 0, eNB_index) > PLThreshold)) { + // use Group A procedure + UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = + (taus()) % sizeOfRA_PreamblesGroupA; + UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = + 0; + UE_mac_inst[module_idP].RA_usedGroupA = 1; + } else { // use Group B + UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = + sizeOfRA_PreamblesGroupA + + (taus()) % (numberOfRA_Preambles - + sizeOfRA_PreamblesGroupA); + UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = + 0; + UE_mac_inst[module_idP].RA_usedGroupA = 0; + } - // choose RA-RNTI - UE_mac_inst[module_idP].RA_prach_resources.ra_RNTI = 1 + t_id + 10*f_id; + UE_mac_inst[module_idP]. + RA_prach_resources.ra_PREAMBLE_RECEIVED_TARGET_POWER = + get_Po_NOMINAL_PUSCH(module_idP, CC_id); + } else { // Msg3 is being retransmitted + if (UE_mac_inst[module_idP].RA_usedGroupA == 1) { + if (rach_ConfigCommon->preambleInfo.preamblesGroupAConfig) { + UE_mac_inst[module_idP].RA_prach_resources. + ra_PreambleIndex = + (taus()) % + rach_ConfigCommon->preambleInfo. + preamblesGroupAConfig->sizeOfRA_PreamblesGroupA; + } else { + UE_mac_inst[module_idP].RA_prach_resources. + ra_PreambleIndex = (taus()) & 0x3f; + } + + UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = + 0; + } else { + // FIXME rach_ConfigCommon->preambleInfo.preamblesGroupAConfig may be zero + UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = + rach_ConfigCommon->preambleInfo. + preamblesGroupAConfig->sizeOfRA_PreamblesGroupA + + (taus()) % + (rach_ConfigCommon->preambleInfo.numberOfRA_Preambles - + rach_ConfigCommon->preambleInfo. + preamblesGroupAConfig->sizeOfRA_PreamblesGroupA); + UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = + 0; + } + } + + // choose random PRACH resource in TDD + if (UE_mac_inst[module_idP].tdd_Config) { + num_prach = get_num_prach_tdd(module_idP); + + if ((num_prach > 0) && (num_prach < 6)) { + UE_mac_inst[module_idP].RA_prach_resources.ra_TDD_map_index = + (taus() % num_prach); + } + + f_id = get_fid_prach_tdd(module_idP, + UE_mac_inst + [module_idP].RA_prach_resources. + ra_TDD_map_index); + } + // choose RA-RNTI + UE_mac_inst[module_idP].RA_prach_resources.ra_RNTI = + 1 + t_id + 10 * f_id; } -void Msg1_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id) +void +Msg1_transmitted(module_id_t module_idP, uint8_t CC_id, + frame_t frameP, uint8_t eNB_id) { - AssertFatal(CC_id==0, - "Transmission on secondary CCs is not supported yet\n"); - // start contention resolution timer - UE_mac_inst[module_idP].RA_attempt_number++; + AssertFatal(CC_id == 0, + "Transmission on secondary CCs is not supported yet\n"); + // start contention resolution timer + UE_mac_inst[module_idP].RA_attempt_number++; - if (opt_enabled) { - trace_pdu(0, NULL, 0, module_idP, 0 , UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex, - UE_mac_inst[module_idP].txFrame, UE_mac_inst[module_idP].txSubframe, 0, UE_mac_inst[module_idP].RA_attempt_number); - LOG_D(OPT,"[UE %d][RAPROC] TX MSG1 Frame %d trace pdu for rnti %x with size %d\n", - module_idP, frameP, 1, UE_mac_inst[module_idP].RA_Msg3_size); - } + if (opt_enabled) { + trace_pdu(0, NULL, 0, module_idP, 0, + UE_mac_inst[module_idP].RA_prach_resources. + ra_PreambleIndex, UE_mac_inst[module_idP].txFrame, + UE_mac_inst[module_idP].txSubframe, 0, + UE_mac_inst[module_idP].RA_attempt_number); + LOG_D(OPT, + "[UE %d][RAPROC] TX MSG1 Frame %d trace pdu for rnti %x with size %d\n", + module_idP, frameP, 1, UE_mac_inst[module_idP].RA_Msg3_size); + } } -void Msg3_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id) +void +Msg3_transmitted(module_id_t module_idP, uint8_t CC_id, + frame_t frameP, uint8_t eNB_id) { - AssertFatal(CC_id==0, - "Transmission on secondary CCs is not supported yet\n"); + AssertFatal(CC_id == 0, + "Transmission on secondary CCs is not supported yet\n"); - // start contention resolution timer - LOG_D(MAC,"[UE %d][RAPROC] Frame %d : Msg3_tx: Setting contention resolution timer\n",module_idP,frameP); - UE_mac_inst[module_idP].RA_contention_resolution_cnt = 0; - UE_mac_inst[module_idP].RA_contention_resolution_timer_active = 1; + // start contention resolution timer + LOG_D(MAC, + "[UE %d][RAPROC] Frame %d : Msg3_tx: Setting contention resolution timer\n", + module_idP, frameP); + UE_mac_inst[module_idP].RA_contention_resolution_cnt = 0; + UE_mac_inst[module_idP].RA_contention_resolution_timer_active = 1; - if (opt_enabled) { // msg3 - trace_pdu(0, &UE_mac_inst[module_idP].CCCH_pdu.payload[0], UE_mac_inst[module_idP].RA_Msg3_size, - module_idP, 3, UE_mac_inst[module_idP].crnti, UE_mac_inst[module_idP].txFrame, UE_mac_inst[module_idP].txSubframe, 0, 0); - LOG_D(OPT,"[UE %d][RAPROC] MSG3 Frame %d trace pdu Preamble %d with size %d\n", - module_idP, frameP, UE_mac_inst[module_idP].crnti /*UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex*/, UE_mac_inst[module_idP].RA_Msg3_size); - } + if (opt_enabled) { // msg3 + trace_pdu(0, &UE_mac_inst[module_idP].CCCH_pdu.payload[0], + UE_mac_inst[module_idP].RA_Msg3_size, module_idP, 3, + UE_mac_inst[module_idP].crnti, + UE_mac_inst[module_idP].txFrame, + UE_mac_inst[module_idP].txSubframe, 0, 0); + LOG_D(OPT, + "[UE %d][RAPROC] MSG3 Frame %d trace pdu Preamble %d with size %d\n", + module_idP, frameP, UE_mac_inst[module_idP].crnti + /*UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex */ + , UE_mac_inst[module_idP].RA_Msg3_size); + } } -PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP, uint8_t eNB_indexP,sub_frame_t subframeP) +PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP, int CC_id, + frame_t frameP, uint8_t eNB_indexP, + sub_frame_t subframeP) { - uint8_t Size = 0; - UE_MODE_t UE_mode = get_ue_mode(module_idP,0,eNB_indexP); - uint8_t lcid = CCCH; - uint16_t Size16; - struct RACH_ConfigCommon *rach_ConfigCommon = (struct RACH_ConfigCommon *)NULL; - int32_t frame_diff = 0; - mac_rlc_status_resp_t rlc_status; - uint8_t dcch_header_len = 0; - uint16_t sdu_lengths[8]; - uint8_t ulsch_buff[MAX_ULSCH_PAYLOAD_BYTES]; + uint8_t Size = 0; + UE_MODE_t UE_mode = get_ue_mode(module_idP, 0, eNB_indexP); + uint8_t lcid = CCCH; + uint16_t Size16; + struct RACH_ConfigCommon *rach_ConfigCommon = + (struct RACH_ConfigCommon *) NULL; + int32_t frame_diff = 0; + mac_rlc_status_resp_t rlc_status; + uint8_t dcch_header_len = 0; + uint16_t sdu_lengths[8]; + uint8_t ulsch_buff[MAX_ULSCH_PAYLOAD_BYTES]; - AssertFatal(CC_id==0, - "Transmission on secondary CCs is not supported yet\n"); + AssertFatal(CC_id == 0, + "Transmission on secondary CCs is not supported yet\n"); - if (UE_mode == PRACH) { - if (UE_mac_inst[module_idP].radioResourceConfigCommon) { - rach_ConfigCommon = &UE_mac_inst[module_idP].radioResourceConfigCommon->rach_ConfigCommon; - } else { - return(NULL); + if (UE_mode == PRACH) { + if (UE_mac_inst[module_idP].radioResourceConfigCommon) { + rach_ConfigCommon = + &UE_mac_inst[module_idP]. + radioResourceConfigCommon->rach_ConfigCommon; + } else { + return (NULL); + } + + if (UE_mac_inst[module_idP].RA_active == 0) { + LOG_I(MAC, "RA not active\n"); + // check if RRC is ready to initiate the RA procedure + Size = mac_rrc_data_req(module_idP, + CC_id, + frameP, + CCCH, 1, + &UE_mac_inst[module_idP]. + CCCH_pdu.payload[sizeof + (SCH_SUBHEADER_SHORT) + + 1], 0, eNB_indexP, + 0); + Size16 = (uint16_t) Size; + + // LOG_D(MAC,"[UE %d] Frame %d: Requested RRCConnectionRequest, got %d bytes\n",module_idP,frameP,Size); + LOG_I(RRC, + "[MSC_MSG][FRAME %05d][RRC_UE][MOD %02d][][--- MAC_DATA_REQ (RRCConnectionRequest eNB %d) --->][MAC_UE][MOD %02d][]\n", + frameP, module_idP, eNB_indexP, module_idP); + LOG_I(MAC, + "[UE %d] Frame %d: Requested RRCConnectionRequest, got %d bytes\n", + module_idP, frameP, Size); + + if (Size > 0) { + + UE_mac_inst[module_idP].RA_active = 1; + UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER = + 1; + UE_mac_inst[module_idP].RA_Msg3_size = + Size + sizeof(SCH_SUBHEADER_SHORT) + + sizeof(SCH_SUBHEADER_SHORT); + UE_mac_inst[module_idP].RA_prachMaskIndex = 0; + UE_mac_inst[module_idP].RA_prach_resources.Msg3 = + UE_mac_inst[module_idP].CCCH_pdu.payload; + UE_mac_inst[module_idP].RA_backoff_cnt = 0; // add the backoff condition here if we have it from a previous RA reponse which failed (i.e. backoff indicator) + + AssertFatal(rach_ConfigCommon != NULL, + "[UE %d] FATAL Frame %d: rach_ConfigCommon is NULL !!!\n", + module_idP, frameP); + UE_mac_inst[module_idP].RA_window_cnt = + 2 + + rach_ConfigCommon->ra_SupervisionInfo. + ra_ResponseWindowSize; + + if (UE_mac_inst[module_idP].RA_window_cnt == 9) { + UE_mac_inst[module_idP].RA_window_cnt = 10; // Note: 9 subframe window doesn't exist, after 8 is 10! + } + + UE_mac_inst[module_idP].RA_tx_frame = frameP; + UE_mac_inst[module_idP].RA_tx_subframe = subframeP; + UE_mac_inst[module_idP].RA_backoff_frame = frameP; + UE_mac_inst[module_idP].RA_backoff_subframe = subframeP; + // Fill in preamble and PRACH resource + get_prach_resources(module_idP, CC_id, eNB_indexP, + subframeP, 1, NULL); + + generate_ulsch_header((uint8_t *) & UE_mac_inst[module_idP].CCCH_pdu.payload[0], // mac header + 1, // num sdus + 0, // short pading + &Size16, // sdu length + &lcid, // sdu lcid + NULL, // power headroom + NULL, // crnti + NULL, // truncated bsr + NULL, // short bsr + NULL, // long_bsr + 1); //post_padding + return (&UE_mac_inst[module_idP].RA_prach_resources); + + } else if (UE_mac_inst[module_idP]. + scheduling_info.BSR_bytes[UE_mac_inst[module_idP]. + scheduling_info.LCGID + [DCCH]] > 0) { + // This is for triggering a transmission on DCCH using PRACH (during handover, or sending SR for example) + dcch_header_len = 2 + 2; /// SHORT Subheader + C-RNTI control element + rlc_status = + mac_rlc_status_ind(module_idP, + UE_mac_inst[module_idP].crnti, + eNB_indexP, frameP, subframeP, + ENB_FLAG_NO, MBMS_FLAG_NO, DCCH, 6); + + if (UE_mac_inst[module_idP].crnti_before_ho) + LOG_D(MAC, + "[UE %d] Frame %d : UL-DCCH -> ULSCH, HO RRCConnectionReconfigurationComplete (%x, %x), RRC message has %d bytes to send throug PRACH (mac header len %d)\n", + module_idP, frameP, + UE_mac_inst[module_idP].crnti, + UE_mac_inst[module_idP].crnti_before_ho, + rlc_status.bytes_in_buffer, dcch_header_len); + else + LOG_D(MAC, + "[UE %d] Frame %d : UL-DCCH -> ULSCH, RRC message has %d bytes to send through PRACH(mac header len %d)\n", + module_idP, frameP, rlc_status.bytes_in_buffer, + dcch_header_len); + + sdu_lengths[0] = mac_rlc_data_req(module_idP, UE_mac_inst[module_idP].crnti, eNB_indexP, frameP, ENB_FLAG_NO, MBMS_FLAG_NO, DCCH, 6, //not used + (char *) &ulsch_buff[0]); + + LOG_D(MAC, "[UE %d] TX Got %d bytes for DCCH\n", + module_idP, sdu_lengths[0]); + update_bsr(module_idP, frameP, subframeP, eNB_indexP); + UE_mac_inst[module_idP]. + scheduling_info.BSR[UE_mac_inst[module_idP]. + scheduling_info.LCGID[DCCH]] = + locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, + UE_mac_inst + [module_idP].scheduling_info.BSR_bytes + [UE_mac_inst + [module_idP].scheduling_info.LCGID + [DCCH]]); + + //TO DO: fill BSR infos in UL TBS + + //header_len +=2; + UE_mac_inst[module_idP].RA_active = 1; + UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER = + 1; + UE_mac_inst[module_idP].RA_Msg3_size = + Size + dcch_header_len; + UE_mac_inst[module_idP].RA_prachMaskIndex = 0; + UE_mac_inst[module_idP].RA_prach_resources.Msg3 = + ulsch_buff; + UE_mac_inst[module_idP].RA_backoff_cnt = 0; // add the backoff condition here if we have it from a previous RA reponse which failed (i.e. backoff indicator) + + AssertFatal(rach_ConfigCommon != NULL, + "[UE %d] FATAL Frame %d: rach_ConfigCommon is NULL !!!\n", + module_idP, frameP); + UE_mac_inst[module_idP].RA_window_cnt = + 2 + + rach_ConfigCommon->ra_SupervisionInfo. + ra_ResponseWindowSize; + + if (UE_mac_inst[module_idP].RA_window_cnt == 9) { + UE_mac_inst[module_idP].RA_window_cnt = 10; // Note: 9 subframe window doesn't exist, after 8 is 10! + } + + + UE_mac_inst[module_idP].RA_tx_frame = frameP; + UE_mac_inst[module_idP].RA_tx_subframe = subframeP; + UE_mac_inst[module_idP].RA_backoff_frame = frameP; + UE_mac_inst[module_idP].RA_backoff_subframe = subframeP; + // Fill in preamble and PRACH resource + get_prach_resources(module_idP, CC_id, eNB_indexP, + subframeP, 1, NULL); + generate_ulsch_header((uint8_t *) ulsch_buff, // mac header + 1, // num sdus + 0, // short pading + &Size16, // sdu length + &lcid, // sdu lcid + NULL, // power headroom + &UE_mac_inst[module_idP].crnti, // crnti + NULL, // truncated bsr + NULL, // short bsr + NULL, // long_bsr + 0); //post_padding + + return (&UE_mac_inst[module_idP].RA_prach_resources); + } + } else { // RACH is active + LOG_D(MAC, + "[MAC][UE %d][RAPROC] frameP %d, subframe %d: RA Active, window cnt %d (RA_tx_frame %d, RA_tx_subframe %d)\n", + module_idP, frameP, subframeP, + UE_mac_inst[module_idP].RA_window_cnt, + UE_mac_inst[module_idP].RA_tx_frame, + UE_mac_inst[module_idP].RA_tx_subframe); + + // compute backoff parameters + if (UE_mac_inst[module_idP].RA_backoff_cnt > 0) { + frame_diff = + (sframe_t) frameP - + UE_mac_inst[module_idP].RA_backoff_frame; + + if (frame_diff < 0) { + frame_diff = -frame_diff; + } + + UE_mac_inst[module_idP].RA_backoff_cnt -= + ((10 * frame_diff) + + (subframeP - + UE_mac_inst[module_idP].RA_backoff_subframe)); + + UE_mac_inst[module_idP].RA_backoff_frame = frameP; + UE_mac_inst[module_idP].RA_backoff_subframe = subframeP; + } + // compute RA window parameters + if (UE_mac_inst[module_idP].RA_window_cnt > 0) { + frame_diff = + (frame_t) frameP - UE_mac_inst[module_idP].RA_tx_frame; + + if (frame_diff < 0) { + frame_diff = -frame_diff; + } + + UE_mac_inst[module_idP].RA_window_cnt -= + ((10 * frame_diff) + + (subframeP - UE_mac_inst[module_idP].RA_tx_subframe)); + LOG_D(MAC, + "[MAC][UE %d][RAPROC] frameP %d, subframe %d: RA Active, adjusted window cnt %d\n", + module_idP, frameP, subframeP, + UE_mac_inst[module_idP].RA_window_cnt); + } + + if ((UE_mac_inst[module_idP].RA_window_cnt <= 0) && + (UE_mac_inst[module_idP].RA_backoff_cnt <= 0)) { + + UE_mac_inst[module_idP].RA_tx_frame = frameP; + UE_mac_inst[module_idP].RA_tx_subframe = subframeP; + UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER++; + UE_mac_inst[module_idP].RA_prach_resources.ra_PREAMBLE_RECEIVED_TARGET_POWER += (rach_ConfigCommon->powerRampingParameters.powerRampingStep << 1); // 2dB increments in ASN.1 definition + int preambleTransMax = -1; + switch (rach_ConfigCommon->ra_SupervisionInfo. + preambleTransMax) { + case PreambleTransMax_n3: + preambleTransMax = 3; + break; + case PreambleTransMax_n4: + preambleTransMax = 4; + break; + case PreambleTransMax_n5: + preambleTransMax = 5; + break; + case PreambleTransMax_n6: + preambleTransMax = 6; + break; + case PreambleTransMax_n7: + preambleTransMax = 7; + break; + case PreambleTransMax_n8: + preambleTransMax = 8; + break; + case PreambleTransMax_n10: + preambleTransMax = 10; + break; + case PreambleTransMax_n20: + preambleTransMax = 20; + break; + case PreambleTransMax_n50: + preambleTransMax = 50; + break; + case PreambleTransMax_n100: + preambleTransMax = 100; + break; + case PreambleTransMax_n200: + preambleTransMax = 200; + break; + } + + if (UE_mac_inst[module_idP]. + RA_PREAMBLE_TRANSMISSION_COUNTER == preambleTransMax) { + LOG_D(MAC, + "[UE %d] Frame %d: Maximum number of RACH attempts (%d)\n", + module_idP, frameP, preambleTransMax); + // send message to RRC + UE_mac_inst[module_idP]. + RA_PREAMBLE_TRANSMISSION_COUNTER = 1; + UE_mac_inst[module_idP]. + RA_prach_resources.ra_PREAMBLE_RECEIVED_TARGET_POWER + = get_Po_NOMINAL_PUSCH(module_idP, CC_id); + } + + UE_mac_inst[module_idP].RA_window_cnt = + 2 + + rach_ConfigCommon->ra_SupervisionInfo. + ra_ResponseWindowSize; + UE_mac_inst[module_idP].RA_backoff_cnt = 0; + + // Fill in preamble and PRACH resource + get_prach_resources(module_idP, CC_id, eNB_indexP, + subframeP, 0, NULL); + return (&UE_mac_inst[module_idP].RA_prach_resources); + } + } + } else if (UE_mode == PUSCH) { + LOG_D(MAC, + "[UE %d] FATAL: Should not have checked for RACH in PUSCH yet ...", + module_idP); + AssertFatal(1 == 0, ""); } - if (UE_mac_inst[module_idP].RA_active == 0) { - LOG_I(MAC,"RA not active\n"); - // check if RRC is ready to initiate the RA procedure - Size = mac_rrc_data_req(module_idP, - CC_id, - frameP, - CCCH,1, - &UE_mac_inst[module_idP].CCCH_pdu.payload[sizeof(SCH_SUBHEADER_SHORT)+1],0, - eNB_indexP, - 0); - Size16 = (uint16_t)Size; - - // LOG_D(MAC,"[UE %d] Frame %d: Requested RRCConnectionRequest, got %d bytes\n",module_idP,frameP,Size); - LOG_I(RRC, "[MSC_MSG][FRAME %05d][RRC_UE][MOD %02d][][--- MAC_DATA_REQ (RRCConnectionRequest eNB %d) --->][MAC_UE][MOD %02d][]\n", - frameP, module_idP, eNB_indexP, module_idP); - LOG_I(MAC,"[UE %d] Frame %d: Requested RRCConnectionRequest, got %d bytes\n",module_idP,frameP,Size); - - if (Size>0) { - - UE_mac_inst[module_idP].RA_active = 1; - UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER = 1; - UE_mac_inst[module_idP].RA_Msg3_size = Size+sizeof(SCH_SUBHEADER_SHORT)+sizeof(SCH_SUBHEADER_SHORT); - UE_mac_inst[module_idP].RA_prachMaskIndex = 0; - UE_mac_inst[module_idP].RA_prach_resources.Msg3 = UE_mac_inst[module_idP].CCCH_pdu.payload; - UE_mac_inst[module_idP].RA_backoff_cnt = 0; // add the backoff condition here if we have it from a previous RA reponse which failed (i.e. backoff indicator) - - AssertFatal(rach_ConfigCommon!=NULL, - "[UE %d] FATAL Frame %d: rach_ConfigCommon is NULL !!!\n",module_idP,frameP); - UE_mac_inst[module_idP].RA_window_cnt = 2+ rach_ConfigCommon->ra_SupervisionInfo.ra_ResponseWindowSize; - - if (UE_mac_inst[module_idP].RA_window_cnt == 9) { - UE_mac_inst[module_idP].RA_window_cnt = 10; // Note: 9 subframe window doesn't exist, after 8 is 10! - } - - UE_mac_inst[module_idP].RA_tx_frame = frameP; - UE_mac_inst[module_idP].RA_tx_subframe = subframeP; - UE_mac_inst[module_idP].RA_backoff_frame = frameP; - UE_mac_inst[module_idP].RA_backoff_subframe = subframeP; - // Fill in preamble and PRACH resource - get_prach_resources(module_idP,CC_id,eNB_indexP,subframeP,1,NULL); - - generate_ulsch_header((uint8_t*)&UE_mac_inst[module_idP].CCCH_pdu.payload[0], // mac header - 1, // num sdus - 0, // short pading - &Size16, // sdu length - &lcid, // sdu lcid - NULL, // power headroom - NULL, // crnti - NULL, // truncated bsr - NULL, // short bsr - NULL, // long_bsr - 1); //post_padding - return(&UE_mac_inst[module_idP].RA_prach_resources); - - } else if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] > 0) { - // This is for triggering a transmission on DCCH using PRACH (during handover, or sending SR for example) - dcch_header_len = 2 + 2; /// SHORT Subheader + C-RNTI control element - rlc_status = mac_rlc_status_ind(module_idP,UE_mac_inst[module_idP].crnti, eNB_indexP,frameP,subframeP,ENB_FLAG_NO,MBMS_FLAG_NO, - DCCH, - 6); - - if (UE_mac_inst[module_idP].crnti_before_ho) - LOG_D(MAC, - "[UE %d] Frame %d : UL-DCCH -> ULSCH, HO RRCConnectionReconfigurationComplete (%x, %x), RRC message has %d bytes to send throug PRACH (mac header len %d)\n", - module_idP,frameP, UE_mac_inst[module_idP].crnti,UE_mac_inst[module_idP].crnti_before_ho, rlc_status.bytes_in_buffer,dcch_header_len); - else - LOG_D(MAC,"[UE %d] Frame %d : UL-DCCH -> ULSCH, RRC message has %d bytes to send through PRACH(mac header len %d)\n", - module_idP,frameP, rlc_status.bytes_in_buffer,dcch_header_len); - - sdu_lengths[0] = mac_rlc_data_req(module_idP, UE_mac_inst[module_idP].crnti, - eNB_indexP, frameP,ENB_FLAG_NO, MBMS_FLAG_NO, - DCCH, - 6, //not used - (char *)&ulsch_buff[0]); - - LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH\n",module_idP,sdu_lengths[0]); - update_bsr(module_idP, frameP, subframeP,eNB_indexP); - UE_mac_inst[module_idP].scheduling_info.BSR[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] = - locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]]); - - //TO DO: fill BSR infos in UL TBS - - //header_len +=2; - UE_mac_inst[module_idP].RA_active = 1; - UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER = 1; - UE_mac_inst[module_idP].RA_Msg3_size = Size+dcch_header_len; - UE_mac_inst[module_idP].RA_prachMaskIndex = 0; - UE_mac_inst[module_idP].RA_prach_resources.Msg3 = ulsch_buff; - UE_mac_inst[module_idP].RA_backoff_cnt = 0; // add the backoff condition here if we have it from a previous RA reponse which failed (i.e. backoff indicator) - - AssertFatal(rach_ConfigCommon!=NULL, - "[UE %d] FATAL Frame %d: rach_ConfigCommon is NULL !!!\n",module_idP,frameP); - UE_mac_inst[module_idP].RA_window_cnt = 2+ rach_ConfigCommon->ra_SupervisionInfo.ra_ResponseWindowSize; - - if (UE_mac_inst[module_idP].RA_window_cnt == 9) { - UE_mac_inst[module_idP].RA_window_cnt = 10; // Note: 9 subframe window doesn't exist, after 8 is 10! - } - - - UE_mac_inst[module_idP].RA_tx_frame = frameP; - UE_mac_inst[module_idP].RA_tx_subframe = subframeP; - UE_mac_inst[module_idP].RA_backoff_frame = frameP; - UE_mac_inst[module_idP].RA_backoff_subframe = subframeP; - // Fill in preamble and PRACH resource - get_prach_resources(module_idP,CC_id,eNB_indexP,subframeP,1,NULL); - generate_ulsch_header((uint8_t*)ulsch_buff, // mac header - 1, // num sdus - 0, // short pading - &Size16, // sdu length - &lcid, // sdu lcid - NULL, // power headroom - &UE_mac_inst[module_idP].crnti, // crnti - NULL, // truncated bsr - NULL, // short bsr - NULL, // long_bsr - 0); //post_padding - - return(&UE_mac_inst[module_idP].RA_prach_resources); - } - } else { // RACH is active - LOG_D(MAC,"[MAC][UE %d][RAPROC] frameP %d, subframe %d: RA Active, window cnt %d (RA_tx_frame %d, RA_tx_subframe %d)\n",module_idP, - frameP,subframeP,UE_mac_inst[module_idP].RA_window_cnt, - UE_mac_inst[module_idP].RA_tx_frame,UE_mac_inst[module_idP].RA_tx_subframe); - - // compute backoff parameters - if (UE_mac_inst[module_idP].RA_backoff_cnt>0) { - frame_diff = (sframe_t)frameP - UE_mac_inst[module_idP].RA_backoff_frame; - - if (frame_diff < 0) { - frame_diff = -frame_diff; - } - - UE_mac_inst[module_idP].RA_backoff_cnt -= ((10*frame_diff) + (subframeP-UE_mac_inst[module_idP].RA_backoff_subframe)); - - UE_mac_inst[module_idP].RA_backoff_frame = frameP; - UE_mac_inst[module_idP].RA_backoff_subframe = subframeP; - } - - // compute RA window parameters - if (UE_mac_inst[module_idP].RA_window_cnt>0) { - frame_diff = (frame_t)frameP - UE_mac_inst[module_idP].RA_tx_frame; - - if (frame_diff < 0) { - frame_diff = -frame_diff; - } - - UE_mac_inst[module_idP].RA_window_cnt -= ((10*frame_diff) + (subframeP-UE_mac_inst[module_idP].RA_tx_subframe)); - LOG_D(MAC,"[MAC][UE %d][RAPROC] frameP %d, subframe %d: RA Active, adjusted window cnt %d\n",module_idP, - frameP,subframeP,UE_mac_inst[module_idP].RA_window_cnt); - } - - if ((UE_mac_inst[module_idP].RA_window_cnt<=0) && - (UE_mac_inst[module_idP].RA_backoff_cnt<=0)) { - - UE_mac_inst[module_idP].RA_tx_frame = frameP; - UE_mac_inst[module_idP].RA_tx_subframe = subframeP; - UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER++; - UE_mac_inst[module_idP].RA_prach_resources.ra_PREAMBLE_RECEIVED_TARGET_POWER += - (rach_ConfigCommon->powerRampingParameters.powerRampingStep<<1); // 2dB increments in ASN.1 definition - int preambleTransMax = -1; - switch (rach_ConfigCommon->ra_SupervisionInfo.preambleTransMax) { - case PreambleTransMax_n3: - preambleTransMax = 3; - break; - case PreambleTransMax_n4: - preambleTransMax = 4; - break; - case PreambleTransMax_n5: - preambleTransMax = 5; - break; - case PreambleTransMax_n6: - preambleTransMax = 6; - break; - case PreambleTransMax_n7: - preambleTransMax = 7; - break; - case PreambleTransMax_n8: - preambleTransMax = 8; - break; - case PreambleTransMax_n10: - preambleTransMax = 10; - break; - case PreambleTransMax_n20: - preambleTransMax = 20; - break; - case PreambleTransMax_n50: - preambleTransMax = 50; - break; - case PreambleTransMax_n100: - preambleTransMax = 100; - break; - case PreambleTransMax_n200: - preambleTransMax = 200; - break; - } - - if (UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER == preambleTransMax) { - LOG_D(MAC,"[UE %d] Frame %d: Maximum number of RACH attempts (%d)\n",module_idP,frameP,preambleTransMax); - // send message to RRC - UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER=1; - UE_mac_inst[module_idP].RA_prach_resources.ra_PREAMBLE_RECEIVED_TARGET_POWER = get_Po_NOMINAL_PUSCH(module_idP,CC_id); - } - - UE_mac_inst[module_idP].RA_window_cnt = 2+ rach_ConfigCommon->ra_SupervisionInfo.ra_ResponseWindowSize; - UE_mac_inst[module_idP].RA_backoff_cnt = 0; - - // Fill in preamble and PRACH resource - get_prach_resources(module_idP,CC_id,eNB_indexP,subframeP,0,NULL); - return(&UE_mac_inst[module_idP].RA_prach_resources); - } - } - } else if (UE_mode == PUSCH) { - LOG_D(MAC,"[UE %d] FATAL: Should not have checked for RACH in PUSCH yet ...",module_idP); - AssertFatal(1==0,""); - } - - return(NULL); + return (NULL); } diff --git a/openair2/LAYER2/MAC/rar_tools.c b/openair2/LAYER2/MAC/rar_tools.c index ad870b6387..8d9e5bb3e1 100644 --- a/openair2/LAYER2/MAC/rar_tools.c +++ b/openair2/LAYER2/MAC/rar_tools.c @@ -40,269 +40,246 @@ #define DEBUG_RAR -extern unsigned int localRIV2alloc_LUT25[512]; -extern unsigned int distRIV2alloc_LUT25[512]; +extern unsigned int localRIV2alloc_LUT25[512]; +extern unsigned int distRIV2alloc_LUT25[512]; extern unsigned short RIV2nb_rb_LUT25[512]; extern unsigned short RIV2first_rb_LUT25[512]; extern RAN_CONTEXT_t RC; //------------------------------------------------------------------------------ -unsigned short fill_rar( - const module_id_t module_idP, - const int CC_id, - const frame_t frameP, - uint8_t* const dlsch_buffer, - const uint16_t N_RB_UL, - const uint8_t input_buffer_length -) +unsigned short +fill_rar(const module_id_t module_idP, + const int CC_id, + RA_t * ra, + const frame_t frameP, + uint8_t * const dlsch_buffer, + const uint16_t N_RB_UL, const uint8_t input_buffer_length) //------------------------------------------------------------------------------ { - RA_HEADER_RAPID *rarh = (RA_HEADER_RAPID *)dlsch_buffer; - // RAR_PDU *rar = (RAR_PDU *)(dlsch_buffer+1); - uint8_t *rar = (uint8_t *)(dlsch_buffer+1); - int i,ra_idx = -1; - RA_TEMPLATE *RA_template; + RA_HEADER_RAPID *rarh = (RA_HEADER_RAPID *) dlsch_buffer; + uint8_t *rar = (uint8_t *) (dlsch_buffer + 1); - AssertFatal(CC_id < MAX_NUM_CCs, "CC_id %u < MAX_NUM_CCs %u", CC_id, MAX_NUM_CCs); - for (i=0; icommon_channels[CC_id].RA_template[i].generate_rar == 1) { - ra_idx=i; - RC.mac[module_idP]->common_channels[CC_id].RA_template[i].generate_rar = 0; - break; + // subheader fixed + rarh->E = 0; // First and last RAR + rarh->T = 1; // 0 for E/T/R/R/BI subheader, 1 for E/T/RAPID subheader + rarh->RAPID = ra->preamble_index; // Respond to Preamble 0 only for the moment + rar[4] = (uint8_t) (ra->rnti >> 8); + rar[5] = (uint8_t) (ra->rnti & 0xff); + //ra->timing_offset = 0; + ra->timing_offset /= 16; //T_A = N_TA/16, where N_TA should be on a 30.72Msps + rar[0] = (uint8_t) (ra->timing_offset >> (2 + 4)); // 7 MSBs of timing advance + divide by 4 + rar[1] = (uint8_t) (ra->timing_offset << (4 - 2)) & 0xf0; // 4 LSBs of timing advance + divide by 4 + ra->msg3_first_rb = 6; + ra->msg3_nb_rb = 1; + uint16_t rballoc = mac_computeRIV(N_RB_UL, ra->msg3_first_rb, ra->msg3_nb_rb); // first PRB only for UL Grant + rar[1] |= (rballoc >> 7) & 7; // Hopping = 0 (bit 3), 3 MSBs of rballoc + rar[2] = ((uint8_t) (rballoc & 0xff)) << 1; // 7 LSBs of rballoc + ra->msg3_mcs = 10; + ra->msg3_TPC = 3; + ra->msg3_ULdelay = 0; + ra->msg3_cqireq = 0; + rar[2] |= ((ra->msg3_mcs & 0x8) >> 3); // mcs 10 + rar[3] = + (((ra->msg3_mcs & 0x7) << 5)) | ((ra->msg3_TPC & 7) << 2) | + ((ra->msg3_ULdelay & 1) << 1) | (ra->msg3_cqireq & 1); + + if (opt_enabled) { + trace_pdu(1, dlsch_buffer, input_buffer_length, module_idP, 2, 1, + RC.mac[module_idP]->frame, RC.mac[module_idP]->subframe, + 0, 0); + LOG_D(OPT, + "[eNB %d][RAPROC] CC_id %d RAR Frame %d trace pdu for rnti %x and rapid %d size %d\n", + module_idP, CC_id, frameP, ra->rnti, rarh->RAPID, + input_buffer_length); } - } - RA_template = &RC.mac[module_idP]->common_channels[CC_id].RA_template[ra_idx]; - - //DevAssert( ra_idx != -1 ); - if (ra_idx==-1) - return(0); - // subheader fixed - rarh->E = 0; // First and last RAR - rarh->T = 1; // 0 for E/T/R/R/BI subheader, 1 for E/T/RAPID subheader - rarh->RAPID = RA_template->preamble_index; // Respond to Preamble 0 only for the moment - rar[4] = (uint8_t)(RA_template->rnti>>8); - rar[5] = (uint8_t)(RA_template->rnti&0xff); - //RA_template->timing_offset = 0; - RA_template->timing_offset /= 16; //T_A = N_TA/16, where N_TA should be on a 30.72Msps - rar[0] = (uint8_t)(RA_template->timing_offset>>(2+4)); // 7 MSBs of timing advance + divide by 4 - rar[1] = (uint8_t)(RA_template->timing_offset<<(4-2))&0xf0; // 4 LSBs of timing advance + divide by 4 - RA_template->msg3_first_rb=6; - RA_template->msg3_nb_rb=1; - uint16_t rballoc = mac_computeRIV(N_RB_UL,RA_template->msg3_first_rb,RA_template->msg3_nb_rb); // first PRB only for UL Grant - rar[1] |= (rballoc>>7)&7; // Hopping = 0 (bit 3), 3 MSBs of rballoc - rar[2] = ((uint8_t)(rballoc&0xff))<<1; // 7 LSBs of rballoc - RA_template->msg3_mcs = 10; - RA_template->msg3_TPC = 3; - RA_template->msg3_ULdelay = 0; - RA_template->msg3_cqireq = 0; - rar[2] |= ((RA_template->msg3_mcs&0x8)>>3); // mcs 10 - rar[3] = (((RA_template->msg3_mcs&0x7)<<5)) | ((RA_template->msg3_TPC&7)<<2) | ((RA_template->msg3_ULdelay&1)<<1) | (RA_template->msg3_cqireq&1); - - LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d Generating RAR (%02x|%02x.%02x.%02x.%02x.%02x.%02x) for ra_idx %d, CRNTI %x,preamble %d/%d,TIMING OFFSET %d\n", - module_idP, CC_id, - frameP, - *(uint8_t*)rarh,rar[0],rar[1],rar[2],rar[3],rar[4],rar[5], - ra_idx, - RA_template->rnti, - rarh->RAPID,RC.mac[module_idP]->common_channels[CC_id].RA_template[0].preamble_index, - RA_template->timing_offset); - - if (opt_enabled) { - trace_pdu(1, dlsch_buffer, input_buffer_length, module_idP, 2, 1, - RC.mac[module_idP]->frame, RC.mac[module_idP]->subframe, 0, 0); - LOG_D(OPT,"[eNB %d][RAPROC] CC_id %d RAR Frame %d trace pdu for rnti %x and rapid %d size %d\n", - module_idP, CC_id, frameP, RA_template->rnti, - rarh->RAPID, input_buffer_length); - } - - return(RA_template->rnti); + return (ra->rnti); } #ifdef Rel14 //------------------------------------------------------------------------------ -unsigned short fill_rar_br(eNB_MAC_INST *eNB, - int CC_id, - RA_TEMPLATE *RA_template, - const frame_t frameP, - const sub_frame_t subframeP, - uint8_t* const dlsch_buffer, - const uint8_t ce_level -) +unsigned short +fill_rar_br(eNB_MAC_INST * eNB, + int CC_id, + RA_t * ra, + const frame_t frameP, + const sub_frame_t subframeP, + uint8_t * const dlsch_buffer, const uint8_t ce_level) //------------------------------------------------------------------------------ { - RA_HEADER_RAPID *rarh = (RA_HEADER_RAPID *)dlsch_buffer; - COMMON_channels_t *cc = &eNB->common_channels[CC_id]; - uint8_t *rar = (uint8_t *)(dlsch_buffer+1); - // uint8_t nb,reps; - uint8_t rballoc; - uint8_t mcs,TPC,ULdelay,cqireq; - int input_buffer_length; + RA_HEADER_RAPID *rarh = (RA_HEADER_RAPID *) dlsch_buffer; + COMMON_channels_t *cc = &eNB->common_channels[CC_id]; + uint8_t *rar = (uint8_t *) (dlsch_buffer + 1); + // uint8_t nb,reps; + uint8_t rballoc; + uint8_t mcs, TPC, ULdelay, cqireq; + int input_buffer_length; - AssertFatal(RA_template != NULL, "RA is null \n"); + AssertFatal(ra != NULL, "RA is null \n"); - // subheader fixed - rarh->E = 0; // First and last RAR - rarh->T = 1; // 0 for E/T/R/R/BI subheader, 1 for E/T/RAPID subheader - rarh->RAPID = RA_template->preamble_index; // Respond to Preamble 0 only for the moment - RA_template->timing_offset /= 16; //T_A = N_TA/16, where N_TA should be on a 30.72Msps - rar[0] = (uint8_t)(RA_template->timing_offset>>(2+4)); // 7 MSBs of timing advance + divide by 4 - rar[1] = (uint8_t)(RA_template->timing_offset<<(4-2))&0xf0; // 4 LSBs of timing advance + divide by 4 + // subheader fixed + rarh->E = 0; // First and last RAR + rarh->T = 1; // 0 for E/T/R/R/BI subheader, 1 for E/T/RAPID subheader + rarh->RAPID = ra->preamble_index; // Respond to Preamble 0 only for the moment + ra->timing_offset /= 16; //T_A = N_TA/16, where N_TA should be on a 30.72Msps + rar[0] = (uint8_t) (ra->timing_offset >> (2 + 4)); // 7 MSBs of timing advance + divide by 4 + rar[1] = (uint8_t) (ra->timing_offset << (4 - 2)) & 0xf0; // 4 LSBs of timing advance + divide by 4 - int N_NB_index; + int N_NB_index; - AssertFatal(1==0,"RAR for BL/CE Still to be finished ...\n"); + AssertFatal(1 == 0, "RAR for BL/CE Still to be finished ...\n"); - // Copy the Msg2 narrowband - RA_template->msg34_narrowband = RA_template->msg2_narrowband; + // Copy the Msg2 narrowband + ra->msg34_narrowband = ra->msg2_narrowband; - if (ce_level<2) { //CE Level 0,1, CEmodeA - input_buffer_length =6; + if (ce_level < 2) { //CE Level 0,1, CEmodeA + input_buffer_length = 6; - N_NB_index = get_numnarrowbandbits(cc->mib->message.dl_Bandwidth); + N_NB_index = get_numnarrowbandbits(cc->mib->message.dl_Bandwidth); - rar[4] = (uint8_t)(RA_template->rnti>>8); - rar[5] = (uint8_t)(RA_template->rnti&0xff); - //cc->RA_template[ra_idx].timing_offset = 0; - // nb = 0; - rballoc = mac_computeRIV(6,1+ce_level,1); // one PRB only for UL Grant in position 1+ce_level within Narrowband - rar[1] |= (rballoc&15)<<(4-N_NB_index); // Hopping = 0 (bit 3), 3 MSBs of rballoc + rar[4] = (uint8_t) (ra->rnti >> 8); + rar[5] = (uint8_t) (ra->rnti & 0xff); + //cc->ra[ra_idx].timing_offset = 0; + // nb = 0; + rballoc = mac_computeRIV(6, 1 + ce_level, 1); // one PRB only for UL Grant in position 1+ce_level within Narrowband + rar[1] |= (rballoc & 15) << (4 - N_NB_index); // Hopping = 0 (bit 3), 3 MSBs of rballoc - // reps = 4; - mcs = 7; - TPC = 3; // no power increase - ULdelay = 0; - cqireq = 0; - rar[2] |= ((mcs&0x8)>>3); // mcs 10 - rar[3] = (((mcs&0x7)<<5)) | ((TPC&7)<<2) | ((ULdelay&1)<<1) | (cqireq&1); - } - else { // CE level 2,3 => CEModeB + // reps = 4; + mcs = 7; + TPC = 3; // no power increase + ULdelay = 0; + cqireq = 0; + rar[2] |= ((mcs & 0x8) >> 3); // mcs 10 + rar[3] = + (((mcs & 0x7) << 5)) | ((TPC & 7) << 2) | ((ULdelay & 1) << 1) + | (cqireq & 1); + } else { // CE level 2,3 => CEModeB - input_buffer_length =5; + input_buffer_length = 5; - rar[3] = (uint8_t)(RA_template->rnti>>8); - rar[4] = (uint8_t)(RA_template->rnti&0xff); - } - LOG_D(MAC,"[RAPROC] Frame %d Generating RAR BR (%02x|%02x.%02x.%02x.%02x.%02x.%02x) for ce_level %d, CRNTI %x,preamble %d/%d,TIMING OFFSET %d\n", - frameP, - *(uint8_t*)rarh,rar[0],rar[1],rar[2],rar[3],rar[4],rar[5], - ce_level, - RA_template->rnti, - rarh->RAPID,RA_template->preamble_index, - RA_template->timing_offset); + rar[3] = (uint8_t) (ra->rnti >> 8); + rar[4] = (uint8_t) (ra->rnti & 0xff); + } + LOG_D(MAC, + "[RAPROC] Frame %d Generating RAR BR (%02x|%02x.%02x.%02x.%02x.%02x.%02x) for ce_level %d, CRNTI %x,preamble %d/%d,TIMING OFFSET %d\n", + frameP, *(uint8_t *) rarh, rar[0], rar[1], rar[2], rar[3], + rar[4], rar[5], ce_level, ra->rnti, rarh->RAPID, + ra->preamble_index, ra->timing_offset); - if (opt_enabled) { - trace_pdu(1, dlsch_buffer, input_buffer_length, eNB->Mod_id, 2, 1, - eNB->frame, eNB->subframe, 0, 0); - LOG_D(OPT,"[RAPROC] RAR Frame %d trace pdu for rnti %x and rapid %d size %d\n", - frameP, RA_template->rnti, - rarh->RAPID, input_buffer_length); - } + if (opt_enabled) { + trace_pdu(1, dlsch_buffer, input_buffer_length, eNB->Mod_id, 2, 1, + eNB->frame, eNB->subframe, 0, 0); + LOG_D(OPT, + "[RAPROC] RAR Frame %d trace pdu for rnti %x and rapid %d size %d\n", + frameP, ra->rnti, rarh->RAPID, input_buffer_length); + } - return(RA_template->rnti); + return (ra->rnti); } #endif //------------------------------------------------------------------------------ -uint16_t -ue_process_rar( - const module_id_t module_idP, - const int CC_id, - const frame_t frameP, - const rnti_t ra_rnti, - uint8_t* const dlsch_buffer, - rnti_t* const t_crnti, - const uint8_t preamble_index, - uint8_t* selected_rar_buffer // output argument for storing the selected RAR header and RAR payload -) +uint16_t ue_process_rar(const module_id_t module_idP, const int CC_id, const frame_t frameP, const rnti_t ra_rnti, uint8_t * const dlsch_buffer, rnti_t * const t_crnti, const uint8_t preamble_index, uint8_t * selected_rar_buffer // output argument for storing the selected RAR header and RAR payload + ) //------------------------------------------------------------------------------ { - uint16_t ret = 0; // return value + uint16_t ret = 0; // return value - RA_HEADER_RAPID *rarh = (RA_HEADER_RAPID *)dlsch_buffer; - // RAR_PDU *rar = (RAR_PDU *)(dlsch_buffer+1); - uint8_t *rar = (uint8_t *)(dlsch_buffer+1); + RA_HEADER_RAPID *rarh = (RA_HEADER_RAPID *) dlsch_buffer; + // RAR_PDU *rar = (RAR_PDU *)(dlsch_buffer+1); + uint8_t *rar = (uint8_t *) (dlsch_buffer + 1); - // get the last RAR payload for working with CMW500 - uint8_t n_rarpy = 0; // number of RAR payloads - uint8_t n_rarh = 0; // number of MAC RAR subheaders - uint8_t best_rx_rapid = -1; // the closest RAPID receive from all RARs - while (1) { - n_rarh++; - if (rarh->T == 1) { - n_rarpy++; - LOG_D(MAC, "RAPID %d\n", rarh->RAPID); - } + // get the last RAR payload for working with CMW500 + uint8_t n_rarpy = 0; // number of RAR payloads + uint8_t n_rarh = 0; // number of MAC RAR subheaders + uint8_t best_rx_rapid = -1; // the closest RAPID receive from all RARs + while (1) { + n_rarh++; + if (rarh->T == 1) { + n_rarpy++; + LOG_D(MAC, "RAPID %d\n", rarh->RAPID); + } - if (rarh->RAPID == preamble_index) { - LOG_D(PHY, "Found RAR with the intended RAPID %d\n", rarh->RAPID); - rar = (uint8_t *)(dlsch_buffer+n_rarh + (n_rarpy-1)*6); - break; - } + if (rarh->RAPID == preamble_index) { + LOG_D(PHY, "Found RAR with the intended RAPID %d\n", + rarh->RAPID); + rar = (uint8_t *) (dlsch_buffer + n_rarh + (n_rarpy - 1) * 6); + break; + } - if (abs((int)rarh->RAPID - (int)preamble_index) < abs((int)best_rx_rapid - (int)preamble_index)) { - best_rx_rapid = rarh->RAPID; - rar = (uint8_t *)(dlsch_buffer+n_rarh + (n_rarpy-1)*6); - } + if (abs((int) rarh->RAPID - (int) preamble_index) < + abs((int) best_rx_rapid - (int) preamble_index)) { + best_rx_rapid = rarh->RAPID; + rar = (uint8_t *) (dlsch_buffer + n_rarh + (n_rarpy - 1) * 6); + } - if (rarh->E == 0) { - LOG_I(PHY, "No RAR found with the intended RAPID. The closest RAPID in all RARs is %d\n", best_rx_rapid); - break; - } else { - rarh++; - } - }; - LOG_D(MAC, "number of RAR subheader %d; number of RAR pyloads %d\n", n_rarh, n_rarpy); + if (rarh->E == 0) { + LOG_I(PHY, + "No RAR found with the intended RAPID. The closest RAPID in all RARs is %d\n", + best_rx_rapid); + break; + } else { + rarh++; + } + }; + LOG_D(MAC, "number of RAR subheader %d; number of RAR pyloads %d\n", + n_rarh, n_rarpy); - if (CC_id>0) { - LOG_W(MAC,"Should not have received RAR on secondary CCs! \n"); - return(0xffff); - } + if (CC_id > 0) { + LOG_W(MAC, "Should not have received RAR on secondary CCs! \n"); + return (0xffff); + } - LOG_I(MAC,"[eNB %d][RAPROC] Frame %d Received RAR (%02x|%02x.%02x.%02x.%02x.%02x.%02x) for preamble %d/%d\n",module_idP,frameP, - *(uint8_t*)rarh,rar[0],rar[1],rar[2],rar[3],rar[4],rar[5], - rarh->RAPID,preamble_index); + LOG_I(MAC, + "[eNB %d][RAPROC] Frame %d Received RAR (%02x|%02x.%02x.%02x.%02x.%02x.%02x) for preamble %d/%d\n", + module_idP, frameP, *(uint8_t *) rarh, rar[0], rar[1], rar[2], + rar[3], rar[4], rar[5], rarh->RAPID, preamble_index); #ifdef DEBUG_RAR - LOG_D(MAC,"[UE %d][RAPROC] rarh->E %d\n",module_idP,rarh->E); - LOG_D(MAC,"[UE %d][RAPROC] rarh->T %d\n",module_idP,rarh->T); - LOG_D(MAC,"[UE %d][RAPROC] rarh->RAPID %d\n",module_idP,rarh->RAPID); + LOG_D(MAC, "[UE %d][RAPROC] rarh->E %d\n", module_idP, rarh->E); + LOG_D(MAC, "[UE %d][RAPROC] rarh->T %d\n", module_idP, rarh->T); + LOG_D(MAC, "[UE %d][RAPROC] rarh->RAPID %d\n", module_idP, + rarh->RAPID); - // LOG_I(MAC,"[UE %d][RAPROC] rar->R %d\n",module_idP,rar->R); - LOG_D(MAC,"[UE %d][RAPROC] rar->Timing_Advance_Command %d\n",module_idP,(((uint16_t)(rar[0]&0x7f))<<4) + (rar[1]>>4)); - // LOG_I(MAC,"[UE %d][RAPROC] rar->hopping_flag %d\n",module_idP,rar->hopping_flag); - // LOG_I(MAC,"[UE %d][RAPROC] rar->rb_alloc %d\n",module_idP,rar->rb_alloc); - // LOG_I(MAC,"[UE %d][RAPROC] rar->mcs %d\n",module_idP,rar->mcs); - // LOG_I(MAC,"[UE %d][RAPROC] rar->TPC %d\n",module_idP,rar->TPC); - // LOG_I(MAC,"[UE %d][RAPROC] rar->UL_delay %d\n",module_idP,rar->UL_delay); - // LOG_I(MAC,"[UE %d][RAPROC] rar->cqi_req %d\n",module_idP,rar->cqi_req); - LOG_D(MAC,"[UE %d][RAPROC] rar->t_crnti %x\n",module_idP,(uint16_t)rar[5]+(rar[4]<<8)); + // LOG_I(MAC,"[UE %d][RAPROC] rar->R %d\n",module_idP,rar->R); + LOG_D(MAC, "[UE %d][RAPROC] rar->Timing_Advance_Command %d\n", + module_idP, (((uint16_t) (rar[0] & 0x7f)) << 4) + (rar[1] >> 4)); + // LOG_I(MAC,"[UE %d][RAPROC] rar->hopping_flag %d\n",module_idP,rar->hopping_flag); + // LOG_I(MAC,"[UE %d][RAPROC] rar->rb_alloc %d\n",module_idP,rar->rb_alloc); + // LOG_I(MAC,"[UE %d][RAPROC] rar->mcs %d\n",module_idP,rar->mcs); + // LOG_I(MAC,"[UE %d][RAPROC] rar->TPC %d\n",module_idP,rar->TPC); + // LOG_I(MAC,"[UE %d][RAPROC] rar->UL_delay %d\n",module_idP,rar->UL_delay); + // LOG_I(MAC,"[UE %d][RAPROC] rar->cqi_req %d\n",module_idP,rar->cqi_req); + LOG_D(MAC, "[UE %d][RAPROC] rar->t_crnti %x\n", module_idP, + (uint16_t) rar[5] + (rar[4] << 8)); #endif - if (opt_enabled) { - LOG_D(OPT,"[UE %d][RAPROC] CC_id %d RAR Frame %d trace pdu for ra-RNTI %x\n", - module_idP, CC_id, frameP, ra_rnti); - trace_pdu(1, (uint8_t*)dlsch_buffer, n_rarh + n_rarpy*6, module_idP, 2, ra_rnti, - UE_mac_inst[module_idP].rxFrame, UE_mac_inst[module_idP].rxSubframe, 0, 0); - } + if (opt_enabled) { + LOG_D(OPT, + "[UE %d][RAPROC] CC_id %d RAR Frame %d trace pdu for ra-RNTI %x\n", + module_idP, CC_id, frameP, ra_rnti); + trace_pdu(1, (uint8_t *) dlsch_buffer, n_rarh + n_rarpy * 6, + module_idP, 2, ra_rnti, UE_mac_inst[module_idP].rxFrame, + UE_mac_inst[module_idP].rxSubframe, 0, 0); + } - if (preamble_index == rarh->RAPID) { - *t_crnti = (uint16_t)rar[5]+(rar[4]<<8);//rar->t_crnti; - UE_mac_inst[module_idP].crnti = *t_crnti;//rar->t_crnti; - //return(rar->Timing_Advance_Command); - ret = ((((uint16_t)(rar[0]&0x7f))<<4) + (rar[1]>>4)); - } else { - UE_mac_inst[module_idP].crnti=0; - ret = (0xffff); - } + if (preamble_index == rarh->RAPID) { + *t_crnti = (uint16_t) rar[5] + (rar[4] << 8); //rar->t_crnti; + UE_mac_inst[module_idP].crnti = *t_crnti; //rar->t_crnti; + //return(rar->Timing_Advance_Command); + ret = ((((uint16_t) (rar[0] & 0x7f)) << 4) + (rar[1] >> 4)); + } else { + UE_mac_inst[module_idP].crnti = 0; + ret = (0xffff); + } - // move the selected RAR to the front of the RA_PDSCH buffer - memcpy(selected_rar_buffer+0, (uint8_t*)rarh, 1); - memcpy(selected_rar_buffer+1, (uint8_t*)rar , 6); + // move the selected RAR to the front of the RA_PDSCH buffer + memcpy(selected_rar_buffer + 0, (uint8_t *) rarh, 1); + memcpy(selected_rar_buffer + 1, (uint8_t *) rar, 6); - return ret; + return ret; } diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index d6c2512309..5b73a76312 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -37,10 +37,10 @@ #include "defs.h" #include "proto.h" #ifdef PHY_EMUL -# include "SIMULATION/PHY_EMULATION/impl_defs.h" +#include "SIMULATION/PHY_EMULATION/impl_defs.h" #else -# include "SCHED/defs.h" -# include "PHY/impl_defs_top.h" +#include "SCHED/defs.h" +#include "PHY/impl_defs_top.h" #endif #include "PHY_INTERFACE/extern.h" #include "COMMON/mac_rrc_primitives.h" @@ -54,17 +54,17 @@ #include "OCG_extern.h" #ifdef PHY_EMUL -# include "SIMULATION/simulation_defs.h" +#include "SIMULATION/simulation_defs.h" #endif #include "pdcp.h" #if defined(ENABLE_ITTI) -# include "intertask_interface.h" +#include "intertask_interface.h" #endif #include "assertions.h" -#include "SIMULATION/TOOLS/defs.h" // for taus +#include "SIMULATION/TOOLS/defs.h" // for taus #define DEBUG_HEADER_PARSING 1 #define ENABLE_MAC_PAYLOAD_DEBUG 1 @@ -77,1738 +77,2071 @@ extern uint8_t usim_test; #endif */ mapping BSR_names[] = { - {"NONE", 0}, - {"SHORT BSR", 1}, - {"TRUNCATED BSR", 2}, - {"LONG BSR", 3}, - {"PADDING BSR", 4}, - {NULL, -1} + {"NONE", 0}, + {"SHORT BSR", 1}, + {"TRUNCATED BSR", 2}, + {"LONG BSR", 3}, + {"PADDING BSR", 4}, + {NULL, -1} }; void ue_init_mac(module_id_t module_idP) { - int i; - // default values as deined in 36.331 sec 9.2.2 - LOG_I(MAC,"[UE%d] Applying default macMainConfig\n",module_idP); - //UE_mac_inst[module_idP].scheduling_info.macConfig=NULL; - UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer= RetxBSR_Timer_r12_sf10240; - UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer=PeriodicBSR_Timer_r12_infinity; - UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer = MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20; - UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer = MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20; - UE_mac_inst[module_idP].scheduling_info.PathlossChange_db = MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1; - UE_mac_inst[module_idP].PHR_state = MAC_MainConfig__phr_Config_PR_setup; - UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; - UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer=0; - UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer_Running=0; - UE_mac_inst[module_idP].scheduling_info.maxHARQ_Tx=MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; - UE_mac_inst[module_idP].scheduling_info.ttiBundling=0; - UE_mac_inst[module_idP].scheduling_info.extendedBSR_Sizes_r10=0; - UE_mac_inst[module_idP].scheduling_info.extendedPHR_r10=0; - UE_mac_inst[module_idP].scheduling_info.drx_config=NULL; - UE_mac_inst[module_idP].scheduling_info.phr_config=NULL; - // set init value 0xFFFF, make sure periodic timer and retx time counters are NOT active, after bsr transmission set the value configured by the NW. - UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; - UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; - UE_mac_inst[module_idP].BSR_reporting_active = BSR_TRIGGER_NONE; - - UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer); - UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer); - UE_mac_inst[module_idP].scheduling_info.PathlossChange_db = get_db_dl_PathlossChange(UE_mac_inst[module_idP].scheduling_info.PathlossChange); - UE_mac_inst[module_idP].PHR_reporting_active = 0; + int i; + // default values as deined in 36.331 sec 9.2.2 + LOG_I(MAC, "[UE%d] Applying default macMainConfig\n", module_idP); + //UE_mac_inst[module_idP].scheduling_info.macConfig=NULL; + UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer = + RetxBSR_Timer_r12_sf10240; + UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer = + PeriodicBSR_Timer_r12_infinity; + UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer = + MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20; + UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer = + MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20; + UE_mac_inst[module_idP].scheduling_info.PathlossChange_db = + MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1; + UE_mac_inst[module_idP].PHR_state = + MAC_MainConfig__phr_Config_PR_setup; + UE_mac_inst[module_idP].scheduling_info.SR_COUNTER = 0; + UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer = 0; + UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer_Running = 0; + UE_mac_inst[module_idP].scheduling_info.maxHARQ_Tx = + MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; + UE_mac_inst[module_idP].scheduling_info.ttiBundling = 0; + UE_mac_inst[module_idP].scheduling_info.extendedBSR_Sizes_r10 = 0; + UE_mac_inst[module_idP].scheduling_info.extendedPHR_r10 = 0; + UE_mac_inst[module_idP].scheduling_info.drx_config = NULL; + UE_mac_inst[module_idP].scheduling_info.phr_config = NULL; + // set init value 0xFFFF, make sure periodic timer and retx time counters are NOT active, after bsr transmission set the value configured by the NW. + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = + MAC_UE_BSR_TIMER_NOT_RUNNING; + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = + MAC_UE_BSR_TIMER_NOT_RUNNING; + UE_mac_inst[module_idP].BSR_reporting_active = BSR_TRIGGER_NONE; - for (i=0; i < MAX_NUM_LCID; i++) { - LOG_D(MAC,"[UE%d] Applying default logical channel config for LCGID %d\n",module_idP,i); - UE_mac_inst[module_idP].scheduling_info.Bj[i]=-1; - UE_mac_inst[module_idP].scheduling_info.bucket_size[i]=-1; + UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF = + get_sf_perioidicPHR_Timer(UE_mac_inst[module_idP]. + scheduling_info.periodicPHR_Timer); + UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF = + get_sf_prohibitPHR_Timer(UE_mac_inst[module_idP]. + scheduling_info.prohibitPHR_Timer); + UE_mac_inst[module_idP].scheduling_info.PathlossChange_db = + get_db_dl_PathlossChange(UE_mac_inst[module_idP]. + scheduling_info.PathlossChange); + UE_mac_inst[module_idP].PHR_reporting_active = 0; - if (i < DTCH) { // initilize all control channels lcgid to 0 - UE_mac_inst[module_idP].scheduling_info.LCGID[i]=0; - } else { // initialize all the data channels lcgid to 1 - UE_mac_inst[module_idP].scheduling_info.LCGID[i]=1; + for (i = 0; i < MAX_NUM_LCID; i++) { + LOG_D(MAC, + "[UE%d] Applying default logical channel config for LCGID %d\n", + module_idP, i); + UE_mac_inst[module_idP].scheduling_info.Bj[i] = -1; + UE_mac_inst[module_idP].scheduling_info.bucket_size[i] = -1; + + if (i < DTCH) { // initilize all control channels lcgid to 0 + UE_mac_inst[module_idP].scheduling_info.LCGID[i] = 0; + } else { // initialize all the data channels lcgid to 1 + UE_mac_inst[module_idP].scheduling_info.LCGID[i] = 1; + } + + UE_mac_inst[module_idP].scheduling_info.LCID_status[i] = + LCID_EMPTY; + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[i] = 0; } - UE_mac_inst[module_idP].scheduling_info.LCID_status[i]=LCID_EMPTY; - UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[i] = 0; - } - #ifdef CBA - for (i=0; i E == 0) { - // printf("E=0\n"); - not_done = 0; + if (((SCH_SUBHEADER_FIXED *) mac_header_ptr)->E == 0) { + // printf("E=0\n"); + not_done = 0; + } + + lcid = ((SCH_SUBHEADER_FIXED *) mac_header_ptr)->LCID; + + if (lcid < UE_CONT_RES) { + //printf("[MAC][UE] header %x.%x.%x\n",mac_header_ptr[0],mac_header_ptr[1],mac_header_ptr[2]); + if (not_done == 0) { // last MAC SDU, length is implicit + mac_header_ptr++; + length = + tb_length - (mac_header_ptr - mac_header) - ce_len; + + for (num_sdu_cnt = 0; num_sdu_cnt < num_sdus; + num_sdu_cnt++) { + length -= rx_lengths[num_sdu_cnt]; + } + } else { + if (((SCH_SUBHEADER_LONG *) mac_header_ptr)->F == 1) { + length = + ((((SCH_SUBHEADER_LONG *) mac_header_ptr)-> + L_MSB & 0x7f) + << 8) | (((SCH_SUBHEADER_LONG *) mac_header_ptr)-> + L_LSB & 0xff); + mac_header_ptr += 3; +#ifdef DEBUG_HEADER_PARSING + LOG_D(MAC, "[UE] parse long sdu, size %x \n", length); +#endif + + } else { //if (((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F == 0) { + length = ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->L; + mac_header_ptr += 2; + } + } + +#ifdef DEBUG_HEADER_PARSING + LOG_D(MAC, "[UE] sdu %d lcid %d length %d (offset now %ld)\n", + num_sdus, lcid, length, mac_header_ptr - mac_header); +#endif + rx_lcids[num_sdus] = lcid; + rx_lengths[num_sdus] = length; + num_sdus++; + } else { // This is a control element subheader + if (lcid == SHORT_PADDING) { + num_padding++; + mac_header_ptr++; + } else { + rx_ces[num_ces] = lcid; + num_ces++; + mac_header_ptr++; + + if (lcid == TIMING_ADV_CMD) { + ce_len++; + } else if (lcid == UE_CONT_RES) { + + // FNA: check MAC Header is one of thoses defined in Annex B of 36.321 + // Check there is only 1 Contention Resolution + if (num_cont_res) { + LOG_W(MAC, + "[UE] Msg4 Wrong received format: More than 1 Contention Resolution\n"); + // exit parsing + return NULL; + + } + // UE_CONT_RES shall never be the last subheader unless this is the only MAC subheader + if ((not_done == 0) + && ((num_sdus) || (num_ces > 1) || (num_padding))) { + LOG_W(MAC, + "[UE] Msg4 Wrong received format: Contention Resolution after num_ces=%d num_sdus=%d num_padding=%d\n", + num_ces, num_sdus, num_padding); + // exit parsing + return NULL; + } + num_cont_res++; + ce_len += 6; + } + } + +#ifdef DEBUG_HEADER_PARSING + LOG_D(MAC, "[UE] ce %d lcid %d (offset now %ld)\n", num_ces, + lcid, mac_header_ptr - mac_header); +#endif + } } - lcid = ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID; + *num_ce = num_ces; + *num_sdu = num_sdus; - if (lcid < UE_CONT_RES) { - //printf("[MAC][UE] header %x.%x.%x\n",mac_header_ptr[0],mac_header_ptr[1],mac_header_ptr[2]); - if (not_done==0) {// last MAC SDU, length is implicit - mac_header_ptr++; - length = tb_length-(mac_header_ptr-mac_header)-ce_len; - - for (num_sdu_cnt=0; num_sdu_cnt < num_sdus ; num_sdu_cnt++) { - length -= rx_lengths[num_sdu_cnt]; - } - } else { - if (((SCH_SUBHEADER_LONG *)mac_header_ptr)->F == 1) { - length = ((((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_MSB & 0x7f ) << 8 ) | (((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB & 0xff); - mac_header_ptr += 3; -#ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] parse long sdu, size %x \n",length); -#endif - - } else { //if (((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F == 0) { - length = ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L; - mac_header_ptr += 2; - } - } - -#ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] sdu %d lcid %d length %d (offset now %ld)\n", - num_sdus,lcid,length,mac_header_ptr-mac_header); -#endif - rx_lcids[num_sdus] = lcid; - rx_lengths[num_sdus] = length; - num_sdus++; - } else { // This is a control element subheader - if (lcid == SHORT_PADDING) { - num_padding ++; - mac_header_ptr++; - } else { - rx_ces[num_ces] = lcid; - num_ces++; - mac_header_ptr ++; - - if (lcid==TIMING_ADV_CMD) { - ce_len++; - } else if (lcid==UE_CONT_RES) { - - // FNA: check MAC Header is one of thoses defined in Annex B of 36.321 - // Check there is only 1 Contention Resolution - if (num_cont_res) { - LOG_W(MAC,"[UE] Msg4 Wrong received format: More than 1 Contention Resolution\n"); - // exit parsing - return NULL; - - } - - // UE_CONT_RES shall never be the last subheader unless this is the only MAC subheader - if ((not_done == 0) && ((num_sdus) || (num_ces > 1) || (num_padding))) { - LOG_W(MAC,"[UE] Msg4 Wrong received format: Contention Resolution after num_ces=%d num_sdus=%d num_padding=%d\n",num_ces,num_sdus,num_padding); - // exit parsing - return NULL; - } - num_cont_res ++; - ce_len+=6; - } - } - -#ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] ce %d lcid %d (offset now %ld)\n",num_ces,lcid,mac_header_ptr-mac_header); -#endif - } - } - - *num_ce = num_ces; - *num_sdu = num_sdus; - - return(mac_header_ptr); + return (mac_header_ptr); } -uint32_t ue_get_SR(module_id_t module_idP,int CC_id,frame_t frameP,uint8_t eNB_id,uint16_t rnti, sub_frame_t subframe) +uint32_t +ue_get_SR(module_id_t module_idP, int CC_id, frame_t frameP, + uint8_t eNB_id, uint16_t rnti, sub_frame_t subframe) { - // no UL-SCH resources available for this tti && UE has a valid PUCCH resources for SR configuration for this tti - // int MGL=6;// measurement gap length in ms - int MGRP = 0; // measurement gap repetition period in ms - int gapOffset = -1; - int T = 0; + // no UL-SCH resources available for this tti && UE has a valid PUCCH resources for SR configuration for this tti + // int MGL=6;// measurement gap length in ms + int MGRP = 0; // measurement gap repetition period in ms + int gapOffset = -1; + int T = 0; - DevCheck(module_idP < (int)NB_UE_INST, module_idP, NB_UE_INST, 0); + DevCheck(module_idP < (int) NB_UE_INST, module_idP, NB_UE_INST, 0); - AssertFatal(CC_id==0, - "Transmission on secondary CCs is not supported yet\n"); + AssertFatal(CC_id == 0, + "Transmission on secondary CCs is not supported yet\n"); - // determin the measurement gap - if (UE_mac_inst[module_idP].measGapConfig !=NULL) { - if (UE_mac_inst[module_idP].measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp0) { - MGRP= 40; - gapOffset= UE_mac_inst[module_idP].measGapConfig->choice.setup.gapOffset.choice.gp0; - } else if (UE_mac_inst[module_idP].measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp1) { - MGRP= 80; - gapOffset= UE_mac_inst[module_idP].measGapConfig->choice.setup.gapOffset.choice.gp1; + // determin the measurement gap + if (UE_mac_inst[module_idP].measGapConfig != NULL) { + if (UE_mac_inst[module_idP].measGapConfig->choice.setup. + gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp0) { + MGRP = 40; + gapOffset = + UE_mac_inst[module_idP].measGapConfig->choice. + setup.gapOffset.choice.gp0; + } else if (UE_mac_inst[module_idP].measGapConfig->choice. + setup.gapOffset.present == + MeasGapConfig__setup__gapOffset_PR_gp1) { + MGRP = 80; + gapOffset = + UE_mac_inst[module_idP].measGapConfig->choice. + setup.gapOffset.choice.gp1; + } else { + LOG_W(MAC, "Measurement GAP offset is unknown\n"); + } + + T = MGRP / 10; + DevAssert(T != 0); + + //check the measurement gap and sr prohibit timer + if ((subframe == gapOffset % 10) + && ((frameP % T) == (floor(gapOffset / 10))) + && (UE_mac_inst[module_idP]. + scheduling_info.sr_ProhibitTimer_Running == 0)) { + UE_mac_inst[module_idP].scheduling_info.SR_pending = 1; + return (0); + } + } + + if ((UE_mac_inst[module_idP].physicalConfigDedicated != NULL) && + (UE_mac_inst[module_idP].scheduling_info.SR_pending == 1) && + (UE_mac_inst[module_idP].scheduling_info.SR_COUNTER < + (1 << + (2 + + UE_mac_inst[module_idP]. + physicalConfigDedicated->schedulingRequestConfig->choice.setup. + dsr_TransMax)))) { + LOG_D(MAC, + "[UE %d][SR %x] Frame %d subframe %d PHY asks for SR (SR_COUNTER/dsr_TransMax %d/%d), SR_pending %d\n", + module_idP, rnti, frameP, subframe, + UE_mac_inst[module_idP].scheduling_info.SR_COUNTER, + (1 << + (2 + + UE_mac_inst[module_idP]. + physicalConfigDedicated->schedulingRequestConfig->choice. + setup.dsr_TransMax)), + UE_mac_inst[module_idP].scheduling_info.SR_pending); + + UE_mac_inst[module_idP].scheduling_info.SR_COUNTER++; + + // start the sr-prohibittimer : rel 9 and above + if (UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer > 0) { // timer configured + UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer--; + UE_mac_inst[module_idP].scheduling_info. + sr_ProhibitTimer_Running = 1; + } else { + UE_mac_inst[module_idP].scheduling_info. + sr_ProhibitTimer_Running = 0; + } + + LOG_D(MAC, + "[UE %d][SR %x] Frame %d subframe %d send SR indication (SR_COUNTER/dsr_TransMax %d/%d), SR_pending %d\n", + module_idP, rnti, frameP, subframe, + UE_mac_inst[module_idP].scheduling_info.SR_COUNTER, + (1 << + (2 + + UE_mac_inst[module_idP]. + physicalConfigDedicated->schedulingRequestConfig->choice. + setup.dsr_TransMax)), + UE_mac_inst[module_idP].scheduling_info.SR_pending); + + //UE_mac_inst[module_idP].ul_active =1; + return (1); //instruct phy to signal SR } else { - LOG_W(MAC, "Measurement GAP offset is unknown\n"); + // notify RRC to relase PUCCH/SRS + // clear any configured dl/ul + // initiate RA + if (UE_mac_inst[module_idP].scheduling_info.SR_pending) { + // release all pucch resource + UE_mac_inst[module_idP].physicalConfigDedicated = NULL; + UE_mac_inst[module_idP].ul_active = 0; + UE_mac_inst[module_idP].BSR_reporting_active = + BSR_TRIGGER_NONE; + + LOG_I(MAC, "[UE %d] Release all SRs \n", module_idP); + } + UE_mac_inst[module_idP].scheduling_info.SR_pending = 0; + UE_mac_inst[module_idP].scheduling_info.SR_COUNTER = 0; + return (0); } - - T=MGRP/10; - DevAssert( T != 0 ); - - //check the measurement gap and sr prohibit timer - if ((subframe == gapOffset %10) && ((frameP %T) == (floor(gapOffset/10))) - && (UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer_Running ==0)) { - UE_mac_inst[module_idP].scheduling_info.SR_pending=1; - return(0); - } - } - - if ((UE_mac_inst[module_idP].physicalConfigDedicated != NULL) && - (UE_mac_inst[module_idP].scheduling_info.SR_pending==1) && - (UE_mac_inst[module_idP].scheduling_info.SR_COUNTER < - (1<<(2+UE_mac_inst[module_idP].physicalConfigDedicated->schedulingRequestConfig->choice.setup.dsr_TransMax))) - ) { - LOG_D(MAC,"[UE %d][SR %x] Frame %d subframe %d PHY asks for SR (SR_COUNTER/dsr_TransMax %d/%d), SR_pending %d\n", - module_idP,rnti,frameP,subframe, - UE_mac_inst[module_idP].scheduling_info.SR_COUNTER, - (1<<(2+UE_mac_inst[module_idP].physicalConfigDedicated->schedulingRequestConfig->choice.setup.dsr_TransMax)), - UE_mac_inst[module_idP].scheduling_info.SR_pending); - - UE_mac_inst[module_idP].scheduling_info.SR_COUNTER++; - - // start the sr-prohibittimer : rel 9 and above - if (UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer > 0) { // timer configured - UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer--; - UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer_Running=1; - } else { - UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer_Running=0; - } - - LOG_D(MAC,"[UE %d][SR %x] Frame %d subframe %d send SR indication (SR_COUNTER/dsr_TransMax %d/%d), SR_pending %d\n", - module_idP,rnti,frameP,subframe, - UE_mac_inst[module_idP].scheduling_info.SR_COUNTER, - (1<<(2+UE_mac_inst[module_idP].physicalConfigDedicated->schedulingRequestConfig->choice.setup.dsr_TransMax)), - UE_mac_inst[module_idP].scheduling_info.SR_pending); - - //UE_mac_inst[module_idP].ul_active =1; - return(1); //instruct phy to signal SR - } else { - // notify RRC to relase PUCCH/SRS - // clear any configured dl/ul - // initiate RA - if (UE_mac_inst[module_idP].scheduling_info.SR_pending){ - // release all pucch resource - UE_mac_inst[module_idP].physicalConfigDedicated = NULL; - UE_mac_inst[module_idP].ul_active=0; - UE_mac_inst[module_idP].BSR_reporting_active=BSR_TRIGGER_NONE; - - LOG_I(MAC,"[UE %d] Release all SRs \n", module_idP); - } - UE_mac_inst[module_idP].scheduling_info.SR_pending=0; - UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; - return(0); - } } //------------------------------------------------------------------------------ void -ue_send_sdu( - module_id_t module_idP, +ue_send_sdu(module_id_t module_idP, uint8_t CC_id, frame_t frameP, - sub_frame_t subframeP, - uint8_t* sdu, - uint16_t sdu_len, - uint8_t eNB_index -) + sub_frame_t subframeP, + uint8_t * sdu, uint16_t sdu_len, uint8_t eNB_index) //------------------------------------------------------------------------------ { - unsigned char rx_ces[MAX_NUM_CE],num_ce,num_sdu,i,*payload_ptr; - unsigned char rx_lcids[NB_RB_MAX]; - unsigned short rx_lengths[NB_RB_MAX]; - unsigned char *tx_sdu; + unsigned char rx_ces[MAX_NUM_CE], num_ce, num_sdu, i, *payload_ptr; + unsigned char rx_lcids[NB_RB_MAX]; + unsigned short rx_lengths[NB_RB_MAX]; + unsigned char *tx_sdu; #if UE_TIMING_TRACE - start_meas(&UE_mac_inst[module_idP].rx_dlsch_sdu); + start_meas(&UE_mac_inst[module_idP].rx_dlsch_sdu); #endif - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_IN); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_IN); - LOG_T(MAC,"sdu: %x.%x.%x\n",sdu[0],sdu[1],sdu[2]); + LOG_T(MAC, "sdu: %x.%x.%x\n", sdu[0], sdu[1], sdu[2]); - if (opt_enabled) { - trace_pdu(1, sdu, sdu_len, module_idP, 3, UE_mac_inst[module_idP].crnti, - frameP, subframeP, 0, 0); - LOG_D(OPT,"[UE %d][DLSCH] Frame %d trace pdu for rnti %x with size %d\n", - module_idP, frameP, UE_mac_inst[module_idP].crnti, sdu_len); - } - - payload_ptr = parse_header(sdu,&num_ce,&num_sdu,rx_ces,rx_lcids,rx_lengths,sdu_len); - -#ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE %d] ue_send_sdu : Frame %d eNB_index %d : num_ce %d num_sdu %d\n",module_idP, - frameP,eNB_index,num_ce,num_sdu); -#endif - -#if defined(ENABLE_MAC_PAYLOAD_DEBUG) - LOG_T(MAC,"[UE %d] First 32 bytes of DLSCH : \n", module_idP); - - for (i=0; i<32; i++) { - LOG_T(MAC,"%x.",sdu[i]); - } - - LOG_T(MAC,"\n"); -#endif - - if (payload_ptr != NULL) { - - for (i=0; i= 9 (64 bits) - // (other possibility is 1 for TBS=7 (SCH_SUBHEADER_FIXED), or 2 for TBS=8 (SCH_SUBHEADER_FIXED+PADDING or SCH_SUBHEADER_SHORT) - for (i=0; i<6; i++) - if (tx_sdu[i] != payload_ptr[i]) { - LOG_E(MAC,"[UE %d][RAPROC] Contention detected, RA failed\n",module_idP); - ra_failed(module_idP,CC_id,eNB_index); - UE_mac_inst[module_idP].RA_contention_resolution_timer_active = 0; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_OUT); - return; - } - - LOG_I(MAC,"[UE %d][RAPROC] Frame %d : Clearing contention resolution timer\n", module_idP, frameP); - UE_mac_inst[module_idP].RA_contention_resolution_timer_active = 0; - ra_succeeded(module_idP,CC_id,eNB_index); - } - - payload_ptr+=6; - break; - - case TIMING_ADV_CMD: -#ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] CE %d : UE Timing Advance : %d\n",i,payload_ptr[0]); -#endif - process_timing_advance(module_idP,CC_id,payload_ptr[0]); - payload_ptr++; - break; - - case DRX_CMD: -#ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] CE %d : UE DRX :",i); -#endif - payload_ptr++; - break; + if (opt_enabled) { + trace_pdu(1, sdu, sdu_len, module_idP, 3, + UE_mac_inst[module_idP].crnti, frameP, subframeP, 0, 0); + LOG_D(OPT, + "[UE %d][DLSCH] Frame %d trace pdu for rnti %x with size %d\n", + module_idP, frameP, UE_mac_inst[module_idP].crnti, sdu_len); } - } - for (i=0; i DL-CCCH, RRC message (eNB %d, %d bytes)\n", - module_idP, - UE_mac_inst[module_idP].crnti, - frameP, - eNB_index, - rx_lengths[i]); #if defined(ENABLE_MAC_PAYLOAD_DEBUG) - int j; + LOG_T(MAC, "[UE %d] First 32 bytes of DLSCH : \n", module_idP); - for (j=0; j DL-DCCH%d, RRC message (eNB %d, %d bytes)\n", module_idP, frameP, rx_lcids[i],eNB_index,rx_lengths[i]); - mac_rlc_data_ind(module_idP, - UE_mac_inst[module_idP].crnti, - eNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_NO, - rx_lcids[i], - (char *)payload_ptr, - rx_lengths[i], - 1, - NULL); - - } else if ((rx_lcids[i] < NB_RB_MAX) && (rx_lcids[i] > DCCH1 )) { - - LOG_D(MAC,"[UE %d] Frame %d : DLSCH -> DL-DTCH%d (eNB %d, %d bytes)\n", module_idP, frameP,rx_lcids[i], eNB_index,rx_lengths[i]); - -#if defined(ENABLE_MAC_PAYLOAD_DEBUG) - int j; - for (j=0;j= 9 (64 bits) + // (other possibility is 1 for TBS=7 (SCH_SUBHEADER_FIXED), or 2 for TBS=8 (SCH_SUBHEADER_FIXED+PADDING or SCH_SUBHEADER_SHORT) + for (i = 0; i < 6; i++) + if (tx_sdu[i] != payload_ptr[i]) { + LOG_E(MAC, + "[UE %d][RAPROC] Contention detected, RA failed\n", + module_idP); + ra_failed(module_idP, CC_id, eNB_index); + UE_mac_inst + [module_idP]. + RA_contention_resolution_timer_active = 0; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, + VCD_FUNCTION_OUT); + return; + } + + LOG_I(MAC, + "[UE %d][RAPROC] Frame %d : Clearing contention resolution timer\n", + module_idP, frameP); + UE_mac_inst + [module_idP]. + RA_contention_resolution_timer_active = 0; + ra_succeeded(module_idP, CC_id, eNB_index); + } + + payload_ptr += 6; + break; + + case TIMING_ADV_CMD: +#ifdef DEBUG_HEADER_PARSING + LOG_D(MAC, "[UE] CE %d : UE Timing Advance : %d\n", i, + payload_ptr[0]); +#endif + process_timing_advance(module_idP, CC_id, payload_ptr[0]); + payload_ptr++; + break; + + case DRX_CMD: +#ifdef DEBUG_HEADER_PARSING + LOG_D(MAC, "[UE] CE %d : UE DRX :", i); +#endif + payload_ptr++; + break; + } + } + + for (i = 0; i < num_sdu; i++) { +#ifdef DEBUG_HEADER_PARSING + LOG_D(MAC, "[UE] SDU %d : LCID %d, length %d\n", i, + rx_lcids[i], rx_lengths[i]); +#endif + + if (rx_lcids[i] == CCCH) { + + LOG_D(MAC, + "[UE %d] rnti %x Frame %d : DLSCH -> DL-CCCH, RRC message (eNB %d, %d bytes)\n", + module_idP, UE_mac_inst[module_idP].crnti, frameP, + eNB_index, rx_lengths[i]); + +#if defined(ENABLE_MAC_PAYLOAD_DEBUG) + int j; + + for (j = 0; j < rx_lengths[i]; j++) { + LOG_T(MAC, "%x.", (uint8_t) payload_ptr[j]); + } + + LOG_T(MAC, "\n"); +#endif + mac_rrc_data_ind(module_idP, + CC_id, + frameP, subframeP, + UE_mac_inst[module_idP].crnti, + CCCH, + (uint8_t *) payload_ptr, + rx_lengths[i], ENB_FLAG_NO, eNB_index, 0); + + } else if ((rx_lcids[i] == DCCH) || (rx_lcids[i] == DCCH1)) { + LOG_D(MAC, + "[UE %d] Frame %d : DLSCH -> DL-DCCH%d, RRC message (eNB %d, %d bytes)\n", + module_idP, frameP, rx_lcids[i], eNB_index, + rx_lengths[i]); + mac_rlc_data_ind(module_idP, UE_mac_inst[module_idP].crnti, + eNB_index, frameP, ENB_FLAG_NO, + MBMS_FLAG_NO, rx_lcids[i], + (char *) payload_ptr, rx_lengths[i], 1, + NULL); + + } else if ((rx_lcids[i] < NB_RB_MAX) && (rx_lcids[i] > DCCH1)) { + + LOG_D(MAC, + "[UE %d] Frame %d : DLSCH -> DL-DTCH%d (eNB %d, %d bytes)\n", + module_idP, frameP, rx_lcids[i], eNB_index, + rx_lengths[i]); + +#if defined(ENABLE_MAC_PAYLOAD_DEBUG) + int j; + for (j = 0; j < rx_lengths[i]; j++) + LOG_T(MAC, "%x.", (unsigned char) payload_ptr[j]); + LOG_T(MAC, "\n"); +#endif + mac_rlc_data_ind(module_idP, + UE_mac_inst[module_idP].crnti, + eNB_index, + frameP, + ENB_FLAG_NO, + MBMS_FLAG_NO, + rx_lcids[i], + (char *) payload_ptr, rx_lengths[i], 1, + NULL); + } else { + LOG_E(MAC, "[UE %d] Frame %d : unknown LCID %d (eNB %d)\n", + module_idP, frameP, rx_lcids[i], eNB_index); + } + payload_ptr += rx_lengths[i]; + } + } // end if (payload_ptr != NULL) + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_OUT); #if UE_TIMING_TRACE - stop_meas(&UE_mac_inst[module_idP].rx_dlsch_sdu); + stop_meas(&UE_mac_inst[module_idP].rx_dlsch_sdu); #endif } -void ue_decode_si(module_id_t module_idP,int CC_id,frame_t frameP, uint8_t eNB_index, void *pdu,uint16_t len) +void +ue_decode_si(module_id_t module_idP, int CC_id, frame_t frameP, + uint8_t eNB_index, void *pdu, uint16_t len) { #if UE_TIMING_TRACE start_meas(&UE_mac_inst[module_idP].rx_si); #endif - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_SI, VCD_FUNCTION_IN); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_SI, VCD_FUNCTION_IN); - LOG_D(MAC,"[UE %d] Frame %d Sending SI to RRC (LCID Id %d,len %d)\n",module_idP,frameP,BCCH,len); + LOG_D(MAC, "[UE %d] Frame %d Sending SI to RRC (LCID Id %d,len %d)\n", + module_idP, frameP, BCCH, len); - mac_rrc_data_ind(module_idP, - CC_id, - frameP,0, // unknown subframe - SI_RNTI, - BCCH, - (uint8_t *)pdu, - len, - ENB_FLAG_NO, - eNB_index, - 0); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_SI, VCD_FUNCTION_OUT); + mac_rrc_data_ind(module_idP, CC_id, frameP, 0, // unknown subframe + SI_RNTI, + BCCH, (uint8_t *) pdu, len, ENB_FLAG_NO, eNB_index, + 0); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_SI, VCD_FUNCTION_OUT); #if UE_TIMING_TRACE - stop_meas(&UE_mac_inst[module_idP].rx_si); + stop_meas(&UE_mac_inst[module_idP].rx_si); #endif - if (opt_enabled == 1) { - trace_pdu(0, - (uint8_t *)pdu, - len, - module_idP, - 4, - 0xffff, - UE_mac_inst[module_idP].rxFrame, - UE_mac_inst[module_idP].rxSubframe, - 0, - 0); - LOG_D(OPT,"[UE %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", - module_idP, frameP, CC_id, 0xffff, len); - } + if (opt_enabled == 1) { + trace_pdu(0, + (uint8_t *) pdu, + len, + module_idP, + 4, + 0xffff, + UE_mac_inst[module_idP].rxFrame, + UE_mac_inst[module_idP].rxSubframe, 0, 0); + LOG_D(OPT, + "[UE %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", + module_idP, frameP, CC_id, 0xffff, len); + } } -void ue_decode_p(module_id_t module_idP,int CC_id,frame_t frameP, uint8_t eNB_index, void *pdu,uint16_t len) +void +ue_decode_p(module_id_t module_idP, int CC_id, frame_t frameP, + uint8_t eNB_index, void *pdu, uint16_t len) { #if UE_TIMING_TRACE start_meas(&UE_mac_inst[module_idP].rx_p); #endif - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_PCCH, VCD_FUNCTION_IN); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_PCCH, VCD_FUNCTION_IN); - LOG_D(MAC,"[UE %d] Frame %d Sending Paging message to RRC (LCID Id %d,len %d)\n",module_idP,frameP,PCCH,len); + LOG_D(MAC, + "[UE %d] Frame %d Sending Paging message to RRC (LCID Id %d,len %d)\n", + module_idP, frameP, PCCH, len); - mac_rrc_data_ind(module_idP, - CC_id, - frameP,0, // unknown subframe - P_RNTI, - PCCH, - (uint8_t *)pdu, - len, - ENB_FLAG_NO, - eNB_index, - 0); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_PCCH, VCD_FUNCTION_OUT); + mac_rrc_data_ind(module_idP, CC_id, frameP, 0, // unknown subframe + P_RNTI, + PCCH, (uint8_t *) pdu, len, ENB_FLAG_NO, eNB_index, + 0); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_PCCH, VCD_FUNCTION_OUT); #if UE_TIMING_TRACE - stop_meas(&UE_mac_inst[module_idP].rx_p); + stop_meas(&UE_mac_inst[module_idP].rx_p); #endif - if (opt_enabled == 1) { - trace_pdu(0, - (uint8_t *)pdu, - len, - module_idP, - 4, - P_RNTI, - UE_mac_inst[module_idP].rxFrame, - UE_mac_inst[module_idP].rxSubframe, - 0, - 0); - LOG_D(OPT,"[UE %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", - module_idP, frameP, CC_id, P_RNTI, len); - } + if (opt_enabled == 1) { + trace_pdu(0, + (uint8_t *) pdu, + len, + module_idP, + 4, + P_RNTI, + UE_mac_inst[module_idP].rxFrame, + UE_mac_inst[module_idP].rxSubframe, 0, 0); + LOG_D(OPT, + "[UE %d][BCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", + module_idP, frameP, CC_id, P_RNTI, len); + } } #if defined(Rel10) || defined(Rel14) unsigned char *parse_mch_header(unsigned char *mac_header, - unsigned char *num_sdu, - unsigned char *rx_lcids, - unsigned short *rx_lengths, - unsigned short tb_length) + unsigned char *num_sdu, + unsigned char *rx_lcids, + unsigned short *rx_lengths, + unsigned short tb_length) { - unsigned char not_done=1, num_sdus=0, lcid, i; - unsigned char *mac_header_ptr = mac_header; - unsigned short length; + unsigned char not_done = 1, num_sdus = 0, lcid, i; + unsigned char *mac_header_ptr = mac_header; + unsigned short length; - while (not_done == 1) { - if (((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E == 0) { - not_done = 0; + while (not_done == 1) { + if (((SCH_SUBHEADER_FIXED *) mac_header_ptr)->E == 0) { + not_done = 0; + } + + lcid = ((SCH_SUBHEADER_FIXED *) mac_header_ptr)->LCID; + + if (lcid < SHORT_PADDING) { // subheader for MSI, MCCH or MTCH + if (not_done == 0) { // last MAC SDU, length is implicit + mac_header_ptr++; + length = tb_length - (mac_header_ptr - mac_header); + + for (i = 0; i < num_sdus; i++) { + length -= rx_lengths[i]; + } + } else { // not the last MAC SDU + if (((SCH_SUBHEADER_LONG *) mac_header_ptr)->F == 1) { // subheader has length of 3octets + // length = ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L; + length = + ((((SCH_SUBHEADER_LONG *) mac_header_ptr)-> + L_MSB & 0x7f) + << 8) | (((SCH_SUBHEADER_LONG *) mac_header_ptr)-> + L_LSB & 0xff); + mac_header_ptr += 3; + } else { // subheader has length of 2octets + length = ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->L; + mac_header_ptr += 2; + } + } + + rx_lcids[num_sdus] = lcid; + rx_lengths[num_sdus] = length; + num_sdus++; + } else { // subheader for padding + // if (lcid == SHORT_PADDING) + mac_header_ptr++; + } } - lcid = ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID; - - if (lcid < SHORT_PADDING) {// subheader for MSI, MCCH or MTCH - if (not_done == 0) { // last MAC SDU, length is implicit - mac_header_ptr++; - length = tb_length- (mac_header_ptr - mac_header); - - for (i=0; iF == 1) {// subheader has length of 3octets - // length = ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L; - length = ((((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_MSB & 0x7f ) << 8 ) | (((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB & 0xff); - mac_header_ptr += 3; - } else { // subheader has length of 2octets - length = ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L; - mac_header_ptr += 2; - } - } - - rx_lcids[num_sdus] = lcid; - rx_lengths[num_sdus] = length; - num_sdus++; - } else { // subheader for padding - // if (lcid == SHORT_PADDING) - mac_header_ptr++; - } - } - - *num_sdu = num_sdus; - return(mac_header_ptr); + *num_sdu = num_sdus; + return (mac_header_ptr); } // this function is for sending mch_sdu from phy to mac -void ue_send_mch_sdu(module_id_t module_idP, uint8_t CC_id, frame_t frameP, uint8_t *sdu, uint16_t sdu_len, uint8_t eNB_index, uint8_t sync_area) +void +ue_send_mch_sdu(module_id_t module_idP, uint8_t CC_id, frame_t frameP, + uint8_t * sdu, uint16_t sdu_len, uint8_t eNB_index, + uint8_t sync_area) { - unsigned char num_sdu, i, *payload_ptr; - unsigned char rx_lcids[NB_RB_MAX]; - unsigned short rx_lengths[NB_RB_MAX]; + unsigned char num_sdu, i, *payload_ptr; + unsigned char rx_lcids[NB_RB_MAX]; + unsigned short rx_lengths[NB_RB_MAX]; #if UE_TIMING_TRACE - start_meas(&UE_mac_inst[module_idP].rx_mch_sdu); + start_meas(&UE_mac_inst[module_idP].rx_mch_sdu); #endif - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_MCH_SDU, VCD_FUNCTION_IN); - - LOG_D(MAC,"[UE %d] Frame %d : process the mch PDU for sync area %d \n",module_idP,frameP, sync_area); - LOG_D(MAC,"[UE %d] sdu: %x.%x\n", module_idP,sdu[0], sdu[1]); - LOG_D(MAC,"[UE %d] parse_mch_header, demultiplex\n",module_idP); - - payload_ptr = parse_mch_header(sdu, &num_sdu, rx_lcids, rx_lengths, sdu_len); - LOG_D(MAC,"[UE %d] parse_mch_header, found %d sdus\n",module_idP,num_sdu); - - for (i=0; iMSI for sync area %d (eNB %d, %d bytes)\n",module_idP,frameP, sync_area, eNB_index, rx_lengths[i]); - // ??store necessary scheduling info to ue_mac_inst in order to - // calculate exact position of interested service (for the complex case has >1 mtch) - // set msi_status to 1 - UE_mac_inst[module_idP].msi_status = 1; - } - } else if (rx_lcids[i] == MCCH_LCHANID) { - LOG_I(MAC,"[UE %d] Frame %d : SDU %d MCH->MCCH for sync area %d (eNB %d, %d bytes)\n",module_idP,frameP, i, sync_area, eNB_index, rx_lengths[i]); - mac_rrc_data_ind(module_idP, - CC_id, - frameP,0, // unknown subframe - M_RNTI, - MCCH, - payload_ptr, rx_lengths[i], 0, eNB_index, sync_area); - } else if (rx_lcids[i] == MTCH) { - if (UE_mac_inst[module_idP].msi_status==1) { - LOG_I(MAC,"[UE %d] Frame %d : MCH->MTCH for sync area %d (eNB %d, %d bytes)\n",module_idP,frameP, sync_area, eNB_index, rx_lengths[i]); - - mac_rlc_data_ind( - module_idP, - UE_mac_inst[module_idP].crnti, - eNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_YES, - MTCH, /*+ (maxDRB + 3),*/ - (char *)payload_ptr, - rx_lengths[i], - 1, - NULL); - - } - } else { - LOG_W(MAC,"[UE %d] Frame %d : unknown sdu %d rx_lcids[%d]=%d mcch status %d eNB %d \n", - module_idP, - frameP, - rx_lengths[i], - i, - rx_lcids[i], - UE_mac_inst[module_idP].mcch_status, eNB_index); - } - - payload_ptr += rx_lengths[i]; - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_MCH_SDU, VCD_FUNCTION_OUT); -#if UE_TIMING_TRACE - stop_meas(&UE_mac_inst[module_idP].rx_mch_sdu); -#endif -} - -int8_t ue_get_mbsfn_sf_alloction (module_id_t module_idP, uint8_t mbsfn_sync_area, unsigned char eNB_index) -{ - // currently there is one-to-one mapping between sf allocation pattern and sync area - if (mbsfn_sync_area >= MAX_MBSFN_AREA) { - LOG_W( MAC, "[UE %"PRIu8"] MBSFN synchronization area %"PRIu8" out of range for eNB %"PRIu8"\n", module_idP, mbsfn_sync_area, eNB_index ); - return -1; - } else if (UE_mac_inst[module_idP].mbsfn_SubframeConfig[mbsfn_sync_area] != NULL) { - return mbsfn_sync_area; - } else { - LOG_W( MAC, "[UE %"PRIu8"] MBSFN Subframe Config pattern %"PRIu8" not found \n", module_idP, mbsfn_sync_area ); - return -1; - } -} - -int ue_query_mch(module_id_t module_idP, uint8_t CC_id, uint32_t frameP, uint32_t subframe, uint8_t eNB_index,uint8_t *sync_area, uint8_t *mcch_active) -{ - - int i=0, j=0, ii=0, msi_pos=0, mcch_mcs = - 1; - int mcch_flag=0, mtch_flag=0, msi_flag=0; - int mbsfn_period = 0;// 1<<(UE_mac_inst[module_idP].mbsfn_SubframeConfig[0]->radioframeAllocationPeriod); - int mcch_period = 0;// 32<<(UE_mac_inst[module_idP].mbsfn_AreaInfo[0]->mcch_Config_r9.mcch_RepetitionPeriod_r9); - int mch_scheduling_period = -1; - - int frame_FDD=1; - - -#if UE_TIMING_TRACE - start_meas(&UE_mac_inst[module_idP].ue_query_mch); -#endif - - if (UE_mac_inst[module_idP].pmch_Config[0]) { - mch_scheduling_period = 8<<(UE_mac_inst[module_idP].pmch_Config[0]->mch_SchedulingPeriod_r9); - } - - for (i=0; - i< UE_mac_inst[module_idP].num_active_mbsfn_area; - i++ ) { - // assume, that there is always a mapping - if ((j=ue_get_mbsfn_sf_alloction(module_idP,i,eNB_index)) == -1) { - return -1; // continue; - } - - ii=0; - msi_pos=0; - mbsfn_period = 1<<(UE_mac_inst[module_idP].mbsfn_SubframeConfig[0]->radioframeAllocationPeriod); - mcch_period = 32<<(UE_mac_inst[module_idP].mbsfn_AreaInfo[0]->mcch_Config_r9.mcch_RepetitionPeriod_r9); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_MCH_SDU, VCD_FUNCTION_IN); LOG_D(MAC, - "[UE %d] Frame %d subframe %d: Checking MBSFN Sync Area %d/%d with SF allocation %d/%d for MCCH and MTCH (mbsfn period %d, mcch period %d,mac sched period (%d,%ld))\n", - module_idP,frameP, subframe,i,UE_mac_inst[module_idP].num_active_mbsfn_area, - j,UE_mac_inst[module_idP].num_sf_allocation_pattern,mbsfn_period,mcch_period, - mch_scheduling_period,UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->radioframeAllocationOffset); + "[UE %d] Frame %d : process the mch PDU for sync area %d \n", + module_idP, frameP, sync_area); + LOG_D(MAC, "[UE %d] sdu: %x.%x\n", module_idP, sdu[0], sdu[1]); + LOG_D(MAC, "[UE %d] parse_mch_header, demultiplex\n", module_idP); - // get the real MCS value - switch (UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.signallingMCS_r9) { - case 0: - mcch_mcs = 2; - break; + payload_ptr = + parse_mch_header(sdu, &num_sdu, rx_lcids, rx_lengths, sdu_len); + LOG_D(MAC, "[UE %d] parse_mch_header, found %d sdus\n", module_idP, + num_sdu); - case 1: - mcch_mcs = 7; - break; + for (i = 0; i < num_sdu; i++) { + if (rx_lcids[i] == MCH_SCHDL_INFO) { + if (UE_mac_inst[module_idP].mcch_status == 1) { + LOG_I(MAC, + "[UE %d] Frame %d : MCH->MSI for sync area %d (eNB %d, %d bytes)\n", + module_idP, frameP, sync_area, eNB_index, + rx_lengths[i]); + // ??store necessary scheduling info to ue_mac_inst in order to + // calculate exact position of interested service (for the complex case has >1 mtch) + // set msi_status to 1 + UE_mac_inst[module_idP].msi_status = 1; + } + } else if (rx_lcids[i] == MCCH_LCHANID) { + LOG_I(MAC, + "[UE %d] Frame %d : SDU %d MCH->MCCH for sync area %d (eNB %d, %d bytes)\n", + module_idP, frameP, i, sync_area, eNB_index, + rx_lengths[i]); + mac_rrc_data_ind(module_idP, CC_id, frameP, 0, // unknown subframe + M_RNTI, + MCCH, + payload_ptr, rx_lengths[i], 0, eNB_index, + sync_area); + } else if (rx_lcids[i] == MTCH) { + if (UE_mac_inst[module_idP].msi_status == 1) { + LOG_I(MAC, + "[UE %d] Frame %d : MCH->MTCH for sync area %d (eNB %d, %d bytes)\n", + module_idP, frameP, sync_area, eNB_index, + rx_lengths[i]); - case 2: - mcch_mcs = 13; - break; + mac_rlc_data_ind(module_idP, UE_mac_inst[module_idP].crnti, eNB_index, frameP, ENB_FLAG_NO, MBMS_FLAG_YES, MTCH, /*+ (maxDRB + 3), */ + (char *) payload_ptr, rx_lengths[i], 1, + NULL); - case 3: - mcch_mcs = 19; - break; + } + } else { + LOG_W(MAC, + "[UE %d] Frame %d : unknown sdu %d rx_lcids[%d]=%d mcch status %d eNB %d \n", + module_idP, frameP, rx_lengths[i], i, rx_lcids[i], + UE_mac_inst[module_idP].mcch_status, eNB_index); + } + + payload_ptr += rx_lengths[i]; } - if (frameP % mbsfn_period == UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->radioframeAllocationOffset) { // MBSFN frameP - if (UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.present == MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { // one-frameP format - - if (UE_mac_inst[module_idP].pmch_Config[0]) { - // Find the first subframe in this MCH to transmit MSI - if (frameP % mch_scheduling_period == UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->radioframeAllocationOffset ) { - while (ii == 0) { - ii = UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & (0x80>>msi_pos); - msi_pos++; - } - } - } - - if (UE_mac_inst[module_idP].tdd_Config == NULL) frame_FDD=1; - else frame_FDD=0; - // Check if the subframe is for MSI, MCCH or MTCHs and Set the correspoding flag to 1 - switch (subframe) { - case 1: - if (frame_FDD==1) { - if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF1) == MBSFN_FDD_SF1) { - if (msi_pos == 1) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF1) == MBSFN_FDD_SF1) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 2: - if (frame_FDD==1) { - if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF2) == MBSFN_FDD_SF2) { - if (msi_pos == 2) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF2) == MBSFN_FDD_SF2) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 3: - if (frame_FDD==0) { //TDD - if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF3) == MBSFN_TDD_SF3) { - if (msi_pos == 1) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF3) == MBSFN_TDD_SF3) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } else { // FDD - if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF3) == MBSFN_FDD_SF3) { - if (msi_pos == 3) { - msi_flag = 1; - } - - if ((frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF3) == MBSFN_FDD_SF3) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 4: - if (frame_FDD==0) { - if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF4) == MBSFN_TDD_SF4) { - if (msi_pos == 2) { - msi_flag = 1; - } - - if ((frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF4) == MBSFN_TDD_SF4) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 6: - if (frame_FDD==1) { - if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF6) == MBSFN_FDD_SF6) { - if (msi_pos == 4) { - msi_flag = 1; - } - - if ((frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF6) == MBSFN_FDD_SF6) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 7: - if (frame_FDD==0) { // TDD - if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF7) == MBSFN_TDD_SF7) { - if (msi_pos == 3) { - msi_flag = 1; - } - - if ((frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF7) == MBSFN_TDD_SF7) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } else { // FDD - if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF7) == MBSFN_FDD_SF7) { - if (msi_pos == 5) { - msi_flag = 1; - } - - if ((frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF7) == MBSFN_FDD_SF7) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 8: - if (frame_FDD==0) { //TDD - if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF8) == MBSFN_TDD_SF8) { - if (msi_pos == 4) { - msi_flag = 1; - } - - if ( (frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF8) == MBSFN_TDD_SF8) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } else { // FDD - if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_FDD_SF8) == MBSFN_FDD_SF8) { - if (msi_pos == 6) { - msi_flag = 1; - } - - if ((frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_FDD_SF8) == MBSFN_FDD_SF8) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - - case 9: - if (frame_FDD==0) { - if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.choice.oneFrame.buf[0] & MBSFN_TDD_SF9) == MBSFN_TDD_SF9) { - if (msi_pos == 5) { - msi_flag = 1; - } - - if ((frameP % mcch_period == UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_Offset_r9) && - ((UE_mac_inst[module_idP].mbsfn_AreaInfo[i]->mcch_Config_r9.sf_AllocInfo_r9.buf[0] & MBSFN_TDD_SF9) == MBSFN_TDD_SF9) ) { - mcch_flag = 1; - } - - mtch_flag = 1; - } - } - - break; - }// end switch - - // sf allocation is non-overlapping - if ((msi_flag==1) || (mcch_flag==1) || (mtch_flag==1)) { - LOG_D(MAC,"[UE %d] Frame %d Subframe %d: sync area %d SF alloc %d: msi flag %d, mcch flag %d, mtch flag %d\n", - module_idP, frameP, subframe,i,j,msi_flag,mcch_flag,mtch_flag); - - *sync_area=i; - break; - } - } else { // four-frameP format - } - } - } // end of for + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_MCH_SDU, VCD_FUNCTION_OUT); #if UE_TIMING_TRACE - stop_meas(&UE_mac_inst[module_idP].ue_query_mch); + stop_meas(&UE_mac_inst[module_idP].rx_mch_sdu); +#endif +} + +int8_t +ue_get_mbsfn_sf_alloction(module_id_t module_idP, + uint8_t mbsfn_sync_area, unsigned char eNB_index) +{ + // currently there is one-to-one mapping between sf allocation pattern and sync area + if (mbsfn_sync_area >= MAX_MBSFN_AREA) { + LOG_W(MAC, + "[UE %" PRIu8 "] MBSFN synchronization area %" PRIu8 + " out of range for eNB %" PRIu8 "\n", module_idP, + mbsfn_sync_area, eNB_index); + return -1; + } else if (UE_mac_inst[module_idP]. + mbsfn_SubframeConfig[mbsfn_sync_area] != NULL) { + return mbsfn_sync_area; + } else { + LOG_W(MAC, + "[UE %" PRIu8 "] MBSFN Subframe Config pattern %" PRIu8 + " not found \n", module_idP, mbsfn_sync_area); + return -1; + } +} + +int +ue_query_mch(module_id_t module_idP, uint8_t CC_id, uint32_t frameP, + uint32_t subframe, uint8_t eNB_index, uint8_t * sync_area, + uint8_t * mcch_active) +{ + + int i = 0, j = 0, ii = 0, msi_pos = 0, mcch_mcs = -1; + int mcch_flag = 0, mtch_flag = 0, msi_flag = 0; + int mbsfn_period = 0; // 1<<(UE_mac_inst[module_idP].mbsfn_SubframeConfig[0]->radioframeAllocationPeriod); + int mcch_period = 0; // 32<<(UE_mac_inst[module_idP].mbsfn_AreaInfo[0]->mcch_Config_r9.mcch_RepetitionPeriod_r9); + int mch_scheduling_period = -1; + + int frame_FDD = 1; + + +#if UE_TIMING_TRACE + start_meas(&UE_mac_inst[module_idP].ue_query_mch); #endif - if ( (mcch_flag==1)) { // || (msi_flag==1)) - *mcch_active=1; - } + if (UE_mac_inst[module_idP].pmch_Config[0]) { + mch_scheduling_period = + 8 << (UE_mac_inst[module_idP]. + pmch_Config[0]->mch_SchedulingPeriod_r9); + } - if ( (mcch_flag==1) || ((msi_flag==1) && (UE_mac_inst[module_idP].mcch_status==1)) ) { - return mcch_mcs; - } else if ((mtch_flag==1) && (UE_mac_inst[module_idP].msi_status==1)) { - return UE_mac_inst[module_idP].pmch_Config[0]->dataMCS_r9; - } else { - return -1; - } + for (i = 0; i < UE_mac_inst[module_idP].num_active_mbsfn_area; i++) { + // assume, that there is always a mapping + if ((j = + ue_get_mbsfn_sf_alloction(module_idP, i, eNB_index)) == -1) { + return -1; // continue; + } + + ii = 0; + msi_pos = 0; + mbsfn_period = + 1 << (UE_mac_inst[module_idP]. + mbsfn_SubframeConfig[0]->radioframeAllocationPeriod); + mcch_period = + 32 << (UE_mac_inst[module_idP]. + mbsfn_AreaInfo[0]->mcch_Config_r9. + mcch_RepetitionPeriod_r9); + + LOG_D(MAC, + "[UE %d] Frame %d subframe %d: Checking MBSFN Sync Area %d/%d with SF allocation %d/%d for MCCH and MTCH (mbsfn period %d, mcch period %d,mac sched period (%d,%ld))\n", + module_idP, frameP, subframe, i, + UE_mac_inst[module_idP].num_active_mbsfn_area, j, + UE_mac_inst[module_idP].num_sf_allocation_pattern, + mbsfn_period, mcch_period, mch_scheduling_period, + UE_mac_inst[module_idP]. + mbsfn_SubframeConfig[j]->radioframeAllocationOffset); + + // get the real MCS value + switch (UE_mac_inst[module_idP].mbsfn_AreaInfo[i]-> + mcch_Config_r9.signallingMCS_r9) { + case 0: + mcch_mcs = 2; + break; + + case 1: + mcch_mcs = 7; + break; + + case 2: + mcch_mcs = 13; + break; + + case 3: + mcch_mcs = 19; + break; + } + + if (frameP % mbsfn_period == UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->radioframeAllocationOffset) { // MBSFN frameP + if (UE_mac_inst[module_idP].mbsfn_SubframeConfig[j]->subframeAllocation.present == MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { // one-frameP format + + if (UE_mac_inst[module_idP].pmch_Config[0]) { + // Find the first subframe in this MCH to transmit MSI + if (frameP % mch_scheduling_period == + UE_mac_inst[module_idP]. + mbsfn_SubframeConfig + [j]->radioframeAllocationOffset) { + while (ii == 0) { + ii = UE_mac_inst[module_idP]. + mbsfn_SubframeConfig[j]-> + subframeAllocation.choice. + oneFrame.buf[0] & (0x80 >> msi_pos); + msi_pos++; + } + } + } + + if (UE_mac_inst[module_idP].tdd_Config == NULL) + frame_FDD = 1; + else + frame_FDD = 0; + // Check if the subframe is for MSI, MCCH or MTCHs and Set the correspoding flag to 1 + switch (subframe) { + case 1: + if (frame_FDD == 1) { + if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig + [j]->subframeAllocation.choice.oneFrame. + buf[0] & MBSFN_FDD_SF1) == MBSFN_FDD_SF1) { + if (msi_pos == 1) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.mcch_Offset_r9) + && + ((UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF1) == + MBSFN_FDD_SF1)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 2: + if (frame_FDD == 1) { + if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig + [j]->subframeAllocation.choice.oneFrame. + buf[0] & MBSFN_FDD_SF2) == MBSFN_FDD_SF2) { + if (msi_pos == 2) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.mcch_Offset_r9) + && + ((UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF2) == + MBSFN_FDD_SF2)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 3: + if (frame_FDD == 0) { //TDD + if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig + [j]->subframeAllocation.choice.oneFrame. + buf[0] & MBSFN_TDD_SF3) == MBSFN_TDD_SF3) { + if (msi_pos == 1) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.mcch_Offset_r9) + && + ((UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF3) == + MBSFN_TDD_SF3)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } else { // FDD + if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig + [j]->subframeAllocation.choice.oneFrame. + buf[0] & MBSFN_FDD_SF3) == MBSFN_FDD_SF3) { + if (msi_pos == 3) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.mcch_Offset_r9) + && + ((UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF3) == + MBSFN_FDD_SF3)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 4: + if (frame_FDD == 0) { + if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig + [j]->subframeAllocation.choice.oneFrame. + buf[0] & MBSFN_TDD_SF4) == MBSFN_TDD_SF4) { + if (msi_pos == 2) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.mcch_Offset_r9) + && + ((UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF4) == + MBSFN_TDD_SF4)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 6: + if (frame_FDD == 1) { + if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig + [j]->subframeAllocation.choice.oneFrame. + buf[0] & MBSFN_FDD_SF6) == MBSFN_FDD_SF6) { + if (msi_pos == 4) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.mcch_Offset_r9) + && + ((UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF6) == + MBSFN_FDD_SF6)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 7: + if (frame_FDD == 0) { // TDD + if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig + [j]->subframeAllocation.choice.oneFrame. + buf[0] & MBSFN_TDD_SF7) == MBSFN_TDD_SF7) { + if (msi_pos == 3) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.mcch_Offset_r9) + && + ((UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF7) == + MBSFN_TDD_SF7)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } else { // FDD + if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig + [j]->subframeAllocation.choice.oneFrame. + buf[0] & MBSFN_FDD_SF7) == MBSFN_FDD_SF7) { + if (msi_pos == 5) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.mcch_Offset_r9) + && + ((UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF7) == + MBSFN_FDD_SF7)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 8: + if (frame_FDD == 0) { //TDD + if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig + [j]->subframeAllocation.choice.oneFrame. + buf[0] & MBSFN_TDD_SF8) == MBSFN_TDD_SF8) { + if (msi_pos == 4) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.mcch_Offset_r9) + && + ((UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF8) == + MBSFN_TDD_SF8)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } else { // FDD + if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig + [j]->subframeAllocation.choice.oneFrame. + buf[0] & MBSFN_FDD_SF8) == MBSFN_FDD_SF8) { + if (msi_pos == 6) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.mcch_Offset_r9) + && + ((UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_FDD_SF8) == + MBSFN_FDD_SF8)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + + case 9: + if (frame_FDD == 0) { + if ((UE_mac_inst[module_idP].mbsfn_SubframeConfig + [j]->subframeAllocation.choice.oneFrame. + buf[0] & MBSFN_TDD_SF9) == MBSFN_TDD_SF9) { + if (msi_pos == 5) { + msi_flag = 1; + } + + if ((frameP % mcch_period == + UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.mcch_Offset_r9) + && + ((UE_mac_inst[module_idP].mbsfn_AreaInfo + [i]->mcch_Config_r9.sf_AllocInfo_r9. + buf[0] & MBSFN_TDD_SF9) == + MBSFN_TDD_SF9)) { + mcch_flag = 1; + } + + mtch_flag = 1; + } + } + + break; + } // end switch + + // sf allocation is non-overlapping + if ((msi_flag == 1) || (mcch_flag == 1) + || (mtch_flag == 1)) { + LOG_D(MAC, + "[UE %d] Frame %d Subframe %d: sync area %d SF alloc %d: msi flag %d, mcch flag %d, mtch flag %d\n", + module_idP, frameP, subframe, i, j, msi_flag, + mcch_flag, mtch_flag); + + *sync_area = i; + break; + } + } else { // four-frameP format + } + } + } // end of for +#if UE_TIMING_TRACE + stop_meas(&UE_mac_inst[module_idP].ue_query_mch); +#endif + + if ((mcch_flag == 1)) { // || (msi_flag==1)) + *mcch_active = 1; + } + + if ((mcch_flag == 1) + || ((msi_flag == 1) && (UE_mac_inst[module_idP].mcch_status == 1))) { + return mcch_mcs; + } else if ((mtch_flag == 1) + && (UE_mac_inst[module_idP].msi_status == 1)) { + return UE_mac_inst[module_idP].pmch_Config[0]->dataMCS_r9; + } else { + return -1; + } } #endif -unsigned char generate_ulsch_header(uint8_t *mac_header, - uint8_t num_sdus, - uint8_t short_padding, - uint16_t *sdu_lengths, - uint8_t *sdu_lcids, - POWER_HEADROOM_CMD *power_headroom, - uint16_t *crnti, - BSR_SHORT *truncated_bsr, - BSR_SHORT *short_bsr, - BSR_LONG *long_bsr, - unsigned short post_padding) +unsigned char +generate_ulsch_header(uint8_t * mac_header, + uint8_t num_sdus, + uint8_t short_padding, + uint16_t * sdu_lengths, + uint8_t * sdu_lcids, + POWER_HEADROOM_CMD * power_headroom, + uint16_t * crnti, + BSR_SHORT * truncated_bsr, + BSR_SHORT * short_bsr, + BSR_LONG * long_bsr, unsigned short post_padding) { - SCH_SUBHEADER_FIXED *mac_header_ptr = (SCH_SUBHEADER_FIXED *)mac_header; - unsigned char first_element=0,last_size=0,i; - unsigned char mac_header_control_elements[16],*ce_ptr; + SCH_SUBHEADER_FIXED *mac_header_ptr = + (SCH_SUBHEADER_FIXED *) mac_header; + unsigned char first_element = 0, last_size = 0, i; + unsigned char mac_header_control_elements[16], *ce_ptr; - LOG_D(MAC,"[UE] Generate ULSCH : num_sdus %d\n",num_sdus); + LOG_D(MAC, "[UE] Generate ULSCH : num_sdus %d\n", num_sdus); #ifdef DEBUG_HEADER_PARSING - for (i=0; iR = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = SHORT_PADDING; - first_element=1; - last_size=1; - } - - if (short_padding == 2) { - mac_header_ptr->E = 1; - mac_header_ptr++; - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = SHORT_PADDING; - last_size=1; - } - - if (power_headroom) { - if (first_element>0) { - mac_header_ptr->E = 1; - mac_header_ptr++; - } else { - first_element=1; + for (i = 0; i < num_sdus; i++) { + LOG_T(MAC, "[UE] sdu %d : lcid %d length %d", i, sdu_lcids[i], + sdu_lengths[i]); } - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = POWER_HEADROOM; - last_size=1; - *((POWER_HEADROOM_CMD *)ce_ptr)=(*power_headroom); - ce_ptr+=sizeof(POWER_HEADROOM_CMD); - LOG_D(MAC, "phr header size %zu\n",sizeof(POWER_HEADROOM_CMD)); - } + LOG_T(MAC, "\n"); +#endif + ce_ptr = &mac_header_control_elements[0]; - if (crnti) { + if ((short_padding == 1) || (short_padding == 2)) { + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = SHORT_PADDING; + first_element = 1; + last_size = 1; + } + + if (short_padding == 2) { + mac_header_ptr->E = 1; + mac_header_ptr++; + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = SHORT_PADDING; + last_size = 1; + } + + if (power_headroom) { + if (first_element > 0) { + mac_header_ptr->E = 1; + mac_header_ptr++; + } else { + first_element = 1; + } + + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = POWER_HEADROOM; + last_size = 1; + *((POWER_HEADROOM_CMD *) ce_ptr) = (*power_headroom); + ce_ptr += sizeof(POWER_HEADROOM_CMD); + LOG_D(MAC, "phr header size %zu\n", sizeof(POWER_HEADROOM_CMD)); + } + + if (crnti) { #ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] CRNTI : %x (first_element %d)\n",*crnti,first_element); + LOG_D(MAC, "[UE] CRNTI : %x (first_element %d)\n", *crnti, + first_element); #endif - if (first_element>0) { - mac_header_ptr->E = 1; - mac_header_ptr++; - } else { - first_element=1; + if (first_element > 0) { + mac_header_ptr->E = 1; + mac_header_ptr++; + } else { + first_element = 1; + } + + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = CRNTI; + last_size = 1; + *((uint16_t *) ce_ptr) = (*crnti); + ce_ptr += sizeof(uint16_t); + // printf("offset %d\n",ce_ptr-mac_header_control_elements); } - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = CRNTI; - last_size=1; - *((uint16_t *)ce_ptr)=(*crnti); - ce_ptr+=sizeof(uint16_t); - // printf("offset %d\n",ce_ptr-mac_header_control_elements); - } - - if (truncated_bsr) { - if (first_element>0) { - mac_header_ptr->E = 1; - /* - printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); - */ - mac_header_ptr++; - } else { - first_element=1; - } + if (truncated_bsr) { + if (first_element > 0) { + mac_header_ptr->E = 1; + /* + printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); + */ + mac_header_ptr++; + } else { + first_element = 1; + } #ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] Scheduler Truncated BSR Header\n"); + LOG_D(MAC, "[UE] Scheduler Truncated BSR Header\n"); #endif - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = TRUNCATED_BSR; - last_size=1; - *((BSR_TRUNCATED *)ce_ptr)=(*truncated_bsr); - ce_ptr+=sizeof(BSR_TRUNCATED); - // printf("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements); + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = TRUNCATED_BSR; + last_size = 1; + *((BSR_TRUNCATED *) ce_ptr) = (*truncated_bsr); + ce_ptr += sizeof(BSR_TRUNCATED); + // printf("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements); - } else if (short_bsr) { - if (first_element>0) { - mac_header_ptr->E = 1; - /* - printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); - */ - mac_header_ptr++; - } else { - first_element=1; - } + } else if (short_bsr) { + if (first_element > 0) { + mac_header_ptr->E = 1; + /* + printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); + */ + mac_header_ptr++; + } else { + first_element = 1; + } #ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] Scheduler SHORT BSR Header\n"); + LOG_D(MAC, "[UE] Scheduler SHORT BSR Header\n"); #endif - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = SHORT_BSR; - last_size=1; - *((BSR_SHORT *)ce_ptr)=(*short_bsr); - ce_ptr+=sizeof(BSR_SHORT); + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = SHORT_BSR; + last_size = 1; + *((BSR_SHORT *) ce_ptr) = (*short_bsr); + ce_ptr += sizeof(BSR_SHORT); - // printf("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements); - } else if (long_bsr) { - if (first_element>0) { - mac_header_ptr->E = 1; - /* - printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); - */ - mac_header_ptr++; - } else { - first_element=1; - } + // printf("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements); + } else if (long_bsr) { + if (first_element > 0) { + mac_header_ptr->E = 1; + /* + printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); + */ + mac_header_ptr++; + } else { + first_element = 1; + } #ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] Scheduler Long BSR Header\n"); + LOG_D(MAC, "[UE] Scheduler Long BSR Header\n"); #endif - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = LONG_BSR; - last_size=1; + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = LONG_BSR; + last_size = 1; - *(ce_ptr) = (long_bsr->Buffer_size0 << 2) | ((long_bsr->Buffer_size1 & 0x30) >> 4); - *(ce_ptr + 1) = ((long_bsr->Buffer_size1 & 0x0F) << 4) | ((long_bsr->Buffer_size2 & 0x3C) >> 2); - *(ce_ptr + 2) = ((long_bsr->Buffer_size2 & 0x03) << 2) | (long_bsr->Buffer_size3 & 0x3F); - ce_ptr += BSR_LONG_SIZE; + *(ce_ptr) = + (long_bsr-> + Buffer_size0 << 2) | ((long_bsr->Buffer_size1 & 0x30) >> 4); + *(ce_ptr + 1) = + ((long_bsr->Buffer_size1 & 0x0F) << 4) | ((long_bsr-> + Buffer_size2 & 0x3C) + >> 2); + *(ce_ptr + 2) = + ((long_bsr-> + Buffer_size2 & 0x03) << 2) | (long_bsr->Buffer_size3 & 0x3F); + ce_ptr += BSR_LONG_SIZE; - // printf("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements); - } - - // printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); - - for (i=0; i0) { - mac_header_ptr->E = 1; - #ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); - #endif - mac_header_ptr+=last_size; - } - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = sdu_lcids[i]; + // printf("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements); } - else { - if ((first_element>0)) { - mac_header_ptr->E = 1; - #ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); - #endif - mac_header_ptr+=last_size; - // printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); - } else { - first_element=1; - - } - - if (sdu_lengths[i] < 128) { - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R = 0; // 3 - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->E = 0; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F = 0; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->LCID = sdu_lcids[i]; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L = (unsigned char)sdu_lengths[i]; - last_size=2; - #ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] short sdu\n"); - LOG_T(MAC,"[UE] last subheader : %x (R%d,E%d,LCID%d,F%d,L%d)\n", - ((uint16_t*)mac_header_ptr)[0], - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R, - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->E, - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->LCID, - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F, - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L); - #endif - } else { - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->R = 0; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->E = 0; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->F = 1; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->LCID = sdu_lcids[i]; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_MSB = ((unsigned short) sdu_lengths[i]>>8)&0x7f; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB = (unsigned short) sdu_lengths[i]&0xff; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->padding = 0x00; - last_size=3; - #ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] long sdu\n"); - #endif - } - } - } - - if (post_padding>0) {// we have lots of padding at the end of the packet - mac_header_ptr->E = 1; - mac_header_ptr+=last_size; - // add a padding element - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = SHORT_PADDING; - mac_header_ptr++; - } else { // no end of packet padding - // last SDU subhead is of fixed type (sdu length implicitly to be computed at UE) - mac_header_ptr++; - //mac_header_ptr=last_size; // FIXME: should be ++ - } - - - if ((ce_ptr-mac_header_control_elements) > 0) { - memcpy((void*)mac_header_ptr,mac_header_control_elements,ce_ptr-mac_header_control_elements); - mac_header_ptr+=(unsigned char)(ce_ptr-mac_header_control_elements); - } + // printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); + for (i = 0; i < num_sdus; i++) { #ifdef DEBUG_HEADER_PARSING - LOG_T(MAC," [UE] header : "); - - for (i=0; i<((unsigned char*)mac_header_ptr - mac_header); i++) { - LOG_T(MAC,"%2x.",mac_header[i]); - } - - LOG_T(MAC,"\n"); + LOG_T(MAC, "[UE] sdu subheader %d (lcid %d, %d bytes)\n", i, + sdu_lcids[i], sdu_lengths[i]); #endif - return((unsigned char*)mac_header_ptr - mac_header); + + if ((i == (num_sdus - 1)) + && ((short_padding) || (post_padding == 0))) { + if (first_element > 0) { + mac_header_ptr->E = 1; +#ifdef DEBUG_HEADER_PARSING + LOG_D(MAC, "[UE] last subheader : %x (R%d,E%d,LCID%d)\n", + *(unsigned char *) mac_header_ptr, + ((SCH_SUBHEADER_FIXED *) mac_header_ptr)->R, + ((SCH_SUBHEADER_FIXED *) mac_header_ptr)->E, + ((SCH_SUBHEADER_FIXED *) mac_header_ptr)->LCID); +#endif + mac_header_ptr += last_size; + } + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = sdu_lcids[i]; + } else { + if ((first_element > 0)) { + mac_header_ptr->E = 1; +#ifdef DEBUG_HEADER_PARSING + LOG_D(MAC, "[UE] last subheader : %x (R%d,E%d,LCID%d)\n", + *(unsigned char *) mac_header_ptr, + ((SCH_SUBHEADER_FIXED *) mac_header_ptr)->R, + ((SCH_SUBHEADER_FIXED *) mac_header_ptr)->E, + ((SCH_SUBHEADER_FIXED *) mac_header_ptr)->LCID); +#endif + mac_header_ptr += last_size; + // printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); + } else { + first_element = 1; + + } + + if (sdu_lengths[i] < 128) { + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->R = 0; // 3 + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->E = 0; + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->F = 0; + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->LCID = + sdu_lcids[i]; + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->L = + (unsigned char) sdu_lengths[i]; + last_size = 2; +#ifdef DEBUG_HEADER_PARSING + LOG_D(MAC, "[UE] short sdu\n"); + LOG_T(MAC, + "[UE] last subheader : %x (R%d,E%d,LCID%d,F%d,L%d)\n", + ((uint16_t *) mac_header_ptr)[0], + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->R, + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->E, + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->LCID, + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->F, + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->L); +#endif + } else { + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->R = 0; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->E = 0; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->F = 1; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->LCID = + sdu_lcids[i]; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB = + ((unsigned short) sdu_lengths[i] >> 8) & 0x7f; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_LSB = + (unsigned short) sdu_lengths[i] & 0xff; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->padding = 0x00; + last_size = 3; +#ifdef DEBUG_HEADER_PARSING + LOG_D(MAC, "[UE] long sdu\n"); +#endif + } + } + } + + if (post_padding > 0) { // we have lots of padding at the end of the packet + mac_header_ptr->E = 1; + mac_header_ptr += last_size; + // add a padding element + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = SHORT_PADDING; + mac_header_ptr++; + } else { // no end of packet padding + // last SDU subhead is of fixed type (sdu length implicitly to be computed at UE) + mac_header_ptr++; + //mac_header_ptr=last_size; // FIXME: should be ++ + } + + + if ((ce_ptr - mac_header_control_elements) > 0) { + memcpy((void *) mac_header_ptr, mac_header_control_elements, + ce_ptr - mac_header_control_elements); + mac_header_ptr += + (unsigned char) (ce_ptr - mac_header_control_elements); + } +#ifdef DEBUG_HEADER_PARSING + LOG_T(MAC, " [UE] header : "); + + for (i = 0; i < ((unsigned char *) mac_header_ptr - mac_header); i++) { + LOG_T(MAC, "%2x.", mac_header[i]); + } + + LOG_T(MAC, "\n"); +#endif + return ((unsigned char *) mac_header_ptr - mac_header); } -void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subframe, uint8_t eNB_index,uint8_t *ulsch_buffer,uint16_t buflen, uint8_t *access_mode) +void +ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP, + sub_frame_t subframe, uint8_t eNB_index, + uint8_t * ulsch_buffer, uint16_t buflen, uint8_t * access_mode) { - uint8_t total_rlc_pdu_header_len=0, rlc_pdu_header_len_last=0 ; - uint16_t buflen_remain = 0; - uint8_t bsr_len=0,bsr_ce_len=0,bsr_header_len=0; - uint8_t phr_header_len=0, phr_ce_len=0,phr_len=0; - uint8_t lcid=0,lcid_rlc_pdu_count=0; - boolean_t is_lcid_processed = FALSE; - boolean_t is_all_lcid_processed = FALSE; - uint16_t sdu_lengths[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - uint8_t sdu_lcids[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - uint8_t payload_offset=0,num_sdus=0; - uint8_t ulsch_buff[MAX_ULSCH_PAYLOAD_BYTES]; - uint16_t sdu_length_total=0; - BSR_SHORT bsr_short,bsr_truncated; - BSR_LONG bsr_long; - BSR_SHORT *bsr_s=&bsr_short; - BSR_LONG *bsr_l=&bsr_long; - BSR_SHORT *bsr_t=&bsr_truncated; - POWER_HEADROOM_CMD phr; - POWER_HEADROOM_CMD *phr_p=&phr; - unsigned short short_padding=0, post_padding=0, padding_len=0; - int j; // used for padding - // Compute header length - int lcg_id = 0; - int lcg_id_bsr_trunc = 0; - int highest_priority = 16; - int num_lcg_id_with_data = 0; - rlc_buffer_occupancy_t lcid_buffer_occupancy_old=0, lcid_buffer_occupancy_new=0; - - LOG_D(MAC,"[UE %d] MAC PROCESS UL TRANSPORT BLOCK at frame%d subframe %d TBS=%d\n", - module_idP, frameP, subframe, buflen); + uint8_t total_rlc_pdu_header_len = 0, rlc_pdu_header_len_last = 0; + uint16_t buflen_remain = 0; + uint8_t bsr_len = 0, bsr_ce_len = 0, bsr_header_len = 0; + uint8_t phr_header_len = 0, phr_ce_len = 0, phr_len = 0; + uint8_t lcid = 0, lcid_rlc_pdu_count = 0; + boolean_t is_lcid_processed = FALSE; + boolean_t is_all_lcid_processed = FALSE; + uint16_t sdu_lengths[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t sdu_lcids[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t payload_offset = 0, num_sdus = 0; + uint8_t ulsch_buff[MAX_ULSCH_PAYLOAD_BYTES]; + uint16_t sdu_length_total = 0; + BSR_SHORT bsr_short, bsr_truncated; + BSR_LONG bsr_long; + BSR_SHORT *bsr_s = &bsr_short; + BSR_LONG *bsr_l = &bsr_long; + BSR_SHORT *bsr_t = &bsr_truncated; + POWER_HEADROOM_CMD phr; + POWER_HEADROOM_CMD *phr_p = &phr; + unsigned short short_padding = 0, post_padding = 0, padding_len = 0; + int j; // used for padding + // Compute header length + int lcg_id = 0; + int lcg_id_bsr_trunc = 0; + int highest_priority = 16; + int num_lcg_id_with_data = 0; + rlc_buffer_occupancy_t lcid_buffer_occupancy_old = + 0, lcid_buffer_occupancy_new = 0; + + LOG_D(MAC, + "[UE %d] MAC PROCESS UL TRANSPORT BLOCK at frame%d subframe %d TBS=%d\n", + module_idP, frameP, subframe, buflen); - AssertFatal(CC_id==0, - "Transmission on secondary CCs is not supported yet\n"); + AssertFatal(CC_id == 0, + "Transmission on secondary CCs is not supported yet\n"); #if UE_TIMING_TRACE - start_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu); + start_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu); #endif - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_IN); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_IN); #ifdef CBA - if (*access_mode==CBA_ACCESS) { - LOG_D(MAC,"[UE %d] frameP %d subframe %d try CBA transmission\n", - module_idP, frameP, subframe); + if (*access_mode == CBA_ACCESS) { + LOG_D(MAC, "[UE %d] frameP %d subframe %d try CBA transmission\n", + module_idP, frameP, subframe); - //if (UE_mac_inst[module_idP].scheduling_info.LCID_status[DTCH] == LCID_EMPTY) - if (cba_access(module_idP,frameP,subframe,eNB_index,buflen)==0) { - *access_mode=POSTPONED_ACCESS; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_OUT); - return; + //if (UE_mac_inst[module_idP].scheduling_info.LCID_status[DTCH] == LCID_EMPTY) + if (cba_access(module_idP, frameP, subframe, eNB_index, buflen) == + 0) { + *access_mode = POSTPONED_ACCESS; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_OUT); + return; + } + + LOG_I(MAC, + "[UE %d] frameP %d subframe %d CBA transmission oppurtunity, tbs %d\n", + module_idP, frameP, subframe, buflen); } - - LOG_I(MAC,"[UE %d] frameP %d subframe %d CBA transmission oppurtunity, tbs %d\n", - module_idP, frameP, subframe,buflen); - } - #endif - bsr_header_len = 0; - phr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED); - - while (lcg_id < MAX_NUM_LCGID) { - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]){ - num_lcg_id_with_data ++; - } - lcg_id ++; - } - - if (num_lcg_id_with_data){ - LOG_D(MAC,"[UE %d] MAC Tx data pending at frame%d subframe %d nb LCG =%d Bytes for LCG0=%d LCG1=%d LCG2=%d LCG3=%d BSR Trigger status =%d TBS=%d\n", - module_idP, - frameP, - subframe, - num_lcg_id_with_data, - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[0], - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[1], - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[2], - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[3], - UE_mac_inst[module_idP].BSR_reporting_active, buflen); - - } - //Restart ReTxBSR Timer at new grant indication (36.321) - if (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF != MAC_UE_BSR_TIMER_NOT_RUNNING){ - UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); - } - - // periodicBSR-Timer expires, trigger BSR - if ((UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer != PeriodicBSR_Timer_r12_infinity) - && (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF == 0)){ - // Trigger BSR Periodic - UE_mac_inst[module_idP].BSR_reporting_active |= BSR_TRIGGER_PERIODIC; - - LOG_D(MAC,"[UE %d] MAC BSR Triggered PeriodicBSR Timer expiry at frame%d subframe %d TBS=%d\n", - module_idP, frameP, subframe, buflen); + bsr_header_len = 0; + phr_header_len = 1; //sizeof(SCH_SUBHEADER_FIXED); + while (lcg_id < MAX_NUM_LCGID) { + if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]) { + num_lcg_id_with_data++; + } + lcg_id++; } - //Compute BSR Length if Regular or Periodic BSR is triggered - //WARNING: if BSR long is computed, it may be changed to BSR short during or after multiplexing if there remains less than 1 LCGROUP with data after Tx - if (UE_mac_inst[module_idP].BSR_reporting_active){ + if (num_lcg_id_with_data) { + LOG_D(MAC, + "[UE %d] MAC Tx data pending at frame%d subframe %d nb LCG =%d Bytes for LCG0=%d LCG1=%d LCG2=%d LCG3=%d BSR Trigger status =%d TBS=%d\n", + module_idP, frameP, subframe, num_lcg_id_with_data, + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[0], + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[1], + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[2], + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[3], + UE_mac_inst[module_idP].BSR_reporting_active, buflen); - AssertFatal ((UE_mac_inst[module_idP].BSR_reporting_active & BSR_TRIGGER_PADDING) == 0 , "Inconsistent BSR Trigger=%d !\n", - UE_mac_inst[module_idP].BSR_reporting_active); + } + //Restart ReTxBSR Timer at new grant indication (36.321) + if (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF != + MAC_UE_BSR_TIMER_NOT_RUNNING) { + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = + get_sf_retxBSRTimer(UE_mac_inst[module_idP]. + scheduling_info.retxBSR_Timer); + } + // periodicBSR-Timer expires, trigger BSR + if ((UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer != + PeriodicBSR_Timer_r12_infinity) + && (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF == 0)) { + // Trigger BSR Periodic + UE_mac_inst[module_idP].BSR_reporting_active |= + BSR_TRIGGER_PERIODIC; - if (buflen >= 4){ - //A Regular or Periodic BSR can only be sent if TBS >= 4 as transmitting only a BSR is not allowed if UE has data to transmit - bsr_header_len = 1; + LOG_D(MAC, + "[UE %d] MAC BSR Triggered PeriodicBSR Timer expiry at frame%d subframe %d TBS=%d\n", + module_idP, frameP, subframe, buflen); - if (num_lcg_id_with_data <= 1){ - bsr_ce_len = sizeof(BSR_SHORT); //1 byte - } - else{ - bsr_ce_len = BSR_LONG_SIZE; //3 bytes - } - } - } + } + //Compute BSR Length if Regular or Periodic BSR is triggered + //WARNING: if BSR long is computed, it may be changed to BSR short during or after multiplexing if there remains less than 1 LCGROUP with data after Tx + if (UE_mac_inst[module_idP].BSR_reporting_active) { - bsr_len = bsr_ce_len + bsr_header_len; + AssertFatal((UE_mac_inst[module_idP].BSR_reporting_active & + BSR_TRIGGER_PADDING) == 0, + "Inconsistent BSR Trigger=%d !\n", + UE_mac_inst[module_idP].BSR_reporting_active); - phr_ce_len = (UE_mac_inst[module_idP].PHR_reporting_active == 1) ? 1 /* sizeof(POWER_HEADROOM_CMD)*/: 0; - if ((phr_ce_len > 0) && ((phr_ce_len + phr_header_len + bsr_len) <= buflen)){ - phr_len = phr_ce_len + phr_header_len; - LOG_D(MAC,"[UE %d] header size info: PHR len %d (ce%d,hdr%d) buff_len %d\n", - module_idP, phr_len, phr_ce_len, phr_header_len, buflen); - } else { - phr_len=0; - phr_header_len = 0; - phr_ce_len = 0; - } + if (buflen >= 4) { + //A Regular or Periodic BSR can only be sent if TBS >= 4 as transmitting only a BSR is not allowed if UE has data to transmit + bsr_header_len = 1; - // check for UL bandwidth requests and add SR control element + if (num_lcg_id_with_data <= 1) { + bsr_ce_len = sizeof(BSR_SHORT); //1 byte + } else { + bsr_ce_len = BSR_LONG_SIZE; //3 bytes + } + } + } - // check for UL bandwidth requests and add SR control element + bsr_len = bsr_ce_len + bsr_header_len; - // Check for DCCH first + phr_ce_len = + (UE_mac_inst[module_idP].PHR_reporting_active == + 1) ? 1 /* sizeof(POWER_HEADROOM_CMD) */ : 0; + if ((phr_ce_len > 0) + && ((phr_ce_len + phr_header_len + bsr_len) <= buflen)) { + phr_len = phr_ce_len + phr_header_len; + LOG_D(MAC, + "[UE %d] header size info: PHR len %d (ce%d,hdr%d) buff_len %d\n", + module_idP, phr_len, phr_ce_len, phr_header_len, buflen); + } else { + phr_len = 0; + phr_header_len = 0; + phr_ce_len = 0; + } + + // check for UL bandwidth requests and add SR control element + + // check for UL bandwidth requests and add SR control element + + // Check for DCCH first // TO DO: Multiplex in the order defined by the logical channel prioritization -for (lcid=DCCH; (lcid < MAX_NUM_LCID) && (is_all_lcid_processed == FALSE) ; lcid++) { - if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) { + for (lcid = DCCH; + (lcid < MAX_NUM_LCID) && (is_all_lcid_processed == FALSE); lcid++) + { + if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == + LCID_NOT_EMPTY) { - lcid_rlc_pdu_count = 0; - is_lcid_processed = FALSE; - lcid_buffer_occupancy_old = mac_rlc_get_buffer_occupancy_ind(module_idP, - UE_mac_inst[module_idP].crnti, - eNB_index, - frameP, - subframe, - ENB_FLAG_NO, - lcid); + lcid_rlc_pdu_count = 0; + is_lcid_processed = FALSE; + lcid_buffer_occupancy_old = + mac_rlc_get_buffer_occupancy_ind(module_idP, + UE_mac_inst[module_idP]. + crnti, eNB_index, frameP, + subframe, ENB_FLAG_NO, + lcid); - lcid_buffer_occupancy_new = lcid_buffer_occupancy_old; + lcid_buffer_occupancy_new = lcid_buffer_occupancy_old; - AssertFatal (lcid_buffer_occupancy_new == UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid], "LCID=%d RLC has BO %d bytes but MAC has stored %d bytes\n", - lcid,lcid_buffer_occupancy_new,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]); + AssertFatal(lcid_buffer_occupancy_new == + UE_mac_inst[module_idP]. + scheduling_info.LCID_buffer_remain[lcid], + "LCID=%d RLC has BO %d bytes but MAC has stored %d bytes\n", + lcid, lcid_buffer_occupancy_new, + UE_mac_inst[module_idP]. + scheduling_info.LCID_buffer_remain[lcid]); - AssertFatal (lcid_buffer_occupancy_new <= UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], "LCID=%d RLC has more BO %d bytes than BSR = %d bytes\n", - lcid,lcid_buffer_occupancy_new,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); + AssertFatal(lcid_buffer_occupancy_new <= + UE_mac_inst[module_idP]. + scheduling_info.BSR_bytes[UE_mac_inst[module_idP]. + scheduling_info.LCGID + [lcid]], + "LCID=%d RLC has more BO %d bytes than BSR = %d bytes\n", + lcid, lcid_buffer_occupancy_new, + UE_mac_inst[module_idP]. + scheduling_info.BSR_bytes[UE_mac_inst[module_idP]. + scheduling_info.LCGID + [lcid]]); - //Multiplex all available DCCH RLC PDUs considering to multiplex the last PDU each time for maximize the data - //Adjust at the end of the loop - while ((!is_lcid_processed) && (lcid_buffer_occupancy_new) && (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + MIN_MAC_HDR_RLC_SIZE <= buflen)) { + //Multiplex all available DCCH RLC PDUs considering to multiplex the last PDU each time for maximize the data + //Adjust at the end of the loop + while ((!is_lcid_processed) && (lcid_buffer_occupancy_new) + && (bsr_len + phr_len + total_rlc_pdu_header_len + + sdu_length_total + MIN_MAC_HDR_RLC_SIZE <= buflen)) + { - // Workaround for issue in OAI eNB or EPC which are not able to process SRB2 message multiplexed with SRB1 on the same MAC PDU - if ((usim_test == 0) && (lcid == DCCH1) && (lcid_rlc_pdu_count == 0) && (num_sdus)) { + // Workaround for issue in OAI eNB or EPC which are not able to process SRB2 message multiplexed with SRB1 on the same MAC PDU + if ((usim_test == 0) && (lcid == DCCH1) + && (lcid_rlc_pdu_count == 0) && (num_sdus)) { - // Skip SRB2 multiplex if at least one SRB1 SDU is already multiplexed - break; - } + // Skip SRB2 multiplex if at least one SRB1 SDU is already multiplexed + break; + } - buflen_remain = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); + buflen_remain = + buflen - (bsr_len + phr_len + + total_rlc_pdu_header_len + sdu_length_total + + 1); - LOG_D(MAC, "[UE %d] Frame %d : UL-DXCH -> ULSCH, RLC %d has %d bytes to " - "send (Transport Block size %d BSR size=%d PHR=%d SDU Length Total %d , mac header len %d BSR byte before Tx=%d)\n", - module_idP,frameP, lcid,lcid_buffer_occupancy_new,buflen,bsr_len,phr_len,sdu_length_total,total_rlc_pdu_header_len,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); + LOG_D(MAC, + "[UE %d] Frame %d : UL-DXCH -> ULSCH, RLC %d has %d bytes to " + "send (Transport Block size %d BSR size=%d PHR=%d SDU Length Total %d , mac header len %d BSR byte before Tx=%d)\n", + module_idP, frameP, lcid, lcid_buffer_occupancy_new, + buflen, bsr_len, phr_len, sdu_length_total, + total_rlc_pdu_header_len, + UE_mac_inst[module_idP]. + scheduling_info.BSR_bytes[UE_mac_inst[module_idP]. + scheduling_info.LCGID + [lcid]]); - sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, - UE_mac_inst[module_idP].crnti, - eNB_index, + sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, + UE_mac_inst + [module_idP]. + crnti, eNB_index, frameP, ENB_FLAG_NO, MBMS_FLAG_NO, lcid, buflen_remain, - (char *)&ulsch_buff[sdu_length_total]); + (char *) + &ulsch_buff + [sdu_length_total]); - AssertFatal (buflen_remain >= sdu_lengths[num_sdus], "LCID=%d RLC has segmented %d bytes but MAC has max=%d\n", - lcid,sdu_lengths[num_sdus],buflen_remain); + AssertFatal(buflen_remain >= sdu_lengths[num_sdus], + "LCID=%d RLC has segmented %d bytes but MAC has max=%d\n", + lcid, sdu_lengths[num_sdus], buflen_remain); - if (sdu_lengths[num_sdus]) - { - sdu_length_total += sdu_lengths[num_sdus]; - sdu_lcids[num_sdus] = lcid; - LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU TX Got %d bytes for LcId%d\n",module_idP,sdu_lengths[num_sdus],lcid); + if (sdu_lengths[num_sdus]) { + sdu_length_total += sdu_lengths[num_sdus]; + sdu_lcids[num_sdus] = lcid; + LOG_D(MAC, + "[UE %d] TX Multiplex RLC PDU TX Got %d bytes for LcId%d\n", + module_idP, sdu_lengths[num_sdus], lcid); - if (buflen == (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1)) { - //No more remaining TBS after this PDU - //exit the function - rlc_pdu_header_len_last = 1; - is_lcid_processed = TRUE; - is_all_lcid_processed = TRUE; - } - else { - rlc_pdu_header_len_last = (sdu_lengths[num_sdus] > 128 ) ? 3 : 2 ; + if (buflen == + (bsr_len + phr_len + total_rlc_pdu_header_len + + sdu_length_total + 1)) { + //No more remaining TBS after this PDU + //exit the function + rlc_pdu_header_len_last = 1; + is_lcid_processed = TRUE; + is_all_lcid_processed = TRUE; + } else { + rlc_pdu_header_len_last = + (sdu_lengths[num_sdus] > 128) ? 3 : 2; - //Change to 1 byte if it does not fit in the TBS, ie last PDU - if (buflen <= (bsr_len + phr_len + total_rlc_pdu_header_len + rlc_pdu_header_len_last + sdu_length_total)) { - rlc_pdu_header_len_last = 1; - is_lcid_processed = TRUE; - is_all_lcid_processed = TRUE; - } - } + //Change to 1 byte if it does not fit in the TBS, ie last PDU + if (buflen <= + (bsr_len + phr_len + total_rlc_pdu_header_len + + rlc_pdu_header_len_last + sdu_length_total)) { + rlc_pdu_header_len_last = 1; + is_lcid_processed = TRUE; + is_all_lcid_processed = TRUE; + } + } - //Update number of SDU - num_sdus ++; + //Update number of SDU + num_sdus++; - //Update total MAC Header size for RLC PDUs and save last one - total_rlc_pdu_header_len += rlc_pdu_header_len_last; + //Update total MAC Header size for RLC PDUs and save last one + total_rlc_pdu_header_len += rlc_pdu_header_len_last; - lcid_rlc_pdu_count ++; - } - else - { - /* avoid infinite loop ... */ - is_lcid_processed = TRUE; - } + lcid_rlc_pdu_count++; + } else { + /* avoid infinite loop ... */ + is_lcid_processed = TRUE; + } - /* Get updated BO after multiplexing this PDU */ - lcid_buffer_occupancy_new = mac_rlc_get_buffer_occupancy_ind(module_idP, - UE_mac_inst[module_idP].crnti, - eNB_index, - frameP, - subframe, - ENB_FLAG_NO, - lcid); + /* Get updated BO after multiplexing this PDU */ + lcid_buffer_occupancy_new = + mac_rlc_get_buffer_occupancy_ind(module_idP, + UE_mac_inst + [module_idP].crnti, + eNB_index, frameP, + subframe, ENB_FLAG_NO, + lcid); - is_lcid_processed = (is_lcid_processed) || (lcid_buffer_occupancy_new <= 0); - } + is_lcid_processed = (is_lcid_processed) + || (lcid_buffer_occupancy_new <= 0); + } - //Update Buffer remain and BSR bytes after transmission + //Update Buffer remain and BSR bytes after transmission - AssertFatal (lcid_buffer_occupancy_new <= lcid_buffer_occupancy_old, "MAC UE Tx error : Buffer Occupancy After Tx=%d greater than before=%d BO! for LCID=%d RLC PDU nb=%d Frame %d Subrame %d\n", - lcid_buffer_occupancy_new,lcid_buffer_occupancy_old,lcid,lcid_rlc_pdu_count,frameP,subframe); + AssertFatal(lcid_buffer_occupancy_new <= + lcid_buffer_occupancy_old, + "MAC UE Tx error : Buffer Occupancy After Tx=%d greater than before=%d BO! for LCID=%d RLC PDU nb=%d Frame %d Subrame %d\n", + lcid_buffer_occupancy_new, + lcid_buffer_occupancy_old, lcid, + lcid_rlc_pdu_count, frameP, subframe); - UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] = lcid_buffer_occupancy_new; - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] += (lcid_buffer_occupancy_new - lcid_buffer_occupancy_old); + UE_mac_inst[module_idP].scheduling_info. + LCID_buffer_remain[lcid] = lcid_buffer_occupancy_new; + UE_mac_inst[module_idP]. + scheduling_info.BSR_bytes[UE_mac_inst[module_idP]. + scheduling_info.LCGID[lcid]] += + (lcid_buffer_occupancy_new - lcid_buffer_occupancy_old); - //Update the number of LCGID with data as BSR shall reflect status after BSR transmission - if ((num_lcg_id_with_data > 1) && (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] == 0)) - { - num_lcg_id_with_data --; - // Change BSR size to BSR SHORT if num_lcg_id_with_data becomes to 1 - if ((bsr_len) && (num_lcg_id_with_data == 1)) - { - bsr_ce_len = sizeof(BSR_SHORT); - bsr_len = bsr_ce_len + bsr_header_len; - } + //Update the number of LCGID with data as BSR shall reflect status after BSR transmission + if ((num_lcg_id_with_data > 1) + && (UE_mac_inst[module_idP]. + scheduling_info.BSR_bytes[UE_mac_inst[module_idP]. + scheduling_info.LCGID[lcid]] + == 0)) { + num_lcg_id_with_data--; + // Change BSR size to BSR SHORT if num_lcg_id_with_data becomes to 1 + if ((bsr_len) && (num_lcg_id_with_data == 1)) { + bsr_ce_len = sizeof(BSR_SHORT); + bsr_len = bsr_ce_len + bsr_header_len; + } + } + + + UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = + LCID_EMPTY; + } } - UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_EMPTY; - } - } + + // Compute BSR Values and update Nb LCGID with data after multiplexing + num_lcg_id_with_data = 0; + lcg_id_bsr_trunc = 0; + for (lcg_id = 0; lcg_id < MAX_NUM_LCGID; lcg_id++) { + UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] = + locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, + UE_mac_inst + [module_idP].scheduling_info. + BSR_bytes[lcg_id]); + + if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]) { + num_lcg_id_with_data++; + lcg_id_bsr_trunc = lcg_id; + } + } + if (bsr_ce_len) { + //Print updated BSR when sent + LOG_D(MAC, + "[UE %d] Remaining Buffer after Tx frame%d subframe %d nb LCG =%d Bytes for LCG0=%d LCG1=%d LCG2=%d LCG3=%d BSR Trigger status =%d TBS=%d\n", + module_idP, frameP, subframe, num_lcg_id_with_data, + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[0], + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[1], + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[2], + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[3], + UE_mac_inst[module_idP].BSR_reporting_active, buflen); - // Compute BSR Values and update Nb LCGID with data after multiplexing - num_lcg_id_with_data = 0; - lcg_id_bsr_trunc = 0; - for (lcg_id=0;lcg_idPH = get_phr_mapping(module_idP, CC_id, eNB_index); + phr_p->R = 0; + LOG_D(MAC, + "[UE %d] Frame %d report PHR with mapping (%d->%d) for LCID %d\n", + module_idP, frameP, get_PHR(module_idP, CC_id, eNB_index), + phr_p->PH, POWER_HEADROOM); + update_phr(module_idP, CC_id); + } else { + phr_p = NULL; + } - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]){ - num_lcg_id_with_data ++; - lcg_id_bsr_trunc = lcg_id; - } - } + LOG_T(MAC, "[UE %d] Frame %d: bsr s %p bsr_l %p, phr_p %p\n", + module_idP, frameP, bsr_s, bsr_l, phr_p); - if (bsr_ce_len) { - //Print updated BSR when sent - LOG_D(MAC,"[UE %d] Remaining Buffer after Tx frame%d subframe %d nb LCG =%d Bytes for LCG0=%d LCG1=%d LCG2=%d LCG3=%d BSR Trigger status =%d TBS=%d\n", - module_idP, - frameP, - subframe, - num_lcg_id_with_data, - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[0], - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[1], - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[2], - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[3], - UE_mac_inst[module_idP].BSR_reporting_active, buflen); - - LOG_D(MAC,"[UE %d] Frame %d Subframe %d TX BSR Regular or Periodic size=%d BSR0=%d BSR1=%d BSR2=%d BSR3=%d\n",module_idP,frameP,subframe,bsr_ce_len, - UE_mac_inst[module_idP].scheduling_info.BSR[0], - UE_mac_inst[module_idP].scheduling_info.BSR[1], - UE_mac_inst[module_idP].scheduling_info.BSR[2], - UE_mac_inst[module_idP].scheduling_info.BSR[3]); - } + // Check BSR padding: it is done after PHR according to Logical Channel Prioritization order + // Check for max padding size, ie MAC Hdr for last RLC PDU = 1 + /* For Padding BSR: + - if the number of padding bits is equal to or larger than the size of the Short BSR plus its subheader but smaller than the size of the Long BSR plus its subheader: + - if more than one LCG has data available for transmission in the TTI where the BSR is transmitted: report Truncated BSR of the LCG with the highest priority logical channel with data available for transmission; + - else report Short BSR. + - else if the number of padding bits is equal to or larger than the size of the Long BSR plus its subheader, report Long BSR. + */ + if (sdu_length_total) { + padding_len = + buflen - (bsr_len + phr_len + total_rlc_pdu_header_len - + rlc_pdu_header_len_last + sdu_length_total + 1); + } else { + padding_len = buflen - (bsr_len + phr_len); + } - // build PHR and update the timers - if (phr_ce_len == sizeof(POWER_HEADROOM_CMD)) { - phr_p->PH = get_phr_mapping(module_idP,CC_id,eNB_index); - phr_p->R = 0; - LOG_D(MAC,"[UE %d] Frame %d report PHR with mapping (%d->%d) for LCID %d\n", - module_idP,frameP, get_PHR(module_idP,CC_id,eNB_index), phr_p->PH,POWER_HEADROOM); - update_phr(module_idP,CC_id); - } else { - phr_p=NULL; - } - - LOG_T(MAC,"[UE %d] Frame %d: bsr s %p bsr_l %p, phr_p %p\n", module_idP,frameP,bsr_s, bsr_l, phr_p); + if ((padding_len) && (bsr_len == 0)) { + /* if the number of padding bits is equal to or larger than the size of the Long BSR plus its subheader, report Long BSR */ + if (padding_len >= (1 + BSR_LONG_SIZE)) { + bsr_ce_len = BSR_LONG_SIZE; + bsr_header_len = 1; + // Trigger BSR Padding + UE_mac_inst[module_idP].BSR_reporting_active |= + BSR_TRIGGER_PADDING; - // Check BSR padding: it is done after PHR according to Logical Channel Prioritization order - // Check for max padding size, ie MAC Hdr for last RLC PDU = 1 - /* For Padding BSR: - - if the number of padding bits is equal to or larger than the size of the Short BSR plus its subheader but smaller than the size of the Long BSR plus its subheader: - - if more than one LCG has data available for transmission in the TTI where the BSR is transmitted: report Truncated BSR of the LCG with the highest priority logical channel with data available for transmission; - - else report Short BSR. - - else if the number of padding bits is equal to or larger than the size of the Long BSR plus its subheader, report Long BSR. - */ - if (sdu_length_total) { - padding_len = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len - rlc_pdu_header_len_last + sdu_length_total + 1); - } - else { - padding_len = buflen - (bsr_len + phr_len); - } + } else if (padding_len >= (1 + sizeof(BSR_SHORT))) { + bsr_ce_len = sizeof(BSR_SHORT); + bsr_header_len = 1; + if (num_lcg_id_with_data > 1) { + // REPORT TRUNCATED BSR + //Get LCGID of highest priority LCID with data + for (lcid = DCCH; lcid < MAX_NUM_LCID; lcid++) { + if (UE_mac_inst[module_idP]. + logicalChannelConfig[lcid] != NULL) { + lcg_id = + UE_mac_inst[module_idP].scheduling_info. + LCGID[lcid]; - if ((padding_len) && (bsr_len == 0)) - { - /* if the number of padding bits is equal to or larger than the size of the Long BSR plus its subheader, report Long BSR*/ - if (padding_len >= (1+BSR_LONG_SIZE)) - { - bsr_ce_len = BSR_LONG_SIZE; - bsr_header_len = 1; - // Trigger BSR Padding - UE_mac_inst[module_idP].BSR_reporting_active |= BSR_TRIGGER_PADDING; + if ((lcg_id < MAX_NUM_LCGID) + && (UE_mac_inst[module_idP]. + scheduling_info.BSR_bytes[lcg_id]) + && + (UE_mac_inst[module_idP].logicalChannelConfig + [lcid]->ul_SpecificParameters->priority <= + highest_priority)) { + highest_priority = + UE_mac_inst[module_idP]. + logicalChannelConfig[lcid]-> + ul_SpecificParameters->priority; + lcg_id_bsr_trunc = lcg_id; + } + } + } + } else { + //Report SHORT BSR, clear bsr_t + bsr_t = NULL; + } + // Trigger BSR Padding + UE_mac_inst[module_idP].BSR_reporting_active |= + BSR_TRIGGER_PADDING; + } + bsr_len = bsr_header_len + bsr_ce_len; + } + //Fill BSR Infos + if (bsr_ce_len == 0) { + bsr_s = NULL; + bsr_l = NULL; + bsr_t = NULL; + } else if (bsr_ce_len == BSR_LONG_SIZE) { + bsr_s = NULL; + bsr_t = NULL; + bsr_l->Buffer_size0 = + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0]; + bsr_l->Buffer_size1 = + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]; + bsr_l->Buffer_size2 = + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]; + bsr_l->Buffer_size3 = + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]; - } else if (padding_len >= (1+sizeof(BSR_SHORT))) { - bsr_ce_len = sizeof(BSR_SHORT); - bsr_header_len = 1; + LOG_D(MAC, + "[UE %d] Frame %d subframe %d BSR Trig=%d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", + module_idP, frameP, subframe, + UE_mac_inst[module_idP].BSR_reporting_active, + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0], + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2], + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]); - if (num_lcg_id_with_data > 1) - { - // REPORT TRUNCATED BSR - //Get LCGID of highest priority LCID with data - for (lcid=DCCH; lcid < MAX_NUM_LCID ; lcid++) { - if (UE_mac_inst[module_idP].logicalChannelConfig[lcid] != NULL) { - lcg_id = UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]; + } else if (bsr_ce_len == sizeof(BSR_SHORT)) { + bsr_l = NULL; + if ((bsr_t != NULL) + && (UE_mac_inst[module_idP].BSR_reporting_active & + BSR_TRIGGER_PADDING)) { + //Truncated BSR + bsr_s = NULL; + bsr_t->LCGID = lcg_id_bsr_trunc; + bsr_t->Buffer_size = + UE_mac_inst[module_idP].scheduling_info. + BSR[lcg_id_bsr_trunc]; - if ((lcg_id < MAX_NUM_LCGID) && (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]) - && (UE_mac_inst[module_idP].logicalChannelConfig[lcid]->ul_SpecificParameters->priority <= highest_priority)) { - highest_priority = UE_mac_inst[module_idP].logicalChannelConfig[lcid]->ul_SpecificParameters->priority; - lcg_id_bsr_trunc = lcg_id; - } - } - } - } - else - { - //Report SHORT BSR, clear bsr_t - bsr_t = NULL; - } + LOG_D(MAC, + "[UE %d] Frame %d subframe %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n", + module_idP, frameP, subframe, + UE_mac_inst[module_idP].BSR_reporting_active, + UE_mac_inst[module_idP]. + scheduling_info.BSR[lcg_id_bsr_trunc], lcg_id_bsr_trunc); - // Trigger BSR Padding - UE_mac_inst[module_idP].BSR_reporting_active |= BSR_TRIGGER_PADDING; - } - bsr_len = bsr_header_len + bsr_ce_len; - } - - //Fill BSR Infos - if (bsr_ce_len == 0 ) { - bsr_s = NULL; - bsr_l = NULL; - bsr_t = NULL; - } else if (bsr_ce_len == BSR_LONG_SIZE) { - bsr_s = NULL; - bsr_t = NULL; - bsr_l->Buffer_size0 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0]; - bsr_l->Buffer_size1 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]; - bsr_l->Buffer_size2 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]; - bsr_l->Buffer_size3 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]; - - LOG_D(MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP,subframe, - UE_mac_inst[module_idP].BSR_reporting_active, - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0], - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2], - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]); - - } else if (bsr_ce_len == sizeof(BSR_SHORT)) { - bsr_l = NULL; - if ((bsr_t != NULL) && (UE_mac_inst[module_idP].BSR_reporting_active & BSR_TRIGGER_PADDING)) { - //Truncated BSR - bsr_s = NULL; - bsr_t->LCGID = lcg_id_bsr_trunc; - bsr_t->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc]; - - LOG_D(MAC,"[UE %d] Frame %d subframe %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n", - module_idP, frameP, subframe, UE_mac_inst[module_idP].BSR_reporting_active, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc],lcg_id_bsr_trunc); - - } - else - { - bsr_t = NULL; - bsr_s->LCGID = lcg_id_bsr_trunc; - bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc]; - - LOG_D(MAC,"[UE %d] Frame %d subframe %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n", - module_idP, frameP, subframe, UE_mac_inst[module_idP].BSR_reporting_active, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc],lcg_id_bsr_trunc); - } - } + } else { + bsr_t = NULL; + bsr_s->LCGID = lcg_id_bsr_trunc; + bsr_s->Buffer_size = + UE_mac_inst[module_idP].scheduling_info. + BSR[lcg_id_bsr_trunc]; + LOG_D(MAC, + "[UE %d] Frame %d subframe %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n", + module_idP, frameP, subframe, + UE_mac_inst[module_idP].BSR_reporting_active, + UE_mac_inst[module_idP]. + scheduling_info.BSR[lcg_id_bsr_trunc], lcg_id_bsr_trunc); + } + } // 1-bit padding or 2-bit padding special padding subheader // Check for max padding size, ie MAC Hdr for last RLC PDU = 1 - if (sdu_length_total) { - padding_len = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len - rlc_pdu_header_len_last + sdu_length_total + 1); - } - else { - padding_len = buflen - (bsr_len + phr_len); - } - - if (padding_len <= 2) { - short_padding = padding_len; - // only add padding header - post_padding = 0; - //update total MAC Hdr size for RLC data if (sdu_length_total) { - total_rlc_pdu_header_len = total_rlc_pdu_header_len - rlc_pdu_header_len_last + 1; - rlc_pdu_header_len_last = 1; - } - } - else if (sdu_length_total) { - post_padding = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); - // If by adding MAC Hdr for last RLC PDU the padding is 0 then set MAC Hdr for last RLC PDU = 1 and compute 1 or 2 byte padding - if (post_padding == 0) { - total_rlc_pdu_header_len -= rlc_pdu_header_len_last; - padding_len = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); - short_padding = padding_len; - total_rlc_pdu_header_len ++; - } - } - else { - if (padding_len == buflen) {// nona mac pdu - *access_mode=CANCELED_ACCESS; + padding_len = + buflen - (bsr_len + phr_len + total_rlc_pdu_header_len - + rlc_pdu_header_len_last + sdu_length_total + 1); + } else { + padding_len = buflen - (bsr_len + phr_len); } - short_padding = 0; + if (padding_len <= 2) { + short_padding = padding_len; + // only add padding header + post_padding = 0; + //update total MAC Hdr size for RLC data + if (sdu_length_total) { + total_rlc_pdu_header_len = + total_rlc_pdu_header_len - rlc_pdu_header_len_last + 1; + rlc_pdu_header_len_last = 1; + } + } else if (sdu_length_total) { + post_padding = + buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + + sdu_length_total + 1); + // If by adding MAC Hdr for last RLC PDU the padding is 0 then set MAC Hdr for last RLC PDU = 1 and compute 1 or 2 byte padding + if (post_padding == 0) { + total_rlc_pdu_header_len -= rlc_pdu_header_len_last; + padding_len = + buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + + sdu_length_total + 1); + short_padding = padding_len; + total_rlc_pdu_header_len++; + } + } else { + if (padding_len == buflen) { // nona mac pdu + *access_mode = CANCELED_ACCESS; + } - post_padding = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); - } + short_padding = 0; - // Generate header - // if (num_sdus>0) { + post_padding = + buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + + sdu_length_total + 1); + } - payload_offset = generate_ulsch_header(ulsch_buffer, // mac header - num_sdus, // num sdus - short_padding, // short pading - sdu_lengths, // sdu length - sdu_lcids, // sdu lcid - phr_p, // power headroom - NULL, // crnti - bsr_t, // truncated bsr - bsr_s, // short bsr - bsr_l, - post_padding); // long_bsr + // Generate header + // if (num_sdus>0) { - LOG_D(MAC, - "[UE %d] Generate header :bufflen %d sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d, total_rlc_pdu_header_len %d, padding %d,post_padding %d, bsr len %d, phr len %d, reminder %d \n", - module_idP,buflen, sdu_length_total,num_sdus,sdu_lengths[0],sdu_lcids[0],payload_offset, total_rlc_pdu_header_len, - short_padding,post_padding, bsr_len, phr_len,buflen-sdu_length_total-payload_offset); - // cycle through SDUs and place in ulsch_buffer - if (sdu_length_total) { - memcpy(&ulsch_buffer[payload_offset],ulsch_buff,sdu_length_total); - } + payload_offset = generate_ulsch_header(ulsch_buffer, // mac header + num_sdus, // num sdus + short_padding, // short pading + sdu_lengths, // sdu length + sdu_lcids, // sdu lcid + phr_p, // power headroom + NULL, // crnti + bsr_t, // truncated bsr + bsr_s, // short bsr + bsr_l, post_padding); // long_bsr - // fill remainder of DLSCH with random data - if (post_padding) { - for (j=0; j<(buflen-sdu_length_total-payload_offset); j++) { - ulsch_buffer[payload_offset+sdu_length_total+j] = (char)(taus()&0xff); - } - } - LOG_D(MAC,"[UE %d][SR] Gave SDU to PHY, clearing any scheduling request\n", module_idP); - UE_mac_inst[module_idP].scheduling_info.SR_pending=0; - UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; + LOG_D(MAC, + "[UE %d] Generate header :bufflen %d sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d, total_rlc_pdu_header_len %d, padding %d,post_padding %d, bsr len %d, phr len %d, reminder %d \n", + module_idP, buflen, sdu_length_total, num_sdus, sdu_lengths[0], + sdu_lcids[0], payload_offset, total_rlc_pdu_header_len, + short_padding, post_padding, bsr_len, phr_len, + buflen - sdu_length_total - payload_offset); + // cycle through SDUs and place in ulsch_buffer + if (sdu_length_total) { + memcpy(&ulsch_buffer[payload_offset], ulsch_buff, + sdu_length_total); + } + // fill remainder of DLSCH with random data + if (post_padding) { + for (j = 0; j < (buflen - sdu_length_total - payload_offset); j++) { + ulsch_buffer[payload_offset + sdu_length_total + j] = + (char) (taus() & 0xff); + } + } + LOG_D(MAC, + "[UE %d][SR] Gave SDU to PHY, clearing any scheduling request\n", + module_idP); + UE_mac_inst[module_idP].scheduling_info.SR_pending = 0; + UE_mac_inst[module_idP].scheduling_info.SR_COUNTER = 0; - /* Actions when a BSR is sent */ - if (bsr_ce_len) - { - LOG_D(MAC,"[UE %d] MAC BSR Sent !! bsr (ce%d,hdr%d) buff_len %d\n", - module_idP, bsr_ce_len, bsr_header_len, buflen); + /* Actions when a BSR is sent */ + if (bsr_ce_len) { + LOG_D(MAC, + "[UE %d] MAC BSR Sent !! bsr (ce%d,hdr%d) buff_len %d\n", + module_idP, bsr_ce_len, bsr_header_len, buflen); - // Reset ReTx BSR Timer - UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); + // Reset ReTx BSR Timer + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = + get_sf_retxBSRTimer(UE_mac_inst[module_idP]. + scheduling_info.retxBSR_Timer); - LOG_D(MAC,"[UE %d] MAC ReTx BSR Timer Reset =%d\n", module_idP, - UE_mac_inst[module_idP].scheduling_info.retxBSR_SF); + LOG_D(MAC, "[UE %d] MAC ReTx BSR Timer Reset =%d\n", module_idP, + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF); - // Reset Periodic Timer except when BSR is truncated - if ((bsr_t == NULL) && (UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer != PeriodicBSR_Timer_r12_infinity)) - { - UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer); + // Reset Periodic Timer except when BSR is truncated + if ((bsr_t == NULL) + && (UE_mac_inst[module_idP].scheduling_info. + periodicBSR_Timer != PeriodicBSR_Timer_r12_infinity)) { + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = + get_sf_periodicBSRTimer(UE_mac_inst + [module_idP].scheduling_info. + periodicBSR_Timer); - LOG_D(MAC,"[UE %d] MAC Periodic BSR Timer Reset =%d\n", - module_idP, UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF); + LOG_D(MAC, "[UE %d] MAC Periodic BSR Timer Reset =%d\n", + module_idP, + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF); - } + } + // Reset BSR Trigger flags + UE_mac_inst[module_idP].BSR_reporting_active = BSR_TRIGGER_NONE; + } - // Reset BSR Trigger flags - UE_mac_inst[module_idP].BSR_reporting_active = BSR_TRIGGER_NONE; - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_OUT); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_OUT); #if UE_TIMING_TRACE - stop_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu); + stop_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu); #endif - - if (opt_enabled) { - trace_pdu(0, ulsch_buffer, buflen, module_idP, 3, UE_mac_inst[module_idP].crnti, UE_mac_inst[module_idP].txFrame, UE_mac_inst[module_idP].txSubframe, 0, 0); - LOG_D(OPT,"[UE %d][ULSCH] Frame %d subframe %d trace pdu for rnti %x with size %d\n", - module_idP, frameP, subframe, UE_mac_inst[module_idP].crnti, buflen); - } + + if (opt_enabled) { + trace_pdu(0, ulsch_buffer, buflen, module_idP, 3, + UE_mac_inst[module_idP].crnti, + UE_mac_inst[module_idP].txFrame, + UE_mac_inst[module_idP].txSubframe, 0, 0); + LOG_D(OPT, + "[UE %d][ULSCH] Frame %d subframe %d trace pdu for rnti %x with size %d\n", + module_idP, frameP, subframe, UE_mac_inst[module_idP].crnti, + buflen); + } } //------------------------------------------------------------------------------ @@ -1820,281 +2153,327 @@ for (lcid=DCCH; (lcid < MAX_NUM_LCID) && (is_all_lcid_processed == FALSE) ; lcid // 4. Perform PHR procedures UE_L2_STATE_t -ue_scheduler( - const module_id_t module_idP, - const frame_t rxFrameP, - const sub_frame_t rxSubframeP, - const frame_t txFrameP, - const sub_frame_t txSubframeP, - const lte_subframe_t directionP, - const uint8_t eNB_indexP, - const int CC_id) +ue_scheduler(const module_id_t module_idP, + const frame_t rxFrameP, + const sub_frame_t rxSubframeP, + const frame_t txFrameP, + const sub_frame_t txSubframeP, + const lte_subframe_t directionP, + const uint8_t eNB_indexP, const int CC_id) //------------------------------------------------------------------------------ { - int lcid; // lcid index - int TTI= 1; - int bucketsizeduration = -1; - int bucketsizeduration_max = -1; - // mac_rlc_status_resp_t rlc_status[MAX_NUM_LCGID]; // 4 - // int8_t lcg_id; - struct RACH_ConfigCommon *rach_ConfigCommon = (struct RACH_ConfigCommon *)NULL; - protocol_ctxt_t ctxt; + int lcid; // lcid index + int TTI = 1; + int bucketsizeduration = -1; + int bucketsizeduration_max = -1; + // mac_rlc_status_resp_t rlc_status[MAX_NUM_LCGID]; // 4 + // int8_t lcg_id; + struct RACH_ConfigCommon *rach_ConfigCommon = + (struct RACH_ConfigCommon *) NULL; + protocol_ctxt_t ctxt; #if defined(ENABLE_ITTI) - MessageDef *msg_p; - const char *msg_name; - instance_t instance; - int result; + MessageDef *msg_p; + const char *msg_name; + instance_t instance; + int result; #endif #if UE_TIMING_TRACE - start_meas(&UE_mac_inst[module_idP].ue_scheduler); + start_meas(&UE_mac_inst[module_idP].ue_scheduler); #endif - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_IN); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_IN); - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_NO, UE_mac_inst[module_idP].crnti, txFrameP, txSubframeP,eNB_indexP); + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_NO, + UE_mac_inst[module_idP].crnti, txFrameP, + txSubframeP, eNB_indexP); #if defined(ENABLE_ITTI) - do { - // Checks if a message has been sent to MAC sub-task - itti_poll_msg (TASK_MAC_UE, &msg_p); + do { + // Checks if a message has been sent to MAC sub-task + itti_poll_msg(TASK_MAC_UE, &msg_p); - if (msg_p != NULL) { - msg_name = ITTI_MSG_NAME (msg_p); - instance = ITTI_MSG_INSTANCE (msg_p); + if (msg_p != NULL) { + msg_name = ITTI_MSG_NAME(msg_p); + instance = ITTI_MSG_INSTANCE(msg_p); - switch (ITTI_MSG_ID(msg_p)) { - case RRC_MAC_CCCH_DATA_REQ: - LOG_I(MAC, "Received %s from %s: instance %d, frameP %d, eNB_index %d\n", - msg_name, ITTI_MSG_ORIGIN_NAME(msg_p), instance, - RRC_MAC_CCCH_DATA_REQ (msg_p).frame, RRC_MAC_CCCH_DATA_REQ (msg_p).enb_index); + switch (ITTI_MSG_ID(msg_p)) { + case RRC_MAC_CCCH_DATA_REQ: + LOG_I(MAC, + "Received %s from %s: instance %d, frameP %d, eNB_index %d\n", + msg_name, ITTI_MSG_ORIGIN_NAME(msg_p), instance, + RRC_MAC_CCCH_DATA_REQ(msg_p).frame, + RRC_MAC_CCCH_DATA_REQ(msg_p).enb_index); - // TODO process CCCH data req. - break; + // TODO process CCCH data req. + break; - default: - LOG_E(MAC, "Received unexpected message %s\n", msg_name); - break; - } + default: + LOG_E(MAC, "Received unexpected message %s\n", msg_name); + break; + } - result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); - AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + result = itti_free(ITTI_MSG_ORIGIN_ID(msg_p), msg_p); + AssertFatal(result == EXIT_SUCCESS, + "Failed to free memory (%d)!\n", result); + } } - } while(msg_p != NULL); + while (msg_p != NULL); #endif - //Mac_rlc_xface->frameP=frameP; - //Rrc_xface->Frame_index=Mac_rlc_xface->frameP; - //if (subframe%5 == 0) - //LG#ifdef EXMIMO - pdcp_run(&ctxt); - //#endif - UE_mac_inst[module_idP].txFrame = txFrameP; - UE_mac_inst[module_idP].txSubframe = txSubframeP; - UE_mac_inst[module_idP].rxFrame = rxFrameP; - UE_mac_inst[module_idP].rxSubframe = rxSubframeP; + //Mac_rlc_xface->frameP=frameP; + //Rrc_xface->Frame_index=Mac_rlc_xface->frameP; + //if (subframe%5 == 0) + //LG#ifdef EXMIMO + pdcp_run(&ctxt); + //#endif + UE_mac_inst[module_idP].txFrame = txFrameP; + UE_mac_inst[module_idP].txSubframe = txSubframeP; + UE_mac_inst[module_idP].rxFrame = rxFrameP; + UE_mac_inst[module_idP].rxSubframe = rxSubframeP; #ifdef CELLULAR - rrc_rx_tx(module_idP, txFrameP, 0, eNB_indexP); + rrc_rx_tx(module_idP, txFrameP, 0, eNB_indexP); #else - switch (rrc_rx_tx(&ctxt, - eNB_indexP, - CC_id)) { - case RRC_OK: - break; + switch (rrc_rx_tx(&ctxt, eNB_indexP, CC_id)) { + case RRC_OK: + break; - case RRC_ConnSetup_failed: - LOG_E(MAC,"RRCConnectionSetup failed, returning to IDLE state\n"); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT); + case RRC_ConnSetup_failed: + LOG_E(MAC, "RRCConnectionSetup failed, returning to IDLE state\n"); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT); +#if UE_TIMING_TRACE + stop_meas(&UE_mac_inst[module_idP].ue_scheduler); +#endif + return (CONNECTION_LOST); + break; + + case RRC_PHY_RESYNCH: + LOG_E(MAC, "RRC Loss of synch, returning PHY_RESYNCH\n"); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT); +#if UE_TIMING_TRACE + stop_meas(&UE_mac_inst[module_idP].ue_scheduler); +#endif + return (PHY_RESYNCH); + + case RRC_Handover_failed: + LOG_N(MAC, "Handover failure for UE %d eNB_index %d\n", module_idP, + eNB_indexP); + //Invalid...need to add another MAC UE state for re-connection procedure + phy_config_afterHO_ue(module_idP, 0, eNB_indexP, + (MobilityControlInfo_t *) NULL, 1); + //return(3); + break; + + case RRC_HO_STARTED: + LOG_I(MAC, + "RRC handover, Instruct PHY to start the contention-free PRACH and synchronization\n"); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT); +#if UE_TIMING_TRACE + stop_meas(&UE_mac_inst[module_idP].ue_scheduler); +#endif + return (PHY_HO_PRACH); + + default: + break; + } + +#endif + + // Check Contention resolution timer (put in a function later) + if (UE_mac_inst[module_idP].RA_contention_resolution_timer_active == 1) { + + if (UE_mac_inst[module_idP].radioResourceConfigCommon) { + rach_ConfigCommon = + &UE_mac_inst[module_idP]. + radioResourceConfigCommon->rach_ConfigCommon; + } else { + LOG_E(MAC, "FATAL: radioResourceConfigCommon is NULL!!!\n"); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, + VCD_FUNCTION_OUT); + + stop_meas(&UE_mac_inst[module_idP].ue_scheduler); + AssertFatal(1 == 0, ""); + +#if UE_TIMING_TRACE + stop_meas(&UE_mac_inst[module_idP].ue_scheduler); +#endif + //return(RRC_OK); + } + + LOG_I(MAC, "Frame %d: Contention resolution timer %d/%ld\n", + txFrameP, + UE_mac_inst[module_idP].RA_contention_resolution_cnt, + ((1 + + rach_ConfigCommon-> + ra_SupervisionInfo.mac_ContentionResolutionTimer) << 3)); + + UE_mac_inst[module_idP].RA_contention_resolution_cnt++; + + if (UE_mac_inst[module_idP].RA_contention_resolution_cnt == + ((1 + + rach_ConfigCommon-> + ra_SupervisionInfo.mac_ContentionResolutionTimer) << 3)) { + UE_mac_inst[module_idP].RA_active = 0; + UE_mac_inst[module_idP].RA_contention_resolution_timer_active = + 0; + // Signal PHY to quit RA procedure + LOG_E(MAC, + "Module id %u Contention resolution timer expired, RA failed\n", + module_idP); + ra_failed(module_idP, 0, eNB_indexP); + } + } + // Get RLC status info and update Bj for all lcids that are active + for (lcid = DCCH; lcid < MAX_NUM_LCID; lcid++) { + if (UE_mac_inst[module_idP].logicalChannelConfig[lcid]) { + // meausre the Bj + if ((directionP == SF_UL) + && (UE_mac_inst[module_idP].scheduling_info.Bj[lcid] >= 0)) { + if (UE_mac_inst[module_idP]. + logicalChannelConfig[lcid]->ul_SpecificParameters) { + bucketsizeduration = + UE_mac_inst[module_idP].logicalChannelConfig + [lcid]->ul_SpecificParameters->prioritisedBitRate * + TTI; + bucketsizeduration_max = + get_ms_bucketsizeduration(UE_mac_inst + [module_idP].logicalChannelConfig + [lcid]->ul_SpecificParameters->bucketSizeDuration); + } else { + LOG_E(MAC, + "[UE %d] lcid %d, NULL ul_SpecificParameters\n", + module_idP, lcid); + AssertFatal(1 == 0, ""); + } + + if (UE_mac_inst[module_idP].scheduling_info.Bj[lcid] > + bucketsizeduration_max) { + UE_mac_inst[module_idP].scheduling_info.Bj[lcid] = + bucketsizeduration_max; + } else { + UE_mac_inst[module_idP].scheduling_info.Bj[lcid] = + bucketsizeduration; + } + } + + + /* + if (lcid == DCCH) { + LOG_D(MAC,"[UE %d][SR] Frame %d subframe %d Pending data for SRB1=%d for LCGID %d \n", + module_idP, txFrameP,txSubframeP,UE_mac_inst[module_idP].scheduling_info.BSR[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], + // UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]); + } + */ + } + } + + // Call BSR procedure as described in Section 5.4.5 in 36.321 + + // First check ReTxBSR Timer because it is always configured + // Decrement ReTxBSR Timer if it is running and not null + if ((UE_mac_inst[module_idP].scheduling_info.retxBSR_SF != + MAC_UE_BSR_TIMER_NOT_RUNNING) + && (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF != 0)) { + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF--; + } + // Decrement Periodic Timer if it is running and not null + if ((UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF != + MAC_UE_BSR_TIMER_NOT_RUNNING) + && (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF != 0)) { + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF--; + } + //Check whether Regular BSR is triggered + if (update_bsr(module_idP, txFrameP, txSubframeP, eNB_indexP) == TRUE) { + // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures + // outlined in Sections 5.4.4 an 5.4.5 of 36.321 + UE_mac_inst[module_idP].scheduling_info.SR_pending = 1; + // Regular BSR trigger + UE_mac_inst[module_idP].BSR_reporting_active |= + BSR_TRIGGER_REGULAR; + LOG_D(MAC, + "[UE %d][BSR] Regular BSR Triggered Frame %d subframe %d SR for PUSCH is pending\n", + module_idP, txFrameP, txSubframeP); + } + // UE has no valid phy config dedicated || no valid/released SR + if ((UE_mac_inst[module_idP].physicalConfigDedicated == NULL)) { + // cancel all pending SRs + UE_mac_inst[module_idP].scheduling_info.SR_pending = 0; + UE_mac_inst[module_idP].ul_active = 0; + LOG_T(MAC, "[UE %d] Release all SRs \n", module_idP); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT); +#if UE_TIMING_TRACE + stop_meas(&UE_mac_inst[module_idP].ue_scheduler); +#endif + return (CONNECTION_OK); + } + + if ((UE_mac_inst[module_idP]. + physicalConfigDedicated->schedulingRequestConfig == NULL) + || (UE_mac_inst[module_idP]. + physicalConfigDedicated->schedulingRequestConfig->present == + SchedulingRequestConfig_PR_release)) { + + // initiate RA with CRNTI included in msg3 (no contention) as descibed in 36.321 sec 5.1.5 + + // cancel all pending SRs + UE_mac_inst[module_idP].scheduling_info.SR_pending = 0; + UE_mac_inst[module_idP].ul_active = 0; + LOG_T(MAC, "[UE %d] Release all SRs \n", module_idP); + } + // Put this in a function + // Call PHR procedure as described in Section 5.4.6 in 36.321 + if (UE_mac_inst[module_idP].PHR_state == MAC_MainConfig__phr_Config_PR_setup) { // normal operation + + if (UE_mac_inst[module_idP].PHR_reconfigured == 1) { // upon (re)configuration of the power headroom reporting functionality by upper layers + UE_mac_inst[module_idP].PHR_reporting_active = 1; + UE_mac_inst[module_idP].PHR_reconfigured = 0; + } else { + //LOG_D(MAC,"PHR normal operation %d active %d \n", UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF, UE_mac_inst[module_idP].PHR_reporting_active); + if ((UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF <= + 0) + && + ((get_PL(module_idP, 0, eNB_indexP) < + UE_mac_inst[module_idP].scheduling_info. + PathlossChange_db) + || (UE_mac_inst[module_idP].power_backoff_db[eNB_indexP] > + UE_mac_inst[module_idP]. + scheduling_info.PathlossChange_db))) + // trigger PHR and reset the timer later when the PHR report is sent + { + UE_mac_inst[module_idP].PHR_reporting_active = 1; + } else if (UE_mac_inst[module_idP].PHR_reporting_active == 0) { + UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF--; + } + + if (UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF <= + 0) + // trigger PHR and reset the timer later when the PHR report is sent + { + UE_mac_inst[module_idP].PHR_reporting_active = 1; + } else if (UE_mac_inst[module_idP].PHR_reporting_active == 0) { + UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF--; + } + } + } else { // release / nothing + UE_mac_inst[module_idP].PHR_reporting_active = 0; // release PHR + } + + //If the UE has UL resources allocated for new transmission for this TTI here: + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT); #if UE_TIMING_TRACE stop_meas(&UE_mac_inst[module_idP].ue_scheduler); #endif - return(CONNECTION_LOST); - break; - - case RRC_PHY_RESYNCH: - LOG_E(MAC,"RRC Loss of synch, returning PHY_RESYNCH\n"); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT); -#if UE_TIMING_TRACE - stop_meas(&UE_mac_inst[module_idP].ue_scheduler); -#endif - return(PHY_RESYNCH); - - case RRC_Handover_failed: - LOG_N(MAC,"Handover failure for UE %d eNB_index %d\n",module_idP,eNB_indexP); - //Invalid...need to add another MAC UE state for re-connection procedure - phy_config_afterHO_ue(module_idP,0,eNB_indexP,(MobilityControlInfo_t *)NULL,1); - //return(3); - break; - - case RRC_HO_STARTED: - LOG_I(MAC,"RRC handover, Instruct PHY to start the contention-free PRACH and synchronization\n"); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT); -#if UE_TIMING_TRACE - stop_meas(&UE_mac_inst[module_idP].ue_scheduler); -#endif - return(PHY_HO_PRACH); - - default: - break; - } - -#endif - - // Check Contention resolution timer (put in a function later) - if (UE_mac_inst[module_idP].RA_contention_resolution_timer_active == 1) { - - if (UE_mac_inst[module_idP].radioResourceConfigCommon) { - rach_ConfigCommon = &UE_mac_inst[module_idP].radioResourceConfigCommon->rach_ConfigCommon; - } else { - LOG_E(MAC,"FATAL: radioResourceConfigCommon is NULL!!!\n"); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT); - - stop_meas(&UE_mac_inst[module_idP].ue_scheduler); - AssertFatal(1==0,""); - -#if UE_TIMING_TRACE - stop_meas(&UE_mac_inst[module_idP].ue_scheduler); -#endif - //return(RRC_OK); - } - - LOG_I(MAC,"Frame %d: Contention resolution timer %d/%ld\n",txFrameP,UE_mac_inst[module_idP].RA_contention_resolution_cnt, - ((1+rach_ConfigCommon->ra_SupervisionInfo.mac_ContentionResolutionTimer)<<3)); - - UE_mac_inst[module_idP].RA_contention_resolution_cnt++; - - if (UE_mac_inst[module_idP].RA_contention_resolution_cnt == - ((1+rach_ConfigCommon->ra_SupervisionInfo.mac_ContentionResolutionTimer)<<3)) { - UE_mac_inst[module_idP].RA_active = 0; - UE_mac_inst[module_idP].RA_contention_resolution_timer_active = 0; - // Signal PHY to quit RA procedure - LOG_E(MAC,"Module id %u Contention resolution timer expired, RA failed\n", module_idP); - ra_failed(module_idP,0,eNB_indexP); - } - } - - - // Get RLC status info and update Bj for all lcids that are active - for (lcid=DCCH; lcid < MAX_NUM_LCID; lcid++ ) { - if (UE_mac_inst[module_idP].logicalChannelConfig[lcid]) { - // meausre the Bj - if ((directionP == SF_UL)&& (UE_mac_inst[module_idP].scheduling_info.Bj[lcid] >= 0)) { - if (UE_mac_inst[module_idP].logicalChannelConfig[lcid]->ul_SpecificParameters) { - bucketsizeduration = UE_mac_inst[module_idP].logicalChannelConfig[lcid]->ul_SpecificParameters->prioritisedBitRate * TTI; - bucketsizeduration_max = get_ms_bucketsizeduration(UE_mac_inst[module_idP].logicalChannelConfig[lcid]->ul_SpecificParameters->bucketSizeDuration); - } else { - LOG_E(MAC,"[UE %d] lcid %d, NULL ul_SpecificParameters\n",module_idP,lcid); - AssertFatal(1==0,""); - } - - if ( UE_mac_inst[module_idP].scheduling_info.Bj[lcid] > bucketsizeduration_max ) { - UE_mac_inst[module_idP].scheduling_info.Bj[lcid] = bucketsizeduration_max; - } else { - UE_mac_inst[module_idP].scheduling_info.Bj[lcid] = bucketsizeduration; - } - } - - - /* - if (lcid == DCCH) { - LOG_D(MAC,"[UE %d][SR] Frame %d subframe %d Pending data for SRB1=%d for LCGID %d \n", - module_idP, txFrameP,txSubframeP,UE_mac_inst[module_idP].scheduling_info.BSR[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], -// UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]); - } - */ - } - } - - // Call BSR procedure as described in Section 5.4.5 in 36.321 - - // First check ReTxBSR Timer because it is always configured - // Decrement ReTxBSR Timer if it is running and not null - if ((UE_mac_inst[module_idP].scheduling_info.retxBSR_SF != MAC_UE_BSR_TIMER_NOT_RUNNING) - && (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF != 0)){ - UE_mac_inst[module_idP].scheduling_info.retxBSR_SF --; - } - - // Decrement Periodic Timer if it is running and not null - if ((UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF != MAC_UE_BSR_TIMER_NOT_RUNNING) - && (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF != 0)){ - UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF--; - } - - //Check whether Regular BSR is triggered - if (update_bsr(module_idP,txFrameP, txSubframeP,eNB_indexP) == TRUE) { - // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures - // outlined in Sections 5.4.4 an 5.4.5 of 36.321 - UE_mac_inst[module_idP].scheduling_info.SR_pending= 1; - // Regular BSR trigger - UE_mac_inst[module_idP].BSR_reporting_active |= BSR_TRIGGER_REGULAR; - LOG_D(MAC,"[UE %d][BSR] Regular BSR Triggered Frame %d subframe %d SR for PUSCH is pending\n", - module_idP, txFrameP,txSubframeP); - } - - // UE has no valid phy config dedicated || no valid/released SR - if ((UE_mac_inst[module_idP].physicalConfigDedicated == NULL)) { - // cancel all pending SRs - UE_mac_inst[module_idP].scheduling_info.SR_pending=0; - UE_mac_inst[module_idP].ul_active=0; - LOG_T(MAC,"[UE %d] Release all SRs \n", module_idP); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT); -#if UE_TIMING_TRACE - stop_meas(&UE_mac_inst[module_idP].ue_scheduler); -#endif - return(CONNECTION_OK); - } - - if ((UE_mac_inst[module_idP].physicalConfigDedicated->schedulingRequestConfig == NULL) || - (UE_mac_inst[module_idP].physicalConfigDedicated->schedulingRequestConfig->present == SchedulingRequestConfig_PR_release)) { - - // initiate RA with CRNTI included in msg3 (no contention) as descibed in 36.321 sec 5.1.5 - - // cancel all pending SRs - UE_mac_inst[module_idP].scheduling_info.SR_pending=0; - UE_mac_inst[module_idP].ul_active=0; - LOG_T(MAC,"[UE %d] Release all SRs \n", module_idP); - } - - // Put this in a function - // Call PHR procedure as described in Section 5.4.6 in 36.321 - if (UE_mac_inst[module_idP].PHR_state == MAC_MainConfig__phr_Config_PR_setup) { // normal operation - - if (UE_mac_inst[module_idP].PHR_reconfigured == 1) { // upon (re)configuration of the power headroom reporting functionality by upper layers - UE_mac_inst[module_idP].PHR_reporting_active = 1; - UE_mac_inst[module_idP].PHR_reconfigured = 0; - } else { - //LOG_D(MAC,"PHR normal operation %d active %d \n", UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF, UE_mac_inst[module_idP].PHR_reporting_active); - if ((UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF <= 0) && - ((get_PL(module_idP,0,eNB_indexP) < UE_mac_inst[module_idP].scheduling_info.PathlossChange_db) || - (UE_mac_inst[module_idP].power_backoff_db[eNB_indexP] > UE_mac_inst[module_idP].scheduling_info.PathlossChange_db))) - // trigger PHR and reset the timer later when the PHR report is sent - { - UE_mac_inst[module_idP].PHR_reporting_active = 1; - } else if (UE_mac_inst[module_idP].PHR_reporting_active ==0 ) { - UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF--; - } - - if (UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF <= 0 ) - // trigger PHR and reset the timer later when the PHR report is sent - { - UE_mac_inst[module_idP].PHR_reporting_active = 1; - } else if (UE_mac_inst[module_idP].PHR_reporting_active == 0 ) { - UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF--; - } - } - } else { // release / nothing - UE_mac_inst[module_idP].PHR_reporting_active = 0; // release PHR - } - - //If the UE has UL resources allocated for new transmission for this TTI here: - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SCHEDULER, VCD_FUNCTION_OUT); -#if UE_TIMING_TRACE - stop_meas(&UE_mac_inst[module_idP].ue_scheduler); -#endif - return(CONNECTION_OK); + return (CONNECTION_OK); } // to be improved @@ -2102,522 +2481,564 @@ ue_scheduler( extern int cba_backoff; double uniform_rngen(int min, int max) { - double random = (double)taus()/((double)0xffffffff); - return (max - min) * random + min; + double random = (double) taus() / ((double) 0xffffffff); + return (max - min) * random + min; } -int cba_access(module_id_t module_idP,frame_t frameP,sub_frame_t subframe, uint8_t eNB_index,uint16_t buflen) +int +cba_access(module_id_t module_idP, frame_t frameP, + sub_frame_t subframe, uint8_t eNB_index, uint16_t buflen) { - mac_rlc_status_resp_t rlc_status; - int header_offset=4; - int rv =0; + mac_rlc_status_resp_t rlc_status; + int header_offset = 4; + int rv = 0; - /* - if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]<64)) || - ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]<64)) || - ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]<64)) ) - // && (UE_mac_inst[module_idP].ul_active == 0) // check if the ul is acrtive - && (UE_mac_inst[module_idP].cba_last_access[0] <= 0) ) { // backoff - // LOG_D(MAC,"[UE %d] Frame %d Subframe %d: the current CBA backoff is %d \n", module_idP, frameP, subframe, - // UE_mac_inst[module_idP].cba_last_access[0] ); + /* + if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]<64)) || + ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]<64)) || + ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]<64)) ) + // && (UE_mac_inst[module_idP].ul_active == 0) // check if the ul is acrtive + && (UE_mac_inst[module_idP].cba_last_access[0] <= 0) ) { // backoff + // LOG_D(MAC,"[UE %d] Frame %d Subframe %d: the current CBA backoff is %d \n", module_idP, frameP, subframe, + // UE_mac_inst[module_idP].cba_last_access[0] ); - UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,40)); - LOG_D(MAC,"[UE %d] Frame %d Subframe %d: start a new CBA backoff %d UL active state %d \n", module_idP, frameP, subframe, - UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active); + UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,40)); + LOG_D(MAC,"[UE %d] Frame %d Subframe %d: start a new CBA backoff %d UL active state %d \n", module_idP, frameP, subframe, + UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active); - rv=1; - } else if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]> 0 )) || - ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]> 0 )) || - ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]> 0 )) ) - // && (UE_mac_inst[module_idP].ul_active == 0) // check if the ul is acrtive - && (UE_mac_inst[module_idP].cba_last_access[0]> 0) ){ + rv=1; + } else if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]> 0 )) || + ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]> 0 )) || + ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]> 0 )) ) + // && (UE_mac_inst[module_idP].ul_active == 0) // check if the ul is acrtive + && (UE_mac_inst[module_idP].cba_last_access[0]> 0) ){ - UE_mac_inst[module_idP].cba_last_access[0]-=1; - LOG_D(MAC,"[UE %d] Frame %d Subframe %d: CBA backoff is decreased by one to %d UL active state %d \n", - module_idP, frameP, subframe, - UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active); + UE_mac_inst[module_idP].cba_last_access[0]-=1; + LOG_D(MAC,"[UE %d] Frame %d Subframe %d: CBA backoff is decreased by one to %d UL active state %d \n", + module_idP, frameP, subframe, + UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active); - } else if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1] == 0 )) && - ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2] == 0 )) && - ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3] == 0 )) ) - && (UE_mac_inst[module_idP].cba_last_access[0]> 0) ){ - UE_mac_inst[module_idP].cba_last_access[0]-=1; - }*/ + } else if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1] == 0 )) && + ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2] == 0 )) && + ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3] == 0 )) ) + && (UE_mac_inst[module_idP].cba_last_access[0]> 0) ){ + UE_mac_inst[module_idP].cba_last_access[0]-=1; + } */ - if ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0]<64) ) { - return 0; - } - - if ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1] <= 0 ) && - (UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2] <= 0 ) && - (UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3] <= 0 ) ) { - return 0; - } - - if (cba_backoff == 0 ) { // apply probablisitc method - UE_mac_inst[module_idP].cba_last_access[0]= uniform_rngen(0,1); - - if (uniform_rngen(0,1) > 0.6 ) { - LOG_I(MAC,"[UE %d] Frame %d Subframe %d: CBA probability-based backoff (%d), UL active state %d \n", module_idP, frameP, subframe, - cba_backoff,UE_mac_inst[module_idP].ul_active); - - rv=1; + if ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0] > 0) + && (UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0] < 64)) { + return 0; } - } else { - if (UE_mac_inst[module_idP].cba_last_access[0] <= 0) { - UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,cba_backoff)); + if ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1] <= 0) && + (UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2] <= 0) && + (UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3] <= 0)) { + return 0; + } - LOG_I(MAC,"[UE %d] Frame %d Subframe %d: start a new CBA backoff %d/%d UL active state %d \n", module_idP, frameP, subframe, - UE_mac_inst[module_idP].cba_last_access[0], cba_backoff,UE_mac_inst[module_idP].ul_active); + if (cba_backoff == 0) { // apply probablisitc method + UE_mac_inst[module_idP].cba_last_access[0] = uniform_rngen(0, 1); - rv = 1; - /* - rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,frameP,ENB_FLAG_NO,MBMS_FLAG_NO, // eNB_index - DTCH, - 0); + if (uniform_rngen(0, 1) > 0.6) { + LOG_I(MAC, + "[UE %d] Frame %d Subframe %d: CBA probability-based backoff (%d), UL active state %d \n", + module_idP, frameP, subframe, cba_backoff, + UE_mac_inst[module_idP].ul_active); - if (( - // (rlc_status.pdus_in_buffer > 0 ) && - // (UE_mac_inst[module_idP].ul_active == 0) && // check if the ul is acrtive - (rlc_status.head_sdu_is_segmented == 0 ) && - ((rlc_status.head_sdu_remaining_size_to_send + header_offset ) <= buflen ) - )){ - rv = 1; - - UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,30)); - LOG_D(MAC,"[UE %d] Frame %d Subframe %d: start a new CBA backoff %d UL active state %d \n", module_idP, frameP, subframe, - UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active); - */ + rv = 1; + } } else { - UE_mac_inst[module_idP].cba_last_access[0]-=1; - LOG_D(MAC,"[UE %d] Frame %d Subframe %d: wait for backoff to expire (%d) CBA UL active state %d \n", - module_idP, frameP, subframe, - UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active); + + if (UE_mac_inst[module_idP].cba_last_access[0] <= 0) { + UE_mac_inst[module_idP].cba_last_access[0] = + round(uniform_rngen(1, cba_backoff)); + + LOG_I(MAC, + "[UE %d] Frame %d Subframe %d: start a new CBA backoff %d/%d UL active state %d \n", + module_idP, frameP, subframe, + UE_mac_inst[module_idP].cba_last_access[0], cba_backoff, + UE_mac_inst[module_idP].ul_active); + + rv = 1; + /* + rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,frameP,ENB_FLAG_NO,MBMS_FLAG_NO, // eNB_index + DTCH, + 0); + + if (( + // (rlc_status.pdus_in_buffer > 0 ) && + // (UE_mac_inst[module_idP].ul_active == 0) && // check if the ul is acrtive + (rlc_status.head_sdu_is_segmented == 0 ) && + ((rlc_status.head_sdu_remaining_size_to_send + header_offset ) <= buflen ) + )){ + rv = 1; + + UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,30)); + LOG_D(MAC,"[UE %d] Frame %d Subframe %d: start a new CBA backoff %d UL active state %d \n", module_idP, frameP, subframe, + UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active); + */ + } else { + UE_mac_inst[module_idP].cba_last_access[0] -= 1; + LOG_D(MAC, + "[UE %d] Frame %d Subframe %d: wait for backoff to expire (%d) CBA UL active state %d \n", + module_idP, frameP, subframe, + UE_mac_inst[module_idP].cba_last_access[0], + UE_mac_inst[module_idP].ul_active); + } } - } - return rv; - /* - if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]<64)) || - ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]<64)) || - ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]<64)) ) - // && (UE_mac_inst[module_idP].ul_active == 0) // check if the ul is acrtive - && (UE_mac_inst[module_idP].cba_last_access[0] <= 0) ) { + return rv; + /* + if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]<64)) || + ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]<64)) || + ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]>0)&&(UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]<64)) ) + // && (UE_mac_inst[module_idP].ul_active == 0) // check if the ul is acrtive + && (UE_mac_inst[module_idP].cba_last_access[0] <= 0) ) { - UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,cba_backoff)); + UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,cba_backoff)); - LOG_I(MAC,"[UE %d] Frame %d Subframe %d: start a new CBA backoff %d/%d UL active state %d \n", module_idP, frameP, subframe, - UE_mac_inst[module_idP].cba_last_access[0], cba_backoff,UE_mac_inst[module_idP].ul_active); + LOG_I(MAC,"[UE %d] Frame %d Subframe %d: start a new CBA backoff %d/%d UL active state %d \n", module_idP, frameP, subframe, + UE_mac_inst[module_idP].cba_last_access[0], cba_backoff,UE_mac_inst[module_idP].ul_active); - rv = 1; + rv = 1; - rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,frameP,ENB_FLAG_NO,MBMS_FLAG_NO, // eNB_index - DTCH, - 0); + rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,frameP,ENB_FLAG_NO,MBMS_FLAG_NO, // eNB_index + DTCH, + 0); - if (( - // (rlc_status.pdus_in_buffer > 0 ) && - // (UE_mac_inst[module_idP].ul_active == 0) && // check if the ul is acrtive - (rlc_status.head_sdu_is_segmented == 0 ) && - ((rlc_status.head_sdu_remaining_size_to_send + header_offset ) <= buflen ) - )){ - rv = 1; + if (( + // (rlc_status.pdus_in_buffer > 0 ) && + // (UE_mac_inst[module_idP].ul_active == 0) && // check if the ul is acrtive + (rlc_status.head_sdu_is_segmented == 0 ) && + ((rlc_status.head_sdu_remaining_size_to_send + header_offset ) <= buflen ) + )){ + rv = 1; - UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,30)); - LOG_D(MAC,"[UE %d] Frame %d Subframe %d: start a new CBA backoff %d UL active state %d \n", module_idP, frameP, subframe, - UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active); - } else - UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,5)); + UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,30)); + LOG_D(MAC,"[UE %d] Frame %d Subframe %d: start a new CBA backoff %d UL active state %d \n", module_idP, frameP, subframe, + UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active); + } else + UE_mac_inst[module_idP].cba_last_access[0]= round(uniform_rngen(1,5)); - } else if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]> 0 )) || - ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]> 0 )) || - ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]> 0 )) ) - // && (UE_mac_inst[module_idP].ul_active == 0) // check if the ul is acrtive - && (UE_mac_inst[module_idP].cba_last_access[0]> 0) ) - { + } else if (( ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]> 0 )) || + ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]> 0 )) || + ((UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]> 0 )) ) + // && (UE_mac_inst[module_idP].ul_active == 0) // check if the ul is acrtive + && (UE_mac_inst[module_idP].cba_last_access[0]> 0) ) + { - UE_mac_inst[module_idP].cba_last_access[0]-=1; - LOG_D(MAC,"[UE %d] Frame %d Subframe %d: wait for backoff to expire (%d) CBA UL active state %d \n", - module_idP, frameP, subframe, - UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active); - } - } - */ + UE_mac_inst[module_idP].cba_last_access[0]-=1; + LOG_D(MAC,"[UE %d] Frame %d Subframe %d: wait for backoff to expire (%d) CBA UL active state %d \n", + module_idP, frameP, subframe, + UE_mac_inst[module_idP].cba_last_access[0], UE_mac_inst[module_idP].ul_active); + } + } + */ } #endif -boolean_t update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP,eNB_index_t eNB_index) +boolean_t +update_bsr(module_id_t module_idP, frame_t frameP, + sub_frame_t subframeP, eNB_index_t eNB_index) { - mac_rlc_status_resp_t rlc_status; - boolean_t bsr_regular_triggered = FALSE; - uint8_t lcid; - uint8_t lcgid; - uint8_t num_lcid_with_data = 0; // for LCID with data only if LCGID is defined - uint16_t lcgid_buffer_remain[MAX_NUM_LCGID] = {0,0,0,0}; - int32_t lcid_bytes_in_buffer[MAX_NUM_LCID]; - /* Array for ordering LCID with data per decreasing priority order */ - uint8_t lcid_reordered_array[MAX_NUM_LCID]= - {MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID}; - uint8_t pos_next = 0; - uint8_t highest_priority = 16; - uint8_t array_index = 0; + mac_rlc_status_resp_t rlc_status; + boolean_t bsr_regular_triggered = FALSE; + uint8_t lcid; + uint8_t lcgid; + uint8_t num_lcid_with_data = 0; // for LCID with data only if LCGID is defined + uint16_t lcgid_buffer_remain[MAX_NUM_LCGID] = { 0, 0, 0, 0 }; + int32_t lcid_bytes_in_buffer[MAX_NUM_LCID]; + /* Array for ordering LCID with data per decreasing priority order */ + uint8_t lcid_reordered_array[MAX_NUM_LCID] = + { MAX_NUM_LCID, MAX_NUM_LCID, MAX_NUM_LCID, MAX_NUM_LCID, + MAX_NUM_LCID, MAX_NUM_LCID, MAX_NUM_LCID, MAX_NUM_LCID, + MAX_NUM_LCID, + MAX_NUM_LCID, MAX_NUM_LCID + }; + uint8_t pos_next = 0; + uint8_t highest_priority = 16; + uint8_t array_index = 0; - // Reset All BSR Infos - lcid_bytes_in_buffer[0] = 0; - for (lcid=DCCH; lcid < MAX_NUM_LCID; lcid++) - { - // Reset transmission status - lcid_bytes_in_buffer[lcid] = 0; - UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid]=LCID_EMPTY; - } - - for (lcgid=0; lcgid < MAX_NUM_LCGID; lcgid++) - { - // Reset Buffer Info - UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]=0; - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid]=0; - } - - //Get Buffer Occupancy and fill lcid_reordered_array - for (lcid=DCCH; lcid < MAX_NUM_LCID; lcid++) - { - if (UE_mac_inst[module_idP].logicalChannelConfig[lcid]) - { - lcgid = UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]; - - // Store already available data to transmit per Group - if (lcgid < MAX_NUM_LCGID) - { - lcgid_buffer_remain[lcgid] += UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]; - } - - rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,eNB_index,frameP,subframeP,ENB_FLAG_NO,MBMS_FLAG_NO, - lcid, - 0xFFFF); //TBS is not used in RLC at this step, set a special value for debug - - lcid_bytes_in_buffer[lcid] = rlc_status.bytes_in_buffer; - - if (rlc_status.bytes_in_buffer > 0) - { - LOG_D(MAC,"[UE %d] PDCCH Tick : LCID%d LCGID%d has data to transmit =%d bytes at frame %d subframe %d\n", - module_idP, lcid,lcgid,rlc_status.bytes_in_buffer,frameP,subframeP); - - UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_NOT_EMPTY; - //Update BSR_bytes and position in lcid_reordered_array only if Group is defined - if (lcgid < MAX_NUM_LCGID) - { - num_lcid_with_data ++; - // sum lcid buffer which has same lcgid - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] += rlc_status.bytes_in_buffer; - - //Fill in the array - array_index = 0; - do - { - if (UE_mac_inst[module_idP].logicalChannelConfig[lcid]->ul_SpecificParameters->priority <= highest_priority) - { - //Insert if priority is higher or equal (lower or equal in value) - for (pos_next=num_lcid_with_data-1; pos_next > array_index; pos_next--) - { - lcid_reordered_array[pos_next] = lcid_reordered_array[pos_next - 1]; - - } - lcid_reordered_array[array_index] = lcid; - break; - - } - array_index ++; - } - while ((array_index < num_lcid_with_data) && (array_index < MAX_NUM_LCID)); - } - } - } - - } - - // Check whether a regular BSR can be triggered according to the first cases in 36.321 - if (num_lcid_with_data) - { - LOG_D(MAC,"[UE %d] PDCCH Tick at frame %d subframe %d: NumLCID with data=%d Reordered LCID0=%d LCID1=%d LCID2=%d\n", - module_idP, frameP, subframeP,num_lcid_with_data,lcid_reordered_array[0],lcid_reordered_array[1],lcid_reordered_array[2]); - - for (array_index=0; array_index < num_lcid_with_data; array_index++) - { - lcid = lcid_reordered_array[array_index]; - /* UL data, for a logical channel which belongs to a LCG, becomes available for transmission in the RLC entity - either the data belongs to a logical channel with higher priority than the priorities of the logical channels - which belong to any LCG and for which data is already available for transmission - */ - if ((UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] == 0) - /* or there is no data available for any of the logical channels which belong to a LCG */ - ||(lcgid_buffer_remain[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] == 0) - ) - { - bsr_regular_triggered = TRUE; - - LOG_D(MAC,"[UE %d] PDCCH Tick : MAC BSR Triggered LCID%d LCGID%d data become available at frame %d subframe %d\n", - module_idP, lcid,UE_mac_inst[module_idP].scheduling_info.LCGID[lcid],frameP, subframeP); - - break; - } - } - - // Trigger Regular BSR if ReTxBSR Timer has expired and UE has data for transmission - if (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF == 0) - { - bsr_regular_triggered = TRUE; - - if ((UE_mac_inst[module_idP].BSR_reporting_active & BSR_TRIGGER_REGULAR) == 0) { - LOG_I(MAC,"[UE %d] PDCCH Tick : MAC BSR Triggered ReTxBSR Timer expiry at frame %d subframe %d\n", - module_idP, frameP, subframeP); - } - - } - } - - //Store Buffer Occupancy in remain buffers for next TTI - for (lcid=DCCH; lcid < MAX_NUM_LCID; lcid++) - { - UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] = lcid_bytes_in_buffer[lcid]; - } - - return bsr_regular_triggered; -} - -uint8_t locate_BsrIndexByBufferSize (const uint32_t *table, int size, int value) -{ - - uint8_t ju, jm, jl; - int ascend; - - DevAssert( size > 0 ); - DevAssert( size <= 256 ); - - if (value == 0) { - return 0; //elseif (value > 150000) return 63; - } - - jl = 0; // lower bound - ju = size - 1; // upper bound - ascend = (table[ju] >= table[jl]) ? 1 : 0; // determine the order of the the table: 1 if ascending order of table, 0 otherwise - - while (ju-jl > 1) { //If we are not yet done, - jm = (ju+jl) >> 1; //compute a midpoint, - - if ((value >= table[jm]) == ascend) { - jl=jm; // replace the lower limit - } else { - ju=jm; //replace the upper limit + // Reset All BSR Infos + lcid_bytes_in_buffer[0] = 0; + for (lcid = DCCH; lcid < MAX_NUM_LCID; lcid++) { + // Reset transmission status + lcid_bytes_in_buffer[lcid] = 0; + UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = + LCID_EMPTY; } - LOG_T(MAC,"[UE] searching BSR index %d for (BSR TABLE %d < value %d)\n", jm, table[jm], value); - } + for (lcgid = 0; lcgid < MAX_NUM_LCGID; lcgid++) { + // Reset Buffer Info + UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] = 0; + } - if (value == table[jl]) { - return jl; - } else { - return jl+1; //equally ju - } + //Get Buffer Occupancy and fill lcid_reordered_array + for (lcid = DCCH; lcid < MAX_NUM_LCID; lcid++) { + if (UE_mac_inst[module_idP].logicalChannelConfig[lcid]) { + lcgid = UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]; + + // Store already available data to transmit per Group + if (lcgid < MAX_NUM_LCGID) { + lcgid_buffer_remain[lcgid] += + UE_mac_inst[module_idP]. + scheduling_info.LCID_buffer_remain[lcid]; + } + + rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti, eNB_index, frameP, subframeP, ENB_FLAG_NO, MBMS_FLAG_NO, lcid, 0xFFFF); //TBS is not used in RLC at this step, set a special value for debug + + lcid_bytes_in_buffer[lcid] = rlc_status.bytes_in_buffer; + + if (rlc_status.bytes_in_buffer > 0) { + LOG_D(MAC, + "[UE %d] PDCCH Tick : LCID%d LCGID%d has data to transmit =%d bytes at frame %d subframe %d\n", + module_idP, lcid, lcgid, rlc_status.bytes_in_buffer, + frameP, subframeP); + + UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = + LCID_NOT_EMPTY; + //Update BSR_bytes and position in lcid_reordered_array only if Group is defined + if (lcgid < MAX_NUM_LCGID) { + num_lcid_with_data++; + // sum lcid buffer which has same lcgid + UE_mac_inst[module_idP].scheduling_info. + BSR_bytes[lcgid] += rlc_status.bytes_in_buffer; + + //Fill in the array + array_index = 0; + do { + if (UE_mac_inst[module_idP].logicalChannelConfig + [lcid]->ul_SpecificParameters->priority <= + highest_priority) { + //Insert if priority is higher or equal (lower or equal in value) + for (pos_next = num_lcid_with_data - 1; + pos_next > array_index; pos_next--) { + lcid_reordered_array[pos_next] = + lcid_reordered_array[pos_next - 1]; + + } + lcid_reordered_array[array_index] = lcid; + break; + + } + array_index++; + } + while ((array_index < num_lcid_with_data) + && (array_index < MAX_NUM_LCID)); + } + } + } + + } + + // Check whether a regular BSR can be triggered according to the first cases in 36.321 + if (num_lcid_with_data) { + LOG_D(MAC, + "[UE %d] PDCCH Tick at frame %d subframe %d: NumLCID with data=%d Reordered LCID0=%d LCID1=%d LCID2=%d\n", + module_idP, frameP, subframeP, num_lcid_with_data, + lcid_reordered_array[0], lcid_reordered_array[1], + lcid_reordered_array[2]); + + for (array_index = 0; array_index < num_lcid_with_data; + array_index++) { + lcid = lcid_reordered_array[array_index]; + /* UL data, for a logical channel which belongs to a LCG, becomes available for transmission in the RLC entity + either the data belongs to a logical channel with higher priority than the priorities of the logical channels + which belong to any LCG and for which data is already available for transmission + */ + if ((UE_mac_inst[module_idP]. + scheduling_info.LCID_buffer_remain[lcid] == 0) + /* or there is no data available for any of the logical channels which belong to a LCG */ + || + (lcgid_buffer_remain + [UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] == + 0)) { + bsr_regular_triggered = TRUE; + + LOG_D(MAC, + "[UE %d] PDCCH Tick : MAC BSR Triggered LCID%d LCGID%d data become available at frame %d subframe %d\n", + module_idP, lcid, + UE_mac_inst[module_idP].scheduling_info.LCGID[lcid], + frameP, subframeP); + + break; + } + } + + // Trigger Regular BSR if ReTxBSR Timer has expired and UE has data for transmission + if (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF == 0) { + bsr_regular_triggered = TRUE; + + if ((UE_mac_inst[module_idP].BSR_reporting_active & + BSR_TRIGGER_REGULAR) == 0) { + LOG_I(MAC, + "[UE %d] PDCCH Tick : MAC BSR Triggered ReTxBSR Timer expiry at frame %d subframe %d\n", + module_idP, frameP, subframeP); + } + + } + } + //Store Buffer Occupancy in remain buffers for next TTI + for (lcid = DCCH; lcid < MAX_NUM_LCID; lcid++) { + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] = + lcid_bytes_in_buffer[lcid]; + } + + return bsr_regular_triggered; +} + +uint8_t +locate_BsrIndexByBufferSize(const uint32_t * table, int size, int value) +{ + + uint8_t ju, jm, jl; + int ascend; + + DevAssert(size > 0); + DevAssert(size <= 256); + + if (value == 0) { + return 0; //elseif (value > 150000) return 63; + } + + jl = 0; // lower bound + ju = size - 1; // upper bound + ascend = (table[ju] >= table[jl]) ? 1 : 0; // determine the order of the the table: 1 if ascending order of table, 0 otherwise + + while (ju - jl > 1) { //If we are not yet done, + jm = (ju + jl) >> 1; //compute a midpoint, + + if ((value >= table[jm]) == ascend) { + jl = jm; // replace the lower limit + } else { + ju = jm; //replace the upper limit + } + + LOG_T(MAC, + "[UE] searching BSR index %d for (BSR TABLE %d < value %d)\n", + jm, table[jm], value); + } + + if (value == table[jl]) { + return jl; + } else { + return jl + 1; //equally ju + } } int get_sf_periodicBSRTimer(uint8_t sf_offset) { - switch (sf_offset) { - case PeriodicBSR_Timer_r12_sf5: - return 5; - break; + switch (sf_offset) { + case PeriodicBSR_Timer_r12_sf5: + return 5; + break; - case PeriodicBSR_Timer_r12_sf10: - return 10; - break; + case PeriodicBSR_Timer_r12_sf10: + return 10; + break; - case PeriodicBSR_Timer_r12_sf16: - return 16; - break; + case PeriodicBSR_Timer_r12_sf16: + return 16; + break; - case PeriodicBSR_Timer_r12_sf20: - return 20; - break; + case PeriodicBSR_Timer_r12_sf20: + return 20; + break; - case PeriodicBSR_Timer_r12_sf32: - return 32; - break; + case PeriodicBSR_Timer_r12_sf32: + return 32; + break; - case PeriodicBSR_Timer_r12_sf40: - return 40; - break; + case PeriodicBSR_Timer_r12_sf40: + return 40; + break; - case PeriodicBSR_Timer_r12_sf64: - return 64; - break; + case PeriodicBSR_Timer_r12_sf64: + return 64; + break; - case PeriodicBSR_Timer_r12_sf80: - return 80; - break; + case PeriodicBSR_Timer_r12_sf80: + return 80; + break; - case PeriodicBSR_Timer_r12_sf128: - return 128; - break; + case PeriodicBSR_Timer_r12_sf128: + return 128; + break; - case PeriodicBSR_Timer_r12_sf160: - return 160; - break; + case PeriodicBSR_Timer_r12_sf160: + return 160; + break; - case PeriodicBSR_Timer_r12_sf320: - return 320; - break; + case PeriodicBSR_Timer_r12_sf320: + return 320; + break; - case PeriodicBSR_Timer_r12_sf640: - return 640; - break; + case PeriodicBSR_Timer_r12_sf640: + return 640; + break; - case PeriodicBSR_Timer_r12_sf1280: - return 1280; - break; + case PeriodicBSR_Timer_r12_sf1280: + return 1280; + break; - case PeriodicBSR_Timer_r12_sf2560: - return 2560; - break; + case PeriodicBSR_Timer_r12_sf2560: + return 2560; + break; - case PeriodicBSR_Timer_r12_infinity: - default: - return 0xFFFF; - break; - } + case PeriodicBSR_Timer_r12_infinity: + default: + return 0xFFFF; + break; + } } int get_sf_retxBSRTimer(uint8_t sf_offset) { - switch (sf_offset) { - case RetxBSR_Timer_r12_sf320: - return 320; - break; + switch (sf_offset) { + case RetxBSR_Timer_r12_sf320: + return 320; + break; - case RetxBSR_Timer_r12_sf640: - return 640; - break; + case RetxBSR_Timer_r12_sf640: + return 640; + break; - case RetxBSR_Timer_r12_sf1280: - return 1280; - break; + case RetxBSR_Timer_r12_sf1280: + return 1280; + break; - case RetxBSR_Timer_r12_sf2560: - return 2560; - break; + case RetxBSR_Timer_r12_sf2560: + return 2560; + break; - case RetxBSR_Timer_r12_sf5120: - return 5120; - break; + case RetxBSR_Timer_r12_sf5120: + return 5120; + break; - case RetxBSR_Timer_r12_sf10240: - return 10240; - break; + case RetxBSR_Timer_r12_sf10240: + return 10240; + break; - default: - return -1; - break; - } + default: + return -1; + break; + } } + int get_ms_bucketsizeduration(uint8_t bucketsizeduration) { - switch (bucketsizeduration) { - case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50: - return 50; - break; + switch (bucketsizeduration) { + case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50: + return + 50; + break; - case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100: - return 100; - break; + case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100: + return + 100; + break; - case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms150: - return 150; - break; + case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms150: + return + 150; + break; - case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms300: - return 300; - break; + case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms300: + return + 300; + break; - case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms500: - return 500; - break; + case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms500: + return + 500; + break; - case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms1000: - return 1000; - break; + case LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms1000: + return + 1000; + break; - default: - return 0; - break; - } + default: + return 0; + break; + } } -void update_phr(module_id_t module_idP,int CC_id) +void update_phr(module_id_t module_idP, int CC_id) { - AssertFatal(CC_id==0, - "Transmission on secondary CCs is not supported yet\n"); + AssertFatal(CC_id == 0, + "Transmission on secondary CCs is not supported yet\n"); - UE_mac_inst[module_idP].PHR_reporting_active =0; - UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer); - UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer); - // LOG_D(MAC,"phr %d %d\n ",UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF, UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF); + UE_mac_inst[module_idP].PHR_reporting_active = 0; + UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF = + get_sf_perioidicPHR_Timer(UE_mac_inst[module_idP]. + scheduling_info.periodicPHR_Timer); + UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF = + get_sf_prohibitPHR_Timer(UE_mac_inst[module_idP]. + scheduling_info.prohibitPHR_Timer); + // LOG_D(MAC,"phr %d %d\n ",UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF, UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF); } -uint8_t get_phr_mapping (module_id_t module_idP, int CC_id, uint8_t eNB_index) + +uint8_t +get_phr_mapping(module_id_t module_idP, int CC_id, uint8_t eNB_index) { - AssertFatal(CC_id==0, - "Transmission on secondary CCs is not supported yet\n"); + AssertFatal(CC_id == 0, + "Transmission on secondary CCs is not supported yet\n"); - //power headroom reporting range is from -23 ...+40 dB, as described in 36313 - //note: mac_xface->get_Po_NOMINAL_PUSCH(module_idP) is float - if (get_PHR(module_idP,CC_id,eNB_index) < -23) { - return 0; - } else if (get_PHR(module_idP,CC_id,eNB_index) >= 40) { - return 63; - } else { // -23 to 40 - return (uint8_t) get_PHR(module_idP,CC_id,eNB_index) + PHR_MAPPING_OFFSET; + //power headroom reporting range is from -23 ...+40 dB, as described in 36313 + //note: mac_xface->get_Po_NOMINAL_PUSCH(module_idP) is float + if (get_PHR(module_idP, CC_id, eNB_index) < -23) { + return 0; + } else if (get_PHR(module_idP, CC_id, eNB_index) >= 40) { + return 63; + } else { // -23 to 40 + return (uint8_t) get_PHR(module_idP, CC_id, + eNB_index) + PHR_MAPPING_OFFSET; - } + } } + int get_sf_perioidicPHR_Timer(uint8_t perioidicPHR_Timer) { - return (perioidicPHR_Timer+1)*10; + return (perioidicPHR_Timer + 1) * 10; } int get_sf_prohibitPHR_Timer(uint8_t prohibitPHR_Timer) { - return (prohibitPHR_Timer)*10; + return (prohibitPHR_Timer) * 10; } int get_db_dl_PathlossChange(uint8_t dl_PathlossChange) { - switch (dl_PathlossChange) { - case MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1: - return 1; - break; + switch (dl_PathlossChange) { + case MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1: + return 1; + break; - case MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB3: - return 3; - break; + case MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB3: + return 3; + break; - case MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB6: - return 6; - break; + case MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB6: + return 6; + break; - case MAC_MainConfig__phr_Config__setup__dl_PathlossChange_infinity: - default: - return -1; - break; - } + case MAC_MainConfig__phr_Config__setup__dl_PathlossChange_infinity: + default: + return -1; + break; + } } diff --git a/openair2/LAYER2/MAC/vars.h b/openair2/LAYER2/MAC/vars.h index 4ff5475253..2386088161 100644 --- a/openair2/LAYER2/MAC/vars.h +++ b/openair2/LAYER2/MAC/vars.h @@ -34,25 +34,32 @@ #define __MAC_VARS_H__ #ifdef USER_MODE //#include "stdio.h" -#endif //USER_MODE +#endif //USER_MODE #include "PHY/defs.h" #include "defs.h" #include "COMMON/mac_rrc_primitives.h" -const uint32_t BSR_TABLE[BSR_TABLE_SIZE]= {0,10,12,14,17,19,22,26,31,36,42,49,57,67,78,91, - 105,125,146,171,200,234,274,321,376,440,515,603,706,826,967,1132, - 1326,1552,1817,2127,2490,2915,3413,3995,4677,5467,6411,7505,8787,10287,12043,14099, - 16507,19325,22624,26487,31009,36304,42502,49759,58255,68201,79846,93479,109439, 128125,150000, 300000 - }; -// extended bsr table--currently not used -const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE] = {0,10,13,16,19,23,29,35,43,53,65,80,98,120,147, - 181,223,274,337,414,509,625,769,945,1162,1429, - 1757,2161,2657,3267,4017,4940,6074,7469,9185, - 11294,13888,17077,20999,25822,31752,39045,48012, - 59039,72598,89272,109774,134986,165989,204111, - 250990,308634,379519,466683,573866,705666,867737, - 1067031,1312097,1613447,1984009,2439678,3000000, - 6000000}; +const uint32_t BSR_TABLE[BSR_TABLE_SIZE] = + { 0, 10, 12, 14, 17, 19, 22, 26, 31, 36, 42, 49, 57, 67, 78, 91, + 105, 125, 146, 171, 200, 234, 274, 321, 376, 440, 515, 603, 706, 826, + 967, 1132, + 1326, 1552, 1817, 2127, 2490, 2915, 3413, 3995, 4677, 5467, 6411, 7505, + 8787, 10287, 12043, 14099, + 16507, 19325, 22624, 26487, 31009, 36304, 42502, 49759, 58255, 68201, + 79846, 93479, 109439, 128125, 150000, 300000 +}; + +// extended bsr table--currently not used +const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE] = + { 0, 10, 13, 16, 19, 23, 29, 35, 43, 53, 65, 80, 98, 120, 147, + 181, 223, 274, 337, 414, 509, 625, 769, 945, 1162, 1429, + 1757, 2161, 2657, 3267, 4017, 4940, 6074, 7469, 9185, + 11294, 13888, 17077, 20999, 25822, 31752, 39045, 48012, + 59039, 72598, 89272, 109774, 134986, 165989, 204111, + 250990, 308634, 379519, 466683, 573866, 705666, 867737, + 1067031, 1312097, 1613447, 1984009, 2439678, 3000000, + 6000000 +}; //#define MAX_SIZE_OF_AGG3 576 //#define MAX_SIZE_OF_AGG2 288 @@ -64,24 +71,26 @@ const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE] = {0,10,13,16,19,23,29,35,43,5 * this is also dependent to transmission mode, where an offset could be defined */ // the follwoing three tables are calibrated for TXMODE 1 and 2 -const uint8_t cqi2fmt0_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE]= { - {3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 1.4_DCI0_CRC_Size= 37 bits - //{3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0}, // 5_DCI0_CRC_SIZE = 41 - {3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, // 5_DCI0_CRC_SIZE = 41 - {3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0}, // 10_DCI0_CRC_SIZE = 43 - {3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0} // 20_DCI0_CRC_SIZE = 44 +const uint8_t cqi2fmt0_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE] = { + {3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 1.4_DCI0_CRC_Size= 37 bits + //{3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0}, // 5_DCI0_CRC_SIZE = 41 + {3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, // 5_DCI0_CRC_SIZE = 41 + {3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0}, // 10_DCI0_CRC_SIZE = 43 + {3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0} // 20_DCI0_CRC_SIZE = 44 }; -const uint8_t cqi2fmt1x_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE]= { - {3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 1.4_DCI0_CRC_Size < 38 bits - {3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, // 5_DCI0_CRC_SIZE < 43 - {3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0}, // 10_DCI0_CRC_SIZE < 47 - {3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0} // 20_DCI0_CRC_SIZE < 55 + +const uint8_t cqi2fmt1x_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE] = { + {3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 1.4_DCI0_CRC_Size < 38 bits + {3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, // 5_DCI0_CRC_SIZE < 43 + {3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0}, // 10_DCI0_CRC_SIZE < 47 + {3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0} // 20_DCI0_CRC_SIZE < 55 }; -const uint8_t cqi2fmt2x_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE]= { - {3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 1.4_DCI0_CRC_Size= 47 bits - {3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, // 5_DCI0_CRC_SIZE = 55 - {3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0}, // 10_DCI0_CRC_SIZE = 59 - {3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0} // 20_DCI0_CRC_SIZE = 64 + +const uint8_t cqi2fmt2x_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE] = { + {3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 1.4_DCI0_CRC_Size= 47 bits + {3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, // 5_DCI0_CRC_SIZE = 55 + {3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0}, // 10_DCI0_CRC_SIZE = 59 + {3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0} // 20_DCI0_CRC_SIZE = 64 }; //uint32_t EBSR_Level[63]={0,10,13,16,19,23,29,35,43,53,65,80,98,120,147,181}; @@ -89,7 +98,7 @@ const uint8_t cqi2fmt2x_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE]= { uint32_t RRC_CONNECTION_FLAG; -UE_MAC_INST *UE_mac_inst; //[NB_MODULE_MAX]; +UE_MAC_INST *UE_mac_inst; //[NB_MODULE_MAX]; MAC_RLC_XFACE *Mac_rlc_xface; /// Primary component carrier index of eNB @@ -97,39 +106,39 @@ int pCC_id[NUMBER_OF_eNB_MAX]; -eNB_ULSCH_INFO eNB_ulsch_info[NUMBER_OF_eNB_MAX][MAX_NUM_CCs][NUMBER_OF_UE_MAX]; // eNBxUE = 8x8 -eNB_DLSCH_INFO eNB_dlsch_info[NUMBER_OF_eNB_MAX][MAX_NUM_CCs][NUMBER_OF_UE_MAX]; // eNBxUE = 8x8 +eNB_ULSCH_INFO eNB_ulsch_info[NUMBER_OF_eNB_MAX][MAX_NUM_CCs][NUMBER_OF_UE_MAX]; // eNBxUE = 8x8 +eNB_DLSCH_INFO eNB_dlsch_info[NUMBER_OF_eNB_MAX][MAX_NUM_CCs][NUMBER_OF_UE_MAX]; // eNBxUE = 8x8 #ifdef OPENAIR2 -unsigned char NB_eNB_INST=0; -unsigned char NB_UE_INST=0; -unsigned char NB_RN_INST=0; -unsigned char NB_INST=0; +unsigned char NB_eNB_INST = 0; +unsigned char NB_UE_INST = 0; +unsigned char NB_RN_INST = 0; +unsigned char NB_INST = 0; #endif -DCI0_5MHz_TDD_1_6_t UL_alloc_pdu; +DCI0_5MHz_TDD_1_6_t UL_alloc_pdu; -DCI1A_5MHz_TDD_1_6_t DLSCH_alloc_pdu1A; -DCI1A_5MHz_TDD_1_6_t RA_alloc_pdu; -DCI1A_5MHz_TDD_1_6_t BCCH_alloc_pdu; +DCI1A_5MHz_TDD_1_6_t DLSCH_alloc_pdu1A; +DCI1A_5MHz_TDD_1_6_t RA_alloc_pdu; +DCI1A_5MHz_TDD_1_6_t BCCH_alloc_pdu; -DCI1A_5MHz_TDD_1_6_t CCCH_alloc_pdu; -DCI1_5MHz_TDD_t DLSCH_alloc_pdu; +DCI1A_5MHz_TDD_1_6_t CCCH_alloc_pdu; +DCI1_5MHz_TDD_t DLSCH_alloc_pdu; #if defined(Rel10) || defined(Rel14) -DCI1C_5MHz_t MCCH_alloc_pdu; +DCI1C_5MHz_t MCCH_alloc_pdu; #endif -DCI0_5MHz_FDD_t UL_alloc_pdu_fdd; +DCI0_5MHz_FDD_t UL_alloc_pdu_fdd; -DCI1A_5MHz_FDD_t DLSCH_alloc_pdu1A_fdd; -DCI1A_5MHz_FDD_t RA_alloc_pdu_fdd; -DCI1A_5MHz_FDD_t BCCH_alloc_pdu_fdd; +DCI1A_5MHz_FDD_t DLSCH_alloc_pdu1A_fdd; +DCI1A_5MHz_FDD_t RA_alloc_pdu_fdd; +DCI1A_5MHz_FDD_t BCCH_alloc_pdu_fdd; -DCI1A_5MHz_FDD_t CCCH_alloc_pdu_fdd; -DCI1_5MHz_FDD_t DLSCH_alloc_pdu_fdd; +DCI1A_5MHz_FDD_t CCCH_alloc_pdu_fdd; +DCI1_5MHz_FDD_t DLSCH_alloc_pdu_fdd; DCI2_5MHz_2A_TDD_t DLSCH_alloc_pdu1; DCI2_5MHz_2A_TDD_t DLSCH_alloc_pdu2; @@ -137,5 +146,3 @@ DCI2_5MHz_2A_TDD_t DLSCH_alloc_pdu2; DCI1E_5MHz_2A_M10PRB_TDD_t DLSCH_alloc_pdu1E; #endif - - From 7d3ce9bd1d7e29e04c48e72069d5a1f4c8695b22 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Mon, 13 Nov 2017 07:15:08 -0800 Subject: [PATCH 075/284] added .ipe file for L1_L2_procedures slides and updated .pdf file --- targets/DOCS/oai_L1_L2_procedures.ipe | 12461 ++++++++++++++++++++++++ targets/DOCS/oai_L1_L2_procedures.pdf | Bin 1118156 -> 663552 bytes 2 files changed, 12461 insertions(+) create mode 100755 targets/DOCS/oai_L1_L2_procedures.ipe diff --git a/targets/DOCS/oai_L1_L2_procedures.ipe b/targets/DOCS/oai_L1_L2_procedures.ipe new file mode 100755 index 0000000000..2062240c14 --- /dev/null +++ b/targets/DOCS/oai_L1_L2_procedures.ipe @@ -0,0 +1,12461 @@ + + + + +\usepackage{setspace}\usepackage{amsmath}\usepackage{stackrel} + +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 +2NraK/l2+fJVply/fvPGjVufKLfxKb6yX+Xq1ev46b8t2KodLrbDcuXK51Z4+crVm7duPXh4 +7/6DPZSH9xDZS5eu4Of09C4rWceT+zqhGuuIcl9EuZ6eHqIcUe4zWlpaqqmptbGxVdDs9hfB +4QMirh1w2fcfBXxAns8UXd3LF3UuXby4h6JzCVhTjRvDukt6V1w8LYWd2bMygXLY9B32L6ft +lEPt3nv/cjh0+/r6tDoOjo7O36p/uSNCORwhr169vX//IbzZl/KNyt4LWIc09sxpHScPi0Fp +JTNI4k76Ci4pLX327IW9g6MjaoIWFjs7B3lfwY177SvY3d3D0NBYS4PwPg7yvoKbiXJfVWtr +a2VlZfr6hshV4ei2WzUkkp8pB2/k9j1j/XaIuwK+Xbiga2z2Nr8ianSxVqK49rqT0W36+vuF +IlEDh9PA4Wpn4TQ1N+99oKvOri4Ol6u1QfhkHIhyX0Orq6slJaXv3qmz7vr1W3fu3MXMjxZQ +br/yR6xn5+fu/nYx7MKtW3d2UrAXOhf0Tp2SXxf4TDlzek8Fa9DR0VOyV8G3Cxd19Cxs3lVw +E6SbvAWZUHl7yQ7H8ELrr+1lX0ZnPpRxIMp9TdatFRUVIYdlWIc0Ni8vTyKRjH9MExMT+Dc6 +0ZruWd3d3XgRiUQ8Hv8zEgiE8fEJDg5OmOB/dkEOh1teXrGTEhIcbutoWlgek1UU9tGSXRKW +lB0QleQdk7z7kpjhb2Khf+GCHuPfQDxLW8NqYfKMjC/n2187fdo55UbEYu0t+0U5rQ7Cp+JA +lPvaWllZhq/T1ze4d+9hTU2Npt3rwjyDs28rFLZEJ/nIZN2LMtEnSiNeF/ZWZLL20BjPH/9z +Qkfn0nu+bfHnVfzbLkad5vEF1fh7amu1sVRX14gaG1GX956x1tTWaWkQPhMHotxBsW4lKyur +ublFo7ZKS599mJcJgiLc9A1fMP7tU3zb+UiFpWVlL1++cnZ2dXV108bi5OT8+vXb7SP0fenV +B09PlomJqZYG4X0c3rxtam454lcfmE4SVN8yczY2NpaWliHmqZMjIi2lHJjWO1mG18/z7Yvu +JAkLC6c7SWxsbHfXHzvdSaJRlBsaGjYyMhofn2DepqVlNDQ0zM/PGxqaID5oCxwcHNva2ohy +mkw55nDaYafrdFcwPftwFCi3vr7OPEEMn4Y9vnbthouLG/NRaGh4SUnp2NiYmZnlikLt7R3G +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 +QvYK19Ha2tbxQci8mLHPoPX19fb2dqSrCwsLdF7uU0JwEDTVTsCQ2iOSaFC6u7sRQCawbW1t +fX39ym6I+vsHmptbhodH6LwciShHT3jRE15EORJRjihHlCPKkQ4B5QQCofbGUyqd0diel4KC +grX7WK2rJ8qRDgHlPDxZ6ekZvVorDodraWk9NDysaZTLLyh0dnbt1WYlJaWwvX2IciStphwO +YDbbW1//HRydlhYrKxtTU3P54IkaRrnSsvI//nji5uahvbF980bfzz+AKEc6BBmrUCjS3njO +zMxSxvqV1NDAoYyVRFcf6OoDXX0gypGIckQ5ohxRjihHlCPKEeVIRDnNpFx+fr6bm3t8fAJz +7/3w8LC3t4+XF7urq5tZYG1tLSwsPDIySrVr9I2NjdLSMjc3DxbLa499oB1WynV2diKMCKZY +LJYpekGPi4tHqAsKCpXLlJdXuLq6qfVB2tnZ5efnj/lpaenKTtSJciSi3K53x9ra5l//+vel +S1eYvkcyM7O+++77H374qazsfRdAra1tP//8y/HjJ7u733NveXnZzs7+xx9/vnbthp7e5Z9/ +/hUY/NTwEEeWcsXFxQjj99//mJubJ1P096Kjo/vPf35na2uvbCmePn32X//135GR0cpv5ebm +njhx6sKFi4gtwv7y5WvlU3VEORJRbndydHS6fv3mo0eP6+vlD92zWOxHj/5ALUMFYRZgs33e +vjX4/fdHkZGRzJyUlFTU3+TklNXV1dnZWUtL66dPn++6x7nDSrny8nKE8fHjJz4+vnhbXV39 +22+PwC5nZ1dmAYFAcP/+QwsLy2fPnjNP5Q8ODp09e97ExGxiYhKxRYujq6u3F6tMlCMR5WSK +fs9QEx0cnMLDI5C0GhgYMp1qMpRbXFy8fftuRUVlaGgYquTa2jpmYhmmDw1GqI9wd5Sxqglm +GGH09vY1MjLB26CgYEdHZ4QazQqzgIeHJ3xda2vrmTPnmHuBgLVjx35taWlVrmSPo6QR5UhE +OQi554sXL2HPYMl6e/tev36TlyfvIpihXG1t3Y0btzAxMDBw5sz5pqZmTD979oKpuXT14fOU +gzHLzy949ep1X1+fubllamrakyfPGMqhXbh7935lZRWmYZ7ZbG9MxMXFnzt3YXh4iK4+kIhy ++0s5VD3g6+XL1yEhoQ4Ojo2NTSdPnkGGhU+RXiHtCggI9PJinzx5OiwsHDPfvTN6+PB35Rq6 +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 +pHyubtC511LJ/iprOhgsChWTdiq+k6qkHDJIM3Y21kpT2fnmC+Zs7sXzpob2fn4uelrn4uoH +idQJCH4WLI7fq2h9PvOS/W156klV+0OWqbR0vyQ5Mupm98QKc3G4pv3h3OriQH3n0Pjy4kT/ +vZ5Hy+vG9mxH04NH4yw/x8pkS13Ng4cDzc2D86yri8MPqutaaNNqbepuxvWIiKg7TWQpREBA +QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBA +QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBA +QEBAQEBA8K6xOPWsvrI0P+cV8hu7R8af9d69P7j0Mzzu2YN66hl1D8f+TJ6x4aHnL5Z/4OLK +8EBHxZ0idl0LbtePLq5fmH7aU9PYv/DmDTND9xrujyysvXHhRefdxocj8z+1CQsTQ02VZRsS +y73bMcw6vfysd+D5xMJ/i5RWXwxVFuRWdQ6t/rj8a2sLkzMLtHAGex6OvPjxD5oZ6qstK8nd +6Pvi+s7XO325/34FLefy1tnvVeXl6N07BdSlu22P31Lu0lR7Q3Vx/kbBeWUD4+wOXR1/0l1R +WvxqtFU09G8qeLm7sZJ+XFn98ze65eWL4Y6Ovsmltbe3ZHluZm5+5Uc0ebS/MS+ndGB04YOk +c3uy88cf7VExNNuATWzBg4H2spi0urn/5kcttRVEmhubmpmZ6hk4xKY1L76Vy00pDEW5S3fH +f6CQcR9Frm0HRdbramZuaH3hTtckdeFp653opKo3h/LqcEt8QlrX1BvMWB7Jj0ms6Zn8qc1o +izH97Pe7lY3W5aWjdC74ZsMqczxQQi8w+cF/xwz7LNxAU1rFODSv6eWPY3NNrI9H3D1qprmk +K6gaWf2jn7SWbSP6h52cBht9r6iseM4vZ5TFvJXR9qBAH1sne+q8uZGFkUtgSe80+7ah+qIg +S2dre1vqkpWZpa1X6uPXx8rig5tHtm3nV1ov2ERTVVHXNr97ihoDkQZCH+/hNV5/oKm6rLzd +1WK63KXnWYHuFlZ0mdZOzg6Wnrn3Hm0uc6Q8eP8BqVsDb53nl0tCfX3jG/5igyc7cxWlZPWt +Aqp7pj5IOt+PdTjEY/P0exRYXlpYXGbPg2MDDxqbHoy/mB0fn1p4uTo/OTo8/oJ1aW1ucmxk +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 ++2+FvNhG86Nc74/+Y5dXOa2SXzTG8AnJZ7Z13fSzMrR1o+5ytbVyvHF3fv6BMYdQYNGTuf5K +W30zOzd3T0cXXROX7I4p5nAB99en/YpZGn28Vk3gjFf581c1aArV2nVCs/X723hDPsKaF249 +nO6/raEqr27j6X/lioeB4J/4NSq7GnS5ThlcaV1fGsidMUnreNKcqWNo4UHJycfRxPh8ceOz +73Tdo9ty+8Xim2eZy0NxQbZ6xk6enl7mhiaBydTac+6C5MGztknf229qTnIW4ddIzCn11hVS +CWXPdeMB4gw9X+p4ruCCq6GZA9VwMwMTt/M5YyuvTJvVVGOebxXOf7dnM9Gsc/yIhGs2xeIX +PaVWFiaWjlQVPd3tHXTM7RLqn7DvbM+OMVY3t/P2pi652VrpmoY2P39tG2OuJeHwl7yxTa90 +2WpJgN5ODt2mobEIbREunZhXps3Ks0rJg0e0wqpezvXdcLezd/TwovvV28neIaGi57WNqrLA +r7+RLJxcqXCX2CvmyO6Pu8HW/EKeVP2bIjz5ebWii7sf1SabGJtRytTJysrY9nzj09lib/V9 +gq7s/HXX7fYLnx+jlgbl12V5FS09PcMjo40luHZwulKKoLkgQlXLjBpa+poGPmEVL5nz+VG+ +eka2VI3szIyNLuaMvFzb4nSeGequrO148brTY+JxV+39gcXFuZnpiY768sys8rbbMVJGHndZ +bpnpwab46zF5Ne1DfX3tHU9mJx7VVt8bfrXOeTlWmpMUExNX/fDNveOVB7WFMTExaRWdyz+4 +6zre0tAwwN5lWRytzC1sfrLZsns50FaTnhwfw0JiWvnwwtvCSBZH6+91snfKWGEkzWNUeS/H +y7KoisXklLezhtPsqzCStamB/OSYmNjCx9OsuXh+pL6q/iH7/uWptob6/onvbOuZR+2VdW0v +vu8mWuxvbHv4jCb5xEDjjesx8fnVz8dGuvp6RmemOurrO5+wVdVCT3N9B2unbKq7PoWqTVxK +49Dru+UL4y01TU+n2RJaaCm4SdWsrIsdePPy4f2ae93P3tjSHytPTi2q6uh90Nz2mG3YLA/c +b+roZ9+13FaTRze8off1RdXa8wf3aloebnZKj/U2FZS1rZtULyfrC1KpG+NvVX4v7OLlRE9G +cix1qaC6c+ktoTvPaqsans5sKnhppKq0rHt0+knn/fr218JjnnXWFtc9YGVd6qgouE4VmpLV +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 +wJn/A5vjFyA= + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-0.8 0 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-0.8 0 l +-1 -0.333 l +h + + + + +0.6 0 0 0.6 0 0 e +0.4 0 0 0.4 0 0 e + + + + +0.6 0 0 0.6 0 0 e + + + + + +0.5 0 0 0.5 0 0 e + + +0.6 0 0 0.6 0 0 e +0.4 0 0 0.4 0 0 e + + + + + +-0.6 -0.6 m +0.6 -0.6 l +0.6 0.6 l +-0.6 0.6 l +h +-0.4 -0.4 m +0.4 -0.4 l +0.4 0.4 l +-0.4 0.4 l +h + + + + +-0.6 -0.6 m +0.6 -0.6 l +0.6 0.6 l +-0.6 0.6 l +h + + + + + +-0.5 -0.5 m +0.5 -0.5 l +0.5 0.5 l +-0.5 0.5 l +h + + +-0.6 -0.6 m +0.6 -0.6 l +0.6 0.6 l +-0.6 0.6 l +h +-0.4 -0.4 m +0.4 -0.4 l +0.4 0.4 l +-0.4 0.4 l +h + + + + + + +-0.43 -0.57 m +0.57 0.43 l +0.43 0.57 l +-0.57 -0.43 l +h + + +-0.43 0.57 m +0.57 -0.43 l +0.43 -0.57 l +-0.57 0.43 l +h + + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-0.8 0 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-0.8 0 l +-1 -0.333 l +h + + + + +-1 0.333 m +0 0 l +-1 -0.333 l + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h +-1 0 m +-2 0.333 l +-2 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h +-1 0 m +-2 0.333 l +-2 -0.333 l +h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h + + + + +0.6 0 0 0.6 0 0 e +0.4 0 0 0.4 0 0 e + + + + +0.6 0 0 0.6 0 0 e + + + + + +0.5 0 0 0.5 0 0 e + + +0.6 0 0 0.6 0 0 e +0.4 0 0 0.4 0 0 e + + + + + +-0.6 -0.6 m +0.6 -0.6 l +0.6 0.6 l +-0.6 0.6 l +h +-0.4 -0.4 m +0.4 -0.4 l +0.4 0.4 l +-0.4 0.4 l +h + + + + +-0.6 -0.6 m +0.6 -0.6 l +0.6 0.6 l +-0.6 0.6 l +h + + + + + +-0.5 -0.5 m +0.5 -0.5 l +0.5 0.5 l +-0.5 0.5 l +h + + +-0.6 -0.6 m +0.6 -0.6 l +0.6 0.6 l +-0.6 0.6 l +h +-0.4 -0.4 m +0.4 -0.4 l +0.4 0.4 l +-0.4 0.4 l +h + + + + + + +-0.43 -0.57 m +0.57 0.43 l +0.43 0.57 l +-0.57 -0.43 l +h + + +-0.43 0.57 m +0.57 -0.43 l +0.43 -0.57 l +-0.57 0.43 l +h + + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-0.8 0 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-0.8 0 l +-1 -0.333 l +h + + + + +-1 0.333 m +0 0 l +-1 -0.333 l + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h +-1 0 m +-2 0.333 l +-2 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h +-1 0 m +-2 0.333 l +-2 -0.333 l +h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +\renewcommand\rmdefault{cmss} +\makeatletter +\leftmargini 1.5em +\leftmargin \leftmargini +\leftmarginii 1.2em +\leftmarginiii 1em +\def\@listI{\leftmargin\leftmargini + \parsep \z@ + \partopsep 3pt + \topsep \z@ + \itemsep \z@} +\@listI +\def\@listii {\leftmargin\leftmarginii + \labelwidth\leftmarginii + \advance\labelwidth-\labelsep + \topsep \z@ + \parsep \z@ + \itemsep \parsep} +\def\@listiii{\leftmargin\leftmarginiii + \labelwidth\leftmarginiii + \advance\labelwidth-\labelsep + \topsep \z@ + \parsep \z@ + \partopsep \z@ + \itemsep \topsep} +\makeatother + + + + + + + + + +Some Preliminaries +\begin{itemize} +\item This description corresponds to the {\tt RU-RAU-split} branch for RAN infrastructure components (located in {\tt targets/DOCS/oai\_L1\_L2\_procedures.pdf}, editable with {\tt ipe}) +\item we describe +\begin{enumerate} +\item node functions +\item current functional splits and packet formats +\item RAN procedures +\item process scheduling +\end{enumerate} +\end{itemize} + + + + + +NGFI Harmonization in OAI +\small +\begin{itemize} +\item New descriptions for OAI RAN infrastructure Node Functions +\begin{itemize} +\item{\tt NGFI\_RCC} : Radio Cloud Center +\item{\tt NGFI\_RAU} : Radio Aggregation Unit +\item{\tt NGFI\_RRU} : Remote Radio Unit +\item{\tt 3GPP\_BBU} : Baseband Unit +\item{\tt 3GPP\_eNodeB} : Complete eNodeB +\end{itemize} +\end{itemize} +\small Source: China Mobile - {\tt http://www.windriver.com.cn/windforum/download/wf2015\_networking03.pdf} + + + + + +\small\begin{itemize} +\item Current OAI implementation (RRU/RCC) supports either +\begin{itemize} +\item IF5 time-domain fronthaul ($>$ 1 GbE required) +\item IF4.5 split (FFTs) (280 Mbit/s/antenna port fronthaul – 20 MHz carrier) per carrier/sector +\item Soon IF2 (NFAPI) +\item IF1’ for “PDCP/RRC” soon (3GPP Fh-C/Fh-U) +\end{itemize} +\end{itemize} +NGFI split points + + + + + + +OAI RAN Software Architecture + + + + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +528 64 m +528 32 l +640 32 l +640 64 l +h + + +528 64 m +528 32 l +640 32 l +640 64 l +h + + +528 101 m +528 48 l +736 48 l +736 101 l +h + + +392 376 m +392 296 l +512 296 l +512 376 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +392 376 m +392 296 l +512 296 l +512 376 l +h + + +136 312 m +136 272 l +200 272 l +200 312 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + +\tiny\bf LTE\\ +MODEM + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +96 408 m +96 360 l +208 360 l +208 408 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + +\tiny\bf LTE/NR/NB\\ +PDCP + +128 320 m +128 280 l +192 280 l +192 320 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + +\tiny\bf LTE\\ +RRC + +112 464 m +112 440 l +648 440 l +648 464 l +h + + +432 224 m +432 224 l +432 224 l +432 224 l +h + +\bf OSS/BSS/MEC + +192 296 m +232 296 l +232 404 l +256 404 l + + +144 288 m +144 320 l + + +384 368 m +448 368 l + + +384 352 m +448 352 l + + +152 456 m +152 368 l + + +304 456 m +304 408 l + + +456 456 m +456 416 l + + +600 456 m +600 409 l + + +512 368 m +576 368 l + + +512 352 m +576 352 l + + +88 384 m +8 384 l + + +128 264 m +8 264 l + +OAI Functional Splits + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\bf\tiny LTE-L1 + +192 368 m +96 368 l + + +192 368 m +96 368 l + + +192 368 m +96 368 l + +\bf\tiny Management +\bf\tiny data (user/control plane) +\bf\tiny configuration + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\tiny\bf LTE\\ +MAC-RLC + +288 432 m +288 432 l +288 432 l +288 432 l +h + + +240 460 m +240 40 l +520 40 l +520 460 l +h + + +384 416 m +384 416 l +384 416 l +384 416 l +h + + +560 416 m +560 336 l +656 336 l +656 416 l +h + + +88 456 m +88 40 l +216 40 l +216 221 l +216 261 l +216 456 l +100.8 456 l +88 456 l + +\bf\tiny Radio-Cloud Center (RCC) +\tiny\bf Radio-Access Unit (RAU) + +136 248 m +136 208 l +200 208 l +200 248 l +h + + +128 256 m +128 216 l +192 216 l +192 256 l +h + +\tiny\bf NR\\ +RRC + +128 229 m +112 229 l +112 261 l +112 360 l + + +488 368 m +488 304 l +504 304 l +504 368 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +384 368 m +448 368 l + + +384 352 m +448 352 l + + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\bf\tiny NR-L1 +\tiny\bf NR\\ +MAC-RLC + +488 368 m +488 304 l +504 304 l +504 368 l +h + +\tiny PRECODE +\tiny PRECODE + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + +\tiny\bf NR\\ +MODEM + +512 368 m +576 368 l + + +512 352 m +576 352 l + + +560 231 m +560 160 l +656 160 l +656 231 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +336 264 m +536 264 l + + +336 248 m +536 248 l + + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\bf\tiny LTE-L1 + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\tiny\bf LTE\\ +MAC-RLC + +488 368 m +488 304 l +504 304 l +504 368 l +h + +\tiny PRECODE + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + +\tiny\bf LTE\\ +MODEM + +232 264 m +256 264 l + + +256 424 m +224 424 l +224 316 l +256 316 l + + +64 264 m +64 264 l + + +528 288 m +528 208 l +736 208 l +736 288 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\tiny\bf NR\\ +MAC-RLC + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\tiny\bf NB-IoT\\ +MAC-RLC + +128 264 m +8 264 l + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +336 264 m +536 264 l + + +336 248 m +536 248 l + + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\bf\tiny NR-L1 + +488 368 m +488 304 l +504 304 l +504 368 l +h + +\tiny PRECODE + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + +\tiny\bf NR\\ +MODEM + +528 288 m +528 208 l +736 208 l +736 288 l +h + +\tiny\bf Remote Radio-Unit (RRU) + +336 72 m +576 72 l + + +336 86 m +576 88 l + + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\tiny\bf NB-IoT\\ +RRC + +128 264 m +8 264 l + + +104 360 m +104 88 l +120 88 l + + +192 88 m +256 88 l + + +528 64 m +528 32 l +640 32 l +640 64 l +h + +\tiny\bf NB-IoT\\ +L1/MODEM + +224 384 m +208 384 l + + +192 240 m +256 240 l + + +232 240 m +232 168 l +256 168 l + + +224 192 m +224 192 l + + +224 192 m +224 192 l + + +224 312 m +224 72 l +256 72 l + + + + + +OAI Functional Splits +\tiny\begin{itemize} +\item OAI currently implements the following entities in openairinterface5g +\begin{itemize} +\item LTE-MODEM (eNB 36.211 OFDM modulation/demodulation) +\item LTE-L1 (eNB 36.211/212/213) +\item LTE-MACRLC (eNB 36.321/322) +\item LTE-PDCP (eNB PDCP/GTPU 36.323) +\item LTE-RRC (eNB RRC/SCTP 36.331) +\end{itemize} +\item Each entity comprises +\begin{itemize} +\item a northbound interface (backhaul/midhaul/fronthaul and configuration) +\item a southbound interface (midaul/fronthaul and configuration) +\item one or two management interfaces +\item Three computing nodes +\begin{itemize} +\item {\bf Radio Cloud Center (RCC)} : multiple RRC/PDCP entities +\item {\bf Radio-Access Unit (RAU)}: multiple MACRLC entities with medium-latency midhaul and L1 entities with low-latency fronthaul. +\item {\bf Remote Radio-Unit (RRU)}: Equipment at radio site. Varying degrees of processing elements depending on fronthaul/midhaul interface. +\end{itemize} +\end{itemize} +\item Each entity has a configuration which is a local file or received via the management interface +\item default interface between all entities is implemented using a UDP socket. Transport is configurable via a dynamically-loadable networking device +\end{itemize} + +288 192 m +288 64 l +432 64 l +432 192 l +h + +OAI entity + +336 171 m +336 208 l + + +384 171 m +384 208 l + + +336 171 m +336 208 l + + +384 171 m +384 208 l + + +240 80 m +288 80 l + + +240 80 m +288 80 l + + +16 0 0 16 288 224 e + + +16 0 0 16 288 224 e + +\tiny\bf Northbound interface +\tiny\bf Southbound interface +\tiny\bf data +\tiny\bf data +\tiny\bf in-band configuration +\tiny\bf in-band configuration +\tiny\bf OSS/BSS +\tiny\bf FlexRAN + +240 80 m +288 80 l + +\tiny\tt .conf + + + + + +511.895 513.539 m +511.895 14.2386 l +734.284 14.2386 l +734.284 513.539 l +h + + +511.895 513.539 m +511.895 14.2386 l +734.284 14.2386 l +734.284 513.539 l +h + + +511.895 513.539 m +511.895 14.2386 l +734.284 14.2386 l +734.284 513.539 l +h + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +16 432 m +16 112 l +192 112 l +192 432 l +h + +Functional Splits (Current) + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +RRC +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-C +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-U +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX +\end{tiny} + + +384 432 m +384 384 l + + +384 432 m +384 384 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt rf\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +RRC +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-C +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-U +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +3GPP\_eNodeB +3GPP\_BBU +\tiny to MME +\tiny to S-PGw + +384 432 m +384 384 l + + +384 432 m +384 384 l + +\tiny to MME +\tiny to S-PGw + +160 112 m +160 112 l +160 112 l +160 112 l +h + + +144 112 m +144 112 l +144 112 l +144 112 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt USB3 or PCIe} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF5 / ethernet} +\end{tiny} + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +RRC +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-C +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-U +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +upper-PHY RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +NGFI\_RCC (IF4.5) + +384 432 m +384 384 l + + +384 432 m +384 384 l + +\tiny to MME +\tiny to S-PGw + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF4p5 / ethernet} +\end{tiny} + +\setstretch{.5}\begin{tiny} +upper-PHY TX +\end{tiny} + + +384 432 m +384 384 l + +\tiny to NGFI\_RRU + +384 432 m +384 384 l + +\tiny to NGFI\_RRU or RRH\_gw + +384 432 m +384 384 l + +\tiny to RF Device + + + + + +1.83417 462.604 m +1.83417 50.8252 l +207.006 50.8252 l +207.006 462.604 l +h + + +1.83417 462.604 m +1.83417 50.8252 l +207.006 50.8252 l +207.006 462.604 l +h + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +RRC +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-C +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-U +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +NGFI\_RCC (IF1'') + +384 432 m +384 384 l + + +384 432 m +384 384 l + +\tiny to MME +\tiny to S-PGw + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF1pp} / ethernet +\end{tiny} + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +RRC +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-C +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-U +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +NGFI\_RCC (IF1') + +384 432 m +384 384 l + + +384 432 m +384 384 l + +\tiny to MME +\tiny to S-PGw + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF1p} / ethernet +\end{tiny} + +\tiny to NGFI\_RRU + +384 432 m +384 384 l + +\tiny to NGFI\_RAU + +384 432 m +384 384 l + +\tiny to NGFI\_RAU +Functional Splits (Current) + +1.83417 462.604 m +1.83417 50.8252 l +207.006 50.8252 l +207.006 462.604 l +h + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +upper-PHY RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +NGFI\_RAU(IF1'') + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF4p5 / ethernet} +\end{tiny} + +\setstretch{.5}\begin{tiny} +upper-PHY TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF1pp / ethernet} +\end{tiny} + + +384 432 m +384 384 l + +\tiny to NGFI\_RCC + +384 432 m +384 384 l + +\tiny to NGFI\_RRU + + + + + +1.83417 462.604 m +1.83417 50.8252 l +207.006 50.8252 l +207.006 462.604 l +h + + +1.83417 462.604 m +1.83417 50.8252 l +207.006 50.8252 l +207.006 462.604 l +h + + +1.83417 462.604 m +1.83417 50.8252 l +207.006 50.8252 l +207.006 462.604 l +h + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +NGFI\_RRU (IF5) + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF5/ ethernet} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt rf\_device} +\end{tiny} + +NGFI\_RRU (IF4.5) + +384 432 m +384 384 l + +\tiny to NGFI\_RCC, NGFI\_RAU,3GPP\_BBU + +384 432 m +384 384 l + +\tiny to RF Device + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt USB3, PCIe, CPRI} +\end{tiny} + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF4p5/ ethernet} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt rf\_device} +\end{tiny} + + +384 432 m +384 384 l + +\tiny to NGFI\_RCC, NGFI\_RAU + +384 432 m +384 384 l + +\tiny to RF Device + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt USB3, PCIe, CPRI} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +lower-PHY RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +lower-PHY TX +\end{tiny} + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +\setstretch{.5}\begin{tiny} +upper-PHY TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF1pp\_4P5 / ethernet} +\end{tiny} + + +384 432 m +384 384 l + +\tiny to NGFI\_RCC, NGFI\_RAU + +384 432 m +384 384 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt USB3, PCIe, CPRI} +\end{tiny} + +\tiny to RF Device +Functional Splits (Current) +NGFI\_RRU\par +(IF1'') + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +lower-PHY RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +lower-PHY TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +upper-PHY RX +\end{tiny} + + + + + +Some Notes on usage of splits +\tiny\begin{itemize} +\item IF4p5 corresponds to the split-point at the input (TX) and output (RX) of the OFDM symbol generator (i.e. frequency-domain signals). According to NGFI, IF4 is "Resource mapping and IFFT" and "FFT and Resource demapping". We currently do not try to exploit multiplexing gains for unused spectral components. So, IF4p5 is simply compressed transmitted or received resource elements in the usable channel band. +\item The simplest deployment for DAS (indoor) is one NGFI\_RCC (IF4p5) and many NGFI\_RRU (IF4p5). Spatio-temportal filtering (Precoding, later) is done in RCC and RRU perform IFFT/FFT and signal generation/acquisition. Fronthaul rates in this case are feasible with 1GbE copper links. This allows for PoE in addition to fronthaul data. +\item More complex indoor, for instance with RCC in a common data center with outdoor RRS, could be +\begin{enumerate} + \item RCC-RAU with IF1'', RAU-RRU with IF4p5. Spatio-temporal filtering is done in frequency-domain in RAU along with full TX and RX processing (L1/L2) for the indoor RRS. Note that IF1' fronthaul on TX to RRU would be difficult because spatio-temporal filtering should be used. RRU does only IFFT/FFT and signal generation/acquisition +\item RCC-RAU with IF1', RAU-RRU with IF4p5. Here RCC does L2, RAU does L1 and precoding for RRS. +\end{enumerate} +\item A massive-MIMO solution would consist either of +\begin{enumerate} +\item an embedded RAU with processing (Spatio-temporal in frequency-domain, lower/upper PHY TX/RX) like the IF1' DAS solution above +\item or more simply a high-speed fronthaul (IF4p5) with an RAU for multiple sites +\item directly connected to RCC via high-speed IF4p5 (several virtual cells, precoder and IFFT/FFT in array). +\end{enumerate} +\item RCC solution with IF1'' would cater to evolved-PDCP for heterogenity (4G,5G,WIFI,IoT) +\item Currently supported node functionalities +\begin{enumerate} +\item {\tt 3GPP\_eNodeB} +\item {\tt 3GPP\_eNodeB\_BBU} [NGFI\_IF5] +\item {\tt NGFI\_RCC} [NGFI\_IF4p5] +\item {\tt NGFI\_RRU} [NGFI\_IF5] +\item {\tt NGFI\_RRU} [NGFI\_IF4p5] +\end{enumerate} +\end{itemize} + + + + +RU - L1 negotiation + +64 448 m +64 256 l +256 256 l +256 448 l +h + + +64 448 m +64 256 l +256 256 l +256 448 l +h + +RRU Entity +RAU/RCC Entity + +544 192 m +544 256 l + + +256 320 m +448 320 l + + +448 288 m +256 288 l + + +544 192 m +544 256 l + +\tiny\tt .conf +\tiny\tt .conf +\tiny\tt fronthaul data (IF5,IF4p5) + +256 320 m +448 320 l + + +448 288 m +256 288 l + +\tiny\tt RRU control/config +\begin{small} +Control and Configuration protocol +\begin{enumerate} +\item RAU$\rightarrow$ RRU : heartbeat (capabilities request) +\item RRU$\rightarrow$ RAU: capabilities indication +\item RAU$\rightarrow$ RRU: configuration (band, dl\_Carrier,ul\_Carrier, dl\_RS\_EPRE, rx/tx attenuation) +\end{enumerate} +\end{small} +During steady state, the control port manages the link quality and status (packet losses, synchronization state, start/stop, etc.) + + + + +\begin{small} +\begin{itemize} +\item IF5 interface +\begin{itemize} +\item DL subframes with timestamp (16-bit samples) +\item UL subframes with timestamp (16-bit samples) +\item optional A-law compression (13$\rightarrow$8bit) +\end{itemize} +\item IF4p5 interface +\begin{itemize} +\item DL packets, ofdm symbols with frame/subframe/symbol count +\item UL packets, ofdm symbols with frame/subframe/symbol count (16-bit) +\item UL PRACH packets with frame/subframe count (16-bit) +\item optional A-law compression (13$\rightarrow$8bit) +\end{itemize} +\end{itemize} +\end{small} +RU - L1 data plane + + + + + +544 288 m +544 256 l +704 256 l +704 288 l +h + +IF5 Packet Format (16-bit) + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + +0 +16 +32 +48 +15 +31 +47 +63 + +64 320 m +64 288 l +544 288 l +544 320 l +h + + +544 320 m +544 288 l +704 288 l +704 320 l +h + + +64 288 m +64 256 l +384 256 l +384 288 l +h + + +384 288 m +384 256 l +544 256 l +544 288 l +h + + +544 288 m +544 256 l +704 256 l +704 288 l +h + +\small Destination Address +\small Source +\small Type (0x1234) +\small RF Config +\small Address + +64 160 m +64 128 l +384 128 l +384 160 l +h + +\small Frame Check Sequence + +256 240 m +256 240 l +256 240 l + +\small Timestamp + +5 63.5079 m +5 46.9999 l +645 46.9999 l +645 63.5079 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +256 240 m +256 240 l +256 240 l + + +166 304 m +165.917 272.508 l +166.247 272.508 l + + +486 304 m +486.316 272.508 l +485.986 272.508 l + + +486.316 256 m +486.646 224 l +485.657 224 l + + +486.316 256 m +486.646 224 l +485.657 224 l + +\tiny $I_0$ +\tiny $Q_0$ +\tiny $I_1$ +\tiny $Q_1$ +\tiny $Q_{N-2}$ +\tiny $Q_{N-2}$ +\tiny $I_{N-1}$ +\tiny $Q_{N-1}$ +\tiny +\begin{itemize} +\item {\bf Type:} 2 byte (16 bit) field that specifies the RoE protocol +\item {\bf RX Config:} 16-bit. Currently just antenna index (0-7). Can later be used for gain/timing adjustments. +\item {\bf Timstamp:} Timestamp in samples of the first sample of the received packet. +\end{itemize} +\begin{itemize} +\item {\bf data block :} Uncompressed IQ samples, 16-bit resolution for each real and imaginary component. $N$ complex samples per packet. $N$ can be configured at initialization. +\end{itemize} + + + + +IF5 Packet Format (8-bit) + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + +0 +16 +32 +48 +15 +31 +47 +63 + +64 320 m +64 288 l +544 288 l +544 320 l +h + + +544 320 m +544 288 l +704 288 l +704 320 l +h + + +64 288 m +64 256 l +384 256 l +384 288 l +h + + +384 288 m +384 256 l +544 256 l +544 288 l +h + + +544 288 m +544 256 l +704 256 l +704 288 l +h + + +384 256 m +384 224 l +704 224 l +704 256 l +h + +\small Destination Address +\small Source +\small Type (0xBEEF) +\small RX Flags +\small Address + +544 288 m +544 256 l +704 256 l +704 288 l +h + +\small FIFO\_status + +544 288 m +544 256 l +704 256 l +704 288 l +h + +\tiny SeqNum +\tiny rsvd + +248.997 435.732 m +248.997 403.732 l + +\small Word0 + +5 63.5079 m +5 46.9999 l +645 46.9999 l +645 63.5079 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +166 304 m +165.917 272.508 l +166.247 272.508 l + + +486 304 m +486.316 272.508 l +485.986 272.508 l + + +486.316 256 m +486.646 224 l +485.657 224 l + +\tiny $I_0$ + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + +\tiny $Q_0$ +\tiny $I_1$ +\tiny $Q_1$ +\tiny $I_2$ +\tiny $Q_2$ +\tiny $I_3$ +\tiny $Q_3$ +\tiny $I_{638}$ +\tiny $Q_{638}$ +\tiny $I_{639}$ +\tiny $Q_{639}$ +\tiny +\begin{itemize} +\item {\bf Type:} 2 byte (16 bit) field that specifies the RoE protocol +\item {\bf RX Flags:} overrun indicator. should be '0'. +\item {\bf FIFO status:} 2 bytes. should be '0'. +\item {\bf SeqNum:} 1 byte. Sequence number of the ethernet packet. +\item {\bf rsvd:} 1 byte. shoult be '0'. \item {\bf Word0:} 4 byte (32-bit). should be '0'. +\item {\bf Timstamp:} Timestamp in samples of the first sample of the received packet. \end{itemize} +\begin{itemize} +\item {\bf data block :} Uncompressed IQ samples, 8-bit resolution for each real and imaginary component. 640 complex samples per packet. +\end{itemize} + +384 256 m +384 224 l +704 224 l +704 256 l +h + +\small Timestamp + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +486 304 m +486.316 272.508 l +485.986 272.508 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + +\tiny $I_4$ +\tiny $Q_4$ +\tiny $I_5$ +\tiny $Q_5$ + +64 160 m +64 128 l +384 128 l +384 160 l +h + +\small Frame Check Sequence + + + + +IF4p5 Packet Formats (RAW) + +272 512 m +272 512 l +272 512 l +272 512 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + +0 +16 +32 +48 +15 +31 +47 +63 + +64 320 m +64 288 l +544 288 l +544 320 l +h + + +544 320 m +544 288 l +704 288 l +704 320 l +h + + +64 288 m +64 256 l +384 256 l +384 288 l +h + + +384 288 m +384 256 l +544 256 l +544 288 l +h + + +544 288 m +544 256 l +704 256 l +704 288 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +384 256 m +384 224 l +704 224 l +704 256 l +h + + +64 160 m +64 96 l +704 96 l +704 160 l +h + +\small Destination Address +\small Source +\small Type (0x080A) +\small Subtype (0x0021) +\small Address +\small LTE PRACH Configuration +\small Reserved +\small PRACH data block (one antenna) + +64 160 m +64 128 l +384 128 l +384 160 l +h + +\small Frame Check Sequence + +384 160 m +384 128 l +704 128 l +704 160 l +h + +IF4p5 PRACH Packet (RRU$\rightarrow$ RAU,RCC) +\tiny +\begin{itemize} +\item {\bf Type:} 2 byte (16 bit) field that specifies the RoE protocol +\item {\bf Subtype:} 2 byte (16 bit) field that specifies the packet subtype +\item {\bf Reserved:} 4 byte (32 bit) field reserved +\item {\bf LTE PRACH conf:} 4 byte (32-bit) field that details the configuration of the LTE PRACH packet +\end{itemize} +\vskip 3pt +\begin{tabular}{|c|c|} +\hline +{\bf field (0 is LSB, 31 is MSB)} & {\bf description}\\ \hline +rsvd (0:2) & Reserved.\\ \hline +ant (3:5) & 3-bit Antenna index of LTE PRACH packet\\ \hline +RF Num (6:21) & 16-bit field indicating the Radio Frame number of this received PRACH packet\\ \hline +SF Num (22:25) & 4-bit field indicating the sub-frame number in the radio frame for the LTE PRACH packet\\ + & Valid range of 0 to 9.\\ \hline +Exponent (26:31) & FFT exponent output (0 if unscaled) \\ +\hline +\end{tabular} +\begin{itemize} +\item {\bf PRACH data block:} Uncompressed IQ samples +\end{itemize} + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + +\tiny RE 0 (Real) +\tiny RE 0 (Imag) +\tiny RE 1 (Real) +\tiny RE 1 (Imag) + +166 304 m +165.917 272.508 l +166.247 272.508 l + + +486 304 m +486.316 272.508 l +485.986 272.508 l + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + +\tiny RE 837 (Real) +\tiny RE 837 (Imag) +\tiny RE 838 (Real) +\tiny RE 838 (Imag) + +166 304 m +165.917 272.508 l +166.247 272.508 l + + +486 304 m +486.316 272.508 l +485.986 272.508 l + + +6.00001 47.492 m +6.00001 32 l +646 32 l +646 47.492 l +h + + +528 16 m +528 16 l +528 16 l +528 16 l +h + + +560 16 m +560 16 l +560 16 l +560 16 l +h + + + + + + +64 224 m +64 192 l +224 192 l +224 224 l +h + + +224 224 m +224 192 l +384 192 l +384 224 l +h + + +384 224 m +384 192 l +544 192 l +544 224 l +h + + +544 224 m +544 192 l +704 192 l +704 224 l +h + + +64 192 m +64 160 l +224 160 l +224 192 l +h + + +224 192 m +224 160 l +384 160 l +384 192 l +h + + +384 192 m +384 160 l +544 160 l +544 192 l +h + + +544 192 m +544 160 l +704 160 l +704 192 l +h + +\small Gain 0 +\small Gain 1 +\small Gain 4 +\small Gain 5 +\small Gain 2 +\small Gain 3 +\small Gain 6 +\small Gain 7 + +272 512 m +272 512 l +272 512 l +272 512 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + +0 +16 +32 +48 +15 +31 +47 +63 + +64 320 m +64 288 l +544 288 l +544 320 l +h + + +544 320 m +544 288 l +704 288 l +704 320 l +h + + +64 288 m +64 256 l +384 256 l +384 288 l +h + + +384 288 m +384 256 l +544 256 l +544 288 l +h + + +544 288 m +544 256 l +704 256 l +704 288 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +384 256 m +384 224 l +704 224 l +704 256 l +h + +\small Destination Address +\small Source +\small Type (0x080A) +\small Subtype (0x0019) +\small Address +\small Frame status +\small Reserved + +64 160 m +64 128 l +384 128 l +384 160 l +h + +\small Frame Check Sequence +\tiny +\begin{itemize} +\item {\bf Type:} 2 byte (16 bit) field that specifies the RoE protocol +\item {\bf Subtype:} 2 byte (16 bit) field that specifies the packet subtype +\item {\bf Reserved:} 4 byte (32 bit) field reserved +\item {\bf Frame Status:} 4 byte (32 bit) field +\end{itemize} +\vskip 3pt +\begin{tabular}{|c|c|} +\hline +{\bf field (0 is LSB, 31 is MSB)} & {\bf description}\\ \hline +{\bf ant} (0:2) & The number of Antenna Carriers represented in the packet. Antenna numbers \\ +& range from 0 to 7 with valid inputs being 0,1, 3 and 7 (1,2,4,8 antennas)\\ \hline +{\bf ant start} (3:5) & starting antenna number\\ \hline +{\bf RF Num} (6:21) & 16-bit field indicating the Radio Frame number of the UL\_RE samples\\ \hline +{\bf SF Num} (22:25) & 4-bit field indicating the sub-frame number in the radio frame for the UL\_RE samples\\ + & Valid range of 0 to 9.\\ \hline +{\bf Sym Num:} (26:29) & Symbol number. Valid range of 0 to 13. \\ +{\bf rsvd:} (30:31) & reserved\\ +\hline +\end{tabular} +\begin{itemize} +\item {\bf ULRE data block:} compressed IQ samples (8-bit A-law). $N$ is the number of resource elements $N_{\mathrm{RB}}^{\mathrm{UL}}$. +\end{itemize} + +5 63.5079 m +5 46.9999 l +645 46.9999 l +645 63.5079 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + +IF4p5 Packets : ULRE (RRU$\rightarrow$ RAU,RCC) + +256 240 m +256 240 l +256 240 l + + +166 304 m +165.917 272.508 l +166.247 272.508 l + + +486 304 m +486.316 272.508 l +485.986 272.508 l + + +486.316 256 m +486.646 224 l +485.657 224 l + + +486.316 256 m +486.646 224 l +485.657 224 l + + +258.16 141.771 m +258.16 141.771 l + + +418.597 191.907 m +418.597 191.907 l + + +429.181 79.9357 m +429.181 79.9357 l + +\tiny RE 0\\Ant 1 (Re) +\tiny RE 0\\Ant 1 (Im) +\tiny RE 1\\Ant 1 (Re) +\tiny RE 1\\Ant 1 (Im) +\tiny RE 2\\Ant 1 (Re) +\tiny RE 2\\Ant 1 (Im) +\tiny RE 3\\Ant 1 (Re) +\tiny RE 3\\Ant 1 (Im) +\tiny RE $N-4$\\Ant $R$ (Re) +\tiny RE $N-4$\\Ant $R$ (Im) +\tiny RE $N-3$\\Ant $R$ (Re) +\tiny RE $N-3$\\Ant $R$ (Im) +\tiny RE $N-2$\\Ant $R$ (Re) +\tiny RE $N-2$\\Ant $R$ (Im) +\tiny RE $N-1$\\Ant $R$ (Re) +\tiny RE $N-1$\\Ant $R$ (Im) + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + + + + + +272 512 m +272 512 l +272 512 l +272 512 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + +0 +16 +32 +48 +15 +31 +47 +63 + +64 320 m +64 288 l +544 288 l +544 320 l +h + + +544 320 m +544 288 l +704 288 l +704 320 l +h + + +64 288 m +64 256 l +384 256 l +384 288 l +h + + +384 288 m +384 256 l +544 256 l +544 288 l +h + + +544 288 m +544 256 l +704 256 l +704 288 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +384 256 m +384 224 l +704 224 l +704 256 l +h + +\small Destination Address +\small Source +\small Type (0x080A) +\small Subtype (0x0020) +\small Address +\small Frame status +\small Reserved + +64 160 m +64 128 l +384 128 l +384 160 l +h + +\small Frame Check Sequence +\tiny +\begin{itemize} +\item {\bf Type:} 2 byte (16 bit) field that specifies the RoE protocol +\item {\bf Subtype:} 2 byte (16 bit) field that specifies the packet subtype +\item {\bf Reserved:} 4 byte (32 bit) field reserved +\item {\bf Frame Status:} 4 byte (32 bit) field +\end{itemize} +\vskip 3pt +\begin{tabular}{|c|c|} +\hline +{\bf field (0 is LSB, 31 is MSB)} & {\bf description}\\ \hline +{\bf ant} (0:2) & The number of Antenna Carriers represented in the packet. Antenna numbers \\ +& range from 0 to 7 with valid inputs being 0,1, 3 and 7 (1,2,4,8 antennas)\\ \hline +{\bf ant start} (3:5) & starting antenna number\\ \hline +{\bf RF Num} (6:21) & 16-bit field indicating the Radio Frame number of this DLRE packet\\ \hline +{\bf SF Num} (22:25) & 4-bit field indicating the sub-frame number in the radio frame for the DLRE packet\\ + & Valid range of 0 to 9.\\ \hline +{\bf Sym Num:} (26:29) & Symbol number. Valid range of 0 to 13. \\ +{\bf rsvd:} (30:31) & reserved\\ +\hline +\end{tabular} +\begin{itemize} +\item DLRE data block : compressed IQ samples (8-bit A-law). $N$ is the number of resource elements $N_{\mathrm{RB}}^{\mathrm{DL}}$. +\end{itemize} +IF4p5 Packets : DLRE (RAU,RCC $\rightarrow$RRU) + +258.16 141.771 m +258.16 141.771 l + + +418.597 191.907 m +418.597 191.907 l + + +429.181 79.9357 m +429.181 79.9357 l + + +5 63.5079 m +5 46.9999 l +645 46.9999 l +645 63.5079 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +166 304 m +165.917 272.508 l +166.247 272.508 l + + +486 304 m +486.316 272.508 l +485.986 272.508 l + + +486.316 256 m +486.646 224 l +485.657 224 l + + +486.316 256 m +486.646 224 l +485.657 224 l + +\tiny RE 0\\Ant 1 (Re) +\tiny RE 0\\Ant 1 (Im) +\tiny RE 1\\Ant 1 (Re) +\tiny RE 1\\Ant 1 (Im) +\tiny RE 2\\Ant 1 (Re) +\tiny RE 2\\Ant 1 (Im) +\tiny RE 3\\Ant 1 (Re) +\tiny RE 3\\Ant 1 (Im) +\tiny RE $N-4$\\Ant $R$ (Re) +\tiny RE $N-4$\\Ant $R$ (Im) +\tiny RE $N-3$\\Ant $R$ (Re) +\tiny RE $N-3$\\Ant $R$ (Im) +\tiny RE $N-2$\\Ant $R$ (Re) +\tiny RE $N-2$\\Ant $R$ (Im) +\tiny RE $N-1$\\Ant $R$ (Re) +\tiny RE $N-1$\\Ant $R$ (Im) + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + + + + + +640 128 m +640 32 l +704 32 l +704 128 l +h + + +640 480 m +640 176 l +720 176 l +720 480 l +h + + +328.159 119.72 m +328.159 15.3556 l +554.022 15.3556 l +554.022 119.72 l +h + + +96 784 m +96 496 l +224 496 l +224 784 l +h + + +-192 928 m +-192 944 l +-192 944 l +-192 928 l +h + + +96 784 m +96 496 l +224 496 l +224 784 l +h + +\begin{small}L1 Instance 0\end{small} +LI instance 1 +\begin{small}MAC/RLC/PDCP Instance 0\end{small} + +364 518 m +364 518 l +364 518 l +364 518 l +h + + +96 784 m +96 496 l +224 496 l +224 784 l +h + + +128 768 m +128 704 l +192 704 l +192 768 l +h + +\setstretch{.5}\begin{tiny} +DL/UL Scheduler +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + + +180 460 m +340 460 l + + +180 460 m +340 460 l + +\begin{tiny}1ms TICK\end{tiny} + +392.067 448.35 m +232.502 360 l + +\begin{tiny}$\mathrm{DCI}_0$, Transport Blocks\end{tiny} + +\begin{tiny}$\mathrm{DCI}_1$\end{tiny} + +\begin{tiny}$\mathrm{DCI}_2$\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_0$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_1$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_2$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_0$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_1$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_2$ +\end{tiny} + + +234.502 211.006 m +387 210 l + + +243.386 213.48 m +243.386 213.48 l + + +232.502 250.102 m +387.004 250.371 l + + +232.502 310 m +387 310 l + + +232.502 346.88 m +387 347 l + + +336.917 451.424 m +185.872 274.589 l + + +232.5 410 m +386.079 409.083 l + +\begin{tiny}Transport Blocks\end{tiny} + +\begin{tiny}Transport Blocks\end{tiny} + +\setstretch{.5}\begin{tiny}CQI/SR/ACK/NAK/PHR\\Transport Blocks\end{tiny} +\setstretch{.5}\begin{tiny}CQI/SR/ACK/NAK/PHR\\Transport Blocks\end{tiny} +\setstretch{.5}\begin{tiny}CQI/SR/ACK/NAK/PHR\\Transport Blocks\end{tiny} + +180 460 m +340 460 l + + +180 460 m +340 460 l + +\begin{tiny}1ms TICK\end{tiny} +\begin{tiny}$\mathrm{DCI}_0$, Transport Blocks\end{tiny} + + +184.502 313 m +332 313 l + +\begin{small}MAC/RLC/PDCP Instance 1\end{small} + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX \\ +$\mathrm{eNB}_0$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX \\ +$\mathrm{eNB}_0$ +\end{tiny} + +\setstretch{.5}\begin{tiny}CQI/SR/ACK/NAK/PHR\\Transport Blocks\end{tiny} + +128 768 m +128 704 l +192 704 l +192 768 l +h + +\setstretch{.5}\begin{tiny} +DL/UL Scheduler +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + +RU/L1 Instances and Component Carriers + +96 784 m +96 496 l +224 496 l +224 784 l +h + + +96 784 m +96 496 l +224 496 l +224 784 l +h + + +364 518 m +364 518 l +364 518 l +364 518 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_3$ +\end{tiny} + + +144 480 m +144 32 l +176 32 l +176 480 l +h + + +176 432 m +176 432 l + + +192 464 m +176 464 l + + +190.041 464 m +190.041 464 l + + +190.041 464 m +190.041 464 l + + +192 464 m +176 464 l + + +192 464 m +176 464 l + + +192 464 m +176 464 l + + +192 464 m +176 464 l + + +192 464 m +176 464 l + + +192 464 m +176 464 l + + +192 464 m +176 464 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_0$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_1$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_2$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_4$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_5$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_6$ +\end{tiny} + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +640 400 m +640 400 l +640 400 l +640 400 l +h + + + + + +\small\begin{itemize} +\item {\em Radio Unit} (RU) is +\begin{itemize} +\item an entity managing a set of {\bf physical} antennas. It can have a {\em local RF unit} or {\em remote RF unit} +\item performs precoding of multiple eNB TX streams and OFDM modulation (TX) and demodulation (RX) (part of 36.211) +\end{itemize} +\item {\em L1 Instance} (indexed by {\tt Mod\_id}, or {\tt enb\_mod\_id}) is a separate set of threads and contexts for the eNB/gNB procedures. There is one MAC/RLC entity associated to all :1 component carriers. +\item {\em L1 Component Carrier} (indexed by {\tt CC\_id}) is +\begin{itemize} +\item a software entity managing the L1 procedures (36.213,36.212,36.211) and can act on +\begin{itemize} +\item sectored antenna component +\item Rel10+ component carrier +\item virtual cell for DAS or Massive-MIMO array +\end{itemize} +\item each L1 instance is managed by one or two threads which operate on a subframe (TX and RX) and can have a {\em local RU} or {\em remote RU} +\item if a remote radio unit the eNB performs the 36.213 specifications only (HARQ, etc.) and connects to the remainder via the IF2 midhaul interface. +\end{itemize} +\end{itemize} +RU/L1 Instances and Component Carriers + + + + +RU/L1 Instances and Component Carriers +\small\begin{itemize} +\item RU may have both an {\tt if\_device} for fronthaul and an {\tt rf\_device} for interconnection with a local RF unit +\item if the {\tt rf\_device} is absent, it must have a southbound fronthaul interface (either IF5 or IF4p5) depending on the local processing of the remote RU +\item if the {\tt if\_device} is absent, it must have a southbound RF interface and {\tt rf\_device}. +\item three types of L1 processing are performed by the RU \begin{itemize} +\item subset of common L1 procedures from 36.211 specifications +\item fronthaul compression/decompression +\item framing +\end{itemize} +\item on TX +\begin{itemize} +\item A-law compression for (NGFI\_RAU\_IF4p5, NGFI\_RAU\_IF5) +\item A-law decompression (for NGFI\_RRU\_IF4p5 and NGFI\_RRU\_IF5) +\item OFDM modulation and cyclic prefix insertion (for NGFI\_RRU\_IF4p5,NGFI\_RAU\_IF5,3GPP\_eNodeB\_BBU,3GPP\_eNodeB) +\item Precoding (for NGFI\_RAU\_IF5, NGFI\_RAU\_IF4p5,3GPP\_eNodeB\_BBU,3GPP\_eNodeB) +\end{itemize} +\end{itemize} + + + + +RU/L1 Instances and Component Carriers +\small\begin{itemize} +\item on RX +\begin{itemize} +\item A-law compression for (NGFI\_RRU\_IF4p5, NGFI\_RRU\_IF5) +\item A-law decompression (for NGFI\_RAU\_IF4p5 and 3GPP\_eNodeB\_BBU) +\item cyclic prefix removal, frequency-shifting, OFDM demodulation, PRACH DFT (for NGFI\_RRU\_IF4p5, NGFI\_RAU\_IF5, 3GPP\_eNodeB\_BBU, 3GPP\_eNodeB) +\end{itemize} +\item On TX path +\begin{itemize} +\item L1 instances/component carriers operate on a set of logical antenna ports (0-3 for TM1-6, 4 for eMBMS, 5 for TM7, 6 for positioning, 7-8 for TM8, etc.) +\item each L1 instance has a list of RUs and the logical antenna ports are mapped to the physical antennas attached to the RUs via the precoding function +\end{itemize} +\end{itemize} + + + + +\small\begin{itemize} +\item Example configurations +\begin{itemize} +\item {\em itsolated eNB:} one instance and one or several component carriers (multiple-frequencies or antenna sectors). Potentially multiple radio-units (for CoMP). Here there is a common MACRLC instnance driving multiple L1 procedures +\item {\em indoor DAS system (RCC split with L1/L2 RAU) Multiple layer 2 instances each driving one or more component carriers} here the RAU implements multiple L1/L2 instances and precoding function. Usually with IF2/IF1'' xhaul to RCC or potentially also MAC/RLC in RAU with IF1' xhaul to RCC. +\item {\em massive-MIMO array} same as 2nd indoor DAS system (i.e. integrated L1/L2 RAU with array) +\end{itemize} +\end{itemize} +RU/L1 Instances and Component Carriers + + + + + +288 384 m +288 96 l +672 96 l +672 384 l +h + + +301.83 142.941 m +301.83 103.286 l +648 104 l +648 144 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +301.83 142.941 m +301.83 103.286 l +648 104 l +648 144 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF4p5 / ethernet} +\end{tiny} + +\setstretch{.5}\begin{tiny} +upper-PHY TX (212,213) +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +389.83 375.941 m +389.83 336.286 l +616 336 l +616 376 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF1pp / ethernet} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +\setstretch{.5}\begin{tiny} +TX PRECODING\\RX COMBINING +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +\small\begin{itemize} +\item Example: RAU with {\tt NGFI\_IF1pp} xhaul (MAC/PHY split) northbound, {\tt NGFI\_IF4p5} fronthaul southbound, 2 vCell logical interfaces (2 L1/L2 instances, or 1 L2 instance and 2 CCs), 4 RRUs with {\tt NGFI\_IF4p5} + +\end{itemize} + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +upper-PHY RX (212,213) +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +upper-PHY RX (212,213) +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +upper-PHY TX (212,213) +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_0$ +\end{tiny} + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_1$ +\end{tiny} + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_2$ +\end{tiny} + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_3$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{eNB}_0$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{eNB}_1$ +\end{tiny} + +RAU Example (DAS) + + + + + +168 416 m +168 32 l +576 32 l +576 416 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX0 +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +176 176 m +176 136 l +552 136 l +552 176 l +h + +\setstretch{.5}\begin{tiny} +{\tt NGFI\_IF4p5 / ethernet} +\end{tiny} + +\setstretch{.5}\begin{tiny} +PHY TX0 +\end{tiny} + +184 360 m +184 336 l +552 336 l +552 360 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +184 408 m +184 368 l +552 368 l +552 408 l +h + +\setstretch{.5}\begin{tiny} +{\tt NGFI\_IF1p / ethernet} +\end{tiny} + + +184 264 m +184 224 l +552 224 l +552 264 l +h + +\setstretch{.5}\begin{tiny} +TX PRECODING\\RX COMBINING +\end{tiny} + +\small\begin{itemize} +\item Example: massive-MIMO RAU with {\tt NGFI\_IF1p} fronthaul northbound, 8 L1 component carriers,1 L2 instances, many local RRUs with {\tt NGFI\_IF4p5} southbound + +\end{itemize} + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX1 +\end{tiny} + +\setstretch{.5}\begin{tiny} +PHY TX1 +\end{tiny} + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX7 +\end{tiny} + +\setstretch{.5}\begin{tiny} +PHY TX7 +\end{tiny} + +184 320 m +184 288 l +552 288 l +552 320 l +h + +\setstretch{.5}\begin{tiny} +RLC +\end{tiny} + + +184 280 m +184 248 l +552 248 l +552 280 l +h + +\setstretch{.5}\begin{tiny} +MAC +\end{tiny} + + +376 208 m +448 208 l + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{eNB}_0$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{eNB}_1$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{eNB}_7$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_{0\cdots 15}$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_{16\cdots 31}$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_{32\cdots 47}$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_{48\cdots 63}$ +\end{tiny} + +RAU Example (Massive-MIMO) + + + + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +232 384 m +232 256 l +543.99 256 l +543.99 384 l +h + + +96 136 m +96 48 l +540 48 l +540 136 l +h + + +88 192 m +88 80 l +248 80 l +248 192 l +h + + +88 192 m +88 80 l +248 80 l +248 192 l +h + + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\small\begin{itemize} +\item IF5 transports packets of size equal to a subframe and corresponding to a 1ms chunk of signal in the time-domain. This is done via the functions send\_if5 and recv\_if5, in the layer1 transport procedures ({\tt openair1/PHY/LTE\_TRANSPORT/if5\_tools.c}). A timestamp is given along with the samples, corresponding to the time (in samples) of the first sample of the packet. +\item each block can be compressed with A-law compression, yielding a compression rate of .5. +\end{itemize} +RU Procedures (NGFI\_IF5) + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_2$ (211,212) +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_2$ (211,212) +\end{tiny} + + +144 480 m +144 32 l +176 32 l +176 480 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_0$ +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_1$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_0$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_1$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_0$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +132 294 m +132 208 l +384 208 l +384 294 l +h + + +144.991 145.396 m +289.432 145.382 l + + +144.991 120.982 m +289.432 121.382 l + +\tiny {\tt RU->ru\_time.rxdata[0]} +\tiny {\tt RU->ru\_time.rxdata[R-1]} + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\tt\tiny slot\_fep\_ul\par36.211 + +153 232 m +153 176 l +228 176 l +228 232 l +h + + +184 268 m +196 268 l + + +184 244 m +196 244 l + +\tiny {\tt eNB->common\_vars.rxdataF[0]} +\tiny {\tt eNB->common\_vars.rxdataF[R-1]} + +273 269 m +412 268 l + + +415.263 120.984 m +575 120.608 l + + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\tiny $\mathrm{Alaw}^{-1}()$ + +56 128 m +110.531 128.542 l + +\tiny from IF5 {\tt if\_device} + +680 104 m +680 104 l +680 104 l +680 104 l +h + + +544 324 m +544 144 l +576 144 l +576 324 l +h + +\setstretch{.5}\tt\tiny P\\R\\E\\C\\O\\D\\I\\N\\G\\ + +632 360 m +632 188 l +660 188 l +660 360 l +h + +\tiny {\tt RU->ru\_time.txdata[0]} + +700 264 m +735.133 264 l + + +632 264.556 m +671.833 265 l + +\setstretch{.5}\tt\tiny do\_ofdm\_mod\_rt()\par 36.211 +\setstretch{.5}\begin{tiny} +{\tt openair1/SCHED/ru-procedures.c} +\end{tiny} + + +517.232 240.387 m +576.078 240 l +576.078 240 l + + +517.232 240.387 m +576.078 240 l +576.078 240 l + + +517.232 240.387 m +576.078 240 l +576.078 240 l + + +517.232 240.387 m +576.078 240 l +576.078 240 l + +\tiny $\mathrm{Alaw}()$ +\tiny to IF5 {\tt if\_device} + +56 240 m +356.214 240.281 l + + +700 264 m +735.133 264 l + +\tiny {\tt RU->ru\_time.txdata[T-1]} +\setstretch{.5}\begin{tiny} +{\tt recv\_IF5()} +\end{tiny} + +\setstretch{.5}\begin{tiny} +{\tt send\_IF5()} +\end{tiny} + +\setstretch{.5}\begin{tiny} +{\tt ru\_fep\_full()} +\end{tiny} + +IF5 RU eNB end +\tiny $\mathrm{7.5kHz}()$ +\setstretch{.5}\begin{tiny} +{\tt ru\_thread()} +\end{tiny} + +\setstretch{.5}\begin{tiny} +{\tt ru\_thread\_asynch\_rxtx()} +\end{tiny} + + + + + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +96 136 m +96 48 l +540 48 l +540 136 l +h + + +88 192 m +88 80 l +248 80 l +248 192 l +h + + +88 192 m +88 80 l +248 80 l +248 192 l +h + + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\small\begin{itemize} +\item IF4p5 transports packets of size equal to an OFDM symbol (for DLRE and ULRE) indexed by the symbol, subframe and frame number. This is done via the functions send\_if4p5 and recv\_if4p5, in the layer1 transport procedures ({\tt openair1/PHY/LTE\_TRANSPORT/if4\_tools.c}). +\item each block are compressed with A-law compression, yielding a compression rate of .5. +\end{itemize} +RU Procedures (NGFI\_IF4p5) + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_2$ (211,212) +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_2$ (211,212) +\end{tiny} + + +144 480 m +144 32 l +176 32 l +176 480 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_0$ +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_1$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_0$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_1$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_0$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +175.991 137.396 m +575 138.93 l + + +175.991 112.982 m +575 114.329 l + + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\tiny $\mathrm{Alaw}^{-1}()$ + +56 120 m +141.531 120.07 l + +\tiny from IF4p5 {\tt if\_device} + +680 104 m +680 104 l +680 104 l +680 104 l +h + + +544 324 m +544 144 l +576 144 l +576 324 l +h + +\setstretch{.5}\tt\tiny P\\R\\E\\C\\O\\D\\I\\N\\G\\ + +700 264 m +735.133 264 l + +\setstretch{.5}\begin{tiny} +{\tt openair1/SCHED/ru-procedures.c} +\end{tiny} + + +517.232 240.387 m +576.078 240 l +576.078 240 l + + +517.232 240.387 m +576.078 240 l +576.078 240 l + + +517.232 240.387 m +576.078 240 l +576.078 240 l + + +517.232 240.387 m +576.078 240 l +576.078 240 l + +\tiny $\mathrm{Alaw}()$ +\tiny to IF4p5 {\tt if\_device} + +56 240 m +356.214 240.281 l + + +700 264 m +735.133 264 l + +\setstretch{.5}\begin{tiny} +{\tt recv\_IF4p5()} +\end{tiny} + +\setstretch{.5}\begin{tiny} +{\tt send\_IF4p5()} +\end{tiny} + +IF4p5 RU eNB end + +153 232 m +153 176 l +228 176 l +228 232 l +h + + +111.191 120.045 m +112 70 l +142 69.9344 l + + +-36 68 m +-36 68 l + + +175.991 112.982 m +575 114.329 l + +\tiny {\tt eNB->common\_vars.rxdataF[0]} +\tiny {\tt eNB->common\_vars.rxdataF[R-1]} +\tiny {\tt eNB->prach\_vars.prachF[0$\cdots$ R-1]} +\setstretch{.5}\begin{tiny} +{\tt ru\_thread()} +\end{tiny} + + + + + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +232 384 m +232 256 l +543.99 256 l +543.99 384 l +h + + +96 136 m +96 48 l +540 48 l +540 136 l +h + + +132 294 m +132 208 l +384 208 l +384 294 l +h + + +96 384 m +96 148 l +544 148 l +544 256 l +224 256 l +224 384 l +h + + +444 164 m +444 84.382 l +522.222 84.382 l +522.222 164 l +h + + +132 294 m +132 208 l +384 208 l +384 294 l +h + + +444 164 m +444 84.382 l +522.222 84.382 l +522.222 164 l +h + + +153 232 m +153 176 l +228 176 l +228 232 l +h + +RU Procedures (NGFI\_IF4p5) +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_0$ +\end{tiny} + + +144.991 145.396 m +289.432 145.382 l + + +144.991 120.982 m +289.432 121.382 l + +\tiny {\tt RU->ru\_time.rxdata[0]} +\tiny {\tt RU->ru\_time.rxdata[R-1]} + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\tt\tiny slot\_fep\_ul\par36.211 + +153 232 m +153 176 l +228 176 l +228 232 l +h + + +184 268 m +196 268 l + + +184 244 m +196 244 l + + +273 269 m +412 268 l + + +415.263 120.984 m +575 120.608 l + + +56 128 m +110.531 128.542 l + +\tiny from {\tt rf\_device} + +680 104 m +680 104 l +680 104 l +680 104 l +h + + +632 360 m +632 188 l +660 188 l +660 360 l +h + +\tiny {\tt RU->ru\_time.txdata[0]} + +380.13 336.98 m +149.46 336.349 l + + +632 264.556 m +671.833 265 l + +\setstretch{.5}\tt\tiny do\_ofdm\_mod\_rt()\par 36.211 +\setstretch{.5}\begin{tiny} +{\tt openair1/SCHED/ru-procedures.c} +\end{tiny} + +\tiny to {\tt rf\_device} + +58 240 m +114.121 240.053 l + + +380.45 296 m +149.46 295.058 l + +\tiny {\tt RU->ru\_time.txdata[T-1]} +\setstretch{.5}\begin{tiny} +{\tt ru\_fep\_full()} +\end{tiny} + +IF4p5 RU remote-end + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\tiny $\mathrm{Alaw}^{-1}()$ + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\tiny $\mathrm{Alaw}()$ +\tiny $\mathrm{7.5kHz}()$ + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\begin{tiny} +{\tt recv\_IF4p5()} +\end{tiny} + +\setstretch{.5}\begin{tiny} +{\tt send\_IF4p5()} +\end{tiny} + + +485.71 128.939 m +581.963 129.331 l + +\tiny to {\tt if\_device} +\tiny from {\tt if\_device} + +58 240 m +114.121 240.053 l + + +131 344 m +131 316 l +276 316 l +276 344 l +h + +\setstretch{.5}\tt\tiny ru\_prach\_procedures\par36.211 + +440.514 328 m +477 327.572 l + +\tt\tiny ru\_prach\_procedures() + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\tt\tiny rx\_prachl\par36.211 + +199.412 220.391 m +200 104 l +236.674 103.978 l + + +178.262 196.069 m +179.06 92 l +236.674 91.6468 l + + +65.0054 121.159 m +65.0054 121.159 l +65.0054 121.159 l +65.0054 121.159 l +h + +\setstretch{.5}\begin{tiny} +{\tt ru\_thread\_prach()} +\end{tiny} + +\setstretch{.5}\begin{tiny} +{\tt ru\_thread()} +\end{tiny} + + +65.0054 357.66 m +65.0054 357.66 l +65.0054 357.66 l +65.0054 357.66 l +h + +\setstretch{.5}\begin{tiny} +{\tt ru\_thread\_asynch\_rxtx()} +\end{tiny} + +\tiny to {\tt if\_device} + +485.71 128.939 m +581.963 129.331 l + + + + + + +175.695 380 m +176.42 128 l + +OAI IF1pp Interface +\tiny\begin{itemize} +\item OAI IF1pp is the interface between the 36.213 Physical Layer Procedures (HARQ, SR, CSI, etc.) and the transport/physical channel processing +\item it can be networked, although this is not used as an xhaul interface at the moment. +\end{itemize} + +96 384 m +96 320 l +640 320 l +640 384 l +h + + +128 368 m +128 336 l +352 336 l +352 368 l +h + + +128 368 m +128 336 l +352 336 l +352 368 l +h + +\tiny {\tt phy\_procedures\_lte\_eNB\_TX} +\tiny {\tt phy\_procedures\_lte\_eNB\_RX} + +96 384 m +96 320 l +640 320 l +640 384 l +h + +\small PHY transport and physical channel procedures +\tiny {\tt common\_signal\_procedures()} +\tiny {\tt pmch\_procedures()} +\tiny {\tt generate\_dlsch\_parameters\_from\_dci()} +\tiny {\tt generate\_ulsch\_parameters\_from\_dci()} +\tiny {\tt phy\_config\_dedicated\_step2()} +\tiny {\tt generate\_dci\_top()} +\tiny {\tt generate\_phich\_top()} +\tiny {\tt pdsch\_procedures()} + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + +\tiny {\tt pucch\_procedures()} +\tiny {\tt process\_Msg3()} + +175.695 380 m +176.42 128 l + +\tiny {\tt rx\_ulsch()} + +175.695 380 m +176.42 128 l + +\tiny {\tt ulsch\_decoding()} + +175.695 380 m +176.42 128 l + +\tiny {\tt extract\_cqi()} + +175.695 380 m +176.42 128 l + +\tiny {\tt get\_Msg3\_alloc\_ret()} + +175.695 380 m +176.42 128 l + +\tiny {\tt lte\_est\_timing\_advance\_pusch()} + +175.695 380 m +176.42 128 l + +\tiny {\tt lte\_eNB\_I0\_measurements()} + +175.695 380 m +176.42 128 l + +\tiny {\tt process\_HARQ\_info()} + +175.695 380 m +176.42 128 l + +\small {\tt 36.213}\par +{\tt openair1/SCHED} +\small {\tt 36.211/212}\par +{\tt openair1/PHY} + + + + + +120 528 m +120 0 l +592 0 l +592 528 l +h + + +180 524 m +180 476 l +588 476 l +588 524 l +h + + +248 520 m +248 483.903 l +400 484 l +400 520 l +h + + +180 493.216 m +180 452 l +536 452 l +536 493.216 l +h + + +404 480 m +404 472 l +404 472 l +404 480 l +h + + +340 488 m +340 464 l +444 464 l +444 488 l +h + + +312 456 m +312 432 l +424 432 l +424.001 456 l +h + + +144 448 m +144 360 l +536 360 l +536 448 l +h + + +144 260 m +144 116 l +536 116 l +536 260 l +h + + +144 344 m +144 264 l +536 264 l +536 344 l +h + + +128 440 m +128 384 l +224 384 l +224 440 l +h + +\tt\tiny generate\_dci\_top() + + +0 424 m +0 32 l +48 32 l +48 424 l +h + +M\\ +A\\ +C + +64 416 m +172 416 l + +\tt\tiny DCI\_PDU + +128 440 m +128 384 l +224 384 l +224 440 l +h + +\setstretch{.5}\tt\tiny dlsch\_coding()\par36.212 + +64 416 m +172 416 l + +\tt\tiny DLSCH\_PDU\_0 + +128 440 m +128 384 l +224 384 l +224 440 l +h + + +64 416 m +172 416 l + +\tt\tiny DLSCH\_PDU\_1\_0 + +128 440 m +128 384 l +224 384 l +224 440 l +h + + +64 416 m +172 416 l + +\tt\tiny DLSCH\_PDU\_1\_1 + +312 456 m +312 432 l +424 432 l +424.001 456 l +h + +\setstretch{.5}\tt\tiny generate\_pcfich()\par36.212,36.211 + +304 408 m +304 384 l +400 384 l +400 408 l +h + +\setstretch{.5}\tt\tiny generate\_dci0()\par36.212 + +408 400 m +408 352 l +520 352 l +520 400 l +h + +\setstretch{.5}\tt\tiny pdcch\_scrambling()\par pdcch\_modulation\par pdcch\_interleaving\par36.211 +\setstretch{.5}\tt\tiny dlsch\_coding()\par36.212 +\setstretch{.5}\tt\tiny dlsch\_coding()\par36.212 + +268 426.729 m +293 426.729 l + + +268 399.17 m +293 399.17 l + + +405 397.373 m +421 397.373 l + + +294 320 m +294 296 l +392 296 l +392 320 l +h + +\setstretch{.5}\tt\tiny dlsch\_encoding()\par36.212 + +268 399.17 m +293 399.17 l + + +408 322.774 m +408 288 l +520 288 l +520 322.774 l +h + +\setstretch{.5}\tt\tiny dlsch\_scrambling()\par dlsch\_modulation()\par36.211 + +405 397.373 m +421 397.373 l + + +294 320 m +294 296 l +392 296 l +392 320 l +h + +\setstretch{.5}\tt\tiny dlsch\_encoding()\par36.212 + +408 251 m +408 144 l +520 144 l +520 251 l +h + +\setstretch{.5}\tt\tiny dlsch\_scrambling()\par dlsch\_modulation()\par[2-4 layers]\par 36.211 + +405 397.373 m +421 397.373 l + + +294 320 m +294 296 l +392 296 l +392 320 l +h + +\setstretch{.5}\tt\tiny dlsch\_encoding()\par36.212 + +405 397.373 m +421 397.373 l + + +268 399.17 m +293 399.17 l + + +268 399.17 m +293 399.17 l + + +552 428 m +552 428 l + + +405 409 m +600 408.924 l + + +520 381 m +600 380.885 l + + +521 292.923 m +600 293.648 l + +\tt\tiny openair1/SCHED/phy\_procedures\_lte\_eNb.c:pdsch\_procedures() +\tt\tiny openair1/SCHED/phy\_procedures\_lte\_eNb.c:pdsch\_procedures() +\tt\tiny openair1/PHY/LTE\_TRANSPORT/dci.c + +360 104 m +360 104 l +360 104 l +360 104 l +h + + +144 344 m +144 264 l +536 264 l +536 344 l +h + + +128 440 m +128 384 l +224 384 l +224 440 l +h + +\setstretch{.5}\tt\tiny dlsch\_coding()\par36.212 +\tt\tiny MCH\_PDU + +294 320 m +294 296 l +392 296 l +392 320 l +h + +\setstretch{.5}\tt\tiny dlsch\_encoding()\par36.212 + +268 399.17 m +293 399.17 l + + +408 322.774 m +408 288 l +520 288 l +520 322.774 l +h + +\setstretch{.5}\tt\tiny dlsch\_scrambling()\par mch\_modulation()\par36.211 + +405 397.373 m +421 397.373 l + +\tt\tiny openair1/SCHED/phy\_procedures\_lte\_eNb.c:pmch\_procedures() + +64 416 m +172 416 l + + +128 488 m +128 452 l +172 452 l +172 488 l +h + + +140 472 m +140 472 l +140 472 l +140 472 l +h + +\setstretch{.5}\tt\tiny UL CNTL\\36.213 + +188 476 m +188 460 l +316 460 l +316 476 l +h + +\tt\tiny generate\_phich\_top() + +172 468 m +188 468 l + +\setstretch{.5}\tt\tiny generate\_phich()\par36.212,36.211 + +405 397.373 m +421 397.373 l + + +445 457 m +600 456.672 l + + +520.262 58 m +600 58.7558 l + +\tt\tiny openair1/PHY/LTE\_TRANSPORT/phich.c +\tiny PHICH REs +\tiny PCFICH REs +\tiny PDCCH REs +\tiny PDSCH REs + +104.077 0 0 104.077 528 236 e + +\tiny PMCH REs +\setstretch{.5}\tt\tiny generate\_pilots\_slot()\par generate\_pss/sss/pbch()\par36.211 + +248 488.695 m +248 488.695 l +248 488.695 l +248 488.695 l +h + +\tt\tiny openair1/SCHED/phy\_procedures\_lte\_eNb.c:common\_signal\_procedures() + +401 507 m +600.424 507.963 l + +\tiny CS-RS/PSS/SSS/PBCH REs + +576 332 m +592 324 l + +\tt\tiny openair1/SCHED/phy\_procedures\_lte\_eNb.c:phy\_procedures\_eNB\_TX() +eNB TX Procedures +\tiny eNodeB\_3GPP or NGFI\_RCC\_IF4p5 + +232 276 m +232 240 l +240 240 l +240 276 l +h + +\tt\tiny IF2 split points + +232 276 m +232 240 l +240 240 l +240 276 l +h + + +521 292.923 m +600 293.648 l + + +521 292.923 m +600 293.648 l + + + + + + +539.766 93 m +539.306 79.0026 l +340 79.7439 l + + +447.064 116 m +447.064 92 l +632 92 l +632 116 l +h + + +304 384 m +304 320 l +368 320 l +368 384 l +h + + +225.588 267.631 m +225.588 257.004 l +451.999 257.004 l +451.999 267.631 l +h + + +286.577 417.212 m +286.577 407.581 l +412.989 407.581 l +412.989 417.212 l +h + + +-66.4757 363.53 m +-66.4757 358.467 l +-65.4632 358.467 l +-65.4632 363.53 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\begin{tiny} +\tt {\bf phy\_procedures\_eNB\_TX}(sched\_subframe,eNB,abstraction\_flag,r\_type,rn) +\end{tiny} + +\begin{tiny} eNB instance and component carriers \end{tiny} +\begin{tiny} subframe where TX was scheduled \end{tiny} + +293.168 472.33 m +189.522 511.272 l + + +372.849 474.127 m +310.542 512.47 l + +\setstretch{.5}\begin{tiny} Flag to indicate 212/213 Split\\(transport channels, no 211 procedures) \end{tiny} + +432.16 473.528 m +526.22 499.29 l + + +27.6629 0 0 27.6629 531.612 404.032 e + + +526.819 478.92 m +598.712 484.312 l + +\begin{tiny} Experimental (for relays)\end{tiny} +\begin{tiny} +\bf\tt Check for dead UEs +\end{tiny} + +304 384 m +304 320 l +368 320 l +368 384 l +h + + +340.45 451.636 m +340.45 417.212 l + +\begin{tiny}\tt eNB$\rightarrow$CC\_id==0?\end{tiny} +\begin{tiny} +\bf\tt Call eNB\_dlsch\_ulsch\_scheduler [MAC] +\end{tiny} + +340.45 451.636 m +340.45 417.212 l + + +340.45 451.636 m +340.45 417.212 l + + +340.45 451.636 m +340.45 417.212 l + + +418.155 336 m +528 336 l +528 248 l +340 247.665 l + +\tiny no + +225.588 267.631 m +225.588 257.004 l +451.999 257.004 l +451.999 267.631 l +h + +\begin{tiny}\tt is PMCH subframe?\end{tiny} +\begin{tiny} +\bf\tt Call pmch\_procedures +\end{tiny} + +340.45 451.636 m +340.45 417.212 l + + +340 97.4877 m +340 52 l + +\tiny no +\setstretch{.5} +\begin{tiny} +\bf\tt Call common\_signal\_procedures\\ +(CS-RS/PSS/SSS/PBCH) +\end{tiny} + +417.889 180.561 m +540 180 l +539.532 116 l + + +352 0 m +352 12 l +384 12 l +384 12 l +384 0 l +368 -12 l +368 -12 l +h + +eNB TX Flowchart + + + + + +225.588 267.631 m +225.588 257.004 l +451.999 257.004 l +451.999 267.631 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call get\_dci\_sdu [MAC]\\ dci=first\_dci +\end{tiny} + +368.672 502.411 m +368 524 l + + +304 384 m +304 320 l +368 320 l +368 384 l +h + +\setstretch{.5}\begin{tiny}\tt dci not empty and DL dci?\end{tiny} + +368.672 502.411 m +368 524 l + + +368.297 357.206 m +368 380 l + + +260 356 m +260 328 l +476 328 l +476 356 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call generate\_dlsch\_params\_from\_dci\\ +dci=next(dci) +\end{tiny} +\tt\tiny no + +260 342 m +240.242 342 l +240 472 l +368 472 l + + +445.666 417.484 m +512.662 417.484 l +512.662 303.725 l +367.862 303.725 l +367.862 288.454 l + + +260 356 m +260 328 l +476 328 l +476 356 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call phy\_config\_dedicated\_step2\\ +dci=first\_dci +\end{tiny} + +272 200 m +344.961 161.229 l +416 200 l +344.961 235.739 l +h + +\setstretch{.5}\begin{tiny}\tt dci not empty and UL dci?\end{tiny} + +368.297 357.206 m +368 380 l + + +260 356 m +260 328 l +476 328 l +476 356 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call generate\_ulsch\_params\_from\_dci\\ +dci=next(dci) +\end{tiny} +\tt\tiny no + +260 123 m +240.242 123 l +240 252 l +368 252 l + + +416 200 m +488 200 l +489 96 l +345 96 l +344.862 77.0895 l + + +272 80 m +272 48 l +416 48 l +416 80 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call generate\_dci\_top\\ +Call generate\_phich\_top +\end{tiny} + +368.297 357.206 m +368 380 l + + +352 0 m +352 12 l +384 12 l +384 12 l +384 0 l +368 -12 l +368 -12 l +h + + +344 24 m +344 48 l + +\tt\tiny yes +\tt\tiny yes +eNB TX Flowchart + + + + + +240 96 m +240 56 l +496 56 l +496 96 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt dlsch\_eNB[UE].subframe\_active=false\par [no PUCCH ACK to be checked in TTI n+k]\par +UE=next(UE) +\end{tiny} + +288 464 m +368 432 l +448 464 l +368 496 l +h + + +288 464 m +368 432 l +448 464 l +368 496 l +h + + +368 528 m +368 512 l + + +288 464 m +368 432 l +448 464 l +368 496 l +h + +\setstretch{.5}\begin{tiny}\tt is dlsch\_SI active?\end{tiny} + +368 528 m +368 504 l + +\setstretch{.5}\begin{tiny}\tt is dlsch\_P active?\end{tiny} + +368 528 m +368 504 l + +\setstretch{.5}\begin{tiny}\tt is dlsch\_RA active?\end{tiny} +\tt\tiny no +\tt\tiny no +\tt\tiny no + +368 528 m +368 504 l + + +456 480 m +456 464 l +648 464 l +648 480 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call pdsch\_procedures(dlsch\_SI) +\end{tiny} + +448 464 m +536 464 l +536 448 l + + +536 432 m +536 424 l +368 424 l + +\tt\tiny yes + +456 480 m +456 464 l +648 464 l +648 480 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call pdsch\_procedures(dlsch\_P) +\end{tiny} + +448 464 m +536 464 l +536 448 l + + +536 432 m +536 424 l +368 424 l + +\tt\tiny yes + +456 480 m +456 464 l +648 464 l +648 480 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call pdsch\_procedures(dlsch\_RA) +\end{tiny} + +448 464 m +536 464 l +536 448 l + + +536 432 m +536 424 l +368 424 l + +\tt\tiny yes + +256 232 m +256 208 l +480 208 l +480 232 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt UE=first\_UE from UE\_list \par [list of UE with t-CRNTI or CRNTI] +\end{tiny} + +288 464 m +368 432 l +448 464 l +368 496 l +h + +\setstretch{.5}\begin{tiny}\tt is dlsch\_UE active?\end{tiny} + +368 528 m +368 504 l + + +368 528 m +368 504 l + + +456 480 m +456 464 l +648 464 l +648 480 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call pdsch\_procedures(dlsch\_UE) +\end{tiny} +\tt\tiny yes + +448 464 m +536 464 l +536 448 l + + +536 432 m +536 424 l +368 424 l + +\tt\tiny no + +416 88 m +416 88 l +416 88 l +416 88 l +h + + +320 32 m +368 16 l +416 32 l +368 48 l +h + +\setstretch{.5}\begin{tiny}\tt UE=NULL?\end{tiny} + +368 72 m +368 56 l + + +320 40 m +224 40 l +224 168 l +288 168 l + +\tt\tiny no + +352 0 m +352 12 l +384 12 l +384 12 l +384 0 l +368 -12 l +368 -12 l +h + + +416 40 m +640 40 l +640 24 l + +\tt\tiny yes + +512 48 m +512 32 l +544 32 l +544 48 l +h + + +528 80 m +528 48 l + +\bf\setstretch{.5}\tiny IF4p5 \par [All Frequency-domain Signals are created] +eNB TX Flowchart + + + + + +130 527 m +130 -1 l +608 0 l +608 528 l +h + + +388 288 m +388 208 l +584 208 l +584 288 l +h + + +141 449 m +141 361 l +580.427 361 l +580 448 l +h + + +464 428 m +464 396 l +576 396 l +576 428 l +h + + +462.358 361 m +462.358 287.368 l +602 287.368 l +602 361 l +h + + +462.358 361 m +462.358 287.368 l +602 287.368 l +602 361 l +h + + +492 200 m +492 16 l +596 16 l +596 200 l +h + + +130 202.157 m +130 16 l +484 16 l +484 204 l +h + +\tt\tiny openair1/SCHED/phy\_procedures\_lte\_eNb.c:phy\_procedures\_eNB\_RX() + +0 424 m +0 32 l +48 32 l +48 424 l +h + +M\\ +A\\ +C + +64 416 m +172 416 l + +\setstretch{.5}\tt\tiny RACH Preamble + +534 125.858 m +688 126 l + +\tt\tiny ULSCH\_SDU(UE\_id) +\tiny eNB\_common\_vars.rxdataF[0] +\tiny eNB\_common\_vars.rxdataF[R-1] + +273 269 m +412 268 l + + +273 245 m +412 244 l + + +184 128 m +184 100 l +276 100 l +276 128 l +h + +\setstretch{.5}\tt\tiny rx\_ulsch(UE\_id)\par36.211 + +208 240 m +208 128 l + +\tt\tiny LTE\_TRANSPORT/prach.c +\tt\tiny openair1/PHY/LTE\_TRANSPORT/ulsch\_demodulation.c + +393 285 m +393 229 l +552 228 l +552 284 l +h + +\tt\tiny lte\_eNB\_I0\_measurements() + + + +280 32 m +280 199 l +308 199 l +308 32 l +h + +\setstretch{.5}\tt\tiny ulsch\_extract\_rbs\_single()\par36.211 + + + + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny lte\_ul\_channel\_estimation()\par36.211 + + + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny ulsch\_detection\_mrc()\par36.211 + + + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny frequency\_equalization()\par36.211 + + + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny lte\_idft()\par36.211 + + + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny ulsch\_XXX\_llr()\par36.211 + + + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny ulsch\_decoding()\par36.212 + + + +332 32 m +332 199 l +360 199 l +360 32 l +h + + +\setstretch{.5}\tt\tiny ulsch\_channel\_compensation()\par36.211 + + + +476 118 m +504.475 118 l + + +564 220 m +564 220 l +564 220 l +564 220 l +h + +\tt\tiny ulsch\_decoding.c + +476 118 m +504.475 118 l + +\tt\tiny ACK/NAK,RI,CQI + +131 344 m +131 316 l +276 316 l +276 344 l +h + +\setstretch{.5}\tt\tiny pucch\_procedures(UE\_id)\par36.211 + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\tt\tiny rx\_pucchl\par36.211 + +476 118 m +504.475 118 l + + +551.76 312.126 m +687 312.231 l + +\tt\tiny ACK/NAK +\tt\tiny SR + +440.514 328 m +477 327.572 l + +\tt\tiny TRANSPORT/pucch.c + +373.112 244.28 m +373.112 316 l + + +344.968 268.786 m +345.381 316 l + + +131 344 m +131 316 l +276 316 l +276 344 l +h + +\setstretch{.5}\tt\tiny prach\_procedures\par36.211 + +405.275 413 m +464 412.625 l + + +440.514 328 m +477 327.572 l + +\tt\tiny openair1/SCHED/phy\_procedures\_lte\_eNb.c:prach\_procedures() + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\tt\tiny rx\_prachl\par36.211 +\setstretch{.5}\tt\tiny E\_PRACH>Lmin\par36.211 +\tt\tiny LTE\_ESTIMATION/lte\_eNB\_I0\_measurements.c +eNB PHY RX Procedures + +0 416 m +144 416 l + +\tiny {\tt eNB->prach\_vars.prachF[0$\cdots$ R-1]} + +160 268 m +160 128 l + + + + + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +184 128 m +184 100 l +276 100 l +276 128 l +h + +\setstretch{.5}\tt\tiny rx\_ulsch(UE\_id)\par36.211 +\tiny$\mathbf{R}_{r,l}=\mathrm{DFT}_{N_{\mathrm{fft}}}(\mathbf{r}_{r,l}\odot\mathbf{F}_{7.5}),r=0,1,\cdots,R-1,l=0,1,\cdots,N_{\mathrm{symb}}-1$ (\tt\bf eNB\_common\_vars$\rightarrow$rxdataF[][])%,N_{\mathrm{fft}}=2^{1+\left\lceil\log_2 12N^{\mathrm{RB}}_{\mathrm{DL}}\right\rceil$ + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\tt\tiny slot\_fep\_ul\par36.211 + +144 440 m +176 440 l + + +272 328 m +272 328 l + + +144 440 m +176 440 l + +\tiny $\mathbf{r}_{r,l}$ +\tiny $\mathbf{R}_{r,l}$ +\tiny $\mathbf{R}_{\mathrm{ext},r,l}$ +\tiny $R_{\mathrm{ext},r,l}(n)={R}_{r,l}(12\mathrm{firstPRB}+n),n=0,1,\cdots,12N_{\mathrm{PRB}}-1$ (\tt\bf eNB\_pusch\_vars$\rightarrow$ulsch\_rxdataF\_ext[][]) +\tiny $\mathbf{\hat{H}}_{r,l}$ +\tiny $\mathbf{\hat{H}}_{r,l} = \mathbf{R}_{\mathrm{ext},r,l}\odot\mathbf{DRS}^*_{l}(\mathrm{cyclicShift},n_{\mathrm{DMRS}^{(2)}},n_{\mathrm{PRS}})$, (\tt\bf eNB\_pusch\_vars$\rightarrow$drs\_ch\_estimates[]) +\tiny $\mathbf{R}_{\mathrm{comp},r,l}$ +\tiny $\mathbf{R}_{\mathrm{comp},0,l}$ +\tiny $\mathbf{R}_{\mathrm{comp},0,l}=\frac{1}{R}\sum_{r=0}^{R-1}\mathbf{R}_{\mathrm{comp},r,l}$ +\tiny $\mathbf{R}_{\mathrm{comp},0,l}$ +\tiny $\mathbf{r}_{\mathrm{comp},0,l}$ +\tiny $R_{\mathrm{comp},0,l}(n)=R_{\mathrm{comp},0,l}(n)\dot Q_8\left(\frac{1}{|\hat{H}(n)|^2+I_0}\right), \hat{H}(n)=\sum_{r=0}^{R-1}\hat{H}_{r}(n)$ +\tiny $\mathbf{R}_{\mathrm{comp},r,l}=\mathbf{\hat{H}}_r\odot\mathbf{R}_{\mathrm{ext},r,l}2^{-\log_2|H_\mathrm{max}|}, \mathbf{\hat{H}}_r = \frac{1}{2}(\mathbf{\hat{H}}_{r,3}+\mathbf{\hat{H}}_{r,10})$\par (\tt\bf eNB\_pusch\_vars$\rightarrow$ulsch\_rxdataF\_comp) +\tiny $\mathbf{\lambda}_{l}$ +\tiny QPSK : $\lambda_l(2n)=\mathrm{Re}(r_{\mathrm{comp},0,l}(n)), \lambda_l(2n+1)=\mathrm{Im}(r_{\mathrm{comp},0,l}(n))$ (\tt\bf eNB\_pusch\_vars$\rightarrow$ulsch\_llr) +\tiny ${\mathbf r}_{\mathrm{comp},0,l} = \mathrm{IDFT}_{12N_{\mathrm{PRB}}}({\mathbf R}_{\mathrm{comp},0,l})$ +\tiny 16QAM : $\lambda_l(4n)=\mathrm{Re}(r_{\mathrm{comp},0,l}(n)), \lambda_l(4n+2)=\mathrm{Im}(r_{\mathrm{comp},0,l}(n))$\par$\lambda_l(4n+1)=|\mathrm{Re}(r_{\mathrm{comp},0,l}(n))|-2\overline{|h(n)|},\lambda_l(4n+3)=|\mathrm{Im}(r_{\mathrm{comp},0,l}(n))|-2\overline{|h(n)|}$ + +280 32 m +280 199 l +308 199 l +308 32 l +h + +\setstretch{.5}\tt\tiny ulsch\_extract\_rbs\_single()\par36.211 + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny lte\_ul\_channel\_estimation()\par36.211 + +332 32 m +332 199 l +360 199 l +360 32 l +h + + +\setstretch{.5}\tt\tiny ulsch\_channel\_compensation()\par36.211 + + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny ulsch\_detection\_mrc()\par36.211 + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny frequency\_equalization()\par36.211 + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny lte\_idft()\par36.211 + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny ulsch\_XXX\_llr()\par36.211 + +304 236 m +304 236 l +304 236 l +304 236 l +h + +eNB ULSCH Demodulation + + + + +eNB PRACH Detection + +0 296 m +0 264 l +736 264 l +736 296 l +h + +\tiny$\mathbf{R}_{r}=\mathrm{DFT}_{N_{\mathrm{PRACH}}}(\mathbf{r}_{r}),r=0,1,\cdots,R-1$ (\tt\bf lte\_eNB\_prach\_vars$\rightarrow$rxsigF[])%,N_{\mathrm{fft}}=2^{1+\left\lceil\log_2 12N^{\mathrm{RB}}_{\mathrm{DL}}\right\rceil$ + +0 296 m +0 264 l +736 264 l +736 296 l +h + +\tiny$\mathbf{R}_{\mathrm{comp},r}=\mathbf{R}_{r}\odot \mathbf{X}^*_u[i],r=0,1,\cdots,R-1$ (\tt\bf lte\_eNB\_prach\_vars$\rightarrow$prachF[])%,N_{\mathrm{fft}}=2^{1+\left\lceil\log_2 12N^{\mathrm{RB}}_{\mathrm{DL}}\right\rceil$ + +0 296 m +0 264 l +736 264 l +736 296 l +h + +\tiny$\mathbf{r}_{839,r}=\mathrm{IDFT}_{1024}\left(\mathbf{R}_{\mathrm{comp},r}\right), r=0,1,\cdots,R-1$ (\tt\bf lte\_eNB\_prach\_vars$\rightarrow$prach\_ifft[]) + +112 460 m +112 400 l +176 400 l +176 460 l +h + +\tiny $\mathbf{r}_{r}$ + +144 440 m +176 440 l + +DFT +\tiny $\mathbf{R}_{r}$ + +268 480 m +268 452 l +300 452 l +300 480 l +h + +$\odot$ + +176 428 m +208 428 l +208 456 l +268 456 l + + +208 428 m +208 400 l +268 400 l + +\tiny $\mathbf{X}^*_{u}(0)$ +\tiny $\mathbf{X}^*_{u}(1)$ + +284 480 m +284 468 l + + +284 372 m +284 384 l + + +268 480 m +268 452 l +300 452 l +300 480 l +h + +\tiny$R\times\mathrm{IDFT}_{1024}$ + +300 456 m +336 456 l + + +300 456 m +336 456 l + + +268 480 m +268 452 l +300 452 l +300 480 l +h + +\tiny$R\times\mathrm{IDFT}_{1024}$ + + +268 480 m +268 452 l +300 452 l +300 480 l +h + + + +\tiny$\sum_{r}|\cdot|^2$ + + + + + +268 480 m +268 452 l +300 452 l +300 480 l +h + + + +\tiny$\sum_{r}|\cdot|^2$ + + + + + +268 480 m +268 452 l +300 452 l +300 480 l +h + +\tiny max peak in size $\mathrm{NCS}_2$ window, keep delay + + +412 456 m +440 456 l + + +412 400 m +440 400 l + + +500 460 m +532 460 l + + +500 460 m +532 460 l + + +500 460 m +532 460 l + + +624 456 m +672 456 l + + +624 456 m +672 456 l + + +268 480 m +268 452 l +300 452 l +300 480 l +h + +\tiny max peak in size $\mathrm{NCS}_2$ window, keep delay +\tiny\tt preamble\_energy\_list[]\par preamble\_delay\_list[] +\tiny $\mathbf{r}_{839,r}$ +\small\begin{itemize} +\item PRACH detection is a quasi-optimal non-coherent receiver for vector observations (multiple antennas) +\item correlation is done in the frequency-domain, number of correlations (in the example above 2) depends on {\em zeroCorrelationConfig} configuration parameter +\item peak-detection (for delay estimation) is performed in each NCS time-window +\end{itemize} + + +268 480 m +268 452 l +300 452 l +300 480 l +h + +$\odot$ + + + + + + +340 416 m +340 340 l +564 340 l +564 416 l +h + + +268 480 m +268 452 l +300 452 l +300 480 l +h + +\tiny$\sum_{r,l,i}|\cdot|^2$ +\begin{tiny}$\stackbin{<}{>}\sigma^2[\mathrm{dB}]$\end{tiny} +eNB PUCCH1 Detection + +184 128 m +184 100 l +276 100 l +276 128 l +h + +\setstretch{.5}\tt\tiny rx\_pucch()\par36.211 + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\tt\tiny slot\_fep\_ul\par36.211 + +144 440 m +176 440 l + + +144 440 m +176 440 l + +\tiny $\mathbf{r}_{r,l}$ +\tiny $\mathbf{R}_{r,l}$ +\tiny $\mathbf{Z}^*_{l}e^{-j2\pi f/16},-3\leq f\leq 2$ + +308 448 m +352 448 l + +$\odot$ + +308 448 m +352 448 l + + +392 484 m +392 456 l + + +328 448 m +328 400 l +352 400 l + +$\odot$ + +392 484 m +392 456 l + +\tiny $\mathbf{Z}^*_{l}$ + +288 496 m +288 496 l +288 496 l +288 496 l +h + + +308 448 m +352 448 l + + +412 408 m +412 392 l +464 392 l +464 408 l +h + +\tiny$\mathbf{\hat{H}}$ +$\odot$ + +420 392 m +420 376 l + + +384 400 m +384 368 l +412 368 l + + +428 368 m +464 368 l + +\tiny$\mathrm{sgn}(\mathrm{Re}(\cdot))$ + +444 368 m +444 352 l +464 352 l + +\tiny$\mathrm{sgn}(\mathrm{Im}(\cdot))$ + +532 408 m +532 408 l +532 408 l +532 408 l +h + +\tiny PUCCH1 (Scheduling Request) +\tiny PUCCH1a/1b (ACK/NAK) +\small\begin{itemize} +\item PUCCH1 detection is a quasi-optimal non-coherent receiver (energy detector) for vector observations (multiple antennas) for scheduling request. Care is taken to handle residual frequency-offset. +\item PUCCH1A/1B detection is quasi-coherent based on a rough channel estimate obtained on the 3 symbols without data modulation. \item In both cases, correlation is done in the frequency-domain +\end{itemize} + + + + +\small\begin{itemize} +\item Threads (all in {\tt targets/RT/USER/lte-ru.c}) +\begin{itemize} +\item {\tt ru\_thread}: Thread per RU which sequentially +performs +\begin{itemize} +\item read from south interface (RF or IF fronthaul) +\item RX processing for subframe $n$ (if necessary). +\item wakeup eNBs that are waiting for signal (if necessary) +\item wait for eNB task completion (if necessary) +\item do TX processing for subframe $n+4$ (if necessary). Note that this can spawn multiple worker threads for very high order spatial processing (e.g. massive-MIMO or DAS for UDN) +\item do outgoing fronthaul (RF or IF fronthaul) +\end{itemize} +\item {\tt ru\_thread\_prach}: Thread for PRACH processing in remote RU (DFT on RX, IF4p5 RRU) +\item {\tt ru\_thread\_asynch}: Thread for asynchronous reception from fronthaul interface (TX direction in RRU). %Allows for some jitter so as not to block the RRU real-time processing. +\end{itemize} +\item Synchronization on fronthaul interface +\begin{itemize} +\item {\em synch\_to\_ext\_device} : synchronizes to incoming samples from RF or Fronthaul interface using blocking read +\item {\em synch\_to\_other} : synchronizes via POSIX mechanism to other source (other CC, timer) which maintains real-time. +\end{itemize} +\end{itemize} +RU Threads + + + + +\small\begin{itemize} +\item Threads (all in {\tt targets/RT/USER/lte-enb.c}) +\begin{itemize} +\item multi RX/TX thread mode (optional) +\begin{itemize} +\item {\tt eNB\_thread\_rxtx}: 2 threads per CC/Instance which do both RX procedures for subframe $n$ and TX procedures for subframe $n+4$. One operates on even subframes, one on odd. This allows 1ms subframe processing to use multiple-cores. +\end{itemize} +\item common RU-eNB RX/TX thread (default if single RU/eNB) +\begin{itemize} +\item calls {\tt eNB\_top}: procedure per CC/Instance which sequentially +\begin{itemize} +\item blocks on signal from RU +\item RX/TX processing for subframe $n$ and $n+4$ +\item signals completion to RU +\end{itemize} +\end{itemize} +\item {\tt eNB\_prach}: Thread per CC\_id/Instance for PRACH processing +\end{itemize} +\end{itemize} +eNB Threads + + + + + +400 400 m +400 388 l +520 388 l +520 400 l +h + + +400 432 m +400 420 l +520 420 l +520 432 l +h + + +400 448 m +400 436 l +528 436 l +528 448 l +h + + +400 448 m +400 436 l +528 436 l +528 448 l +h + + +192 388 m +192 364 l +272 364 l +272 388 l +h + + +32 480 m +32 464 l +112 464 l +112 480 l +h + +eNB Timing (multi-thread mode) + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny SF $n+1$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny SF $n+2$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny SF $n+3$ +\tiny $n$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny$n+4$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny SF $n+4$ + +32 480 m +212 572 +352 480 c + + +384 464 m +384 464 l + + +380 472 m +380 472 l + +\tiny\begin{itemize} +\item The current processing requires approximately 1ms peak in each direction (basically 1 core RX, 1core TX). The current architecture will work on a single core if the sum of RX and TX procedures is limited to 1ms. It can fit on 2 cores if the sum of RX,TX and PRACH is less than 2ms. +\item three threads, RX-TX even, RX-TX odd and PRACH. RX-TX blocks until woken by the RU thread with a new RX subframe $n$ that is linked to this eNB process. The RX-TX thread performs ue-specific processing for subframe $n$ and then TX common and ue-specific processing for subframe $n+4$ (frequency-domain generation only). This insures the data dependency between TX $n+4$ and RX $n$ is respected. The duration of this thread should be less than 2ms which can compensate some jitter on the RX processing. +\end{itemize} + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny SF $n$ +\tiny LTE HARQ periodicity (FDD, TDD can be longer) +\tiny PRACH $n$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny $n+1$ +\tiny $n$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny$n+5$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny $n+1$ + +124 424 m +172 416 +152 392 c + + +204 424 m +228 424 +236 416 c + + +192 396 m +196 416 l + + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny $n-1$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny$n+3$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny $n-1$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny $n+2$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny$n+6$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + + +284 424 m +308 424 +316 436 c + +\tiny $n+2$ + +268 452 m +276 436 l + +\tiny RU thread +\tiny RX-TX thread (even) + +400 448 m +400 436 l +528 436 l +528 448 l +h + + +400 448 m +400 436 l +528 436 l +528 448 l +h + +\tiny RX-TX thread (odd) +\tiny PRACH + +192 396 m +196 416 l + + + + + + +96 384 m +96 320 l +640 320 l +640 384 l +h + + +96 384 m +96 320 l +640 320 l +640 384 l +h + + +96 384 m +96 320 l +640 320 l +640 384 l +h + + +96 384 m +96 320 l +640 320 l +640 384 l +h + + +128 368 m +128 336 l +352 336 l +352 368 l +h + + +128 368 m +128 336 l +352 336 l +352 368 l +h + + +175.695 380 m +176.42 128 l + +OAI IF1'' Interface (can be NFAPI) +\tiny\begin{itemize} +\item OAI IF1'' is the interface between the 36.321 Medium-Access (MAC) Layer Procedures and the 36.213 Physical Layer Procedures. It links several PHY instances to one MAC instance. +\item It is a configurable (dynamically loadable) module which can implement an (N)FAPI P5/P7 or a simpler interface. +\end{itemize} + +128 368 m +128 336 l +352 336 l +352 368 l +h + +\tiny Random-Access +\tiny Events +\small PHY procedures +\tiny {\tt initiate\_ra\_proc()} +\tiny {\tt terminate\_ra\_proc()} +\tiny {\tt cancel\_ra\_proc()} +\tiny {\tt phy\_config\_dedicated()} +\tiny {\tt phy\_config\_sib1()} +\tiny {\tt phy\_config\_sib2()} +\tiny {\tt phy\_config\_sib13()} + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + +\tiny {\tt eNB\_dlsch\_ulsch\_scheduler()} +\tiny {\tt get\_dcii\_sdu()} + +175.695 380 m +176.42 128 l + +\tiny {\tt get\_dlsch\_sdu()} + +175.695 380 m +176.42 128 l + +\tiny {\tt rx\_sdu()} + +175.695 380 m +176.42 128 l + +\tiny {\tt get\_mch\_sdu()} + +175.695 380 m +176.42 128 l + +\tiny {\tt SR\_indication()} + +175.695 380 m +176.42 128 l + + +128 368 m +128 336 l +352 336 l +352 368 l +h + +\tiny PHY Config +\tiny Scheduling +\small {\tt 36.213/36.321}\\ +{\tt openair2/LAYER2/MAC} +\small {\tt 36.211/212}\par +{\tt openair1/PHY} + +96 384 m +96 320 l +640 320 l +640 384 l +h + +\small OAI MAC interface +\tiny {\tt phy\_config\_mib()} + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + +\small UL-Indication +\small Config-Req +\small Schedule-Resp +\tiny Northbound interface +\tiny Southbound interface + + + + +OAI IF1'' Interface +\tiny\begin{itemize} +\item The PHY end uses three basic messages +\begin{itemize} +\item {\tt CONFIG\_REQ}: this provides the cell configuration and UE-specific configuration to the PHY instances. This comprises the following FAPI P5/P7 messages +\begin{enumerate} +\item CONFIG.request +\item UE\_CONFIG.request (**not used in OAI PHY) +\end{enumerate} +\item {\tt UL\_INDICATION} This is an uplink indication that sends all UL information received in one TTI, including PRACH, if available. It also provides the subframe indication for the DL scheduler. It maps to the following FAPI P7 messages +\begin{enumerate} +\item {\tt SUBFRAME.indication} +\item {\tt HARQ.indication} +\item {\tt CRC.indication } +\item {\tt RX\_ULSCH.indication} +\item {\tt RX\_SR.indication} +\item {\tt RX\_CQI.indication} +\item {\tt RACH.indication} +\item {\tt SRS.indication} +\end{enumerate} +\item {\tt SCHEDULE\_REQUEST} This message contains the scheduling response information and comprises the following FAPI P7 messages +\begin{enumerate} +\item {\tt DL\_CONFIG.request} +\item {\tt UL\_CONFIG.request} +\item {\tt TX.request} +\item {\tt HI\_DCI0.request} +\end{enumerate} +\end{itemize} +\item The module is registered both by PHY and MAC and can implement different types of transport (NFAPI, function call, FAPI over UDP, etc.). During registration, fuction pointers for the different messages are provided for the module to interact with either PHY or MAC or both if they are executing in the same machine. Note that for a networked implementation (e.g. NFAPI), there are north and south components running in different machines. +\end{itemize} + + + + +OAI IF1'' Interface +\small\begin{itemize} +\item The PHY-layer timing is assumed to be +\begin{enumerate} +\item wait for subframe indication $n$ from HW +\item trigger PRACH if $n$ has PRACH (parallel thread) +\item trigger UE specific RX procedures for $n$ if $n$ is UL +\item assemble {\tt UL\_INDICATION} and send to MAC +\item wait for {\tt SCHEDULE\_REQUEST} +\item do TX procedures if $n+4$ is TX and RX programming if $n+4+k$ is UL +\end{enumerate} +\item The MAC-layer timing is assumed to be +\begin{enumerate} +\item do all UL processing for subframe $n$ if $n$ is UL after unraveling of UL\_INDICATION in MAC module +\item wait for call to {\tt eNB\_dlsch\_ulsch\_scheduler} +\item do DL scheduling for $n+4$ if it is DL +\item do UL scheduling for $n+8$ if it is UL +\item return from eNB\_dlsch\_ulsch\_scheduler +\item let MAC module form SCHEDULE\_REQUEST +\end{enumerate} +\end{itemize} + + + + + +96 384 m +96 320 l +640 320 l +640 384 l +h + + +128 368 m +128 336 l +352 336 l +352 368 l +h + + +128 368 m +128 336 l +352 336 l +352 368 l +h + +OAI MAC + +128 368 m +128 336 l +352 336 l +352 368 l +h + +\tiny Random-Access +\tiny Events + +128 368 m +128 336 l +352 336 l +352 368 l +h + +\tiny PHY Config +\tiny Scheduling +\small {\tt 36.321}\\ +{\tt openair2/LAYER2/MAC} + +175.695 380 m +176.42 128 l + + +176 496 m +176 384 l +400 384 l +400 496 l +h + + +176 496 m +176 384 l +400 384 l +400 496 l +h + +\small RRC + +384 384 m +272 144 l + + +384 384 m +384 144 l + + +384 384 m +528 144 l + + +608 384 m +528 144 l + +\small RLC + +176 496 m +176 384 l +400 384 l +400 496 l +h + +\small Preprocessor + +160 256 m +528 144 l + + +272 312 m +608 384 l + + +472 504 m +472 232 l +152 232 l +152 40 l +728 40 l +736 40 l +736 504 l +h + +\small {\tt 36.322}\\ +{\tt openair2/LAYER2/RLC} +\small {\tt user customizable scheduling module} + + + + +TX Precoding +\small\begin{itemize} +\item Spatio-temporal filtering for muli-cell (vCell) and multi-user transmission. Input and output are frequency-domain signals. +\item can be applied to Rel-10/11/12/13 physical channels and Rel-8 common channels +\begin{itemize} +\item UE-specific precoding (TM7-10) +\item vCell-specific precoding (PDCCH + TM1-6) for groups of UEs +\item PMCH vCells +\end{itemize} +\item Precoding applicable to +\begin{enumerate} +\item indoor DAS +\item outdoor co-localized arrays (e,g, Massive-MIMO) +\item outdoor CoMP +\end{enumerate} +\end{itemize} + +208 480 m +208 80 l +512 80 l +512 480 l +h + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +400 160 +480 192 +528 160 +400 160 +400 160 u + + +400 96 +448 128 +512 144 +576 96 +496 80 +400 96 +400 96 u + + +480 160 m +480 160 l + + +496 160 m +496 160 l + + +400 96 +448 128 +512 144 +576 96 +496 80 +400 96 +400 96 u + +\small UE +\small vCell +\small vCell +TX Precoding + + + + + +608 516 m +607 37 l +679 37 l +680 516 l +h + + +632 360 m +632 188 l +660 188 l +660 360 l +h + +TX Precoding (to RF device) + +208 480 m +208 80 l +512 80 l +512 480 l +h + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + +\tt eNB[0] +\tt eNB[1] +\tt eNB[CC\_max] + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +528 464 m +528 416 l +592 416 l +592 464 l +h + +\tiny\tt rf\_device[0] + +528 464 m +528 416 l +592 416 l +592 464 l +h + +\tiny\tt rf\_device[1] + +528 464 m +528 416 l +592 416 l +592 464 l +h + +\tiny\tt rf\_device[N-1] + +192 432 m +192 368 l +272 368 l +272 432 l +h + + +192 432 m +192 368 l +272 368 l +272 432 l +h + + +192 432 m +192 368 l +272 368 l +272 432 l +h + +\tiny\tt common signal precoding(vCell)\\ PBCH,PSS/SSS,PCFICH/PHICH/PDCCH\\ +PDSCH - TM1-6 +\tiny\tt UE-specific signal precoding(vCell)\\ +UE-RS,PDSCH - TM7-10 +\tiny\tt PMCH precoding + +145 413.44 m +192 384 l + + +145 413.44 m +192 288 l + + +145 413.44 m +192 192 l + + +145 349.44 m +192 384 l + + +145 349.44 m +191.982 288.048 l + + +145 349.44 m +191.982 192.084 l + + +145 157.44 m +192 384 l +192 384 l + + +145 157.44 m +191.982 288.048 l + + +145 157.44 m +191.982 192.084 l + + +400 384 m +449 447.637 l + + +400.059 384.077 m +449 431.796 l + + +400.059 384.077 m +449 383.637 l + + +400.059 384.077 m +449 367.763 l + + +400.059 384.077 m +449 143.57 l + + +400.059 384.077 m +449 127.637 l + + +400 288 m +449 383.637 l + + +400.001 288.002 m +449 367.763 l + + +400.001 288.002 m +449 143.57 l + + +400.001 288.002 m +449 127.637 l + + +400 192 m +449 447.637 l + + +400.001 288.002 m +449 447.637 l + + +400.001 288.002 m +448.966 431.763 l + + +400.001 192.005 m +449 367.763 l + + +400.001 192.005 m +449 143.57 l + + +400.001 192.005 m +449 127.637 l + +\tiny phy\_vars\_eNB.txdataF +\tiny phy\_vars\_eNB.txdata + +632 264.556 m +671.833 265 l + +\setstretch{.5}\tt\tiny do\_ofdm\_mod\_rt()\par 36.211 + + + + +TX Precoding (to IF device, NGFI\_IFv4p5) + +208 480 m +208 80 l +512 80 l +512 480 l +h + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + +\tt eNB[0] +\tt eNB[1] +\tt eNB[CC\_max] + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +528 464 m +528 416 l +592 416 l +592 464 l +h + +\tiny\tt if\_device[0] + +528 464 m +528 416 l +592 416 l +592 464 l +h + +\tiny\tt if\_device[1] + +528 464 m +528 416 l +592 416 l +592 464 l +h + +\tiny\tt if\_device[N-1] + +192 432 m +192 368 l +272 368 l +272 432 l +h + + +192 432 m +192 368 l +272 368 l +272 432 l +h + + +192 432 m +192 368 l +272 368 l +272 432 l +h + +\tiny\tt common signal precoding(vCell)\\ PBCH,PSS/SSS,PCFICH/PHICH/PDCCH\\ +PDSCH - TM1-6 +\tiny\tt UE-specific signal precoding(vCell)\\ +UE-RS,PDSCH - TM7-10 +\tiny\tt PMCH precoding + +145 413.44 m +192 384 l + + +145 413.44 m +192 288 l + + +145 413.44 m +192 192 l + + +145 349.44 m +192 384 l + + +145 349.44 m +191.982 288.048 l + + +145 349.44 m +191.982 192.084 l + + +145 157.44 m +192 384 l +192 384 l + + +145 157.44 m +191.982 288.048 l + + +145 157.44 m +191.982 192.084 l + + +400 384 m +449 447.637 l + + +400.059 384.077 m +449 431.796 l + + +400.059 384.077 m +449 383.637 l + + +400.059 384.077 m +449 367.763 l + + +400.059 384.077 m +449 143.57 l + + +400.059 384.077 m +449 127.637 l + + +400 288 m +449 383.637 l + + +400.001 288.002 m +449 367.763 l + + +400.001 288.002 m +449 143.57 l + + +400.001 288.002 m +449 127.637 l + + +400 192 m +449 447.637 l + + +400.001 288.002 m +449 447.637 l + + +400.001 288.002 m +448.966 431.763 l + + +400.001 192.005 m +449 367.763 l + + +400.001 192.005 m +449 143.57 l + + +400.001 192.005 m +449 127.637 l + + +448 544 m +448 544 l + + +432 544 m +432 544 l + + +624 432 m +672 432 l + + +624 432 m +672 432 l + + +624 432 m +672 432 l + +\tiny NGFI\_IFv4p5 +\tiny NGFI\_IFv4p5 +\tiny NGFI\_IFv4p5 + + diff --git a/targets/DOCS/oai_L1_L2_procedures.pdf b/targets/DOCS/oai_L1_L2_procedures.pdf index 369efc3b479b960c74e89b7e73e427a15cea8de9..28a4416e83a119a8950658dfe93969e8d5e2af6a 100755 GIT binary patch delta 285060 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 z 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 Q;*&0_)+dVCO51k*AA48tBLDyZ literal 1118156 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

pNXaJbVmkKJVxnwbgs&>%-fm{V=PYdh zp(I(GUI{^2K)1kYWaTd}37wQmky)mK_gAp2)7StR6aFlnt^!Djoy@>wm-mHO?D`q6 zcNWD%^}w=M#rC1Gw*A)OWV@kfCObWS@bvWHs`5vN&&N$3i}vX<59f zN&(({LDEe9?_j@MD&OB6-i*gN+MJ8;A>K7SXM%#sK2M_8zMa38M%*}ABHQ1Soi>6F zV<-^LHy~kP5IO1t>rzTiZeaIHAsaX{K7M<3bqu+Bou329$ndeTq3gd02uxxD$H|o6 zi7$_|rqUt(5;6n+vPV__E+oiMHOTrzG(_vaweEQ|)qmx;Mz&SFzAT=->?G)FGy6N| zHV6%1Ya695DQPdamO{|{$}f9fsSv0ki2NR2bjj>~a`umFBs(H_;N-{e?dGWqJnzt( z=i8t6k_|*Kb&)0!8hRAPhqOF2nMh}NUs}Djm{hr2byw;hKQZdL8nkEZv{F<#Q~vSu zbq4J)o3uf^0h!uA?RN1^a5K;FbW1{Il(|sZ@5WstN^39WxrRbYOj6c5ymFMi!<%aZ z^!0kGwixm@^Mv%osBGz#5HzaW>$$-nlTrWF?a&|AE2|>Z)wxz1JEmta1ljprF5;&4 zPpW@KY*$vAJ;WMOmie&>B0t`T_S-K$Axy70y_eZRQ{N)au35Eq?t zPX9v&OioV1!oqUdt)*sVot>V-k-|hnSwljRb`B2_(R*~B=APLp=k#q#_f5lZfnE*m zez9sSkeoJ8{vKGM>%qZcC36*UvfXv+1I03=z8N?-tpPT*aM+oIZJ8_Etl2w%RY!t~ znP499=A(XTlgOM3~fFQa8$rV^I3YMs$Z zE<07yoh^02?!s&1d$>?s14N4L;9g^mp!na~^ukeuM{i?WUvR5R#VP0{H7FFPyY};x zd>CH;3uN0l(x;N;)l0AK3vkiRMwt7+{3_jSmUH% zQ?q%=KvkkTgKFqE-nY$4M*i0gy3qFsvjKS_a==m0xAJ3o}vAGFgtS`|Mju<9Ed z12`f74HSNm$hLjHp5tZrKhRbHDyuK+rDBUN$MnaCy}=kcmJ`sazqeuB>D*>LA@ zOu19P04bXN7R|s_JoZ%&)rHR+%}zTKk-O;j_V)GFyGCPedAaQ8?~aa+IOR{v%Mgsp zPt@VEy9d_y*KWX=J|ghT{npLX9s1q=Xnb$oj|GSTAs#x(&8&{6nrOYk>&eBe;1Lr0 z&0XvA)zZHXd0d?wBd?JD3x3sNT9B%}$7`VO__5Bzkd+F#5$&JTV=GA|DCFU-vFl9g zMfgZxCxZ`rl}GIq&}NWKN_LdqC|2ALGY%1$V^BbUsK{{sh{;!~4wZ2N&6;}=p*3N1 z-;^)21I=sHDboMsgD-$7Tco3IC{$#;?#_+q_2#9D@(Ih|EA{~b8}TYPc9I-bnU$M9_W!0 zh+q}>dDD=i4xv`V;j$S4WYEwH1ww)gczk@^*w_dQL#i%rZ-4C#Muo`!enkJ*_d)@7 zJ132pz(g5*)ox9&o|kL}QsvMUCe+RH*kDBV>AzcE-UJo4_@br>vRGjF3%qQE4Uaup z2r%a#Fv;Mbc5}7zJPcC-Dr0;TNqBy%j`(5!3xv*t&Z5jB_F^?O6}pP(E5vk{=ps

@tr0 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%0ASU{V0vYcyBwu^$s3C57mL_ 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%0A6G*7Y(aa!MIG@`KA> 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�w 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 cKA7y|>)`GC-?xgnJ7R_^0|$eP5=M^ From 79458ae7c5449b666798be0c2254bcfa9237d028 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Tue, 14 Nov 2017 13:57:34 +0100 Subject: [PATCH 076/284] added .ipe file for L1_L2_procedures slides and updated .pdf file --- targets/DOCS/oai_L1_L2_procedures.ipe | 12461 ++++++++++++++++++++++++ targets/DOCS/oai_L1_L2_procedures.pdf | Bin 1118156 -> 1511882 bytes 2 files changed, 12461 insertions(+) create mode 100755 targets/DOCS/oai_L1_L2_procedures.ipe mode change 100755 => 100644 targets/DOCS/oai_L1_L2_procedures.pdf diff --git a/targets/DOCS/oai_L1_L2_procedures.ipe b/targets/DOCS/oai_L1_L2_procedures.ipe new file mode 100755 index 0000000000..2062240c14 --- /dev/null +++ b/targets/DOCS/oai_L1_L2_procedures.ipe @@ -0,0 +1,12461 @@ + + + + +\usepackage{setspace}\usepackage{amsmath}\usepackage{stackrel} + +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 +2NraK/l2+fJVply/fvPGjVufKLfxKb6yX+Xq1ev46b8t2KodLrbDcuXK51Z4+crVm7duPXh4 +7/6DPZSH9xDZS5eu4Of09C4rWceT+zqhGuuIcl9EuZ6eHqIcUe4zWlpaqqmptbGxVdDs9hfB +4QMirh1w2fcfBXxAns8UXd3LF3UuXby4h6JzCVhTjRvDukt6V1w8LYWd2bMygXLY9B32L6ft +lEPt3nv/cjh0+/r6tDoOjo7O36p/uSNCORwhr169vX//IbzZl/KNyt4LWIc09sxpHScPi0Fp +JTNI4k76Ci4pLX327IW9g6MjaoIWFjs7B3lfwY177SvY3d3D0NBYS4PwPg7yvoKbiXJfVWtr +a2VlZfr6hshV4ei2WzUkkp8pB2/k9j1j/XaIuwK+Xbiga2z2Nr8ianSxVqK49rqT0W36+vuF +IlEDh9PA4Wpn4TQ1N+99oKvOri4Ol6u1QfhkHIhyX0Orq6slJaXv3qmz7vr1W3fu3MXMjxZQ +br/yR6xn5+fu/nYx7MKtW3d2UrAXOhf0Tp2SXxf4TDlzek8Fa9DR0VOyV8G3Cxd19Cxs3lVw +E6SbvAWZUHl7yQ7H8ELrr+1lX0ZnPpRxIMp9TdatFRUVIYdlWIc0Ni8vTyKRjH9MExMT+Dc6 +0ZruWd3d3XgRiUQ8Hv8zEgiE8fEJDg5OmOB/dkEOh1teXrGTEhIcbutoWlgek1UU9tGSXRKW +lB0QleQdk7z7kpjhb2Khf+GCHuPfQDxLW8NqYfKMjC/n2187fdo55UbEYu0t+0U5rQ7Cp+JA +lPvaWllZhq/T1ze4d+9hTU2Npt3rwjyDs28rFLZEJ/nIZN2LMtEnSiNeF/ZWZLL20BjPH/9z +Qkfn0nu+bfHnVfzbLkad5vEF1fh7amu1sVRX14gaG1GX956x1tTWaWkQPhMHotxBsW4lKyur +ublFo7ZKS599mJcJgiLc9A1fMP7tU3zb+UiFpWVlL1++cnZ2dXV108bi5OT8+vXb7SP0fenV +B09PlomJqZYG4X0c3rxtam454lcfmE4SVN8yczY2NpaWliHmqZMjIi2lHJjWO1mG18/z7Yvu +JAkLC6c7SWxsbHfXHzvdSaJRlBsaGjYyMhofn2DepqVlNDQ0zM/PGxqaID5oCxwcHNva2ohy +mkw55nDaYafrdFcwPftwFCi3vr7OPEEMn4Y9vnbthouLG/NRaGh4SUnp2NiYmZnlikLt7R3G +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 +QvYK19Ha2tbxQci8mLHPoPX19fb2dqSrCwsLdF7uU0JwEDTVTsCQ2iOSaFC6u7sRQCawbW1t +fX39ym6I+vsHmptbhodH6LwciShHT3jRE15EORJRjihHlCPKkQ4B5QQCofbGUyqd0diel4KC +grX7WK2rJ8qRDgHlPDxZ6ekZvVorDodraWk9NDysaZTLLyh0dnbt1WYlJaWwvX2IciStphwO +YDbbW1//HRydlhYrKxtTU3P54IkaRrnSsvI//nji5uahvbF980bfzz+AKEc6BBmrUCjS3njO +zMxSxvqV1NDAoYyVRFcf6OoDXX0gypGIckQ5ohxRjihHlCPKEeVIRDnNpFx+fr6bm3t8fAJz +7/3w8LC3t4+XF7urq5tZYG1tLSwsPDIySrVr9I2NjdLSMjc3DxbLa499oB1WynV2diKMCKZY +LJYpekGPi4tHqAsKCpXLlJdXuLq6qfVB2tnZ5efnj/lpaenKTtSJciSi3K53x9ra5l//+vel +S1eYvkcyM7O+++77H374qazsfRdAra1tP//8y/HjJ7u733NveXnZzs7+xx9/vnbthp7e5Z9/ +/hUY/NTwEEeWcsXFxQjj99//mJubJ1P096Kjo/vPf35na2uvbCmePn32X//135GR0cpv5ebm +njhx6sKFi4gtwv7y5WvlU3VEORJRbndydHS6fv3mo0eP6+vlD92zWOxHj/5ALUMFYRZgs33e +vjX4/fdHkZGRzJyUlFTU3+TklNXV1dnZWUtL66dPn++6x7nDSrny8nKE8fHjJz4+vnhbXV39 +22+PwC5nZ1dmAYFAcP/+QwsLy2fPnjNP5Q8ODp09e97ExGxiYhKxRYujq6u3F6tMlCMR5WSK +fs9QEx0cnMLDI5C0GhgYMp1qMpRbXFy8fftuRUVlaGgYquTa2jpmYhmmDw1GqI9wd5Sxqglm +GGH09vY1MjLB26CgYEdHZ4QazQqzgIeHJ3xda2vrmTPnmHuBgLVjx35taWlVrmSPo6QR5UhE +OQi554sXL2HPYMl6e/tev36TlyfvIpihXG1t3Y0btzAxMDBw5sz5pqZmTD979oKpuXT14fOU +gzHLzy949ep1X1+fubllamrakyfPGMqhXbh7935lZRWmYZ7ZbG9MxMXFnzt3YXh4iK4+kIhy ++0s5VD3g6+XL1yEhoQ4Ojo2NTSdPnkGGhU+RXiHtCggI9PJinzx5OiwsHDPfvTN6+PB35Rq6 +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 +pHyubtC511LJ/iprOhgsChWTdiq+k6qkHDJIM3Y21kpT2fnmC+Zs7sXzpob2fn4uelrn4uoH +idQJCH4WLI7fq2h9PvOS/W156klV+0OWqbR0vyQ5Mupm98QKc3G4pv3h3OriQH3n0Pjy4kT/ +vZ5Hy+vG9mxH04NH4yw/x8pkS13Ng4cDzc2D86yri8MPqutaaNNqbepuxvWIiKg7TWQpREBA +QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBA +QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBA +QEBAQEBA8K6xOPWsvrI0P+cV8hu7R8af9d69P7j0Mzzu2YN66hl1D8f+TJ6x4aHnL5Z/4OLK +8EBHxZ0idl0LbtePLq5fmH7aU9PYv/DmDTND9xrujyysvXHhRefdxocj8z+1CQsTQ02VZRsS +y73bMcw6vfysd+D5xMJ/i5RWXwxVFuRWdQ6t/rj8a2sLkzMLtHAGex6OvPjxD5oZ6qstK8nd +6Pvi+s7XO325/34FLefy1tnvVeXl6N07BdSlu22P31Lu0lR7Q3Vx/kbBeWUD4+wOXR1/0l1R +WvxqtFU09G8qeLm7sZJ+XFn98ze65eWL4Y6Ovsmltbe3ZHluZm5+5Uc0ebS/MS+ndGB04YOk +c3uy88cf7VExNNuATWzBg4H2spi0urn/5kcttRVEmhubmpmZ6hk4xKY1L76Vy00pDEW5S3fH +f6CQcR9Frm0HRdbramZuaH3hTtckdeFp653opKo3h/LqcEt8QlrX1BvMWB7Jj0ms6Zn8qc1o +izH97Pe7lY3W5aWjdC74ZsMqczxQQi8w+cF/xwz7LNxAU1rFODSv6eWPY3NNrI9H3D1qprmk +K6gaWf2jn7SWbSP6h52cBht9r6iseM4vZ5TFvJXR9qBAH1sne+q8uZGFkUtgSe80+7ah+qIg +S2dre1vqkpWZpa1X6uPXx8rig5tHtm3nV1ov2ERTVVHXNr97ihoDkQZCH+/hNV5/oKm6rLzd +1WK63KXnWYHuFlZ0mdZOzg6Wnrn3Hm0uc6Q8eP8BqVsDb53nl0tCfX3jG/5igyc7cxWlZPWt +Aqp7pj5IOt+PdTjEY/P0exRYXlpYXGbPg2MDDxqbHoy/mB0fn1p4uTo/OTo8/oJ1aW1ucmxk +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 ++2+FvNhG86Nc74/+Y5dXOa2SXzTG8AnJZ7Z13fSzMrR1o+5ytbVyvHF3fv6BMYdQYNGTuf5K +W30zOzd3T0cXXROX7I4p5nAB99en/YpZGn28Vk3gjFf581c1aArV2nVCs/X723hDPsKaF249 +nO6/raEqr27j6X/lioeB4J/4NSq7GnS5ThlcaV1fGsidMUnreNKcqWNo4UHJycfRxPh8ceOz +73Tdo9ty+8Xim2eZy0NxQbZ6xk6enl7mhiaBydTac+6C5MGztknf229qTnIW4ddIzCn11hVS +CWXPdeMB4gw9X+p4ruCCq6GZA9VwMwMTt/M5YyuvTJvVVGOebxXOf7dnM9Gsc/yIhGs2xeIX +PaVWFiaWjlQVPd3tHXTM7RLqn7DvbM+OMVY3t/P2pi652VrpmoY2P39tG2OuJeHwl7yxTa90 +2WpJgN5ODt2mobEIbREunZhXps3Ks0rJg0e0wqpezvXdcLezd/TwovvV28neIaGi57WNqrLA +r7+RLJxcqXCX2CvmyO6Pu8HW/EKeVP2bIjz5ebWii7sf1SabGJtRytTJysrY9nzj09lib/V9 +gq7s/HXX7fYLnx+jlgbl12V5FS09PcMjo40luHZwulKKoLkgQlXLjBpa+poGPmEVL5nz+VG+ +eka2VI3szIyNLuaMvFzb4nSeGequrO148brTY+JxV+39gcXFuZnpiY768sys8rbbMVJGHndZ +bpnpwab46zF5Ne1DfX3tHU9mJx7VVt8bfrXOeTlWmpMUExNX/fDNveOVB7WFMTExaRWdyz+4 +6zre0tAwwN5lWRytzC1sfrLZsns50FaTnhwfw0JiWvnwwtvCSBZH6+91snfKWGEkzWNUeS/H +y7KoisXklLezhtPsqzCStamB/OSYmNjCx9OsuXh+pL6q/iH7/uWptob6/onvbOuZR+2VdW0v +vu8mWuxvbHv4jCb5xEDjjesx8fnVz8dGuvp6RmemOurrO5+wVdVCT3N9B2unbKq7PoWqTVxK +49Dru+UL4y01TU+n2RJaaCm4SdWsrIsdePPy4f2ae93P3tjSHytPTi2q6uh90Nz2mG3YLA/c +b+roZ9+13FaTRze8off1RdXa8wf3aloebnZKj/U2FZS1rZtULyfrC1KpG+NvVX4v7OLlRE9G +cix1qaC6c+ktoTvPaqsans5sKnhppKq0rHt0+knn/fr218JjnnXWFtc9YGVd6qgouE4VmpLV +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 +wJn/A5vjFyA= + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-0.8 0 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-0.8 0 l +-1 -0.333 l +h + + + + +0.6 0 0 0.6 0 0 e +0.4 0 0 0.4 0 0 e + + + + +0.6 0 0 0.6 0 0 e + + + + + +0.5 0 0 0.5 0 0 e + + +0.6 0 0 0.6 0 0 e +0.4 0 0 0.4 0 0 e + + + + + +-0.6 -0.6 m +0.6 -0.6 l +0.6 0.6 l +-0.6 0.6 l +h +-0.4 -0.4 m +0.4 -0.4 l +0.4 0.4 l +-0.4 0.4 l +h + + + + +-0.6 -0.6 m +0.6 -0.6 l +0.6 0.6 l +-0.6 0.6 l +h + + + + + +-0.5 -0.5 m +0.5 -0.5 l +0.5 0.5 l +-0.5 0.5 l +h + + +-0.6 -0.6 m +0.6 -0.6 l +0.6 0.6 l +-0.6 0.6 l +h +-0.4 -0.4 m +0.4 -0.4 l +0.4 0.4 l +-0.4 0.4 l +h + + + + + + +-0.43 -0.57 m +0.57 0.43 l +0.43 0.57 l +-0.57 -0.43 l +h + + +-0.43 0.57 m +0.57 -0.43 l +0.43 -0.57 l +-0.57 0.43 l +h + + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-0.8 0 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-0.8 0 l +-1 -0.333 l +h + + + + +-1 0.333 m +0 0 l +-1 -0.333 l + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h +-1 0 m +-2 0.333 l +-2 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h +-1 0 m +-2 0.333 l +-2 -0.333 l +h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h + + + + +0.6 0 0 0.6 0 0 e +0.4 0 0 0.4 0 0 e + + + + +0.6 0 0 0.6 0 0 e + + + + + +0.5 0 0 0.5 0 0 e + + +0.6 0 0 0.6 0 0 e +0.4 0 0 0.4 0 0 e + + + + + +-0.6 -0.6 m +0.6 -0.6 l +0.6 0.6 l +-0.6 0.6 l +h +-0.4 -0.4 m +0.4 -0.4 l +0.4 0.4 l +-0.4 0.4 l +h + + + + +-0.6 -0.6 m +0.6 -0.6 l +0.6 0.6 l +-0.6 0.6 l +h + + + + + +-0.5 -0.5 m +0.5 -0.5 l +0.5 0.5 l +-0.5 0.5 l +h + + +-0.6 -0.6 m +0.6 -0.6 l +0.6 0.6 l +-0.6 0.6 l +h +-0.4 -0.4 m +0.4 -0.4 l +0.4 0.4 l +-0.4 0.4 l +h + + + + + + +-0.43 -0.57 m +0.57 0.43 l +0.43 0.57 l +-0.57 -0.43 l +h + + +-0.43 0.57 m +0.57 -0.43 l +0.43 -0.57 l +-0.57 0.43 l +h + + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-0.8 0 l +-1 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-0.8 0 l +-1 -0.333 l +h + + + + +-1 0.333 m +0 0 l +-1 -0.333 l + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h +-1 0 m +-2 0.333 l +-2 -0.333 l +h + + + + +0 0 m +-1 0.333 l +-1 -0.333 l +h +-1 0 m +-2 0.333 l +-2 -0.333 l +h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +\renewcommand\rmdefault{cmss} +\makeatletter +\leftmargini 1.5em +\leftmargin \leftmargini +\leftmarginii 1.2em +\leftmarginiii 1em +\def\@listI{\leftmargin\leftmargini + \parsep \z@ + \partopsep 3pt + \topsep \z@ + \itemsep \z@} +\@listI +\def\@listii {\leftmargin\leftmarginii + \labelwidth\leftmarginii + \advance\labelwidth-\labelsep + \topsep \z@ + \parsep \z@ + \itemsep \parsep} +\def\@listiii{\leftmargin\leftmarginiii + \labelwidth\leftmarginiii + \advance\labelwidth-\labelsep + \topsep \z@ + \parsep \z@ + \partopsep \z@ + \itemsep \topsep} +\makeatother + + + + + + + + + +Some Preliminaries +\begin{itemize} +\item This description corresponds to the {\tt RU-RAU-split} branch for RAN infrastructure components (located in {\tt targets/DOCS/oai\_L1\_L2\_procedures.pdf}, editable with {\tt ipe}) +\item we describe +\begin{enumerate} +\item node functions +\item current functional splits and packet formats +\item RAN procedures +\item process scheduling +\end{enumerate} +\end{itemize} + + + + + +NGFI Harmonization in OAI +\small +\begin{itemize} +\item New descriptions for OAI RAN infrastructure Node Functions +\begin{itemize} +\item{\tt NGFI\_RCC} : Radio Cloud Center +\item{\tt NGFI\_RAU} : Radio Aggregation Unit +\item{\tt NGFI\_RRU} : Remote Radio Unit +\item{\tt 3GPP\_BBU} : Baseband Unit +\item{\tt 3GPP\_eNodeB} : Complete eNodeB +\end{itemize} +\end{itemize} +\small Source: China Mobile - {\tt http://www.windriver.com.cn/windforum/download/wf2015\_networking03.pdf} + + + + + +\small\begin{itemize} +\item Current OAI implementation (RRU/RCC) supports either +\begin{itemize} +\item IF5 time-domain fronthaul ($>$ 1 GbE required) +\item IF4.5 split (FFTs) (280 Mbit/s/antenna port fronthaul – 20 MHz carrier) per carrier/sector +\item Soon IF2 (NFAPI) +\item IF1’ for “PDCP/RRC” soon (3GPP Fh-C/Fh-U) +\end{itemize} +\end{itemize} +NGFI split points + + + + + + +OAI RAN Software Architecture + + + + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +528 64 m +528 32 l +640 32 l +640 64 l +h + + +528 64 m +528 32 l +640 32 l +640 64 l +h + + +528 101 m +528 48 l +736 48 l +736 101 l +h + + +392 376 m +392 296 l +512 296 l +512 376 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +392 376 m +392 296 l +512 296 l +512 376 l +h + + +136 312 m +136 272 l +200 272 l +200 312 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + +\tiny\bf LTE\\ +MODEM + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +96 408 m +96 360 l +208 360 l +208 408 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + +\tiny\bf LTE/NR/NB\\ +PDCP + +128 320 m +128 280 l +192 280 l +192 320 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + +\tiny\bf LTE\\ +RRC + +112 464 m +112 440 l +648 440 l +648 464 l +h + + +432 224 m +432 224 l +432 224 l +432 224 l +h + +\bf OSS/BSS/MEC + +192 296 m +232 296 l +232 404 l +256 404 l + + +144 288 m +144 320 l + + +384 368 m +448 368 l + + +384 352 m +448 352 l + + +152 456 m +152 368 l + + +304 456 m +304 408 l + + +456 456 m +456 416 l + + +600 456 m +600 409 l + + +512 368 m +576 368 l + + +512 352 m +576 352 l + + +88 384 m +8 384 l + + +128 264 m +8 264 l + +OAI Functional Splits + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\bf\tiny LTE-L1 + +192 368 m +96 368 l + + +192 368 m +96 368 l + + +192 368 m +96 368 l + +\bf\tiny Management +\bf\tiny data (user/control plane) +\bf\tiny configuration + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\tiny\bf LTE\\ +MAC-RLC + +288 432 m +288 432 l +288 432 l +288 432 l +h + + +240 460 m +240 40 l +520 40 l +520 460 l +h + + +384 416 m +384 416 l +384 416 l +384 416 l +h + + +560 416 m +560 336 l +656 336 l +656 416 l +h + + +88 456 m +88 40 l +216 40 l +216 221 l +216 261 l +216 456 l +100.8 456 l +88 456 l + +\bf\tiny Radio-Cloud Center (RCC) +\tiny\bf Radio-Access Unit (RAU) + +136 248 m +136 208 l +200 208 l +200 248 l +h + + +128 256 m +128 216 l +192 216 l +192 256 l +h + +\tiny\bf NR\\ +RRC + +128 229 m +112 229 l +112 261 l +112 360 l + + +488 368 m +488 304 l +504 304 l +504 368 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +384 368 m +448 368 l + + +384 352 m +448 352 l + + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\bf\tiny NR-L1 +\tiny\bf NR\\ +MAC-RLC + +488 368 m +488 304 l +504 304 l +504 368 l +h + +\tiny PRECODE +\tiny PRECODE + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + +\tiny\bf NR\\ +MODEM + +512 368 m +576 368 l + + +512 352 m +576 352 l + + +560 231 m +560 160 l +656 160 l +656 231 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +336 264 m +536 264 l + + +336 248 m +536 248 l + + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\bf\tiny LTE-L1 + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\tiny\bf LTE\\ +MAC-RLC + +488 368 m +488 304 l +504 304 l +504 368 l +h + +\tiny PRECODE + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + +\tiny\bf LTE\\ +MODEM + +232 264 m +256 264 l + + +256 424 m +224 424 l +224 316 l +256 316 l + + +64 264 m +64 264 l + + +528 288 m +528 208 l +736 208 l +736 288 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\tiny\bf NR\\ +MAC-RLC + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\tiny\bf NB-IoT\\ +MAC-RLC + +128 264 m +8 264 l + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + + +336 264 m +536 264 l + + +336 248 m +536 248 l + + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\bf\tiny NR-L1 + +488 368 m +488 304 l +504 304 l +504 368 l +h + +\tiny PRECODE + +576 384 m +576 336 l +640 336 l +640 384 l +h + + +624 336 m +624 336 l +624 336 l +624 336 l +h + + +608 336 m +608 336 l +608 336 l +608 336 l +h + +\tiny\bf NR\\ +MODEM + +528 288 m +528 208 l +736 208 l +736 288 l +h + +\tiny\bf Remote Radio-Unit (RRU) + +336 72 m +576 72 l + + +336 86 m +576 88 l + + +576 384 m +576 336 l +640 336 l +640 384 l +h + +\tiny\bf NB-IoT\\ +RRC + +128 264 m +8 264 l + + +104 360 m +104 88 l +120 88 l + + +192 88 m +256 88 l + + +528 64 m +528 32 l +640 32 l +640 64 l +h + +\tiny\bf NB-IoT\\ +L1/MODEM + +224 384 m +208 384 l + + +192 240 m +256 240 l + + +232 240 m +232 168 l +256 168 l + + +224 192 m +224 192 l + + +224 192 m +224 192 l + + +224 312 m +224 72 l +256 72 l + + + + + +OAI Functional Splits +\tiny\begin{itemize} +\item OAI currently implements the following entities in openairinterface5g +\begin{itemize} +\item LTE-MODEM (eNB 36.211 OFDM modulation/demodulation) +\item LTE-L1 (eNB 36.211/212/213) +\item LTE-MACRLC (eNB 36.321/322) +\item LTE-PDCP (eNB PDCP/GTPU 36.323) +\item LTE-RRC (eNB RRC/SCTP 36.331) +\end{itemize} +\item Each entity comprises +\begin{itemize} +\item a northbound interface (backhaul/midhaul/fronthaul and configuration) +\item a southbound interface (midaul/fronthaul and configuration) +\item one or two management interfaces +\item Three computing nodes +\begin{itemize} +\item {\bf Radio Cloud Center (RCC)} : multiple RRC/PDCP entities +\item {\bf Radio-Access Unit (RAU)}: multiple MACRLC entities with medium-latency midhaul and L1 entities with low-latency fronthaul. +\item {\bf Remote Radio-Unit (RRU)}: Equipment at radio site. Varying degrees of processing elements depending on fronthaul/midhaul interface. +\end{itemize} +\end{itemize} +\item Each entity has a configuration which is a local file or received via the management interface +\item default interface between all entities is implemented using a UDP socket. Transport is configurable via a dynamically-loadable networking device +\end{itemize} + +288 192 m +288 64 l +432 64 l +432 192 l +h + +OAI entity + +336 171 m +336 208 l + + +384 171 m +384 208 l + + +336 171 m +336 208 l + + +384 171 m +384 208 l + + +240 80 m +288 80 l + + +240 80 m +288 80 l + + +16 0 0 16 288 224 e + + +16 0 0 16 288 224 e + +\tiny\bf Northbound interface +\tiny\bf Southbound interface +\tiny\bf data +\tiny\bf data +\tiny\bf in-band configuration +\tiny\bf in-band configuration +\tiny\bf OSS/BSS +\tiny\bf FlexRAN + +240 80 m +288 80 l + +\tiny\tt .conf + + + + + +511.895 513.539 m +511.895 14.2386 l +734.284 14.2386 l +734.284 513.539 l +h + + +511.895 513.539 m +511.895 14.2386 l +734.284 14.2386 l +734.284 513.539 l +h + + +511.895 513.539 m +511.895 14.2386 l +734.284 14.2386 l +734.284 513.539 l +h + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +16 432 m +16 112 l +192 112 l +192 432 l +h + +Functional Splits (Current) + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +RRC +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-C +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-U +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX +\end{tiny} + + +384 432 m +384 384 l + + +384 432 m +384 384 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt rf\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +RRC +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-C +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-U +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +3GPP\_eNodeB +3GPP\_BBU +\tiny to MME +\tiny to S-PGw + +384 432 m +384 384 l + + +384 432 m +384 384 l + +\tiny to MME +\tiny to S-PGw + +160 112 m +160 112 l +160 112 l +160 112 l +h + + +144 112 m +144 112 l +144 112 l +144 112 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt USB3 or PCIe} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF5 / ethernet} +\end{tiny} + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +RRC +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-C +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-U +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +upper-PHY RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +NGFI\_RCC (IF4.5) + +384 432 m +384 384 l + + +384 432 m +384 384 l + +\tiny to MME +\tiny to S-PGw + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF4p5 / ethernet} +\end{tiny} + +\setstretch{.5}\begin{tiny} +upper-PHY TX +\end{tiny} + + +384 432 m +384 384 l + +\tiny to NGFI\_RRU + +384 432 m +384 384 l + +\tiny to NGFI\_RRU or RRH\_gw + +384 432 m +384 384 l + +\tiny to RF Device + + + + + +1.83417 462.604 m +1.83417 50.8252 l +207.006 50.8252 l +207.006 462.604 l +h + + +1.83417 462.604 m +1.83417 50.8252 l +207.006 50.8252 l +207.006 462.604 l +h + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +RRC +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-C +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-U +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +NGFI\_RCC (IF1'') + +384 432 m +384 384 l + + +384 432 m +384 384 l + +\tiny to MME +\tiny to S-PGw + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF1pp} / ethernet +\end{tiny} + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +RRC +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-C +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +GTP-U +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +NGFI\_RCC (IF1') + +384 432 m +384 384 l + + +384 432 m +384 384 l + +\tiny to MME +\tiny to S-PGw + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF1p} / ethernet +\end{tiny} + +\tiny to NGFI\_RRU + +384 432 m +384 384 l + +\tiny to NGFI\_RAU + +384 432 m +384 384 l + +\tiny to NGFI\_RAU +Functional Splits (Current) + +1.83417 462.604 m +1.83417 50.8252 l +207.006 50.8252 l +207.006 462.604 l +h + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +upper-PHY RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +NGFI\_RAU(IF1'') + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF4p5 / ethernet} +\end{tiny} + +\setstretch{.5}\begin{tiny} +upper-PHY TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF1pp / ethernet} +\end{tiny} + + +384 432 m +384 384 l + +\tiny to NGFI\_RCC + +384 432 m +384 384 l + +\tiny to NGFI\_RRU + + + + + +1.83417 462.604 m +1.83417 50.8252 l +207.006 50.8252 l +207.006 462.604 l +h + + +1.83417 462.604 m +1.83417 50.8252 l +207.006 50.8252 l +207.006 462.604 l +h + + +1.83417 462.604 m +1.83417 50.8252 l +207.006 50.8252 l +207.006 462.604 l +h + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +NGFI\_RRU (IF5) + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF5/ ethernet} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt rf\_device} +\end{tiny} + +NGFI\_RRU (IF4.5) + +384 432 m +384 384 l + +\tiny to NGFI\_RCC, NGFI\_RAU,3GPP\_BBU + +384 432 m +384 384 l + +\tiny to RF Device + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt USB3, PCIe, CPRI} +\end{tiny} + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF4p5/ ethernet} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt rf\_device} +\end{tiny} + + +384 432 m +384 384 l + +\tiny to NGFI\_RCC, NGFI\_RAU + +384 432 m +384 384 l + +\tiny to RF Device + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt USB3, PCIe, CPRI} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +lower-PHY RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +lower-PHY TX +\end{tiny} + + +16 432 m +16 112 l +192 112 l +192 432 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +\setstretch{.5}\begin{tiny} +upper-PHY TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF1pp\_4P5 / ethernet} +\end{tiny} + + +384 432 m +384 384 l + +\tiny to NGFI\_RCC, NGFI\_RAU + +384 432 m +384 384 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt USB3, PCIe, CPRI} +\end{tiny} + +\tiny to RF Device +Functional Splits (Current) +NGFI\_RRU\par +(IF1'') + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +lower-PHY RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +lower-PHY TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +upper-PHY RX +\end{tiny} + + + + + +Some Notes on usage of splits +\tiny\begin{itemize} +\item IF4p5 corresponds to the split-point at the input (TX) and output (RX) of the OFDM symbol generator (i.e. frequency-domain signals). According to NGFI, IF4 is "Resource mapping and IFFT" and "FFT and Resource demapping". We currently do not try to exploit multiplexing gains for unused spectral components. So, IF4p5 is simply compressed transmitted or received resource elements in the usable channel band. +\item The simplest deployment for DAS (indoor) is one NGFI\_RCC (IF4p5) and many NGFI\_RRU (IF4p5). Spatio-temportal filtering (Precoding, later) is done in RCC and RRU perform IFFT/FFT and signal generation/acquisition. Fronthaul rates in this case are feasible with 1GbE copper links. This allows for PoE in addition to fronthaul data. +\item More complex indoor, for instance with RCC in a common data center with outdoor RRS, could be +\begin{enumerate} + \item RCC-RAU with IF1'', RAU-RRU with IF4p5. Spatio-temporal filtering is done in frequency-domain in RAU along with full TX and RX processing (L1/L2) for the indoor RRS. Note that IF1' fronthaul on TX to RRU would be difficult because spatio-temporal filtering should be used. RRU does only IFFT/FFT and signal generation/acquisition +\item RCC-RAU with IF1', RAU-RRU with IF4p5. Here RCC does L2, RAU does L1 and precoding for RRS. +\end{enumerate} +\item A massive-MIMO solution would consist either of +\begin{enumerate} +\item an embedded RAU with processing (Spatio-temporal in frequency-domain, lower/upper PHY TX/RX) like the IF1' DAS solution above +\item or more simply a high-speed fronthaul (IF4p5) with an RAU for multiple sites +\item directly connected to RCC via high-speed IF4p5 (several virtual cells, precoder and IFFT/FFT in array). +\end{enumerate} +\item RCC solution with IF1'' would cater to evolved-PDCP for heterogenity (4G,5G,WIFI,IoT) +\item Currently supported node functionalities +\begin{enumerate} +\item {\tt 3GPP\_eNodeB} +\item {\tt 3GPP\_eNodeB\_BBU} [NGFI\_IF5] +\item {\tt NGFI\_RCC} [NGFI\_IF4p5] +\item {\tt NGFI\_RRU} [NGFI\_IF5] +\item {\tt NGFI\_RRU} [NGFI\_IF4p5] +\end{enumerate} +\end{itemize} + + + + +RU - L1 negotiation + +64 448 m +64 256 l +256 256 l +256 448 l +h + + +64 448 m +64 256 l +256 256 l +256 448 l +h + +RRU Entity +RAU/RCC Entity + +544 192 m +544 256 l + + +256 320 m +448 320 l + + +448 288 m +256 288 l + + +544 192 m +544 256 l + +\tiny\tt .conf +\tiny\tt .conf +\tiny\tt fronthaul data (IF5,IF4p5) + +256 320 m +448 320 l + + +448 288 m +256 288 l + +\tiny\tt RRU control/config +\begin{small} +Control and Configuration protocol +\begin{enumerate} +\item RAU$\rightarrow$ RRU : heartbeat (capabilities request) +\item RRU$\rightarrow$ RAU: capabilities indication +\item RAU$\rightarrow$ RRU: configuration (band, dl\_Carrier,ul\_Carrier, dl\_RS\_EPRE, rx/tx attenuation) +\end{enumerate} +\end{small} +During steady state, the control port manages the link quality and status (packet losses, synchronization state, start/stop, etc.) + + + + +\begin{small} +\begin{itemize} +\item IF5 interface +\begin{itemize} +\item DL subframes with timestamp (16-bit samples) +\item UL subframes with timestamp (16-bit samples) +\item optional A-law compression (13$\rightarrow$8bit) +\end{itemize} +\item IF4p5 interface +\begin{itemize} +\item DL packets, ofdm symbols with frame/subframe/symbol count +\item UL packets, ofdm symbols with frame/subframe/symbol count (16-bit) +\item UL PRACH packets with frame/subframe count (16-bit) +\item optional A-law compression (13$\rightarrow$8bit) +\end{itemize} +\end{itemize} +\end{small} +RU - L1 data plane + + + + + +544 288 m +544 256 l +704 256 l +704 288 l +h + +IF5 Packet Format (16-bit) + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + +0 +16 +32 +48 +15 +31 +47 +63 + +64 320 m +64 288 l +544 288 l +544 320 l +h + + +544 320 m +544 288 l +704 288 l +704 320 l +h + + +64 288 m +64 256 l +384 256 l +384 288 l +h + + +384 288 m +384 256 l +544 256 l +544 288 l +h + + +544 288 m +544 256 l +704 256 l +704 288 l +h + +\small Destination Address +\small Source +\small Type (0x1234) +\small RF Config +\small Address + +64 160 m +64 128 l +384 128 l +384 160 l +h + +\small Frame Check Sequence + +256 240 m +256 240 l +256 240 l + +\small Timestamp + +5 63.5079 m +5 46.9999 l +645 46.9999 l +645 63.5079 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +256 240 m +256 240 l +256 240 l + + +166 304 m +165.917 272.508 l +166.247 272.508 l + + +486 304 m +486.316 272.508 l +485.986 272.508 l + + +486.316 256 m +486.646 224 l +485.657 224 l + + +486.316 256 m +486.646 224 l +485.657 224 l + +\tiny $I_0$ +\tiny $Q_0$ +\tiny $I_1$ +\tiny $Q_1$ +\tiny $Q_{N-2}$ +\tiny $Q_{N-2}$ +\tiny $I_{N-1}$ +\tiny $Q_{N-1}$ +\tiny +\begin{itemize} +\item {\bf Type:} 2 byte (16 bit) field that specifies the RoE protocol +\item {\bf RX Config:} 16-bit. Currently just antenna index (0-7). Can later be used for gain/timing adjustments. +\item {\bf Timstamp:} Timestamp in samples of the first sample of the received packet. +\end{itemize} +\begin{itemize} +\item {\bf data block :} Uncompressed IQ samples, 16-bit resolution for each real and imaginary component. $N$ complex samples per packet. $N$ can be configured at initialization. +\end{itemize} + + + + +IF5 Packet Format (8-bit) + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + +0 +16 +32 +48 +15 +31 +47 +63 + +64 320 m +64 288 l +544 288 l +544 320 l +h + + +544 320 m +544 288 l +704 288 l +704 320 l +h + + +64 288 m +64 256 l +384 256 l +384 288 l +h + + +384 288 m +384 256 l +544 256 l +544 288 l +h + + +544 288 m +544 256 l +704 256 l +704 288 l +h + + +384 256 m +384 224 l +704 224 l +704 256 l +h + +\small Destination Address +\small Source +\small Type (0xBEEF) +\small RX Flags +\small Address + +544 288 m +544 256 l +704 256 l +704 288 l +h + +\small FIFO\_status + +544 288 m +544 256 l +704 256 l +704 288 l +h + +\tiny SeqNum +\tiny rsvd + +248.997 435.732 m +248.997 403.732 l + +\small Word0 + +5 63.5079 m +5 46.9999 l +645 46.9999 l +645 63.5079 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +166 304 m +165.917 272.508 l +166.247 272.508 l + + +486 304 m +486.316 272.508 l +485.986 272.508 l + + +486.316 256 m +486.646 224 l +485.657 224 l + +\tiny $I_0$ + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + +\tiny $Q_0$ +\tiny $I_1$ +\tiny $Q_1$ +\tiny $I_2$ +\tiny $Q_2$ +\tiny $I_3$ +\tiny $Q_3$ +\tiny $I_{638}$ +\tiny $Q_{638}$ +\tiny $I_{639}$ +\tiny $Q_{639}$ +\tiny +\begin{itemize} +\item {\bf Type:} 2 byte (16 bit) field that specifies the RoE protocol +\item {\bf RX Flags:} overrun indicator. should be '0'. +\item {\bf FIFO status:} 2 bytes. should be '0'. +\item {\bf SeqNum:} 1 byte. Sequence number of the ethernet packet. +\item {\bf rsvd:} 1 byte. shoult be '0'. \item {\bf Word0:} 4 byte (32-bit). should be '0'. +\item {\bf Timstamp:} Timestamp in samples of the first sample of the received packet. \end{itemize} +\begin{itemize} +\item {\bf data block :} Uncompressed IQ samples, 8-bit resolution for each real and imaginary component. 640 complex samples per packet. +\end{itemize} + +384 256 m +384 224 l +704 224 l +704 256 l +h + +\small Timestamp + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +486 304 m +486.316 272.508 l +485.986 272.508 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + +\tiny $I_4$ +\tiny $Q_4$ +\tiny $I_5$ +\tiny $Q_5$ + +64 160 m +64 128 l +384 128 l +384 160 l +h + +\small Frame Check Sequence + + + + +IF4p5 Packet Formats (RAW) + +272 512 m +272 512 l +272 512 l +272 512 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + +0 +16 +32 +48 +15 +31 +47 +63 + +64 320 m +64 288 l +544 288 l +544 320 l +h + + +544 320 m +544 288 l +704 288 l +704 320 l +h + + +64 288 m +64 256 l +384 256 l +384 288 l +h + + +384 288 m +384 256 l +544 256 l +544 288 l +h + + +544 288 m +544 256 l +704 256 l +704 288 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +384 256 m +384 224 l +704 224 l +704 256 l +h + + +64 160 m +64 96 l +704 96 l +704 160 l +h + +\small Destination Address +\small Source +\small Type (0x080A) +\small Subtype (0x0021) +\small Address +\small LTE PRACH Configuration +\small Reserved +\small PRACH data block (one antenna) + +64 160 m +64 128 l +384 128 l +384 160 l +h + +\small Frame Check Sequence + +384 160 m +384 128 l +704 128 l +704 160 l +h + +IF4p5 PRACH Packet (RRU$\rightarrow$ RAU,RCC) +\tiny +\begin{itemize} +\item {\bf Type:} 2 byte (16 bit) field that specifies the RoE protocol +\item {\bf Subtype:} 2 byte (16 bit) field that specifies the packet subtype +\item {\bf Reserved:} 4 byte (32 bit) field reserved +\item {\bf LTE PRACH conf:} 4 byte (32-bit) field that details the configuration of the LTE PRACH packet +\end{itemize} +\vskip 3pt +\begin{tabular}{|c|c|} +\hline +{\bf field (0 is LSB, 31 is MSB)} & {\bf description}\\ \hline +rsvd (0:2) & Reserved.\\ \hline +ant (3:5) & 3-bit Antenna index of LTE PRACH packet\\ \hline +RF Num (6:21) & 16-bit field indicating the Radio Frame number of this received PRACH packet\\ \hline +SF Num (22:25) & 4-bit field indicating the sub-frame number in the radio frame for the LTE PRACH packet\\ + & Valid range of 0 to 9.\\ \hline +Exponent (26:31) & FFT exponent output (0 if unscaled) \\ +\hline +\end{tabular} +\begin{itemize} +\item {\bf PRACH data block:} Uncompressed IQ samples +\end{itemize} + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + +\tiny RE 0 (Real) +\tiny RE 0 (Imag) +\tiny RE 1 (Real) +\tiny RE 1 (Imag) + +166 304 m +165.917 272.508 l +166.247 272.508 l + + +486 304 m +486.316 272.508 l +485.986 272.508 l + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + +\tiny RE 837 (Real) +\tiny RE 837 (Imag) +\tiny RE 838 (Real) +\tiny RE 838 (Imag) + +166 304 m +165.917 272.508 l +166.247 272.508 l + + +486 304 m +486.316 272.508 l +485.986 272.508 l + + +6.00001 47.492 m +6.00001 32 l +646 32 l +646 47.492 l +h + + +528 16 m +528 16 l +528 16 l +528 16 l +h + + +560 16 m +560 16 l +560 16 l +560 16 l +h + + + + + + +64 224 m +64 192 l +224 192 l +224 224 l +h + + +224 224 m +224 192 l +384 192 l +384 224 l +h + + +384 224 m +384 192 l +544 192 l +544 224 l +h + + +544 224 m +544 192 l +704 192 l +704 224 l +h + + +64 192 m +64 160 l +224 160 l +224 192 l +h + + +224 192 m +224 160 l +384 160 l +384 192 l +h + + +384 192 m +384 160 l +544 160 l +544 192 l +h + + +544 192 m +544 160 l +704 160 l +704 192 l +h + +\small Gain 0 +\small Gain 1 +\small Gain 4 +\small Gain 5 +\small Gain 2 +\small Gain 3 +\small Gain 6 +\small Gain 7 + +272 512 m +272 512 l +272 512 l +272 512 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + +0 +16 +32 +48 +15 +31 +47 +63 + +64 320 m +64 288 l +544 288 l +544 320 l +h + + +544 320 m +544 288 l +704 288 l +704 320 l +h + + +64 288 m +64 256 l +384 256 l +384 288 l +h + + +384 288 m +384 256 l +544 256 l +544 288 l +h + + +544 288 m +544 256 l +704 256 l +704 288 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +384 256 m +384 224 l +704 224 l +704 256 l +h + +\small Destination Address +\small Source +\small Type (0x080A) +\small Subtype (0x0019) +\small Address +\small Frame status +\small Reserved + +64 160 m +64 128 l +384 128 l +384 160 l +h + +\small Frame Check Sequence +\tiny +\begin{itemize} +\item {\bf Type:} 2 byte (16 bit) field that specifies the RoE protocol +\item {\bf Subtype:} 2 byte (16 bit) field that specifies the packet subtype +\item {\bf Reserved:} 4 byte (32 bit) field reserved +\item {\bf Frame Status:} 4 byte (32 bit) field +\end{itemize} +\vskip 3pt +\begin{tabular}{|c|c|} +\hline +{\bf field (0 is LSB, 31 is MSB)} & {\bf description}\\ \hline +{\bf ant} (0:2) & The number of Antenna Carriers represented in the packet. Antenna numbers \\ +& range from 0 to 7 with valid inputs being 0,1, 3 and 7 (1,2,4,8 antennas)\\ \hline +{\bf ant start} (3:5) & starting antenna number\\ \hline +{\bf RF Num} (6:21) & 16-bit field indicating the Radio Frame number of the UL\_RE samples\\ \hline +{\bf SF Num} (22:25) & 4-bit field indicating the sub-frame number in the radio frame for the UL\_RE samples\\ + & Valid range of 0 to 9.\\ \hline +{\bf Sym Num:} (26:29) & Symbol number. Valid range of 0 to 13. \\ +{\bf rsvd:} (30:31) & reserved\\ +\hline +\end{tabular} +\begin{itemize} +\item {\bf ULRE data block:} compressed IQ samples (8-bit A-law). $N$ is the number of resource elements $N_{\mathrm{RB}}^{\mathrm{UL}}$. +\end{itemize} + +5 63.5079 m +5 46.9999 l +645 46.9999 l +645 63.5079 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + +IF4p5 Packets : ULRE (RRU$\rightarrow$ RAU,RCC) + +256 240 m +256 240 l +256 240 l + + +166 304 m +165.917 272.508 l +166.247 272.508 l + + +486 304 m +486.316 272.508 l +485.986 272.508 l + + +486.316 256 m +486.646 224 l +485.657 224 l + + +486.316 256 m +486.646 224 l +485.657 224 l + + +258.16 141.771 m +258.16 141.771 l + + +418.597 191.907 m +418.597 191.907 l + + +429.181 79.9357 m +429.181 79.9357 l + +\tiny RE 0\\Ant 1 (Re) +\tiny RE 0\\Ant 1 (Im) +\tiny RE 1\\Ant 1 (Re) +\tiny RE 1\\Ant 1 (Im) +\tiny RE 2\\Ant 1 (Re) +\tiny RE 2\\Ant 1 (Im) +\tiny RE 3\\Ant 1 (Re) +\tiny RE 3\\Ant 1 (Im) +\tiny RE $N-4$\\Ant $R$ (Re) +\tiny RE $N-4$\\Ant $R$ (Im) +\tiny RE $N-3$\\Ant $R$ (Re) +\tiny RE $N-3$\\Ant $R$ (Im) +\tiny RE $N-2$\\Ant $R$ (Re) +\tiny RE $N-2$\\Ant $R$ (Im) +\tiny RE $N-1$\\Ant $R$ (Re) +\tiny RE $N-1$\\Ant $R$ (Im) + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + + + + + +272 512 m +272 512 l +272 512 l +272 512 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + + +64 352 m +64 320 l +224 320 l +224 352 l +h + +0 +16 +32 +48 +15 +31 +47 +63 + +64 320 m +64 288 l +544 288 l +544 320 l +h + + +544 320 m +544 288 l +704 288 l +704 320 l +h + + +64 288 m +64 256 l +384 256 l +384 288 l +h + + +384 288 m +384 256 l +544 256 l +544 288 l +h + + +544 288 m +544 256 l +704 256 l +704 288 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +384 256 m +384 224 l +704 224 l +704 256 l +h + +\small Destination Address +\small Source +\small Type (0x080A) +\small Subtype (0x0020) +\small Address +\small Frame status +\small Reserved + +64 160 m +64 128 l +384 128 l +384 160 l +h + +\small Frame Check Sequence +\tiny +\begin{itemize} +\item {\bf Type:} 2 byte (16 bit) field that specifies the RoE protocol +\item {\bf Subtype:} 2 byte (16 bit) field that specifies the packet subtype +\item {\bf Reserved:} 4 byte (32 bit) field reserved +\item {\bf Frame Status:} 4 byte (32 bit) field +\end{itemize} +\vskip 3pt +\begin{tabular}{|c|c|} +\hline +{\bf field (0 is LSB, 31 is MSB)} & {\bf description}\\ \hline +{\bf ant} (0:2) & The number of Antenna Carriers represented in the packet. Antenna numbers \\ +& range from 0 to 7 with valid inputs being 0,1, 3 and 7 (1,2,4,8 antennas)\\ \hline +{\bf ant start} (3:5) & starting antenna number\\ \hline +{\bf RF Num} (6:21) & 16-bit field indicating the Radio Frame number of this DLRE packet\\ \hline +{\bf SF Num} (22:25) & 4-bit field indicating the sub-frame number in the radio frame for the DLRE packet\\ + & Valid range of 0 to 9.\\ \hline +{\bf Sym Num:} (26:29) & Symbol number. Valid range of 0 to 13. \\ +{\bf rsvd:} (30:31) & reserved\\ +\hline +\end{tabular} +\begin{itemize} +\item DLRE data block : compressed IQ samples (8-bit A-law). $N$ is the number of resource elements $N_{\mathrm{RB}}^{\mathrm{DL}}$. +\end{itemize} +IF4p5 Packets : DLRE (RAU,RCC $\rightarrow$RRU) + +258.16 141.771 m +258.16 141.771 l + + +418.597 191.907 m +418.597 191.907 l + + +429.181 79.9357 m +429.181 79.9357 l + + +5 63.5079 m +5 46.9999 l +645 46.9999 l +645 63.5079 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +64 256 m +64 224 l +384 224 l +384 256 l +h + + +166 304 m +165.917 272.508 l +166.247 272.508 l + + +486 304 m +486.316 272.508 l +485.986 272.508 l + + +486.316 256 m +486.646 224 l +485.657 224 l + + +486.316 256 m +486.646 224 l +485.657 224 l + +\tiny RE 0\\Ant 1 (Re) +\tiny RE 0\\Ant 1 (Im) +\tiny RE 1\\Ant 1 (Re) +\tiny RE 1\\Ant 1 (Im) +\tiny RE 2\\Ant 1 (Re) +\tiny RE 2\\Ant 1 (Im) +\tiny RE 3\\Ant 1 (Re) +\tiny RE 3\\Ant 1 (Im) +\tiny RE $N-4$\\Ant $R$ (Re) +\tiny RE $N-4$\\Ant $R$ (Im) +\tiny RE $N-3$\\Ant $R$ (Re) +\tiny RE $N-3$\\Ant $R$ (Im) +\tiny RE $N-2$\\Ant $R$ (Re) +\tiny RE $N-2$\\Ant $R$ (Im) +\tiny RE $N-1$\\Ant $R$ (Re) +\tiny RE $N-1$\\Ant $R$ (Im) + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + +248.997 435.732 m +248.997 403.732 l + + + + + + +640 128 m +640 32 l +704 32 l +704 128 l +h + + +640 480 m +640 176 l +720 176 l +720 480 l +h + + +328.159 119.72 m +328.159 15.3556 l +554.022 15.3556 l +554.022 119.72 l +h + + +96 784 m +96 496 l +224 496 l +224 784 l +h + + +-192 928 m +-192 944 l +-192 944 l +-192 928 l +h + + +96 784 m +96 496 l +224 496 l +224 784 l +h + +\begin{small}L1 Instance 0\end{small} +LI instance 1 +\begin{small}MAC/RLC/PDCP Instance 0\end{small} + +364 518 m +364 518 l +364 518 l +364 518 l +h + + +96 784 m +96 496 l +224 496 l +224 784 l +h + + +128 768 m +128 704 l +192 704 l +192 768 l +h + +\setstretch{.5}\begin{tiny} +DL/UL Scheduler +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + + +180 460 m +340 460 l + + +180 460 m +340 460 l + +\begin{tiny}1ms TICK\end{tiny} + +392.067 448.35 m +232.502 360 l + +\begin{tiny}$\mathrm{DCI}_0$, Transport Blocks\end{tiny} + +\begin{tiny}$\mathrm{DCI}_1$\end{tiny} + +\begin{tiny}$\mathrm{DCI}_2$\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_0$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_1$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_2$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_0$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_1$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_2$ +\end{tiny} + + +234.502 211.006 m +387 210 l + + +243.386 213.48 m +243.386 213.48 l + + +232.502 250.102 m +387.004 250.371 l + + +232.502 310 m +387 310 l + + +232.502 346.88 m +387 347 l + + +336.917 451.424 m +185.872 274.589 l + + +232.5 410 m +386.079 409.083 l + +\begin{tiny}Transport Blocks\end{tiny} + +\begin{tiny}Transport Blocks\end{tiny} + +\setstretch{.5}\begin{tiny}CQI/SR/ACK/NAK/PHR\\Transport Blocks\end{tiny} +\setstretch{.5}\begin{tiny}CQI/SR/ACK/NAK/PHR\\Transport Blocks\end{tiny} +\setstretch{.5}\begin{tiny}CQI/SR/ACK/NAK/PHR\\Transport Blocks\end{tiny} + +180 460 m +340 460 l + + +180 460 m +340 460 l + +\begin{tiny}1ms TICK\end{tiny} +\begin{tiny}$\mathrm{DCI}_0$, Transport Blocks\end{tiny} + + +184.502 313 m +332 313 l + +\begin{small}MAC/RLC/PDCP Instance 1\end{small} + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX \\ +$\mathrm{eNB}_0$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX \\ +$\mathrm{eNB}_0$ +\end{tiny} + +\setstretch{.5}\begin{tiny}CQI/SR/ACK/NAK/PHR\\Transport Blocks\end{tiny} + +128 768 m +128 704 l +192 704 l +192 768 l +h + +\setstretch{.5}\begin{tiny} +DL/UL Scheduler +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP RX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +MAC TX +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PDCP TX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC RX +\end{tiny} + +\setstretch{.5}\begin{tiny} +RLC TX +\end{tiny} + +RU/L1 Instances and Component Carriers + +96 784 m +96 496 l +224 496 l +224 784 l +h + + +96 784 m +96 496 l +224 496 l +224 784 l +h + + +364 518 m +364 518 l +364 518 l +364 518 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_3$ +\end{tiny} + + +144 480 m +144 32 l +176 32 l +176 480 l +h + + +176 432 m +176 432 l + + +192 464 m +176 464 l + + +190.041 464 m +190.041 464 l + + +190.041 464 m +190.041 464 l + + +192 464 m +176 464 l + + +192 464 m +176 464 l + + +192 464 m +176 464 l + + +192 464 m +176 464 l + + +192 464 m +176 464 l + + +192 464 m +176 464 l + + +192 464 m +176 464 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_0$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_1$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_2$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_4$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_5$ +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_6$ +\end{tiny} + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +144 464 m +129.959 464 l + + +640 400 m +640 400 l +640 400 l +640 400 l +h + + + + + +\small\begin{itemize} +\item {\em Radio Unit} (RU) is +\begin{itemize} +\item an entity managing a set of {\bf physical} antennas. It can have a {\em local RF unit} or {\em remote RF unit} +\item performs precoding of multiple eNB TX streams and OFDM modulation (TX) and demodulation (RX) (part of 36.211) +\end{itemize} +\item {\em L1 Instance} (indexed by {\tt Mod\_id}, or {\tt enb\_mod\_id}) is a separate set of threads and contexts for the eNB/gNB procedures. There is one MAC/RLC entity associated to all :1 component carriers. +\item {\em L1 Component Carrier} (indexed by {\tt CC\_id}) is +\begin{itemize} +\item a software entity managing the L1 procedures (36.213,36.212,36.211) and can act on +\begin{itemize} +\item sectored antenna component +\item Rel10+ component carrier +\item virtual cell for DAS or Massive-MIMO array +\end{itemize} +\item each L1 instance is managed by one or two threads which operate on a subframe (TX and RX) and can have a {\em local RU} or {\em remote RU} +\item if a remote radio unit the eNB performs the 36.213 specifications only (HARQ, etc.) and connects to the remainder via the IF2 midhaul interface. +\end{itemize} +\end{itemize} +RU/L1 Instances and Component Carriers + + + + +RU/L1 Instances and Component Carriers +\small\begin{itemize} +\item RU may have both an {\tt if\_device} for fronthaul and an {\tt rf\_device} for interconnection with a local RF unit +\item if the {\tt rf\_device} is absent, it must have a southbound fronthaul interface (either IF5 or IF4p5) depending on the local processing of the remote RU +\item if the {\tt if\_device} is absent, it must have a southbound RF interface and {\tt rf\_device}. +\item three types of L1 processing are performed by the RU \begin{itemize} +\item subset of common L1 procedures from 36.211 specifications +\item fronthaul compression/decompression +\item framing +\end{itemize} +\item on TX +\begin{itemize} +\item A-law compression for (NGFI\_RAU\_IF4p5, NGFI\_RAU\_IF5) +\item A-law decompression (for NGFI\_RRU\_IF4p5 and NGFI\_RRU\_IF5) +\item OFDM modulation and cyclic prefix insertion (for NGFI\_RRU\_IF4p5,NGFI\_RAU\_IF5,3GPP\_eNodeB\_BBU,3GPP\_eNodeB) +\item Precoding (for NGFI\_RAU\_IF5, NGFI\_RAU\_IF4p5,3GPP\_eNodeB\_BBU,3GPP\_eNodeB) +\end{itemize} +\end{itemize} + + + + +RU/L1 Instances and Component Carriers +\small\begin{itemize} +\item on RX +\begin{itemize} +\item A-law compression for (NGFI\_RRU\_IF4p5, NGFI\_RRU\_IF5) +\item A-law decompression (for NGFI\_RAU\_IF4p5 and 3GPP\_eNodeB\_BBU) +\item cyclic prefix removal, frequency-shifting, OFDM demodulation, PRACH DFT (for NGFI\_RRU\_IF4p5, NGFI\_RAU\_IF5, 3GPP\_eNodeB\_BBU, 3GPP\_eNodeB) +\end{itemize} +\item On TX path +\begin{itemize} +\item L1 instances/component carriers operate on a set of logical antenna ports (0-3 for TM1-6, 4 for eMBMS, 5 for TM7, 6 for positioning, 7-8 for TM8, etc.) +\item each L1 instance has a list of RUs and the logical antenna ports are mapped to the physical antennas attached to the RUs via the precoding function +\end{itemize} +\end{itemize} + + + + +\small\begin{itemize} +\item Example configurations +\begin{itemize} +\item {\em itsolated eNB:} one instance and one or several component carriers (multiple-frequencies or antenna sectors). Potentially multiple radio-units (for CoMP). Here there is a common MACRLC instnance driving multiple L1 procedures +\item {\em indoor DAS system (RCC split with L1/L2 RAU) Multiple layer 2 instances each driving one or more component carriers} here the RAU implements multiple L1/L2 instances and precoding function. Usually with IF2/IF1'' xhaul to RCC or potentially also MAC/RLC in RAU with IF1' xhaul to RCC. +\item {\em massive-MIMO array} same as 2nd indoor DAS system (i.e. integrated L1/L2 RAU with array) +\end{itemize} +\end{itemize} +RU/L1 Instances and Component Carriers + + + + + +288 384 m +288 96 l +672 96 l +672 384 l +h + + +301.83 142.941 m +301.83 103.286 l +648 104 l +648 144 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +301.83 142.941 m +301.83 103.286 l +648 104 l +648 144 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF4p5 / ethernet} +\end{tiny} + +\setstretch{.5}\begin{tiny} +upper-PHY TX (212,213) +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +389.83 375.941 m +389.83 336.286 l +616 336 l +616 376 l +h + +\setstretch{.5}\begin{tiny} +{\tt NFGI\_IF1pp / ethernet} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +\setstretch{.5}\begin{tiny} +TX PRECODING\\RX COMBINING +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + +\small\begin{itemize} +\item Example: RAU with {\tt NGFI\_IF1pp} xhaul (MAC/PHY split) northbound, {\tt NGFI\_IF4p5} fronthaul southbound, 2 vCell logical interfaces (2 L1/L2 instances, or 1 L2 instance and 2 CCs), 4 RRUs with {\tt NGFI\_IF4p5} + +\end{itemize} + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +upper-PHY RX (212,213) +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +upper-PHY RX (212,213) +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +upper-PHY TX (212,213) +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_0$ +\end{tiny} + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_1$ +\end{tiny} + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_2$ +\end{tiny} + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_3$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{eNB}_0$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{eNB}_1$ +\end{tiny} + +RAU Example (DAS) + + + + + +168 416 m +168 32 l +576 32 l +576 416 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX0 +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +176 176 m +176 136 l +552 136 l +552 176 l +h + +\setstretch{.5}\begin{tiny} +{\tt NGFI\_IF4p5 / ethernet} +\end{tiny} + +\setstretch{.5}\begin{tiny} +PHY TX0 +\end{tiny} + +184 360 m +184 336 l +552 336 l +552 360 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +184 408 m +184 368 l +552 368 l +552 408 l +h + +\setstretch{.5}\begin{tiny} +{\tt NGFI\_IF1p / ethernet} +\end{tiny} + + +184 264 m +184 224 l +552 224 l +552 264 l +h + +\setstretch{.5}\begin{tiny} +TX PRECODING\\RX COMBINING +\end{tiny} + +\small\begin{itemize} +\item Example: massive-MIMO RAU with {\tt NGFI\_IF1p} fronthaul northbound, 8 L1 component carriers,1 L2 instances, many local RRUs with {\tt NGFI\_IF4p5} southbound + +\end{itemize} + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +{\tt if\_device} +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX1 +\end{tiny} + +\setstretch{.5}\begin{tiny} +PHY TX1 +\end{tiny} + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX7 +\end{tiny} + +\setstretch{.5}\begin{tiny} +PHY TX7 +\end{tiny} + +184 320 m +184 288 l +552 288 l +552 320 l +h + +\setstretch{.5}\begin{tiny} +RLC +\end{tiny} + + +184 280 m +184 248 l +552 248 l +552 280 l +h + +\setstretch{.5}\begin{tiny} +MAC +\end{tiny} + + +376 208 m +448 208 l + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{eNB}_0$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{eNB}_1$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{eNB}_7$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_{0\cdots 15}$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_{16\cdots 31}$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_{32\cdots 47}$ +\end{tiny} + + +184.83 261.941 m +184.83 128 l +272 128 l +272 261.941 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_{48\cdots 63}$ +\end{tiny} + +RAU Example (Massive-MIMO) + + + + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +232 384 m +232 256 l +543.99 256 l +543.99 384 l +h + + +96 136 m +96 48 l +540 48 l +540 136 l +h + + +88 192 m +88 80 l +248 80 l +248 192 l +h + + +88 192 m +88 80 l +248 80 l +248 192 l +h + + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\small\begin{itemize} +\item IF5 transports packets of size equal to a subframe and corresponding to a 1ms chunk of signal in the time-domain. This is done via the functions send\_if5 and recv\_if5, in the layer1 transport procedures ({\tt openair1/PHY/LTE\_TRANSPORT/if5\_tools.c}). A timestamp is given along with the samples, corresponding to the time (in samples) of the first sample of the packet. +\item each block can be compressed with A-law compression, yielding a compression rate of .5. +\end{itemize} +RU Procedures (NGFI\_IF5) + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_2$ (211,212) +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_2$ (211,212) +\end{tiny} + + +144 480 m +144 32 l +176 32 l +176 480 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_0$ +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_1$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_0$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_1$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_0$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +132 294 m +132 208 l +384 208 l +384 294 l +h + + +144.991 145.396 m +289.432 145.382 l + + +144.991 120.982 m +289.432 121.382 l + +\tiny {\tt RU->ru\_time.rxdata[0]} +\tiny {\tt RU->ru\_time.rxdata[R-1]} + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\tt\tiny slot\_fep\_ul\par36.211 + +153 232 m +153 176 l +228 176 l +228 232 l +h + + +184 268 m +196 268 l + + +184 244 m +196 244 l + +\tiny {\tt eNB->common\_vars.rxdataF[0]} +\tiny {\tt eNB->common\_vars.rxdataF[R-1]} + +273 269 m +412 268 l + + +415.263 120.984 m +575 120.608 l + + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\tiny $\mathrm{Alaw}^{-1}()$ + +56 128 m +110.531 128.542 l + +\tiny from IF5 {\tt if\_device} + +680 104 m +680 104 l +680 104 l +680 104 l +h + + +544 324 m +544 144 l +576 144 l +576 324 l +h + +\setstretch{.5}\tt\tiny P\\R\\E\\C\\O\\D\\I\\N\\G\\ + +632 360 m +632 188 l +660 188 l +660 360 l +h + +\tiny {\tt RU->ru\_time.txdata[0]} + +700 264 m +735.133 264 l + + +632 264.556 m +671.833 265 l + +\setstretch{.5}\tt\tiny do\_ofdm\_mod\_rt()\par 36.211 +\setstretch{.5}\begin{tiny} +{\tt openair1/SCHED/ru-procedures.c} +\end{tiny} + + +517.232 240.387 m +576.078 240 l +576.078 240 l + + +517.232 240.387 m +576.078 240 l +576.078 240 l + + +517.232 240.387 m +576.078 240 l +576.078 240 l + + +517.232 240.387 m +576.078 240 l +576.078 240 l + +\tiny $\mathrm{Alaw}()$ +\tiny to IF5 {\tt if\_device} + +56 240 m +356.214 240.281 l + + +700 264 m +735.133 264 l + +\tiny {\tt RU->ru\_time.txdata[T-1]} +\setstretch{.5}\begin{tiny} +{\tt recv\_IF5()} +\end{tiny} + +\setstretch{.5}\begin{tiny} +{\tt send\_IF5()} +\end{tiny} + +\setstretch{.5}\begin{tiny} +{\tt ru\_fep\_full()} +\end{tiny} + +IF5 RU eNB end +\tiny $\mathrm{7.5kHz}()$ +\setstretch{.5}\begin{tiny} +{\tt ru\_thread()} +\end{tiny} + +\setstretch{.5}\begin{tiny} +{\tt ru\_thread\_asynch\_rxtx()} +\end{tiny} + + + + + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +96 136 m +96 48 l +540 48 l +540 136 l +h + + +88 192 m +88 80 l +248 80 l +248 192 l +h + + +88 192 m +88 80 l +248 80 l +248 192 l +h + + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\small\begin{itemize} +\item IF4p5 transports packets of size equal to an OFDM symbol (for DLRE and ULRE) indexed by the symbol, subframe and frame number. This is done via the functions send\_if4p5 and recv\_if4p5, in the layer1 transport procedures ({\tt openair1/PHY/LTE\_TRANSPORT/if4\_tools.c}). +\item each block are compressed with A-law compression, yielding a compression rate of .5. +\end{itemize} +RU Procedures (NGFI\_IF4p5) + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_2$ (211,212) +\end{tiny} + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_2$ (211,212) +\end{tiny} + + +144 480 m +144 32 l +176 32 l +176 480 l +h + +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_0$ +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_1$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY RX $n$\\ +$\mathrm{eNB}_0$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_1$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\setstretch{.5}\begin{tiny} +PHY TX $n+4$\\ +$\mathrm{eNB}_0$ (211,212) +\end{tiny} + + +371.001 106.337 m +323.502 106.337 l +323.502 106.337 l + + +175.991 137.396 m +575 138.93 l + + +175.991 112.982 m +575 114.329 l + + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\tiny $\mathrm{Alaw}^{-1}()$ + +56 120 m +141.531 120.07 l + +\tiny from IF4p5 {\tt if\_device} + +680 104 m +680 104 l +680 104 l +680 104 l +h + + +544 324 m +544 144 l +576 144 l +576 324 l +h + +\setstretch{.5}\tt\tiny P\\R\\E\\C\\O\\D\\I\\N\\G\\ + +700 264 m +735.133 264 l + +\setstretch{.5}\begin{tiny} +{\tt openair1/SCHED/ru-procedures.c} +\end{tiny} + + +517.232 240.387 m +576.078 240 l +576.078 240 l + + +517.232 240.387 m +576.078 240 l +576.078 240 l + + +517.232 240.387 m +576.078 240 l +576.078 240 l + + +517.232 240.387 m +576.078 240 l +576.078 240 l + +\tiny $\mathrm{Alaw}()$ +\tiny to IF4p5 {\tt if\_device} + +56 240 m +356.214 240.281 l + + +700 264 m +735.133 264 l + +\setstretch{.5}\begin{tiny} +{\tt recv\_IF4p5()} +\end{tiny} + +\setstretch{.5}\begin{tiny} +{\tt send\_IF4p5()} +\end{tiny} + +IF4p5 RU eNB end + +153 232 m +153 176 l +228 176 l +228 232 l +h + + +111.191 120.045 m +112 70 l +142 69.9344 l + + +-36 68 m +-36 68 l + + +175.991 112.982 m +575 114.329 l + +\tiny {\tt eNB->common\_vars.rxdataF[0]} +\tiny {\tt eNB->common\_vars.rxdataF[R-1]} +\tiny {\tt eNB->prach\_vars.prachF[0$\cdots$ R-1]} +\setstretch{.5}\begin{tiny} +{\tt ru\_thread()} +\end{tiny} + + + + + + +330 430 m +330 390 l +380 390 l +380 430 l +h + + +232 384 m +232 256 l +543.99 256 l +543.99 384 l +h + + +96 136 m +96 48 l +540 48 l +540 136 l +h + + +132 294 m +132 208 l +384 208 l +384 294 l +h + + +96 384 m +96 148 l +544 148 l +544 256 l +224 256 l +224 384 l +h + + +444 164 m +444 84.382 l +522.222 84.382 l +522.222 164 l +h + + +132 294 m +132 208 l +384 208 l +384 294 l +h + + +444 164 m +444 84.382 l +522.222 84.382 l +522.222 164 l +h + + +153 232 m +153 176 l +228 176 l +228 232 l +h + +RU Procedures (NGFI\_IF4p5) +\setstretch{.5}\begin{tiny} +$\mathrm{RU}_0$ +\end{tiny} + + +144.991 145.396 m +289.432 145.382 l + + +144.991 120.982 m +289.432 121.382 l + +\tiny {\tt RU->ru\_time.rxdata[0]} +\tiny {\tt RU->ru\_time.rxdata[R-1]} + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\tt\tiny slot\_fep\_ul\par36.211 + +153 232 m +153 176 l +228 176 l +228 232 l +h + + +184 268 m +196 268 l + + +184 244 m +196 244 l + + +273 269 m +412 268 l + + +415.263 120.984 m +575 120.608 l + + +56 128 m +110.531 128.542 l + +\tiny from {\tt rf\_device} + +680 104 m +680 104 l +680 104 l +680 104 l +h + + +632 360 m +632 188 l +660 188 l +660 360 l +h + +\tiny {\tt RU->ru\_time.txdata[0]} + +380.13 336.98 m +149.46 336.349 l + + +632 264.556 m +671.833 265 l + +\setstretch{.5}\tt\tiny do\_ofdm\_mod\_rt()\par 36.211 +\setstretch{.5}\begin{tiny} +{\tt openair1/SCHED/ru-procedures.c} +\end{tiny} + +\tiny to {\tt rf\_device} + +58 240 m +114.121 240.053 l + + +380.45 296 m +149.46 295.058 l + +\tiny {\tt RU->ru\_time.txdata[T-1]} +\setstretch{.5}\begin{tiny} +{\tt ru\_fep\_full()} +\end{tiny} + +IF4p5 RU remote-end + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\tiny $\mathrm{Alaw}^{-1}()$ + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\tiny $\mathrm{Alaw}()$ +\tiny $\mathrm{7.5kHz}()$ + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\begin{tiny} +{\tt recv\_IF4p5()} +\end{tiny} + +\setstretch{.5}\begin{tiny} +{\tt send\_IF4p5()} +\end{tiny} + + +485.71 128.939 m +581.963 129.331 l + +\tiny to {\tt if\_device} +\tiny from {\tt if\_device} + +58 240 m +114.121 240.053 l + + +131 344 m +131 316 l +276 316 l +276 344 l +h + +\setstretch{.5}\tt\tiny ru\_prach\_procedures\par36.211 + +440.514 328 m +477 327.572 l + +\tt\tiny ru\_prach\_procedures() + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\tt\tiny rx\_prachl\par36.211 + +199.412 220.391 m +200 104 l +236.674 103.978 l + + +178.262 196.069 m +179.06 92 l +236.674 91.6468 l + + +65.0054 121.159 m +65.0054 121.159 l +65.0054 121.159 l +65.0054 121.159 l +h + +\setstretch{.5}\begin{tiny} +{\tt ru\_thread\_prach()} +\end{tiny} + +\setstretch{.5}\begin{tiny} +{\tt ru\_thread()} +\end{tiny} + + +65.0054 357.66 m +65.0054 357.66 l +65.0054 357.66 l +65.0054 357.66 l +h + +\setstretch{.5}\begin{tiny} +{\tt ru\_thread\_asynch\_rxtx()} +\end{tiny} + +\tiny to {\tt if\_device} + +485.71 128.939 m +581.963 129.331 l + + + + + + +175.695 380 m +176.42 128 l + +OAI IF1pp Interface +\tiny\begin{itemize} +\item OAI IF1pp is the interface between the 36.213 Physical Layer Procedures (HARQ, SR, CSI, etc.) and the transport/physical channel processing +\item it can be networked, although this is not used as an xhaul interface at the moment. +\end{itemize} + +96 384 m +96 320 l +640 320 l +640 384 l +h + + +128 368 m +128 336 l +352 336 l +352 368 l +h + + +128 368 m +128 336 l +352 336 l +352 368 l +h + +\tiny {\tt phy\_procedures\_lte\_eNB\_TX} +\tiny {\tt phy\_procedures\_lte\_eNB\_RX} + +96 384 m +96 320 l +640 320 l +640 384 l +h + +\small PHY transport and physical channel procedures +\tiny {\tt common\_signal\_procedures()} +\tiny {\tt pmch\_procedures()} +\tiny {\tt generate\_dlsch\_parameters\_from\_dci()} +\tiny {\tt generate\_ulsch\_parameters\_from\_dci()} +\tiny {\tt phy\_config\_dedicated\_step2()} +\tiny {\tt generate\_dci\_top()} +\tiny {\tt generate\_phich\_top()} +\tiny {\tt pdsch\_procedures()} + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + +\tiny {\tt pucch\_procedures()} +\tiny {\tt process\_Msg3()} + +175.695 380 m +176.42 128 l + +\tiny {\tt rx\_ulsch()} + +175.695 380 m +176.42 128 l + +\tiny {\tt ulsch\_decoding()} + +175.695 380 m +176.42 128 l + +\tiny {\tt extract\_cqi()} + +175.695 380 m +176.42 128 l + +\tiny {\tt get\_Msg3\_alloc\_ret()} + +175.695 380 m +176.42 128 l + +\tiny {\tt lte\_est\_timing\_advance\_pusch()} + +175.695 380 m +176.42 128 l + +\tiny {\tt lte\_eNB\_I0\_measurements()} + +175.695 380 m +176.42 128 l + +\tiny {\tt process\_HARQ\_info()} + +175.695 380 m +176.42 128 l + +\small {\tt 36.213}\par +{\tt openair1/SCHED} +\small {\tt 36.211/212}\par +{\tt openair1/PHY} + + + + + +120 528 m +120 0 l +592 0 l +592 528 l +h + + +180 524 m +180 476 l +588 476 l +588 524 l +h + + +248 520 m +248 483.903 l +400 484 l +400 520 l +h + + +180 493.216 m +180 452 l +536 452 l +536 493.216 l +h + + +404 480 m +404 472 l +404 472 l +404 480 l +h + + +340 488 m +340 464 l +444 464 l +444 488 l +h + + +312 456 m +312 432 l +424 432 l +424.001 456 l +h + + +144 448 m +144 360 l +536 360 l +536 448 l +h + + +144 260 m +144 116 l +536 116 l +536 260 l +h + + +144 344 m +144 264 l +536 264 l +536 344 l +h + + +128 440 m +128 384 l +224 384 l +224 440 l +h + +\tt\tiny generate\_dci\_top() + + +0 424 m +0 32 l +48 32 l +48 424 l +h + +M\\ +A\\ +C + +64 416 m +172 416 l + +\tt\tiny DCI\_PDU + +128 440 m +128 384 l +224 384 l +224 440 l +h + +\setstretch{.5}\tt\tiny dlsch\_coding()\par36.212 + +64 416 m +172 416 l + +\tt\tiny DLSCH\_PDU\_0 + +128 440 m +128 384 l +224 384 l +224 440 l +h + + +64 416 m +172 416 l + +\tt\tiny DLSCH\_PDU\_1\_0 + +128 440 m +128 384 l +224 384 l +224 440 l +h + + +64 416 m +172 416 l + +\tt\tiny DLSCH\_PDU\_1\_1 + +312 456 m +312 432 l +424 432 l +424.001 456 l +h + +\setstretch{.5}\tt\tiny generate\_pcfich()\par36.212,36.211 + +304 408 m +304 384 l +400 384 l +400 408 l +h + +\setstretch{.5}\tt\tiny generate\_dci0()\par36.212 + +408 400 m +408 352 l +520 352 l +520 400 l +h + +\setstretch{.5}\tt\tiny pdcch\_scrambling()\par pdcch\_modulation\par pdcch\_interleaving\par36.211 +\setstretch{.5}\tt\tiny dlsch\_coding()\par36.212 +\setstretch{.5}\tt\tiny dlsch\_coding()\par36.212 + +268 426.729 m +293 426.729 l + + +268 399.17 m +293 399.17 l + + +405 397.373 m +421 397.373 l + + +294 320 m +294 296 l +392 296 l +392 320 l +h + +\setstretch{.5}\tt\tiny dlsch\_encoding()\par36.212 + +268 399.17 m +293 399.17 l + + +408 322.774 m +408 288 l +520 288 l +520 322.774 l +h + +\setstretch{.5}\tt\tiny dlsch\_scrambling()\par dlsch\_modulation()\par36.211 + +405 397.373 m +421 397.373 l + + +294 320 m +294 296 l +392 296 l +392 320 l +h + +\setstretch{.5}\tt\tiny dlsch\_encoding()\par36.212 + +408 251 m +408 144 l +520 144 l +520 251 l +h + +\setstretch{.5}\tt\tiny dlsch\_scrambling()\par dlsch\_modulation()\par[2-4 layers]\par 36.211 + +405 397.373 m +421 397.373 l + + +294 320 m +294 296 l +392 296 l +392 320 l +h + +\setstretch{.5}\tt\tiny dlsch\_encoding()\par36.212 + +405 397.373 m +421 397.373 l + + +268 399.17 m +293 399.17 l + + +268 399.17 m +293 399.17 l + + +552 428 m +552 428 l + + +405 409 m +600 408.924 l + + +520 381 m +600 380.885 l + + +521 292.923 m +600 293.648 l + +\tt\tiny openair1/SCHED/phy\_procedures\_lte\_eNb.c:pdsch\_procedures() +\tt\tiny openair1/SCHED/phy\_procedures\_lte\_eNb.c:pdsch\_procedures() +\tt\tiny openair1/PHY/LTE\_TRANSPORT/dci.c + +360 104 m +360 104 l +360 104 l +360 104 l +h + + +144 344 m +144 264 l +536 264 l +536 344 l +h + + +128 440 m +128 384 l +224 384 l +224 440 l +h + +\setstretch{.5}\tt\tiny dlsch\_coding()\par36.212 +\tt\tiny MCH\_PDU + +294 320 m +294 296 l +392 296 l +392 320 l +h + +\setstretch{.5}\tt\tiny dlsch\_encoding()\par36.212 + +268 399.17 m +293 399.17 l + + +408 322.774 m +408 288 l +520 288 l +520 322.774 l +h + +\setstretch{.5}\tt\tiny dlsch\_scrambling()\par mch\_modulation()\par36.211 + +405 397.373 m +421 397.373 l + +\tt\tiny openair1/SCHED/phy\_procedures\_lte\_eNb.c:pmch\_procedures() + +64 416 m +172 416 l + + +128 488 m +128 452 l +172 452 l +172 488 l +h + + +140 472 m +140 472 l +140 472 l +140 472 l +h + +\setstretch{.5}\tt\tiny UL CNTL\\36.213 + +188 476 m +188 460 l +316 460 l +316 476 l +h + +\tt\tiny generate\_phich\_top() + +172 468 m +188 468 l + +\setstretch{.5}\tt\tiny generate\_phich()\par36.212,36.211 + +405 397.373 m +421 397.373 l + + +445 457 m +600 456.672 l + + +520.262 58 m +600 58.7558 l + +\tt\tiny openair1/PHY/LTE\_TRANSPORT/phich.c +\tiny PHICH REs +\tiny PCFICH REs +\tiny PDCCH REs +\tiny PDSCH REs + +104.077 0 0 104.077 528 236 e + +\tiny PMCH REs +\setstretch{.5}\tt\tiny generate\_pilots\_slot()\par generate\_pss/sss/pbch()\par36.211 + +248 488.695 m +248 488.695 l +248 488.695 l +248 488.695 l +h + +\tt\tiny openair1/SCHED/phy\_procedures\_lte\_eNb.c:common\_signal\_procedures() + +401 507 m +600.424 507.963 l + +\tiny CS-RS/PSS/SSS/PBCH REs + +576 332 m +592 324 l + +\tt\tiny openair1/SCHED/phy\_procedures\_lte\_eNb.c:phy\_procedures\_eNB\_TX() +eNB TX Procedures +\tiny eNodeB\_3GPP or NGFI\_RCC\_IF4p5 + +232 276 m +232 240 l +240 240 l +240 276 l +h + +\tt\tiny IF2 split points + +232 276 m +232 240 l +240 240 l +240 276 l +h + + +521 292.923 m +600 293.648 l + + +521 292.923 m +600 293.648 l + + + + + + +539.766 93 m +539.306 79.0026 l +340 79.7439 l + + +447.064 116 m +447.064 92 l +632 92 l +632 116 l +h + + +304 384 m +304 320 l +368 320 l +368 384 l +h + + +225.588 267.631 m +225.588 257.004 l +451.999 257.004 l +451.999 267.631 l +h + + +286.577 417.212 m +286.577 407.581 l +412.989 407.581 l +412.989 417.212 l +h + + +-66.4757 363.53 m +-66.4757 358.467 l +-65.4632 358.467 l +-65.4632 363.53 l +h + + +330 430 m +330 390 l +380 390 l +380 430 l +h + +\begin{tiny} +\tt {\bf phy\_procedures\_eNB\_TX}(sched\_subframe,eNB,abstraction\_flag,r\_type,rn) +\end{tiny} + +\begin{tiny} eNB instance and component carriers \end{tiny} +\begin{tiny} subframe where TX was scheduled \end{tiny} + +293.168 472.33 m +189.522 511.272 l + + +372.849 474.127 m +310.542 512.47 l + +\setstretch{.5}\begin{tiny} Flag to indicate 212/213 Split\\(transport channels, no 211 procedures) \end{tiny} + +432.16 473.528 m +526.22 499.29 l + + +27.6629 0 0 27.6629 531.612 404.032 e + + +526.819 478.92 m +598.712 484.312 l + +\begin{tiny} Experimental (for relays)\end{tiny} +\begin{tiny} +\bf\tt Check for dead UEs +\end{tiny} + +304 384 m +304 320 l +368 320 l +368 384 l +h + + +340.45 451.636 m +340.45 417.212 l + +\begin{tiny}\tt eNB$\rightarrow$CC\_id==0?\end{tiny} +\begin{tiny} +\bf\tt Call eNB\_dlsch\_ulsch\_scheduler [MAC] +\end{tiny} + +340.45 451.636 m +340.45 417.212 l + + +340.45 451.636 m +340.45 417.212 l + + +340.45 451.636 m +340.45 417.212 l + + +418.155 336 m +528 336 l +528 248 l +340 247.665 l + +\tiny no + +225.588 267.631 m +225.588 257.004 l +451.999 257.004 l +451.999 267.631 l +h + +\begin{tiny}\tt is PMCH subframe?\end{tiny} +\begin{tiny} +\bf\tt Call pmch\_procedures +\end{tiny} + +340.45 451.636 m +340.45 417.212 l + + +340 97.4877 m +340 52 l + +\tiny no +\setstretch{.5} +\begin{tiny} +\bf\tt Call common\_signal\_procedures\\ +(CS-RS/PSS/SSS/PBCH) +\end{tiny} + +417.889 180.561 m +540 180 l +539.532 116 l + + +352 0 m +352 12 l +384 12 l +384 12 l +384 0 l +368 -12 l +368 -12 l +h + +eNB TX Flowchart + + + + + +225.588 267.631 m +225.588 257.004 l +451.999 257.004 l +451.999 267.631 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call get\_dci\_sdu [MAC]\\ dci=first\_dci +\end{tiny} + +368.672 502.411 m +368 524 l + + +304 384 m +304 320 l +368 320 l +368 384 l +h + +\setstretch{.5}\begin{tiny}\tt dci not empty and DL dci?\end{tiny} + +368.672 502.411 m +368 524 l + + +368.297 357.206 m +368 380 l + + +260 356 m +260 328 l +476 328 l +476 356 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call generate\_dlsch\_params\_from\_dci\\ +dci=next(dci) +\end{tiny} +\tt\tiny no + +260 342 m +240.242 342 l +240 472 l +368 472 l + + +445.666 417.484 m +512.662 417.484 l +512.662 303.725 l +367.862 303.725 l +367.862 288.454 l + + +260 356 m +260 328 l +476 328 l +476 356 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call phy\_config\_dedicated\_step2\\ +dci=first\_dci +\end{tiny} + +272 200 m +344.961 161.229 l +416 200 l +344.961 235.739 l +h + +\setstretch{.5}\begin{tiny}\tt dci not empty and UL dci?\end{tiny} + +368.297 357.206 m +368 380 l + + +260 356 m +260 328 l +476 328 l +476 356 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call generate\_ulsch\_params\_from\_dci\\ +dci=next(dci) +\end{tiny} +\tt\tiny no + +260 123 m +240.242 123 l +240 252 l +368 252 l + + +416 200 m +488 200 l +489 96 l +345 96 l +344.862 77.0895 l + + +272 80 m +272 48 l +416 48 l +416 80 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call generate\_dci\_top\\ +Call generate\_phich\_top +\end{tiny} + +368.297 357.206 m +368 380 l + + +352 0 m +352 12 l +384 12 l +384 12 l +384 0 l +368 -12 l +368 -12 l +h + + +344 24 m +344 48 l + +\tt\tiny yes +\tt\tiny yes +eNB TX Flowchart + + + + + +240 96 m +240 56 l +496 56 l +496 96 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt dlsch\_eNB[UE].subframe\_active=false\par [no PUCCH ACK to be checked in TTI n+k]\par +UE=next(UE) +\end{tiny} + +288 464 m +368 432 l +448 464 l +368 496 l +h + + +288 464 m +368 432 l +448 464 l +368 496 l +h + + +368 528 m +368 512 l + + +288 464 m +368 432 l +448 464 l +368 496 l +h + +\setstretch{.5}\begin{tiny}\tt is dlsch\_SI active?\end{tiny} + +368 528 m +368 504 l + +\setstretch{.5}\begin{tiny}\tt is dlsch\_P active?\end{tiny} + +368 528 m +368 504 l + +\setstretch{.5}\begin{tiny}\tt is dlsch\_RA active?\end{tiny} +\tt\tiny no +\tt\tiny no +\tt\tiny no + +368 528 m +368 504 l + + +456 480 m +456 464 l +648 464 l +648 480 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call pdsch\_procedures(dlsch\_SI) +\end{tiny} + +448 464 m +536 464 l +536 448 l + + +536 432 m +536 424 l +368 424 l + +\tt\tiny yes + +456 480 m +456 464 l +648 464 l +648 480 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call pdsch\_procedures(dlsch\_P) +\end{tiny} + +448 464 m +536 464 l +536 448 l + + +536 432 m +536 424 l +368 424 l + +\tt\tiny yes + +456 480 m +456 464 l +648 464 l +648 480 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call pdsch\_procedures(dlsch\_RA) +\end{tiny} + +448 464 m +536 464 l +536 448 l + + +536 432 m +536 424 l +368 424 l + +\tt\tiny yes + +256 232 m +256 208 l +480 208 l +480 232 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt UE=first\_UE from UE\_list \par [list of UE with t-CRNTI or CRNTI] +\end{tiny} + +288 464 m +368 432 l +448 464 l +368 496 l +h + +\setstretch{.5}\begin{tiny}\tt is dlsch\_UE active?\end{tiny} + +368 528 m +368 504 l + + +368 528 m +368 504 l + + +456 480 m +456 464 l +648 464 l +648 480 l +h + +\setstretch{.5}\begin{tiny} +\bf\tt Call pdsch\_procedures(dlsch\_UE) +\end{tiny} +\tt\tiny yes + +448 464 m +536 464 l +536 448 l + + +536 432 m +536 424 l +368 424 l + +\tt\tiny no + +416 88 m +416 88 l +416 88 l +416 88 l +h + + +320 32 m +368 16 l +416 32 l +368 48 l +h + +\setstretch{.5}\begin{tiny}\tt UE=NULL?\end{tiny} + +368 72 m +368 56 l + + +320 40 m +224 40 l +224 168 l +288 168 l + +\tt\tiny no + +352 0 m +352 12 l +384 12 l +384 12 l +384 0 l +368 -12 l +368 -12 l +h + + +416 40 m +640 40 l +640 24 l + +\tt\tiny yes + +512 48 m +512 32 l +544 32 l +544 48 l +h + + +528 80 m +528 48 l + +\bf\setstretch{.5}\tiny IF4p5 \par [All Frequency-domain Signals are created] +eNB TX Flowchart + + + + + +130 527 m +130 -1 l +608 0 l +608 528 l +h + + +388 288 m +388 208 l +584 208 l +584 288 l +h + + +141 449 m +141 361 l +580.427 361 l +580 448 l +h + + +464 428 m +464 396 l +576 396 l +576 428 l +h + + +462.358 361 m +462.358 287.368 l +602 287.368 l +602 361 l +h + + +462.358 361 m +462.358 287.368 l +602 287.368 l +602 361 l +h + + +492 200 m +492 16 l +596 16 l +596 200 l +h + + +130 202.157 m +130 16 l +484 16 l +484 204 l +h + +\tt\tiny openair1/SCHED/phy\_procedures\_lte\_eNb.c:phy\_procedures\_eNB\_RX() + +0 424 m +0 32 l +48 32 l +48 424 l +h + +M\\ +A\\ +C + +64 416 m +172 416 l + +\setstretch{.5}\tt\tiny RACH Preamble + +534 125.858 m +688 126 l + +\tt\tiny ULSCH\_SDU(UE\_id) +\tiny eNB\_common\_vars.rxdataF[0] +\tiny eNB\_common\_vars.rxdataF[R-1] + +273 269 m +412 268 l + + +273 245 m +412 244 l + + +184 128 m +184 100 l +276 100 l +276 128 l +h + +\setstretch{.5}\tt\tiny rx\_ulsch(UE\_id)\par36.211 + +208 240 m +208 128 l + +\tt\tiny LTE\_TRANSPORT/prach.c +\tt\tiny openair1/PHY/LTE\_TRANSPORT/ulsch\_demodulation.c + +393 285 m +393 229 l +552 228 l +552 284 l +h + +\tt\tiny lte\_eNB\_I0\_measurements() + + + +280 32 m +280 199 l +308 199 l +308 32 l +h + +\setstretch{.5}\tt\tiny ulsch\_extract\_rbs\_single()\par36.211 + + + + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny lte\_ul\_channel\_estimation()\par36.211 + + + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny ulsch\_detection\_mrc()\par36.211 + + + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny frequency\_equalization()\par36.211 + + + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny lte\_idft()\par36.211 + + + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny ulsch\_XXX\_llr()\par36.211 + + + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny ulsch\_decoding()\par36.212 + + + +332 32 m +332 199 l +360 199 l +360 32 l +h + + +\setstretch{.5}\tt\tiny ulsch\_channel\_compensation()\par36.211 + + + +476 118 m +504.475 118 l + + +564 220 m +564 220 l +564 220 l +564 220 l +h + +\tt\tiny ulsch\_decoding.c + +476 118 m +504.475 118 l + +\tt\tiny ACK/NAK,RI,CQI + +131 344 m +131 316 l +276 316 l +276 344 l +h + +\setstretch{.5}\tt\tiny pucch\_procedures(UE\_id)\par36.211 + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\tt\tiny rx\_pucchl\par36.211 + +476 118 m +504.475 118 l + + +551.76 312.126 m +687 312.231 l + +\tt\tiny ACK/NAK +\tt\tiny SR + +440.514 328 m +477 327.572 l + +\tt\tiny TRANSPORT/pucch.c + +373.112 244.28 m +373.112 316 l + + +344.968 268.786 m +345.381 316 l + + +131 344 m +131 316 l +276 316 l +276 344 l +h + +\setstretch{.5}\tt\tiny prach\_procedures\par36.211 + +405.275 413 m +464 412.625 l + + +440.514 328 m +477 327.572 l + +\tt\tiny openair1/SCHED/phy\_procedures\_lte\_eNb.c:prach\_procedures() + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\tt\tiny rx\_prachl\par36.211 +\setstretch{.5}\tt\tiny E\_PRACH>Lmin\par36.211 +\tt\tiny LTE\_ESTIMATION/lte\_eNB\_I0\_measurements.c +eNB PHY RX Procedures + +0 416 m +144 416 l + +\tiny {\tt eNB->prach\_vars.prachF[0$\cdots$ R-1]} + +160 268 m +160 128 l + + + + + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +0 296 m +0 264 l +736 264 l +736 296 l +h + + +184 128 m +184 100 l +276 100 l +276 128 l +h + +\setstretch{.5}\tt\tiny rx\_ulsch(UE\_id)\par36.211 +\tiny$\mathbf{R}_{r,l}=\mathrm{DFT}_{N_{\mathrm{fft}}}(\mathbf{r}_{r,l}\odot\mathbf{F}_{7.5}),r=0,1,\cdots,R-1,l=0,1,\cdots,N_{\mathrm{symb}}-1$ (\tt\bf eNB\_common\_vars$\rightarrow$rxdataF[][])%,N_{\mathrm{fft}}=2^{1+\left\lceil\log_2 12N^{\mathrm{RB}}_{\mathrm{DL}}\right\rceil$ + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\tt\tiny slot\_fep\_ul\par36.211 + +144 440 m +176 440 l + + +272 328 m +272 328 l + + +144 440 m +176 440 l + +\tiny $\mathbf{r}_{r,l}$ +\tiny $\mathbf{R}_{r,l}$ +\tiny $\mathbf{R}_{\mathrm{ext},r,l}$ +\tiny $R_{\mathrm{ext},r,l}(n)={R}_{r,l}(12\mathrm{firstPRB}+n),n=0,1,\cdots,12N_{\mathrm{PRB}}-1$ (\tt\bf eNB\_pusch\_vars$\rightarrow$ulsch\_rxdataF\_ext[][]) +\tiny $\mathbf{\hat{H}}_{r,l}$ +\tiny $\mathbf{\hat{H}}_{r,l} = \mathbf{R}_{\mathrm{ext},r,l}\odot\mathbf{DRS}^*_{l}(\mathrm{cyclicShift},n_{\mathrm{DMRS}^{(2)}},n_{\mathrm{PRS}})$, (\tt\bf eNB\_pusch\_vars$\rightarrow$drs\_ch\_estimates[]) +\tiny $\mathbf{R}_{\mathrm{comp},r,l}$ +\tiny $\mathbf{R}_{\mathrm{comp},0,l}$ +\tiny $\mathbf{R}_{\mathrm{comp},0,l}=\frac{1}{R}\sum_{r=0}^{R-1}\mathbf{R}_{\mathrm{comp},r,l}$ +\tiny $\mathbf{R}_{\mathrm{comp},0,l}$ +\tiny $\mathbf{r}_{\mathrm{comp},0,l}$ +\tiny $R_{\mathrm{comp},0,l}(n)=R_{\mathrm{comp},0,l}(n)\dot Q_8\left(\frac{1}{|\hat{H}(n)|^2+I_0}\right), \hat{H}(n)=\sum_{r=0}^{R-1}\hat{H}_{r}(n)$ +\tiny $\mathbf{R}_{\mathrm{comp},r,l}=\mathbf{\hat{H}}_r\odot\mathbf{R}_{\mathrm{ext},r,l}2^{-\log_2|H_\mathrm{max}|}, \mathbf{\hat{H}}_r = \frac{1}{2}(\mathbf{\hat{H}}_{r,3}+\mathbf{\hat{H}}_{r,10})$\par (\tt\bf eNB\_pusch\_vars$\rightarrow$ulsch\_rxdataF\_comp) +\tiny $\mathbf{\lambda}_{l}$ +\tiny QPSK : $\lambda_l(2n)=\mathrm{Re}(r_{\mathrm{comp},0,l}(n)), \lambda_l(2n+1)=\mathrm{Im}(r_{\mathrm{comp},0,l}(n))$ (\tt\bf eNB\_pusch\_vars$\rightarrow$ulsch\_llr) +\tiny ${\mathbf r}_{\mathrm{comp},0,l} = \mathrm{IDFT}_{12N_{\mathrm{PRB}}}({\mathbf R}_{\mathrm{comp},0,l})$ +\tiny 16QAM : $\lambda_l(4n)=\mathrm{Re}(r_{\mathrm{comp},0,l}(n)), \lambda_l(4n+2)=\mathrm{Im}(r_{\mathrm{comp},0,l}(n))$\par$\lambda_l(4n+1)=|\mathrm{Re}(r_{\mathrm{comp},0,l}(n))|-2\overline{|h(n)|},\lambda_l(4n+3)=|\mathrm{Im}(r_{\mathrm{comp},0,l}(n))|-2\overline{|h(n)|}$ + +280 32 m +280 199 l +308 199 l +308 32 l +h + +\setstretch{.5}\tt\tiny ulsch\_extract\_rbs\_single()\par36.211 + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny lte\_ul\_channel\_estimation()\par36.211 + +332 32 m +332 199 l +360 199 l +360 32 l +h + + +\setstretch{.5}\tt\tiny ulsch\_channel\_compensation()\par36.211 + + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny ulsch\_detection\_mrc()\par36.211 + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny frequency\_equalization()\par36.211 + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny lte\_idft()\par36.211 + +332 32 m +332 199 l +360 199 l +360 32 l +h + +\setstretch{.5}\tt\tiny ulsch\_XXX\_llr()\par36.211 + +304 236 m +304 236 l +304 236 l +304 236 l +h + +eNB ULSCH Demodulation + + + + +eNB PRACH Detection + +0 296 m +0 264 l +736 264 l +736 296 l +h + +\tiny$\mathbf{R}_{r}=\mathrm{DFT}_{N_{\mathrm{PRACH}}}(\mathbf{r}_{r}),r=0,1,\cdots,R-1$ (\tt\bf lte\_eNB\_prach\_vars$\rightarrow$rxsigF[])%,N_{\mathrm{fft}}=2^{1+\left\lceil\log_2 12N^{\mathrm{RB}}_{\mathrm{DL}}\right\rceil$ + +0 296 m +0 264 l +736 264 l +736 296 l +h + +\tiny$\mathbf{R}_{\mathrm{comp},r}=\mathbf{R}_{r}\odot \mathbf{X}^*_u[i],r=0,1,\cdots,R-1$ (\tt\bf lte\_eNB\_prach\_vars$\rightarrow$prachF[])%,N_{\mathrm{fft}}=2^{1+\left\lceil\log_2 12N^{\mathrm{RB}}_{\mathrm{DL}}\right\rceil$ + +0 296 m +0 264 l +736 264 l +736 296 l +h + +\tiny$\mathbf{r}_{839,r}=\mathrm{IDFT}_{1024}\left(\mathbf{R}_{\mathrm{comp},r}\right), r=0,1,\cdots,R-1$ (\tt\bf lte\_eNB\_prach\_vars$\rightarrow$prach\_ifft[]) + +112 460 m +112 400 l +176 400 l +176 460 l +h + +\tiny $\mathbf{r}_{r}$ + +144 440 m +176 440 l + +DFT +\tiny $\mathbf{R}_{r}$ + +268 480 m +268 452 l +300 452 l +300 480 l +h + +$\odot$ + +176 428 m +208 428 l +208 456 l +268 456 l + + +208 428 m +208 400 l +268 400 l + +\tiny $\mathbf{X}^*_{u}(0)$ +\tiny $\mathbf{X}^*_{u}(1)$ + +284 480 m +284 468 l + + +284 372 m +284 384 l + + +268 480 m +268 452 l +300 452 l +300 480 l +h + +\tiny$R\times\mathrm{IDFT}_{1024}$ + +300 456 m +336 456 l + + +300 456 m +336 456 l + + +268 480 m +268 452 l +300 452 l +300 480 l +h + +\tiny$R\times\mathrm{IDFT}_{1024}$ + + +268 480 m +268 452 l +300 452 l +300 480 l +h + + + +\tiny$\sum_{r}|\cdot|^2$ + + + + + +268 480 m +268 452 l +300 452 l +300 480 l +h + + + +\tiny$\sum_{r}|\cdot|^2$ + + + + + +268 480 m +268 452 l +300 452 l +300 480 l +h + +\tiny max peak in size $\mathrm{NCS}_2$ window, keep delay + + +412 456 m +440 456 l + + +412 400 m +440 400 l + + +500 460 m +532 460 l + + +500 460 m +532 460 l + + +500 460 m +532 460 l + + +624 456 m +672 456 l + + +624 456 m +672 456 l + + +268 480 m +268 452 l +300 452 l +300 480 l +h + +\tiny max peak in size $\mathrm{NCS}_2$ window, keep delay +\tiny\tt preamble\_energy\_list[]\par preamble\_delay\_list[] +\tiny $\mathbf{r}_{839,r}$ +\small\begin{itemize} +\item PRACH detection is a quasi-optimal non-coherent receiver for vector observations (multiple antennas) +\item correlation is done in the frequency-domain, number of correlations (in the example above 2) depends on {\em zeroCorrelationConfig} configuration parameter +\item peak-detection (for delay estimation) is performed in each NCS time-window +\end{itemize} + + +268 480 m +268 452 l +300 452 l +300 480 l +h + +$\odot$ + + + + + + +340 416 m +340 340 l +564 340 l +564 416 l +h + + +268 480 m +268 452 l +300 452 l +300 480 l +h + +\tiny$\sum_{r,l,i}|\cdot|^2$ +\begin{tiny}$\stackbin{<}{>}\sigma^2[\mathrm{dB}]$\end{tiny} +eNB PUCCH1 Detection + +184 128 m +184 100 l +276 100 l +276 128 l +h + +\setstretch{.5}\tt\tiny rx\_pucch()\par36.211 + +153 232 m +153 176 l +228 176 l +228 232 l +h + +\setstretch{.5}\tt\tiny slot\_fep\_ul\par36.211 + +144 440 m +176 440 l + + +144 440 m +176 440 l + +\tiny $\mathbf{r}_{r,l}$ +\tiny $\mathbf{R}_{r,l}$ +\tiny $\mathbf{Z}^*_{l}e^{-j2\pi f/16},-3\leq f\leq 2$ + +308 448 m +352 448 l + +$\odot$ + +308 448 m +352 448 l + + +392 484 m +392 456 l + + +328 448 m +328 400 l +352 400 l + +$\odot$ + +392 484 m +392 456 l + +\tiny $\mathbf{Z}^*_{l}$ + +288 496 m +288 496 l +288 496 l +288 496 l +h + + +308 448 m +352 448 l + + +412 408 m +412 392 l +464 392 l +464 408 l +h + +\tiny$\mathbf{\hat{H}}$ +$\odot$ + +420 392 m +420 376 l + + +384 400 m +384 368 l +412 368 l + + +428 368 m +464 368 l + +\tiny$\mathrm{sgn}(\mathrm{Re}(\cdot))$ + +444 368 m +444 352 l +464 352 l + +\tiny$\mathrm{sgn}(\mathrm{Im}(\cdot))$ + +532 408 m +532 408 l +532 408 l +532 408 l +h + +\tiny PUCCH1 (Scheduling Request) +\tiny PUCCH1a/1b (ACK/NAK) +\small\begin{itemize} +\item PUCCH1 detection is a quasi-optimal non-coherent receiver (energy detector) for vector observations (multiple antennas) for scheduling request. Care is taken to handle residual frequency-offset. +\item PUCCH1A/1B detection is quasi-coherent based on a rough channel estimate obtained on the 3 symbols without data modulation. \item In both cases, correlation is done in the frequency-domain +\end{itemize} + + + + +\small\begin{itemize} +\item Threads (all in {\tt targets/RT/USER/lte-ru.c}) +\begin{itemize} +\item {\tt ru\_thread}: Thread per RU which sequentially +performs +\begin{itemize} +\item read from south interface (RF or IF fronthaul) +\item RX processing for subframe $n$ (if necessary). +\item wakeup eNBs that are waiting for signal (if necessary) +\item wait for eNB task completion (if necessary) +\item do TX processing for subframe $n+4$ (if necessary). Note that this can spawn multiple worker threads for very high order spatial processing (e.g. massive-MIMO or DAS for UDN) +\item do outgoing fronthaul (RF or IF fronthaul) +\end{itemize} +\item {\tt ru\_thread\_prach}: Thread for PRACH processing in remote RU (DFT on RX, IF4p5 RRU) +\item {\tt ru\_thread\_asynch}: Thread for asynchronous reception from fronthaul interface (TX direction in RRU). %Allows for some jitter so as not to block the RRU real-time processing. +\end{itemize} +\item Synchronization on fronthaul interface +\begin{itemize} +\item {\em synch\_to\_ext\_device} : synchronizes to incoming samples from RF or Fronthaul interface using blocking read +\item {\em synch\_to\_other} : synchronizes via POSIX mechanism to other source (other CC, timer) which maintains real-time. +\end{itemize} +\end{itemize} +RU Threads + + + + +\small\begin{itemize} +\item Threads (all in {\tt targets/RT/USER/lte-enb.c}) +\begin{itemize} +\item multi RX/TX thread mode (optional) +\begin{itemize} +\item {\tt eNB\_thread\_rxtx}: 2 threads per CC/Instance which do both RX procedures for subframe $n$ and TX procedures for subframe $n+4$. One operates on even subframes, one on odd. This allows 1ms subframe processing to use multiple-cores. +\end{itemize} +\item common RU-eNB RX/TX thread (default if single RU/eNB) +\begin{itemize} +\item calls {\tt eNB\_top}: procedure per CC/Instance which sequentially +\begin{itemize} +\item blocks on signal from RU +\item RX/TX processing for subframe $n$ and $n+4$ +\item signals completion to RU +\end{itemize} +\end{itemize} +\item {\tt eNB\_prach}: Thread per CC\_id/Instance for PRACH processing +\end{itemize} +\end{itemize} +eNB Threads + + + + + +400 400 m +400 388 l +520 388 l +520 400 l +h + + +400 432 m +400 420 l +520 420 l +520 432 l +h + + +400 448 m +400 436 l +528 436 l +528 448 l +h + + +400 448 m +400 436 l +528 436 l +528 448 l +h + + +192 388 m +192 364 l +272 364 l +272 388 l +h + + +32 480 m +32 464 l +112 464 l +112 480 l +h + +eNB Timing (multi-thread mode) + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny SF $n+1$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny SF $n+2$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny SF $n+3$ +\tiny $n$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny$n+4$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny SF $n+4$ + +32 480 m +212 572 +352 480 c + + +384 464 m +384 464 l + + +380 472 m +380 472 l + +\tiny\begin{itemize} +\item The current processing requires approximately 1ms peak in each direction (basically 1 core RX, 1core TX). The current architecture will work on a single core if the sum of RX and TX procedures is limited to 1ms. It can fit on 2 cores if the sum of RX,TX and PRACH is less than 2ms. +\item three threads, RX-TX even, RX-TX odd and PRACH. RX-TX blocks until woken by the RU thread with a new RX subframe $n$ that is linked to this eNB process. The RX-TX thread performs ue-specific processing for subframe $n$ and then TX common and ue-specific processing for subframe $n+4$ (frequency-domain generation only). This insures the data dependency between TX $n+4$ and RX $n$ is respected. The duration of this thread should be less than 2ms which can compensate some jitter on the RX processing. +\end{itemize} + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny SF $n$ +\tiny LTE HARQ periodicity (FDD, TDD can be longer) +\tiny PRACH $n$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny $n+1$ +\tiny $n$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny$n+5$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny $n+1$ + +124 424 m +172 416 +152 392 c + + +204 424 m +228 424 +236 416 c + + +192 396 m +196 416 l + + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny $n-1$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny$n+3$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny $n-1$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny $n+2$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + +\tiny$n+6$ + +32 480 m +32 464 l +112 464 l +112 480 l +h + + +284 424 m +308 424 +316 436 c + +\tiny $n+2$ + +268 452 m +276 436 l + +\tiny RU thread +\tiny RX-TX thread (even) + +400 448 m +400 436 l +528 436 l +528 448 l +h + + +400 448 m +400 436 l +528 436 l +528 448 l +h + +\tiny RX-TX thread (odd) +\tiny PRACH + +192 396 m +196 416 l + + + + + + +96 384 m +96 320 l +640 320 l +640 384 l +h + + +96 384 m +96 320 l +640 320 l +640 384 l +h + + +96 384 m +96 320 l +640 320 l +640 384 l +h + + +96 384 m +96 320 l +640 320 l +640 384 l +h + + +128 368 m +128 336 l +352 336 l +352 368 l +h + + +128 368 m +128 336 l +352 336 l +352 368 l +h + + +175.695 380 m +176.42 128 l + +OAI IF1'' Interface (can be NFAPI) +\tiny\begin{itemize} +\item OAI IF1'' is the interface between the 36.321 Medium-Access (MAC) Layer Procedures and the 36.213 Physical Layer Procedures. It links several PHY instances to one MAC instance. +\item It is a configurable (dynamically loadable) module which can implement an (N)FAPI P5/P7 or a simpler interface. +\end{itemize} + +128 368 m +128 336 l +352 336 l +352 368 l +h + +\tiny Random-Access +\tiny Events +\small PHY procedures +\tiny {\tt initiate\_ra\_proc()} +\tiny {\tt terminate\_ra\_proc()} +\tiny {\tt cancel\_ra\_proc()} +\tiny {\tt phy\_config\_dedicated()} +\tiny {\tt phy\_config\_sib1()} +\tiny {\tt phy\_config\_sib2()} +\tiny {\tt phy\_config\_sib13()} + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + +\tiny {\tt eNB\_dlsch\_ulsch\_scheduler()} +\tiny {\tt get\_dcii\_sdu()} + +175.695 380 m +176.42 128 l + +\tiny {\tt get\_dlsch\_sdu()} + +175.695 380 m +176.42 128 l + +\tiny {\tt rx\_sdu()} + +175.695 380 m +176.42 128 l + +\tiny {\tt get\_mch\_sdu()} + +175.695 380 m +176.42 128 l + +\tiny {\tt SR\_indication()} + +175.695 380 m +176.42 128 l + + +128 368 m +128 336 l +352 336 l +352 368 l +h + +\tiny PHY Config +\tiny Scheduling +\small {\tt 36.213/36.321}\\ +{\tt openair2/LAYER2/MAC} +\small {\tt 36.211/212}\par +{\tt openair1/PHY} + +96 384 m +96 320 l +640 320 l +640 384 l +h + +\small OAI MAC interface +\tiny {\tt phy\_config\_mib()} + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + + +175.695 380 m +176.42 128 l + +\small UL-Indication +\small Config-Req +\small Schedule-Resp +\tiny Northbound interface +\tiny Southbound interface + + + + +OAI IF1'' Interface +\tiny\begin{itemize} +\item The PHY end uses three basic messages +\begin{itemize} +\item {\tt CONFIG\_REQ}: this provides the cell configuration and UE-specific configuration to the PHY instances. This comprises the following FAPI P5/P7 messages +\begin{enumerate} +\item CONFIG.request +\item UE\_CONFIG.request (**not used in OAI PHY) +\end{enumerate} +\item {\tt UL\_INDICATION} This is an uplink indication that sends all UL information received in one TTI, including PRACH, if available. It also provides the subframe indication for the DL scheduler. It maps to the following FAPI P7 messages +\begin{enumerate} +\item {\tt SUBFRAME.indication} +\item {\tt HARQ.indication} +\item {\tt CRC.indication } +\item {\tt RX\_ULSCH.indication} +\item {\tt RX\_SR.indication} +\item {\tt RX\_CQI.indication} +\item {\tt RACH.indication} +\item {\tt SRS.indication} +\end{enumerate} +\item {\tt SCHEDULE\_REQUEST} This message contains the scheduling response information and comprises the following FAPI P7 messages +\begin{enumerate} +\item {\tt DL\_CONFIG.request} +\item {\tt UL\_CONFIG.request} +\item {\tt TX.request} +\item {\tt HI\_DCI0.request} +\end{enumerate} +\end{itemize} +\item The module is registered both by PHY and MAC and can implement different types of transport (NFAPI, function call, FAPI over UDP, etc.). During registration, fuction pointers for the different messages are provided for the module to interact with either PHY or MAC or both if they are executing in the same machine. Note that for a networked implementation (e.g. NFAPI), there are north and south components running in different machines. +\end{itemize} + + + + +OAI IF1'' Interface +\small\begin{itemize} +\item The PHY-layer timing is assumed to be +\begin{enumerate} +\item wait for subframe indication $n$ from HW +\item trigger PRACH if $n$ has PRACH (parallel thread) +\item trigger UE specific RX procedures for $n$ if $n$ is UL +\item assemble {\tt UL\_INDICATION} and send to MAC +\item wait for {\tt SCHEDULE\_REQUEST} +\item do TX procedures if $n+4$ is TX and RX programming if $n+4+k$ is UL +\end{enumerate} +\item The MAC-layer timing is assumed to be +\begin{enumerate} +\item do all UL processing for subframe $n$ if $n$ is UL after unraveling of UL\_INDICATION in MAC module +\item wait for call to {\tt eNB\_dlsch\_ulsch\_scheduler} +\item do DL scheduling for $n+4$ if it is DL +\item do UL scheduling for $n+8$ if it is UL +\item return from eNB\_dlsch\_ulsch\_scheduler +\item let MAC module form SCHEDULE\_REQUEST +\end{enumerate} +\end{itemize} + + + + + +96 384 m +96 320 l +640 320 l +640 384 l +h + + +128 368 m +128 336 l +352 336 l +352 368 l +h + + +128 368 m +128 336 l +352 336 l +352 368 l +h + +OAI MAC + +128 368 m +128 336 l +352 336 l +352 368 l +h + +\tiny Random-Access +\tiny Events + +128 368 m +128 336 l +352 336 l +352 368 l +h + +\tiny PHY Config +\tiny Scheduling +\small {\tt 36.321}\\ +{\tt openair2/LAYER2/MAC} + +175.695 380 m +176.42 128 l + + +176 496 m +176 384 l +400 384 l +400 496 l +h + + +176 496 m +176 384 l +400 384 l +400 496 l +h + +\small RRC + +384 384 m +272 144 l + + +384 384 m +384 144 l + + +384 384 m +528 144 l + + +608 384 m +528 144 l + +\small RLC + +176 496 m +176 384 l +400 384 l +400 496 l +h + +\small Preprocessor + +160 256 m +528 144 l + + +272 312 m +608 384 l + + +472 504 m +472 232 l +152 232 l +152 40 l +728 40 l +736 40 l +736 504 l +h + +\small {\tt 36.322}\\ +{\tt openair2/LAYER2/RLC} +\small {\tt user customizable scheduling module} + + + + +TX Precoding +\small\begin{itemize} +\item Spatio-temporal filtering for muli-cell (vCell) and multi-user transmission. Input and output are frequency-domain signals. +\item can be applied to Rel-10/11/12/13 physical channels and Rel-8 common channels +\begin{itemize} +\item UE-specific precoding (TM7-10) +\item vCell-specific precoding (PDCCH + TM1-6) for groups of UEs +\item PMCH vCells +\end{itemize} +\item Precoding applicable to +\begin{enumerate} +\item indoor DAS +\item outdoor co-localized arrays (e,g, Massive-MIMO) +\item outdoor CoMP +\end{enumerate} +\end{itemize} + +208 480 m +208 80 l +512 80 l +512 480 l +h + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +400 160 +480 192 +528 160 +400 160 +400 160 u + + +400 96 +448 128 +512 144 +576 96 +496 80 +400 96 +400 96 u + + +480 160 m +480 160 l + + +496 160 m +496 160 l + + +400 96 +448 128 +512 144 +576 96 +496 80 +400 96 +400 96 u + +\small UE +\small vCell +\small vCell +TX Precoding + + + + + +608 516 m +607 37 l +679 37 l +680 516 l +h + + +632 360 m +632 188 l +660 188 l +660 360 l +h + +TX Precoding (to RF device) + +208 480 m +208 80 l +512 80 l +512 480 l +h + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + +\tt eNB[0] +\tt eNB[1] +\tt eNB[CC\_max] + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +528 464 m +528 416 l +592 416 l +592 464 l +h + +\tiny\tt rf\_device[0] + +528 464 m +528 416 l +592 416 l +592 464 l +h + +\tiny\tt rf\_device[1] + +528 464 m +528 416 l +592 416 l +592 464 l +h + +\tiny\tt rf\_device[N-1] + +192 432 m +192 368 l +272 368 l +272 432 l +h + + +192 432 m +192 368 l +272 368 l +272 432 l +h + + +192 432 m +192 368 l +272 368 l +272 432 l +h + +\tiny\tt common signal precoding(vCell)\\ PBCH,PSS/SSS,PCFICH/PHICH/PDCCH\\ +PDSCH - TM1-6 +\tiny\tt UE-specific signal precoding(vCell)\\ +UE-RS,PDSCH - TM7-10 +\tiny\tt PMCH precoding + +145 413.44 m +192 384 l + + +145 413.44 m +192 288 l + + +145 413.44 m +192 192 l + + +145 349.44 m +192 384 l + + +145 349.44 m +191.982 288.048 l + + +145 349.44 m +191.982 192.084 l + + +145 157.44 m +192 384 l +192 384 l + + +145 157.44 m +191.982 288.048 l + + +145 157.44 m +191.982 192.084 l + + +400 384 m +449 447.637 l + + +400.059 384.077 m +449 431.796 l + + +400.059 384.077 m +449 383.637 l + + +400.059 384.077 m +449 367.763 l + + +400.059 384.077 m +449 143.57 l + + +400.059 384.077 m +449 127.637 l + + +400 288 m +449 383.637 l + + +400.001 288.002 m +449 367.763 l + + +400.001 288.002 m +449 143.57 l + + +400.001 288.002 m +449 127.637 l + + +400 192 m +449 447.637 l + + +400.001 288.002 m +449 447.637 l + + +400.001 288.002 m +448.966 431.763 l + + +400.001 192.005 m +449 367.763 l + + +400.001 192.005 m +449 143.57 l + + +400.001 192.005 m +449 127.637 l + +\tiny phy\_vars\_eNB.txdataF +\tiny phy\_vars\_eNB.txdata + +632 264.556 m +671.833 265 l + +\setstretch{.5}\tt\tiny do\_ofdm\_mod\_rt()\par 36.211 + + + + +TX Precoding (to IF device, NGFI\_IFv4p5) + +208 480 m +208 80 l +512 80 l +512 480 l +h + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + +\tt eNB[0] +\tt eNB[1] +\tt eNB[CC\_max] + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +128 448 m +208 448.44 l + + +528 464 m +528 416 l +592 416 l +592 464 l +h + +\tiny\tt if\_device[0] + +528 464 m +528 416 l +592 416 l +592 464 l +h + +\tiny\tt if\_device[1] + +528 464 m +528 416 l +592 416 l +592 464 l +h + +\tiny\tt if\_device[N-1] + +192 432 m +192 368 l +272 368 l +272 432 l +h + + +192 432 m +192 368 l +272 368 l +272 432 l +h + + +192 432 m +192 368 l +272 368 l +272 432 l +h + +\tiny\tt common signal precoding(vCell)\\ PBCH,PSS/SSS,PCFICH/PHICH/PDCCH\\ +PDSCH - TM1-6 +\tiny\tt UE-specific signal precoding(vCell)\\ +UE-RS,PDSCH - TM7-10 +\tiny\tt PMCH precoding + +145 413.44 m +192 384 l + + +145 413.44 m +192 288 l + + +145 413.44 m +192 192 l + + +145 349.44 m +192 384 l + + +145 349.44 m +191.982 288.048 l + + +145 349.44 m +191.982 192.084 l + + +145 157.44 m +192 384 l +192 384 l + + +145 157.44 m +191.982 288.048 l + + +145 157.44 m +191.982 192.084 l + + +400 384 m +449 447.637 l + + +400.059 384.077 m +449 431.796 l + + +400.059 384.077 m +449 383.637 l + + +400.059 384.077 m +449 367.763 l + + +400.059 384.077 m +449 143.57 l + + +400.059 384.077 m +449 127.637 l + + +400 288 m +449 383.637 l + + +400.001 288.002 m +449 367.763 l + + +400.001 288.002 m +449 143.57 l + + +400.001 288.002 m +449 127.637 l + + +400 192 m +449 447.637 l + + +400.001 288.002 m +449 447.637 l + + +400.001 288.002 m +448.966 431.763 l + + +400.001 192.005 m +449 367.763 l + + +400.001 192.005 m +449 143.57 l + + +400.001 192.005 m +449 127.637 l + + +448 544 m +448 544 l + + +432 544 m +432 544 l + + +624 432 m +672 432 l + + +624 432 m +672 432 l + + +624 432 m +672 432 l + +\tiny NGFI\_IFv4p5 +\tiny NGFI\_IFv4p5 +\tiny NGFI\_IFv4p5 + + diff --git a/targets/DOCS/oai_L1_L2_procedures.pdf b/targets/DOCS/oai_L1_L2_procedures.pdf old mode 100755 new mode 100644 index 369efc3b479b960c74e89b7e73e427a15cea8de9..4e8059f503d8a4fedd634dc014c4f572275a5be8 GIT binary patch literal 1511882 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¬ZrkHke`UyE$Y>bjJnv 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

F=NfSEzXj z>h)Ur?szYrx;-7*RWbMp(q(Oj>j#VL6b~7)T>Ws!W&66>mQqk8DSC$nqznGLdcv8A zS?1U;-K5E5487X#=X2)XWktvd6sH<(Lgy?~n2mkxF>>$K9wTd{Af@~7%@RQ2f41wb)pc>-7a36tDHEVIBWp+ zA`S1Y9!c|J6K~9D^TDKWpM{aJ8G~h>Go(3;OC(R6^%?od9M>sV=jb-Y!^*RMM1q6Z zFQ`r2IR_#ct9UTw9iB&)^L?~%Zl$?#SPi5dZ$AWIbcS!+wjFzR&f-lTLXN$aLq&Im z`m&a4Jrx+EUW~+0%p)H-Fr+$6G$PCHZn)mgK6|jIL_ubJQ$>jHJT%6jXFHST|Kgyr z+*ZKComrfO`A+V77fl{~!M~Nw{xTJ>epN)P)@<9$I#B6qsu>19c2WC~Y+-lP0h?aE zf{|ZrHrZXPXR7u~G#^nyBq*w0<6C;ESHwvBTaK9oREM)?`7E!#6hMia0lUz2%Cx

0@l`n|SKN<2B5pe0J&F=(QJDtmVkwrm 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�hrpRq)G9SBtZ(lfs0F$AlJ2RRcAXb4ilHH#wJ7 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 z%0DQma_|)ZY-y$f{5p;8cs)mHO?i%W8;xPW}2&FN#cZ4@^ zdffPtenzq(>6^^on4$de@UlKpei6AVj9<3r*8XpAH}#vHZdm(~xyOzDyz)VxJ8!?e z51zL0d#Tz_(>!=Ia!0!G;FIr`Uwqp;X`659t2YVQb98FJl1C?IHM{DOD8qr=j=9~l zwRH3i3;M+;_lH3Y??B8O| zwVe}|ojBV4PPy_8#>3^I~|9h>!7Ck19C5_{$D8#=YoYI`^~M zM>d@}+Vj`)>tiS7sy*sq`&tpt%vG6PL4PiPP`SvmJm*`Fm~@~|uPpw>+wM+${npW} zYsV$e+a-RY;B#e~InK8^kh}Sqh{SU`WKWjyYNcrn+iW?~Z)bxCZD#DbzSwzxL&(pQ zUvqWavVHT;w|ygyr}6XnRPSuccquo2&s{lB5y!eFMu(NktnNW&(seKJ?DY5={%ba* z9QCwM;+2OohK?!JM!$Wn(51MCmL_gLyXEH+H+Pijx}(LGqi;8!i<9bd-jYu@UhMYC zdriHX*II7=^Z1UGnYXF_Y8We9> zF@BxADf(vKRJzsWj-Q)&q_5L*W_K;ysoaOIJT(t|9C15EpFcCD@gH2-EBnQ^MPEKU z&?Cpr!XKh5UU9wLkak(3twrN@ZPKCE%_HH9R+U~FXY{O{ey1;;xpt{U4XsCyjw{mM z9sbkz`__0@#veD5C$ErYT)V-cjea;TdEXv=|5c3)?~lLi^~dm9i9JsqnU=F+*WQH! zx^#N;Yt9{?{DYhmckMg#YRQNcc}{qS>^PfeP{wv;k0xw2xO4dd$1f%6m}Tsuz{%FA z$HhB3)2^ttAj6sI>u2}dv%c5QPay-1Jzi&DTSIy^pVF^?*t=waoJJ!<2R3 zQ~q&f$JM{(%jvdvK+BIrmOTzMOj}BwxQ`_BYm z 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 +x}@6oHrN*MuHJPW*ypXaw#X7&&?dck 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 G{{H|TvG2J6 literal 1118156 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

m4lna$D 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%0A(N4(W~ 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%0Df-!&lu!T0b{TC?YGvIKoDV;NAFz% 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%0Dm?wEGLTUiF*;j3)9j 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

pNXaJbVmkKJVxnwbgs&>%-fm{V=PYdh zp(I(GUI{^2K)1kYWaTd}37wQmky)mK_gAp2)7StR6aFlnt^!Djoy@>wm-mHO?D`q6 zcNWD%^}w=M#rC1Gw*A)OWV@kfCObWS@bvWHs`5vN&&N$3i}vX<59f zN&(({LDEe9?_j@MD&OB6-i*gN+MJ8;A>K7SXM%#sK2M_8zMa38M%*}ABHQ1Soi>6F zV<-^LHy~kP5IO1t>rzTiZeaIHAsaX{K7M<3bqu+Bou329$ndeTq3gd02uxxD$H|o6 zi7$_|rqUt(5;6n+vPV__E+oiMHOTrzG(_vaweEQ|)qmx;Mz&SFzAT=->?G)FGy6N| zHV6%1Ya695DQPdamO{|{$}f9fsSv0ki2NR2bjj>~a`umFBs(H_;N-{e?dGWqJnzt( z=i8t6k_|*Kb&)0!8hRAPhqOF2nMh}NUs}Djm{hr2byw;hKQZdL8nkEZv{F<#Q~vSu zbq4J)o3uf^0h!uA?RN1^a5K;FbW1{Il(|sZ@5WstN^39WxrRbYOj6c5ymFMi!<%aZ z^!0kGwixm@^Mv%osBGz#5HzaW>$$-nlTrWF?a&|AE2|>Z)wxz1JEmta1ljprF5;&4 zPpW@KY*$vAJ;WMOmie&>B0t`T_S-K$Axy70y_eZRQ{N)au35Eq?t zPX9v&OioV1!oqUdt)*sVot>V-k-|hnSwljRb`B2_(R*~B=APLp=k#q#_f5lZfnE*m zez9sSkeoJ8{vKGM>%qZcC36*UvfXv+1I03=z8N?-tpPT*aM+oIZJ8_Etl2w%RY!t~ znP499=A(XTlgOM3~fFQa8$rV^I3YMs$Z zE<07yoh^02?!s&1d$>?s14N4L;9g^mp!na~^ukeuM{i?WUvR5R#VP0{H7FFPyY};x zd>CH;3uN0l(x;N;)l0AK3vkiRMwt7+{3_jSmUH% zQ?q%=KvkkTgKFqE-nY$4M*i0gy3qFsvjKS_a==m0xAJ3o}vAGFgtS`|Mju<9Ed z12`f74HSNm$hLjHp5tZrKhRbHDyuK+rDBUN$MnaCy}=kcmJ`sazqeuB>D*>LA@ zOu19P04bXN7R|s_JoZ%&)rHR+%}zTKk-O;j_V)GFyGCPedAaQ8?~aa+IOR{v%Mgsp zPt@VEy9d_y*KWX=J|ghT{npLX9s1q=Xnb$oj|GSTAs#x(&8&{6nrOYk>&eBe;1Lr0 z&0XvA)zZHXd0d?wBd?JD3x3sNT9B%}$7`VO__5Bzkd+F#5$&JTV=GA|DCFU-vFl9g zMfgZxCxZ`rl}GIq&}NWKN_LdqC|2ALGY%1$V^BbUsK{{sh{;!~4wZ2N&6;}=p*3N1 z-;^)21I=sHDboMsgD-$7Tco3IC{$#;?#_+q_2#9D@(Ih|EA{~b8}TYPc9I-bnU$M9_W!0 zh+q}>dDD=i4xv`V;j$S4WYEwH1ww)gczk@^*w_dQL#i%rZ-4C#Muo`!enkJ*_d)@7 zJ132pz(g5*)ox9&o|kL}QsvMUCe+RH*kDBV>AzcE-UJo4_@br>vRGjF3%qQE4Uaup z2r%a#Fv;Mbc5}7zJPcC-Dr0;TNqBy%j`(5!3xv*t&Z5jB_F^?O6}pP(E5vk{=ps

@tr0 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%0ASU{V0vYcyBwu^$s3C57mL_ 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%0A6G*7Y(aa!MIG@`KA> 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�w ze<^ORi_v{2XaAq2W>1}#YFB}8uS=l)?n2)ddqg#usM;k8qztYyRwD@#A=?#?D5rUZ zzJ}kT@%UI^L1Dyk7s8Q)6Z z`8QpNnZx=06bYE6yE^$|ser2;hI|ooE#wYEUKA+TP$ONVhPZlFDwVt{vxP6jQf3 zH=Jy5)|vq|DE(1!_r{1ZEf-%X$s%-#WN3G4hxCa-Yk>+^ChTNSJ<^)d2Go5VC?*3aoN z`Eb=I`|2lPVdB2xJWzfSvHuq)wQ|_d>U4)O-O0LT!RiXfI*Z3*>?f8^T&x}o@T75( z9jQC;j#F+9{u^{@nscUF9DFYx=l_Ni189U&G|o80Ds(mj&^Ld2_a~U1`iZBoI6nSF zqU5XL)pT?^& zpBZPSVw~+~A?G6)p;A_nb4G?+F{}LA>JCVea~CG%+x=A(_`T+b+k!{O<-6pKmue-YLonLo#-8;YT zt#rTIue+?v$d37S@8Gmc`E~E$yi56Y@8G=4_;v3hnw0VD-bFMiqYQt{JK|;S(RV63G4OiF0T*UO2T}2kv=$2>k5`s zzo#{0>|uFYSF)hWJguoM_OxcyJ_t{1qbo>8Z_$Xfjb!xB|7sx_{c7KLeV=@*S6&0w z*5r9i***3=UX@y}?4oY&FH3>YNOa3hIMYxBCNxhDvpzYW+qAPJJ74Y(@6hknebpLF zujia!KV4=$O%o5-qt!FkQhbH;-l6U>DC+Mf?yYyb57vo{y`+;h} zB{=ZkoQr68FuIyf$a#crsNo9=i*Tv(H0;+4_CmZcNvOi)V0rFH5XZQJjBl=cqCkjaQU>5%KE_@hsJQb=^mWj2{4JU<`y;%NlAeSwgQJD$x7xzEFl zYj1KwZs5NA`Q7Q8dGFm^-`%(%D|y-IwZ0$tI=EebvS%BH`5BS(BvCJN1%u(WFMl`rB6j=4 z^YVKl!+Wxl!ac$3gsUo6V$~K_^87e^_04Dc6&W^qy3TLy;@Ipe^%8eRHR{5CFKb#>)Gd|SJmaDR~6NQ zR9LW4R0Zscx^~d6sBZ`E+xJ~>e48sPPf>Fu zNi)?~JB(o49%hvhI^G;3%NJ1EDbMP-EctFuzl4YNPS3xDr}a+Hzu4m%r_Xj5e~MkN zcN>3-U9fi>e~MkPcY6NCF4^lZ=c;_OOO0BAllErgZp&M{)TmXtZI>Fn694V;%igld zeB*()=h5x26U=m5Njb_pb?tVPuBxTg?&9rN!)P@db%(Cr)h?{MH@R-C&9!rE(J8d_NLz3aEkD*K&Y~+~3wUUEDYk%$deffQK3-UJ(0h&J zg?XcG+etomi0yjGuNq>zZt`%tx8^3l(sR$D_k-{RzaJ|p<*&EPOWDvD{C+H@l$YKv zFJ(h-@cXfpQoeb+yp#?7!SBaXN;!nP8}b2pgx{z2l)GYfdqJD~gx{wHmAh_sdqJCf zh2N(ImAiU&dqJD~h2N(Im2?cxbDrFeuW~g#J6Gjux^|w*6~V*7Ixq9@c3@pi&kokr zbnRe$>#n!x6zWWYp_U7mU=U79j#HG)0&8z%W|c(irN1 zXDeExQC|r|B6Wa3RXLq_I{AgkPL>nV?S`@=+9Aa*oBMgsyFS9deNUa)K{45 z#MzXt23KfdLHj7|XwO+)Tm{cbK+c9QVo<`QC*A%CI?q^T90v5eQ#27mPpM^U+58gQ zvjD-)doa_>)?g6z$T_Sjh<6OFk#2-&f(2+{%0KX@Zi=s8o&mH6o#AkNfHT1g*a*+& z7c^z;yBYe;>$l*Ni@!SkoO}ff86loFV4%@(JcU(WbbD|l5EAv=#I17iZ_CKz=lP;XUq-fy8pqu;QP!#CJXtJ85~;1*w` zqo4sT0qOhUIC9$sdrmy~Ubr4$>!+@*a zli7-;lZM*^>#zGdT`*90!RP6lR!G# z3`7AU&?5lZ%{pE^>2xnHx@|a7@S)v;69fln)fy(3$*=IF1+Jsc(2-m?Pvx;`ZykK| zA^SE06u=F3~NT=I6AAU<5K48IpJR>n>YmrO1ei}dtVPZ1`Na%~3X3OIo!YZMs z@bf8_9(G-Jx&Y6qBa=Yl+DI7@bzld+b?5r`WOaWMeT#63-@4=J6;j`**PFbEcLi3K zTnP?C@RW|ntse)g_6WzBZA{MjOLhzCoVy#o4SPVb8y{aEeRPYujNqFg;9qz8gY1i6 zU&voy{MQLwT_?j&2k|IJ=|wXE@B=-CFRS#Ag4Y3V#wTftiMnq@`tKwL@Sqr}`VRcoOG;-oa8(0qw z*kS13HwE^#)MRGudaVQwl=-28&`6k^H336gVS_8+Z#m14IoNn{`Kma9g+og^mk5I_ zcR7Dnfv(27#D7tsX@revaILq$KB-|nY|gb>g`91$zPTk8 zL|%yy(1EF~FN5hYaLFid=^>uos`oFC4o}}59Xevae$VpHn^3vujVl4`azQq6tC!na zd7c9;B@n9ksA-ot-l#w*#1W~2(B=`m+Yu2UXk21OcTdoi28eUQRTxkh9!@xnDs-L; z2f89_h0ArV5Jy3Rl4&Wk?t}+iQJM^Fm}T&~P&&}o60HMijV$ZVE3_ypWXtTC&>&u; zHZese=dr(1dk91PKmr~s5`Jk;qA83TP1~1$1@by^U{AmK_`*z+hFAg=Myl}G5i7Pr34XSRjkt_D8zZK$PU5&9A) z!3fg($593so z+2ENVrU{)}2DB^k})`njBnC^KL0Hl zDY;*8Ap_9}7nizX!zjxJp8_|qhU}BWdm@^*8@|?Z{*7G#B z;ppW0OZfZ+`GgZhRSkKC!4;D{G+#LH#&BWbyaO9-UEHw9W zrVoYl1<7_5TT})PMpk^2)d`0(7a5w6!!T147$nbnd2*EW7~Dh52B8qF0+`deBo8*A zVJ7Q~_IJ~E*oU|OjRvRZgXhiWUV1c-j*$A^Y%4-XZSG<_8ctA<=3(v!y~Td8ki)sX zi!Gs=dv)ML+!A*4EvZx3Nj5`24081e_u^l~Rtc7*^=}89$_GKNR_(`a2o}AI^UK|5NOKKt#X&M#Euv>l+upHr@@Dc&wn}IBr-DwzuiNdt6}@9$xDM59qw14J=)`;a6ehNB8F zj$FXJL&J-8N$^{$aIlaCqHNu>^1`z$-QE{6&sLDr;hnL^3NdR|(KF2{*Q2 zaEe1+8f8VyZgD3&_*M}%VLXn~7&4`S+qC!DSBe(;N-a6FAZw&hB!jygi(AwsjiEyk zL)T1(%p8AwrgsK>Gx|F;q^QIA9&UTIQcf+X{*ZwdMmY)W6MA z(WjKvw+GhJrdPyL9AQ z*UA^hr2294gkt+ZUpwC2Y_gQP%1z$+Xi%lS+L&YRwK~V`VAL*-^} zYG@s3?Q#xnHFZ;do*c$lC5dvf0yIO}!Rd^79DBi4AQu+a{?V#1I7v8nf5`%Q&%SyISKq3@3bIyjvh)VB$fjg!AbeLSQNDt4HmA5@fye|?XbO-o&^zMaRRxSO z5$Ym)bdC9n7wenGX^|&UdpaCPowQhOnrJ&o-Wv62_%E}^r0qM6zs_ceO|xRdpZD3U zye>WLVx{5PgcI)Wn(VvOr|*ZI=9g~g`UQ66oGQ?cp z9hmE@pRS3|FdaMjx+L)M0H&X0=Uv*93E5B5|2C4;#8_JzmmF`e-*3zV?~*WMTI9&X zGtRT^&P9W{fd_8n&ba#x6CkIVh21OE1Eq5{PO}XAMfeofF1zuM2|nI;;78H`lkWbn zgF}+U9Fsf0{Csdt&R~S3YrM-cOR-yQ~ea$Ws&!DAj_<4LZVjtG6ikCvHc`9 z`uqy73Av0n%PlLjq7*KE&{_A3S+wIE$RxXz{?Zw}_DJ8F5H@h-poio6rMlt*T>#G4 zu|w2!t#KY|mj`Z&v08#>;WKuKsH( zV=`l~5;R8PLd%JkO0!vm7f81Y9u=|67BySc;;tL9L3I!cw(TKHvCXhhT}Lzn(}Bnu zC@~0dYicByvA*HW=p_Ql17)<3iER>)gJES`&4Q3&w1Ev!y4(I10CU7N=K7kqotxNy z#OR8Yc`_3fW?{XQm5K`6WCI)<(Yu4O_Q;s;zMlz}Sz zl(e*3e>EyAQs`3wgak%ro-}Yy1E#BhKE7Fpk!6lJ(9x)nIIQ&_QMPXOh%!~hkR?c< zv$Q+{_Na^l50_83fxiu?rgv}~h>$({+W;s4zq9)w^tUnc>DAl^l+|Q)|MWZgc>3n( zx7Q~her+~Segjnfc0Q+_{aJPskv&neFC0U{u}I%om%Mewr!XGbIC^fO4I! z6p0ot9Egc!+d zvbRe4U#%j%gua{NiKm#(5?ih=w*;h48~EM2+F<$mPw5F4x=?J5a+Mj_gz>;aR7El~ zRDwNNBC*!Qz>GIBU`E-RtQsgSZhy!!@n{CUL{XoAuU+B2z#iUMX_@fkn8l_}i$=nf zJLUT0lT<^}Fu7_0Bq{h`-?z9g7R$1&wQ}it3kIk9{#!6+*Y8#=7+7@@)BN9mI`C`A`+1NucV&P(3V@7Jj>_UWr*>C5NL6 zYc+Z$9@cz*>4r9jV$ul!XG+AN$FKnp@JvgIo2&Ff`N&jycPmeFV3(Dg;UKWfH}@J% z#mPB`uvN02HdIWa7-x~Y?;S)vA8wrnPw5b@yc^9G>o3V_d z=7G(f@T%y*{3vvKU^SDwK)c!I*Nb(Dou+1_ z6N#bbks;lJUP@{2O;VpGjM^$jEF%CL`EV3r^rmV6&iTVp1JJ$V+)Mc>PwT^Xtm$|+ z2rtwF(){Y%C02eQ2(LHQd$C0Cg|Q&9av*Ktw>Q;$fpAp)t+_$jmJJhaY^v&FCIzHO z0Xb`#%>l`iq@j%8Ur4@xc~oAZrAW9m^-gO7)4_kE4iZAG2ylRGw|WOF17I=C_rt5^7yq;7m*cnBKgIJRBiOT} zqryTwOHrhd~(YI)jzJv}I`2BzkJDmU)jKR3*q%a{^ zM=I?r4nf9X&gl??kJH%CMtcY&2f6Xp6CYNavmu@60w6XmzaPG3F5@$}`< z+stHgdp-LxXkWtUN&GVWe=gdsj_#gd4*N_ZECoWfQ_|W zXABZ55Sl&RM^E?B(|vT?`)JnB1rYLo{^#bGR!r3Y`JdDN{9Yfwg(bBkhut&W84RcX zesDP?kY*>q-_J$#S>lx(h#v&x430E9j!v={Nyl9zcmu#<`lBR`3Qh+I7pxbE2^`cWK~{e^V1Z3VXR?Z-f#Ns58lE_@8aXj4pU&D=aLxvwO})8g&PM zBx4AZjNv`zn8~(;DLn?$b7RcA@!x(Z9c$PyHa8HMOeEKP3f;?$b6mrg^ORzGu4UGb zLzDGjm1A@P)a&9D(k$}~i&vwH-;rOe-$3VDrj*mZ;iQ73O5Do8TC;_NeERYO`PA+E z%v{JuHZr{7!FmNDKp@OXYP%J{`M%4*&5u|1dNlLygfvqXdVQ5~)R>a9V`N3?^MV5K zszSiTo$n@OSOH|1s1P!7=er3R{(O}YjLMV_dIIG#V{d;Ilx6GCOIgyrAzlSYVyi5+ z!g8f&=!r#uIeNvdptA8*wWZS_F<7LMT^He;ImSw}$+kO*b^T#Lb6#bKA?|!P55pp4 zl99(z=NV=)9De`#*#IZqJH%gQfx=L5(rk}Q|D?Te?Jq2%-5S9(U6uvmVAxMvz0$u# zD;{&d^sQb2>>E^V0DHcHY!_y;?u0UsY$n@TtfjbMhVoEfrRa-D`)WK!7CobX!Q`b~ z)L*qm@bu3v%s%S zL$$_jWWn3hEBN|5Pz3UQIQ|1=$yTDHa=+|e_*Af0eM~WX`g@Lstvew-U|ld9CWvY< zLzgAC-2$<+JH;NE>uR#p*NacSJFoA-Zea273jC7wCrKLF3y}H}Ii?`Die4sf>p(!T;$_flbC;a|vIwddUPSUcz#F z@Y0}#qNsPEcgb#XujZibw6~KXjE{im4!%W`Y4>Z(P1`5Rbz{c+i;B&0qX&r9Bje!} z99xVDKR*8Sg1|{RA2t9mz>z1PI+$KII`9VwRye+L>X-#ZFaep|gQN`%{|h%zjDLQr znVpKEbrI*%g=6jx)STKPpK9Ok;;Q(DD(^>;y`dJEwQ_TG)qS4LUuJp28`Ho|U{&WC zH)eH)xnSPCU`bZXo9(+#Z^+x1r~iqkx;yN2+ui98K%3XEUyx6)Uppj6{2va!M&pC^ zN+-;iXw0*n+YnFT*6^RHr)tOpwTAJW*I#Umtt+((#%mQ!^;(5_VZkUA79_7?%apkd z^SdAjj=1Hm(AJhoL{PQadT|$l@bvBp%U~pt|J|U5#ky)r%qO zl^m8ipVHeNmONP`S0tiXiHfJ20uLDe2bk5kKT)Ef(v-WV!^ zVQ!53%q};Y8!CRS%ROL|{4j-NncWRlX1h$38?+ovGqsX5y}J~R7g98KM+8mmGCgY) zX~-M7D)QUXlG}{33606t%&m~&Ttj5w8m)|NlIpg%87oI+FgBq^RWYZ0XH~^&CB$a; znX2+aD}S?_XYH2`8I4*+nkt5ncS=+A71&yxZ+I#ad)s}@mKcnbDT=S>J%JJEiQ z!~I$p^Xd3ccn99R-lwELIUt$uCcWXb`Q;+Q6i8@Mf{zpOoF(4j3^gd^Z|>F60x%n&& zm}_&%XKF)nQ{-@{xe`0(QeMGP%G5~>xDmyu@o5!mpgnIHIi`QE1#~X(rhi_OEQp5} zoxUqpx{OyYNWkOO^_|hjUbY(8g8n*%jcbP5?rXh7) z0PyQVgzL0jIkZ~{dwbelNb!WUF~yU&p?Eg~5fFNiex0u_Dl55K3H7r3C=lp=A6*J+ zR#71HI)CMW8f!e1T`6LYDBljSHteaCjh`+e8NTa*m2x5;$GU4Oq80XEPw~56p$`w1GWU5IU925*>Tmb zZYQ=RD+?2wSJ&Jv!n(Be$&#c?mX2z$Su1{{^gxT|dx3g3;~n5d?B}%5G8?ZW0Tf3Q zg(GUNyWGVtN=ctiQ7n4X73%tG35FA#kJAv{u)Srqy{JK4OX z?3-cz=bca1ioSW7SH2E=C}ea&c=`(WZ5P=+*xoSK5{AC8gD~k|!9|-z98( zcXssF;bZelxDiTPyIquALm$Fw_r&$TqkBR(+!m&IZQG($wcAqG;o)w!g%(j0gVa=z z1{X2swQW9pMeLhG6K-|P9;Nf?0ckb~tONmlOH_Qu4UXCu-S%ackiT$$igv)RVX+<9 z!=&B=wsi>f=z(@(u(H41}^ z)UI^+D;kzt8-Qr*M~y%93ON$tu3Tv?y}_^|lrWNp>z^ZuVl@3!VzpGSA$-gxDQmIC zEZ*VhGCXS)rmR)g@?fTZ>%9=>+9d$d*u(F;WZsRD(xMdJWC(#$#eV5;LfRhe_4R$X*APQ8-%4? zv?bczoQVWm@j=JZs%eXtGEzHjOg#((WH;uAa^MT1s%Ob^eF-oAN#xa7^%L%mG&;XG*nH0n&|UFwR>q_}u0_2XQAd|XOV zcUQZuw5zwvOLLRTt2qn*`1ZdK-+g-1{POAa<%hG6zny+M?6kWFQKyNM8}vH7)&H=~+0I>D;O~u!bvPfY)$7$|ZzxbRRE-PTt>gBeIPAhcJH#nubw3C}yh=t0KUqE4H zZc$Mz!JyCY$kB&S@0v|_`gkETSG;GjlXl;?oMWpCFP^ouDi;7rP3$0C1p#EH6lYx4 zBXoob=@xxLHvnROLIcEbWl~rci;)a?M^_TDDzMe>Tyc3L-wJ@23Ih?+Z7YpR^(G|H zD4nP#qzcr0%F#_!69H3e4A!D5tY8@+Xe+yg{dj%0u#SZozffzY1dF5mtX2Y~8;KTM;ABl;@P9dcP$=-1 z9tv?AHHy0f7)}vs+t-%q8HmoJm|PaBJQ2 z)!D@uYY@NSPb_$4zMM=BC-C3seC~Rs>+{3<5IGYlE7O2E|Eah3Q*o#WO3G9`2vI8u zRQEZd*9l$aSQ9v9Va!Yf=ynUA0;@_0umTuDy8WX`r3^HR#al>zdvw+~Jv;n(c6N9M z|9yP5j=s&9JGeH>@paAy=L+^nr(hGsK(o$EJ$x8Ke{RhEr{7muB>YhXI4H{l?wrHX z>%+*Tj+sT1W;rCGDnMg-hJ3S({K~NVk~rd4@vSxX^ADzfVy^Myf)!{XZ@YpJL~bUl zTf%xQ&o8rrq2S(flC*lct()Wp(}>KjzJlf;%W)o?Og8TcBg^5pfpkFwO4Go&-sH;T zm+qSd;u504MZl$KIgj^Ep#f)u#6V)s%%M!C#07>sh%Km2I#`GxfV%$0Rx3o4_)1?8eJy?Q8)RAz`6PCMjU&L)QcW?H4R zL)_^(cqIZZy+ta(7-lEOVkB+7cR)|?`#)|}G;Ad!g;Xd#_Xru;kyTcuT{6-}_Q=jm z!z_|fMpPncASxq~q)@12M5U6#?{Qvle&3J#%3n{9?sLw4uKU{8b>An8YY%czd719} zGe{|Z_F`52zE&43uh?spr?@1|P~Gg(6nE3XYZWobjw0vj?wSBw-XGPZ(n!VZb8bAUD{mh z4~{!PvsR;G=Tm9@cMLKxh;fcoEg#`(CCS$aT~h0pX?`o?M&YS4JJ0b4x;k_cEk4yp4Uvw z+Vjqq&whSt&x3OJD~-{G!xu@`Etc3x59>cD-|AXh;CiLi2(yx4-noZLhIf@K%6G3= zJi({6p|#e9SNpG>;4Sudyne7)Y5pKbud45@!-p*0#B+WqRGg};q4?`f?zubHuT8RD z5ZU^SY2DP3Kb;@zZrnfSMZ`xR?bg;tXVUuI-txG!Q*)2wt)BEWn6RYen5)EigjLtc zz1!uRg!bMY<@!wEV)JOT@W;@L2l+ki0|tlAJu)k_X879vkFVtfR!!cqDD#GX^~K4X zlgxEZEX&P~^pqve@3x`A#BY1h0sY7=g(dAR(gcz(lbT}$)9>w@(R;Gu81q!Eu5pX% z$7UEsAfCb@9cagH;gLVp)5(Y`8MCq zZr5QuPrh;HCRy+3FRAxhPxpk6qIBMG)CAqMjD_=~7xfrlmSw%zS5T6n5H?rok^0o- z+ou${KltWvBRqP4w%w%_9WB?pXXKtdA20ltIlWbL2esrNhk>f=MMK^<Z0KTjuMw~V3$p%B+@v?CP%U>w`uu#-{)M|c=dA3h+tI_WaauhP3@0V}j z4@rmMSU@O)k3Yc{y&n+w$DX#JKYQHr=+4TAbChCi_A8P3t=g zWlG;tmvm5?v8-mJ+Lo`q9$5Yy{@i4C``wefJs;BQ;vU2F{-*agc-T%{k*3z^K%UY@ z_aS`$p1ULaYx=na&7E>HJGWn->%RTWysW*yw{{&r`t6`%yT>8ZJNIZ^(7{l3ll74< zZ9PoqG>wk<=pV;7i!|?OZ#T-wc*uoworT58Ho=Lyc{4h8i~khuUUo&ZzI>YDrswV2 zy!fzh&He5pcCUYOv`=vKiJqBfEMKIooPGAj4Q0a)r>+dNb}oJ%H1u6y@9)iRj7v}E zocX!c{NT&<&Cia%o>H$eZK}Lu&)Qbf?(>hw#)ga=I%MPeU0r0y2gxSbG^(Af8lAl@ zBn?s4i-w((Rpx=8f2u^Lqu#1C^Jbzmg;KDJNFo@Tx%DRRnwy*`^KZgdwX^w zuugU9)N_HWO)~awUeAjOKNAvlqBu6uXRF4(f~woe8wb{8cQ`Y+(+tb~3A6IYS=EOq z{8Za#tJbk_Z&ZK#4^iUy=7|bf5sytC&L28Yd4HZ~M++CP-@6Cp?AW#L-b;t4izbe! z&);#mcTv}hfe%v-uDJf<%7wz>BD?y5!=5Mai#-U)p>i-s+RGea@?+y;rue=jY$) zWg+!blvQ;|y=rXz)?Izv^=HqguiqD_72p4%YX4o%`={^jabieL=BW14Us zR`19e+p|aJ0JAM$J+G{)Kjw3oN*;q?TBsI zj4^HYc~%cPd@m>FvBC@miS~tYoliEMtn74p`?{YUwSP5j(JZy`Sl>2O{mq>vw;$y0 znHL|CUae|1Tutgw=-_=u{n-z%zK1T9)qHIq8gH=l;N;3;&r=oa$2#tJ`26N{-*zJ= zKk2e6<@OoHjd!9N%N&P)S~WSp*sMm>D&n)*fY9FaO6#ny-!SaEc7bVB*rT3nqmG0o zX5TWX{xEmo+Y5KA)uXj;k15@iuhWIMuvGs`zqbS8u1TAVzdD~Usn~qGyK%=3fhVsl zd_7~wsc8X~-TJoKD6Din5f?V+VK>)Nn)}Nv)|rI|bkqx3_T)&xYMzz-n0*h7osK9c zf7n!MSn#>D8M~D|0z8s$YIg5Mhk-m zTjQU*z4rD$`eaIFOkwyj=fdl$4UOKvZd8|jx)JcP*SYG$6P?Gs zl8>11D|A~A^z%~*H-FRh$)k9Oj3A3HJ(@dO>{C8-@B0G-U-Pq}pLfONI`q8KxXiV1 zqNMA#eU1`?lM@9WBjbauVwa2#OFWHb`S2Z?xa$G;FGKF@wu;9Zs)}G{rWQOP7 zNwJ=?Hc^uNZo%7g?d;;ChiEN*6P0r8e&e^4mAdznTRC*FvRn8(p}B02;#4;ytBvaw zM;)|XJ=UysnbM5YQOia~$P!$J+?<&B4z(VmanUEH*=SmyJ=+(CNR|w`Fzfxhn`%~ROA`tP2Kc#MG~ZI)Ibdj3gg_lP za?I*<@mGE0gV&pGe=BP4`sKm680mJK`&F-%%xbEIuG?3x{HFcBWJTY75)=DzT6tP~ zryaMrS7P_e)4j66G__joLxr^LfqB?B^Rkc}*P&NJw|#k#bm9=t%gUwUen@Ql^No^r z25t_1=PV8wj4+?OER@$={^b50@147+X}DLLJ@sC$uRQbk(c9h2UrW(wsJs(S;!$eurWXCmF)e7AS2V}q^5?;bCyZe=w=m~{N6P22D4T~Fxkcr87emVHX} z-E7`YPxZ@vH(%ECy%Uh=l~mAu&9iGW4t5pmS*WFlBNElt)JHjCn88f;}a3SB;9YYCm@S!gn3Ec-j82ob%jqP?2T-%7Z%} zBy=)sZqU~Y_UqHrSMTEM0luLR@81n_)_Jg4E-brytt_(iTfd_{bMU|5D-+f(w6OEI zAV2f=d9e2Tkc#Mjb+=@)A$5M9mSLOrEWRfAykd&LXhEj=)pUN=deys0JI!XLMt-k7 zd|Ujsw)aMVhZT9vc^@sJZx8ukk9!FEg|o)?6F&t=M`g^z1PPWgNhzTKg5Cuo7i$>)chyq#LxsKg=fo)0+Xvc~@MK~J8l`}h-sCVMoh z*68n4HgfBEEM;O%*A<~}y}s>7%CFx=b*4!p;4aKYn&JukcfH9GFvE z6X0>BG$VTMZ5^-VeGdJylT)i-zBoF5&G)XFeoOXU>0%Mv8l6qWANq}JElZned*Z|| ztBXYoCwTU$Pt{64-nQaHr)j5OX67q=%{YJl_0cKzUajRlcU_3CI#`~K=5 zuzu8Qt*HF-+TAW|r+ojh@y4?B*{gT<`ZDd+Z~seQV@{Sf?OD5^aNp%xn}aXMzTaCU zI@`;pNfME_*XrPa3XyT-_CU8KjbQ=Vu0aDIuN+si?8X#9?6nxRn>86V>+%M_((9`= ze}lm@#iaiC4V^sS$7ilfDzlVFWPL5M+nQowwJEayKw)rEO#Pl`I#XkJJ2~y^U(xlW zmZOo+oSRKYhBvIs%HL6nY_j@^W&QW+zxloMc*#;1^{=jBb7l;kQr7OsvC;--!Jv0P zH^+Jl__0N$9n~}BKi)X)=vv*A zy^0qET73pAE@+!p+PJjGm!UCv$LM z?c6`t_kzxssXa<2t{pva%w9qE?8u_RaS;}0mz4KB`z*HK=`lHDR%%P;yqZv*Q0VF{ zk3Up=qwS*DNi%QtvcF}v<(JuT`!M%sO8q(s#m~!6*1tXZD`$aC`7M`21v>U8zMVsg zJWtoX=hjjsjTMV{^QS*5ta$5xLZFxE^=Et62tL9pns5Eb1>mI`T zV9~L;rzOVbfx25}h3&e3Z(*8nb9>DmR@0X&T(SOTWSFa(G;m>Zj(Nm5^R!*fVUt@w z_l{WQ@^SU62adezMX7ZauT{Hl;oq-|-8b)Twq?L{PlKdH+lLD-IFE4h(s(8aiwrw9 zrp&dt@YmezJ$Dk$y79U_<7+N=uk1a%`-T$r4jT7li};osaVaj?y_RV7~Mz9@b( z70piHqc~VCA#CM=%2qyu<>^br$-S(%8H~9femL$x~zObbY7f=Cet7clQjR zttXQQzqQ(Rb8`Eky%V~1n)kv*-&(J8Rqsf_!v)=ACLIpiwS_rV?e!p#~ zU;0u06^HYc`L=wg#C-LHPa3vf4p$S>rp%cenpqL98d&HW8n(*R@W`p(d_}Lt4(?a& zoTHyCHS#{2CHImsIdJQw2l~(tlNo9?>F{l(7@h(BfZs(0?N z>hhKm^KKoBb(r?-(*J>Da(jgoxFw6*ME8G~IbhACeMwe7LenPSP2FXkA}DmsHnMOq z?RqyWCU~*&u2u)nU9Xz4BcZ5rU0}3k&c}mJy0*v9*%%xZZ0IO1+L3O&c=n*YRiSen ziudGu255)QT4oidbSI$J{hr?uX*=OW!RH+r_Bn1nz2_~-3wfxjV3U|Wqi@%&y%W-A zw;i(AX_tfM?}M>ZvImcMv)c0ZjOT9g+dio!^M^JJY;RpS+d~q2M0d31^o`C*U*_A) zC>X8TKHBa08%sCEo*T;F_MV}rXHzqBiPzmljuGEt2TnH9-nOfs!Nl@$OH>p!^@9$( zkNkOiSH~Ml;{unI9uyjm+QCu8usZBq@MTTj&D zdo&(#341ok{nGTADQjwfcbWIHDH*Mj#4#wZ{7Rk!_@%IEGT z#ZmV+Juwg6-Re=4Z<~D~HB&6~D>9s(>F;0ldP!Bv?d#h=mg+w4tUoz=+}JU1PFy}~ z;rmHZZ+lXMpd@|hIQQZ4i*Bl15%(0us~);}u&?N}@t#*Fj3>t6OBg$Rl0zT%-9G81 zv%PLt+rX@^bNR8Gr)u8$Y-S#It=G!g&ikDnr=1(;Iq+*E0+xlfIfWk|HHAeb6%F#< zKDu`g^#IlH@zLw1#$*(1iT~B#VQzh^X~mffybUHe{|Iydw#QJMqmHW0i@G`wxD7eQ{N*y=}WFZ0S78 z`ew}JaZdX+?|=LDZOZbIFSWWmJ1-2?jlB`tb4KWkidpeTw0lP!Y3r{L7a;2}zL$mB zjN^-6d=^msZXF7FzdeUads#6}m z6&*CsWGFp-dSYNhg2CCB`K>z3v>$0~dXn>A>EpBk-M_Z(>N%^8|Do#P%kCM@Y}D)L zwe^0@(h*O5PCQweduh;<#dga1)x)1%dv#vTfBpCTT-}%Bmc)33B%&mF92E_b4rX4o0 z=+fE*L3d#{6KlhBW5;J2JsbWp@K#ry)F~n6R?F2gl&h|pxW{$(FZmSyPSN0YfRcZ^ zveKr8QO_InjbGm!_N)5c&(f*Gho{y*`smy?gI4TXa!#TB!K`TY?ZP`fcOM%dkR2U+OK$L>+X`oo z${f8}Zj(Mc$J!oU_t|-_qe)Kw!zmVHqlO+ypB+81h9H)sMn!TznpPpxG9r0^5fAaDL;s?^bChs)P7Cdp>8xWrN zQ02Y(>YY!S z4;mMo8T`g+{xhvE$Mf{l8^(X#HFRi?pfg6})Dx_dgp14@gQM;nr#1^@T6^A(7gabY zKImDNd;&)zU3M8%Ak_W1H@hsS-+0~nK*ig_?n%9!?_YQkv8L6hrM9wlbTl-d(M`N>t+v;7K-z?P1`bGBG>tYCKRer*JQ^@i;aM~u;N)iko7(AUI! z&eMR#56QQ#8mE3d+NW;8PhZQagX8C09qK6eoT&2bPKZ}-M0)Nb<ncdF?T~_kGD_Ldvwa%r?9|or*YPuBUuL)Jt_D86zu;++s?RTj%m$u z{SL)4o`K!W*fFlH=CzL1zGZWyjyFwXvgX`vr(W}ak9_%f--~-s7l&7P`HUDo^W_bV zi0cZOPs&bK+Fx$ooZLz=yZeiphV?qCqwLJ~j66_2Vt>S!qRJ6-KhOMBvbo#vgNeys zgVN_sKD*{-!l|;JbEdX_kbhg6SUhQLuStfZ63iomHab>XR8B9FwH5f^aGE;0x59vp zlfV0|ukJh4UQ1<<(xsJVANVJhd+IwV3@LVqzq0njoUXd@!i}2_@3=KA%tw9e2-j@S ztP$f4UfEsLSl85d%U8|g@^jIdg-fSD(wj0PR^7wDYHGJl`@-za_PQ*KnzwB3Z>w!L zy2k2u_}QqW++4)nrl8zv^5cQ8~48Z_Jhx~eN1(Y z(%UaLi)_2|$tmNH9*%?TJ^j11wyyncVp{L&r4j7sT_YUtx;-dxqD%YVF7iWRnTC?q z?}ZAHqXz$sxV5t&@7vHZ&vWm!Rrq!9RHIf@--@a(omQA9#&^~joNU6s81*LezIyw< z?Uhc~T$TQQF;Y|Q(1IbIO+q)kACoYmIj?G9jzvUqZfKIqnqI*@LYB?&50Bjyb@)ky zyGd7T|D}6vl9gv|=5LMc>^{%TH9K_6E_?revl0SEgs84nAKY!;?I~@}wYqZm!h8p- z#*B=dZ5P|Rr{+dzs`9s;Puc0ncj~%1?DgI^Lx*m@?^oL^vEQ*vDOVenUfQR`tsat) ztJ$K&K&b6b~Z!y+BGcCknI-2XutWTMK?qENqz%6vSepaPzac_O&`|YaVRn=Yn zQhM_0>E(^>LPK}zPO7hM_vX`v^iPh7_eM5rn5wP!ZI|+0vGVb&l0G+&G>npe4Eo$D z)}vyb#l!tk(;9B9(fwXn7O*+&LB|)_ok&=e25m^=?z`T_JS8x7IYA(x?PP!aWRo5_S|4sYOZ@aA$zfgJAJ!#gnn<24oYt9B~ z`gDB0dVjy^Rdd9aB|!%jl?N$!J@jzQQ|c8Na`i)pyohB_$CqALyMOKSwMq78Uv`(| zmQAg>wz`hD^rF>_-u@@FcHPK(oTpy6D(PUuqH~Ae<{nEhRsP&A<5^@}K*WoHj`|)x z_R+I9#CW;vbXV{^s(fmZQ?G0G8>{t4Y?X&Uw{{a{YxvCUx7FyJircdfRn}Wf z)=L~YVnv+IwKdrxCsucV)Z?yB^zmt(0%kRpw36Ta&~9DaTJPfGUQcshr0fQC;mqPr z*^}!n!iSs=esq6Tsg(y#GI>{*mHh5)>hV`WSDI9szcxRrt$yG9vabCF<&?92&A->D zrWCogn^aos^j#)@{_z^WKymgIKHtE-`&iM%3Pay*Gv<8B)mR+qa5(Rh)r`%fChE`A z&3*dfj{jqx@iXEJ4SieMs5P~uDZSah zP4WlD)|p$ASJs>vcz5!kmtU*hY`n*I@x68Te!=)UkJ5+F_U;Q@vS#-F$fo`3vA2t# z2hMRnwrQ_8X-I7Ome9bdc50*QSB*Tn=;Zg$#`2%0!^V{KXwWXKJvnQ?dqBGp%j)uX zCVbwzR#CgOz)z%@|8QSKhA>Oh#3Kd1 zLk=WFZ#pczGp5hDrK19~JKh!@JM$yw^=X$`Wg)^(4`)8-G=%byqEjMCKh{K^D zJ9e}QSGNk8vB#hyCe1c;)PhF-zSpNhU2pm&3@)^*pRsoRv#fD%_*H{7!u>;cL`^qe z-}S_2vn?t!jMdNns4VL=PSSnq^XXHL3+G72%4e_8_WqjkWXPAMCA_BYcan;iHx#T0 z8<;X?PVt9x-kL79`Gv#W17p(aJ>o-rb;dpI)%#;Xuy4fh96K#9VXCEdrDBHYUZ}&_ zJr@V3j9NKX^P>K;56(+8s+0O|%DAuk+jznlk8MsD5B4{2=VRUFneM^^`KjxNckI2s z*g?@nxOtSduGMAR%Ibmd+zj?it{AOoRonf^(!f)~Uw3@m{hkGS_u68$^>9#@d(hq= zSxXwSH>;f5@OtimBVGz?-<|hzkCEs~Mb*F0Z<-MPt!?iExthZl%`6JIcz(0f@i=?` zcEOGt>f2@(tuH)en02xCz)8KSmoF+bY+hZzV&Y?^*q!y)6ynZW-%Xy_rfA~YEiz1OJHA!llcV|XHx6DpAkXabd0E=a^DCcU8JjV~wby_ty5V+_ z8<&Qx4V)lUD!#H_eMy5?qlx2Z+u1vYot%3CI$Ng%PdU%uB4)hej=)D5o=yWJ{TA!< zJQIQ>pPV;@*Qh&<8yl*%;_da@`WEK9ibkECxk-16!6KU}Pxjw0KCt~|o<-BB?0D0p zZbzr^^zS{d6MX7D;NINU3f)!ALuQOr8{!mPf4_Cv7~Ky^ikB~&&FdM^cE8A|+o157 zdHo)2I&ooT-ytmmHV$8$&ZB@p7+A*M=6q)N6`* zXgy|Xf2Zu5&1ZAlwsZBd4KS+F+F^9cx@^e%{p}1t-iYl}b#9dW?!CPt%TDzsbDoB} zv>sHx@oC81$jW2Ifzy@OWW8hN_~+2$IBbun6x_Z^Y@t5Re?O^t;f!r_cc1B zA}Bm5(im1Hv{-%i(h`LN)6x?M#e?>2n|}1d2HQ2;CfOD0^}au1hVdr*+v`?HAAglD z6N&BILc4aJu*@#S+@i4Wjl}`{rsKyNth>J)Rq?j;`0lk?Mizr(vk&wgct#^}bvupl z6UY24wiWU3y$lGwrYDnnpi`lLL)jResPN9Y zC!G3?(!9T8O~OojGZp74s%HK|_qmqt^5hPEc zeOvUC(q^4i`HhCVPX?=fKeV$@l(F=3((c*QxBa@aM9^pIs#o9qy_J@Q+rHQ{`b%Nk z$J)2Hue@9MY1X^Awz}g*DPgN}8(y|rP=C?jSjzknjf*5HeQXEj_WYF+^khaWpN{&x zI$7_2RmHz{Xf(+t+`9ZqrND2!Q|fj{o09i!^gDNWbP;X7eFyjZ>AUW?ORJOf@~)rR zWLcCtw_^O5$;Y{D^lG%QP?=&rF7}RM!Y+5Wai^qJLD|6vYupvj?44eqcE+=(a@>ny<=!2N zyFE-_ZTYxkzqY-voS71lqm*Vgul46C#c$%fg*CKUuukdsua7ILufFRjw9?zu_;^4Fg0p%ry@K}MA@ z#dm8To9Lsi6&&m292CB<=kbJKJ?EFxGjBX>zFm0l_zI=Y zhW;_f0#rKBa*JPcQQG$CZY9M*%to2$&q3X)rZl`T*JeM2KX>Ys8A^T-W z(S{=d4mtfU7mx5z`dDHh-BPdL!J#C2{QDQ{-+WfSnXWnZs)6HWtKIGF7FvBv^?5mW z@F%O2w|lx?mV8gSAs)Ike_(q{g)icz%e3D3bTyc}??%8Ck)rp#>kdNkw!_yu=DyK8 zXfk{M+ysR|$-yRf4o9y^u1P#@P29H=F0#L&E;dGKoHsq-d& zyJbywiuFB{^5;gVSW3Gl&U8xG>~rSo@2X~#>q&vfZCC0qoPEr=#yv06CZHQP(2zW6#0+eTr5>Cs@3dazs#stQ~x~0B_+F_PfM{VJbC52 zeeZ_Njh|QF5qV{cZZ<5^oFLnB=j+vlABe?}Q}{VQAyiRN@oG!^EjKmWn1^Xc7HwJ;w#{F1?3Sb9 z1-GlJou1rV5u+n|Z9c(MRQJ$Tr^CZi_1agG3!xp3?JQPWC%e93UzkfcCjUQ56HIqZ+ ze}2gLe}4%7{t*BD@prK7?_l}g!ScU@<$nju{|=V_87$`g87$`g87$`g87$`g87$`g z9nAkbnE!V$|9>B3=8O5V|IJ4%;Qjr#$^*n~L#&6xR9ghX4D|6bDC_B|bXChwB(y_$}p# z&BK3;r|TH-2br4k|NIuzY2M6fJ>{>Dv(|936|ZZ24<|NTwC%|-BcE`t9E@pmo)ZZ3kqa}jWJ!Fv9= zj+=|%?_31jT(HD{{>IHk@OLf(ZZ25$KY!!qBKSKOAvYH=!vFpzqv(RhKdJa)xDQF`#HHV=zl}qmwAkJ@O9BK7;7Tn z@g+PlzOoM16v%Pe)Md{9_iub2kI&}`M0o4}^ZXUwF0Ly0NVizTSK36CYQ7CE0cpV>^QkZ z#y(djmqF0~oeOS9FgZ^`<_wJRpPbKUX~=r^CTh>vqr$=oGJRh z*YbH%F}uFNq?{FE#!2PO`to@)zJQT84wI27IkYa?d1X3&#J5I{u9KwI^Cl$eMAefZp4N!`eEj};_xu1;B z`H25ML)HTQWMbBq@dYvo=g%?M%7x^9a@aF=9QdA&6H4hgDJ&}U4Ddb68$zfPmi9uB zlzoPf_n%k#&zymAzBGf$Sslw4LXcQF7s60ejOr^PUn*wbO~{uK9VQg;2~B~qx}7f+ z{O7>`J7N=t1zc}jO^^m|r zAlJ%>ObaD)5#eVkv>1D>6kJ3w36V>bf*yZjm!@+P3VleEbjs%`~o+Y_+}!A7I|ODG+8&O5>}6k#4;{={6{WD zVmZAQwwurZVFh_#h#PsXL`r-CL{XG3QaHTqT%=;kyKw6Wt)x`{iDXp&iDb~m>@z?D zvPLo~@v}uxO@w}Os9yGda()Zr#KdkPA|ZAQ%ge?Pd|+hF#XJG=OJMPcKPko;TI{+Z zkwy4a3^8ZlLk!tx-xuCJks~oee|oK)jq{KblM_FJOEj=+iHMWFhd@H)QjD0BT{p3i zPjshPC?GM8SSTjGj~I_-^(5S4`V1&pmWRY5cpMBL0Hf;$5hOH)$|3Z_B9Xa>;Y_j5 z5Q~W}5#!b9wQ^!F#S$0`_I{EU-b2#Ddq^O_#h;!swpz5)$h|`;iz-!Udx2GmukY*B4fw&IM^Hb}cyEoM2WKq;SqCM*VSk3`F*U5x$qg zAd&TLA@>FGAo(U>geRpf_`tx3d`P8KmjEL%u@rf9!Us|@+{} zyag~4cLS5KzC17~tFuwrCNd3-&+-~DlGg)9-wkSwwdWWoXJZ!u+!A)(;D}1tyc94} z3&f>FK7bKh!C|aE5D4K8G4cTn*?NZdXfI=Z& zEwj&%!qZ_f8Juc@wLp6rvb1CzGG_!MIXrm9G9s6VwphPiAVg}8v6sL|jvJVS^>cuc zdYM3kvL8D?WFpym3dRZ9+A%Ov_v0|4bC9d2_oKCF0auPrWEGwO8#^N_ zKxz&EAl1xzAbY^tX^fMyu?CXpJl017#%Fs|fWZl2pMf$R%Nxkwv-LMzOJXYl!Vj|M zuz0Kwf^ibI9tw=qnFL&}p3oV2Jy!Nn_G5d6a4oWy?7NB4MMW?}2CNa)#jsG6R*+vpQ-mqx-Q>s= zvhv%Ch3(pf_Kmf(e<8H}X?(o(D( z!CND`37rtc4--q|tp6=^FybE|%RtsrBBcHm^72HsxV${O z=16g~wRd<7R8}QO2@)DWRtfFJ0%8{==!s!b;&S?gPmyXS>x=1;Iin4kVq#)1B~ofb5d{$4gpP!kFk%D1X)Rz#wy?5* z(geZeJYpA+YH10he2S2htR-^)te%ATO!O6U|Afw5h{N&~Ft%n5gN()k=G}l1za1?O zY%Ws3EhW3YaHZI~B*uXg*k{n1I=p8d;ax5*#ma&drjfiG%{$_Lr1u;hHl)uIf`!Bs zGe6`G3I9R06P+kSOw7ub40UmK&S)ov0$y%a>+X6=7JY=d`z^Jb*hy5k%+k&qwhy5k*+k&r*Dj4xufl+>efg{gt z!B>{IU~A`chT<6WBnlxWBn3f|81)L zzcp)MB(DsNF44+Og5edM*4?1jO7g>$^op8&S7jX7%&nWa2P9Fz|e5} zFOPE=YooB~g!BmlBYlFvNNxleDqQR{;M+3mi;Na-NXC)+7RC|(k89Is{d-_22D0~q z&&tR&*Ur!K6#`-bYrBEr(d_+@s%PX4lw+a~9 z8w90GZ7m9&geM`sMDHS-Lu8O^5h3rvNe%mM+#3@N*-e7MAtIQZ*dDGRMd&OdHBvA= znnc+9q1Hj30XLh>1uiRj2A7m(?}r2`%WDF$n2im<7)b1qYvpWwj?yuy*>D)K`)D(# zyv8**vd`cGbb_I*Nibv?35Kpu76Yj$M)uyIw2ev=xfWFdf+2b)7|D@w)p(*4xwc#~ z7dXpg-QWbXG~gUcmR4}=2%mD!56drbObEZg$P<16Mr=F`9I?MJTx<;-&3|-#(Z)#D z7lKag0tB7Sx1+6q^lAX3x{2Gm&e9Z>O5(qWAPX#APzfY@5+NAz^^i?ub4$q3irE|r zFf;-%yusD!*!2ZQ^r;Aag6x_DBYrkllVkZ0(H5O^3%n+RO<`pQ88w$eS zgb%nqFs!^G#m)A{qZtzqX5S6kle{lNHCDf1Ukr&GvAvAV!*RRhh%?##7pZ z?^#?dkg>1<&eJbd{2r2^isLuH?_k5o!}e zKg-}V5MGmGG7SCjSi*l?A2Mr?&~r>|EimFoa6QNDb8+Smc{kK1$a>(+AF>{(SCIS* z>J`LShQ~$hG-?=Zo*$iWr0QlxEp_4|c+ndId1j+XIZoDd=7!ItQIS zlzuomi(T^;Y7+?ZNFN^BHlfMcHAl&i<$HuZ#LfUCb_OPZ=r9~fL}UT#l*CbRZArX^ zx&g7Zz=(c9S1z$--1Zs5&+yw>9f7(5r60;_bR6lYfuh6VCoKJtQXtReCP>DSdMGZ0 za{qT6FtS$*7?Q|j9N9;OMI&`4U}Vm~NWPuJ*nBn;9>jmkABr<*;)>;K=Ye#!1-y71)Uf2aCNHK033O7)Q<* z07mln+;JnUZvhP3AJ}IgHA2>xo+-h#KeK);htX?k{|m;!V6xAJn@FCE_?OHNwQ@o~ zm=D6caK{NBz^D*DfMO$aK`D^X8KrGH4qA+P4@5X@94bNx%j!B{Rwj02?VDE=kNy1k$vY!OkqL9d5 z3)h0&kDk|pEe+Hz03&t*sejhTgg}$pEHILX1BR0gnE9bz!Nv>F;w0Y$42(strMd}b zi;b~yE$KDjyes-1=xbqh4tFdQOM7%*5j%rTSY+LRk#$2i9MQYLh~7nQf{l~W&_VW1 z07GEL(gm(4nKRlV35Mh$%cscrvc58uDNG3a473`s_5-yEHvh*Royx`^z{t5)z+^34 zOKkwO5bJYsnu+yKfuUoMoipM$vc5QSkJUricFg*Eoaar~7xG5vf<`Thkvt&+PINo7 z^Mg~(>LIjh5Iu>S1JRRQV+MOa)EtOjLt37!2kHxKoD8NS{ZicaBOVXOrt_dd`yIhL=PcDLG%!wKq< z8FF$hcC-@=U4{&X0Exs*T;M~;;e-`(E!iK6E@UK(*>T)~xdcO1iC{R;gT-KISh|49 zWZj@piJpW~Bzh9U&(?&w?SpKN8yGnslf&q9(T2?GQ!EIPea;LL`hgQzzDG5g-j6E~ zvUI^Q39Q}_Ax0#$LeYji1KSPgwJppUX-qN>`4@6O^P)- z2(94qQ;h7jLua#52LMuC=DQXF1E@);aYlOro%WLQ&BQ}aFPqX)f7e>|`QcmcC z3?88i*ZRTgE7U_tjttpE68FIKCbGb_JF@Qv)*$=`X(M_KofSl{acB6E_vH@JVE7N! zOQQdPQCh*+vieE_ZkS&(4uq%PsH(}!$ zgf84bmM&3##_0Tz?qqERT2n|K7}-g}lgQo^eT8s_$TTn# z`@x!%H3GX3Uy7^8v$RKAkHn3ry_30cXOyw;#?{$bSw$32=*R69WNiQ}EwNGDUP0D2 zqN9!2%NA_&rM@nNid$e~|YK0w>bHtQ1tBWHti80(jSG05I^U~t6P=feDw^+10tnIF!l zVRQt-Eh!tra>uu`F%yTe@(Yae0WdapL5nNN1py;*Eikgr9~hBUVB{P_9D+gm`hX#` z!qAHQI1x)L)cEMT!CfQc=-JT-Ly;C_p8+vv^dH8N?;s%KLC*REM)nv3Bl`k@k#C0m z*CNdF2D0OX4^ZP{bt0}M-!MYZgX4zScWXgDxT6FJ4J0Ig&xPl#?Eyy4E&`n`dX zGf03DzYZA4z|x9KR1=JxV~7TNl1Jh&HYNr}_SZ65bAks z42IMaIiCv{*`ost=8=702{{i1mXXwT5w4Ow16$;<^MVOCG#5M0tPfPjSThro_yG*L14!?8WA{YBF?={d&H+l2Nw2#$Q~2pCFm z|2_i_5;pr1jGR{h?-?w^j6b>p&{vCzDKti$rA#DVE(I5;fW$O@-Odl7@EcZc@KD^h>8E@ zUCuj2@%{ge^YwOcU*h7eGJLp-@htZMm;Zfv*m&l$Wxn{yt)|XQ72`=BuFJT;-~sqA cKA7y|>)`GC-?xgnJ7R_^0|$eP5=M^ From 90731761e370f9f55c5500a98aa8203c65f2922e Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 14 Nov 2017 19:03:46 +0100 Subject: [PATCH 077/284] This commit provides the IQ record-playback feature know under issue #272 --- cmake_targets/CMakeLists.txt | 1 + cmake_targets/build_oai | 8 + openair1/PHY/LTE_TRANSPORT/pucch.c | 27 +- openair2/LAYER2/MAC/defs.h | 4 + openair2/LAYER2/MAC/eNB_scheduler_RA.c | 18 + .../LAYER2/MAC/eNB_scheduler_primitives.c | 3 + openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c | 4 +- openair2/RRC/LITE/defs.h | 4 + openair2/RRC/LITE/rrc_eNB_S1AP.c | 4 +- targets/ARCH/COMMON/common_lib.h | 9 + targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp | 329 +++++++++++++++++- targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.h | 89 +++++ 12 files changed, 490 insertions(+), 10 deletions(-) create mode 100644 targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 3dbb61b5ae..c5ca88d5b8 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -241,6 +241,7 @@ add_boolean_option(UE_AUTOTEST_TRACE False "Activate UE autotest specific logs add_boolean_option(UE_DEBUG_TRACE False "Activate UE debug trace") add_boolean_option(UE_TIMING_TRACE False "Activate UE timing trace") add_boolean_option(DISABLE_LOG_X False "Deactivate all LOG_* macros") +add_boolean_option(USRP_REC_PLAY False "Enable USRP record playback mode") add_boolean_option(DEBUG_CONSOLE False "makes debugging easier, disables stdout/stderr buffering") diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index d3a13c41c9..d625dfa159 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -66,6 +66,7 @@ UE_AUTOTEST_TRACE="False" UE_DEBUG_TRACE="False" UE_TIMING_TRACE="False" DISABLE_LOG_X="False" +USRP_REC_PLAY="False" BUILD_ECLIPSE=0 trap handle_ctrl_c INT @@ -158,6 +159,8 @@ Options Disable all LOG_* macros --build-eclipse Build eclipse project files. Paths are auto corrected by fixprj.sh +--usrp-recplay + Build for I/Q record-playback modes Usage (first build): oaisim (eNB + UE): ./build_oai -I --oaisim -x --install-system-files Eurecom EXMIMO + COTS UE : ./build_oai -I --eNB -x --install-system-files @@ -350,6 +353,10 @@ function main() { BUILD_TELNETSRV=1 echo_info "Build embedded telnet server" shift ;; + --usrp-recplay) + USRP_REC_PLAY="True" + echo_info "Enabling USRP record playback mode" + shift 1;; -h | --help) print_help exit 1;; @@ -540,6 +547,7 @@ function main() { echo "set (UE_DEBUG_TRACE $UE_DEBUG_TRACE)" >> $cmake_file echo "set (UE_TIMING_TRACE $UE_TIMING_TRACE)" >> $cmake_file echo "set (DISABLE_LOG_X $DISABLE_LOG_X)" >> $cmake_file + echo "set (USRP_REC_PLAY $USRP_REC_PLAY)" >> $cmake_file if [ "$UE" = 1 -a "$NOS1" = "0" ] ; then echo_info "Compiling UE S1 build : enabling Linux and NETLINK" echo "set (LINUX True )" >> $cmake_file diff --git a/openair1/PHY/LTE_TRANSPORT/pucch.c b/openair1/PHY/LTE_TRANSPORT/pucch.c index 61d2cc0e9b..dacafa6b29 100644 --- a/openair1/PHY/LTE_TRANSPORT/pucch.c +++ b/openair1/PHY/LTE_TRANSPORT/pucch.c @@ -1871,6 +1871,23 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB, eNB->pucch1ab_stats_cnt[j][i]=0; } } +#if defined(USRP_REC_PLAY) + // It's probably bad to do this statically only once. + // Looks like the above is incomplete. + // Such reset needs to be done once a UE PHY structure is being used/re-used + // Don't know if this is ever possible in current architecture + for (i=0;i<10240;i++) { + for (j=0;jpucch1_stats[j][i]=0; + eNB->pucch1_stats_thres[j][i]=0; + } + } + for (i=0;i<20480;i++) { + for (j=0;jpucch1ab_stats[j][i]=0; + } + } +#endif first_call=0; } @@ -2289,8 +2306,12 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB, stat_im=0; // Do detection now +#if defined(USRP_REC_PLAY) + // It looks like the value is a bit messy when RF is replayed. + if (sigma2_dB<=(dB_fixed(stat_max)-pucch1_thres+2)) {// +#else if (sigma2_dB<(dB_fixed(stat_max)-pucch1_thres)) {// - +#endif chL = (nsymb>>1)-4; chest_mag=0; cfo = (frame_parms->Ncp==0) ? &cfo_pucch_np[14*phase_max] : &cfo_pucch_ep[12*phase_max]; @@ -2431,7 +2452,11 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB, if (fmt==pucch_format1b) *(1+payload) = (stat_im<0) ? 1 : 2; } else { // insufficient energy on PUCCH so NAK +#if defined(USRP_REC_PLAY) + LOG_I(PHY,"PUCCH 1a/b: NAK subframe %d : sigma2_dB %d, stat_max %d, pucch1_thres %d\n",subframe,sigma2_dB,dB_fixed(stat_max),pucch1_thres); +#else LOG_I(PHY,"PUCCH 1a/b: subframe %d : sigma2_dB %d, stat_max %d, pucch1_thres %d\n",subframe,sigma2_dB,dB_fixed(stat_max),pucch1_thres); +#endif *payload = 4; // DTX ((int16_t*)&eNB->pucch1ab_stats[UE_id][(subframe<<10) + (eNB->pucch1ab_stats_cnt[UE_id][subframe])])[0] = (int16_t)(stat_re); ((int16_t*)&eNB->pucch1ab_stats[UE_id][(subframe<<10) + (eNB->pucch1ab_stats_cnt[UE_id][subframe])])[1] = (int16_t)(stat_im); diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index ba02a35694..0c9e149820 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -128,7 +128,11 @@ /*!\brief Maximum number od control elemenets */ #define MAX_NUM_CE 5 /*!\brief Maximum number of random access process */ +#if defined(USRP_REC_PLAY) +#define NB_RA_PROC_MAX 1 +#else #define NB_RA_PROC_MAX 4 +#endif /*!\brief size of buffer status report table */ #define BSR_TABLE_SIZE 64 /*!\brief The power headroom reporting range is from -23 ...+40 dB and beyond, with step 1 */ diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c index c6df031876..9ddb78e01f 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c @@ -1244,7 +1244,25 @@ void initiate_ra_proc(module_id_t module_idP, RA_template[i].Msg2_subframe = (subframeP+4)%10; /* TODO: find better procedure to allocate RNTI */ do { +#if defined(USRP_REC_PLAY) // deterministic rnti in usrp record/playback mode + static int drnti[NUMBER_OF_UE_MAX] = { 0xbda7, 0x71da, 0x9c40, 0xc350, 0x2710, 0x4e20, 0x7530, 0x1388, 0x3a98, 0x61a8, 0x88b8, 0xafc8, 0xd6d8, 0x1b58, 0x4268, 0x6978 }; + int j = 0; + int nb_ue = 0; + for (j = 0; j < NUMBER_OF_UE_MAX; j++) { + if (UE_RNTI(module_idP, j) > 0) { + nb_ue++; + } else { + break; + } + } + if (nb_ue >= NUMBER_OF_UE_MAX) { + printf("No more free RNTI available, increase NUMBER_OF_UE_MAX\n"); + abort(); + } + RA_template[i].rnti = drnti[nb_ue]; +#else RA_template[i].rnti = taus(); +#endif loop++; } while (loop != 100 && /* TODO: this is not correct, the rnti may be in use without diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 19ff3cf39f..08b04f5188 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -1717,6 +1717,9 @@ int add_new_ue(module_id_t mod_idP, int cc_idP, rnti_t rntiP,int harq_pidP UE_list->ordered_ULCCids[0][UE_id] = cc_idP; UE_list->num_UEs++; UE_list->active[UE_id] = TRUE; +#if defined(USRP_REC_PLAY) // not specific to record/playback ? + UE_list->UE_template[cc_idP][UE_id].pre_assigned_mcs_ul = 0; +#endif #ifdef Rel14 UE_list->UE_template[cc_idP][UE_id].rach_resource_type = rach_resource_type ; diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c index d395f95981..2554eb145a 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c @@ -220,7 +220,7 @@ pdcp_validate_security( stream_decrypt(pdcp_pP->cipheringAlgorithm, &decrypt_params, &buffer_decrypted); - +#if !defined(USRP_REC_PLAY) if (srb_flagP) { /* Now check the integrity of the complete PDU */ decrypt_params.message = pdcp_pdu_buffer; @@ -241,7 +241,7 @@ pdcp_validate_security( return -1; } } - +#endif VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT); return 0; diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index 0811818c72..9d7f7fdf2d 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -242,7 +242,11 @@ typedef enum HO_STATE_e { // #define NUM_MAX_CBA_GROUP 4 // in the platform_constants /* TS 36.331: RRC-TransactionIdentifier ::= INTEGER (0..3) */ +#if defined(USRP_REC_PLAY) +#define RRC_TRANSACTION_IDENTIFIER_NUMBER 1 +#else #define RRC_TRANSACTION_IDENTIFIER_NUMBER 3 +#endif typedef struct { unsigned short transport_block_size; /*!< \brief Minimum PDU size in bytes provided by RLC to MAC layer interface */ diff --git a/openair2/RRC/LITE/rrc_eNB_S1AP.c b/openair2/RRC/LITE/rrc_eNB_S1AP.c index 55adb217fa..24ee3c06da 100644 --- a/openair2/RRC/LITE/rrc_eNB_S1AP.c +++ b/openair2/RRC/LITE/rrc_eNB_S1AP.c @@ -390,8 +390,10 @@ rrc_pdcp_config_security( ue_context_pP->ue_context.kenb, &kRRCint); +#if !defined(USRP_REC_PLAY) #define DEBUG_SECURITY 1 - +#endif + #if defined (DEBUG_SECURITY) #undef msg #define msg printf diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h index 6214c81cc6..2dc1650bfd 100644 --- a/targets/ARCH/COMMON/common_lib.h +++ b/targets/ARCH/COMMON/common_lib.h @@ -207,6 +207,15 @@ typedef struct { int iq_rxrescale; //! Configuration file for LMS7002M char *configFilename; +#if defined(USRP_REC_PLAY) + unsigned short sf_mode; // 1=record, 2=replay + char sf_filename[1024]; // subframes file path + unsigned int sf_max; // max number of recorded subframes + unsigned int sf_loops; // number of loops in replay mode + unsigned int sf_read_delay; // read delay in replay mode + unsigned int sf_write_delay; // write delay in replay mode + unsigned int eth_mtu; // ethernet MTU +#endif } openair0_config_t; /*! \brief RF mapping */ diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index 30faf8d2b7..8b62a8e698 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -270,11 +270,53 @@ static int sync_to_gps(openair0_device *device) return EXIT_SUCCESS; } +#if defined(USRP_REC_PLAY) +#include "usrp_lib.h" +static FILE *pFile = NULL; +int mmapfd = 0; +struct stat sb; +iqrec_t *ms_sample = NULL; // memory for all subframes +unsigned int nb_samples = 0; +unsigned int cur_samples = 0; +int64_t wrap_count = 0; +int64_t wrap_ts = 0; +unsigned int u_sf_mode = 0; // 1=record, 2=replay +unsigned int u_sf_record = 0; // record mode +unsigned int u_sf_replay = 0; // replay mode +char u_sf_filename[1024]; // subframes file path +unsigned int u_sf_max = DEF_NB_SF; // max number of recorded subframes +unsigned int u_sf_loops = DEF_SF_NB_LOOP; // number of loops in replay mode +unsigned int u_sf_read_delay = DEF_SF_DELAY_READ; // read delay in replay mode +unsigned int u_sf_write_delay = DEF_SF_DELAY_WRITE; // write delay in replay mode +char *tmp_filename[1]; // use an array of pointer (libconfig does not seems to work with char array yet) + +char config_opt_sf_file[] = CONFIG_OPT_SF_FILE; +char config_def_sf_file[] = DEF_SF_FILE; +char config_hlp_sf_file[] = CONFIG_HLP_SF_FILE; +char config_opt_sf_rec[] = CONFIG_OPT_SF_REC; +char config_hlp_sf_rec[] = CONFIG_HLP_SF_REC; +char config_opt_sf_rep[] = CONFIG_OPT_SF_REP; +char config_hlp_sf_rep[] = CONFIG_HLP_SF_REP; +char config_opt_sf_max[] = CONFIG_OPT_SF_MAX; +char config_hlp_sf_max[] = CONFIG_HLP_SF_MAX; +char config_opt_sf_loops[] = CONFIG_OPT_SF_LOOPS; +char config_hlp_sf_loops[] = CONFIG_HLP_SF_LOOPS; +char config_opt_sf_rdelay[] = CONFIG_OPT_SF_RDELAY; +char config_hlp_sf_rdelay[] = CONFIG_HLP_SF_RDELAY; +char config_opt_sf_wdelay[] = CONFIG_OPT_SF_WDELAY; +char config_hlp_sf_wdelay[] = CONFIG_HLP_SF_WDELAY; + +#endif + /*! \brief Called to start the USRP transceiver. Return 0 if OK, < 0 if error @param device pointer to the device structure specific to the RF hardware target */ static int trx_usrp_start(openair0_device *device) { +#if defined(USRP_REC_PLAY) + if (u_sf_mode != 2) { // not replay mode +#endif + usrp_state_t *s = (usrp_state_t*)device->priv; @@ -313,12 +355,21 @@ static int trx_usrp_start(openair0_device *device) { s->rx_count = 0; s->tx_count = 0; s->rx_timestamp = 0; +#if defined(USRP_REC_PLAY) + } +#endif return 0; } /*! \brief Terminate operation of the USRP transceiver -- free all associated resources * \param device the hardware to use */ static void trx_usrp_end(openair0_device *device) { +#if defined(USRP_REC_PLAY) // For some ugly reason, this can be called several times... + static int done = 0; + if (done == 1) return; + done = 1; + if (u_sf_mode != 2) { // not subframes replay +#endif usrp_state_t *s = (usrp_state_t*)device->priv; s->rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); @@ -326,7 +377,45 @@ static void trx_usrp_end(openair0_device *device) { s->tx_md.end_of_burst = true; s->tx_stream->send("", 0, s->tx_md); s->tx_md.end_of_burst = false; - +#if defined(USRP_REC_PLAY) + } +#endif +#if defined(USRP_REC_PLAY) + if (u_sf_mode == 1) { // subframes store + pFile = fopen (u_sf_filename,"wb+"); + if (pFile == NULL) { + std::cerr << "Cannot open " << u_sf_filename << std::endl; + } else { + unsigned int i = 0; + unsigned int modu = 0; + if ((modu = nb_samples % 10) != 0) { + nb_samples -= modu; // store entire number of frames + } + std::cerr << "Writing " << nb_samples << " subframes to " << u_sf_filename << " ..." << std::endl; + for (i = 0; i < nb_samples; i++) { + fwrite(ms_sample+i, sizeof(unsigned char), sizeof(iqrec_t), pFile); + } + fclose (pFile); + std::cerr << "File " << u_sf_filename << " closed." << std::endl; + } + } + if (u_sf_mode == 1) { // record + if (ms_sample != NULL) { + free((void*)ms_sample); + ms_sample = NULL; + } + } + if (u_sf_mode == 2) { // replay + if (ms_sample != MAP_FAILED) { + munmap(ms_sample, sb.st_size); + ms_sample = NULL; + } + if (mmapfd != 0) { + close(mmapfd); + mmapfd = 0; + } + } +#endif } /*! \brief Called to send samples to the USRP RF target @@ -339,6 +428,9 @@ static void trx_usrp_end(openair0_device *device) { */ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) { int ret=0; +#if defined(USRP_REC_PLAY) + if (u_sf_mode != 2) { // not replay mode +#endif usrp_state_t *s = (usrp_state_t*)device->priv; int nsamps2; // aligned to upper 32 or 16 byte boundary @@ -405,6 +497,15 @@ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, if (ret != nsamps) LOG_E(PHY,"[xmit] tx samples %d != %d\n",ret,nsamps); +#if defined(USRP_REC_PLAY) + } else { + struct timespec req; + req.tv_sec = 0; + req.tv_nsec = u_sf_write_delay * 1000; + nanosleep(&req, NULL); + ret = nsamps; + } +#endif return ret; } @@ -421,9 +522,12 @@ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, * \returns the number of sample read */ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) { - usrp_state_t *s = (usrp_state_t*)device->priv; - int samples_received=0,i,j; - int nsamps2; // aligned to upper 32 or 16 byte boundary + usrp_state_t *s = (usrp_state_t*)device->priv; + int samples_received=0,i,j; + int nsamps2; // aligned to upper 32 or 16 byte boundary +#if defined(USRP_REC_PLAY) + if (u_sf_mode != 2) { // not replay mode +#endif #if defined(__x86_64) || defined(__i386__) #ifdef __AVX2__ nsamps2 = (nsamps+7)>>3; @@ -490,7 +594,45 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp s->rx_count += nsamps; s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate); *ptimestamp = s->rx_timestamp; - return samples_received; +#if defined (USRP_REC_PLAY) + } +#endif +#if defined(USRP_REC_PLAY) + if (u_sf_mode == 1) { // record mode + // Copy subframes to memory (later dump on a file) + if (nb_samples < u_sf_max) { + (ms_sample+nb_samples)->header = BELL_LABS_IQ_HEADER; + (ms_sample+nb_samples)->ts = *ptimestamp; + memcpy((ms_sample+nb_samples)->samples, buff[0], nsamps*4); + nb_samples++; + } + } else if (u_sf_mode == 2) { // replay mode + if (cur_samples == nb_samples) { + cur_samples = 0; + wrap_count++; + if (wrap_count == u_sf_loops) { + std::cerr << "USRP device terminating subframes replay mode after " << u_sf_loops << " loops." << std::endl; + return 0; // should make calling process exit + } + wrap_ts = wrap_count * (nb_samples * (((int)(device->openair0_cfg[0].sample_rate)) / 1000)); + } + if (cur_samples < nb_samples) { + *ptimestamp = (ms_sample[0].ts + (cur_samples * (((int)(device->openair0_cfg[0].sample_rate)) / 1000))) + wrap_ts; + if (cur_samples == 0) { + std::cerr << "starting subframes file with wrap_count=" << wrap_count << " wrap_ts=" << wrap_ts + << " ts=" << *ptimestamp << std::endl; + } + memcpy(buff[0], &ms_sample[cur_samples].samples[0], nsamps*4); + cur_samples++; + } + struct timespec req; + req.tv_sec = 0; + req.tv_nsec = u_sf_read_delay * 1000; + nanosleep(&req, NULL); + return nsamps; + } +#endif + return samples_received; } /*! \brief Compares two variables within precision @@ -684,12 +826,135 @@ int trx_usrp_reset_stats(openair0_device* device) { return(0); } +#if defined(USRP_REC_PLAY) +extern "C" { +/*! \brief Initializer for USRP record/playback config + * \param parameter array description + * \returns 0 on success + */ +int trx_usrp_recplay_config_init(paramdef_t *usrp_recplay_params) { + // --subframes-file + memcpy(usrp_recplay_params[0].optname, config_opt_sf_file, strlen(config_opt_sf_file)); + usrp_recplay_params[0].helpstr = config_hlp_sf_file; + usrp_recplay_params[0].paramflags=PARAMFLAG_NOFREE; + usrp_recplay_params[0].strptr=(char **)&tmp_filename[0]; + usrp_recplay_params[0].defstrval = NULL; + usrp_recplay_params[0].type=TYPE_STRING; + usrp_recplay_params[0].numelt=sizeof(u_sf_filename); + // --subframes-record + memcpy(usrp_recplay_params[1].optname, config_opt_sf_rec, strlen(config_opt_sf_rec)); + usrp_recplay_params[1].helpstr = config_hlp_sf_rec; + usrp_recplay_params[1].paramflags=PARAMFLAG_BOOL; + usrp_recplay_params[1].uptr=&u_sf_record; + usrp_recplay_params[1].defuintval=0; + usrp_recplay_params[1].type=TYPE_UINT; + usrp_recplay_params[1].numelt=0; + // --subframes-replay + memcpy(usrp_recplay_params[2].optname, config_opt_sf_rep, strlen(config_opt_sf_rep)); + usrp_recplay_params[2].helpstr = config_hlp_sf_rep; + usrp_recplay_params[2].paramflags=PARAMFLAG_BOOL; + usrp_recplay_params[2].uptr=&u_sf_replay; + usrp_recplay_params[2].defuintval=0; + usrp_recplay_params[2].type=TYPE_UINT; + usrp_recplay_params[2].numelt=0; + // --subframes-max + memcpy(usrp_recplay_params[3].optname, config_opt_sf_max, strlen(config_opt_sf_max)); + usrp_recplay_params[3].helpstr = config_hlp_sf_max; + usrp_recplay_params[3].paramflags=0; + usrp_recplay_params[3].uptr=&u_sf_max; + usrp_recplay_params[3].defuintval=DEF_NB_SF; + usrp_recplay_params[3].type=TYPE_UINT; + usrp_recplay_params[3].numelt=0; + // --subframes-loops + memcpy(usrp_recplay_params[4].optname, config_opt_sf_loops, strlen(config_opt_sf_loops)); + usrp_recplay_params[4].helpstr = config_hlp_sf_loops; + usrp_recplay_params[4].paramflags=0; + usrp_recplay_params[4].uptr=&u_sf_loops; + usrp_recplay_params[4].defuintval=DEF_SF_NB_LOOP; + usrp_recplay_params[4].type=TYPE_UINT; + usrp_recplay_params[4].numelt=0; + // --subframes-read-delay + memcpy(usrp_recplay_params[5].optname, config_opt_sf_rdelay, strlen(config_opt_sf_rdelay)); + usrp_recplay_params[5].helpstr = config_hlp_sf_rdelay; + usrp_recplay_params[5].paramflags=0; + usrp_recplay_params[5].uptr=&u_sf_read_delay; + usrp_recplay_params[5].defuintval=DEF_SF_DELAY_READ; + usrp_recplay_params[5].type=TYPE_UINT; + usrp_recplay_params[5].numelt=0; + // --subframes-write-delay + memcpy(usrp_recplay_params[6].optname, config_opt_sf_wdelay, strlen(config_opt_sf_wdelay)); + usrp_recplay_params[6].helpstr = config_hlp_sf_wdelay; + usrp_recplay_params[6].paramflags=0; + usrp_recplay_params[6].uptr=&u_sf_write_delay; + usrp_recplay_params[6].defuintval=DEF_SF_DELAY_WRITE; + usrp_recplay_params[6].type=TYPE_UINT; + usrp_recplay_params[6].numelt=0; + + return 0; // always ok +} +} +#endif + extern "C" { /*! \brief Initialize Openair USRP target. It returns 0 if OK * \param device the hardware to use * \param openair0_cfg RF frontend parameters set by application */ int device_init(openair0_device* device, openair0_config_t *openair0_cfg) { +#if defined(USRP_REC_PLAY) + paramdef_t usrp_recplay_params[7]; + // to check + static int done = 0; + if (done == 1) { + return 0; + } // prevent from multiple init + done = 1; + // end to check + memset(usrp_recplay_params, 0, 7*sizeof(paramdef_t)); + memset(&u_sf_filename[0], 0, 1024); + tmp_filename[0] = u_sf_filename; + if (trx_usrp_recplay_config_init(usrp_recplay_params) != 0) { + std::cerr << "USRP device record/replay mode configuration error exiting" << std::endl; + return -1; + } + config_process_cmdline(usrp_recplay_params,sizeof(usrp_recplay_params)/sizeof(paramdef_t),NULL); + + if (strlen(tmp_filename[0]) != 0) { + (void) strcpy(u_sf_filename, tmp_filename[0]); + } else { + (void) strcpy(u_sf_filename, DEF_SF_FILE); + } + + if (u_sf_replay == 1) u_sf_mode = 2; + if (u_sf_record == 1) u_sf_mode = 1; + + if (u_sf_mode == 2) { + // Replay subframes from from file + int bw_gain_adjust=0; + device->openair0_cfg = openair0_cfg; + device->type = USRP_B200_DEV; + openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38; + bw_gain_adjust=1; + openair0_cfg[0].tx_sample_advance = 80; + openair0_cfg[0].tx_bw = 20e6; + openair0_cfg[0].rx_bw = 20e6; + openair0_cfg[0].iq_txshift = 4;//shift + openair0_cfg[0].iq_rxrescale = 15;//rescale iqs + set_rx_gain_offset(&openair0_cfg[0],0,bw_gain_adjust); + device->priv = NULL; + device->trx_start_func = trx_usrp_start; + device->trx_write_func = trx_usrp_write; + device->trx_read_func = trx_usrp_read; + device->trx_get_stats_func = trx_usrp_get_stats; + device->trx_reset_stats_func = trx_usrp_reset_stats; + device->trx_end_func = trx_usrp_end; + device->trx_stop_func = trx_usrp_stop; + device->trx_set_freq_func = trx_usrp_set_freq; + device->trx_set_gains_func = trx_usrp_set_gains; + device->openair0_cfg = openair0_cfg; + std::cerr << "USRP device initialized in subframes replay mode for " << u_sf_loops << " loops." << std::endl; + } else { +#endif uhd::set_thread_priority_safe(1.0); usrp_state_t *s = (usrp_state_t*)calloc(sizeof(usrp_state_t),1); @@ -705,6 +970,11 @@ extern "C" { int vers=0,subvers=0,subsubvers=0; int bw_gain_adjust=0; +#if defined(USRP_REC_PLAY) + if (u_sf_mode == 1) { + std::cerr << "USRP device initialized in subframes record mode" << std::endl; + } +#endif sscanf(uhd::get_version_string().c_str(),"%d.%d.%d",&vers,&subvers,&subsubvers); LOG_I(PHY,"Checking for USRPs : UHD %s (%d.%d.%d)\n", uhd::get_version_string().c_str(),vers,subvers,subsubvers); @@ -742,7 +1012,9 @@ extern "C" { //s->usrp->set_master_clock_rate(usrp_master_clock); openair0_cfg[0].rx_gain_calib_table = calib_table_x310; - +#if defined(USRP_REC_PLAY) + std::cerr << "-- Using calibration table: calib_table_x310" << std::endl; // Bell Labs info +#endif switch ((int)openair0_cfg[0].sample_rate) { case 30720000: // from usrp_time_offset @@ -801,9 +1073,15 @@ extern "C" { if ((vers == 3) && (subvers == 9) && (subsubvers>=2)) { openair0_cfg[0].rx_gain_calib_table = calib_table_b210; bw_gain_adjust=0; +#if defined(USRP_REC_PLAY) + std::cerr << "-- Using calibration table: calib_table_b210" << std::endl; // Bell Labs info +#endif } else { openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38; bw_gain_adjust=1; +#if defined(USRP_REC_PLAY) + std::cerr << "-- Using calibration table: calib_table_b210_38" << std::endl; // Bell Labs info +#endif } switch ((int)openair0_cfg[0].sample_rate) { @@ -965,6 +1243,45 @@ extern "C" { } } +#if defined(USRP_REC_PLAY) + } +#endif +#if defined(USRP_REC_PLAY) + if (u_sf_mode == 1) { // record mode + ms_sample = (iqrec_t*) malloc(u_sf_max * sizeof(iqrec_t)); + if (ms_sample == NULL) { + std::cerr<< "Memory allocation failed for subframe record or replay mode." << std::endl; + exit(-1); + } + memset(ms_sample, 0, u_sf_max * BELL_LABS_IQ_BYTES_PER_SF); + } + if (u_sf_mode == 2) { + // use mmap + mmapfd = open(u_sf_filename, O_RDONLY | O_LARGEFILE); + if (mmapfd != 0) { + fstat(mmapfd, &sb); + std::cerr << "Loading subframes using mmap() from " << u_sf_filename << " size=" << (uint64_t)sb.st_size << " bytes ..." << std::endl; + ms_sample = (iqrec_t*) mmap(NULL, sb.st_size, PROT_WRITE, MAP_PRIVATE, mmapfd, 0); + if (ms_sample != MAP_FAILED) { + nb_samples = (sb.st_size / sizeof(iqrec_t)); + int aligned = (((unsigned long)ms_sample & 31) == 0)? 1:0; + std::cerr<< "Loaded "<< nb_samples << " subframes." << std::endl; + if (aligned == 0) { + std::cerr<< "mmap address is not 32 bytes aligned, exiting." << std::endl; + close(mmapfd); + exit(-1); + } + } else { + std::cerr << "Cannot mmap file, exiting." << std::endl; + close(mmapfd); + exit(-1); + } + } else { + std::cerr << "Cannot open " << u_sf_filename << " , exiting." << std::endl; + exit(-1); + } + } +#endif return 0; } } diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.h b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.h new file mode 100644 index 0000000000..3863571273 --- /dev/null +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.h @@ -0,0 +1,89 @@ +#ifndef __USRP_LIB_H +#define __USRP_LIB_H +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/** usrp_lib.h + * + * \author: bruno.mongazon-cazavet@nokia-bell-labs.com + */ + +#if defined (USRP_REC_PLAY) + +#include +#include +#include +#include +#include "common/config/config_paramdesc.h" +#include "common/config/config_userapi.h" + +#define BELL_LABS_IQ_HEADER 0xabababababababab +#define BELL_LABS_IQ_PER_SF 7680 // Up to 5MHz bw for now +#define BELL_LABS_IQ_BYTES_PER_SF (BELL_LABS_IQ_PER_SF * 4) +typedef struct { + int64_t header; + int64_t ts; + int64_t rfu1; + int64_t rfu2; // pad for 256 bits alignement required by AVX2 + unsigned char samples[BELL_LABS_IQ_BYTES_PER_SF]; // iq's for one subframe +} iqrec_t; +#define DEF_NB_SF 120000 // default nb of sf or ms to capture (2 minutes at 5MHz) +#define DEF_SF_FILE "/home/nokia/iqfile" // default subframes file name +#define DEF_SF_DELAY_READ 860 // default read delay µs (860=real) +#define DEF_SF_DELAY_WRITE 15 // default write delay µs (15=real) +#define DEF_SF_NB_LOOP 5 // default nb loops + + +/* help strings definition for command line options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */ +#define CONFIG_HLP_SF_FILE "Path of the file used for subframes record or replay" +#define CONFIG_HLP_SF_REC "Record subframes from USRP driver into a file for later replay" +#define CONFIG_HLP_SF_REP "Replay subframes into USRP driver from a file" +#define CONFIG_HLP_SF_MAX "Maximum count of subframes to be recorded in subframe file" +#define CONFIG_HLP_SF_LOOPS "Number of loops to replay of the entire subframes file" +#define CONFIG_HLP_SF_RDELAY "Delay in microseconds to read a subframe in replay mode" +#define CONFIG_HLP_SF_WDELAY "Delay in microseconds to write a subframe in replay mode" + +/* keyword strings for command line options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */ +#define CONFIG_OPT_SF_FILE "subframes-file" +#define CONFIG_OPT_SF_REC "subframes-record" +#define CONFIG_OPT_SF_REP "subframes-replay" +#define CONFIG_OPT_SF_MAX "subframes-max" +#define CONFIG_OPT_SF_LOOPS "subframes-loops" +#define CONFIG_OPT_SF_RDELAY "subframes-read-delay" +#define CONFIG_OPT_SF_WDELAY "subframes-write-delay" + +/* For information only - the macro is not usable in C++ */ +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* command line parameters for USRP record/playback */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define USRP_RECPLAY_PARAMS_DESC { \ +{"subframes-file", CONFIG_HLP_SF_FILE, 0, strptr:(char **)&u_sf_filename, defstrval:DEF_SF_FILE, TYPE_STRING, sizeof(u_sf_filename)}, \ +{"subframes-record", CONFIG_HLP_SF_REC, PARAMFLAG_BOOL, uptr:&u_sf_record, defuintval:0, TYPE_UINT, 0}, \ +{"subframes-replay", CONFIG_HLP_SF_REP, PARAMFLAG_BOOL, uptr:&u_sf_replay, defuintval:0, TYPE_UINT, 0}, \ +{"subframes-max", CONFIG_HLP_SF_MAX, 0, uptr:&u_sf_max, defintval:DEF_NB_SF, TYPE_UINT, 0}, \ +{"subframes-loops", CONFIG_HLP_SF_LOOPS, 0, uptr:&u_sf_loops, defintval:DEF_SF_NB_LOOP, TYPE_UINT, 0}, \ +{"subframes-read-delay", CONFIG_HLP_SF_RDELAY, 0, uptr:&u_sf_read_delay, defintval:DEF_SF_DELAY_READ, TYPE_UINT, 0}, \ +{"subframes-write-delay", CONFIG_HLP_SF_WDELAY, 0, uptr:&u_sf_write_delay, defintval:DEF_SF_DELAY_WRITE, TYPE_UINT, 0}, \ +} +#endif // BELL_LABS_MUST +#endif // __USRP_LIB_H + From e996f5d0f5a83255e3741866dfb991098154ba9b Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Fri, 17 Nov 2017 16:53:58 +0100 Subject: [PATCH 078/284] Add new RAN APIs form SMA app based on the initial eNb config file --- .../ENB_APP/flexran_agent_common_internal.c | 163 +++++++++++++++++- .../ENB_APP/flexran_agent_common_internal.h | 8 +- openair2/ENB_APP/flexran_agent_ran_api.c | 139 ++++++++++++--- openair2/ENB_APP/flexran_agent_ran_api.h | 25 ++- 4 files changed, 303 insertions(+), 32 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c index e735b2748b..fca73894c5 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.c +++ b/openair2/ENB_APP/flexran_agent_common_internal.c @@ -21,8 +21,8 @@ /*! \file flexran_agent_common_internal.c * \brief internal functions for common message primitves and utilities - * \author Xenofon Foukas - * \date 2016 + * \author Xenofon Foukas and N. Nikaein + * \date 2017 * \version 0.1 */ @@ -31,6 +31,7 @@ #include "flexran_agent_common_internal.h" #include "flexran_agent_mac_internal.h" +extern volatile int reconfigure_enb; int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy_length) { @@ -64,7 +65,17 @@ int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy break; case YAML_SCALAR_EVENT: // Check the system name and call the proper handler - if (strcmp((char *) event.data.scalar.value, "mac") == 0) { + // Check the system name and call the proper handler + if (strcmp((char *) event.data.scalar.value, "enb") == 0) { + LOG_I(ENB_APP, "This is intended for the enb system\n"); + // Call the enb handler + if (parse_enb_id(mod_id, &parser) == -1) { + goto error; + } else { // succeful parse and setting + LOG_I(ENB_APP, "Successful parsed config for enb system\n"); + //reconfigure_enb=RECONF_FREQ; + } + } else if (strcmp((char *) event.data.scalar.value, "mac") == 0) { LOG_D(ENB_APP, "This is intended for the mac system\n"); // Call the mac handler if (parse_mac_config(mod_id, &parser) == -1) { @@ -90,8 +101,8 @@ int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy // TODO : Just skip it for now if (skip_system_section(&parser) == -1) { goto error; - } - } else { + } + } else { goto error; } break; @@ -115,6 +126,148 @@ int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy } +int parse_enb_id(mid_t mod_id, yaml_parser_t *parser) { + yaml_event_t event; + + void *param; + char *endptr; + int is_array = 0; + int i = 0; + + int done = 0; + int mapping_started = 0; + + while (!done) { + + if (!yaml_parser_parse(parser, &event)) + goto error; + + switch (event.type) { + // We are expecting a mapping of parameters + case YAML_SEQUENCE_START_EVENT: + is_array = 1; + break; + case YAML_MAPPING_START_EVENT: + LOG_D(ENB_APP, "The mapping of the parameters started\n"); + mapping_started = 1; + break; + case YAML_MAPPING_END_EVENT: + LOG_D(ENB_APP, "The mapping of the parameters ended\n"); + mapping_started = 0; + break; + case YAML_SCALAR_EVENT: + if (!mapping_started) { + goto error; + } + // Check what key needs to be set + // use eNB egistered + if (mac_agent_registered[mod_id]) { + LOG_I(ENB_APP, "Setting parameter for eNB %s\n", event.data.scalar.value); + if (strcmp((char *) event.data.scalar.tag, YAML_INT_TAG) == 0) { // if int + if ((strtol((char *) event.data.scalar.value, &endptr, 10))== mod_id ) { // enb_id == mod_id: right enb instance to be configured + if (parse_enb_config_parameters(mod_id, parser) == -1) { + goto error; + } + } + else{ + goto error; // not the expected type + } + } + } + break; + default: + goto error; + } + + done = (event.type == YAML_MAPPING_END_EVENT); + yaml_event_delete(&event); + } + + return 0; + + error: + yaml_event_delete(&event); + return -1; +} + +int parse_enb_config_parameters(mid_t mod_id, yaml_parser_t *parser) { + yaml_event_t event; + + void *param; + char *endptr; + + int done = 0; + int mapping_started = 0; + + while (!done) { + + if (!yaml_parser_parse(parser, &event)) + goto error; + + switch (event.type) { + // We are expecting a mapping of parameters + case YAML_MAPPING_START_EVENT: + LOG_D(ENB_APP, "The mapping of the parameters started\n"); + mapping_started = 1; + break; + case YAML_MAPPING_END_EVENT: + LOG_D(ENB_APP, "The mapping of the parameters ended\n"); + mapping_started = 0; + break; + case YAML_SCALAR_EVENT: + if (!mapping_started) { + goto error; + } + // Check what key needs to be set + LOG_I(ENB_APP, "Setting parameter %s\n", event.data.scalar.value); + if (strcmp((char *) event.data.scalar.value, "dl_freq") == 0) { + if (!yaml_parser_parse(parser, &event)) + goto error; + flexran_agent_set_operating_dl_freq(mod_id, + 0, + strtol((char *) event.data.scalar.value, &endptr, 10)); + LOG_I(ENB_APP, "Setting parameter value %s\n", event.data.scalar.value); + } else if (strcmp((char *) event.data.scalar.value, "ul_freq_offset") == 0) { + if (!yaml_parser_parse(parser, &event)) + goto error; + flexran_agent_set_operating_ul_freq(mod_id, + 0, + strtol((char *) event.data.scalar.value, &endptr, 10)); + LOG_I(ENB_APP, "Setting parameter value %s\n", event.data.scalar.value); + } else if (strcmp((char *) event.data.scalar.value, "bandwidth") == 0) { + if (!yaml_parser_parse(parser, &event)) + goto error; + flexran_agent_set_operating_bandwidth(mod_id, + 0, + strtol((char *) event.data.scalar.value, &endptr, 10)); + LOG_I(ENB_APP, "Setting parameter value %s\n", event.data.scalar.value); + } else if (strcmp((char *) event.data.scalar.value, "frame_type") == 0) { + if (!yaml_parser_parse(parser, &event)) + goto error; + flexran_agent_set_operating_frame_type (mod_id, + 0, + strtol((char *) event.data.scalar.value, &endptr, 10)); + LOG_I(ENB_APP, "Setting parameter value %s\n", event.data.scalar.value); + }else { // not supported tag + goto error; + } + + break; + default: + goto error; + } + + done = (event.type == YAML_MAPPING_END_EVENT); + yaml_event_delete(&event); + } + + return 0; + + error: + yaml_event_delete(&event); + return -1; +} + int skip_system_section(yaml_parser_t *parser) { yaml_event_t event; diff --git a/openair2/ENB_APP/flexran_agent_common_internal.h b/openair2/ENB_APP/flexran_agent_common_internal.h index c8f78aafe9..2b39025489 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.h +++ b/openair2/ENB_APP/flexran_agent_common_internal.h @@ -21,8 +21,8 @@ /*! \file flexran_agent_common_internal.h * \brief internal agent functions for common message primitves and utilities - * \author Xenofon Foukas - * \date 2016 + * \author Xenofon Foukas and N. Nikaein + * \date 2017 * \version 0.1 */ @@ -37,6 +37,10 @@ int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy int apply_parameter_modification(void *parameter, yaml_parser_t *parser); +int parse_enb_id(mid_t mod_id, yaml_parser_t *parser); +int parse_enb_config_parameters(mid_t mod_id, yaml_parser_t *parser) ; + + // This can be used when parsing for a specific system that is not yet implmeneted // in order to skip its configuration, without affecting the rest int skip_system_section(yaml_parser_t *parser); diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index a22b6cb061..0d3145e1d2 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -21,7 +21,7 @@ /*! \file flexran_agent_ran_api.c * \brief FlexRAN RAN API abstraction - * \author shahab SHARIAT BAGHERI + * \author N. Nikaein, X. Foukas and S. SHARIAT BAGHERI * \date 2017 * \version 0.1 */ @@ -30,7 +30,7 @@ /* - * get generic info from RAN + * generic info from RAN */ @@ -43,9 +43,15 @@ void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran){ switch (ran){ case RAN_LTE_OAI : - enb[mod_id] = (void *)&eNB_mac_inst[mod_id]; - enb_ue[mod_id] = (void *)&eNB_mac_inst[mod_id].UE_list; - enb_rrc[mod_id] = (void *)&eNB_rrc_inst[mod_id]; + if(eNB_mac_inst == NULL){ + enb[mod_id] = NULL; + enb_ue[mod_id] = NULL; + enb_rrc[mod_id] = NULL; + }else{ + enb[mod_id] = (void *)&eNB_mac_inst[mod_id]; + enb_ue[mod_id] = (void *)&eNB_mac_inst[mod_id].UE_list; + enb_rrc[mod_id] = (void *)&eNB_rrc_inst[mod_id]; + } break; default : goto error; @@ -56,9 +62,20 @@ void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran){ error: LOG_E(FLEXRAN_AGENT, "unknown RAN name %d\n", ran); } +static int mac_xface_not_ready(void); + +static int mac_xface_not_ready(void){ + if (mac_xface == NULL) + return 1; + else { + //printf("max_xface %p %d \n", mac_xface, mac_xface->active); + return 0;// !mac_xface->active; + } +} + int flexran_get_current_time_ms (mid_t mod_id, int subframe_flag){ - + if (enb[mod_id] == NULL) return 0; if (subframe_flag == 1){ return ((eNB_MAC_INST *)enb[mod_id])->frame*10 + ((eNB_MAC_INST *)enb[mod_id])->subframe; }else { @@ -68,7 +85,7 @@ int flexran_get_current_time_ms (mid_t mod_id, int subframe_flag){ } unsigned int flexran_get_current_frame (mid_t mod_id) { - + if (enb[mod_id] == NULL) return 0; // #warning "SFN will not be in [0-1023] when oaisim is used" return ((eNB_MAC_INST *)enb[mod_id])->frame; @@ -79,7 +96,7 @@ unsigned int flexran_get_current_system_frame_num(mid_t mod_id) { } unsigned int flexran_get_current_subframe (mid_t mod_id) { - + if (enb[mod_id] == NULL) return 0; return ((eNB_MAC_INST *)enb[mod_id])->subframe; } @@ -125,7 +142,7 @@ uint16_t flexran_get_future_sfn_sf (mid_t mod_id, int ahead_of_time) { } int flexran_get_num_ues (mid_t mod_id){ - + if (enb_ue[mod_id] == NULL) return 0; return ((UE_list_t *)enb_ue[mod_id])->num_UEs; } @@ -135,17 +152,19 @@ int flexran_get_ue_crnti (mid_t mod_id, mid_t ue_id) { } int flexran_get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid) { - + if (enb_ue[mod_id] == NULL) return 0; return ((UE_list_t *)enb_ue[mod_id])->UE_template[UE_PCCID(mod_id,ue_id)][ue_id].bsr_info[lcid]; } int flexran_get_ue_phr (mid_t mod_id, mid_t ue_id) { - + if (enb_ue[mod_id] == NULL) return 0; return ((UE_list_t *)enb_ue[mod_id])->UE_template[UE_PCCID(mod_id,ue_id)][ue_id].phr_info; } int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id) { LTE_eNB_UE_stats *eNB_UE_stats = NULL; + if (mac_xface_not_ready()) return 0 ; + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, 0, UE_RNTI(mod_id, ue_id)); return eNB_UE_stats->DL_cqi[0]; @@ -174,10 +193,11 @@ short flexran_get_TA(mid_t mod_id, mid_t ue_id, int CC_id) { int rnti; rnti = flexran_get_ue_crnti(mod_id, ue_id); + if (mac_xface_not_ready()) return 0 ; LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); //ue_sched_ctl->ta_timer = 20; // wait 20 subframes before taking TA measurement from PHY - switch (PHY_vars_eNB_g[mod_id][CC_id]->frame_parms.N_RB_DL) { + switch (flexran_get_N_RB_DL(mod_id, CC_id)) { case 6: return eNB_UE_stats->timing_advance_update; case 15: @@ -189,7 +209,7 @@ short flexran_get_TA(mid_t mod_id, mid_t ue_id, int CC_id) { case 75: return eNB_UE_stats->timing_advance_update/12; case 100: - if (PHY_vars_eNB_g[mod_id][CC_id]->frame_parms.threequarter_fs == 0) { + if (flexran_get_threequarter_fs(mod_id, CC_id) == 0) { return eNB_UE_stats->timing_advance_update/16; } else { return eNB_UE_stats->timing_advance_update/12; @@ -232,6 +252,8 @@ int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) { // UE_list_t *UE_list = &eNB_mac_inst[mod_id].UE_list; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + if (mac_xface_not_ready()) return 0 ; + LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); if (eNB_UE_stats == NULL) { @@ -247,11 +269,13 @@ int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) { } int flexran_get_active_CC(mid_t mod_id, mid_t ue_id) { + if (enb_ue[mod_id] == NULL) return 0; return ((UE_list_t *)enb_ue[mod_id])->numactiveCCs[ue_id]; } int flexran_get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) { LTE_eNB_UE_stats *eNB_UE_stats = NULL; + if (mac_xface_not_ready()) return 0 ; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); @@ -271,6 +295,7 @@ int flexran_get_tpc(mid_t mod_id, mid_t ue_id) { int pCCid = UE_PCCID(mod_id,ue_id); rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + if (mac_xface_not_ready()) return 0 ; eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, pCCid, rnti); @@ -309,6 +334,7 @@ int flexran_get_harq(const mid_t mod_id, uint8_t harq_pid; uint8_t harq_round; + if (mac_xface_not_ready()) return 0 ; uint16_t rnti = flexran_get_ue_crnti(mod_id,ue_id); if (harq_flag == openair_harq_DL){ @@ -340,7 +366,8 @@ int flexran_get_harq(const mid_t mod_id, int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id) { LTE_eNB_UE_stats *eNB_UE_stats = NULL; uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - + if (mac_xface_not_ready()) return 0 ; + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); if (eNB_UE_stats == NULL) { @@ -355,11 +382,15 @@ int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id) { } int flexran_get_p0_nominal_pucch(mid_t mod_id, int CC_id) { + if (mac_xface_not_ready()) return 0 ; + int32_t pucch_rx_received = mac_xface->get_target_pucch_rx_power(mod_id, CC_id); return pucch_rx_received; } int flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, int CC_id) { + if (mac_xface_not_ready()) return 0 ; + LTE_eNB_UE_stats *eNB_UE_stats = NULL; uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); @@ -368,6 +399,8 @@ int flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, int CC_id) { } int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id) { + if (mac_xface_not_ready()) return 0 ; + LTE_eNB_UE_stats *eNB_UE_stats = NULL; uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); @@ -383,9 +416,18 @@ int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id) { * Get Messages for eNB Configuration Reply * ************************************ */ +int flexran_get_threequarter_fs(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->threequarter_fs; +} + int flexran_get_hopping_offset(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->pusch_config_common.pusch_HoppingOffset; @@ -393,6 +435,7 @@ int flexran_get_hopping_offset(mid_t mod_id, int CC_id) { int flexran_get_hopping_mode(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->pusch_config_common.hoppingMode; @@ -400,6 +443,7 @@ int flexran_get_hopping_mode(mid_t mod_id, int CC_id) { int flexran_get_n_SB(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->pusch_config_common.n_SB; @@ -407,6 +451,7 @@ int flexran_get_n_SB(mid_t mod_id, int CC_id) { int flexran_get_enable64QAM(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->pusch_config_common.enable64QAM; @@ -414,6 +459,7 @@ int flexran_get_enable64QAM(mid_t mod_id, int CC_id) { int flexran_get_phich_duration(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->phich_config_common.phich_duration; @@ -421,6 +467,7 @@ int flexran_get_phich_duration(mid_t mod_id, int CC_id) { int flexran_get_phich_resource(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); if(frame_parms->phich_config_common.phich_resource == oneSixth) @@ -437,6 +484,7 @@ int flexran_get_phich_resource(mid_t mod_id, int CC_id) { int flexran_get_n1pucch_an(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->pucch_config_common.n1PUCCH_AN; @@ -444,6 +492,7 @@ int flexran_get_n1pucch_an(mid_t mod_id, int CC_id) { int flexran_get_nRB_CQI(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->pucch_config_common.nRB_CQI; @@ -451,6 +500,7 @@ int flexran_get_nRB_CQI(mid_t mod_id, int CC_id) { int flexran_get_deltaPUCCH_Shift(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->pucch_config_common.deltaPUCCH_Shift; @@ -458,6 +508,7 @@ int flexran_get_deltaPUCCH_Shift(mid_t mod_id, int CC_id) { int flexran_get_prach_ConfigIndex(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex; @@ -465,6 +516,7 @@ int flexran_get_prach_ConfigIndex(mid_t mod_id, int CC_id) { int flexran_get_prach_FreqOffset(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset; @@ -472,6 +524,7 @@ int flexran_get_prach_FreqOffset(mid_t mod_id, int CC_id) { int flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->maxHARQ_Msg3Tx; @@ -479,6 +532,7 @@ int flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id) { int flexran_get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->Ncp_UL; @@ -486,7 +540,8 @@ int flexran_get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id) { int flexran_get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; - + if (mac_xface_not_ready()) return 0 ; + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->Ncp; } @@ -494,19 +549,23 @@ int flexran_get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id) { int flexran_get_cell_id(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0; + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->Nid_cell; } int flexran_get_srs_BandwidthConfig(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; - + if (mac_xface_not_ready()) return 0 ; + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->soundingrs_ul_config_common.srs_BandwidthConfig; } int flexran_get_srs_SubframeConfig(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->soundingrs_ul_config_common.srs_SubframeConfig; @@ -514,6 +573,7 @@ int flexran_get_srs_SubframeConfig(mid_t mod_id, int CC_id) { int flexran_get_srs_MaxUpPts(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->soundingrs_ul_config_common.srs_MaxUpPts; @@ -521,6 +581,7 @@ int flexran_get_srs_MaxUpPts(mid_t mod_id, int CC_id) { int flexran_get_N_RB_DL(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->N_RB_DL; @@ -528,6 +589,7 @@ int flexran_get_N_RB_DL(mid_t mod_id, int CC_id) { int flexran_get_N_RB_UL(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->N_RB_UL; @@ -535,6 +597,7 @@ int flexran_get_N_RB_UL(mid_t mod_id, int CC_id) { int flexran_get_N_RBG(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->N_RBG; @@ -542,6 +605,7 @@ int flexran_get_N_RBG(mid_t mod_id, int CC_id) { int flexran_get_subframe_assignment(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return frame_parms->tdd_config; @@ -549,9 +613,10 @@ int flexran_get_subframe_assignment(mid_t mod_id, int CC_id) { int flexran_get_special_subframe_assignment(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->tdd_config_S; + return (frame_parms == NULL)? 0:frame_parms->tdd_config_S; } int flexran_get_ra_ResponseWindowSize(mid_t mod_id, int CC_id) { @@ -564,8 +629,10 @@ int flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id) { int flexran_get_duplex_mode(mid_t mod_id, int CC_id) { LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0 ; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + if (frame_parms == NULL) return -1; if(frame_parms->frame_type == TDD) return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD; else if (frame_parms->frame_type == FDD) @@ -671,10 +738,12 @@ int flexran_get_rrc_status(const mid_t mod_id, const rnti_t rntiP){ } int flexran_get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id) { + if (enb_ue[mod_id] == NULL) return 0; return ((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateDL; } int flexran_get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id) { + if (enb_ue[mod_id] == NULL) return 0; return ((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateUL; } @@ -953,19 +1022,19 @@ int flexran_get_antenna_ports(mid_t mod_id, int CC_id){ LTE_DL_FRAME_PARMS *frame_parms; frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->nb_antenna_ports_eNB; + return (frame_parms == NULL)? 0:frame_parms->nb_antenna_ports_eNB; } -float flexran_agent_get_operating_dl_freq (mid_t mod_id, int cc_id) { +uint32_t flexran_agent_get_operating_dl_freq (mid_t mod_id, int cc_id) { const Enb_properties_array_t* enb_properties = enb_config_get(); return (enb_properties->properties[mod_id]->downlink_frequency[cc_id] / 1000000); } -float flexran_agent_get_operating_ul_freq (mid_t mod_id, int cc_id) { +uint32_t flexran_agent_get_operating_ul_freq (mid_t mod_id, int cc_id) { const Enb_properties_array_t* enb_properties = enb_config_get(); - return ((enb_properties->properties[mod_id] ->downlink_frequency[cc_id] + enb_properties->properties[0]->uplink_frequency_offset[cc_id]) / 1000000); + return ((enb_properties->properties[mod_id]->downlink_frequency[cc_id] + enb_properties->properties[0]->uplink_frequency_offset[cc_id]) / 1000000); } int flexran_agent_get_operating_eutra_band (mid_t mod_id, int cc_id) { @@ -981,5 +1050,33 @@ int flexran_agent_get_operating_pusch_p0 (mid_t mod_id, int cc_id) { return enb_properties->properties[mod_id]->pusch_p0_Nominal[cc_id]; } +void flexran_agent_set_operating_dl_freq (mid_t mod_id, int cc_id, uint32_t dl_freq_mhz) { + + Enb_properties_array_t* enb_properties = enb_config_get(); + enb_properties->properties[mod_id]->downlink_frequency[cc_id]=dl_freq_mhz * 1000000; + /*printf("[ENB_APP] mod id %d ccid %d dl freq %d/%d\n", mod_id, cc_id, dl_freq_mhz, enb_properties->properties[mod_id]->downlink_frequency[cc_id]); */ +} + +void flexran_agent_set_operating_ul_freq (mid_t mod_id, int cc_id, int32_t ul_freq_offset_mhz) { + Enb_properties_array_t* enb_properties = enb_config_get(); + enb_properties->properties[mod_id]->uplink_frequency_offset[cc_id]=ul_freq_offset_mhz * 1000000; +} +//TBD +void flexran_agent_set_operating_eutra_band (mid_t mod_id, int cc_id) { + Enb_properties_array_t* enb_properties = enb_config_get(); + enb_properties->properties[mod_id]->eutra_band[cc_id]=7; +} + +void flexran_agent_set_operating_bandwidth (mid_t mod_id, int cc_id, int bandwidth) { + Enb_properties_array_t* enb_properties = enb_config_get(); + enb_properties->properties[mod_id]->N_RB_DL[cc_id]=bandwidth; +} + +void flexran_agent_set_operating_frame_type (mid_t mod_id, int cc_id, int frame_type) { + Enb_properties_array_t* enb_properties = enb_config_get(); + enb_properties->properties[mod_id]->frame_type[cc_id]=frame_type; +} + + diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 33def5e09a..9f0313c1ca 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -21,7 +21,7 @@ /*! \file flexran_agent_ran_api.h * \brief FlexRAN RAN API abstraction header - * \author shahab SHARIAT BAGHERI + * \author N. Nikaein, X. Foukas and S. SHARIAT BAGHERI * \date 2017 * \version 0.1 */ @@ -198,6 +198,8 @@ int flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, int CC_id); int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id); +int flexran_get_threequarter_fs(mid_t mod_id, int CC_id); + int flexran_get_hopping_mode(mid_t mod_id, int CC_id); int flexran_get_hopping_offset(mid_t mod_id, int CC_id); @@ -301,10 +303,10 @@ int flexran_get_lcg(mid_t ue_id, mid_t lc_id); int flexran_get_direction(mid_t ue_id, mid_t lc_id); /*Get downlink frequency*/ -float flexran_agent_get_operating_dl_freq (mid_t mod_id, int cc_id); +uint32_t flexran_agent_get_operating_dl_freq (mid_t mod_id, int cc_id); /*Get uplink frequency*/ -float flexran_agent_get_operating_ul_freq (mid_t mod_id, int cc_id); +uint32_t flexran_agent_get_operating_ul_freq (mid_t mod_id, int cc_id); /*Get eutra band*/ int flexran_agent_get_operating_eutra_band (mid_t mod_id, int cc_id); @@ -315,5 +317,20 @@ int flexran_agent_get_operating_pdsch_refpower (mid_t mod_id, int cc_id); /*Get uplink power*/ int flexran_agent_get_operating_pusch_p0 (mid_t mod_id, int cc_id); +/*set the dl freq */ +void flexran_agent_set_operating_dl_freq (mid_t mod_id, int cc_id, uint32_t dl_freq_mhz); + +/* set the ul freq */ +void flexran_agent_set_operating_ul_freq (mid_t mod_id, int cc_id, int32_t ul_freq_offset_mhz); + +/*set the the band */ +void flexran_agent_set_operating_eutra_band (mid_t mod_id, int cc_id); + +/* set the bandwidth */ +void flexran_agent_set_operating_bandwidth (mid_t mod_id, int cc_id, int bandwidth); + +/*set frame type*/ +void flexran_agent_set_operating_frame_type (mid_t mod_id, int cc_id, int frame_type); + /*RRC status flexRAN*/ -int flexran_get_rrc_status(const mid_t mod_id, const rnti_t rntiP); \ No newline at end of file +int flexran_get_rrc_status(const mid_t mod_id, const rnti_t rntiP); From fb9776d2aa3baade283c72fd4f6e2f07b6f20891 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Fri, 17 Nov 2017 07:55:19 -0800 Subject: [PATCH 079/284] adds config module initialization to oaisim target. --- openair2/ENB_APP/enb_config.c | 4 +++- .../GENERIC-LTE-EPC/CONF/rru.oaisim.conf | 17 +++++++++++++++++ targets/SIMU/USER/oaisim_functions.c | 5 ++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index 9141a85d33..f2f89ad1ca 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -2592,7 +2592,9 @@ void RCConfig(void) { /* get global parameters, defined outside any section in the config file */ - + + printf("Getting ENBSParams\n"); + config_get( ENBSParams,sizeof(ENBSParams)/sizeof(paramdef_t),NULL); RC.nb_inst = ENBSParams[ENB_ACTIVE_ENBS_IDX].numelt; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.oaisim.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.oaisim.conf index af262223f0..24ae36a0a4 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.oaisim.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.oaisim.conf @@ -17,3 +17,20 @@ RUs = ( } ); +log_config = { + global_log_level ="debug"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="debug"; + phy_log_verbosity ="medium"; + mac_log_level ="debug"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; +}; + diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index dce104dc0a..778f250a78 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -782,7 +782,10 @@ void get_simulation_options(int argc, char *argv[]) } } - + if ( load_configmodule(argc,argv) == NULL) { + exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); + } + if (RC.config_file_name != NULL) { /* Read eNB configuration file */ RCConfig(); From bcb6f1715fbbbee19c132d0d92abaded7348c2f0 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Wed, 22 Nov 2017 09:56:43 +0100 Subject: [PATCH 080/284] patch from francois UE config --- common/config/config_cmdline.c | 9 ++++--- common/config/config_userapi.c | 10 +++++++- common/config/config_userapi.h | 1 + common/config/libconfig/config_libconfig.c | 29 +++++++++++++++------- openair2/UTIL/LOG/log.h | 4 +-- targets/RT/USER/lte-softmodem.c | 17 +++++++------ 6 files changed, 48 insertions(+), 22 deletions(-) diff --git a/common/config/config_cmdline.c b/common/config/config_cmdline.c index 42ea7259c3..cb24cc5222 100644 --- a/common/config/config_cmdline.c +++ b/common/config/config_cmdline.c @@ -52,9 +52,12 @@ char defbool[2]="1"; switch(cfgoptions->type) { case TYPE_STRING: - config_check_valptr(cfgoptions, (char **)(cfgoptions->strptr), sizeof(char *)); - config_check_valptr(cfgoptions, cfgoptions->strptr, strlen(tmpval+1)); - sprintf(*(cfgoptions->strptr), "%s",tmpval); + if (cfgoptions->numelt == 0 ) { + config_check_valptr(cfgoptions, cfgoptions->strptr, strlen(tmpval)+1); + sprintf(*(cfgoptions->strptr), "%s",tmpval); + } else { + sprintf( (char *)(cfgoptions->strptr), "%s",tmpval); + } printf_cmdl("[CONFIG] %s set to %s from command line\n", cfgoptions->optname, tmpval); optisset=1; break; diff --git a/common/config/config_userapi.c b/common/config/config_userapi.c index ad2e355d52..37c77be93f 100644 --- a/common/config/config_userapi.c +++ b/common/config/config_userapi.c @@ -50,7 +50,11 @@ configmodule_interface_t *config_get_if(void) char * config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length) { - printf_ptrs("-- %s 0x%08lx %i\n",cfgoptions->optname,(uintptr_t)(*ptr),length); + printf_ptrs("[CONFIG] %s ptr: 0x%08lx requested size: %i\n",cfgoptions->optname,(uintptr_t)(ptr),length); + if(cfgoptions->numelt > 0) { /* already allocated */ + return *ptr; + } + if (*ptr == NULL) { *ptr = malloc(length); if ( *ptr != NULL) { @@ -147,3 +151,7 @@ int config_isparamset(paramdef_t *params,int paramidx) return 0; } } + +int config_getparamval_fromparamdefidx(paramdef_t *cfgoptions,int paramidx) { + +} diff --git a/common/config/config_userapi.h b/common/config/config_userapi.h index 6acaacf716..8c8fc9d2bf 100644 --- a/common/config/config_userapi.h +++ b/common/config/config_userapi.h @@ -51,6 +51,7 @@ extern int config_get(paramdef_t *params,int numparams, char *prefix); extern int config_isparamset(paramdef_t *params,int paramidx); extern void config_assign_int(paramdef_t *cfgoptions, char *fullname, int val); extern int config_process_cmdline(paramdef_t *cfgoptions,int numoptions, char *prefix); +extern int config_getparamval_fromparamdefidx(paramdef_t *cfgoptions,int paramidx); #define config_getlist config_get_if()->getlist #define CONFIG_GETCONFFILE (config_get_if()->cfgP[0]) diff --git a/common/config/libconfig/config_libconfig.c b/common/config/libconfig/config_libconfig.c index 35a70dfcc7..00f5f38b8f 100644 --- a/common/config/libconfig/config_libconfig.c +++ b/common/config/libconfig/config_libconfig.c @@ -104,17 +104,28 @@ int config_libconfig_get(paramdef_t *cfgoptions,int numoptions, char *prefix ) cfgpath,str,cfgoptions[i].numelt); str[strlen(str)-1] = 0; } - config_check_valptr(&(cfgoptions[i]), (char **)(&(cfgoptions[i].strptr)), sizeof(char *)); - config_check_valptr(&(cfgoptions[i]), cfgoptions[i].strptr, strlen(str)+1); - sprintf( *(cfgoptions[i].strptr) , "%s", str); - printf_params("[LIBCONFIG] %s: %s\n", cfgpath,*(cfgoptions[i].strptr) ); + if (cfgoptions[i].numelt == 0 ) { + config_check_valptr(&(cfgoptions[i]), (char **)(&(cfgoptions[i].strptr)), sizeof(char *)); + config_check_valptr(&(cfgoptions[i]), cfgoptions[i].strptr, strlen(str)+1); + sprintf( *(cfgoptions[i].strptr) , "%s", str); + printf_params("[LIBCONFIG] %s: %s\n", cfgpath,*(cfgoptions[i].strptr) ); + } else { + sprintf( (char *)(cfgoptions[i].strptr) , "%s", str); + printf_params("[LIBCONFIG] %s: %s\n", cfgpath,(char *)cfgoptions[i].strptr ); + } } else { if( cfgoptions[i].defstrval != NULL) { defval=1; - config_check_valptr(&(cfgoptions[i]), (char **)(&(cfgoptions[i].strptr)), sizeof(char *)); - config_check_valptr(&(cfgoptions[i]), cfgoptions[i].strptr, strlen(cfgoptions[i].defstrval)+1); - sprintf(*(cfgoptions[i].strptr), "%s",cfgoptions[i].defstrval); - printf_params("[LIBCONFIG] %s set to default value %s\n", cfgpath, *(cfgoptions[i].strptr)); + + if (cfgoptions[i].numelt == 0 ) { + config_check_valptr(&(cfgoptions[i]), (char **)(&(cfgoptions[i].strptr)), sizeof(char *)); + config_check_valptr(&(cfgoptions[i]), cfgoptions[i].strptr, strlen(cfgoptions[i].defstrval)+1); + sprintf(*(cfgoptions[i].strptr), "%s",cfgoptions[i].defstrval); + printf_params("[LIBCONFIG] %s set to default value %s\n", cfgpath, *(cfgoptions[i].strptr)); + } else { + sprintf((char *)(cfgoptions[i].strptr), "%s",cfgoptions[i].defstrval); + printf_params("[LIBCONFIG] %s set to default value %s\n", cfgpath, (char *)cfgoptions[i].strptr); + } } else { notfound=1; } @@ -183,7 +194,7 @@ int config_libconfig_get(paramdef_t *cfgoptions,int numoptions, char *prefix ) read_intarray(&cfgoptions[i],setting,cfgpath); } else { if( cfgoptions[i].defintarrayval != NULL) { - config_check_valptr(&(cfgoptions[i]),(char **)&(cfgoptions[i].iptr), sizeof(int32_t)); + config_check_valptr(&(cfgoptions[i]),(char **)&(cfgoptions[i].iptr), sizeof(int32_t*)); cfgoptions[i].iptr=cfgoptions[i].defintarrayval; defval=1; for (int j=0; jonlinelog), defintval:1, TYPE_INT, 0, }, \ {LOG_CONFIG_STRING_GLOBAL_LOG_INFILE, NULL, 0, iptr:&(g_log->filelog), defintval:0, TYPE_INT, 0, }, \ } diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 3dfa2f5936..e23e50eb4a 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -227,6 +227,9 @@ threads_t threads= {-1,-1,-1,-1,-1,-1,-1}; */ uint8_t abstraction_flag=0; +/* forward declarations */ +void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); + /*---------------------BMC: timespec helpers -----------------------------*/ struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; @@ -609,9 +612,9 @@ static void get_options(void) { if ( (cmdline_uemodeparams[CMDLINE_CALIBUERX_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue; if ( (cmdline_uemodeparams[CMDLINE_CALIBUERXMED_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue_med; if ( (cmdline_uemodeparams[CMDLINE_CALIBUERXBYP_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue_byp; - if ( *(cmdline_uemodeparams[CMDLINE_DEBUGUEPRACH_IDX].uptr) > 0) mode = debug_prach; - if ( *(cmdline_uemodeparams[CMDLINE_NOL2CONNECT_IDX].uptr) > 0) mode = no_L2_connect; - if ( *(cmdline_uemodeparams[CMDLINE_CALIBPRACHTX_IDX].uptr) > 0) mode = calib_prach_tx; + if ( (cmdline_uemodeparams[CMDLINE_DEBUGUEPRACH_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = debug_prach; + if ( (cmdline_uemodeparams[CMDLINE_NOL2CONNECT_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = no_L2_connect; + if ( (cmdline_uemodeparams[CMDLINE_CALIBPRACHTX_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = calib_prach_tx; if (dumpframe > 0) mode = rx_dump_frame; if ( downlink_frequency[0][0] > 0) { @@ -628,7 +631,7 @@ static void get_options(void) { for (CC_id=0; CC_idframe_type = TDD; } - + set_default_frame_parms(frame_parms); if (frame_parms[0]->N_RB_DL !=0) { if ( frame_parms[0]->N_RB_DL < 6 ) { frame_parms[0]->N_RB_DL = 6; @@ -691,7 +694,7 @@ int T_dont_fork = 0; /* default is to fork, see 'T_init' to understand */ #endif -void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); + void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { int CC_id; @@ -905,14 +908,14 @@ int main( int argc, char **argv ) // set default parameters - if (UE_flag == 1) set_default_frame_parms(frame_parms); +// if (UE_flag == 1) set_default_frame_parms(frame_parms); logInit(); printf("Reading in command-line options\n"); get_options (); - if (CONFIG_ISFLAGSET(CONFIG_ABORT)) { + if (CONFIG_ISFLAGSET(CONFIG_ABORT) && UE_flag == 0) { fprintf(stderr,"Getting configuration failed\n"); exit(-1); } From 5f25852693c1a1d86b776c2cb0aafe137345f425 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Wed, 22 Nov 2017 09:58:06 +0100 Subject: [PATCH 081/284] fix UE init sequence --- targets/RT/USER/lte-softmodem.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index e23e50eb4a..993a004fc6 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1133,8 +1133,6 @@ int main( int argc, char **argv ) #if defined(ENABLE_ITTI) - - if ((UE_flag == 1)|| (RC.nb_inst > 0)) { @@ -1152,16 +1150,6 @@ int main( int argc, char **argv ) } #endif - if (phy_test==0) { - if (UE_flag==1) { - printf("Filling UE band info\n"); - fill_ue_band_info(); - dl_phy_sync_success (0, 0, 0, 1); - } - } - - - mlockall(MCL_CURRENT | MCL_FUTURE); @@ -1228,14 +1216,18 @@ int main( int argc, char **argv ) rt_sleep_ns(10*100000000ULL); - - // start the main threads if (UE_flag == 1) { int eMBMS_active = 0; init_UE(1,eMBMS_active,uecap_xer_in); + + if (phy_test==0) { + printf("Filling UE band info\n"); + fill_ue_band_info(); + dl_phy_sync_success (0, 0, 0, 1); + } + number_of_cards = 1; - for(CC_id=0; CC_idrf_map.card=0; PHY_vars_UE_g[0][CC_id]->rf_map.chain=CC_id+chain_offset; From bc54a0d83f2f7db80547896b5bdd3137000da96b Mon Sep 17 00:00:00 2001 From: "Wolfgang A. Mozart" Date: Fri, 10 Nov 2017 09:04:10 +0100 Subject: [PATCH 082/284] making noS1 mode compile --- cmake_targets/CMakeLists.txt | 1 + openair2/RRC/LITE/rrc_eNB.c | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 3dbb61b5ae..4fc2e1ccd3 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1803,6 +1803,7 @@ add_executable(lte-softmodem-nos1 ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c ${OPENAIR_TARGETS}/RT/USER/lte-ue.c ${OPENAIR_TARGETS}/RT/USER/lte-enb.c + ${OPENAIR_TARGETS}/RT/USER/lte-ru.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 28d6982652..c8b42d41b3 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -627,12 +627,12 @@ void rrc_eNB_emulation_notify_ue_module_id( return; } for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - if (RC.rrc[enb_module_id].carrier[CC_id].sib1 != NULL) { + if (&RC.rrc[enb_module_id]->carrier[CC_id].sib1 != NULL) { if ( - (RC.rrc[enb_module_id].carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[0] == cell_identity_byte0P) && - (RC.rrc[enb_module_id].carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[1] == cell_identity_byte1P) && - (RC.rrc[enb_module_id].carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[2] == cell_identity_byte2P) && - (RC.rrc[enb_module_id].carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[3] == cell_identity_byte3P) + (&RC.rrc[enb_module_id]->carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[0] == cell_identity_byte0P) && + (&RC.rrc[enb_module_id]->carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[1] == cell_identity_byte1P) && + (&RC.rrc[enb_module_id]->carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[2] == cell_identity_byte2P) && + (&RC.rrc[enb_module_id]->carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[3] == cell_identity_byte3P) ) { ue_context_p = rrc_eNB_get_ue_context( RC.rrc[enb_module_id], From 27387ee8c2329a25b55b56bddf06c055a80a1bd9 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Wed, 22 Nov 2017 17:50:04 +0100 Subject: [PATCH 083/284] fixing -C option --- targets/RT/USER/lte-softmodem.c | 30 ++++++++++++------------------ targets/RT/USER/lte-ue.c | 1 + 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 993a004fc6..ea4a182ed5 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -599,7 +599,7 @@ static void get_options(void) { paramdef_t cmdline_uemodeparams[] =CMDLINE_UEMODEPARAMS_DESC; paramdef_t cmdline_ueparams[] =CMDLINE_UEPARAMS_DESC; - + set_default_frame_parms(frame_parms); config_process_cmdline( cmdline_uemodeparams,sizeof(cmdline_uemodeparams)/sizeof(paramdef_t),NULL); config_process_cmdline( cmdline_ueparams,sizeof(cmdline_ueparams)/sizeof(paramdef_t),NULL); @@ -618,20 +618,18 @@ static void get_options(void) { if (dumpframe > 0) mode = rx_dump_frame; if ( downlink_frequency[0][0] > 0) { - for (CC_id=1; CC_iddl_CarrierFreq = downlink_frequency[0][0]; + } + UE_scan=0; } if (tddflag > 0) { for (CC_id=0; CC_idframe_type = TDD; } - set_default_frame_parms(frame_parms); + if (frame_parms[0]->N_RB_DL !=0) { if ( frame_parms[0]->N_RB_DL < 6 ) { frame_parms[0]->N_RB_DL = 6; @@ -681,8 +679,9 @@ static void get_options(void) { } else if (UE_flag == 1 && (CONFIG_GETCONFFILE != NULL)) { // Here the configuration file is the XER encoded UE capabilities // Read it in and store in asn1c data structures - strcpy(uecap_xer,CONFIG_GETCONFFILE); - uecap_xer_in=1; + sprintf(uecap_xer,"%stargets/PROJECTS/GENERIC-LTE-EPC/CONF/UE_config.xml",getenv("OPENAIR_HOME")); + printf("%s\n",uecap_xer); + uecap_xer_in=0; } /* UE with config file */ } @@ -731,12 +730,7 @@ void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.highSpeedFlag=0; frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset=0; - downlink_frequency[CC_id][0] = 2680000000; // Use float to avoid issue with frequency over 2^31. - downlink_frequency[CC_id][1] = downlink_frequency[CC_id][0]; - downlink_frequency[CC_id][2] = downlink_frequency[CC_id][0]; - downlink_frequency[CC_id][3] = downlink_frequency[CC_id][0]; - //printf("Downlink for CC_id %d frequency set to %u\n", CC_id, downlink_frequency[CC_id][0]); - + frame_parms[CC_id]->dl_CarrierFreq = 2680000000; } } @@ -908,7 +902,7 @@ int main( int argc, char **argv ) // set default parameters -// if (UE_flag == 1) set_default_frame_parms(frame_parms); + //if (UE_flag == 1) set_default_frame_parms(frame_parms); logInit(); diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index cf0754f63d..913ae958fc 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -303,6 +303,7 @@ static void *UE_thread_synch(void *arg) } while (ind < sizeof(eutra_bands) / sizeof(eutra_bands[0])); if (found == 0) { + LOG_E(PHY,"Can't find EUTRA band for frequency %d",UE->frame_parms.dl_CarrierFreq); exit_fun("Can't find EUTRA band for frequency"); return &UE_thread_synch_retval; } From 28c4c6a47801ea356b44a837c451c5aa4a1b4f27 Mon Sep 17 00:00:00 2001 From: oai Date: Wed, 22 Nov 2017 18:09:42 +0100 Subject: [PATCH 084/284] fix config problems preventing UE to start --- common/config/config_load_configmodule.c | 9 +++++---- common/config/config_load_configmodule.h | 1 + common/config/config_userapi.h | 3 +++ targets/RT/USER/lte-softmodem.c | 15 ++++++++------- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/common/config/config_load_configmodule.c b/common/config/config_load_configmodule.c index 8351d4d82c..ff66d22a1c 100644 --- a/common/config/config_load_configmodule.c +++ b/common/config/config_load_configmodule.c @@ -129,20 +129,21 @@ int i; /* default */ if (cfgparam == NULL) { - cfgparam = "libconfig:oaisoftmodem.conf"; + tmpflags = tmpflags | CONFIG_NOOOPT; + cfgparam = DEFAULT_CFGMODE ":" DEFAULT_CFGFILENAME; } /* parse the config parameters to set the config source */ i = sscanf(cfgparam,"%m[^':']:%ms",&cfgmode,&modeparams); if (i< 0) { fprintf(stderr,"[CONFIG] %s, %d, sscanf error parsing config source %s: %s\n", __FILE__, __LINE__,cfgparam, strerror(errno)); - cfgmode=strdup("libconfig"); - modeparams = strdup("oaisoftmodem.conf"); + cfgmode=strdup(DEFAULT_CFGMODE); + modeparams = strdup(DEFAULT_CFGFILENAME); } else if ( i == 1 ) { /* -O argument doesn't contain ":" separator, assume -O option, default cfgmode to libconfig with one parameter, the path to the configuration file */ modeparams=cfgmode; - cfgmode=strdup("libconfig"); + cfgmode=strdup(DEFAULT_CFGMODE); } cfgptr = malloc(sizeof(configmodule_interface_t)); diff --git a/common/config/config_load_configmodule.h b/common/config/config_load_configmodule.h index 71c642f680..76f074cd6c 100644 --- a/common/config/config_load_configmodule.h +++ b/common/config/config_load_configmodule.h @@ -46,6 +46,7 @@ #define CONFIG_DEBUGCMDLINE 4 // print command line processing messages #define CONFIG_HELP 8 // print help message #define CONFIG_ABORT 16 // config failed,abort execution +#define CONFIG_NOOOPT 32 // no -O option found when parsing command line typedef int(*configmodule_initfunc_t)(char *cfgP[],int numP); diff --git a/common/config/config_userapi.h b/common/config/config_userapi.h index 8c8fc9d2bf..5bbc20a950 100644 --- a/common/config/config_userapi.h +++ b/common/config/config_userapi.h @@ -38,6 +38,9 @@ extern "C" { #endif +#define DEFAULT_CFGFILENAME "oaisoftmodem.conf" +#define DEFAULT_CFGMODE "libconfig" + #define CONFIG_GETSOURCE ( (config_get_if()==NULL) ? NULL : config_get_if()->cfgmode ) #define CONFIG_GETNUMP ( (config_get_if()==NULL) ? 0 : config_get_if()->num_cfgP ) #define CONFIG_GETP(P) ( (config_get_if()==NULL) ? NULL : config_get_if()->cfgP[P] ) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 993a004fc6..28f3d2f25a 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -678,7 +678,7 @@ static void get_options(void) { NB_RU = RC.nb_RU; printf("Configuration: nb_rrc_inst %d, nb_L1_inst %d, nb_ru %d\n",NB_eNB_INST,RC.nb_L1_inst,NB_RU); } - } else if (UE_flag == 1 && (CONFIG_GETCONFFILE != NULL)) { + } else if (UE_flag == 1 && (!(CONFIG_ISFLAGSET(CONFIG_NOOOPT))) ) { // Here the configuration file is the XER encoded UE capabilities // Read it in and store in asn1c data structures strcpy(uecap_xer,CONFIG_GETCONFFILE); @@ -731,12 +731,12 @@ void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.highSpeedFlag=0; frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset=0; - downlink_frequency[CC_id][0] = 2680000000; // Use float to avoid issue with frequency over 2^31. - downlink_frequency[CC_id][1] = downlink_frequency[CC_id][0]; - downlink_frequency[CC_id][2] = downlink_frequency[CC_id][0]; - downlink_frequency[CC_id][3] = downlink_frequency[CC_id][0]; +// downlink_frequency[CC_id][0] = 2680000000; // Use float to avoid issue with frequency over 2^31. +// downlink_frequency[CC_id][1] = downlink_frequency[CC_id][0]; +// downlink_frequency[CC_id][2] = downlink_frequency[CC_id][0]; +// downlink_frequency[CC_id][3] = downlink_frequency[CC_id][0]; //printf("Downlink for CC_id %d frequency set to %u\n", CC_id, downlink_frequency[CC_id][0]); - + frame_parms[CC_id]->dl_CarrierFreq=downlink_frequency[CC_id][0]; } } @@ -1083,8 +1083,9 @@ int main( int argc, char **argv ) else if (frame_parms[CC_id]->N_RB_DL == 25) UE[CC_id]->N_TA_offset = 624/4; } - + init_openair0(); } + } fill_modeled_runtime_table(runtime_phy_rx,runtime_phy_tx); From 1940750a913ae4b47c588938ab2d68dac2638df1 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Thu, 23 Nov 2017 11:30:42 +0100 Subject: [PATCH 085/284] fixing -r option for UE --- targets/RT/USER/lte-softmodem.c | 56 ++++++++++++++++----------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 51b8ef270d..8dd479c9b9 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -632,38 +632,38 @@ static void get_options(void) { frame_parms[CC_id]->frame_type = TDD; } - if (frame_parms[0]->N_RB_DL !=0) { - if ( frame_parms[0]->N_RB_DL < 6 ) { - frame_parms[0]->N_RB_DL = 6; - printf ( "%i: Invalid number of ressource blocks, adjusted to 6\n",frame_parms[0]->N_RB_DL); - } - if ( frame_parms[0]->N_RB_DL > 100 ) { - frame_parms[0]->N_RB_DL = 100; - printf ( "%i: Invalid number of ressource blocks, adjusted to 100\n",frame_parms[0]->N_RB_DL); - } - if ( frame_parms[0]->N_RB_DL > 50 && frame_parms[0]->N_RB_DL < 100 ) { - frame_parms[0]->N_RB_DL = 50; - printf ( "%i: Invalid number of ressource blocks, adjusted to 50\n",frame_parms[0]->N_RB_DL); - } - if ( frame_parms[0]->N_RB_DL > 25 && frame_parms[0]->N_RB_DL < 50 ) { - frame_parms[0]->N_RB_DL = 25; - printf ( "%i: Invalid number of ressource blocks, adjusted to 25\n",frame_parms[0]->N_RB_DL); - } - UE_scan = 0; - frame_parms[0]->N_RB_UL=frame_parms[0]->N_RB_DL; - for (CC_id=0; CC_idN_RB_DL=n_rb_dl; - frame_parms[CC_id]->N_RB_UL=n_rb_dl; - } + if (n_rb_dl !=0) { + printf("NB_RB set to %d\n",frame_parms[0]->N_RB_DL); + if ( n_rb_dl < 6 ) { + n_rb_dl = 6; + printf ( "%i: Invalid number of ressource blocks, adjusted to 6\n",n_rb_dl); + } + if ( n_rb_dl > 100 ) { + n_rb_dl = 100; + printf ( "%i: Invalid number of ressource blocks, adjusted to 100\n",n_rb_dl); + } + if ( n_rb_dl > 50 && n_rb_dl < 100 ) { + n_rb_dl = 50; + printf ( "%i: Invalid number of ressource blocks, adjusted to 50\n",n_rb_dl); + } + if ( n_rb_dl > 25 && n_rb_dl < 50 ) { + n_rb_dl = 25; + printf ( "%i: Invalid number of ressource blocks, adjusted to 25\n",n_rb_dl); + } + UE_scan = 0; + for (CC_id=0; CC_idN_RB_DL=n_rb_dl; + frame_parms[CC_id]->N_RB_UL=n_rb_dl; + } } - - for (CC_id=1;CC_id 0 */ + #if T_TRACER paramdef_t cmdline_ttraceparams[] =CMDLINE_TTRACEPARAMS_DESC ; config_process_cmdline( cmdline_ttraceparams,sizeof(cmdline_ttraceparams)/sizeof(paramdef_t),NULL); From b0d505d2e8492bbee330ba8205758089d07da624 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 27 Nov 2017 11:19:12 +0100 Subject: [PATCH 086/284] bugfix: always cancel Random Access Process Even if the old UE is not found, we have to cancel the random access. --- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 343d391538..421eab7cd7 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -268,6 +268,9 @@ rx_sdu(const module_id_t enb_mod_idP, "[eNB %d] Frame %d, Subframe %d CC_id %d MAC CE_LCID %d (ce %d/%d): CRNTI %x (UE_id %d) in Msg3\n", enb_mod_idP, frameP, subframeP, CC_idP, rx_ces[i], i, num_ce, old_rnti, old_UE_id); + /* receiving CRNTI means that the current rnti has to go away */ + cancel_ra_proc(enb_mod_idP, CC_idP, frameP, + current_rnti); if (old_UE_id != -1) { /* TODO: if the UE did random access (followed by a MAC uplink with * CRNTI) because none of its scheduling request was granted, then @@ -288,9 +291,6 @@ rx_sdu(const module_id_t enb_mod_idP, mac_eNB_rrc_ul_in_sync(enb_mod_idP, CC_idP, frameP, subframeP, old_rnti); } - /* receiving CRNTI means that the current rnti has to go away */ - cancel_ra_proc(enb_mod_idP, CC_idP, frameP, - current_rnti); current_rnti = old_rnti; } crnti_rx = 1; From 4526622b3627a5441ab98352c0de226271daa515 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 27 Nov 2017 16:45:01 +0100 Subject: [PATCH 087/284] bugfix: don't check for physicalConfigDedicated at the wrong places physicalConfigDedicated may be legitimately NULL at some places with the current code. A cleaner solution is needed (we should always have a dedicated config, initialized with values from the 3GPP specs, not have a NULL as we do now). --- openair2/LAYER2/MAC/eNB_scheduler.c | 10 +++++----- openair2/LAYER2/MAC/eNB_scheduler_primitives.c | 13 ++++++++----- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index f7c3f5829d..2c3b88306a 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -352,17 +352,17 @@ schedule_SR(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) ul_req = &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body; + // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet + if (mac_eNB_get_rrc_status + (module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) + continue; + AssertFatal(UE_list-> UE_template[CC_id][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n", UE_id); - // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet - if (mac_eNB_get_rrc_status - (module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) - continue; - if ((SRconfig = UE_list-> UE_template[CC_id][UE_id].physicalConfigDedicated-> diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 42c50d8063..afbb85425e 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -1349,9 +1349,14 @@ fill_nfapi_harq_information(module_id_t module_idP, AssertFatal(UE_id >= 0, "UE_id cannot be found, impossible\n"); AssertFatal(UE_list != NULL, "UE_list is null\n"); +#if 0 + /* TODO: revisit, don't use Assert, it's perfectly possible to + * have physicalConfigDedicated NULL here + */ AssertFatal(UE_list->UE_template[CC_idP][UE_id]. physicalConfigDedicated != NULL, "physicalConfigDedicated for rnti %x is null\n", rntiP); +#endif harq_information->harq_information_rel11.num_ant_ports = 1; @@ -3585,11 +3590,9 @@ extract_harq(module_id_t mod_idP, int CC_idP, int UE_id, uint8_t *pdu; #ifdef Rel14 - AssertFatal(UE_list-> - UE_template[pCCid][UE_id].physicalConfigDedicated-> - pucch_ConfigDedicated != NULL, - "pucch_ConfigDedicated is null!\n"); - if ((UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7) + if (UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated != NULL && + UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->pucch_ConfigDedicated != NULL && + (UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7) && (UE_list->UE_template[pCCid][UE_id]. physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13) && From d81438cd17877c3179f0ec1dbda8296d2eaa7fc4 Mon Sep 17 00:00:00 2001 From: Xu Bo Date: Tue, 28 Nov 2017 11:13:03 +0900 Subject: [PATCH 088/284] merge the implemention of Paging, RRCConnectionRelease, RRCConnectionReestablishment, E-RAB Modify, E-RAB Release --- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 20 +- openair1/PHY/defs.h | 1 + openair1/SCHED/defs.h | 7 + openair1/SCHED/phy_procedures_lte_common.c | 20 + openair2/COMMON/mac_messages_def.h | 2 + openair2/COMMON/mac_messages_types.h | 8 + openair2/COMMON/pdcp_messages_def.h | 1 + openair2/COMMON/pdcp_messages_types.h | 10 + openair2/COMMON/s1ap_messages_def.h | 9 + openair2/COMMON/s1ap_messages_types.h | 130 +- openair2/LAYER2/MAC/defs.h | 18 + openair2/LAYER2/MAC/eNB_scheduler.c | 8 + openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 355 ++++ .../LAYER2/MAC/eNB_scheduler_primitives.c | 30 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 2 + openair2/LAYER2/MAC/extern.h | 2 + openair2/LAYER2/MAC/pre_processor.c | 3 + openair2/LAYER2/MAC/proto.h | 8 + openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 38 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 2 +- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c | 1 + .../RLC/UM_v9.3.0/rlc_um_control_primitives.c | 1 + openair2/LAYER2/openair2_proc.c | 6 + openair2/RRC/LITE/L2_interface.c | 64 +- openair2/RRC/LITE/MESSAGES/asn1_msg.c | 278 +++ openair2/RRC/LITE/MESSAGES/asn1_msg.h | 24 + openair2/RRC/LITE/defs.h | 28 +- openair2/RRC/LITE/extern.h | 5 + openair2/RRC/LITE/proto.h | 20 + openair2/RRC/LITE/rrc_common.c | 7 +- openair2/RRC/LITE/rrc_eNB.c | 1518 ++++++++++++++++- openair2/RRC/LITE/rrc_eNB_GTPV1U.c | 16 +- openair2/RRC/LITE/rrc_eNB_GTPV1U.h | 3 +- openair2/RRC/LITE/rrc_eNB_S1AP.c | 589 ++++++- openair2/RRC/LITE/rrc_eNB_S1AP.h | 56 + openair2/RRC/LITE/rrc_eNB_UE_context.c | 5 + openair2/RRC/LITE/vars.h | 8 + openair3/GTPV1-U/gtpv1u_eNB.c | 41 + openair3/GTPV1-U/gtpv1u_eNB_task.h | 6 +- openair3/S1AP/s1ap_eNB.c | 12 + openair3/S1AP/s1ap_eNB_decoder.c | 44 +- openair3/S1AP/s1ap_eNB_encoder.c | 81 + openair3/S1AP/s1ap_eNB_handlers.c | 400 ++++- openair3/S1AP/s1ap_eNB_nas_procedures.c | 279 +++ openair3/S1AP/s1ap_eNB_nas_procedures.h | 5 + openair3/SECU/kdf.c | 40 + openair3/SECU/secu_defs.h | 4 + targets/RT/USER/lte-softmodem.c | 6 +- 48 files changed, 4136 insertions(+), 85 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index f885bf8eb3..310e783fc5 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -178,9 +178,26 @@ void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch) //ulsch->harq_processes[i]->phich_active = 0; //this will be done later after transmission of PHICH ulsch->harq_processes[i]->phich_ACK = 0; ulsch->harq_processes[i]->round = 0; + ulsch->harq_processes[i]->rar_alloc = 0; + ulsch->harq_processes[i]->first_rb = 0; + ulsch->harq_processes[i]->nb_rb = 0; + ulsch->harq_processes[i]->TBS = 0; + ulsch->harq_processes[i]->Or1 = 0; + ulsch->harq_processes[i]->Or2 = 0; + for ( int j = 0; j < 2; j++ ) { + ulsch->harq_processes[i]->o_RI[j] = 0; + } + ulsch->harq_processes[i]->O_ACK = 0; + ulsch->harq_processes[i]->srs_active = 0; + ulsch->harq_processes[i]->rvidx = 0; + ulsch->harq_processes[i]->Msc_initial = 0; + ulsch->harq_processes[i]->Nsymb_initial = 0; } } - + ulsch->beta_offset_cqi_times8 = 0; + ulsch->beta_offset_ri_times8 = 0; + ulsch->beta_offset_harqack_times8 = 0; + ulsch->Msg3_active = 0; } } @@ -2038,3 +2055,4 @@ uint32_t ulsch_decoding_emul(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, } #endif + diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 24ea961b0e..02bbb2f8bb 100644 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -985,6 +985,7 @@ typedef struct PHY_VARS_eNB_s { LTE_eNB_ULSCH_t *ulsch[NUMBER_OF_UE_MAX+1]; // Nusers + number of RA LTE_eNB_DLSCH_t *dlsch_SI,*dlsch_ra,*dlsch_p; LTE_eNB_DLSCH_t *dlsch_MCH; + LTE_eNB_DLSCH_t *dlsch_PCH; LTE_eNB_UE_stats UE_stats[NUMBER_OF_UE_MAX]; LTE_eNB_UE_stats *UE_stats_ptr[NUMBER_OF_UE_MAX]; diff --git a/openair1/SCHED/defs.h b/openair1/SCHED/defs.h index e29bbf7aad..7fb9e6991d 100644 --- a/openair1/SCHED/defs.h +++ b/openair1/SCHED/defs.h @@ -213,6 +213,13 @@ void prach_procedures(PHY_VARS_eNB *eNB, int br_flag #endif ); + +/*! \brief Function to compute subframe Number(DL and S) as a function of Frame type and TDD Configuration + @param frame_parms Pointer to DL frame parameter descriptor + @returns Subframe Number (DL,S) +*/ +int subframe_num(LTE_DL_FRAME_PARMS *frame_parms); + /*! \brief Function to compute subframe type as a function of Frame type and TDD Configuration (implements Table 4.2.2 from 36.211, p.11 from version 8.6) and subframe index. @param frame_parms Pointer to DL frame parameter descriptor @param subframe Subframe index diff --git a/openair1/SCHED/phy_procedures_lte_common.c b/openair1/SCHED/phy_procedures_lte_common.c index c8675dd814..81146289de 100644 --- a/openair1/SCHED/phy_procedures_lte_common.c +++ b/openair1/SCHED/phy_procedures_lte_common.c @@ -709,6 +709,26 @@ uint16_t get_Np(uint8_t N_RB_DL,uint8_t nCCE,uint8_t plus1) return(Np[0+plus1]); } +int subframe_num(LTE_DL_FRAME_PARMS *frame_parms){ + if (frame_parms->frame_type == FDD) + return 10; + + switch (frame_parms->tdd_config) { + case 1: + return 6; + case 3: + return 7; + case 4: + return 8; + case 5: + return 9; + default: + LOG_E(PHY,"Unsupported TDD configuration %d\n",frame_parms->tdd_config); + AssertFatal(frame_parms->tdd_config==1 || frame_parms->tdd_config==3 || frame_parms->tdd_config==4 || frame_parms->tdd_config==5,"subframe x Unsupported TDD configuration"); + return(255); + } +} + lte_subframe_t subframe_select(LTE_DL_FRAME_PARMS *frame_parms,unsigned char subframe) { diff --git a/openair2/COMMON/mac_messages_def.h b/openair2/COMMON/mac_messages_def.h index c1135a34ae..fcb4543149 100644 --- a/openair2/COMMON/mac_messages_def.h +++ b/openair2/COMMON/mac_messages_def.h @@ -40,3 +40,5 @@ MESSAGE_DEF(RRC_MAC_CCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, RrcMacCcchDat MESSAGE_DEF(RRC_MAC_MCCH_DATA_REQ, MESSAGE_PRIORITY_MED_PLUS, RrcMacMcchDataReq, rrc_mac_mcch_data_req) MESSAGE_DEF(RRC_MAC_MCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, RrcMacMcchDataInd, rrc_mac_mcch_data_ind) + +MESSAGE_DEF(RRC_MAC_PCCH_DATA_REQ, MESSAGE_PRIORITY_MED_PLUS, RrcMacPcchDataReq, rrc_mac_pcch_data_req) diff --git a/openair2/COMMON/mac_messages_types.h b/openair2/COMMON/mac_messages_types.h index 5f27a0fe69..d7fd44f072 100644 --- a/openair2/COMMON/mac_messages_types.h +++ b/openair2/COMMON/mac_messages_types.h @@ -43,11 +43,13 @@ #define RRC_MAC_MCCH_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_mcch_data_req #define RRC_MAC_MCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_mcch_data_ind +#define RRC_MAC_PCCH_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_pcch_data_req // Some constants from "LAYER2/MAC/defs.h" #define BCCH_SDU_SIZE (512) #define CCCH_SDU_SIZE (512) #define MCCH_SDU_SIZE (512) +#define PCCH_SDU_SIZE (512) //-------------------------------------------------------------------------------------------// // Messages between RRC and MAC layers @@ -114,4 +116,10 @@ typedef struct RrcMacMcchDataInd_s { uint8_t mbsfn_sync_area; } RrcMacMcchDataInd; +typedef struct RrcMacPcchDataReq_s { + uint32_t frame; + uint32_t sdu_size; + uint8_t sdu[PCCH_SDU_SIZE]; + uint8_t enb_index; +} RrcMacPcchDataReq; #endif /* MAC_MESSAGES_TYPES_H_ */ diff --git a/openair2/COMMON/pdcp_messages_def.h b/openair2/COMMON/pdcp_messages_def.h index da0d770def..c4be4b2957 100644 --- a/openair2/COMMON/pdcp_messages_def.h +++ b/openair2/COMMON/pdcp_messages_def.h @@ -30,3 +30,4 @@ // Messages between RRC and PDCP layers MESSAGE_DEF(RRC_DCCH_DATA_REQ, MESSAGE_PRIORITY_MED_PLUS, RrcDcchDataReq, rrc_dcch_data_req) MESSAGE_DEF(RRC_DCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, RrcDcchDataInd, rrc_dcch_data_ind) +MESSAGE_DEF(RRC_PCCH_DATA_REQ, MESSAGE_PRIORITY_MED_PLUS, RrcPcchDataReq, rrc_pcch_data_req) diff --git a/openair2/COMMON/pdcp_messages_types.h b/openair2/COMMON/pdcp_messages_types.h index 033e73e86b..c90490b0fd 100644 --- a/openair2/COMMON/pdcp_messages_types.h +++ b/openair2/COMMON/pdcp_messages_types.h @@ -33,6 +33,7 @@ // Defines to access message fields. #define RRC_DCCH_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_dcch_data_req #define RRC_DCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.rrc_dcch_data_ind +#define RRC_PCCH_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_pcch_data_req //-------------------------------------------------------------------------------------------// // Messages between RRC and PDCP layers @@ -60,4 +61,13 @@ typedef struct RrcDcchDataInd_s { uint8_t eNB_index; // LG: needed in UE } RrcDcchDataInd; +typedef struct RrcPcchDataReq_s { + uint32_t sdu_size; + uint8_t *sdu_p; + uint8_t mode; + uint16_t rnti; + uint8_t ue_index; + uint8_t CC_id; +} RrcPcchDataReq; + #endif /* PDCP_MESSAGES_TYPES_H_ */ diff --git a/openair2/COMMON/s1ap_messages_def.h b/openair2/COMMON/s1ap_messages_def.h index d3d853c7e7..a39953d8f7 100644 --- a/openair2/COMMON/s1ap_messages_def.h +++ b/openair2/COMMON/s1ap_messages_def.h @@ -33,6 +33,11 @@ MESSAGE_DEF(S1AP_UE_CONTEXT_RELEASE_COMPLETE_LOG, MESSAGE_PRIORITY_MED, IttiMsgT MESSAGE_DEF(S1AP_UE_CONTEXT_RELEASE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_ue_context_release_log) MESSAGE_DEF(S1AP_E_RAB_SETUP_REQUEST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_e_rab_setup_request_log) MESSAGE_DEF(S1AP_E_RAB_SETUP_RESPONSE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_e_rab_setup_response_log) +MESSAGE_DEF(S1AP_E_RAB_MODIFY_REQUEST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_e_rab_modify_request_log) +MESSAGE_DEF(S1AP_E_RAB_MODIFY_RESPONSE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_e_rab_modify_response_log) +MESSAGE_DEF(S1AP_PAGING_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_paging_log) +MESSAGE_DEF(S1AP_E_RAB_RELEASE_REQUEST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_e_rab_release_request_log) +MESSAGE_DEF(S1AP_E_RAB_RELEASE_RESPONSE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , s1ap_e_rab_release_response_log) /* eNB application layer -> S1AP messages */ MESSAGE_DEF(S1AP_REGISTER_ENB_REQ , MESSAGE_PRIORITY_MED, s1ap_register_enb_req_t , s1ap_register_enb_req) @@ -54,6 +59,8 @@ MESSAGE_DEF(S1AP_UE_CTXT_MODIFICATION_RESP , MESSAGE_PRIORITY_MED, s1ap_ue_ctxt_ MESSAGE_DEF(S1AP_UE_CTXT_MODIFICATION_FAIL , MESSAGE_PRIORITY_MED, s1ap_ue_ctxt_modification_fail_t , s1ap_ue_ctxt_modification_fail) MESSAGE_DEF(S1AP_E_RAB_SETUP_RESP , MESSAGE_PRIORITY_MED, s1ap_e_rab_setup_resp_t , s1ap_e_rab_setup_resp) MESSAGE_DEF(S1AP_E_RAB_SETUP_REQUEST_FAIL , MESSAGE_PRIORITY_MED, s1ap_e_rab_setup_req_fail_t , s1ap_e_rab_setup_request_fail) +MESSAGE_DEF(S1AP_E_RAB_MODIFY_RESP , MESSAGE_PRIORITY_MED, s1ap_e_rab_modify_resp_t , s1ap_e_rab_modify_resp) +MESSAGE_DEF(S1AP_E_RAB_RELEASE_RESPONSE , MESSAGE_PRIORITY_MED, s1ap_e_rab_release_resp_t , s1ap_e_rab_release_resp) /* S1AP -> RRC messages */ MESSAGE_DEF(S1AP_DOWNLINK_NAS , MESSAGE_PRIORITY_MED, s1ap_downlink_nas_t , s1ap_downlink_nas ) @@ -61,6 +68,8 @@ MESSAGE_DEF(S1AP_INITIAL_CONTEXT_SETUP_REQ , MESSAGE_PRIORITY_MED, s1ap_initial_ MESSAGE_DEF(S1AP_UE_CTXT_MODIFICATION_REQ , MESSAGE_PRIORITY_MED, s1ap_ue_ctxt_modification_req_t , s1ap_ue_ctxt_modification_req) MESSAGE_DEF(S1AP_PAGING_IND , MESSAGE_PRIORITY_MED, s1ap_paging_ind_t , s1ap_paging_ind ) MESSAGE_DEF(S1AP_E_RAB_SETUP_REQ , MESSAGE_PRIORITY_MED, s1ap_e_rab_setup_req_t , s1ap_e_rab_setup_req ) +MESSAGE_DEF(S1AP_E_RAB_MODIFY_REQ , MESSAGE_PRIORITY_MED, s1ap_e_rab_modify_req_t , s1ap_e_rab_modify_req ) +MESSAGE_DEF(S1AP_E_RAB_RELEASE_COMMAND , MESSAGE_PRIORITY_MED, s1ap_e_rab_release_command_t , s1ap_e_rab_release_command) MESSAGE_DEF(S1AP_UE_CONTEXT_RELEASE_COMMAND, MESSAGE_PRIORITY_MED, s1ap_ue_release_command_t , s1ap_ue_release_command) /* S1AP <-> RRC messages (can be initiated either by MME or eNB) */ diff --git a/openair2/COMMON/s1ap_messages_types.h b/openair2/COMMON/s1ap_messages_types.h index c17097d4ec..4a5f492b0b 100644 --- a/openair2/COMMON/s1ap_messages_types.h +++ b/openair2/COMMON/s1ap_messages_types.h @@ -41,6 +41,7 @@ #define S1AP_UE_CTXT_MODIFICATION_FAIL(mSGpTR) (mSGpTR)->ittiMsg.s1ap_ue_ctxt_modification_fail #define S1AP_E_RAB_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.s1ap_e_rab_setup_resp #define S1AP_E_RAB_SETUP_FAIL(mSGpTR) (mSGpTR)->ittiMsg.s1ap_e_rab_setup_req_fail +#define S1AP_E_RAB_MODIFY_RESP(mSGpTR) (mSGpTR)->ittiMsg.s1ap_e_rab_modify_resp #define S1AP_DOWNLINK_NAS(mSGpTR) (mSGpTR)->ittiMsg.s1ap_downlink_nas #define S1AP_INITIAL_CONTEXT_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.s1ap_initial_context_setup_req @@ -48,9 +49,12 @@ #define S1AP_UE_CONTEXT_RELEASE_COMMAND(mSGpTR) (mSGpTR)->ittiMsg.s1ap_ue_release_command #define S1AP_UE_CONTEXT_RELEASE_COMPLETE(mSGpTR) (mSGpTR)->ittiMsg.s1ap_ue_release_complete #define S1AP_E_RAB_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.s1ap_e_rab_setup_req -#define S1AP_PAGIND_IND(mSGpTR) (mSGpTR)->ittiMsg.s1ap_paging_ind +#define S1AP_E_RAB_MODIFY_REQ(mSGpTR) (mSGpTR)->ittiMsg.s1ap_e_rab_modify_req +#define S1AP_PAGING_IND(mSGpTR) (mSGpTR)->ittiMsg.s1ap_paging_ind #define S1AP_UE_CONTEXT_RELEASE_REQ(mSGpTR) (mSGpTR)->ittiMsg.s1ap_ue_release_req +#define S1AP_E_RAB_RELEASE_COMMAND(mSGpTR) (mSGpTR)->ittiMsg.s1ap_e_rab_release_command +#define S1AP_E_RAB_RELEASE_RESPONSE(mSGpTR) (mSGpTR)->ittiMsg.s1ap_e_rab_release_resp //-------------------------------------------------------------------------------------------// /* Maximum number of e-rabs to be setup/deleted in a single message. @@ -175,6 +179,11 @@ typedef struct s1ap_gummei_s { uint16_t mme_group_id; } s1ap_gummei_t; +typedef struct s1ap_imsi_s { + uint8_t buffer[S1AP_IMSI_LENGTH]; + uint8_t length; +} s1ap_imsi_t; + typedef struct s_tmsi_s { uint8_t mme_code; uint32_t m_tmsi; @@ -189,7 +198,7 @@ typedef enum ue_paging_identity_presenceMask_e { typedef struct ue_paging_identity_s { ue_paging_identity_presenceMask_t presenceMask; union { - char imsi[S1AP_IMSI_LENGTH]; + s1ap_imsi_t imsi; s_tmsi_t s_tmsi; } choice; } ue_paging_identity_t; @@ -260,11 +269,29 @@ typedef struct e_rab_setup_s { uint32_t gtp_teid; } e_rab_setup_t; +typedef struct e_rab_modify_s { + /* Unique e_rab_id for the UE. */ + uint8_t e_rab_id; +} e_rab_modify_t; + +typedef enum S1ap_Cause_e { + S1AP_CAUSE_NOTHING, /* No components present */ + S1AP_CAUSE_RADIO_NETWORK, + S1AP_CAUSE_TRANSPORT, + S1AP_CAUSE_NAS, + S1AP_CAUSE_PROTOCOL, + S1AP_CAUSE_MISC, + /* Extensions may appear below */ + +} s1ap_Cause_t; + typedef struct e_rab_failed_s { /* Unique e_rab_id for the UE. */ uint8_t e_rab_id; /* Cause of the failure */ // cause_t cause; + s1ap_Cause_t cause; + uint8_t cause_value; } e_rab_failed_t; typedef enum s1ap_ue_ctxt_modification_present_s { @@ -460,6 +487,12 @@ typedef struct s1ap_initial_context_setup_req_s { e_rab_t e_rab_param[S1AP_MAX_E_RAB]; } s1ap_initial_context_setup_req_t; +typedef struct tai_plmn_identity_s { + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_digit_length; +} plmn_identity_t; + typedef struct s1ap_paging_ind_s { /* UE identity index value. * Specified in 3GPP TS 36.304 @@ -472,6 +505,15 @@ typedef struct s1ap_paging_ind_s { /* Indicates origin of paging */ cn_domain_t cn_domain; + /* PLMN_identity in TAI of Paging*/ + plmn_identity_t plmn_identity[256]; + + /* TAC in TAIList of Paging*/ + int16_t tac[256]; + + /* size of TAIList*/ + int16_t tai_size; + /* Optional fields */ paging_drx_t paging_drx; @@ -520,16 +562,6 @@ typedef struct s1ap_ue_release_command_s { //-------------------------------------------------------------------------------------------// -typedef enum S1ap_Cause_e { - S1AP_CAUSE_NOTHING, /* No components present */ - S1AP_CAUSE_RADIO_NETWORK, - S1AP_CAUSE_TRANSPORT, - S1AP_CAUSE_NAS, - S1AP_CAUSE_PROTOCOL, - S1AP_CAUSE_MISC, - /* Extensions may appear below */ - -} s1ap_Cause_t; // S1AP <-- RRC messages typedef struct s1ap_ue_release_req_s { unsigned eNB_ue_s1ap_id:24; @@ -537,4 +569,78 @@ typedef struct s1ap_ue_release_req_s { long cause_value; } s1ap_ue_release_req_t, s1ap_ue_release_resp_t; +typedef struct s1ap_e_rab_modify_req_s { + /* UE id for initial connection to S1AP */ + uint16_t ue_initial_id; + + /* MME UE id */ + uint16_t mme_ue_s1ap_id; + + /* eNB ue s1ap id as initialized by S1AP layer */ + unsigned eNB_ue_s1ap_id:24; + + /* Number of e_rab to be modify in the list */ + uint8_t nb_e_rabs_tomodify; + + /* E RAB modify request */ + e_rab_t e_rab_modify_params[S1AP_MAX_E_RAB]; +} s1ap_e_rab_modify_req_t; + +typedef struct s1ap_e_rab_modify_resp_s { + unsigned eNB_ue_s1ap_id:24; + + /* Number of e_rab modify-ed in the list */ + uint8_t nb_of_e_rabs; + /* list of e_rab modify-ed by RRC layers */ + e_rab_modify_t e_rabs[S1AP_MAX_E_RAB]; + + /* Number of e_rab failed to be modify in list */ + uint8_t nb_of_e_rabs_failed; + /* list of e_rabs that failed to be modify */ + e_rab_failed_t e_rabs_failed[S1AP_MAX_E_RAB]; +} s1ap_e_rab_modify_resp_t; + +typedef struct e_rab_release_s { + /* Unique e_rab_id for the UE. */ + uint8_t e_rab_id; +} e_rab_release_t; + +typedef struct s1ap_e_rab_release_command_s { + /* MME UE id */ + uint16_t mme_ue_s1ap_id; + + /* eNB ue s1ap id as initialized by S1AP layer */ + unsigned eNB_ue_s1ap_id:24; + + /* The NAS PDU should be forwarded by the RRC layer to the NAS layer */ + nas_pdu_t nas_pdu; + + /* Number of e_rab to be released in the list */ + uint8_t nb_e_rabs_torelease; + + /* E RAB release command */ + e_rab_release_t e_rab_release_params[S1AP_MAX_E_RAB]; + +} s1ap_e_rab_release_command_t; + +typedef struct s1ap_e_rab_release_resp_s { + /* MME UE id */ + uint16_t mme_ue_s1ap_id; + + /* eNB ue s1ap id as initialized by S1AP layer */ + unsigned eNB_ue_s1ap_id:24; + + /* Number of e_rab released in the list */ + uint8_t nb_of_e_rabs_released; + + /* list of e_rabs released */ + e_rab_release_t e_rab_release[S1AP_MAX_E_RAB]; + + /* Number of e_rab failed to be released in list */ + uint8_t nb_of_e_rabs_failed; + /* list of e_rabs that failed to be released */ + e_rab_failed_t e_rabs_failed[S1AP_MAX_E_RAB]; + +} s1ap_e_rab_release_resp_t; + #endif /* S1AP_MESSAGES_TYPES_H_ */ diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index ba02a35694..1d1016f64d 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -159,6 +159,8 @@ /*!\brief maximum number of slices / groups */ #define MAX_NUM_SLICES 4 +#define U_PLANE_INACTIVITY_VALUE 6000 + /* * eNB part */ @@ -459,6 +461,15 @@ typedef struct { /// BCCH MCS uint32_t ccch_mcs; + /// num PCCH PDU per CC + uint32_t total_num_pcch_pdu; + /// PCCH buffer size + uint32_t pcch_buffer; + /// total PCCH buffer size + uint32_t total_pcch_buffer; + /// BCCH MCS + uint32_t pcch_mcs; + /// num active users uint16_t num_dlactive_UEs; /// available number of PRBs for a give SF @@ -842,6 +853,7 @@ typedef struct { uint8_t aperiodic_wideband_cqi1[NFAPI_CC_MAX]; uint8_t aperiodic_wideband_pmi1[NFAPI_CC_MAX]; uint8_t dl_cqi[NFAPI_CC_MAX]; + int32_t uplane_inactivity_timer; } UE_sched_ctrl; /*! \brief eNB template for the Random access information */ typedef struct { @@ -990,6 +1002,10 @@ typedef struct { uint32_t BCCH_alloc_pdu; /// Outgoing CCCH pdu for PHY CCCH_PDU CCCH_pdu; + /// Outgoing PCCH DCI allocation + uint32_t PCCH_alloc_pdu; + /// Outgoing PCCH pdu for PHY + PCCH_PDU PCCH_pdu; /// Outgoing RAR pdu for PHY RAR_PDU RAR_pdu; /// Template for RA computations @@ -1105,6 +1121,8 @@ typedef struct eNB_MAC_INST_s { time_stats_t schedule_mch; /// processing time of eNB ULSCH reception time_stats_t rx_ulsch_sdu; // include rlc_data_ind + /// processing time of eNB PCH scheduler + time_stats_t schedule_pch; } eNB_MAC_INST; /* diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 6bcbc13106..bbf153d46d 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -375,6 +375,12 @@ void check_ul_failure(module_id_t module_idP,int CC_id,int UE_id, } } // ul_failure_timer>0 + UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer++; + if(UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer > (U_PLANE_INACTIVITY_VALUE*subframe_num(&RC.eNB[module_idP][CC_id]->frame_parms))){ + LOG_D(MAC,"UE %d rnti %x: U-Plane Failure after repeated PDCCH orders: Triggering RRC \n",UE_id,rnti); + mac_eNB_rrc_uplane_failure(module_idP,CC_id,frameP,subframeP,rnti); + UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0; + }// time > 60s } void clear_nfapi_information(eNB_MAC_INST *eNB,int CC_idP,frame_t frameP,sub_frame_t subframeP) @@ -521,6 +527,8 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, sub_frame if ((subframeP==0) && (frameP&3) == 0) schedule_mib(module_idP,frameP,subframeP); // This schedules SI for legacy LTE and eMTC starting in subframeP schedule_SI(module_idP,frameP,subframeP); + // This schedules Paging in subframeP + schedule_PCH(module_idP,frameP,subframeP); // This schedules Random-Access for legacy LTE and eMTC starting in subframeP schedule_RA(module_idP,frameP,subframeP); // copy previously scheduled UL resources (ULSCH + HARQ) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 3e767ec516..508b9d078e 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -986,6 +986,7 @@ schedule_ue_spec( header_len_dtch_last--; } num_sdus++; + UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0; } // no data for this LCID else { header_len_dtch-=3; @@ -1436,6 +1437,12 @@ get_dlsch_sdu( return((unsigned char *)&eNB->common_channels[CC_id].BCCH_pdu.payload[0]); } + if (rntiP==P_RNTI) { + LOG_D(MAC,"[eNB %d] CC_id %d Frame %d Get PCH sdu for PCCH \n", module_idP, CC_id, frameP); + + return((unsigned char *)&eNB->common_channels[CC_id].PCCH_pdu.payload[0]); + } + UE_id = find_UE_id(module_idP,rntiP); if (UE_id != -1) { @@ -1541,3 +1548,351 @@ void set_ue_dai( break; } } + +void schedule_PCH(module_id_t module_idP,frame_t frameP,sub_frame_t subframeP) +{ + /* DCI:format 1A/1C P-RNTI:0xFFFE */ + /* PDU:eNB_rrc_inst[Mod_idP].common_channels[CC_id].PCCH_pdu.payload */ + uint16_t pcch_sdu_length; + int mcs = -1; + int CC_id; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc; + uint8_t *vrb_map; + int n_rb_dl; + int first_rb = -1; + nfapi_dl_config_request_pdu_t *dl_config_pdu; + nfapi_tx_request_pdu_t *TX_req; + nfapi_dl_config_request_body_t *dl_req; +#ifdef FORMAT1C + int gap_index = 0; /* indicate which gap(1st or 2nd) is used (0:1st) */ + const int GAP_MAP [9][2] = { + {-1, 0}, /* N_RB_DL [6-10] -1: |N_RB/2| 0: N/A*/ + {4, 0}, /* N_RB_DL [11] */ + {8, 0}, /* N_RB_DL [12-19] */ + {12, 0}, /* N_RB_DL [20-26] */ + {18, 0}, /* N_RB_DL [27-44] */ + {27, 0}, /* N_RB_DL [45-49] */ + {27, 9}, /* N_RB_DL [50-63] */ + {32, 16}, /* N_RB_DL [64-79] */ + {48, 16} /* N_RB_DL [80-110] */ + }; + uint8_t n_rb_step = 0; + uint8_t n_gap = 0; + uint8_t n_vrb_dl = 0; + uint8_t Lcrbs = 0; + uint16_t rb_bit = 168; /* RB bit number value is unsure */ + #endif + + start_meas(&eNB->schedule_pch); + + for (CC_id=0; CC_idcommon_channels[CC_id]; + vrb_map = (void*)&cc->vrb_map; + n_rb_dl = to_prb(cc->mib->message.dl_Bandwidth); + dl_req = &eNB->DL_req[CC_id].dl_config_request_body; + for (uint8_t i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (UE_PF_PO[CC_id][i].enable_flag != TRUE) { + continue; + } + if (frameP % UE_PF_PO[CC_id][i].T == UE_PF_PO[CC_id][i].PF_min && subframeP == UE_PF_PO[CC_id][i].PO) { + pcch_sdu_length = mac_rrc_data_req(module_idP, + CC_id, + frameP, + PCCH,1, + &cc->PCCH_pdu.payload[0], + 1, + module_idP, + i); // used for ue index + if (pcch_sdu_length == 0) { + LOG_D(MAC,"[eNB %d] Frame %d subframe %d: PCCH not active(size = 0 byte)\n", module_idP,frameP, subframeP); + continue; + } + LOG_D(MAC,"[eNB %d] Frame %d subframe %d: PCCH->PCH CC_id %d UE_id %d, Received %d bytes \n", module_idP, frameP, subframeP, CC_id,i, pcch_sdu_length); +#ifdef FORMAT1C + //NO SIB + if ((subframeP == 1 || subframeP == 2 || subframeP == 4 || subframeP == 6 || subframeP == 9) || + (subframeP == 5 && ((frameP % 2) != 0 && (frameP % 8) != 1))) { + switch (n_rb_dl) { +#if 0 + case 6: + n_gap = n_rb_dl/2; /* expect: 3 */ + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap));; /* expect: 6 */ + first_rb = 0; + break; + case 15: + n_gap = GAP_MAP[2][0]; /* expect: 8 */ + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 14 */ + first_rb = 6; + break; +#endif + case 25: + n_gap = GAP_MAP[3][0]; /* expect: 12 */ + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 24 */ + first_rb = 10; + break; + case 50: + n_gap = GAP_MAP[6][gap_index]; /* expect: 27 or 9 */ + if (gap_index > 0) { + n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap); /* 36 */ + } else { + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 46 */ + } + first_rb = 24; + break; + case 100: + n_gap = GAP_MAP[8][gap_index]; /* expect: 48 or 16 */ + if (gap_index > 0) { + n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap); /* expect: 96 */ + } else { + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 96 */ + } + first_rb = 48; + break; + } + } else if (subframeP == 5 && ((frameP % 2) == 0 || (frameP % 8) == 1)) { // SIB + paging + switch (n_rb_dl) { +#if 0 + case 6: + n_gap = n_rb_dl/2; /* expect: 3 */ + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap));; /* expect: 6 */ + first_rb = 0; + break; + case 15: + n_gap = GAP_MAP[2][0]; /* expect: 8 */ + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 14 */ + first_rb = 10; + break; +#endif + case 25: + n_gap = GAP_MAP[3][0]; /* expect: 12 */ + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 24 */ + first_rb = 14; + break; + case 50: + n_gap = GAP_MAP[6][gap_index]; /* expect: 27 or 9 */ + if (gap_index > 0) { + n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap); /* 36 */ + } else { + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 46 */ + } + first_rb = 28; + break; + case 100: + n_gap = GAP_MAP[8][gap_index]; /* expect: 48 or 16 */ + if (gap_index > 0) { + n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap); /* expect: 96 */ + } else { + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 96 */ + } + first_rb = 52; + break; + } + } + /* Get MCS for length of PCH */ + if (pcch_sdu_length <= TBStable1C[0]) { + mcs=0; + } else if (pcch_sdu_length <= TBStable1C[1]) { + mcs=1; + } else if (pcch_sdu_length <= TBStable1C[2]) { + mcs=2; + } else if (pcch_sdu_length <= TBStable1C[3]) { + mcs=3; + } else if (pcch_sdu_length <= TBStable1C[4]) { + mcs=4; + } else if (pcch_sdu_length <= TBStable1C[5]) { + mcs=5; + } else if (pcch_sdu_length <= TBStable1C[6]) { + mcs=6; + } else if (pcch_sdu_length <= TBStable1C[7]) { + mcs=7; + } else if (pcch_sdu_length <= TBStable1C[8]) { + mcs=8; + } else if (pcch_sdu_length <= TBStable1C[9]) { + mcs=9; + } else { + /* unexpected: pcch sdb size is over max value*/ + LOG_E(MAC,"[eNB %d] Frame %d : PCCH->PCH CC_id %d, Received %d bytes is over max length(256) \n", + module_idP, frameP,CC_id, pcch_sdu_length); + return; + } + rb_num = TBStable1C[mcs] / rb_bit + ( (TBStable1C[mcs] % rb_bit == 0)? 0: 1) + 1; + /* calculate N_RB_STEP and Lcrbs */ + if (n_rb_dl < 50) { + n_rb_step = 2; + Lcrbs = rb_num / 2 + ((rb_num % 2 == 0) ? 0:2); + } else { + n_rb_step = 4; + Lcrbs = rb_num / 4 + ((rb_num % 4 == 0) ? 0:4); + } + for(i = 0;i < Lcrbs ;i++){ + vrb_map[first_rb+i] = 1; + } +#else + //NO SIB + if ((subframeP == 1 || subframeP == 2 || subframeP == 4 || subframeP == 6 || subframeP == 9) || + (subframeP == 5 && ((frameP % 2) != 0 && (frameP % 8) != 1))) { + switch (n_rb_dl) { + case 25: + first_rb = 10; + break; + case 50: + first_rb = 24; + break; + case 100: + first_rb = 48; + break; + } + } else if (subframeP == 5 && ((frameP % 2) == 0 || (frameP % 8) == 1)) { // SIB + paging + switch (n_rb_dl) { + case 25: + first_rb = 14; + break; + case 50: + first_rb = 28; + break; + case 100: + first_rb = 52; + break; + } + } + + vrb_map[first_rb] = 1; + vrb_map[first_rb+1] = 1; + vrb_map[first_rb+2] = 1; + vrb_map[first_rb+3] = 1; + /* Get MCS for length of PCH */ + if (pcch_sdu_length <= get_TBS_DL(0,3)) { + mcs=0; + } else if (pcch_sdu_length <= get_TBS_DL(1,3)) { + mcs=1; + } else if (pcch_sdu_length <= get_TBS_DL(2,3)) { + mcs=2; + } else if (pcch_sdu_length <= get_TBS_DL(3,3)) { + mcs=3; + } else if (pcch_sdu_length <= get_TBS_DL(4,3)) { + mcs=4; + } else if (pcch_sdu_length <= get_TBS_DL(5,3)) { + mcs=5; + } else if (pcch_sdu_length <= get_TBS_DL(6,3)) { + mcs=6; + } else if (pcch_sdu_length <= get_TBS_DL(7,3)) { + mcs=7; + } else if (pcch_sdu_length <= get_TBS_DL(8,3)) { + mcs=8; + } else if (pcch_sdu_length <= get_TBS_DL(9,3)) { + mcs=9; + } +#endif + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu)); +#ifdef FORMAT1C + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1C; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = getRIV(n_vrb_dl/n_rb_step, first_rb/n_rb_step, Lcrbs/n_rb_step); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.ngap = n_gap; +#else + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // no TPC + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = 1; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = 1; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = getRIV(n_rb_dl,first_rb,4); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0; +#endif + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = 4; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = 0xFFFE; // P-RNTI + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 2; // P-RNTI : see Table 4-10 from SCF082 - nFAPI specifications + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; + + // Rel10 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = 3; + // Rel13 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 0; // regular UE + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not BR + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = 0xFFFF; + + if (!CCE_allocation_infeasible(module_idP, CC_id, 0, subframeP, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, P_RNTI)) { + LOG_D(MAC,"Frame %d: Subframe %d : Adding common DCI for P_RNTI\n", frameP,subframeP); + dl_req->number_dci++; + dl_req->number_pdu++; + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFE; +#ifdef FORMAT1C + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 3; // format 1C + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(n_vrb_dl/n_rb_step, first_rb/n_rb_step, Lcrbs/n_rb_step); +#else + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(n_rb_dl,first_rb,4); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized +#endif + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1;// first block + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB==1 ) ? 0 : 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB==1 ) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; + dl_req->number_pdu++; + + eNB->TX_req[CC_id].sfn_sf = (frameP<<4)+subframeP; + TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; + TX_req->pdu_length = pcch_sdu_length; + TX_req->pdu_index = eNB->pdu_index[CC_id]++; + TX_req->num_segments = 1; + TX_req->segments[0].segment_length = pcch_sdu_length; + TX_req->segments[0].segment_data = cc[CC_id].PCCH_pdu.payload; + eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; + } else { + LOG_E(MAC,"[eNB %d] CCid %d Frame %d, subframe %d : Cannot add DCI 1A/1C for Paging\n",module_idP, CC_id, frameP, subframeP); + continue; + } + + if (opt_enabled == 1) { + trace_pdu(1, + &eNB->common_channels[CC_id].PCCH_pdu.payload[0], + pcch_sdu_length, + 0xffff, + PCCH, + P_RNTI, + eNB->frame, + eNB->subframe, + 0, + 0); + LOG_D(OPT,"[eNB %d][PCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", + module_idP, frameP, CC_id, 0xffff, pcch_sdu_length); + } + eNB->eNB_stats[CC_id].total_num_pcch_pdu+=1; + eNB->eNB_stats[CC_id].pcch_buffer=pcch_sdu_length; + eNB->eNB_stats[CC_id].total_pcch_buffer+=pcch_sdu_length; + eNB->eNB_stats[CC_id].pcch_mcs=mcs; + //paging first_rb log + LOG_D(MAC,"[eNB %d] Frame %d subframe %d PCH: paging_ue_index %d pcch_sdu_length %d mcs %d first_rb %d\n", + module_idP, frameP, subframeP, UE_PF_PO[CC_id][i].ue_index_value, pcch_sdu_length, mcs, first_rb); + + pthread_mutex_lock(&ue_pf_po_mutex); + memset(&UE_PF_PO[CC_id][i], 0, sizeof(UE_PF_PO_t)); + pthread_mutex_unlock(&ue_pf_po_mutex); + } + } + } + /* this might be misleading when pcch is inactive */ + stop_meas(&eNB->schedule_pch); + return; +} diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 19ff3cf39f..8863cf7d52 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -1752,6 +1752,7 @@ int rrc_mac_remove_ue(module_id_t mod_idP,rnti_t rntiP) //------------------------------------------------------------------------------ { int i; + int j; UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; int UE_id = find_UE_id(mod_idP,rntiP); int pCC_id; @@ -1775,7 +1776,7 @@ int rrc_mac_remove_ue(module_id_t mod_idP,rnti_t rntiP) else UE_list->next_ul[prev(UE_list,UE_id,0)]=UE_list->next_ul[UE_id]; // clear all remaining pending transmissions - UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID0] = 0; +/* UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID0] = 0; UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID1] = 0; UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID2] = 0; UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID3] = 0; @@ -1783,11 +1784,37 @@ int rrc_mac_remove_ue(module_id_t mod_idP,rnti_t rntiP) UE_list->UE_template[pCC_id][UE_id].ul_SR = 0; UE_list->UE_template[pCC_id][UE_id].rnti = NOT_A_RNTI; UE_list->UE_template[pCC_id][UE_id].ul_active = FALSE; +*/ + memset (&UE_list->UE_template[pCC_id][UE_id],0,sizeof(UE_TEMPLATE)); + + UE_list->eNB_UE_stats[pCC_id][UE_id].total_rbs_used = 0; + UE_list->eNB_UE_stats[pCC_id][UE_id].total_rbs_used_retx = 0; + for ( j = 0; j < NB_RB_MAX; j++ ) { + UE_list->eNB_UE_stats[pCC_id][UE_id].num_pdu_tx[j] = 0; + UE_list->eNB_UE_stats[pCC_id][UE_id].num_bytes_tx[j] = 0; + } + UE_list->eNB_UE_stats[pCC_id][UE_id].num_retransmission = 0; + UE_list->eNB_UE_stats[pCC_id][UE_id].total_sdu_bytes = 0; + UE_list->eNB_UE_stats[pCC_id][UE_id].total_pdu_bytes = 0; + UE_list->eNB_UE_stats[pCC_id][UE_id].total_num_pdus = 0; + UE_list->eNB_UE_stats[pCC_id][UE_id].total_rbs_used_rx = 0; + for ( j = 0; j < NB_RB_MAX; j++ ) { + UE_list->eNB_UE_stats[pCC_id][UE_id].num_pdu_rx[j] = 0; + UE_list->eNB_UE_stats[pCC_id][UE_id].num_bytes_rx[j] = 0; + } + UE_list->eNB_UE_stats[pCC_id][UE_id].num_errors_rx = 0; + UE_list->eNB_UE_stats[pCC_id][UE_id].total_pdu_bytes_rx = 0; + UE_list->eNB_UE_stats[pCC_id][UE_id].total_num_pdus_rx = 0; + UE_list->eNB_UE_stats[pCC_id][UE_id].total_num_errors_rx = 0; + eNB_ulsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI; eNB_ulsch_info[mod_idP][pCC_id][UE_id].status = S_UL_NONE; eNB_dlsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI; eNB_dlsch_info[mod_idP][pCC_id][UE_id].status = S_DL_NONE; + eNB_ulsch_info[mod_idP][pCC_id][UE_id].serving_num = 0; + eNB_dlsch_info[mod_idP][pCC_id][UE_id].serving_num = 0; + // check if this has an RA process active RA_TEMPLATE *RA_template; for (i=0;itiming_offset=0; RA_template->RRC_timer=20; RA_template->rnti = 0; + RA_template->Msg3_subframe=0; //break; } } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 1fcd07c1d3..1f2ed2fe34 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -552,6 +552,8 @@ void rx_sdu(const module_id_t enb_mod_idP, UE_list->eNB_UE_stats[CC_idP][UE_id].num_pdu_rx[rx_lcids[i]]+=1; UE_list->eNB_UE_stats[CC_idP][UE_id].num_bytes_rx[rx_lcids[i]]+=rx_lengths[i]; + //clear uplane_inactivity_timer + UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0; } else { /* rx_length[i] */ UE_list->eNB_UE_stats[CC_idP][UE_id].num_errors_rx+=1; diff --git a/openair2/LAYER2/MAC/extern.h b/openair2/LAYER2/MAC/extern.h index f192cd7e12..df0519e477 100644 --- a/openair2/LAYER2/MAC/extern.h +++ b/openair2/LAYER2/MAC/extern.h @@ -101,6 +101,8 @@ extern DCI2_5MHz_2A_TDD_t DLSCH_alloc_pdu1; extern DCI2_5MHz_2A_TDD_t DLSCH_alloc_pdu2; extern DCI1E_5MHz_2A_M10PRB_TDD_t DLSCH_alloc_pdu1E; +extern uint16_t reestablish_rnti_map[NUMBER_OF_UE_MAX][2]; + #endif //DEF_H diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 612f64fe61..fdfffd1a59 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -581,6 +581,9 @@ void dlsch_scheduler_pre_processor (module_id_t Mod_id, if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) continue; UE_id = i; +/* harada */ +int harq_pid_ul = (((frameP<<1)+subframeP)&7);//subframe2harqpid(&RC.mac[Mod_id]->common_channels[CC_id],frameP,subframeP); +if( (UE_list->UE_sched_ctrl[UE_id].ul_scheduled & (1<ordered_CCids[ii][UE_id]; diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index b316cbfeeb..f00500e727 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -393,6 +393,14 @@ void set_ue_dai(sub_frame_t subframeP, uint8_t tdd_config, UE_list_t *UE_list); +/** \brief First stage of PCH Scheduling. Gets a PCH SDU from RRC if available and computes the MCS required to transport it as a function of the SDU length. It assumes a length less than or equal to 64 bytes (MCS 6, 3 PRBs). +@param Mod_id Instance ID of eNB +@param frame Frame index +@param subframe Subframe number on which to act +@param paging_ue_index +*/ +void schedule_PCH(module_id_t module_idP,frame_t frameP,sub_frame_t subframeP); + uint8_t find_num_active_UEs_in_cbagroup(module_id_t module_idP, unsigned char group_id); uint8_t UE_is_to_be_scheduled(module_id_t module_idP,int CC_id,uint8_t UE_id); /** \brief Round-robin scheduler for ULSCH traffic. diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index b362e8887a..894abeb100 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -68,6 +68,8 @@ extern int otg_enabled; #endif +#include "common/ran_context.h" +extern RAN_CONTEXT_t RC; //----------------------------------------------------------------------------- /* @@ -948,6 +950,21 @@ pdcp_run ( AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); break; + case RRC_PCCH_DATA_REQ: + { + sdu_size_t sdu_buffer_sizeP; + sdu_buffer_sizeP = RRC_PCCH_DATA_REQ(msg_p).sdu_size; + uint8_t CC_id = RRC_PCCH_DATA_REQ(msg_p).CC_id; + uint8_t ue_index = RRC_PCCH_DATA_REQ(msg_p).ue_index; + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].sizeof_paging[ue_index] = sdu_buffer_sizeP; + if (sdu_buffer_sizeP > 0) { + memcpy(RC.rrc[ctxt_pP->module_id]->carrier[CC_id].paging[ue_index], RRC_PCCH_DATA_REQ(msg_p).sdu_p, sdu_buffer_sizeP); + } + //paging pdcp log + LOG_D(PDCP, "PDCP Received RRC_PCCH_DATA_REQ CC_id %d length %d \n", CC_id, sdu_buffer_sizeP); + } + break; + default: LOG_E(PDCP, "Received unexpected message %s\n", msg_name); break; @@ -1037,6 +1054,13 @@ pdcp_remove_UE( // check and remove SRBs first + for(int i = 0;irnti){ + pdcp_eNB_UE_instance_to_rnti[i] = NOT_A_RNTI; + break; + } + } + for (srb_id=0; srb_id<2; srb_id++) { key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, srb_id, SRB_FLAG_YES); h_rc = hashtable_remove(pdcp_coll_p, key); @@ -1344,7 +1368,7 @@ rrc_pdcp_config_asn1_req ( for (cnt=0; cntlist.count; cnt++) { pdrb_id_p = drb2release_list_pP->list.array[cnt]; drb_id = *pdrb_id_p; - key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, srb_id, SRB_FLAG_NO); + key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, drb_id, SRB_FLAG_NO); h_rc = hashtable_get(pdcp_coll_p, key, (void**)&pdcp_p); if (h_rc != HASH_TABLE_OK) { @@ -1472,7 +1496,17 @@ pdcp_config_req_asn1 ( if (ctxt_pP->enb_flag == ENB_FLAG_YES) { pdcp_pP->is_ue = FALSE; //pdcp_eNB_UE_instance_to_rnti[ctxtP->module_id] = ctxt_pP->rnti; - pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] = ctxt_pP->rnti; +// pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] = ctxt_pP->rnti; + if( srb_flagP == SRB_FLAG_NO ) { + for(int i = 0;irnti; + pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % NUMBER_OF_UE_MAX; + } //pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % NUMBER_OF_UE_MAX; } else { pdcp_pP->is_ue = TRUE; diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index 6dffada99d..452343b967 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -587,7 +587,7 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const ctxt_pP) if (ctxt_cpy.enb_flag) { ctxt.module_id = 0; rab_id = pdcp_read_header_g.rb_id % maxDRB; - ctxt.rnti = pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index]; + ctxt.rnti = pdcp_eNB_UE_instance_to_rnti[pdcp_read_header_g.rb_id / maxDRB]; } else { ctxt.module_id = 0; rab_id = pdcp_read_header_g.rb_id % maxDRB; diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c index faf7763e4f..15dc90f175 100644 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c @@ -125,6 +125,7 @@ rlc_tm_cleanup ( // RX SIDE if ((rlcP->output_sdu_in_construction)) { free_mem_block (rlcP->output_sdu_in_construction, __func__); + rlcP->output_sdu_in_construction = NULL; } memset(rlcP, 0, sizeof(rlc_tm_entity_t)); diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c index 423aca55e9..4e2723a8f4 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c @@ -343,6 +343,7 @@ rlc_um_cleanup ( if ((rlc_pP->output_sdu_in_construction)) { free_mem_block (rlc_pP->output_sdu_in_construction, __func__); + rlc_pP->output_sdu_in_construction = NULL; } if (rlc_pP->dar_buffer) { diff --git a/openair2/LAYER2/openair2_proc.c b/openair2/LAYER2/openair2_proc.c index 7801279be2..a5a8135fed 100644 --- a/openair2/LAYER2/openair2_proc.c +++ b/openair2/LAYER2/openair2_proc.c @@ -131,6 +131,12 @@ int dump_eNB_l2_stats(char *buffer, int length) eNB->eNB_stats[CC_id].bcch_buffer, eNB->eNB_stats[CC_id].total_bcch_buffer, eNB->eNB_stats[CC_id].bcch_mcs); + + len += sprintf(&buffer[len],"PCCH , NB_TX_MAC = %d, transmitted bytes (TTI %d, total %d) MCS (TTI %d)\n", + eNB->eNB_stats[CC_id].total_num_pcch_pdu, + eNB->eNB_stats[CC_id].pcch_buffer, + eNB->eNB_stats[CC_id].total_pcch_buffer, + eNB->eNB_stats[CC_id].pcch_mcs); eNB->eNB_stats[CC_id].dlsch_bitrate=((eNB->eNB_stats[CC_id].dlsch_bytes_tx*8)/((eNB->frame + 1)*10)); eNB->eNB_stats[CC_id].total_dlsch_pdus_tx+=eNB->eNB_stats[CC_id].dlsch_pdus_tx; diff --git a/openair2/RRC/LITE/L2_interface.c b/openair2/RRC/LITE/L2_interface.c index 408e0e8175..1b088f5393 100644 --- a/openair2/RRC/LITE/L2_interface.c +++ b/openair2/RRC/LITE/L2_interface.c @@ -250,6 +250,44 @@ mac_rrc_data_req( return (Sdu_size); } + if( (Srb_id & RAB_OFFSET ) == PCCH) { + LOG_T(RRC,"[eNB %d] Frame %d PCCH request (Srb_id %d)\n",Mod_idP,frameP, Srb_id); + + // check if data is there for MAC + if(RC.rrc[Mod_idP]->carrier[CC_id].sizeof_paging[mbsfn_sync_area] > 0) { //Fill buffer + LOG_D(RRC,"[eNB %d] PCCH (%p) has %d bytes\n",Mod_idP,&RC.rrc[Mod_idP]->carrier[CC_id].paging[mbsfn_sync_area], + RC.rrc[Mod_idP]->carrier[CC_id].sizeof_paging[mbsfn_sync_area]); + +#if 0 //defined(ENABLE_ITTI) + { + MessageDef *message_p; + int pcch_size = RC.rrc[Mod_idP]->arrier[CC_id].sizeof_paging[mbsfn_sync_area]; + int sdu_size = sizeof(RRC_MAC_PCCH_DATA_REQ (message_p).sdu); + + if (pcch_size > sdu_size) { + LOG_E(RRC, "SDU larger than PCCH SDU buffer size (%d, %d)", pcch_size, sdu_size); + pcch_size = sdu_size; + } + + message_p = itti_alloc_new_message (TASK_RRC_ENB, RRC_MAC_PCCH_DATA_REQ); + RRC_MAC_PCCH_DATA_REQ (message_p).frame = frameP; + RRC_MAC_PCCH_DATA_REQ (message_p).sdu_size = pcch_size; + memset (RRC_MAC_PCCH_DATA_REQ (message_p).sdu, 0, PCCH_SDU_SIZE); + memcpy (RRC_MAC_PCCH_DATA_REQ (message_p).sdu, RC.rrc[Mod_idP]->carrier[CC_id].paging[mbsfn_sync_area], pcch_size); + RRC_MAC_PCCH_DATA_REQ (message_p).enb_index = eNB_index; + + itti_send_msg_to_task (TASK_MAC_ENB, ENB_MODULE_ID_TO_INSTANCE(Mod_idP), message_p); + } +#endif + + memcpy(buffer_pP, RC.rrc[Mod_idP]->carrier[CC_id].paging[mbsfn_sync_area], RC.rrc[Mod_idP]->carrier[CC_id].sizeof_paging[mbsfn_sync_area]); + Sdu_size = RC.rrc[Mod_idP]->carrier[CC_id].sizeof_paging[mbsfn_sync_area]; + RC.rrc[Mod_idP]->carrier[CC_id].sizeof_paging[mbsfn_sync_area] = 0; + } + + return (Sdu_size); + } + #if defined(Rel10) || defined(Rel14) if((Srb_id & RAB_OFFSET) == MCCH) { @@ -771,12 +809,34 @@ void mac_eNB_rrc_ul_failure(const module_id_t Mod_instP, if (ue_context_p != NULL) { LOG_I(RRC,"Frame %d, Subframe %d: UE %x UL failure, activating timer\n",frameP,subframeP,rntiP); - ue_context_p->ue_context.ul_failure_timer=1; + if(ue_context_p->ue_context.ul_failure_timer == 0) + ue_context_p->ue_context.ul_failure_timer=1; } else { LOG_W(RRC,"Frame %d, Subframe %d: UL failure: UE %x unknown \n",frameP,subframeP,rntiP); } - rrc_mac_remove_ue(Mod_instP,rntiP); +// rrc_mac_remove_ue(Mod_instP,rntiP); +} + +void mac_eNB_rrc_uplane_failure(const module_id_t Mod_instP, + const int CC_idP, + const frame_t frameP, + const sub_frame_t subframeP, + const rnti_t rntiP) +{ + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + ue_context_p = rrc_eNB_get_ue_context( + RC.rrc[Mod_instP], + rntiP); + if (ue_context_p != NULL) { + LOG_I(RRC,"Frame %d, Subframe %d: UE %x U-Plane failure, activating timer\n",frameP,subframeP,rntiP); + + if(ue_context_p->ue_context.ul_failure_timer == 0) + ue_context_p->ue_context.ul_failure_timer=19999; + } + else { + LOG_W(RRC,"Frame %d, Subframe %d: U-Plane failure: UE %x unknown \n",frameP,subframeP,rntiP); + } } void mac_eNB_rrc_ul_in_sync(const module_id_t Mod_instP, diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index a05b27ddc3..163950950e 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -54,6 +54,8 @@ #include "UL-DCCH-Message.h" #include "DL-CCCH-Message.h" #include "DL-DCCH-Message.h" +#include "PCCH-Message.h" +#include "openair3/UTILS/conversions.h" #include "EstablishmentCause.h" #include "RRCConnectionSetup.h" #include "SRB-ToAddModList.h" @@ -89,6 +91,7 @@ #endif #include "common/ran_context.h" +#include "secu_defs.h" //#include "PHY/defs.h" #ifndef USER_MODE @@ -1964,6 +1967,214 @@ do_RRCConnectionReconfiguration( return((enc_rval.encoded+7)/8); } +//------------------------------------------------------------------------------ +uint8_t +do_RRCConnectionReestablishment( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + int CC_id, + uint8_t* const buffer, + const uint8_t transmission_mode, + const uint8_t Transaction_id, + SRB_ToAddModList_t **SRB_configList, + struct PhysicalConfigDedicated **physicalConfigDedicated) +{ + asn_enc_rval_t enc_rval; + + long* logicalchannelgroup = NULL; + struct SRB_ToAddMod* SRB1_config = NULL; + struct SRB_ToAddMod* SRB2_config = NULL; + struct SRB_ToAddMod__rlc_Config* SRB1_rlc_config = NULL; + struct SRB_ToAddMod__logicalChannelConfig* SRB1_lchan_config = NULL; + struct LogicalChannelConfig__ul_SpecificParameters* SRB1_ul_SpecificParameters = NULL; + eNB_RRC_INST *rrc = RC.rrc[ctxt_pP->module_id]; + +#ifdef CBA + struct PUSCH_CBAConfigDedicated_vlola* pusch_CBAConfigDedicated_vlola = NULL; + long* betaOffset_CBA_Index = NULL; + long* cShift_CBA = NULL; +#endif + PhysicalConfigDedicated_t* physicalConfigDedicated2 = NULL; + + DL_CCCH_Message_t dl_ccch_msg; + + RRCConnectionReestablishment_t* rrcConnectionReestablishment = NULL; + + int i = 0; + SRB_ToAddModList_t **SRB_configList2 = NULL; + SRB_configList2 = &ue_context_pP->ue_context.SRB_configList2[Transaction_id]; + if (*SRB_configList2) { + free(*SRB_configList2); + } + *SRB_configList2 = CALLOC(1, sizeof(SRB_ToAddModList_t)); + + memset((void *)&dl_ccch_msg, 0, sizeof(DL_CCCH_Message_t)); + dl_ccch_msg.message.present = DL_CCCH_MessageType_PR_c1; + dl_ccch_msg.message.choice.c1.present = DL_CCCH_MessageType__c1_PR_rrcConnectionReestablishment; + rrcConnectionReestablishment = &dl_ccch_msg.message.choice.c1.choice.rrcConnectionReestablishment; + + // RRCConnectionReestablishment + // Configure SRB1 + + + // get old configuration of SRB2 + if (*SRB_configList != NULL) { + for (i = 0; (i < (*SRB_configList)->list.count) && (i < 3); i++) { + LOG_D(RRC, "(*SRB_configList)->list.array[%d]->srb_Identity=%ld\n", + i, (*SRB_configList)->list.array[i]->srb_Identity); + if ((*SRB_configList)->list.array[i]->srb_Identity == 2 ){ + SRB2_config = (*SRB_configList)->list.array[i]; + } else if ((*SRB_configList)->list.array[i]->srb_Identity == 1 ){ + SRB1_config = (*SRB_configList)->list.array[i]; + } + } + } + + if (SRB1_config == NULL) { + // default SRB1 configuration + LOG_W(RRC,"SRB1 configuration does not exist in SRB configuration list, use default\n"); + /// SRB1 + SRB1_config = CALLOC(1, sizeof(*SRB1_config)); + + SRB1_config->srb_Identity = 1; + SRB1_rlc_config = CALLOC(1, sizeof(*SRB1_rlc_config)); + SRB1_config->rlc_Config = SRB1_rlc_config; + + SRB1_rlc_config->present = SRB_ToAddMod__rlc_Config_PR_explicitValue; + SRB1_rlc_config->choice.explicitValue.present=RLC_Config_PR_am; + #if defined(ENABLE_ITTI) + SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.t_PollRetransmit = rrc->srb1_timer_poll_retransmit; + SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollPDU = rrc->srb1_poll_pdu; + SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollByte = rrc->srb1_poll_byte; + SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.maxRetxThreshold = rrc->srb1_max_retx_threshold; + SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_Reordering = rrc->srb1_timer_reordering; + SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_StatusProhibit = rrc->srb1_timer_status_prohibit; + #else + SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.t_PollRetransmit = T_PollRetransmit_ms20;; + SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollPDU = PollPDU_p4;; + SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollByte = PollByte_kBinfinity; + SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.maxRetxThreshold = UL_AM_RLC__maxRetxThreshold_t8; + SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_Reordering = T_Reordering_ms35; + SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_StatusProhibit = T_StatusProhibit_ms0; + #endif + + SRB1_lchan_config = CALLOC(1, sizeof(*SRB1_lchan_config)); + SRB1_config->logicalChannelConfig = SRB1_lchan_config; + + SRB1_lchan_config->present = SRB_ToAddMod__logicalChannelConfig_PR_explicitValue; + SRB1_ul_SpecificParameters = CALLOC(1, sizeof(*SRB1_ul_SpecificParameters)); + + SRB1_lchan_config->choice.explicitValue.ul_SpecificParameters = SRB1_ul_SpecificParameters; + SRB1_ul_SpecificParameters->priority = 1; + + //assign_enum(&SRB1_ul_SpecificParameters->prioritisedBitRate,LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity); + SRB1_ul_SpecificParameters->prioritisedBitRate=LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity; + + //assign_enum(&SRB1_ul_SpecificParameters->bucketSizeDuration,LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50); + SRB1_ul_SpecificParameters->bucketSizeDuration=LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50; + + logicalchannelgroup = CALLOC(1, sizeof(long)); + *logicalchannelgroup = 0; + SRB1_ul_SpecificParameters->logicalChannelGroup = logicalchannelgroup; + } + + if (SRB2_config == NULL) { + LOG_W(RRC,"SRB2 configuration does not exist in SRB configuration list\n"); + } else { + ASN_SEQUENCE_ADD(&(*SRB_configList2)->list, SRB2_config); + } + + if (*SRB_configList) { + free(*SRB_configList); + } + + *SRB_configList = CALLOC(1, sizeof(SRB_ToAddModList_t)); + + ASN_SEQUENCE_ADD(&(*SRB_configList)->list,SRB1_config); + + physicalConfigDedicated2 = *physicalConfigDedicated; + + rrcConnectionReestablishment->rrc_TransactionIdentifier = Transaction_id; + rrcConnectionReestablishment->criticalExtensions.present = RRCConnectionReestablishment__criticalExtensions_PR_c1; + rrcConnectionReestablishment->criticalExtensions.choice.c1.present = RRCConnectionReestablishment__criticalExtensions__c1_PR_rrcConnectionReestablishment_r8; + rrcConnectionReestablishment->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r8.radioResourceConfigDedicated.srb_ToAddModList = *SRB_configList; + rrcConnectionReestablishment->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r8.radioResourceConfigDedicated.drb_ToAddModList = NULL; + rrcConnectionReestablishment->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r8.radioResourceConfigDedicated.drb_ToReleaseList = NULL; + rrcConnectionReestablishment->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r8.radioResourceConfigDedicated.sps_Config = NULL; + rrcConnectionReestablishment->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r8.radioResourceConfigDedicated.physicalConfigDedicated = physicalConfigDedicated2; + rrcConnectionReestablishment->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r8.radioResourceConfigDedicated.mac_MainConfig = NULL; + + uint8_t KeNB_star[32] = { 0 }; + uint16_t pci = rrc->carrier[CC_id].physCellId; + uint32_t earfcn_dl = (uint32_t)freq_to_arfcn10(RC.mac[ctxt_pP->module_id]->common_channels[CC_id].eutra_band, + rrc->carrier[CC_id].dl_CarrierFreq); + bool is_rel8_only = true; + if (earfcn_dl > 65535) { + is_rel8_only = false; + } + + LOG_D(RRC, "pci=%d, eutra_band=%d, downlink_frequency=%d, earfcn_dl=%u, is_rel8_only=%s\n", + pci, + RC.mac[ctxt_pP->module_id]->common_channels[CC_id].eutra_band, + rrc->carrier[CC_id].dl_CarrierFreq, + earfcn_dl, + is_rel8_only == true ? "true": "false"); +#if defined(ENABLE_SECURITY) + if (ue_context_pP->ue_context.nh_ncc >= 0) { + derive_keNB_star(ue_context_pP->ue_context.nh, pci, earfcn_dl, is_rel8_only, KeNB_star); + rrcConnectionReestablishment->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r8.nextHopChainingCount = ue_context_pP->ue_context.nh_ncc; + } else { // first HO + derive_keNB_star (ue_context_pP->ue_context.kenb, pci, earfcn_dl, is_rel8_only, KeNB_star); + // LG: really 1 + rrcConnectionReestablishment->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r8.nextHopChainingCount = 0; + } + + // copy KeNB_star to ue_context_pP->ue_context.kenb + memcpy (ue_context_pP->ue_context.kenb, KeNB_star, 32); + ue_context_pP->ue_context.kenb_ncc = 0; +#else + rrcConnectionReestablishment->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r8.nextHopChainingCount = 0; +#endif + + rrcConnectionReestablishment->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r8.nonCriticalExtension = NULL; + +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_DL_CCCH_Message, (void*)&dl_ccch_msg); +#endif + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_CCCH_Message, + (void*)&dl_ccch_msg, + buffer, + 100); + AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + +#if defined(ENABLE_ITTI) +# if !defined(DISABLE_XER_SPRINT) + { + char message_string[20000]; + size_t message_string_size; + + if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_DL_CCCH_Message, (void *) &dl_ccch_msg)) > 0) { + MessageDef *msg_p; + + msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB, RRC_DL_CCCH, message_string_size + sizeof (IttiMsgText)); + msg_p->ittiMsg.rrc_dl_ccch.size = message_string_size; + memcpy(&msg_p->ittiMsg.rrc_dl_ccch.text, message_string, message_string_size); + + itti_send_msg_to_task(TASK_UNKNOWN, ctxt_pP->instance, msg_p); + } + } +# endif +#endif + +#ifdef USER_MODE + LOG_D(RRC,"RRCConnectionReestablishment Encoded %zd bits (%zd bytes)\n", + enc_rval.encoded,(enc_rval.encoded+7)/8); +#endif + + return((enc_rval.encoded+7)/8); +} + //------------------------------------------------------------------------------ uint8_t do_RRCConnectionReestablishmentReject( @@ -2451,6 +2662,73 @@ uint8_t do_DLInformationTransfer(uint8_t Mod_id, uint8_t **buffer, uint8_t trans return encoded; } +uint8_t do_Paging(uint8_t Mod_id, uint8_t *buffer, ue_paging_identity_t ue_paging_identity, cn_domain_t cn_domain) +{ + LOG_D(RRC, "[eNB %d] do_Paging start\n", Mod_id); + asn_enc_rval_t enc_rval; + + PCCH_Message_t pcch_msg; + PagingRecord_t *paging_record_p; + int j; + + pcch_msg.message.present = PCCH_MessageType_PR_c1; + pcch_msg.message.choice.c1.present = PCCH_MessageType__c1_PR_paging; + + pcch_msg.message.choice.c1.choice.paging.pagingRecordList = CALLOC(1,sizeof(*pcch_msg.message.choice.c1.choice.paging.pagingRecordList)); + + pcch_msg.message.choice.c1.choice.paging.systemInfoModification = NULL; + pcch_msg.message.choice.c1.choice.paging.etws_Indication = NULL; + pcch_msg.message.choice.c1.choice.paging.nonCriticalExtension = NULL; + + asn_set_empty(&pcch_msg.message.choice.c1.choice.paging.pagingRecordList->list); + pcch_msg.message.choice.c1.choice.paging.pagingRecordList->list.count = 0; + + if ((paging_record_p = calloc(1, sizeof(PagingRecord_t))) == NULL) { + /* Possible error on calloc */ + return (-1); + } + + memset(paging_record_p, 0, sizeof(PagingRecord_t)); + + /* convert ue_paging_identity_t to PagingUE_Identity_t */ + if (ue_paging_identity.presenceMask == UE_PAGING_IDENTITY_s_tmsi) { + paging_record_p->ue_Identity.present = PagingUE_Identity_PR_s_TMSI; + MME_CODE_TO_OCTET_STRING(ue_paging_identity.choice.s_tmsi.mme_code, + &paging_record_p->ue_Identity.choice.s_TMSI.mmec); + paging_record_p->ue_Identity.choice.s_TMSI.mmec.bits_unused = 0; + M_TMSI_TO_OCTET_STRING(ue_paging_identity.choice.s_tmsi.m_tmsi, + &paging_record_p->ue_Identity.choice.s_TMSI.m_TMSI); + paging_record_p->ue_Identity.choice.s_TMSI.m_TMSI.bits_unused = 0; + } else if (ue_paging_identity.presenceMask == UE_PAGING_IDENTITY_imsi) { + IMSI_Digit_t imsi_digit[21]; + for (j = 0; j< ue_paging_identity.choice.imsi.length; j++) { /* IMSI size */ + imsi_digit[j] = (IMSI_Digit_t)ue_paging_identity.choice.imsi.buffer[j]; + ASN_SEQUENCE_ADD(&paging_record_p->ue_Identity.choice.imsi.list, &imsi_digit[j]); + } + } + + /* set cn_domain */ + if (cn_domain == CN_DOMAIN_PS) { + paging_record_p->cn_Domain = PagingRecord__cn_Domain_ps; + } else { + paging_record_p->cn_Domain = PagingRecord__cn_Domain_cs; + } + /* add to list */ + ASN_SEQUENCE_ADD(&pcch_msg.message.choice.c1.choice.paging.pagingRecordList->list, paging_record_p); + LOG_D(RRC, "[eNB %d] do_Paging paging_record: cn_Domain %ld, ue_paging_identity.presenceMask %d, PagingRecordList.count %d\n", + Mod_id, paging_record_p->cn_Domain, ue_paging_identity.presenceMask, pcch_msg.message.choice.c1.choice.paging.pagingRecordList->list.count); + + enc_rval = uper_encode_to_buffer(&asn_DEF_PCCH_Message, (void*)&pcch_msg, buffer, RRC_BUF_SIZE); + + AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_PCCH_Message, (void*)&pcch_msg); +#endif + + return((enc_rval.encoded+7)/8); +} + uint8_t do_ULInformationTransfer(uint8_t **buffer, uint32_t pdu_length, uint8_t *pdu_buffer) { ssize_t encoded; diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.h b/openair2/RRC/LITE/MESSAGES/asn1_msg.h index 6241e2963f..270d9bc58f 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.h +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.h @@ -195,6 +195,28 @@ do_RRCConnectionReconfiguration( , SCellToAddMod_r10_t *SCell_config #endif ); +/** +\brief Generate an RRCConnectionReestablishment DL-CCCH-Message (eNB). This routine configures SRB_ToAddMod (SRB1/SRB2) and +PhysicalConfigDedicated IEs. The latter does not enable periodic CQI reporting (PUCCH format 2/2a/2b) or SRS. +@param ctxt_pP Running context +@param ue_context_pP UE context +@param CC_id Component Carrier ID +@param buffer Pointer to PER-encoded ASN.1 description of DL-CCCH-Message PDU +@param transmission_mode Transmission mode for UE (1-9) +@param Transaction_id Transaction_ID for this message +@param SRB_configList Pointer (returned) to SRB1_config/SRB2_config(later) IEs for this UE +@param physicalConfigDedicated Pointer (returned) to PhysicalConfigDedicated IE for this UE +@returns Size of encoded bit stream in bytes*/ +uint8_t +do_RRCConnectionReestablishment( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + int CC_id, + uint8_t* const buffer, + const uint8_t transmission_mode, + const uint8_t Transaction_id, + SRB_ToAddModList_t **SRB_configList, + struct PhysicalConfigDedicated **physicalConfigDedicated); /** \brief Generate an RRCConnectionReestablishmentReject DL-CCCH-Message (eNB). @@ -249,6 +271,8 @@ uint8_t do_MeasurementReport(uint8_t Mod_id, uint8_t *buffer,int measid,int phy_ uint8_t do_DLInformationTransfer(uint8_t Mod_id, uint8_t **buffer, uint8_t transaction_id, uint32_t pdu_length, uint8_t *pdu_buffer); +uint8_t do_Paging(uint8_t Mod_id, uint8_t *buffer, ue_paging_identity_t ue_paging_identity, cn_domain_t cn_domain); + uint8_t do_ULInformationTransfer(uint8_t **buffer, uint32_t pdu_length, uint8_t *pdu_buffer); OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer); diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index 0811818c72..0aaa6d1869 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -292,12 +292,15 @@ typedef enum e_rab_satus_e { E_RAB_STATUS_DONE, // from the eNB perspective E_RAB_STATUS_ESTABLISHED, // get the reconfigurationcomplete form UE E_RAB_STATUS_FAILED, + E_RAB_STATUS_TORELEASE // to release DRB between eNB and UE } e_rab_status_t; typedef struct e_rab_param_s { e_rab_t param; uint8_t status; uint8_t xid; // transaction_id + s1ap_Cause_t cause; + uint8_t cause_value; } __attribute__ ((__packed__)) e_rab_param_t; #endif @@ -375,6 +378,7 @@ typedef struct eNB_RRC_UE_s { SRB_ToAddModList_t* SRB_configList2[RRC_TRANSACTION_IDENTIFIER_NUMBER]; DRB_ToAddModList_t* DRB_configList; DRB_ToAddModList_t* DRB_configList2[RRC_TRANSACTION_IDENTIFIER_NUMBER]; + DRB_ToReleaseList_t* DRB_Release_configList2[RRC_TRANSACTION_IDENTIFIER_NUMBER]; uint8_t DRB_active[8]; struct PhysicalConfigDedicated* physicalConfigDedicated; struct SPS_Config* sps_Config; @@ -394,6 +398,9 @@ typedef struct eNB_RRC_UE_s { #if defined(ENABLE_SECURITY) /* KeNB as derived from KASME received from EPC */ uint8_t kenb[32]; + int8_t kenb_ncc; + uint8_t nh[32]; + int8_t nh_ncc; #endif /* Used integrity/ciphering algorithms */ CipheringAlgorithm_r12_t ciphering_algorithm; @@ -423,9 +430,15 @@ typedef struct eNB_RRC_UE_s { uint8_t setup_e_rabs; /* Number of e_rab to be setup in the list */ uint8_t nb_of_e_rabs; + /* Number of e_rab to be modified in the list */ + uint8_t nb_of_modify_e_rabs; + uint8_t nb_of_failed_e_rabs; + e_rab_param_t modify_e_rab[NB_RB_MAX];//[S1AP_MAX_E_RAB]; /* list of e_rab to be setup by RRC layers */ e_rab_param_t e_rab[NB_RB_MAX];//[S1AP_MAX_E_RAB]; - + //release e_rabs + uint8_t nb_release_of_e_rabs; + e_rab_failed_t e_rabs_release_failed[S1AP_MAX_E_RAB]; // LG: For GTPV1 TUNNELS uint32_t enb_gtp_teid[S1AP_MAX_E_RAB]; transport_layer_addr_t enb_gtp_addrs[S1AP_MAX_E_RAB]; @@ -434,6 +447,7 @@ typedef struct eNB_RRC_UE_s { uint32_t ul_failure_timer; uint32_t ue_release_timer; uint32_t ue_release_timer_thres; + uint8_t e_rab_release_command_flag; } eNB_RRC_UE_t; typedef uid_t ue_uid_t; @@ -497,6 +511,8 @@ typedef struct { #endif SRB_INFO SI; SRB_INFO Srb0; + uint8_t *paging[NUMBER_OF_UE_MAX]; + uint32_t sizeof_paging[NUMBER_OF_UE_MAX]; } rrc_eNB_carrier_data_t; typedef struct eNB_RRC_INST_s { @@ -624,6 +640,8 @@ typedef struct UE_RRC_INST_s { #if defined(ENABLE_SECURITY) /* KeNB as computed from parameters within USIM card */ uint8_t kenb[32]; + uint8_t nh[32]; + int8_t nh_ncc; #endif /* Used integrity/ciphering algorithms */ @@ -631,6 +649,14 @@ typedef struct UE_RRC_INST_s { e_SecurityAlgorithmConfig__integrityProtAlgorithm integrity_algorithm; } UE_RRC_INST; +typedef struct UE_PF_PO_s { + boolean_t enable_flag; /* flag indicate whether current object is used */ + uint16_t ue_index_value; /* UE index value */ + uint8_t PF_min; /* minimal value of Paging Frame (PF) */ + uint8_t PO; /* Paging Occasion (PO) */ + uint32_t T; /* DRX cycle */ +} UE_PF_PO_t; + #include "proto.h" #endif diff --git a/openair2/RRC/LITE/extern.h b/openair2/RRC/LITE/extern.h index 77dcaac5e6..71d8c9d0dc 100644 --- a/openair2/RRC/LITE/extern.h +++ b/openair2/RRC/LITE/extern.h @@ -77,6 +77,11 @@ extern uint32_t timeToTrigger_ms[16]; extern float RSRP_meas_mapping[100]; extern float RSRQ_meas_mapping[33]; +extern UE_PF_PO_t UE_PF_PO[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +extern pthread_mutex_t ue_pf_po_mutex; + +extern uint16_t reestablish_rnti_map[NUMBER_OF_UE_MAX][2]; + #endif diff --git a/openair2/RRC/LITE/proto.h b/openair2/RRC/LITE/proto.h index b3d5beb292..3e00bc9769 100644 --- a/openair2/RRC/LITE/proto.h +++ b/openair2/RRC/LITE/proto.h @@ -254,6 +254,8 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration( const uint8_t ho_state ); +int freq_to_arfcn10(int band, unsigned long freq); + void rrc_eNB_generate_dedeicatedRRCConnectionReconfiguration( const protocol_ctxt_t* const ctxt_pP, @@ -261,6 +263,18 @@ rrc_eNB_generate_dedeicatedRRCConnectionReconfiguration( const uint8_t ho_state ); +/**\brief release Data Radio Bearer between ENB and UE + \param ctxt_pP Running context + \param ue_context_pP UE context of UE receiving the message*/ +void +rrc_eNB_generate_dedicatedRRCConnectionReconfiguration_release( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + uint8_t xid, + uint32_t nas_length, + uint8_t* nas_buffer +); + void rrc_eNB_reconfigure_DRBs (const protocol_ctxt_t* const ctxt_pP, rrc_eNB_ue_context_t* ue_context_pP); @@ -324,6 +338,12 @@ void mac_eNB_rrc_ul_failure(const module_id_t Mod_instP, const sub_frame_t subframeP, const rnti_t rnti); +void mac_eNB_rrc_uplane_failure(const module_id_t Mod_instP, + const int CC_id, + const frame_t frameP, + const sub_frame_t subframeP, + const rnti_t rnti); + void mac_eNB_rrc_ul_in_sync(const module_id_t Mod_instP, const int CC_id, const frame_t frameP, diff --git a/openair2/RRC/LITE/rrc_common.c b/openair2/RRC/LITE/rrc_common.c index 0e836f5677..718c8c63f3 100644 --- a/openair2/RRC/LITE/rrc_common.c +++ b/openair2/RRC/LITE/rrc_common.c @@ -363,9 +363,12 @@ rrc_rx_tx( } } } - if (ue_to_be_removed) + if (ue_to_be_removed) { rrc_eNB_free_UE(ctxt_pP->module_id,ue_to_be_removed); - + if(ue_to_be_removed->ue_context.ul_failure_timer >= 20000){ + ue_to_be_removed->ue_context.ul_failure_timer = 0; + } + } #ifdef RRC_LOCALIZATION /* for the localization, only primary CC_id might be relevant*/ diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 28d6982652..23559a90c9 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -84,6 +84,7 @@ #endif #include "pdcp.h" +#include "gtpv1u_eNB_task.h" #if defined(ENABLE_ITTI) # include "intertask_interface.h" @@ -679,11 +680,29 @@ rrc_eNB_free_mem_UE_context( ue_context_pP->ue_context.SRB_configList = NULL; } + for(i = 0;i < RRC_TRANSACTION_IDENTIFIER_NUMBER;i++){ + if (ue_context_pP->ue_context.SRB_configList2[i]) { + free(ue_context_pP->ue_context.SRB_configList2[i]); + ue_context_pP->ue_context.SRB_configList2[i] = NULL; + } + } + if (ue_context_pP->ue_context.DRB_configList) { ASN_STRUCT_FREE(asn_DEF_DRB_ToAddModList, ue_context_pP->ue_context.DRB_configList); ue_context_pP->ue_context.DRB_configList = NULL; } + for(i = 0;i < RRC_TRANSACTION_IDENTIFIER_NUMBER;i++){ + if (ue_context_pP->ue_context.DRB_configList2[i]) { + free(ue_context_pP->ue_context.DRB_configList2[i]); + ue_context_pP->ue_context.DRB_configList2[i] = NULL; + } + if (ue_context_pP->ue_context.DRB_Release_configList2[i]) { + free(ue_context_pP->ue_context.DRB_Release_configList2[i]); + ue_context_pP->ue_context.DRB_Release_configList2[i] = NULL; + } + } + memset(ue_context_pP->ue_context.DRB_active, 0, sizeof(ue_context_pP->ue_context.DRB_active)); if (ue_context_pP->ue_context.physicalConfigDedicated) { @@ -720,10 +739,14 @@ rrc_eNB_free_mem_UE_context( ue_context_pP->ue_context.mac_MainConfig = NULL; } - if (ue_context_pP->ue_context.measGapConfig) { +/* if (ue_context_pP->ue_context.measGapConfig) { ASN_STRUCT_FREE(asn_DEF_MeasGapConfig, ue_context_pP->ue_context.measGapConfig); ue_context_pP->ue_context.measGapConfig = NULL; - } + }*/ + if (ue_context_pP->ue_context.handover_info) { + ASN_STRUCT_FREE(asn_DEF_Handover, ue_context_pP->ue_context.handover_info); + ue_context_pP->ue_context.handover_info = NULL; + } //SRB_INFO SI; //SRB_INFO Srb0; @@ -791,6 +814,7 @@ rrc_eNB_free_UE(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_s* LOG_W(RRC, "[eNB %d] Removing UE RNTI %x\n", enb_mod_idP, rnti); #if defined(ENABLE_USE_MME) + if( ue_context_pP->ue_context.ul_failure_timer >= 20000 ) { rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ(enb_mod_idP, ue_context_pP, S1AP_CAUSE_RADIO_NETWORK, 21); // send cause 21: connection with ue lost /* From 3GPP 36300v10 p129 : 19.2.2.2.2 S1 UE Context Release Request (eNB triggered) * If the E-UTRAN internal reason is a radio link failure detected in the eNB, the eNB shall wait a sufficient time before @@ -798,6 +822,8 @@ rrc_eNB_free_UE(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_s* * in order to allow the UE to perform the NAS recovery * procedure, see TS 23.401 [17]. */ + return; + } #else #if defined(OAI_EMU) AssertFatal(ue_context_pP->local_uid < NUMBER_OF_UE_MAX, "local_uid invalid (%d<%d) for UE %x!", ue_context_pP->local_uid, NUMBER_OF_UE_MAX, rnti); @@ -1021,6 +1047,706 @@ rrc_eNB_generate_RRCConnectionReject( RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Tx_buffer.payload_size); } +//----------------------------------------------------------------------------- +void +rrc_eNB_generate_RRCConnectionReestablishment( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + const int CC_id +) +//----------------------------------------------------------------------------- +{ + LogicalChannelConfig_t *SRB1_logicalChannelConfig; + SRB_ToAddModList_t **SRB_configList; + SRB_ToAddMod_t *SRB1_config; + int cnt; + + T(T_ENB_RRC_CONNECTION_REESTABLISHMENT, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + SRB_configList = &ue_context_pP->ue_context.SRB_configList; + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Tx_buffer.payload_size = + do_RRCConnectionReestablishment(ctxt_pP, + ue_context_pP, + CC_id, + (uint8_t*) RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Tx_buffer.Payload, + (uint8_t) RC.rrc[ctxt_pP->module_id]->carrier[CC_id].p_eNB, //at this point we do not have the UE capability information, so it can only be TM1 or TM2 + rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id), + SRB_configList, + &ue_context_pP->ue_context.physicalConfigDedicated); + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRCConnectionReestablishment\n"); + + for (cnt = 0; cnt < RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Tx_buffer.payload_size; cnt++) { + LOG_F(RRC,"%02x ", ((uint8_t*)RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Tx_buffer.Payload)[cnt]); + } + + LOG_F(RRC,"\n"); +#endif + + // configure SRB1 for UE + + if (*SRB_configList != NULL) { + for (cnt = 0; cnt < (*SRB_configList)->list.count; cnt++) { + if ((*SRB_configList)->list.array[cnt]->srb_Identity == 1) { + SRB1_config = (*SRB_configList)->list.array[cnt]; + + if (SRB1_config->logicalChannelConfig) { + if (SRB1_config->logicalChannelConfig->present == + SRB_ToAddMod__logicalChannelConfig_PR_explicitValue) { + SRB1_logicalChannelConfig = &SRB1_config->logicalChannelConfig->choice.explicitValue; + } else { + SRB1_logicalChannelConfig = &SRB1_logicalChannelConfig_defaultValue; + } + } else { + SRB1_logicalChannelConfig = &SRB1_logicalChannelConfig_defaultValue; + } + + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RRC_eNB --- MAC_CONFIG_REQ (SRB1) ---> MAC_eNB\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + rrc_mac_config_req_eNB(ctxt_pP->module_id, + ue_context_pP->ue_context.primaryCC_id, + 0,0,0,0,0, +#ifdef Rel14 + 0, +#endif + ctxt_pP->rnti, + (BCCH_BCH_Message_t *) NULL, + (RadioResourceConfigCommonSIB_t *) NULL, + (RadioResourceConfigCommonSIB_t *) NULL, + (struct PhysicalConfigDedicated* ) ue_context_pP->ue_context.physicalConfigDedicated, +#if defined(Rel10) || defined(Rel14) + (SCellToAddMod_r10_t *)NULL, + //(struct PhysicalConfigDedicatedSCell_r10 *)NULL, +#endif + (MeasObjectToAddMod_t **) NULL, + ue_context_pP->ue_context.mac_MainConfig, + 1, + SRB1_logicalChannelConfig, + ue_context_pP->ue_context.measGapConfig, + (TDD_Config_t *) NULL, + NULL, + (SchedulingInfoList_t *) NULL, + 0, NULL, NULL, (MBSFN_SubframeConfigList_t *) NULL +#if defined(Rel10) || defined(Rel14) + , 0, (MBSFN_AreaInfoList_r9_t *) NULL, (PMCH_InfoList_r9_t *) NULL +#endif +#ifdef Rel14 + ,(SystemInformationBlockType1_v1310_IEs_t *)NULL +#endif + ); + break; + } + } + } + + MSC_LOG_TX_MESSAGE(MSC_RRC_ENB, + MSC_RRC_UE, + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Tx_buffer.Header, + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Tx_buffer.payload_size, + MSC_AS_TIME_FMT" RRCConnectionReestablishment UE %x size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_pP->ue_context.rnti, + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Tx_buffer.payload_size); + + + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel DL-CCCH, Generating RRCConnectionReestablishment (bytes %d)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Tx_buffer.payload_size); + + // activate release timer, if RRCComplete not received after 10 frames, remove UE + ue_context_pP->ue_context.ue_release_timer = 1; + // remove UE after 10 frames after RRCConnectionReestablishmentRelease is triggered + ue_context_pP->ue_context.ue_release_timer_thres = 100; +} + +//----------------------------------------------------------------------------- +void +rrc_eNB_process_RRCConnectionReestablishmentComplete( + const protocol_ctxt_t* const ctxt_pP, + const rnti_t const reestablish_rnti, + rrc_eNB_ue_context_t* ue_context_pP, + const uint8_t xid, + RRCConnectionReestablishmentComplete_r8_IEs_t * rrcConnectionReestablishmentComplete +) +//----------------------------------------------------------------------------- +{ + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel UL-DCCH, processing RRCConnectionReestablishmentComplete from UE (SRB1 Active)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + + T(T_ENB_RRC_CONNECTION_REESTABLISHMENT_COMPLETE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + DRB_ToAddModList_t* DRB_configList = ue_context_pP->ue_context.DRB_configList; + SRB_ToAddModList_t* SRB_configList = ue_context_pP->ue_context.SRB_configList; + SRB_ToAddModList_t** SRB_configList2 = NULL; + DRB_ToAddModList_t** DRB_configList2 = NULL; + struct SRB_ToAddMod *SRB2_config = NULL; + struct DRB_ToAddMod *DRB_config = NULL; + int i = 0; +# if defined(ENABLE_USE_MME) + int j = 0; + hashtable_rc_t h_rc; +#endif + uint8_t buffer[RRC_BUF_SIZE]; + uint16_t size; + MeasObjectToAddModList_t *MeasObj_list = NULL; + MeasObjectToAddMod_t *MeasObj = NULL; + ReportConfigToAddModList_t *ReportConfig_list = NULL; + ReportConfigToAddMod_t *ReportConfig_per, *ReportConfig_A1, + *ReportConfig_A2, *ReportConfig_A3, *ReportConfig_A4, *ReportConfig_A5; + MeasIdToAddModList_t *MeasId_list = NULL; + MeasIdToAddMod_t *MeasId0, *MeasId1, *MeasId2, *MeasId3, *MeasId4, *MeasId5; + RSRP_Range_t *rsrp = NULL; + struct MeasConfig__speedStatePars *Sparams = NULL; + QuantityConfig_t *quantityConfig = NULL; + CellsToAddMod_t *CellToAdd = NULL; + CellsToAddModList_t *CellsToAddModList = NULL; + struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList *dedicatedInfoNASList = NULL; + DedicatedInfoNAS_t *dedicatedInfoNas = NULL; + /* for no gcc warnings */ + (void)dedicatedInfoNas; + C_RNTI_t *cba_RNTI = NULL; + uint8_t next_xid = rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id); + + ue_context_pP->ue_context.Status = RRC_CONNECTED; + + SRB_configList2 = &ue_context_pP->ue_context.SRB_configList2[xid]; + // get old configuration of SRB2 + if (*SRB_configList2 != NULL) { + LOG_D(RRC, "SRB_configList2(%p) count is %d\n SRB_configList2->list.array[0] addr is %p", + SRB_configList2, (*SRB_configList2)->list.count, (*SRB_configList2)->list.array[0]); + for (i = 0; (i < (*SRB_configList2)->list.count) && (i < 3); i++) { + if ((*SRB_configList2)->list.array[i]->srb_Identity == 2 ){ + LOG_D(RRC, "get SRB2_config from (ue_context_pP->ue_context.SRB_configList2[%d])\n", xid); + SRB2_config = (*SRB_configList2)->list.array[i]; + break; + } + } + } + SRB_configList2 = &ue_context_pP->ue_context.SRB_configList2[next_xid]; + DRB_configList2 = &ue_context_pP->ue_context.DRB_configList2[next_xid]; + + if (*SRB_configList2) { + free(*SRB_configList2); + LOG_D(RRC, "free(ue_context_pP->ue_context.SRB_configList2[%d])\n", next_xid); + } + *SRB_configList2 = CALLOC(1, sizeof(**SRB_configList2)); + if (SRB2_config != NULL) { + // Add SRB2 to SRB configuration list + + ASN_SEQUENCE_ADD(&SRB_configList->list, SRB2_config); + ASN_SEQUENCE_ADD(&(*SRB_configList2)->list, SRB2_config); + + LOG_D(RRC, "Add SRB2_config (srb_Identity:%ld) to ue_context_pP->ue_context.SRB_configList\n", + SRB2_config->srb_Identity); + LOG_D(RRC, "Add SRB2_config (srb_Identity:%ld) to ue_context_pP->ue_context.SRB_configList2[%d]\n", + SRB2_config->srb_Identity, next_xid); + } else { + // SRB configuration list only contains SRB1. + LOG_W(RRC,"SRB2 configuration does not exist in SRB configuration list\n"); + } + + + + if (*DRB_configList2) { + free(*DRB_configList2); + LOG_D(RRC, "free(ue_context_pP->ue_context.DRB_configList2[%d])\n", next_xid); + } + *DRB_configList2 = CALLOC(1, sizeof(**DRB_configList2)); + + if (DRB_configList != NULL) { + LOG_D(RRC, "get DRB_config from (ue_context_pP->ue_context.DRB_configList)\n"); + for (i = 0; (i < DRB_configList->list.count) && (i < 3); i++) { + DRB_config = DRB_configList->list.array[i]; + + // Add DRB to DRB configuration list, for RRCConnectionReconfigurationComplete + ASN_SEQUENCE_ADD(&(*DRB_configList2)->list, DRB_config); + } + } + ue_context_pP->ue_context.Srb1.Active = 1; + //ue_context_pP->ue_context.Srb2.Srb_info.Srb_id = 2; + +# if defined(ENABLE_USE_MME) + rrc_ue_s1ap_ids_t* rrc_ue_s1ap_ids_p = NULL; + uint16_t ue_initial_id = ue_context_pP->ue_context.ue_initial_id; + uint32_t eNB_ue_s1ap_id = ue_context_pP->ue_context.eNB_ue_s1ap_id; + eNB_RRC_INST *rrc_instance_p = RC.rrc[ENB_INSTANCE_TO_MODULE_ID(ctxt_pP->instance)]; + if (eNB_ue_s1ap_id > 0) { + h_rc = hashtable_get(rrc_instance_p->s1ap_id2_s1ap_ids, (hash_key_t)eNB_ue_s1ap_id, (void**)&rrc_ue_s1ap_ids_p); + if (h_rc == HASH_TABLE_OK) { + rrc_ue_s1ap_ids_p->ue_rnti = ctxt_pP->rnti; + } + } + if (ue_initial_id != 0) { + h_rc = hashtable_get(rrc_instance_p->initial_id2_s1ap_ids, (hash_key_t)ue_initial_id, (void**)&rrc_ue_s1ap_ids_p); + if (h_rc == HASH_TABLE_OK) { + rrc_ue_s1ap_ids_p->ue_rnti = ctxt_pP->rnti; + } + } + + gtpv1u_enb_create_tunnel_req_t create_tunnel_req; + + /* Save e RAB information for later */ + memset(&create_tunnel_req, 0 , sizeof(create_tunnel_req)); + + for (j = 0, i = 0; i < NB_RB_MAX; i++) { + if (ue_context_pP->ue_context.e_rab[i].status == E_RAB_STATUS_ESTABLISHED) { + create_tunnel_req.eps_bearer_id[j] = ue_context_pP->ue_context.e_rab[i].param.e_rab_id; + create_tunnel_req.sgw_S1u_teid[j] = ue_context_pP->ue_context.e_rab[i].param.gtp_teid; + + memcpy(&create_tunnel_req.sgw_addr[j], + &ue_context_pP->ue_context.e_rab[i].param.sgw_addr, + sizeof(transport_layer_addr_t)); + j++; + } + } + + create_tunnel_req.rnti = ctxt_pP->rnti; // warning put zero above + create_tunnel_req.num_tunnels = j; + + gtpv1u_update_s1u_tunnel( + ctxt_pP->instance, + &create_tunnel_req, + reestablish_rnti); +#endif + /* Update RNTI in ue_context */ + ue_context_pP->ue_id_rnti = ctxt_pP->rnti; // here ue_id_rnti is just a key, may be something else + ue_context_pP->ue_context.rnti = ctxt_pP->rnti; +# if defined(ENABLE_USE_MME) + uint8_t send_security_mode_command = FALSE; + rrc_pdcp_config_security( + ctxt_pP, + ue_context_pP, + send_security_mode_command); + LOG_D(RRC, "set security successfully \n"); +#endif + // Measurement ID list + MeasId_list = CALLOC(1, sizeof(*MeasId_list)); + memset((void *)MeasId_list, 0, sizeof(*MeasId_list)); + + MeasId0 = CALLOC(1, sizeof(*MeasId0)); + MeasId0->measId = 1; + MeasId0->measObjectId = 1; + MeasId0->reportConfigId = 1; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId0); + + MeasId1 = CALLOC(1, sizeof(*MeasId1)); + MeasId1->measId = 2; + MeasId1->measObjectId = 1; + MeasId1->reportConfigId = 2; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId1); + + MeasId2 = CALLOC(1, sizeof(*MeasId2)); + MeasId2->measId = 3; + MeasId2->measObjectId = 1; + MeasId2->reportConfigId = 3; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId2); + + MeasId3 = CALLOC(1, sizeof(*MeasId3)); + MeasId3->measId = 4; + MeasId3->measObjectId = 1; + MeasId3->reportConfigId = 4; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId3); + + MeasId4 = CALLOC(1, sizeof(*MeasId4)); + MeasId4->measId = 5; + MeasId4->measObjectId = 1; + MeasId4->reportConfigId = 5; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId4); + + MeasId5 = CALLOC(1, sizeof(*MeasId5)); + MeasId5->measId = 6; + MeasId5->measObjectId = 1; + MeasId5->reportConfigId = 6; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId5); + + // rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measIdToAddModList = MeasId_list; + + // Add one EUTRA Measurement Object + MeasObj_list = CALLOC(1, sizeof(*MeasObj_list)); + memset((void *)MeasObj_list, 0, sizeof(*MeasObj_list)); + + // Configure MeasObject + + MeasObj = CALLOC(1, sizeof(*MeasObj)); + memset((void *)MeasObj, 0, sizeof(*MeasObj)); + + MeasObj->measObjectId = 1; + MeasObj->measObject.present = MeasObjectToAddMod__measObject_PR_measObjectEUTRA; + MeasObj->measObject.choice.measObjectEUTRA.carrierFreq = 3350; //band 7, 2.68GHz + //MeasObj->measObject.choice.measObjectEUTRA.carrierFreq = 36090; //band 33, 1.909GHz + MeasObj->measObject.choice.measObjectEUTRA.allowedMeasBandwidth = AllowedMeasBandwidth_mbw25; + MeasObj->measObject.choice.measObjectEUTRA.presenceAntennaPort1 = 1; + MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.buf = CALLOC(1, sizeof(uint8_t)); + MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.buf[0] = 0; + MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.size = 1; + MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.bits_unused = 6; + MeasObj->measObject.choice.measObjectEUTRA.offsetFreq = NULL; // Default is 15 or 0dB + + MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList = + (CellsToAddModList_t *) CALLOC(1, sizeof(*CellsToAddModList)); + + CellsToAddModList = MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList; + + // Add adjacent cell lists (6 per eNB) + for (i = 0; i < 6; i++) { + CellToAdd = (CellsToAddMod_t *) CALLOC(1, sizeof(*CellToAdd)); + CellToAdd->cellIndex = i + 1; + CellToAdd->physCellId = get_adjacent_cell_id(ctxt_pP->module_id, i); + CellToAdd->cellIndividualOffset = Q_OffsetRange_dB0; + + ASN_SEQUENCE_ADD(&CellsToAddModList->list, CellToAdd); + } + + ASN_SEQUENCE_ADD(&MeasObj_list->list, MeasObj); + // rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measObjectToAddModList = MeasObj_list; + + // Report Configurations for periodical, A1-A5 events + ReportConfig_list = CALLOC(1, sizeof(*ReportConfig_list)); + + ReportConfig_per = CALLOC(1, sizeof(*ReportConfig_per)); + + ReportConfig_A1 = CALLOC(1, sizeof(*ReportConfig_A1)); + + ReportConfig_A2 = CALLOC(1, sizeof(*ReportConfig_A2)); + + ReportConfig_A3 = CALLOC(1, sizeof(*ReportConfig_A3)); + + ReportConfig_A4 = CALLOC(1, sizeof(*ReportConfig_A4)); + + ReportConfig_A5 = CALLOC(1, sizeof(*ReportConfig_A5)); + + ReportConfig_per->reportConfigId = 1; + ReportConfig_per->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_periodical; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerType.choice.periodical.purpose = + ReportConfigEUTRA__triggerType__periodical__purpose_reportStrongestCells; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerQuantity = ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_per); + + ReportConfig_A1->reportConfigId = 2; + ReportConfig_A1->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA1; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA1. + a1_Threshold.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA1. + a1_Threshold.choice.threshold_RSRP = 10; + + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerQuantity = ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A1); + + if (RC.rrc[ctxt_pP->module_id]->HO_flag == 1 /*HO_MEASURMENT */ ) { + LOG_I(RRC, "[eNB %d] frame %d: requesting A2, A3, A4, A5, and A6 event reporting\n", + ctxt_pP->module_id, ctxt_pP->frame); + ReportConfig_A2->reportConfigId = 3; + ReportConfig_A2->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA2; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA2.a2_Threshold.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA2.a2_Threshold.choice.threshold_RSRP = 10; + + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerQuantity = + ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A2); + + ReportConfig_A3->reportConfigId = 4; + ReportConfig_A3->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA3; + + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA3.a3_Offset = 1; //10; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA3.reportOnLeave = 1; + + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerQuantity = + ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.hysteresis = 0.5; // FIXME ...hysteresis is of type long! + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.timeToTrigger = + TimeToTrigger_ms40; + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A3); + + ReportConfig_A4->reportConfigId = 5; + ReportConfig_A4->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA4; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA4.a4_Threshold.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA4.a4_Threshold.choice.threshold_RSRP = 10; + + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerQuantity = + ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A4); + + ReportConfig_A5->reportConfigId = 6; + ReportConfig_A5->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA5; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA5.a5_Threshold1.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA5.a5_Threshold2.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA5.a5_Threshold1.choice.threshold_RSRP = 10; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA5.a5_Threshold2.choice.threshold_RSRP = 10; + + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerQuantity = + ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A5); + // rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->reportConfigToAddModList = ReportConfig_list; + + rsrp = CALLOC(1, sizeof(RSRP_Range_t)); + *rsrp = 20; + + Sparams = CALLOC(1, sizeof(*Sparams)); + Sparams->present = MeasConfig__speedStatePars_PR_setup; + Sparams->choice.setup.timeToTrigger_SF.sf_High = SpeedStateScaleFactors__sf_Medium_oDot75; + Sparams->choice.setup.timeToTrigger_SF.sf_Medium = SpeedStateScaleFactors__sf_High_oDot5; + Sparams->choice.setup.mobilityStateParameters.n_CellChangeHigh = 10; + Sparams->choice.setup.mobilityStateParameters.n_CellChangeMedium = 5; + Sparams->choice.setup.mobilityStateParameters.t_Evaluation = MobilityStateParameters__t_Evaluation_s60; + Sparams->choice.setup.mobilityStateParameters.t_HystNormal = MobilityStateParameters__t_HystNormal_s120; + + quantityConfig = CALLOC(1, sizeof(*quantityConfig)); + memset((void *)quantityConfig, 0, sizeof(*quantityConfig)); + quantityConfig->quantityConfigEUTRA = CALLOC(1, sizeof(struct QuantityConfigEUTRA)); + memset((void *)quantityConfig->quantityConfigEUTRA, 0, sizeof(*quantityConfig->quantityConfigEUTRA)); + quantityConfig->quantityConfigCDMA2000 = NULL; + quantityConfig->quantityConfigGERAN = NULL; + quantityConfig->quantityConfigUTRA = NULL; + quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP = + CALLOC(1, sizeof(*(quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP))); + quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ = + CALLOC(1, sizeof(*(quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ))); + *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP = FilterCoefficient_fc4; + *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ = FilterCoefficient_fc4; + + LOG_I(RRC, + "[eNB %d] Frame %d: potential handover preparation: store the information in an intermediate structure in case of failure\n", + ctxt_pP->module_id, ctxt_pP->frame); + // store the information in an intermediate structure for Hanodver management + //rrc_inst->handover_info.as_config.sourceRadioResourceConfig.srb_ToAddModList = CALLOC(1,sizeof()); + ue_context_pP->ue_context.handover_info = CALLOC(1, sizeof(*(ue_context_pP->ue_context.handover_info))); + //memcpy((void *)rrc_inst->handover_info[ue_mod_idP]->as_config.sourceRadioResourceConfig.srb_ToAddModList,(void *)SRB_list,sizeof(SRB_ToAddModList_t)); + ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.srb_ToAddModList = *SRB_configList2; + //memcpy((void *)rrc_inst->handover_info[ue_mod_idP]->as_config.sourceRadioResourceConfig.drb_ToAddModList,(void *)DRB_list,sizeof(DRB_ToAddModList_t)); + ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.drb_ToAddModList = DRB_configList; + ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.drb_ToReleaseList = NULL; + ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.mac_MainConfig = + CALLOC(1, sizeof(*ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.mac_MainConfig)); + memcpy((void*)ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.mac_MainConfig, + (void *)ue_context_pP->ue_context.mac_MainConfig, sizeof(MAC_MainConfig_t)); + ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.physicalConfigDedicated = + CALLOC(1, sizeof(PhysicalConfigDedicated_t)); + memcpy((void*)ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.physicalConfigDedicated, + (void*)ue_context_pP->ue_context.physicalConfigDedicated, sizeof(PhysicalConfigDedicated_t)); + ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.sps_Config = NULL; + //memcpy((void *)rrc_inst->handover_info[ue_mod_idP]->as_config.sourceRadioResourceConfig.sps_Config,(void *)rrc_inst->sps_Config[ue_mod_idP],sizeof(SPS_Config_t)); + + } + +#ifdef CBA + //struct PUSCH_CBAConfigDedicated_vlola *pusch_CBAConfigDedicated_vlola; + uint8_t *cba_RNTI_buf; + cba_RNTI = CALLOC(1, sizeof(C_RNTI_t)); + cba_RNTI_buf = CALLOC(1, 2 * sizeof(uint8_t)); + cba_RNTI->buf = cba_RNTI_buf; + cba_RNTI->size = 2; + cba_RNTI->bits_unused = 0; + + // associate UEs to the CBa groups as a function of their UE id + if (rrc_inst->num_active_cba_groups) { + cba_RNTI->buf[0] = rrc_inst->cba_rnti[ue_mod_idP % rrc_inst->num_active_cba_groups] & 0xff; + cba_RNTI->buf[1] = 0xff; + LOG_D(RRC, + "[eNB %d] Frame %d: cba_RNTI = %x in group %d is attribued to UE %d\n", + enb_mod_idP, frameP, + rrc_inst->cba_rnti[ue_mod_idP % rrc_inst->num_active_cba_groups], + ue_mod_idP % rrc_inst->num_active_cba_groups, ue_mod_idP); + } else { + cba_RNTI->buf[0] = 0x0; + cba_RNTI->buf[1] = 0x0; + LOG_D(RRC, "[eNB %d] Frame %d: no cba_RNTI is configured for UE %d\n", enb_mod_idP, frameP, ue_mod_idP); + } + +#endif + +#if defined(ENABLE_ITTI) + /* Initialize NAS list */ + dedicatedInfoNASList = CALLOC(1, sizeof(struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList)); + + /* Add all NAS PDUs to the list */ + for (i = 0; i < ue_context_pP->ue_context.nb_of_e_rabs; i++) { + if (ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer != NULL) { + dedicatedInfoNas = CALLOC(1, sizeof(DedicatedInfoNAS_t)); + memset(dedicatedInfoNas, 0, sizeof(OCTET_STRING_t)); + OCTET_STRING_fromBuf(dedicatedInfoNas, + (char*)ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer, + ue_context_pP->ue_context.e_rab[i].param.nas_pdu.length); + LOG_D(RRC, "Add dedicatedInfoNas(%d) to dedicatedInfoNASList\n", i); + ASN_SEQUENCE_ADD(&dedicatedInfoNASList->list, dedicatedInfoNas); + } + + /* TODO parameters yet to process ... */ + { + // ue_context_pP->ue_context.e_rab[i].param.qos; + // ue_context_pP->ue_context.e_rab[i].param.sgw_addr; + // ue_context_pP->ue_context.e_rab[i].param.gtp_teid; + } + + /* TODO should test if e RAB are Ok before! */ + ue_context_pP->ue_context.e_rab[i].status = E_RAB_STATUS_DONE; + LOG_D(RRC, "setting the status for the default DRB (index %d) to (%d,%s)\n", + i, ue_context_pP->ue_context.e_rab[i].status, "E_RAB_STATUS_DONE"); + } + + /* If list is empty free the list and reset the address */ + if (dedicatedInfoNASList->list.count == 0) { + free(dedicatedInfoNASList); + dedicatedInfoNASList = NULL; + } + +#endif + + // send RRCConnectionReconfiguration + memset(buffer, 0, RRC_BUF_SIZE); + + size = do_RRCConnectionReconfiguration(ctxt_pP, + buffer, + next_xid, //Transaction_id, + (SRB_ToAddModList_t*)*SRB_configList2, // SRB_configList + (DRB_ToAddModList_t*)DRB_configList, + (DRB_ToReleaseList_t*)NULL, // DRB2_list, + (struct SPS_Config*)NULL, // maybe ue_context_pP->ue_context.sps_Config, + (struct PhysicalConfigDedicated*)ue_context_pP->ue_context.physicalConfigDedicated, +#ifdef EXMIMO_IOT + NULL, NULL, NULL,NULL, +#else + (MeasObjectToAddModList_t*)MeasObj_list, // MeasObj_list, + (ReportConfigToAddModList_t*)ReportConfig_list, // ReportConfig_list, + (QuantityConfig_t*)quantityConfig, //quantityConfig, + (MeasIdToAddModList_t*)NULL, +#endif + (MAC_MainConfig_t*)ue_context_pP->ue_context.mac_MainConfig, + (MeasGapConfig_t*)NULL, + (MobilityControlInfo_t*)NULL, + (struct MeasConfig__speedStatePars*)Sparams, // Sparams, + (RSRP_Range_t*)rsrp, // rsrp, + (C_RNTI_t*)cba_RNTI, // cba_RNTI + (struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList*)dedicatedInfoNASList //dedicatedInfoNASList +#if defined(Rel10) || defined(Rel14) + , (SCellToAddMod_r10_t*)NULL +#endif + ); + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC Connection Reconfiguration\n"); + for (i = 0; i < size; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)buffer)[i]); + } + LOG_F(RRC,"\n"); + //////////////////////////////////////// +#endif + +#if defined(ENABLE_ITTI) + + /* Free all NAS PDUs */ + for (i = 0; i < ue_context_pP->ue_context.nb_of_e_rabs; i++) { + if (ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer != NULL) { + /* Free the NAS PDU buffer and invalidate it */ + free(ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer); + ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer = NULL; + } + } + +#endif + + LOG_I(RRC, + "[eNB %d] Frame %d, Logical Channel DL-DCCH, Generate RRCConnectionReconfiguration (bytes %d, UE id %x)\n", + ctxt_pP->module_id, ctxt_pP->frame, size, ue_context_pP->ue_context.rnti); + + LOG_D(RRC, + "[FRAME %05d][RRC_eNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcConnectionReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n", + ctxt_pP->frame, ctxt_pP->module_id, size, ue_context_pP->ue_context.rnti, rrc_eNB_mui, ctxt_pP->module_id, DCCH); + + MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + buffer, + size, + MSC_AS_TIME_FMT" rrcConnectionReconfiguration UE %x MUI %d size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_pP->ue_context.rnti, + rrc_eNB_mui, + size); + + rrc_data_req( + ctxt_pP, + DCCH, + rrc_eNB_mui++, + SDU_CONFIRM_NO, + size, + buffer, + PDCP_TRANSMISSION_MODE_CONTROL); + + // delete UE data of prior RNTI. UE use current RNTI. + protocol_ctxt_t ctxt_prior = *ctxt_pP; + ctxt_prior.rnti = reestablish_rnti; + rrc_mac_remove_ue(ctxt_prior.module_id, ctxt_prior.rnti); + rrc_rlc_remove_ue(&ctxt_prior); + pdcp_remove_UE(&ctxt_prior); +} + //----------------------------------------------------------------------------- void rrc_eNB_generate_RRCConnectionReestablishmentReject( @@ -1045,7 +1771,7 @@ rrc_eNB_generate_RRCConnectionReestablishmentReject( LOG_F(RRC,"[MSG] RRCConnectionReestablishmentReject\n"); for (cnt = 0; cnt < RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Tx_buffer.payload_size; cnt++) { - LOG_F(RRC,"%02x ", ((uint8_t*)RC.rrc[ctxt_pP->module_id]->Srb0.Tx_buffer.Payload)[cnt]); + LOG_F(RRC,"%02x ", ((uint8_t*)RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Tx_buffer.Payload)[cnt]); } LOG_F(RRC,"\n"); @@ -1158,7 +1884,7 @@ rrc_eNB_generate_dedicatedRRCConnectionReconfiguration(const protocol_ctxt_t* co (void)dedicatedInfoNas; long *logicalchannelgroup_drb; - int drb_identity_index=0; +// int drb_identity_index=0; uint8_t xid = rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id); //Transaction_id, DRB_configList2=&ue_context_pP->ue_context.DRB_configList2[xid]; @@ -1175,10 +1901,14 @@ rrc_eNB_generate_dedicatedRRCConnectionReconfiguration(const protocol_ctxt_t* co for ( i = 0 ; i < ue_context_pP->ue_context.setup_e_rabs ; i++){ + + if (e_rab_done >= ue_context_pP->ue_context.nb_of_e_rabs){ + break; + } // bypass the new and already configured erabs if (ue_context_pP->ue_context.e_rab[i].status >= E_RAB_STATUS_DONE) { - drb_identity_index++; +// drb_identity_index++; continue; } @@ -1188,8 +1918,9 @@ rrc_eNB_generate_dedicatedRRCConnectionReconfiguration(const protocol_ctxt_t* co // allowed value 5..15, value : x+4 *(DRB_config->eps_BearerIdentity) = ue_context_pP->ue_context.e_rab[i].param.e_rab_id;//+ 4; // especial case generation - DRB_config->drb_Identity = 1 + drb_identity_index + e_rab_done;// + i ;// (DRB_Identity_t) ue_context_pP->ue_context.e_rab[i].param.e_rab_id; + // DRB_config->drb_Identity = 1 + drb_identity_index + e_rab_done;// + i ;// (DRB_Identity_t) ue_context_pP->ue_context.e_rab[i].param.e_rab_id; // 1 + drb_identiy_index; + DRB_config->drb_Identity = i+1; DRB_config->logicalChannelIdentity = CALLOC(1, sizeof(long)); *(DRB_config->logicalChannelIdentity) = DRB_config->drb_Identity + 2; //(long) (ue_context_pP->ue_context.e_rab[i].param.e_rab_id + 2); // value : x+2 @@ -1257,6 +1988,7 @@ rrc_eNB_generate_dedicatedRRCConnectionReconfiguration(const protocol_ctxt_t* co LOG_E(RRC,"not supported qci %d\n", ue_context_pP->ue_context.e_rab[i].param.qos.qci); ue_context_pP->ue_context.e_rab[i].status = E_RAB_STATUS_FAILED; ue_context_pP->ue_context.e_rab[i].xid = xid; + e_rab_done++; continue; } @@ -1401,6 +2133,392 @@ rrc_eNB_generate_dedicatedRRCConnectionReconfiguration(const protocol_ctxt_t* co PDCP_TRANSMISSION_MODE_CONTROL); +} +int +rrc_eNB_modify_dedicatedRRCConnectionReconfiguration(const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + const uint8_t ho_state + ) +//----------------------------------------------------------------------------- +{ + uint8_t buffer[RRC_BUF_SIZE]; + uint16_t size; + int i, j; + + struct DRB_ToAddMod *DRB_config = NULL; + struct RLC_Config *DRB_rlc_config = NULL; + struct PDCP_Config *DRB_pdcp_config = NULL; + struct PDCP_Config__rlc_AM *PDCP_rlc_AM = NULL; + struct PDCP_Config__rlc_UM *PDCP_rlc_UM = NULL; + struct LogicalChannelConfig *DRB_lchan_config = NULL; + struct LogicalChannelConfig__ul_SpecificParameters + *DRB_ul_SpecificParameters = NULL; + DRB_ToAddModList_t* DRB_configList = ue_context_pP->ue_context.DRB_configList; + DRB_ToAddModList_t* DRB_configList2 = NULL; + + struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList *dedicatedInfoNASList = NULL; + DedicatedInfoNAS_t *dedicatedInfoNas = NULL; + /* for no gcc warnings */ + (void)dedicatedInfoNas; + + uint8_t xid = rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id); // Transaction_id, + DRB_configList2 = CALLOC(1, sizeof(*DRB_configList2)); + /* Initialize NAS list */ + dedicatedInfoNASList = CALLOC(1, sizeof(struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList)); + + for (i = 0; i < ue_context_pP->ue_context.nb_of_modify_e_rabs; i++) { + // bypass the new and already configured erabs + if (ue_context_pP->ue_context.modify_e_rab[i].status >= E_RAB_STATUS_DONE) { + ue_context_pP->ue_context.modify_e_rab[i].xid = xid; + continue; + } + + if (ue_context_pP->ue_context.modify_e_rab[i].cause != S1AP_CAUSE_NOTHING) { + // set xid of failure RAB + ue_context_pP->ue_context.modify_e_rab[i].xid = xid; + ue_context_pP->ue_context.modify_e_rab[i].status = E_RAB_STATUS_FAILED; + continue; + } + + DRB_config = NULL; + // search exist DRB_config + for (j = 0; j < DRB_configList->list.count; j++) { + if((uint8_t)*(DRB_configList->list.array[j]->eps_BearerIdentity) == ue_context_pP->ue_context.modify_e_rab[i].param.e_rab_id) { + DRB_config = DRB_configList->list.array[j]; + break; + } + } + if (NULL == DRB_config) { + ue_context_pP->ue_context.modify_e_rab[i].xid = xid; + ue_context_pP->ue_context.modify_e_rab[i].status = E_RAB_STATUS_FAILED; + // TODO use which cause + ue_context_pP->ue_context.modify_e_rab[i].cause = S1AP_CAUSE_RADIO_NETWORK; + ue_context_pP->ue_context.modify_e_rab[i].cause_value = 0;//S1ap_CauseRadioNetwork_unspecified; + ue_context_pP->ue_context.nb_of_failed_e_rabs++; + continue; + } + + DRB_rlc_config = DRB_config->rlc_Config; + + DRB_pdcp_config = DRB_config->pdcp_Config; + *DRB_pdcp_config->discardTimer = PDCP_Config__discardTimer_infinity; + switch (ue_context_pP->ue_context.modify_e_rab[i].param.qos.qci) { + /* + * type: realtime data with medium packer error rate + * action: swtich to RLC UM + */ + case 1: // 100ms, 10^-2, p2, GBR + case 2: // 150ms, 10^-3, p4, GBR + case 3: // 50ms, 10^-3, p3, GBR + case 4: // 300ms, 10^-6, p5 + case 7: // 100ms, 10^-3, p7, GBR + case 9: // 300ms, 10^-6, p9 + case 65: // 75ms, 10^-2, p0.7, mission critical voice, GBR + case 66: // 100ms, 10^-2, p2, non-mission critical voice , GBR + // RLC + DRB_rlc_config->present = RLC_Config_PR_um_Bi_Directional; + DRB_rlc_config->choice.um_Bi_Directional.ul_UM_RLC.sn_FieldLength = SN_FieldLength_size10; + DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.sn_FieldLength = SN_FieldLength_size10; + DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.t_Reordering = T_Reordering_ms35; + // PDCP + if (DRB_pdcp_config->rlc_AM) { + free(DRB_pdcp_config->rlc_AM); + DRB_pdcp_config->rlc_AM = NULL; + } + if (DRB_pdcp_config->rlc_UM) { + free(DRB_pdcp_config->rlc_UM); + DRB_pdcp_config->rlc_UM = NULL; + } + PDCP_rlc_UM = CALLOC(1, sizeof(*PDCP_rlc_UM)); + DRB_pdcp_config->rlc_UM = PDCP_rlc_UM; + PDCP_rlc_UM->pdcp_SN_Size = PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits; + break; + + /* + * type: non-realtime data with low packer error rate + * action: swtich to RLC AM + */ + case 5: // 100ms, 10^-6, p1 , IMS signaling + case 6: // 300ms, 10^-6, p6 + case 8: // 300ms, 10^-6, p8 + case 69: // 60ms, 10^-6, p0.5, mission critical delay sensitive data, Lowest Priority + case 70: // 200ms, 10^-6, p5.5, mision critical data + // RLC + DRB_rlc_config->present = RLC_Config_PR_am; + DRB_rlc_config->choice.am.ul_AM_RLC.t_PollRetransmit = T_PollRetransmit_ms50; + DRB_rlc_config->choice.am.ul_AM_RLC.pollPDU = PollPDU_p16; + DRB_rlc_config->choice.am.ul_AM_RLC.pollByte = PollByte_kBinfinity; + DRB_rlc_config->choice.am.ul_AM_RLC.maxRetxThreshold = UL_AM_RLC__maxRetxThreshold_t8; + DRB_rlc_config->choice.am.dl_AM_RLC.t_Reordering = T_Reordering_ms35; + DRB_rlc_config->choice.am.dl_AM_RLC.t_StatusProhibit = T_StatusProhibit_ms25; + + // PDCP + if (DRB_pdcp_config->rlc_AM) { + free(DRB_pdcp_config->rlc_AM); + DRB_pdcp_config->rlc_AM = NULL; + } + if (DRB_pdcp_config->rlc_UM) { + free(DRB_pdcp_config->rlc_UM); + DRB_pdcp_config->rlc_UM = NULL; + } + PDCP_rlc_AM = CALLOC(1, sizeof(*PDCP_rlc_AM)); + DRB_pdcp_config->rlc_AM = PDCP_rlc_AM; + PDCP_rlc_AM->statusReportRequired = FALSE; + + break; + default : + LOG_E(RRC, "not supported qci %d\n", ue_context_pP->ue_context.modify_e_rab[i].param.qos.qci); + ue_context_pP->ue_context.modify_e_rab[i].status = E_RAB_STATUS_FAILED; + ue_context_pP->ue_context.modify_e_rab[i].xid = xid; + ue_context_pP->ue_context.modify_e_rab[i].cause = S1AP_CAUSE_RADIO_NETWORK; + ue_context_pP->ue_context.modify_e_rab[i].cause_value = 37;//S1ap_CauseRadioNetwork_not_supported_QCI_value; + ue_context_pP->ue_context.nb_of_failed_e_rabs++; + continue; + } + + DRB_pdcp_config->headerCompression.present = PDCP_Config__headerCompression_PR_notUsed; + + DRB_lchan_config = DRB_config->logicalChannelConfig; + DRB_ul_SpecificParameters = DRB_lchan_config->ul_SpecificParameters; + + if (ue_context_pP->ue_context.modify_e_rab[i].param.qos.qci < 9 ) + DRB_ul_SpecificParameters->priority = qci_to_priority[ue_context_pP->ue_context.modify_e_rab[i].param.qos.qci-1] + 3; + else + DRB_ul_SpecificParameters->priority= 4; + + DRB_ul_SpecificParameters->prioritisedBitRate = LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8; + + DRB_ul_SpecificParameters->bucketSizeDuration = + LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50; + + ASN_SEQUENCE_ADD(&(DRB_configList2)->list, DRB_config); + + LOG_I(RRC, "EPS ID %ld, DRB ID %ld (index %d), QCI %d, priority %ld, LCID %ld LCGID %ld \n", + *DRB_config->eps_BearerIdentity, + DRB_config->drb_Identity, i, + ue_context_pP->ue_context.modify_e_rab[i].param.qos.qci, + DRB_ul_SpecificParameters->priority, + *(DRB_config->logicalChannelIdentity), + *DRB_ul_SpecificParameters->logicalChannelGroup + ); + + //e_rab_done++; + ue_context_pP->ue_context.modify_e_rab[i].status = E_RAB_STATUS_DONE; + ue_context_pP->ue_context.modify_e_rab[i].xid = xid; + + { + if (ue_context_pP->ue_context.modify_e_rab[i].param.nas_pdu.buffer != NULL) { + dedicatedInfoNas = CALLOC(1, sizeof(DedicatedInfoNAS_t)); + memset(dedicatedInfoNas, 0, sizeof(OCTET_STRING_t)); + OCTET_STRING_fromBuf(dedicatedInfoNas, + (char*)ue_context_pP->ue_context.modify_e_rab[i].param.nas_pdu.buffer, + ue_context_pP->ue_context.modify_e_rab[i].param.nas_pdu.length); + ASN_SEQUENCE_ADD(&dedicatedInfoNASList->list, dedicatedInfoNas); + LOG_I(RRC, "add NAS info with size %d (rab id %d)\n",ue_context_pP->ue_context.modify_e_rab[i].param.nas_pdu.length, i); + } + else { + LOG_W(RRC, "Not received activate dedicated EPS bearer context request\n"); + } + } + } + + /* If list is empty free the list and reset the address */ + if (dedicatedInfoNASList != NULL) { + if (dedicatedInfoNASList->list.count == 0) { + free(dedicatedInfoNASList); + dedicatedInfoNASList = NULL; + LOG_W(RRC,"dedlicated NAS list is empty, free the list and reset the address\n"); + } + } else { + LOG_W(RRC,"dedlicated NAS list is empty\n"); + } + + memset(buffer, 0, RRC_BUF_SIZE); + + size = do_RRCConnectionReconfiguration(ctxt_pP, + buffer, + xid, + (SRB_ToAddModList_t*)NULL, + (DRB_ToAddModList_t*)DRB_configList2, + (DRB_ToReleaseList_t*)NULL, // DRB2_list, + (struct SPS_Config*)NULL, // *sps_Config, + NULL, NULL, NULL, NULL,NULL, + NULL, NULL, NULL, NULL, NULL, NULL, + (struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList*)dedicatedInfoNASList +#if defined(Rel10) || defined(Rel14) + , (SCellToAddMod_r10_t*)NULL +#endif + ); + + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC Connection Reconfiguration\n"); + for (i = 0; i < size; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)buffer)[i]); + } + LOG_F(RRC,"\n"); + //////////////////////////////////////// +#endif + +#if defined(ENABLE_ITTI) + + /* Free all NAS PDUs */ + for (i = 0; i < ue_context_pP->ue_context.nb_of_modify_e_rabs; i++) { + if (ue_context_pP->ue_context.modify_e_rab[i].param.nas_pdu.buffer != NULL) { + /* Free the NAS PDU buffer and invalidate it */ + free(ue_context_pP->ue_context.modify_e_rab[i].param.nas_pdu.buffer); + ue_context_pP->ue_context.modify_e_rab[i].param.nas_pdu.buffer = NULL; + } + } +#endif + + LOG_I(RRC, + "[eNB %d] Frame %d, Logical Channel DL-DCCH, Generate RRCConnectionReconfiguration (bytes %d, UE RNTI %x)\n", + ctxt_pP->module_id, ctxt_pP->frame, size, ue_context_pP->ue_context.rnti); + + LOG_D(RRC, + "[FRAME %05d][RRC_eNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcConnectionReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n", + ctxt_pP->frame, ctxt_pP->module_id, size, ue_context_pP->ue_context.rnti, rrc_eNB_mui, ctxt_pP->module_id, DCCH); + + MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + buffer, + size, + MSC_AS_TIME_FMT" dedicated rrcConnectionReconfiguration UE %x MUI %d size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_pP->ue_context.rnti, + rrc_eNB_mui, + size); + + rrc_data_req( + ctxt_pP, + DCCH, + rrc_eNB_mui++, + SDU_CONFIRM_NO, + size, + buffer, + PDCP_TRANSMISSION_MODE_CONTROL); + return 0; +} + +//----------------------------------------------------------------------------- +void +rrc_eNB_generate_dedicatedRRCConnectionReconfiguration_release( const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + uint8_t xid, + uint32_t nas_length, + uint8_t* nas_buffer) +//----------------------------------------------------------------------------- +{ + uint8_t buffer[RRC_BUF_SIZE]; + int i; + uint16_t size = 0; + DRB_ToReleaseList_t** DRB_Release_configList2=NULL; + DRB_Identity_t* DRB_release; + struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList *dedicatedInfoNASList = NULL; + + DRB_Release_configList2=&ue_context_pP->ue_context.DRB_Release_configList2[xid]; + if (*DRB_Release_configList2) { + free(*DRB_Release_configList2); + } + *DRB_Release_configList2 = CALLOC(1, sizeof(**DRB_Release_configList2)); + + for(i = 0; i < NB_RB_MAX; i++){ + if((ue_context_pP->ue_context.e_rab[i].status == E_RAB_STATUS_TORELEASE) && ue_context_pP->ue_context.e_rab[i].xid == xid){ + DRB_release = CALLOC(1, sizeof(DRB_Identity_t)); + *DRB_release = i+1; + ASN_SEQUENCE_ADD(&(*DRB_Release_configList2)->list, DRB_release); + //free(DRB_release); + } + } + + /* If list is empty free the list and reset the address */ + if (nas_length > 0) { + DedicatedInfoNAS_t *dedicatedInfoNas = NULL; + dedicatedInfoNASList = CALLOC(1, sizeof(struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList)); + dedicatedInfoNas = CALLOC(1, sizeof(DedicatedInfoNAS_t)); + memset(dedicatedInfoNas, 0, sizeof(OCTET_STRING_t)); + OCTET_STRING_fromBuf(dedicatedInfoNas, + (char*)nas_buffer, + nas_length); + ASN_SEQUENCE_ADD(&dedicatedInfoNASList->list, dedicatedInfoNas); + LOG_I(RRC,"add NAS info with size %d\n",nas_length); + } else { + LOG_W(RRC,"dedlicated NAS list is empty\n"); + } + + memset(buffer, 0, RRC_BUF_SIZE); + size = do_RRCConnectionReconfiguration(ctxt_pP, + buffer, + xid, + NULL, + NULL, + (DRB_ToReleaseList_t*)*DRB_Release_configList2, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList*)dedicatedInfoNASList +#if defined(Rel10) || defined(Rel14) + , (SCellToAddMod_r10_t*)NULL +#endif + ); + ue_context_pP->ue_context.e_rab_release_command_flag = 1; + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC Connection Reconfiguration\n"); + for (i = 0; i < size; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)buffer)[i]); + } + LOG_F(RRC,"\n"); + //////////////////////////////////////// +#endif + +#if defined(ENABLE_ITTI) + /* Free all NAS PDUs */ + if (nas_length > 0) { + /* Free the NAS PDU buffer and invalidate it */ + free(nas_buffer); + } +#endif + + LOG_I(RRC, + "[eNB %d] Frame %d, Logical Channel DL-DCCH, Generate RRCConnectionReconfiguration (bytes %d, UE RNTI %x)\n", + ctxt_pP->module_id, ctxt_pP->frame, size, ue_context_pP->ue_context.rnti); + + LOG_D(RRC, + "[FRAME %05d][RRC_eNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcConnectionReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n", + ctxt_pP->frame, ctxt_pP->module_id, size, ue_context_pP->ue_context.rnti, rrc_eNB_mui, ctxt_pP->module_id, DCCH); + + MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + buffer, + size, + MSC_AS_TIME_FMT" dedicated rrcConnectionReconfiguration UE %x MUI %d size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_pP->ue_context.rnti, + rrc_eNB_mui, + size); + + rrc_data_req( + ctxt_pP, + DCCH, + rrc_eNB_mui++, + SDU_CONFIRM_NO, + size, + buffer, + PDCP_TRANSMISSION_MODE_CONTROL); + } #endif //----------------------------------------------------------------------------- @@ -2134,7 +3252,113 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* cons PDCP_TRANSMISSION_MODE_CONTROL); } +typedef enum { BAND_TYPE_FDD, BAND_TYPE_TDD } band_type; +typedef struct { + band_type t; + int band; + unsigned long ul_minfreq, ul_maxfreq; + unsigned long dl_minfreq, dl_maxfreq; +} band_freq; + +static band_freq bands[] = { + { BAND_TYPE_FDD, 1, 1920000000UL, 1980000000UL, 2110000000UL, 2170000000UL }, + { BAND_TYPE_FDD, 2, 1850000000UL, 1910000000UL, 1930000000UL, 1990000000UL }, + { BAND_TYPE_FDD, 3, 1710000000UL, 1785000000UL, 1805000000UL, 1880000000UL }, + { BAND_TYPE_FDD, 4, 1710000000UL, 1755000000UL, 2110000000UL, 2155000000UL }, + { BAND_TYPE_FDD, 5, 824000000UL, 849000000UL, 869000000UL, 894000000UL }, + /* to remove? */{ BAND_TYPE_FDD, 6, 830000000UL, 840000000UL, 875000000UL, 885000000UL }, + { BAND_TYPE_FDD, 7, 2500000000UL, 2570000000UL, 2620000000UL, 2690000000UL }, + { BAND_TYPE_FDD, 8, 880000000UL, 915000000UL, 925000000UL, 960000000UL }, + { BAND_TYPE_FDD, 9, 1749900000UL, 1784900000UL, 1844900000UL, 1879900000UL }, + { BAND_TYPE_FDD, 10, 1710000000UL, 1770000000UL, 2110000000UL, 2170000000UL }, + { BAND_TYPE_FDD, 11, 1427900000UL, 1447900000UL, 1475900000UL, 1495900000UL }, + { BAND_TYPE_FDD, 12, 699000000UL, 716000000UL, 729000000UL, 746000000UL }, + { BAND_TYPE_FDD, 13, 777000000UL, 787000000UL, 746000000UL, 756000000UL }, + { BAND_TYPE_FDD, 14, 788000000UL, 798000000UL, 758000000UL, 768000000UL }, + { BAND_TYPE_FDD, 17, 704000000UL, 716000000UL, 734000000UL, 746000000UL }, + { BAND_TYPE_FDD, 18, 815000000UL, 830000000UL, 860000000UL, 875000000UL }, + { BAND_TYPE_FDD, 19, 830000000UL, 845000000UL, 875000000UL, 890000000UL }, + { BAND_TYPE_FDD, 20, 832000000UL, 862000000UL, 791000000UL, 821000000UL }, + { BAND_TYPE_FDD, 21, 1447900000UL, 1462900000UL, 1495900000UL, 1510900000UL }, + { BAND_TYPE_FDD, 22, 3410000000UL, 3490000000UL, 3510000000UL, 3590000000UL }, + { BAND_TYPE_FDD, 23, 2000000000UL, 2020000000UL, 2180000000UL, 2200000000UL }, + { BAND_TYPE_FDD, 24, 1626500000UL, 1660500000UL, 1525000000UL, 1559000000UL }, + { BAND_TYPE_FDD, 25, 1850000000UL, 1915000000UL, 1930000000UL, 1995000000UL }, + + { BAND_TYPE_TDD, 33, 1900000000UL, 1920000000UL, 1900000000UL, 1920000000UL }, + { BAND_TYPE_TDD, 34, 2010000000UL, 2025000000UL, 2010000000UL, 2025000000UL }, + { BAND_TYPE_TDD, 35, 1850000000UL, 1910000000UL, 1850000000UL, 1910000000UL }, + { BAND_TYPE_TDD, 36, 1930000000UL, 1990000000UL, 1930000000UL, 1990000000UL }, + { BAND_TYPE_TDD, 37, 1910000000UL, 1930000000UL, 1910000000UL, 1930000000UL }, + { BAND_TYPE_TDD, 38, 2570000000UL, 2620000000UL, 2570000000UL, 2620000000UL }, + { BAND_TYPE_TDD, 39, 1880000000UL, 1920000000UL, 1880000000UL, 1920000000UL }, + { BAND_TYPE_TDD, 40, 2300000000UL, 2400000000UL, 2300000000UL, 2400000000UL }, + { BAND_TYPE_TDD, 41, 2496000000UL, 2690000000UL, 2496000000UL, 2690000000UL }, + { BAND_TYPE_TDD, 42, 3400000000UL, 3600000000UL, 3400000000UL, 3600000000UL }, + { BAND_TYPE_TDD, 43, 3600000000UL, 3800000000UL, 3600000000UL, 3800000000UL }, +}; + +typedef struct { + int band; + unsigned long dl_flow; + int dl_off; + int dl_offmin, dl_offmax; + unsigned long ul_flow; + int ul_off; + int ul_offmin, ul_offmax; +} earfcn; + +static earfcn earfcn_table[] = { + { 1, 2110000000UL, 0, 0, 599, 1920000000UL, 18000, 18000, 18599 }, + { 2, 1930000000UL, 600, 600, 1199, 1850000000UL, 18600, 18600, 19199 }, + { 3, 1805000000UL, 1200, 1200, 1949, 1710000000UL, 19200, 19200, 19949 }, + { 4, 2110000000UL, 1950, 1950, 2399, 1710000000UL, 19950, 19950, 20399 }, + { 5, 869000000UL, 2400, 2400, 2649, 824000000UL, 20400, 20400, 20649 }, + { 6, 875000000UL, 2650, 2650, 2749, 830000000UL, 20650, 20650, 20749 }, + { 7, 2620000000UL, 2750, 2750, 3449, 2500000000UL, 20750, 20750, 21449 }, + { 8, 925000000UL, 3450, 3450, 3799, 880000000UL, 21450, 21450, 21799 }, + { 9, 1844900000UL, 3800, 3800, 4149, 1749900000UL, 21800, 21800, 22149 }, + { 10, 2110000000UL, 4150, 4150, 4749, 1710000000UL, 22150, 22150, 22749 }, + { 11, 1475900000UL, 4750, 4750, 4949, 1427900000UL, 22750, 22750, 22949 }, + { 12, 729000000UL, 5010, 5010, 5179, 699000000UL, 23010, 23010, 23179 }, + { 13, 746000000UL, 5180, 5180, 5279, 777000000UL, 23180, 23180, 23279 }, + { 14, 758000000UL, 5280, 5280, 5379, 788000000UL, 23280, 23280, 23379 }, + { 17, 734000000UL, 5730, 5730, 5849, 704000000UL, 23730, 23730, 23849 }, + { 18, 860000000UL, 5850, 5850, 5999, 815000000UL, 23850, 23850, 23999 }, + { 19, 875000000UL, 6000, 6000, 6149, 830000000UL, 24000, 24000, 24149 }, + { 20, 791000000UL, 6150, 6150, 6449, 832000000UL, 24150, 24150, 24449 }, + { 21, 1495900000UL, 6450, 6450, 6599, 1447900000UL, 24450, 24450, 24599 }, + { 22, 3510000000UL, 6600, 6600, 7399, 3410000000UL, 24600, 24600, 25399 }, + { 23, 2180000000UL, 7500, 7500, 7699, 2000000000UL, 25500, 25500, 25699 }, + { 24, 1525000000UL, 7700, 7700, 8039, 1626500000UL, 25700, 25700, 26039 }, + { 25, 1930000000UL, 8040, 8040, 8689, 1850000000UL, 26040, 26040, 26689 }, + { 33, 1900000000UL, 36000, 36000, 36199, 1900000000UL, 36000, 36000, 36199 }, + { 34, 2010000000UL, 36200, 36200, 36349, 2010000000UL, 36200, 36200, 36349 }, + { 35, 1850000000UL, 36350, 36350, 36949, 1850000000UL, 36350, 36350, 36949 }, + { 36, 1930000000UL, 36950, 36950, 37549, 1930000000UL, 36950, 36950, 37549 }, + { 37, 1910000000UL, 37550, 37550, 37749, 1910000000UL, 37550, 37550, 37749 }, + { 38, 2570000000UL, 37750, 37750, 38249, 2570000000UL, 37750, 37750, 38249 }, + { 39, 1880000000UL, 38250, 38250, 38649, 1880000000UL, 38250, 38250, 38649 }, + { 40, 2300000000UL, 38650, 38650, 39649, 2300000000UL, 38650, 38650, 39649 }, + { 41, 2496000000UL, 39650, 39650, 41589, 2496000000UL, 39650, 39650, 41589 }, + { 42, 3400000000UL, 41590, 41590, 43589, 3400000000UL, 41590, 41590, 43589 }, + { 43, 3600000000UL, 43590, 43590, 45589, 3600000000UL, 43590, 43590, 45589 }, +}; + +int freq_to_arfcn10(int band, unsigned long freq) +{ + int N = sizeof(earfcn_table) / sizeof(earfcn_table[0]); + int i; + + for (i = 0; i < N; i++) if (bands[i].band == band) break; + if (i == N) return -1; + + if (!(bands[i].dl_minfreq < freq && freq < bands[i].dl_maxfreq)) + return -1; + + return (freq - earfcn_table[i].dl_flow) / 100000UL + earfcn_table[i].dl_off; +} //----------------------------------------------------------------------------- int @@ -3435,6 +4659,8 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( DRB_ToAddModList_t* DRB_configList = ue_context_pP->ue_context.DRB_configList2[xid]; SRB_ToAddModList_t* SRB_configList = ue_context_pP->ue_context.SRB_configList2[xid]; + DRB_ToReleaseList_t* DRB_Release_configList2 = ue_context_pP->ue_context.DRB_Release_configList2[xid]; + DRB_Identity_t* drb_id_p = NULL; T(T_ENB_RRC_CONNECTION_RECONFIGURATION_COMPLETE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); @@ -3468,7 +4694,8 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( ctxt_pP, SRB_configList, //NULL, //LG-RK 14/05/2014 SRB_configList, DRB_configList, - (DRB_ToReleaseList_t *) NULL, +// (DRB_ToReleaseList_t *) NULL, + DRB_Release_configList2, /*RC.rrc[ctxt_pP->module_id]->ciphering_algorithm[ue_mod_idP] | (RC.rrc[ctxt_pP->module_id]->integrity_algorithm[ue_mod_idP] << 4), */ @@ -3485,7 +4712,8 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( ctxt_pP, SRB_configList, // NULL, //LG-RK 14/05/2014 SRB_configList, DRB_configList, - (DRB_ToReleaseList_t *) NULL +// (DRB_ToReleaseList_t *) NULL + DRB_Release_configList2 #if defined(Rel10) || defined(Rel14) , (PMCH_InfoList_r9_t *) NULL #endif @@ -3512,6 +4740,8 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( SRB_configList->list.array[i]->srb_Identity); } } + free(SRB_configList); + ue_context_pP->ue_context.SRB_configList2[xid] = NULL; } // Loop through DRBs and establish if necessary @@ -3687,6 +4917,22 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( } } } + free(DRB_configList); + ue_context_pP->ue_context.DRB_configList2[xid] = NULL; + } + + if(DRB_Release_configList2 != NULL){ + for (i = 0; i < DRB_Release_configList2->list.count; i++) { + if (DRB_Release_configList2->list.array[i]) { + drb_id_p = DRB_Release_configList2->list.array[i]; + drb_id = *drb_id_p; + if (ue_context_pP->ue_context.DRB_active[drb_id] == 1) { + ue_context_pP->ue_context.DRB_active[drb_id] = 0; + } + } + } + free(DRB_Release_configList2); + ue_context_pP->ue_context.DRB_Release_configList2[xid] = NULL; } } @@ -3931,6 +5177,10 @@ openair_rrc_eNB_init( , configuration #endif ); + for (int ue_id = 0; ue_id < NUMBER_OF_UE_MAX; ue_id++) { + RC.rrc[ctxt.module_id]->carrier[CC_id].sizeof_paging[ue_id] = 0; + RC.rrc[ctxt.module_id]->carrier[CC_id].paging[ue_id] = (uint8_t*) malloc16(256); + } } rrc_init_global_param(); @@ -4070,7 +5320,7 @@ rrc_eNB_decode_ccch( T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); #ifdef RRC_MSG_PRINT - LOG_F(RRC,"[MSG] RRC Connection Reestablishement Request\n"); + LOG_F(RRC,"[MSG] RRC Connection Reestablishment Request\n"); for (i = 0; i < Srb_info->Rx_buffer.payload_size; i++) { LOG_F(RRC,"%02x ", ((uint8_t*)Srb_info->Rx_buffer.Payload)[i]); @@ -4105,9 +5355,141 @@ rrc_eNB_decode_ccch( } */ /* reject all reestablishment attempts for the moment */ - rrc_eNB_generate_RRCConnectionReestablishmentReject(ctxt_pP, - rrc_eNB_get_ue_context(RC.rrc[ctxt_pP->module_id], ctxt_pP->rnti), - CC_id); +// rrc_eNB_generate_RRCConnectionReestablishmentReject(ctxt_pP, +// rrc_eNB_get_ue_context(RC.rrc[ctxt_pP->module_id], ctxt_pP->rnti), +// CC_id); +{ + uint16_t c_rnti = 0; + + if (rrcConnectionReestablishmentRequest->ue_Identity.physCellId != RC.rrc[ctxt_pP->module_id]->carrier[CC_id].physCellId) { + LOG_E(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RRCConnectionReestablishmentRequest ue_Identity.physCellId(%ld) is not equal to current physCellId(%d), let's reject the UE\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + rrcConnectionReestablishmentRequest->ue_Identity.physCellId, + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].physCellId); + rrc_eNB_generate_RRCConnectionReestablishmentReject(ctxt_pP, ue_context_p, CC_id); + break; + } + LOG_D(RRC, "physCellId is %ld\n", rrcConnectionReestablishmentRequest->ue_Identity.physCellId); + + for (i = 0; i < rrcConnectionReestablishmentRequest->ue_Identity.shortMAC_I.size; i++) { + LOG_D(RRC, "rrcConnectionReestablishmentRequest->ue_Identity.shortMAC_I.buf[%d] = %x\n", + i, rrcConnectionReestablishmentRequest->ue_Identity.shortMAC_I.buf[i]); + } + + if (rrcConnectionReestablishmentRequest->ue_Identity.c_RNTI.size == 0 || + rrcConnectionReestablishmentRequest->ue_Identity.c_RNTI.size > 2) { + LOG_E(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RRCConnectionReestablishmentRequest c_RNTI range error, let's reject the UE\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + rrc_eNB_generate_RRCConnectionReestablishmentReject(ctxt_pP, ue_context_p, CC_id); + break; + + } + + c_rnti = BIT_STRING_to_uint16(&rrcConnectionReestablishmentRequest->ue_Identity.c_RNTI); + LOG_D(RRC, "c_rnti is %x\n", c_rnti); + + ue_context_p = rrc_eNB_get_ue_context(RC.rrc[ctxt_pP->module_id], c_rnti); + if (ue_context_p == NULL) { + LOG_E(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RRCConnectionReestablishmentRequest without UE context, let's reject the UE\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + rrc_eNB_generate_RRCConnectionReestablishmentReject(ctxt_pP, ue_context_p, CC_id); + break; + } + + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" UE context: %p\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + ue_context_p); + + // insert C-RNTI to map + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (reestablish_rnti_map[i][0] == 0) { + reestablish_rnti_map[i][0] = ctxt_pP->rnti; + reestablish_rnti_map[i][1] = c_rnti; + break; + } + } + LOG_D(RRC, "reestablish_rnti_map[%d] [0] %x, [1] %x\n", + i, reestablish_rnti_map[i][0], reestablish_rnti_map[i][1]); + +#if defined(ENABLE_ITTI) + ue_context_p->ue_context.reestablishment_cause = rrcConnectionReestablishmentRequest->reestablishmentCause; + LOG_D(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Accept connection reestablishment request from UE physCellId %ld cause %ld\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + rrcConnectionReestablishmentRequest->ue_Identity.physCellId, + ue_context_p->ue_context.reestablishment_cause); +#else + LOG_D(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Accept connection restablishment request for UE\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); +#endif + +#ifndef NO_RRM + send_msg(&S_rrc, msg_rrc_MR_attach_ind(ctxt_pP->module_id, Mac_id)); +#else + + ue_context_p->ue_context.primaryCC_id = CC_id; + + //LG COMMENT Idx = (ue_mod_idP * NB_RB_MAX) + DCCH; + Idx = DCCH; + // SRB1 + ue_context_p->ue_context.Srb1.Active = 1; + ue_context_p->ue_context.Srb1.Srb_info.Srb_id = Idx; + memcpy(&ue_context_p->ue_context.Srb1.Srb_info.Lchan_desc[0], + &DCCH_LCHAN_DESC, + LCHAN_DESC_SIZE); + memcpy(&ue_context_p->ue_context.Srb1.Srb_info.Lchan_desc[1], + &DCCH_LCHAN_DESC, + LCHAN_DESC_SIZE); + + // SRB2: set it to go through SRB1 with id 1 (DCCH) + ue_context_p->ue_context.Srb2.Active = 1; + ue_context_p->ue_context.Srb2.Srb_info.Srb_id = Idx; + memcpy(&ue_context_p->ue_context.Srb2.Srb_info.Lchan_desc[0], + &DCCH_LCHAN_DESC, + LCHAN_DESC_SIZE); + memcpy(&ue_context_p->ue_context.Srb2.Srb_info.Lchan_desc[1], + &DCCH_LCHAN_DESC, + LCHAN_DESC_SIZE); + + rrc_eNB_generate_RRCConnectionReestablishment(ctxt_pP, ue_context_p, CC_id); + LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT"CALLING RLC CONFIG SRB1 (rbid %d)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + Idx); + + MSC_LOG_TX_MESSAGE(MSC_RRC_ENB, + MSC_PDCP_ENB, + NULL, + 0, + MSC_AS_TIME_FMT" CONFIG_REQ UE %x SRB", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_p->ue_context.rnti); + + rrc_pdcp_config_asn1_req(ctxt_pP, + ue_context_p->ue_context.SRB_configList, + (DRB_ToAddModList_t *) NULL, + (DRB_ToReleaseList_t*) NULL, + 0xff, + NULL, + NULL, + NULL +# if defined(Rel10) || defined(Rel14) + , (PMCH_InfoList_r9_t *) NULL +# endif + ,NULL); + + rrc_rlc_config_asn1_req(ctxt_pP, + ue_context_p->ue_context.SRB_configList, + (DRB_ToAddModList_t*) NULL, + (DRB_ToReleaseList_t*) NULL +# if defined(Rel10) || defined(Rel14) + , (PMCH_InfoList_r9_t *) NULL +# endif + ); +#endif //NO_RRM + } break; case UL_CCCH_MessageType__c1_PR_rrcConnectionRequest: @@ -4187,7 +5569,8 @@ rrc_eNB_decode_ccch( ue_context_p->ue_context.ue_release_timer = 0; } else { LOG_I(RRC," S-TMSI doesn't exist, setting Initialue_identity_s_TMSI.m_tmsi to %p => %x\n",ue_context_p,m_tmsi); - ue_context_p = rrc_eNB_get_next_free_ue_context(ctxt_pP, NOT_A_RANDOM_UE_IDENTITY); +// ue_context_p = rrc_eNB_get_next_free_ue_context(ctxt_pP, NOT_A_RANDOM_UE_IDENTITY); + ue_context_p = rrc_eNB_get_next_free_ue_context(ctxt_pP,random_value); if (ue_context_p == NULL) LOG_E(RRC, "%s:%d:%s: rrc_eNB_get_next_free_ue_context returned NULL\n", __FILE__, __LINE__, __FUNCTION__); if (ue_context_p != NULL) { @@ -4233,6 +5616,7 @@ rrc_eNB_decode_ccch( #if defined(ENABLE_ITTI) ue_context_p->ue_context.establishment_cause = rrcConnectionRequest->establishmentCause; + ue_context_p->ue_context.reestablishment_cause = ReestablishmentCause_spare1; if (stmsi_received==0) LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Accept new connection from UE random UE identity (0x%" PRIx64 ") MME code %u TMSI %u cause %ld\n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), @@ -4365,6 +5749,12 @@ rrc_eNB_decode_dcch( UE_EUTRA_Capability_t *UE_EUTRA_Capability = NULL; int i; struct rrc_eNB_ue_context_s* ue_context_p = NULL; +#if defined(ENABLE_ITTI) +# if defined(ENABLE_USE_MME) + MessageDef * msg_delete_tunnels_p = NULL; + uint8_t xid; +#endif +#endif int dedicated_DRB=0; @@ -4525,12 +5915,53 @@ rrc_eNB_decode_dcch( # if defined(ENABLE_USE_MME) if (EPC_MODE_ENABLED == 1) { if (dedicated_DRB == 1){ - rrc_eNB_send_S1AP_E_RAB_SETUP_RESP(ctxt_pP, - ue_context_p, - ul_dcch_msg->message.choice.c1.choice.rrcConnectionReconfigurationComplete.rrc_TransactionIdentifier); +// rrc_eNB_send_S1AP_E_RAB_SETUP_RESP(ctxt_pP, +// ue_context_p, +// ul_dcch_msg->message.choice.c1.choice.rrcConnectionReconfigurationComplete.rrc_TransactionIdentifier); +if (ue_context_p->ue_context.nb_of_modify_e_rabs > 0) { + rrc_eNB_send_S1AP_E_RAB_MODIFY_RESP(ctxt_pP, + ue_context_p, + ul_dcch_msg->message.choice.c1.choice.rrcConnectionReconfigurationComplete.rrc_TransactionIdentifier); + + ue_context_p->ue_context.nb_of_modify_e_rabs = 0; + ue_context_p->ue_context.nb_of_failed_e_rabs = 0; + memset(ue_context_p->ue_context.modify_e_rab, 0, sizeof(ue_context_p->ue_context.modify_e_rab)); + for(int i = 0; i < NB_RB_MAX; i++) { + ue_context_p->ue_context.modify_e_rab[i].xid = -1; + } + + } else if(ue_context_p->ue_context.e_rab_release_command_flag == 1){ + xid = ul_dcch_msg->message.choice.c1.choice.rrcConnectionReconfigurationComplete.rrc_TransactionIdentifier; + ue_context_p->ue_context.e_rab_release_command_flag = 0; + //gtp tunnel delete + msg_delete_tunnels_p = itti_alloc_new_message(TASK_RRC_ENB, GTPV1U_ENB_DELETE_TUNNEL_REQ); + memset(>PV1U_ENB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p), 0, sizeof(GTPV1U_ENB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p))); + GTPV1U_ENB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p).rnti = ue_context_p->ue_context.rnti; + for(i = 0; i < NB_RB_MAX; i++){ + if(xid == ue_context_p->ue_context.e_rab[i].xid){ + GTPV1U_ENB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p).eps_bearer_id[GTPV1U_ENB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p).num_erab++] = ue_context_p->ue_context.enb_gtp_ebi[i]; + ue_context_p->ue_context.enb_gtp_teid[i] = 0; + memset(&ue_context_p->ue_context.enb_gtp_addrs[i], 0, sizeof(ue_context_p->ue_context.enb_gtp_addrs[i])); + ue_context_p->ue_context.enb_gtp_ebi[i] = 0; + } + } + itti_send_msg_to_task(TASK_GTPV1_U, ctxt_pP->instance, msg_delete_tunnels_p); + //S1AP_E_RAB_RELEASE_RESPONSE + rrc_eNB_send_S1AP_E_RAB_RELEASE_RESPONSE(ctxt_pP, + ue_context_p, + xid); + } else { + rrc_eNB_send_S1AP_E_RAB_SETUP_RESP(ctxt_pP, + ue_context_p, + ul_dcch_msg->message.choice.c1.choice.rrcConnectionReconfigurationComplete.rrc_TransactionIdentifier); + } }else { - rrc_eNB_send_S1AP_INITIAL_CONTEXT_SETUP_RESP(ctxt_pP, + if(ue_context_p->ue_context.reestablishment_cause == ReestablishmentCause_spare1){ + rrc_eNB_send_S1AP_INITIAL_CONTEXT_SETUP_RESP(ctxt_pP, ue_context_p); + } else { + ue_context_p->ue_context.reestablishment_cause = ReestablishmentCause_spare1; + } } } #else // establish a dedicated bearer @@ -4573,6 +6004,48 @@ rrc_eNB_decode_dcch( PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), DCCH, sdu_sizeP); + { + rnti_t reestablish_rnti = 0; + // select C-RNTI from map + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (reestablish_rnti_map[i][0] == ctxt_pP->rnti) { + reestablish_rnti = reestablish_rnti_map[i][1]; + ue_context_p = rrc_eNB_get_ue_context( + RC.rrc[ctxt_pP->module_id], + reestablish_rnti); + // clear currentC-RNTI from map + reestablish_rnti_map[i][0] = 0; + reestablish_rnti_map[i][1] = 0; + break; + } + } + LOG_D(RRC, "reestablish_rnti_map[%d] [0] %x, [1] %x\n", + i, reestablish_rnti_map[i][0], reestablish_rnti_map[i][1]); + + if (!ue_context_p) { + LOG_E(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RRCConnectionReestablishmentComplete without UE context, falt\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + break; + } + + if (ul_dcch_msg->message.choice.c1.choice.rrcConnectionReestablishmentComplete.criticalExtensions.present == + RRCConnectionReestablishmentComplete__criticalExtensions_PR_rrcConnectionReestablishmentComplete_r8) { + rrc_eNB_process_RRCConnectionReestablishmentComplete(ctxt_pP, reestablish_rnti, ue_context_p, + ul_dcch_msg->message.choice.c1.choice.rrcConnectionReestablishmentComplete.rrc_TransactionIdentifier, + &ul_dcch_msg->message.choice.c1.choice.rrcConnectionReestablishmentComplete.criticalExtensions.choice.rrcConnectionReestablishmentComplete_r8); + +#if defined(FLEXRAN_AGENT_SB_IF) + //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future + if (mac_agent_registered[ctxt_pP->module_id]) { + agent_mac_xface[ctxt_pP->eNB_index]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, + ue_context_p->ue_id_rnti, + PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_ACTIVATED); + } +#endif + } + ue_context_p->ue_context.ue_release_timer = 0; + } break; case UL_DCCH_MessageType__c1_PR_rrcConnectionSetupComplete: @@ -5024,13 +6497,22 @@ rrc_enb_task( break; case S1AP_PAGING_IND: - LOG_E(RRC, "[eNB %d] Received not yet implemented message %s\n", instance, msg_name_p); + LOG_D(RRC, "[eNB %d] Received Paging message from S1AP: %s\n", instance, msg_name_p); + rrc_eNB_process_PAGING_IND(msg_p, msg_name_p, instance); break; case S1AP_E_RAB_SETUP_REQ: rrc_eNB_process_S1AP_E_RAB_SETUP_REQ(msg_p, msg_name_p, instance); LOG_D(RRC, "[eNB %d] Received the message %s\n", instance, msg_name_p); break; + + case S1AP_E_RAB_MODIFY_REQ: + rrc_eNB_process_S1AP_E_RAB_MODIFY_REQ(msg_p, msg_name_p, instance); + break; + + case S1AP_E_RAB_RELEASE_COMMAND: + rrc_eNB_process_S1AP_E_RAB_RELEASE_COMMAND(msg_p, msg_name_p, instance); + break; case S1AP_UE_CONTEXT_RELEASE_REQ: rrc_eNB_process_S1AP_UE_CONTEXT_RELEASE_REQ(msg_p, msg_name_p, instance); diff --git a/openair2/RRC/LITE/rrc_eNB_GTPV1U.c b/openair2/RRC/LITE/rrc_eNB_GTPV1U.c index 9aca049166..e5f2c5aaae 100644 --- a/openair2/RRC/LITE/rrc_eNB_GTPV1U.c +++ b/openair2/RRC/LITE/rrc_eNB_GTPV1U.c @@ -47,7 +47,8 @@ extern RAN_CONTEXT_t RC; int rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP( const protocol_ctxt_t* const ctxt_pP, - const gtpv1u_enb_create_tunnel_resp_t * const create_tunnel_resp_pP + const gtpv1u_enb_create_tunnel_resp_t * const create_tunnel_resp_pP, + uint8_t *inde_list ) { rnti_t rnti; @@ -66,15 +67,18 @@ rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP( for (i = 0; i < create_tunnel_resp_pP->num_tunnels; i++) { - ue_context_p->ue_context.enb_gtp_teid[i+ue_context_p->ue_context.setup_e_rabs] = create_tunnel_resp_pP->enb_S1u_teid[i]; - ue_context_p->ue_context.enb_gtp_addrs[i+ue_context_p->ue_context.setup_e_rabs] = create_tunnel_resp_pP->enb_addr; - ue_context_p->ue_context.enb_gtp_ebi[i+ue_context_p->ue_context.setup_e_rabs] = create_tunnel_resp_pP->eps_bearer_id[i]; +// ue_context_p->ue_context.enb_gtp_teid[i+ue_context_p->ue_context.setup_e_rabs] = create_tunnel_resp_pP->enb_S1u_teid[i]; +// ue_context_p->ue_context.enb_gtp_addrs[i+ue_context_p->ue_context.setup_e_rabs] = create_tunnel_resp_pP->enb_addr; +// ue_context_p->ue_context.enb_gtp_ebi[i+ue_context_p->ue_context.setup_e_rabs] = create_tunnel_resp_pP->eps_bearer_id[i]; + ue_context_p->ue_context.enb_gtp_teid[inde_list[i]] = create_tunnel_resp_pP->enb_S1u_teid[i]; + ue_context_p->ue_context.enb_gtp_addrs[inde_list[i]] = create_tunnel_resp_pP->enb_addr; + ue_context_p->ue_context.enb_gtp_ebi[inde_list[i]] = create_tunnel_resp_pP->eps_bearer_id[i]; LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP tunnel (%u, %u) bearer UE context index %u, msg index %u, id %u, gtp addr len %d \n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), create_tunnel_resp_pP->enb_S1u_teid[i], - ue_context_p->ue_context.enb_gtp_teid[i+ue_context_p->ue_context.setup_e_rabs], - i+ue_context_p->ue_context.setup_e_rabs, + ue_context_p->ue_context.enb_gtp_teid[inde_list[i]], + inde_list[i], i, create_tunnel_resp_pP->eps_bearer_id[i], create_tunnel_resp_pP->enb_addr.length); diff --git a/openair2/RRC/LITE/rrc_eNB_GTPV1U.h b/openair2/RRC/LITE/rrc_eNB_GTPV1U.h index 981c3f8d3b..aedbdeac5e 100644 --- a/openair2/RRC/LITE/rrc_eNB_GTPV1U.h +++ b/openair2/RRC/LITE/rrc_eNB_GTPV1U.h @@ -43,7 +43,8 @@ int rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP( const protocol_ctxt_t* const ctxt_pP, - const gtpv1u_enb_create_tunnel_resp_t * const create_tunnel_resp_pP + const gtpv1u_enb_create_tunnel_resp_t * const create_tunnel_resp_pP, + uint8_t *inde_list ); # endif diff --git a/openair2/RRC/LITE/rrc_eNB_S1AP.c b/openair2/RRC/LITE/rrc_eNB_S1AP.c index 55adb217fa..c1a5b67b0f 100644 --- a/openair2/RRC/LITE/rrc_eNB_S1AP.c +++ b/openair2/RRC/LITE/rrc_eNB_S1AP.c @@ -342,6 +342,8 @@ static void process_eNB_security_key ( /* Saves the security key */ memcpy (ue_context_pP->ue_context.kenb, security_key_pP, SECURITY_KEY_LENGTH); + memset (ue_context_pP->ue_context.nh, 0, SECURITY_KEY_LENGTH); + ue_context_pP->ue_context.nh_ncc = -1; for (i = 0; i < 32; i++) { sprintf(&ascii_buffer[2 * i], "%02X", ue_context_pP->ue_context.kenb[i]); @@ -355,7 +357,7 @@ static void process_eNB_security_key ( //------------------------------------------------------------------------------ -static void +void rrc_pdcp_config_security( const protocol_ctxt_t* const ctxt_pP, rrc_eNB_ue_context_t* const ue_context_pP, @@ -890,6 +892,7 @@ int rrc_eNB_process_S1AP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, const char //MessageDef *message_gtpv1u_p = NULL; gtpv1u_enb_create_tunnel_req_t create_tunnel_req; gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp; + uint8_t inde_list[NB_RB_MAX - 3]={0}; struct rrc_eNB_ue_context_s* ue_context_p = NULL; protocol_ctxt_t ctxt; @@ -935,10 +938,12 @@ int rrc_eNB_process_S1AP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, const char memcpy(&create_tunnel_req.sgw_addr[i], &S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).e_rab_param[i].sgw_addr, sizeof(transport_layer_addr_t)); + inde_list[create_tunnel_req.num_tunnels]= i; + create_tunnel_req.num_tunnels++; } create_tunnel_req.rnti = ue_context_p->ue_context.rnti; // warning put zero above - create_tunnel_req.num_tunnels = i; +// create_tunnel_req.num_tunnels = i; gtpv1u_create_s1u_tunnel( instance, @@ -947,7 +952,8 @@ int rrc_eNB_process_S1AP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, const char rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP( &ctxt, - &create_tunnel_resp); + &create_tunnel_resp, + &inde_list[0]); ue_context_p->ue_context.setup_e_rabs=ue_context_p->ue_context.nb_of_e_rabs; } @@ -1263,9 +1269,12 @@ int rrc_eNB_process_S1AP_E_RAB_SETUP_REQ(MessageDef *msg_p, const char *msg_name uint32_t eNB_ue_s1ap_id; gtpv1u_enb_create_tunnel_req_t create_tunnel_req; gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp; + uint8_t inde_list[NB_RB_MAX - 3]={0}; struct rrc_eNB_ue_context_s* ue_context_p = NULL; protocol_ctxt_t ctxt; + uint8_t e_rab_done; + ue_initial_id = S1AP_E_RAB_SETUP_REQ (msg_p).ue_initial_id; eNB_ue_s1ap_id = S1AP_E_RAB_SETUP_REQ (msg_p).eNB_ue_s1ap_id; ue_context_p = rrc_eNB_get_ue_context_from_s1ap_ids(instance, ue_initial_id, eNB_ue_s1ap_id); @@ -1296,35 +1305,46 @@ int rrc_eNB_process_S1AP_E_RAB_SETUP_REQ(MessageDef *msg_p, const char *msg_name memset(&create_tunnel_req, 0 , sizeof(create_tunnel_req)); uint8_t nb_e_rabs_tosetup = S1AP_E_RAB_SETUP_REQ (msg_p).nb_e_rabs_tosetup; + e_rab_done = 0; // keep the previous bearer // the index for the rec for (i = 0; - i < nb_e_rabs_tosetup; + // i < nb_e_rabs_tosetup; + i < NB_RB_MAX - 3; // loop all e-rabs in e_rab[] i++) { - if (ue_context_p->ue_context.e_rab[i+ue_context_p->ue_context.setup_e_rabs].status == E_RAB_STATUS_DONE) - LOG_W(RRC,"E-RAB already configured, reconfiguring\n"); - ue_context_p->ue_context.e_rab[i+ue_context_p->ue_context.setup_e_rabs].status = E_RAB_STATUS_NEW; - ue_context_p->ue_context.e_rab[i+ue_context_p->ue_context.setup_e_rabs].param = S1AP_E_RAB_SETUP_REQ (msg_p).e_rab_setup_params[i]; + //if (ue_context_p->ue_context.e_rab[i+ue_context_p->ue_context.setup_e_rabs].status == E_RAB_STATUS_DONE) + // LOG_W(RRC,"E-RAB already configured, reconfiguring\n"); + // check e-rab status, if e rab status is greater than E_RAB_STATUS_DONE, don't not config this one + if(ue_context_p->ue_context.e_rab[i].status >= E_RAB_STATUS_DONE) + continue; + //ue_context_p->ue_context.e_rab[i+ue_context_p->ue_context.setup_e_rabs].status = E_RAB_STATUS_NEW; + //ue_context_p->ue_context.e_rab[i+ue_context_p->ue_context.setup_e_rabs].param = S1AP_E_RAB_SETUP_REQ (msg_p).e_rab_setup_params[i]; + ue_context_p->ue_context.e_rab[i].status = E_RAB_STATUS_NEW; + ue_context_p->ue_context.e_rab[i].param = S1AP_E_RAB_SETUP_REQ (msg_p).e_rab_setup_params[e_rab_done]; + create_tunnel_req.eps_bearer_id[e_rab_done] = S1AP_E_RAB_SETUP_REQ (msg_p).e_rab_setup_params[e_rab_done].e_rab_id; + create_tunnel_req.sgw_S1u_teid[e_rab_done] = S1AP_E_RAB_SETUP_REQ (msg_p).e_rab_setup_params[e_rab_done].gtp_teid; - create_tunnel_req.eps_bearer_id[i] = S1AP_E_RAB_SETUP_REQ (msg_p).e_rab_setup_params[i].e_rab_id; - create_tunnel_req.sgw_S1u_teid[i] = S1AP_E_RAB_SETUP_REQ (msg_p).e_rab_setup_params[i].gtp_teid; - - memcpy(&create_tunnel_req.sgw_addr[i], - & S1AP_E_RAB_SETUP_REQ (msg_p).e_rab_setup_params[i].sgw_addr, + memcpy(&create_tunnel_req.sgw_addr[e_rab_done], + & S1AP_E_RAB_SETUP_REQ (msg_p).e_rab_setup_params[e_rab_done].sgw_addr, sizeof(transport_layer_addr_t)); LOG_I(RRC,"E_RAB setup REQ: local index %d teid %u, eps id %d \n", - i+ue_context_p->ue_context.setup_e_rabs, - create_tunnel_req.sgw_S1u_teid[i], + i, + create_tunnel_req.sgw_S1u_teid[e_rab_done], create_tunnel_req.eps_bearer_id[i] ); + inde_list[e_rab_done] = i; + e_rab_done++; + if(e_rab_done >= nb_e_rabs_tosetup){ + break; + } } ue_context_p->ue_context.nb_of_e_rabs=nb_e_rabs_tosetup; create_tunnel_req.rnti = ue_context_p->ue_context.rnti; // warning put zero above - create_tunnel_req.num_tunnels = i; + create_tunnel_req.num_tunnels = e_rab_done; // NN: not sure if we should create a new tunnel: need to check teid, etc. gtpv1u_create_s1u_tunnel( @@ -1334,7 +1354,8 @@ int rrc_eNB_process_S1AP_E_RAB_SETUP_REQ(MessageDef *msg_p, const char *msg_name rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP( &ctxt, - &create_tunnel_resp); + &create_tunnel_resp, + &inde_list[0]); ue_context_p->ue_context.setup_e_rabs+=nb_e_rabs_tosetup; @@ -1398,12 +1419,17 @@ int rrc_eNB_send_S1AP_E_RAB_SETUP_RESP(const protocol_ctxt_t* const ctxt_pP, S1AP_E_RAB_SETUP_RESP (msg_p).e_rabs_failed[e_rabs_failed].e_rab_id = ue_context_pP->ue_context.e_rab[e_rab].param.e_rab_id; e_rabs_failed++; // TODO add cause when it will be integrated - } - + } S1AP_E_RAB_SETUP_RESP (msg_p).nb_of_e_rabs = e_rabs_done; S1AP_E_RAB_SETUP_RESP (msg_p).nb_of_e_rabs_failed = e_rabs_failed; // NN: add conditions for e_rabs_failed + } else { + /*debug info for the xid */ + LOG_D(RRC,"xid does not corresponds (context e_rab index %d, status %d, xid %d/%d) \n ", + e_rab, ue_context_pP->ue_context.e_rab[e_rab].status, xid, ue_context_pP->ue_context.e_rab[e_rab].xid); + } + } if ((e_rabs_done > 0) ){ LOG_I(RRC,"S1AP_E_RAB_SETUP_RESP: sending the message: nb_of_erabs %d, total e_rabs %d, index %d\n", @@ -1422,17 +1448,528 @@ int rrc_eNB_send_S1AP_E_RAB_SETUP_RESP(const protocol_ctxt_t* const ctxt_pP, itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, msg_p); } - - } else { - /*debug info for the xid */ - LOG_D(RRC,"xid does not corresponds (context e_rab index %d, status %d, xid %d/%d) \n ", - e_rab, ue_context_pP->ue_context.e_rab[e_rab].status, xid, ue_context_pP->ue_context.e_rab[e_rab].xid); - } - + for(int i = 0; i < NB_RB_MAX; i++) { + ue_context_pP->ue_context.e_rab[i].xid = -1; } return 0; } +int rrc_eNB_process_S1AP_E_RAB_MODIFY_REQ(MessageDef *msg_p, const char *msg_name, instance_t instance) +{ + int i; + uint16_t ue_initial_id; + uint32_t eNB_ue_s1ap_id; + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + protocol_ctxt_t ctxt; + + ue_initial_id = S1AP_E_RAB_MODIFY_REQ (msg_p).ue_initial_id; + eNB_ue_s1ap_id = S1AP_E_RAB_MODIFY_REQ (msg_p).eNB_ue_s1ap_id; + ue_context_p = rrc_eNB_get_ue_context_from_s1ap_ids(instance, ue_initial_id, eNB_ue_s1ap_id); + LOG_D(RRC, "[eNB %d] Received %s: ue_initial_id %d, eNB_ue_s1ap_id %d, nb_of_e_rabs %d\n", + instance, msg_name, ue_initial_id, eNB_ue_s1ap_id, S1AP_E_RAB_MODIFY_REQ (msg_p).nb_e_rabs_tomodify); + + if (ue_context_p == NULL) { + /* Can not associate this message to an UE index, send a failure to S1AP and discard it! */ + LOG_W(RRC, "[eNB %d] In S1AP_E_RAB_MODIFY_REQ: unknown UE from S1AP ids (%d, %d)\n", instance, ue_initial_id, eNB_ue_s1ap_id); + int nb_of_e_rabs_failed = 0; + MessageDef *msg_fail_p = NULL; + + msg_fail_p = itti_alloc_new_message (TASK_RRC_ENB, S1AP_E_RAB_MODIFY_RESP); + + S1AP_E_RAB_MODIFY_RESP (msg_fail_p).eNB_ue_s1ap_id = S1AP_E_RAB_MODIFY_REQ (msg_p).eNB_ue_s1ap_id; + S1AP_E_RAB_MODIFY_RESP (msg_fail_p).nb_of_e_rabs = 0; + + for (nb_of_e_rabs_failed = 0; nb_of_e_rabs_failed < S1AP_E_RAB_MODIFY_REQ (msg_p).nb_e_rabs_tomodify; nb_of_e_rabs_failed++) { + S1AP_E_RAB_MODIFY_RESP (msg_fail_p).e_rabs_failed[nb_of_e_rabs_failed].e_rab_id = + S1AP_E_RAB_MODIFY_REQ (msg_p).e_rab_modify_params[nb_of_e_rabs_failed].e_rab_id; + S1AP_E_RAB_MODIFY_RESP (msg_fail_p).e_rabs_failed[nb_of_e_rabs_failed].cause = S1AP_CAUSE_RADIO_NETWORK; + S1AP_E_RAB_MODIFY_RESP (msg_fail_p).e_rabs_failed[nb_of_e_rabs_failed].cause_value = 31;//S1ap_CauseRadioNetwork_multiple_E_RAB_ID_instances; + } + S1AP_E_RAB_MODIFY_RESP (msg_fail_p).nb_of_e_rabs_failed = nb_of_e_rabs_failed; + + itti_send_msg_to_task(TASK_S1AP, instance, msg_fail_p); + return (-1); + + } else { + PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); + ue_context_p->ue_context.eNB_ue_s1ap_id = eNB_ue_s1ap_id; + + /* Save e RAB information for later */ + { + int j; + boolean_t is_treated[S1AP_MAX_E_RAB] = {FALSE}; + uint8_t nb_of_failed_e_rabs = 0; + + // keep the previous bearer + // the index for the rec + for (i = 0; i < S1AP_E_RAB_MODIFY_REQ (msg_p).nb_e_rabs_tomodify; i++) { + if (is_treated[i] == TRUE) { + // already treated + continue; + } + for (j = i+1; j < S1AP_E_RAB_MODIFY_REQ (msg_p).nb_e_rabs_tomodify; j++) { + if (is_treated[j] == FALSE && + S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[j].e_rab_id == S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id) { + // handle multiple E-RAB ID + ue_context_p->ue_context.modify_e_rab[j].status = E_RAB_STATUS_NEW; + ue_context_p->ue_context.modify_e_rab[j].param.e_rab_id = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[j].e_rab_id; + ue_context_p->ue_context.modify_e_rab[j].cause = S1AP_CAUSE_RADIO_NETWORK; + ue_context_p->ue_context.modify_e_rab[j].cause_value = 31;//S1ap_CauseRadioNetwork_multiple_E_RAB_ID_instances; + nb_of_failed_e_rabs++; + is_treated[i] = TRUE; + is_treated[j] = TRUE; + } + } + if (is_treated[i] == TRUE) { + // handle multiple E-RAB ID + ue_context_p->ue_context.modify_e_rab[i].status = E_RAB_STATUS_NEW; + ue_context_p->ue_context.modify_e_rab[i].param.e_rab_id = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id; + ue_context_p->ue_context.modify_e_rab[i].cause = S1AP_CAUSE_RADIO_NETWORK; + ue_context_p->ue_context.modify_e_rab[i].cause_value = 31;//S1ap_CauseRadioNetwork_multiple_E_RAB_ID_instances; + nb_of_failed_e_rabs++; + continue; + } + + if (S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].nas_pdu.length == 0) { + // nas_pdu.length == 0 + ue_context_p->ue_context.modify_e_rab[i].status = E_RAB_STATUS_NEW; + ue_context_p->ue_context.modify_e_rab[i].param.e_rab_id = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id; + ue_context_p->ue_context.modify_e_rab[i].cause = S1AP_CAUSE_NAS; + ue_context_p->ue_context.modify_e_rab[i].cause_value = 3;//S1ap_CauseNas_unspecified; + nb_of_failed_e_rabs++; + is_treated[i] = TRUE; + continue; + } + + for (j = 0; j < NB_RB_MAX-3; j++) { + if (ue_context_p->ue_context.e_rab[j].param.e_rab_id == S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id) { + if(ue_context_p->ue_context.e_rab[j].status == E_RAB_STATUS_TORELEASE || ue_context_p->ue_context.e_rab[j].status == E_RAB_STATUS_DONE){ + break; + } + ue_context_p->ue_context.modify_e_rab[i].status = E_RAB_STATUS_NEW; + ue_context_p->ue_context.modify_e_rab[i].cause = S1AP_CAUSE_NOTHING; + ue_context_p->ue_context.modify_e_rab[i].param.e_rab_id = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id; + ue_context_p->ue_context.modify_e_rab[i].param.qos = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].qos; + ue_context_p->ue_context.modify_e_rab[i].param.nas_pdu.length = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].nas_pdu.length; + ue_context_p->ue_context.modify_e_rab[i].param.nas_pdu.buffer = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].nas_pdu.buffer; + ue_context_p->ue_context.modify_e_rab[i].param.sgw_addr = ue_context_p->ue_context.e_rab[j].param.sgw_addr; + ue_context_p->ue_context.modify_e_rab[i].param.gtp_teid = ue_context_p->ue_context.e_rab[j].param.gtp_teid; + + is_treated[i] = TRUE; + break; + } + } + + if (is_treated[i] == FALSE) { + // handle Unknown E-RAB ID + ue_context_p->ue_context.modify_e_rab[i].status = E_RAB_STATUS_NEW; + ue_context_p->ue_context.modify_e_rab[i].param.e_rab_id = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id; + ue_context_p->ue_context.modify_e_rab[i].cause = S1AP_CAUSE_RADIO_NETWORK; + ue_context_p->ue_context.modify_e_rab[i].cause_value = 30;//S1ap_CauseRadioNetwork_unknown_E_RAB_ID; + nb_of_failed_e_rabs++; + is_treated[i] = TRUE; + } + } + + ue_context_p->ue_context.nb_of_modify_e_rabs = S1AP_E_RAB_MODIFY_REQ (msg_p).nb_e_rabs_tomodify; + ue_context_p->ue_context.nb_of_failed_e_rabs = nb_of_failed_e_rabs; + } + + /* TODO parameters yet to process ... */ + { + // S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).ue_ambr; + } + + if (ue_context_p->ue_context.nb_of_failed_e_rabs < ue_context_p->ue_context.nb_of_modify_e_rabs) { + if (0 == rrc_eNB_modify_dedicatedRRCConnectionReconfiguration(&ctxt, ue_context_p, 0)) { + return (0); + } + } + + { + int nb_of_e_rabs_failed = 0; + MessageDef *msg_fail_p = NULL; + + msg_fail_p = itti_alloc_new_message (TASK_RRC_ENB, S1AP_E_RAB_MODIFY_RESP); + + S1AP_E_RAB_MODIFY_RESP (msg_fail_p).eNB_ue_s1ap_id = S1AP_E_RAB_MODIFY_REQ (msg_p).eNB_ue_s1ap_id; +// S1AP_E_RAB_MODIFY_RESP (msg_fail_p).e_rabs[S1AP_MAX_E_RAB]; + S1AP_E_RAB_MODIFY_RESP (msg_fail_p).nb_of_e_rabs = 0; + + for(nb_of_e_rabs_failed = 0; nb_of_e_rabs_failed < ue_context_p->ue_context.nb_of_failed_e_rabs; nb_of_e_rabs_failed++) { + S1AP_E_RAB_MODIFY_RESP (msg_fail_p).e_rabs_failed[nb_of_e_rabs_failed].e_rab_id = + ue_context_p->ue_context.modify_e_rab[nb_of_e_rabs_failed].param.e_rab_id; + S1AP_E_RAB_MODIFY_RESP (msg_fail_p).e_rabs_failed[nb_of_e_rabs_failed].cause = ue_context_p->ue_context.modify_e_rab[nb_of_e_rabs_failed].cause; + } + S1AP_E_RAB_MODIFY_RESP (msg_fail_p).nb_of_e_rabs_failed = nb_of_e_rabs_failed; + + itti_send_msg_to_task (TASK_S1AP, instance, msg_fail_p); + + ue_context_p->ue_context.nb_of_modify_e_rabs = 0; + ue_context_p->ue_context.nb_of_failed_e_rabs = 0; + memset(ue_context_p->ue_context.modify_e_rab, 0, sizeof(ue_context_p->ue_context.modify_e_rab)); + + return (0); + } + } // end of ue_context_p != NULL +} + +/*NN: careful about the typcast of xid (long -> uint8_t*/ +int rrc_eNB_send_S1AP_E_RAB_MODIFY_RESP(const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + uint8_t xid ) { + + MessageDef *msg_p = NULL; + int i; + int e_rab; + int e_rabs_done = 0; + int e_rabs_failed = 0; + msg_p = itti_alloc_new_message (TASK_RRC_ENB, S1AP_E_RAB_MODIFY_RESP); + S1AP_E_RAB_MODIFY_RESP (msg_p).eNB_ue_s1ap_id = ue_context_pP->ue_context.eNB_ue_s1ap_id; + + for (e_rab = 0; e_rab < ue_context_pP->ue_context.nb_of_modify_e_rabs; e_rab++) { + + /* only respond to the corresponding transaction */ + if (xid == ue_context_pP->ue_context.modify_e_rab[e_rab].xid) { + if (ue_context_pP->ue_context.modify_e_rab[e_rab].status == E_RAB_STATUS_DONE) { + for (i = 0; i < ue_context_pP->ue_context.setup_e_rabs; i++) { + if (ue_context_pP->ue_context.modify_e_rab[e_rab].param.e_rab_id == ue_context_pP->ue_context.e_rab[i].param.e_rab_id) { + // Update ue_context_pP->ue_context.e_rab + ue_context_pP->ue_context.e_rab[i].status = E_RAB_STATUS_ESTABLISHED; + ue_context_pP->ue_context.e_rab[i].param.qos = ue_context_pP->ue_context.modify_e_rab[e_rab].param.qos; + ue_context_pP->ue_context.e_rab[i].cause = S1AP_CAUSE_NOTHING; + break; + } + } + if (i < ue_context_pP->ue_context.setup_e_rabs) { + S1AP_E_RAB_MODIFY_RESP (msg_p).e_rabs[e_rabs_done].e_rab_id = ue_context_pP->ue_context.modify_e_rab[e_rab].param.e_rab_id; + // TODO add other information from S1-U when it will be integrated + + LOG_D (RRC,"enb_gtp_addr (msg index %d, e_rab index %d, status %d, xid %d): nb_of_modify_e_rabs %d, e_rab_id %d \n ", + e_rabs_done, e_rab, ue_context_pP->ue_context.modify_e_rab[e_rab].status, xid, + ue_context_pP->ue_context.nb_of_modify_e_rabs, + S1AP_E_RAB_MODIFY_RESP (msg_p).e_rabs[e_rabs_done].e_rab_id); + + e_rabs_done++; + } else { + // unexpected + S1AP_E_RAB_MODIFY_RESP (msg_p).e_rabs_failed[e_rabs_failed].e_rab_id = ue_context_pP->ue_context.modify_e_rab[e_rab].param.e_rab_id; + + S1AP_E_RAB_MODIFY_RESP (msg_p).e_rabs_failed[e_rabs_failed].cause = S1AP_CAUSE_RADIO_NETWORK; + S1AP_E_RAB_MODIFY_RESP (msg_p).e_rabs_failed[e_rabs_failed].cause_value = 30;//S1ap_CauseRadioNetwork_unknown_E_RAB_ID; + + e_rabs_failed++; + } + } else if ((ue_context_pP->ue_context.modify_e_rab[e_rab].status == E_RAB_STATUS_NEW) || + (ue_context_pP->ue_context.modify_e_rab[e_rab].status == E_RAB_STATUS_ESTABLISHED)){ + LOG_D (RRC,"E-RAB is NEW or already ESTABLISHED\n"); + } else { /* status == E_RAB_STATUS_FAILED; */ + S1AP_E_RAB_MODIFY_RESP (msg_p).e_rabs_failed[e_rabs_failed].e_rab_id = ue_context_pP->ue_context.modify_e_rab[e_rab].param.e_rab_id; + // add failure cause when defined + S1AP_E_RAB_MODIFY_RESP (msg_p).e_rabs_failed[e_rabs_failed].cause = ue_context_pP->ue_context.modify_e_rab[e_rab].cause; + + e_rabs_failed++; + } + } else { + /*debug info for the xid */ + LOG_D(RRC,"xid does not corresponds (context e_rab index %d, status %d, xid %d/%d) \n ", + e_rab, ue_context_pP->ue_context.modify_e_rab[e_rab].status, xid, ue_context_pP->ue_context.modify_e_rab[e_rab].xid); + } + } + + + S1AP_E_RAB_MODIFY_RESP (msg_p).nb_of_e_rabs = e_rabs_done; + S1AP_E_RAB_MODIFY_RESP (msg_p).nb_of_e_rabs_failed = e_rabs_failed; + // NN: add conditions for e_rabs_failed + if (e_rabs_done > 0 || e_rabs_failed > 0) { + LOG_D(RRC,"S1AP_E_RAB_MODIFY_RESP: sending the message: nb_of_modify_e_rabs %d, total e_rabs %d, index %d\n", + ue_context_pP->ue_context.nb_of_modify_e_rabs, ue_context_pP->ue_context.setup_e_rabs, e_rab); +MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_S1AP_ENB, + (const char *)&S1AP_E_RAB_SETUP_RESP (msg_p), + sizeof(s1ap_e_rab_setup_resp_t), + MSC_AS_TIME_FMT" E_RAB_MODIFY_RESP UE %X eNB_ue_s1ap_id %u e_rabs:%u succ %u fail", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_pP->ue_id_rnti, + S1AP_E_RAB_MODIFY_RESP (msg_p).eNB_ue_s1ap_id, + e_rabs_done, e_rabs_failed); + + itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, msg_p); + } + + return 0; +} +int rrc_eNB_process_S1AP_E_RAB_RELEASE_COMMAND(MessageDef *msg_p, const char *msg_name, instance_t instance){ + uint16_t mme_ue_s1ap_id; + uint32_t eNB_ue_s1ap_id; + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + protocol_ctxt_t ctxt; + e_rab_release_t e_rab_release_params[S1AP_MAX_E_RAB]; + uint8_t nb_e_rabs_torelease; + int erab; + int i; + uint8_t b_existed,is_existed; + uint8_t xid; + uint8_t e_rab_release_drb; + MessageDef * msg_delete_tunnels_p = NULL; + e_rab_release_drb = 0; + memcpy(&e_rab_release_params[0], &(S1AP_E_RAB_RELEASE_COMMAND (msg_p).e_rab_release_params[0]), sizeof(e_rab_release_t)*S1AP_MAX_E_RAB); + + mme_ue_s1ap_id = S1AP_E_RAB_RELEASE_COMMAND (msg_p).mme_ue_s1ap_id; + eNB_ue_s1ap_id = S1AP_E_RAB_RELEASE_COMMAND (msg_p).eNB_ue_s1ap_id; + nb_e_rabs_torelease = S1AP_E_RAB_RELEASE_COMMAND (msg_p).nb_e_rabs_torelease; + ue_context_p = rrc_eNB_get_ue_context_from_s1ap_ids(instance, UE_INITIAL_ID_INVALID, eNB_ue_s1ap_id); + if(ue_context_p != NULL){ + PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); + + xid = rrc_eNB_get_next_transaction_identifier(ctxt.module_id); + + LOG_D(RRC,"S1AP-E-RAB Release Command: MME_UE_S1AP_ID %d ENB_UE_S1AP_ID %d release_e_rabs %d \n", + mme_ue_s1ap_id, eNB_ue_s1ap_id,nb_e_rabs_torelease); + for(erab = 0; erab < nb_e_rabs_torelease; erab++){ + b_existed = 0; + is_existed = 0; + for ( i = erab-1; i>= 0; i--){ + if (e_rab_release_params[erab].e_rab_id == e_rab_release_params[i].e_rab_id){ + is_existed = 1; + break; + } + } + if(is_existed == 1){ + //e_rab_id is existed + continue; + } + for ( i = 0; i < NB_RB_MAX; i++){ + if (e_rab_release_params[erab].e_rab_id == ue_context_p->ue_context.e_rab[i].param.e_rab_id){ + b_existed = 1; + break; + } + } + if(b_existed == 0) { + //no e_rab_id + ue_context_p->ue_context.e_rabs_release_failed[ue_context_p->ue_context.nb_release_of_e_rabs].e_rab_id = e_rab_release_params[erab].e_rab_id; + ue_context_p->ue_context.e_rabs_release_failed[ue_context_p->ue_context.nb_release_of_e_rabs].cause = S1AP_CAUSE_RADIO_NETWORK; + ue_context_p->ue_context.e_rabs_release_failed[ue_context_p->ue_context.nb_release_of_e_rabs].cause_value = 30; + ue_context_p->ue_context.nb_release_of_e_rabs++; + } else { + if(ue_context_p->ue_context.e_rab[i].status == E_RAB_STATUS_FAILED){ + ue_context_p->ue_context.e_rab[i].xid = xid; + continue; + } else if(ue_context_p->ue_context.e_rab[i].status == E_RAB_STATUS_ESTABLISHED){ + ue_context_p->ue_context.e_rab[i].status = E_RAB_STATUS_TORELEASE; + ue_context_p->ue_context.e_rab[i].xid = xid; + e_rab_release_drb++; + }else{ + //e_rab_id status NG + ue_context_p->ue_context.e_rabs_release_failed[ue_context_p->ue_context.nb_release_of_e_rabs].e_rab_id = e_rab_release_params[erab].e_rab_id; + ue_context_p->ue_context.e_rabs_release_failed[ue_context_p->ue_context.nb_release_of_e_rabs].cause = S1AP_CAUSE_RADIO_NETWORK; + ue_context_p->ue_context.e_rabs_release_failed[ue_context_p->ue_context.nb_release_of_e_rabs].cause_value = 0; + ue_context_p->ue_context.nb_release_of_e_rabs++; + } + } + } + if(e_rab_release_drb > 0) { + //RRCConnectionReconfiguration To UE + rrc_eNB_generate_dedicatedRRCConnectionReconfiguration_release(&ctxt, ue_context_p, xid, S1AP_E_RAB_RELEASE_COMMAND (msg_p).nas_pdu.length, S1AP_E_RAB_RELEASE_COMMAND (msg_p).nas_pdu.buffer); + } else { + //gtp tunnel delete + msg_delete_tunnels_p = itti_alloc_new_message(TASK_RRC_ENB, GTPV1U_ENB_DELETE_TUNNEL_REQ); + memset(>PV1U_ENB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p), 0, sizeof(GTPV1U_ENB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p))); + GTPV1U_ENB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p).rnti = ue_context_p->ue_context.rnti; + for(i = 0; i < NB_RB_MAX; i++){ + if(xid == ue_context_p->ue_context.e_rab[i].xid){ + GTPV1U_ENB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p).eps_bearer_id[GTPV1U_ENB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p).num_erab++] = ue_context_p->ue_context.enb_gtp_ebi[i]; + ue_context_p->ue_context.enb_gtp_teid[i] = 0; + memset(&ue_context_p->ue_context.enb_gtp_addrs[i], 0, sizeof(ue_context_p->ue_context.enb_gtp_addrs[i])); + ue_context_p->ue_context.enb_gtp_ebi[i] = 0; + } + } + + itti_send_msg_to_task(TASK_GTPV1_U, instance, msg_delete_tunnels_p); + + //S1AP_E_RAB_RELEASE_RESPONSE + rrc_eNB_send_S1AP_E_RAB_RELEASE_RESPONSE(&ctxt, ue_context_p, xid); + } + } else { + LOG_E(RRC,"S1AP-E-RAB Release Command: MME_UE_S1AP_ID %d ENB_UE_S1AP_ID %d Error ue_context_p NULL \n", + S1AP_E_RAB_RELEASE_COMMAND (msg_p).mme_ue_s1ap_id, S1AP_E_RAB_RELEASE_COMMAND (msg_p).eNB_ue_s1ap_id); + return -1; + } + + return 0; +} + + +int rrc_eNB_send_S1AP_E_RAB_RELEASE_RESPONSE(const protocol_ctxt_t* const ctxt_pP, rrc_eNB_ue_context_t* const ue_context_pP, uint8_t xid){ + int e_rabs_released = 0; + MessageDef *msg_p; + + msg_p = itti_alloc_new_message (TASK_RRC_ENB, S1AP_E_RAB_RELEASE_RESPONSE); + S1AP_E_RAB_RELEASE_RESPONSE (msg_p).eNB_ue_s1ap_id = ue_context_pP->ue_context.eNB_ue_s1ap_id; + + for (int i = 0; i < NB_RB_MAX; i++){ + if (xid == ue_context_pP->ue_context.e_rab[i].xid){ + S1AP_E_RAB_RELEASE_RESPONSE (msg_p).e_rab_release[e_rabs_released].e_rab_id = ue_context_pP->ue_context.e_rab[i].param.e_rab_id; + e_rabs_released++; + //clear + memset(&ue_context_pP->ue_context.e_rab[i],0,sizeof(e_rab_param_t)); + } + } + S1AP_E_RAB_RELEASE_RESPONSE (msg_p).nb_of_e_rabs_released = e_rabs_released; + S1AP_E_RAB_RELEASE_RESPONSE (msg_p).nb_of_e_rabs_failed = ue_context_pP->ue_context.nb_release_of_e_rabs; + memcpy(&(S1AP_E_RAB_RELEASE_RESPONSE (msg_p).e_rabs_failed[0]),&ue_context_pP->ue_context.e_rabs_release_failed[0],sizeof(e_rab_failed_t)*ue_context_pP->ue_context.nb_release_of_e_rabs); + + ue_context_pP->ue_context.setup_e_rabs -= e_rabs_released; + LOG_I(RRC,"S1AP-E-RAB RELEASE RESPONSE: ENB_UE_S1AP_ID %d release_e_rabs %d setup_e_rabs %d \n", + S1AP_E_RAB_RELEASE_RESPONSE (msg_p).eNB_ue_s1ap_id, + e_rabs_released, ue_context_pP->ue_context.setup_e_rabs); + + itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, msg_p); + //clear xid + for(int i = 0; i < NB_RB_MAX; i++) { + ue_context_pP->ue_context.e_rab[i].xid = -1; + } + //clear release e_rabs + ue_context_pP->ue_context.nb_release_of_e_rabs = 0; + memset(&ue_context_pP->ue_context.e_rabs_release_failed[0],0,sizeof(e_rab_failed_t)*S1AP_MAX_E_RAB); + return 0; +} + +/*------------------------------------------------------------------------------*/ +int rrc_eNB_process_PAGING_IND(MessageDef *msg_p, const char *msg_name, instance_t instance) +{ + const unsigned int Ttab[4] = {32,64,128,256}; + uint8_t Tc,Tue; /* DRX cycle of UE */ + uint32_t pcch_nB; /* 4T, 2T, T, T/2, T/4, T/8, T/16, T/32 */ + uint32_t N; /* N: min(T,nB). total count of PF in one DRX cycle */ + uint32_t Ns = 0; /* Ns: max(1,nB/T) */ + uint8_t i_s; /* i_s = floor(UE_ID/N) mod Ns */ + uint32_t T; /* DRX cycle */ + for (uint16_t tai_size = 0; tai_size < S1AP_PAGING_IND(msg_p).tai_size; tai_size++) { + LOG_D(RRC,"[eNB %d] In S1AP_PAGING_IND: MCC %d, MNC %d, TAC %d\n", instance, S1AP_PAGING_IND(msg_p).plmn_identity[tai_size].mcc, + S1AP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc, S1AP_PAGING_IND(msg_p).tac[tai_size]); + if (RC.rrc[instance]->configuration.mcc == S1AP_PAGING_IND(msg_p).plmn_identity[tai_size].mcc + && RC.rrc[instance]->configuration.mnc == S1AP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc + && RC.rrc[instance]->configuration.tac == S1AP_PAGING_IND(msg_p).tac[tai_size]) { + for (uint8_t CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + lte_frame_type_t frame_type = RC.eNB[instance][CC_id]->frame_parms.frame_type; + /* get nB from configuration */ + /* get default DRX cycle from configuration */ + Tc = (uint8_t)RC.rrc[instance]->configuration.pcch_defaultPagingCycle[CC_id]; + if (Tc < PCCH_Config__defaultPagingCycle_rf32 || Tc > PCCH_Config__defaultPagingCycle_rf256) { + continue; + } + Tue = (uint8_t)S1AP_PAGING_IND(msg_p).paging_drx; + /* set T = min(Tc,Tue) */ + T = Tc < Tue ? Ttab[Tc] : Ttab[Tue]; + /* set pcch_nB = PCCH-Config->nB */ + pcch_nB = (uint32_t)RC.rrc[instance]->configuration.pcch_nB[CC_id]; + switch (pcch_nB) { + case PCCH_Config__nB_fourT: + Ns = 4; + break; + case PCCH_Config__nB_twoT: + Ns = 2; + break; + default: + Ns = 1; + break; + } + /* set N = min(T,nB) */ + if (pcch_nB > PCCH_Config__nB_oneT) { + switch (pcch_nB) { + case PCCH_Config__nB_halfT: + N = T/2; + break; + case PCCH_Config__nB_quarterT: + N = T/4; + break; + case PCCH_Config__nB_oneEighthT: + N = T/8; + break; + case PCCH_Config__nB_oneSixteenthT: + N = T/16; + break; + case PCCH_Config__nB_oneThirtySecondT: + N = T/32; + break; + default: + /* pcch_nB error */ + LOG_E(RRC, "[eNB %d] In S1AP_PAGING_IND: pcch_nB error (pcch_nB %d) \n", + instance, pcch_nB); + return (-1); + } + } else { + N = T; + } + + /* insert data to UE_PF_PO or update data in UE_PF_PO */ + pthread_mutex_lock(&ue_pf_po_mutex); + uint8_t i = 0; + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if ((UE_PF_PO[CC_id][i].enable_flag == TRUE && UE_PF_PO[CC_id][i].ue_index_value == (uint16_t)(S1AP_PAGING_IND(msg_p).ue_index_value)) + || (UE_PF_PO[CC_id][i].enable_flag != TRUE)) { + /* set T = min(Tc,Tue) */ + UE_PF_PO[CC_id][i].T = T; + /* set UE_ID */ + UE_PF_PO[CC_id][i].ue_index_value = (uint16_t)S1AP_PAGING_IND(msg_p).ue_index_value; + /* calculate PF and PO */ + /* set PF_min : SFN mod T = (T div N)*(UE_ID mod N) */ + UE_PF_PO[CC_id][i].PF_min = (T / N) * (UE_PF_PO[CC_id][i].ue_index_value % N); + /* set PO */ + /* i_s = floor(UE_ID/N) mod Ns */ + i_s = (uint8_t)((UE_PF_PO[CC_id][i].ue_index_value / N) % Ns); + if (Ns == 1) { + UE_PF_PO[CC_id][i].PO = (frame_type==FDD) ? 9 : 0; + } else if (Ns==2) { + UE_PF_PO[CC_id][i].PO = (frame_type==FDD) ? (4+(5*i_s)) : (5*i_s); + } else if (Ns==4) { + UE_PF_PO[CC_id][i].PO = (frame_type==FDD) ? (4*(i_s&1)+(5*(i_s>>1))) : ((i_s&1)+(5*(i_s>>1))); + } + if (UE_PF_PO[CC_id][i].enable_flag == TRUE) { + //paging exist UE log + LOG_D(RRC,"[eNB %d] CC_id %d In S1AP_PAGING_IND: Update exist UE %d, T %d, PF %d, PO %d\n", instance, CC_id, UE_PF_PO[CC_id][i].ue_index_value, T, UE_PF_PO[CC_id][i].PF_min, UE_PF_PO[CC_id][i].PO); + } else { + /* set enable_flag */ + UE_PF_PO[CC_id][i].enable_flag = TRUE; + //paging new UE log + LOG_D(RRC,"[eNB %d] CC_id %d In S1AP_PAGING_IND: Insert a new UE %d, T %d, PF %d, PO %d\n", instance, CC_id, UE_PF_PO[CC_id][i].ue_index_value, T, UE_PF_PO[CC_id][i].PF_min, UE_PF_PO[CC_id][i].PO); + } + break; + } + } + pthread_mutex_unlock(&ue_pf_po_mutex); + + uint32_t length; + uint8_t buffer[RRC_BUF_SIZE]; + uint8_t *message_buffer; + /* Transfer data to PDCP */ + MessageDef *message_p; + message_p = itti_alloc_new_message (TASK_RRC_ENB, RRC_PCCH_DATA_REQ); + /* Create message for PDCP (DLInformationTransfer_t) */ + length = do_Paging (instance, + buffer, + S1AP_PAGING_IND(msg_p).ue_paging_identity, + S1AP_PAGING_IND(msg_p).cn_domain); + message_buffer = itti_malloc (TASK_RRC_ENB, TASK_PDCP_ENB, length); + /* Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling). */ + memcpy (message_buffer, buffer, length); + RRC_PCCH_DATA_REQ (message_p).sdu_size = length; + RRC_PCCH_DATA_REQ (message_p).sdu_p = message_buffer; + RRC_PCCH_DATA_REQ (message_p).mode = PDCP_TRANSMISSION_MODE_TRANSPARENT; /* not used */ + RRC_PCCH_DATA_REQ (message_p).rnti = P_RNTI; + RRC_PCCH_DATA_REQ (message_p).ue_index = i; + RRC_PCCH_DATA_REQ (message_p).CC_id = CC_id; + LOG_D(RRC, "[eNB %d] CC_id %d In S1AP_PAGING_IND: send encdoed buffer to PDCP buffer_size %d\n", instance, CC_id, length); + itti_send_msg_to_task (TASK_PDCP_ENB, instance, message_p); + } + } + } + + return (0); +} + # endif /* defined(ENABLE_ITTI) */ #endif /* defined(ENABLE_USE_MME) */ diff --git a/openair2/RRC/LITE/rrc_eNB_S1AP.h b/openair2/RRC/LITE/rrc_eNB_S1AP.h index 6b2de919bd..a924caf254 100644 --- a/openair2/RRC/LITE/rrc_eNB_S1AP.h +++ b/openair2/RRC/LITE/rrc_eNB_S1AP.h @@ -79,6 +79,11 @@ rrc_eNB_generate_dedicatedRRCConnectionReconfiguration(const protocol_ctxt_t* co const uint8_t ho_state ); +int +rrc_eNB_modify_dedicatedRRCConnectionReconfiguration(const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + const uint8_t ho_state + ); /*! \fn void rrc_eNB_send_S1AP_INITIAL_CONTEXT_SETUP_RESP(uint8_t mod_id, uint8_t ue_index) *\brief create a S1AP_INITIAL_CONTEXT_SETUP_RESP for S1AP. @@ -186,6 +191,24 @@ int rrc_eNB_process_S1AP_E_RAB_SETUP_REQ(MessageDef *msg_p, const char *msg_name */ int rrc_eNB_send_S1AP_E_RAB_SETUP_RESP(const protocol_ctxt_t* const ctxt_pP, rrc_eNB_ue_context_t* const ue_context_pP, uint8_t xid ); +/*! \fn rrc_eNB_process_S1AP_E_RAB_MODIFY_REQ(MessageDef *msg_p, const char *msg_name, instance_t instance); + *\brief process a S1AP dedicated E_RAB modify request message received from S1AP. + *\param msg_p Message received by RRC. + *\param msg_name Message name. + *\param instance Message instance. + *\return 0 when successful, -1 if the UE index can not be retrieved. + */ +int rrc_eNB_process_S1AP_E_RAB_MODIFY_REQ(MessageDef *msg_p, const char *msg_name, instance_t instance); + +/*! \fn rrc_eNB_send_S1AP_E_RAB_MODIFY_RESP(const protocol_ctxt_t* const ctxt_pP, rrc_eNB_ue_context_t* const ue_context_pP, uint8_t xid ) + *\brief send a S1AP dedicated E_RAB modify response + *\param ctxt_pP contxt infirmation + *\param e_contxt_pP ue specific context at the eNB + *\param xid transaction identifier + *\return 0 when successful, -1 if the UE index can not be retrieved. + */ +int rrc_eNB_send_S1AP_E_RAB_MODIFY_RESP(const protocol_ctxt_t* const ctxt_pP, rrc_eNB_ue_context_t* const ue_context_pP, uint8_t xid ); + /*! \fn rrc_eNB_process_S1AP_UE_CTXT_MODIFICATION_REQ(MessageDef *msg_p, const char *msg_name, instance_t instance) *\brief process a S1AP_UE_CTXT_MODIFICATION_REQ message received from S1AP. *\param msg_p Message received by RRC. @@ -213,6 +236,39 @@ int rrc_eNB_process_S1AP_UE_CONTEXT_RELEASE_REQ (MessageDef *msg_p, const char * */ int rrc_eNB_process_S1AP_UE_CONTEXT_RELEASE_COMMAND (MessageDef *msg_p, const char *msg_name, instance_t instance); +/*! \fn rrc_eNB_process_PAGING_IND(MessageDef *msg_p, const char *msg_name, instance_t instance) + *\brief process a S1AP_PAGING_IND message received from S1AP. + *\param msg_p Message received by RRC. + *\param msg_name Message name. + *\param instance Message instance. + *\return 0 when successful, -1 if the UE index can not be retrieved. + */ +int rrc_eNB_process_PAGING_IND(MessageDef *msg_p, const char *msg_name, instance_t instance); + +void +rrc_pdcp_config_security( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + const uint8_t send_security_mode_command +); +/*! \fn rrc_eNB_process_S1AP_E_RAB_RELEASE_COMMAND(MessageDef *msg_p, const char *msg_name, instance_t instance); + *\brief process a S1AP dedicated E_RAB release command message received from S1AP. + *\param msg_p Message received by RRC. + *\param msg_name Message name. + *\param instance Message instance. + *\return 0 when successful, -1 if the UE index can not be retrieved. + */ +int rrc_eNB_process_S1AP_E_RAB_RELEASE_COMMAND(MessageDef *msg_p, const char *msg_name, instance_t instance); + +/*! \fn rrc_eNB_send_S1AP_E_RAB_RELEASE_RESPONSE(const protocol_ctxt_t* const ctxt_pP, rrc_eNB_ue_context_t* const ue_context_pP, uint8_t xid ) + *\brief send a S1AP dedicated E_RAB release response + *\param ctxt_pP contxt infirmation + *\param e_contxt_pP ue specific context at the eNB + *\param xid transaction identifier + *\return 0 when successful, -1 if the UE index can not be retrieved. + */ +int rrc_eNB_send_S1AP_E_RAB_RELEASE_RESPONSE(const protocol_ctxt_t* const ctxt_pP, rrc_eNB_ue_context_t* const ue_context_pP, uint8_t xid ); + # endif # endif /* defined(ENABLE_USE_MME) */ #endif /* RRC_ENB_S1AP_H_ */ diff --git a/openair2/RRC/LITE/rrc_eNB_UE_context.c b/openair2/RRC/LITE/rrc_eNB_UE_context.c index 78f85a6da2..28eace8f5a 100644 --- a/openair2/RRC/LITE/rrc_eNB_UE_context.c +++ b/openair2/RRC/LITE/rrc_eNB_UE_context.c @@ -136,6 +136,10 @@ rrc_eNB_allocate_new_UE_context( memset(new_p, 0, sizeof(struct rrc_eNB_ue_context_s)); new_p->local_uid = uid_linear_allocator_new(rrc_instance_pP); + for(int i = 0; i < NB_RB_MAX; i++) { + new_p->ue_context.e_rab[i].xid = -1; + new_p->ue_context.modify_e_rab[i].xid = -1; + } return new_p; } @@ -184,6 +188,7 @@ void rrc_eNB_remove_ue_context( rrc_eNB_free_mem_UE_context(ctxt_pP, ue_context_pP); uid_linear_allocator_free(rrc_instance_pP, ue_context_pP->local_uid); free(ue_context_pP); + rrc_instance_pP->Nb_ue --; LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Removed UE context\n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); diff --git a/openair2/RRC/LITE/vars.h b/openair2/RRC/LITE/vars.h index fbf3ae1dff..e3bab5f5eb 100644 --- a/openair2/RRC/LITE/vars.h +++ b/openair2/RRC/LITE/vars.h @@ -36,6 +36,8 @@ #include "COMMON/mac_rrc_primitives.h" #include "LAYER2/MAC/defs.h" +UE_PF_PO_t UE_PF_PO[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +pthread_mutex_t ue_pf_po_mutex; UE_RRC_INST *UE_rrc_inst; #include "LAYER2/MAC/extern.h" #define MAX_U32 0xFFFFFFFF @@ -236,4 +238,10 @@ float RSRQ_meas_mapping[35] = { -2 }; +// only used for RRC connection re-establishment procedure TS36.331 5.3.7 +// [0]: current C-RNTI, [1]: prior C-RNTI +// insert one when eNB received RRCConnectionReestablishmentRequest message +// delete one when eNB received RRCConnectionReestablishmentComplete message +uint16_t reestablish_rnti_map[NUMBER_OF_UE_MAX][2] = {{0}}; + #endif diff --git a/openair3/GTPV1-U/gtpv1u_eNB.c b/openair3/GTPV1-U/gtpv1u_eNB.c index f70fe9cf2b..d152840dd4 100644 --- a/openair3/GTPV1-U/gtpv1u_eNB.c +++ b/openair3/GTPV1-U/gtpv1u_eNB.c @@ -766,6 +766,7 @@ gtpv1u_create_s1u_tunnel( gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_eNB = s1u_teid; gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_eNB_stack_session = stack_req.apiInfo.createTunnelEndPointInfo.hStackSession; gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_sgw = create_tunnel_req_pP->sgw_S1u_teid[i]; + gtpv1u_ue_data_p->num_bearers++; create_tunnel_resp_pP->enb_S1u_teid[i] = s1u_teid; } else { @@ -807,7 +808,47 @@ gtpv1u_create_s1u_tunnel( return 0; } +int gtpv1u_update_s1u_tunnel( + const instance_t instanceP, + const gtpv1u_enb_create_tunnel_req_t * const create_tunnel_req_pP, + const rnti_t prior_rnti + ) +{ + /* Local tunnel end-point identifier */ + teid_t s1u_teid = 0; + gtpv1u_teid_data_t *gtpv1u_teid_data_p = NULL; + gtpv1u_ue_data_t *gtpv1u_ue_data_p = NULL; + //MessageDef *message_p = NULL; + hashtable_rc_t hash_rc = HASH_TABLE_KEY_NOT_EXISTS; + int i; + ebi_t eps_bearer_id = 0; + //----------------------- + // PDCP->GTPV1U mapping + //----------------------- + hash_rc = hashtable_get(RC.gtpv1u_data_g->ue_mapping, prior_rnti, (void **)>pv1u_ue_data_p); + AssertFatal(hash_rc == HASH_TABLE_OK, "Error get ue_mapping(rnti=%x) from GTPV1U hashtable error\n", prior_rnti); + + gtpv1u_ue_data_p->ue_id = create_tunnel_req_pP->rnti; + hash_rc = hashtable_insert(RC.gtpv1u_data_g->ue_mapping, create_tunnel_req_pP->rnti, gtpv1u_ue_data_p); + AssertFatal(hash_rc == HASH_TABLE_OK, "Error inserting ue_mapping in GTPV1U hashtable"); + LOG_I(GTPU, "inserting ue_mapping(rnti=%x) in GTPV1U hashtable\n", + create_tunnel_req_pP->rnti); + + //----------------------- + // GTPV1U->PDCP mapping + //----------------------- + for (i = 0; i < create_tunnel_req_pP->num_tunnels; i++) { + eps_bearer_id = create_tunnel_req_pP->eps_bearer_id[i]; + s1u_teid = gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_eNB; + hash_rc = hashtable_get(RC.gtpv1u_data_g->teid_mapping, s1u_teid, (void**)>pv1u_teid_data_p); + AssertFatal(hash_rc == HASH_TABLE_OK, "Error get teid mapping(s1u_teid=%u) from GTPV1U hashtable", s1u_teid); + + gtpv1u_teid_data_p->ue_id = create_tunnel_req_pP->rnti; + gtpv1u_teid_data_p->eps_bearer_id = eps_bearer_id; + } + return 0; +} //----------------------------------------------------------------------------- static int gtpv1u_delete_s1u_tunnel( diff --git a/openair3/GTPV1-U/gtpv1u_eNB_task.h b/openair3/GTPV1-U/gtpv1u_eNB_task.h index 6f74c73a29..5a7822fe8c 100644 --- a/openair3/GTPV1-U/gtpv1u_eNB_task.h +++ b/openair3/GTPV1-U/gtpv1u_eNB_task.h @@ -49,5 +49,9 @@ gtpv1u_create_s1u_tunnel( const gtpv1u_enb_create_tunnel_req_t * const create_tunnel_req_pP, gtpv1u_enb_create_tunnel_resp_t * const create_tunnel_resp_pP); - +int +gtpv1u_update_s1u_tunnel( + const instance_t instanceP, + const gtpv1u_enb_create_tunnel_req_t * const create_tunnel_req_pP, + const rnti_t prior_rnti); #endif /* GTPV1U_ENB_TASK_H_ */ diff --git a/openair3/S1AP/s1ap_eNB.c b/openair3/S1AP/s1ap_eNB.c index 08a18b629e..aba32aa494 100644 --- a/openair3/S1AP/s1ap_eNB.c +++ b/openair3/S1AP/s1ap_eNB.c @@ -364,6 +364,12 @@ void *s1ap_eNB_task(void *arg) &S1AP_E_RAB_SETUP_RESP(received_msg)); } break; + + case S1AP_E_RAB_MODIFY_RESP: { + s1ap_eNB_e_rab_modify_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &S1AP_E_RAB_MODIFY_RESP(received_msg)); + } + break; case S1AP_NAS_NON_DELIVERY_IND: { s1ap_eNB_nas_non_delivery_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg), @@ -397,6 +403,12 @@ void *s1ap_eNB_task(void *arg) } break; + case S1AP_E_RAB_RELEASE_RESPONSE: { + s1ap_eNB_e_rab_release_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg), + &S1AP_E_RAB_RELEASE_RESPONSE(received_msg)); + } + break; + default: S1AP_ERROR("Received unhandled message: %d:%s\n", ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg)); diff --git a/openair3/S1AP/s1ap_eNB_decoder.c b/openair3/S1AP/s1ap_eNB_decoder.c index f8daf6c67a..eac52c53ba 100644 --- a/openair3/S1AP/s1ap_eNB_decoder.c +++ b/openair3/S1AP/s1ap_eNB_decoder.c @@ -108,7 +108,15 @@ static int s1ap_eNB_decode_initiating_message(s1ap_message *message, ret = s1ap_decode_s1ap_pagingies( &message->msg.s1ap_PagingIEs, &initiating_p->value); s1ap_xer_print_s1ap_paging(s1ap_xer__print2sp, message_string, message); - S1AP_ERROR("TODO Paging initiating message\n"); + message_id = S1AP_PAGING_LOG; + message_string_size = strlen(message_string); + message_p = itti_alloc_new_message_sized(TASK_S1AP, + message_id, + message_string_size + sizeof (IttiMsgText)); + message_p->ittiMsg.s1ap_paging_log.size = message_string_size; + memcpy(&message_p->ittiMsg.s1ap_paging_log.text, message_string, message_string_size); + itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p); + S1AP_INFO("Paging initiating message\n"); free(message_string); break; @@ -128,12 +136,36 @@ static int s1ap_eNB_decode_initiating_message(s1ap_message *message, free(message_string); S1AP_INFO("E_RABSetup initiating message\n"); break; - case S1ap_ProcedureCode_id_E_RABRelease: - ret = s1ap_decode_s1ap_e_rabreleasecommandies(&message->msg.s1ap_E_RABReleaseCommandIEs, - &initiating_p->value); - //s1ap_xer_print_s1ap_e_rabsetuprequest(s1ap_xer__print2sp, message_string, message); - S1AP_INFO("TODO E_RABRelease nitiating message\n"); + + case S1ap_ProcedureCode_id_E_RABModify: + ret = s1ap_decode_s1ap_e_rabmodifyrequesties( + &message->msg.s1ap_E_RABModifyRequestIEs, &initiating_p->value); + message_id = S1AP_E_RAB_MODIFY_REQUEST_LOG; + message_string_size = strlen(message_string); + message_p = itti_alloc_new_message_sized(TASK_S1AP, + message_id, + message_string_size + sizeof (IttiMsgText)); + message_p->ittiMsg.s1ap_e_rab_modify_request_log.size = message_string_size; + memcpy(&message_p->ittiMsg.s1ap_e_rab_modify_request_log.text, message_string, message_string_size); + itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p); free(message_string); + S1AP_INFO("E_RABModify initiating message\n"); + break; + + case S1ap_ProcedureCode_id_E_RABRelease: + ret = s1ap_decode_s1ap_e_rabreleasecommandies( + &message->msg.s1ap_E_RABReleaseCommandIEs, &initiating_p->value); + s1ap_xer_print_s1ap_e_rabreleasecommand(s1ap_xer__print2sp, message_string, message); + message_id = S1AP_E_RAB_RELEASE_REQUEST_LOG; + message_string_size = strlen(message_string); + message_p = itti_alloc_new_message_sized(TASK_S1AP, + message_id, + message_string_size + sizeof (IttiMsgText)); + message_p->ittiMsg.s1ap_e_rab_release_request_log.size = message_string_size; + memcpy(&message_p->ittiMsg.s1ap_e_rab_release_request_log.text, message_string, message_string_size); + itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p); + free(message_string); + S1AP_INFO("TODO E_RABRelease nitiating message\n"); break; default: diff --git a/openair3/S1AP/s1ap_eNB_encoder.c b/openair3/S1AP/s1ap_eNB_encoder.c index 4ab2f1f317..9a5f422158 100644 --- a/openair3/S1AP/s1ap_eNB_encoder.c +++ b/openair3/S1AP/s1ap_eNB_encoder.c @@ -100,6 +100,16 @@ int s1ap_eNB_encode_e_rab_setup_response(S1ap_E_RABSetupResponseIEs_t *E_RABSet uint8_t **buffer, uint32_t *length); +static inline +int s1ap_eNB_encode_e_rab_modify_response(S1ap_E_RABModifyResponseIEs_t *E_RABModifyResponseIEs, + uint8_t **buffer, + uint32_t *length); + +static inline +int s1ap_eNB_encode_e_rab_release_response(S1ap_E_RABReleaseResponseIEs_t *s1ap_E_RABReleaseResponseIEs, + uint8_t **buffer, + uint32_t *length); + int s1ap_eNB_encode_pdu(s1ap_message *message, uint8_t **buffer, uint32_t *len) { DevAssert(message != NULL); @@ -264,6 +274,32 @@ int s1ap_eNB_encode_successfull_outcome(s1ap_message *s1ap_message_p, free(message_string); S1AP_INFO("E_RABSetup successful message\n"); break; + + case S1ap_ProcedureCode_id_E_RABModify: + ret = s1ap_eNB_encode_e_rab_modify_response ( + &s1ap_message_p->msg.s1ap_E_RABModifyResponseIEs, buffer, len); + message_id = S1AP_E_RAB_MODIFY_RESPONSE_LOG ; + message_p = itti_alloc_new_message_sized(TASK_S1AP, message_id, message_string_size + sizeof (IttiMsgText)); + message_p->ittiMsg.s1ap_e_rab_modify_response_log.size = message_string_size; + memcpy(&message_p->ittiMsg.s1ap_e_rab_modify_response_log.text, message_string, message_string_size); + itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p); + free(message_string); + S1AP_INFO("E_RABModify successful message\n"); + break; + + case S1ap_ProcedureCode_id_E_RABRelease: + ret = s1ap_eNB_encode_e_rab_release_response ( + &s1ap_message_p->msg.s1ap_E_RABReleaseResponseIEs, buffer, len); + s1ap_xer_print_s1ap_e_rabreleaseresponse(s1ap_xer__print2sp, message_string, s1ap_message_p); + message_id = S1AP_E_RAB_RELEASE_RESPONSE_LOG ; + message_p = itti_alloc_new_message_sized(TASK_S1AP, message_id, message_string_size + sizeof (IttiMsgText)); + message_p->ittiMsg.s1ap_e_rab_release_response_log.size = message_string_size; + memcpy(&message_p->ittiMsg.s1ap_e_rab_release_response_log.text, message_string, message_string_size); + itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p); + free(message_string); + S1AP_INFO("E_RAB Release successful message\n"); + break; + default: S1AP_WARN("Unknown procedure ID (%d) for successfull outcome message\n", (int)s1ap_message_p->procedureCode); @@ -563,3 +599,48 @@ int s1ap_eNB_encode_e_rab_setup_response(S1ap_E_RABSetupResponseIEs_t *s1ap_E_R &asn_DEF_S1ap_E_RABSetupResponse, e_rab_setup_response_p); } + +static inline +int s1ap_eNB_encode_e_rab_modify_response(S1ap_E_RABModifyResponseIEs_t *s1ap_E_RABModifyResponseIEs, + uint8_t **buffer, + uint32_t *length) +{ + S1ap_E_RABModifyResponse_t e_rab_modify_response; + S1ap_E_RABModifyResponse_t *e_rab_modify_response_p = &e_rab_modify_response; + + memset((void *)e_rab_modify_response_p, 0, + sizeof(e_rab_modify_response)); + + if (s1ap_encode_s1ap_e_rabmodifyresponseies (e_rab_modify_response_p, s1ap_E_RABModifyResponseIEs) < 0) { + return -1; + } + + return s1ap_generate_successfull_outcome(buffer, + length, + S1ap_ProcedureCode_id_E_RABModify, + S1ap_Criticality_reject, + &asn_DEF_S1ap_E_RABModifyResponse, + e_rab_modify_response_p); +} +static inline +int s1ap_eNB_encode_e_rab_release_response(S1ap_E_RABReleaseResponseIEs_t *s1ap_E_RABReleaseResponseIEs, + uint8_t **buffer, + uint32_t *length) +{ + S1ap_E_RABReleaseResponse_t e_rab_release_response; + S1ap_E_RABReleaseResponse_t *e_rab_release_response_p = &e_rab_release_response; + + memset((void *)e_rab_release_response_p, 0, + sizeof(e_rab_release_response)); + + if (s1ap_encode_s1ap_e_rabreleaseresponseies (e_rab_release_response_p, s1ap_E_RABReleaseResponseIEs) < 0) { + return -1; + } + + return s1ap_generate_successfull_outcome(buffer, + length, + S1ap_ProcedureCode_id_E_RABRelease, + S1ap_Criticality_reject, + &asn_DEF_S1ap_E_RABReleaseResponse, + e_rab_release_response_p); +} diff --git a/openair3/S1AP/s1ap_eNB_handlers.c b/openair3/S1AP/s1ap_eNB_handlers.c index 186f034644..0b02fc6db9 100644 --- a/openair3/S1AP/s1ap_eNB_handlers.c +++ b/openair3/S1AP/s1ap_eNB_handlers.c @@ -81,6 +81,20 @@ int s1ap_eNB_handle_e_rab_setup_request(uint32_t assoc_id, uint32_t stream, struct s1ap_message_s *s1ap_message_p); +static +int s1ap_eNB_handle_paging(uint32_t assoc_id, + uint32_t stream, + struct s1ap_message_s *message_p); + +static +int s1ap_eNB_handle_e_rab_modify_request(uint32_t assoc_id, + uint32_t stream, + struct s1ap_message_s *s1ap_message_p); + +static +int s1ap_eNB_handle_e_rab_release_command(uint32_t assoc_id, + uint32_t stream, + struct s1ap_message_s *s1ap_message_p); /* Handlers matrix. Only eNB related procedure present here */ s1ap_message_decoded_callback messages_callback[][3] = { @@ -90,11 +104,11 @@ s1ap_message_decoded_callback messages_callback[][3] = { { 0, 0, 0 }, /* PathSwitchRequest */ { 0, 0, 0 }, /* HandoverCancel */ { s1ap_eNB_handle_e_rab_setup_request, 0, 0 }, /* E_RABSetup */ - { 0, 0, 0 }, /* E_RABModify */ - { 0, 0, 0 }, /* E_RABRelease */ + { s1ap_eNB_handle_e_rab_modify_request, 0, 0 }, /* E_RABModify */ + { s1ap_eNB_handle_e_rab_release_command, 0, 0 }, /* E_RABRelease */ { 0, 0, 0 }, /* E_RABReleaseIndication */ { s1ap_eNB_handle_initial_context_request, 0, 0 }, /* InitialContextSetup */ - { 0, 0, 0 }, /* Paging */ + { s1ap_eNB_handle_paging, 0, 0 }, /* Paging */ { s1ap_eNB_handle_nas_downlink, 0, 0 }, /* downlinkNASTransport */ { 0, 0, 0 }, /* initialUEMessage */ { 0, 0, 0 }, /* uplinkNASTransport */ @@ -950,7 +964,7 @@ int s1ap_eNB_handle_e_rab_setup_request(uint32_t assoc_id, S1AP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].nas_pdu.buffer = NULL; S1AP_WARN("NAS PDU is not provided, generate a E_RAB_SETUP Failure (TBD) back to MME \n"); - return -1; + // return -1; } /* Set the transport layer address */ @@ -983,4 +997,382 @@ int s1ap_eNB_handle_e_rab_setup_request(uint32_t assoc_id, return 0; } +static +int s1ap_eNB_handle_paging(uint32_t assoc_id, + uint32_t stream, + struct s1ap_message_s *s1ap_message_p) +{ + S1ap_PagingIEs_t *paging_p; + s1ap_eNB_mme_data_t *mme_desc_p = NULL; + s1ap_eNB_instance_t *s1ap_eNB_instance = NULL; + MessageDef *message_p = NULL; + DevAssert(s1ap_message_p != NULL); + // received Paging Message from MME + S1AP_DEBUG("[SCTP %d] Received Paging Message From MME\n",assoc_id); + + paging_p = &s1ap_message_p->msg.s1ap_PagingIEs; + + /* Paging procedure -> stream != 0 */ + if (stream == 0) { + S1AP_ERROR("[SCTP %d] Received Paging procedure on stream (%d)\n", + assoc_id, stream); + return -1; + } + + if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) { + S1AP_ERROR("[SCTP %d] Received Paging for non " + "existing MME context\n", assoc_id); + return -1; + } + + s1ap_eNB_instance = mme_desc_p->s1ap_eNB_instance; + if (s1ap_eNB_instance == NULL) { + S1AP_ERROR("[SCTP %d] Received Paging for non existing MME context : s1ap_eNB_instance is NULL\n", + assoc_id); + return -1; + } + + message_p = itti_alloc_new_message(TASK_S1AP, S1AP_PAGING_IND); + + /* convert S1ap_PagingIEs_t to s1ap_paging_ind_t */ + /* convert UE Identity Index value */ + S1AP_PAGING_IND(message_p).ue_index_value = BIT_STRING_to_uint32(&paging_p->ueIdentityIndexValue); + S1AP_DEBUG("[SCTP %d] Received Paging ue_index_value (%d)\n", + assoc_id,(uint32_t)S1AP_PAGING_IND(message_p).ue_index_value); + + S1AP_PAGING_IND(message_p).ue_paging_identity.choice.s_tmsi.mme_code = 0; + S1AP_PAGING_IND(message_p).ue_paging_identity.choice.s_tmsi.m_tmsi = 0; + + /* convert UE Paging Identity */ + if (paging_p->uePagingID.present == S1ap_UEPagingID_PR_s_TMSI) { + S1AP_PAGING_IND(message_p).ue_paging_identity.presenceMask = UE_PAGING_IDENTITY_s_tmsi; + OCTET_STRING_TO_INT8(&paging_p->uePagingID.choice.s_TMSI.mMEC, S1AP_PAGING_IND(message_p).ue_paging_identity.choice.s_tmsi.mme_code); + OCTET_STRING_TO_INT32(&paging_p->uePagingID.choice.s_TMSI.m_TMSI, S1AP_PAGING_IND(message_p).ue_paging_identity.choice.s_tmsi.m_tmsi); + } else if (paging_p->uePagingID.present == S1ap_UEPagingID_PR_iMSI) { + S1AP_PAGING_IND(message_p).ue_paging_identity.presenceMask = UE_PAGING_IDENTITY_imsi; + S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.length = 0; + for (int i = 0; i < paging_p->uePagingID.choice.iMSI.size; i++) { + S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[2*i] = (uint8_t)(paging_p->uePagingID.choice.iMSI.buf[i] & 0x0F ); + S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.length++; + S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[2*i+1] = (uint8_t)((paging_p->uePagingID.choice.iMSI.buf[i]>>4) & 0x0F); + LOG_D(S1AP,"paging : i %d %d imsi %d %d \n",2*i,2*i+1,S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[2*i], S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[2*i+1]); + if (S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[2*i+1] == 0x0F) { + if(i != paging_p->uePagingID.choice.iMSI.size - 1){ + /* invalid paging_p->uePagingID.choise.iMSI.buffer */ + S1AP_ERROR("[SCTP %d] Received Paging : uePagingID.choise.iMSI error(i %d 0x0F)\n", assoc_id,i); + return -1; + } + } else { + S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.length++; + } + } + if (S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.length >= S1AP_IMSI_LENGTH) { + /* invalid paging_p->uePagingID.choise.iMSI.size */ + S1AP_ERROR("[SCTP %d] Received Paging : uePagingID.choise.iMSI.size(%d) is over IMSI length(%d)\n", assoc_id, S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.length, S1AP_IMSI_LENGTH); + return -1; + } +} else { + /* invalid paging_p->uePagingID.present */ + S1AP_ERROR("[SCTP %d] Received Paging : uePagingID.present(%d) is unknown\n", assoc_id, paging_p->uePagingID.present); + return -1; + } + +#if 0 + /* convert Paging DRX(optional) */ + if (paging_p->presenceMask & S1AP_PAGINGIES_PAGINGDRX_PRESENT) { + switch(paging_p->pagingDRX) { + case S1ap_PagingDRX_v32: + S1AP_PAGING_IND(message_p).paging_drx = PAGING_DRX_32; + break; + case S1ap_PagingDRX_v64: + S1AP_PAGING_IND(message_p).paging_drx = PAGING_DRX_64; + break; + case S1ap_PagingDRX_v128: + S1AP_PAGING_IND(message_p).paging_drx = PAGING_DRX_128; + break; + case S1ap_PagingDRX_v256: + S1AP_PAGING_IND(message_p).paging_drx = PAGING_DRX_256; + break; + default: + // when UE Paging DRX is no value + S1AP_PAGING_IND(message_p).paging_drx = PAGING_DRX_256; + break; + } + } +#endif + S1AP_PAGING_IND(message_p).paging_drx = PAGING_DRX_256; + + /* convert cnDomain */ + if (paging_p->cnDomain == S1ap_CNDomain_ps) { + S1AP_PAGING_IND(message_p).cn_domain = CN_DOMAIN_PS; + } else if (paging_p->cnDomain == S1ap_CNDomain_cs) { + S1AP_PAGING_IND(message_p).cn_domain = CN_DOMAIN_CS; + } else { + /* invalid paging_p->cnDomain */ + S1AP_ERROR("[SCTP %d] Received Paging : cnDomain(%ld) is unknown\n", assoc_id, paging_p->cnDomain); + return -1; + } + + memset (&S1AP_PAGING_IND(message_p).plmn_identity[0], 0, sizeof(plmn_identity_t)*256); + memset (&S1AP_PAGING_IND(message_p).tac[0], 0, sizeof(int16_t)*256); + S1AP_PAGING_IND(message_p).tai_size = 0; + + for (int i = 0; i < paging_p->taiList.s1ap_TAIItem.count; i++) { + S1AP_INFO("[SCTP %d] Received Paging taiList: i %d, count %d\n", assoc_id, i, paging_p->taiList.s1ap_TAIItem.count); + S1ap_TAIItem_t s1ap_TAIItem; + memset (&s1ap_TAIItem, 0, sizeof(S1ap_TAIItem_t)); + + memcpy(&s1ap_TAIItem, paging_p->taiList.s1ap_TAIItem.array[i], sizeof(S1ap_TAIItem_t)); + + TBCD_TO_MCC_MNC(&s1ap_TAIItem.tAI.pLMNidentity, S1AP_PAGING_IND(message_p).plmn_identity[i].mcc, + S1AP_PAGING_IND(message_p).plmn_identity[i].mnc, + S1AP_PAGING_IND(message_p).plmn_identity[i].mnc_digit_length); + OCTET_STRING_TO_INT16(&s1ap_TAIItem.tAI.tAC, S1AP_PAGING_IND(message_p).tac[i]); + S1AP_PAGING_IND(message_p).tai_size++; + S1AP_DEBUG("[SCTP %d] Received Paging: MCC %d, MNC %d, TAC %d\n", assoc_id, S1AP_PAGING_IND(message_p).plmn_identity[i].mcc, S1AP_PAGING_IND(message_p).plmn_identity[i].mnc, S1AP_PAGING_IND(message_p).tac[i]); + } + +#if 0 + // CSG Id(optional) List is not used + if (paging_p->presenceMask & S1AP_PAGINGIES_CSG_IDLIST_PRESENT) { + // TODO + } + + /* convert pagingPriority (optional) if has value */ + if (paging_p->presenceMask & S1AP_PAGINGIES_PAGINGPRIORITY_PRESENT) { + switch(paging_p->pagingPriority) { + case S1ap_PagingPriority_priolevel1: + S1AP_PAGING_IND(message_p).paging_priority = PAGING_PRIO_LEVEL1; + break; + case S1ap_PagingPriority_priolevel2: + S1AP_PAGING_IND(message_p).paging_priority = PAGING_PRIO_LEVEL2; + break; + case S1ap_PagingPriority_priolevel3: + S1AP_PAGING_IND(message_p).paging_priority = PAGING_PRIO_LEVEL3; + break; + case S1ap_PagingPriority_priolevel4: + S1AP_PAGING_IND(message_p).paging_priority = PAGING_PRIO_LEVEL4; + break; + case S1ap_PagingPriority_priolevel5: + S1AP_PAGING_IND(message_p).paging_priority = PAGING_PRIO_LEVEL5; + break; + case S1ap_PagingPriority_priolevel6: + S1AP_PAGING_IND(message_p).paging_priority = PAGING_PRIO_LEVEL6; + break; + case S1ap_PagingPriority_priolevel7: + S1AP_PAGING_IND(message_p).paging_priority = PAGING_PRIO_LEVEL7; + break; + case S1ap_PagingPriority_priolevel8: + S1AP_PAGING_IND(message_p).paging_priority = PAGING_PRIO_LEVEL8; + break; + default: + /* invalid paging_p->pagingPriority */ + S1AP_ERROR("[SCTP %d] Received paging : pagingPriority(%ld) is invalid\n", assoc_id, paging_p->pagingPriority); + return -1; + } + } +#endif + //paging parameter values + S1AP_DEBUG("[SCTP %d] Received Paging parameters: ue_index_value %d cn_domain %d paging_drx %d paging_priority %d\n",assoc_id, + S1AP_PAGING_IND(message_p).ue_index_value, S1AP_PAGING_IND(message_p).cn_domain, + S1AP_PAGING_IND(message_p).paging_drx, S1AP_PAGING_IND(message_p).paging_priority); + S1AP_DEBUG("[SCTP %d] Received Paging parameters(ue): presenceMask %d s_tmsi.m_tmsi %d s_tmsi.mme_code %d IMSI length %d (0-5) %d%d%d%d%d%d\n",assoc_id, + S1AP_PAGING_IND(message_p).ue_paging_identity.presenceMask, S1AP_PAGING_IND(message_p).ue_paging_identity.choice.s_tmsi.m_tmsi, + S1AP_PAGING_IND(message_p).ue_paging_identity.choice.s_tmsi.mme_code, S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.length, + S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[0], S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[1], + S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[2], S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[3], + S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[4], S1AP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[5]); + + /* send message to RRC */ + itti_send_msg_to_task(TASK_RRC_ENB, s1ap_eNB_instance->instance, message_p); + + return 0; +} + +static +int s1ap_eNB_handle_e_rab_modify_request(uint32_t assoc_id, + uint32_t stream, + struct s1ap_message_s *s1ap_message_p) { + + int i; + + s1ap_eNB_mme_data_t *mme_desc_p = NULL; + s1ap_eNB_ue_context_t *ue_desc_p = NULL; + MessageDef *message_p = NULL; + int nb_of_e_rabs_failed = 0; + + S1ap_E_RABModifyRequestIEs_t *s1ap_E_RABModifyRequest; + DevAssert(s1ap_message_p != NULL); + + s1ap_E_RABModifyRequest = &s1ap_message_p->msg.s1ap_E_RABModifyRequestIEs; + + if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) { + S1AP_ERROR("[SCTP %d] Received E-RAB modify request for non " + "existing MME context\n", assoc_id); + return -1; + } + + + if ((ue_desc_p = s1ap_eNB_get_ue_context(mme_desc_p->s1ap_eNB_instance, + s1ap_E_RABModifyRequest->eNB_UE_S1AP_ID)) == NULL) { + S1AP_ERROR("[SCTP %d] Received E-RAB modify request for non " + "existing UE context 0x%06lx\n", assoc_id, + s1ap_E_RABModifyRequest->eNB_UE_S1AP_ID); + return -1; + } + + /* E-RAB modify request = UE-related procedure -> stream != 0 */ + if (stream == 0) { + S1AP_ERROR("[SCTP %d] Received UE-related procedure on stream (%d)\n", + assoc_id, stream); + return -1; + } + + ue_desc_p->rx_stream = stream; + + if ( ue_desc_p->mme_ue_s1ap_id != s1ap_E_RABModifyRequest->mme_ue_s1ap_id){ + S1AP_WARN("UE context mme_ue_s1ap_id is different form that of the message (%d != %ld)", + ue_desc_p->mme_ue_s1ap_id, s1ap_E_RABModifyRequest->mme_ue_s1ap_id); + message_p = itti_alloc_new_message (TASK_RRC_ENB, S1AP_E_RAB_MODIFY_RESP); + + S1AP_E_RAB_MODIFY_RESP (message_p).eNB_ue_s1ap_id = s1ap_E_RABModifyRequest->eNB_UE_S1AP_ID; +// S1AP_E_RAB_MODIFY_RESP (msg_fail_p).e_rabs[S1AP_MAX_E_RAB]; + S1AP_E_RAB_MODIFY_RESP (message_p).nb_of_e_rabs = 0; + + for(nb_of_e_rabs_failed = 0; nb_of_e_rabs_failed < s1ap_E_RABModifyRequest->e_RABToBeModifiedListBearerModReq.s1ap_E_RABToBeModifiedItemBearerModReq.count; nb_of_e_rabs_failed++) { + S1AP_E_RAB_MODIFY_RESP (message_p).e_rabs_failed[nb_of_e_rabs_failed].e_rab_id = + ((S1ap_E_RABToBeModifiedItemBearerModReq_t *)s1ap_E_RABModifyRequest->e_RABToBeModifiedListBearerModReq.s1ap_E_RABToBeModifiedItemBearerModReq.array[nb_of_e_rabs_failed])->e_RAB_ID; + S1AP_E_RAB_MODIFY_RESP (message_p).e_rabs_failed[nb_of_e_rabs_failed].cause = S1AP_CAUSE_RADIO_NETWORK; + S1AP_E_RAB_MODIFY_RESP (message_p).e_rabs_failed[nb_of_e_rabs_failed].cause_value = 13;//S1ap_CauseRadioNetwork_unknown_mme_ue_s1ap_id; + } + S1AP_E_RAB_MODIFY_RESP (message_p).nb_of_e_rabs_failed = nb_of_e_rabs_failed; + + s1ap_eNB_e_rab_modify_resp(mme_desc_p->s1ap_eNB_instance->instance, + &S1AP_E_RAB_MODIFY_RESP(message_p)); + + message_p = NULL; + return -1; + } + + message_p = itti_alloc_new_message(TASK_S1AP, S1AP_E_RAB_MODIFY_REQ); + + S1AP_E_RAB_MODIFY_REQ(message_p).ue_initial_id = ue_desc_p->ue_initial_id; + + S1AP_E_RAB_MODIFY_REQ(message_p).mme_ue_s1ap_id = s1ap_E_RABModifyRequest->mme_ue_s1ap_id; + S1AP_E_RAB_MODIFY_REQ(message_p).eNB_ue_s1ap_id = s1ap_E_RABModifyRequest->eNB_UE_S1AP_ID; + + S1AP_E_RAB_MODIFY_REQ(message_p).nb_e_rabs_tomodify = + s1ap_E_RABModifyRequest->e_RABToBeModifiedListBearerModReq.s1ap_E_RABToBeModifiedItemBearerModReq.count; + + for (i = 0; i < s1ap_E_RABModifyRequest->e_RABToBeModifiedListBearerModReq.s1ap_E_RABToBeModifiedItemBearerModReq.count; i++) { + S1ap_E_RABToBeModifiedItemBearerModReq_t *item_p; + + item_p = (S1ap_E_RABToBeModifiedItemBearerModReq_t *)s1ap_E_RABModifyRequest->e_RABToBeModifiedListBearerModReq.s1ap_E_RABToBeModifiedItemBearerModReq.array[i]; + + S1AP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].e_rab_id = item_p->e_RAB_ID; + + // check for the NAS PDU + if (item_p->nAS_PDU.size > 0 ) { + S1AP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].nas_pdu.length = item_p->nAS_PDU.size; + + S1AP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].nas_pdu.buffer = malloc(sizeof(uint8_t) * item_p->nAS_PDU.size); + + memcpy(S1AP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].nas_pdu.buffer, + item_p->nAS_PDU.buf, item_p->nAS_PDU.size); + } else { + S1AP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].nas_pdu.length = 0; + S1AP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].nas_pdu.buffer = NULL; + continue; + } + + /* Set the QOS informations */ + S1AP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].qos.qci = item_p->e_RABLevelQoSParameters.qCI; + + S1AP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].qos.allocation_retention_priority.priority_level = + item_p->e_RABLevelQoSParameters.allocationRetentionPriority.priorityLevel; + S1AP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].qos.allocation_retention_priority.pre_emp_capability = + item_p->e_RABLevelQoSParameters.allocationRetentionPriority.pre_emptionCapability; + S1AP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].qos.allocation_retention_priority.pre_emp_vulnerability = + item_p->e_RABLevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability; + + } + + itti_send_msg_to_task(TASK_RRC_ENB, ue_desc_p->eNB_instance->instance, message_p); + + return 0; +} +// handle e-rab release command and send it to rrc_end +static +int s1ap_eNB_handle_e_rab_release_command(uint32_t assoc_id, + uint32_t stream, + struct s1ap_message_s *s1ap_message_p) { + + int i; + + s1ap_eNB_mme_data_t *mme_desc_p = NULL; + s1ap_eNB_ue_context_t *ue_desc_p = NULL; + MessageDef *message_p = NULL; + + S1ap_E_RABReleaseCommandIEs_t *s1ap_E_RABReleaseCommand; + DevAssert(s1ap_message_p != NULL); + s1ap_E_RABReleaseCommand = &s1ap_message_p->msg.s1ap_E_RABReleaseCommandIEs; + + if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) { + S1AP_ERROR("[SCTP %d] Received E-RAB release command for non existing MME context\n", assoc_id); + return -1; + } + if ((ue_desc_p = s1ap_eNB_get_ue_context(mme_desc_p->s1ap_eNB_instance, + s1ap_E_RABReleaseCommand->eNB_UE_S1AP_ID)) == NULL) { + S1AP_ERROR("[SCTP %d] Received E-RAB release command for non existing UE context 0x%06lx\n", assoc_id, + s1ap_E_RABReleaseCommand->eNB_UE_S1AP_ID); + return -1; + } + + /* Initial context request = UE-related procedure -> stream != 0 */ + if (stream == 0) { + S1AP_ERROR("[SCTP %d] Received UE-related procedure on stream (%d)\n", + assoc_id, stream); + return -1; + } + + ue_desc_p->rx_stream = stream; + + if ( ue_desc_p->mme_ue_s1ap_id != s1ap_E_RABReleaseCommand->mme_ue_s1ap_id){ + S1AP_WARN("UE context mme_ue_s1ap_id is different form that of the message (%d != %ld)", + ue_desc_p->mme_ue_s1ap_id, s1ap_E_RABReleaseCommand->mme_ue_s1ap_id); + } + + S1AP_DEBUG("[SCTP %d] Received E-RAB release command for eNB_UE_S1AP_ID %ld mme_ue_s1ap_id %ld\n", + assoc_id, s1ap_E_RABReleaseCommand->eNB_UE_S1AP_ID, s1ap_E_RABReleaseCommand->mme_ue_s1ap_id); + + message_p = itti_alloc_new_message(TASK_S1AP, S1AP_E_RAB_RELEASE_COMMAND); + + S1AP_E_RAB_RELEASE_COMMAND(message_p).eNB_ue_s1ap_id = s1ap_E_RABReleaseCommand->eNB_UE_S1AP_ID; + S1AP_E_RAB_RELEASE_COMMAND(message_p).mme_ue_s1ap_id = s1ap_E_RABReleaseCommand->mme_ue_s1ap_id; + if(s1ap_E_RABReleaseCommand->nas_pdu.size > 0 ){ + S1AP_E_RAB_RELEASE_COMMAND(message_p).nas_pdu.length = s1ap_E_RABReleaseCommand->nas_pdu.size; + + S1AP_E_RAB_RELEASE_COMMAND(message_p).nas_pdu.buffer = + malloc(sizeof(uint8_t) * s1ap_E_RABReleaseCommand->nas_pdu.size); + + memcpy(S1AP_E_RAB_RELEASE_COMMAND(message_p).nas_pdu.buffer, + s1ap_E_RABReleaseCommand->nas_pdu.buf, + s1ap_E_RABReleaseCommand->nas_pdu.size); + } else { + S1AP_E_RAB_RELEASE_COMMAND(message_p).nas_pdu.length = 0; + S1AP_E_RAB_RELEASE_COMMAND(message_p).nas_pdu.buffer = NULL; + } + + S1AP_E_RAB_RELEASE_COMMAND(message_p).nb_e_rabs_torelease = s1ap_E_RABReleaseCommand->e_RABToBeReleasedList.s1ap_E_RABItem.count; + for(i=0; i < s1ap_E_RABReleaseCommand->e_RABToBeReleasedList.s1ap_E_RABItem.count; i++){ + S1ap_E_RABItem_t *item_p; + item_p = (S1ap_E_RABItem_t*)s1ap_E_RABReleaseCommand->e_RABToBeReleasedList.s1ap_E_RABItem.array[i]; + S1AP_E_RAB_RELEASE_COMMAND(message_p).e_rab_release_params[i].e_rab_id = item_p->e_RAB_ID; + S1AP_DEBUG("[SCTP] Received E-RAB release command for e-rab id %ld\n", item_p->e_RAB_ID); + } + + itti_send_msg_to_task(TASK_RRC_ENB, ue_desc_p->eNB_instance->instance, message_p); + + return 0; +} diff --git a/openair3/S1AP/s1ap_eNB_nas_procedures.c b/openair3/S1AP/s1ap_eNB_nas_procedures.c index ea0dbcb70a..d6d9b52c07 100644 --- a/openair3/S1AP/s1ap_eNB_nas_procedures.c +++ b/openair3/S1AP/s1ap_eNB_nas_procedures.c @@ -837,3 +837,282 @@ int s1ap_eNB_e_rab_setup_resp(instance_t instance, return ret; } + +//------------------------------------------------------------------------------ +int s1ap_eNB_e_rab_modify_resp(instance_t instance, + s1ap_e_rab_modify_resp_t *e_rab_modify_resp_p) +//------------------------------------------------------------------------------ +{ + s1ap_eNB_instance_t *s1ap_eNB_instance_p = NULL; + struct s1ap_eNB_ue_context_s *ue_context_p = NULL; + + S1ap_E_RABModifyResponseIEs_t *initial_ies_p = NULL; + + s1ap_message message; + + uint8_t *buffer = NULL; + uint32_t length; + int ret = -1; + int i; + + /* Retrieve the S1AP eNB instance associated with Mod_id */ + s1ap_eNB_instance_p = s1ap_eNB_get_instance(instance); + + DevAssert(e_rab_modify_resp_p != NULL); + DevAssert(s1ap_eNB_instance_p != NULL); + + if ((ue_context_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance_p, + e_rab_modify_resp_p->eNB_ue_s1ap_id)) == NULL) { + /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */ + S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: 0x%06x\n", + e_rab_modify_resp_p->eNB_ue_s1ap_id); + return -1; + } + + /* Uplink NAS transport can occur either during an s1ap connected state + * or during initial attach (for example: NAS authentication). + */ + if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED || + ue_context_p->ue_state == S1AP_UE_WAITING_CSR)) { + S1AP_WARN("You are attempting to send NAS data over non-connected " + "eNB ue s1ap id: %06x, current state: %d\n", + e_rab_modify_resp_p->eNB_ue_s1ap_id, ue_context_p->ue_state); + return -1; + } + + /* Prepare the S1AP message to encode */ + memset(&message, 0, sizeof(s1ap_message)); + + message.direction = S1AP_PDU_PR_successfulOutcome; + message.procedureCode = S1ap_ProcedureCode_id_E_RABModify; + message.criticality = S1ap_Criticality_reject; + + initial_ies_p = &message.msg.s1ap_E_RABModifyResponseIEs; + + initial_ies_p->eNB_UE_S1AP_ID = e_rab_modify_resp_p->eNB_ue_s1ap_id; + initial_ies_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id; + + if ( e_rab_modify_resp_p->nb_of_e_rabs >= 1 ) + initial_ies_p->presenceMask |= S1AP_E_RABMODIFYRESPONSEIES_E_RABMODIFYLISTBEARERMODRES_PRESENT; + + for (i = 0; i < e_rab_modify_resp_p->nb_of_e_rabs; i++) { + S1ap_E_RABModifyItemBearerModRes_t *modify_item; + + modify_item = calloc(1, sizeof(S1ap_E_RABModifyItemBearerModRes_t)); + + modify_item->e_RAB_ID = e_rab_modify_resp_p->e_rabs[i].e_rab_id; + + S1AP_DEBUG("e_rab_modify_resp: modified e_rab ID %ld\n", + modify_item->e_RAB_ID); + + S1ap_IE_t *ie = s1ap_new_ie(S1ap_ProtocolIE_ID_id_E_RABModifyItemBearerModRes, + S1ap_Criticality_ignore, + &asn_DEF_S1ap_E_RABModifyItemBearerModRes, + modify_item); + + ASN_SEQUENCE_ADD(&initial_ies_p->e_RABModifyListBearerModRes.s1ap_E_RABModifyItemBearerModRes, + ie); + } + + if ( e_rab_modify_resp_p->nb_of_e_rabs_failed >= 1 ) + initial_ies_p->presenceMask |= S1AP_E_RABMODIFYRESPONSEIES_E_RABFAILEDTOMODIFYLIST_PRESENT; + + for (i = 0; i < e_rab_modify_resp_p->nb_of_e_rabs_failed; i++) { + S1ap_E_RABItem_t *failed_item; + + failed_item = calloc(1, sizeof(S1ap_E_RABItem_t)); + + failed_item->e_RAB_ID = e_rab_modify_resp_p->e_rabs_failed[i].e_rab_id; + switch(e_rab_modify_resp_p->e_rabs_failed[i].cause) + { + case S1AP_CAUSE_RADIO_NETWORK: + failed_item->cause.present = S1ap_Cause_PR_radioNetwork; + failed_item->cause.choice.radioNetwork = e_rab_modify_resp_p->e_rabs_failed[i].cause_value; + break; + case S1AP_CAUSE_TRANSPORT: + failed_item->cause.present = S1ap_Cause_PR_transport; + failed_item->cause.choice.transport = e_rab_modify_resp_p->e_rabs_failed[i].cause_value; + break; + case S1AP_CAUSE_NAS: + failed_item->cause.present = S1ap_Cause_PR_nas; + failed_item->cause.choice.nas = e_rab_modify_resp_p->e_rabs_failed[i].cause_value; + break; + case S1AP_CAUSE_PROTOCOL: + failed_item->cause.present = S1ap_Cause_PR_protocol; + failed_item->cause.choice.protocol = e_rab_modify_resp_p->e_rabs_failed[i].cause_value; + break; + case S1AP_CAUSE_MISC: + failed_item->cause.present = S1ap_Cause_PR_misc; + failed_item->cause.choice.misc = e_rab_modify_resp_p->e_rabs_failed[i].cause_value; + break; + default: + break; + } + S1AP_DEBUG("e_rab_modify_resp: failed e_rab ID %ld\n", + failed_item->e_RAB_ID); + + S1ap_IE_t *ie = s1ap_new_ie(S1ap_ProtocolIE_ID_id_E_RABItem, + S1ap_Criticality_ignore, + &asn_DEF_S1ap_E_RABItem, + failed_item); + + ASN_SEQUENCE_ADD(&initial_ies_p->e_RABFailedToModifyList.s1ap_E_RABItem, + ie); + } + + fprintf(stderr, "start encode\n"); + if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) { + S1AP_ERROR("Failed to encode uplink transport\n"); + /* Encode procedure has failed... */ + return -1; + } + + MSC_LOG_TX_MESSAGE( + MSC_S1AP_ENB, + MSC_S1AP_MME, + (const char *)buffer, + length, + MSC_AS_TIME_FMT" E_RAN Modify successful Outcome eNB_ue_s1ap_id %u mme_ue_s1ap_id %u", + 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + initial_ies_p->eNB_UE_S1AP_ID, + initial_ies_p->mme_ue_s1ap_id); + + /* UE associated signalling -> use the allocated stream */ + s1ap_eNB_itti_send_sctp_data_req(s1ap_eNB_instance_p->instance, + ue_context_p->mme_ref->assoc_id, buffer, + length, ue_context_p->tx_stream); + + return ret; +} +//------------------------------------------------------------------------------ +int s1ap_eNB_e_rab_release_resp(instance_t instance, + s1ap_e_rab_release_resp_t *e_rab_release_resp_p) +//------------------------------------------------------------------------------ +{ + s1ap_eNB_instance_t *s1ap_eNB_instance_p = NULL; + struct s1ap_eNB_ue_context_s *ue_context_p = NULL; + + S1ap_E_RABReleaseResponseIEs_t *release_response_ies_p = NULL; + + s1ap_message message; + + uint8_t *buffer = NULL; + uint32_t length; + int ret = -1; + int i; + /* Retrieve the S1AP eNB instance associated with Mod_id */ + s1ap_eNB_instance_p = s1ap_eNB_get_instance(instance); + DevAssert(e_rab_release_resp_p != NULL); + DevAssert(s1ap_eNB_instance_p != NULL); + + /* Prepare the S1AP message to encode */ + memset(&message, 0, sizeof(s1ap_message)); + + message.direction = S1AP_PDU_PR_successfulOutcome; + message.procedureCode = S1ap_ProcedureCode_id_E_RABRelease; + message.criticality = S1ap_Criticality_ignore; + + if ((ue_context_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance_p, + e_rab_release_resp_p->eNB_ue_s1ap_id)) == NULL) { + /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */ + S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %u\n", + e_rab_release_resp_p->eNB_ue_s1ap_id); + return -1; + } + + release_response_ies_p = &message.msg.s1ap_E_RABReleaseResponseIEs; + release_response_ies_p->eNB_UE_S1AP_ID = e_rab_release_resp_p->eNB_ue_s1ap_id; + release_response_ies_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id; + + if ( e_rab_release_resp_p->nb_of_e_rabs_released > 0 ) + release_response_ies_p->presenceMask |= S1AP_E_RABRELEASERESPONSEIES_E_RABRELEASELISTBEARERRELCOMP_PRESENT; + + //release + for (i = 0; i < e_rab_release_resp_p->nb_of_e_rabs_released; i++) { + + S1ap_E_RABReleaseItemBearerRelComp_t *new_item; + + new_item = calloc(1, sizeof(S1ap_E_RABReleaseItemBearerRelComp_t)); + + new_item->e_RAB_ID = e_rab_release_resp_p->e_rab_release[i].e_rab_id; + + S1AP_DEBUG("e_rab_release_resp: e_rab ID %ld\n",new_item->e_RAB_ID); + + ASN_SEQUENCE_ADD(&release_response_ies_p->e_RABReleaseListBearerRelComp.s1ap_E_RABReleaseItemBearerRelComp, + new_item); + + } + + if ( e_rab_release_resp_p->nb_of_e_rabs_failed > 0 ) + release_response_ies_p->presenceMask |= S1AP_E_RABRELEASERESPONSEIES_E_RABFAILEDTORELEASELIST_PRESENT; + + //release failed + for (i = 0; i < e_rab_release_resp_p->nb_of_e_rabs_failed; i++) { + S1ap_E_RABItem_t *new_rabitem; + new_rabitem = calloc(1, sizeof(S1ap_E_RABItem_t)); + //e_rab_id + new_rabitem->e_RAB_ID = e_rab_release_resp_p->e_rabs_failed[i].e_rab_id; + //cause + switch(e_rab_release_resp_p->e_rabs_failed[i].cause) + { + case S1AP_CAUSE_NOTHING: + new_rabitem->cause.present = S1ap_Cause_PR_NOTHING; + break; + + case S1AP_CAUSE_RADIO_NETWORK: + new_rabitem->cause.present = S1ap_Cause_PR_radioNetwork; + new_rabitem->cause.choice.radioNetwork = e_rab_release_resp_p->e_rabs_failed[i].cause_value; + break; + + case S1AP_CAUSE_TRANSPORT: + new_rabitem->cause.present = S1ap_Cause_PR_transport; + new_rabitem->cause.choice.transport = e_rab_release_resp_p->e_rabs_failed[i].cause_value; + break; + + case S1AP_CAUSE_NAS: + new_rabitem->cause.present = S1ap_Cause_PR_nas; + new_rabitem->cause.choice.nas = e_rab_release_resp_p->e_rabs_failed[i].cause_value; + break; + + case S1AP_CAUSE_PROTOCOL: + new_rabitem->cause.present = S1ap_Cause_PR_protocol; + new_rabitem->cause.choice.protocol = e_rab_release_resp_p->e_rabs_failed[i].cause_value; + break; + + case S1AP_CAUSE_MISC: + default: + new_rabitem->cause.present = S1ap_Cause_PR_misc; + new_rabitem->cause.choice.misc = e_rab_release_resp_p->e_rabs_failed[i].cause_value; + break; + } + S1AP_DEBUG("e_rab_release_resp: failed e_rab ID %ld\n",new_rabitem->e_RAB_ID); + ASN_SEQUENCE_ADD(&release_response_ies_p->e_RABFailedToReleaseList.s1ap_E_RABItem, new_rabitem); + } + + fprintf(stderr, "start encode\n"); + if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) { + S1AP_ERROR("Failed to encode release response\n"); + /* Encode procedure has failed... */ + return -1; + } + + MSC_LOG_TX_MESSAGE( + MSC_S1AP_ENB, + MSC_S1AP_MME, + (const char *)buffer, + length, + MSC_AS_TIME_FMT" E_RAN Release successfulOutcome eNB_ue_s1ap_id %u mme_ue_s1ap_id %u", + 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), + e_rab_release_resp_p->eNB_ue_s1ap_id, + ue_context_p->mme_ue_s1ap_id); + + /* UE associated signalling -> use the allocated stream */ + s1ap_eNB_itti_send_sctp_data_req(s1ap_eNB_instance_p->instance, + ue_context_p->mme_ref->assoc_id, buffer, + length, ue_context_p->tx_stream); + + S1AP_INFO("e_rab_release_response sended eNB_UE_S1AP_ID %d mme_ue_s1ap_id %d nb_of_e_rabs_released %d nb_of_e_rabs_failed %d\n", + e_rab_release_resp_p->eNB_ue_s1ap_id, ue_context_p->mme_ue_s1ap_id,e_rab_release_resp_p->nb_of_e_rabs_released,e_rab_release_resp_p->nb_of_e_rabs_failed); + + return ret; +} diff --git a/openair3/S1AP/s1ap_eNB_nas_procedures.h b/openair3/S1AP/s1ap_eNB_nas_procedures.h index 2693872576..bb2a0488bf 100644 --- a/openair3/S1AP/s1ap_eNB_nas_procedures.h +++ b/openair3/S1AP/s1ap_eNB_nas_procedures.h @@ -44,4 +44,9 @@ int s1ap_eNB_ue_capabilities(instance_t instance, int s1ap_eNB_e_rab_setup_resp(instance_t instance, s1ap_e_rab_setup_resp_t *e_rab_setup_resp_p); +int s1ap_eNB_e_rab_modify_resp(instance_t instance, + s1ap_e_rab_modify_resp_t *e_rab_modify_resp_p); + +int s1ap_eNB_e_rab_release_resp(instance_t instance, + s1ap_e_rab_release_resp_t *e_rab_release_resp_p); #endif /* S1AP_ENB_NAS_PROCEDURES_H_ */ diff --git a/openair3/SECU/kdf.c b/openair3/SECU/kdf.c index 0717d17c59..1073df8ebe 100644 --- a/openair3/SECU/kdf.c +++ b/openair3/SECU/kdf.c @@ -63,3 +63,43 @@ int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB } #endif +int derive_keNB_star( + const uint8_t *kenb_32, + const uint16_t pci, + const uint32_t earfcn_dl, + const bool is_rel8_only, + uint8_t *kenb_star) +{ + // see 33.401 section A.5 KeNB* derivation function + uint8_t s[10] = {0}; + + // FC = 0x13 + s[0] = FC_KENB_STAR; + // P0 = PCI (target physical cell id) + s[1] = (pci & 0x0000ff00) >> 8; + s[2] = (pci & 0x000000ff); + // L0 = length of PCI (i.e. 0x00 0x02) + s[3] = 0x00; + s[4] = 0x02; + // P1 = EARFCN-DL (target physical cell downlink frequency) + if (is_rel8_only) { + s[5] = (earfcn_dl & 0x0000ff00) >> 8; + s[6] = (earfcn_dl & 0x000000ff); + s[7] = 0x00; + s[8] = 0x02; + kdf (kenb_32, 32, s, 9, kenb_star, 32); + } else { + s[5] = (earfcn_dl & 0x00ff0000) >> 16; + s[6] = (earfcn_dl & 0x0000ff00) >> 8; + s[7] = (earfcn_dl & 0x000000ff); + s[8] = 0x00; + s[9] = 0x03; + kdf (kenb_32, 32, s, 10, kenb_star, 32); + } + // L1 length of EARFCN-DL (i.e. L1 = 0x00 0x02 if EARFCN-DL is between 0 and 65535, and L1 = 0x00 0x03 if EARFCN-DL is between 65536 and 262143) + // NOTE: The length of EARFCN-DL cannot be generally set to 3 bytes for backward compatibility reasons: A Rel-8 + // entity (UE or eNB) would always assume an input parameter length of 2 bytes for the EARFCN-DL. This + // would lead to different derived keys if another entity assumed an input parameter length of 3 bytes for the + // EARFCN-DL. + return 0; +} diff --git a/openair3/SECU/secu_defs.h b/openair3/SECU/secu_defs.h index 4130098c99..8ec05f3daf 100644 --- a/openair3/SECU/secu_defs.h +++ b/openair3/SECU/secu_defs.h @@ -23,6 +23,7 @@ #define SECU_DEFS_H_ #include "security_types.h" +#include #define EIA0_ALG_ID 0x00 #define EIA1_128_ALG_ID 0x01 @@ -44,6 +45,9 @@ void kdf(const uint8_t *key, int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB); +int derive_keNB_star(const uint8_t *kenb_32, const uint16_t pci, const uint32_t earfcn_dl, + const bool is_rel8_only, uint8_t * kenb_star); + int derive_key_nas(algorithm_type_dist_t nas_alg_type, uint8_t nas_enc_alg_id, const uint8_t kasme[32], uint8_t *knas); diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 3dfa2f5936..3e1b4195a8 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1148,6 +1148,10 @@ int main( int argc, char **argv ) RCconfig_L1(); } #endif + + // init UE_PF_PO and mutex lock + pthread_mutex_init(&ue_pf_po_mutex, NULL); + memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*NUMBER_OF_UE_MAX*MAX_NUM_CCs); if (phy_test==0) { if (UE_flag==1) { @@ -1369,7 +1373,7 @@ int main( int argc, char **argv ) pthread_cond_destroy(&sync_cond); pthread_mutex_destroy(&sync_mutex); - + pthread_mutex_destroy(&ue_pf_po_mutex); // *** Handle per CC_id openair0 if (UE_flag==1) { From b98a98b95b66881dca5d62308430fb1518f1b9e9 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Tue, 28 Nov 2017 14:42:33 +0100 Subject: [PATCH 089/284] few minor fixes --- openair2/RRC/LITE/L2_interface.c | 5 ++++- targets/RT/USER/lte-softmodem.c | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/openair2/RRC/LITE/L2_interface.c b/openair2/RRC/LITE/L2_interface.c index 408e0e8175..504bf8ee9b 100644 --- a/openair2/RRC/LITE/L2_interface.c +++ b/openair2/RRC/LITE/L2_interface.c @@ -807,7 +807,10 @@ mac_UE_get_rrc_status( ) //------------------------------------------------------------------------------ { - return(UE_rrc_inst[Mod_idP].Info[indexP].State); + if (UE_rrc_inst) + return(UE_rrc_inst[Mod_idP].Info[indexP].State); + else + return(-1); } //-------------------------------------------------------------------------------------------// diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 8dd479c9b9..e90fc4335c 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -633,7 +633,7 @@ static void get_options(void) { } if (n_rb_dl !=0) { - printf("NB_RB set to %d\n",frame_parms[0]->N_RB_DL); + printf("NB_RB set to %d\n",n_rb_dl); if ( n_rb_dl < 6 ) { n_rb_dl = 6; printf ( "%i: Invalid number of ressource blocks, adjusted to 6\n",n_rb_dl); @@ -936,7 +936,7 @@ int main( int argc, char **argv ) printf("configuring for UE\n"); set_comp_log(HW, LOG_DEBUG, LOG_HIGH, 1); - set_comp_log(PHY, LOG_DEBUG, LOG_HIGH, 1); + set_comp_log(PHY, LOG_INFO, LOG_HIGH, 1); set_comp_log(MAC, LOG_INFO, LOG_HIGH, 1); set_comp_log(RLC, LOG_INFO, LOG_HIGH | FLAG_THREAD, 1); set_comp_log(PDCP, LOG_INFO, LOG_HIGH, 1); From 5847a14053e3e5e86e0fc0178bbb604066177ef4 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Thu, 30 Nov 2017 11:45:33 +0100 Subject: [PATCH 090/284] bugfix in phy_procedures_lte_ue making oaisim_nos1 compile --- cmake_targets/CMakeLists.txt | 2 +- openair1/SCHED/phy_procedures_lte_ue.c | 7 +++---- targets/RT/USER/lte-softmodem.c | 2 +- targets/RT/USER/lte-softmodem.h | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 4fc2e1ccd3..be49dd4dc2 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1934,7 +1934,7 @@ add_executable(oaisim_nos1 ${x2ap_h} ${OPENAIR_BIN_DIR}/messages_xml.h ${OPENAIR_TARGETS}/RT/USER/lte-ue.c - ${OPENAIR_TARGETS}/RT/USER/lte-enb.c + ${OPENAIR_TARGETS}/RT/USER/lte-ru.c ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c ${OPENAIR_TARGETS}/SIMU/USER/channel_sim.c ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index a1ad4c5375..6094f52940 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -2939,12 +2939,12 @@ int ue_pdcch_procedures(uint8_t eNB_id,PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint //dump_dci(&ue->frame_parms, &dci_alloc_rx[i]); ue->UE_mode[eNB_id] = PUSCH; - - } else { + } + } else { LOG_E(PHY,"[UE %d] Frame %d, subframe %d: Problem in DCI!\n",ue->Mod_id,frame_rx,subframe_rx); dump_dci(&ue->frame_parms, &dci_alloc_rx[i]); } - } + } else if ((dci_alloc_rx[i].rnti == SI_RNTI) && ((dci_alloc_rx[i].format == format1A) || (dci_alloc_rx[i].format == format1C))) { @@ -2977,7 +2977,6 @@ int ue_pdcch_procedures(uint8_t eNB_id,PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint } } - } else if ((dci_alloc_rx[i].rnti == P_RNTI) && ((dci_alloc_rx[i].format == format1A) || (dci_alloc_rx[i].format == format1C))) { diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 8dd479c9b9..f9b177365c 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -633,7 +633,7 @@ static void get_options(void) { } if (n_rb_dl !=0) { - printf("NB_RB set to %d\n",frame_parms[0]->N_RB_DL); + printf("NB_RB set to %d\n",n_rb_dl); if ( n_rb_dl < 6 ) { n_rb_dl = 6; printf ( "%i: Invalid number of ressource blocks, adjusted to 6\n",n_rb_dl); diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index c12e275f92..44e35c88a3 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -65,7 +65,7 @@ #define CONFIG_HLP_NOSNGLT "Disables single-thread mode in lte-softmodem\n" #define CONFIG_HLP_TADV "Set timing_advance\n" #define CONFIG_HLP_DLF "Set the downlink frequency for all component carriers\n" -#define CONFIG_HLP_CHOFF "Channel id offset" +#define CONFIG_HLP_CHOFF "Channel id offset\n" #define CONFIG_HLP_SOFTS "Enable soft scope and L1 and L2 stats (Xforms)\n" #define CONFIG_HLP_EXMCAL "Calibrate the EXMIMO borad, available files: exmimo2_2arxg.lime exmimo2_2brxg.lime \n" #define CONFIG_HLP_ITTIL "Generate ITTI analyzser logs (similar to wireshark logs but with more details)\n" From 7489644cc111902ffcd2acb1b4eef601e1fb03d5 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Tue, 14 Nov 2017 13:57:34 +0100 Subject: [PATCH 091/284] added .ipe file for L1_L2_procedures slides and updated .pdf file Conflicts: targets/DOCS/oai_L1_L2_procedures.pdf --- targets/DOCS/oai_L1_L2_procedures.pdf | Bin 663552 -> 1511882 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/targets/DOCS/oai_L1_L2_procedures.pdf b/targets/DOCS/oai_L1_L2_procedures.pdf index 28a4416e83a119a8950658dfe93969e8d5e2af6a..4e8059f503d8a4fedd634dc014c4f572275a5be8 100644 GIT binary patch delta 251133 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

  • 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%0A!i(S3$Wn` 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/pTdQGxgUgT}<{9=|?g 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 delta 28 jcmX@LIHuu%Mnel@3sVbo3rh=Y3tJ0&3r7p*5-tS*o$U!x From e68d6bd4c01e476a748b22d20894ae288b593cf9 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 1 Dec 2017 12:15:07 +0100 Subject: [PATCH 092/284] integration fix: remove compilation warning --- openair2/LAYER2/MAC/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/MAC/main.c b/openair2/LAYER2/MAC/main.c index fcaab0b80b..534f603dfd 100644 --- a/openair2/LAYER2/MAC/main.c +++ b/openair2/LAYER2/MAC/main.c @@ -210,7 +210,7 @@ void mac_init_cell_params(int Mod_idP, int CC_idP) UE_TEMPLATE *UE_template; LOG_D(MAC, "[MSC_NEW][FRAME 00000][MAC_eNB][MOD %02d][]\n", Mod_idP); - COMMON_channels_t *cc = &RC.mac[Mod_idP]->common_channels[CC_idP]; + //COMMON_channels_t *cc = &RC.mac[Mod_idP]->common_channels[CC_idP]; memset(&RC.mac[Mod_idP]->eNB_stats, 0, sizeof(eNB_STATS)); UE_template = From a7b7de35b9db75220087128365754ade5ee812bf Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 1 Dec 2017 12:15:34 +0100 Subject: [PATCH 093/284] integration fix: remove compilation warning (not sure -1 is the correct value) --- common/config/config_userapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/config/config_userapi.c b/common/config/config_userapi.c index 37c77be93f..4e49f2c56a 100644 --- a/common/config/config_userapi.c +++ b/common/config/config_userapi.c @@ -153,5 +153,5 @@ int config_isparamset(paramdef_t *params,int paramidx) } int config_getparamval_fromparamdefidx(paramdef_t *cfgoptions,int paramidx) { - + return -1; } From 1a5a0297686876f84ea15f1aa7698504d2af6772 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sat, 2 Dec 2017 15:15:30 -0800 Subject: [PATCH 094/284] minor changes to config.c --- openair2/LAYER2/MAC/config.c | 1851 ++++++++++++++++------------------ 1 file changed, 882 insertions(+), 969 deletions(-) diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index 764c762f6a..6943013c34 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -63,34 +63,34 @@ extern RAN_CONTEXT_t RC; void ue_mac_reset(module_id_t module_idP, uint8_t eNB_index) { - //Resetting Bj - UE_mac_inst[module_idP].scheduling_info.Bj[0] = 0; - UE_mac_inst[module_idP].scheduling_info.Bj[1] = 0; - UE_mac_inst[module_idP].scheduling_info.Bj[2] = 0; + //Resetting Bj + UE_mac_inst[module_idP].scheduling_info.Bj[0] = 0; + UE_mac_inst[module_idP].scheduling_info.Bj[1] = 0; + UE_mac_inst[module_idP].scheduling_info.Bj[2] = 0; - //Stopping all timers + //Stopping all timers - //timeAlignmentTimer expires + //timeAlignmentTimer expires - // PHY changes for UE MAC reset - phy_reset_ue(module_idP, 0, eNB_index); + // PHY changes for UE MAC reset + phy_reset_ue(module_idP, 0, eNB_index); - // notify RRC to relase PUCCH/SRS - // cancel all pending SRs - UE_mac_inst[module_idP].scheduling_info.SR_pending = 0; - UE_mac_inst[module_idP].scheduling_info.SR_COUNTER = 0; + // notify RRC to relase PUCCH/SRS + // cancel all pending SRs + UE_mac_inst[module_idP].scheduling_info.SR_pending = 0; + UE_mac_inst[module_idP].scheduling_info.SR_COUNTER = 0; -//Set BSR Trigger Bmp and remove timer flags - UE_mac_inst[module_idP].BSR_reporting_active = BSR_TRIGGER_NONE; + //Set BSR Trigger Bmp and remove timer flags + UE_mac_inst[module_idP].BSR_reporting_active = BSR_TRIGGER_NONE; - // stop ongoing RACH procedure + // stop ongoing RACH procedure - // discard explicitly signaled ra_PreambleIndex and ra_RACH_MaskIndex, if any - UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = 0; // check! - UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0; + // discard explicitly signaled ra_PreambleIndex and ra_RACH_MaskIndex, if any + UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = 0; // check! + UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0; - ue_init_mac(module_idP); //This will hopefully do the rest of the MAC reset procedure + ue_init_mac(module_idP); //This will hopefully do the rest of the MAC reset procedure } @@ -99,121 +99,121 @@ int32_t **txdata; typedef struct eutra_bandentry_s { - int16_t band; - uint32_t ul_min; - uint32_t ul_max; - uint32_t dl_min; - uint32_t dl_max; - uint32_t N_OFFs_DL; + int16_t band; + uint32_t ul_min; + uint32_t ul_max; + uint32_t dl_min; + uint32_t dl_max; + uint32_t N_OFFs_DL; } eutra_bandentry_t; typedef struct band_info_s { - int nbands; - eutra_bandentry_t band_info[100]; + int nbands; + eutra_bandentry_t band_info[100]; } band_info_t; static const eutra_bandentry_t eutra_bandtable[] = { - {1, 19200, 19800, 21100, 21700, 0}, - {2, 18500, 19100, 19300, 19900, 6000}, - {3, 17100, 17850, 18050, 18800, 12000}, - {4, 17100, 17550, 21100, 21550, 19500}, - {5, 8240, 8490, 8690, 8940, 24000}, - {6, 8300, 8400, 8750, 8850, 26500}, - {7, 25000, 25700, 26200, 26900, 27500}, - {8, 8800, 9150, 9250, 9600, 34500}, - {9, 17499, 17849, 18449, 18799, 38000}, - {10, 17100, 17700, 21100, 21700, 41500}, - {11, 14279, 14529, 14759, 15009, 47500}, - {12, 6980, 7160, 7280, 7460, 50100}, - {13, 7770, 7870, 7460, 7560, 51800}, - {14, 7880, 7980, 7580, 7680, 52800}, - {17, 7040, 7160, 7340, 7460, 57300}, - {18, 8150, 9650, 8600, 10100, 58500}, - {19, 8300, 8450, 8750, 8900, 60000}, - {20, 8320, 8620, 7910, 8210, 61500}, - {21, 14479, 14629, 14959, 15109, 64500}, - {22, 34100, 34900, 35100, 35900, 66000}, - {23, 20000, 20200, 21800, 22000, 75000}, - {24, 16126, 16605, 15250, 15590, 77000}, - {25, 18500, 19150, 19300, 19950, 80400}, - {26, 8140, 8490, 8590, 8940, 86900}, - {27, 8070, 8240, 8520, 8690, 90400}, - {28, 7030, 7580, 7580, 8130, 92100}, - {29, 0, 0, 7170, 7280, 96600}, - {30, 23050, 23250, 23500, 23600, 97700}, - {31, 45250, 34900, 46250, 35900, 98700}, - {32, 0, 0, 14520, 14960, 99200}, - {33, 19000, 19200, 19000, 19200, 36000}, - {34, 20100, 20250, 20100, 20250, 36200}, - {35, 18500, 19100, 18500, 19100, 36350}, - {36, 19300, 19900, 19300, 19900, 36950}, - {37, 19100, 19300, 19100, 19300, 37550}, - {38, 25700, 26200, 25700, 26300, 37750}, - {39, 18800, 19200, 18800, 19200, 38250}, - {40, 23000, 24000, 23000, 24000, 38650}, - {41, 24960, 26900, 24960, 26900, 39650}, - {42, 34000, 36000, 34000, 36000, 41590}, - {43, 36000, 38000, 36000, 38000, 43590}, - {44, 7030, 8030, 7030, 8030, 45590}, - {45, 14470, 14670, 14470, 14670, 46590}, - {46, 51500, 59250, 51500, 59250, 46790}, - {65, 19200, 20100, 21100, 22000, 65536}, - {66, 17100, 18000, 21100, 22000, 66436}, - {67, 0, 0, 7380, 7580, 67336}, - {68, 6980, 7280, 7530, 7830, 67536} + {1, 19200, 19800, 21100, 21700, 0}, + {2, 18500, 19100, 19300, 19900, 6000}, + {3, 17100, 17850, 18050, 18800, 12000}, + {4, 17100, 17550, 21100, 21550, 19500}, + {5, 8240, 8490, 8690, 8940, 24000}, + {6, 8300, 8400, 8750, 8850, 26500}, + {7, 25000, 25700, 26200, 26900, 27500}, + {8, 8800, 9150, 9250, 9600, 34500}, + {9, 17499, 17849, 18449, 18799, 38000}, + {10, 17100, 17700, 21100, 21700, 41500}, + {11, 14279, 14529, 14759, 15009, 47500}, + {12, 6980, 7160, 7280, 7460, 50100}, + {13, 7770, 7870, 7460, 7560, 51800}, + {14, 7880, 7980, 7580, 7680, 52800}, + {17, 7040, 7160, 7340, 7460, 57300}, + {18, 8150, 9650, 8600, 10100, 58500}, + {19, 8300, 8450, 8750, 8900, 60000}, + {20, 8320, 8620, 7910, 8210, 61500}, + {21, 14479, 14629, 14959, 15109, 64500}, + {22, 34100, 34900, 35100, 35900, 66000}, + {23, 20000, 20200, 21800, 22000, 75000}, + {24, 16126, 16605, 15250, 15590, 77000}, + {25, 18500, 19150, 19300, 19950, 80400}, + {26, 8140, 8490, 8590, 8940, 86900}, + {27, 8070, 8240, 8520, 8690, 90400}, + {28, 7030, 7580, 7580, 8130, 92100}, + {29, 0, 0, 7170, 7280, 96600}, + {30, 23050, 23250, 23500, 23600, 97700}, + {31, 45250, 34900, 46250, 35900, 98700}, + {32, 0, 0, 14520, 14960, 99200}, + {33, 19000, 19200, 19000, 19200, 36000}, + {34, 20100, 20250, 20100, 20250, 36200}, + {35, 18500, 19100, 18500, 19100, 36350}, + {36, 19300, 19900, 19300, 19900, 36950}, + {37, 19100, 19300, 19100, 19300, 37550}, + {38, 25700, 26200, 25700, 26300, 37750}, + {39, 18800, 19200, 18800, 19200, 38250}, + {40, 23000, 24000, 23000, 24000, 38650}, + {41, 24960, 26900, 24960, 26900, 39650}, + {42, 34000, 36000, 34000, 36000, 41590}, + {43, 36000, 38000, 36000, 38000, 43590}, + {44, 7030, 8030, 7030, 8030, 45590}, + {45, 14470, 14670, 14470, 14670, 46590}, + {46, 51500, 59250, 51500, 59250, 46790}, + {65, 19200, 20100, 21100, 22000, 65536}, + {66, 17100, 18000, 21100, 22000, 66436}, + {67, 0, 0, 7380, 7580, 67336}, + {68, 6980, 7280, 7530, 7830, 67536} }; uint32_t to_earfcn(int eutra_bandP, uint32_t dl_CarrierFreq, uint32_t bw) { - uint32_t dl_CarrierFreq_by_100k = dl_CarrierFreq / 100000; - int bw_by_100 = bw / 100; + uint32_t dl_CarrierFreq_by_100k = dl_CarrierFreq / 100000; + int bw_by_100 = bw / 100; - int i; + int i; - AssertFatal(eutra_bandP < 69, "eutra_band %d > 68\n", eutra_bandP); - for (i = 0; i < 69 && eutra_bandtable[i].band != eutra_bandP; i++); + AssertFatal(eutra_bandP < 69, "eutra_band %d > 68\n", eutra_bandP); + for (i = 0; i < 69 && eutra_bandtable[i].band != eutra_bandP; i++); - AssertFatal(dl_CarrierFreq_by_100k >= eutra_bandtable[i].dl_min, - "Band %d, bw %u : DL carrier frequency %u Hz < %u\n", - eutra_bandP, bw, dl_CarrierFreq, - eutra_bandtable[i].dl_min); - AssertFatal(dl_CarrierFreq_by_100k <= - (eutra_bandtable[i].dl_max - bw_by_100), - "Band %d, bw %u: DL carrier frequency %u Hz > %d\n", - eutra_bandP, bw, dl_CarrierFreq, - eutra_bandtable[i].dl_max - bw_by_100); + AssertFatal(dl_CarrierFreq_by_100k >= eutra_bandtable[i].dl_min, + "Band %d, bw %u : DL carrier frequency %u Hz < %u\n", + eutra_bandP, bw, dl_CarrierFreq, + eutra_bandtable[i].dl_min); + AssertFatal(dl_CarrierFreq_by_100k <= + (eutra_bandtable[i].dl_max - bw_by_100), + "Band %d, bw %u: DL carrier frequency %u Hz > %d\n", + eutra_bandP, bw, dl_CarrierFreq, + eutra_bandtable[i].dl_max - bw_by_100); - return (dl_CarrierFreq_by_100k - eutra_bandtable[i].dl_min + - (eutra_bandtable[i].N_OFFs_DL / 10)); + return (dl_CarrierFreq_by_100k - eutra_bandtable[i].dl_min + + (eutra_bandtable[i].N_OFFs_DL / 10)); } uint32_t from_earfcn(int eutra_bandP, uint32_t dl_earfcn) { - int i; + int i; - AssertFatal(eutra_bandP < 69, "eutra_band %d > 68\n", eutra_bandP); - for (i = 0; i < 69 && eutra_bandtable[i].band != eutra_bandP; i++); + AssertFatal(eutra_bandP < 69, "eutra_band %d > 68\n", eutra_bandP); + for (i = 0; i < 69 && eutra_bandtable[i].band != eutra_bandP; i++); - return (eutra_bandtable[i].dl_min + - (dl_earfcn - (eutra_bandtable[i].N_OFFs_DL / 10))) * 100000; + return (eutra_bandtable[i].dl_min + + (dl_earfcn - (eutra_bandtable[i].N_OFFs_DL / 10))) * 100000; } int32_t get_uldl_offset(int eutra_bandP) { - int i; + int i; - for (i = 0; i < 69 && eutra_bandtable[i].band != eutra_bandP; i++); - return (eutra_bandtable[i].dl_min - eutra_bandtable[i].ul_min); + for (i = 0; i < 69 && eutra_bandtable[i].band != eutra_bandP; i++); + return (eutra_bandtable[i].dl_min - eutra_bandtable[i].ul_min); } uint32_t bw_table[6] = - { 6 * 180, 15 * 180, 25 * 180, 50 * 180, 75 * 180, 100 * 180 }; + { 6 * 180, 15 * 180, 25 * 180, 50 * 180, 75 * 180, 100 * 180 }; void config_mib(int Mod_idP, @@ -228,52 +228,52 @@ config_mib(int Mod_idP, uint32_t ul_CarrierFreqP, uint32_t pbch_repetitionP) { - nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; + nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; - cfg->subframe_config.pcfich_power_offset.value = 6000; // 0dB - cfg->subframe_config.dl_cyclic_prefix_type.value = NcpP; - cfg->subframe_config.ul_cyclic_prefix_type.value = NcpP; + cfg->subframe_config.pcfich_power_offset.value = 6000; // 0dB + cfg->subframe_config.dl_cyclic_prefix_type.value = NcpP; + cfg->subframe_config.ul_cyclic_prefix_type.value = NcpP; - LOG_I(MAC, "Ncp %d,p_eNB %d\n", NcpP, p_eNBP); + LOG_I(MAC, "Ncp %d,p_eNB %d\n", NcpP, p_eNBP); - cfg->rf_config.dl_channel_bandwidth.value = dl_BandwidthP; - cfg->rf_config.ul_channel_bandwidth.value = dl_BandwidthP; - cfg->rf_config.tx_antenna_ports.value = p_eNBP; - cfg->rf_config.rx_antenna_ports.value = 2; + cfg->rf_config.dl_channel_bandwidth.value = dl_BandwidthP; + cfg->rf_config.ul_channel_bandwidth.value = dl_BandwidthP; + cfg->rf_config.tx_antenna_ports.value = p_eNBP; + cfg->rf_config.rx_antenna_ports.value = 2; - cfg->nfapi_config.earfcn.value = - to_earfcn(eutra_bandP, dl_CarrierFreqP, - bw_table[dl_BandwidthP] / 100); - cfg->nfapi_config.rf_bands.number_rf_bands = 1; - cfg->nfapi_config.rf_bands.rf_band[0] = eutra_bandP; - cfg->phich_config.phich_resource.value = phich_configP->phich_Resource; - cfg->phich_config.phich_duration.value = phich_configP->phich_Duration; - cfg->phich_config.phich_power_offset.value = 6000; // 0dB + cfg->nfapi_config.earfcn.value = + to_earfcn(eutra_bandP, dl_CarrierFreqP, + bw_table[dl_BandwidthP] / 100); + cfg->nfapi_config.rf_bands.number_rf_bands = 1; + cfg->nfapi_config.rf_bands.rf_band[0] = eutra_bandP; + cfg->phich_config.phich_resource.value = phich_configP->phich_Resource; + cfg->phich_config.phich_duration.value = phich_configP->phich_Duration; + cfg->phich_config.phich_power_offset.value = 6000; // 0dB - cfg->sch_config.primary_synchronization_signal_epre_eprers.value = 6000; // 0dB - cfg->sch_config.secondary_synchronization_signal_epre_eprers.value = 6000; // 0dB - cfg->sch_config.physical_cell_id.value = Nid_cellP; + cfg->sch_config.primary_synchronization_signal_epre_eprers.value = 6000; // 0dB + cfg->sch_config.secondary_synchronization_signal_epre_eprers.value = 6000; // 0dB + cfg->sch_config.physical_cell_id.value = Nid_cellP; #ifdef Rel14 - cfg->emtc_config.pbch_repetitions_enable_r13.value = pbch_repetitionP; + cfg->emtc_config.pbch_repetitions_enable_r13.value = pbch_repetitionP; #endif } void config_sib1(int Mod_idP, int CC_idP, TDD_Config_t * tdd_ConfigP) { - nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; + nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; - if (tdd_ConfigP) { //TDD - cfg->subframe_config.duplex_mode.value = 0; - cfg->tdd_frame_structure_config.subframe_assignment.value = - tdd_ConfigP->subframeAssignment; - cfg->tdd_frame_structure_config.special_subframe_patterns.value = - tdd_ConfigP->specialSubframePatterns; - } else { // FDD - cfg->subframe_config.duplex_mode.value = 1; - // Note no half-duplex here - } + if (tdd_ConfigP) { //TDD + cfg->subframe_config.duplex_mode.value = 0; + cfg->tdd_frame_structure_config.subframe_assignment.value = + tdd_ConfigP->subframeAssignment; + cfg->tdd_frame_structure_config.special_subframe_patterns.value = + tdd_ConfigP->specialSubframePatterns; + } else { // FDD + cfg->subframe_config.duplex_mode.value = 1; + // Note no half-duplex here + } } @@ -294,241 +294,154 @@ config_sib2(int Mod_idP, struct MBSFN_SubframeConfigList *mbsfn_SubframeConfigListP) { - nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; + nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; - cfg->subframe_config.pb.value = - radioResourceConfigCommonP->pdsch_ConfigCommon.p_b; - cfg->rf_config.reference_signal_power.value = - radioResourceConfigCommonP->pdsch_ConfigCommon. - referenceSignalPower; - cfg->nfapi_config.max_transmit_power.value = - cfg->rf_config.reference_signal_power.value + - power_off_dB[cfg->rf_config.dl_channel_bandwidth.value]; + cfg->subframe_config.pb.value = radioResourceConfigCommonP->pdsch_ConfigCommon.p_b; + cfg->rf_config.reference_signal_power.value = radioResourceConfigCommonP->pdsch_ConfigCommon.referenceSignalPower; + cfg->nfapi_config.max_transmit_power.value = cfg->rf_config.reference_signal_power.value + + power_off_dB[cfg->rf_config.dl_channel_bandwidth.value]; - cfg->prach_config.configuration_index.value = - radioResourceConfigCommonP->prach_Config. - prach_ConfigInfo.prach_ConfigIndex; - cfg->prach_config.root_sequence_index.value = - radioResourceConfigCommonP->prach_Config.rootSequenceIndex; - cfg->prach_config.zero_correlation_zone_configuration.value = - radioResourceConfigCommonP->prach_Config. - prach_ConfigInfo.zeroCorrelationZoneConfig; - cfg->prach_config.high_speed_flag.value = - radioResourceConfigCommonP->prach_Config.prach_ConfigInfo. - highSpeedFlag; - cfg->prach_config.frequency_offset.value = - radioResourceConfigCommonP->prach_Config. - prach_ConfigInfo.prach_FreqOffset; + cfg->prach_config.configuration_index.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.prach_ConfigIndex; + cfg->prach_config.root_sequence_index.value = radioResourceConfigCommonP->prach_Config.rootSequenceIndex; + cfg->prach_config.zero_correlation_zone_configuration.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig; + cfg->prach_config.high_speed_flag.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.highSpeedFlag; + cfg->prach_config.frequency_offset.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.prach_FreqOffset; - cfg->pusch_config.hopping_mode.value = - radioResourceConfigCommonP->pusch_ConfigCommon. - pusch_ConfigBasic.hoppingMode; - cfg->pusch_config.number_of_subbands.value = - radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic. - n_SB; - cfg->pusch_config.hopping_offset.value = - radioResourceConfigCommonP->pusch_ConfigCommon. - pusch_ConfigBasic.pusch_HoppingOffset; + cfg->pusch_config.hopping_mode.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode; + cfg->pusch_config.number_of_subbands.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.n_SB; + cfg->pusch_config.hopping_offset.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset; + cfg->pucch_config.delta_pucch_shift.value = radioResourceConfigCommonP->pucch_ConfigCommon.deltaPUCCH_Shift; + cfg->pucch_config.n_cqi_rb.value = radioResourceConfigCommonP->pucch_ConfigCommon.nRB_CQI; + cfg->pucch_config.n_an_cs.value = radioResourceConfigCommonP->pucch_ConfigCommon.nCS_AN; + cfg->pucch_config.n1_pucch_an.value = radioResourceConfigCommonP->pucch_ConfigCommon.n1PUCCH_AN; + if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled == true) + cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 1; + else if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled == true) + cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 2; + else // No hopping + cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 0; - cfg->pucch_config.delta_pucch_shift.value = - radioResourceConfigCommonP->pucch_ConfigCommon.deltaPUCCH_Shift; - cfg->pucch_config.n_cqi_rb.value = - radioResourceConfigCommonP->pucch_ConfigCommon.nRB_CQI; - cfg->pucch_config.n_an_cs.value = - radioResourceConfigCommonP->pucch_ConfigCommon.nCS_AN; - cfg->pucch_config.n1_pucch_an.value = - radioResourceConfigCommonP->pucch_ConfigCommon.n1PUCCH_AN; + cfg->uplink_reference_signal_config.group_assignment.value = radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH; + cfg->uplink_reference_signal_config.cyclic_shift_1_for_drms.value = radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift; - if (radioResourceConfigCommonP-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled == - true) - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 1; - else if (radioResourceConfigCommonP-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. - sequenceHoppingEnabled == true) - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 2; - else // No hopping - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 0; + // how to enable/disable SRS? + if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.present == SoundingRS_UL_ConfigCommon_PR_setup) { + cfg->srs_config.bandwidth_configuration.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_BandwidthConfig; + cfg->srs_config.srs_subframe_configuration.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig; + cfg->srs_config.srs_acknack_srs_simultaneous_transmission.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; - cfg->uplink_reference_signal_config.group_assignment.value = - radioResourceConfigCommonP-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH; - cfg->uplink_reference_signal_config.cyclic_shift_1_for_drms.value = - radioResourceConfigCommonP-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift; - - // how to enable/disable SRS? - if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.present == - SoundingRS_UL_ConfigCommon_PR_setup) { - cfg->srs_config.bandwidth_configuration.value = - radioResourceConfigCommonP->soundingRS_UL_ConfigCommon. - choice.setup.srs_BandwidthConfig; - cfg->srs_config.srs_subframe_configuration.value = - radioResourceConfigCommonP->soundingRS_UL_ConfigCommon. - choice.setup.srs_SubframeConfig; - cfg->srs_config.srs_acknack_srs_simultaneous_transmission.value = - radioResourceConfigCommonP->soundingRS_UL_ConfigCommon. - choice.setup.ackNackSRS_SimultaneousTransmission; - - if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon. - choice.setup.srs_MaxUpPts) - cfg->srs_config.max_up_pts.value = 1; - else - cfg->srs_config.max_up_pts.value = 0; - } + if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts) + cfg->srs_config.max_up_pts.value = 1; + else + cfg->srs_config.max_up_pts.value = 0; + } #ifdef Rel14 - if (RC.mac[Mod_idP]->common_channels[CC_idP].mib-> - message.schedulingInfoSIB1_BR_r13 > 0) { - AssertFatal(radioResourceConfigCommon_BRP != NULL, - "radioResource rou is missing\n"); - AssertFatal(radioResourceConfigCommon_BRP->ext4 != NULL, - "ext4 is missing\n"); - cfg->emtc_config.prach_catm_root_sequence_index.value = - radioResourceConfigCommon_BRP->prach_Config.rootSequenceIndex; - cfg->emtc_config.prach_catm_zero_correlation_zone_configuration. - value = - radioResourceConfigCommon_BRP->prach_Config. - prach_ConfigInfo.zeroCorrelationZoneConfig; - cfg->emtc_config.prach_catm_high_speed_flag.value = - radioResourceConfigCommon_BRP->prach_Config. - prach_ConfigInfo.highSpeedFlag; + if (RC.mac[Mod_idP]->common_channels[CC_idP].mib->message.schedulingInfoSIB1_BR_r13 > 0) { + AssertFatal(radioResourceConfigCommon_BRP != NULL, + "radioResource rou is missing\n"); + AssertFatal(radioResourceConfigCommon_BRP->ext4 != NULL, + "ext4 is missing\n"); + cfg->emtc_config.prach_catm_root_sequence_index.value = radioResourceConfigCommon_BRP->prach_Config.rootSequenceIndex; + cfg->emtc_config.prach_catm_zero_correlation_zone_configuration.value = radioResourceConfigCommon_BRP->prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig; + cfg->emtc_config.prach_catm_high_speed_flag.value = radioResourceConfigCommon_BRP->prach_Config.prach_ConfigInfo.highSpeedFlag; - struct PRACH_ConfigSIB_v1310 *ext4_prach = - radioResourceConfigCommon_BRP->ext4->prach_ConfigCommon_v1310; + struct PRACH_ConfigSIB_v1310 *ext4_prach = radioResourceConfigCommon_BRP->ext4->prach_ConfigCommon_v1310; - PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13 = - &ext4_prach->prach_ParametersListCE_r13; + PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13; - PRACH_ParametersCE_r13_t *p; - cfg->emtc_config.prach_ce_level_0_enable.value = 0; - cfg->emtc_config.prach_ce_level_1_enable.value = 0; - cfg->emtc_config.prach_ce_level_2_enable.value = 0; - cfg->emtc_config.prach_ce_level_3_enable.value = 0; - switch (prach_ParametersListCE_r13->list.count) { - case 4: - p = prach_ParametersListCE_r13->list.array[3]; - cfg->emtc_config.prach_ce_level_3_enable.value = 1; - cfg->emtc_config.prach_ce_level_3_configuration_index.value = - p->prach_ConfigIndex_r13; - cfg->emtc_config.prach_ce_level_3_frequency_offset.value = - p->prach_FreqOffset_r13; - cfg-> - emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt. - value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) - cfg-> - emtc_config.prach_ce_level_3_starting_subframe_periodicity. - value = *p->prach_StartingSubframe_r13; - cfg->emtc_config.prach_ce_level_3_hopping_enable.value = - p->prach_HoppingConfig_r13; - cfg->emtc_config.prach_ce_level_3_hopping_offset.value = - cfg->rf_config.ul_channel_bandwidth.value - 6; - case 3: - p = prach_ParametersListCE_r13->list.array[2]; - cfg->emtc_config.prach_ce_level_2_enable.value = 1; - cfg->emtc_config.prach_ce_level_2_configuration_index.value = - p->prach_ConfigIndex_r13; - cfg->emtc_config.prach_ce_level_2_frequency_offset.value = - p->prach_FreqOffset_r13; - cfg-> - emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt. - value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) - cfg-> - emtc_config.prach_ce_level_2_starting_subframe_periodicity. - value = *p->prach_StartingSubframe_r13; - cfg->emtc_config.prach_ce_level_2_hopping_enable.value = - p->prach_HoppingConfig_r13; - cfg->emtc_config.prach_ce_level_2_hopping_offset.value = - cfg->rf_config.ul_channel_bandwidth.value - 6; - case 2: - p = prach_ParametersListCE_r13->list.array[1]; - cfg->emtc_config.prach_ce_level_1_enable.value = 1; - cfg->emtc_config.prach_ce_level_1_configuration_index.value = - p->prach_ConfigIndex_r13; - cfg->emtc_config.prach_ce_level_1_frequency_offset.value = - p->prach_FreqOffset_r13; - cfg-> - emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt. - value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) - cfg-> - emtc_config.prach_ce_level_1_starting_subframe_periodicity. - value = *p->prach_StartingSubframe_r13; - cfg->emtc_config.prach_ce_level_1_hopping_enable.value = - p->prach_HoppingConfig_r13; - cfg->emtc_config.prach_ce_level_1_hopping_offset.value = - cfg->rf_config.ul_channel_bandwidth.value - 6; - case 1: - p = prach_ParametersListCE_r13->list.array[0]; - cfg->emtc_config.prach_ce_level_0_enable.value = 1; - cfg->emtc_config.prach_ce_level_0_configuration_index.value = - p->prach_ConfigIndex_r13; - cfg->emtc_config.prach_ce_level_0_frequency_offset.value = - p->prach_FreqOffset_r13; - cfg-> - emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt. - value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) - cfg-> - emtc_config.prach_ce_level_0_starting_subframe_periodicity. - value = *p->prach_StartingSubframe_r13; - cfg->emtc_config.prach_ce_level_0_hopping_enable.value = - p->prach_HoppingConfig_r13; - cfg->emtc_config.prach_ce_level_0_hopping_offset.value = - cfg->rf_config.ul_channel_bandwidth.value - 6; - } - - struct FreqHoppingParameters_r13 *ext4_freqHoppingParameters = - radioResourceConfigCommonP->ext4->freqHoppingParameters_r13; - if ((ext4_freqHoppingParameters) - && - (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13)) - { - switch - (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13-> - present) { - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_NOTHING: /* No components present */ - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_FDD_r13: - cfg->emtc_config. - pucch_interval_ulhoppingconfigcommonmodea.value = - ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13-> - choice.interval_FDD_r13; - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_TDD_r13: - cfg->emtc_config. - pucch_interval_ulhoppingconfigcommonmodea.value = - ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13-> - choice.interval_TDD_r13; - break; - } - } - if ((ext4_freqHoppingParameters) && - (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13)) - { - switch - (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> - present) { - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_NOTHING: /* No components present */ - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_FDD_r13: - cfg->emtc_config. - pucch_interval_ulhoppingconfigcommonmodeb.value = - ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> - choice.interval_FDD_r13; - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_TDD_r13: - cfg->emtc_config. - pucch_interval_ulhoppingconfigcommonmodeb.value = - ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> - choice.interval_TDD_r13; - break; - } - } + PRACH_ParametersCE_r13_t *p; + cfg->emtc_config.prach_ce_level_0_enable.value = 0; + cfg->emtc_config.prach_ce_level_1_enable.value = 0; + cfg->emtc_config.prach_ce_level_2_enable.value = 0; + cfg->emtc_config.prach_ce_level_3_enable.value = 0; + switch (prach_ParametersListCE_r13->list.count) { + case 4: + p = prach_ParametersListCE_r13->list.array[3]; + cfg->emtc_config.prach_ce_level_3_enable.value = 1; + cfg->emtc_config.prach_ce_level_3_configuration_index.value = p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_3_frequency_offset.value = p->prach_FreqOffset_r13; + cfg->emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; + if (p->prach_StartingSubframe_r13) + cfg->emtc_config.prach_ce_level_3_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_3_hopping_enable.value = p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_3_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value - 6; + case 3: + p = prach_ParametersListCE_r13->list.array[2]; + cfg->emtc_config.prach_ce_level_2_enable.value = 1; + cfg->emtc_config.prach_ce_level_2_configuration_index.value = p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_2_frequency_offset.value = p->prach_FreqOffset_r13; + cfg->emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; + if (p->prach_StartingSubframe_r13) + cfg->emtc_config.prach_ce_level_2_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_2_hopping_enable.value = p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_2_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value - 6; + case 2: + p = prach_ParametersListCE_r13->list.array[1]; + cfg->emtc_config.prach_ce_level_1_enable.value = 1; + cfg->emtc_config.prach_ce_level_1_configuration_index.value = p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_1_frequency_offset.value = p->prach_FreqOffset_r13; + cfg->emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; + if (p->prach_StartingSubframe_r13) + cfg->emtc_config.prach_ce_level_1_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_1_hopping_enable.value = p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_1_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value - 6; + case 1: + p = prach_ParametersListCE_r13->list.array[0]; + cfg->emtc_config.prach_ce_level_0_enable.value = 1; + cfg->emtc_config.prach_ce_level_0_configuration_index.value = p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_0_frequency_offset.value = p->prach_FreqOffset_r13; + cfg->emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; + if (p->prach_StartingSubframe_r13) + cfg->emtc_config.prach_ce_level_0_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_0_hopping_enable.value = p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_0_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value - 6; } + + struct FreqHoppingParameters_r13 *ext4_freqHoppingParameters = radioResourceConfigCommonP->ext4->freqHoppingParameters_r13; + if ((ext4_freqHoppingParameters)&& + (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13)) + { + switch (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13->present) { + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_NOTHING: /* No components present */ + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_FDD_r13: + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodea.value = + ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13-> + choice.interval_FDD_r13; + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_TDD_r13: + cfg->emtc_config. + pucch_interval_ulhoppingconfigcommonmodea.value = + ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13-> + choice.interval_TDD_r13; + break; + } + } + if ((ext4_freqHoppingParameters) && + (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13)) + { + switch + (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> + present) { + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_NOTHING: /* No components present */ + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_FDD_r13: + cfg->emtc_config. + pucch_interval_ulhoppingconfigcommonmodeb.value = + ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> + choice.interval_FDD_r13; + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_TDD_r13: + cfg->emtc_config. + pucch_interval_ulhoppingconfigcommonmodeb.value = + ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> + choice.interval_TDD_r13; + break; + } + } + } #endif } @@ -597,273 +510,273 @@ rrc_mac_config_req_eNB(module_id_t Mod_idP, SystemInformationBlockType1_v1310_IEs_t * sib1_v13ext #endif - ) + ) { - int i; + int i; - int UE_id = -1; - eNB_MAC_INST *eNB = RC.mac[Mod_idP]; - UE_list_t *UE_list = &eNB->UE_list; + int UE_id = -1; + eNB_MAC_INST *eNB = RC.mac[Mod_idP]; + UE_list_t *UE_list = &eNB->UE_list; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN); - if (mib != NULL) { - if (RC.mac == NULL) - l2_init_eNB(); + if (mib != NULL) { + if (RC.mac == NULL) + l2_init_eNB(); - mac_top_init_eNB(); + mac_top_init_eNB(); - RC.mac[Mod_idP]->common_channels[CC_idP].mib = mib; - RC.mac[Mod_idP]->common_channels[CC_idP].physCellId = physCellId; - RC.mac[Mod_idP]->common_channels[CC_idP].p_eNB = p_eNB; - RC.mac[Mod_idP]->common_channels[CC_idP].Ncp = Ncp; - RC.mac[Mod_idP]->common_channels[CC_idP].eutra_band = eutra_band; - RC.mac[Mod_idP]->common_channels[CC_idP].dl_CarrierFreq = - dl_CarrierFreq; + RC.mac[Mod_idP]->common_channels[CC_idP].mib = mib; + RC.mac[Mod_idP]->common_channels[CC_idP].physCellId = physCellId; + RC.mac[Mod_idP]->common_channels[CC_idP].p_eNB = p_eNB; + RC.mac[Mod_idP]->common_channels[CC_idP].Ncp = Ncp; + RC.mac[Mod_idP]->common_channels[CC_idP].eutra_band = eutra_band; + RC.mac[Mod_idP]->common_channels[CC_idP].dl_CarrierFreq = + dl_CarrierFreq; - LOG_I(MAC, - "Configuring MIB for instance %d, CCid %d : (band %d,N_RB_DL %d,Nid_cell %d,p %d,DL freq %u,phich_config.resource %d, phich_config.duration %d)\n", - Mod_idP, - CC_idP, - eutra_band, - to_prb((int) mib->message.dl_Bandwidth), - physCellId, - p_eNB, - dl_CarrierFreq, - (int) mib->message.phich_Config.phich_Resource, - (int) mib->message.phich_Config.phich_Duration); + LOG_I(MAC, + "Configuring MIB for instance %d, CCid %d : (band %d,N_RB_DL %d,Nid_cell %d,p %d,DL freq %u,phich_config.resource %d, phich_config.duration %d)\n", + Mod_idP, + CC_idP, + eutra_band, + to_prb((int) mib->message.dl_Bandwidth), + physCellId, + p_eNB, + dl_CarrierFreq, + (int) mib->message.phich_Config.phich_Resource, + (int) mib->message.phich_Config.phich_Duration); - config_mib(Mod_idP, CC_idP, - eutra_band, - mib->message.dl_Bandwidth, - &mib->message.phich_Config, - physCellId, Ncp, p_eNB, dl_CarrierFreq, ul_CarrierFreq + config_mib(Mod_idP, CC_idP, + eutra_band, + mib->message.dl_Bandwidth, + &mib->message.phich_Config, + physCellId, Ncp, p_eNB, dl_CarrierFreq, ul_CarrierFreq #ifdef Rel14 - , pbch_repetition + , pbch_repetition #endif - ); + ); - mac_init_cell_params(Mod_idP, CC_idP); - } - if (schedulingInfoList != NULL) { - RC.mac[Mod_idP]->common_channels[CC_idP].tdd_Config = tdd_Config; - RC.mac[Mod_idP]->common_channels[CC_idP].schedulingInfoList = - schedulingInfoList; - config_sib1(Mod_idP, CC_idP, tdd_Config); - } + mac_init_cell_params(Mod_idP, CC_idP); + } + if (schedulingInfoList != NULL) { + RC.mac[Mod_idP]->common_channels[CC_idP].tdd_Config = tdd_Config; + RC.mac[Mod_idP]->common_channels[CC_idP].schedulingInfoList = + schedulingInfoList; + config_sib1(Mod_idP, CC_idP, tdd_Config); + } #ifdef Rel14 - if (sib1_v13ext != NULL) { - RC.mac[Mod_idP]->common_channels[CC_idP].sib1_v13ext = sib1_v13ext; - } + if (sib1_v13ext != NULL) { + RC.mac[Mod_idP]->common_channels[CC_idP].sib1_v13ext = sib1_v13ext; + } #endif - if (radioResourceConfigCommon != NULL) { - LOG_I(MAC, "[CONFIG]SIB2/3 Contents (partial)\n"); - LOG_I(MAC, "[CONFIG]pusch_config_common.n_SB = %ld\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.pusch_ConfigBasic.n_SB); - LOG_I(MAC, "[CONFIG]pusch_config_common.hoppingMode = %ld\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode); - LOG_I(MAC, - "[CONFIG]pusch_config_common.pusch_HoppingOffset = %ld\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset); - LOG_I(MAC, "[CONFIG]pusch_config_common.enable64QAM = %d\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.pusch_ConfigBasic.enable64QAM); - LOG_I(MAC, - "[CONFIG]pusch_config_common.groupHoppingEnabled = %d\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. - groupHoppingEnabled); - LOG_I(MAC, - "[CONFIG]pusch_config_common.groupAssignmentPUSCH = %ld\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. - groupAssignmentPUSCH); - LOG_I(MAC, - "[CONFIG]pusch_config_common.sequenceHoppingEnabled = %d\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. - sequenceHoppingEnabled); - LOG_I(MAC, "[CONFIG]pusch_config_common.cyclicShift = %ld\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift); + if (radioResourceConfigCommon != NULL) { + LOG_I(MAC, "[CONFIG]SIB2/3 Contents (partial)\n"); + LOG_I(MAC, "[CONFIG]pusch_config_common.n_SB = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.pusch_ConfigBasic.n_SB); + LOG_I(MAC, "[CONFIG]pusch_config_common.hoppingMode = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode); + LOG_I(MAC, + "[CONFIG]pusch_config_common.pusch_HoppingOffset = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset); + LOG_I(MAC, "[CONFIG]pusch_config_common.enable64QAM = %d\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.pusch_ConfigBasic.enable64QAM); + LOG_I(MAC, + "[CONFIG]pusch_config_common.groupHoppingEnabled = %d\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. + groupHoppingEnabled); + LOG_I(MAC, + "[CONFIG]pusch_config_common.groupAssignmentPUSCH = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. + groupAssignmentPUSCH); + LOG_I(MAC, + "[CONFIG]pusch_config_common.sequenceHoppingEnabled = %d\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. + sequenceHoppingEnabled); + LOG_I(MAC, "[CONFIG]pusch_config_common.cyclicShift = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift); - AssertFatal(radioResourceConfigCommon-> - rach_ConfigCommon.maxHARQ_Msg3Tx > 0, - "radioResourceconfigCommon %d == 0\n", - (int) radioResourceConfigCommon-> - rach_ConfigCommon.maxHARQ_Msg3Tx); + AssertFatal(radioResourceConfigCommon-> + rach_ConfigCommon.maxHARQ_Msg3Tx > 0, + "radioResourceconfigCommon %d == 0\n", + (int) radioResourceConfigCommon-> + rach_ConfigCommon.maxHARQ_Msg3Tx); - RC.mac[Mod_idP]->common_channels[CC_idP]. - radioResourceConfigCommon = radioResourceConfigCommon; - if (ul_CarrierFreq > 0) - RC.mac[Mod_idP]->common_channels[CC_idP].ul_CarrierFreq = - ul_CarrierFreq; - if (ul_Bandwidth) - RC.mac[Mod_idP]->common_channels[CC_idP].ul_Bandwidth = - *ul_Bandwidth; - else - RC.mac[Mod_idP]->common_channels[CC_idP].ul_Bandwidth = - RC.mac[Mod_idP]->common_channels[CC_idP].mib->message. - dl_Bandwidth; + RC.mac[Mod_idP]->common_channels[CC_idP]. + radioResourceConfigCommon = radioResourceConfigCommon; + if (ul_CarrierFreq > 0) + RC.mac[Mod_idP]->common_channels[CC_idP].ul_CarrierFreq = + ul_CarrierFreq; + if (ul_Bandwidth) + RC.mac[Mod_idP]->common_channels[CC_idP].ul_Bandwidth = + *ul_Bandwidth; + else + RC.mac[Mod_idP]->common_channels[CC_idP].ul_Bandwidth = + RC.mac[Mod_idP]->common_channels[CC_idP].mib->message. + dl_Bandwidth; - config_sib2(Mod_idP, CC_idP, radioResourceConfigCommon, + config_sib2(Mod_idP, CC_idP, radioResourceConfigCommon, #ifdef Rel14 - radioResourceConfigCommon_BR, + radioResourceConfigCommon_BR, #endif - NULL, ul_Bandwidth, additionalSpectrumEmission, - mbsfn_SubframeConfigList); + NULL, ul_Bandwidth, additionalSpectrumEmission, + mbsfn_SubframeConfigList); + } + // SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup + if (logicalChannelConfig != NULL) { // check for eMTC specific things + UE_id = find_UE_id(Mod_idP, rntiP); + + if (UE_id == -1) { + LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, + __LINE__, __FUNCTION__); + } else { + if (logicalChannelConfig) + UE_list-> + UE_template[CC_idP][UE_id].lcgidmap + [logicalChannelIdentity] = + *logicalChannelConfig-> + ul_SpecificParameters->logicalChannelGroup; + else + UE_list-> + UE_template[CC_idP][UE_id].lcgidmap + [logicalChannelIdentity] = 0; } - // SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup - if (logicalChannelConfig != NULL) { // check for eMTC specific things - UE_id = find_UE_id(Mod_idP, rntiP); - - if (UE_id == -1) { - LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, - __LINE__, __FUNCTION__); - } else { - if (logicalChannelConfig) - UE_list-> - UE_template[CC_idP][UE_id].lcgidmap - [logicalChannelIdentity] = - *logicalChannelConfig-> - ul_SpecificParameters->logicalChannelGroup; - else - UE_list-> - UE_template[CC_idP][UE_id].lcgidmap - [logicalChannelIdentity] = 0; - } - } + } - if (physicalConfigDedicated != NULL) { - UE_id = find_UE_id(Mod_idP, rntiP); + if (physicalConfigDedicated != NULL) { + UE_id = find_UE_id(Mod_idP, rntiP); - if (UE_id == -1) - LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, - __LINE__, __FUNCTION__); - else - UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated = - physicalConfigDedicated; - } + if (UE_id == -1) + LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, + __LINE__, __FUNCTION__); + else + UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated = + physicalConfigDedicated; + } #if defined(Rel10) || defined(Rel14) - if (sCellToAddMod_r10 != NULL) { - UE_id = find_UE_id(Mod_idP, rntiP); - if (UE_id == -1) - LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, - __LINE__, __FUNCTION__); - else - config_dedicated_scell(Mod_idP, rntiP, sCellToAddMod_r10); + if (sCellToAddMod_r10 != NULL) { + UE_id = find_UE_id(Mod_idP, rntiP); + if (UE_id == -1) + LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, + __LINE__, __FUNCTION__); + else + config_dedicated_scell(Mod_idP, rntiP, sCellToAddMod_r10); - } + } #endif - if (mbsfn_SubframeConfigList != NULL) { - LOG_I(MAC, - "[eNB %d][CONFIG] Received %d subframe allocation pattern for MBSFN\n", - Mod_idP, mbsfn_SubframeConfigList->list.count); - RC.mac[Mod_idP]->common_channels[0].num_sf_allocation_pattern = - mbsfn_SubframeConfigList->list.count; + if (mbsfn_SubframeConfigList != NULL) { + LOG_I(MAC, + "[eNB %d][CONFIG] Received %d subframe allocation pattern for MBSFN\n", + Mod_idP, mbsfn_SubframeConfigList->list.count); + RC.mac[Mod_idP]->common_channels[0].num_sf_allocation_pattern = + mbsfn_SubframeConfigList->list.count; - for (i = 0; i < mbsfn_SubframeConfigList->list.count; i++) { - RC.mac[Mod_idP]->common_channels[0].mbsfn_SubframeConfig[i] = - mbsfn_SubframeConfigList->list.array[i]; - LOG_I(MAC, - "[eNB %d][CONFIG] MBSFN_SubframeConfig[%d] pattern is %x\n", - Mod_idP, i, - RC.mac[Mod_idP]-> - common_channels[0].mbsfn_SubframeConfig[i]-> - subframeAllocation.choice.oneFrame.buf[0]); - } + for (i = 0; i < mbsfn_SubframeConfigList->list.count; i++) { + RC.mac[Mod_idP]->common_channels[0].mbsfn_SubframeConfig[i] = + mbsfn_SubframeConfigList->list.array[i]; + LOG_I(MAC, + "[eNB %d][CONFIG] MBSFN_SubframeConfig[%d] pattern is %x\n", + Mod_idP, i, + RC.mac[Mod_idP]-> + common_channels[0].mbsfn_SubframeConfig[i]-> + subframeAllocation.choice.oneFrame.buf[0]); + } #ifdef Rel10 - RC.mac[Mod_idP]->common_channels[0].MBMS_flag = MBMS_Flag; + RC.mac[Mod_idP]->common_channels[0].MBMS_flag = MBMS_Flag; #endif - } + } #if defined(Rel10) || defined(Rel14) - if (mbsfn_AreaInfoList != NULL) { - // One eNB could be part of multiple mbsfn syc area, this could change over time so reset each time - LOG_I(MAC, "[eNB %d][CONFIG] Received %d MBSFN Area Info\n", - Mod_idP, mbsfn_AreaInfoList->list.count); - RC.mac[Mod_idP]->common_channels[0].num_active_mbsfn_area = - mbsfn_AreaInfoList->list.count; + if (mbsfn_AreaInfoList != NULL) { + // One eNB could be part of multiple mbsfn syc area, this could change over time so reset each time + LOG_I(MAC, "[eNB %d][CONFIG] Received %d MBSFN Area Info\n", + Mod_idP, mbsfn_AreaInfoList->list.count); + RC.mac[Mod_idP]->common_channels[0].num_active_mbsfn_area = + mbsfn_AreaInfoList->list.count; - for (i = 0; i < mbsfn_AreaInfoList->list.count; i++) { - RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i] = - mbsfn_AreaInfoList->list.array[i]; - LOG_I(MAC, - "[eNB %d][CONFIG] MBSFN_AreaInfo[%d]: MCCH Repetition Period = %ld\n", - Mod_idP, i, - RC.mac[Mod_idP]->common_channels[0]. - mbsfn_AreaInfo[i]->mcch_Config_r9. - mcch_RepetitionPeriod_r9); - // config_sib13(Mod_idP,0,i,RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i]->mbsfn_AreaId_r9); - } + for (i = 0; i < mbsfn_AreaInfoList->list.count; i++) { + RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i] = + mbsfn_AreaInfoList->list.array[i]; + LOG_I(MAC, + "[eNB %d][CONFIG] MBSFN_AreaInfo[%d]: MCCH Repetition Period = %ld\n", + Mod_idP, i, + RC.mac[Mod_idP]->common_channels[0]. + mbsfn_AreaInfo[i]->mcch_Config_r9. + mcch_RepetitionPeriod_r9); + // config_sib13(Mod_idP,0,i,RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i]->mbsfn_AreaId_r9); } + } - if (pmch_InfoList != NULL) { + if (pmch_InfoList != NULL) { - // LOG_I(MAC,"DUY: lcid when entering rrc_mac config_req is %02d\n",(pmch_InfoList->list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9)); + // LOG_I(MAC,"DUY: lcid when entering rrc_mac config_req is %02d\n",(pmch_InfoList->list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9)); - LOG_I(MAC, "[CONFIG] Number of PMCH in this MBSFN Area %d\n", - pmch_InfoList->list.count); + LOG_I(MAC, "[CONFIG] Number of PMCH in this MBSFN Area %d\n", + pmch_InfoList->list.count); - for (i = 0; i < pmch_InfoList->list.count; i++) { - RC.mac[Mod_idP]->common_channels[0].pmch_Config[i] = - &pmch_InfoList->list.array[i]->pmch_Config_r9; + for (i = 0; i < pmch_InfoList->list.count; i++) { + RC.mac[Mod_idP]->common_channels[0].pmch_Config[i] = + &pmch_InfoList->list.array[i]->pmch_Config_r9; - LOG_I(MAC, - "[CONFIG] PMCH[%d]: This PMCH stop (sf_AllocEnd_r9) at subframe %ldth\n", - i, - RC.mac[Mod_idP]->common_channels[0]. - pmch_Config[i]->sf_AllocEnd_r9); - LOG_I(MAC, "[CONFIG] PMCH[%d]: mch_Scheduling_Period = %ld\n", - i, - RC.mac[Mod_idP]->common_channels[0]. - pmch_Config[i]->mch_SchedulingPeriod_r9); - LOG_I(MAC, "[CONFIG] PMCH[%d]: dataMCS = %ld\n", i, - RC.mac[Mod_idP]->common_channels[0]. - pmch_Config[i]->dataMCS_r9); + LOG_I(MAC, + "[CONFIG] PMCH[%d]: This PMCH stop (sf_AllocEnd_r9) at subframe %ldth\n", + i, + RC.mac[Mod_idP]->common_channels[0]. + pmch_Config[i]->sf_AllocEnd_r9); + LOG_I(MAC, "[CONFIG] PMCH[%d]: mch_Scheduling_Period = %ld\n", + i, + RC.mac[Mod_idP]->common_channels[0]. + pmch_Config[i]->mch_SchedulingPeriod_r9); + LOG_I(MAC, "[CONFIG] PMCH[%d]: dataMCS = %ld\n", i, + RC.mac[Mod_idP]->common_channels[0]. + pmch_Config[i]->dataMCS_r9); - // MBMS session info list in each MCH - RC.mac[Mod_idP]->common_channels[0].mbms_SessionList[i] = - &pmch_InfoList->list.array[i]->mbms_SessionInfoList_r9; - LOG_I(MAC, "PMCH[%d] Number of session (MTCH) is: %d\n", i, - RC.mac[Mod_idP]->common_channels[0]. - mbms_SessionList[i]->list.count); - } + // MBMS session info list in each MCH + RC.mac[Mod_idP]->common_channels[0].mbms_SessionList[i] = + &pmch_InfoList->list.array[i]->mbms_SessionInfoList_r9; + LOG_I(MAC, "PMCH[%d] Number of session (MTCH) is: %d\n", i, + RC.mac[Mod_idP]->common_channels[0]. + mbms_SessionList[i]->list.count); } + } #endif - if (radioResourceConfigCommon != NULL) { - AssertFatal(RC.mac[Mod_idP]->if_inst->PHY_config_req != NULL, - "if_inst->phy_config_request is null\n"); - PHY_Config_t phycfg; - phycfg.Mod_id = Mod_idP; - phycfg.CC_id = CC_idP; - phycfg.cfg = &RC.mac[Mod_idP]->config[CC_idP]; + if (radioResourceConfigCommon != NULL) { + AssertFatal(RC.mac[Mod_idP]->if_inst->PHY_config_req != NULL, + "if_inst->phy_config_request is null\n"); + PHY_Config_t phycfg; + phycfg.Mod_id = Mod_idP; + phycfg.CC_id = CC_idP; + phycfg.cfg = &RC.mac[Mod_idP]->config[CC_idP]; - if (RC.mac[Mod_idP]->if_inst->PHY_config_req) - RC.mac[Mod_idP]->if_inst->PHY_config_req(&phycfg); - } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); + if (RC.mac[Mod_idP]->if_inst->PHY_config_req) + RC.mac[Mod_idP]->if_inst->PHY_config_req(&phycfg); + } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); - return (0); + return (0); } int @@ -901,450 +814,450 @@ rrc_mac_config_req_ue(module_id_t Mod_idP, #ifdef CBA , uint8_t num_active_cba_groups, uint16_t cba_rnti #endif - ) + ) { - int i; + int i; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN); - LOG_I(MAC, "[CONFIG][UE %d] Configuring MAC/PHY from eNB %d\n", + LOG_I(MAC, "[CONFIG][UE %d] Configuring MAC/PHY from eNB %d\n", + Mod_idP, eNB_index); + + if (tdd_Config != NULL) { + UE_mac_inst[Mod_idP].tdd_Config = tdd_Config; + } + + + if (tdd_Config && SIwindowsize && SIperiod) { + phy_config_sib1_ue(Mod_idP, 0, eNB_index, tdd_Config, + *SIwindowsize, *SIperiod); + } + + if (radioResourceConfigCommon != NULL) { + UE_mac_inst[Mod_idP].radioResourceConfigCommon = + radioResourceConfigCommon; + phy_config_sib2_ue(Mod_idP, 0, eNB_index, + radioResourceConfigCommon, ul_CarrierFreq, + ul_Bandwidth, additionalSpectrumEmission, + mbsfn_SubframeConfigList); + } + // SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup + if (logicalChannelConfig != NULL) { + LOG_I(MAC, + "[CONFIG][UE %d] Applying RRC logicalChannelConfig from eNB%d\n", Mod_idP, eNB_index); + UE_mac_inst[Mod_idP].logicalChannelConfig[logicalChannelIdentity] = + logicalChannelConfig; + UE_mac_inst[Mod_idP].scheduling_info.Bj[logicalChannelIdentity] = 0; // initilize the bucket for this lcid - if (tdd_Config != NULL) { - UE_mac_inst[Mod_idP].tdd_Config = tdd_Config; + AssertFatal(logicalChannelConfig->ul_SpecificParameters != NULL, + "[UE %d] LCID %ld NULL ul_SpecificParameters\n", + Mod_idP, logicalChannelIdentity); + UE_mac_inst[Mod_idP].scheduling_info.bucket_size[logicalChannelIdentity] = logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate * logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration; // set the max bucket size + if (logicalChannelConfig->ul_SpecificParameters-> + logicalChannelGroup != NULL) { + UE_mac_inst[Mod_idP].scheduling_info. + LCGID[logicalChannelIdentity] = + *logicalChannelConfig->ul_SpecificParameters-> + logicalChannelGroup; + LOG_D(MAC, + "[CONFIG][UE %d] LCID %ld is attached to the LCGID %ld\n", + Mod_idP, logicalChannelIdentity, + *logicalChannelConfig-> + ul_SpecificParameters->logicalChannelGroup); + } else { + UE_mac_inst[Mod_idP].scheduling_info. + LCGID[logicalChannelIdentity] = MAX_NUM_LCGID; } + UE_mac_inst[Mod_idP]. + scheduling_info.LCID_buffer_remain[logicalChannelIdentity] = 0; + } + if (mac_MainConfig != NULL) { + LOG_I(MAC, + "[CONFIG][UE%d] Applying RRC macMainConfig from eNB%d\n", + Mod_idP, eNB_index); + UE_mac_inst[Mod_idP].macConfig = mac_MainConfig; + UE_mac_inst[Mod_idP].measGapConfig = measGapConfig; - if (tdd_Config && SIwindowsize && SIperiod) { - phy_config_sib1_ue(Mod_idP, 0, eNB_index, tdd_Config, - *SIwindowsize, *SIperiod); - } + if (mac_MainConfig->ul_SCH_Config) { - if (radioResourceConfigCommon != NULL) { - UE_mac_inst[Mod_idP].radioResourceConfigCommon = - radioResourceConfigCommon; - phy_config_sib2_ue(Mod_idP, 0, eNB_index, - radioResourceConfigCommon, ul_CarrierFreq, - ul_Bandwidth, additionalSpectrumEmission, - mbsfn_SubframeConfigList); - } - // SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup - if (logicalChannelConfig != NULL) { - LOG_I(MAC, - "[CONFIG][UE %d] Applying RRC logicalChannelConfig from eNB%d\n", - Mod_idP, eNB_index); - UE_mac_inst[Mod_idP].logicalChannelConfig[logicalChannelIdentity] = - logicalChannelConfig; - UE_mac_inst[Mod_idP].scheduling_info.Bj[logicalChannelIdentity] = 0; // initilize the bucket for this lcid - - AssertFatal(logicalChannelConfig->ul_SpecificParameters != NULL, - "[UE %d] LCID %ld NULL ul_SpecificParameters\n", - Mod_idP, logicalChannelIdentity); - UE_mac_inst[Mod_idP].scheduling_info.bucket_size[logicalChannelIdentity] = logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate * logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration; // set the max bucket size - if (logicalChannelConfig->ul_SpecificParameters-> - logicalChannelGroup != NULL) { - UE_mac_inst[Mod_idP].scheduling_info. - LCGID[logicalChannelIdentity] = - *logicalChannelConfig->ul_SpecificParameters-> - logicalChannelGroup; - LOG_D(MAC, - "[CONFIG][UE %d] LCID %ld is attached to the LCGID %ld\n", - Mod_idP, logicalChannelIdentity, - *logicalChannelConfig-> - ul_SpecificParameters->logicalChannelGroup); - } else { - UE_mac_inst[Mod_idP].scheduling_info. - LCGID[logicalChannelIdentity] = MAX_NUM_LCGID; - } - UE_mac_inst[Mod_idP]. - scheduling_info.LCID_buffer_remain[logicalChannelIdentity] = 0; - } - - if (mac_MainConfig != NULL) { - LOG_I(MAC, - "[CONFIG][UE%d] Applying RRC macMainConfig from eNB%d\n", - Mod_idP, eNB_index); - UE_mac_inst[Mod_idP].macConfig = mac_MainConfig; - UE_mac_inst[Mod_idP].measGapConfig = measGapConfig; - - if (mac_MainConfig->ul_SCH_Config) { - - if (mac_MainConfig->ul_SCH_Config->periodicBSR_Timer) { - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer = - (uint16_t) * - mac_MainConfig->ul_SCH_Config->periodicBSR_Timer; - } else { - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer = + if (mac_MainConfig->ul_SCH_Config->periodicBSR_Timer) { + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer = + (uint16_t) * + mac_MainConfig->ul_SCH_Config->periodicBSR_Timer; + } else { + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer = #ifndef Rel14 - (uint16_t) - MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity + (uint16_t) + MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity #else - (uint16_t) PeriodicBSR_Timer_r12_infinity; + (uint16_t) PeriodicBSR_Timer_r12_infinity; #endif - ; - } + ; + } - if (mac_MainConfig->ul_SCH_Config->maxHARQ_Tx) { - UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx = - (uint16_t) * mac_MainConfig->ul_SCH_Config->maxHARQ_Tx; - } else { - UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx = - (uint16_t) - MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; - } - phy_config_harq_ue(Mod_idP, 0, eNB_index, - UE_mac_inst[Mod_idP]. - scheduling_info.maxHARQ_Tx); + if (mac_MainConfig->ul_SCH_Config->maxHARQ_Tx) { + UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx = + (uint16_t) * mac_MainConfig->ul_SCH_Config->maxHARQ_Tx; + } else { + UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx = + (uint16_t) + MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; + } + phy_config_harq_ue(Mod_idP, 0, eNB_index, + UE_mac_inst[Mod_idP]. + scheduling_info.maxHARQ_Tx); - if (mac_MainConfig->ul_SCH_Config->retxBSR_Timer) { - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = - (uint16_t) mac_MainConfig->ul_SCH_Config-> - retxBSR_Timer; - } else { + if (mac_MainConfig->ul_SCH_Config->retxBSR_Timer) { + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = + (uint16_t) mac_MainConfig->ul_SCH_Config-> + retxBSR_Timer; + } else { #ifndef Rel14 - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = - (uint16_t) - MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf2560; + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = + (uint16_t) + MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf2560; #else - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = - (uint16_t) RetxBSR_Timer_r12_sf2560; + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = + (uint16_t) RetxBSR_Timer_r12_sf2560; #endif - } - } -#if defined(Rel10) || defined(Rel14) - - if (mac_MainConfig->ext1 - && mac_MainConfig->ext1->sr_ProhibitTimer_r9) { - UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = - (uint16_t) * mac_MainConfig->ext1->sr_ProhibitTimer_r9; - } else { - UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = 0; - } - - if (mac_MainConfig->ext2 - && mac_MainConfig->ext2->mac_MainConfig_v1020) { - if (mac_MainConfig->ext2-> - mac_MainConfig_v1020->extendedBSR_Sizes_r10) { - UE_mac_inst[Mod_idP].scheduling_info. - extendedBSR_Sizes_r10 = - (uint16_t) * - mac_MainConfig->ext2-> - mac_MainConfig_v1020->extendedBSR_Sizes_r10; - } else { - UE_mac_inst[Mod_idP].scheduling_info. - extendedBSR_Sizes_r10 = (uint16_t) 0; - } - if (mac_MainConfig->ext2->mac_MainConfig_v1020-> - extendedPHR_r10) { - UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = - (uint16_t) * - mac_MainConfig->ext2->mac_MainConfig_v1020-> - extendedPHR_r10; - } else { - UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = - (uint16_t) 0; - } - } else { - UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = - (uint16_t) 0; - UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = - (uint16_t) 0; - } -#endif - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = - MAC_UE_BSR_TIMER_NOT_RUNNING; - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = - MAC_UE_BSR_TIMER_NOT_RUNNING; - - UE_mac_inst[Mod_idP].BSR_reporting_active = BSR_TRIGGER_NONE; - - LOG_D(MAC, "[UE %d]: periodic BSR %d (SF), retx BSR %d (SF)\n", - Mod_idP, - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF, - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF); - - UE_mac_inst[Mod_idP].scheduling_info.drx_config = - mac_MainConfig->drx_Config; - UE_mac_inst[Mod_idP].scheduling_info.phr_config = - mac_MainConfig->phr_Config; - - if (mac_MainConfig->phr_Config) { - UE_mac_inst[Mod_idP].PHR_state = - mac_MainConfig->phr_Config->present; - UE_mac_inst[Mod_idP].PHR_reconfigured = 1; - UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer = - mac_MainConfig->phr_Config->choice.setup.periodicPHR_Timer; - UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer = - mac_MainConfig->phr_Config->choice.setup.prohibitPHR_Timer; - UE_mac_inst[Mod_idP].scheduling_info.PathlossChange = - mac_MainConfig->phr_Config->choice.setup.dl_PathlossChange; - } else { - UE_mac_inst[Mod_idP].PHR_reconfigured = 0; - UE_mac_inst[Mod_idP].PHR_state = - MAC_MainConfig__phr_Config_PR_setup; - UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer = - MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20; - UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer = - MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20; - UE_mac_inst[Mod_idP].scheduling_info.PathlossChange = - MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1; - } - - UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF = - get_sf_perioidicPHR_Timer(UE_mac_inst[Mod_idP]. - scheduling_info.periodicPHR_Timer); - UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF = - get_sf_prohibitPHR_Timer(UE_mac_inst[Mod_idP]. - scheduling_info.prohibitPHR_Timer); - UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db = - get_db_dl_PathlossChange(UE_mac_inst[Mod_idP]. - scheduling_info.PathlossChange); - UE_mac_inst[Mod_idP].PHR_reporting_active = 0; - LOG_D(MAC, - "[UE %d] config PHR (%d): periodic %d (SF) prohibit %d (SF) pathlosschange %d (db) \n", - Mod_idP, - (mac_MainConfig->phr_Config) ? mac_MainConfig-> - phr_Config->present : -1, - UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF, - UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF, - UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db); - } - - - if (physicalConfigDedicated != NULL) { - phy_config_dedicated_ue(Mod_idP, 0, eNB_index, - physicalConfigDedicated); - UE_mac_inst[Mod_idP].physicalConfigDedicated = physicalConfigDedicated; // for SR proc + } } #if defined(Rel10) || defined(Rel14) - if (sCellToAddMod_r10 != NULL) { + if (mac_MainConfig->ext1 + && mac_MainConfig->ext1->sr_ProhibitTimer_r9) { + UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = + (uint16_t) * mac_MainConfig->ext1->sr_ProhibitTimer_r9; + } else { + UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = 0; + } - - phy_config_dedicated_scell_ue(Mod_idP, eNB_index, - sCellToAddMod_r10, 1); - UE_mac_inst[Mod_idP].physicalConfigDedicatedSCell_r10 = sCellToAddMod_r10->radioResourceConfigDedicatedSCell_r10->physicalConfigDedicatedSCell_r10; // using SCell index 0 + if (mac_MainConfig->ext2 + && mac_MainConfig->ext2->mac_MainConfig_v1020) { + if (mac_MainConfig->ext2-> + mac_MainConfig_v1020->extendedBSR_Sizes_r10) { + UE_mac_inst[Mod_idP].scheduling_info. + extendedBSR_Sizes_r10 = + (uint16_t) * + mac_MainConfig->ext2-> + mac_MainConfig_v1020->extendedBSR_Sizes_r10; + } else { + UE_mac_inst[Mod_idP].scheduling_info. + extendedBSR_Sizes_r10 = (uint16_t) 0; + } + if (mac_MainConfig->ext2->mac_MainConfig_v1020-> + extendedPHR_r10) { + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = + (uint16_t) * + mac_MainConfig->ext2->mac_MainConfig_v1020-> + extendedPHR_r10; + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = + (uint16_t) 0; + } + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = + (uint16_t) 0; + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = + (uint16_t) 0; } #endif + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = + MAC_UE_BSR_TIMER_NOT_RUNNING; + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = + MAC_UE_BSR_TIMER_NOT_RUNNING; - if (measObj != NULL) { - if (measObj[0] != NULL) { - UE_mac_inst[Mod_idP].n_adj_cells = - measObj[0]->measObject.choice. - measObjectEUTRA.cellsToAddModList->list.count; - LOG_I(MAC, "Number of adjacent cells %d\n", - UE_mac_inst[Mod_idP].n_adj_cells); + UE_mac_inst[Mod_idP].BSR_reporting_active = BSR_TRIGGER_NONE; - for (i = 0; i < UE_mac_inst[Mod_idP].n_adj_cells; i++) { - UE_mac_inst[Mod_idP].adj_cell_id[i] = - measObj[0]->measObject.choice. - measObjectEUTRA.cellsToAddModList->list.array[i]-> - physCellId; - LOG_I(MAC, "Cell %d : Nid_cell %d\n", i, - UE_mac_inst[Mod_idP].adj_cell_id[i]); - } + LOG_D(MAC, "[UE %d]: periodic BSR %d (SF), retx BSR %d (SF)\n", + Mod_idP, + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF, + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF); - phy_config_meas_ue(Mod_idP, 0, eNB_index, - UE_mac_inst[Mod_idP].n_adj_cells, - UE_mac_inst[Mod_idP].adj_cell_id); - } + UE_mac_inst[Mod_idP].scheduling_info.drx_config = + mac_MainConfig->drx_Config; + UE_mac_inst[Mod_idP].scheduling_info.phr_config = + mac_MainConfig->phr_Config; + + if (mac_MainConfig->phr_Config) { + UE_mac_inst[Mod_idP].PHR_state = + mac_MainConfig->phr_Config->present; + UE_mac_inst[Mod_idP].PHR_reconfigured = 1; + UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer = + mac_MainConfig->phr_Config->choice.setup.periodicPHR_Timer; + UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer = + mac_MainConfig->phr_Config->choice.setup.prohibitPHR_Timer; + UE_mac_inst[Mod_idP].scheduling_info.PathlossChange = + mac_MainConfig->phr_Config->choice.setup.dl_PathlossChange; + } else { + UE_mac_inst[Mod_idP].PHR_reconfigured = 0; + UE_mac_inst[Mod_idP].PHR_state = + MAC_MainConfig__phr_Config_PR_setup; + UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer = + MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20; + UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer = + MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20; + UE_mac_inst[Mod_idP].scheduling_info.PathlossChange = + MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1; } - - if (mobilityControlInfo != NULL) { - - LOG_D(MAC, "[UE%d] MAC Reset procedure triggered by RRC eNB %d \n", - Mod_idP, eNB_index); - ue_mac_reset(Mod_idP, eNB_index); - - if (mobilityControlInfo->radioResourceConfigCommon. - rach_ConfigCommon) { - memcpy((void *) - &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> - rach_ConfigCommon, - (void *) mobilityControlInfo-> - radioResourceConfigCommon.rach_ConfigCommon, - sizeof(RACH_ConfigCommon_t)); - } - - memcpy((void *) &UE_mac_inst[Mod_idP]. - radioResourceConfigCommon->prach_Config.prach_ConfigInfo, - (void *) mobilityControlInfo-> - radioResourceConfigCommon.prach_Config.prach_ConfigInfo, - sizeof(PRACH_ConfigInfo_t)); - UE_mac_inst[Mod_idP].radioResourceConfigCommon-> - prach_Config.rootSequenceIndex = - mobilityControlInfo->radioResourceConfigCommon. - prach_Config.rootSequenceIndex; - - if (mobilityControlInfo->radioResourceConfigCommon. - pdsch_ConfigCommon) { - memcpy((void *) - &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> - pdsch_ConfigCommon, - (void *) mobilityControlInfo-> - radioResourceConfigCommon.pdsch_ConfigCommon, - sizeof(PDSCH_ConfigCommon_t)); - } - // not a pointer: mobilityControlInfo->radioResourceConfigCommon.pusch_ConfigCommon - memcpy((void *) &UE_mac_inst[Mod_idP]. - radioResourceConfigCommon->pusch_ConfigCommon, - (void *) &mobilityControlInfo-> - radioResourceConfigCommon.pusch_ConfigCommon, - sizeof(PUSCH_ConfigCommon_t)); - - if (mobilityControlInfo->radioResourceConfigCommon.phich_Config) { - /* memcpy((void *)&UE_mac_inst[Mod_idP].radioResourceConfigCommon->phich_Config, - (void *)mobilityControlInfo->radioResourceConfigCommon.phich_Config, - sizeof(PHICH_Config_t)); */ - } - - if (mobilityControlInfo->radioResourceConfigCommon. - pucch_ConfigCommon) { - memcpy((void *) - &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> - pucch_ConfigCommon, - (void *) mobilityControlInfo-> - radioResourceConfigCommon.pucch_ConfigCommon, - sizeof(PUCCH_ConfigCommon_t)); - } - - if (mobilityControlInfo-> - radioResourceConfigCommon.soundingRS_UL_ConfigCommon) { - memcpy((void *) - &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> - soundingRS_UL_ConfigCommon, - (void *) mobilityControlInfo-> - radioResourceConfigCommon.soundingRS_UL_ConfigCommon, - sizeof(SoundingRS_UL_ConfigCommon_t)); - } - - if (mobilityControlInfo-> - radioResourceConfigCommon.uplinkPowerControlCommon) { - memcpy((void *) - &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> - uplinkPowerControlCommon, - (void *) mobilityControlInfo-> - radioResourceConfigCommon.uplinkPowerControlCommon, - sizeof(UplinkPowerControlCommon_t)); - } - //configure antennaInfoCommon somewhere here.. - if (mobilityControlInfo->radioResourceConfigCommon.p_Max) { - //to be configured - } - - if (mobilityControlInfo->radioResourceConfigCommon.tdd_Config) { - UE_mac_inst[Mod_idP].tdd_Config = - mobilityControlInfo->radioResourceConfigCommon.tdd_Config; - } - - if (mobilityControlInfo-> - radioResourceConfigCommon.ul_CyclicPrefixLength) { - memcpy((void *) - &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> - ul_CyclicPrefixLength, - (void *) mobilityControlInfo-> - radioResourceConfigCommon.ul_CyclicPrefixLength, - sizeof(UL_CyclicPrefixLength_t)); - } - // store the previous rnti in case of failure, and set thenew rnti - UE_mac_inst[Mod_idP].crnti_before_ho = UE_mac_inst[Mod_idP].crnti; - UE_mac_inst[Mod_idP].crnti = - ((mobilityControlInfo-> - newUE_Identity.buf[0]) | (mobilityControlInfo-> - newUE_Identity.buf[1] << 8)); - LOG_I(MAC, "[UE %d] Received new identity %x from %d\n", Mod_idP, - UE_mac_inst[Mod_idP].crnti, eNB_index); - UE_mac_inst[Mod_idP].rach_ConfigDedicated = - malloc(sizeof(*mobilityControlInfo->rach_ConfigDedicated)); - - if (mobilityControlInfo->rach_ConfigDedicated) { - memcpy((void *) UE_mac_inst[Mod_idP].rach_ConfigDedicated, - (void *) mobilityControlInfo->rach_ConfigDedicated, - sizeof(*mobilityControlInfo->rach_ConfigDedicated)); - } - - phy_config_afterHO_ue(Mod_idP, 0, eNB_index, mobilityControlInfo, - 0); - } + UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF = + get_sf_perioidicPHR_Timer(UE_mac_inst[Mod_idP]. + scheduling_info.periodicPHR_Timer); + UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF = + get_sf_prohibitPHR_Timer(UE_mac_inst[Mod_idP]. + scheduling_info.prohibitPHR_Timer); + UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db = + get_db_dl_PathlossChange(UE_mac_inst[Mod_idP]. + scheduling_info.PathlossChange); + UE_mac_inst[Mod_idP].PHR_reporting_active = 0; + LOG_D(MAC, + "[UE %d] config PHR (%d): periodic %d (SF) prohibit %d (SF) pathlosschange %d (db) \n", + Mod_idP, + (mac_MainConfig->phr_Config) ? mac_MainConfig-> + phr_Config->present : -1, + UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF, + UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF, + UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db); + } - if (mbsfn_SubframeConfigList != NULL) { - LOG_I(MAC, - "[UE %d][CONFIG] Received %d subframe allocation pattern for MBSFN\n", - Mod_idP, mbsfn_SubframeConfigList->list.count); - UE_mac_inst[Mod_idP].num_sf_allocation_pattern = - mbsfn_SubframeConfigList->list.count; - - for (i = 0; i < mbsfn_SubframeConfigList->list.count; i++) { - LOG_I(MAC, - "[UE %d] Configuring MBSFN_SubframeConfig %d from received SIB2 \n", - Mod_idP, i); - UE_mac_inst[Mod_idP].mbsfn_SubframeConfig[i] = - mbsfn_SubframeConfigList->list.array[i]; - // LOG_I("[UE %d] MBSFN_SubframeConfig[%d] pattern is %ld\n", Mod_idP, - // UE_mac_inst[Mod_idP].mbsfn_SubframeConfig[i]->subframeAllocation.choice.oneFrame.buf[0]); - } - } + if (physicalConfigDedicated != NULL) { + phy_config_dedicated_ue(Mod_idP, 0, eNB_index, + physicalConfigDedicated); + UE_mac_inst[Mod_idP].physicalConfigDedicated = physicalConfigDedicated; // for SR proc + } #if defined(Rel10) || defined(Rel14) - if (mbsfn_AreaInfoList != NULL) { - LOG_I(MAC, "[UE %d][CONFIG] Received %d MBSFN Area Info\n", - Mod_idP, mbsfn_AreaInfoList->list.count); - UE_mac_inst[Mod_idP].num_active_mbsfn_area = - mbsfn_AreaInfoList->list.count; + if (sCellToAddMod_r10 != NULL) { - for (i = 0; i < mbsfn_AreaInfoList->list.count; i++) { - UE_mac_inst[Mod_idP].mbsfn_AreaInfo[i] = - mbsfn_AreaInfoList->list.array[i]; - LOG_I(MAC, - "[UE %d] MBSFN_AreaInfo[%d]: MCCH Repetition Period = %ld\n", - Mod_idP, i, - UE_mac_inst[Mod_idP].mbsfn_AreaInfo[i]-> - mcch_Config_r9.mcch_RepetitionPeriod_r9); - phy_config_sib13_ue(Mod_idP, 0, eNB_index, i, - UE_mac_inst[Mod_idP]. - mbsfn_AreaInfo[i]->mbsfn_AreaId_r9); - } + + phy_config_dedicated_scell_ue(Mod_idP, eNB_index, + sCellToAddMod_r10, 1); + UE_mac_inst[Mod_idP].physicalConfigDedicatedSCell_r10 = sCellToAddMod_r10->radioResourceConfigDedicatedSCell_r10->physicalConfigDedicatedSCell_r10; // using SCell index 0 + } +#endif + + if (measObj != NULL) { + if (measObj[0] != NULL) { + UE_mac_inst[Mod_idP].n_adj_cells = + measObj[0]->measObject.choice. + measObjectEUTRA.cellsToAddModList->list.count; + LOG_I(MAC, "Number of adjacent cells %d\n", + UE_mac_inst[Mod_idP].n_adj_cells); + + for (i = 0; i < UE_mac_inst[Mod_idP].n_adj_cells; i++) { + UE_mac_inst[Mod_idP].adj_cell_id[i] = + measObj[0]->measObject.choice. + measObjectEUTRA.cellsToAddModList->list.array[i]-> + physCellId; + LOG_I(MAC, "Cell %d : Nid_cell %d\n", i, + UE_mac_inst[Mod_idP].adj_cell_id[i]); + } + + phy_config_meas_ue(Mod_idP, 0, eNB_index, + UE_mac_inst[Mod_idP].n_adj_cells, + UE_mac_inst[Mod_idP].adj_cell_id); + } + } + + + if (mobilityControlInfo != NULL) { + + LOG_D(MAC, "[UE%d] MAC Reset procedure triggered by RRC eNB %d \n", + Mod_idP, eNB_index); + ue_mac_reset(Mod_idP, eNB_index); + + if (mobilityControlInfo->radioResourceConfigCommon. + rach_ConfigCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + rach_ConfigCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.rach_ConfigCommon, + sizeof(RACH_ConfigCommon_t)); } - if (pmch_InfoList != NULL) { + memcpy((void *) &UE_mac_inst[Mod_idP]. + radioResourceConfigCommon->prach_Config.prach_ConfigInfo, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.prach_Config.prach_ConfigInfo, + sizeof(PRACH_ConfigInfo_t)); + UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + prach_Config.rootSequenceIndex = + mobilityControlInfo->radioResourceConfigCommon. + prach_Config.rootSequenceIndex; - // LOG_I(MAC,"DUY: lcid when entering rrc_mac config_req is %02d\n",(pmch_InfoList->list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9)); - - LOG_I(MAC, "[UE %d] Configuring PMCH_config from MCCH MESSAGE \n", - Mod_idP); - - for (i = 0; i < pmch_InfoList->list.count; i++) { - UE_mac_inst[Mod_idP].pmch_Config[i] = - &pmch_InfoList->list.array[i]->pmch_Config_r9; - LOG_I(MAC, "[UE %d] PMCH[%d]: MCH_Scheduling_Period = %ld\n", - Mod_idP, i, - UE_mac_inst[Mod_idP]. - pmch_Config[i]->mch_SchedulingPeriod_r9); - } - - UE_mac_inst[Mod_idP].mcch_status = 1; + if (mobilityControlInfo->radioResourceConfigCommon. + pdsch_ConfigCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + pdsch_ConfigCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.pdsch_ConfigCommon, + sizeof(PDSCH_ConfigCommon_t)); } + // not a pointer: mobilityControlInfo->radioResourceConfigCommon.pusch_ConfigCommon + memcpy((void *) &UE_mac_inst[Mod_idP]. + radioResourceConfigCommon->pusch_ConfigCommon, + (void *) &mobilityControlInfo-> + radioResourceConfigCommon.pusch_ConfigCommon, + sizeof(PUSCH_ConfigCommon_t)); + + if (mobilityControlInfo->radioResourceConfigCommon.phich_Config) { + /* memcpy((void *)&UE_mac_inst[Mod_idP].radioResourceConfigCommon->phich_Config, + (void *)mobilityControlInfo->radioResourceConfigCommon.phich_Config, + sizeof(PHICH_Config_t)); */ + } + + if (mobilityControlInfo->radioResourceConfigCommon. + pucch_ConfigCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + pucch_ConfigCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.pucch_ConfigCommon, + sizeof(PUCCH_ConfigCommon_t)); + } + + if (mobilityControlInfo-> + radioResourceConfigCommon.soundingRS_UL_ConfigCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + soundingRS_UL_ConfigCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.soundingRS_UL_ConfigCommon, + sizeof(SoundingRS_UL_ConfigCommon_t)); + } + + if (mobilityControlInfo-> + radioResourceConfigCommon.uplinkPowerControlCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + uplinkPowerControlCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.uplinkPowerControlCommon, + sizeof(UplinkPowerControlCommon_t)); + } + //configure antennaInfoCommon somewhere here.. + if (mobilityControlInfo->radioResourceConfigCommon.p_Max) { + //to be configured + } + + if (mobilityControlInfo->radioResourceConfigCommon.tdd_Config) { + UE_mac_inst[Mod_idP].tdd_Config = + mobilityControlInfo->radioResourceConfigCommon.tdd_Config; + } + + if (mobilityControlInfo-> + radioResourceConfigCommon.ul_CyclicPrefixLength) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + ul_CyclicPrefixLength, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.ul_CyclicPrefixLength, + sizeof(UL_CyclicPrefixLength_t)); + } + // store the previous rnti in case of failure, and set thenew rnti + UE_mac_inst[Mod_idP].crnti_before_ho = UE_mac_inst[Mod_idP].crnti; + UE_mac_inst[Mod_idP].crnti = + ((mobilityControlInfo-> + newUE_Identity.buf[0]) | (mobilityControlInfo-> + newUE_Identity.buf[1] << 8)); + LOG_I(MAC, "[UE %d] Received new identity %x from %d\n", Mod_idP, + UE_mac_inst[Mod_idP].crnti, eNB_index); + UE_mac_inst[Mod_idP].rach_ConfigDedicated = + malloc(sizeof(*mobilityControlInfo->rach_ConfigDedicated)); + + if (mobilityControlInfo->rach_ConfigDedicated) { + memcpy((void *) UE_mac_inst[Mod_idP].rach_ConfigDedicated, + (void *) mobilityControlInfo->rach_ConfigDedicated, + sizeof(*mobilityControlInfo->rach_ConfigDedicated)); + } + + phy_config_afterHO_ue(Mod_idP, 0, eNB_index, mobilityControlInfo, + 0); + } + + + if (mbsfn_SubframeConfigList != NULL) { + LOG_I(MAC, + "[UE %d][CONFIG] Received %d subframe allocation pattern for MBSFN\n", + Mod_idP, mbsfn_SubframeConfigList->list.count); + UE_mac_inst[Mod_idP].num_sf_allocation_pattern = + mbsfn_SubframeConfigList->list.count; + + for (i = 0; i < mbsfn_SubframeConfigList->list.count; i++) { + LOG_I(MAC, + "[UE %d] Configuring MBSFN_SubframeConfig %d from received SIB2 \n", + Mod_idP, i); + UE_mac_inst[Mod_idP].mbsfn_SubframeConfig[i] = + mbsfn_SubframeConfigList->list.array[i]; + // LOG_I("[UE %d] MBSFN_SubframeConfig[%d] pattern is %ld\n", Mod_idP, + // UE_mac_inst[Mod_idP].mbsfn_SubframeConfig[i]->subframeAllocation.choice.oneFrame.buf[0]); + } + } +#if defined(Rel10) || defined(Rel14) + + if (mbsfn_AreaInfoList != NULL) { + LOG_I(MAC, "[UE %d][CONFIG] Received %d MBSFN Area Info\n", + Mod_idP, mbsfn_AreaInfoList->list.count); + UE_mac_inst[Mod_idP].num_active_mbsfn_area = + mbsfn_AreaInfoList->list.count; + + for (i = 0; i < mbsfn_AreaInfoList->list.count; i++) { + UE_mac_inst[Mod_idP].mbsfn_AreaInfo[i] = + mbsfn_AreaInfoList->list.array[i]; + LOG_I(MAC, + "[UE %d] MBSFN_AreaInfo[%d]: MCCH Repetition Period = %ld\n", + Mod_idP, i, + UE_mac_inst[Mod_idP].mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_RepetitionPeriod_r9); + phy_config_sib13_ue(Mod_idP, 0, eNB_index, i, + UE_mac_inst[Mod_idP]. + mbsfn_AreaInfo[i]->mbsfn_AreaId_r9); + } + } + + if (pmch_InfoList != NULL) { + + // LOG_I(MAC,"DUY: lcid when entering rrc_mac config_req is %02d\n",(pmch_InfoList->list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9)); + + LOG_I(MAC, "[UE %d] Configuring PMCH_config from MCCH MESSAGE \n", + Mod_idP); + + for (i = 0; i < pmch_InfoList->list.count; i++) { + UE_mac_inst[Mod_idP].pmch_Config[i] = + &pmch_InfoList->list.array[i]->pmch_Config_r9; + LOG_I(MAC, "[UE %d] PMCH[%d]: MCH_Scheduling_Period = %ld\n", + Mod_idP, i, + UE_mac_inst[Mod_idP]. + pmch_Config[i]->mch_SchedulingPeriod_r9); + } + + UE_mac_inst[Mod_idP].mcch_status = 1; + } #endif #ifdef CBA - if (cba_rnti) { - UE_mac_inst[Mod_idP].cba_rnti[num_active_cba_groups - 1] = - cba_rnti; - LOG_D(MAC, - "[UE %d] configure CBA group %d RNTI %x for eNB %d (total active cba group %d)\n", - Mod_idP, Mod_idP % num_active_cba_groups, cba_rnti, - eNB_index, num_active_cba_groups); - phy_config_cba_rnti(Mod_idP, CC_idP, eNB_flagP, eNB_index, - cba_rnti, num_active_cba_groups - 1, - num_active_cba_groups); - } + if (cba_rnti) { + UE_mac_inst[Mod_idP].cba_rnti[num_active_cba_groups - 1] = + cba_rnti; + LOG_D(MAC, + "[UE %d] configure CBA group %d RNTI %x for eNB %d (total active cba group %d)\n", + Mod_idP, Mod_idP % num_active_cba_groups, cba_rnti, + eNB_index, num_active_cba_groups); + phy_config_cba_rnti(Mod_idP, CC_idP, eNB_flagP, eNB_index, + cba_rnti, num_active_cba_groups - 1, + num_active_cba_groups); + } #endif - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); - return (0); + return (0); } From dc9cada6c2f3841677ce00801f3ec7c3c95fe3b2 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Fri, 8 Dec 2017 18:05:42 +0100 Subject: [PATCH 095/284] Add PDCP stats and update agent and RAN APIs --- cmake_targets/CMakeLists.txt | 2 + .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 2 +- .../CONTROL_MODULES/PDCP/flexran_agent_pdcp.c | 168 ++++++++++ .../CONTROL_MODULES/PDCP/flexran_agent_pdcp.h | 64 ++++ .../PDCP/flexran_agent_pdcp_defs.h | 63 ++++ .../CONTROL_MODULES/RRC/flexran_agent_rrc.c | 314 +++++++----------- .../CONTROL_MODULES/RRC/flexran_agent_rrc.h | 52 ++- .../RRC/flexran_agent_rrc_defs.h | 64 ++-- openair2/ENB_APP/MESSAGES/V2/flexran.proto | 1 + .../ENB_APP/MESSAGES/V2/stats_common.proto | 21 ++ .../ENB_APP/MESSAGES/V2/stats_messages.proto | 6 +- .../ENB_APP/MESSAGES/V2/time_common.proto | 1 + openair2/ENB_APP/flexran_agent.c | 3 + openair2/ENB_APP/flexran_agent.h | 1 + openair2/ENB_APP/flexran_agent_defs.h | 5 + openair2/ENB_APP/flexran_agent_extern.h | 7 + openair2/ENB_APP/flexran_agent_handler.c | 25 +- openair2/ENB_APP/flexran_agent_ran_api.c | 90 +++++ openair2/ENB_APP/flexran_agent_ran_api.h | 55 +++ openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 187 ++++++++--- openair2/LAYER2/PDCP_v10.1.0/pdcp.h | 46 ++- 21 files changed, 880 insertions(+), 297 deletions(-) create mode 100644 openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c create mode 100644 openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h create mode 100644 openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp_defs.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 734bfccf2d..6399f02ef0 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -762,6 +762,7 @@ include_directories("${OPENAIR_DIR}/targets/ARCH/EXMIMO/DEFS") include_directories("${OPENAIR2_DIR}/ENB_APP") include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC") include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC") +include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/PDCP") include_directories("${OPENAIR2_DIR}/UTIL/OSA") include_directories("${OPENAIR2_DIR}/UTIL/LFDS/liblfds6.1.1/liblfds611/inc") include_directories("${OPENAIR2_DIR}/UTIL/LFDS/liblfds7.0.0/liblfds700/inc") @@ -852,6 +853,7 @@ if (FLEXRAN_AGENT_SB_IF) ${OPENAIR2_DIR}/ENB_APP/flexran_agent_common_internal.c ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c + ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent_task_manager.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent_net_comm.c diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 60cdba76aa..736cdb67e0 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -128,7 +128,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, rlc_reports[j]->retransmission_queue_hol_delay = 100; rlc_reports[j]->has_retransmission_queue_hol_delay = 0; //TODO DONE:Set current size of the pending message in bytes - rlc_reports[j]->status_pdu_size = flexran_get_tx_queue_size(enb_id, i, j + 1); + rlc_reports[j]->status_pdu_size = flexran_get_num_pdus_buffer(enb_id , i, j + 1); rlc_reports[j]->has_status_pdu_size = 1; } diff --git a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c new file mode 100644 index 0000000000..ecc40cd89a --- /dev/null +++ b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c @@ -0,0 +1,168 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file flexran_agent_pdcp.c + * \brief FlexRAN agent Control Module PDCP + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + */ + +#include "flexran_agent_pdcp.h" + + +/*Trigger boolean for PDCP measurement*/ +bool triggered_pdcp = false; +/*Flags showing if a pdcp agent has already been registered*/ +unsigned int pdcp_agent_registered[NUM_MAX_ENB]; + +/*Array containing the Agent-PDCP interfaces*/ +AGENT_PDCP_xface *agent_pdcp_xface[NUM_MAX_ENB]; + +// NUMBER_OF_UE_MAX + +void flexran_agent_pdcp_aggregate_stats(const mid_t mod_id, + const mid_t ue_id, + Protocol__FlexPdcpStats *pdcp_aggr_stats){ + + int lcid=0; + /* only calculate the DRBs */ + //LOG_I(FLEXRAN_AGENT, "enb %d ue %d \n", mod_id, ue_id); + + for (lcid=NUM_MAX_SRB ; lcid < NUM_MAX_SRB + NUM_MAX_DRB; lcid++){ + + pdcp_aggr_stats->pkt_tx += flexran_get_pdcp_tx(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_tx_bytes += flexran_get_pdcp_tx_bytes(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_tx_rate_s += flexran_get_pdcp_tx_rate_s(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_tx_throughput_s += flexran_get_pdcp_tx_throughput_s(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_tx_aiat += flexran_get_pdcp_tx_aiat(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_tx_aiat_s += flexran_get_pdcp_tx_aiat_s(mod_id,ue_id,lcid); + + + pdcp_aggr_stats->pkt_rx += flexran_get_pdcp_rx(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_rx_bytes += flexran_get_pdcp_rx_bytes(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_rx_rate_s += flexran_get_pdcp_rx_rate_s(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_rx_goodput_s += flexran_get_pdcp_rx_goodput_s(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_rx_aiat += flexran_get_pdcp_rx_aiat(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_rx_aiat_s += flexran_get_pdcp_rx_aiat_s(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_rx_oo += flexran_get_pdcp_rx_oo(mod_id,ue_id,lcid); + + } + +} + + +int flexran_agent_pdcp_stats_reply(mid_t mod_id, + const report_config_t *report_config, + Protocol__FlexUeStatsReport **ue_report, + Protocol__FlexCellStatsReport **cell_report) { + + + // Protocol__FlexHeader *header; + int i, j, k; + // int cc_id = 0; + + + /* Allocate memory for list of UE reports */ + if (report_config->nr_ue > 0) { + + for (i = 0; i < report_config->nr_ue; i++) { + + /* Check flag for creation of buffer status report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PDCP_STATS) { + + Protocol__FlexPdcpStats *pdcp_aggr_stats; + pdcp_aggr_stats = malloc(sizeof(Protocol__FlexPdcpStats)); + if (pdcp_aggr_stats == NULL) + goto error; + protocol__flex_pdcp_stats__init(pdcp_aggr_stats); + + flexran_agent_pdcp_aggregate_stats(mod_id, i, pdcp_aggr_stats); + + pdcp_aggr_stats->has_pkt_tx=1; + pdcp_aggr_stats->has_pkt_tx_bytes =1; + pdcp_aggr_stats->has_pkt_tx_rate_s=1; + pdcp_aggr_stats->has_pkt_tx_throughput_s =1; + pdcp_aggr_stats->has_pkt_tx_aiat =1; + pdcp_aggr_stats->has_pkt_tx_aiat_s =1; + + pdcp_aggr_stats->pkt_tx_sn = flexran_get_pdcp_tx_sn(mod_id, i, DEFAULT_DRB); + pdcp_aggr_stats->has_pkt_tx_sn =1; + + pdcp_aggr_stats->has_pkt_rx =1; + pdcp_aggr_stats->has_pkt_rx_bytes =1; + pdcp_aggr_stats->has_pkt_rx_rate_s =1; + pdcp_aggr_stats->has_pkt_rx_goodput_s =1; + pdcp_aggr_stats->has_pkt_rx_aiat =1; + pdcp_aggr_stats->has_pkt_rx_aiat_s =1; + pdcp_aggr_stats->has_pkt_rx_oo =1; + + pdcp_aggr_stats->pkt_rx_sn = flexran_get_pdcp_rx_sn(mod_id, i, DEFAULT_DRB); + pdcp_aggr_stats->has_pkt_rx_sn =1; + + ue_report[i]->pdcp_stats = pdcp_aggr_stats; + + } + } + } else { + LOG_D(FLEXRAN_AGENT, "no UE\n"); + } + + return 0; + + error: + LOG_W(FLEXRAN_AGENT, "Can't allocate PDCP stats\n"); + + /* if (cell_report != NULL) + free(cell_report); + if (ue_report != NULL) + free(ue_report); + */ + return -1; +} + + + +int flexran_agent_register_pdcp_xface(mid_t mod_id, AGENT_PDCP_xface *xface) { + if (pdcp_agent_registered[mod_id]) { + LOG_E(PDCP, "PDCP agent for eNB %d is already registered\n", mod_id); + return -1; + } + + //xface->flexran_pdcp_stats_measurement = NULL; + + pdcp_agent_registered[mod_id] = 1; + agent_pdcp_xface[mod_id] = xface; + + return 0; +} + +int flexran_agent_unregister_pdcp_xface(mid_t mod_id, AGENT_PDCP_xface *xface) { + + //xface->agent_ctxt = NULL; + //xface->flexran_pdcp_stats_measurement = NULL; + + + pdcp_agent_registered[mod_id] = 0; + agent_pdcp_xface[mod_id] = NULL; + + return 0; +} diff --git a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h new file mode 100644 index 0000000000..a962390c00 --- /dev/null +++ b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h @@ -0,0 +1,64 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file flexran_agent_pdcp.h + * \brief FlexRAN agent Control Module PDCP header + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + */ + +#ifndef FLEXRAN_AGENT_PDCP_H_ +#define FLEXRAN_AGENT_PDCP_H_ + +#include "header.pb-c.h" +#include "flexran.pb-c.h" +#include "stats_messages.pb-c.h" +#include "stats_common.pb-c.h" + + +#include "flexran_agent_common.h" +#include "flexran_agent_defs.h" +#include "flexran_agent_pdcp_defs.h" +#include "flexran_agent_ran_api.h" + +/********************************** + * FlexRAN agent - technology PDCP API + **********************************/ + +/* Send to the controller all the pdcp stat updates that occured during this subframe*/ +int flexran_agent_pdcp_stats_reply(mid_t mod_id, + const report_config_t *report_config, + Protocol__FlexUeStatsReport **ue_report, + Protocol__FlexCellStatsReport **cell_report); + +/* Get the stats from RAN API and aggregate them per USER*/ +void flexran_agent_pdcp_aggregate_stats(const mid_t mod_id, + const mid_t ue_id, + Protocol__FlexPdcpStats *pdcp_aggr_stats); + +/*Register technology specific interface callbacks*/ +int flexran_agent_register_pdcp_xface(mid_t mod_id, AGENT_PDCP_xface *xface); + +/*Unregister technology specific callbacks*/ +int flexran_agent_unregister_pdcp_xface(mid_t mod_id, AGENT_PDCP_xface*xface); + +#endif diff --git a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp_defs.h b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp_defs.h new file mode 100644 index 0000000000..46bdf744de --- /dev/null +++ b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp_defs.h @@ -0,0 +1,63 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ +#ifndef __FLEXRAN_AGENT_PDCP_PRIMITIVES_H__ +#define __FLEXRAN_AGENT_PDCP_PRIMITIVES_H__ + +#include "flexran_agent_defs.h" +#include "flexran.pb-c.h" +#include "header.pb-c.h" + + /*PDCP aggregated Packet stats */ +/* +typedef struct pdcp_aggr_stats_s { + int32_t rnti; + + int32_t pkt_tx; + int32_t pkt_tx_bytes; + int32_t pkt_tx_sn; + int32_t pkt_tx_rate_s; + int32_t pkt_tx_throughput_s; + int32_t pkt_tx_aiat; + int32_t pkt_tx_aiat_s; + + int32_t pkt_rx; + int32_t pkt_rx_bytes; + int32_t pkt_rx_sn; + int32_t pkt_rx_rate_s; + int32_t pkt_rx_goodput_s; + int32_t pkt_rx_aiat; + int32_t pkt_rx_aiat_s; + int32_t pkt_rx_oo; + + +} pdcp_aggr_stats_t; +*/ + +/* FLEXRAN AGENT-PDCP Interface */ +typedef struct { + + + // PDCP statistics + void (*flexran_pdcp_stats_measurement)(mid_t mod_id, uint16_t rnti, uint16_t seq_num, uint32_t size); + +} AGENT_PDCP_xface; + +#endif diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c index d48d12d670..e70d2a3d97 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c @@ -33,33 +33,15 @@ #include "log.h" +/*Trigger boolean for RRC measurement*/ +bool triggered_rrc = false; -/*Flags showing if a rrc agent has already been registered*/ +/*Flags showing if an rrc agent has already been registered*/ unsigned int rrc_agent_registered[NUM_MAX_ENB]; /*Array containing the Agent-RRC interfaces*/ AGENT_RRC_xface *agent_rrc_xface[NUM_MAX_ENB]; -/* Ringbuffer related structs used for maintaining the dl rrc config messages */ -//message_queue_t *rrc_dl_config_queue; -struct lfds700_misc_prng_state rrc_ps[NUM_MAX_ENB]; -struct lfds700_ringbuffer_element *rrc_dl_config_array[NUM_MAX_ENB]; -struct lfds700_ringbuffer_state rrc_ringbuffer_state[NUM_MAX_ENB]; - - - -void flexran_agent_init_rrc_agent(mid_t mod_id) { - lfds700_misc_library_init_valid_on_current_logical_core(); - lfds700_misc_prng_init(&rrc_ps[mod_id]); - int num_elements = RINGBUFFER_SIZE + 1; - //Allow RINGBUFFER_SIZE messages to be stored in the ringbuffer at any time - rrc_dl_config_array[mod_id] = malloc( sizeof(struct lfds700_ringbuffer_element) * num_elements); - lfds700_ringbuffer_init_valid_on_current_logical_core( &rrc_ringbuffer_state[mod_id], rrc_dl_config_array[mod_id], num_elements, &rrc_ps[mod_id], NULL ); -} - - - - void flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { int size; @@ -280,156 +262,26 @@ int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg) { /* this is called by RRC as a part of rrc xface . The controller previously requested this*/ void flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t* measResults) { - // int i, m, k; - int priority = 0; // Warning Preventing - void *data; - int size; - err_code_t err_code; - Protocol__FlexUeStatsReport **ue_report; - Protocol__FlexCellStatsReport **cell_report; - Protocol__FlexStatsReply *stats_reply_msg; - Protocol__FlexranMessage *msg; + int i, m, k; + // int priority = 0; // Warning Preventing + // void *data; + // int size; + err_code_t err_code = -100; + triggered_rrc = true; + int num; - Protocol__FlexHeader *header; - int xid = 0; - int i; + num = flexran_get_num_ues (mod_id); - if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) - goto error; + meas_stats = malloc(sizeof(rrc_meas_stats) * num); - - - stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply)); - - if (stats_reply_msg == NULL) - goto error; - - protocol__flex_stats_reply__init(stats_reply_msg); - stats_reply_msg->header = header; - stats_reply_msg->n_ue_report = 1; - stats_reply_msg->n_cell_report = 1; - -/****** LOCK ******************************************************************/ - // pthread_spin_lock(&rrc_meas_t_lock); - - // struct rrc_meas_trigg *ctxt; - // ctxt = rrc_meas_get_trigg(p->rnti, p->meas->measId); - - // pthread_spin_unlock(&rrc_meas_t_lock); -/****** UNLOCK ****************************************************************/ - - // if (ctxt == NULL) { - - // flexran_RRC_meas_reconf(p->rnti, -1, p->meas->measId, NULL, NULL); - // Free the measurement report received from UE. - // ASN_STRUCT_FREE(asn_DEF_MeasResults, p->meas); - // /* Free the params. */ - // free(p); - // return 0; - // } - - - /* Check here whether trigger is registered in agent and then proceed. - */ - // if (em_has_trigger(mod_id, ctxt->t_id, RRC_MEAS_TRIGGER) == 0) { - - // flexran_RRC_meas_reconf(p->rnti, -1, p->meas->measId, NULL, NULL); - // /* Trigger does not exist in agent so remove from wrapper as well. */ - // if (rrc_meas_rem_trigg(ctxt) < 0) { - // goto error; - // } - // } - - - - - /* Set the RNTI of the UE. */ - // repl->rnti = p->rnti; - /* Set the request status. */ - // if (p->reconfig_success == 0) { - // repl->status = STATS_REQ_STATUS__SREQS_FAILURE; - // goto error; - // } - /* Successful outcome. */ - // repl->status = STATS_REQ_STATUS__SREQS_SUCCESS; - /* Set the measurement ID of measurement. */ - // repl->has_measid = 1; - // repl->measid = measResults->measId; - /* Fill the Primary Cell RSRP and RSRQ. */ - // repl->has_pcell_rsrp = 1; - // repl->has_pcell_rsrq = 1; - // #ifdef Rel10 - // repl->has_pcell_rsrp = 1; - // repl->has_pcell_rsrq = 1; - // repl->pcell_rsrp = measResults2->measResultPCell.rsrpResult - 140; - // repl->pcell_rsrq = (measResults2->measResultPCell.rsrqResult)/2 - 20; - - ue_report = malloc(sizeof(Protocol__FlexUeStatsReport *) * 1); - if (ue_report == NULL) - goto error; - - for (i = 0; i < 1; i++) { - - ue_report[i] = malloc(sizeof(Protocol__FlexUeStatsReport)); - if(ue_report[i] == NULL) - goto error; - protocol__flex_ue_stats_report__init(ue_report[i]); - ue_report[i]->rnti = flexran_get_ue_crnti(mod_id, 0); - ue_report[i]->has_rnti = 1; - ue_report[i]->flags = 65536; - ue_report[i]->has_flags = 1; - - } - - cell_report = malloc(sizeof(Protocol__FlexCellStatsReport *) * 1); - if (cell_report == NULL) - goto error; - - for (i = 0; i < 1; i++) { - - cell_report[i] = malloc(sizeof(Protocol__FlexCellStatsReport)); - if(cell_report[i] == NULL) - goto error; - - protocol__flex_cell_stats_report__init(cell_report[i]); - cell_report[i]->carrier_index = 0; //report_config->cc_report_type[i].cc_id; - cell_report[i]->has_carrier_index = 1; - cell_report[i]->flags = 0; // report_config->cc_report_type[i].cc_report_flags; - cell_report[i]->has_flags = 1; - } - - - Protocol__FlexRrcMeasurements *rrc_measurements; - rrc_measurements = malloc(sizeof(Protocol__FlexRrcMeasurements)); - if (rrc_measurements == NULL) - goto error; - protocol__flex_rrc_measurements__init(rrc_measurements); - - rrc_measurements->measid = measResults->measId; - rrc_measurements->has_measid = 1; - - rrc_measurements->pcell_rsrp = measResults->measResultPCell.rsrpResult - 140; - rrc_measurements->has_pcell_rsrp = 1; - - rrc_measurements->pcell_rsrq = (measResults->measResultPCell.rsrqResult)/2 - 20; - rrc_measurements->has_pcell_rsrq = 1 ; - - ue_report[0]->rrc_measurements = rrc_measurements; - - - - - - // #else - // repl->has_pcell_rsrp = 1; - // repl->has_pcell_rsrq = 1; - // repl->pcell_rsrp = RSRP_meas_mapping[meas-> - // measResultServCell.rsrpResult]; - // repl->pcell_rsrq = RSRQ_meas_mapping[meas-> - // measResultServCell.rsrqResult]; - // #endif - - // repl->neigh_meas = NULL; + for (i = 0; i < num; i++){ + meas_stats[i].rnti = flexran_get_ue_crnti(mod_id, i); + meas_stats[i].meas_id = measResults->measId; + meas_stats[i].rsrp = measResults->measResultPCell.rsrpResult - 140; + meas_stats[i].rsrq = (measResults->measResultPCell.rsrqResult)/2 - 20; + + } + // repl->neigh_meas = NULL; // if (meas->measResultNeighCells != NULL) { // /* @@ -595,34 +447,34 @@ void flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t* measResults // free(p); - stats_reply_msg->cell_report = cell_report; + // stats_reply_msg->cell_report = cell_report; - stats_reply_msg->ue_report = ue_report; + // stats_reply_msg->ue_report = ue_report; - msg = malloc(sizeof(Protocol__FlexranMessage)); - if(msg == NULL) - goto error; - protocol__flexran_message__init(msg); - msg->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG; - msg->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; - msg->stats_reply_msg = stats_reply_msg; + // msg = malloc(sizeof(Protocol__FlexranMessage)); + // if(msg == NULL) + // goto error; + // protocol__flexran_message__init(msg); + // msg->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG; + // msg->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; + // msg->stats_reply_msg = stats_reply_msg; - data = flexran_agent_pack_message(msg, &size); + // data = flexran_agent_pack_message(msg, &size); - if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) { + // if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) { - err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; - goto error; - } + // err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; + // goto error; + // } - LOG_I(FLEXRAN_AGENT,"RRC Trigger is done \n"); + // LOG_I(FLEXRAN_AGENT,"RRC Trigger is done \n"); return; - error: + // error: - LOG_E(FLEXRAN_AGENT, "Could not send UE state message becasue of %d \n",err_code); + // LOG_E(FLEXRAN_AGENT, "Could not send UE state message becasue of %d \n",err_code); /* Free the measurement report received from UE. */ // ASN_STRUCT_FREE(asn_DEF_MeasResults, p->meas); /* Free the params. */ @@ -631,6 +483,98 @@ void flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t* measResults } +int flexran_agent_rrc_stats_reply(mid_t mod_id, + const report_config_t *report_config, + Protocol__FlexUeStatsReport **ue_report, + Protocol__FlexCellStatsReport **cell_report) { + + + // Protocol__FlexHeader *header; + int i, j, k; + // int cc_id = 0; + int enb_id = mod_id; + + /* Allocate memory for list of UE reports */ + if (report_config->nr_ue > 0) { + + for (i = 0; i < report_config->nr_ue; i++) { + + /* Check flag for creation of buffer status report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RRC_MEASUREMENTS) { + + Protocol__FlexRrcMeasurements *rrc_measurements; + rrc_measurements = malloc(sizeof(Protocol__FlexRrcMeasurements)); + if (rrc_measurements == NULL) + goto error; + protocol__flex_rrc_measurements__init(rrc_measurements); + + if (triggered_rrc){ + rrc_measurements->measid = meas_stats[i].meas_id; + rrc_measurements->has_measid = 1; + + rrc_measurements->pcell_rsrp = meas_stats[i].rsrp; + rrc_measurements->has_pcell_rsrp = 1; + + rrc_measurements->pcell_rsrq = meas_stats[i].rsrq; + rrc_measurements->has_pcell_rsrq = 1 ; + + ue_report[i]->rrc_measurements = rrc_measurements; + // triggered_rrc = false; // To be decided later + } + } + } + } + + /* To be extended for RRC layer */ + // if (report_config->nr_cc > 0) { + + + // // Fill in the Cell reports + // for (i = 0; i < report_config->nr_cc; i++) { + + + // /* Check flag for creation of noise and interference report */ + // if(report_config->cc_report_type[i].cc_report_flags & PROTOCOL__FLEX_CELL_STATS_TYPE__FLCST_NOISE_INTERFERENCE) { + // // TODO: Fill in the actual noise and interference report for this cell + // Protocol__FlexNoiseInterferenceReport *ni_report; + // ni_report = malloc(sizeof(Protocol__FlexNoiseInterferenceReport)); + // if(ni_report == NULL) + // goto error; + // protocol__flex_noise_interference_report__init(ni_report); + // // Current frame and subframe number + // ni_report->sfn_sf = flexran_get_sfn_sf(enb_id); + // ni_report->has_sfn_sf = 1; + // //TODO:Received interference power in dbm + // ni_report->rip = 0; + // ni_report->has_rip = 1; + // //TODO:Thermal noise power in dbm + // ni_report->tnp = 0; + // ni_report->has_tnp = 1; + + // ni_report->p0_nominal_pucch = flexran_get_p0_nominal_pucch(enb_id, 0); + // ni_report->has_p0_nominal_pucch = 1; + // cell_report[i]->noise_inter_report = ni_report; + // } + // } + + + + + // } + + return 0; + + error: + + if (cell_report != NULL) + free(cell_report); + if (ue_report != NULL) + free(ue_report); + + return -1; +} + + int flexran_agent_register_rrc_xface(mid_t mod_id, AGENT_RRC_xface *xface) { if (rrc_agent_registered[mod_id]) { LOG_E(RRC, "RRC agent for eNB %d is already registered\n", mod_id); diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h index aa210f9d41..ae26b41621 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h @@ -1,31 +1,23 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2014 Eurecom - - OpenAirInterface is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - - OpenAirInterface 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with OpenAirInterface.The full GNU General Public License is - included in this distribution in the file called "COPYING". If not, - see . - - Contact Information - OpenAirInterface Admin: openair_admin@eurecom.fr - OpenAirInterface Tech : openair_tech@eurecom.fr - OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr - - Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. - - *******************************************************************************/ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ /*! \file flexran_agent_rrc.h * \brief FlexRAN agent Control Module RRC header @@ -65,6 +57,10 @@ int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg); /* this is called by RRC as a part of rrc xface . The controller previously requested this*/ void flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t *); +/* Statistics reply protocol message constructor and destructor */ +int flexran_agent_rrc_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report); +int flexran_agent_rrc_destroy_stats_reply(Protocol__FlexranMessage *msg); + /*Register technology specific interface callbacks*/ int flexran_agent_register_rrc_xface(mid_t mod_id, AGENT_RRC_xface *xface); diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h index ad1375171e..a101bab242 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h @@ -1,31 +1,24 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2016 Eurecom +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ - OpenAirInterface is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - - OpenAirInterface 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with OpenAirInterface.The full GNU General Public License is - included in this distribution in the file called "COPYING". If not, - see . - - Contact Information - OpenAirInterface Admin: openair_admin@eurecom.fr - OpenAirInterface Tech : openair_tech@eurecom.fr - OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr - - Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. - - *******************************************************************************/ /*! \file flexran_agent_rrc_defs.h * \brief FlexRAN agent - RRC interface primitives @@ -46,11 +39,24 @@ #define RINGBUFFER_SIZE 100 + +typedef struct +{ + int32_t rnti; + int32_t meas_id; + int32_t rsrp; + int32_t rsrq; + + /*To Be Extended*/ +}rrc_meas_stats; + +/* RRC CMI statistics */ +rrc_meas_stats * meas_stats; + + /* FLEXRAN AGENT-RRC Interface */ typedef struct { - /// Inform the controller about the scheduling requests received during the subframe - //void (*flexran_agent_send_update_rrc_stats)(mid_t mod_id); /// Notify the controller for a state change of a particular UE, by sending the proper /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) diff --git a/openair2/ENB_APP/MESSAGES/V2/flexran.proto b/openair2/ENB_APP/MESSAGES/V2/flexran.proto index d79051d201..18eb760cc3 100644 --- a/openair2/ENB_APP/MESSAGES/V2/flexran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/flexran.proto @@ -132,6 +132,7 @@ message flex_enb_config_reply { optional flex_header header = 1; optional uint32 eNB_id = 2; // Unique id to distinguish the eNB repeated flex_cell_config cell_config = 3; + optional uint32 device_spec = 4; } message flex_ue_config_request { diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto index 0d8a565c06..a7d78841a3 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto @@ -242,3 +242,24 @@ message flex_eutra_ref_signal_meas { optional int32 rsrq = 2; } + +message flex_pdcp_stats { + + optional uint32 pkt_tx = 1; + optional uint32 pkt_tx_bytes = 2; + optional uint32 pkt_tx_sn = 3; + optional uint32 pkt_tx_rate_s = 4; + optional uint32 pkt_tx_throughput_s = 5; + optional uint32 pkt_tx_aiat = 7; + optional uint32 pkt_tx_aiat_s = 8; + + optional uint32 pkt_rx = 9; + optional uint32 pkt_rx_bytes = 10; + optional uint32 pkt_rx_sn = 11; + optional uint32 pkt_rx_rate_s = 12; + optional uint32 pkt_rx_goodput_s = 13; + optional uint32 pkt_rx_aiat = 14; + optional uint32 pkt_rx_aiat_s = 15; + optional uint32 pkt_rx_oo = 16; + } + diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto index 1ddb19722b..8cad6f4fbe 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto @@ -47,7 +47,8 @@ message flex_ue_stats_report { optional flex_dl_cqi_report dl_cqi_report = 7; optional flex_paging_buffer_report pbr = 8; optional flex_ul_cqi_report ul_cqi_report = 9; - optional flex_rrc_measurements rrc_measurements = 10; + optional flex_rrc_measurements rrc_measurements = 10; + optional flex_pdcp_stats pdcp_stats = 11; } // @@ -84,6 +85,9 @@ enum flex_ue_stats_type { FLUST_DL_CQI = 16; FLUST_PBS = 32; FLUST_UL_CQI = 64; + + FLUST_PDCP_STATS = 1024; // To be changed // To be extended with more types of stats FLUST_RRC_MEASUREMENTS = 65536; + } diff --git a/openair2/ENB_APP/MESSAGES/V2/time_common.proto b/openair2/ENB_APP/MESSAGES/V2/time_common.proto index 8bd2497443..baf0c0e9ae 100644 --- a/openair2/ENB_APP/MESSAGES/V2/time_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/time_common.proto @@ -26,5 +26,6 @@ message flex_ul_info { optional uint32 reception_status = 3; optional uint32 tpc = 4; optional uint32 serv_cell_index = 5; + optional uint32 rssi = 6; } diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c index ec984cfa8b..23ac8f02ac 100644 --- a/openair2/ENB_APP/flexran_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -267,6 +267,9 @@ int flexran_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properti AGENT_RRC_xface *rrc_agent_xface = (AGENT_RRC_xface *) malloc(sizeof(AGENT_RRC_xface)); flexran_agent_register_rrc_xface(mod_id, rrc_agent_xface); + AGENT_PDCP_xface *pdcp_agent_xface = (AGENT_PDCP_xface *) malloc(sizeof(AGENT_PDCP_xface)); + flexran_agent_register_pdcp_xface(mod_id, pdcp_agent_xface); + /* * initilize a timer */ diff --git a/openair2/ENB_APP/flexran_agent.h b/openair2/ENB_APP/flexran_agent.h index 0ef48e2105..f9205c071f 100644 --- a/openair2/ENB_APP/flexran_agent.h +++ b/openair2/ENB_APP/flexran_agent.h @@ -38,6 +38,7 @@ #include "flexran_agent_ran_api.h" #include "flexran_agent_mac.h" #include "flexran_agent_rrc.h" +#include "flexran_agent_pdcp.h" #include "log.h" #include "assertions.h" diff --git a/openair2/ENB_APP/flexran_agent_defs.h b/openair2/ENB_APP/flexran_agent_defs.h index 0b8822a949..040a8192f6 100644 --- a/openair2/ENB_APP/flexran_agent_defs.h +++ b/openair2/ENB_APP/flexran_agent_defs.h @@ -32,11 +32,16 @@ #include #include #include +#include +#include #include "link_manager.h" #define NUM_MAX_ENB 2 +#define NUM_MAX_DRB 8 +#define NUM_MAX_SRB 3 #define NUM_MAX_UE 2048 +#define DEFAULT_DRB 3 #define DEFAULT_FLEXRAN_AGENT_IPv4_ADDRESS "127.0.0.1" #define DEFAULT_FLEXRAN_AGENT_PORT 2210 #define DEFAULT_FLEXRAN_AGENT_CACHE "/mnt/oai_agent_cache" diff --git a/openair2/ENB_APP/flexran_agent_extern.h b/openair2/ENB_APP/flexran_agent_extern.h index 4df984e1a0..a9af552856 100644 --- a/openair2/ENB_APP/flexran_agent_extern.h +++ b/openair2/ENB_APP/flexran_agent_extern.h @@ -33,6 +33,7 @@ // #include "flexran_agent_defs.h" #include "flexran_agent_mac_defs.h" #include "flexran_agent_rrc_defs.h" +#include "flexran_agent_pdcp_defs.h" //extern msg_context_t shared_ctxt[NUM_MAX_ENB][FLEXRAN_AGENT_MAX]; @@ -51,6 +52,12 @@ extern AGENT_RRC_xface *agent_rrc_xface[NUM_MAX_ENB]; /* Flag indicating whether the VSFs for the RRC control module have been registered */ extern unsigned int rrc_agent_registered[NUM_MAX_ENB]; +/* Control module interface for the communication of the RRC Control Module with the agent */ +extern AGENT_PDCP_xface *agent_pdcp_xface[NUM_MAX_ENB]; + +/* Flag indicating whether the VSFs for the RRC control module have been registered */ +extern unsigned int pdcp_agent_registered[NUM_MAX_ENB]; + /* Requried to know which UEs had a harq updated over some subframe */ extern int harq_pid_updated[NUMBER_OF_UE_MAX][8]; extern int harq_pid_round[NUMBER_OF_UE_MAX][8]; diff --git a/openair2/ENB_APP/flexran_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c index fc2ed135c8..6ad0b88975 100644 --- a/openair2/ENB_APP/flexran_agent_handler.c +++ b/openair2/ENB_APP/flexran_agent_handler.c @@ -143,7 +143,7 @@ void * flexran_agent_pack_message(Protocol__FlexranMessage *msg, DevAssert(buffer !=NULL); - LOG_D(FLEXRAN_AGENT,"Serilized the enb mac stats reply (size %d)\n", *size); + LOG_D(FLEXRAN_AGENT,"Serilized the eNB-UE stats reply (size %d)\n", *size); return buffer; @@ -457,7 +457,7 @@ int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *re } - /* + /* MAC reply split */ @@ -467,7 +467,26 @@ int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *re goto error; } - + /* + RRC reply split + */ + + if (flexran_agent_rrc_stats_reply(enb_id, report_config, ue_report, cell_report) < 0 ) { + err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; + goto error; + } + + + /* + PDCP reply split + */ + + if (flexran_agent_pdcp_stats_reply(enb_id, report_config, ue_report, cell_report) < 0 ) { + err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; + goto error; + } + + stats_reply_msg->cell_report = cell_report; stats_reply_msg->ue_report = ue_report; diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 0d3145e1d2..01f05b1ba5 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -179,6 +179,17 @@ int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t chann return rlc_status.bytes_in_buffer; } + +int flexran_get_num_pdus_buffer(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); + uint16_t subframe = (uint16_t) flexran_get_current_subframe(mod_id); + mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id, frame, subframe, ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0); + return rlc_status.pdus_in_buffer; +} + + + int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); @@ -1077,6 +1088,85 @@ void flexran_agent_set_operating_frame_type (mid_t mod_id, int cc_id, int frame_ enb_properties->properties[mod_id]->frame_type[cc_id]=frame_type; } +/*********** PDCP *************/ + +/*PDCP num tx pdu status flexRAN*/ +uint32_t flexran_get_pdcp_tx(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + if (mod_id <0 || mod_id> MAX_NUM_CCs || ue_id<0 || ue_id> NUMBER_OF_UE_MAX || lcid<0 || lcid>NB_RB_MAX) + return -1; + return Pdcp_stats_tx[mod_id][ue_id][lcid]; +} + +/*PDCP num tx bytes status flexRAN*/ +uint32_t flexran_get_pdcp_tx_bytes(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_tx_bytes[mod_id][ue_id][lcid]; +} + +/*PDCP number of transmit packet / second status flexRAN*/ +uint32_t flexran_get_pdcp_tx_rate_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_tx_rate_s[mod_id][ue_id][lcid]; +} + +/*PDCP throughput (bit/s) status flexRAN*/ +uint32_t flexran_get_pdcp_tx_throughput_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_tx_throughput_s[mod_id][ue_id][lcid]; +} + +/*PDCP tx sequence number flexRAN*/ +uint32_t flexran_get_pdcp_tx_sn(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_tx_sn[mod_id][ue_id][lcid]; +} + +/*PDCP tx aggregated packet arrival flexRAN*/ +uint32_t flexran_get_pdcp_tx_aiat(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_tx_aiat[mod_id][ue_id][lcid]; +} + +/*PDCP tx aggregated packet arrival flexRAN*/ +uint32_t flexran_get_pdcp_tx_aiat_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_tx_aiat_s[mod_id][ue_id][lcid]; +} + + +/*PDCP num rx pdu status flexRAN*/ +uint32_t flexran_get_pdcp_rx(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_rx[mod_id][ue_id][lcid]; +} + +/*PDCP num rx bytes status flexRAN*/ +uint32_t flexran_get_pdcp_rx_bytes(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_rx_bytes[mod_id][ue_id][lcid]; +} + +/*PDCP number of received packet / second flexRAN*/ +uint32_t flexran_get_pdcp_rx_rate_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_rx_rate_s[mod_id][ue_id][lcid]; +} + +/*PDCP gootput (bit/s) status flexRAN*/ +uint32_t flexran_get_pdcp_rx_goodput_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_rx_goodput_s[mod_id][ue_id][lcid]; +} + +/*PDCP rx sequence number flexRAN*/ +uint32_t flexran_get_pdcp_rx_sn(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_rx_sn[mod_id][ue_id][lcid]; +} + +/*PDCP rx aggregated packet arrival flexRAN*/ +uint32_t flexran_get_pdcp_rx_aiat(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_rx_aiat[mod_id][ue_id][lcid]; +} + +/*PDCP rx aggregated packet arrival flexRAN*/ +uint32_t flexran_get_pdcp_rx_aiat_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_rx_aiat_s[mod_id][ue_id][lcid]; +} + +/*PDCP num of received outoforder pdu status flexRAN*/ +uint32_t flexran_get_pdcp_rx_oo(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_rx_outoforder[mod_id][ue_id][lcid]; +} diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 9f0313c1ca..4d84251608 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -39,6 +39,7 @@ #include "LAYER2/MAC/extern.h" #include "LAYER2/RLC/rlc.h" #include "SCHED/defs.h" +#include "pdcp.h" #include "RRC/LITE/extern.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" #include "RRC/LITE/rrc_eNB_UE_context.h" @@ -91,6 +92,9 @@ int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id); /* Get the transmission queue size for a UE with a channel_id logical channel id */ int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); +/*Get number of pdus in RLC buffer*/ +int flexran_get_num_pdus_buffer(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); + /* Get the head of line delay for a UE with a channel_id logical channel id */ int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); @@ -334,3 +338,54 @@ void flexran_agent_set_operating_frame_type (mid_t mod_id, int cc_id, int frame_ /*RRC status flexRAN*/ int flexran_get_rrc_status(const mid_t mod_id, const rnti_t rntiP); + + +/***************************** PDCP ***********************/ + +/*PDCP num tx pdu status flexRAN*/ +uint32_t flexran_get_pdcp_tx(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + +/*PDCP num tx bytes status flexRAN*/ +uint32_t flexran_get_pdcp_tx_bytes(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + +/*PDCP number of transmit packet / second status flexRAN*/ +uint32_t flexran_get_pdcp_tx_rate_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + +/*PDCP throughput (bit/s) status flexRAN*/ +uint32_t flexran_get_pdcp_tx_throughput_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + +/*PDCP tx sequence number flexRAN*/ +uint32_t flexran_get_pdcp_tx_sn(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + +/*PDCP tx aggregated packet arrival flexRAN*/ +uint32_t flexran_get_pdcp_tx_aiat(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + +/*PDCP tx aggregated packet arrival per second flexRAN*/ +uint32_t flexran_get_pdcp_tx_aiat_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + + +/*PDCP num rx pdu status flexRAN*/ +uint32_t flexran_get_pdcp_rx(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + +/*PDCP num rx bytes status flexRAN*/ +uint32_t flexran_get_pdcp_rx_bytes(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + +/*PDCP number of received packet / second flexRAN*/ +uint32_t flexran_get_pdcp_rx_rate_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + +/*PDCP gootput (bit/s) status flexRAN*/ +uint32_t flexran_get_pdcp_rx_goodput_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + +/*PDCP rx sequence number flexRAN*/ +uint32_t flexran_get_pdcp_rx_sn(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + +/*PDCP rx aggregated packet arrival flexRAN*/ +uint32_t flexran_get_pdcp_rx_aiat(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + +/*PDCP rx aggregated packet arrival per second flexRAN*/ +uint32_t flexran_get_pdcp_rx_aiat_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + +/*PDCP num of received outoforder pdu status flexRAN*/ +uint32_t flexran_get_pdcp_rx_oo(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); + + diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 8dad83a90a..397a194edf 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -69,6 +69,7 @@ extern int otg_enabled; #endif + //----------------------------------------------------------------------------- /* * If PDCP_UNIT_TEST is set here then data flow between PDCP and RLC is broken @@ -102,6 +103,8 @@ boolean_t pdcp_data_req( hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; + uint8_t rb_offset= (srb_flagP == 0) ? DTCH -1 : 0; + uint16_t pdcp_uid=0; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_IN); CHECK_CTXT_ARGS(ctxt_pP); @@ -152,7 +155,7 @@ boolean_t pdcp_data_req( ctxt_pP->configured=TRUE; } - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); } else { start_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); @@ -223,7 +226,7 @@ boolean_t pdcp_data_req( LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Cannot fill PDU buffer with relevant header fields!\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p)); - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); @@ -241,8 +244,9 @@ boolean_t pdcp_data_req( if (pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer((unsigned char*)pdcp_pdu_p->data, &pdu_header) == FALSE) { LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Cannot fill PDU buffer with relevant header fields!\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p)); + + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); @@ -264,7 +268,7 @@ boolean_t pdcp_data_req( free_mem_block(pdcp_pdu_p, __func__); - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); @@ -292,7 +296,7 @@ boolean_t pdcp_data_req( (((pdcp_p->cipheringAlgorithm) != 0) || ((pdcp_p->integrityProtAlgorithm) != 0))) { - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].apply_security); } else { start_meas(&UE_pdcp_stats[ctxt_pP->module_id].apply_security); @@ -387,7 +391,7 @@ boolean_t pdcp_data_req( break; } - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); } else { stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); @@ -397,16 +401,45 @@ boolean_t pdcp_data_req( * Control arrives here only if rlc_data_req() returns RLC_OP_STATUS_OK * so we return TRUE afterwards */ - /* - if (rb_id>=DTCH) { - if (ctxt_pP->enb_flag == 1) { - Pdcp_stats_tx[module_id][(rb_id & RAB_OFFSET2 )>> RAB_SHIFT2][(rb_id & RAB_OFFSET)-DTCH]++; - Pdcp_stats_tx_bytes[module_id][(rb_id & RAB_OFFSET2 )>> RAB_SHIFT2][(rb_id & RAB_OFFSET)-DTCH] += sdu_buffer_size; - } else { - Pdcp_stats_tx[module_id][(rb_id & RAB_OFFSET2 )>> RAB_SHIFT2][(rb_id & RAB_OFFSET)-DTCH]++; - Pdcp_stats_tx_bytes[module_id][(rb_id & RAB_OFFSET2 )>> RAB_SHIFT2][(rb_id & RAB_OFFSET)-DTCH] += sdu_buffer_size; - } - }*/ + + for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){ + if (pdcp_p->rnti[pdcp_uid] == ctxt_pP->rnti ) + break; + } + + //LOG_I(PDCP,"ueid %d lcid %d tx seq num %d\n", pdcp_uid, rb_idP+rb_offset, current_sn); + Pdcp_stats_tx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_tx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; + Pdcp_stats_tx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=current_sn; + + if (Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset] < pdcp_frame *10 + pdcp_subframe) { + Pdcp_stats_tx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_frame *10 + pdcp_subframe - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_frame *10 + pdcp_subframe - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + } + else { + Pdcp_stats_tx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (1024 + pdcp_frame *10 + pdcp_subframe - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (1024 + pdcp_frame *10 + pdcp_subframe - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + } + + + Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=ctxt_pP->frame*10+ctxt_pP->subframe; + + if (pdcp_frame % 100 == 0 ) { + Pdcp_stats_tx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]= Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]; + Pdcp_stats_tx_throughput_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_stats_tx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]*8/1000; + Pdcp_stats_tx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]; + + Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0; + Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0; + Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0; + }else { + Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; + + } + + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); return ret; @@ -436,6 +469,9 @@ pdcp_data_ind( boolean_t packet_forwarded = FALSE; hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; + uint8_t rb_offset= (srb_flagP == 0) ? DTCH -1 :0; + uint16_t pdcp_uid=0; + uint8_t oo_flag=0; #if defined(LINK_ENB_PDCP_TO_GTPV1U) MessageDef *message_p = NULL; uint8_t *gtpu_buffer_p = NULL; @@ -590,6 +626,7 @@ pdcp_data_ind( else LOG_D(PDCP, "Passing piggybacked SDU to RRC ...\n");*/ } else { + oo_flag=1; LOG_W(PDCP, PROTOCOL_PDCP_CTXT_FMT"Incoming PDU has an unexpected sequence number (%d), RX window synchronisation have probably been lost!\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), @@ -789,6 +826,53 @@ pdcp_data_ind( GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).rab_id = rb_id + 4; itti_send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p); packet_forwarded = TRUE; + + /* Print octets of incoming data in hexadecimal form */ + LOG_D(PDCP, "Following content has been received from RLC (%d,%d)(PDCP header has already been removed):\n", + sdu_buffer_sizeP - payload_offset + (int)sizeof(pdcp_data_ind_header_t), + sdu_buffer_sizeP - payload_offset); + //util_print_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); + //util_flush_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); + + /* + * Update PDCP statistics + * XXX Following two actions are identical, is there a merge error? + */ + + for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){ + if (pdcp_p->rnti[pdcp_uid] == ctxt_pP->rnti ) + break; + } + + Pdcp_stats_rx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_rx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP - payload_offset; + + Pdcp_stats_rx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=sequence_number; + + if (oo_flag == 1 ) + Pdcp_stats_rx_outoforder[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + + if (Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset] < pdcp_frame * 10 + pdcp_subframe) { + Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_frame *10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(pdcp_frame *10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + } else { + Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (1024 +pdcp_frame * 10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(1024 +pdcp_frame * 10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + } + Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_frame * 10 +pdcp_subframe; + + if (pdcp_frame % 102 == 0) { + Pdcp_stats_rx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]; + Pdcp_stats_rx_goodput_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]*8/1023; + Pdcp_stats_rx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]= Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]; + + Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0; + Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0; + Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0; + }else { + Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); + } } #else @@ -842,25 +926,8 @@ pdcp_data_ind( sdu_buffer_sizeP - payload_offset); list_add_tail_eurecom (new_sdu_p, sdu_list_p); - /* Print octets of incoming data in hexadecimal form */ - LOG_D(PDCP, "Following content has been received from RLC (%d,%d)(PDCP header has already been removed):\n", - sdu_buffer_sizeP - payload_offset + (int)sizeof(pdcp_data_ind_header_t), - sdu_buffer_sizeP - payload_offset); - //util_print_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); - //util_flush_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); - - /* - * Update PDCP statistics - * XXX Following two actions are identical, is there a merge error? - */ - - /*if (ctxt_pP->enb_flag == 1) { - Pdcp_stats_rx[module_id][(rb_idP & RAB_OFFSET2) >> RAB_SHIFT2][(rb_idP & RAB_OFFSET) - DTCH]++; - Pdcp_stats_rx_bytes[module_id][(rb_idP & RAB_OFFSET2) >> RAB_SHIFT2][(rb_idP & RAB_OFFSET) - DTCH] += sdu_buffer_sizeP; - } else { - Pdcp_stats_rx[module_id][(rb_idP & RAB_OFFSET2) >> RAB_SHIFT2][(rb_idP & RAB_OFFSET) - DTCH]++; - Pdcp_stats_rx_bytes[module_id][(rb_idP & RAB_OFFSET2) >> RAB_SHIFT2][(rb_idP & RAB_OFFSET) - DTCH] += sdu_buffer_sizeP; - }*/ + + } } @@ -891,6 +958,9 @@ pdcp_run ( ) //----------------------------------------------------------------------------- { + + pdcp_frame =ctxt_pP->frame; + pdcp_subframe= ctxt_pP->subframe; #if defined(ENABLE_ITTI) MessageDef *msg_p; const char *msg_name; @@ -1139,7 +1209,7 @@ rrc_pdcp_config_asn1_req ( return TRUE; } else { - LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD key 0x%"PRIx64"\n", + LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD key 0x%"PRIx64"\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), key); } @@ -1470,12 +1540,19 @@ pdcp_config_req_asn1 ( uint8_t *const kUPenc_pP) //----------------------------------------------------------------------------- { - + int i; switch (actionP) { case CONFIG_ACTION_ADD: DevAssert(pdcp_pP != NULL); if (ctxt_pP->enb_flag == ENB_FLAG_YES) { pdcp_pP->is_ue = FALSE; + for (i=0; i < NUMBER_OF_UE_MAX; i++) { + if (pdcp_pP->rnti[i] != 0 ) continue ; // skip active ues + pdcp_pP->rnti[i]=ctxt_pP->rnti; + pdcp_pP->uid[i]=i; + pdcp_num_ues++; + break; + } //pdcp_eNB_UE_instance_to_rnti[ctxtP->module_id] = ctxt_pP->rnti; pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] = ctxt_pP->rnti; //pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % NUMBER_OF_UE_MAX; @@ -1575,6 +1652,18 @@ pdcp_config_req_asn1 ( lc_idP, rb_idP); + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { + + for (i=0; i < NUMBER_OF_UE_MAX; i++) { + if (pdcp_pP->rnti[i] == ctxt_pP->rnti ) { + pdcp_pP->rnti[i]=0; + pdcp_pP->uid[i]=0; + pdcp_num_ues--; + break; + } + } + } + /* Security keys */ if (pdcp_pP->kUPenc != NULL) { free(pdcp_pP->kUPenc); @@ -1826,13 +1915,14 @@ rrc_pdcp_config_req ( //----------------------------------------------------------------------------- -// TODO PDCP module initialization code might be removed + int pdcp_module_init ( void ) //----------------------------------------------------------------------------- { + #ifdef PDCP_USE_RT_FIFO int ret; @@ -1952,14 +2042,27 @@ void pdcp_layer_init(void) pdcp_input_sdu_remaining_size_to_read=0; memset(Pdcp_stats_tx, 0, sizeof(Pdcp_stats_tx)); + memset(Pdcp_stats_tx_s, 0, sizeof(Pdcp_stats_tx_s)); memset(Pdcp_stats_tx_bytes, 0, sizeof(Pdcp_stats_tx_bytes)); - memset(Pdcp_stats_tx_bytes_last, 0, sizeof(Pdcp_stats_tx_bytes_last)); - memset(Pdcp_stats_tx_rate, 0, sizeof(Pdcp_stats_tx_rate)); + memset(Pdcp_stats_tx_bytes_s, 0, sizeof(Pdcp_stats_tx_bytes_s)); + memset(Pdcp_stats_tx_rate_s, 0, sizeof(Pdcp_stats_tx_rate_s)); + memset(Pdcp_stats_tx_sn, 0, sizeof(Pdcp_stats_tx_sn)); + memset(Pdcp_stats_tx_throughput_s, 0, sizeof(Pdcp_stats_tx_throughput_s)); + memset(Pdcp_stats_tx_aiat, 0, sizeof(Pdcp_stats_tx_aiat)); + memset(Pdcp_stats_tx_iat, 0, sizeof(Pdcp_stats_tx_iat)); + memset(Pdcp_stats_rx, 0, sizeof(Pdcp_stats_rx)); + memset(Pdcp_stats_rx_s, 0, sizeof(Pdcp_stats_rx_s)); memset(Pdcp_stats_rx_bytes, 0, sizeof(Pdcp_stats_rx_bytes)); - memset(Pdcp_stats_rx_bytes_last, 0, sizeof(Pdcp_stats_rx_bytes_last)); - memset(Pdcp_stats_rx_rate, 0, sizeof(Pdcp_stats_rx_rate)); + memset(Pdcp_stats_rx_bytes_s, 0, sizeof(Pdcp_stats_rx_bytes_s)); + memset(Pdcp_stats_rx_rate_s, 0, sizeof(Pdcp_stats_rx_rate_s)); + memset(Pdcp_stats_rx_sn, 0, sizeof(Pdcp_stats_rx_sn)); + memset(Pdcp_stats_rx_goodput_s, 0, sizeof(Pdcp_stats_rx_goodput_s)); + memset(Pdcp_stats_rx_aiat, 0, sizeof(Pdcp_stats_rx_aiat)); + memset(Pdcp_stats_rx_iat, 0, sizeof(Pdcp_stats_rx_iat)); + memset(Pdcp_stats_rx_outoforder, 0, sizeof(Pdcp_stats_rx_outoforder)); + } //----------------------------------------------------------------------------- diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h index 94084273d1..fb3e02b299 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h @@ -94,15 +94,41 @@ extern int pdcp_instance_cnt; int init_pdcp_thread(void); void cleanup_pdcp_thread(void); +public_pdcp(frame_t pdcp_frame); +public_pdcp(sub_frame_t pdcp_subframe); +public_pdcp(uint16_t pdcp_num_ues); + + +public_pdcp(uint32_t Pdcp_stats_tx_bytes[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_bytes_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_sn[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_rate_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_throughput_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_aiat[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_aiat_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_aiat_tmp_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_iat[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); + +public_pdcp(uint32_t Pdcp_stats_rx[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_bytes[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_bytes_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_sn[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_rate_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_goodput_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_aiat[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_aiat_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_aiat_tmp_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_iat[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_outoforder[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); + + +/*Packet Probing for agent PDCP*/ +//public_pdcp(uint64_t *pdcp_packet_counter); +//public_pdcp(uint64_t *pdcp_size_packet); -public_pdcp(unsigned int Pdcp_stats_tx[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]); -public_pdcp(unsigned int Pdcp_stats_tx_bytes[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]); -public_pdcp(unsigned int Pdcp_stats_tx_bytes_last[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]); -public_pdcp(unsigned int Pdcp_stats_tx_rate[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]); -public_pdcp(unsigned int Pdcp_stats_rx[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]); -public_pdcp(unsigned int Pdcp_stats_rx_bytes[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]); -public_pdcp(unsigned int Pdcp_stats_rx_bytes_last[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]); -public_pdcp(unsigned int Pdcp_stats_rx_rate[NB_MODULES_MAX][NB_CNX_CH][NB_RAB_MAX]); typedef struct pdcp_stats_s { time_stats_t pdcp_run; @@ -125,6 +151,10 @@ typedef struct pdcp_s { boolean_t is_ue; boolean_t is_srb; + // used for eNB stats generation + uint16_t uid[NUMBER_OF_UE_MAX]; // local to pdcp + rnti_t rnti[NUMBER_OF_UE_MAX]; + /* Configured security algorithms */ uint8_t cipheringAlgorithm; uint8_t integrityProtAlgorithm; From 5e20c970e991ca0854bbf0c0754f4b135c0a8ed9 Mon Sep 17 00:00:00 2001 From: shahab Date: Sat, 9 Dec 2017 17:41:06 +0100 Subject: [PATCH 096/284] warning decreasing --- .../CONTROL_MODULES/PDCP/flexran_agent_pdcp.c | 2 +- .../CONTROL_MODULES/RRC/flexran_agent_rrc.c | 8 +++----- openair2/ENB_APP/flexran_agent_async.c | 4 ++-- openair2/ENB_APP/flexran_agent_common_internal.c | 7 ++----- openair2/ENB_APP/flexran_agent_handler.c | 2 +- openair2/ENB_APP/flexran_agent_net_comm.c | 8 ++++---- openair2/ENB_APP/flexran_agent_ran_api.c | 14 ++++---------- openair2/UTIL/ASYNC_IF/ringbuffer_queue.c | 2 +- openair2/UTIL/ASYNC_IF/ringbuffer_queue.h | 2 +- 9 files changed, 19 insertions(+), 30 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c index ecc40cd89a..4aa2e691b9 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c +++ b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c @@ -77,7 +77,7 @@ int flexran_agent_pdcp_stats_reply(mid_t mod_id, // Protocol__FlexHeader *header; - int i, j, k; + int i; // int cc_id = 0; diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c index e70d2a3d97..587ac8c263 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c @@ -262,11 +262,11 @@ int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg) { /* this is called by RRC as a part of rrc xface . The controller previously requested this*/ void flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t* measResults) { - int i, m, k; + int i; // int priority = 0; // Warning Preventing // void *data; // int size; - err_code_t err_code = -100; + // err_code_t err_code = -100; triggered_rrc = true; int num; @@ -490,9 +490,7 @@ int flexran_agent_rrc_stats_reply(mid_t mod_id, // Protocol__FlexHeader *header; - int i, j, k; - // int cc_id = 0; - int enb_id = mod_id; + int i; /* Allocate memory for list of UE reports */ if (report_config->nr_ue > 0) { diff --git a/openair2/ENB_APP/flexran_agent_async.c b/openair2/ENB_APP/flexran_agent_async.c index 978b44929d..7b7bb89d6c 100644 --- a/openair2/ENB_APP/flexran_agent_async.c +++ b/openair2/ENB_APP/flexran_agent_async.c @@ -68,12 +68,12 @@ flexran_agent_async_channel_t * flexran_agent_async_channel_info(mid_t mod_id, c error: LOG_I(FLEXRAN_AGENT,"there was an error\n"); - return 1; + return NULL; } int flexran_agent_async_msg_send(void *data, int size, int priority, void *channel_info) { flexran_agent_async_channel_t *channel; - channel = (flexran_agent_channel_t *)channel_info; + channel = (flexran_agent_async_channel_t *)channel_info; return message_put(channel->send_queue, data, size, priority); } diff --git a/openair2/ENB_APP/flexran_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c index fca73894c5..839fb4c784 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.c +++ b/openair2/ENB_APP/flexran_agent_common_internal.c @@ -129,10 +129,8 @@ int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy int parse_enb_id(mid_t mod_id, yaml_parser_t *parser) { yaml_event_t event; - void *param; char *endptr; - int is_array = 0; - int i = 0; + // int is_array; int done = 0; int mapping_started = 0; @@ -145,7 +143,7 @@ int parse_enb_id(mid_t mod_id, yaml_parser_t *parser) { switch (event.type) { // We are expecting a mapping of parameters case YAML_SEQUENCE_START_EVENT: - is_array = 1; + // is_array = 1; break; case YAML_MAPPING_START_EVENT: LOG_D(ENB_APP, "The mapping of the parameters started\n"); @@ -193,7 +191,6 @@ int parse_enb_id(mid_t mod_id, yaml_parser_t *parser) { int parse_enb_config_parameters(mid_t mod_id, yaml_parser_t *parser) { yaml_event_t event; - void *param; char *endptr; int done = 0; diff --git a/openair2/ENB_APP/flexran_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c index 6ad0b88975..2a36b3e5c8 100644 --- a/openair2/ENB_APP/flexran_agent_handler.c +++ b/openair2/ENB_APP/flexran_agent_handler.c @@ -30,6 +30,7 @@ #include "flexran_agent_common.h" #include "flexran_agent_mac.h" #include "flexran_agent_rrc.h" +#include "flexran_agent_pdcp.h" #include "flexran_agent_timer.h" #include "flexran_agent_ran_api.h" #include "log.h" @@ -97,7 +98,6 @@ Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id, err_code= PROTOCOL__FLEXRAN_ERR__MSG_DECODING; goto error; } - // printf("==================> %d %d \n", decoded_message->msg_case, decoded_message->msg_dir); if ((decoded_message->msg_case > sizeof(agent_messages_callback) / (3 * sizeof(flexran_agent_message_decoded_callback))) || (decoded_message->msg_dir > PROTOCOL__FLEXRAN_DIRECTION__UNSUCCESSFUL_OUTCOME)){ err_code= PROTOCOL__FLEXRAN_ERR__MSG_NOT_HANDLED; diff --git a/openair2/ENB_APP/flexran_agent_net_comm.c b/openair2/ENB_APP/flexran_agent_net_comm.c index f8e350d6a9..d801bbdda5 100644 --- a/openair2/ENB_APP/flexran_agent_net_comm.c +++ b/openair2/ENB_APP/flexran_agent_net_comm.c @@ -141,9 +141,9 @@ int flexran_agent_destroy_channel(int channel_id) { for (i = 0; i < NUM_MAX_ENB; i++) { for (j = 0; j < FLEXRAN_AGENT_MAX; j++) { if (agent_channel[i][j] != NULL) { - if (agent_channel[i][j]->channel_id == e->channel_id) { - agent_channel[i][j] == NULL; - } + if (agent_channel[i][j]->channel_id == e->channel_id) { + free(agent_channel[i][j]); + } } } } @@ -164,7 +164,7 @@ err_code_t flexran_agent_init_channel_container(void) { for (i = 0; i < NUM_MAX_ENB; i++) { for (j = 0; j < FLEXRAN_AGENT_MAX; j++) { - agent_channel[i][j] == NULL; + agent_channel[i][j] = malloc(sizeof(flexran_agent_channel_t)); } } diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 01f05b1ba5..280b9807fd 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -38,6 +38,7 @@ void * enb[NUM_MAX_ENB]; void * enb_ue[NUM_MAX_ENB]; void * enb_rrc[NUM_MAX_ENB]; +Enb_properties_array_t* enb_properties; void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran){ @@ -47,10 +48,12 @@ void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran){ enb[mod_id] = NULL; enb_ue[mod_id] = NULL; enb_rrc[mod_id] = NULL; + enb_properties = NULL; }else{ enb[mod_id] = (void *)&eNB_mac_inst[mod_id]; enb_ue[mod_id] = (void *)&eNB_mac_inst[mod_id].UE_list; enb_rrc[mod_id] = (void *)&eNB_rrc_inst[mod_id]; + enb_properties = (Enb_properties_array_t *) enb_config_get(); } break; default : @@ -1039,52 +1042,43 @@ int flexran_get_antenna_ports(mid_t mod_id, int CC_id){ uint32_t flexran_agent_get_operating_dl_freq (mid_t mod_id, int cc_id) { - const Enb_properties_array_t* enb_properties = enb_config_get(); + return (enb_properties->properties[mod_id]->downlink_frequency[cc_id] / 1000000); } uint32_t flexran_agent_get_operating_ul_freq (mid_t mod_id, int cc_id) { - const Enb_properties_array_t* enb_properties = enb_config_get(); return ((enb_properties->properties[mod_id]->downlink_frequency[cc_id] + enb_properties->properties[0]->uplink_frequency_offset[cc_id]) / 1000000); } int flexran_agent_get_operating_eutra_band (mid_t mod_id, int cc_id) { - const Enb_properties_array_t* enb_properties = enb_config_get(); return enb_properties->properties[mod_id]->eutra_band[cc_id]; } int flexran_agent_get_operating_pdsch_refpower (mid_t mod_id, int cc_id) { - const Enb_properties_array_t* enb_properties = enb_config_get(); return enb_properties->properties[mod_id]->pdsch_referenceSignalPower[cc_id]; } int flexran_agent_get_operating_pusch_p0 (mid_t mod_id, int cc_id) { - const Enb_properties_array_t* enb_properties = enb_config_get(); return enb_properties->properties[mod_id]->pusch_p0_Nominal[cc_id]; } void flexran_agent_set_operating_dl_freq (mid_t mod_id, int cc_id, uint32_t dl_freq_mhz) { - Enb_properties_array_t* enb_properties = enb_config_get(); enb_properties->properties[mod_id]->downlink_frequency[cc_id]=dl_freq_mhz * 1000000; /*printf("[ENB_APP] mod id %d ccid %d dl freq %d/%d\n", mod_id, cc_id, dl_freq_mhz, enb_properties->properties[mod_id]->downlink_frequency[cc_id]); */ } void flexran_agent_set_operating_ul_freq (mid_t mod_id, int cc_id, int32_t ul_freq_offset_mhz) { - Enb_properties_array_t* enb_properties = enb_config_get(); enb_properties->properties[mod_id]->uplink_frequency_offset[cc_id]=ul_freq_offset_mhz * 1000000; } //TBD void flexran_agent_set_operating_eutra_band (mid_t mod_id, int cc_id) { - Enb_properties_array_t* enb_properties = enb_config_get(); enb_properties->properties[mod_id]->eutra_band[cc_id]=7; } void flexran_agent_set_operating_bandwidth (mid_t mod_id, int cc_id, int bandwidth) { - Enb_properties_array_t* enb_properties = enb_config_get(); enb_properties->properties[mod_id]->N_RB_DL[cc_id]=bandwidth; } void flexran_agent_set_operating_frame_type (mid_t mod_id, int cc_id, int frame_type) { - Enb_properties_array_t* enb_properties = enb_config_get(); enb_properties->properties[mod_id]->frame_type[cc_id]=frame_type; } diff --git a/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c index 047e3f716c..0c4bb1dfbb 100644 --- a/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c +++ b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c @@ -117,7 +117,7 @@ int message_get(message_queue_t *queue, void **data, int *size, int *priority) { return 0; } -message_queue_t destroy_message_queue(message_queue_t *queue) { +void destroy_message_queue(message_queue_t *queue) { struct lfds700_misc_prng_state ls; message_t *m; diff --git a/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h index 7dc4637404..bdc5adce99 100644 --- a/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h +++ b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h @@ -48,6 +48,6 @@ typedef struct { message_queue_t * new_message_queue(int size); int message_put(message_queue_t *queue, void *data, int size, int priority); int message_get(message_queue_t *queue, void **data, int *size, int *priority); -message_queue_t destroy_message_queue(message_queue_t *queue); +void destroy_message_queue(message_queue_t *queue); #endif /* RINGBUFFER_QUEUE_H */ From cd74f4d61b20cfacb71a10cea80ba24f6ad85626 Mon Sep 17 00:00:00 2001 From: shahab SHARIAT BAGHERI Date: Sun, 10 Dec 2017 16:19:27 +0100 Subject: [PATCH 097/284] Message balance --- .../ENB_APP/MESSAGES/V2/config_messages.proto | 2 +- .../MESSAGES/V2/control_delegation.proto | 2 +- .../MESSAGES/V2/controller_commands.proto | 8 +- openair2/ENB_APP/MESSAGES/V2/flexran.proto | 22 +--- openair2/ENB_APP/MESSAGES/V2/header.proto | 3 +- .../ENB_APP/MESSAGES/V2/mac_primitives.proto | 37 ------ .../ENB_APP/MESSAGES/V2/stats_common.proto | 106 +++++++++--------- .../ENB_APP/MESSAGES/V2/stats_messages.proto | 12 +- .../ENB_APP/MESSAGES/V2/time_common.proto | 4 +- openair2/ENB_APP/flexran_agent_common.c | 8 -- 10 files changed, 70 insertions(+), 134 deletions(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto index 657f362873..995865f1ab 100644 --- a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto +++ b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto @@ -38,7 +38,7 @@ message flex_cell_config { optional uint32 srs_mac_up_pts = 32; // Boolean value. See TS 36.211, section 5.5.3.2. TDD only optional uint32 enable_64QAM = 33; // One of the FLEQ_* enum values optional uint32 carrier_index = 34; // Carrier component index - optional uint32 dl_freq = 35; // operating downlink frequency + optional uint32 dl_freq = 35; // operating downlink frequency optional uint32 ul_freq = 36; // operating uplink frequency optional uint32 eutra_band= 37; // operating band optional int32 dl_pdsch_power = 38; // operating downlink power diff --git a/openair2/ENB_APP/MESSAGES/V2/control_delegation.proto b/openair2/ENB_APP/MESSAGES/V2/control_delegation.proto index 0f7e34de15..ef0eea3bd2 100644 --- a/openair2/ENB_APP/MESSAGES/V2/control_delegation.proto +++ b/openair2/ENB_APP/MESSAGES/V2/control_delegation.proto @@ -3,4 +3,4 @@ package protocol; enum flex_control_delegation_type { FLCDT_MAC_DL_UE_SCHEDULER = 1; // DL UE scheduler delegation -} \ No newline at end of file +} diff --git a/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto b/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto index eeda90b8cb..6f30ea4755 100644 --- a/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto +++ b/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto @@ -4,7 +4,7 @@ package protocol; import "mac_primitives.proto"; // -// Body of UE DL/UL MAC scheduling configuration info +// Body of UE DL MAC scheduling configuration info // message flex_dl_data { @@ -16,12 +16,6 @@ message flex_dl_data { optional uint32 act_deact_ce = 6; //Hex content of MAC CE for Activation/Deactivation in CA } - -message flex_ul_data { - optional uint32 rnti = 1; - optional flex_ul_dci ul_dci = 2; -} - // // Body of the RAR scheduler configuration // diff --git a/openair2/ENB_APP/MESSAGES/V2/flexran.proto b/openair2/ENB_APP/MESSAGES/V2/flexran.proto index 18eb760cc3..45a139b73a 100644 --- a/openair2/ENB_APP/MESSAGES/V2/flexran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/flexran.proto @@ -8,6 +8,7 @@ import "config_messages.proto"; import "controller_commands.proto"; import "control_delegation.proto"; + message flexran_message { optional flexran_direction msg_dir = 100; oneof msg { @@ -24,12 +25,11 @@ message flexran_message { flex_ue_config_reply ue_config_reply_msg = 11; flex_lc_config_request lc_config_request_msg = 12; flex_lc_config_reply lc_config_reply_msg = 13; - flex_dl_mac_config dl_mac_config_msg = 14; + flex_dl_mac_config dl_mac_config_msg = 14; flex_ue_state_change ue_state_change_msg = 15; flex_control_delegation control_delegation_msg = 16; flex_agent_reconfiguration agent_reconfiguration_msg = 17; flex_rrc_triggering rrc_triggering = 18; - flex_ul_mac_config ul_mac_config_msg = 19; } } @@ -166,22 +166,6 @@ message flex_dl_mac_config { repeated flex_pdcch_ofdm_sym_count ofdm_sym = 6; // OFDM symbol count for each CC } - -message flex_ul_mac_config { - optional flex_header header = 1; - optional uint32 sfn_sf = 2; - repeated flex_ul_data ul_ue_data = 3; -} - - -message flex_rrc_triggering { - - optional flex_header header = 1; - optional string rrc_trigger = 2; -} - - - // // UE state change message // @@ -209,7 +193,7 @@ message flex_control_delegation { message flex_agent_reconfiguration { optional flex_header header = 1; - optional string policy = 2; // The policy changes using YAML syntax in string format + optional string policy = 2; // The policy changes using YAML syntax in string format } // Extensions of the echo request and reply diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index 4f03e0755e..12110de24e 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -33,7 +33,7 @@ enum flex_type { //Controller command messages FLPT_DL_MAC_CONFIG = 13; - + // UE state change messages FLPT_UE_STATE_CHANGE = 14; @@ -41,6 +41,5 @@ enum flex_type { FLPT_DELEGATE_CONTROL = 15; FLPT_RECONFIGURE_AGENT = 16; FLPT_RRC_TRIGGERING = 17; - FLPT_UL_MAC_CONFIG = 18; } diff --git a/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto b/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto index a34e9b6eaf..d3acb51318 100644 --- a/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto +++ b/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto @@ -36,37 +36,6 @@ message flex_dl_dci { optional uint32 cif = 27; // CIF for cross-carrier scheduling } -message flex_ul_dci { - optional uint32 rnti = 1; - optional uint32 rb_start = 2; // The start RB allocated to the UE - optional uint32 rb_len = 3; // The number of RBs allocated to the UE - optional uint32 mcs = 4; // Modulation and coding scheme - optional uint32 cyclic_shift2 = 5; // match DCI format 0/4 PDU - optional uint32 freq_hop_flag = 6; // 0 no hopping, 1 hoppping - optional uint32 freq_hop_map = 7; // Frequency hopping bits (0..4) - optional uint32 ndi = 8; // New data indicator - optional uint32 rv = 9; // Redundancy version - optional uint32 harq_pid = 10; // The harq process id - optional uint32 ultx_mode = 11; // A FLULM_* value - optional uint32 tbs_size = 12; // The size of each TBS - optional uint32 n_srs = 13; // Overlap indication with srs - optional uint32 res_alloc = 14; // Type of resource allocation - optional uint32 size = 15; // Size of the ULSCH PDU in bytes for UL Grant. - - optional uint32 dai = 16; // TDD only - -// optional uint32 tb_swap = 17; // Boolean. TB to codeword swap flag - -// optional uint32 pdcch_order = 19; -// optional uint32 preamble_index = 20; // Only valid if pdcch_order = 1 -// optional uint32 prach_mask_index = 21; // Only valid if pdcch_order = 1 - -// optional uint32 tbs_idx = 23; // The TBS index for Format 1A - - - - -} // // Messages related to the creation of RLC PDUs @@ -107,9 +76,3 @@ enum flex_ngap_val { FLNGV_1 = 0; FLNGV_2 = 1; } - -enum flex_mod_type { - FLMOD_QPSK = 2; - FLMOD_16QAM = 4; - FLMOD_64QAM = 6; -} diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto index a7d78841a3..35550c3733 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto @@ -183,83 +183,87 @@ message flex_noise_interference_report { } // -// RRC Primitives +// RRC Measurements Primitives // + + message flex_rrc_measurements { - // Measurement identifier. - optional int32 measid = 1; - // Primary Cell Reference Signal Received Power (RSRP). - optional int32 pcell_rsrp = 2; - // Primary Cell Reference Signal Received Quality (RSRQ). - optional int32 pcell_rsrq = 3; - // Neighboring cells measurements performed by UE. - optional flex_neigh_cells_measurements neigh_meas = 4; + // Measurement identifier. + optional int32 measid = 1; + // Primary Cell Reference Signal Received Power (RSRP). + optional int32 pcell_rsrp = 2; + // Primary Cell Reference Signal Received Quality (RSRQ). + optional int32 pcell_rsrq = 3; + // Neighboring cells measurements performed by UE. + optional flex_neigh_cells_measurements neigh_meas = 4; } message flex_neigh_cells_measurements { - // Neighboring EUTRA cells measurements. - repeated flex_eutra_measurements eutra_meas = 1; + // Neighboring EUTRA cells measurements. + repeated flex_eutra_measurements eutra_meas = 1; } message flex_eutra_measurements { - // Physical Cell identifier. - optional int32 phys_cell_id = 1; - // EUTRA Cell Global Identity (CGI) measurement. - optional flex_eutra_cgi_measurements cgi_meas = 2; - // EUTRA nearby cell reference signal measurement. - optional flex_eutra_ref_signal_meas meas_result = 3; + // Physical Cell identifier. + optional int32 phys_cell_id = 1; + // EUTRA Cell Global Identity (CGI) measurement. + optional flex_eutra_cgi_measurements cgi_meas = 2; + // EUTRA nearby cell reference signal measurement. + optional flex_eutra_ref_signal_meas meas_result = 3; } message flex_eutra_cgi_measurements { - // EUTRA Cell Global Identity (CGI). - optional flex_cell_global_eutra_id cgi = 1; - // Tracking area code of the neighbor cell. - optional uint32 tracking_area_code = 2; - // Public land mobile network identifiers of neighbor cell. - repeated flex_plmn_identity plmn_id = 3; + // EUTRA Cell Global Identity (CGI). + optional flex_cell_global_eutra_id cgi = 1; + // Tracking area code of the neighbor cell. + optional uint32 tracking_area_code = 2; + // Public land mobile network identifiers of neighbor cell. + repeated flex_plmn_identity plmn_id = 3; } message flex_cell_global_eutra_id { - // Public land mobile network identifier of neighbor cell. - optional flex_plmn_identity plmn_id = 1; - // Cell identifier of neighbor cell. - optional uint32 cell_id = 2; + // Public land mobile network identifier of neighbor cell. + optional flex_plmn_identity plmn_id = 1; + // Cell identifier of neighbor cell. + optional uint32 cell_id = 2; } message flex_plmn_identity { - // Mobile Network Code (MNC). - repeated uint32 mnc = 1; - // Mobile Country Code (MCC). - repeated uint32 mcc = 2; - // tracking area code - repeated uint32 tac = 3; -} + // Mobile Network Code (MNC). + repeated uint32 mnc = 1; + // Mobile Country Code (MCC). + repeated uint32 mcc = 2; + // tracking area code + repeated uint32 tac = 3; +} message flex_eutra_ref_signal_meas { - // Neighboring Cell Reference Signal Received Power (RSRP). - optional int32 rsrp = 1; - // Neighboring Cell Reference Signal Received Quality (RSRQ). - optional int32 rsrq = 2; - + // Neighboring Cell RSRP + optional int32 rsrp = 1; + // Neighboring Cell RSRQ + optional int32 rsrq = 2; } +// +// PDCP Statistics +// + message flex_pdcp_stats { - optional uint32 pkt_tx = 1; - optional uint32 pkt_tx_bytes = 2; - optional uint32 pkt_tx_sn = 3; - optional uint32 pkt_tx_rate_s = 4; + optional uint32 pkt_tx = 1; + optional uint32 pkt_tx_bytes = 2; + optional uint32 pkt_tx_sn = 3; + optional uint32 pkt_tx_rate_s = 4; optional uint32 pkt_tx_throughput_s = 5; - optional uint32 pkt_tx_aiat = 7; + optional uint32 pkt_tx_aiat = 7; optional uint32 pkt_tx_aiat_s = 8; optional uint32 pkt_rx = 9; - optional uint32 pkt_rx_bytes = 10; - optional uint32 pkt_rx_sn = 11; - optional uint32 pkt_rx_rate_s = 12; + optional uint32 pkt_rx_bytes = 10; + optional uint32 pkt_rx_sn = 11; + optional uint32 pkt_rx_rate_s = 12; optional uint32 pkt_rx_goodput_s = 13; - optional uint32 pkt_rx_aiat = 14; + optional uint32 pkt_rx_aiat = 14; optional uint32 pkt_rx_aiat_s = 15; - optional uint32 pkt_rx_oo = 16; - } - + optional uint32 pkt_rx_oo = 16; +} diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto index 8cad6f4fbe..b8126c55f2 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto @@ -47,8 +47,8 @@ message flex_ue_stats_report { optional flex_dl_cqi_report dl_cqi_report = 7; optional flex_paging_buffer_report pbr = 8; optional flex_ul_cqi_report ul_cqi_report = 9; - optional flex_rrc_measurements rrc_measurements = 10; - optional flex_pdcp_stats pdcp_stats = 11; + optional flex_rrc_measurements rrc_measurements = 10; + optional flex_pdcp_stats pdcp_stats = 11; } // @@ -85,9 +85,9 @@ enum flex_ue_stats_type { FLUST_DL_CQI = 16; FLUST_PBS = 32; FLUST_UL_CQI = 64; - - FLUST_PDCP_STATS = 1024; // To be changed - // To be extended with more types of stats + + FLUST_PDCP_STATS = 1024; FLUST_RRC_MEASUREMENTS = 65536; - + // To be extended with more types of stats + } diff --git a/openair2/ENB_APP/MESSAGES/V2/time_common.proto b/openair2/ENB_APP/MESSAGES/V2/time_common.proto index baf0c0e9ae..6c0affbe51 100644 --- a/openair2/ENB_APP/MESSAGES/V2/time_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/time_common.proto @@ -25,7 +25,7 @@ message flex_ul_info { repeated uint32 ul_reception = 2; optional uint32 reception_status = 3; optional uint32 tpc = 4; - optional uint32 serv_cell_index = 5; - optional uint32 rssi = 6; + optional uint32 serv_cell_index = 5; + optional uint32 rssi = 6; } diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index e56ebdfd22..386dd18f1e 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -387,7 +387,6 @@ int flexran_agent_control_delegation(mid_t mod_id, const void *params, Protocol_ Protocol__FlexControlDelegation *control_delegation_msg = input->control_delegation_msg; // struct timespec vartime = timer_start(); - int status; //Write the payload lib into a file in the cache and load the lib char lib_name[120]; char target[512]; @@ -395,13 +394,6 @@ int flexran_agent_control_delegation(mid_t mod_id, const void *params, Protocol_ strcpy(target, local_cache); strcat(target, lib_name); - status = mkdir(local_cache, S_IRWXU | S_IRWXG | S_IRWXO); - - if (status < 0){ - - LOG_W(ENB_APP, "Couldn't create local cache!"); - } - FILE *f; f = fopen(target, "wb"); fwrite(control_delegation_msg->payload.data, control_delegation_msg->payload.len, 1, f); From acd996d2eb555248afefe5cd17fbb0c931e0b3e6 Mon Sep 17 00:00:00 2001 From: shahab Date: Sun, 10 Dec 2017 18:23:21 +0100 Subject: [PATCH 098/284] ul proto msg --- .../MESSAGES/V2/controller_commands.proto | 6 ++++ openair2/ENB_APP/MESSAGES/V2/flexran.proto | 13 ++++++++ openair2/ENB_APP/MESSAGES/V2/header.proto | 1 + .../ENB_APP/MESSAGES/V2/mac_primitives.proto | 32 +++++++++++++++++++ 4 files changed, 52 insertions(+) diff --git a/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto b/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto index 6f30ea4755..29e0723835 100644 --- a/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto +++ b/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto @@ -16,6 +16,12 @@ message flex_dl_data { optional uint32 act_deact_ce = 6; //Hex content of MAC CE for Activation/Deactivation in CA } + +message flex_ul_data { + optional uint32 rnti = 1; + optional flex_ul_dci ul_dci = 2; +} + // // Body of the RAR scheduler configuration // diff --git a/openair2/ENB_APP/MESSAGES/V2/flexran.proto b/openair2/ENB_APP/MESSAGES/V2/flexran.proto index 45a139b73a..b54fc171c6 100644 --- a/openair2/ENB_APP/MESSAGES/V2/flexran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/flexran.proto @@ -30,6 +30,7 @@ message flexran_message { flex_control_delegation control_delegation_msg = 16; flex_agent_reconfiguration agent_reconfiguration_msg = 17; flex_rrc_triggering rrc_triggering = 18; + flex_ul_mac_config ul_mac_config_msg = 19; } } @@ -166,6 +167,18 @@ message flex_dl_mac_config { repeated flex_pdcch_ofdm_sym_count ofdm_sym = 6; // OFDM symbol count for each CC } +message flex_ul_mac_config { + optional flex_header header = 1; + optional uint32 sfn_sf = 2; + repeated flex_ul_data ul_ue_data = 3; +} + +message flex_rrc_triggering { + + optional flex_header header = 1; + optional string rrc_trigger = 2; +} + // // UE state change message // diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index 12110de24e..8900b93492 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -41,5 +41,6 @@ enum flex_type { FLPT_DELEGATE_CONTROL = 15; FLPT_RECONFIGURE_AGENT = 16; FLPT_RRC_TRIGGERING = 17; + FLPT_UL_MAC_CONFIG = 18; } diff --git a/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto b/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto index d3acb51318..bd2b9cbe50 100644 --- a/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto +++ b/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto @@ -34,6 +34,38 @@ message flex_dl_dci { optional uint32 pdcch_power_offset = 25; // DL PDCCH power boosting in dB optional uint32 cif_present = 26; // Boolean. Indication of CIF field optional uint32 cif = 27; // CIF for cross-carrier scheduling +} + +message flex_ul_dci { + optional uint32 rnti = 1; + optional uint32 rb_start = 2; // The start RB allocated to the UE + optional uint32 rb_len = 3; // The number of RBs allocated to the UE + optional uint32 mcs = 4; // Modulation and coding scheme + optional uint32 cyclic_shift2 = 5; // match DCI format 0/4 PDU + optional uint32 freq_hop_flag = 6; // 0 no hopping, 1 hoppping + optional uint32 freq_hop_map = 7; // Frequency hopping bits (0..4) + optional uint32 ndi = 8; // New data indicator + optional uint32 rv = 9; // Redundancy version + optional uint32 harq_pid = 10; // The harq process id + optional uint32 ultx_mode = 11; // A FLULM_* value + optional uint32 tbs_size = 12; // The size of each TBS + optional uint32 n_srs = 13; // Overlap indication with srs + optional uint32 res_alloc = 14; // Type of resource allocation + optional uint32 size = 15; // Size of the ULSCH PDU in bytes for UL Grant. + + optional uint32 dai = 16; // TDD only + +// optional uint32 tb_swap = 17; // Boolean. TB to codeword swap flag + +// optional uint32 pdcch_order = 19; +// optional uint32 preamble_index = 20; // Only valid if pdcch_order = 1 +// optional uint32 prach_mask_index = 21; // Only valid if pdcch_order = 1 + +// optional uint32 tbs_idx = 23; // The TBS index for Format 1A + + + + } From 9601ea66c5f1aa709cccbe4da4627458932a1a66 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Mon, 11 Dec 2017 16:46:22 +0100 Subject: [PATCH 099/284] Update PDCP stats --- openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 139 +++++++++++++++------------- openair2/LAYER2/PDCP_v10.1.0/pdcp.h | 2 + 2 files changed, 78 insertions(+), 63 deletions(-) diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 397a194edf..fb4cc0c526 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -409,7 +409,9 @@ boolean_t pdcp_data_req( //LOG_I(PDCP,"ueid %d lcid %d tx seq num %d\n", pdcp_uid, rb_idP+rb_offset, current_sn); Pdcp_stats_tx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; Pdcp_stats_tx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; + Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; Pdcp_stats_tx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=current_sn; if (Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset] < pdcp_frame *10 + pdcp_subframe) { @@ -421,22 +423,8 @@ boolean_t pdcp_data_req( Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (1024 + pdcp_frame *10 + pdcp_subframe - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); } - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=ctxt_pP->frame*10+ctxt_pP->subframe; - if (pdcp_frame % 100 == 0 ) { - Pdcp_stats_tx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]= Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]; - Pdcp_stats_tx_throughput_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_stats_tx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]*8/1000; - Pdcp_stats_tx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]; - - Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0; - Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0; - Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0; - }else { - Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; - - } @@ -828,53 +816,43 @@ pdcp_data_ind( packet_forwarded = TRUE; /* Print octets of incoming data in hexadecimal form */ - LOG_D(PDCP, "Following content has been received from RLC (%d,%d)(PDCP header has already been removed):\n", - sdu_buffer_sizeP - payload_offset + (int)sizeof(pdcp_data_ind_header_t), - sdu_buffer_sizeP - payload_offset); - //util_print_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); - //util_flush_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); - - /* - * Update PDCP statistics - * XXX Following two actions are identical, is there a merge error? - */ - - for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){ - if (pdcp_p->rnti[pdcp_uid] == ctxt_pP->rnti ) - break; - } - - Pdcp_stats_rx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - Pdcp_stats_rx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP - payload_offset; - - Pdcp_stats_rx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=sequence_number; - - if (oo_flag == 1 ) - Pdcp_stats_rx_outoforder[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - - if (Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset] < pdcp_frame * 10 + pdcp_subframe) { - Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_frame *10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(pdcp_frame *10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - } else { - Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (1024 +pdcp_frame * 10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(1024 +pdcp_frame * 10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - } - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_frame * 10 +pdcp_subframe; - - if (pdcp_frame % 102 == 0) { - Pdcp_stats_rx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]; - Pdcp_stats_rx_goodput_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]*8/1023; - Pdcp_stats_rx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]= Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]; - - Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0; - Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0; - Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=0; - }else { - Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); - } + LOG_D(PDCP, "Following content has been received from RLC (%d,%d)(PDCP header has already been removed):\n", + sdu_buffer_sizeP - payload_offset + (int)sizeof(pdcp_data_ind_header_t), + sdu_buffer_sizeP - payload_offset); + //util_print_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); + //util_flush_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); + + /* + * Update PDCP statistics + * XXX Following two actions are identical, is there a merge error? + */ + + for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){ + if (pdcp_p->rnti[pdcp_uid] == ctxt_pP->rnti ) + break; + } + + Pdcp_stats_rx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_rx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); + Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); + + Pdcp_stats_rx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=sequence_number; + + if (oo_flag == 1 ) + Pdcp_stats_rx_outoforder[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + + if (Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset] < pdcp_frame * 10 + pdcp_subframe) { + Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_frame *10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(pdcp_frame *10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + } else { + Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (1024 +pdcp_frame * 10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(1024 +pdcp_frame * 10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + } + Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_frame * 10 +pdcp_subframe; + } - + #else packet_forwarded = FALSE; #endif @@ -951,6 +929,38 @@ pdcp_data_ind( return TRUE; } +void pdcp_update_stats(const protocol_ctxt_t* const ctxt_pP){ + + uint8_t pdcp_uid = 0; + uint8_t rb_id = 0; + + // these stats can be measured for both eNB and UE + if ((pdcp_frame % 102 == 0) && (pdcp_subframe ==0)) { + for (rb_id =0; rb_id < NB_RB_MAX; rb_id ++){ + for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){ + //printf("frame %d and subframe %d \n", pdcp_frame, pdcp_subframe); + // tx stats + Pdcp_stats_tx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]; + Pdcp_stats_tx_throughput_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_tx_bytes[ctxt_pP->module_id][pdcp_uid][rb_id]*8/1024; + Pdcp_stats_tx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]; + + Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + + // rx stats + Pdcp_stats_rx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id]; + Pdcp_stats_rx_goodput_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]*8/1024; + Pdcp_stats_rx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]; + + Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + + } + } + } +} //----------------------------------------------------------------------------- void pdcp_run ( @@ -958,9 +968,7 @@ pdcp_run ( ) //----------------------------------------------------------------------------- { - - pdcp_frame =ctxt_pP->frame; - pdcp_subframe= ctxt_pP->subframe; + #if defined(ENABLE_ITTI) MessageDef *msg_p; const char *msg_name; @@ -969,12 +977,17 @@ pdcp_run ( protocol_ctxt_t ctxt; #endif + if (ctxt_pP->enb_flag) { start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_run); } else { start_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_run); } + pdcp_frame =ctxt_pP->frame; // 1023 + pdcp_subframe= ctxt_pP->subframe; + pdcp_update_stats(ctxt_pP); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_IN); #if defined(ENABLE_ITTI) diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h index fb3e02b299..2f1d15ad5e 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h @@ -124,6 +124,8 @@ public_pdcp(uint32_t Pdcp_stats_rx_aiat_tmp_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_ public_pdcp(uint32_t Pdcp_stats_rx_iat[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); public_pdcp(uint32_t Pdcp_stats_rx_outoforder[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(void pdcp_update_perioidical_stats(const protocol_ctxt_t* const ctxt_pP)); + /*Packet Probing for agent PDCP*/ //public_pdcp(uint64_t *pdcp_packet_counter); From 38627c85d063073ae6e88a56d2ec6690a1e5f8c1 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Tue, 12 Dec 2017 10:14:30 +0100 Subject: [PATCH 100/284] Minor fix in the PDCP stats update --- openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index fb4cc0c526..7262d6b8d2 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -941,7 +941,8 @@ void pdcp_update_stats(const protocol_ctxt_t* const ctxt_pP){ //printf("frame %d and subframe %d \n", pdcp_frame, pdcp_subframe); // tx stats Pdcp_stats_tx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]; - Pdcp_stats_tx_throughput_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_tx_bytes[ctxt_pP->module_id][pdcp_uid][rb_id]*8/1024; + // unit: bit/s + Pdcp_stats_tx_throughput_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]*8; Pdcp_stats_tx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]; Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; @@ -950,7 +951,7 @@ void pdcp_update_stats(const protocol_ctxt_t* const ctxt_pP){ // rx stats Pdcp_stats_rx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id]; - Pdcp_stats_rx_goodput_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]*8/1024; + Pdcp_stats_rx_goodput_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]*8; Pdcp_stats_rx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]; Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; From b7a1661855f440ac624a9bf78a544dbba2f573b4 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Tue, 12 Dec 2017 11:57:24 +0100 Subject: [PATCH 101/284] Better management of frame counter and stats in PDCP --- .../CONTROL_MODULES/PDCP/flexran_agent_pdcp.c | 5 +- .../ENB_APP/MESSAGES/V2/stats_common.proto | 2 + openair2/ENB_APP/flexran_agent_ran_api.c | 4 + openair2/ENB_APP/flexran_agent_ran_api.h | 3 + openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 127 ++++++++---------- openair2/LAYER2/PDCP_v10.1.0/pdcp.h | 7 +- 6 files changed, 76 insertions(+), 72 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c index 4aa2e691b9..e4cc520070 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c +++ b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c @@ -21,7 +21,7 @@ /*! \file flexran_agent_pdcp.c * \brief FlexRAN agent Control Module PDCP - * \author shahab SHARIAT BAGHERI + * \author Navid Nikaein and shahab SHARIAT BAGHERI * \date 2017 * \version 0.1 */ @@ -118,6 +118,9 @@ int flexran_agent_pdcp_stats_reply(mid_t mod_id, pdcp_aggr_stats->pkt_rx_sn = flexran_get_pdcp_rx_sn(mod_id, i, DEFAULT_DRB); pdcp_aggr_stats->has_pkt_rx_sn =1; + pdcp_aggr_stats->sfn = flexran_get_pdcp_sfn(mod_id); + pdcp_aggr_stats->has_sfn =1; + ue_report[i]->pdcp_stats = pdcp_aggr_stats; } diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto index 35550c3733..94da9fbd04 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto @@ -266,4 +266,6 @@ message flex_pdcp_stats { optional uint32 pkt_rx_aiat = 14; optional uint32 pkt_rx_aiat_s = 15; optional uint32 pkt_rx_oo = 16; + + optional uint64 sfn=17; } diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 280b9807fd..7a4522e870 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -1083,6 +1083,10 @@ void flexran_agent_set_operating_frame_type (mid_t mod_id, int cc_id, int frame_ } /*********** PDCP *************/ +/*PDCP num tx pdu status flexRAN*/ +uint32_t flexran_get_pdcp_sfn(const mid_t mod_id){ + return Pdcp_sfn[mod_id]; +} /*PDCP num tx pdu status flexRAN*/ uint32_t flexran_get_pdcp_tx(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 4d84251608..bb9592399e 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -342,6 +342,9 @@ int flexran_get_rrc_status(const mid_t mod_id, const rnti_t rntiP); /***************************** PDCP ***********************/ +/*PDCP superframe numberflexRAN*/ +uint32_t flexran_get_pdcp_sfn(const mid_t mod_id); + /*PDCP num tx pdu status flexRAN*/ uint32_t flexran_get_pdcp_tx(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 7262d6b8d2..c561043f4a 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -414,20 +414,10 @@ boolean_t pdcp_data_req( Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; Pdcp_stats_tx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=current_sn; - if (Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset] < pdcp_frame *10 + pdcp_subframe) { - Pdcp_stats_tx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_frame *10 + pdcp_subframe - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_frame *10 + pdcp_subframe - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - } - else { - Pdcp_stats_tx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (1024 + pdcp_frame *10 + pdcp_subframe - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (1024 + pdcp_frame *10 + pdcp_subframe - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - } - - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=ctxt_pP->frame*10+ctxt_pP->subframe; - - - - + Pdcp_stats_tx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (Pdcp_sfn[ctxt_pP->module_id] - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (Pdcp_sfn[ctxt_pP->module_id] - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_sfn[ctxt_pP->module_id]; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); return ret; @@ -813,44 +803,7 @@ pdcp_data_ind( GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).rnti = ctxt_pP->rnti; GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).rab_id = rb_id + 4; itti_send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p); - packet_forwarded = TRUE; - - /* Print octets of incoming data in hexadecimal form */ - LOG_D(PDCP, "Following content has been received from RLC (%d,%d)(PDCP header has already been removed):\n", - sdu_buffer_sizeP - payload_offset + (int)sizeof(pdcp_data_ind_header_t), - sdu_buffer_sizeP - payload_offset); - //util_print_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); - //util_flush_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); - - /* - * Update PDCP statistics - * XXX Following two actions are identical, is there a merge error? - */ - - for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){ - if (pdcp_p->rnti[pdcp_uid] == ctxt_pP->rnti ) - break; - } - - Pdcp_stats_rx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - Pdcp_stats_rx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); - Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); - - Pdcp_stats_rx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=sequence_number; - - if (oo_flag == 1 ) - Pdcp_stats_rx_outoforder[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - - if (Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset] < pdcp_frame * 10 + pdcp_subframe) { - Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_frame *10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(pdcp_frame *10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - } else { - Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (1024 +pdcp_frame * 10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(1024 +pdcp_frame * 10 + pdcp_subframe - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - } - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_frame * 10 +pdcp_subframe; - + packet_forwarded = TRUE; } #else @@ -909,6 +862,38 @@ pdcp_data_ind( } } + /* Print octets of incoming data in hexadecimal form */ + LOG_D(PDCP, "Following content has been received from RLC (%d,%d)(PDCP header has already been removed):\n", + sdu_buffer_sizeP - payload_offset + (int)sizeof(pdcp_data_ind_header_t), + sdu_buffer_sizeP - payload_offset); + //util_print_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); + //util_flush_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); + + /* + * Update PDCP statistics + * XXX Following two actions are identical, is there a merge error? + */ + + for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){ + if (pdcp_p->rnti[pdcp_uid] == ctxt_pP->rnti ) + break; + } + + Pdcp_stats_rx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_rx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); + Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); + + Pdcp_stats_rx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=sequence_number; + + if (oo_flag == 1 ) + Pdcp_stats_rx_outoforder[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + + Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (Pdcp_sfn[ctxt_pP->module_id] - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(Pdcp_sfn[ctxt_pP->module_id] - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_sfn[ctxt_pP->module_id]; + + #if defined(STOP_ON_IP_TRAFFIC_OVERLOAD) else { AssertFatal(0, PROTOCOL_PDCP_CTXT_FMT" PDCP_DATA_IND SDU DROPPED, OUT OF MEMORY \n", @@ -934,16 +919,16 @@ void pdcp_update_stats(const protocol_ctxt_t* const ctxt_pP){ uint8_t pdcp_uid = 0; uint8_t rb_id = 0; - // these stats can be measured for both eNB and UE - if ((pdcp_frame % 102 == 0) && (pdcp_subframe ==0)) { + // these stats are measured for both eNB and UE on per seond basis + if (Pdcp_sfn[ctxt_pP->module_id] % 1000 == 0){ for (rb_id =0; rb_id < NB_RB_MAX; rb_id ++){ for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){ - //printf("frame %d and subframe %d \n", pdcp_frame, pdcp_subframe); + //printf("frame %d and subframe %d \n", Pdcp_frame[ctxt_pP->module_id], Pdcp_subframe[ctxt_pP->module_id]); // tx stats Pdcp_stats_tx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]; // unit: bit/s Pdcp_stats_tx_throughput_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]*8; - Pdcp_stats_tx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]; + Pdcp_stats_tx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_id]=(uint32_t)(Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]); Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; @@ -952,7 +937,7 @@ void pdcp_update_stats(const protocol_ctxt_t* const ctxt_pP){ // rx stats Pdcp_stats_rx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id]; Pdcp_stats_rx_goodput_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]*8; - Pdcp_stats_rx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]; + Pdcp_stats_rx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_id]= (uint32_t)(Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id]); Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; @@ -985,8 +970,9 @@ pdcp_run ( start_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_run); } - pdcp_frame =ctxt_pP->frame; // 1023 - pdcp_subframe= ctxt_pP->subframe; + Pdcp_sfn[ctxt_pP->module_id]++; // range: 0 to 18,446,744,073,709,551,615 + Pdcp_frame[ctxt_pP->module_id]=ctxt_pP->frame; // 1023 + Pdcp_subframe[ctxt_pP->module_id]= ctxt_pP->subframe; pdcp_update_stats(ctxt_pP); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_IN); @@ -1564,9 +1550,9 @@ pdcp_config_req_asn1 ( if (pdcp_pP->rnti[i] != 0 ) continue ; // skip active ues pdcp_pP->rnti[i]=ctxt_pP->rnti; pdcp_pP->uid[i]=i; - pdcp_num_ues++; + Pdcp_num_ues[ctxt_pP->module_id]++; break; - } + } //pdcp_eNB_UE_instance_to_rnti[ctxtP->module_id] = ctxt_pP->rnti; pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] = ctxt_pP->rnti; //pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % NUMBER_OF_UE_MAX; @@ -1669,14 +1655,14 @@ pdcp_config_req_asn1 ( if (ctxt_pP->enb_flag == ENB_FLAG_YES) { for (i=0; i < NUMBER_OF_UE_MAX; i++) { - if (pdcp_pP->rnti[i] == ctxt_pP->rnti ) { - pdcp_pP->rnti[i]=0; - pdcp_pP->uid[i]=0; - pdcp_num_ues--; - break; - } - } + if (pdcp_pP->rnti[i] == ctxt_pP->rnti ) { + pdcp_pP->rnti[i]=0; + pdcp_pP->uid[i]=0; + Pdcp_num_ues[ctxt_pP->module_id]--; + break; + } } + } /* Security keys */ if (pdcp_pP->kUPenc != NULL) { @@ -2055,6 +2041,11 @@ void pdcp_layer_init(void) pdcp_output_header_bytes_to_write=0; pdcp_input_sdu_remaining_size_to_read=0; + memset(Pdcp_sfn, 0, sizeof(Pdcp_sfn)); + memset(Pdcp_frame, 0, sizeof(Pdcp_frame)); + memset(Pdcp_subframe, 0, sizeof(Pdcp_subframe)); + memset(Pdcp_num_ues, 0, sizeof(Pdcp_num_ues)); + memset(Pdcp_stats_tx, 0, sizeof(Pdcp_stats_tx)); memset(Pdcp_stats_tx_s, 0, sizeof(Pdcp_stats_tx_s)); memset(Pdcp_stats_tx_bytes, 0, sizeof(Pdcp_stats_tx_bytes)); diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h index 2f1d15ad5e..e9f20e0a94 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h @@ -94,9 +94,10 @@ extern int pdcp_instance_cnt; int init_pdcp_thread(void); void cleanup_pdcp_thread(void); -public_pdcp(frame_t pdcp_frame); -public_pdcp(sub_frame_t pdcp_subframe); -public_pdcp(uint16_t pdcp_num_ues); +public_pdcp(uint64_t Pdcp_sfn[MAX_NUM_CCs]); +public_pdcp(frame_t Pdcp_frame[MAX_NUM_CCs]); +public_pdcp(sub_frame_t Pdcp_subframe[MAX_NUM_CCs]); +public_pdcp(uint16_t Pdcp_num_ues[MAX_NUM_CCs]); public_pdcp(uint32_t Pdcp_stats_tx_bytes[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); From b74c668ddb032f8148b56ce538efcc2555393a03 Mon Sep 17 00:00:00 2001 From: shahab SHARIAT BAGHERI Date: Tue, 12 Dec 2017 15:57:24 +0100 Subject: [PATCH 102/284] bug zero division for pdcp stats --- openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index c561043f4a..6118ddc745 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -928,7 +928,9 @@ void pdcp_update_stats(const protocol_ctxt_t* const ctxt_pP){ Pdcp_stats_tx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]; // unit: bit/s Pdcp_stats_tx_throughput_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]*8; - Pdcp_stats_tx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_id]=(uint32_t)(Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]); + if (Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id] > 0){ + Pdcp_stats_tx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_id]=(Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]); + } Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; @@ -937,7 +939,10 @@ void pdcp_update_stats(const protocol_ctxt_t* const ctxt_pP){ // rx stats Pdcp_stats_rx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id]; Pdcp_stats_rx_goodput_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]*8; - Pdcp_stats_rx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_id]= (uint32_t)(Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id]); + + if(Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id] > 0){ + Pdcp_stats_rx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_id]= (Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id]); + } Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; From 33696a4e93115d8ee366fb9b9b1164d75cf441a3 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Tue, 12 Dec 2017 20:24:29 +0100 Subject: [PATCH 103/284] *Update RRC RSRP/RSRQ measurement reports for multiple UEs, and add the corresponding RAN APIs *Fix the issue with the PDCP UE ID/RNTI management --- .../CONTROL_MODULES/RRC/flexran_agent_rrc.c | 36 +++---- openair2/ENB_APP/flexran_agent_ran_api.c | 68 +++++++++++++- openair2/ENB_APP/flexran_agent_ran_api.h | 8 ++ openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 93 +++++++++++-------- openair2/LAYER2/PDCP_v10.1.0/pdcp.h | 31 +++++-- openair2/RRC/LITE/L2_interface.c | 4 +- openair2/RRC/LITE/defs.h | 3 +- openair2/RRC/LITE/proto.h | 2 +- openair2/RRC/LITE/rrc_eNB.c | 67 ++++++++----- 9 files changed, 217 insertions(+), 95 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c index 587ac8c263..7a251be78b 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c @@ -276,9 +276,11 @@ void flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t* measResults for (i = 0; i < num; i++){ meas_stats[i].rnti = flexran_get_ue_crnti(mod_id, i); - meas_stats[i].meas_id = measResults->measId; - meas_stats[i].rsrp = measResults->measResultPCell.rsrpResult - 140; - meas_stats[i].rsrq = (measResults->measResultPCell.rsrqResult)/2 - 20; + meas_stats[i].meas_id = flexran_get_rrc_pcell_measid(mod_id,i); + meas_stats[i].rsrp = flexran_get_rrc_pcell_rsrp(mod_id,i) - 140; + // measResults->measResultPCell.rsrpResult - 140; + meas_stats[i].rsrq = flexran_get_rrc_pcell_rsrq(mod_id,i)/2 - 20; + // (measResults->measResultPCell.rsrqResult)/2 - 20; } // repl->neigh_meas = NULL; @@ -505,23 +507,21 @@ int flexran_agent_rrc_stats_reply(mid_t mod_id, if (rrc_measurements == NULL) goto error; protocol__flex_rrc_measurements__init(rrc_measurements); - - if (triggered_rrc){ - rrc_measurements->measid = meas_stats[i].meas_id; - rrc_measurements->has_measid = 1; - - rrc_measurements->pcell_rsrp = meas_stats[i].rsrp; - rrc_measurements->has_pcell_rsrp = 1; - - rrc_measurements->pcell_rsrq = meas_stats[i].rsrq; - rrc_measurements->has_pcell_rsrq = 1 ; - - ue_report[i]->rrc_measurements = rrc_measurements; - // triggered_rrc = false; // To be decided later - } + + rrc_measurements->measid = flexran_get_rrc_pcell_measid(mod_id,i); + rrc_measurements->has_measid = 1; + + rrc_measurements->pcell_rsrp = flexran_get_rrc_pcell_rsrp(mod_id,i) - 140; + rrc_measurements->has_pcell_rsrp = 1; + + rrc_measurements->pcell_rsrq = flexran_get_rrc_pcell_rsrq(mod_id,i)/2 - 20; + rrc_measurements->has_pcell_rsrq = 1 ; + + ue_report[i]->rrc_measurements = rrc_measurements; + } } - } + } /* To be extended for RRC layer */ // if (report_config->nr_cc > 0) { diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 7a4522e870..17d62ced86 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -1083,9 +1083,9 @@ void flexran_agent_set_operating_frame_type (mid_t mod_id, int cc_id, int frame_ } /*********** PDCP *************/ -/*PDCP num tx pdu status flexRAN*/ +/*PDCP super frame counter flexRAN*/ uint32_t flexran_get_pdcp_sfn(const mid_t mod_id){ - return Pdcp_sfn[mod_id]; + return pdcp_enb[mod_id].sfn; } /*PDCP num tx pdu status flexRAN*/ @@ -1166,5 +1166,67 @@ uint32_t flexran_get_pdcp_rx_oo(const mid_t mod_id, const mid_t ue_id, const lc return Pdcp_stats_rx_outoforder[mod_id][ue_id][lcid]; } +/******************** RRC *****************************/ - +int flexran_get_rrc_pcell_measid(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.measResults != NULL) { + return ue_context_p->ue_context.measResults->measId; + } else { + return -1; + } + } else { + return -1; + } +} +int flexran_get_rrc_pcell_rsrp(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.measResults != NULL) { + return ue_context_p->ue_context.measResults->measResultPCell.rsrpResult; + } else { + return -1; + } + } else { + return -1; + } +} +int flexran_get_rrc_pcell_rsrq(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.measResults != NULL) { + return ue_context_p->ue_context.measResults->measResultPCell.rsrqResult; + } else { + return -1; + } + } else { + return -1; + } +} +/* +void* flexran_get_rrc_ncell_measresult_eutra(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.measResults != NULL) { + return &ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA; + } else { + return -1; + } + } else { + return -1; + } +} +*/ diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index bb9592399e..84723be005 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -391,4 +391,12 @@ uint32_t flexran_get_pdcp_rx_aiat_s(const mid_t mod_id, const mid_t ue_id, cons /*PDCP num of received outoforder pdu status flexRAN*/ uint32_t flexran_get_pdcp_rx_oo(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); +/*********************RRC**********************/ +/*Get primary cell measuremeant id flexRAN*/ +int flexran_get_rrc_pcell_measid(mid_t mod_id, mid_t ue_id); +/*Get primary cell RSRP measurement flexRAN*/ +int flexran_get_rrc_pcell_rsrp(mid_t mod_id, mid_t ue_id); + +/*Get primary cell RSRQ measurement flexRAN*/ +int flexran_get_rrc_pcell_rsrq(mid_t mod_id, mid_t ue_id); diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 6118ddc745..baba5fa39e 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -69,7 +69,6 @@ extern int otg_enabled; #endif - //----------------------------------------------------------------------------- /* * If PDCP_UNIT_TEST is set here then data flow between PDCP and RLC is broken @@ -403,7 +402,7 @@ boolean_t pdcp_data_req( */ for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){ - if (pdcp_p->rnti[pdcp_uid] == ctxt_pP->rnti ) + if (pdcp_enb[ctxt_pP->module_id].rnti[pdcp_uid] == ctxt_pP->rnti ) break; } @@ -414,9 +413,9 @@ boolean_t pdcp_data_req( Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; Pdcp_stats_tx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=current_sn; - Pdcp_stats_tx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (Pdcp_sfn[ctxt_pP->module_id] - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (Pdcp_sfn[ctxt_pP->module_id] - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_sfn[ctxt_pP->module_id]; + Pdcp_stats_tx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_enb[ctxt_pP->module_id].sfn; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); return ret; @@ -875,8 +874,9 @@ pdcp_data_ind( */ for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){ - if (pdcp_p->rnti[pdcp_uid] == ctxt_pP->rnti ) + if (pdcp_enb[ctxt_pP->module_id].rnti[pdcp_uid] == ctxt_pP->rnti ){ break; + } } Pdcp_stats_rx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; @@ -889,9 +889,9 @@ pdcp_data_ind( if (oo_flag == 1 ) Pdcp_stats_rx_outoforder[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (Pdcp_sfn[ctxt_pP->module_id] - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(Pdcp_sfn[ctxt_pP->module_id] - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=Pdcp_sfn[ctxt_pP->module_id]; + Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_enb[ctxt_pP->module_id].sfn; #if defined(STOP_ON_IP_TRAFFIC_OVERLOAD) @@ -920,10 +920,10 @@ void pdcp_update_stats(const protocol_ctxt_t* const ctxt_pP){ uint8_t rb_id = 0; // these stats are measured for both eNB and UE on per seond basis - if (Pdcp_sfn[ctxt_pP->module_id] % 1000 == 0){ + if (pdcp_enb[ctxt_pP->module_id].sfn % 1000 == 0){ for (rb_id =0; rb_id < NB_RB_MAX; rb_id ++){ for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){ - //printf("frame %d and subframe %d \n", Pdcp_frame[ctxt_pP->module_id], Pdcp_subframe[ctxt_pP->module_id]); + //printf("frame %d and subframe %d \n", pdcp_enb[ctxt_pP->module_id].frame, pdcp_enb[ctxt_pP->module_id].subframe); // tx stats Pdcp_stats_tx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]; // unit: bit/s @@ -975,9 +975,9 @@ pdcp_run ( start_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_run); } - Pdcp_sfn[ctxt_pP->module_id]++; // range: 0 to 18,446,744,073,709,551,615 - Pdcp_frame[ctxt_pP->module_id]=ctxt_pP->frame; // 1023 - Pdcp_subframe[ctxt_pP->module_id]= ctxt_pP->subframe; + pdcp_enb[ctxt_pP->module_id].sfn++; // range: 0 to 18,446,744,073,709,551,615 + pdcp_enb[ctxt_pP->module_id].frame=ctxt_pP->frame; // 1023 + pdcp_enb[ctxt_pP->module_id].subframe= ctxt_pP->subframe; pdcp_update_stats(ctxt_pP); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_IN); @@ -1102,6 +1102,28 @@ pdcp_run ( VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_OUT); } +void pdcp_add_UE(const protocol_ctxt_t* const ctxt_pP){ + int i, ue_flag=1, ret=-1;; + for (i=0; i < NUMBER_OF_UE_MAX; i++){ + if (pdcp_enb[ctxt_pP->module_id].rnti[i] == ctxt_pP->rnti) { + ue_flag=-1; + break; + } + } + if (ue_flag == 1 ){ + for (i=0; i < NUMBER_OF_UE_MAX ; i++){ + if (pdcp_enb[ctxt_pP->module_id].rnti[i] == 0 ){ + pdcp_enb[ctxt_pP->module_id].rnti[i]=ctxt_pP->rnti; + pdcp_enb[ctxt_pP->module_id].uid[i]=i; + pdcp_enb[ctxt_pP->module_id].num_ues++; + printf("add new uid is %d %x\n\n", i, ctxt_pP->rnti); + ret=1; + break; + } + } + } + //return ret; +} //----------------------------------------------------------------------------- boolean_t @@ -1115,7 +1137,7 @@ pdcp_remove_UE( hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; - // check and remove SRBs first + // check and remove SRBs first for (srb_id=0; srb_id<2; srb_id++) { key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, srb_id, SRB_FLAG_YES); @@ -1130,6 +1152,19 @@ pdcp_remove_UE( (void)h_rc; /* remove gcc warning "set but not used" */ + // remove ue for pdcp enb inst + for (i=0; i < NUMBER_OF_UE_MAX; i++) { + if (pdcp_enb[ctxt_pP->module_id].rnti[i] == ctxt_pP->rnti ) { + LOG_I(PDCP, "remove uid is %d/%d %x\n", i, + pdcp_enb[ctxt_pP->module_id].uid[i], + pdcp_enb[ctxt_pP->module_id].rnti[i]); + pdcp_enb[ctxt_pP->module_id].uid[i]=0; + pdcp_enb[ctxt_pP->module_id].rnti[i]=0; + pdcp_enb[ctxt_pP->module_id].num_ues--; + break; + } + } + return 1; } @@ -1524,7 +1559,6 @@ rrc_pdcp_config_asn1_req ( return 0; } - //----------------------------------------------------------------------------- boolean_t pdcp_config_req_asn1 ( @@ -1545,19 +1579,14 @@ pdcp_config_req_asn1 ( uint8_t *const kUPenc_pP) //----------------------------------------------------------------------------- { - int i; + switch (actionP) { case CONFIG_ACTION_ADD: DevAssert(pdcp_pP != NULL); if (ctxt_pP->enb_flag == ENB_FLAG_YES) { pdcp_pP->is_ue = FALSE; - for (i=0; i < NUMBER_OF_UE_MAX; i++) { - if (pdcp_pP->rnti[i] != 0 ) continue ; // skip active ues - pdcp_pP->rnti[i]=ctxt_pP->rnti; - pdcp_pP->uid[i]=i; - Pdcp_num_ues[ctxt_pP->module_id]++; - break; - } + pdcp_add_ue(ctxt_pP); + //pdcp_eNB_UE_instance_to_rnti[ctxtP->module_id] = ctxt_pP->rnti; pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] = ctxt_pP->rnti; //pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % NUMBER_OF_UE_MAX; @@ -1658,15 +1687,7 @@ pdcp_config_req_asn1 ( rb_idP); if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - - for (i=0; i < NUMBER_OF_UE_MAX; i++) { - if (pdcp_pP->rnti[i] == ctxt_pP->rnti ) { - pdcp_pP->rnti[i]=0; - pdcp_pP->uid[i]=0; - Pdcp_num_ues[ctxt_pP->module_id]--; - break; - } - } + // pdcp_remove_UE(ctxt_pP); } /* Security keys */ @@ -2046,10 +2067,8 @@ void pdcp_layer_init(void) pdcp_output_header_bytes_to_write=0; pdcp_input_sdu_remaining_size_to_read=0; - memset(Pdcp_sfn, 0, sizeof(Pdcp_sfn)); - memset(Pdcp_frame, 0, sizeof(Pdcp_frame)); - memset(Pdcp_subframe, 0, sizeof(Pdcp_subframe)); - memset(Pdcp_num_ues, 0, sizeof(Pdcp_num_ues)); + memset(pdcp_enb, 0, sizeof(pdcp_enb_t)); + memset(Pdcp_stats_tx, 0, sizeof(Pdcp_stats_tx)); memset(Pdcp_stats_tx_s, 0, sizeof(Pdcp_stats_tx_s)); diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h index e9f20e0a94..cf3d927051 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h @@ -94,11 +94,12 @@ extern int pdcp_instance_cnt; int init_pdcp_thread(void); void cleanup_pdcp_thread(void); +/* public_pdcp(uint64_t Pdcp_sfn[MAX_NUM_CCs]); public_pdcp(frame_t Pdcp_frame[MAX_NUM_CCs]); public_pdcp(sub_frame_t Pdcp_subframe[MAX_NUM_CCs]); public_pdcp(uint16_t Pdcp_num_ues[MAX_NUM_CCs]); - +*/ public_pdcp(uint32_t Pdcp_stats_tx_bytes[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); public_pdcp(uint32_t Pdcp_stats_tx_bytes_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); @@ -131,7 +132,19 @@ public_pdcp(void pdcp_update_perioidical_stats(const protocol_ctxt_t* const ctx /*Packet Probing for agent PDCP*/ //public_pdcp(uint64_t *pdcp_packet_counter); //public_pdcp(uint64_t *pdcp_size_packet); +typedef struct pdcp_enb_s { + // used for eNB stats generation + uint16_t uid[NUMBER_OF_UE_MAX]; + rnti_t rnti[NUMBER_OF_UE_MAX]; + uint16_t num_ues; + + uint64_t sfn; + frame_t frame; + sub_frame_t subframe; + +} pdcp_enb_t; +public_pdcp(pdcp_enb_t pdcp_enb[MAX_NUM_CCs]); typedef struct pdcp_stats_s { time_stats_t pdcp_run; @@ -154,11 +167,7 @@ typedef struct pdcp_s { boolean_t is_ue; boolean_t is_srb; - // used for eNB stats generation - uint16_t uid[NUMBER_OF_UE_MAX]; // local to pdcp - rnti_t rnti[NUMBER_OF_UE_MAX]; - - /* Configured security algorithms */ + /* Configured security algorithms */ uint8_t cipheringAlgorithm; uint8_t integrityProtAlgorithm; @@ -360,9 +369,15 @@ public_pdcp(boolean_t pdcp_config_req_asn1 ( uint8_t *const kRRCint, uint8_t *const kUPenc)); - +/*! \fn void pdcp_add_UE(const protocol_ctxt_t* const ctxt_pP) +* \brief Function (for RRC) to add a new UE in PDCP module +* \param[in] ctxt_pP Running context. +* \return A status about the processing, OK or error code. +*/ +public_pdcp(void pdcp_add_UE(const protocol_ctxt_t* const ctxt_pP)); + /*! \fn boolean_t pdcp_remove_UE(const protocol_ctxt_t* const ctxt_pP) -* \brief Function for RRC to configure a Radio Bearer clear all PDCP resources for a particular UE +* \brief Function for RRC to remove UE from PDCP module hashtable * \param[in] ctxt_pP Running context. * \return A status about the processing, OK or error code. */ diff --git a/openair2/RRC/LITE/L2_interface.c b/openair2/RRC/LITE/L2_interface.c index 6a64d7811e..71616ffd91 100644 --- a/openair2/RRC/LITE/L2_interface.c +++ b/openair2/RRC/LITE/L2_interface.c @@ -597,10 +597,10 @@ rrc_data_ind( rb_id_t DCCH_index = Srb_id; if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - LOG_N(RRC, "[UE %x] Frame %d: received a DCCH %d message on SRB %d with Size %d from eNB %d\n", + LOG_D(RRC, "[UE %x] Frame %d: received a DCCH %d message on SRB %d with Size %d from eNB %d\n", ctxt_pP->module_id, ctxt_pP->frame, DCCH_index,Srb_id,sdu_sizeP, ctxt_pP->eNB_index); } else { - LOG_N(RRC, "[eNB %d] Frame %d: received a DCCH %d message on SRB %d with Size %d from UE %x\n", + LOG_D(RRC, "[eNB %d] Frame %d: received a DCCH %d message on SRB %d with Size %d from UE %x\n", ctxt_pP->module_id, ctxt_pP->frame, DCCH_index, diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index 0a2043fd4e..29bc3e3997 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -374,7 +374,8 @@ typedef struct eNB_RRC_UE_s { SRB_INFO_TABLE_ENTRY Srb2; MeasConfig_t* measConfig; HANDOVER_INFO* handover_info; - + MeasResults_t* measResults; + #if defined(ENABLE_SECURITY) /* KeNB as derived from KASME received from EPC */ uint8_t kenb[32]; diff --git a/openair2/RRC/LITE/proto.h b/openair2/RRC/LITE/proto.h index 20bc99ab79..3b64d2a45c 100644 --- a/openair2/RRC/LITE/proto.h +++ b/openair2/RRC/LITE/proto.h @@ -425,7 +425,7 @@ rrc_eNB_generate_SecurityModeCommand( void rrc_eNB_process_MeasurementReport( const protocol_ctxt_t* const ctxt_pP, - rrc_eNB_ue_context_t* const ue_context_pP, + rrc_eNB_ue_context_t* ue_context_pP, const MeasResults_t* const measResults2 ); diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 05e59755c2..aaf12da175 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -2840,32 +2840,56 @@ rrc_eNB_generate_RRCConnectionReconfiguration_SCell( void rrc_eNB_process_MeasurementReport( const protocol_ctxt_t* const ctxt_pP, - rrc_eNB_ue_context_t* const ue_context_pP, + rrc_eNB_ue_context_t* ue_context_pP, const MeasResults_t* const measResults2 ) //----------------------------------------------------------------------------- { - // T(T_ENB_RRC_MEASUREMENT_REPORT, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), - // T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + int i=0; + int neighboring_cells=-1; + + T(T_ENB_RRC_MEASUREMENT_REPORT, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + if (measResults2 == NULL ) + return; + + if (measResults2->measId > 0 ){ + if (ue_context_pP->ue_context.measResults == NULL) { + ue_context_pP->ue_context.measResults = CALLOC(1, sizeof(MeasResults_t)); + } + ue_context_pP->ue_context.measResults->measId=measResults2->measId; + ue_context_pP->ue_context.measResults->measResultPCell.rsrpResult=measResults2->measResultPCell.rsrpResult; + ue_context_pP->ue_context.measResults->measResultPCell.rsrqResult=measResults2->measResultPCell.rsrqResult; + LOG_D(RRC, "[eNB %d]Frame %d: UE %x (Measurement Id %d): RSRP of Source %ld\n", ctxt_pP->module_id, ctxt_pP->frame, ctxt_pP->rnti, (int)measResults2->measId, ue_context_pP->ue_context.measResults->measResultPCell.rsrpResult-140); + LOG_D(RRC, "[eNB %d]Frame %d: UE %x (Measurement Id %d): RSRQ of Source %ld\n", ctxt_pP->module_id, ctxt_pP->frame, ctxt_pP->rnti, (int)measResults2->measId, ue_context_pP->ue_context.measResults->measResultPCell.rsrqResult/2 - 20); + } + if (measResults2->measResultNeighCells == NULL) + return; - // LOG_I(RRC, "[eNB %d] Frame %d: Process Measurement Report From UE %x (Measurement Id %d)\n", - // ctxt_pP->module_id, ctxt_pP->frame, ctxt_pP->rnti, (int)measResults2->measId); - - // if (measResults2->measResultNeighCells->choice.measResultListEUTRA.list.count > 0) { - // LOG_I(RRC, "Physical Cell Id %d\n", - // (int)measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]->physCellId); - // LOG_I(RRC, "RSRP of Target %d\n", - // (int)*(measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]-> - // measResult.rsrpResult)); - // LOG_I(RRC, "RSRQ of Target %d\n", - // (int)*(measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]-> - // measResult.rsrqResult)); - // } + if (measResults2->measResultNeighCells->choice.measResultListEUTRA.list.count > 0) { + neighboring_cells=measResults2->measResultNeighCells->choice.measResultListEUTRA.list.count; + + if (ue_context_pP->ue_context.measResults->measResultNeighCells == NULL) { + + ue_context_pP->ue_context.measResults->measResultNeighCells = CALLOC(1, sizeof(*measResults2->measResultNeighCells)*neighboring_cells); + } + ue_context_pP->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.count=neighboring_cells; + for (i=0; i < neighboring_cells; i++){ + memcpy (ue_context_pP->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[i], + measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[i], + sizeof(MeasResultListEUTRA_t)); + + LOG_D(RRC, "Physical Cell Id %d\n", + (int)ue_context_pP->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[i]->physCellId); + LOG_D(RRC, "RSRP of Target %d\n", + (int)*(ue_context_pP->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[i]->measResult.rsrpResult)); + LOG_D(RRC, "RSRQ of Target %d\n", + (int)*(ue_context_pP->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[i]->measResult.rsrqResult)); + } + } // #if defined(Rel10) || defined(Rel14) - LOG_I(RRC, "RSRP of Source %ld\n", measResults2->measResultPCell.rsrpResult); - LOG_I(RRC, "RSRQ of Source %ld\n", measResults2->measResultPCell.rsrqResult); // #else @@ -5109,13 +5133,6 @@ rrc_eNB_decode_dcch( ue_context_p, &ul_dcch_msg->message.choice.c1.choice.measurementReport. criticalExtensions.choice.c1.choice.measurementReport_r8.measResults); - #if defined(FLEXRAN_AGENT_SB_IF) - - if (rrc_agent_registered[ctxt_pP->module_id]) { - agent_rrc_xface[ctxt_pP->eNB_index]->flexran_trigger_rrc_measurements (ctxt_pP->module_id, &ul_dcch_msg->message.choice.c1.choice.measurementReport.criticalExtensions.choice.c1.choice.measurementReport_r8.measResults); - } -#endif - break; case UL_DCCH_MessageType__c1_PR_rrcConnectionReconfigurationComplete: From 49ea4748072f50107d47bf9260003861fb42a896 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Wed, 13 Dec 2017 17:00:33 +0100 Subject: [PATCH 104/284] Fix the compilation issues --- openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index baba5fa39e..df85b06d06 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -1136,7 +1136,7 @@ pdcp_remove_UE( DRB_Identity_t drb_id = 0; hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; - + int i; // check and remove SRBs first for (srb_id=0; srb_id<2; srb_id++) { @@ -1585,7 +1585,7 @@ pdcp_config_req_asn1 ( DevAssert(pdcp_pP != NULL); if (ctxt_pP->enb_flag == ENB_FLAG_YES) { pdcp_pP->is_ue = FALSE; - pdcp_add_ue(ctxt_pP); + pdcp_add_UE(ctxt_pP); //pdcp_eNB_UE_instance_to_rnti[ctxtP->module_id] = ctxt_pP->rnti; pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] = ctxt_pP->rnti; From 6e6a462dc420def86472dc4e0530c5592437b5ee Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 14 Dec 2017 12:46:38 +0100 Subject: [PATCH 105/284] check whether RRC instance is present in RAN API --- openair2/ENB_APP/flexran_agent_ran_api.c | 73 +++++++++++++++++++++--- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 17d62ced86..3ecbf77e11 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -65,17 +65,27 @@ void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran){ error: LOG_E(FLEXRAN_AGENT, "unknown RAN name %d\n", ran); } -static int mac_xface_not_ready(void); -static int mac_xface_not_ready(void){ - if (mac_xface == NULL) +static int mac_xface_not_ready(void) +{ + if (mac_xface == NULL) { return 1; + } else { //printf("max_xface %p %d \n", mac_xface, mac_xface->active); return 0;// !mac_xface->active; } } - + +static int eNB_rrc_inst_not_ready(void) +{ + if (NULL == eNB_rrc_inst) { + return 1; + } + else { + return 0; + } +} int flexran_get_current_time_ms (mid_t mod_id, int subframe_flag){ if (enb[mod_id] == NULL) return 0; @@ -681,6 +691,8 @@ int flexran_get_num_pdcch_symb(mid_t mod_id, int CC_id) { int flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return -1; ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { @@ -698,6 +710,8 @@ int flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + if (eNB_rrc_inst_not_ready()) return -1; + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { if(ue_context_p->ue_context.measGapConfig != NULL) { @@ -719,6 +733,8 @@ int flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id) { int flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return -1; ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); @@ -741,6 +757,8 @@ int flexran_get_rrc_status(const mid_t mod_id, const rnti_t rntiP){ struct rrc_eNB_ue_context_s* ue_context_p = NULL; + if (eNB_rrc_inst_not_ready()) return -1; + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if (ue_context_p != NULL) { @@ -805,6 +823,8 @@ int flexran_get_res_alloc_type1(mid_t ue_id) { int flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return -1; ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); @@ -822,6 +842,8 @@ int flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) { int flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return -1; ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { @@ -839,6 +861,8 @@ int flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id) { int flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return -1; ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { @@ -852,6 +876,8 @@ int flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) { int flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return -1; ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { @@ -868,6 +894,8 @@ int flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) { int flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return -1; ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { @@ -884,6 +912,8 @@ int flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) { int flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return -1; ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { @@ -901,6 +931,8 @@ int flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) { int flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return -1; ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { @@ -914,13 +946,18 @@ int flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) { } int flexran_get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id) { - return (&eNB_rrc_inst[mod_id])->carrier[0].sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; + + if (eNB_rrc_inst_not_ready()) return -1; + + return (&eNB_rrc_inst[mod_id])->carrier[0].sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; } int flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - + + if (eNB_rrc_inst_not_ready()) return -1; + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { @@ -935,6 +972,8 @@ int flexran_get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) { // TODO: This needs fixing return -1; + /* if (eNB_rrc_inst_not_ready()) return -1; */ + /* struct rrc_eNB_ue_context_s* ue_context_p = NULL; */ /* uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); */ @@ -954,6 +993,8 @@ int flexran_get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) { int flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return -1; ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { @@ -972,6 +1013,8 @@ int flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + if (eNB_rrc_inst_not_ready()) return -1; + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { if(ue_context_p->ue_context.mac_MainConfig != NULL){ @@ -989,7 +1032,9 @@ int flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id) { int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - + + if (eNB_rrc_inst_not_ready()) return -1; + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { @@ -1035,6 +1080,8 @@ int flexran_get_antenna_ports(mid_t mod_id, int CC_id){ LTE_DL_FRAME_PARMS *frame_parms; + if (mac_xface_not_ready()) return 0; + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); return (frame_parms == NULL)? 0:frame_parms->nb_antenna_ports_eNB; @@ -1171,6 +1218,8 @@ uint32_t flexran_get_pdcp_rx_oo(const mid_t mod_id, const mid_t ue_id, const lc int flexran_get_rrc_pcell_measid(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return -1; ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { @@ -1186,7 +1235,9 @@ int flexran_get_rrc_pcell_measid(mid_t mod_id, mid_t ue_id) { int flexran_get_rrc_pcell_rsrp(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - + + if (eNB_rrc_inst_not_ready()) return -1; + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { if(ue_context_p->ue_context.measResults != NULL) { @@ -1201,7 +1252,9 @@ int flexran_get_rrc_pcell_rsrp(mid_t mod_id, mid_t ue_id) { int flexran_get_rrc_pcell_rsrq(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - + + if (eNB_rrc_inst_not_ready()) return -1; + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { if(ue_context_p->ue_context.measResults != NULL) { @@ -1217,6 +1270,8 @@ int flexran_get_rrc_pcell_rsrq(mid_t mod_id, mid_t ue_id) { void* flexran_get_rrc_ncell_measresult_eutra(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return -1; ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { From 612ab055d7b97e02503f2f1143ba2092c3a1cd9b Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Wed, 6 Dec 2017 12:23:16 +0100 Subject: [PATCH 106/284] Add control logic to reconfigure and start eNB --- openair2/ENB_APP/enb_app.c | 36 ++++- openair2/ENB_APP/enb_config.c | 22 ++- openair2/ENB_APP/enb_config.h | 11 +- .../ENB_APP/flexran_agent_common_internal.c | 9 +- .../LAYER2/MAC/eNB_scheduler_primitives.c | 4 + targets/COMMON/create_tasks.c | 19 ++- targets/COMMON/create_tasks.h | 1 + .../CONF/enb.band7.flexran.usrpb210.conf | 6 +- targets/RT/USER/lte-softmodem.c | 143 ++++++++++++------ 9 files changed, 175 insertions(+), 76 deletions(-) diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index de0d0490aa..4a5981f509 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -55,6 +55,17 @@ extern unsigned char NB_eNB_INST; #endif +extern volatile int node_control_state; + +static void enb_app_wait_reconfig_cmd (void) +{ + LOG_I(ENB_APP, "ENB APP await reconfiguration command\n"); + + while (node_control_state == ENB_WAIT_RECONFIGURATION_CMD) { + usleep(200000); + } + sleep(2); // wait for createing other tasks +} #if defined(ENABLE_ITTI) @@ -270,7 +281,7 @@ static uint32_t eNB_app_register(uint32_t enb_id_start, uint32_t enb_id_end, con /*------------------------------------------------------------------------------*/ void *eNB_app_task(void *args_p) { - const Enb_properties_array_t *enb_properties_p = NULL; + Enb_properties_array_t *enb_properties_p = NULL; #if defined(ENABLE_ITTI) uint32_t enb_nb = 1; /* Default number of eNB is 1 */ uint32_t enb_id_start = 0; @@ -309,19 +320,28 @@ void *eNB_app_task(void *args_p) "Number of eNB is greater than eNB defined in configuration file (%d/%d)!", enb_nb, enb_properties_p->number); +#if defined (FLEXRAN_AGENT_SB_IF) + + for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { + flexran_agent_start(enb_id, enb_properties_p); + } + // wait for config comd from the controller/network app + enb_app_wait_reconfig_cmd(); + + // set again the ran api vars + for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { + printf("\n set again enb vars %d\n", enb_id); + flexran_set_enb_vars(enb_id, RAN_LTE_OAI); + } + +#endif + for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { configure_phy(enb_id, enb_properties_p); configure_rrc(enb_id, enb_properties_p); } -#if defined (FLEXRAN_AGENT_SB_IF) - for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { - printf("\n start enb agent %d\n", enb_id); - flexran_agent_start(enb_id, enb_properties_p); - } -#endif - # if defined(ENABLE_USE_MME) /* Try to register each eNB */ registered_enb = 0; diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index 09d7495a69..6282523b55 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -197,6 +197,7 @@ #define ENB_CONFIG_STRING_FLEXRAN_AGENT_IPV4_ADDRESS "FLEXRAN_AGENT_IPV4_ADDRESS" #define ENB_CONFIG_STRING_FLEXRAN_AGENT_PORT "FLEXRAN_AGENT_PORT" #define ENB_CONFIG_STRING_FLEXRAN_AGENT_CACHE "FLEXRAN_AGENT_CACHE" +#define ENB_CONFIG_STRING_FLEXRAN_AGENT_AWAIT_RECONF "FLEXRAN_AGENT_AWAIT_RECONF" #define ENB_CONFIG_STRING_RRH_GW_CONFIG "rrh_gw_config" #define ENB_CONFIG_STRING_RRH_GW_LOCAL_IF_NAME "local_if_name" @@ -351,6 +352,8 @@ void enb_config_display(void) // printf( "\tInterface IP Address: \t%s:\n",enb_properties.properties[i]->flexran_agent_ipv4_address); printf( "\tInterface PORT: \t%d:\n\n",enb_properties.properties[i]->flexran_agent_port); printf( "\tCache directory: \t%s:\n",enb_properties.properties[i]->flexran_agent_cache); + printf( "\teNB Control State: \t%s:\n",(enb_properties.properties[i]->flexran_agent_reconf==0)? "ENB_NORMAL_OPERATION":"ENB_WAIT_RECONFIGURATION_CMD"); + #endif @@ -536,7 +539,7 @@ extern int asn1_xer_print; #else #define libconfig_int int #endif -const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) +Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) { config_t cfg; config_setting_t *setting = NULL; @@ -689,6 +692,8 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) char* flexran_agent_ipv4_address = NULL; libconfig_int flexran_agent_port = 0; char* flexran_agent_cache = NULL; + char* flexran_agent_reconf = NULL; + libconfig_int otg_ue_id = 0; char* otg_app_type = NULL; char* otg_bg_traffic = NULL; @@ -2580,6 +2585,9 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) &flexran_agent_port) && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_FLEXRAN_AGENT_CACHE, (const char **)&flexran_agent_cache) + && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_FLEXRAN_AGENT_AWAIT_RECONF, + (const char **)&flexran_agent_reconf) + ) ) { enb_properties.properties[enb_properties_index]->flexran_agent_interface_name = strdup(flexran_agent_interface_name); @@ -2590,8 +2598,14 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) IPV4_STR_ADDR_TO_INT_NWBO (address, enb_properties.properties[enb_properties_index]->flexran_agent_ipv4_address, "BAD IP ADDRESS FORMAT FOR eNB Agent !\n" ); } - enb_properties.properties[enb_properties_index]->flexran_agent_port = flexran_agent_port; - enb_properties.properties[enb_properties_index]->flexran_agent_cache = strdup(flexran_agent_cache); + enb_properties.properties[enb_properties_index]->flexran_agent_port = flexran_agent_port; + enb_properties.properties[enb_properties_index]->flexran_agent_cache = strdup(flexran_agent_cache); + if ((strcmp(flexran_agent_reconf, "yes") == 0) || (strcmp(flexran_agent_reconf, "YES") == 0)){ + enb_properties.properties[enb_properties_index]->flexran_agent_reconf = 1; + } else { + enb_properties.properties[enb_properties_index]->flexran_agent_reconf = 0; + } + } } @@ -2885,7 +2899,7 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) } -const Enb_properties_array_t *enb_config_get(void) +Enb_properties_array_t *enb_config_get(void) { return &enb_properties; } diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h index 094360749b..8e914458bf 100644 --- a/openair2/ENB_APP/enb_config.h +++ b/openair2/ENB_APP/enb_config.h @@ -237,6 +237,8 @@ typedef struct Enb_properties_s { in_addr_t flexran_agent_ipv4_address; tcp_udp_port_t flexran_agent_port; char *flexran_agent_cache; + int flexran_agent_reconf; + /* Nb of RRH to connect to */ uint8_t nb_rrh_gw; @@ -276,15 +278,20 @@ typedef struct Enb_properties_s { #endif } Enb_properties_t; +typedef enum { + ENB_NORMAL_OPERATION=0x0, + ENB_WAIT_RECONFIGURATION_CMD=0x1 +} ENB_MODULE_STATE; + typedef struct Enb_properties_array_s { int number; Enb_properties_t *properties[MAX_ENB]; } Enb_properties_array_t; void enb_config_display(void); -const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP); +Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP); -const Enb_properties_array_t *enb_config_get(void); +Enb_properties_array_t *enb_config_get(void); #endif /* ENB_CONFIG_H_ */ /** @} */ diff --git a/openair2/ENB_APP/flexran_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c index 839fb4c784..c883523855 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.c +++ b/openair2/ENB_APP/flexran_agent_common_internal.c @@ -31,7 +31,7 @@ #include "flexran_agent_common_internal.h" #include "flexran_agent_mac_internal.h" -extern volatile int reconfigure_enb; +extern volatile int node_control_state; int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy_length) { @@ -72,8 +72,8 @@ int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy if (parse_enb_id(mod_id, &parser) == -1) { goto error; } else { // succeful parse and setting - LOG_I(ENB_APP, "Successful parsed config for enb system\n"); - //reconfigure_enb=RECONF_FREQ; + node_control_state= ENB_NORMAL_OPERATION; + LOG_I(ENB_APP, "Successful parsed config for enb system, entering normal state\n"); } } else if (strcmp((char *) event.data.scalar.value, "mac") == 0) { LOG_D(ENB_APP, "This is intended for the mac system\n"); @@ -258,6 +258,9 @@ int parse_enb_config_parameters(mid_t mod_id, yaml_parser_t *parser) { yaml_event_delete(&event); } + /* reflect in RAN API */ + flexran_set_enb_vars(mod_id, RAN_LTE_OAI); + return 0; error: diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 610700f3e8..a678178435 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -131,6 +131,7 @@ int UE_num_active_CC(UE_list_t *listP,int ue_idP) int UE_PCCID(module_id_t mod_idP,int ue_idP) //------------------------------------------------------------------------------ { + if (eNB_mac_inst == NULL) return 0; return(eNB_mac_inst[mod_idP].UE_list.pCC_id[ue_idP]); } @@ -139,6 +140,7 @@ rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP) //------------------------------------------------------------------------------ { + if (eNB_mac_inst == NULL) return 0; rnti_t rnti = eNB_mac_inst[mod_idP].UE_list.UE_template[UE_PCCID(mod_idP,ue_idP)][ue_idP].rnti; if (rnti>0) { @@ -154,6 +156,7 @@ rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP) boolean_t is_UE_active(module_id_t mod_idP, int ue_idP) //------------------------------------------------------------------------------ { + if (eNB_mac_inst == NULL) return 0; return(eNB_mac_inst[mod_idP].UE_list.active[ue_idP]); } @@ -182,6 +185,7 @@ uint8_t find_active_UEs(module_id_t module_idP,int CC_id){ int UE_BSR (uint8_t mod_id, uint8_t ue_id, uint8_t lcid) { + if (eNB_mac_inst == NULL) return 0; return eNB_mac_inst[mod_id].UE_list.UE_template[UE_PCCID(mod_id,ue_id)][ue_id].bsr_info[lcid]; } diff --git a/targets/COMMON/create_tasks.c b/targets/COMMON/create_tasks.c index c28b9e839c..1ca55b5926 100644 --- a/targets/COMMON/create_tasks.c +++ b/targets/COMMON/create_tasks.c @@ -40,6 +40,17 @@ # endif # include "enb_app.h" +int create_enb_app_task(uint32_t enb_nb) +{ + if (enb_nb > 0) { + if (itti_create_task (TASK_ENB_APP, eNB_app_task, NULL) < 0) { + LOG_E(ENB_APP, "Create task for eNB APP failed\n"); + return -1; + } + } + return 0; +} + int create_tasks(uint32_t enb_nb, uint32_t ue_nb) { itti_wait_ready(1); @@ -48,14 +59,6 @@ int create_tasks(uint32_t enb_nb, uint32_t ue_nb) return -1; } - if (enb_nb > 0) { - /* Last task to create, others task must be ready before its start */ - if (itti_create_task (TASK_ENB_APP, eNB_app_task, NULL) < 0) { - LOG_E(ENB_APP, "Create task for eNB APP failed\n"); - return -1; - } - } - # ifdef OPENAIR2 { diff --git a/targets/COMMON/create_tasks.h b/targets/COMMON/create_tasks.h index 6545f4b9d9..3455b283b5 100644 --- a/targets/COMMON/create_tasks.h +++ b/targets/COMMON/create_tasks.h @@ -27,6 +27,7 @@ extern void *l2l1_task(void *arg); int create_tasks(uint32_t enb_nb, uint32_t ue_nb); +int create_enb_app_task(uint32_t enb_nb); #endif #endif /* CREATE_TASKS_H_ */ diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.usrpb210.conf index 4ee429f45e..378d932f57 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.usrpb210.conf @@ -155,10 +155,11 @@ eNBs = NETWORK_CONTROLLER : { - FLEXRAN_AGENT_INTERFACE_NAME = "eth1"; - FLEXRAN_AGENT_IPV4_ADDRESS = "10.0.2.5/30"; + FLEXRAN_AGENT_INTERFACE_NAME = "lo"; + FLEXRAN_AGENT_IPV4_ADDRESS = "127.0.0.1/30"; FLEXRAN_AGENT_PORT = 2210; FLEXRAN_AGENT_CACHE = "/mnt/oai_agent_cache"; + FLEXRAN_AGENT_AWAIT_RECONF = "no"; }; log_config : @@ -177,6 +178,7 @@ eNBs = pdcp_log_verbosity ="medium"; rrc_log_level ="info"; rrc_log_verbosity ="medium"; + }; } ); diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index a1f3bcb57b..042f77eea7 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -174,6 +174,8 @@ eNB_func_t node_function[MAX_NUM_CCs]; eNB_timing_t node_timing[MAX_NUM_CCs]; int16_t node_synch_ref[MAX_NUM_CCs]; +volatile int16_t node_control_state; + uint32_t target_dl_mcs = 28; //maximum allowed mcs uint32_t target_ul_mcs = 20; uint32_t timing_advance = 0; @@ -232,6 +234,12 @@ threads_t threads= {-1,-1,-1,-1,-1,-1,-1}; */ uint8_t abstraction_flag=0; +/* */ + +/* overrid the enb configuration params*/ +static void reconfigure_enb_params(int enb_id); + + /*---------------------BMC: timespec helpers -----------------------------*/ struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; @@ -1080,11 +1088,20 @@ static void get_options (int argc, char **argv) { "Number of eNB is greater than eNB defined in configuration file %s (%d/%d)!", conf_config_file_name, NB_eNB_INST, enb_properties->number); + NB_eNB_INST=enb_properties->number; + /* Update some simulation parameters */ for (i=0; i < enb_properties->number; i++) { AssertFatal (MAX_NUM_CCs == enb_properties->properties[i]->nb_cc, "lte-softmodem compiled with MAX_NUM_CCs=%d, but only %d CCs configured for eNB %d!", MAX_NUM_CCs, enb_properties->properties[i]->nb_cc, i); + + if (enb_properties->properties[i]->flexran_agent_reconf == 1) { + node_control_state = ENB_WAIT_RECONFIGURATION_CMD; + } else { + node_control_state = ENB_NORMAL_OPERATION; + } + eth_params = (eth_params_t*)malloc(enb_properties->properties[i]->nb_rrh_gw * sizeof(eth_params_t)); memset(eth_params, 0, enb_properties->properties[i]->nb_rrh_gw * sizeof(eth_params_t)); @@ -1133,37 +1150,9 @@ static void get_options (int argc, char **argv) { } - for (CC_id=0; CC_idproperties[i]->cc_node_function[CC_id]; - node_timing[CC_id] = enb_properties->properties[i]->cc_node_timing[CC_id]; - node_synch_ref[CC_id] = enb_properties->properties[i]->cc_node_synch_ref[CC_id]; - - frame_parms[CC_id]->frame_type = enb_properties->properties[i]->frame_type[CC_id]; - frame_parms[CC_id]->tdd_config = enb_properties->properties[i]->tdd_config[CC_id]; - frame_parms[CC_id]->tdd_config_S = enb_properties->properties[i]->tdd_config_s[CC_id]; - frame_parms[CC_id]->Ncp = enb_properties->properties[i]->prefix_type[CC_id]; - - //for (j=0; j < enb_properties->properties[i]->nb_cc; j++ ){ - frame_parms[CC_id]->Nid_cell = enb_properties->properties[i]->Nid_cell[CC_id]; - frame_parms[CC_id]->N_RB_DL = enb_properties->properties[i]->N_RB_DL[CC_id]; - frame_parms[CC_id]->N_RB_UL = enb_properties->properties[i]->N_RB_DL[CC_id]; - frame_parms[CC_id]->nb_antennas_tx = enb_properties->properties[i]->nb_antennas_tx[CC_id]; - frame_parms[CC_id]->nb_antenna_ports_eNB = enb_properties->properties[i]->nb_antenna_ports[CC_id]; - frame_parms[CC_id]->nb_antennas_rx = enb_properties->properties[i]->nb_antennas_rx[CC_id]; - - frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_ConfigIndex = enb_properties->properties[i]->prach_config_index[CC_id]; - frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset = enb_properties->properties[i]->prach_freq_offset[CC_id]; - - frame_parms[CC_id]->mode1_flag = (frame_parms[CC_id]->nb_antenna_ports_eNB == 1) ? 1 : 0; - frame_parms[CC_id]->threequarter_fs = threequarter_fs; - - //} // j - } - - - init_all_otg(0); + init_all_otg(0); g_otg->seed = 0; init_seeds(g_otg->seed); @@ -1206,20 +1195,7 @@ static void get_options (int argc, char **argv) { osa_log_verbosity = enb_properties->properties[i]->osa_log_verbosity; #endif - // adjust the log - for (CC_id=0; CC_idproperties[i]->downlink_frequency[CC_id]; - uplink_frequency_offset[CC_id][k] = enb_properties->properties[i]->uplink_frequency_offset[CC_id]; - rx_gain[CC_id][k] = (double)enb_properties->properties[i]->rx_gain[CC_id]; - tx_gain[CC_id][k] = (double)enb_properties->properties[i]->tx_gain[CC_id]; - } - - printf("Downlink frequency/ uplink offset of CC_id %d set to %ju/%d\n", CC_id, - enb_properties->properties[i]->downlink_frequency[CC_id], - enb_properties->properties[i]->uplink_frequency_offset[CC_id]); - - } // CC_id + }// i //this is needed for phy-test option @@ -1236,6 +1212,57 @@ static void get_options (int argc, char **argv) { } } + +static void reconfigure_enb_params(int enb_id) +{ + int CC_id, k; + const Enb_properties_array_t *enb_properties=enb_config_get(); + + + for (CC_id=0; CC_idproperties[enb_id]->cc_node_function[CC_id]; + node_timing[CC_id] = enb_properties->properties[enb_id]->cc_node_timing[CC_id]; + node_synch_ref[CC_id] = enb_properties->properties[enb_id]->cc_node_synch_ref[CC_id]; + + frame_parms[CC_id]->frame_type = enb_properties->properties[enb_id]->frame_type[CC_id]; + frame_parms[CC_id]->tdd_config = enb_properties->properties[enb_id]->tdd_config[CC_id]; + frame_parms[CC_id]->tdd_config_S = enb_properties->properties[enb_id]->tdd_config_s[CC_id]; + frame_parms[CC_id]->Ncp = enb_properties->properties[enb_id]->prefix_type[CC_id]; + + //for (j=0; j < enb_properties->properties[i]->nb_cc; j++ ){ + frame_parms[CC_id]->Nid_cell = enb_properties->properties[enb_id]->Nid_cell[CC_id]; + frame_parms[CC_id]->N_RB_DL = enb_properties->properties[enb_id]->N_RB_DL[CC_id]; + frame_parms[CC_id]->N_RB_UL = enb_properties->properties[enb_id]->N_RB_DL[CC_id]; + frame_parms[CC_id]->nb_antennas_tx = enb_properties->properties[enb_id]->nb_antennas_tx[CC_id]; + frame_parms[CC_id]->nb_antenna_ports_eNB = enb_properties->properties[enb_id]->nb_antenna_ports[CC_id]; + frame_parms[CC_id]->nb_antennas_rx = enb_properties->properties[enb_id]->nb_antennas_rx[CC_id]; + + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_ConfigIndex = enb_properties->properties[enb_id]->prach_config_index[CC_id]; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset = enb_properties->properties[enb_id]->prach_freq_offset[CC_id]; + + frame_parms[CC_id]->mode1_flag = (frame_parms[CC_id]->nb_antenna_ports_eNB == 1) ? 1 : 0; + frame_parms[CC_id]->threequarter_fs = threequarter_fs; + + + for (k = 0 ; k < 4; k++) { + downlink_frequency[CC_id][k] = enb_properties->properties[enb_id]->downlink_frequency[CC_id]; + uplink_frequency_offset[CC_id][k] = enb_properties->properties[enb_id]->uplink_frequency_offset[CC_id]; + rx_gain[CC_id][k] = (double)enb_properties->properties[enb_id]->rx_gain[CC_id]; + tx_gain[CC_id][k] = (double)enb_properties->properties[enb_id]->tx_gain[CC_id]; + } + + printf("Downlink frequency/ uplink offset of CC_id %d set to %ju/%d\n", CC_id, + enb_properties->properties[enb_id]->downlink_frequency[CC_id], + enb_properties->properties[enb_id]->uplink_frequency_offset[CC_id]); + + init_ul_hopping(frame_parms[CC_id]); + init_frame_parms(frame_parms[CC_id],1); + // phy_init_top(frame_parms[CC_id]); + phy_init_lte_top(frame_parms[CC_id]); + } // CC_id +} + #if T_TRACER int T_wait = 1; /* by default we wait for the tracer */ int T_port = 2021; /* default port to listen to to wait for the tracer */ @@ -1395,6 +1422,19 @@ void init_openair0() { } } +/* check the state : either continue or wait for a command to start/stop the eNB + * if needed override the current configuration parameters, such as + * frequencies, bands, power, bandwidth + */ +static void ltesm_wait_reconfig_cmd(void) +{ + LOG_I(ENB_APP, "LTE Softmodem wait reconfiguration command\n"); + + while (node_control_state == ENB_WAIT_RECONFIGURATION_CMD) { + usleep(200000); + } +} + int main( int argc, char **argv ) { int i,j,k,aa,re; #if defined (XFORMS) @@ -1405,6 +1445,8 @@ int main( int argc, char **argv ) { uint8_t abstraction_flag=0; uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2; + PHY_vars_eNB_g=NULL; + #if defined (XFORMS) int ret; #endif @@ -1570,11 +1612,6 @@ int main( int argc, char **argv ) { LOG_I(PHY,"Set nb_rx_antenna %d , nb_tx_antenna %d \n",frame_parms[CC_id]->nb_antennas_rx, frame_parms[CC_id]->nb_antennas_tx); } - - init_ul_hopping(frame_parms[CC_id]); - init_frame_parms(frame_parms[CC_id],1); - // phy_init_top(frame_parms[CC_id]); - phy_init_lte_top(frame_parms[CC_id]); } @@ -1586,6 +1623,14 @@ int main( int argc, char **argv ) { // N_ZC = (prach_fmt <4)?839:139; } + create_enb_app_task(UE_flag ? 0 : 1); + ltesm_wait_reconfig_cmd (); + // reconfigure_enb: 0 for wait, 1 for skip, and other values to reconfigure + for (i=0; (i < NB_eNB_INST && node_control_state == ENB_NORMAL_OPERATION ) ; i++){ + reconfigure_enb_params(i); + printf("[ENB_APP] Reconfigured eNB module %d - continue\n", i); + } + if (UE_flag==1) { NB_UE_INST=1; NB_INST=1; From c62be7a101ce487b329e889e2746c8c94afd880b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 8 Dec 2017 15:28:28 +0100 Subject: [PATCH 107/284] Uniform messages of exiting threads --- common/utils/msc/msc.c | 1 + openair2/ENB_APP/enb_app.c | 1 + openair2/ENB_APP/flexran_agent.c | 1 + openair2/RRC/LITE/rrc_UE.c | 1 + openair2/RRC/LITE/rrc_eNB.c | 1 + openair2/X2AP/x2ap.c | 1 + openair3/GTPV1-U/gtpv1u_eNB.c | 1 + openair3/GTPV1-U/gtpv1u_task.c | 1 + openair3/S1AP/s1ap_eNB.c | 1 + openair3/SCTP/sctp_eNB_task.c | 1 + openair3/TEST/EPC_TEST/play_scenario_s1ap.c | 1 + openair3/UDP/udp_eNB_task.c | 2 +- targets/RT/USER/lte-enb.c | 24 +++++++++++++++++---- targets/RT/USER/lte-softmodem.c | 3 ++- 14 files changed, 34 insertions(+), 6 deletions(-) diff --git a/common/utils/msc/msc.c b/common/utils/msc/msc.c index 7de2a47f98..83f3beb512 100644 --- a/common/utils/msc/msc.c +++ b/common/utils/msc/msc.c @@ -99,6 +99,7 @@ void *msc_task(void *args_p) break; case TERMINATE_MESSAGE: { + fprintf(stderr, " *** Exiting MSC thread\n"); timer_remove(timer_id); msc_end(); itti_exit_task(); diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index 4a5981f509..bada59ffec 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -361,6 +361,7 @@ void *eNB_app_task(void *args_p) switch (ITTI_MSG_ID(msg_p)) { case TERMINATE_MESSAGE: + LOG_W(TASK_ENB_APP, " *** Exiting ENB_APP thread\n"); itti_exit_task (); break; diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c index 23ac8f02ac..8af071527f 100644 --- a/openair2/ENB_APP/flexran_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -74,6 +74,7 @@ void *flexran_agent_task(void *args){ switch (ITTI_MSG_ID(msg_p)) { case TERMINATE_MESSAGE: + LOG_W(FLEXRAN_AGENT, " *** Exiting FLEXRAN thread\n"); itti_exit_task (); break; diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index 6798212fb2..7f0c3a8800 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -4286,6 +4286,7 @@ void *rrc_ue_task( void *args_p ) switch (ITTI_MSG_ID(msg_p)) { case TERMINATE_MESSAGE: + LOG_W(RRC, " *** Exiting RRC thread\n"); itti_exit_task (); break; diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index aaf12da175..c441c102e3 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -5621,6 +5621,7 @@ rrc_enb_task( switch (ITTI_MSG_ID(msg_p)) { case TERMINATE_MESSAGE: + LOG_W(RRC, " *** Exiting RRC thread\n"); itti_exit_task(); break; diff --git a/openair2/X2AP/x2ap.c b/openair2/X2AP/x2ap.c index 699ad5ddbf..6af71e5ca5 100644 --- a/openair2/X2AP/x2ap.c +++ b/openair2/X2AP/x2ap.c @@ -49,6 +49,7 @@ void *x2ap_task(void *arg) switch (ITTI_MSG_ID(received_msg)) { case TERMINATE_MESSAGE: + X2AP_WARN(" *** Exiting X2AP thread\n"); itti_exit_task(); break; diff --git a/openair3/GTPV1-U/gtpv1u_eNB.c b/openair3/GTPV1-U/gtpv1u_eNB.c index e273ac0712..d0a3bbd342 100644 --- a/openair3/GTPV1-U/gtpv1u_eNB.c +++ b/openair3/GTPV1-U/gtpv1u_eNB.c @@ -1132,6 +1132,7 @@ void *gtpv1u_eNB_task(void *args) hashtable_destroy (gtpv1u_data_g.teid_mapping); } + LOG_W(GTPU, " *** Exiting GTPU thread\n"); itti_exit_task(); } break; diff --git a/openair3/GTPV1-U/gtpv1u_task.c b/openair3/GTPV1-U/gtpv1u_task.c index f9397f21ca..bea003a655 100644 --- a/openair3/GTPV1-U/gtpv1u_task.c +++ b/openair3/GTPV1-U/gtpv1u_task.c @@ -423,6 +423,7 @@ static void *gtpv1u_thread(void *args) switch (ITTI_MSG_ID(received_message_p)) { case TERMINATE_MESSAGE: { + GTPU_WARN(" *** Exiting GTPU thread\n"); itti_exit_task(); } break; diff --git a/openair3/S1AP/s1ap_eNB.c b/openair3/S1AP/s1ap_eNB.c index 65b82055a3..b96d9103f4 100644 --- a/openair3/S1AP/s1ap_eNB.c +++ b/openair3/S1AP/s1ap_eNB.c @@ -310,6 +310,7 @@ void *s1ap_eNB_task(void *arg) switch (ITTI_MSG_ID(received_msg)) { case TERMINATE_MESSAGE: + S1AP_WARN(" *** Exiting S1AP thread\n"); itti_exit_task(); break; diff --git a/openair3/SCTP/sctp_eNB_task.c b/openair3/SCTP/sctp_eNB_task.c index 1f166af74c..758cbd5aa5 100644 --- a/openair3/SCTP/sctp_eNB_task.c +++ b/openair3/SCTP/sctp_eNB_task.c @@ -841,6 +841,7 @@ void *sctp_eNB_task(void *arg) break; case TERMINATE_MESSAGE: + SCTP_WARN("*** Exiting SCTP thread\n"); itti_exit_task(); break; diff --git a/openair3/TEST/EPC_TEST/play_scenario_s1ap.c b/openair3/TEST/EPC_TEST/play_scenario_s1ap.c index f1bbe393be..d2247f70a8 100644 --- a/openair3/TEST/EPC_TEST/play_scenario_s1ap.c +++ b/openair3/TEST/EPC_TEST/play_scenario_s1ap.c @@ -1089,6 +1089,7 @@ void *et_s1ap_eNB_task(void *arg) switch (ITTI_MSG_ID(received_msg)) { case TERMINATE_MESSAGE: + S1AP_WARN("*** Exiting S1AP thread\n"); itti_exit_task(); break; diff --git a/openair3/UDP/udp_eNB_task.c b/openair3/UDP/udp_eNB_task.c index b8b6b897a7..94c5612ec6 100644 --- a/openair3/UDP/udp_eNB_task.c +++ b/openair3/UDP/udp_eNB_task.c @@ -389,7 +389,7 @@ void *udp_eNB_task(void *args_p) break; case TERMINATE_MESSAGE: { - LOG_W(UDP_, "Received TERMINATE_MESSAGE\n"); + LOG_W(UDP_, " *** Exiting UDP thread\n"); itti_exit_task(); } break; diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 5cbe0fe1d4..2223855419 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -643,7 +643,9 @@ static void* eNB_thread_rxtx( void* param ) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); - printf( "Exiting eNB thread RXn_TXnp4\n"); +#ifdef DEBUG_THREADS + printf(" *** Exiting eNB thread RXn_TXnp4\n"); +#endif eNB_thread_rxtx_status = 0; return &eNB_thread_rxtx_status; @@ -907,6 +909,10 @@ static void* eNB_thread_asynch_rxtx( void* param ) { } +#ifdef DEBUG_THREADS + printf(" *** Exiting eNB asynch rxtx thread\n"); +#endif + eNB_thread_asynch_rxtx_status=0; return(&eNB_thread_asynch_rxtx_status); } @@ -1372,6 +1378,10 @@ void *eNB_thread_synch(void *arg) { lte_sync_time_free(); +#ifdef DEBUG_THREADS + printf(" *** Exiting eNB synch thread\n"); +#endif + return NULL; } @@ -1484,7 +1494,9 @@ static void* eNB_thread_FH( void* param ) { rt_sleep_ns(800000LL); } - printf( "Exiting FH thread \n"); +#ifdef DEBUG_THREADS + printf(" *** Exiting FH thread \n"); +#endif eNB_thread_FH_status = 0; return &eNB_thread_FH_status; @@ -1518,7 +1530,9 @@ static void* eNB_thread_prach( void* param ) { if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break; } - printf( "Exiting eNB thread PRACH\n"); +#ifdef DEBUG_THREADS + printf(" *** Exiting eNB thread PRACH\n"); +#endif eNB_thread_prach_status = 0; return &eNB_thread_prach_status; @@ -1688,7 +1702,9 @@ static void* eNB_thread_single( void* param ) { } - printf( "Exiting eNB_single thread \n"); +#ifdef DEBUG_THREADS + printf(" *** Exiting eNB_single thread\n"); +#endif eNB_thread_single_status = 0; return &eNB_thread_single_status; diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 042f77eea7..ed0dd20360 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -558,7 +558,7 @@ void *l2l1_task(void *arg) { break; case TERMINATE_MESSAGE: - printf("received terminate message\n"); + LOG_W(TASK_L2L1, " *** Exiting L2L1 thread\n"); oai_exit=1; itti_exit_task (); break; @@ -579,6 +579,7 @@ void *l2l1_task(void *arg) { switch (ITTI_MSG_ID(message_p)) { case TERMINATE_MESSAGE: + LOG_W(TASK_L2L1, " *** Exiting L2L1 thread\n"); oai_exit=1; itti_exit_task (); break; From c313dff2ad9b37a23458d63f1431197c01d7e842 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 11 Dec 2017 11:32:06 +0100 Subject: [PATCH 108/284] better logging, remove warnings --- openair2/ENB_APP/enb_app.c | 2 +- .../ENB_APP/flexran_agent_common_internal.c | 25 +++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index bada59ffec..89e20889cb 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -330,7 +330,7 @@ void *eNB_app_task(void *args_p) // set again the ran api vars for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { - printf("\n set again enb vars %d\n", enb_id); + LOG_I(ENB_APP, "set again enb vars %d\n", enb_id); flexran_set_enb_vars(enb_id, RAN_LTE_OAI); } diff --git a/openair2/ENB_APP/flexran_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c index c883523855..e2ee656b23 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.c +++ b/openair2/ENB_APP/flexran_agent_common_internal.c @@ -216,35 +216,34 @@ int parse_enb_config_parameters(mid_t mod_id, yaml_parser_t *parser) { goto error; } // Check what key needs to be set - LOG_I(ENB_APP, "Setting parameter %s\n", event.data.scalar.value); if (strcmp((char *) event.data.scalar.value, "dl_freq") == 0) { - if (!yaml_parser_parse(parser, &event)) - goto error; + if (!yaml_parser_parse(parser, &event)) + goto error; flexran_agent_set_operating_dl_freq(mod_id, 0, strtol((char *) event.data.scalar.value, &endptr, 10)); - LOG_I(ENB_APP, "Setting parameter value %s\n", event.data.scalar.value); + LOG_I(ENB_APP, "Setting dl_freq to %s\n", event.data.scalar.value); } else if (strcmp((char *) event.data.scalar.value, "ul_freq_offset") == 0) { - if (!yaml_parser_parse(parser, &event)) - goto error; + if (!yaml_parser_parse(parser, &event)) + goto error; flexran_agent_set_operating_ul_freq(mod_id, 0, strtol((char *) event.data.scalar.value, &endptr, 10)); - LOG_I(ENB_APP, "Setting parameter value %s\n", event.data.scalar.value); + LOG_I(ENB_APP, "Setting ul_freq_offset to %s\n", event.data.scalar.value); } else if (strcmp((char *) event.data.scalar.value, "bandwidth") == 0) { - if (!yaml_parser_parse(parser, &event)) - goto error; + if (!yaml_parser_parse(parser, &event)) + goto error; flexran_agent_set_operating_bandwidth(mod_id, 0, strtol((char *) event.data.scalar.value, &endptr, 10)); - LOG_I(ENB_APP, "Setting parameter value %s\n", event.data.scalar.value); + LOG_I(ENB_APP, "Setting bandwidth to %s\n", event.data.scalar.value); } else if (strcmp((char *) event.data.scalar.value, "frame_type") == 0) { - if (!yaml_parser_parse(parser, &event)) - goto error; + if (!yaml_parser_parse(parser, &event)) + goto error; flexran_agent_set_operating_frame_type (mod_id, 0, strtol((char *) event.data.scalar.value, &endptr, 10)); - LOG_I(ENB_APP, "Setting parameter value %s\n", event.data.scalar.value); + LOG_I(ENB_APP, "Setting frame_type to %s\n", event.data.scalar.value); }else { // not supported tag goto error; } From 1aa5d2930a61fc499b0233758ce7c27950667cdc Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 11 Dec 2017 11:37:10 +0100 Subject: [PATCH 109/284] Handle TERMINATE_MESSAGE in TASK_MAC --- openair2/LAYER2/MAC/eNB_scheduler.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index f46b9deb8d..60a6e22125 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -323,6 +323,11 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; #endif + case TERMINATE_MESSAGE: + LOG_W(MAC, "+++ Exiting MAC thread\n"); + itti_exit_task (); + break; + default: LOG_E(MAC, "Received unexpected message %s\n", msg_name); break; From ea65ddad2cb2fa33a6c4eb935a47d20b32bd0274 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 11 Dec 2017 15:31:21 +0100 Subject: [PATCH 110/284] fill PHY_vars_eNB_g in own function --- targets/RT/USER/lte-softmodem.c | 120 ++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 54 deletions(-) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index ed0dd20360..d36907bba7 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1423,6 +1423,70 @@ void init_openair0() { } } +void fill_PHY_vars_eNB_g(uint8_t abstraction_flag, uint8_t beta_ACK, uint8_t beta_RI, uint8_t beta_CQI) +{ + int CC_id, i, j, k, re; + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + PHY_vars_eNB_g[0][CC_id] = init_lte_eNB(frame_parms[CC_id], + 0, + frame_parms[CC_id]->Nid_cell, + node_function[CC_id], + abstraction_flag); + PHY_vars_eNB_g[0][CC_id]->ue_dl_rb_alloc = 0x1fff; + PHY_vars_eNB_g[0][CC_id]->target_ue_dl_mcs = target_dl_mcs; + PHY_vars_eNB_g[0][CC_id]->ue_ul_nb_rb = 6; + PHY_vars_eNB_g[0][CC_id]->target_ue_ul_mcs = target_ul_mcs; + // initialization for phy-test + for (k = 0; k < NUMBER_OF_UE_MAX; k++) { + PHY_vars_eNB_g[0][CC_id]->transmission_mode[k] = transmission_mode; + if (transmission_mode == 7) + lte_gold_ue_spec_port5(PHY_vars_eNB_g[0][CC_id]->lte_gold_uespec_port5_table[k], + frame_parms[CC_id]->Nid_cell, + 0x1235+k); + } + if ((transmission_mode == 1) || (transmission_mode == 7)) { + for (j = 0; j < frame_parms[CC_id]->nb_antennas_tx; j++) + for (re = 0; re < frame_parms[CC_id]->ofdm_symbol_size; re++) + PHY_vars_eNB_g[0][CC_id]->common_vars.beam_weights[0][0][j][re] = 0x00007fff / frame_parms[CC_id]->nb_antennas_tx; + } + + if (phy_test==1) + PHY_vars_eNB_g[0][CC_id]->mac_enabled = 0; + else + PHY_vars_eNB_g[0][CC_id]->mac_enabled = 1; + + if (PHY_vars_eNB_g[0][CC_id]->mac_enabled == 0) { //set default parameters for testing mode + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + PHY_vars_eNB_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_ACK_Index = beta_ACK; + PHY_vars_eNB_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_RI_Index = beta_RI; + PHY_vars_eNB_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_CQI_Index = beta_CQI; + + PHY_vars_eNB_g[0][CC_id]->scheduling_request_config[i].sr_PUCCH_ResourceIndex = i; + PHY_vars_eNB_g[0][CC_id]->scheduling_request_config[i].sr_ConfigIndex = 7+(i%3); + PHY_vars_eNB_g[0][CC_id]->scheduling_request_config[i].dsr_TransMax = sr_n4; + } + } + + compute_prach_seq(&PHY_vars_eNB_g[0][CC_id]->frame_parms.prach_config_common, + PHY_vars_eNB_g[0][CC_id]->frame_parms.frame_type, + PHY_vars_eNB_g[0][CC_id]->X_u); + + + PHY_vars_eNB_g[0][CC_id]->rx_total_gain_dB = (int)rx_gain[CC_id][0]; + + if (frame_parms[CC_id]->frame_type == FDD) { + PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 0; + } else { + if (frame_parms[CC_id]->N_RB_DL == 100) + PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624; + else if (frame_parms[CC_id]->N_RB_DL == 50) + PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624/2; + else if (frame_parms[CC_id]->N_RB_DL == 25) + PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624/4; + } + } +} + /* check the state : either continue or wait for a command to start/stop the eNB * if needed override the current configuration parameters, such as * frequencies, bands, power, bandwidth @@ -1437,7 +1501,7 @@ static void ltesm_wait_reconfig_cmd(void) } int main( int argc, char **argv ) { - int i,j,k,aa,re; + int i,aa; #if defined (XFORMS) void *status; #endif @@ -1710,59 +1774,7 @@ int main( int argc, char **argv ) { PHY_vars_eNB_g = malloc(sizeof(PHY_VARS_eNB**)); PHY_vars_eNB_g[0] = malloc(sizeof(PHY_VARS_eNB*)); - for (CC_id=0; CC_idNid_cell,node_function[CC_id],abstraction_flag); - PHY_vars_eNB_g[0][CC_id]->ue_dl_rb_alloc=0x1fff; - PHY_vars_eNB_g[0][CC_id]->target_ue_dl_mcs=target_dl_mcs; - PHY_vars_eNB_g[0][CC_id]->ue_ul_nb_rb=6; - PHY_vars_eNB_g[0][CC_id]->target_ue_ul_mcs=target_ul_mcs; - // initialization for phy-test - for (k=0; ktransmission_mode[k] = transmission_mode; - if (transmission_mode==7) - lte_gold_ue_spec_port5(PHY_vars_eNB_g[0][CC_id]->lte_gold_uespec_port5_table[k],frame_parms[CC_id]->Nid_cell,0x1235+k); - } - if ((transmission_mode==1) || (transmission_mode==7)) { - for (j=0; jnb_antennas_tx; j++) - for (re=0; reofdm_symbol_size; re++) - PHY_vars_eNB_g[0][CC_id]->common_vars.beam_weights[0][0][j][re] = 0x00007fff/frame_parms[CC_id]->nb_antennas_tx; - } - - if (phy_test==1) PHY_vars_eNB_g[0][CC_id]->mac_enabled = 0; - else PHY_vars_eNB_g[0][CC_id]->mac_enabled = 1; - - if (PHY_vars_eNB_g[0][CC_id]->mac_enabled == 0) { //set default parameters for testing mode - for (i=0; ipusch_config_dedicated[i].betaOffset_ACK_Index = beta_ACK; - PHY_vars_eNB_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_RI_Index = beta_RI; - PHY_vars_eNB_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_CQI_Index = beta_CQI; - - PHY_vars_eNB_g[0][CC_id]->scheduling_request_config[i].sr_PUCCH_ResourceIndex = i; - PHY_vars_eNB_g[0][CC_id]->scheduling_request_config[i].sr_ConfigIndex = 7+(i%3); - PHY_vars_eNB_g[0][CC_id]->scheduling_request_config[i].dsr_TransMax = sr_n4; - } - } - - compute_prach_seq(&PHY_vars_eNB_g[0][CC_id]->frame_parms.prach_config_common, - PHY_vars_eNB_g[0][CC_id]->frame_parms.frame_type, - PHY_vars_eNB_g[0][CC_id]->X_u); - - - PHY_vars_eNB_g[0][CC_id]->rx_total_gain_dB = (int)rx_gain[CC_id][0]; - - if (frame_parms[CC_id]->frame_type==FDD) { - PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 0; - } else { - if (frame_parms[CC_id]->N_RB_DL == 100) - PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624; - else if (frame_parms[CC_id]->N_RB_DL == 50) - PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624/2; - else if (frame_parms[CC_id]->N_RB_DL == 25) - PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624/4; - } - - } - + fill_PHY_vars_eNB_g(abstraction_flag, beta_ACK, beta_RI, beta_CQI); NB_eNB_INST=1; NB_INST=1; From e88a3cdf469f04b67158625e5a663dc29fad299e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 12 Dec 2017 10:56:40 +0100 Subject: [PATCH 111/284] bugfix ITTI: clean up in itti_exit_task() - when exiting task, the task is set as "not configured" - this permits to start a task again --- common/utils/itti/intertask_interface.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/common/utils/itti/intertask_interface.c b/common/utils/itti/intertask_interface.c index 28267900af..59209994b6 100644 --- a/common/utils/itti/intertask_interface.c +++ b/common/utils/itti/intertask_interface.c @@ -775,15 +775,19 @@ void itti_mark_task_ready(task_id_t task_id) void itti_exit_task(void) { -#if defined(OAI_EMU) || defined(RTAI) task_id_t task_id = itti_get_current_task_id(); + thread_id_t thread_id = TASK_GET_THREAD_ID(task_id); +#if defined(OAI_EMU) || defined(RTAI) if (task_id > TASK_UNKNOWN) { VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_ITTI_RECV_MSG, __sync_and_and_fetch (&itti_desc.vcd_receive_msg, ~(1L << task_id))); } - #endif + + itti_desc.threads[thread_id].task_state = TASK_STATE_NOT_CONFIGURED; + itti_desc.created_tasks--; + ITTI_DEBUG(ITTI_DEBUG_EXIT, "Thread for task %s (%d) exits\n", itti_get_task_name(task_id), task_id); pthread_exit (NULL); } From c619f6eff76234d2efd14d29e99d8132dd768946 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 12 Dec 2017 10:03:06 +0100 Subject: [PATCH 112/284] Feature: Provide restart for lte-softmodem - {restart,stop}_L1L2() in lte-softmodem.c - add function start_phy_rrc() in enb_app.{c,h}, accessible from outside - will be used to restart PHY and RRC when lte-softmodem is restarted use only one FlexRAN wait function --- openair2/ENB_APP/enb_app.c | 30 ++-- openair2/ENB_APP/enb_app.h | 7 + .../ENB_APP/flexran_agent_common_internal.c | 28 +++- targets/RT/USER/lte-softmodem.c | 133 ++++++++++++++++-- targets/RT/USER/lte-softmodem.h | 3 + 5 files changed, 178 insertions(+), 23 deletions(-) diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index 89e20889cb..be0b88acff 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -57,14 +57,13 @@ extern unsigned char NB_eNB_INST; #endif extern volatile int node_control_state; -static void enb_app_wait_reconfig_cmd (void) +void ltesm_wait_reconfig_cmd(void) { - LOG_I(ENB_APP, "ENB APP await reconfiguration command\n"); - - while (node_control_state == ENB_WAIT_RECONFIGURATION_CMD) { + LOG_I(ENB_APP, "LTE Softmodem wait reconfiguration command\n"); + + while (node_control_state == ENB_WAIT_RECONFIGURATION_CMD) { usleep(200000); } - sleep(2); // wait for createing other tasks } #if defined(ENABLE_ITTI) @@ -202,6 +201,15 @@ static void configure_rrc(uint32_t enb_id, const Enb_properties_array_t *enb_pro itti_send_msg_to_task (TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); } +void enb_app_start_phy_rrc(uint32_t enb_id_start, uint32_t enb_id_end) +{ + Enb_properties_array_t *enb_properties_p = enb_config_get(); + for (uint32_t enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { + configure_phy(enb_id, enb_properties_p); + configure_rrc(enb_id, enb_properties_p); + } +} + /*------------------------------------------------------------------------------*/ # if defined(ENABLE_USE_MME) static uint32_t eNB_app_register(uint32_t enb_id_start, uint32_t enb_id_end, const Enb_properties_array_t *enb_properties) @@ -325,8 +333,10 @@ void *eNB_app_task(void *args_p) for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { flexran_agent_start(enb_id, enb_properties_p); } - // wait for config comd from the controller/network app - enb_app_wait_reconfig_cmd(); + // wait for config comd from the controller/network app plus some time so + // that the other Tasks are in place + ltesm_wait_reconfig_cmd(); + sleep(2); // set again the ran api vars for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { @@ -336,11 +346,7 @@ void *eNB_app_task(void *args_p) #endif - for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { - configure_phy(enb_id, enb_properties_p); - configure_rrc(enb_id, enb_properties_p); - } - + enb_app_start_phy_rrc(enb_id_start, enb_id_end); # if defined(ENABLE_USE_MME) /* Try to register each eNB */ diff --git a/openair2/ENB_APP/enb_app.h b/openair2/ENB_APP/enb_app.h index 8e3c28760b..be5adfbb34 100644 --- a/openair2/ENB_APP/enb_app.h +++ b/openair2/ENB_APP/enb_app.h @@ -30,8 +30,15 @@ #ifndef ENB_APP_H_ #define ENB_APP_H_ +#include void *eNB_app_task(void *args_p); +/* needed for flexran: start PHY and RRC when restarting */ +void enb_app_start_phy_rrc(uint32_t enb_id_start, uint32_t enb_id_end); + +/* wait that FlexRAN left state ENB_WAIT_RECONFIGURATION_CMD */ +void ltesm_wait_reconfig_cmd(void); + #endif /* ENB_APP_H_ */ diff --git a/openair2/ENB_APP/flexran_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c index e2ee656b23..e77557e9ee 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.c +++ b/openair2/ENB_APP/flexran_agent_common_internal.c @@ -31,8 +31,33 @@ #include "flexran_agent_common_internal.h" #include "flexran_agent_mac_internal.h" + +/* the following is needed to soft-restart the lte-softmodem */ +#include "targets/RT/USER/lte-softmodem.h" +#include "assertions.h" +#include "enb_app.h" extern volatile int node_control_state; +void handle_reconfiguration(mid_t mod_id) +{ + /* NOTE: this function might be extended by using stop_modem() + * to halt the modem so that it can later be resumed */ + + if (ENB_NORMAL_OPERATION != node_control_state) { + node_control_state = ENB_NORMAL_OPERATION; + } else { + if (stop_L1L2(mod_id) < 0 || restart_L1L2(mod_id) < 0) { + LOG_E(ENB_APP, "could not restart, killing lte-softmodem\n"); + /* shutdown the whole lte-softmodem */ + itti_terminate_tasks(TASK_PHY_ENB); + return; + } + + enb_app_start_phy_rrc(mod_id, mod_id+1); + LOG_I(ENB_APP, "lte-softmodem restart succeeded\n"); + } +} + int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy_length) { yaml_parser_t parser; @@ -72,8 +97,7 @@ int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy if (parse_enb_id(mod_id, &parser) == -1) { goto error; } else { // succeful parse and setting - node_control_state= ENB_NORMAL_OPERATION; - LOG_I(ENB_APP, "Successful parsed config for enb system, entering normal state\n"); + handle_reconfiguration(mod_id); } } else if (strcmp((char *) event.data.scalar.value, "mac") == 0) { LOG_D(ENB_APP, "This is intended for the mac system\n"); diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index d36907bba7..b89c82aff4 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1487,19 +1487,129 @@ void fill_PHY_vars_eNB_g(uint8_t abstraction_flag, uint8_t beta_ACK, uint8_t bet } } -/* check the state : either continue or wait for a command to start/stop the eNB - * if needed override the current configuration parameters, such as - * frequencies, bands, power, bandwidth +#if defined(ENABLE_ITTI) && defined(FLEXRAN_AGENT_SB_IF) +/* + * helper function to terminate a certain ITTI task */ -static void ltesm_wait_reconfig_cmd(void) +void terminate_task(task_id_t task_id, mid_t mod_id) { - LOG_I(ENB_APP, "LTE Softmodem wait reconfiguration command\n"); - - while (node_control_state == ENB_WAIT_RECONFIGURATION_CMD) { - usleep(200000); - } + LOG_I(ENB_APP, "sending TERMINATE_MESSAGE to task %s (%d)\n", itti_get_task_name(task_id), task_id); + MessageDef *msg; + msg = itti_alloc_new_message (ENB_APP, TERMINATE_MESSAGE); + itti_send_msg_to_task (task_id, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg); } +int stop_L1L2(int enb_id) +{ + int CC_id; + + LOG_W(ENB_APP, "stopping lte-softmodem\n"); + + /* stop trx devices */ + for(CC_id=0; CC_idrfdevice.trx_stop_func) { + LOG_I(ENB_APP, "stopping PHY_vars_eNB_g[0][%d]->rfdevice (via trx_stop_func())\n", CC_id); + PHY_vars_eNB_g[0][CC_id]->rfdevice.trx_stop_func(&PHY_vars_eNB_g[0][CC_id]->rfdevice); + } + if (PHY_vars_eNB_g[0][CC_id]->ifdevice.trx_stop_func) { + LOG_I(ENB_APP, "stopping PHY_vars_eNB_g[0][%d]->ifdevice (via trx_stop_func())\n", CC_id); + PHY_vars_eNB_g[0][CC_id]->ifdevice.trx_stop_func(&PHY_vars_eNB_g[0][CC_id]->ifdevice); + } + } + + /* these tasks need to pick up new configuration */ + terminate_task(TASK_RRC_ENB, enb_id); + terminate_task(TASK_L2L1, enb_id); + oai_exit = 1; + LOG_W(ENB_APP, "calling kill_eNB_proc() for instance %d\n", enb_id); + kill_eNB_proc(enb_id); + /* give some time for all threads */ + sleep(1); + return 0; +} + +/* + * Restart the lte-softmodem. + * This function checks whether we are in ENB_NORMAL_OPERATION (defined by + * FlexRAN). If yes, first stop L1/L2/L3, then resume. + */ +int restart_L1L2(int enb_id) +{ + int i, aa, CC_id; + /* needed for fill_PHY_vars_eNB_g(), defined locally in main(); + * abstraction flag is needed too, but defined both globally and in main () */ + uint8_t beta_ACK = 0, beta_RI = 0, beta_CQI = 2; + /* needed for macphy_init() */ + int eMBMS_active = 0; + + LOG_W(ENB_APP, "restarting lte-softmodem\n"); + + /* block threads */ + sync_var = -1; + oai_exit = 0; + + reconfigure_enb_params(enb_id); /* set frame parameters from configuration */ + + /* PHY_vars_eNB_g will be filled by init_lte_eNB(), so free and + * let the data structure be filled again */ + for (CC_id=0; CC_idframe_parms = frame_parms[0]; + mac_xface->macphy_init(eMBMS_active,(uecap_xer_in==1)?uecap_xer:NULL,0,0); + + LOG_I(ENB_APP, "attempting to create ITTI tasks\n"); + if (itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL) < 0) { + LOG_E(RRC, "Create task for RRC eNB failed\n"); + return -1; + } else { + LOG_I(RRC, "Re-created task for RRC eNB successfully\n"); + } + if (itti_create_task (TASK_L2L1, l2l1_task, NULL) < 0) { + LOG_E(PDCP, "Create task for L2L1 failed\n"); + return -1; + } else { + LOG_I(PDCP, "Re-created task for L2L1 successfully\n"); + } + + /* TODO XForms here */ + + printf("Initializing eNB threads\n"); + init_eNB(node_function, node_timing, 1, eth_params, single_thread_flag, wait_for_sync); + for(CC_id=0; CC_idrf_map.card=0; + PHY_vars_eNB_g[0][CC_id]->rf_map.chain=CC_id+chain_offset; + } + + mlockall(MCL_CURRENT | MCL_FUTURE); + + printf("Setting eNB buffer to all-RX\n"); + // Set LSBs for antenna switch (ExpressMIMO) + for (CC_id=0; CC_idhw_timing_advance = 0; + for (i=0; isamples_per_tti*10; i++) + for (aa=0; aanb_antennas_tx; aa++) + PHY_vars_eNB_g[0][CC_id]->common_vars.txdata[0][aa][i] = 0x00010001; + } + + printf("Sending sync to all threads\n"); + + pthread_mutex_lock(&sync_mutex); + sync_var=0; + pthread_cond_broadcast(&sync_cond); + pthread_mutex_unlock(&sync_mutex); + + return 0; +} +#endif + int main( int argc, char **argv ) { int i,aa; #if defined (XFORMS) @@ -1689,7 +1799,12 @@ int main( int argc, char **argv ) { } create_enb_app_task(UE_flag ? 0 : 1); + +#ifdef FLEXRAN_AGENT_SB_IF + /* wait command for flexran agent: only start when configuration received */ ltesm_wait_reconfig_cmd (); +#endif + // reconfigure_enb: 0 for wait, 1 for skip, and other values to reconfigure for (i=0; (i < NB_eNB_INST && node_control_state == ENB_NORMAL_OPERATION ) ; i++){ reconfigure_enb_params(i); diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index 4d9d145c68..a0883c3d59 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -89,4 +89,7 @@ extern void init_fep_thread(PHY_VARS_eNB *, pthread_attr_t *); extern void init_td_thread(PHY_VARS_eNB *, pthread_attr_t *); extern void init_te_thread(PHY_VARS_eNB *, pthread_attr_t *); +extern int stop_L1L2(int enb_id); +extern int restart_L1L2(int enb_id); + #endif From eb2dfa1b70db81fa77df72f2474982af973b0c9f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 12 Dec 2017 16:59:46 +0100 Subject: [PATCH 113/284] kill_eNB_proc(): join all PHY threads --- targets/RT/USER/lte-enb.c | 43 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 2223855419..9bde18df40 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -1754,6 +1754,7 @@ void init_eNB_proc(int inst) { pthread_mutex_init( &proc->mutex_prach, NULL); pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL); pthread_mutex_init( &proc->mutex_synch,NULL); + pthread_mutex_init( &proc->mutex_FH, NULL); pthread_cond_init( &proc->cond_prach, NULL); pthread_cond_init( &proc->cond_FH, NULL); @@ -1862,30 +1863,68 @@ void kill_eNB_proc(int inst) { printf( "Killing TX CC_id %d thread %d\n", CC_id, i ); #endif - proc_rxtx[0].instance_cnt_rxtx = 0; // FIXME data race! - proc_rxtx[1].instance_cnt_rxtx = 0; // FIXME data race! + pthread_mutex_lock(&proc_rxtx[0].mutex_rxtx); + proc_rxtx[0].instance_cnt_rxtx = 0; + pthread_mutex_unlock(&proc_rxtx[0].mutex_rxtx); + pthread_mutex_lock(&proc_rxtx[1].mutex_rxtx); + proc_rxtx[1].instance_cnt_rxtx = 0; + pthread_mutex_unlock(&proc_rxtx[1].mutex_rxtx); + pthread_mutex_lock(&PHY_vars_eNB_g[0][CC_id]->proc.mutex_synch); + PHY_vars_eNB_g[0][CC_id]->proc.instance_cnt_synch = 1; + pthread_mutex_unlock(&PHY_vars_eNB_g[0][CC_id]->proc.mutex_synch); proc->instance_cnt_prach = 0; proc->instance_cnt_FH = 0; pthread_cond_signal( &proc_rxtx[0].cond_rxtx ); pthread_cond_signal( &proc_rxtx[1].cond_rxtx ); pthread_cond_signal( &proc->cond_prach ); pthread_cond_signal( &proc->cond_FH ); + pthread_cond_signal( &proc->cond_asynch_rxtx ); + pthread_cond_signal( &proc->cond_synch ); pthread_cond_broadcast(&sync_phy_proc.cond_phy_proc_tx); +#ifdef DEBUG_THREADS + printf("joining pthread_FH\n"); +#endif pthread_join( proc->pthread_FH, (void**)&status ); pthread_mutex_destroy( &proc->mutex_FH ); pthread_cond_destroy( &proc->cond_FH ); +#ifdef DEBUG_THREADS + printf("joining pthread_prach\n"); +#endif pthread_join( proc->pthread_prach, (void**)&status ); pthread_mutex_destroy( &proc->mutex_prach ); pthread_cond_destroy( &proc->cond_prach ); int i; for (i=0;i<2;i++) { +#ifdef DEBUG_THREADS + printf("joining pthread_rxtx\n"); +#endif pthread_join( proc_rxtx[i].pthread_rxtx, (void**)&status ); pthread_mutex_destroy( &proc_rxtx[i].mutex_rxtx ); pthread_cond_destroy( &proc_rxtx[i].cond_rxtx ); } + +#ifdef DEBUG_THREADS + printf("joining pthread_asynch_rxtx\n"); +#endif + pthread_join(proc->pthread_asynch_rxtx, (void**)&status ); + pthread_mutex_destroy(&proc->mutex_asynch_rxtx); + pthread_cond_destroy(&proc->cond_asynch_rxtx); + +#ifdef DEBUG_THREADS + printf("joining pthread_single\n"); +#endif + pthread_join(proc->pthread_single, (void**)&status ); + +#ifdef DEBUG_THREADS + printf("joining pthread_synch\n"); +#endif + pthread_join(proc->pthread_synch, (void**)&status ); + pthread_mutex_destroy(&proc->mutex_synch); + pthread_cond_destroy(&proc->cond_synch); + printf("joined all threads\n"); } } From 730ffc76f4009b8164e17e959ccdf639e3b5631c Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 12 Dec 2017 17:00:43 +0100 Subject: [PATCH 114/284] stop_L1L2(): no sleep, better oai_exit handling --- targets/RT/USER/lte-softmodem.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index b89c82aff4..f881441cdb 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1504,6 +1504,7 @@ int stop_L1L2(int enb_id) int CC_id; LOG_W(ENB_APP, "stopping lte-softmodem\n"); + oai_exit = 1; /* stop trx devices */ for(CC_id=0; CC_id Date: Tue, 12 Dec 2017 18:04:25 +0100 Subject: [PATCH 115/284] Fix multiple compilation warnings --- openair2/ENB_APP/enb_config.c | 4 ++-- openair2/ENB_APP/flexran_agent_net_comm.c | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index 6282523b55..08de05c144 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -2009,7 +2009,7 @@ Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_infinity; }else{ AssertFatal (0, - "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for report_amount choice: r1, r2, r4, r8, r16, r32, r64, infinity !\n", + "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for report_amount choice: r1, r2, r4, r8, r16, r32, r64, infinity !\n", lib_config_file_name_pP, i,rrc_report_amount); } @@ -2041,7 +2041,7 @@ Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_min60; } else { AssertFatal (0, - "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for report_interval choice: 120ms, 240ms, 480ms, 640ms, 1024ms, 2048ms, 5120ms, 10240ms, 1min, 6min, 12", + "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for report_interval choice: 120ms, 240ms, 480ms, 640ms, 1024ms, 2048ms, 5120ms, 10240ms, 1min, 6min, 12", lib_config_file_name_pP, i,rrc_report_interval); } diff --git a/openair2/ENB_APP/flexran_agent_net_comm.c b/openair2/ENB_APP/flexran_agent_net_comm.c index d801bbdda5..e5f9109871 100644 --- a/openair2/ENB_APP/flexran_agent_net_comm.c +++ b/openair2/ENB_APP/flexran_agent_net_comm.c @@ -141,9 +141,9 @@ int flexran_agent_destroy_channel(int channel_id) { for (i = 0; i < NUM_MAX_ENB; i++) { for (j = 0; j < FLEXRAN_AGENT_MAX; j++) { if (agent_channel[i][j] != NULL) { - if (agent_channel[i][j]->channel_id == e->channel_id) { - free(agent_channel[i][j]); - } + if (agent_channel[i][j]->channel_id == e->channel_id) { + free(agent_channel[i][j]); + } } } } @@ -164,7 +164,9 @@ err_code_t flexran_agent_init_channel_container(void) { for (i = 0; i < NUM_MAX_ENB; i++) { for (j = 0; j < FLEXRAN_AGENT_MAX; j++) { - agent_channel[i][j] = malloc(sizeof(flexran_agent_channel_t)); + agent_channel[i][j] = malloc(sizeof(flexran_agent_channel_t)); + if (!agent_channel[i][j]) + return -1; } } From fea641220b7ca7b76715dc933b95fd0a639d8d48 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 12 Dec 2017 16:54:30 +0100 Subject: [PATCH 116/284] Start FlexRAN agent directly, lock with mutex&condition - lock with mutexes - don't start ENB_APP task, but Agent directly and wait in case of reconfiguration --- openair2/ENB_APP/enb_app.c | 31 +------------- openair2/ENB_APP/enb_app.h | 3 -- .../ENB_APP/flexran_agent_common_internal.c | 15 +++++-- targets/COMMON/create_tasks.c | 19 ++++----- targets/COMMON/create_tasks.h | 1 - targets/RT/USER/lte-softmodem.c | 42 ++++++++++++------- targets/RT/USER/lte-softmodem.h | 7 ++++ 7 files changed, 55 insertions(+), 63 deletions(-) diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index be0b88acff..5fe0f741bf 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -50,21 +50,11 @@ # endif #if defined(FLEXRAN_AGENT_SB_IF) -# include "flexran_agent.h" +# include "targets/RT/USER/lte-softmodem.h" #endif extern unsigned char NB_eNB_INST; #endif -extern volatile int node_control_state; - -void ltesm_wait_reconfig_cmd(void) -{ - LOG_I(ENB_APP, "LTE Softmodem wait reconfiguration command\n"); - - while (node_control_state == ENB_WAIT_RECONFIGURATION_CMD) { - usleep(200000); - } -} #if defined(ENABLE_ITTI) @@ -299,7 +289,6 @@ void *eNB_app_task(void *args_p) uint32_t registered_enb; long enb_register_retry_timer_id; # endif - uint32_t enb_id; MessageDef *msg_p = NULL; const char *msg_name = NULL; instance_t instance; @@ -328,24 +317,6 @@ void *eNB_app_task(void *args_p) "Number of eNB is greater than eNB defined in configuration file (%d/%d)!", enb_nb, enb_properties_p->number); -#if defined (FLEXRAN_AGENT_SB_IF) - - for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { - flexran_agent_start(enb_id, enb_properties_p); - } - // wait for config comd from the controller/network app plus some time so - // that the other Tasks are in place - ltesm_wait_reconfig_cmd(); - sleep(2); - - // set again the ran api vars - for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { - LOG_I(ENB_APP, "set again enb vars %d\n", enb_id); - flexran_set_enb_vars(enb_id, RAN_LTE_OAI); - } - -#endif - enb_app_start_phy_rrc(enb_id_start, enb_id_end); # if defined(ENABLE_USE_MME) diff --git a/openair2/ENB_APP/enb_app.h b/openair2/ENB_APP/enb_app.h index be5adfbb34..441693ab31 100644 --- a/openair2/ENB_APP/enb_app.h +++ b/openair2/ENB_APP/enb_app.h @@ -38,7 +38,4 @@ void *eNB_app_task(void *args_p); /* needed for flexran: start PHY and RRC when restarting */ void enb_app_start_phy_rrc(uint32_t enb_id_start, uint32_t enb_id_end); -/* wait that FlexRAN left state ENB_WAIT_RECONFIGURATION_CMD */ -void ltesm_wait_reconfig_cmd(void); - #endif /* ENB_APP_H_ */ diff --git a/openair2/ENB_APP/flexran_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c index e77557e9ee..c2bd396e36 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.c +++ b/openair2/ENB_APP/flexran_agent_common_internal.c @@ -36,25 +36,34 @@ #include "targets/RT/USER/lte-softmodem.h" #include "assertions.h" #include "enb_app.h" -extern volatile int node_control_state; void handle_reconfiguration(mid_t mod_id) { /* NOTE: this function might be extended by using stop_modem() * to halt the modem so that it can later be resumed */ + int do_restart = 0; + pthread_mutex_lock(&mutex_node_ctrl); if (ENB_NORMAL_OPERATION != node_control_state) { node_control_state = ENB_NORMAL_OPERATION; + pthread_cond_broadcast(&cond_node_ctrl); } else { + do_restart = 1; + } + pthread_mutex_unlock(&mutex_node_ctrl); + + if (do_restart) { + clock_t start_ms = 1000 * clock(); + /* operator || enforces sequence points */ if (stop_L1L2(mod_id) < 0 || restart_L1L2(mod_id) < 0) { LOG_E(ENB_APP, "could not restart, killing lte-softmodem\n"); /* shutdown the whole lte-softmodem */ itti_terminate_tasks(TASK_PHY_ENB); return; } - enb_app_start_phy_rrc(mod_id, mod_id+1); - LOG_I(ENB_APP, "lte-softmodem restart succeeded\n"); + int diff_ms = (1000 * clock() - start_ms) / CLOCKS_PER_SEC; + LOG_I(ENB_APP, "lte-softmodem restart succeeded in %d ms\n", diff_ms); } } diff --git a/targets/COMMON/create_tasks.c b/targets/COMMON/create_tasks.c index 1ca55b5926..c28b9e839c 100644 --- a/targets/COMMON/create_tasks.c +++ b/targets/COMMON/create_tasks.c @@ -40,17 +40,6 @@ # endif # include "enb_app.h" -int create_enb_app_task(uint32_t enb_nb) -{ - if (enb_nb > 0) { - if (itti_create_task (TASK_ENB_APP, eNB_app_task, NULL) < 0) { - LOG_E(ENB_APP, "Create task for eNB APP failed\n"); - return -1; - } - } - return 0; -} - int create_tasks(uint32_t enb_nb, uint32_t ue_nb) { itti_wait_ready(1); @@ -59,6 +48,14 @@ int create_tasks(uint32_t enb_nb, uint32_t ue_nb) return -1; } + if (enb_nb > 0) { + /* Last task to create, others task must be ready before its start */ + if (itti_create_task (TASK_ENB_APP, eNB_app_task, NULL) < 0) { + LOG_E(ENB_APP, "Create task for eNB APP failed\n"); + return -1; + } + } + # ifdef OPENAIR2 { diff --git a/targets/COMMON/create_tasks.h b/targets/COMMON/create_tasks.h index 3455b283b5..6545f4b9d9 100644 --- a/targets/COMMON/create_tasks.h +++ b/targets/COMMON/create_tasks.h @@ -27,7 +27,6 @@ extern void *l2l1_task(void *arg); int create_tasks(uint32_t enb_nb, uint32_t ue_nb); -int create_enb_app_task(uint32_t enb_nb); #endif #endif /* CREATE_TASKS_H_ */ diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index f881441cdb..39f40733f2 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -174,8 +174,6 @@ eNB_func_t node_function[MAX_NUM_CCs]; eNB_timing_t node_timing[MAX_NUM_CCs]; int16_t node_synch_ref[MAX_NUM_CCs]; -volatile int16_t node_control_state; - uint32_t target_dl_mcs = 28; //maximum allowed mcs uint32_t target_ul_mcs = 20; uint32_t timing_advance = 0; @@ -234,9 +232,7 @@ threads_t threads= {-1,-1,-1,-1,-1,-1,-1}; */ uint8_t abstraction_flag=0; -/* */ - -/* overrid the enb configuration params*/ +/* override the enb configuration parameters */ static void reconfigure_enb_params(int enb_id); @@ -1097,11 +1093,13 @@ static void get_options (int argc, char **argv) { "lte-softmodem compiled with MAX_NUM_CCs=%d, but only %d CCs configured for eNB %d!", MAX_NUM_CCs, enb_properties->properties[i]->nb_cc, i); +#ifdef FLEXRAN_AGENT_SB_IF if (enb_properties->properties[i]->flexran_agent_reconf == 1) { node_control_state = ENB_WAIT_RECONFIGURATION_CMD; } else { node_control_state = ENB_NORMAL_OPERATION; } +#endif eth_params = (eth_params_t*)malloc(enb_properties->properties[i]->nb_rrh_gw * sizeof(eth_params_t)); memset(eth_params, 0, enb_properties->properties[i]->nb_rrh_gw * sizeof(eth_params_t)); @@ -1796,19 +1794,28 @@ int main( int argc, char **argv ) { // N_ZC = (prach_fmt <4)?839:139; } - create_enb_app_task(UE_flag ? 0 : 1); - #ifdef FLEXRAN_AGENT_SB_IF - /* wait command for flexran agent: only start when configuration received */ - ltesm_wait_reconfig_cmd (); + pthread_mutex_init(&mutex_node_ctrl, NULL); + pthread_cond_init(&cond_node_ctrl, NULL); + + for (i = 0; i < NB_eNB_INST; i++) { + flexran_agent_start(i, enb_config_get()); + } + + LOG_I(ENB_APP, " * Waiting for FlexRAN RTController command *\n"); + pthread_mutex_lock(&mutex_node_ctrl); + while (ENB_NORMAL_OPERATION != node_control_state) + pthread_cond_wait(&cond_node_ctrl, &mutex_node_ctrl); + pthread_mutex_unlock(&mutex_node_ctrl); + + /* reconfigure eNB in case FlexRAN controller applied changes */ + for (i=0; i < NB_eNB_INST; i++){ + LOG_I(ENB_APP, "Reconfigure eNB module %d and FlexRAN eNB variables\n", i); + reconfigure_enb_params(i); + flexran_set_enb_vars(i, RAN_LTE_OAI); + } #endif - // reconfigure_enb: 0 for wait, 1 for skip, and other values to reconfigure - for (i=0; (i < NB_eNB_INST && node_control_state == ENB_NORMAL_OPERATION ) ; i++){ - reconfigure_enb_params(i); - printf("[ENB_APP] Reconfigured eNB module %d - continue\n", i); - } - if (UE_flag==1) { NB_UE_INST=1; NB_INST=1; @@ -2175,6 +2182,10 @@ int main( int argc, char **argv ) { stop_eNB(1); } +#ifdef FLEXRAN_AGENT_SB_IF + pthread_cond_destroy(&cond_node_ctrl); + pthread_mutex_destroy(&mutex_node_ctrl); +#endif pthread_cond_destroy(&sync_cond); pthread_mutex_destroy(&sync_mutex); @@ -2200,5 +2211,6 @@ int main( int argc, char **argv ) { logClean(); + printf("Bye.\n"); return 0; } diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index a0883c3d59..4dbdd2a40a 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -92,4 +92,11 @@ extern void init_te_thread(PHY_VARS_eNB *, pthread_attr_t *); extern int stop_L1L2(int enb_id); extern int restart_L1L2(int enb_id); +#ifdef FLEXRAN_AGENT_SB_IF +#include "flexran_agent.h" // for locking +volatile ENB_MODULE_STATE node_control_state; +pthread_cond_t cond_node_ctrl; +pthread_mutex_t mutex_node_ctrl; +#endif + #endif From f39dd5df1887519ee23257e5347840dc0ba32175 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 13 Dec 2017 14:43:33 +0100 Subject: [PATCH 117/284] bugfix: handle variable start_eNB in restart --- openair2/ENB_APP/flexran_agent_common_internal.c | 3 +++ targets/RT/USER/lte-softmodem.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/openair2/ENB_APP/flexran_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c index c2bd396e36..67f4b7371c 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.c +++ b/openair2/ENB_APP/flexran_agent_common_internal.c @@ -62,6 +62,9 @@ void handle_reconfiguration(mid_t mod_id) return; } enb_app_start_phy_rrc(mod_id, mod_id+1); + MessageDef *msg_p = itti_alloc_new_message(TASK_ENB_APP, INITIALIZE_MESSAGE); + itti_send_msg_to_task(TASK_L2L1, INSTANCE_DEFAULT, msg_p); + int diff_ms = (1000 * clock() - start_ms) / CLOCKS_PER_SEC; LOG_I(ENB_APP, "lte-softmodem restart succeeded in %d ms\n", diff_ms); } diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 39f40733f2..04113ef3ae 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -555,7 +555,8 @@ void *l2l1_task(void *arg) { case TERMINATE_MESSAGE: LOG_W(TASK_L2L1, " *** Exiting L2L1 thread\n"); - oai_exit=1; + oai_exit = 1; + start_eNB = 0; itti_exit_task (); break; From 359e1528dd2c0e20232aac7fad67b6ee14b0c71f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 14 Dec 2017 12:44:16 +0100 Subject: [PATCH 118/284] refactor: FlexRAN reads eNB configuration automatically --- openair2/ENB_APP/flexran_agent.c | 5 +++-- openair2/ENB_APP/flexran_agent.h | 2 +- openair2/ENB_APP/flexran_agent_ran_api.c | 3 +-- targets/RT/USER/lte-softmodem.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c index 8af071527f..5a399541f5 100644 --- a/openair2/ENB_APP/flexran_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -187,9 +187,10 @@ pthread_t new_thread(void *(*f)(void *), void *b) { } int channel_container_init = 0; -int flexran_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ - +int flexran_agent_start(mid_t mod_id) +{ int channel_id; + Enb_properties_array_t *enb_properties = enb_config_get(); flexran_set_enb_vars(mod_id, RAN_LTE_OAI); flexran_agent[mod_id].enb_id = mod_id; diff --git a/openair2/ENB_APP/flexran_agent.h b/openair2/ENB_APP/flexran_agent.h index f9205c071f..c1eb997e57 100644 --- a/openair2/ENB_APP/flexran_agent.h +++ b/openair2/ENB_APP/flexran_agent.h @@ -46,7 +46,7 @@ /* Initiation and termination of the eNodeB agent */ -int flexran_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties); +int flexran_agent_start(mid_t mod_id); int flexran_agent_stop(mid_t mod_id); /* diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 3ecbf77e11..01c5c472bd 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -44,16 +44,15 @@ void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran){ switch (ran){ case RAN_LTE_OAI : + enb_properties = enb_config_get(); if(eNB_mac_inst == NULL){ enb[mod_id] = NULL; enb_ue[mod_id] = NULL; enb_rrc[mod_id] = NULL; - enb_properties = NULL; }else{ enb[mod_id] = (void *)&eNB_mac_inst[mod_id]; enb_ue[mod_id] = (void *)&eNB_mac_inst[mod_id].UE_list; enb_rrc[mod_id] = (void *)&eNB_rrc_inst[mod_id]; - enb_properties = (Enb_properties_array_t *) enb_config_get(); } break; default : diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 04113ef3ae..cbcf26145b 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1800,7 +1800,7 @@ int main( int argc, char **argv ) { pthread_cond_init(&cond_node_ctrl, NULL); for (i = 0; i < NB_eNB_INST; i++) { - flexran_agent_start(i, enb_config_get()); + flexran_agent_start(i); } LOG_I(ENB_APP, " * Waiting for FlexRAN RTController command *\n"); From d35f52a22847404ffa328091d160f4f1d94e5c37 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Thu, 14 Dec 2017 15:15:00 +0100 Subject: [PATCH 119/284] Add observation window to the PDCP stats --- .../CONTROL_MODULES/PDCP/flexran_agent_pdcp.c | 24 ++--- .../ENB_APP/MESSAGES/V2/stats_common.proto | 12 +-- openair2/ENB_APP/flexran_agent_ran_api.c | 40 +++++--- openair2/ENB_APP/flexran_agent_ran_api.h | 20 ++-- openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 95 +++++++++++-------- openair2/LAYER2/PDCP_v10.1.0/pdcp.h | 35 ++++--- 6 files changed, 133 insertions(+), 93 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c index e4cc520070..25ec919127 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c +++ b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c @@ -51,18 +51,18 @@ void flexran_agent_pdcp_aggregate_stats(const mid_t mod_id, pdcp_aggr_stats->pkt_tx += flexran_get_pdcp_tx(mod_id,ue_id,lcid); pdcp_aggr_stats->pkt_tx_bytes += flexran_get_pdcp_tx_bytes(mod_id,ue_id,lcid); - pdcp_aggr_stats->pkt_tx_rate_s += flexran_get_pdcp_tx_rate_s(mod_id,ue_id,lcid); - pdcp_aggr_stats->pkt_tx_throughput_s += flexran_get_pdcp_tx_throughput_s(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_tx_w += flexran_get_pdcp_tx_w(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_tx_bytes_w += flexran_get_pdcp_tx_bytes_w(mod_id,ue_id,lcid); pdcp_aggr_stats->pkt_tx_aiat += flexran_get_pdcp_tx_aiat(mod_id,ue_id,lcid); - pdcp_aggr_stats->pkt_tx_aiat_s += flexran_get_pdcp_tx_aiat_s(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_tx_aiat_w += flexran_get_pdcp_tx_aiat_w(mod_id,ue_id,lcid); pdcp_aggr_stats->pkt_rx += flexran_get_pdcp_rx(mod_id,ue_id,lcid); pdcp_aggr_stats->pkt_rx_bytes += flexran_get_pdcp_rx_bytes(mod_id,ue_id,lcid); - pdcp_aggr_stats->pkt_rx_rate_s += flexran_get_pdcp_rx_rate_s(mod_id,ue_id,lcid); - pdcp_aggr_stats->pkt_rx_goodput_s += flexran_get_pdcp_rx_goodput_s(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_rx_w += flexran_get_pdcp_rx_w(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_rx_bytes_w += flexran_get_pdcp_rx_bytes_w(mod_id,ue_id,lcid); pdcp_aggr_stats->pkt_rx_aiat += flexran_get_pdcp_rx_aiat(mod_id,ue_id,lcid); - pdcp_aggr_stats->pkt_rx_aiat_s += flexran_get_pdcp_rx_aiat_s(mod_id,ue_id,lcid); + pdcp_aggr_stats->pkt_rx_aiat_w += flexran_get_pdcp_rx_aiat_w(mod_id,ue_id,lcid); pdcp_aggr_stats->pkt_rx_oo += flexran_get_pdcp_rx_oo(mod_id,ue_id,lcid); } @@ -99,20 +99,20 @@ int flexran_agent_pdcp_stats_reply(mid_t mod_id, pdcp_aggr_stats->has_pkt_tx=1; pdcp_aggr_stats->has_pkt_tx_bytes =1; - pdcp_aggr_stats->has_pkt_tx_rate_s=1; - pdcp_aggr_stats->has_pkt_tx_throughput_s =1; + pdcp_aggr_stats->has_pkt_tx_w=1; + pdcp_aggr_stats->has_pkt_tx_bytes_w =1; pdcp_aggr_stats->has_pkt_tx_aiat =1; - pdcp_aggr_stats->has_pkt_tx_aiat_s =1; + pdcp_aggr_stats->has_pkt_tx_aiat_w =1; pdcp_aggr_stats->pkt_tx_sn = flexran_get_pdcp_tx_sn(mod_id, i, DEFAULT_DRB); pdcp_aggr_stats->has_pkt_tx_sn =1; pdcp_aggr_stats->has_pkt_rx =1; pdcp_aggr_stats->has_pkt_rx_bytes =1; - pdcp_aggr_stats->has_pkt_rx_rate_s =1; - pdcp_aggr_stats->has_pkt_rx_goodput_s =1; + pdcp_aggr_stats->has_pkt_rx_w =1; + pdcp_aggr_stats->has_pkt_rx_bytes_w =1; pdcp_aggr_stats->has_pkt_rx_aiat =1; - pdcp_aggr_stats->has_pkt_rx_aiat_s =1; + pdcp_aggr_stats->has_pkt_rx_aiat_w =1; pdcp_aggr_stats->has_pkt_rx_oo =1; pdcp_aggr_stats->pkt_rx_sn = flexran_get_pdcp_rx_sn(mod_id, i, DEFAULT_DRB); diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto index 94da9fbd04..f651195ab1 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto @@ -253,18 +253,18 @@ message flex_pdcp_stats { optional uint32 pkt_tx = 1; optional uint32 pkt_tx_bytes = 2; optional uint32 pkt_tx_sn = 3; - optional uint32 pkt_tx_rate_s = 4; - optional uint32 pkt_tx_throughput_s = 5; + optional uint32 pkt_tx_w = 4; + optional uint32 pkt_tx_bytes_w = 5; optional uint32 pkt_tx_aiat = 7; - optional uint32 pkt_tx_aiat_s = 8; + optional uint32 pkt_tx_aiat_w = 8; optional uint32 pkt_rx = 9; optional uint32 pkt_rx_bytes = 10; optional uint32 pkt_rx_sn = 11; - optional uint32 pkt_rx_rate_s = 12; - optional uint32 pkt_rx_goodput_s = 13; + optional uint32 pkt_rx_w = 12; + optional uint32 pkt_rx_bytes_w = 13; optional uint32 pkt_rx_aiat = 14; - optional uint32 pkt_rx_aiat_s = 15; + optional uint32 pkt_rx_aiat_w = 15; optional uint32 pkt_rx_oo = 16; optional uint64 sfn=17; diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 01c5c472bd..556f018f7c 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -1134,6 +1134,22 @@ uint32_t flexran_get_pdcp_sfn(const mid_t mod_id){ return pdcp_enb[mod_id].sfn; } +/*PDCP super frame counter flexRAN*/ +uint32_t flexran_set_pdcp_tx_stat_window(const mid_t mod_id, const mid_t ue_id, uint16_t obs_window){ + if (obs_window > 0 ) + Pdcp_stats_tx_window_ms[mod_id][ue_id]=obs_window; + else + Pdcp_stats_tx_window_ms[mod_id][ue_id]=1000; +} + +/*PDCP super frame counter flexRAN*/ +uint32_t flexran_set_pdcp_rx_stat_window(const mid_t mod_id, const mid_t ue_id, uint16_t obs_window){ + if (obs_window > 0 ) + Pdcp_stats_rx_window_ms[mod_id][ue_id]=obs_window; + else + Pdcp_stats_rx_window_ms[mod_id][ue_id]=1000; +} + /*PDCP num tx pdu status flexRAN*/ uint32_t flexran_get_pdcp_tx(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ if (mod_id <0 || mod_id> MAX_NUM_CCs || ue_id<0 || ue_id> NUMBER_OF_UE_MAX || lcid<0 || lcid>NB_RB_MAX) @@ -1147,13 +1163,13 @@ uint32_t flexran_get_pdcp_tx_bytes(const mid_t mod_id, const mid_t ue_id, const } /*PDCP number of transmit packet / second status flexRAN*/ -uint32_t flexran_get_pdcp_tx_rate_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ - return Pdcp_stats_tx_rate_s[mod_id][ue_id][lcid]; +uint32_t flexran_get_pdcp_tx_w(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_tx_w[mod_id][ue_id][lcid]; } /*PDCP throughput (bit/s) status flexRAN*/ -uint32_t flexran_get_pdcp_tx_throughput_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ - return Pdcp_stats_tx_throughput_s[mod_id][ue_id][lcid]; +uint32_t flexran_get_pdcp_tx_bytes_w(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_tx_bytes_w[mod_id][ue_id][lcid]; } /*PDCP tx sequence number flexRAN*/ @@ -1167,8 +1183,8 @@ uint32_t flexran_get_pdcp_tx_aiat(const mid_t mod_id, const mid_t ue_id, const } /*PDCP tx aggregated packet arrival flexRAN*/ -uint32_t flexran_get_pdcp_tx_aiat_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ - return Pdcp_stats_tx_aiat_s[mod_id][ue_id][lcid]; +uint32_t flexran_get_pdcp_tx_aiat_w(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_tx_aiat_w[mod_id][ue_id][lcid]; } @@ -1183,13 +1199,13 @@ uint32_t flexran_get_pdcp_rx_bytes(const mid_t mod_id, const mid_t ue_id, const } /*PDCP number of received packet / second flexRAN*/ -uint32_t flexran_get_pdcp_rx_rate_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ - return Pdcp_stats_rx_rate_s[mod_id][ue_id][lcid]; +uint32_t flexran_get_pdcp_rx_w(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_rx_w[mod_id][ue_id][lcid]; } /*PDCP gootput (bit/s) status flexRAN*/ -uint32_t flexran_get_pdcp_rx_goodput_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ - return Pdcp_stats_rx_goodput_s[mod_id][ue_id][lcid]; +uint32_t flexran_get_pdcp_rx_bytes_w(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_rx_bytes_w[mod_id][ue_id][lcid]; } /*PDCP rx sequence number flexRAN*/ @@ -1203,8 +1219,8 @@ uint32_t flexran_get_pdcp_rx_aiat(const mid_t mod_id, const mid_t ue_id, const } /*PDCP rx aggregated packet arrival flexRAN*/ -uint32_t flexran_get_pdcp_rx_aiat_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ - return Pdcp_stats_rx_aiat_s[mod_id][ue_id][lcid]; +uint32_t flexran_get_pdcp_rx_aiat_w(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid){ + return Pdcp_stats_rx_aiat_w[mod_id][ue_id][lcid]; } /*PDCP num of received outoforder pdu status flexRAN*/ diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 84723be005..12ca5febea 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -345,6 +345,12 @@ int flexran_get_rrc_status(const mid_t mod_id, const rnti_t rntiP); /*PDCP superframe numberflexRAN*/ uint32_t flexran_get_pdcp_sfn(const mid_t mod_id); +/*PDCP pdcp tx stats window*/ +uint32_t flexran_set_pdcp_tx_stat_window(const mid_t mod_id, const mid_t ue_id, uint16_t obs_window); + +/*PDCP pdcp rx stats window*/ +uint32_t flexran_set_pdcp_rx_stat_window(const mid_t mod_id, const mid_t ue_id, uint16_t obs_window); + /*PDCP num tx pdu status flexRAN*/ uint32_t flexran_get_pdcp_tx(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); @@ -352,10 +358,10 @@ uint32_t flexran_get_pdcp_tx(const mid_t mod_id, const mid_t ue_id, const lcid_ uint32_t flexran_get_pdcp_tx_bytes(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); /*PDCP number of transmit packet / second status flexRAN*/ -uint32_t flexran_get_pdcp_tx_rate_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); +uint32_t flexran_get_pdcp_tx_w(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); -/*PDCP throughput (bit/s) status flexRAN*/ -uint32_t flexran_get_pdcp_tx_throughput_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); +/*PDCP pdcp tx bytes in a given window flexRAN*/ +uint32_t flexran_get_pdcp_tx_bytes_w(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); /*PDCP tx sequence number flexRAN*/ uint32_t flexran_get_pdcp_tx_sn(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); @@ -364,7 +370,7 @@ uint32_t flexran_get_pdcp_tx_sn(const mid_t mod_id, const mid_t ue_id, const lc uint32_t flexran_get_pdcp_tx_aiat(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); /*PDCP tx aggregated packet arrival per second flexRAN*/ -uint32_t flexran_get_pdcp_tx_aiat_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); +uint32_t flexran_get_pdcp_tx_aiat_w(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); /*PDCP num rx pdu status flexRAN*/ @@ -374,10 +380,10 @@ uint32_t flexran_get_pdcp_rx(const mid_t mod_id, const mid_t ue_id, const lcid_ uint32_t flexran_get_pdcp_rx_bytes(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); /*PDCP number of received packet / second flexRAN*/ -uint32_t flexran_get_pdcp_rx_rate_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); +uint32_t flexran_get_pdcp_rx_w(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); /*PDCP gootput (bit/s) status flexRAN*/ -uint32_t flexran_get_pdcp_rx_goodput_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); +uint32_t flexran_get_pdcp_rx_bytes_w(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); /*PDCP rx sequence number flexRAN*/ uint32_t flexran_get_pdcp_rx_sn(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); @@ -386,7 +392,7 @@ uint32_t flexran_get_pdcp_rx_sn(const mid_t mod_id, const mid_t ue_id, const lc uint32_t flexran_get_pdcp_rx_aiat(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); /*PDCP rx aggregated packet arrival per second flexRAN*/ -uint32_t flexran_get_pdcp_rx_aiat_s(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); +uint32_t flexran_get_pdcp_rx_aiat_w(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); /*PDCP num of received outoforder pdu status flexRAN*/ uint32_t flexran_get_pdcp_rx_oo(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index df85b06d06..d74e8552d6 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -408,13 +408,13 @@ boolean_t pdcp_data_req( //LOG_I(PDCP,"ueid %d lcid %d tx seq num %d\n", pdcp_uid, rb_idP+rb_offset, current_sn); Pdcp_stats_tx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; Pdcp_stats_tx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; - Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; + Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; Pdcp_stats_tx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=current_sn; Pdcp_stats_tx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_tx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_enb[ctxt_pP->module_id].sfn; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); @@ -880,9 +880,9 @@ pdcp_data_ind( } Pdcp_stats_rx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; Pdcp_stats_rx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); - Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); + Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); Pdcp_stats_rx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=sequence_number; @@ -890,7 +890,7 @@ pdcp_data_ind( Pdcp_stats_rx_outoforder[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_rx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_enb[ctxt_pP->module_id].sfn; @@ -920,36 +920,45 @@ void pdcp_update_stats(const protocol_ctxt_t* const ctxt_pP){ uint8_t rb_id = 0; // these stats are measured for both eNB and UE on per seond basis - if (pdcp_enb[ctxt_pP->module_id].sfn % 1000 == 0){ - for (rb_id =0; rb_id < NB_RB_MAX; rb_id ++){ - for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){ - //printf("frame %d and subframe %d \n", pdcp_enb[ctxt_pP->module_id].frame, pdcp_enb[ctxt_pP->module_id].subframe); - // tx stats - Pdcp_stats_tx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]; + for (rb_id =0; rb_id < NB_RB_MAX; rb_id ++){ + for (pdcp_uid=0; pdcp_uid< NUMBER_OF_UE_MAX;pdcp_uid++){ + //printf("frame %d and subframe %d \n", pdcp_enb[ctxt_pP->module_id].frame, pdcp_enb[ctxt_pP->module_id].subframe); + // tx stats + if (pdcp_enb[ctxt_pP->module_id].sfn % Pdcp_stats_tx_window_ms[ctxt_pP->module_id][pdcp_uid] == 0){ // unit: bit/s - Pdcp_stats_tx_throughput_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]*8; - if (Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id] > 0){ - Pdcp_stats_tx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_id]=(Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]); - } - - Pdcp_stats_tx_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; - Pdcp_stats_tx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; - Pdcp_stats_tx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + Pdcp_stats_tx_throughput_w[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]*8; + Pdcp_stats_tx_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; + Pdcp_stats_tx_bytes_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; + if (Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id] > 0){ + Pdcp_stats_tx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]=(Pdcp_stats_tx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]); + }else { + Pdcp_stats_tx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + } + // reset the tmp vars + Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + Pdcp_stats_tx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + } + if (pdcp_enb[ctxt_pP->module_id].sfn % Pdcp_stats_rx_window_ms[ctxt_pP->module_id][pdcp_uid] == 0){ // rx stats - Pdcp_stats_rx_rate_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id]; - Pdcp_stats_rx_goodput_s[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]*8; - - if(Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id] > 0){ - Pdcp_stats_rx_aiat_s[ctxt_pP->module_id][pdcp_uid][rb_id]= (Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id]); - } + Pdcp_stats_rx_goodput_w[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]*8; + Pdcp_stats_rx_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; + Pdcp_stats_rx_bytes_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; - Pdcp_stats_rx_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; - Pdcp_stats_rx_bytes_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; - Pdcp_stats_rx_aiat_tmp_s[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + if(Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id] > 0){ + Pdcp_stats_rx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]= (Pdcp_stats_rx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]); + } else { + Pdcp_stats_rx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + } + // reset the tmp vars + Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + Pdcp_stats_rx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; } } + } } //----------------------------------------------------------------------------- @@ -2024,6 +2033,7 @@ void pdcp_layer_init(void) { module_id_t instance; + int i,j; #if defined(Rel10) || defined(Rel14) mbms_session_id_t session_id; mbms_service_id_t service_id; @@ -2070,24 +2080,35 @@ void pdcp_layer_init(void) memset(pdcp_enb, 0, sizeof(pdcp_enb_t)); + memset(Pdcp_stats_tx_window_ms, 0, sizeof(Pdcp_stats_tx_window_ms)); + memset(Pdcp_stats_rx_window_ms, 0, sizeof(Pdcp_stats_rx_window_ms)); + for (i =0; i< MAX_NUM_CCs ; i ++){ + for (j=0; j< NUMBER_OF_UE_MAX;j++){ + Pdcp_stats_tx_window_ms[i][j]=100; + Pdcp_stats_rx_window_ms[i][j]=100; + } + } + memset(Pdcp_stats_tx, 0, sizeof(Pdcp_stats_tx)); - memset(Pdcp_stats_tx_s, 0, sizeof(Pdcp_stats_tx_s)); + memset(Pdcp_stats_tx_w, 0, sizeof(Pdcp_stats_tx_w)); + memset(Pdcp_stats_tx_tmp_w, 0, sizeof(Pdcp_stats_tx_tmp_w)); memset(Pdcp_stats_tx_bytes, 0, sizeof(Pdcp_stats_tx_bytes)); - memset(Pdcp_stats_tx_bytes_s, 0, sizeof(Pdcp_stats_tx_bytes_s)); - memset(Pdcp_stats_tx_rate_s, 0, sizeof(Pdcp_stats_tx_rate_s)); + memset(Pdcp_stats_tx_bytes_w, 0, sizeof(Pdcp_stats_tx_bytes_w)); + memset(Pdcp_stats_tx_bytes_tmp_w, 0, sizeof(Pdcp_stats_tx_bytes_tmp_w)); memset(Pdcp_stats_tx_sn, 0, sizeof(Pdcp_stats_tx_sn)); - memset(Pdcp_stats_tx_throughput_s, 0, sizeof(Pdcp_stats_tx_throughput_s)); + memset(Pdcp_stats_tx_throughput_w, 0, sizeof(Pdcp_stats_tx_throughput_w)); memset(Pdcp_stats_tx_aiat, 0, sizeof(Pdcp_stats_tx_aiat)); memset(Pdcp_stats_tx_iat, 0, sizeof(Pdcp_stats_tx_iat)); memset(Pdcp_stats_rx, 0, sizeof(Pdcp_stats_rx)); - memset(Pdcp_stats_rx_s, 0, sizeof(Pdcp_stats_rx_s)); + memset(Pdcp_stats_rx_w, 0, sizeof(Pdcp_stats_rx_w)); + memset(Pdcp_stats_rx_tmp_w, 0, sizeof(Pdcp_stats_rx_tmp_w)); memset(Pdcp_stats_rx_bytes, 0, sizeof(Pdcp_stats_rx_bytes)); - memset(Pdcp_stats_rx_bytes_s, 0, sizeof(Pdcp_stats_rx_bytes_s)); - memset(Pdcp_stats_rx_rate_s, 0, sizeof(Pdcp_stats_rx_rate_s)); + memset(Pdcp_stats_rx_bytes_w, 0, sizeof(Pdcp_stats_rx_bytes_w)); + memset(Pdcp_stats_rx_bytes_tmp_w, 0, sizeof(Pdcp_stats_rx_bytes_tmp_w)); memset(Pdcp_stats_rx_sn, 0, sizeof(Pdcp_stats_rx_sn)); - memset(Pdcp_stats_rx_goodput_s, 0, sizeof(Pdcp_stats_rx_goodput_s)); + memset(Pdcp_stats_rx_goodput_w, 0, sizeof(Pdcp_stats_rx_goodput_w)); memset(Pdcp_stats_rx_aiat, 0, sizeof(Pdcp_stats_rx_aiat)); memset(Pdcp_stats_rx_iat, 0, sizeof(Pdcp_stats_rx_iat)); memset(Pdcp_stats_rx_outoforder, 0, sizeof(Pdcp_stats_rx_outoforder)); diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h index cf3d927051..cdd69a8659 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h @@ -94,35 +94,32 @@ extern int pdcp_instance_cnt; int init_pdcp_thread(void); void cleanup_pdcp_thread(void); -/* -public_pdcp(uint64_t Pdcp_sfn[MAX_NUM_CCs]); -public_pdcp(frame_t Pdcp_frame[MAX_NUM_CCs]); -public_pdcp(sub_frame_t Pdcp_subframe[MAX_NUM_CCs]); -public_pdcp(uint16_t Pdcp_num_ues[MAX_NUM_CCs]); -*/ - +public_pdcp(uint32_t Pdcp_stats_tx_window_ms[MAX_NUM_CCs][NUMBER_OF_UE_MAX]); public_pdcp(uint32_t Pdcp_stats_tx_bytes[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); -public_pdcp(uint32_t Pdcp_stats_tx_bytes_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_bytes_w[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_bytes_tmp_w[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); public_pdcp(uint32_t Pdcp_stats_tx[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); -public_pdcp(uint32_t Pdcp_stats_tx_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_w[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_tmp_w[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); public_pdcp(uint32_t Pdcp_stats_tx_sn[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); -public_pdcp(uint32_t Pdcp_stats_tx_rate_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); -public_pdcp(uint32_t Pdcp_stats_tx_throughput_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_throughput_w[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); public_pdcp(uint32_t Pdcp_stats_tx_aiat[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); -public_pdcp(uint32_t Pdcp_stats_tx_aiat_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); -public_pdcp(uint32_t Pdcp_stats_tx_aiat_tmp_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_aiat_w[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_tx_aiat_tmp_w[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); public_pdcp(uint32_t Pdcp_stats_tx_iat[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_window_ms[MAX_NUM_CCs][NUMBER_OF_UE_MAX]); public_pdcp(uint32_t Pdcp_stats_rx[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); -public_pdcp(uint32_t Pdcp_stats_rx_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_w[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_tmp_w[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); public_pdcp(uint32_t Pdcp_stats_rx_bytes[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); -public_pdcp(uint32_t Pdcp_stats_rx_bytes_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_bytes_w[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_bytes_tmp_w[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); public_pdcp(uint32_t Pdcp_stats_rx_sn[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); -public_pdcp(uint32_t Pdcp_stats_rx_rate_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); -public_pdcp(uint32_t Pdcp_stats_rx_goodput_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_goodput_w[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); public_pdcp(uint32_t Pdcp_stats_rx_aiat[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); -public_pdcp(uint32_t Pdcp_stats_rx_aiat_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); -public_pdcp(uint32_t Pdcp_stats_rx_aiat_tmp_s[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_aiat_w[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); +public_pdcp(uint32_t Pdcp_stats_rx_aiat_tmp_w[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); public_pdcp(uint32_t Pdcp_stats_rx_iat[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); public_pdcp(uint32_t Pdcp_stats_rx_outoforder[MAX_NUM_CCs][NUMBER_OF_UE_MAX][NB_RB_MAX]); From ccac021050d2754aa4f5591a42c04f95b6223096 Mon Sep 17 00:00:00 2001 From: shahab SHARIAT BAGHERI Date: Thu, 14 Dec 2017 18:34:41 +0100 Subject: [PATCH 120/284] Ue stats bugfix for dynamic reconfiguration --- openair2/ENB_APP/enb_app.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index 5fe0f741bf..98f9ee3682 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -283,6 +283,7 @@ void *eNB_app_task(void *args_p) #if defined(ENABLE_ITTI) uint32_t enb_nb = 1; /* Default number of eNB is 1 */ uint32_t enb_id_start = 0; + uint32_t enb_i; uint32_t enb_id_end = enb_id_start + enb_nb; # if defined(ENABLE_USE_MME) uint32_t register_enb_pending; @@ -318,7 +319,13 @@ void *eNB_app_task(void *args_p) enb_nb, enb_properties_p->number); enb_app_start_phy_rrc(enb_id_start, enb_id_end); - + +#ifdef FLEXRAN_AGENT_SB_IF + for (enb_i = 0; enb_i <1; enb_i ++){ // To be handled for all of current eNB + flexran_set_enb_vars(enb_i, RAN_LTE_OAI); + +} +#endif # if defined(ENABLE_USE_MME) /* Try to register each eNB */ registered_enb = 0; From b049f0c820ad7f09e763ff3e1dc602e3f7cdc663 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Thu, 14 Dec 2017 18:34:41 +0100 Subject: [PATCH 121/284] Ue stats bugfix for dynamic reconfiguration --- openair2/ENB_APP/enb_app.c | 8 +- openair2/ENB_APP/flexran_agent.c | 24 ++- openair2/ENB_APP/flexran_agent.h | 1 + .../MAC/flexran_agent_scheduler_dlsch_ue.c | 153 ++++++++------- .../MAC/flexran_agent_scheduler_ulsch_ue.c | 179 ++++++++++-------- 5 files changed, 209 insertions(+), 156 deletions(-) diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index 5fe0f741bf..d51b0efcd7 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -283,6 +283,7 @@ void *eNB_app_task(void *args_p) #if defined(ENABLE_ITTI) uint32_t enb_nb = 1; /* Default number of eNB is 1 */ uint32_t enb_id_start = 0; + uint32_t enb_i; uint32_t enb_id_end = enb_id_start + enb_nb; # if defined(ENABLE_USE_MME) uint32_t register_enb_pending; @@ -318,7 +319,12 @@ void *eNB_app_task(void *args_p) enb_nb, enb_properties_p->number); enb_app_start_phy_rrc(enb_id_start, enb_id_end); - + +#ifdef FLEXRAN_AGENT_SB_IF + for (enb_i = 0; enb_i <1; enb_i ++){ // To be handled for all of current eNB + flexran_set_enb_vars(enb_i, RAN_LTE_OAI); + } +#endif # if defined(ENABLE_USE_MME) /* Try to register each eNB */ registered_enb = 0; diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c index 5a399541f5..7cb910ae1a 100644 --- a/openair2/ENB_APP/flexran_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -186,15 +186,9 @@ pthread_t new_thread(void *(*f)(void *), void *b) { return t; } -int channel_container_init = 0; -int flexran_agent_start(mid_t mod_id) -{ - int channel_id; +void flexran_agent_reconfigure(mid_t mod_id){ Enb_properties_array_t *enb_properties = enb_config_get(); - - flexran_set_enb_vars(mod_id, RAN_LTE_OAI); - flexran_agent[mod_id].enb_id = mod_id; - + /* * check the configuration */ @@ -204,7 +198,7 @@ int flexran_agent_start(mid_t mod_id) } else { strcpy(local_cache, DEFAULT_FLEXRAN_AGENT_CACHE); } - + if (enb_properties->properties[mod_id]->flexran_agent_ipv4_address != 0) { inet_ntop(AF_INET, &(enb_properties->properties[mod_id]->flexran_agent_ipv4_address), in_ip, INET_ADDRSTRLEN); } else { @@ -220,6 +214,18 @@ int flexran_agent_start(mid_t mod_id) flexran_agent[mod_id].enb_id, in_ip, in_port); + +} + +int channel_container_init = 0; +int flexran_agent_start(mid_t mod_id) +{ + int channel_id; + + flexran_set_enb_vars(mod_id, RAN_LTE_OAI); + flexran_agent[mod_id].enb_id = mod_id; + + flexran_agent_reconfigure(mod_id); /* * Initialize the channel container diff --git a/openair2/ENB_APP/flexran_agent.h b/openair2/ENB_APP/flexran_agent.h index c1eb997e57..b092e26d53 100644 --- a/openair2/ENB_APP/flexran_agent.h +++ b/openair2/ENB_APP/flexran_agent.h @@ -48,6 +48,7 @@ /* Initiation and termination of the eNodeB agent */ int flexran_agent_start(mid_t mod_id); int flexran_agent_stop(mid_t mod_id); +void flexran_agent_reconfigure(mid_t mod_id); /* * enb agent task mainly wakes up the tx thread for periodic and oneshot messages to the controller diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index 601310d67a..a04987f07c 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -96,9 +96,11 @@ int slicing_strategy = UEID_TO_SLICEID; int slicing_strategy_current = UEID_TO_SLICEID; // RB share for each slice for past and current time -float slice_percentage[MAX_NUM_SLICES] = {1.0, 1.0, 0.0, 0.0}; -float slice_percentage_current[MAX_NUM_SLICES] = {1.0, 1.0, 0.0, 0.0}; +float avg_slice_percentage=0.25; +float slice_percentage[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; +float slice_percentage_current[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; float total_slice_percentage = 0; +float total_slice_percentage_current = 0; // MAX MCS for each slice for past and current time int slice_maxmcs[MAX_NUM_SLICES] = {28, 28, 28, 28}; @@ -724,7 +726,23 @@ flexran_schedule_ue_dl_spec_default(mid_t mod_id, int i=0; flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); - + + total_slice_percentage=0; + avg_slice_percentage=1.0/n_active_slices; + + // reset the slice percentage for inactive slices + for (i = n_active_slices; i< MAX_NUM_SLICES; i++) { + slice_percentage[i]=0; + } + for (i = 0; i < n_active_slices; i++) { + if (slice_percentage[i] < 0 ){ + LOG_W(MAC, "[eNB %d] frame %d subframe %d:invalid slice %d percentage %d. resetting to zero", + mod_id, frame, subframe, i, slice_percentage[i]); + slice_percentage[i]=0; + } + total_slice_percentage+=slice_percentage[i]; + } + for (i = 0; i < n_active_slices; i++) { // Load any updated functions @@ -732,84 +750,77 @@ flexran_schedule_ue_dl_spec_default(mid_t mod_id, slice_sched_dl[i] = dlsym(NULL, dl_scheduler_type[i]); update_dl_scheduler[i] = 0; update_dl_scheduler_current[i] = 0; - slice_percentage_current[i]= slice_percentage[i]; - total_slice_percentage+=slice_percentage[i]; LOG_N(MAC,"update dl scheduler slice %d\n", i); } - - // check if the number of slices has changed, and log - if (n_active_slices_current != n_active_slices ){ - if ((n_active_slices > 0) && (n_active_slices <= MAX_NUM_SLICES)) { - LOG_N(MAC,"[eNB %d]frame %d subframe %d: number of active slices has changed: %d-->%d\n", - mod_id, frame, subframe, n_active_slices_current, n_active_slices); - n_active_slices_current = n_active_slices; + if (total_slice_percentage <= 1.0){ // the new total RB share is within the range - } else { - LOG_W(MAC,"invalid number of slices %d, revert to the previous value %d\n",n_active_slices, n_active_slices_current); - n_active_slices = n_active_slices_current; + // check if the number of slices has changed, and log + if (n_active_slices_current != n_active_slices ){ + if ((n_active_slices > 0) && (n_active_slices <= MAX_NUM_SLICES)) { + LOG_N(MAC,"[eNB %d]frame %d subframe %d: number of active DL slices has changed: %d-->%d\n", + mod_id, frame, subframe, n_active_slices_current, n_active_slices); + + n_active_slices_current = n_active_slices; + + } else { + LOG_W(MAC,"invalid number of DL slices %d, revert to the previous value %d\n",n_active_slices, n_active_slices_current); + n_active_slices = n_active_slices_current; + } } - } - - // check if the slice rb share has changed, and log the console - if (slice_percentage_current[i] != slice_percentage[i]){ - // if ((slice_percentage[i] >= 0.0) && (slice_percentage[i] <= 1.0)){ - // if ((total_slice_percentage - slice_percentage_current[i] + slice_percentage[i]) <= 1.0) { - // total_slice_percentage=total_slice_percentage - slice_percentage_current[i] + slice_percentage[i]; - LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: total percentage %f, slice RB percentage has changed: %f-->%f\n", - mod_id, i, frame, subframe, total_slice_percentage, slice_percentage_current[i], slice_percentage[i]); - - slice_percentage_current[i] = slice_percentage[i]; - - // } else { - // LOG_W(MAC,"[eNB %d][SLICE %d] invalid total RB share (%f->%f), revert the previous value (%f->%f)\n", - // mod_id,i, - // total_slice_percentage, - // total_slice_percentage - slice_percentage_current[i] + slice_percentage[i], - // slice_percentage[i],slice_percentage_current[i]); - - // slice_percentage[i]= slice_percentage_current[i]; - - // } - // } else { - // LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice RB share, revert the previous value (%f->%f)\n",mod_id, i, slice_percentage[i],slice_percentage_current[i]); - - // slice_percentage[i]= slice_percentage_current[i]; - - // } - } - - // check if the slice max MCS, and log the console - if (slice_maxmcs_current[i] != slice_maxmcs[i]){ - if ((slice_maxmcs[i] >= 0) && (slice_maxmcs[i] < 29)){ - LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: slice MAX MCS has changed: %d-->%d\n", - mod_id, i, frame, subframe, slice_maxmcs_current[i], slice_maxmcs[i]); - - slice_maxmcs_current[i] = slice_maxmcs[i]; - - } else { - // LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice max mcs %d, revert the previous value %d\n",mod_id, i, slice_maxmcs[i],slice_percentage[i]); - - slice_maxmcs[i]= slice_maxmcs_current[i]; - - } - } - - // check if a new scheduler, and log the console - if (update_dl_scheduler_current[i] != update_dl_scheduler[i]){ - LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: DL scheduler for this slice is updated: %s \n", - mod_id, i, frame, subframe, dl_scheduler_type[i]); - - update_dl_scheduler_current[i] = update_dl_scheduler[i]; + // check if the slice rb share has changed, and log the console + if (slice_percentage_current[i] != slice_percentage[i]){ // new slice percentage + LOG_N(MAC,"[eNB %d][SLICE %d][DL] frame %d subframe %d: total percentage %f-->%f, slice RB percentage has changed: %f-->%f\n", + mod_id, i, frame, subframe, total_slice_percentage_current, total_slice_percentage, slice_percentage_current[i], slice_percentage[i]); + total_slice_percentage_current= total_slice_percentage; + slice_percentage_current[i] = slice_percentage[i]; + + } + + // check if the slice max MCS, and log the console + if (slice_maxmcs_current[i] != slice_maxmcs[i]){ + if ((slice_maxmcs[i] >= 0) && (slice_maxmcs[i] < 29)){ + LOG_N(MAC,"[eNB %d][SLICE %d][DL] frame %d subframe %d: slice MAX MCS has changed: %d-->%d\n", + mod_id, i, frame, subframe, slice_maxmcs_current[i], slice_maxmcs[i]); + slice_maxmcs_current[i] = slice_maxmcs[i]; + } else { + LOG_W(MAC,"[eNB %d][SLICE %d][DL] invalid slice max mcs %d, revert the previous value %d\n",mod_id, i, slice_maxmcs[i],slice_maxmcs_current[i]); + slice_maxmcs[i]= slice_maxmcs_current[i]; + } + } + + // check if a new scheduler, and log the console + if (update_dl_scheduler_current[i] != update_dl_scheduler[i]){ + LOG_N(MAC,"[eNB %d][SLICE %d][DL] frame %d subframe %d: DL scheduler for this slice is updated: %s \n", + mod_id, i, frame, subframe, dl_scheduler_type[i]); + update_dl_scheduler_current[i] = update_dl_scheduler[i]; + } + + } else { + // here we can correct the values, e.g. reduce proportionally + + if (n_active_slices == n_active_slices_current){ + LOG_W(MAC,"[eNB %d][SLICE %d][DL] invalid total RB share (%f->%f), reduce proportionally the RB share by 0.1\n", + mod_id,i, + total_slice_percentage_current, total_slice_percentage); + if (slice_percentage[i] >= avg_slice_percentage){ + slice_percentage[i]-=0.1; + total_slice_percentage-=0.1; + } + } else { + LOG_W(MAC,"[eNB %d][SLICE %d][DL] invalid total RB share (%f->%f), revert the number of slice to its previous value (%d->%d)\n", + mod_id,i, + total_slice_percentage_current, total_slice_percentage, + n_active_slices, n_active_slices_current ); + n_active_slices = n_active_slices_current; + slice_percentage[i] = slice_percentage_current[i]; + } } - + // Run each enabled slice-specific schedulers one by one - //LOG_N(MAC,"[eNB %d]frame %d subframe %d slice %d: calling the scheduler\n", mod_id, frame, subframe,i); slice_sched_dl[i](mod_id, i, frame, subframe, mbsfn_flag,dl_info); - } - } uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, int total_rbs){ diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index 5b31c11681..64f21482fb 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -21,7 +21,7 @@ /*! \file eNB_scheduler_ulsch.c * \brief FlexRAN eNB procedures for the ULSCH transport channel - * \author shahab SHARIAT BAGHERI + * \author Navid Nikaein and shahab SHARIAT BAGHERI * \date 2017 * \version 1.0 * @ingroup _mac @@ -67,19 +67,21 @@ /* number of active slices for past and current time*/ int n_active_slices_uplink = 1; -int n_active_slices_uplink_current = 1; +int n_active_slices_current_uplink = 1; /* RB share for each slice for past and current time*/ -float slice_percentage_uplink[MAX_NUM_SLICES] = {1.0, 1.0, 0.0, 0.0}; -float slice_percentage_current_uplink[MAX_NUM_SLICES] = {1.0, 1.0, 0.0, 0.0}; +float avg_slice_percentage_uplink=0.25; +float slice_percentage_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; +float slice_percentage_current_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; float total_slice_percentage_uplink = 0; +float total_slice_percentage_current_uplink = 0; // MAX MCS for each slice for past and current time int slice_maxmcs_uplink[MAX_NUM_SLICES] = {16, 16, 16, 16}; -int slice_maxmcs_current_uplink[MAX_NUM_SLICES] = {28, 28, 28, 28}; +int slice_maxmcs_current_uplink[MAX_NUM_SLICES] = {16,16,16,16}; /*resource blocks allowed*/ -uint16_t nb_rbs_allowed_slice_uplink[MAX_NUM_CCs][MAX_NUM_SLICES]; +uint16_t nb_rbs_allowed_slice_uplink[MAX_NUM_CCs][MAX_NUM_SLICES]; /*Slice Update */ int update_ul_scheduler[MAX_NUM_SLICES] = {1, 1, 1, 1}; int update_ul_scheduler_current[MAX_NUM_SLICES] = {1, 1, 1, 1}; @@ -89,9 +91,9 @@ slice_scheduler_ul slice_sched_ul[MAX_NUM_SLICES] = {0}; /* name of available scheduler*/ char *ul_scheduler_type[MAX_NUM_SLICES] = {"flexran_schedule_ue_ul_spec_embb", - "flexran_schedule_ue_ul_spec_urllc", - "flexran_schedule_ue_ul_spec_mmtc", - "flexran_schedule_ue_ul_spec_be" // best effort + "flexran_schedule_ue_ul_spec_embb", + "flexran_schedule_ue_ul_spec_embb", + "flexran_schedule_ue_ul_spec_embb" // best effort }; @@ -418,6 +420,22 @@ flexran_schedule_ue_ul_spec_default(mid_t mod_id, flexran_agent_mac_create_empty_ul_config(mod_id, ul_info); + total_slice_percentage_uplink=0; + avg_slice_percentage_uplink=1.0/n_active_slices_uplink; + + // reset the slice percentage for inactive slices + for (i = n_active_slices_uplink; i< MAX_NUM_SLICES; i++) { + slice_percentage_uplink[i]=0; + } + for (i = 0; i < n_active_slices_uplink; i++) { + if (slice_percentage_uplink[i] < 0 ){ + LOG_W(MAC, "[eNB %d] frame %d subframe %d:invalid slice %d percentage %d. resetting to zero", + mod_id, frame, subframe, i, slice_percentage_uplink[i]); + slice_percentage_uplink[i]=0; + } + total_slice_percentage_uplink+=slice_percentage_uplink[i]; + } + for (i = 0; i < n_active_slices_uplink; i++) { // Load any updated functions @@ -425,89 +443,100 @@ flexran_schedule_ue_ul_spec_default(mid_t mod_id, slice_sched_ul[i] = dlsym(NULL, ul_scheduler_type[i]); update_ul_scheduler[i] = 0; update_ul_scheduler_current[i] = 0; - slice_percentage_current_uplink[i]= slice_percentage_uplink[i]; - total_slice_percentage_uplink+=slice_percentage_uplink[i]; + //slice_percentage_current_uplink[i]= slice_percentage_uplink[i]; + //total_slice_percentage_current_uplink+=slice_percentage_uplink[i]; + //if (total_slice_percentage_current_uplink> 1) + // total_slice_percentage_current_uplink=1; LOG_N(MAC,"update ul scheduler slice %d\n", i); } - - // check if the number of slices has changed, and log - if (n_active_slices_uplink_current != n_active_slices_uplink ){ - if ((n_active_slices_uplink > 0) && (n_active_slices_uplink <= MAX_NUM_SLICES)) { - LOG_N(MAC,"[eNB %d]frame %d subframe %d: number of active slices has changed: %d-->%d\n", - mod_id, frame, subframe, n_active_slices_uplink_current, n_active_slices_uplink); + // the new total RB share is within the range + if (total_slice_percentage_uplink <= 1.0){ - n_active_slices_uplink_current = n_active_slices_uplink; - - } else { - LOG_W(MAC,"invalid number of slices %d, revert to the previous value %d\n",n_active_slices_uplink, n_active_slices_uplink_current); - n_active_slices_uplink = n_active_slices_uplink_current; + // check if the number of slices has changed, and log + if (n_active_slices_current_uplink != n_active_slices_uplink ){ + if ((n_active_slices_uplink > 0) && (n_active_slices_uplink <= MAX_NUM_SLICES)) { + LOG_N(MAC,"[eNB %d]frame %d subframe %d: number of active UL slices has changed: %d-->%d\n", + mod_id, frame, subframe, n_active_slices_current_uplink, n_active_slices_uplink); + + n_active_slices_current_uplink = n_active_slices_uplink; + + } else { + LOG_W(MAC,"invalid number of UL slices %d, revert to the previous value %d\n",n_active_slices_uplink, n_active_slices_current_uplink); + n_active_slices_uplink = n_active_slices_current_uplink; + } } - } // check if the slice rb share has changed, and log the console - if (slice_percentage_current_uplink[i] != slice_percentage_uplink[i]){ - // if ((slice_percentage_uplink[i] >= 0.0) && (slice_percentage_uplink[i] <= 1.0)){ - // if ((total_slice_percentage_uplink - slice_percentage_current_uplink[i] + slice_percentage_uplink[i]) <= 1.0) { - // total_slice_percentage_uplink=total_slice_percentage_uplink - slice_percentage_current_uplink[i] + slice_percentage_uplink[i]; - LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: total percentage %f, slice RB percentage has changed: %f-->%f\n", - mod_id, i, frame, subframe, total_slice_percentage_uplink, slice_percentage_current_uplink[i], slice_percentage_uplink[i]); - - slice_percentage_current_uplink[i] = slice_percentage_uplink[i]; - - // } else { - // LOG_W(MAC,"[eNB %d][SLICE %d] invalid total RB share (%f->%f), revert the previous value (%f->%f)\n", - // mod_id,i, - // total_slice_percentage_uplink, - // total_slice_percentage_uplink - slice_percentage_current_uplink[i] + slice_percentage_uplink[i], - // slice_percentage_uplink[i],slice_percentage_current_uplink[i]); - - // slice_percentage_uplink[i]= slice_percentage_current_uplink[i]; - - // } - // } else { - // LOG_W(MAC,"[eNB %d][SLICE %d] invalid slice RB share, revert the previous value (%f->%f)\n",mod_id, i, slice_percentage_uplink[i],slice_percentage_current_uplink[i]); - - // slice_percentage_uplink[i]= slice_percentage_current_uplink[i]; - - // } - } - - // check if a new scheduler, and log the console - if (update_ul_scheduler_current[i] != update_ul_scheduler[i]){ - LOG_N(MAC,"[eNB %d][SLICE %d] frame %d subframe %d: DL scheduler for this slice is updated: %s \n", - mod_id, i, frame, subframe, ul_scheduler_type[i]); - - update_ul_scheduler_current[i] = update_ul_scheduler[i]; + if (slice_percentage_current_uplink[i] != slice_percentage_uplink[i]){ + LOG_N(MAC,"[eNB %d][SLICE %d][UL] frame %d subframe %d: total percentage %f-->%f, slice RB percentage has changed: %f-->%f\n", + mod_id, i, frame, subframe, total_slice_percentage_current_uplink, total_slice_percentage_uplink, slice_percentage_current_uplink[i], slice_percentage_uplink[i]); + total_slice_percentage_current_uplink= total_slice_percentage_uplink; + slice_percentage_current_uplink[i] = slice_percentage_uplink[i]; + + } + // check if the slice max MCS, and log the console + if (slice_maxmcs_current_uplink[i] != slice_maxmcs_uplink[i]){ + if ((slice_maxmcs_uplink[i] >= 0) && (slice_maxmcs_uplink[i] <= 16)){ + LOG_N(MAC,"[eNB %d][SLICE %d][UL] frame %d subframe %d: slice MAX MCS has changed: %d-->%d\n", + mod_id, i, frame, subframe, slice_maxmcs_current_uplink[i], slice_maxmcs_uplink[i]); + slice_maxmcs_current_uplink[i] = slice_maxmcs_uplink[i]; + } else { + LOG_W(MAC,"[eNB %d][SLICE %d][UL] invalid slice max mcs %d, revert the previous value %d\n",mod_id, i, slice_maxmcs_uplink[i],slice_maxmcs_current_uplink[i]); + slice_maxmcs_uplink[i]= slice_maxmcs_current_uplink[i]; + + } + } + + // check if a new scheduler, and log the console + if (update_ul_scheduler_current[i] != update_ul_scheduler[i]){ + LOG_N(MAC,"[eNB %d][SLICE %d][UL] frame %d subframe %d: UL scheduler for this slice is updated: %s \n", + mod_id, i, frame, subframe, ul_scheduler_type[i]); + + update_ul_scheduler_current[i] = update_ul_scheduler[i]; + } } - + else { + + if (n_active_slices_uplink == n_active_slices_current_uplink){ + LOG_W(MAC,"[eNB %d][SLICE %d][UL] invalid total RB share (%f->%f), reduce proportionally the RB share by 0.1\n", + mod_id,i, + total_slice_percentage_current_uplink, total_slice_percentage_uplink); + if (slice_percentage_uplink[i] > avg_slice_percentage_uplink){ + slice_percentage_uplink[i]-=0.1; + total_slice_percentage_uplink-=0.1; + } + } else { + // here we can correct the values, e.g. reduce proportionally + LOG_W(MAC,"[eNB %d][SLICE %d][UL] invalid total RB share (%f->%f), revert the number of slice to its previous value (%d->%d)\n", + mod_id,i, + total_slice_percentage_current_uplink, total_slice_percentage_uplink, + n_active_slices_uplink, n_active_slices_current_uplink); + n_active_slices_uplink = n_active_slices_current_uplink; + slice_percentage_uplink[i] = slice_percentage_current_uplink[i]; + } + } + // Run each enabled slice-specific schedulers one by one - //LOG_N(MAC,"[eNB %d]frame %d subframe %d slice %d: calling the scheduler\n", mod_id, frame, subframe,i); - - slice_sched_ul[i](mod_id, frame, cooperation_flag, subframe, sched_subframe,ul_info); - } - - - } void flexran_schedule_ue_ul_spec_embb(mid_t mod_id, - frame_t frame, - unsigned char cooperation_flag, - uint32_t subframe, - unsigned char sched_subframe, - Protocol__FlexranMessage **ul_info) - + frame_t frame, + unsigned char cooperation_flag, + uint32_t subframe, + unsigned char sched_subframe, + Protocol__FlexranMessage **ul_info) + { flexran_agent_schedule_ulsch_ue_spec(mod_id, - frame, - cooperation_flag, - subframe, - sched_subframe, - ul_info); + frame, + cooperation_flag, + subframe, + sched_subframe, + ul_info); } From b1acde2007a04995373e4bea44e6d8565cf49a9e Mon Sep 17 00:00:00 2001 From: shahab SHARIAT BAGHERI Date: Thu, 21 Dec 2017 13:55:37 +0100 Subject: [PATCH 122/284] Neighbouring cell RRC measurement + decrease warning --- .../CONTROL_MODULES/RRC/flexran_agent_rrc.c | 110 ++++++++++--- openair2/ENB_APP/flexran_agent_handler.c | 2 +- openair2/ENB_APP/flexran_agent_ran_api.c | 149 ++++++++++++++++-- openair2/ENB_APP/flexran_agent_ran_api.h | 22 ++- openair2/RRC/LITE/rrc_eNB.c | 4 +- 5 files changed, 248 insertions(+), 39 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c index 7a251be78b..6f42d1da97 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c @@ -492,7 +492,7 @@ int flexran_agent_rrc_stats_reply(mid_t mod_id, // Protocol__FlexHeader *header; - int i; + int i,j; /* Allocate memory for list of UE reports */ if (report_config->nr_ue > 0) { @@ -501,29 +501,86 @@ int flexran_agent_rrc_stats_reply(mid_t mod_id, /* Check flag for creation of buffer status report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RRC_MEASUREMENTS) { - - Protocol__FlexRrcMeasurements *rrc_measurements; - rrc_measurements = malloc(sizeof(Protocol__FlexRrcMeasurements)); - if (rrc_measurements == NULL) - goto error; - protocol__flex_rrc_measurements__init(rrc_measurements); - - rrc_measurements->measid = flexran_get_rrc_pcell_measid(mod_id,i); - rrc_measurements->has_measid = 1; - - rrc_measurements->pcell_rsrp = flexran_get_rrc_pcell_rsrp(mod_id,i) - 140; - rrc_measurements->has_pcell_rsrp = 1; - - rrc_measurements->pcell_rsrq = flexran_get_rrc_pcell_rsrq(mod_id,i)/2 - 20; - rrc_measurements->has_pcell_rsrq = 1 ; - - ue_report[i]->rrc_measurements = rrc_measurements; - + + /*Source Cell*/ + Protocol__FlexRrcMeasurements *rrc_measurements; + rrc_measurements = malloc(sizeof(Protocol__FlexRrcMeasurements)); + if (rrc_measurements == NULL) + goto error; + protocol__flex_rrc_measurements__init(rrc_measurements); + + rrc_measurements->measid = flexran_get_rrc_pcell_measid(mod_id,i); + rrc_measurements->has_measid = 1; + + rrc_measurements->pcell_rsrp = flexran_get_rrc_pcell_rsrp(mod_id,i); + rrc_measurements->has_pcell_rsrp = 1; + + rrc_measurements->pcell_rsrq = flexran_get_rrc_pcell_rsrq(mod_id,i); + rrc_measurements->has_pcell_rsrq = 1 ; + + + /* Target Cell, Neghibouring*/ + Protocol__FlexNeighCellsMeasurements *neigh_meas; + neigh_meas = malloc(sizeof(Protocol__FlexNeighCellsMeasurements)); + if (neigh_meas == NULL) + goto error; + protocol__flex_neigh_cells_measurements__init(neigh_meas); + + + neigh_meas->n_eutra_meas = flexran_get_rrc_num_ncell(mod_id, i); + + Protocol__FlexEutraMeasurements **eutra_meas = NULL; + + if (neigh_meas->n_eutra_meas > 0){ + + eutra_meas = malloc(sizeof(Protocol__FlexEutraMeasurements) * neigh_meas->n_eutra_meas); + if (eutra_meas == NULL) + goto error; + + for (j = 0; j < neigh_meas->n_eutra_meas; j++ ){ + + eutra_meas[j] = malloc(sizeof(Protocol__FlexEutraMeasurements)); + if (eutra_meas[j] == NULL) + goto error; + + protocol__flex_eutra_measurements__init(eutra_meas[j]); + + eutra_meas[j]->phys_cell_id = flexran_get_rrc_neigh_phy_cell_id(mod_id, i, j); + eutra_meas[j]->has_phys_cell_id = 1; + + + /*TODO: Extend for CGI and PLMNID*/ + + Protocol__FlexEutraRefSignalMeas *meas_result; + meas_result = malloc(sizeof(Protocol__FlexEutraRefSignalMeas)); + + protocol__flex_eutra_ref_signal_meas__init(meas_result); + + meas_result->rsrp = flexran_get_rrc_neigh_rsrp(mod_id, i, eutra_meas[j]->phys_cell_id); + meas_result->has_rsrp = 1; + + meas_result->rsrq = flexran_get_rrc_neigh_rsrq(mod_id, i, eutra_meas[j]->phys_cell_id); + meas_result->has_rsrq = 1; + + eutra_meas[j]->meas_result = meas_result; + + } + + neigh_meas->eutra_meas = eutra_meas; + + rrc_measurements->neigh_meas = neigh_meas; + + } + + ue_report[i]->rrc_measurements = rrc_measurements; + } - } + + } + } - /* To be extended for RRC layer */ + /* To be considered for RRC signaling of cell*/ // if (report_config->nr_cc > 0) { @@ -564,6 +621,17 @@ int flexran_agent_rrc_stats_reply(mid_t mod_id, error: + for (i = 0; i < report_config->nr_ue; i++){ + + if (ue_report[i]->rrc_measurements->neigh_meas != NULL){ + for (j = 0; j < flexran_get_rrc_num_ncell(mod_id, i); j++){ + + free(ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]); + } + free(ue_report[i]->rrc_measurements->neigh_meas); + } + } + if (cell_report != NULL) free(cell_report); if (ue_report != NULL) diff --git a/openair2/ENB_APP/flexran_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c index 2a36b3e5c8..02df1d41dc 100644 --- a/openair2/ENB_APP/flexran_agent_handler.c +++ b/openair2/ENB_APP/flexran_agent_handler.c @@ -756,7 +756,7 @@ err_code_t flexran_agent_init_cont_stats_update(mid_t mod_id) { if (stats_context[mod_id].mutex == NULL) goto error; if (pthread_mutex_init(stats_context[mod_id].mutex, NULL)) - goto error;; + goto error; return 0; diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 556f018f7c..16462b4d40 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -1135,19 +1135,23 @@ uint32_t flexran_get_pdcp_sfn(const mid_t mod_id){ } /*PDCP super frame counter flexRAN*/ -uint32_t flexran_set_pdcp_tx_stat_window(const mid_t mod_id, const mid_t ue_id, uint16_t obs_window){ - if (obs_window > 0 ) +void flexran_set_pdcp_tx_stat_window(const mid_t mod_id, const mid_t ue_id, uint16_t obs_window){ + if (obs_window > 0 ){ Pdcp_stats_tx_window_ms[mod_id][ue_id]=obs_window; - else + } + else{ Pdcp_stats_tx_window_ms[mod_id][ue_id]=1000; + } } /*PDCP super frame counter flexRAN*/ -uint32_t flexran_set_pdcp_rx_stat_window(const mid_t mod_id, const mid_t ue_id, uint16_t obs_window){ - if (obs_window > 0 ) +void flexran_set_pdcp_rx_stat_window(const mid_t mod_id, const mid_t ue_id, uint16_t obs_window){ + if (obs_window > 0 ){ Pdcp_stats_rx_window_ms[mod_id][ue_id]=obs_window; - else + } + else{ Pdcp_stats_rx_window_ms[mod_id][ue_id]=1000; + } } /*PDCP num tx pdu status flexRAN*/ @@ -1256,7 +1260,7 @@ int flexran_get_rrc_pcell_rsrp(mid_t mod_id, mid_t ue_id) { ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { if(ue_context_p->ue_context.measResults != NULL) { - return ue_context_p->ue_context.measResults->measResultPCell.rsrpResult; + return RSRP_meas_mapping[ue_context_p->ue_context.measResults->measResultPCell.rsrpResult]; } else { return -1; } @@ -1273,7 +1277,7 @@ int flexran_get_rrc_pcell_rsrq(mid_t mod_id, mid_t ue_id) { ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { if(ue_context_p->ue_context.measResults != NULL) { - return ue_context_p->ue_context.measResults->measResultPCell.rsrqResult; + return RSRQ_meas_mapping[ue_context_p->ue_context.measResults->measResultPCell.rsrqResult]; } else { return -1; } @@ -1281,8 +1285,48 @@ int flexran_get_rrc_pcell_rsrq(mid_t mod_id, mid_t ue_id) { return -1; } } -/* -void* flexran_get_rrc_ncell_measresult_eutra(mid_t mod_id, mid_t ue_id) { + +/*Number of neighbouring cells for specific UE*/ +int flexran_get_rrc_num_ncell(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return 0; + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + + if (ue_context_p->ue_context.measResults != NULL){ + + if(ue_context_p->ue_context.measResults->measResultNeighCells != NULL) { + + if (ue_context_p->ue_context.measResults->measResultNeighCells->present == MeasResults__measResultNeighCells_PR_measResultListEUTRA) { + + return ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.count; + } + else{ + + return 0; + } + + } else { + + return 0; + } + + } else { + + return 0; + + } + + } else { + return 0; + } + +} + +int flexran_get_rrc_neigh_phy_cell_id(mid_t mod_id, mid_t ue_id, int cell_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); @@ -1290,8 +1334,88 @@ void* flexran_get_rrc_ncell_measresult_eutra(mid_t mod_id, mid_t ue_id) { ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { - if(ue_context_p->ue_context.measResults != NULL) { - return &ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA; + if(ue_context_p->ue_context.measResults->measResultNeighCells != NULL) { + + if (ue_context_p->ue_context.measResults->measResultNeighCells->present == MeasResults__measResultNeighCells_PR_measResultListEUTRA) { + + return ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->physCellId; + + } + else { + + return -1; + } + } else { + return -1; + } + } else { + return -1; + } +} + +int flexran_get_rrc_neigh_rsrp(mid_t mod_id, mid_t ue_id, int cell_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return -1; + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + + if(ue_context_p->ue_context.measResults->measResultNeighCells != NULL) { + + if (ue_context_p->ue_context.measResults->measResultNeighCells->present == MeasResults__measResultNeighCells_PR_measResultListEUTRA) { + + if (ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrpResult){ + return RSRP_meas_mapping[*(ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrpResult)]; + + } + else { + + return 0; + } + + } + else { + + return -1; + } + + } + else { + return -1; + } + + } + else { + return -1; + } +} + +int flexran_get_rrc_neigh_rsrq(mid_t mod_id, mid_t ue_id, int cell_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + if (eNB_rrc_inst_not_ready()) return -1; + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.measResults->measResultNeighCells != NULL) { + if (ue_context_p->ue_context.measResults->measResultNeighCells->present == MeasResults__measResultNeighCells_PR_measResultListEUTRA) { + + if (ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrqResult){ + return RSRQ_meas_mapping[*(ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrqResult)]; + + } + else { + + return 0; + } + } + else { + + return -1; + } } else { return -1; } @@ -1299,4 +1423,3 @@ void* flexran_get_rrc_ncell_measresult_eutra(mid_t mod_id, mid_t ue_id) { return -1; } } -*/ diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 12ca5febea..05c6817136 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -346,10 +346,10 @@ int flexran_get_rrc_status(const mid_t mod_id, const rnti_t rntiP); uint32_t flexran_get_pdcp_sfn(const mid_t mod_id); /*PDCP pdcp tx stats window*/ -uint32_t flexran_set_pdcp_tx_stat_window(const mid_t mod_id, const mid_t ue_id, uint16_t obs_window); +void flexran_set_pdcp_tx_stat_window(const mid_t mod_id, const mid_t ue_id, uint16_t obs_window); /*PDCP pdcp rx stats window*/ -uint32_t flexran_set_pdcp_rx_stat_window(const mid_t mod_id, const mid_t ue_id, uint16_t obs_window); +void flexran_set_pdcp_rx_stat_window(const mid_t mod_id, const mid_t ue_id, uint16_t obs_window); /*PDCP num tx pdu status flexRAN*/ uint32_t flexran_get_pdcp_tx(const mid_t mod_id, const mid_t ue_id, const lcid_t lcid); @@ -406,3 +406,21 @@ int flexran_get_rrc_pcell_rsrp(mid_t mod_id, mid_t ue_id); /*Get primary cell RSRQ measurement flexRAN*/ int flexran_get_rrc_pcell_rsrq(mid_t mod_id, mid_t ue_id); + +/* Get RRC neighbouring measurement */ +int flexran_get_rrc_num_ncell(mid_t mod_id, mid_t ue_id); + +/*Get physical cell id*/ +int flexran_get_rrc_neigh_phy_cell_id(mid_t mod_id, mid_t ue_id, int cell_id); + +/*Get RSRP of neighbouring Cell*/ +int flexran_get_rrc_neigh_rsrp(mid_t mod_id, mid_t ue_id, int cell_id); + +/*Get RSRQ of neighbouring Cell*/ +int flexran_get_rrc_neigh_rsrq(mid_t mod_id, mid_t ue_id, int cell_id); + +/*Get MCC PLMN identity neighbouring Cell*/ +int flexran_get_rrc_neigh_plmn_mcc(mid_t mod_id, mid_t ue_id, int cell_id); + +/*Get MNC PLMN identity neighbouring Cell*/ +int flexran_get_rrc_neigh_plmn_mnc(mid_t mod_id, mid_t ue_id, int cell_id); \ No newline at end of file diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index c441c102e3..c3c1421533 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -2868,13 +2868,13 @@ rrc_eNB_process_MeasurementReport( return; if (measResults2->measResultNeighCells->choice.measResultListEUTRA.list.count > 0) { - neighboring_cells=measResults2->measResultNeighCells->choice.measResultListEUTRA.list.count; + neighboring_cells = measResults2->measResultNeighCells->choice.measResultListEUTRA.list.count; if (ue_context_pP->ue_context.measResults->measResultNeighCells == NULL) { ue_context_pP->ue_context.measResults->measResultNeighCells = CALLOC(1, sizeof(*measResults2->measResultNeighCells)*neighboring_cells); } - ue_context_pP->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.count=neighboring_cells; + ue_context_pP->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.count = neighboring_cells; for (i=0; i < neighboring_cells; i++){ memcpy (ue_context_pP->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[i], measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[i], From a09728addba81262300e475a87cacdcf88f21b9b Mon Sep 17 00:00:00 2001 From: shahab SHARIAT BAGHERI Date: Sun, 24 Dec 2017 10:17:18 +0100 Subject: [PATCH 123/284] Warning decreasing --- openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c | 2 +- openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c | 2 +- openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index a04987f07c..e5b0dc61d8 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -736,7 +736,7 @@ flexran_schedule_ue_dl_spec_default(mid_t mod_id, } for (i = 0; i < n_active_slices; i++) { if (slice_percentage[i] < 0 ){ - LOG_W(MAC, "[eNB %d] frame %d subframe %d:invalid slice %d percentage %d. resetting to zero", + LOG_W(MAC, "[eNB %d] frame %d subframe %d:invalid slice %d percentage %f. resetting to zero", mod_id, frame, subframe, i, slice_percentage[i]); slice_percentage[i]=0; } diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c index 64f21482fb..86ea61d943 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c @@ -429,7 +429,7 @@ flexran_schedule_ue_ul_spec_default(mid_t mod_id, } for (i = 0; i < n_active_slices_uplink; i++) { if (slice_percentage_uplink[i] < 0 ){ - LOG_W(MAC, "[eNB %d] frame %d subframe %d:invalid slice %d percentage %d. resetting to zero", + LOG_W(MAC, "[eNB %d] frame %d subframe %d:invalid slice %d percentage %f. resetting to zero", mod_id, frame, subframe, i, slice_percentage_uplink[i]); slice_percentage_uplink[i]=0; } diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index d74e8552d6..08bf37fb94 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -1112,7 +1112,7 @@ pdcp_run ( } void pdcp_add_UE(const protocol_ctxt_t* const ctxt_pP){ - int i, ue_flag=1, ret=-1;; + int i, ue_flag=1; //, ret=-1; to be decied later for (i=0; i < NUMBER_OF_UE_MAX; i++){ if (pdcp_enb[ctxt_pP->module_id].rnti[i] == ctxt_pP->rnti) { ue_flag=-1; @@ -1126,7 +1126,7 @@ void pdcp_add_UE(const protocol_ctxt_t* const ctxt_pP){ pdcp_enb[ctxt_pP->module_id].uid[i]=i; pdcp_enb[ctxt_pP->module_id].num_ues++; printf("add new uid is %d %x\n\n", i, ctxt_pP->rnti); - ret=1; + // ret=1; break; } } From 02d18cc583ae35bb7ed8134c68836067a433a0c1 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 28 Dec 2017 17:30:00 -0800 Subject: [PATCH 124/284] noS1 will compile and run correctly on develop, also for oaisim/RRU --- cmake_targets/CMakeLists.txt | 2 ++ openair2/RRC/LITE/rrc_UE.c | 2 +- openair2/RRC/LITE/rrc_eNB.c | 2 +- targets/SIMU/USER/oaisim_functions.c | 5 ++++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 3dbb61b5ae..f523ae09bb 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1803,6 +1803,7 @@ add_executable(lte-softmodem-nos1 ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c ${OPENAIR_TARGETS}/RT/USER/lte-ue.c ${OPENAIR_TARGETS}/RT/USER/lte-enb.c + ${OPENAIR_TARGETS}/RT/USER/lte-ru.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c @@ -1934,6 +1935,7 @@ add_executable(oaisim_nos1 ${OPENAIR_BIN_DIR}/messages_xml.h ${OPENAIR_TARGETS}/RT/USER/lte-ue.c ${OPENAIR_TARGETS}/RT/USER/lte-enb.c + ${OPENAIR_TARGETS}/RT/USER/lte-ru.c ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c ${OPENAIR_TARGETS}/SIMU/USER/channel_sim.c ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index f0f495e8b7..56dbe9e75c 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -1540,7 +1540,7 @@ rrc_ue_process_radioResourceConfigDedicated( UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State = RRC_CONNECTED; LOG_I(RRC,"[UE %d] State = RRC_CONNECTED (eNB %d)\n",ctxt_pP->module_id,eNB_index); -#if !defined(ENABLE_USE_MME) && defined(OAI_EMU) +#if 0//!defined(ENABLE_USE_MME) && defined(OAI_EMU) # ifdef OAI_EMU rrc_eNB_emulation_notify_ue_module_id( ctxt_pP->module_id, diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 28d6982652..ff31925ea8 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -608,7 +608,7 @@ rrc_eNB_get_next_free_ue_context( } } -#if !defined(ENABLE_USE_MME) +#if 0 //!defined(ENABLE_USE_MME) void rrc_eNB_emulation_notify_ue_module_id( const module_id_t ue_module_idP, const rnti_t rntiP, diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index dce104dc0a..98dd11be75 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -782,7 +782,10 @@ void get_simulation_options(int argc, char *argv[]) } } - + if ( load_configmodule(argc,argv) == NULL) { + exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); + } + if (RC.config_file_name != NULL) { /* Read eNB configuration file */ RCConfig(); From 55af824cc045317d9bfad6e25570562c775458ea Mon Sep 17 00:00:00 2001 From: "Wolfgang A. Mozart" Date: Tue, 2 Jan 2018 08:06:05 +0100 Subject: [PATCH 125/284] some extra logging --- targets/SIMU/USER/oaisim.c | 196 +-------------------------- targets/SIMU/USER/oaisim_functions.c | 22 +-- 2 files changed, 13 insertions(+), 205 deletions(-) diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index 359faf4672..4b6e27178f 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -742,7 +742,7 @@ l2l1_task (void *args_p) int subframe_ru_mask_local = subframe_ru_mask; int subframe_UE_mask_local = subframe_UE_mask; pthread_mutex_unlock(&subframe_mutex); - LOG_D(EMU,"Frame %d, Subframe %d: Checking masks %x,%x\n",frame,sf,subframe_ru_mask_local,subframe_UE_mask_local); + LOG_D(EMU,"Frame %d, Subframe %d, NB_RU %d, NB_UE %d: Checking masks %x,%x\n",frame,sf,NB_RU,NB_UE_INST,subframe_ru_mask_local,subframe_UE_mask_local); if ((subframe_ru_mask_local == ((1<= (UE_inst * 20)) // activate UE only after 20*UE_id frames so that different UEs turn on separately -#endif - { - LOG_D(EMU, - "PHY procedures UE %d for frame %d, slot %d (subframe TX %d, RX %d)\n", - UE_inst, frame % MAX_FRAME_NUMBER, slot, next_slot >> 1, - last_slot >> 1); - - if (PHY_vars_UE_g[UE_inst][0]->UE_mode[0] - != NOT_SYNCHED) { - if (frame > 0) { - PHY_vars_UE_g[UE_inst][0]->frame_rx = frame % MAX_FRAME_NUMBER; - PHY_vars_UE_g[UE_inst][0]->slot_rx = last_slot; - PHY_vars_UE_g[UE_inst][0]->slot_tx = next_slot; - - if (next_slot > 1) - PHY_vars_UE_g[UE_inst][0]->frame_tx = frame % MAX_FRAME_NUMBER; - else - PHY_vars_UE_g[UE_inst][0]->frame_tx = (frame + 1) % MAX_FRAME_NUMBER; -#ifdef OPENAIR2 - //Application - update_otg_UE (UE_inst, oai_emulation.info.time_ms); - - //Access layer - // PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, UE_inst, ENB_FLAG_NO, NOT_A_RNTI, frame, next_slot>>1, 0); - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, UE_inst, 0, ENB_FLAG_NO, NOT_A_RNTI, frame % MAX_FRAME_NUMBER, next_slot); - pdcp_run (&ctxt); -#endif - - for (CC_id = 0; CC_id < MAX_NUM_CCs; - CC_id++) { - phy_procedures_UE_lte ( - PHY_vars_UE_g[UE_inst][CC_id], - 0, abstraction_flag, - normal_txrx, no_relay, - NULL); - } - - ue_data[UE_inst]->tx_power_dBm = - PHY_vars_UE_g[UE_inst][0]->tx_power_dBm; - } - } else { - if (abstraction_flag == 1) { - LOG_E(EMU, - "sync not supported in abstraction mode (UE%d,mode%d)\n", - UE_inst, - PHY_vars_UE_g[UE_inst][0]->UE_mode[0]); - exit (-1); - } - - if ((frame > 0) - && (last_slot - == (LTE_SLOTS_PER_FRAME - - 2))) { - initial_sync (PHY_vars_UE_g[UE_inst][0], - normal_txrx); - - } - } - -#ifdef PRINT_STATS - - if(last_slot==2 && frame%10==0) { - if (UE_stats_th[UE_inst]) { - fprintf(UE_stats_th[UE_inst],"%d %d\n",frame%MAX_FRAME_NUMBER, PHY_vars_UE_g[UE_inst][0]->bitrate[0]/1000); - } - } - - if (UE_stats[UE_inst]) { - len = dump_ue_stats (PHY_vars_UE_g[UE_inst][0], stats_buffer, 0, normal_txrx, 0); - rewind (UE_stats[UE_inst]); - fwrite (stats_buffer, 1, len, UE_stats[UE_inst]); - fflush(UE_stats[UE_inst]); - } - -#endif - } - } - } - -#if defined(Rel10) || defined(Rel14) - - for (RN_id=oai_emulation.info.first_rn_local; - RN_idframe = frame % MAX_FRAME_NUMBER; - - if ( oai_emulation.info.frame_type == 0) { - // RN == UE - if (frame>0) { - if (PHY_vars_UE_g[UE_inst][0]->UE_mode[0] != NOT_SYNCHED) { - LOG_D(EMU,"[RN %d] PHY procedures UE %d for frame %d, slot %d (subframe TX %d, RX %d)\n", - RN_id, UE_inst, frame, slot, next_slot >> 1,last_slot>>1); - PHY_vars_UE_g[UE_inst][0]->frame_rx = frame % MAX_FRAME_NUMBER; - PHY_vars_UE_g[UE_inst][0]->slot_rx = last_slot; - PHY_vars_UE_g[UE_inst][0]->slot_tx = next_slot; - - if (next_slot>1) PHY_vars_UE_g[UE_inst][0]->frame_tx = frame % MAX_FRAME_NUMBER; - else PHY_vars_UE_g[UE_inst][0]->frame_tx = (frame+1) % MAX_FRAME_NUMBER; - - phy_procedures_UE_lte (PHY_vars_UE_g[UE_inst][0], 0, abstraction_flag,normal_txrx, - r_type, PHY_vars_RN_g[RN_id]); - } else if (last_slot == (LTE_SLOTS_PER_FRAME-2)) { - initial_sync(PHY_vars_UE_g[UE_inst][0],normal_txrx); - } - } - - emu_transport (frame % MAX_FRAME_NUMBER, sf<<1, ((sf+4)%10)<<1, subframe_select(&PHY_vars_eNB_g[0][0]->frame_parms,sf), - oai_emulation.info.frame_type[0], ethernet_flag); - - start_meas (&dl_chan_stats); - - for (UE_inst = 0; UE_inst < NB_UE_INST; UE_inst++) - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - //#warning figure out what to do with UE frame_parms during initial_sync - do_DL_sig (r_re0, - r_im0, - r_re, - r_im, - s_re, - s_im, - eNB2UE, - enb_data, - ue_data, - PHY_vars_eNB_g[0][CC_id]->proc.proc_rxtx[sf&1].subframe_tx<<1, - abstraction_flag, - &PHY_vars_eNB_g[0][CC_id]->frame_parms, - UE_inst, CC_id); - do_DL_sig (r_re0, - r_im0, - r_re, - r_im,n - - s_re, - s_im, - eNB2UE, - enb_data, - ue_data, - (PHY_vars_eNB_g[0][CC_id]->proc.proc_rxtx[sf&1].subframe_tx<<1)+1, - abstraction_flag, - &PHY_vars_eNB_g[0][CC_id]->frame_parms, - UE_inst, CC_id); - } - - stop_meas (&dl_chan_stats); - - - start_meas (&ul_chan_stats); - - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - //#warning figure out what to do with UE frame_parms during initial_sync - do_UL_sig (r_re0, r_im0, r_re, r_im, s_re, s_im, UE2eNB, - enb_data, ue_data, - PHY_vars_UE_g[0][CC_id]->proc.proc_rxtx[sf&1].subframe_tx<<1, - abstraction_flag, - &PHY_vars_eNB_g[0][CC_id]->frame_parms, - frame % MAX_FRAME_NUMBER, CC_id); - do_UL_sig (r_re0, r_im0, r_re, r_im, s_re, s_im, UE2eNB, - enb_data, ue_data, - (PHY_vars_UE_g[0][CC_id]->proc.proc_rxtx[sf&1].subframe_tx<<1)+1, - abstraction_flag, - &PHY_vars_eNB_g[0][CC_id]->frame_parms, - frame % MAX_FRAME_NUMBER, CC_id); - } - - stop_meas (&ul_chan_stats); - - */ - if ((sf == 0) && ((frame % MAX_FRAME_NUMBER) == 0) && (abstraction_flag == 0) && (oai_emulation.info.n_frames == 1)) { diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index 9d0c5a6973..4f30a5c2e7 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -1106,7 +1106,9 @@ int UE_trx_read(openair0_device *device, openair0_timestamp *ptimestamp, void ** *ptimestamp = last_UE_rx_timestamp[UE_id][CC_id]; - LOG_D(EMU,"DL simulation 0: UE_trx_read nsamps %d TS %llu (%llu, offset %d) antenna %d\n",nsamps, + LOG_D(EMU,"UE %d DL simulation 0: UE_trx_read nsamps %d TS %llu (%llu, offset %d) antenna %d\n", + UE_id, + nsamps, (unsigned long long)current_UE_rx_timestamp[UE_id][CC_id], (unsigned long long)last_UE_rx_timestamp[UE_id][CC_id], (int)(last_UE_rx_timestamp[UE_id][CC_id]%sptti), @@ -1119,13 +1121,13 @@ int UE_trx_read(openair0_device *device, openair0_timestamp *ptimestamp, void ** read_size = sptti; while (sample_countframe_parms, UE_id, CC_id); - LOG_D(EMU,"DL simulation 6: UE_trx_read @ TS %llu (%llu)=> frame %d, subframe %d\n", - (unsigned long long)current_UE_rx_timestamp[UE_id][CC_id], + LOG_D(EMU,"UE %d: DL simulation 6: UE_trx_read @ TS %llu (%llu)=> frame %d, subframe %d\n", + UE_id,(unsigned long long)current_UE_rx_timestamp[UE_id][CC_id], (unsigned long long)last_UE_rx_timestamp[UE_id][CC_id], ((unsigned long long)last_UE_rx_timestamp[UE_id][CC_id]/(sptti*10))&1023, subframe); From b6b86292d0991414fd41babc254a425856b4a089 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Tue, 2 Jan 2018 08:39:08 -0800 Subject: [PATCH 126/284] small changes in tracing --- openair1/SCHED/phy_procedures_lte_ue.c | 60 +++++++++++++------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 28abb570c8..a61aacd303 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -1481,38 +1481,36 @@ void ue_prach_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin ue->tx_power_dBm[subframe_tx], dB_fixed(prach_power), ue->prach_vars[eNB_id]->amp); - } else { - UE_transport_info[ue->Mod_id][ue->CC_id].cntl.prach_flag=1; - UE_transport_info[ue->Mod_id][ue->CC_id].cntl.prach_id=ue->prach_resources[eNB_id]->ra_PreambleIndex; + + + + if (ue->mac_enabled==1){ + Msg1_transmitted(ue->Mod_id, + ue->CC_id, + frame_tx, + eNB_id); + } + + LOG_I(PHY,"[UE %d][RAPROC] Frame %d, subframe %d: Generating PRACH (eNB %d) preamble index %d for UL, TX power %d dBm (PL %d dB), l3msg \n", + ue->Mod_id,frame_tx,subframe_tx,eNB_id, + ue->prach_resources[eNB_id]->ra_PreambleIndex, + ue->prach_resources[eNB_id]->ra_PREAMBLE_RECEIVED_TARGET_POWER+get_PL(ue->Mod_id,ue->CC_id,eNB_id), + get_PL(ue->Mod_id,ue->CC_id,eNB_id)); + + + + // if we're calibrating the PRACH kill the pointer to its resources so that the RA protocol doesn't continue + if (mode == calib_prach_tx) + ue->prach_resources[eNB_id]=NULL; + + LOG_D(PHY,"[UE %d] frame %d subframe %d : generate_prach %d, prach_cnt %d\n", + ue->Mod_id,frame_tx,subframe_tx,ue->generate_prach,ue->prach_cnt); + + ue->prach_cnt++; + + if (ue->prach_cnt==3) + ue->generate_prach=0; } - - if (ue->mac_enabled==1){ - Msg1_transmitted(ue->Mod_id, - ue->CC_id, - frame_tx, - eNB_id); - } - - LOG_I(PHY,"[UE %d][RAPROC] Frame %d, subframe %d: Generating PRACH (eNB %d) preamble index %d for UL, TX power %d dBm (PL %d dB), l3msg \n", - ue->Mod_id,frame_tx,subframe_tx,eNB_id, - ue->prach_resources[eNB_id]->ra_PreambleIndex, - ue->prach_resources[eNB_id]->ra_PREAMBLE_RECEIVED_TARGET_POWER+get_PL(ue->Mod_id,ue->CC_id,eNB_id), - get_PL(ue->Mod_id,ue->CC_id,eNB_id)); - - - - // if we're calibrating the PRACH kill the pointer to its resources so that the RA protocol doesn't continue - if (mode == calib_prach_tx) - ue->prach_resources[eNB_id]=NULL; - - LOG_D(PHY,"[UE %d] frame %d subframe %d : generate_prach %d, prach_cnt %d\n", - ue->Mod_id,frame_tx,subframe_tx,ue->generate_prach,ue->prach_cnt); - - ue->prach_cnt++; - - if (ue->prach_cnt==3) - ue->generate_prach=0; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, VCD_FUNCTION_OUT); } From c5ca2bd86227d958175f2a5569546c1d60179d07 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 3 Jan 2018 11:19:54 +0100 Subject: [PATCH 127/284] hotfix: clear DCI padding bits The problem is the following (as reported by an user): "one UE is attached to OAI system. UE is near the antenna. Try to detach the UE and attach again. Repeat this procedure for 5-6 times. OAI system does not work and any the UE can not attach to this system. I use TEMS software and I can see MIB signaling on this UE but UE can not decode SIB1 and SIB2." What happens is that the DCI for SIB1 and SIB2 is not cleared before use. That is the bits in the 'padding' field keep the values that were set before. If the structure has been used to transmit other DCIs (eg. for UEs) in the past, it may be reused with some of those bits set to 1. When receiving this DCI, the UE won't accept it because it gets some bits at 1 where it expects them to be 0. The short-term/quick solution is to clear the 'padding' field. A better solution would be to rewrite this part of the code, which is way too complicated for what it does. But this takes too much time. In dci.h the field 'dummy' of some structures was renamed to 'padding'. The fields 'padding32' and 'padding64' were also renamed to 'padding' for consistency. Some structures (DCI2B_1_5MHz_TDD, DCI2B_10MHz_FDD, DCI2D_1_5MHz_FDD, DCI2D_5MHz_FDD, DCI2D_10MHz_FDD) had a 'padding' field at the end, which was renamed to 'padding0'. I don't know if this field should be here at all. To me this field looks very suspicious. When we test DCIs 2B and 2D we should be careful. --- openair1/PHY/LTE_TRANSPORT/dci.h | 140 ++++++++++++------------- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 98 +++++++++++++---- 2 files changed, 144 insertions(+), 94 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci.h b/openair1/PHY/LTE_TRANSPORT/dci.h index 0e74324b2c..9381dd63fd 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci.h +++ b/openair1/PHY/LTE_TRANSPORT/dci.h @@ -482,8 +482,8 @@ typedef struct DCI1A_20MHz_FDD DCI1A_20MHz_FDD_t; /// DCI Format Type 1 (1.5 MHz, TDD, 23 bits) struct DCI1_1_5MHz_TDD { - /// Dummy bits to align to 32-bits - uint32_t dummy:9; + /// padding bits to align to 32-bits + uint32_t padding:9; /// DAI (TDD) uint32_t dai:2; /// Power Control @@ -507,8 +507,8 @@ typedef struct DCI1_1_5MHz_TDD DCI1_1_5MHz_TDD_t; /// DCI Format Type 1 (5 MHz, TDD, 30 bits) struct DCI1_5MHz_TDD { - /// Dummy bits to align to 32-bits - uint32_t dummy:2; + /// padding bits to align to 32-bits + uint32_t padding:2; /// DAI (TDD) uint32_t dai:2; /// Power Control @@ -532,8 +532,8 @@ typedef struct DCI1_5MHz_TDD DCI1_5MHz_TDD_t; /// DCI Format Type 1 (10 MHz, TDD, 34 bits) struct DCI1_10MHz_TDD { - /// Dummy bits to align to 64-bits - uint64_t dummy:30; + /// padding bits to align to 64-bits + uint64_t padding:30; /// DAI (TDD) uint64_t dai:2; /// Power Control @@ -557,8 +557,8 @@ typedef struct DCI1_10MHz_TDD DCI1_10MHz_TDD_t; /// DCI Format Type 1 (20 MHz, TDD, 42 bits) struct DCI1_20MHz_TDD { - /// Dummy bits to align to 64-bits - uint64_t dummy:22; + /// padding bits to align to 64-bits + uint64_t padding:22; /// DAI (TDD) uint64_t dai:2; /// Power Control @@ -582,8 +582,8 @@ typedef struct DCI1_20MHz_TDD DCI1_20MHz_TDD_t; /// DCI Format Type 1 (1.5 MHz, FDD, 21 bits) struct DCI1_1_5MHz_FDD { - /// Dummy bits to align to 32-bits - uint32_t dummy:11; + /// padding bits to align to 32-bits + uint32_t padding:11; /// Power Control uint32_t TPC:2; /// Redundancy version @@ -605,8 +605,8 @@ typedef struct DCI1_1_5MHz_FDD DCI1_1_5MHz_FDD_t; /// DCI Format Type 1 (5 MHz, FDD, 27 bits) struct DCI1_5MHz_FDD { - /// dummy bits (not transmitted) - uint32_t dummy:5; + /// padding its (not transmitted) + uint32_t padding:5; /// Power Control uint32_t TPC:2; /// Redundancy version @@ -628,8 +628,8 @@ typedef struct DCI1_5MHz_FDD DCI1_5MHz_FDD_t; /// DCI Format Type 1 (10 MHz, FDD, 31 bits) struct DCI1_10MHz_FDD { - /// dummy bits (not transmitted) - uint32_t dummy:1; + /// padding bits (not transmitted) + uint32_t padding:1; /// Power Control uint32_t TPC:2; /// Redundancy version @@ -651,8 +651,8 @@ typedef struct DCI1_10MHz_FDD DCI1_10MHz_FDD_t; /// DCI Format Type 1 (20 MHz, FDD, 39 bits) struct DCI1_20MHz_FDD { - /// dummy bits (not transmitted) - uint64_t dummy:25; + /// padding bits (not transmitted) + uint64_t padding:25; /// Power Control uint64_t TPC:2; /// Redundancy version @@ -674,10 +674,8 @@ typedef struct DCI1_20MHz_FDD DCI1_20MHz_FDD_t; /// DCI Format Type 1A (5 MHz, TDD, frame 1-6, 27 bits) struct DCI1A_RA_5MHz_TDD_1_6 { - /// Dummy bits to align to 32-bits - uint32_t dummy:5; - /// Padding - uint32_t padding:6; + /// padding bits to align to 32-bits + uint32_t padding:11; /// PRACH mask index uint32_t prach_mask_index:4; /// Preamble Index @@ -822,7 +820,7 @@ typedef struct DCI1B_5MHz_4A_TDD DCI1B_5MHz_4A_TDD_t; struct DCI1C_1_5MHz { /// padding to 32bits - uint32_t padding32:24; + uint32_t padding:24; uint32_t mcs:5; uint32_t rballoc:3; // N_RB_step = 2, Ngap=Ngap1=3, NDLVRBGap = 6, ceil(log2((3*4)/2)) = 3 } __attribute__ ((__packed__)); @@ -836,7 +834,7 @@ typedef struct DCI1C_1_5MHz DCI1C_1_5MHz_t; struct DCI1C_5MHz { /// padding to 32bits - uint32_t padding32:20; + uint32_t padding:20; uint32_t mcs:5; uint32_t rballoc:7; // N_RB_step = 2, Ngap1=Ngap2=12, NDLVRBGap = 24, ceil(log2((12*13)/2)) = 7 } __attribute__ ((__packed__)); @@ -848,7 +846,7 @@ typedef struct DCI1C_5MHz DCI1C_5MHz_t; struct DCI1C_10MHz { /// padding to 32bits - uint32_t padding32:19; + uint32_t padding:19; uint32_t mcs:5; uint32_t rballoc:7; // N_RB_step = 4, Ngap1=27, NDLVRBGap = 46, ceil(log2(((11*12)/2)) = 7 uint32_t Ngap:1; @@ -861,7 +859,7 @@ typedef struct DCI1C_10MHz DCI1C_10MHz_t; struct DCI1C_15MHz { /// padding to 32bits - uint32_t padding32:18; + uint32_t padding:18; uint32_t mcs:5; uint32_t rballoc:8; // N_RB_step = 4, Ngap1=64, ceil(log2((16*17)/2)) = 8 uint32_t Ngap:1; @@ -874,7 +872,7 @@ typedef struct DCI1C_15MHz DCI1C_15MHz_t; struct DCI1C_20MHz { /// padding to 32bits - uint32_t padding32:17; + uint32_t padding:17; uint32_t mcs:5; uint32_t rballoc:9; // N_RB_step = 4, Ngap1=48, ceil(log2((24*25)/2)) = 9 uint32_t Ngap:1; @@ -1006,7 +1004,7 @@ typedef struct DCI1D_5MHz_4A_TDD DCI1D_5MHz_4A_TDD_t; /// DCI Format Type 1E (5 MHz, TDD, 2 Antenna Ports, more than 10 PRBs, 34 bits) struct DCI1E_5MHz_2A_M10PRB_TDD { /// padding to 64bits - uint64_t padding64:30; + uint64_t padding:30; /// Redundancy version 2 ///uint64_t rv2:2; /// New Data Indicator 2 @@ -1045,7 +1043,7 @@ typedef struct DCI1E_5MHz_2A_M10PRB_TDD DCI1E_5MHz_2A_M10PRB_TDD_t; /// DCI Format Type 2 (1.5 MHz, TDD, 2 Antenna Ports, 34 bits) struct DCI2_1_5MHz_2A_TDD { /// padding to 64bits - uint64_t padding64:30; + uint64_t padding:30; /// TPMI information for precoding uint64_t tpmi:3; /// Redundancy version 2 @@ -1078,7 +1076,7 @@ typedef struct DCI2_1_5MHz_2A_TDD DCI2_1_5MHz_2A_TDD_t; /// DCI Format Type 2 (1.5 MHz, TDD, 4 Antenna Ports, 37 bits) struct DCI2_1_5MHz_4A_TDD { /// padding for 64-bit - uint64_t padding64:27; + uint64_t padding:27; /// TPMI information for precoding uint64_t tpmi:6; /// Redundancy version 2 @@ -1111,7 +1109,7 @@ typedef struct DCI2_1_5MHz_4A_TDD DCI2_1_5MHz_4A_TDD_t; /// DCI Format Type 2 (5 MHz, TDD, 2 Antenna Ports, 42 bits) struct DCI2_5MHz_2A_TDD { /// padding to 64bits - uint64_t padding64:22; + uint64_t padding:22; /// TPMI information for precoding uint64_t tpmi:3; /// Redundancy version 2 @@ -1146,7 +1144,7 @@ typedef struct DCI2_5MHz_2A_TDD DCI2_5MHz_2A_TDD_t; /// DCI Format Type 2 (5 MHz, TDD, 4 Antenna Ports, 45 bits) struct DCI2_5MHz_4A_TDD { /// padding for 64-bit - uint64_t padding64:19; + uint64_t padding:19; /// TPMI information for precoding uint64_t tpmi:6; /// Redundancy version 2 @@ -1181,7 +1179,7 @@ typedef struct DCI2_5MHz_4A_TDD DCI2_5MHz_4A_TDD_t; /// DCI Format Type 2 (10 MHz, TDD, 2 Antenna Ports, 46 bits) struct DCI2_10MHz_2A_TDD { /// padding to 64bits - uint64_t padding64:18; + uint64_t padding:18; /// TPMI information for precoding uint64_t tpmi:3; /// Redundancy version 2 @@ -1216,7 +1214,7 @@ typedef struct DCI2_10MHz_2A_TDD DCI2_10MHz_2A_TDD_t; /// DCI Format Type 2 (10 MHz, TDD, 4 Antenna Ports, 49 bits) struct DCI2_10MHz_4A_TDD { /// padding for 64-bit - uint64_t padding64:15; + uint64_t padding:15; /// TPMI information for precoding uint64_t tpmi:6; /// Redundancy version 2 @@ -1251,7 +1249,7 @@ typedef struct DCI2_10MHz_4A_TDD DCI2_10MHz_4A_TDD_t; /// DCI Format Type 2 (20 MHz, TDD, 2 Antenna Ports, 54 bits) struct DCI2_20MHz_2A_TDD { /// padding to 64bits - uint64_t padding64:10; + uint64_t padding:10; /// TPMI information for precoding uint64_t tpmi:3; /// Redundancy version 2 @@ -1286,7 +1284,7 @@ typedef struct DCI2_20MHz_2A_TDD DCI2_20MHz_2A_TDD_t; /// DCI Format Type 2 (20 MHz, TDD, 4 Antenna Ports, 57 bits) struct DCI2_20MHz_4A_TDD { /// padding for 64-bit - uint64_t padding64:7; + uint64_t padding:7; /// TPMI information for precoding uint64_t tpmi:6; /// Redundancy version 2 @@ -1321,7 +1319,7 @@ typedef struct DCI2_20MHz_4A_TDD DCI2_20MHz_4A_TDD_t; /// DCI Format Type 2 (1.5 MHz, FDD, 2 Antenna Ports, 31 bits) struct DCI2_1_5MHz_2A_FDD { //padding for 32 bits - uint32_t padding32:1; + uint32_t padding:1; /// precoding bits uint32_t tpmi:3; /// Redundancy version 2 @@ -1352,7 +1350,7 @@ typedef struct DCI2_1_5MHz_2A_FDD DCI2_1_5MHz_2A_FDD_t; /// DCI Format Type 2 (1.5 MHz, FDD, 4 Antenna Ports, 34 bits) struct DCI2_1_5MHz_4A_FDD { /// padding for 32 bits - uint64_t padding64:30; + uint64_t padding:30; /// precoding bits uint64_t tpmi:6; /// Redundancy version 2 @@ -1383,7 +1381,7 @@ typedef struct DCI2_1_5MHz_4A_FDD DCI2_1_5MHz_4A_FDD_t; /// DCI Format Type 2 (5 MHz, FDD, 2 Antenna Ports, 39 bits) struct DCI2_5MHz_2A_FDD { /// padding for 64-bit - uint64_t padding64:25; + uint64_t padding:25; /// TPMI information for precoding uint64_t tpmi:3; /// Redundancy version 2 @@ -1416,7 +1414,7 @@ typedef struct DCI2_5MHz_2A_FDD DCI2_5MHz_2A_FDD_t; /// DCI Format Type 2 (5 MHz, TDD, 4 Antenna Ports, 42 bits) struct DCI2_5MHz_4A_FDD { /// padding for 64-bit - uint64_t padding64:21; + uint64_t padding:21; /// TPMI information for precoding uint64_t tpmi:6; /// Redundancy version 2 @@ -1448,7 +1446,7 @@ typedef struct DCI2_5MHz_4A_FDD DCI2_5MHz_4A_FDD_t; /// DCI Format Type 2 (10 MHz, FDD, 2 Antenna Ports, 43 bits) struct DCI2_10MHz_2A_FDD { /// padding for 64-bit - uint64_t padding64:21; + uint64_t padding:21; /// TPMI information for precoding uint64_t tpmi:3; /// Redundancy version 2 @@ -1481,7 +1479,7 @@ typedef struct DCI2_10MHz_2A_FDD DCI2_10MHz_2A_FDD_t; /// DCI Format Type 2 (5 MHz, TDD, 4 Antenna Ports, 46 bits) struct DCI2_10MHz_4A_FDD { /// padding for 64-bit - uint64_t padding64:18; + uint64_t padding:18; /// TPMI information for precoding uint64_t tpmi:6; /// Redundancy version 2 @@ -1513,7 +1511,7 @@ typedef struct DCI2_10MHz_4A_FDD DCI2_10MHz_4A_FDD_t; /// DCI Format Type 2 (20 MHz, FDD, 2 Antenna Ports, 51 bits) struct DCI2_20MHz_2A_FDD { /// padding for 64-bit - uint64_t padding64:13; + uint64_t padding:13; /// TPMI information for precoding uint64_t tpmi:3; /// Redundancy version 2 @@ -1546,7 +1544,7 @@ typedef struct DCI2_20MHz_2A_FDD DCI2_20MHz_2A_FDD_t; /// DCI Format Type 2 (20 MHz, FDD, 4 Antenna Ports, 54 bits) struct DCI2_20MHz_4A_FDD { /// padding for 64-bit - uint64_t padding64:10; + uint64_t padding:10; /// TPMI information for precoding uint64_t tpmi:6; /// Redundancy version 2 @@ -2083,7 +2081,7 @@ typedef struct DCI2A_20MHz_4A_FDD DCI2A_20MHz_4A_FDD_t; // ******************************************************************* /// DCI Format Type 2B (1.5 MHz, TDD, 33 bits) struct DCI2B_1_5MHz_TDD { - uint64_t padding64:31; + uint64_t padding:31; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 @@ -2109,7 +2107,7 @@ struct DCI2B_1_5MHz_TDD { /// RB Assignment (ceil(log2(N_RB_DL/P)) bits) uint64_t rballoc:6; /// Padding for ambiguity - uint64_t padding:1; + uint64_t padding0:1; } __attribute__ ((__packed__)); typedef struct DCI2B_1_5MHz_TDD DCI2B_1_5MHz_TDD_t; @@ -2118,7 +2116,7 @@ typedef struct DCI2B_1_5MHz_TDD DCI2B_1_5MHz_TDD_t; /// DCI Format Type 2B (5 MHz, TDD, 39 bits) struct DCI2B_5MHz_TDD { /// padding to 64bits - uint64_t padding64:25; + uint64_t padding:25; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 @@ -2153,7 +2151,7 @@ typedef struct DCI2B_5MHz_TDD DCI2B_5MHz_TDD_t; /// DCI Format Type 2B (10 MHz, TDD, 43 bits) struct DCI2B_10MHz_TDD { /// padding to 64bits - uint64_t padding64:21; + uint64_t padding:21; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 @@ -2188,7 +2186,7 @@ typedef struct DCI2B_10MHz_TDD DCI2B_10MHz_TDD_t; /// DCI Format Type 2B (20 MHz, TDD, 51 bits) struct DCI2B_20MHz_TDD { /// padding to 64bits - uint64_t padding64:13; + uint64_t padding:13; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 @@ -2223,7 +2221,7 @@ typedef struct DCI2B_20MHz_TDD DCI2B_20MHz_TDD_t; /// DCI Format Type 2B (1.5 MHz, FDD, 28 bits) struct DCI2B_1_5MHz_FDD { //padding for 32 bits - uint32_t padding32:4; + uint32_t padding:4; /// Redundancy version 2 uint32_t rv2:2; /// New Data Indicator 2 @@ -2252,7 +2250,7 @@ typedef struct DCI2B_1_5MHz_FDD DCI2B_1_5MHz_FDD_t; /// DCI Format Type 2B (5 MHz, FDD, 36 bits) struct DCI2B_5MHz_FDD { /// padding for 64-bit - uint64_t padding64:28; + uint64_t padding:28; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 @@ -2283,7 +2281,7 @@ typedef struct DCI2B_5MHz_FDD DCI2B_5MHz_FDD_t; /// DCI Format Type 2B (10 MHz, FDD, 41 bits) struct DCI2B_10MHz_FDD { /// padding for 64-bit - uint64_t padding64:23; + uint64_t padding:23; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 @@ -2307,7 +2305,7 @@ struct DCI2B_10MHz_FDD { /// Resource Allocation Header uint64_t rah:1; /// Padding for ambiguity - uint64_t padding:1; + uint64_t padding0:1; } __attribute__ ((__packed__)); #define sizeof_DCI2B_10MHz_FDD_t 41 @@ -2316,7 +2314,7 @@ typedef struct DCI2B_10MHz_FDD DCI2B_10MHz_FDD_t; /// DCI Format Type 2B (20 MHz, FDD, 48 bits) struct DCI2B_20MHz_FDD { /// padding for 64-bit - uint64_t padding64:16; + uint64_t padding:16; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 @@ -2350,7 +2348,7 @@ typedef struct DCI2B_20MHz_FDD DCI2B_20MHz_FDD_t; /// DCI Format Type 2C (1.5 MHz, TDD, 34 bits) struct DCI2C_1_5MHz_TDD { - uint64_t padding64:30; + uint64_t padding:30; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 @@ -2383,7 +2381,7 @@ typedef struct DCI2C_1_5MHz_TDD DCI2C_1_5MHz_TDD_t; /// DCI Format Type 2C (5 MHz, TDD, 41 bits) struct DCI2C_5MHz_TDD { /// padding to 64bits - uint64_t padding64:23; + uint64_t padding:23; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 @@ -2418,7 +2416,7 @@ typedef struct DCI2C_5MHz_TDD DCI2C_5MHz_TDD_t; /// DCI Format Type 2C (10 MHz, TDD, 45 bits) struct DCI2C_10MHz_TDD { /// padding to 64bits - uint64_t padding64:19; + uint64_t padding:19; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 @@ -2453,7 +2451,7 @@ typedef struct DCI2C_10MHz_TDD DCI2C_10MHz_TDD_t; /// DCI Format Type 2C (20 MHz, TDD, 53 bits) struct DCI2C_20MHz_TDD { /// padding to 64bits - uint64_t padding64:11; + uint64_t padding:11; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 @@ -2488,7 +2486,7 @@ typedef struct DCI2C_20MHz_TDD DCI2C_20MHz_TDD_t; /// DCI Format Type 2C (1.5 MHz, FDD, 30 bits) struct DCI2C_1_5MHz_FDD { //padding for 32 bits - uint32_t padding32:2; + uint32_t padding:2; /// Redundancy version 2 uint32_t rv2:2; /// New Data Indicator 2 @@ -2517,7 +2515,7 @@ typedef struct DCI2C_1_5MHz_FDD DCI2C_1_5MHz_FDD_t; /// DCI Format Type 2C (5 MHz, FDD, 38 bits) struct DCI2C_5MHz_FDD { /// padding for 64-bit - uint64_t padding64:26; + uint64_t padding:26; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 @@ -2548,7 +2546,7 @@ typedef struct DCI2C_5MHz_FDD DCI2C_5MHz_FDD_t; /// DCI Format Type 2C (10 MHz, FDD, 42 bits) struct DCI2C_10MHz_FDD { /// padding for 64-bit - uint64_t padding64:22; + uint64_t padding:22; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 @@ -2579,7 +2577,7 @@ typedef struct DCI2C_10MHz_FDD DCI2C_10MHz_FDD_t; /// DCI Format Type 2C (20 MHz, FDD, 50 bits) struct DCI2C_20MHz_FDD { /// padding for 64-bit - uint64_t padding64:14; + uint64_t padding:14; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 @@ -2613,7 +2611,7 @@ typedef struct DCI2C_20MHz_FDD DCI2C_20MHz_FDD_t; /// DCI Format Type 2D (1.5 MHz, TDD, 36 bits) struct DCI2D_1_5MHz_TDD { - uint64_t padding64:28; + uint64_t padding:28; /// PDSCH REsource Mapping and Quasi-Co-Location Indicator uint64_t REMQCL:2; /// Redundancy version 2 @@ -2648,7 +2646,7 @@ typedef struct DCI2D_1_5MHz_TDD DCI2D_1_5MHz_TDD_t; /// DCI Format Type 2D (5 MHz, TDD, 43 bits) struct DCI2D_5MHz_TDD { /// padding to 64bits - uint64_t padding64:21; + uint64_t padding:21; /// PDSCH REsource Mapping and Quasi-Co-Location Indicator uint64_t REMQCL:2; /// Redundancy version 2 @@ -2685,7 +2683,7 @@ typedef struct DCI2D_5MHz_TDD DCI2D_5MHz_TDD_t; /// DCI Format Type 2D (10 MHz, TDD, 47 bits) struct DCI2D_10MHz_TDD { /// padding to 64bits - uint64_t padding64:17; + uint64_t padding:17; /// PDSCH REsource Mapping and Quasi-Co-Location Indicator uint64_t REMQCL:2; /// Redundancy version 2 @@ -2722,7 +2720,7 @@ typedef struct DCI2D_10MHz_TDD DCI2D_10MHz_TDD_t; /// DCI Format Type 2D (20 MHz, TDD, 55 bits) struct DCI2D_20MHz_TDD { /// padding to 64bits - uint64_t padding64:9; + uint64_t padding:9; /// PDSCH REsource Mapping and Quasi-Co-Location Indicator uint64_t REMQCL:2; /// Redundancy version 2 @@ -2759,7 +2757,7 @@ typedef struct DCI2D_20MHz_TDD DCI2D_20MHz_TDD_t; /// DCI Format Type 2D (1.5 MHz, FDD, 33 bits) struct DCI2D_1_5MHz_FDD { //padding for 33 bits - uint64_t padding64:31; + uint64_t padding:31; /// PDSCH REsource Mapping and Quasi-Co-Location Indicator uint64_t REMQCL:2; /// Redundancy version 2 @@ -2783,7 +2781,7 @@ struct DCI2D_1_5MHz_FDD { /// RB Assignment (ceil(log2(N_RB_DL/P)) bits) uint64_t rballoc:6; /// padding for ambiguity - uint64_t padding; + uint64_t padding0; } __attribute__ ((__packed__)); typedef struct DCI2D_1_5MHz_FDD DCI2D_1_5MHz_FDD_t; @@ -2792,7 +2790,7 @@ typedef struct DCI2D_1_5MHz_FDD DCI2D_1_5MHz_FDD_t; /// DCI Format Type 2D (5 MHz, FDD, 41 bits) struct DCI2D_5MHz_FDD { /// padding for 64-bit - uint64_t padding64:23; + uint64_t padding:23; /// PDSCH REsource Mapping and Quasi-Co-Location Indicator uint64_t REMQCL:2; /// Redundancy version 2 @@ -2818,7 +2816,7 @@ struct DCI2D_5MHz_FDD { /// Resource Allocation Header uint64_t rah:1; /// padding for ambiguity - uint64_t padding:1; + uint64_t padding0:1; } __attribute__ ((__packed__)); #define sizeof_DCI2D_5MHz_FDD_t 41 @@ -2827,7 +2825,7 @@ typedef struct DCI2D_5MHz_FDD DCI2D_5MHz_FDD_t; /// DCI Format Type 2D (10 MHz, FDD, 45 bits) struct DCI2D_10MHz_FDD { /// padding for 64-bit - uint64_t padding64:19; + uint64_t padding:19; /// PDSCH REsource Mapping and Quasi-Co-Location Indicator uint64_t REMQCL:2; /// Redundancy version 2 @@ -2853,7 +2851,7 @@ struct DCI2D_10MHz_FDD { /// Resource Allocation Header uint64_t rah:1; /// padding for ambiguity - uint64_t padding:1; + uint64_t padding0:1; } __attribute__ ((__packed__)); #define sizeof_DCI2D_10MHz_FDD_t 45 @@ -2862,7 +2860,7 @@ typedef struct DCI2D_10MHz_FDD DCI2D_10MHz_FDD_t; /// DCI Format Type 2D (20 MHz, FDD, 52 bits) struct DCI2D_20MHz_FDD { /// padding for 64-bit - uint64_t padding64:12; + uint64_t padding:12; /// Redundancy version 2 uint64_t rv2:2; /// New Data Indicator 2 diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 97a9709df5..b64a8d6c23 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -890,6 +890,7 @@ void fill_pdcch_order(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_a ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->harq_pid = rel8->harq_process; ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->padding = 0; } else { dci_alloc->dci_length = sizeof_DCI1A_1_5MHz_FDD_t; ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->type = 1; @@ -900,6 +901,7 @@ void fill_pdcch_order(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_a ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->padding = 0; // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } break; @@ -914,7 +916,8 @@ void fill_pdcch_order(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_a ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->padding = 0; // printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI1A_5MHz_FDD_t; @@ -926,6 +929,7 @@ void fill_pdcch_order(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_a ((DCI1A_5MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1A_5MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_5MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1A_5MHz_FDD_t *)dci_pdu)->padding = 0; // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } break; @@ -941,6 +945,7 @@ void fill_pdcch_order(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_a ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->harq_pid = rel8->harq_process; ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->padding = 0; // printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI1A_10MHz_FDD_t; @@ -952,6 +957,7 @@ void fill_pdcch_order(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_a ((DCI1A_10MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1A_10MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_10MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1A_10MHz_FDD_t *)dci_pdu)->padding = 0; // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } break; @@ -967,6 +973,7 @@ void fill_pdcch_order(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_a ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->harq_pid = rel8->harq_process; ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->padding = 0; // printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI1A_20MHz_FDD_t; @@ -978,6 +985,7 @@ void fill_pdcch_order(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_a ((DCI1A_20MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1A_20MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_20MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1A_20MHz_FDD_t *)dci_pdu)->padding = 0; // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } break; @@ -1084,6 +1092,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->harq_pid = rel8->harq_process; ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->padding = 0; } else { dci_alloc->dci_length = sizeof_DCI1A_1_5MHz_FDD_t; @@ -1095,6 +1104,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->padding = 0; // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } AssertFatal(rel8->virtual_resource_block_assignment_flag==LOCALIZED,"Distributed RB allocation not done yet\n"); @@ -1113,7 +1123,8 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->padding = 0; // printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI1A_5MHz_FDD_t; @@ -1125,6 +1136,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1A_5MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1A_5MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_5MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1A_5MHz_FDD_t *)dci_pdu)->padding = 0; // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } AssertFatal(rel8->virtual_resource_block_assignment_flag==LOCALIZED,"Distributed RB allocation not done yet\n"); @@ -1143,7 +1155,8 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->padding = 0; // printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI1A_10MHz_FDD_t; @@ -1155,6 +1168,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1A_10MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1A_10MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_10MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1A_10MHz_FDD_t *)dci_pdu)->padding = 0; // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } AssertFatal(rel8->virtual_resource_block_assignment_flag==LOCALIZED,"Distributed RB allocation not done yet\n"); @@ -1174,7 +1188,8 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->padding = 0; // printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI1A_20MHz_FDD_t; @@ -1186,6 +1201,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1A_20MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1A_20MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1A_20MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1A_20MHz_FDD_t *)dci_pdu)->padding = 0; // printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } AssertFatal(rel8->virtual_resource_block_assignment_flag==LOCALIZED,"Distributed RB allocation not done yet\n"); @@ -1249,7 +1265,8 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1_1_5MHz_TDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1_1_5MHz_TDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1_1_5MHz_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI1_1_5MHz_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1_1_5MHz_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1_1_5MHz_TDD_t *)dci_pdu)->padding = 0; // printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI1_1_5MHz_FDD_t; @@ -1260,6 +1277,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1_1_5MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1_1_5MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1_1_5MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1_1_5MHz_FDD_t *)dci_pdu)->padding = 0; // printf("FDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } break; @@ -1273,7 +1291,8 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1_5MHz_TDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1_5MHz_TDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1_5MHz_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI1_5MHz_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1_5MHz_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1_5MHz_TDD_t *)dci_pdu)->padding = 0; // printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI1_5MHz_FDD_t; @@ -1284,6 +1303,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1_5MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1_5MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1_5MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1_5MHz_FDD_t *)dci_pdu)->padding = 0; // printf("FDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } break; @@ -1297,7 +1317,8 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1_10MHz_TDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1_10MHz_TDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1_10MHz_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI1_10MHz_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1_10MHz_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1_10MHz_TDD_t *)dci_pdu)->padding = 0; // printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI1_10MHz_FDD_t; @@ -1308,6 +1329,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1_10MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1_10MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1_10MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1_10MHz_FDD_t *)dci_pdu)->padding = 0; } break; case 100: @@ -1320,7 +1342,8 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1_20MHz_TDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1_20MHz_TDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1_20MHz_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI1_20MHz_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1_20MHz_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI1_20MHz_TDD_t *)dci_pdu)->padding = 0; // printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI1_20MHz_FDD_t; @@ -1331,6 +1354,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI1_20MHz_FDD_t *)dci_pdu)->rv = rel8->redundancy_version_1; ((DCI1_20MHz_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI1_20MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; + ((DCI1_20MHz_FDD_t *)dci_pdu)->padding = 0; } break; } @@ -1415,6 +1439,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process; ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + /* there is no padding in this structure, it is exactly 32 bits */ // printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI2A_1_5MHz_2A_FDD_t; @@ -1429,6 +1454,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; + ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->padding = 0; // printf("FDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } break; @@ -1445,8 +1471,9 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->rv2 = rel8->redundancy_version_2; ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; - ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; + ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->padding = 0; // printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI2A_5MHz_2A_FDD_t; @@ -1461,6 +1488,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; + ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->padding = 0; // printf("FDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } break; @@ -1477,8 +1505,9 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->rv2 = rel8->redundancy_version_2; ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; - ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; + ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->padding = 0; // printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI2A_10MHz_2A_FDD_t; @@ -1492,7 +1521,8 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->rv2 = rel8->redundancy_version_2; ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; + ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; + ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->padding = 0; } break; case 100: @@ -1508,8 +1538,9 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->rv2 = rel8->redundancy_version_2; ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; - ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; + ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->padding = 0; // printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI2A_20MHz_2A_FDD_t; @@ -1523,7 +1554,8 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->rv2 = rel8->redundancy_version_2; ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; + ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; + ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->padding = 0; } break; @@ -1726,6 +1758,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->tpmi = rel8->precoding_information; + ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->padding = 0; // printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI2_1_5MHz_2A_FDD_t; @@ -1740,6 +1773,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->tpmi = rel8->precoding_information; + ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->padding = 0; // printf("FDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } break; @@ -1759,6 +1793,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->tpmi = rel8->precoding_information; + ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->padding = 0; // printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI2_5MHz_2A_FDD_t; @@ -1773,7 +1808,8 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; - ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->tpmi = rel8->precoding_information; + ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->tpmi = rel8->precoding_information; + ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->padding = 0; // printf("FDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } break; @@ -1793,6 +1829,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->tpmi = rel8->precoding_information; + ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->padding = 0; // printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { dci_alloc->dci_length = sizeof_DCI2_10MHz_2A_FDD_t; @@ -1806,13 +1843,14 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->rv2 = rel8->redundancy_version_2; ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; + ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->tpmi = rel8->precoding_information; + ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->padding = 0; } break; case 100: if (fp->frame_type == TDD) { - dci_alloc->dci_length = sizeof_DCI2_20MHz_2A_TDD_t; + dci_alloc->dci_length = sizeof_DCI2_20MHz_2A_TDD_t; ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->rah = rel8->resource_allocation_type; ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->mcs1 = rel8->mcs_1; ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->mcs2 = rel8->mcs_2; @@ -1823,12 +1861,13 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->rv2 = rel8->redundancy_version_2; ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; - ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; + ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; + ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->dai = rel8->downlink_assignment_index; ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->tpmi = rel8->precoding_information; + ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->padding = 0; // printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB); } else { - dci_alloc->dci_length = sizeof_DCI2_20MHz_2A_FDD_t; + dci_alloc->dci_length = sizeof_DCI2_20MHz_2A_FDD_t; ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->rah = rel8->resource_allocation_type; ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->mcs1 = rel8->mcs_1; ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->mcs2 = rel8->mcs_2; @@ -1839,8 +1878,9 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->rv2 = rel8->redundancy_version_2; ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->TPC = rel8->tpc; ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process; - ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; + ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->tb_swap = rel8->transport_block_to_codeword_swap_flag; ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->tpmi = rel8->precoding_information; + ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->padding = 0; } break; @@ -2201,6 +2241,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *d ((DCI6_1A_5MHz_t *)dci_pdu)->srs_req = rel13->srs_request; ((DCI6_1A_5MHz_t *)dci_pdu)->harq_ack_off = rel13->harq_resource_offset; ((DCI6_1A_5MHz_t *)dci_pdu)->dci_rep = rel13->dci_subframe_repetition_number-1; + ((DCI6_1A_5MHz_t *)dci_pdu)->padding = 0; break; case 50: @@ -2217,6 +2258,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *d ((DCI6_1A_10MHz_t *)dci_pdu)->srs_req = rel13->srs_request; ((DCI6_1A_10MHz_t *)dci_pdu)->harq_ack_off = rel13->harq_resource_offset; ((DCI6_1A_10MHz_t *)dci_pdu)->dci_rep = rel13->dci_subframe_repetition_number-1; + ((DCI6_1A_10MHz_t *)dci_pdu)->padding = 0; break; case 100: dci_alloc->dci_length = sizeof_DCI6_1A_20MHz_t; @@ -2232,6 +2274,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *d ((DCI6_1A_20MHz_t *)dci_pdu)->srs_req = rel13->srs_request; ((DCI6_1A_20MHz_t *)dci_pdu)->harq_ack_off = rel13->harq_resource_offset; ((DCI6_1A_20MHz_t *)dci_pdu)->dci_rep = rel13->dci_subframe_repetition_number-1; + ((DCI6_1A_20MHz_t *)dci_pdu)->padding = 0; break; } break; @@ -2250,6 +2293,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *d ((DCI6_1B_5MHz_t *)dci_pdu)->ndi = rel13->new_data_indicator; ((DCI6_1B_5MHz_t *)dci_pdu)->harq_ack_off = rel13->harq_resource_offset; ((DCI6_1B_5MHz_t *)dci_pdu)->dci_rep = rel13->dci_subframe_repetition_number-1; + ((DCI6_1B_5MHz_t *)dci_pdu)->padding = 0; break; case 50: @@ -2262,6 +2306,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *d ((DCI6_1B_10MHz_t *)dci_pdu)->ndi = rel13->new_data_indicator; ((DCI6_1B_10MHz_t *)dci_pdu)->harq_ack_off = rel13->harq_resource_offset; ((DCI6_1B_10MHz_t *)dci_pdu)->dci_rep = rel13->dci_subframe_repetition_number-1; + ((DCI6_1B_10MHz_t *)dci_pdu)->padding = 0; break; case 100: dci_alloc->dci_length = sizeof_DCI6_1B_20MHz_t; @@ -2273,6 +2318,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *d ((DCI6_1B_20MHz_t *)dci_pdu)->ndi = rel13->new_data_indicator; ((DCI6_1B_20MHz_t *)dci_pdu)->harq_ack_off = rel13->harq_resource_offset; ((DCI6_1B_20MHz_t *)dci_pdu)->dci_rep = rel13->dci_subframe_repetition_number-1; + ((DCI6_1B_20MHz_t *)dci_pdu)->padding = 0; break; } case 12: // Format 6-2 @@ -2284,6 +2330,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *d if (rel13->paging_direct_indication_differentiation_flag==0) { ((DCI6_2_di_5MHz_t *)dci_pdu)->type = 0; ((DCI6_2_di_5MHz_t *)dci_pdu)->di_info = rel13->direct_indication; + ((DCI6_2_di_5MHz_t *)dci_pdu)->padding = 0; } else { ((DCI6_2_paging_5MHz_t *)dci_pdu)->type = 1; @@ -2291,6 +2338,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *d ((DCI6_2_paging_5MHz_t *)dci_pdu)->mcs = rel13->mcs; ((DCI6_2_paging_5MHz_t *)dci_pdu)->rep = (rel13->pdsch_reptition_levels-1); ((DCI6_2_paging_5MHz_t *)dci_pdu)->dci_rep = rel13->dci_subframe_repetition_number-1; + ((DCI6_2_paging_5MHz_t *)dci_pdu)->padding = 0; } break; @@ -2299,6 +2347,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *d if (rel13->paging_direct_indication_differentiation_flag==0) { ((DCI6_2_di_10MHz_t *)dci_pdu)->type = 0; ((DCI6_2_di_10MHz_t *)dci_pdu)->di_info = rel13->direct_indication; + ((DCI6_2_di_10MHz_t *)dci_pdu)->padding = 0; } else { ((DCI6_2_paging_10MHz_t *)dci_pdu)->type = 1; @@ -2306,6 +2355,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *d ((DCI6_2_paging_10MHz_t *)dci_pdu)->mcs = rel13->mcs; ((DCI6_2_paging_10MHz_t *)dci_pdu)->rep = (rel13->pdsch_reptition_levels-1); ((DCI6_2_paging_10MHz_t *)dci_pdu)->dci_rep = rel13->dci_subframe_repetition_number-1; + ((DCI6_2_paging_10MHz_t *)dci_pdu)->padding = 0; } break; @@ -2314,6 +2364,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *d if (rel13->paging_direct_indication_differentiation_flag==0) { ((DCI6_2_di_20MHz_t *)dci_pdu)->type = 0; ((DCI6_2_di_20MHz_t *)dci_pdu)->di_info = rel13->direct_indication; + ((DCI6_2_di_20MHz_t *)dci_pdu)->padding = 0; } else { ((DCI6_2_paging_20MHz_t *)dci_pdu)->type = 1; @@ -2321,6 +2372,7 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *d ((DCI6_2_paging_20MHz_t *)dci_pdu)->mcs = rel13->mcs; ((DCI6_2_paging_20MHz_t *)dci_pdu)->rep = (rel13->pdsch_reptition_levels-1); ((DCI6_2_paging_20MHz_t *)dci_pdu)->dci_rep = rel13->dci_subframe_repetition_number-1; + ((DCI6_2_paging_20MHz_t *)dci_pdu)->padding = 0; } break; From ec56a416b72f634de22686b81f82be48dd955ce1 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 4 Jan 2018 16:35:09 +0100 Subject: [PATCH 128/284] Add support for Ubuntu 17.04 and 17.10. Basically, build_helper has been adapted so that: ./buil_oai -I -w USRP works for Ubuntu 17.04 and 17.10. Concerning those systems: - compilation with "--eNB --UE -w USRP" works - the enb softmodem runs on 17.04 (not tested on 17.10) - nothing else has been tested. Users should report any problem. --- cmake_targets/tools/build_helper | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 8cf0d22e91..9686b650d1 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -95,6 +95,8 @@ get_distribution_release() { check_supported_distribution() { local distribution=$(get_distribution_release) case "$distribution" in + "ubuntu17.10") return 0 ;; + "ubuntu17.04") return 0 ;; "ubuntu16.04") return 0 ;; "ubuntu14.04") return 0 ;; "fedora24") return 0 ;; @@ -479,16 +481,26 @@ check_install_oai_software() { fi $SUDO $INSTALLER update -y if [[ "$OS_DISTRO" == "ubuntu" ]]; then + local LAPACK_LIBNAME="liblapack.so" + local LAPACK_TARGET="/usr/lib/atlas-base/atlas/liblapack.so" $SUDO apt install -y software-properties-common case "$(get_distribution_release)" in "ubuntu14.04") - specific_packages="libtasn1-3-dev" + specific_packages="libtasn1-3-dev gccxml libgnutls-dev libatlas-dev" # For iperf3 $SUDO add-apt-repository "deb http://archive.ubuntu.com/ubuntu trusty-backports universe" $SUDO apt-get update ;; "ubuntu16.04") - specific_packages="libtasn1-6-dev" + specific_packages="libtasn1-6-dev gccxml libgnutls-dev libatlas-dev" + ;; + "ubuntu17.04") + specific_packages="libtasn1-6-dev castxml libgnutls28-dev libatlas-dev" + ;; + "ubuntu17.10") + specific_packages="libtasn1-6-dev castxml libgnutls28-dev" + LAPACK_LIBNAME="liblapack.so-x86_64-linux-gnu" + LAPACK_TARGET="/usr/lib/x86_64-linux-gnu/atlas/liblapack.so" ;; esac $SUDO apt-get install -y \ @@ -504,7 +516,6 @@ check_install_oai_software() { texlive-latex-base \ ethtool \ flex \ - gccxml \ gdb \ git \ graphviz \ @@ -515,7 +526,6 @@ check_install_oai_software() { iptables \ iptables-dev \ libatlas-base-dev \ - libatlas-dev \ libblas-dev \ libconfig8-dev \ libffi-dev \ @@ -553,11 +563,9 @@ check_install_oai_software() { wget \ libxpm-dev - $SUDO update-alternatives --set liblapack.so /usr/lib/atlas-base/atlas/liblapack.so - - $SUDO apt-get install -y nettle-dev nettle-bin + $SUDO update-alternatives --set "$LAPACK_LIBNAME" "$LAPACK_TARGET" - $SUDO apt-get install -y libgnutls-dev + $SUDO apt-get install -y nettle-dev nettle-bin elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then if [[ "$OS_DISTRO" == "rhel" ]] || [[ "$OS_DISTRO" == "centos" ]]; then if rpm -q epel-release > /dev/null; then From 27c3074ff96f2632b332b719ccd7adce6c889917 Mon Sep 17 00:00:00 2001 From: Xu Bo Date: Mon, 8 Jan 2018 15:27:54 +0900 Subject: [PATCH 129/284] fix RRCConnectionReestablishment issue when multiple RRCConnectionReestablishment happen --- cmake_targets/CMakeLists.txt | 1 + openair1/PHY/LTE_TRANSPORT/dci_tools.c | 2 +- openair1/SCHED/phy_procedures_lte_eNb.c | 4 +- openair2/LAYER2/MAC/defs.h | 2 + openair2/LAYER2/MAC/eNB_scheduler.c | 39 ++++- .../LAYER2/MAC/eNB_scheduler_primitives.c | 1 + openair2/LAYER2/MAC/extern.h | 2 - openair2/RRC/LITE/MESSAGES/asn1_msg.c | 2 +- openair2/RRC/LITE/defs.h | 6 + openair2/RRC/LITE/rrc_common.c | 46 +++++- openair2/RRC/LITE/rrc_eNB.c | 143 ++++++++++++++++-- openair2/RRC/LITE/rrc_eNB_S1AP.c | 1 + openair2/RRC/LITE/rrc_eNB_UE_context.c | 14 ++ openair3/GTPV1-U/gtpv1u_eNB.c | 65 ++++++-- 14 files changed, 294 insertions(+), 34 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index b24db90edb..89d17cb279 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1936,6 +1936,7 @@ add_executable(oaisim_nos1 ${OPENAIR_BIN_DIR}/messages_xml.h ${OPENAIR_TARGETS}/RT/USER/lte-ue.c ${OPENAIR_TARGETS}/RT/USER/lte-ru.c + ${OPENAIR_TARGETS}/RT/USER/lte-enb.c ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c ${OPENAIR_TARGETS}/SIMU/USER/channel_sim.c ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 97a9709df5..ea6d850196 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -6492,7 +6492,7 @@ uint8_t pdcch_alloc2ul_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t n) else ul_subframe = ((n+4)%10); - if (subframe_select(frame_parms,ul_subframe) != SF_UL) return(255); + if ((subframe_select(frame_parms,ul_subframe) != SF_UL) && (frame_parms->frame_type == TDD)) return(255); LOG_D(PHY, "subframe %d: PUSCH subframe = %d\n", n, ul_subframe); return ul_subframe; diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index c99776e7e5..d2d38a88be 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -834,10 +834,10 @@ void uci_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) if (uci->type == SR) { if (SR_payload == 1) { fill_sr_indication(eNB,uci->rnti,frame,subframe,metric_SR); - return; + continue; } else { - return; + continue; } } case HARQ: diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index e4c931ea51..78a74f00d3 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -835,6 +835,8 @@ typedef struct { int32_t cqi_req_timer; int32_t ul_inactivity_timer; int32_t ul_failure_timer; + uint32_t ue_reestablishment_reject_timer; + uint32_t ue_reestablishment_reject_timer_thres; int32_t ul_scheduled; int32_t ra_pdcch_order_sent; int32_t ul_out_of_sync; diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index de4213f6eb..38a34d5eec 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -163,7 +163,7 @@ schedule_SRS(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) (nfapi_ul_config_srs_pdu)); ul_config_pdu->srs_pdu.srs_pdu_rel8.size = (uint8_t) - sizeof(nfapi_ul_config_srs_pdu);; + sizeof(nfapi_ul_config_srs_pdu); ul_config_pdu->srs_pdu.srs_pdu_rel8.rnti = UE_list->UE_template[CC_id][UE_id]. rnti; @@ -549,7 +549,7 @@ check_ul_failure(module_id_t module_idP, int CC_id, int UE_id, UE_list->UE_sched_ctrl[UE_id].ul_failure_timer++; // check threshold - if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 200) { + if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 20000) { // inform RRC of failure and clear timer LOG_I(MAC, "UE %d rnti %x: UL Failure after repeated PDCCH orders: Triggering RRC \n", @@ -707,6 +707,41 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, ul_inactivity_timer, RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer); check_ul_failure(module_idP, CC_id, i, frameP, subframeP); + + if (RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer > 0) { + RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer++; + if(RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer >= + RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer_thres) { + RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer = 0; + for (int ii=0; iiulsch[ii]; + if((ulsch != NULL) && (ulsch->rnti == rnti)){ + LOG_I(MAC, "clean_eNb_ulsch UE %x \n", rnti); + clean_eNb_ulsch(ulsch); + break; + } + } + + for(int j = 0; j < 10; j++){ + nfapi_ul_config_request_body_t *ul_req_tmp = NULL; + ul_req_tmp = &RC.mac[module_idP]->UL_req_tmp[CC_id][j].ul_config_request_body; + if(ul_req_tmp){ + int pdu_number = ul_req_tmp->number_of_pdus; + for(int pdu_index = pdu_number-1; pdu_index >= 0; pdu_index--){ + if(ul_req_tmp->ul_config_pdu_list[pdu_index].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti){ + LOG_I(MAC, "remove UE %x from ul_config_pdu_list %d/%d\n", rnti, pdu_index, pdu_number); + if(pdu_index < pdu_number -1){ + memcpy(&ul_req_tmp->ul_config_pdu_list[pdu_index], &ul_req_tmp->ul_config_pdu_list[pdu_index+1], (pdu_number-1-pdu_index) * sizeof(nfapi_ul_config_request_pdu_t)); + } + ul_req_tmp->number_of_pdus--; + } + } + } + } + rrc_mac_remove_ue(module_idP,rnti); + } + } } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 05d8e8dc2d..b1d66b0946 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -2075,6 +2075,7 @@ int add_new_ue(module_id_t mod_idP, int cc_idP, rnti_t rntiP, int harq_pidP sizeof(UE_sched_ctrl)); memset((void *) &UE_list->eNB_UE_stats[cc_idP][UE_id], 0, sizeof(eNB_UE_STATS)); + UE_list->UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer = 0; UE_list->UE_sched_ctrl[UE_id].ta_update = 31; diff --git a/openair2/LAYER2/MAC/extern.h b/openair2/LAYER2/MAC/extern.h index db0aac7768..d0c8706ad6 100644 --- a/openair2/LAYER2/MAC/extern.h +++ b/openair2/LAYER2/MAC/extern.h @@ -101,6 +101,4 @@ extern DCI2_5MHz_2A_TDD_t DLSCH_alloc_pdu1; extern DCI2_5MHz_2A_TDD_t DLSCH_alloc_pdu2; extern DCI1E_5MHz_2A_M10PRB_TDD_t DLSCH_alloc_pdu1E; -extern uint16_t reestablish_rnti_map[NUMBER_OF_UE_MAX][2]; - #endif //DEF_H diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index 163950950e..db5ce5db95 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -233,7 +233,7 @@ uint8_t do_MIB(rrc_eNB_carrier_data_t *carrier, uint32_t N_RB_DL, uint32_t phich AssertFatal(phich_Resource <= PHICH_Config__phich_Resource_two,"Illegal phich_Resource\n"); mib->message.phich_Config.phich_Resource = phich_Resource; - AssertFatal(phich_Resource <= PHICH_Config__phich_Duration_extended,"Illegal phich_Duration\n"); + AssertFatal(phich_duration <= PHICH_Config__phich_Duration_extended,"Illegal phich_Duration\n"); mib->message.phich_Config.phich_Duration = phich_duration; LOG_I(RRC,"[MIB] systemBandwidth %x, phich_duration %x, phich_resource %x,sfn %x\n", (uint32_t)mib->message.dl_Bandwidth, diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index fa9a2161fc..0a66184998 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -451,6 +451,12 @@ typedef struct eNB_RRC_UE_s { uint32_t ul_failure_timer; uint32_t ue_release_timer; uint32_t ue_release_timer_thres; + uint32_t ue_release_timer_s1; + uint32_t ue_release_timer_thres_s1; + uint32_t ue_release_timer_rrc; + uint32_t ue_release_timer_thres_rrc; + uint32_t ue_reestablishment_timer; + uint32_t ue_reestablishment_timer_thres; uint8_t e_rab_release_command_flag; } eNB_RRC_UE_t; diff --git a/openair2/RRC/LITE/rrc_common.c b/openair2/RRC/LITE/rrc_common.c index 718c8c63f3..f8cfbdc12a 100644 --- a/openair2/RRC/LITE/rrc_common.c +++ b/openair2/RRC/LITE/rrc_common.c @@ -333,26 +333,58 @@ rrc_rx_tx( RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(RC.rrc[ctxt_pP->module_id]->rrc_ue_head)) { if ((ctxt_pP->frame == 0) && (ctxt_pP->subframe==0)) { if (ue_context_p->ue_context.Initialue_identity_s_TMSI.presence == TRUE) { - LOG_I(RRC,"UE rnti %x:S-TMSI %x failure timer %d/20000\n", + LOG_I(RRC,"UE rnti %x:S-TMSI %x failure timer %d/8\n", ue_context_p->ue_context.rnti, ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, ue_context_p->ue_context.ul_failure_timer); } else { - LOG_I(RRC,"UE rnti %x failure timer %d/20000\n", + LOG_I(RRC,"UE rnti %x failure timer %d/8\n", ue_context_p->ue_context.rnti, ue_context_p->ue_context.ul_failure_timer); } } if (ue_context_p->ue_context.ul_failure_timer>0) { ue_context_p->ue_context.ul_failure_timer++; - if (ue_context_p->ue_context.ul_failure_timer >= 20000) { + if (ue_context_p->ue_context.ul_failure_timer >= 8) { // remove UE after 20 seconds after MAC has indicated UL failure LOG_I(RRC,"Removing UE %x instance\n",ue_context_p->ue_context.rnti); ue_to_be_removed = ue_context_p; break; } } + if (ue_context_p->ue_context.ue_release_timer_s1>0) { + ue_context_p->ue_context.ue_release_timer_s1++; + if (ue_context_p->ue_context.ue_release_timer_s1 >= + ue_context_p->ue_context.ue_release_timer_thres_s1) { + LOG_I(RRC,"Removing UE %x instance Because of UE_CONTEXT_RELEASE_COMMAND not received after %d ms from sending request\n", + ue_context_p->ue_context.rnti, ue_context_p->ue_context.ue_release_timer_thres_s1); + ue_to_be_removed = ue_context_p; + break; + } + } + + if (ue_context_p->ue_context.ue_release_timer_rrc>0) { + ue_context_p->ue_context.ue_release_timer_rrc++; + if (ue_context_p->ue_context.ue_release_timer_rrc >= + ue_context_p->ue_context.ue_release_timer_thres_rrc) { + LOG_I(RRC,"Removing UE %x instance After UE_CONTEXT_RELEASE_Complete\n", ue_context_p->ue_context.rnti); + ue_to_be_removed = ue_context_p; + break; + } + } + + if (ue_context_p->ue_context.ue_reestablishment_timer>0) { + ue_context_p->ue_context.ue_reestablishment_timer++; + if (ue_context_p->ue_context.ue_reestablishment_timer >= + ue_context_p->ue_context.ue_reestablishment_timer_thres) { + LOG_I(RRC,"UE %d reestablishment_timer max\n",ue_context_p->ue_context.rnti); + ue_context_p->ue_context.ul_failure_timer = 20000; + ue_to_be_removed = ue_context_p; + ue_context_p->ue_context.ue_reestablishment_timer = 0; + break; + } + } if (ue_context_p->ue_context.ue_release_timer>0) { ue_context_p->ue_context.ue_release_timer++; if (ue_context_p->ue_context.ue_release_timer >= @@ -364,8 +396,14 @@ rrc_rx_tx( } } if (ue_to_be_removed) { + if(ue_to_be_removed->ue_context.ul_failure_timer >= 8) { + ue_to_be_removed->ue_context.ue_release_timer_s1 = 1; + ue_to_be_removed->ue_context.ue_release_timer_thres_s1 = 100; + ue_to_be_removed->ue_context.ue_release_timer = 0; + ue_to_be_removed->ue_context.ue_reestablishment_timer = 0; + } rrc_eNB_free_UE(ctxt_pP->module_id,ue_to_be_removed); - if(ue_to_be_removed->ue_context.ul_failure_timer >= 20000){ + if(ue_to_be_removed->ue_context.ul_failure_timer >= 8){ ue_to_be_removed->ue_context.ul_failure_timer = 0; } } diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 5817319198..24571ad4f7 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -572,6 +572,7 @@ rrc_eNB_get_next_free_ue_context( ctxt_pP->rnti); if (ue_context_p == NULL) { +#if 0 RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(RC.rrc[ctxt_pP->module_id]->rrc_ue_head)) { if (ue_context_p->ue_context.random_ue_identity == ue_identityP) { LOG_D(RRC, @@ -582,6 +583,7 @@ rrc_eNB_get_next_free_ue_context( return NULL; } } +#endif ue_context_p = rrc_eNB_allocate_new_UE_context(RC.rrc[ctxt_pP->module_id]); if (ue_context_p == NULL) { @@ -801,7 +803,11 @@ rrc_eNB_free_UE(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_s* (void)ue_module_id; #endif rnti_t rnti = ue_context_pP->ue_context.rnti; - + int i, j , CC_id, pdu_number; + LTE_eNB_ULSCH_t *ulsch = NULL; + nfapi_ul_config_request_body_t *ul_req_tmp = NULL; + PHY_VARS_eNB *eNB_PHY = NULL; + eNB_MAC_INST *eNB_MAC = RC.mac[enb_mod_idP]; AssertFatal(enb_mod_idP < NB_eNB_INST, "eNB inst invalid (%d/%d) for UE %x!", enb_mod_idP, NB_eNB_INST, rnti); /* ue_context_p = rrc_eNB_get_ue_context( @@ -814,7 +820,8 @@ rrc_eNB_free_UE(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_s* LOG_W(RRC, "[eNB %d] Removing UE RNTI %x\n", enb_mod_idP, rnti); #if defined(ENABLE_USE_MME) - if( ue_context_pP->ue_context.ul_failure_timer >= 20000 ) { + if( ue_context_pP->ue_context.ul_failure_timer >= 8 ) { + LOG_I(RRC, "[eNB %d] S1AP_UE_CONTEXT_RELEASE_REQ RNTI %x\n", enb_mod_idP, rnti); rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ(enb_mod_idP, ue_context_pP, S1AP_CAUSE_RADIO_NETWORK, 21); // send cause 21: connection with ue lost /* From 3GPP 36300v10 p129 : 19.2.2.2.2 S1 UE Context Release Request (eNB triggered) * If the E-UTRAN internal reason is a radio link failure detected in the eNB, the eNB shall wait a sufficient time before @@ -833,7 +840,33 @@ rrc_eNB_free_UE(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_s* oai_emulation.info.eNB_ue_module_id_to_rnti[enb_mod_idP][ue_module_id] = NOT_A_RNTI; #endif #endif + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + eNB_PHY = RC.eNB[enb_mod_idP][CC_id]; + for (i=0; iulsch[i]; + if((ulsch != NULL) && (ulsch->rnti == rnti)){ + LOG_I(RRC, "clean_eNb_ulsch UE %x \n", rnti); + clean_eNb_ulsch(ulsch); + break; + } + } + for(j = 0; j < 10; j++){ + ul_req_tmp = &eNB_MAC->UL_req_tmp[CC_id][j].ul_config_request_body; + if(ul_req_tmp){ + pdu_number = ul_req_tmp->number_of_pdus; + for(int pdu_index = pdu_number-1; pdu_index >= 0; pdu_index--){ + if(ul_req_tmp->ul_config_pdu_list[pdu_index].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti){ + LOG_I(RRC, "remove UE %x from ul_config_pdu_list %d/%d\n", rnti, pdu_index, pdu_number); + if(pdu_index < pdu_number -1){ + memcpy(&ul_req_tmp->ul_config_pdu_list[pdu_index], &ul_req_tmp->ul_config_pdu_list[pdu_index+1], (pdu_number-1-pdu_index) * sizeof(nfapi_ul_config_request_pdu_t)); + } + ul_req_tmp->number_of_pdus--; + } + } + } + } + } rrc_mac_remove_ue(enb_mod_idP,rnti); rrc_rlc_remove_ue(&ctxt); pdcp_remove_UE(&ctxt); @@ -1158,9 +1191,13 @@ rrc_eNB_generate_RRCConnectionReestablishment( RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Tx_buffer.payload_size); // activate release timer, if RRCComplete not received after 10 frames, remove UE - ue_context_pP->ue_context.ue_release_timer = 1; + //ue_context_pP->ue_context.ue_release_timer = 1; // remove UE after 10 frames after RRCConnectionReestablishmentRelease is triggered - ue_context_pP->ue_context.ue_release_timer_thres = 100; + //ue_context_pP->ue_context.ue_release_timer_thres = 100; + // activate release timer, if RRCComplete not received after 100 frames, remove UE + ue_context_pP->ue_context.ue_reestablishment_timer = 1; + // remove UE after 100 frames after RRCConnectionReestablishmentRelease is triggered + ue_context_pP->ue_context.ue_reestablishment_timer_thres = 1000; } //----------------------------------------------------------------------------- @@ -1742,6 +1779,38 @@ rrc_eNB_process_RRCConnectionReestablishmentComplete( // delete UE data of prior RNTI. UE use current RNTI. protocol_ctxt_t ctxt_prior = *ctxt_pP; ctxt_prior.rnti = reestablish_rnti; + + LTE_eNB_ULSCH_t *ulsch = NULL; + nfapi_ul_config_request_body_t *ul_req_tmp = NULL; + PHY_VARS_eNB *eNB_PHY = NULL; + eNB_MAC_INST *eNB_MAC = RC.mac[ctxt_prior.module_id]; + for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + eNB_PHY = RC.eNB[ctxt_prior.module_id][CC_id]; + for (int i=0; iulsch[i]; + if((ulsch != NULL) && (ulsch->rnti == ctxt_prior.rnti)){ + LOG_I(RRC, "clean_eNb_ulsch UE %x \n", ctxt_prior.rnti); + clean_eNb_ulsch(ulsch); + break; + } + } + + for(int j = 0; j < 10; j++){ + ul_req_tmp = &eNB_MAC->UL_req_tmp[CC_id][j].ul_config_request_body; + if(ul_req_tmp){ + int pdu_number = ul_req_tmp->number_of_pdus; + for(int pdu_index = pdu_number-1; pdu_index >= 0; pdu_index--){ + if(ul_req_tmp->ul_config_pdu_list[pdu_index].ulsch_pdu.ulsch_pdu_rel8.rnti == ctxt_prior.rnti){ + LOG_I(RRC, "remove UE %x from ul_config_pdu_list %d/%d\n", ctxt_prior.rnti, pdu_index, pdu_number); + if(pdu_index < pdu_number -1){ + memcpy(&ul_req_tmp->ul_config_pdu_list[pdu_index], &ul_req_tmp->ul_config_pdu_list[pdu_index+1], (pdu_number-1-pdu_index) * sizeof(nfapi_ul_config_request_pdu_t)); + } + ul_req_tmp->number_of_pdus--; + } + } + } + } + } rrc_mac_remove_ue(ctxt_prior.module_id, ctxt_prior.rnti); rrc_rlc_remove_ue(&ctxt_prior); pdcp_remove_UE(&ctxt_prior); @@ -1759,6 +1828,9 @@ rrc_eNB_generate_RRCConnectionReestablishmentReject( #ifdef RRC_MSG_PRINT int cnt; #endif + int UE_id = find_UE_id(ctxt_pP->module_id, ctxt_pP->rnti); + RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer = 1; + RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer_thres = 20; T(T_ENB_RRC_CONNECTION_REESTABLISHMENT_REJECT, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); @@ -1812,9 +1884,16 @@ rrc_eNB_generate_RRCConnectionRelease( size = do_RRCConnectionRelease(ctxt_pP->module_id, buffer,rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id)); // set release timer - ue_context_pP->ue_context.ue_release_timer=1; + //ue_context_pP->ue_context.ue_release_timer=1; // remove UE after 10 frames after RRCConnectionRelease is triggered - ue_context_pP->ue_context.ue_release_timer_thres=100; + //ue_context_pP->ue_context.ue_release_timer_thres=100; + // set release timer + ue_context_pP->ue_context.ue_release_timer_rrc = 1; + // remove UE after 10 frames after RRCConnectionRelease is triggered + ue_context_pP->ue_context.ue_release_timer_thres_rrc = 100; + ue_context_pP->ue_context.ue_reestablishment_timer = 0; + ue_context_pP->ue_context.ue_release_timer = 0; + ue_context_pP->ue_context.ue_release_timer_s1 = 0; LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Logical Channel DL-DCCH, Generate RRCConnectionRelease (bytes %d)\n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), @@ -4656,6 +4735,7 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( uint8_t *kRRCenc = NULL; uint8_t *kRRCint = NULL; uint8_t *kUPenc = NULL; + ue_context_pP->ue_context.ue_reestablishment_timer = 0; DRB_ToAddModList_t* DRB_configList = ue_context_pP->ue_context.DRB_configList2[xid]; SRB_ToAddModList_t* SRB_configList = ue_context_pP->ue_context.SRB_configList2[xid]; @@ -5052,9 +5132,13 @@ rrc_eNB_generate_RRCConnectionSetup( RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Tx_buffer.payload_size); // activate release timer, if RRCSetupComplete not received after 10 frames, remove UE - ue_context_pP->ue_context.ue_release_timer=1; + //ue_context_pP->ue_context.ue_release_timer=1; // remove UE after 10 frames after RRCConnectionRelease is triggered - ue_context_pP->ue_context.ue_release_timer_thres=100; + //ue_context_pP->ue_context.ue_release_timer_thres=100; + // activate release timer, if RRCSetupComplete not received after 100 frames, remove UE + ue_context_pP->ue_context.ue_release_timer=1; + // remove UE after 10 frames after RRCConnectionRelease is triggered + ue_context_pP->ue_context.ue_release_timer_thres=1000; } @@ -5398,11 +5482,27 @@ rrc_eNB_decode_ccch( rrc_eNB_generate_RRCConnectionReestablishmentReject(ctxt_pP, ue_context_p, CC_id); break; } - + if(ue_context_p->ue_context.ue_reestablishment_timer > 0){ + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RRCConnectionReestablishment(Previous) don't complete, let's reject the UE\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + rrc_eNB_generate_RRCConnectionReestablishmentReject(ctxt_pP, ue_context_p, CC_id); + ue_context_p->ue_context.ue_reestablishment_timer_thres = 1000; + break; + } LOG_D(RRC, PROTOCOL_RRC_CTXT_UE_FMT" UE context: %p\n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), ue_context_p); + ue_context_p->ue_context.ul_failure_timer = 0; + ue_context_p->ue_context.ue_release_timer = 0; + ue_context_p->ue_context.ue_reestablishment_timer = 0; + ue_context_p->ue_context.ue_release_timer_s1 = 0; + ue_context_p->ue_context.ue_release_timer_rrc = 0; + + /* reset timers */ + ue_context_p->ue_context.ul_failure_timer = 0; + ue_context_p->ue_context.ue_release_timer = 0; // insert C-RNTI to map for (i = 0; i < NUMBER_OF_UE_MAX; i++) { @@ -5538,6 +5638,7 @@ rrc_eNB_decode_ccch( /* if there is already a registered UE (with another RNTI) with this random_value, * the current one must be removed from MAC/PHY (zombie UE) */ +#if 0 if ((ue_context_p = rrc_eNB_ue_context_random_exist(ctxt_pP, random_value))) { LOG_W(RRC, "new UE rnti %x (coming with random value) is already there as UE %x, removing %x from MAC/PHY\n", ctxt_pP->rnti, ue_context_p->ue_context.rnti, ctxt_pP->rnti); @@ -5547,6 +5648,13 @@ rrc_eNB_decode_ccch( } else { ue_context_p = rrc_eNB_get_next_free_ue_context(ctxt_pP, random_value); } +#endif + if ((ue_context_p = rrc_eNB_ue_context_random_exist(ctxt_pP, random_value))) { + LOG_W(RRC, "new UE rnti %x (coming with random value) is already there as UE %x, removing %x from MAC/PHY\n", + ctxt_pP->rnti, ue_context_p->ue_context.rnti, ue_context_p->ue_context.rnti); + ue_context_p->ue_context.ul_failure_timer = 20000; + } + ue_context_p = rrc_eNB_get_next_free_ue_context(ctxt_pP, random_value); } else if (InitialUE_Identity_PR_s_TMSI == rrcConnectionRequest->ue_Identity.present) { /* Save s-TMSI */ S_TMSI_t s_TMSI = rrcConnectionRequest->ue_Identity.choice.s_TMSI; @@ -5567,6 +5675,9 @@ rrc_eNB_decode_ccch( /* reset timers */ ue_context_p->ue_context.ul_failure_timer = 0; ue_context_p->ue_context.ue_release_timer = 0; + ue_context_p->ue_context.ue_reestablishment_timer = 0; + ue_context_p->ue_context.ue_release_timer_s1 = 0; + ue_context_p->ue_context.ue_release_timer_rrc = 0; } else { LOG_I(RRC," S-TMSI doesn't exist, setting Initialue_identity_s_TMSI.m_tmsi to %p => %x\n",ue_context_p,m_tmsi); // ue_context_p = rrc_eNB_get_next_free_ue_context(ctxt_pP, NOT_A_RANDOM_UE_IDENTITY); @@ -5961,6 +6072,13 @@ if (ue_context_p->ue_context.nb_of_modify_e_rabs > 0) { ue_context_p); } else { ue_context_p->ue_context.reestablishment_cause = ReestablishmentCause_spare1; + for (uint8_t e_rab = 0; e_rab < ue_context_p->ue_context.nb_of_e_rabs; e_rab++) { + if (ue_context_p->ue_context.e_rab[e_rab].status == E_RAB_STATUS_DONE) { + ue_context_p->ue_context.e_rab[e_rab].status = E_RAB_STATUS_ESTABLISHED; + } else { + ue_context_p->ue_context.e_rab[e_rab].status = E_RAB_STATUS_FAILED; + } + } } } } @@ -6044,7 +6162,8 @@ if (ue_context_p->ue_context.nb_of_modify_e_rabs > 0) { } #endif } - ue_context_p->ue_context.ue_release_timer = 0; + //ue_context_p->ue_context.ue_release_timer = 0; + ue_context_p->ue_context.ue_reestablishment_timer = 1; } break; @@ -6526,6 +6645,10 @@ rrc_enb_task( /* Nothing to do. Apparently everything is done in S1AP processing */ //LOG_I(RRC, "[eNB %d] Received message %s, not processed because procedure not synched\n", //instance, msg_name_p); + if (rrc_eNB_get_ue_context(RC.rrc[instance], GTPV1U_ENB_DELETE_TUNNEL_RESP(msg_p).rnti)) { + rrc_eNB_get_ue_context(RC.rrc[instance], GTPV1U_ENB_DELETE_TUNNEL_RESP(msg_p).rnti)->ue_context.ue_release_timer_rrc = + rrc_eNB_get_ue_context(RC.rrc[instance], GTPV1U_ENB_DELETE_TUNNEL_RESP(msg_p).rnti)->ue_context.ue_release_timer_thres_rrc; + } break; # endif diff --git a/openair2/RRC/LITE/rrc_eNB_S1AP.c b/openair2/RRC/LITE/rrc_eNB_S1AP.c index ae8fa0a450..d2c0d0acbe 100644 --- a/openair2/RRC/LITE/rrc_eNB_S1AP.c +++ b/openair2/RRC/LITE/rrc_eNB_S1AP.c @@ -1197,6 +1197,7 @@ int rrc_eNB_process_S1AP_UE_CONTEXT_RELEASE_COMMAND (MessageDef *msg_p, const ch } return (-1); } else { + ue_context_p->ue_context.ue_release_timer_s1 = 0; PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, ENB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); rrc_eNB_generate_RRCConnectionRelease(&ctxt, ue_context_p); /* diff --git a/openair2/RRC/LITE/rrc_eNB_UE_context.c b/openair2/RRC/LITE/rrc_eNB_UE_context.c index 28eace8f5a..0ae3d7ca15 100644 --- a/openair2/RRC/LITE/rrc_eNB_UE_context.c +++ b/openair2/RRC/LITE/rrc_eNB_UE_context.c @@ -155,7 +155,21 @@ rrc_eNB_get_ue_context( memset(&temp, 0, sizeof(struct rrc_eNB_ue_context_s)); /* eNB ue rrc id = 24 bits wide */ temp.ue_id_rnti = rntiP; +#if 0 return RB_FIND(rrc_ue_tree_s, &rrc_instance_pP->rrc_ue_head, &temp); +#endif + struct rrc_eNB_ue_context_s *ue_context_p = NULL; + ue_context_p = RB_FIND(rrc_ue_tree_s, &rrc_instance_pP->rrc_ue_head, &temp); + if ( ue_context_p != NULL) { + return ue_context_p; + } else { + RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(rrc_instance_pP->rrc_ue_head)) { + if (ue_context_p->ue_context.rnti == rntiP) { + return ue_context_p; + } + } + return NULL; + } } diff --git a/openair3/GTPV1-U/gtpv1u_eNB.c b/openair3/GTPV1-U/gtpv1u_eNB.c index d152840dd4..7c87cbc073 100644 --- a/openair3/GTPV1-U/gtpv1u_eNB.c +++ b/openair3/GTPV1-U/gtpv1u_eNB.c @@ -814,40 +814,81 @@ int gtpv1u_update_s1u_tunnel( const rnti_t prior_rnti ) { + /* Local tunnel end-point identifier */ teid_t s1u_teid = 0; gtpv1u_teid_data_t *gtpv1u_teid_data_p = NULL; gtpv1u_ue_data_t *gtpv1u_ue_data_p = NULL; + gtpv1u_ue_data_t *gtpv1u_ue_data_new_p = NULL; //MessageDef *message_p = NULL; hashtable_rc_t hash_rc = HASH_TABLE_KEY_NOT_EXISTS; - int i; - ebi_t eps_bearer_id = 0; + int i,j; + uint8_t bearers_num = 0,bearers_total = 0; //----------------------- // PDCP->GTPV1U mapping //----------------------- hash_rc = hashtable_get(RC.gtpv1u_data_g->ue_mapping, prior_rnti, (void **)>pv1u_ue_data_p); - AssertFatal(hash_rc == HASH_TABLE_OK, "Error get ue_mapping(rnti=%x) from GTPV1U hashtable error\n", prior_rnti); + if(hash_rc != HASH_TABLE_OK){ + LOG_E(GTPU,"Error get ue_mapping(rnti=%x) from GTPV1U hashtable error\n", prior_rnti); + return -1; + } - gtpv1u_ue_data_p->ue_id = create_tunnel_req_pP->rnti; - hash_rc = hashtable_insert(RC.gtpv1u_data_g->ue_mapping, create_tunnel_req_pP->rnti, gtpv1u_ue_data_p); + gtpv1u_ue_data_new_p = calloc (1, sizeof(gtpv1u_ue_data_t)); + memcpy(gtpv1u_ue_data_new_p,gtpv1u_ue_data_p,sizeof(gtpv1u_ue_data_t)); + gtpv1u_ue_data_new_p->ue_id = create_tunnel_req_pP->rnti; + + hash_rc = hashtable_insert(RC.gtpv1u_data_g->ue_mapping, create_tunnel_req_pP->rnti, gtpv1u_ue_data_new_p); AssertFatal(hash_rc == HASH_TABLE_OK, "Error inserting ue_mapping in GTPV1U hashtable"); LOG_I(GTPU, "inserting ue_mapping(rnti=%x) in GTPV1U hashtable\n", create_tunnel_req_pP->rnti); + hash_rc = hashtable_remove(RC.gtpv1u_data_g->ue_mapping, prior_rnti); + LOG_I(GTPU, "hashtable_remove ue_mapping(rnti=%x) in GTPV1U hashtable\n", + prior_rnti); //----------------------- // GTPV1U->PDCP mapping //----------------------- - for (i = 0; i < create_tunnel_req_pP->num_tunnels; i++) { - eps_bearer_id = create_tunnel_req_pP->eps_bearer_id[i]; - s1u_teid = gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_eNB; - hash_rc = hashtable_get(RC.gtpv1u_data_g->teid_mapping, s1u_teid, (void**)>pv1u_teid_data_p); - AssertFatal(hash_rc == HASH_TABLE_OK, "Error get teid mapping(s1u_teid=%u) from GTPV1U hashtable", s1u_teid); + bearers_total =gtpv1u_ue_data_new_p->num_bearers; + for(j = 0;jue_id = create_tunnel_req_pP->rnti; - gtpv1u_teid_data_p->eps_bearer_id = eps_bearer_id; + if(gtpv1u_ue_data_new_p->bearers[j].state != BEARER_IN_CONFIG) + continue; + + bearers_num++; + for (i = 0; i < create_tunnel_req_pP->num_tunnels; i++) { + if(j == (create_tunnel_req_pP->eps_bearer_id[i]-GTPV1U_BEARER_OFFSET)) + break; + } + if(i < create_tunnel_req_pP->num_tunnels){ + s1u_teid = gtpv1u_ue_data_new_p->bearers[j].teid_eNB; + hash_rc = hashtable_get(RC.gtpv1u_data_g->teid_mapping, s1u_teid, (void**)>pv1u_teid_data_p); + if (hash_rc == HASH_TABLE_OK) { + gtpv1u_teid_data_p->ue_id = create_tunnel_req_pP->rnti; + gtpv1u_teid_data_p->eps_bearer_id = create_tunnel_req_pP->eps_bearer_id[i]; + + LOG_I(GTPU, "updata teid_mapping te_id %u (prior_rnti %x rnti %x) in GTPV1U hashtable\n", + s1u_teid,prior_rnti,create_tunnel_req_pP->rnti); + }else{ + LOG_W(GTPU, "Error get teid mapping(s1u_teid=%u) from GTPV1U hashtable", s1u_teid); + } + }else{ + s1u_teid = gtpv1u_ue_data_new_p->bearers[j].teid_eNB; + hash_rc = hashtable_remove(RC.gtpv1u_data_g->teid_mapping, s1u_teid); + + if (hash_rc != HASH_TABLE_OK) { + LOG_D(GTPU, "Removed user rnti %x , enb S1U teid %u not found\n", prior_rnti, s1u_teid); + } + gtpv1u_ue_data_new_p->bearers[j].state = BEARER_DOWN; + gtpv1u_ue_data_new_p->num_bearers--; + LOG_I(GTPU, "delete teid_mapping te_id %u (rnti%x) bearer_id %d in GTPV1U hashtable\n", + s1u_teid,prior_rnti,j+GTPV1U_BEARER_OFFSET);; + } + if(bearers_num > bearers_total) + break; } return 0; + } //----------------------------------------------------------------------------- From 0f2cb0aada71e146925c0cff5b4ce50ef19050c0 Mon Sep 17 00:00:00 2001 From: Xu Bo Date: Mon, 8 Jan 2018 18:53:30 +0900 Subject: [PATCH 130/284] fix the timer between reestablishment and reestablishmentComplete --- openair2/LAYER2/MAC/eNB_scheduler.c | 11 ++++++++++- openair2/RRC/LITE/rrc_eNB.c | 15 ++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 38a34d5eec..35e866248c 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -712,7 +712,16 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer++; if(RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer >= RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer_thres) { - RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer = 0; + RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ue_reestablishment_reject_timer = 0; + for (int ue_id_l = 0; ue_id_l < NUMBER_OF_UE_MAX; ue_id_l++) { + if (reestablish_rnti_map[ue_id_l][0] == rnti) { + // clear currentC-RNTI from map + reestablish_rnti_map[ue_id_l][0] = 0; + reestablish_rnti_map[ue_id_l][1] = 0; + break; + } + } + for (int ii=0; iiulsch[ii]; diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 24571ad4f7..886a18a557 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -1195,9 +1195,10 @@ rrc_eNB_generate_RRCConnectionReestablishment( // remove UE after 10 frames after RRCConnectionReestablishmentRelease is triggered //ue_context_pP->ue_context.ue_release_timer_thres = 100; // activate release timer, if RRCComplete not received after 100 frames, remove UE - ue_context_pP->ue_context.ue_reestablishment_timer = 1; + int UE_id = find_UE_id(ctxt_pP->module_id, ctxt_pP->rnti); + RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer = 1; // remove UE after 100 frames after RRCConnectionReestablishmentRelease is triggered - ue_context_pP->ue_context.ue_reestablishment_timer_thres = 1000; + RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer_thres = 1000; } //----------------------------------------------------------------------------- @@ -5482,12 +5483,12 @@ rrc_eNB_decode_ccch( rrc_eNB_generate_RRCConnectionReestablishmentReject(ctxt_pP, ue_context_p, CC_id); break; } - if(ue_context_p->ue_context.ue_reestablishment_timer > 0){ + int UE_id = find_UE_id(ctxt_pP->module_id, c_rnti); + if(ue_context_p->ue_context.ue_reestablishment_timer > 0 || RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer > 0){ LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" RRCConnectionReestablishment(Previous) don't complete, let's reject the UE\n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); rrc_eNB_generate_RRCConnectionReestablishmentReject(ctxt_pP, ue_context_p, CC_id); - ue_context_p->ue_context.ue_reestablishment_timer_thres = 1000; break; } LOG_D(RRC, @@ -6123,6 +6124,8 @@ if (ue_context_p->ue_context.nb_of_modify_e_rabs > 0) { DCCH, sdu_sizeP); { + int UE_id = find_UE_id(ctxt_pP->module_id, ctxt_pP->rnti); + RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer = 0; rnti_t reestablish_rnti = 0; // select C-RNTI from map for (i = 0; i < NUMBER_OF_UE_MAX; i++) { @@ -6163,7 +6166,9 @@ if (ue_context_p->ue_context.nb_of_modify_e_rabs > 0) { #endif } //ue_context_p->ue_context.ue_release_timer = 0; - ue_context_p->ue_context.ue_reestablishment_timer = 1; + ue_context_p->ue_context.ue_reestablishment_timer = 1; + // remove UE after 100 frames after RRCConnectionReestablishmentRelease is triggered + ue_context_p->ue_context.ue_reestablishment_timer_thres = 1000; } break; From 89ea5ed9882d97338a98ad7c3bdc48558318fc93 Mon Sep 17 00:00:00 2001 From: Xu Bo Date: Tue, 9 Jan 2018 13:52:41 +0900 Subject: [PATCH 131/284] fix RRCConnection timer thres when GTPV1U_ENB_DELETE_TUNNEL_RESP --- openair2/RRC/LITE/rrc_eNB.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 886a18a557..eb82f36b84 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -6650,10 +6650,11 @@ rrc_enb_task( /* Nothing to do. Apparently everything is done in S1AP processing */ //LOG_I(RRC, "[eNB %d] Received message %s, not processed because procedure not synched\n", //instance, msg_name_p); - if (rrc_eNB_get_ue_context(RC.rrc[instance], GTPV1U_ENB_DELETE_TUNNEL_RESP(msg_p).rnti)) { - rrc_eNB_get_ue_context(RC.rrc[instance], GTPV1U_ENB_DELETE_TUNNEL_RESP(msg_p).rnti)->ue_context.ue_release_timer_rrc = - rrc_eNB_get_ue_context(RC.rrc[instance], GTPV1U_ENB_DELETE_TUNNEL_RESP(msg_p).rnti)->ue_context.ue_release_timer_thres_rrc; - } + if (rrc_eNB_get_ue_context(RC.rrc[instance], GTPV1U_ENB_DELETE_TUNNEL_RESP(msg_p).rnti) + && rrc_eNB_get_ue_context(RC.rrc[instance], GTPV1U_ENB_DELETE_TUNNEL_RESP(msg_p).rnti)->ue_context.ue_release_timer_rrc > 0) { + rrc_eNB_get_ue_context(RC.rrc[instance], GTPV1U_ENB_DELETE_TUNNEL_RESP(msg_p).rnti)->ue_context.ue_release_timer_rrc = + rrc_eNB_get_ue_context(RC.rrc[instance], GTPV1U_ENB_DELETE_TUNNEL_RESP(msg_p).rnti)->ue_context.ue_release_timer_thres_rrc; + } break; # endif From 9d03290858026ad5580e395cc19b1fdc2bec99b0 Mon Sep 17 00:00:00 2001 From: Guy De Souza Date: Tue, 5 Dec 2017 13:53:40 +0100 Subject: [PATCH 132/284] rx_dump_frame ue_mode fix --- targets/RT/USER/lte-softmodem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index dae462397c..1fe3e4e0a0 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -616,8 +616,8 @@ static void get_options(void) { if ( (cmdline_uemodeparams[CMDLINE_CALIBUERXBYP_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue_byp; if ( (cmdline_uemodeparams[CMDLINE_DEBUGUEPRACH_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = debug_prach; if ( (cmdline_uemodeparams[CMDLINE_NOL2CONNECT_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = no_L2_connect; - if ( (cmdline_uemodeparams[CMDLINE_CALIBPRACHTX_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = calib_prach_tx; - if (dumpframe > 0) mode = rx_dump_frame; + if ( (cmdline_uemodeparams[CMDLINE_CALIBPRACHTX_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = calib_prach_tx; + if ( (cmdline_uemodeparams[CMDLINE_DUMPMEMORY_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_dump_frame; if ( downlink_frequency[0][0] > 0) { printf("Downlink frequency set to %u\n", downlink_frequency[0][0]); From 380222eefd03ca6329826ab48796d573907d4253 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Wed, 10 Jan 2018 21:07:45 +0100 Subject: [PATCH 133/284] timestamp handling for IF4p5, attenuation parameters --- targets/RT/USER/lte-ru.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 54693f43c8..e8a5497d42 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -624,7 +624,8 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { if ((frame_tx == 0)&&(subframe_tx == 0)) proc->frame_tx_unwrap += 1024; - proc->timestamp_tx = (((frame_tx + proc->frame_tx_unwrap) * 10) + subframe_tx) * fp->samples_per_tti; + proc->timestamp_tx = ((((uint64_t)frame_tx + (uint64_t)proc->frame_tx_unwrap) * 10) + (uint64_t)subframe_tx) * (uint64_t)fp->samples_per_tti; + LOG_D(PHY,"RU %d/%d TST %llu, frame %d, subframe %d\n",ru->idx,0,(long long unsigned int)proc->timestamp_tx,frame_tx,subframe_tx); // dump VCD output for first RU in list if (ru == RC.ru[0]) { @@ -1801,8 +1802,11 @@ void configure_rru(int idx, ru->frame_parms.threequarter_fs = config->threequarter_fs[0]; ru->frame_parms.pdsch_config_common.referenceSignalPower = ru->max_pdschReferenceSignalPower-config->att_tx[0]; if (ru->function==NGFI_RRU_IF4p5) { - LOG_I(PHY,"Setting ru->function to NGFI_RRU_IF4p5, prach_FrequOffset %d, prach_ConfigIndex %d\n", - config->prach_FreqOffset[0],config->prach_ConfigIndex[0]); + ru->frame_parms.att_rx = ru->att_rx; + ru->frame_parms.att_tx = ru->att_tx; + + LOG_I(PHY,"Setting ru->function to NGFI_RRU_IF4p5, prach_FrequOffset %d, prach_ConfigIndex %d, att (%d,%d)\n", + config->prach_FreqOffset[0],config->prach_ConfigIndex[0],ru->att_tx,ru->att_rx); ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset = config->prach_FreqOffset[0]; ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex = config->prach_ConfigIndex[0]; #ifdef Rel14 @@ -1816,6 +1820,8 @@ void configure_rru(int idx, init_frame_parms(&ru->frame_parms,1); + fill_rf_config(ru,ru->rf_config_file); + phy_init_RU(ru); From 5a202db54d7753c2c8086d9c503370ef1714b785 Mon Sep 17 00:00:00 2001 From: Younes Date: Wed, 10 Jan 2018 21:10:35 +0100 Subject: [PATCH 134/284] removal of assertions which failed for TDD --- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 2 +- openair1/SCHED/fapi_l1.c | 10 ++++++++-- openair1/SCHED/phy_procedures_lte_eNb.c | 6 ++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 3b1b6895c6..ff29f9429d 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -6488,7 +6488,7 @@ uint8_t pdcch_alloc2ul_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t n) else ul_subframe = ((n+4)%10); - AssertFatal(frame_parms->frame_type == FDD || subframe_select(frame_parms,ul_subframe) == SF_UL,"illegal ul_subframe %d\n",ul_subframe); + // AssertFatal(frame_parms->frame_type == FDD || subframe_select(frame_parms,ul_subframe) == SF_UL,"illegal ul_subframe %d (n %d)\n",ul_subframe,n); LOG_D(PHY, "subframe %d: PUSCH subframe = %d\n", n, ul_subframe); return ul_subframe; diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c index 8aff92d485..e749a52a44 100644 --- a/openair1/SCHED/fapi_l1.c +++ b/openair1/SCHED/fapi_l1.c @@ -580,9 +580,14 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) AssertFatal(RC.eNB[Mod_id]!=NULL,"RC.eNB[%d] is null\n",Mod_id); AssertFatal(RC.eNB[Mod_id][CC_id]!=NULL,"RC.eNB[%d][%d] is null\n",Mod_id,CC_id); + + eNB = RC.eNB[Mod_id][CC_id]; fp = &eNB->frame_parms; proc = &eNB->proc.proc_rxtx[0]; + + if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)==SF_UL)) return; + ul_subframe = pdcch_alloc2ul_subframe(fp,subframe); ul_frame = pdcch_alloc2ul_frame(fp,frame,subframe); @@ -608,8 +613,9 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) frame,subframe,ul_subframe,number_dl_pdu,TX_req->tx_request_body.number_of_pdus,number_hi_dci0_pdu,number_ul_pdu); - if (ul_subframe<10) { // This means that there is an ul_subframe that can be configured here - LOG_D(PHY,"NFAPI: Clearing dci allocations for potential UL\n"); + if ((ul_subframe<10)&& + (subframe_select(fp,ul_subframe)==SF_UL)) { // This means that there is an ul_subframe that can be configured here + LOG_D(PHY,"NFAPI: Clearing dci allocations for potential UL subframe %d\n",ul_subframe); harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); // clear DCI allocation maps for new subframe diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 92ff87668d..8c6acca9d4 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -404,6 +404,7 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, int offset = eNB->CC_id;//proc == &eNB->proc.proc_rxtx[0] ? 0 : 1; + if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)==SF_UL)) return; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX+offset,1); @@ -437,7 +438,8 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, } /* save old HARQ information needed for PHICH generation */ - if (ul_subframe < 10) { // This means that there is a potential UL subframe that will be scheduled here + if ((ul_subframe < 10)&& + (subframe_select(fp,ul_subframe)==SF_UL)) { // This means that there is a potential UL subframe that will be scheduled here for (i=0; iulsch[i]) { @@ -1959,7 +1961,7 @@ void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,const eNB->first_run_I0_measurements); int min_I0=1000,max_I0=0; - if ((frame==0) && (subframe==6)) { + if ((frame==0) && (subframe==4)) { for (int i=0;iframe_parms.N_RB_UL;i++) { if (i==(eNB->frame_parms.N_RB_UL>>1) - 1) i+=2; From 1823ce9525bc009ac26ab4cc2bffcab46b58e66a Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Thu, 11 Jan 2018 10:37:17 +0100 Subject: [PATCH 135/284] Fix #281 --- targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index 8b62a8e698..446e602f6d 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -283,12 +283,11 @@ int64_t wrap_ts = 0; unsigned int u_sf_mode = 0; // 1=record, 2=replay unsigned int u_sf_record = 0; // record mode unsigned int u_sf_replay = 0; // replay mode -char u_sf_filename[1024]; // subframes file path +char u_sf_filename[1024] = ""; // subframes file path unsigned int u_sf_max = DEF_NB_SF; // max number of recorded subframes unsigned int u_sf_loops = DEF_SF_NB_LOOP; // number of loops in replay mode unsigned int u_sf_read_delay = DEF_SF_DELAY_READ; // read delay in replay mode unsigned int u_sf_write_delay = DEF_SF_DELAY_WRITE; // write delay in replay mode -char *tmp_filename[1]; // use an array of pointer (libconfig does not seems to work with char array yet) char config_opt_sf_file[] = CONFIG_OPT_SF_FILE; char config_def_sf_file[] = DEF_SF_FILE; @@ -837,7 +836,7 @@ int trx_usrp_recplay_config_init(paramdef_t *usrp_recplay_params) { memcpy(usrp_recplay_params[0].optname, config_opt_sf_file, strlen(config_opt_sf_file)); usrp_recplay_params[0].helpstr = config_hlp_sf_file; usrp_recplay_params[0].paramflags=PARAMFLAG_NOFREE; - usrp_recplay_params[0].strptr=(char **)&tmp_filename[0]; + usrp_recplay_params[0].strptr=(char **)&u_sf_filename; usrp_recplay_params[0].defstrval = NULL; usrp_recplay_params[0].type=TYPE_STRING; usrp_recplay_params[0].numelt=sizeof(u_sf_filename); @@ -912,16 +911,13 @@ extern "C" { // end to check memset(usrp_recplay_params, 0, 7*sizeof(paramdef_t)); memset(&u_sf_filename[0], 0, 1024); - tmp_filename[0] = u_sf_filename; if (trx_usrp_recplay_config_init(usrp_recplay_params) != 0) { std::cerr << "USRP device record/replay mode configuration error exiting" << std::endl; return -1; } config_process_cmdline(usrp_recplay_params,sizeof(usrp_recplay_params)/sizeof(paramdef_t),NULL); - if (strlen(tmp_filename[0]) != 0) { - (void) strcpy(u_sf_filename, tmp_filename[0]); - } else { + if (strlen(u_sf_filename) == 0) { (void) strcpy(u_sf_filename, DEF_SF_FILE); } From afcc9aabd854b3b13022a534af9234ffe09216d1 Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Thu, 11 Jan 2018 16:50:50 +0100 Subject: [PATCH 136/284] Fix #582, USER_MODE flag removed --- cmake_targets/CMakeLists.txt | 2 - cmake_targets/epc_test/CMakeLists.template | 1 - .../oaisim_build_oai/CMakeLists.template | 1 - .../oaisim_mme_build_oai/CMakeLists.template | 1 - .../oaisim_noS1_build_oai/CMakeLists.template | 1 - .../s1c_mme_test/CMakeLists.template | 1 - common/utils/itti/itti_types.h | 4 - common/utils/telnetsrv/CMakeLists.txt | 2 +- openair1/PHY/CODING/Makefile.arm | 2 +- openair1/PHY/CODING/TESTBENCH/Makefile | 2 +- openair1/PHY/CODING/crc_byte.c | 7 -- openair1/PHY/CODING/viterbi_lte.c | 6 +- openair1/PHY/INIT/init_top.c | 4 - openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c | 4 - .../lte_dl_bf_channel_estimation.c | 2 - .../lte_dl_channel_estimation.c | 2 - .../lte_dl_channel_estimation_emos.c | 2 - .../lte_dl_mbsfn_channel_estimation.c | 2 - .../PHY/LTE_ESTIMATION/lte_ue_measurements.c | 3 - .../lte_ul_channel_estimation.c | 15 --- openair1/PHY/LTE_REFSIG/lte_dl_cell_spec.c | 2 - openair1/PHY/LTE_REFSIG/lte_dl_mbsfn.c | 2 - openair1/PHY/LTE_REFSIG/lte_dl_uespec.c | 2 - openair1/PHY/LTE_TRANSPORT/dci.c | 2 - openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c | 8 -- .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 8 -- openair1/PHY/LTE_TRANSPORT/drs_modulation.c | 15 --- openair1/PHY/LTE_TRANSPORT/edci.c | 2 - openair1/PHY/LTE_TRANSPORT/initial_sync.c | 4 - openair1/PHY/LTE_TRANSPORT/pbch.c | 10 -- openair1/PHY/LTE_TRANSPORT/phich.c | 4 - openair1/PHY/LTE_TRANSPORT/prach.c | 2 - openair1/PHY/LTE_TRANSPORT/srs_modulation.c | 28 ----- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 9 -- openair1/PHY/MODULATION/ul_7_5_kHz.c | 4 - openair1/PHY/TOOLS/Makefile | 8 +- openair1/PHY/TOOLS/cmult_vv.c | 5 +- openair1/PHY/TOOLS/defs.h | 2 - openair1/PHY/TOOLS/file_output.c | 4 - openair1/PHY/TOOLS/lte_dfts.c | 2 - openair1/PHY/types.h | 4 - openair1/SCHED/extern.h | 34 ------ openair1/SCHED/phy_procedures_lte_ue.c | 2 + .../ETH_TRANSPORT/bypass_session_layer.c | 92 +-------------- openair1/SIMULATION/ETH_TRANSPORT/extern.h | 4 - .../SIMULATION/ETH_TRANSPORT/multicast_link.c | 4 +- openair1/SIMULATION/ETH_TRANSPORT/proto.h | 8 -- openair1/SIMULATION/ETH_TRANSPORT/socket.c | 2 - openair1/SIMULATION/ETH_TRANSPORT/vars.h | 4 - openair1/SIMULATION/LTE_PHY/Makefile | 2 +- openair1/SIMULATION/RF/Makefile | 2 +- openair1/SIMULATION/TOOLS/rangen_double.c | 2 - openair1/SIMULATION/TOOLS/taus.c | 21 ---- openair2/COMMON/openair_defs.h | 43 ------- openair2/COMMON/openair_types.h | 14 --- openair2/COMMON/platform_constants.h | 8 -- openair2/COMMON/platform_types.h | 2 - openair2/COMMON/rtos_header.h | 48 ++------ openair2/LAYER2/MAC/defs.h | 8 -- openair2/LAYER2/MAC/extern.h | 4 - openair2/LAYER2/MAC/main.c | 4 - openair2/LAYER2/MAC/pre_processor.c | 6 - openair2/LAYER2/MAC/ue_procedures.c | 5 - openair2/LAYER2/MAC/vars.h | 3 - openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 7 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 8 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c | 2 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h | 4 - openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c | 2 - .../LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c | 8 -- .../LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c | 4 - .../LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h | 2 - .../LAYER2/RLC/AM_v9.3.0/rlc_am_windows.c | 2 - openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c | 4 - openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h | 3 - .../LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.c | 2 - .../LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c | 6 - .../LAYER2/RLC/UM_v9.3.0/rlc_um_structs.h | 2 - openair2/LAYER2/RLC/rlc.h | 4 - openair2/LAYER2/RLC/rlc_primitives.h | 6 +- openair2/LAYER2/openair2_proc.c | 52 +-------- openair2/LAYER2/register.c | 40 ------- openair2/NAS/SIMU_CELLULAR/Makefile | 4 +- openair2/PHY_INTERFACE/mac_phy_primitives.c | 9 -- openair2/PHY_INTERFACE/vars.h | 4 - .../L2_INTERFACE/openair_rrc_L2_interface.c | 35 ------ openair2/RRC/LITE/MESSAGES/asn1_msg.c | 46 +------- openair2/RRC/LITE/MESSAGES/asn1_msg.h | 4 - openair2/RRC/LITE/defs.h | 7 -- openair2/RRC/LITE/mesh_top.c | 107 ------------------ openair2/RRC/LITE/rrc_UE.c | 10 -- openair2/RRC/LITE/rrc_common.c | 2 - openair2/RRC/LITE/rrc_eNB.c | 10 +- openair2/RRC/LITE/rrc_rrm_interface.c | 5 - openair2/RRC/LITE/rrc_rrm_interface.h | 12 -- openair2/RRC/LITE/rrm_2_rrc_msg.c | 48 -------- openair2/RRC/LITE/utils.c | 22 ---- openair2/UTIL/LISTS/list2.c | 6 - openair2/UTIL/LOG/log.c | 16 --- openair2/UTIL/LOG/log.h | 25 ---- openair2/UTIL/MATH/random.c | 10 +- openair2/UTIL/MEM/mem_block.c | 4 +- openair2/UTIL/MEM/mem_block.h | 13 --- openair2/UTIL/MEM/mem_mngt.c | 4 - openair2/UTIL/OCG/makefile | 2 +- openair2/UTIL/OMG/makefile | 2 +- openair2/UTIL/OMG/makefile_old | 2 +- openair2/UTIL/OMG/makefile_standalone | 2 +- openair2/UTIL/TRACE/print.h | 11 +- openair2/X2AP/Makefile.inc | 1 - targets/ARCH/EXMIMO/USERSPACE/OCTAVE/Makefile | 2 +- targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp | 10 +- targets/Makefile.common | 1 - targets/PROJECTS/E-MBMS/build_all.bash | 4 +- targets/RT/USER/Makefile | 2 +- targets/RT/USER/Makefile.agilent | 4 +- targets/SIMU/USER/Makefile | 2 +- targets/SIMU/USER/oaisim_functions.c | 4 +- targets/TEST/AT_COMMANDS/Makefile | 2 +- targets/TEST/OAI/case01.py | 8 +- targets/TEST/PACKET_TRACER/Makefile | 2 +- targets/TEST/PDCP/Makefile | 2 +- .../TEST/PDCP/with_rlc/Makefile.data_bearer | 2 +- targets/TEST/RLC_AM_V9.3.0/Makefile | 2 +- targets/TEST/RLC_UM_V9.3.0/Makefile | 2 +- 125 files changed, 69 insertions(+), 1074 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index b24db90edb..f788f95f3c 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -587,7 +587,6 @@ Message("CPU_Affinity flag is ${CPU_AFFINITY}") add_boolean_option(ENABLE_SECURITY True "Enable LTE integrity and ciphering between RRC UE and eNB") add_boolean_option(ENABLE_USE_MME True "eNB connected to MME (INTERFACE S1-C), not standalone eNB") add_boolean_option(NO_RRM True "DO WE HAVE A RADIO RESSOURCE MANAGER: NO") -add_boolean_option(USER_MODE True "????") add_boolean_option(RRC_DEFAULT_RAB_IS_AM False "set the RLC mode to AM for the default bearer") add_boolean_option(OAI_NW_DRIVER_TYPE_ETHERNET False "????") @@ -2136,7 +2135,6 @@ get_directory_property(DirDefs COMPILE_DEFINITIONS ) foreach( d ${DirDefs} ) set(module_cc_opt_tmp "${module_cc_opt_tmp} -D${d}") endforeach() -string(REPLACE "-DUSER_MODE" "" module_cc_opt ${module_cc_opt_tmp}) get_directory_property( DirDefs INCLUDE_DIRECTORIES ) foreach( d ${DirDefs} ) set(module_cc_opt "${module_cc_opt} -I${d}") diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index 76defbc7d7..15fec380e9 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -75,5 +75,4 @@ set ( SECU False ) set ( SMBV False ) set ( TEST_OMG False ) set ( USE_MME "R10" ) -set ( USER_MODE True ) set ( XER_PRINT True ) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index 0a05d68d10..80d2b60500 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -76,5 +76,4 @@ set ( SPECTRA False ) set ( TEST_OMG False ) set ( USE_3GPP_ADDR_AS_LINK_ADDR False ) set ( USE_MME "R10" ) -set ( USER_MODE True ) set ( XER_PRINT False ) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index 69fa209b16..0a11b8a249 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -78,6 +78,5 @@ set ( UPDATE_RELEASE_9 True) set ( UPDATE_RELEASE_10 True) set ( USE_3GPP_ADDR_AS_LINK_ADDR False ) set ( USE_MME "R10" ) -set ( USER_MODE True ) set ( XER_PRINT False ) set ( XFORMS False ) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 8e1670ea43..510744cd7b 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -77,7 +77,6 @@ set ( SPECTRA False ) set ( TEST_OMG False ) set ( USE_3GPP_ADDR_AS_LINK_ADDR False ) set ( USE_MME "R10" ) -set ( USER_MODE True ) set ( XER_PRINT False ) set ( DEBUG_PHY False ) set ( DEBUG_PHY_PROC False) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index 994edf8352..2bbf7bc536 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -80,6 +80,5 @@ set ( TEST_S1C_MME True ) set ( USE_3GPP_ADDR_AS_LINK_ADDR False ) set ( USE_MME "R10" ) -set ( USER_MODE True ) set ( XER_PRINT False ) set ( XFORMS False ) diff --git a/common/utils/itti/itti_types.h b/common/utils/itti/itti_types.h index 7f01901712..d07853133b 100644 --- a/common/utils/itti/itti_types.h +++ b/common/utils/itti/itti_types.h @@ -27,11 +27,7 @@ #ifndef _ITTI_TYPES_H_ #define _ITTI_TYPES_H_ -#ifdef USER_MODE #include -#else -#include -#endif #define CHARS_TO_UINT32(c1, c2, c3, c4) (((c4) << 24) | ((c3) << 16) | ((c2) << 8) | (c1)) diff --git a/common/utils/telnetsrv/CMakeLists.txt b/common/utils/telnetsrv/CMakeLists.txt index 51284ad2e8..56c1d70791 100644 --- a/common/utils/telnetsrv/CMakeLists.txt +++ b/common/utils/telnetsrv/CMakeLists.txt @@ -24,7 +24,7 @@ set(OPENAIR_NFAPIINC $ENV{NFAPI_DIR} ) set(CMAKE_INSTALL_PREFIX $ENV{OPENAIR_TARGETS}) -add_definitions (-DRel14 -DCMAKER -DENABLE_FXP -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNEW_FFT -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR1 -DOPENAIR2 -DOPENAIR_LTE -DPC_DSP -DPC_TARGET -DPHYSIM -DPHY_CONTEXT -DPUCCH -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DUSER_MODE -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) +add_definitions (-DRel14 -DCMAKER -DENABLE_FXP -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNEW_FFT -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR1 -DOPENAIR2 -DOPENAIR_LTE -DPC_DSP -DPC_TARGET -DPHYSIM -DPHY_CONTEXT -DPUCCH -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) add_compile_options( -fPIC -march=native -Ofast) include_directories( ./ ${OPENAIR_COMMON_DIR} ${OPENAIR_DIR} ${OPENAIR1_DIR} ${OPENAIR2_DIR} ${OPENAIR2_COMMON_DIR} ${OPENAIR2_DIR}/UTIL/LOG diff --git a/openair1/PHY/CODING/Makefile.arm b/openair1/PHY/CODING/Makefile.arm index 07dbf55909..04598075e3 100644 --- a/openair1/PHY/CODING/Makefile.arm +++ b/openair1/PHY/CODING/Makefile.arm @@ -5,7 +5,7 @@ RATE12CC_SRC = ccoding_byte.c viterbi.c crc_byte.c all: 3gpplte_sse 3gpplte_sse: $(TURBO_SRC) - gcc -O3 -gdwarf-2 -mfloat-abi=hard -mfpu=neon -lm -lgcc -lrt ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR2_DIR/COMMON -DUSER_MODE -DTC_MAIN -DNB_ANTENNAS_RX=1 -o 3gpplte_sse 3gpplte_sse.c -Wall -g -ggdb -DTC_MAIN + gcc -O3 -gdwarf-2 -mfloat-abi=hard -mfpu=neon -lm -lgcc -lrt ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR2_DIR/COMMON -DTC_MAIN -DNB_ANTENNAS_RX=1 -o 3gpplte_sse 3gpplte_sse.c -Wall -g -ggdb -DTC_MAIN diff --git a/openair1/PHY/CODING/TESTBENCH/Makefile b/openair1/PHY/CODING/TESTBENCH/Makefile index a8ddd1fcb5..515775a102 100644 --- a/openair1/PHY/CODING/TESTBENCH/Makefile +++ b/openair1/PHY/CODING/TESTBENCH/Makefile @@ -7,7 +7,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DNODE_RG -DUSER_MODE -DPC_TARGET -DNO_UL_REF -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DOPENAIR_LTE -DMAX_NUM_CCs=1 +CFLAGS += -DNODE_RG -DPC_TARGET -DNO_UL_REF -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DOPENAIR_LTE -DMAX_NUM_CCs=1 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/openair1/PHY/CODING/crc_byte.c b/openair1/PHY/CODING/crc_byte.c index 4f0dcf2196..5ec4fcaaa4 100644 --- a/openair1/PHY/CODING/crc_byte.c +++ b/openair1/PHY/CODING/crc_byte.c @@ -31,13 +31,6 @@ */ -#ifndef USER_MODE -#define __NO_VERSION__ - -#endif - -//#include "PHY/types.h" - #include "defs.h" diff --git a/openair1/PHY/CODING/viterbi_lte.c b/openair1/PHY/CODING/viterbi_lte.c index d112e7c109..5e11cb3453 100644 --- a/openair1/PHY/CODING/viterbi_lte.c +++ b/openair1/PHY/CODING/viterbi_lte.c @@ -28,10 +28,6 @@ date: 21.10.2009 */ -#ifdef USER_MODE -#include -#endif - #ifndef TEST_DEBUG #include "PHY/defs.h" #include "PHY/extern.h" @@ -126,7 +122,7 @@ void print_shorts(__m128i x,char *s) { } */ -#endif // USER_MODE +#endif // DEBUG_VITERBI diff --git a/openair1/PHY/INIT/init_top.c b/openair1/PHY/INIT/init_top.c index c4d5850501..218beb4faf 100644 --- a/openair1/PHY/INIT/init_top.c +++ b/openair1/PHY/INIT/init_top.c @@ -20,10 +20,6 @@ */ /*!\brief Initilization and reconfiguration routines for LTE PHY */ -#ifndef USER_MODE -#define __NO_VERSION__ -#endif - #include "defs.h" #include "PHY/extern.h" #include "MAC_INTERFACE/extern.h" diff --git a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c index cd032e688f..18444076f3 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c @@ -149,10 +149,8 @@ int lte_est_timing_advance(LTE_DL_FRAME_PARMS *frame_parms, int temp, i, aa, max_pos = 0,ind; int max_val=0; short Re,Im,ncoef; -#ifdef USER_MODE #ifdef DEBUG_PHY char fname[100],vname[100]; -#endif #endif ncoef = 32768 - coef; @@ -187,12 +185,10 @@ int lte_est_timing_advance(LTE_DL_FRAME_PARMS *frame_parms, 1); break; } -#ifdef USER_MODE #ifdef DEBUG_PHY sprintf(fname,"srs_ch_estimates_time_%d%d.m",ind,aa); sprintf(vname,"srs_time_%d%d",ind,aa); write_output(fname,vname,lte_eNB_srs->srs_ch_estimates_time[aa],frame_parms->ofdm_symbol_size*2,2,1); -#endif #endif } diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c index 8dcf4b1c11..55d2cf6c5c 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c @@ -19,9 +19,7 @@ * contact@openairinterface.org */ -#ifdef USER_MODE #include -#endif #include "defs.h" #include "PHY/defs.h" #include "filt16_32.h" diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c index fb935e47a8..a4b29bb25e 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c @@ -19,9 +19,7 @@ * contact@openairinterface.org */ -#ifdef USER_MODE #include -#endif #include "defs.h" #include "SCHED/defs.h" #include "PHY/defs.h" diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation_emos.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation_emos.c index a64aa797af..4f1015a0e1 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation_emos.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation_emos.c @@ -19,9 +19,7 @@ * contact@openairinterface.org */ -#ifdef USER_MODE #include -#endif #include "defs.h" #include "PHY/defs.h" #include "SCHED/phy_procedures_emos.h" diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_mbsfn_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_mbsfn_channel_estimation.c index f298f8738c..17d44b22f8 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_mbsfn_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_mbsfn_channel_estimation.c @@ -19,9 +19,7 @@ * contact@openairinterface.org */ -#ifdef USER_MODE #include -#endif #include "defs.h" #include "PHY/defs.h" diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c b/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c index acda933d38..c4df34638b 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c @@ -38,7 +38,6 @@ int16_t cond_num_threshold = 0; -#ifdef USER_MODE void print_shorts(char *s,short *x) { @@ -57,8 +56,6 @@ void print_ints(char *s,int *x) ); } -#endif - int16_t get_PL(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index) { diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c index b495385612..18069f9759 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c @@ -91,7 +91,6 @@ int32_t temp_in_ifft_0[2048*2] __attribute__((aligned(32))); eNB->ulsch[UE_id]->harq_processes[harq_pid]->n_DMRS2 + frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.nPRS[(subframe<<1)+Ns]) % 12; -#if defined(USER_MODE) Msc_idx_ptr = (uint16_t*) bsearch(&Msc_RS, dftsizes, 33, sizeof(uint16_t), compareints); if (Msc_idx_ptr) @@ -101,26 +100,14 @@ int32_t temp_in_ifft_0[2048*2] __attribute__((aligned(32))); return(-1); } -#else - uint8_t b; - - for (b=0; b<33; b++) - if (Msc_RS==dftsizes[b]) - Msc_RS_idx = b; - -#endif - // LOG_I(PHY,"subframe %d, Ns %d, l %d, Msc_RS = %d, Msc_RS_idx = %d, u %d, v %d, cyclic_shift %d\n",subframe,Ns,l,Msc_RS, Msc_RS_idx,u,v,cyclic_shift); #ifdef DEBUG_CH -#ifdef USER_MODE - if (Ns==0) write_output("drs_seq0.m","drsseq0",ul_ref_sigs_rx[u][v][Msc_RS_idx],2*Msc_RS,2,1); else write_output("drs_seq1.m","drsseq1",ul_ref_sigs_rx[u][v][Msc_RS_idx],2*Msc_RS,2,1); -#endif #endif @@ -489,12 +476,10 @@ int32_t lte_srs_channel_estimation(LTE_DL_FRAME_PARMS *frame_parms, 15, 0); -#ifdef USER_MODE #ifdef DEBUG_SRS sprintf(fname,"srs_ch_est%d.m",aa); sprintf(vname,"srs_est%d",aa); write_output(fname,vname,srs_vars->srs_ch_estimates[aa],frame_parms->ofdm_symbol_size,1,1); -#endif #endif } diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_cell_spec.c b/openair1/PHY/LTE_REFSIG/lte_dl_cell_spec.c index b715b3ffa2..5bf69578d1 100644 --- a/openair1/PHY/LTE_REFSIG/lte_dl_cell_spec.c +++ b/openair1/PHY/LTE_REFSIG/lte_dl_cell_spec.c @@ -19,10 +19,8 @@ * contact@openairinterface.org */ -#ifdef USER_MODE #include #include -#endif #include "defs.h" #include "PHY/defs.h" diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_mbsfn.c b/openair1/PHY/LTE_REFSIG/lte_dl_mbsfn.c index 445c84623c..35e5fe6aff 100644 --- a/openair1/PHY/LTE_REFSIG/lte_dl_mbsfn.c +++ b/openair1/PHY/LTE_REFSIG/lte_dl_mbsfn.c @@ -21,10 +21,8 @@ // 6.10.2.2 MBSFN reference signals Mapping to resource elements -#ifdef USER_MODE #include #include -#endif #include "defs.h" #include "PHY/defs.h" diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c b/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c index ed9ff1f5cd..a7db8fd5aa 100644 --- a/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c +++ b/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c @@ -30,10 +30,8 @@ * \warning */ -#ifdef USER_MODE #include #include -#endif #include "defs.h" #include "PHY/defs.h" diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index 1bea8db59a..b74e05ab1b 100755 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -29,11 +29,9 @@ * \note * \warning */ -#ifdef USER_MODE #include #include #include -#endif #include "PHY/defs.h" #include "PHY/extern.h" #include "SCHED/defs.h" diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c index 271de54795..384c633fdc 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c @@ -801,8 +801,6 @@ int dlsch_abstraction_EESM(double* sinr_dB, uint8_t TM, uint32_t rb_alloc[4], ui bler = interp(sinr_eff,&sinr_bler_map[mcs][0][0],&sinr_bler_map[mcs][1][0],table_length[mcs]); -#ifdef USER_MODE // need to be adapted for the emulation in the kernel space - if (uniformrandom() < bler) { LOG_I(OCM,"abstraction_decoding failed (mcs=%d, sinr_eff=%f, bler=%f, TM %d)\n",mcs,sinr_eff,bler, TM); return(1); @@ -810,8 +808,6 @@ int dlsch_abstraction_EESM(double* sinr_dB, uint8_t TM, uint32_t rb_alloc[4], ui LOG_I(OCM,"abstraction_decoding successful (mcs=%d, sinr_eff=%f, bler=%f, TM %d)\n",mcs,sinr_eff,bler, TM); return(1); } - -#endif } int dlsch_abstraction_MIESM(double* sinr_dB,uint8_t TM, uint32_t rb_alloc[4], uint8_t mcs,uint8_t dl_power_off) @@ -884,8 +880,6 @@ int dlsch_abstraction_MIESM(double* sinr_dB,uint8_t TM, uint32_t rb_alloc[4], ui bler = interp(sinr_eff,&sinr_bler_map[mcs][0][0],&sinr_bler_map[mcs][1][0],table_length[mcs]); -#ifdef USER_MODE // need to be adapted for the emulation in the kernel space - if (uniformrandom() < bler) { LOG_N(OCM,"abstraction_decoding failed (mcs=%d, sinr_eff=%f, bler=%f)\n",mcs,sinr_eff,bler); return(0); @@ -893,8 +887,6 @@ int dlsch_abstraction_MIESM(double* sinr_dB,uint8_t TM, uint32_t rb_alloc[4], ui LOG_I(OCM,"abstraction_decoding successful (mcs=%d, sinr_eff=%f, bler=%f)\n",mcs,sinr_eff,bler); return(1); } - -#endif } /* diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index f53e83dbaf..1bd0076e14 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -37,11 +37,7 @@ #include "PHY/sse_intrin.h" #include "T.h" -#ifndef USER_MODE -#define NOCYGWIN_STATIC static -#else #define NOCYGWIN_STATIC -#endif /* dynamic shift for LLR computation for TM3/4 * set as command line argument, see lte-softmodem.c @@ -6027,9 +6023,6 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, //============================================================================================== -#ifdef USER_MODE - - void dump_dlsch2(PHY_VARS_UE *ue,uint8_t eNB_id,uint8_t subframe,unsigned int *coded_bits_per_codeword,int round, unsigned char harq_pid) { unsigned int nsymb = (ue->frame_parms.Ncp == 0) ? 14 : 12; @@ -6119,7 +6112,6 @@ void dump_dlsch2(PHY_VARS_UE *ue,uint8_t eNB_id,uint8_t subframe,unsigned int *c // printf("log2_maxh = %d\n",ue->pdsch_vars[eNB_id]->log2_maxh); } -#endif #ifdef DEBUG_DLSCH_DEMOD /* diff --git a/openair1/PHY/LTE_TRANSPORT/drs_modulation.c b/openair1/PHY/LTE_TRANSPORT/drs_modulation.c index 2a94d77b8e..a432cde4e4 100644 --- a/openair1/PHY/LTE_TRANSPORT/drs_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/drs_modulation.c @@ -81,7 +81,6 @@ int generate_drs_pusch(PHY_VARS_UE *ue, // cyclic_shift1 = 0; Msc_RS = 12*nb_rb; -#ifdef USER_MODE Msc_idx_ptr = (uint16_t*) bsearch(&Msc_RS, dftsizes, 33, sizeof(uint16_t), compareints); if (Msc_idx_ptr) @@ -91,20 +90,6 @@ int generate_drs_pusch(PHY_VARS_UE *ue, return(-1); } -#else - uint8_t b; - - for (b=0; b<33; b++) - if (Msc_RS==dftsizes[b]) - Msc_RS_idx = b; - -#endif -#ifdef DEBUG_DRS - printf("[PHY] drs_modulation: Msc_RS = %d, Msc_RS_idx = %d,cyclic_shift %d, u0 %d, v0 %d, u1 %d, v1 %d,cshift0 %d,cshift1 %d\n",Msc_RS, Msc_RS_idx,cyclic_shift,u0,v0,u1,v1,cyclic_shift0,cyclic_shift1); - -#endif - - for (l = (3 - frame_parms->Ncp),u=u0,v=v0,cyclic_shift=cyclic_shift0; lsymbols_per_tti; l += (7 - frame_parms->Ncp),u=u1,v=v1,cyclic_shift=cyclic_shift1) { diff --git a/openair1/PHY/LTE_TRANSPORT/edci.c b/openair1/PHY/LTE_TRANSPORT/edci.c index 49a60ae9e8..37b1c56349 100755 --- a/openair1/PHY/LTE_TRANSPORT/edci.c +++ b/openair1/PHY/LTE_TRANSPORT/edci.c @@ -29,11 +29,9 @@ * \note * \warning */ -#ifdef USER_MODE #include #include #include -#endif #include "PHY/defs.h" #include "PHY/extern.h" #include "SCHED/defs.h" diff --git a/openair1/PHY/LTE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_TRANSPORT/initial_sync.c index d1880b0c55..918696968b 100644 --- a/openair1/PHY/LTE_TRANSPORT/initial_sync.c +++ b/openair1/PHY/LTE_TRANSPORT/initial_sync.c @@ -237,10 +237,6 @@ int pbch_detection(PHY_VARS_UE *ue, runmode_t mode) ue->proc.proc_rxtx[i].frame_rx = (((ue->pbch_vars[0]->decoded_output[2]&3)<<6) + (ue->pbch_vars[0]->decoded_output[1]>>2))<<2; ue->proc.proc_rxtx[i].frame_rx = (((ue->pbch_vars[0]->decoded_output[2]&3)<<6) + (ue->pbch_vars[0]->decoded_output[1]>>2))<<2; -#ifndef USER_MODE - // one frame delay - ue->proc.proc_rxtx[i].frame_rx ++; -#endif ue->proc.proc_rxtx[i].frame_tx = ue->proc.proc_rxtx[0].frame_rx; } #ifdef DEBUG_INITIAL_SYNCH diff --git a/openair1/PHY/LTE_TRANSPORT/pbch.c b/openair1/PHY/LTE_TRANSPORT/pbch.c index e86f225157..4fbaf3f111 100644 --- a/openair1/PHY/LTE_TRANSPORT/pbch.c +++ b/openair1/PHY/LTE_TRANSPORT/pbch.c @@ -258,13 +258,11 @@ int generate_pbch(LTE_eNB_PBCH *eNB_pbch, #endif #ifdef DEBUG_PBCH - #ifdef USER_MODE write_output("pbch_encoded_output2.m","pbch_encoded_out2", pbch_coded_data2, pbch_coded_bits, 1, 4); - #endif //USER_MODE #endif //DEBUG_PBCH */ #ifdef DEBUG_PBCH_ENCODING @@ -286,8 +284,6 @@ int generate_pbch(LTE_eNB_PBCH *eNB_pbch, #ifdef DEBUG_PBCH -#ifdef USER_MODE - if (frame_mod4==0) { write_output("pbch_e.m","pbch_e", eNB_pbch->pbch_e, @@ -298,8 +294,6 @@ int generate_pbch(LTE_eNB_PBCH *eNB_pbch, for (i=0; i<16; i++) printf("e[%d] %d\n",i,eNB_pbch->pbch_e[i]); } - -#endif //USER_MODE #endif //DEBUG_PBCH // scrambling @@ -307,8 +301,6 @@ int generate_pbch(LTE_eNB_PBCH *eNB_pbch, eNB_pbch->pbch_e, pbch_E); #ifdef DEBUG_PBCH -#ifdef USER_MODE - if (frame_mod4==0) { write_output("pbch_e_s.m","pbch_e_s", eNB_pbch->pbch_e, @@ -319,8 +311,6 @@ int generate_pbch(LTE_eNB_PBCH *eNB_pbch, for (i=0; i<16; i++) printf("e_s[%d] %d\n",i,eNB_pbch->pbch_e[i]); } - -#endif //USER_MODE #endif //DEBUG_PBCH } // frame_mod4==0 diff --git a/openair1/PHY/LTE_TRANSPORT/phich.c b/openair1/PHY/LTE_TRANSPORT/phich.c index dd96910549..13d7c44f2f 100644 --- a/openair1/PHY/LTE_TRANSPORT/phich.c +++ b/openair1/PHY/LTE_TRANSPORT/phich.c @@ -38,10 +38,6 @@ #include "LAYER2/MAC/extern.h" #include "LAYER2/MAC/defs.h" -#ifndef USER_MODE -#include "ARCH/CBMIMO1/DEVICE_DRIVER/extern.h" -#endif - #include "T.h" //#define DEBUG_PHICH 1 diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c index 606900677e..56d9ce6d00 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.c +++ b/openair1/PHY/LTE_TRANSPORT/prach.c @@ -341,7 +341,6 @@ uint16_t prach_root_sequence_map4[138] = { 1,138,2,137,3,136,4,135,5,134,6,133, 61,78,62,77,63,76,64,75,65,74,66,73,67,72,68,71,69,70 }; -#ifdef USER_MODE void dump_prach_config(LTE_DL_FRAME_PARMS *frame_parms,uint8_t subframe) { @@ -362,7 +361,6 @@ void dump_prach_config(LTE_DL_FRAME_PARMS *frame_parms,uint8_t subframe) fclose(fd); } -#endif // This function computes the du void fill_du(uint8_t prach_fmt) diff --git a/openair1/PHY/LTE_TRANSPORT/srs_modulation.c b/openair1/PHY/LTE_TRANSPORT/srs_modulation.c index a360b35ff6..c4c02e6312 100644 --- a/openair1/PHY/LTE_TRANSPORT/srs_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/srs_modulation.c @@ -180,7 +180,6 @@ int32_t generate_srs(LTE_DL_FRAME_PARMS *frame_parms, return(-1); } -#ifdef USER_MODE Msc_idx_ptr = (uint16_t*) bsearch((uint16_t*) &Msc_RS, (uint16_t*) dftsizes, 33, sizeof(uint16_t), compareints); if (Msc_idx_ptr) @@ -190,19 +189,6 @@ int32_t generate_srs(LTE_DL_FRAME_PARMS *frame_parms, return(-1); } -#else //stdlib not availiable in RTAI - - if (Msc_RS==216) - Msc_RS_idx = 12; - else if (Msc_RS==144) - Msc_RS_idx = 9; - else { - LOG_E(PHY,"generate_srs: index for Msc_RS=%d not implemented\n",Msc_RS); - return(-1); - } - -#endif - #ifdef DEBUG_SRS LOG_D(PHY,"generate_srs_tx: Msc_RS = %d, Msc_RS_idx = %d, k0 = %d\n",Msc_RS, Msc_RS_idx,k0); #endif @@ -279,7 +265,6 @@ int generate_srs_rx(LTE_DL_FRAME_PARMS *frame_parms, return(-1); } -#ifdef USER_MODE Msc_idx_ptr = (uint16_t*) bsearch((uint16_t*) &Msc_RS, (uint16_t*) dftsizes, 33, sizeof(uint16_t), compareints); if (Msc_idx_ptr) @@ -289,19 +274,6 @@ int generate_srs_rx(LTE_DL_FRAME_PARMS *frame_parms, return(-1); } -#else //stdlib not availiable in RTAI - - if (Msc_RS==216) - Msc_RS_idx = 12; - else if (Msc_RS==144) - Msc_RS_idx = 9; - else { - LOG_E(PHY,"generate_srs: index for Msc_RS=%d not implemented\n",Msc_RS); - return(-1); - } - -#endif - #ifdef DEBUG_SRS LOG_I(PHY,"generate_srs_rx: Msc_RS = %d, Msc_RS_idx = %d, k0=%d\n",Msc_RS, Msc_RS_idx,k0); #endif diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index f885bf8eb3..dcf94c4826 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -1616,8 +1616,6 @@ int ulsch_abstraction(double* sinr_dB, uint8_t TM, uint8_t mcs,uint16_t nrb, uin } } -#ifdef USER_MODE // need to be adapted for the emulation in the kernel space - if (uniformrandom() < bler) { LOG_I(OCM,"abstraction_decoding failed (mcs=%d, sinr_eff=%f, bler=%f)\n",mcs,sinr_eff,bler); return(0); @@ -1625,8 +1623,6 @@ int ulsch_abstraction(double* sinr_dB, uint8_t TM, uint8_t mcs,uint16_t nrb, uin LOG_I(OCM,"abstraction_decoding successful (mcs=%d, sinr_eff=%f, bler=%f)\n",mcs,sinr_eff,bler); return(1); } - -#endif } @@ -1935,8 +1931,6 @@ int ulsch_abstraction_MIESM(double* sinr_dB,uint8_t TM, uint8_t mcs,uint16_t nrb } } -#ifdef USER_MODE // need to be adapted for the emulation in the kernel space - if (uniformrandom() < bler) { printf("abstraction_decoding failed (mcs=%d, sinr_eff=%f, bler=%f)\n",mcs,sinr_eff,bler); return(0); @@ -1944,9 +1938,6 @@ int ulsch_abstraction_MIESM(double* sinr_dB,uint8_t TM, uint8_t mcs,uint16_t nrb printf("abstraction_decoding successful (mcs=%d, sinr_eff=%f, bler=%f)\n",mcs,sinr_eff,bler); return(1); } - -#endif - } #endif diff --git a/openair1/PHY/MODULATION/ul_7_5_kHz.c b/openair1/PHY/MODULATION/ul_7_5_kHz.c index f2e43a533e..80efc70c40 100644 --- a/openair1/PHY/MODULATION/ul_7_5_kHz.c +++ b/openair1/PHY/MODULATION/ul_7_5_kHz.c @@ -23,11 +23,7 @@ #include "PHY/extern.h" #include "extern.h" #include "kHz_7_5.h" -#ifdef USER_MODE #include -#else -#include "rtai_math.h" -#endif #include "PHY/sse_intrin.h" short conjugate75[8]__attribute__((aligned(16))) = {-1,1,-1,1,-1,1,-1,1} ; diff --git a/openair1/PHY/TOOLS/Makefile b/openair1/PHY/TOOLS/Makefile index eee9d78344..59b6a1e03b 100644 --- a/openair1/PHY/TOOLS/Makefile +++ b/openair1/PHY/TOOLS/Makefile @@ -1,14 +1,14 @@ lte_dfts_sse4: lte_dfts.c - gcc -O2 -msse4.1 -g -ggdb -o lte_dfts_sse4 lte_dfts.c time_meas.c file_output.c ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR2_DIR/COMMON -DUSER_MODE -DMR_MAIN -DNB_ANTENNAS_RX=1 # -DD256STATS #-DD64STATS + gcc -O2 -msse4.1 -g -ggdb -o lte_dfts_sse4 lte_dfts.c time_meas.c file_output.c ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR2_DIR/COMMON -DMR_MAIN -DNB_ANTENNAS_RX=1 # -DD256STATS #-DD64STATS lte_dfts_avx2: lte_dfts.c - gcc -O2 -mavx2 -g -ggdb -o lte_dfts_avx2 lte_dfts.c time_meas.c file_output.c ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR2_DIR/COMMON -DUSER_MODE -DMR_MAIN -DNB_ANTENNAS_RX=1 # -DD256STATS #-DD64STATS + gcc -O2 -mavx2 -g -ggdb -o lte_dfts_avx2 lte_dfts.c time_meas.c file_output.c ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR2_DIR/COMMON -DMR_MAIN -DNB_ANTENNAS_RX=1 # -DD256STATS #-DD64STATS lte_dfts_avx2.s: lte_dfts.c - gcc -O2 -mavx2 -S lte_dfts.c time_meas.c file_output.c ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR2_DIR/COMMON -DUSER_MODE -DMR_MAIN -DNB_ANTENNAS_RX=1 # -DD256STATS #-DD64STATS + gcc -O2 -mavx2 -S lte_dfts.c time_meas.c file_output.c ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR2_DIR/COMMON -DMR_MAIN -DNB_ANTENNAS_RX=1 # -DD256STATS #-DD64STATS lte_dfts_sse4.s: lte_dfts.c - gcc -O2 -msse4.1 -S lte_dfts.c time_meas.c file_output.c ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR2_DIR/COMMON -DUSER_MODE -DMR_MAIN -DNB_ANTENNAS_RX=1 # -DD256STATS #-DD64STATS + gcc -O2 -msse4.1 -S lte_dfts.c time_meas.c file_output.c ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR2_DIR/COMMON -DMR_MAIN -DNB_ANTENNAS_RX=1 # -DD256STATS #-DD64STATS dft_cycles_avx2: lte_dfts_avx2 ./lte_dfts_avx2 | egrep cycles diff --git a/openair1/PHY/TOOLS/cmult_vv.c b/openair1/PHY/TOOLS/cmult_vv.c index b5b551f008..13facf6907 100644 --- a/openair1/PHY/TOOLS/cmult_vv.c +++ b/openair1/PHY/TOOLS/cmult_vv.c @@ -20,10 +20,7 @@ */ #include "defs.h" -//#include "MAC_INTERFACE/extern.h" -#ifdef USER_MODE #include -#endif #if defined(__x86_64__) || defined(__i386__) int16_t conjug[8]__attribute__((aligned(16))) = {-1,1,-1,1,-1,1,-1,1} ; @@ -267,4 +264,4 @@ int multadd_cpx_vector(int16_t *x1, _mm_empty(); _m_empty(); return(0); -} \ No newline at end of file +} diff --git a/openair1/PHY/TOOLS/defs.h b/openair1/PHY/TOOLS/defs.h index 41d7c9528a..5e215bfef1 100644 --- a/openair1/PHY/TOOLS/defs.h +++ b/openair1/PHY/TOOLS/defs.h @@ -286,7 +286,6 @@ void bit8_txmux(int32_t length,int32_t offset); void bit8_rxdemux(int32_t length,int32_t offset); -#ifdef USER_MODE /*!\fn int32_t write_output(const char *fname, const char *vname, void *data, int length, int dec, char format); \brief Write output file from signal data @param fname output file name @@ -297,7 +296,6 @@ void bit8_rxdemux(int32_t length,int32_t offset); @param format data format (0 = real 16-bit, 1 = complex 16-bit,2 real 32-bit, 3 complex 32-bit,4 = real 8-bit, 5 = complex 8-bit) */ int32_t write_output(const char *fname, const char *vname, void *data, int length, int dec, char format); -#endif void Zero_Buffer(void *,uint32_t); void Zero_Buffer_nommx(void *buf,uint32_t length); diff --git a/openair1/PHY/TOOLS/file_output.c b/openair1/PHY/TOOLS/file_output.c index 1a4adb04cd..1e0b31a47f 100644 --- a/openair1/PHY/TOOLS/file_output.c +++ b/openair1/PHY/TOOLS/file_output.c @@ -19,8 +19,6 @@ * contact@openairinterface.org */ -#ifdef USER_MODE - #include #include #include @@ -180,5 +178,3 @@ int write_output(const char *fname,const char *vname,void *data,int length,int d return 0; } - -#endif // USER_MODE diff --git a/openair1/PHY/TOOLS/lte_dfts.c b/openair1/PHY/TOOLS/lte_dfts.c index dc4708ce6c..e0e171f6bf 100644 --- a/openair1/PHY/TOOLS/lte_dfts.c +++ b/openair1/PHY/TOOLS/lte_dfts.c @@ -19,11 +19,9 @@ * contact@openairinterface.org */ -#ifdef USER_MODE #include #include #include -#endif #include diff --git a/openair1/PHY/types.h b/openair1/PHY/types.h index be8ec7115a..c0a9af388c 100644 --- a/openair1/PHY/types.h +++ b/openair1/PHY/types.h @@ -22,11 +22,7 @@ #ifndef __openair_TYPES_H__ #define __openair_TYPES_H__ -#ifdef USER_MODE #include -#else -#include -#endif #endif /*__openair_TYPES_H__ */ diff --git a/openair1/SCHED/extern.h b/openair1/SCHED/extern.h index 80a815dda7..98d4703be8 100644 --- a/openair1/SCHED/extern.h +++ b/openair1/SCHED/extern.h @@ -24,40 +24,6 @@ #ifndef __SCHED_EXTERN_H__ #define __SCHED_EXTERN_H__ -#ifndef USER_MODE -#define __NO_VERSION__ - - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - - - - -#ifdef RTAI_ENABLED -#include -//#include -#include -#include -#include -//#include "rt_compat.h" - -#else -#include -#endif - -#endif /* USER_MODE */ - #include "defs.h" //#include "dlc_engine.h" diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 6094f52940..1a1dcc9abd 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -68,6 +68,8 @@ fifo_dump_emos_UE emos_dump_UE; #include "T.h" +#include "PHY/TOOLS/defs.h" + #define DLSCH_RB_ALLOC 0x1fbf // skip DC RB (total 23/25 RBs) #define DLSCH_RB_ALLOC_12 0x0aaa // skip DC RB (total 23/25 RBs) diff --git a/openair1/SIMULATION/ETH_TRANSPORT/bypass_session_layer.c b/openair1/SIMULATION/ETH_TRANSPORT/bypass_session_layer.c index 01bc8f4901..b3aefbb245 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/bypass_session_layer.c +++ b/openair1/SIMULATION/ETH_TRANSPORT/bypass_session_layer.c @@ -38,10 +38,8 @@ #include "UTIL/OCG/OCG_extern.h" #include "UTIL/LOG/log.h" -#ifdef USER_MODE -# include "multicast_link.h" -# include "pgm_link.h" -#endif +#include "multicast_link.h" +#include "pgm_link.h" char rx_bufferP[BYPASS_RX_BUFFER_SIZE]; unsigned int num_bytesP = 0; @@ -90,10 +88,8 @@ void init_bypass (void) void bypass_init (tx_handler_t tx_handlerP, rx_handler_t rx_handlerP) { /***************************************************************************/ -#if defined(USER_MODE) multicast_link_start (bypass_rx_handler, oai_emulation.info.multicast_group, oai_emulation.info.multicast_ifname); -#endif //USER_MODE tx_handler = tx_handlerP; rx_handler = rx_handlerP; Master_list_rx=0; @@ -448,35 +444,6 @@ int bypass_rx_data(unsigned int frame, unsigned int last_slot, return bytes_read; } -/******************************************************************************************************/ -#ifndef USER_MODE -int bypass_rx_handler(unsigned int fifo, int rw) -{ - /******************************************************************************************************/ - int bytes_read; - int bytes_processed=0; - int header_bytes; //, elapsed_time; - //printk("[BYPASS] BYPASS_RX_HANDLER IN...\n"); - header_bytes= rtf_get(fifo_bypass_phy_user2kern, rx_bufferP, - sizeof(bypass_proto2multicast_header_t) ); - - if (header_bytes> 0) { - bytes_read = rtf_get(fifo_bypass_phy_user2kern, &rx_bufferP[header_bytes], - ((bypass_proto2multicast_header_t *) (&rx_bufferP[0]))->size); - - // printk("BYTES_READ=%d\n",bytes_read); - if (bytes_read > 0) { - num_bytesP=header_bytes+bytes_read; - emul_low_mutex_var=0; - //printk("BYPASS_PHY SIGNAL MAC_LOW...\n"); - pthread_cond_signal(&emul_low_cond); - } - } - - // } - return 0; -} -#else //USER_MODE /******************************************************************************************************/ void bypass_rx_handler(unsigned int Num_bytes,char *Rx_buffer) { @@ -503,7 +470,6 @@ void bypass_rx_handler(unsigned int Num_bytes,char *Rx_buffer) #endif } } -#endif //USER_MODE /******************************************************************************************************/ void bypass_signal_mac_phy(unsigned int frame, unsigned int last_slot, @@ -511,50 +477,12 @@ void bypass_signal_mac_phy(unsigned int frame, unsigned int last_slot, { /******************************************************************************************************/ if (Master_list_rx != oai_emulation.info.master_list) { -#ifndef USER_MODE - rtf_put(fifo_mac_bypass, &tt, 1); - /* the Rx window is still opened (Re)signal bypass_phy (emulate MAC signal) */ -#endif bypass_rx_data(frame, last_slot, next_slot, is_master); } else { Master_list_rx = 0; } } -#ifndef USER_MODE -/***************************************************************************/ -int multicast_link_write_sock (int groupP, char *dataP, unsigned int sizeP) -{ - /***************************************************************************/ - int tx_bytes=0; - - pthread_mutex_lock(&Tx_mutex); - - while(!Tx_mutex_var) { - pthread_cond_wait(&Tx_cond,&Tx_mutex); - } - - Tx_mutex_var=0; - N_P=(int)((sizeP-sizeof (bypass_proto2multicast_header_t))/1000)+2; - tx_bytes += rtf_put (fifo_bypass_phy_kern2user, &dataP[tx_bytes], - sizeof (bypass_proto2multicast_header_t)); - - while(tx_bytesmaster_id, messg->seq_num); } -#ifndef USER_MODE -/*********************************************************************************************************************/ -int bypass_tx_handler(unsigned int fifo, int rw) -{ - /***************************************************************************/ - if(++N_R==N_P) { - rtf_reset(fifo_bypass_phy_kern2user); - - Tx_mutex_var=1; - N_R=0; - - pthread_cond_signal(&Tx_cond); - } -} -#endif - diff --git a/openair1/SIMULATION/ETH_TRANSPORT/extern.h b/openair1/SIMULATION/ETH_TRANSPORT/extern.h index fafa7009f5..c01b5584e2 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/extern.h +++ b/openair1/SIMULATION/ETH_TRANSPORT/extern.h @@ -31,11 +31,7 @@ #ifndef __BYPASS_SESSION_LAYER_EXTERN_H__ # define __BYPASS_SESSION_LAYER_EXTERN_H__ -#ifndef USER_MODE -#include -#else #include -#endif //RTAI_ENABLED extern unsigned char Emulation_status; extern unsigned char emu_tx_status; diff --git a/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.c b/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.c index f32823f3bb..8750be7096 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.c +++ b/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.c @@ -54,9 +54,7 @@ #include "socket.h" #include "multicast_link.h" -#ifdef USER_MODE -# include "UTIL/LOG/log.h" -#endif //USER_MODE +#include "UTIL/LOG/log.h" extern unsigned short Master_id; diff --git a/openair1/SIMULATION/ETH_TRANSPORT/proto.h b/openair1/SIMULATION/ETH_TRANSPORT/proto.h index 6a693085c9..25b3265757 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/proto.h +++ b/openair1/SIMULATION/ETH_TRANSPORT/proto.h @@ -39,14 +39,6 @@ int bypass_rx_data(unsigned int frame, unsigned int last_slot, unsigned int next_slot, uint8_t is_master); void bypass_signal_mac_phy(unsigned int frame, unsigned int last_slot, unsigned int next_slot, uint8_t is_master); -#ifndef USER_MODE -int multicast_link_write_sock (int groupP, char *dataP, unsigned int sizeP); -int bypass_tx_handler(unsigned int fifo, int rw); -int bypass_rx_handler(unsigned int fifo, int rw); -#else -void bypass_rx_handler(unsigned int Num_bytes,char *Rx_buffer); -#endif - void bypass_tx_data (emu_transport_info_t Type, unsigned int frame, unsigned int next_slot); void emulation_tx_rx(void); diff --git a/openair1/SIMULATION/ETH_TRANSPORT/socket.c b/openair1/SIMULATION/ETH_TRANSPORT/socket.c index e288dcb378..2b28a66170 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/socket.c +++ b/openair1/SIMULATION/ETH_TRANSPORT/socket.c @@ -41,9 +41,7 @@ //#include "openair_defs.h" #include "socket.h" -#ifdef USER_MODE #define msg printf -#endif //------------------------------------------------------------------------------ void socket_setnonblocking (int sockP) diff --git a/openair1/SIMULATION/ETH_TRANSPORT/vars.h b/openair1/SIMULATION/ETH_TRANSPORT/vars.h index 0ec38a8e90..f49678642e 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/vars.h +++ b/openair1/SIMULATION/ETH_TRANSPORT/vars.h @@ -28,11 +28,7 @@ * \email: navid.nikaein@eurecom.fr */ -#ifndef USER_MODE -#include -#else #include -#endif #include "defs.h" #ifndef __BYPASS_SESSION_LAYER_VARS_H__ diff --git a/openair1/SIMULATION/LTE_PHY/Makefile b/openair1/SIMULATION/LTE_PHY/Makefile index 713bfba370..d235a01103 100644 --- a/openair1/SIMULATION/LTE_PHY/Makefile +++ b/openair1/SIMULATION/LTE_PHY/Makefile @@ -6,7 +6,7 @@ OPENAIR1_TOP = $(OPENAIR1_DIR) OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DMAX_NUM_CCs=1 -Wall -DPHYSIM -DNODE_RG -DUSER_MODE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DPHY_CONTEXT=1 -DMALLOC_CHECK_=1 -DENABLE_VCD_FIFO -DLOG_NO_THREAD # -Wno-packed-bitfield-compat +CFLAGS += -DMAX_NUM_CCs=1 -Wall -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DPHY_CONTEXT=1 -DMALLOC_CHECK_=1 -DENABLE_VCD_FIFO -DLOG_NO_THREAD # -Wno-packed-bitfield-compat # enable C99 mode CFLAGS += -std=gnu99 diff --git a/openair1/SIMULATION/RF/Makefile b/openair1/SIMULATION/RF/Makefile index 5b713b1d94..c6c03ad8d5 100644 --- a/openair1/SIMULATION/RF/Makefile +++ b/openair1/SIMULATION/RF/Makefile @@ -1,6 +1,6 @@ include $(OPENAIR_DIR)/common/utils/Makefile.inc OBJS = rf.o ../../PHY/TOOLS/file_output.o ../TOOLS/rangen_double.o -CFLAGS += -DRF_MAIN -DUSER_MODE -DDEBUG_PHY +CFLAGS += -DRF_MAIN -DDEBUG_PHY all: $(OBJS) gcc -o rf $(OBJS) -lm diff --git a/openair1/SIMULATION/TOOLS/rangen_double.c b/openair1/SIMULATION/TOOLS/rangen_double.c index 5168a64ef4..0fc01a8d31 100644 --- a/openair1/SIMULATION/TOOLS/rangen_double.c +++ b/openair1/SIMULATION/TOOLS/rangen_double.c @@ -19,12 +19,10 @@ * contact@openairinterface.org */ -#ifdef USER_MODE #include #include #include #include -#endif #include "defs.h" diff --git a/openair1/SIMULATION/TOOLS/taus.c b/openair1/SIMULATION/TOOLS/taus.c index a86be23aec..8b5ad7dfaf 100644 --- a/openair1/SIMULATION/TOOLS/taus.c +++ b/openair1/SIMULATION/TOOLS/taus.c @@ -19,13 +19,8 @@ * contact@openairinterface.org */ -#ifdef USER_MODE #include #include -#else -#include -#include -#endif #ifdef RTAI_ENABLED #include #include @@ -55,21 +50,14 @@ unsigned int taus(void) void set_taus_seed(unsigned int seed_init) { -#ifdef USER_MODE struct drand48_data buffer; unsigned long result = 0; -#endif if (seed_init == 0) { s0 = (unsigned int)time(NULL); s1 = (unsigned int)time(NULL); s2 = (unsigned int)time(NULL); } else { -#ifndef USER_MODE - s0 = (unsigned int)0x1e23d852; - s1 = (unsigned int)0x81f38a1c; - s2 = (unsigned int)0xfe1a133e; -#else /* Use reentrant version of rand48 to ensure that no conflicts with other generators occur */ srand48_r((long int)seed_init, &buffer); mrand48_r(&buffer, (long int *)&result); @@ -78,7 +66,6 @@ void set_taus_seed(unsigned int seed_init) s1 = result; mrand48_r(&buffer, (long int *)&result); s2 = result; -#endif } } #endif @@ -87,10 +74,8 @@ void set_taus_seed(unsigned int seed_init) void set_taus_seed(unsigned int seed_init) { -#ifdef USER_MODE struct drand48_data buffer; unsigned long result = 0; -#endif s0 = (unsigned int)0x1e23d852; s1 = (unsigned int)0x81f38a1c; s2 = (unsigned int)0xfe1a133e; @@ -102,11 +87,6 @@ void set_taus_seed(unsigned int seed_init) s1 = (unsigned int)time(NULL); s2 = (unsigned int)time(NULL); } else { -#ifndef USER_MODE - s0 = (unsigned int)0x1e23d852; - s1 = (unsigned int)0x81f38a1c; - s2 = (unsigned int)0xfe1a133e; -#else // Use reentrant version of rand48 to ensure that no conflicts with other generators occur */ srand48_r((long int)seed_init, &buffer); mrand48_r(&buffer, (long int *)&result); @@ -115,7 +95,6 @@ void set_taus_seed(unsigned int seed_init) s1 = result; mrand48_r(&buffer, (long int *)&result); s2 = result; -#endif } } #endif diff --git a/openair2/COMMON/openair_defs.h b/openair2/COMMON/openair_defs.h index 908f8f9813..4d8d50606c 100644 --- a/openair2/COMMON/openair_defs.h +++ b/openair2/COMMON/openair_defs.h @@ -22,12 +22,6 @@ #ifndef __openair_DEFS_H__ #define __openair_DEFS_H__ -#ifndef USER_MODE -#include -#endif //USER_MODE - - -#ifdef USER_MODE #include #include #if !defined (msg) @@ -49,44 +43,7 @@ #define PAGE_MASK 0xfffff000 #define virt_to_phys(x) (x) -#else // USER_MODE -#include -#define msg rt_printk - -#ifdef BIGPHYSAREA - -#define bigmalloc(x) (bigphys_malloc(x)) -#define bigmalloc16(x) (bigphys_malloc(x)) - -#define malloc16(x) (bigphys_malloc(x)) -#define free16(y,x) - -#define bigfree(y,x) - -#else // BIGPHYSAREA - -#define bigmalloc(x) (dma_alloc_coherent(pdev[0],(x),&dummy_dma_ptr,0)) -#define bigmalloc16(x) (dma_alloc_coherent(pdev[0],(x),&dummy_dma_ptr,0)) -#define bigfree(y,x) (dma_free_coherent(pdev[0],(x),(void *)(y),dummy_dma_ptr)) -#define malloc16(x) (kmalloc(x,GFP_KERNEL)) -#define free16(y,x) (kfree(y)) - -#endif // BIGPHYSAREA - - -#ifdef CBMIMO1 -#define openair_get_mbox() (*(unsigned int *)mbox) -#else //CBMIMO1 -#define openair_get_mbox() (*(unsigned int *)PHY_vars->mbox>>1) -#endif //CBMIMO1 - - -#endif // USERMODE - -// #define bzero(s,n) (memset((s),0,(n))) - #define cmax(a,b) ((a>b) ? (a) : (b)) #define cmin(a,b) ((a -//typedef int8_t s8; /* 8 bit signed integer */ -//typedef int16_t s16; /* 16 bit signed integer */ -//typedef int32_t s32; /* 32 bit signed integer */ -//typedef int64_t s64; /* 64 bit signed integer */ - -//typedef uint8_t u8; /* 8 bit unsigned integer */ -//typedef uint16_t u16; /* 16 bit unsigned integer */ -//typedef uint32_t u32; /* 32 bit unsigned integer */ -//typedef uint64_t u64; /* 64 bit unsigned integer */ -//#else -//#include -//#endif #endif /*__openair_TYPES_H__ */ diff --git a/openair2/COMMON/platform_constants.h b/openair2/COMMON/platform_constants.h index 533c5eaa2b..f4004bdbf9 100644 --- a/openair2/COMMON/platform_constants.h +++ b/openair2/COMMON/platform_constants.h @@ -43,7 +43,6 @@ #define NL_MAX_PAYLOAD 9000 /* this should cover the max mtu size*/ #endif -#ifdef USER_MODE #ifdef LARGE_SCALE # define NB_MODULES_MAX 128 # define NB_NODE_MAX 128 @@ -51,11 +50,6 @@ # define NB_MODULES_MAX 32 # define NB_NODE_MAX 32 #endif -#else -# define NB_MODULES_MAX 1 -# define NB_NODE_MAX 1 -#endif //PHY_EMUL - #ifdef JUMBO_FRAME # define MAX_IP_PACKET_SIZE 10000 // 9000 @@ -132,9 +126,7 @@ #define UNUSED_PARAM_MBMS_SESSION_ID 0 #define UNUSED_PARAM_MBMS_SERVICE_ID 0 -#ifdef USER_MODE #define printk printf -#endif #define UNUSED_VARIABLE(vARIABLE) (void)(vARIABLE) diff --git a/openair2/COMMON/platform_types.h b/openair2/COMMON/platform_types.h index 3997d579bd..c0ee976fdd 100644 --- a/openair2/COMMON/platform_types.h +++ b/openair2/COMMON/platform_types.h @@ -30,9 +30,7 @@ #ifndef __PLATFORM_TYPES_H__ # define __PLATFORM_TYPES_H__ -#ifdef USER_MODE #include -#endif #if defined(ENABLE_ITTI) #include "itti_types.h" diff --git a/openair2/COMMON/rtos_header.h b/openair2/COMMON/rtos_header.h index 63bc57d942..2ba3534d7e 100644 --- a/openair2/COMMON/rtos_header.h +++ b/openair2/COMMON/rtos_header.h @@ -21,44 +21,12 @@ #ifndef _RTOS_HEADER_H_ # define _RTOS_HEADER_H_ -# if defined(RTAI) && !defined(USER_MODE) -// CONVERSION BETWEEN POSIX PTHREAD AND RTAI FUNCTIONS -/* -# define pthread_mutex_init pthread_mutex_init_rt -# define pthread_mutexattr_init pthread_mutexattr_init_rt -# define pthread_mutex_lock pthread_mutex_lock_rt -# define pthread_mutex_unlock pthread_mutex_unlock_rt -# define pthread_mutex_destroy pthread_mutex_destroy_rt -# define pthread_cond_init pthread_cond_init_rt -# define pthread_cond_wait pthread_cond_wait_rt -# define pthread_cond_signal pthread_cond_signal_rt -# define pthread_cond_destroy pthread_cond_destroy_rt -# define pthread_attr_init pthread_attr_init_rt -# define pthread_attr_setschedparam pthread_attr_setschedparam_rt -# define pthread_create pthread_create_rt -# define pthread_cancel pthread_cancel_rt -# define pthread_delete_np pthread_cancel_rt -# define pthread_attr_setstacksize pthread_attr_setstacksize_rt -# define pthread_self rt_whoami -*/ -# include -# include -# include -# include -# include -# ifdef CONFIG_PROC_FS -# include -# endif -# else -# ifdef USER_MODE -# include -# include -# include -# include -# include -# include -# define rtf_get read -# define rtf_put write -# endif -# endif +# include +# include +# include +# include +# include +# include +# define rtf_get read +# define rtf_put write #endif diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 43d8167fe6..638a7a4b56 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -39,15 +39,9 @@ -#ifdef USER_MODE #include #include #include -#endif - -//#include "COMMON/openair_defs.h" - - #include "PHY/defs.h" #include "PHY/LTE_TRANSPORT/defs.h" @@ -109,9 +103,7 @@ //#define MCH_PAYLOAD_SIZE_MAX 16384// this value is using in case mcs and TBS index are high #endif -#ifdef USER_MODE #define printk printf -#endif //USER_MODE /*!\brief Maximum number of logical channl group IDs */ #define MAX_NUM_LCGID 4 diff --git a/openair2/LAYER2/MAC/extern.h b/openair2/LAYER2/MAC/extern.h index 50ea5634b9..e9d7a5997d 100644 --- a/openair2/LAYER2/MAC/extern.h +++ b/openair2/LAYER2/MAC/extern.h @@ -32,10 +32,6 @@ #ifndef __MAC_EXTERN_H__ #define __MAC_EXTERN_H__ - -#ifdef USER_MODE -//#include "stdio.h" -#endif //USER_MODE #include "PHY/defs.h" #include "defs.h" diff --git a/openair2/LAYER2/MAC/main.c b/openair2/LAYER2/MAC/main.c index 534f603dfd..0bfad4e5b1 100644 --- a/openair2/LAYER2/MAC/main.c +++ b/openair2/LAYER2/MAC/main.c @@ -247,10 +247,6 @@ int rlcmac_init_global_param(void) void mac_top_cleanup(void) { -#ifndef USER_MODE - pdcp_module_cleanup(); -#endif - if (NB_UE_INST > 0) { free(UE_mac_inst); } diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 23d3f3bd60..ff8939d82b 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -59,12 +59,6 @@ //#define ICIC 0 -/* - #ifndef USER_MODE - #define msg debug_msg - #endif -*/ - /* this function checks that get_eNB_UE_stats returns * a non-NULL pointer for all the active CCs of an UE */ diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 5b73a76312..7a9b811d0e 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -71,11 +71,6 @@ extern uint8_t usim_test; -/* -#ifndef USER_MODE -#define msg debug_msg -#endif - */ mapping BSR_names[] = { {"NONE", 0}, {"SHORT BSR", 1}, diff --git a/openair2/LAYER2/MAC/vars.h b/openair2/LAYER2/MAC/vars.h index 2386088161..d153c82aee 100644 --- a/openair2/LAYER2/MAC/vars.h +++ b/openair2/LAYER2/MAC/vars.h @@ -32,9 +32,6 @@ #ifndef __MAC_VARS_H__ #define __MAC_VARS_H__ -#ifdef USER_MODE -//#include "stdio.h" -#endif //USER_MODE #include "PHY/defs.h" #include "defs.h" #include "COMMON/mac_rrc_primitives.h" diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index b362e8887a..8bb04c37b8 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -30,9 +30,6 @@ #define PDCP_C //#define DEBUG_PDCP_FIFO_FLUSH_SDU -#ifndef USER_MODE -#include -#endif #include "assertions.h" #include "hashtable.h" #include "pdcp.h" @@ -691,7 +688,7 @@ pdcp_data_ind( payload_offset=0; } -#if defined(USER_MODE) && defined(OAI_EMU) +#if defined(OAI_EMU) if (oai_emulation.info.otg_enabled == 1) { //unsigned int dst_instance; @@ -983,7 +980,7 @@ pdcp_run ( # endif #endif -#if defined(USER_MODE) && defined(OAI_EMU) +#if defined(OAI_EMU) pdcp_fifo_read_input_sdus_from_otg(ctxt_pP); #endif diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index 6dffada99d..c19adb6753 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -40,7 +40,6 @@ extern int otg_enabled; #include "pdcp.h" #include "pdcp_primitives.h" -#ifdef USER_MODE #include #include #include @@ -48,9 +47,6 @@ extern int otg_enabled; #include #define rtf_put write #define rtf_get read -#else -#include -#endif //USER_MODE #include "../MAC/extern.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" @@ -808,7 +804,7 @@ void pdcp_fifo_read_input_sdus_from_otg (const protocol_ctxt_t* const ctxt_pP) module_id_t dst_id; // dst for otg rb_id_t rb_id; unsigned int pkt_size=0; -#if defined(USER_MODE) && defined(OAI_EMU) +#if defined(OAI_EMU) module_id_t src_id; static unsigned int pkt_cnt_enb=0, pkt_cnt_ue=0; @@ -818,7 +814,7 @@ void pdcp_fifo_read_input_sdus_from_otg (const protocol_ctxt_t* const ctxt_pP) #endif protocol_ctxt_t ctxt; // we need to add conditions to avoid transmitting data when the UE is not RRC connected. -#if defined(USER_MODE) && defined(OAI_EMU) +#if defined(OAI_EMU) if (oai_emulation.info.otg_enabled ==1 ) { // module_id is source id diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c index eddd42c34b..e0a0c062d7 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c @@ -101,7 +101,7 @@ pdcp_netlink_init( struct sched_param sched_param; reset_meas(&ip_pdcp_stats_tmp); -#if defined(USER_MODE) && defined(OAI_EMU) +#if defined(OAI_EMU) nb_inst_enb = oai_emulation.info.nb_enb_local; nb_inst_ue = oai_emulation.info.nb_ue_local; #else diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h index 131d56e1f8..5130bde38b 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h @@ -73,10 +73,6 @@ # include "RLC-Config.h" //# include "rlc_am_test.h" -#ifdef USER_MODE -//# include "rlc_am_very_simple_test.h" -#endif - #define PROTOCOL_RLC_AM_CTXT_FMT PROTOCOL_CTXT_FMT"[%s %02u]" #define PROTOCOL_RLC_AM_CTXT_ARGS(CTXT_Pp, rLC_Pp) PROTOCOL_CTXT_ARGS(CTXT_Pp),\ diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c index f6dd0c5809..01a635656e 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c @@ -21,9 +21,7 @@ #define RLC_AM_MODULE 1 #define RLC_AM_INIT_C 1 -#ifdef USER_MODE #include -#endif //----------------------------------------------------------------------------- #include "rlc_am.h" #include "LAYER2/MAC/extern.h" diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c index addc949d35..d0b5b52395 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c @@ -268,11 +268,9 @@ rlc_am_reassemble_pdu( //} break; -#if USER_MODE default: assert(0 != 0); -#endif } } else { switch (pdu_info->fi) { @@ -382,19 +380,13 @@ rlc_am_reassemble_pdu( if (pdu_info->hidden_size > 0) { // normally should always be > 0 but just for help debug // data is already ok, done by last loop above rlc_am_reassembly (ctxt_pP, rlc_pP, &pdu_info->payload[j], pdu_info->hidden_size); - } else { -#if USER_MODE - //assert (5!=5); -#endif } //rlc_pP->reassembly_missing_sn_detected = 0; break; -#if USER_MODE default: assert(1 != 1); -#endif } } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c index afce72b455..c16e897bb6 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c @@ -22,9 +22,7 @@ #define RLC_AM_MODULE 1 #define RLC_AM_SEGMENT_C 1 //----------------------------------------------------------------------------- -#if USER_MODE #include -#endif //----------------------------------------------------------------------------- #include "platform_types.h" //----------------------------------------------------------------------------- @@ -468,9 +466,7 @@ void rlc_am_segment_10 ( PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), sdu_mngt_p->sdu_remaining_size, pdu_remaining_size - sdu_mngt_p->sdu_remaining_size); -#if USER_MODE assert(1!=1); -#endif memcpy(data, data_sdu_p, sdu_mngt_p->sdu_remaining_size); pdu_mngt_p->payload_size += sdu_mngt_p->sdu_remaining_size; pdu_remaining_size = pdu_remaining_size - sdu_mngt_p->sdu_remaining_size; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h index a6c340a165..147fd44d07 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h @@ -36,9 +36,7 @@ # include "list.h" # include "mem_block.h" # include "rlc_am_constants.h" -//#ifdef USER_MODE # include "mac_rlc_primitives.h" -//#endif //USER_MODE # include "mac_primitives.h" # include "rlc_primitives.h" /** diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_windows.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_windows.c index f0cacc2874..7a3005334e 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_windows.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_windows.c @@ -22,9 +22,7 @@ #define RLC_AM_MODULE 1 #define RLC_AM_WINDOWS_C 1 //----------------------------------------------------------------------------- -#if USER_MODE #include -#endif //----------------------------------------------------------------------------- #include "platform_types.h" //----------------------------------------------------------------------------- diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c index 2e1629f8c8..7bd0da83a9 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c @@ -682,10 +682,6 @@ rlc_um_data_req (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP, mem_block_t { rlc_um_entity_t *rlc_p = (rlc_um_entity_t *) rlc_pP; -#if ! USER_MODE - unsigned long int rlc_um_time_us; - int min, sec, usec; -#endif #if TRACE_RLC_UM_PDU #if ENABLE_ITTI MessageDef *msg_p; diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h index c7754f587a..abf4f8ad6e 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h @@ -64,9 +64,6 @@ # include "rlc_um_receiver.h" # include "rlc_um_segment.h" # include "rlc_um_test.h" -#ifdef USER_MODE -//# include "rlc_um_very_simple_test.h" -#endif #define PROTOCOL_RLC_UM_CTXT_FMT PROTOCOL_CTXT_FMT"[%s %02u] %s()" #define PROTOCOL_RLC_UM_CTXT_ARGS(CTXT_Pp, rLC_Pp) PROTOCOL_CTXT_ARGS(CTXT_Pp),\ diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.c index 468a7d062a..91e1ba66d1 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_reassembly.c @@ -23,9 +23,7 @@ #define RLC_UM_REASSEMBLY_C 1 #include "platform_types.h" //----------------------------------------------------------------------------- -#if USER_MODE #include -#endif #if ENABLE_ITTI # include "platform_types.h" # include "intertask_interface.h" diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c index 4d4362251e..f9af7c1cc2 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c @@ -25,9 +25,7 @@ #include "platform_types.h" #include "platform_constants.h" //----------------------------------------------------------------------------- -#if USER_MODE #include -#endif #include "assertions.h" #include "msc.h" #include "list.h" @@ -367,10 +365,8 @@ rlc_um_segment_10 (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t *rlc_pP sdu_mngt_p->sdu_remaining_size, pdu_remaining_size - sdu_mngt_p->sdu_remaining_size); #endif -#if USER_MODE #if !EXMIMO assert(1!=1); -#endif #endif memcpy(data, data_sdu_p, sdu_mngt_p->sdu_remaining_size); // reduce the size of the PDU @@ -754,9 +750,7 @@ rlc_um_segment_5 (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t *rlc_pP) sdu_mngt_p->sdu_remaining_size, pdu_remaining_size - sdu_mngt_p->sdu_remaining_size); #endif -#if USER_MODE assert(1!=1); -#endif memcpy(data, data_sdu_p, sdu_mngt_p->sdu_remaining_size); // reduce the size of the PDU continue_fill_pdu_with_sdu = 0; diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_structs.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_structs.h index a5425cb8a0..7ab9798a38 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_structs.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_structs.h @@ -36,9 +36,7 @@ # include "rlc_um_constants.h" # include "mac_primitives.h" # include "rlc_primitives.h" -//#ifdef USER_MODE # include "mac_rlc_primitives.h" -//#endif //USER_MODE //----------------------- /** * @addtogroup _rlc_um_impl_ diff --git a/openair2/LAYER2/RLC/rlc.h b/openair2/LAYER2/RLC/rlc.h index fca786b4d3..ffd963204e 100644 --- a/openair2/LAYER2/RLC/rlc.h +++ b/openair2/LAYER2/RLC/rlc.h @@ -662,10 +662,6 @@ public_rlc(rlc_op_status_t rlc_stat_req ( public_rlc(int rlc_module_init(void);) /** @} */ -#ifndef USER_MODE -#define assert(x) ((x)?msg("rlc assertion fails\n"):0) -#endif - #define RLC_FG_COLOR_BLACK "\e[0;30m" #define RLC_FG_COLOR_RED "\e[0;31m" diff --git a/openair2/LAYER2/RLC/rlc_primitives.h b/openair2/LAYER2/RLC/rlc_primitives.h index 8d679ab9aa..eb7b9ae005 100644 --- a/openair2/LAYER2/RLC/rlc_primitives.h +++ b/openair2/LAYER2/RLC/rlc_primitives.h @@ -31,10 +31,8 @@ #ifndef __RLC_PRIMITIVES_H__ # define __RLC_PRIMITIVES_H__ -# ifdef USER_MODE -# include -# include -# endif +# include +# include # include "platform_types.h" # include "platform_constants.h" # include "mem_block.h" diff --git a/openair2/LAYER2/openair2_proc.c b/openair2/LAYER2/openair2_proc.c index 7801279be2..c4cac46141 100644 --- a/openair2/LAYER2/openair2_proc.c +++ b/openair2/LAYER2/openair2_proc.c @@ -29,21 +29,7 @@ # @ingroup _openair2 */ -#ifdef USER_MODE -# include -#else -#include -#include -#include - -# ifndef PRIu64 -# if __WORDSIZE == 64 -# define PRIu64 "lu" -# else -# define PRIu64 "llu" -# endif -# endif -#endif +#include #include "LAYER2/RLC/rlc.h" #include "LAYER2/MAC/defs.h" @@ -404,11 +390,7 @@ int dump_eNB_l2_stats(char *buffer, int length) } #ifdef PROC -#ifndef USER_MODE -static int openair2_stats_read(char *buffer, char **my_buffer, off_t off, int length) -#else int openair2_stats_read(char *buffer, char **my_buffer, off_t off, int length) -#endif { int len = 0,fg,Overhead, Sign; @@ -691,36 +673,4 @@ int openair2_stats_read(char *buffer, char **my_buffer, off_t off, int length) return len; } -#ifndef USER_MODE -static struct proc_dir_entry *proc_openair2_root; -/* - * Initialize the module and add the /proc file. - */ -int add_openair2_stats() -{ - struct proc_dir_entry *pde; - - proc_openair2_root = proc_mkdir("openair2",0); - // pde = proc_create_entry("lchan_stats", S_IFREG | S_IRUGO, proc_openair2_root); - pde = proc_create_data("lchan_stats", S_IFREG | S_IRUGO, proc_openair2_root, NULL,openair2_stats_read); - - if (!pde) { - printk("[OPENAIR][ERROR] can't create proc entry !\n"); - } - - return 0; -} -/* - * Unregister the file when the module is closed. - */ -void remove_openair_stats() -{ - - if (proc_openair2_root) { - printk("[OPENAIR][CLEANUP] Removing openair proc entry\n"); - remove_proc_entry("lchan_stats", proc_openair2_root); - - } -} -#endif #endif diff --git a/openair2/LAYER2/register.c b/openair2/LAYER2/register.c index 964666875a..6d869a9508 100644 --- a/openair2/LAYER2/register.c +++ b/openair2/LAYER2/register.c @@ -27,55 +27,15 @@ ________________________________________________________________*/ -#ifndef USER_MODE -#define __NO_VERSION__ -#else #include #include #include -#endif #include "COMMON/openair_types.h" #include "MAC/extern.h" #include -#ifndef USER_MODE - -//-----------------------------------------------------------------------------------------------------------// -MAC_RLC_XFACE* mac_rrc_register(RRC_XFACE* RRC_xface) -{ - //-----------------------------------------------------------------------------------------------------------// - if(Is_rrc_registered) { - msg("[OPENAIR][MAC][RRC_REGISTER] RRC interface already registered, aborting ...\n"); - return NULL; - } else { - msg("[OPENAIR][MAC][RRC_REGISTER] Registering RRC Interface, Mac_rlc_xface=%p\n",Mac_rlc_xface); - Rrc_xface=RRC_xface; - Is_rrc_registered=1; - return Mac_rlc_xface; - } -} - -//-----------------------------------------------------------------------------------------------------------// -int mac_rrc_unregister(RRC_XFACE *RRC_xface) -{ - //-----------------------------------------------------------------------------------------------------------// - if (Rrc_xface == RRC_xface) { - msg("[OPENAIR][MAC XFACE][RRC_UNREGISTER] Unregistering RRC interface\n"); - Rrc_xface=NULL; - Is_rrc_registered=0; - return(0); - } else { - msg("[OPENAIR][MAC XFACE][RRC_UNREGISTER] Not the right interface descriptor pointer!!!, aborting ...\n"); - return (-1); - } - -} - -EXPORT_SYMBOL(mac_rrc_register); -EXPORT_SYMBOL(mac_rrc_unregister); -#endif //USER_MODE diff --git a/openair2/NAS/SIMU_CELLULAR/Makefile b/openair2/NAS/SIMU_CELLULAR/Makefile index 26af978a4e..12070071a6 100755 --- a/openair2/NAS/SIMU_CELLULAR/Makefile +++ b/openair2/NAS/SIMU_CELLULAR/Makefile @@ -19,8 +19,8 @@ ASN1_DIR = $(OPENAIR2_DIR) #GRAAL_DIR =$(UPDIR)/non_access_stratum/driver/nasmt #RRC_DIR =$(UPDIR)/access_stratum/l3/rrc -#CFLAGS += -Wall -g -DDEBUG_RRC_STATE -DUSER_MODE -DNODE_RG -DNODE_MT -CFLAGS += -std=gnu99 -I$(KERNEL_DIR) -DUSER_MODE -DNB_ANTENNAS_RX=1 +#CFLAGS += -Wall -g -DDEBUG_RRC_STATE -DNODE_RG -DNODE_MT +CFLAGS += -std=gnu99 -I$(KERNEL_DIR) -DNB_ANTENNAS_RX=1 ifdef CELL_RRM CFLAGS += -DNODE_RG diff --git a/openair2/PHY_INTERFACE/mac_phy_primitives.c b/openair2/PHY_INTERFACE/mac_phy_primitives.c index 3d42393d11..06e06d096d 100644 --- a/openair2/PHY_INTERFACE/mac_phy_primitives.c +++ b/openair2/PHY_INTERFACE/mac_phy_primitives.c @@ -187,9 +187,6 @@ MACPHY_DATA_REQ *new_macphy_data_req(unsigned char Mod_id) return((MACPHY_DATA_REQ*)0); } -#ifndef USER_MODE -EXPORT_SYMBOL(new_macphy_data_req); -#endif #endif //PHY_CONTEXT @@ -262,13 +259,7 @@ void macphy_data_ind(unsigned char Mod_id,unsigned char Pdu_type,void *pdu,unsig } } msg("[OPENAIR][MAC][ERROR] No more PHY_RESOURCES !!!!\n"); -#ifdef USER_MODE exit(-1); -#else - print_active_indications(); - print_active_requests(); - mac_xface->macphy_exit(); -#endif } */ diff --git a/openair2/PHY_INTERFACE/vars.h b/openair2/PHY_INTERFACE/vars.h index 736d6f89db..566f4347b6 100644 --- a/openair2/PHY_INTERFACE/vars.h +++ b/openair2/PHY_INTERFACE/vars.h @@ -42,7 +42,3 @@ unsigned int mac_registered; #endif -#ifndef USER_MODE -EXPORT_SYMBOL(mac_xface); -#endif //PHY_EMUL - diff --git a/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.c b/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.c index 8d69b6e76b..0844593d93 100644 --- a/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.c +++ b/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.c @@ -28,45 +28,10 @@ * \email: navid.nikaein@eurecom.fr */ -#ifdef USER_MODE #include #include #include -#else //USER_MODE - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - - -#ifdef KERNEL2_6 - -#include -#endif - -#ifdef KERNEL2_4 -#include -#include -#endif -#endif //USER_MODE - #include "platform_types.h" #include "openair_defs.h" diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index a05b27ddc3..b1035cf33c 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -28,7 +28,6 @@ * \email: raymond.knopp@eurecom.fr and navid.nikaein@eurecom.fr */ -#ifdef USER_MODE #include #include #include /* for atoi(3) */ @@ -36,14 +35,7 @@ #include /* for strerror(3) */ #include /* for EX_* exit codes */ #include /* for errno */ -#else -#include /* Needed by all modules */ -#endif -#ifdef USER_MODE -//#include "RRC/LITE/defs.h" -//#include "COMMON/mac_rrc_primitives.h" #include "UTIL/LOG/log.h" -#endif #include #include /* for _ASN_DEFAULT_STACK_MAX */ #include @@ -90,16 +82,8 @@ #include "common/ran_context.h" -//#include "PHY/defs.h" -#ifndef USER_MODE -#define msg printk -#ifndef errno -int errno; -#endif -#else -# if !defined (msg) -# define msg printf -# endif +#if !defined (msg) +#define msg printf #endif //#define XER_PRINT @@ -483,9 +467,7 @@ uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier, # endif #endif -#ifdef USER_MODE LOG_D(RRC,"[eNB] SystemInformationBlockType1 Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif if (enc_rval.encoded==-1) { return(-1); @@ -1013,9 +995,7 @@ uint8_t do_SIB23(uint8_t Mod_id, # endif #endif -#ifdef USER_MODE LOG_D(RRC,"[eNB] SystemInformation Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif if (enc_rval.encoded==-1) { msg("[RRC] ASN1 : SI encoding failed for SIB23\n"); @@ -1102,9 +1082,7 @@ uint8_t do_RRCConnectionRequest(uint8_t Mod_id, uint8_t *buffer,uint8_t *rv) # endif #endif -#ifdef USER_MODE LOG_D(RRC,"[UE] RRCConnectionRequest Encoded %zd bits (%zd bytes), ecause %d\n",enc_rval.encoded,(enc_rval.encoded+7)/8,ecause); -#endif return((enc_rval.encoded+7)/8); @@ -1185,9 +1163,7 @@ uint8_t do_RRCConnectionSetupComplete(uint8_t Mod_id, uint8_t *buffer, const uin # endif #endif -#ifdef USER_MODE LOG_D(RRC,"RRCConnectionSetupComplete Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif return((enc_rval.encoded+7)/8); @@ -1247,9 +1223,7 @@ do_RRCConnectionReconfigurationComplete( # endif #endif -#ifdef USER_MODE LOG_D(RRC,"RRCConnectionReconfigurationComplete Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif return((enc_rval.encoded+7)/8); } @@ -1636,10 +1610,8 @@ do_RRCConnectionSetup( # endif #endif -#ifdef USER_MODE LOG_D(RRC,"RRCConnectionSetup Encoded %zd bits (%zd bytes), ecause %d\n", enc_rval.encoded,(enc_rval.encoded+7)/8,ecause); -#endif // FREEMEM(SRB_list); // free(SRB1_config); @@ -1709,13 +1681,11 @@ do_SecurityModeCommand( # endif #endif -#ifdef USER_MODE LOG_D(RRC,"[eNB %d] securityModeCommand for UE %x Encoded %zd bits (%zd bytes)\n", ctxt_pP->module_id, ctxt_pP->rnti, enc_rval.encoded, (enc_rval.encoded+7)/8); -#endif if (enc_rval.encoded==-1) { LOG_E(RRC,"[eNB %d] ASN1 : securityModeCommand encoding failed for UE %x\n", @@ -1787,13 +1757,11 @@ do_UECapabilityEnquiry( # endif #endif -#ifdef USER_MODE LOG_D(RRC,"[eNB %d] UECapabilityRequest for UE %x Encoded %zd bits (%zd bytes)\n", ctxt_pP->module_id, ctxt_pP->rnti, enc_rval.encoded, (enc_rval.encoded+7)/8); -#endif if (enc_rval.encoded==-1) { LOG_E(RRC,"[eNB %d] ASN1 : UECapabilityRequest encoding failed for UE %x\n", @@ -1953,13 +1921,11 @@ do_RRCConnectionReconfiguration( # endif #endif - //#ifdef USER_MODE LOG_I(RRC,"RRCConnectionReconfiguration Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); // for (i=0;i<30;i++) // msg("%x.",buffer[i]); // msg("\n"); - //#endif return((enc_rval.encoded+7)/8); } @@ -2014,10 +1980,8 @@ do_RRCConnectionReestablishmentReject( # endif #endif -#ifdef USER_MODE LOG_D(RRC,"RRCConnectionReestablishmentReject Encoded %zd bits (%zd bytes)\n", enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif return((enc_rval.encoded+7)/8); } @@ -2075,10 +2039,8 @@ do_RRCConnectionReject( # endif #endif -#ifdef USER_MODE LOG_D(RRC,"RRCConnectionReject Encoded %zd bits (%zd bytes)\n", enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif return((enc_rval.encoded+7)/8); } @@ -2266,9 +2228,7 @@ uint8_t do_MBSFNAreaConfig(uint8_t Mod_id, # endif #endif -#ifdef USER_MODE LOG_D(RRC,"[eNB] MCCH Message Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif if (enc_rval.encoded==-1) { msg("[RRC] ASN1 : MCCH encoding failed for MBSFNAreaConfiguration\n"); @@ -2400,9 +2360,7 @@ uint8_t do_MeasurementReport(uint8_t Mod_id, uint8_t *buffer,int measid,int phy_ # endif #endif -#ifdef USER_MODE printf("Measurement Report Encoded %zu bits (%zu bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif return((enc_rval.encoded+7)/8); } diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.h b/openair2/RRC/LITE/MESSAGES/asn1_msg.h index 6241e2963f..af11f18b94 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.h +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.h @@ -28,7 +28,6 @@ * \email: raymond.knopp@eurecom.fr and navid.nikaein@eurecom.fr */ -#ifdef USER_MODE #include #include #include /* for atoi(3) */ @@ -36,9 +35,6 @@ #include /* for strerror(3) */ #include /* for EX_* exit codes */ #include /* for errno */ -#else -#include /* Needed by all modules */ -#endif #include #include /* for _ASN_DEFAULT_STACK_MAX */ diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index 9d7f7fdf2d..df306105d3 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -31,11 +31,9 @@ #ifndef __OPENAIR_RRC_DEFS_H__ #define __OPENAIR_RRC_DEFS_H__ -#ifdef USER_MODE #include #include #include -#endif #include "collection/tree.h" #include "rrc_types.h" @@ -47,11 +45,6 @@ #include "LAYER2/MAC/defs.h" -//#include "COMMON/openair_defs.h" -#ifndef USER_MODE -#include -#endif - #include "SystemInformationBlockType1.h" #include "SystemInformation.h" #include "RRCConnectionReconfiguration.h" diff --git a/openair2/RRC/LITE/mesh_top.c b/openair2/RRC/LITE/mesh_top.c index 16395e99c6..a2b4e0f7d0 100644 --- a/openair2/RRC/LITE/mesh_top.c +++ b/openair2/RRC/LITE/mesh_top.c @@ -27,41 +27,6 @@ ________________________________________________________________*/ -#ifndef USER_MODE -#define __NO_VERSION__ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#ifdef KERNEL2_6 -#include -#endif - -#ifdef KERNEL2_4 -#include -#include -#endif - -#endif - - - #include "defs.h" #include "vars.h" @@ -72,75 +37,3 @@ extern void *bigphys_malloc(int); - -#ifndef USER_MODE - -/*------------------------------------------------*/ -/* Prototypes */ -/*------------------------------------------------*/ -#ifdef KERNEL2_4 -static int init_module( void ); -static void cleanup_module(void); -#else -static int openair_rrc_init_module( void ); -static void openair_rrc_cleanup_module(void); -#endif - -#ifdef KERNEL2_6 -static int __init openair_rrc_init_module( void ) -#else -int init_module( void ) -#endif //KERNEL2_6 -{ - printk("[OPENAIR][RRC][INIT] inserting module\n"); - - - Rrc_xface = (RRC_XFACE*)malloc16(sizeof(RRC_XFACE)); - - if(Rrc_xface == NULL) { - printk("[RRC] FATAL EROOR: Could not allocate memory for Rrc_xface !!!\n"); - return (-1); - } - - Mac_rlc_xface=mac_rrc_register(Rrc_xface); - - if( Mac_rlc_xface == NULL ) { - printk("[OPENAIR][RRC][INIT] Could not get RRC descriptor\n"); - return -1; - } else { - printk("[OPENAIR][RRC][INIT] Got RRC descriptor , Rcc_xface %p,Mac_rlc_xface=%p \n",Rrc_xface,Mac_rlc_xface); - } - - if(rrc_init_global_param()==-1) { - printk("[OPENAIR][RRC][INIT] FATAL ERROR: INIT_GLOBAL_PARAM_NOK\n"); - return -1; - } - - return 0; -} - -#ifdef KERNEL2_6 -static void __exit openair_rrc_cleanup_module(void) -#else -void cleanup_module(void) -#endif //KERNEL2_6 -{ -#ifndef NO_RRM - rtf_destroy(RRC2RRM_FIFO); - rtf_destroy(RRM2RRC_FIFO); -#endif //NO_RRM - printk("[OPENAIR][RRC][CLEANUP] cleanup module\n"); - mac_rrc_unregister(Rrc_xface); - -} - -MODULE_AUTHOR -("Lionel GAUTHIER , Raymond KNOPP , Aawatif MENOUNI ,Dominique NUSSBAUM , Michelle WETTERWALD , Maxime GUILLAUD "); -MODULE_DESCRIPTION ("openair RRC layer module"); -MODULE_LICENSE ("GPL"); -module_init (openair_rrc_init_module); -module_exit (openair_rrc_cleanup_module); - -#endif //USER_MODE - - diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index f0f495e8b7..bae76203c6 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -66,10 +66,8 @@ #include "OCG.h" #include "OCG_extern.h" #endif -#ifdef USER_MODE #include "RRC/NAS/nas_config.h" #include "RRC/NAS/rb_config.h" -#endif #if ENABLE_RAL #include "rrc_UE_ral.h" #endif @@ -1730,9 +1728,7 @@ rrc_ue_process_securityModeCommand( # endif #endif -#ifdef USER_MODE LOG_D(RRC, "securityModeComplete Encoded %zd bits (%zd bytes)\n", enc_rval.encoded, (enc_rval.encoded+7)/8); -#endif for (i = 0; i < (enc_rval.encoded + 7) / 8; i++) { LOG_T(RRC, "%02x.", buffer[i]); @@ -1835,9 +1831,7 @@ rrc_ue_process_ueCapabilityEnquiry( # endif #endif -#ifdef USER_MODE LOG_D(RRC,"UECapabilityInformation Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif for (i = 0; i < (enc_rval.encoded + 7) / 8; i++) { LOG_T(RRC, "%02x.", buffer[i]); @@ -4246,10 +4240,6 @@ static void decode_MBSFNAreaConfiguration( module_id_t ue_mod_idP, uint8_t eNB_i #endif // rel10 -#ifndef USER_MODE -EXPORT_SYMBOL(Rlc_info_am_config); -#endif - #if defined(ENABLE_ITTI) //----------------------------------------------------------------------------- void *rrc_ue_task( void *args_p ) diff --git a/openair2/RRC/LITE/rrc_common.c b/openair2/RRC/LITE/rrc_common.c index 0e836f5677..8ff04518be 100644 --- a/openair2/RRC/LITE/rrc_common.c +++ b/openair2/RRC/LITE/rrc_common.c @@ -97,9 +97,7 @@ rrc_init_global_param( //----------------------------------------------------------------------------- { - //#ifdef USER_MODE // Rrc_xface = (RRC_XFACE*)malloc16(sizeof(RRC_XFACE)); - //#endif //USRE_MODE // Rrc_xface->openair_rrc_top_init = openair_rrc_top_init; // Rrc_xface->openair_rrc_eNB_init = openair_rrc_eNB_init; diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index c8b42d41b3..e4c162d5f7 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -63,12 +63,10 @@ #include "MeasResults.h" //#endif -#ifdef USER_MODE -# include "RRC/NAS/nas_config.h" -# include "RRC/NAS/rb_config.h" -# include "OCG.h" -# include "OCG_extern.h" -#endif +#include "RRC/NAS/nas_config.h" +#include "RRC/NAS/rb_config.h" +#include "OCG.h" +#include "OCG_extern.h" #if defined(ENABLE_SECURITY) # include "UTIL/OSA/osa_defs.h" diff --git a/openair2/RRC/LITE/rrc_rrm_interface.c b/openair2/RRC/LITE/rrc_rrm_interface.c index 822ce554af..9f4270be89 100644 --- a/openair2/RRC/LITE/rrc_rrm_interface.c +++ b/openair2/RRC/LITE/rrc_rrm_interface.c @@ -292,10 +292,5 @@ int send_msg_fifo(int *s, msg_t *fmsg) int send_msg(void *s, msg_t *smsg) { -#ifdef USER_MODE send_msg_sock((sock_rrm_t *)s, smsg); -#else - send_msg_fifo((int *)s,smsg); -#endif - } diff --git a/openair2/RRC/LITE/rrc_rrm_interface.h b/openair2/RRC/LITE/rrc_rrm_interface.h index d204ab2db6..0880859a59 100644 --- a/openair2/RRC/LITE/rrc_rrm_interface.h +++ b/openair2/RRC/LITE/rrc_rrm_interface.h @@ -101,8 +101,6 @@ extern "C" { #define START_MSG_PUSU 0xCC -#ifdef USER_MODE - #include #include @@ -128,16 +126,6 @@ char *recv_msg( sock_rrm_t *s ) ; } #endif -#else //USER_MODE -#include - -#define RRC2RRM_FIFO 14 -#define RRM2RRC_FIFO 15 -int send_msg_fifo(int *s ,msg_t *msg ) ; -#endif //USER_MODE - int send_msg(void *, msg_t *); - - #endif diff --git a/openair2/RRC/LITE/rrm_2_rrc_msg.c b/openair2/RRC/LITE/rrm_2_rrc_msg.c index 3ef0bc2e0a..3ed3a9d859 100644 --- a/openair2/RRC/LITE/rrm_2_rrc_msg.c +++ b/openair2/RRC/LITE/rrm_2_rrc_msg.c @@ -65,17 +65,12 @@ void fn_rrc (void) /******************************************************************************/ msg_head_t *Header ; -#ifdef USER_MODE char *Data; -#else - int bytes_read; -#endif L2_ID Mac_id; while(1) { -#ifdef USER_MODE Header = (msg_head_t *) recv_msg(&S_rrc) ; if(Header==NULL) { @@ -83,52 +78,9 @@ void fn_rrc (void) } Data_to_read=Header->size; -#else - - if(Header_read_idx < Header_size) { - bytes_read = rtf_get (RRM2RRC_FIFO,&Header_buf[Header_read_idx],Header_size-Header_read_idx); - - if(bytes_read >0) { - msg("RRC: GET FIFOS RETURNS %d bytes, header %d\n",bytes_read,Header_read_idx); - } - - Header_read_idx+=bytes_read; - - if(Header_read_idx == Header_size) { - Header = (msg_head_t *) Header_buf; - Data_to_read=Header->size; - msg("RRC: Header read completed, data size %d\n",Data_to_read); - } - //msg("[fn_rrc]TTI %d: rcv_msg return Null\n",Rrc_xface->Frame_index); - else { - break; - } - } - -#endif if (Data_to_read > 0 ) { -#ifdef USER_MODE Data = (char *) (Header +1) ; -#else - bytes_read = rtf_get (RRM2RRC_FIFO,&Data[Data_read_idx],Data_to_read); - - if(bytes_read >0) { - msg("RRC: GET FIFOS RETURNS %d bytes, Data_to_read %d\n",bytes_read,Data_to_read); - } - - Data_to_read-=bytes_read; - Data_read_idx+=bytes_read; - - if(Data_to_read > 0 ) { - break; - } - - msg("RRC: DATA read completed, data size %d\n",Data_to_read); - Header_read_idx=0; - Data_read_idx=0; - Data_to_read=0; -#endif } msg("Got MSG of Type %d on Inst %d\n",Header->msg_type,Header->inst); diff --git a/openair2/RRC/LITE/utils.c b/openair2/RRC/LITE/utils.c index fd37fdf65c..bbf97046bf 100644 --- a/openair2/RRC/LITE/utils.c +++ b/openair2/RRC/LITE/utils.c @@ -29,25 +29,8 @@ ________________________________________________________________*/ -//#include "openair_types.h" #include "defs.h" #include "extern.h" -//#include "openair_proto.h" - - -#ifndef USER_MODE -char bcmp(void *x, void *y,int Size ) -{ - unsigned char i; - - for(i=0; imacphy_exit(); - #else exit(-1); - #endif */ } /* diff --git a/openair2/UTIL/LISTS/list2.c b/openair2/UTIL/LISTS/list2.c index 875f5e2d2f..3f0a59df53 100644 --- a/openair2/UTIL/LISTS/list2.c +++ b/openair2/UTIL/LISTS/list2.c @@ -38,11 +38,7 @@ ***************************************************************************/ #define LIST2_C #include "list.h" -#ifdef USER_MODE #include "assertions.h" -#else -#define NULL 0 -#endif #include @@ -336,9 +332,7 @@ list2_display (list2_t * listP) nb_elements++; } msg (" found nb_elements %d nb_elements %d\n", nb_elements, listP->nb_elements); - #ifdef USER_MODE AssertFatal(nb_elements == listP->nb_elements, "Bad count of elements %d != %d", nb_elements, listP->nb_elements); - #endif } }*/ } diff --git a/openair2/UTIL/LOG/log.c b/openair2/UTIL/LOG/log.c index f3bd04754b..887ce5bff6 100644 --- a/openair2/UTIL/LOG/log.c +++ b/openair2/UTIL/LOG/log.c @@ -42,10 +42,8 @@ # include "intertask_interface.h" #endif -#ifdef USER_MODE # include # include -#endif #ifdef RTAI # include # include @@ -164,24 +162,14 @@ void log_getconfig(log_t *g_log) { int logInit (void) { -#ifdef USER_MODE #ifndef RTAI int i; #endif g_log = calloc(1, sizeof(log_t)); -#else - g_log = kmalloc(sizeof(log_t), GFP_KERNEL); -#endif - if (g_log == NULL) { -#ifdef USER_MODE perror ("cannot allocated memory for log generation module \n"); exit(EXIT_FAILURE); -#else - printk("cannot allocated memory for log generation module \n"); - return(-1); -#endif } @@ -519,11 +507,7 @@ int logInit (void) rtf_create (FIFO_PRINTF_NO, FIFO_PRINTF_SIZE); #endif -#ifdef USER_MODE printf("log init done\n"); -#else - printk("log init done\n"); -#endif return 0; } diff --git a/openair2/UTIL/LOG/log.h b/openair2/UTIL/LOG/log.h index 1d795740b6..c21407f6eb 100644 --- a/openair2/UTIL/LOG/log.h +++ b/openair2/UTIL/LOG/log.h @@ -32,7 +32,6 @@ # define __LOG_H__ /*--- INCLUDES ---------------------------------------------------------------*/ -#ifdef USER_MODE #include #include #include @@ -53,9 +52,6 @@ #define _GNU_SOURCE #endif #include -#else -#include "rtai_fifos.h" -#endif /*----------------------------------------------------------------------------*/ @@ -282,20 +278,11 @@ void *log_thread_function(void * list); * @ingroup _macro * @brief Macro used to call tr_log_full_ex with file, function and line information * @{*/ -#ifdef USER_MODE -//#define logIt(component, level, format, args...) do {logRecord(__FILE__, __FUNCTION__, __LINE__, component, level, format, ##args);} while(0); #ifdef LOG_NO_THREAD #define logIt(component, level, format, args...) logRecord_mt(__FILE__, __FUNCTION__, __LINE__, component, level, format, ##args) #else //default #define logIt(component, level, format, args...) logRecord(__FILE__, __FUNCTION__, __LINE__, component, level, format, ##args) #endif -#else -#ifdef LOG_NO_THREAD -#define logIt(component, level, format, args...) logRecord_mt(NULL, __FUNCTION__, __LINE__, component, level, format, ##args) -#else // default -#define logIt(component, level, format, args...) logRecord(NULL, __FUNCTION__, __LINE__, component, level, format, ##args) -#endif -#endif /* @}*/ /*----------------macro definitions for reading log configuration from the config module */ @@ -326,7 +313,6 @@ void *log_thread_function(void * list); * @{*/ // debugging macros -#ifdef USER_MODE # if T_TRACER # include "T.h" # define LOG_I(c, x...) T(T_LEGACY_ ## c ## _INFO, T_PRINTF(x)) @@ -364,17 +350,6 @@ void *log_thread_function(void * list); # define LOG_T(c, x...) logIt(c, LOG_TRACE, x) # endif /*DISABLE_LOG_X*/ # endif /* T_TRACER */ -#else /* USER_MODE */ -# define LOG_G(c, x...) printk(x) -# define LOG_A(c, x...) printk(x) -# define LOG_C(c, x...) printk(x) -# define LOG_E(c, x...) printk(x) -# define LOG_W(c, x...) printk(x) -# define LOG_N(c, x...) printk(x) -# define LOG_I(c, x...) printk(x) -# define LOG_D(c, x...) printk(x) -# define LOG_T(c, x...) printk(x) -#endif /* @}*/ diff --git a/openair2/UTIL/MATH/random.c b/openair2/UTIL/MATH/random.c index 06caa3bc3c..30a6e9b1ab 100644 --- a/openair2/UTIL/MATH/random.c +++ b/openair2/UTIL/MATH/random.c @@ -29,11 +29,7 @@ #include "rtos_header.h" #include "platform_types.h" -#ifdef USER_MODE -# include -#else -#include -#endif +#include /* Random generators */ @@ -47,7 +43,6 @@ static int seed; void init_uniform (void) { -#ifdef USER_MODE struct timeval tv; struct timezone tz; @@ -61,9 +56,6 @@ init_uniform (void) #warning TO DO seed = rgId //seed += rgId; #endif -#else - seed = rt_get_time_ns(); -#endif } diff --git a/openair2/UTIL/MEM/mem_block.c b/openair2/UTIL/MEM/mem_block.c index 09f10547cb..9c3a50467a 100644 --- a/openair2/UTIL/MEM/mem_block.c +++ b/openair2/UTIL/MEM/mem_block.c @@ -54,7 +54,7 @@ static pthread_mutex_t mtex = PTHREAD_MUTEX_INITIALIZER; //#define DEBUG_MEM_MNGT_ALLOC_SIZE //#define DEBUG_MEM_MNGT_ALLOC //----------------------------------------------------------------------------- -#if defined(USER_MODE) && defined(DEBUG_MEM_MNGT_ALLOC) +#if defined(DEBUG_MEM_MNGT_ALLOC) uint32_t counters[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; #endif //----------------------------------------------------------------------------- @@ -269,10 +269,8 @@ get_free_mem_block (uint32_t sizeP, const char* caller) #ifdef DEBUG_MEM_MNGT_ALLOC LOG_E (RLC,"[MEM_MNGT][ERROR][MINOR] memory pool %d is empty trying next pool alloc count = %d\n", pool_selected, counters[pool_selected]); -#ifdef USER_MODE // display_mem_load (); // check_mem_area ((void *)&mem_block_var); -#endif #endif } while (pool_selected++ < 12); diff --git a/openair2/UTIL/MEM/mem_block.h b/openair2/UTIL/MEM/mem_block.h index b7e36bf5b3..e967380269 100644 --- a/openair2/UTIL/MEM/mem_block.h +++ b/openair2/UTIL/MEM/mem_block.h @@ -31,9 +31,7 @@ #ifndef __MEM_BLOCK_H__ # define __MEM_BLOCK_H__ -#ifdef USER_MODE #include -#endif #ifdef MEM_BLOCK_C # define public_mem_block(x) x # define private_mem_block(x) x @@ -63,19 +61,8 @@ public_mem_block(mem_block_t *copy_mem_block (mem_block_t * leP, mem_block_t * d public_mem_block(void display_mem_load (void);) public_mem_block(void check_mem_area (void);) -# ifdef USER_MODE private_mem_block(void check_free_mem_block (mem_block_t * leP);) -# endif -#ifdef USER_MODE -//# define MEM_SCALE MAX_MOBILES_PER_ENB*NB_RB_MAX # define MEM_SCALE MAX_MOBILES_PER_ENB -#else -# ifdef NODE_RG -# define MEM_SCALE 2 -# else -# define MEM_SCALE 1 -# endif -#endif // definition of the size of the allocated memory area # define MEM_MNGT_MB0_BLOCK_SIZE 64 // 64 diff --git a/openair2/UTIL/MEM/mem_mngt.c b/openair2/UTIL/MEM/mem_mngt.c index 49cd310ac9..57c90ea4f9 100644 --- a/openair2/UTIL/MEM/mem_mngt.c +++ b/openair2/UTIL/MEM/mem_mngt.c @@ -49,9 +49,7 @@ // #endif //----------------------------------------------------------------------------- -#ifdef USER_MODE uint32_t counters[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -#endif //----------------------------------------------------------------------------- /* * initialize all ures @@ -227,10 +225,8 @@ get_free_mem_block (uint16_t sizeP, __func__) #ifdef DEBUG_MEM_MNGT_ALLOC msg ("[MEM_MNGT][ERROR][MINOR] memory pool %d is empty trying next pool alloc count = %d\n", pool_selected, counters[pool_selected]); -# ifdef USER_MODE display_mem_load (); check_mem_area (mem); -# endif #endif } while (pool_selected++ < 9); diff --git a/openair2/UTIL/OCG/makefile b/openair2/UTIL/OCG/makefile index 1e531f9494..da28c888d4 100644 --- a/openair2/UTIL/OCG/makefile +++ b/openair2/UTIL/OCG/makefile @@ -7,7 +7,7 @@ OPENAIR2_TOP = ../../../openair2 OPENAIR3_TOP = ../../../openair3 OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DPHYSIM -DNODE_RG -DUSER_MODE -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat +CFLAGS += -DPHYSIM -DNODE_RG -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat CFLAGS += -m32 -DOPENAIR_LTE -DOPENAIR2 #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE diff --git a/openair2/UTIL/OMG/makefile b/openair2/UTIL/OMG/makefile index 319b8296cd..1fb0f3efd9 100644 --- a/openair2/UTIL/OMG/makefile +++ b/openair2/UTIL/OMG/makefile @@ -60,7 +60,7 @@ OPENAIR2_TOP = ../../../openair2 OPENAIR3_TOP = ../../../openair3 OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DPHYSIM -DNODE_RG -DUSER_MODE -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat +CFLAGS += -DPHYSIM -DNODE_RG -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat CFLAGS += -DOPENAIR_LTE -DOPENAIR2 #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE diff --git a/openair2/UTIL/OMG/makefile_old b/openair2/UTIL/OMG/makefile_old index acc89254fb..06d4a6f46f 100644 --- a/openair2/UTIL/OMG/makefile_old +++ b/openair2/UTIL/OMG/makefile_old @@ -62,7 +62,7 @@ OPENAIR2_TOP = ../../../openair2 OPENAIR3_TOP = ../../../openair3 OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DPHYSIM -DNODE_RG -DUSER_MODE -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat +CFLAGS += -DPHYSIM -DNODE_RG -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat CFLAGS += -DOPENAIR_LTE -DOPENAIR2 #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE diff --git a/openair2/UTIL/OMG/makefile_standalone b/openair2/UTIL/OMG/makefile_standalone index 68170543ee..d612c01837 100644 --- a/openair2/UTIL/OMG/makefile_standalone +++ b/openair2/UTIL/OMG/makefile_standalone @@ -8,7 +8,7 @@ OBJsumo = omg.c common.c sumo.c client_traci_OMG.c socket_traci_OMG.c storage_tr OBJ = omg.c common.c static.c job.c rwp.c rwalk.c trace.c steadystaterwp.c sumo.c grid.c mobility_parser.c hashtable.c client_traci_OMG.c socket_traci_OMG.c storage_traci_OMG.c id_manager.c -CFLAGS += -DSTANDALONE -DUSER_MODE -g +CFLAGS += -DSTANDALONE -g .PHONY: help staticOMG rwpOMG clean diff --git a/openair2/UTIL/TRACE/print.h b/openair2/UTIL/TRACE/print.h index 5982d249fa..72c43f20d4 100644 --- a/openair2/UTIL/TRACE/print.h +++ b/openair2/UTIL/TRACE/print.h @@ -28,14 +28,5 @@ ***************************************************************************/ #ifndef __PRINT_H__ # define __PRINT_H__ -# ifdef USER_MODE -# define msg printf -# else -# ifdef FIFO_PRINTF -# include "fifo_printf_proto_extern.h" -# define msg fifo_printf -# else -# define msg fifo_printf_null -# endif -# endif +# define msg printf #endif diff --git a/openair2/X2AP/Makefile.inc b/openair2/X2AP/Makefile.inc index 7369cf8dfa..a301a9934e 100755 --- a/openair2/X2AP/Makefile.inc +++ b/openair2/X2AP/Makefile.inc @@ -28,7 +28,6 @@ CFLAGS = \ -Wall \ -DENB_MODE \ -DENABLE_USE_MME \ - -DUSER_MODE \ -I. \ -I$(ASN1MESSAGESDIR)/ASN1/$(ASN1RELDIR) \ -I$(ASN1MESSAGESDIR) \ diff --git a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/Makefile b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/Makefile index c9c5f82819..77b3d41f25 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/Makefile +++ b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/Makefile @@ -1,5 +1,5 @@ CC = gcc -CFLAGS = -DUSER_MODE -DEXMIMO -g +CFLAGS = -DEXMIMO -g XTRA_CFLAGS = -msse -msse2 -mssse3 -fPIC #ifndef OPENAIR0_DIR diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index 8b62a8e698..446e602f6d 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -283,12 +283,11 @@ int64_t wrap_ts = 0; unsigned int u_sf_mode = 0; // 1=record, 2=replay unsigned int u_sf_record = 0; // record mode unsigned int u_sf_replay = 0; // replay mode -char u_sf_filename[1024]; // subframes file path +char u_sf_filename[1024] = ""; // subframes file path unsigned int u_sf_max = DEF_NB_SF; // max number of recorded subframes unsigned int u_sf_loops = DEF_SF_NB_LOOP; // number of loops in replay mode unsigned int u_sf_read_delay = DEF_SF_DELAY_READ; // read delay in replay mode unsigned int u_sf_write_delay = DEF_SF_DELAY_WRITE; // write delay in replay mode -char *tmp_filename[1]; // use an array of pointer (libconfig does not seems to work with char array yet) char config_opt_sf_file[] = CONFIG_OPT_SF_FILE; char config_def_sf_file[] = DEF_SF_FILE; @@ -837,7 +836,7 @@ int trx_usrp_recplay_config_init(paramdef_t *usrp_recplay_params) { memcpy(usrp_recplay_params[0].optname, config_opt_sf_file, strlen(config_opt_sf_file)); usrp_recplay_params[0].helpstr = config_hlp_sf_file; usrp_recplay_params[0].paramflags=PARAMFLAG_NOFREE; - usrp_recplay_params[0].strptr=(char **)&tmp_filename[0]; + usrp_recplay_params[0].strptr=(char **)&u_sf_filename; usrp_recplay_params[0].defstrval = NULL; usrp_recplay_params[0].type=TYPE_STRING; usrp_recplay_params[0].numelt=sizeof(u_sf_filename); @@ -912,16 +911,13 @@ extern "C" { // end to check memset(usrp_recplay_params, 0, 7*sizeof(paramdef_t)); memset(&u_sf_filename[0], 0, 1024); - tmp_filename[0] = u_sf_filename; if (trx_usrp_recplay_config_init(usrp_recplay_params) != 0) { std::cerr << "USRP device record/replay mode configuration error exiting" << std::endl; return -1; } config_process_cmdline(usrp_recplay_params,sizeof(usrp_recplay_params)/sizeof(paramdef_t),NULL); - if (strlen(tmp_filename[0]) != 0) { - (void) strcpy(u_sf_filename, tmp_filename[0]); - } else { + if (strlen(u_sf_filename) == 0) { (void) strcpy(u_sf_filename, DEF_SF_FILE); } diff --git a/targets/Makefile.common b/targets/Makefile.common index 042a36bf45..ac0771770b 100644 --- a/targets/Makefile.common +++ b/targets/Makefile.common @@ -86,7 +86,6 @@ endif ifeq ($(ENABLE_ITTI),1) COMMON_CFLAGS += -DENABLE_ITTI -COMMON_CFLAGS += -DUSER_MODE COMMON_CFLAGS += -I$(OPENAIR1_DIR) COMMON_CFLAGS += -I$(OPENAIR2_DIR)/NAS COMMON_CFLAGS += $(L2_incl) diff --git a/targets/PROJECTS/E-MBMS/build_all.bash b/targets/PROJECTS/E-MBMS/build_all.bash index 0cbece916e..bac9b33736 100755 --- a/targets/PROJECTS/E-MBMS/build_all.bash +++ b/targets/PROJECTS/E-MBMS/build_all.bash @@ -61,8 +61,8 @@ echo_success "\n###############################" echo_success "# COMPILE oaisim" echo_success "###############################" cd $OPENAIR_TARGETS/SIMU/USER -echo_success "Executing: make oaisim NAS=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 USER_MODE=1 OPENAIR2=1 Rel10=1 -j`grep -c ^processor /proc/cpuinfo `" -make oaisim NAS=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 USER_MODE=1 OPENAIR2=1 Rel10=1 -j`grep -c ^processor /proc/cpuinfo ` +echo_success "Executing: make oaisim NAS=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 OPENAIR2=1 Rel10=1 -j`grep -c ^processor /proc/cpuinfo `" +make oaisim NAS=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 OPENAIR2=1 Rel10=1 -j`grep -c ^processor /proc/cpuinfo ` if [[ $? -eq 2 ]] ; then exit 1 fi diff --git a/targets/RT/USER/Makefile b/targets/RT/USER/Makefile index 8c413d4e2e..ae5e006d06 100644 --- a/targets/RT/USER/Makefile +++ b/targets/RT/USER/Makefile @@ -178,7 +178,7 @@ ifdef SMBV CFLAGS += -DSMBV endif -CFLAGS += -DPHYSIM -DUSER_MODE -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DPHY_CONTEXT=1 +CFLAGS += -DPHYSIM -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DPHY_CONTEXT=1 CFLAGS += -DOPENAIR_LTE -DENABLE_FXP -DOPENAIR1 #-DDLSCH_THREAD #-DULSCH_THREAD diff --git a/targets/RT/USER/Makefile.agilent b/targets/RT/USER/Makefile.agilent index 061c15a31c..31dd3b6e7f 100644 --- a/targets/RT/USER/Makefile.agilent +++ b/targets/RT/USER/Makefile.agilent @@ -90,7 +90,7 @@ ifdef SMBV CFLAGS += -DSMBV endif -CFLAGS += -DPHYSIM -DUSER_MODE -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DPHY_CONTEXT=1 +CFLAGS += -DPHYSIM -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DPHY_CONTEXT=1 CFLAGS += -DOPENAIR_LTE -DENABLE_FXP -DOPENAIR1 -DDLSCH_THREAD #-DULSCH_THREAD #only for CBMIMO1 @@ -143,7 +143,7 @@ ifdef USE_MME include $(OPENAIR2_DIR)/S1AP/MESSAGES/Makefile.inc CFLAGS += -DENABLE_USE_MME -DENB_MODE LDFLAGS += -lsctp - CFLAGS_S1AP += -DENB_MODE -DENABLE_USE_MME -DEMIT_ASN_DEBUG=1 -DUSER_MODE + CFLAGS_S1AP += -DENB_MODE -DENABLE_USE_MME -DEMIT_ASN_DEBUG=1 S1AP_BUILT_OBJS += $(S1AP_OBJS) $(addprefix $(OPENAIR2_DIR)/S1AP/MESSAGES/, $(S1AP_ASN_MODULE_SOURCES)) S1AP_BUILT_OBJS += $(OPENAIR3_DIR)/OPENAIRMME/SCTP/sctp_primitives_client.o endif diff --git a/targets/SIMU/USER/Makefile b/targets/SIMU/USER/Makefile index 7de5f9382f..e48b4b62ad 100644 --- a/targets/SIMU/USER/Makefile +++ b/targets/SIMU/USER/Makefile @@ -29,7 +29,7 @@ endif CFLAGS += -Wpointer-sign -CFLAGS += -DUSER_MODE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 $(CPUFLAGS) -I/usr/include/X11 #-Wno-packed-bitfield-compat +CFLAGS += -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 $(CPUFLAGS) -I/usr/include/X11 #-Wno-packed-bitfield-compat ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index 778f250a78..852b764ed7 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -1566,7 +1566,7 @@ void update_ocm() void update_otg_eNB(module_id_t enb_module_idP, unsigned int ctime) { -#if defined(USER_MODE) && defined(OAI_EMU) +#if defined(OAI_EMU) //int rrc_state=0; @@ -1710,7 +1710,7 @@ void update_otg_eNB(module_id_t enb_module_idP, unsigned int ctime) void update_otg_UE(module_id_t ue_mod_idP, unsigned int ctime) { -#if defined(USER_MODE) && defined(OAI_EMU) +#if defined(OAI_EMU) int app_id; if (oai_emulation.info.otg_enabled ==1 ) { diff --git a/targets/TEST/AT_COMMANDS/Makefile b/targets/TEST/AT_COMMANDS/Makefile index 2939b30c01..41d079bbcb 100755 --- a/targets/TEST/AT_COMMANDS/Makefile +++ b/targets/TEST/AT_COMMANDS/Makefile @@ -6,7 +6,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3_TOP = $(OPENAIR3_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -m32 -DPHYSIM -DNODE_RG -DUSER_MODE -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DNODE_RG -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/OAI/case01.py b/targets/TEST/OAI/case01.py index cdc3bd9eb4..9595f7e35d 100644 --- a/targets/TEST/OAI/case01.py +++ b/targets/TEST/OAI/case01.py @@ -246,7 +246,7 @@ def execute(oai, user, pw, host, logfile,logdir,debug,timeout): log.start() test = '14' name = 'Compile oai.rel8.itti.ral.make' - conf = 'make DISABLE_XER_PRINT=1 LINK_ENB_PDCP_TO_IP_DRIVER=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 USER_MODE=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 RLC_STOP_ON_LOST_PDU=1 Rel8=1' + conf = 'make DISABLE_XER_PRINT=1 LINK_ENB_PDCP_TO_IP_DRIVER=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 RLC_STOP_ON_LOST_PDU=1 Rel8=1' trace = logdir + '/log_' + case + test + '.txt;' tee = ' 2>&1 | tee ' + trace diag = 'check the compilation errors for ITTI Rel8' @@ -254,7 +254,7 @@ def execute(oai, user, pw, host, logfile,logdir,debug,timeout): oai.send('make cleanall;') oai.send('make cleanasn1;') oai.send('rm -f ./oaisim.rel8.itti.ral.'+host) - oai.send_expect_false('make DISABLE_XER_PRINT=1 LINK_ENB_PDCP_TO_IP_DRIVER=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 USER_MODE=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 RLC_STOP_ON_LOST_PDU=1 Rel8=1 -j4' + tee, makerr1, timeout) + oai.send_expect_false('make DISABLE_XER_PRINT=1 LINK_ENB_PDCP_TO_IP_DRIVER=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 RLC_STOP_ON_LOST_PDU=1 Rel8=1 -j4' + tee, makerr1, timeout) oai.send('cp ./oaisim ./oaisim.rel8.itti.ral.'+host) except log.err, e: log.fail(case, test, name, conf, e.value, diag, logfile,trace) @@ -265,7 +265,7 @@ def execute(oai, user, pw, host, logfile,logdir,debug,timeout): log.start() test = '15' name = 'Compile oai.rel10.itti.ral.make' - conf = 'make DISABLE_XER_PRINT=1 LINK_ENB_PDCP_TO_IP_DRIVER=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 USER_MODE=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 RLC_STOP_ON_LOST_PDU=1 Rel10=1' + conf = 'make DISABLE_XER_PRINT=1 LINK_ENB_PDCP_TO_IP_DRIVER=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 RLC_STOP_ON_LOST_PDU=1 Rel10=1' trace = logdir + '/log_' + case + test + '.txt;' tee = ' 2>&1 | tee ' + trace diag = 'check the compilation errors for ITTI Rel10' @@ -273,7 +273,7 @@ def execute(oai, user, pw, host, logfile,logdir,debug,timeout): oai.send('make cleanall;') oai.send('make cleanasn1;') oai.send('rm -f ./oaisim.rel10.itti.ral.'+host) - oai.send_expect_false('make DISABLE_XER_PRINT=1 LINK_ENB_PDCP_TO_IP_DRIVER=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 USER_MODE=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 RLC_STOP_ON_LOST_PDU=1 Rel10=1 -j4' + tee, makerr1, timeout) + oai.send_expect_false('make DISABLE_XER_PRINT=1 LINK_ENB_PDCP_TO_IP_DRIVER=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 RLC_STOP_ON_LOST_PDU=1 Rel10=1 -j4' + tee, makerr1, timeout) oai.send('cp ./oaisim ./oaisim.rel10.itti.ral.'+host) except log.err, e: log.fail(case, test, name, conf, e.value, diag, logfile,trace) diff --git a/targets/TEST/PACKET_TRACER/Makefile b/targets/TEST/PACKET_TRACER/Makefile index 46fa86037c..93e67bc9e2 100755 --- a/targets/TEST/PACKET_TRACER/Makefile +++ b/targets/TEST/PACKET_TRACER/Makefile @@ -6,7 +6,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3_TOP = $(OPENAIR3_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -m32 -DPHYSIM -DUSER_MODE -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/PDCP/Makefile b/targets/TEST/PDCP/Makefile index 66af847af5..12193cbb99 100755 --- a/targets/TEST/PDCP/Makefile +++ b/targets/TEST/PDCP/Makefile @@ -8,7 +8,7 @@ OPENAIR3 = $(OPENAIR3_DIR) EXE_FILE_NAME = test_pdcp -CFLAGS += -m32 -DPHYSIM -DNODE_RG -DUSER_MODE -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DNODE_RG -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/PDCP/with_rlc/Makefile.data_bearer b/targets/TEST/PDCP/with_rlc/Makefile.data_bearer index 00f07c1b92..495dcda572 100755 --- a/targets/TEST/PDCP/with_rlc/Makefile.data_bearer +++ b/targets/TEST/PDCP/with_rlc/Makefile.data_bearer @@ -8,7 +8,7 @@ OPENAIR3 = $(OPENAIR3_DIR) EXE_FILE_NAME = test_pdcp_rlc -CFLAGS += -m32 -DPHYSIM -DNODE_RG -DUSER_MODE -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DNODE_RG -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/RLC_AM_V9.3.0/Makefile b/targets/TEST/RLC_AM_V9.3.0/Makefile index 9c807cd826..68f520b31d 100755 --- a/targets/TEST/RLC_AM_V9.3.0/Makefile +++ b/targets/TEST/RLC_AM_V9.3.0/Makefile @@ -8,7 +8,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3_TOP = $(OPENAIR3_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -m32 -DUSER_MODE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 +CFLAGS += -m32 -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/RLC_UM_V9.3.0/Makefile b/targets/TEST/RLC_UM_V9.3.0/Makefile index b01ea156f4..91ad44e08b 100755 --- a/targets/TEST/RLC_UM_V9.3.0/Makefile +++ b/targets/TEST/RLC_UM_V9.3.0/Makefile @@ -8,7 +8,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3_TOP = $(OPENAIR3_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -m32 -DUSER_MODE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 +CFLAGS += -m32 -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES From 8b5a963346d3001e9efc0fc5bd93f82036128c2f Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Sun, 14 Jan 2018 08:54:51 +0100 Subject: [PATCH 137/284] changes for noS1 IP addressing --- openair2/RRC/LITE/rrc_UE.c | 7 +------ openair2/RRC/LITE/rrc_eNB.c | 5 ----- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index a75e29d3e0..67159fa248 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -730,13 +730,8 @@ rrc_ue_establish_drb( */ #ifdef PDCP_USE_NETLINK # if !defined(OAI_NW_DRIVER_TYPE_ETHERNET) && !defined(EXMIMO) && !defined(OAI_USRP) && !defined(OAI_BLADERF) && !defined(ETHERNET) && !defined(LINK_ENB_PDCP_TO_GTPV1U) -# ifdef OAI_EMU - ip_addr_offset3 = oai_emulation.info.nb_enb_local; - ip_addr_offset4 = NB_eNB_INST; -# else ip_addr_offset3 = 0; - ip_addr_offset4 = 8; -# endif + ip_addr_offset4 = 1; LOG_I(OIP,"[UE %d] trying to bring up the OAI interface oai%d, IP 10.0.%d.%d\n", ue_mod_idP, ip_addr_offset3+ue_mod_idP, ip_addr_offset3+ue_mod_idP+1,ip_addr_offset4+ue_mod_idP+1); oip_ifup=nas_config(ip_addr_offset3+ue_mod_idP, // interface_id diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index b675495c98..c8b0e3390a 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -3561,12 +3561,7 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( ctxt_pP->module_id + 1); // fourth octet if (oip_ifup == 0) { // interface is up --> send a config the DRB -# ifdef OAI_EMU - oai_emulation.info.oai_ifup[ctxt_pP->module_id] = 1; - dest_ip_offset = NB_eNB_INST; -# else dest_ip_offset = 8; -# endif LOG_I(OIP, "[eNB %d] Config the oai%d to send/receive pkt on DRB %ld to/from the protocol stack\n", ctxt_pP->module_id, ctxt_pP->module_id, From 3120f16610198ecea7826d97e2761c77fc02909d Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Sun, 14 Jan 2018 08:55:46 +0100 Subject: [PATCH 138/284] changes for noS1 IP addressing (UE side) --- cmake_targets/oaisim_noS1_build_oai/CMakeLists.template | 2 +- cmake_targets/tools/init_nas_nos1 | 4 ++-- openair1/SCHED/phy_procedures_lte_ue.c | 2 +- openair2/RRC/LITE/rrc_UE.c | 7 +------ 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 8e1670ea43..68be4b5b02 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -36,7 +36,7 @@ set ( MESSAGE_CHART_GENERATOR_PHY False ) set ( MIH_C_MEDIEVAL_EXTENSIONS False ) set ( MSG_PRINT False ) set ( MU_RECEIVER False ) -set ( NAS_ADDRESS_FIX True ) +set ( NAS_ADDRESS_FIX False ) set ( NAS_BUILT_IN_UE False) set ( NAS_MME False ) set ( NAS_UE False ) diff --git a/cmake_targets/tools/init_nas_nos1 b/cmake_targets/tools/init_nas_nos1 index 9bcaa0afb5..f7347e5508 100755 --- a/cmake_targets/tools/init_nas_nos1 +++ b/cmake_targets/tools/init_nas_nos1 @@ -44,11 +44,11 @@ load_module $OPENAIR_DIR/targets/bin/nasmesh.ko if [ "$1" = "eNB" ]; then echo "bring up oai0 interface for enb" sudo ifconfig oai0 10.0.1.1 netmask 255.255.255.0 broadcast 10.0.1.255 - $OPENAIR_DIR/targets/bin/rb_tool -a -c0 -i0 -z0 -s 10.0.1.1 -t 10.0.1.9 -r 1 + $OPENAIR_DIR/targets/bin/rb_tool -a -c0 -i0 -z0 -s 10.0.1.1 -t 10.0.1.2 -r 1 else if [ "$1" = "UE" ]; then echo "bring up oai0 interface for UE" sudo ifconfig oai0 10.0.1.9 netmask 255.255.255.0 broadcast 10.0.1.255 - $OPENAIR_DIR/targets/bin/rb_tool -a -c0 -i0 -z0 -s 10.0.1.9 -t 10.0.1.1 -r 1 + $OPENAIR_DIR/targets/bin/rb_tool -a -c0 -i0 -z0 -s 10.0.1.2 -t 10.0.1.1 -r 1 fi fi diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index a61aacd303..9614d2d9e7 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -1623,7 +1623,7 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB // deactivate service request // ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 0; - LOG_I(PHY,"Generating PUSCH (Abssubframe: %d.%d): harq-Id: %d, round: %d, MaxReTrans: %d \n",frame_tx,subframe_tx,harq_pid,ue->ulsch[eNB_id]->harq_processes[harq_pid]->round,ue->ulsch[eNB_id]->Mlimit); + LOG_D(PHY,"Generating PUSCH (Abssubframe: %d.%d): harq-Id: %d, round: %d, MaxReTrans: %d \n",frame_tx,subframe_tx,harq_pid,ue->ulsch[eNB_id]->harq_processes[harq_pid]->round,ue->ulsch[eNB_id]->Mlimit); if (ue->ulsch[eNB_id]->harq_processes[harq_pid]->round >= (ue->ulsch[eNB_id]->Mlimit - 1)) { LOG_D(PHY,"PUSCH MAX Retransmission achieved ==> send last pusch\n"); diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index a75e29d3e0..67159fa248 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -730,13 +730,8 @@ rrc_ue_establish_drb( */ #ifdef PDCP_USE_NETLINK # if !defined(OAI_NW_DRIVER_TYPE_ETHERNET) && !defined(EXMIMO) && !defined(OAI_USRP) && !defined(OAI_BLADERF) && !defined(ETHERNET) && !defined(LINK_ENB_PDCP_TO_GTPV1U) -# ifdef OAI_EMU - ip_addr_offset3 = oai_emulation.info.nb_enb_local; - ip_addr_offset4 = NB_eNB_INST; -# else ip_addr_offset3 = 0; - ip_addr_offset4 = 8; -# endif + ip_addr_offset4 = 1; LOG_I(OIP,"[UE %d] trying to bring up the OAI interface oai%d, IP 10.0.%d.%d\n", ue_mod_idP, ip_addr_offset3+ue_mod_idP, ip_addr_offset3+ue_mod_idP+1,ip_addr_offset4+ue_mod_idP+1); oip_ifup=nas_config(ip_addr_offset3+ue_mod_idP, // interface_id From 7757b9e7e75f16449a6c72a5f16541c36474c1ea Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 8 Jan 2018 12:07:26 +0100 Subject: [PATCH 139/284] import NFAPI work from David Price from Cisco (non-working commit, do not use it) It has been chosen to not include the full history of commits from David. He included a binary version of wireshark, probably a modified one that understands NFAPI. Wireshark is released under the GPL license, we cannot include it in the repository. We could have done a next commit to remove this binary. But then it would still be present in the history of commits, which may not be allowed. And it would take space on disk. We could edit the history to remove wireshark entirely. But this operation is too complicated. There was also a pcap capture file, which has nothing to do in the history of commits and would take space on disk. There again, it's too difficult to edit the history to remove it. There was a file .gitignore that was also removed. The original history can be found on David's repository: https://gitlab.eurecom.fr/daveprice/openairinterface5g/ The branch is: nfapi-ru-rau-split. A copy of that branch has been included in the internal OAI repository, for those who have access to it. The branch is the same. The last commit ID is 9106438239e0bc626ff1fa1d97d911caadd0fbb9. You can compare the current commit with the commit 9106... to see what differs. The current commit has to be considered non-working. The commit following the current commit will fix problems with the work in the current commit. If you use git bisect, don't spend time analyzing the current commit. --- cmake_targets/CMakeLists.txt | 132 +- cmake_targets/build_oai | 2 +- cmake_targets/tools/build_helper | 1 + common/config/config_userapi.c | 1 + nfapi/nfapi_interface.h | 3855 --- nfapi/oai_integration/nfapi.c | 51 + nfapi/oai_integration/nfapi_pnf.c | 1625 ++ nfapi/oai_integration/nfapi_pnf.h | 27 + nfapi/oai_integration/nfapi_vnf.c | 1221 + nfapi/oai_integration/nfapi_vnf.h | 27 + nfapi/oai_integration/vendor_ext.h | 67 + nfapi/open-nfapi.oai.patch | 20010 ++++++++++++++++ oaienv | 11 + open-nfapi.oai.patch | 40 - openair1/PHY/INIT/lte_init.c | 510 +- openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c | 2 +- openair1/PHY/LTE_TRANSPORT/dci.c | 39 +- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 117 +- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 89 +- openair1/PHY/LTE_TRANSPORT/pbch.c | 2 + openair1/PHY/LTE_TRANSPORT/phich.c | 2 +- openair1/PHY/LTE_TRANSPORT/prach.c | 77 +- openair1/PHY/LTE_TRANSPORT/proto.h | 4 +- openair1/PHY/LTE_TRANSPORT/rar_tools.c | 6 +- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 14 +- .../PHY/LTE_TRANSPORT/ulsch_demodulation.c | 7 + openair1/PHY/TOOLS/file_output.c | 6 +- openair1/PHY/defs.h | 2 + openair1/PHY/impl_defs_lte.h | 2 +- openair1/SCHED/fapi_l1.c | 237 +- openair1/SCHED/fapi_l1.h | 8 +- openair1/SCHED/phy_procedures_lte_common.c | 4 +- openair1/SCHED/phy_procedures_lte_eNb.c | 551 +- openair1/SCHED/phy_procedures_lte_ue.c | 3 +- openair1/SCHED/ru_procedures.c | 36 +- openair2/ENB_APP/enb_app.c | 6 + openair2/ENB_APP/enb_config.c | 104 +- openair2/LAYER2/MAC/config.c | 919 +- openair2/LAYER2/MAC/eNB_scheduler.c | 166 +- openair2/LAYER2/MAC/eNB_scheduler_RA.c | 225 +- openair2/LAYER2/MAC/eNB_scheduler_bch.c | 95 +- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 32 +- .../LAYER2/MAC/eNB_scheduler_primitives.c | 66 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 112 +- openair2/LAYER2/MAC/main.c | 5 +- openair2/LAYER2/MAC/pre_processor.c | 16 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 2 + openair2/PHY_INTERFACE/IF_Module.c | 380 +- openair2/PHY_INTERFACE/IF_Module.h | 12 +- openair2/RRC/LITE/L2_interface.c | 6 +- openair2/RRC/LITE/rrc_common.c | 4 +- openair2/RRC/LITE/rrc_eNB.c | 5 + openair2/UTIL/LOG/log.c | 354 +- openair2/UTIL/LOG/log.h | 27 +- openair2/UTIL/LOG/vcd_signal_dumper.c | 11 + openair2/UTIL/LOG/vcd_signal_dumper.h | 10 + openair3/GTPV1-U/gtpv1u_eNB.c | 1 + openair3/UDP/udp_eNB_task.c | 2 +- targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp | 12 +- targets/COMMON/create_tasks.c | 2 + .../CONF/enb.band7.tm1.50PRB.usrpb210.conf | 47 +- .../CONF/oaiL1.nfapi.usrpb210.conf | 38 +- .../CONF/rcc.band7.tm1.50PRB.nfapi.conf | 71 +- targets/RT/USER/lte-enb.c | 260 +- targets/RT/USER/lte-ran.c | 7 + targets/RT/USER/lte-ru.c | 212 +- targets/RT/USER/lte-softmodem.c | 124 +- targets/RT/USER/pnf.gtkw | 54 + targets/RT/USER/rt_wrapper.c | 2 + 69 files changed, 26638 insertions(+), 5539 deletions(-) delete mode 100644 nfapi/nfapi_interface.h create mode 100644 nfapi/oai_integration/nfapi.c create mode 100644 nfapi/oai_integration/nfapi_pnf.c create mode 100644 nfapi/oai_integration/nfapi_pnf.h create mode 100644 nfapi/oai_integration/nfapi_vnf.c create mode 100644 nfapi/oai_integration/nfapi_vnf.h create mode 100644 nfapi/oai_integration/vendor_ext.h create mode 100644 nfapi/open-nfapi.oai.patch delete mode 100644 open-nfapi.oai.patch create mode 100644 targets/RT/USER/pnf.gtkw diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index b24db90edb..7b4e30b030 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -27,8 +27,8 @@ cmake_minimum_required (VERSION 2.8) # Base directories, compatible with legacy OAI building ################################################ set (OPENAIR_DIR $ENV{OPENAIR_DIR}) -#set (NFAPI_DIR $ENV{NFAPI_DIR}) -set (NFAPI_DIR ${OPENAIR_DIR}/nfapi) +set (NFAPI_DIR $ENV{NFAPI_DIR}) +set (NFAPI_USER_DIR ${OPENAIR_DIR}/nfapi) set (OPENAIR1_DIR ${OPENAIR_DIR}/openair1) set (OPENAIR2_DIR ${OPENAIR_DIR}/openair2) set (OPENAIR3_DIR ${OPENAIR_DIR}/openair3) @@ -769,7 +769,12 @@ else() include_directories("${OPENAIR2_DIR}/UTIL") include_directories("${OPENAIR2_DIR}/UTIL/LOG") endif() -include_directories("${NFAPI_DIR}") +include_directories("${NFAPI_DIR}/nfapi/public_inc") +include_directories("${NFAPI_DIR}/common/public_inc") +include_directories("${NFAPI_DIR}/pnf/public_inc") +include_directories("${NFAPI_DIR}/nfapi/inc") +include_directories("${NFAPI_DIR}/sim_common/inc") +include_directories("${NFAPI_DIR}/pnf_sim/inc") include_directories("${OPENAIR1_DIR}") include_directories("${OPENAIR2_DIR}/NAS") include_directories("${OPENAIR2_DIR}") @@ -1011,6 +1016,58 @@ set(SCHED_SRC ) add_library(SCHED_LIB ${SCHED_SRC}) +# nFAPI +################################# +set(NFAPI_COMMON_SRC + ${NFAPI_DIR}/common/src/debug.c +) +add_library(NFAPI_COMMON_LIB ${NFAPI_COMMON_SRC}) + +include_directories(${NFAPI_DIR}/common/public_inc) + +set(NFAPI_SRC + ${NFAPI_DIR}/nfapi/src/nfapi.c + ${NFAPI_DIR}/nfapi/src/nfapi_p4.c + ${NFAPI_DIR}/nfapi/src/nfapi_p5.c + ${NFAPI_DIR}/nfapi/src/nfapi_p7.c +) +add_library(NFAPI_LIB ${NFAPI_SRC}) + +include_directories(${NFAPI_DIR}/nfapi/public_inc) +include_directories(${NFAPI_DIR}/nfapi/inc) + +set(NFAPI_PNF_SRC + ${NFAPI_DIR}/pnf/src/pnf.c + ${NFAPI_DIR}/pnf/src/pnf_interface.c + ${NFAPI_DIR}/pnf/src/pnf_p7.c + ${NFAPI_DIR}/pnf/src/pnf_p7_interface.c +) +add_library(NFAPI_PNF_LIB ${NFAPI_PNF_SRC}) + +include_directories(${NFAPI_DIR}/pnf/public_inc) +include_directories(${NFAPI_DIR}/pnf/inc) + +set(NFAPI_VNF_SRC + ${NFAPI_DIR}/vnf/src/vnf.c + ${NFAPI_DIR}/vnf/src/vnf_interface.c + ${NFAPI_DIR}/vnf/src/vnf_p7.c + ${NFAPI_DIR}/vnf/src/vnf_p7_interface.c +) +add_library(NFAPI_VNF_LIB ${NFAPI_VNF_SRC}) + +include_directories(${NFAPI_DIR}/vnf/public_inc) +include_directories(${NFAPI_DIR}/vnf/inc) + +# nFAPI user defined code +############################# +set(NFAPI_USER_SRC +${NFAPI_USER_DIR}/nfapi.c +${NFAPI_USER_DIR}/nfapi_pnf.c +${NFAPI_USER_DIR}/nfapi_vnf.c +) +add_library(NFAPI_USER_LIB ${NFAPI_USER_SRC}) +include_directories(${NFAPI_USER_DIR}) + # Layer 1 ############################# set(PHY_SRC @@ -1206,6 +1263,8 @@ add_library(L2 ${ENB_APP_SRC}) # ${OPENAIR2_DIR}/RRC/L2_INTERFACE/openair_rrc_L2_interface.c) +include_directories(${NFAPI_USER_DIR}) + if (FLEXRAN_AGENT_SB_IF) #Test for adding a shared library @@ -1619,6 +1678,13 @@ add_library(OPENAIR0_LIB ${OPENAIR_TARGETS}/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c ) +include_directories("${NFAPI_DIR}/nfapi/public_inc") +include_directories("${NFAPI_DIR}/common/public_inc") +include_directories("${NFAPI_DIR}/pnf/public_inc") +include_directories("${NFAPI_DIR}/nfapi/inc") +include_directories("${NFAPI_DIR}/sim_common/inc") +include_directories("${NFAPI_DIR}/pnf_sim/inc") + # System packages that are required # We use either the cmake buildin, in ubuntu are in: /usr/share/cmake*/Modules/ # or cmake provide a generic interface to pkg-config that widely used @@ -1674,6 +1740,26 @@ endif() add_definitions("-DNETTLE_VERSION_MAJOR=${NETTLE_VERSION_MAJOR}") add_definitions("-DNETTLE_VERSION_MINOR=${NETTLE_VERSION_MINOR}") +#pkg_search_module(NFAPI nfapi) +#if(NOT ${NFAPI_FOUND}) + #message( FATAL_ERROR "PACKAGE nfapi not found: some targets will fail. Run build_oai -I again!") +#else() + #include_directories(${NFAPI_INCLUDE_DIRS}) + #message( "PACKAGE nfapi!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") + #message( "${NFAPI_INCLUDE_DIR}") + #message( "${NFAPI_COMMON_INCLUDE_DIR}") + #message( "${NFAPI_VNF_INCLUDE_DIR}") + #message( "${NFAPI_PNF_INCLUDE_DIR}") + #message( "XXX") + #message( "${NFAPI_LIBRARY}") + #message( "${NFAPI_COMMON_LIBRARY}") + #message( "${NFAPI_PNF_LIBRARY}") + #message( "XXX") + #message( "${NFAPI_LIBRARIES}") + #message( "XXX") +#endif() + + pkg_search_module(XPM xpm) if(NOT ${XPM_FOUND}) message("PACKAGE xpm not found: some targets will fail") @@ -1729,6 +1815,12 @@ if (${T_TRACER}) set (T_LIB "rt") endif (${T_TRACER}) +#if (${NFAPI_DIR}) +#set (NFAPI_PNF_LIB "nfapi_pnf") +#set (NFAPI_LIB "nfapi") +#set (NFAPI_COMMON_LIB "nfapi_common") +#endif (${NFAPI_DIR}) +# #Some files in the T directory are generated. #This rule and the following deal with it. add_custom_command ( @@ -1785,10 +1877,12 @@ add_executable(lte-softmodem ${SHLIB_LOADER_SOURCES} ) -target_link_libraries (lte-softmodem -ldl +target_link_libraries (lte-softmodem -Wl,--start-group RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 - -Wl,--end-group ) + NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB + NFAPI_USER_LIB + -Wl,--end-group z dl) target_link_libraries (lte-softmodem ${LIBXML2_LIBRARIES}) target_link_libraries (lte-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES}) @@ -1911,22 +2005,44 @@ add_executable(oaisim ${SHLIB_LOADER_SOURCES} ) +#add_library( imp_nfapi STATIC IMPORTED) +#set_property(TARGET imp_nfapi PROPERTY IMPORTED_LOCATION ${NFAPI_DIR}/libnfapi.a) +#set_property(TARGET imp_nfapi PROPERTY IMPORTED_IMPLIB ${NFAPI_DIR}/libnfapi.a) +#target_link_libraries(oaisim imp_nfapi) + +#add_library( imp_nfapi_common STATIC IMPORTED) +#set_property(TARGET imp_nfapi_common PROPERTY IMPORTED_LOCATION ${NFAPI_DIR}/common/libnfapi_common.a) +#set_property(TARGET imp_nfapi_common PROPERTY IMPORTED_IMPLIB ${NFAPI_DIR}/common/libnfapi_common.a) +#target_link_libraries(oaisim imp_nfapi_common) + +#add_library( imp_nfapi_pnf STATIC IMPORTED) +#set_property(TARGET imp_nfapi_pnf PROPERTY IMPORTED_LOCATION ${NFAPI_DIR}/pnf/libnfapi_pnf.a) +#set_property(TARGET imp_nfapi_pnf PROPERTY IMPORTED_IMPLIB ${NFAPI_DIR}/pnf/libnfapi_pnf.a) +#target_link_libraries(oaisim imp_nfapi_pnf) + +# +#add_library (imp_nfapi_common STATIC IMPORTED) +#set_target_properties(imp_nfapi_common PROPERTIES IMPORTED_LOCATION ${NFAPI_DIR}/common/libnfapi_common.a +#set_target_properties(oaisim PROPERTIES LINK_FLAGS ${NFAPI_DIR}/nfapi/libnfapi.a ${NFAPI_DIR}/pnf/libnfapi_pnf.a ${NFAPI_DIR}/common/libnfapi_common.a) + + target_include_directories(oaisim PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim -Wl,-ldl,--start-group RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB GTPV1U SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} LIB_NAS_UE SIMU SECU_OSA ${ITTI_LIB} ${MIH_LIB} + NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB + NFAPI_USER_LIB -Wl,--end-group ) target_link_libraries (oaisim ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) -target_link_libraries (oaisim pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp - ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${OPENPGM_LIBRARIES}) +target_link_libraries (oaisim pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp z + ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${OPENPGM_LIBRARIES} ) #Force link with forms, regardless XFORMS option target_link_libraries (oaisim forms) target_link_libraries (oaisim ${T_LIB}) - # A all in one network simulator ################ add_executable(oaisim_nos1 diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index d625dfa159..7eb583bcfd 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -199,7 +199,7 @@ function main() { GDB=1 CMAKE_BUILD_TYPE="Debug" echo_info "Will Compile with gdb symbols and disable compiler optimization" - CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=Debug" + CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=Debug --trace-expand" shift;; --eNB) eNB=1 diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 8cf0d22e91..e98a2b9fbf 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -230,6 +230,7 @@ install_protobuf_c_from_source(){ rm -rf /tmp/protobuf-c git clone https://github.com/protobuf-c/protobuf-c.git cd protobuf-c + git checkout 2a46af42784abf86804d536f6e0122d47cfeea45 ./autogen.sh ./configure echo "Compiling protobuf-c" diff --git a/common/config/config_userapi.c b/common/config/config_userapi.c index 4e49f2c56a..acee5646cd 100644 --- a/common/config/config_userapi.c +++ b/common/config/config_userapi.c @@ -128,6 +128,7 @@ int config_get(paramdef_t *params,int numparams, char *prefix) { int ret= -1; +printf("numparams:%d prefix:%s\n", numparams, prefix); if (CONFIG_ISFLAGSET(CONFIG_ABORT)) { fprintf(stderr,"[CONFIG] config_get skipped, config module not properly initialized\n"); return ret; diff --git a/nfapi/nfapi_interface.h b/nfapi/nfapi_interface.h deleted file mode 100644 index 45af99a50f..0000000000 --- a/nfapi/nfapi_interface.h +++ /dev/null @@ -1,3855 +0,0 @@ -/* - * Copyright 2017 Cisco Systems, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef _NFAPI_INTERFACE_H_ -#define _NFAPI_INTERFACE_H_ - -#include "stddef.h" - -// Constants - update based on implementation -#define NFAPI_MAX_PHY_RF_INSTANCES 2 -#define NFAPI_PNF_PARAM_GENERAL_LOCATION_LENGTH 16 -#define NFAPI_PNF_PARAM_GENERAL_OUI_LENGTH 3 -#define NFAPI_MAX_NUM_RF_BANDS 16 - -// The following definition control the size of arrays used in the interface. -// These may be changed if desired. They are used in the encoder to make sure -// that the user has not specified a 'count' larger than the max array, and also -// used by the decoder when decode an array. If the 'count' received is larger -// than the array it is to be stored in the decode fails. -#define NFAPI_MAX_NUM_ANTENNAS 8 -#define NFAPI_MAX_NUM_SUBBANDS 13 -#define NFAPI_MAX_BF_VECTORS 8 -#define NFAPI_MAX_CC 2 -#define NFAPI_MAX_NUM_PHYSICAL_ANTENNAS 8 -#define NFAPI_MAX_RSSI 8 -#define NFAPI_MAX_PSC_LIST 32 -#define NFAPI_MAX_PCI_LIST 32 -#define NFAPI_MAX_CARRIER_LIST 32 -#define NFAPI_MAX_ARFCN_LIST 128 -#define NFAPI_MAX_LTE_CELLS_FOUND 8 -#define NFAPI_MAX_UTRAN_CELLS_FOUND 8 -#define NFAPI_MAX_GSM_CELLS_FOUND 8 -#define NFAPI_MAX_NB_IOT_CELLS_FOUND 8 -#define NFAPI_MAX_SI_PERIODICITY 8 -#define NFAPI_MAX_SI_INDEX 8 -#define NFAPI_MAX_MIB_LENGTH 32 -#define NFAPI_MAX_SIB_LENGTH 256 -#define NFAPI_MAX_SI_LENGTH 256 -#define NFAPI_MAX_OPAQUE_DATA 64 -#define NFAPI_MAX_NUM_SCHEDULED_UES 8 // Used in the TPM structure -#define NFAPI_MAX_PNF_PHY 5 -#define NFAPI_MAX_PNF_PHY_RF_CONFIG 5 -#define NFAPI_MAX_PNF_RF 5 -#define NFAPI_MAX_NMM_FREQUENCY_BANDS 32 -#define NFAPI_MAX_RECEIVED_INTERFERENCE_POWER_RESULTS 100 -#define NFAPI_MAX_UL_DL_CONFIGURATIONS 5 -#define NFAPI_MAX_CSI_RS_RESOURCE_CONFIG 4 -#define NFAPI_MAX_ANTENNA_PORT_COUNT 8 -#define NFAPI_MAX_EPDCCH_PRB 8 -#define NFAPI_MAX_TX_PHYSICAL_ANTENNA_PORTS 8 -#define NFAPI_MAX_NUMBER_ACK_NACK_TDD 8 -#define NFAPI_MAX_RO_DL 8 - -#define NFAPI_HEADER_LENGTH 8 -#define NFAPI_P7_HEADER_LENGTH 16 - -#define NFAPI_VENDOR_EXTENSION_MIN_TAG_VALUE 0xF000 -#define NFAPI_VENDOR_EXTENSION_MAX_TAG_VALUE 0xFFFF - -#define NFAPI_VERSION_3_0_11 0x000 -#define NFAPI_VERSION_3_0_12 0x001 - -// The IANA agreed port definition of the P5 SCTP VNF enpoint -// http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=7701 -#define NFAPI_P5_SCTP_PORT 7701 - -typedef unsigned int uint32_t; -typedef unsigned short uint16_t; -typedef unsigned char uint8_t; -typedef signed int int32_t; -typedef signed short int16_t; -typedef signed char int8_t; - -typedef struct { - uint16_t phy_id; - uint16_t message_id; - uint16_t message_length; - uint16_t spare; -} nfapi_p4_p5_message_header_t; - -typedef struct { - uint16_t phy_id; - uint16_t message_id; - uint16_t message_length; - uint16_t m_segment_sequence; /* This consists of 3 fields - namely, M, Segement & Sequence number*/ - uint32_t checksum; - uint32_t transmit_timestamp; -} nfapi_p7_message_header_t; - -#define NFAPI_PHY_ID_NA 0 - -//#define NFAPI_P7_GET_MORE(_mss) ( ((_mss) & 0x80) >> 7 ) -//#define NFAPI_P7_GET_SEGMENT(_mss) ( ((_mss) & 0x70) >> 4 ) -#define NFAPI_P7_GET_MORE(_mss) ( ((_mss) & 0x8000) >> 15 ) -#define NFAPI_P7_GET_SEGMENT(_mss) ( ((_mss) & 0x7F00) >> 8 ) -#define NFAPI_P7_GET_SEQUENCE(_mss) ( (_mss) & 0x00FF ) -#define NFAPI_P7_SET_MSS(_more, _segm, _sequ) ( (((_more) & 0x1) << 7) | (((_segm) & 0x7) << 4) | ((_sequ) & 0xF) ) - -typedef struct { - uint16_t tag; - uint16_t length; -} nfapi_tl_t; -#define NFAPI_TAG_LENGTH_PACKED_LEN 4 - -// Convenience methods to convert between SFN/SFN formats -#define NFAPI_SFNSF2DEC(_sfnsf) ((((_sfnsf) >> 4) * 10) + ((_sfnsf) & 0xF)) -#define NFAPI_SFNSFDEC2SFNSF(_sfnsf_dec) ((((_sfnsf_dec) / 10) << 4) | (((_sfnsf_dec) - (((_sfnsf_dec) / 10) * 10)) & 0xF)) - -#define NFAPI_SFNSF2SFN(_sfnsf) ((_sfnsf) >> 4) -#define NFAPI_SFNSF2SF(_sfnsf) ((_sfnsf) & 0xF) - -#define NFAPI_MAX_SFNSFDEC 10240 - -typedef nfapi_tl_t* nfapi_vendor_extension_tlv_t; - - -// nFAPI Message IDs -typedef enum { - NFAPI_DL_CONFIG_REQUEST = 0x0080, - NFAPI_UL_CONFIG_REQUEST, - NFAPI_SUBFRAME_INDICATION, - NFAPI_HI_DCI0_REQUEST, - NFAPI_TX_REQUEST, - NFAPI_HARQ_INDICATION, - NFAPI_CRC_INDICATION, - NFAPI_RX_ULSCH_INDICATION, - NFAPI_RACH_INDICATION, - NFAPI_SRS_INDICATION, - NFAPI_RX_SR_INDICATION, - NFAPI_RX_CQI_INDICATION, - NFAPI_LBT_DL_CONFIG_REQUEST, - NFAPI_LBT_DL_INDICATION, - NFAPI_NB_HARQ_INDICATION, - NFAPI_NRACH_INDICATION, - - NFAPI_PNF_PARAM_REQUEST = 0x0100, - NFAPI_PNF_PARAM_RESPONSE, - NFAPI_PNF_CONFIG_REQUEST, - NFAPI_PNF_CONFIG_RESPONSE, - NFAPI_PNF_START_REQUEST, - NFAPI_PNF_START_RESPONSE, - NFAPI_PNF_STOP_REQUEST, - NFAPI_PNF_STOP_RESPONSE, - NFAPI_PARAM_REQUEST, - NFAPI_PARAM_RESPONSE, - NFAPI_CONFIG_REQUEST, - NFAPI_CONFIG_RESPONSE, - NFAPI_START_REQUEST, - NFAPI_START_RESPONSE, - NFAPI_STOP_REQUEST, - NFAPI_STOP_RESPONSE, - NFAPI_MEASUREMENT_REQUEST, - NFAPI_MEASUREMENT_RESPONSE, - - NFAPI_UL_NODE_SYNC = 0x0180, - NFAPI_DL_NODE_SYNC, - NFAPI_TIMING_INFO, - - - NFAPI_RSSI_REQUEST = 0x0200, - NFAPI_RSSI_RESPONSE, - NFAPI_RSSI_INDICATION, - NFAPI_CELL_SEARCH_REQUEST, - NFAPI_CELL_SEARCH_RESPONSE, - NFAPI_CELL_SEARCH_INDICATION, - NFAPI_BROADCAST_DETECT_REQUEST, - NFAPI_BROADCAST_DETECT_RESPONSE, - NFAPI_BROADCAST_DETECT_INDICATION, - NFAPI_SYSTEM_INFORMATION_SCHEDULE_REQUEST, - NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE, - NFAPI_SYSTEM_INFORMATION_SCHEDULE_INDICATION, - NFAPI_SYSTEM_INFORMATION_REQUEST, - NFAPI_SYSTEM_INFORMATION_RESPONSE, - NFAPI_SYSTEM_INFORMATION_INDICATION, - NFAPI_NMM_STOP_REQUEST, - NFAPI_NMM_STOP_RESPONSE, - - NFAPI_VENDOR_EXT_MSG_MIN = 0x0300, - NFAPI_VENDOR_EXT_MSG_MAX = 0x03FF, - - - NFAPI_MAX_MESSAGE_ID, -} nfapi_message_id_e; - -// nFAPI Error Codes -typedef enum { - NFAPI_MSG_OK = 0, - NFAPI_MSG_INVALID_STATE, - NFAPI_MSG_INVALID_CONFIG, - NFAPI_SFN_OUT_OF_SYNC, - NFAPI_MSG_SUBFRAME_ERR, - NFAPI_MSG_BCH_MISSING, - NFAPI_MSG_INVALID_SFN, - NFAPI_MSG_HI_ERR, - NFAPI_MSG_TX_ERR, - - NFAPI_LBT_NO_PDU_IN_DL_REQ, - NFAPI_LBT_NO_VALID_CONFIG_REQ_RECEIVED, - NFAPI_FAPI_E_LBT_SF_SFN_PASSED_END_SF_SFN, - NFAPI_FAPI_E_LBT_OVERLAP, - NFAPI_MSG_BCH_PRESENT, - - NFAPI_NBIOT_UNEXPECTED_REQ, - - // This is special return code that indicates that a response has - // been send via P9 - NFAPI_MSG_P9_RESPONSE = 0xAA -} nfapi_error_code_e; - - -typedef enum { - NFAPI_P4_MSG_OK = 100, - NFAPI_P4_MSG_INVALID_STATE = 101, - NFAPI_P4_MSG_INVALID_CONFIG = 102, - NFAPI_P4_MSG_RAT_NOT_SUPPORTED = 103, - NFAPI_P4_MSG_NMM_STOP_OK = 200, - NFAPI_P4_MSG_NMM_STOP_IGNOREDED = 201, - NFAPI_P4_MSG_NMM_STOP_INVALID_STATE = 202, - NFAPI_P4_MSG_PROCEDURE_COMPLETE = 300, - NFAPI_P4_MSG_PROCEDURE_STOPPED = 301, - NFAPI_P4_MSG_PARTIAL_RESULTS = 302, - NFAPI_P4_MSG_TIMEOUT = 303 -} nfapi_p4_error_code_e; - -// nFAPI enums -typedef enum { - NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE = 0, - NFAPI_DL_CONFIG_BCH_PDU_TYPE, - NFAPI_DL_CONFIG_MCH_PDU_TYPE, - NFAPI_DL_CONFIG_DLSCH_PDU_TYPE, - NFAPI_DL_CONFIG_PCH_PDU_TYPE, - NFAPI_DL_CONFIG_PRS_PDU_TYPE, - NFAPI_DL_CONFIG_CSI_RS_PDU_TYPE, - NFAPI_DL_CONFIG_EPDCCH_DL_PDU_TYPE, - NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE, - NFAPI_DL_CONFIG_NBCH_PDU_TYPE, - NFAPI_DL_CONFIG_NPDCCH_PDU_TYPE, - NFAPI_DL_CONFIG_NDLSCH_PDU_TYPE -} nfapi_dl_config_pdu_type_e; - -typedef enum { - NFAPI_DL_DCI_FORMAT_1 = 0, - NFAPI_DL_DCI_FORMAT_1A, - NFAPI_DL_DCI_FORMAT_1B, - NFAPI_DL_DCI_FORMAT_1C, - NFAPI_DL_DCI_FORMAT_1D, - NFAPI_DL_DCI_FORMAT_2, - NFAPI_DL_DCI_FORMAT_2A, - NFAPI_DL_DCI_FORMAT_2B, - NFAPI_DL_DCI_FORMAT_2C -} nfapi_dl_dci_format_e; - -typedef enum { - NFAPI_UL_DCI_FORMAT_0 = 0, - NFAPI_UL_DCI_FORMAT_3, - NFAPI_UL_DCI_FORMAT_3A, - NFAPI_UL_DCI_FORMAT_4 -} nfapi_ul_dci_format_e; - -typedef enum { - NFAPI_UL_CONFIG_ULSCH_PDU_TYPE = 0, - NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE, - NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE, - NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE, - NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE, - NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE, - NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE, - NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE, - NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE, - NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE, - NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE, - NFAPI_UL_CONFIG_SRS_PDU_TYPE, - NFAPI_UL_CONFIG_HARQ_BUFFER_PDU_TYPE, - NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE, - NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE, - NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE, - NFAPI_UL_CONFIG_NULSCH_PDU_TYPE, - NFAPI_UL_CONFIG_NRACH_PDU_TYPE, -} nfapi_ul_config_pdu_type_e; - -typedef enum { - NFAPI_HI_DCI0_HI_PDU_TYPE = 0, - NFAPI_HI_DCI0_DCI_PDU_TYPE, - NFAPI_HI_DCI0_EPDCCH_DCI_PDU_TYPE, - NFAPI_HI_DCI0_MPDCCH_DCI_PDU_TYPE, - NFAPI_HI_DCI0_NPDCCH_DCI_PDU_TYPE, -} nfapi_hi_dci0_pdu_type_e; - -typedef enum { - NFAPI_HARQ_ACK = 1, - NFAPI_HARQ_NACK, - NFAPI_HARQ_ACK_OR_NACK, - NFAPI_HARQ_DTX, - NFAPI_HARQ_ACK_OR_DTX, - NFAPI_HARQ_NACK_OR_DTX, - NFAPI_HARQ_ACK_OR_NACK_OR_DTX -} nfapi_harq_type_e; - -typedef enum { - NFAPI_CSI_REPORT_TYPE_PERIODIC = 0, - NFAPI_CSI_REPORT_TYPE_APERIODIC -} nfapi_csi_report_type_e; - -typedef enum { - NFAPI_DL_BW_SUPPORTED_6 = 1, - NFAPI_DL_BW_SUPPORTED_15 = 2, - NFAPI_DL_BW_SUPPORTED_25 = 4, - NFAPI_DL_BW_SUPPORTED_50 = 8, - NFAPI_DL_BW_SUPPORTED_75 = 16, - NFAPI_DL_BW_SUPPORTED_100 = 32 -} nfapi_dl_bandwith_supported_e; - -typedef enum { - NFAPI_UL_BW_SUPPORTED_6 = 1, - NFAPI_UL_BW_SUPPORTED_15 = 2, - NFAPI_UL_BW_SUPPORTED_25 = 4, - NFAPI_UL_BW_SUPPORTED_50 = 8, - NFAPI_UL_BW_SUPPORTED_75 = 16, - NFAPI_UL_BW_SUPPORTED_100 = 32 -} nfapi_ul_bandwith_supported_e; - -typedef enum { - NFAPI_3GPP_REL_SUPPORTED_8 = 0, - NFAPI_3GPP_REL_SUPPORTED_9 = 1, - NFAPI_3GPP_REL_SUPPORTED_10 = 2, - NFAPI_3GPP_REL_SUPPORTED_11 = 4, - NFAPI_3GPP_REL_SUPPORTED_12 = 8 -} nfapi_3gpp_release_supported_e; - - -typedef enum { - NFAPI_DUPLEXING_MODE_TDD = 0, - NFAPI_DUPLEXING_MODE_FDD = 1, - NFAPI_DUPLEXING_MODE_HD_FDD = 2, -} nfapi_duplexing_mode_e; - -typedef enum { - NFAPI_CP_NORMAL = 0, - NFAPI_CP_EXTENDED = 1 -} nfapi_cyclic_prefix_type_e; - -typedef enum { - NFAPI_RAT_TYPE_LTE = 0, - NFAPI_RAT_TYPE_UTRAN = 1, - NFAPI_RAT_TYPE_GERAN = 2, - NFAPI_RAT_TYPE_NB_IOT = 3 -} nfapi_rat_type_e; - -typedef enum { - NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_BUNDLING, - NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_MULIPLEXING, - NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_SPECIAL_BUNDLING, - NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_CHANNEL_SELECTION, - NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_3, - NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_4, - NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_5 -} nfapi_harq_indication_tdd_ack_nackformat_e; - - -typedef enum { - NFAPI_LBT_DL_CONFIG_REQUEST_PDSCH_PDU_TYPE = 0, - NFAPI_LBT_DL_CONFIG_REQUEST_DRS_PDU_TYPE -} nfapi_lbt_dl_config_pdu_type_e; - -typedef enum { - NFAPI_LBT_DL_RSP_PDSCH_PDU_TYPE = 0, - NFAPI_LBT_DL_RSP_DRS_PDU_TYPE -} nfapi_lbt_dl_rsp_pdu_type_e; - -typedef struct { - nfapi_tl_t tl; - uint32_t length; - uint8_t value[NFAPI_MAX_OPAQUE_DATA]; -} nfapi_opaqaue_data_t; - -// Utility functions to turn enums into char* -const char* nfapi_error_code_to_str(nfapi_error_code_e value); - - -// P5 Sub Structures -typedef struct { - nfapi_tl_t tl; - uint8_t nfapi_sync_mode; - uint8_t location_mode; - uint16_t location_coordinates_length; - uint8_t location_coordinates[NFAPI_PNF_PARAM_GENERAL_LOCATION_LENGTH]; - uint32_t dl_config_timing; - uint32_t tx_timing; - uint32_t ul_config_timing; - uint32_t hi_dci0_timing; - uint16_t maximum_number_phys; - uint16_t maximum_total_bandwidth; - uint8_t maximum_total_number_dl_layers; - uint8_t maximum_total_number_ul_layers; - uint8_t shared_bands; - uint8_t shared_pa; - int16_t maximum_total_power; - uint8_t oui[NFAPI_PNF_PARAM_GENERAL_OUI_LENGTH]; -} nfapi_pnf_param_general_t; -#define NFAPI_PNF_PARAM_GENERAL_TAG 0x1000 - - - - - -typedef struct { - uint16_t rf_config_index; -} nfapi_rf_config_info_t; - -typedef struct { - uint16_t phy_config_index; - uint16_t number_of_rfs; - nfapi_rf_config_info_t rf_config[NFAPI_MAX_PNF_PHY_RF_CONFIG]; - uint16_t number_of_rf_exclusions; - nfapi_rf_config_info_t excluded_rf_config[NFAPI_MAX_PNF_PHY_RF_CONFIG]; - uint16_t downlink_channel_bandwidth_supported; - uint16_t uplink_channel_bandwidth_supported; - uint8_t number_of_dl_layers_supported; - uint8_t number_of_ul_layers_supported; - uint16_t maximum_3gpp_release_supported; - uint8_t nmm_modes_supported; -} nfapi_pnf_phy_info_t; - - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_phys; - nfapi_pnf_phy_info_t phy[NFAPI_MAX_PNF_PHY]; -} nfapi_pnf_phy_t; -#define NFAPI_PNF_PHY_TAG 0x1001 - -typedef struct { - uint16_t phy_config_index; - uint16_t transmission_mode_7_supported; - uint16_t transmission_mode_8_supported; - uint16_t two_antenna_ports_for_pucch; - uint16_t transmission_mode_9_supported; - uint16_t simultaneous_pucch_pusch; - uint16_t four_layer_tx_with_tm3_and_tm4; -} nfapi_pnf_phy_rel10_info_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_phys; - nfapi_pnf_phy_rel10_info_t phy[NFAPI_MAX_PNF_PHY]; -} nfapi_pnf_phy_rel10_t; -#define NFAPI_PNF_PHY_REL10_TAG 0x100A - -typedef struct { - uint16_t phy_config_index; - uint16_t edpcch_supported; - uint16_t multi_ack_csi_reporting; - uint16_t pucch_tx_diversity; - uint16_t ul_comp_supported; - uint16_t transmission_mode_5_supported; -} nfapi_pnf_phy_rel11_info_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_phys; - nfapi_pnf_phy_rel11_info_t phy[NFAPI_MAX_PNF_PHY]; -} nfapi_pnf_phy_rel11_t; -#define NFAPI_PNF_PHY_REL11_TAG 0x100B - - -typedef struct { - uint16_t phy_config_index; - uint16_t csi_subframe_set; - uint16_t enhanced_4tx_codebook; - uint16_t drs_supported; - uint16_t ul_64qam_supported; - uint16_t transmission_mode_10_supported; - uint16_t alternative_bts_indices; -} nfapi_pnf_phy_rel12_info_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_phys; - nfapi_pnf_phy_rel12_info_t phy[NFAPI_MAX_PNF_PHY]; -} nfapi_pnf_phy_rel12_t; -#define NFAPI_PNF_PHY_REL12_TAG 0x100C - -typedef struct { - uint16_t phy_config_index; - uint16_t pucch_format4_supported; - uint16_t pucch_format5_supported; - uint16_t more_than_5_ca_support; - uint16_t laa_supported; - uint16_t laa_ending_in_dwpts_supported; - uint16_t laa_starting_in_second_slot_supported; - uint16_t beamforming_supported; - uint16_t csi_rs_enhancement_supported; - uint16_t drms_enhancement_supported; - uint16_t srs_enhancement_supported; -} nfapi_pnf_phy_rel13_info_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_phys; - nfapi_pnf_phy_rel13_info_t phy[NFAPI_MAX_PNF_PHY]; -} nfapi_pnf_phy_rel13_t; -#define NFAPI_PNF_PHY_REL13_TAG 0x100D - -typedef struct { - uint16_t phy_config_index; - uint16_t number_of_rfs; - nfapi_rf_config_info_t rf_config[NFAPI_MAX_PNF_PHY_RF_CONFIG]; - uint16_t number_of_rf_exclusions; - nfapi_rf_config_info_t excluded_rf_config[NFAPI_MAX_PNF_PHY_RF_CONFIG]; - uint8_t number_of_dl_layers_supported; - uint8_t number_of_ul_layers_supported; - uint16_t maximum_3gpp_release_supported; - uint8_t nmm_modes_supported; -} nfapi_pnf_phy_rel13_nb_iot_info_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_phys; - nfapi_pnf_phy_rel13_nb_iot_info_t phy[NFAPI_MAX_PNF_PHY]; -} nfapi_pnf_phy_rel13_nb_iot_t; -#define NFAPI_PNF_PHY_REL13_NB_IOT_TAG 0x100E - - - -typedef struct { - uint16_t rf_config_index; - uint16_t band; - int16_t maximum_transmit_power; - int16_t minimum_transmit_power; - uint8_t number_of_antennas_suppported; - uint32_t minimum_downlink_frequency; - uint32_t maximum_downlink_frequency; - uint32_t minimum_uplink_frequency; - uint32_t maximum_uplink_frequency; -} nfapi_pnf_rf_info_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_rfs; - nfapi_pnf_rf_info_t rf[NFAPI_MAX_PNF_RF]; -} nfapi_pnf_rf_t; -#define NFAPI_PNF_RF_TAG 0x1002 - -typedef struct { - uint16_t phy_id; - uint16_t phy_config_index; - uint16_t rf_config_index; -} nfapi_phy_rf_config_info_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t number_phy_rf_config_info; - nfapi_phy_rf_config_info_t phy_rf_config[NFAPI_MAX_PHY_RF_INSTANCES]; -} nfapi_pnf_phy_rf_config_t; -#define NFAPI_PNF_PHY_RF_TAG 0x1003 - -// Generic strucutre for single tlv value. -typedef struct { - nfapi_tl_t tl; - uint16_t value; -} nfapi_uint16_tlv_t; - -typedef struct { - nfapi_tl_t tl; - int16_t value; -} nfapi_int16_tlv_t; - -typedef struct { - nfapi_tl_t tl; - uint8_t value; -} nfapi_uint8_tlv_t; - -typedef struct { - nfapi_uint16_tlv_t phy_state; -} nfapi_l1_status; - -#define NFAPI_L1_STATUS_PHY_STATE_TAG 0x00FA - -typedef struct { - nfapi_uint16_tlv_t dl_bandwidth_support; - nfapi_uint16_tlv_t ul_bandwidth_support; - nfapi_uint16_tlv_t dl_modulation_support; - nfapi_uint16_tlv_t ul_modulation_support; - nfapi_uint16_tlv_t phy_antenna_capability; - nfapi_uint16_tlv_t release_capability; - nfapi_uint16_tlv_t mbsfn_capability; -} nfapi_phy_capabilities_t; - -#define NFAPI_PHY_CAPABILITIES_DL_BANDWIDTH_SUPPORT_TAG 0x00C8 -#define NFAPI_PHY_CAPABILITIES_UL_BANDWIDTH_SUPPORT_TAG 0x00C9 -#define NFAPI_PHY_CAPABILITIES_DL_MODULATION_SUPPORT_TAG 0x00CA -#define NFAPI_PHY_CAPABILITIES_UL_MODULATION_SUPPORT_TAG 0x00CB -#define NFAPI_PHY_CAPABILITIES_PHY_ANTENNA_CAPABILITY_TAG 0x00CC -#define NFAPI_PHY_CAPABILITIES_RELEASE_CAPABILITY_TAG 0x00CD -#define NFAPI_PHY_CAPABILITIES_MBSFN_CAPABILITY_TAG 0x00CE - - -typedef struct { - nfapi_uint16_tlv_t data_report_mode; - nfapi_uint16_tlv_t sfnsf; -} nfapi_l23_config_t; - - -#define NFAPI_L23_CONFIG_DATA_REPORT_MODE_TAG 0x00F0 -#define NFAPI_L23_CONFIG_SFNSF_TAG 0x00F1 - -typedef struct { - nfapi_uint16_tlv_t duplex_mode; - nfapi_uint16_tlv_t pcfich_power_offset; - nfapi_uint16_tlv_t pb; - nfapi_uint16_tlv_t dl_cyclic_prefix_type; - nfapi_uint16_tlv_t ul_cyclic_prefix_type; -} nfapi_subframe_config_t; - -#define NFAPI_SUBFRAME_CONFIG_DUPLEX_MODE_TAG 0x0001 -#define NFAPI_SUBFRAME_CONFIG_PCFICH_POWER_OFFSET_TAG 0x0002 -#define NFAPI_SUBFRAME_CONFIG_PB_TAG 0x0003 -#define NFAPI_SUBFRAME_CONFIG_DL_CYCLIC_PREFIX_TYPE_TAG 0x0004 -#define NFAPI_SUBFRAME_CONFIG_UL_CYCLIC_PREFIX_TYPE_TAG 0x0005 - -typedef struct { - nfapi_uint16_tlv_t dl_channel_bandwidth; - nfapi_uint16_tlv_t ul_channel_bandwidth; - nfapi_uint16_tlv_t reference_signal_power; - nfapi_uint16_tlv_t tx_antenna_ports; - nfapi_uint16_tlv_t rx_antenna_ports; -} nfapi_rf_config_t; - -#define NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG 0x000A -#define NFAPI_RF_CONFIG_UL_CHANNEL_BANDWIDTH_TAG 0x000B -#define NFAPI_RF_CONFIG_REFERENCE_SIGNAL_POWER_TAG 0x000C -#define NFAPI_RF_CONFIG_TX_ANTENNA_PORTS_TAG 0x000D -#define NFAPI_RF_CONFIG_RX_ANTENNA_PORTS_TAG 0x000E - -typedef struct { - nfapi_uint16_tlv_t phich_resource; - nfapi_uint16_tlv_t phich_duration; - nfapi_uint16_tlv_t phich_power_offset; -} nfapi_phich_config_t; - -#define NFAPI_PHICH_CONFIG_PHICH_RESOURCE_TAG 0x0014 -#define NFAPI_PHICH_CONFIG_PHICH_DURATION_TAG 0x0015 -#define NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG 0x0016 - -typedef struct { - nfapi_uint16_tlv_t primary_synchronization_signal_epre_eprers; - nfapi_uint16_tlv_t secondary_synchronization_signal_epre_eprers; - nfapi_uint16_tlv_t physical_cell_id; -} nfapi_sch_config_t; - -#define NFAPI_SCH_CONFIG_PRIMARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG 0x001E -#define NFAPI_SCH_CONFIG_SECONDARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG 0x001F -#define NFAPI_SCH_CONFIG_PHYSICAL_CELL_ID_TAG 0x0020 - -typedef struct { - nfapi_uint16_tlv_t configuration_index; - nfapi_uint16_tlv_t root_sequence_index; - nfapi_uint16_tlv_t zero_correlation_zone_configuration; - nfapi_uint16_tlv_t high_speed_flag; - nfapi_uint16_tlv_t frequency_offset; -} nfapi_prach_config_t; - -#define NFAPI_PRACH_CONFIG_CONFIGURATION_INDEX_TAG 0x0028 -#define NFAPI_PRACH_CONFIG_ROOT_SEQUENCE_INDEX_TAG 0x0029 -#define NFAPI_PRACH_CONFIG_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG 0x002A -#define NFAPI_PRACH_CONFIG_HIGH_SPEED_FLAG_TAG 0x002B -#define NFAPI_PRACH_CONFIG_FREQUENCY_OFFSET_TAG 0x002C - -typedef struct { - nfapi_uint16_tlv_t hopping_mode; - nfapi_uint16_tlv_t hopping_offset; - nfapi_uint16_tlv_t number_of_subbands; -} nfapi_pusch_config_t; - -#define NFAPI_PUSCH_CONFIG_HOPPING_MODE_TAG 0x0032 -#define NFAPI_PUSCH_CONFIG_HOPPING_OFFSET_TAG 0x0033 -#define NFAPI_PUSCH_CONFIG_NUMBER_OF_SUBBANDS_TAG 0x0034 - -typedef struct { - nfapi_uint16_tlv_t delta_pucch_shift; - nfapi_uint16_tlv_t n_cqi_rb; - nfapi_uint16_tlv_t n_an_cs; - nfapi_uint16_tlv_t n1_pucch_an; -} nfapi_pucch_config_t; - -#define NFAPI_PUCCH_CONFIG_DELTA_PUCCH_SHIFT_TAG 0x003C -#define NFAPI_PUCCH_CONFIG_N_CQI_RB_TAG 0x003D -#define NFAPI_PUCCH_CONFIG_N_AN_CS_TAG 0x003E -#define NFAPI_PUCCH_CONFIG_N1_PUCCH_AN_TAG 0x003F - -typedef struct { - nfapi_uint16_tlv_t bandwidth_configuration; - nfapi_uint16_tlv_t max_up_pts; - nfapi_uint16_tlv_t srs_subframe_configuration; - nfapi_uint16_tlv_t srs_acknack_srs_simultaneous_transmission; -} nfapi_srs_config_t; - -#define NFAPI_SRS_CONFIG_BANDWIDTH_CONFIGURATION_TAG 0x0046 -#define NFAPI_SRS_CONFIG_MAX_UP_PTS_TAG 0x0047 -#define NFAPI_SRS_CONFIG_SRS_SUBFRAME_CONFIGURATION_TAG 0x0048 -#define NFAPI_SRS_CONFIG_SRS_ACKNACK_SRS_SIMULTANEOUS_TRANSMISSION_TAG 0x0049 - -typedef struct { - nfapi_uint16_tlv_t uplink_rs_hopping; - nfapi_uint16_tlv_t group_assignment; - nfapi_uint16_tlv_t cyclic_shift_1_for_drms; -} nfapi_uplink_reference_signal_config_t; - -#define NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_UPLINK_RS_HOPPING_TAG 0x0050 -#define NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_GROUP_ASSIGNMENT_TAG 0x0051 -#define NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_CYCLIC_SHIFT_1_FOR_DRMS_TAG 0x0052 - - -typedef struct { - nfapi_uint16_tlv_t ed_threshold_lbt_pdsch; - nfapi_uint16_tlv_t ed_threshold_lbt_drs; - nfapi_uint16_tlv_t pd_threshold; - nfapi_uint16_tlv_t multi_carrier_type; - nfapi_uint16_tlv_t multi_carrier_tx; - nfapi_uint16_tlv_t multi_carrier_freeze; - nfapi_uint16_tlv_t tx_antenna_ports_drs; - nfapi_uint16_tlv_t tx_power_drs; -} nfapi_laa_config_t; - -#define NFAPI_LAA_CONFIG_ED_THRESHOLD_FOR_LBT_FOR_PDSCH_TAG 0x0064 -#define NFAPI_LAA_CONFIG_ED_THRESHOLD_FOR_LBT_FOR_DRS_TAG 0x0065 -#define NFAPI_LAA_CONFIG_PD_THRESHOLD_TAG 0x0066 -#define NFAPI_LAA_CONFIG_MULTI_CARRIER_TYPE_TAG 0x0067 -#define NFAPI_LAA_CONFIG_MULTI_CARRIER_TX_TAG 0x0068 -#define NFAPI_LAA_CONFIG_MULTI_CARRIER_FREEZE_TAG 0x0069 -#define NFAPI_LAA_CONFIG_TX_ANTENNA_PORTS_FOR_DRS_TAG 0x006A -#define NFAPI_LAA_CONFIG_TRANSMISSION_POWER_FOR_DRS_TAG 0x006B - -typedef struct { - - nfapi_uint16_tlv_t pbch_repetitions_enable_r13; - nfapi_uint16_tlv_t prach_catm_root_sequence_index; - nfapi_uint16_tlv_t prach_catm_zero_correlation_zone_configuration; - nfapi_uint16_tlv_t prach_catm_high_speed_flag; - nfapi_uint16_tlv_t prach_ce_level_0_enable; - nfapi_uint16_tlv_t prach_ce_level_0_configuration_index; - nfapi_uint16_tlv_t prach_ce_level_0_frequency_offset; - nfapi_uint16_tlv_t prach_ce_level_0_number_of_repetitions_per_attempt; - nfapi_uint16_tlv_t prach_ce_level_0_starting_subframe_periodicity; - nfapi_uint16_tlv_t prach_ce_level_0_hopping_enable; - nfapi_uint16_tlv_t prach_ce_level_0_hopping_offset; - nfapi_uint16_tlv_t prach_ce_level_1_enable; - nfapi_uint16_tlv_t prach_ce_level_1_configuration_index; - nfapi_uint16_tlv_t prach_ce_level_1_frequency_offset; - nfapi_uint16_tlv_t prach_ce_level_1_number_of_repetitions_per_attempt; - nfapi_uint16_tlv_t prach_ce_level_1_starting_subframe_periodicity; - nfapi_uint16_tlv_t prach_ce_level_1_hopping_enable; - nfapi_uint16_tlv_t prach_ce_level_1_hopping_offset; - nfapi_uint16_tlv_t prach_ce_level_2_enable; - nfapi_uint16_tlv_t prach_ce_level_2_configuration_index; - nfapi_uint16_tlv_t prach_ce_level_2_frequency_offset; - nfapi_uint16_tlv_t prach_ce_level_2_number_of_repetitions_per_attempt; - nfapi_uint16_tlv_t prach_ce_level_2_starting_subframe_periodicity; - nfapi_uint16_tlv_t prach_ce_level_2_hopping_enable; - nfapi_uint16_tlv_t prach_ce_level_2_hopping_offset; - nfapi_uint16_tlv_t prach_ce_level_3_enable; - nfapi_uint16_tlv_t prach_ce_level_3_configuration_index; - nfapi_uint16_tlv_t prach_ce_level_3_frequency_offset; - nfapi_uint16_tlv_t prach_ce_level_3_number_of_repetitions_per_attempt; - nfapi_uint16_tlv_t prach_ce_level_3_starting_subframe_periodicity; - nfapi_uint16_tlv_t prach_ce_level_3_hopping_enable; - nfapi_uint16_tlv_t prach_ce_level_3_hopping_offset; - nfapi_uint16_tlv_t pucch_interval_ulhoppingconfigcommonmodea; - nfapi_uint16_tlv_t pucch_interval_ulhoppingconfigcommonmodeb; -} nfapi_emtc_config_t; - -#define NFAPI_EMTC_CONFIG_PBCH_REPETITIONS_ENABLE_R13_TAG 0x0078 -#define NFAPI_EMTC_CONFIG_PRACH_CATM_ROOT_SEQUENCE_INDEX_TAG 0x0079 -#define NFAPI_EMTC_CONFIG_PRACH_CATM_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG 0x007A -#define NFAPI_EMTC_CONFIG_PRACH_CATM_HIGH_SPEED_FLAG 0x007B -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_ENABLE_TAG 0x007C -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_CONFIGURATION_INDEX_TAG 0x007D -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_FREQUENCY_OFFSET_TAG 0x007E -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x007F -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_STARTING_SUBFRAME_PERIODICITY_TAG 0x0080 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_ENABLE_TAG 0x0081 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_OFFSET_TAG 0x0082 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_ENABLE_TAG 0x0083 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_CONFIGURATION_INDEX_TAG 0x0084 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_FREQUENCY_OFFSET_TAG 0x0085 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x0086 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_STARTING_SUBFRAME_PERIODICITY_TAG 0x0087 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_ENABLE_TAG 0x0088 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_OFFSET_TAG 0x0089 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_ENABLE_TAG 0x008A -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_CONFIGURATION_INDEX_TAG 0x008B -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_FREQUENCY_OFFSET_TAG 0x008C -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x008D -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_STARTING_SUBFRAME_PERIODICITY_TAG 0x008E -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_ENABLE_TAG 0x008F -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_OFFSET_TAG 0x0090 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_ENABLE_TAG 0x0091 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_CONFIGURATION_INDEX_TAG 0x0092 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_FREQUENCY_OFFSET_TAG 0x0093 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x0094 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_STARTING_SUBFRAME_PERIODICITY_TAG 0x0095 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_ENABLE_TAG 0x0096 -#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_OFFSET_TAG 0x0097 -#define NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEA_TAG 0x0098 -#define NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEB_TAG 0x0099 - -typedef struct { - nfapi_uint16_tlv_t operating_mode; - nfapi_uint16_tlv_t anchor; - nfapi_uint16_tlv_t prb_index; - nfapi_uint16_tlv_t control_region_size; - nfapi_uint16_tlv_t assumed_crs_aps; - nfapi_uint16_tlv_t nprach_config_0_enabled; - nfapi_uint16_tlv_t nprach_config_0_sf_periodicity; - nfapi_uint16_tlv_t nprach_config_0_start_time; - nfapi_uint16_tlv_t nprach_config_0_subcarrier_offset; - nfapi_uint16_tlv_t nprach_config_0_number_of_subcarriers; - nfapi_uint16_tlv_t nprach_config_0_cp_length; - nfapi_uint16_tlv_t nprach_config_0_number_of_repetitions_per_attempt; - nfapi_uint16_tlv_t nprach_config_1_enabled; - nfapi_uint16_tlv_t nprach_config_1_sf_periodicity; - nfapi_uint16_tlv_t nprach_config_1_start_time; - nfapi_uint16_tlv_t nprach_config_1_subcarrier_offset; - nfapi_uint16_tlv_t nprach_config_1_number_of_subcarriers; - nfapi_uint16_tlv_t nprach_config_1_cp_length; - nfapi_uint16_tlv_t nprach_config_1_number_of_repetitions_per_attempt; - nfapi_uint16_tlv_t nprach_config_2_enabled; - nfapi_uint16_tlv_t nprach_config_2_sf_periodicity; - nfapi_uint16_tlv_t nprach_config_2_start_time; - nfapi_uint16_tlv_t nprach_config_2_subcarrier_offset; - nfapi_uint16_tlv_t nprach_config_2_number_of_subcarriers; - nfapi_uint16_tlv_t nprach_config_2_cp_length; - nfapi_uint16_tlv_t nprach_config_2_number_of_repetitions_per_attempt; - nfapi_uint16_tlv_t three_tone_base_sequence; - nfapi_uint16_tlv_t six_tone_base_sequence; - nfapi_uint16_tlv_t twelve_tone_base_sequence; - nfapi_uint16_tlv_t three_tone_cyclic_shift; - nfapi_uint16_tlv_t six_tone_cyclic_shift; - nfapi_uint16_tlv_t dl_gap_config_enable; - nfapi_uint16_tlv_t dl_gap_threshold; - nfapi_uint16_tlv_t dl_gap_periodicity; - nfapi_uint16_tlv_t dl_gap_duration_coefficient; -} nfapi_nb_iot_config_t; - -#define NFAPI_NB_IOT_CONFIG_OPERATING_MODE_TAG 0x00A5 -#define NFAPI_NB_IOT_CONFIG_ANCHOR_TAG 0x00A6 -#define NFAPI_NB_IOT_CONFIG_PRB_INDEX_TAG 0x00A7 -#define NFAPI_NB_IOT_CONFIG_CONTROL_REGION_SIZE_TAG 0x00A8 -#define NFAPI_NB_IOT_CONFIG_ASSUMED_CRS_APS_TAG 0x00A9 -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_ENABLED_TAG 0x00AA -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_SF_PERIODICITY_TAG 0x00AB -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_START_TIME_TAG 0x00AC -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_SUBCARRIER_OFFSET_TAG 0x00AD -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_NUMBER_OF_SUBCARRIERS_TAG 0x00AE -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_CP_LENGTH_TAG 0x00AF -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x00B0 -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_ENABLED_TAG 0x00B1 -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_SF_PERIODICITY_TAG 0x00B2 -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_START_TIME_TAG 0x00B3 -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_SUBCARRIER_OFFSET_TAG 0x00B4 -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_NUMBER_OF_SUBCARRIERS_TAG 0x00B5 -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_CP_LENGTH_TAG 0x00B6 -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x00B7 -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_ENABLED_TAG 0x00B8 -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_SF_PERIODICITY_TAG 0x00B9 -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_START_TIME_TAG 0x00BA -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_SUBCARRIER_OFFSET_TAG 0x00BB -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_NUMBER_OF_SUBCARRIERS_TAG 0x00BC -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_CP_LENGTH_TAG 0x00BD -#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x00BE -#define NFAPI_NB_IOT_CONFIG_THREE_TONE_BASE_SEQUENCE_TAG 0x00BF -#define NFAPI_NB_IOT_CONFIG_SIX_TONE_BASE_SEQUENCE_TAG 0x00C0 -#define NFAPI_NB_IOT_CONFIG_TWELVE_TONE_BASE_SEQUENCE_TAG 0x00C1 -#define NFAPI_NB_IOT_CONFIG_THREE_TONE_CYCLIC_SHIFT_TAG 0x00C2 -#define NFAPI_NB_IOT_CONFIG_SIX_TONE_CYCLIC_SHIFT_TAG 0x00C3 -#define NFAPI_NB_IOT_CONFIG_DL_GAP_CONFIG_ENABLE_TAG 0x00C4 -#define NFAPI_NB_IOT_CONFIG_DL_GAP_THRESHOLD_TAG 0x00C5 -#define NFAPI_NB_IOT_CONFIG_DL_GAP_PERIODICITY_TAG 0x00C6 -#define NFAPI_NB_IOT_CONFIG_DL_GAP_DURATION_COEFFICIENT_TAG 0x00C7 - -typedef struct { - nfapi_uint16_tlv_t laa_support; - nfapi_uint16_tlv_t pd_sensing_lbt_support; - nfapi_uint16_tlv_t multi_carrier_lbt_support; - nfapi_uint16_tlv_t partial_sf_support; -} nfapi_laa_capability_t; - -#define NFAPI_LAA_CAPABILITY_LAA_SUPPORT_TAG 0x00D1 -#define NFAPI_LAA_CAPABILITY_PD_SENSING_LBT_SUPPORT_TAG 0x00D2 -#define NFAPI_LAA_CAPABILITY_MULTI_CARRIER_LBT_SUPPORT_TAG 0x00D3 -#define NFAPI_LAA_CAPABILITY_PARTIAL_SF_SUPPORT_TAG 0x00D4 - -typedef struct { - nfapi_uint16_tlv_t nb_iot_support; - nfapi_uint16_tlv_t nb_iot_operating_mode_capability; -} nfapi_nb_iot_capability_t; - -#define NFAPI_LAA_CAPABILITY_NB_IOT_SUPPORT_TAG 0x00D5 -#define NFAPI_LAA_CAPABILITY_NB_IOT_OPERATING_MODE_CAPABILITY_TAG 0x00D6 - -typedef struct { - nfapi_uint16_tlv_t subframe_assignment; - nfapi_uint16_tlv_t special_subframe_patterns; -} nfapi_tdd_frame_structure_t; - -#define NFAPI_TDD_FRAME_STRUCTURE_SUBFRAME_ASSIGNMENT_TAG 0x005A -#define NFAPI_TDD_FRAME_STRUCTURE_SPECIAL_SUBFRAME_PATTERNS_TAG 0x005B - -typedef struct { - nfapi_tl_t tl; - uint16_t number_rf_bands; - uint16_t rf_band[NFAPI_MAX_NUM_RF_BANDS]; -} nfapi_rf_bands_t; -#define NFAPI_PHY_RF_BANDS_TAG 0x0114 - -#define NFAPI_IPV4_ADDRESS_LENGTH 4 -#define NFAPI_IPV6_ADDRESS_LENGTH 16 - -// Convience enum to allow the ip addres type to be distinguished -typedef enum { - NFAPI_IP_ADDRESS_IPV4 = 0, - NFAPI_IP_ADDRESS_IPV6 -} nfapi_ip_address_type_e; - -// The type could be infered from the length, but it is clearer in -// code to have a type variable set -typedef struct { - nfapi_tl_t tl; - uint8_t type; - union { - uint8_t ipv4_address[NFAPI_IPV4_ADDRESS_LENGTH]; - uint8_t ipv6_address[NFAPI_IPV6_ADDRESS_LENGTH]; - } u; -} nfapi_ip_address_t; - -typedef struct { - nfapi_tl_t tl; - uint8_t address[NFAPI_IPV4_ADDRESS_LENGTH]; -} nfapi_ipv4_address_t; - -typedef struct { - nfapi_tl_t tl; - uint8_t address[NFAPI_IPV6_ADDRESS_LENGTH]; -} nfapi_ipv6_address_t; - - - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_rf_bands; - uint16_t bands[NFAPI_MAX_NMM_FREQUENCY_BANDS]; -} nfapi_nmm_frequency_bands_t; - -//These TLVs are used exclusively by nFAPI -typedef struct -{ - // These TLVs are used to setup the transport connection between VNF and PNF - nfapi_ipv4_address_t p7_vnf_address_ipv4; - nfapi_ipv6_address_t p7_vnf_address_ipv6; - nfapi_uint16_tlv_t p7_vnf_port; - - nfapi_ipv4_address_t p7_pnf_address_ipv4; - nfapi_ipv6_address_t p7_pnf_address_ipv6; - nfapi_uint16_tlv_t p7_pnf_port; - - // These TLVs are used to setup the transport connection between VNF and PNF - nfapi_uint8_tlv_t dl_ue_per_sf; - nfapi_uint8_tlv_t ul_ue_per_sf; - - // These TLVs are used by PNF to report its RF capabilities to the VNF software - nfapi_rf_bands_t rf_bands; - - // These TLVs are used by the VNF to configure the synchronization with the PNF. - nfapi_uint8_tlv_t timing_window; - nfapi_uint8_tlv_t timing_info_mode; - nfapi_uint8_tlv_t timing_info_period; - - // These TLVs are used by the VNF to configure the RF in the PNF - nfapi_uint16_tlv_t max_transmit_power; - nfapi_uint16_tlv_t earfcn; - - nfapi_nmm_frequency_bands_t nmm_gsm_frequency_bands; - nfapi_nmm_frequency_bands_t nmm_umts_frequency_bands; - nfapi_nmm_frequency_bands_t nmm_lte_frequency_bands; - nfapi_uint8_tlv_t nmm_uplink_rssi_supported; - -} nfapi_nfapi_t; - -#define NFAPI_NFAPI_P7_VNF_ADDRESS_IPV4_TAG 0x0100 -#define NFAPI_NFAPI_P7_VNF_ADDRESS_IPV6_TAG 0x0101 -#define NFAPI_NFAPI_P7_VNF_PORT_TAG 0x0102 -#define NFAPI_NFAPI_P7_PNF_ADDRESS_IPV4_TAG 0x0103 -#define NFAPI_NFAPI_P7_PNF_ADDRESS_IPV6_TAG 0x0104 -#define NFAPI_NFAPI_P7_PNF_PORT_TAG 0x0105 - -#define NFAPI_NFAPI_DOWNLINK_UES_PER_SUBFRAME_TAG 0x010A -#define NFAPI_NFAPI_UPLINK_UES_PER_SUBFRAME_TAG 0x010B -#define NFAPI_NFAPI_RF_BANDS_TAG 0x0114 -#define NFAPI_NFAPI_TIMING_WINDOW_TAG 0x011E -#define NFAPI_NFAPI_TIMING_INFO_MODE_TAG 0x011F -#define NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG 0x0120 -#define NFAPI_NFAPI_MAXIMUM_TRANSMIT_POWER_TAG 0x0128 -#define NFAPI_NFAPI_EARFCN_TAG 0x0129 -#define NFAPI_NFAPI_NMM_GSM_FREQUENCY_BANDS_TAG 0x0130 -#define NFAPI_NFAPI_NMM_UMTS_FREQUENCY_BANDS_TAG 0x0131 -#define NFAPI_NFAPI_NMM_LTE_FREQUENCY_BANDS_TAG 0x0132 -#define NFAPI_NFAPI_NMM_UPLINK_RSSI_SUPPORTED_TAG 0x0133 - - -// P5 Message Structures -typedef struct { - nfapi_p4_p5_message_header_t header; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_pnf_param_request_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_pnf_param_general_t pnf_param_general; - nfapi_pnf_phy_t pnf_phy; - nfapi_pnf_rf_t pnf_rf; - nfapi_pnf_phy_rel10_t pnf_phy_rel10; - nfapi_pnf_phy_rel11_t pnf_phy_rel11; - nfapi_pnf_phy_rel12_t pnf_phy_rel12; - nfapi_pnf_phy_rel13_t pnf_phy_rel13; - nfapi_pnf_phy_rel13_nb_iot_t pnf_phy_rel13_nb_iot; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_pnf_param_response_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - nfapi_pnf_phy_rf_config_t pnf_phy_rf_config; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_pnf_config_request_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_pnf_config_response_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_pnf_start_request_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_pnf_start_response_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_pnf_stop_request_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_pnf_stop_response_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_param_request_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint8_t error_code; - uint8_t num_tlv; - // fdd or tdd in idle or configured tlvs - nfapi_l1_status l1_status; - nfapi_phy_capabilities_t phy_capabilities; - nfapi_laa_capability_t laa_capability; - nfapi_nb_iot_capability_t nb_iot_capability; - - nfapi_subframe_config_t subframe_config; - nfapi_rf_config_t rf_config; - nfapi_phich_config_t phich_config; - nfapi_sch_config_t sch_config; - nfapi_prach_config_t prach_config; - nfapi_pusch_config_t pusch_config; - nfapi_pucch_config_t pucch_config; - nfapi_srs_config_t srs_config; - nfapi_uplink_reference_signal_config_t uplink_reference_signal_config; - nfapi_tdd_frame_structure_t tdd_frame_structure_config; - nfapi_l23_config_t l23_config; - nfapi_nb_iot_config_t nb_iot_config; - - // addition nfapi tlvs as per table 2-16 in idle or configure - nfapi_nfapi_t nfapi_config; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_param_response_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint8_t num_tlv; - nfapi_subframe_config_t subframe_config; - nfapi_rf_config_t rf_config; - nfapi_phich_config_t phich_config; - nfapi_sch_config_t sch_config; - nfapi_prach_config_t prach_config; - nfapi_pusch_config_t pusch_config; - nfapi_pucch_config_t pucch_config; - nfapi_srs_config_t srs_config; - nfapi_uplink_reference_signal_config_t uplink_reference_signal_config; - nfapi_laa_config_t laa_config; - nfapi_emtc_config_t emtc_config; - nfapi_tdd_frame_structure_t tdd_frame_structure_config; - nfapi_l23_config_t l23_config; - nfapi_nb_iot_config_t nb_iot_config; - - // addition nfapi tlvs as per table 2-16 in idle or configure - nfapi_nfapi_t nfapi_config; - - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_config_request_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_config_response_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_start_request_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_start_response_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_stop_request_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_stop_response_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - nfapi_uint16_tlv_t dl_rs_tx_power; - nfapi_uint16_tlv_t received_interference_power; - nfapi_uint16_tlv_t thermal_noise_power; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_measurement_request_t; - -#define NFAPI_MEASUREMENT_REQUEST_DL_RS_XTX_POWER_TAG 0x1004 -#define NFAPI_MEASUREMENT_REQUEST_RECEIVED_INTERFERENCE_POWER_TAG 0x1005 -#define NFAPI_MEASUREMENT_REQUEST_THERMAL_NOISE_POWER_TAG 0x1006 - - - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_resource_blocks; - int16_t received_interference_power[NFAPI_MAX_RECEIVED_INTERFERENCE_POWER_RESULTS]; -} nfapi_received_interference_power_measurement_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_int16_tlv_t dl_rs_tx_power_measurement; - nfapi_received_interference_power_measurement_t received_interference_power_measurement; - nfapi_int16_tlv_t thermal_noise_power_measurement; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_measurement_response_t; - -#define NFAPI_MEASUREMENT_RESPONSE_DL_RS_POWER_MEASUREMENT_TAG 0x1007 -#define NFAPI_MEASUREMENT_RESPONSE_RECEIVED_INTERFERENCE_POWER_MEASUREMENT_TAG 0x1008 -#define NFAPI_MEASUREMENT_RESPONSE_THERMAL_NOISE_MEASUREMENT_TAG 0x1009 - -// P7 Sub Structures -typedef struct { - nfapi_tl_t tl; - uint8_t dci_format; - uint8_t cce_idx; - uint8_t aggregation_level; - uint16_t rnti; - uint8_t resource_allocation_type; - uint8_t virtual_resource_block_assignment_flag; - uint32_t resource_block_coding; - uint8_t mcs_1; - uint8_t redundancy_version_1; - uint8_t new_data_indicator_1; - uint8_t transport_block_to_codeword_swap_flag; - uint8_t mcs_2; - uint8_t redundancy_version_2; - uint8_t new_data_indicator_2; - uint8_t harq_process; - uint8_t tpmi; - uint8_t pmi; - uint8_t precoding_information; - uint8_t tpc; - uint8_t downlink_assignment_index; - uint8_t ngap; - uint8_t transport_block_size_index; - uint8_t downlink_power_offset; - uint8_t allocate_prach_flag; - uint8_t preamble_index; - uint8_t prach_mask_index; - uint8_t rnti_type; - uint16_t transmission_power; -} nfapi_dl_config_dci_dl_pdu_rel8_t; -#define NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG 0x2001 - -typedef struct { - nfapi_tl_t tl; - uint8_t mcch_flag; - uint8_t mcch_change_notification; - uint8_t scrambling_identity; -} nfapi_dl_config_dci_dl_pdu_rel9_t; -#define NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL9_TAG 0x2002 - -typedef struct { - nfapi_tl_t tl; - uint8_t cross_carrier_scheduling_flag; - uint8_t carrier_indicator; - uint8_t srs_flag; - uint8_t srs_request; - uint8_t antenna_ports_scrambling_and_layers; - uint8_t total_dci_length_including_padding; - uint8_t n_dl_rb; -} nfapi_dl_config_dci_dl_pdu_rel10_t; -#define NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL10_TAG 0x2003 - - -typedef struct { - nfapi_tl_t tl; - uint8_t harq_ack_resource_offset; - uint8_t pdsch_re_mapping_quasi_co_location_indicator; -} nfapi_dl_config_dci_dl_pdu_rel11_t; - -#define NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL11_TAG 0x2039 - - - -typedef struct { - nfapi_tl_t tl; - uint8_t primary_cell_type; - uint8_t ul_dl_configuration_flag; - uint8_t number_ul_dl_configurations; - uint8_t ul_dl_configuration_indication[NFAPI_MAX_UL_DL_CONFIGURATIONS]; -} nfapi_dl_config_dci_dl_pdu_rel12_t; - -#define NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL12_TAG 0x203a - - - -typedef struct { - uint8_t subband_index; - uint8_t scheduled_ues; - uint16_t precoding_value[NFAPI_MAX_NUM_PHYSICAL_ANTENNAS][NFAPI_MAX_NUM_SCHEDULED_UES]; -} nfapi_dl_config_dci_dl_tpm_subband_info_t; - -typedef struct { - uint8_t num_prb_per_subband; - uint8_t number_of_subbands; - uint8_t num_antennas; - nfapi_dl_config_dci_dl_tpm_subband_info_t subband_info[NFAPI_MAX_NUM_SUBBANDS]; -} nfapi_dl_config_dci_dl_tpm_t; - -typedef struct { - nfapi_tl_t tl; - uint8_t laa_end_partial_sf_flag; - uint8_t laa_end_partial_sf_configuration; - uint8_t initial_lbt_sf; - uint8_t codebook_size_determination; - uint8_t drms_table_flag; - uint8_t tpm_struct_flag; - nfapi_dl_config_dci_dl_tpm_t tpm; -} nfapi_dl_config_dci_dl_pdu_rel13_t; - -#define NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL13_TAG 0x203b - -typedef struct { - nfapi_dl_config_dci_dl_pdu_rel8_t dci_dl_pdu_rel8; - nfapi_dl_config_dci_dl_pdu_rel9_t dci_dl_pdu_rel9; - nfapi_dl_config_dci_dl_pdu_rel10_t dci_dl_pdu_rel10; - nfapi_dl_config_dci_dl_pdu_rel11_t dci_dl_pdu_rel11; - nfapi_dl_config_dci_dl_pdu_rel12_t dci_dl_pdu_rel12; - nfapi_dl_config_dci_dl_pdu_rel13_t dci_dl_pdu_rel13; -} nfapi_dl_config_dci_dl_pdu; - -typedef struct { - nfapi_tl_t tl; - uint16_t length; - uint16_t pdu_index; - uint16_t transmission_power; -} nfapi_dl_config_bch_pdu_rel8_t; -#define NFAPI_DL_CONFIG_REQUEST_BCH_PDU_REL8_TAG 0x2004 - -typedef struct { - nfapi_dl_config_bch_pdu_rel8_t bch_pdu_rel8; -} nfapi_dl_config_bch_pdu; - -typedef struct { - nfapi_tl_t tl; - uint16_t length; - uint16_t pdu_index; - uint16_t rnti; - uint8_t resource_allocation_type; - uint32_t resource_block_coding; - uint8_t modulation; - uint16_t transmission_power; - uint16_t mbsfn_area_id; -} nfapi_dl_config_mch_pdu_rel8_t; -#define NFAPI_DL_CONFIG_REQUEST_MCH_PDU_REL8_TAG 0x2005 - -typedef struct { - nfapi_dl_config_mch_pdu_rel8_t mch_pdu_rel8; -} nfapi_dl_config_mch_pdu; - - -typedef struct { - uint8_t subband_index; - uint8_t num_antennas; - uint16_t bf_value[NFAPI_MAX_NUM_ANTENNAS]; -} nfapi_bf_vector_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t length; - uint16_t pdu_index; - uint16_t rnti; - uint8_t resource_allocation_type; - uint8_t virtual_resource_block_assignment_flag; - uint32_t resource_block_coding; - uint8_t modulation; - uint8_t redundancy_version; - uint8_t transport_blocks; - uint8_t transport_block_to_codeword_swap_flag; - uint8_t transmission_scheme; - uint8_t number_of_layers; - uint8_t number_of_subbands; - uint8_t codebook_index[NFAPI_MAX_NUM_SUBBANDS]; - uint8_t ue_category_capacity; - uint8_t pa; - uint8_t delta_power_offset_index; - uint8_t ngap; - uint8_t nprb; - uint8_t transmission_mode; - uint8_t num_bf_prb_per_subband; - uint8_t num_bf_vector; - nfapi_bf_vector_t bf_vector[NFAPI_MAX_BF_VECTORS]; -} nfapi_dl_config_dlsch_pdu_rel8_t; -#define NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG 0x2006 - -typedef struct { - nfapi_tl_t tl; - uint8_t nscid; -} nfapi_dl_config_dlsch_pdu_rel9_t; -#define NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL9_TAG 0x2007 - -typedef struct { - nfapi_tl_t tl; - uint8_t csi_rs_flag; - uint8_t csi_rs_resource_config_r10; - uint16_t csi_rs_zero_tx_power_resource_config_bitmap_r10; - uint8_t csi_rs_number_nzp_configuration; - uint8_t csi_rs_resource_config[NFAPI_MAX_CSI_RS_RESOURCE_CONFIG]; - uint8_t pdsch_start; -} nfapi_dl_config_dlsch_pdu_rel10_t; -#define NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG 0x2008 - -typedef struct { - nfapi_tl_t tl; - uint8_t drms_config_flag; - uint16_t drms_scrambling; - uint8_t csi_config_flag; - uint16_t csi_scrambling; - uint8_t pdsch_re_mapping_flag; - uint8_t pdsch_re_mapping_atenna_ports; - uint8_t pdsch_re_mapping_freq_shift; -} nfapi_dl_config_dlsch_pdu_rel11_t; -#define NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL11_TAG 0x203C - -typedef struct { - nfapi_tl_t tl; - uint8_t altcqi_table_r12; - uint8_t maxlayers; - uint8_t n_dl_harq; -} nfapi_dl_config_dlsch_pdu_rel12_t; -#define NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL12_TAG 0x203D - -typedef struct { - nfapi_tl_t tl; - uint8_t dwpts_symbols; - uint8_t initial_lbt_sf; - uint8_t ue_type; - uint8_t pdsch_payload_type; - uint16_t initial_transmission_sf_io; - uint8_t drms_table_flag; -} nfapi_dl_config_dlsch_pdu_rel13_t; -#define NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG 0x203E - -typedef struct { - nfapi_dl_config_dlsch_pdu_rel8_t dlsch_pdu_rel8; - nfapi_dl_config_dlsch_pdu_rel9_t dlsch_pdu_rel9; - nfapi_dl_config_dlsch_pdu_rel10_t dlsch_pdu_rel10; - nfapi_dl_config_dlsch_pdu_rel11_t dlsch_pdu_rel11; - nfapi_dl_config_dlsch_pdu_rel12_t dlsch_pdu_rel12; - nfapi_dl_config_dlsch_pdu_rel13_t dlsch_pdu_rel13; -} nfapi_dl_config_dlsch_pdu; - -typedef struct { - nfapi_tl_t tl; - uint16_t length; - uint16_t pdu_index; - uint16_t p_rnti; - uint8_t resource_allocation_type; - uint8_t virtual_resource_block_assignment_flag; - uint32_t resource_block_coding; - uint8_t mcs; - uint8_t redundancy_version; - uint8_t number_of_transport_blocks; - uint8_t transport_block_to_codeword_swap_flag; - uint8_t transmission_scheme; - uint8_t number_of_layers; - uint8_t codebook_index; - uint8_t ue_category_capacity; - uint8_t pa; - uint16_t transmission_power; - uint8_t nprb; - uint8_t ngap; -} nfapi_dl_config_pch_pdu_rel8_t; -#define NFAPI_DL_CONFIG_REQUEST_PCH_PDU_REL8_TAG 0x2009 - -typedef struct { - nfapi_tl_t tl; - uint8_t ue_mode; - uint16_t initial_transmission_sf_io; -} nfapi_dl_config_pch_pdu_rel13_t; -#define NFAPI_DL_CONFIG_REQUEST_PCH_PDU_REL13_TAG 0x203F - -typedef struct { - nfapi_dl_config_pch_pdu_rel8_t pch_pdu_rel8; - nfapi_dl_config_pch_pdu_rel13_t pch_pdu_rel13; -} nfapi_dl_config_pch_pdu; - -typedef struct { - nfapi_tl_t tl; - uint16_t transmission_power; - uint8_t prs_bandwidth; - uint8_t prs_cyclic_prefix_type; - uint8_t prs_muting; -} nfapi_dl_config_prs_pdu_rel9_t; -#define NFAPI_DL_CONFIG_REQUEST_PRS_PDU_REL9_TAG 0x200A - -typedef struct { - nfapi_dl_config_prs_pdu_rel9_t prs_pdu_rel9; -} nfapi_dl_config_prs_pdu; - -typedef struct { - nfapi_tl_t tl; - uint8_t csi_rs_antenna_port_count_r10; - uint8_t csi_rs_resource_config_r10; - uint16_t transmission_power; - uint16_t csi_rs_zero_tx_power_resource_config_bitmap_r10; - uint8_t csi_rs_number_of_nzp_configuration; - uint8_t csi_rs_resource_config[NFAPI_MAX_CSI_RS_RESOURCE_CONFIG]; -} nfapi_dl_config_csi_rs_pdu_rel10_t; -#define NFAPI_DL_CONFIG_REQUEST_CSI_RS_PDU_REL10_TAG 0x200B - -typedef struct { - nfapi_tl_t tl; - uint8_t csi_rs_class; - uint8_t cdm_type; - uint8_t num_bf_vector; - struct { - uint8_t csi_rs_resource_index; - uint16_t bf_value[NFAPI_MAX_ANTENNA_PORT_COUNT]; - } bf_vector[NFAPI_MAX_BF_VECTORS]; - -}nfapi_dl_config_csi_rs_pdu_rel13_t; -#define NFAPI_DL_CONFIG_REQUEST_CSI_RS_PDU_REL13_TAG 0x2040 - -typedef struct { - nfapi_dl_config_csi_rs_pdu_rel10_t csi_rs_pdu_rel10; - nfapi_dl_config_csi_rs_pdu_rel13_t csi_rs_pdu_rel13; -} nfapi_dl_config_csi_rs_pdu; - -#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL8_TAG 0x2001 -#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL9_TAG 0x2002 -#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL10_TAG 0x2003 -#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL11_TAG 0x2039 -#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL12_TAG 0x203a -#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL13_TAG 0x203b - -typedef struct { - nfapi_tl_t tl; - uint8_t epdcch_resource_assignment_flag; - uint16_t epdcch_id; - uint8_t epdcch_start_symbol; - uint8_t epdcch_num_prb; - uint8_t epdcch_prb_index[NFAPI_MAX_EPDCCH_PRB]; - nfapi_bf_vector_t bf_vector; -} nfapi_dl_config_epdcch_parameters_rel11_t; -#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PARAM_REL11_TAG 0x2041 - -typedef struct { - nfapi_tl_t tl; - uint8_t dwpts_symbols; - uint8_t initial_lbt_sf; -} nfapi_dl_config_epdcch_parameters_rel13_t; -#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PARAM_REL13_TAG 0x2042 - -typedef struct { - nfapi_dl_config_dci_dl_pdu_rel8_t epdcch_pdu_rel8; - nfapi_dl_config_dci_dl_pdu_rel9_t epdcch_pdu_rel9; - nfapi_dl_config_dci_dl_pdu_rel10_t epdcch_pdu_rel10; - nfapi_dl_config_dci_dl_pdu_rel11_t epdcch_pdu_rel11; - nfapi_dl_config_dci_dl_pdu_rel12_t epdcch_pdu_rel12; - nfapi_dl_config_dci_dl_pdu_rel13_t epdcch_pdu_rel13; - nfapi_dl_config_epdcch_parameters_rel11_t epdcch_params_rel11; - nfapi_dl_config_epdcch_parameters_rel13_t epdcch_params_rel13; -} nfapi_dl_config_epdcch_pdu; - - -typedef struct { - nfapi_tl_t tl; - uint8_t mpdcch_narrow_band; - uint8_t number_of_prb_pairs; - uint8_t resource_block_assignment; - uint8_t mpdcch_tansmission_type; - uint8_t start_symbol; - uint8_t ecce_index; - uint8_t aggregation_level; - uint8_t rnti_type; - uint16_t rnti; - uint8_t ce_mode; - uint16_t drms_scrambling_init; - uint16_t initial_transmission_sf_io; - uint16_t transmission_power; - uint8_t dci_format; - uint16_t resource_block_coding; - uint8_t mcs; - uint8_t pdsch_reptition_levels; - uint8_t redundancy_version; - uint8_t new_data_indicator; - uint8_t harq_process; - uint8_t tpmi_length; - uint8_t tpmi; - uint8_t pmi_flag; - uint8_t pmi; - uint8_t harq_resource_offset; - uint8_t dci_subframe_repetition_number; - uint8_t tpc; - uint8_t downlink_assignment_index_length; - uint8_t downlink_assignment_index; - uint8_t allocate_prach_flag; - uint8_t preamble_index; - uint8_t prach_mask_index; - uint8_t starting_ce_level; - uint8_t srs_request; - uint8_t antenna_ports_and_scrambling_identity_flag; - uint8_t antenna_ports_and_scrambling_identity; - uint8_t frequency_hopping_enabled_flag; - uint8_t paging_direct_indication_differentiation_flag; - uint8_t direct_indication; - uint8_t total_dci_length_including_padding; - uint8_t number_of_tx_antenna_ports; - uint16_t precoding_value[NFAPI_MAX_TX_PHYSICAL_ANTENNA_PORTS]; -} nfapi_dl_config_mpdcch_pdu_rel13_t; -#define NFAPI_DL_CONFIG_REQUEST_MPDCCH_PDU_REL13_TAG 0x205B - - -typedef struct { - nfapi_dl_config_mpdcch_pdu_rel13_t mpdcch_pdu_rel13; -} nfapi_dl_config_mpdcch_pdu; - -typedef struct { - nfapi_tl_t tl; - uint16_t length; - uint16_t pdu_index; - uint16_t transmission_power; - uint16_t hyper_sfn_2_lsbs; -} nfapi_dl_config_nbch_pdu_rel13_t; - -#define NFAPI_DL_CONFIG_REQUEST_NBCH_PDU_REL13_TAG 0x205C - -typedef struct { - nfapi_dl_config_nbch_pdu_rel13_t nbch_pdu_rel13; -} nfapi_dl_config_nbch_pdu; - -typedef struct { - nfapi_tl_t tl; - uint16_t length; - uint16_t pdu_index; - uint8_t ncce_index; - uint8_t aggregation_level; - uint8_t start_symbol; - uint8_t rnti_type; - uint16_t rnti; - uint8_t scrambling_reinitialization_batch_index; - uint8_t nrs_antenna_ports_assumed_by_the_ue; - uint8_t dci_format; - uint8_t scheduling_delay; - uint8_t resource_assignment; - uint8_t repetition_number; - uint8_t mcs; - uint8_t new_data_indicator; - uint8_t harq_ack_resource; - uint8_t npdcch_order_indication; - uint8_t starting_number_of_nprach_repetitions; - uint8_t subcarrier_indication_of_nprach; - uint8_t paging_direct_indication_differentation_flag; - uint8_t direct_indication; - uint8_t dci_subframe_repetition_number; - uint8_t total_dci_length_including_padding; -} nfapi_dl_config_npdcch_pdu_rel13_t; - -#define NFAPI_DL_CONFIG_REQUEST_NPDCCH_PDU_REL13_TAG 0x205D - -typedef struct { - nfapi_dl_config_npdcch_pdu_rel13_t npdcch_pdu_rel13; -} nfapi_dl_config_npdcch_pdu; - -typedef struct { - nfapi_tl_t tl; - uint16_t length; - uint16_t pdu_index; - uint8_t start_symbol; - uint8_t rnti_type; - uint16_t rnti; - uint16_t resource_assignment; - uint16_t repetition_number; - uint8_t modulation; - uint8_t number_of_subframes_for_resource_assignment; - uint8_t scrambling_sequence_initialization_cinit; - uint16_t sf_idx; - uint8_t nrs_antenna_ports_assumed_by_the_ue; -} nfapi_dl_config_ndlsch_pdu_rel13_t; - -#define NFAPI_DL_CONFIG_REQUEST_NDLSCH_PDU_REL13_TAG 0x205E - -typedef struct { - nfapi_dl_config_ndlsch_pdu_rel13_t ndlsch_pdu_rel13; -} nfapi_dl_config_ndlsch_pdu; - - -typedef struct { - uint8_t pdu_type; - uint8_t pdu_size; - union { - nfapi_dl_config_dci_dl_pdu dci_dl_pdu; - nfapi_dl_config_bch_pdu bch_pdu; - nfapi_dl_config_mch_pdu mch_pdu; - nfapi_dl_config_dlsch_pdu dlsch_pdu; - nfapi_dl_config_pch_pdu pch_pdu; - nfapi_dl_config_prs_pdu prs_pdu; - nfapi_dl_config_csi_rs_pdu csi_rs_pdu; - nfapi_dl_config_epdcch_pdu epdcch_pdu; - nfapi_dl_config_mpdcch_pdu mpdcch_pdu; - nfapi_dl_config_nbch_pdu nbch_pdu; - nfapi_dl_config_npdcch_pdu npdcch_pdu; - nfapi_dl_config_ndlsch_pdu ndlsch_pdu; - }; -} nfapi_dl_config_request_pdu_t; - -#define NFAPI_DL_CONFIG_MAX_PDU 100 -typedef struct { - nfapi_tl_t tl; - uint8_t number_pdcch_ofdm_symbols; - uint8_t number_dci; - uint16_t number_pdu; - uint8_t number_pdsch_rnti; - uint16_t transmission_power_pcfich; - nfapi_dl_config_request_pdu_t* dl_config_pdu_list; -} nfapi_dl_config_request_body_t; -#define NFAPI_DL_CONFIG_REQUEST_BODY_TAG 0x2000 - -typedef struct { - nfapi_tl_t tl; - uint32_t handle; - uint16_t size; - uint16_t rnti; - uint8_t resource_block_start; - uint8_t number_of_resource_blocks; - uint8_t modulation_type; - uint8_t cyclic_shift_2_for_drms; - uint8_t frequency_hopping_enabled_flag; - uint8_t frequency_hopping_bits; - uint8_t new_data_indication; - uint8_t redundancy_version; - uint8_t harq_process_number; - uint8_t ul_tx_mode; - uint8_t current_tx_nb; - uint8_t n_srs; -} nfapi_ul_config_ulsch_pdu_rel8_t; -#define NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG 0x200D - -typedef struct { - nfapi_tl_t tl; - uint8_t resource_allocation_type; - uint32_t resource_block_coding; - uint8_t transport_blocks; - uint8_t transmission_scheme; - uint8_t number_of_layers; - uint8_t codebook_index; - uint8_t disable_sequence_hopping_flag; -} nfapi_ul_config_ulsch_pdu_rel10_t; -#define NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL10_TAG 0x200E - - -typedef struct { - nfapi_tl_t tl; - uint8_t virtual_cell_id_enabled_flag; - uint16_t npusch_identity; - uint8_t dmrs_config_flag; - uint16_t ndmrs_csh_identity; -} nfapi_ul_config_ulsch_pdu_rel11_t; - -#define NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL11_TAG 0x2043 - -typedef struct { - nfapi_tl_t tl; - uint8_t ue_type; - uint16_t total_number_of_repetitions; - uint16_t repetition_number; - uint16_t initial_transmission_sf_io; - uint8_t empty_symbols_due_to_re_tunning; -} nfapi_ul_config_ulsch_pdu_rel13_t; -#define NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL13_TAG 0x2044 - -typedef struct { - nfapi_ul_config_ulsch_pdu_rel8_t ulsch_pdu_rel8; - nfapi_ul_config_ulsch_pdu_rel10_t ulsch_pdu_rel10; - nfapi_ul_config_ulsch_pdu_rel11_t ulsch_pdu_rel11; - nfapi_ul_config_ulsch_pdu_rel13_t ulsch_pdu_rel13; -} nfapi_ul_config_ulsch_pdu; - -typedef struct { - nfapi_tl_t tl; - uint8_t dl_cqi_pmi_size_rank_1; - uint8_t dl_cqi_pmi_size_rank_greater_1; - uint8_t ri_size; - uint8_t delta_offset_cqi; - uint8_t delta_offset_ri; -} nfapi_ul_config_cqi_ri_information_rel8_t; -#define NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL8_TAG 0x2010 - -typedef struct { - uint8_t dl_cqi_pmi_ri_size; - uint8_t control_type; -} nfapi_ul_config_periodic_cqi_pmi_ri_report_t; - -typedef struct { - uint8_t number_of_cc; - struct { - uint8_t ri_size; - uint8_t dl_cqi_pmi_size[8]; - } cc[NFAPI_MAX_CC]; -} nfapi_ul_config_aperiodic_cqi_pmi_ri_report_t; - -typedef struct { - nfapi_tl_t tl; - uint8_t report_type; - uint8_t delta_offset_cqi; - uint8_t delta_offset_ri; - union { - nfapi_ul_config_periodic_cqi_pmi_ri_report_t periodic_cqi_pmi_ri_report; - nfapi_ul_config_aperiodic_cqi_pmi_ri_report_t aperiodic_cqi_pmi_ri_report; - }; -} nfapi_ul_config_cqi_ri_information_rel9_t; -#define NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL9_TAG 0x2011 - -typedef struct { - uint16_t dl_cqi_pmi_ri_size_2; -} nfapi_ul_config_periodic_cqi_pmi_ri_report_re13_t; - -typedef struct { -} nfapi_ul_config_aperiodic_cqi_pmi_ri_report_re13_t; - -typedef struct { - nfapi_tl_t tl; - uint8_t report_type; // Convience parameter, not sent on the wire - union { - nfapi_ul_config_periodic_cqi_pmi_ri_report_re13_t periodic_cqi_pmi_ri_report; - nfapi_ul_config_aperiodic_cqi_pmi_ri_report_re13_t aperiodic_cqi_pmi_ri_report; - }; -} nfapi_ul_config_cqi_ri_information_rel13_t; -#define NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL13_TAG 0x2045 - -typedef struct { - nfapi_ul_config_cqi_ri_information_rel8_t cqi_ri_information_rel8; - nfapi_ul_config_cqi_ri_information_rel9_t cqi_ri_information_rel9; - nfapi_ul_config_cqi_ri_information_rel13_t cqi_ri_information_rel13; -} nfapi_ul_config_cqi_ri_information; - -typedef struct { - nfapi_tl_t tl; - uint8_t harq_size; - uint8_t delta_offset_harq; - uint8_t ack_nack_mode; -} nfapi_ul_config_ulsch_harq_information_rel10_t; -#define NFAPI_UL_CONFIG_REQUEST_ULSCH_HARQ_INFORMATION_REL10_TAG 0x2012 - -typedef struct { - nfapi_tl_t tl; - uint16_t harq_size_2; - uint8_t delta_offset_harq_2; -} nfapi_ul_config_ulsch_harq_information_rel13_t; -#define NFAPI_UL_CONFIG_REQUEST_ULSCH_HARQ_INFORMATION_REL13_TAG 0x2046 - -typedef struct { - nfapi_ul_config_ulsch_harq_information_rel10_t harq_information_rel10; - nfapi_ul_config_ulsch_harq_information_rel13_t harq_information_rel13; -} nfapi_ul_config_ulsch_harq_information; - -typedef struct { - nfapi_tl_t tl; - uint8_t n_srs_initial; - uint8_t initial_number_of_resource_blocks; -} nfapi_ul_config_initial_transmission_parameters_rel8_t; -#define NFAPI_UL_CONFIG_REQUEST_INITIAL_TRANSMISSION_PARAMETERS_REL8_TAG 0x200F - -typedef struct { - nfapi_ul_config_initial_transmission_parameters_rel8_t initial_transmission_parameters_rel8; -} nfapi_ul_config_initial_transmission_parameters; - -typedef struct { - nfapi_ul_config_ulsch_pdu ulsch_pdu; - nfapi_ul_config_cqi_ri_information cqi_ri_information; - nfapi_ul_config_initial_transmission_parameters initial_transmission_parameters; -} nfapi_ul_config_ulsch_cqi_ri_pdu; - -typedef struct { - nfapi_ul_config_ulsch_pdu ulsch_pdu; - nfapi_ul_config_ulsch_harq_information harq_information; - nfapi_ul_config_initial_transmission_parameters initial_transmission_parameters; -} nfapi_ul_config_ulsch_harq_pdu; - -typedef struct { - nfapi_ul_config_ulsch_pdu ulsch_pdu; - nfapi_ul_config_cqi_ri_information cqi_ri_information; - nfapi_ul_config_ulsch_harq_information harq_information; - nfapi_ul_config_initial_transmission_parameters initial_transmission_parameters; -} nfapi_ul_config_ulsch_cqi_harq_ri_pdu; - - -typedef struct { - nfapi_tl_t tl; - uint32_t handle; - uint16_t rnti; -} nfapi_ul_config_ue_information_rel8_t; -#define NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG 0x2013 - -typedef struct { - nfapi_tl_t tl; - uint8_t virtual_cell_id_enabled_flag; - uint16_t npusch_identity; -} nfapi_ul_config_ue_information_rel11_t; - -#define NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL11_TAG 0x2047 - -typedef struct { - nfapi_tl_t tl; - uint8_t ue_type; - uint8_t empty_symbols; - uint16_t total_number_of_repetitions; - uint16_t repetition_number; -} nfapi_ul_config_ue_information_rel13_t; - -#define NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL13_TAG 0x2048 - -typedef struct { - nfapi_ul_config_ue_information_rel8_t ue_information_rel8; - nfapi_ul_config_ue_information_rel11_t ue_information_rel11; - nfapi_ul_config_ue_information_rel13_t ue_information_rel13; -} nfapi_ul_config_ue_information; - -typedef struct { - nfapi_tl_t tl; - uint16_t pucch_index; - uint8_t dl_cqi_pmi_size; -} nfapi_ul_config_cqi_information_rel8_t; -#define NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG 0x2014 - -typedef struct { - nfapi_tl_t tl; - uint8_t number_of_pucch_resource; - uint16_t pucch_index_p1; -} nfapi_ul_config_cqi_information_rel10_t; -#define NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL10_TAG 0x2015 - -typedef struct { - nfapi_tl_t tl; - uint8_t csi_mode; - uint16_t dl_cqi_pmi_size_2; - uint8_t starting_prb; - uint8_t n_prb; - uint8_t cdm_index; - uint8_t n_srs; -} nfapi_ul_config_cqi_information_rel13_t; -#define NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL13_TAG 0x2049 - -typedef struct { - nfapi_ul_config_cqi_information_rel8_t cqi_information_rel8; - nfapi_ul_config_cqi_information_rel10_t cqi_information_rel10; - nfapi_ul_config_cqi_information_rel13_t cqi_information_rel13; -} nfapi_ul_config_cqi_information; - -typedef struct { - nfapi_tl_t tl; - uint16_t pucch_index; -} nfapi_ul_config_sr_information_rel8_t; -#define NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL8_TAG 0x2016 - -typedef struct { - nfapi_tl_t tl; - uint8_t number_of_pucch_resources; - uint16_t pucch_index_p1; -} nfapi_ul_config_sr_information_rel10_t; -#define NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL10_TAG 0x2017 - -typedef struct { - nfapi_ul_config_sr_information_rel8_t sr_information_rel8; - nfapi_ul_config_sr_information_rel10_t sr_information_rel10; -} nfapi_ul_config_sr_information; - -typedef struct { - nfapi_tl_t tl; - uint8_t harq_size; - uint8_t ack_nack_mode; - uint8_t number_of_pucch_resources; - uint16_t n_pucch_1_0; - uint16_t n_pucch_1_1; - uint16_t n_pucch_1_2; - uint16_t n_pucch_1_3; -} nfapi_ul_config_harq_information_rel10_tdd_t; -#define NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG 0x2018 - - -typedef struct { - nfapi_tl_t tl; - uint16_t n_pucch_1_0; - uint8_t harq_size; -} nfapi_ul_config_harq_information_rel8_fdd_t; -#define NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL8_FDD_TAG 0x2019 - -typedef struct { - nfapi_tl_t tl; - uint8_t harq_size; - uint8_t ack_nack_mode; - uint8_t number_of_pucch_resources; - uint16_t n_pucch_1_0; - uint16_t n_pucch_1_1; - uint16_t n_pucch_1_2; - uint16_t n_pucch_1_3; -} nfapi_ul_config_harq_information_rel9_fdd_t; -#define NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG 0x201a - -typedef struct { - nfapi_tl_t tl; - uint8_t num_ant_ports; - uint16_t n_pucch_2_0; - uint16_t n_pucch_2_1; - uint16_t n_pucch_2_2; - uint16_t n_pucch_2_3; -} nfapi_ul_config_harq_information_rel11_t; -#define NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL11_TAG 0x204A - -typedef struct { - nfapi_tl_t tl; - uint16_t harq_size_2; - uint8_t starting_prb; - uint8_t n_prb; - uint8_t cdm_index; - uint8_t n_srs; -} nfapi_ul_config_harq_information_rel13_t; -#define NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL13_TAG 0x204B - -typedef struct { - nfapi_ul_config_harq_information_rel10_tdd_t harq_information_rel10_tdd; - nfapi_ul_config_harq_information_rel8_fdd_t harq_information_rel8_fdd; - nfapi_ul_config_harq_information_rel9_fdd_t harq_information_rel9_fdd; - nfapi_ul_config_harq_information_rel11_t harq_information_rel11; - nfapi_ul_config_harq_information_rel13_t harq_information_rel13; -} nfapi_ul_config_harq_information; - -typedef struct { - nfapi_tl_t tl; - uint32_t handle; - uint16_t size; - uint16_t rnti; - uint8_t srs_bandwidth; - uint8_t frequency_domain_position; - uint8_t srs_hopping_bandwidth; - uint8_t transmission_comb; - uint16_t i_srs; - uint8_t sounding_reference_cyclic_shift; -} nfapi_ul_config_srs_pdu_rel8_t; -#define NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL8_TAG 0x201b - -typedef struct { - nfapi_tl_t tl; - uint8_t antenna_port; -} nfapi_ul_config_srs_pdu_rel10_t; -#define NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL10_TAG 0x201c - -typedef struct { - nfapi_tl_t tl; - uint8_t number_of_combs; -} nfapi_ul_config_srs_pdu_rel13_t; -#define NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL13_TAG 0x204c - -typedef struct { - nfapi_ul_config_srs_pdu_rel8_t srs_pdu_rel8; - nfapi_ul_config_srs_pdu_rel10_t srs_pdu_rel10; - nfapi_ul_config_srs_pdu_rel13_t srs_pdu_rel13; -} nfapi_ul_config_srs_pdu; - -typedef struct { - nfapi_ul_config_ue_information ue_information; - nfapi_ul_config_cqi_information cqi_information; -} nfapi_ul_config_uci_cqi_pdu; - -typedef struct { - nfapi_ul_config_ue_information ue_information; - nfapi_ul_config_sr_information sr_information; -} nfapi_ul_config_uci_sr_pdu; - -typedef struct { - nfapi_ul_config_ue_information ue_information; - nfapi_ul_config_harq_information harq_information; -} nfapi_ul_config_uci_harq_pdu; - -typedef struct { - nfapi_ul_config_ue_information ue_information; - nfapi_ul_config_sr_information sr_information; - nfapi_ul_config_harq_information harq_information; -} nfapi_ul_config_uci_sr_harq_pdu; - -typedef struct { - nfapi_ul_config_ue_information ue_information; - nfapi_ul_config_cqi_information cqi_information; - nfapi_ul_config_harq_information harq_information; -} nfapi_ul_config_uci_cqi_harq_pdu; - -typedef struct { - nfapi_ul_config_ue_information ue_information; - nfapi_ul_config_cqi_information cqi_information; - nfapi_ul_config_sr_information sr_information; -} nfapi_ul_config_uci_cqi_sr_pdu; - -typedef struct { - nfapi_ul_config_ue_information ue_information; - nfapi_ul_config_cqi_information cqi_information; - nfapi_ul_config_sr_information sr_information; - nfapi_ul_config_harq_information harq_information; -} nfapi_ul_config_uci_cqi_sr_harq_pdu; - -typedef struct { - nfapi_ul_config_ue_information ue_information; -} nfapi_ul_config_harq_buffer_pdu; - -typedef struct { - nfapi_ul_config_ulsch_pdu ulsch_pdu; - nfapi_ul_config_cqi_information csi_information; -} nfapi_ul_config_ulsch_uci_csi_pdu; - -typedef struct { - nfapi_ul_config_ulsch_pdu ulsch_pdu; - nfapi_ul_config_harq_information harq_information; -} nfapi_ul_config_ulsch_uci_harq_pdu; - -typedef struct { - nfapi_ul_config_ulsch_pdu ulsch_pdu; - nfapi_ul_config_cqi_information csi_information; - nfapi_ul_config_harq_information harq_information; -} nfapi_ul_config_ulsch_csi_uci_harq_pdu; - -typedef struct { - nfapi_tl_t tl; - uint8_t harq_ack_resource; -} nfapi_ul_config_nb_harq_information_rel13_fdd_t; -#define NFAPI_UL_CONFIG_REQUEST_NB_HARQ_INFORMATION_REL13_FDD_TAG 0x2061 - -typedef struct { - nfapi_ul_config_nb_harq_information_rel13_fdd_t nb_harq_information_rel13_fdd; -} nfapi_ul_config_nb_harq_information; - -typedef struct { - nfapi_tl_t tl; - uint8_t nulsch_format; - uint32_t handle; - uint16_t size; - uint16_t rnti; - uint8_t subcarrier_indication; - uint8_t resource_assignment; - uint8_t mcs; - uint8_t redudancy_version; - uint8_t repetition_number; - uint8_t new_data_indication; - uint8_t n_srs; - uint16_t scrambling_sequence_initialization_cinit; - uint16_t sf_idx; - nfapi_ul_config_ue_information ue_information; - nfapi_ul_config_nb_harq_information nb_harq_information; -} nfapi_ul_config_nulsch_pdu_rel13_t; -#define NFAPI_UL_CONFIG_REQUEST_NULSCH_PDU_REL13_TAG 0x205F - -typedef struct { - nfapi_ul_config_nulsch_pdu_rel13_t nulsch_pdu_rel13; -} nfapi_ul_config_nulsch_pdu; - - -typedef struct { - nfapi_tl_t tl; - uint8_t nprach_config_0; - uint8_t nprach_config_1; - uint8_t nprach_config_2; -} nfapi_ul_config_nrach_pdu_rel13_t; -#define NFAPI_UL_CONFIG_REQUEST_NRACH_PDU_REL13_TAG 0x2067 - -typedef struct { - nfapi_ul_config_nrach_pdu_rel13_t nrach_pdu_rel13; -} nfapi_ul_config_nrach_pdu; - -typedef struct { - uint8_t pdu_type; - uint8_t pdu_size; - union { - nfapi_ul_config_ulsch_pdu ulsch_pdu; - nfapi_ul_config_ulsch_cqi_ri_pdu ulsch_cqi_ri_pdu; - nfapi_ul_config_ulsch_harq_pdu ulsch_harq_pdu; - nfapi_ul_config_ulsch_cqi_harq_ri_pdu ulsch_cqi_harq_ri_pdu; - nfapi_ul_config_uci_cqi_pdu uci_cqi_pdu; - nfapi_ul_config_uci_sr_pdu uci_sr_pdu; - nfapi_ul_config_uci_harq_pdu uci_harq_pdu; - nfapi_ul_config_uci_sr_harq_pdu uci_sr_harq_pdu; - nfapi_ul_config_uci_cqi_harq_pdu uci_cqi_harq_pdu; - nfapi_ul_config_uci_cqi_sr_pdu uci_cqi_sr_pdu; - nfapi_ul_config_uci_cqi_sr_harq_pdu uci_cqi_sr_harq_pdu; - nfapi_ul_config_srs_pdu srs_pdu; - nfapi_ul_config_harq_buffer_pdu harq_buffer_pdu; - nfapi_ul_config_ulsch_uci_csi_pdu ulsch_uci_csi_pdu; - nfapi_ul_config_ulsch_uci_harq_pdu ulsch_uci_harq_pdu; - nfapi_ul_config_ulsch_csi_uci_harq_pdu ulsch_csi_uci_harq_pdu; - nfapi_ul_config_nulsch_pdu nulsch_pdu; - nfapi_ul_config_nrach_pdu nrach_pdu; - }; -} nfapi_ul_config_request_pdu_t; - -#define NFAPI_UL_CONFIG_MAX_PDU 100 -typedef struct { - nfapi_tl_t tl; - uint8_t number_of_pdus; - uint8_t rach_prach_frequency_resources; - uint8_t srs_present; - nfapi_ul_config_request_pdu_t* ul_config_pdu_list; -} nfapi_ul_config_request_body_t; -#define NFAPI_UL_CONFIG_REQUEST_BODY_TAG 0x200C - -typedef struct { - nfapi_tl_t tl; - uint8_t resource_block_start; - uint8_t cyclic_shift_2_for_drms; - uint8_t hi_value; - uint8_t i_phich; - uint16_t transmission_power; -} nfapi_hi_dci0_hi_pdu_rel8_t; -#define NFAPI_HI_DCI0_REQUEST_HI_PDU_REL8_TAG 0x201e - -typedef struct { - nfapi_tl_t tl; - uint8_t flag_tb2; - uint8_t hi_value_2; -} nfapi_hi_dci0_hi_pdu_rel10_t; -#define NFAPI_HI_DCI0_REQUEST_HI_PDU_REL10_TAG 0x201f - -typedef struct { - nfapi_hi_dci0_hi_pdu_rel8_t hi_pdu_rel8; - nfapi_hi_dci0_hi_pdu_rel10_t hi_pdu_rel10; -} nfapi_hi_dci0_hi_pdu; - -typedef struct { - nfapi_tl_t tl; - uint8_t dci_format; - uint8_t cce_index; - uint8_t aggregation_level; - uint16_t rnti; - uint8_t resource_block_start; - uint8_t number_of_resource_block; - uint8_t mcs_1; - uint8_t cyclic_shift_2_for_drms; - uint8_t frequency_hopping_enabled_flag; - uint8_t frequency_hopping_bits; - uint8_t new_data_indication_1; - uint8_t ue_tx_antenna_seleciton; - uint8_t tpc; - uint8_t cqi_csi_request; - uint8_t ul_index; - uint8_t dl_assignment_index; - uint32_t tpc_bitmap; - uint16_t transmission_power; -} nfapi_hi_dci0_dci_pdu_rel8_t; -#define NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL8_TAG 0x2020 - -typedef struct { - nfapi_tl_t tl; - uint8_t cross_carrier_scheduling_flag; - uint8_t carrier_indicator; - uint8_t size_of_cqi_csi_feild; - uint8_t srs_flag; - uint8_t srs_request; - uint8_t resource_allocation_flag; - uint8_t resource_allocation_type; - uint32_t resource_block_coding; - uint8_t mcs_2; - uint8_t new_data_indication_2; - uint8_t number_of_antenna_ports; - uint8_t tpmi; - uint8_t total_dci_length_including_padding; - uint8_t n_ul_rb; -} nfapi_hi_dci0_dci_pdu_rel10_t; -#define NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL10_TAG 0x2021 - -typedef struct { - nfapi_tl_t tl; - uint8_t pscch_resource; - uint8_t time_resource_pattern; -} nfapi_hi_dci0_dci_pdu_rel12_t; - -#define NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL12_TAG 0x204D - -typedef struct { - nfapi_hi_dci0_dci_pdu_rel8_t dci_pdu_rel8; - nfapi_hi_dci0_dci_pdu_rel10_t dci_pdu_rel10; - nfapi_hi_dci0_dci_pdu_rel12_t dci_pdu_rel12; -} nfapi_hi_dci0_dci_pdu; - -typedef nfapi_hi_dci0_dci_pdu_rel8_t nfapi_hi_dci0_epdcch_dci_pdu_rel8_t; -#define NFAPI_HI_DCI0_REQUEST_EPDCCH_DCI_PDU_REL8_TAG 0x2020 - -typedef nfapi_hi_dci0_dci_pdu_rel10_t nfapi_hi_dci0_epdcch_dci_pdu_rel10_t; -#define NFAPI_HI_DCI0_REQUEST_EPDCCH_DCI_PDU_REL10_TAG 0x2021 - -typedef nfapi_dl_config_epdcch_parameters_rel11_t nfapi_hi_dci0_epdcch_parameters_rel11_t; -#define NFAPI_HI_DCI0_REQUEST_EPDCCH_PARAMETERS_REL11_TAG 0x2041 - -typedef struct { - nfapi_hi_dci0_epdcch_dci_pdu_rel8_t epdcch_dci_pdu_rel8; - nfapi_hi_dci0_epdcch_dci_pdu_rel10_t epdcch_dci_pdu_rel10; - nfapi_hi_dci0_epdcch_parameters_rel11_t epdcch_parameters_rel11; -} nfapi_hi_dci0_epdcch_dci_pdu; - - -typedef struct { - nfapi_tl_t tl; - uint8_t mpdcch_narrowband; - uint8_t number_of_prb_pairs; - uint8_t resource_block_assignment; - uint8_t mpdcch_transmission_type; - uint8_t start_symbol; - uint8_t ecce_index; - uint8_t aggreagation_level; - uint8_t rnti_type; - uint16_t rnti; - uint8_t ce_mode; - uint16_t drms_scrambling_init; - uint16_t initial_transmission_sf_io; - uint16_t transmission_power; - uint8_t dci_format; - uint8_t resource_block_start; - uint8_t number_of_resource_blocks; - uint8_t mcs; - uint8_t pusch_repetition_levels; - uint8_t frequency_hopping_flag; - uint8_t new_data_indication; - uint8_t harq_process; - uint8_t redudency_version; - uint8_t tpc; - uint8_t csi_request; - uint8_t ul_inex; - uint8_t dai_presence_flag; - uint8_t dl_assignment_index; - uint8_t srs_request; - uint8_t dci_subframe_repetition_number; - uint32_t tcp_bitmap; - uint8_t total_dci_length_include_padding; - uint8_t number_of_tx_antenna_ports; - uint16_t precoding_value[NFAPI_MAX_ANTENNA_PORT_COUNT]; -} nfapi_hi_dci0_mpdcch_dci_pdu_rel13_t; -#define NFAPI_HI_DCI0_REQUEST_MPDCCH_DCI_PDU_REL13_TAG 0x204E - -typedef struct { - nfapi_hi_dci0_mpdcch_dci_pdu_rel13_t mpdcch_dci_pdu_rel13; -} nfapi_hi_dci0_mpdcch_dci_pdu; - -typedef struct { - nfapi_tl_t tl; - uint8_t ncce_index; - uint8_t aggregation_level; - uint8_t start_symbol; - uint16_t rnti; - uint8_t scrambling_reinitialization_batch_index; - uint8_t nrs_antenna_ports_assumed_by_the_ue; - uint8_t subcarrier_indication; - uint8_t resource_assignment; - uint8_t scheduling_delay; - uint8_t mcs; - uint8_t redudancy_version; - uint8_t repetition_number; - uint8_t new_data_indicator; - uint8_t dci_subframe_repetition_number; -} nfapi_hi_dci0_npdcch_dci_pdu_rel13_t; - -#define NFAPI_HI_DCI0_REQUEST_NPDCCH_DCI_PDU_REL13_TAG 0x2062 - -typedef struct { - nfapi_hi_dci0_npdcch_dci_pdu_rel13_t npdcch_dci_pdu_rel13; -} nfapi_hi_dci0_npdcch_dci_pdu; - -typedef struct { - uint8_t pdu_type; - uint8_t pdu_size; - union { - nfapi_hi_dci0_hi_pdu hi_pdu; - nfapi_hi_dci0_dci_pdu dci_pdu; - nfapi_hi_dci0_epdcch_dci_pdu epdcch_dci_pdu; - nfapi_hi_dci0_mpdcch_dci_pdu mpdcch_dci_pdu; - nfapi_hi_dci0_npdcch_dci_pdu npdcch_dci_pdu; - }; -} nfapi_hi_dci0_request_pdu_t; - -#define NFAPI_HI_DCI0_MAX_PDU 100 -typedef struct { - nfapi_tl_t tl; - uint16_t sfnsf; - uint8_t number_of_dci; - uint8_t number_of_hi; - nfapi_hi_dci0_request_pdu_t* hi_dci0_pdu_list; -} nfapi_hi_dci0_request_body_t; -#define NFAPI_HI_DCI0_REQUEST_BODY_TAG 0x201D - -#define NFAPI_TX_MAX_SEGMENTS 32 -typedef struct { - uint16_t pdu_length; - uint16_t pdu_index; - uint8_t num_segments; - struct { - uint32_t segment_length; - uint8_t* segment_data; - } segments[NFAPI_TX_MAX_SEGMENTS]; -} nfapi_tx_request_pdu_t; - -#define NFAPI_TX_MAX_PDU 100 -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_pdus; - nfapi_tx_request_pdu_t* tx_pdu_list; -} nfapi_tx_request_body_t; -#define NFAPI_TX_REQUEST_BODY_TAG 0x2022 - -// P7 Message Structures -typedef struct { - nfapi_p7_message_header_t header; - uint32_t t1; - int32_t delta_sfn_sf; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_dl_node_sync_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint32_t t1; - uint32_t t2; - uint32_t t3; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_ul_node_sync_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint32_t last_sfn_sf; - uint32_t time_since_last_timing_info; - uint32_t dl_config_jitter; - uint32_t tx_request_jitter; - uint32_t ul_config_jitter; - uint32_t hi_dci0_jitter; - int32_t dl_config_latest_delay; - int32_t tx_request_latest_delay; - int32_t ul_config_latest_delay; - int32_t hi_dci0_latest_delay; - int32_t dl_config_earliest_arrival; - int32_t tx_request_earliest_arrival; - int32_t ul_config_earliest_arrival; - int32_t hi_dci0_earliest_arrival; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_timing_info_t; - -typedef struct { - nfapi_tl_t tl; - uint32_t handle; - uint16_t rnti; -} nfapi_rx_ue_information; -#define NFAPI_RX_UE_INFORMATION_TAG 0x2038 - -typedef struct { - uint8_t value_0; - uint8_t value_1; -} nfapi_harq_indication_tdd_harq_data_bundling_t; - -typedef struct { - uint8_t value_0; - uint8_t value_1; - uint8_t value_2; - uint8_t value_3; -} nfapi_harq_indication_tdd_harq_data_multiplexing_t; - -typedef struct { - uint8_t value_0; -} nfapi_harq_indication_tdd_harq_data_special_bundling_t; - -typedef struct { - uint8_t value_0; -} nfapi_harq_indication_tdd_harq_data_t; - -typedef struct { - nfapi_tl_t tl; - uint8_t mode; - uint8_t number_of_ack_nack; - union{ - nfapi_harq_indication_tdd_harq_data_bundling_t bundling; - nfapi_harq_indication_tdd_harq_data_multiplexing_t multiplex; - nfapi_harq_indication_tdd_harq_data_special_bundling_t special_bundling; - } harq_data; -} nfapi_harq_indication_tdd_rel8_t; -#define NFAPI_HARQ_INDICATION_TDD_REL8_TAG 0x2027 - -typedef struct { - nfapi_tl_t tl; - uint8_t mode; - uint8_t number_of_ack_nack; - union{ - nfapi_harq_indication_tdd_harq_data_t bundling; - nfapi_harq_indication_tdd_harq_data_t multiplex; - nfapi_harq_indication_tdd_harq_data_special_bundling_t special_bundling; - nfapi_harq_indication_tdd_harq_data_t channel_selection; - nfapi_harq_indication_tdd_harq_data_t format_3; - } harq_data[NFAPI_MAX_NUMBER_ACK_NACK_TDD]; -} nfapi_harq_indication_tdd_rel9_t; -#define NFAPI_HARQ_INDICATION_TDD_REL9_TAG 0x2028 - -typedef struct { - nfapi_tl_t tl; - uint8_t mode; - uint16_t number_of_ack_nack; - union{ - nfapi_harq_indication_tdd_harq_data_t bundling; - nfapi_harq_indication_tdd_harq_data_t multiplex; - nfapi_harq_indication_tdd_harq_data_special_bundling_t special_bundling; - nfapi_harq_indication_tdd_harq_data_t channel_selection; - nfapi_harq_indication_tdd_harq_data_t format_3; - nfapi_harq_indication_tdd_harq_data_t format_4; - nfapi_harq_indication_tdd_harq_data_t format_5; - } harq_data[NFAPI_MAX_NUMBER_ACK_NACK_TDD]; -} nfapi_harq_indication_tdd_rel13_t; -#define NFAPI_HARQ_INDICATION_TDD_REL13_TAG 0x204F - -typedef struct { - nfapi_tl_t tl; - uint8_t harq_tb1; - uint8_t harq_tb2; -} nfapi_harq_indication_fdd_rel8_t; -#define NFAPI_HARQ_INDICATION_FDD_REL8_TAG 0x2029 - -#define NFAPI_HARQ_ACK_NACK_REL9_MAX 10 -typedef struct { - nfapi_tl_t tl; - uint8_t mode; - uint8_t number_of_ack_nack; - uint8_t harq_tb_n[NFAPI_HARQ_ACK_NACK_REL9_MAX]; -} nfapi_harq_indication_fdd_rel9_t; -#define NFAPI_HARQ_INDICATION_FDD_REL9_TAG 0x202a - -#define NFAPI_HARQ_ACK_NACK_REL13_MAX 22 // Need to check this max? -typedef struct { - nfapi_tl_t tl; - uint8_t mode; - uint16_t number_of_ack_nack; - uint8_t harq_tb_n[NFAPI_HARQ_ACK_NACK_REL13_MAX]; -} nfapi_harq_indication_fdd_rel13_t; -#define NFAPI_HARQ_INDICATION_FDD_REL13_TAG 0x2050 - -typedef struct { - nfapi_tl_t tl; - uint8_t ul_cqi; - uint8_t channel; -} nfapi_ul_cqi_information_t; -#define NFAPI_UL_CQI_INFORMATION_TAG 0x2052 - -// Only expect 1 harq_indication TLV.tag to be set -// Would this be a better a an union, but not clear which combinations -// are valid -typedef struct { - uint16_t instance_length; - nfapi_rx_ue_information rx_ue_information; - nfapi_harq_indication_tdd_rel8_t harq_indication_tdd_rel8; - nfapi_harq_indication_tdd_rel9_t harq_indication_tdd_rel9; - nfapi_harq_indication_tdd_rel13_t harq_indication_tdd_rel13; - nfapi_harq_indication_fdd_rel8_t harq_indication_fdd_rel8; - nfapi_harq_indication_fdd_rel9_t harq_indication_fdd_rel9; - nfapi_harq_indication_fdd_rel13_t harq_indication_fdd_rel13; - nfapi_ul_cqi_information_t ul_cqi_information; -} nfapi_harq_indication_pdu_t; - -#define NFAPI_HARQ_IND_MAX_PDU 100 -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_harqs; - nfapi_harq_indication_pdu_t* harq_pdu_list; -} nfapi_harq_indication_body_t; -#define NFAPI_HARQ_INDICATION_BODY_TAG 0x2026 - -typedef struct { - nfapi_tl_t tl; - uint8_t crc_flag; -} nfapi_crc_indication_rel8_t; -#define NFAPI_CRC_INDICATION_REL8_TAG 0x202c - -typedef struct { - uint16_t instance_length; - nfapi_rx_ue_information rx_ue_information; - nfapi_crc_indication_rel8_t crc_indication_rel8; -} nfapi_crc_indication_pdu_t; - -#define NFAPI_CRC_IND_MAX_PDU 100 -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_crcs; - nfapi_crc_indication_pdu_t* crc_pdu_list; -} nfapi_crc_indication_body_t; -#define NFAPI_CRC_INDICATION_BODY_TAG 0x202b - -typedef struct { - uint16_t instance_length; - nfapi_rx_ue_information rx_ue_information; - nfapi_ul_cqi_information_t ul_cqi_information; -} nfapi_sr_indication_pdu_t; - -#define NFAPI_SR_IND_MAX_PDU 100 -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_srs; // Question : should this be srs - nfapi_sr_indication_pdu_t* sr_pdu_list; -} nfapi_sr_indication_body_t; -#define NFAPI_SR_INDICATION_BODY_TAG 0x202d - -// The data offset should be set to 0 or 1 before encoding -// If it is set to 1 the nfapi library will detemine the correct offset - -typedef struct { - nfapi_tl_t tl; - uint16_t length; - uint16_t data_offset; - uint8_t ul_cqi; - uint8_t ri; - uint16_t timing_advance; -} nfapi_cqi_indication_rel8_t; -#define NFAPI_CQI_INDICATION_REL8_TAG 0x202f - -#define NFAPI_CC_MAX 4 -typedef struct { - nfapi_tl_t tl; - uint16_t length; - uint16_t data_offset; - uint8_t ul_cqi; - uint8_t number_of_cc_reported; - uint8_t ri[NFAPI_CC_MAX]; - uint16_t timing_advance; - uint16_t timing_advance_r9; -} nfapi_cqi_indication_rel9_t; -#define NFAPI_CQI_INDICATION_REL9_TAG 0x2030 - -typedef struct { - uint16_t instance_length; - nfapi_rx_ue_information rx_ue_information; - nfapi_cqi_indication_rel8_t cqi_indication_rel8; - nfapi_cqi_indication_rel9_t cqi_indication_rel9; - nfapi_ul_cqi_information_t ul_cqi_information; -} nfapi_cqi_indication_pdu_t; - -#define NFAPI_CQI_RAW_MAX_LEN 12 -typedef struct { - uint8_t pdu[NFAPI_CQI_RAW_MAX_LEN]; -} nfapi_cqi_indication_raw_pdu_t; - -#define NFAPI_CQI_IND_MAX_PDU 100 -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_cqis; - nfapi_cqi_indication_pdu_t* cqi_pdu_list; - nfapi_cqi_indication_raw_pdu_t* cqi_raw_pdu_list; -} nfapi_cqi_indication_body_t; -#define NFAPI_CQI_INDICATION_BODY_TAG 0x202e - -typedef struct { - nfapi_tl_t tl; - uint16_t rnti; - uint8_t preamble; - uint16_t timing_advance; -} nfapi_preamble_pdu_rel8_t; -#define NFAPI_PREAMBLE_REL8_TAG 0x2032 - -typedef struct { - nfapi_tl_t tl; - uint16_t timing_advance_r9; -} nfapi_preamble_pdu_rel9_t; -#define NFAPI_PREAMBLE_REL9_TAG 0x2033 - -typedef struct { - nfapi_tl_t tl; - uint8_t rach_resource_type; -} nfapi_preamble_pdu_rel13_t; -#define NFAPI_PREAMBLE_REL13_TAG 0x2051 - -typedef struct { - uint16_t instance_length; - nfapi_preamble_pdu_rel8_t preamble_rel8; - nfapi_preamble_pdu_rel9_t preamble_rel9; - nfapi_preamble_pdu_rel13_t preamble_rel13; -} nfapi_preamble_pdu_t; - -#define NFAPI_PREAMBLE_MAX_PDU 100 -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_preambles; - nfapi_preamble_pdu_t* preamble_list; -} nfapi_rach_indication_body_t; -#define NFAPI_RACH_INDICATION_BODY_TAG 0x2031 - -#define NFAPI_NUM_RB_MAX 1000 -typedef struct { - nfapi_tl_t tl; - uint16_t doppler_estimation; - uint16_t timing_advance; - uint8_t number_of_resource_blocks; - uint8_t rb_start; - uint8_t snr[NFAPI_NUM_RB_MAX]; -} nfapi_srs_indication_fdd_rel8_t; -#define NFAPI_SRS_INDICATION_FDD_REL8_TAG 0x2035 - -typedef struct { - nfapi_tl_t tl; - uint16_t timing_advance_r9; -} nfapi_srs_indication_fdd_rel9_t; -#define NFAPI_SRS_INDICATION_FDD_REL9_TAG 0x2036 - -typedef struct { - nfapi_tl_t tl; - uint8_t uppts_symbol; -} nfapi_srs_indication_ttd_rel10_t; -#define NFAPI_SRS_INDICATION_TDD_REL10_TAG 0x2037 - -typedef struct { - nfapi_tl_t tl; - uint16_t ul_rtoa; -} nfapi_srs_indication_fdd_rel11_t; -#define NFAPI_SRS_INDICATION_FDD_REL11_TAG 0x2053 - - -typedef struct { - nfapi_tl_t tl; - uint8_t num_prb_per_subband; - uint8_t number_of_subbands; - uint8_t num_atennas; - struct { - uint8_t subband_index; - uint16_t channel[NFAPI_MAX_NUM_PHYSICAL_ANTENNAS]; - } subands[NFAPI_MAX_NUM_SUBBANDS]; -} nfapi_tdd_channel_measurement_t; -#define NFAPI_TDD_CHANNEL_MEASUREMENT_TAG 0x2054 - -typedef struct { - uint16_t instance_length; - nfapi_rx_ue_information rx_ue_information; - nfapi_srs_indication_fdd_rel8_t srs_indication_fdd_rel8; - nfapi_srs_indication_fdd_rel9_t srs_indication_fdd_rel9; - nfapi_srs_indication_ttd_rel10_t srs_indication_tdd_rel10; - nfapi_srs_indication_fdd_rel11_t srs_indication_fdd_rel11; - nfapi_tdd_channel_measurement_t tdd_channel_measurement; -} nfapi_srs_indication_pdu_t; - -#define NFAPI_SRS_IND_MAX_PDU 16 -typedef struct { - nfapi_tl_t tl; - uint8_t number_of_ues; - nfapi_srs_indication_pdu_t* srs_pdu_list; -} nfapi_srs_indication_body_t; -#define NFAPI_SRS_INDICATION_BODY_TAG 0x2034 - -typedef struct { - nfapi_tl_t tl; - uint16_t length; - uint16_t offset; - uint8_t ul_cqi; - uint16_t timing_advance; -} nfapi_rx_indication_rel8_t; -#define NFAPI_RX_INDICATION_REL8_TAG 0x2024 - -typedef struct { - nfapi_tl_t tl; - uint16_t timing_advance_r9; - } nfapi_rx_indication_rel9_t; -#define NFAPI_RX_INDICATION_REL9_TAG 0x2025 - -typedef struct { - nfapi_rx_ue_information rx_ue_information; - nfapi_rx_indication_rel8_t rx_indication_rel8; - nfapi_rx_indication_rel9_t rx_indication_rel9; - uint8_t* data; -} nfapi_rx_indication_pdu_t; - -#define NFAPI_RX_IND_MAX_PDU 100 -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_pdus; - nfapi_rx_indication_pdu_t* rx_pdu_list; -} nfapi_rx_indication_body_t; -#define NFAPI_RX_INDICATION_BODY_TAG 0x2023 - -typedef struct { - nfapi_tl_t tl; - uint8_t harq_tb1; -} nfapi_nb_harq_indication_fdd_rel13_t; -#define NFAPI_NB_HARQ_INDICATION_FDD_REL13_TAG 0x2064 - -typedef struct { - uint16_t instance_length; - nfapi_rx_ue_information rx_ue_information; - nfapi_nb_harq_indication_fdd_rel13_t nb_harq_indication_fdd_rel13; - nfapi_ul_cqi_information_t ul_cqi_information; -} nfapi_nb_harq_indication_pdu_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_harqs; - nfapi_nb_harq_indication_pdu_t* nb_harq_pdu_list; -} nfapi_nb_harq_indication_body_t; -#define NFAPI_NB_HARQ_INDICATION_BODY_TAG 0x2063 - -typedef struct { - nfapi_tl_t tl; - uint16_t rnti; - uint8_t initial_sc; - uint16_t timing_advance; - uint8_t nrach_ce_level; -} nfapi_nrach_indication_pdu_rel13_t; -#define NFAPI_NRACH_INDICATION_REL13_TAG 0x2066 - -typedef struct { - nfapi_nrach_indication_pdu_rel13_t nrach_indication_rel13; -} nfapi_nrach_indication_pdu_t; - -typedef struct { - nfapi_tl_t tl; - uint8_t number_of_initial_scs_detected; - nfapi_nrach_indication_pdu_t* nrach_pdu_list; -} nfapi_nrach_indication_body_t; -#define NFAPI_NRACH_INDICATION_BODY_TAG 0x2065 - -typedef struct { - nfapi_tl_t tl; - uint32_t handle; - uint32_t mp_cca; - uint32_t n_cca; - uint32_t offset; - uint32_t lte_txop_sf; - uint16_t txop_sfn_sf_end; - uint32_t lbt_mode; -} nfapi_lbt_pdsch_req_pdu_rel13_t; -#define NFAPI_LBT_PDSCH_REQ_PDU_REL13_TAG 0x2056 - -typedef struct { - nfapi_lbt_pdsch_req_pdu_rel13_t lbt_pdsch_req_pdu_rel13; -} nfapi_lbt_pdsch_req_pdu; - -typedef struct { - nfapi_tl_t tl; - uint32_t handle; - uint32_t offset; - uint16_t sfn_sf_end; - uint32_t lbt_mode; -} nfapi_lbt_drs_req_pdu_rel13_t; -#define NFAPI_LBT_DRS_REQ_PDU_REL13_TAG 0x2057 - -typedef struct { - nfapi_lbt_drs_req_pdu_rel13_t lbt_drs_req_pdu_rel13; -} nfapi_lbt_drs_req_pdu; - -typedef struct { - uint8_t pdu_type; - uint8_t pdu_size; - union { - nfapi_lbt_pdsch_req_pdu lbt_pdsch_req_pdu; - nfapi_lbt_drs_req_pdu lbt_drs_req_pdu; - }; -} nfapi_lbt_dl_config_request_pdu_t; - -#define NFAPI_LBT_DL_CONFIG_REQ_MAX_PDU 16 -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_pdus; - nfapi_lbt_dl_config_request_pdu_t* lbt_dl_config_req_pdu_list; -} nfapi_lbt_dl_config_request_body_t; -#define NFAPI_LBT_DL_CONFIG_REQUEST_BODY_TAG 0x2055 - - -typedef struct { - nfapi_tl_t tl; - uint32_t handle; - uint32_t result; - uint32_t lte_txop_symbols; - uint32_t initial_partial_sf; -} nfapi_lbt_pdsch_rsp_pdu_rel13_t; -#define NFAPI_LBT_PDSCH_RSP_PDU_REL13_TAG 0x2059 - -typedef struct { - nfapi_lbt_pdsch_rsp_pdu_rel13_t lbt_pdsch_rsp_pdu_rel13; -} nfapi_lbt_pdsch_rsp_pdu; - -typedef struct { - nfapi_tl_t tl; - uint32_t handle; - uint32_t result; -} nfapi_lbt_drs_rsp_pdu_rel13_t; -#define NFAPI_LBT_DRS_RSP_PDU_REL13_TAG 0x205A - -typedef struct { - nfapi_lbt_drs_rsp_pdu_rel13_t lbt_drs_rsp_pdu_rel13; -} nfapi_lbt_drs_rsp_pdu; - - -typedef struct { - uint8_t pdu_type; - uint8_t pdu_size; - union { - nfapi_lbt_pdsch_rsp_pdu lbt_pdsch_rsp_pdu; - nfapi_lbt_drs_rsp_pdu lbt_drs_rsp_pdu; - }; -} nfapi_lbt_dl_indication_pdu_t; - -#define NFAPI_LBT_IND_MAX_PDU 16 -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_pdus; - nfapi_lbt_dl_indication_pdu_t* lbt_indication_pdu_list; -} nfapi_lbt_dl_indication_body_t; -#define NFAPI_LBT_DL_INDICATION_BODY_TAG 0x2058 - -typedef struct { -} nfapi_error_indication_msg_invalid_state; - -typedef struct { -} nfapi_error_indication_msg_bch_missing; - -typedef struct { - uint16_t recieved_sfn_sf; - uint16_t expected_sfn_sf; -} nfapi_error_indication_sfn_out_of_sync; - -typedef struct { - uint8_t sub_error_code; - uint8_t direction; - uint16_t rnti; - uint8_t pdu_type; -} nfapi_error_indication_msg_pdu_err; - -typedef struct { - uint16_t recieved_sfn_sf; - uint16_t expected_sfn_sf; -} nfapi_error_indication_msg_invalid_sfn; - -typedef struct { - uint8_t sub_error_code; - uint8_t phich_lowest_ul_rb_index; -} nfapi_error_indication_msg_hi_err; - -typedef struct { - uint8_t sub_error_code; - uint16_t pdu_index; -} nfapi_error_indication_msg_tx_err; - -// -// P4 Message Structures -// - -typedef struct { - nfapi_tl_t tl; - uint8_t frequency_band_indicator; - uint16_t measurement_period; - uint8_t bandwidth; - uint32_t timeout; - uint8_t number_of_earfcns; - uint16_t earfcn[NFAPI_MAX_CARRIER_LIST]; -} nfapi_lte_rssi_request_t; - -#define NFAPI_LTE_RSSI_REQUEST_TAG 0x3000 - -#define NFAPI_P4_START_TAG NFAPI_LTE_RSSI_REQUEST_TAG - -typedef struct { - nfapi_tl_t tl; - uint8_t frequency_band_indicator; - uint16_t measurement_period; - uint32_t timeout; - uint8_t number_of_uarfcns; - uint16_t uarfcn[NFAPI_MAX_CARRIER_LIST]; -} nfapi_utran_rssi_request_t; - -#define NFAPI_UTRAN_RSSI_REQUEST_TAG 0x3001 - -typedef struct { - uint16_t arfcn; - uint8_t direction; -} nfapi_arfcn_t; - -typedef struct { - nfapi_tl_t tl; - uint8_t frequency_band_indicator; - uint16_t measurement_period; - uint32_t timeout; - uint8_t number_of_arfcns; - nfapi_arfcn_t arfcn[NFAPI_MAX_CARRIER_LIST]; -} nfapi_geran_rssi_request_t; - -#define NFAPI_GERAN_RSSI_REQUEST_TAG 0x3002 - - - -typedef struct { - uint16_t earfcn; - uint8_t number_of_ro_dl; - uint8_t ro_dl[NFAPI_MAX_RO_DL]; -} nfapi_earfcn_t; - -typedef struct { - nfapi_tl_t tl; - uint8_t frequency_band_indicator; - uint16_t measurement_period; - uint32_t timeout; - uint8_t number_of_earfcns; - nfapi_earfcn_t earfcn[NFAPI_MAX_CARRIER_LIST]; -} nfapi_nb_iot_rssi_request_t; - -#define NFAPI_NB_IOT_RSSI_REQUEST_TAG 0x3020 - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_rssi; - int16_t rssi[NFAPI_MAX_RSSI]; -} nfapi_rssi_indication_body_t; - -#define NFAPI_RSSI_INDICATION_TAG 0x3003 - -typedef struct { - nfapi_tl_t tl; - uint16_t earfcn; - uint8_t measurement_bandwidth; - uint8_t exhaustive_search; - uint32_t timeout; - uint8_t number_of_pci; - uint16_t pci[NFAPI_MAX_PCI_LIST]; -} nfapi_lte_cell_search_request_t; - -#define NFAPI_LTE_CELL_SEARCH_REQUEST_TAG 0x3004 - -typedef struct { - nfapi_tl_t tl; - uint16_t uarfcn; - uint8_t exhaustive_search; - uint32_t timeout; - uint8_t number_of_psc; - uint16_t psc[NFAPI_MAX_PSC_LIST]; -} nfapi_utran_cell_search_request_t; - -#define NFAPI_UTRAN_CELL_SEARCH_REQUEST_TAG 0x3005 - -typedef struct { - nfapi_tl_t tl; - uint32_t timeout; - uint8_t number_of_arfcn; - uint16_t arfcn[NFAPI_MAX_ARFCN_LIST]; -} nfapi_geran_cell_search_request_t; - -#define NFAPI_GERAN_CELL_SEARCH_REQUEST_TAG 0x3006 - -typedef struct { - nfapi_tl_t tl; - uint16_t earfcn; - uint8_t ro_dl; - uint8_t exhaustive_search; - uint32_t timeout; - uint8_t number_of_pci; - uint16_t pci[NFAPI_MAX_PCI_LIST]; -} nfapi_nb_iot_cell_search_request_t; - -#define NFAPI_NB_IOT_CELL_SEARCH_REQUEST_TAG 0x3021 - -typedef struct { - uint16_t pci; - uint8_t rsrp; - uint8_t rsrq; - int16_t frequency_offset; -} nfapi_lte_found_cell_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_lte_cells_found; - nfapi_lte_found_cell_t lte_found_cells[NFAPI_MAX_LTE_CELLS_FOUND]; -} nfapi_lte_cell_search_indication_t; - -#define NFAPI_LTE_CELL_SEARCH_INDICATION_TAG 0x3007 - -typedef struct { - uint16_t psc; - uint8_t rscp; - uint8_t ecno; - int16_t frequency_offset; -} nfapi_utran_found_cell_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_utran_cells_found; - nfapi_utran_found_cell_t utran_found_cells[NFAPI_MAX_UTRAN_CELLS_FOUND]; -} nfapi_utran_cell_search_indication_t; - -#define NFAPI_UTRAN_CELL_SEARCH_INDICATION_TAG 0x3008 - -typedef struct { - uint16_t arfcn; - uint8_t bsic; - uint8_t rxlev; - uint8_t rxqual; - int16_t frequency_offset; - uint32_t sfn_offset; -} nfapi_gsm_found_cell_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_gsm_cells_found; - nfapi_gsm_found_cell_t gsm_found_cells[NFAPI_MAX_GSM_CELLS_FOUND]; -} nfapi_geran_cell_search_indication_t; - -#define NFAPI_GERAN_CELL_SEARCH_INDICATION_TAG 0x3009 - -typedef struct { - uint16_t pci; - uint8_t rsrp; - uint8_t rsrq; - int16_t frequency_offset; -} nfapi_nb_iot_found_cell_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t number_of_nb_iot_cells_found; - nfapi_nb_iot_found_cell_t nb_iot_found_cells[NFAPI_MAX_NB_IOT_CELLS_FOUND]; -} nfapi_nb_iot_cell_search_indication_t; - -#define NFAPI_NB_IOT_CELL_SEARCH_INDICATION_TAG 0x3022 - -typedef nfapi_opaqaue_data_t nfapi_pnf_cell_search_state_t; - -#define NFAPI_PNF_CELL_SEARCH_STATE_TAG 0x300A - -typedef struct { - nfapi_tl_t tl; - uint16_t earfcn; - uint16_t pci; - uint32_t timeout; -} nfapi_lte_broadcast_detect_request_t; - -#define NFAPI_LTE_BROADCAST_DETECT_REQUEST_TAG 0x300B - -typedef struct { - nfapi_tl_t tl; - uint16_t uarfcn; - uint16_t psc; - uint32_t timeout; -} nfapi_utran_broadcast_detect_request_t; - -#define NFAPI_UTRAN_BROADCAST_DETECT_REQUEST_TAG 0x300C - -typedef struct { - nfapi_tl_t tl; - uint16_t earfcn; - uint8_t ro_dl; - uint16_t pci; - uint32_t timeout; -} nfapi_nb_iot_broadcast_detect_request_t; - -#define NFAPI_NB_IOT_BROADCAST_DETECT_REQUEST_TAG 0x3023 - -typedef struct { - nfapi_tl_t tl; - uint8_t number_of_tx_antenna; - uint16_t mib_length; - uint8_t mib[NFAPI_MAX_MIB_LENGTH]; - uint32_t sfn_offset; -} nfapi_lte_broadcast_detect_indication_t; - -#define NFAPI_LTE_BROADCAST_DETECT_INDICATION_TAG 0x300E - -typedef struct { - nfapi_tl_t tl; - uint16_t mib_length; - uint8_t mib[NFAPI_MAX_MIB_LENGTH]; - uint32_t sfn_offset; -} nfapi_utran_broadcast_detect_indication_t; - -#define NFAPI_UTRAN_BROADCAST_DETECT_INDICATION_TAG 0x300F - - -typedef struct { - nfapi_tl_t tl; - uint8_t number_of_tx_antenna; - uint16_t mib_length; - uint8_t mib[NFAPI_MAX_MIB_LENGTH]; - uint32_t sfn_offset; -} nfapi_nb_iot_broadcast_detect_indication_t; - -#define NFAPI_NB_IOT_BROADCAST_DETECT_INDICATION_TAG 0x3024 - -#define NFAPI_PNF_CELL_BROADCAST_STATE_TAG 0x3010 - -typedef struct { - nfapi_tl_t tl; - uint16_t earfcn; - uint16_t pci; - uint16_t downlink_channel_bandwidth; - uint8_t phich_configuration; - uint8_t number_of_tx_antenna; - uint8_t retry_count; - uint32_t timeout; -} nfapi_lte_system_information_schedule_request_t; - -#define NFAPI_LTE_SYSTEM_INFORMATION_SCHEDULE_REQUEST_TAG 0x3011 - - -typedef struct { - nfapi_tl_t tl; - uint16_t earfcn; - uint8_t ro_dl; - uint16_t pci; - uint8_t scheduling_info_sib1_nb; - uint32_t timeout; -} nfapi_nb_iot_system_information_schedule_request_t; - -#define NFAPI_NB_IOT_SYSTEM_INFORMATION_SCHEDULE_REQUEST_TAG 0x3025 - -typedef nfapi_opaqaue_data_t nfapi_pnf_cell_broadcast_state_t; - -typedef struct { - uint8_t si_periodicity; - uint8_t si_index; -} nfapi_lte_system_information_si_periodicity_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t earfcn; - uint16_t pci; - uint16_t downlink_channel_bandwidth; - uint8_t phich_configuration; - uint8_t number_of_tx_antenna; - uint8_t number_of_si_periodicity; - nfapi_lte_system_information_si_periodicity_t si_periodicity[NFAPI_MAX_SI_PERIODICITY]; - uint8_t si_window_length; - uint32_t timeout; -} nfapi_lte_system_information_request_t; - -#define NFAPI_LTE_SYSTEM_INFORMATION_REQUEST_TAG 0x3014 - -typedef struct { - nfapi_tl_t tl; - uint16_t uarfcn; - uint16_t psc; - uint32_t timeout; -} nfapi_utran_system_information_request_t; - -#define NFAPI_UTRAN_SYSTEM_INFORMATION_REQUEST_TAG 0x3015 - -typedef struct { - nfapi_tl_t tl; - uint16_t arfcn; - uint8_t bsic; - uint32_t timeout; -} nfapi_geran_system_information_request_t; - -#define NFAPI_GERAN_SYSTEM_INFORMATION_REQUEST_TAG 0x3016 - -typedef struct { - uint8_t si_periodicity; - uint8_t si_repetition_pattern; - uint8_t si_tb_size; - uint8_t number_of_si_index; - uint8_t si_index[NFAPI_MAX_SI_INDEX]; -} nfapi_nb_iot_system_information_si_periodicity_t; - -typedef struct { - nfapi_tl_t tl; - uint16_t earfcn; - uint8_t ro_dl; - uint16_t pci; - uint8_t number_of_si_periodicity; - nfapi_nb_iot_system_information_si_periodicity_t si_periodicity[NFAPI_MAX_SI_PERIODICITY]; - uint8_t si_window_length; - uint32_t timeout; -} nfapi_nb_iot_system_information_request_t; - -#define NFAPI_NB_IOT_SYSTEM_INFORMATION_REQUEST_TAG 0x3027 - -typedef struct { - nfapi_tl_t tl; - uint8_t sib_type; - uint16_t sib_length; - uint8_t sib[NFAPI_MAX_SIB_LENGTH]; -} nfapi_lte_system_information_indication_t; - -#define NFAPI_LTE_SYSTEM_INFORMATION_INDICATION_TAG 0x3018 - -typedef struct { - nfapi_tl_t tl; - uint16_t sib_length; - uint8_t sib[NFAPI_MAX_SIB_LENGTH]; -} nfapi_utran_system_information_indication_t; - -#define NFAPI_UTRAN_SYSTEM_INFORMATION_INDICATION_TAG 0x3019 - -typedef struct { - nfapi_tl_t tl; - uint16_t si_length; - uint8_t si[NFAPI_MAX_SI_LENGTH]; -} nfapi_geran_system_information_indication_t; - -#define NFAPI_GERAN_SYSTEM_INFORMATION_INDICATION_TAG 0x301a - -typedef struct { - nfapi_tl_t tl; - uint8_t sib_type; - uint16_t sib_length; - uint8_t sib[NFAPI_MAX_SIB_LENGTH]; -} nfapi_nb_iot_system_information_indication_t; - -#define NFAPI_NB_IOT_SYSTEM_INFORMATION_INDICATION_TAG 0x3026 - - -// -// Top level NFAP messages -// - -// -// P7 -// - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_dl_config_request_body_t dl_config_request_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_dl_config_request_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_ul_config_request_body_t ul_config_request_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_ul_config_request_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_hi_dci0_request_body_t hi_dci0_request_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_hi_dci0_request_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_tx_request_body_t tx_request_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_tx_request_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; -} nfapi_subframe_indication_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_harq_indication_body_t harq_indication_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_harq_indication_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_crc_indication_body_t crc_indication_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_crc_indication_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_sr_indication_body_t sr_indication_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_sr_indication_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_cqi_indication_body_t cqi_indication_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_cqi_indication_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_rach_indication_body_t rach_indication_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_rach_indication_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_srs_indication_body_t srs_indication_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_srs_indication_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_rx_indication_body_t rx_indication_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_rx_indication_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_nb_harq_indication_body_t nb_harq_indication_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_nb_harq_indication_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_nrach_indication_body_t nrach_indication_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_nrach_indication_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_lbt_dl_config_request_body_t lbt_dl_config_request_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_lbt_dl_config_request_t; - -typedef struct { - nfapi_p7_message_header_t header; - uint16_t sfn_sf; - nfapi_lbt_dl_indication_body_t lbt_dl_indication_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_lbt_dl_indication_t; - - -typedef struct { - nfapi_p7_message_header_t header; - uint8_t message_id; - uint8_t error_code; - union { - nfapi_error_indication_msg_invalid_state msg_invalid_state; - nfapi_error_indication_msg_bch_missing msg_bch_missing; - nfapi_error_indication_sfn_out_of_sync sfn_out_of_sync; - nfapi_error_indication_msg_pdu_err msg_pdu_err; - nfapi_error_indication_msg_invalid_sfn msg_invalid_sfn; - nfapi_error_indication_msg_hi_err msg_hi_err; - nfapi_error_indication_msg_tx_err msg_tx_err; - }; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_error_indication_t; - -// -// P4 Messages -// - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint8_t rat_type; - union { - nfapi_lte_rssi_request_t lte_rssi_request; - nfapi_utran_rssi_request_t utran_rssi_request; - nfapi_geran_rssi_request_t geran_rssi_request; - nfapi_nb_iot_rssi_request_t nb_iot_rssi_request; - }; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_rssi_request_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_rssi_response_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_rssi_indication_body_t rssi_indication_body; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_rssi_indication_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint8_t rat_type; - union { - nfapi_lte_cell_search_request_t lte_cell_search_request; - nfapi_utran_cell_search_request_t utran_cell_search_request; - nfapi_geran_cell_search_request_t geran_cell_search_request; - nfapi_nb_iot_cell_search_request_t nb_iot_cell_search_request; - }; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_cell_search_request_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_cell_search_response_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_lte_cell_search_indication_t lte_cell_search_indication; - nfapi_utran_cell_search_indication_t utran_cell_search_indication; - nfapi_geran_cell_search_indication_t geran_cell_search_indication; - nfapi_pnf_cell_search_state_t pnf_cell_search_state; - nfapi_nb_iot_cell_search_indication_t nb_iot_cell_search_indication; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_cell_search_indication_t; - - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint8_t rat_type; - union { - nfapi_lte_broadcast_detect_request_t lte_broadcast_detect_request; - nfapi_utran_broadcast_detect_request_t utran_broadcast_detect_request; - nfapi_nb_iot_broadcast_detect_request_t nb_iot_broadcast_detect_request; - }; - nfapi_pnf_cell_search_state_t pnf_cell_search_state; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_broadcast_detect_request_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_broadcast_detect_response_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_lte_broadcast_detect_indication_t lte_broadcast_detect_indication; - nfapi_utran_broadcast_detect_indication_t utran_broadcast_detect_indication; - nfapi_nb_iot_broadcast_detect_indication_t nb_iot_broadcast_detect_indication; - nfapi_pnf_cell_broadcast_state_t pnf_cell_broadcast_state; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_broadcast_detect_indication_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint8_t rat_type; - union { - nfapi_lte_system_information_schedule_request_t lte_system_information_schedule_request; - nfapi_nb_iot_system_information_schedule_request_t nb_iot_system_information_schedule_request; - }; - nfapi_pnf_cell_broadcast_state_t pnf_cell_broadcast_state; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_system_information_schedule_request_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_system_information_schedule_response_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_lte_system_information_indication_t lte_system_information_indication; - nfapi_nb_iot_system_information_indication_t nb_iot_system_information_indication; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_system_information_schedule_indication_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint8_t rat_type; - union { - nfapi_lte_system_information_request_t lte_system_information_request; - nfapi_utran_system_information_request_t utran_system_information_request; - nfapi_geran_system_information_request_t geran_system_information_request; - nfapi_nb_iot_system_information_request_t nb_iot_system_information_request; - }; - nfapi_pnf_cell_broadcast_state_t pnf_cell_broadcast_state; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_system_information_request_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_system_information_response_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_lte_system_information_indication_t lte_system_information_indication; - nfapi_utran_system_information_indication_t utran_system_information_indication; - nfapi_geran_system_information_indication_t geran_system_information_indication; - nfapi_nb_iot_system_information_indication_t nb_iot_system_information_indication; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_system_information_indication_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_nmm_stop_request_t; - -typedef struct { - nfapi_p4_p5_message_header_t header; - uint32_t error_code; - nfapi_vendor_extension_tlv_t vendor_extension; -} nfapi_nmm_stop_response_t; - -// -// Configuration options for the encode decode functions -// - -/*! Configuration options for the p7 pack unpack functions - * - */ -typedef struct nfapi_p7_codec_config { - - /*! Optional call back to allow the user to define the memory allocator. - * \param size The size of the memory to allocate - * \return a pointer to a valid memory block or 0 if it has failed. - * - * If not set the nfapi unpack functions will use malloc - */ - void* (*allocate)(size_t size); - - /*! Optional call back to allow the user to define the memory deallocator. - * \param ptr A poiner to a memory block allocated by the allocate callback - * - * If not set the client should use free - */ - void (*deallocate)(void* ptr); - - /*! Optional call back function to handle unpacking vendor extension tlv. - * \param tl A pointer to a decoded tag length structure - * \param ppReadPackedMsg A handle to the read buffer. - * \param end The end of the read buffer - * \param ve A handle to a vendor extention structure that the call back should allocate if the structure can be decoded - * \param config A pointer to the p7 codec configuration - * \return return 0 if packed successfully, -1 if failed. - * - * If not set the tlv will be skipped - * - * Client should use the help methods in nfapi.h to decode the vendor extention. - * - * \todo Add code example - */ - int (*unpack_vendor_extension_tlv)(nfapi_tl_t* tl, uint8_t **ppReadPackedMsg, uint8_t *end, void** ve, struct nfapi_p7_codec_config* config); - - /*! Optional call back function to handle packing vendor extension tlv. - * \param ve A pointer to a vendor extention structure. - * \param ppWritePackedMsg A handle to the write buffer - * \param end The end of the write buffer. The callee should make sure not to write beyond the end - * \param config A pointer to the p7 codec configuration - * \return return 0 if packed successfully, -1 if failed. - * - * If not set the the tlv will be skipped - * - * Client should use the help methods in nfapi.h to encode the vendor extention - * - * \todo Add code example - */ - int (*pack_vendor_extension_tlv)(void* ve, uint8_t **ppWritePackedMsg, uint8_t *end, struct nfapi_p7_codec_config* config); - - /*! Optional call back function to handle unpacking vendor extension messages. - * \param header A pointer to a decode P7 message header for the vendor extention message - * \param ppReadPackedMsg A handle to the encoded data buffer - * \param end A pointer to the end of the encoded data buffer - * \param config A pointer to the p7 codec configuration - * \return 0 if unpacked successfully, -1 if failed - * - * If not set the message will be ignored - * - * If the message if is unknown the function should return -1 - */ - int (*unpack_p7_vendor_extension)(nfapi_p7_message_header_t* header, uint8_t **ppReadPackedMsg, uint8_t *end, struct nfapi_p7_codec_config* config); - - /*! Optional call back function to handle packing vendor extension messages. - * \param header A poiner to a P7 message structure for the venfor extention message - * \param ppWritePackedmsg A handle to the buffer to write the encoded message into - * \param end A pointer to the end of the buffer - * \param cofig A pointer to the p7 codec configuration - * \return 0 if packed successfully, -1 if failed - * - * If not set the the message will be ingored - * - * If the message if is unknown the function should return -1 - */ - int (*pack_p7_vendor_extension)(nfapi_p7_message_header_t* header, uint8_t **ppWritePackedmsg, uint8_t *end, struct nfapi_p7_codec_config* config); - - /*! Optional user data that will be passed back with callbacks - */ - void* user_data; - -} nfapi_p7_codec_config_t; - -/*! Configuration options for the p4 & p5 pack unpack functions - * - */ -typedef struct nfapi_p4_p5_codec_config { - - /*! Optional call back to allow the user to define the memory allocator. - * \param size The size of the memory to allocate - * \return a pointer to a valid memory block or 0 if it has failed. - * - * If not set the nfapi unpack functions will use malloc - */ - void* (*allocate)(size_t size); - - /*! Optional call back to allow the user to define the memory deallocator. - * \param ptr A poiner to a memory block allocated by the allocate callback - * - * If not set free will be used - */ - void (*deallocate)(void* ptr); - - /*! Optional call back function to handle unpacking vendor extension tlv. - * \param tl A pointer to a decoded tag length structure - * \param ppReadPackedMsg A handle to the data buffer to decode - * \param end A pointer to the end of the buffer - * \param ve A handle to a vendor extention structure that will be allocated by this callback - * \param config A pointer to the P4/P5 codec configuration - * \return 0 if unpacked successfully, -1 if failed - * - * If not set the tlv will be skipped - */ - int (*unpack_vendor_extension_tlv)(nfapi_tl_t* tl, uint8_t **ppReadPackedMsg, uint8_t *end, void** ve, struct nfapi_p4_p5_codec_config* config); - - /*! Optional call back function to handle packing vendor extension tlv. - * \param ve - * \param ppWritePackedMsg A handle to the data buffer pack the tlv into - * \param end A pointer to the end of the buffer - * \param config A pointer to the P4/P5 codec configuration - * \return 0 if packed successfully, -1 if failed - * - * If not set the the tlv will be skipped - */ - int (*pack_vendor_extension_tlv)(void* ve, uint8_t **ppWritePackedMsg, uint8_t *end, struct nfapi_p4_p5_codec_config* config); - - /*! Optional call back function to handle unpacking vendor extension messages. - * \param header A pointer to a decode P4/P5 message header - * \param ppReadPackgedMsg A handle to the data buffer to decode - * \param end A pointer to the end of the buffer - * \param config A pointer to the P4/P5 codec configuration - * \return 0 if packed successfully, -1 if failed - * - * If not set the message will be ignored - */ - int (*unpack_p4_p5_vendor_extension)(nfapi_p4_p5_message_header_t* header, uint8_t **ppReadPackedMsg, uint8_t *end, struct nfapi_p4_p5_codec_config* config); - - /*! Optional call back function to handle packing vendor extension messages. - * \param header A pointer to the P4/P5 message header to be encoded - * \param ppWritePackedMsg A handle to the data buffer pack the message into - * \param end A pointer to the end of the buffer - * \param config A pointer to the P4/P5 codec configuration - * \return 0 if packed successfully, -1 if failed - * - * If not set the the message will be ingored - */ - int (*pack_p4_p5_vendor_extension)(nfapi_p4_p5_message_header_t* header, uint8_t **ppwritepackedmsg, uint8_t *end, struct nfapi_p4_p5_codec_config* config); - - /*! Optional user data that will be passed back with callbacks - */ - void* user_data; - -} nfapi_p4_p5_codec_config_t; - -// -// Functions -// - -/*! \brief Encodes an NFAPI P4 message to a buffer - * \param pMessageBuf A pointer to a nfapi p4 message structure - * \param messageBufLen The size of the p4 message structure - * \param pPackedBuf A pointer to the buffer that the p4 message will be packed into - * \param packedBufLen The size of the buffer - * \param config A pointer to the nfapi configuration structure - * \return 0 means success, -1 means failure. - * - * The function will encode a nFAPI P4 message structure pointed to be pMessageBuf into a byte stream pointed to by pPackedBuf. - * - */ -int nfapi_p4_message_pack(void *pMessageBuf, uint32_t messageBufLen, void *pPackedBuf, uint32_t packedBufLen, nfapi_p4_p5_codec_config_t* config); - -/*! \brief Decodes a NFAPI P4 message header - * \param pMessageBuf A pointer to an encoded P4 message header - * \param messageBufLen The size of the encoded P4 message header - * \param pUnpackedBuf A pointer to the nfapi_message_header - * \param unpackedBufLen The size of nfapi_message_header structure. - * \param config A pointer to the nfapi configuration structure - * \return 0 means success, -1 means failure. - * - * The function will decode a byte stream pointed to by pMessageBuf into a nfapi_p4_p5_message_header structure pointer to by pUnpackedBuf - */ -int nfapi_p4_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t* config); - -/*! \brief Decodes a NFAPI P4 message - * \param pMessageBuf A pointer to an encoded P4 message - * \param messageBufLen The size of the encoded P4 message - * \param pUnpackedBuf A pointer to the nfapi_message_header - * \param unpackedBufLen The size of nfapi_message_header structure. - * \param config A pointer to the nfapi configuration structure - * \return 0 means success, -1 means failure. - * - * The function will decode a byte stream pointed to by pMessageBuf into a nfapi p4 message structure pointer to by pUnpackedBuf - */ -int nfapi_p4_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t* config); - -/*! \brief Encodes an NFAPI P5 message to a buffer - * \param pMessageBuf A pointer to a nfapi p5 message structure - * \param messageBufLen The size of the p5 message structure - * \param pPackedBuf A pointer to the buffer that the p5 message will be packed into - * \param packedBufLen The size of the buffer - * \param config A pointer to the nfapi configuration structure - * \return 0 means success, -1 means failure. - * - * The function will encode a nFAPI P5 message structure pointed to be pMessageBuf into a byte stream pointed to by pPackedBuf. - * - */ -int nfapi_p5_message_pack(void *pMessageBuf, uint32_t messageBufLen, void *pPackedBuf, uint32_t packedBufLen, nfapi_p4_p5_codec_config_t* config); - -/*! \brief Decodes an NFAPI P5 message header - * \param pMessageBuf A pointer to an encoded P5 message header - * \param messageBufLen The size of the encoded P5 message header - * \param pUnpackedBuf A pointer to the nfapi_message_header - * \param unpackedBufLen The size of nfapi_message_header structure. - * \param config A pointer to the nfapi configuration structure - * \return 0 means success, -1 means failure. - * - * The function will decode a byte stream pointed to by pMessageBuf into a nfapi_p4_p5_message_header structure pointer to by pUnpackedBuf - */ -int nfapi_p5_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t* config); - -/*! \brief Decodes a NFAPI P5 message - * \param pMessageBuf A pointer to an encoded P5 message - * \param messageBufLen The size of the encoded P5 message - * \param pUnpackedBuf A pointer to the nfapi_message_header - * \param unpackedBufLen The size of nfapi_message_header structure. - * \param config A pointer to the nfapi configuration structure - * \return 0 means success, -1 means failure. - * - * The function will decode a byte stream pointed to by pMessageBuf into a nfapi p5 message structure pointer to by pUnpackedBuf - */ -int nfapi_p5_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t* config); - -/*! \brief Encodes an NFAPI P7 message to a buffer - * \param pMessageBuf A pointer to a nfapi p7 message structure - * \param pPackedBuf A pointer to the buffer that the p7 message will be packed into - * \param packedBufLen The size of the buffer - * \param config A pointer to the nfapi configuration structure - * \return 0 means success, -1 means failure. - * - * The function will encode a nFAPI P7 message structure pointed to be pMessageBuf into a byte stream pointed to by pPackedBuf. - * - */ -int nfapi_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen, nfapi_p7_codec_config_t* config); - -/*! \brief Decodes an NFAPI P7 message header - * \param pMessageBuf A pointer to an encoded P7 message header - * \param messageBufLen The size of the encoded P7 message header - * \param pUnpackedBuf A pointer to the nfapi_message_header - * \param unpackedBufLen The size of nfapi_message_header structure. - * \param config A pointer to the nfapi configuration structure - * \return 0 means success, -1 means failure. - * - * The function will decode a byte stream pointed to by pMessageBuf into a nfapi_p7_message_header structure pointer to by pUnpackedBuf - - */ -int nfapi_p7_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p7_codec_config_t* config); - -/*! \brief Decodes a NFAPI P7 message - * \param pMessageBuf A pointer to an encoded P7 message - * \param messageBufLen The size of the encoded P7 message - * \param pUnpackedBuf A pointer to the nfapi_message_header - * \param unpackedBufLen The size of nfapi_message_header structure. - * \param config A pointer to the nfapi configuration structure - * \return 0 means success, -1 means failure. - * - * The function will decode a byte stream pointed to by pMessageBuf into a nfapi p7 message structure pointer to by pUnpackedBuf - */ -int nfapi_p7_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p7_codec_config_t* config); - -/*! \brief Calculates the checksum of a message - * - * \param buffer Pointer to the packed message - * \param len The length of the message - * \return The checksum. If there is an error the function with return -1 - */ -uint32_t nfapi_p7_calculate_checksum(uint8_t* buffer, uint32_t len); - -/*! \brief Calculates & updates the checksum in the message - * - * \param buffer Pointer to the packed message - * \param len The length of the message - * \return 0 means success, -1 means failure. - */ -int nfapi_p7_update_checksum(uint8_t* buffer, uint32_t len); - -/*! \brief Updates the transmition time stamp in the p7 message header - * - * \param buffer Pointer to the packed message - * \param timestamp The time stamp value - * \return 0 means success, -1 means failure. - */ -int nfapi_p7_update_transmit_timestamp(uint8_t* buffer, uint32_t timestamp); - -#endif /* _NFAPI_INTERFACE_H_ */ diff --git a/nfapi/oai_integration/nfapi.c b/nfapi/oai_integration/nfapi.c new file mode 100644 index 0000000000..5a3bc804c1 --- /dev/null +++ b/nfapi/oai_integration/nfapi.c @@ -0,0 +1,51 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include +#include + +void set_thread_priority(int priority) +{ + //printf("%s(priority:%d)\n", __FUNCTION__, priority); + + pthread_attr_t ptAttr; + + struct sched_param schedParam; + schedParam.__sched_priority = priority; //79; + if(sched_setscheduler(0, SCHED_RR, &schedParam) != 0) + { + printf("Failed to set scheduler to SCHED_RR\n"); + } + + if(pthread_attr_setschedpolicy(&ptAttr, SCHED_RR) != 0) + { + printf("Failed to set pthread sched policy SCHED_RR\n"); + } + + pthread_attr_setinheritsched(&ptAttr, PTHREAD_EXPLICIT_SCHED); + + struct sched_param thread_params; + thread_params.sched_priority = 20; + if(pthread_attr_setschedparam(&ptAttr, &thread_params) != 0) + { + printf("failed to set sched param\n"); + } +} diff --git a/nfapi/oai_integration/nfapi_pnf.c b/nfapi/oai_integration/nfapi_pnf.c new file mode 100644 index 0000000000..c63d504e43 --- /dev/null +++ b/nfapi/oai_integration/nfapi_pnf.c @@ -0,0 +1,1625 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include "debug.h" +#include "nfapi_pnf_interface.h" +#include "nfapi.h" +#include "nfapi_pnf.h" +#include "common/ran_context.h" +//#include "openair1/PHY/vars.h" +extern RAN_CONTEXT_t RC; + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "fapi_stub.h" +//#include "fapi_l1.h" +#include "UTIL/LOG/log.h" +#include "openair2/LAYER2/MAC/proto.h" + +#define NUM_P5_PHY 2 + +#define _GNU_SOURCE + +extern void phy_init_RU(RU_t*); +extern int config_sync_var; + +extern pthread_cond_t nfapi_sync_cond; +extern pthread_mutex_t nfapi_sync_mutex; +extern int nfapi_sync_var; + +extern int sync_var; + +extern void init_eNB_afterRU(void); +extern void handle_nfapi_dci_dl_pdu(PHY_VARS_eNB *eNB, int frame, int subframe, eNB_rxtx_proc_t *proc, nfapi_dl_config_request_pdu_t *dl_config_pdu); +extern void handle_nfapi_ul_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, nfapi_ul_config_request_pdu_t *ul_config_pdu, uint16_t frame,uint8_t subframe,uint8_t srs_present); +extern void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame, int subframe, eNB_rxtx_proc_t *proc, nfapi_dl_config_request_pdu_t *dl_config_pdu, uint8_t codeword_index, uint8_t *sdu); +extern void handle_nfapi_hi_dci0_dci_pdu(PHY_VARS_eNB *eNB,int frame, int subframe, eNB_rxtx_proc_t *proc, nfapi_hi_dci0_request_pdu_t *hi_dci0_config_pdu); +extern void handle_nfapi_hi_dci0_hi_pdu(PHY_VARS_eNB *eNB,int frame, int subframe, eNB_rxtx_proc_t *proc, nfapi_hi_dci0_request_pdu_t *hi_dci0_config_pdu); +extern void handle_nfapi_bch_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, nfapi_dl_config_request_pdu_t *dl_config_pdu, uint8_t *sdu); + +extern uint8_t nfapi_mode; + +nfapi_tx_request_pdu_t* tx_request_pdu[1023][10][10]; // [frame][subframe][max_num_pdus] + +uint8_t tx_pdus[32][8][4096]; + + +uint16_t phy_antenna_capability_values[] = { 1, 2, 4, 8, 16 }; + +nfapi_pnf_param_response_t g_pnf_param_resp; + + +nfapi_pnf_p7_config_t *p7_config_g = NULL; + +void* pnf_allocate(size_t size) { + return malloc(size); +} + +void pnf_deallocate(void* ptr) { + free(ptr); +} + + +typedef struct { + //public: + uint8_t enabled; + uint32_t rx_port; + uint32_t tx_port; + //std::string tx_addr; + char tx_addr[80]; +} udp_data; + +typedef struct { + uint16_t index; + uint16_t id; + uint8_t rfs[2]; + uint8_t excluded_rfs[2]; + + udp_data udp; + + char local_addr[80]; + int local_port; + + char* remote_addr; + int remote_port; + + uint8_t duplex_mode; + uint16_t dl_channel_bw_support; + uint16_t ul_channel_bw_support; + uint8_t num_dl_layers_supported; + uint8_t num_ul_layers_supported; + uint16_t release_supported; + uint8_t nmm_modes_supported; + + uint8_t dl_ues_per_subframe; + uint8_t ul_ues_per_subframe; + + uint8_t first_subframe_ind; + + // timing information recevied from the vnf + uint8_t timing_window; + uint8_t timing_info_mode; + uint8_t timing_info_period; + +} phy_info; + +typedef struct { + //public: + uint16_t index; + uint16_t band; + int16_t max_transmit_power; + int16_t min_transmit_power; + uint8_t num_antennas_supported; + uint32_t min_downlink_frequency; + uint32_t max_downlink_frequency; + uint32_t max_uplink_frequency; + uint32_t min_uplink_frequency; +} rf_info; + + +typedef struct { + + int release; + phy_info phys[2]; + rf_info rfs[2]; + + uint8_t sync_mode; + uint8_t location_mode; + uint8_t location_coordinates[6]; + uint32_t dl_config_timing; + uint32_t ul_config_timing; + uint32_t tx_timing; + uint32_t hi_dci0_timing; + + uint16_t max_phys; + uint16_t max_total_bw; + uint16_t max_total_dl_layers; + uint16_t max_total_ul_layers; + uint8_t shared_bands; + uint8_t shared_pa; + int16_t max_total_power; + uint8_t oui; + + uint8_t wireshark_test_mode; + +} pnf_info; + +typedef struct { + uint16_t phy_id; + nfapi_pnf_config_t* config; + phy_info* phy; + nfapi_pnf_p7_config_t* p7_config; +} pnf_phy_user_data_t; + +static pnf_info pnf; +static pthread_t pnf_start_pthread; + +extern void nfapi_log(char *file, char *func, int line, int comp, int level, const char* format, va_list args); + +void pnf_nfapi_trace(nfapi_trace_level_t nfapi_level, const char* message, ...) { + va_list args; + int oai_level; + + if (nfapi_level==NFAPI_TRACE_ERROR) { + oai_level = LOG_ERR; + } else if (nfapi_level==NFAPI_TRACE_WARN) { + oai_level = LOG_WARNING; + } else if (nfapi_level==NFAPI_TRACE_NOTE) { + oai_level = LOG_INFO; + } else if (nfapi_level==NFAPI_TRACE_INFO) { + oai_level = LOG_DEBUG; + } else { + oai_level = LOG_ERR; + } + + va_start(args, message); + nfapi_log("FILE>", "FUNC", 999, PHY, oai_level, message, args); + va_end(args); +} + +void pnf_set_thread_priority(int priority) { + + pthread_attr_t ptAttr; + + struct sched_param schedParam; + schedParam.__sched_priority = priority; + if(sched_setscheduler(0, SCHED_RR, &schedParam) != 0) { + printf("failed to set SCHED_RR\n"); + } + + if(pthread_attr_setschedpolicy(&ptAttr, SCHED_RR) != 0) { + printf("failed to set pthread SCHED_RR %d\n", errno); + } + + pthread_attr_setinheritsched(&ptAttr, PTHREAD_EXPLICIT_SCHED); + + struct sched_param thread_params; + thread_params.sched_priority = 20; + if(pthread_attr_setschedparam(&ptAttr, &thread_params) != 0) { + printf("failed to set sched param\n"); + } +} + +void* pnf_p7_thread_start(void* ptr) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] P7 THREAD %s\n", __FUNCTION__); + + pnf_set_thread_priority(79); + + nfapi_pnf_p7_config_t* config = (nfapi_pnf_p7_config_t*)ptr; + nfapi_pnf_p7_start(config); + + return 0; +} + +int pnf_param_request(nfapi_pnf_config_t* config, nfapi_pnf_param_request_t* req) { + + printf("[PNF] pnf param request\n"); + + nfapi_pnf_param_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_PARAM_RESPONSE; + resp.error_code = NFAPI_MSG_OK; + + pnf_info* pnf = (pnf_info*)(config->user_data); + + resp.pnf_param_general.tl.tag = NFAPI_PNF_PARAM_GENERAL_TAG; + resp.pnf_param_general.nfapi_sync_mode = pnf->sync_mode; + resp.pnf_param_general.location_mode = pnf->location_mode; + resp.pnf_param_general.dl_config_timing = pnf->dl_config_timing; + resp.pnf_param_general.tx_timing = pnf->tx_timing; + resp.pnf_param_general.ul_config_timing = pnf->ul_config_timing; + resp.pnf_param_general.hi_dci0_timing = pnf->hi_dci0_timing; + resp.pnf_param_general.maximum_number_phys = pnf->max_phys; + resp.pnf_param_general.maximum_total_bandwidth = pnf->max_total_bw; + resp.pnf_param_general.maximum_total_number_dl_layers = pnf->max_total_dl_layers; + resp.pnf_param_general.maximum_total_number_ul_layers = pnf->max_total_ul_layers; + resp.pnf_param_general.shared_bands = pnf->shared_bands; + resp.pnf_param_general.shared_pa = pnf->shared_pa; + resp.pnf_param_general.maximum_total_power = pnf->max_total_power; + + resp.pnf_phy.tl.tag = NFAPI_PNF_PHY_TAG; + resp.pnf_phy.number_of_phys = 1; + + for(int i = 0; i < 1; ++i) { + resp.pnf_phy.phy[i].phy_config_index = pnf->phys[i].index; + resp.pnf_phy.phy[i].downlink_channel_bandwidth_supported = pnf->phys[i].dl_channel_bw_support; + resp.pnf_phy.phy[i].uplink_channel_bandwidth_supported = pnf->phys[i].ul_channel_bw_support; + resp.pnf_phy.phy[i].number_of_dl_layers_supported = pnf->phys[i].num_dl_layers_supported; + resp.pnf_phy.phy[i].number_of_ul_layers_supported = pnf->phys[i].num_ul_layers_supported; + resp.pnf_phy.phy[i].maximum_3gpp_release_supported = pnf->phys[i].release_supported; + resp.pnf_phy.phy[i].nmm_modes_supported = pnf->phys[i].nmm_modes_supported; + + resp.pnf_phy.phy[i].number_of_rfs = 2; + for(int j = 0; j < 1; ++j) { + resp.pnf_phy.phy[i].rf_config[j].rf_config_index = pnf->phys[i].rfs[j]; + } + + resp.pnf_phy.phy[i].number_of_rf_exclusions = 0; + for(int j = 0; j < 0; ++j) { + resp.pnf_phy.phy[i].excluded_rf_config[j].rf_config_index = pnf->phys[i].excluded_rfs[j]; + } + } + + resp.pnf_rf.tl.tag = NFAPI_PNF_RF_TAG; + resp.pnf_rf.number_of_rfs = 2; + + for(int i = 0; i < 2; ++i) { + resp.pnf_rf.rf[i].rf_config_index = pnf->rfs[i].index; + resp.pnf_rf.rf[i].band = pnf->rfs[i].band; + resp.pnf_rf.rf[i].maximum_transmit_power = pnf->rfs[i].max_transmit_power; + resp.pnf_rf.rf[i].minimum_transmit_power = pnf->rfs[i].min_transmit_power; + resp.pnf_rf.rf[i].number_of_antennas_suppported = pnf->rfs[i].num_antennas_supported; + resp.pnf_rf.rf[i].minimum_downlink_frequency = pnf->rfs[i].min_downlink_frequency; + resp.pnf_rf.rf[i].maximum_downlink_frequency = pnf->rfs[i].max_downlink_frequency; + resp.pnf_rf.rf[i].minimum_uplink_frequency = pnf->rfs[i].min_uplink_frequency; + resp.pnf_rf.rf[i].maximum_uplink_frequency = pnf->rfs[i].max_uplink_frequency; + } + + if(pnf->release >= 10) { + resp.pnf_phy_rel10.tl.tag = NFAPI_PNF_PHY_REL10_TAG; + resp.pnf_phy_rel10.number_of_phys = 1; + + for(int i = 0; i < 1; ++i) + { + resp.pnf_phy_rel10.phy[i].phy_config_index = pnf->phys[i].index; + resp.pnf_phy_rel10.phy[i].transmission_mode_7_supported = 0; + resp.pnf_phy_rel10.phy[i].transmission_mode_8_supported = 1; + resp.pnf_phy_rel10.phy[i].two_antenna_ports_for_pucch = 0; + resp.pnf_phy_rel10.phy[i].transmission_mode_9_supported = 1; + resp.pnf_phy_rel10.phy[i].simultaneous_pucch_pusch = 0; + resp.pnf_phy_rel10.phy[i].four_layer_tx_with_tm3_and_tm4 = 1; + } + } + + if(pnf->release >= 11) { + resp.pnf_phy_rel11.tl.tag = NFAPI_PNF_PHY_REL11_TAG; + resp.pnf_phy_rel11.number_of_phys = 1; + + for(int i = 0; i < 1; ++i) { + resp.pnf_phy_rel11.phy[i].phy_config_index = pnf->phys[i].index; + resp.pnf_phy_rel11.phy[i].edpcch_supported = 0; + resp.pnf_phy_rel11.phy[i].multi_ack_csi_reporting = 1; + resp.pnf_phy_rel11.phy[i].pucch_tx_diversity = 0; + resp.pnf_phy_rel11.phy[i].ul_comp_supported = 1; + resp.pnf_phy_rel11.phy[i].transmission_mode_5_supported = 0; + } + } + + if(pnf->release >= 12) { + resp.pnf_phy_rel12.tl.tag = NFAPI_PNF_PHY_REL12_TAG; + resp.pnf_phy_rel12.number_of_phys = 1; + + for(int i = 0; i < 1; ++i) { + resp.pnf_phy_rel12.phy[i].phy_config_index = pnf->phys[i].index; + resp.pnf_phy_rel12.phy[i].csi_subframe_set = 0; + resp.pnf_phy_rel12.phy[i].enhanced_4tx_codebook = 2; + resp.pnf_phy_rel12.phy[i].drs_supported = 0; + resp.pnf_phy_rel12.phy[i].ul_64qam_supported = 1; + resp.pnf_phy_rel12.phy[i].transmission_mode_10_supported = 0; + resp.pnf_phy_rel12.phy[i].alternative_bts_indices = 1; + } + } + + if(pnf->release >= 13) { + resp.pnf_phy_rel13.tl.tag = NFAPI_PNF_PHY_REL13_TAG; + resp.pnf_phy_rel13.number_of_phys = 1; + + for(int i = 0; i < 1; ++i) { + resp.pnf_phy_rel13.phy[i].phy_config_index = pnf->phys[i].index; + resp.pnf_phy_rel13.phy[i].pucch_format4_supported = 0; + resp.pnf_phy_rel13.phy[i].pucch_format5_supported = 1; + resp.pnf_phy_rel13.phy[i].more_than_5_ca_support = 0; + resp.pnf_phy_rel13.phy[i].laa_supported = 1; + resp.pnf_phy_rel13.phy[i].laa_ending_in_dwpts_supported = 0; + resp.pnf_phy_rel13.phy[i].laa_starting_in_second_slot_supported = 1; + resp.pnf_phy_rel13.phy[i].beamforming_supported = 0; + resp.pnf_phy_rel13.phy[i].csi_rs_enhancement_supported = 1; + resp.pnf_phy_rel13.phy[i].drms_enhancement_supported = 0; + resp.pnf_phy_rel13.phy[i].srs_enhancement_supported = 1; + } + + resp.pnf_phy_rel13_nb_iot.tl.tag = NFAPI_PNF_PHY_REL13_NB_IOT_TAG; + resp.pnf_phy_rel13_nb_iot.number_of_phys = 1; + + for(int i = 0; i < 1; ++i) { + resp.pnf_phy_rel13_nb_iot.phy[i].phy_config_index = pnf->phys[i].index; + + resp.pnf_phy_rel13_nb_iot.phy[i].number_of_rfs = 1; + for(int j = 0; j < 1; ++j) { + resp.pnf_phy_rel13_nb_iot.phy[i].rf_config[j].rf_config_index = pnf->phys[i].rfs[j]; + } + + resp.pnf_phy_rel13_nb_iot.phy[i].number_of_rf_exclusions = 1; + for(int j = 0; j < 1; ++j) { + resp.pnf_phy_rel13_nb_iot.phy[i].excluded_rf_config[j].rf_config_index = pnf->phys[i].excluded_rfs[j]; + } + + resp.pnf_phy_rel13_nb_iot.phy[i].number_of_dl_layers_supported = pnf->phys[i].num_dl_layers_supported; + resp.pnf_phy_rel13_nb_iot.phy[i].number_of_ul_layers_supported = pnf->phys[i].num_ul_layers_supported; + resp.pnf_phy_rel13_nb_iot.phy[i].maximum_3gpp_release_supported = pnf->phys[i].release_supported; + resp.pnf_phy_rel13_nb_iot.phy[i].nmm_modes_supported = pnf->phys[i].nmm_modes_supported; + } + } + + nfapi_pnf_pnf_param_resp(config, &resp); + + return 0; +} + +int pnf_config_request(nfapi_pnf_config_t* config, nfapi_pnf_config_request_t* req) { + + printf("[PNF] pnf config request\n"); + + pnf_info* pnf = (pnf_info*)(config->user_data); + + phy_info *phy = pnf->phys; + phy->id = req->pnf_phy_rf_config.phy_rf_config[0].phy_id; + printf("[PNF] pnf config request assigned phy_id %d to phy_config_index %d\n", phy->id, req->pnf_phy_rf_config.phy_rf_config[0].phy_config_index); + + nfapi_pnf_config_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_CONFIG_RESPONSE; + resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_pnf_config_resp(config, &resp); + printf("[PNF] Sent pnf_config_resp\n"); + + return 0; +} + +void nfapi_send_pnf_start_resp(nfapi_pnf_config_t* config, uint16_t phy_id) { + + printf("Sending NFAPI_START_RESPONSE config:%p phy_id:%d\n", config, phy_id); + + nfapi_start_response_t start_resp; + memset(&start_resp, 0, sizeof(start_resp)); + start_resp.header.message_id = NFAPI_START_RESPONSE; + start_resp.header.phy_id = phy_id; + start_resp.error_code = NFAPI_MSG_OK; + + nfapi_pnf_start_resp(config, &start_resp); +} + +int pnf_start_request(nfapi_pnf_config_t* config, nfapi_pnf_start_request_t* req) { + + printf("Received NFAPI_PNF_START_REQUEST\n"); + + pnf_info* pnf = (pnf_info*)(config->user_data); + + // start all phys that have been configured + phy_info* phy = pnf->phys; + + if(phy->id != 0) { + nfapi_pnf_start_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_START_RESPONSE; + resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_pnf_start_resp(config, &resp); + printf("[PNF] Sent NFAPI_PNF_START_RESP\n"); + } + return 0; +} + +int pnf_stop_request(nfapi_pnf_config_t* config, nfapi_pnf_stop_request_t* req) { + + printf("[PNF] Received NFAPI_PNF_STOP_REQ\n"); + + nfapi_pnf_stop_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_STOP_RESPONSE; + resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_pnf_stop_resp(config, &resp); + printf("[PNF] Sent NFAPI_PNF_STOP_REQ\n"); + + return 0; +} + +int param_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_param_request_t* req) { + + printf("[PNF] Received NFAPI_PARAM_REQUEST phy_id:%d\n", req->header.phy_id); + + //pnf_info* pnf = (pnf_info*)(config->user_data); + + nfapi_param_response_t nfapi_resp; + + pnf_info* pnf = (pnf_info*)(config->user_data); + + memset(&nfapi_resp, 0, sizeof(nfapi_resp)); + nfapi_resp.header.message_id = NFAPI_PARAM_RESPONSE; + nfapi_resp.header.phy_id = req->header.phy_id; + nfapi_resp.error_code = 0; // DJP - what value??? + + struct sockaddr_in pnf_p7_sockaddr; + + pnf_p7_sockaddr.sin_addr.s_addr = inet_addr(pnf->phys[0].local_addr); + nfapi_resp.nfapi_config.p7_pnf_address_ipv4.tl.tag = NFAPI_NFAPI_P7_PNF_ADDRESS_IPV4_TAG; + memcpy(nfapi_resp.nfapi_config.p7_pnf_address_ipv4.address, &pnf_p7_sockaddr.sin_addr.s_addr, 4); + nfapi_resp.num_tlv++; + + // P7 PNF Port + nfapi_resp.nfapi_config.p7_pnf_port.tl.tag = NFAPI_NFAPI_P7_PNF_PORT_TAG; + nfapi_resp.nfapi_config.p7_pnf_port.value = 32123; // DJP - hard code alert!!!! FIXME TODO + nfapi_resp.num_tlv++; + + nfapi_pnf_param_resp(config, &nfapi_resp); + + printf("[PNF] Sent NFAPI_PARAM_RESPONSE phy_id:%d number_of_tlvs:%u\n", req->header.phy_id, nfapi_resp.num_tlv); + + printf("[PNF] param request .. exit\n"); + + return 0; +} + +int config_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_config_request_t* req) { + + printf("[PNF] Received NFAPI_CONFIG_REQ phy_id:%d\n", req->header.phy_id); + + pnf_info* pnf = (pnf_info*)(config->user_data); + uint8_t num_tlv = 0; + struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; + LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; + + phy_info* phy_info = pnf->phys; + + if(req->nfapi_config.timing_window.tl.tag == NFAPI_NFAPI_TIMING_WINDOW_TAG) { + phy_info->timing_window = req->nfapi_config.timing_window.value; + printf("Phy_info:Timing window:%u NFAPI_CONFIG:timing_window:%u\n", phy_info->timing_window, req->nfapi_config.timing_window.value); + num_tlv++; + } + + if(req->nfapi_config.timing_info_mode.tl.tag == NFAPI_NFAPI_TIMING_INFO_MODE_TAG) { + printf("timing info mode:%d\n", req->nfapi_config.timing_info_mode.value); + phy_info->timing_info_mode = req->nfapi_config.timing_info_mode.value; + num_tlv++; + } else { + phy_info->timing_info_mode = 0; + printf("NO timing info mode provided\n"); + } + + if(req->nfapi_config.timing_info_period.tl.tag == NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG) { + printf("timing info period provided value:%d\n", req->nfapi_config.timing_info_period.value); + phy_info->timing_info_period = req->nfapi_config.timing_info_period.value; + num_tlv++; + } else { + phy_info->timing_info_period = 0; + } + + if(req->rf_config.dl_channel_bandwidth.tl.tag == NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG) { + phy_info->dl_channel_bw_support = req->rf_config.dl_channel_bandwidth.value; + fp->N_RB_DL = req->rf_config.dl_channel_bandwidth.value; + num_tlv++; + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG N_RB_DL:%u\n", __FUNCTION__, fp->N_RB_DL); + } else { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() Missing NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG\n", __FUNCTION__); + } + + if(req->rf_config.ul_channel_bandwidth.tl.tag == NFAPI_RF_CONFIG_UL_CHANNEL_BANDWIDTH_TAG) { + phy_info->ul_channel_bw_support = req->rf_config.ul_channel_bandwidth.value; + fp->N_RB_UL = req->rf_config.ul_channel_bandwidth.value; + num_tlv++; + } + + if(req->nfapi_config.rf_bands.tl.tag == NFAPI_NFAPI_RF_BANDS_TAG) { + pnf->rfs[0].band = req->nfapi_config.rf_bands.rf_band[0]; + fp->eutra_band = req->nfapi_config.rf_bands.rf_band[0]; + num_tlv++; + } + + if(req->nfapi_config.earfcn.tl.tag == NFAPI_NFAPI_EARFCN_TAG) { + fp->dl_CarrierFreq = from_earfcn(fp->eutra_band, req->nfapi_config.earfcn.value); + fp->ul_CarrierFreq = fp->dl_CarrierFreq - (get_uldl_offset(fp->eutra_band) * 1e5); + num_tlv++; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() earfcn:%u dl_carrierFreq:%u ul_CarrierFreq:%u band:%u N_RB_DL:%u\n", + __FUNCTION__, req->nfapi_config.earfcn.value, fp->dl_CarrierFreq, fp->ul_CarrierFreq, pnf->rfs[0].band, fp->N_RB_DL); + } + + if (req->subframe_config.duplex_mode.tl.tag == NFAPI_SUBFRAME_CONFIG_DUPLEX_MODE_TAG) { + fp->frame_type = req->subframe_config.duplex_mode.value==0 ? TDD : FDD; + num_tlv++; + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() frame_type:%d\n", __FUNCTION__, fp->frame_type); + } + + if (req->subframe_config.dl_cyclic_prefix_type.tl.tag == NFAPI_SUBFRAME_CONFIG_DL_CYCLIC_PREFIX_TYPE_TAG) { + fp->Ncp = req->subframe_config.dl_cyclic_prefix_type.value; + num_tlv++; + } + + if (req->subframe_config.ul_cyclic_prefix_type.tl.tag == NFAPI_SUBFRAME_CONFIG_UL_CYCLIC_PREFIX_TYPE_TAG) { + fp->Ncp_UL = req->subframe_config.ul_cyclic_prefix_type.value; + num_tlv++; + } + + fp->num_MBSFN_config = 0; // DJP - hard code alert + + if (req->sch_config.physical_cell_id.tl.tag == NFAPI_SCH_CONFIG_PHYSICAL_CELL_ID_TAG) { + fp->Nid_cell = req->sch_config.physical_cell_id.value; + fp->nushift = fp->Nid_cell%6; + num_tlv++; + } + + if (req->rf_config.tx_antenna_ports.tl.tag == NFAPI_RF_CONFIG_TX_ANTENNA_PORTS_TAG) { + fp->nb_antennas_tx = req->rf_config.tx_antenna_ports.value; + fp->nb_antenna_ports_eNB = 1; + num_tlv++; + } + + if (req->rf_config.rx_antenna_ports.tl.tag == NFAPI_RF_CONFIG_RX_ANTENNA_PORTS_TAG) { + fp->nb_antennas_rx = req->rf_config.rx_antenna_ports.value; + num_tlv++; + } + + if (req->phich_config.phich_resource.tl.tag == NFAPI_PHICH_CONFIG_PHICH_RESOURCE_TAG) { + fp->phich_config_common.phich_resource = req->phich_config.phich_resource.value; + num_tlv++; + } + + if (req->phich_config.phich_duration.tl.tag == NFAPI_PHICH_CONFIG_PHICH_DURATION_TAG) { + fp->phich_config_common.phich_duration = req->phich_config.phich_duration.value; + num_tlv++; + } + + if (req->phich_config.phich_power_offset.tl.tag == NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG) { + LOG_E(PHY, "%s() NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG tag:%d not supported\n", __FUNCTION__, req->phich_config.phich_power_offset.tl.tag); + //fp->phich_config_common.phich_power_offset = req->phich_config. + num_tlv++; + } + + // UL RS Config + if (req->uplink_reference_signal_config.cyclic_shift_1_for_drms.tl.tag == NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_CYCLIC_SHIFT_1_FOR_DRMS_TAG) { + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = req->uplink_reference_signal_config.cyclic_shift_1_for_drms.value; + num_tlv++; + } + + if (req->uplink_reference_signal_config.uplink_rs_hopping.tl.tag == NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_UPLINK_RS_HOPPING_TAG) { + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = req->uplink_reference_signal_config.uplink_rs_hopping.value; + num_tlv++; + } + + if (req->uplink_reference_signal_config.group_assignment.tl.tag == NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_GROUP_ASSIGNMENT_TAG) { + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = req->uplink_reference_signal_config.group_assignment.value; + num_tlv++; + } + + if (req->pusch_config.hopping_mode.tl.tag == NFAPI_PUSCH_CONFIG_HOPPING_MODE_TAG) { + } // DJP - not being handled? + + if (req->pusch_config.hopping_offset.tl.tag == NFAPI_PUSCH_CONFIG_HOPPING_OFFSET_TAG) { + } // DJP - not being handled? + + if (req->pusch_config.number_of_subbands.tl.tag == NFAPI_PUSCH_CONFIG_NUMBER_OF_SUBBANDS_TAG) { + } // DJP - not being handled? + + if (req->prach_config.configuration_index.tl.tag == NFAPI_PRACH_CONFIG_CONFIGURATION_INDEX_TAG) { + fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex=req->prach_config.configuration_index.value; + num_tlv++; + } + + if (req->prach_config.root_sequence_index.tl.tag == NFAPI_PRACH_CONFIG_ROOT_SEQUENCE_INDEX_TAG) { + fp->prach_config_common.rootSequenceIndex=req->prach_config.root_sequence_index.value; + num_tlv++; + } + + if (req->prach_config.zero_correlation_zone_configuration.tl.tag == NFAPI_PRACH_CONFIG_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG) { + fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig=req->prach_config.zero_correlation_zone_configuration.value; + num_tlv++; + } + + if (req->prach_config.high_speed_flag.tl.tag == NFAPI_PRACH_CONFIG_HIGH_SPEED_FLAG_TAG) { + fp->prach_config_common.prach_ConfigInfo.highSpeedFlag=req->prach_config.high_speed_flag.value; + num_tlv++; + } + + if (req->prach_config.frequency_offset.tl.tag == NFAPI_PRACH_CONFIG_FREQUENCY_OFFSET_TAG) { + fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset=req->prach_config.frequency_offset.value; + num_tlv++; + } + + printf("[PNF] CONFIG_REQUEST[num_tlv:%d] TLVs processed:%d\n", req->num_tlv, num_tlv); + + printf("[PNF] Simulating PHY CONFIG - DJP\n"); + PHY_Config_t phy_config; + phy_config.Mod_id = 0; + phy_config.CC_id=0; + phy_config.cfg = req; + + phy_config_request(&phy_config); + + dump_frame_parms(fp); + + phy_info->remote_port = req->nfapi_config.p7_vnf_port.value; + + struct sockaddr_in vnf_p7_sockaddr; + memcpy(&vnf_p7_sockaddr.sin_addr.s_addr, &(req->nfapi_config.p7_vnf_address_ipv4.address[0]), 4); + phy_info->remote_addr = inet_ntoa(vnf_p7_sockaddr.sin_addr); + + printf("[PNF] %d vnf p7 %s:%d timing %d %d %d\n", phy_info->id, phy_info->remote_addr, phy_info->remote_port, + phy_info->timing_window, phy_info->timing_info_mode, phy_info->timing_info_period); + + nfapi_config_response_t nfapi_resp; + memset(&nfapi_resp, 0, sizeof(nfapi_resp)); + nfapi_resp.header.message_id = NFAPI_CONFIG_RESPONSE; + nfapi_resp.header.phy_id = phy_info->id; + nfapi_resp.error_code = 0; // DJP - some value resp->error_code; + nfapi_pnf_config_resp(config, &nfapi_resp); + printf("[PNF] Sent NFAPI_CONFIG_RESPONSE phy_id:%d\n", phy_info->id); + + return 0; +} + +nfapi_p7_message_header_t* pnf_phy_allocate_p7_vendor_ext(uint16_t message_id, uint16_t* msg_size) { + + if(message_id == P7_VENDOR_EXT_REQ) { + (*msg_size) = sizeof(vendor_ext_p7_req); + return (nfapi_p7_message_header_t*)malloc(sizeof(vendor_ext_p7_req)); + } + + return 0; +} + +void pnf_phy_deallocate_p7_vendor_ext(nfapi_p7_message_header_t* header) { + + free(header); +} + +int pnf_phy_hi_dci0_req(nfapi_pnf_p7_config_t* pnf_p7, nfapi_hi_dci0_request_t* req) { + + if (req->hi_dci0_request_body.number_of_dci == 0 && req->hi_dci0_request_body.number_of_hi == 0) + LOG_D(PHY,"[PNF] HI_DCI0_REQUEST SFN/SF:%05d dci:%d hi:%d\n", NFAPI_SFNSF2DEC(req->sfn_sf), req->hi_dci0_request_body.number_of_dci, req->hi_dci0_request_body.number_of_hi); + + //phy_info* phy = (phy_info*)(pnf_p7->user_data); + + struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; + eNB_rxtx_proc_t *proc = &eNB->proc.proc_rxtx[0]; + + for (int i=0; ihi_dci0_request_body.number_of_dci + req->hi_dci0_request_body.number_of_hi; i++) { + + //LOG_D(PHY,"[PNF] HI_DCI0_REQ sfn_sf:%d PDU[%d]\n", NFAPI_SFNSF2DEC(req->sfn_sf), i); + + if (req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) { + + //LOG_D(PHY,"[PNF] HI_DCI0_REQ sfn_sf:%d PDU[%d] - NFAPI_HI_DCI0_DCI_PDU_TYPE\n", NFAPI_SFNSF2DEC(req->sfn_sf), i); + + nfapi_hi_dci0_request_pdu_t *hi_dci0_req_pdu = &req->hi_dci0_request_body.hi_dci0_pdu_list[i]; + + handle_nfapi_hi_dci0_dci_pdu(eNB,NFAPI_SFNSF2SFN(req->sfn_sf),NFAPI_SFNSF2SF(req->sfn_sf),proc,hi_dci0_req_pdu); + + eNB->pdcch_vars[NFAPI_SFNSF2SF(req->sfn_sf)&1].num_dci++; + + } else if (req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type == NFAPI_HI_DCI0_HI_PDU_TYPE) { + + LOG_D(PHY,"[PNF] HI_DCI0_REQ sfn_sf:%d PDU[%d] - NFAPI_HI_DCI0_HI_PDU_TYPE\n", NFAPI_SFNSF2DEC(req->sfn_sf), i); + + nfapi_hi_dci0_request_pdu_t *hi_dci0_req_pdu = &req->hi_dci0_request_body.hi_dci0_pdu_list[i]; + + handle_nfapi_hi_dci0_hi_pdu(eNB, NFAPI_SFNSF2SFN(req->sfn_sf),NFAPI_SFNSF2SF(req->sfn_sf), proc, hi_dci0_req_pdu); + + } else { + + LOG_E(PHY,"[PNF] HI_DCI0_REQ sfn_sf:%d PDU[%d] - unknown pdu type:%d\n", NFAPI_SFNSF2DEC(req->sfn_sf), i, req->hi_dci0_request_body.hi_dci0_pdu_list[i].pdu_type); + + } + } + + return 0; +} + +int pnf_phy_dl_config_req(nfapi_pnf_p7_config_t* pnf_p7, nfapi_dl_config_request_t* req) { + + if (RC.ru == 0) { + return -1; + } + + if (RC.eNB == 0) { + return -2; + } + + if (RC.eNB[0][0] == 0) { + return -3; + } + + if (sync_var != 0) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() Main system not up - is this a dummy subframe?\n", __FUNCTION__); + return -4; + } + + int sfn = NFAPI_SFNSF2SFN(req->sfn_sf); + int sf = NFAPI_SFNSF2SF(req->sfn_sf); + + struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; + eNB_rxtx_proc_t *proc = &eNB->proc.proc_rxtx[0]; + nfapi_dl_config_request_pdu_t* dl_config_pdu_list = req->dl_config_request_body.dl_config_pdu_list; + LTE_eNB_PDCCH *pdcch_vars = &eNB->pdcch_vars[sf&1]; + + pdcch_vars->num_pdcch_symbols = req->dl_config_request_body.number_pdcch_ofdm_symbols; + pdcch_vars->num_dci = 0; + + if (req->dl_config_request_body.number_dci || + req->dl_config_request_body.number_pdu || + req->dl_config_request_body.number_pdsch_rnti) + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() TX:%d/%d RX:%d/%d sfn_sf:%d pdcch:%u dl_cfg[dci:%u pdus:%d pdsch_rnti:%d] pcfich:%u\n", + __FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->frame_rx, proc->subframe_rx, + NFAPI_SFNSF2DEC(req->sfn_sf), + req->dl_config_request_body.number_pdcch_ofdm_symbols, + req->dl_config_request_body.number_dci, + req->dl_config_request_body.number_pdu, + req->dl_config_request_body.number_pdsch_rnti, + req->dl_config_request_body.transmission_power_pcfich); + + for (int i=0;idl_config_request_body.number_pdu;i++) { + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() sfn/sf:%d PDU[%d] size:%d pdcch_vars->num_dci:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), i, dl_config_pdu_list[i].pdu_size,pdcch_vars->num_dci); + + if (dl_config_pdu_list[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) { + + handle_nfapi_dci_dl_pdu(eNB,NFAPI_SFNSF2SFN(req->sfn_sf),NFAPI_SFNSF2SF(req->sfn_sf),proc,&dl_config_pdu_list[i]); + + pdcch_vars->num_dci++; // Is actually number of DCI PDUs + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() pdcch_vars->num_dci:%d\n", __FUNCTION__, pdcch_vars->num_dci); + + } else if (dl_config_pdu_list[i].pdu_type == NFAPI_DL_CONFIG_BCH_PDU_TYPE) { + + nfapi_dl_config_bch_pdu *bch_pdu = &dl_config_pdu_list[i].bch_pdu; + uint16_t pdu_index = bch_pdu->bch_pdu_rel8.pdu_index; + + if (tx_request_pdu[sfn][sf][pdu_index] != NULL) { + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() PDU:%d BCH: pdu_index:%u pdu_length:%d sdu_length:%d BCH_SDU:%x,%x,%x\n", __FUNCTION__, i, pdu_index, bch_pdu->bch_pdu_rel8.length, tx_request_pdu[sfn][sf][pdu_index]->segments[0].segment_length, sdu[0], sdu[1], sdu[2]); + + handle_nfapi_bch_pdu(eNB, proc, &dl_config_pdu_list[i], tx_request_pdu[sfn][sf][pdu_index]->segments[0].segment_data); + + eNB->pbch_configured=1; + + } else { + + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() BCH NULL TX PDU SFN/SF:%d PDU_INDEX:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), pdu_index); + } + } else if (dl_config_pdu_list[i].pdu_type == NFAPI_DL_CONFIG_DLSCH_PDU_TYPE) { + + nfapi_dl_config_dlsch_pdu *dlsch_pdu = &dl_config_pdu_list[i].dlsch_pdu; + nfapi_dl_config_dlsch_pdu_rel8_t *rel8_pdu = &dlsch_pdu->dlsch_pdu_rel8; + nfapi_tx_request_pdu_t *tx_pdu = tx_request_pdu[sfn][sf][rel8_pdu->pdu_index]; + + if (tx_pdu != NULL) { + int UE_id = find_dlsch(rel8_pdu->rnti,eNB,SEARCH_EXIST_OR_FREE); + AssertFatal(UE_id!=-1,"no free or exiting dlsch_context\n"); + AssertFatal(UE_id= %d(NUMBER_OF_UE_MAX)\n",UE_id,NUMBER_OF_UE_MAX); + LTE_eNB_DLSCH_t *dlsch0 = eNB->dlsch[UE_id][0]; + //LTE_eNB_DLSCH_t *dlsch1 = eNB->dlsch[UE_id][1]; + int harq_pid = dlsch0->harq_ids[sf]; + uint8_t *dlsch_sdu = tx_pdus[UE_id][harq_pid]; + + memcpy(dlsch_sdu, tx_pdu->segments[0].segment_data, tx_pdu->segments[0].segment_length); + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() DLSCH:pdu_index:%d handle_nfapi_dlsch_pdu(eNB, proc_rxtx, dlsch_pdu, transport_blocks:%d sdu:%p) eNB->pdcch_vars[proc->subframe_tx & 1].num_pdcch_symbols:%d\n", __FUNCTION__, rel8_pdu->pdu_index, rel8_pdu->transport_blocks, dlsch_sdu, eNB->pdcch_vars[proc->subframe_tx & 1].num_pdcch_symbols); + + handle_nfapi_dlsch_pdu( eNB, sfn,sf, &eNB->proc.proc_rxtx[0], &dl_config_pdu_list[i], rel8_pdu->transport_blocks-1, dlsch_sdu); + + } else { + + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() DLSCH NULL TX PDU SFN/SF:%d PDU_INDEX:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), rel8_pdu->pdu_index); + } + + } else { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() UNKNOWN:%d\n", __FUNCTION__, dl_config_pdu_list[i].pdu_type); + } + } + + if(req->vendor_extension) + free(req->vendor_extension); + + return 0; +} + +int pnf_phy_tx_req(nfapi_pnf_p7_config_t* pnf_p7, nfapi_tx_request_t* req) { + + uint16_t sfn = NFAPI_SFNSF2SFN(req->sfn_sf); + uint16_t sf = NFAPI_SFNSF2SF(req->sfn_sf); + + if (req->tx_request_body.number_of_pdus==0) + LOG_D(PHY,"%s() SFN/SF:%d%d PDUs:%d\n", __FUNCTION__, sfn, sf, req->tx_request_body.number_of_pdus); + + if (req->tx_request_body.tl.tag==NFAPI_TX_REQUEST_BODY_TAG) { + for (int i=0; itx_request_body.number_of_pdus; i++) { + LOG_D(PHY,"%s() SFN/SF:%d%d number_of_pdus:%d [PDU:%d] pdu_length:%d pdu_index:%d num_segments:%d\n", + __FUNCTION__, + sfn, sf, + req->tx_request_body.number_of_pdus, + i, + req->tx_request_body.tx_pdu_list[i].pdu_length, + req->tx_request_body.tx_pdu_list[i].pdu_index, + req->tx_request_body.tx_pdu_list[i].num_segments + ); + + tx_request_pdu[sfn][sf][i] = &req->tx_request_body.tx_pdu_list[i]; + } + } + + return 0; +} + +int pnf_phy_ul_config_req(nfapi_pnf_p7_config_t* pnf_p7, nfapi_ul_config_request_t* req) { + + if (0)LOG_D(PHY,"[PNF] UL_CONFIG_REQ %s() sfn_sf:%d pdu:%d rach_prach_frequency_resources:%d srs_present:%u\n", + __FUNCTION__, + NFAPI_SFNSF2DEC(req->sfn_sf), + req->ul_config_request_body.number_of_pdus, + req->ul_config_request_body.rach_prach_frequency_resources, + req->ul_config_request_body.srs_present + ); + + if (RC.ru == 0) { + return -1; + } + + if (RC.eNB == 0) { + return -2; + } + + if (RC.eNB[0][0] == 0) { + return -3; + } + + if (sync_var != 0) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() Main system not up - is this a dummy subframe?\n", __FUNCTION__); + return -4; + } + + uint16_t curr_sfn = NFAPI_SFNSF2SFN(req->sfn_sf); + uint16_t curr_sf = NFAPI_SFNSF2SF(req->sfn_sf); + + struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; + eNB_rxtx_proc_t *proc = &eNB->proc.proc_rxtx[0]; + nfapi_ul_config_request_pdu_t* ul_config_pdu_list = req->ul_config_request_body.ul_config_pdu_list; + + for (int i=0;iul_config_request_body.number_of_pdus;i++) { + //LOG_D(PHY, "%s() sfn/sf:%d PDU[%d] size:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), i, ul_config_pdu_list[i].pdu_size); + + if ( + ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE || + ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE || + ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE || + ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE || + ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE || + ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE || + ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE + ) { + //LOG_D(PHY, "%s() handle_nfapi_ul_pdu() for PDU:%d\n", __FUNCTION__, i); + + handle_nfapi_ul_pdu(eNB,proc,&ul_config_pdu_list[i],curr_sfn,curr_sf,req->ul_config_request_body.srs_present); + } else { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() PDU:%i UNKNOWN type :%d\n", __FUNCTION__, i, ul_config_pdu_list[i].pdu_type); + } + } + + return 0; +} + +int pnf_phy_lbt_dl_config_req(nfapi_pnf_p7_config_t* config, nfapi_lbt_dl_config_request_t* req) { + //printf("[PNF] lbt dl config request\n"); + return 0; +} + +int pnf_phy_vendor_ext(nfapi_pnf_p7_config_t* config, nfapi_p7_message_header_t* msg) { + if(msg->message_id == P7_VENDOR_EXT_REQ) { + //vendor_ext_p7_req* req = (vendor_ext_p7_req*)msg; + //printf("[PNF] vendor request (1:%d 2:%d)\n", req->dummy1, req->dummy2); + } else { + printf("[PNF] unknown vendor ext\n"); + } + return 0; +} + +int pnf_phy_pack_p7_vendor_extension(nfapi_p7_message_header_t* header, uint8_t** ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* codex) { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if(header->message_id == P7_VENDOR_EXT_IND) { + vendor_ext_p7_ind* ind = (vendor_ext_p7_ind*)(header); + if(!push16(ind->error_code, ppWritePackedMsg, end)) + return 0; + + return 1; + } + return -1; +} + +int pnf_phy_unpack_p7_vendor_extension(nfapi_p7_message_header_t* header, uint8_t** ppReadPackedMessage, uint8_t *end, nfapi_p7_codec_config_t* codec) { + if(header->message_id == P7_VENDOR_EXT_REQ) { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + vendor_ext_p7_req* req = (vendor_ext_p7_req*)(header); + if(!(pull16(ppReadPackedMessage, &req->dummy1, end) && + pull16(ppReadPackedMessage, &req->dummy2, end))) + return 0; + return 1; + } + return -1; +} + +int pnf_phy_unpack_vendor_extension_tlv(nfapi_tl_t* tl, uint8_t **ppReadPackedMessage, uint8_t* end, void** ve, nfapi_p7_codec_config_t* config) { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "pnf_phy_unpack_vendor_extension_tlv\n"); + + switch(tl->tag) + { + case VENDOR_EXT_TLV_1_TAG: + *ve = malloc(sizeof(vendor_ext_tlv_1)); + if(!pull32(ppReadPackedMessage, &((vendor_ext_tlv_1*)(*ve))->dummy, end)) + return 0; + + return 1; + break; + } + + return -1; +} + +int pnf_phy_pack_vendor_extention_tlv(void* ve, uint8_t **ppWritePackedMsg, uint8_t* end, nfapi_p7_codec_config_t* config) { + //printf("%s\n", __FUNCTION__); + (void)ve; + (void)ppWritePackedMsg; + return -1; +} + +int pnf_sim_unpack_vendor_extension_tlv(nfapi_tl_t* tl, uint8_t **ppReadPackedMessage, uint8_t *end, void** ve, nfapi_p4_p5_codec_config_t* config) { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "pnf_sim_unpack_vendor_extension_tlv\n"); + + switch(tl->tag) + { + case VENDOR_EXT_TLV_2_TAG: + *ve = malloc(sizeof(vendor_ext_tlv_2)); + if(!pull32(ppReadPackedMessage, &((vendor_ext_tlv_2*)(*ve))->dummy, end)) + return 0; + + return 1; + break; + } + + return -1; +} + +int pnf_sim_pack_vendor_extention_tlv(void* ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) { + //printf("%s\n", __FUNCTION__); + (void)ve; + (void)ppWritePackedMsg; + return -1; +} + +nfapi_dl_config_request_t dummy_dl_config_req; +nfapi_tx_request_t dummy_tx_req; + +nfapi_pnf_p7_subframe_buffer_t dummy_subframe; + +int start_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_start_request_t* req) { + + printf("[PNF] Received NFAPI_START_REQ phy_id:%d\n", req->header.phy_id); + + nfapi_set_trace_level(NFAPI_TRACE_INFO); + + pnf_info* pnf = (pnf_info*)(config->user_data); + + phy_info* phy_info = pnf->phys; + + nfapi_pnf_p7_config_t* p7_config = nfapi_pnf_p7_config_create(); + + p7_config->phy_id = phy->phy_id; + + p7_config->remote_p7_port = phy_info->remote_port; + p7_config->remote_p7_addr = phy_info->remote_addr; + p7_config->local_p7_port = 32123; // DJP - good grief cannot seem to get the right answer phy_info->local_port; + //DJP p7_config->local_p7_addr = (char*)phy_info->local_addr.c_str(); + p7_config->local_p7_addr = phy_info->local_addr; + + printf("[PNF] P7 remote:%s:%d local:%s:%d\n", p7_config->remote_p7_addr, p7_config->remote_p7_port, p7_config->local_p7_addr, p7_config->local_p7_port); + + p7_config->user_data = phy_info; + + p7_config->malloc = &pnf_allocate; + p7_config->free = &pnf_deallocate; + p7_config->codec_config.allocate = &pnf_allocate; + p7_config->codec_config.deallocate = &pnf_deallocate; + + p7_config->trace = &pnf_nfapi_trace; + + phy->user_data = p7_config; + + p7_config->subframe_buffer_size = phy_info->timing_window; + printf("subframe_buffer_size configured using phy_info->timing_window:%d\n", phy_info->timing_window); + if(phy_info->timing_info_mode & 0x1) { + p7_config->timing_info_mode_periodic = 1; + p7_config->timing_info_period = phy_info->timing_info_period; + } + + if(phy_info->timing_info_mode & 0x2) { + p7_config->timing_info_mode_aperiodic = 1; + } + + p7_config->dl_config_req = &pnf_phy_dl_config_req; + p7_config->ul_config_req = &pnf_phy_ul_config_req; + p7_config->hi_dci0_req = &pnf_phy_hi_dci0_req; + p7_config->tx_req = &pnf_phy_tx_req; + p7_config->lbt_dl_config_req = &pnf_phy_lbt_dl_config_req; + + memset(&dummy_dl_config_req, 0, sizeof(dummy_dl_config_req)); + dummy_dl_config_req.dl_config_request_body.tl.tag=NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + dummy_dl_config_req.dl_config_request_body.number_pdcch_ofdm_symbols=1; + dummy_dl_config_req.dl_config_request_body.number_dci=0; + dummy_dl_config_req.dl_config_request_body.number_pdu=0; + dummy_dl_config_req.dl_config_request_body.number_pdsch_rnti=0; + dummy_dl_config_req.dl_config_request_body.transmission_power_pcfich=6000; + dummy_dl_config_req.dl_config_request_body.dl_config_pdu_list=0; + + memset(&dummy_tx_req, 0, sizeof(dummy_tx_req)); + dummy_tx_req.tx_request_body.number_of_pdus=0; + dummy_tx_req.tx_request_body.tl.tag=NFAPI_TX_REQUEST_BODY_TAG; + + dummy_subframe.dl_config_req = &dummy_dl_config_req; + dummy_subframe.tx_req = 0;//&dummy_tx_req; + + dummy_subframe.ul_config_req=0; + dummy_subframe.hi_dci0_req=0; + dummy_subframe.lbt_dl_config_req=0; + + p7_config->dummy_subframe = dummy_subframe; + + p7_config->vendor_ext = &pnf_phy_vendor_ext; + + p7_config->allocate_p7_vendor_ext = &pnf_phy_allocate_p7_vendor_ext; + p7_config->deallocate_p7_vendor_ext = &pnf_phy_deallocate_p7_vendor_ext; + + p7_config->codec_config.unpack_p7_vendor_extension = &pnf_phy_unpack_p7_vendor_extension; + p7_config->codec_config.pack_p7_vendor_extension = &pnf_phy_pack_p7_vendor_extension; + p7_config->codec_config.unpack_vendor_extension_tlv = &pnf_phy_unpack_vendor_extension_tlv; + p7_config->codec_config.pack_vendor_extension_tlv = &pnf_phy_pack_vendor_extention_tlv; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] Creating P7 thread %s\n", __FUNCTION__); + pthread_t p7_thread; + pthread_create(&p7_thread, NULL, &pnf_p7_thread_start, p7_config); + + //((pnf_phy_user_data_t*)(phy_info->fapi->user_data))->p7_config = p7_config; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] Calling l1_north_init_eNB() %s\n", __FUNCTION__); + l1_north_init_eNB(); + + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] DJP - HACK - Set p7_config global ready for subframe ind%s\n", __FUNCTION__); + p7_config_g = p7_config; + + // Need to wait for main thread to create RU structures + while(config_sync_var<0) { + usleep(5000000); + printf("[PNF] waiting for OAI to be configured (eNB/RU)\n"); + } + printf("[PNF] OAI eNB/RU configured\n"); + + printf("[PNF] About to call init_eNB_afterRU()\n"); + init_eNB_afterRU(); + + // Signal to main thread that it can carry on - otherwise RU will startup too quickly and it is not initialised + pthread_mutex_lock(&nfapi_sync_mutex); + nfapi_sync_var=0; + pthread_cond_broadcast(&nfapi_sync_cond); + pthread_mutex_unlock(&nfapi_sync_mutex); + + while(sync_var<0) { + usleep(5000000); + printf("[PNF] waiting for OAI to be started\n"); + } + + printf("[PNF] Sending PNF_START_RESP\n"); + nfapi_send_pnf_start_resp(config, p7_config->phy_id); + + printf("[PNF] Sending first P7 subframe ind\n"); + nfapi_pnf_p7_subframe_ind(p7_config, p7_config->phy_id, 0); // DJP - SFN_SF set to zero - correct??? + printf("[PNF] Sent first P7 subframe ind\n"); + + return 0; +} + +int measurement_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_measurement_request_t* req) { + + nfapi_measurement_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_MEASUREMENT_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_measurement_resp(config, &resp); + return 0; +} + +int rssi_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_rssi_request_t* req) { + + nfapi_rssi_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_RSSI_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_P4_MSG_OK; + nfapi_pnf_rssi_resp(config, &resp); + + nfapi_rssi_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_RSSI_INDICATION; + ind.header.phy_id = req->header.phy_id; + ind.error_code = NFAPI_P4_MSG_OK; + ind.rssi_indication_body.tl.tag = NFAPI_RSSI_INDICATION_TAG; + ind.rssi_indication_body.number_of_rssi = 1; + ind.rssi_indication_body.rssi[0] = -42; + nfapi_pnf_rssi_ind(config, &ind); + + return 0; +} + +int cell_search_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_cell_search_request_t* req) { + + nfapi_cell_search_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_CELL_SEARCH_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_P4_MSG_OK; + nfapi_pnf_cell_search_resp(config, &resp); + + nfapi_cell_search_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_CELL_SEARCH_INDICATION; + ind.header.phy_id = req->header.phy_id; + ind.error_code = NFAPI_P4_MSG_OK; + + switch(req->rat_type) { + case NFAPI_RAT_TYPE_LTE: + ind.lte_cell_search_indication.tl.tag = NFAPI_LTE_CELL_SEARCH_INDICATION_TAG; + ind.lte_cell_search_indication.number_of_lte_cells_found = 1; + ind.lte_cell_search_indication.lte_found_cells[0].pci = 123; + ind.lte_cell_search_indication.lte_found_cells[0].rsrp = 123; + ind.lte_cell_search_indication.lte_found_cells[0].rsrq = 123; + ind.lte_cell_search_indication.lte_found_cells[0].frequency_offset = 123; + break; + case NFAPI_RAT_TYPE_UTRAN: + { + ind.utran_cell_search_indication.tl.tag = NFAPI_UTRAN_CELL_SEARCH_INDICATION_TAG; + ind.utran_cell_search_indication.number_of_utran_cells_found = 1; + ind.utran_cell_search_indication.utran_found_cells[0].psc = 89; + ind.utran_cell_search_indication.utran_found_cells[0].rscp = 89; + ind.utran_cell_search_indication.utran_found_cells[0].ecno = 89; + ind.utran_cell_search_indication.utran_found_cells[0].frequency_offset = -89; + + } + break; + case NFAPI_RAT_TYPE_GERAN: + { + ind.geran_cell_search_indication.tl.tag = NFAPI_GERAN_CELL_SEARCH_INDICATION_TAG; + ind.geran_cell_search_indication.number_of_gsm_cells_found = 1; + ind.geran_cell_search_indication.gsm_found_cells[0].bsic = 23; + ind.geran_cell_search_indication.gsm_found_cells[0].rxlev = 23; + ind.geran_cell_search_indication.gsm_found_cells[0].rxqual = 23; + ind.geran_cell_search_indication.gsm_found_cells[0].frequency_offset = -23; + ind.geran_cell_search_indication.gsm_found_cells[0].sfn_offset = 230; + + } + break; + } + + ind.pnf_cell_search_state.tl.tag = NFAPI_PNF_CELL_SEARCH_STATE_TAG; + ind.pnf_cell_search_state.length = 3; + + nfapi_pnf_cell_search_ind(config, &ind); + + return 0; +} + +int broadcast_detect_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_broadcast_detect_request_t* req) +{ + nfapi_broadcast_detect_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_BROADCAST_DETECT_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_P4_MSG_OK; + nfapi_pnf_broadcast_detect_resp(config, &resp); + + nfapi_broadcast_detect_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_BROADCAST_DETECT_INDICATION; + ind.header.phy_id = req->header.phy_id; + ind.error_code = NFAPI_P4_MSG_OK; + + switch(req->rat_type) + { + case NFAPI_RAT_TYPE_LTE: + { + ind.lte_broadcast_detect_indication.tl.tag = NFAPI_LTE_BROADCAST_DETECT_INDICATION_TAG; + ind.lte_broadcast_detect_indication.number_of_tx_antenna = 1; + ind.lte_broadcast_detect_indication.mib_length = 4; + //ind.lte_broadcast_detect_indication.mib... + ind.lte_broadcast_detect_indication.sfn_offset = 77; + + } + break; + case NFAPI_RAT_TYPE_UTRAN: + { + ind.utran_broadcast_detect_indication.tl.tag = NFAPI_UTRAN_BROADCAST_DETECT_INDICATION_TAG; + ind.utran_broadcast_detect_indication.mib_length = 4; + //ind.utran_broadcast_detect_indication.mib... + // ind.utran_broadcast_detect_indication.sfn_offset; DJP - nonsense line + + } + break; + } + + ind.pnf_cell_broadcast_state.tl.tag = NFAPI_PNF_CELL_BROADCAST_STATE_TAG; + ind.pnf_cell_broadcast_state.length = 3; + + nfapi_pnf_broadcast_detect_ind(config, &ind); + + return 0; +} + +int system_information_schedule_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_system_information_schedule_request_t* req) +{ + nfapi_system_information_schedule_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_P4_MSG_OK; + nfapi_pnf_system_information_schedule_resp(config, &resp); + + nfapi_system_information_schedule_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_SYSTEM_INFORMATION_SCHEDULE_INDICATION; + ind.header.phy_id = req->header.phy_id; + ind.error_code = NFAPI_P4_MSG_OK; + + ind.lte_system_information_indication.tl.tag = NFAPI_LTE_SYSTEM_INFORMATION_INDICATION_TAG; + ind.lte_system_information_indication.sib_type = 3; + ind.lte_system_information_indication.sib_length = 5; + //ind.lte_system_information_indication.sib... + + nfapi_pnf_system_information_schedule_ind(config, &ind); + + return 0; +} + +int system_information_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_system_information_request_t* req) +{ + nfapi_system_information_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_SYSTEM_INFORMATION_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_P4_MSG_OK; + nfapi_pnf_system_information_resp(config, &resp); + + nfapi_system_information_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_SYSTEM_INFORMATION_INDICATION; + ind.header.phy_id = req->header.phy_id; + ind.error_code = NFAPI_P4_MSG_OK; + + switch(req->rat_type) + { + case NFAPI_RAT_TYPE_LTE: + { + ind.lte_system_information_indication.tl.tag = NFAPI_LTE_SYSTEM_INFORMATION_INDICATION_TAG; + ind.lte_system_information_indication.sib_type = 1; + ind.lte_system_information_indication.sib_length = 3; + //ind.lte_system_information_indication.sib... + } + break; + case NFAPI_RAT_TYPE_UTRAN: + { + ind.utran_system_information_indication.tl.tag = NFAPI_UTRAN_SYSTEM_INFORMATION_INDICATION_TAG; + ind.utran_system_information_indication.sib_length = 3; + //ind.utran_system_information_indication.sib... + + } + break; + case NFAPI_RAT_TYPE_GERAN: + { + ind.geran_system_information_indication.tl.tag = NFAPI_GERAN_SYSTEM_INFORMATION_INDICATION_TAG; + ind.geran_system_information_indication.si_length = 3; + //ind.geran_system_information_indication.si... + + } + break; + } + + nfapi_pnf_system_information_ind(config, &ind); + + return 0; +} + +int nmm_stop_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_nmm_stop_request_t* req) +{ + nfapi_nmm_stop_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_NMM_STOP_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_P4_MSG_OK; + nfapi_pnf_nmm_stop_resp(config, &resp); + return 0; +} + +int vendor_ext(nfapi_pnf_config_t* config, nfapi_p4_p5_message_header_t* msg) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] P5 %s %p\n", __FUNCTION__, msg); + + switch(msg->message_id) + { + case P5_VENDOR_EXT_REQ: + { + vendor_ext_p5_req* req = (vendor_ext_p5_req*)msg; + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] P5 Vendor Ext Req (%d %d)\n", req->dummy1, req->dummy2); + // send back the P5_VENDOR_EXT_RSP + vendor_ext_p5_rsp rsp; + memset(&rsp, 0, sizeof(rsp)); + rsp.header.message_id = P5_VENDOR_EXT_RSP; + rsp.error_code = NFAPI_MSG_OK; + nfapi_pnf_vendor_extension(config, &rsp.header, sizeof(vendor_ext_p5_rsp)); + } + break; + } + + return 0; +} + +nfapi_p4_p5_message_header_t* pnf_sim_allocate_p4_p5_vendor_ext(uint16_t message_id, uint16_t* msg_size) { + + if(message_id == P5_VENDOR_EXT_REQ) { + (*msg_size) = sizeof(vendor_ext_p5_req); + return (nfapi_p4_p5_message_header_t*)malloc(sizeof(vendor_ext_p5_req)); + } + + return 0; +} + +void pnf_sim_deallocate_p4_p5_vendor_ext(nfapi_p4_p5_message_header_t* header) { + free(header); +} + +int pnf_sim_pack_p4_p5_vendor_extension(nfapi_p4_p5_message_header_t* header, uint8_t** ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if(header->message_id == P5_VENDOR_EXT_RSP) { + vendor_ext_p5_rsp* rsp = (vendor_ext_p5_rsp*)(header); + return (!push16(rsp->error_code, ppWritePackedMsg, end)); + } + return 0; +} + +int pnf_sim_unpack_p4_p5_vendor_extension(nfapi_p4_p5_message_header_t* header, uint8_t** ppReadPackedMessage, uint8_t *end, nfapi_p4_p5_codec_config_t* codec) { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if(header->message_id == P5_VENDOR_EXT_REQ) { + vendor_ext_p5_req* req = (vendor_ext_p5_req*)(header); + return (!(pull16(ppReadPackedMessage, &req->dummy1, end) && + pull16(ppReadPackedMessage, &req->dummy2, end))); + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s (%d %d)\n", __FUNCTION__, req->dummy1, req->dummy2); + } + return 0; +} + +/*------------------------------------------------------------------------------*/ + +void* pnf_start_thread(void* ptr) { + + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] IN PNF NFAPI start thread %s\n", __FUNCTION__); + + nfapi_pnf_config_t *config = (nfapi_pnf_config_t*)ptr; + + struct sched_param sp; + sp.sched_priority = 20; + pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp); + + nfapi_pnf_start(config); + + return (void*)0; +} + +void configure_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port) { + + printf("%s() PNF\n\n\n\n\n\n", __FUNCTION__); + + nfapi_mode = 1; // PNF! + + nfapi_pnf_config_t* config = nfapi_pnf_config_create(); + + config->vnf_ip_addr = vnf_ip_addr; + config->vnf_p5_port = vnf_p5_port; + + pnf.phys[0].udp.enabled = 1; + pnf.phys[0].udp.rx_port = pnf_p7_port; + pnf.phys[0].udp.tx_port = vnf_p7_port; + strcpy(pnf.phys[0].udp.tx_addr, vnf_ip_addr); + + strcpy(pnf.phys[0].local_addr, pnf_ip_addr); + + printf("%s() VNF:%s:%d PNF_PHY[addr:%s UDP:tx_addr:%s:%d rx:%d]\n", + __FUNCTION__, + config->vnf_ip_addr, config->vnf_p5_port, + pnf.phys[0].local_addr, + pnf.phys[0].udp.tx_addr, pnf.phys[0].udp.tx_port, + pnf.phys[0].udp.rx_port); + + config->pnf_param_req = &pnf_param_request; + config->pnf_config_req = &pnf_config_request; + config->pnf_start_req = &pnf_start_request; + config->pnf_stop_req = &pnf_stop_request; + config->param_req = ¶m_request; + config->config_req = &config_request; + config->start_req = &start_request; + + config->measurement_req = &measurement_request; + config->rssi_req = &rssi_request; + config->cell_search_req = &cell_search_request; + config->broadcast_detect_req = &broadcast_detect_request; + config->system_information_schedule_req = &system_information_schedule_request; + config->system_information_req = &system_information_request; + config->nmm_stop_req = &nmm_stop_request; + + config->vendor_ext = &vendor_ext; + + config->trace = &pnf_nfapi_trace; + + config->user_data = &pnf; + + // To allow custom vendor extentions to be added to nfapi + config->codec_config.unpack_vendor_extension_tlv = &pnf_sim_unpack_vendor_extension_tlv; + config->codec_config.pack_vendor_extension_tlv = &pnf_sim_pack_vendor_extention_tlv; + + config->allocate_p4_p5_vendor_ext = &pnf_sim_allocate_p4_p5_vendor_ext; + config->deallocate_p4_p5_vendor_ext = &pnf_sim_deallocate_p4_p5_vendor_ext; + + config->codec_config.unpack_p4_p5_vendor_extension = &pnf_sim_unpack_p4_p5_vendor_extension; + config->codec_config.pack_p4_p5_vendor_extension = &pnf_sim_pack_p4_p5_vendor_extension; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] Creating PNF NFAPI start thread %s\n", __FUNCTION__); + pthread_create(&pnf_start_pthread, NULL, &pnf_start_thread, config); + + pthread_setname_np(pnf_start_pthread, "NFAPI_PNF"); +} + +void oai_subframe_ind(uint16_t sfn, uint16_t sf) { + + //LOG_D(PHY,"%s(sfn:%d, sf:%d)\n", __FUNCTION__, sfn, sf); + + //TODO FIXME - HACK - DJP - using a global to bodge it in + + if (p7_config_g != NULL && sync_var==0) { + + uint16_t sfn_sf_tx = sfn<<4 | sf; + + if ((sfn % 100 == 0) && sf==0) + { + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] %s %d.%d (sfn:%u sf:%u) SFN/SF(TX):%u\n", __FUNCTION__, ts.tv_sec, ts.tv_nsec, sfn, sf, NFAPI_SFNSF2DEC(sfn_sf_tx)); + } + + int subframe_ret = nfapi_pnf_p7_subframe_ind(p7_config_g, p7_config_g->phy_id, sfn_sf_tx); + + if (subframe_ret) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] %s(frame:%u subframe:%u) SFN/SF(TX):%u - PROBLEM with pnf_p7_subframe_ind()\n", __FUNCTION__, sfn, sf, sfn_sf_tx, NFAPI_SFNSF2DEC(sfn_sf_tx)); + } else { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "***NFAPI subframe handler finished *** \n"); + } + } else { + } +} + +int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind) { + + rach_ind->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + + LOG_D(PHY, "%s() sfn_sf:%d preambles:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(rach_ind->sfn_sf), rach_ind->rach_indication_body.number_of_preambles); + + return nfapi_pnf_p7_rach_ind(p7_config_g, rach_ind); +} + +int oai_nfapi_harq_indication(nfapi_harq_indication_t *harq_ind) { + + harq_ind->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + harq_ind->header.message_id = NFAPI_HARQ_INDICATION; + + LOG_D(PHY, "%s() sfn_sf:%d number_of_harqs:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(harq_ind->sfn_sf), harq_ind->harq_indication_body.number_of_harqs); + + int retval = nfapi_pnf_p7_harq_ind(p7_config_g, harq_ind); + + if (retval != 0) + LOG_E(PHY, "%s() sfn_sf:%d number_of_harqs:%d nfapi_pnf_p7_harq_ind()=%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(harq_ind->sfn_sf), harq_ind->harq_indication_body.number_of_harqs, retval); + + return retval; +} + +int oai_nfapi_crc_indication(nfapi_crc_indication_t *crc_ind) { + + crc_ind->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + crc_ind->header.message_id = NFAPI_CRC_INDICATION; + + //LOG_D(PHY, "%s() sfn_sf:%d number_of_crcs:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(crc_ind->sfn_sf), crc_ind->crc_indication_body.number_of_crcs); + + return nfapi_pnf_p7_crc_ind(p7_config_g, crc_ind); +} + +int oai_nfapi_cqi_indication(nfapi_cqi_indication_t *ind) { + + ind->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + ind->header.message_id = NFAPI_RX_CQI_INDICATION; + + //LOG_D(PHY, "%s() sfn_sf:%d number_of_cqis:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->cqi_indication_body.number_of_cqis); + + return nfapi_pnf_p7_cqi_ind(p7_config_g, ind); +} + +int oai_nfapi_rx_ind(nfapi_rx_indication_t *ind) { + + ind->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + ind->header.message_id = NFAPI_RX_ULSCH_INDICATION; + + int retval = nfapi_pnf_p7_rx_ind(p7_config_g, ind); + + //LOG_D(PHY,"%s() SFN/SF:%d pdus:%d retval:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->rx_indication_body.number_of_pdus, retval); + + //free(ind.rx_indication_body.rx_pdu_list); + + return retval; +} + +int oai_nfapi_sr_indication(nfapi_sr_indication_t *ind) { + + ind->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + + int retval = nfapi_pnf_p7_sr_ind(p7_config_g, ind); + + //LOG_D(PHY,"%s() SFN/SF:%d srs:%d retval:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->sr_indication_body.number_of_srs, retval); + + //free(ind.rx_indication_body.rx_pdu_list); + + return retval; +} diff --git a/nfapi/oai_integration/nfapi_pnf.h b/nfapi/oai_integration/nfapi_pnf.h new file mode 100644 index 0000000000..592d4877af --- /dev/null +++ b/nfapi/oai_integration/nfapi_pnf.h @@ -0,0 +1,27 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#if !defined(NFAPI_PNF_H__) +#define NFAPI_PNF_H__ + +void configure_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port); + +#endif diff --git a/nfapi/oai_integration/nfapi_vnf.c b/nfapi/oai_integration/nfapi_vnf.c new file mode 100644 index 0000000000..07c3f1aa91 --- /dev/null +++ b/nfapi/oai_integration/nfapi_vnf.c @@ -0,0 +1,1221 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nfapi_interface.h" +#include "nfapi_vnf_interface.h" +#include "nfapi.h" +#include "vendor_ext.h" + +#include "nfapi_vnf.h" + + +#include "common/ran_context.h" +extern RAN_CONTEXT_t RC; + +typedef struct { + uint8_t enabled; + uint32_t rx_port; + uint32_t tx_port; + char tx_addr[80]; +} udp_data; + +typedef struct { + uint16_t index; + uint16_t id; + uint8_t rfs[2]; + uint8_t excluded_rfs[2]; + + udp_data udp; + + char local_addr[80]; + int local_port; + + char* remote_addr; + int remote_port; + + uint8_t duplex_mode; + uint16_t dl_channel_bw_support; + uint16_t ul_channel_bw_support; + uint8_t num_dl_layers_supported; + uint8_t num_ul_layers_supported; + uint16_t release_supported; + uint8_t nmm_modes_supported; + + uint8_t dl_ues_per_subframe; + uint8_t ul_ues_per_subframe; + + uint8_t first_subframe_ind; + + // timing information recevied from the vnf + uint8_t timing_window; + uint8_t timing_info_mode; + uint8_t timing_info_period; + +} phy_info; + +typedef struct { + uint16_t index; + uint16_t band; + int16_t max_transmit_power; + int16_t min_transmit_power; + uint8_t num_antennas_supported; + uint32_t min_downlink_frequency; + uint32_t max_downlink_frequency; + uint32_t max_uplink_frequency; + uint32_t min_uplink_frequency; +} rf_info; + +typedef struct { + + int release; + phy_info phys[2]; + rf_info rfs[2]; + + uint8_t sync_mode; + uint8_t location_mode; + uint8_t location_coordinates[6]; + uint32_t dl_config_timing; + uint32_t ul_config_timing; + uint32_t tx_timing; + uint32_t hi_dci0_timing; + + uint16_t max_phys; + uint16_t max_total_bw; + uint16_t max_total_dl_layers; + uint16_t max_total_ul_layers; + uint8_t shared_bands; + uint8_t shared_pa; + int16_t max_total_power; + uint8_t oui; + + uint8_t wireshark_test_mode; + +} pnf_info; + +typedef struct mac mac_t; + +typedef struct mac { + + void* user_data; + + void (*dl_config_req)(mac_t* mac, nfapi_dl_config_request_t* req); + void (*ul_config_req)(mac_t* mac, nfapi_ul_config_request_t* req); + void (*hi_dci0_req)(mac_t* mac, nfapi_hi_dci0_request_t* req); + void (*tx_req)(mac_t* mac, nfapi_tx_request_t* req); +} mac_t; + +typedef struct { + + int local_port; + char local_addr[80]; + + unsigned timing_window; + unsigned periodic_timing_enabled; + unsigned aperiodic_timing_enabled; + unsigned periodic_timing_period; + + // This is not really the right place if we have multiple PHY, + // should be part of the phy struct + udp_data udp; + + uint8_t thread_started; + + nfapi_vnf_p7_config_t* config; + + mac_t* mac; + +} vnf_p7_info; + +typedef struct { + + uint8_t wireshark_test_mode; + pnf_info pnfs[2]; + vnf_p7_info p7_vnfs[2]; + +} vnf_info; + +int vnf_pack_vendor_extension_tlv(void* ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* codec) { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "vnf_pack_vendor_extension_tlv\n"); + nfapi_tl_t* tlv = (nfapi_tl_t*)ve; + switch(tlv->tag) { + case VENDOR_EXT_TLV_2_TAG: + { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "Packing VENDOR_EXT_TLV_2\n"); + vendor_ext_tlv_2* ve = (vendor_ext_tlv_2*)tlv; + if(!push32(ve->dummy, ppWritePackedMsg, end)) + return 0; + return 1; + } + break; + } + return -1; +} + +int vnf_unpack_vendor_extension_tlv(nfapi_tl_t* tl, uint8_t **ppReadPackedMessage, uint8_t *end, void** ve, nfapi_p4_p5_codec_config_t* codec) { + return -1; +} + +void install_schedule_handlers(IF_Module_t *if_inst); +extern int single_thread_flag; +extern void init_eNB_afterRU(void); +extern uint16_t sf_ahead; + +void oai_create_enb(void) { + + int bodge_counter=0; + PHY_VARS_eNB *eNB = RC.eNB[0][0]; + + printf("[VNF] RC.eNB[0][0]. Mod_id:%d CC_id:%d nb_CC[0]:%d abstraction_flag:%d single_thread_flag:%d td:%p te:%p if_inst:%p\n", eNB->Mod_id, eNB->CC_id, RC.nb_CC[0], eNB->abstraction_flag, eNB->single_thread_flag, eNB->td, eNB->te, eNB->if_inst); + + eNB->Mod_id = bodge_counter; + eNB->CC_id = bodge_counter; + eNB->abstraction_flag = 0; + eNB->single_thread_flag = 0;//single_thread_flag; + eNB->td = ulsch_decoding_data;//(single_thread_flag==1) ? ulsch_decoding_data_2thread : ulsch_decoding_data; + eNB->te = dlsch_encoding;//(single_thread_flag==1) ? dlsch_encoding_2threads : dlsch_encoding; + + RC.nb_CC[bodge_counter] = 1; + + if (eNB->if_inst==0) { + eNB->if_inst = IF_Module_init(bodge_counter); + } + + // This will cause phy_config_request to be installed. That will result in RRC configuring the PHY + // that will result in eNB->configured being set to TRUE. + // See we need to wait for that to happen otherwise the NFAPI message exchanges won't contain the right parameter values + if (RC.eNB[0][0]->if_inst==0 || RC.eNB[0][0]->if_inst->PHY_config_req==0 || RC.eNB[0][0]->if_inst->schedule_response==0) { + + printf("RC.eNB[0][0]->if_inst->PHY_config_req is not installed - install it\n"); + install_schedule_handlers(RC.eNB[0][0]->if_inst); + } + + do { + printf("%s() Waiting for eNB to become configured (by RRC/PHY) - need to wait otherwise NFAPI messages won't contain correct values\n", __FUNCTION__); + usleep(50000); + } while(eNB->configured != 1); + + printf("%s() eNB is now configured\n", __FUNCTION__); +} + +void oai_enb_init(void) { + + printf("%s() About to call init_eNB_afterRU()\n", __FUNCTION__); + init_eNB_afterRU(); +} + +int pnf_connection_indication_cb(nfapi_vnf_config_t* config, int p5_idx) { + + printf("[VNF] pnf connection indication idx:%d\n", p5_idx); + + oai_create_enb(); + + nfapi_pnf_param_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PNF_PARAM_REQUEST; + nfapi_vnf_pnf_param_req(config, p5_idx, &req); + return 0; +} + +int pnf_disconnection_indication_cb(nfapi_vnf_config_t* config, int p5_idx) { + printf("[VNF] pnf disconnection indication idx:%d\n", p5_idx); + + vnf_info* vnf = (vnf_info*)(config->user_data); + + pnf_info *pnf = vnf->pnfs; + phy_info *phy = pnf->phys; + + vnf_p7_info* p7_vnf = vnf->p7_vnfs; + nfapi_vnf_p7_del_pnf((p7_vnf->config), phy->id); + + return 0; +} + +int pnf_param_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_param_response_t* resp) { + + printf("[VNF] pnf param response idx:%d error:%d\n", p5_idx, resp->error_code); + + vnf_info* vnf = (vnf_info*)(config->user_data); + + pnf_info *pnf = vnf->pnfs; + + for(int i = 0; i < resp->pnf_phy.number_of_phys; ++i) + { + phy_info phy; + phy.index = resp->pnf_phy.phy[i].phy_config_index; + + printf("[VNF] (PHY:%d) phy_config_idx:%d\n", i, resp->pnf_phy.phy[i].phy_config_index); + + nfapi_vnf_allocate_phy(config, p5_idx, &(phy.id)); + + for(int j = 0; j < resp->pnf_phy.phy[i].number_of_rfs; ++j) + { + printf("[VNF] (PHY:%d) (RF%d) %d\n", i, j, resp->pnf_phy.phy[i].rf_config[j].rf_config_index); + phy.rfs[0] = resp->pnf_phy.phy[i].rf_config[j].rf_config_index; + } + + pnf->phys[0] = phy; + } + + for(int i = 0; i < resp->pnf_rf.number_of_rfs; ++i) { + rf_info rf; + rf.index = resp->pnf_rf.rf[i].rf_config_index; + + printf("[VNF] (RF:%d) rf_config_idx:%d\n", i, resp->pnf_rf.rf[i].rf_config_index); + + pnf->rfs[0] = rf; + } + + nfapi_pnf_config_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PNF_CONFIG_REQUEST; + + req.pnf_phy_rf_config.tl.tag = NFAPI_PNF_PHY_RF_TAG; + req.pnf_phy_rf_config.number_phy_rf_config_info = 2; // DJP pnf.phys.size(); + printf("DJP:Hard coded num phy rf to 2\n"); + + for(unsigned i = 0; i < 2; ++i) { + req.pnf_phy_rf_config.phy_rf_config[i].phy_id = pnf->phys[i].id; + req.pnf_phy_rf_config.phy_rf_config[i].phy_config_index = pnf->phys[i].index; + req.pnf_phy_rf_config.phy_rf_config[i].rf_config_index = pnf->phys[i].rfs[0]; + } + + nfapi_vnf_pnf_config_req(config, p5_idx, &req); + + return 0; +} + +int pnf_config_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_config_response_t* resp) { + + printf("[VNF] pnf config response idx:%d resp[header[phy_id:%u message_id:%02x message_length:%u]]\n", p5_idx, resp->header.phy_id, resp->header.message_id, resp->header.message_length); + + if(1) { + nfapi_pnf_start_request_t req; + memset(&req, 0, sizeof(req)); + req.header.phy_id = resp->header.phy_id; + req.header.message_id = NFAPI_PNF_START_REQUEST; + nfapi_vnf_pnf_start_req(config, p5_idx, &req); + } else { + // Rather than send the pnf_start_request we will demonstrate + // sending a vendor extention message. The start request will be + // send when the vendor extension response is received + + //vnf_info* vnf = (vnf_info*)(config->user_data); + vendor_ext_p5_req req; + memset(&req, 0, sizeof(req)); + req.header.message_id = P5_VENDOR_EXT_REQ; + req.dummy1 = 45; + req.dummy2 = 1977; + nfapi_vnf_vendor_extension(config, p5_idx, &req.header); + } + return 0; +} + +int wake_eNB_rxtx(PHY_VARS_eNB *eNB, uint16_t sfn, uint16_t sf) { + + eNB_proc_t *proc=&eNB->proc; + + eNB_rxtx_proc_t *proc_rxtx=&proc->proc_rxtx[sf&1]; + + LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; + + //printf("%s(eNB:%p, sfn:%d, sf:%d)\n", __FUNCTION__, eNB, sfn, sf); + + //int i; + struct timespec wait; + + wait.tv_sec=0; + wait.tv_nsec=5000000L; + +#if 0 + /* accept some delay in processing - up to 5ms */ + for (i = 0; i < 10 && proc_rxtx->instance_cnt_rxtx == 0; i++) { + LOG_W( PHY,"[eNB] sfn/sf:%d:%d proc_rxtx[%d]:TXsfn:%d/%d eNB RXn-TXnp4 thread busy!! (cnt_rxtx %i)\n", sfn, sf, sf&1, proc_rxtx->frame_tx, proc_rxtx->subframe_tx, proc_rxtx->instance_cnt_rxtx); + usleep(500); + } + if (proc_rxtx->instance_cnt_rxtx == 0) { + exit_fun( "TX thread busy" ); + return(-1); + } +#endif + + // wake up TX for subframe n+sf_ahead + // lock the TX mutex and make sure the thread is ready + if (pthread_mutex_timedlock(&proc_rxtx->mutex_rxtx,&wait) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB RXTX thread %d (IC %d)\n", proc_rxtx->subframe_rx&1,proc_rxtx->instance_cnt_rxtx ); + exit_fun( "error locking mutex_rxtx" ); + return(-1); + } + + { + static uint16_t old_sf = 0; + static uint16_t old_sfn = 0; + + proc->subframe_rx = old_sf; + proc->frame_rx = old_sfn; + + // Try to be 1 frame back + old_sf = sf; + old_sfn = sfn; + + if (old_sf == 0 && old_sfn % 100==0) LOG_W( PHY,"[eNB] sfn/sf:%d%d old_sfn/sf:%d%d proc[rx:%d%d]\n", sfn, sf, old_sfn, old_sf, proc->frame_rx, proc->subframe_rx); + } + + ++proc_rxtx->instance_cnt_rxtx; + + //LOG_D( PHY,"[VNF-subframe_ind] sfn/sf:%d:%d proc[frame_rx:%d subframe_rx:%d] proc_rxtx->instance_cnt_rxtx:%d \n", sfn, sf, proc->frame_rx, proc->subframe_rx, proc_rxtx->instance_cnt_rxtx); + + // We have just received and processed the common part of a subframe, say n. + // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired + // transmitted timestamp of the next TX slot (first). + // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, + // we want to generate subframe (n+N), so TS_tx = TX_rx+N*samples_per_tti, + // and proc->subframe_tx = proc->subframe_rx+sf_ahead + proc_rxtx->timestamp_tx = proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); + proc_rxtx->frame_rx = proc->frame_rx; + proc_rxtx->subframe_rx = proc->subframe_rx; + proc_rxtx->frame_tx = (proc_rxtx->subframe_rx > (9-sf_ahead)) ? (proc_rxtx->frame_rx+1)&1023 : proc_rxtx->frame_rx; + proc_rxtx->subframe_tx = (proc_rxtx->subframe_rx + sf_ahead)%10; + + //LOG_D(PHY, "sfn/sf:%d%d proc[rx:%d%d] proc_rxtx[instance_cnt_rxtx:%d rx:%d%d] About to wake rxtx thread\n\n", sfn, sf, proc->frame_rx, proc->subframe_rx, proc_rxtx->instance_cnt_rxtx, proc_rxtx->frame_rx, proc_rxtx->subframe_rx); + + // the thread can now be woken up + if (pthread_cond_signal(&proc_rxtx->cond_rxtx) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB RXn-TXnp4 thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + return(-1); + } + + //LOG_D(PHY,"%s() About to attempt pthread_mutex_unlock\n", __FUNCTION__); + pthread_mutex_unlock( &proc_rxtx->mutex_rxtx ); + //LOG_D(PHY,"%s() UNLOCKED pthread_mutex_unlock\n", __FUNCTION__); + + return(0); +} + +extern pthread_cond_t nfapi_sync_cond; +extern pthread_mutex_t nfapi_sync_mutex; +extern int nfapi_sync_var; + +int phy_sync_indication(struct nfapi_vnf_p7_config* config, uint8_t sync) { + + printf("[VNF] SYNC %s\n", sync==1 ? "ACHIEVED" : "LOST"); + + if (sync==1 && nfapi_sync_var!=0) { + + printf("[VNF] Signal to OAI main code that it can go\n"); + pthread_mutex_lock(&nfapi_sync_mutex); + nfapi_sync_var=0; + pthread_cond_broadcast(&nfapi_sync_cond); + pthread_mutex_unlock(&nfapi_sync_mutex); + } + + return(0); +} + +int phy_subframe_indication(struct nfapi_vnf_p7_config* config, uint16_t phy_id, uint16_t sfn_sf) { + + static uint8_t first_time = 1; + if (first_time) { + printf("[VNF] subframe indication %d\n", NFAPI_SFNSF2DEC(sfn_sf)); + first_time = 0; + } + + if (RC.eNB && RC.eNB[0][0]->configured) { + uint16_t sfn = NFAPI_SFNSF2SFN(sfn_sf); + uint16_t sf = NFAPI_SFNSF2SF(sfn_sf); + + //LOG_D(PHY,"[VNF] subframe indication sfn_sf:%d sfn:%d sf:%d\n", sfn_sf, sfn, sf); + + wake_eNB_rxtx(RC.eNB[0][0], sfn, sf); + } else { + printf("[VNF] %s() RC.eNB:%p\n", __FUNCTION__, RC.eNB); + if (RC.eNB) printf("RC.eNB[0][0]->configured:%d\n", RC.eNB[0][0]->configured); + } + + return 0; +} + +int phy_rach_indication(struct nfapi_vnf_p7_config* config, nfapi_rach_indication_t* ind) { + + LOG_D(MAC, "%s() NFAPI SFN/SF:%d number_of_preambles:%u\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->rach_indication_body.number_of_preambles); + + struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; + + printf("[VNF] RACH_IND eNB:%p sfn_sf:%d number_of_preambles:%d\n", eNB, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->rach_indication_body.number_of_preambles); + + pthread_mutex_lock(&eNB->UL_INFO_mutex); + + eNB->UL_INFO.rach_ind = *ind; + eNB->UL_INFO.rach_ind.rach_indication_body.preamble_list = eNB->preamble_list; + + for (int i=0;irach_indication_body.number_of_preambles;i++) { + if (ind->rach_indication_body.preamble_list[i].preamble_rel8.tl.tag == NFAPI_PREAMBLE_REL8_TAG) { + + printf("preamble[%d]: rnti:%02x preamble:%d timing_advance:%d\n", + i, + ind->rach_indication_body.preamble_list[i].preamble_rel8.rnti, + ind->rach_indication_body.preamble_list[i].preamble_rel8.preamble, + ind->rach_indication_body.preamble_list[i].preamble_rel8.timing_advance + ); + } + + if(ind->rach_indication_body.preamble_list[i].preamble_rel13.tl.tag == NFAPI_PREAMBLE_REL13_TAG) { + printf("RACH PREAMBLE REL13 present\n"); + } + + eNB->preamble_list[i] = ind->rach_indication_body.preamble_list[i]; + } + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + //mac_rach_ind(p7_vnf->mac, ind); + return 1; +} + +int phy_harq_indication(struct nfapi_vnf_p7_config* config, nfapi_harq_indication_t* ind) { + + struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; + + LOG_D(MAC, "%s() NFAPI SFN/SF:%d number_of_harqs:%u\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->harq_indication_body.number_of_harqs); + + pthread_mutex_lock(&eNB->UL_INFO_mutex); + + eNB->UL_INFO.harq_ind = *ind; + eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = eNB->harq_pdu_list; + + for (int i=0; iharq_indication_body.number_of_harqs; i++) { + memcpy(&eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list[i], &ind->harq_indication_body.harq_pdu_list[i], sizeof(eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list[i])); + } + + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + //mac_harq_ind(p7_vnf->mac, ind); + + return 1; +} + +int phy_crc_indication(struct nfapi_vnf_p7_config* config, nfapi_crc_indication_t* ind) { + + struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; + + pthread_mutex_lock(&eNB->UL_INFO_mutex); + + eNB->UL_INFO.crc_ind = *ind; + + nfapi_crc_indication_t *dest_ind = &eNB->UL_INFO.crc_ind; + nfapi_crc_indication_pdu_t *dest_pdu_list = eNB->crc_pdu_list; + + *dest_ind = *ind; + dest_ind->crc_indication_body.crc_pdu_list = dest_pdu_list; + + if (ind->crc_indication_body.number_of_crcs==0) + LOG_D(MAC, "%s() NFAPI SFN/SF:%d IND:number_of_crcs:%u UL_INFO:crcs:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->crc_indication_body.number_of_crcs, eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs); + + for (int i=0; icrc_indication_body.number_of_crcs; i++) { + memcpy(&dest_ind->crc_indication_body.crc_pdu_list[i], &ind->crc_indication_body.crc_pdu_list[i], sizeof(ind->crc_indication_body.crc_pdu_list[0])); + + LOG_D(MAC, "%s() NFAPI SFN/SF:%d CRC_IND:number_of_crcs:%u UL_INFO:crcs:%d PDU[%d] rnti:%04x UL_INFO:rnti:%04x\n", + __FUNCTION__, + NFAPI_SFNSF2DEC(ind->sfn_sf), ind->crc_indication_body.number_of_crcs, eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs, + i, + ind->crc_indication_body.crc_pdu_list[i].rx_ue_information.rnti, + eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list[i].rx_ue_information.rnti); + } + + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + //mac_crc_ind(p7_vnf->mac, ind); + + return 1; +} + +int phy_rx_indication(struct nfapi_vnf_p7_config* config, nfapi_rx_indication_t* ind) { + + struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; + + if (ind->rx_indication_body.number_of_pdus==0) { + LOG_D(MAC, "%s() NFAPI SFN/SF:%d number_of_pdus:%u\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->rx_indication_body.number_of_pdus); + } + + pthread_mutex_lock(&eNB->UL_INFO_mutex); + + nfapi_rx_indication_t *dest_ind = &eNB->UL_INFO.rx_ind; + nfapi_rx_indication_pdu_t *dest_pdu_list = eNB->rx_pdu_list; + + *dest_ind = *ind; + dest_ind->rx_indication_body.rx_pdu_list = dest_pdu_list; + + for(int i=0; irx_indication_body.number_of_pdus; i++) { + nfapi_rx_indication_pdu_t *dest_pdu = &dest_ind->rx_indication_body.rx_pdu_list[i]; + nfapi_rx_indication_pdu_t *src_pdu = &ind->rx_indication_body.rx_pdu_list[i]; + + memcpy(dest_pdu, src_pdu, sizeof(*src_pdu)); + + // DJP - TODO FIXME - intentional memory leak + dest_pdu->data = malloc(dest_pdu->rx_indication_rel8.length); + + memcpy(dest_pdu->data, src_pdu->data, dest_pdu->rx_indication_rel8.length); + + LOG_D(PHY, "%s() NFAPI SFN/SF:%d PDUs:%d [PDU:%d] handle:%d rnti:%04x length:%d offset:%d ul_cqi:%d ta:%d data:%p\n", + __FUNCTION__, + NFAPI_SFNSF2DEC(ind->sfn_sf), ind->rx_indication_body.number_of_pdus, i, + dest_pdu->rx_ue_information.handle, + dest_pdu->rx_ue_information.rnti, + dest_pdu->rx_indication_rel8.length, + dest_pdu->rx_indication_rel8.offset, + dest_pdu->rx_indication_rel8.ul_cqi, + dest_pdu->rx_indication_rel8.timing_advance, + dest_pdu->data + ); + } + + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + //mac_rx_ind(p7_vnf->mac, ind); + return 1; +} +int phy_srs_indication(struct nfapi_vnf_p7_config* config, nfapi_srs_indication_t* ind) { + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + //mac_srs_ind(p7_vnf->mac, ind); + return 1; +} + +int phy_sr_indication(struct nfapi_vnf_p7_config* config, nfapi_sr_indication_t* ind) { + + struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; + + LOG_D(MAC, "%s() NFAPI SFN/SF:%d srs:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->sr_indication_body.number_of_srs); + + pthread_mutex_lock(&eNB->UL_INFO_mutex); + + nfapi_sr_indication_t *dest_ind = &eNB->UL_INFO.sr_ind; + nfapi_sr_indication_pdu_t *dest_pdu_list = eNB->sr_pdu_list; + + *dest_ind = *ind; + dest_ind->sr_indication_body.sr_pdu_list = dest_pdu_list; + + LOG_D(MAC,"%s() eNB->UL_INFO.sr_ind.sr_indication_body.number_of_srs:%d\n", __FUNCTION__, eNB->UL_INFO.sr_ind.sr_indication_body.number_of_srs); + + for (int i=0;iUL_INFO.sr_ind.sr_indication_body.number_of_srs;i++) { + nfapi_sr_indication_pdu_t *dest_pdu = &dest_ind->sr_indication_body.sr_pdu_list[i]; + nfapi_sr_indication_pdu_t *src_pdu = &ind->sr_indication_body.sr_pdu_list[i]; + + LOG_D(MAC, "SR_IND[PDU:%d][rnti:%x cqi:%d channel:%d]\n", i, src_pdu->rx_ue_information.rnti, src_pdu->ul_cqi_information.ul_cqi, src_pdu->ul_cqi_information.channel); + + memcpy(dest_pdu, src_pdu, sizeof(*src_pdu)); + } + + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + //mac_sr_ind(p7_vnf->mac, ind); + + return 1; +} + +int phy_cqi_indication(struct nfapi_vnf_p7_config* config, nfapi_cqi_indication_t* ind) { + + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + //mac_cqi_ind(p7_vnf->mac, ind); + struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; + + LOG_D(MAC, "%s() NFAPI SFN/SF:%d number_of_cqis:%u\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->cqi_indication_body.number_of_cqis); + + pthread_mutex_lock(&eNB->UL_INFO_mutex); + + eNB->UL_INFO.cqi_ind = ind->cqi_indication_body; + + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + + return 1; +} + +int phy_lbt_dl_indication(struct nfapi_vnf_p7_config* config, nfapi_lbt_dl_indication_t* ind) { + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + //mac_lbt_dl_ind(p7_vnf->mac, ind); + return 1; +} + +int phy_nb_harq_indication(struct nfapi_vnf_p7_config* config, nfapi_nb_harq_indication_t* ind) { + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + //mac_nb_harq_ind(p7_vnf->mac, ind); + return 1; +} + +int phy_nrach_indication(struct nfapi_vnf_p7_config* config, nfapi_nrach_indication_t* ind) { + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + //mac_nrach_ind(p7_vnf->mac, ind); + return 1; +} + +void* vnf_allocate(size_t size) { + //return (void*)memory_pool::allocate(size); + return (void*)malloc(size); +} + +void vnf_deallocate(void* ptr) { + //memory_pool::deallocate((uint8_t*)ptr); + free(ptr); +} + +extern void nfapi_log(char *file, char *func, int line, int comp, int level, const char* format, va_list args); + +void vnf_trace(nfapi_trace_level_t nfapi_level, const char* message, ...) { + + va_list args; + int oai_level; + + if (nfapi_level==NFAPI_TRACE_ERROR) + { + oai_level = LOG_ERR; + } + else if (nfapi_level==NFAPI_TRACE_WARN) + { + oai_level = LOG_WARNING; + } + else if (nfapi_level==NFAPI_TRACE_NOTE) + { + oai_level = LOG_INFO; + } + else if (nfapi_level==NFAPI_TRACE_INFO) + { + oai_level = LOG_INFO; + } + else + { + oai_level = LOG_INFO; + } + + va_start(args, message); + nfapi_log("FILE>", "FUNC", 999, PHY, oai_level, message, args); + va_end(args); +} + +int phy_vendor_ext(struct nfapi_vnf_p7_config* config, nfapi_p7_message_header_t* msg) { + + if(msg->message_id == P7_VENDOR_EXT_IND) + { + //vendor_ext_p7_ind* ind = (vendor_ext_p7_ind*)msg; + //printf("[VNF] vendor_ext (error_code:%d)\n", ind->error_code); + } + else + { + printf("[VNF] unknown %02x\n", msg->message_id); + } + return 0; +} + +nfapi_p7_message_header_t* phy_allocate_p7_vendor_ext(uint16_t message_id, uint16_t* msg_size) { + if(message_id == P7_VENDOR_EXT_IND) + { + *msg_size = sizeof(vendor_ext_p7_ind); + return (nfapi_p7_message_header_t*)malloc(sizeof(vendor_ext_p7_ind)); + } + return 0; +} + +void phy_deallocate_p7_vendor_ext(nfapi_p7_message_header_t* header) { + free(header); +} + +int phy_unpack_vendor_extension_tlv(nfapi_tl_t* tl, uint8_t **ppReadPackedMessage, uint8_t *end, void** ve, nfapi_p7_codec_config_t* codec) { + + (void)tl; + (void)ppReadPackedMessage; + (void)ve; + return -1; +} + +int phy_pack_vendor_extension_tlv(void* ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* codec) { + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "phy_pack_vendor_extension_tlv\n"); + + nfapi_tl_t* tlv = (nfapi_tl_t*)ve; + switch(tlv->tag) { + case VENDOR_EXT_TLV_1_TAG: + { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "Packing VENDOR_EXT_TLV_1\n"); + vendor_ext_tlv_1* ve = (vendor_ext_tlv_1*)tlv; + if(!push32(ve->dummy, ppWritePackedMsg, end)) + return 0; + return 1; + } + break; + default: + return -1; + break; + } +} + +int phy_unpack_p7_vendor_extension(nfapi_p7_message_header_t* header, uint8_t** ppReadPackedMessage, uint8_t *end, nfapi_p7_codec_config_t* config) { + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if(header->message_id == P7_VENDOR_EXT_IND) { + vendor_ext_p7_ind* req = (vendor_ext_p7_ind*)(header); + if(!pull16(ppReadPackedMessage, &req->error_code, end)) + return 0; + } + + return 1; +} + +int phy_pack_p7_vendor_extension(nfapi_p7_message_header_t* header, uint8_t** ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if(header->message_id == P7_VENDOR_EXT_REQ) { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + vendor_ext_p7_req* req = (vendor_ext_p7_req*)(header); + if(!(push16(req->dummy1, ppWritePackedMsg, end) && + push16(req->dummy2, ppWritePackedMsg, end))) + return 0; + } + return 1; +} + +int vnf_pack_p4_p5_vendor_extension(nfapi_p4_p5_message_header_t* header, uint8_t** ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* codec) { + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if(header->message_id == P5_VENDOR_EXT_REQ) { + vendor_ext_p5_req* req = (vendor_ext_p5_req*)(header); + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s %d %d\n", __FUNCTION__, req->dummy1, req->dummy2); + return (!(push16(req->dummy1, ppWritePackedMsg, end) && + push16(req->dummy2, ppWritePackedMsg, end))); + } + return 0; +} + +static pthread_t vnf_start_pthread; +static pthread_t vnf_p7_start_pthread; + +void* vnf_p7_start_thread(void *ptr) { + + printf("%s()\n", __FUNCTION__); + + pthread_setname_np(pthread_self(), "VNF_P7"); + + nfapi_vnf_p7_config_t* config = (nfapi_vnf_p7_config_t*)ptr; + + nfapi_vnf_p7_start(config); + + return config; +} + +void set_thread_priority(int priority); + +void* vnf_p7_thread_start(void* ptr) { + + set_thread_priority(79); + + vnf_p7_info* p7_vnf = (vnf_p7_info*)ptr; + + p7_vnf->config->port = p7_vnf->local_port; + p7_vnf->config->sync_indication = &phy_sync_indication; + p7_vnf->config->subframe_indication = &phy_subframe_indication; + p7_vnf->config->harq_indication = &phy_harq_indication; + p7_vnf->config->crc_indication = &phy_crc_indication; + p7_vnf->config->rx_indication = &phy_rx_indication; + p7_vnf->config->rach_indication = &phy_rach_indication; + p7_vnf->config->srs_indication = &phy_srs_indication; + p7_vnf->config->sr_indication = &phy_sr_indication; + p7_vnf->config->cqi_indication = &phy_cqi_indication; + p7_vnf->config->lbt_dl_indication = &phy_lbt_dl_indication; + p7_vnf->config->nb_harq_indication = &phy_nb_harq_indication; + p7_vnf->config->nrach_indication = &phy_nrach_indication; + p7_vnf->config->malloc = &vnf_allocate; + p7_vnf->config->free = &vnf_deallocate; + + p7_vnf->config->trace = &vnf_trace; + + p7_vnf->config->vendor_ext = &phy_vendor_ext; + p7_vnf->config->user_data = p7_vnf; + + p7_vnf->mac->user_data = p7_vnf; + + p7_vnf->config->codec_config.unpack_p7_vendor_extension = &phy_unpack_p7_vendor_extension; + p7_vnf->config->codec_config.pack_p7_vendor_extension = &phy_pack_p7_vendor_extension; + p7_vnf->config->codec_config.unpack_vendor_extension_tlv = &phy_unpack_vendor_extension_tlv; + p7_vnf->config->codec_config.pack_vendor_extension_tlv = &phy_pack_vendor_extension_tlv; + p7_vnf->config->codec_config.allocate = &vnf_allocate; + p7_vnf->config->codec_config.deallocate = &vnf_deallocate; + + p7_vnf->config->allocate_p7_vendor_ext = &phy_allocate_p7_vendor_ext; + p7_vnf->config->deallocate_p7_vendor_ext = &phy_deallocate_p7_vendor_ext; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Creating VNF NFAPI start thread %s\n", __FUNCTION__); + pthread_create(&vnf_p7_start_pthread, NULL, &vnf_p7_start_thread, p7_vnf->config); + + return 0; +} + +int pnf_start_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_start_response_t* resp) { + + vnf_info* vnf = (vnf_info*)(config->user_data); + vnf_p7_info *p7_vnf = vnf->p7_vnfs; + pnf_info *pnf = vnf->pnfs; + nfapi_param_request_t req; + + printf("[VNF] pnf start response idx:%d config:%p user_data:%p p7_vnf[config:%p thread_started:%d]\n", p5_idx, config, config->user_data, vnf->p7_vnfs[0].config, vnf->p7_vnfs[0].thread_started); + + if(p7_vnf->thread_started == 0) { + + pthread_t vnf_p7_thread; + pthread_create(&vnf_p7_thread, NULL, &vnf_p7_thread_start, p7_vnf); + p7_vnf->thread_started = 1; + } + else + { + // P7 thread already running. + } + + // start all the phys in the pnf. + printf("[VNF] Sending NFAPI_PARAM_REQUEST phy_id:%d\n", pnf->phys[0].id); + + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PARAM_REQUEST; + req.header.phy_id = pnf->phys[0].id; + + nfapi_vnf_param_req(config, p5_idx, &req); + + return 0; +} + +extern uint32_t to_earfcn(int eutra_bandP,uint32_t dl_CarrierFreq,uint32_t bw); + +int param_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_param_response_t* resp) { + + printf("[VNF] Received NFAPI_PARAM_RESP idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id); + + vnf_info* vnf = (vnf_info*)(config->user_data); + vnf_p7_info *p7_vnf = vnf->p7_vnfs; + + pnf_info *pnf = vnf->pnfs; + phy_info *phy = pnf->phys; + struct sockaddr_in pnf_p7_sockaddr; + nfapi_config_request_t *req = &RC.mac[0]->config[0]; + + phy->remote_port = resp->nfapi_config.p7_pnf_port.value; + + memcpy(&pnf_p7_sockaddr.sin_addr.s_addr, &(resp->nfapi_config.p7_pnf_address_ipv4.address[0]), 4); + + phy->remote_addr = inet_ntoa(pnf_p7_sockaddr.sin_addr); + + // for now just 1 + + printf("[VNF] %d.%d pnf p7 %s:%d timing %d %d %d %d\n", p5_idx, phy->id, phy->remote_addr, phy->remote_port, p7_vnf->timing_window, p7_vnf->periodic_timing_period, p7_vnf->aperiodic_timing_enabled, p7_vnf->periodic_timing_period); + + req->header.message_id = NFAPI_CONFIG_REQUEST; + req->header.phy_id = phy->id; + + printf("[VNF] Send NFAPI_CONFIG_REQUEST\n"); + + req->nfapi_config.p7_vnf_port.tl.tag = NFAPI_NFAPI_P7_VNF_PORT_TAG; + req->nfapi_config.p7_vnf_port.value = p7_vnf->local_port; + req->num_tlv++; + + printf("[VNF] DJP local_port:%d\n", p7_vnf->local_port); + + req->nfapi_config.p7_vnf_address_ipv4.tl.tag = NFAPI_NFAPI_P7_VNF_ADDRESS_IPV4_TAG; + struct sockaddr_in vnf_p7_sockaddr; + vnf_p7_sockaddr.sin_addr.s_addr = inet_addr(p7_vnf->local_addr); + memcpy(&(req->nfapi_config.p7_vnf_address_ipv4.address[0]), &vnf_p7_sockaddr.sin_addr.s_addr, 4); + req->num_tlv++; + printf("[VNF] DJP local_addr:%s\n", p7_vnf->local_addr); + + req->nfapi_config.timing_window.tl.tag = NFAPI_NFAPI_TIMING_WINDOW_TAG; + req->nfapi_config.timing_window.value = p7_vnf->timing_window; + printf("[VNF] Timing window:%d\n", p7_vnf->timing_window); + req->num_tlv++; + + if(p7_vnf->periodic_timing_enabled || p7_vnf->aperiodic_timing_enabled) { + + req->nfapi_config.timing_info_mode.tl.tag = NFAPI_NFAPI_TIMING_INFO_MODE_TAG; + req->nfapi_config.timing_info_mode.value = (p7_vnf->aperiodic_timing_enabled << 1) | (p7_vnf->periodic_timing_enabled); + req->num_tlv++; + + if(p7_vnf->periodic_timing_enabled) { + + req->nfapi_config.timing_info_period.tl.tag = NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG; + req->nfapi_config.timing_info_period.value = p7_vnf->periodic_timing_period; + req->num_tlv++; + } + } + + vendor_ext_tlv_2 ve2; + memset(&ve2, 0, sizeof(ve2)); + ve2.tl.tag = VENDOR_EXT_TLV_2_TAG; + ve2.dummy = 2016; + req->vendor_extension = &ve2.tl; + + nfapi_vnf_config_req(config, p5_idx, req); + printf("[VNF] Sent NFAPI_CONFIG_REQ num_tlv:%u\n",req->num_tlv); + + return 0; +} + +int config_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_config_response_t* resp) { + + nfapi_start_request_t req; + + printf("[VNF] Received NFAPI_CONFIG_RESP idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id); + + printf("[VNF] Calling oai_enb_init()\n"); + oai_enb_init(); + + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_START_REQUEST; + req.header.phy_id = resp->header.phy_id; + nfapi_vnf_start_req(config, p5_idx, &req); + + printf("[VNF] Send NFAPI_START_REQUEST idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id); + + return 0; +} + +int start_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_start_response_t* resp) { + + printf("[VNF] Received NFAPI_START_RESP idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id); + + vnf_info* vnf = (vnf_info*)(config->user_data); + + pnf_info *pnf = vnf->pnfs; + phy_info *phy = pnf->phys; + vnf_p7_info *p7_vnf = vnf->p7_vnfs; + nfapi_vnf_p7_add_pnf((p7_vnf->config), phy->remote_addr, phy->remote_port, phy->id); + + return 0; +} + +int vendor_ext_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_p4_p5_message_header_t* msg) { + + printf("[VNF] %s\n", __FUNCTION__); + + switch(msg->message_id) { + case P5_VENDOR_EXT_RSP: + { + vendor_ext_p5_rsp* rsp = (vendor_ext_p5_rsp*)msg; + printf("[VNF] P5_VENDOR_EXT_RSP error_code:%d\n", rsp->error_code); + + // send the start request + + nfapi_pnf_start_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PNF_START_REQUEST; + nfapi_vnf_pnf_start_req(config, p5_idx, &req); + } + break; + } + + return 0; +} + +int vnf_unpack_p4_p5_vendor_extension(nfapi_p4_p5_message_header_t* header, uint8_t** ppReadPackedMessage, uint8_t *end, nfapi_p4_p5_codec_config_t* codec) { + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if(header->message_id == P5_VENDOR_EXT_RSP) + { + vendor_ext_p5_rsp* req = (vendor_ext_p5_rsp*)(header); + return(!pull16(ppReadPackedMessage, &req->error_code, end)); + } + return 0; +} + +nfapi_p4_p5_message_header_t* vnf_allocate_p4_p5_vendor_ext(uint16_t message_id, uint16_t* msg_size) { + + if(message_id == P5_VENDOR_EXT_RSP) { + *msg_size = sizeof(vendor_ext_p5_rsp); + return (nfapi_p4_p5_message_header_t*)malloc(sizeof(vendor_ext_p5_rsp)); + } + return 0; +} + +void vnf_deallocate_p4_p5_vendor_ext(nfapi_p4_p5_message_header_t* header) { + free(header); +} + +nfapi_vnf_config_t *config = 0; + +void vnf_start_thread(void* ptr) { + + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] VNF NFAPI thread - nfapi_vnf_start()%s\n", __FUNCTION__); + + pthread_setname_np(pthread_self(), "VNF"); + + config = (nfapi_vnf_config_t*)ptr; + + nfapi_vnf_start(config); +} + +static vnf_info vnf; +extern uint8_t nfapi_mode; +/*------------------------------------------------------------------------------*/ +void configure_nfapi_vnf(char *vnf_addr, int vnf_p5_port) +{ + nfapi_mode = 2; + + memset(&vnf, 0, sizeof(vnf)); + + memset(vnf.p7_vnfs, 0, sizeof(vnf.p7_vnfs)); + + vnf.p7_vnfs[0].timing_window = 32; + vnf.p7_vnfs[0].periodic_timing_enabled = 1; + vnf.p7_vnfs[0].aperiodic_timing_enabled = 0; + vnf.p7_vnfs[0].periodic_timing_period = 10; + + vnf.p7_vnfs[0].config = nfapi_vnf_p7_config_create(); + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] %s() vnf.p7_vnfs[0].config:%p VNF ADDRESS:%s:%d\n", __FUNCTION__, vnf.p7_vnfs[0].config, vnf_addr, vnf_p5_port); + + strcpy(vnf.p7_vnfs[0].local_addr, vnf_addr); + vnf.p7_vnfs[0].local_port = 50001; + vnf.p7_vnfs[0].mac = (mac_t*)malloc(sizeof(mac_t)); + + nfapi_vnf_config_t* config = nfapi_vnf_config_create(); + + config->malloc = malloc; + config->free = free; + config->trace = &vnf_trace; + + config->vnf_p5_port = vnf_p5_port; + config->vnf_ipv4 = 1; + config->vnf_ipv6 = 0; + + config->pnf_list = 0; + config->phy_list = 0; + + config->pnf_connection_indication = &pnf_connection_indication_cb; + config->pnf_disconnect_indication = &pnf_disconnection_indication_cb; + config->pnf_param_resp = &pnf_param_resp_cb; + config->pnf_config_resp = &pnf_config_resp_cb; + config->pnf_start_resp = &pnf_start_resp_cb; + config->param_resp = ¶m_resp_cb; + config->config_resp = &config_resp_cb; + config->start_resp = &start_resp_cb; + config->vendor_ext = &vendor_ext_cb; + + config->user_data = &vnf; + + // To allow custom vendor extentions to be added to nfapi + config->codec_config.unpack_vendor_extension_tlv = &vnf_unpack_vendor_extension_tlv; + config->codec_config.pack_vendor_extension_tlv = &vnf_pack_vendor_extension_tlv; + + config->codec_config.unpack_p4_p5_vendor_extension = &vnf_unpack_p4_p5_vendor_extension; + config->codec_config.pack_p4_p5_vendor_extension = &vnf_pack_p4_p5_vendor_extension; + config->allocate_p4_p5_vendor_ext = &vnf_allocate_p4_p5_vendor_ext; + config->deallocate_p4_p5_vendor_ext = &vnf_deallocate_p4_p5_vendor_ext; + config->codec_config.allocate = &vnf_allocate; + config->codec_config.deallocate = &vnf_deallocate; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Creating VNF NFAPI start thread %s\n", __FUNCTION__); + pthread_create(&vnf_start_pthread, NULL, (void*)&vnf_start_thread, config); + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Created VNF NFAPI start thread %s\n", __FUNCTION__); +} + +int oai_nfapi_dl_config_req(nfapi_dl_config_request_t *dl_config_req) +{ + nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config; + + dl_config_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + + int retval = nfapi_vnf_p7_dl_config_req(p7_config, dl_config_req); + + dl_config_req->dl_config_request_body.number_pdcch_ofdm_symbols = 1; + dl_config_req->dl_config_request_body.number_dci = 0; + dl_config_req->dl_config_request_body.number_pdu = 0; + dl_config_req->dl_config_request_body.number_pdsch_rnti = 0; + + if (retval!=0) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } + return retval; +} + +int oai_nfapi_tx_req(nfapi_tx_request_t *tx_req) +{ + nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config; + + tx_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + + //LOG_D(PHY, "[VNF] %s() TX_REQ sfn_sf:%d number_of_pdus:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(tx_req->sfn_sf), tx_req->tx_request_body.number_of_pdus); + + int retval = nfapi_vnf_p7_tx_req(p7_config, tx_req); + + + if (retval!=0) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } else { + tx_req->tx_request_body.number_of_pdus = 0; + } + return retval; +} + +int oai_nfapi_hi_dci0_req(nfapi_hi_dci0_request_t *hi_dci0_req) { + nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config; + + hi_dci0_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + + //LOG_D(PHY, "[VNF] %s() HI_DCI0_REQ sfn_sf:%d dci:%d hi:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(hi_dci0_req->sfn_sf), hi_dci0_req->hi_dci0_request_body.number_of_dci, hi_dci0_req->hi_dci0_request_body.number_of_hi); + + int retval = nfapi_vnf_p7_hi_dci0_req(p7_config, hi_dci0_req); + + if (retval!=0) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } else { + hi_dci0_req->hi_dci0_request_body.number_of_hi = 0; + hi_dci0_req->hi_dci0_request_body.number_of_dci = 0; + } + return retval; +} + +int oai_nfapi_ul_config_req(nfapi_ul_config_request_t *ul_config_req) { + + nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config; + + ul_config_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + + //LOG_D(PHY, "[VNF] %s() header message_id:%02x\n", __FUNCTION__, ul_config_req->header.message_id); + + //LOG_D(PHY, "[VNF] %s() UL_CONFIG sfn_sf:%d PDUs:%d rach_prach_frequency_resources:%d srs_present:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(ul_config_req->sfn_sf), ul_config_req->ul_config_request_body.number_of_pdus, ul_config_req->ul_config_request_body.rach_prach_frequency_resources, ul_config_req->ul_config_request_body.srs_present); + + int retval = nfapi_vnf_p7_ul_config_req(p7_config, ul_config_req); + + if (retval!=0) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } else { + // Reset number of PDUs so that it is not resent + ul_config_req->ul_config_request_body.number_of_pdus = 0; + ul_config_req->ul_config_request_body.rach_prach_frequency_resources = 0; + ul_config_req->ul_config_request_body.srs_present = 0; + } + return retval; +} diff --git a/nfapi/oai_integration/nfapi_vnf.h b/nfapi/oai_integration/nfapi_vnf.h new file mode 100644 index 0000000000..4ea26eda12 --- /dev/null +++ b/nfapi/oai_integration/nfapi_vnf.h @@ -0,0 +1,27 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#if !defined(NFAPI_VNF_H__) +#define NFAPI_VNF_H__ + +void configure_nfapi_vnf(char *vnf_addr, int vnf_p5_port); + +#endif diff --git a/nfapi/oai_integration/vendor_ext.h b/nfapi/oai_integration/vendor_ext.h new file mode 100644 index 0000000000..0622432260 --- /dev/null +++ b/nfapi/oai_integration/vendor_ext.h @@ -0,0 +1,67 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _VENDOR_EXT_H_ +#define _VENDOR_EXT_H_ + +#include "nfapi_interface.h" + +typedef enum { + P5_VENDOR_EXT_REQ = NFAPI_VENDOR_EXT_MSG_MIN, + P5_VENDOR_EXT_RSP, + + P7_VENDOR_EXT_REQ, + P7_VENDOR_EXT_IND + +} vendor_ext_message_id_e; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint16_t dummy1; + uint16_t dummy2; +} vendor_ext_p5_req; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint16_t error_code; +} vendor_ext_p5_rsp; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t dummy1; + uint16_t dummy2; +} vendor_ext_p7_req; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t error_code; +} vendor_ext_p7_ind; + +typedef struct { + nfapi_tl_t tl; + uint32_t dummy; +} vendor_ext_tlv_1; + +#define VENDOR_EXT_TLV_1_TAG 0xF001 + +typedef struct { + nfapi_tl_t tl; + uint32_t dummy; +} vendor_ext_tlv_2; + +#define VENDOR_EXT_TLV_2_TAG 0xF002 + +#endif // _VENDOR_EXT_ diff --git a/nfapi/open-nfapi.oai.patch b/nfapi/open-nfapi.oai.patch new file mode 100644 index 0000000000..5b91e3675b --- /dev/null +++ b/nfapi/open-nfapi.oai.patch @@ -0,0 +1,20010 @@ +diff --git a/common/public_inc/debug.h b/common/public_inc/debug.h +index 05e9870..14f97a1 100644 +--- a/common/public_inc/debug.h ++++ b/common/public_inc/debug.h +@@ -39,7 +39,8 @@ extern nfapi_trace_fn_t nfapi_trace_g; + extern nfapi_trace_level_t nfapi_trace_level_g; + + /*! NFAPI trace macro */ +-#define NFAPI_TRACE(level, format, ...) { if(nfapi_trace_g && ((nfapi_trace_level_t)level <= nfapi_trace_level_g)) (*nfapi_trace_g)(level, format, ##__VA_ARGS__); } ++//#define NFAPI_TRACE(level, format, ...) { if(nfapi_trace_g && ((nfapi_trace_level_t)level <= nfapi_trace_level_g)) (*nfapi_trace_g)(level, format, ##__VA_ARGS__); } ++#define NFAPI_TRACE(level, format, ...) { if (nfapi_trace_g) (*nfapi_trace_g)(level, format, ##__VA_ARGS__); } + + /*! Function to change the trace level + * \param new_level The modified trace level +diff --git a/nfapi/public_inc/nfapi_interface.h b/nfapi/public_inc/nfapi_interface.h +index 2d58c2a..f665d11 100644 +--- a/nfapi/public_inc/nfapi_interface.h ++++ b/nfapi/public_inc/nfapi_interface.h +@@ -1772,7 +1772,7 @@ typedef struct { + uint8_t number_of_cc; + struct { + uint8_t ri_size; +- uint8_t dl_cqi_pmi_size; ++ uint8_t dl_cqi_pmi_size[8]; + } cc[NFAPI_MAX_CC]; + } nfapi_ul_config_aperiodic_cqi_pmi_ri_report_t; + +diff --git a/nfapi/src/nfapi.c b/nfapi/src/nfapi.c +index 0e06963..3f017bc 100644 +--- a/nfapi/src/nfapi.c ++++ b/nfapi/src/nfapi.c +@@ -823,6 +823,10 @@ uint8_t pack_tlv(uint16_t tag, void *tlv, uint8_t **ppWritePackedMsg, uint8_t *e + { + NFAPI_TRACE(NFAPI_TRACE_WARN, "Warning pack_tlv tag 0x%x does not match expected 0x%x\n", tl->tag, tag); + } ++ else ++ { ++ //NFAPI_TRACE(NFAPI_TRACE_ERROR, "Warning pack_tlv tag 0x%x ZERO does not match expected 0x%x\n", tl->tag, tag); ++ } + } + + return 1; +diff --git a/nfapi/src/nfapi_p7.c b/nfapi/src/nfapi_p7.c +index a3b0141..69ff860 100644 +--- a/nfapi/src/nfapi_p7.c ++++ b/nfapi/src/nfapi_p7.c +@@ -111,6 +111,8 @@ static uint8_t pack_dl_config_dci_dl_pdu_rel8_value(void* tlv, uint8_t **ppWrite + { + nfapi_dl_config_dci_dl_pdu_rel8_t* value = (nfapi_dl_config_dci_dl_pdu_rel8_t*)tlv; + ++ //NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() dci_format:%u\n", __FUNCTION__, value->dci_format); ++ + return ( push8(value->dci_format, ppWritePackedMsg, end) && + push8(value->cce_idx, ppWritePackedMsg, end) && + push8(value->aggregation_level, ppWritePackedMsg, end) && +@@ -234,6 +236,8 @@ static uint8_t pack_dl_config_bch_pdu_rel8_value(void* tlv, uint8_t **ppWritePac + { + nfapi_dl_config_bch_pdu_rel8_t* value = (nfapi_dl_config_bch_pdu_rel8_t*)tlv; + ++ //NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s()\n", __FUNCTION__); ++ + return( push16(value->length, ppWritePackedMsg, end) && + push16(value->pdu_index, ppWritePackedMsg, end) && + push16(value->transmission_power, ppWritePackedMsg, end)); +@@ -545,6 +549,8 @@ static uint8_t pack_dl_config_request_body_value(void* tlv, uint8_t **ppWritePac + { + nfapi_dl_config_request_body_t* value = (nfapi_dl_config_request_body_t*)tlv; + ++ //NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() dci:%u pdu:%u pdsch:%u rnti:%u pcfich:%u\n", __FUNCTION__, value->number_dci, value->number_pdu, value->number_pdsch_rnti, value->transmission_power_pcfich); ++ + if(!(push8(value->number_pdcch_ofdm_symbols, ppWritePackedMsg, end) && + push8(value->number_dci, ppWritePackedMsg, end) && + push16(value->number_pdu, ppWritePackedMsg, end) && +@@ -574,6 +580,8 @@ static uint8_t pack_dl_config_request_body_value(void* tlv, uint8_t **ppWritePac + { + case NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE: + { ++ //NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE\n", __FUNCTION__); ++ + if(!(pack_tlv(NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel8, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel8_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL9_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel9, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel9_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL10_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel10, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel10_value) && +@@ -587,6 +595,8 @@ static uint8_t pack_dl_config_request_body_value(void* tlv, uint8_t **ppWritePac + break; + case NFAPI_DL_CONFIG_BCH_PDU_TYPE: + { ++ //NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() NFAPI_DL_CONFIG_BCH_PDU_TYPE\n", __FUNCTION__); ++ + if(!(pack_tlv(NFAPI_DL_CONFIG_REQUEST_BCH_PDU_REL8_TAG, &pdu->bch_pdu.bch_pdu_rel8, ppWritePackedMsg, end, &pack_dl_config_bch_pdu_rel8_value))) + return 0; + } +@@ -684,10 +694,21 @@ static uint8_t pack_dl_config_request(void *msg, uint8_t **ppWritePackedMsg, uin + { + nfapi_dl_config_request_t *pNfapiMsg = (nfapi_dl_config_request_t*)msg; + +- return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && +- pack_tlv(NFAPI_DL_CONFIG_REQUEST_BODY_TAG, &pNfapiMsg->dl_config_request_body, ppWritePackedMsg, end, &pack_dl_config_request_body_value) && +- pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); ++ //return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && ++ //pack_tlv(NFAPI_DL_CONFIG_REQUEST_BODY_TAG, &pNfapiMsg->dl_config_request_body, ppWritePackedMsg, end, &pack_dl_config_request_body_value) && ++ //pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); ++ { ++ uint8_t x = push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end); ++ uint8_t y = pack_tlv(NFAPI_DL_CONFIG_REQUEST_BODY_TAG, &pNfapiMsg->dl_config_request_body, ppWritePackedMsg, end, &pack_dl_config_request_body_value); ++ uint8_t z = pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config); + ++ if (!x || !y || !z) ++ { ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() NFAPI_DL_CONFIG_REQUEST x:%u y:%u z:%u \n", __FUNCTION__,x,y,z); ++ } ++ ++ return x && y && z; ++ } + } + + static uint8_t pack_ul_config_request_ulsch_rel8_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t * end) +@@ -796,9 +817,10 @@ static uint8_t pack_ul_config_request_cqi_ri_rel9_value(void *tlv, uint8_t **ppW + if(push8(cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.cc[i].ri_size, ppWritePackedMsg, end) == 0) + return 0; + +- if(cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.cc[i].ri_size > 0) ++ uint8_t j; ++ for(j = 0; j < 8; ++j) + { +- if(push8(cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.cc[i].dl_cqi_pmi_size, ppWritePackedMsg, end) == 0) ++ if(push8(cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.cc[i].dl_cqi_pmi_size[j], ppWritePackedMsg, end) == 0) + return 0; + } + } +@@ -1518,7 +1540,21 @@ static uint8_t pack_tx_request_body_value(void* tlv, uint8_t **ppWritePackedMsg, + for(j = 0; j < pdu->num_segments; ++j) + { + // Use -1 as it is unbounded +- if(pusharray8(pdu->segments[j].segment_data, (uint32_t)(-1), pdu->segments[j].segment_length, ppWritePackedMsg, end) == 0) ++ // DJP - does not handle -1 ++ // DJP - if(pusharray8(pdu->segments[j].segment_data, (uint32_t)(-1), pdu->segments[j].segment_length, ppWritePackedMsg, end) == 0) ++ int push_ret = pusharray8(pdu->segments[j].segment_data, 65535, pdu->segments[j].segment_length, ppWritePackedMsg, end); ++ ++ if (0 && pdu->segments[j].segment_length == 3) ++ { ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() BCH? segment_data:%x %x %x\n", __FUNCTION__, ++ pdu->segments[j].segment_data[0], ++ pdu->segments[j].segment_data[1], ++ pdu->segments[j].segment_data[2] ++ ); ++ } ++ //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() segment_data:%p segment_length:%u pusharray8()=%d\n", __FUNCTION__, pdu->segments[j].segment_data, pdu->segments[j].segment_length, push_ret); ++ ++ if (push_ret == 0) + { + return 0; + } +@@ -1532,9 +1568,13 @@ static uint8_t pack_tx_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e + { + nfapi_tx_request_t *pNfapiMsg = (nfapi_tx_request_t*)msg; + +- return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && +- pack_tlv(NFAPI_TX_REQUEST_BODY_TAG, &pNfapiMsg->tx_request_body, ppWritePackedMsg, end, &pack_tx_request_body_value) && +- pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); ++ int x = push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end); ++ int y = pack_tlv(NFAPI_TX_REQUEST_BODY_TAG, &pNfapiMsg->tx_request_body, ppWritePackedMsg, end, &pack_tx_request_body_value); ++ int z = pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config); ++ ++ //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() x:%d y:%d z:%d\n", __FUNCTION__, x, y, z); ++ ++ return x && y && z; + } + + static uint8_t pack_rx_ue_information_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +@@ -1844,6 +1884,8 @@ static uint8_t pack_rx_ulsch_indication_body_value(void *tlv, uint8_t **ppWriteP + { + nfapi_rx_indication_body_t* value = (nfapi_rx_indication_body_t*)tlv; + ++ //printf("RX ULSCH BODY\n"); ++ + if( push16(value->number_of_pdus, ppWritePackedMsg, end) == 0) + return 0; + +@@ -1851,21 +1893,26 @@ static uint8_t pack_rx_ulsch_indication_body_value(void *tlv, uint8_t **ppWriteP + uint16_t i = 0; + uint16_t offset = 2; // taking into account the number_of_pdus + uint16_t total_number_of_pdus = value->number_of_pdus; ++ //printf("ULSCH:pdus:%d\n", total_number_of_pdus); ++ + for(i = 0; i < total_number_of_pdus; ++i) + { + nfapi_rx_indication_pdu_t* pdu = &(value->rx_pdu_list[i]); + if(pdu->rx_ue_information.tl.tag == NFAPI_RX_UE_INFORMATION_TAG) + { ++ //printf("NFAPI_RX_UE_INFORMATION_TAG\n"); + offset += 4 + 6; + } + + if(pdu->rx_indication_rel8.tl.tag == NFAPI_RX_INDICATION_REL8_TAG) + { ++ //printf("NFAPI_RX_INDICATION_REL8_TAG\n"); + offset += 4 + 7; + } + + if(pdu->rx_indication_rel9.tl.tag == NFAPI_RX_INDICATION_REL9_TAG) + { ++ //printf("NFAPI_RX_INDICATION_REL9_TAG\n"); + offset += 4 + 2; + } + } +@@ -2592,11 +2639,16 @@ int nfapi_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packedBu + return -1; + } + ++ if (pMessageHeader->message_id != NFAPI_TIMING_INFO) ++ { ++ //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() message_id:0x%04x phy_id:%u m_segment_sequence:%u timestamp:%u\n", __FUNCTION__, pMessageHeader->message_id, pMessageHeader->phy_id, pMessageHeader->m_segment_sequence, pMessageHeader->transmit_timestamp); ++ } + // look for the specific message + uint8_t result = 0; + switch (pMessageHeader->message_id) + { + case NFAPI_DL_CONFIG_REQUEST: ++ //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() NFAPI_DL_CONFIG_REQUEST\n", __FUNCTION__); + result = pack_dl_config_request(pMessageHeader, &pWritePackedMessage, end, config); + break; + +@@ -2609,6 +2661,7 @@ int nfapi_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packedBu + break; + + case NFAPI_TX_REQUEST: ++ //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() NFAPI_TX_REQUEST\n", __FUNCTION__); + result = pack_tx_request(pMessageHeader, &pWritePackedMessage, end, config); + break; + +@@ -2621,6 +2674,7 @@ int nfapi_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packedBu + break; + + case NFAPI_RX_ULSCH_INDICATION: ++ //printf("RX ULSCH\n"); + result = pack_rx_ulsch_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + +@@ -3482,9 +3536,10 @@ static uint8_t unpack_ul_config_cqi_ri_info_rel9_value(void *tlv, uint8_t **ppRe + if(pull8(ppReadPackedMsg, &cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.cc[i].ri_size, end) == 0) + return 0; + +- if(cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.cc[i].ri_size > 0) ++ uint8_t j; ++ for(j = 0; j < 8; ++j) + { +- if(pull8(ppReadPackedMsg, &cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.cc[i].dl_cqi_pmi_size, end) == 0) ++ if(pull8(ppReadPackedMsg, &cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.cc[i].dl_cqi_pmi_size[j], end) == 0) + return 0; + } + } +@@ -4394,6 +4449,14 @@ static uint8_t unpack_tx_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * + { + if(!pullarray8(ppReadPackedMsg, pdu->segments[0].segment_data, pdu->segments[0].segment_length, pdu->segments[0].segment_length, end)) + return 0; ++ if (0 && pdu->segments[0].segment_length == 3) ++ { ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() BCH? segment_data:%x %x %x\n", __FUNCTION__, ++ pdu->segments[0].segment_data[0], ++ pdu->segments[0].segment_data[1], ++ pdu->segments[0].segment_data[2] ++ ); ++ } + } + else + { +diff --git a/pnf/public_inc/nfapi_pnf_interface.h b/pnf/public_inc/nfapi_pnf_interface.h +index f93624d..b25caf2 100644 +--- a/pnf/public_inc/nfapi_pnf_interface.h ++++ b/pnf/public_inc/nfapi_pnf_interface.h +@@ -319,10 +319,10 @@ typedef struct nfapi_pnf_config + * 0 will be returned if it fails. + * + * \code +- * nfapi_pnf_config_t* config = nfapi_pnf_config_create(); ++ * nfapi_pnf_config_t* config = nfapi_pnf_config_create(void); + * \endcode + */ +-nfapi_pnf_config_t* nfapi_pnf_config_create(); ++nfapi_pnf_config_t* nfapi_pnf_config_create(void); + + /*! Delete a pnf configuration + * \param config A pointer to a pnf configuraiton +@@ -681,7 +681,7 @@ typedef struct nfapi_pnf_p7_config + /*! Create and initialise a nfapi_pnf_p7_config structure + * \return A pointer to a PNF P7 config structure + */ +-nfapi_pnf_p7_config_t* nfapi_pnf_p7_config_create(); ++nfapi_pnf_p7_config_t* nfapi_pnf_p7_config_create(void); + + /*! Delete an nfapi_pnf_p7_config structure + * \param config +diff --git a/pnf/src/pnf.c b/pnf/src/pnf.c +index d6cf364..d0a7fa6 100644 +--- a/pnf/src/pnf.c ++++ b/pnf/src/pnf.c +@@ -412,10 +412,10 @@ void pnf_handle_start_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) + { + nfapi_start_request_t req; + +- NFAPI_TRACE(NFAPI_TRACE_INFO, "START.request received\n"); +- + nfapi_pnf_config_t* config = &(pnf->_public); + ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() START.request received state:%d\n", __FUNCTION__, config->state); ++ + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + { +diff --git a/pnf/src/pnf_interface.c b/pnf/src/pnf_interface.c +index 74f29a0..7310fc0 100644 +--- a/pnf/src/pnf_interface.c ++++ b/pnf/src/pnf_interface.c +@@ -76,6 +76,7 @@ int nfapi_pnf_start(nfapi_pnf_config_t* config) + + sleep(1); + } ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() terminate=1 - EXITTING............\n", __FUNCTION__); + + return 0; + } +@@ -227,7 +228,7 @@ int nfapi_pnf_start_resp(nfapi_pnf_config_t* config, nfapi_start_response_t* res + } + else + { +- NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: unknow phy id %d\n", __FUNCTION__, resp->header.phy_id); ++ NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: unknown phy id %d\n", __FUNCTION__, resp->header.phy_id); + return -1; + } + +diff --git a/pnf/src/pnf_p7.c b/pnf/src/pnf_p7.c +index 0fd7828..02b828d 100644 +--- a/pnf/src/pnf_p7.c ++++ b/pnf/src/pnf_p7.c +@@ -25,12 +25,64 @@ + #include + #include + #include ++#include + + #include "pnf_p7.h" + + #define FAPI2_IP_DSCP 0 + +-uint32_t get_current_time_hr() ++extern uint16_t sf_ahead; ++//uint16_t sf_ahead=4; ++ ++void add_sf(uint16_t *frameP, uint16_t *subframeP, int offset) ++{ ++ *frameP = *frameP + ((*subframeP + offset) / 10); ++ ++ *subframeP = ((*subframeP + offset) % 10); ++} ++ ++void subtract_sf(uint16_t *frameP, uint16_t *subframeP, int offset) ++{ ++ if (*subframeP < offset) ++ { ++ *frameP = (*frameP+1024-1)%1024; ++ } ++ *subframeP = (*subframeP+10-offset)%10; ++} ++ ++uint16_t sfnsf_add_sf(uint16_t sfnsf, int offset) ++{ ++ uint16_t new_sfnsf; ++ uint16_t sfn = NFAPI_SFNSF2SFN(sfnsf); ++ uint16_t sf = NFAPI_SFNSF2SF(sfnsf); ++ ++ //printf("%s() sfn:%u sf:%u\n", __FUNCTION__, sfn, sf); ++ add_sf(&sfn, &sf, offset); ++ ++ new_sfnsf = sfn<<4|sf; ++ ++ //printf("%s() sfn:%u sf:%u offset:%d sfnsf:%d(DEC:%d) new:%d(DEC:%d)\n", __FUNCTION__, sfn, sf, offset, sfnsf, NFAPI_SFNSF2DEC(sfnsf), new_sfnsf, NFAPI_SFNSF2DEC(new_sfnsf)); ++ ++ return new_sfnsf; ++} ++ ++uint16_t sfnsf_subtract_sf(uint16_t sfnsf, int offset) ++{ ++ uint16_t new_sfnsf; ++ uint16_t sfn = NFAPI_SFNSF2SFN(sfnsf); ++ uint16_t sf = NFAPI_SFNSF2SF(sfnsf); ++ ++ //printf("%s() sfn:%u sf:%u\n", __FUNCTION__, sfn, sf); ++ subtract_sf(&sfn, &sf, offset); ++ ++ new_sfnsf = sfn<<4|sf; ++ ++ //printf("%s() offset:%d sfnsf:%d(DEC:%d) new:%d(DEC:%d)\n", __FUNCTION__, offset, sfnsf, NFAPI_SFNSF2DEC(sfnsf), new_sfnsf, NFAPI_SFNSF2DEC(new_sfnsf)); ++ ++ return new_sfnsf; ++} ++ ++uint32_t pnf_get_current_time_hr(void) + { + struct timeval now; + (void)gettimeofday(&now, NULL); +@@ -64,11 +116,14 @@ void pnf_p7_free(pnf_p7_t* pnf_p7, void* ptr) + // todo : for now these just malloc/free need to move to a memory cache + nfapi_dl_config_request_t* allocate_nfapi_dl_config_request(pnf_p7_t* pnf_p7) + { +- return pnf_p7_malloc(pnf_p7, sizeof(nfapi_dl_config_request_t)); ++ void *ptr= pnf_p7_malloc(pnf_p7, sizeof(nfapi_dl_config_request_t)); ++ //printf("%s() ptr:%p\n", __FUNCTION__, ptr); ++ return ptr; + } + + void deallocate_nfapi_dl_config_request(nfapi_dl_config_request_t* req, pnf_p7_t* pnf_p7) + { ++ //printf("%s() SFN/SF:%d %s req:%p pdu_list:%p\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), pnf_p7->_public.codec_config.deallocate ? "DEALLOCATE" : "FREE", req, req->dl_config_request_body.dl_config_pdu_list); + if(pnf_p7->_public.codec_config.deallocate) + { + (pnf_p7->_public.codec_config.deallocate)(req->dl_config_request_body.dl_config_pdu_list); +@@ -77,17 +132,21 @@ void deallocate_nfapi_dl_config_request(nfapi_dl_config_request_t* req, pnf_p7_t + { + free(req->dl_config_request_body.dl_config_pdu_list); + } ++ req->dl_config_request_body.dl_config_pdu_list=0; + + pnf_p7_free(pnf_p7, req); + } + + nfapi_ul_config_request_t* allocate_nfapi_ul_config_request(pnf_p7_t* pnf_p7) + { +- return pnf_p7_malloc(pnf_p7, sizeof(nfapi_ul_config_request_t)); ++ void *ptr= pnf_p7_malloc(pnf_p7, sizeof(nfapi_ul_config_request_t)); ++ //printf("%s() ptr:%p\n", __FUNCTION__, ptr); ++ return ptr; + } + + void deallocate_nfapi_ul_config_request(nfapi_ul_config_request_t* req, pnf_p7_t* pnf_p7) + { ++ //printf("%s() SFN/SF:%d %s req:%p pdu_list:%p\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), pnf_p7->_public.codec_config.deallocate ? "DEALLOCATE" : "FREE", req, req->ul_config_request_body.ul_config_pdu_list); + if(pnf_p7->_public.codec_config.deallocate) + { + (pnf_p7->_public.codec_config.deallocate)(req->ul_config_request_body.ul_config_pdu_list); +@@ -96,6 +155,7 @@ void deallocate_nfapi_ul_config_request(nfapi_ul_config_request_t* req, pnf_p7_t + { + free(req->ul_config_request_body.ul_config_pdu_list); + } ++ req->ul_config_request_body.ul_config_pdu_list=0; + + pnf_p7_free(pnf_p7, req); + } +@@ -107,6 +167,7 @@ nfapi_hi_dci0_request_t* allocate_nfapi_hi_dci0_request(pnf_p7_t* pnf_p7) + + void deallocate_nfapi_hi_dci0_request(nfapi_hi_dci0_request_t* req, pnf_p7_t* pnf_p7) + { ++ //printf("%s() SFN/SF:%d %s req:%p pdu_list:%p\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), pnf_p7->_public.codec_config.deallocate ? "DEALLOCATE" : "FREE", req, req->hi_dci0_request_body.hi_dci0_pdu_list); + if(pnf_p7->_public.codec_config.deallocate) + { + (pnf_p7->_public.codec_config.deallocate)(req->hi_dci0_request_body.hi_dci0_pdu_list); +@@ -115,6 +176,7 @@ void deallocate_nfapi_hi_dci0_request(nfapi_hi_dci0_request_t* req, pnf_p7_t* pn + { + free(req->hi_dci0_request_body.hi_dci0_pdu_list); + } ++ req->hi_dci0_request_body.hi_dci0_pdu_list=0; + + pnf_p7_free(pnf_p7, req); + } +@@ -127,6 +189,9 @@ nfapi_tx_request_t* allocate_nfapi_tx_request(pnf_p7_t* pnf_p7) + void deallocate_nfapi_tx_request(nfapi_tx_request_t* req, pnf_p7_t* pnf_p7) + { + int i = 0; ++ ++ //printf("%s() SFN/SF:%d %s req:%p pdu[0]:data:%p\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), pnf_p7->_public.codec_config.deallocate ? "DEALLOCATE" : "FREE", req, req->tx_request_body.tx_pdu_list[i].segments[0].segment_data); ++ + for(i = 0; i < req->tx_request_body.number_of_pdus; ++i) + { + void* data = req->tx_request_body.tx_pdu_list[i].segments[0].segment_data; +@@ -139,6 +204,7 @@ void deallocate_nfapi_tx_request(nfapi_tx_request_t* req, pnf_p7_t* pnf_p7) + { + free(data); + } ++ data=0; + } + + +@@ -150,6 +216,7 @@ void deallocate_nfapi_tx_request(nfapi_tx_request_t* req, pnf_p7_t* pnf_p7) + { + free(req->tx_request_body.tx_pdu_list); + } ++ req->tx_request_body.tx_pdu_list=0; + + pnf_p7_free(pnf_p7, req); + } +@@ -169,6 +236,7 @@ void deallocate_nfapi_lbt_dl_config_request(nfapi_lbt_dl_config_request_t* req, + { + free(req->lbt_dl_config_request_body.lbt_dl_config_req_pdu_list); + } ++ req->lbt_dl_config_request_body.lbt_dl_config_req_pdu_list=0; + + pnf_p7_free(pnf_p7, req); + } +@@ -307,11 +375,11 @@ void pnf_p7_rx_reassembly_queue_remove_old_msgs(pnf_p7_t* pnf_p7, pnf_p7_rx_reas + } + + +-uint32_t get_sf_time(uint32_t now_hr, uint32_t sf_start_hr) ++static uint32_t get_sf_time(uint32_t now_hr, uint32_t sf_start_hr) + { + if(now_hr < sf_start_hr) + { +- NFAPI_TRACE(NFAPI_TRACE_INFO, "now is earlier that start of subframe\n"); ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "now is earlier than start of subframe now_hr:%u sf_start_hr:%u\n", now_hr, sf_start_hr); + return 0; + } + else +@@ -482,29 +550,41 @@ void pnf_pack_and_send_timing_info(pnf_p7_t* pnf_p7) + + void send_dummy_subframe(pnf_p7_t* pnf_p7, uint16_t sfn_sf) + { ++ struct timespec t; ++ clock_gettime( CLOCK_MONOTONIC, &t); ++ ++ //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(sfn_sf:%d) t:%ld.%09ld\n", __FUNCTION__, NFAPI_SFNSF2DEC(sfn_sf), t.tv_sec, t.tv_nsec); ++ ++ if(pnf_p7->_public.tx_req && pnf_p7->_public.dummy_subframe.tx_req) ++ { ++ pnf_p7->_public.dummy_subframe.tx_req->sfn_sf = sfn_sf; ++ //NFAPI_TRACE(NFAPI_TRACE_INFO, "Dummy tx_req - enter\n"); ++ (pnf_p7->_public.tx_req)(&pnf_p7->_public, pnf_p7->_public.dummy_subframe.tx_req); ++ //NFAPI_TRACE(NFAPI_TRACE_INFO, "Dummy tx_req - exit\n"); ++ } + if(pnf_p7->_public.dl_config_req && pnf_p7->_public.dummy_subframe.dl_config_req) + { + pnf_p7->_public.dummy_subframe.dl_config_req->sfn_sf = sfn_sf; ++ //NFAPI_TRACE(NFAPI_TRACE_INFO, "Dummy dl_config_req - enter\n"); + (pnf_p7->_public.dl_config_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.dl_config_req); ++ //NFAPI_TRACE(NFAPI_TRACE_INFO, "Dummy dl_config_req - exit\n"); + } + if(pnf_p7->_public.ul_config_req && pnf_p7->_public.dummy_subframe.ul_config_req) + { + pnf_p7->_public.dummy_subframe.ul_config_req->sfn_sf = sfn_sf; ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "Dummy ul_config_req - enter\n"); + (pnf_p7->_public.ul_config_req)(&pnf_p7->_public, pnf_p7->_public.dummy_subframe.ul_config_req); + } + if(pnf_p7->_public.hi_dci0_req && pnf_p7->_public.dummy_subframe.hi_dci0_req) + { + pnf_p7->_public.dummy_subframe.hi_dci0_req->sfn_sf = sfn_sf; ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "Dummy hi_dci0 - enter\n"); + (pnf_p7->_public.hi_dci0_req)(&pnf_p7->_public, pnf_p7->_public.dummy_subframe.hi_dci0_req); + } +- if(pnf_p7->_public.tx_req && pnf_p7->_public.dummy_subframe.tx_req) +- { +- pnf_p7->_public.dummy_subframe.tx_req->sfn_sf = sfn_sf; +- (pnf_p7->_public.tx_req)(&pnf_p7->_public, pnf_p7->_public.dummy_subframe.tx_req); +- } + if(pnf_p7->_public.lbt_dl_config_req && pnf_p7->_public.dummy_subframe.lbt_dl_config_req) + { + pnf_p7->_public.dummy_subframe.lbt_dl_config_req->sfn_sf = sfn_sf; ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "Dummy lbt - enter\n"); + (pnf_p7->_public.lbt_dl_config_req)(&pnf_p7->_public, pnf_p7->_public.dummy_subframe.lbt_dl_config_req); + } + } +@@ -526,10 +606,14 @@ int pnf_p7_subframe_ind(pnf_p7_t* pnf_p7, uint16_t phy_id, uint16_t sfn_sf) + return -1; + } + ++#if 1 + // save the curren time and sfn_sf +- pnf_p7->sf_start_time_hr = get_current_time_hr(); ++ pnf_p7->sf_start_time_hr = pnf_get_current_time_hr(); + pnf_p7->sfn_sf = sfn_sf; + ++ uint32_t sfn_sf_tx = sfnsf_add_sf(sfn_sf, sf_ahead); ++ uint32_t tx_sfn_sf_dec = NFAPI_SFNSF2DEC(sfn_sf_tx); ++ + // If the subframe_buffer has been configured + if(pnf_p7->_public.subframe_buffer_size != 0) + { +@@ -550,6 +634,10 @@ int pnf_p7_subframe_ind(pnf_p7_t* pnf_p7, uint16_t phy_id, uint16_t sfn_sf) + NFAPI_TRACE(NFAPI_TRACE_INFO, "Applying shift %d to sfn/sf (%d -> %d)\n", pnf_p7->sfn_sf_shift, NFAPI_SFNSF2DEC(sfn_sf), shifted_sfn_sf); + sfn_sf = shifted_sfn_sf; + ++ // ++ // DJP - why does the shift not apply to pnf_p7->sfn_sf??? ++ // ++ + pnf_p7->sfn_sf_shift = 0; + } + +@@ -558,77 +646,119 @@ int pnf_p7_subframe_ind(pnf_p7_t* pnf_p7, uint16_t phy_id, uint16_t sfn_sf) + + nfapi_pnf_p7_subframe_buffer_t* subframe_buffer = &(pnf_p7->subframe_buffer[buffer_index]); + ++ uint8_t tx_buffer_index = tx_sfn_sf_dec % pnf_p7->_public.subframe_buffer_size; ++ nfapi_pnf_p7_subframe_buffer_t* tx_subframe_buffer = &(pnf_p7->subframe_buffer[tx_buffer_index]); ++ ++ //printf("sfn_sf_dec:%d tx_sfn_sf_dec:%d\n", sfn_sf_dec, tx_sfn_sf_dec); ++ ++ if (0) NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() shift:%d subframe_buffer->sfn_sf:%d tx_subframe_buffer->sfn_sf:%d sfn_sf:%d subframe_buffer[buffer_index:%u dl_config_req:%p tx_req:%p] " ++ "TX:sfn_sf:%d:tx_buffer_index:%d[dl_config_req:%p tx_req:%p]\n", ++ __FUNCTION__, ++ pnf_p7->sfn_sf_shift, ++ NFAPI_SFNSF2DEC(subframe_buffer->sfn_sf), ++ NFAPI_SFNSF2DEC(tx_subframe_buffer->sfn_sf), ++ sfn_sf_dec, buffer_index, subframe_buffer->dl_config_req, subframe_buffer->tx_req, ++ tx_sfn_sf_dec, tx_buffer_index, tx_subframe_buffer->dl_config_req, tx_subframe_buffer->tx_req); ++ + // if the subframe buffer sfn sf is set then we have atlease 1 message + // from the vnf. + // todo : how to handle the messages we don't have, send dummies for + // now +- if(subframe_buffer->sfn_sf == sfn_sf) ++ ++ //printf("tx_subframe_buffer->sfn_sf:%d sfn_sf_tx:%d\n", tx_subframe_buffer->sfn_sf, sfn_sf_tx); ++ //printf("subframe_buffer->sfn_sf:%d sfn_sf:%d\n", subframe_buffer->sfn_sf, sfn_sf); ++ if(tx_subframe_buffer->sfn_sf == sfn_sf_tx) + { +- if(subframe_buffer->dl_config_req != 0) ++ if(tx_subframe_buffer->tx_req != 0) + { +- if(pnf_p7->_public.dl_config_req) +- (pnf_p7->_public.dl_config_req)(&(pnf_p7->_public), subframe_buffer->dl_config_req); ++ if(pnf_p7->_public.tx_req) ++ (pnf_p7->_public.tx_req)(&(pnf_p7->_public), tx_subframe_buffer->tx_req); + +- deallocate_nfapi_dl_config_request(subframe_buffer->dl_config_req, pnf_p7); ++ //deallocate_nfapi_tx_request(subframe_buffer->tx_req, pnf_p7); + } + else + { + // send dummy +- if(pnf_p7->_public.dl_config_req && pnf_p7->_public.dummy_subframe.dl_config_req) ++ if(pnf_p7->_public.tx_req && pnf_p7->_public.dummy_subframe.tx_req) + { +- pnf_p7->_public.dummy_subframe.dl_config_req->sfn_sf = sfn_sf; +- (pnf_p7->_public.dl_config_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.dl_config_req); ++ pnf_p7->_public.dummy_subframe.tx_req->sfn_sf = sfn_sf_tx; ++ (pnf_p7->_public.tx_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.tx_req); + } + } + +- if(subframe_buffer->ul_config_req != 0) ++ if(tx_subframe_buffer->dl_config_req != 0) + { +- if(pnf_p7->_public.ul_config_req) +- (pnf_p7->_public.ul_config_req)(&(pnf_p7->_public), subframe_buffer->ul_config_req); ++ if(pnf_p7->_public.dl_config_req) ++ (pnf_p7->_public.dl_config_req)(&(pnf_p7->_public), tx_subframe_buffer->dl_config_req); + +- deallocate_nfapi_ul_config_request(subframe_buffer->ul_config_req, pnf_p7); ++ //deallocate_nfapi_dl_config_request(subframe_buffer->dl_config_req, pnf_p7); + } + else + { + // send dummy +- if(pnf_p7->_public.ul_config_req && pnf_p7->_public.dummy_subframe.ul_config_req) ++ if(pnf_p7->_public.dl_config_req && pnf_p7->_public.dummy_subframe.dl_config_req) + { +- pnf_p7->_public.dummy_subframe.ul_config_req->sfn_sf = sfn_sf; +- (pnf_p7->_public.ul_config_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.ul_config_req); ++ pnf_p7->_public.dummy_subframe.dl_config_req->sfn_sf = sfn_sf_tx; ++ (pnf_p7->_public.dl_config_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.dl_config_req); + } + } + +- if(subframe_buffer->hi_dci0_req != 0) ++ if(tx_subframe_buffer->hi_dci0_req != 0) + { + if(pnf_p7->_public.hi_dci0_req) +- (pnf_p7->_public.hi_dci0_req)(&(pnf_p7->_public), subframe_buffer->hi_dci0_req); ++ (pnf_p7->_public.hi_dci0_req)(&(pnf_p7->_public), tx_subframe_buffer->hi_dci0_req); + +- deallocate_nfapi_hi_dci0_request(subframe_buffer->hi_dci0_req, pnf_p7); ++ //deallocate_nfapi_hi_dci0_request(subframe_buffer->hi_dci0_req, pnf_p7); + } + else + { + //send dummy + if(pnf_p7->_public.hi_dci0_req && pnf_p7->_public.dummy_subframe.hi_dci0_req) + { +- pnf_p7->_public.dummy_subframe.hi_dci0_req->sfn_sf = sfn_sf; ++ pnf_p7->_public.dummy_subframe.hi_dci0_req->sfn_sf = sfn_sf_tx; + (pnf_p7->_public.hi_dci0_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.hi_dci0_req); + } + } + +- if(subframe_buffer->tx_req != 0) ++ if(tx_subframe_buffer->dl_config_req != 0) ++ { ++ deallocate_nfapi_dl_config_request(tx_subframe_buffer->dl_config_req, pnf_p7); ++ tx_subframe_buffer->dl_config_req = 0; ++ } ++ if(tx_subframe_buffer->tx_req != 0) ++ { ++ deallocate_nfapi_tx_request(tx_subframe_buffer->tx_req, pnf_p7); ++ tx_subframe_buffer->tx_req = 0; ++ } ++ if(tx_subframe_buffer->hi_dci0_req != 0) ++ { ++ deallocate_nfapi_hi_dci0_request(tx_subframe_buffer->hi_dci0_req, pnf_p7); ++ tx_subframe_buffer->hi_dci0_req = 0; ++ } ++ } ++ else ++ { ++ // If we ever need to "send" a dummy ul_config this won't work!!! ++ send_dummy_subframe(pnf_p7, sfn_sf_tx); ++ } ++ ++ if(subframe_buffer->sfn_sf == sfn_sf) ++ { ++ ++ if(subframe_buffer->ul_config_req != 0) + { +- if(pnf_p7->_public.tx_req) +- (pnf_p7->_public.tx_req)(&(pnf_p7->_public), subframe_buffer->tx_req); ++ if(pnf_p7->_public.ul_config_req) ++ (pnf_p7->_public.ul_config_req)(&(pnf_p7->_public), subframe_buffer->ul_config_req); + +- deallocate_nfapi_tx_request(subframe_buffer->tx_req, pnf_p7); ++ //deallocate_nfapi_ul_config_request(subframe_buffer->ul_config_req, pnf_p7); + } + else + { + // send dummy +- if(pnf_p7->_public.tx_req && pnf_p7->_public.dummy_subframe.tx_req) ++ if(pnf_p7->_public.ul_config_req && pnf_p7->_public.dummy_subframe.ul_config_req) + { +- pnf_p7->_public.dummy_subframe.tx_req->sfn_sf = sfn_sf; +- (pnf_p7->_public.tx_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.tx_req); ++ pnf_p7->_public.dummy_subframe.ul_config_req->sfn_sf = sfn_sf; ++ (pnf_p7->_public.ul_config_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.ul_config_req); + } + } + +@@ -637,7 +767,7 @@ int pnf_p7_subframe_ind(pnf_p7_t* pnf_p7, uint16_t phy_id, uint16_t sfn_sf) + if(pnf_p7->_public.lbt_dl_config_req) + (pnf_p7->_public.lbt_dl_config_req)(&(pnf_p7->_public), subframe_buffer->lbt_dl_config_req); + +- deallocate_nfapi_lbt_dl_config_request(subframe_buffer->lbt_dl_config_req, pnf_p7); ++ //deallocate_nfapi_lbt_dl_config_request(subframe_buffer->lbt_dl_config_req, pnf_p7); + } + else + { +@@ -650,14 +780,35 @@ int pnf_p7_subframe_ind(pnf_p7_t* pnf_p7, uint16_t phy_id, uint16_t sfn_sf) + + } + +- memset(&(pnf_p7->subframe_buffer[buffer_index]), 0, sizeof(nfapi_pnf_p7_subframe_buffer_t)); +- pnf_p7->subframe_buffer[buffer_index].sfn_sf = -1; +- } +- else +- { +- send_dummy_subframe(pnf_p7, sfn_sf); ++ //if(subframe_buffer->dl_config_req != 0) ++ //deallocate_nfapi_dl_config_request(subframe_buffer->dl_config_req, pnf_p7); ++ //if(subframe_buffer->tx_req != 0) ++ //deallocate_nfapi_tx_request(subframe_buffer->tx_req, pnf_p7); ++ if(subframe_buffer->ul_config_req != 0) ++ { ++ deallocate_nfapi_ul_config_request(subframe_buffer->ul_config_req, pnf_p7); ++ subframe_buffer->ul_config_req = 0; ++ ++ } ++ //if(subframe_buffer->hi_dci0_req != 0) ++ //deallocate_nfapi_hi_dci0_request(subframe_buffer->hi_dci0_req, pnf_p7); ++ if(subframe_buffer->lbt_dl_config_req != 0) ++ { ++ deallocate_nfapi_lbt_dl_config_request(subframe_buffer->lbt_dl_config_req, pnf_p7); ++ subframe_buffer->lbt_dl_config_req = 0; ++ } ++ } // sfn_sf match ++ ++ if (subframe_buffer->dl_config_req == 0 && subframe_buffer->tx_req == 0 && subframe_buffer->ul_config_req == 0 && subframe_buffer->lbt_dl_config_req == 0) ++ { ++ memset(&(pnf_p7->subframe_buffer[buffer_index]), 0, sizeof(nfapi_pnf_p7_subframe_buffer_t)); ++ pnf_p7->subframe_buffer[buffer_index].sfn_sf = -1; + } + ++ //printf("pnf_p7->_public.timing_info_mode_periodic:%d pnf_p7->timing_info_period_counter:%d pnf_p7->_public.timing_info_period:%d\n", pnf_p7->_public.timing_info_mode_periodic, pnf_p7->timing_info_period_counter, pnf_p7->_public.timing_info_period); ++ //printf("pnf_p7->_public.timing_info_mode_aperiodic:%d pnf_p7->timing_info_aperiodic_send:%d\n", pnf_p7->_public.timing_info_mode_aperiodic, pnf_p7->timing_info_aperiodic_send); ++ //printf("pnf_p7->timing_info_ms_counter:%d\n", pnf_p7->timing_info_ms_counter); ++ + // send the periodic timing info if configured + if(pnf_p7->_public.timing_info_mode_periodic && (pnf_p7->timing_info_period_counter++) == pnf_p7->_public.timing_info_period) + { +@@ -678,14 +829,15 @@ int pnf_p7_subframe_ind(pnf_p7_t* pnf_p7, uint16_t phy_id, uint16_t sfn_sf) + } + else + { +- send_dummy_subframe(pnf_p7, sfn_sf); ++ //send_dummy_subframe(pnf_p7, sfn_sf_tx); + } + + ++ //printf("pnf_p7->tick:%d\n", pnf_p7->tick); + if(pnf_p7->tick == 1000) + { + +- NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF P7:%d] DL:(%d/%d) UL:(%d/%d) HI:(%d/%d) TX:(%d/%d)\n", pnf_p7->_public.phy_id, ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF P7:%d] (ONTIME/LATE) DL:(%d/%d) UL:(%d/%d) HI:(%d/%d) TX:(%d/%d)\n", pnf_p7->_public.phy_id, + pnf_p7->stats.dl_conf_ontime, pnf_p7->stats.dl_conf_late, + pnf_p7->stats.ul_conf_ontime, pnf_p7->stats.ul_conf_late, + pnf_p7->stats.hi_dci0_ontime, pnf_p7->stats.hi_dci0_late, +@@ -694,6 +846,7 @@ int pnf_p7_subframe_ind(pnf_p7_t* pnf_p7, uint16_t phy_id, uint16_t sfn_sf) + memset(&pnf_p7->stats, 0, sizeof(pnf_p7->stats)); + } + pnf_p7->tick++; ++#endif + + if(pthread_mutex_unlock(&(pnf_p7->mutex)) != 0) + { +@@ -724,7 +877,7 @@ uint8_t is_p7_request_in_window(uint16_t sfnsf, const char* name, pnf_p7_t* phy) + if(recv_sfn_sf_dec > ((current_sfn_sf_dec + timing_window) % NFAPI_MAX_SFNSFDEC)) + { + // out of window +- //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] %s is late %d (with wrap)\n", current_sfn_sf_dec, name, recv_sfn_sf_dec); ++ NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] %s is late %d (with wrap)\n", current_sfn_sf_dec, name, recv_sfn_sf_dec); + } + else + { +@@ -736,7 +889,7 @@ uint8_t is_p7_request_in_window(uint16_t sfnsf, const char* name, pnf_p7_t* phy) + else + { + // too late +- //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] %s is in late %d (%d)\n", current_sfn_sf_dec, name, recv_sfn_sf_dec, (current_sfn_sf_dec - recv_sfn_sf_dec)); ++ NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] %s is in late %d (delta:%d)\n", current_sfn_sf_dec, name, recv_sfn_sf_dec, (current_sfn_sf_dec - recv_sfn_sf_dec)); + } + + } +@@ -751,8 +904,8 @@ uint8_t is_p7_request_in_window(uint16_t sfnsf, const char* name, pnf_p7_t* phy) + } + else + { +- // to far in the future +- //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] %s is out of window %d (%d) [%d]\n", current_sfn_sf_dec, name, recv_sfn_sf_dec, (recv_sfn_sf_dec - current_sfn_sf_dec), timing_window); ++ // too far in the future ++ NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] %s is out of window %d (delta:%d) [max:%d]\n", current_sfn_sf_dec, name, recv_sfn_sf_dec, (recv_sfn_sf_dec - current_sfn_sf_dec), timing_window); + } + + } +@@ -785,15 +938,35 @@ void pnf_handle_dl_config_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_ + return; + } + +- if(is_p7_request_in_window(req->sfn_sf, "dl_config_request", pnf_p7)) +- { +- uint32_t sfn_sf_dec = NFAPI_SFNSF2DEC(req->sfn_sf); +- uint8_t buffer_index = sfn_sf_dec % pnf_p7->_public.subframe_buffer_size; ++ if ( ++ 0 && ++ (NFAPI_SFNSF2DEC(req->sfn_sf) % 100 ==0 || ++ NFAPI_SFNSF2DEC(req->sfn_sf) % 105 ==0 ++ ) ++ ) ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "DL_CONFIG.req sfn_sf:%d pdcch:%u dci:%u pdu:%u pdsch_rnti:%u pcfich:%u\n", ++ NFAPI_SFNSF2DEC(req->sfn_sf), ++ req->dl_config_request_body.number_pdcch_ofdm_symbols, ++ req->dl_config_request_body.number_dci, ++ req->dl_config_request_body.number_pdu, ++ req->dl_config_request_body.number_pdsch_rnti, ++ req->dl_config_request_body.transmission_power_pcfich ++ ); ++ ++ if(is_p7_request_in_window(req->sfn_sf, "dl_config_request", pnf_p7)) ++ { ++ uint32_t sfn_sf_dec = NFAPI_SFNSF2DEC(req->sfn_sf); ++ uint8_t buffer_index = sfn_sf_dec % pnf_p7->_public.subframe_buffer_size; ++ ++ struct timespec t; ++ clock_gettime(CLOCK_MONOTONIC, &t); ++ ++ NFAPI_TRACE(NFAPI_TRACE_INFO,"%s() %ld.%09ld POPULATE DL_CONFIG_REQ sfn_sf:%d buffer_index:%d\n", __FUNCTION__, t.tv_sec, t.tv_nsec, sfn_sf_dec, buffer_index); + + // if there is already an dl_config_req make sure we free it. + if(pnf_p7->subframe_buffer[buffer_index].dl_config_req != 0) + { +- NFAPI_TRACE(NFAPI_TRACE_NOTE, "HERE HERE HERE\n"); ++ NFAPI_TRACE(NFAPI_TRACE_NOTE, "%s() is_p7_request_in_window()=TRUE buffer_index occupied - free it first sfn_sf:%d buffer_index:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), buffer_index); + //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] Freeing dl_config_req at index %d (%d/%d)", + // pMyPhyInfo->sfnSf, bufferIdx, + // SFNSF2SFN(dreq->sfn_sf), SFNSF2SF(dreq->sfn_sf)); +@@ -860,6 +1033,11 @@ void pnf_handle_ul_config_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_ + uint32_t sfn_sf_dec = NFAPI_SFNSF2DEC(req->sfn_sf); + uint8_t buffer_index = sfn_sf_dec % pnf_p7->_public.subframe_buffer_size; + ++ struct timespec t; ++ clock_gettime(CLOCK_MONOTONIC, &t); ++ ++ NFAPI_TRACE(NFAPI_TRACE_INFO,"%s() %ld.%09ld POPULATE UL_CONFIG_REQ sfn_sf:%d buffer_index:%d\n", __FUNCTION__, t.tv_sec, t.tv_nsec, sfn_sf_dec, buffer_index); ++ + if(pnf_p7->subframe_buffer[buffer_index].ul_config_req != 0) + { + //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] Freeing ul_config_req at index %d (%d/%d)", +@@ -876,7 +1054,7 @@ void pnf_handle_ul_config_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_ + } + else + { +- //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] NOT storing ul_config_req SFN/SF %d/%d\n", pMyPhyInfo->sfnSf, SFNSF2SFN(req->sfn_sf), SFNSF2SF(req->sfn_sf)); ++ NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] NOT storing ul_config_req OUTSIDE OF TRANSMIT BUFFER WINDOW SFN/SF %d\n", NFAPI_SFNSF2DEC(pnf_p7->sfn_sf), NFAPI_SFNSF2DEC(req->sfn_sf)); + deallocate_nfapi_ul_config_request(req, pnf_p7); + + if(pnf_p7->_public.timing_info_mode_aperiodic) +@@ -994,6 +1172,16 @@ void pnf_handle_tx_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7) + uint32_t sfn_sf_dec = NFAPI_SFNSF2DEC(req->sfn_sf); + uint8_t buffer_index = sfn_sf_dec % pnf_p7->_public.subframe_buffer_size; + ++ struct timespec t; ++ clock_gettime(CLOCK_MONOTONIC, &t); ++ ++ NFAPI_TRACE(NFAPI_TRACE_INFO,"%s() %ld.%09ld POPULATE TX_REQ sfn_sf:%d buffer_index:%d\n", __FUNCTION__, t.tv_sec, t.tv_nsec, sfn_sf_dec, buffer_index); ++ ++ if (0 && NFAPI_SFNSF2DEC(req->sfn_sf)%100==0) NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() TX_REQ.req sfn_sf:%d pdus:%d - TX_REQ is within window\n", ++ __FUNCTION__, ++ NFAPI_SFNSF2DEC(req->sfn_sf), ++ req->tx_request_body.number_of_pdus); ++ + if(pnf_p7->subframe_buffer[buffer_index].tx_req != 0) + { + //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] Freeing tx_req at index %d (%d/%d)", +@@ -1010,6 +1198,8 @@ void pnf_handle_tx_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7) + } + else + { ++ NFAPI_TRACE(NFAPI_TRACE_INFO,"%s() TX_REQUEST Request is outside of window REQ:SFN_SF:%d CURR:SFN_SF:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), NFAPI_SFNSF2DEC(pnf_p7->sfn_sf)); ++ + deallocate_nfapi_tx_request(req, pnf_p7); + + if(pnf_p7->_public.timing_info_mode_aperiodic) +@@ -1126,12 +1316,27 @@ uint32_t calculate_t2(uint32_t now_time_hr, uint16_t sfn_sf, uint32_t sf_start_t + uint32_t sf_time_us = get_sf_time(now_time_hr, sf_start_time_hr); + uint32_t t2 = (NFAPI_SFNSF2DEC(sfn_sf) * 1000) + sf_time_us; + ++ if (0) ++ { ++ static uint32_t prev_t2 = 0; ++ ++ NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s(now_time_hr:%u sfn_sf:%d sf_start_time_Hr:%u) sf_time_us:%u t2:%u prev_t2:%u diff:%u\n", ++ __FUNCTION__, ++ now_time_hr, NFAPI_SFNSF2DEC(sfn_sf), sf_start_time_hr, ++ sf_time_us, ++ t2, ++ prev_t2, ++ t2-prev_t2); ++ ++ prev_t2 = t2; ++ } ++ + return t2; + } + + uint32_t calculate_t3(uint16_t sfn_sf, uint32_t sf_start_time_hr) + { +- uint32_t now_time_hr = get_current_time_hr(); ++ uint32_t now_time_hr = pnf_get_current_time_hr(); + + uint32_t sf_time_us = get_sf_time(now_time_hr, sf_start_time_hr); + +@@ -1391,6 +1596,8 @@ void pnf_nfapi_p7_read_dispatch_message(pnf_p7_t* pnf_p7, uint32_t now_hr_time) + // read the segment + recvfrom_result = recvfrom(pnf_p7->p7_sock, pnf_p7->rx_message_buffer, header.message_length, MSG_DONTWAIT, (struct sockaddr*)&remote_addr, &remote_addr_size); + ++ now_hr_time = pnf_get_current_time_hr(); //DJP - moved to here - get closer timestamp??? ++ + if(recvfrom_result > 0) + { + pnf_handle_p7_message(pnf_p7->rx_message_buffer, recvfrom_result, pnf_p7, now_hr_time); +@@ -1417,7 +1624,10 @@ void pnf_nfapi_p7_read_dispatch_message(pnf_p7_t* pnf_p7, uint32_t now_hr_time) + + // need to update the time as we would only use the value from the + // select +- now_hr_time = get_current_time_hr(); ++#if 0 ++// DJP - why do this here and not on return from recv??? ++ now_hr_time = pnf_get_current_time_hr(); ++#endif + } + while(recvfrom_result > 0); + } +@@ -1512,7 +1722,7 @@ int pnf_p7_message_pump(pnf_p7_t* pnf_p7) + + selectRetval = select(pnf_p7->p7_sock+1, &rfds, NULL, NULL, &timeout); + +- uint32_t now_hr_time = get_current_time_hr(); ++ uint32_t now_hr_time = pnf_get_current_time_hr(); + + if(selectRetval == 0) + { +diff --git a/pnf_sim/src/main.cpp b/pnf_sim/src/main.cpp +index 38767d8..e2622cf 100644 +--- a/pnf_sim/src/main.cpp ++++ b/pnf_sim/src/main.cpp +@@ -1124,16 +1124,18 @@ int fapi_rx_ulsch_ind(fapi_t* fapi, fapi_rx_ulsch_ind_t* ind) + rx_ind.header.phy_id = data->p7_config->phy_id; + rx_ind.sfn_sf = ind->sfn_sf; + +- if(((pnf_info*)(data->config->user_data))->wireshark_test_mode) ++ if(1)//((pnf_info*)(data->config->user_data))->wireshark_test_mode) + { + rx_ind.rx_indication_body.tl.tag = NFAPI_RX_INDICATION_BODY_TAG; +- rx_ind.rx_indication_body.number_of_pdus = 8; ++ rx_ind.rx_indication_body.number_of_pdus = 1; + + uint8_t rx_data[1024]; + + nfapi_rx_indication_pdu_t pdus[rx_ind.rx_indication_body.number_of_pdus]; + memset(&pdus, 0, sizeof(pdus)); + ++ strcpy((char*)rx_data, (char*)"123456789"); ++ + for(int i = 0; i < rx_ind.rx_indication_body.number_of_pdus;++i) + { + +@@ -1142,13 +1144,13 @@ int fapi_rx_ulsch_ind(fapi_t* fapi, fapi_rx_ulsch_ind_t* ind) + pdus[i].rx_ue_information.rnti = rand_range(1, 65535); + + pdus[i].rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG; +- pdus[i].rx_indication_rel8.length = rand_range(0, 1024); +- pdus[i].rx_indication_rel8.offset = 1; ++ pdus[i].rx_indication_rel8.length = 10;//rand_range(0, 1024); ++ pdus[i].rx_indication_rel8.offset = 0;//djp - 1; + pdus[i].rx_indication_rel8.ul_cqi = rand_range(0, 255); + pdus[i].rx_indication_rel8.timing_advance = rand_range(0, 63); + +- pdus[i].rx_indication_rel9.tl.tag = NFAPI_RX_INDICATION_REL9_TAG; +- pdus[i].rx_indication_rel9.timing_advance_r9 = rand_range(0, 7690); ++ //pdus[i].rx_indication_rel9.tl.tag = NFAPI_RX_INDICATION_REL9_TAG; ++ //pdus[i].rx_indication_rel9.timing_advance_r9 = rand_range(0, 7690); + + pdus[i].data = &rx_data[0]; + } +diff --git a/vnf/inc/vnf_p7.h b/vnf/inc/vnf_p7.h +index ab9a335..fc2ab4e 100644 +--- a/vnf/inc/vnf_p7.h ++++ b/vnf/inc/vnf_p7.h +@@ -116,7 +116,8 @@ typedef struct { + + } vnf_p7_t; + +-uint32_t get_current_time_hr(); ++uint32_t vnf_get_current_time_hr(void); ++ + uint16_t increment_sfn_sf(uint16_t sfn_sf); + int vnf_sync(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* p7_info); + int send_mac_subframe_indications(vnf_p7_t* config); +diff --git a/vnf/public_inc/nfapi_vnf_interface.h b/vnf/public_inc/nfapi_vnf_interface.h +index 6659e5d..4629013 100644 +--- a/vnf/public_inc/nfapi_vnf_interface.h ++++ b/vnf/public_inc/nfapi_vnf_interface.h +@@ -450,7 +450,7 @@ typedef struct nfapi_vnf_config + /*! Creates and initialise the vnf config structure before use + * \return A pointer to a vnf config structure + */ +-nfapi_vnf_config_t* nfapi_vnf_config_create(); ++nfapi_vnf_config_t* nfapi_vnf_config_create(void); + + /*! Delete an vnf config + */ +@@ -864,7 +864,7 @@ typedef struct nfapi_vnf_p7_config + /*! Creates and initializes the nfapi_vnf_p7_config structure before use + * \return A pointer to an allocated vnf p7 configuration + */ +-nfapi_vnf_p7_config_t* nfapi_vnf_p7_config_create(); ++nfapi_vnf_p7_config_t* nfapi_vnf_p7_config_create(void); + + /*! Cleanup and delete nfapi_vnf_p7_config structure + * \param config A pointer to an vnf p7 configuration structure +diff --git a/vnf/src/vnf.c b/vnf/src/vnf.c +index fea3cf7..6800ee2 100644 +--- a/vnf/src/vnf.c ++++ b/vnf/src/vnf.c +@@ -82,11 +82,18 @@ void nfapi_vnf_pnf_list_add(nfapi_vnf_config_t* config, nfapi_vnf_pnf_info_t* no + + nfapi_vnf_pnf_info_t* nfapi_vnf_pnf_list_find(nfapi_vnf_config_t* config, int p5_idx) + { ++ NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s : config->pnf_list:%p\n", __FUNCTION__, config->pnf_list); ++ + nfapi_vnf_pnf_info_t* curr = config->pnf_list; + while(curr != 0) + { + if(curr->p5_idx == p5_idx) ++ { ++ NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s : curr->p5_idx:%d p5_idx:%d\n", __FUNCTION__, curr->p5_idx, p5_idx); + return curr; ++ } ++ ++ NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s : curr->next:%p\n", __FUNCTION__, curr->next); + + curr = curr->next; + } +diff --git a/vnf/src/vnf_interface.c b/vnf/src/vnf_interface.c +index e559730..0aba0a2 100644 +--- a/vnf/src/vnf_interface.c ++++ b/vnf/src/vnf_interface.c +@@ -342,6 +342,7 @@ int nfapi_vnf_start(nfapi_vnf_config_t* config) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF connection (fd:%d) accepted from %s:%d \n", p5Sock, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + nfapi_vnf_pnf_info_t* pnf = (nfapi_vnf_pnf_info_t*)malloc(sizeof(nfapi_vnf_pnf_info_t)); ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "MALLOC nfapi_vnf_pnf_info_t for pnf_list pnf:%p\n", pnf); + memset(pnf, 0, sizeof(nfapi_vnf_pnf_info_t)); + pnf->p5_sock = p5Sock; + pnf->p5_idx = p5_idx++; +@@ -663,7 +664,7 @@ int nfapi_vnf_allocate_phy(nfapi_vnf_config_t* config, int p5_idx, uint16_t* phy + info->p5_idx = p5_idx; + info->phy_id = vnf->next_phy_id++; + +- info->timing_window = 10; ++ info->timing_window = 30; // This seems to override what gets set by the user - why??? + info->timing_info_mode = 0x03; + info->timing_info_period = 128; + +diff --git a/vnf/src/vnf_p7.c b/vnf/src/vnf_p7.c +index 8630385..1304176 100644 +--- a/vnf/src/vnf_p7.c ++++ b/vnf/src/vnf_p7.c +@@ -15,6 +15,8 @@ + */ + + ++#include ++ + #include + #include + #include +@@ -159,7 +161,7 @@ vnf_p7_rx_message_t* vnf_p7_rx_reassembly_queue_add_segment(vnf_p7_t* vnf_p7, vn + msg->sequence_number = sequence_number; + msg->num_segments_expected = m ? 255 : segment_number + 1; + msg->num_segments_received = 1; +- msg->rx_hr_time = get_current_time_hr(); ++ msg->rx_hr_time = vnf_get_current_time_hr(); + + msg->segments[segment_number].buffer = (uint8_t*)vnf_p7_malloc(vnf_p7, data_len); + memcpy(msg->segments[segment_number].buffer, data, data_len); +@@ -216,7 +218,7 @@ void vnf_p7_rx_reassembly_queue_remove_old_msgs(vnf_p7_t* vnf_p7, vnf_p7_rx_reas + vnf_p7_rx_message_t* iterator = queue->msg_queue; + vnf_p7_rx_message_t* previous = 0; + +- uint32_t rx_hr_time = get_current_time_hr(); ++ uint32_t rx_hr_time = vnf_get_current_time_hr(); + + while(iterator != 0) + { +@@ -254,7 +256,7 @@ void vnf_p7_rx_reassembly_queue_remove_old_msgs(vnf_p7_t* vnf_p7, vnf_p7_rx_reas + } + } + +-uint32_t get_current_time_hr() ++uint32_t vnf_get_current_time_hr() + { + struct timeval now; + (void)gettimeofday(&now, NULL); +@@ -297,7 +299,7 @@ struct timespec timespec_delta(struct timespec start, struct timespec end) + return temp; + } + +-uint32_t get_sf_time(uint32_t now_hr, uint32_t sf_start_hr) ++static uint32_t get_sf_time(uint32_t now_hr, uint32_t sf_start_hr) + { + if(now_hr < sf_start_hr) + { +@@ -321,7 +323,7 @@ uint32_t get_sf_time(uint32_t now_hr, uint32_t sf_start_hr) + + uint32_t calculate_t1(uint16_t sfn_sf, uint32_t sf_start_time_hr) + { +- uint32_t now_time_hr = get_current_time_hr(); ++ uint32_t now_time_hr = vnf_get_current_time_hr(); + + uint32_t sf_time_us = get_sf_time(now_time_hr, sf_start_time_hr); + +@@ -344,7 +346,7 @@ uint32_t calculate_t4(uint32_t now_time_hr, uint16_t sfn_sf, uint32_t sf_start_t + + uint32_t calculate_transmit_timestamp(uint16_t sfn_sf, uint32_t sf_start_time_hr) + { +- uint32_t now_time_hr = get_current_time_hr(); ++ uint32_t now_time_hr = vnf_get_current_time_hr(); + + uint32_t sf_time_us = get_sf_time(now_time_hr, sf_start_time_hr); + +@@ -410,6 +412,8 @@ int vnf_p7_pack_and_send_p7_msg(vnf_p7_t* vnf_p7, nfapi_p7_message_header_t* hea + + int len = nfapi_p7_message_pack(header, buffer, sizeof(buffer), &vnf_p7->_public.codec_config); + ++ //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() phy_id:%d nfapi_p7_message_pack()=len=%d vnf_p7->_public.segment_size:%u\n", __FUNCTION__, header->phy_id, len, vnf_p7->_public.segment_size); ++ + if(len < 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() failed to pack p7 message phy_id:%d\n", __FUNCTION__, header->phy_id); +@@ -429,6 +433,7 @@ int vnf_p7_pack_and_send_p7_msg(vnf_p7_t* vnf_p7, nfapi_p7_message_header_t* hea + int segment = 0; + int offset = NFAPI_P7_HEADER_LENGTH; + uint8_t tx_buffer[vnf_p7->_public.segment_size]; ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() MORE THAN ONE SEGMENT phy_id:%d nfapi_p7_message_pack()=len=%d vnf_p7->_public.segment_size:%u\n", __FUNCTION__, header->phy_id, len, vnf_p7->_public.segment_size); + for(segment = 0; segment < segment_count; ++segment) + { + uint8_t last = 0; +@@ -851,7 +856,7 @@ void vnf_handle_p7_vendor_extension(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vn + + void vnf_handle_ul_node_sync(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) + { +- uint32_t now_time_hr = get_current_time_hr(); ++ uint32_t now_time_hr = vnf_get_current_time_hr(); + + if (pRecvMsg == NULL || vnf_p7 == NULL) + { +@@ -871,7 +876,7 @@ void vnf_handle_ul_node_sync(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) + nfapi_vnf_p7_connection_info_t* phy = vnf_p7_connection_info_list_find(vnf_p7, ind.header.phy_id); + uint32_t t4 = calculate_t4(now_time_hr, phy->sfn_sf, vnf_p7->sf_start_time_hr); + +- uint32_t tx_2_rx = t4 - ind.t1; ++ uint32_t tx_2_rx = t4>ind.t1 ? t4 - ind.t1 : t4 + NFAPI_MAX_SFNSFDEC - ind.t1 ; + uint32_t pnf_proc_time = ind.t3 - ind.t2; + + // divide by 2 using shift operator +@@ -881,7 +886,7 @@ void vnf_handle_ul_node_sync(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) + { + phy->latency[phy->min_sync_cycle_count] = latency; + +- NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%d/%d) PNF to VNF !sync phy_id:%d (t1/2/3/4:%8u, %8u, %8u, %8u) txrx:%4u procT:%3u latency(us):%4d\n", ++ NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%4d/%d) PNF to VNF !sync phy_id:%d (t1/2/3/4:%8u, %8u, %8u, %8u) txrx:%4u procT:%3u latency(us):%4d\n", + NFAPI_SFNSF2SFN(phy->sfn_sf), NFAPI_SFNSF2SF(phy->sfn_sf), ind.header.phy_id, ind.t1, ind.t2, ind.t3, t4, + tx_2_rx, pnf_proc_time, latency); + } +@@ -923,15 +928,27 @@ void vnf_handle_ul_node_sync(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) + + if(1) + { +- NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%4d/%1d) PNF to VNF phy_id:%2d (t1/2/3/4:%8u, %8u, %8u, %8u) txrx:%4u procT:%3u latency(us):%4d offset(us):%8d filtered(us):%8d wrap[t1:%u t2:%u]\n", +- NFAPI_SFNSF2SFN(phy->sfn_sf), NFAPI_SFNSF2SF(phy->sfn_sf), ind.header.phy_id, ++ struct timespec ts; ++ clock_gettime(CLOCK_MONOTONIC, &ts); ++ ++ NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%4d/%1d) %d.%d PNF to VNF phy_id:%2d (t1/2/3/4:%8u, %8u, %8u, %8u) txrx:%4u procT:%3u latency(us):%4d(avg:%4d) offset(us):%8d filtered(us):%8d wrap[t1:%u t2:%u]\n", ++ NFAPI_SFNSF2SFN(phy->sfn_sf), NFAPI_SFNSF2SF(phy->sfn_sf), ts.tv_sec, ts.tv_nsec, ind.header.phy_id, + ind.t1, ind.t2, ind.t3, t4, +- tx_2_rx, pnf_proc_time, latency, phy->sf_offset, phy->sf_offset_filtered, ++ tx_2_rx, pnf_proc_time, latency, phy->average_latency, phy->sf_offset, phy->sf_offset_filtered, + (ind.t1previous_t1), (ind.t2previous_t2)); + } + + } + ++ if (phy->filtered_adjust && (phy->sf_offset_filtered > 1e6 || phy->sf_offset_filtered < -1e6)) ++ { ++ phy->filtered_adjust = 0; ++ phy->zero_count=0; ++ phy->min_sync_cycle_count = 2; ++ phy->in_sync = 0; ++ NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s - ADJUST TOO BAD - go out of filtered phy->sf_offset_filtered:%d\n", __FUNCTION__, phy->sf_offset_filtered); ++ } ++ + if(phy->min_sync_cycle_count) + phy->min_sync_cycle_count--; + +@@ -954,7 +971,6 @@ void vnf_handle_ul_node_sync(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) + phy->sf_offset = ind.t2 - (ind.t1 - phy->average_latency); + + sfn_sf_dec += (phy->sf_offset / 1000); +- + } + else + { +@@ -976,12 +992,11 @@ void vnf_handle_ul_node_sync(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) + { + phy->adjustment = NFAPI_SFNSF2DEC(new_sfn_sf) - NFAPI_SFNSF2DEC(curr_sfn_sf); + +- //NFAPI_TRACE(NFAPI_TRACE_NOTE, "PNF to VNF phy_id:%d adjustment%d\n", ind.header.phy_id, phy->adjustment); ++ NFAPI_TRACE(NFAPI_TRACE_NOTE, "PNF to VNF phy_id:%d adjustment%d phy->previous_sf_offset_filtered:%d phy->previous_sf_offset_filtered:%d phy->sf_offset_trend:%d\n", ind.header.phy_id, phy->adjustment, phy->previous_sf_offset_filtered, phy->previous_sf_offset_filtered, phy->sf_offset_trend); + + phy->previous_t1 = 0; + phy->previous_t2 = 0; + +- + if(phy->previous_sf_offset_filtered > 0) + { + if( phy->sf_offset_filtered > phy->previous_sf_offset_filtered) +@@ -1083,9 +1098,14 @@ void vnf_handle_ul_node_sync(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) + + if(phy->insync_minor_adjustment != 0) + { +- NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%d/%d) VNF phy_id:%d Apply minor insync adjustment %dus for %d suframes (sf_offset_filtered:%d) %d %d %d\n", ++ NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%4d/%d) VNF phy_id:%d Apply minor insync adjustment %dus for %d subframes (sf_offset_filtered:%d) %d %d %d NEW:%d CURR:%d adjustment:%d\n", + NFAPI_SFNSF2SFN(phy->sfn_sf), NFAPI_SFNSF2SF(phy->sfn_sf), ind.header.phy_id, +- phy->insync_minor_adjustment, phy->insync_minor_adjustment_duration, phy->sf_offset_filtered, insync_minor_adjustment_1, insync_minor_adjustment_2, phy->sf_offset_trend); ++ phy->insync_minor_adjustment, phy->insync_minor_adjustment_duration, ++ phy->sf_offset_filtered, ++ insync_minor_adjustment_1, insync_minor_adjustment_2, phy->sf_offset_trend, ++ NFAPI_SFNSF2DEC(new_sfn_sf), ++ NFAPI_SFNSF2DEC(curr_sfn_sf), ++ phy->adjustment); + } + } + } +@@ -1121,10 +1141,13 @@ void vnf_handle_ul_node_sync(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) + // out of sync? + } + +- NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%d/%d) VNF phy_id:%d Apply minor insync adjustment %dus for %d suframes (adjusment:%d sf_offset_filtered:%d) %d %d %d\n", ++ NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%4d/%d) VNF phy_id:%d Apply minor insync adjustment %dus for %d subframes (adjustment:%d sf_offset_filtered:%d) %d %d %d NEW:%d CURR:%d adj:%d\n", + NFAPI_SFNSF2SFN(phy->sfn_sf), NFAPI_SFNSF2SF(phy->sfn_sf), ind.header.phy_id, + phy->insync_minor_adjustment, phy->insync_minor_adjustment_duration, phy->adjustment, phy->sf_offset_filtered, +- insync_minor_adjustment_1, insync_minor_adjustment_2, phy->sf_offset_trend); ++ insync_minor_adjustment_1, insync_minor_adjustment_2, phy->sf_offset_trend, ++ NFAPI_SFNSF2DEC(new_sfn_sf), ++ NFAPI_SFNSF2DEC(curr_sfn_sf), ++ phy->adjustment); + + } + else if(phy->adjustment < 0) +@@ -1151,7 +1174,7 @@ void vnf_handle_ul_node_sync(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) + // out of sync? + } + +- NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%d/%d) VNF phy_id:%d Apply minor insync adjustment %dus for %d suframes (adjusment:%d sf_offset_filtered:%d) %d %d %d\n", ++ NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%d/%d) VNF phy_id:%d Apply minor insync adjustment %dus for %d subframes (adjustment:%d sf_offset_filtered:%d) %d %d %d\n", + NFAPI_SFNSF2SFN(phy->sfn_sf), NFAPI_SFNSF2SF(phy->sfn_sf), ind.header.phy_id, + phy->insync_minor_adjustment, phy->insync_minor_adjustment_duration, phy->adjustment, phy->sf_offset_filtered, + insync_minor_adjustment_1, insync_minor_adjustment_2, phy->sf_offset_trend); +@@ -1219,7 +1242,16 @@ void vnf_handle_timing_info(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) + return; + } + +- // todo : how to use this? ++ if (vnf_p7 && vnf_p7->p7_connections) ++ { ++ int16_t vnf_pnf_sfnsf_delta = NFAPI_SFNSF2DEC(vnf_p7->p7_connections[0].sfn_sf) - NFAPI_SFNSF2DEC(ind.last_sfn_sf); ++ ++ //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() PNF:SFN/SF:%d VNF:SFN/SF:%d deltaSFNSF:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind.last_sfn_sf), NFAPI_SFNSF2DEC(vnf_p7->p7_connections[0].sfn_sf), vnf_pnf_sfnsf_delta); ++ if (vnf_pnf_sfnsf_delta>1 || vnf_pnf_sfnsf_delta < -1) ++ { ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() LARGE SFN/SF DELTA between PNF and VNF delta:%d VNF:%d PNF:%d\n\n\n\n\n\n\n\n\n", __FUNCTION__, vnf_pnf_sfnsf_delta, NFAPI_SFNSF2DEC(vnf_p7->p7_connections[0].sfn_sf), NFAPI_SFNSF2DEC(ind.last_sfn_sf)); ++ } ++ } + } + + void vnf_dispatch_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +diff --git a/vnf/src/vnf_p7_interface.c b/vnf/src/vnf_p7_interface.c +index ab4f00c..a35d8e3 100644 +--- a/vnf/src/vnf_p7_interface.c ++++ b/vnf/src/vnf_p7_interface.c +@@ -142,6 +142,7 @@ int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config) + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 bind succeeded...\n"); + + ++ //struct timespec original_pselect_timeout; + struct timespec pselect_timeout; + pselect_timeout.tv_sec = 0; + pselect_timeout.tv_nsec = 1000000; // ns in a 1 us +@@ -157,13 +158,13 @@ int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config) + + struct timespec sf_duration; + sf_duration.tv_sec = 0; +- sf_duration.tv_nsec = 1000000; // ns in a 1 us ++ sf_duration.tv_nsec = 1e6; // We want 1ms pause + + struct timespec sf_start; + clock_gettime(CLOCK_MONOTONIC, &sf_start); + long millisecond = sf_start.tv_nsec / 1e6; + sf_start = timespec_add(sf_start, sf_duration); +- //NFAPI_TRACE(NFAPI_TRACE_INFO, "next subframe will start at %d.%d\n", sf_start.tv_sec, sf_start.tv_nsec); ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "next subframe will start at %d.%d\n", sf_start.tv_sec, sf_start.tv_nsec); + + while(vnf_p7->terminate == 0) + { +@@ -181,6 +182,8 @@ int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config) + + if((last_millisecond == -1) || (millisecond == last_millisecond) || (millisecond == (last_millisecond + 1) % 1000) ) + { ++ //NFAPI_TRACE(NFAPI_TRACE_INFO, "pselect_start:%d.%d sf_start:%d.%d\n", pselect_start.tv_sec, pselect_start.tv_nsec, sf_start.tv_sec, sf_start.tv_nsec); ++ + + if((pselect_start.tv_sec > sf_start.tv_sec) || + ((pselect_start.tv_sec == sf_start.tv_sec) && (pselect_start.tv_nsec > sf_start.tv_nsec))) +@@ -196,16 +199,26 @@ int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config) + { + // still time before the end of the subframe wait + pselect_timeout = timespec_sub(sf_start, pselect_start); ++ ++#if 0 ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() sf_start:%d.%ld pselect_start:%d.%ld pseclect_timeout:%d.%ld\n", ++ __FUNCTION__, ++ sf_start.tv_sec, sf_start.tv_nsec, ++ pselect_start.tv_sec, pselect_start.tv_nsec, ++ pselect_timeout.tv_sec, pselect_timeout.tv_nsec); ++#endif + } + ++//original_pselect_timeout = pselect_timeout; ++ + // detemine how long to sleep in ns before the start of the next 1ms + //pselect_timeout.tv_nsec = 1e6 - (pselect_start.tv_nsec % 1000000); + +- //uint8_t underun_possiable =0; ++ //uint8_t underrun_possible =0; + + // if we are not sleeping until the next milisecond due to the + // insycn minor adjment flag it so we don't consider it an error +- //uint8_t underun_possiable =0; ++ //uint8_t underrun_possible =0; + /* + { + nfapi_vnf_p7_connection_info_t* phy = vnf_p7->p7_connections; +@@ -222,7 +235,7 @@ int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config) + pselect_timeout.tv_nsec = pselect_timeout.tv_nsec - (phy->insync_minor_adjustment * 1000); + + +- //underun_possiable = 1; ++ //underrun_possible = 1; + } + else if(phy->insync_minor_adjustment < 0) + { +@@ -237,41 +250,98 @@ int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config) + */ + + ++//long wraps = pselect_timeout.tv_nsec % 1e9; ++ ++ + selectRetval = pselect(maxSock+1, &rfds, NULL, NULL, &pselect_timeout, NULL); + + clock_gettime(CLOCK_MONOTONIC, &pselect_stop); + ++ nfapi_vnf_p7_connection_info_t* phy = vnf_p7->p7_connections; ++ ++if (selectRetval==-1 && errno == 22) ++{ ++ NFAPI_TRACE(NFAPI_TRACE_ERROR, "INVAL: pselect_timeout:%d.%ld adj[dur:%d adj:%d], sf_dur:%d.%ld\n", ++ pselect_timeout.tv_sec, pselect_timeout.tv_nsec, ++ phy->insync_minor_adjustment_duration, phy->insync_minor_adjustment, ++ sf_duration.tv_sec, sf_duration.tv_nsec); ++} ++#if 0 ++ if (selectRetval != 0 || phy->insync_minor_adjustment_duration != 0) ++ NFAPI_TRACE(NFAPI_TRACE_NOTE, "pselect()=%d maxSock:%d vnf_p7->socket:%d pselect_timeout:%u.%u original_pselect_timeout:%u.%u\n", ++ selectRetval, maxSock, vnf_p7->socket, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, ++ original_pselect_timeout.tv_sec, original_pselect_timeout.tv_nsec); ++#endif ++ + if(selectRetval == 0) + { +- // calcualte the start of the next subframe ++ // calculate the start of the next subframe + sf_start = timespec_add(sf_start, sf_duration); + //NFAPI_TRACE(NFAPI_TRACE_INFO, "next subframe will start at %d.%d\n", sf_start.tv_sec, sf_start.tv_nsec); + +- nfapi_vnf_p7_connection_info_t* phy = vnf_p7->p7_connections; + if(phy && phy->in_sync && phy->insync_minor_adjustment != 0 && phy->insync_minor_adjustment_duration > 0) + { +- NFAPI_TRACE(NFAPI_TRACE_NOTE, "[VNF] Subframe minor adjustment %dus\n", phy->insync_minor_adjustment); ++ long insync_minor_adjustment_ns = (phy->insync_minor_adjustment * 1000); ++ ++ sf_start.tv_nsec -= insync_minor_adjustment_ns; ++ ++#if 1 ++ if (sf_start.tv_nsec > 1e9) ++ { ++ sf_start.tv_sec++; ++ sf_start.tv_nsec-=1e9; ++ } ++ else if (sf_start.tv_nsec < 0) ++ { ++ sf_start.tv_sec--; ++ sf_start.tv_nsec+=1e9; ++ } ++#else ++ //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[VNF] BEFORE adjustment - Subframe minor adjustment %dus sf_start.tv_nsec:%d\n", phy->insync_minor_adjustment, sf_start.tv_nsec); + if(phy->insync_minor_adjustment > 0) + { + // decrease the subframe duration a little +- sf_start.tv_nsec = sf_start.tv_nsec - (phy->insync_minor_adjustment * 1000); ++ if (sf_start.tv_nsec > insync_minor_adjustment_ns) ++ sf_start.tv_nsec -= insync_minor_adjustment_ns; ++ else ++ { ++ NFAPI_TRACE(NFAPI_TRACE_ERROR, "[VNF] Adjustment would make it negative sf:%d.%ld adjust:%ld\n\n\n", sf_start.tv_sec, sf_start.tv_nsec, insync_minor_adjustment_ns); ++ sf_start.tv_sec--; ++ sf_start.tv_nsec += 1e9 - insync_minor_adjustment_ns; ++ } + } + else if(phy->insync_minor_adjustment < 0) + { + // todo check we don't go below 0 + // increase the subframe duration a little +- sf_start.tv_nsec = sf_start.tv_nsec - (phy->insync_minor_adjustment * 1000); ++ sf_start.tv_nsec += insync_minor_adjustment_ns; ++ ++ if (sf_start.tv_nsec < 0) ++ { ++ NFAPI_TRACE(NFAPI_TRACE_ERROR, "[VNF] OVERFLOW %d.%ld\n\n\n\n", sf_start.tv_sec, sf_start.tv_nsec); ++ sf_start.tv_sec++; ++ sf_start.tv_nsec += 1e9; ++ } + } ++#endif + + //phy->insync_minor_adjustment = 0; +- phy->insync_minor_adjustment_duration--; ++ phy->insync_minor_adjustment_duration--; ++ ++ NFAPI_TRACE(NFAPI_TRACE_NOTE, "[VNF] AFTER adjustment - Subframe minor adjustment %dus sf_start.tv_nsec:%d duration:%u\n", ++ phy->insync_minor_adjustment, sf_start.tv_nsec, phy->insync_minor_adjustment_duration); ++ ++ if (phy->insync_minor_adjustment_duration==0) ++ { ++ phy->insync_minor_adjustment = 0; ++ } + } + /* + long pselect_stop_millisecond = pselect_stop.tv_nsec / 1e6; + if(millisecond == pselect_stop_millisecond) + { + // we have woke up in the same subframe +- if(underun_possiable == 0) ++ if(underrun_possible == 0) + NFAPI_TRACE(NFAPI_TRACE_WARN, "subframe pselect underrun %ld (%d.%d)\n", millisecond, pselect_stop.tv_sec, pselect_stop.tv_nsec); + } + else if(((millisecond + 1) % 1000) != pselect_stop_millisecond) +@@ -298,7 +368,7 @@ int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config) + + if(selectRetval == 0) + { +- vnf_p7->sf_start_time_hr = get_current_time_hr(); ++ vnf_p7->sf_start_time_hr = vnf_get_current_time_hr(); + + // pselect timed out + nfapi_vnf_p7_connection_info_t* curr = vnf_p7->p7_connections; +@@ -326,14 +396,18 @@ int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config) + else + { + // pselect error +- if(selectRetval == EINTR) ++ if(selectRetval == -1 && errno == EINTR) + { + // a sigal was received. + } + else + { +- NFAPI_TRACE(NFAPI_TRACE_INFO, "P7 select failed result %d errno %d timeout:%d.%d\n", selectRetval, errno, pselect_timeout.tv_sec, pselect_timeout.tv_nsec); ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "P7 select failed result %d errno %d timeout:%d.%d orginal:%d.%d last_ms:%ld ms:%ld\n", selectRetval, errno, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, last_millisecond, millisecond); + // should we exit now? ++ if (selectRetval == -1 && errno == 22) // invalid argument??? not sure about timeout duration ++ { ++ usleep(100000); ++ } + } + } + +@@ -360,10 +434,12 @@ int nfapi_vnf_p7_stop(nfapi_vnf_p7_config_t* config) + + int nfapi_vnf_p7_add_pnf(nfapi_vnf_p7_config_t* config, const char* pnf_p7_addr, int pnf_p7_port, int phy_id) + { +- NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(phy_id:%d pnf_addr:%s:%d)\n", __FUNCTION__, phy_id, pnf_p7_addr, pnf_p7_port); ++ NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(config:%p phy_id:%d pnf_addr:%s pnf_p7_port:%d)\n", __FUNCTION__, config, phy_id, pnf_p7_addr, pnf_p7_port); + + if(config == 0) +- return -1; ++ { ++ return -1; ++ } + + vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; + +@@ -411,6 +487,8 @@ int nfapi_vnf_p7_del_pnf(nfapi_vnf_p7_config_t* config, int phy_id) + } + int nfapi_vnf_p7_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_dl_config_request_t* req) + { ++ //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(config:%p req:%p)\n", __FUNCTION__, config, req); ++ + if(config == 0 || req == 0) + return -1; + +diff --git a/vnf_sim/src/mac.cpp b/vnf_sim/src/mac.cpp +index aa97f72..fa6f487 100644 +--- a/vnf_sim/src/mac.cpp ++++ b/vnf_sim/src/mac.cpp +@@ -743,7 +743,7 @@ extern "C" + { + cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.number_of_cc = 1; + cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = rand_range(0, 3); +- cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size = rand_range(0, 255); ++ cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[0] = rand_range(0, 255); + } + + cqi_ri_information.cqi_ri_information_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL13_TAG; +diff --git a/vnf_sim/src/main.cpp b/vnf_sim/src/main.cpp +index b79ac40..5dc7161 100644 +--- a/vnf_sim/src/main.cpp ++++ b/vnf_sim/src/main.cpp +@@ -428,6 +428,20 @@ void phy_deallocate_p7_vendor_ext(nfapi_p7_message_header_t* header) + free(header); + } + ++//static pthread_t vnf_start_pthread; ++static pthread_t vnf_p7_start_pthread; ++void* vnf_p7_start_thread(void *ptr) ++{ ++ printf("%s()\n", __FUNCTION__); ++ ++ //std::shared_ptr config = std::shared_ptr(ptr); ++ nfapi_vnf_p7_config_t *config = (nfapi_vnf_p7_config_t *)ptr; ++ ++ nfapi_vnf_p7_start(config); ++ ++ return 0; ++} ++ + void set_thread_priority(int priority) + { + //printf("%s(priority:%d)\n", __FUNCTION__, priority); +@@ -458,6 +472,8 @@ void set_thread_priority(int priority) + + void* vnf_p7_thread_start(void* ptr) + { ++ printf("%s()\n", __FUNCTION__); ++ + set_thread_priority(79); + + vnf_p7_info* p7_vnf = (vnf_p7_info*)ptr; +@@ -494,10 +510,10 @@ void* vnf_p7_thread_start(void* ptr) + p7_vnf->config->allocate_p7_vendor_ext = &phy_allocate_p7_vendor_ext; + p7_vnf->config->deallocate_p7_vendor_ext = &phy_deallocate_p7_vendor_ext; + +- nfapi_vnf_p7_start(p7_vnf->config.get()); ++ printf("[VNF] Creating VNF NFAPI start thread %s\n", __FUNCTION__); ++ pthread_create(&vnf_p7_start_pthread, NULL, &vnf_p7_start_thread, p7_vnf->config.get()); + + return 0; +- + } + + int pnf_connection_indication_cb(nfapi_vnf_config_t* config, int p5_idx) +diff --git a/wireshark/packet-nfapi.c b/wireshark/packet-nfapi.c +index da0edb0..7e0f23f 100755 +--- a/wireshark/packet-nfapi.c ++++ b/wireshark/packet-nfapi.c +@@ -1,6069 +1,12284 @@ +-/* ++/* packet-nfapi.c ++* Routines for Network Function Application Platform Interface (nFAPI) dissection + * Copyright 2017 Cisco Systems, Inc. + * +-* Licensed under the Apache License, Version 2.0 (the "License"); +-* you may not use this file except in compliance with the License. +-* You may obtain a copy of the License at ++* Wireshark - Network traffic analyzer ++* By Gerald Combs ++* Copyright 1998 Gerald Combs ++* ++* This program is free software; you can redistribute it and/or ++* modify it under the terms of the GNU General Public License ++* as published by the Free Software Foundation; either version 2 ++* of the License, or (at your option) any later version. ++* ++* This program 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 General Public License for more details. ++* ++* You should have received a copy of the GNU General Public License ++* along with this program; if not, write to the Free Software ++* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * +-* http://www.apache.org/licenses/LICENSE-2.0 ++* References: ++* SCF082.09.04 http://scf.io/en/documents/082_-_nFAPI_and_FAPI_specifications.php + * +-* Unless required by applicable law or agreed to in writing, software +-* distributed under the License is distributed on an "AS IS" BASIS, +-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-* See the License for the specific language governing permissions and +-* limitations under the License. + */ +- +- +-#include "config.h" +- +-#include +-#include +-#include +- +-#include +-#include +-#include +-#include +-#include +- ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++void proto_register_nfapi(void); ++void proto_reg_handoff_nfapi(void); ++ + #define NFAPI_HEADER_LENGTH 8 +-#define NFAPI_P7_HEADER_LENGTH 16 +- +-typedef int(*Decode_operation)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset); +- +-static const value_string nfapi_error_vals[] = { +- { 0x0, "MSG_OK" }, +- { 0x1, "MSG_INVALID_STATE" }, +- { 0x2, "MSG_INVALID_CONFIG" }, +- { 0x3, "SFN_OUT_OF_SYNC" }, +- { 0x4, "MSG_SUBFRAME_ERR" }, +- { 0x5, "MSG_BCH_MISSING" }, +- { 0x6, "MSG_BCH_MISSING" }, +- { 0x7, "MSG_HI_ERR" }, +- { 0x8, "MSG_TX_ERR" }, +- { 0, NULL }, +-}; +- +-static const value_string nfapi_p4_error_vals[] = { +- { 100, "MSG_OK" }, +- { 101, "MSG_INVALID_STATE" }, +- { 102, "MSG_INVALID_CONFIG" }, +- { 103, "MSG_RAT_NOT_SUPPORTED" }, +- { 200, "MSG_NMM_STOP_OK" }, +- { 201, "MSG_NMM_STOP_IGNORED" }, +- { 202, "MSG_NMM_STOP_INVALID_STATE" }, +- { 300, "MSG_PROCEDURE_COMPLETE" }, +- { 301, "MSG_PROCEDURE_STOPPED" }, +- { 302, "MSG_PARTIAL_RESULTS" }, +- { 303, "MSG_TIMEOUT" }, +- { 0, NULL }, +-}; +- +-static const value_string nfapi_rat_type_vals[] = { +- { 0, "LTE" }, +- { 1, "UTRAN" }, +- { 2, "GERAN" }, +- { 0, NULL }, +-}; +- +-typedef enum{ +- UN_ALIGNED_SYNCHRONIZATION = 0, +- INTERNAL_PNF_FRAME_ALIGNMENT, +- ABSOLUTE_TIME_ALIGNED_SYNCHRONIZATION +-} nfapi_sync_mode_e; +- +-static const value_string nfapi_sync_mode_vals[] = { +- { UN_ALIGNED_SYNCHRONIZATION, "UN-ALIGNED SYNCHRONIZATION" }, +- { INTERNAL_PNF_FRAME_ALIGNMENT, "INTERNAL PNF FRAME ALIGNMENT" }, +- { ABSOLUTE_TIME_ALIGNED_SYNCHRONIZATION, "ABSOLUTE TIME ALIGNED SYNCHRONIZATION" } +-}; +- +-typedef enum { +- NONE = 0, +- GPS, +- GLONASS, +- BEIDOU +-} location_mode_e; +- +-static const value_string location_mode_vals[] = { +- { NONE, "NONE" }, +- { GPS, "GPS" }, +- { GLONASS, "GLONASS" }, +- { BEIDOU, "BeiDou" }, +- { 0, NULL } +-}; +- +-static const value_string nfapi_uplink_rs_hopping_vals[] = { +- { 0, "RS_NO_HOPPING" }, +- { 1, "RS_GROUP_HOPPING" }, +- { 2, "RS_SEQUENCE_HOPPING" }, +- { 0, NULL } +-}; +- +-static const value_string nfapi_laa_carrier_type_vals[] = { +- { 0, "No multi carrier support" }, +- { 1, "Mode A1" }, +- { 2, "Mode A12" }, +- { 3, "Mode B1" }, +- { 4, "Mode B2" }, +- { 0, NULL } +-}; +- +-static const value_string nfapi_mutli_carrier_lbt_support_vals[] = { +- { 0, "Multi carrier Mode A1" }, +- { 1, "Multi carrier Mode A2" }, +- { 2, "Multi carrier Mode B1" }, +- { 3, "Multi carrier Mode B2" }, +- { 0, NULL } +-}; +- +-static const value_string nfapi_lbt_dl_req_pdu_type[] = { +- { 0, "LBT_PDSCH_REQ PDU" }, +- { 1, "LBT_DRS_REQ PDU" }, +- { 0, NULL } +-}; +- +- +-static const value_string nfapi_lbt_dl_ind_pdu_type[] = { +- { 0, "LBT_PDSCH_RSP PDU" }, +- { 1, "LBT_DRS_RSP PDU" }, +- +- { 0, NULL } +-}; +- +- +- +- +-/* These are definitions where data 0 & 1 represent/provide a string name*/ +- +-static const true_false_string true_false_strname = { +- "TRUE", +- "FALSE" +-}; +- +-static const true_false_string nfapi_csi_report_type_strname = { +- "Periodic", +- "Aperiodic", +-}; +- +-static const true_false_string nfapi_control_type_string_name = { +- "CQI/PMI", +- "RI", +-}; +- +-static const true_false_string transport_block_to_codeword_swap_flag = { +- "NO_SWAPPING", +- "SWAPPED" +-}; +- +-static const true_false_string virtual_resource_block_assignment_flag = { +- "LOCALIZED", +- "DISTRIBUTED" +-}; +- +-static const true_false_string ngap_string_name = { +- "N-GAP 1", +- "N-GAP 2" +-}; +- +-static const true_false_string nprb_strname = { +- "= 2", +- "= 3", +-}; +- +-static const true_false_string cyclic_prefix_type_strname = { +- "CP_NORMAL", +- "CP_EXTENDED" +-}; +- +-static const true_false_string support_strname = { +- "No Support", +- "Support" +-}; +- +-static const true_false_string partial_sf_support_strname = +-{ +- "Start partial SF support", +- "End partial SF support" +-}; +- +-static const true_false_string phich_duration_strname = { +- "PHICH_D_NORMAL", +- "PHICH_D_EXTENDED" +-}; +- +-static const true_false_string high_speed_flag_strname = { +- "HS_UNRESTRICTED_SET", +- "HS_RESTRICTED_SET" +-}; +- +-static const true_false_string hopping_mode_strname = { +- "HM_INTER_SF", +- "HM_INTRA_INTER_SF" +-}; +- +-static const true_false_string enabled_disabled_strname = { +- "Enabled", +- "Disabled" +-}; +- +-static const true_false_string srs_simult_tx_strname = { +- "No Simultaneous Transmission", +- "Simultaneous Transmission" +-}; +- +-static const true_false_string crc_flag_strname = { +- "CRC_CORRECT", +- "CRC_ERROR" +-}; +- +-static const true_false_string hi_value_strname = { +- "HI_NACK", +- "HI_ACK" +-}; +- +-static const true_false_string flag_tb2_strname = { +- "HI_NOT_PRESENT", +- "HI_PRESENT" +-}; +- +-static const true_false_string nfapi_multi_carrier_tx_strname = { +- "Mutual transmission (self-deferral support for current carrier)", +- "Transmit on channel access win (no self-deferral)" +-}; +- +-static const true_false_string nfapi_multi_carrier_freeze_strname = { +- "Absence of other technology isn’t guaranteed", +- "Absence of other technology is guaranteed" +-}; +- +-static const value_string nfapi_dl_config_pdu_type_vals[] = { +- { 0, "DL_CONFIG_DCI_DL_PDU" }, +- { 1, "DL_CONFIG_BCH_PDU" }, +- { 2, "DL_CONFIG_MCH_PDU" }, +- { 3, "DL_CONFIG_DLSCH_PDU" }, +- { 4, "DL_CONFIG_PCH_PDU" }, +- { 5, "DL_CONFIG_PRS_PDU" }, +- { 6, "DL_CONFIG_CSI_RS_PDU" }, +- { 7, "DL_CONFIG_EPDCCH_DL_PDU" }, +- { 8, "DL_CONFIG_EPDCCH_DL_PDU" }, +- { 0, NULL } +-}; +- +-static const value_string nfapi_duplex_mode_vals[] = { +- { 0, "TDD" }, +- { 1, "FDD" }, +- { 2, "HD-FDD" }, +- { 0, NULL } +-}; +- +-static const value_string modulation_vals[] = { +- { 2, "QPSK" }, +- { 4, "16QAM" }, +- { 6, "64QAM" }, +- { 8, "256QAM" }, +- { 0, NULL } +-}; +- +-static const value_string pch_modulation_vals[] = { +- { 0, "QPSK" }, +- { 0, NULL } +-}; +- +-static const value_string ue_mode_vals[] = { +- { 0, "non LC/CE UE" }, +- { 1, "LC/CE UE" }, +- { 0, NULL } +-}; +- +-static const value_string csi_rs_class_vals[] = { +- { 0, "not used" }, +- { 1, "Class A" }, +- { 1, "Class B" }, +- { 0, NULL } +-}; +- +-static const value_string csi_rs_cdm_type_vals[] = { +- { 0, "cdm 2" }, +- { 1, "cdm 4" }, +- { 0, NULL } +-}; +- +-static const value_string antenna_ports_vals[] = { +- { 0, "1 antenna ports" }, +- { 1, "2 antenna ports" }, +- { 2, "4 antenna ports" }, +- { 0, NULL } +-}; +- +-static const value_string combs_vals[] = { +- { 0, "2 TC" }, +- { 1, "4 TC" }, +- { 0, NULL } +-}; +- +-static const value_string resource_allocation_type_vals[] = { +- { 0, "type 0" }, +- { 1, "type 1" }, +- { 2, "type 2 1A/1B/1D" }, +- { 3, "type 2 1C" }, +- { 4, "type 2 6-1A" }, +- { 5, "type UEModeB" }, +- { 0, NULL } +-}; +- +-static const value_string transmission_scheme_vals[] = { +- { 0, "SINGLE_ANTENNA_PORT_0" }, +- { 1, "TX_DIVERSITY" }, +- { 2, "LARGE_DELAY_CDD" }, +- { 3, "CLOSED_LOOP_SPATIAL_MULTIPLEXING" }, +- { 4, "MULTI_USER_MIMO" }, +- { 5, "CLOSED_LOOP_RANK_1_PRECODING" }, +- { 6, "SINGLE_ANTENNA_PORT_5" }, +- { 7, "SINGLE_ANTENNA_PORT_7" }, +- { 8, "SINGLE_ANTENNA_PORT_8" }, +- { 9, "DUAL_LAYER_TX_PORT_7_AND_8" }, +- { 10, "UP_TO_8_LAYER_TX" }, +- { 11, "SINGLE_ANTENNA_PORT_11" }, +- { 12, "SINGLE_ANTENNA_PORT_13" }, +- { 13, "SINGLE_ANTENNA_PORT_11_13" }, +- { 0, NULL } +-}; +- +-static const value_string ul_transmission_scheme_vals[] = { +- { 0, "SINGLE_ANTENNA_PORT_10" }, +- { 1, "CLOSED_LOOP_SPATIAL_MULTIPLEXING" }, +-}; +- +-static const value_string dci_format_vals[] = { +- { 0, "1" }, +- { 1, "1A" }, +- { 2, "1B" }, +- { 3, "1C" }, +- { 4, "1D" }, +- { 5, "2" }, +- { 6, "2A" }, +- { 7, "2B" }, +- { 8, "2C" }, +- { 9, "2D" }, +- { 0, NULL } +-}; +- +-static const value_string pa_vals[] = { +- { 0, "-6dB" }, +- { 1, "-4.77dB" }, +- { 2, "-3dB" }, +- { 3, "-1.77dB" }, +- { 4, "0dB" }, +- { 5, "1dB" }, +- { 6, "2dB" }, +- { 7, "3dB" }, +- { 0, NULL } +-}; +- +-static const value_string transmission_mode_vals[] = { +- { 1, "Mode 1" }, +- { 2, "Mode 2" }, +- { 3, "Mode 3" }, +- { 4, "Mode 4" }, +- { 5, "Mode 5" }, +- { 6, "Mode 6" }, +- { 7, "Mode 7" }, +- { 8, "Mode 8" }, +- { 9, "Mode 9" }, +- { 10, "Mode 10" }, +- { 0, NULL } +-}; +- +-static const value_string nfapi_ul_config_pdu_type_vals[] = { +- { 0, "ULSCH" }, +- { 1, "ULSCH_CQI_RI" }, +- { 2, "ULSCH_HARQ" }, +- { 3, "ULSCH_CQI_HARQ_RI" }, +- { 4, "UCI_CQI" }, +- { 5, "UCI_SR" }, +- { 6, "UCI_HARQ" }, +- { 7, "UCI_SR_HARQ" }, +- { 8, "UCI_CQI_HARQ" }, +- { 9, "UCI_CQI_SR" }, +- { 10, "UCI_CQI_SR_HARQ" }, +- { 11, "SRS" }, +- { 12, "HARQ_BUFFER" }, +- { 13, "ULSCH_UCI_CSI" }, +- { 14, "ULSCH_UCI_HARQ" }, +- { 15, "ULSCH_CSI_UCI_HARQ" }, +- { 0, NULL } +-}; +- +-typedef enum { +- NFAPI_ACK_NACK_MODE_BUNDLING = 0, +- NFAPI_ACK_NACK_MODE_MULTIPLEXING, +- NFAPI_ACK_NACK_MODE_FORMAT_1B_WITH_CHAN_SEL, +- NFAPI_ACK_NACK_MODE_FORMAT_3, +-} nfapi_ack_nack_mode_e; +- +-static const value_string nfapi_ack_nack_mode_vals[] = { +- { NFAPI_ACK_NACK_MODE_BUNDLING, "Bundling" }, +- { NFAPI_ACK_NACK_MODE_MULTIPLEXING, "Multiplexing" }, +- { NFAPI_ACK_NACK_MODE_FORMAT_1B_WITH_CHAN_SEL, "Format 1b with channel selection" }, +- { NFAPI_ACK_NACK_MODE_FORMAT_3, "Format 3" }, +- { 0, NULL } +-}; +- +-typedef enum { +- NFAPI_ANTENNA_PORT1 = 0, +- NFAPI_ANTENNA_PORT2, +- NFAPI_ANTENNA_PORT4, +-} nfapi_ack_nack_mode_e; +- +-static const value_string nfapi_antenna_port_vals[] = { +- { NFAPI_ANTENNA_PORT1, "1 " }, +- { NFAPI_ANTENNA_PORT2, "2 " }, +- { NFAPI_ANTENNA_PORT4, "4 " }, +- { 0, NULL } +-}; +- +-typedef enum{ +- PHICH_R_ONE_SIXTH = 0, +- PHICH_R_HALF, +- PHICH_R_ONE, +- PHICH_R_TWO +-} nfapi_phich_resource_e; +- +-static const value_string nfapi_phich_resource_vals[] = { +- { PHICH_R_ONE_SIXTH, "PHICH_R_ONE_SIXTH " }, +- { PHICH_R_HALF, "PHICH_R_HALF" }, +- { PHICH_R_ONE, "PHICH_R_ONE" }, +- { PHICH_R_TWO, "PHICH_R_TWO" }, +- { 0, NULL } +-}; +- +-static const value_string local_distributed_vals[] = { +- { 0, "localized" }, +- { 1, "distributed" }, +- { 0, NULL } +-}; +- +-static const value_string transport_block_to_codeword_swap_flag_vals[] = { +- { 0, "no swapping" }, +- { 1, "swapped" }, +- { 0, NULL } +-}; +- +-static const value_string ngap_vals[] = { +- { 0, "Ngap1" }, +- { 1, "Ngap2" }, +- { 0, NULL } +-}; +- +-static const value_string true_false_vals[] = { +- { 0, "false" }, +- { 1, "true" }, +- { 0, NULL } +-}; +- +-static const value_string exhustive_search_vals[] = { +- { 0, "non-exhaustive search" }, +- { 1, "exhaustive search" }, +- { 0, NULL } +-}; +- +-static const value_string not_used_enabled_vals[] = { +- { 0, "not used" }, +- { 1, "enabled" }, +- { 0, NULL } +-}; +- +-static const value_string hopping_vals[] = { +- { 0, "no hopping" }, +- { 1, "hopping enabled" }, +- { 0, NULL } +-}; +- +- +-static const value_string rnti_type_vals[] = { +- { 1, "C-RNTI" }, +- { 2, "RA-RNTI, P-RNTI, SI-RNTI, SC-RNTI, G-RNTI" }, +- { 3, "SPS-CRNTI" }, +- { 0, NULL } +-}; +- +-static const value_string primary_cells_type_vals[] = { +- { 1, "TDD" }, +- { 2, "FDD" }, +- { 3, "HD_FDD" }, +- { 0, NULL } +-}; +- +-static const value_string ul_rssi_supported_vals[] = { +- { 0, "Uplink RSSI not supported" }, +- { 1, "Uplink RSSI supported" }, +- { 0, NULL} +-}; +- +- +-typedef enum +-{ +- NMM_NONE = 0, +- NMM_ONLY, +- NMM_IN_CONFIGURED_STATE, +- NMM_IN_RUNNING_STATE, +- NMM_IN_CONFIGURED_AND_RUNNING_STATE +-} nmm_modes_supported_e; +- +-static const value_string nmm_modes_supported_vals[] = +-{ +- { NMM_NONE, "NONE" }, +- { NMM_ONLY, "NMM_ONLY" }, +- { NMM_IN_CONFIGURED_STATE, "NMM_IN_CONFIGURED_STATE" }, +- { NMM_IN_RUNNING_STATE, "NMM_IN_RUNNING_STATE" }, +- { NMM_IN_CONFIGURED_AND_RUNNING_STATE, "NMM_IN_CONFIGURED_AND_RUNNING_STAT" }, +- { 0, NULL } +-}; +- +- +- +- +- +-static int proto_nfapi = -1; +- +-/* These are for the subtrees */ +-static gint ett_nfapi_message_tree = -1; +-static gint ett_nfapi_p4_p5_message_header = -1; +-static gint ett_nfapi_p7_message_header = -1; +-static gint ett_nfapi_tlv_tree = -1; +-static gint ett_nfapi_tl = -1; +-static gint ett_nfapi_pnf_param_response = -1; +-static gint ett_nfapi_pnf_phy = -1; +-static gint ett_nfapi_pnf_phy_rel10 = -1; +-static gint ett_nfapi_pnf_phy_rel11 = -1; +-static gint ett_nfapi_pnf_phy_rel12 = -1; +-static gint ett_nfapi_pnf_phy_rel13 = -1; +-static gint ett_nfapi_pnf_rf = -1; +-static gint ett_nfapi_phy_rf_config_info = -1; +-static gint ett_nfapi_pnf_phy_rf_config = -1; +-static gint ett_nfapi_pnf_phy_rf_config_instance = -1; +-static gint ett_nfapi_phy_state = -1; +-static gint ett_nfapi_l1_status = -1; +-static gint ett_nfapi_rf_bands = -1; +-static gint ett_nfapi_tx_antenna_ports = -1; +-static gint ett_nfapi_harq_ack_nack_data = -1; +-static gint ett_nfapi_harq_data = -1; +-static gint ett_nfapi_cc = -1; +-static gint ett_nfapi_rbs = -1; +-static gint ett_nfapi_antennas = -1; +-static gint ett_nfapi_dl_config_dci_dl_pdu_rel8 = -1; +-static gint ett_nfapi_dl_config_dci_dl_pdu_rel9 = -1; +-static gint ett_nfapi_dl_config_dci_dl_pdu_rel10 = -1; +-static gint ett_nfapi_dl_config_dci_dl_pdu = -1; +-static gint ett_nfapi_dl_config_request_pdu = -1; +-static gint ett_nfapi_dl_config_request_body = -1; +-static gint ett_nfapi_dl_config_request_pdu_list = -1; +-static gint ett_nfapi_ul_config_request_pdu_list = -1; +-static gint ett_nfapi_hi_dci0_request_pdu_list = -1; +-static gint ett_nfapi_tx_request_pdu_list = -1; +-static gint ett_nfapi_rx_indication_pdu_list = -1; +-static gint ett_nfapi_harq_indication_pdu_list = -1; +-static gint ett_nfapi_crc_indication_pdu_list = -1; +-static gint ett_nfapi_sr_indication_pdu_list = -1; +-static gint ett_nfapi_cqi_indication_pdu_list = -1; +-static gint ett_nfapi_preamble_indication_pdu_list = -1; +-static gint ett_nfapi_srs_indication_pdu_list = -1; +-static gint ett_nfapi_lbt_dl_config_pdu_list = -1; +-static gint ett_nfapi_lbt_dl_indication_pdu_list = -1; +-static gint ett_nfapi_dl_node_sync = -1; +-static gint ett_nfapi_ul_node_sync = -1; +-static gint ett_nfapi_timing_info = -1; +-static gint ett_nfapi_dl_config_request_dlsch_pdu_rel8 = -1; +-static gint ett_nfapi_subbands = -1; +-static gint ett_nfapi_dl_config_request_dlsch_pdu_rel9 = -1; +-static gint ett_nfapi_dl_config_request_dlsch_pdu_rel10 = -1; +-static gint ett_nfapi_dl_config_bch_pdu_rel8 = -1; +-static gint ett_nfapi_dl_config_mch_pdu_rel8 = -1; +-static gint ett_nfapi_dl_config_pch_pdu_rel8 = -1; +-static gint ett_nfapi_dl_config_prs_pdu_rel9 = -1; +-static gint ett_nfapi_dl_config_csi_rs_pdu_rel10 = -1; +-static gint ett_nfapi_ul_config_request_body = -1; +-static gint ett_nfapi_ul_config_harq_buffer_pdu = -1; +-static gint ett_nfapi_ul_config_ue_information_rel8 = -1; +-static gint ett_nfapi_ul_config_sr_information_pdu_rel8 = -1; +-static gint ett_nfapi_ul_config_ulsch_pdu_rel8 = -1; +-static gint ett_nfapi_ul_config_ulsch_pdu_rel10 = -1; +-static gint ett_nfapi_ul_config_cqi_ri_information_rel8 = -1; +-static gint ett_nfapi_ul_config_cqi_ri_information_rel9 = -1; +-static gint ett_nfapi_ul_config_ulsch_harq_information_rel10 = -1; +-static gint ett_nfapi_ul_config_initial_transmission_parameters_rel8 = -1; +-static gint ett_nfapi_ul_config_cqi_information_rel8 = -1; +-static gint ett_nfapi_ul_config_cqi_information_rel10 = -1; +-static gint ett_nfapi_ul_config_sr_information_rel8 = -1; +-static gint ett_nfapi_ul_config_sr_information_rel10 = -1; +-static gint ett_nfapi_ul_config_harq_information_rel10_tdd = -1; +-static gint ett_nfapi_ul_config_harq_information_rel8_fdd = -1; +-static gint ett_nfapi_ul_config_harq_information_rel9_fdd = -1; +-static gint ett_nfapi_ul_config_srs_pdu_rel8 = -1; +-static gint ett_nfapi_ul_config_srs_pdu_rel10 = -1; +-static gint ett_nfapi_crc_indication_body = -1; +-static gint ett_nfapi_bf_vector_antennas = -1; +-static gint ett_nfapi_bf_vectors = -1; +-static gint ett_nfapi_csi_rs_resource_configs = -1; +-static gint ett_nfapi_csi_rs_bf_vector = -1; +-static gint ett_nfapi_epdcch_prbs = -1; +-static gint ett_nfapi_precoding = -1; +-static gint ett_nfapi_earfcn_list = -1; +-static gint ett_nfapi_uarfcn_list = -1; +-static gint ett_nfapi_arfcn_list = -1; +-static gint ett_nfapi_rssi_list = -1; +-static gint ett_nfapi_pci_list = -1; +-static gint ett_nfapi_psc_list = -1; +-static gint ett_nfapi_lte_cells_found_list = -1; +-static gint ett_nfapi_utran_cells_found_list = -1; +-static gint ett_nfapi_geran_cells_found_list = -1; +-static gint ett_nfapi_si_periodicity_list = -1; +- +-static expert_field ei_invalid_range = EI_INIT; +-static expert_field ei_power_invalid = EI_INIT; +-static expert_field ei_ref_sig_power_invalid = EI_INIT; +- +- +-static int hf_nfapi_message_tree = -1; +- +-static int hf_nfapi_p4_p5_message_header = -1; +-static int hf_nfapi_p4_p5_message_header_phy_id = -1; +-static int hf_nfapi_p4_p5_message_header_message_id = -1; +-static int hf_nfapi_p4_p5_message_header_message_length = -1; +-static int hf_nfapi_p4_p5_message_header_spare = -1; +- +-static int hf_nfapi_p7_message_header = -1; +-static int hf_nfapi_p7_message_header_phy_id = -1; +-static int hf_nfapi_p7_message_header_message_id = -1; +-static int hf_nfapi_p7_message_header_message_length = -1; +-static int hf_nfapi_p7_message_header_m = -1; +-static int hf_nfapi_p7_message_header_segment = -1; +-static int hf_nfapi_p7_message_header_sequence_number = -1; +-static int hf_nfapi_p7_message_header_checksum = -1; +-static int hf_nfapi_p7_message_header_transmit_timestamp = -1; +- +-static int hf_nfapi_tlv_tree = -1; +- +-static int hf_nfapi_tl = -1; +-static int hf_nfapi_tl_tag = -1; +-static int hf_nfapi_tl_length = -1; +-static int hf_nfapi_tag_uint8_value = -1; +-static int hf_nfapi_tag_uint16_value = -1; +- +-static int hf_nfapi_pnf_param_general = -1; +-static int hf_nfapi_sync_mode = -1; +-static int hf_nfapi_location_mode = -1; +-static int hf_nfapi_location_coordinates = -1; +-static int hf_nfapi_location_coordinates_length = -1; +-static int hf_nfapi_dl_config_timing = -1; +-static int hf_nfapi_tx_timing = -1; +-static int hf_nfapi_ul_config_timing = -1; +-static int hf_nfapi_hi_dci0_timing = -1; +-static int hf_nfapi_maximum_number_phys = -1; +-static int hf_nfapi_maximum_total_bandwidth = -1; +-static int hf_nfapi_maximum_total_number_dl_layers = -1; +-static int hf_nfapi_maximum_total_number_ul_layers = -1; +-static int hf_nfapi_shared_bands = -1; +-static int hf_nfapi_shared_pa = -1; +-static int hf_nfapi_maximum_total_power = -1; +-static int hf_nfapi_oui= -1; +- +-static int hf_nfapi_pdu = -1; +- +-static int hf_nfapi_pnf_phy = -1; +-static int hf_nfapi_pnf_phy_nfapi_tl = -1; /* structure hf_nfapi_tl*/ +-static int hf_nfapi_pnf_phy_number_phy = -1; +-static int hf_nfapi_pnf_phy_config_index = -1; +-static int hf_nfapi_number_of_rf_exclusions = -1; +-static int hf_nfapi_dl_bandwidth_support = -1; +-static int hf_nfapi_ul_bandwidth_support = -1; +-static int hf_nfapi_downlink_channel_bandwidth_supported = -1; +-static int hf_nfapi_uplink_channel_bandwidth_supported = -1; +-static int hf_nfapi_number_of_dl_layers_supported = -1; +-static int hf_nfapi_number_of_ul_layers_supported = -1; +-static int hf_nfapi_maximum_3gpp_release_supported = -1; +-static int hf_nfapi_nmm_modes_supported = -1; +- +- +-static int hf_nfapi_pnf_rf = -1; +-static int hf_nfapi_pnf_rf_nfapi_tl = -1; +-static int hf_nfapi_number_of_rfs = -1; +-static int hf_nfapi_rf_config_index = -1; +-static int hf_nfapi_band = -1; +-static int hf_nfapi_maximum_transmit_power = -1; +-static int hf_nfapi_earfcn = -1; +-static int hf_nfapi_minimum_transmit_power = -1; +-static int hf_nfapi_number_of_antennas_suppported = -1; +-static int hf_nfapi_minimum_downlink_frequency = -1; +-static int hf_nfapi_maximum_downlink_frequency = -1; +-static int hf_nfapi_minimum_uplink_frequency = -1; +-static int hf_nfapi_maximum_uplink_frequency = -1; +- +-static int hf_nfapi_number_of_rf_bands = -1; +-static int hf_nfapi_nmm_uplink_rssi_supported = -1; +- +-static int hf_nfapi_phy_rf_config_info = -1; +-static int hf_nfapi_phy_rf_config_info_phy_id = -1; +-static int hf_nfapi_phy_rf_config_info_band = -1; +- +-static int hf_nfapi_pnf_phy_rf_config = -1; +-static int hf_nfapi_pnf_phy_rf_config_number_phy_rf_config_info = -1; +-static int hf_nfapi_pnf_phy_rf_config_array_phy_rf_config_info = -1; +- +-static int hf_nfapi_pnf_phy_rel10 = -1; +-static int hf_nfapi_transmission_mode7_supported = -1; +-static int hi_nfapi_transmission_mode8_supported = -1; +-static int hi_nfapi_two_antennas_ports_for_pucch = -1; +-static int hi_nfapi_transmission_mode_9_supported = -1; +-static int hi_nfapi_simultaneous_pucch_pusch = -1; +-static int hi_nfapi_for_layer_tx_with_tm3_and_tm4 = -1; +- +-static int hf_nfapi_pnf_phy_rel11 = -1; +-static int hf_nfapi_epdcch_supported = -1; +-static int hi_nfapi_multi_ack_csi_reporting = -1; +-static int hi_nfapi_pucch_tx_diversity_with_channel_selection = -1; +-static int hi_nfapi_ul_comp_supported = -1; +-static int hi_nfapi_transmission_mode_5_supported = -1; +- +-static int hf_nfapi_pnf_phy_rel12 = -1; +-static int hf_nfapi_csi_subframe_set = -1; +-static int hi_nfapi_enhanced_4tx_codebook = -1; +-static int hi_nfapi_drs_supported = -1; +-static int hi_nfapi_ul_64qam_supported = -1; +-static int hi_nfapi_transmission_mode_10_supported = -1; +-static int hi_nfapi_alternative_tbs_indices = -1; +- +-static int hf_nfapi_pnf_phy_rel13 = -1; +-static int hf_nfapi_pucch_format_4_supported = -1; +-static int hf_nfapi_pucch_format_5_supported = -1; +-static int hf_nfapi_more_than_5_ca_supported = -1; +-static int hf_nfapi_laa_supported = -1; +-static int hf_nfapi_laa_ending_in_dwpts_supported = -1; +-static int hf_nfapi_laa_starting_in_second_slot_supported = -1; +-static int hf_nfapi_beamforming_supported = -1; +-static int hf_nfapi_csi_rs_enhancements_supported = -1; +-static int hf_nfapi_drms_enhancements_supported = -1; +-static int hf_nfapi_srs_enhancements_supported = -1; +- +- +-// P5 Message Structures +-static int hf_nfapi_pnf_param_response_pnf_param_general = -1; +-static int hf_nfapi_pnf_param_response_pnf_phy = -1; +-static int hf_nfapi_pnf_param_response_pnf_rf = -1; +- +-static int hf_nfapi_pnf_param_request = -1; +-static int hf_nfapi_pnf_param_response = -1; +-static int hf_nfapi_pnf_config_request = -1; +-static int hf_nfapi_pnf_config_response = -1; +-static int hf_nfapi_pnf_start_request = -1; +-static int hf_nfapi_pnf_start_response = -1; +-static int hf_nfapi_pnf_stop_request = -1; +-static int hf_nfapi_pnf_stop_response = -1; +-static int hf_nfapi_param_response = -1; +-static int hf_nfapi_start_request = -1; +-static int hf_nfapi_start_response = -1; +-static int hf_nfapi_stop_request = -1; +-static int hf_nfapi_stop_response = -1; +- +-static int hf_nfapi_uint8_tag = -1; +-static int hf_nfapi_uint16_tag = -1; +- +-static int hf_nfapi_error_code = -1; +-static int hf_nfapi_p4_error_code = -1; +-static int hf_nfapi_rat_type = -1; +-static int hf_nfapi_num_tlv = -1; +-static int hf_nfapi_phy_state = -1; +-// static int hf_nfapi_bandwidth_support = -1; +- +-static int hf_nfapi_modulation_support = -1; +-static int hf_nfapi_phy_antenna_capability = -1; +-static int hf_nfapi_release_capability = -1; +-static int hf_nfapi_mbsfn_capability = -1; +- +-static int hf_nfapi_laa_capability = -1; +-static int hf_nfapi_pd_sensing_lbt_support = -1; +-static int hf_nfapi_multi_carrier_lbt_support = -1; +-static int hf_nfapi_partial_sf_support = -1; +- +-/* nfapi nfapi */ +-static int hf_nfapi_pnf_address = -1; +-static int hf_nfapi_pnf_address_ipv4 = -1; +-static int hf_nfapi_pnf_address_ipv6 = -1; +- +-static int hf_nfapi_vnf_address = -1; +-static int hf_nfapi_vnf_address_ipv4 = -1; +-static int hf_nfapi_vnf_address_ipv6 = -1; +- +-static int hf_nfapi_pnf_port = -1; +-static int hf_nfapi_vnf_port = -1; +-static int hf_nfapi_dl_ue_per_sf = -1; +-static int hf_nfapi_ul_ue_per_sf = -1; +- +-static int hf_nfapi_rf_bands = -1; +-static int hf_nfapi_rf_bands_nfapi_tl = -1; +-static int hf_nfapi_rf_bands_count = -1; +-static int hf_nfapi_rf_bands_value = -1; +- +-static int hf_nfapi_timing_window = -1; +-static int hf_nfapi_timing_info_mode = -1; +-static int hf_nfapi_timing_info_period = -1; +-static int hf_nfapi_max_transmit_power = -1; +- +-/* subframe config */ +-static int hf_nfapi_duplex_mode = -1; +-static int hf_nfapi_pcfich_power_offset = -1; +-static int hf_nfapi_pb = -1; +-static int hf_nfapi_dl_cyclic_prefix_type = -1; +-static int hf_nfapi_ul_cyclic_prefix_type = -1; +- +-static int hf_nfapi_tx_antenna_ports = -1; +-static int hf_nfapi_rx_antenna_ports = -1; +- +- +- +-/* RF Config */ +-static int hf_nfapi_downlink_channel_bandwidth = -1; +-static int hf_nfapi_uplink_channel_bandwidth = -1; +-static int hf_nfapi_reference_signal_power = -1; +- +-/* PHICH config*/ +-static int hf_nfapi_phich_resource = -1; +-static int hf_nfapi_phich_duration = -1; +-static int hf_nfapi_phich_power_offset = -1; +- +-static int hf_nfapi_value_float = -1; +- +-/* SCH Config */ +-static int hf_nfapi_primary_synchronization_signal_epre_eprers = -1; +-static int hf_nfapi_secondary_synchronization_signal_epre_eprers = -1; +-static int hf_nfapi_physical_cell_id = -1; +- +-/* PRACH config */ +-static int hf_nfapi_configuration_index = -1; +-static int hf_nfapi_root_sequence_index = -1; +-static int hf_nfapi_zero_correlation_zone_configuration = -1; +-static int hf_nfapi_high_speed_flag = -1; +-static int hf_nfapi_frequency_offset = -1; +- +-/* PUSCH config */ +-static int hf_nfapi_hopping_mode = -1; +-static int hf_nfapi_hopping_offset = -1; +- +-/* PUCCH config */ +-static int hf_nfapi_delta_pucch_shift = -1; +-static int hf_nfapi_n_cqi_rb = -1; +-static int hf_nfapi_n_an_cs = -1; +-static int hf_nfapi_n1_pucch_an = -1; +- +-/* SRS config */ +-static int hf_nfapi_bandwidth_configuration = -1; +-static int hf_nfapi_max_up_pts = -1; +-static int hf_nfapi_srs_subframe_configuration = -1; +-static int hf_nfapi_srs_acknack_srs_simultaneous_transmission = -1; +- +-/* uplink reference signal config */ +-static int hf_nfapi_uplink_rs_hopping = -1; +-static int hf_nfapi_group_assignment = -1; +-static int hf_nfapi_cyclic_shift_1_for_drms = -1; +- +-/* tdd frame structure */ +-static int hf_nfapi_subframe_assignment = -1; +-static int hf_nfapi_special_subframe_patterns = -1; +- +-/* laa config */ +-static int hf_nfapi_ed_threshold_for_lbt_for_pdsch = -1; +-static int hf_nfapi_ed_threshold_for_lbt_for_drs = -1; +-static int hf_nfapi_pd_threshold = -1; +-static int hf_nfapi_multi_carrier_type = -1; +-static int hf_nfapi_multi_carrier_tx = -1; +-static int hf_nfapi_multi_carrier_freeze = -1; +-static int hf_nfapi_tx_antenna_ports_for_drs = -1; +-static int hf_nfapi_transmission_power_for_drs = -1; +- +-/* eMTC config */ +-static int hf_nfapi_pbch_repetitions_enabled_r13 = -1; +-static int hf_nfapi_prach_cat_m_root_sequence_index = -1; +-static int hf_nfapi_prach_cat_m_zero_correlation_zone_configuration = -1; +-static int hf_nfapi_prach_cat_m_high_speed_flag = -1; +- +-static int hf_nfapi_prach_ce_level_0_enable = -1; +-static int hf_nfapi_prach_ce_level_0_configuration_index = -1; +-static int hf_nfapi_prach_ce_level_0_frequency_offset = -1; +-static int hf_nfapi_prach_ce_level_0_number_of_repetitions_per_attempt = -1; +-static int hf_nfapi_prach_ce_level_0_starting_subframe_periodicity = -1; +-static int hf_nfapi_prach_ce_level_0_hopping_enabled = -1; +-static int hf_nfapi_prach_ce_level_0_hopping_offset = -1; +- +-static int hf_nfapi_prach_ce_level_1_enable = -1; +-static int hf_nfapi_prach_ce_level_1_configuration_index = -1; +-static int hf_nfapi_prach_ce_level_1_frequency_offset = -1; +-static int hf_nfapi_prach_ce_level_1_number_of_repetitions_per_attempt = -1; +-static int hf_nfapi_prach_ce_level_1_starting_subframe_periodicity = -1; +-static int hf_nfapi_prach_ce_level_1_hopping_enabled = -1; +-static int hf_nfapi_prach_ce_level_1_hopping_offset = -1; +- +-static int hf_nfapi_prach_ce_level_2_enable = -1; +-static int hf_nfapi_prach_ce_level_2_configuration_index = -1; +-static int hf_nfapi_prach_ce_level_2_frequency_offset = -1; +-static int hf_nfapi_prach_ce_level_2_number_of_repetitions_per_attempt = -1; +-static int hf_nfapi_prach_ce_level_2_starting_subframe_periodicity = -1; +-static int hf_nfapi_prach_ce_level_2_hopping_enabled = -1; +-static int hf_nfapi_prach_ce_level_2_hopping_offset = -1; +- +-static int hf_nfapi_prach_ce_level_3_enable = -1; +-static int hf_nfapi_prach_ce_level_3_configuration_index = -1; +-static int hf_nfapi_prach_ce_level_3_frequency_offset = -1; +-static int hf_nfapi_prach_ce_level_3_number_of_repetitions_per_attempt = -1; +-static int hf_nfapi_prach_ce_level_3_starting_subframe_periodicity = -1; +-static int hf_nfapi_prach_ce_level_3_hopping_enabled = -1; +-static int hf_nfapi_prach_ce_level_3_hopping_offset = -1; +-static int hf_nfapi_pucch_internal_ul_hopping_config_common_mode_b = -1; +-static int hf_nfapi_pucch_internal_ul_hopping_config_common_mode_a = -1; +- +-static int hf_nfapi_dl_modulation_support = -1; +-static int hf_nfapi_ul_modulation_support = -1; +- +-/* 123 config */ +-static int hf_nfapi_data_report_mode = -1; +-static int hf_nfapi_sfnsf = -1; +- +-// P7 Sub Structures +-static int hf_nfapi_dl_config_dci_dl_pdu_rel8 = -1; +-static int hf_nfapi_dci_format = -1; +-static int hf_nfapi_cce_idx = -1; +-static int hf_nfapi_aggregation_level = -1; +-static int hf_nfapi_mcs_1 = -1; +-static int hf_nfapi_redundancy_version_1 = -1; +-static int hf_nfapi_new_data_indicator_1 = -1; +-static int hf_nfapi_mcs_2 = -1; +-static int hf_nfapi_redundancy_version_2 = -1; +-static int hf_nfapi_new_data_indicator_2 = -1; +-static int hf_nfapi_harq_process = -1; +-static int hf_nfapi_tpmi = -1; +-static int hf_nfapi_pmi = -1; +-static int hf_nfapi_precoding_information = -1; +-static int hf_nfapi_tpc = -1; +-static int hf_nfapi_downlink_assignment_index = -1; +-static int hf_nfapi_transport_block_size_index = -1; +-static int hf_nfapi_downlink_power_offset = -1; +-static int hf_nfapi_allocate_prach_flag = -1; +-static int hf_nfapi_preamble_index = -1; +-static int hf_nfapi_prach_mask_index = -1; +-static int hf_nfapi_rnti_type = -1; +- +-static int hf_nfapi_dl_config_dci_dl_pdu_rel9 = -1; +-static int hf_nfapi_mcch_flag = -1; +-static int hf_nfapi_mcch_change_notification = -1; +-static int hf_nfapi_scrambling_identity = -1; +- +-static int hf_nfapi_dl_config_dci_dl_pdu_rel10 = -1; +-static int hf_nfapi_cross_carrier_scheduling_flag = -1; +-static int hf_nfapi_carrier_indicator = -1; +-static int hf_nfapi_srs_flag = -1; +-static int hf_nfapi_srs_request = -1; +-static int hf_nfapi_antenna_ports_scrambling_and_layers = -1; +-static int hf_nfapi_total_dci_length_including_padding = -1; +-static int hf_nfapi_n_dl_rb = -1; +- +-static int hf_nfapi_dl_config_dci_dl_pdu_rel11 = -1; +-static int hf_nfapi_harq_ack_resource_offset = -1; +-static int hf_nfapi_pdsch_re_mapping_and_quasi_co_location_indicator = -1; +-static int hf_nfapi_dl_config_dci_dl_pdu_rel12 = -1; +-static int hf_nfapi_primary_cell_type = -1; +-static int hf_nfapi_ul_dl_configuration_flag = -1; +-static int hf_nfapi_number_of_ul_dl_configurations = -1; +-static int hf_nfapi_ul_dl_configuration_index = -1; +-static int hf_nfapi_dl_config_dci_dl_pdu_rel13 = -1; +-static int hf_nfapi_laa_end_partial_sf_flag = -1; +-static int hf_nfapi_laa_end_partial_sf_configuration = -1; +-static int hf_nfapi_initial_lbt_sf = -1; +-static int hf_nfapi_codebooksize_determination_r13 = -1; +-static int hf_nfapi_rel13_drms_table_flag = -1; +- +- +-static int hf_nfapi_dl_config_dci_dl_pdu = -1; +-static int hf_nfapi_dl_config_dci_dl_pdu_nfapi_dl_config_dci_dl_pdu_rel8 = -1; +-static int hf_nfapi_dl_config_dci_dl_pdu_nfapi_dl_config_dci_dl_pdu_rel9 = -1; +-static int hf_nfapi_dl_config_dci_dl_pdu_nfapi_dl_config_dci_dl_pdu_rel10 = -1; +- +-static int hf_nfapi_bf_vector_antennas = -1; +-static int hf_nfapi_subbands = -1; +-static int hf_nfapi_bf_vectors = -1; +-static int hf_nfapi_csi_rs_resource_config = -1; +-static int hf_nfapi_csi_rs_number_if_nzp_configurations = -1; +-static int hf_nfapi_csi_rs_resource_configs = -1; +-static int hf_nfapi_pdsch_start = -1; +-static int hf_nfapi_drms_config_flag = -1; +-static int hf_nfapi_drms_scrambling = -1; +-static int hf_nfapi_csi_config_flag = -1; +-static int hf_nfapi_csi_scrambling = -1; +-static int hf_nfapi_pdsch_re_mapping_flag = -1; +-static int hf_nfapi_pdsch_re_mapping_antenna_ports = -1; +-static int hf_nfapi_pdsch_re_mapping_freq_shift = -1; +-static int hf_nfapi_alt_cqi_table_r12 = -1; +-static int hf_nfapi_max_layers = -1; +-static int hf_nfapi_n_dl_harq = -1; +-static int hf_nfapi_dwpts_symbols = -1; +-static int hf_nfapi_ue_type = -1; +-static int hf_nfapi_pdsch_payload_type = -1; +-static int hf_nfapi_initial_transmission_sf = -1; +-static int hf_nfapi_req13_drms_table_flag = -1; +-static int hf_nfapi_prnti = -1; +-static int hf_nfapi_mcs = -1; +-static int hf_nfapi_number_of_transport_blocks = -1; +-static int hf_nfapi_ue_mode = -1; +-static int hf_prs_bandwidth = -1; +-static int hf_prs_cyclic_prefix_type = -1; +-static int hf_prs_muting = -1; +-static int hf_nfapi_csi_rs_number_of_nzp_configuration = -1; +-static int hf_nfapi_csi_rs_resource_index = -1; +-static int hf_nfapi_csi_rs_class = -1; +-static int hf_nfapi_cdm_type = -1; +-static int hf_nfapi_csi_rs_bf_vector = -1; +-static int hf_nfapi_edpcch_prb_index = -1; +-static int hf_nfapi_epdcch_resource_assignment_flag = -1; +-static int hf_nfapi_epdcch_id = -1; +-static int hf_nfapi_epdcch_start_symbol = -1; +-static int hf_nfapi_epdcch_num_prb = -1; +-static int hf_nfapi_epdcch_prbs = -1; +-static int hf_nfapi_precoding_value = -1; +-static int hf_nfapi_mpdcch_narrowband = -1; +-static int hf_nfapi_number_of_prb_pairs = -1; +-static int hf_nfapi_resource_block_assignment = -1; +-static int hf_nfapi_start_symbol = -1; +-static int hf_nfapi_ecce_index = -1; +-static int hf_nfapi_ce_mode = -1; +-static int hf_nfapi_drms_scrabmling_init = -1; +-static int hf_nfapi_pdsch_reception_levels = -1; +-static int hf_nfapi_new_data_indicator = -1; +-static int hf_nfapi_tpmi_length = -1; +-static int hf_nfapi_pmi_flag = -1; +-static int hf_nfapi_harq_resource_offset = -1; +-static int hf_nfapi_dci_subframe_repetition_number = -1; +-static int hf_nfapi_downlink_assignment_index_length = -1; +-static int hf_nfapi_starting_ce_level = -1; +-static int hf_nfapi_antenna_ports_and_scrambling_identity_flag = -1; +-static int hf_nfapi_antenna_ports_and_scrambling_identity = -1; +-static int hf_nfapi_paging_direct_indication_differentiation_flag = -1; +-static int hf_nfapi_direct_indication = -1; +-static int hf_nfapi_number_of_tx_antenna_ports = -1; +-static int hf_nfapi_precoding = -1; +- +- +- +-// P7 Message Structures +-static int hf_nfapi_dl_node_sync = -1; +-static int hf_nfapi_dl_node_sync_nfapi_p7_message_header = -1; +-static int hf_nfapi_dl_node_sync_t1 = -1; +-static int hf_nfapi_dl_node_sync_delta_sfn_sf = -1; +- +-static int hf_nfapi_ul_node_sync = -1; +-static int hf_nfapi_ul_node_sync_nfapi_p7_message_header = -1; +-static int hf_nfapi_ul_node_sync_t1 = -1; +-static int hf_nfapi_ul_node_sync_t2 = -1; +-static int hf_nfapi_ul_node_sync_t3 = -1; +- +-static int hf_nfapi_timing_info = -1; +-static int hf_nfapi_timing_info_nfapi_p7_message_header = -1; +-static int hf_nfapi_timing_info_last_sfn_sf = -1; +-static int hf_nfapi_timing_info_time_since_last_timing_info = -1; +-static int hf_nfapi_timing_info_dl_config_jitter = -1; +-static int hf_nfapi_timing_info_tx_request_jitter = -1; +-static int hf_nfapi_timing_info_ul_config_jitter = -1; +-static int hf_nfapi_timing_info_hi_dci0_jitter = -1; +-static int hf_nfapi_timing_info_dl_config_latest_delay = -1; +-static int hf_nfapi_timing_info_tx_request_latest_delay = -1; +-static int hf_nfapi_timing_info_ul_config_latest_delay = -1; +-static int hf_nfapi_timing_info_hi_dci0_latest_delay = -1; +-static int hf_nfapi_timing_info_dl_config_earliest_arrival = -1; +-static int hf_nfapi_timing_info_tx_request_earliest_arrival = -1; +-static int hf_nfapi_timing_info_ul_config_earliest_arrival = -1; +-static int hf_nfapi_timing_info_hi_dci0_earliest_arrival = -1; +- +-static int hf_nfapi_dl_config_request = -1; +-static int hf_nfapi_sfn_sf = -1; +- +-static int hf_nfapi_dl_config_request_body = -1; +-static int hf_nfapi_number_pdcch_ofdm_symbols = -1; +-static int hf_nfapi_number_dci = -1; +-static int hf_nfapi_number_pdus = -1; +-static int hf_nfapi_number_pdsch_rnti = -1; +-static int hf_nfapi_transmission_power_pcfich = -1; +- +-static int hf_nfapi_number_of_harqs = -1; +-static int hf_nfapi_number_of_crcs = -1; +-static int hf_nfapi_number_of_srs = -1; +-static int hf_nfapi_number_of_cqi = -1; +-static int hf_nfapi_number_of_preambles = -1; +-static int hf_nfapi_number_of_srss = -1; +-static int hf_nfapi_lbt_dl_req_pdu_type = -1; +-static int hf_nfapi_lbt_dl_ind_pdu_type = -1; +- +-static int hf_nfapi_dl_config_request_pdu_list = -1; +-static int hf_nfapi_ul_config_request_pdu_list = -1; +-static int hf_nfapi_hi_dci0_request_pdu_list = -1; +-static int hf_nfapi_tx_request_pdu_list = -1; +-static int hf_nfapi_rx_indication_pdu_list = -1; +-static int hf_nfapi_harq_indication_pdu_list = -1; +-static int hf_nfapi_crc_indication_pdu_list = -1; +-static int hf_nfapi_sr_indication_pdu_list = -1; +-static int hf_nfapi_cqi_indication_pdu_list = -1; +-static int hf_nfapi_preamble_indication_pdu_list = -1; +-static int hf_nfapi_srs_indication_pdu_list = -1; +-static int hf_nfapi_lbt_dl_config_pdu_list = -1; +-static int hf_nfapi_lbt_dl_indication_pdu_list = -1; +- +- +-static int hf_nfapi_dl_config_pdu_type = -1; +-static int hf_nfapi_pdu_size = -1; +-static int hf_nfapi_instance_length = -1; +- +-static int hf_nfapi_dl_config_dlsch_pdu_rel8 = -1; +-static int hf_nfapi_length; +-static int hf_nfapi_pdu_index = -1; +-static int hf_nfapi_rnti = -1; +-static int hf_nfapi_resource_allocation_type = -1; +-static int hf_nfapi_virtual_resource_block_assignment_flag = -1; +-static int hf_nfapi_resource_block_coding = -1; +-static int hf_nfapi_modulation = -1; +-static int hf_nfapi_redundancy_version = -1; +-static int hf_nfapi_transport_blocks = -1; +-static int hf_nfapi_transport_block_to_codeword_swap_flag = -1; +-static int hf_nfapi_transmission_scheme = -1; +-static int hf_nfapi_ul_transmission_scheme = -1; +-static int hf_nfapi_number_of_layers = -1; +-static int hf_nfapi_number_of_subbands = -1; +-static int hf_nfapi_codebook_index = -1; +-static int hf_nfapi_ue_category_capacity = -1; +-static int hf_nfapi_pa = -1; +-static int hf_nfapi_delta_power_offset_index = -1; +-static int hf_nfapi_ngap = -1; +-static int hf_nfapi_nprb = -1; +-static int hf_nfapi_transmission_mode = -1; +-static int hf_nfapi_num_bf_prb_per_subband = -1; +- +-static int hf_nfapi_num_bf_vector = -1; +-static int hf_nfapi_bf_vector_subband_index = -1; +-static int hf_nfapi_bf_vector_num_antennas = -1; +-static int hf_nfapi_bf_vector_bf_value = -1; +- +-static int hf_nfapi_dl_config_dlsch_pdu_rel9 = -1; +-static int hf_nfapi_nscid = -1; +- +-static int hf_nfapi_dl_config_dlsch_pdu_rel10 = -1; +-static int hf_nfapi_csi_rs_flag = -1; +-static int hf_nfapi_csi_rs_resource_config_r10 = -1; +-static int hf_nfapi_csi_rs_zero_tx_power_resource_config_bitmap_r10 = -1; +- +-static int hf_nfapi_dl_config_bch_pdu_rel8 = -1; +-static int hf_nfapi_transmission_power = -1; +- +-static int hf_nfapi_dl_config_mch_pdu_rel8 = -1; +-static int hf_nfapi_mbsfn_area_id = -1; +- +-static int hf_nfapi_dl_config_pch_pdu_rel8 = -1; +- +-static int hf_nfapi_dl_config_prs_pdu_rel9 = -1; +-static int hf_nfapi_prs_bandwidth = -1; +-static int hf_nfapi_prs_cyclic_prefix_type = -1; +- +-static int hf_nfapi_dl_config_csi_rs_pdu_rel10 = -1; +-static int hf_nfapi_csi_rs_antenna_port_count_r10 = -1; +- +-static int hf_nfapi_ul_config_request = -1; +-static int hf_nfapi_ul_config_request_body = -1; +-static int hf_nfapi_ul_config_pdu_type = -1; +- +-static int hf_nfapi_rach_prach_frequency_resources = -1; +-static int hf_nfapi_srs_present = -1; +-static int hf_nfapi_ul_config_harq_buffer_pdu = -1; +- +-static int hf_nfapi_ul_config_ue_information_rel8 = -1; +-static int hf_nfapi_handle = -1; +-static int hf_nfapi_ul_config_sr_information_pdu_rel8 = -1; +-static int hf_nfapi_pucch_index = -1; +-static int hf_nfapi_size = -1; +-static int hf_nfapi_resource_block_start = -1; +-static int hf_nfapi_number_of_resource_blocks = -1; +-static int hf_nfapi_cyclic_shift_2_for_drms = -1; +-static int hf_nfapi_frequency_hopping_enabled_flag = -1; +-static int hf_nfapi_frequency_hopping_bits = -1; +-static int hf_nfapi_new_data_indication = -1; +-static int hf_nfapi_harq_process_number = -1; +-static int hf_nfapi_ul_tx_mode = -1; +-static int hf_nfapi_current_tx_nb = -1; +-static int hf_nfapi_n_srs = -1; +-static int hf_nfapi_disable_sequence_hopping_flag = -1; +-static int hf_nfapi_dl_cqi_pmi_size_rank_1 = -1; +-static int hf_nfapi_dl_cqi_pmi_size_rank_greater_1 = -1; +-static int hf_nfapi_ri_size = -1; +-static int hf_nfapi_delta_offset_cqi = -1; +-static int hf_nfapi_delta_offset_ri = -1; +-static int hf_nfapi_harq_size = -1; +-static int hf_nfapi_delta_offset_harq = -1; +-static int hf_nfapi_ack_nack_mode = -1; +-static int hf_nfapi_n_srs_initial = -1; +-static int hf_nfapi_initial_number_of_resource_blocks = -1; +-static int hf_nfapi_dl_cqi_pmi_size = -1; +-static int hf_nfapi_report_type = -1; +-static int hf_nfapi_dl_cqi_ri_pmi_size = -1; +-static int hf_nfapi_control_type = -1; +-static int hf_nfapi_number_of_cc = -1; +-static int hf_nfapi_virtual_cell_id_enabled_flag = -1; +-static int hf_nfapi_npusch_identity = -1; +-static int hf_nfapi_ndrms_csh_identity = -1; +-static int hf_nfapi_total_number_of_repetitions = -1; +-static int hf_nfapi_repetition_number = -1; +-static int hf_nfapi_initial_sf_io = -1; +-static int hf_nfapi_empty_symbols_due_to_retunning = -1; +-static int hf_nfapi_dl_cqi_ri_pmi_size_2 = -1; +-static int hf_nfapi_npucch_identity = -1; +-static int hf_nfapi_harq_size_2 = -1; +-static int hf_nfapi_delta_offset_harq_2 = -1; +-static int hf_nfapi_empty_symbols = -1; +-static int hf_nfapi_total_number_of_repetitons = -1; +-static int hf_nfapi_csi_mode = -1; +-static int hf_nfapi_dl_cqi_pmi_size_2 = -1; +-static int hf_nfapi_statring_prb = -1; +-static int hf_nfapi_cdm_index = -1; +-static int hf_nfapi_nsrs = -1; +-static int hf_nfapi_num_ant_ports = -1; +-static int hf_nfapi_n_pucch_2_0 = -1; +-static int hf_nfapi_n_pucch_2_1 = -1; +-static int hf_nfapi_n_pucch_2_2 = -1; +-static int hf_nfapi_n_pucch_2_3 = -1; +-static int hf_nfapi_starting_prb = -1; +-static int hf_nfapi_antenna_port = -1; +-static int hf_nfapi_number_of_combs = -1; +- +- +- +-static int hf_nfapi_number_of_pucch_resource = -1; +-static int hf_nfapi_pucch_index_p1 = -1; +-static int hf_nfapi_n_pucch_1_0 = -1; +-static int hf_nfapi_n_pucch_1_1 = -1; +-static int hf_nfapi_n_pucch_1_2 = -1; +-static int hf_nfapi_n_pucch_1_3 = -1; +-static int hf_nfapi_srs_bandwidth = -1; +-static int hf_nfapi_frequency_domain_position = -1; +-static int hf_nfapi_srs_hopping_bandwidth = -1; +-static int hf_nfapi_transmission_comb = -1; +-static int hf_nfapi_i_srs = -1; +-static int hf_nfapi_sounding_reference_cyclic_shift = -1; +-static int hf_nfapi_antenna_ports = -1; +-static int hf_nfapi_ul_config_srs_pdu_rel10 = -1; +-static int hf_nfapi_ul_config_srs_pdu_rel8 = -1; +-static int hf_nfapi_ul_config_harq_information_rel9_fdd = -1; +-static int hf_nfapi_ul_config_harq_information_rel8_fdd = -1; +-static int hf_nfapi_ul_config_harq_information_rel10_tdd = -1; +-static int hf_nfapi_ul_config_sr_information_rel10 = -1; +-static int hf_nfapi_ul_config_sr_information_rel8 = -1; +-static int hf_nfapi_ul_config_cqi_information_rel10 = -1; +-static int hf_nfapi_ul_config_cqi_information_rel8 = -1; +-static int hf_nfapi_ul_config_initial_transmission_parameters_rel8 = -1; +-static int hf_nfapi_ul_config_ulsch_harq_information_rel10 = -1; +- +-/* Tx request */ +-static int hf_nfapi_pdu_length = -1; +-static int hf_nfapi_num_segments = -1; +-static int hf_nfapi_segment_length = -1; +-static int hf_nfapi_segment_data = -1; +- +-/* CRC Indication */ +-static int hf_nfapi_crc_indication_body = -1; +-static int hf_nfapi_crc_flag = -1; +- +-static int hf_nfapi_number_of_hi_pdus = -1; +-static int hf_nfapi_number_of_dci_pdus = -1; +-static int hf_nfapi_pdu_type = -1; +-static int hf_nfapi_hi_value = -1; +-static int hf_nfapi_i_phich = -1; +-static int hf_nfapi_flag_tb2 = -1; +-static int hf_nfapi_hi_value_2 = -1; +-static int hf_nfapi_ue_tx_antenna_selection = -1; +-static int hf_nfapi_cqi_csi_request = -1; +-static int hf_nfapi_ul_index = -1; +-static int hf_nfapi_dl_assignment_index = -1; +-static int hf_nfapi_tpc_bitmap = -1; +-static int hf_nfapi_new_data_indication_two = -1; +-static int hf_nfapi_size_of_cqi_csi_feild = -1; +-static int hf_nfapi_resource_allocation_flag = -1; +-static int hf_nfapi_number_of_antenna_ports =-1 ; +- +-static int hf_nfapi_n_ul_rb = -1; +-static int hf_nfapi_pscch_resource = -1; +-static int hf_nfapi_time_resource_pattern = -1; +-static int hf_nfapi_mpdcch_transmission_type = -1; +-static int hf_nfapi_drms_scrambling_init = -1; +-static int hf_nfapi_pusch_repetition_levels = -1; +-static int hf_nfapi_frequency_hopping_flag = -1; +-static int hf_nfapi_csi_request = -1; +-static int hf_nfapi_dai_presence_flag = -1; +-static int hf_nfapi_total_dci_length_include_padding = -1; +-static int hf_nfapi_data_offset = -1; +-static int hf_nfapi_ul_cqi = -1; +-static int hf_nfapi_timing_advance_r9 = -1; +-static int hf_nfapi_timing_advance = -1; +-static int hf_nfapi_harq_data_value_0 = -1; +-static int hf_nfapi_harq_data_value_1 = -1; +-static int hf_nfapi_harq_data_value_2 = -1; +-static int hf_nfapi_harq_data_value_3 = -1; +-static int hf_nfapi_harq_mode = -1; +-static int hf_nfapi_number_of_ack_nack = -1; +-static int hf_nfapi_harq_ack_nack_data = -1; +-static int hf_nfapi_harq_tb_1 = -1; +-static int hf_nfapi_harq_tb_2 = -1; +-static int hf_nfapi_harq_tb_n = -1; +-static int hf_nfapi_harq_data = -1; +-static int hf_nfapi_channel = -1; +-static int hf_nfapi_ri = -1; +-static int hf_nfapi_number_of_cc_reported = -1; +-static int hf_nfapi_cc = -1; +-static int hf_nfapi_preamble = -1; +-static int hf_nfapi_rach_resource_type = -1; +-static int hf_nfapi_snr = -1; +-static int hf_nfapi_doppler_estimation = -1; +-static int hf_nfapi_rb_start = -1; +-static int hf_nfapi_rbs = -1; +-static int hf_nfapi_up_pts_symbol = -1; +-static int hf_nfapi_number_prb_per_subband = -1; +-static int hf_nfapi_number_antennas = -1; +-static int hf_nfapi_subband_index = -1; +-static int hf_nfapi_antennas = -1; +-static int hf_nfapi_channel_coefficient = -1; +-static int hf_nfapi_ul_rtoa = -1; +-static int hf_nfapi_mp_cca = -1; +-static int hf_nfapi_n_cca = -1; +-static int hf_nfapi_offset = -1; +-static int hf_nfapi_lte_txop_sf = -1; +-static int hf_nfapi_txop_sfn_sf_end = -1; +-static int hf_nfapi_lbt_mode = -1; +-static int hf_nfapi_sfn_sf_end = -1; +-static int hf_nfapi_result = -1; +-static int hf_nfapi_txop_symbols = -1; +-static int hf_nfapi_initial_partial_sf = -1; +- +- +-static int hf_nfapi_frequency_band_indicator = -1; +-static int hf_nfapi_measurement_period = -1; +-static int hf_nfapi_bandwidth = -1; +-static int hf_nfapi_timeout = -1; +-static int hf_nfapi_number_of_earfcns = -1; +-static int hf_nfapi_earfcn_list = -1; +-static int hf_nfapi_uarfcn = -1; +-static int hf_nfapi_number_of_uarfcns = -1; +-static int hf_nfapi_uarfcn_list = -1; +-static int hf_nfapi_arfcn = -1; +-static int hf_nfapi_arfcn_direction = -1; +-static int hf_nfapi_number_of_arfcns = -1; +-static int hf_nfapi_arfcn_list = -1; +-static int hf_nfapi_rssi = -1; +-static int hf_nfapi_number_of_rssi = -1; +-static int hf_nfapi_rssi_list = -1; +-static int hf_nfapi_pci = -1; +-static int hf_nfapi_measurement_bandwidth = -1; +-static int hf_nfapi_exhaustive_search = -1; +-static int hf_nfapi_number_of_pci = -1; +-static int hf_nfapi_pci_list = -1; +-static int hf_nfapi_psc = -1; +-static int hf_nfapi_number_of_psc = -1; +-static int hf_nfapi_psc_list = -1; +-static int hf_nfapi_rsrp = -1; +-static int hf_nfapi_rsrq = -1; +-static int hf_nfapi_number_of_lte_cells_found = -1; +-static int hf_nfapi_lte_cells_found_list = -1; +-static int hf_nfapi_rscp = -1; +-static int hf_nfapi_enco = -1; +-static int hf_nfapi_number_of_utran_cells_found = -1; +-static int hf_nfapi_utran_cells_found_list = -1; +-static int hf_nfapi_bsic = -1; +-static int hf_nfapi_rxlev = -1; +-static int hf_nfapi_rxqual = -1; +-static int hf_nfapi_sfn_offset = -1; +-static int hf_nfapi_number_of_geran_cells_found = -1; +-static int hf_nfapi_geran_cells_found_list = -1; +-static int hf_nfapi_number_of_tx_antenna = -1; +-static int hf_nfapi_mib_length = -1; +-static int hf_nfapi_mib = -1; +-static int hf_nfapi_phich_configuration = -1; +-static int hf_nfapi_retry_count = -1; +-static int hf_nfapi_sib1 = -1; +-static int hf_nfapi_si_periodicity = -1; +-static int hf_nfapi_si_index = -1; +-static int hf_nfapi_number_of_si_periodicity = -1; +-static int hf_nfapi_si_periodicity_list = -1; +-static int hf_nfapi_si_window_length = -1; +-static int hf_nfapi_sib_type = -1; +-static int hf_nfapi_sib_len = -1; +-static int hf_nfapi_sib = -1; +-static int hf_nfapi_si_len = -1; +-static int hf_nfapi_si = -1; +- +-static int hf_nfapi_pnf_search_state = -1; +-static int hf_nfapi_pnf_broadcast_state = -1; +- +-static const value_string message_id_vals[] = { { 0x80, "DL_CONFIG.request"}, +- { 0x81, "UL_CONFIG.request"}, +- { 0x82, "SUBFRAME_INDICATION"}, +- { 0x83, "HI_DCI0.request"}, +- { 0x84, "TX.request"}, +- { 0x85, "HARQ.indication"}, +- { 0x86, "CRC.indication"}, +- { 0x87, "RX_ULSCH.indication"}, +- { 0x88, "RACH.indication" }, +- { 0x89, "SRS.indication" }, +- { 0x8A, "RX_SR.indication" }, +- { 0x8B, "RX_CQI.indication" }, +- { 0x8C, "LBT_DL_CONFIG.request" } , +- { 0x8D, "LBT_DL.indication" } , +- +- { 0x0100, "PNF_PARAM.request" }, +- { 0x0101, "PNF_PARAM.response" }, +- { 0x0102, "PNF_CONFIG.request" }, +- { 0x0103, "PNF_CONFIG.response" }, +- { 0x0104, "PNF_START.request" }, +- { 0x0105, "PNF_START.response" }, +- { 0x0106, "PNF_STOP.request" }, +- { 0x0107, "PNF_STOP.response" }, +- { 0x0108, "PARAM.request" }, +- { 0x0109, "PARAM.response" }, +- { 0x010A, "CONFIG.request" }, +- { 0x010B, "CONFIG.response" }, +- { 0x010C, "START.request" }, +- { 0x010D, "START.response" }, +- { 0x010E, "STOP.request" }, +- { 0x010F, "STOP.response" }, +- { 0x0110, "MEASUREMENT.request" }, +- { 0x0111, "MEASUREMENT.response" }, +- +- { 0x0180, "UL_NODE_SYNC" }, +- { 0x0181, "DL_NODE_SYNC" }, +- { 0x0182, "TIMING_INFO" }, +- +- { 0x0200, "RSSI.request" }, +- { 0x0201, "RSSI.response" }, +- { 0x0202, "RSSI.indication" }, +- { 0x0203, "CELL_SEARCH.request" }, +- { 0x0204, "CELL_SEARCH.response" }, +- { 0x0205, "CELL_SEARCH.indication" }, +- { 0x0206, "BROADCAST_DETECT.request" }, +- { 0x0207, "BROADCAST_DETECT.response" }, +- { 0x0208, "BROADCAST_DETECT.indication" }, +- { 0x0209, "SYSTEM_INFORMATION_SCHEDULE.request" }, +- { 0x020A, "SYSTEM_INFORMATION_SCHEDULE.response" }, +- { 0x020B, "SYSTEM_INFORMATION_SCHEDULE.indication" }, +- { 0x020C, "SYSTEM_INFORMATION.request" }, +- { 0x020D, "SYSTEM_INFORMATION.response" }, +- { 0x020E, "SYSTEM_INFORMATION.indication" }, +- { 0x020F, "NMM_STOP.request" }, +- { 0x0210, "NMM_STOP.response" }, +- +- { 0 , NULL }, +-}; +- +- +-typedef int(*tlv_decode)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end); +- +-typedef struct +-{ +- uint16_t tag_id; +- char* name; +- tlv_decode decode; +-} tlv_t; +- +-static int dissect_tlv_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint end); +- +- +- +- +-static guint8 proto_tree_add_uint8(proto_tree *tree, int hfindex, tvbuff_t *tvb, guint* offset, char* units) +-{ +- guint8 value = tvb_get_guint8(tvb, *offset); +- proto_item * item = proto_tree_add_item(tree, hfindex, tvb, *offset, 1, ENC_NA); +- +- if (units != NULL) +- { +- proto_item_append_text(item, " "); +- proto_item_append_text(item, units); +- } +- +- *offset += 1; +- +- return value; +-} +- +-static guint8 proto_tree_add_uint8_with_range(proto_tree *tree, int hfindex, tvbuff_t *tvb, guint* offset, packet_info *pinfo, guint8 min, guint8 max, char* units) +-{ +- guint8 value = tvb_get_guint8(tvb, *offset); +- proto_item * item = proto_tree_add_item(tree, hfindex, tvb, *offset, 1, ENC_NA); +- +- if (units != NULL) +- { +- proto_item_append_text(item, " "); +- proto_item_append_text(item, units); +- } +- +- *offset += 1; +- +- if (value < min || value > max) +- { +- expert_add_info(pinfo, tree, &ei_invalid_range); +- } +- +- +- return value; +-} +- +-static guint16 proto_tree_add_uint16(proto_tree *tree, int hfindex, tvbuff_t *tvb, guint* offset, char* units) +-{ +- guint16 value = tvb_get_guint16(tvb, *offset, ENC_NA); +- proto_item * item = proto_tree_add_item(tree, hfindex, tvb, *offset, 2, ENC_NA); +- +- if (units != NULL) +- { +- proto_item_append_text(item, " "); +- proto_item_append_text(item, units); +- } +- +- *offset += 2; +- +- return value; +-} +- +-static void proto_tree_add_int16(proto_tree *tree, int hfindex, tvbuff_t *tvb, guint* offset, char* units) +-{ +- proto_item * item = proto_tree_add_item(tree, hfindex, tvb, *offset, 2, ENC_NA); +- +- if (units != NULL) +- { +- proto_item_append_text(item, " "); +- proto_item_append_text(item, units); +- } +- +- *offset += 2; +-} +- +-typedef int(*uint8_value_conversion)(proto_item* tree, int hfindex, tvbuff_t *tvb, guint* offset, guint8 value); +- +-static guint8 proto_tree_add_uint8_with_conversion(proto_tree *tree, int hfindex, tvbuff_t *tvb, guint* offset, uint8_value_conversion conversion) +-{ +- guint8 value = tvb_get_guint8(tvb, *offset); +- +- conversion(tree, hfindex, tvb, offset, value); +- +- *offset += 1; +- +- return value; +-} +- +-typedef int(*uint16_value_conversion)(proto_item* tree, int hfindex, tvbuff_t *tvb, guint* offset, guint16 value); +- +-static guint16 proto_tree_add_uint16_with_conversion(proto_tree *tree, int hfindex, tvbuff_t *tvb, guint* offset, uint16_value_conversion conversion) +-{ +- guint16 value = tvb_get_guint16(tvb, *offset, ENC_NA); +- +- conversion(tree, hfindex, tvb, offset, value); +- +- *offset += 2; +- +- return value; +-} +- +-typedef int(*int16_value_conversion)(proto_item* tree, int hfindex, tvbuff_t *tvb, guint* offset, gint16 value); +- +-static gint16 proto_tree_add_int16_with_conversion(proto_tree *tree, int hfindex, tvbuff_t *tvb, guint* offset, int16_value_conversion conversion) +-{ +- gint16 value = (gint16)(tvb_get_guint16(tvb, *offset, ENC_NA)); +- +- conversion(tree, hfindex, tvb, offset, value); +- +- *offset += 2; +- +- return value; +-} +- +- +-static void proto_tree_add_uint32(proto_tree *tree, int hfindex, tvbuff_t *tvb, guint* offset, char* units) +-{ +- proto_item * item = proto_tree_add_item(tree, hfindex, tvb, *offset, 4, ENC_NA); +- +- if (units != NULL) +- { +- proto_item_append_text(item, " "); +- proto_item_append_text(item, units); +- } +- +- *offset += 4; +-} +- +-static void proto_tree_add_uint8_array(proto_tree *tree, int hfindex, guint len, tvbuff_t *tvb, guint* offset) +-{ +- proto_tree_add_item(tree, hfindex, tvb, *offset, len, ENC_NA); +- +- *offset += len; +-} +- +- +- +- +- +-int dissect_array_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end, const char* name, guint32 hf_idx, guint32 ett_idx, guint32 count, tlv_decode decode) +-{ +- guint16 i = 0; +- +- if (count > 0) +- { +- proto_item *list_ti = proto_tree_add_string_format(tree, hf_idx, tvb, *offset, 2, "", name); +- proto_tree *list_tree = proto_item_add_subtree(list_ti, ett_idx); +- +- gint start_of_list = *offset; +- +- for (i = 0; i < count; ++i) +- { +- proto_item *item_ti = proto_tree_add_string_format(list_tree, hf_idx, tvb, *offset, 2, "", "[%d]", i); +- proto_tree *item_tree = proto_item_add_subtree(item_ti, ett_idx); +- +- gint start_of_item = *offset; +- +- decode(tvb, pinfo, item_tree, data, offset, end); +- +- if (item_ti != NULL) +- item_ti->finfo->length = *offset - start_of_item; +- } +- +- if (list_ti != NULL) +- list_ti->finfo->length = *offset - start_of_list; +- } +- +- return 0; +-} +- +-int dissect_pnf_param_general_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_sync_mode, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_location_mode, tvb, offset, 0); +- guint16 len = proto_tree_add_uint16(tree, hf_nfapi_location_coordinates_length, tvb, offset, 0); +- if (len > 0) +- proto_tree_add_uint8_array(tree, hf_nfapi_location_coordinates, len, tvb, offset); +- proto_tree_add_uint32(tree, hf_nfapi_dl_config_timing, tvb, offset, "milliseconds"); +- proto_tree_add_uint32(tree, hf_nfapi_tx_timing, tvb, offset, "milliseconds"); +- proto_tree_add_uint32(tree, hf_nfapi_ul_config_timing, tvb, offset, "milliseconds"); +- proto_tree_add_uint32(tree, hf_nfapi_hi_dci0_timing, tvb, offset, "milliseconds"); +- proto_tree_add_uint16(tree, hf_nfapi_maximum_number_phys, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_maximum_total_bandwidth, tvb, offset, "(100 khz)"); +- proto_tree_add_uint8(tree, hf_nfapi_maximum_total_number_dl_layers, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_maximum_total_number_ul_layers, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_shared_bands, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_shared_pa, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_maximum_total_power, tvb, offset, 0); +- proto_tree_add_uint8_array(tree, hf_nfapi_oui, 3, tvb, offset); +- +- return 0; +-} +- +-int dissect_pnf_rf_config_instance_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_rf_config_index, tvb, offset, 0); +- return 0; +-} +- +-int dissect_pnf_phy_instance_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_pnf_phy_config_index, tvb, offset, 0); +- guint16 num_rf_configs = proto_tree_add_uint16(tree, hf_nfapi_number_of_rfs, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "RF Config List", hf_nfapi_pnf_phy, ett_nfapi_pnf_phy, num_rf_configs, dissect_pnf_rf_config_instance_value); +- guint16 num_rf_exclusions = proto_tree_add_uint16(tree, hf_nfapi_number_of_rf_exclusions, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "RF Exclustion List", hf_nfapi_pnf_phy, ett_nfapi_pnf_phy, num_rf_exclusions, dissect_pnf_rf_config_instance_value); +- proto_tree_add_uint16(tree, hf_nfapi_downlink_channel_bandwidth_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_uplink_channel_bandwidth_supported, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_dl_layers_supported, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_ul_layers_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_maximum_3gpp_release_supported, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_nmm_modes_supported, tvb, offset, 0); +- return 0; +-} +- +-int dissect_pnf_phy_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_phy = proto_tree_add_uint16(tree, hf_nfapi_pnf_phy_number_phy, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "PHY List", hf_nfapi_pnf_phy, ett_nfapi_pnf_phy, num_phy, dissect_pnf_phy_instance_value); +- +- +- return 0; +- +-} +- +- +-int dissect_pnf_rf_config_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_rf_config_index, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_band, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_maximum_transmit_power, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_minimum_transmit_power, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_antennas_suppported, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_minimum_downlink_frequency, tvb, offset, "(100 khz)"); +- proto_tree_add_uint32(tree, hf_nfapi_maximum_downlink_frequency, tvb, offset, "(100 khz)"); +- proto_tree_add_uint32(tree, hf_nfapi_minimum_uplink_frequency, tvb, offset, "(100 khz)"); +- proto_tree_add_uint32(tree, hf_nfapi_maximum_uplink_frequency, tvb, offset, "(100 khz)"); +- +- return 0; +-} +- +- +-int dissect_pnf_rf_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_rf = proto_tree_add_uint16(tree, hf_nfapi_number_of_rfs, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "RF List", hf_nfapi_pnf_phy_rf_config_array_phy_rf_config_info, ett_nfapi_pnf_phy_rf_config, num_rf, dissect_pnf_rf_config_value); +- +- return 0; +- +-} +- +-int dissect_pnf_phy_rel10_instance_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_pnf_phy_config_index, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_transmission_mode7_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hi_nfapi_transmission_mode8_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hi_nfapi_two_antennas_ports_for_pucch, tvb, offset, 0); +- proto_tree_add_uint16(tree, hi_nfapi_transmission_mode_9_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hi_nfapi_simultaneous_pucch_pusch, tvb, offset, 0); +- proto_tree_add_uint16(tree, hi_nfapi_for_layer_tx_with_tm3_and_tm4, tvb, offset, 0); +- +- return 0; +-} +- +-int dissect_pnf_phy_rel10_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_phy = proto_tree_add_uint16(tree, hf_nfapi_pnf_phy_number_phy, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "PHY Rel 10 List", hf_nfapi_pnf_phy, ett_nfapi_pnf_phy_rel10, num_phy, dissect_pnf_phy_rel10_instance_value); +- +- return 0; +-} +- +-int dissect_pnf_phy_rel11_instance_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_pnf_phy_config_index, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_epdcch_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hi_nfapi_multi_ack_csi_reporting, tvb, offset, 0); +- proto_tree_add_uint16(tree, hi_nfapi_pucch_tx_diversity_with_channel_selection, tvb, offset, 0); +- proto_tree_add_uint16(tree, hi_nfapi_ul_comp_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hi_nfapi_transmission_mode_5_supported, tvb, offset, 0); +- return 0; +-} +- +-int dissect_pnf_phy_rel11_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_phy = proto_tree_add_uint16(tree, hf_nfapi_pnf_phy_number_phy, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "PHY Rel 11 List", hf_nfapi_pnf_phy, ett_nfapi_pnf_phy_rel11, num_phy, dissect_pnf_phy_rel11_instance_value); +- return 0; +-} +- +-int dissect_pnf_phy_rel12_instance_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_pnf_phy_config_index, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_csi_subframe_set, tvb, offset, 0); +- proto_tree_add_uint16(tree, hi_nfapi_enhanced_4tx_codebook, tvb, offset, 0); +- proto_tree_add_uint16(tree, hi_nfapi_drs_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hi_nfapi_ul_64qam_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hi_nfapi_transmission_mode_10_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hi_nfapi_alternative_tbs_indices, tvb, offset, 0); +- return 0; +-} +- +-int dissect_pnf_phy_rel12_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_phy = proto_tree_add_uint16(tree, hf_nfapi_pnf_phy_number_phy, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "PHY Rel 12 List", hf_nfapi_pnf_phy, ett_nfapi_pnf_phy_rel12, num_phy, dissect_pnf_phy_rel12_instance_value); +- return 0; +-} +- +-int dissect_pnf_phy_rel13_instance_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_pnf_phy_config_index, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_pucch_format_4_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_pucch_format_5_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_more_than_5_ca_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_laa_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_laa_ending_in_dwpts_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_laa_starting_in_second_slot_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_beamforming_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_csi_rs_enhancements_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_drms_enhancements_supported, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_srs_enhancements_supported, tvb, offset, 0); +- return 0; +-} +- +-int dissect_pnf_phy_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_phy = proto_tree_add_uint16(tree, hf_nfapi_pnf_phy_number_phy, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "PHY Rel 13 List", hf_nfapi_pnf_phy, ett_nfapi_pnf_phy_rel13, num_phy, dissect_pnf_phy_rel13_instance_value); +- return 0; +-} +- +-int dissect_pnf_phy_rf_config_instance_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_phy_rf_config_info_phy_id, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_pnf_phy_config_index, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_rf_config_index, tvb, offset, 0); +- return 0; +-} +- +- +-int dissect_pnf_phy_rf_config_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_configs = proto_tree_add_uint16(tree, hf_nfapi_pnf_phy_number_phy, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "PHY RF Config List", hf_nfapi_pnf_phy_rf_config, ett_nfapi_pnf_phy_rf_config, num_configs, dissect_pnf_phy_rf_config_instance_value); +- return 0; +-} +- +-int bandwidth_conversion(proto_item* tree, int hfindex, tvbuff_t *tvb, guint* offset, guint16 value) +-{ +- /* +- guint8 comma = 0; +- +- proto_item_append_text(item, "("); +- +- if (value & 0x1) +- { +- proto_item_append_text(item, "6 Mhz"); +- comma = 1; +- } +- +- if (comma) +- proto_item_append_text(item, ", "); +- +- if (value & 0x2) +- { +- proto_item_append_text(item, "15 Mhz"); +- comma = 1; +- } +- +- if (comma) +- proto_item_append_text(item, ", "); +- +- if (value & 0x4) +- { +- proto_item_append_text(item, "25 Mhz"); +- comma = 1; +- } +- +- if (comma) +- proto_item_append_text(item, ", "); +- +- if (value & 0x8) +- { +- proto_item_append_text(item, "50 Mhz"); +- comma = 1; +- } +- +- if (comma) +- proto_item_append_text(item, ", "); +- +- if (value & 0x10) +- { +- proto_item_append_text(item, "75 Mhz"); +- comma = 1; +- } +- +- if (comma) +- proto_item_append_text(item, ", "); +- +- if (value & 0x20) +- { +- proto_item_append_text(item, "100 Mhz"); +- comma = 1; +- } +- +- proto_item_append_text(item, ")"); +- */ +- proto_tree_add_uint_format_value(tree, hfindex, tvb, *offset, 2, value, "?? (%d)", value); +- return 0; +- +-} +- +-int sfn_sf_conversion(proto_item* tree, int hfindex, tvbuff_t *tvb, guint* offset, guint16 value) +-{ +- proto_tree_add_uint_format_value(tree, hfindex, tvb, *offset, 2, value, "%d/%d (%d)", value >> 3, value & 0x0007, value); +- return 0; +-} +- +- +-int dissect_duplex_mode_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_duplex_mode, tvb, offset, 0); +- return 0; +-} +- +-int power_offset_conversion(proto_item* tree, int hfindex, tvbuff_t *tvb, guint* offset, guint16 value) +-{ +- proto_tree_add_uint_format_value(tree, hfindex, tvb, *offset, 2, value, "%.2f dB (%d)", (((float)value * 0.001) - 6.0), value); +- return 0; +-} +- +-int dissect_pcfich_power_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 value = proto_tree_add_uint16_with_conversion(tree, hf_nfapi_pcfich_power_offset, tvb, offset, power_offset_conversion); +- +- if (value > 10000) +- { +- expert_add_info(pinfo, tree, &ei_power_invalid); +- } +- +- return 0; +-} +- +-int dissect_pb_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 value = proto_tree_add_uint16(tree, hf_nfapi_pb, tvb, offset, 0); +- +- if (value > 3) +- { +- expert_add_info(pinfo, tree, &ei_power_invalid); +- } +- return 0; +-} +- +-int dissect_dl_cyclic_prefix_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_dl_cyclic_prefix_type, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_cyclic_prefix_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_ul_cyclic_prefix_type, tvb, offset, 0); +- return 0; +-} +-int dissect_dl_channel_bandwidth_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_downlink_channel_bandwidth, tvb, offset, bandwidth_conversion); +- return 0; +-} +-int dissect_ul_channel_bandwidth_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_uplink_channel_bandwidth, tvb, offset, bandwidth_conversion); +- return 0; +-} +- +- +-int reference_signal_power_conversion(proto_item* tree, int hfindex, tvbuff_t *tvb, guint* offset, guint16 value) +-{ +- proto_tree_add_uint_format_value(tree, hfindex, tvb, *offset, 2, value, "%.2f dB (%d)", (((float)value * 0.25) - 63.75), value); +- return 0; +-} +- +-int dissect_reference_signal_power_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_reference_signal_power, tvb, offset, reference_signal_power_conversion); +- return 0; +-} +-int dissect_tx_antenna_ports_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_tx_antenna_ports, tvb, offset, 0); +- return 0; +-} +-int dissect_rx_antenna_ports_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_rx_antenna_ports, tvb, offset, 0); +- return 0; +-} +-int dissect_phich_resource_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_phich_resource, tvb, offset, 0); +- return 0; +-} +-int dissect_phich_duration_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_phich_duration, tvb, offset, 0); +- return 0; +-} +-int dissect_phich_power_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_phich_power_offset, tvb, offset, power_offset_conversion); +- return 0; +-} +-int dissect_psch_synch_signal_epre_eprers_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_primary_synchronization_signal_epre_eprers, tvb, offset, power_offset_conversion); +- return 0; +-} +-int dissect_physical_cell_id_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_physical_cell_id, tvb, offset, 0); +- return 0; +-} +-int dissect_ssch_synch_signal_epre_eprers_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_secondary_synchronization_signal_epre_eprers, tvb, offset, power_offset_conversion); +- return 0; +-} +-int dissect_prach_configuration_index_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_configuration_index, tvb, offset, 0); +- return 0; +-} +-int dissect_prach_root_sequence_index_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_root_sequence_index, tvb, offset, 0); +- return 0; +-} +-int dissect_prach_zero_correlation_zone_configuration_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_zero_correlation_zone_configuration, tvb, offset, 0); +- return 0; +-} +-int dissect_prach_high_speed_flag_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_high_speed_flag, tvb, offset, 0); +- return 0; +-} +-int dissect_prach_frequency_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_frequency_offset, tvb, offset, 0); +- return 0; +-} +-int dissect_pusch_hopping_mode_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_hopping_mode, tvb, offset, 0); +- return 0; +-} +-int dissect_pusch_hopping_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_hopping_offset, tvb, offset, 0); +- return 0; +-} +-int dissect_pusch_number_of_subbands_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_number_of_subbands, tvb, offset, 0); +- return 0; +-} +-int dissect_pucch_delta_pucch_shift_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_delta_pucch_shift, tvb, offset, 0); +- return 0; +-} +-int dissect_pucch_n_cqi_rb_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_n_cqi_rb, tvb, offset, 0); +- return 0; +-} +-int dissect_pucch_n_an_cs_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_n_an_cs, tvb, offset, 0); +- return 0; +-} +-int dissect_pucch_n1_pucch_an_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_n1_pucch_an, tvb, offset, 0); +- return 0; +-} +-int dissect_srs_bandwidth_configuration_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_bandwidth_configuration, tvb, offset, 0); +- return 0; +-} +-int dissect_srs_max_uppts_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_max_up_pts, tvb, offset, 0); +- return 0; +-} +-int dissect_srs_subframe_configuration_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_srs_subframe_configuration, tvb, offset, 0); +- return 0; +-} +-int dissect_srs_acknack_srs_sim_tx_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_srs_acknack_srs_simultaneous_transmission, tvb, offset, 0); +- return 0; +-} +-int dissect_uplink_rs_hopping_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_uplink_rs_hopping, tvb, offset, 0); +- return 0; +-} +-int dissect_group_assignment_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_group_assignment, tvb, offset, 0); +- return 0; +-} +-int dissect_cyclic_shift_1_for_drms_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_cyclic_shift_1_for_drms, tvb, offset, 0); +- return 0; +-} +-int dissect_tdd_subframe_assignement_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_subframe_assignment, tvb, offset, 0); +- return 0; +-} +-int dissect_tdd_subframe_patterns_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_special_subframe_patterns, tvb, offset, 0); +- return 0; +-} +- +-int laa_threshold_conversion(proto_item* tree, int hfindex, tvbuff_t *tvb, guint* offset, guint16 value) +-{ +- proto_tree_add_uint_format_value(tree, hfindex, tvb, *offset, 2, value, "%.2f dB (%d)", (float)(value * -100.00), value); +- return 0; +-} +- +-int dissect_laa_ed_threashold_for_lbt_for_pdsch_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_ed_threshold_for_lbt_for_pdsch, tvb, offset, laa_threshold_conversion); +- return 0; +-} +-int dissect_laa_ed_threashold_for_lbt_for_drs_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_ed_threshold_for_lbt_for_drs, tvb, offset, laa_threshold_conversion); +- return 0; +-} +-int dissect_laa_pd_threshold_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_pd_threshold, tvb, offset, laa_threshold_conversion); +- return 0; +-} +-int dissect_laa_multi_carrier_type_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_multi_carrier_type, tvb, offset, 0); +- return 0; +-} +-int dissect_laa_multi_carrier_tx_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_multi_carrier_tx, tvb, offset, 0); +- return 0; +-} +-int dissect_laa_multi_carrier_freeze_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_multi_carrier_freeze, tvb, offset, 0); +- return 0; +-} +-int dissect_laa_tx_antenna_port_for_drs_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_tx_antenna_ports_for_drs, tvb, offset, 0); +- return 0; +-} +-int dissect_laa_transmission_power_for_drs_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_transmission_power_for_drs, tvb, offset, power_offset_conversion); +- return 0; +-} +- +-int dissect_emtc_pbch_repeitions_enabled_r13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_pbch_repetitions_enabled_r13, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_prach_cat_m_root_sequence_index_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_cat_m_root_sequence_index, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_prach_cat_m_zero_correlation_zone_configuration_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_cat_m_zero_correlation_zone_configuration, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_prach_cat_m_high_speed_flag_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_cat_m_high_speed_flag, tvb, offset, 0); +- return 0; +-} +- +-int dissect_emtc_prach_ce_level_0_enabled_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_0_enable, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_prach_ce_level_0_configuration_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_0_configuration_index, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_prach_ce_level_0_frequency_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_0_frequency_offset, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_preach_ce_level_0_num_of_repeitions_per_attempt_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_0_number_of_repetitions_per_attempt, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_ce_level_0_starting_subframe_periodicity_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_0_starting_subframe_periodicity, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_preach_ce_level_0_hopping_enabled_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_0_hopping_enabled, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_preach_ce_level_0_hopping_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_0_hopping_offset, tvb, offset, 0); +- return 0; +-} +- +-int dissect_emtc_prach_ce_level_1_enabled_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_1_enable, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_prach_ce_level_1_configuration_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_1_configuration_index, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_prach_ce_level_1_frequency_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_1_frequency_offset, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_preach_ce_level_1_num_of_repeitions_per_attempt_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_1_number_of_repetitions_per_attempt, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_ce_level_1_starting_subframe_periodicity_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_1_starting_subframe_periodicity, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_preach_ce_level_1_hopping_enabled_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_1_hopping_enabled, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_preach_ce_level_1_hopping_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_1_hopping_offset, tvb, offset, 0); +- return 0; +-} +- +-int dissect_emtc_prach_ce_level_2_enabled_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_2_enable, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_prach_ce_level_2_configuration_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_2_configuration_index, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_prach_ce_level_2_frequency_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_2_frequency_offset, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_preach_ce_level_2_num_of_repeitions_per_attempt_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_2_number_of_repetitions_per_attempt, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_ce_level_2_starting_subframe_periodicity_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_2_starting_subframe_periodicity, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_preach_ce_level_2_hopping_enabled_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_2_hopping_enabled, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_preach_ce_level_2_hopping_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_2_hopping_offset, tvb, offset, 0); +- return 0; +-} +- +-int dissect_emtc_prach_ce_level_3_enabled_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_3_enable, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_prach_ce_level_3_configuration_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_3_configuration_index, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_prach_ce_level_3_frequency_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_3_frequency_offset, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_preach_ce_level_3_num_of_repeitions_per_attempt_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_3_number_of_repetitions_per_attempt, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_ce_level_3_starting_subframe_periodicity_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_3_starting_subframe_periodicity, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_preach_ce_level_3_hopping_enabled_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_3_hopping_enabled, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_preach_ce_level_3_hopping_offset_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_prach_ce_level_3_hopping_offset, tvb, offset, 0); +- return 0; +-} +- +-int dissect_emtc_pucch_interval_ul_hopping_config_common_mode_a_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_pucch_internal_ul_hopping_config_common_mode_a, tvb, offset, 0); +- return 0; +-} +-int dissect_emtc_pucch_interval_ul_hopping_config_common_mode_b_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_pucch_internal_ul_hopping_config_common_mode_b, tvb, offset, 0); +- return 0; +-} +- +- +-int dissect_dl_bandwidth_support_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_dl_bandwidth_support, tvb, offset, bandwidth_conversion); +- return 0; +-} +- +-int dissect_ul_bandwidth_support_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_ul_bandwidth_support, tvb, offset, bandwidth_conversion); +- return 0; +-} +- +-int dl_modulation_conversion(proto_item* tree, int hfindex, tvbuff_t *tvb, guint* offset, guint16 value) +-{ +- proto_tree_add_uint_format_value(tree, hfindex, tvb, *offset, 2, value, "?? (%d)", value); +- return 0; +-} +- +-int dissect_dl_modulation_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_dl_modulation_support, tvb, offset, dl_modulation_conversion); +- return 0; +-} +- +-int ul_modulation_conversion(proto_item* tree, int hfindex, tvbuff_t *tvb, guint* offset, guint16 value) +-{ +- proto_tree_add_uint_format_value(tree, hfindex, tvb, *offset, 2, value, "?? (%d)", value); +- return 0; +-} +-int dissect_ul_modulation_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_ul_modulation_support, tvb, offset, ul_modulation_conversion); +- return 0; +-} +-int dissect_phy_antenna_capability_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_phy_antenna_capability, tvb, offset, 0); +- return 0; +-} +- +-int release_capability_conversion(proto_item* tree, int hfindex, tvbuff_t *tvb, guint* offset, guint16 value) +-{ +- proto_tree_add_uint_format_value(tree, hfindex, tvb, *offset, 2, value, "?? (%d)", value); +- return 0; +-} +-int dissect_release_capability_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_release_capability, tvb, offset, release_capability_conversion); +- return 0; +-} +-int dissect_mbsfn_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_mbsfn_capability, tvb, offset, 0); +- return 0; +-} +- +-int dissect_laa_support_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_laa_capability, tvb, offset, 0); +- return 0; +-} +-int dissect_laa_pd_sensing_lbt_support_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_pd_sensing_lbt_support, tvb, offset, 0); +- return 0; +-} +-int dissect_laa_multi_carrier_lbt_support_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_multi_carrier_lbt_support, tvb, offset, 0); +- return 0; +-} +-int dissect_laa_partial_sf_support_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_partial_sf_support, tvb, offset, 0); +- return 0; +-} +- +-int dissect_data_report_mode_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_data_report_mode, tvb, offset, 0); +- return 0; +-} +-int dissect_sfn_sf_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_sfnsf, tvb, offset, 0); +- return 0; +-} +-int dissect_phy_state_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_phy_state, tvb, offset, 0); +- return 0; +-} +- +- +- +-int dissect_p7_vnf_address_ipv4_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8_array(tree, hf_nfapi_vnf_address_ipv4, 4, tvb, offset); +- return 0; +-} +-int dissect_p7_vnf_address_ipv6_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8_array(tree, hf_nfapi_vnf_address_ipv4, 16, tvb, offset); +- return 0; +-} +-int dissect_p7_vnf_port_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_vnf_port, tvb, offset, 0); +- return 0; +-} +- +-int dissect_p7_pnf_address_ipv4_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8_array(tree, hf_nfapi_pnf_address_ipv4, 4, tvb, offset); +- return 0; +-} +-int dissect_p7_pnf_address_ipv6_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8_array(tree, hf_nfapi_pnf_address_ipv4, 16, tvb, offset); +- return 0; +-} +-int dissect_p7_pnf_port_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_pnf_port, tvb, offset, 0); +- return 0; +-} +- +-int dissect_downlink_ues_per_subframe_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_dl_ue_per_sf, tvb, offset, 0); +- return 0; +-} +- +-int dissect_uplink_ues_per_subframe_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_ul_ue_per_sf, tvb, offset, 0); +- return 0; +-} +- +-int dissect_rf_band_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_band, tvb, offset, 0); +- return 0; +-} +- +-int dissect_rf_bands_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 count = proto_tree_add_uint16(tree, hf_nfapi_number_of_rf_bands, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "RF Band List", hf_nfapi_rf_bands, ett_nfapi_rf_bands, count, dissect_rf_band_value); +- return 0; +-} +- +-int dissect_timing_window_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_timing_window, tvb, offset, 0); +- return 0; +-} +-int dissect_timing_info_mode_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_timing_info_mode, tvb, offset, 0); +- return 0; +-} +-int dissect_timing_info_period_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_timing_info_period, tvb, offset, 0); +- return 0; +-} +- +-int dissect_maximum_transmit_power_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_maximum_transmit_power, tvb, offset, 0); +- return 0; +-} +-int dissect_earfcn_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_earfcn, tvb, offset, 0); +- return 0; +-} +- +-int dissect_nmm_gsm_frequency_bands_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 count = proto_tree_add_uint16(tree, hf_nfapi_number_of_rf_bands, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "RF Band List", hf_nfapi_rf_bands, ett_nfapi_rf_bands, count, dissect_rf_band_value); +- return 0; +-} +-int dissect_nmm_umts_frequency_bands_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 count = proto_tree_add_uint16(tree, hf_nfapi_number_of_rf_bands, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "RF Band List", hf_nfapi_rf_bands, ett_nfapi_rf_bands, count, dissect_rf_band_value); +- return 0; +-} +-int dissect_nmm_lte_frequency_bands_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 count = proto_tree_add_uint16(tree, hf_nfapi_number_of_rf_bands, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "RF Band List", hf_nfapi_rf_bands, ett_nfapi_rf_bands, count, dissect_rf_band_value); +- return 0; +-} +-int dissect_nmm_uplink_rssi_supported_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_nmm_uplink_rssi_supported, tvb, offset, 0); +- return 0; +-} +- +-int dissect_dl_config_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_dl_config_pdu_type, tvb, offset, 0); +- guint8 size = proto_tree_add_uint8(tree, hf_nfapi_pdu_size, tvb, offset, 0); +- +- guint pdu_end = (*offset + size - 2); +- dissect_tlv_list(tvb, pinfo, tree, data, offset, pdu_end); +- +- return 0; +-} +- +- +-static int dissect_dl_config_request_body_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_number_pdcch_ofdm_symbols, tvb, offset, 0); +- guint16 num_pdu = proto_tree_add_uint8(tree, hf_nfapi_number_dci, tvb, offset, 0); +- num_pdu += proto_tree_add_uint16(tree, hf_nfapi_number_pdus, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_pdsch_rnti, tvb, offset, 0); +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_transmission_power_pcfich, tvb, offset, power_offset_conversion); +- +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "DL Config PDU List", hf_nfapi_dl_config_request_pdu_list, ett_nfapi_dl_config_request_pdu_list, num_pdu, dissect_dl_config_pdu); +- +- +- return 0; +-} +- +-static int dissect_dl_config_request_bch_pdu_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_length, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_pdu_index, tvb, offset, 0); +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_transmission_power, tvb, offset, power_offset_conversion); +- return 0; +-} +- +-static int dissect_dl_config_request_dl_dci_pdu_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_dci_format, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_cce_idx, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_aggregation_level, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_rnti, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_resource_allocation_type, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_virtual_resource_block_assignment_flag, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_resource_block_coding, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_mcs_1, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_redundancy_version_1, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_new_data_indicator_1, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_transport_block_to_codeword_swap_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_mcs_2, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_redundancy_version_2, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_new_data_indicator_2, tvb, offset, 0); +- proto_tree_add_uint8_with_range(tree, hf_nfapi_harq_process, tvb, offset, pinfo, 0, 15, 0); +- proto_tree_add_uint8(tree, hf_nfapi_tpmi, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_precoding_information, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_tpc, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_downlink_assignment_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ngap, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_transport_block_size_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_downlink_power_offset, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_allocate_prach_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_preamble_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_prach_mask_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_rnti_type, tvb, offset, 0); +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_transmission_power, tvb, offset, power_offset_conversion); +- return 0; +-} +-static int dissect_dl_config_request_dl_dci_pdu_rel9_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_mcch_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_mcch_change_notification, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_scrambling_identity, tvb, offset, 0); +- return 0; +-} +-static int dissect_dl_config_request_dl_dci_pdu_rel10_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_cross_carrier_scheduling_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_carrier_indicator, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_size_of_cqi_csi_feild, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_srs_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_srs_request, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_antenna_ports_scrambling_and_layers, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_total_dci_length_including_padding, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_n_dl_rb, tvb, offset, 0); +- return 0; +-} +-static int dissect_dl_config_request_dl_dci_pdu_rel11_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_harq_ack_resource_offset, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_pdsch_re_mapping_and_quasi_co_location_indicator, tvb, offset, 0); +- return 0; +-} +- +-int dissect_ul_dl_configuration_index_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_ul_dl_configuration_index, tvb, offset, 0); +- return 0; +-} +- +- +-static int dissect_dl_config_request_dl_dci_pdu_rel12_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_primary_cell_type, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ul_dl_configuration_flag, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_number_of_ul_dl_configurations, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "UL/DL Configurations", hf_nfapi_pnf_phy, ett_nfapi_pnf_phy, count, dissect_ul_dl_configuration_index_value); +- +- return 0; +-} +-static int dissect_dl_config_request_dl_dci_pdu_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_laa_end_partial_sf_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_laa_end_partial_sf_configuration, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_initial_lbt_sf, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_codebooksize_determination_r13, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_rel13_drms_table_flag, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_dl_config_request_mch_pdu_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_length, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_pdu_index, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_rnti, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_resource_allocation_type, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_resource_block_coding, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_modulation, tvb, offset, 0); +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_transmission_power, tvb, offset, power_offset_conversion); +- proto_tree_add_uint16(tree, hf_nfapi_mbsfn_area_id, tvb, offset, 0); +- +- return 0; +-} +- +-int dissect_codebook_index_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_codebook_index, tvb, offset, 0); +- return 0; +-} +- +-int dissect_bf_vector_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_bf_vector_bf_value, tvb, offset, 0); +- return 0; +-} +- +-int dissect_bf_vector_type_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_bf_vector_subband_index, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_bf_vector_num_antennas, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "Antennas", hf_nfapi_bf_vector_antennas, ett_nfapi_bf_vector_antennas, count, dissect_bf_vector_value); +- return 0; +-} +- +-static int dissect_dl_config_request_dlsch_pdu_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_length, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_pdu_index, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_rnti, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_resource_allocation_type, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_virtual_resource_block_assignment_flag, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_resource_block_coding, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_modulation, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_redundancy_version, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_transport_blocks, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_transport_block_to_codeword_swap_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_transmission_scheme, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_layers, tvb, offset, 0); +- guint8 num_subbands = proto_tree_add_uint8(tree, hf_nfapi_number_of_subbands, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "Subbands", hf_nfapi_subbands, ett_nfapi_subbands, num_subbands, dissect_codebook_index_value); +- proto_tree_add_uint8(tree, hf_nfapi_ue_category_capacity, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_pa, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_delta_power_offset_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ngap, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_nprb, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_transmission_mode, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_num_bf_prb_per_subband, tvb, offset, 0); +- guint8 num_vectors = proto_tree_add_uint8(tree, hf_nfapi_num_bf_vector, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "Beamforming Vectors", hf_nfapi_bf_vectors, ett_nfapi_bf_vectors, num_vectors, dissect_bf_vector_type_value); +- +- +- return 0; +-} +- +-int dissect_csi_rs_resource_config_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_csi_rs_resource_config, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_dl_config_request_dlsch_pdu_rel9_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_nscid, tvb, offset, 0); +- +- return 0; +-} +-static int dissect_dl_config_request_dlsch_pdu_rel10_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_csi_rs_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_csi_rs_resource_config_r10, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_csi_rs_zero_tx_power_resource_config_bitmap_r10, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_csi_rs_number_if_nzp_configurations, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "CSI-RS Resource Configs", hf_nfapi_csi_rs_resource_configs, ett_nfapi_csi_rs_resource_configs, count, dissect_csi_rs_resource_config_value); +- proto_tree_add_uint8(tree, hf_nfapi_pdsch_start, tvb, offset, 0); +- +- return 0; +-} +-static int dissect_dl_config_request_dlsch_pdu_rel11_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_drms_config_flag, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_drms_scrambling, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_csi_config_flag, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_csi_scrambling, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_pdsch_re_mapping_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_pdsch_re_mapping_antenna_ports, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_pdsch_re_mapping_freq_shift, tvb, offset, 0); +- return 0; +-} +-static int dissect_dl_config_request_dlsch_pdu_rel12_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_alt_cqi_table_r12, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_max_layers, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_n_dl_harq, tvb, offset, 0); +- return 0; +-} +-static int dissect_dl_config_request_dlsch_pdu_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_dwpts_symbols, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_initial_lbt_sf, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ue_type, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_pdsch_payload_type, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_initial_transmission_sf, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_req13_drms_table_flag, tvb, offset, 0); +- return 0; +-} +-static int dissect_dl_config_request_pch_pdu_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_length, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_pdu_index, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_prnti, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_resource_allocation_type, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_virtual_resource_block_assignment_flag, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_resource_block_coding, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_mcs, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_redundancy_version, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_transport_blocks, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_transport_block_to_codeword_swap_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_transmission_scheme, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_layers, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_codebook_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ue_category_capacity, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_pa, tvb, offset, 0); +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_transmission_power, tvb, offset, power_offset_conversion); +- proto_tree_add_uint8(tree, hf_nfapi_nprb, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ngap, tvb, offset, 0); +- return 0; +-} +-static int dissect_dl_config_request_pch_pdu_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_ue_mode, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_initial_transmission_sf, tvb, offset, 0); +- return 0; +-} +-static int dissect_dl_config_request_prs_pdu_rel9_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_transmission_power, tvb, offset, power_offset_conversion); +- proto_tree_add_uint8(tree, hf_prs_bandwidth, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_prs_cyclic_prefix_type, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_prs_muting, tvb, offset, 0); +- return 0; +-} +-static int dissect_dl_config_request_csi_rs_pdu_rel10_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_csi_rs_antenna_port_count_r10, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_csi_rs_resource_config_r10, tvb, offset, 0); +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_transmission_power, tvb, offset, power_offset_conversion); +- proto_tree_add_uint16(tree, hf_nfapi_csi_rs_zero_tx_power_resource_config_bitmap_r10, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_csi_rs_number_if_nzp_configurations, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "CSI-RS Resource Configs", hf_nfapi_csi_rs_resource_configs, ett_nfapi_csi_rs_resource_configs, count, dissect_csi_rs_resource_config_value); +- return 0; +-} +- +- +-int dissect_csi_rs_bf_vector_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_csi_rs_resource_index, tvb, offset, 0); +- //proto_tree_add_uint8(tree, hf_nfapi_csi_rs_resource_config, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_dl_config_request_csi_rs_pdu_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_csi_rs_class, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_cdm_type, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_num_bf_vector, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "Beamforming Vector", hf_nfapi_csi_rs_bf_vector, ett_nfapi_csi_rs_bf_vector, count, dissect_csi_rs_bf_vector_value); +- return 0; +-} +- +-int dissect_epdcch_prb_index_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_edpcch_prb_index, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_dl_config_request_edpcch_params_rel11_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_epdcch_resource_assignment_flag, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_epdcch_id, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_epdcch_start_symbol, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_epdcch_num_prb, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "PRBs", hf_nfapi_epdcch_prbs, ett_nfapi_epdcch_prbs, count, dissect_epdcch_prb_index_value); +- dissect_bf_vector_type_value(tvb, pinfo, tree, data, offset, end); +- +- return 0; +-} +-static int dissect_dl_config_request_edpcch_params_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_dwpts_symbols, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_initial_lbt_sf, tvb, offset, 0); +- return 0; +-} +- +-int dissect_precoding_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_precoding_value, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_dl_config_request_mpdpcch_pdu_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_mpdcch_narrowband, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_prb_pairs, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_resource_block_assignment, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_start_symbol, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ecce_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_aggregation_level, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_rnti_type, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_rnti, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ce_mode, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_drms_scrabmling_init, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_initial_transmission_sf, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_transmission_power, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_dci_format, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_resource_block_coding , tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_mcs, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_pdsch_reception_levels , tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_redundancy_version, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_new_data_indicator, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_harq_process, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_tpmi_length, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_tpmi, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_pmi_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_harq_resource_offset, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_dci_subframe_repetition_number, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_tpc, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_downlink_assignment_index_length, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_downlink_assignment_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_allocate_prach_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_preamble_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_prach_mask_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_starting_ce_level, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_srs_request, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_antenna_ports_and_scrambling_identity_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_antenna_ports_and_scrambling_identity, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_frequency_hopping_enabled_flag , tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_paging_direct_indication_differentiation_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_direct_indication, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_total_dci_length_including_padding, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_number_of_tx_antenna_ports, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "Precoding", hf_nfapi_precoding, ett_nfapi_precoding, count, dissect_precoding_value); +- +- return 0; +-} +- +-int dissect_ul_config_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_ul_config_pdu_type, tvb, offset, 0); +- guint8 size = proto_tree_add_uint8(tree, hf_nfapi_pdu_size, tvb, offset, 0); +- +- guint pdu_end = (*offset + size - 2); +- dissect_tlv_list(tvb, pinfo, tree, data, offset, pdu_end); +- +- return 0; +-} +- +-static int dissect_ul_config_request_body_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint8 num_pdu = proto_tree_add_uint8(tree, hf_nfapi_number_pdus, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_rach_prach_frequency_resources, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_srs_present, tvb, offset, 0); +- +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "UL Config PDU List", hf_nfapi_ul_config_request_pdu_list, ett_nfapi_ul_config_request_pdu_list, num_pdu, dissect_ul_config_pdu); +- +- return 0; +-} +- +- +-int dissect_ul_config_ulsch_pdu_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint32(tree, hf_nfapi_handle, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_size, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_rnti, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_resource_block_start, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_resource_blocks, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_modulation, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_cyclic_shift_2_for_drms, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_frequency_hopping_enabled_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_frequency_hopping_bits, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_new_data_indication, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_redundancy_version, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_harq_process_number, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ul_tx_mode, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_current_tx_nb, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_n_srs, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_ulsch_pdu_rel10_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_resource_allocation_type, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_resource_block_coding, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_transport_blocks, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ul_transmission_scheme, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_layers, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_codebook_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_disable_sequence_hopping_flag, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_ulsch_pdu_rel11_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_virtual_cell_id_enabled_flag, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_npusch_identity, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_drms_config_flag, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_ndrms_csh_identity, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_ulsch_pdu_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_ue_type, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_total_number_of_repetitions, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_repetition_number, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_initial_sf_io, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_empty_symbols_due_to_retunning, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_init_tx_params_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_n_srs_initial, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_initial_number_of_resource_blocks, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_cqi_ri_info_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_dl_cqi_pmi_size_rank_1, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_dl_cqi_pmi_size_rank_greater_1, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ri_size, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_delta_offset_cqi, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_delta_offset_ri, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_cqi_ri_info_rel9_later_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint8 type = proto_tree_add_uint8(tree, hf_nfapi_report_type, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_delta_offset_cqi, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_delta_offset_ri, tvb, offset, 0); +- +- switch (type) +- { +- case 0: +- { +- proto_tree_add_uint8(tree, hf_nfapi_dl_cqi_ri_pmi_size, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_control_type, tvb, offset, 0); +- break; +- } +- case 1: +- { +- /*guint8 num_cc = */proto_tree_add_uint8(tree, hf_nfapi_number_of_cc, tvb, offset, 0); +- +- // todo ... +- +- break; +- } +- } +- return 0; +-} +-int dissect_ul_config_cqi_ri_info_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_dl_cqi_ri_pmi_size_2, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_harq_info_ulsch_rel10_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_harq_size, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_delta_offset_harq, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ack_nack_mode, tvb, offset, 0); +- +- return 0; +-} +-int dissect_ul_config_harq_info_ulsch_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_harq_size_2, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_delta_offset_harq_2, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_ue_info_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint32(tree, hf_nfapi_handle, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_rnti, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_ue_info_rel11_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_virtual_cell_id_enabled_flag, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_npucch_identity, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_ue_info_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_ue_type, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_empty_symbols, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_total_number_of_repetitions, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_repetition_number, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_cqi_info_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_pucch_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_dl_cqi_pmi_size, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_cqi_info_rel10_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_number_of_pucch_resource, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_pucch_index_p1, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_cqi_info_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_csi_mode, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_dl_cqi_pmi_size_2, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_statring_prb, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_nprb, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_cdm_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_nsrs, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_sr_info_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_pucch_index, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_sr_info_rel10_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_number_of_pucch_resource, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_pucch_index_p1, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_harq_info_uci_rel10_tdd_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_harq_size, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ack_nack_mode, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_pucch_resource, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_n_pucch_1_0, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_n_pucch_1_1, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_n_pucch_1_2, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_n_pucch_1_3, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_harq_info_uci_rel8_fdd_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_n_pucch_1_0, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_harq_size, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_harq_info_uci_rel9_later_fdd_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_harq_size, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ack_nack_mode, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_pucch_resource, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_n_pucch_1_0, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_n_pucch_1_1, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_n_pucch_1_2, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_n_pucch_1_3, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_harq_info_uci_rel11_fdd_tdd_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_num_ant_ports, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_n_pucch_2_0, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_n_pucch_2_1, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_n_pucch_2_2, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_n_pucch_2_3, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_harq_info_uci_rel13_fdd_tdd_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_harq_size_2, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_starting_prb, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_nprb, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_cdm_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_nsrs, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_srs_info_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint32(tree, hf_nfapi_handle, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_size, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_rnti, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_srs_bandwidth, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_frequency_domain_position, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_srs_hopping_bandwidth, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_transmission_comb, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_i_srs, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_sounding_reference_cyclic_shift, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_srs_info_rel10_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_antenna_port, tvb, offset, 0); +- return 0; +-} +-int dissect_ul_config_srs_info_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_number_of_combs, tvb, offset, 0); +- return 0; +-} +- +-int dissect_hi_dci0_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_pdu_type, tvb, offset, 0); +- guint8 size = proto_tree_add_uint8(tree, hf_nfapi_pdu_size, tvb, offset, 0); +- +- guint pdu_end = (*offset + size - 2); +- dissect_tlv_list(tvb, pinfo, tree, data, offset, pdu_end); +- +- return 0; +-} +- +-static int dissect_hi_dci0_request_body_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_sfn_sf, tvb, offset, 0); +- guint8 num_pdu = proto_tree_add_uint8(tree, hf_nfapi_number_of_dci_pdus, tvb, offset, 0); +- num_pdu += proto_tree_add_uint8(tree, hf_nfapi_number_of_hi_pdus, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "HI DCI0 PDU List", hf_nfapi_hi_dci0_request_pdu_list, ett_nfapi_hi_dci0_request_pdu_list, num_pdu, dissect_hi_dci0_pdu); +- return 0; +-} +- +-static int dissect_hi_dci0_hi_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_resource_block_start, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_cyclic_shift_2_for_drms, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_hi_value, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_i_phich, tvb, offset, 0); +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_transmission_power, tvb, offset, power_offset_conversion); +- return 0; +-} +-static int dissect_hi_dci0_hi_rel10_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_flag_tb2, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_hi_value_2, tvb, offset, 0); +- return 0; +-} +-static int dissect_hi_dci0_dci_ul_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_dci_format, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_cce_idx, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_aggregation_level, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_rnti, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_resource_block_start, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_resource_blocks, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_mcs_1, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_cyclic_shift_2_for_drms, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_frequency_hopping_enabled_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_frequency_hopping_bits, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_new_data_indication, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ue_tx_antenna_selection, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_tpc, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_cqi_csi_request, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ul_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_dl_assignment_index, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_tpc_bitmap, tvb, offset, 0); +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_transmission_power, tvb, offset, power_offset_conversion); +- return 0; +-} +-static int dissect_hi_dci0_dci_ul_rel10_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_cross_carrier_scheduling_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_carrier_indicator, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_size_of_cqi_csi_feild, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_srs_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_srs_request, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_resource_allocation_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_resource_allocation_type, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_resource_block_coding, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_mcs_2, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_new_data_indication_two, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_antenna_ports, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_tpmi, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_total_dci_length_including_padding, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_n_ul_rb, tvb, offset, 0); +- return 0; +-} +-static int dissect_hi_dci0_dci_ul_rel12_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_pscch_resource, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_time_resource_pattern, tvb, offset, 0); +- return 0; +-} +-static int dissect_hi_dci0_edpcch_dci_ul_rel11_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_epdcch_resource_assignment_flag, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_epdcch_id, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_epdcch_start_symbol, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_epdcch_num_prb, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "PRBs", hf_nfapi_epdcch_prbs, ett_nfapi_epdcch_prbs, count, dissect_epdcch_prb_index_value); +- dissect_bf_vector_type_value(tvb, pinfo, tree, data, offset, end); +- return 0; +-} +- +-static int dissect_hi_dci0_mdpcch_dci_ul_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_mpdcch_narrowband, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_prb_pairs, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_resource_block_assignment, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_mpdcch_transmission_type, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_start_symbol, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ecce_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_aggregation_level, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_rnti_type, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ce_mode, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_drms_scrambling_init, tvb, offset, 0); +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_transmission_power, tvb, offset, power_offset_conversion); +- proto_tree_add_uint8(tree, hf_nfapi_dci_format, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_resource_blocks, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_mcs, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_pusch_repetition_levels, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_frequency_hopping_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_new_data_indication, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_harq_process, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_redundancy_version, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_tpc, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_csi_request, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ul_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_dai_presence_flag, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_dl_assignment_index, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_srs_request, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_dci_subframe_repetition_number, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_tpc_bitmap, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_total_dci_length_include_padding, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_number_of_tx_antenna_ports, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "TX Antenna Ports", hf_nfapi_tx_antenna_ports, ett_nfapi_tx_antenna_ports, count, dissect_precoding_value); +- +- +- return 0; +-} +-static int dissect_rx_ue_info_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint32(tree, hf_nfapi_handle, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_rnti, tvb, offset, 0); +- return 0; +-} +-static int dissect_rx_indication_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_length, tvb, offset, 0); +- int data_offset = proto_tree_add_uint16(tree, hf_nfapi_data_offset, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ul_cqi, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_timing_advance, tvb, offset, 0); +- return data_offset; +-} +-static int dissect_rx_indication_rel9_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_timing_advance_r9, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_harq_indication_data_bundling_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_harq_data_value_0, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_harq_data_value_1, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_harq_indication_data_multplexing_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_harq_data_value_0, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_harq_data_value_1, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_harq_data_value_2, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_harq_data_value_3, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_harq_indication_data_special_bundling_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_harq_data_value_0, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_harq_indication_data_channel_selection_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_harq_data_value_0, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_harq_indication_data_format_3_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_harq_data_value_0, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_harq_indication_data_format_4_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_harq_data_value_0, tvb, offset, 0); +- return 0; +-} +- +- +-static int dissect_harq_indication_data_format_5_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_harq_data_value_0, tvb, offset, 0); +- return 0; +-} +- +- +- +-static int dissect_harq_indication_rel8_tdd_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint8 mode = proto_tree_add_uint8(tree, hf_nfapi_harq_mode, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_ack_nack, tvb, offset, 0); +- +- switch (mode) +- { +- case 0: +- { +- dissect_harq_indication_data_bundling_value(tvb, pinfo, tree, data, offset, end); +- break; +- } +- case 1: +- { +- dissect_harq_indication_data_multplexing_value(tvb, pinfo, tree, data, offset, end); +- break; +- } +- case 2: +- { +- dissect_harq_indication_data_special_bundling_value(tvb, pinfo, tree, data, offset, end); +- break; +- } +- }; +- +- return 0; +-} +-static int dissect_harq_indication_rel9_later_tdd_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint8 mode = proto_tree_add_uint8(tree, hf_nfapi_harq_mode, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_number_of_ack_nack, tvb, offset, 0); +- +- // Have to do this as the mode value is need to decode the value +- guint16 i = 0; +- +- proto_item *list_ti = proto_tree_add_string_format(tree, hf_nfapi_harq_ack_nack_data, tvb, *offset, 2, "", "ACK/NACK Data"); +- proto_tree *list_tree = proto_item_add_subtree(list_ti, ett_nfapi_harq_ack_nack_data); +- +- for (i = 0; i < count; ++i) +- { +- +- proto_item *item_ti = proto_tree_add_string_format(list_tree, hf_nfapi_harq_ack_nack_data, tvb, *offset, 2, "", "[%d]", i); +- proto_tree *item_tree = proto_item_add_subtree(item_ti, ett_nfapi_harq_ack_nack_data); +- +- switch (mode) +- { +- case 0: +- { +- dissect_harq_indication_data_bundling_value(tvb, pinfo, item_tree, data, offset, end); +- break; +- } +- case 1: +- { +- dissect_harq_indication_data_multplexing_value(tvb, pinfo, item_tree, data, offset, end); +- break; +- } +- case 2: +- { +- dissect_harq_indication_data_special_bundling_value(tvb, pinfo, item_tree, data, offset, end); +- break; +- } +- case 3: +- { +- dissect_harq_indication_data_channel_selection_value(tvb, pinfo, item_tree, data, offset, end); +- break; +- } +- case 4: +- { +- dissect_harq_indication_data_format_3_value(tvb, pinfo, item_tree, data, offset, end); +- break; +- } +- }; +- } +- +- return 0; +-} +-static int dissect_harq_indication_rel13_later_tdd_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint8 mode = proto_tree_add_uint8(tree, hf_nfapi_harq_mode, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_number_of_ack_nack, tvb, offset, 0); +- +- // Have to do this as the mode value is need to decode the value +- guint16 i = 0; +- +- proto_item *list_ti = proto_tree_add_string_format(tree, hf_nfapi_harq_ack_nack_data, tvb, *offset, 2, "", "ACK/NACK Data"); +- proto_tree *list_tree = proto_item_add_subtree(list_ti, ett_nfapi_harq_ack_nack_data); +- +- for (i = 0; i < count; ++i) +- { +- proto_item *item_ti = proto_tree_add_string_format(list_tree, hf_nfapi_harq_ack_nack_data, tvb, *offset, 2, "", "[%d]", i); +- proto_tree *item_tree = proto_item_add_subtree(item_ti, ett_nfapi_harq_ack_nack_data); +- +- switch (mode) +- { +- case 0: +- { +- dissect_harq_indication_data_bundling_value(tvb, pinfo, item_tree, data, offset, end); +- break; +- } +- case 1: +- { +- dissect_harq_indication_data_multplexing_value(tvb, pinfo, item_tree, data, offset, end); +- break; +- } +- case 2: +- { +- dissect_harq_indication_data_special_bundling_value(tvb, pinfo, item_tree, data, offset, end); +- break; +- } +- case 3: +- { +- dissect_harq_indication_data_channel_selection_value(tvb, pinfo, item_tree, data, offset, end); +- break; +- } +- case 4: +- { +- dissect_harq_indication_data_format_3_value(tvb, pinfo, item_tree, data, offset, end); +- break; +- } +- case 5: +- { +- dissect_harq_indication_data_format_4_value(tvb, pinfo, item_tree, data, offset, end); +- break; +- } +- case 6: +- { +- dissect_harq_indication_data_format_5_value(tvb, pinfo, item_tree, data, offset, end); +- break; +- } +- }; +- } +- +- return 0; +-} +-static int dissect_harq_indication_rel8_fdd_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_harq_tb_1, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_harq_tb_2, tvb, offset, 0); +- return 0; +-} +- +-int dissect_harq_tb_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_harq_tb_n, tvb, offset, 0); +- return 0; +-} +- +- +-static int dissect_harq_indication_rel9_later_fdd_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_harq_mode, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_number_of_ack_nack, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "HARQ TB List", hf_nfapi_harq_data, ett_nfapi_harq_data, count, dissect_harq_tb_value); +- return 0; +-} +-static int dissect_harq_indication_rel13_later_fdd_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_harq_mode, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_number_of_ack_nack, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "HARQ TB List", hf_nfapi_harq_data, ett_nfapi_harq_data, count, dissect_harq_tb_value); +- return 0; +-} +-static int dissect_ul_cqi_information_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_ul_cqi, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_channel, tvb, offset, 0); +- return 0; +-} +-static int dissect_crc_indication_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_crc_flag, tvb, offset, 0); +- return 0; +-} +-static int dissect_rx_cqi_indication_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_length, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_data_offset, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ul_cqi, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ri, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_timing_advance, tvb, offset, 0); +- return 0; +-} +- +-int dissect_ri_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_ri, tvb, offset, 0); +- return 0; +-} +-static int dissect_rx_cqi_indication_rel9_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_length, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_data_offset, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_ul_cqi, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_number_of_cc_reported, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "CC List", hf_nfapi_cc, ett_nfapi_cc, count, dissect_ri_value); +- proto_tree_add_uint16(tree, hf_nfapi_timing_advance, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_timing_advance_r9, tvb, offset, 0); +- +- return 0; +-} +-static int dissect_rach_indication_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_rnti, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_preamble, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_timing_advance, tvb, offset, 0); +- return 0; +-} +-static int dissect_rach_indication_rel9_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_timing_advance_r9, tvb, offset, 0); +- return 0; +-} +-static int dissect_rach_indication_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_rach_resource_type, tvb, offset, 0); +- return 0; +-} +- +-int dissect_snr_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_snr, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_srs_indication_rel8_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_doppler_estimation, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_timing_advance, tvb, offset, 0); +- guint8 count = proto_tree_add_uint8(tree, hf_nfapi_number_of_resource_blocks, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_rb_start, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "RB List", hf_nfapi_rbs, ett_nfapi_rbs, count, dissect_snr_value); +- +- +- return 0; +-} +-static int dissect_srs_indication_rel9_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_timing_advance_r9, tvb, offset, 0); +- return 0; +-} +-static int dissect_srs_indication_rel10_tdd_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_up_pts_symbol, tvb, offset, 0); +- return 0; +-} +-static int dissect_tdd_channel_measuerment_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_number_prb_per_subband, tvb, offset, 0); +- guint8 num_subbands = proto_tree_add_uint8(tree, hf_nfapi_number_of_subbands, tvb, offset, 0); +- guint8 num_phy_ant = proto_tree_add_uint8(tree, hf_nfapi_number_antennas, tvb, offset, 0); +- +- guint16 i = 0; +- guint16 j = 0; +- +- proto_item *sb_list_ti = proto_tree_add_string_format(tree, hf_nfapi_subbands, tvb, *offset, 2, "", "Subbands"); +- proto_tree *sb_list_tree = proto_item_add_subtree(sb_list_ti, ett_nfapi_subbands); +- +- for (i = 0; i < num_subbands; ++i) +- { +- proto_item *sb_item_ti = proto_tree_add_string_format(sb_list_tree, hf_nfapi_subbands, tvb, *offset, 2, "", "[%d]", i); +- proto_tree *sb_item_tree = proto_item_add_subtree(sb_item_ti, ett_nfapi_subbands); +- +- proto_tree_add_uint8(sb_item_ti, hf_nfapi_subband_index, tvb, offset, 0); +- +- +- proto_item *ant_list_ti = proto_tree_add_string_format(sb_item_tree, hf_nfapi_antennas, tvb, *offset, 2, "", "Physical Antennas"); +- proto_tree *ant_list_tree = proto_item_add_subtree(ant_list_ti, ett_nfapi_antennas); +- +- for (j = 0; j < num_phy_ant; ++j) +- { +- proto_item *ant_item_ti = proto_tree_add_string_format(ant_list_tree, hf_nfapi_antennas, tvb, *offset, 2, "", "[%d]", j); +- proto_tree *ant_item_tree = proto_item_add_subtree(ant_item_ti, ett_nfapi_antennas); +- +- proto_tree_add_uint16(ant_item_tree, hf_nfapi_channel_coefficient, tvb, offset, 0); +- } +- } +- +- return 0; +-} +- +-static int dissect_srs_indication_rel11_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_ul_rtoa, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_lbt_dl_config_request_pdsch_req_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint32(tree, hf_nfapi_handle, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_mp_cca, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_n_cca, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_offset, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_lte_txop_sf, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_txop_sfn_sf_end, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_lbt_mode, tvb, offset, 0); +- return 0; +-} +-static int dissect_lbt_dl_config_request_drs_req_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint32(tree, hf_nfapi_handle, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_offset, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_sfn_sf_end, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_lbt_mode, tvb, offset, 0); +- return 0; +-} +-static int dissect_lbt_dl_config_request_pdsch_resp_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint32(tree, hf_nfapi_handle, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_result, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_txop_symbols, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_initial_partial_sf, tvb, offset, 0); +- return 0; +-} +-static int dissect_lbt_dl_config_request_drs_resp_rel13_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint32(tree, hf_nfapi_handle, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_result, tvb, offset, 0); +- return 0; +-} +- +-int dissect_tx_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 len = proto_tree_add_uint16(tree, hf_nfapi_pdu_length, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_pdu_index, tvb, offset, 0); +- +- proto_tree_add_uint8_array(tree, hf_nfapi_pdu, len, tvb, offset); +- +- return 0; +-} +- +-static int dissect_tx_request_body_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_pdu = proto_tree_add_uint16(tree, hf_nfapi_number_pdus, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "TX PDU List", hf_nfapi_tx_request_pdu_list, ett_nfapi_tx_request_pdu_list, num_pdu, dissect_tx_pdu); +- return 0; +- +-} +- +-int dissect_rx_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- //guint end = (*offset + size - 2); +- //dissect_tlv_list(tvb, pinfo, tree, data, offset, end); +- return 0; +-} +- +- +- +-int dissect_harq_indication_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 pdu_len = proto_tree_add_uint16(tree, hf_nfapi_instance_length, tvb, offset, 0); +- guint pdu_end = (*offset + pdu_len - 2); +- dissect_tlv_list(tvb, pinfo, tree, data, offset, pdu_end); +- return 0; +-} +- +-static int dissect_harq_indication_body_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_pdu = proto_tree_add_uint16(tree, hf_nfapi_number_of_harqs, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "HARQ PDU List", hf_nfapi_harq_indication_pdu_list, ett_nfapi_harq_indication_pdu_list, num_pdu, dissect_harq_indication_pdu); +- return 0; +-} +- +-int dissect_crc_indication_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 pdu_len = proto_tree_add_uint16(tree, hf_nfapi_instance_length, tvb, offset, 0); +- guint pdu_end = (*offset + pdu_len - 2); +- dissect_tlv_list(tvb, pinfo, tree, data, offset, pdu_end); +- return 0; +-} +- +- +-static int dissect_crc_indication_body_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_pdu = proto_tree_add_uint16(tree, hf_nfapi_number_of_crcs, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "CRC PDU List", hf_nfapi_crc_indication_pdu_list, ett_nfapi_crc_indication_pdu_list, num_pdu, dissect_crc_indication_pdu); +- return 0; +-} +-int dissect_sr_indication_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 pdu_len = proto_tree_add_uint16(tree, hf_nfapi_instance_length, tvb, offset, 0); +- guint pdu_end = (*offset + pdu_len - 2); +- dissect_tlv_list(tvb, pinfo, tree, data, offset, pdu_end); +- return 0; +-} +- +-static int dissect_rx_sr_indication_body_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_pdu = proto_tree_add_uint16(tree, hf_nfapi_number_of_srs, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "SR PDU List", hf_nfapi_sr_indication_pdu_list, ett_nfapi_sr_indication_pdu_list, num_pdu, dissect_sr_indication_pdu); +- return 0; +-} +-int dissect_cqi_indication_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 pdu_len = proto_tree_add_uint16(tree, hf_nfapi_instance_length, tvb, offset, 0); +- guint pdu_end = (*offset + pdu_len - 2); +- dissect_tlv_list(tvb, pinfo, tree, data, offset, pdu_end); +- return 0; +-} +-static int dissect_rx_cqi_indication_body_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_pdu = proto_tree_add_uint16(tree, hf_nfapi_number_of_cqi, tvb, offset, 0); +- +- guint16* lengths = malloc(num_pdu * 2); +- memset(lengths, 0, num_pdu * 2); +- +- guint8 tmp_offset = *offset; +- +- int i = 0; +- for (i = 0; i < num_pdu; ++i) +- { +- guint16 instance_len = tvb_get_guint16(tvb, tmp_offset, ENC_NA); +- tmp_offset += 2; +- guint8 pdu_end = tmp_offset + instance_len; +- +- while (tmp_offset < pdu_end) +- { +- guint16 tlv_id = tvb_get_guint16(tvb, tmp_offset, ENC_NA); +- tmp_offset += 2; +- guint16 tlv_len = tvb_get_guint16(tvb, tmp_offset, ENC_NA); +- tmp_offset += 2; +- +- if (tlv_id == 0x202F) +- { +- lengths[i] = tvb_get_guint16(tvb, tmp_offset, ENC_NA); +- } +- else if (tlv_id == 0x2030) +- { +- lengths[i] = tvb_get_guint16(tvb, tmp_offset, ENC_NA); +- } +- +- tmp_offset += tlv_len; +- } +- +- } +- +- +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "CQI PDU List", hf_nfapi_cqi_indication_pdu_list, ett_nfapi_cqi_indication_pdu_list, num_pdu, dissect_cqi_indication_pdu); +- +- +- for (i = 0; i < num_pdu; ++i) +- { +- proto_tree_add_uint8_array(tree, hf_nfapi_pdu, lengths[i], tvb, offset); +- } +- +- free(lengths); +- +- return 0; +-} +-int dissect_preamble_indication_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 pdu_len = proto_tree_add_uint16(tree, hf_nfapi_instance_length, tvb, offset, 0); +- guint pdu_end = (*offset + pdu_len - 2); +- dissect_tlv_list(tvb, pinfo, tree, data, offset, pdu_end); +- return 0; +-} +-static int dissect_rach_indication_body_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_pdu = proto_tree_add_uint16(tree, hf_nfapi_number_of_preambles, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "Preamble PDU List", hf_nfapi_preamble_indication_pdu_list, ett_nfapi_preamble_indication_pdu_list, num_pdu, dissect_preamble_indication_pdu); +- return 0; +-} +-int dissect_srs_indication_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 pdu_len = proto_tree_add_uint16(tree, hf_nfapi_instance_length, tvb, offset, 0); +- guint pdu_end = (*offset + pdu_len - 2); +- dissect_tlv_list(tvb, pinfo, tree, data, offset, pdu_end); +- return 0; +-} +-static int dissect_srs_indication_body_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- +- guint8 num_pdu = proto_tree_add_uint8(tree, hf_nfapi_number_of_srss, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "SRS PDU List", hf_nfapi_srs_indication_pdu_list, ett_nfapi_srs_indication_pdu_list, num_pdu, dissect_srs_indication_pdu); +- return 0; +-} +-int dissect_lbt_dl_config_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_lbt_dl_req_pdu_type, tvb, offset, 0); +- guint8 size = proto_tree_add_uint8(tree, hf_nfapi_pdu_size, tvb, offset, 0); +- guint pdu_end = (*offset + size - 2); +- dissect_tlv_list(tvb, pinfo, tree, data, offset, pdu_end); +- return 0; +-} +-static int dissect_lbt_dl_config_request_body_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint8 num_pdu = proto_tree_add_uint8(tree, hf_nfapi_number_pdus, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "LBT DL PDU List", hf_nfapi_lbt_dl_config_pdu_list, ett_nfapi_lbt_dl_config_pdu_list, num_pdu, dissect_lbt_dl_config_pdu); +- +- return 0; +-} +-int dissect_lbt_dl_indication_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_lbt_dl_ind_pdu_type, tvb, offset, 0); +- guint8 size = proto_tree_add_uint8(tree, hf_nfapi_pdu_size, tvb, offset, 0); +- guint pdu_end = (*offset + size - 2); +- dissect_tlv_list(tvb, pinfo, tree, data, offset, pdu_end); +- return 0; +-} +-static int dissect_lbt_indication_message_body_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint8 num_pdu = proto_tree_add_uint8(tree, hf_nfapi_number_pdus, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "LBT DL PDU List", hf_nfapi_lbt_dl_indication_pdu_list, ett_nfapi_lbt_dl_indication_pdu_list, num_pdu, dissect_lbt_dl_indication_pdu); +- return 0; +-} +- +-static int dissect_lte_rssi_request_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_frequency_band_indicator, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_measurement_period, tvb, offset, "ms"); +- proto_tree_add_uint8(tree, hf_nfapi_bandwidth, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_timeout, tvb, offset, "ms"); +- guint8 num_earfcns = proto_tree_add_uint8(tree, hf_nfapi_number_of_earfcns, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "EARFCNs", hf_nfapi_earfcn_list, ett_nfapi_earfcn_list, num_earfcns, dissect_earfcn_value); +- return 0; +-} +- +-int dissect_uarfcn_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_uarfcn, tvb, offset, 0); +- return 0; +-} +-static int dissect_utran_rssi_request_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_frequency_band_indicator, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_measurement_period, tvb, offset, "ms"); +- proto_tree_add_uint32(tree, hf_nfapi_timeout, tvb, offset, "ms"); +- guint8 num_uarfcns = proto_tree_add_uint8(tree, hf_nfapi_number_of_uarfcns, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "UARFCNs", hf_nfapi_uarfcn_list, ett_nfapi_uarfcn_list, num_uarfcns, dissect_uarfcn_value); +- return 0; +-} +- +-int dissect_arfcn_dir_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_arfcn, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_arfcn_direction, tvb, offset, 0); +- return 0; +-} +-static int dissect_geran_rssi_request_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_frequency_band_indicator, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_measurement_period, tvb, offset, "ms"); +- proto_tree_add_uint32(tree, hf_nfapi_timeout, tvb, offset, "ms"); +- guint8 num_arfcns = proto_tree_add_uint8(tree, hf_nfapi_number_of_arfcns, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "ARFCNs", hf_nfapi_arfcn_list, ett_nfapi_arfcn_list, num_arfcns, dissect_arfcn_dir_value); +- return 0; +-} +- +- +-int rssi_conversion(proto_item* tree, int hfindex, tvbuff_t *tvb, guint* offset, gint16 value) +-{ +- proto_tree_add_int_format_value(tree, hfindex, tvb, *offset, 2, value, "%.2f dB (%d)", ((float)value * 0.1), value); +- return 0; +-} +-int dissect_rssi_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_int16_with_conversion(tree, hf_nfapi_rssi, tvb, offset, rssi_conversion); +- return 0; +-} +-static int dissect_rssi_indication_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_rssi = proto_tree_add_uint16(tree, hf_nfapi_number_of_rssi, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "ARFCNs", hf_nfapi_rssi_list, ett_nfapi_rssi_list, num_rssi, dissect_rssi_value); +- return 0; +-} +- +-int dissect_pci_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_pci, tvb, offset, 0); +- return 0; +-} +-static int dissect_lte_cell_search_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_earfcn, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_measurement_bandwidth, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_exhaustive_search, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_timeout, tvb, offset, "ms"); +- guint8 num_pci = proto_tree_add_uint8(tree, hf_nfapi_number_of_pci, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "PCIs", hf_nfapi_pci_list, ett_nfapi_pci_list, num_pci, dissect_pci_value); +- return 0; +-} +- +-int dissect_psc_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_psc, tvb, offset, 0); +- return 0; +-} +-static int dissect_utran_cell_search_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_uarfcn, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_exhaustive_search, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_timeout, tvb, offset, "ms"); +- guint8 num_psc = proto_tree_add_uint8(tree, hf_nfapi_number_of_psc, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "PSCs", hf_nfapi_psc_list, ett_nfapi_psc_list, num_psc, dissect_psc_value); +- return 0; +-} +- +-int dissect_arfcn_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_arfcn, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_geran_cell_search_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint32(tree, hf_nfapi_timeout, tvb, offset, "ms"); +- guint8 num_arfcn = proto_tree_add_uint8(tree, hf_nfapi_number_of_arfcns, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "ARFCNs", hf_nfapi_arfcn_list, ett_nfapi_arfcn_list, num_arfcn, dissect_arfcn_value); +- return 0; +-} +- +-int neg_pow_conversion(proto_item* tree, int hfindex, tvbuff_t *tvb, guint* offset, guint8 value) +-{ +- proto_tree_add_uint_format_value(tree, hfindex, tvb, *offset, 1, value, "%d dB (%d)", ((gint16)value * (-1)), value); +- return 0; +-} +- +-int dissect_lte_cell_found_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_pci, tvb, offset, 0); +- proto_tree_add_uint8_with_conversion(tree, hf_nfapi_rsrp, tvb, offset, neg_pow_conversion); +- proto_tree_add_uint8_with_conversion(tree, hf_nfapi_rsrq, tvb, offset, neg_pow_conversion); +- proto_tree_add_int16(tree, hf_nfapi_frequency_offset, tvb, offset, 0); +- return 0; +-} +-static int dissect_lte_cell_search_indication_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_lte_cells = proto_tree_add_uint16(tree, hf_nfapi_number_of_lte_cells_found, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "LTE Cells Found", hf_nfapi_lte_cells_found_list, ett_nfapi_lte_cells_found_list, num_lte_cells, dissect_lte_cell_found_value); +- return 0; +-} +-int dissect_utran_cell_found_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_psc, tvb, offset, 0); +- proto_tree_add_uint8_with_conversion(tree, hf_nfapi_rscp, tvb, offset, neg_pow_conversion); +- proto_tree_add_uint8_with_conversion(tree, hf_nfapi_enco, tvb, offset, neg_pow_conversion); +- proto_tree_add_int16(tree, hf_nfapi_frequency_offset, tvb, offset, 0); +- return 0; +-} +-static int dissect_utran_cell_search_indication_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_utran_cells = proto_tree_add_uint16(tree, hf_nfapi_number_of_utran_cells_found, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "UTRAN Cells Found", hf_nfapi_utran_cells_found_list, ett_nfapi_utran_cells_found_list, num_utran_cells, dissect_utran_cell_found_value); +- return 0; +-} +- +-int dissect_geran_cell_found_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_arfcn, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_bsic, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_rxlev, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_rxqual, tvb, offset, 0); +- proto_tree_add_int16(tree, hf_nfapi_frequency_offset, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_sfn_offset, tvb, offset, 0); +- return 0; +-} +-static int dissect_geran_cell_search_indication_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 num_geran_cells = proto_tree_add_uint16(tree, hf_nfapi_number_of_geran_cells_found, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "GERAN Cells Found", hf_nfapi_geran_cells_found_list, ett_nfapi_geran_cells_found_list, num_geran_cells, dissect_geran_cell_found_value); +- +- return 0; +-} +-static int dissect_pnf_cell_search_state_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8_array(tree, hf_nfapi_pnf_search_state, *end - *offset, tvb, offset); +- return 0; +-} +- +-static int dissect_pnf_cell_broadcast_state_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8_array(tree, hf_nfapi_pnf_broadcast_state, *end - *offset, tvb, offset); +- return 0; +-} +-static int dissect_lte_broadcast_detect_request_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_earfcn, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_pci, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_timeout, tvb, offset, "ms"); +- return 0; +-} +-static int dissect_utran_broadcast_detect_request_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_uarfcn, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_psc, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_timeout, tvb, offset, "ms"); +- return 0; +-} +- +-static int dissect_lte_broadcast_detect_indication_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_number_of_tx_antenna, tvb, offset, 0); +- guint16 mib_len = proto_tree_add_uint16(tree, hf_nfapi_mib_length, tvb, offset, 0); +- proto_tree_add_uint8_array(tree, hf_nfapi_mib, mib_len, tvb, offset); +- proto_tree_add_uint32(tree, hf_nfapi_sfn_offset, tvb, offset, 0); +- return 0; +-} +-static int dissect_utran_broadcast_detect_indication_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 mib_len = proto_tree_add_uint16(tree, hf_nfapi_mib_length, tvb, offset, 0); +- proto_tree_add_uint8_array(tree, hf_nfapi_mib, mib_len, tvb, offset); +- proto_tree_add_uint32(tree, hf_nfapi_sfn_offset, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_lte_system_information_schedule_request_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_earfcn, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_pci, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_downlink_channel_bandwidth, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_phich_configuration, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_tx_antenna, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_retry_count, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_timeout, tvb, offset, 0); +- return 0; +-} +-//static int dissect_pnf_cell_broadcast_state_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-//{ +-// return 0; +-//} +-static int dissect_lte_system_information_schedule_indication_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- // this needs to be SIB 1 +- proto_tree_add_uint8_array(tree, hf_nfapi_sib1, (*end - *offset), tvb, offset); +- return 0; +-} +- +-int dissect_si_periodicity_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_si_periodicity, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_si_index, tvb, offset, 0); +- return 0; +-} +- +-static int dissect_lte_system_information_request_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_earfcn, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_pci, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_downlink_channel_bandwidth, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_phich_configuration, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_number_of_tx_antenna, tvb, offset, 0); +- guint8 si_priodicity = proto_tree_add_uint8(tree, hf_nfapi_number_of_si_periodicity, tvb, offset, 0); +- dissect_array_value(tvb, pinfo, tree, data, offset, end, "Number SI Periodicity", hf_nfapi_si_periodicity_list, ett_nfapi_si_periodicity_list, si_priodicity, dissect_si_periodicity_value); +- proto_tree_add_uint8(tree, hf_nfapi_si_window_length, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_timeout, tvb, offset, 0); +- +- return 0; +-} +-static int dissect_utran_system_information_request_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_uarfcn, tvb, offset, 0); +- proto_tree_add_uint16(tree, hf_nfapi_psc, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_timeout, tvb, offset, 0); +- return 0; +-} +-static int dissect_geran_system_information_request_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint16(tree, hf_nfapi_arfcn, tvb, offset, 0); +- proto_tree_add_uint8(tree, hf_nfapi_bsic, tvb, offset, 0); +- proto_tree_add_uint32(tree, hf_nfapi_timeout, tvb, offset, 0); +- return 0; +-} +-//static int dissect_pnf_cell_broadcast_state_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-//{ +-// return 0; +-//} +-static int dissect_lte_system_information_indication_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- proto_tree_add_uint8(tree, hf_nfapi_sib_type, tvb, offset, 0); +- guint16 sib_len = proto_tree_add_uint16(tree, hf_nfapi_sib_len, tvb, offset, 0); +- proto_tree_add_uint8_array(tree, hf_nfapi_sib, sib_len, tvb, offset); +- return 0; +-} +-static int dissect_utran_system_information_indication_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 sib_len = proto_tree_add_uint16(tree, hf_nfapi_sib_len, tvb, offset, 0); +- proto_tree_add_uint8_array(tree, hf_nfapi_sib, sib_len, tvb, offset); +- return 0; +-} +-static int dissect_geran_system_information_indication_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint16 si_len = proto_tree_add_uint16(tree, hf_nfapi_si_len, tvb, offset, 0); +- proto_tree_add_uint8_array(tree, hf_nfapi_si, si_len, tvb, offset); +- return 0; +-} +- +-static int dissect_rx_indication_body_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end); +- +-const tlv_t tags[] = +-{ +- { 0x1000, "PNF Param General", dissect_pnf_param_general_value }, +- { 0x1001, "PNF PHY", dissect_pnf_phy_value }, +- { 0x1002, "PNF RF", dissect_pnf_rf_value }, +- { 0x100A, "PNF PHY Rel 10", dissect_pnf_phy_rel10_value }, +- { 0x100B, "PNF PHY Rel 11", dissect_pnf_phy_rel11_value }, +- { 0x100C, "PNF PHY Rel 12", dissect_pnf_phy_rel12_value }, +- { 0x100D, "PNF PHY Rel 13", dissect_pnf_phy_rel13_value }, +- { 0x1003, "PNF PHY RF Config", dissect_pnf_phy_rf_config_value }, +- +- { 0x0001, "Subframe config - Duplex Mode", dissect_duplex_mode_value }, +- { 0x0002, "Subframe config - PCFICH power offset TLV", dissect_pcfich_power_offset_value }, +- { 0x0003, "Subframe config - P-B", dissect_pb_value }, +- { 0x0004, "Subframe config - DL cyclic prefix type", dissect_dl_cyclic_prefix_value }, +- { 0x0005, "Subframe config - UL cyclic prefix type", dissect_ul_cyclic_prefix_value }, +- { 0x000A, "RF config - Downlink channel bandwidth", dissect_dl_channel_bandwidth_value }, +- { 0x000B, "RF config - Uplink channel bandwidth", dissect_ul_channel_bandwidth_value }, +- { 0x000C, "RF config - Reference signal power", dissect_reference_signal_power_value }, +- { 0x000D, "RF config - Tx antenna ports", dissect_tx_antenna_ports_value }, +- { 0x000E, "RF config - Rx Antenna ports", dissect_rx_antenna_ports_value }, +- { 0x0014, "PHICH config - PHICH resource", dissect_phich_resource_value }, +- { 0x0015, "PHICH config - PHICH duration", dissect_phich_duration_value }, +- { 0x0016, "PHICH config - PHICH power offset", dissect_phich_power_offset_value }, +- { 0x001E, "SCH config - Primary synchronization signal EPRE/EPRERS", dissect_psch_synch_signal_epre_eprers_value }, +- { 0x001F, "SCH config - Secondary synchronization signal EPRE/EPRERS", dissect_ssch_synch_signal_epre_eprers_value }, +- { 0x0020, "SCH config - Physical Cell Id", dissect_physical_cell_id_value }, +- { 0x0028, "PRACH config - Configuration index", dissect_prach_configuration_index_value }, +- { 0x0029, "PRACH config - Root sequence index", dissect_prach_root_sequence_index_value }, +- { 0x002A, "PRACH config - Zero correlation zone configuration", dissect_prach_zero_correlation_zone_configuration_value }, +- { 0x002B, "PRACH config - High speed flag", dissect_prach_high_speed_flag_value }, +- { 0x002C, "PRACH config - Frequency offset", dissect_prach_frequency_offset_value }, +- { 0x0032, "PUSCH config - Hopping mode", dissect_pusch_hopping_mode_value }, +- { 0x0033, "PUSCH config - Hopping offset", dissect_pusch_hopping_offset_value }, +- { 0x0034, "PUSCH config - Number of sub-bands", dissect_pusch_number_of_subbands_value }, +- { 0x003C, "PUCCH config - Delta PUCCH Shift", dissect_pucch_delta_pucch_shift_value }, +- { 0x003D, "PUCCH config - N_CQI RB", dissect_pucch_n_cqi_rb_value }, +- { 0x003E, "PUCCH config - N_AN CS", dissect_pucch_n_an_cs_value }, +- { 0x003F, "PUCCH config - N1Pucch-AN", dissect_pucch_n1_pucch_an_value }, +- { 0x0046, "SRS config - Bandwidth configuration", dissect_srs_bandwidth_configuration_value }, +- { 0x0047, "SRS config - MaxUpPTS", dissect_srs_max_uppts_value }, +- { 0x0048, "SRS config - SRS subframe configuration", dissect_srs_subframe_configuration_value }, +- { 0x0049, "SRS config - SRS AckNack SRS simultaneous transmission", dissect_srs_acknack_srs_sim_tx_value }, +- { 0x0050, "Uplink reference signal config - Uplink RS hopping", dissect_uplink_rs_hopping_value }, +- { 0x0051, "Uplink reference signal config - Group assignment (delta sequence-shift pattern)", dissect_group_assignment_value }, +- { 0x0052, "Uplink reference signal config - Cyclic Shift 1 for DMRS", dissect_cyclic_shift_1_for_drms_value }, +- { 0x005A, "TDD frame structure config - Subframe assignment", dissect_tdd_subframe_assignement_value }, +- { 0x005B, "TDD frame structure config - Special sub-frame patterns", dissect_tdd_subframe_patterns_value }, +- { 0x0064, "LAA config - ED Threshold for LBT for PDSCH", dissect_laa_ed_threashold_for_lbt_for_pdsch_value }, +- { 0x0065, "LAA config - ED Threshold for LBT for DRS", dissect_laa_ed_threashold_for_lbt_for_drs_value }, +- { 0x0066, "LAA config - PD Threshold", dissect_laa_pd_threshold_value }, +- { 0x0067, "LAA config - Multi carrier type", dissect_laa_multi_carrier_type_value }, +- { 0x0068, "LAA config - Multi carrier TX", dissect_laa_multi_carrier_tx_value }, +- { 0x0069, "LAA config - Multi carrier freeze ", dissect_laa_multi_carrier_freeze_value }, +- { 0x006A, "LAA config - Tx antenna ports for DRS", dissect_laa_tx_antenna_port_for_drs_value }, +- { 0x006B, "LAA config - Transmission power for DRS", dissect_laa_transmission_power_for_drs_value }, +- +- { 0x0078, "eMTC config - PBCH Repetitions enable R13", dissect_emtc_pbch_repeitions_enabled_r13_value }, +- { 0x0079, "eMTC config - PRACH CAT-M Root sequence index", dissect_emtc_prach_cat_m_root_sequence_index_value }, +- { 0x007A, "eMTC config - PRACH CAT-M Zero correlation zone configuration", dissect_emtc_prach_cat_m_zero_correlation_zone_configuration_value }, +- { 0x007B, "eMTC config - PRACH CAT-M High speed flag", dissect_emtc_prach_cat_m_high_speed_flag_value }, +- { 0x007C, "eMTC config - PRACH CE level #0 Enable", dissect_emtc_prach_ce_level_0_enabled_value }, +- { 0x007D, "eMTC config - PRACH CE level #0 Configuration index", dissect_emtc_prach_ce_level_0_configuration_offset_value }, +- { 0x007E, "eMTC config - PRACH CE level #0 Frequency offset", dissect_emtc_prach_ce_level_0_frequency_offset_value }, +- { 0x007F, "eMTC config - PRACH CE level #0 Number of repetitions per attempt", dissect_emtc_preach_ce_level_0_num_of_repeitions_per_attempt_value }, +- { 0x0080, "eMTC config - CE level #0 Starting subframe periodicity", dissect_emtc_ce_level_0_starting_subframe_periodicity_value }, +- { 0x0081, "eMTC config - PRACH CE level #0 Hopping Enable", dissect_emtc_preach_ce_level_0_hopping_enabled_value }, +- { 0x0082, "eMTC config - PRACH CE level #0 Hopping Offset", dissect_emtc_preach_ce_level_0_hopping_offset_value }, +- { 0x0083, "eMTC config - PRACH CE level #1 Enable", dissect_emtc_prach_ce_level_1_enabled_value }, +- { 0x0084, "eMTC config - PRACH CE level #1 Configuration index", dissect_emtc_prach_ce_level_1_configuration_offset_value }, +- { 0x0085, "eMTC config - PRACH CE level #1 Frequency offset", dissect_emtc_prach_ce_level_1_frequency_offset_value }, +- { 0x0086, "eMTC config - PRACH CE level #1 Number of repetitions per attempt", dissect_emtc_preach_ce_level_1_num_of_repeitions_per_attempt_value }, +- { 0x0087, "eMTC config - CE level #1 Starting subframe periodicity", dissect_emtc_ce_level_1_starting_subframe_periodicity_value }, +- { 0x0088, "eMTC config - PRACH CE level #1 Hopping Enable", dissect_emtc_preach_ce_level_1_hopping_enabled_value }, +- { 0x0089, "eMTC config - PRACH CE level #1 Hopping Offset", dissect_emtc_preach_ce_level_1_hopping_offset_value }, +- { 0x008A, "eMTC config - PRACH CE level #2 Enable", dissect_emtc_prach_ce_level_2_enabled_value }, +- { 0x008B, "eMTC config - PRACH CE level #2 Configuration index", dissect_emtc_prach_ce_level_2_configuration_offset_value }, +- { 0x008C, "eMTC config - PRACH CE level #2 Frequency offset", dissect_emtc_prach_ce_level_2_frequency_offset_value }, +- { 0x008D, "eMTC config - PRACH CE level #2 Number of repetitions per attempt", dissect_emtc_preach_ce_level_2_num_of_repeitions_per_attempt_value }, +- { 0x008E, "eMTC config - CE level #2 Starting subframe periodicity", dissect_emtc_ce_level_2_starting_subframe_periodicity_value }, +- { 0x008F, "eMTC config - PRACH CE level #2 Hopping Enable", dissect_emtc_preach_ce_level_2_hopping_enabled_value }, +- { 0x0090, "eMTC config - PRACH CE level #2 Hopping Offset", dissect_emtc_preach_ce_level_2_hopping_offset_value }, +- { 0x0091, "eMTC config - PRACH CE level #3 Enable", dissect_emtc_prach_ce_level_3_enabled_value }, +- { 0x0092, "eMTC config - PRACH CE level #3 Configuration index", dissect_emtc_prach_ce_level_3_configuration_offset_value }, +- { 0x0093, "eMTC config - PRACH CE level #3 Frequency offset", dissect_emtc_prach_ce_level_3_frequency_offset_value }, +- { 0x0094, "eMTC config - PRACH CE level #3 Number of repetitions per attempt", dissect_emtc_preach_ce_level_3_num_of_repeitions_per_attempt_value }, +- { 0x0095, "eMTC config - CE level #3 Starting subframe periodicity", dissect_emtc_ce_level_3_starting_subframe_periodicity_value }, +- { 0x0096, "eMTC config - PRACH CE level #3 Hopping Enable", dissect_emtc_preach_ce_level_3_hopping_enabled_value }, +- { 0x0097, "eMTC config - PRACH CE level #3 Hopping Offset", dissect_emtc_preach_ce_level_3_hopping_offset_value }, +- { 0x0098, "eMTC config - PUCCH Interval - ULHoppingConfigCommonModeA", dissect_emtc_pucch_interval_ul_hopping_config_common_mode_a_value }, +- { 0x0099, "eMTC config - PUCCH Interval - ULHoppingConfigCommonModeB", dissect_emtc_pucch_interval_ul_hopping_config_common_mode_b_value }, +- +- { 0x00C8, "Layer 2/3 - Downlink Bandwidth Support", dissect_dl_bandwidth_support_value }, +- { 0x00C9, "Layer 2/3 - Uplink Bandwidth Support", dissect_ul_bandwidth_support_value }, +- { 0x00CA, "Layer 2/3 - Downlink modulation support", dissect_dl_modulation_value }, +- { 0x00CB, "Layer 2/3 - Uplink modulation support", dissect_ul_modulation_value }, +- { 0x00CC, "Layer 2/3 - PHY antenna capability", dissect_phy_antenna_capability_value }, +- { 0x00CD, "Layer 2/3 - Release capability", dissect_release_capability_value }, +- { 0x00CE, "Layer 2/3 - MBSFN capability", dissect_mbsfn_value }, +- +- { 0x00D1, "LAA Capability - LAA support", dissect_laa_support_value }, +- { 0x00D1, "LAA Capability - PD sensing LBT support", dissect_laa_pd_sensing_lbt_support_value }, +- { 0x00D1, "LAA Capability - Multi carrier LBT support", dissect_laa_multi_carrier_lbt_support_value }, +- { 0x00D1, "LAA Capability - Partial SF support", dissect_laa_partial_sf_support_value }, +- +- { 0x00F0, "Layer 2/3 - Data report mode", dissect_data_report_mode_value }, +- { 0x00F1, "Layer 2/3 - SFN/SF", dissect_sfn_sf_value }, +- { 0x00FA, "Layer 1 - PHY state", dissect_phy_state_value }, +- +- { 0x0100, "NFAPI - P7 VNF Address IPv4", dissect_p7_vnf_address_ipv4_value }, +- { 0x0101, "NFAPI - P7 VNF Address IPv4", dissect_p7_vnf_address_ipv6_value }, +- { 0x0102, "NFAPI - P7 Port", dissect_p7_vnf_port_value }, +- { 0x0103, "NFAPI - P7 PNF Address IPv4", dissect_p7_pnf_address_ipv4_value }, +- { 0x0104, "NFAPI - P7 PNF Address IPv4", dissect_p7_pnf_address_ipv6_value }, +- { 0x0105, "NFAPI - P7 Port", dissect_p7_pnf_port_value }, +- { 0x010A, "NFAPI - Downlink UEs per Subframe", dissect_downlink_ues_per_subframe_value }, +- { 0x010B, "NFAPI - Uplink UEs per Subframe", dissect_uplink_ues_per_subframe_value }, +- +- { 0x0114, "NFAPI - nFAPI RF Bands", dissect_rf_bands_value }, +- +- { 0x011E, "NFAPI - Timing window", dissect_timing_window_value }, +- { 0x011F, "NFAPI - Timing info mode", dissect_timing_info_mode_value }, +- { 0x0120, "NFAPI - Timing info period", dissect_timing_info_period_value }, +- { 0x0128, "NFAPI - Maximum Transmit Power", dissect_maximum_transmit_power_value }, +- { 0x0129, "NFAPI - EARFCN", dissect_earfcn_value }, +- { 0x0130, "NFAPI - NMM GSM Frequency Bands", dissect_nmm_gsm_frequency_bands_value }, +- { 0x0131, "NFAPI - NMM UMTS Frequency Bands", dissect_nmm_umts_frequency_bands_value }, +- { 0x0132, "NFAPI - NMM LTE Frequency Bands", dissect_nmm_lte_frequency_bands_value }, +- { 0x0133, "NFAPI - NMM Uplink RSSI supported", dissect_nmm_uplink_rssi_supported_value }, +- +- { 0x2000, "DL Config Request Body", dissect_dl_config_request_body_value }, +- +- { 0x2001, "DL DCI PDU Release 8", dissect_dl_config_request_dl_dci_pdu_rel8_value }, +- { 0x2002, "DL DCI PDU Release 9", dissect_dl_config_request_dl_dci_pdu_rel9_value }, +- { 0x2003, "DL DCI PDU Release 10", dissect_dl_config_request_dl_dci_pdu_rel10_value }, +- { 0x2039, "DL DCI PDU Release 11", dissect_dl_config_request_dl_dci_pdu_rel11_value }, +- { 0x203A, "DL DCI PDU Release 12", dissect_dl_config_request_dl_dci_pdu_rel12_value }, +- { 0x203B, "DL DCI PDU Release 13", dissect_dl_config_request_dl_dci_pdu_rel13_value }, +- +- +- { 0x2004, "BCH PDU Release 8", dissect_dl_config_request_bch_pdu_rel8_value }, +- +- { 0x2005, "MCH PDU Release 8", dissect_dl_config_request_mch_pdu_rel8_value }, +- +- { 0x2006, "DLSCH PDU Release 8", dissect_dl_config_request_dlsch_pdu_rel8_value }, +- { 0x2007, "DLSCH PDU Release 9", dissect_dl_config_request_dlsch_pdu_rel9_value }, +- { 0x2008, "DLSCH PDU Release 10", dissect_dl_config_request_dlsch_pdu_rel10_value }, +- { 0x203C, "DLSCH PDU Release 11", dissect_dl_config_request_dlsch_pdu_rel11_value }, +- { 0x203D, "DLSCH PDU Release 12", dissect_dl_config_request_dlsch_pdu_rel12_value }, +- { 0x203E, "DLSCH PDU Release 13", dissect_dl_config_request_dlsch_pdu_rel13_value }, +- +- { 0x2009, "PCH PDU Release 8", dissect_dl_config_request_pch_pdu_rel8_value }, +- { 0x203F, "PCH PDU Release 13", dissect_dl_config_request_pch_pdu_rel13_value }, +- +- { 0x200A, "PRS PDU Release 9", dissect_dl_config_request_prs_pdu_rel9_value }, +- +- { 0x200B, "CSI-RS PDU Release 10", dissect_dl_config_request_csi_rs_pdu_rel10_value }, +- { 0x2040, "CSI-RS PDU Release 13", dissect_dl_config_request_csi_rs_pdu_rel13_value }, +- +- //{ 0x2001, "EDPCCH PDU Release 8", ?? }, +- //{ 0x2002, "EDPCCH PDU Release 8", ?? }, +- //{ 0x2003, "EDPCCH PDU Release 8", ?? }, +- //{ 0x2039, "EDPCCH PDU Release 11", ?? }, +- //{ 0x203A, "EDPCCH PDU Release 12", ?? }, +- //{ 0x203B, "EDPCCH PDU Release 13", ?? }, +- { 0x2041, "EDPCCH PDU Release 11 Parameters", dissect_dl_config_request_edpcch_params_rel11_value }, +- { 0x2042, "EDPCCH PDU Release 13 Parameters", dissect_dl_config_request_edpcch_params_rel13_value }, +- +- { 0x205B, "MPDCCH PDU Release 13", dissect_dl_config_request_mpdpcch_pdu_rel13_value }, +- +- +- { 0x200C, "UL Config Request Body", dissect_ul_config_request_body_value }, +- { 0x200D, "ULSCH PDU Release 8", dissect_ul_config_ulsch_pdu_rel8_value }, +- { 0x200E, "ULSCH PDU Release 10", dissect_ul_config_ulsch_pdu_rel10_value }, +- { 0x2043, "ULSCH PDU Release 11", dissect_ul_config_ulsch_pdu_rel11_value }, +- { 0x2044, "ULSCH PDU Release 13", dissect_ul_config_ulsch_pdu_rel13_value }, +- { 0x200F, "Initial Transmission Paramters Release 8", dissect_ul_config_init_tx_params_rel8_value }, +- { 0x2010, "CQI RI Information Release 8", dissect_ul_config_cqi_ri_info_rel8_value }, +- { 0x2011, "CQI RI Information Release 9 or later", dissect_ul_config_cqi_ri_info_rel9_later_value }, +- { 0x2045, "CQI RI Information Release 13", dissect_ul_config_cqi_ri_info_rel13_value }, +- { 0x2012, "HARQ Information (ULSCH) Release 10", dissect_ul_config_harq_info_ulsch_rel10_value }, +- { 0x2046, "HARQ Information (ULSCH) Release 13", dissect_ul_config_harq_info_ulsch_rel13_value }, +- { 0x2013, "UE Information Release 8", dissect_ul_config_ue_info_rel8_value }, +- { 0x2047, "UE Information Release 11", dissect_ul_config_ue_info_rel11_value }, +- { 0x2048, "UE Information Release 13", dissect_ul_config_ue_info_rel13_value }, +- { 0x2014, "CQI Information Release 8", dissect_ul_config_cqi_info_rel8_value }, +- { 0x2015, "CQI Information Release 10", dissect_ul_config_cqi_info_rel10_value }, +- { 0x2049, "CQI Information Release 13", dissect_ul_config_cqi_info_rel13_value }, +- { 0x2016, "SR Information Release 8", dissect_ul_config_sr_info_rel8_value }, +- { 0x2017, "SR Information Release 10", dissect_ul_config_sr_info_rel10_value }, +- { 0x2018, "HARQ Information (UCI) Release 10 TDD", dissect_ul_config_harq_info_uci_rel10_tdd_value }, +- { 0x2019, "HARQ Information (UCI) Release 8 FDD", dissect_ul_config_harq_info_uci_rel8_fdd_value }, +- { 0x201A, "HARQ Information (UCI) Release 9 or later FDD", dissect_ul_config_harq_info_uci_rel9_later_fdd_value }, +- { 0x204A, "HARQ Information (UCI) Release 11 FDD/TDD", dissect_ul_config_harq_info_uci_rel11_fdd_tdd_value }, +- { 0x204B, "HARQ Information (UCI) Release 13 FDD/TDD", dissect_ul_config_harq_info_uci_rel13_fdd_tdd_value }, +- { 0x201B, "SRS Information Release 8", dissect_ul_config_srs_info_rel8_value }, +- { 0x201C, "SRS Information Release 10", dissect_ul_config_srs_info_rel10_value }, +- { 0x204C, "SRS Information Release 13", dissect_ul_config_srs_info_rel13_value }, +- +- { 0x201D, "HI DCI0 Request Body", dissect_hi_dci0_request_body_value }, +- { 0x201E, "HI PDU Release 8", dissect_hi_dci0_hi_rel8_value }, +- { 0x201F, "HI PDU Release 10", dissect_hi_dci0_hi_rel10_value }, +- { 0x2020, "DCI UL PDU Release 8", dissect_hi_dci0_dci_ul_rel8_value }, +- { 0x2021, "DCI UL PDU Release 10", dissect_hi_dci0_dci_ul_rel10_value }, +- { 0x204D, "DCI UL PDU Release 12", dissect_hi_dci0_dci_ul_rel12_value }, +- //{ 0x2041, "EDPCCH DCI UL PDU Release 11", dissect_hi_dci0_edpcch_dci_ul_rel11_value }, +- { 0x204E, "MDPCCH DCI UL PDU Release 13", dissect_hi_dci0_mdpcch_dci_ul_rel13_value }, +- +- { 0x2022, "Tx Request Body", dissect_tx_request_body_value }, +- +- { 0x2038, "RX UE Information", dissect_rx_ue_info_value }, +- +- { 0x2023, "RX Indication Body", dissect_rx_indication_body_value }, +- { 0x2024, "RX PDU Release 8", dissect_rx_indication_rel8_value }, +- { 0x2025, "RX PDU Release 9", dissect_rx_indication_rel9_value }, +- +- { 0x2026, "HARQ Indication Body", dissect_harq_indication_body_value }, +- { 0x2027, "HARQ PDU Release 8 TDD", dissect_harq_indication_rel8_tdd_value }, +- { 0x2028, "HARQ PDU Release 9 or later TDD", dissect_harq_indication_rel9_later_tdd_value }, +- { 0x204F, "HARQ PDU Release 13 or later TDD", dissect_harq_indication_rel13_later_tdd_value }, +- { 0x2029, "HARQ PDU Release 8 FDD", dissect_harq_indication_rel8_fdd_value }, +- { 0x202A, "HARQ PDU Release 9 or later FDD", dissect_harq_indication_rel9_later_fdd_value }, +- { 0x2050, "HARQ PDU Release 13 or later FDD", dissect_harq_indication_rel13_later_fdd_value }, +- { 0x2052, "UL CQI Information", dissect_ul_cqi_information_value }, +- +- { 0x202B, "CRC Indication Body", dissect_crc_indication_body_value }, +- { 0x202C, "CRC PDU Release 8", dissect_crc_indication_rel8_value }, +- +- { 0x202D, "RX SR Indication Body", dissect_rx_sr_indication_body_value }, +- +- { 0x202E, "RX CQI Indication Body", dissect_rx_cqi_indication_body_value }, +- { 0x202F, "CQI PDU Release 8", dissect_rx_cqi_indication_rel8_value }, +- { 0x2030, "CQI PDU Release 9", dissect_rx_cqi_indication_rel9_value }, +- +- { 0x2031, "RACH Indication Body", dissect_rach_indication_body_value }, +- { 0x2032, "Preamable PDU Release 8", dissect_rach_indication_rel8_value }, +- { 0x2033, "Preamable PDU Release 9", dissect_rach_indication_rel9_value }, +- { 0x2051, "Preamable PDU Release 13", dissect_rach_indication_rel13_value }, +- +- { 0x2034, "SRS Indication Body", dissect_srs_indication_body_value }, +- { 0x2035, "SRS PDU Release 8", dissect_srs_indication_rel8_value }, +- { 0x2036, "SRS PDU Release 9", dissect_srs_indication_rel9_value }, +- { 0x2037, "SRS PDU Release 10 TDD", dissect_srs_indication_rel10_tdd_value }, +- { 0x2054, "TDD Channel Measurement", dissect_tdd_channel_measuerment_value }, +- { 0x2053, "SRS PDU Release 11", dissect_srs_indication_rel11_value }, +- +- +- { 0x2055, "LBT DL Config Request Body", dissect_lbt_dl_config_request_body_value }, +- { 0x2056, "LBT PDSCH Req PDU Release 13", dissect_lbt_dl_config_request_pdsch_req_rel13_value }, +- { 0x2057, "LBT DRS req PDU Release 13", dissect_lbt_dl_config_request_drs_req_rel13_value }, +- +- { 0x2058, "LBT DL Indication Message Body", dissect_lbt_indication_message_body_value }, +- { 0x2056, "LBT PDSCH Resp PDU Release 13", dissect_lbt_dl_config_request_pdsch_resp_rel13_value }, +- { 0x2057, "LBT DRS Resp PDU Release 13", dissect_lbt_dl_config_request_drs_resp_rel13_value }, +- +- { 0x3000, "LTE RSSI Request", dissect_lte_rssi_request_value }, +- { 0x3001, "UTRAN RSSI Request", dissect_utran_rssi_request_value }, +- { 0x3002, "GERAN RSSI Request", dissect_geran_rssi_request_value }, +- { 0x3003, "RSSI Indication", dissect_rssi_indication_value }, +- { 0x3004, "LTE CELL SEARCH Request", dissect_lte_cell_search_value }, +- { 0x3005, "UTRAN CELL SEARCH Request", dissect_utran_cell_search_value }, +- { 0x3006, "GERAN CELL SEARCH Request", dissect_geran_cell_search_value }, +- { 0x3007, "LTE CELL SEARCH Indication", dissect_lte_cell_search_indication_value }, +- { 0x3008, "UTRAN CELL SEARCH Indication", dissect_utran_cell_search_indication_value }, +- { 0x3009, "GERAN CELL SEARCH Indication", dissect_geran_cell_search_indication_value }, +- { 0x300a, "PNF CELL SEARCH STATE", dissect_pnf_cell_search_state_value }, +- { 0x300b, "LTE BROADCAST DETECT Request", dissect_lte_broadcast_detect_request_value }, +- { 0x300c, "UTRAN BROADCAST DETECT Request", dissect_utran_broadcast_detect_request_value }, +- { 0x300d, "PNF CELL SEARCH STATE", dissect_pnf_cell_search_state_value }, +- { 0x300e, "LTE BROADCAST DETECT Indication", dissect_lte_broadcast_detect_indication_value }, +- { 0x300f, "UTRAN BROADCAST DETECT Indication", dissect_utran_broadcast_detect_indication_value }, +- { 0x3010, "PNF CELL BROADCAST STATE", dissect_pnf_cell_broadcast_state_value }, +- { 0x3011, "LTE SYSTEM INFORMATION SCHEDULE Request", dissect_lte_system_information_schedule_request_value }, +- { 0x3012, "PNF CELL BROADCAST STATE", dissect_pnf_cell_broadcast_state_value }, +- { 0x3013, "LTE SYSTEM INFORMATION SCHEDULE Indication", dissect_lte_system_information_schedule_indication_value }, +- { 0x3014, "LTE SYSTEM INFORMATION Request", dissect_lte_system_information_request_value }, +- { 0x3015, "UTRAN SYSTEM INFORMATION Request", dissect_utran_system_information_request_value }, +- { 0x3016, "GERAN SYSTEM INFORMATION Request", dissect_geran_system_information_request_value }, +- { 0x3017, "PNF CELL BROADCAST STATE", dissect_pnf_cell_broadcast_state_value }, +- { 0x3018, "LTE SYSTEM INFORMATION Indication", dissect_lte_system_information_indication_value }, +- { 0x3019, "UTRAN SYSTEM INFORMATION Indication", dissect_utran_system_information_indication_value }, +- { 0x301a, "GERAN SYSTEM INFORMATION Indication", dissect_geran_system_information_indication_value }, +- +- +- +- +-}; +- +-int look_up_tlv(int tag_id) +-{ +- int i; +- int num_tags = sizeof(tags) / sizeof(tlv_t); +- +- for (i = 0; i < num_tags; i++) +- { +- if (tag_id == tags[i].tag_id) +- return i; +- } +- return -1; +-} +- +-static int dissect_tl_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset) +-{ +- proto_item *tl_ti = proto_tree_add_string_format(tree, hf_nfapi_tl, tvb, *offset, 4, "", "TL"); +- proto_tree *tl_tree = proto_item_add_subtree(tl_ti, ett_nfapi_tl); +- +- proto_tree_add_uint16(tl_tree, hf_nfapi_tl_tag, tvb, offset, 0); +- proto_tree_add_uint16(tl_tree, hf_nfapi_tl_length, tvb, offset, "bytes"); +- +- return 0; +- +-} +- +-static int dissect_tlv_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint len) +-{ +- while (*offset < len) +- { +- guint16 tlv_id = tvb_get_guint16(tvb, *offset, ENC_NA); +- guint16 tlv_len = tvb_get_guint16(tvb, *offset + 2, ENC_NA); +- +- int tlv_index = look_up_tlv(tlv_id); +- +- char* tlv_name = tlv_index != -1 ? tags[tlv_index].name : "Unknown"; +- +- proto_item *tlv_ti = proto_tree_add_string_format(tree, hf_nfapi_tlv_tree, tvb, *offset, tlv_len + 4, "", tlv_name); +- proto_tree *tlv_tree = proto_item_add_subtree(tlv_ti, ett_nfapi_tlv_tree); +- +- dissect_tl_header(tvb, pinfo, tlv_tree, data, offset); +- +- if (tags[tlv_index].decode != NULL) +- { +- guint tmp = *offset; +- guint end = *offset + tlv_len; +- tags[tlv_index].decode(tvb, pinfo, tlv_tree, data, &tmp, &end); +- *offset += tlv_len; +- } +- else +- { +- *offset += tlv_len; +- } +- } +- +- return 0; +-} +- +-static int dissect_rx_indication_body_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint* end) +-{ +- guint number_of_pdu_addr = *offset; +- guint16 count = proto_tree_add_uint16(tree, hf_nfapi_number_pdus, tvb, offset, 0); +- //dissect_array_value(tvb, pinfo, tree, data, offset, "RX PDU List", hf_nfapi_rx_indication_pdu_list, ett_nfapi_rx_indication_pdu_list, num_pdu, dissect_rx_pdu); +- +- guint16* lengths = malloc(count * 2); +- memset(lengths, 0, count * 2); +- +- guint16 i = 0; +- +- if (count > 0) +- { +- proto_item *list_ti = proto_tree_add_string_format(tree, hf_nfapi_rx_indication_pdu_list, tvb, *offset, 2, "", "RX PDU List"); +- proto_tree *list_tree = proto_item_add_subtree(list_ti, ett_nfapi_rx_indication_pdu_list); +- +- //for (i = 0; i < count; ++i) +- proto_tree *item_tree = 0; +- +- guint pdu_end = *end; +- while (*offset < *end && *offset < pdu_end) +- { +- +- guint16 tlv_id = tvb_get_guint16(tvb, *offset, ENC_NA); +- guint16 tlv_len = tvb_get_guint16(tvb, *offset + 2, ENC_NA); +- +- if (tlv_id == 0x2038) +- { +- proto_item *item_ti = proto_tree_add_string_format(list_tree, hf_nfapi_rx_indication_pdu_list, tvb, *offset, 2, "", "[%d]", i); +- item_tree = proto_item_add_subtree(item_ti, ett_nfapi_rx_indication_pdu_list); +- +- i++; +- } +- +- int tlv_index = look_up_tlv(tlv_id); +- +- char* tlv_name = tlv_index != -1 ? tags[tlv_index].name : "Unknown"; +- +- proto_item *tlv_ti = proto_tree_add_string_format(item_tree, hf_nfapi_tlv_tree, tvb, *offset, tlv_len + 4, "", tlv_name); +- proto_tree *tlv_tree = proto_item_add_subtree(tlv_ti, ett_nfapi_tlv_tree); +- +- +- +- +- dissect_tl_header(tvb, pinfo, tlv_tree, data, offset); +- +- guint tmp_offset = *offset; +- +- if (tlv_id == 0x2038) +- { +- dissect_rx_ue_info_value(tvb, pinfo, tlv_tree, data, &tmp_offset, end); +- } +- +- else if (tlv_id == 0x2024) +- { +- //int data_offset = dissect_rx_indication_rel8_value(tvb, pinfo, tlv_tree, data, &tmp_offset, end); +- +- lengths[i-1] = proto_tree_add_uint16(tlv_tree, hf_nfapi_length, tvb, &tmp_offset, 0); +- int data_offset = proto_tree_add_uint16(tlv_tree, hf_nfapi_data_offset, tvb, &tmp_offset, 0); +- proto_tree_add_uint8(tlv_tree, hf_nfapi_ul_cqi, tvb, &tmp_offset, 0); +- proto_tree_add_uint16(tlv_tree, hf_nfapi_timing_advance, tvb, &tmp_offset, 0); +- +- if ((data_offset > 0) && (pdu_end == *end)) +- { +- pdu_end = number_of_pdu_addr + data_offset; +- } +- +- } +- else if (tlv_id == 0x2025) +- { +- dissect_rx_indication_rel9_value(tvb, pinfo, tlv_tree, data, &tmp_offset, end); +- } +- +- +- *offset += tlv_len; +- } +- +- } +- +- for (i = 0; i < count; ++i) +- { +- proto_tree_add_uint8_array(tree, hf_nfapi_pdu, lengths[i], tvb, offset); +- } +- +- free(lengths); +- +- // more to follow here ?? +- return 0; +- +-} +- +- +-// ----------------------------------------------------------------------------| +- +- +-static int dissect_p45_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset) +-{ +- proto_item *p4_p5_header_ti = proto_tree_add_string_format(tree, hf_nfapi_p4_p5_message_header, tvb, *offset, NFAPI_HEADER_LENGTH, "", "P4 P5 Header"); +- proto_tree *p4_p5_header_tree = proto_item_add_subtree(p4_p5_header_ti, ett_nfapi_p4_p5_message_header); +- +- proto_tree_add_uint16(p4_p5_header_tree, hf_nfapi_p4_p5_message_header_phy_id, tvb, offset, 0); +- proto_tree_add_uint16(p4_p5_header_tree, hf_nfapi_p4_p5_message_header_message_id, tvb, offset, 0); +- proto_tree_add_uint16(p4_p5_header_tree, hf_nfapi_p4_p5_message_header_message_length, tvb, offset, 0); +- proto_tree_add_uint16(p4_p5_header_tree, hf_nfapi_p4_p5_message_header_spare, tvb, offset, 0); +- +- return 0; +-} +- +-static int dissect_p7_header_new(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset, guint8* m, guint8* seg, guint8* seq) +-{ +- proto_item *p7_header_ti = proto_tree_add_string_format(tree, hf_nfapi_p7_message_header, tvb, *offset, NFAPI_P7_HEADER_LENGTH, "", "P7 Header"); +- proto_tree *p7_header_tree = proto_item_add_subtree(p7_header_ti, ett_nfapi_p7_message_header); +- +- proto_tree_add_uint16(p7_header_tree, hf_nfapi_p7_message_header_phy_id, tvb, offset, 0); +- proto_tree_add_uint16(p7_header_tree, hf_nfapi_p7_message_header_message_id, tvb, offset, 0); +- proto_tree_add_uint16(p7_header_tree, hf_nfapi_p7_message_header_message_length, tvb, offset, "bytes"); +- +- // decoding bits for p7 header +- +- guint8 m_seg = tvb_get_guint8(tvb, *offset); +- *m = (m_seg & 0x80) >> 7; +- *seg = m_seg & 0x7F; +- +- +- proto_tree_add_bits_item(p7_header_tree, hf_nfapi_p7_message_header_m, tvb, (*offset) * 8, 1, ENC_NA); +- proto_tree_add_bits_item(p7_header_tree, hf_nfapi_p7_message_header_segment, tvb, ((*offset) * 8) + 1, 7, ENC_NA); +- *offset += 1; +- +- *seq = tvb_get_guint8(tvb, *offset); +- proto_tree_add_uint8(p7_header_tree, hf_nfapi_p7_message_header_sequence_number, tvb, offset, 0); +- +- +- proto_tree_add_uint32(p7_header_tree, hf_nfapi_p7_message_header_checksum, tvb, offset, 0); +- proto_tree_add_uint32(p7_header_tree, hf_nfapi_p7_message_header_transmit_timestamp, tvb, offset, "microseconds"); +- +- return 0; +- +-} +- +- +- +- +-static int dissect_p7_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data, guint* offset) +-{ +- proto_item *p7_header_ti = proto_tree_add_string_format(tree, hf_nfapi_p7_message_header, tvb, *offset, NFAPI_P7_HEADER_LENGTH, "", "P7 Header"); +- proto_tree *p7_header_tree = proto_item_add_subtree(p7_header_ti, ett_nfapi_p7_message_header); +- +- proto_tree_add_uint16(p7_header_tree, hf_nfapi_p7_message_header_phy_id, tvb, offset, 0); +- proto_tree_add_uint16(p7_header_tree, hf_nfapi_p7_message_header_message_id, tvb, offset, 0); +- proto_tree_add_uint16(p7_header_tree, hf_nfapi_p7_message_header_message_length, tvb, offset, "bytes"); +- +- +- proto_tree_add_bits_item(p7_header_tree, hf_nfapi_p7_message_header_m, tvb, (*offset) * 8, 1, ENC_NA); +- proto_tree_add_bits_item(p7_header_tree, hf_nfapi_p7_message_header_segment, tvb, ((*offset) * 8) + 1, 7, ENC_NA); +- *offset += 1; +- +- proto_tree_add_uint8(p7_header_tree, hf_nfapi_p7_message_header_sequence_number, tvb, offset, 0); +- +- +- proto_tree_add_uint32(p7_header_tree, hf_nfapi_p7_message_header_checksum, tvb, offset, 0); +- proto_tree_add_uint32(p7_header_tree, hf_nfapi_p7_message_header_transmit_timestamp, tvb, offset, "microseconds"); +- +- return 0; +- +-} +- +-static reassembly_table ul_p7_reassemble_table; +-static reassembly_table dl_p7_reassemble_table; +- +- +- +-static int hf_msg_fragments = -1; +-static int hf_msg_fragment = -1; +-static int hf_msg_fragment_overlap = -1; +-static int hf_msg_fragment_overlap_conflicts = -1; +-static int hf_msg_fragment_multiple_tails = -1; +-static int hf_msg_fragment_too_long_fragment = -1; +-static int hf_msg_fragment_error = -1; +-static int hf_msg_fragment_count = -1; +-static int hf_msg_reassembled_in = -1; +-static int hf_msg_reassembled_length = -1; +-static int hf_msg_reassembled_data = -1; +-static gint ett_msg_fragment = -1; +-static gint ett_msg_fragments = -1; +- +-static const fragment_items msg_frag_items = { +- /* Fragment subtrees */ +- &ett_msg_fragment, +- &ett_msg_fragments, +- /* Fragment fields */ +- &hf_msg_fragments, +- &hf_msg_fragment, +- &hf_msg_fragment_overlap, +- &hf_msg_fragment_overlap_conflicts, +- &hf_msg_fragment_multiple_tails, +- &hf_msg_fragment_too_long_fragment, +- &hf_msg_fragment_error, +- &hf_msg_fragment_count, +- /* Reassembled in field */ +- &hf_msg_reassembled_in, +- /* Reassembled length field */ +- &hf_msg_reassembled_length, +- NULL, +- /* Tag */ +- "Message fragments" +-}; +- +-static int dissect_nfapi_ul_p7(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) +-{ +- guint8 m; +- guint8 seg; +- guint8 seq; +- guint offset = 0; +- +- guint16 msg_id = tvb_get_guint16(tvb, 2, ENC_NA); +- guint16 msg_len = tvb_get_guint16(tvb, 4, ENC_NA); +- +- dissect_p7_header_new(tvb, pinfo, tree, data, &offset, &m, &seg, &seq); +- +- guint8 save_fragmented = pinfo->fragmented; +- +- // not sure why I need to do this, but if I don't it does not reasses the protocol +- pinfo->fd->flags.visited = 0; +- +- if (m == 1 || (m == 0 && seg > 0)) +- { +- pinfo->fragmented = TRUE; +- +- fragment_head *fd_head = fragment_add_seq_check(&ul_p7_reassemble_table, tvb, offset, pinfo, seq, NULL, seg, msg_len - offset, (m == 1)); +- +- guint8 reassembled = 0; +- if (fd_head) +- { +- tvbuff_t * new_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled UL P7", fd_head, &msg_frag_items, NULL, tree); +- +- if (new_tvb) +- { +- // set the tvb to the new reassembled buffer. +- tvb = new_tvb; +- reassembled = 1; +- col_append_fstr(pinfo->cinfo, COL_INFO, "[NFAPI P7 Reassembled %d]", seg); +- +- // reset the offset for the new tvb +- offset = 0; +- } +- else +- { +- // Is this a failure to reassemble the data +- return 0; +- } +- } +- else +- { +- // this is a segement skip the body +- col_append_fstr(pinfo->cinfo, COL_INFO, "[NFAPI P7 Segment %d]", seg); +- return 0; +- } +- } +- +- pinfo->fragmented = save_fragmented; +- +- { +- switch (msg_id) +- { +- //HARQ.indication +- case 0x85: +- { +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_sfn_sf, tvb, &offset, sfn_sf_conversion); +- dissect_tlv_list(tvb, pinfo, tree, data, &offset, tvb_reported_length(tvb)); +- } +- break; +- //CRC.indication +- case 0x86: +- { +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_sfn_sf, tvb, &offset, sfn_sf_conversion); +- dissect_tlv_list(tvb, pinfo, tree, data, &offset, tvb_reported_length(tvb)); +- } +- break; +- //RX_ULSCH.indication +- case 0x87: +- { +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_sfn_sf, tvb, &offset, sfn_sf_conversion); +- dissect_tlv_list(tvb, pinfo, tree, data, &offset, tvb_reported_length(tvb)); +- } +- break; +- //RACH.indication +- case 0x88: +- { +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_sfn_sf, tvb, &offset, sfn_sf_conversion); +- dissect_tlv_list(tvb, pinfo, tree, data, &offset, tvb_reported_length(tvb)); +- } +- break; +- //SRS.indication +- case 0x89: +- { +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_sfn_sf, tvb, &offset, sfn_sf_conversion); +- dissect_tlv_list(tvb, pinfo, tree, data, &offset, tvb_reported_length(tvb)); +- } +- break; +- //RX_SR.indication +- case 0x8A: +- { +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_sfn_sf, tvb, &offset, sfn_sf_conversion); +- dissect_tlv_list(tvb, pinfo, tree, data, &offset, tvb_reported_length(tvb)); +- } +- break; +- //RX_CQI.indication +- case 0x8B: +- { +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_sfn_sf, tvb, &offset, sfn_sf_conversion); +- dissect_tlv_list(tvb, pinfo, tree, data, &offset, tvb_reported_length(tvb)); +- } +- break; +- }; +- } +- +- return 0; +-} +- +-static int dissect_nfapi_dl_p7(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) +-{ +- guint8 m; +- guint8 seg; +- guint8 seq; +- guint offset = 0; +- +- guint16 msg_id = tvb_get_guint16(tvb, 2, ENC_NA); +- guint16 msg_len = tvb_get_guint16(tvb, 4, ENC_NA); +- +- dissect_p7_header_new(tvb, pinfo, tree, data, &offset, &m, &seg, &seq); +- +- guint8 save_fragmented = pinfo->fragmented; +- +- // not sure why I need to do this, but if I don't it does not reasses the protocol +- pinfo->fd->flags.visited = 0; +- +- if (m == 1 || (m == 0 && seg > 0)) +- { +- pinfo->fragmented = TRUE; +- +- fragment_head *fd_head = fragment_add_seq_check(&dl_p7_reassemble_table, tvb, offset, pinfo, seq, NULL, seg, msg_len - offset, (m == 1)); +- +- guint8 reassembled = 0; +- if (fd_head) +- { +- tvbuff_t * new_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled DL P7", fd_head, &msg_frag_items, NULL, tree); +- +- if (new_tvb) +- { +- // set the tvb to the new reassembled buffer. +- tvb = new_tvb; +- reassembled = 1; +- col_append_fstr(pinfo->cinfo, COL_INFO, "[NFAPI P7 Reassembled %d]", seg); +- +- // reset the offset for the new tvb +- offset = 0; +- } +- else +- { +- // Is this a failure to reassemble the data +- return 0; +- } +- } +- else +- { +- // this is a segement skip the body +- col_append_fstr(pinfo->cinfo, COL_INFO, "[NFAPI P7 Segment %d]", seg); +- return 0; +- } +- } +- +- pinfo->fragmented = save_fragmented; +- +- { +- switch (msg_id) +- { +- // DL_CONFIG.request +- case 0x80: +- { +- //dissect_p7_header(tvb, pinfo, tree, data, &offset); +- proto_tree_add_uint16_with_conversion(tree, hf_nfapi_sfn_sf, tvb, &offset, sfn_sf_conversion); +- dissect_tlv_list(tvb, pinfo, tree, data, &offset, tvb_reported_length(tvb)); +- break; +- } +- +- }; +- } +- +- return 0; +-} +- +- +-static int dissect_nfapi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) +-{ +- col_set_str(pinfo->cinfo, COL_PROTOCOL, "NFAPI"); +- +- guint16 msg_id = tvb_get_guint16(tvb, 2, ENC_NA); +- guint16 msg_len = tvb_get_guint16(tvb, 4, ENC_NA); +- +- const gchar* message_str = val_to_str_const(msg_id, message_id_vals, "Unknown"); +- +- col_clear(pinfo->cinfo,COL_INFO); +- col_append_fstr(pinfo->cinfo, COL_INFO, " %s ", message_str); +- +- proto_item *msg_tree_ti = proto_tree_add_string_format(tree, hf_nfapi_message_tree, +- tvb, 0, msg_len, +- "", message_str); +- +- proto_tree *msg_tree = proto_item_add_subtree(msg_tree_ti, ett_nfapi_message_tree); +- +- guint offset = 0; +- +- +- switch (msg_id) +- { +- // HARQ.indication +- case 0x85: +- // CRC.indication +- case 0x86: +- // RX_ULSCH.indicatoin +- case 0x87: +- // RACH.indication +- case 0x88: +- // SRS.indication +- case 0x89: +- // RX_SR.indication +- case 0x8A: +- // RX_CQI.indication +- case 0x8B: +- { +- dissect_nfapi_ul_p7(tvb, pinfo, msg_tree, data); +- } +- break; +- +- // DL_CONFIG.request +- case 0x80: +- { +- dissect_nfapi_dl_p7(tvb, pinfo, msg_tree, data); +- //dissect_p7_header(tvb, pinfo, msg_tree, data, &offset); +- //proto_tree_add_uint16_with_conversion(msg_tree, hf_nfapi_sfn_sf, tvb, &offset, sfn_sf_conversion); +- //dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; +- } +- +- // UL_CONFIG.request +- case 0x81: +- { +- dissect_p7_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint16_with_conversion(msg_tree, hf_nfapi_sfn_sf, tvb, &offset, sfn_sf_conversion); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- } +- break; +- // HI_DCI0.request +- case 0x83: +- { +- dissect_p7_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint16_with_conversion(msg_tree, hf_nfapi_sfn_sf, tvb, &offset, sfn_sf_conversion); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- } +- break; +- // TX.request +- case 0x84: +- { +- dissect_p7_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint16_with_conversion(msg_tree, hf_nfapi_sfn_sf, tvb, &offset, sfn_sf_conversion); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- } +- break; +- +- // LBT_DL_CONFIG.request +- case 0x8C: +- { +- dissect_p7_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint16_with_conversion(msg_tree, hf_nfapi_sfn_sf, tvb, &offset, sfn_sf_conversion); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- } ++#define NFAPI_P7_HEADER_LENGTH 16 ++ ++static const unit_name_string khz_100_units_db = { " (100)khz", NULL }; ++ ++typedef enum{ ++ NFAPI_DL_CONFIG_REQUEST_MSG_ID = 0x0080, ++ NFAPI_UL_CONFIG_REQUEST_MSG_ID, ++ NFAPI_SUBFRAME_INDICATION_MSG_ID, ++ NFAPI_HI_DCI0_REQUEST_MSG_ID, ++ NFAPI_TX_REQUEST_MSG_ID, ++ NFAPI_HARQ_INDICATION_MSG_ID, ++ NFAPI_CRC_INDICATION_MSG_ID, ++ NFAPI_RX_ULSCH_INDICATION_MSG_ID, ++ NFAPI_RACH_INDICATION_MSG_ID, ++ NFAPI_SRS_INDICATION_MSG_ID, ++ NFAPI_RX_SR_INDICATION_MSG_ID, ++ NFAPI_RX_CQI_INDICATION_MSG_ID, ++ NFAPI_LBT_DL_CONFIG_REQUEST_MSG_ID, ++ NFAPI_LBT_DL_INDICATION_MSG_ID, ++ ++ NFAPI_PNF_PARAM_REQUEST_MSG_ID = 0x0100, ++ NFAPI_PNF_PARAM_RESPONSE_MSG_ID, ++ NFAPI_PNF_CONFIG_REQUEST_MSG_ID, ++ NFAPI_PNF_CONFIG_RESPONSE_MSG_ID, ++ NFAPI_PNF_START_REQUEST_MSG_ID, ++ NFAPI_PNF_START_RESPONSE_MSG_ID, ++ NFAPI_PNF_STOP_REQUEST_MSG_ID, ++ NFAPI_PNF_STOP_RESPONSE_MSG_ID, ++ NFAPI_PARAM_REQUEST_MSG_ID, ++ NFAPI_PARAM_RESPONSE_MSG_ID, ++ NFAPI_CONFIG_REQUEST_MSG_ID, ++ NFAPI_CONFIG_RESPONSE_MSG_ID, ++ NFAPI_START_REQUEST_MSG_ID, ++ NFAPI_START_RESPONSE_MSG_ID, ++ NFAPI_STOP_REQUEST_MSG_ID, ++ NFAPI_STOP_RESPONSE_MSG_ID, ++ NFAPI_MEASUREMENT_REQUEST_MSG_ID, ++ NFAPI_MEASUREMENT_RESPONSE_MSG_ID, ++ ++ NFAPI_DL_NODE_SYNC_MSG_ID = 0x0180, ++ NFAPI_UL_NODE_SYNC_MSG_ID, ++ NFAPI_TIMING_INFO_MSG_ID, ++ ++ NFAPI_RSSI_REQUEST_MSG_ID = 0x0200, ++ NFAPI_RSSI_RESPONSE_MSG_ID, ++ NFAPI_RSSI_INDICATION_MSG_ID, ++ NFAPI_CELL_SEARCH_REQUEST_MSG_ID, ++ NFAPI_CELL_SEARCH_RESPONSE_MSG_ID, ++ NFAPI_CELL_SEARCH_INDICATION_MSG_ID, ++ NFAPI_BROADCAST_DETECT_REQUEST_MSG_ID, ++ NFAPI_BROADCAST_DETECT_RESPONSE_MSG_ID, ++ NFAPI_BROADCAST_DETECT_INDICATION_MSG_ID, ++ NFAPI_SYSTEM_INFORMATION_SCHEDULE_REQUEST_MSG_ID, ++ NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE_MSG_ID, ++ NFAPI_SYSTEM_INFORMATION_SCHEDULE_INDICATION_MSG_ID, ++ NFAPI_SYSTEM_INFORMATION_REQUEST_MSG_ID, ++ NFAPI_SYSTEM_INFORMATION_RESPONSE_MSG_ID, ++ NFAPI_SYSTEM_INFORMATION_INDICATION_MSG_ID, ++ NFAPI_NMM_STOP_REQUEST_MSG_ID, ++ NFAPI_NMM_STOP_RESPONSE_MSG_ID, ++} nfapi_message_id_e; ++ ++static const value_string nfapi_error_vals[] = { ++ { 0x0, "MSG_OK" }, ++ { 0x1, "MSG_INVALID_STATE" }, ++ { 0x2, "MSG_INVALID_CONFIG" }, ++ { 0x3, "SFN_OUT_OF_SYNC" }, ++ { 0x4, "MSG_SUBFRAME_ERR" }, ++ { 0x5, "MSG_BCH_MISSING" }, ++ { 0x6, "MSG_BCH_MISSING" }, ++ { 0x7, "MSG_HI_ERR" }, ++ { 0x8, "MSG_TX_ERR" }, ++ { 0, NULL }, ++}; ++ ++static const value_string nfapi_p4_error_vals[] = { ++ { 100, "MSG_OK" }, ++ { 101, "MSG_INVALID_STATE" }, ++ { 102, "MSG_INVALID_CONFIG" }, ++ { 103, "MSG_RAT_NOT_SUPPORTED" }, ++ { 200, "MSG_NMM_STOP_OK" }, ++ { 201, "MSG_NMM_STOP_IGNORED" }, ++ { 202, "MSG_NMM_STOP_INVALID_STATE" }, ++ { 300, "MSG_PROCEDURE_COMPLETE" }, ++ { 301, "MSG_PROCEDURE_STOPPED" }, ++ { 302, "MSG_PARTIAL_RESULTS" }, ++ { 303, "MSG_TIMEOUT" }, ++ { 0, NULL }, ++}; ++ ++static const value_string nfapi_rat_type_vals[] = { ++ { 0, "LTE" }, ++ { 1, "UTRAN" }, ++ { 2, "GERAN" }, ++ { 0, NULL }, ++}; ++ ++typedef enum{ ++ UN_ALIGNED_SYNCHRONIZATION = 0, ++ INTERNAL_PNF_FRAME_ALIGNMENT, ++ ABSOLUTE_TIME_ALIGNED_SYNCHRONIZATION ++} nfapi_sync_mode_e; ++ ++static const value_string nfapi_sync_mode_vals[] = { ++ { UN_ALIGNED_SYNCHRONIZATION, "UN-ALIGNED SYNCHRONIZATION" }, ++ { INTERNAL_PNF_FRAME_ALIGNMENT, "INTERNAL PNF FRAME ALIGNMENT" }, ++ { ABSOLUTE_TIME_ALIGNED_SYNCHRONIZATION, "ABSOLUTE TIME ALIGNED SYNCHRONIZATION" }, ++ { 0, NULL }, ++}; ++ ++typedef enum { ++ NONE = 0, ++ GPS, ++ GLONASS, ++ BEIDOU ++} location_mode_e; ++ ++static const value_string location_mode_vals[] = { ++ { NONE, "NONE" }, ++ { GPS, "GPS" }, ++ { GLONASS, "GLONASS" }, ++ { BEIDOU, "BeiDou" }, ++ { 0, NULL } ++}; ++ ++static const value_string nfapi_uplink_rs_hopping_vals[] = { ++ { 0, "RS_NO_HOPPING" }, ++ { 1, "RS_GROUP_HOPPING" }, ++ { 2, "RS_SEQUENCE_HOPPING" }, ++ { 0, NULL } ++}; ++ ++static const value_string nfapi_laa_carrier_type_vals[] = { ++ { 0, "No multi carrier support" }, ++ { 1, "Mode A1" }, ++ { 2, "Mode A12" }, ++ { 3, "Mode B1" }, ++ { 4, "Mode B2" }, ++ { 0, NULL } ++}; ++ ++static const value_string nfapi_mutli_carrier_lbt_support_vals[] = { ++ { 0, "Multi carrier Mode A1" }, ++ { 1, "Multi carrier Mode A2" }, ++ { 2, "Multi carrier Mode B1" }, ++ { 3, "Multi carrier Mode B2" }, ++ { 0, NULL } ++}; ++ ++static const value_string nfapi_lbt_dl_req_pdu_type[] = { ++ { 0, "LBT_PDSCH_REQ PDU" }, ++ { 1, "LBT_DRS_REQ PDU" }, ++ { 0, NULL } ++}; ++ ++ ++static const value_string nfapi_lbt_dl_ind_pdu_type[] = { ++ { 0, "LBT_PDSCH_RSP PDU" }, ++ { 1, "LBT_DRS_RSP PDU" }, ++ { 0, NULL } ++}; ++ ++static const value_string nfapi_phy_state_vals[] = { ++ { 0, "IDLE" }, ++ { 1, "CONFIGURED" }, ++ { 2, "RUNNING" }, ++ { 0, NULL }, ++}; ++ ++ ++/* These are definitions where data 0 & 1 represent/provide a string name*/ ++static const true_false_string nfapi_csi_report_type_strname = { ++ "Periodic", ++ "Aperiodic", ++}; ++ ++static const true_false_string nfapi_control_type_string_name = { ++ "CQI/PMI", ++ "RI", ++}; ++ ++static const true_false_string cyclic_prefix_type_strname = { ++ "CP_NORMAL", ++ "CP_EXTENDED" ++}; ++ ++static const true_false_string support_strname = { ++ "No Support", ++ "Support" ++}; ++ ++static const true_false_string partial_sf_support_strname = ++{ ++ "Start partial SF support", ++ "End partial SF support" ++}; ++ ++static const true_false_string phich_duration_strname = { ++ "PHICH_D_NORMAL", ++ "PHICH_D_EXTENDED" ++}; ++ ++static const true_false_string high_speed_flag_strname = { ++ "HS_UNRESTRICTED_SET", ++ "HS_RESTRICTED_SET" ++}; ++ ++static const true_false_string hopping_mode_strname = { ++ "HM_INTER_SF", ++ "HM_INTRA_INTER_SF" ++}; ++ ++static const true_false_string srs_simult_tx_strname = { ++ "No Simultaneous Transmission", ++ "Simultaneous Transmission" ++}; ++ ++static const true_false_string crc_flag_strname = { ++ "CRC_ERROR", ++ "CRC_CORRECT" ++}; ++ ++static const true_false_string hi_value_strname = { ++ "HI_ACK", ++ "HI_NACK" ++}; ++ ++static const true_false_string flag_tb2_strname = { ++ "HI_NOT_PRESENT", ++ "HI_PRESENT" ++}; ++ ++static const true_false_string nfapi_multi_carrier_tx_strname = { ++ "Mutual transmission (self-deferral support for current carrier)", ++ "Transmit on channel access win (no self-deferral)" ++}; ++ ++static const true_false_string nfapi_multi_carrier_freeze_strname = { ++ "Absence of other technology is not guaranteed", ++ "Absence of other technology is guaranteed" ++}; ++ ++static const true_false_string initial_partial_sf_strname = { ++ "Full SF", ++ "Partial SF" ++}; ++ ++static const true_false_string lbt_mode_strname = { ++ "Full LBT", ++ "Partial LBT" ++}; ++ ++static const true_false_string data_report_mode_vals = { ++ "Crc reported in CRC.indication", ++ "Crc reported in RX.indication" ++}; ++ ++static const true_false_string mcch_flag_string_name = { ++ "MCCH or SC-MCCH change notification field is not valid", ++ "MCCH or SC-MCCH change notification field is valid" ++}; ++ ++static const true_false_string cross_carrier_scheduling_flag_strname = { ++ "Carrier indicator field is not valid", ++ "Carrier indicator field is valid" ++}; ++ ++static const true_false_string srs_flag_strname = { ++ "SRS request field is not valid", ++ "SRS request field is valid" ++}; ++static const true_false_string srs_request_strname = { ++ "SRS not requested", ++ "SRS requested" ++}; ++ ++static const true_false_string ul_dl_configuration_flag_strname = { ++ "UL/DL configuration field is not valid", ++ "UL/DL configuration field is valid" ++}; ++ ++static const true_false_string prs_cyclic_prefix_type_strname = { ++ "normal cyclic prefix", ++ "extended cyclic prefix" ++}; ++ ++static const true_false_string prs_muting_strname = { ++ "no muting", ++ "muting" ++}; ++ ++ ++static const value_string nfapi_dl_config_pdu_type_vals[] = { ++ { 0, "DL_CONFIG_DCI_DL_PDU" }, ++ { 1, "DL_CONFIG_BCH_PDU" }, ++ { 2, "DL_CONFIG_MCH_PDU" }, ++ { 3, "DL_CONFIG_DLSCH_PDU" }, ++ { 4, "DL_CONFIG_PCH_PDU" }, ++ { 5, "DL_CONFIG_PRS_PDU" }, ++ { 6, "DL_CONFIG_CSI_RS_PDU" }, ++ { 7, "DL_CONFIG_EPDCCH_DL_PDU" }, ++ { 8, "DL_CONFIG_EPDCCH_DL_PDU" }, ++ { 0, NULL } ++}; ++ ++static const value_string nfapi_duplex_mode_vals[] = { ++ { 0, "TDD" }, ++ { 1, "FDD" }, ++ { 2, "HD-FDD" }, ++ { 0, NULL } ++}; ++ ++static const value_string modulation_vals[] = { ++ { 2, "QPSK" }, ++ { 4, "16QAM" }, ++ { 6, "64QAM" }, ++ { 8, "256QAM" }, ++ { 0, NULL } ++}; ++ ++static const value_string pch_modulation_vals[] = { ++ { 0, "QPSK" }, ++ { 0, NULL } ++}; ++ ++static const value_string ue_mode_vals[] = { ++ { 0, "non LC/CE UE" }, ++ { 1, "LC/CE UE" }, ++ { 0, NULL } ++}; ++ ++static const value_string csi_rs_class_vals[] = { ++ { 0, "not used" }, ++ { 1, "Class A" }, ++ { 1, "Class B" }, ++ { 0, NULL } ++}; ++ ++static const value_string csi_rs_cdm_type_vals[] = { ++ { 0, "cdm 2" }, ++ { 1, "cdm 4" }, ++ { 0, NULL } ++}; ++ ++static const value_string antenna_ports_vals[] = { ++ { 0, "1 antenna ports" }, ++ { 1, "2 antenna ports" }, ++ { 2, "4 antenna ports" }, ++ { 0, NULL } ++}; ++ ++static const value_string combs_vals[] = { ++ { 0, "2 TC" }, ++ { 1, "4 TC" }, ++ { 0, NULL } ++}; ++ ++static const value_string resource_allocation_type_vals[] = { ++ { 0, "type 0" }, ++ { 1, "type 1" }, ++ { 2, "type 2 1A/1B/1D" }, ++ { 3, "type 2 1C" }, ++ { 4, "type 2 6-1A" }, ++ { 5, "type UEModeB" }, ++ { 6, "NB index" }, ++ { 0, NULL } ++}; ++ ++static const value_string transmission_scheme_vals[] = { ++ { 0, "SINGLE_ANTENNA_PORT_0" }, ++ { 1, "TX_DIVERSITY" }, ++ { 2, "LARGE_DELAY_CDD" }, ++ { 3, "CLOSED_LOOP_SPATIAL_MULTIPLEXING" }, ++ { 4, "MULTI_USER_MIMO" }, ++ { 5, "CLOSED_LOOP_RANK_1_PRECODING" }, ++ { 6, "SINGLE_ANTENNA_PORT_5" }, ++ { 7, "SINGLE_ANTENNA_PORT_7" }, ++ { 8, "SINGLE_ANTENNA_PORT_8" }, ++ { 9, "DUAL_LAYER_TX_PORT_7_AND_8" }, ++ { 10, "UP_TO_8_LAYER_TX" }, ++ { 11, "SINGLE_ANTENNA_PORT_11" }, ++ { 12, "SINGLE_ANTENNA_PORT_13" }, ++ { 13, "DUAL_LAYER_TX_PORT_11_13" }, ++ { 0, NULL } ++}; ++ ++static const value_string ul_transmission_scheme_vals[] = { ++ { 0, "SINGLE_ANTENNA_PORT_10" }, ++ { 1, "CLOSED_LOOP_SPATIAL_MULTIPLEXING" }, ++ { 0, NULL }, ++}; ++ ++static const value_string dl_dci_format_vals[] = { ++ { 0, "1" }, ++ { 1, "1A" }, ++ { 2, "1B" }, ++ { 3, "1C" }, ++ { 4, "1D" }, ++ { 5, "2" }, ++ { 6, "2A" }, ++ { 7, "2B" }, ++ { 8, "2C" }, ++ { 9, "2D" }, ++ { 10, "6-1A" }, ++ { 11, "6-1B" }, ++ { 12, "6-2" }, ++ { 0, NULL } ++}; ++ ++static const value_string ul_dci_format_vals[] = { ++ { 0, "0" }, ++ { 1, "3" }, ++ { 2, "3A" }, ++ { 3, "4" }, ++ { 4, "5" }, ++ { 0, NULL } ++}; ++ ++static const value_string mpdcch_ul_dci_format_vals[] = { ++ { 1, "3" }, ++ { 2, "3A" }, ++ { 4, "6-0A" }, ++ { 5, "6-0B" }, ++ { 0, NULL } ++}; ++ ++ ++static const value_string pa_vals[] = { ++ { 0, "-6dB" }, ++ { 1, "-4.77dB" }, ++ { 2, "-3dB" }, ++ { 3, "-1.77dB" }, ++ { 4, "0dB" }, ++ { 5, "1dB" }, ++ { 6, "2dB" }, ++ { 7, "3dB" }, ++ { 0, NULL } ++}; ++ ++static const value_string transmission_mode_vals[] = { ++ { 1, "Mode 1" }, ++ { 2, "Mode 2" }, ++ { 3, "Mode 3" }, ++ { 4, "Mode 4" }, ++ { 5, "Mode 5" }, ++ { 6, "Mode 6" }, ++ { 7, "Mode 7" }, ++ { 8, "Mode 8" }, ++ { 9, "Mode 9" }, ++ { 10, "Mode 10" }, ++ { 0, NULL } ++}; ++ ++static const value_string nfapi_ul_config_pdu_type_vals[] = { ++ { 0, "ULSCH" }, ++ { 1, "ULSCH_CQI_RI" }, ++ { 2, "ULSCH_HARQ" }, ++ { 3, "ULSCH_CQI_HARQ_RI" }, ++ { 4, "UCI_CQI" }, ++ { 5, "UCI_SR" }, ++ { 6, "UCI_HARQ" }, ++ { 7, "UCI_SR_HARQ" }, ++ { 8, "UCI_CQI_HARQ" }, ++ { 9, "UCI_CQI_SR" }, ++ { 10, "UCI_CQI_SR_HARQ" }, ++ { 11, "SRS" }, ++ { 12, "HARQ_BUFFER" }, ++ { 13, "ULSCH_UCI_CSI" }, ++ { 14, "ULSCH_UCI_HARQ" }, ++ { 15, "ULSCH_CSI_UCI_HARQ" }, ++ { 0, NULL } ++}; ++ ++static const value_string nfapi_tdd_ack_nack_mode_vals[] = { ++ { 0, "Bundling" }, ++ { 1, "Multiplexing" }, ++ { 2, "Format 1b with channel selection" }, ++ { 3, "Format 3" }, ++ { 4, "Format 4" }, ++ { 5, "Format 5" }, ++ { 0, NULL } ++}; ++static const value_string nfapi_fdd_ack_nack_mode_vals[] = { ++ { 0, "Format 1a/1b" }, ++ { 1, "Channel selection" }, ++ { 2, "Format 3" }, ++ { 3, "Format 4" }, ++ { 4, "Format 5" }, ++ { 0, NULL } ++}; ++ ++static const value_string nfapi_phich_resource_vals[] = { ++ { 0, "PHICH_R_ONE_SIXTH " }, ++ { 1, "PHICH_R_HALF" }, ++ { 2, "PHICH_R_ONE" }, ++ { 3, "PHICH_R_TWO" }, ++ { 0, NULL } ++}; ++ ++static const value_string local_distributed_vals[] = { ++ { 0, "localized" }, ++ { 1, "distributed" }, ++ { 0, NULL } ++}; ++ ++static const value_string transport_block_to_codeword_swap_flag_vals[] = { ++ { 0, "no swapping" }, ++ { 1, "swapped" }, ++ { 0, NULL } ++}; ++ ++static const value_string ngap_vals[] = { ++ { 0, "Ngap1" }, ++ { 1, "Ngap2" }, ++ { 0, NULL } ++}; ++ ++static const value_string pmi_vals[] = { ++ { 0, "Use precoding indicated in TPMI field" }, ++ { 1, "Use precoding indicated in last PMI report on PUSCH" }, ++ { 2, "use precoding indicated in TPM field" }, ++ { 0, NULL } ++}; ++ ++static const value_string true_false_vals[] = { ++ { 0, "false" }, ++ { 1, "true" }, ++ { 0, NULL } ++}; ++ ++static const value_string exhustive_search_vals[] = { ++ { 0, "non-exhaustive search" }, ++ { 1, "exhaustive search" }, ++ { 0, NULL } ++}; ++ ++static const value_string not_used_enabled_vals[] = { ++ { 0, "not used" }, ++ { 1, "enabled" }, ++ { 0, NULL } ++}; ++ ++static const value_string hopping_vals[] = { ++ { 0, "no hopping" }, ++ { 1, "hopping enabled" }, ++ { 0, NULL } ++}; ++ ++ ++static const value_string mpdcch_rnti_type_vals[] = { ++ { 1, "Temporary C-RNTI" }, ++ { 2, "RA-RNTI" }, ++ { 3, "P-RNTI" }, ++ { 4, "other" }, ++ { 0, NULL } ++}; ++ ++static const value_string rnti_type_vals[] = { ++ { 1, "C-RNTI" }, ++ { 2, "RA-RNTI, P-RNTI, SI-RNTI, SC-RNTI, G-RNTI" }, ++ { 3, "SPS-CRNTI" }, ++ { 0, NULL } ++}; ++ ++static const value_string primary_cells_type_vals[] = { ++ { 1, "TDD" }, ++ { 2, "FDD" }, ++ { 3, "HD_FDD" }, ++ { 0, NULL } ++}; ++ ++static const value_string ul_rssi_supported_vals[] = { ++ { 0, "Uplink RSSI not supported" }, ++ { 1, "Uplink RSSI supported" }, ++ { 0, NULL } ++}; ++ ++static const value_string nprb_vals[] = { ++ { 0, "2" }, ++ { 1, "3" }, ++ { 0, NULL } ++}; ++ ++static const value_string nmm_modes_supported_vals[] = ++{ ++ { 0, "NONE" }, ++ { 1, "NMM_ONLY" }, ++ { 2, "NMM_IN_CONFIGURED_STATE" }, ++ { 3, "NMM_IN_RUNNING_STATE" }, ++ { 4, "NMM_IN_CONFIGURED_AND_RUNNING_STATE" }, ++ { 0, NULL } ++}; ++ ++static const value_string dlsch_re13_ue_type_vals[] = { ++ { 0, "non LC/CE UE" }, ++ { 1, "LC/CE CEModeA UE" }, ++ { 2, "LC/CE CEModeB UE" }, ++ { 0, NULL } ++}; ++ ++static const value_string dlsch_re13_pdsch_payload_type_vals[] = { ++ { 0, "PDSCH carrying SIB1-BR " }, ++ { 1, "PDSCH carrying SI message (except for SIB1-BR or PCH)" }, ++ { 2, "PDSCH carrying other" }, ++ { 0, NULL } ++}; ++ ++static const value_string csi_rs_flags_strname[] = { ++ { 0, "CSI - RS parameters are not valid" }, ++ { 1, "CSI - RS parameters are valid" }, ++ { 0, NULL} ++}; ++ ++ ++static const value_string paging_direct_indication_differtiation_flag_vals[] = { ++ { 0, "Direct Information" }, ++ { 1, "Paging" }, ++ { 0, NULL } ++}; ++ ++static const value_string ul_tx_mode_vals[] = { ++ { 0, "SISO/MIMO" }, ++ { 1, "MIMO" }, ++ { 0, NULL } ++}; ++ ++static const value_string n_srs_vals[] = { ++ { 0, "No overlap" }, ++ { 1, "Overlap" }, ++ { 0, NULL } ++}; ++ ++static const value_string n_srs_initial_vals[] = { ++ { 0, "Last OFDM symbol is not punctured" }, ++ { 1, "Last OFDM symbol is punctured." }, ++ { 0, NULL } ++}; ++ ++ ++static const value_string csi_mode_vals[] = { ++ { 0, "PUCCH format 2/2a/2b/3" }, ++ { 1, "PUCCH format 4" }, ++ { 2, "PUCCH format 5" }, ++ { 0, NULL } ++}; ++ ++static const value_string hi_dci0_pdu_type_vals[] = { ++ { 0, "HI" }, ++ { 1, "DCI UL" }, ++ { 2, "EDPCCH DCI UL" }, ++ { 3, "MDPCCH DCI UL" }, ++ { 0, NULL } ++}; ++ ++static const value_string ue_tx_antenna_selection_vals[] = { ++ { 0, "Not Configured" }, ++ { 1, "Configured and using UE port 0" }, ++ { 2, "Configured and using UE port 1" }, ++ { 0, NULL } ++}; ++ ++static const value_string size_of_cqi_csi_feild_vals[] = { ++ { 0, "1 bit" }, ++ { 1, "2 bits" }, ++ { 2, "3 bits" }, ++ { 0, NULL } ++}; ++ ++static const value_string number_of_antenna_port_vals[] = { ++ { 0, "1 antenna port" }, ++ { 1, "2 antenna ports" }, ++ { 2, "4 antenna ports" }, ++ { 0, NULL } ++}; ++ ++static const value_string ce_mode_vals[] = { ++ { 1, "CEModeA" }, ++ { 2, "CEModeB" }, ++ { 0, NULL } ++}; ++ ++ ++static const value_string csi_request_vals[] = { ++ { 0, "Aperiodic CSI not requested" }, ++ { 1, "Aperiodic CSI requested" }, ++ { 0, NULL } ++}; ++ ++static const value_string tdd_harq_mode_vals[] = { ++ { 0, "Format 1a/1b BUNDLING" }, ++ { 1, "Format 1a/1b MULTIPLEXING" }, ++ { 2, "Format 1a/1b SPECIAL BUNDLING" }, ++ { 3, "Channel Selection" }, ++ { 4, "Format 3" }, ++ { 5, "Format 4" }, ++ { 6, "Format 5" }, ++ { 0, NULL } ++}; ++ ++static const value_string fdd_harq_mode_vals[] = { ++ { 0, "Format 1a/1b" }, ++ { 1, "Channel Selection" }, ++ { 2, "Format 3" }, ++ { 3, "Format 4" }, ++ { 4, "Format 5" }, ++ { 0, NULL } ++}; ++ ++static const value_string harq_value_vals[] = { ++ { 1, "ACK" }, ++ { 2, "NACK" }, ++ { 3, "ACK or NACK" }, ++ { 4, "DTX" }, ++ { 5, "ACK or DTX" }, ++ { 6, "NACK or DTX" }, ++ { 7, "ACK or NACK or DTX" }, ++ { 0, NULL } ++}; ++ ++ ++static const value_string harq_special_value_vals[] = { ++ { 0, "0 or None" }, ++ { 1, "1 or 4 or 7 ACKs reported" }, ++ { 2, "2 or 5 or 8 ACKs reported" }, ++ { 3, "3 or 6 or 9 ACKs reported" }, ++ { 4, "DTX (UE did not transmit anything)" }, ++ { 0, NULL } ++}; ++ ++static const value_string channel_vals[] = { ++ { 0, "PUCCH" }, ++ { 1, "PUSCH" }, ++ { 0, NULL } ++}; ++ ++static const value_string rach_resource_type_vals[] = { ++ { 0, "Non LC / CE RACH" }, ++ { 1, "LC / CE RACH CE level 0" }, ++ { 2, "LC / CE RACH CE level 1" }, ++ { 3, "LC / CE RACH CE level 2" }, ++ { 4, "LC / CE RACH CE level 3" }, ++ { 0, NULL } ++}; ++ ++static const value_string up_pts_symbol_vals[] = { ++ { 0, "Symbol 0" }, ++ { 1, "Symbol 1" }, ++ { 0, NULL } ++}; ++ ++static const value_string arfcn_direction_vals[] = { ++ { 0, "DL" }, ++ { 1, "UL" }, ++ { 0, NULL } ++}; ++ ++static int proto_nfapi = -1; ++ ++/* These are for the subtrees */ ++static gint ett_nfapi_message_tree = -1; ++static gint ett_nfapi_p4_p5_message_header = -1; ++static gint ett_nfapi_p7_message_header = -1; ++static gint ett_nfapi_tlv_tree = -1; ++static gint ett_nfapi_tl = -1; ++static gint ett_nfapi_pnf_phy = -1; ++static gint ett_nfapi_pnf_phy_rel10 = -1; ++static gint ett_nfapi_pnf_phy_rel11 = -1; ++static gint ett_nfapi_pnf_phy_rel12 = -1; ++static gint ett_nfapi_pnf_phy_rel13 = -1; ++static gint ett_nfapi_pnf_phy_rf_config = -1; ++static gint ett_nfapi_rf_bands = -1; ++static gint ett_nfapi_tx_antenna_ports = -1; ++static gint ett_nfapi_harq_ack_nack_data = -1; ++static gint ett_nfapi_harq_data = -1; ++static gint ett_nfapi_cqi_pmi_size = -1; ++static gint ett_nfapi_cc = -1; ++static gint ett_nfapi_rbs = -1; ++static gint ett_nfapi_antennas = -1; ++static gint ett_nfapi_dl_config_request_pdu_list = -1; ++static gint ett_nfapi_ul_config_request_pdu_list = -1; ++static gint ett_nfapi_hi_dci0_request_pdu_list = -1; ++static gint ett_nfapi_tx_request_pdu_list = -1; ++static gint ett_nfapi_rx_indication_pdu_list = -1; ++static gint ett_nfapi_harq_indication_pdu_list = -1; ++static gint ett_nfapi_crc_indication_pdu_list = -1; ++static gint ett_nfapi_sr_indication_pdu_list = -1; ++static gint ett_nfapi_cqi_indication_pdu_list = -1; ++static gint ett_nfapi_preamble_indication_pdu_list = -1; ++static gint ett_nfapi_srs_indication_pdu_list = -1; ++static gint ett_nfapi_lbt_dl_config_pdu_list = -1; ++static gint ett_nfapi_lbt_dl_indication_pdu_list = -1; ++static gint ett_nfapi_subbands = -1; ++static gint ett_nfapi_bf_vector_antennas = -1; ++static gint ett_nfapi_bf_vectors = -1; ++static gint ett_nfapi_csi_rs_resource_configs = -1; ++static gint ett_nfapi_csi_rs_bf_vector = -1; ++static gint ett_nfapi_epdcch_prbs = -1; ++static gint ett_nfapi_precoding = -1; ++static gint ett_nfapi_earfcn_list = -1; ++static gint ett_nfapi_uarfcn_list = -1; ++static gint ett_nfapi_arfcn_list = -1; ++static gint ett_nfapi_rssi_list = -1; ++static gint ett_nfapi_pci_list = -1; ++static gint ett_nfapi_psc_list = -1; ++static gint ett_nfapi_lte_cells_found_list = -1; ++static gint ett_nfapi_utran_cells_found_list = -1; ++static gint ett_nfapi_geran_cells_found_list = -1; ++static gint ett_nfapi_si_periodicity_list = -1; ++static gint ett_nfapi_downlink_bandwidth_support = -1; ++static gint ett_nfapi_uplink_bandwidth_support = -1; ++static gint ett_nfapi_downlink_modulation_support = -1; ++static gint ett_nfapi_uplink_modulation_support = -1; ++static gint ett_nfapi_received_interference_power_mesurement_results = -1; ++static gint ett_nfapi_release_support = -1; ++static expert_field ei_invalid_range = EI_INIT; ++static expert_field ei_invalid_tlv_length = EI_INIT; ++ ++static int hf_nfapi_p4_p5_message_header_phy_id = -1; ++static int hf_nfapi_p4_p5_message_header_message_id = -1; ++static int hf_nfapi_p4_p5_message_header_message_length = -1; ++static int hf_nfapi_p4_p5_message_header_spare = -1; ++static int hf_nfapi_p7_message_header_phy_id = -1; ++static int hf_nfapi_p7_message_header_message_id = -1; ++static int hf_nfapi_p7_message_header_message_length = -1; ++static int hf_nfapi_p7_message_header_m = -1; ++static int hf_nfapi_p7_message_header_segment = -1; ++static int hf_nfapi_p7_message_header_sequence_number = -1; ++static int hf_nfapi_p7_message_header_checksum = -1; ++static int hf_nfapi_p7_message_header_transmit_timestamp = -1; ++static int hf_nfapi_tl_tag = -1; ++static int hf_nfapi_tl_length = -1; ++static int hf_nfapi_sync_mode = -1; ++static int hf_nfapi_location_mode = -1; ++static int hf_nfapi_location_coordinates = -1; ++static int hf_nfapi_location_coordinates_length = -1; ++static int hf_nfapi_dl_config_timing = -1; ++static int hf_nfapi_tx_timing = -1; ++static int hf_nfapi_ul_config_timing = -1; ++static int hf_nfapi_hi_dci0_timing = -1; ++static int hf_nfapi_maximum_number_phys = -1; ++static int hf_nfapi_maximum_total_bandwidth = -1; ++static int hf_nfapi_maximum_total_number_dl_layers = -1; ++static int hf_nfapi_maximum_total_number_ul_layers = -1; ++static int hf_nfapi_shared_bands = -1; ++static int hf_nfapi_shared_pa = -1; ++static int hf_nfapi_maximum_total_power = -1; ++static int hf_nfapi_oui = -1; ++static int hf_nfapi_pdu = -1; ++static int hf_nfapi_pnf_phy_number_phy = -1; ++static int hf_nfapi_pnf_phy_config_index = -1; ++static int hf_nfapi_number_of_rf_exclusions = -1; ++static int hf_nfapi_dl_bandwidth_support = -1; ++static int hf_nfapi_dl_bandwidth_support_6 = -1; ++static int hf_nfapi_dl_bandwidth_support_15 = -1; ++static int hf_nfapi_dl_bandwidth_support_25 = -1; ++static int hf_nfapi_dl_bandwidth_support_50 = -1; ++static int hf_nfapi_dl_bandwidth_support_75 = -1; ++static int hf_nfapi_dl_bandwidth_support_100 = -1; ++static int hf_nfapi_ul_bandwidth_support = -1; ++static int hf_nfapi_ul_bandwidth_support_6 = -1; ++static int hf_nfapi_ul_bandwidth_support_15= -1; ++static int hf_nfapi_ul_bandwidth_support_25 = -1; ++static int hf_nfapi_ul_bandwidth_support_50 = -1; ++static int hf_nfapi_ul_bandwidth_support_75 = -1; ++static int hf_nfapi_ul_bandwidth_support_100 = -1; ++static int hf_nfapi_downlink_channel_bandwidth_supported = -1; ++static int hf_nfapi_uplink_channel_bandwidth_supported = -1; ++static int hf_nfapi_number_of_dl_layers_supported = -1; ++static int hf_nfapi_number_of_ul_layers_supported = -1; ++static int hf_nfapi_maximum_3gpp_release_supported = -1; ++static int hf_nfapi_maximum_3gpp_release_supported_rel8 = -1; ++static int hf_nfapi_maximum_3gpp_release_supported_rel9 = -1; ++static int hf_nfapi_maximum_3gpp_release_supported_rel10 = -1; ++static int hf_nfapi_maximum_3gpp_release_supported_rel11 = -1; ++static int hf_nfapi_maximum_3gpp_release_supported_rel12 = -1; ++static int hf_nfapi_maximum_3gpp_release_supported_rel13 = -1; ++static int hf_nfapi_nmm_modes_supported = -1; ++static int hf_nfapi_number_of_rfs = -1; ++static int hf_nfapi_rf_config_index = -1; ++static int hf_nfapi_band = -1; ++static int hf_nfapi_maximum_transmit_power = -1; ++static int hf_nfapi_maximum_transmit_power_2 = -1; ++static int hf_nfapi_earfcn = -1; ++static int hf_nfapi_minimum_transmit_power = -1; ++static int hf_nfapi_number_of_antennas_suppported = -1; ++static int hf_nfapi_minimum_downlink_frequency = -1; ++static int hf_nfapi_maximum_downlink_frequency = -1; ++static int hf_nfapi_minimum_uplink_frequency = -1; ++static int hf_nfapi_maximum_uplink_frequency = -1; ++static int hf_nfapi_number_of_rf_bands = -1; ++static int hf_nfapi_nmm_uplink_rssi_supported = -1; ++static int hf_nfapi_phy_rf_config_info_phy_id = -1; ++static int hf_nfapi_transmission_mode7_supported = -1; ++static int hi_nfapi_transmission_mode8_supported = -1; ++static int hi_nfapi_two_antennas_ports_for_pucch = -1; ++static int hi_nfapi_transmission_mode_9_supported = -1; ++static int hi_nfapi_simultaneous_pucch_pusch = -1; ++static int hi_nfapi_four_layer_tx_with_tm3_and_tm4 = -1; ++static int hf_nfapi_epdcch_supported = -1; ++static int hi_nfapi_multi_ack_csi_reporting = -1; ++static int hi_nfapi_pucch_tx_diversity_with_channel_selection = -1; ++static int hi_nfapi_ul_comp_supported = -1; ++static int hi_nfapi_transmission_mode_5_supported = -1; ++static int hf_nfapi_csi_subframe_set = -1; ++static int hi_nfapi_enhanced_4tx_codebook = -1; ++static int hi_nfapi_drs_supported = -1; ++static int hi_nfapi_ul_64qam_supported = -1; ++static int hi_nfapi_transmission_mode_10_supported = -1; ++static int hi_nfapi_alternative_tbs_indices = -1; ++static int hf_nfapi_pucch_format_4_supported = -1; ++static int hf_nfapi_pucch_format_5_supported = -1; ++static int hf_nfapi_more_than_5_ca_supported = -1; ++static int hf_nfapi_laa_supported = -1; ++static int hf_nfapi_laa_ending_in_dwpts_supported = -1; ++static int hf_nfapi_laa_starting_in_second_slot_supported = -1; ++static int hf_nfapi_beamforming_supported = -1; ++static int hf_nfapi_csi_rs_enhancements_supported = -1; ++static int hf_nfapi_drms_enhancements_supported = -1; ++static int hf_nfapi_srs_enhancements_supported = -1; ++static int hf_nfapi_dl_rs_tx_power = -1; ++static int hf_nfapi_received_interference_power = -1; ++static int hf_nfapi_thermal_noise_power = -1; ++static int hf_nfapi_dl_rs_tx_power_measurement = -1; ++static int hf_nfapi_received_interference_power_measurement = -1; ++static int hf_nfapi_thermal_noise_power_measurement = -1; ++ ++// P5 Message Structures ++static int hf_nfapi_error_code = -1; ++static int hf_nfapi_p4_error_code = -1; ++static int hf_nfapi_rat_type = -1; ++static int hf_nfapi_num_tlv = -1; ++static int hf_nfapi_phy_state = -1; ++static int hf_nfapi_phy_antenna_capability = -1; ++static int hf_nfapi_release_capability = -1; ++static int hf_nfapi_mbsfn_capability = -1; ++static int hf_nfapi_laa_capability = -1; ++static int hf_nfapi_pd_sensing_lbt_support = -1; ++static int hf_nfapi_multi_carrier_lbt_support = -1; ++static int hf_nfapi_partial_sf_support = -1; ++ ++static int hf_nfapi_pnf_address_ipv4 = -1; ++static int hf_nfapi_pnf_address_ipv6 = -1; ++static int hf_nfapi_vnf_address_ipv4 = -1; ++static int hf_nfapi_vnf_address_ipv6 = -1; ++static int hf_nfapi_pnf_port = -1; ++static int hf_nfapi_vnf_port = -1; ++static int hf_nfapi_dl_ue_per_sf = -1; ++static int hf_nfapi_ul_ue_per_sf = -1; ++static int hf_nfapi_timing_window = -1; ++static int hf_nfapi_timing_info_mode = -1; ++static int hf_nfapi_timing_info_period = -1; ++static int hf_nfapi_duplex_mode = -1; ++static int hf_nfapi_pcfich_power_offset = -1; ++static int hf_nfapi_pb = -1; ++static int hf_nfapi_dl_cyclic_prefix_type = -1; ++static int hf_nfapi_ul_cyclic_prefix_type = -1; ++static int hf_nfapi_tx_antenna_ports = -1; ++static int hf_nfapi_rx_antenna_ports = -1; ++static int hf_nfapi_downlink_channel_bandwidth = -1; ++static int hf_nfapi_uplink_channel_bandwidth = -1; ++static int hf_nfapi_reference_signal_power = -1; ++static int hf_nfapi_phich_resource = -1; ++static int hf_nfapi_phich_duration = -1; ++static int hf_nfapi_phich_power_offset = -1; ++static int hf_nfapi_primary_synchronization_signal_epre_eprers = -1; ++static int hf_nfapi_secondary_synchronization_signal_epre_eprers = -1; ++static int hf_nfapi_physical_cell_id = -1; ++static int hf_nfapi_configuration_index = -1; ++static int hf_nfapi_root_sequence_index = -1; ++static int hf_nfapi_zero_correlation_zone_configuration = -1; ++static int hf_nfapi_high_speed_flag = -1; ++static int hf_nfapi_frequency_offset = -1; ++static int hf_nfapi_hopping_mode = -1; ++static int hf_nfapi_hopping_offset = -1; ++static int hf_nfapi_delta_pucch_shift = -1; ++static int hf_nfapi_n_cqi_rb = -1; ++static int hf_nfapi_n_an_cs = -1; ++static int hf_nfapi_n1_pucch_an = -1; ++static int hf_nfapi_bandwidth_configuration = -1; ++static int hf_nfapi_max_up_pts = -1; ++static int hf_nfapi_srs_subframe_configuration = -1; ++static int hf_nfapi_srs_acknack_srs_simultaneous_transmission = -1; ++static int hf_nfapi_uplink_rs_hopping = -1; ++static int hf_nfapi_group_assignment = -1; ++static int hf_nfapi_cyclic_shift_1_for_drms = -1; ++static int hf_nfapi_subframe_assignment = -1; ++static int hf_nfapi_special_subframe_patterns = -1; ++static int hf_nfapi_ed_threshold_for_lbt_for_pdsch = -1; ++static int hf_nfapi_ed_threshold_for_lbt_for_drs = -1; ++static int hf_nfapi_pd_threshold = -1; ++static int hf_nfapi_multi_carrier_type = -1; ++static int hf_nfapi_multi_carrier_tx = -1; ++static int hf_nfapi_multi_carrier_freeze = -1; ++static int hf_nfapi_tx_antenna_ports_for_drs = -1; ++static int hf_nfapi_transmission_power_for_drs = -1; ++static int hf_nfapi_pbch_repetitions_enabled_r13 = -1; ++static int hf_nfapi_prach_cat_m_root_sequence_index = -1; ++static int hf_nfapi_prach_cat_m_zero_correlation_zone_configuration = -1; ++static int hf_nfapi_prach_cat_m_high_speed_flag = -1; ++static int hf_nfapi_prach_ce_level_0_enable = -1; ++static int hf_nfapi_prach_ce_level_0_configuration_index = -1; ++static int hf_nfapi_prach_ce_level_0_frequency_offset = -1; ++static int hf_nfapi_prach_ce_level_0_number_of_repetitions_per_attempt = -1; ++static int hf_nfapi_prach_ce_level_0_starting_subframe_periodicity = -1; ++static int hf_nfapi_prach_ce_level_0_hopping_enabled = -1; ++static int hf_nfapi_prach_ce_level_0_hopping_offset = -1; ++static int hf_nfapi_prach_ce_level_1_enable = -1; ++static int hf_nfapi_prach_ce_level_1_configuration_index = -1; ++static int hf_nfapi_prach_ce_level_1_frequency_offset = -1; ++static int hf_nfapi_prach_ce_level_1_number_of_repetitions_per_attempt = -1; ++static int hf_nfapi_prach_ce_level_1_starting_subframe_periodicity = -1; ++static int hf_nfapi_prach_ce_level_1_hopping_enabled = -1; ++static int hf_nfapi_prach_ce_level_1_hopping_offset = -1; ++static int hf_nfapi_prach_ce_level_2_enable = -1; ++static int hf_nfapi_prach_ce_level_2_configuration_index = -1; ++static int hf_nfapi_prach_ce_level_2_frequency_offset = -1; ++static int hf_nfapi_prach_ce_level_2_number_of_repetitions_per_attempt = -1; ++static int hf_nfapi_prach_ce_level_2_starting_subframe_periodicity = -1; ++static int hf_nfapi_prach_ce_level_2_hopping_enabled = -1; ++static int hf_nfapi_prach_ce_level_2_hopping_offset = -1; ++static int hf_nfapi_prach_ce_level_3_enable = -1; ++static int hf_nfapi_prach_ce_level_3_configuration_index = -1; ++static int hf_nfapi_prach_ce_level_3_frequency_offset = -1; ++static int hf_nfapi_prach_ce_level_3_number_of_repetitions_per_attempt = -1; ++static int hf_nfapi_prach_ce_level_3_starting_subframe_periodicity = -1; ++static int hf_nfapi_prach_ce_level_3_hopping_enabled = -1; ++static int hf_nfapi_prach_ce_level_3_hopping_offset = -1; ++static int hf_nfapi_pucch_internal_ul_hopping_config_common_mode_b = -1; ++static int hf_nfapi_pucch_internal_ul_hopping_config_common_mode_a = -1; ++static int hf_nfapi_dl_modulation_support = -1; ++static int hf_nfapi_dl_modulation_support_qpsk = -1; ++static int hf_nfapi_dl_modulation_support_16qam = -1; ++static int hf_nfapi_dl_modulation_support_64qam = -1; ++static int hf_nfapi_dl_modulation_support_256qam = -1; ++static int hf_nfapi_ul_modulation_support = -1; ++static int hf_nfapi_ul_modulation_support_qpsk = -1; ++static int hf_nfapi_ul_modulation_support_16qam = -1; ++static int hf_nfapi_ul_modulation_support_64qam = -1; ++static int hf_nfapi_data_report_mode = -1; ++static int hf_nfapi_sfnsf = -1; ++ ++// P7 Sub Structures ++static int hf_nfapi_dl_dci_format = -1; ++static int hf_nfapi_ul_dci_format = -1; ++static int hf_nfapi_mpdcch_ul_dci_format = -1; ++static int hf_nfapi_cce_idx = -1; ++static int hf_nfapi_aggregation_level = -1; ++static int hf_nfapi_mcs_1 = -1; ++static int hf_nfapi_redundancy_version_1 = -1; ++static int hf_nfapi_new_data_indicator_1 = -1; ++static int hf_nfapi_mcs_2 = -1; ++static int hf_nfapi_redundancy_version_2 = -1; ++static int hf_nfapi_new_data_indicator_2 = -1; ++static int hf_nfapi_harq_process = -1; ++static int hf_nfapi_tpmi = -1; ++static int hf_nfapi_pmi = -1; ++static int hf_nfapi_precoding_information = -1; ++static int hf_nfapi_tpc = -1; ++static int hf_nfapi_downlink_assignment_index = -1; ++static int hf_nfapi_transport_block_size_index = -1; ++static int hf_nfapi_downlink_power_offset = -1; ++static int hf_nfapi_allocate_prach_flag = -1; ++static int hf_nfapi_preamble_index = -1; ++static int hf_nfapi_prach_mask_index = -1; ++static int hf_nfapi_rnti_type = -1; ++static int hf_nfapi_mpdcch_rnti_type = -1; ++static int hf_nfapi_mcch_flag = -1; ++static int hf_nfapi_mcch_change_notification = -1; ++static int hf_nfapi_scrambling_identity = -1; ++static int hf_nfapi_cross_carrier_scheduling_flag = -1; ++static int hf_nfapi_carrier_indicator = -1; ++static int hf_nfapi_srs_flag = -1; ++static int hf_nfapi_srs_request = -1; ++static int hf_nfapi_antenna_ports_scrambling_and_layers = -1; ++static int hf_nfapi_total_dci_length_including_padding = -1; ++static int hf_nfapi_harq_ack_resource_offset = -1; ++static int hf_nfapi_pdsch_re_mapping_and_quasi_co_location_indicator = -1; ++static int hf_nfapi_primary_cell_type = -1; ++static int hf_nfapi_ul_dl_configuration_flag = -1; ++static int hf_nfapi_number_of_ul_dl_configurations = -1; ++static int hf_nfapi_ul_dl_configuration_index = -1; ++static int hf_nfapi_laa_end_partial_sf_flag = -1; ++static int hf_nfapi_laa_end_partial_sf_configuration = -1; ++static int hf_nfapi_initial_lbt_sf = -1; ++static int hf_nfapi_codebooksize_determination_r13 = -1; ++static int hf_nfapi_rel13_drms_table_flag = -1; ++static int hf_nfapi_csi_rs_resource_config = -1; ++static int hf_nfapi_csi_rs_number_of_nzp_configurations = -1; ++static int hf_nfapi_pdsch_start = -1; ++static int hf_nfapi_drms_config_flag = -1; ++static int hf_nfapi_drms_scrambling = -1; ++static int hf_nfapi_csi_config_flag = -1; ++static int hf_nfapi_csi_scrambling = -1; ++static int hf_nfapi_pdsch_re_mapping_flag = -1; ++static int hf_nfapi_pdsch_re_mapping_antenna_ports = -1; ++static int hf_nfapi_pdsch_re_mapping_freq_shift = -1; ++static int hf_nfapi_alt_cqi_table_r12 = -1; ++static int hf_nfapi_max_layers = -1; ++static int hf_nfapi_n_dl_harq = -1; ++static int hf_nfapi_dwpts_symbols = -1; ++static int hf_nfapi_ue_type = -1; ++static int hf_nfapi_pdsch_payload_type = -1; ++static int hf_nfapi_initial_transmission_sf = -1; ++static int hf_nfapi_req13_drms_table_flag = -1; ++static int hf_nfapi_prnti = -1; ++static int hf_nfapi_mcs = -1; ++static int hf_nfapi_number_of_transport_blocks = -1; ++static int hf_nfapi_ue_mode = -1; ++static int hf_prs_bandwidth = -1; ++static int hf_prs_cyclic_prefix_type = -1; ++static int hf_prs_muting = -1; ++static int hf_nfapi_csi_rs_resource_index = -1; ++static int hf_nfapi_csi_rs_class = -1; ++static int hf_nfapi_cdm_type = -1; ++static int hf_nfapi_edpcch_prb_index = -1; ++static int hf_nfapi_epdcch_resource_assignment_flag = -1; ++static int hf_nfapi_epdcch_id = -1; ++static int hf_nfapi_epdcch_start_symbol = -1; ++static int hf_nfapi_epdcch_num_prb = -1; ++static int hf_nfapi_precoding_value = -1; ++static int hf_nfapi_mpdcch_narrowband = -1; ++static int hf_nfapi_number_of_prb_pairs = -1; ++static int hf_nfapi_resource_block_assignment = -1; ++static int hf_nfapi_start_symbol = -1; ++static int hf_nfapi_ecce_index = -1; ++static int hf_nfapi_ce_mode = -1; ++static int hf_nfapi_drms_scrabmling_init = -1; ++static int hf_nfapi_pdsch_reception_levels = -1; ++static int hf_nfapi_new_data_indicator = -1; ++static int hf_nfapi_tpmi_length = -1; ++static int hf_nfapi_pmi_flag = -1; ++static int hf_nfapi_harq_resource_offset = -1; ++static int hf_nfapi_dci_subframe_repetition_number = -1; ++static int hf_nfapi_downlink_assignment_index_length = -1; ++static int hf_nfapi_starting_ce_level = -1; ++static int hf_nfapi_antenna_ports_and_scrambling_identity_flag = -1; ++static int hf_nfapi_antenna_ports_and_scrambling_identity = -1; ++static int hf_nfapi_paging_direct_indication_differentiation_flag = -1; ++static int hf_nfapi_direct_indication = -1; ++static int hf_nfapi_number_of_tx_antenna_ports = -1; ++ ++// P7 Message Structures ++static int hf_nfapi_dl_node_sync_t1 = -1; ++static int hf_nfapi_dl_node_sync_delta_sfn_sf = -1; ++static int hf_nfapi_ul_node_sync_t1 = -1; ++static int hf_nfapi_ul_node_sync_t2 = -1; ++static int hf_nfapi_ul_node_sync_t3 = -1; ++static int hf_nfapi_timing_info_last_sfn_sf = -1; ++static int hf_nfapi_timing_info_time_since_last_timing_info = -1; ++static int hf_nfapi_timing_info_dl_config_jitter = -1; ++static int hf_nfapi_timing_info_tx_request_jitter = -1; ++static int hf_nfapi_timing_info_ul_config_jitter = -1; ++static int hf_nfapi_timing_info_hi_dci0_jitter = -1; ++static int hf_nfapi_timing_info_dl_config_latest_delay = -1; ++static int hf_nfapi_timing_info_tx_request_latest_delay = -1; ++static int hf_nfapi_timing_info_ul_config_latest_delay = -1; ++static int hf_nfapi_timing_info_hi_dci0_latest_delay = -1; ++static int hf_nfapi_timing_info_dl_config_earliest_arrival = -1; ++static int hf_nfapi_timing_info_tx_request_earliest_arrival = -1; ++static int hf_nfapi_timing_info_ul_config_earliest_arrival = -1; ++static int hf_nfapi_timing_info_hi_dci0_earliest_arrival = -1; ++static int hf_nfapi_sfn_sf = -1; ++static int hf_nfapi_number_pdcch_ofdm_symbols = -1; ++static int hf_nfapi_number_dci = -1; ++static int hf_nfapi_number_pdus = -1; ++static int hf_nfapi_number_pdsch_rnti = -1; ++static int hf_nfapi_transmission_power_pcfich = -1; ++static int hf_nfapi_number_of_harqs = -1; ++static int hf_nfapi_number_of_crcs = -1; ++static int hf_nfapi_number_of_srs = -1; ++static int hf_nfapi_number_of_cqi = -1; ++static int hf_nfapi_number_of_preambles = -1; ++static int hf_nfapi_number_of_srss = -1; ++static int hf_nfapi_lbt_dl_req_pdu_type = -1; ++static int hf_nfapi_lbt_dl_ind_pdu_type = -1; ++static int hf_nfapi_dl_config_pdu_type = -1; ++static int hf_nfapi_pdu_size = -1; ++static int hf_nfapi_instance_length = -1; ++static int hf_nfapi_length; ++static int hf_nfapi_pdu_index = -1; ++static int hf_nfapi_rnti = -1; ++static int hf_nfapi_resource_allocation_type = -1; ++static int hf_nfapi_virtual_resource_block_assignment_flag = -1; ++static int hf_nfapi_resource_block_coding = -1; ++static int hf_nfapi_modulation = -1; ++static int hf_nfapi_redundancy_version = -1; ++static int hf_nfapi_transport_blocks = -1; ++static int hf_nfapi_transport_block_to_codeword_swap_flag = -1; ++static int hf_nfapi_transmission_scheme = -1; ++static int hf_nfapi_ul_transmission_scheme = -1; ++static int hf_nfapi_number_of_layers = -1; ++static int hf_nfapi_number_of_subbands = -1; ++static int hf_nfapi_codebook_index = -1; ++static int hf_nfapi_ue_category_capacity = -1; ++static int hf_nfapi_pa = -1; ++static int hf_nfapi_delta_power_offset_index = -1; ++static int hf_nfapi_ngap = -1; ++static int hf_nfapi_nprb = -1; ++static int hf_nfapi_transmission_mode = -1; ++static int hf_nfapi_num_bf_prb_per_subband = -1; ++static int hf_nfapi_num_bf_vector = -1; ++static int hf_nfapi_bf_vector_subband_index = -1; ++static int hf_nfapi_bf_vector_num_antennas = -1; ++static int hf_nfapi_bf_vector_bf_value = -1; ++static int hf_nfapi_nscid = -1; ++static int hf_nfapi_csi_rs_flag = -1; ++static int hf_nfapi_csi_rs_resource_config_r10 = -1; ++static int hf_nfapi_csi_rs_zero_tx_power_resource_config_bitmap_r10 = -1; ++static int hf_nfapi_transmission_power = -1; ++static int hf_nfapi_mbsfn_area_id = -1; ++static int hf_nfapi_csi_rs_antenna_port_count_r10 = -1; ++static int hf_nfapi_ul_config_pdu_type = -1; ++static int hf_nfapi_rach_prach_frequency_resources = -1; ++static int hf_nfapi_srs_present = -1; ++static int hf_nfapi_handle = -1; ++static int hf_nfapi_pucch_index = -1; ++static int hf_nfapi_size = -1; ++static int hf_nfapi_resource_block_start = -1; ++static int hf_nfapi_number_of_resource_blocks = -1; ++static int hf_nfapi_cyclic_shift_2_for_drms = -1; ++static int hf_nfapi_frequency_hopping_enabled_flag = -1; ++static int hf_nfapi_frequency_hopping_bits = -1; ++static int hf_nfapi_new_data_indication = -1; ++static int hf_nfapi_harq_process_number = -1; ++static int hf_nfapi_ul_tx_mode = -1; ++static int hf_nfapi_current_tx_nb = -1; ++static int hf_nfapi_n_srs = -1; ++static int hf_nfapi_disable_sequence_hopping_flag = -1; ++static int hf_nfapi_dl_cqi_pmi_size_rank_1 = -1; ++static int hf_nfapi_dl_cqi_pmi_size_rank_greater_1 = -1; ++static int hf_nfapi_ri_size = -1; ++static int hf_nfapi_delta_offset_cqi = -1; ++static int hf_nfapi_delta_offset_ri = -1; ++static int hf_nfapi_harq_size = -1; ++static int hf_nfapi_delta_offset_harq = -1; ++static int hf_nfapi_tdd_ack_nack_mode = -1; ++static int hf_nfapi_fdd_ack_nack_mode = -1; ++static int hf_nfapi_n_srs_initial = -1; ++static int hf_nfapi_initial_number_of_resource_blocks = -1; ++static int hf_nfapi_dl_cqi_pmi_size = -1; ++static int hf_nfapi_report_type = -1; ++static int hf_nfapi_dl_cqi_ri_pmi_size = -1; ++static int hf_nfapi_control_type = -1; ++static int hf_nfapi_number_of_cc = -1; ++static int hf_nfapi_virtual_cell_id_enabled_flag = -1; ++static int hf_nfapi_npusch_identity = -1; ++static int hf_nfapi_ndrms_csh_identity = -1; ++static int hf_nfapi_total_number_of_repetitions = -1; ++static int hf_nfapi_repetition_number = -1; ++static int hf_nfapi_initial_sf_io = -1; ++static int hf_nfapi_empty_symbols_due_to_retunning = -1; ++static int hf_nfapi_dl_cqi_ri_pmi_size_2 = -1; ++static int hf_nfapi_npucch_identity = -1; ++static int hf_nfapi_harq_size_2 = -1; ++static int hf_nfapi_delta_offset_harq_2 = -1; ++static int hf_nfapi_empty_symbols = -1; ++static int hf_nfapi_csi_mode = -1; ++static int hf_nfapi_dl_cqi_pmi_size_2 = -1; ++static int hf_nfapi_statring_prb = -1; ++static int hf_nfapi_cdm_index = -1; ++static int hf_nfapi_nsrs = -1; ++static int hf_nfapi_num_ant_ports = -1; ++static int hf_nfapi_n_pucch_2_0 = -1; ++static int hf_nfapi_n_pucch_2_1 = -1; ++static int hf_nfapi_n_pucch_2_2 = -1; ++static int hf_nfapi_n_pucch_2_3 = -1; ++static int hf_nfapi_starting_prb = -1; ++static int hf_nfapi_antenna_port = -1; ++static int hf_nfapi_number_of_combs = -1; ++static int hf_nfapi_number_of_pucch_resource = -1; ++static int hf_nfapi_pucch_index_p1 = -1; ++static int hf_nfapi_n_pucch_1_0 = -1; ++static int hf_nfapi_n_pucch_1_1 = -1; ++static int hf_nfapi_n_pucch_1_2 = -1; ++static int hf_nfapi_n_pucch_1_3 = -1; ++static int hf_nfapi_srs_bandwidth = -1; ++static int hf_nfapi_frequency_domain_position = -1; ++static int hf_nfapi_srs_hopping_bandwidth = -1; ++static int hf_nfapi_transmission_comb = -1; ++static int hf_nfapi_i_srs = -1; ++static int hf_nfapi_sounding_reference_cyclic_shift = -1; ++static int hf_nfapi_pdu_length = -1; ++static int hf_nfapi_crc_flag = -1; ++static int hf_nfapi_number_of_hi_pdus = -1; ++static int hf_nfapi_number_of_dci_pdus = -1; ++static int hf_nfapi_hi_dci0_pdu_type = -1; ++static int hf_nfapi_hi_value = -1; ++static int hf_nfapi_i_phich = -1; ++static int hf_nfapi_flag_tb2 = -1; ++static int hf_nfapi_hi_value_2 = -1; ++static int hf_nfapi_ue_tx_antenna_selection = -1; ++static int hf_nfapi_cqi_csi_request = -1; ++static int hf_nfapi_ul_index = -1; ++static int hf_nfapi_dl_assignment_index = -1; ++static int hf_nfapi_tpc_bitmap = -1; ++static int hf_nfapi_new_data_indication_two = -1; ++static int hf_nfapi_size_of_cqi_csi_feild = -1; ++static int hf_nfapi_resource_allocation_flag = -1; ++static int hf_nfapi_number_of_antenna_ports = -1; ++static int hf_nfapi_n_ul_rb = -1; ++static int hf_nfapi_pscch_resource = -1; ++static int hf_nfapi_time_resource_pattern = -1; ++static int hf_nfapi_mpdcch_transmission_type = -1; ++static int hf_nfapi_drms_scrambling_init = -1; ++static int hf_nfapi_pusch_repetition_levels = -1; ++static int hf_nfapi_frequency_hopping_flag = -1; ++static int hf_nfapi_csi_request = -1; ++static int hf_nfapi_dai_presence_flag = -1; ++static int hf_nfapi_total_dci_length_include_padding = -1; ++static int hf_nfapi_data_offset = -1; ++static int hf_nfapi_ul_cqi = -1; ++static int hf_nfapi_timing_advance_r9 = -1; ++static int hf_nfapi_timing_advance = -1; ++static int hf_nfapi_harq_data_value_0 = -1; ++static int hf_nfapi_harq_data_value_0_special = -1; ++static int hf_nfapi_harq_data_value_1 = -1; ++static int hf_nfapi_harq_data_value_2 = -1; ++static int hf_nfapi_harq_data_value_3 = -1; ++static int hf_nfapi_tdd_harq_mode = -1; ++static int hf_nfapi_fdd_harq_mode = -1; ++static int hf_nfapi_number_of_ack_nack = -1; ++static int hf_nfapi_harq_tb_1 = -1; ++static int hf_nfapi_harq_tb_2 = -1; ++static int hf_nfapi_harq_tb_n = -1; ++static int hf_nfapi_channel = -1; ++static int hf_nfapi_ri = -1; ++static int hf_nfapi_number_of_cc_reported = -1; ++static int hf_nfapi_preamble = -1; ++static int hf_nfapi_rach_resource_type = -1; ++static int hf_nfapi_snr = -1; ++static int hf_nfapi_doppler_estimation = -1; ++static int hf_nfapi_rb_start = -1; ++static int hf_nfapi_up_pts_symbol = -1; ++static int hf_nfapi_number_prb_per_subband = -1; ++static int hf_nfapi_number_antennas = -1; ++static int hf_nfapi_subband_index = -1; ++static int hf_nfapi_channel_coefficient = -1; ++static int hf_nfapi_ul_rtoa = -1; ++static int hf_nfapi_mp_cca = -1; ++static int hf_nfapi_n_cca = -1; ++static int hf_nfapi_offset = -1; ++static int hf_nfapi_lte_txop_sf = -1; ++static int hf_nfapi_txop_sfn_sf_end = -1; ++static int hf_nfapi_lbt_mode = -1; ++static int hf_nfapi_sfn_sf_end = -1; ++static int hf_nfapi_result = -1; ++static int hf_nfapi_txop_symbols = -1; ++static int hf_nfapi_initial_partial_sf = -1; ++static int hf_nfapi_frequency_band_indicator = -1; ++static int hf_nfapi_measurement_period = -1; ++static int hf_nfapi_bandwidth = -1; ++static int hf_nfapi_timeout = -1; ++static int hf_nfapi_number_of_earfcns = -1; ++static int hf_nfapi_uarfcn = -1; ++static int hf_nfapi_number_of_uarfcns = -1; ++static int hf_nfapi_arfcn = -1; ++static int hf_nfapi_arfcn_direction = -1; ++static int hf_nfapi_number_of_arfcns = -1; ++static int hf_nfapi_rssi = -1; ++static int hf_nfapi_number_of_rssi = -1; ++static int hf_nfapi_pci = -1; ++static int hf_nfapi_measurement_bandwidth = -1; ++static int hf_nfapi_exhaustive_search = -1; ++static int hf_nfapi_number_of_pci = -1; ++static int hf_nfapi_psc = -1; ++static int hf_nfapi_number_of_psc = -1; ++static int hf_nfapi_rsrp = -1; ++static int hf_nfapi_rsrq = -1; ++static int hf_nfapi_number_of_lte_cells_found = -1; ++static int hf_nfapi_rscp = -1; ++static int hf_nfapi_enco = -1; ++static int hf_nfapi_number_of_utran_cells_found = -1; ++static int hf_nfapi_bsic = -1; ++static int hf_nfapi_rxlev = -1; ++static int hf_nfapi_rxqual = -1; ++static int hf_nfapi_sfn_offset = -1; ++static int hf_nfapi_number_of_geran_cells_found = -1; ++static int hf_nfapi_number_of_tx_antenna = -1; ++static int hf_nfapi_mib_length = -1; ++static int hf_nfapi_mib = -1; ++static int hf_nfapi_phich_configuration = -1; ++static int hf_nfapi_retry_count = -1; ++static int hf_nfapi_sib1 = -1; ++static int hf_nfapi_si_periodicity = -1; ++static int hf_nfapi_si_index = -1; ++static int hf_nfapi_number_of_si_periodicity = -1; ++static int hf_nfapi_si_window_length = -1; ++static int hf_nfapi_sib_type = -1; ++static int hf_nfapi_sib_len = -1; ++static int hf_nfapi_sib = -1; ++static int hf_nfapi_si_len = -1; ++static int hf_nfapi_si = -1; ++static int hf_nfapi_pnf_search_state = -1; ++static int hf_nfapi_pnf_broadcast_state = -1; ++ ++static const value_string message_id_vals[] = ++{ ++ { NFAPI_DL_CONFIG_REQUEST_MSG_ID, "DL_CONFIG.request" }, ++ { NFAPI_UL_CONFIG_REQUEST_MSG_ID, "UL_CONFIG.request" }, ++ { NFAPI_SUBFRAME_INDICATION_MSG_ID, "SUBFRAME_INDICATION" }, ++ { NFAPI_HI_DCI0_REQUEST_MSG_ID, "HI_DCI0.request" }, ++ { NFAPI_TX_REQUEST_MSG_ID, "TX.request" }, ++ { NFAPI_HARQ_INDICATION_MSG_ID, "HARQ.indication" }, ++ { NFAPI_CRC_INDICATION_MSG_ID, "CRC.indication" }, ++ { NFAPI_RX_ULSCH_INDICATION_MSG_ID, "RX_ULSCH.indication" }, ++ { NFAPI_RACH_INDICATION_MSG_ID, "RACH.indication" }, ++ { NFAPI_SRS_INDICATION_MSG_ID, "SRS.indication" }, ++ { NFAPI_RX_SR_INDICATION_MSG_ID, "RX_SR.indication" }, ++ { NFAPI_RX_CQI_INDICATION_MSG_ID, "RX_CQI.indication" }, ++ { NFAPI_LBT_DL_CONFIG_REQUEST_MSG_ID, "LBT_DL_CONFIG.request" }, ++ { NFAPI_LBT_DL_INDICATION_MSG_ID, "LBT_DL.indication" }, ++ ++ { NFAPI_PNF_PARAM_REQUEST_MSG_ID, "PNF_PARAM.request" }, ++ { NFAPI_PNF_PARAM_RESPONSE_MSG_ID, "PNF_PARAM.response" }, ++ { NFAPI_PNF_CONFIG_REQUEST_MSG_ID, "PNF_CONFIG.request" }, ++ { NFAPI_PNF_CONFIG_RESPONSE_MSG_ID, "PNF_CONFIG.response" }, ++ { NFAPI_PNF_START_REQUEST_MSG_ID, "PNF_START.request" }, ++ { NFAPI_PNF_START_RESPONSE_MSG_ID, "PNF_START.response" }, ++ { NFAPI_PNF_STOP_REQUEST_MSG_ID, "PNF_STOP.request" }, ++ { NFAPI_PNF_STOP_RESPONSE_MSG_ID, "PNF_STOP.response" }, ++ { NFAPI_PARAM_REQUEST_MSG_ID, "PARAM.request" }, ++ { NFAPI_PARAM_RESPONSE_MSG_ID, "PARAM.response" }, ++ { NFAPI_CONFIG_REQUEST_MSG_ID, "CONFIG.request" }, ++ { NFAPI_CONFIG_RESPONSE_MSG_ID, "CONFIG.response" }, ++ { NFAPI_START_REQUEST_MSG_ID, "START.request" }, ++ { NFAPI_START_RESPONSE_MSG_ID, "START.response" }, ++ { NFAPI_STOP_REQUEST_MSG_ID, "STOP.request" }, ++ { NFAPI_STOP_RESPONSE_MSG_ID, "STOP.response" }, ++ { NFAPI_MEASUREMENT_REQUEST_MSG_ID, "MEASUREMENT.request" }, ++ { NFAPI_MEASUREMENT_RESPONSE_MSG_ID, "MEASUREMENT.response" }, ++ ++ { NFAPI_DL_NODE_SYNC_MSG_ID, "UL_NODE_SYNC" }, ++ { NFAPI_UL_NODE_SYNC_MSG_ID, "DL_NODE_SYNC" }, ++ { NFAPI_TIMING_INFO_MSG_ID, "TIMING_INFO" }, ++ ++ { NFAPI_RSSI_REQUEST_MSG_ID, "RSSI.request" }, ++ { NFAPI_RSSI_RESPONSE_MSG_ID, "RSSI.response" }, ++ { NFAPI_RSSI_INDICATION_MSG_ID, "RSSI.indication" }, ++ { NFAPI_CELL_SEARCH_REQUEST_MSG_ID, "CELL_SEARCH.request" }, ++ { NFAPI_CELL_SEARCH_RESPONSE_MSG_ID, "CELL_SEARCH.response" }, ++ { NFAPI_CELL_SEARCH_INDICATION_MSG_ID, "CELL_SEARCH.indication" }, ++ { NFAPI_BROADCAST_DETECT_REQUEST_MSG_ID, "BROADCAST_DETECT.request" }, ++ { NFAPI_BROADCAST_DETECT_RESPONSE_MSG_ID, "BROADCAST_DETECT.response" }, ++ { NFAPI_BROADCAST_DETECT_INDICATION_MSG_ID, "BROADCAST_DETECT.indication" }, ++ { NFAPI_SYSTEM_INFORMATION_SCHEDULE_REQUEST_MSG_ID, "SYSTEM_INFORMATION_SCHEDULE.request" }, ++ { NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE_MSG_ID, "SYSTEM_INFORMATION_SCHEDULE.response" }, ++ { NFAPI_SYSTEM_INFORMATION_SCHEDULE_INDICATION_MSG_ID, "SYSTEM_INFORMATION_SCHEDULE.indication" }, ++ { NFAPI_SYSTEM_INFORMATION_REQUEST_MSG_ID, "SYSTEM_INFORMATION.request" }, ++ { NFAPI_SYSTEM_INFORMATION_RESPONSE_MSG_ID, "SYSTEM_INFORMATION.response" }, ++ { NFAPI_SYSTEM_INFORMATION_INDICATION_MSG_ID, "SYSTEM_INFORMATION.indication" }, ++ { NFAPI_NMM_STOP_REQUEST_MSG_ID, "NMM_STOP.request" }, ++ { NFAPI_NMM_STOP_RESPONSE_MSG_ID, "NMM_STOP.response" }, ++ ++ { 0, NULL }, ++}; ++ ++typedef void(*tlv_decode)(ptvcursor_t * ptvc, packet_info* pinfo); ++ ++typedef struct ++{ ++ guint16 tag_id; ++ char* name; ++ tlv_decode decode; ++} tlv_t; ++ ++static void dissect_tlv_list(ptvcursor_t * ptvc, packet_info* pinfo, gint len); ++ ++static void dissect_array_value(ptvcursor_t * ptvc, packet_info* pinfo, const char* name, guint32 ett_idx, guint32 count, tlv_decode decode) ++{ ++ guint16 i = 0; ++ ++ if (count > 0) ++ { ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_idx, "%s", name); ++ ++ for (i = 0; i < count; ++i) ++ { ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_idx, "[%d]", i); ++ decode(ptvc, pinfo); ++ ptvcursor_pop_subtree(ptvc); ++ } ++ ++ ptvcursor_pop_subtree(ptvc); ++ } ++} ++ ++static void dissect_pnf_param_general_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // nFAPI Sync Mode ++ guint8 nfapi_sync_mode_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_sync_mode, 1, ENC_BIG_ENDIAN); ++ if (nfapi_sync_mode_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid nfapi sync mode value [0..2]"); ++ } ++ ++ // Location Mode ++ guint8 location_mode_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_location_mode, 1, ENC_BIG_ENDIAN); ++ if (location_mode_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid location mode value [0..3]"); ++ } ++ ++ guint16 len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_location_coordinates_length, 2, ENC_BIG_ENDIAN); ++ if (len > 0) ++ ptvcursor_add(ptvc, hf_nfapi_location_coordinates, len, ENC_NA); ++ ptvcursor_add(ptvc, hf_nfapi_dl_config_timing, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_tx_timing, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_ul_config_timing, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_hi_dci0_timing, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_maximum_number_phys, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_maximum_total_bandwidth, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_maximum_total_number_dl_layers, 1, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_maximum_total_number_ul_layers, 1, ENC_BIG_ENDIAN); ++ ++ // Shared Bands ++ guint8 shared_bands_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_shared_bands, 1, ENC_BIG_ENDIAN); ++ if (shared_bands_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid shared bands value [0..1]"); ++ } ++ ++ // Shared PA ++ guint8 shared_pa_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_shared_pa, 1, ENC_BIG_ENDIAN); ++ if (shared_pa_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid shared pa value [0..1]"); ++ } ++ ++ ptvcursor_add(ptvc, hf_nfapi_maximum_total_power, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_oui, 3, ENC_HOST_ENDIAN); ++} ++static void dissect_pnf_rf_config_instance_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_rf_config_index, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_pnf_phy_instance_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ ptvcursor_add(ptvc, hf_nfapi_pnf_phy_config_index, 2, ENC_BIG_ENDIAN); ++ ++ guint16 num_rf_configs = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_rfs, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "RF Config List", ett_nfapi_pnf_phy, num_rf_configs, dissect_pnf_rf_config_instance_value); ++ ++ guint16 num_rf_exclusions = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_rf_exclusions, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "RF Exclustion List", ett_nfapi_pnf_phy, num_rf_exclusions, dissect_pnf_rf_config_instance_value); ++ ++ // Downlink Channel Bandwidth Supported ++ guint16 downlink_channel_bandwidth_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add_no_advance(ptvc, hf_nfapi_downlink_channel_bandwidth_supported, 2, ENC_BIG_ENDIAN); ++ if (downlink_channel_bandwidth_supported_value > 0x3F) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid downlink channel bandwidht supported bits [0..0x3F]"); ++ } ++ ++ proto_tree* dl_bw_support_tree = proto_item_add_subtree(item, ett_nfapi_downlink_bandwidth_support); ++ ++ proto_tree_add_bits_item(dl_bw_support_tree, hf_nfapi_dl_bandwidth_support_6, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 15, 1, ENC_NA); ++ proto_tree_add_bits_item(dl_bw_support_tree, hf_nfapi_dl_bandwidth_support_15, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 14, 1, ENC_NA); ++ proto_tree_add_bits_item(dl_bw_support_tree, hf_nfapi_dl_bandwidth_support_25, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 13, 1, ENC_NA); ++ proto_tree_add_bits_item(dl_bw_support_tree, hf_nfapi_dl_bandwidth_support_50, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 12, 1, ENC_NA); ++ proto_tree_add_bits_item(dl_bw_support_tree, hf_nfapi_dl_bandwidth_support_75, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 11, 1, ENC_NA); ++ proto_tree_add_bits_item(dl_bw_support_tree, hf_nfapi_dl_bandwidth_support_100, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 10, 1, ENC_NA); ++ ++ ptvcursor_advance(ptvc, 2); ++ ++ ++ ++ // Uplink Channel Bandwidth Supported ++ guint16 uplink_channel_bandwidth_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add_no_advance(ptvc, hf_nfapi_uplink_channel_bandwidth_supported, 2, ENC_BIG_ENDIAN); ++ if (uplink_channel_bandwidth_supported_value > 0x3F) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid uplink channel bandwidht supported bits [0..0x3F]"); ++ } ++ ++ proto_tree* ul_bw_support_tree = proto_item_add_subtree(item, ett_nfapi_uplink_bandwidth_support); ++ ++ proto_tree_add_bits_item(ul_bw_support_tree, hf_nfapi_ul_bandwidth_support_6, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 15, 1, ENC_NA); ++ proto_tree_add_bits_item(ul_bw_support_tree, hf_nfapi_ul_bandwidth_support_15, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 14, 1, ENC_NA); ++ proto_tree_add_bits_item(ul_bw_support_tree, hf_nfapi_ul_bandwidth_support_25, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 13, 1, ENC_NA); ++ proto_tree_add_bits_item(ul_bw_support_tree, hf_nfapi_ul_bandwidth_support_50, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 12, 1, ENC_NA); ++ proto_tree_add_bits_item(ul_bw_support_tree, hf_nfapi_ul_bandwidth_support_75, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 11, 1, ENC_NA); ++ proto_tree_add_bits_item(ul_bw_support_tree, hf_nfapi_ul_bandwidth_support_100, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 10, 1, ENC_NA); ++ ++ ptvcursor_advance(ptvc, 2); ++ ++ // Number of DL layers supported ++ guint8 number_of_dl_layer_supported_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_dl_layers_supported, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_dl_layer_supported_value == 1 || number_of_dl_layer_supported_value == 2 || ++ number_of_dl_layer_supported_value == 4 || number_of_dl_layer_supported_value == 8)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of dl layers supported value [1, 2, 4, 8]"); ++ } ++ ++ // Number of DL layers supported ++ guint8 number_of_ul_layer_supported_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_ul_layers_supported, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_ul_layer_supported_value == 1 || number_of_ul_layer_supported_value == 2 || ++ number_of_ul_layer_supported_value == 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ul layers supported value [1, 2, 4]"); ++ } ++ ++ // Maximum 3GPP Release Supported ++ guint16 maximum_3gpp_release_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add_no_advance(ptvc, hf_nfapi_maximum_3gpp_release_supported, 2, ENC_BIG_ENDIAN); ++ if (maximum_3gpp_release_supported_value > 0x3F) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid maximum 3GPP release supported value [0..0x3F]"); ++ } ++ ++ proto_tree* release_support_tree = proto_item_add_subtree(item, ett_nfapi_release_support); ++ ++ proto_tree_add_bits_item(release_support_tree, hf_nfapi_maximum_3gpp_release_supported_rel8, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 15, 1, ENC_NA); ++ proto_tree_add_bits_item(release_support_tree, hf_nfapi_maximum_3gpp_release_supported_rel9, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 14, 1, ENC_NA); ++ proto_tree_add_bits_item(release_support_tree, hf_nfapi_maximum_3gpp_release_supported_rel10, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 13, 1, ENC_NA); ++ proto_tree_add_bits_item(release_support_tree, hf_nfapi_maximum_3gpp_release_supported_rel11, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 12, 1, ENC_NA); ++ proto_tree_add_bits_item(release_support_tree, hf_nfapi_maximum_3gpp_release_supported_rel12, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 11, 1, ENC_NA); ++ proto_tree_add_bits_item(release_support_tree, hf_nfapi_maximum_3gpp_release_supported_rel13, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 10, 1, ENC_NA); ++ ++ ptvcursor_advance(ptvc, 2); ++ ++ ++ // NMM Modes Supported ++ guint8 nmm_modes_supported_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_nmm_modes_supported, 1, ENC_BIG_ENDIAN); ++ if (nmm_modes_supported_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid nmm modes supported value [0..3]"); ++ } ++} ++ ++static void dissect_pnf_phy_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 num_phy = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pnf_phy_number_phy, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "PHY List", ett_nfapi_pnf_phy, num_phy, dissect_pnf_phy_instance_value); ++} ++ ++static void dissect_pnf_rf_config_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ ptvcursor_add(ptvc, hf_nfapi_rf_config_index, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_band, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_maximum_transmit_power, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_minimum_transmit_power, 2, ENC_BIG_ENDIAN); ++ ++ guint8 number_of_antennas_supported_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_antennas_suppported, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_antennas_supported_value == 1 || number_of_antennas_supported_value == 2 || ++ number_of_antennas_supported_value == 4 || number_of_antennas_supported_value == 8)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of supported antennas [1, 2, 4, 8]"); ++ } ++ ++ ptvcursor_add(ptvc, hf_nfapi_minimum_downlink_frequency, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_maximum_downlink_frequency, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_minimum_uplink_frequency, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_maximum_uplink_frequency, 4, ENC_BIG_ENDIAN); ++} ++ ++ ++static void dissect_pnf_rf_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 num_rf = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_rfs, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "RF List", ett_nfapi_pnf_phy_rf_config, num_rf, dissect_pnf_rf_config_value); ++} ++ ++static void dissect_pnf_phy_rel10_instance_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // PHY Config Index ++ ptvcursor_add(ptvc, hf_nfapi_pnf_phy_config_index, 2, ENC_BIG_ENDIAN); ++ ++ // Transmission mode 7 supported ++ guint16 transmission_mode7_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_mode7_supported, 2, ENC_BIG_ENDIAN); ++ if (transmission_mode7_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission mode 7 supported value [0..1]"); ++ } ++ ++ // Two antennas ports for PUCCH ++ guint16 transmission_mode8_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hi_nfapi_transmission_mode8_supported, 2, ENC_BIG_ENDIAN); ++ if (transmission_mode8_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission mode 8 supported value [0..1]"); ++ } ++ ++ // Transmission mode 8 supported ++ guint16 two_antennas_port_for_pucch_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hi_nfapi_two_antennas_ports_for_pucch, 2, ENC_BIG_ENDIAN); ++ if (two_antennas_port_for_pucch_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid two antennas ports for pucch value [0..1]"); ++ } ++ ++ // Transmission mode 9 supported ++ guint16 transmission_mode9_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hi_nfapi_transmission_mode_9_supported, 2, ENC_BIG_ENDIAN); ++ if (transmission_mode9_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission mode 9 supported value [0..1]"); ++ } ++ ++ // Simultaneous PUCCH PUSCH ++ guint16 simultaenous_pucch_pusch_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hi_nfapi_simultaneous_pucch_pusch, 2, ENC_BIG_ENDIAN); ++ if (simultaenous_pucch_pusch_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid simultaneous pucch pusch supported value [0..1]"); ++ } ++ ++ // Four layer Tx with TM3 and TM4 ++ guint16 four_layer_tx_with_tm3_and_tm4_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hi_nfapi_four_layer_tx_with_tm3_and_tm4, 2, ENC_BIG_ENDIAN); ++ if (four_layer_tx_with_tm3_and_tm4_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid four layer tx with tm3 and tm4 value [0..1]"); ++ } ++} ++ ++static void dissect_pnf_phy_rel10_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 num_phy = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pnf_phy_number_phy, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "PHY Rel 10 List", ett_nfapi_pnf_phy_rel10, num_phy, dissect_pnf_phy_rel10_instance_value); ++} ++ ++static void dissect_pnf_phy_rel11_instance_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // PHY Config Index ++ ptvcursor_add(ptvc, hf_nfapi_pnf_phy_config_index, 2, ENC_BIG_ENDIAN); ++ ++ // ePDCCH supported ++ guint16 epdcch_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_epdcch_supported, 2, ENC_BIG_ENDIAN); ++ if (epdcch_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid edpcch supported value [0..1]"); ++ } ++ ++ // Multi ACK CSI reporting ++ guint16 multi_ack_csi_reporting_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hi_nfapi_multi_ack_csi_reporting, 2, ENC_BIG_ENDIAN); ++ if (multi_ack_csi_reporting_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid multi ack csi reporting value [0..1]"); ++ } ++ ++ // PUCCH Tx diversity with channel selection ++ guint16 pucch_tx_diversity_with_channel_selection_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hi_nfapi_pucch_tx_diversity_with_channel_selection, 2, ENC_BIG_ENDIAN); ++ if (pucch_tx_diversity_with_channel_selection_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pucch tx diversity with channel selection value [0..1]"); ++ } ++ ++ // UL CoMP supported ++ guint16 ul_comp_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hi_nfapi_ul_comp_supported, 2, ENC_BIG_ENDIAN); ++ if (ul_comp_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ul comp supported value [0..1]"); ++ } ++ ++ // Transmission mode 5 supported ++ guint16 transmission_mode_5_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hi_nfapi_transmission_mode_5_supported, 2, ENC_BIG_ENDIAN); ++ if (transmission_mode_5_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission mode 5 supported value [0..1]"); ++ } ++} ++ ++static void dissect_pnf_phy_rel11_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 num_phy = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pnf_phy_number_phy, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "PHY Rel 11 List", ett_nfapi_pnf_phy_rel11, num_phy, dissect_pnf_phy_rel11_instance_value); ++} ++ ++static void dissect_pnf_phy_rel12_instance_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // PHY Config Index ++ ptvcursor_add(ptvc, hf_nfapi_pnf_phy_config_index, 2, ENC_BIG_ENDIAN); ++ ++ // CSI subframe set ++ guint16 csi_subframe_set_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_csi_subframe_set, 2, ENC_BIG_ENDIAN); ++ if (csi_subframe_set_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid csi subframe set value [0..1]"); ++ } ++ ++ // Enhanced 4TX codebook ++ guint16 enhanced_4tx_codebook_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hi_nfapi_enhanced_4tx_codebook, 2, ENC_BIG_ENDIAN); ++ if (enhanced_4tx_codebook_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid enhanced 4TX codebook value [0..1]"); ++ } ++ ++ // DRS supported ++ guint16 drs_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hi_nfapi_drs_supported, 2, ENC_BIG_ENDIAN); ++ if (drs_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid drs supported value [0..1]"); ++ } ++ ++ // UL 64QAM supported ++ guint16 ul_64qam_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hi_nfapi_ul_64qam_supported, 2, ENC_BIG_ENDIAN); ++ if (ul_64qam_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ul 64 QAM supported value [0..1]"); ++ } ++ ++ // Transmission mode 10 supported ++ guint16 transmission_mode_10_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hi_nfapi_transmission_mode_10_supported, 2, ENC_BIG_ENDIAN); ++ if (transmission_mode_10_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission mode 10 supported value [0..1]"); ++ } ++ ++ // Alternative TBS indices ++ guint16 alternative_tbs_indices_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hi_nfapi_alternative_tbs_indices, 2, ENC_BIG_ENDIAN); ++ if (alternative_tbs_indices_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid alternative tbs indicies supported value [0..1]"); ++ } ++} ++ ++static void dissect_pnf_phy_rel12_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 num_phy = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pnf_phy_number_phy, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "PHY Rel 12 List", ett_nfapi_pnf_phy_rel12, num_phy, dissect_pnf_phy_rel12_instance_value); ++} ++ ++static void dissect_pnf_phy_rel13_instance_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // PHY Config Index ++ ptvcursor_add(ptvc, hf_nfapi_pnf_phy_config_index, 2, ENC_BIG_ENDIAN); ++ ++ // PUCCH format 4 supported ++ guint16 pucch_format_4_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pucch_format_4_supported, 2, ENC_BIG_ENDIAN); ++ if (pucch_format_4_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pucch format 4 supported value [0..1]"); ++ } ++ ++ // PUCCH format 5 supported ++ guint16 pucch_format_5_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pucch_format_5_supported, 2, ENC_BIG_ENDIAN); ++ if (pucch_format_5_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pucch format 5 supported value [0..1]"); ++ } ++ ++ // More than 5 CA support ++ guint16 more_than_5_ca_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_more_than_5_ca_supported, 2, ENC_BIG_ENDIAN); ++ if (more_than_5_ca_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid more than 5 ca supported value [0..1]"); ++ } ++ ++ // LAA supported ++ guint16 laa_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_laa_supported, 2, ENC_BIG_ENDIAN); ++ if (laa_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid laa supported value [0..1]"); ++ } ++ ++ // LAA ending in DwPTS supported ++ guint16 laa_ending_in_dwpts_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_laa_ending_in_dwpts_supported, 2, ENC_BIG_ENDIAN); ++ if (laa_ending_in_dwpts_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid laa ending in dwpts supported value [0..1]"); ++ } ++ ++ // LAA starting in second slot Supported ++ guint16 laa_starting_in_second_slot_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_laa_starting_in_second_slot_supported, 2, ENC_BIG_ENDIAN); ++ if (laa_starting_in_second_slot_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid laa starting in second slot supported value [0..1]"); ++ } ++ ++ // Beamforming Supported ++ guint16 beamingforming_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_beamforming_supported, 2, ENC_BIG_ENDIAN); ++ if (beamingforming_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid beamforming supported value [0..1]"); ++ } ++ ++ // CSI-RS enhancements supported ++ guint16 csi_rs_enhancements_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_csi_rs_enhancements_supported, 2, ENC_BIG_ENDIAN); ++ if (csi_rs_enhancements_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid csi rs enhancements supported value [0..1]"); ++ } ++ ++ // DMRS enhancements supported ++ guint16 drms_enhancements_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_drms_enhancements_supported, 2, ENC_BIG_ENDIAN); ++ if (drms_enhancements_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid drms enhancements supported value [0..1]"); ++ } ++ ++ // SRS enhancements supported ++ guint16 srs_enhancements_supported_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_srs_enhancements_supported, 2, ENC_BIG_ENDIAN); ++ if (srs_enhancements_supported_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid srs enhancements supported value [0..1]"); ++ } ++ ++} ++ ++static void dissect_pnf_phy_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 num_phy = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pnf_phy_number_phy, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "PHY Rel 13 List", ett_nfapi_pnf_phy_rel13, num_phy, dissect_pnf_phy_rel13_instance_value); ++} ++ ++static void dissect_pnf_phy_rf_config_instance_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_phy_rf_config_info_phy_id, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_pnf_phy_config_index, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_rf_config_index, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_pnf_phy_rf_config_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 num_configs = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pnf_phy_number_phy, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "PHY RF Config List", ett_nfapi_pnf_phy_rf_config, num_configs, dissect_pnf_phy_rf_config_instance_value); ++} ++ ++static void dissect_dl_rs_tx_power_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_dl_rs_tx_power, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value >= 1 && value <= 255)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value [1..255]"); ++ } ++} ++static void dissect_received_interference_power_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_received_interference_power, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value >= 1 && value <= 255)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value [1..255]"); ++ } ++} ++static void dissect_thermal_noise_power_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_thermal_noise_power, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_dl_rs_tx_power_measurement_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_dl_rs_tx_power_measurement, 2, ENC_BIG_ENDIAN); ++} ++ ++static void dissect_received_interference_power_result_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_received_interference_power_measurement, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_received_interference_power_measurement_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 num_resource_block = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_resource_blocks, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "Results", ett_nfapi_received_interference_power_mesurement_results, num_resource_block, dissect_received_interference_power_result_value); ++} ++static void dissect_thermal_noise_power_measurement_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_thermal_noise_power_measurement, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_duplex_mode_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_duplex_mode, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid duplex mode [0..2]"); ++ } ++} ++static void dissect_pcfich_power_offset_value(ptvcursor_t* ptvc, packet_info *pinfo) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_pcfich_power_offset, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid power level [0..10000]"); ++ } ++} ++static void dissect_pb_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_pb, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid downlink power allocation index [0..3]"); ++ } ++} ++ ++static void dissect_dl_cyclic_prefix_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_dl_cyclic_prefix_type, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid dl cyclic prefix type [0..1]"); ++ } ++} ++static void dissect_ul_cyclic_prefix_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_ul_cyclic_prefix_type, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ul cyclic prefix type [0..1]"); ++ } ++} ++static void dissect_dl_channel_bandwidth_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_downlink_channel_bandwidth, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 6 || value == 15 || value == 25 || value == 50 || value == 75 || value == 100)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid downlink bandwidth value [6, 15, 25, 50, 75, 100]"); ++ } ++} ++static void dissect_ul_channel_bandwidth_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_uplink_channel_bandwidth, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 6 || value == 15 || value == 25 || value == 50 || value == 75 || value == 100)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid uplink bandwidth value [6, 15, 25, 50, 75, 100]"); ++ } ++} ++static void dissect_reference_signal_power_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_reference_signal_power, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid reference signal power [0..255]"); ++ } ++ ++} ++static void dissect_tx_antenna_ports_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_tx_antenna_ports, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 1 || value == 2 || value == 4 || value == 8 || value == 16)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid tx antenna ports value [1, 2, 4, 8, 16]"); ++ } ++} ++static void dissect_rx_antenna_ports_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_rx_antenna_ports, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 1 || value == 2 || value == 4 || value == 8 || value == 16)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rx antenna ports value [1, 2, 4, 8, 16]"); ++ } ++} ++static void dissect_phich_resource_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_phich_resource, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid phich resource value [0..3]"); ++ } ++} ++static void dissect_phich_duration_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_phich_duration, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid phich duration value [0..1]"); ++ } ++} ++static void dissect_phich_power_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_phich_power_offset, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid phich power offset value [0..10000]"); ++ } ++} ++static void dissect_psch_synch_signal_epre_eprers_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_primary_synchronization_signal_epre_eprers, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid primary synchronization signal epre/eprers value [0..10000]"); ++ } ++} ++static void dissect_physical_cell_id_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_physical_cell_id, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 503) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid physical cell id [0..503]"); ++ } ++} ++static void dissect_ssch_synch_signal_epre_eprers_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_secondary_synchronization_signal_epre_eprers, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid secondary synchronization signal epre/eprers value [0..10000]"); ++ } ++} ++static void dissect_prach_configuration_index_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_configuration_index, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 63) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach configuration index [0..63]"); ++ } ++} ++static void dissect_prach_root_sequence_index_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_root_sequence_index, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 837) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach root sequency index [0..837]"); ++ } ++} ++static void dissect_prach_zero_correlation_zone_configuration_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_zero_correlation_zone_configuration, 2, ENC_BIG_ENDIAN); ++ ++ // How do differentiate between fdd 0..6 and tdd 0..15 ranges? ++ if (value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid zero correlation zone configuration [0..15]"); ++ } ++} ++static void dissect_prach_high_speed_flag_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_high_speed_flag, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid high speed flag value [0..1]"); ++ } ++} ++static void dissect_prach_frequency_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_frequency_offset, 2, ENC_BIG_ENDIAN); ++ ++ // How to determine the ul channel bandiwdth? ++ if (value > (100 -6)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach frequency offset value [0..94]"); ++ } ++} ++static void dissect_pusch_hopping_mode_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_hopping_mode, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pusch hopping mode value [0..1]"); ++ } ++} ++static void dissect_pusch_hopping_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_hopping_offset, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 98) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pusch hopping offset value [0..98]"); ++ } ++} ++static void dissect_pusch_number_of_subbands_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_number_of_subbands, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value >= 1 && value <= 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of sub-bands [1..4]"); ++ } ++} ++static void dissect_pucch_delta_pucch_shift_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_delta_pucch_shift, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value >= 1 && value <= 3)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid delta pucch shift [1..3]"); ++ } ++} ++static void dissect_pucch_n_cqi_rb_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_n_cqi_rb, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 98) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n cqi rb value [0..98]"); ++ } ++} ++static void dissect_pucch_n_an_cs_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_n_an_cs, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n an cs value [0..7]"); ++ } ++} ++static void dissect_pucch_n1_pucch_an_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_n1_pucch_an, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n1pucch an value [0..2047]"); ++ } ++} ++static void dissect_srs_bandwidth_configuration_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_bandwidth_configuration, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid srs bandwidth configuration value [0..7]"); ++ } ++} ++static void dissect_srs_max_uppts_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_max_up_pts, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid max up pts value [0..1]"); ++ } ++} ++static void dissect_srs_subframe_configuration_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_srs_subframe_configuration, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid srs subframe configuration value [0..15]"); ++ } ++} ++static void dissect_srs_acknack_srs_sim_tx_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_srs_acknack_srs_simultaneous_transmission, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid srs ack nack srs simultaneous transmission value [0..1]"); ++ } ++} ++static void dissect_uplink_rs_hopping_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_uplink_rs_hopping, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid uplink rs hopping value [0..2]"); ++ } ++} ++static void dissect_group_assignment_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_group_assignment, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 29) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid group assignment value [0..29]"); ++ } ++} ++static void dissect_cyclic_shift_1_for_drms_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_cyclic_shift_1_for_drms, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid cyclic shift 1 for drms value [0..7]"); ++ } ++} ++static void dissect_tdd_subframe_assignement_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_subframe_assignment, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 6) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid tdd subframe assignment value [0..6]"); ++ } ++} ++static void dissect_tdd_subframe_patterns_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_special_subframe_patterns, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 9) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid special subframe pattern value [0..9]"); ++ } ++} ++static void dissect_laa_ed_threashold_for_lbt_for_pdsch_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_ed_threshold_for_lbt_for_pdsch, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 70) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ed threshold for ltb for pdsch value [0..70]"); ++ } ++} ++static void dissect_laa_ed_threashold_for_lbt_for_drs_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_ed_threshold_for_lbt_for_drs, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 70) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ed threshold for ltb for drs value [0..70]"); ++ } ++} ++static void dissect_laa_pd_threshold_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_pd_threshold, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 70 && value != 65535) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pd threshold value [0..70, 65536]"); ++ } ++} ++static void dissect_laa_multi_carrier_type_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_multi_carrier_type, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 4) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mutli carrier type [0..4]"); ++ } ++} ++static void dissect_laa_multi_carrier_tx_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_multi_carrier_tx, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mutli carrier tx value [0..1]"); ++ } ++} ++static void dissect_laa_multi_carrier_freeze_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_multi_carrier_freeze, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mutli carrier freeze value [0..1]"); ++ } ++} ++static void dissect_laa_tx_antenna_port_for_drs_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_tx_antenna_ports_for_drs, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 1 || value == 2 || value == 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid tx antenna ports for drs value [1, 2, 4]"); ++ } ++} ++static void dissect_laa_transmission_power_for_drs_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_transmission_power_for_drs, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission power for drs [0..10000]"); ++ } ++} ++static void dissect_emtc_pbch_repeitions_enabled_r13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_pbch_repetitions_enabled_r13, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pbch repetitions enabled r13 value [0..1]"); ++ } ++} ++static void dissect_emtc_prach_cat_m_root_sequence_index_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_cat_m_root_sequence_index, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 837) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach cat-m root sequence index value [0..837]"); ++ } ++} ++static void dissect_emtc_prach_cat_m_zero_correlation_zone_configuration_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_cat_m_zero_correlation_zone_configuration, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach cat-m zero correlation zone configuration value [0..15]"); ++ } ++} ++static void dissect_emtc_prach_cat_m_high_speed_flag_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_cat_m_high_speed_flag, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach cat-m high speed flag value [0..1]"); ++ } ++} ++static void dissect_emtc_prach_ce_level_0_enabled_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_0_enable, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #0 enable value [0..1]"); ++ } ++} ++static void dissect_emtc_prach_ce_level_0_configuration_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_0_configuration_index, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 63) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #0 configuration index value [0..63]"); ++ } ++} ++static void dissect_emtc_prach_ce_level_0_frequency_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_0_frequency_offset, 2, ENC_BIG_ENDIAN); ++ ++ if (value > (100 - 6)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #0 frequency offset value [0..94]"); ++ } ++} ++static void dissect_emtc_preach_ce_level_0_num_of_repeitions_per_attempt_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_0_number_of_repetitions_per_attempt, 2, ENC_BIG_ENDIAN); ++ ++ if (!( value == 1 || value == 2 || value == 4 || value == 8 || value == 16 || value == 32 || ++ value == 64 || value == 128)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #0 number of repetitions per attempt value [1, 2, 4, 8, 16, 32, 64, 128]"); ++ } ++} ++static void dissect_emtc_ce_level_0_starting_subframe_periodicity_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_0_starting_subframe_periodicity, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 0xFFF || value == 2 || value == 4 || value == 8 || value == 16 || value == 32 || ++ value == 64 || value == 128 || value == 256)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #0 starting subframe periodicity value [2, 4, 8, 16, 32, 64, 128, 256, 0xFFFF]"); ++ } ++} ++static void dissect_emtc_preach_ce_level_0_hopping_enabled_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_0_hopping_enabled, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #0 hopping enabled value [0..1]"); ++ } ++} ++static void dissect_emtc_preach_ce_level_0_hopping_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_0_hopping_offset, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 94) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #0 hopping offset value [0..94]"); ++ } ++} ++static void dissect_emtc_prach_ce_level_1_enabled_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_1_enable, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #1 enable value [0..1]"); ++ } ++} ++static void dissect_emtc_prach_ce_level_1_configuration_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_1_configuration_index, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 63) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #1 configuration index value [0..63]"); ++ } ++} ++static void dissect_emtc_prach_ce_level_1_frequency_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_1_frequency_offset, 2, ENC_BIG_ENDIAN); ++ ++ if (value > (100 - 6)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #1 frequency offset value [0..94]"); ++ } ++} ++static void dissect_emtc_preach_ce_level_1_num_of_repeitions_per_attempt_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_1_number_of_repetitions_per_attempt, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 1 || value == 2 || value == 4 || value == 8 || value == 16 || value == 32 || ++ value == 64 || value == 128)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #1 number of repetitions per attempt value [1, 2, 4, 8, 16, 32, 64, 128]"); ++ } ++} ++static void dissect_emtc_ce_level_1_starting_subframe_periodicity_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_1_starting_subframe_periodicity, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 0xFFF || value == 2 || value == 4 || value == 8 || value == 16 || value == 32 || ++ value == 64 || value == 128 || value == 256)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #1 starting subframe periodicity value [2, 4, 8, 16, 32, 64, 128, 256, 0xFFFF]"); ++ } ++} ++static void dissect_emtc_preach_ce_level_1_hopping_enabled_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_1_hopping_enabled, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #1 hopping enabled value [0..1]"); ++ } ++} ++static void dissect_emtc_preach_ce_level_1_hopping_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_1_hopping_offset, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 94) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #1 hopping offset value [0..94]"); ++ } ++} ++static void dissect_emtc_prach_ce_level_2_enabled_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_2_enable, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #2 enable value [0..1]"); ++ } ++} ++static void dissect_emtc_prach_ce_level_2_configuration_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_2_configuration_index, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 63) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #2 configuration index value [0..63]"); ++ } ++} ++static void dissect_emtc_prach_ce_level_2_frequency_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_2_frequency_offset, 2, ENC_BIG_ENDIAN); ++ ++ if (value > (100 - 6)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #2 frequency offset value [0..94]"); ++ } ++} ++static void dissect_emtc_preach_ce_level_2_num_of_repeitions_per_attempt_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_2_number_of_repetitions_per_attempt, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 1 || value == 2 || value == 4 || value == 8 || value == 16 || value == 32 || ++ value == 64 || value == 128)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #2 number of repetitions per attempt value [1, 2, 4, 8, 16, 32, 64, 128]"); ++ } ++} ++static void dissect_emtc_ce_level_2_starting_subframe_periodicity_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_2_starting_subframe_periodicity, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 0xFFF || value == 2 || value == 4 || value == 8 || value == 16 || value == 32 || ++ value == 64 || value == 128 || value == 256)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #2 starting subframe periodicity value [2, 4, 8, 16, 32, 64, 128, 256, 0xFFFF]"); ++ } ++} ++static void dissect_emtc_preach_ce_level_2_hopping_enabled_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_2_hopping_enabled, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #2 hopping enabled value [0..1]"); ++ } ++} ++static void dissect_emtc_preach_ce_level_2_hopping_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_2_hopping_offset, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 94) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #2 hopping offset value [0..94]"); ++ } ++} ++static void dissect_emtc_prach_ce_level_3_enabled_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_3_enable, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #3 enable value [0..1]"); ++ } ++} ++static void dissect_emtc_prach_ce_level_3_configuration_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_3_configuration_index, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 63) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #2 configuration index value [0..63]"); ++ } ++} ++static void dissect_emtc_prach_ce_level_3_frequency_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_3_frequency_offset, 2, ENC_BIG_ENDIAN); ++ ++ if (value > (100 - 6)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #3 frequency offset value [0..94]"); ++ } ++} ++static void dissect_emtc_preach_ce_level_3_num_of_repeitions_per_attempt_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_3_number_of_repetitions_per_attempt, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 1 || value == 2 || value == 4 || value == 8 || value == 16 || value == 32 || ++ value == 64 || value == 128)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #3 number of repetitions per attempt value [1, 2, 4, 8, 16, 32, 64, 128]"); ++ } ++} ++static void dissect_emtc_ce_level_3_starting_subframe_periodicity_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_3_starting_subframe_periodicity, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 0xFFF || value == 2 || value == 4 || value == 8 || value == 16 || value == 32 || ++ value == 64 || value == 128 || value == 256)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #3 starting subframe periodicity value [2, 4, 8, 16, 32, 64, 128, 256, 0xFFFF]"); ++ } ++} ++static void dissect_emtc_preach_ce_level_3_hopping_enabled_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_3_hopping_enabled, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #3 hopping enabled value [0..1]"); ++ } ++} ++static void dissect_emtc_preach_ce_level_3_hopping_offset_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_prach_ce_level_3_hopping_offset, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 94) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach ce level #3 hopping offset value [0..94]"); ++ } ++} ++static void dissect_emtc_pucch_interval_ul_hopping_config_common_mode_a_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_pucch_internal_ul_hopping_config_common_mode_a, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 1 || value == 2 || value == 4 || value == 8 || value == 5 || value == 10 || value == 20)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pucch internal ul hopping config common mode a value [1, 2, 4, 8] or [1, 5, 10, 20]"); ++ } ++} ++static void dissect_emtc_pucch_interval_ul_hopping_config_common_mode_b_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_pucch_internal_ul_hopping_config_common_mode_b, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 2 || value == 4 || value == 8 || value == 16 || value == 5 || value == 10 || value == 20 || value == 40)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pucch internal ul hopping config common mode a value [2, 4, 8, 16] or [5, 10, 20, 40]"); ++ } ++} ++static void dissect_dl_bandwidth_support_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add_no_advance(ptvc, hf_nfapi_dl_bandwidth_support, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 0x1F) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid downlink bandwidth support bit [0..0x1F]"); ++ } ++ ++ proto_tree* dl_bw_support_tree = proto_item_add_subtree(item, ett_nfapi_downlink_bandwidth_support); ++ ++ proto_tree_add_bits_item(dl_bw_support_tree, hf_nfapi_dl_bandwidth_support_6, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 15, 1, ENC_NA); ++ proto_tree_add_bits_item(dl_bw_support_tree, hf_nfapi_dl_bandwidth_support_15, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 14, 1, ENC_NA); ++ proto_tree_add_bits_item(dl_bw_support_tree, hf_nfapi_dl_bandwidth_support_25, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 13, 1, ENC_NA); ++ proto_tree_add_bits_item(dl_bw_support_tree, hf_nfapi_dl_bandwidth_support_50, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 12, 1, ENC_NA); ++ proto_tree_add_bits_item(dl_bw_support_tree, hf_nfapi_dl_bandwidth_support_75, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 11, 1, ENC_NA); ++ proto_tree_add_bits_item(dl_bw_support_tree, hf_nfapi_dl_bandwidth_support_100, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 10, 1, ENC_NA); ++ ++ ptvcursor_advance(ptvc, 2); ++} ++static void dissect_ul_bandwidth_support_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add_no_advance(ptvc, hf_nfapi_ul_bandwidth_support, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 0x1F) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid uplink bandwidth support bit [0..0x1F]"); ++ } ++ ++ proto_tree* ul_bw_support_tree = proto_item_add_subtree(item, ett_nfapi_uplink_bandwidth_support); ++ ++ proto_tree_add_bits_item(ul_bw_support_tree, hf_nfapi_ul_bandwidth_support_6, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 15, 1, ENC_NA); ++ proto_tree_add_bits_item(ul_bw_support_tree, hf_nfapi_ul_bandwidth_support_15, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 14, 1, ENC_NA); ++ proto_tree_add_bits_item(ul_bw_support_tree, hf_nfapi_ul_bandwidth_support_25, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 13, 1, ENC_NA); ++ proto_tree_add_bits_item(ul_bw_support_tree, hf_nfapi_ul_bandwidth_support_50, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 12, 1, ENC_NA); ++ proto_tree_add_bits_item(ul_bw_support_tree, hf_nfapi_ul_bandwidth_support_75, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 11, 1, ENC_NA); ++ proto_tree_add_bits_item(ul_bw_support_tree, hf_nfapi_ul_bandwidth_support_100, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 10, 1, ENC_NA); ++ ++ ptvcursor_advance(ptvc, 2); ++ ++} ++static void dissect_dl_modulation_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add_no_advance(ptvc, hf_nfapi_dl_modulation_support, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 0x7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid downlink modulation support bit [0..0x7]"); ++ } ++ ++ proto_tree* dl_mod_support_tree = proto_item_add_subtree(item, ett_nfapi_downlink_modulation_support); ++ ++ proto_tree_add_bits_item(dl_mod_support_tree, hf_nfapi_dl_modulation_support_qpsk, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 15, 1, ENC_NA); ++ proto_tree_add_bits_item(dl_mod_support_tree, hf_nfapi_dl_modulation_support_16qam, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 14, 1, ENC_NA); ++ proto_tree_add_bits_item(dl_mod_support_tree, hf_nfapi_dl_modulation_support_64qam, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 13, 1, ENC_NA); ++ proto_tree_add_bits_item(dl_mod_support_tree, hf_nfapi_dl_modulation_support_256qam, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 12, 1, ENC_NA); ++ ++ ptvcursor_advance(ptvc, 2); ++} ++static void dissect_ul_modulation_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add_no_advance(ptvc, hf_nfapi_ul_modulation_support, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 0x7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid uplink modulation support bit [0..0x7]"); ++ } ++ ++ proto_tree* ul_mod_support_tree = proto_item_add_subtree(item, ett_nfapi_uplink_modulation_support); ++ ++ proto_tree_add_bits_item(ul_mod_support_tree, hf_nfapi_ul_modulation_support_qpsk, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 15, 1, ENC_NA); ++ proto_tree_add_bits_item(ul_mod_support_tree, hf_nfapi_ul_modulation_support_16qam, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 14, 1, ENC_NA); ++ proto_tree_add_bits_item(ul_mod_support_tree, hf_nfapi_ul_modulation_support_64qam, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 13, 1, ENC_NA); ++ ++ ptvcursor_advance(ptvc, 2); ++} ++static void dissect_phy_antenna_capability_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_phy_antenna_capability, 2, ENC_BIG_ENDIAN); ++ ++ if (!(value == 1 || value == 2 || value == 4 || value == 8 || value == 16)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid phy antenna capability [1, 2, 4, 8, 16]"); ++ } ++} ++static void dissect_release_capability_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add_no_advance(ptvc, hf_nfapi_release_capability, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 0x3F) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid release capability value [0..0x3F]"); ++ } ++ ++ proto_tree* release_support_tree = proto_item_add_subtree(item, ett_nfapi_release_support); ++ ++ proto_tree_add_bits_item(release_support_tree, hf_nfapi_maximum_3gpp_release_supported_rel8, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 15, 1, ENC_NA); ++ proto_tree_add_bits_item(release_support_tree, hf_nfapi_maximum_3gpp_release_supported_rel9, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 14, 1, ENC_NA); ++ proto_tree_add_bits_item(release_support_tree, hf_nfapi_maximum_3gpp_release_supported_rel10, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 13, 1, ENC_NA); ++ proto_tree_add_bits_item(release_support_tree, hf_nfapi_maximum_3gpp_release_supported_rel11, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 12, 1, ENC_NA); ++ proto_tree_add_bits_item(release_support_tree, hf_nfapi_maximum_3gpp_release_supported_rel12, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 11, 1, ENC_NA); ++ proto_tree_add_bits_item(release_support_tree, hf_nfapi_maximum_3gpp_release_supported_rel13, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8 + 10, 1, ENC_NA); ++ ++ ptvcursor_advance(ptvc, 2); ++} ++static void dissect_mbsfn_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_mbsfn_capability, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mbsfn capability bit [0..0x1]"); ++ } ++} ++static void dissect_laa_support_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_laa_capability, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid laa support bit [0..0x1]"); ++ } ++} ++static void dissect_laa_pd_sensing_lbt_support_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_pd_sensing_lbt_support, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pd sensing lbt support bit [0..0x1]"); ++ } ++} ++static void dissect_laa_multi_carrier_lbt_support_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_multi_carrier_lbt_support, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 0xF) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid multi carrier LBT support bit [0..0xF]"); ++ } ++} ++static void dissect_laa_partial_sf_support_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_partial_sf_support, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 0x1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid partial SF support bit [0..0x1]"); ++ } ++} ++static void dissect_data_report_mode_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_data_report_mode, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid data report mode value [0..1]"); ++ } ++} ++static void dissect_sfn_sf_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_sfnsf, 2, ENC_BIG_ENDIAN); ++ ++ guint16 sfn = value >> 0x4; ++ guint16 sf = value & 0x000F; ++ if (sfn > 1023 || sf > 9) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid sfn/sf value sfn:%d [0..1023] sf:%d [0..9]", sfn, sf); ++ } ++} ++static void dissect_phy_state_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_phy_state, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid phy state [0..2]"); ++ } ++} ++static void dissect_p7_vnf_address_ipv4_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_vnf_address_ipv4, 4, ENC_NA); ++} ++static void dissect_p7_vnf_address_ipv6_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_vnf_address_ipv6, 16, ENC_NA); ++} ++static void dissect_p7_vnf_port_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_vnf_port, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_p7_pnf_address_ipv4_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_pnf_address_ipv4, 4, ENC_NA); ++} ++static void dissect_p7_pnf_address_ipv6_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_pnf_address_ipv6, 16, ENC_NA); ++} ++static void dissect_p7_pnf_port_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_pnf_port, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_downlink_ues_per_subframe_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_dl_ue_per_sf, 1, ENC_BIG_ENDIAN); ++} ++static void dissect_uplink_ues_per_subframe_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_ul_ue_per_sf, 1, ENC_BIG_ENDIAN); ++} ++static void dissect_rf_band_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_band, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_rf_bands_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 count = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_rf_bands, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "RF Band List", ett_nfapi_rf_bands, count, dissect_rf_band_value); ++} ++static void dissect_timing_window_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_timing_window, 1, ENC_BIG_ENDIAN); ++ ++ if (value > 30) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid timing window value [0..30]"); ++ } ++} ++static void dissect_timing_info_mode_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_timing_info_mode, 1, ENC_BIG_ENDIAN); ++ ++ if (value > 0x3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid timing info mode [0..0x3]"); ++ } ++} ++static void dissect_timing_info_period_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_timing_info_period, 1, ENC_BIG_ENDIAN); ++ ++ // Compiler throws an hissy fit that value <= 255 is always true... Yes, but I am trying to ++ // follow the specification... ++ if (!(value >= 1 /* && value <= 255*/)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid timing info period [1..255]"); ++ } ++} ++static void dissect_maximum_transmit_power_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_maximum_transmit_power_2, 2, ENC_BIG_ENDIAN); ++ ++ if (value > 700) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid maxiumum transmit power [0..700]"); ++ } ++} ++static void dissect_earfcn_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_earfcn, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_nmm_gsm_frequency_bands_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 count = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_rf_bands, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "RF Band List", ett_nfapi_rf_bands, count, dissect_rf_band_value); ++} ++static void dissect_nmm_umts_frequency_bands_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 count = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_rf_bands, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "RF Band List", ett_nfapi_rf_bands, count, dissect_rf_band_value); ++} ++static void dissect_nmm_lte_frequency_bands_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 count = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_rf_bands, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "RF Band List", ett_nfapi_rf_bands, count, dissect_rf_band_value); ++} ++static void dissect_nmm_uplink_rssi_supported_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_nmm_uplink_rssi_supported, 1, ENC_BIG_ENDIAN); ++ ++ if (value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid nmm uplink rssi supported value [0..1]"); ++ } ++} ++static void dissect_dl_config_pdu(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_dl_config_pdu_type, 1, ENC_BIG_ENDIAN); ++ guint8 size = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pdu_size, 1, ENC_BIG_ENDIAN); ++ ++ guint pdu_end = (ptvcursor_current_offset(ptvc) + size - 2); ++ dissect_tlv_list(ptvc, pinfo, pdu_end); ++} ++static void dissect_dl_config_request_body_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Number of PDCCH OFDM symbols ++ guint8 number_of_pdcch_ofdm_symbols_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_pdcch_ofdm_symbols, 1, ENC_BIG_ENDIAN); ++ if (number_of_pdcch_ofdm_symbols_value > 4) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of pdcch ofdm symbols value [0..4]"); ++ } ++ ++ // Number of DCIs ++ guint8 number_of_dcis_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_dci, 1, ENC_BIG_ENDIAN); ++ ++ // Number of PDUs ++ guint16 number_of_pdus_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_pdus, 2, ENC_BIG_ENDIAN); ++ if (number_of_pdus_value > 514) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of pdus value [0..514]"); ++ } ++ ++ // Number of PDSCH RNTIs ++ ptvcursor_add(ptvc, hf_nfapi_number_pdsch_rnti, 1, ENC_BIG_ENDIAN); ++ ++ // Transmission power for PCFICH ++ guint16 transmission_power_for_pdsch_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_power_pcfich, 2, ENC_BIG_ENDIAN); ++ if (transmission_power_for_pdsch_value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission power for pcfich value [0..10000]"); ++ } ++ ++ dissect_array_value(ptvc, pinfo, "DL Config PDU List", ett_nfapi_dl_config_request_pdu_list, number_of_dcis_value + number_of_pdus_value, dissect_dl_config_pdu); ++} ++static void dissect_dl_config_request_bch_pdu_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Length ++ ptvcursor_add(ptvc, hf_nfapi_length, 2, ENC_BIG_ENDIAN); ++ ++ // PDU index ++ ptvcursor_add(ptvc, hf_nfapi_pdu_index, 2, ENC_BIG_ENDIAN); ++ ++ // Transmission power ++ guint16 transmission_power_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_power, 2, ENC_BIG_ENDIAN); ++ if (transmission_power_value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission power value [0..10000]"); ++ } ++ ++} ++static void dissect_dl_config_request_dl_dci_pdu_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // DCI format ++ guint8 dci_format_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_dl_dci_format, 1, ENC_BIG_ENDIAN); ++ if (dci_format_value > 9) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid dci format value [0..9]"); ++ } ++ ++ // CCE index ++ guint8 cce_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_cce_idx, 1, ENC_BIG_ENDIAN); ++ if (cce_index_value > 88) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid cce index value [0..88]"); ++ } ++ ++ // Aggregation level ++ guint8 aggregation_level_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_aggregation_level, 1, ENC_BIG_ENDIAN); ++ if (!(aggregation_level_value == 1 || aggregation_level_value == 2 || aggregation_level_value == 4 || ++ aggregation_level_value == 8 || aggregation_level_value == 16 || aggregation_level_value == 32)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid aggregation level value [1, 2, 4, 8, 16, 32]"); ++ } ++ ++ // RNTI ++ guint16 rnti_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_rnti, 2, ENC_BIG_ENDIAN); ++ if (rnti_value < 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rnti value [1..65535]"); ++ } ++ ++ // Resource allocation type ++ guint8 resource_allocation_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_resource_allocation_type, 1, ENC_BIG_ENDIAN); ++ if (resource_allocation_type_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid resource allocation type value [0..1]"); ++ } ++ ++ // Virtual resource block assignment flag ++ guint8 virtual_resource_block_assignment_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_virtual_resource_block_assignment_flag, 1, ENC_BIG_ENDIAN); ++ if (virtual_resource_block_assignment_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid virtual resource block assignment flag value [0..1]"); ++ } ++ ++ // Resource block coding ++ ptvcursor_add(ptvc, hf_nfapi_resource_block_coding, 4, ENC_BIG_ENDIAN); ++ ++ // MCS_1 ++ guint8 mcs_1_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mcs_1, 1, ENC_BIG_ENDIAN); ++ if (mcs_1_value > 31) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mcs 1 value [0..31]"); ++ } ++ ++ // Redundancy version_1 ++ guint8 redundancy_version_1_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_redundancy_version_1, 1, ENC_BIG_ENDIAN); ++ if (redundancy_version_1_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid redundancy version 1 value [0..3]"); ++ } ++ ++ // New data indicator_1 ++ guint8 new_data_indicator_1_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_new_data_indicator_1, 1, ENC_BIG_ENDIAN); ++ if (new_data_indicator_1_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid new data indicator 1 value [0..1]"); ++ } ++ ++ // Transport block to codeword swap flag ++ guint8 transport_block_to_codeword_swap_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transport_block_to_codeword_swap_flag, 1, ENC_BIG_ENDIAN); ++ if (transport_block_to_codeword_swap_flag_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transport block to codeword swap flag value [0..1]"); ++ } ++ ++ // MCS_2 ++ guint8 mcs_2_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mcs_2, 1, ENC_BIG_ENDIAN); ++ if (mcs_2_value > 31) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mcs 2 value [0..31]"); ++ } ++ ++ // Redundancy version_2 ++ guint8 redundancy_version_2_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_redundancy_version_2, 1, ENC_BIG_ENDIAN); ++ if (redundancy_version_2_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid redundancy version 2 value [0..3]"); ++ } ++ ++ // New Data indicator_2 ++ guint8 new_data_indicator_2_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_new_data_indicator_2, 1, ENC_BIG_ENDIAN); ++ if (new_data_indicator_2_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid new data indicator 2 value [0..1]"); ++ } ++ ++ // HARQ process ++ guint8 harq_process_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_process, 1, ENC_BIG_ENDIAN); ++ if (harq_process_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq process value [0..15]"); ++ } ++ ++ // TPMI ++ guint8 tpmi_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_tpmi, 1, ENC_BIG_ENDIAN); ++ if (tpmi_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid tpmi value [0..3]"); ++ } ++ ++ // PMI ++ guint8 pmi_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pmi, 1, ENC_BIG_ENDIAN); ++ if (pmi_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid tpmi value [0..2]"); ++ } ++ ++ // Precoding information ++ guint8 precoding_information_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_precoding_information, 1, ENC_BIG_ENDIAN); ++ if (precoding_information_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid precoding information value [0..15]"); ++ } ++ ++ // TPC ++ guint8 tpc_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_tpc, 1, ENC_BIG_ENDIAN); ++ if (tpc_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid tpc value [0..3]"); ++ } ++ ++ // Downlink assignment index ++ guint8 downlink_assignment_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_downlink_assignment_index, 1, ENC_BIG_ENDIAN); ++ if (downlink_assignment_index_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid downlink assignment value [0..15]"); ++ } ++ ++ // NGAP ++ guint8 ngap_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ngap, 1, ENC_BIG_ENDIAN); ++ if (ngap_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ngap value [0..1]"); ++ } ++ ++ // Transport block size index ++ guint8 transport_block_size_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transport_block_size_index, 1, ENC_BIG_ENDIAN); ++ if (transport_block_size_index_value > 31) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transport block size index value [0..31]"); ++ } ++ ++ // Downlink power offset ++ guint8 downlink_power_offset_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_downlink_power_offset, 1, ENC_BIG_ENDIAN); ++ if (downlink_power_offset_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid downlink power offset value [0..1]"); ++ } ++ ++ // Allocate PRACH flag ++ guint8 allocate_prach_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_allocate_prach_flag, 1, ENC_BIG_ENDIAN); ++ if (allocate_prach_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid allocate prach flag value [0..1]"); ++ } ++ ++ // Preamble index ++ guint8 preamble_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_preamble_index, 1, ENC_BIG_ENDIAN); ++ if (preamble_index_value > 63) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid preamble index value [0..63]"); ++ } ++ ++ // PRACH mask index ++ guint8 prach_mask_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_prach_mask_index, 1, ENC_BIG_ENDIAN); ++ if (prach_mask_index_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach mask index value [0..15]"); ++ } ++ ++ // RNTI type ++ guint8 rnti_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_rnti_type, 1, ENC_BIG_ENDIAN); ++ if (!(rnti_type_value >= 1 && rnti_type_value <= 3)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rnti type value [1..3]"); ++ } ++ ++ // Transmission power ++ guint16 transmission_power_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_power, 2, ENC_BIG_ENDIAN); ++ if (transmission_power_value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission power value value [0..10000]"); ++ } ++ ++} ++static void dissect_dl_config_request_dl_dci_pdu_rel9_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // MCCH flag ++ guint8 mcch_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mcch_flag, 1, ENC_BIG_ENDIAN); ++ if (mcch_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mcch flag value [0..1]"); ++ } ++ ++ // MCCH change notification ++ ptvcursor_add(ptvc, hf_nfapi_mcch_change_notification, 1, ENC_BIG_ENDIAN); ++ ++ // Scrambling identity ++ guint8 scrambling_identity_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_scrambling_identity, 1, ENC_BIG_ENDIAN); ++ if (scrambling_identity_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid scrambling identity value [0..1]"); ++ } ++ ++} ++static void dissect_dl_config_request_dl_dci_pdu_rel10_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Cross carrier scheduling flag ++ guint8 cross_carrier_scheduling_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_cross_carrier_scheduling_flag, 1, ENC_BIG_ENDIAN); ++ if (cross_carrier_scheduling_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid cross carrier scheduling flag value [0..1]"); ++ } ++ ++ // Carrier indicator ++ guint8 carrier_indicator_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_carrier_indicator, 1, ENC_BIG_ENDIAN); ++ if (carrier_indicator_value > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid carrier indicator value [0..7]"); ++ } ++ ++ // SRS flag ++ guint8 srs_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_srs_flag, 1, ENC_BIG_ENDIAN); ++ if (srs_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid srs flag value [0..1]"); ++ } ++ ++ // SRS request ++ guint8 srs_request_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_srs_request, 1, ENC_BIG_ENDIAN); ++ if (srs_request_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid srs request value [0..1]"); ++ } ++ ++ // Antenna ports, scrambling and layers ++ guint8 antenna_ports_scrambling_and_layers_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_antenna_ports_scrambling_and_layers, 1, ENC_BIG_ENDIAN); ++ if (antenna_ports_scrambling_and_layers_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid antenna ports scrambling and layers value [0..15]"); ++ } ++ ++ // Total DCI length including padding ++ ptvcursor_add(ptvc, hf_nfapi_total_dci_length_including_padding, 1, ENC_BIG_ENDIAN); ++ ++ // N_DL_RB ++ // TODO : This is missing from the encoder.... ++ //ptvcursor_add(ptvc, hf_nfapi_n_dl_rb, 1, ENC_BIG_ENDIAN); ++} ++static void dissect_dl_config_request_dl_dci_pdu_rel11_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // HARQ-ACK resource offset ++ guint8 harq_ack_resource_offset_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_ack_resource_offset, 1, ENC_BIG_ENDIAN); ++ if (harq_ack_resource_offset_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid hack ack resource offset value [0..3]"); ++ } ++ ++ // PDSCH RE Mapping and Quasi-Co-Location Indicator ++ guint8 pdsch_re_mapping_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pdsch_re_mapping_and_quasi_co_location_indicator, 1, ENC_BIG_ENDIAN); ++ if (pdsch_re_mapping_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pdsch re mapping value [0..3]"); ++ } ++ ++} ++static void dissect_ul_dl_configuration_index_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // UL/DL configuration indication ++ guint8 ul_dl_configuration_indication_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_ul_dl_configuration_index, 1, ENC_BIG_ENDIAN); ++ if (!(ul_dl_configuration_indication_value >= 1 && ul_dl_configuration_indication_value <= 5)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ul/dl configuration indication value [1..5]"); ++ } ++} ++static void dissect_dl_config_request_dl_dci_pdu_rel12_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Primary cell type ++ guint8 primary_cell_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_primary_cell_type, 1, ENC_BIG_ENDIAN); ++ if (primary_cell_type_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid primary cell type value [0..2]"); ++ } ++ ++ // UL/DL configuration flag ++ guint8 ul_dl_configuration_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ul_dl_configuration_flag, 1, ENC_BIG_ENDIAN); ++ if (ul_dl_configuration_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ul/dl configuration flag value [0..1]"); ++ } ++ ++ // Number of UL / DL configurations ++ guint8 count = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_ul_dl_configurations, 1, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "UL/DL Configurations", ett_nfapi_pnf_phy, count, dissect_ul_dl_configuration_index_value); ++} ++static void dissect_dl_config_request_dl_dci_pdu_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_laa_end_partial_sf_flag, 1, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_laa_end_partial_sf_configuration, 1, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_initial_lbt_sf, 1, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_codebooksize_determination_r13, 1, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_rel13_drms_table_flag, 1, ENC_BIG_ENDIAN); ++} ++static void dissect_dl_config_request_mch_pdu_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_length, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_pdu_index, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_rnti, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_resource_allocation_type, 1, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_resource_block_coding, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_modulation, 1, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_transmission_power, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_mbsfn_area_id, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_codebook_index_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 codebook_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_codebook_index, 1, ENC_BIG_ENDIAN); ++ if (codebook_index_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid codebook index value [0..15]"); ++ } ++} ++static void dissect_bf_vector_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_bf_vector_bf_value, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_bf_vector_type_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_bf_vector_subband_index, 1, ENC_BIG_ENDIAN); ++ guint8 count = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_bf_vector_num_antennas, 1, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "Antennas", ett_nfapi_bf_vector_antennas, count, dissect_bf_vector_value); ++} ++static void dissect_dl_config_request_dlsch_pdu_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Length ++ ptvcursor_add(ptvc, hf_nfapi_length, 2, ENC_BIG_ENDIAN); ++ ++ // PDU index ++ ptvcursor_add(ptvc, hf_nfapi_pdu_index, 2, ENC_BIG_ENDIAN); ++ ++ // RNTI ++ guint16 rnti_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_rnti, 2, ENC_BIG_ENDIAN); ++ if (!(rnti_value >= 1 /* && rnti_value <= 65535)*/)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid codebook index value [1..65535]"); ++ } ++ ++ // Resource allocation type ++ guint8 resource_allocation_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_resource_allocation_type, 1, ENC_BIG_ENDIAN); ++ if (resource_allocation_type_value > 5) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid resource allocation type value [0..5]"); ++ } ++ ++ // Virtual resource block assignment flag ++ guint8 virtual_resource_block_assignment_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_virtual_resource_block_assignment_flag, 1, ENC_BIG_ENDIAN); ++ if (virtual_resource_block_assignment_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid virtual resource block allocation assignment value [0..1]"); ++ } ++ ++ // Resource block coding ++ ptvcursor_add(ptvc, hf_nfapi_resource_block_coding, 4, ENC_BIG_ENDIAN); ++ ++ // Modulation ++ guint8 modulation_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_modulation, 1, ENC_BIG_ENDIAN); ++ if (!(modulation_value == 2 || modulation_value == 4 || modulation_value == 6 || modulation_value == 8)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid modulation value [2, 4, 6, 8]"); ++ } ++ ++ // Redundancy version ++ guint8 redundancy_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_redundancy_version, 1, ENC_BIG_ENDIAN); ++ if (redundancy_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid redundancy value [0..3]"); ++ } ++ ++ // Transport blocks ++ guint8 transport_blocks_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transport_blocks, 1, ENC_BIG_ENDIAN); ++ if (!(transport_blocks_value >= 1 && transport_blocks_value <= 2)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transport blocks value [1..2]"); ++ } ++ ++ // Transport block to codeword swap flag ++ guint8 transport_blocks_to_codeword_swap_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transport_block_to_codeword_swap_flag, 1, ENC_BIG_ENDIAN); ++ if (transport_blocks_to_codeword_swap_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transport block to codeword swap flag value [0..1]"); ++ } ++ ++ // Transmission scheme ++ guint8 transmission_scheme_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_scheme, 1, ENC_BIG_ENDIAN); ++ if (transmission_scheme_value > 13) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission scheme value [0..13]"); ++ } ++ ++ // Number of layers ++ guint8 number_of_layers_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_layers, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_layers_value >= 1 && number_of_layers_value <= 8)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of layers value [1..8]"); ++ } ++ ++ // Number of subbands ++ guint8 num_subbands = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_subbands, 1, ENC_BIG_ENDIAN); ++ if (num_subbands > 13) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of subbands value [0..13]"); ++ } ++ ++ dissect_array_value(ptvc, pinfo, "Subbands", ett_nfapi_subbands, num_subbands, dissect_codebook_index_value); ++ ++ // UE category capacity ++ guint8 ue_category_capacity_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ue_category_capacity, 1, ENC_BIG_ENDIAN); ++ if (ue_category_capacity_value > 14) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ue category capacity value [0..14]"); ++ } ++ ++ // P-A ++ guint8 pa_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pa, 1, ENC_BIG_ENDIAN); ++ if (pa_value > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid p-a value [0..7]"); ++ } ++ ++ // Delta power offset index ++ guint8 delta_power_offset_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_delta_power_offset_index, 1, ENC_BIG_ENDIAN); ++ if (delta_power_offset_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid delta power offset value [0..1]"); ++ } ++ ++ // NGAP ++ guint8 ngap_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ngap, 1, ENC_BIG_ENDIAN); ++ if (ngap_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ngap value [0..1]"); ++ } ++ ++ // NPRB ++ guint8 nrpb_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_nprb, 1, ENC_BIG_ENDIAN); ++ if (nrpb_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid nprb value [0..1]"); ++ } ++ ++ // Transmission mode ++ guint8 transmission_mode_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_mode, 1, ENC_BIG_ENDIAN); ++ if (!(transmission_mode_value >= 1 && transmission_mode_value <= 10)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission mode value [1..10]"); ++ } ++ ++ // numBfPRBperSubband ++ ptvcursor_add(ptvc, hf_nfapi_num_bf_prb_per_subband, 1, ENC_BIG_ENDIAN); ++ ++ // numBfVector ++ guint8 num_vectors = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_num_bf_vector, 1, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "Beamforming Vectors", ett_nfapi_bf_vectors, num_vectors, dissect_bf_vector_type_value); ++} ++static void dissect_csi_rs_resource_config_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 csi_rs_resource_config_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_csi_rs_resource_config, 1, ENC_BIG_ENDIAN); ++ if (csi_rs_resource_config_value > 31) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid csi-rs resource config value [0..31]"); ++ } ++} ++static void dissect_dl_config_request_dlsch_pdu_rel9_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 nscid_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_nscid, 1, ENC_BIG_ENDIAN); ++ if (nscid_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid nscid value [0..1]"); ++ } ++} ++static void dissect_dl_config_request_dlsch_pdu_rel10_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // CSI-RS flag ++ guint8 csi_rs_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_csi_rs_flag, 1, ENC_BIG_ENDIAN); ++ if (csi_rs_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid csi-rs flag value [0..1]"); ++ } ++ ++ // CSI-RS resource config R10 ++ ptvcursor_add(ptvc, hf_nfapi_csi_rs_resource_config_r10, 1, ENC_BIG_ENDIAN); ++ ++ // CSI-RS zero Tx power resource config bitmap R10 ++ ptvcursor_add(ptvc, hf_nfapi_csi_rs_zero_tx_power_resource_config_bitmap_r10, 2, ENC_BIG_ENDIAN); ++ ++ // CSI-RS Number of NZP configuration ++ guint8 count = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_csi_rs_number_of_nzp_configurations, 1, ENC_BIG_ENDIAN); ++ if (count > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid csi-rs number of nzp configuration value [0..3]"); ++ } ++ ++ // CSI-RS configuration ++ dissect_array_value(ptvc, pinfo, "CSI-RS Resource Configs", ett_nfapi_csi_rs_resource_configs, count, dissect_csi_rs_resource_config_value); ++ ++ // PDSCH start ++ guint8 pdsch_start_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pdsch_start, 1, ENC_BIG_ENDIAN); ++ if (pdsch_start_value > 4) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pdsch start value [0..4]"); ++ } ++ ++} ++static void dissect_dl_config_request_dlsch_pdu_rel11_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // DMRS Config flag ++ guint8 drms_config_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_drms_config_flag, 1, ENC_BIG_ENDIAN); ++ if (drms_config_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid drms config flag value [0..1]"); ++ } ++ ++ // DMRS-Scrambling ++ guint16 drms_scrambling_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_drms_scrambling, 2, ENC_BIG_ENDIAN); ++ if (drms_scrambling_value > 503) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid drms scrambling value [0..503]"); ++ } ++ ++ // CSI Config flag ++ guint8 csi_config_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_csi_config_flag, 1, ENC_BIG_ENDIAN); ++ if (csi_config_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid csi config flag value [0..1]"); ++ } ++ ++ // CSI- Scrambling ++ guint16 csi_scrambling_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_csi_scrambling, 2, ENC_BIG_ENDIAN); ++ if (csi_scrambling_value > 503) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid csi scrambling value [0..503]"); ++ } ++ ++ // PDSCH RE mapping flag ++ guint8 pdsch_re_mapping_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pdsch_re_mapping_flag, 1, ENC_BIG_ENDIAN); ++ if (pdsch_re_mapping_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pdsch re mapping flag value [0..1]"); ++ } ++ ++ // PDSCH RE mapping antenna ports ++ guint8 pdsch_re_mapping_antenna_ports_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pdsch_re_mapping_antenna_ports, 1, ENC_BIG_ENDIAN); ++ if (!(pdsch_re_mapping_antenna_ports_value == 1 || pdsch_re_mapping_antenna_ports_value == 2 || ++ pdsch_re_mapping_antenna_ports_value == 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pdsch re mapping antenna ports value [1, 2, 4]"); ++ } ++ ++ // PDSCH RE mapping freq shift ++ guint8 pdsch_re_mapping_freq_shift_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pdsch_re_mapping_freq_shift, 1, ENC_BIG_ENDIAN); ++ if (pdsch_re_mapping_freq_shift_value > 5) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pdsch re mapping freq shift value [0..5]"); ++ } ++} ++static void dissect_dl_config_request_dlsch_pdu_rel12_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // altCQI-Table-r12 ++ guint8 alt_cqi_table_r12_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_alt_cqi_table_r12, 1, ENC_BIG_ENDIAN); ++ if (alt_cqi_table_r12_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid alt cqi table r12 value [0..1]"); ++ } ++ ++ // MaxLayers ++ guint8 max_layers_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_max_layers, 1, ENC_BIG_ENDIAN); ++ if (!(max_layers_value >= 1 && max_layers_value <= 8)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid max layers value [1..8]"); ++ } ++ ++ ptvcursor_add(ptvc, hf_nfapi_n_dl_harq, 1, ENC_BIG_ENDIAN); ++} ++static void dissect_dl_config_request_dlsch_pdu_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // DwPTS Symbols ++ guint8 dwpts_symbols_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_dwpts_symbols, 1, ENC_BIG_ENDIAN); ++ if (!(dwpts_symbols_value == 3 || dwpts_symbols_value == 6 || dwpts_symbols_value == 9 || ++ dwpts_symbols_value == 10 || dwpts_symbols_value == 11 || dwpts_symbols_value == 12 || ++ dwpts_symbols_value == 14)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid dwpts symbols value [3, 6, 9, 10, 11, 12, 14]"); ++ } ++ ++ // Initial LBT SF ++ guint8 initial_lbt_sf_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_initial_lbt_sf, 1, ENC_BIG_ENDIAN); ++ if (initial_lbt_sf_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid initial lbt sf value [0..1]"); ++ } ++ ++ // UE Type ++ guint8 ue_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ue_type, 1, ENC_BIG_ENDIAN); ++ if (ue_type_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ue type value [0..2]"); ++ } ++ ++ // PDSCH Payload Type ++ guint8 pdsch_payload_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pdsch_payload_type, 1, ENC_BIG_ENDIAN); ++ if (pdsch_payload_type_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pdsch payload type value [0..2]"); ++ } ++ ++ // Initial transmission SF (io) ++ guint16 initial_transmission_sf_io_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_initial_transmission_sf, 2, ENC_BIG_ENDIAN); ++ if (!(initial_transmission_sf_io_value <= 10239 || initial_transmission_sf_io_value == 0xFFFF)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid initial transmission sf io value [0..10239, 0xFFFF]"); ++ } ++ ++ // Rel-13-DMRS-tabe flag ++ guint8 rel13_drms_table_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_req13_drms_table_flag, 1, ENC_BIG_ENDIAN); ++ if (rel13_drms_table_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rel13 drms table flag value [0..1]"); ++ } ++} ++static void dissect_dl_config_request_pch_pdu_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Length ++ ptvcursor_add(ptvc, hf_nfapi_length, 2, ENC_BIG_ENDIAN); ++ ++ // PDU index ++ ptvcursor_add(ptvc, hf_nfapi_pdu_index, 2, ENC_BIG_ENDIAN); ++ ++ // P-RNTI ++ guint16 prnti_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_prnti, 2, ENC_BIG_ENDIAN); ++ if (prnti_value != 0xFFFE) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prnti value [0xFFFE]"); ++ } ++ ++ // Resource allocation type ++ guint8 resource_allocation_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_resource_allocation_type, 1, ENC_BIG_ENDIAN); ++ if (!(resource_allocation_type_value == 2 || resource_allocation_type_value == 3 || resource_allocation_type_value == 6)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid resource allocate type value [2, 3, 6]"); ++ } ++ ++ // Virtual resource block assignment flag ++ guint8 virtual_resource_block_assignment_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_virtual_resource_block_assignment_flag, 1, ENC_BIG_ENDIAN); ++ if (virtual_resource_block_assignment_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid virtual resource block assignment flag value [0..1]"); ++ } ++ ++ // Resource block coding ++ ptvcursor_add(ptvc, hf_nfapi_resource_block_coding, 4, ENC_BIG_ENDIAN); ++ ++ // MCS ++ guint8 mcs_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mcs, 1, ENC_BIG_ENDIAN); ++ if (mcs_value != 0) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mcs value [0]"); ++ } ++ ++ // Redundancy version ++ guint8 redundancy_version_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_redundancy_version, 1, ENC_BIG_ENDIAN); ++ if (redundancy_version_value != 0) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid redundancy value [0]"); ++ } ++ ++ // Number of transport blocks ++ guint8 number_of_transport_blocks_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_transport_blocks, 1, ENC_BIG_ENDIAN); ++ if (number_of_transport_blocks_value != 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transport blocks value [1]"); ++ } ++ ++ // Transport block to codeword swap flag ++ ptvcursor_add(ptvc, hf_nfapi_transport_block_to_codeword_swap_flag, 1, ENC_BIG_ENDIAN); ++ ++ // Transmission scheme ++ guint8 transmission_scheme_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_scheme, 1, ENC_BIG_ENDIAN); ++ if (!(transmission_scheme_value == 0 || transmission_scheme_value == 1 || transmission_scheme_value == 6)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission schemes value [0, 1, 6]"); ++ } ++ ++ // Number of layers ++ guint8 number_of_layers_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_layers, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_layers_value >= 1 && number_of_layers_value <= 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of layers value [1..4]"); ++ } ++ ++ // Codebook index ++ ptvcursor_add(ptvc, hf_nfapi_codebook_index, 1, ENC_BIG_ENDIAN); ++ ++ // UE category capacity ++ guint8 ue_category_capacity_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ue_category_capacity, 1, ENC_BIG_ENDIAN); ++ if (ue_category_capacity_value > 14) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ue category capacity value [0..14]"); ++ } ++ ++ // P-A ++ guint8 p_a_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pa, 1, ENC_BIG_ENDIAN); ++ if (p_a_value > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid p-a value value [0..7]"); ++ } ++ ++ // Transmission power ++ guint16 transmission_power_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_power, 2, ENC_BIG_ENDIAN); ++ if (transmission_power_value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission power value [0..10000]"); ++ } ++ ++ // NPRB ++ guint8 nprb_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_nprb, 1, ENC_BIG_ENDIAN); ++ if (nprb_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid nprb value [0..1]"); ++ } ++ ++ // NGAP ++ guint8 ngap_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ngap, 1, ENC_BIG_ENDIAN); ++ if (ngap_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ngap value [0..1]"); ++ } ++ ++} ++static void dissect_dl_config_request_pch_pdu_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // UE mode ++ guint8 ue_mode_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ue_mode, 1, ENC_BIG_ENDIAN); ++ if (ue_mode_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ue mode value [0..1]"); ++ } ++ ++ // Initial transmission SF (io) ++ guint16 initial_transmission_sf_io_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_initial_transmission_sf, 2, ENC_BIG_ENDIAN); ++ if (!(initial_transmission_sf_io_value <= 10239 || initial_transmission_sf_io_value == 0xFFFF)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid initial transmission sf io value [0..10239, 0xFFFF]"); ++ } ++} ++static void dissect_dl_config_request_prs_pdu_rel9_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Transmission power ++ guint16 transmission_power_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_power, 2, ENC_BIG_ENDIAN); ++ if (transmission_power_value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission power value [0..10000]"); ++ } ++ ++ // PRS bandwidth ++ guint8 prs_bandwidth_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_prs_bandwidth, 1, ENC_BIG_ENDIAN); ++ if (!(prs_bandwidth_value == 6 || prs_bandwidth_value == 15 || prs_bandwidth_value == 25 || ++ prs_bandwidth_value == 50 || prs_bandwidth_value == 75 || prs_bandwidth_value == 100)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prs bandwidth value [6, 15, 25, 50, 75, 100]"); ++ } ++ ++ // PRS cyclic prefix type ++ guint8 prs_cyclic_prefix_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_prs_cyclic_prefix_type, 1, ENC_BIG_ENDIAN); ++ if (prs_cyclic_prefix_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prs cyclic prefix value [0..1]"); ++ } ++ ++ // PRS muting ++ guint8 prs_muting_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_prs_muting, 1, ENC_BIG_ENDIAN); ++ if (prs_muting_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prs muting value [0..1]"); ++ } ++} ++static void dissect_dl_config_request_csi_rs_pdu_rel10_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // CSI-RS antenna port count R10 ++ guint8 csi_rs_antenna_port_count_r10_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_csi_rs_antenna_port_count_r10, 1, ENC_BIG_ENDIAN); ++ if (!(csi_rs_antenna_port_count_r10_value == 1 || csi_rs_antenna_port_count_r10_value == 2 || ++ csi_rs_antenna_port_count_r10_value == 4 || csi_rs_antenna_port_count_r10_value == 8 || ++ csi_rs_antenna_port_count_r10_value == 12 || csi_rs_antenna_port_count_r10_value == 16)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid csi rs antenna port count r10 value [1, 2, 4, 6, 8, 10]"); ++ } ++ ++ // CSI-RS resource config R10 ++ ptvcursor_add(ptvc, hf_nfapi_csi_rs_resource_config_r10, 1, ENC_BIG_ENDIAN); ++ ++ // Transmission power ++ guint16 transmission_power_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_power, 2, ENC_BIG_ENDIAN); ++ if (transmission_power_value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission power value [0..10000]"); ++ } ++ ++ // CSI-RS zero Tx power resource config bitmap R10 ++ ptvcursor_add(ptvc, hf_nfapi_csi_rs_zero_tx_power_resource_config_bitmap_r10, 2, ENC_BIG_ENDIAN); ++ ++ // CSI-RS Number of NZP configuration ++ guint8 count = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_csi_rs_number_of_nzp_configurations, 1, ENC_BIG_ENDIAN); ++ if (count > 8) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid csi-rs number of nzp configuration value [0..8]"); ++ } ++ ++ // CSI-RS configuration ++ dissect_array_value(ptvc, pinfo, "CSI-RS Resource Configs", ett_nfapi_csi_rs_resource_configs, count, dissect_csi_rs_resource_config_value); ++} ++static void dissect_csi_rs_bf_vector_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 count = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_csi_rs_resource_index, 1, ENC_BIG_ENDIAN); ++ if (count > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid csi-rs resource index value [0..7]"); ++ } ++ ++ // todo : how to work out the antenna port count for the bfValue ++} ++static void dissect_dl_config_request_csi_rs_pdu_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Class ++ guint8 class_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_csi_rs_class, 1, ENC_BIG_ENDIAN); ++ if (class_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid class value [0..2]"); ++ } ++ ++ // cdmType ++ guint8 cdm_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_cdm_type, 1, ENC_BIG_ENDIAN); ++ if (cdm_type_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid cdm type value [0..1]"); ++ } ++ ++ // numBfVector ++ guint8 count = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_num_bf_vector, 1, ENC_BIG_ENDIAN); ++ if (!((class_value == 1 && count == 0) || (class_value == 2 && count <= 8))) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid num bf vector value [0] or [0..8]"); ++ } ++ ++ dissect_array_value(ptvc, pinfo, "Beamforming Vector", ett_nfapi_csi_rs_bf_vector, count, dissect_csi_rs_bf_vector_value); ++} ++static void dissect_epdcch_prb_index_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // EPDCCH PRB index ++ guint8 epdcch_prb_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_edpcch_prb_index, 1, ENC_BIG_ENDIAN); ++ if (epdcch_prb_index_value > 99) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid epdcch prb_index value [0..99]"); ++ } ++} ++static void dissect_dl_config_request_edpcch_params_rel11_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // EPDCCH Resource assignment flag ++ guint8 epdcch_resource_assignment_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_epdcch_resource_assignment_flag, 1, ENC_BIG_ENDIAN); ++ if (epdcch_resource_assignment_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid epdcch resource assignment flag value [0..1]"); ++ } ++ ++ // EPDCCH ID ++ guint16 epdcch_id_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_epdcch_id, 2, ENC_BIG_ENDIAN); ++ if (epdcch_id_value > 503) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid epdcch id value [0..503]"); ++ } ++ ++ // EPDCCH Start Symbol ++ guint8 epdcch_start_symbol_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_epdcch_start_symbol, 1, ENC_BIG_ENDIAN); ++ if (!(epdcch_start_symbol_value >= 1 && epdcch_start_symbol_value <= 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid epdcch start symbol value [1..4]"); ++ } ++ ++ // EPDCCH NumPRB ++ guint8 count = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_epdcch_num_prb, 1, ENC_BIG_ENDIAN); ++ if (!(count == 2 || count == 4 || count == 8)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid epdcch num prb value [2, 4, 8]"); ++ } ++ ++ dissect_array_value(ptvc, pinfo, "PRBs", ett_nfapi_epdcch_prbs, count, dissect_epdcch_prb_index_value); ++ ++ dissect_bf_vector_type_value(ptvc, pinfo); ++} ++static void dissect_dl_config_request_edpcch_params_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // DwPTS Symbols ++ guint8 dwtps_symbols_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_initial_lbt_sf, 1, ENC_BIG_ENDIAN); ++ if (!(dwtps_symbols_value == 3 || dwtps_symbols_value == 6 || dwtps_symbols_value == 9 || ++ dwtps_symbols_value == 10 || dwtps_symbols_value == 11 || dwtps_symbols_value == 12 || ++ dwtps_symbols_value == 14)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid dwpts symbols value [3, 6, 9, 10, 11, 12, 14]"); ++ } ++ ++ // Initial LBT SF ++ guint8 initial_lbt_sf_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_dwpts_symbols, 1, ENC_BIG_ENDIAN); ++ if (initial_lbt_sf_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid initial lbt sf value [0..1]"); ++ } ++ ++} ++static void dissect_precoding_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add(ptvc, hf_nfapi_precoding_value, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_dl_config_request_mpdpcch_pdu_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // MPDCCH Narrowband ++ guint8 mpdcch_narrowband_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mpdcch_narrowband, 1, ENC_BIG_ENDIAN); ++ if (mpdcch_narrowband_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mpdcch narrowband value [0..15]"); ++ } ++ ++ // Number of PRB pairs ++ guint8 number_of_prb_pair_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_prb_pairs, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_prb_pair_value == 2 || number_of_prb_pair_value == 4 || number_of_prb_pair_value == 6)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of prb pair value [2, 4, 6]"); ++ } ++ ++ // Resource Block Assignment ++ guint8 resource_block_assignment_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_resource_block_assignment, 1, ENC_BIG_ENDIAN); ++ if (resource_block_assignment_value > 14) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid resource block assignment value [0..14]"); ++ } ++ ++ // MPDCCH transmission type ++ guint8 mpdcch_transmission_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mpdcch_transmission_type, 1, ENC_BIG_ENDIAN); ++ if (mpdcch_transmission_type_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mpdcch transmission type value [0..1]"); ++ } ++ ++ // Start symbol ++ guint8 start_symbol_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_start_symbol, 1, ENC_BIG_ENDIAN); ++ if (!(start_symbol_value >= 1 && start_symbol_value <=4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid start symbol value [1..4]"); ++ } ++ ++ // ECCE index ++ guint8 ecce_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ecce_index, 1, ENC_BIG_ENDIAN); ++ if (ecce_index_value > 22) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ecce index value [0..22]"); ++ } ++ ++ // Aggregation level ++ guint8 aggregation_level_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_aggregation_level, 1, ENC_BIG_ENDIAN); ++ if (!(aggregation_level_value == 2 || aggregation_level_value == 4 || aggregation_level_value == 8 || ++ aggregation_level_value == 16 || aggregation_level_value == 24)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid aggregation level value [2, 4, 8, 16, 24]"); ++ } ++ ++ // RNTI type ++ guint8 rnti_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mpdcch_rnti_type, 1, ENC_BIG_ENDIAN); ++ if (rnti_type_value > 4) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rnti type value [0..4]"); ++ } ++ ++ // RNTI ++ guint16 rnti_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_rnti, 2, ENC_BIG_ENDIAN); ++ if (!(rnti_value >= 1)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rnti value [1..65535]"); ++ } ++ ++ // CEMode ++ guint8 cemode_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ce_mode, 1, ENC_BIG_ENDIAN); ++ if (!(cemode_value >= 1 && cemode_value <= 2)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid cemode value [1..2]"); ++ } ++ ++ // DMRS scrambling init ++ guint16 drms_scrambling_init_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_drms_scrabmling_init, 2, ENC_BIG_ENDIAN); ++ if (drms_scrambling_init_value > 503) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid drms scrambling init value [0..503]"); ++ } ++ ++ // Initial transmission SF (io) ++ guint16 initial_transmission_sf_io_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_initial_transmission_sf, 2, ENC_BIG_ENDIAN); ++ if (!(initial_transmission_sf_io_value <= 10239 || initial_transmission_sf_io_value == 0xFFFF)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid initial transmission sf io value [0..10239, 0xFFFF]"); ++ } ++ ++ // Transmission power ++ guint16 transmission_power_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_power, 2, ENC_BIG_ENDIAN); ++ if (transmission_power_value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission power value [0..10000]"); ++ } ++ ++ // DCI format ++ guint8 dci_format_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_dl_dci_format, 1, ENC_BIG_ENDIAN); ++ if (!(dci_format_value == 10 || dci_format_value == 11 || dci_format_value == 12)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid dci format value [10, 11, 12]"); ++ } ++ ++ // Resource block coding ++ ptvcursor_add(ptvc, hf_nfapi_resource_block_coding, 2, ENC_BIG_ENDIAN); ++ ++ // MCS ++ guint8 mcs_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mcs, 1, ENC_BIG_ENDIAN); ++ if (mcs_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission power value [0..15]"); ++ } ++ ++ // PDSCH repetition levels ++ guint8 pdsch_repetition_levels_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pdsch_reception_levels, 1, ENC_BIG_ENDIAN); ++ if (!(pdsch_repetition_levels_value >= 1 && pdsch_repetition_levels_value <= 8)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pdsch repetition levels value [1..8]"); ++ } ++ ++ // Redundancy version ++ guint8 redundancy_version_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_redundancy_version, 1, ENC_BIG_ENDIAN); ++ if (redundancy_version_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid redundancy version value [0..3]"); ++ } ++ ++ // New data indicator ++ guint8 new_data_indicator_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_new_data_indicator, 1, ENC_BIG_ENDIAN); ++ if (new_data_indicator_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid new data indicator value [0..1]"); ++ } ++ ++ // HARQ process ++ guint8 harq_process_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_process, 1, ENC_BIG_ENDIAN); ++ if (harq_process_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq process value [0..15]"); ++ } ++ ++ // TPMI length ++ guint8 tpmi_length_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_tpmi_length, 1, ENC_BIG_ENDIAN); ++ if (!(tpmi_length_value == 0 || tpmi_length_value == 2 || tpmi_length_value == 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid tpmi length value [0, 2, 4]"); ++ } ++ ++ // TPMI ++ guint8 tpmi_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_tpmi, 1, ENC_BIG_ENDIAN); ++ if (tpmi_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid tpmi value [0..15]"); ++ } ++ ++ // PMI flag ++ guint8 pmi_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pmi_flag, 1, ENC_BIG_ENDIAN); ++ if (pmi_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pmi flag value [0..1]"); ++ } ++ ++ // PMI ++ guint8 pmi_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pmi, 1, ENC_BIG_ENDIAN); ++ if (pmi_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pmi value [0..1]"); ++ } ++ ++ // HARQ resource offset ++ guint8 harq_resource_offset_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_resource_offset, 1, ENC_BIG_ENDIAN); ++ if (harq_resource_offset_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq resource offset value [0..3]"); ++ } ++ ++ // DCI subframe repetition number ++ guint8 dci_subframe_reptition_number_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_dci_subframe_repetition_number, 1, ENC_BIG_ENDIAN); ++ if (!(dci_subframe_reptition_number_value >= 1 && dci_subframe_reptition_number_value <= 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid dci subframe repetition number value [1..4]"); ++ } ++ ++ // TPC ++ guint8 tpc_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_tpc, 1, ENC_BIG_ENDIAN); ++ if (tpc_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid tpc value [0..3]"); ++ } ++ ++ // Downlink assignment index Length ++ guint8 downlink_assignment_index_length_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_downlink_assignment_index_length, 1, ENC_BIG_ENDIAN); ++ if (!(downlink_assignment_index_length_value == 0 || downlink_assignment_index_length_value == 2 || ++ downlink_assignment_index_length_value == 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid downlink assignmnet index value [0, 2, 4]"); ++ } ++ ++ // Downlink assignment index ++ guint8 downlink_assignment_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_downlink_assignment_index, 1, ENC_BIG_ENDIAN); ++ if (downlink_assignment_index_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid downlink assignment index value [0..15]"); ++ } ++ ++ // Allocate PRACH flag ++ guint8 allocate_prach_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_allocate_prach_flag, 1, ENC_BIG_ENDIAN); ++ if (allocate_prach_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid allocate prach flag value [0..1]"); ++ } ++ ++ // Preamble index ++ guint8 preamble_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_preamble_index, 1, ENC_BIG_ENDIAN); ++ if (preamble_index_value > 63) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid preamble index value [0..63]"); ++ } ++ ++ // PRACH mask index ++ guint8 prach_mask_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_prach_mask_index, 1, ENC_BIG_ENDIAN); ++ if (prach_mask_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid prach mask index value [0..15]"); ++ } ++ ++ // Starting CE Level ++ guint8 starting_ce_level_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_starting_ce_level, 1, ENC_BIG_ENDIAN); ++ if (starting_ce_level_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid starting ce level value [0..3]"); ++ } ++ ++ // SRS request ++ guint8 srs_request_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_srs_request, 1, ENC_BIG_ENDIAN); ++ if (srs_request_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid srs request value [0..1]"); ++ } ++ ++ // Antenna ports and scrambling identity flag ++ guint8 antenna_ports_and_scrambling_identity_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_antenna_ports_and_scrambling_identity_flag, 1, ENC_BIG_ENDIAN); ++ if (antenna_ports_and_scrambling_identity_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid antenna ports and scrambling identity flag value [0..1]"); ++ } ++ ++ // Antenna ports and scrambling identity ++ guint8 antenna_ports_and_scrambling_identity_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_antenna_ports_and_scrambling_identity, 1, ENC_BIG_ENDIAN); ++ if (antenna_ports_and_scrambling_identity_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid antenna ports and scrambling identity value [0..3]"); ++ } ++ ++ // Frequency hopping enabled flag ++ guint8 frequency_hopping_enabled_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_frequency_hopping_enabled_flag, 1, ENC_BIG_ENDIAN); ++ if (frequency_hopping_enabled_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid frequency hopping enabled flag value [0..1]"); ++ } ++ ++ // Paging/Direct indication differentiation flag ++ guint8 paging_direct_indicaton_differentiation_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_paging_direct_indication_differentiation_flag, 1, ENC_BIG_ENDIAN); ++ if (paging_direct_indicaton_differentiation_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid paging/direct indication differentiation flag value [0..1]"); ++ } ++ ++ // Direct indication ++ ptvcursor_add(ptvc, hf_nfapi_direct_indication, 1, ENC_BIG_ENDIAN); ++ ++ // Total DCI length including padding ++ item = ptvcursor_add(ptvc, hf_nfapi_total_dci_length_including_padding, 1, ENC_BIG_ENDIAN); ++ ++ // Number of TX Antenna ports ++ guint8 count = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_tx_antenna_ports, 1, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "Precoding", ett_nfapi_precoding, count, dissect_precoding_value); ++} ++static void dissect_ul_config_pdu(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // PDU Type ++ guint8 ul_pdu_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ul_config_pdu_type, 1, ENC_BIG_ENDIAN); ++ if (ul_pdu_type_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ul pdu type value [0..15]"); ++ } ++ ++ guint8 size = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pdu_size, 1, ENC_BIG_ENDIAN); ++ ++ guint pdu_end = (ptvcursor_current_offset(ptvc) + size - 2); ++ dissect_tlv_list(ptvc, pinfo, pdu_end); ++} ++static void dissect_ul_config_request_body_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Number of PDUs ++ guint8 num_pdu = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_pdus, 1, ENC_BIG_ENDIAN); ++ ++ // RACH/PRACH frequency resources ++ guint8 rach_prach_frequency_resources_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_rach_prach_frequency_resources, 1, ENC_BIG_ENDIAN); ++ if (rach_prach_frequency_resources_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rach prach frequency resources value [0..1]"); ++ } ++ ++ // SRS present ++ guint8 srs_present_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_srs_present, 1, ENC_BIG_ENDIAN); ++ if (srs_present_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid srs present value [0..1]"); ++ } ++ ++ dissect_array_value(ptvc, pinfo, "UL Config PDU List", ett_nfapi_ul_config_request_pdu_list, num_pdu, dissect_ul_config_pdu); ++} ++static void dissect_ul_config_ulsch_pdu_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Handle ++ ptvcursor_add(ptvc, hf_nfapi_handle, 4, ENC_BIG_ENDIAN); ++ ++ // Size ++ ptvcursor_add(ptvc, hf_nfapi_size, 2, ENC_BIG_ENDIAN); ++ ++ // RNTI ++ guint16 rnti_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_rnti, 2, ENC_BIG_ENDIAN); ++ if (!(rnti_value >= 1)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rnti value [1..65535]"); ++ } ++ ++ // Resource block start ++ guint8 resource_block_start_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_resource_block_start, 1, ENC_BIG_ENDIAN); ++ if (resource_block_start_value > 99) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid resource block start value [0..99]"); ++ } ++ ++ // Number of resource blocks ++ guint8 number_of_resource_blocks_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_resource_blocks, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_resource_blocks_value >= 1 && number_of_resource_blocks_value <= 100)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of resource blocks value [1..100]"); ++ } ++ ++ // Modulation type ++ guint8 modulation_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_modulation, 1, ENC_BIG_ENDIAN); ++ if (!(modulation_type_value == 2 || modulation_type_value == 4 || modulation_type_value == 6)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid modulation type value [2, 4, 6]"); ++ } ++ ++ // Cyclic Shift 2 for DMRS ++ guint8 cyclic_shift_2_for_drms_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_cyclic_shift_2_for_drms, 1, ENC_BIG_ENDIAN); ++ if (cyclic_shift_2_for_drms_value > 99) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid cyclic shift 2 for drms value [0..7]"); ++ } ++ ++ // Frequency hopping enabled flag ++ guint8 frequency_hopping_enabled_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_frequency_hopping_enabled_flag, 1, ENC_BIG_ENDIAN); ++ if (frequency_hopping_enabled_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid frequency hopping enabled flag value [0..1]"); ++ } ++ ++ // Frequency hopping bits ++ guint8 frequency_hopping_bits_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_frequency_hopping_bits, 1, ENC_BIG_ENDIAN); ++ if (frequency_hopping_bits_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid frequency hopping bits value [0..3]"); ++ } ++ ++ // New data indication ++ guint8 new_data_indication_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_new_data_indication, 1, ENC_BIG_ENDIAN); ++ if (new_data_indication_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid new data indicator value [0..1]"); ++ } ++ ++ // Redundancy version ++ guint8 redundancy_version_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_redundancy_version, 1, ENC_BIG_ENDIAN); ++ if (redundancy_version_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid redundancy version value [0..3]"); ++ } ++ ++ // HARQ process number ++ guint8 harq_process_number_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_process_number, 1, ENC_BIG_ENDIAN); ++ if (harq_process_number_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq process number value [0..15]"); ++ } ++ ++ // UL Tx mode ++ guint8 ul_tx_mode_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ul_tx_mode, 1, ENC_BIG_ENDIAN); ++ if (ul_tx_mode_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ul tx mode value [0..1]"); ++ } ++ ++ // Current TX NB ++ ptvcursor_add(ptvc, hf_nfapi_current_tx_nb, 1, ENC_BIG_ENDIAN); ++ ++ // N srs ++ guint8 n_srs_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_srs, 1, ENC_BIG_ENDIAN); ++ if (n_srs_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n_srs value [0..1]"); ++ } ++} ++static void dissect_ul_config_ulsch_pdu_rel10_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Resource allocation type ++ guint8 resource_allocation_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_resource_allocation_type, 1, ENC_BIG_ENDIAN); ++ if (resource_allocation_type_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid resource allocation type value [0..1]"); ++ } ++ ++ // Resource block coding ++ ptvcursor_add(ptvc, hf_nfapi_resource_block_coding, 4, ENC_BIG_ENDIAN); ++ ++ // Transport blocks ++ guint8 transport_blocks_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transport_blocks, 1, ENC_BIG_ENDIAN); ++ if (!(transport_blocks_value >= 1 && transport_blocks_value <= 2)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transport blocks value [1..2]"); ++ } ++ ++ // Transmission scheme ++ guint8 transmission_scheme_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ul_transmission_scheme, 1, ENC_BIG_ENDIAN); ++ if (transmission_scheme_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission scheme value [0..1]"); ++ } ++ ++ // Number Of layers ++ guint8 number_of_layers_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_layers, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_layers_value >= 1 && number_of_layers_value <=4 )) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of layers value [1..4]"); ++ } ++ ++ // Codebook Index ++ guint8 codebook_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_codebook_index, 1, ENC_BIG_ENDIAN); ++ if (codebook_index_value > 23) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid codebook index value [0..23]"); ++ } ++ ++ // Disable sequence hopping flag ++ guint8 disable_sequence_hopping_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_disable_sequence_hopping_flag, 1, ENC_BIG_ENDIAN); ++ if (disable_sequence_hopping_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid disable sequence hopping flag value [0..1]"); ++ } ++} ++static void dissect_ul_config_ulsch_pdu_rel11_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Virtual cell ID enabled flag ++ guint8 virtual_cell_id_enabled_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_virtual_cell_id_enabled_flag, 1, ENC_BIG_ENDIAN); ++ if (virtual_cell_id_enabled_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid virtual cell id enabled flag value [0..1]"); ++ } ++ ++ // nPUSCH Identity ++ guint16 npusch_identity_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_npusch_identity, 2, ENC_BIG_ENDIAN); ++ if (npusch_identity_value > 509) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid npusch identity value [0..509]"); ++ } ++ ++ // DMRS Config flag ++ guint8 drms_config_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_drms_config_flag, 1, ENC_BIG_ENDIAN); ++ if (drms_config_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid drms config flag value [0..1]"); ++ } ++ ++ // nDMRS-CSH Identity ++ guint16 ndrms_csh_identity_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ndrms_csh_identity, 2, ENC_BIG_ENDIAN); ++ if (ndrms_csh_identity_value > 509) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ndrms-csh identity value [0..509]"); ++ } ++ ++} ++static void dissect_ul_config_ulsch_pdu_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // UE Type ++ guint8 ue_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ue_type, 1, ENC_BIG_ENDIAN); ++ if (ue_type_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ue type value [0..2]"); ++ } ++ ++ // Total Number of repetitions ++ guint16 total_number_of_repetitions_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_total_number_of_repetitions, 2, ENC_BIG_ENDIAN); ++ if (!(total_number_of_repetitions_value >= 1 && total_number_of_repetitions_value <= 2048)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid total number of repetitions value [1..2048]"); ++ } ++ ++ // Repetition Number ++ guint16 repetition_number_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_repetition_number, 2, ENC_BIG_ENDIAN); ++ if (!(repetition_number_value >= 1 && repetition_number_value <= 2048)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid repetition number value [1..2048]"); ++ } ++ ++ // Initial transmission SF (io) ++ guint16 intial_transmission_sf_io_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_initial_sf_io, 2, ENC_BIG_ENDIAN); ++ if (!(intial_transmission_sf_io_value <= 10239 || intial_transmission_sf_io_value == 0xFFFF)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid repetition number value [0..10239, 0xFFFF]"); ++ } ++ ++ // Empy symbols due to re-tunning ++ // todo : decode as a bitmap ++ ptvcursor_add(ptvc, hf_nfapi_empty_symbols_due_to_retunning, 1, ENC_BIG_ENDIAN); ++} ++static void dissect_ul_config_init_tx_params_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // N srs initial ++ guint8 n_srs_initial_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_srs_initial, 1, ENC_BIG_ENDIAN); ++ if (n_srs_initial_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n srs initial value [0..1]"); ++ } ++ ++ // Initial number of resource blocks ++ guint8 initial_number_of_resource_blocks_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_initial_number_of_resource_blocks, 1, ENC_BIG_ENDIAN); ++ if (!(initial_number_of_resource_blocks_value >= 1 && initial_number_of_resource_blocks_value <= 100)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid initial number of reosurce blocks value [1..100]"); ++ } ++ ++} ++static void dissect_ul_config_cqi_ri_info_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // DL CQI/PMI Size Rank = 1 ++ ptvcursor_add(ptvc, hf_nfapi_dl_cqi_pmi_size_rank_1, 1, ENC_BIG_ENDIAN); ++ ++ // DL CQI/PMI Size Rank>1 ++ ptvcursor_add(ptvc, hf_nfapi_dl_cqi_pmi_size_rank_greater_1, 1, ENC_BIG_ENDIAN); ++ ++ // RI Size ++ guint8 ri_size_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ri_size, 1, ENC_BIG_ENDIAN); ++ if (ri_size_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ri size value [0..3]"); ++ } ++ ++ // Delta Offset CQI ++ guint8 delta_offset_cqi_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_delta_offset_cqi, 1, ENC_BIG_ENDIAN); ++ if (delta_offset_cqi_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid delta offset cqi value [0..15]"); ++ } ++ ++ // Delta Offset RI ++ guint8 delta_offset_ri_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_delta_offset_ri, 1, ENC_BIG_ENDIAN); ++ if (delta_offset_ri_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid delta offset ri value [0..15]"); ++ } ++} ++static void dissect_ul_cqi_pmi_size(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Delta Offset RI ++ guint8 dl_cqi_pmi_size_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_delta_offset_ri, 1, ENC_BIG_ENDIAN); ++ if (dl_cqi_pmi_size_value > 255) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid delta offset ri value [0..255]"); ++ } ++} ++ ++static void dissect_ul_config_cqi_ri_info_rel9_later_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ // Report type ++ guint8 type = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_report_type, 1, ENC_BIG_ENDIAN); ++ if (type > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid report type value [0..1]"); ++ } ++ ++ // Delta offset CQI ++ guint8 delta_offset_cqi_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_delta_offset_cqi, 1, ENC_BIG_ENDIAN); ++ if (delta_offset_cqi_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid delta offset cqi value [0..15]"); ++ } ++ ++ // Delta offset RI ++ guint8 delta_offset_ri_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_delta_offset_ri, 1, ENC_BIG_ENDIAN); ++ if (delta_offset_ri_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid delta offset ri value [0..15]"); ++ } ++ ++ switch (type) ++ { ++ case 0: ++ { ++ // DL CQI/PMI/RI size ++ ptvcursor_add(ptvc, hf_nfapi_dl_cqi_ri_pmi_size, 1, ENC_BIG_ENDIAN); ++ ++ // Control Type ++ guint8 control_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_control_type, 1, ENC_BIG_ENDIAN); ++ if (control_type_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid control type value [0..1]"); ++ } ++ break; ++ } ++ case 1: ++ { ++ // todo : encoder not right for this case. ++ gint8 num_cc_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_cc, 1, ENC_BIG_ENDIAN); ++ ++ if (!(num_cc_value >= 1 && num_cc_value <= 32)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of cc value [1..32]"); ++ } ++ ++ // UL CONFIG CQI PMI SIZE ++ dissect_array_value(ptvc, pinfo, "CQI PMI SIZE", ett_nfapi_cqi_pmi_size, 8, dissect_ul_cqi_pmi_size); ++ ++ /* ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_tlv_tree, "CCs"); ++ ++ for (int i = 0; i < num_cc; ++i) ++ { ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_tlv_tree, "[%d]", i); ++ ++ guint8 ri_size = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_ri_size, 1, ENC_BIG_ENDIAN); ++ ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_tlv_tree, "Rank"); ++ ++ for (int j = 0; j < ri_size; ++j) ++ { ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_tlv_tree, "[%d]", j); ++ ptvcursor_add(ptvc, hf_nfapi_dl_cqi_pmi_size, 1, ENC_BIG_ENDIAN); ++ ptvcursor_pop_subtree(ptvc); ++ } ++ ++ ptvcursor_pop_subtree(ptvc); ++ ++ ptvcursor_pop_subtree(ptvc); ++ } ++ ++ ptvcursor_pop_subtree(ptvc); ++ */ ++ ++ break; ++ } ++ } ++} ++static void dissect_ul_config_cqi_ri_info_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // DL CQI/PMI/RI size 2 ++ guint16 dl_cqi_ri_pmi_size_2_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_dl_cqi_ri_pmi_size_2, 2, ENC_BIG_ENDIAN); ++ if (dl_cqi_ri_pmi_size_2_value < 255) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid dl cqi ri pmi size 2 value [>= 255]"); ++ } ++} ++static void dissect_ul_config_harq_info_ulsch_rel10_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // HARQ Size ++ guint8 harq_size_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_size, 1, ENC_BIG_ENDIAN); ++ if (harq_size_value > 21) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq size value [0..21]"); ++ } ++ ++ // Delta Offset HARQ ++ guint8 delta_offset_harq_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_delta_offset_harq, 1, ENC_BIG_ENDIAN); ++ if (delta_offset_harq_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid delta offset harq value [0..15]"); ++ } ++ ++ // ACK_NACK mode ++ guint8 ack_nack_mode_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_tdd_ack_nack_mode, 1, ENC_BIG_ENDIAN); ++ if (ack_nack_mode_value > 5) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ack nack mode value [0..5]"); ++ } ++} ++static void dissect_ul_config_harq_info_ulsch_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // HARQ Size 2 ++ ptvcursor_add(ptvc, hf_nfapi_harq_size_2, 2, ENC_BIG_ENDIAN); ++ ++ // Delta Offset HARQ 2 ++ guint8 delta_offset_harq_2_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_delta_offset_harq_2, 1, ENC_BIG_ENDIAN); ++ if (delta_offset_harq_2_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid delta offset harq 2 value [0..15]"); ++ } ++} ++static void dissect_ul_config_ue_info_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Handle ++ ptvcursor_add(ptvc, hf_nfapi_handle, 4, ENC_BIG_ENDIAN); ++ ++ // RNTI ++ guint16 rnti_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_rnti, 2, ENC_BIG_ENDIAN); ++ if (rnti_value < 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rnti value [1..65535]"); ++ } ++} ++static void dissect_ul_config_ue_info_rel11_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Virtual cell ID enabled flag ++ guint8 virtual_cell_id_enabled_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_virtual_cell_id_enabled_flag, 1, ENC_BIG_ENDIAN); ++ if (virtual_cell_id_enabled_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid virtual cell id enabled flag value [0..1]"); ++ } ++ ++ // nPUCCH Identity ++ guint16 npucch_identity_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_npucch_identity, 2, ENC_BIG_ENDIAN); ++ if (npucch_identity_value > 503) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid npucch identity value [0..503]"); ++ } ++ ++} ++static void dissect_ul_config_ue_info_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // UE Type ++ guint8 ue_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ue_type, 1, ENC_BIG_ENDIAN); ++ if (ue_type_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ue type value [0..2]"); ++ } ++ ++ // Empty symbols ++ // todo : use bit map decoding ++ ptvcursor_add(ptvc, hf_nfapi_empty_symbols, 1, ENC_BIG_ENDIAN); ++ ++ // Total Number of repetitions ++ guint16 total_number_of_repetitions_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_total_number_of_repetitions, 2, ENC_BIG_ENDIAN); ++ if (!(total_number_of_repetitions_value >= 1 && total_number_of_repetitions_value <= 32)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid total number of repetitions value [1..32]"); ++ } ++ ++ // Repetition Number ++ guint16 repetition_number_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_repetition_number, 2, ENC_BIG_ENDIAN); ++ if (!(repetition_number_value >= 1 && repetition_number_value <= 32)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid repetition number value [1..32]"); ++ } ++ ++} ++static void dissect_ul_config_cqi_info_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // PUCCH index ++ guint16 pucch_index_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pucch_index, 2, ENC_BIG_ENDIAN); ++ if (pucch_index_value > 1184) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pucch index value [0..1184]"); ++ } ++ ++ // DL CQI/PMI Size ++ ptvcursor_add(ptvc, hf_nfapi_dl_cqi_pmi_size, 1, ENC_BIG_ENDIAN); ++} ++static void dissect_ul_config_cqi_info_rel10_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Number of PUCCH Resources ++ guint8 number_of_pucch_resources_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_pucch_resource, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_pucch_resources_value >= 1 && number_of_pucch_resources_value <= 2)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of pucch resources value [1..2]"); ++ } ++ ++ //PUCCH Index P1 ++ guint16 pucch_index_p1_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pucch_index_p1, 2, ENC_BIG_ENDIAN); ++ if (pucch_index_p1_value > 1184) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pucch index p1 value [0..1184]"); ++ } ++} ++static void dissect_ul_config_cqi_info_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // CSI_mode ++ guint8 csi_mode_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_csi_mode, 1, ENC_BIG_ENDIAN); ++ if (csi_mode_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid csi mode value [0..2]"); ++ } ++ ++ // DL CQI/PMI Size 2 ++ ptvcursor_add(ptvc, hf_nfapi_dl_cqi_pmi_size_2, 2, ENC_BIG_ENDIAN); ++ ++ // Starting PRB ++ guint8 starting_prb_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_statring_prb, 1, ENC_BIG_ENDIAN); ++ if (starting_prb_value > 109) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid starting prb value [0..109]"); ++ } ++ ++ // n_PRB ++ guint8 n_prb_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_nprb, 1, ENC_BIG_ENDIAN); ++ if (n_prb_value > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n prb value [0..7]"); ++ } ++ ++ // cdm_Index ++ guint8 cdm_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_cdm_index, 1, ENC_BIG_ENDIAN); ++ if (cdm_index_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid cdm index value [0..1]"); ++ } ++ ++ // N srs ++ guint8 n_srs_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_nsrs, 1, ENC_BIG_ENDIAN); ++ if (n_srs_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n srs value [0..1]"); ++ } ++ ++} ++static void dissect_ul_config_sr_info_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 pucch_index_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_pucch_index, 2, ENC_BIG_ENDIAN); ++ if (pucch_index_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pucch index value [0..2047]"); ++ } ++} ++static void dissect_ul_config_sr_info_rel10_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Number of PUCCH Resources ++ guint8 number_of_pucch_resources_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_pucch_resource, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_pucch_resources_value >= 1 && number_of_pucch_resources_value <= 2)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of pucch resources value [0..2047]"); ++ } ++ ++ // PUCCH Index P1 ++ guint16 pucch_index_p1_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pucch_index_p1, 2, ENC_BIG_ENDIAN); ++ if (pucch_index_p1_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pucch index p1 value [0..2047]"); ++ } ++} ++static void dissect_ul_config_harq_info_uci_rel10_tdd_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // HARQ size ++ guint8 harq_size_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_size, 1, ENC_BIG_ENDIAN); ++ if (harq_size_value > 21) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq size value [0..21]"); ++ } ++ ++ // ACK_NACK mode ++ guint8 ack_nack_mode_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_tdd_ack_nack_mode, 1, ENC_BIG_ENDIAN); ++ if (ack_nack_mode_value > 5) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ack nack mode value [0..5]"); ++ } ++ ++ // Number of PUCCH resources ++ guint8 number_of_pucch_resources_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_pucch_resource, 1, ENC_BIG_ENDIAN); ++ if (number_of_pucch_resources_value > 4) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of pucch resources value [0..4]"); ++ } ++ ++ // n_PUCCH_1_0 ++ guint16 npucch_1_0_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_pucch_1_0, 2, ENC_BIG_ENDIAN); ++ if (ack_nack_mode_value == 0 || ack_nack_mode_value == 1 || ack_nack_mode_value == 2) ++ { ++ if (npucch_1_0_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n pucch 1 0 value [0..2047] (All Format 1a/1b)"); ++ } ++ } ++ else if (ack_nack_mode_value == 3) ++ { ++ if (npucch_1_0_value > 549) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n pucch 1 0 value [0..549] (Format 3)"); ++ } ++ } ++ ++ // n_PUCCH_1_1 ++ guint16 npucch_1_1_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_pucch_1_1, 2, ENC_BIG_ENDIAN); ++ if (ack_nack_mode_value == 0 || ack_nack_mode_value == 1 || ack_nack_mode_value == 2) ++ { ++ if (npucch_1_1_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n pucch 1 1 value [0..2047] (All Format 1a/1b)"); ++ } ++ } ++ ++ // n_PUCCH_1_2 ++ guint16 npucch_1_2_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_pucch_1_2, 2, ENC_BIG_ENDIAN); ++ if (ack_nack_mode_value == 2) ++ { ++ if (npucch_1_2_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n pucch 1 2 value [0..2047] (All Format 1a/1b)"); ++ } ++ } ++ ++ // n_PUCCH_1_3 ++ guint16 npucch_1_3_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_pucch_1_3, 2, ENC_BIG_ENDIAN); ++ if (ack_nack_mode_value == 2) ++ { ++ if (npucch_1_3_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n pucch 1 3 value [0..2047] (All Format 1a/1b)"); ++ } ++ } ++} ++static void dissect_ul_config_harq_info_uci_rel8_fdd_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // n_PUCCH_1_0 ++ // todo : how to work out the ack_nack mode? ++ guint16 npucch_1_0_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_pucch_1_0, 2, ENC_BIG_ENDIAN); ++ if (npucch_1_0_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n pucch 1 0 value [0..2047]"); ++ } ++ ++ // HARQ Size ++ guint8 harq_size_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_size, 1, ENC_BIG_ENDIAN); ++ if (!(harq_size_value >= 1 && harq_size_value <= 2)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq size value [1..2]"); ++ } ++} ++static void dissect_ul_config_harq_info_uci_rel9_later_fdd_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // HARQ Size ++ guint8 harq_size_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* harq_size_item = ptvcursor_add(ptvc, hf_nfapi_harq_size, 1, ENC_BIG_ENDIAN); ++ ++ // ACK_NAK mode ++ guint8 ack_nack_mode_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_fdd_ack_nack_mode, 1, ENC_BIG_ENDIAN); ++ if (ack_nack_mode_value > 4) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ack nack mode value [0..4]"); ++ } ++ ++ if (ack_nack_mode_value == 0 || ack_nack_mode_value == 2) ++ { ++ if (!(harq_size_value >= 1 && harq_size_value <= 10)) ++ { ++ expert_add_info_format(pinfo, harq_size_item, &ei_invalid_range, "Invalid harq size value [1..10] (Format 1a/1b/3)"); ++ } ++ } ++ else if (ack_nack_mode_value == 3 || ack_nack_mode_value == 4) ++ { ++ if (harq_size_value != 0) ++ { ++ expert_add_info_format(pinfo, harq_size_item, &ei_invalid_range, "Invalid harq size value [0] (Format 4/5)"); ++ } ++ } ++ ++ // Number of PUCCH Resources ++ guint8 number_of_pucch_resources_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_pucch_resource, 1, ENC_BIG_ENDIAN); ++ if (number_of_pucch_resources_value == 0 || number_of_pucch_resources_value == 2) ++ { ++ if (!(number_of_pucch_resources_value >= 1 && number_of_pucch_resources_value <= 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq size value [1..4] (Format 1a/1b/3)"); ++ } ++ } ++ else if (number_of_pucch_resources_value == 3 || number_of_pucch_resources_value == 4) ++ { ++ if (number_of_pucch_resources_value != 0) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq size value [0] (Format 4/5)"); ++ } ++ } ++ ++ // n_PUCCH_1_0 ++ guint16 npucch_1_0_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_pucch_1_0, 2, ENC_BIG_ENDIAN); ++ if (ack_nack_mode_value == 0 || ack_nack_mode_value == 1) ++ { ++ if (npucch_1_0_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid npucch 1 0 value [0..2047] (Format 1a/1b/channel selection)"); ++ } ++ } ++ else if (ack_nack_mode_value == 2) ++ { ++ if (npucch_1_0_value > 549) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid npucch 1 0 value [0..549] (Format 3)"); ++ } ++ } ++ ++ // n_PUCCH_1_1 ++ guint16 npucch_1_1_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_pucch_1_1, 2, ENC_BIG_ENDIAN); ++ if (ack_nack_mode_value == 0 || ack_nack_mode_value == 1) ++ { ++ if (npucch_1_1_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid npucch 1 1 value [0..2047] (Format 1a/1b/channel selection)"); ++ } ++ } ++ ++ // n_PUCCH_1_2 ++ guint16 npucch_1_2_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_pucch_1_2, 2, ENC_BIG_ENDIAN); ++ if (ack_nack_mode_value == 0 || ack_nack_mode_value == 1) ++ { ++ if (npucch_1_2_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid npucch 1 2 value [0..2047] (Format 1a/1b/channel selection)"); ++ } ++ } ++ ++ // n_PUCCH_1_3 ++ guint16 npucch_1_3_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_pucch_1_3, 2, ENC_BIG_ENDIAN); ++ if (ack_nack_mode_value == 0 || ack_nack_mode_value == 1) ++ { ++ if (npucch_1_3_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid npucch 1 3 value [0..2047] (Format 1a/1b/channel selection)"); ++ } ++ } ++} ++static void dissect_ul_config_harq_info_uci_rel11_fdd_tdd_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Num_ant_ports ++ guint8 num_ant_ports_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_num_ant_ports, 1, ENC_BIG_ENDIAN); ++ if (!(num_ant_ports_value >= 1 && num_ant_ports_value <= 2)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid num ant ports value [1..2]"); ++ } ++ ++ // n_PUCCH_2_0 ++ // todo : how to work out the ack nack mode ++ guint16 npucch_2_0_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_pucch_2_0, 2, ENC_BIG_ENDIAN); ++ if (npucch_2_0_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid npucch 2 0 value [0..2047]"); ++ } ++ ++ // n_PUCCH_2_1 ++ guint16 npucch_2_1_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_pucch_2_1, 2, ENC_BIG_ENDIAN); ++ if (npucch_2_1_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid npucch 2 1 value [0..2047]"); ++ } ++ ++ // n_PUCCH_2_2 ++ guint16 npucch_2_2_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_pucch_2_2, 2, ENC_BIG_ENDIAN); ++ if (npucch_2_2_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid npucch 2 2 value [0..2047]"); ++ } ++ ++ // n_PUCCH_2_3 ++ guint16 npucch_2_3_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_pucch_2_3, 2, ENC_BIG_ENDIAN); ++ if (npucch_2_3_value > 2047) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid npucch 2 3 value [0..2047]"); ++ } ++ ++} ++static void dissect_ul_config_harq_info_uci_rel13_fdd_tdd_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // HARQ Size 2 ++ ptvcursor_add(ptvc, hf_nfapi_harq_size_2, 2, ENC_BIG_ENDIAN); ++ ++ // Starting PRB ++ guint8 starting_prb_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_starting_prb, 1, ENC_BIG_ENDIAN); ++ if (starting_prb_value > 109) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid starting prb value [0..109]"); ++ } ++ ++ // n_PRB ++ guint8 n_prb_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_nprb, 1, ENC_BIG_ENDIAN); ++ if (n_prb_value > 109) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n prb value [0..7]"); ++ } ++ ++ // cdm_Index ++ guint8 cdm_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_cdm_index, 1, ENC_BIG_ENDIAN); ++ if (cdm_index_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid cdm index value [0..1]"); ++ } ++ ++ // N srs ++ guint8 n_srs_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_nsrs, 1, ENC_BIG_ENDIAN); ++ if (n_srs_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n srs value [0..1]"); ++ } ++} ++static void dissect_ul_config_srs_info_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Handle ++ ptvcursor_add(ptvc, hf_nfapi_handle, 4, ENC_BIG_ENDIAN); ++ ++ // Size ++ ptvcursor_add(ptvc, hf_nfapi_size, 2, ENC_BIG_ENDIAN); ++ ++ // RNTI ++ guint16 rnti_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_rnti, 2, ENC_BIG_ENDIAN); ++ if (rnti_value < 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rnti value [1..65535]"); ++ } ++ ++ // SRS Bandwidth ++ guint8 srs_bandwidth_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_srs_bandwidth, 1, ENC_BIG_ENDIAN); ++ if (srs_bandwidth_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid srs bandwidth value [0..3]"); ++ } ++ ++ // Frequency Domain Position ++ guint8 frequency_domain_position_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_frequency_domain_position, 1, ENC_BIG_ENDIAN); ++ if (frequency_domain_position_value > 23) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid frequency domain bandwidth value [0..23]"); ++ } ++ ++ // SRS Hopping Bandwidth ++ guint8 srs_hopping_bandwidth_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_srs_hopping_bandwidth, 1, ENC_BIG_ENDIAN); ++ if (srs_hopping_bandwidth_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid srs hopping bandwidth value [0..3]"); ++ } ++ ++ // Transmission Comb ++ guint8 transmission_comb_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_comb, 1, ENC_BIG_ENDIAN); ++ if (transmission_comb_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission comb value [0..3]"); ++ } ++ ++ // ISRS / SRS-ConfigIndex ++ guint16 srs_config_index_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_i_srs, 2, ENC_BIG_ENDIAN); ++ if (srs_config_index_value > 1023) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid isrs/srs-configindex value [0..1023]"); ++ } ++ ++ // Sounding Reference Cyclic Shift ++ guint8 sounding_reference_cyclic_shift_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_sounding_reference_cyclic_shift, 1, ENC_BIG_ENDIAN); ++ if (sounding_reference_cyclic_shift_value > 11) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid sounding reference cyclic shift value [0..11]"); ++ } ++} ++static void dissect_ul_config_srs_info_rel10_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 antenna_port_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_antenna_port, 1, ENC_BIG_ENDIAN); ++ if (antenna_port_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid antenna port value [0..2]"); ++ } ++} ++static void dissect_ul_config_srs_info_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 number_of_combs_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_number_of_combs, 1, ENC_BIG_ENDIAN); ++ if (number_of_combs_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of combs value [0..1]"); ++ } ++} ++static void dissect_hi_dci0_pdu(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ++ // PDU Type ++ guint8 pdu_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_hi_dci0_pdu_type, 1, ENC_BIG_ENDIAN); ++ if (pdu_type_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pdu type value [0..3]"); ++ } ++ ++ // PDU Size ++ guint8 size = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pdu_size, 1, ENC_BIG_ENDIAN); ++ ++ guint pdu_end = (ptvcursor_current_offset(ptvc) + size - 2); ++ dissect_tlv_list(ptvc, pinfo, pdu_end); ++} ++static void dissect_hi_dci0_request_body_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // SFN/SF ++ ptvcursor_add(ptvc, hf_nfapi_sfn_sf, 2, ENC_BIG_ENDIAN); ++ ++ // Number of DCI ++ guint8 num_pdu = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_dci_pdus, 1, ENC_BIG_ENDIAN); ++ ++ // Number of HI ++ num_pdu += tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_hi_pdus, 1, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "HI DCI0 PDU List", ett_nfapi_hi_dci0_request_pdu_list, num_pdu, dissect_hi_dci0_pdu); ++} ++static void dissect_hi_dci0_hi_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Resource block start ++ guint8 resource_block_start_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_resource_block_start, 1, ENC_BIG_ENDIAN); ++ if (resource_block_start_value > 100) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid resource block start value [0..100]"); ++ } ++ ++ // Cyclic Shift 2 for DMRS ++ guint8 cyclic_shift_2_for_drms_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_cyclic_shift_2_for_drms, 1, ENC_BIG_ENDIAN); ++ if (cyclic_shift_2_for_drms_value > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid cyclic shift 2 for drms value [0..7]"); ++ } ++ ++ // HI value ++ guint8 hi_value_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_hi_value, 1, ENC_BIG_ENDIAN); ++ if (hi_value_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid hi value [0..1]"); ++ } ++ ++ // I_PHICH ++ guint8 i_pich_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_i_phich, 1, ENC_BIG_ENDIAN); ++ if (i_pich_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid i phich value [0..1]"); ++ } ++ ++ // Transmission power ++ guint16 transmission_power_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_power, 2, ENC_BIG_ENDIAN); ++ if (transmission_power_value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission power value [0..10000]"); ++ } ++ ++} ++static void dissect_hi_dci0_hi_rel10_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Flag TB2 ++ guint8 flag_tb2_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_flag_tb2, 1, ENC_BIG_ENDIAN); ++ if (flag_tb2_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid flag tb2 value [0..1]"); ++ } ++ ++ // HI Value 2 ++ guint8 hi2_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_hi_value_2, 1, ENC_BIG_ENDIAN); ++ if (hi2_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid hi2 value [0..1]"); ++ } ++ ++} ++static void dissect_hi_dci0_dci_ul_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // DCI format ++ guint8 dci_format_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ul_dci_format, 1, ENC_BIG_ENDIAN); ++ if (dci_format_value > 4) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid dci format value [0..4]"); ++ } ++ ++ // CCE index ++ guint8 cce_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_cce_idx, 1, ENC_BIG_ENDIAN); ++ if (cce_index_value > 88) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid cce index value [0..88]"); ++ } ++ ++ // Aggregation level ++ guint8 aggregation_level_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_aggregation_level, 1, ENC_BIG_ENDIAN); ++ if (!(aggregation_level_value == 1 || aggregation_level_value == 2 || aggregation_level_value == 4 || ++ aggregation_level_value == 8)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid aggregation level value [1, 2, 4, 8]"); ++ } ++ ++ // RNTI ++ guint16 rnti_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_rnti, 2, ENC_BIG_ENDIAN); ++ if (rnti_value < 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rnti value [1..65535]"); ++ } ++ ++ // Resource block start ++ guint8 resource_block_start_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_resource_block_start, 1, ENC_BIG_ENDIAN); ++ if (resource_block_start_value > 100) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid resource block start value [0..100]"); ++ } ++ ++ // Number of resource blocks ++ guint8 number_of_resource_blocks_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_resource_blocks, 1, ENC_BIG_ENDIAN); ++ if (number_of_resource_blocks_value > 100) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of resource blocks value [0..100]"); ++ } ++ ++ // MCS_1 ++ guint8 mcs_1_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mcs_1, 1, ENC_BIG_ENDIAN); ++ if (mcs_1_value > 31) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mcs 1 value [0..31]"); ++ } ++ ++ // Cyclic Shift 2 for DMRS ++ guint8 cyclic_shift_2_for_drms_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_cyclic_shift_2_for_drms, 1, ENC_BIG_ENDIAN); ++ if (cyclic_shift_2_for_drms_value > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid cyclic shift 2 for drms value [0..7]"); ++ } ++ ++ // Frequency hopping enabled flag ++ guint8 frequency_hopping_enabled_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_frequency_hopping_enabled_flag, 1, ENC_BIG_ENDIAN); ++ if (frequency_hopping_enabled_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid frequency hopping enabled flag value [0..1]"); ++ } ++ ++ // Frequency hopping bits ++ guint8 frequency_hopping_bit_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_frequency_hopping_bits, 1, ENC_BIG_ENDIAN); ++ if (frequency_hopping_bit_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid frequency hopping bits value [0..3]"); ++ } ++ ++ // New Data indication_1 ++ guint8 new_data_indication_1_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_new_data_indication, 1, ENC_BIG_ENDIAN); ++ if (new_data_indication_1_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid new data indication value [0..1]"); ++ } ++ ++ // UE TX antenna selection ++ guint8 ue_tx_antenna_selection_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ue_tx_antenna_selection, 1, ENC_BIG_ENDIAN); ++ if (ue_tx_antenna_selection_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ue tx antenna selection value [0..2]"); ++ } ++ ++ // TPC ++ guint8 tpc_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_tpc, 1, ENC_BIG_ENDIAN); ++ if (tpc_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid tpc value value [0..3]"); ++ } ++ ++ // CQI/CSI request ++ guint8 cqi_csi_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_cqi_csi_request, 1, ENC_BIG_ENDIAN); ++ if (cqi_csi_value > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid cqi csi value [0..7]"); ++ } ++ ++ // UL index ++ guint8 ul_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ul_index, 1, ENC_BIG_ENDIAN); ++ if (ul_index_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ul index value [0..3]"); ++ } ++ ++ // DL assignment index ++ guint8 dl_assignment_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_dl_assignment_index, 1, ENC_BIG_ENDIAN); ++ if (!(dl_assignment_index_value >= 1 && dl_assignment_index_value <= 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid dl assignment index value [1..4]"); ++ } ++ ++ // TPC bitmap ++ ptvcursor_add(ptvc, hf_nfapi_tpc_bitmap, 4, ENC_BIG_ENDIAN); ++ ++ // Transmission power ++ guint16 transmission_power_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_power, 2, ENC_BIG_ENDIAN); ++ if (transmission_power_value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission power value [0..10000]"); ++ } ++} ++static void dissect_hi_dci0_dci_ul_rel10_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Cross carrier scheduling flag ++ guint8 cross_carrier_scheduling_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_cross_carrier_scheduling_flag, 1, ENC_BIG_ENDIAN); ++ if (cross_carrier_scheduling_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid cross carrier scheduling flag value [0..1]"); ++ } ++ ++ // Carrier indicator ++ guint8 carrier_indicator_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_carrier_indicator, 1, ENC_BIG_ENDIAN); ++ if (carrier_indicator_value > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid carrier indicator value [0..7]"); ++ } ++ ++ // Size of CQI/CSI field ++ guint8 size_of_cqi_csi_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_size_of_cqi_csi_feild, 1, ENC_BIG_ENDIAN); ++ if (size_of_cqi_csi_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid size of cqi/csi field value [0..2]"); ++ } ++ ++ // SRS flag ++ guint8 srs_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_srs_flag, 1, ENC_BIG_ENDIAN); ++ if (srs_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid srs field value [0..1]"); ++ } ++ ++ // SRS request ++ //guint8 srs_request_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ //item = ptvcursor_add(ptvc, hf_nfapi_srs_request, 1, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_srs_request, 1, ENC_BIG_ENDIAN); ++ ++ // Resource allocation flag ++ guint8 resource_allocation_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_resource_allocation_flag, 1, ENC_BIG_ENDIAN); ++ if (resource_allocation_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid resource allocation flag value [0..1]"); ++ } ++ ++ // Resource allocation type ++ guint8 resource_alloction_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_resource_allocation_type, 1, ENC_BIG_ENDIAN); ++ if (resource_alloction_type_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid resource allocation type value [0..1]"); ++ } ++ ++ // Resource block coding ++ ptvcursor_add(ptvc, hf_nfapi_resource_block_coding, 4, ENC_BIG_ENDIAN); ++ ++ // MCS_2 ++ guint8 mcs_2_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mcs_2, 1, ENC_BIG_ENDIAN); ++ if (mcs_2_value > 31) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mcs 2 value [0..31]"); ++ } ++ ++ // New data indication_2 ++ guint8 new_data_indication_2_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_new_data_indication_two, 1, ENC_BIG_ENDIAN); ++ if (new_data_indication_2_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid new data indication 2 value [0..1]"); ++ } ++ ++ // Number of antenna ports ++ guint8 number_of_antenna_ports_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_antenna_ports, 1, ENC_BIG_ENDIAN); ++ if (number_of_antenna_ports_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of antenna ports value [0..2]"); ++ } ++ ++ // TPMI ++ guint8 tpmi_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_tpmi, 1, ENC_BIG_ENDIAN); ++ if (number_of_antenna_ports_value == 2) ++ { ++ if (tpmi_value > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid tpmi value [0..7]"); ++ } ++ } ++ else if (number_of_antenna_ports_value == 4) ++ { ++ if (tpmi_value > 63) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid tpmi value [0..63]"); ++ } ++ } ++ ++ // Total DCI length including padding ++ ptvcursor_add(ptvc, hf_nfapi_total_dci_length_including_padding, 1, ENC_BIG_ENDIAN); ++ ++ // N_UL_RB ++ guint8 n_ul_rb_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_n_ul_rb, 1, ENC_BIG_ENDIAN); ++ if (!(n_ul_rb_value == 6 || n_ul_rb_value == 15 || n_ul_rb_value == 25 || n_ul_rb_value == 50 || ++ n_ul_rb_value == 75 || n_ul_rb_value == 100)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid n ul rb value [6, 15, 25, 50, 75, 100]"); ++ } ++} ++static void dissect_hi_dci0_dci_ul_rel12_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // PSCCH Resource ++ guint8 pscch_resource_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pscch_resource, 1, ENC_BIG_ENDIAN); ++ if (pscch_resource_value > 0x3F) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pscch resource value [0..0x3F]"); ++ } ++ ++ // Time resource pattern ++ guint8 time_resource_pattern_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_time_resource_pattern, 1, ENC_BIG_ENDIAN); ++ if (time_resource_pattern_value > 0x7F) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid time resource pattern value [0..0x7F]"); ++ } ++ ++} ++static void dissect_hi_dci0_mdpcch_dci_ul_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // MPDCCH Narrowband ++ guint8 mpdcch_narrowband_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mpdcch_narrowband, 1, ENC_BIG_ENDIAN); ++ if (mpdcch_narrowband_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mpdcch narrowband value [0..15]"); ++ } ++ ++ // Number of PRB pairs ++ guint8 number_of_prb_pairs_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_prb_pairs, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_prb_pairs_value == 2 || number_of_prb_pairs_value == 4 || number_of_prb_pairs_value == 6)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of prb pairs value [2, 4, 6]"); ++ } ++ ++ // Resource Block Assignment ++ guint8 resource_block_assignment_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_resource_block_assignment, 1, ENC_BIG_ENDIAN); ++ if (resource_block_assignment_value > 14) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid resource block assignment value [0..14]"); ++ } ++ ++ // MPDCCH transmission type ++ guint8 mpdcch_transmission_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mpdcch_transmission_type, 1, ENC_BIG_ENDIAN); ++ if (mpdcch_transmission_type_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mpdcch transmission type value [0..1]"); ++ } ++ ++ // Start symbol ++ guint8 start_symbol_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_start_symbol, 1, ENC_BIG_ENDIAN); ++ if (!(start_symbol_value >= 1 && start_symbol_value <=4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid start symbol value [0..1]"); ++ } ++ ++ // ECCE index ++ guint8 ecce_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ecce_index, 1, ENC_BIG_ENDIAN); ++ if (ecce_index_value > 22) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ecce index value [0..22]"); ++ } ++ ++ // Aggregation level ++ guint8 aggregation_level_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_aggregation_level, 1, ENC_BIG_ENDIAN); ++ if (!(aggregation_level_value == 2 || aggregation_level_value == 4 || aggregation_level_value == 8 || ++ aggregation_level_value == 16 || aggregation_level_value == 24)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid aggregation level value [2, 4, 8, 16, 24]"); ++ } ++ ++ // RNTI type ++ guint8 rnti_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mpdcch_rnti_type, 1, ENC_BIG_ENDIAN); ++ if (!(rnti_type_value == 0 || rnti_type_value == 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rnti type value [0, 4]"); ++ } ++ ++ // RNTI ++ guint16 rnti_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_rnti, 2, ENC_BIG_ENDIAN); ++ if (rnti_value < 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rnti value [1..65535]"); ++ } ++ ++ // CEMode ++ guint8 cemode_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ce_mode, 1, ENC_BIG_ENDIAN); ++ if (!(cemode_value == 1 || cemode_value == 2)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid cemode value [1,2]"); ++ } ++ ++ // DMRS scrambling init ++ guint16 drms_scrambling_init_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_drms_scrambling_init, 2, ENC_BIG_ENDIAN); ++ if (drms_scrambling_init_value < 503) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid drms scrambling init value [0..503]"); ++ } ++ ++ // Initial transmission SF (io) ++ guint16 initial_transmission_sf_io_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_initial_transmission_sf, 2, ENC_BIG_ENDIAN); ++ if (!(initial_transmission_sf_io_value <= 10239 || initial_transmission_sf_io_value == 0xFFFF)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid initial transmission sf io value [0..10239, 0xFFFF]"); ++ } ++ ++ // Transmission power ++ guint16 transmission_power_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_transmission_power, 2, ENC_BIG_ENDIAN); ++ if (transmission_power_value > 10000) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid transmission power value [0..10000]"); ++ } ++ ++ // DCI format ++ guint8 dci_format_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mpdcch_ul_dci_format, 1, ENC_BIG_ENDIAN); ++ if (!(dci_format_value == 1 || dci_format_value == 2 || dci_format_value == 4 || dci_format_value == 5)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid dci format value [1, 2, 4, 5]"); ++ } ++ ++ // Resource block start ++ guint8 resource_block_start_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_resource_block_start, 1, ENC_BIG_ENDIAN); ++ if (resource_block_start_value > 99) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid resource block start value [0..99]"); ++ } ++ ++ // Number of resource blocks ++ guint8 number_of_resource_blocks_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_resource_blocks, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_resource_blocks_value >= 1 && number_of_resource_blocks_value <= 6)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of resource blocks value [1..6]"); ++ } ++ ++ // MCS ++ guint8 mcs_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_mcs, 1, ENC_BIG_ENDIAN); ++ if (mcs_value > 15) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mcs value [0..15]"); ++ } ++ ++ // PUSCH repetition levels ++ guint8 pusch_repetition_levels_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_pusch_repetition_levels, 1, ENC_BIG_ENDIAN); ++ if (dci_format_value == 4) ++ { ++ if (!(pusch_repetition_levels_value >= 1 && pusch_repetition_levels_value <= 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pusch repetition levels value [1..4]"); ++ } ++ } ++ else if (dci_format_value == 5) ++ { ++ if (!(pusch_repetition_levels_value >= 1 && pusch_repetition_levels_value <= 8)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pusch repetition levels value [1..8]"); ++ } ++ } ++ ++ // Frequency hopping flag ++ guint8 frequency_hopping_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_frequency_hopping_flag, 1, ENC_BIG_ENDIAN); ++ if (frequency_hopping_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid frequency hopping flag value [0..1]"); ++ } ++ ++ // New Data indication ++ guint8 new_data_indication_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_new_data_indication, 1, ENC_BIG_ENDIAN); ++ if (new_data_indication_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid new data indication value [0..1]"); ++ } ++ ++ // HARQ process ++ guint8 harq_process_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_process, 1, ENC_BIG_ENDIAN); ++ if (harq_process_value > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq process value [0..7]"); ++ } ++ ++ // Redundancy version ++ guint8 redundancy_version_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_redundancy_version, 1, ENC_BIG_ENDIAN); ++ if (redundancy_version_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid redundancy version value [0..3]"); ++ } ++ ++ // TPC ++ guint8 tpc_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_tpc, 1, ENC_BIG_ENDIAN); ++ if (tpc_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid tpc value [0..3]"); ++ } ++ ++ // CSI request ++ guint8 csi_request_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_csi_request, 1, ENC_BIG_ENDIAN); ++ if (csi_request_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid csi request value [0..1]"); ++ } ++ ++ // UL index ++ guint8 ul_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ul_index, 1, ENC_BIG_ENDIAN); ++ if (ul_index_value > 3) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ul index value [0..3]"); ++ } ++ ++ // DAI presence flag ++ guint8 dai_presence_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_dai_presence_flag, 1, ENC_BIG_ENDIAN); ++ if (dai_presence_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid dai presence value [0..1]"); ++ } ++ ++ // DL assignment index ++ guint8 dl_assignment_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_dl_assignment_index, 1, ENC_BIG_ENDIAN); ++ if (!(dl_assignment_value >=1 && dl_assignment_value <= 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid dl assignment value [1, 2, 3, 4]"); ++ } ++ ++ // SRS request ++ guint8 srs_request_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_srs_request, 1, ENC_BIG_ENDIAN); ++ if (srs_request_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid srs request value [0..1]"); ++ } ++ ++ // DCI subframe repetition number ++ guint8 dci_subframe_repetition_number_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_dci_subframe_repetition_number, 1, ENC_BIG_ENDIAN); ++ if (!(dci_subframe_repetition_number_value >= 1 && dci_subframe_repetition_number_value <= 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid dci subframe repetition number value [1..4]"); ++ } ++ ++ //TPC bitmap ++ ptvcursor_add(ptvc, hf_nfapi_tpc_bitmap, 4, ENC_BIG_ENDIAN); ++ ++ // Total DCI length including padding ++ ptvcursor_add(ptvc, hf_nfapi_total_dci_length_include_padding, 1, ENC_BIG_ENDIAN); ++ ++ // Number of TX Antenna ports ++ guint8 count = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_tx_antenna_ports, 1, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "TX Antenna Ports", ett_nfapi_tx_antenna_ports, count, dissect_precoding_value); ++} ++static void dissect_rx_ue_info_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Handle ++ ptvcursor_add(ptvc, hf_nfapi_handle, 4, ENC_BIG_ENDIAN); ++ ++ // RNTI ++ guint16 rnti_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_rnti, 2, ENC_BIG_ENDIAN); ++ if (rnti_value < 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rnti value [1..65535]"); ++ } ++} ++static void dissect_rx_indication_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Length ++ ptvcursor_add(ptvc, hf_nfapi_length, 2, ENC_BIG_ENDIAN); ++ ++ // Data offset ++ ptvcursor_add(ptvc, hf_nfapi_data_offset, 2, ENC_BIG_ENDIAN); ++ ++ // UL_CQI ++ ptvcursor_add(ptvc, hf_nfapi_ul_cqi, 1, ENC_BIG_ENDIAN); ++ ++ // Timing advance ++ guint16 timing_advance_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_timing_advance, 2, ENC_BIG_ENDIAN); ++ if (timing_advance_value > 63) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid timing advance value [0..63]"); ++ } ++} ++static void dissect_rx_indication_rel9_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Timing advance R9 ++ guint16 timing_advance_r9_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_timing_advance_r9, 2, ENC_BIG_ENDIAN); ++ if (timing_advance_r9_value > 7690) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid timing advance r9 value [0..7690]"); ++ } ++ ++} ++static void dissect_harq_indication_data_bundling_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ guint8 value_0 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_data_value_0, 1, ENC_BIG_ENDIAN); ++ if (!(value_0 >= 1 && value_0 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value 0 [1..7]"); ++ } ++ ++ guint8 value_1 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_data_value_1, 1, ENC_BIG_ENDIAN); ++ if (!(value_1 >= 1 && value_1 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value 1 [1..7]"); ++ } ++} ++static void dissect_harq_indication_data_format_1a_1b_bundling_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 value_0 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_harq_data_value_0, 1, ENC_BIG_ENDIAN); ++ if (!(value_0 >= 1 && value_0 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value 0 [1..7]"); ++ } ++} ++static void dissect_harq_indication_data_multplexing_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ guint8 value_0 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_data_value_0, 1, ENC_BIG_ENDIAN); ++ if (!(value_0 >= 1 && value_0 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value 0 [1..7]"); ++ } ++ ++ guint8 value_1 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_data_value_1, 1, ENC_BIG_ENDIAN); ++ if (!(value_1 >= 1 && value_1 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value 1 [1..7]"); ++ } ++ ++ guint8 value_2 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_data_value_2, 1, ENC_BIG_ENDIAN); ++ if (!(value_2 >= 1 && value_2 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value 2 [1..7]"); ++ } ++ ++ guint8 value_3 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_data_value_3, 1, ENC_BIG_ENDIAN); ++ if (!(value_3 >= 1 && value_3 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value 3 [1..7]"); ++ } ++ ++} ++static void dissect_harq_indication_data_format_1a_1b_multplexing_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 value_0 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_harq_data_value_0, 1, ENC_BIG_ENDIAN); ++ if (!(value_0 >= 1 && value_0 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value 0 [1..7]"); ++ } ++} ++static void dissect_harq_indication_data_special_bundling_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 value_0 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_harq_data_value_0_special, 1, ENC_BIG_ENDIAN); ++ if (value_0 > 4) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value 0 [0..4]"); ++ } ++} ++static void dissect_harq_indication_data_format_1a_1b_special_bundling_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 value_0 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_harq_data_value_0_special, 1, ENC_BIG_ENDIAN); ++ if (value_0 > 4) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value 0 [0..4]"); ++ } ++} ++static void dissect_harq_indication_data_channel_selection_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 value_0 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_harq_data_value_0, 1, ENC_BIG_ENDIAN); ++ if (!(value_0 >= 1 && value_0 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value 0 [1..7]"); ++ } ++} ++static void dissect_harq_indication_data_format_3_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 value_0 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_harq_data_value_0, 1, ENC_BIG_ENDIAN); ++ if (!(value_0 >= 1 && value_0 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value 0 [1..7]"); ++ } ++} ++static void dissect_harq_indication_data_format_4_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 value_0 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_harq_data_value_0, 1, ENC_BIG_ENDIAN); ++ if (!(value_0 >= 1 && value_0 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value 0 [1..7]"); ++ } ++} ++static void dissect_harq_indication_data_format_5_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 value_0 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_harq_data_value_0, 1, ENC_BIG_ENDIAN); ++ if (!(value_0 >= 1 && value_0 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid value 0 [1..7]"); ++ } ++} ++static void dissect_harq_indication_rel8_tdd_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ guint8 mode = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_tdd_harq_mode, 1, ENC_BIG_ENDIAN); ++ if (mode > 4) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mode value [0..4]"); ++ } ++ ++ guint8 number_of_ack_nack_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_ack_nack, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_ack_nack_value >= 1 && number_of_ack_nack_value <= 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack nack value [1..4]"); ++ } ++ ++ switch (mode) ++ { ++ case 0: ++ { ++ dissect_harq_indication_data_bundling_value(ptvc, pinfo); ++ break; ++ } ++ case 1: ++ { ++ dissect_harq_indication_data_multplexing_value(ptvc, pinfo); ++ break; ++ } ++ case 2: ++ { ++ dissect_harq_indication_data_special_bundling_value(ptvc, pinfo); ++ break; ++ } ++ }; ++} ++static void dissect_harq_indication_rel9_later_tdd_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 i; ++ proto_item* item; ++ ++ guint8 mode = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_tdd_harq_mode, 1, ENC_BIG_ENDIAN); ++ if (mode > 4) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mode value [0..4]"); ++ } ++ ++ guint8 count = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_ack_nack, 1, ENC_BIG_ENDIAN); ++ if (mode == 0 || mode == 1) ++ { ++ if (!(count >= 1 && count <= 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack nack value [1..4]"); ++ } ++ } ++ else if (mode == 3) ++ { ++ if (!(count >= 1 && count <= 8)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack nack value [1..8]"); ++ } ++ } ++ else if (mode == 4) ++ { ++ if (!(count >= 1 && count <= 21)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack nack value [1..21]"); ++ } ++ } ++ ++ ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_harq_ack_nack_data, "ACK/NACK Data"); ++ ++ for (i = 0; i < count; ++i) ++ { ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_harq_ack_nack_data, "[%d]", i); ++ ++ switch (mode) ++ { ++ case 0: ++ { ++ dissect_harq_indication_data_format_1a_1b_bundling_value(ptvc, pinfo); ++ break; ++ } ++ case 1: ++ { ++ dissect_harq_indication_data_format_1a_1b_multplexing_value(ptvc, pinfo); ++ break; ++ } ++ case 2: ++ { ++ dissect_harq_indication_data_format_1a_1b_special_bundling_value(ptvc, pinfo); ++ break; ++ } ++ case 3: ++ { ++ dissect_harq_indication_data_channel_selection_value(ptvc, pinfo); ++ break; ++ } ++ case 4: ++ { ++ dissect_harq_indication_data_format_3_value(ptvc, pinfo); ++ break; ++ } ++ }; ++ ++ ptvcursor_pop_subtree(ptvc); ++ } ++ ++ ptvcursor_pop_subtree(ptvc); ++} ++static void dissect_harq_indication_rel13_later_tdd_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 i = 0; ++ proto_item* item; ++ ++ guint8 mode = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_tdd_harq_mode, 1, ENC_BIG_ENDIAN); ++ if (mode > 6) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid mode value [0..6]"); ++ } ++ ++ ++ guint16 count = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_ack_nack, 2, ENC_BIG_ENDIAN); ++ if (mode == 0 || mode == 1) ++ { ++ if (!(count >= 1 && count <= 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack nack value [1..4]"); ++ } ++ } ++ else if (mode == 3) ++ { ++ if (!(count >= 1 && count <= 8)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack nack value [1..8]"); ++ } ++ } ++ else if (mode == 4) ++ { ++ if (!(count >= 1 && count <= 21)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack nack value [1..21]"); ++ } ++ } ++ else if (mode == 5 || mode == 6) ++ { ++ if (count < 22) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack nack value [>= 22]"); ++ } ++ ++ } ++ ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_harq_ack_nack_data, "ACK/NACK Data"); ++ ++ for (i = 0; i < count; ++i) ++ { ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_harq_ack_nack_data, "[%d]", i); ++ ++ switch (mode) ++ { ++ case 0: ++ { ++ dissect_harq_indication_data_format_1a_1b_bundling_value(ptvc, pinfo); ++ break; ++ } ++ case 1: ++ { ++ dissect_harq_indication_data_format_1a_1b_multplexing_value(ptvc, pinfo); ++ break; ++ } ++ case 2: ++ { ++ dissect_harq_indication_data_special_bundling_value(ptvc, pinfo); ++ break; ++ } ++ case 3: ++ { ++ dissect_harq_indication_data_channel_selection_value(ptvc, pinfo); ++ break; ++ } ++ case 4: ++ { ++ dissect_harq_indication_data_format_3_value(ptvc, pinfo); ++ break; ++ } ++ case 5: ++ { ++ dissect_harq_indication_data_format_4_value(ptvc, pinfo); ++ break; ++ } ++ case 6: ++ { ++ dissect_harq_indication_data_format_5_value(ptvc, pinfo); ++ break; ++ } ++ }; ++ ++ ptvcursor_pop_subtree(ptvc); ++ } ++ ++ ptvcursor_pop_subtree(ptvc); ++} ++static void dissect_harq_indication_rel8_fdd_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ guint8 harq_tb_1 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_tb_1, 1, ENC_BIG_ENDIAN); ++ if (!(harq_tb_1 >= 1 && harq_tb_1 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq tb 1 [1..7]"); ++ } ++ ++ guint8 harq_tb_2 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_harq_tb_2, 1, ENC_BIG_ENDIAN); ++ if (!(harq_tb_2 >= 1 && harq_tb_2 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq tb 2 [1..7]"); ++ } ++ ++} ++static void dissect_harq_tb_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint8 harq_tb_1 = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_harq_tb_n, 1, ENC_BIG_ENDIAN); ++ if (!(harq_tb_1 >= 1 && harq_tb_1 <= 7)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq tb n [1..7]"); ++ } ++} ++static void dissect_harq_indication_rel9_later_fdd_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Mode ++ guint8 harq_mode_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_fdd_harq_mode, 1, ENC_BIG_ENDIAN); ++ if (harq_mode_value > 2) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq mode value [0..2]"); ++ } ++ ++ // Number of ACK/NACK ++ guint8 count = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_ack_nack, 1, ENC_BIG_ENDIAN); ++ ++ if (harq_mode_value == 0) ++ { ++ if (!(count >=1 && count <= 2)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack/nack value [1..2]"); ++ } ++ } ++ else if (harq_mode_value == 1) ++ { ++ if (!(count >= 1 && count <= 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack/nack value [1..4]"); ++ } ++ ++ } ++ else if (harq_mode_value == 2) ++ { ++ if (!(count >= 1 && count <= 10)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack/nack value [1..10]"); ++ } ++ ++ } ++ ++ dissect_array_value(ptvc, pinfo, "HARQ TB List", ett_nfapi_harq_data, count, dissect_harq_tb_value); ++} ++static void dissect_harq_indication_rel13_later_fdd_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Mode ++ guint8 harq_mode_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_fdd_harq_mode, 1, ENC_BIG_ENDIAN); ++ if (harq_mode_value > 4) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid harq mode value [0..4]"); ++ } ++ ++ // Number of ACK/NACK ++ guint16 count = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_ack_nack, 2, ENC_BIG_ENDIAN); ++ ++ if (harq_mode_value == 0) ++ { ++ if (!(count >= 1 && count <= 2)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack/nack value [1..2]"); ++ } ++ } ++ else if (harq_mode_value == 1) ++ { ++ if (!(count >= 1 && count <= 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack/nack value [1..4]"); ++ } ++ ++ } ++ else if (harq_mode_value == 2) ++ { ++ if (!(count >= 1 && count <= 10)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack/nack value [1..10]"); ++ } ++ } ++ else if (harq_mode_value == 3 || harq_mode_value == 4) ++ { ++ if (count < 22) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of ack/nack value [>= 22]"); ++ } ++ } ++ ++ dissect_array_value(ptvc, pinfo, "HARQ TB List", ett_nfapi_harq_data, count, dissect_harq_tb_value); ++} ++static void dissect_ul_cqi_information_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // UL_CQI ++ ptvcursor_add(ptvc, hf_nfapi_ul_cqi, 1, ENC_BIG_ENDIAN); ++ ++ // Channel ++ guint8 channel_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_channel, 1, ENC_BIG_ENDIAN); ++ if (channel_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid channel value [0..1]"); ++ } ++} ++static void dissect_crc_indication_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // CRC Flag ++ guint8 crc_flag_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_crc_flag, 1, ENC_BIG_ENDIAN); ++ if (crc_flag_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid crc flag value [0..1]"); ++ } ++} ++static void dissect_rx_cqi_indication_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ //Length ++ ptvcursor_add(ptvc, hf_nfapi_length, 2, ENC_BIG_ENDIAN); ++ ++ // Data Offset ++ ptvcursor_add(ptvc, hf_nfapi_data_offset, 2, ENC_BIG_ENDIAN); ++ ++ // UL_CQI ++ ptvcursor_add(ptvc, hf_nfapi_ul_cqi, 1, ENC_BIG_ENDIAN); ++ ++ // RI ++ guint8 ri_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_ri, 1, ENC_BIG_ENDIAN); ++ if (ri_value > 8) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ri value [0..8]"); ++ } ++ ++ // Timing Advance ++ guint16 timing_advance_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_timing_advance, 2, ENC_BIG_ENDIAN); ++ if (timing_advance_value > 8) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid timing advance value [0..63]"); ++ } ++} ++static void dissect_ri_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // RI ++ guint8 ri_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_ri, 1, ENC_BIG_ENDIAN); ++ if (ri_value > 8) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ri value [0..8]"); ++ } ++} ++static void dissect_rx_cqi_indication_rel9_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Length ++ ptvcursor_add(ptvc, hf_nfapi_length, 2, ENC_BIG_ENDIAN); ++ ++ // Data Offset ++ ptvcursor_add(ptvc, hf_nfapi_data_offset, 2, ENC_BIG_ENDIAN); ++ ++ // UL_CQI ++ ptvcursor_add(ptvc, hf_nfapi_ul_cqi, 1, ENC_BIG_ENDIAN); ++ ++ // Number of CC reported ++ guint8 count = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_cc_reported, 1, ENC_BIG_ENDIAN); ++ if (!(count >= 1 && count <= 5)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of CC reported value [1..5]"); ++ } ++ ++ dissect_array_value(ptvc, pinfo, "CC List", ett_nfapi_cc, count, dissect_ri_value); ++ ++ // Timing Advance ++ guint16 timing_advance_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_timing_advance, 2, ENC_BIG_ENDIAN); ++ if (timing_advance_value > 63) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid timing advance value [0..63]"); ++ } ++ ++ // Timing Advance R9 ++ guint16 timing_advance_r9_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_timing_advance_r9, 2, ENC_BIG_ENDIAN); ++ if (timing_advance_r9_value > 7690) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid timing advance value [0..7690]"); ++ } ++} ++static void dissect_rach_indication_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // RNTI ++ guint16 rnti_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_rnti, 2, ENC_BIG_ENDIAN); ++ if (rnti_value < 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rnti value [1..65535]"); ++ } ++ ++ // Preamble ++ guint8 preamble_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_preamble, 1, ENC_BIG_ENDIAN); ++ if (preamble_value > 63) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid preamble value [0..63]"); ++ } ++ ++ // Timing Advance ++ guint16 timing_advance_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_timing_advance, 2, ENC_BIG_ENDIAN); ++ if (timing_advance_value > 1282) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid timing advance value [0..1282]"); ++ } ++ ++} ++static void dissect_rach_indication_rel9_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Timing Advance R9 ++ guint16 timing_advance_r9_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_timing_advance_r9, 2, ENC_BIG_ENDIAN); ++ if (timing_advance_r9_value > 7690) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid timing advance value [0..7690]"); ++ } ++} ++static void dissect_rach_indication_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // RACH resource type ++ guint8 rach_resource_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_rach_resource_type, 1, ENC_BIG_ENDIAN); ++ if (rach_resource_type_value > 4) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid rach resource type value [0..4]"); ++ } ++} ++static void dissect_snr_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // SNR ++ ptvcursor_add(ptvc, hf_nfapi_snr, 1, ENC_BIG_ENDIAN); ++} ++static void dissect_srs_indication_rel8_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Doppler estimation ++ ptvcursor_add(ptvc, hf_nfapi_doppler_estimation, 2, ENC_BIG_ENDIAN); ++ ++ // Timing Advance ++ guint16 timing_advance_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_timing_advance, 2, ENC_BIG_ENDIAN); ++ if (timing_advance_value > 1282) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid timing advance value [0..1282]"); ++ } ++ ++ // Number of resource blocks ++ guint8 count = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_resource_blocks, 1, ENC_BIG_ENDIAN); ++ ++ // RB start ++ ptvcursor_add(ptvc, hf_nfapi_rb_start, 1, ENC_BIG_ENDIAN); ++ ++ ++ dissect_array_value(ptvc, pinfo, "RB List", ett_nfapi_rbs, count, dissect_snr_value); ++} ++static void dissect_srs_indication_rel9_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Timing Advance R9 ++ guint16 timing_advance_r9_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_timing_advance_r9, 2, ENC_BIG_ENDIAN); ++ if (timing_advance_r9_value > 7690) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid timing advance value [0..7690]"); ++ } ++} ++static void dissect_srs_indication_rel10_tdd_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // UpPTS Symbol ++ guint8 uppts_symbol_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_up_pts_symbol, 1, ENC_BIG_ENDIAN); ++ if (uppts_symbol_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid up pts symbol value [0..1]"); ++ } ++ ++} ++static void dissect_tdd_channel_measurement_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint16 i = 0; ++ guint16 j = 0; ++ ++ // numPRBperSubband ++ ptvcursor_add(ptvc, hf_nfapi_number_prb_per_subband, 1, ENC_BIG_ENDIAN); ++ ++ // Number of subbands ++ guint8 num_subbands = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_subbands, 1, ENC_BIG_ENDIAN); ++ ++ // numAntennas ++ guint8 num_phy_ant = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_antennas, 1, ENC_BIG_ENDIAN); ++ ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_subbands, "Subbands"); ++ ++ for (i = 0; i < num_subbands; ++i) ++ { ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_subbands, "[%d]", i); ++ ++ // subbandIndex ++ ptvcursor_add(ptvc, hf_nfapi_subband_index, 1, ENC_BIG_ENDIAN); ++ ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_antennas, "Physical Antennas"); ++ ++ for (j = 0; j < num_phy_ant; ++j) ++ { ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_antennas, "[%d]", j); ++ ++ // Channel ++ ptvcursor_add(ptvc, hf_nfapi_channel_coefficient, 2, ENC_BIG_ENDIAN); ++ ++ ptvcursor_pop_subtree(ptvc); ++ } ++ ++ ptvcursor_pop_subtree(ptvc); ++ ++ ptvcursor_pop_subtree(ptvc); ++ } ++ ++ ptvcursor_pop_subtree(ptvc); ++} ++static void dissect_srs_indication_rel11_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ //UL_RTOA ++ guint16 ul_rtoa_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_ul_rtoa, 2, ENC_BIG_ENDIAN); ++ if (ul_rtoa_value > 4800) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid ul rtoa value [0..4800]"); ++ } ++} ++static void dissect_lbt_dl_config_request_pdsch_req_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Handle ++ ptvcursor_add(ptvc, hf_nfapi_handle, 4, ENC_BIG_ENDIAN); ++ ++ // nCCA ++ ptvcursor_add(ptvc, hf_nfapi_mp_cca, 4, ENC_BIG_ENDIAN); ++ ++ // NCCA ++ ptvcursor_add(ptvc, hf_nfapi_n_cca, 4, ENC_BIG_ENDIAN); ++ ++ // Offset ++ guint32 ul_rtoa_value = tvb_get_guint32(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), ENC_BIG_ENDIAN); ++ item = ptvcursor_add(ptvc, hf_nfapi_offset, 4, ENC_BIG_ENDIAN); ++ if (ul_rtoa_value > 999) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid offset value [0..999]"); ++ } ++ ++ // LTE TXOP SF ++ ptvcursor_add(ptvc, hf_nfapi_lte_txop_sf, 4, ENC_BIG_ENDIAN); ++ ++ // TXOP SFN/SF End ++ ptvcursor_add(ptvc, hf_nfapi_txop_sfn_sf_end, 2, ENC_BIG_ENDIAN); ++ ++ // LBT mode ++ guint32 lbt_mode = tvb_get_guint32(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), ENC_BIG_ENDIAN); ++ item = ptvcursor_add(ptvc, hf_nfapi_lbt_mode, 4, ENC_BIG_ENDIAN); ++ if (lbt_mode > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid offset value [0..1]"); ++ } ++} ++static void dissect_lbt_dl_config_request_drs_req_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Handle ++ ptvcursor_add(ptvc, hf_nfapi_handle, 4, ENC_BIG_ENDIAN); ++ ++ // Offset ++ guint32 ul_rtoa_value = tvb_get_guint32(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), ENC_BIG_ENDIAN); ++ item = ptvcursor_add(ptvc, hf_nfapi_offset, 4, ENC_BIG_ENDIAN); ++ if (ul_rtoa_value > 999) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid offset value [0..999]"); ++ } ++ ++ // SFN/SF End ++ ptvcursor_add(ptvc, hf_nfapi_sfn_sf_end, 2, ENC_BIG_ENDIAN); ++ ++ // LBT mode ++ guint32 lbt_mode = tvb_get_guint32(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), ENC_BIG_ENDIAN); ++ item = ptvcursor_add(ptvc, hf_nfapi_lbt_mode, 4, ENC_BIG_ENDIAN); ++ if (lbt_mode > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid offset value [0..1]"); ++ } ++} ++static void dissect_lbt_dl_config_request_pdsch_resp_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Handle ++ ptvcursor_add(ptvc, hf_nfapi_handle, 4, ENC_BIG_ENDIAN); ++ ++ // result ++ guint32 result_value = tvb_get_guint32(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), ENC_BIG_ENDIAN); ++ item = ptvcursor_add(ptvc, hf_nfapi_result, 4, ENC_BIG_ENDIAN); ++ if (result_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid result value [0..1]"); ++ } ++ ++ // LTE TXOP symbols ++ ptvcursor_add(ptvc, hf_nfapi_txop_symbols, 4, ENC_BIG_ENDIAN); ++ ++ // Initial Partial SF ++ guint32 initial_partial_sf_value = tvb_get_guint32(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), ENC_BIG_ENDIAN); ++ item = ptvcursor_add(ptvc, hf_nfapi_initial_partial_sf, 4, ENC_BIG_ENDIAN); ++ if (initial_partial_sf_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid initial partial sf value [0..1]"); ++ } ++} ++static void dissect_lbt_dl_config_request_drs_resp_rel13_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // Handle ++ ptvcursor_add(ptvc, hf_nfapi_handle, 4, ENC_BIG_ENDIAN); ++ ++ // result ++ guint32 result_value = tvb_get_guint32(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), ENC_BIG_ENDIAN); ++ item = ptvcursor_add(ptvc, hf_nfapi_result, 4, ENC_BIG_ENDIAN); ++ if (result_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid result value [0..1]"); ++ } ++} ++static void dissect_tx_pdu(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // PDU length ++ guint16 len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pdu_length, 2, ENC_BIG_ENDIAN); ++ ++ // PDU index ++ ptvcursor_add(ptvc, hf_nfapi_pdu_index, 2, ENC_BIG_ENDIAN); ++ ++ // PDU#N ++ ptvcursor_add(ptvc, hf_nfapi_pdu, len, ENC_NA); ++} ++static void dissect_tx_request_body_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Number of PDUs ++ guint16 num_pdu = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_pdus, 2, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "TX PDU List", ett_nfapi_tx_request_pdu_list, num_pdu, dissect_tx_pdu); ++} ++static void dissect_harq_indication_pdu(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Instance Length ++ guint16 instance_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_instance_length, 2, ENC_BIG_ENDIAN); ++ ++ guint instance_end = (ptvcursor_current_offset(ptvc) + instance_len - 2); ++ dissect_tlv_list(ptvc, pinfo, instance_end); ++} ++static void dissect_harq_indication_body_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Number of HARQs ++ guint16 num_pdu = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_harqs, 2, ENC_BIG_ENDIAN); ++ ++ ++ dissect_array_value(ptvc, pinfo, "HARQ PDU List", ett_nfapi_harq_indication_pdu_list, num_pdu, dissect_harq_indication_pdu); ++} ++static void dissect_crc_indication_pdu(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Instance Length ++ guint16 instance_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_instance_length, 2, ENC_BIG_ENDIAN); ++ ++ guint instance_end = (ptvcursor_current_offset(ptvc) + instance_len - 2); ++ dissect_tlv_list(ptvc, pinfo, instance_end); ++} ++static void dissect_crc_indication_body_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Number of CRCs ++ guint16 num_pdu = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_crcs, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "CRC PDU List", ett_nfapi_crc_indication_pdu_list, num_pdu, dissect_crc_indication_pdu); ++} ++static void dissect_sr_indication_pdu(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Instance Length ++ guint16 instance_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_instance_length, 2, ENC_BIG_ENDIAN); ++ ++ guint instance_end = (ptvcursor_current_offset(ptvc) + instance_len - 2); ++ dissect_tlv_list(ptvc, pinfo, instance_end); ++} ++static void dissect_rx_sr_indication_body_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Number of SRs ++ guint16 num_pdu = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_srs, 2, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "SR PDU List", ett_nfapi_sr_indication_pdu_list, num_pdu, dissect_sr_indication_pdu); ++} ++static void dissect_cqi_indication_pdu(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Instance Length ++ guint16 instance_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_instance_length, 2, ENC_BIG_ENDIAN); ++ ++ guint instance_end = (ptvcursor_current_offset(ptvc) + instance_len - 2); ++ dissect_tlv_list(ptvc, pinfo, instance_end); ++} ++static void dissect_rx_cqi_indication_body_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Number of PDUs ++ guint16 num_pdu = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_cqi, 2, ENC_BIG_ENDIAN); ++ ++ guint16* lengths = (guint16*)wmem_alloc0(wmem_packet_scope(), num_pdu * 2); ++ memset(lengths, 0, num_pdu * 2); ++ ++ tvbuff_t* tvb = ptvcursor_tvbuff(ptvc); ++ guint8 tmp_offset = ptvcursor_current_offset(ptvc); ++ ++ int i = 0; ++ for (i = 0; i < num_pdu; ++i) ++ { ++ guint16 instance_len = tvb_get_ntohs(tvb, tmp_offset); ++ tmp_offset += 2; ++ guint8 pdu_end = tmp_offset + instance_len; ++ ++ while (tmp_offset < pdu_end) ++ { ++ guint16 tlv_id = tvb_get_ntohs(tvb, tmp_offset); ++ tmp_offset += 2; ++ guint16 tlv_len = tvb_get_ntohs(tvb, tmp_offset); ++ tmp_offset += 2; ++ ++ if (tlv_id == 0x202F) ++ { ++ lengths[i] = tvb_get_ntohs(tvb, tmp_offset); ++ } ++ else if (tlv_id == 0x2030) ++ { ++ lengths[i] = tvb_get_ntohs(tvb, tmp_offset); ++ } ++ ++ tmp_offset += tlv_len; ++ } ++ } ++ ++ dissect_array_value(ptvc, pinfo, "CQI PDU List", ett_nfapi_cqi_indication_pdu_list, num_pdu, dissect_cqi_indication_pdu); ++ ++ for (i = 0; i < num_pdu; ++i) ++ { ++ ptvcursor_add(ptvc, hf_nfapi_pdu, lengths[i], ENC_NA); ++ } ++} ++static void dissect_preamble_indication_pdu(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Instance Length ++ guint16 instance_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_instance_length, 2, ENC_BIG_ENDIAN); ++ ++ guint instance_end = (ptvcursor_current_offset(ptvc) + instance_len - 2); ++ dissect_tlv_list(ptvc, pinfo, instance_end); ++} ++static void dissect_rach_indication_body_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Number of Preambles ++ guint16 num_pdu = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_preambles, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "Preamble PDU List", ett_nfapi_preamble_indication_pdu_list, num_pdu, dissect_preamble_indication_pdu); ++} ++static void dissect_srs_indication_pdu(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Instance Length ++ guint16 instance_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_instance_length, 2, ENC_BIG_ENDIAN); ++ guint instance_end = (ptvcursor_current_offset(ptvc) + instance_len - 2); ++ dissect_tlv_list(ptvc, pinfo, instance_end); ++} ++static void dissect_srs_indication_body_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Number of UEs ++ guint8 num_pdu = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_srss, 1, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "SRS PDU List", ett_nfapi_srs_indication_pdu_list, num_pdu, dissect_srs_indication_pdu); ++} ++static void dissect_lbt_dl_config_pdu(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // PDU Type ++ guint8 pdu_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_lbt_dl_req_pdu_type, 1, ENC_BIG_ENDIAN); ++ if (pdu_type_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pdu type value [0..1]"); ++ } ++ ++ guint8 size = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pdu_size, 1, ENC_BIG_ENDIAN); ++ guint pdu_end = (ptvcursor_current_offset(ptvc) + size - 2); ++ ++ dissect_tlv_list(ptvc, pinfo, pdu_end); ++} ++static void dissect_lbt_dl_config_request_body_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Number of PDUs ++ guint16 num_pdu = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_number_pdus, 2, ENC_BIG_ENDIAN); ++ if (!(num_pdu >= 1 && num_pdu <= 2)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of pdus value [1..2]"); ++ } ++ ++ dissect_array_value(ptvc, pinfo, "LBT DL PDU List", ett_nfapi_lbt_dl_config_pdu_list, num_pdu, dissect_lbt_dl_config_pdu); ++} ++static void dissect_lbt_dl_indication_pdu(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // PDU Type ++ guint8 pdu_type_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_lbt_dl_ind_pdu_type, 1, ENC_BIG_ENDIAN); ++ if (pdu_type_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid pdu type value [0..1]"); ++ } ++ ++ // PDU Size ++ guint8 size = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pdu_size, 1, ENC_BIG_ENDIAN); ++ guint pdu_end = (ptvcursor_current_offset(ptvc) + size - 2); ++ dissect_tlv_list(ptvc, pinfo, pdu_end); ++} ++static void dissect_lbt_indication_message_body_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Number of PDUs ++ guint16 num_pdu = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_number_pdus, 2, ENC_BIG_ENDIAN); ++ if (!(num_pdu >= 1 && num_pdu <= 2)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of pdus value [1..2]"); ++ } ++ ++ dissect_array_value(ptvc, pinfo, "LBT DL PDU List", ett_nfapi_lbt_dl_indication_pdu_list, num_pdu, dissect_lbt_dl_indication_pdu); ++} ++static void dissect_lte_rssi_request_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Frequency Band Indicator ++ ptvcursor_add(ptvc, hf_nfapi_frequency_band_indicator, 1, ENC_BIG_ENDIAN); ++ ++ // Measurement Period ++ ptvcursor_add(ptvc, hf_nfapi_measurement_period, 2, ENC_BIG_ENDIAN); ++ ++ // Bandwidth ++ guint8 bandwidth_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_bandwidth, 1, ENC_BIG_ENDIAN); ++ if (!(bandwidth_value == 6 || bandwidth_value == 15 || bandwidth_value == 25 || ++ bandwidth_value == 50 || bandwidth_value == 75 || bandwidth_value == 100)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid bandwidth value [6, 15, 25, 50, 75, 100]"); ++ } ++ ++ // Timeout ++ ptvcursor_add(ptvc, hf_nfapi_timeout, 4, ENC_BIG_ENDIAN); ++ ++ // Number of EARFCNs ++ guint8 num_earfcns = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_earfcns, 1, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "EARFCNs", ett_nfapi_earfcn_list, num_earfcns, dissect_earfcn_value); ++} ++static void dissect_uarfcn_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // UARFCN ++ ptvcursor_add(ptvc, hf_nfapi_uarfcn, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_utran_rssi_request_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Frequency Band Indicator ++ ptvcursor_add(ptvc, hf_nfapi_frequency_band_indicator, 1, ENC_BIG_ENDIAN); ++ ++ // Measurement Period ++ ptvcursor_add(ptvc, hf_nfapi_measurement_period, 2, ENC_BIG_ENDIAN); ++ ++ // Timeout ++ ptvcursor_add(ptvc, hf_nfapi_timeout, 4, ENC_BIG_ENDIAN); ++ ++ // Number of UARFCNs ++ guint8 num_uarfcns = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_uarfcns, 1, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "UARFCNs", ett_nfapi_uarfcn_list, num_uarfcns, dissect_uarfcn_value); ++} ++static void dissect_arfcn_dir_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // ARFCN ++ ptvcursor_add(ptvc, hf_nfapi_arfcn, 2, ENC_BIG_ENDIAN); ++ ++ // Direction ++ guint8 direction_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_arfcn_direction, 1, ENC_BIG_ENDIAN); ++ if (direction_value > 1) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid direction value [0..1]"); ++ } ++ ++} ++static void dissect_geran_rssi_request_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Frequency Band Indicator ++ ptvcursor_add(ptvc, hf_nfapi_frequency_band_indicator, 1, ENC_BIG_ENDIAN); ++ ++ // Measurement Period ++ ptvcursor_add(ptvc, hf_nfapi_measurement_period, 2, ENC_BIG_ENDIAN); ++ ++ // Timeout ++ ptvcursor_add(ptvc, hf_nfapi_timeout, 4, ENC_BIG_ENDIAN); ++ ++ // Number of ARFCNs ++ guint8 num_arfcns = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_arfcns, 1, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "ARFCNs", ett_nfapi_arfcn_list, num_arfcns, dissect_arfcn_dir_value); ++} ++static void dissect_rssi_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // RSSI ++ ptvcursor_add(ptvc, hf_nfapi_rssi, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_rssi_indication_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Number of RSSI ++ guint16 num_rssi = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_rssi, 2, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "ARFCNs", ett_nfapi_rssi_list, num_rssi, dissect_rssi_value); ++} ++static void dissect_pci_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // PCI ++ ptvcursor_add(ptvc, hf_nfapi_pci, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_lte_cell_search_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // EARFCN ++ ptvcursor_add(ptvc, hf_nfapi_earfcn, 2, ENC_BIG_ENDIAN); ++ ++ // Measurement Bandwidth ++ ptvcursor_add(ptvc, hf_nfapi_measurement_bandwidth, 1, ENC_BIG_ENDIAN); ++ ++ // Exhaustive Search ++ ptvcursor_add(ptvc, hf_nfapi_exhaustive_search, 1, ENC_BIG_ENDIAN); ++ ++ // Timeout ++ ptvcursor_add(ptvc, hf_nfapi_timeout, 4, ENC_BIG_ENDIAN); ++ ++ // Number of PCI ++ guint8 num_pci = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_pci, 1, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "PCIs", ett_nfapi_pci_list, num_pci, dissect_pci_value); ++} ++static void dissect_psc_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // PSC ++ ptvcursor_add(ptvc, hf_nfapi_psc, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_utran_cell_search_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // UARFCN ++ ptvcursor_add(ptvc, hf_nfapi_uarfcn, 2, ENC_BIG_ENDIAN); ++ ++ // Exhaustive Search ++ ptvcursor_add(ptvc, hf_nfapi_exhaustive_search, 1, ENC_BIG_ENDIAN); ++ ++ // Timeout ++ ptvcursor_add(ptvc, hf_nfapi_timeout, 4, ENC_BIG_ENDIAN); ++ ++ // Number of PSC ++ guint8 num_psc = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_psc, 1, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "PSCs", ett_nfapi_psc_list, num_psc, dissect_psc_value); ++} ++static void dissect_arfcn_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // ARFCN ++ ptvcursor_add(ptvc, hf_nfapi_arfcn, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_geran_cell_search_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Timeout ++ ptvcursor_add(ptvc, hf_nfapi_timeout, 4, ENC_BIG_ENDIAN); ++ ++ // Number of ARFCN ++ guint8 num_arfcn = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_arfcns, 1, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "ARFCNs", ett_nfapi_arfcn_list, num_arfcn, dissect_arfcn_value); ++} ++ ++static void dissect_lte_cell_found_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // PCI ++ ptvcursor_add(ptvc, hf_nfapi_pci, 2, ENC_BIG_ENDIAN); ++ ++ // RSRP ++ ptvcursor_add(ptvc, hf_nfapi_rsrp, 1, ENC_BIG_ENDIAN); ++ ++ // RSRQ ++ ptvcursor_add(ptvc, hf_nfapi_rsrq, 1, ENC_BIG_ENDIAN); ++ ++ // Frequency Offset ++ ptvcursor_add(ptvc, hf_nfapi_frequency_offset, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_lte_cell_search_indication_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Number of LTE Cells Found ++ guint16 num_lte_cells = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_lte_cells_found, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "LTE Cells Found", ett_nfapi_lte_cells_found_list, num_lte_cells, dissect_lte_cell_found_value); ++} ++static void dissect_utran_cell_found_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // PSC ++ ptvcursor_add(ptvc, hf_nfapi_psc, 2, ENC_BIG_ENDIAN); ++ ++ // RSCP ++ ptvcursor_add(ptvc, hf_nfapi_rscp, 1, ENC_BIG_ENDIAN); ++ ++ // EcN0 ++ ptvcursor_add(ptvc, hf_nfapi_enco, 1, ENC_BIG_ENDIAN); ++ ++ // Frequency Offset ++ ptvcursor_add(ptvc, hf_nfapi_frequency_offset, 2, ENC_BIG_ENDIAN); ++} ++static void dissect_utran_cell_search_indication_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Number of UTRAN Cells Found ++ guint16 num_utran_cells = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_utran_cells_found, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "UTRAN Cells Found", ett_nfapi_utran_cells_found_list, num_utran_cells, dissect_utran_cell_found_value); ++} ++static void dissect_geran_cell_found_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // ARFCN ++ ptvcursor_add(ptvc, hf_nfapi_arfcn, 2, ENC_BIG_ENDIAN); ++ ++ // BSIC ++ ptvcursor_add(ptvc, hf_nfapi_bsic, 1, ENC_BIG_ENDIAN); ++ ++ // RxLev ++ ptvcursor_add(ptvc, hf_nfapi_rxlev, 1, ENC_BIG_ENDIAN); ++ ++ // RxQual ++ ptvcursor_add(ptvc, hf_nfapi_rxqual, 1, ENC_BIG_ENDIAN); ++ ++ // Frequency Offset ++ ptvcursor_add(ptvc, hf_nfapi_frequency_offset, 2, ENC_BIG_ENDIAN); ++ ++ // SFN Offset ++ ptvcursor_add(ptvc, hf_nfapi_sfn_offset, 4, ENC_BIG_ENDIAN); ++} ++static void dissect_geran_cell_search_indication_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Number of GSM Cells Found ++ guint16 num_geran_cells = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_geran_cells_found, 2, ENC_BIG_ENDIAN); ++ dissect_array_value(ptvc, pinfo, "GERAN Cells Found", ett_nfapi_geran_cells_found_list, num_geran_cells, dissect_geran_cell_found_value); ++} ++static void dissect_pnf_cell_search_state_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint len = tvb_reported_length_remaining(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pnf_search_state, len, ENC_NA); ++} ++static void dissect_pnf_cell_broadcast_state_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint len = tvb_reported_length_remaining(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_pnf_broadcast_state, len, ENC_NA); ++} ++static void dissect_lte_broadcast_detect_request_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // EARFCN ++ ptvcursor_add(ptvc, hf_nfapi_earfcn, 2, ENC_BIG_ENDIAN); ++ ++ // PCI ++ ptvcursor_add(ptvc, hf_nfapi_pci, 2, ENC_BIG_ENDIAN); ++ ++ // Timeout ++ ptvcursor_add(ptvc, hf_nfapi_timeout, 4, ENC_BIG_ENDIAN); ++} ++static void dissect_utran_broadcast_detect_request_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // UARFCN ++ ptvcursor_add(ptvc, hf_nfapi_uarfcn, 2, ENC_BIG_ENDIAN); ++ ++ // PSC ++ ptvcursor_add(ptvc, hf_nfapi_psc, 2, ENC_BIG_ENDIAN); ++ ++ // Timeout ++ ptvcursor_add(ptvc, hf_nfapi_timeout, 4, ENC_BIG_ENDIAN); ++} ++static void dissect_lte_broadcast_detect_indication_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // Number of Tx Antenna ++ guint8 number_of_tx_antenna_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_number_of_tx_antenna, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_tx_antenna_value == 1 || number_of_tx_antenna_value == 2 || number_of_tx_antenna_value == 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of tx antenna value [1, 2, 4]"); ++ } ++ ++ ++ // MIB Length ++ guint16 mib_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_mib_length, 2, ENC_BIG_ENDIAN); ++ ++ // MIB[MIB Length] ++ ptvcursor_add(ptvc, hf_nfapi_mib, mib_len, ENC_NA); ++ ++ // SFN Offset ++ ptvcursor_add(ptvc, hf_nfapi_sfn_offset, 4, ENC_BIG_ENDIAN); ++} ++static void dissect_utran_broadcast_detect_indication_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // MIB Length ++ guint16 mib_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_mib_length, 2, ENC_BIG_ENDIAN); ++ ++ // MIB[MIB Length] ++ ptvcursor_add(ptvc, hf_nfapi_mib, mib_len, ENC_NA); ++ ++ // SFN Offset ++ ptvcursor_add(ptvc, hf_nfapi_sfn_offset, 4, ENC_BIG_ENDIAN); ++} ++static void dissect_lte_system_information_schedule_request_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // EARFCN ++ ptvcursor_add(ptvc, hf_nfapi_earfcn, 2, ENC_BIG_ENDIAN); ++ ++ // PCI ++ ptvcursor_add(ptvc, hf_nfapi_pci, 2, ENC_BIG_ENDIAN); ++ ++ // Bandwidth ++ guint16 bandwidth_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_bandwidth, 2, ENC_BIG_ENDIAN); ++ if (!(bandwidth_value == 6 || bandwidth_value == 15 || bandwidth_value == 25 || ++ bandwidth_value == 50 || bandwidth_value == 75 || bandwidth_value == 100)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid bandwidth value [6, 15, 25, 50, 75, 100]"); ++ } ++ ++ // PHICH Configuration ++ // todo : phich bit decode ++ ptvcursor_add(ptvc, hf_nfapi_phich_configuration, 1, ENC_BIG_ENDIAN); ++ ++ // Number of Tx Antenna ++ guint8 number_of_tx_antenna_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_tx_antenna, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_tx_antenna_value == 1 || number_of_tx_antenna_value == 2 || number_of_tx_antenna_value == 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of tx antenna value [1, 2, 4]"); ++ } ++ ++ // retryCount ++ ptvcursor_add(ptvc, hf_nfapi_retry_count, 1, ENC_BIG_ENDIAN); ++ ++ // Timeout ++ ptvcursor_add(ptvc, hf_nfapi_timeout, 4, ENC_BIG_ENDIAN); ++} ++static void dissect_lte_system_information_schedule_indication_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // this needs to be SIB 1 ++ guint len = tvb_reported_length_remaining(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_sib1, len, ENC_NA); ++} ++static void dissect_si_periodicity_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ proto_item* item; ++ ++ // SI Periodicity ++ guint8 si_periodicity_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_si_periodicity, 1, ENC_BIG_ENDIAN); ++ if (si_periodicity_value > 7) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid si periodicity value [0..7]"); ++ } ++ ++ // SI Index ++ guint8 si_index_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_si_index, 1, ENC_BIG_ENDIAN); ++ if (si_index_value > 32) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid si index value [0..32]"); ++ } ++} ++ ++static void dissect_lte_system_information_request_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // EARFCN ++ ptvcursor_add(ptvc, hf_nfapi_earfcn, 2, ENC_BIG_ENDIAN); ++ ++ // PCI ++ ptvcursor_add(ptvc, hf_nfapi_pci, 2, ENC_BIG_ENDIAN); ++ ++ // Downlink channel bandwidth ++ guint16 bandwidth_value = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_downlink_channel_bandwidth, 2, ENC_BIG_ENDIAN); ++ if (!(bandwidth_value == 6 || bandwidth_value == 15 || bandwidth_value == 25 || ++ bandwidth_value == 50 || bandwidth_value == 75 || bandwidth_value == 100)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid bandwidth value [6, 15, 25, 50, 75, 100]"); ++ } ++ ++ // PHICH Configuration ++ ptvcursor_add(ptvc, hf_nfapi_phich_configuration, 1, ENC_BIG_ENDIAN); ++ ++ // Number of Tx Antenna ++ guint8 number_of_tx_antenna_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_number_of_tx_antenna, 1, ENC_BIG_ENDIAN); ++ if (!(number_of_tx_antenna_value == 1 || number_of_tx_antenna_value == 2 || number_of_tx_antenna_value == 4)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid number of tx antenna value [1, 2, 4]"); ++ } ++ ++ // Number of SI Periodicity ++ guint8 si_priodicity = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_of_si_periodicity, 1, ENC_BIG_ENDIAN); ++ ++ dissect_array_value(ptvc, pinfo, "Number SI Periodicity", ett_nfapi_si_periodicity_list, si_priodicity, dissect_si_periodicity_value); ++ ++ // SI Window Length ++ guint8 si_window_length_value = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ item = ptvcursor_add(ptvc, hf_nfapi_si_window_length, 1, ENC_BIG_ENDIAN); ++ if (!(si_window_length_value == 1 || si_window_length_value == 2 || si_window_length_value == 5 || si_window_length_value == 10 || ++ si_window_length_value == 15 || si_window_length_value == 20 || si_window_length_value == 40)) ++ { ++ expert_add_info_format(pinfo, item, &ei_invalid_range, "Invalid si window length value [1, 2, 5, 10, 15, 20, 40]"); ++ } ++ ++ // Timeout ++ ptvcursor_add(ptvc, hf_nfapi_timeout, 4, ENC_BIG_ENDIAN); ++} ++static void dissect_utran_system_information_request_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // UARFCN ++ ptvcursor_add(ptvc, hf_nfapi_uarfcn, 2, ENC_BIG_ENDIAN); ++ ++ // PSC ++ ptvcursor_add(ptvc, hf_nfapi_psc, 2, ENC_BIG_ENDIAN); ++ ++ // Timeout ++ ptvcursor_add(ptvc, hf_nfapi_timeout, 4, ENC_BIG_ENDIAN); ++} ++static void dissect_geran_system_information_request_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // ARFCN ++ ptvcursor_add(ptvc, hf_nfapi_arfcn, 2, ENC_BIG_ENDIAN); ++ ++ // BSIC ++ ptvcursor_add(ptvc, hf_nfapi_bsic, 1, ENC_BIG_ENDIAN); ++ ++ // Timeout ++ ptvcursor_add(ptvc, hf_nfapi_timeout, 4, ENC_BIG_ENDIAN); ++} ++static void dissect_lte_system_information_indication_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // SIB Type ++ ptvcursor_add(ptvc, hf_nfapi_sib_type, 1, ENC_BIG_ENDIAN); ++ ++ // SIB Length ++ guint16 sib_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_sib_len, 2, ENC_BIG_ENDIAN); ++ ++ // SIB[SIB Length] ++ ptvcursor_add(ptvc, hf_nfapi_sib, sib_len, ENC_NA); ++} ++static void dissect_utran_system_information_indication_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // SIB Length ++ guint16 sib_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_sib_len, 2, ENC_BIG_ENDIAN); ++ ++ // SIB[SIB Length] ++ ptvcursor_add(ptvc, hf_nfapi_sib, sib_len, ENC_NA); ++} ++static void dissect_geran_system_information_indication_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ // SI Length ++ guint16 si_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_si_len, 2, ENC_BIG_ENDIAN); ++ ++ // SI[SI Length] ++ ptvcursor_add(ptvc, hf_nfapi_si, si_len, ENC_NA); ++} ++ ++static void dissect_rx_indication_body_value(ptvcursor_t * ptvc, packet_info* pinfo _U_); ++ ++// Important the tags must be in numerical order so that they can be indexed correctly ++const tlv_t nfapi_tags[] = ++{ ++ { 0x1000, "PNF Param General", dissect_pnf_param_general_value }, ++ { 0x1001, "PNF PHY", dissect_pnf_phy_value }, ++ { 0x1002, "PNF RF", dissect_pnf_rf_value }, ++ { 0x1003, "PNF PHY RF Config", dissect_pnf_phy_rf_config_value }, ++ { 0x1004, "DL RS Tx power", dissect_dl_rs_tx_power_value }, ++ { 0x1005, "Received interference power", dissect_received_interference_power_value }, ++ { 0x1006, "Thermal noise power", dissect_thermal_noise_power_value }, ++ { 0x1007, "DL RS TX Power measurement", dissect_dl_rs_tx_power_measurement_value }, ++ { 0x1008, "Received Interference power measurement", dissect_received_interference_power_measurement_value }, ++ { 0x1009, "Thermal noise power measurement", dissect_thermal_noise_power_measurement_value }, ++ { 0x100A, "PNF PHY Rel 10", dissect_pnf_phy_rel10_value }, ++ { 0x100B, "PNF PHY Rel 11", dissect_pnf_phy_rel11_value }, ++ { 0x100C, "PNF PHY Rel 12", dissect_pnf_phy_rel12_value }, ++ { 0x100D, "PNF PHY Rel 13", dissect_pnf_phy_rel13_value }, ++}; ++ ++const tlv_t configuration_tags[] = ++{ ++ { 0x0000, NULL, NULL }, ++ { 0x0001, "Subframe config - Duplex Mode", dissect_duplex_mode_value }, ++ { 0x0002, "Subframe config - PCFICH power offset TLV", dissect_pcfich_power_offset_value }, ++ { 0x0003, "Subframe config - P-B", dissect_pb_value }, ++ { 0x0004, "Subframe config - DL cyclic prefix type", dissect_dl_cyclic_prefix_value }, ++ { 0x0005, "Subframe config - UL cyclic prefix type", dissect_ul_cyclic_prefix_value }, ++ { 0x0006, NULL, NULL }, ++ { 0x0007, NULL, NULL }, ++ { 0x0008, NULL, NULL }, ++ { 0x0009, NULL, NULL }, ++ { 0x000A, "RF config - Downlink channel bandwidth", dissect_dl_channel_bandwidth_value }, ++ { 0x000B, "RF config - Uplink channel bandwidth", dissect_ul_channel_bandwidth_value }, ++ { 0x000C, "RF config - Reference signal power", dissect_reference_signal_power_value }, ++ { 0x000D, "RF config - Tx antenna ports", dissect_tx_antenna_ports_value }, ++ { 0x000E, "RF config - Rx Antenna ports", dissect_rx_antenna_ports_value }, ++ { 0x000F, NULL, NULL }, ++ { 0x0010, NULL, NULL }, ++ { 0x0011, NULL, NULL }, ++ { 0x0012, NULL, NULL }, ++ { 0x0013, NULL, NULL }, ++ { 0x0014, "PHICH config - PHICH resource", dissect_phich_resource_value }, ++ { 0x0015, "PHICH config - PHICH duration", dissect_phich_duration_value }, ++ { 0x0016, "PHICH config - PHICH power offset", dissect_phich_power_offset_value }, ++ { 0x0017, NULL, NULL }, ++ { 0x0018, NULL, NULL }, ++ { 0x0019, NULL, NULL }, ++ { 0x001A, NULL, NULL }, ++ { 0x001B, NULL, NULL }, ++ { 0x001C, NULL, NULL }, ++ { 0x001D, NULL, NULL }, ++ { 0x001E, "SCH config - Primary synchronization signal EPRE/EPRERS", dissect_psch_synch_signal_epre_eprers_value }, ++ { 0x001F, "SCH config - Secondary synchronization signal EPRE/EPRERS", dissect_ssch_synch_signal_epre_eprers_value }, ++ { 0x0020, "SCH config - Physical Cell Id", dissect_physical_cell_id_value }, ++ { 0x0021, NULL, NULL }, ++ { 0x0022, NULL, NULL }, ++ { 0x0023, NULL, NULL }, ++ { 0x0024, NULL, NULL }, ++ { 0x0025, NULL, NULL }, ++ { 0x0026, NULL, NULL }, ++ { 0x0027, NULL, NULL }, ++ { 0x0028, "PRACH config - Configuration index", dissect_prach_configuration_index_value }, ++ { 0x0029, "PRACH config - Root sequence index", dissect_prach_root_sequence_index_value }, ++ { 0x002A, "PRACH config - Zero correlation zone configuration", dissect_prach_zero_correlation_zone_configuration_value }, ++ { 0x002B, "PRACH config - High speed flag", dissect_prach_high_speed_flag_value }, ++ { 0x002C, "PRACH config - Frequency offset", dissect_prach_frequency_offset_value }, ++ { 0x002D, NULL, NULL }, ++ { 0x002E, NULL, NULL }, ++ { 0x002F, NULL, NULL }, ++ { 0x0030, NULL, NULL }, ++ { 0x0031, NULL, NULL }, ++ { 0x0032, "PUSCH config - Hopping mode", dissect_pusch_hopping_mode_value }, ++ { 0x0033, "PUSCH config - Hopping offset", dissect_pusch_hopping_offset_value }, ++ { 0x0034, "PUSCH config - Number of sub-bands", dissect_pusch_number_of_subbands_value }, ++ { 0x0035, NULL, NULL }, ++ { 0x0036, NULL, NULL }, ++ { 0x0037, NULL, NULL }, ++ { 0x0038, NULL, NULL }, ++ { 0x0039, NULL, NULL }, ++ { 0x003A, NULL, NULL }, ++ { 0x003B, NULL, NULL }, ++ { 0x003C, "PUCCH config - Delta PUCCH Shift", dissect_pucch_delta_pucch_shift_value }, ++ { 0x003D, "PUCCH config - N_CQI RB", dissect_pucch_n_cqi_rb_value }, ++ { 0x003E, "PUCCH config - N_AN CS", dissect_pucch_n_an_cs_value }, ++ { 0x003F, "PUCCH config - N1Pucch-AN", dissect_pucch_n1_pucch_an_value }, ++ { 0x0040, NULL, NULL }, ++ { 0x0041, NULL, NULL }, ++ { 0x0042, NULL, NULL }, ++ { 0x0043, NULL, NULL }, ++ { 0x0044, NULL, NULL }, ++ { 0x0045, NULL, NULL }, ++ { 0x0046, "SRS config - Bandwidth configuration", dissect_srs_bandwidth_configuration_value }, ++ { 0x0047, "SRS config - MaxUpPTS", dissect_srs_max_uppts_value }, ++ { 0x0048, "SRS config - SRS subframe configuration", dissect_srs_subframe_configuration_value }, ++ { 0x0049, "SRS config - SRS AckNack SRS simultaneous transmission", dissect_srs_acknack_srs_sim_tx_value }, ++ { 0x004A, NULL, NULL }, ++ { 0x004B, NULL, NULL }, ++ { 0x004C, NULL, NULL }, ++ { 0x004D, NULL, NULL }, ++ { 0x004E, NULL, NULL }, ++ { 0x004F, NULL, NULL }, ++ { 0x0050, "Uplink reference signal config - Uplink RS hopping", dissect_uplink_rs_hopping_value }, ++ { 0x0051, "Uplink reference signal config - Group assignment (delta sequence-shift pattern)", dissect_group_assignment_value }, ++ { 0x0052, "Uplink reference signal config - Cyclic Shift 1 for DMRS", dissect_cyclic_shift_1_for_drms_value }, ++ { 0x0053, NULL, NULL }, ++ { 0x0054, NULL, NULL }, ++ { 0x0055, NULL, NULL }, ++ { 0x0056, NULL, NULL }, ++ { 0x0057, NULL, NULL }, ++ { 0x0058, NULL, NULL }, ++ { 0x0059, NULL, NULL }, ++ { 0x005A, "TDD frame structure config - Subframe assignment", dissect_tdd_subframe_assignement_value }, ++ { 0x005B, "TDD frame structure config - Special sub-frame patterns", dissect_tdd_subframe_patterns_value }, ++ { 0x005C, NULL, NULL }, ++ { 0x005D, NULL, NULL }, ++ { 0x005E, NULL, NULL }, ++ { 0x005F, NULL, NULL }, ++ { 0x0060, NULL, NULL }, ++ { 0x0061, NULL, NULL }, ++ { 0x0062, NULL, NULL }, ++ { 0x0063, NULL, NULL }, ++ { 0x0064, "LAA config - ED Threshold for LBT for PDSCH", dissect_laa_ed_threashold_for_lbt_for_pdsch_value }, ++ { 0x0065, "LAA config - ED Threshold for LBT for DRS", dissect_laa_ed_threashold_for_lbt_for_drs_value }, ++ { 0x0066, "LAA config - PD Threshold", dissect_laa_pd_threshold_value }, ++ { 0x0067, "LAA config - Multi carrier type", dissect_laa_multi_carrier_type_value }, ++ { 0x0068, "LAA config - Multi carrier TX", dissect_laa_multi_carrier_tx_value }, ++ { 0x0069, "LAA config - Multi carrier freeze", dissect_laa_multi_carrier_freeze_value }, ++ { 0x006A, "LAA config - Tx antenna ports for DRS", dissect_laa_tx_antenna_port_for_drs_value }, ++ { 0x006B, "LAA config - Transmission power for DRS", dissect_laa_transmission_power_for_drs_value }, ++ { 0x006C, NULL, NULL }, ++ { 0x006D, NULL, NULL }, ++ { 0x006E, NULL, NULL }, ++ { 0x006F, NULL, NULL }, ++ { 0x0070, NULL, NULL }, ++ { 0x0071, NULL, NULL }, ++ { 0x0072, NULL, NULL }, ++ { 0x0073, NULL, NULL }, ++ { 0x0074, NULL, NULL }, ++ { 0x0075, NULL, NULL }, ++ { 0x0076, NULL, NULL }, ++ { 0x0077, NULL, NULL }, ++ { 0x0078, "eMTC config - PBCH Repetitions enable R13", dissect_emtc_pbch_repeitions_enabled_r13_value }, ++ { 0x0079, "eMTC config - PRACH CAT-M Root sequence index", dissect_emtc_prach_cat_m_root_sequence_index_value }, ++ { 0x007A, "eMTC config - PRACH CAT-M Zero correlation zone configuration", dissect_emtc_prach_cat_m_zero_correlation_zone_configuration_value }, ++ { 0x007B, "eMTC config - PRACH CAT-M High speed flag", dissect_emtc_prach_cat_m_high_speed_flag_value }, ++ { 0x007C, "eMTC config - PRACH CE level #0 Enable", dissect_emtc_prach_ce_level_0_enabled_value }, ++ { 0x007D, "eMTC config - PRACH CE level #0 Configuration index", dissect_emtc_prach_ce_level_0_configuration_offset_value }, ++ { 0x007E, "eMTC config - PRACH CE level #0 Frequency offset", dissect_emtc_prach_ce_level_0_frequency_offset_value }, ++ { 0x007F, "eMTC config - PRACH CE level #0 Number of repetitions per attempt", dissect_emtc_preach_ce_level_0_num_of_repeitions_per_attempt_value }, ++ { 0x0080, "eMTC config - CE level #0 Starting subframe periodicity", dissect_emtc_ce_level_0_starting_subframe_periodicity_value }, ++ { 0x0081, "eMTC config - PRACH CE level #0 Hopping Enable", dissect_emtc_preach_ce_level_0_hopping_enabled_value }, ++ { 0x0082, "eMTC config - PRACH CE level #0 Hopping Offset", dissect_emtc_preach_ce_level_0_hopping_offset_value }, ++ { 0x0083, "eMTC config - PRACH CE level #1 Enable", dissect_emtc_prach_ce_level_1_enabled_value }, ++ { 0x0084, "eMTC config - PRACH CE level #1 Configuration index", dissect_emtc_prach_ce_level_1_configuration_offset_value }, ++ { 0x0085, "eMTC config - PRACH CE level #1 Frequency offset", dissect_emtc_prach_ce_level_1_frequency_offset_value }, ++ { 0x0086, "eMTC config - PRACH CE level #1 Number of repetitions per attempt", dissect_emtc_preach_ce_level_1_num_of_repeitions_per_attempt_value }, ++ { 0x0087, "eMTC config - CE level #1 Starting subframe periodicity", dissect_emtc_ce_level_1_starting_subframe_periodicity_value }, ++ { 0x0088, "eMTC config - PRACH CE level #1 Hopping Enable", dissect_emtc_preach_ce_level_1_hopping_enabled_value }, ++ { 0x0089, "eMTC config - PRACH CE level #1 Hopping Offset", dissect_emtc_preach_ce_level_1_hopping_offset_value }, ++ { 0x008A, "eMTC config - PRACH CE level #2 Enable", dissect_emtc_prach_ce_level_2_enabled_value }, ++ { 0x008B, "eMTC config - PRACH CE level #2 Configuration index", dissect_emtc_prach_ce_level_2_configuration_offset_value }, ++ { 0x008C, "eMTC config - PRACH CE level #2 Frequency offset", dissect_emtc_prach_ce_level_2_frequency_offset_value }, ++ { 0x008D, "eMTC config - PRACH CE level #2 Number of repetitions per attempt", dissect_emtc_preach_ce_level_2_num_of_repeitions_per_attempt_value }, ++ { 0x008E, "eMTC config - CE level #2 Starting subframe periodicity", dissect_emtc_ce_level_2_starting_subframe_periodicity_value }, ++ { 0x008F, "eMTC config - PRACH CE level #2 Hopping Enable", dissect_emtc_preach_ce_level_2_hopping_enabled_value }, ++ { 0x0090, "eMTC config - PRACH CE level #2 Hopping Offset", dissect_emtc_preach_ce_level_2_hopping_offset_value }, ++ { 0x0091, "eMTC config - PRACH CE level #3 Enable", dissect_emtc_prach_ce_level_3_enabled_value }, ++ { 0x0092, "eMTC config - PRACH CE level #3 Configuration index", dissect_emtc_prach_ce_level_3_configuration_offset_value }, ++ { 0x0093, "eMTC config - PRACH CE level #3 Frequency offset", dissect_emtc_prach_ce_level_3_frequency_offset_value }, ++ { 0x0094, "eMTC config - PRACH CE level #3 Number of repetitions per attempt", dissect_emtc_preach_ce_level_3_num_of_repeitions_per_attempt_value }, ++ { 0x0095, "eMTC config - CE level #3 Starting subframe periodicity", dissect_emtc_ce_level_3_starting_subframe_periodicity_value }, ++ { 0x0096, "eMTC config - PRACH CE level #3 Hopping Enable", dissect_emtc_preach_ce_level_3_hopping_enabled_value }, ++ { 0x0097, "eMTC config - PRACH CE level #3 Hopping Offset", dissect_emtc_preach_ce_level_3_hopping_offset_value }, ++ { 0x0098, "eMTC config - PUCCH Interval - ULHoppingConfigCommonModeA", dissect_emtc_pucch_interval_ul_hopping_config_common_mode_a_value }, ++ { 0x0099, "eMTC config - PUCCH Interval - ULHoppingConfigCommonModeB", dissect_emtc_pucch_interval_ul_hopping_config_common_mode_b_value }, ++ { 0x009A, NULL, NULL }, ++ { 0x009B, NULL, NULL }, ++ { 0x009C, NULL, NULL }, ++ { 0x009D, NULL, NULL }, ++ { 0x009E, NULL, NULL }, ++ { 0x009F, NULL, NULL }, ++ { 0x00A0, NULL, NULL }, ++ { 0x00A1, NULL, NULL }, ++ { 0x00A2, NULL, NULL }, ++ { 0x00A3, NULL, NULL }, ++ { 0x00A4, NULL, NULL }, ++ { 0x00A5, NULL, NULL }, ++ { 0x00A6, NULL, NULL }, ++ { 0x00A7, NULL, NULL }, ++ { 0x00A8, NULL, NULL }, ++ { 0x00A9, NULL, NULL }, ++ { 0x00AA, NULL, NULL }, ++ { 0x00AB, NULL, NULL }, ++ { 0x00AC, NULL, NULL }, ++ { 0x00AD, NULL, NULL }, ++ { 0x00AE, NULL, NULL }, ++ { 0x00AF, NULL, NULL }, ++ { 0x00B0, NULL, NULL }, ++ { 0x00B1, NULL, NULL }, ++ { 0x00B2, NULL, NULL }, ++ { 0x00B3, NULL, NULL }, ++ { 0x00B4, NULL, NULL }, ++ { 0x00B5, NULL, NULL }, ++ { 0x00B6, NULL, NULL }, ++ { 0x00B7, NULL, NULL }, ++ { 0x00B8, NULL, NULL }, ++ { 0x00B9, NULL, NULL }, ++ { 0x00BA, NULL, NULL }, ++ { 0x00BB, NULL, NULL }, ++ { 0x00BC, NULL, NULL }, ++ { 0x00BD, NULL, NULL }, ++ { 0x00BE, NULL, NULL }, ++ { 0x00BF, NULL, NULL }, ++ { 0x00C0, NULL, NULL }, ++ { 0x00C1, NULL, NULL }, ++ { 0x00C2, NULL, NULL }, ++ { 0x00C3, NULL, NULL }, ++ { 0x00C4, NULL, NULL }, ++ { 0x00C5, NULL, NULL }, ++ { 0x00C6, NULL, NULL }, ++ { 0x00C7, NULL, NULL }, ++ { 0x00C8, "Layer 2/3 - Downlink Bandwidth Support", dissect_dl_bandwidth_support_value }, ++ { 0x00C9, "Layer 2/3 - Uplink Bandwidth Support", dissect_ul_bandwidth_support_value }, ++ { 0x00CA, "Layer 2/3 - Downlink modulation support", dissect_dl_modulation_value }, ++ { 0x00CB, "Layer 2/3 - Uplink modulation support", dissect_ul_modulation_value }, ++ { 0x00CC, "Layer 2/3 - PHY antenna capability", dissect_phy_antenna_capability_value }, ++ { 0x00CD, "Layer 2/3 - Release capability", dissect_release_capability_value }, ++ { 0x00CE, "Layer 2/3 - MBSFN capability", dissect_mbsfn_value }, ++ { 0x00CF, NULL, NULL }, ++ { 0x00D0, NULL, NULL }, ++ { 0x00D1, "LAA Capability - LAA support", dissect_laa_support_value }, ++ { 0x00D2, "LAA Capability - PD sensing LBT support", dissect_laa_pd_sensing_lbt_support_value }, ++ { 0x00D3, "LAA Capability - Multi carrier LBT support", dissect_laa_multi_carrier_lbt_support_value }, ++ { 0x00D4, "LAA Capability - Partial SF support", dissect_laa_partial_sf_support_value }, ++ { 0x00D5, NULL, NULL }, ++ { 0x00D6, NULL, NULL }, ++ { 0x00D7, NULL, NULL }, ++ { 0x00D8, NULL, NULL }, ++ { 0x00D9, NULL, NULL }, ++ { 0x00DA, NULL, NULL }, ++ { 0x00DB, NULL, NULL }, ++ { 0x00DC, NULL, NULL }, ++ { 0x00DD, NULL, NULL }, ++ { 0x00DE, NULL, NULL }, ++ { 0x00DF, NULL, NULL }, ++ { 0x00E0, NULL, NULL }, ++ { 0x00E1, NULL, NULL }, ++ { 0x00E2, NULL, NULL }, ++ { 0x00E3, NULL, NULL }, ++ { 0x00E4, NULL, NULL }, ++ { 0x00E5, NULL, NULL }, ++ { 0x00E6, NULL, NULL }, ++ { 0x00E7, NULL, NULL }, ++ { 0x00E8, NULL, NULL }, ++ { 0x00E9, NULL, NULL }, ++ { 0x00EA, NULL, NULL }, ++ { 0x00EB, NULL, NULL }, ++ { 0x00EC, NULL, NULL }, ++ { 0x00ED, NULL, NULL }, ++ { 0x00EE, NULL, NULL }, ++ { 0x00EF, NULL, NULL }, ++ { 0x00F0, "Layer 2/3 - Data report mode", dissect_data_report_mode_value }, ++ { 0x00F1, "Layer 2/3 - SFN/SF", dissect_sfn_sf_value }, ++ { 0x00F2, NULL, NULL }, ++ { 0x00F3, NULL, NULL }, ++ { 0x00F4, NULL, NULL }, ++ { 0x00F5, NULL, NULL }, ++ { 0x00F6, NULL, NULL }, ++ { 0x00F7, NULL, NULL }, ++ { 0x00F8, NULL, NULL }, ++ { 0x00F9, NULL, NULL }, ++ { 0x00FA, "Layer 1 - PHY state", dissect_phy_state_value }, ++ { 0x00FB, NULL, NULL }, ++ { 0x00FC, NULL, NULL }, ++ { 0x00FD, NULL, NULL }, ++ { 0x00FE, NULL, NULL }, ++ { 0x00FF, NULL, NULL }, ++ { 0x0100, "NFAPI - P7 VNF Address IPv4", dissect_p7_vnf_address_ipv4_value }, ++ { 0x0101, "NFAPI - P7 VNF Address IPv4", dissect_p7_vnf_address_ipv6_value }, ++ { 0x0102, "NFAPI - P7 Port", dissect_p7_vnf_port_value }, ++ { 0x0103, "NFAPI - P7 PNF Address IPv4", dissect_p7_pnf_address_ipv4_value }, ++ { 0x0104, "NFAPI - P7 PNF Address IPv4", dissect_p7_pnf_address_ipv6_value }, ++ { 0x0105, "NFAPI - P7 Port", dissect_p7_pnf_port_value }, ++ { 0x0106, NULL, NULL }, ++ { 0x0107, NULL, NULL }, ++ { 0x0108, NULL, NULL }, ++ { 0x0109, NULL, NULL }, ++ { 0x010A, "NFAPI - Downlink UEs per Subframe", dissect_downlink_ues_per_subframe_value }, ++ { 0x010B, "NFAPI - Uplink UEs per Subframe", dissect_uplink_ues_per_subframe_value }, ++ { 0x010C, NULL, NULL }, ++ { 0x010D, NULL, NULL }, ++ { 0x010E, NULL, NULL }, ++ { 0x010F, NULL, NULL }, ++ { 0x0110, NULL, NULL }, ++ { 0x0111, NULL, NULL }, ++ { 0x0112, NULL, NULL }, ++ { 0x0113, NULL, NULL }, ++ { 0x0114, "NFAPI - nFAPI RF Bands", dissect_rf_bands_value }, ++ { 0x0115, NULL, NULL }, ++ { 0x0116, NULL, NULL }, ++ { 0x0117, NULL, NULL }, ++ { 0x0118, NULL, NULL }, ++ { 0x0119, NULL, NULL }, ++ { 0x011A, NULL, NULL }, ++ { 0x011B, NULL, NULL }, ++ { 0x011C, NULL, NULL }, ++ { 0x011D, NULL, NULL }, ++ { 0x011E, "NFAPI - Timing window", dissect_timing_window_value }, ++ { 0x011F, "NFAPI - Timing info mode", dissect_timing_info_mode_value }, ++ { 0x0120, "NFAPI - Timing info period", dissect_timing_info_period_value }, ++ { 0x0121, NULL, NULL }, ++ { 0x0122, NULL, NULL }, ++ { 0x0123, NULL, NULL }, ++ { 0x0124, NULL, NULL }, ++ { 0x0125, NULL, NULL }, ++ { 0x0126, NULL, NULL }, ++ { 0x0127, NULL, NULL }, ++ { 0x0128, "NFAPI - Maximum Transmit Power", dissect_maximum_transmit_power_value }, ++ { 0x0129, "NFAPI - EARFCN", dissect_earfcn_value }, ++ { 0x012A, NULL, NULL }, ++ { 0x012B, NULL, NULL }, ++ { 0x012C, NULL, NULL }, ++ { 0x012D, NULL, NULL }, ++ { 0x012E, NULL, NULL }, ++ { 0x012F, NULL, NULL }, ++ { 0x0130, "NFAPI - NMM GSM Frequency Bands", dissect_nmm_gsm_frequency_bands_value }, ++ { 0x0131, "NFAPI - NMM UMTS Frequency Bands", dissect_nmm_umts_frequency_bands_value }, ++ { 0x0132, "NFAPI - NMM LTE Frequency Bands", dissect_nmm_lte_frequency_bands_value }, ++ { 0x0133, "NFAPI - NMM Uplink RSSI supported", dissect_nmm_uplink_rssi_supported_value }, ++}; ++ ++const tlv_t p7_tags[] = ++{ ++ { 0x2000, "DL Config Request Body", dissect_dl_config_request_body_value }, ++ { 0x2001, "DL DCI PDU Release 8", dissect_dl_config_request_dl_dci_pdu_rel8_value }, ++ { 0x2002, "DL DCI PDU Release 9", dissect_dl_config_request_dl_dci_pdu_rel9_value }, ++ { 0x2003, "DL DCI PDU Release 10", dissect_dl_config_request_dl_dci_pdu_rel10_value }, ++ { 0x2004, "BCH PDU Release 8", dissect_dl_config_request_bch_pdu_rel8_value }, ++ { 0x2005, "MCH PDU Release 8", dissect_dl_config_request_mch_pdu_rel8_value }, ++ { 0x2006, "DLSCH PDU Release 8", dissect_dl_config_request_dlsch_pdu_rel8_value }, ++ { 0x2007, "DLSCH PDU Release 9", dissect_dl_config_request_dlsch_pdu_rel9_value }, ++ { 0x2008, "DLSCH PDU Release 10", dissect_dl_config_request_dlsch_pdu_rel10_value }, ++ { 0x2009, "PCH PDU Release 8", dissect_dl_config_request_pch_pdu_rel8_value }, ++ { 0x200A, "PRS PDU Release 9", dissect_dl_config_request_prs_pdu_rel9_value }, ++ { 0x200B, "CSI-RS PDU Release 10", dissect_dl_config_request_csi_rs_pdu_rel10_value }, ++ { 0x200C, "UL Config Request Body", dissect_ul_config_request_body_value }, ++ { 0x200D, "ULSCH PDU Release 8", dissect_ul_config_ulsch_pdu_rel8_value }, ++ { 0x200E, "ULSCH PDU Release 10", dissect_ul_config_ulsch_pdu_rel10_value }, ++ { 0x200F, "Initial Transmission Parameters Release 8", dissect_ul_config_init_tx_params_rel8_value }, ++ { 0x2010, "CQI RI Information Release 8", dissect_ul_config_cqi_ri_info_rel8_value }, ++ { 0x2011, "CQI RI Information Release 9 or later", dissect_ul_config_cqi_ri_info_rel9_later_value }, ++ { 0x2012, "HARQ Information (ULSCH) Release 10", dissect_ul_config_harq_info_ulsch_rel10_value }, ++ { 0x2013, "UE Information Release 8", dissect_ul_config_ue_info_rel8_value }, ++ { 0x2014, "CQI Information Release 8", dissect_ul_config_cqi_info_rel8_value }, ++ { 0x2015, "CQI Information Release 10", dissect_ul_config_cqi_info_rel10_value }, ++ { 0x2016, "SR Information Release 8", dissect_ul_config_sr_info_rel8_value }, ++ { 0x2017, "SR Information Release 10", dissect_ul_config_sr_info_rel10_value }, ++ { 0x2018, "HARQ Information (UCI) Release 10 TDD", dissect_ul_config_harq_info_uci_rel10_tdd_value }, ++ { 0x2019, "HARQ Information (UCI) Release 8 FDD", dissect_ul_config_harq_info_uci_rel8_fdd_value }, ++ { 0x201A, "HARQ Information (UCI) Release 9 or later FDD", dissect_ul_config_harq_info_uci_rel9_later_fdd_value }, ++ { 0x201B, "SRS Information Release 8", dissect_ul_config_srs_info_rel8_value }, ++ { 0x201C, "SRS Information Release 10", dissect_ul_config_srs_info_rel10_value }, ++ { 0x201D, "HI DCI0 Request Body", dissect_hi_dci0_request_body_value }, ++ { 0x201E, "HI PDU Release 8", dissect_hi_dci0_hi_rel8_value }, ++ { 0x201F, "HI PDU Release 10", dissect_hi_dci0_hi_rel10_value }, ++ { 0x2020, "DCI UL PDU Release 8", dissect_hi_dci0_dci_ul_rel8_value }, ++ { 0x2021, "DCI UL PDU Release 10", dissect_hi_dci0_dci_ul_rel10_value }, ++ { 0x2022, "Tx Request Body", dissect_tx_request_body_value }, ++ { 0x2023, "RX Indication Body", dissect_rx_indication_body_value }, ++ { 0x2024, "RX PDU Release 8", dissect_rx_indication_rel8_value }, ++ { 0x2025, "RX PDU Release 9", dissect_rx_indication_rel9_value }, ++ { 0x2026, "HARQ Indication Body", dissect_harq_indication_body_value }, ++ { 0x2027, "HARQ PDU Release 8 TDD", dissect_harq_indication_rel8_tdd_value }, ++ { 0x2028, "HARQ PDU Release 9 or later TDD", dissect_harq_indication_rel9_later_tdd_value }, ++ { 0x2029, "HARQ PDU Release 8 FDD", dissect_harq_indication_rel8_fdd_value }, ++ { 0x202A, "HARQ PDU Release 9 or later FDD", dissect_harq_indication_rel9_later_fdd_value }, ++ { 0x202B, "CRC Indication Body", dissect_crc_indication_body_value }, ++ { 0x202C, "CRC PDU Release 8", dissect_crc_indication_rel8_value }, ++ { 0x202D, "RX SR Indication Body", dissect_rx_sr_indication_body_value }, ++ { 0x202E, "RX CQI Indication Body", dissect_rx_cqi_indication_body_value }, ++ { 0x202F, "CQI PDU Release 8", dissect_rx_cqi_indication_rel8_value }, ++ { 0x2030, "CQI PDU Release 9", dissect_rx_cqi_indication_rel9_value }, ++ { 0x2031, "RACH Indication Body", dissect_rach_indication_body_value }, ++ { 0x2032, "Preamable PDU Release 8", dissect_rach_indication_rel8_value }, ++ { 0x2033, "Preamable PDU Release 9", dissect_rach_indication_rel9_value }, ++ { 0x2034, "SRS Indication Body", dissect_srs_indication_body_value }, ++ { 0x2035, "SRS PDU Release 8", dissect_srs_indication_rel8_value }, ++ { 0x2036, "SRS PDU Release 9", dissect_srs_indication_rel9_value }, ++ { 0x2037, "SRS PDU Release 10 TDD", dissect_srs_indication_rel10_tdd_value }, ++ { 0x2038, "RX UE Information", dissect_rx_ue_info_value }, ++ { 0x2039, "DL DCI PDU Release 11", dissect_dl_config_request_dl_dci_pdu_rel11_value }, ++ { 0x203A, "DL DCI PDU Release 12", dissect_dl_config_request_dl_dci_pdu_rel12_value }, ++ { 0x203B, "DL DCI PDU Release 13", dissect_dl_config_request_dl_dci_pdu_rel13_value }, ++ { 0x203C, "DLSCH PDU Release 11", dissect_dl_config_request_dlsch_pdu_rel11_value }, ++ { 0x203D, "DLSCH PDU Release 12", dissect_dl_config_request_dlsch_pdu_rel12_value }, ++ { 0x203E, "DLSCH PDU Release 13", dissect_dl_config_request_dlsch_pdu_rel13_value }, ++ { 0x203F, "PCH PDU Release 13", dissect_dl_config_request_pch_pdu_rel13_value }, ++ { 0x2040, "CSI-RS PDU Release 13", dissect_dl_config_request_csi_rs_pdu_rel13_value }, ++ { 0x2041, "EDPCCH PDU Release 11 Parameters", dissect_dl_config_request_edpcch_params_rel11_value }, ++ { 0x2042, "EDPCCH PDU Release 13 Parameters", dissect_dl_config_request_edpcch_params_rel13_value }, ++ { 0x2043, "ULSCH PDU Release 11", dissect_ul_config_ulsch_pdu_rel11_value }, ++ { 0x2044, "ULSCH PDU Release 13", dissect_ul_config_ulsch_pdu_rel13_value }, ++ { 0x2045, "CQI RI Information Release 13", dissect_ul_config_cqi_ri_info_rel13_value }, ++ { 0x2046, "HARQ Information (ULSCH) Release 13", dissect_ul_config_harq_info_ulsch_rel13_value }, ++ { 0x2047, "UE Information Release 11", dissect_ul_config_ue_info_rel11_value }, ++ { 0x2048, "UE Information Release 13", dissect_ul_config_ue_info_rel13_value }, ++ { 0x2049, "CQI Information Release 13", dissect_ul_config_cqi_info_rel13_value }, ++ { 0x204A, "HARQ Information (UCI) Release 11 FDD/TDD", dissect_ul_config_harq_info_uci_rel11_fdd_tdd_value }, ++ { 0x204B, "HARQ Information (UCI) Release 13 FDD/TDD", dissect_ul_config_harq_info_uci_rel13_fdd_tdd_value }, ++ { 0x204C, "SRS Information Release 13", dissect_ul_config_srs_info_rel13_value }, ++ { 0x204D, "DCI UL PDU Release 12", dissect_hi_dci0_dci_ul_rel12_value }, ++ { 0x204E, "MDPCCH DCI UL PDU Release 13", dissect_hi_dci0_mdpcch_dci_ul_rel13_value }, ++ { 0x204F, "HARQ PDU Release 13 or later TDD", dissect_harq_indication_rel13_later_tdd_value }, ++ { 0x2050, "HARQ PDU Release 13 or later FDD", dissect_harq_indication_rel13_later_fdd_value }, ++ { 0x2051, "Preamable PDU Release 13", dissect_rach_indication_rel13_value }, ++ { 0x2052, "UL CQI Information", dissect_ul_cqi_information_value }, ++ { 0x2053, "SRS PDU Release 11", dissect_srs_indication_rel11_value }, ++ { 0x2054, "TDD Channel Measurement", dissect_tdd_channel_measurement_value }, ++ { 0x2055, "LBT DL Config Request Body", dissect_lbt_dl_config_request_body_value }, ++ { 0x2056, "LBT PDSCH Req PDU Release 13", dissect_lbt_dl_config_request_pdsch_req_rel13_value }, ++ { 0x2057, "LBT DRS req PDU Release 13", dissect_lbt_dl_config_request_drs_req_rel13_value }, ++ { 0x2058, "LBT DL Indication Message Body", dissect_lbt_indication_message_body_value }, ++ { 0x2059, "LBT PDSCH Resp PDU Release 13", dissect_lbt_dl_config_request_pdsch_resp_rel13_value }, ++ { 0x205A, "LBT DRS Resp PDU Release 13", dissect_lbt_dl_config_request_drs_resp_rel13_value }, ++ { 0x205B, "MPDCCH PDU Release 13", dissect_dl_config_request_mpdpcch_pdu_rel13_value }, ++}; ++ ++const tlv_t p4_tags[] = ++{ ++ { 0x3000, "LTE RSSI Request", dissect_lte_rssi_request_value }, ++ { 0x3001, "UTRAN RSSI Request", dissect_utran_rssi_request_value }, ++ { 0x3002, "GERAN RSSI Request", dissect_geran_rssi_request_value }, ++ { 0x3003, "RSSI Indication", dissect_rssi_indication_value }, ++ { 0x3004, "LTE CELL SEARCH Request", dissect_lte_cell_search_value }, ++ { 0x3005, "UTRAN CELL SEARCH Request", dissect_utran_cell_search_value }, ++ { 0x3006, "GERAN CELL SEARCH Request", dissect_geran_cell_search_value }, ++ { 0x3007, "LTE CELL SEARCH Indication", dissect_lte_cell_search_indication_value }, ++ { 0x3008, "UTRAN CELL SEARCH Indication", dissect_utran_cell_search_indication_value }, ++ { 0x3009, "GERAN CELL SEARCH Indication", dissect_geran_cell_search_indication_value }, ++ { 0x300A, "PNF CELL SEARCH STATE", dissect_pnf_cell_search_state_value }, ++ { 0x300B, "LTE BROADCAST DETECT Request", dissect_lte_broadcast_detect_request_value }, ++ { 0x300C, "UTRAN BROADCAST DETECT Request", dissect_utran_broadcast_detect_request_value }, ++ { 0x300D, "PNF CELL SEARCH STATE", dissect_pnf_cell_search_state_value }, ++ { 0x300E, "LTE BROADCAST DETECT Indication", dissect_lte_broadcast_detect_indication_value }, ++ { 0x300F, "UTRAN BROADCAST DETECT Indication", dissect_utran_broadcast_detect_indication_value }, ++ { 0x3010, "PNF CELL BROADCAST STATE", dissect_pnf_cell_broadcast_state_value }, ++ { 0x3011, "LTE SYSTEM INFORMATION SCHEDULE Request", dissect_lte_system_information_schedule_request_value }, ++ { 0x3012, "PNF CELL BROADCAST STATE", dissect_pnf_cell_broadcast_state_value }, ++ { 0x3013, "LTE SYSTEM INFORMATION SCHEDULE Indication", dissect_lte_system_information_schedule_indication_value }, ++ { 0x3014, "LTE SYSTEM INFORMATION Request", dissect_lte_system_information_request_value }, ++ { 0x3015, "UTRAN SYSTEM INFORMATION Request", dissect_utran_system_information_request_value }, ++ { 0x3016, "GERAN SYSTEM INFORMATION Request", dissect_geran_system_information_request_value }, ++ { 0x3017, "PNF CELL BROADCAST STATE", dissect_pnf_cell_broadcast_state_value }, ++ { 0x3018, "LTE SYSTEM INFORMATION Indication", dissect_lte_system_information_indication_value }, ++ { 0x3019, "UTRAN SYSTEM INFORMATION Indication", dissect_utran_system_information_indication_value }, ++ { 0x301A, "GERAN SYSTEM INFORMATION Indication", dissect_geran_system_information_indication_value }, ++}; ++ ++ ++static const tlv_t* look_up_tlv(int tag_id) ++{ ++ const tlv_t* tlv = NULL; ++ ++ static const gint num_configuration_tags = sizeof(configuration_tags) / sizeof(tlv_t); ++ static const gint num_nfapi_tags = sizeof(nfapi_tags) / sizeof(tlv_t); ++ static const gint num_p7_tags = sizeof(p7_tags) / sizeof(tlv_t); ++ static const gint num_p4_tags = sizeof(p4_tags) / sizeof(tlv_t); ++ ++ if (tag_id >= 0x0000 && tag_id <= (0x0000 + num_configuration_tags - 1)) // 0x0133) ++ { ++ tlv = &configuration_tags[tag_id]; ++ } ++ else if (tag_id >= 0x1000 && tag_id <= (0x1000 + num_nfapi_tags - 1)) // 0x100D) ++ { ++ tlv = &nfapi_tags[tag_id - 0x1000]; ++ } ++ else if (tag_id >= 0x2000 && tag_id <= (0x2000 + num_p7_tags - 1)) //0x205B) ++ { ++ tlv = &p7_tags[tag_id - 0x2000]; ++ } ++ else if (tag_id >= 0x3000 && tag_id <= (0x3000 + num_p4_tags - 1)) // 0x301A) ++ { ++ tlv = &p4_tags[tag_id - 0x3000]; ++ } ++ return tlv; ++} ++ ++ ++static proto_item* dissect_tl_header(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_tl, "TL"); ++ ptvcursor_add(ptvc, hf_nfapi_tl_tag, 2, ENC_BIG_ENDIAN); ++ proto_item* item = ptvcursor_add(ptvc, hf_nfapi_tl_length, 2, ENC_BIG_ENDIAN); ++ ptvcursor_pop_subtree(ptvc); ++ ++ return item; ++} ++ ++static void dissect_tlv_list(ptvcursor_t* ptvc, packet_info* pinfo, gint len) ++{ ++ while (ptvcursor_current_offset(ptvc) < len) ++ { ++ guint16 tlv_id = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ guint16 tlv_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc) + 2); ++ ++ const tlv_t* tlv = look_up_tlv(tlv_id); ++ ++ if (tlv != NULL && tlv->name != NULL && tlv->tag_id == tlv_id) ++ { ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_tlv_tree, "%s", tlv->name); ++ proto_item* tlv_length_item = dissect_tl_header(ptvc, pinfo); ++ ++ // There are rare cases where the len of the tlv is 0. ++ if (tlv_len > 0) ++ { ++ ++ if (tlv->decode != NULL) ++ { ++ // Create a sub buff with the correct length, so we can detect reading off the end ++ tvbuff_t* sub_tvbuff = tvb_new_subset_length(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), tlv_len); ++ ptvcursor_t* sub_ptvc = ptvcursor_new(ptvcursor_tree(ptvc), sub_tvbuff, 0); ++ ++ tlv->decode(sub_ptvc, pinfo); ++ ++ if (ptvcursor_current_offset(sub_ptvc) != tlv_len) ++ { ++ // error in the tlv length ++ expert_add_info_format(pinfo, tlv_length_item, &ei_invalid_tlv_length, "TLV length does not match decoded length"); ++ } ++ ++ ptvcursor_free(sub_ptvc); ++ } ++ ++ ptvcursor_advance(ptvc, tlv_len); ++ } ++ ++ ptvcursor_pop_subtree(ptvc); ++ } ++ else ++ { ++ if (tlv_id >= 0xF000 /* && tlv_id <= 0xFFFF*/) ++ { ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_tlv_tree, "Unknown Vendor Extension Tag"); ++ } ++ else ++ { ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_tlv_tree, "Unknown"); ++ } ++ ++ dissect_tl_header(ptvc, pinfo); ++ ptvcursor_advance(ptvc, tlv_len); ++ ptvcursor_pop_subtree(ptvc); ++ } ++ } ++} ++ ++ ++static void dissect_rx_indication_body_value(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ guint number_of_pdu_addr = ptvcursor_current_offset(ptvc); // *offset; ++ guint16 count = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_number_pdus, 2, ENC_BIG_ENDIAN); ++ ++ guint16* lengths = (guint16*)wmem_alloc0(wmem_packet_scope(), count * 2); ++ memset(lengths, 0, count * 2); ++ ++ guint16 i = 0; ++ ++ if (count > 0) ++ { ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_rx_indication_pdu_list, "RX PDU List"); ++ gint pdu_end = tvb_reported_length_remaining(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)) + ptvcursor_current_offset(ptvc); ++ ++ while (tvb_reported_length_remaining(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)) > 0 && ++ ptvcursor_current_offset(ptvc) < pdu_end ) ++ { ++ guint16 tlv_id = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ //guint16 tlv_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc) + 2); ++ ++ if (tlv_id == 0x2038) ++ { ++ if (i != 0) ++ ptvcursor_pop_subtree(ptvc); ++ ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_rx_indication_pdu_list, "[%d]", i); ++ ++ i++; ++ } ++ ++ char* tlv_name = "Unknown"; ++ const tlv_t* tlv = look_up_tlv(tlv_id); ++ ++ if (tlv != NULL && tlv->name != NULL && tlv->tag_id == tlv_id) ++ { ++ tlv_name = tlv->name; ++ } ++ ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_rx_indication_pdu_list, "%s", tlv_name); ++ ++ dissect_tl_header(ptvc, pinfo); ++ ++ ++ if (tlv_id == 0x2038) ++ { ++ dissect_rx_ue_info_value(ptvc, pinfo); ++ } ++ else if (tlv_id == 0x2024) ++ { ++ lengths[i - 1] = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_length, 2, ENC_BIG_ENDIAN); ++ int data_offset = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_data_offset, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_ul_cqi, 1, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_timing_advance, 2, ENC_BIG_ENDIAN); ++ ++ if ((data_offset > 0) && (pdu_end == (tvb_reported_length_remaining(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)) + ptvcursor_current_offset(ptvc)))) ++ { ++ pdu_end = number_of_pdu_addr + data_offset; ++ } ++ ++ } ++ else if (tlv_id == 0x2025) ++ { ++ dissect_rx_indication_rel9_value(ptvc, pinfo); ++ } ++ ++ ptvcursor_pop_subtree(ptvc); ++ ++ } ++ ++ // pop the last pdu index. ++ ptvcursor_pop_subtree(ptvc); ++ ++ ptvcursor_pop_subtree(ptvc); ++ } ++ ++ for (i = 0; i < count; ++i) ++ { ++ ptvcursor_add(ptvc, hf_nfapi_pdu, lengths[i], ENC_NA); ++ } ++} ++ ++ ++// ----------------------------------------------------------------------------| ++ ++static void dissect_p45_header(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_p4_p5_message_header, "P4 P5 Header"); ++ ptvcursor_add(ptvc, hf_nfapi_p4_p5_message_header_phy_id, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_p4_p5_message_header_message_id, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_p4_p5_message_header_message_length, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_p4_p5_message_header_spare, 2, ENC_BIG_ENDIAN); ++ ptvcursor_pop_subtree(ptvc); ++ ++} ++ ++static void dissect_p7_header_new(ptvcursor_t* ptvc, guint8* m, guint8* seg, guint8* seq) ++{ ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_p7_message_header, "P7 Header"); ++ ++ ptvcursor_add(ptvc, hf_nfapi_p7_message_header_phy_id, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_p7_message_header_message_id, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_p7_message_header_message_length, 2, ENC_BIG_ENDIAN); ++ ++ guint8 m_seg = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ *m = (m_seg & 0x80) >> 7; ++ *seg = m_seg & 0x7F; ++ ++ proto_tree_add_bits_item(ptvcursor_tree(ptvc), hf_nfapi_p7_message_header_m, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8, 1, ENC_NA); ++ proto_tree_add_bits_item(ptvcursor_tree(ptvc), hf_nfapi_p7_message_header_segment, ptvcursor_tvbuff(ptvc), ((ptvcursor_current_offset(ptvc)) * 8) + 1, 7, ENC_NA); ++ ptvcursor_advance(ptvc, 1); ++ ++ ++ *seq = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); ++ ptvcursor_add(ptvc, hf_nfapi_p7_message_header_sequence_number, 1, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_p7_message_header_checksum, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_p7_message_header_transmit_timestamp, 4, ENC_BIG_ENDIAN); ++ ++ ptvcursor_pop_subtree(ptvc); ++} ++ ++ ++static void dissect_p7_header(ptvcursor_t * ptvc, packet_info* pinfo _U_) ++{ ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_p7_message_header, "P7 Header"); ++ ptvcursor_add(ptvc, hf_nfapi_p7_message_header_phy_id, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_p7_message_header_message_id, 2, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_p7_message_header_message_length, 2, ENC_BIG_ENDIAN); ++ ++ proto_tree_add_bits_item(ptvcursor_tree(ptvc), hf_nfapi_p7_message_header_m, ptvcursor_tvbuff(ptvc), (ptvcursor_current_offset(ptvc)) * 8, 1, ENC_NA); ++ proto_tree_add_bits_item(ptvcursor_tree(ptvc), hf_nfapi_p7_message_header_segment, ptvcursor_tvbuff(ptvc), ((ptvcursor_current_offset(ptvc)) * 8) + 1, 7, ENC_NA); ++ ptvcursor_advance(ptvc, 1); ++ ++ ptvcursor_add(ptvc, hf_nfapi_p7_message_header_sequence_number, 1, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_p7_message_header_checksum, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_p7_message_header_transmit_timestamp, 4, ENC_BIG_ENDIAN); ++ ++ ptvcursor_pop_subtree(ptvc); ++} ++ ++static reassembly_table ul_p7_reassemble_table; ++static reassembly_table dl_p7_reassemble_table; ++ ++static int hf_msg_fragments = -1; ++static int hf_msg_fragment = -1; ++static int hf_msg_fragment_overlap = -1; ++static int hf_msg_fragment_overlap_conflicts = -1; ++static int hf_msg_fragment_multiple_tails = -1; ++static int hf_msg_fragment_too_long_fragment = -1; ++static int hf_msg_fragment_error = -1; ++static int hf_msg_fragment_count = -1; ++static int hf_msg_reassembled_in = -1; ++static int hf_msg_reassembled_length = -1; ++static gint ett_msg_fragment = -1; ++static gint ett_msg_fragments = -1; ++ ++static const fragment_items msg_frag_items = { ++ /* Fragment subtrees */ ++ &ett_msg_fragment, ++ &ett_msg_fragments, ++ /* Fragment fields */ ++ &hf_msg_fragments, ++ &hf_msg_fragment, ++ &hf_msg_fragment_overlap, ++ &hf_msg_fragment_overlap_conflicts, ++ &hf_msg_fragment_multiple_tails, ++ &hf_msg_fragment_too_long_fragment, ++ &hf_msg_fragment_error, ++ &hf_msg_fragment_count, ++ /* Reassembled in field */ ++ &hf_msg_reassembled_in, ++ /* Reassembled length field */ ++ &hf_msg_reassembled_length, ++ NULL, ++ /* Tag */ ++ "Message fragments" ++}; ++ ++static void dissect_nfapi_ul_p7(ptvcursor_t *ptvc, packet_info *pinfo) ++{ ++ guint8 m; ++ guint8 seg; ++ guint8 seq; ++ ++ guint8 save_fragmented; ++ ptvcursor_t* sub_ptvc = 0; ++ ++ guint16 msg_id = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), 2); ++ guint16 msg_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), 4); ++ ++ dissect_p7_header_new(ptvc, &m, &seg, &seq); ++ save_fragmented = pinfo->fragmented; ++ ++ if (m == 1 || (m == 0 && seg > 0)) ++ { ++ tvbuff_t* tvbuff = ptvcursor_tvbuff(ptvc); ++ guint offset = ptvcursor_current_offset(ptvc); ++ proto_tree* tree = ptvcursor_tree(ptvc); ++ ++ pinfo->fragmented = TRUE; ++ ++ fragment_head *fd_head = fragment_add_seq_check(&ul_p7_reassemble_table, tvbuff, offset, pinfo, seq, NULL, seg, msg_len - offset, (m == 1)); ++ ++ if (fd_head) ++ { ++ tvbuff_t * new_tvb = process_reassembled_data(tvbuff, offset, pinfo, "Reassembled UL P7", fd_head, &msg_frag_items, NULL, tree); ++ if (new_tvb) ++ { ++ sub_ptvc = ptvcursor_new(tree, new_tvb, 0); ++ ++ col_append_fstr(pinfo->cinfo, COL_INFO, "[NFAPI P7 Reassembled %d]", seg); ++ } ++ else ++ { ++ col_append_fstr(pinfo->cinfo, COL_INFO, "[NFAPI P7 Segment %d]", seg); ++ return; ++ } ++ } ++ else ++ { ++ return; ++ } ++ } ++ ++ pinfo->fragmented = save_fragmented; ++ ++ { ++ switch (msg_id) ++ { ++ case NFAPI_HARQ_INDICATION_MSG_ID: ++ { ++ ptvcursor_add(sub_ptvc ? sub_ptvc : ptvc, hf_nfapi_sfn_sf, 2, ENC_BIG_ENDIAN); ++ dissect_tlv_list(sub_ptvc ? sub_ptvc : ptvc, pinfo, msg_len); ++ } ++ break; ++ case NFAPI_CRC_INDICATION_MSG_ID: ++ { ++ ptvcursor_add(sub_ptvc ? sub_ptvc : ptvc, hf_nfapi_sfn_sf, 2, ENC_BIG_ENDIAN); ++ dissect_tlv_list(sub_ptvc ? sub_ptvc : ptvc, pinfo, msg_len); ++ } ++ break; ++ case NFAPI_RX_ULSCH_INDICATION_MSG_ID: ++ { ++ ptvcursor_add(sub_ptvc ? sub_ptvc : ptvc, hf_nfapi_sfn_sf, 2, ENC_BIG_ENDIAN); ++ dissect_tlv_list(sub_ptvc ? sub_ptvc : ptvc, pinfo, msg_len); ++ } ++ break; ++ case NFAPI_RACH_INDICATION_MSG_ID: ++ { ++ ptvcursor_add(sub_ptvc ? sub_ptvc : ptvc, hf_nfapi_sfn_sf, 2, ENC_BIG_ENDIAN); ++ dissect_tlv_list(sub_ptvc ? sub_ptvc : ptvc, pinfo, msg_len); ++ } ++ break; ++ case NFAPI_SRS_INDICATION_MSG_ID: ++ { ++ ptvcursor_add(sub_ptvc ? sub_ptvc : ptvc, hf_nfapi_sfn_sf, 2, ENC_BIG_ENDIAN); ++ dissect_tlv_list(sub_ptvc ? sub_ptvc : ptvc, pinfo, msg_len); ++ } ++ break; ++ case NFAPI_RX_SR_INDICATION_MSG_ID: ++ { ++ ptvcursor_add(sub_ptvc ? sub_ptvc : ptvc, hf_nfapi_sfn_sf, 2, ENC_BIG_ENDIAN); ++ dissect_tlv_list(sub_ptvc ? sub_ptvc : ptvc, pinfo, msg_len); ++ } ++ break; ++ case NFAPI_RX_CQI_INDICATION_MSG_ID: ++ { ++ ptvcursor_add(sub_ptvc ? sub_ptvc : ptvc, hf_nfapi_sfn_sf, 2, ENC_BIG_ENDIAN); ++ dissect_tlv_list(sub_ptvc ? sub_ptvc : ptvc, pinfo, msg_len); ++ } ++ break; ++ ++ }; ++ } ++ ++ if (sub_ptvc) ++ ptvcursor_free(sub_ptvc); ++} ++ ++static void dissect_nfapi_dl_p7(ptvcursor_t *ptvc, packet_info *pinfo) ++{ ++ guint8 m; ++ guint8 seg; ++ guint8 seq; ++ ++ guint8 save_fragmented; ++ ptvcursor_t* sub_ptvc = 0; ++ ++ guint16 msg_id = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), 2); ++ guint16 msg_len = tvb_get_ntohs(ptvcursor_tvbuff(ptvc), 4); ++ ++ dissect_p7_header_new(ptvc, &m, &seg, &seq); ++ save_fragmented = pinfo->fragmented; ++ ++ if (m == 1 || (m == 0 && seg > 0)) ++ { ++ tvbuff_t* tvbuff = ptvcursor_tvbuff(ptvc); ++ guint offset = ptvcursor_current_offset(ptvc); ++ proto_tree* tree = ptvcursor_tree(ptvc); ++ ++ pinfo->fragmented = TRUE; ++ ++ fragment_head *fd_head = fragment_add_seq_check(&dl_p7_reassemble_table, tvbuff, offset, pinfo, seq, NULL, seg, msg_len - offset, (m == 1)); ++ ++ if (fd_head) ++ { ++ tvbuff_t * new_tvb = process_reassembled_data(tvbuff, offset, pinfo, "Reassembled DL P7", fd_head, &msg_frag_items, NULL, tree); ++ if (new_tvb) ++ { ++ sub_ptvc = ptvcursor_new(tree, new_tvb, 0); ++ col_append_fstr(pinfo->cinfo, COL_INFO, "[NFAPI P7 Reassembled %d]", seg); ++ } ++ else ++ { ++ col_append_fstr(pinfo->cinfo, COL_INFO, "[NFAPI P7 Segment %d]", seg); ++ return; ++ } ++ } ++ else ++ { ++ return; ++ } ++ } ++ ++ pinfo->fragmented = save_fragmented; ++ ++ switch (msg_id) ++ { ++ case NFAPI_DL_CONFIG_REQUEST_MSG_ID: ++ { ++ ptvcursor_add(sub_ptvc ? sub_ptvc : ptvc, hf_nfapi_sfn_sf, 2, ENC_BIG_ENDIAN); ++ dissect_tlv_list(sub_ptvc ? sub_ptvc : ptvc, pinfo, msg_len); ++ break; ++ } ++ case NFAPI_UL_CONFIG_REQUEST_MSG_ID: ++ { ++ ptvcursor_add(sub_ptvc ? sub_ptvc : ptvc, hf_nfapi_sfn_sf, 2, ENC_BIG_ENDIAN); ++ dissect_tlv_list(sub_ptvc ? sub_ptvc : ptvc, pinfo, msg_len); ++ } ++ break; ++ case NFAPI_HI_DCI0_REQUEST_MSG_ID: ++ { ++ ptvcursor_add(sub_ptvc ? sub_ptvc : ptvc, hf_nfapi_sfn_sf, 2, ENC_BIG_ENDIAN); ++ dissect_tlv_list(sub_ptvc ? sub_ptvc : ptvc, pinfo, msg_len); ++ } ++ break; ++ case NFAPI_TX_REQUEST_MSG_ID: ++ { ++ ptvcursor_add(sub_ptvc ? sub_ptvc : ptvc, hf_nfapi_sfn_sf, 2, ENC_BIG_ENDIAN); ++ dissect_tlv_list(sub_ptvc ? sub_ptvc : ptvc, pinfo, msg_len); ++ } ++ break; ++ case NFAPI_LBT_DL_CONFIG_REQUEST_MSG_ID: ++ { ++ ptvcursor_add(sub_ptvc ? sub_ptvc : ptvc, hf_nfapi_sfn_sf, 2, ENC_BIG_ENDIAN); ++ dissect_tlv_list(sub_ptvc ? sub_ptvc : ptvc, pinfo, msg_len); ++ } ++ break; ++ case NFAPI_LBT_DL_INDICATION_MSG_ID: ++ { ++ ptvcursor_add(sub_ptvc ? sub_ptvc : ptvc, hf_nfapi_sfn_sf, 2, ENC_BIG_ENDIAN); ++ dissect_tlv_list(sub_ptvc ? sub_ptvc : ptvc, pinfo, msg_len); ++ break; ++ } ++ } ++ ++ if (sub_ptvc) ++ ptvcursor_free(sub_ptvc); ++} ++ ++ ++static int dissect_nfapi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) ++{ ++ col_set_str(pinfo->cinfo, COL_PROTOCOL, "NFAPI"); ++ ++ ptvcursor_t* ptvc = ptvcursor_new(tree, tvb, 0); ++ ++ guint16 msg_id = tvb_get_ntohs(tvb, 2); ++ ++ // Get the name of the message ++ const gchar* message_str = val_to_str_const(msg_id, message_id_vals, "Unknown"); ++ ++ // Append to the Info string the nFAPI messages ++ col_clear(pinfo->cinfo, COL_INFO); ++ col_append_fstr(pinfo->cinfo, COL_INFO, " %s ", message_str); ++ ++ // Flag if this is a vendor extention message, could do it for P4, 5, 7 ++ if (msg_id >= 0x0300 && msg_id <= 0x03FF) ++ { ++ col_append_fstr(pinfo->cinfo, COL_INFO, " Vendor Extension"); ++ } ++ ++ // Create the top level tree ++ ptvcursor_add_text_with_subtree(ptvc, SUBTREE_UNDEFINED_LENGTH, ett_nfapi_message_tree, "%s", message_str); ++ ++ switch (msg_id) ++ { ++ case NFAPI_HARQ_INDICATION_MSG_ID: ++ case NFAPI_CRC_INDICATION_MSG_ID: ++ case NFAPI_RX_ULSCH_INDICATION_MSG_ID: ++ case NFAPI_RACH_INDICATION_MSG_ID: ++ case NFAPI_SRS_INDICATION_MSG_ID: ++ case NFAPI_RX_SR_INDICATION_MSG_ID: ++ case NFAPI_RX_CQI_INDICATION_MSG_ID: ++ { ++ dissect_nfapi_ul_p7(ptvc, pinfo); ++ } + break; +- // LBT_DL.indication +- case 0x8D: +- { +- dissect_p7_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint16_with_conversion(msg_tree, hf_nfapi_sfn_sf, tvb, &offset, sfn_sf_conversion); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; +- } +- // PNF_PARAM.request +- case 0x100: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; +- } +- // PNF_PARAM.response +- case 0x101: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_error_code, tvb, &offset, 0); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; +- } +- // PNF_CONFIG.request +- case 0x102: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; +- } +- // PNF_CONFIG.response +- case 0x103: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_error_code, tvb, &offset, 0); +- break; +- } +- // PNF_START.request +- case 0x104: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- break; +- } +- // PNF_START.response +- case 0x105: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_error_code, tvb, &offset, 0); +- break; +- } +- // PNF_STOP.response +- case 0x106: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- break; +- } +- // PNF_STOP.request +- case 0x107: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_error_code, tvb, &offset, 0); +- break; +- } +- // PARAM.request +- case 0x108: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- break; +- } +- // PARAM.response +- case 0x109: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_error_code, tvb, &offset, 0); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; +- } +- // CONFIG.request +- case 0x10A: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint8(msg_tree, hf_nfapi_num_tlv, tvb, &offset, 0); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; +- } +- // CONFIG.response +- case 0x10B: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_error_code, tvb, &offset, 0); +- break; +- } +- // START.request +- case 0x10C: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- break; +- } +- // START.response +- case 0x10D: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_error_code, tvb, &offset, 0); +- break; +- } +- // STOP.request +- case 0x10E: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- break; +- } +- // STOP.response +- case 0x10F: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_error_code, tvb, &offset, 0); +- break; +- } +- // MEASUREMENT.request +- case 0x110: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; ++ ++ case NFAPI_DL_CONFIG_REQUEST_MSG_ID: ++ case NFAPI_UL_CONFIG_REQUEST_MSG_ID: ++ case NFAPI_HI_DCI0_REQUEST_MSG_ID: ++ case NFAPI_TX_REQUEST_MSG_ID: ++ case NFAPI_LBT_DL_CONFIG_REQUEST_MSG_ID: ++ case NFAPI_LBT_DL_INDICATION_MSG_ID: ++ { ++ dissect_nfapi_dl_p7(ptvc, pinfo); ++ break; ++ } ++ ++ case NFAPI_PNF_PARAM_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; ++ } ++ case NFAPI_PNF_PARAM_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_error_code, 4, ENC_BIG_ENDIAN); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ ++ break; ++ } ++ case NFAPI_PNF_CONFIG_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; ++ } ++ case NFAPI_PNF_CONFIG_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_error_code, 4, ENC_BIG_ENDIAN); ++ break; ++ } ++ case NFAPI_PNF_START_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ break; ++ } ++ case NFAPI_PNF_START_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_error_code, 4, ENC_BIG_ENDIAN); ++ break; ++ } ++ case NFAPI_PNF_STOP_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ break; ++ } ++ case NFAPI_PNF_STOP_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_error_code, 4, ENC_BIG_ENDIAN); ++ break; ++ } ++ case NFAPI_PARAM_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ break; ++ } ++ case NFAPI_PARAM_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_error_code, 1, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_num_tlv, 1, ENC_BIG_ENDIAN); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; ++ } ++ case NFAPI_CONFIG_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_error_code, 1, ENC_BIG_ENDIAN); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; ++ } ++ case NFAPI_CONFIG_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_error_code, 4, ENC_BIG_ENDIAN); ++ break; ++ } ++ case NFAPI_START_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ break; ++ } ++ case NFAPI_START_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_error_code, 4, ENC_BIG_ENDIAN); ++ break; ++ } ++ case NFAPI_STOP_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ break; ++ } ++ case NFAPI_STOP_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_error_code, 4, ENC_BIG_ENDIAN); ++ break; ++ } ++ case NFAPI_MEASUREMENT_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; ++ } ++ case NFAPI_MEASUREMENT_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_error_code, 4, ENC_BIG_ENDIAN); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; ++ } ++ ++ // P4 ++ case NFAPI_RSSI_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_rat_type, 1, ENC_BIG_ENDIAN); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; ++ } ++ case NFAPI_RSSI_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_p4_error_code, 4, ENC_BIG_ENDIAN); ++ break; ++ } ++ case NFAPI_RSSI_INDICATION_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_p4_error_code, 4, ENC_BIG_ENDIAN); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; ++ } ++ case NFAPI_CELL_SEARCH_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_rat_type, 1, ENC_BIG_ENDIAN); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; + } +- // MEASUREMENT.response +- case 0x111: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_error_code, tvb, &offset, 0); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; +- } +- +- // P4 +- // RSSI.request +- case 0x200: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint8(msg_tree, hf_nfapi_rat_type, tvb, &offset, 0); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; ++ case NFAPI_CELL_SEARCH_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_p4_error_code, 4, ENC_BIG_ENDIAN); ++ break; + } +- // RSSI.response +- case 0x201: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_p4_error_code, tvb, &offset, 0); +- break; ++ case NFAPI_CELL_SEARCH_INDICATION_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_p4_error_code, 4, ENC_BIG_ENDIAN); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; + } +- // RSSI.indication +- case 0x202: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_p4_error_code, tvb, &offset, 0); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; ++ case NFAPI_BROADCAST_DETECT_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_rat_type, 1, ENC_BIG_ENDIAN); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; + } +- // CELL_SEARCH.request +- case 0x203: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint8(msg_tree, hf_nfapi_rat_type, tvb, &offset, 0); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; ++ case NFAPI_BROADCAST_DETECT_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_p4_error_code, 4, ENC_BIG_ENDIAN); ++ break; + } +- // CELL_SEARCH.response +- case 0x204: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_p4_error_code, tvb, &offset, 0); +- break; ++ case NFAPI_BROADCAST_DETECT_INDICATION_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_p4_error_code, 4, ENC_BIG_ENDIAN); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; + } +- // CELL_SEARCH.indication +- case 0x205: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_p4_error_code, tvb, &offset, 0); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; ++ case NFAPI_SYSTEM_INFORMATION_SCHEDULE_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_rat_type, 1, ENC_BIG_ENDIAN); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; + } +- // BROADCAST_DETECT.request +- case 0x206: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint8(msg_tree, hf_nfapi_rat_type, tvb, &offset, 0); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; ++ case NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_p4_error_code, 4, ENC_BIG_ENDIAN); ++ break; + } +- // BROADCAST_DETECT.response +- case 0x207: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_p4_error_code, tvb, &offset, 0); +- break; ++ case NFAPI_SYSTEM_INFORMATION_SCHEDULE_INDICATION_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_p4_error_code, 4, ENC_BIG_ENDIAN); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; + } +- // BROADCAST_DETECT.indication +- case 0x208: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_p4_error_code, tvb, &offset, 0); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; ++ case NFAPI_SYSTEM_INFORMATION_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_rat_type, 1, ENC_BIG_ENDIAN); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; + } +- // SYSTEM_INFORMATION_SCHEDULE.request +- case 0x209: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint8(msg_tree, hf_nfapi_rat_type, tvb, &offset, 0); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; ++ case NFAPI_SYSTEM_INFORMATION_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_p4_error_code, 4, ENC_BIG_ENDIAN); ++ break; + } +- // SYSTEM_INFORMATOIN_SCHEDULE.response +- case 0x20A: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_p4_error_code, tvb, &offset, 0); +- break; ++ case NFAPI_SYSTEM_INFORMATION_INDICATION_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_p4_error_code, 4, ENC_BIG_ENDIAN); ++ dissect_tlv_list(ptvc, pinfo, tvb_reported_length(tvb)); ++ break; + } +- // SYSTEM_INFORMATION_SCHEDULE.indication +- case 0x20B: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_p4_error_code, tvb, &offset, 0); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; ++ case NFAPI_NMM_STOP_REQUEST_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ break; + } +- // SYSTEM_INFORMATION.request +- case 0x20C: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint8(msg_tree, hf_nfapi_rat_type, tvb, &offset, 0); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; ++ case NFAPI_NMM_STOP_RESPONSE_MSG_ID: ++ { ++ dissect_p45_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_p4_error_code, 4, ENC_BIG_ENDIAN); ++ break; + } +- // SYSTEM_INFORMATION.response +- case 0x20D: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_p4_error_code, tvb, &offset, 0); +- break; ++ case NFAPI_DL_NODE_SYNC_MSG_ID: ++ { ++ dissect_p7_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_ul_node_sync_t1, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_ul_node_sync_t2, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_ul_node_sync_t3, 4, ENC_BIG_ENDIAN); ++ break; + } +- // SYSTEM_INFORMATION.indication +- case 0x20E: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_p4_error_code, tvb, &offset, 0); +- dissect_tlv_list(tvb, pinfo, msg_tree, data, &offset, tvb_reported_length(tvb)); +- break; ++ case NFAPI_UL_NODE_SYNC_MSG_ID: ++ { ++ dissect_p7_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_dl_node_sync_t1, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_dl_node_sync_delta_sfn_sf, 4, ENC_BIG_ENDIAN); ++ break; + } +- // NMM_STOP.request +- case 0x20F: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- break; ++ case NFAPI_TIMING_INFO_MSG_ID: ++ { ++ dissect_p7_header(ptvc, pinfo); ++ ptvcursor_add(ptvc, hf_nfapi_timing_info_last_sfn_sf, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_timing_info_time_since_last_timing_info, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_timing_info_dl_config_jitter, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_timing_info_tx_request_jitter, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_timing_info_ul_config_jitter, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_timing_info_hi_dci0_jitter, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_timing_info_dl_config_latest_delay, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_timing_info_tx_request_latest_delay, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_timing_info_ul_config_latest_delay, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_timing_info_hi_dci0_latest_delay, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_timing_info_dl_config_earliest_arrival, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_timing_info_tx_request_earliest_arrival, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_timing_info_ul_config_earliest_arrival, 4, ENC_BIG_ENDIAN); ++ ptvcursor_add(ptvc, hf_nfapi_timing_info_hi_dci0_earliest_arrival, 4, ENC_BIG_ENDIAN); ++ break; + } +- // NMM_STOP_response +- case 0x210: +- { +- dissect_p45_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_p4_error_code, tvb, &offset, 0); +- break; +- } +- +- // DL_NODE.sync +- case 0x0180: +- { +- dissect_p7_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_ul_node_sync_t1, tvb, &offset, "microseconds"); +- proto_tree_add_uint32(msg_tree, hf_nfapi_ul_node_sync_t2, tvb, &offset, "microseconds"); +- proto_tree_add_uint32(msg_tree, hf_nfapi_ul_node_sync_t3, tvb, &offset, "microseconds"); +- break; +- } +- // UL_NODE.sync +- case 0x0181: +- { +- dissect_p7_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_dl_node_sync_t1, tvb, &offset, "microseconds"); +- proto_tree_add_uint32(msg_tree, hf_nfapi_dl_node_sync_delta_sfn_sf, tvb, &offset, 0); +- break; +- } +- // TIMING_INFO +- case 0x0182: +- { +- dissect_p7_header(tvb, pinfo, msg_tree, data, &offset); +- proto_tree_add_uint32(msg_tree, hf_nfapi_timing_info_last_sfn_sf, tvb, &offset, 0); +- proto_tree_add_uint32(msg_tree, hf_nfapi_timing_info_time_since_last_timing_info, tvb, &offset, 0); +- proto_tree_add_uint32(msg_tree, hf_nfapi_timing_info_dl_config_jitter, tvb, &offset, 0); +- proto_tree_add_uint32(msg_tree, hf_nfapi_timing_info_tx_request_jitter, tvb, &offset, 0); +- proto_tree_add_uint32(msg_tree, hf_nfapi_timing_info_ul_config_jitter, tvb, &offset, 0); +- proto_tree_add_uint32(msg_tree, hf_nfapi_timing_info_hi_dci0_jitter, tvb, &offset, 0); +- proto_tree_add_uint32(msg_tree, hf_nfapi_timing_info_dl_config_latest_delay, tvb, &offset, 0); +- proto_tree_add_uint32(msg_tree, hf_nfapi_timing_info_tx_request_latest_delay, tvb, &offset, 0); +- proto_tree_add_uint32(msg_tree, hf_nfapi_timing_info_ul_config_latest_delay, tvb, &offset, 0); +- proto_tree_add_uint32(msg_tree, hf_nfapi_timing_info_hi_dci0_latest_delay, tvb, &offset, 0); +- proto_tree_add_uint32(msg_tree, hf_nfapi_timing_info_dl_config_earliest_arrival, tvb, &offset, 0); +- proto_tree_add_uint32(msg_tree, hf_nfapi_timing_info_tx_request_earliest_arrival, tvb, &offset, 0); +- proto_tree_add_uint32(msg_tree, hf_nfapi_timing_info_ul_config_earliest_arrival, tvb, &offset, 0); +- proto_tree_add_uint32(msg_tree, hf_nfapi_timing_info_hi_dci0_earliest_arrival, tvb, &offset, 0); +- break; +- } +- default: +- { +- // todo : is this vendor extention? +- break; +- } +- }; +- +- return tvb_captured_length(tvb); +-} +- +-static void nfapi_tag_vals_fn(gchar* s, guint32 v) +-{ +- int index = look_up_tlv(v); +- if (v >= 0) +- { +- g_snprintf(s, ITEM_LABEL_LENGTH, "%s (0x%x)", tags[index].name, v); +- } +- else +- { +- g_snprintf(s, ITEM_LABEL_LENGTH, "%s (0x%x)", "Unknown", v); +- } +-} +- +-// ----------------------------------------------------------------------------| +- +-void proto_register_nfapi(void) +-{ +- +- static hf_register_info hf[] = +- { +- { &hf_msg_fragments, { "Message fragments", "afs.fragments", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } }, +- { &hf_msg_fragment, { "Message fragment", "afs.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, +- { &hf_msg_fragment_overlap, { "Message fragment overlap", "afs.fragment.overlap", FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } }, +- { &hf_msg_fragment_overlap_conflicts, { "Message fragment overlapping with conflicting data", "afs.fragment.overlap.conflicts", FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } }, +- { &hf_msg_fragment_multiple_tails, { "Message has multiple tail fragments", "afs.fragment.multiple_tails", FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } }, +- { &hf_msg_fragment_too_long_fragment, { "Message fragment too long", "afs.fragment.too_long_fragment", FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } }, +- { &hf_msg_fragment_error, { "Message defragmentation error", "afs.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, +- { &hf_msg_fragment_count, { "Message fragment count", "afs.fragment.count", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } }, +- { &hf_msg_reassembled_in, { "Reassembled in", "afs.reassembled.in", FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, +- { &hf_msg_reassembled_length, { "Reassembled length", "afs.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } }, +- { &hf_msg_reassembled_data, { "Reassembled data", "afs.reassembled.data", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } }, +- { &hf_nfapi_message_tree, { "Message tree", "nfapi.message_tree", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_p4_p5_message_header, { "P4 P5 Header", "nfapi.p4_p5_message_header", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_p4_p5_message_header_phy_id, { "PHY ID", "nfapi.p4_p5_message_header.phy_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_p4_p5_message_header_message_id, { "Message ID", "nfapi.p4_p5_message_header.message_id", FT_UINT16, BASE_HEX_DEC, VALS(message_id_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_p4_p5_message_header_message_length, { "Message Length", "nfapi.p4_p5_message_header.message_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_p4_p5_message_header_spare, { "Spare", "nfapi.p4_p5_message_header.spare", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_p7_message_header, { "P7 Header", "nfapi.p7_message_header", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_p7_message_header_phy_id, { "Phy ID", "nfapi.p7_message_header.phy_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_p7_message_header_message_id, { "Message ID", "nfapi.p7.message_header.message_id", FT_UINT16, BASE_HEX_DEC, VALS(message_id_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_p7_message_header_message_length, { "Message Length", "nfapi.p7_message_header.message_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_p7_message_header_m, { "M", "nfapi.p7_message_header.m_segment_sequence", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_p7_message_header_segment, { "Segment Number", "nfapi.p7_message_header.m_segment_sequence", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_p7_message_header_sequence_number, { "Sequence Number", "nfapi.p7_message_header.m_segment_sequence", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_p7_message_header_checksum, { "Checksum", "nfapi.p7_message_header.checksum", FT_UINT32, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_p7_message_header_transmit_timestamp, { "Transmit Timestamp", "nfapi.p7_message_header.timestamp", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_tlv_tree, { "TAG", "nfapi.tlv.tree", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_tl, { "TL", "nfapi.tl", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_tl_tag, { "TL Tag", "nfapi.tl_tag", FT_UINT16, BASE_CUSTOM, CF_FUNC(nfapi_tag_vals_fn), 0x0, NULL, HFILL } }, +- { &hf_nfapi_tl_length, { "TL Length", "nfapi.tl_length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_tag_uint8_value, { "Value", "nfapi.tag.uint8.value", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_tag_uint16_value, { "Value", "nfapi.tag.uint16.value", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_param_response, { "Param Request", "nfapi.param.request", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_error_code, { "Error Code", "nfapi.error.code", FT_UINT8, BASE_DEC, VALS(nfapi_error_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_p4_error_code, { "Error Code", "nfapi.p4_error.code", FT_UINT8, BASE_DEC, VALS(nfapi_p4_error_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_rat_type, { "RAT Type", "nfapi.rat_type", FT_UINT8, BASE_DEC, VALS(nfapi_rat_type_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_num_tlv, { "Number of TLV", "nfapi.param.response.num_tlv", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_phy_state, { "Phy state value", "nfapi.phy.state", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_modulation_support, { "Modulation value", "nfapi.modulation.support", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_ue_per_sf, { "Downlink UEs per Subframe", "nfapi.dl.ue.per.sf", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_ue_per_sf, { "Uplink UEs per Subframe", "nfapi.ul.ue.per.sf", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_duplex_mode, { "Duplex Mode", "nfapi.duplex.mode", FT_UINT16, BASE_DEC, VALS(nfapi_duplex_mode_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_bandwidth_support, { "Downlink bandwidth support", "nfapi.dl.bandwidth.support", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_bandwidth_support, { "Uplink bandwidth support", "nfapi.ul.bandwidth.support", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_modulation_support, { "Downlink modulation support", "nfapi.dl.modulation.support", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_modulation_support, { "Uplink modulation support", "nfapi.ul.modulation.support", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_phy_antenna_capability, { "Phy Antenna capability", "nfapi.phy.antenna.capability", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_release_capability, { "Release capability", "nfapi.release.capability", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_mbsfn_capability, { "MBSFN capability", "nfapi.mbsfn.capability", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_laa_capability, { "LAA Support", "nfapi.laa.support", FT_BOOLEAN, 8, TFS(&support_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_pd_sensing_lbt_support, { "PD sensing LBT support", "nfapi.pd.sensing.lbt.support", FT_BOOLEAN, 8, TFS(&support_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_multi_carrier_lbt_support, { "Multi carrier LBT support", "nfapi.multi.carrier.lbt.support", FT_UINT16, BASE_DEC, VALS(nfapi_mutli_carrier_lbt_support_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_partial_sf_support, { "Partial SF support", "nfapi.partial.sf.support", FT_BOOLEAN, 8, TFS(&partial_sf_support_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_reference_signal_power, { "Reference signal power", "nfapi.ref_sig_power", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_primary_synchronization_signal_epre_eprers, { "Primary synchronization signal EPRE/EPRERS", "nfapi.primary.sync.signal", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_secondary_synchronization_signal_epre_eprers, { "Secondary synchronization signal EPRE/EPRERS", "nfapi.secondary.sync.signal", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_physical_cell_id, { "Physical Cell ID", "nfapi.physical.cell.id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_phich_resource, { "PHICH Resource", "nfapi.phich.resource", FT_UINT16, BASE_DEC, VALS(nfapi_phich_resource_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_phich_duration, { "PHICH Duration", "nfapi.phich.duration", FT_BOOLEAN, 8, TFS(&phich_duration_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_phich_power_offset, { "PHICH Power Offset", "nfapi.phich.power.offset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_configuration_index, { "Configuration Index", "nfapi.configuration.index", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_root_sequence_index, { "Root sequence Index", "nfapi.root.sequence.index", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_zero_correlation_zone_configuration, { "Zero correlation zone configuration", "nfapi.zero.correlation.zone.configuration", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_high_speed_flag, { "High Speed Flag", "nfapi.high.speed.flag", FT_BOOLEAN, 8, TFS(&high_speed_flag_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_frequency_offset, { "Frequency offset", "nfapi.frequency.offset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_hopping_mode, { "Hopping Mode", "nfapi.hopping.mode", FT_BOOLEAN, 8, TFS(&hopping_mode_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_hopping_offset, { "Hopping offset", "nfapi.hopping.offset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_delta_pucch_shift, { "Delta PUCCH Shift", "nfapi.delta.pucch.shift", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_cqi_rb, { "N CQI RB", "nfapi.n.cqi.rb", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_an_cs, { "N AN CS", "nfapi.n.an.cs", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n1_pucch_an, { "N1 PUCCH AN", "nfapi.n1.pucch.an", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_bandwidth_configuration, { "Bandwidth configuration", "nfapi.bw.configuration", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_srs_subframe_configuration, { "SRS subframe configuration", "nfapi.srs.subframe.configuration", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_uplink_rs_hopping, { "Uplink RS hopping", "nfapi.uplink.rs.hopping", FT_UINT16, BASE_DEC, VALS(nfapi_uplink_rs_hopping_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_group_assignment, { "Group assigment", "nfapi.group.assignment", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_cyclic_shift_1_for_drms, { "Cyclic Shift 1 for DRMS", "nfapi.cyclic.shift.1.for.drms", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_subframe_assignment, { "Subframe_assignment", "nfapi.subframe.assignment", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_special_subframe_patterns, { "Special Subframe patterns", "nfapi.special.subframe.patterns", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ed_threshold_for_lbt_for_pdsch, { "ED Threshold for LBT for PDSCH", "nfapi.subframe.assignment", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ed_threshold_for_lbt_for_drs, { "ED Threshold for LBT for DRS", "nfapi.subframe.assignment", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pd_threshold, { "PD Threshold", "nfapi.subframe.assignment", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_multi_carrier_type, { "Multi carrier type", "nfapi.subframe.assignment", FT_UINT16, BASE_DEC, VALS(nfapi_laa_carrier_type_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_multi_carrier_tx, { "Multi carrier TX", "nfapi.subframe.assignment", FT_BOOLEAN, 8, TFS(&nfapi_multi_carrier_tx_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_multi_carrier_freeze, { "Multi carrier freeze ", "nfapi.subframe.assignment", FT_BOOLEAN, 8, TFS(&nfapi_multi_carrier_freeze_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_tx_antenna_ports_for_drs, { "Tx antenna ports for DRS", "nfapi.subframe.assignment", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_transmission_power_for_drs, { "Transmission power for DRS", "nfapi.subframe.assignment", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pbch_repetitions_enabled_r13, { "PBCH Repetitions enable R13", "nfapi.pbch.repetitions.enabled_r13", FT_BOOLEAN, 8, TFS(&enabled_disabled_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_cat_m_root_sequence_index, { "PRACH CAT-M Root sequence index", "nfapi.prach.cat_m.root.squence.index", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_cat_m_zero_correlation_zone_configuration, { "PRACH CAT-M Zero correlation zone configuration", "nfapi.prach.cat_m.zero.correlation.zone.configuration", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_cat_m_high_speed_flag, { "PRACH CAT-M High speed flag", "nfapi.prach.cat_m.high.speed.flag", FT_BOOLEAN, 8, TFS(&high_speed_flag_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_0_enable, { "PRACH CE level #0 Enable", "nfapi.prach.ce.level.0.enable", FT_BOOLEAN, 8, TFS(&enabled_disabled_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_0_configuration_index, { "PRACH CE level #0 Configuration index", "nfapi.prach.ce.level.0.configuration.index", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_0_frequency_offset, { "PRACH CE level #0 Frequency offset", "nfapi.prach.ce.level.0.frequency_offset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_0_number_of_repetitions_per_attempt, { "PRACH CE level #0 Number of repetitions per attempt", "nfapi.prach.ce.level.0.number.of.repetitions.per_attempt", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_0_starting_subframe_periodicity, { "CE level #0 Starting subframe periodicity", "nfapi.prach.ce.level.0.starting.subframe_periodicity", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_0_hopping_enabled, { "PRACH CE level #0 Hopping Enable", "nfapi.prach.ce.level.0.hopping_enable", FT_BOOLEAN, 8, TFS(&enabled_disabled_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_0_hopping_offset, { "PRACH CE level #0 Hopping Offset", "nfapi.prach.ce.level.0.hopping.offset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_1_enable, { "PRACH CE level #1 Enable", "nfapi.prach.ce.level.0.enable", FT_BOOLEAN, 8, TFS(&enabled_disabled_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_1_configuration_index, { "PRACH CE level #1 Configuration index", "nfapi.prach.ce.level.0.configuration.index", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_1_frequency_offset, { "PRACH CE level #1 Frequency offset", "nfapi.prach.ce.level.0.frequency_offset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_1_number_of_repetitions_per_attempt, { "PRACH CE level #1 Number of repetitions per attempt", "nfapi.prach.ce.level.0.number.of.repetitions.per_attempt", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_1_starting_subframe_periodicity, { "CE level #1 Starting subframe periodicity", "nfapi.prach.ce.level.0.starting.subframe_periodicity", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_1_hopping_enabled, { "PRACH CE level #1 Hopping Enable", "nfapi.prach.ce.level.0.hopping_enable", FT_BOOLEAN, 8, TFS(&enabled_disabled_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_1_hopping_offset, { "PRACH CE level #1 Hopping Offset", "nfapi.prach.ce.level.0.hopping.offset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_2_enable, { "PRACH CE level #2 Enable", "nfapi.prach.ce.level.0.enable", FT_BOOLEAN, 8, TFS(&enabled_disabled_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_2_configuration_index, { "PRACH CE level #2 Configuration index", "nfapi.prach.ce.level.0.configuration.index", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_2_frequency_offset, { "PRACH CE level #2 Frequency offset", "nfapi.prach.ce.level.0.frequency_offset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_2_number_of_repetitions_per_attempt, { "PRACH CE level #2 Number of repetitions per attempt", "nfapi.prach.ce.level.0.number.of.repetitions.per_attempt", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_2_starting_subframe_periodicity, { "CE level #2 Starting subframe periodicity", "nfapi.prach.ce.level.0.starting.subframe_periodicity", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_2_hopping_enabled, { "PRACH CE level #2 Hopping Enable", "nfapi.prach.ce.level.0.hopping_enable", FT_BOOLEAN, 8, TFS(&enabled_disabled_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_2_hopping_offset, { "PRACH CE level #2 Hopping Offset", "nfapi.prach.ce.level.0.hopping.offset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_3_enable, { "PRACH CE level #3 Enable", "nfapi.prach.ce.level.0.enable", FT_BOOLEAN, 8, TFS(&enabled_disabled_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_3_configuration_index, { "PRACH CE level #3 Configuration index", "nfapi.prach.ce.level.0.configuration.index", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_3_frequency_offset, { "PRACH CE level #3 Frequency offset", "nfapi.prach.ce.level.0.frequency_offset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_3_number_of_repetitions_per_attempt, { "PRACH CE level #3 Number of repetitions per attempt", "nfapi.prach.ce.level.0.number.of.repetitions.per_attempt", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_3_starting_subframe_periodicity, { "CE level #3 Starting subframe periodicity", "nfapi.prach.ce.level.0.starting.subframe_periodicity", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_3_hopping_enabled, { "PRACH CE level #3 Hopping Enable", "nfapi.prach.ce.level.0.hopping_enable", FT_BOOLEAN, 8, TFS(&enabled_disabled_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_ce_level_3_hopping_offset, { "PRACH CE level #3 Hopping Offset", "nfapi.prach.ce.level.0.hopping.offset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pucch_internal_ul_hopping_config_common_mode_a, { "PUCCH Interval-ULHoppingConfigCommonModeA", "nfapi.pucch.interval.ulhopping.config.common.mode.a", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pucch_internal_ul_hopping_config_common_mode_b, { "PUCCH Interval-ULHoppingConfigCommonModeB", "nfapi.pucch.interval.ulhopping.config.common.mode.b", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_data_report_mode, { "Data Report Mode", "nfapi.data.report.mode", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_sfnsf, { "SFN/SF", "nfapi.sfn.sf", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_max_up_pts, { "Max UpPTS frames", "nfapi.max.uppts.frame", FT_BOOLEAN, 8, TFS(&enabled_disabled_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_srs_acknack_srs_simultaneous_transmission, { "SRS AckNack Simultaneous transmission", "nfapi.srs.acknack.simult.tx", FT_BOOLEAN, 8, TFS(&srs_simult_tx_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_address, { "PNF address", "nfapi.p7.pnf.address", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_address_ipv4, { "PNF IPV4", "nfapi.pnf.address.ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_address_ipv6, { "PNF IPV6", "nfapi.pnf.address.ipv6", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_vnf_address, { "VNF address", "nfapi.vnf.address", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_vnf_address_ipv4, { "VNF IPV4 Address", "nfapi.vnf.address.ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_vnf_address_ipv6, { "VNF IPV6 Address", "nfapi.vnf.address.ipv6", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_port, { "PNF PORT value", "nfapi.config.pnf.port.value", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_vnf_port, { "VNF PORT value", "nfapi.config.vnf.port.value", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rf_bands, { "RF Bands", "nfapi.rf.bands", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rf_bands_count, { "Number of RF Bands", "nfapi.rf.bands.count", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rf_bands_value, { "Band value", "nfapi.rf.bands.value", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_param_request, { "PNF Param Request", "nfapi.pnf.param.request", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_param_response, { "PNF Param Response", "nfapi.pnf.param.response", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_config_request, { "PNF Config Request", "nfapi.pnf.config.request", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_config_response, { "PNF Config Response", "nfapi.pnf.config.response", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_start_request, { "PNF Start Request", "nfapi.pnf.start.request", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_start_response, { "PNF Start Response", "nfapi.pnf.start.response", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_start_request, { "PNF Start Request", "nfapi.start.request", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_start_response, { "PNF Start Response", "nfapi.start.response", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_param_general, { "PNF Param General ", "nfapi.pnf.param.general", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_sync_mode, { "Sync Mode", "nfapi.sync.mode", FT_UINT8, BASE_DEC, VALS(nfapi_sync_mode_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_location_mode, { "Location Mode", "nfapi.location.mode", FT_UINT8, BASE_DEC, VALS(location_mode_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_location_coordinates_length, { "Location Coordinates Length", "nfapi.location.coordinates.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_location_coordinates, { "Location Coordinates", "nfapi.location.coordinates", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pdu, { "PDU", "nfapi.pdu", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_timing, { "DL config Timing", "nfapi.dl.config.timing", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_tx_timing, { "Tx Timing", "nfapi.general.tx.timing", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_timing, { "UL Config Timing", "nfapi.ul.config.timing", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_hi_dci0_timing, { "HI DCi0 Timing", "nfapi.hi.dci0.timing", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_maximum_number_phys, { "Maximum number of Phys", "nfapi.maximum.number.phys", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_maximum_total_bandwidth, { "Maximum Total Bandwidth", "nfapi.maximum.total.bandwidth", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_maximum_total_number_dl_layers, { "Maximum Total Number DL Layers", "nfapi.maximum.total.number.dl.layers", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_maximum_total_number_ul_layers, { "Maximum Total Number UL Layers", "nfapi.maximum.total.number.ul.layers", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_shared_bands, { "Shared bands", "nfapi.shared.bands", FT_BOOLEAN, 8, TFS(&true_false_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_shared_pa, { "Shared pa", "nfapi.shared.pa", FT_BOOLEAN, 8, TFS(&true_false_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_maximum_total_power, { "Maximum total power", "nfapi.maximum.total.power", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_oui, { "OUI", "nfapi.oui", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_phy, { "PNF Phy", "nfapi.pnf.phy", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_phy_number_phy, { "PNF Phy Number of Phy", "nfapi.pnf.phy.number.phy", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_phy_config_index, { "PNF Phy Config Index", "nfapi.pnf.phy.config.index", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_rf, { "PNF Phy RF", "nfapi.pnf.rf", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_rfs, { "Number of RFs", "nfapi.pnf.rf.number.rf", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_phy_rf_config_info, { "Phy RF Config Info", "nfapi.phy.rf.config.info", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_phy_rf_config_info_phy_id, { "Phy ID", "nfapi.pnf.phy.rf.config.phy.id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_phy_rf_config_info_band, { "RF Band", "nfapi.pnf.phy.rf.config.phy.id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_phy_rf_config, { "PNF Phy RF Config", "nfapi.pnf.phy.rf.config", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_phy_rf_config_number_phy_rf_config_info, { "Number of RF Config Info(s)", "nfapi.pnf.phy.rf.config.number.phy.rf.config.info", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_phy_rf_config_array_phy_rf_config_info, { "PNF Phy RF Config array phy rf config info ", "nfapi.pnf.phy.rf.config.array.phy.rf.config.info", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rf_config_index, { "RF Config Index", "nfapi.rf_config_index", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_rf_exclusions, { "Number of RF exclusions", "nfapi.hf_nfapi_number_of_rf_exclusions", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_maximum_3gpp_release_supported, { "Maximum 3gpp Release Supported", "nfapi.maximum_3gpp_release_supported", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_downlink_channel_bandwidth_supported, { "Maximum Channel Downlink Bandwidth Supported", "nfapi.downlink_channel_bandwidth_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_uplink_channel_bandwidth_supported, { "Maximum Channel Uplink Bandwidth Supported", "nfapi.uplink_channel_bandwidth_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_dl_layers_supported, { "Number of DL Layers Supported", "nfapi.number_of_dl_layer_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_ul_layers_supported, { "Number of UL Layers Supported", "nfapi.number_of_ul_layer_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_nmm_modes_supported, { "NMM modes supported", "nfapi.nmm_modes_supported", FT_UINT8, BASE_DEC, VALS(nmm_modes_supported_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_band, { "Band", "nfapi.band", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_maximum_transmit_power, { "Maximum transmit power", "nfapi.maximum_transmit_power", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_earfcn, { "EARFCN", "nfapi.earfcn", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_rf_bands, { "Number of RF Bands", "nfapi.num.rf_bands", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_nmm_uplink_rssi_supported, { "NMM Uplink RSSI supported", "nfapi.nmm.uplink.rssi.supported", FT_UINT16, BASE_DEC, VALS(ul_rssi_supported_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_minimum_transmit_power, { "Minimum transmit power", "nfapi.minimum_transmit_power", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_antennas_suppported, { "Number of Supported Antennas", "nfapi.number_of_antennas_suppported", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_minimum_downlink_frequency, { "Minimum downlink frequency", "nfapi.minimum_downlink_frequency", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_maximum_downlink_frequency, { "Maximum downlink frequency", "nfapi.maximum_downlink_frequency", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_minimum_uplink_frequency, { "Minimum uplink frequency", "nfapi.minimum_downlink_frequency", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_maximum_uplink_frequency, { "Maximum uplink frequency", "nfapi.maximum_downlink_frequency", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_transmission_mode7_supported, { "Transmission Mode 7 Supported", "nfapi.pnf.phy_rel10.tx_mode7_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hi_nfapi_transmission_mode8_supported, { "Transmission Mode 8 Supported", "nfapi.pnf.phy_rel10.tx_mode8_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hi_nfapi_two_antennas_ports_for_pucch, { "Two antennas ports for PUCCH", "nfapi.pnf.phy_rel10.two_antennas_ports_for_pucch", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hi_nfapi_transmission_mode_9_supported, { "Transmission Mode 9 Supported", "nfapi.pnf.phy_rel10.tx_mode9_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hi_nfapi_simultaneous_pucch_pusch, { "Simultaneous PUCCH PUSCH", "nfapi.pnf.simultaneous_pucch_pusch", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hi_nfapi_for_layer_tx_with_tm3_and_tm4, { "Four layer Tx with TM3 and TM4", "nfapi.pnf.phy_rel10.layer_tx_with_tm3_and_tm4", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_epdcch_supported, { "ePDCCH supported", "nfapi.pnf.phy_rel11.epdcch_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hi_nfapi_multi_ack_csi_reporting, { "Multi ACK CSI reporting", "nfapi.pnf.phy_rel11.mutli_ack_csi_reporting", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hi_nfapi_pucch_tx_diversity_with_channel_selection, { "PUCCH Tx diversity with channel selection", "nfapi.pnf.phy_rel11.tx_div_with_channel_selection", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hi_nfapi_ul_comp_supported, { "UL CoMP supported", "nfapi.pnf.phy_rel11.ul_comp_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hi_nfapi_transmission_mode_5_supported, { "Transmission mode 5 supported", "nfapi.pnf.phy_rel11.tx_mode5_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_subframe_set, { "CSI subframe set", "nfapi.pnf.phy_rel12.csi_subframe_set", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hi_nfapi_enhanced_4tx_codebook, { "Enhanced 4TX codebook", "nfapi.pnf.phy_rel12.exhanced_t4x_codebook", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hi_nfapi_drs_supported, { "DRS supported", "nfapi.pnf.phy_rel12.drs_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hi_nfapi_ul_64qam_supported, { "UL 64QAM supported", "nfapi.pnf.phy_rel12.ul_64qam_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hi_nfapi_transmission_mode_10_supported, { "Transmission mode 10 supported", "nfapi.pnf.phy_rel12.tx_mode10_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hi_nfapi_alternative_tbs_indices, { "Alternative TBS indices", "nfapi.pnf.phy_rel12.alternative_tbs_indices", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pucch_format_4_supported, { "PUCCH format 4 supported", "nfapi.pnf.phy_rel13.pucch_format4_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pucch_format_5_supported, { "PUCCH format 5 supported", "nfapi.pnf.phy_rel13.pucch_format5_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_more_than_5_ca_supported, { "More than 5 CA support", "nfapi.pnf.phy_rel13.mode_than_5_ca_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_laa_supported, { "LAA supported", "nfapi.pnf.phy_rel13.laa_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_laa_ending_in_dwpts_supported, { "LAA ending in DwPTS supported", "nfapi.pnf.phy_rel13.laa_ending_in_dwpts_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_laa_starting_in_second_slot_supported, { "LAA starting in second slot Supported", "nfapi.pnf.phy_rel13.laa_starting_in_second_slot_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_beamforming_supported, { "Beamforming Supported", "nfapi.pnf.phy_rel13.beamingforming_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_rs_enhancements_supported, { "CSI-RS enhancements supported", "nfapi.pnf.phy_rel13.csi_rs_enchancements_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_drms_enhancements_supported, { "DMRS enhancements supported", "nfapi.pnf.phy_rel13.drms_enhancements_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_srs_enhancements_supported, { "SRS enhancements supported", "nfapi.pnf.phy_rel13.srs_enhancements_supported", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_sfn_sf, { "SFN_SF", "nfapi.sfn_sf", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_request_body, { "DL Config Request body", "nfapi.dl.config.request.body", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_pdcch_ofdm_symbols, { "Number of PDCCH OFDM Symbols", "nfapi.number_pdcch_ofdm_symbols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_dci, { "Number of DCI", "nfapi.number_dci", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_pdus, { "Number of PDUs", "nfapi.number_pdu", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_harqs, { "Number of HARQs", "nfapi.number_harqs", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_crcs, { "Number of CRCs", "nfapi.number_crcs", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_srs, { "Number of SRs", "nfapi.number_srs", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_cqi, { "Number of CQIs", "nfapi.number_cqi", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_preambles, { "Number of Preambles", "nfapi.number_preambles", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_srss, { "Number of SRSs", "nfapi.number_srss", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_lbt_dl_req_pdu_type, { "LBT DL Request PDU Type", "nfapi.number_srss", FT_UINT16, BASE_DEC, VALS(nfapi_lbt_dl_req_pdu_type), 0x0, NULL, HFILL } }, +- { &hf_nfapi_lbt_dl_ind_pdu_type, { "LBT DL Indication PDU Type", "nfapi.number_srss", FT_UINT16, BASE_DEC, VALS(nfapi_lbt_dl_ind_pdu_type), 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_pdsch_rnti, { "Number of PDSCH RNTI", "nfapi.number_pdsch_rnti", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_transmission_power_pcfich, { "Transmission Power PCFICH", "nfapi.transmission_power_pcfich", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_request_pdu_list, { "DL Config Request body", "nfapi.dl.config.request.pdu_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_request_pdu_list, { "UL Config Request body", "nfapi.ul.config.request.pdu_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_hi_dci0_request_pdu_list, { "HI DCI0 Request body", "nfapi.hi.dci0.config.request.pdu_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_tx_request_pdu_list, { "Tx Request body", "nfapi.tx.request.pdu_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rx_indication_pdu_list, { "Rx Indication body", "nfapi.rx.indication.pdu_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_indication_pdu_list, { "Harq Indication body", "nfapi.harq.indication.pdu_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_crc_indication_pdu_list, { "CRC Indication body", "nfapi.crc.indication.pdu_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_sr_indication_pdu_list, { "SR Indication body", "nfapi.sr.indication.pdu_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_cqi_indication_pdu_list, { "CQI Indication body", "nfapi.cqi.indication.pdu_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_preamble_indication_pdu_list, { "Preamble Indication body", "nfapi.preamble.indication.pdu_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_srs_indication_pdu_list, { "SRS Indication body", "nfapi.srs.indication.pdu_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_lbt_dl_config_pdu_list, { "LBT DL Config Request body", "nfapi.lbt.dl.request.pdu_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_lbt_dl_indication_pdu_list, { "LBT DL Indicatoin body", "nfapi.lbt.dl.indication.pdu_list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_pdu_type, { "PDU Type", "nfapi.pdu.type", FT_UINT8, BASE_DEC, VALS(nfapi_dl_config_pdu_type_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_pdu_size, { "PDU size", "nfapi.pdu.size", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_instance_length, { "Instance length", "nfapi.instance.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_dlsch_pdu_rel8, { "DL CONFIG DLSCH PDU REL8", "nfapi.dl.config.dlsch.pdu.rel8", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_length, { "PDU length", "nfapi.pdu.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pdu_index, { "PDU Index", "nfapi.pdu.index", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rnti, { "RNTI", "nfapi.rnti", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_resource_allocation_type, { "Resource Allocation Type", "nfapi.resource.allocation.type", FT_UINT8, BASE_DEC, VALS(resource_allocation_type_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_virtual_resource_block_assignment_flag, { "Virtual resource block assignment flag", "nfapi.resource.block.assignment.flag", FT_UINT8, BASE_DEC, VALS(local_distributed_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_resource_block_coding, { "Resource block coding", "nfapi.resource.block.coding", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_modulation, { "Modulation", "nfapi.modulation", FT_UINT8, BASE_DEC, VALS(modulation_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_redundancy_version, { "Redundancy version", "nfapi.redundancy.version", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_transport_blocks, { "Transport blocks", "nfapi.transport.blocks", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_transport_block_to_codeword_swap_flag, { "Transport block to codeword swap flag", "nfapi.transport.block.to.codeword.swap.flag", FT_UINT8, BASE_DEC, VALS(transport_block_to_codeword_swap_flag_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_transmission_scheme, { "Transmission scheme", "nfapi.transmission.scheme", FT_UINT8, BASE_DEC, VALS(transmission_scheme_vals), 0x0, "The MIMO mode used in the PDU", HFILL } }, +- { &hf_nfapi_ul_transmission_scheme, { "Transmission scheme", "nfapi.transmission.scheme", FT_UINT8, BASE_DEC, VALS(ul_transmission_scheme_vals), 0x0, "The MIMO mode used in the PDU", HFILL } }, +- { &hf_nfapi_number_of_layers, { "Number of layers", "nfapi.number.of.layers", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_subbands, { "Number of subbands", "nfapi.number.of.subbands", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_codebook_index, { "Codebook index", "nfapi.number.of.codebook.index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ue_category_capacity, { "UE category capacity", "nfapi.ue.category.capacity", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pa, { "P-A", "nfapi.pa", FT_UINT8, BASE_DEC, VALS(pa_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_delta_power_offset_index, { "Delta Power offset index", "nfapi.delta.power.offset.index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_nprb, { "Nprb", "nfapi.nprb", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_transmission_mode, { "Transmission Mode", "nfapi.transmission_nprb", FT_UINT8, BASE_DEC, VALS(transmission_mode_vals), 0x0, "Transmission mode associated with the UE", HFILL } }, +- { &hf_nfapi_prnti, { "P-RNTI", "nfapi.prnti", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_mcs, { "MCS", "nfapi.mcs", FT_UINT8, BASE_DEC, VALS(pch_modulation_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_transport_blocks, { "Number of transport blocks", "nfapi.number_of_transport_blocks", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ue_mode, { "UE Mode", "nfapi.ue.mode", FT_UINT8, BASE_DEC, VALS(ue_mode_vals), 0x0, NULL, HFILL } }, +- { &hf_prs_bandwidth, { "PRS bandwidth", "nfapi.prs.bandwidth", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_prs_cyclic_prefix_type, { "PRS cyclic prefix type", "nfapi.prs.cyclic.prefix.type", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_prs_muting, { "PRS muting", "nfapi.prs.muting", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_num_bf_prb_per_subband, { "Num of BF PRB per Subband", "nfapi.num.bf.prb.per.subband", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_num_bf_vector, { "Num of BF Vector", "nfapi.num.bf.vector", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_rs_resource_config, { "CSI-RS resource config", "nfapi.csi.rs.resource.config", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_bf_vector_subband_index, { "BF Subband Index", "nfapi.num.bf.vector.subband.index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_bf_vector_num_antennas, { "BF Num of Antennas", "nfapi.num.bf.vector.bf.value", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_bf_vector_bf_value, { "BF Value per Antenna", "nfapi.num.bf.vector.bf.value", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_dlsch_pdu_rel9, { "DL CONFIG DLSCH PDU REL9", "nfapi.dl.config.dlsch.pdu.rel9", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_nscid, { "NSC id", "nfapi.nscid", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_dlsch_pdu_rel10, { "DL CONFIG DLSCH PDU REL10", "nfapi.dl.config.dlsch.pdu.rel10", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_rs_flag, { "CSI RS Flag", "nfapi.csi.rs.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_subbands, { "Subbands", "nfapi.subbands", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_bf_vectors, { "BF Vectors", "nfapi.bf.vectors", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_bf_vector_antennas, { "Antennas", "nfapi.antennas", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_rs_resource_config_r10, { "CSI RS resource config R10", "nfapi.csi.rs.resource_config_r10", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_rs_zero_tx_power_resource_config_bitmap_r10, { "CSI-RS Number of NZP configuration", "nfapi.csi.rs.num.of.nzp.configurations", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_rs_number_if_nzp_configurations, { "CSI RS zero Tx Power Resource config bitmap R10", "nfapi.csi.rs.zero.tx.power.resource.config.bitmap.r10", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_rs_resource_configs, { "CSR/RS Resource Configs", "nfapi.csi.rs.resource.configs", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pdsch_start, { "PDSCH_start", "nfapi.pdsch.start", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_drms_config_flag, { "DMRS Config flag", "nfapi.drms.config.flag", FT_UINT8, BASE_DEC, VALS(not_used_enabled_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_drms_scrambling, { "DMRS Scrambling", "nfapi.drms.scrambling", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_config_flag, { "CSI Config flag", "nfapi.csi.config.flag", FT_UINT8, BASE_DEC, VALS(not_used_enabled_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_scrambling, { "CSI Scrambling", "nfapi.csi.scrambling", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pdsch_re_mapping_flag, { "PDSCH RE mapping flag", "nfapi.pdsch.remapping.flag", FT_UINT8, BASE_DEC, VALS(not_used_enabled_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_pdsch_re_mapping_antenna_ports, { "PDSCH RE mapping antenna ports", "nfapi.pdsch.remapping.antenna.ports", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pdsch_re_mapping_freq_shift, { "PDSCH RE mapping freq shift", "nfapi.pdsch.remapping.freq.shift", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_alt_cqi_table_r12, { "altCQI-Table-r12", "nfapi.alt.cqi.table.r12", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_max_layers, { "MaxLayers", "nfapi.max.layers", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_dl_harq, { "N_DL_HARQ", "nfapi.n.dl.harq", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dwpts_symbols, { "DwPTS Symbols", "nfapi.dwpts.symbols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_initial_lbt_sf, { "Initial LBT SF", "nfapi.initial.lbt.sf", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ue_type, { "UE Type", "nfapi.ue.type", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pdsch_payload_type, { "PDSCH Payload Type", "nfapi.pdsch.payload.type", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_initial_transmission_sf, { "Initial transmission SF (io) ", "nfapi.init.tx.sf.io", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_req13_drms_table_flag, { "Rel-13-DMRS-tabe flag", "nfapi.r13.drms.table.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_rs_resource_index, { "CSI-RS resource index", "nfapi.csi.rs.resource.index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_rs_class, { "Class", "nfapi.csi.rs.class", FT_UINT8, BASE_DEC, VALS(csi_rs_class_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_cdm_type, { "CDM Type", "nfapi.cdm.type", FT_UINT8, BASE_DEC, VALS(csi_rs_cdm_type_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_rs_bf_vector, { "BF Vector", "nfapi.bf.vector", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_edpcch_prb_index, { "EPDCCH PRB index", "nfapi.edpcch.prb.index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_epdcch_resource_assignment_flag, { "EPDCCH Resource assignment flag", "nfapi.epdcch.resource.assignment.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_epdcch_id, { "EPDCCH ID", "nfapi.epdcch.id", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_epdcch_start_symbol, { "EPDCCH Start Symbol", "nfapi.epdcch.start.symbol", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_epdcch_num_prb, { "EPDCCH NumPRB", "nfapi.epdcch.num.prb", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_epdcch_prbs, { "EPDCCH PRBs", "nfapi.epdcch.prbs", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_precoding_value, { "Precoding value", "nfapi.precoding.value", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_mpdcch_narrowband, { "MPDCCH Narrowband", "nfapi.mpdcch.narrowband", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_prb_pairs, { "Number of PRB pairs", "nfapi.number.prb.pairs", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_resource_block_assignment, { "Resource Block Assignment", "nfapi.resource.block.assignement", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_start_symbol, { "Start symbol", "nfapi.start.symbol", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ecce_index, { "ECCE index", "nfapi.ecce.index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ce_mode, { "Rel-13-DMRS-tabe flag", "nfapi.r13.drms.table.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_drms_scrabmling_init, { "DMRS scrambling init", "nfapi.drms.scrambling.init", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pdsch_reception_levels, { "PDSCH repetition levels", "nfapi.pdsch.repetition.levels", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_new_data_indicator, { "New data indicator", "nfapi.new.data.indicator", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_tpmi_length, { "TPMI length", "nfapi.tpmi.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pmi_flag, { "PMI flag", "nfapi.pmi.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_resource_offset, { "HARQ resource offset", "nfapi.harq.resource.offset", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dci_subframe_repetition_number, { "DCI subframe repetition number", "nfapi.dci.subframe.repetition.number", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_downlink_assignment_index_length, { "Downlink assignment index Length", "nfapi.dl.assignement.index.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_starting_ce_level, { "Starting CE Level", "nfapi.starting.ce.level", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_antenna_ports_and_scrambling_identity_flag, { "Antenna ports and scrambling identity flag", "nfapi.antenna.ports.and.scrambling.identity.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_antenna_ports_and_scrambling_identity, { "Antenna ports and scrambling identity", "nfapi.antenna.ports.and.scrambling.identit", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_paging_direct_indication_differentiation_flag, { "Paging/Direct indication differentiation flag", "nfapi.paging.direct.indictation.differentiation.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_direct_indication, { "Direct indication", "nfapi.direct.indication", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_tx_antenna_ports, { "Number of TX Antenna ports", "nfapi.num.of.tx.antenna.ports.", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_precoding, { "Precoding", "nfapi.precodiing", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_bch_pdu_rel8, { "DL CONFIG BCH PDU Rel8", "nfapi.dl.config.bch.pdu.rel8", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_value_float, { "Value", "nfapi.value.float", FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_transmission_power, { "Transmission Power", "nfapi.transmission_power", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_mch_pdu_rel8, { "DL CONFIG MCH PDU Rel8", "nfapi.dl.config.mch.pdu.rel8", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_mbsfn_area_id, { "MBSFN Area id", "nfapi.mbsfn.area.id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_pch_pdu_rel8, { "DL CONFIG MCH PDU Rel8", "nfapi.dl.config.mch.pdu.rel8", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_dci_dl_pdu_rel8, { "DL CONFIG DCI DL PDU Rel8", "nfapi.dl.config.mch.pdu.rel8", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dci_format, { "DCI format", "nfapi.dci.format", FT_UINT8, BASE_DEC, VALS(dci_format_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_cce_idx, { "CCE index", "nfapi.cce.index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_aggregation_level, { "Aggregation level", "nfapi.aggregation.level", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_mcs_1, { "MCS_1", "nfapi.mcs_1", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_mcs_2, { "MCS_2", "nfapi.mcs_2", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_redundancy_version_1, { "Redundancy version_1", "nfapi.redundancy.version.1", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_redundancy_version_2, { "Redundancy version_2", "nfapi.redundancy.version.2", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_new_data_indicator_1, { "New data indicator_1", "nfapi.new.data.indicator.1", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_new_data_indicator_2 ,{ "New data indicator_2", "nfapi.new.data.indicator.2", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_process, { "HARQ process", "nfapi.harq.process", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_tpmi, { "TPMI", "nfapi.tpmi", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pmi, { "PMI", "nfapi.pmi", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_precoding_information, { "Precoding information", "nfapi.precoding.information", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_tpc, { "TPC", "nfapi.tpc", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_downlink_assignment_index, { "Downlink assignment index", "nfapi.downlink.assignment.index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ngap, { "Ngap", "nfapi.ngap", FT_UINT8, BASE_DEC, VALS(ngap_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_transport_block_size_index, { "Transport block size index", "nfapi.transport.block.size.index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_downlink_power_offset, { "Downlink power offset", "nfapi.downlink.power.offset", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_allocate_prach_flag, { "Allocation PRACH flag", "nfapi.allocation.prach.flag", FT_UINT8, BASE_DEC, VALS(true_false_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_preamble_index, { "Preamble index", "nfapi.preamable.index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prach_mask_index, { "PRACH mask index", "nfapi.prach.mask.index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rnti_type, { "RNTI type", "nfapi.rnti.type", FT_UINT8, BASE_DEC, VALS(rnti_type_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_dci_dl_pdu_rel9, { "DL CONFIG DCI DL PDU Rel9", "nfapi.dl.config.mch.pdu.rel9", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_mcch_flag, { "MCCH flag", "nfapi.mcch.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_mcch_change_notification, { "MCCH change notification", "nfapi.mcch.change.notification", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_scrambling_identity, { "Scrambling identity", "nfapi.scrambling.identity", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_dci_dl_pdu_rel10, { "DL CONFIG DCI DL PDU Rel10", "nfapi.dl.config.mch.pdu.rel10", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_cross_carrier_scheduling_flag, { "Cross Carrier scheduling flag", "nfapi.cross.carrier.scheduling.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_carrier_indicator, { "Carrier Indicator", "nfapi.carrier.indicator", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_srs_flag, { "SRS flag", "nfapi.srs.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_srs_request, { "SRS request", "nfapi.srs.request", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_antenna_ports_scrambling_and_layers, { "Antenna ports scrambling and layers", "nfapi.antenna.ports.scrambling.and.layers", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_total_dci_length_including_padding, { "Total DCI length including padding", "nfapi.total.dci.length.including.padding", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_dl_rb, { "N_DL_RB", "nfapi.n.dl.rb", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_ul_rb, { "N_UL_RB", "nfapi.n.dl.rb", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_ack_resource_offset, { "HARQ-ACK resource offset", "nfapi.harq.ack.resource.offset", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pdsch_re_mapping_and_quasi_co_location_indicator, { "PDSCH RE Mapping and Quasi-Co-Location Indicator", "nfapi.pdsch.re.mapping", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_primary_cell_type, { "Primary cell type", "nfapi.primary.cell.type", FT_UINT8, BASE_DEC, VALS(primary_cells_type_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_dl_configuration_flag, { "UL/DL configuration flag", "nfapi.ul.dl.configuration.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_ul_dl_configurations, { "Number of UL/DL configurations", "nfapi.number.ul.dl.configurations", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_dl_configuration_index, { "UL/DL configuration indication", "nfapi.ul.dl.configuration.indication", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_laa_end_partial_sf_flag, { "LAA end partial SF flag", "nfapi.laa.end.partial.sf.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_laa_end_partial_sf_configuration, { "LAA end partial SF configuration", "nfapi.laa.end.partial.sf.configuration", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_codebooksize_determination_r13, { "Codebook Size Determination R13", "nfapi.codebook.size.determination.r13", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rel13_drms_table_flag, { "Rel-13-DMRS-tabe flag", "nfapi.drms.table.flag.r13", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pscch_resource, { "PSCCH Resource", "nfapi.pscch.resource", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_time_resource_pattern, { "Time resource pattern", "nfapi.time.resource.pattern", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_mpdcch_transmission_type, { "MPDCCH transmission type", "nfapi.mpdcch.transmission.type", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_drms_scrambling_init, { "DMRS scrambling init", "nfapi.drms.scrambling.init", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pusch_repetition_levels, { "PUSCH repetition levels", "nfapi.pusch.repetition.levels", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_frequency_hopping_flag, { "Frequency hopping flag", "nfapi.frequency.hopping.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_request, { "CSI request", "nfapi.csi.request", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dai_presence_flag, { "DAI presence flag", "nfapi.dia.presence.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_total_dci_length_include_padding, { "Total DCI length including padding", "nfapi.total.dci.length.including.padding", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_prs_pdu_rel9, { "DL CONFIG PRS PDU Rel9", "nfapi.dl.config.prs.pdu.rel9", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prs_bandwidth, { "PRS Bandwidth", "nfapi.prs.bandwidth", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_prs_cyclic_prefix_type, { "PRS cyclic prefix type", "nfapi.prs.cyclic.prefix.type", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_config_csi_rs_pdu_rel10, { "DL CONFIG CSI RS PDU Rel10", "nfapi.dl.config.csi.rs.pdu.rel10", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_rs_antenna_port_count_r10, { "Antenna port count r10", "nfapi.csi.rs.antenna.port.count.r10", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_request_body, { "UL Config Request body", "nfapi.ul.config.request.body", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_pdu_type, { "UL Config PDU Type", "nfapi.ul.config.pdu.type", FT_UINT8, BASE_DEC, VALS(nfapi_ul_config_pdu_type_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_rach_prach_frequency_resources, { "RACH PRACH Frequency resources", "nfapi.rach.prach.frequency.resources", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_srs_present, { "SRS present", "nfapi.srs.present", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_harq_buffer_pdu, { "HARQ Buffer PDU", "nfapi.ul.config.harq.buffer.pdu", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_ue_information_rel8, { "UE Information Rel 8", "nfapi.ul.config.ue.information.pdu.rel8", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_handle, { "Handle", "nfapi.handle", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_sr_information_pdu_rel8, { "SR Information Rel 8", "nfapi.ul.config.sr.information.pdu.rel8", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pucch_index, { "PUCCH Index", "nfapi.pucch.index", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_size, { "Size", "nfapi.size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_resource_block_start, { "Resource block start", "nfapi.resource.block.start", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_resource_blocks, { "Number of resource blocks", "nfapi.resource.blocks", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_cyclic_shift_2_for_drms, { "Cyclic Shift 2 for DRMS", "nfapi.cyclic.shift.2.for.drms", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_frequency_hopping_enabled_flag, { "Frequency hopping enabled flag", "nfapi.frequency.hopping.enabled.flag", FT_UINT8, BASE_DEC, VALS(hopping_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_frequency_hopping_bits, { "Frequency hopping bits", "nfapi.frequency.hopping.bits", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_new_data_indication, { "New Data inidication", "nfapi.new.data.indication", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_process_number, { "HARQ Process number", "nfapi.harq.process.number", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_tx_mode, { "UL Tx Mode", "nfapi.ul.tx.mode", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_current_tx_nb, { "Current Tx nb", "nfapi.current.tx.nb", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_srs, { "N SRS", "nfapi.n.srs", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_disable_sequence_hopping_flag, { "Disable seqeunce hopping flag", "nfapi.disable.sequence.hopping.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_virtual_cell_id_enabled_flag, { "Virtual cell ID enabled flag", "nfapi.virtual.cell.id.enabled.flag", FT_UINT8, BASE_DEC, VALS(not_used_enabled_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_npusch_identity, { "nPUSCH Identity", "nfapi.npusch.identity", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ndrms_csh_identity, { "nDMRS-CSH Identity", "nfapi.ndrms.csh.identity", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_total_number_of_repetitions, { "Total Number of repetitions", "nfapi.total.number.of.repetitions", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_repetition_number, { "Repetition Number", "nfapi.repetition.number", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_initial_sf_io, { "Initial transmission SF (io) ", "nfapi.initial.sf.io", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_empty_symbols_due_to_retunning, { "Empy symbols due to re-tunning", "nfapi.empty.symbols.due.to.retunning", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_cqi_ri_pmi_size_2, { "DL CQI/PMI/RI size 2", "nfapi.dl.cqi.ri.pmi.size.2", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_size_2, { "HARQ Size 2", "nfapi.harq.size2", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_delta_offset_harq_2, { "Delta Offset HARQ 2", "nfapi.delta.offset.harq.2", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_starting_prb, { "Starting PRB", "nfapi.starting.prb", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_antenna_port, { "Antenna Port", "nfapi.antenna.port", FT_UINT8, BASE_DEC, VALS(antenna_ports_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_combs, { "Number of Combs", "nfapi.num.of.combs", FT_UINT8, BASE_DEC, VALS(combs_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_npucch_identity, { "nPUCCH Identity", "nfapi.npucch.identity", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_empty_symbols, { "Empty symbols", "nfapi.empty.symbols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_csi_mode, { "CSI_mode", "nfapi.csi.mode", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_cqi_pmi_size_2, { "DL CQI/PMI Size 2", "nfapi.dl.cqi.pmi.size.2", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_statring_prb, { "Starting PRB", "nfapi.starting.prb", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_cdm_index, { "cdm_Index", "nfapi.cdm.index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_nsrs, { "N srs", "nfapi.n.srs", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_num_ant_ports, { "Num_ant_ports", "nfapi.num.ant.port", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_pucch_2_0, { "n_PUCCH_2_0", "nfapi.n.pucch.2.0", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_pucch_2_1, { "n_PUCCH_2_1", "nfapi.n.pucch.2.1", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_pucch_2_2, { "n_PUCCH_2_2", "nfapi.n.pucch.2.2", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_pucch_2_3, { "n_PUCCH_2_3", "nfapi.n.pucch.2.3", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_cqi_pmi_size_rank_1, { "DL CQI PMI size rank 1", "nfapi.dl.cqi.pmi.size.rank.1", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_cqi_pmi_size_rank_greater_1, { "DL CQI PMI size rank greater 1", "nfapi.dl.cqi.pmi.size.rank.1", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ri_size, { "RI size", "nfapi.ri.size", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_delta_offset_cqi, { "Delta offset cqi", "nfapi.delta.offset.cqi", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_delta_offset_ri, { "Delta offset ri", "nfapi.delta.offset.ri", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_size, { "HARQ size", "nfapi.harq_size", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_delta_offset_harq, { "Delta offset HARQ", "nfapi.delta.offset.harq", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ack_nack_mode, { "ACK NACK mode", "nfapi.ack.nack.mode", FT_UINT8, BASE_DEC, VALS(nfapi_ack_nack_mode_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_srs_initial, { "N srs initial", "nfapi.n.srs.initial", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_initial_number_of_resource_blocks, { "Initial number of resource blocks", "nfapi.initial.number.of.resource.blocks", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_cqi_pmi_size, { "DL cqi pmi size", "nfapi.dl.cqi.pmi.size", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_report_type, { "Report type", "nfapi.report.type", FT_BOOLEAN, 8, TFS(&nfapi_csi_report_type_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_cqi_ri_pmi_size, { "DL CQI RI PMI size", "nfapi.dl.cqi.ri.pmi.size", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_control_type, { "Control type", "nfapi.control.type", FT_BOOLEAN, 8, TFS(&nfapi_control_type_string_name), 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_cc, { "Number of cc", "nfapi.number.of.cc", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_pucch_resource, { "Number of PUCCH Resource", "nfapi.number.of.pucch.resource", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pucch_index_p1, { "PUCCH Index P1", "nfapi.pucch.index.p1", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_pucch_1_0, { "N PUCCH 1 0", "nfapi.n.pucch.1.0", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_pucch_1_1, { "N PUCCH 1 1", "nfapi.n.pucch.1.1", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_pucch_1_2, { "N PUCCH 1 2", "nfapi.n.pucch.1.2", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_n_pucch_1_3, { "N PUCCH 1 3", "nfapi.n.pucch.1.3", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_srs_bandwidth, { "SRS Bandwidth", "nfapi.srs.bandwidth", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_frequency_domain_position, { "Frequency Domain position", "nfapi.frequency.domain.position", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_srs_hopping_bandwidth, { "SRS hopping bandwidth", "nfapi.srs.hopping.bandwidth", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_transmission_comb, { "Transmission comb", "nfapi.transmission.comb", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_i_srs, { "I SRS", "nfapi.i.srs", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_sounding_reference_cyclic_shift, { "Sounding reference cyclic shift", "nfapi.sounding.reference.cyclic.shift", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_antenna_ports, { "Antenna port(s)", "nfapi.antenna.port", FT_UINT8, BASE_DEC, VALS(nfapi_antenna_port_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_srs_pdu_rel10, { "SRS PDU Rel 10", "nfapi.srs.pdu.rel.10", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_srs_pdu_rel8, { "SRS PDU Rel 8", "nfapi.srs.pdu.rel.8", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_harq_information_rel9_fdd, { "HARQ information Rel 9 FDD", "nfapi.harq.information.rel.9.fdd", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_harq_information_rel8_fdd, { "HARQ information Rel 8 FDD", "nfapi.harq.information.rel.8.fdd", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_harq_information_rel10_tdd, { "HARQ information Rel 10 TDD", "nfapi.harq.information.rel.10.tdd", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_sr_information_rel10, { "SR information Rel 10", "nfapi.sr.information.rel.10", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_sr_information_rel8, { "SR information Rel 8", "nfapi.sr.information.rel.8", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_cqi_information_rel10, { "CQI information Rel 10", "nfapi.cqi.information.rel.10", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_cqi_information_rel8, { "CQI information Rel 8", "nfapi.cqi.information.rel.8", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_initial_transmission_parameters_rel8, { "Initial transmission parameters Rel 8", "nfapi.initial.transmission.parameters.rel.8", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_config_ulsch_harq_information_rel10, { "HARQ Information Rel 10", "nfapi.harq.information.rel.10", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pdu_length, { "PDU length", "nfapi.pdu.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_num_segments, { "Num segments", "nfapi.num.segments", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_segment_length, { "Segment length", "nfapi.segment.length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_segment_data, { "Segment data", "nfapi.segment.data", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_crc_indication_body, { "CRC Indication Body", "nfapi.crc_indication_body", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_crc_flag, { "CRC flag", "nfapi.crc.flag", FT_BOOLEAN, 8, TFS(&crc_flag_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_hi_pdus, { "Number of HI Pdu's", "nfapi.number_of_hi_pdus", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_dci_pdus, { "Number of DCI Pdu's", "nfapi.number_of_dci_pdus", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pdu_type, { "PDU Type", "nfapi.pdu_type", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_hi_value, { "HI Value", "nfapi.hi_value", FT_BOOLEAN, 8, TFS(&hi_value_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_i_phich, { "i phich", "nfapi.i_phich", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_flag_tb2, { "Flag TB2", "nfapi.flag_tb2", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_hi_value_2, { "HI Value 2", "nfapi.hi_value_2", FT_BOOLEAN, BASE_NONE, TFS(&hi_value_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_ue_tx_antenna_selection, { "UE Tx Antenna selection", "nfapi.ue_tx_antenna_selection", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_cqi_csi_request, { "cqi csi request", "nfapi.cqi_csi_request", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_index, { "UL index", "nfapi.ul_index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_assignment_index, { "DL Assignment index", "nfapi.dl_assignment_index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_tpc_bitmap, { "TPC bitmap", "nfapi.tpc_bitmap", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_antenna_ports, { "Number of antenna ports", "nfapi.number.of.antenna.ports", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_size_of_cqi_csi_feild, { "Size of cqi csi feild", "nfapi.size.of.cqi.csi.feild", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_new_data_indication_two, { "New data indicatipon 2", "nfapi.new.data.indication.two", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_resource_allocation_flag, { "Resource allocation flag", "nfapi.resource.allocation.flag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_node_sync, { "DL Node Sync", "nfapi.dl.node.sync", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_node_sync_t1, { "DL Node Sync t1", "nfapi.dl.node.sync.t1", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_node_sync_delta_sfn_sf, { "DL Node Sync Delta SFN SF", "nfapi.dl.node.sync.delta_sfn_sf", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_dl_cyclic_prefix_type, { "DL Cyclic Prefix type", "nfapi.dl.cyclic.prefix.type", FT_BOOLEAN, 8, TFS(&cyclic_prefix_type_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_cyclic_prefix_type, { "UL Cyclic Prefix type", "nfapi.ul.cyclic.prefix.type", FT_BOOLEAN, 8, TFS(&cyclic_prefix_type_strname), 0x0, NULL, HFILL } }, +- { &hf_nfapi_downlink_channel_bandwidth, { "Downlink Channel Bandwidth", "nfapi.dl.channel.bandwidth", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_uplink_channel_bandwidth, { "Uplink Channel Bandwidth", "nfapi.ul.channel_bandwidth", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_tx_antenna_ports, { "Tx Antenna Ports", "nfapi.tx.antenna.ports", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rx_antenna_ports, { "Tx Antenna Ports", "nfapi.rx.antenna.ports", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_node_sync, { "UL Node Sync", "nfapi.ul.node.sync", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_node_sync_t1, { "UL Node Sync t1", "nfapi.ul.node.sync.t1", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_node_sync_t2, { "UL Node Sync t2", "nfapi.ul.node.sync.t2", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_node_sync_t3, { "UL Node Sync t3", "nfapi.ul.node.sync.t3", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pb, { "P-B", "nfapi.pb.allocation", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_last_sfn_sf, { "Last SFN/SF", "nfapi.timing.info.last.sfn.sf", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_time_since_last_timing_info, { "Time since last Timing Info", "nfapi.timing.info.time.since.last.timing.info", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_dl_config_jitter, { "DL Config Jitter", "nfapi.timing.info.dl.config.jitter", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_tx_request_jitter, { "Tx Request Jitter", "nfapi.timing.info.tx.req.jitter", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_ul_config_jitter, { "UL Config Jitter", "nfapi.timing.info.ul.config.jitter", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_hi_dci0_jitter, { "HI_DCI0 Jitter", "nfapi.timing.info.hi.dci0.jitter", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_dl_config_latest_delay, { "DL Config Latest Delay", "nfapi.timing.info.dl.config.latest.delay", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_tx_request_latest_delay, { "Tx Request Latest Delay", "nfapi.timing.info.tx.request.latest.delay", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_ul_config_latest_delay, { "UL Config Latest Delay", "nfapi.timing.info.ul.config.latest.delay", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_hi_dci0_latest_delay, { "HI_DCI0 Latest Delay", "nfapi.timing.info.hi.dci0.latest.delay", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_dl_config_earliest_arrival, { "DL Config Earliest Arrival", "nfapi.timing.info.dl.config.earliest.arrival", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_tx_request_earliest_arrival, { "Tx Request Earliest Arrival", "nfapi.timing.info.tx.request.earliest.arrival", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_ul_config_earliest_arrival, { "UL Config Earliest Arrival", "nfapi.timing.info.ul.config.earliest.arrival", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_hi_dci0_earliest_arrival, { "HI_DCI0 Earliest Arrival", "nfapi.timing.info.hi.dci0.earliest.arrival", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pcfich_power_offset, { "PCFICH Power Offset", "nfapi.pcfich.power.offset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_window, { "NFAPI Timing window", "nfapi.timing.window", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_mode, { "Timing Info mode", "nfapi.timing.info.mode", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_info_period, { "Timing info period", "nfapi.timing.info.period", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_max_transmit_power, { "Max transmit power", "nfapi.max.transmit.power", FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_uint8_tag, { "uint8 tag", "nfapi.uint8.tag", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_uint16_tag, { "uint16 tag", "nfapi.uint16.tag", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_mode, { "Mode", "nfapi.harq.mode", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_ack_nack, { "Number of ACK/NACK", "nfapi.uint16.tag", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_data_value_0, { "Value 0", "nfapi.harq.value.0", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_data_value_1, { "Value 1", "nfapi.harq.value.1", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_data_value_2, { "Value 2", "nfapi.harq.value.2", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_data_value_3, { "Value 3", "nfapi.harq.value.3", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_tb_1, { "HARQ TB1", "nfapi.harq.tb.", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_tb_2, { "HARQ TB2", "nfapi.harq.tb.2", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_tb_n, { "HARQ TB_N", "nfapi.harq.tb.n", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_cqi, { "UL_CQI", "nfapi.ul.cqi", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_channel, { "Channel", "nfapi.channel", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_data_offset, { "Data Offset", "nfapi.data.offset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ri, { "RI", "nfapi.ri", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_ack_nack_data, { "HARQ Ack/Nack Data", "nfapi.harq.ack.nack.data", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_harq_data, { "HARQ TB Data", "nfapi.harq.tb.data", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_cc, { "CC", "nfapi.cc", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rbs, { "RBs", "nfapi.rbs", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_antennas, { "Physical Antennas", "nfapi.physical.antennas", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_advance, { "Timing Advance", "nfapi.timing.advance", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timing_advance_r9, { "Timing Advance R9", "nfapi.timing.advance.r9", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_cc_reported, { "Number of CC reported", "nfapi.number.of.cc.reported", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_preamble, { "Preamble", "nfapi.preamble", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rach_resource_type, { "RACH resource type", "nfapi.rach.resource.type", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_doppler_estimation, { "Doppler estimation", "nfapi.doppler.estimation", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rb_start, { "RB Start", "nfapi.rb.start", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_snr, { "SNR", "nfapi.snr", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_up_pts_symbol, { "UpPTS Symbol", "nfapi.uppts.symbol", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_prb_per_subband, { "numPRBperSubband", "nfapi.num.prb.per.subband", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_antennas, { "numAntennas", "nfapi.num.antennas", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_subband_index, { "subbandIndex", "nfapi.subband.index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_channel_coefficient, { "Channel", "nfapi.channel.coefficient", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_ul_rtoa, { "UL_RTOA", "nfapi.ul.rtoa", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_frequency_band_indicator, { "Frequency Band Indicator", "nfapi.frequency.band.indicator", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_measurement_period, { "Measurement Period", "nfapi.measurement.period", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_bandwidth, { "Bandwidth", "nfapi.bandwidth", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_timeout, { "Timeout", "nfapi.timeout", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_earfcns, { "Number of EARFCNs", "nfapi.number.of.earfcns", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_earfcn_list, { "EARFCN List", "nfapi.earfcn.list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_uarfcn, { "UARFCN", "nfapi.uarfcn", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_uarfcns, { "Number of UARFCNs", "nfapi.number.of.uarfcn", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_uarfcn_list, { "UARFCN List", "nfapi.uarfcn.list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_arfcn, { "ARFCN", "nfapi.arfcn", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_arfcn_direction, { "Direction", "nfapi.arfcn.direction", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_arfcns, { "Number of ARFCNs", "nfapi.number.of.arfcn", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_arfcn_list, { "ARFCN List", "nfapi.arfcn.list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rssi, { "RSSI", "nfapi.rssi", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_rssi, { "Number of RSSI", "nfapi.number.of.rssi", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rssi_list, { "RSSI List", "nfapi.rssi.list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pci, { "PCI", "nfapi.pci", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_measurement_bandwidth, { "Measurement Bandwidth", "nfapi.measurement.bandwidth", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_exhaustive_search, { "Exhaustive Search", "nfapi.exhaustive.search", FT_UINT8, BASE_DEC, VALS(exhustive_search_vals), 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_pci, { "Number of PCI", "nfapi.number.of.pci", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pci_list, { "PCI List", "nfapi.pci.list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_psc, { "PSC", "nfapi.psc", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_psc, { "Number of PSC", "nfapi.number.of.psc", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_psc_list, { "PCS List", "nfapi.psc.list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rsrp, { "RSRP", "nfapi.rsrp", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rsrq, { "RSRQ", "nfapi.rsrq", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_lte_cells_found, { "Number of LTE Cells Found", "nfapi.number.of.lte.cells.found", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_lte_cells_found_list, { "LTE Cells Found List", "nfapi.lte.cells.found.list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rscp, { "RSCP", "nfapi.rscp", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_enco, { "EcNo", "nfapi.ecno", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_utran_cells_found, { "Number of UTRAN Cells Found", "nfapi.number.of.utran.cells.found", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_utran_cells_found_list, { "UTRAN Cells Found List", "nfapi.utran.cells.found.list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_bsic, { "BSIC", "nfapi.bsic", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rxlev, { "RxLev", "nfapi.rxlev", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_rxqual, { "RxQual", "nfapi.rxqual", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_sfn_offset, { "SFN Offset", "nfapi.sfn.offset", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_geran_cells_found, { "Number of GSM Cells Found", "nfapi.number.of.geran.cells.found", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_geran_cells_found_list, { "GERAN Cells Found List", "nfapi.geran.cells.found.list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_tx_antenna, { "Number of Tx Antenna", "nfapi.number.of.tx.antenna", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_mib_length, { "MIB Length", "nfapi.mib.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_mib, { "MIB", "nfapi.mib", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_phich_configuration, { "PHICH Configuration", "nfapi.phich.configuration", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_retry_count, { "retryCount", "nfapi.retry.count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_sib1, { "SIB1", "nfapi.sib1", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_si_periodicity, { "SI Periodicity", "nfapi.si.periodicity", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_si_index, { "SI Index", "nfapi.si.index", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_number_of_si_periodicity, { "Number of SI Periodicity", "nfapi.number.of.si.periodicity", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_si_periodicity_list, { "SI Periodicity List", "nfapi.si.periodicity.list", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_si_window_length, { "SI Window Length", "nfapi.si.window.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_sib_type, { "SIB Type", "nfapi.sib.type", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_sib_len, { "SIB Length", "nfapi.sib.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_sib, { "SIB", "nfapi.sib", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_si_len, { "SI Length", "nfapi.si.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_si, { "SI", "nfapi.si", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_search_state, { "State", "nfapi.state", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- { &hf_nfapi_pnf_broadcast_state, { "State", "nfapi.state", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, +- +- }; +- +- /* Setup protocol subtree array */ +- static gint *ett[] = { +- &ett_nfapi_message_tree, +- &ett_nfapi_p4_p5_message_header, +- &ett_nfapi_p7_message_header, +- &ett_nfapi_tlv_tree, +- &ett_nfapi_tl, +- &ett_nfapi_pnf_param_response, +- &ett_nfapi_pnf_phy_rf_config, +- &ett_nfapi_pnf_phy_rf_config_instance, +- &ett_nfapi_pnf_phy, +- &ett_nfapi_pnf_phy_rel10, +- &ett_nfapi_pnf_phy_rel11, +- &ett_nfapi_pnf_phy_rel12, +- &ett_nfapi_pnf_phy_rel13, +- &ett_nfapi_pnf_rf, +- &ett_nfapi_phy_state, +- &ett_nfapi_rf_bands, +- &ett_nfapi_bf_vectors, +- &ett_nfapi_csi_rs_bf_vector, +- &ett_nfapi_csi_rs_resource_configs, +- &ett_nfapi_tx_antenna_ports, +- &ett_nfapi_harq_ack_nack_data, +- &ett_nfapi_harq_data, +- &ett_nfapi_cc, +- &ett_nfapi_rbs, +- &ett_nfapi_antennas, +- &ett_nfapi_epdcch_prbs, +- &ett_nfapi_dl_config_request_body, +- &ett_nfapi_dl_config_request_pdu_list, +- &ett_nfapi_ul_config_request_pdu_list, +- &ett_nfapi_hi_dci0_request_pdu_list, +- &ett_nfapi_tx_request_pdu_list, +- &ett_nfapi_rx_indication_pdu_list, +- &ett_nfapi_harq_indication_pdu_list, +- &ett_nfapi_crc_indication_pdu_list, +- &ett_nfapi_sr_indication_pdu_list, +- &ett_nfapi_cqi_indication_pdu_list, +- &ett_nfapi_preamble_indication_pdu_list, +- &ett_nfapi_srs_indication_pdu_list, +- &ett_nfapi_lbt_dl_config_pdu_list, +- &ett_nfapi_lbt_dl_indication_pdu_list, +- &ett_nfapi_dl_config_request_dlsch_pdu_rel8, +- &ett_nfapi_dl_config_request_dlsch_pdu_rel9, +- &ett_nfapi_dl_config_request_dlsch_pdu_rel10, +- &ett_nfapi_dl_config_bch_pdu_rel8, +- &ett_nfapi_dl_config_mch_pdu_rel8, +- &ett_nfapi_dl_config_pch_pdu_rel8, +- &ett_nfapi_dl_config_dci_dl_pdu_rel8, +- &ett_nfapi_dl_config_dci_dl_pdu_rel9, +- &ett_nfapi_dl_config_dci_dl_pdu_rel10, +- &ett_nfapi_dl_config_prs_pdu_rel9, +- &ett_nfapi_dl_config_csi_rs_pdu_rel10, +- &ett_nfapi_subbands, +- &ett_nfapi_precoding, +- &ett_nfapi_bf_vector_antennas, +- &ett_nfapi_ul_config_request_body, +- &ett_nfapi_ul_config_harq_buffer_pdu, +- &ett_nfapi_ul_config_ue_information_rel8, +- &ett_nfapi_ul_config_sr_information_pdu_rel8, +- &ett_nfapi_ul_config_ulsch_pdu_rel8, +- &ett_nfapi_ul_config_ulsch_pdu_rel10, +- &ett_nfapi_ul_config_cqi_ri_information_rel8, +- &ett_nfapi_ul_config_cqi_ri_information_rel9, +- &ett_nfapi_ul_config_ulsch_harq_information_rel10, +- &ett_nfapi_ul_config_initial_transmission_parameters_rel8, +- &ett_nfapi_ul_config_cqi_information_rel8, +- &ett_nfapi_ul_config_cqi_information_rel10, +- &ett_nfapi_ul_config_sr_information_rel8, +- &ett_nfapi_ul_config_sr_information_rel10, +- &ett_nfapi_ul_config_harq_information_rel10_tdd, +- &ett_nfapi_ul_config_harq_information_rel8_fdd, +- &ett_nfapi_ul_config_harq_information_rel9_fdd, +- &ett_nfapi_ul_config_srs_pdu_rel8, +- &ett_nfapi_ul_config_srs_pdu_rel10, +- &ett_nfapi_crc_indication_body, +- +- &ett_nfapi_earfcn_list, +- &ett_nfapi_uarfcn_list, +- &ett_nfapi_arfcn_list, +- &ett_nfapi_rssi_list, +- &ett_nfapi_pci_list, +- &ett_nfapi_psc_list, +- &ett_nfapi_lte_cells_found_list, +- &ett_nfapi_utran_cells_found_list, +- &ett_nfapi_geran_cells_found_list, +- &ett_nfapi_si_periodicity_list, +- +- /* for fragmentation support*/ +- &ett_msg_fragment, +- &ett_msg_fragments +- }; +- +- static ei_register_info ei[] = +- { +- { &ei_power_invalid, { "nfapi.power.invalid", PI_PROTOCOL, PI_ERROR, "Tx Power range invalid [0 - 10000]", EXPFILL } }, +- { &ei_ref_sig_power_invalid, { "nfapi.ref_sig_power.invalid", PI_PROTOCOL, PI_ERROR, "Ref Sig Power range invalid [0 - 255]", EXPFILL }}, +- { &ei_invalid_range, { "nfapi.invalid.range", PI_PROTOCOL, PI_ERROR, "Out of valid range. Todo create more specific error", EXPFILL } }, +- }; +- +- +- +- expert_module_t* expert_nfapi; +- +- /* Register protocol */ +- proto_nfapi = proto_register_protocol("Nfapi", "NFAPI", "nfapi"); +- +- expert_nfapi = expert_register_protocol(proto_nfapi); +- +- expert_register_field_array(expert_nfapi, ei, array_length(ei)); +- +- proto_register_field_array(proto_nfapi, hf, array_length(hf)); +- proto_register_subtree_array(ett, array_length(ett)); +- +- reassembly_table_register(&ul_p7_reassemble_table, &addresses_ports_reassembly_table_functions); +- reassembly_table_register(&dl_p7_reassemble_table, &addresses_ports_reassembly_table_functions); +- +- register_dissector("nfapi", dissect_nfapi, proto_nfapi); +- +-} +- +-// ----------------------------------------------------------------------------| +- +-void proto_reg_handoff_nfapi(void) +-{ +- static dissector_handle_t nfapi_handle; +- +- nfapi_handle = create_dissector_handle(dissect_nfapi, proto_nfapi); +- +- dissector_add_for_decode_as("sctp.port", nfapi_handle); +- +- dissector_add_uint("udp.port", 41700, nfapi_handle); +- +-} ++ ++ default: ++ { ++ if (msg_id >= 0x112 && msg_id <= 0x017f) ++ { ++ // reserved P5 message ++ } ++ else if (msg_id >= 0x183 && msg_id <= 0x01ff) ++ { ++ // reserved P7 message ++ } ++ else if (msg_id >= 0x0200 && msg_id <= 0x02ff) ++ { ++ // reserved P4 message ++ } ++ else if (msg_id >= 0x0300 && msg_id <= 0x03ff) ++ { ++ // reserved vendor extentions ++ } ++ ++ break; ++ } ++ }; ++ ++ ptvcursor_pop_subtree(ptvc); ++ ptvcursor_free(ptvc); ++ ++ return tvb_captured_length(tvb); ++} ++ ++static void nfapi_tag_vals_fn(gchar* s, guint32 v) ++{ ++ const tlv_t* tlv = look_up_tlv(v); ++ if (tlv != 0) ++ { ++ g_snprintf(s, ITEM_LABEL_LENGTH, "%s (0x%x)", tlv->name, v); ++ } ++ else ++ { ++ g_snprintf(s, ITEM_LABEL_LENGTH, "%s (0x%x)", "Unknown", v); ++ } ++} ++static void neg_pow_conversion_fn(gchar* s, guint8 v) ++{ ++ g_snprintf(s, ITEM_LABEL_LENGTH, "%d dB (%d)", ((gint16)v * (-1)), v); ++} ++static void power_offset_conversion_fn(gchar* s, guint16 v) ++{ ++ g_snprintf(s, ITEM_LABEL_LENGTH, "%.2f dB (%d)", (((float)v * 0.001) - 6.0), v); ++} ++static void reference_signal_power_conversion_fn(gchar* s, guint16 v) ++{ ++ g_snprintf(s, ITEM_LABEL_LENGTH, "%.2f dB (%d)", (((float)v * 0.25) - 63.75), v); ++} ++static void laa_threshold_conversion_fn(gchar* s, guint16 v) ++{ ++ g_snprintf(s, ITEM_LABEL_LENGTH, "%.2f dB (%d)", (float)(v * -100.00), v); ++} ++static void max_transmit_power_2_conversion_fn(gchar* s, guint16 v) ++{ ++ g_snprintf(s, ITEM_LABEL_LENGTH, "%.2f dB (%d)", ((float)v * 0.1) - 10.0, v); ++} ++static void max_transmit_power_conversion_fn(gchar* s, guint16 v) ++{ ++ g_snprintf(s, ITEM_LABEL_LENGTH, "%.2f dB (%d)", ((float)v * 0.1), v); ++} ++static void sfn_sf_conversion_fn(gchar* s, guint16 v) ++{ ++ g_snprintf(s, ITEM_LABEL_LENGTH, "%d/%d (%d)", v >> 0x4, v & 0x000F, v); ++} ++static void rssi_conversion_fn(gchar* s, guint16 v) ++{ ++ g_snprintf(s, ITEM_LABEL_LENGTH, "%.2f dB (%d)", ((float)v * 0.1), v); ++} ++static void dl_rs_tx_pow_measment_conversion_fn(gchar* s, guint16 v) ++{ ++ g_snprintf(s, ITEM_LABEL_LENGTH, "%.2f dB (%d)", ((float)v * 0.1), v); ++} ++ ++static void ul_cqi_conversion_fn(gchar* s, guint16 v) ++{ ++ g_snprintf(s, ITEM_LABEL_LENGTH, "%.2f dB (%d)", (((float)v / 2 ) - 64.0), v); ++} ++ ++// ----------------------------------------------------------------------------| ++ ++void proto_register_nfapi(void) ++{ ++ static hf_register_info hf[] = ++ { ++ { &hf_msg_fragments, ++ { "Message fragments", "nfapi.fragments", ++ FT_NONE, BASE_NONE, NULL, 0x00, ++ NULL, HFILL } ++ }, ++ { &hf_msg_fragment, ++ { "Message fragment", "nfapi.fragment", ++ FT_FRAMENUM, BASE_NONE, NULL, 0x00, ++ NULL, HFILL } ++ }, ++ { &hf_msg_fragment_overlap, ++ { "Message fragment overlap", "nfapi.fragment.overlap", ++ FT_BOOLEAN, 0, NULL, 0x00, ++ NULL, HFILL } ++ }, ++ { &hf_msg_fragment_overlap_conflicts, ++ { "Message fragment overlapping with conflicting data", "nfapi.fragment.overlap.conflicts", ++ FT_BOOLEAN, 0, NULL, 0x00, ++ NULL, HFILL } ++ }, ++ { &hf_msg_fragment_multiple_tails, ++ { "Message has multiple tail fragments", "nfapi.fragment.multiple_tails", ++ FT_BOOLEAN, 0, NULL, 0x00, ++ NULL, HFILL } ++ }, ++ { &hf_msg_fragment_too_long_fragment, ++ { "Message fragment too long", "nfapi.fragment.too_long_fragment", ++ FT_BOOLEAN, 0, NULL, 0x00, ++ NULL, HFILL } ++ }, ++ { &hf_msg_fragment_error, ++ { "Message defragmentation error", "nfapi.fragment.error", ++ FT_FRAMENUM, BASE_NONE, NULL, 0x00, ++ NULL, HFILL } ++ }, ++ { &hf_msg_fragment_count, ++ { "Message fragment count", "nfapi.fragment.count", ++ FT_UINT32, BASE_DEC, NULL, 0x00, ++ NULL, HFILL } ++ }, ++ { &hf_msg_reassembled_in, ++ { "Reassembled in", "nfapi.reassembled.in", ++ FT_FRAMENUM, BASE_NONE, NULL, 0x00, ++ NULL, HFILL } ++ }, ++ { &hf_msg_reassembled_length, ++ { "Reassembled length", "nfapi.reassembled.length", ++ FT_UINT32, BASE_DEC, NULL, 0x00, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_p4_p5_message_header_phy_id, ++ { "PHY ID", "nfapi.p4_p5_message_header.phy_id", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Within the PNF Device, the unique identity of the PHY instance as assigned through the PNF_CONFIG.request", HFILL } ++ }, ++ { &hf_nfapi_p4_p5_message_header_message_id, ++ { "Message ID", "nfapi.p4_p5_message_header.message_id", ++ FT_UINT16, BASE_HEX_DEC, VALS(message_id_vals), 0x0, ++ "The nFAPI message identity", HFILL } ++ }, ++ { &hf_nfapi_p4_p5_message_header_message_length, ++ { "Message Length", "nfapi.p4_p5_message_header.message_length", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The length in bytes of the message including the header", HFILL } ++ }, ++ { &hf_nfapi_p4_p5_message_header_spare, ++ { "Spare", "nfapi.p4_p5_message_header.spare", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Reserved field to be populated with zeros on transmission and ignored on reception", HFILL } ++ }, ++ { &hf_nfapi_p7_message_header_phy_id, ++ { "Phy ID", "nfapi.p7_message_header.phy_id", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Within the PNF Device, the unique identity of the PHY instance as assigned through the PNF_CONFIG.request", HFILL } ++ }, ++ { &hf_nfapi_p7_message_header_message_id, ++ { "Message ID", "nfapi.p7.message_header.message_id", ++ FT_UINT16, BASE_HEX_DEC, VALS(message_id_vals), 0x0, ++ "The nFAPI message identity", HFILL } ++ }, ++ { &hf_nfapi_p7_message_header_message_length, ++ { "Message Length", "nfapi.p7_message_header.message_length", ++ FT_UINT16, BASE_DEC | BASE_UNIT_STRING, &units_byte_bytes, 0x0, ++ "The length in bytes of the message segment including the header", HFILL } ++ }, ++ { &hf_nfapi_p7_message_header_m, ++ { "M", "nfapi.p7_message_header.m_segment_sequence", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "A More flag indicating there are more segments to follow to complete the entire message", HFILL } ++ }, ++ { &hf_nfapi_p7_message_header_segment, ++ { "Segment Number", "nfapi.p7_message_header.m_segment_sequence", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The segment number starting at zero and incrementing by one between each segment", HFILL } ++ }, ++ { &hf_nfapi_p7_message_header_sequence_number, ++ { "Sequence Number", "nfapi.p7_message_header.m_segment_sequence", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The incrementing sequence number for all complete messages over the P7 nFAPI interface per PHY instance", HFILL } ++ }, ++ { &hf_nfapi_p7_message_header_checksum, ++ { "Checksum", "nfapi.p7_message_header.checksum", ++ FT_UINT32, BASE_HEX_DEC, NULL, 0x0, ++ "The checksum of the whole message segment (including header) as calculated using " ++ "the CRC32c algorithm following the same method as the SCTP protocol defined in IETF RFC 4960 " ++ "The Checksum is optional to populate and must be filled with zero's when not used", HFILL } ++ }, ++ { &hf_nfapi_p7_message_header_transmit_timestamp, ++ { "Transmit Timestamp", "nfapi.p7_message_header.timestamp", ++ FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &units_milliseconds, 0x0, ++ "The offset from VNF SFN/SF 0/0 time reference of the message transmission at the transport layer, in microseconds, with a range of 0 to 10239999", HFILL } ++ }, ++ { &hf_nfapi_tl_tag, ++ { "TLV Tag", "nfapi.tl_tag", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(nfapi_tag_vals_fn), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_tl_length, ++ { "TLV Length", "nfapi.tl_length", ++ FT_UINT16, BASE_DEC | BASE_UNIT_STRING, &units_byte_bytes, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_error_code, ++ { "Error Code", "nfapi.error.code", ++ FT_UINT8, BASE_DEC, VALS(nfapi_error_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_p4_error_code, ++ { "Error Code", "nfapi.p4_error.code", ++ FT_UINT8, BASE_DEC, VALS(nfapi_p4_error_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_rat_type, ++ { "RAT Type", "nfapi.rat_type", ++ FT_UINT8, BASE_DEC, VALS(nfapi_rat_type_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_num_tlv, ++ { "Number of TLV", "nfapi.param.response.num_tlv", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_phy_state, ++ { "Phy state value", "nfapi.phy.state", ++ FT_UINT16, BASE_DEC, VALS(nfapi_phy_state_vals), 0x0, ++ "Indicates the current operational state of the PHY", HFILL } ++ }, ++ { &hf_nfapi_dl_ue_per_sf, ++ { "Downlink UEs per Subframe", "nfapi.dl.ue.per.sf", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The maximum number of downlink UEs per subframe supported." ++ "This is the maximum number of downlink UEs that can be scheduled per " ++ "subframe, non-inclusive of broadcast, paging and common channels.", HFILL } ++ }, ++ { &hf_nfapi_ul_ue_per_sf, ++ { "Uplink UEs per Subframe", "nfapi.ul.ue.per.sf", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The maximum number of uplink UEs per subframe supported." ++ "This is the maximum number of uplink UEs that can be scheduled per " ++ "subframe, non-inclusive of common channels.", HFILL } ++ }, ++ { &hf_nfapi_duplex_mode, ++ { "Duplex Mode", "nfapi.duplex.mode", ++ FT_UINT16, BASE_DEC, VALS(nfapi_duplex_mode_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_dl_bandwidth_support, ++ { "Downlink bandwidth support", "nfapi.dl.bandwidth.support", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The PHY downlink channel bandwidth capability (in resource blocks)", HFILL } ++ }, ++ { &hf_nfapi_dl_bandwidth_support_6, ++ { "6Mhz", "nfapi.dl.bandwidth.support.6", ++ FT_BOOLEAN, 1, TFS(&tfs_supported_not_supported), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_dl_bandwidth_support_15, ++ { "15Mhz", "nfapi.dl.bandwidth.support.15", ++ FT_BOOLEAN, 1, TFS(&tfs_supported_not_supported), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_dl_bandwidth_support_25, ++ { "25Mhz", "nfapi.dl.bandwidth.support.25", ++ FT_BOOLEAN, 1, TFS(&tfs_supported_not_supported), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_dl_bandwidth_support_50, ++ { "50Mhz", "nfapi.dl.bandwidth.support.50", ++ FT_BOOLEAN, 1, TFS(&tfs_supported_not_supported), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_dl_bandwidth_support_75, ++ { "75Mhz", "nfapi.dl.bandwidth.support.75", ++ FT_BOOLEAN, 1, TFS(&tfs_supported_not_supported), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_dl_bandwidth_support_100, ++ { "100Mhz", "nfapi.dl.bandwidth.support.100", ++ FT_BOOLEAN, 1, TFS(&tfs_supported_not_supported), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_ul_bandwidth_support, ++ { "Uplink bandwidth support", "nfapi.ul.bandwidth.support", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The PHY uplink channel bandwidth capability (in resource blocks)", HFILL } ++ }, ++ { &hf_nfapi_ul_bandwidth_support_6, ++ { "6Mhz", "nfapi.ul.bandwidth.support.6", ++ FT_BOOLEAN, 1, TFS(&tfs_supported_not_supported), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_ul_bandwidth_support_15, ++ { "15Mhz", "nfapi.ul.bandwidth.support.15", ++ FT_BOOLEAN, 1, TFS(&tfs_supported_not_supported), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_ul_bandwidth_support_25, ++ { "25Mhz", "nfapi.ul.bandwidth.support.25", ++ FT_BOOLEAN, 1, TFS(&tfs_supported_not_supported), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_ul_bandwidth_support_50, ++ { "50Mhz", "nfapi.ul.bandwidth.support.50", ++ FT_BOOLEAN, 1, TFS(&tfs_supported_not_supported), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_ul_bandwidth_support_75, ++ { "75Mhz", "nfapi.ul.bandwidth.support.75", ++ FT_BOOLEAN, 1, TFS(&tfs_supported_not_supported), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_ul_bandwidth_support_100, ++ { "100Mhz", "nfapi.ul.bandwidth.support.100", ++ FT_BOOLEAN, 1, TFS(&tfs_supported_not_supported), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_dl_modulation_support, ++ { "Downlink modulation support", "nfapi.dl.modulation.support", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The PHY downlink modulation capability", HFILL } ++ }, ++ { &hf_nfapi_dl_modulation_support_qpsk, ++ { "QPSK", "nfapi.dl.modulation.support.qpsk", ++ FT_BOOLEAN, 1, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_dl_modulation_support_16qam, ++ { "16QAM", "nfapi.dl.modulation.support.16qam", ++ FT_BOOLEAN, 1, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_dl_modulation_support_64qam, ++ { "64QAM", "nfapi.dl.modulation.support.64qam", ++ FT_BOOLEAN, 1, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_dl_modulation_support_256qam, ++ { "256QAM", "nfapi.dl.modulation.support.256qam", ++ FT_BOOLEAN, 1, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_ul_modulation_support, ++ { "Uplink modulation support", "nfapi.ul.modulation.support", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The PHY uplink modulation capability", HFILL } ++ }, ++ { &hf_nfapi_ul_modulation_support_qpsk, ++ { "QPSK", "nfapi.ul.modulation.support.qpsk", ++ FT_BOOLEAN, 1, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_ul_modulation_support_16qam, ++ { "16QAM", "nfapi.ul.modulation.support.16qam", ++ FT_BOOLEAN, 1, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_ul_modulation_support_64qam, ++ { "64QAM", "nfapi.ul.modulation.support.64qam", ++ FT_BOOLEAN, 1, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_phy_antenna_capability, ++ { "Phy Antenna capability", "nfapi.phy.antenna.capability", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Number of antennas supported", HFILL } ++ }, ++ { &hf_nfapi_release_capability, ++ { "Release capability", "nfapi.release.capability", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates which release the PHY supports", HFILL } ++ }, ++ { &hf_nfapi_mbsfn_capability, ++ { "MBSFN capability", "nfapi.mbsfn.capability", ++ FT_BOOLEAN, 8, TFS(&support_strname), 0x0, ++ "Indicates support for MBSFN features", HFILL } ++ }, ++ { &hf_nfapi_laa_capability, ++ { "LAA Support", "nfapi.laa.support", ++ FT_BOOLEAN, 8, TFS(&support_strname), 0x0, ++ "Indicates support for LAA features", HFILL } ++ }, ++ { &hf_nfapi_pd_sensing_lbt_support, ++ { "PD sensing LBT support", "nfapi.pd.sensing.lbt.support", ++ FT_BOOLEAN, 8, TFS(&support_strname), 0x0, ++ "Indicates support for PD sensing in L1", HFILL } ++ }, ++ { &hf_nfapi_multi_carrier_lbt_support, ++ { "Multi carrier LBT support", "nfapi.multi.carrier.lbt.support", ++ FT_UINT16, BASE_DEC, VALS(nfapi_mutli_carrier_lbt_support_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_partial_sf_support, ++ { "Partial SF support", "nfapi.partial.sf.support", ++ FT_BOOLEAN, 8, TFS(&partial_sf_support_strname), 0x0, ++ "Indicates support for Partial SF in L1", HFILL } ++ }, ++ { &hf_nfapi_reference_signal_power, ++ { "Reference signal power", "nfapi.ref_sig_power", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(reference_signal_power_conversion_fn), 0x0, ++ "Normalized value levels (relative) to accommodate different absolute Tx Power used by eNb", HFILL } ++ }, ++ { &hf_nfapi_primary_synchronization_signal_epre_eprers, ++ { "Primary synchronization signal EPRE/EPRERS", "nfapi.primary.sync.signal", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(power_offset_conversion_fn), 0x0, ++ "The power of synchronization signal with respect to the reference signal, (PSS for LTE cell, NPSS for NB-IOT cell)", HFILL } ++ }, ++ { &hf_nfapi_secondary_synchronization_signal_epre_eprers, ++ { "Secondary synchronization signal EPRE/EPRERS", "nfapi.secondary.sync.signal", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(power_offset_conversion_fn), 0x0, ++ "The power of synchronization signal with respect to the reference signal, (SSS for LTE cell, NSSS for NB-IOT cell)", HFILL } ++ }, ++ { &hf_nfapi_physical_cell_id, ++ { "Physical Cell ID", "nfapi.physical.cell.id", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The Cell ID sent with the synchronization signal", HFILL } ++ }, ++ { &hf_nfapi_phich_resource, ++ { "PHICH Resource", "nfapi.phich.resource", ++ FT_UINT16, BASE_DEC, VALS(nfapi_phich_resource_vals), 0x0, ++ "The number of resource element groups used for PHICH", HFILL } ++ }, ++ { &hf_nfapi_phich_duration, ++ { "PHICH Duration", "nfapi.phich.duration", ++ FT_BOOLEAN, 8, TFS(&phich_duration_strname), 0x0, ++ "The PHICH duration for MBSFN and non-MBSFN sub-frames", HFILL } ++ }, ++ { &hf_nfapi_phich_power_offset, ++ { "PHICH Power Offset", "nfapi.phich.power.offset", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(power_offset_conversion_fn), 0x0, ++ "The power per antenna of the PHICH with respect to the reference signal", HFILL } ++ }, ++ { &hf_nfapi_configuration_index, ++ { "Configuration Index", "nfapi.configuration.index", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Provides information about the location and format of the PRACH.", HFILL } ++ }, ++ { &hf_nfapi_root_sequence_index, ++ { "Root sequence Index", "nfapi.root.sequence.index", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "PRACH Root sequence index", HFILL } ++ }, ++ { &hf_nfapi_zero_correlation_zone_configuration, ++ { "Zero correlation zone configuration", "nfapi.zero.correlation.zone.configuration", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Equivalent to Ncs", HFILL } ++ }, ++ { &hf_nfapi_high_speed_flag, ++ { "High Speed Flag", "nfapi.high.speed.flag", ++ FT_BOOLEAN, 8, TFS(&high_speed_flag_strname), 0x0, ++ "Indicates if unrestricted, or restricted, set of preambles is used", HFILL } ++ }, ++ { &hf_nfapi_frequency_offset, ++ { "Frequency offset", "nfapi.frequency.offset", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The first physical resource block available for PRACH", HFILL } ++ }, ++ { &hf_nfapi_hopping_mode, ++ { "Hopping Mode", "nfapi.hopping.mode", ++ FT_BOOLEAN, 8, TFS(&hopping_mode_strname), 0x0, ++ "If hopping is enabled indicates the type of hopping used", HFILL } ++ }, ++ { &hf_nfapi_hopping_offset, ++ { "Hopping offset", "nfapi.hopping.offset", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The offset used if hopping is enabled", HFILL } ++ }, ++ { &hf_nfapi_delta_pucch_shift, ++ { "Delta PUCCH Shift", "nfapi.delta.pucch.shift", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The cyclic shift difference", HFILL } ++ }, ++ { &hf_nfapi_n_cqi_rb, ++ { "N CQI RB", "nfapi.n.cqi.rb", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The bandwidth, in units of resource blocks, that is available for use by PUCCH formats 2/2a/2b transmission in each slot", HFILL } ++ }, ++ { &hf_nfapi_n_an_cs, ++ { "N AN CS", "nfapi.n.an.cs", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The number of cyclic shifts used for PUCCH formats 1/1a/1b in a resource block with a mix of formats 1/a/1/ab and 2/2a/2b.", HFILL } ++ }, ++ { &hf_nfapi_n1_pucch_an, ++ { "N1 PUCCH AN", "nfapi.n1.pucch.an", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "N1 PUCCH", HFILL } ++ }, ++ { &hf_nfapi_bandwidth_configuration, ++ { "Bandwidth configuration", "nfapi.bw.configuration", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The available SRS bandwidth of the cell", HFILL } ++ }, ++ { &hf_nfapi_srs_subframe_configuration, ++ { "SRS subframe configuration", "nfapi.srs.subframe.configuration", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The subframe configuration. Needed if semi-static configuration is held in PHY", HFILL } ++ }, ++ { &hf_nfapi_uplink_rs_hopping, ++ { "Uplink RS hopping", "nfapi.uplink.rs.hopping", ++ FT_UINT16, BASE_DEC, VALS(nfapi_uplink_rs_hopping_vals), 0x0, ++ "Indicates the type of hopping to use", HFILL } ++ }, ++ { &hf_nfapi_group_assignment, ++ { "Group assignment", "nfapi.group.assignment", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The sequence shift pattern used if group hopping is enabled", HFILL } ++ }, ++ { &hf_nfapi_cyclic_shift_1_for_drms, ++ { "Cyclic Shift 1 for DRMS", "nfapi.cyclic.shift.1.for.drms", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Specifies the cyclic shift for the reference signal used in the cell.", HFILL } ++ }, ++ { &hf_nfapi_subframe_assignment, ++ { "Subframe_assignment", "nfapi.subframe.assignment", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "For TDD mode only, indicates the DL/UL subframe structure", HFILL } ++ }, ++ { &hf_nfapi_special_subframe_patterns, ++ { "Special Subframe patterns", "nfapi.special.subframe.patterns", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "For TDD mode only. Length of fields DwPTS, GP and UpPTS", HFILL } ++ }, ++ { &hf_nfapi_ed_threshold_for_lbt_for_pdsch, ++ { "ED Threshold for LBT for PDSCH", "nfapi.ed.threshold.for.lbt.pdsch", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(laa_threshold_conversion_fn), 0x0, ++ "Indicates the energy detection threshold in dBm for LBT for PDSCH", HFILL } ++ }, ++ { &hf_nfapi_ed_threshold_for_lbt_for_drs, ++ { "ED Threshold for LBT for DRS", "nfapi.ed.threshold.for.lbt.for.drs", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(laa_threshold_conversion_fn), 0x0, ++ "Indicates the energy detection threshold in dBm for LBT for DRS", HFILL } ++ }, ++ { &hf_nfapi_pd_threshold, ++ { "PD Threshold", "nfapi.pd.threshold", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(laa_threshold_conversion_fn), 0x0, ++ "Indicates the preamble detection threshold in dBm, if the L1 capabilities support PD", HFILL } ++ }, ++ { &hf_nfapi_multi_carrier_type, ++ { "Multi carrier type", "nfapi.multi.carrier.type", ++ FT_UINT16, BASE_DEC, VALS(nfapi_laa_carrier_type_vals), 0x0, ++ "Indicates multi carrier type configuration of L1 (according to L1 capabilities and L2 scheduler requirements", HFILL } ++ }, ++ { &hf_nfapi_multi_carrier_tx, ++ { "Multi carrier TX", "nfapi.multi.carrier.tx", ++ FT_BOOLEAN, 8, TFS(&nfapi_multi_carrier_tx_strname), 0x0, ++ "Indicates multi carrier transmission configuration of L1 (according to type if supporting multi carrier)", HFILL } ++ }, ++ { &hf_nfapi_multi_carrier_freeze, ++ { "Multi carrier freeze", "nfapi.multi.carrier.freeze", ++ FT_BOOLEAN, 8, TFS(&nfapi_multi_carrier_freeze_strname), 0x0, ++ "Indicates multi carrier freeze, configuration of L1 (applicable only to type A type if supporting multi carrier)", HFILL } ++ }, ++ { &hf_nfapi_tx_antenna_ports_for_drs, ++ { "Tx antenna ports for DRS", "nfapi.tx.antenna.ports.for.drs", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The number of cell specific transmit antenna ports within the DRS occasions", HFILL } ++ }, ++ { &hf_nfapi_transmission_power_for_drs, ++ { "Transmission power for DRS", "nfapi.transmission.power.for.drs.", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(power_offset_conversion_fn), 0x0, ++ "Offset of cell specific Reference signals power within DRS occasions to the reference signal power", HFILL } ++ }, ++ { &hf_nfapi_pbch_repetitions_enabled_r13, ++ { "PBCH Repetitions enable R13", "nfapi.pbch.repetitions.enabled_r13", ++ FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), 0x0, ++ "Enable / Disable PBCH repetitions", HFILL } ++ }, ++ { &hf_nfapi_prach_cat_m_root_sequence_index, ++ { "PRACH CAT-M Root sequence index", "nfapi.prach.cat_m.root.squence.index", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "PRACH Root sequence index", HFILL } ++ }, ++ { &hf_nfapi_prach_cat_m_zero_correlation_zone_configuration, ++ { "PRACH CAT-M Zero correlation zone configuration", "nfapi.prach.cat_m.zero.correlation.zone.configuration", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Equivalent to Ncs", HFILL } ++ }, ++ { &hf_nfapi_prach_cat_m_high_speed_flag, ++ { "PRACH CAT-M High speed flag", "nfapi.prach.cat_m.high.speed.flag", ++ FT_BOOLEAN, 8, TFS(&high_speed_flag_strname), 0x0, ++ "Indicates if unrestricted, or restricted, set of preambles is used", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_0_enable, ++ { "PRACH CE level #0 Enable", "nfapi.prach.ce.level.0.enable", ++ FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), 0x0, ++ "Enable \\ Disable CE level #0.", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_0_configuration_index, ++ { "PRACH CE level #0 Configuration index", "nfapi.prach.ce.level.0.configuration.index", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Provides information about the location and format of the PRACH", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_0_frequency_offset, ++ { "PRACH CE level #0 Frequency offset", "nfapi.prach.ce.level.0.frequency_offset", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The first physical resource block available for PRACH for each CE", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_0_number_of_repetitions_per_attempt, ++ { "PRACH CE level #0 Number of repetitions per attempt", "nfapi.prach.ce.level.0.number.of.repetitions.per_attempt", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Number of PRACH repetitions per attempt for each CE level", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_0_starting_subframe_periodicity, ++ { "CE level #0 Starting subframe periodicity", "nfapi.prach.ce.level.0.starting.subframe_periodicity", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Optional. PRACH starting subframe periodicity, expressed in number of slots available for preamble transmission(PRACH opportunities)", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_0_hopping_enabled, ++ { "PRACH CE level #0 Hopping Enable", "nfapi.prach.ce.level.0.hopping_enable", ++ FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), 0x0, ++ "Enable \\ Disable PRACH frequency hopping for each CE level", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_0_hopping_offset, ++ { "PRACH CE level #0 Hopping Offset", "nfapi.prach.ce.level.0.hopping.offset", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Valid in case 'PRACH Hopping Enable' is enabled", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_1_enable, ++ { "PRACH CE level #1 Enable", "nfapi.prach.ce.level.0.enable", ++ FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), 0x0, ++ "Enable \\ Disable CE level #1", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_1_configuration_index, ++ { "PRACH CE level #1 Configuration index", "nfapi.prach.ce.level.1.configuration.index", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Provides information about the location and format of the PRACH", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_1_frequency_offset, ++ { "PRACH CE level #1 Frequency offset", "nfapi.prach.ce.level.1.frequency_offset", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The first physical resource block available for PRACH for each CE", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_1_number_of_repetitions_per_attempt, ++ { "PRACH CE level #1 Number of repetitions per attempt", "nfapi.prach.ce.level.1.number.of.repetitions.per_attempt", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Number of PRACH repetitions per attempt for each CE level", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_1_starting_subframe_periodicity, ++ { "CE level #1 Starting subframe periodicity", "nfapi.prach.ce.level.1.starting.subframe_periodicity", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Optional.PRACH starting subframe periodicity, expressed in number of slots available for preamble transmission(PRACH opportunities),", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_1_hopping_enabled, ++ { "PRACH CE level #1 Hopping Enable", "nfapi.prach.ce.level.1.hopping_enable", ++ FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), 0x0, ++ "Enable \\ Disable PRACH frequency hopping for each CE level.", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_1_hopping_offset, ++ { "PRACH CE level #1 Hopping Offset", "nfapi.prach.ce.level.1.hopping.offset", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Valid in case 'PRACH Hopping Enable' is enabled.", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_2_enable, ++ { "PRACH CE level #2 Enable", "nfapi.prach.ce.level.2.enable", ++ FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), 0x0, ++ "Enable \\ Disable CE level #2", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_2_configuration_index, ++ { "PRACH CE level #2 Configuration index", "nfapi.prach.ce.level.2.configuration.index", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Provides information about the location and format of the PRACH", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_2_frequency_offset, ++ { "PRACH CE level #2 Frequency offset", "nfapi.prach.ce.level.2.frequency_offset", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The first physical resource block available for PRACH for each CE", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_2_number_of_repetitions_per_attempt, ++ { "PRACH CE level #2 Number of repetitions per attempt", "nfapi.prach.ce.level.2.number.of.repetitions.per_attempt", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Number of PRACH repetitions per attempt for each CE level", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_2_starting_subframe_periodicity, ++ { "CE level #2 Starting subframe periodicity", "nfapi.prach.ce.level.2.starting.subframe_periodicity", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Optional. PRACH starting subframe periodicity, expressed in number of slots available for preamble transmission(PRACH opportunities)", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_2_hopping_enabled, ++ { "PRACH CE level #2 Hopping Enable", "nfapi.prach.ce.level.2.hopping_enable", ++ FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), 0x0, ++ "Enable \\ Disable PRACH frequency hopping for each CE level", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_2_hopping_offset, ++ { "PRACH CE level #2 Hopping Offset", "nfapi.prach.ce.level.2.hopping.offset", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Valid in case 'PRACH Hopping Enable' is enabled.", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_3_enable, ++ { "PRACH CE level #3 Enable", "nfapi.prach.ce.level.3.enable", ++ FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), 0x0, ++ "Enable \\ Disable CE level #3.", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_3_configuration_index, ++ { "PRACH CE level #3 Configuration index", "nfapi.prach.ce.level.3.configuration.index", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Provides information about the location and format of the PRACH.", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_3_frequency_offset, ++ { "PRACH CE level #3 Frequency offset", "nfapi.prach.ce.level.3.frequency_offset", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The first physical resource block available for PRACH for each CE", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_3_number_of_repetitions_per_attempt, ++ { "PRACH CE level #3 Number of repetitions per attempt", "nfapi.prach.ce.level.3.number.of.repetitions.per_attempt", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Number of PRACH repetitions per attempt for each CE level", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_3_starting_subframe_periodicity, ++ { "CE level #3 Starting subframe periodicity", "nfapi.prach.ce.level.3.starting.subframe_periodicity", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Optional. PRACH starting subframe periodicity, expressed in number of slots available for preamble transmission(PRACH opportunities)", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_3_hopping_enabled, ++ { "PRACH CE level #3 Hopping Enable", "nfapi.prach.ce.level.3.hopping_enable", ++ FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), 0x0, ++ "Enable \\ Disable PRACH frequency hopping for each CE level.", HFILL } ++ }, ++ { &hf_nfapi_prach_ce_level_3_hopping_offset, ++ { "PRACH CE level #3 Hopping Offset", "nfapi.prach.ce.level.3.hopping.offset", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Valid in case 'PRACH Hopping Enable' is enabled.", HFILL } ++ }, ++ { &hf_nfapi_pucch_internal_ul_hopping_config_common_mode_a, ++ { "PUCCH Interval-ULHoppingConfigCommonModeA", "nfapi.pucch.interval.ulhopping.config.common.mode.a", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "NthULNB for UEModeA", HFILL } ++ }, ++ { &hf_nfapi_pucch_internal_ul_hopping_config_common_mode_b, ++ { "PUCCH Interval-ULHoppingConfigCommonModeB", "nfapi.pucch.interval.ulhopping.config.common.mode.b", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "NthULNB for UEModeB", HFILL } ++ }, ++ { &hf_nfapi_data_report_mode, ++ { "Data Report Mode", "nfapi.data.report.mode", ++ FT_BOOLEAN, 8, TFS(&data_report_mode_vals), 0x0, ++ "The data report mode for the uplink data", HFILL } ++ }, ++ { &hf_nfapi_sfnsf, ++ { "SFN/SF", "nfapi.sfn.sf", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(sfn_sf_conversion_fn), 0x0, ++ "The future SFN/SF subframe where the TLVs included in the message should be applied", HFILL } ++ }, ++ { &hf_nfapi_max_up_pts, ++ { "Max UpPTS frames", "nfapi.max.uppts.frame", ++ FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), 0x0, ++ "Used for TDD only and indicates how SRS operates in UpPTS subframes", HFILL } ++ }, ++ { &hf_nfapi_srs_acknack_srs_simultaneous_transmission, ++ { "SRS AckNack Simultaneous transmission", "nfapi.srs.acknack.simult.tx", ++ FT_BOOLEAN, 8, TFS(&srs_simult_tx_strname), 0x0, ++ "Indicates if SRS and ACK/NACK can be received in the same subframe. Needed if semi-static configuration is held in PHY.", HFILL } ++ }, ++ { &hf_nfapi_pnf_address_ipv4, ++ { "PNF IPV4", "nfapi.pnf.address.ipv4", ++ FT_IPv4, BASE_NONE, NULL, 0x0, ++ "The IPv4 address of the PNF PHY instance to be used by the VNF for this PNF PHY instance", HFILL } ++ }, ++ { &hf_nfapi_pnf_address_ipv6, ++ { "PNF IPV6", "nfapi.pnf.address.ipv6", ++ FT_IPv6, BASE_NONE, NULL, 0x0, ++ "The IPv6 address of the PNF PHY instance to be used by the VNF for this PNF PHY instance", HFILL } ++ }, ++ { &hf_nfapi_vnf_address_ipv4, ++ { "VNF IPV4 Address", "nfapi.vnf.address.ipv4", ++ FT_IPv4, BASE_NONE, NULL, 0x0, ++ "The IPv4 address of the VNF to be used by the PNF for this P7 PHY instance", HFILL } ++ }, ++ { &hf_nfapi_vnf_address_ipv6, ++ { "VNF IPV6 Address", "nfapi.vnf.address.ipv6", ++ FT_IPv6, BASE_NONE, NULL, 0x0, ++ "The IPv6 address of the VNF to be used by the PNF for this P7 PHY instance", HFILL } ++ }, ++ { &hf_nfapi_pnf_port, ++ { "PNF PORT value", "nfapi.config.pnf.port.value", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The port of the PNF PHY instance to be used by the VNF for this PNF PHY instance", HFILL } ++ }, ++ { &hf_nfapi_vnf_port, ++ { "VNF PORT value", "nfapi.config.vnf.port.value", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The port of the VNF to be used by the PNF for this P7 PHY instance", HFILL } }, ++ { &hf_nfapi_sync_mode, ++ { "Sync Mode", "nfapi.sync.mode", ++ FT_UINT8, BASE_DEC, VALS(nfapi_sync_mode_vals), 0x0, ++ "The method of nFAPI Synchronization supported by the PNF", HFILL } ++ }, ++ { &hf_nfapi_location_mode, ++ { "Location Mode", "nfapi.location.mode", ++ FT_UINT8, BASE_DEC, VALS(location_mode_vals), 0x0, ++ "The method of location derivation supported by the PNF", HFILL } ++ }, ++ { &hf_nfapi_location_coordinates_length, ++ { "Location Coordinates Length", "nfapi.location.coordinates.length", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Length in bytes of the Location Coordinates Array field", HFILL } ++ }, ++ { &hf_nfapi_location_coordinates, ++ { "Location Coordinates", "nfapi.location.coordinates", ++ FT_BYTES, BASE_NONE, NULL, 0x0, ++ "The Location of the PNF. The value is formatted as the LocationCoordinates IE using BASIC-PER encoding as defined in " ++ "TS36.355 section 6.4.2. The first bit of the LocationCoordinates IE is in the LSB of the first byte of the array." ++ "The MSBs of the last element of the array may be padded with zeros if the ASN.1 element is not an integer number of bytes", HFILL } ++ }, ++ { &hf_nfapi_pdu, ++ { "PDU", "nfapi.pdu", ++ FT_BYTES, BASE_NONE, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_dl_config_timing, ++ { "DL config Timing", "nfapi.dl.config.timing", ++ FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &units_milliseconds, 0x0, ++ "The timing offset before the air interface subframe start that the DL_Config.request must be received at the PNF.", HFILL } ++ }, ++ { &hf_nfapi_tx_timing, ++ { "Tx Timing", "nfapi.general.tx.timing", ++ FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &units_milliseconds, 0x0, ++ "The timing offset before the air interface subframe start that the TX.request must be received at the PNF.", HFILL } ++ }, ++ { &hf_nfapi_ul_config_timing, ++ { "UL Config Timing", "nfapi.ul.config.timing", ++ FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &units_milliseconds, 0x0, ++ "The timing offset before the air interface subframe start that the UL_CONFIG.request must be received at the PNF.", HFILL } ++ }, ++ { &hf_nfapi_hi_dci0_timing, ++ { "HI DCi0 Timing", "nfapi.hi.dci0.timing", ++ FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &units_milliseconds, 0x0, ++ "The timing offset before the air interface subframe start that the HI_DCI0.request must be received at the PNF.", HFILL } ++ }, ++ { &hf_nfapi_maximum_number_phys, ++ { "Maximum number of Phys", "nfapi.maximum.number.phys", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The maximum number of operational PHYs supported by the PNF device.", HFILL } ++ }, ++ { &hf_nfapi_maximum_total_bandwidth, ++ { "Maximum Total Bandwidth", "nfapi.maximum.total.bandwidth", ++ FT_UINT16, BASE_DEC | BASE_UNIT_STRING, &khz_100_units_db, 0x0, ++ "The total maximum bandwidth (in units of 100kHz) supported by the PNF device.", HFILL } ++ }, ++ { &hf_nfapi_maximum_total_number_dl_layers, ++ { "Maximum Total Number DL Layers", "nfapi.maximum.total.number.dl.layers", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The maximum total number of downlink layers supported.", HFILL } ++ }, ++ { &hf_nfapi_maximum_total_number_ul_layers, ++ { "Maximum Total Number UL Layers", "nfapi.maximum.total.number.ul.layers", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The maximum total number of uplink layers supported across all available PHYs.", HFILL } ++ }, ++ { &hf_nfapi_shared_bands, ++ { "Shared bands", "nfapi.shared.bands", ++ FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x0, ++ "Indication that the PNF device shares the list of RF band options available across all available PHYs, so each may only be used with a single PHY.", HFILL } ++ }, ++ { &hf_nfapi_shared_pa, ++ { "Shared pa", "nfapi.shared.pa", ++ FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x0, ++ "Indication that the PNF device shares a single RF PA across all available PHYs, so that the maximum Total Power is shared across all available PHYs.", HFILL } ++ }, ++ { &hf_nfapi_maximum_total_power, ++ { "Maximum total power", "nfapi.maximum.total.power", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(dl_rs_tx_pow_measment_conversion_fn), 0x0, ++ "The maximum transmit power of the PNF device summed across all PHYs.", HFILL } ++ }, ++ { &hf_nfapi_oui, ++ { "OUI", "nfapi.oui", ++ FT_STRING, BASE_NONE, NULL, 0x0, ++ "The PNF OUI in the format as specified by IEEE", HFILL } ++ }, ++ { &hf_nfapi_pnf_phy_number_phy, ++ { "PNF Phy Number of Phy", "nfapi.pnf.phy.number.phy", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The number of PHY instances", HFILL } ++ }, ++ { &hf_nfapi_pnf_phy_config_index, ++ { "PNF Phy Config Index", "nfapi.pnf.phy.config.index", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The unique index number of the PHY to permit the PNF to identify the PHY in the PNF_CONFIG.Request", HFILL } ++ }, ++ { &hf_nfapi_number_of_rfs, ++ { "Number of RFs", "nfapi.pnf.rf.number.rf", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The number of RF configurations", HFILL } ++ }, ++ { &hf_nfapi_phy_rf_config_info_phy_id, ++ { "Phy ID", "nfapi.pnf.phy.rf.config.phy.id", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_rf_config_index, ++ { "RF Config Index", "nfapi.rf_config_index", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The index number defined in the PNF RF struct that the PHY can support", ++ HFILL } ++ }, ++ { &hf_nfapi_number_of_rf_exclusions, ++ { "Number of RF exclusions", "nfapi.hf_nfapi_number_of_rf_exclusions", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The number of RF configurations excluded from use by this PHY", HFILL } ++ }, ++ { &hf_nfapi_maximum_3gpp_release_supported, ++ { "Maximum 3gpp Release Supported", "nfapi.maximum_3gpp_release_supported", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The major 3GPP releases supported", HFILL } ++ }, ++ { &hf_nfapi_maximum_3gpp_release_supported_rel8, ++ { "Release 8", "nfapi.maximum_3gpp_release_supported.rel8", ++ FT_BOOLEAN, 1, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_maximum_3gpp_release_supported_rel9, ++ { "Release 9", "nfapi.maximum_3gpp_release_supported.rel9", ++ FT_BOOLEAN, 1, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_maximum_3gpp_release_supported_rel10, ++ { "Release 10", "nfapi.maximum_3gpp_release_supported.rel10", ++ FT_BOOLEAN, 1, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_maximum_3gpp_release_supported_rel11, ++ { "Release 11", "nfapi.maximum_3gpp_release_supported.rel11", ++ FT_BOOLEAN, 1, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_maximum_3gpp_release_supported_rel12, ++ { "Release 12", "nfapi.maximum_3gpp_release_supported.rel12", ++ FT_BOOLEAN, 1, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_maximum_3gpp_release_supported_rel13, ++ { "Release 13", "nfapi.maximum_3gpp_release_supported.rel13", ++ FT_BOOLEAN, 1, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_downlink_channel_bandwidth_supported, ++ { "Maximum Channel Downlink Bandwidth Supported", "nfapi.downlink_channel_bandwidth_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The downlink channel bandwidth supported in resource blocks as specified in 3GPP TS 36.104", HFILL } ++ }, ++ { &hf_nfapi_uplink_channel_bandwidth_supported, ++ { "Maximum Channel Uplink Bandwidth Supported", "nfapi.uplink_channel_bandwidth_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The uplink channel bandwidth supported in resource blocks as specified in 3GPP TS 36.104.", HFILL } ++ }, ++ { &hf_nfapi_number_of_dl_layers_supported, ++ { "Number of DL Layers Supported", "nfapi.number_of_dl_layer_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The maximum number of downlink layers supported", HFILL } ++ }, ++ { &hf_nfapi_number_of_ul_layers_supported, ++ { "Number of UL Layers Supported", "nfapi.number_of_ul_layer_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The maximum number of uplink layers supported", HFILL } ++ }, ++ { &hf_nfapi_nmm_modes_supported, ++ { "NMM modes supported", "nfapi.nmm_modes_supported", ++ FT_UINT8, BASE_DEC, VALS(nmm_modes_supported_vals), 0x0, ++ "Network Monitor Modes Supported.", HFILL } ++ }, ++ { &hf_nfapi_band, ++ { "Band", "nfapi.band", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Band number as specified in 3GPP TS36.101", HFILL } ++ }, ++ { &hf_nfapi_maximum_transmit_power_2, ++ { "Maximum transmit power", "nfapi.maximum_transmit_power", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(max_transmit_power_2_conversion_fn), 0x0, ++ "The maximum transmit power for the PHY and RF operating at the configured bandwidth as defined in 3GPP TS 36.104.", HFILL } ++ }, ++ { &hf_nfapi_maximum_transmit_power, ++ { "Maximum transmit power", "nfapi.maximum_transmit_power", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(max_transmit_power_conversion_fn), 0x0, ++ "The maximum transmit power for the RF chain operating at the maximum supported bandwidth as defined in 3GPP TS 36.104.", HFILL } ++ }, ++ { &hf_nfapi_earfcn, ++ { "EARFCN", "nfapi.earfcn", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The EARFCN to be measured.", HFILL } ++ }, ++ { &hf_nfapi_number_of_rf_bands, ++ { "Number of RF Bands", "nfapi.num.rf_bands", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The number of RF Band instances", HFILL } ++ }, ++ { &hf_nfapi_nmm_uplink_rssi_supported, ++ { "NMM Uplink RSSI supported", "nfapi.nmm.uplink.rssi.supported", ++ FT_UINT8, BASE_DEC, VALS(ul_rssi_supported_vals), 0x0, ++ "Indicates if the uplink RSSI meausremnts are supported by NMM.", HFILL } ++ }, ++ { &hf_nfapi_minimum_transmit_power, ++ { "Minimum transmit power", "nfapi.minimum_transmit_power", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(max_transmit_power_conversion_fn), 0x0, ++ "The minimum transmit power for the RF chain operating at the maximum supported bandwidth as defined in 3GPP TS 36.104.", HFILL } ++ }, ++ { &hf_nfapi_number_of_antennas_suppported, ++ { "Number of Supported Antennas", "nfapi.number_of_antennas_suppported", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The maximum number of antennas supported.", HFILL } ++ }, ++ { &hf_nfapi_minimum_downlink_frequency, ++ { "Minimum downlink frequency", "nfapi.minimum_downlink_frequency", ++ FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &khz_100_units_db, 0x0, ++ "The minimum supported downlink frequency in 100kHz units", HFILL } ++ }, ++ { &hf_nfapi_maximum_downlink_frequency, ++ { "Maximum downlink frequency", "nfapi.maximum_downlink_frequency", ++ FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &khz_100_units_db, 0x0, ++ "The maximum supported downlink frequency in 100kHz units", HFILL } ++ }, ++ { &hf_nfapi_minimum_uplink_frequency, ++ { "Minimum uplink frequency", "nfapi.minimum_downlink_frequency", ++ FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &khz_100_units_db, 0x0, ++ "The minimum supported uplink frequency in 100kHz units", HFILL } ++ }, ++ { &hf_nfapi_maximum_uplink_frequency, ++ { "Maximum uplink frequency", "nfapi.maximum_downlink_frequency", ++ FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &khz_100_units_db, 0x0, ++ "The maximum supported uplink frequency in 100kHz units", HFILL } ++ }, ++ { &hf_nfapi_transmission_mode7_supported, ++ { "Transmission Mode 7 Supported", "nfapi.pnf.phy_rel10.tx_mode7_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports TM7 for PDSCH", HFILL } ++ }, ++ { &hi_nfapi_transmission_mode8_supported, ++ { "Transmission Mode 8 Supported", "nfapi.pnf.phy_rel10.tx_mode8_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports TM8 for PDSCH", HFILL } ++ }, ++ { &hi_nfapi_two_antennas_ports_for_pucch, ++ { "Two antennas ports for PUCCH", "nfapi.pnf.phy_rel10.two_antennas_ports_for_pucch", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports PUCCH transmit diversity introduced in Release 10. Equivalent to two-AntennaPortsForPUCCH-r10 in TS36.306", HFILL } ++ }, ++ { &hi_nfapi_transmission_mode_9_supported, ++ { "Transmission Mode 9 Supported", "nfapi.pnf.phy_rel10.tx_mode9_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports TM9 for PDSCH with 8 antennas and 8 CSI. Equivalent to tm9-With-8Tx-FDD-r10 in TS36.306", HFILL } ++ }, ++ { &hi_nfapi_simultaneous_pucch_pusch, ++ { "Simultaneous PUCCH PUSCH", "nfapi.pnf.simultaneous_pucch_pusch", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports UE sending simultaneous PUCCH and PUSCH introduced in Release 10. Equivalent to simultaneousPUCCH-PUSCH-r10 in TS36.306", HFILL } ++ }, ++ { &hi_nfapi_four_layer_tx_with_tm3_and_tm4, ++ { "Four layer Tx with TM3 and TM4", "nfapi.pnf.phy_rel10.layer_tx_with_tm3_and_tm4", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports four layer transmission for TM3 and TM4. Equivalent to fourLayerTM3-TM4-r10 in TS36.306", HFILL } ++ }, ++ { &hf_nfapi_epdcch_supported, ++ { "ePDCCH supported", "nfapi.pnf.phy_rel11.epdcch_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports Enhanced PDCCH", HFILL } ++ }, ++ { &hi_nfapi_multi_ack_csi_reporting, ++ { "Multi ACK CSI reporting", "nfapi.pnf.phy_rel11.mutli_ack_csi_reporting", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports the multi ACK and CSI reporting required with CA and mixed FDD/TDD carriers. Equivalent to multiACK-CSI-Reporting-r11 in TS36.306", HFILL } ++ }, ++ { &hi_nfapi_pucch_tx_diversity_with_channel_selection, ++ { "PUCCH Tx diversity with channel selection", "nfapi.pnf.phy_rel11.tx_div_with_channel_selection", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports transmit diversity for PUCCH format 1b with channel selection. Equivalent to txDiv-PUCCH1b-ChSelect in TS36.306", HFILL } ++ }, ++ { &hi_nfapi_ul_comp_supported, ++ { "UL CoMP supported", "nfapi.pnf.phy_rel11.ul_comp_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports UL CoMP", HFILL } ++ }, ++ { &hi_nfapi_transmission_mode_5_supported, ++ { "Transmission mode 5 supported", "nfapi.pnf.phy_rel11.tx_mode5_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports TM5 for PDSCH", HFILL } ++ }, ++ { &hf_nfapi_csi_subframe_set, ++ { "CSI subframe set", "nfapi.pnf.phy_rel12.csi_subframe_set", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Equivalent to csi-SubframeSet-r12 in TS36.306", HFILL } ++ }, ++ { &hi_nfapi_enhanced_4tx_codebook, ++ { "Enhanced 4TX codebook", "nfapi.pnf.phy_rel12.exhanced_t4x_codebook", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports the enhanced 4TX codebook. Equivalent to enhanced-4TxCodebook-r12 in TS36.306", HFILL } ++ }, ++ { &hi_nfapi_drs_supported, ++ { "DRS supported", "nfapi.pnf.phy_rel12.drs_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports the Discovery Reference Signal", HFILL } ++ }, ++ { &hi_nfapi_ul_64qam_supported, ++ { "UL 64QAM supported", "nfapi.pnf.phy_rel12.ul_64qam_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY support 64 QAM in the uplink", HFILL } ++ }, ++ { &hi_nfapi_transmission_mode_10_supported, ++ { "Transmission mode 10 supported", "nfapi.pnf.phy_rel12.tx_mode10_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports TM10 for PDSCH (DL CoMP)", HFILL } ++ }, ++ { &hi_nfapi_alternative_tbs_indices, ++ { "Alternative TBS indices", "nfapi.pnf.phy_rel12.alternative_tbs_indices", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports the alternate TBS indices (256 QAM). Equivalent to alternativeTBS-Indices-r12 in TS36.306", HFILL } ++ }, ++ { &hf_nfapi_pucch_format_4_supported, ++ { "PUCCH format 4 supported", "nfapi.pnf.phy_rel13.pucch_format4_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports PUCCH format 4", HFILL } ++ }, ++ { &hf_nfapi_pucch_format_5_supported, ++ { "PUCCH format 5 supported", "nfapi.pnf.phy_rel13.pucch_format5_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports PUCCH format 5", HFILL } ++ }, ++ { &hf_nfapi_more_than_5_ca_supported, ++ { "More than 5 CA support", "nfapi.pnf.phy_rel13.mode_than_5_ca_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports features required for more than 5 CA support on PUSCH. Equivalent to uci-PUSCH-Ext-r13 in TS36.306", HFILL } ++ }, ++ { &hf_nfapi_laa_supported, ++ { "LAA supported", "nfapi.pnf.phy_rel13.laa_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports DL LAA (subframe format 3)", HFILL } ++ }, ++ { &hf_nfapi_laa_ending_in_dwpts_supported, ++ { "LAA ending in DwPTS supported", "nfapi.pnf.phy_rel13.laa_ending_in_dwpts_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports DL LAA ending in a DwPTS subframe. Equivalent to endingDwPTS-r13i n TS36.306", HFILL } ++ }, ++ { &hf_nfapi_laa_starting_in_second_slot_supported, ++ { "LAA starting in second slot Supported", "nfapi.pnf.phy_rel13.laa_starting_in_second_slot_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports DL LAA starting in the second slot in a subframe. Equivalent to secondSlotStartingPosition-r13 in TS36.306", HFILL } ++ }, ++ { &hf_nfapi_beamforming_supported, ++ { "Beamforming Supported", "nfapi.pnf.phy_rel13.beamingforming_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports beamforming (FD-MIMO Class B). Equivalent to beamformed-r13 in TS36.306", HFILL } ++ }, ++ { &hf_nfapi_csi_rs_enhancements_supported, ++ { "CSI-RS enhancements supported", "nfapi.pnf.phy_rel13.csi_rs_enchancements_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports CSI-RS enhancements (FD-MIMO Class A). Equivalent to csi-RS-EnhancementsTDD-r13 in TS36.306", HFILL } ++ }, ++ { &hf_nfapi_drms_enhancements_supported, ++ { "DMRS enhancements supported", "nfapi.pnf.phy_rel13.drms_enhancements_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports DMRS enhancements added in Release 13. Equivalent to dmrs-Enhancements-r13 in TS36.306", HFILL } ++ }, ++ { &hf_nfapi_srs_enhancements_supported, ++ { "SRS enhancements supported", "nfapi.pnf.phy_rel13.srs_enhancements_supported", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates if PHY supports SRS enhancements added in Release 13. Equivalent to srs-Enhancements-r13in TS36.306", HFILL } ++ }, ++ { &hf_nfapi_sfn_sf, ++ { "SFN_SF", "nfapi.sfn_sf", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(sfn_sf_conversion_fn), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_number_pdcch_ofdm_symbols, ++ { "Number of PDCCH OFDM Symbols", "nfapi.number_pdcch_ofdm_symbols", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of OFDM symbols for the PDCCH", HFILL } ++ }, ++ { &hf_nfapi_number_dci, ++ { "Number of DCI", "nfapi.number_dci", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of DCI PDUs included in this message", HFILL } ++ }, ++ { &hf_nfapi_number_pdus, ++ { "Number of PDUs", "nfapi.number_pdu", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Number of PDUs that are included in this message", HFILL } ++ }, ++ { &hf_nfapi_number_of_harqs, ++ { "Number of HARQs", "nfapi.number_harqs", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Number of HARQs included in this message", HFILL } ++ }, ++ { &hf_nfapi_number_of_crcs, ++ { "Number of CRCs", "nfapi.number_crcs", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Number of CRCs included in this message", HFILL } ++ }, ++ { &hf_nfapi_number_of_srs, ++ { "Number of SRs", "nfapi.number_srs", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Number of SRs included in this message", HFILL } ++ }, ++ { &hf_nfapi_number_of_cqi, ++ { "Number of CQIs", "nfapi.number_cqi", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Number of CQIs included in this message", HFILL } ++ }, ++ { &hf_nfapi_number_of_preambles, ++ { "Number of Preambles", "nfapi.number_preambles", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Number of RACH preambles", HFILL } ++ }, ++ { &hf_nfapi_number_of_srss, ++ { "Number of SRSs", "nfapi.number_srss", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Number of UEs contributing to the uplink SRS", HFILL } ++ }, ++ { &hf_nfapi_lbt_dl_req_pdu_type, ++ { "LBT DL Request PDU Type", "nfapi.number_srss", ++ FT_UINT16, BASE_DEC, VALS(nfapi_lbt_dl_req_pdu_type), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_lbt_dl_ind_pdu_type, ++ { "LBT DL Indication PDU Type", "nfapi.number_srss", ++ FT_UINT16, BASE_DEC, VALS(nfapi_lbt_dl_ind_pdu_type), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_number_pdsch_rnti, ++ { "Number of PDSCH RNTI", "nfapi.number_pdsch_rnti", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Number of unique RNTIs sent on the PDSCH", HFILL } ++ }, ++ { &hf_nfapi_transmission_power_pcfich, ++ { "Transmission Power PCFICH", "nfapi.transmission_power_pcfich", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(power_offset_conversion_fn), 0x0, ++ "Offset to the reference signal power.", HFILL } ++ }, ++ { &hf_nfapi_dl_config_pdu_type, ++ { "PDU Type", "nfapi.pdu.type", ++ FT_UINT8, BASE_DEC, VALS(nfapi_dl_config_pdu_type_vals), 0x0, ++ "DL_CONFIG.request PDU Type", HFILL } ++ }, ++ { &hf_nfapi_pdu_size, ++ { "PDU size", "nfapi.pdu.size", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Size of the PDU control information (in bytes). This length value includes the 2 bytes required for the PDU type and PDU size parameters", HFILL } ++ }, ++ { &hf_nfapi_instance_length, ++ { "Instance length", "nfapi.instance.length", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The Length in bytes of all TLVs within this instance", HFILL } ++ }, ++ { &hf_nfapi_length, ++ { "PDU length", "nfapi.pdu.length", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Length of PDU in bytes.", HFILL } ++ }, ++ { &hf_nfapi_pdu_index, ++ { "PDU Index", "nfapi.pdu.index", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The PDU index parameter specified for each PDU", HFILL } ++ }, ++ { &hf_nfapi_rnti, ++ { "RNTI", "nfapi.rnti", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The RNTI used for identifying the UE when receiving the PDU", HFILL } ++ }, ++ { &hf_nfapi_resource_allocation_type, ++ { "Resource Allocation Type", "nfapi.resource.allocation.type", ++ FT_UINT8, BASE_DEC, VALS(resource_allocation_type_vals), 0x0, ++ "Resource allocation type/header Valid for DCI formats : 1, 2, 2A, 2B, 2C, 2D", HFILL } ++ }, ++ { &hf_nfapi_virtual_resource_block_assignment_flag, ++ { "Virtual resource block assignment flag", "nfapi.resource.block.assignment.flag", ++ FT_UINT8, BASE_DEC, VALS(local_distributed_vals), 0x0, ++ "Type of virtual resource block used Valid for DCI formats : 1A, 1B, 1D", HFILL } ++ }, ++ { &hf_nfapi_resource_block_coding, ++ { "Resource block coding", "nfapi.resource.block.coding", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "The encoding for the resource blocks. The coding is dependent on whether resource allocation type 0, 1, 2 is in use", HFILL } ++ }, ++ { &hf_nfapi_modulation, ++ { "Modulation", "nfapi.modulation", ++ FT_UINT8, BASE_DEC, VALS(modulation_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_redundancy_version, ++ { "Redundancy version", "nfapi.redundancy.version", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "HARQ redundancy version", HFILL } ++ }, ++ { &hf_nfapi_transport_blocks, ++ { "Transport blocks", "nfapi.transport.blocks", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The transport block transmitted to this RNTI", HFILL } ++ }, ++ { &hf_nfapi_transport_block_to_codeword_swap_flag, ++ { "Transport block to codeword swap flag", "nfapi.transport.block.to.codeword.swap.flag", ++ FT_UINT8, BASE_DEC, VALS(transport_block_to_codeword_swap_flag_vals), 0x0, ++ "Indicates the mapping of transport block to codewords.", HFILL } ++ }, ++ { &hf_nfapi_transmission_scheme, ++ { "Transmission scheme", "nfapi.transmission.scheme", ++ FT_UINT8, BASE_DEC, VALS(transmission_scheme_vals), 0x0, ++ "The MIMO mode used in the PDU", HFILL } ++ }, ++ { &hf_nfapi_ul_transmission_scheme, ++ { "Transmission scheme", "nfapi.transmission.scheme", ++ FT_UINT8, BASE_DEC, VALS(ul_transmission_scheme_vals), 0x0, ++ "The MIMO mode used in the PDU", HFILL } ++ }, ++ { &hf_nfapi_number_of_layers, ++ { "Number of layers", "nfapi.number.of.layers", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of layers used in transmission", HFILL } ++ }, ++ { &hf_nfapi_number_of_subbands, ++ { "Number of subbands", "nfapi.number.of.subbands", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Only valid when transmission scheme = 3, 4, 5. Defines the number of subbands and " ++ "codebooks used for PMI.If value = 1 then a single PMI value is supplied which should be used over all RB", HFILL } ++ }, ++ { &hf_nfapi_codebook_index, ++ { "Codebook index", "nfapi.number.of.codebook.index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Only valid when transmission scheme = 3, 4, 5. Defines the codebook used.", HFILL } ++ }, ++ { &hf_nfapi_ue_category_capacity, ++ { "UE category capacity", "nfapi.ue.category.capacity", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The UE capabilities category", HFILL } ++ }, ++ { &hf_nfapi_pa, ++ { "P-A", "nfapi.pa", ++ FT_UINT8, BASE_DEC, VALS(pa_vals), 0x0, ++ "The ratio of PDSCH EPRE to cell-specific RS EPRE among PDSCH REs in all the OFDM symbols not containing cell-specific RS in dB.", HFILL } ++ }, ++ { &hf_nfapi_delta_power_offset_index, ++ { "Delta Power offset index", "nfapi.delta.power.offset.index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Delta power offset, value: 0..1", HFILL } ++ }, ++ { &hf_nfapi_nprb, ++ { "Nprb", "nfapi.nprb", ++ FT_UINT8, BASE_DEC, VALS(nprb_vals), 0x0, ++ "Used with DCI format 1A and RNTI=SI-RNTI or RA-RNTI. This should match the value sent in the TPC field of the DCI 1A PDU which allocated this grant.", HFILL } ++ }, ++ { &hf_nfapi_transmission_mode, ++ { "Transmission Mode", "nfapi.transmission_nprb", ++ FT_UINT8, BASE_DEC, VALS(transmission_mode_vals), 0x0, ++ "Transmission mode associated with the UE", HFILL } ++ }, ++ { &hf_nfapi_prnti, ++ { "P-RNTI", "nfapi.prnti", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The P-RNTI associated with the paging", HFILL } ++ }, ++ { &hf_nfapi_mcs, ++ { "MCS", "nfapi.mcs", ++ FT_UINT8, BASE_DEC, VALS(pch_modulation_vals), 0x0, ++ "The modulation and coding scheme for the transport block", HFILL } ++ }, ++ { &hf_nfapi_number_of_transport_blocks, ++ { "Number of transport blocks", "nfapi.number_of_transport_blocks", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of transport blocks transmitted to this RNTI", HFILL } ++ }, ++ { &hf_nfapi_ue_mode, ++ { "UE Mode", "nfapi.ue.mode", ++ FT_UINT8, BASE_DEC, VALS(ue_mode_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_prs_bandwidth, ++ { "PRS bandwidth", "nfapi.prs.bandwidth", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "PRS bandwidth in resource blocks.", HFILL } ++ }, ++ { &hf_prs_cyclic_prefix_type, ++ { "PRS cyclic prefix type", "nfapi.prs.cyclic.prefix.type", ++ FT_BOOLEAN, 8, TFS(&prs_cyclic_prefix_type_strname), 0x0, ++ "The cyclic prefix used for PRS transmission", HFILL } ++ }, ++ { &hf_prs_muting, ++ { "PRS muting", "nfapi.prs.muting", ++ FT_BOOLEAN, 8, TFS(&prs_muting_strname), 0x0, ++ "PRS muting dictates if PRS REs are vacant (prsMutingInfo-r9 indicates the SF occasions)", HFILL } ++ }, ++ { &hf_nfapi_num_bf_prb_per_subband, ++ { "Num of BF PRB per Subband", "nfapi.num.bf.prb.per.subband", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Number of PRBs that are treated as one subband", HFILL } ++ }, ++ { &hf_nfapi_num_bf_vector, ++ { "Num of BF Vector", "nfapi.num.bf.vector", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Number of beam forming vectors. One beam forming vector is specified for each subband", HFILL } ++ }, ++ { &hf_nfapi_csi_rs_resource_config, ++ { "CSI-RS resource config", "nfapi.csi.rs.resource.config", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates reference signal configuration for CSI-RS", HFILL } ++ }, ++ { &hf_nfapi_bf_vector_subband_index, ++ { "BF Subband Index", "nfapi.num.bf.vector.subband.index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Index of subband for which the following beam forming vector is applied", HFILL } ++ }, ++ { &hf_nfapi_bf_vector_num_antennas, ++ { "BF Num of Antennas", "nfapi.num.bf.vector.bf.value", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Number of physical antennas", HFILL } ++ }, ++ { &hf_nfapi_bf_vector_bf_value, ++ { "BF Value per Antenna", "nfapi.num.bf.vector.bf.value", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Beam forming vector element for physical antenna #i real 8 bits followed by imaginary 8 bits", HFILL } ++ }, ++ { &hf_nfapi_nscid, ++ { "NSC id", "nfapi.nscid", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Used with DCI format 2B and 2C.", HFILL } ++ }, ++ { &hf_nfapi_csi_rs_flag, ++ { "CSI RS Flag", "nfapi.csi.rs.flag", ++ FT_BOOLEAN, 8, TFS(&csi_rs_flags_strname), 0x0, ++ "Indicates if parameters related to CSI-RS are valid or not.", HFILL } ++ }, ++ { &hf_nfapi_csi_rs_resource_config_r10, ++ { "CSI RS resource config R10", "nfapi.csi.rs.resource_config_r10", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "This value is deprecated", HFILL } ++ }, ++ { &hf_nfapi_csi_rs_zero_tx_power_resource_config_bitmap_r10, ++ { "CSI-RS Number of NZP configuration", "nfapi.csi.rs.num.of.nzp.configurations", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Bitmap of 16 bits. Encoding format of bitmap follows section 6.10.5.2 of 36.211", HFILL } ++ }, ++ { &hf_nfapi_csi_rs_number_of_nzp_configurations, ++ { "CSI RS zero Tx Power Resource config bitmap R10", "nfapi.csi.rs.zero.tx.power.resource.config.bitmap.r10", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates the number of Non-Zero power CSI-RS configurations.", HFILL } ++ }, ++ { &hf_nfapi_pdsch_start, ++ { "PDSCH_start", "nfapi.pdsch.start", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Per UE starting OFDM symbol for the PDSCH, impacts the mapping of PDSCH to REs", HFILL } ++ }, ++ { &hf_nfapi_drms_config_flag, ++ { "DMRS Config flag", "nfapi.drms.config.flag", ++ FT_UINT8, BASE_DEC, VALS(not_used_enabled_vals), 0x0, ++ "Indicates if the DMRS Config parameter is valid", HFILL } ++ }, ++ { &hf_nfapi_drms_scrambling, ++ { "DMRS Scrambling", "nfapi.drms.scrambling", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The scrambling identity for UE specific reference signals.", HFILL } ++ }, ++ { &hf_nfapi_csi_config_flag, ++ { "CSI Config flag", "nfapi.csi.config.flag", ++ FT_UINT8, BASE_DEC, VALS(not_used_enabled_vals), 0x0, ++ "Indicates if the CSI Config parameter is valid", HFILL } ++ }, ++ { &hf_nfapi_csi_scrambling, ++ { "CSI Scrambling", "nfapi.csi.scrambling", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The scrambling identity for CSI.", HFILL } ++ }, ++ { &hf_nfapi_pdsch_re_mapping_flag, ++ { "PDSCH RE mapping flag", "nfapi.pdsch.remapping.flag", ++ FT_UINT8, BASE_DEC, VALS(not_used_enabled_vals), 0x0, ++ "Indicates if the PDSCH RE parameters are valid.", HFILL } ++ }, ++ { &hf_nfapi_pdsch_re_mapping_antenna_ports, ++ { "PDSCH RE mapping antenna ports", "nfapi.pdsch.remapping.antenna.ports", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates number of antennas used for PDSCH RE mapping", HFILL } ++ }, ++ { &hf_nfapi_pdsch_re_mapping_freq_shift, ++ { "PDSCH RE mapping freq shift", "nfapi.pdsch.remapping.freq.shift", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates the frequency shift used for PDSCH RE mapping.", HFILL } ++ }, ++ { &hf_nfapi_alt_cqi_table_r12, ++ { "altCQI-Table-r12", "nfapi.alt.cqi.table.r12", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "altCQI-Table-r12 is indicative of using an alternative MCS table for UEs supporting 256QAM." ++ "This is taken into account for calculation of soft buffer size for the transport block", HFILL } ++ }, ++ { &hf_nfapi_max_layers, ++ { "MaxLayers", "nfapi.max.layers", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Maximal number of negotiated / configured layers for a UE, used for the calculation of soft buffer size for the transport block", HFILL } ++ }, ++ { &hf_nfapi_n_dl_harq, ++ { "N_DL_HARQ", "nfapi.n.dl.harq", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_dwpts_symbols, ++ { "DwPTS Symbols", "nfapi.dwpts.symbols", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Valid if DCI format 1C is being used to signal LAA end partial SF. Indicates the number of starting symbols according to 36.213 Table 13-A-1", HFILL } ++ }, ++ { &hf_nfapi_initial_lbt_sf, ++ { "Initial LBT SF", "nfapi.initial.lbt.sf", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates if the DCI PDU is prepared for full SF (regular) or for initial partial SF (2nd slot) according to [11] section 6.2.4 (if PDCCH) or 6.2.4A (if ePDCCH)", HFILL } ++ }, ++ { &hf_nfapi_ue_type, ++ { "UE Type", "nfapi.ue.type", ++ FT_UINT8, BASE_DEC, VALS(dlsch_re13_ue_type_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_pdsch_payload_type, ++ { "PDSCH Payload Type", "nfapi.pdsch.payload.type", ++ FT_UINT8, BASE_DEC, VALS(dlsch_re13_pdsch_payload_type_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_initial_transmission_sf, ++ { "Initial transmission SF (io)", "nfapi.init.tx.sf.io", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Absolute Sub-Frame of the initial transmission", HFILL } ++ }, ++ { &hf_nfapi_req13_drms_table_flag, ++ { "Rel-13-DMRS-tabe flag", "nfapi.r13.drms.table.flag", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates if Release 13 DMRS table is used.", HFILL } ++ }, ++ { &hf_nfapi_csi_rs_resource_index, ++ { "CSI-RS resource index", "nfapi.csi.rs.resource.index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Index of the CSI-RS resource. This is included to link bfValues to CSI-RS resources included in Release 10 parameters.", HFILL } ++ }, ++ { &hf_nfapi_csi_rs_class, ++ { "Class", "nfapi.csi.rs.class", ++ FT_UINT8, BASE_DEC, VALS(csi_rs_class_vals), 0x0, ++ "Indicates CSI-RS class", HFILL } ++ }, ++ { &hf_nfapi_cdm_type, ++ { "CDM Type", "nfapi.cdm.type", ++ FT_UINT8, BASE_DEC, VALS(csi_rs_cdm_type_vals), 0x0, ++ "Indicates CDM type for CSI-RS. See [36.211] section 6.10.5.2. Valid for Class A", HFILL } ++ }, ++ { &hf_nfapi_edpcch_prb_index, ++ { "EPDCCH PRB index", "nfapi.edpcch.prb.index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "PRB index", HFILL } ++ }, ++ { &hf_nfapi_epdcch_resource_assignment_flag, ++ { "EPDCCH Resource assignment flag", "nfapi.epdcch.resource.assignment.flag", ++ FT_UINT8, BASE_DEC, VALS(local_distributed_vals), 0x0, ++ "Type of virtual resource block used", HFILL } ++ }, ++ { &hf_nfapi_epdcch_id, ++ { "EPDCCH ID", "nfapi.epdcch.id", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "EPDCCH index- used for the scrambler initiation The DMRS scrambling sequence initialization parameter defined in[11] section 6.10.3A.1", HFILL } ++ }, ++ { &hf_nfapi_epdcch_start_symbol, ++ { "EPDCCH Start Symbol", "nfapi.epdcch.start.symbol", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates the OFDM starting symbol for any EPDCCH and PDSCH", HFILL } ++ }, ++ { &hf_nfapi_epdcch_num_prb, ++ { "EPDCCH NumPRB", "nfapi.epdcch.num.prb", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Number of PRBs allocated for EPDCCH", HFILL } ++ }, ++ { &hf_nfapi_precoding_value, ++ { "Precoding value", "nfapi.precoding.value", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Precoding element for physical antenna #i real 8 bits followed by imaginary 8 bits", HFILL } ++ }, ++ { &hf_nfapi_mpdcch_narrowband, ++ { "MPDCCH Narrowband", "nfapi.mpdcch.narrowband", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Narrowband for MPDCCH", HFILL } ++ }, ++ { &hf_nfapi_number_of_prb_pairs, ++ { "Number of PRB pairs", "nfapi.number.prb.pairs", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Number of PRB-pairs constituting the MPDCCH-PRB-pair set", HFILL } ++ }, ++ { &hf_nfapi_resource_block_assignment, ++ { "Resource Block Assignment", "nfapi.resource.block.assignement", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Combinational index r", HFILL } ++ }, ++ { &hf_nfapi_start_symbol, ++ { "Start symbol", "nfapi.start.symbol", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_ecce_index, ++ { "ECCE index", "nfapi.ecce.index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "CCE index used to send the DCI", HFILL } ++ }, ++ { &hf_nfapi_ce_mode, ++ { "CE Mode", "nfapi.ce.mode", ++ FT_UINT8, BASE_DEC, VALS(ce_mode_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_drms_scrabmling_init, ++ { "DMRS scrambling init", "nfapi.drms.scrambling.init", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The DMRS scrambling sequence initialization parameter defined in [11] section 6.10.3A.1", HFILL } ++ }, ++ { &hf_nfapi_pdsch_reception_levels, ++ { "PDSCH repetition levels", "nfapi.pdsch.repetition.levels", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Valid for DCI formats: 6-0A, 6-0B", HFILL } ++ }, ++ { &hf_nfapi_new_data_indicator, ++ { "New data indicator", "nfapi.new.data.indicator", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The new data indicator for the transport block", HFILL } ++ }, ++ { &hf_nfapi_tpmi_length, ++ { "TPMI length", "nfapi.tpmi.length", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Length of 'TPMI' field in units of bits", HFILL } ++ }, ++ { &hf_nfapi_pmi_flag, ++ { "PMI flag", "nfapi.pmi.flag", ++ FT_BOOLEAN, 8, TFS(&tfs_present_not_present), 0x0, ++ "Indicates if 'PMI' field is present", HFILL } ++ }, ++ { &hf_nfapi_harq_resource_offset, ++ { "HARQ resource offset", "nfapi.harq.resource.offset", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "HARQ-ACK resource offset used", HFILL } ++ }, ++ { &hf_nfapi_dci_subframe_repetition_number, ++ { "DCI subframe repetition number", "nfapi.dci.subframe.repetition.number", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates the number of MPDCCH repetitions", HFILL } ++ }, ++ { &hf_nfapi_downlink_assignment_index_length, ++ { "Downlink assignment index Length", "nfapi.dl.assignement.index.length", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Length of Downlink assignment index field in units of bits.", HFILL } ++ }, ++ { &hf_nfapi_starting_ce_level, ++ { "Starting CE Level", "nfapi.starting.ce.level", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "2 bits provide the PRACH starting CE level", HFILL } ++ }, ++ { &hf_nfapi_antenna_ports_and_scrambling_identity_flag, ++ { "Antenna ports and scrambling identity flag", "nfapi.antenna.ports.and.scrambling.identity.flag", ++ FT_BOOLEAN, 8, TFS(&tfs_present_not_present), 0x0, ++ "Indicates if 'Antenna ports and scrambling identity' field is present.", HFILL } ++ }, ++ { &hf_nfapi_antenna_ports_and_scrambling_identity, ++ { "Antenna ports and scrambling identity", "nfapi.antenna.ports.and.scrambling.identit", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates the Antenna port and, scrambling identity value", HFILL } ++ }, ++ { &hf_nfapi_paging_direct_indication_differentiation_flag, ++ { "Paging/Direct indication differentiation flag", "nfapi.paging.direct.indictation.differentiation.flag", ++ FT_UINT8, BASE_DEC, VALS(paging_direct_indication_differtiation_flag_vals), 0x0, ++ "Valid for DCI format 6-2", HFILL } ++ }, ++ { &hf_nfapi_direct_indication, ++ { "Direct indication", "nfapi.direct.indication", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Valid for DCI format 6-2", HFILL } ++ }, ++ { &hf_nfapi_number_of_tx_antenna_ports, ++ { "Number of TX Antenna ports", "nfapi.num.of.tx.antenna.ports.", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Number of TX physical antenna ports", HFILL } ++ }, ++ { &hf_nfapi_transmission_power, ++ { "Transmission Power", "nfapi.transmission_power", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(power_offset_conversion_fn), 0x0, ++ "Offset to the reference signal power.", HFILL } ++ }, ++ { &hf_nfapi_mbsfn_area_id, ++ { "MBSFN Area id", "nfapi.mbsfn.area.id", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates MBSFN area ID", HFILL } ++ }, ++ { &hf_nfapi_dl_dci_format, ++ { "DL DCI format", "nfapi.dl.dci.format", ++ FT_UINT8, BASE_DEC, VALS(dl_dci_format_vals), 0x0, ++ "Format of the DL DCI", HFILL } ++ }, ++ { &hf_nfapi_ul_dci_format, ++ { "UL DCI format", "nfapi.ul_dci.format", ++ FT_UINT8, BASE_DEC, VALS(ul_dci_format_vals), 0x0, ++ "Format of the UL DCI", HFILL } ++ }, ++ { &hf_nfapi_mpdcch_ul_dci_format, ++ { "UL DCI format", "nfapi.mpdcch.ul_dci.format", ++ FT_UINT8, BASE_DEC, VALS(mpdcch_ul_dci_format_vals), 0x0, ++ "Format of the UL DCI", HFILL } ++ }, ++ { &hf_nfapi_cce_idx, ++ { "CCE index", "nfapi.cce.index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "CCE index used to send the DCI", HFILL } ++ }, ++ { &hf_nfapi_aggregation_level, ++ { "Aggregation level", "nfapi.aggregation.level", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The aggregation level used", HFILL } ++ }, ++ { &hf_nfapi_mcs_1, ++ { "MCS_1", "nfapi.mcs_1", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The modulation and coding scheme for 1st transport block", HFILL } ++ }, ++ { &hf_nfapi_mcs_2, ++ { "MCS_2", "nfapi.mcs_2", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The modulation and coding scheme for 2nd transport block", HFILL } ++ }, ++ { &hf_nfapi_redundancy_version_1, ++ { "Redundancy version_1", "nfapi.redundancy.version.1", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The redundancy version for 1st transport block.", HFILL } ++ }, ++ { &hf_nfapi_redundancy_version_2, ++ { "Redundancy version_2", "nfapi.redundancy.version.2", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The redundancy version for 2nd transport block", HFILL } ++ }, ++ { &hf_nfapi_new_data_indicator_1, ++ { "New data indicator_1", "nfapi.new.data.indicator.1", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The new data indicator for 1st transport block.", HFILL } ++ }, ++ { &hf_nfapi_new_data_indicator_2, ++ { "New data indicator_2", "nfapi.new.data.indicator.2", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The new data indicator for 2nd transport block.", HFILL } ++ }, ++ { &hf_nfapi_harq_process, ++ { "HARQ process", "nfapi.harq.process", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "HARQ process number", HFILL } ++ }, ++ { &hf_nfapi_tpmi, ++ { "TPMI", "nfapi.tpmi", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The codebook index to be used for precoding", HFILL } ++ }, ++ { &hf_nfapi_pmi, ++ { "PMI", "nfapi.pmi", ++ FT_UINT8, BASE_DEC, VALS(pmi_vals), 0x0, ++ "Confirmation for precoding", HFILL } ++ }, ++ { &hf_nfapi_precoding_information, ++ { "Precoding information", "nfapi.precoding.information", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_tpc, ++ { "TPC", "nfapi.tpc", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Tx power control command for PUCCH", HFILL } ++ }, ++ { &hf_nfapi_downlink_assignment_index, ++ { "Downlink assignment index", "nfapi.downlink.assignment.index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The downlink assignment index. In release 8-11 this is only used in TDD mode, " ++ "value ignored for FDD. In release 12 or later a field indicating the structure " ++ "type of the primary cell is used to determine if this is valid with size 2 bits." ++ "In release 13 or later a field indicating codebooksizeDetermination - r13 = 0 is " ++ "used to determine is this field is valid with size 4 bits", HFILL } ++ }, ++ { &hf_nfapi_ngap, ++ { "Ngap", "nfapi.ngap", ++ FT_UINT8, BASE_DEC, VALS(ngap_vals), 0x0, ++ "Used in virtual resource block distribution", HFILL } ++ }, ++ { &hf_nfapi_transport_block_size_index, ++ { "Transport block size index", "nfapi.transport.block.size.index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The transport block size", HFILL } ++ }, ++ { &hf_nfapi_downlink_power_offset, ++ { "Downlink power offset", "nfapi.downlink.power.offset", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates the DL power offset type for multi-user MIMO transmission", HFILL } ++ }, ++ { &hf_nfapi_allocate_prach_flag, ++ { "Allocation PRACH flag", "nfapi.allocation.prach.flag", ++ FT_UINT8, BASE_DEC, VALS(true_false_vals), 0x0, ++ "Indicates that PRACH procedure is initiated", HFILL } ++ }, ++ { &hf_nfapi_preamble_index, ++ { "Preamble index", "nfapi.preamable.index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The preamble index to be used on the PRACH", HFILL } ++ }, ++ { &hf_nfapi_prach_mask_index, ++ { "PRACH mask index", "nfapi.prach.mask.index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The mask index to be used on the PRACH", HFILL } ++ }, ++ { &hf_nfapi_rnti_type, ++ { "RNTI type", "nfapi.rnti.type", ++ FT_UINT8, BASE_DEC, VALS(rnti_type_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_mpdcch_rnti_type, ++ { "RNTI type", "nfapi.mpdcch.rnti.type", ++ FT_UINT8, BASE_DEC, VALS(mpdcch_rnti_type_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_mcch_flag, ++ { "MCCH flag", "nfapi.mcch.flag", ++ FT_BOOLEAN, BASE_NONE, TFS(&mcch_flag_string_name), 0x0, ++ "Indicates if format 1C is being used to signal a MCCH or SC-MCCH change notification", HFILL } ++ }, ++ { &hf_nfapi_mcch_change_notification, ++ { "MCCH change notification", "nfapi.mcch.change.notification", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "MCCH or SC-MCCH Change Notification", HFILL } ++ }, ++ { &hf_nfapi_scrambling_identity, ++ { "Scrambling identity", "nfapi.scrambling.identity", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates the scrambling identity value NSCID", HFILL } ++ }, ++ { &hf_nfapi_cross_carrier_scheduling_flag, ++ { "Cross Carrier scheduling flag", "nfapi.cross.carrier.scheduling.flag", ++ FT_BOOLEAN, 8, TFS(&cross_carrier_scheduling_flag_strname), 0x0, ++ "Indicates if cross carrier scheduling has been enabled for the UE receiving this DCI", HFILL } ++ }, ++ { &hf_nfapi_carrier_indicator, ++ { "Carrier Indicator", "nfapi.carrier.indicator", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Serving Cell Index", HFILL } ++ }, ++ { &hf_nfapi_srs_flag, ++ { "SRS flag", "nfapi.srs.flag", ++ FT_BOOLEAN, 8, TFS(&srs_flag_strname), 0x0, ++ "Indicates if the SRS request parameter is valid", HFILL } ++ }, ++ { &hf_nfapi_srs_request, ++ { "SRS request", "nfapi.srs.request", ++ FT_BOOLEAN, 8, TFS(&srs_request_strname), 0x0, ++ "SRS request flag", HFILL } ++ }, ++ { &hf_nfapi_antenna_ports_scrambling_and_layers, ++ { "Antenna ports scrambling and layers", "nfapi.antenna.ports.scrambling.and.layers", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates the Antenna port, scrambling identity value NSCID and number of layers", HFILL } ++ }, ++ { &hf_nfapi_total_dci_length_including_padding, ++ { "Total DCI length including padding", "nfapi.total.dci.length.including.padding", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The total DCI length including padding bits", HFILL } ++ }, ++ { &hf_nfapi_n_ul_rb, ++ { "N_UL_RB", "nfapi.n.dl.rb", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "BW of serving cell for which the DCI was scheduled for. This is valid for " ++ "the case of cross carrier scheduling, for the case of a self - " ++ "scheduling(cross carrier scheduling is not valid or Carrier indicator has value '0', " ++ "the BW is the 'DL BW support' as configured in configuration phase(params) " ++ "Uplink channel bandwidth in resource blocks", HFILL } ++ }, ++ { &hf_nfapi_harq_ack_resource_offset, ++ { "HARQ-ACK resource offset", "nfapi.harq.ack.resource.offset", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "HARQ-ACK resource offset field is present only when this format is carried by EPDCCH.", HFILL } ++ }, ++ { &hf_nfapi_pdsch_re_mapping_and_quasi_co_location_indicator, ++ { "PDSCH RE Mapping and Quasi-Co-Location Indicator", "nfapi.pdsch.re.mapping", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates the parameter set configured by the higher layers which the UE should use.", HFILL } ++ }, ++ { &hf_nfapi_primary_cell_type, ++ { "Primary cell type", "nfapi.primary.cell.type", ++ FT_UINT8, BASE_DEC, VALS(primary_cells_type_vals), 0x0, ++ "Indicates the type of the primary cell.", HFILL } ++ }, ++ { &hf_nfapi_ul_dl_configuration_flag, ++ { "UL/DL configuration flag", "nfapi.ul.dl.configuration.flag", ++ FT_BOOLEAN, 8, TFS(&ul_dl_configuration_flag_strname), 0x0, ++ "Indicates if format 1C is being used to signal UL/DL configuration", HFILL } ++ }, ++ { &hf_nfapi_number_of_ul_dl_configurations, ++ { "Number of UL/DL configurations", "nfapi.number.ul.dl.configurations", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_ul_dl_configuration_index, ++ { "UL/DL configuration indication", "nfapi.ul.dl.configuration.indication", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "UL/DL configuration index", HFILL } ++ }, ++ { &hf_nfapi_laa_end_partial_sf_flag, ++ { "LAA end partial SF flag", "nfapi.laa.end.partial.sf.flag", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates if DCI format 1C is being used to signal LAA end partial SF (valid if end partial SF support configuraton is set)", HFILL } ++ }, ++ { &hf_nfapi_laa_end_partial_sf_configuration, ++ { "LAA end partial SF configuration", "nfapi.laa.end.partial.sf.configuration", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "If DCI format 1C scrambled by CC - RNTI is used to signal end partial SF, this field " ++ "contains LAA common information (4 bits used in [9] Table 13A-1 for configuration of " ++ "occupied OFDM symbols for current and next SF)", HFILL } ++ }, ++ { &hf_nfapi_codebooksize_determination_r13, ++ { "Codebook Size Determination R13", "nfapi.codebook.size.determination.r13", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates if the downlink assignment index parameter (DAI) is 4 bits", HFILL } ++ }, ++ { &hf_nfapi_rel13_drms_table_flag, ++ { "Rel-13-DMRS-tabe flag", "nfapi.drms.table.flag.r13", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates if Release 13 DMRS table for be used", HFILL } ++ }, ++ { &hf_nfapi_pscch_resource, ++ { "PSCCH Resource", "nfapi.pscch.resource", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "6-bits describing the resource blocks for transmitting PSCCH", HFILL } ++ }, ++ { &hf_nfapi_time_resource_pattern, ++ { "Time resource pattern", "nfapi.time.resource.pattern", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "7-bits describing the time resource pattern index", HFILL } ++ }, ++ { &hf_nfapi_mpdcch_transmission_type, ++ { "MPDCCH transmission type", "nfapi.mpdcch.transmission.type", ++ FT_UINT8, BASE_DEC, VALS(local_distributed_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_drms_scrambling_init, ++ { "DMRS scrambling init", "nfapi.drms.scrambling.init", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The DMRS scrambling sequence initialization", HFILL } ++ }, ++ { &hf_nfapi_pusch_repetition_levels, ++ { "PUSCH repetition levels", "nfapi.pusch.repetition.levels", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Valid for DCI formats: 6-0A, 6-0B", HFILL } ++ }, ++ { &hf_nfapi_frequency_hopping_flag, ++ { "Frequency hopping flag", "nfapi.frequency.hopping.flag", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates if hopping is being used.", HFILL } ++ }, ++ { &hf_nfapi_csi_request, ++ { "CSI request", "nfapi.csi.request", ++ FT_UINT8, BASE_DEC, VALS(csi_request_vals), 0x0, ++ "Aperiodic CSI request flag", HFILL } ++ }, ++ { &hf_nfapi_dai_presence_flag, ++ { "DAI presence flag", "nfapi.dia.presence.flag", ++ FT_BOOLEAN, 8, TFS(&tfs_present_not_present), 0x0, ++ "Indicates if DL assignment index field is present in the DCI", HFILL } ++ }, ++ { &hf_nfapi_total_dci_length_include_padding, ++ { "Total DCI length including padding", "nfapi.total.dci.length.including.padding", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The total DCI length including padding bits", HFILL } ++ }, ++ { &hf_nfapi_csi_rs_antenna_port_count_r10, ++ { "CSI-RS antenna port count r10", "nfapi.csi.rs.antenna.port.count.r10", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates number of antennas used for transmission of CSI reference signal.", HFILL } ++ }, ++ { &hf_nfapi_ul_config_pdu_type, ++ { "UL Config PDU Type", "nfapi.ul.config.pdu.type", ++ FT_UINT8, BASE_DEC, VALS(nfapi_ul_config_pdu_type_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_rach_prach_frequency_resources, ++ { "RACH PRACH Frequency resources", "nfapi.rach.prach.frequency.resources", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "If semi-static information is held in the MAC", HFILL } ++ }, ++ { &hf_nfapi_srs_present, ++ { "SRS present", "nfapi.srs.present", ++ FT_BOOLEAN, 8, TFS(&tfs_present_not_present), 0x0, ++ "If semi-static information is held in the MAC", HFILL } ++ }, ++ { &hf_nfapi_handle, ++ { "Handle", "nfapi.handle", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "An opaque handle", HFILL } ++ }, ++ { &hf_nfapi_pucch_index, ++ { "PUCCH Index", "nfapi.pucch.index", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The PUCCH index value", HFILL } ++ }, ++ { &hf_nfapi_size, ++ { "Size", "nfapi.size", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The size of the ULSCH PDU in bytes as defined by the relevant UL grant", HFILL } ++ }, ++ { &hf_nfapi_resource_block_start, ++ { "Resource block start", "nfapi.resource.block.start", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The starting resource block for this ULSCH allocation", HFILL } ++ }, ++ { &hf_nfapi_number_of_resource_blocks, ++ { "Number of resource blocks", "nfapi.resource.blocks", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of resource blocks allocated to this ULSCH grant", HFILL } ++ }, ++ { &hf_nfapi_cyclic_shift_2_for_drms, ++ { "Cyclic Shift 2 for DRMS", "nfapi.cyclic.shift.2.for.drms", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The 2nd cyclic shift for DMRS assigned to the UE in the ULSCH grant", HFILL } ++ }, ++ { &hf_nfapi_frequency_hopping_enabled_flag, ++ { "Frequency hopping enabled flag", "nfapi.frequency.hopping.enabled.flag", ++ FT_UINT8, BASE_DEC, VALS(hopping_vals), 0x0, ++ "Indicates if hopping is being used", HFILL } ++ }, ++ { &hf_nfapi_frequency_hopping_bits, ++ { "Frequency hopping bits", "nfapi.frequency.hopping.bits", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_new_data_indication, ++ { "New Data inidication", "nfapi.new.data.indication", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Specify whether this received transport block is a new transmission from UE", HFILL } ++ }, ++ { &hf_nfapi_harq_process_number, ++ { "HARQ Process number", "nfapi.harq.process.number", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_ul_tx_mode, ++ { "UL Tx Mode", "nfapi.ul.tx.mode", ++ FT_UINT8, BASE_DEC, VALS(ul_tx_mode_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_current_tx_nb, ++ { "Current Tx nb", "nfapi.current.tx.nb", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The current HARQ transmission count of this transport block. Valid if frequency hopping enabled.", HFILL } ++ }, ++ { &hf_nfapi_n_srs, ++ { "N SRS", "nfapi.n.srs", ++ FT_UINT8, BASE_DEC, VALS(n_srs_vals), 0x0, ++ "Indicates if the resource blocks allocated for this grant overlap with the SRS configuration.", HFILL } ++ }, ++ { &hf_nfapi_disable_sequence_hopping_flag, ++ { "Disable seqeunce hopping flag", "nfapi.disable.sequence.hopping.flag", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates if any configured group hopping should be disabled for this UE.", HFILL } ++ }, ++ { &hf_nfapi_virtual_cell_id_enabled_flag, ++ { "Virtual cell ID enabled flag", "nfapi.virtual.cell.id.enabled.flag", ++ FT_UINT8, BASE_DEC, VALS(not_used_enabled_vals), 0x0, ++ "Indicates if virtual cell is being used and nPUSCH identity is valid.", HFILL } ++ }, ++ { &hf_nfapi_npusch_identity, ++ { "nPUSCH Identity", "nfapi.npusch.identity", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Virtual cell ID for initialization of group hopping, sequence hopping and sequence shift pattern of PUSCH DMRS.", HFILL } ++ }, ++ { &hf_nfapi_ndrms_csh_identity, ++ { "nDMRS-CSH Identity", "nfapi.ndrms.csh.identity", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Virtual cell ID for initialization of cyclic shift hopping of PUSCH DMRS.", HFILL } ++ }, ++ { &hf_nfapi_total_number_of_repetitions, ++ { "Total Number of repetitions", "nfapi.total.number.of.repetitions", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_repetition_number, ++ { "Repetition Number", "nfapi.repetition.number", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Current transmission number", HFILL } ++ }, ++ { &hf_nfapi_initial_sf_io, ++ { "Initial transmission SF (io)", "nfapi.initial.sf.io", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Absolute Sub-Frame of the initial transmission", HFILL } ++ }, ++ { &hf_nfapi_empty_symbols_due_to_retunning, ++ { "Empy symbols due to re-tunning", "nfapi.empty.symbols.due.to.retunning", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates the symbols that are left empty due to eMTC retuning.", HFILL } ++ }, ++ { &hf_nfapi_dl_cqi_ri_pmi_size_2, ++ { "DL CQI/PMI/RI size 2", "nfapi.dl.cqi.ri.pmi.size.2", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The size of the DL CQI/PMI/RI in bits. If the CQI/PMI/RI size exceeds 255 (8-bits) then the Release 9 size value = 0, and this field is used instead.", HFILL } ++ }, ++ { &hf_nfapi_harq_size_2, ++ { "HARQ Size 2", "nfapi.harq.size2", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The size of the ACK/NACK in bits.", HFILL } ++ }, ++ { &hf_nfapi_delta_offset_harq_2, ++ { "Delta Offset HARQ 2", "nfapi.delta.offset.harq.2", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Delta offset 2 for HARQ. This value is fixed for a UE, allocated in RRC connection setup and used for ACK_NACK mode = 4 or 5", HFILL } ++ }, ++ { &hf_nfapi_starting_prb, ++ { "Starting PRB", "nfapi.starting.prb", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The starting PRB for the PUCCH", HFILL } ++ }, ++ { &hf_nfapi_antenna_port, ++ { "Antenna Port", "nfapi.antenna.port", ++ FT_UINT8, BASE_DEC, VALS(antenna_ports_vals), 0x0, ++ "Defines the number of antenna ports used by the UE for the SRS. This value is fixed for a UE and allocated in RRC connection setup.", HFILL } ++ }, ++ { &hf_nfapi_number_of_combs, ++ { "Number of Combs", "nfapi.num.of.combs", ++ FT_UINT8, BASE_DEC, VALS(combs_vals), 0x0, ++ "Defines the maximum number of transmission combs (TC).", HFILL } ++ }, ++ { &hf_nfapi_npucch_identity, ++ { "nPUCCH Identity", "nfapi.npucch.identity", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Virtual cell ID for initialization of base sequence and cyclic shift hopping of PUCCH.", HFILL } ++ }, ++ { &hf_nfapi_empty_symbols, ++ { "Empty symbols", "nfapi.empty.symbols", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates the symbols that are left empty due to eMTC retuning.", HFILL } ++ }, ++ { &hf_nfapi_csi_mode, ++ { "CSI_mode", "nfapi.csi.mode", ++ FT_UINT8, BASE_DEC, VALS(csi_mode_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_dl_cqi_pmi_size_2, ++ { "DL CQI/PMI Size 2", "nfapi.dl.cqi.pmi.size.2", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The size of the DL CQI/PMI in bits", HFILL } ++ }, ++ { &hf_nfapi_statring_prb, ++ { "Starting PRB", "nfapi.starting.prb", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The starting PRB for the PUCCH", HFILL } ++ }, ++ { &hf_nfapi_cdm_index, ++ { "cdm_Index", "nfapi.cdm.index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Selected CDM option", HFILL } ++ }, ++ { &hf_nfapi_nsrs, ++ { "N srs", "nfapi.n.srs", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates if the resource blocks allocated for this grant overlap with the SRS configuration.", HFILL } ++ }, ++ { &hf_nfapi_num_ant_ports, ++ { "Num_ant_ports", "nfapi.num.ant.port", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of antenna ports used by the UE transmit", HFILL } ++ }, ++ { &hf_nfapi_n_pucch_2_0, ++ { "n_PUCCH_2_0", "nfapi.n.pucch.2.0", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The PUCCH Index value for ACK/NACK HARQ resource 4 on antenna port", HFILL } ++ }, ++ { &hf_nfapi_n_pucch_2_1, ++ { "n_PUCCH_2_1", "nfapi.n.pucch.2.1", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "HARQ resource 5", HFILL } ++ }, ++ { &hf_nfapi_n_pucch_2_2, ++ { "n_PUCCH_2_2", "nfapi.n.pucch.2.2", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "HARQ resource 6", HFILL } ++ }, ++ { &hf_nfapi_n_pucch_2_3, ++ { "n_PUCCH_2_3", "nfapi.n.pucch.2.3", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "HARQ resource 7", HFILL } ++ }, ++ { &hf_nfapi_dl_cqi_pmi_size_rank_1, ++ { "DL CQI PMI size rank 1", "nfapi.dl.cqi.pmi.size.rank.1", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The size of the DL CQI/PMI in bits in case of rank 1 report.", HFILL } ++ }, ++ { &hf_nfapi_dl_cqi_pmi_size_rank_greater_1, ++ { "DL CQI PMI size rank greater 1", "nfapi.dl.cqi.pmi.size.rank.1", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The size of the DL CQI/PMI in bits in case of rank>1 report.", HFILL } ++ }, ++ { &hf_nfapi_ri_size, ++ { "RI size", "nfapi.ri.size", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The size of RI in bits", HFILL } ++ }, ++ { &hf_nfapi_delta_offset_cqi, ++ { "Delta offset cqi", "nfapi.delta.offset.cqi", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Delta offset for CQI. This value is fixed for a UE and allocated in RRC connection setup.", HFILL } ++ }, ++ { &hf_nfapi_delta_offset_ri, ++ { "Delta offset ri", "nfapi.delta.offset.ri", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Delta offset for RI. This value is fixed for a UE and allocated in RRC connection setup.", HFILL } ++ }, ++ { &hf_nfapi_harq_size, ++ { "HARQ size", "nfapi.harq_size", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The size of the ACK/NACK in bits", HFILL } ++ }, ++ { &hf_nfapi_delta_offset_harq, ++ { "Delta offset HARQ", "nfapi.delta.offset.harq", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Delta offset for HARQ. This value is fixed for a UE and allocated in RRC connection setup.", HFILL } ++ }, ++ { &hf_nfapi_tdd_ack_nack_mode, ++ { "ACK NACK mode", "nfapi.tdd.ack.nack.mode", ++ FT_UINT8, BASE_DEC, VALS(nfapi_tdd_ack_nack_mode_vals), 0x0, ++ "The format of the ACK/NACK response expected. For TDD only.", HFILL } ++ }, ++ { &hf_nfapi_fdd_ack_nack_mode, ++ { "ACK NACK mode", "nfapi.fdd.ack.nack.mode", ++ FT_UINT8, BASE_DEC, VALS(nfapi_fdd_ack_nack_mode_vals), 0x0, ++ "The format of the ACK/NACK response expected. For TDD only.", HFILL } ++ }, ++ { &hf_nfapi_n_srs_initial, ++ { "N srs initial", "nfapi.n.srs.initial", ++ FT_UINT8, BASE_DEC, VALS(n_srs_initial_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_initial_number_of_resource_blocks, ++ { "Initial number of resource blocks", "nfapi.initial.number.of.resource.blocks", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of resource blocks used in the initial transmission of this transport block.", HFILL } ++ }, ++ { &hf_nfapi_dl_cqi_pmi_size, ++ { "DL cqi pmi size", "nfapi.dl.cqi.pmi.size", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The size of the DL CQI/PMI in bits in case of this RI value. The size of the DL CQI / PMI / RI in bits in case of this CRI value", HFILL } ++ }, ++ { &hf_nfapi_report_type, ++ { "Report type", "nfapi.report.type", ++ FT_BOOLEAN, 8, TFS(&nfapi_csi_report_type_strname), 0x0, ++ "Type of CSI report", HFILL } ++ }, ++ { &hf_nfapi_dl_cqi_ri_pmi_size, ++ { "DL CQI/PMI/RI size", "nfapi.dl.cqi.ri.pmi.size", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The size of the DL CQI/PMI/RI/CRI in bits", HFILL } ++ }, ++ { &hf_nfapi_control_type, ++ { "Control type", "nfapi.control.type", ++ FT_BOOLEAN, 8, TFS(&nfapi_control_type_string_name), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_number_of_cc, ++ { "Number of cc", "nfapi.number.of.cc", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of CC in the aperiodic report", HFILL } ++ }, ++ { &hf_nfapi_number_of_pucch_resource, ++ { "Number of PUCCH Resource", "nfapi.number.of.pucch.resource", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "A value of 2 indicates that the UE is configured to transmit on two antenna ports", HFILL } ++ }, ++ { &hf_nfapi_pucch_index_p1, ++ { "PUCCH Index P1", "nfapi.pucch.index.p1", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The PUCCH index value for antenna port P1", HFILL } ++ }, ++ { &hf_nfapi_n_pucch_1_0, ++ { "N PUCCH 1 0", "nfapi.n.pucch.1.0", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "HARQ resource 0", HFILL } ++ }, ++ { &hf_nfapi_n_pucch_1_1, ++ { "N PUCCH 1 1", "nfapi.n.pucch.1.1", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "HARQ resource 1", HFILL } ++ }, ++ { &hf_nfapi_n_pucch_1_2, ++ { "N PUCCH 1 2", "nfapi.n.pucch.1.2", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "HARQ resource 2", HFILL } ++ }, ++ { &hf_nfapi_n_pucch_1_3, ++ { "N PUCCH 1 3", "nfapi.n.pucch.1.3", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "HARQ resource 3", HFILL } ++ }, ++ { &hf_nfapi_srs_bandwidth, ++ { "SRS Bandwidth", "nfapi.srs.bandwidth", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "SRS Bandwidth. This value is fixed for a UE and allocated in RRC connection setup.", HFILL } ++ }, ++ { &hf_nfapi_frequency_domain_position, ++ { "Frequency Domain position", "nfapi.frequency.domain.position", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Frequency-domain position, NRRC This value is fixed for a UE and allocated in RRC connection setup.", HFILL } ++ }, ++ { &hf_nfapi_srs_hopping_bandwidth, ++ { "SRS hopping bandwidth", "nfapi.srs.hopping.bandwidth", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Configures the frequency hopping on the SRS. This value is fixed for a UE and allocated in RRC connection setup.", HFILL } ++ }, ++ { &hf_nfapi_transmission_comb, ++ { "Transmission comb", "nfapi.transmission.comb", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Configures the frequency location of the SRS. This value is fixed for a UE and allocated in RRC connection setup.", HFILL } ++ }, ++ { &hf_nfapi_i_srs, ++ { "I SRS", "nfapi.i.srs", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Defines the periodicity and subframe location of the SRS. SRS Configuration Index. This value is fixed for a UE and allocated in RRC connection setup.", HFILL } ++ }, ++ { &hf_nfapi_sounding_reference_cyclic_shift, ++ { "Sounding reference cyclic shift", "nfapi.sounding.reference.cyclic.shift", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Configures the SRS sequence generation. This value is fixed for a UE and allocated in RRC connection setup.", HFILL } ++ }, ++ { &hf_nfapi_pdu_length, ++ { "PDU length", "nfapi.pdu.length", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The total length (in bytes) of the PDU description and PDU data, without the padding bytes", HFILL } ++ }, ++ { &hf_nfapi_crc_flag, ++ { "CRC flag", "nfapi.crc.flag", ++ FT_BOOLEAN, 8, TFS(&crc_flag_strname), 0x0, ++ "A flag indicating if a CRC error was detected", HFILL } ++ }, ++ { &hf_nfapi_number_of_hi_pdus, ++ { "Number of HI Pdu's", "nfapi.number_of_hi_pdus", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Number of HI PDUs included in this message", HFILL } ++ }, ++ { &hf_nfapi_number_of_dci_pdus, ++ { "Number of DCI Pdu's", "nfapi.number_of_dci_pdus", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Number of DCI PDUs included in this message", HFILL } ++ }, ++ { &hf_nfapi_hi_dci0_pdu_type, ++ { "PDU Type", "nfapi.pdu_type", ++ FT_UINT8, BASE_DEC, VALS(hi_dci0_pdu_type_vals), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_hi_value, ++ { "HI Value", "nfapi.hi_value", ++ FT_BOOLEAN, 8, TFS(&hi_value_strname), 0x0, ++ "The PHICH value which is sent on the resource", HFILL } ++ }, ++ { &hf_nfapi_i_phich, ++ { "i phich", "nfapi.i_phich", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Is used in the calculation of the PHICH location. For TDD only", HFILL } ++ }, ++ { &hf_nfapi_flag_tb2, ++ { "Flag TB2", "nfapi.flag_tb2", ++ FT_BOOLEAN, BASE_NONE, TFS(&flag_tb2_strname), 0x0, ++ "Indicates is HI is present for a second transport block", HFILL } ++ }, ++ { &hf_nfapi_hi_value_2, ++ { "HI Value 2", "nfapi.hi_value_2", ++ FT_BOOLEAN, BASE_NONE, TFS(&hi_value_strname), 0x0, ++ "The PHICH value for a second transport block.", HFILL } ++ }, ++ { &hf_nfapi_ue_tx_antenna_selection, ++ { "UE Tx Antenna selection", "nfapi.ue_tx_antenna_selection", ++ FT_UINT8, BASE_DEC, VALS(ue_tx_antenna_selection_vals), 0x0, ++ "Indicates how the CRC is calculated on the PDCCH.", HFILL } ++ }, ++ { &hf_nfapi_cqi_csi_request, ++ { "cqi csi request", "nfapi.cqi_csi_request", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Aperiodic CQI request flag", HFILL } ++ }, ++ { &hf_nfapi_ul_index, ++ { "UL index", "nfapi.ul_index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Valid for TDD mode only", HFILL } ++ }, ++ { &hf_nfapi_dl_assignment_index, ++ { "DL Assignment index", "nfapi.dl_assignment_index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Valid for TDD mode only.", HFILL } ++ }, ++ { &hf_nfapi_tpc_bitmap, ++ { "TPC bitmap", "nfapi.tpc_bitmap", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "TPC commands for PUCCH and PUSCH", HFILL } ++ }, ++ { &hf_nfapi_number_of_antenna_ports, ++ { "Number of antenna ports", "nfapi.number.of.antenna.ports", ++ FT_UINT8, BASE_DEC, VALS(number_of_antenna_port_vals), 0x0, ++ "Defines number of antenna ports for this ULSCH allocation", HFILL } ++ }, ++ { &hf_nfapi_size_of_cqi_csi_feild, ++ { "Size of cqi csi feild", "nfapi.size.of.cqi.csi.feild", ++ FT_UINT8, BASE_DEC, VALS(size_of_cqi_csi_feild_vals), 0x0, ++ "Indicates the size of the CQI/CSI request field", HFILL } ++ }, ++ { &hf_nfapi_new_data_indication_two, ++ { "New data indication 2", "nfapi.new.data.indication.two", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The new data indicator for the second transport block", HFILL } ++ }, ++ { &hf_nfapi_resource_allocation_flag, ++ { "Resource allocation flag", "nfapi.resource.allocation.flag", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Indicates if the Resource Allocation Type parameter is valid.", HFILL } ++ }, ++ { &hf_nfapi_dl_node_sync_t1, ++ { "DL Node Sync t1", "nfapi.dl.node.sync.t1", ++ FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &units_milliseconds, 0x0, ++ "Offset from VNF SFN/SF 0/0 time reference of the DL Node Sync message transmission at the transport layer, in microseconds.", HFILL } ++ }, ++ { &hf_nfapi_dl_node_sync_delta_sfn_sf, ++ { "DL Node Sync Delta SFN SF", "nfapi.dl.node.sync.delta_sfn_sf", ++ FT_INT32, BASE_DEC, NULL, 0x0, ++ "The delta shift in subframes that the PNF PHY instance must update to on the next subframe boundary", HFILL } ++ }, ++ { &hf_nfapi_dl_cyclic_prefix_type, ++ { "DL Cyclic Prefix type", "nfapi.dl.cyclic.prefix.type", ++ FT_BOOLEAN, 8, TFS(&cyclic_prefix_type_strname), 0x0, ++ "Cyclic prefix type, used for DL", HFILL } ++ }, ++ { &hf_nfapi_ul_cyclic_prefix_type, ++ { "UL Cyclic Prefix type", "nfapi.ul.cyclic.prefix.type", ++ FT_BOOLEAN, 8, TFS(&cyclic_prefix_type_strname), 0x0, ++ "Cyclic prefix type, used for UL", HFILL } ++ }, ++ { &hf_nfapi_downlink_channel_bandwidth, ++ { "Downlink Channel Bandwidth", "nfapi.dl.channel.bandwidth", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Downlink channel bandwidth in resource blocks.", HFILL } ++ }, ++ { &hf_nfapi_uplink_channel_bandwidth, ++ { "Uplink Channel Bandwidth", "nfapi.ul.channel_bandwidth", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Uplink channel bandwidth in resource blocks.", HFILL } ++ }, ++ { &hf_nfapi_tx_antenna_ports, ++ { "Tx Antenna Ports", "nfapi.tx.antenna.ports", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The number of cell specific or NB transmit antenna ports.", HFILL } ++ }, ++ { &hf_nfapi_rx_antenna_ports, ++ { "Tx Antenna Ports", "nfapi.rx.antenna.ports", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The number of cell specific or NB receive antenna ports.", HFILL } ++ }, ++ { &hf_nfapi_ul_node_sync_t1, ++ { "UL Node Sync t1", "nfapi.ul.node.sync.t1", ++ FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &units_milliseconds, 0x0, ++ "The supplied t1 field in the DL Node Sync", HFILL } ++ }, ++ { &hf_nfapi_ul_node_sync_t2, ++ { "UL Node Sync t2", "nfapi.ul.node.sync.t2", ++ FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &units_milliseconds, 0x0, ++ "Offset from PNF SFN/SF 0/0 time reference of the DL Node Sync message reception at the transport layer, in microseconds.", HFILL } ++ }, ++ { &hf_nfapi_ul_node_sync_t3, ++ { "UL Node Sync t3", "nfapi.ul.node.sync.t3", ++ FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &units_milliseconds, 0x0, ++ "Offset from PNF SFN/SF 0/0 time reference of the UL Node Sync message transmission at the transport layer, in microseconds.", HFILL } ++ }, ++ { &hf_nfapi_pb, ++ { "P-B", "nfapi.pb.allocation", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Refers to downlink power allocation. Value is an index into the referenced table.", HFILL } ++ }, ++ { &hf_nfapi_timing_info_last_sfn_sf, ++ { "Last SFN/SF", "nfapi.timing.info.last.sfn.sf", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "The completed SFN/SF at the PNF PHY instance that triggered the Timing Info message", HFILL } ++ }, ++ { &hf_nfapi_timing_info_time_since_last_timing_info, ++ { "Time since last Timing Info", "nfapi.timing.info.time.since.last.timing.info", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "The number of ms since the last Timing Info was sent from this PNF PHY instance.", HFILL } ++ }, ++ { &hf_nfapi_timing_info_dl_config_jitter, ++ { "DL Config Jitter", "nfapi.timing.info.dl.config.jitter", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "The inter message jitter of the DL Config message reception in microseconds", HFILL } ++ }, ++ { &hf_nfapi_timing_info_tx_request_jitter, ++ { "Tx Request Jitter", "nfapi.timing.info.tx.req.jitter", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "The inter message jitter of the Tx Request message reception in microseconds", HFILL } ++ }, ++ { &hf_nfapi_timing_info_ul_config_jitter, ++ { "UL Config Jitter", "nfapi.timing.info.ul.config.jitter", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "The inter message jitter of the UL Config message reception in microseconds", HFILL } ++ }, ++ { &hf_nfapi_timing_info_hi_dci0_jitter, ++ { "HI_DCI0 Jitter", "nfapi.timing.info.hi.dci0.jitter", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "The inter message jitter of the HI_DCI0 message reception in microseconds", HFILL } ++ }, ++ { &hf_nfapi_timing_info_dl_config_latest_delay, ++ { "DL Config Latest Delay", "nfapi.timing.info.dl.config.latest.delay", ++ FT_INT32, BASE_DEC, NULL, 0x0, ++ "The latest delay offset in microseconds from the latest acceptable time for the DL Config as defined in the DL Config Timing in the PNF_PARAM.Response since the last transmission of the Timing Info Message.", HFILL } ++ }, ++ { &hf_nfapi_timing_info_tx_request_latest_delay, ++ { "Tx Request Latest Delay", "nfapi.timing.info.tx.request.latest.delay", ++ FT_INT32, BASE_DEC, NULL, 0x0, ++ "The latest delay offset in microseconds from the latest acceptable time for the Tx Request as defined in the Tx Config Timing in the PNF_PARAM.Response since the last transmission of the Timing Info Message.", HFILL } ++ }, ++ { &hf_nfapi_timing_info_ul_config_latest_delay, ++ { "UL Config Latest Delay", "nfapi.timing.info.ul.config.latest.delay", ++ FT_INT32, BASE_DEC, NULL, 0x0, ++ "The latest delay offset in microseconds from the latest acceptable time for the UL Config as defined in the UL Config Timing in the PNF_PARAM.Response since the last transmission of the Timing Info Message.", HFILL } ++ }, ++ { &hf_nfapi_timing_info_hi_dci0_latest_delay, ++ { "HI_DCI0 Latest Delay", "nfapi.timing.info.hi.dci0.latest.delay", ++ FT_INT32, BASE_DEC, NULL, 0x0, ++ "The latest delay offset in microseconds from the latest acceptable time for the HI_DCI0 as defined in the HI_DCI0 Timing in the PNF_PARAM.Response since the last transmission of the Timing Info Message.", HFILL } ++ }, ++ { &hf_nfapi_timing_info_dl_config_earliest_arrival, ++ { "DL Config Earliest Arrival", "nfapi.timing.info.dl.config.earliest.arrival", ++ FT_INT32, BASE_DEC, NULL, 0x0, ++ "The earlierst arrival offset in microseconds from the latest time acceptable for the DL Config as defined in the Timing Window in the PARAM.Response since the last transmission of the Timing Info Message.", HFILL } ++ }, ++ { &hf_nfapi_timing_info_tx_request_earliest_arrival, ++ { "Tx Request Earliest Arrival", "nfapi.timing.info.tx.request.earliest.arrival", ++ FT_INT32, BASE_DEC, NULL, 0x0, ++ "The earlierst arrival offset in microseconds from the latest time acceptable for the Tx Request as defined in the Timing Window in the PARAM.Response since the last transmission of the Timing Info Message.", HFILL } ++ }, ++ { &hf_nfapi_timing_info_ul_config_earliest_arrival, ++ { "UL Config Earliest Arrival", "nfapi.timing.info.ul.config.earliest.arrival", ++ FT_INT32, BASE_DEC, NULL, 0x0, ++ "The earlierst arrival offset in microseconds from the latest time acceptable for the UL Config as defined in the Timing Window in the PARAM.Response since the last transmission of the Timing Info Message.", HFILL } ++ }, ++ { &hf_nfapi_timing_info_hi_dci0_earliest_arrival, ++ { "HI_DCI0 Earliest Arrival", "nfapi.timing.info.hi.dci0.earliest.arrival", ++ FT_INT32, BASE_DEC, NULL, 0x0, ++ "The earlierst arrival offset in microseconds from the latest time acceptable for the HI_DCI0 as defined in the Timing Window in the PARAM.Response since the last transmission of the Timing Info Message.", HFILL } ++ }, ++ { &hf_nfapi_pcfich_power_offset, ++ { "PCFICH Power Offset", "nfapi.pcfich.power.offset", ++ FT_UINT16, BASE_CUSTOM, CF_FUNC(power_offset_conversion_fn), 0x0, ++ "The power per antenna of the PCFICH with respect to the reference signal.", HFILL } ++ }, ++ { &hf_nfapi_timing_window, ++ { "NFAPI Timing window", "nfapi.timing.window", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The window in milliseconds that the PHY must receive and queue the P7 messages.", HFILL } ++ }, ++ { &hf_nfapi_timing_info_mode, ++ { "Timing Info mode", "nfapi.timing.info.mode", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The configured mode of operation for the timing info message to be sent to the VNF from the PHY", HFILL } ++ }, ++ { &hf_nfapi_timing_info_period, ++ { "Timing info period", "nfapi.timing.info.period", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "If Periodic timing mode is enabled, this defines the periodicity in subframes. This field is ignored if periodic timing mode is disabled.", HFILL } ++ }, ++ { &hf_nfapi_tdd_harq_mode, ++ { "Mode", "nfapi.tdd.harq.mode", ++ FT_UINT8, BASE_DEC, VALS(tdd_harq_mode_vals), 0x0, ++ "The format of the ACK/NACK response expected", HFILL } ++ }, ++ { &hf_nfapi_fdd_harq_mode, ++ { "Mode", "nfapi.fdd.harq.mode", ++ FT_UINT8, BASE_DEC, VALS(fdd_harq_mode_vals), 0x0, ++ "The format of the ACK/NACK response expected", HFILL } ++ }, ++ { &hf_nfapi_number_of_ack_nack, ++ { "Number of ACK/NACK", "nfapi.uint16.tag", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The number of ACK/NACK results reported for this UE", HFILL } ++ }, ++ { &hf_nfapi_harq_data_value_0, ++ { "Value 0", "nfapi.harq.value.0", ++ FT_UINT8, BASE_DEC, VALS(harq_value_vals), 0x0, ++ "Indicates HARQ results", HFILL } ++ }, ++ { &hf_nfapi_harq_data_value_0_special, ++ { "Value 0", "nfapi.harq.value.0.special", ++ FT_UINT8, BASE_DEC, VALS(harq_special_value_vals), 0x0, ++ "Indicates HARQ results", HFILL } ++ }, ++ { &hf_nfapi_harq_data_value_1, ++ { "Value 1", "nfapi.harq.value.1", ++ FT_UINT8, BASE_DEC, VALS(harq_value_vals), 0x0, ++ "Indicates HARQ results", HFILL } ++ }, ++ { &hf_nfapi_harq_data_value_2, ++ { "Value 2", "nfapi.harq.value.2", ++ FT_UINT8, BASE_DEC, VALS(harq_value_vals), 0x0, ++ "Indicates HARQ results", HFILL } ++ }, ++ { &hf_nfapi_harq_data_value_3, ++ { "Value 3", "nfapi.harq.value.3", ++ FT_UINT8, BASE_DEC, VALS(harq_value_vals), 0x0, ++ "Indicates HARQ results", HFILL } ++ }, ++ { &hf_nfapi_harq_tb_1, ++ { "HARQ TB1", "nfapi.harq.tb.", ++ FT_UINT8, BASE_DEC, VALS(harq_value_vals), 0x0, ++ "HARQ feedback of 1st TB.", HFILL } ++ }, ++ { &hf_nfapi_harq_tb_2, ++ { "HARQ TB2", "nfapi.harq.tb.2", ++ FT_UINT8, BASE_DEC, VALS(harq_value_vals), 0x0, ++ "HARQ feedback of 2nd TB.", HFILL } ++ }, ++ { &hf_nfapi_harq_tb_n, ++ { "HARQ TB_N", "nfapi.harq.tb.n", ++ FT_UINT8, BASE_DEC, VALS(harq_value_vals), 0x0, ++ "HARQ feedback of Nth TB.", HFILL } ++ }, ++ { &hf_nfapi_ul_cqi, ++ { "UL_CQI", "nfapi.ul.cqi", ++ FT_UINT8, BASE_CUSTOM, CF_FUNC(ul_cqi_conversion_fn), 0x0, ++ "SNR", HFILL } ++ }, ++ { &hf_nfapi_channel, ++ { "Channel", "nfapi.channel", ++ FT_UINT8, BASE_DEC, VALS(channel_vals), 0x0, ++ "The channel to which this measurement refers", HFILL } ++ }, ++ { &hf_nfapi_data_offset, ++ { "Data Offset", "nfapi.data.offset", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Gives the PDU#i data address offset from the beginning of the 'Number of PDUs' field. An offset of 0 indicates a CRC or decoding error", HFILL } ++ }, ++ { &hf_nfapi_ri, ++ { "RI", "nfapi.ri", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The rank indication reported by the UE on PUSCH for aperiodic CSI.", HFILL } ++ }, ++ { &hf_nfapi_timing_advance, ++ { "Timing Advance", "nfapi.timing.advance", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The timing advance measured for this PDU and UE.", HFILL } ++ }, ++ { &hf_nfapi_timing_advance_r9, ++ { "Timing Advance R9", "nfapi.timing.advance.r9", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Timing advance used for positioning", HFILL } ++ }, ++ { &hf_nfapi_number_of_cc_reported, ++ { "Number of CC reported", "nfapi.number.of.cc.reported", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_preamble, ++ { "Preamble", "nfapi.preamble", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The detected preamble", HFILL } ++ }, ++ { &hf_nfapi_rach_resource_type, ++ { "RACH resource type", "nfapi.rach.resource.type", ++ FT_UINT8, BASE_DEC, VALS(rach_resource_type_vals), 0x0, ++ "Indicates if this indication is related to Cat-M UE and in which CE level", HFILL } ++ }, ++ { &hf_nfapi_doppler_estimation, ++ { "Doppler estimation", "nfapi.doppler.estimation", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "FFS", HFILL } ++ }, ++ { &hf_nfapi_rb_start, ++ { "RB Start", "nfapi.rb.start", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The starting point of the RBs to be reported", HFILL } ++ }, ++ { &hf_nfapi_snr, ++ { "SNR", "nfapi.snr", ++ FT_UINT8, BASE_CUSTOM, CF_FUNC(ul_cqi_conversion_fn), 0x0, ++ "Field size dependent on configured bandwidth SNR for RBs, each RBs report one SNR.", HFILL } ++ }, ++ { &hf_nfapi_up_pts_symbol, ++ { "UpPTS Symbol", "nfapi.uppts.symbol", ++ FT_UINT8, BASE_DEC, VALS(up_pts_symbol_vals), 0x0, ++ "Indicates symbol where SRS was received. Only valid if the SRS was received in subframe 1 or 6.", HFILL } ++ }, ++ { &hf_nfapi_number_prb_per_subband, ++ { "numPRBperSubband", "nfapi.num.prb.per.subband", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Number of PRBs that are treated as one subband", HFILL } ++ }, ++ { &hf_nfapi_number_antennas, ++ { "numAntennas", "nfapi.num.antennas", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Number of physical antennas", HFILL } ++ }, ++ { &hf_nfapi_subband_index, ++ { "subbandIndex", "nfapi.subband.index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "Index of subband for which the following channel coefficient is applied", HFILL } ++ }, ++ { &hf_nfapi_channel_coefficient, ++ { "Channel", "nfapi.channel.coefficient", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Averaged channel coefficient in a subband for physical antenna #i, real 8 bits followed by imaginary 8 bits", HFILL } ++ }, ++ { &hf_nfapi_ul_rtoa, ++ { "UL_RTOA", "nfapi.ul.rtoa", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "UL relative time of arrival used for network based positioning", HFILL } ++ }, ++ { &hf_nfapi_frequency_band_indicator, ++ { "Frequency Band Indicator", "nfapi.frequency.band.indicator", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The E-UTRA band for which the carrierList applies.", HFILL } ++ }, ++ { &hf_nfapi_measurement_period, ++ { "Measurement Period", "nfapi.measurement.period", ++ FT_UINT16, BASE_DEC | BASE_UNIT_STRING, &units_milliseconds, 0x0, ++ "The length of time to measure RSSI over, in units of 1ms.", HFILL } ++ }, ++ { &hf_nfapi_bandwidth, ++ { "Bandwidth", "nfapi.bandwidth", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The bandwidth (in resource blocks) over which the RSSI is measured.", HFILL } ++ }, ++ { &hf_nfapi_timeout, ++ { "Timeout", "nfapi.timeout", ++ FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &units_milliseconds, 0x0, ++ "The timeout value after which the PNF should abort the procedure in units of 1ms. The value of 0 indicates that the PNF should attempt to complete the procedure without any VNF-imposed timeout.", HFILL } ++ }, ++ { &hf_nfapi_number_of_earfcns, ++ { "Number of EARFCNs", "nfapi.number.of.earfcns", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of EARFCNs which should be measured. In the case that no EARFCN (value 0) is specified, all valid EARFCNs for the specified bandwidth in the band shall be measured, in order of ascending EARCFN.", HFILL } ++ }, ++ { &hf_nfapi_uarfcn, ++ { "UARFCN", "nfapi.uarfcn", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "UARFCN to be measured.", HFILL } ++ }, ++ { &hf_nfapi_number_of_uarfcns, ++ { "Number of UARFCNs", "nfapi.number.of.uarfcn", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of UARFCNs which should be measured. In the case that no UARFCN (value 0) is specified, all UARFCNs in the band shall be measured, in order of ascending UARCFN.", HFILL } ++ }, ++ { &hf_nfapi_arfcn, ++ { "ARFCN", "nfapi.arfcn", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The ARFCN to be measured", HFILL } ++ }, ++ { &hf_nfapi_arfcn_direction, ++ { "Direction", "nfapi.arfcn.direction", ++ FT_UINT8, BASE_DEC, VALS(arfcn_direction_vals), 0x0, ++ "The link direction to be measured", HFILL } ++ }, ++ { &hf_nfapi_number_of_arfcns, ++ { "Number of ARFCNs", "nfapi.number.of.arfcn", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of ARFCNs which should be measured. In the case that no ARFCN (value 0) is specified, all ARFCNs in the band shall be measured, in order of ascending ARCFN.", HFILL } ++ }, ++ { &hf_nfapi_rssi, ++ { "RSSI", "nfapi.rssi", ++ FT_INT16, BASE_CUSTOM, CF_FUNC(rssi_conversion_fn), 0x0, ++ "The list of RSSI values of the carriers measured, in the order of the list of the original request.", HFILL } ++ }, ++ { &hf_nfapi_number_of_rssi, ++ { "Number of RSSI", "nfapi.number.of.rssi", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The number of RSSI results returned in the following array.", HFILL } ++ }, ++ { &hf_nfapi_pci, ++ { "PCI", "nfapi.pci", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The PCI for cell which should be searched", HFILL } ++ }, ++ { &hf_nfapi_measurement_bandwidth, ++ { "Measurement Bandwidth", "nfapi.measurement.bandwidth", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of resource blocks which should be used for measuring RSRP", HFILL } ++ }, ++ { &hf_nfapi_exhaustive_search, ++ { "Exhaustive Search", "nfapi.exhaustive.search", ++ FT_UINT8, BASE_DEC, VALS(exhustive_search_vals), 0x0, ++ "NMM should try to find all cells on the carrier", HFILL } ++ }, ++ { &hf_nfapi_number_of_pci, ++ { "Number of PCI", "nfapi.number.of.pci", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of cells in the PCI list. If 0 all cells on the carrier should be found. Otherwise, depending on exhaustiveSearch flag, only the given pciList is searched or the pciList is used for indicating a priority list. Range: 0 to MAX_PCI_LIST.", HFILL } ++ }, ++ { &hf_nfapi_psc, ++ { "PSC", "nfapi.psc", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The PSC for cells which should be searched.", HFILL } ++ }, ++ { &hf_nfapi_number_of_psc, ++ { "Number of PSC", "nfapi.number.of.psc", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of cells in the PSC list. If 0 all cells on the carrier should be found. Otherwise, depending on Exhaustive Search flag, only the given PSC list is searched or the PSC list is used for indicating a priority list. Range: 0 to MAX_PSC_LIST.", HFILL } ++ }, ++ { &hf_nfapi_rsrp, ++ { "RSRP", "nfapi.rsrp", ++ FT_UINT8, BASE_CUSTOM, CF_FUNC(neg_pow_conversion_fn), 0x0, ++ "The measured RSRP value in units of -1dB", HFILL } ++ }, ++ { &hf_nfapi_rsrq, ++ { "RSRQ", "nfapi.rsrq", ++ FT_UINT8, BASE_CUSTOM, CF_FUNC(neg_pow_conversion_fn), 0x0, ++ "The measured RSRQ value in units of -1dB", HFILL } ++ }, ++ { &hf_nfapi_number_of_lte_cells_found, ++ { "Number of LTE Cells Found", "nfapi.number.of.lte.cells.found", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The number of LTE cells indicated in this message.", HFILL } ++ }, ++ { &hf_nfapi_rscp, ++ { "RSCP", "nfapi.rscp", ++ FT_UINT8, BASE_CUSTOM, CF_FUNC(neg_pow_conversion_fn), 0x0, ++ "The measured RSCP value in units of -1dB", HFILL } ++ }, ++ { &hf_nfapi_enco, ++ { "EcNo", "nfapi.ecno", ++ FT_UINT8, BASE_CUSTOM, CF_FUNC(neg_pow_conversion_fn), 0x0, ++ "The measured RSCP value in units of -1dB", HFILL } ++ }, ++ { &hf_nfapi_number_of_utran_cells_found, ++ { "Number of UTRAN Cells Found", "nfapi.number.of.utran.cells.found", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The number of LTE cells indicated in this message", HFILL } ++ }, ++ { &hf_nfapi_bsic, ++ { "BSIC", "nfapi.bsic", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The BSIC of the cell which the NMM synchronized to", HFILL } ++ }, ++ { &hf_nfapi_rxlev, ++ { "RxLev", "nfapi.rxlev", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The measured RxLev value", HFILL } ++ }, ++ { &hf_nfapi_rxqual, ++ { "RxQual", "nfapi.rxqual", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The measured RxQual value", HFILL } ++ }, ++ { &hf_nfapi_sfn_offset, ++ { "SFN Offset", "nfapi.sfn.offset", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "The offset in us of the start of the current GSM Radio HyperFrame (i.e. FN=0) from the start of the preceding LTE Radio Frame of the PNF for SFN=0", HFILL } ++ }, ++ { &hf_nfapi_number_of_geran_cells_found, ++ { "Number of GSM Cells Found", "nfapi.number.of.geran.cells.found", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The number of GSM cells indicated in this message", HFILL } ++ }, ++ { &hf_nfapi_number_of_tx_antenna, ++ { "Number of Tx Antenna", "nfapi.number.of.tx.antenna", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of Tx Antenna detected for the cell", HFILL } ++ }, ++ { &hf_nfapi_mib_length, ++ { "MIB Length", "nfapi.mib.length", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Length in bytes of the following MIB array", HFILL } ++ }, ++ { &hf_nfapi_mib, ++ { "MIB", "nfapi.mib", ++ FT_BYTES, BASE_NONE, NULL, 0x0, ++ "The MIB read from the specified cell.", HFILL } ++ }, ++ { &hf_nfapi_phich_configuration, ++ { "PHICH Configuration", "nfapi.phich.configuration", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The PHICH-Config of the cell", HFILL } ++ }, ++ { &hf_nfapi_retry_count, ++ { "retryCount", "nfapi.retry.count", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of SIB1 repetition periods for which decoding of SIB1 should be retried.", HFILL } ++ }, ++ { &hf_nfapi_sib1, ++ { "SIB1", "nfapi.sib1", ++ FT_BYTES, BASE_NONE, NULL, 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_si_periodicity, ++ { "SI Periodicity", "nfapi.si.periodicity", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The SI Periodicity of the requested SIBs, with the first element being for SIB2, the next for SIB3, etc, encoded as follows", HFILL } ++ }, ++ { &hf_nfapi_si_index, ++ { "SI Index", "nfapi.si.index", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The index of this SIB in the SIB1 SchedulingInfoList:", HFILL } ++ }, ++ { &hf_nfapi_number_of_si_periodicity, ++ { "Number of SI Periodicity", "nfapi.number.of.si.periodicity", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The number of System Information periodicity values in the following array", HFILL } ++ }, ++ { &hf_nfapi_si_window_length, ++ { "SI Window Length", "nfapi.si.window.length", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The SI window in units of 1ms", HFILL } ++ }, ++ { &hf_nfapi_sib_type, ++ { "SIB Type", "nfapi.sib.type", ++ FT_UINT8, BASE_DEC, NULL, 0x0, ++ "The SIB type", HFILL } ++ }, ++ { &hf_nfapi_sib_len, ++ { "SIB Length", "nfapi.sib.length", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The length in bytes of the following SIB array", HFILL } ++ }, ++ { &hf_nfapi_sib, ++ { "SIB", "nfapi.sib", ++ FT_BYTES, BASE_NONE, NULL, 0x0, ++ "The SIB element read from the specified cell.", HFILL } ++ }, ++ { &hf_nfapi_si_len, ++ { "SI Length", "nfapi.si.length", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The length in bytes of the following SI array", HFILL } ++ }, ++ { &hf_nfapi_si, ++ { "SI", "nfapi.si", ++ FT_BYTES, BASE_NONE, NULL, 0x0, ++ "The SI element read from the specified cell.", HFILL } ++ }, ++ { &hf_nfapi_pnf_search_state, ++ { "State", "nfapi.state", ++ FT_BYTES, BASE_NONE, NULL, 0x0, ++ "A structure of opaque data optionally sent by the PNF to the VNF", HFILL } ++ }, ++ { &hf_nfapi_pnf_broadcast_state, ++ { "State", "nfapi.state", ++ FT_BYTES, BASE_NONE, NULL, 0x0, ++ "A structure of opaque data optionally sent by the PNF to the VNF", HFILL } ++ }, ++ { &hf_nfapi_dl_rs_tx_power, ++ { "DL RS Tx power", "nfapi.dl.rs.tx.power", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "The DL RS Tx power measurement", HFILL } ++ }, ++ { &hf_nfapi_received_interference_power, ++ { "Received interference power", "nfapi.received.interference.power", ++ FT_UINT16, BASE_DEC | BASE_UNIT_STRING, &units_milliseconds, 0x0, ++ "The Received interference power measurement", HFILL } ++ }, ++ { &hf_nfapi_thermal_noise_power, ++ { "Thermal noise power", "nfapi.thermal.noise.power", ++ FT_UINT16, BASE_DEC | BASE_UNIT_STRING, &units_milliseconds, 0x0, ++ "The Thermal noise power measurement", HFILL } ++ }, ++ { &hf_nfapi_dl_rs_tx_power_measurement, ++ { "DL RS TX Power measurement", "nfapi.dl.rs.tx.power.measurement", ++ FT_INT16, BASE_CUSTOM, CF_FUNC(dl_rs_tx_pow_measment_conversion_fn), 0x0, ++ "The DL RS Tx power measurement defined", HFILL } ++ }, ++ { &hf_nfapi_received_interference_power_measurement, ++ { "Received interference power measurement", "nfapi.received.interference.power.measurement", ++ FT_INT16, BASE_CUSTOM, CF_FUNC(dl_rs_tx_pow_measment_conversion_fn), 0x0, ++ NULL, HFILL } ++ }, ++ { &hf_nfapi_thermal_noise_power_measurement, ++ { "Thermal noise power measurement", "nfapi.thermal.noise.power.measurement", ++ FT_INT16, BASE_CUSTOM, CF_FUNC(dl_rs_tx_pow_measment_conversion_fn), 0x0, ++ "The Thermal noise power measurement", HFILL } ++ }, ++ { &hf_nfapi_initial_partial_sf, ++ { "Initial Partial SF", "nfapi.initial.partial.sf", ++ FT_BOOLEAN, 32, TFS(&initial_partial_sf_strname), 0x0, ++ "Indicates whether the initial SF in the LBT process is full or partial", HFILL } ++ }, ++ { &hf_nfapi_lbt_mode, ++ { "LBT Mode", "nfapi.lbt.mode", ++ FT_BOOLEAN, 32, TFS(&lbt_mode_strname), 0x0, ++ "Part of multi-carrier support. Indicates whether full LBT process is carried or partial LBT process is carried (multi carrier mode B according to [9] section 15.1.5.2)", HFILL } ++ }, ++ { &hf_nfapi_lte_txop_sf, ++ { "LTE TXOP SF", "nfapi.txop.sf", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "Indicates the LTE TXOP (TMCOT,P in [9] section 15.1.1) duration in subframes.", HFILL } ++ }, ++ { &hf_nfapi_mp_cca, ++ { "mp cca", "nfapi.mp.cca", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "Indicates the value of the defer factor", HFILL } ++ }, ++ { &hf_nfapi_n_cca, ++ { "n cca", "nfapi.n.cca", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "Indicates the value of LBT backoff counter", HFILL } ++ }, ++ { &hf_nfapi_offset, ++ { "offset", "nfapi.offset", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "Indicates the LBT start time in microseconds from the beginning of the subframe scheduled by this message.", HFILL } ++ }, ++ { &hf_nfapi_result, ++ { "result", "nfapi.result", ++ FT_BOOLEAN, 32, TFS(&tfs_fail_success), 0x0, ++ "Indicates the LBT procedure result of SFN/SF:", HFILL } ++ }, ++ { &hf_nfapi_sfn_sf_end, ++ { "SFN/SF End", "nfapi.sfn.sf.end", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates the SFN/SF by which the DRS window (Discovery signal occasion as described in [9] section 6.11A) must end. In worst case, this would be the last TXOP subframe.", HFILL } ++ }, ++ { &hf_nfapi_txop_sfn_sf_end, ++ { "TXOP SFN/SF End", "nfapi.txop.sfn.sf.end", ++ FT_UINT16, BASE_DEC, NULL, 0x0, ++ "Indicates the SFN/SF by which the TXOP must end. In worst case, this would be the last TXOP subframe.", HFILL } ++ }, ++ { &hf_nfapi_txop_symbols, ++ { "LTE TXOP symbols", "nfapi.lte.txop.symbols", ++ FT_UINT32, BASE_DEC, NULL, 0x0, ++ "Actual LTE TXOP in symbols", HFILL } ++ }, ++ }; ++ ++ /* Setup protocol subtree array */ ++ static gint *ett[] = ++ { ++ &ett_nfapi_message_tree, ++ &ett_nfapi_p4_p5_message_header, ++ &ett_nfapi_p7_message_header, ++ &ett_nfapi_tlv_tree, ++ &ett_nfapi_tl, ++ &ett_nfapi_pnf_phy_rf_config, ++ &ett_nfapi_pnf_phy, ++ &ett_nfapi_pnf_phy_rel10, ++ &ett_nfapi_pnf_phy_rel11, ++ &ett_nfapi_pnf_phy_rel12, ++ &ett_nfapi_pnf_phy_rel13, ++ &ett_nfapi_rf_bands, ++ &ett_nfapi_bf_vectors, ++ &ett_nfapi_csi_rs_bf_vector, ++ &ett_nfapi_csi_rs_resource_configs, ++ &ett_nfapi_tx_antenna_ports, ++ &ett_nfapi_harq_ack_nack_data, ++ &ett_nfapi_harq_data, ++ &ett_nfapi_cqi_pmi_size, ++ &ett_nfapi_cc, ++ &ett_nfapi_rbs, ++ &ett_nfapi_antennas, ++ &ett_nfapi_epdcch_prbs, ++ &ett_nfapi_dl_config_request_pdu_list, ++ &ett_nfapi_ul_config_request_pdu_list, ++ &ett_nfapi_hi_dci0_request_pdu_list, ++ &ett_nfapi_tx_request_pdu_list, ++ &ett_nfapi_rx_indication_pdu_list, ++ &ett_nfapi_harq_indication_pdu_list, ++ &ett_nfapi_crc_indication_pdu_list, ++ &ett_nfapi_sr_indication_pdu_list, ++ &ett_nfapi_cqi_indication_pdu_list, ++ &ett_nfapi_preamble_indication_pdu_list, ++ &ett_nfapi_srs_indication_pdu_list, ++ &ett_nfapi_lbt_dl_config_pdu_list, ++ &ett_nfapi_lbt_dl_indication_pdu_list, ++ &ett_nfapi_subbands, ++ &ett_nfapi_precoding, ++ &ett_nfapi_bf_vector_antennas, ++ &ett_nfapi_received_interference_power_mesurement_results, ++ &ett_nfapi_downlink_bandwidth_support, ++ &ett_nfapi_uplink_bandwidth_support, ++ &ett_nfapi_release_support, ++ &ett_nfapi_downlink_modulation_support, ++ &ett_nfapi_uplink_modulation_support, ++ ++ &ett_nfapi_earfcn_list, ++ &ett_nfapi_uarfcn_list, ++ &ett_nfapi_arfcn_list, ++ &ett_nfapi_rssi_list, ++ &ett_nfapi_pci_list, ++ &ett_nfapi_psc_list, ++ &ett_nfapi_lte_cells_found_list, ++ &ett_nfapi_utran_cells_found_list, ++ &ett_nfapi_geran_cells_found_list, ++ &ett_nfapi_si_periodicity_list, ++ ++ /* for fragmentation support*/ ++ &ett_msg_fragment, ++ &ett_msg_fragments ++ }; ++ ++ static ei_register_info ei[] = ++ { ++ { &ei_invalid_range, { "nfapi.invalid.range", PI_PROTOCOL, PI_WARN, NULL, EXPFILL } }, ++ { &ei_invalid_tlv_length, { "nfapi.invalid.tlv.length", PI_PROTOCOL, PI_ERROR, NULL, EXPFILL } }, ++ }; ++ ++ expert_module_t* expert_nfapi; ++ /* Register protocol */ ++ proto_nfapi = proto_register_protocol("Nfapi", "NFAPI", "nfapi"); ++ ++ expert_nfapi = expert_register_protocol(proto_nfapi); ++ expert_register_field_array(expert_nfapi, ei, array_length(ei)); ++ ++ ++ proto_register_field_array(proto_nfapi, hf, array_length(hf)); ++ proto_register_subtree_array(ett, array_length(ett)); ++ ++ reassembly_table_register(&ul_p7_reassemble_table, &addresses_ports_reassembly_table_functions); ++ reassembly_table_register(&dl_p7_reassemble_table, &addresses_ports_reassembly_table_functions); ++ ++ register_dissector("nfapi", dissect_nfapi, proto_nfapi); ++ ++} ++ ++// ----------------------------------------------------------------------------| ++ ++void proto_reg_handoff_nfapi(void) ++{ ++ static dissector_handle_t nfapi_handle; ++ ++ nfapi_handle = create_dissector_handle(dissect_nfapi, proto_nfapi); ++ ++ dissector_add_for_decode_as("sctp.port", nfapi_handle); ++ ++ dissector_add_uint("udp.port", 41700, nfapi_handle); ++ ++} ++ ++ ++/* ++* Editor modelines - http://www.wireshark.org/tools/modelines.html ++* ++* Local variables: ++* c-basic-offset: 8 ++* tab-width: 8 ++* indent-tabs-mode: t ++* End: ++* ++* vi: set shiftwidth=8 tabstop=8 noexpandtab: ++* :indentSize=8:tabSize=8:noTabs=false: ++*/ +diff --git a/xml/pnf_phy_1_A.xml b/xml/pnf_phy_1_A.xml +index da6cc26..45f8f46 100644 +--- a/xml/pnf_phy_1_A.xml ++++ b/xml/pnf_phy_1_A.xml +@@ -26,7 +26,7 @@ + + 88 + 2500 +-
    127.0.0.1
    ++
    192.168.1.74
    + + 1 + +@@ -54,9 +54,9 @@ + + + +- 7722 +- 127.0.0.1 +- 7733 ++ 5201 ++ 192.168.1.28 ++ 5200 + + +
    +diff --git a/xml/vnf_A.xml b/xml/vnf_A.xml +index e609c93..3791239 100644 +--- a/xml/vnf_A.xml ++++ b/xml/vnf_A.xml +@@ -2,8 +2,8 @@ + + + +- 5200 +-
    127.0.0.1
    ++ 5201 ++
    192.168.1.28
    + 10 + 0 + 0 +@@ -12,7 +12,7 @@ + + + 8891 +- 127.0.0.1 ++ 192.168.1.28 + 8892 + + diff --git a/oaienv b/oaienv index f6b298debf..2e5ce16960 100644 --- a/oaienv +++ b/oaienv @@ -17,3 +17,14 @@ alias oait='cd $OPENAIR_TARGETS' alias oailte='cd $OPENAIR_TARGETS/RT/USER' alias oais='cd $OPENAIR_TARGETS/SIMU/USER' alias oaiex='cd $OPENAIR_TARGETS/SIMU/EXAMPLES' + +export NFAPI_DIR=${HOME}/open-nFAPI + +alias bld='cd $OPENAIR_HOME/cmake_targets ; ./build_oai --eNB -w USRP' +alias b='cd $OPENAIR_HOME/cmake_targets ; ./build_oai --eNB -w USRP' +alias run='cd $OPENAIR_HOME/cmake_targets/lte_build_oai/build' +alias nf='cd $OPENAIR_HOME/nfapi' +alias conf='cd $OPENAIR_HOME/targets/PROJECTS/GENERIC-LTE-EPC/CONF' + +alias ttracer='cd $OPENAIR_HOME/cmake_targets ; ./build_oai --eNB -x -w USRP --T-tracer' +alias rec='cd $OPENAIR_HOME/common/utils/T/tracer ; ./record -d ../T_messages.txt -o record.raw -ON -off VCD -off HEAVY -off LEGACY_GROUP_TRACE -off LEGACY_GROUP_DEBUG' diff --git a/open-nfapi.oai.patch b/open-nfapi.oai.patch deleted file mode 100644 index 95aeb2e64a..0000000000 --- a/open-nfapi.oai.patch +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/nfapi/public_inc/nfapi_interface.h b/nfapi/public_inc/nfapi_interface.h -index 2d58c2a..45af99a 100644 ---- a/nfapi/public_inc/nfapi_interface.h -+++ b/nfapi/public_inc/nfapi_interface.h -@@ -34,7 +34,7 @@ - #define NFAPI_MAX_NUM_ANTENNAS 8 - #define NFAPI_MAX_NUM_SUBBANDS 13 - #define NFAPI_MAX_BF_VECTORS 8 --#define NFAPI_MAX_CC 1 -+#define NFAPI_MAX_CC 2 - #define NFAPI_MAX_NUM_PHYSICAL_ANTENNAS 8 - #define NFAPI_MAX_RSSI 8 - #define NFAPI_MAX_PSC_LIST 32 -@@ -1689,7 +1689,7 @@ typedef struct { - uint16_t number_pdu; - uint8_t number_pdsch_rnti; - uint16_t transmission_power_pcfich; -- nfapi_dl_config_request_pdu_t* dl_config_pdu_list; -+ nfapi_dl_config_request_pdu_t* dl_config_pdu_list; - } nfapi_dl_config_request_body_t; - #define NFAPI_DL_CONFIG_REQUEST_BODY_TAG 0x2000 - -@@ -1772,7 +1772,7 @@ typedef struct { - uint8_t number_of_cc; - struct { - uint8_t ri_size; -- uint8_t dl_cqi_pmi_size; -+ uint8_t dl_cqi_pmi_size[8]; - } cc[NFAPI_MAX_CC]; - } nfapi_ul_config_aperiodic_cqi_pmi_ri_report_t; - -@@ -1962,7 +1962,7 @@ typedef struct { - } nfapi_ul_config_harq_information_rel8_fdd_t; - #define NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL8_FDD_TAG 0x2019 - --typedef struct { -+typedef struct { - nfapi_tl_t tl; - uint8_t harq_size; - uint8_t ack_nack_mode; diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 283667134d..93ea87e4c0 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -32,6 +32,9 @@ #include "assertions.h" #include +extern uint32_t from_earfcn(int eutra_bandP,uint32_t dl_earfcn); +extern int32_t get_uldl_offset(int eutra_bandP); + extern uint16_t prach_root_sequence_map0_3[838]; extern uint16_t prach_root_sequence_map4[138]; uint8_t dmrs1_tab[8] = {0,2,3,4,6,8,9,10}; @@ -42,24 +45,41 @@ int N_RB_DL_array[6] = {6,15,25,50,75,100}; int l1_north_init_eNB() { int i,j; - AssertFatal(RC.nb_L1_inst>0,"nb_L1_inst=%d\n",RC.nb_L1_inst); - AssertFatal(RC.nb_L1_CC!=NULL,"nb_L1_CC is null\n"); - AssertFatal(RC.eNB!=NULL,"RC.eNB is null\n"); - for (i=0;i0,"RC.nb_L1_CC[%d]=%d\n",i,RC.nb_L1_CC[i]); - for (j=0;jif_inst = IF_Module_init(i))<0) return(-1); - RC.eNB[i][j]->if_inst->PHY_config_req = phy_config_request; - RC.eNB[i][j]->if_inst->schedule_response = schedule_response; + + if (RC.nb_L1_inst > 0 && RC.nb_L1_CC != NULL && RC.eNB != NULL) + { + AssertFatal(RC.nb_L1_inst>0,"nb_L1_inst=%d\n",RC.nb_L1_inst); + AssertFatal(RC.nb_L1_CC!=NULL,"nb_L1_CC is null\n"); + AssertFatal(RC.eNB!=NULL,"RC.eNB is null\n"); + + LOG_I(PHY,"%s() RC.nb_L1_inst:%d\n", __FUNCTION__, RC.nb_L1_inst); + + for (i=0;i0,"RC.nb_L1_CC[%d]=%d\n",i,RC.nb_L1_CC[i]); + + LOG_I(PHY,"%s() RC.nb_L1_CC[%d]:%d\n", __FUNCTION__, i, RC.nb_L1_CC[i]); + + for (j=0;jif_inst = IF_Module_init(i))<0) return(-1); + + LOG_I(PHY,"%s() RC.eNB[%d][%d] installing callbacks\n", __FUNCTION__, i, j); + + RC.eNB[i][j]->if_inst->PHY_config_req = phy_config_request; + RC.eNB[i][j]->if_inst->schedule_response = schedule_response; + } } } + else + { + LOG_I(PHY,"%s() Not installing PHY callbacks - RC.nb_L1_inst:%d RC.nb_L1_CC:%p RC.eNB:%p\n", __FUNCTION__, RC.nb_L1_inst, RC.nb_L1_CC, RC.eNB); + } return(0); } - void phy_config_request(PHY_Config_t *phy_config) { uint8_t Mod_id = phy_config->Mod_id; @@ -71,13 +91,14 @@ void phy_config_request(PHY_Config_t *phy_config) { PHICH_RESOURCE_t phich_resource_table[4]={oneSixth,half,one,two}; int eutra_band = cfg->nfapi_config.rf_bands.rf_band[0]; int dl_Bandwidth = cfg->rf_config.dl_channel_bandwidth.value; + int ul_Bandwidth = cfg->rf_config.ul_channel_bandwidth.value; int Nid_cell = cfg->sch_config.physical_cell_id.value; int Ncp = cfg->subframe_config.dl_cyclic_prefix_type.value; int p_eNB = cfg->rf_config.tx_antenna_ports.value; uint32_t dl_CarrierFreq = cfg->nfapi_config.earfcn.value; - LOG_I(PHY,"Configuring MIB for instance %d, CCid %d : (band %d,N_RB_DL %d,Nid_cell %d,p %d,Ncp %d,DL freq %u,phich_config.resource %d, phich_config.duration %d)\n", - Mod_id, CC_id, eutra_band, N_RB_DL_array[dl_Bandwidth], Nid_cell, p_eNB,Ncp,dl_CarrierFreq, + LOG_I(PHY,"Configuring MIB for instance %d, CCid %d : (band %d,N_RB_DL %d, N_RB_UL %d, Nid_cell %d,eNB_tx_antenna_ports %d,Ncp %d,DL freq %u,phich_config.resource %d, phich_config.duration %d)\n", + Mod_id, CC_id, eutra_band, dl_Bandwidth, ul_Bandwidth, Nid_cell, p_eNB,Ncp,dl_CarrierFreq, cfg->phich_config.phich_resource.value, cfg->phich_config.phich_duration.value); @@ -86,13 +107,18 @@ void phy_config_request(PHY_Config_t *phy_config) { AssertFatal(RC.eNB[Mod_id][CC_id] != NULL, "PHY instance %d, CCid %d doesn't exist\n",Mod_id,CC_id); + if (RC.eNB[Mod_id][CC_id]->configured == 1) + { + LOG_E(PHY,"Already eNB already configured, do nothing\n"); + return; + } RC.eNB[Mod_id][CC_id]->mac_enabled = 1; fp = &RC.eNB[Mod_id][CC_id]->frame_parms; - fp->N_RB_DL = N_RB_DL_array[dl_Bandwidth]; - fp->N_RB_UL = N_RB_DL_array[dl_Bandwidth]; + fp->N_RB_DL = dl_Bandwidth; + fp->N_RB_UL = ul_Bandwidth; fp->Nid_cell = Nid_cell; fp->nushift = fp->Nid_cell%6; fp->eutra_band = eutra_band; @@ -154,93 +180,95 @@ void phy_config_request(PHY_Config_t *phy_config) { RC.eNB[Mod_id][CC_id]->X_u); #ifdef Rel14 - if (cfg->emtc_config.prach_ce_level_0_enable.value == 1) { - fp->prach_emtc_config_common.prach_Config_enabled=1; + fp->prach_emtc_config_common.prach_Config_enabled=1; - fp->prach_emtc_config_common.rootSequenceIndex = cfg->emtc_config.prach_catm_root_sequence_index.value; + fp->prach_emtc_config_common.rootSequenceIndex = cfg->emtc_config.prach_catm_root_sequence_index.value; - fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag = cfg->emtc_config.prach_catm_high_speed_flag.value; - fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig = cfg->emtc_config.prach_catm_zero_correlation_zone_configuration.value; + fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag = cfg->emtc_config.prach_catm_high_speed_flag.value; + fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig = cfg->emtc_config.prach_catm_zero_correlation_zone_configuration.value; - // CE Level 3 parameters - fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[3] = cfg->emtc_config.prach_ce_level_3_enable.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[3] = cfg->emtc_config.prach_ce_level_3_starting_subframe_periodicity.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[3] = cfg->emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt.value; - AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[3]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[3], - "prach_starting_subframe_periodicity[3] < prach_numPetitionPerPreambleAttempt[3]\n"); + // CE Level 3 parameters + fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[3] = cfg->emtc_config.prach_ce_level_3_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[3] = cfg->emtc_config.prach_ce_level_3_starting_subframe_periodicity.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[3] = cfg->emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt.value; + AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[3]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[3], + "prach_starting_subframe_periodicity[3] < prach_numPetitionPerPreambleAttempt[3]\n"); - fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3] = cfg->emtc_config.prach_ce_level_3_configuration_index.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[3] = cfg->emtc_config.prach_ce_level_3_frequency_offset.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[3] = cfg->emtc_config.prach_ce_level_3_hopping_enable.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[3] = cfg->emtc_config.prach_ce_level_3_hopping_offset.value; - if (fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[3] == 1) - compute_prach_seq(fp->prach_emtc_config_common.rootSequenceIndex, - fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3], - fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, - fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag, - fp->frame_type, - RC.eNB[Mod_id][CC_id]->X_u_br[3]); + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3] = cfg->emtc_config.prach_ce_level_3_configuration_index.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[3] = cfg->emtc_config.prach_ce_level_3_frequency_offset.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[3] = cfg->emtc_config.prach_ce_level_3_hopping_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[3] = cfg->emtc_config.prach_ce_level_3_hopping_offset.value; + if (fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[3] == 1) + compute_prach_seq(fp->prach_emtc_config_common.rootSequenceIndex, + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3], + fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, + fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag, + fp->frame_type, + RC.eNB[Mod_id][CC_id]->X_u_br[3]); - // CE Level 2 parameters - fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[2] = cfg->emtc_config.prach_ce_level_2_enable.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[2] = cfg->emtc_config.prach_ce_level_2_starting_subframe_periodicity.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[2] = cfg->emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt.value; - AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[2]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[2], - "prach_starting_subframe_periodicity[2] < prach_numPetitionPerPreambleAttempt[2]\n"); - fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[2] = cfg->emtc_config.prach_ce_level_2_configuration_index.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[2] = cfg->emtc_config.prach_ce_level_2_frequency_offset.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[2] = cfg->emtc_config.prach_ce_level_2_hopping_enable.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[2] = cfg->emtc_config.prach_ce_level_2_hopping_offset.value; - if (fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[2] == 1) - compute_prach_seq(fp->prach_emtc_config_common.rootSequenceIndex, - fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3], - fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, - fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag, - fp->frame_type, - RC.eNB[Mod_id][CC_id]->X_u_br[2]); + // CE Level 2 parameters + fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[2] = cfg->emtc_config.prach_ce_level_2_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[2] = cfg->emtc_config.prach_ce_level_2_starting_subframe_periodicity.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[2] = cfg->emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt.value; + AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[2]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[2], + "prach_starting_subframe_periodicity[2] < prach_numPetitionPerPreambleAttempt[2]\n"); + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[2] = cfg->emtc_config.prach_ce_level_2_configuration_index.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[2] = cfg->emtc_config.prach_ce_level_2_frequency_offset.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[2] = cfg->emtc_config.prach_ce_level_2_hopping_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[2] = cfg->emtc_config.prach_ce_level_2_hopping_offset.value; + if (fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[2] == 1) + compute_prach_seq(fp->prach_emtc_config_common.rootSequenceIndex, + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3], + fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, + fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag, + fp->frame_type, + RC.eNB[Mod_id][CC_id]->X_u_br[2]); - // CE Level 1 parameters - fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[1] = cfg->emtc_config.prach_ce_level_1_enable.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[1] = cfg->emtc_config.prach_ce_level_1_starting_subframe_periodicity.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[1] = cfg->emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt.value; - AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[1]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[1], - "prach_starting_subframe_periodicity[1] < prach_numPetitionPerPreambleAttempt[1]\n"); + // CE Level 1 parameters + fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[1] = cfg->emtc_config.prach_ce_level_1_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[1] = cfg->emtc_config.prach_ce_level_1_starting_subframe_periodicity.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[1] = cfg->emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt.value; + AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[1]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[1], + "prach_starting_subframe_periodicity[1] < prach_numPetitionPerPreambleAttempt[1]\n"); - fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[1] = cfg->emtc_config.prach_ce_level_1_configuration_index.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[1] = cfg->emtc_config.prach_ce_level_1_frequency_offset.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[1] = cfg->emtc_config.prach_ce_level_1_hopping_enable.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[1] = cfg->emtc_config.prach_ce_level_1_hopping_offset.value; - if (fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[1] == 1) - compute_prach_seq(fp->prach_emtc_config_common.rootSequenceIndex, - fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3], - fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, - fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag, - fp->frame_type, - RC.eNB[Mod_id][CC_id]->X_u_br[1]); + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[1] = cfg->emtc_config.prach_ce_level_1_configuration_index.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[1] = cfg->emtc_config.prach_ce_level_1_frequency_offset.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[1] = cfg->emtc_config.prach_ce_level_1_hopping_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[1] = cfg->emtc_config.prach_ce_level_1_hopping_offset.value; + if (fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[1] == 1) + compute_prach_seq(fp->prach_emtc_config_common.rootSequenceIndex, + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3], + fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, + fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag, + fp->frame_type, + RC.eNB[Mod_id][CC_id]->X_u_br[1]); - // CE Level 0 parameters - fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0] = cfg->emtc_config.prach_ce_level_0_enable.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[0] = cfg->emtc_config.prach_ce_level_0_starting_subframe_periodicity.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0] = cfg->emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt.value; - AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[0]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0], - "prach_starting_subframe_periodicity[0] %d < prach_numPetitionPerPreambleAttempt[0] %d\n", - fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[0], - fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0]); - AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0] > 0, - "prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0]==0\n"); - fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[0] = cfg->emtc_config.prach_ce_level_0_configuration_index.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[0] = cfg->emtc_config.prach_ce_level_0_frequency_offset.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[0] = cfg->emtc_config.prach_ce_level_0_hopping_enable.value; - fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[0] = cfg->emtc_config.prach_ce_level_0_hopping_offset.value; - if (fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0] == 1) - compute_prach_seq(fp->prach_emtc_config_common.rootSequenceIndex, - fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3], - fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, - fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag, - fp->frame_type, - RC.eNB[Mod_id][CC_id]->X_u_br[0]); - } + // CE Level 0 parameters + fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0] = cfg->emtc_config.prach_ce_level_0_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[0] = cfg->emtc_config.prach_ce_level_0_starting_subframe_periodicity.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0] = cfg->emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt.value; + AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[0]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0], + "prach_starting_subframe_periodicity[0] %d < prach_numPetitionPerPreambleAttempt[0] %d\n", + fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[0], + fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0]); +#if 0 + AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0] > 0, + "prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0]==0\n"); +#else + LOG_E(PHY,"***DJP*** removed assert on preamble fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0]:%d expecting >0 %s:%d\n\n\n", fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0], __FILE__, __LINE__); +#endif + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[0] = cfg->emtc_config.prach_ce_level_0_configuration_index.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[0] = cfg->emtc_config.prach_ce_level_0_frequency_offset.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[0] = cfg->emtc_config.prach_ce_level_0_hopping_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[0] = cfg->emtc_config.prach_ce_level_0_hopping_offset.value; + if (fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0] == 1) + compute_prach_seq(fp->prach_emtc_config_common.rootSequenceIndex, + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3], + fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, + fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag, + fp->frame_type, + RC.eNB[Mod_id][CC_id]->X_u_br[0]); #endif @@ -267,9 +295,9 @@ void phy_config_request(PHY_Config_t *phy_config) { fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 0; fp->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 0; if (cfg->uplink_reference_signal_config.uplink_rs_hopping.value == 1) - fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 1; + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 1; if (cfg->uplink_reference_signal_config.uplink_rs_hopping.value == 2) - fp->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 1; + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 1; LOG_I(PHY,"pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = %d\n",fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled); fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = cfg->uplink_reference_signal_config.group_assignment.value; LOG_I(PHY,"pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = %d\n",fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH); @@ -316,14 +344,14 @@ void phy_config_sib1_ue(uint8_t Mod_id,int CC_id, } /* - void phy_config_sib2_eNB(uint8_t Mod_id, - int CC_id, - RadioResourceConfigCommonSIB_t *radioResourceConfigCommon, - ARFCN_ValueEUTRA_t *ul_CArrierFreq, - long *ul_Bandwidth, - AdditionalSpectrumEmission_t *additionalSpectrumEmission, - struct MBSFN_SubframeConfigList *mbsfn_SubframeConfigList) - { +void phy_config_sib2_eNB(uint8_t Mod_id, + int CC_id, + RadioResourceConfigCommonSIB_t *radioResourceConfigCommon, + ARFCN_ValueEUTRA_t *ul_CArrierFreq, + long *ul_Bandwidth, + AdditionalSpectrumEmission_t *additionalSpectrumEmission, + struct MBSFN_SubframeConfigList *mbsfn_SubframeConfigList) +{ LTE_DL_FRAME_PARMS *fp = &RC.eNB[Mod_id][CC_id]->frame_parms; //LTE_eNB_UE_stats *eNB_UE_stats = RC.eNB[Mod_id][CC_id].eNB_UE_stats; @@ -350,7 +378,7 @@ void phy_config_sib1_ue(uint8_t Mod_id,int CC_id, init_prach_tables(839); compute_prach_seq(&fp->prach_config_common,fp->frame_type, - RC.eNB[Mod_id][CC_id]->X_u); + RC.eNB[Mod_id][CC_id]->X_u); fp->pucch_config_common.deltaPUCCH_Shift = 1+radioResourceConfigCommon->pucch_ConfigCommon.deltaPUCCH_Shift; fp->pucch_config_common.nRB_CQI = radioResourceConfigCommon->pucch_ConfigCommon.nRB_CQI; @@ -392,15 +420,15 @@ void phy_config_sib1_ue(uint8_t Mod_id,int CC_id, fp->soundingrs_ul_config_common.enabled_flag = 0; if (radioResourceConfigCommon->soundingRS_UL_ConfigCommon.present==SoundingRS_UL_ConfigCommon_PR_setup) { - fp->soundingrs_ul_config_common.enabled_flag = 1; - fp->soundingrs_ul_config_common.srs_BandwidthConfig = radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.srs_BandwidthConfig; - fp->soundingrs_ul_config_common.srs_SubframeConfig = radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig; - fp->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission = radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; + fp->soundingrs_ul_config_common.enabled_flag = 1; + fp->soundingrs_ul_config_common.srs_BandwidthConfig = radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.srs_BandwidthConfig; + fp->soundingrs_ul_config_common.srs_SubframeConfig = radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig; + fp->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission = radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; - if (radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts) - fp->soundingrs_ul_config_common.srs_MaxUpPts = 1; - else - fp->soundingrs_ul_config_common.srs_MaxUpPts = 0; + if (radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts) + fp->soundingrs_ul_config_common.srs_MaxUpPts = 1; + else + fp->soundingrs_ul_config_common.srs_MaxUpPts = 0; } @@ -428,34 +456,34 @@ void phy_config_sib1_ue(uint8_t Mod_id,int CC_id, // MBSFN if (mbsfn_SubframeConfigList != NULL) { - fp->num_MBSFN_config = mbsfn_SubframeConfigList->list.count; + fp->num_MBSFN_config = mbsfn_SubframeConfigList->list.count; - for (i=0; ilist.count; i++) { - fp->MBSFN_config[i].radioframeAllocationPeriod = mbsfn_SubframeConfigList->list.array[i]->radioframeAllocationPeriod; - fp->MBSFN_config[i].radioframeAllocationOffset = mbsfn_SubframeConfigList->list.array[i]->radioframeAllocationOffset; + for (i=0; ilist.count; i++) { + fp->MBSFN_config[i].radioframeAllocationPeriod = mbsfn_SubframeConfigList->list.array[i]->radioframeAllocationPeriod; + fp->MBSFN_config[i].radioframeAllocationOffset = mbsfn_SubframeConfigList->list.array[i]->radioframeAllocationOffset; - if (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.present == MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { - fp->MBSFN_config[i].fourFrames_flag = 0; - fp->MBSFN_config[i].mbsfn_SubframeConfig = mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[0]; // 6-bit subframe configuration - LOG_I(PHY, "[CONFIG] MBSFN_SubframeConfig[%d] pattern is %d\n", i, - fp->MBSFN_config[i].mbsfn_SubframeConfig); - } else if (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.present == MBSFN_SubframeConfig__subframeAllocation_PR_fourFrames) { // 24-bit subframe configuration - fp->MBSFN_config[i].fourFrames_flag = 1; - fp->MBSFN_config[i].mbsfn_SubframeConfig = - mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[0]| - (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[1]<<8)| - (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[2]<<16); + if (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.present == MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { + fp->MBSFN_config[i].fourFrames_flag = 0; + fp->MBSFN_config[i].mbsfn_SubframeConfig = mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[0]; // 6-bit subframe configuration + LOG_I(PHY, "[CONFIG] MBSFN_SubframeConfig[%d] pattern is %d\n", i, + fp->MBSFN_config[i].mbsfn_SubframeConfig); + } else if (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.present == MBSFN_SubframeConfig__subframeAllocation_PR_fourFrames) { // 24-bit subframe configuration + fp->MBSFN_config[i].fourFrames_flag = 1; + fp->MBSFN_config[i].mbsfn_SubframeConfig = + mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[0]| + (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[1]<<8)| + (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[2]<<16); - LOG_I(PHY, "[CONFIG] MBSFN_SubframeConfig[%d] pattern is %d\n", i, - fp->MBSFN_config[i].mbsfn_SubframeConfig); - } - } + LOG_I(PHY, "[CONFIG] MBSFN_SubframeConfig[%d] pattern is %d\n", i, + fp->MBSFN_config[i].mbsfn_SubframeConfig); + } + } } else - fp->num_MBSFN_config = 0; + fp->num_MBSFN_config = 0; // - } +} */ void phy_config_sib2_ue(uint8_t Mod_id,int CC_id, @@ -667,9 +695,9 @@ void phy_config_dedicated_eNB_step2(PHY_VARS_eNB *eNB) eNB->pusch_config_dedicated[UE_id].betaOffset_RI_Index = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index; eNB->pusch_config_dedicated[UE_id].betaOffset_CQI_Index = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index; - LOG_D(PHY,"pusch_config_dedicated.betaOffset_ACK_Index %d\n",eNB->pusch_config_dedicated[UE_id].betaOffset_ACK_Index); - LOG_D(PHY,"pusch_config_dedicated.betaOffset_RI_Index %d\n",eNB->pusch_config_dedicated[UE_id].betaOffset_RI_Index); - LOG_D(PHY,"pusch_config_dedicated.betaOffset_CQI_Index %d\n",eNB->pusch_config_dedicated[UE_id].betaOffset_CQI_Index); + LOG_E(PHY,"pusch_config_dedicated.betaOffset_ACK_Index %d\n",eNB->pusch_config_dedicated[UE_id].betaOffset_ACK_Index); + LOG_E(PHY,"pusch_config_dedicated.betaOffset_RI_Index %d\n",eNB->pusch_config_dedicated[UE_id].betaOffset_RI_Index); + LOG_E(PHY,"pusch_config_dedicated.betaOffset_CQI_Index %d\n",eNB->pusch_config_dedicated[UE_id].betaOffset_CQI_Index); LOG_D(PHY,"\n"); @@ -855,7 +883,7 @@ void phy_config_afterHO_ue(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_id, Mobility PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[1][eNB_id]->crnti = mobilityControlInfo->newUE_Identity.buf[0]|(mobilityControlInfo->newUE_Identity.buf[1]<<8); LOG_I(PHY,"SET C-RNTI %x %x\n",PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[0][eNB_id]->crnti, - PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[1][eNB_id]->crnti); + PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[1][eNB_id]->crnti); } if(ho_failed) { @@ -884,67 +912,67 @@ void phy_config_meas_ue(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index,uint8_t n } /* - void phy_config_dedicated_eNB(uint8_t Mod_id, - int CC_id, - uint16_t rnti, - struct PhysicalConfigDedicated *physicalConfigDedicated) - { +void phy_config_dedicated_eNB(uint8_t Mod_id, + int CC_id, + uint16_t rnti, + struct PhysicalConfigDedicated *physicalConfigDedicated) +{ PHY_VARS_eNB *eNB = RC.eNB[Mod_id][CC_id]; int8_t UE_id = find_ue(rnti,eNB); int i; if (UE_id == -1) { - LOG_E( PHY, "[eNB %"PRIu8"] find_ue() returns -1\n", Mod_id); - return; + LOG_E( PHY, "[eNB %"PRIu8"] find_ue() returns -1\n", Mod_id); + return; } if (physicalConfigDedicated) { - eNB->physicalConfigDedicated[UE_id] = physicalConfigDedicated; - LOG_I(PHY,"phy_config_dedicated_eNB: physicalConfigDedicated=%p\n",physicalConfigDedicated); + eNB->physicalConfigDedicated[UE_id] = physicalConfigDedicated; + LOG_I(PHY,"phy_config_dedicated_eNB: physicalConfigDedicated=%p\n",physicalConfigDedicated); - if (physicalConfigDedicated->antennaInfo) { - switch(physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode) { - case AntennaInfoDedicated__transmissionMode_tm1: - eNB->transmission_mode[UE_id] = 1; - break; - case AntennaInfoDedicated__transmissionMode_tm2: - eNB->transmission_mode[UE_id] = 2; - break; - case AntennaInfoDedicated__transmissionMode_tm3: - eNB->transmission_mode[UE_id] = 3; - break; - case AntennaInfoDedicated__transmissionMode_tm4: - eNB->transmission_mode[UE_id] = 4; - break; - case AntennaInfoDedicated__transmissionMode_tm5: - eNB->transmission_mode[UE_id] = 5; - break; - case AntennaInfoDedicated__transmissionMode_tm6: - eNB->transmission_mode[UE_id] = 6; - break; - case AntennaInfoDedicated__transmissionMode_tm7: - lte_gold_ue_spec_port5(eNB->lte_gold_uespec_port5_table[0],eNB->frame_parms.Nid_cell,rnti); + if (physicalConfigDedicated->antennaInfo) { + switch(physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode) { + case AntennaInfoDedicated__transmissionMode_tm1: + eNB->transmission_mode[UE_id] = 1; + break; + case AntennaInfoDedicated__transmissionMode_tm2: + eNB->transmission_mode[UE_id] = 2; + break; + case AntennaInfoDedicated__transmissionMode_tm3: + eNB->transmission_mode[UE_id] = 3; + break; + case AntennaInfoDedicated__transmissionMode_tm4: + eNB->transmission_mode[UE_id] = 4; + break; + case AntennaInfoDedicated__transmissionMode_tm5: + eNB->transmission_mode[UE_id] = 5; + break; + case AntennaInfoDedicated__transmissionMode_tm6: + eNB->transmission_mode[UE_id] = 6; + break; + case AntennaInfoDedicated__transmissionMode_tm7: + lte_gold_ue_spec_port5(eNB->lte_gold_uespec_port5_table[0],eNB->frame_parms.Nid_cell,rnti); - for (i=0;inum_RU;i++) eNB->RU_list[i]->do_precoding=1; - eNB->transmission_mode[UE_id] = 7; - break; - default: - LOG_E(PHY,"Unknown transmission mode!\n"); - break; - } - LOG_I(PHY,"Transmission Mode (phy_config_dedicated_eNB) %d\n",eNB->transmission_mode[UE_id]); + for (i=0;inum_RU;i++) eNB->RU_list[i]->do_precoding=1; + eNB->transmission_mode[UE_id] = 7; + break; + default: + LOG_E(PHY,"Unknown transmission mode!\n"); + break; + } + LOG_I(PHY,"Transmission Mode (phy_config_dedicated_eNB) %d\n",eNB->transmission_mode[UE_id]); + } else { + LOG_D(PHY,"[eNB %d] : Received NULL radioResourceConfigDedicated->antennaInfo from eNB %d\n",Mod_id,UE_id); + } } else { - LOG_D(PHY,"[eNB %d] : Received NULL radioResourceConfigDedicated->antennaInfo from eNB %d\n",Mod_id,UE_id); - } - } else { - LOG_E(PHY,"[eNB %d] Received NULL radioResourceConfigDedicated from eNB %d\n",Mod_id, UE_id); - return; + LOG_E(PHY,"[eNB %d] Received NULL radioResourceConfigDedicated from eNB %d\n",Mod_id, UE_id); + return; } - } +} */ #if defined(Rel10) || defined(Rel14) @@ -956,11 +984,11 @@ void phy_config_dedicated_scell_ue(uint8_t Mod_id, } /* - void phy_config_dedicated_scell_eNB(uint8_t Mod_id, - uint16_t rnti, - SCellToAddMod_r10_t *sCellToAddMod_r10, - int CC_id) - { +void phy_config_dedicated_scell_eNB(uint8_t Mod_id, + uint16_t rnti, + SCellToAddMod_r10_t *sCellToAddMod_r10, + int CC_id) +{ uint8_t UE_id = find_ue(rnti,RC.eNB[Mod_id][0]); @@ -971,37 +999,37 @@ void phy_config_dedicated_scell_ue(uint8_t Mod_id, uint32_t carrier_freq_local; if ((dl_CarrierFreq_r10>=36000) && (dl_CarrierFreq_r10<=36199)) { - carrier_freq_local = 1900000000 + (dl_CarrierFreq_r10-36000)*100000; //band 33 from 3GPP 36.101 v 10.9 Table 5.7.3-1 - LOG_I(PHY,"[eNB %d] Frame %d: Configured SCell %d to frequency %d (ARFCN %ld) for UE %d\n",Mod_id, - //eNB->frame - 0, - CC_id,carrier_freq_local,dl_CarrierFreq_r10,UE_id); + carrier_freq_local = 1900000000 + (dl_CarrierFreq_r10-36000)*100000; //band 33 from 3GPP 36.101 v 10.9 Table 5.7.3-1 + LOG_I(PHY,"[eNB %d] Frame %d: Configured SCell %d to frequency %d (ARFCN %ld) for UE %d\n",Mod_id, + //eNB->frame + 0, + CC_id,carrier_freq_local,dl_CarrierFreq_r10,UE_id); } else if ((dl_CarrierFreq_r10>=6150) && (dl_CarrierFreq_r10<=6449)) { - carrier_freq_local = 832000000 + (dl_CarrierFreq_r10-6150)*100000; //band 20 from 3GPP 36.101 v 10.9 Table 5.7.3-1 - // this is actually for the UL only, but we use it for DL too, since there is no TDD mode for this band - LOG_I(PHY,"[eNB %d] Frame %d: Configured SCell %d to frequency %d (ARFCN %ld) for UE %d\n",Mod_id, - //eNB->frame - 0,CC_id,carrier_freq_local,dl_CarrierFreq_r10,UE_id); + carrier_freq_local = 832000000 + (dl_CarrierFreq_r10-6150)*100000; //band 20 from 3GPP 36.101 v 10.9 Table 5.7.3-1 + // this is actually for the UL only, but we use it for DL too, since there is no TDD mode for this band + LOG_I(PHY,"[eNB %d] Frame %d: Configured SCell %d to frequency %d (ARFCN %ld) for UE %d\n",Mod_id, + //eNB->frame + 0,CC_id,carrier_freq_local,dl_CarrierFreq_r10,UE_id); } else { - LOG_E(PHY,"[eNB %d] Frame %d: ARFCN %ld of SCell %d for UE %d not supported\n",Mod_id, - //eNB->frame - 0,dl_CarrierFreq_r10,CC_id,UE_id); + LOG_E(PHY,"[eNB %d] Frame %d: ARFCN %ld of SCell %d for UE %d not supported\n",Mod_id, + //eNB->frame + 0,dl_CarrierFreq_r10,CC_id,UE_id); } if (physicalConfigDedicatedSCell_r10) { - //#warning " eNB->physicalConfigDedicatedSCell_r10 does not exist in eNB" - // eNB->physicalConfigDedicatedSCell_r10[UE_id] = physicalConfigDedicatedSCell_r10; - LOG_I(PHY,"[eNB %d] Frame %d: Configured phyConfigDedicatedSCell with CC_id %d for UE %d\n",Mod_id, - //eNB->frame - 0,CC_id,UE_id); +//#warning " eNB->physicalConfigDedicatedSCell_r10 does not exist in eNB" + // eNB->physicalConfigDedicatedSCell_r10[UE_id] = physicalConfigDedicatedSCell_r10; + LOG_I(PHY,"[eNB %d] Frame %d: Configured phyConfigDedicatedSCell with CC_id %d for UE %d\n",Mod_id, + //eNB->frame + 0,CC_id,UE_id); } else { - LOG_E(PHY,"[eNB %d] Frame %d: Received NULL radioResourceConfigDedicated (CC_id %d, UE %d)\n",Mod_id, - //eNB->frame - 0,CC_id,UE_id); - return; + LOG_E(PHY,"[eNB %d] Frame %d: Received NULL radioResourceConfigDedicated (CC_id %d, UE %d)\n",Mod_id, + //eNB->frame + 0,CC_id,UE_id); + return; } - } +} */ #endif @@ -1178,7 +1206,7 @@ void phy_config_dedicated_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id, } if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic) { if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_setup) { - // configure PUCCH CQI reporting + // configure PUCCH CQI reporting phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PUCCH_ResourceIndex = physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex; phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex = physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.cqi_pmi_ConfigIndex; if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.ri_ConfigIndex) @@ -1221,12 +1249,12 @@ void phy_config_dedicated_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id, } //phy_vars_ue->pdcch_vars[1][eNB_id]->crnti = phy_vars_ue->pdcch_vars[0][eNB_id]->crnti; if(phy_vars_ue->pdcch_vars[0][eNB_id]->crnti == 0x1234) - phy_vars_ue->pdcch_vars[0][eNB_id]->crnti = phy_vars_ue->pdcch_vars[1][eNB_id]->crnti; + phy_vars_ue->pdcch_vars[0][eNB_id]->crnti = phy_vars_ue->pdcch_vars[1][eNB_id]->crnti; else - phy_vars_ue->pdcch_vars[1][eNB_id]->crnti = phy_vars_ue->pdcch_vars[0][eNB_id]->crnti; + phy_vars_ue->pdcch_vars[1][eNB_id]->crnti = phy_vars_ue->pdcch_vars[0][eNB_id]->crnti; LOG_I(PHY,"C-RNTI %x %x \n", phy_vars_ue->pdcch_vars[0][eNB_id]->crnti, - phy_vars_ue->pdcch_vars[1][eNB_id]->crnti); + phy_vars_ue->pdcch_vars[1][eNB_id]->crnti); } @@ -1690,7 +1718,7 @@ int phy_init_RU(RU_t *ru) { ru->common.txdata[i] = (int32_t*)malloc16_clear( fp->samples_per_tti*10*sizeof(int32_t) ); LOG_I(PHY,"[INIT] common.txdata[%d] = %p (%lu bytes)\n",i,ru->common.txdata[i], - fp->samples_per_tti*10*sizeof(int32_t)); + fp->samples_per_tti*10*sizeof(int32_t)); } for (i=0;inb_rx;i++) { @@ -1748,9 +1776,13 @@ int phy_init_RU(RU_t *ru) { AssertFatal(RC.nb_L1_inst <= NUMBER_OF_eNB_MAX,"eNB instances %d > %d\n", RC.nb_L1_inst,NUMBER_OF_eNB_MAX); + LOG_E(PHY,"[INIT] %s() RC.nb_L1_inst:%d \n", __FUNCTION__, RC.nb_L1_inst); + for (i=0; ieNB_list[i]->frame_parms.nb_antenna_ports_eNB); if (peNB_list[i]->frame_parms.nb_antenna_ports_eNB || p==5) { + LOG_D(PHY,"[INIT] %s() DO BEAM WEIGHTS nb_antenna_ports_eNB:%d nb_tx:%d\n", __FUNCTION__, ru->eNB_list[i]->frame_parms.nb_antenna_ports_eNB, ru->nb_tx); ru->beam_weights[i][p] = (int32_t **)malloc16_clear(ru->nb_tx*sizeof(int32_t*)); for (j=0; jnb_tx; j++) { ru->beam_weights[i][p][j] = (int32_t *)malloc16_clear(fp->ofdm_symbol_size*sizeof(int32_t)); @@ -1759,15 +1791,20 @@ int phy_init_RU(RU_t *ru) { // antenna ports 5-14 are mapped on all antennas if (((p<4) && (p==j)) || ((p==4) && (j==0))) { for (re=0; reofdm_symbol_size; re++) + { ru->beam_weights[i][p][j][re] = 0x00007fff; + + //LOG_D(PHY,"[INIT] lte_common_vars->beam_weights[%d][%d][%d][%d] = %d\n", i,p,j,re,ru->beam_weights[i][p][j][re]); + } } else if (p>4) { for (re=0; reofdm_symbol_size; re++) + { ru->beam_weights[i][p][j][re] = 0x00007fff/ru->nb_tx; + //LOG_D(PHY,"[INIT] lte_common_vars->beam_weights[%d][%d][%d][%d] = %d\n", i,p,j,re,ru->beam_weights[i][p][j][re]); + } } - LOG_D(PHY,"[INIT] lte_common_vars->beam_weights[%d][%d] = %p (%lu bytes)\n", - i,j,ru->beam_weights[i][p][j], - fp->ofdm_symbol_size*sizeof(int32_t)); + //LOG_D(PHY,"[INIT] lte_common_vars->beam_weights[%d][%d] = %p (%lu bytes)\n", i,j,ru->beam_weights[i][p][j], fp->ofdm_symbol_size*sizeof(int32_t)); } } } @@ -1794,6 +1831,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, #endif int i, UE_id; + LOG_I(PHY,"[eNB %d] %s() About to wait for eNB to be configured", eNB->Mod_id, __FUNCTION__); eNB->total_dlsch_bitrate = 0; eNB->total_transmitted_bits = 0; @@ -1802,10 +1840,18 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, while(eNB->configured == 0) usleep(10000); - LOG_I(PHY,"[eNB %"PRIu8"] Initializing DL_FRAME_PARMS : N_RB_DL %"PRIu8", PHICH Resource %d, PHICH Duration %d\n", + LOG_I(PHY,"[eNB %"PRIu8"] Initializing DL_FRAME_PARMS : N_RB_DL %"PRIu8", PHICH Resource %d, PHICH Duration %d nb_antennas_tx:%u nb_antennas_rx:%u nb_antenna_ports_eNB:%u PRACH[rootSequenceIndex:%u prach_Config_enabled:%u configIndex:%u highSpeed:%u zeroCorrelationZoneConfig:%u freqOffset:%u]\n", eNB->Mod_id, fp->N_RB_DL,fp->phich_config_common.phich_resource, - fp->phich_config_common.phich_duration); + fp->phich_config_common.phich_duration, + fp->nb_antennas_tx, fp->nb_antennas_rx, fp->nb_antenna_ports_eNB, + fp->prach_config_common.rootSequenceIndex, + fp->prach_config_common.prach_Config_enabled, + fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex, + fp->prach_config_common.prach_ConfigInfo.highSpeedFlag, + fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, + fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset + ); LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_eNB][MOD %02"PRIu8"][]\n", eNB->Mod_id); @@ -1832,6 +1878,8 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, common_vars->txdataF = (int32_t **)malloc16(NB_ANTENNA_PORTS_ENB*sizeof(int32_t*)); common_vars->rxdataF = (int32_t **)malloc16(64*sizeof(int32_t*)); + LOG_D(PHY,"[INIT] NB_ANTENNA_PORTS_ENB:%d fp->nb_antenna_ports_eNB:%d\n", NB_ANTENNA_PORTS_ENB, fp->nb_antenna_ports_eNB); + for (i=0; inb_antenna_ports_eNB || i==5) { common_vars->txdataF[i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*fp->symbols_per_tti*10*sizeof(int32_t) ); @@ -1886,12 +1934,12 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, #endif /* number of elements of an array X is computed as sizeof(X) / sizeof(X[0]) - AssertFatal(fp->nb_antennas_rx <= sizeof(prach_vars->rxsigF) / sizeof(prach_vars->rxsigF[0]), - "nb_antennas_rx too large"); - for (i=0; inb_antennas_rx; i++) { - prach_vars->rxsigF[i] = (int16_t*)malloc16_clear( fp->ofdm_symbol_size*12*2*sizeof(int16_t) ); - LOG_D(PHY,"[INIT] prach_vars->rxsigF[%d] = %p\n",i,prach_vars->rxsigF[i]); - }*/ + AssertFatal(fp->nb_antennas_rx <= sizeof(prach_vars->rxsigF) / sizeof(prach_vars->rxsigF[0]), + "nb_antennas_rx too large"); + for (i=0; inb_antennas_rx; i++) { + prach_vars->rxsigF[i] = (int16_t*)malloc16_clear( fp->ofdm_symbol_size*12*2*sizeof(int16_t) ); + LOG_D(PHY,"[INIT] prach_vars->rxsigF[%d] = %p\n",i,prach_vars->rxsigF[i]); + }*/ for (UE_id=0; UE_idrxdataF_comp[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti ); pusch_vars[UE_id]->ul_ch_mag[i] = (int32_t*)malloc16_clear( fp->symbols_per_tti*sizeof(int32_t)*fp->N_RB_UL*12 ); pusch_vars[UE_id]->ul_ch_magb[i] = (int32_t*)malloc16_clear( fp->symbols_per_tti*sizeof(int32_t)*fp->N_RB_UL*12 ); - } + } pusch_vars[UE_id]->llr = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); } //UE_id @@ -1934,3 +1982,9 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, return (0); } + +void install_schedule_handlers(IF_Module_t *if_inst) +{ + if_inst->PHY_config_req = phy_config_request; + if_inst->schedule_response = schedule_response; +} diff --git a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c index cd032e688f..f852235c18 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c @@ -258,7 +258,7 @@ int lte_est_timing_advance_pusch(PHY_VARS_eNB* eNB,uint8_t UE_id) max_pos = max_pos-frame_parms->ofdm_symbol_size; //#ifdef DEBUG_PHY - LOG_D(PHY,"frame %d: max_pos = %d, sync_pos=%d\n",eNB->proc.frame_rx,max_pos,sync_pos); + //LOG_D(PHY,"frame %d: max_pos = %d, sync_pos=%d\n",eNB->proc.frame_rx,max_pos,sync_pos); //#endif //DEBUG_PHY return max_pos - sync_pos; diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index 1bea8db59a..6ec745293f 100755 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -43,6 +43,7 @@ #include "assertions.h" #include "T.h" #include "UTIL/LOG/log.h" +#include "UTIL/LOG/vcd_signal_dumper.h" //#define DEBUG_DCI_ENCODING 1 //#define DEBUG_DCI_DECODING 1 @@ -2065,6 +2066,8 @@ void pdcch_scrambling(LTE_DL_FRAME_PARMS *frame_parms, uint8_t reset; uint32_t x1, x2, s=0; + //LOG_D(PHY, "%s(fp, subframe:%d, e, length:%d)\n", __FUNCTION__, subframe, length); + reset = 1; // x1 is set in lte_gold_generic @@ -2216,6 +2219,11 @@ uint8_t generate_dci_top(uint8_t num_pdcch_symbols, int Msymb2; int split_flag=0; + if (num_dci>0) + { + //LOG_D(PHY,"%s(num_pdcch_symbols:%d num_dci:%d dci_alloc:%p n_rnti:%04x amp:%d frame_parms:%p txdataF:%p subframe:%d)\n", __FUNCTION__, num_pdcch_symbols, num_dci, dci_alloc, n_rnti, amp, frame_parms, txdataF, subframe); + } + switch (frame_parms->N_RB_DL) { case 100: Msymb2 = Msymb; @@ -2247,11 +2255,13 @@ uint8_t generate_dci_top(uint8_t num_pdcch_symbols, } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_PCFICH,1); generate_pcfich(num_pdcch_symbols, amp, frame_parms, txdataF, subframe); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_PCFICH,0); wbar[0] = &wbar0[0]; wbar[1] = &wbar1[0]; y[0] = &yseq0[0]; @@ -2272,6 +2282,7 @@ uint8_t generate_dci_top(uint8_t num_pdcch_symbols, e_ptr = e; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DCI0,1); // generate DCIs in order of decreasing aggregation level, then common/ue spec // MAC is assumed to have ordered the UE spec DCI according to the RNTI-based randomization @@ -2298,18 +2309,26 @@ uint8_t generate_dci_top(uint8_t num_pdcch_symbols, } } } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DCI0,0); // Scrambling - // printf("pdcch scrambling\n"); +#ifdef DEBUG_DCI_ENCODING + printf("pdcch scrambling\n"); +#endif + //LOG_D(PHY, "num_pdcch_symbols:%d mi:%d nquad:%d\n", num_pdcch_symbols, mi, get_nquad(num_pdcch_symbols, frame_parms, mi)); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_SCRAMBLING,1); pdcch_scrambling(frame_parms, subframe, e, 8*get_nquad(num_pdcch_symbols, frame_parms, mi)); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_SCRAMBLING,0); //72*get_nCCE(num_pdcch_symbols,frame_parms,mi)); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_MODULATION,1); // Now do modulation if (frame_parms->nb_antenna_ports_eNB==1) gain_lin_QPSK = (int16_t)((amp*ONE_OVER_SQRT2_Q15)>>15); @@ -2322,6 +2341,7 @@ uint8_t generate_dci_top(uint8_t num_pdcch_symbols, printf(" PDCCH Modulation, Msymb %d, Msymb2 %d,gain_lin_QPSK %d\n",Msymb,Msymb2,gain_lin_QPSK); #endif + //LOG_D(PHY,"%s() Msymb2:%d\n", __FUNCTION__, Msymb2); if (frame_parms->nb_antenna_ports_eNB==1) { //SISO @@ -2368,22 +2388,38 @@ uint8_t generate_dci_top(uint8_t num_pdcch_symbols, } } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_MODULATION,0); #ifdef DEBUG_DCI_ENCODING printf(" PDCCH Interleaving\n"); #endif + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_INTERLEAVING,1); // printf("y %p (%p,%p), wbar %p (%p,%p)\n",y,y[0],y[1],wbar,wbar[0],wbar[1]); // This is the interleaving procedure defined in 36-211, first part of Section 6.8.5 pdcch_interleaving(frame_parms,&y[0],&wbar[0],num_pdcch_symbols,mi); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_INTERLEAVING,0); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_TX,1); mprime=0; nsymb = (frame_parms->Ncp==0) ? 14:12; re_offset = frame_parms->first_carrier_offset; // This is the REG allocation algorithm from 36-211, second part of Section 6.8.5 // printf("DCI (SF %d) : txdataF %p (0 %p)\n",subframe,&txdataF[0][512*14*subframe],&txdataF[0][0]); +#ifdef DEBUG_DCI_ENCODING + printf("kprime loop - N_RB_DL:%d lprime:num_pdcch_symbols:%d Ncp:%d pcfich:%02x,%02x,%02x,%02x ofdm_symbol_size:%d first_carrier_offset:%d nb_antenna_ports_eNB:%d\n", + frame_parms->N_RB_DL, num_pdcch_symbols,frame_parms->Ncp, + frame_parms->pcfich_reg[0], + frame_parms->pcfich_reg[1], + frame_parms->pcfich_reg[2], + frame_parms->pcfich_reg[3], + frame_parms->ofdm_symbol_size, + frame_parms->first_carrier_offset, + frame_parms->nb_antenna_ports_eNB + ); +#endif for (kprime=0; kprimeN_RB_DL*12; kprime++) { for (lprime=0; lprimeofdm_symbol_size)) re_offset = 1; } // kprime loop + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_TX,0); return(num_pdcch_symbols); } diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 97a9709df5..bab605b573 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -801,6 +801,28 @@ void generate_RIV_tables() // n_tilde_PRB(0,1) = (0,2) +void check_dlsch(char *file, int line) +{ + PHY_VARS_eNB *eNB = RC.eNB[0][0]; + static char oldbuf[13*NUMBER_OF_UE_MAX+100]=""; + char buf[13*NUMBER_OF_UE_MAX+100]; + char *pbuf=buf; + + for (int i=0; idlsch[i][0]->harq_mask, eNB->dlsch[i][0]->rnti); + } + + int diff_size = memcmp(oldbuf, buf, strlen(buf)); + + if (diff_size!=0) + { + LOG_I(PHY,"check_dlsch:%s:%d:%s\n", file, line, buf); + LOG_I(PHY,"check_dlsch:%s:%d:%s\n", file, line, oldbuf); + } + + memcpy(oldbuf, buf, sizeof(buf)); +} + int8_t find_dlsch(uint16_t rnti, PHY_VARS_eNB *eNB,find_type_t type) { uint8_t i; @@ -810,8 +832,7 @@ int8_t find_dlsch(uint16_t rnti, PHY_VARS_eNB *eNB,find_type_t type) for (i=0; idlsch[i]!=NULL,"eNB->dlsch[%d] is null\n",i); AssertFatal(eNB->dlsch[i]!=NULL,"eNB->dlsch[%d][0] is null\n",i); - LOG_D(PHY,"searching for rnti %x : UE index %d=> harq_mask %x, rnti %x, first_free_index %d\n", - rnti,i,eNB->dlsch[i][0]->harq_mask,eNB->dlsch[i][0]->rnti,first_free_index); + LOG_D(PHY,"searching for rnti %x : UE index %d=> harq_mask %x, rnti %x, first_free_index %d\n", rnti,i,eNB->dlsch[i][0]->harq_mask,eNB->dlsch[i][0]->rnti,first_free_index); if ((eNB->dlsch[i][0]->harq_mask >0) && (eNB->dlsch[i][0]->rnti==rnti)) return i; else if ((eNB->dlsch[i][0]->harq_mask == 0) && (first_free_index==-1)) first_free_index=i; @@ -987,7 +1008,7 @@ void fill_pdcch_order(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_a proc->frame_tx, proc->subframe_tx, rel8->rnti); } -void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc,nfapi_dl_config_dci_dl_pdu *pdu) +void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc,nfapi_dl_config_dci_dl_pdu *pdu) { LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; uint8_t *dci_pdu = &dci_alloc->dci_pdu[0]; @@ -1011,7 +1032,6 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci LTE_DL_eNB_HARQ_t *dlsch0_harq=NULL,*dlsch1_harq=NULL; int beamforming_mode = 0; int UE_id=-1; - int subframe = proc->subframe_tx; int NPRB; int TB0_active; int TB1_active; @@ -1024,8 +1044,8 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci dci_alloc->harq_pid = rel8->harq_process; dci_alloc->ra_flag = 0; - LOG_D(PHY,"NFAPI: DCI format %d, nCCE %d, L %d, rnti %x,harq_pid %d\n", - rel8->dci_format,rel8->cce_idx,rel8->aggregation_level,rel8->rnti,rel8->harq_process); + LOG_D(PHY,"NFAPI: SFN/SF:%04d%d proc:TX:[SFN/SF:%04d%d] DCI format %d, nCCE %d, L %d, rnti %x, harq_pid %d\n", + frame,subframe,proc->frame_tx,proc->subframe_tx,rel8->dci_format,rel8->cce_idx,rel8->aggregation_level,rel8->rnti,rel8->harq_process); if ((rel8->rnti_type == 2 ) && (rel8->rnti != SI_RNTI) && (rel8->rnti != P_RNTI)) dci_alloc->ra_flag = 1; UE_id = find_dlsch(rel8->rnti,eNB,SEARCH_EXIST_OR_FREE); @@ -1041,6 +1061,14 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci dlsch1_harq = dlsch1->harq_processes[rel8->harq_process]; dlsch1_harq->codeword = 1; dlsch0->subframe_tx[subframe] = 1; + + LOG_D(PHY,"NFAPI: SFN/SF:%04d%d proc:TX:SFN/SF:%04d%d dlsch0[rnti:%x harq_mask:%04x] dci_pdu[rnti:%x rnti_type:%d harq_process:%d ndi1:%d] dlsch0_harq[round:%d harq_mask:%x ndi:%d]\n", + frame,subframe, + proc->frame_tx,proc->subframe_tx, + dlsch0->rnti,dlsch0->harq_mask, + rel8->rnti, rel8->rnti_type, rel8->harq_process, rel8->new_data_indicator_1, + dlsch0_harq->round, dlsch0->harq_mask, dlsch0_harq->ndi); + if (dlsch0->rnti != rel8->rnti) { // if rnti of dlsch is not the same as in the config, this is a new entry dlsch0_harq->round=0; dlsch0->harq_mask=0; @@ -1057,15 +1085,19 @@ void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci dlsch0->active = 1; if (rel8->rnti_type == 2) dlsch0_harq->round = 0; -LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n",rel8->harq_process,dlsch0->harq_mask,dlsch0_harq->round, - dlsch0_harq->ndi,rel8->new_data_indicator_1, rel8->rnti_type); + + LOG_D(PHY,"NFAPI: rel8[rnti %x dci_format %d harq_process %d ndi1 %d rnti type %d] dlsch0[rnti %x harq_mask %x] dlsch0_harq[round %d ndi %d]\n", + rel8->rnti,rel8->dci_format,rel8->harq_process, rel8->new_data_indicator_1, rel8->rnti_type, + dlsch0->rnti,dlsch0->harq_mask, + dlsch0_harq->round,dlsch0_harq->ndi + ); switch (rel8->dci_format) { case NFAPI_DL_DCI_FORMAT_1A: - AssertFatal(rel8->resource_block_coding < 8192, "Frame %d, Subframe %d: rel8->resource_block_coding (%p) %u >= 8192 (rnti %x, rnti_type %d, format %d, harq_id %d\n", - proc->frame_tx,subframe, + AssertFatal(rel8->resource_block_coding < 8192, "SFN/SF:%04d%d proc:TX:SFN/SF:%04d%d: rel8->resource_block_coding (%p) %u >= 8192 (rnti %x, rnti_type %d, format %d, harq_id %d\n", + frame,subframe,proc->frame_tx,subframe, &rel8->resource_block_coding,rel8->resource_block_coding,rel8->rnti,rel8->rnti_type,rel8->dci_format,rel8->harq_process); @@ -1208,7 +1240,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" NPRB = dlsch0_harq->nb_rb; I_mcs = get_I_TBS(rel8->mcs_1); } - AssertFatal(NPRB>0,"DCI 1A: NPRB = 0 (rnti %x, rnti type %d, tpc %d, round %d, resource_block_coding %d)\n",rel8->rnti,rel8->rnti_type,rel8->tpc,dlsch0_harq->round,rel8->resource_block_coding); + AssertFatal(NPRB>0,"DCI 1A: NPRB = 0 (rnti %x, rnti type %d, tpc %d, round %d, resource_block_coding %d, harq process %d)\n",rel8->rnti,rel8->rnti_type,rel8->tpc,dlsch0_harq->round,rel8->resource_block_coding,rel8->harq_process); dlsch0_harq->rvidx = rel8->redundancy_version_1; dlsch0_harq->Nl = 1; dlsch0_harq->mimo_mode = (fp->nb_antenna_ports_eNB == 1) ? SISO : ALAMOUTI; @@ -1228,7 +1260,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" dlsch0->harq_mask |= (1<harq_process); - if (rel8->rnti_type == 1) LOG_I(PHY,"DCI 1A: round %d, mcs %d, rballoc %x,rv %d, rnti %x\n",dlsch0_harq->round,rel8->mcs_1,rel8->resource_block_coding,rel8->redundancy_version_1,rel8->rnti); + if (rel8->rnti_type == 1) LOG_I(PHY,"DCI 1A: round %d, mcs %d, rballoc %x, rv %d, rnti %x, harq process %d\n",dlsch0_harq->round,rel8->mcs_1,rel8->resource_block_coding,rel8->redundancy_version_1,rel8->rnti,rel8->harq_process); break; case NFAPI_DL_DCI_FORMAT_1: @@ -1236,7 +1268,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" dci_alloc->format = format1; dlsch0->active = 1; - LOG_D(PHY,"Frame %d, Subframe %d: Programming DLSCH for Format 1 DCI, harq_pid %d\n",proc->frame_tx,subframe,rel8->harq_process); + LOG_D(PHY,"SFN/SF:%04d%d proc:TX:SFN/SF:%04d%d: Programming DLSCH for Format 1 DCI, harq_pid %d\n",frame,subframe,proc->frame_tx,subframe,rel8->harq_process); switch (fp->N_RB_DL) { case 6: @@ -2093,11 +2125,11 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" } if (dlsch0_harq) { - dlsch0_harq->frame = proc->frame_tx; + dlsch0_harq->frame = frame; dlsch0_harq->subframe = subframe; } if (dlsch1_harq) { - dlsch1_harq->frame = proc->frame_tx; + dlsch1_harq->frame = frame; dlsch1_harq->subframe = subframe; } @@ -2135,7 +2167,7 @@ LOG_D(PHY,"NFAPI: harq_pid %d harq_mask %x, round %d ndi (%d,%d) rnti type %d\n" #if T_TRACER if (dlsch0->active) - T(T_ENB_PHY_DLSCH_UE_DCI, T_INT(0), T_INT(proc->frame_tx), T_INT(proc->subframe_tx), + T(T_ENB_PHY_DLSCH_UE_DCI, T_INT(0), T_INT(frame), T_INT(subframe), T_INT(rel8->rnti), T_INT(rel8->dci_format), T_INT(rel8->harq_process), T_INT(rel8->mcs_1), T_INT(dlsch0_harq->TBS)); #endif @@ -2382,8 +2414,8 @@ void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *d } -void fill_dci0(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc, - nfapi_hi_dci0_dci_pdu *pdu) +void fill_dci0(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc, + DCI_ALLOC_t *dci_alloc,nfapi_hi_dci0_dci_pdu *pdu) { LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms; @@ -2400,8 +2432,8 @@ void fill_dci0(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc, uint32_t ndi = pdu->dci_pdu_rel8.new_data_indication_1; #ifdef T_TRACER - T(T_ENB_PHY_ULSCH_UE_DCI, T_INT(eNB->Mod_id), T_INT(proc->frame_tx), T_INT(proc->subframe_tx), - T_INT(pdu->dci_pdu_rel8.rnti), T_INT(((proc->frame_tx*10+proc->subframe_tx+4) % 8) /* TODO: correct harq pid */), + T(T_ENB_PHY_ULSCH_UE_DCI, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), + T_INT(pdu->dci_pdu_rel8.rnti), T_INT(((frame*10+subframe+4) % 8) /* TODO: correct harq pid */), T_INT(mcs), T_INT(-1 /* TODO: remove round? */), T_INT(pdu->dci_pdu_rel8.resource_block_start), T_INT(pdu->dci_pdu_rel8.number_of_resource_block), @@ -2412,9 +2444,12 @@ void fill_dci0(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc, void *dci_pdu = (void*)dci_alloc->dci_pdu; - LOG_D(PHY,"Filling DCI0 with cqi %d, mcs %d, hopping %d, rballoc %x (%d,%d) ndi %d TPC %d cshift %d\n",cqi_req, - mcs,hopping,rballoc,pdu->dci_pdu_rel8.resource_block_start,pdu->dci_pdu_rel8.number_of_resource_block, - ndi,TPC,cshift); + if (cqi_req) + LOG_W(PHY,"SFN/SF:%04d%d DCI0[rnti %x cqi %d mcs %d hopping %d rballoc %x (%d,%d) ndi %d TPC %d cshift %d]\n", + frame,subframe, + pdu->dci_pdu_rel8.rnti,cqi_req, mcs,hopping,rballoc, + pdu->dci_pdu_rel8.resource_block_start, + pdu->dci_pdu_rel8.number_of_resource_block, ndi,TPC,cshift); dci_alloc->format = format0; dci_alloc->firstCCE = pdu->dci_pdu_rel8.cce_index; @@ -2574,10 +2609,10 @@ void fill_ulsch(PHY_VARS_eNB *eNB,nfapi_ul_config_ulsch_pdu *ulsch_pdu,int frame ulsch->harq_processes[harq_pid]->dci_alloc = 1; ulsch->harq_processes[harq_pid]->rar_alloc = 0; ulsch->harq_processes[harq_pid]->n_DMRS = ulsch_pdu->ulsch_pdu_rel8.cyclic_shift_2_for_drms; - + ulsch->harq_processes[harq_pid]->Nsymb_pusch = 12-(frame_parms->Ncp<<1)-(use_srs==0?0:1); ulsch->harq_processes[harq_pid]->srs_active = use_srs; - + //Mapping of cyclic shift field in DCI format0 to n_DMRS2 (3GPP 36.211, Table 5.5.2.1.1-1) if(ulsch->harq_processes[harq_pid]->n_DMRS == 0) ulsch->harq_processes[harq_pid]->n_DMRS2 = 0; @@ -2595,23 +2630,25 @@ void fill_ulsch(PHY_VARS_eNB *eNB,nfapi_ul_config_ulsch_pdu *ulsch_pdu,int frame ulsch->harq_processes[harq_pid]->n_DMRS2 = 10; else if(ulsch->harq_processes[harq_pid]->n_DMRS == 7) ulsch->harq_processes[harq_pid]->n_DMRS2 = 9; - - LOG_D(PHY,"[eNB %d][PUSCH %d] Programming PUSCH with n_DMRS2 %d (cshift %d) for Frame %d, Subframe %d\n", - eNB->Mod_id,harq_pid,ulsch->harq_processes[harq_pid]->n_DMRS2,ulsch->harq_processes[harq_pid]->n_DMRS, - frame,subframe); - + + LOG_D(PHY,"[eNB %d][PUSCH %d] Frame %d, Subframe %d Programming PUSCH with n_DMRS2 %d (cshift %d) ulsch:ndi:%d ulsch_pdu:ndi:%d new_ulsch:%d status:%d\n", + eNB->Mod_id,harq_pid,frame,subframe, + ulsch->harq_processes[harq_pid]->n_DMRS2, + ulsch->harq_processes[harq_pid]->n_DMRS, + ulsch->harq_processes[harq_pid]->ndi, ulsch_pdu->ulsch_pdu_rel8.new_data_indication, new_ulsch, ulsch->harq_processes[harq_pid]->status); + ulsch->harq_processes[harq_pid]->rvidx = ulsch_pdu->ulsch_pdu_rel8.redundancy_version; ulsch->harq_processes[harq_pid]->Qm = ulsch_pdu->ulsch_pdu_rel8.modulation_type; - // Set O_ACK to 0 by default, will be set of DLSCH is scheduled and needs to be + // Set O_ACK to 0 by default, will be set of DLSCH is scheduled and needs to be ulsch->harq_processes[harq_pid]->O_ACK = 0; if ((ulsch->harq_processes[harq_pid]->status == SCH_IDLE) || (ulsch->harq_processes[harq_pid]->ndi != ulsch_pdu->ulsch_pdu_rel8.new_data_indication) || (new_ulsch == TRUE)){ ulsch->harq_processes[harq_pid]->status = ACTIVE; - + ulsch->harq_processes[harq_pid]->TBS = ulsch_pdu->ulsch_pdu_rel8.size<<3; - + ulsch->harq_processes[harq_pid]->Msc_initial = 12*ulsch_pdu->ulsch_pdu_rel8.number_of_resource_blocks; ulsch->harq_processes[harq_pid]->Nsymb_initial = ulsch->harq_processes[harq_pid]->Nsymb_pusch; ulsch->harq_processes[harq_pid]->round = 0; @@ -2621,23 +2658,25 @@ void fill_ulsch(PHY_VARS_eNB *eNB,nfapi_ul_config_ulsch_pdu *ulsch_pdu,int frame // will be set if MAC has activated ULSCH_CQI_RI_PDU or ULSCH_CQI_HARQ_RI_PDU ulsch->harq_processes[harq_pid]->Or1 = 0; ulsch->harq_processes[harq_pid]->Or2 = 0; - } + } else ulsch->harq_processes[harq_pid]->round++; ulsch->rnti = ulsch_pdu->ulsch_pdu_rel8.rnti; - LOG_D(PHY,"Filling ULSCH %x (UE_id %d) (new_ulsch %d) for Frame %d, Subframe %d : harq_pid %d, first_rb %d, nb_rb %d, rvidx %d, Qm %d, TBS %d, round %d \n", + LOG_D(PHY,"Filling ULSCH %x (UE_id %d) (new_ulsch %d) for Frame %d, Subframe %d : harq_pid %d, status %d, handled %d, first_rb %d, nb_rb %d, rvidx %d, Qm %d, TBS %d, round %d \n", ulsch->rnti, UE_id, new_ulsch, frame, subframe, harq_pid, + ulsch->harq_processes[harq_pid]->status, + ulsch->harq_processes[harq_pid]->handled, ulsch->harq_processes[harq_pid]->first_rb, ulsch->harq_processes[harq_pid]->nb_rb, ulsch->harq_processes[harq_pid]->rvidx, ulsch->harq_processes[harq_pid]->Qm, ulsch->harq_processes[harq_pid]->TBS, - ulsch->harq_processes[harq_pid]->round); + ulsch->harq_processes[harq_pid]->round); } int dump_dci(LTE_DL_FRAME_PARMS *frame_parms, DCI_ALLOC_t *dci) @@ -2725,7 +2764,7 @@ int dump_dci(LTE_DL_FRAME_PARMS *frame_parms, DCI_ALLOC_t *dci) break; case 25: - LOG_D(PHY,"DCI format0 (FDD, 5MHz), rnti %x (%x): hopping %d, rb_alloc %x, mcs %d, ndi %d, TPC %d, cshift %d, cqi_req %d\n", + LOG_I(PHY,"DCI format0 (FDD, 5MHz), rnti %x (%x): hopping %d, rb_alloc %x, mcs %d, ndi %d, TPC %d, cshift %d, cqi_req %d\n", dci->rnti, ((uint32_t*)&dci->dci_pdu[0])[0], ((DCI0_5MHz_FDD_t *)&dci->dci_pdu[0])->hopping, @@ -6401,7 +6440,7 @@ uint8_t subframe2harq_pid(LTE_DL_FRAME_PARMS *frame_parms,uint32_t frame,uint8_t uint8_t ret = 255; if (frame_parms->frame_type == FDD) { - ret = (((frame<<1)+subframe)&7); + ret = (((frame*10)+subframe)&7); } else { switch (frame_parms->tdd_config) { @@ -6535,7 +6574,7 @@ uint32_t pdcch_alloc2ul_frame(LTE_DL_FRAME_PARMS *frame_parms,uint32_t frame, ui else ul_frame = (frame+(n>=6 ? 1 : 0)); - LOG_D(PHY, "frame %d subframe %d: PUSCH frame = %d\n", frame, n, ul_frame); + //LOG_D(PHY, "frame %d subframe %d: PUSCH frame = %d\n", frame, n, ul_frame); return ul_frame % 1024; } diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 90450b7c1c..49b41615f4 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -38,7 +38,7 @@ #include "defs.h" #include "UTIL/LOG/vcd_signal_dumper.h" -//#define DEBUG_DLSCH_MODULATION +//#define DEBUG_DLSCH_MODULATION 1 //#define is_not_pilot(pilots,re,nushift,use2ndpilots) ((pilots==0) || ((re!=nushift) && (re!=nushift+6)&&((re!=nushift+3)||(use2ndpilots==1))&&((re!=nushift+9)||(use2ndpilots==1)))?1:0) @@ -78,7 +78,7 @@ uint8_t is_not_UEspecRS(int8_t lprime, uint8_t re, uint8_t nushift, uint8_t Ncp, if ((re!=nushift+offset) && (re!=((nushift+4+offset)%12)) && (re!=((nushift+8+offset)%12))) return(1); /*else{ - printf("(is_no_UEspec_RS):lprime=%d, re=%d, nushift=%d, offset=%d\n",lprime, re,nushift,offset); + LOG_I(PHY,"(is_no_UEspec_RS):lprime=%d, re=%d, nushift=%d, offset=%d\n",lprime, re,nushift,offset); }*/ } else { if ((re!=nushift+offset) && (re!=((nushift+3+offset)%12)) && (re!=((nushift+6+offset)%12)) && (re!=((nushift+9+offset)%12))) @@ -270,7 +270,7 @@ int allocate_REs_in_RB_pilots_16QAM_siso(PHY_VARS_eNB* phy_vars_eNB, if (skip_dc == 0) { - // printf("pilots: P1_SHIFT[0] %d\n",P1_SHIFT[0]); + // LOG_I(PHY,"pilots: P1_SHIFT[0] %d\n",P1_SHIFT[0]); for (x0p=&x0[*jj],tti_offset=symbol_offset+re_offset+P1_SHIFT[0],re=P1_SHIFT[0]; re<12; x0p+=4) { @@ -281,7 +281,7 @@ int allocate_REs_in_RB_pilots_16QAM_siso(PHY_VARS_eNB* phy_vars_eNB, qam16_table_offset_im+=x0p[3]; ((int16_t *)&txdataF[0][tti_offset])[0]=qam_table_s0[qam16_table_offset_re]; ((int16_t *)&txdataF[0][tti_offset])[1]=qam_table_s0[qam16_table_offset_im]; - // printf("pilots: re %d, tti_offset %d, P1_SHIFT %d\n",re,tti_offset,P1_SHIFT[re+1]); + // LOG_I(PHY,"pilots: re %d, tti_offset %d, P1_SHIFT %d\n",re,tti_offset,P1_SHIFT[re+1]); tti_offset+=P1_SHIFT[re+1]; re+=P1_SHIFT[re+1]; } @@ -497,7 +497,7 @@ int allocate_REs_in_RB_pilots_64QAM_siso(PHY_VARS_eNB* phy_vars_eNB, if (skip_dc == 0) { - // printf("pilots: P1_SHIFT[0] %d\n",P1_SHIFT[0]); + // LOG_I(PHY,"pilots: P1_SHIFT[0] %d\n",P1_SHIFT[0]); for (x0p=&x0[*jj],tti_offset=symbol_offset+re_offset+P1_SHIFT[0],re=P1_SHIFT[0]; re<12; x0p+=6) { @@ -510,7 +510,7 @@ int allocate_REs_in_RB_pilots_64QAM_siso(PHY_VARS_eNB* phy_vars_eNB, qam64_table_offset_im+=x0p[5]; ((int16_t *)&txdataF[0][tti_offset])[0]=qam_table_s0[qam64_table_offset_re]; ((int16_t *)&txdataF[0][tti_offset])[1]=qam_table_s0[qam64_table_offset_im]; - // printf("pilots: re %d, tti_offset %d, P1_SHIFT %d\n",re,tti_offset,P1_SHIFT[re+1]); + // LOG_I(PHY,"pilots: re %d, tti_offset %d, P1_SHIFT %d\n",re,tti_offset,P1_SHIFT[re+1]); tti_offset+=P1_SHIFT[re+1]; re+=P1_SHIFT[re+1]; } @@ -667,11 +667,11 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, if (dlsch0_harq != NULL){ #ifdef DEBUG_DLSCH_MODULATION - printf("allocate_re (mod %d): symbol_offset %d re_offset %d (%d,%d), jj %d -> %d,%d\n",mod_order0,symbol_offset,re_offset,skip_dc,skip_half,*jj, x0[*jj], x0[1+*jj]); + LOG_I(PHY,"allocate_re (mod %d): symbol_offset %d re_offset %d (%d,%d), jj %d -> %d,%d\n",mod_order0,symbol_offset,re_offset,skip_dc,skip_half,*jj, x0[*jj], x0[1+*jj]); #endif } else{ #ifdef DEBUG_DLSCH_MODULATION - printf("allocate_re (mod %d): symbol_offset %d re_offset %d (%d,%d), jj %d -> %d,%d\n",mod_order0,symbol_offset,re_offset,skip_dc,skip_half,*jj, x0[*jj], x0[1+*jj]); + LOG_I(PHY,"allocate_re (mod %d): symbol_offset %d re_offset %d (%d,%d), jj %d -> %d,%d\n",mod_order0,symbol_offset,re_offset,skip_dc,skip_half,*jj, x0[*jj], x0[1+*jj]); #endif } @@ -685,7 +685,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, for (re=first_re; reofdm_symbol_size+1; @@ -695,7 +695,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, //check that RE is not from Cell-specific RS if (is_not_pilot(pilots,re,frame_parms->nushift,use2ndpilots)==1) { - //printf("re %d (jj %d)\n",re,*jj); + //LOG_I(PHY,"re %d (jj %d)\n",re,*jj); if (mimo_mode == SISO) { //SISO mapping @@ -705,7 +705,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, case 2: //QPSK - //printf("re %d %d(%d) : %d,%d => ",re,tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + //LOG_I(PHY,"re %d %d(%d) : %d,%d => ",re,tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); ((int16_t*)&txdataF[0][tti_offset])[0] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i *jj = *jj + 1; @@ -971,12 +971,12 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, break; case 2: //QPSK - //printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + //LOG_I(PHY,"%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); xx0_re = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; *jj = *jj + 1; xx0_im = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; *jj = *jj + 1; - //printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + //LOG_I(PHY,"%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); break; case 4: //16QAM @@ -1042,12 +1042,12 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, break; case 2: //QPSK - //printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + //LOG_I(PHY,"%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); xx1_re = (x1[*jj2]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; *jj2 = *jj2 + 1; xx1_im = (x1[*jj2]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; *jj2 = *jj2 + 1; - //printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + //LOG_I(PHY,"%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); break; case 4: //16QAM @@ -1114,7 +1114,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, ((int16_t *)&txdataF[0][tti_offset])[1]+=((xx0_im+xx1_im)>>1); ((int16_t *)&txdataF[1][tti_offset])[1]+=(s*((xx0_im-xx1_im)>>1)); /* - printf("CDD: xx0 (%d,%d), xx1(%d,%d), s(%d), txF[0] (%d,%d), txF[1] (%d,%d)\n", + LOG_I(PHY,"CDD: xx0 (%d,%d), xx1(%d,%d), s(%d), txF[0] (%d,%d), txF[1] (%d,%d)\n", xx0_re,xx0_im,xx1_re,xx1_im, s, ((int16_t *)&txdataF[0][tti_offset])[0],((int16_t *)&txdataF[0][tti_offset])[1], ((int16_t *)&txdataF[1][tti_offset])[0],((int16_t *)&txdataF[1][tti_offset])[1]); */ @@ -1244,7 +1244,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, precoder_index1 = 3; //[1 -j] } else { - printf("problem with precoder in TM4\n"); + LOG_I(PHY,"problem with precoder in TM4\n"); return(-1); } @@ -1263,7 +1263,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, ((int16_t*)&txdataF[0][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*ONE_OVER_SQRT2_Q15)>>15); ((int16_t*)&txdataF[0][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*ONE_OVER_SQRT2_Q15)>>15); - //printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + //LOG_I(PHY,"%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); if (frame_parms->nb_antenna_ports_eNB == 2) { layer1prec2A(&tmp_sample1,&tmp_sample2,precoder_index0); @@ -1466,7 +1466,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, ((int16_t*)&txdataF[5][tti_offset])[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; *jj = *jj + 1; - //printf("%d(%d) : %d,%d => + //LOG_I(PHY,"%d(%d) : %d,%d => //",tti_offset,*jj,((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); break; @@ -1545,7 +1545,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, } } else { //precoding UE spec RS - //printf("precoding UE spec RS\n"); + //LOG_I(PHY,"precoding UE spec RS\n"); ind = 3*lprime*dlsch0_harq->nb_rb+mprime2; ind_dword = ind>>4; @@ -1563,7 +1563,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, switch (mod_order0) { case 2: //QPSK - // printf("%d : %d,%d => ",tti_offset,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + // LOG_I(PHY,"%d : %d,%d => ",tti_offset,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); for (int layer=first_layer0; layer<=(first_layer0+Nlayers0); layer++) { ((int16_t*)&txdataF[layer][tti_offset])[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i *jj = *jj + 1; @@ -1651,7 +1651,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, } } } else if (mimo_mode>=TM9_10) { - printf("allocate_REs_in_RB() [dlsch.c] : ERROR, unknown mimo_mode %d\n",mimo_mode); + LOG_I(PHY,"allocate_REs_in_RB() [dlsch.c] : ERROR, unknown mimo_mode %d\n",mimo_mode); return(-1); } } @@ -1686,7 +1686,7 @@ int allocate_REs_in_RB_MCH(int32_t **txdataF, uint8_t first_re,last_re; int inc; #ifdef DEBUG_DLSCH_MODULATION - printf("allocate_re_MCH (mod %d): symbol_offset %d re_offset %d (%d), jj %d -> %d,%d, gain_lin_QPSK %d,txdataF %p\n",mod_order,symbol_offset,re_offset,skip_dc,*jj, x0[*jj], x0[1+*jj],gain_lin_QPSK,&txdataF[0][symbol_offset]); + LOG_I(PHY,"allocate_re_MCH (mod %d): symbol_offset %d re_offset %d (%d), jj %d -> %d,%d, gain_lin_QPSK %d,txdataF %p\n",mod_order,symbol_offset,re_offset,skip_dc,*jj, x0[*jj], x0[1+*jj],gain_lin_QPSK,&txdataF[0][symbol_offset]); #endif last_re=12; @@ -1707,7 +1707,7 @@ int allocate_REs_in_RB_MCH(int32_t **txdataF, tti_offset = symbol_offset + re_off + re; - //printf("re %d (jj %d)\n",re,*jj); + //LOG_I(PHY,"re %d (jj %d)\n",re,*jj); *re_allocated = *re_allocated + 1; @@ -1715,7 +1715,7 @@ int allocate_REs_in_RB_MCH(int32_t **txdataF, case 2: //QPSK - // printf("%d : %d,%d => ",tti_offset,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + // LOG_I(PHY,"%d : %d,%d => ",tti_offset,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); ((int16_t*)&txdataF[4][tti_offset])[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i *jj = *jj + 1; @@ -1724,7 +1724,7 @@ int allocate_REs_in_RB_MCH(int32_t **txdataF, *jj = *jj + 1; - //printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + //LOG_I(PHY,"%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); break; @@ -1931,7 +1931,7 @@ inline int check_skip(int rb,int subframe_offset,LTE_DL_FRAME_PARMS *frame_parms inline int check_skiphalf(int rb,int subframe_offset,LTE_DL_FRAME_PARMS *frame_parms,int l,int nsymb) __attribute__((always_inline)); inline int check_skiphalf(int rb,int subframe_offset,LTE_DL_FRAME_PARMS *frame_parms,int l,int nsymb) { - // printf("check_skiphalf : rb %d, subframe_offset %d,l %d, nsymb %d\n",rb,subframe_offset,l,nsymb); + // LOG_I(PHY,"check_skiphalf : rb %d, subframe_offset %d,l %d, nsymb %d\n",rb,subframe_offset,l,nsymb); if ((frame_parms->N_RB_DL&1) == 1) { // ODD N_RB_DL @@ -2154,19 +2154,19 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, re_allocated=0; - // printf("num_pdcch_symbols %d, nsymb %d\n",num_pdcch_symbols,nsymb); + // LOG_I(PHY,"num_pdcch_symbols %d, nsymb %d\n",num_pdcch_symbols,nsymb); for (l=num_pdcch_symbols; lmimo_mode, pmi2hex_2Ar2(dlsch0_harq->pmi_alloc), mod_order0, mod_order1, - rb_alloc[0], - len); + rb_alloc[0] + ); #endif } @@ -2216,6 +2216,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, for (eNB_id=0;eNB_idnum_eNB;eNB_id++){ if (phy_vars_eNB == ru->eNB_list[eNB_id]) { for (aa=0;aanb_tx;aa++){ + LOG_I(PHY,"ru_id:%d eNB_id:%d aa:%d memcpy(ru->beam_weights, dlsch0->ue_spec_bf_weights[ru_id][0],)\n", ru_id, eNB_id, aa); memcpy(ru->beam_weights[eNB_id][5][aa], dlsch0->ue_spec_bf_weights[ru_id][0], frame_parms->ofdm_symbol_size*sizeof(int32_t)); @@ -2233,7 +2234,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, if (pilots>0) { // compute pilot arrays, could be done statically if performance suffers if (frame_parms->nb_antenna_ports_eNB == 1) { - // printf("l %d, nushift %d, offset %d\n",l,frame_parms->nushift,offset); + // LOG_I(PHY,"l %d, nushift %d, offset %d\n",l,frame_parms->nushift,offset); for (i=0,i2=0;i<12;i++) { if ((i!=(frame_parms->nushift+offset)) && (i!=((frame_parms->nushift+6+offset)%12))) P1_SHIFT[i2++]=1; @@ -2340,7 +2341,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, //for (aa=0;aanb_antennas_tx;aa++) //memset(&txdataF[aa][symbol_offset],0,frame_parms->ofdm_symbol_size<<2); - //printf("symbol_offset %d,subframe offset %d : pilots %d\n",symbol_offset,subframe_offset,pilots); + //LOG_I(PHY,"symbol_offset %d,subframe offset %d : pilots %d\n",symbol_offset,subframe_offset,pilots); for (rb=0; rbN_RB_DL; rb++) { if (rb < 32) @@ -2371,7 +2372,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, if (dlsch1) { if (dlsch1_harq->Nlayers>1) { - printf("Nlayers %d: re_offset %d, symbol %d offset %d\n",dlsch0_harq->Nlayers,re_offset,l,symbol_offset); + LOG_I(PHY,"Nlayers %d: re_offset %d, symbol %d offset %d\n",dlsch0_harq->Nlayers,re_offset,l,symbol_offset); return(-1); } } @@ -2379,7 +2380,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, if (rb_alloc_ind > 0) { - // printf("Allocated rb %d/symbol %d, skip_half %d, subframe_offset %d, symbol_offset %d, re_offset %d, jj %d\n",rb,l,skip_half,subframe_offset,symbol_offset,re_offset,jj); + // LOG_I(PHY,"Allocated rb %d/symbol %d, skip_half %d, subframe_offset %d, symbol_offset %d, re_offset %d, jj %d\n",rb,l,skip_half,subframe_offset,symbol_offset,re_offset,jj); if (dlsch0 != NULL) { get_pmi_temp = get_pmi(frame_parms->N_RB_DL, @@ -2419,7 +2420,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, mprime +=3+frame_parms->Ncp; } else { - // printf("Unallocated rb %d/symbol %d, re_offset %d, jj %d\n",rb,l,re_offset,jj); + // LOG_I(PHY,"Unallocated rb %d/symbol %d, re_offset %d, jj %d\n",rb,l,re_offset,jj); } re_offset+=12; // go to next RB @@ -2436,9 +2437,9 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, #ifdef DEBUG_DLSCH_MODULATION if (dlsch0 != NULL){ - printf("generate_dlsch : jj = %d,re_allocated = %d (G %d)\n",jj,re_allocated,get_G(frame_parms,dlsch0_harq->nb_rb,dlsch0_harq->rb_alloc,mod_order0,Nl0,2,0,subframe_offset)); + LOG_I(PHY,"generate_dlsch : jj = %d,re_allocated = %d (G %d)\n",jj,re_allocated,get_G(frame_parms,dlsch0_harq->nb_rb,dlsch0_harq->rb_alloc,mod_order0,Nl0,2,0,subframe_offset,1)); }else{ - printf("generate_dlsch : jj = %d,re_allocated = %d (G %d)\n",jj,re_allocated,get_G(frame_parms,dlsch1_harq->nb_rb,dlsch1_harq->rb_alloc,mod_order1,Nl1,2,0,subframe_offset)); + LOG_I(PHY,"generate_dlsch : jj = %d,re_allocated = %d (G %d)\n",jj,re_allocated,get_G(frame_parms,dlsch1_harq->nb_rb,dlsch1_harq->rb_alloc,mod_order1,Nl1,2,0,subframe_offset,1)); } #endif @@ -2493,7 +2494,7 @@ int dlsch_modulation_SIC(int32_t **sic_buffer, jj = jj + 1; - //printf("recon %d,%d\n",((int16_t*)&sic_buffer[0][i])[0],((int16_t*)&sic_buffer[0][i])[1]); + //LOG_I(PHY,"recon %d,%d\n",((int16_t*)&sic_buffer[0][i])[0],((int16_t*)&sic_buffer[0][i])[1]); i++; break; @@ -2580,7 +2581,7 @@ int dlsch_modulation_SIC(int32_t **sic_buffer, #ifdef DEBUG_DLSCH_MODULATION - printf("generate_dlsch : jj = %d,re_allocated = %d (G %d)\n",jj,re_allocated,get_G(frame_parms,dlsch0_harq->nb_rb,dlsch0_harq->rb_alloc,mod_order0,Nl0,2,0,subframe_offset,1/*transmission mode*/)); + LOG_I(PHY,"generate_dlsch : jj = %d,re_allocated = %d (G %d)\n",jj,re_allocated,get_G(frame_parms,dlsch0_harq->nb_rb,dlsch0_harq->rb_alloc,mod_order0,Nl0,2,0,subframe_offset,1/*transmission mode*/)); #endif VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_MODULATION, VCD_FUNCTION_OUT); @@ -2618,11 +2619,11 @@ int mch_modulation(int32_t **txdataF, jj=0; re_allocated=0; - // printf("num_pdcch_symbols %d, nsymb %d\n",num_pdcch_symbols,nsymb); + // LOG_I(PHY,"num_pdcch_symbols %d, nsymb %d\n",num_pdcch_symbols,nsymb); for (l=2; lfirst_carrier_offset; @@ -2647,7 +2648,7 @@ int mch_modulation(int32_t **txdataF, else qam_table_s = NULL; - //printf("Allocated rb %d, subframe_offset %d,amp %d\n",rb,subframe_offset,amp); + //LOG_I(PHY,"Allocated rb %d, subframe_offset %d,amp %d\n",rb,subframe_offset,amp); allocate_REs_in_RB_MCH(txdataF, &jj, re_offset, @@ -2674,7 +2675,7 @@ int mch_modulation(int32_t **txdataF, } #ifdef DEBUG_DLSCH_MODULATION - printf("generate_dlsch(MCH) : jj = %d,re_allocated = %d (G %d)\n",jj,re_allocated,get_G(frame_parms,dlsch->harq_processes[0]->nb_rb,dlsch->harq_processes[0]->rb_alloc,mod_order,1,2,0,subframe_offset,1/*transmission mode*/)); + LOG_I(PHY,"generate_dlsch(MCH) : jj = %d,re_allocated = %d (G %d)\n",jj,re_allocated,get_G(frame_parms,dlsch->harq_processes[0]->nb_rb,dlsch->harq_processes[0]->rb_alloc,mod_order,1,2,0,subframe_offset,1/*transmission mode*/)); #endif return (re_allocated); diff --git a/openair1/PHY/LTE_TRANSPORT/pbch.c b/openair1/PHY/LTE_TRANSPORT/pbch.c index e86f225157..226d5ef0ca 100644 --- a/openair1/PHY/LTE_TRANSPORT/pbch.c +++ b/openair1/PHY/LTE_TRANSPORT/pbch.c @@ -174,6 +174,8 @@ int generate_pbch(LTE_eNB_PBCH *eNB_pbch, pbch_E = (frame_parms->Ncp==NORMAL) ? 1920 : 1728; //RE/RB * #RB * bits/RB (QPSK) // pbch_E_bytes = pbch_coded_bits>>3; + LOG_D(PHY,"%s(eNB_pbch:%p txdataF:%p amp:%d frame_parms:%p pbch_pdu:%p frame_mod4:%d)\n", __FUNCTION__, eNB_pbch, txdataF, amp, frame_parms, pbch_pdu, frame_mod4==0); + if (frame_mod4==0) { bzero(pbch_a,PBCH_A>>3); bzero(eNB_pbch->pbch_e,pbch_E); diff --git a/openair1/PHY/LTE_TRANSPORT/phich.c b/openair1/PHY/LTE_TRANSPORT/phich.c index dd96910549..6e955322b8 100644 --- a/openair1/PHY/LTE_TRANSPORT/phich.c +++ b/openair1/PHY/LTE_TRANSPORT/phich.c @@ -162,7 +162,7 @@ int phich_frame2_pusch_frame(LTE_DL_FRAME_PARMS *frame_parms, int frame, int sub pusch_frame = (frame); } - LOG_D(PHY, "frame %d subframe %d: PUSCH frame = %d\n", frame, subframe, pusch_frame); + //LOG_D(PHY, "frame %d subframe %d: PUSCH frame = %d\n", frame, subframe, pusch_frame); return pusch_frame % 1024; } diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c index 606900677e..5f1b3ce448 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.c +++ b/openair1/PHY/LTE_TRANSPORT/prach.c @@ -39,6 +39,7 @@ #include "UTIL/LOG/vcd_signal_dumper.h" //#define PRACH_DEBUG 1 +//#define PRACH_WRITE_OUTPUT_DEBUG 1 uint16_t NCS_unrestricted[16] = {0,13,15,18,22,26,32,38,46,59,76,93,119,167,279,419}; uint16_t NCS_restricted[15] = {15,18,22,26,32,38,46,55,68,82,100,128,158,202,237}; // high-speed case @@ -562,7 +563,7 @@ int is_prach_subframe0(LTE_DL_FRAME_PARMS *frame_parms,uint8_t prach_ConfigIndex t1_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[0].t1_ra; t2_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[0].t2_ra; #ifdef PRACH_DEBUG - LOG_D(PHY,"[PRACH] Checking for PRACH format (ConfigIndex %d) in TDD subframe %d (%d,%d,%d)\n", + LOG_I(PHY,"[PRACH] Checking for PRACH format (ConfigIndex %d) in TDD subframe %d (%d,%d,%d)\n", prach_ConfigIndex, subframe, t0_ra,t1_ra,t2_ra); @@ -655,7 +656,7 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1 #else //normal case (simulation) prach_start = subframe*ue->frame_parms.samples_per_tti-ue->N_TA_offset; - LOG_D(PHY,"[UE %d] prach_start %d, rx_offset %d, hw_timing_advance %d, N_TA_offset %d\n", ue->Mod_id, + LOG_I(PHY,"[UE %d] prach_start %d, rx_offset %d, hw_timing_advance %d, N_TA_offset %d\n", ue->Mod_id, prach_start, ue->rx_offset, ue->hw_timing_advance, @@ -723,7 +724,7 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1 } else { // This is the high-speed case #ifdef PRACH_DEBUG - LOG_D(PHY,"[UE %d] High-speed mode, NCS_config %d\n",ue->Mod_id,Ncs_config); + LOG_I(PHY,"[UE %d] High-speed mode, NCS_config %d\n",ue->Mod_id,Ncs_config); #endif not_found = 1; @@ -784,7 +785,7 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1 #ifdef PRACH_DEBUG if (NCS>0) - LOG_D(PHY,"Generate PRACH for RootSeqIndex %d, Preamble Index %d, NCS %d (NCS_config %d, N_ZC/NCS %d) n_ra_prb %d: Preamble_offset %d, Preamble_shift %d\n", + LOG_I(PHY,"Generate PRACH for RootSeqIndex %d, Preamble Index %d, NCS %d (NCS_config %d, N_ZC/NCS %d) n_ra_prb %d: Preamble_offset %d, Preamble_shift %d\n", rootSequenceIndex,preamble_index,NCS,Ncs_config,N_ZC/NCS,n_ra_prb, preamble_offset,preamble_shift); @@ -1039,14 +1040,14 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1 break; } - //LOG_D(PHY,"prach_len=%d\n",prach_len); + //LOG_I(PHY,"prach_len=%d\n",prach_len); AssertFatal(prach_fmt<4, "prach_fmt4 not fully implemented" ); #if defined(EXMIMO) || defined(OAI_USRP) int j; int overflow = prach_start + prach_len - LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*ue->frame_parms.samples_per_tti; - LOG_D( PHY, "prach_start=%d, overflow=%d\n", prach_start, overflow ); + LOG_I( PHY, "prach_start=%d, overflow=%d\n", prach_start, overflow ); for (i=prach_start,j=0; iframe_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME,prach_start+prach_len); i++,j++) { ((int16_t*)ue->common_vars.txdata[0])[2*i] = prach[2*j]<<4; @@ -1079,7 +1080,7 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1 -#if 0 +#if defined(PRACH_WRITE_OUTPUT_DEBUG) write_output("prach_txF0.m","prachtxF0",prachF,prach_len-Ncp,1,1); write_output("prach_tx0.m","prachtx0",prach+(Ncp<<1),prach_len-Ncp,1,1); write_output("txsig.m","txs",(int16_t*)(&ue->common_vars.txdata[0][0]),2*ue->frame_parms.samples_per_tti,1,1); @@ -1114,7 +1115,9 @@ void rx_prach0(PHY_VARS_eNB *eNB, uint8_t restricted_set; uint8_t n_ra_prb; +#ifdef PRACH_DEBUG int frame; +#endif int subframe; int16_t *prachF=NULL; int16_t **rxsigF=NULL; @@ -1131,7 +1134,7 @@ void rx_prach0(PHY_VARS_eNB *eNB, uint16_t numshift=0; uint16_t *prach_root_sequence_map; uint8_t not_found; - int k; + int k=0; uint16_t u; int16_t *Xu; uint16_t offset; @@ -1152,8 +1155,6 @@ void rx_prach0(PHY_VARS_eNB *eNB, int en0=0; #endif - (void)frame; /* avoid gcc warnings */ - if (ru) { fp = &ru->frame_parms; nb_rx = ru->nb_rx; @@ -1204,7 +1205,9 @@ void rx_prach0(PHY_VARS_eNB *eNB, #ifdef Rel14 if (br_flag == 1) { prach_ifftp = eNB->prach_vars_br.prach_ifft[ce_level]; +#ifdef PRACH_DEBUG frame = eNB->proc.frame_prach_br; +#endif subframe = eNB->proc.subframe_prach_br; prachF = eNB->prach_vars_br.prachF; rxsigF = eNB->prach_vars_br.rxsigF[ce_level]; @@ -1221,19 +1224,23 @@ void rx_prach0(PHY_VARS_eNB *eNB, #endif { prach_ifftp = eNB->prach_vars.prach_ifft[0]; +#ifdef PRACH_DEBUG frame = eNB->proc.frame_prach; +#endif subframe = eNB->proc.subframe_prach; prachF = eNB->prach_vars.prachF; rxsigF = eNB->prach_vars.rxsigF[0]; #ifdef PRACH_DEBUG - if ((frame&1023) < 20) LOG_I(PHY,"PRACH (eNB) : running rx_prach for subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d , rootSequenceIndex %d\n", - subframe,fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset,prach_ConfigIndex,rootSequenceIndex); + //if ((frame&1023) < 20) LOG_I(PHY,"PRACH (eNB) : running rx_prach for subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d , rootSequenceIndex %d\n", subframe,fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset,prach_ConfigIndex,rootSequenceIndex); #endif } } else { #ifdef Rel14 if (br_flag == 1) { +#ifdef PRACH_DEBUG + frame = ru->proc.frame_prach_br; +#endif subframe = ru->proc.subframe_prach_br; rxsigF = ru->prach_rxsigF_br[ce_level]; #ifdef PRACH_DEBUG @@ -1244,6 +1251,9 @@ void rx_prach0(PHY_VARS_eNB *eNB, else #endif { +#ifdef PRACH_DEBUG + frame = ru->proc.frame_prach; +#endif subframe = ru->proc.subframe_prach; rxsigF = ru->prach_rxsigF; #ifdef PRACH_DEBUG @@ -1258,9 +1268,32 @@ void rx_prach0(PHY_VARS_eNB *eNB, for (aa=0; aaif_south == LOCAL_RF) { // set the time-domain signal if we have to use it in this node + // DJP - indexing below in subframe zero takes us off the beginning of the array??? prach[aa] = (int16_t*)&ru->common.rxdata[aa][(subframe*fp->samples_per_tti)-ru->N_TA_offset]; #ifdef PRACH_DEBUG - if ((frame&1023) < 20) LOG_I(PHY,"RU %d, br_flag %d ce_level %d frame %d subframe %d, : prach %p (energy %d)\n",ru->idx,br_flag,ce_level,frame,subframe,prach[aa],dB_fixed(en0=signal_energy(prach[aa],fp->samples_per_tti))); + int32_t en0=signal_energy((int32_t*)prach[aa],fp->samples_per_tti); + int8_t dbEn0 = dB_fixed(en0); + int8_t rach_dBm = dbEn0 - eNB->rx_total_gain_dB; + +#ifdef PRACH_WRITE_OUTPUT_DEBUG + if (dbEn0>32 && prach[0]!= NULL) + { + static int counter=0; + + char buffer[80]; + //counter++; + sprintf(buffer, "%s%d", "/tmp/prach_rx",counter); + write_output(buffer,"prach_rx",prach[0],fp->samples_per_tti,1,13); + } +#endif + + if (dbEn0>32) + { +#ifdef PRACH_WRITE_OUTPUT_DEBUG + if (prach[0]!= NULL) write_output("prach_rx","prach_rx",prach[0],fp->samples_per_tti,1,1); +#endif + LOG_I(PHY,"RU %d, br_flag %d ce_level %d frame %d subframe %d per_tti:%d prach:%p (energy %d) TA:%d rach_dBm:%d rxdata:%p index:%d\n",ru->idx,br_flag,ce_level,frame,subframe,fp->samples_per_tti,prach[aa],dbEn0,ru->N_TA_offset,rach_dBm,ru->common.rxdata[aa], (subframe*fp->samples_per_tti)-ru->N_TA_offset); + } #endif } } @@ -1343,7 +1376,9 @@ void rx_prach0(PHY_VARS_eNB *eNB, if (((eNB!=NULL) && (ru->function != NGFI_RAU_IF4p5))|| ((eNB==NULL) && (ru->function == NGFI_RRU_IF4p5))) { // compute the DFTs of the PRACH temporal resources // Do forward transform - LOG_D(PHY,"rx_prach: Doing FFT for N_RB_UL %d\n",fp->N_RB_UL); +#ifdef PRACH_DEBUG + LOG_D(PHY,"rx_prach: Doing FFT for N_RB_UL %d nb_rx:%d Ncp:%d\n",fp->N_RB_UL, nb_rx, Ncp); +#endif for (aa=0; aaofdm_symbol_size*24; - LOG_D(PHY,"Shifting prach_rxF from %d to 0\n",k); + //LOG_D(PHY,"Shifting prach_rxF from %d to 0\n",k); if ((k+(839*2)) > dftsize_x2) { // PRACH signal is split around DC memmove((void*)&rxsigF[aa][dftsize_x2-k],(void*)&rxsigF[aa][0],(k+(839*2)-dftsize_x2)*2); @@ -1478,7 +1513,6 @@ void rx_prach0(PHY_VARS_eNB *eNB, int en = dB_fixed(signal_energy((int32_t*)&rxsigF[0][0],840)); if ((en > 60)&&(br_flag==1)) LOG_I(PHY,"PRACH (br_flag %d,ce_level %d, n_ra_prb %d, k %d): Frame %d, Subframe %d => %d dB\n",br_flag,ce_level,n_ra_prb,k,eNB->proc.frame_rx,eNB->proc.subframe_rx,en); #endif - } // in case of RAU and prach received rx_thread wakes up prach @@ -1623,7 +1657,7 @@ void rx_prach0(PHY_VARS_eNB *eNB, } memset(prachF, 0, sizeof(int16_t)*2*1024 ); -#ifdef PRACH_DEBUG +#if defined(PRACH_WRITE_OUTPUT_DEBUG) if (prach[0]!= NULL) write_output("prach_rx0.m","prach_rx0",prach[0],6144+792,1,1); #endif // write_output("prach_rx1.m","prach_rx1",prach[1],6144+792,1,1); @@ -1657,7 +1691,7 @@ void rx_prach0(PHY_VARS_eNB *eNB, prach_ifft[i] += (prach_ifft_tmp[i<<1]*prach_ifft_tmp[(i<<1)] + prach_ifft_tmp[1+(i<<1)]*prach_ifft_tmp[1+(i<<1)])>>10; } -#ifdef PRACH_DEBUG +#if defined(PRACH_WRITE_OUTPUT_DEBUG) if (aa==0) write_output("prach_rxF_comp0.m","prach_rxF_comp0",prachF,1024,1,1); #endif // if (aa=1) write_output("prach_rxF_comp1.m","prach_rxF_comp1",prachF,1024,1,1); @@ -1706,19 +1740,22 @@ void rx_prach0(PHY_VARS_eNB *eNB, k*=2; if (br_flag == 0) { - /* +#if defined(PRACH_WRITE_OUTPUT_DEBUG) write_output("rxsigF.m","prach_rxF",&rxsigF[0][0],12288,1,1); write_output("prach_rxF_comp0.m","prach_rxF_comp0",prachF,1024,1,1); write_output("Xu.m","xu",Xu,N_ZC,1,1); - write_output("prach_ifft0.m","prach_t0",prach_ifft,1024,1,1);*/ + write_output("prach_ifft0.m","prach_t0",prach_ifft,1024,1,1); +#endif } else { +#if defined(PRACH_WRITE_OUTPUT_DEBUG) printf("Dumping prach (br_flag %d), k = %d (n_ra_prb %d)\n",br_flag,k,n_ra_prb); write_output("rxsigF_br.m","prach_rxF_br",&rxsigF[0][0],12288,1,1); write_output("prach_rxF_comp0_br.m","prach_rxF_comp0_br",prachF,1024,1,1); write_output("Xu_br.m","xu_br",Xu,N_ZC,1,1); write_output("prach_ifft0_br.m","prach_t0_br",prach_ifft,1024,1,1); exit(-1); +#endif } } diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 8a0e160f23..284523e381 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -1716,13 +1716,15 @@ int generate_ue_dlsch_params_from_dci(int frame, uint16_t tc_rnti); void fill_dci_and_dlsch(PHY_VARS_eNB *eNB, + int frame, + int subframe, eNB_rxtx_proc_t *proc, DCI_ALLOC_t *dci_alloc, nfapi_dl_config_dci_dl_pdu *pdu); void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *dci_alloc,nfapi_dl_config_mpdcch_pdu *pdu); -void fill_dci0(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc, +void fill_dci0(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc, nfapi_hi_dci0_dci_pdu *pdu); void fill_ulsch(PHY_VARS_eNB *eNB,nfapi_ul_config_ulsch_pdu *ulsch_pdu,int frame,int subframe); diff --git a/openair1/PHY/LTE_TRANSPORT/rar_tools.c b/openair1/PHY/LTE_TRANSPORT/rar_tools.c index f10b79ed65..9934b71d78 100644 --- a/openair1/PHY/LTE_TRANSPORT/rar_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/rar_tools.c @@ -173,7 +173,9 @@ int generate_eNB_ulsch_params_from_rar(PHY_VARS_eNB *eNB, &ulsch_harq->frame, &ulsch_harq->subframe); - LOG_I(PHY,"Programming msg3 reception in (%d,%d)\n",ulsch_harq->frame,ulsch_harq->subframe); + LOG_I(PHY,"Programming msg3 reception in (%d,%d) mcs:%d TBS:%d Qm:%d Mcs_intial:%d Nsymb_intial:%d round:%d\n", + ulsch_harq->frame,ulsch_harq->subframe, + mcs, ulsch_harq->TBS, ulsch_harq->Qm, ulsch_harq->Msc_initial, ulsch_harq->Nsymb_initial, ulsch_harq->round); use_srs = is_srs_occasion_common(frame_parms,ulsch_harq->frame,ulsch_harq->subframe); ulsch_harq->Nsymb_pusch = 12-(frame_parms->Ncp<<1)-(use_srs==0?0:1); ulsch_harq->srs_active = use_srs; @@ -185,7 +187,7 @@ int generate_eNB_ulsch_params_from_rar(PHY_VARS_eNB *eNB, LOG_D(PHY,"ulsch ra (eNB): harq_pid %d\n",harq_pid); LOG_D(PHY,"ulsch ra (eNB): round %d\n",ulsch_harq->round); LOG_D(PHY,"ulsch ra (eNB): TBS %d\n",ulsch_harq->TBS); - LOG_D(PHY,"ulsch ra (eNB): mcs %d\n",ulsch_harq->mcs); + LOG_D(PHY,"ulsch ra (eNB): mcs %d\n",ulsch_harq->Msc_initial); LOG_D(PHY,"ulsch ra (eNB): Or1 %d\n",ulsch_harq->Or1); LOG_D(PHY,"ulsch ra (eNB): ORI %d\n",ulsch_harq->O_RI); #endif diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index f885bf8eb3..edbca69433 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -874,12 +874,13 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, int16_t cseq[6*14*1200] __attribute__((aligned(32))); int off; + int frame = proc->frame_rx; int subframe = proc->subframe_rx; LTE_UL_eNB_HARQ_t *ulsch_harq; - harq_pid = subframe2harq_pid(frame_parms,proc->frame_rx,subframe); + harq_pid = subframe2harq_pid(frame_parms,frame,subframe); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_DECODING0+harq_pid,1); @@ -904,7 +905,8 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, //#ifdef DEBUG_ULSCH_DECODING - LOG_D(PHY,"Frame %d, Subframe %d: ulsch_decoding (Nid_cell %d, rnti %x, x2 %x): A %d, round %d, RV %d, O_r1 %d, O_RI %d, O_ACK %d, G %d\n", + LOG_D(PHY,"[PUSCH %d] Frame %d, Subframe %d: ulsch_decoding (Nid_cell %d, rnti %x, x2 %x): A %d, round %d, RV %d, O_r1 %d, O_RI %d, O_ACK %d, G %d, Q_m %d Nsymb_pusch %d nb_rb %d\n", + harq_pid, proc->frame_rx,subframe, frame_parms->Nid_cell,ulsch->rnti,x2, A, @@ -913,7 +915,10 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, ulsch_harq->Or1, ulsch_harq->O_RI, ulsch_harq->O_ACK, - G); + G, + ulsch_harq->Qm, + ulsch_harq->Nsymb_pusch, + nb_rb); //#endif @@ -1260,7 +1265,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, } if (ulsch_harq->O_ACK > 2) { - LOG_E(PHY,"ulsch_decoding: FATAL, ACK cannot be more than 2 bits yet\n"); + LOG_E(PHY,"ulsch_decoding: FATAL, ACK cannot be more than 2 bits yet O_ACK:%d SFN/SF:%04d%d UE_id:%d rnti:%x\n",ulsch_harq->O_ACK,proc->frame_rx,proc->subframe_rx,UE_id,ulsch->rnti); return(-1); } @@ -1572,6 +1577,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, #endif } + LOG_I(PHY,"frame %d subframe %d O_ACK:%d o_ACK[]=%d:%d:%d:%d\n",frame,subframe,ulsch_harq->O_ACK,ulsch_harq->o_ACK[0],ulsch_harq->o_ACK[1],ulsch_harq->o_ACK[2],ulsch_harq->o_ACK[3]); // Do ULSCH Decoding for data portion diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c index 795ed5896b..5f05d33f60 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c @@ -1192,6 +1192,13 @@ void rx_ulsch(PHY_VARS_eNB *eNB, pusch_vars->ulsch_power[i] = signal_energy_nodc(pusch_vars->drs_ch_estimates[i], ulsch[UE_id]->harq_processes[harq_pid]->nb_rb*12)/correction_factor; + if(0)LOG_E(PHY,"rx_ulsch() i:%i drs: UE_id:%d harq_pid:%d nb_rb:%d correction_factor:%d\n", + i, + //pusch_vars->drs_ch_estimates[i], + UE_id, + harq_pid, + ulsch[UE_id]->harq_processes[harq_pid]->nb_rb, + correction_factor); /* printf("%4.4d.%d power harq_pid %d rb %2.2d TBS %2.2d (MPR_times_Ks %d correction %d) power %d dBtimes10\n", proc->frame_rx, proc->subframe_rx, harq_pid, ulsch[UE_id]->harq_processes[harq_pid]->nb_rb, ulsch[UE_id]->harq_processes[harq_pid]->TBS,MPR_times_100Ks,correction_factor,dB_fixed_times10(pusch_vars->ulsch_power[i])); */ } diff --git a/openair1/PHY/TOOLS/file_output.c b/openair1/PHY/TOOLS/file_output.c index 1a4adb04cd..c2256707b5 100644 --- a/openair1/PHY/TOOLS/file_output.c +++ b/openair1/PHY/TOOLS/file_output.c @@ -33,7 +33,7 @@ int write_output(const char *fname,const char *vname,void *data,int length,int d int i; - printf("Writing %d elements of type %d to %s\n",length,format,fname); + //printf("Writing %d elements of type %d to %s\n",length,format,fname); if (format == 10 || format ==11 || format == 12 || format == 13 || format == 14) { @@ -68,9 +68,11 @@ int write_output(const char *fname,const char *vname,void *data,int length,int d case 15: for (i=0; isubframe_tx&1; + int idx = subframe&1; LTE_eNB_PDCCH *pdcch_vars = &eNB->pdcch_vars[idx]; nfapi_dl_config_dci_dl_pdu *pdu = &dl_config_pdu->dci_dl_pdu; - LOG_D(PHY,"Frame %d, Subframe %d: DCI processing\n",proc->frame_tx,proc->subframe_tx); + LOG_D(PHY,"Frame %d, Subframe %d: DCI processing - populating pdcch_vars->dci_alloc[%d] proc:subframe_tx:%d idx:%d pdcch_vars->num_dci:%d\n",frame,subframe, pdcch_vars->num_dci, proc->subframe_tx, idx, pdcch_vars->num_dci); // copy dci configuration into eNB structure - fill_dci_and_dlsch(eNB,proc,&pdcch_vars->dci_alloc[pdcch_vars->num_dci],pdu); + fill_dci_and_dlsch(eNB,frame,subframe,proc,&pdcch_vars->dci_alloc[pdcch_vars->num_dci],pdu); + + LOG_D(PHY,"Frame %d, Subframe %d: DCI processing - populated pdcch_vars->dci_alloc[%d] proc:subframe_tx:%d idx:%d pdcch_vars->num_dci:%d\n",proc->frame_tx,proc->subframe_tx, pdcch_vars->num_dci, proc->subframe_tx, idx, pdcch_vars->num_dci); } void handle_nfapi_mpdcch_pdu(PHY_VARS_eNB *eNB, @@ -65,26 +76,30 @@ void handle_nfapi_mpdcch_pdu(PHY_VARS_eNB *eNB, fill_mdci_and_dlsch(eNB,proc,&mpdcch_vars->mdci_alloc[mpdcch_vars->num_dci],pdu); } -void handle_nfapi_hi_dci0_dci_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, +void handle_nfapi_hi_dci0_dci_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc, nfapi_hi_dci0_request_pdu_t *hi_dci0_config_pdu) { - int idx = proc->subframe_tx&1; + int idx = subframe&1; LTE_eNB_PDCCH *pdcch_vars = &eNB->pdcch_vars[idx]; + + //LOG_D(PHY,"%s() SFN/SF:%04d%d Before num_dci:%d\n", __FUNCTION__,frame,subframe,pdcch_vars->num_dci); + // copy dci configuration in to eNB structure - fill_dci0(eNB,proc,&pdcch_vars->dci_alloc[pdcch_vars->num_dci], &hi_dci0_config_pdu->dci_pdu); + fill_dci0(eNB,frame,subframe,proc,&pdcch_vars->dci_alloc[pdcch_vars->num_dci], &hi_dci0_config_pdu->dci_pdu); } -void handle_nfapi_hi_dci0_hi_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, +void handle_nfapi_hi_dci0_hi_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc, nfapi_hi_dci0_request_pdu_t *hi_dci0_config_pdu) { - LTE_eNB_PHICH *phich = &eNB->phich_vars[proc->subframe_tx&1]; + LTE_eNB_PHICH *phich = &eNB->phich_vars[subframe&1]; // copy dci configuration in to eNB structure - LOG_D(PHY,"Received HI PDU which value %d (rbstart %d,cshift %d)\n", + LOG_D(PHY,"Received HI PDU with value %d (rbstart %d,cshift %d)\n", hi_dci0_config_pdu->hi_pdu.hi_pdu_rel8.hi_value, hi_dci0_config_pdu->hi_pdu.hi_pdu_rel8.resource_block_start, hi_dci0_config_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms); + // DJP - TODO FIXME - transmission power ignored phich->config[phich->num_hi].hi = hi_dci0_config_pdu->hi_pdu.hi_pdu_rel8.hi_value; phich->config[phich->num_hi].first_rb = hi_dci0_config_pdu->hi_pdu.hi_pdu_rel8.resource_block_start; phich->config[phich->num_hi].n_DMRS = hi_dci0_config_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms; @@ -100,7 +115,7 @@ void handle_nfapi_bch_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, AssertFatal(rel8->length == 3, "BCH PDU has length %d != 3\n",rel8->length); - LOG_D(PHY,"bch_pdu: %x,%x,%x\n",sdu[0],sdu[1],sdu[2]); + //LOG_D(PHY,"bch_pdu: %x,%x,%x\n",sdu[0],sdu[1],sdu[2]); eNB->pbch_pdu[0] = sdu[2]; eNB->pbch_pdu[1] = sdu[1]; eNB->pbch_pdu[2] = sdu[0]; @@ -119,7 +134,7 @@ extern uint32_t localRIV2alloc_LUT100_2[6000]; extern uint32_t localRIV2alloc_LUT100_3[6000]; #endif -void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, +void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc, nfapi_dl_config_request_pdu_t *dl_config_pdu, uint8_t codeword_index, uint8_t *sdu) @@ -144,11 +159,25 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, dlsch1 = eNB->dlsch[UE_id][1]; #ifdef Rel14 - if ((rel13->pdsch_payload_type < 2) && (rel13->ue_type>0)) dlsch0->harq_ids[proc->subframe_tx] = 0; + if ((rel13->pdsch_payload_type < 2) && (rel13->ue_type>0)) dlsch0->harq_ids[subframe] = 0; #endif - harq_pid = dlsch0->harq_ids[proc->subframe_tx]; - AssertFatal((harq_pid>=0) && (harq_pid<8),"harq_pid %d not in 0...7\n",harq_pid); + harq_pid = dlsch0->harq_ids[subframe]; + AssertFatal((harq_pid>=0) && (harq_pid<8),"harq_pid %d not in 0...7 frame:%d subframe:%d subframe(TX):%d rnti:%x UE_id:%d dlsch0[harq_ids:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d]\n", + harq_pid, + frame,subframe, + proc->subframe_tx,rel8->rnti,UE_id, + dlsch0->harq_ids[0], + dlsch0->harq_ids[1], + dlsch0->harq_ids[2], + dlsch0->harq_ids[3], + dlsch0->harq_ids[4], + dlsch0->harq_ids[5], + dlsch0->harq_ids[6], + dlsch0->harq_ids[7], + dlsch0->harq_ids[8], + dlsch0->harq_ids[9] + ); dlsch0_harq = dlsch0->harq_processes[harq_pid]; dlsch1_harq = dlsch1->harq_processes[harq_pid]; AssertFatal(dlsch0_harq!=NULL,"dlsch_harq is null\n"); @@ -165,20 +194,21 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, computeRhoB_eNB(&eNB->pdsch_config_dedicated[UE_id],&(eNB->frame_parms.pdsch_config_common),eNB->frame_parms.nb_antenna_ports_eNB,dlsch1,dlsch1_harq->dl_power_off); } - dlsch0_harq->pdsch_start = eNB->pdcch_vars[proc->subframe_tx & 1].num_pdcch_symbols; + dlsch0_harq->pdsch_start = eNB->pdcch_vars[subframe & 1].num_pdcch_symbols; if (dlsch0_harq->round==0) { //get pointer to SDU if this a new SDU - AssertFatal(sdu!=NULL,"NFAPI: frame %d, subframe %d: programming dlsch for round 0, rnti %x, UE_id %d, harq_pid %d : sdu is null for pdu_index %d\n", + AssertFatal(sdu!=NULL,"NFAPI: SFN/SF:%04d%d proc:TX:[frame %d subframe %d]: programming dlsch for round 0, rnti %x, UE_id %d, harq_pid %d : sdu is null for pdu_index %d dlsch0_harq[round:%d SFN/SF:%d%d pdu:%p mcs:%d ndi:%d pdschstart:%d]\n", + frame,subframe, proc->frame_tx,proc->subframe_tx,rel8->rnti,UE_id,harq_pid, - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index); - if (rel8->rnti != 0xFFFF) LOG_D(PHY,"NFAPI: frame %d, subframe %d: programming dlsch for round 0, rnti %x, UE_id %d, harq_pid %d\n", - proc->frame_tx,proc->subframe_tx,rel8->rnti,UE_id,harq_pid); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index,dlsch0_harq->round,dlsch0_harq->frame,dlsch0_harq->subframe,dlsch0_harq->pdu,dlsch0_harq->mcs,dlsch0_harq->ndi,dlsch0_harq->pdsch_start); + if (rel8->rnti != 0xFFFF) LOG_D(PHY,"NFAPI: SFN/SF:%04d%d proc:TX:[frame %d, subframe %d]: programming dlsch for round 0, rnti %x, UE_id %d, harq_pid %d\n", + frame,subframe,proc->frame_tx,proc->subframe_tx,rel8->rnti,UE_id,harq_pid); if (codeword_index == 0) dlsch0_harq->pdu = sdu; else dlsch1_harq->pdu = sdu; } else { - if (rel8->rnti != 0xFFFF) LOG_D(PHY,"NFAPI: frame %d, subframe %d: programming dlsch for round %d, rnti %x, UE_id %d, harq_pid %d\n", - proc->frame_tx,proc->subframe_tx,dlsch0_harq->round, + if (rel8->rnti != 0xFFFF) LOG_D(PHY,"NFAPI: SFN/SF:%04d%d proc:TX:[frame %d, subframe %d]: programming dlsch for round %d, rnti %x, UE_id %d, harq_pid %d\n", + frame,subframe,proc->frame_tx,proc->subframe_tx,dlsch0_harq->round, rel8->rnti,UE_id,harq_pid); } @@ -190,8 +220,6 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, dlsch0->Kmimo = 1; dlsch0->Mdlharq = 4; dlsch0->Nsoft = 25344; - dlsch0->i0 = rel13->initial_transmission_sf_io; - dlsch0_harq->pdsch_start = rel10->pdsch_start; if (rel13->pdsch_payload_type == 0) dlsch0->sib1_br_flag=1; @@ -233,11 +261,16 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, dlsch0_harq->TBS = rel8->length<<3; dlsch0_harq->Qm = rel8->modulation; dlsch0_harq->codeword = 0; - } - else { - dlsch0->i0 = 0xFFFF; + dlsch0_harq->pdsch_start = rel10->pdsch_start; } #endif + dlsch0->i0 = rel13->initial_transmission_sf_io; + + LOG_D(PHY,"dlsch->i0:%04x dlsch0_harq[pdsch_start:%d nb_rb:%d vrb_type:%d rvidx:%d Nl:%d mimo_mode:%d dl_power_off:%d round:%d status:%d TBS:%d Qm:%d codeword:%d rb_alloc:%d] rel8[length:%d]\n", + dlsch0->i0, + dlsch0_harq->pdsch_start, dlsch0_harq->nb_rb, dlsch0_harq->vrb_type, dlsch0_harq->rvidx, dlsch0_harq->Nl, dlsch0_harq->mimo_mode, dlsch0_harq->dl_power_off, dlsch0_harq->round, dlsch0_harq->status, dlsch0_harq->TBS, dlsch0_harq->Qm, dlsch0_harq->codeword, dlsch0_harq->rb_alloc[0], + rel8->length + ); } uint16_t to_beta_offset_harqack[16]={16,20,25,32,40,50,64,80,101,127,160,248,400,640,1008,8}; @@ -281,7 +314,7 @@ void handle_ulsch_cqi_ri_pdu(PHY_VARS_eNB *eNB,int UE_id,nfapi_ul_config_request if (ulsch_harq->O_RI>1) ulsch_harq->Or2 = rel9->aperiodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[1]; ulsch->beta_offset_ri_times8 = to_beta_offset_ri[rel9->delta_offset_ri]; ulsch->beta_offset_cqi_times8 = to_beta_offset_cqi[rel9->delta_offset_cqi]; - LOG_D(PHY,"Filling ulsch_cqi_ri information for frame %d, subframe %d : O_RI %d, Or1 %d, beta_offset_cqi_times8 %d (%d)\n", + LOG_E(PHY,"Filling ulsch_cqi_ri information for frame %d, subframe %d : O_RI %d, Or1 %d, beta_offset_cqi_times8 %d (%d)\n", frame,subframe,ulsch_harq->O_RI,ulsch_harq->Or1,ulsch->beta_offset_cqi_times8, rel9->delta_offset_cqi); } @@ -493,8 +526,7 @@ void handle_nfapi_ul_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) { AssertFatal((UE_id = find_ulsch(ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti,eNB,SEARCH_EXIST_OR_FREE))>=0, "No existing UE ULSCH for rnti %x\n",rel8->rnti); - LOG_D(PHY,"Applying UL config for UE %d, rnti %x for frame %d, subframe %d\n", - UE_id,rel8->rnti,frame,subframe); + //LOG_D(PHY,"Applying UL config for UE %d, rnti %x for frame %d, subframe %d\n", UE_id,rel8->rnti,frame,subframe); fill_ulsch(eNB,&ul_config_pdu->ulsch_pdu,frame,subframe); @@ -586,8 +618,12 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) ul_subframe = pdcch_alloc2ul_subframe(fp,subframe); ul_frame = pdcch_alloc2ul_frame(fp,frame,subframe); - AssertFatal(proc->subframe_tx == subframe, "Current subframe %d != NFAPI subframe %d\n",proc->subframe_tx,subframe); - AssertFatal(proc->frame_tx == frame, "Current frame %d != NFAPI frame %d\n",proc->frame_tx,frame); + // DJP - subframe assert will fail - not sure why yet + // DJP - AssertFatal(proc->subframe_tx == subframe, "Current subframe %d != NFAPI subframe %d\n",proc->subframe_tx,subframe); + // DJP - AssertFatal(proc->subframe_tx == subframe, "Current frame %d != NFAPI frame %d\n",proc->frame_tx,frame); + + uint8_t number_dci = DL_req->dl_config_request_body.number_dci; + uint8_t number_pdcch_ofdm_symbols = DL_req->dl_config_request_body.number_pdcch_ofdm_symbols; uint8_t number_dl_pdu = DL_req->dl_config_request_body.number_pdu; uint8_t number_hi_dci0_pdu = HI_DCI0_req->hi_dci0_request_body.number_of_dci+HI_DCI0_req->hi_dci0_request_body.number_of_hi; @@ -599,15 +635,23 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) int i; - eNB->pdcch_vars[subframe&1].num_pdcch_symbols = DL_req->dl_config_request_body.number_pdcch_ofdm_symbols; - eNB->pdcch_vars[subframe&1].num_dci = 0; + eNB->pdcch_vars[subframe&1].num_pdcch_symbols = number_pdcch_ofdm_symbols; + eNB->pdcch_vars[subframe&1].num_dci = number_dci; eNB->phich_vars[subframe&1].num_hi = 0; + if (number_dl_pdu || TX_req->tx_request_body.number_of_pdus || number_hi_dci0_pdu || number_ul_pdu) { + LOG_D(PHY,"NFAPI: Sched_INFO:SFN/SF:%04d%d DL_req:SFN/SF:%04d%d:dl_pdu:%d tx_req:SFN/SF:%04d%d:pdus:%d hi_dci0:SFN/SF:%04d%d:pdus:%d ul_cfg:SFN/SF:%04d%d:pdus:%d num_pdcch_symbols:%d\n", + frame,subframe, + NFAPI_SFNSF2SFN(DL_req->sfn_sf),NFAPI_SFNSF2SF(DL_req->sfn_sf),number_dl_pdu, + NFAPI_SFNSF2SFN(TX_req->sfn_sf),NFAPI_SFNSF2SF(TX_req->sfn_sf),TX_req->tx_request_body.number_of_pdus, + NFAPI_SFNSF2SFN(HI_DCI0_req->sfn_sf),NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf),number_hi_dci0_pdu, + NFAPI_SFNSF2SFN(UL_req->sfn_sf),NFAPI_SFNSF2SF(UL_req->sfn_sf),number_ul_pdu, + eNB->pdcch_vars[subframe&1].num_pdcch_symbols); + } - LOG_D(PHY,"NFAPI: Frame %d, Subframe %d (ul_subframe %d): received %d dl_pdu, %d tx_req, %d hi_dci0_config_req, %d UL_config \n", - frame,subframe,ul_subframe,number_dl_pdu,TX_req->tx_request_body.number_of_pdus,number_hi_dci0_pdu,number_ul_pdu); - - + int do_oai =0; + int dont_send =0; + if (ul_subframe<10) { // This means that there is an ul_subframe that can be configured here LOG_D(PHY,"NFAPI: Clearing dci allocations for potential UL\n"); harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); @@ -624,11 +668,13 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) } for (i=0;idl_config_request_body.dl_config_pdu_list[i]; - LOG_D(PHY,"NFAPI: dl_pdu %d : type %d\n",i,dl_config_pdu->pdu_type); + //LOG_D(PHY,"NFAPI: dl_pdu %d : type %d\n",i,dl_config_pdu->pdu_type); switch (dl_config_pdu->pdu_type) { case NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE: - handle_nfapi_dci_dl_pdu(eNB,proc,dl_config_pdu); - eNB->pdcch_vars[subframe&1].num_dci++; + handle_nfapi_dci_dl_pdu(eNB,NFAPI_SFNSF2SFN(DL_req->sfn_sf),NFAPI_SFNSF2SF(DL_req->sfn_sf),proc,dl_config_pdu); + eNB->pdcch_vars[NFAPI_SFNSF2SF(DL_req->sfn_sf)&1].num_dci++; + //LOG_E(PHY,"Incremented num_dci:%d but already set??? dl_config:num_dci:%d\n", eNB->pdcch_vars[subframe&1].num_dci, number_dci); + do_oai=1; break; case NFAPI_DL_CONFIG_BCH_PDU_TYPE: AssertFatal(dl_config_pdu->bch_pdu.bch_pdu_rel8.pdu_indextx_request_body.number_of_pdus, @@ -636,6 +682,11 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) dl_config_pdu->bch_pdu.bch_pdu_rel8.pdu_index, TX_req->tx_request_body.number_of_pdus); eNB->pbch_configured=1; + do_oai=1; + //LOG_D(PHY,"%s() NFAPI_DL_CONFIG_BCH_PDU_TYPE TX:%d/%d RX:%d/%d TXREQ:%d/%d\n", + //__FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->frame_rx, proc->subframe_rx, NFAPI_SFNSF2SFN(TX_req->sfn_sf), NFAPI_SFNSF2SF(TX_req->sfn_sf)); + + handle_nfapi_bch_pdu(eNB,proc,dl_config_pdu, TX_req->tx_request_body.tx_pdu_list[dl_config_pdu->bch_pdu.bch_pdu_rel8.pdu_index].segments[0].segment_data); break; @@ -643,22 +694,48 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) // handle_nfapi_mch_dl_pdu(eNB,dl_config_pdu); break; case NFAPI_DL_CONFIG_DLSCH_PDU_TYPE: + { + nfapi_dl_config_dlsch_pdu_rel8_t *dlsch_pdu_rel8 = &dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8; + uint16_t pdu_index = dlsch_pdu_rel8->pdu_index; + uint16_t tx_pdus = TX_req->tx_request_body.number_of_pdus; + uint16_t invalid_pdu = pdu_index == -1; + uint8_t *sdu = invalid_pdu ? NULL : pdu_index >= tx_pdus ? NULL : TX_req->tx_request_body.tx_pdu_list[pdu_index].segments[0].segment_data; + + LOG_D(PHY,"%s() [PDU:%d] NFAPI_DL_CONFIG_DLSCH_PDU_TYPE SFN/SF:%04d%d TX:%d/%d RX:%d/%d transport_blocks:%d pdu_index:%d sdu:%p\n", + __FUNCTION__, i, + NFAPI_SFNSF2SFN(DL_req->sfn_sf),NFAPI_SFNSF2SF(DL_req->sfn_sf), + proc->frame_tx, proc->subframe_tx, + proc->frame_rx, proc->subframe_rx, + dlsch_pdu_rel8->transport_blocks, pdu_index, sdu); + /* AssertFatal(dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_indextx_request_body.number_of_pdus, "dlsch_pdu_rel8.pdu_index>=TX_req->number_of_pdus (%d>%d)\n", dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index, TX_req->tx_request_body.number_of_pdus); */ - AssertFatal((dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks<3) && - (dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks>0), - "dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = %d not in [1,2]\n", - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks); - handle_nfapi_dlsch_pdu(eNB,proc,dl_config_pdu, - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks-1, - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index == -1 ? NULL - : TX_req->tx_request_body.tx_pdu_list[dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_data); + AssertFatal((dlsch_pdu_rel8->transport_blocks<3) && + (dlsch_pdu_rel8->transport_blocks>0), + "dlsch_pdu_rel8->transport_blocks = %d not in [1,2]\n", + dlsch_pdu_rel8->transport_blocks); + if (1)//sdu != NULL) + { + handle_nfapi_dlsch_pdu(eNB,NFAPI_SFNSF2SFN(DL_req->sfn_sf),NFAPI_SFNSF2SF(DL_req->sfn_sf),proc,dl_config_pdu, dlsch_pdu_rel8->transport_blocks-1, sdu); + } + else + { + dont_send=1; + + LOG_E(MAC,"%s() NFAPI_DL_CONFIG_DLSCH_PDU_TYPE sdu is NULL DL_CFG:SFN/SF:%d:pdu_index:%d TX_REQ:SFN/SF:%d:pdus:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(DL_req->sfn_sf), pdu_index, NFAPI_SFNSF2DEC(TX_req->sfn_sf), tx_pdus); + } + + // Send the data first so that the DL_CONFIG can just pluck it out of the buffer + // DJP - OAI was here - moved to bottom + do_oai=1; + /* if (dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti == eNB->preamble_list[0].preamble_rel8.rnti) {// is RAR pdu + LOG_D(PHY,"Frame %d, Subframe %d: Received LTE RAR pdu, programming based on UL Grant\n",frame,subframe); generate_eNB_ulsch_params_from_rar(eNB, TX_req->tx_request_body.tx_pdu_list[dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_data, @@ -666,6 +743,7 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) subframe); } */ + } break; case NFAPI_DL_CONFIG_PCH_PDU_TYPE: // handle_nfapi_pch_pdu(eNB,dl_config_pdu); @@ -685,6 +763,18 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) break; } } + + if (nfapi_mode && do_oai && !dont_send) { + oai_nfapi_tx_req(Sched_INFO->TX_req); + + oai_nfapi_dl_config_req(Sched_INFO->DL_req); // DJP - .dl_config_request_body.dl_config_pdu_list[0]); // DJP - FIXME TODO - yuk - only copes with 1 pdu + } + + if (nfapi_mode && number_hi_dci0_pdu!=0) { + oai_nfapi_hi_dci0_req(HI_DCI0_req); + eNB->pdcch_vars[NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf)&1].num_dci=0; + eNB->pdcch_vars[NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf)&1].num_pdcch_symbols=0; + } for (i=0;ipdu_type) { + case NFAPI_HI_DCI0_DCI_PDU_TYPE: - case NFAPI_HI_DCI0_DCI_PDU_TYPE: - handle_nfapi_hi_dci0_dci_pdu(eNB,proc,hi_dci0_req_pdu); - eNB->pdcch_vars[subframe&1].num_dci++; - break; + handle_nfapi_hi_dci0_dci_pdu(eNB,NFAPI_SFNSF2SFN(HI_DCI0_req->sfn_sf),NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf),proc,hi_dci0_req_pdu); - case NFAPI_HI_DCI0_HI_PDU_TYPE: - handle_nfapi_hi_dci0_hi_pdu(eNB,proc,hi_dci0_req_pdu); + eNB->pdcch_vars[NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf)&1].num_dci++; + break; - break; + case NFAPI_HI_DCI0_HI_PDU_TYPE: + handle_nfapi_hi_dci0_hi_pdu(eNB,NFAPI_SFNSF2SFN(HI_DCI0_req->sfn_sf),NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf),proc,hi_dci0_req_pdu); + break; } } - for (i=0;iul_config_request_body.ul_config_pdu_list[i]; - LOG_D(PHY,"NFAPI: ul_pdu %d : type %d\n",i,ul_config_pdu->pdu_type); - AssertFatal(ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE || - ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE || - ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE || - ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE || - ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE || - ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE || - ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE - , - "Optional UL_PDU type %d not supported\n",ul_config_pdu->pdu_type); - handle_nfapi_ul_pdu(eNB,proc,ul_config_pdu,UL_req->sfn_sf>>4,UL_req->sfn_sf&0xf,UL_req->ul_config_request_body.srs_present); + if (nfapi_mode) { + if (number_ul_pdu>0) + { + //LOG_D(PHY, "UL_CONFIG to send to PNF\n"); + oai_nfapi_ul_config_req(UL_req); + UL_req->ul_config_request_body.number_of_pdus=0; + number_ul_pdu=0; + } + } + else { + for (i=0;iul_config_request_body.ul_config_pdu_list[i]; + LOG_D(PHY,"NFAPI: ul_pdu %d : type %d\n",i,ul_config_pdu->pdu_type); + AssertFatal(ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE || + ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE || + ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE || + ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE || + ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE || + ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE || + ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE + , + "Optional UL_PDU type %d not supported\n",ul_config_pdu->pdu_type); + handle_nfapi_ul_pdu(eNB,proc,ul_config_pdu,UL_req->sfn_sf>>4,UL_req->sfn_sf&0xf,UL_req->ul_config_request_body.srs_present); + } } } diff --git a/openair1/SCHED/fapi_l1.h b/openair1/SCHED/fapi_l1.h index 3f4267c7f2..a912fa9f01 100644 --- a/openair1/SCHED/fapi_l1.h +++ b/openair1/SCHED/fapi_l1.h @@ -42,13 +42,13 @@ void fill_ulsch_cqi_indication(PHY_VARS_eNB *eNB,uint16_t frame,uint8_t subframe void fill_sr_indication(PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat); void fill_rx_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe); void fill_crc_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe,uint8_t crc_flag); -void handle_nfapi_dci_dl_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,nfapi_dl_config_request_pdu_t *dl_config_pdu); +void handle_nfapi_dci_dl_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc,nfapi_dl_config_request_pdu_t *dl_config_pdu); void handle_nfapi_mpdcch_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,nfapi_dl_config_request_pdu_t *dl_config_pdu); -void handle_nfapi_hi_dci0_dci_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, +void handle_nfapi_hi_dci0_dci_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc, nfapi_hi_dci0_request_pdu_t *hi_dci0_config_pdu); -void handle_nfapi_hi_dci0_hi_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, +void handle_nfapi_hi_dci0_hi_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc, nfapi_hi_dci0_request_pdu_t *hi_dci0_config_pdu); -void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, +void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc, nfapi_dl_config_request_pdu_t *dl_config_pdu, uint8_t codeword_index, uint8_t *sdu); diff --git a/openair1/SCHED/phy_procedures_lte_common.c b/openair1/SCHED/phy_procedures_lte_common.c index c8675dd814..01c44d6078 100644 --- a/openair1/SCHED/phy_procedures_lte_common.c +++ b/openair1/SCHED/phy_procedures_lte_common.c @@ -918,7 +918,7 @@ int is_srs_occasion_common(LTE_DL_FRAME_PARMS *frame_parms,int frame_tx,int subf if(frame_parms->soundingrs_ul_config_common.enabled_flag) { - LOG_D(PHY," SRS SUBFRAMECONFIG: %d\n", frame_parms->soundingrs_ul_config_common.srs_SubframeConfig); + //LOG_D(PHY," SRS SUBFRAMECONFIG: %d\n", frame_parms->soundingrs_ul_config_common.srs_SubframeConfig); uint8_t TSFC; uint16_t deltaTSFC; // bitmap @@ -951,7 +951,7 @@ int is_srs_occasion_common(LTE_DL_FRAME_PARMS *frame_parms,int frame_tx,int subf } LOG_D(PHY," ISTDD: %d, TSFC: %d, deltaTSFC: %d, AbsSubframeTX: %d.%d\n", frame_parms->frame_type, TSFC, deltaTSFC, frame_tx, subframe_tx); } - LOG_D(PHY," isSubframeSRS %d\n", isSubframeSRS); + //LOG_D(PHY," isSubframeSRS %d\n", isSubframeSRS); return(isSubframeSRS); } diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index c99776e7e5..5c0b8cd7fd 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -50,6 +50,8 @@ # include "intertask_interface.h" #endif +extern uint8_t nfapi_mode; +int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind); @@ -137,15 +139,13 @@ void pmch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,PHY_VARS_RN *rn,rel #endif } -void common_signal_procedures (PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) { +void common_signal_procedures (PHY_VARS_eNB *eNB,int frame, int subframe) { LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; int **txdataF = eNB->common_vars.txdataF; uint8_t *pbch_pdu=&eNB->pbch_pdu[0]; - int subframe = proc->subframe_tx; - int frame = proc->frame_tx; - LOG_D(PHY,"common_signal_procedures: frame %d, subframe %d\n",frame,subframe); + //LOG_D(PHY,"common_signal_procedures: frame %d, subframe %d fdd:%s dir:%s\n",frame,subframe,fp->frame_type == FDD?"FDD":"TDD", subframe_select(fp,subframe) == SF_DL?"DL":"UL?"); // generate Cell-Specific Reference Signals for both slots VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_RS_TX,1); @@ -196,7 +196,8 @@ void common_signal_procedures (PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) { /// generate PBCH if ((frame&3)==0) { - AssertFatal(eNB->pbch_configured==1,"PBCH was not configured by MAC\n"); + //AssertFatal(eNB->pbch_configured==1,"PBCH was not configured by MAC\n"); + if (eNB->pbch_configured!=1) return; eNB->pbch_configured=0; } generate_pbch(&eNB->pbch, @@ -270,9 +271,10 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, int input_buffer_length = dlsch_harq->TBS/8; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - if (dlsch->rnti == 0x02) {//frame < 200) { + if (1){ + //if (dlsch->rnti == 0x02) {//frame < 200) { - LOG_I(PHY, + LOG_D(PHY, "[eNB %"PRIu8"][PDSCH %"PRIx16"/%"PRIu8"] Frame %d, subframe %d: Generating PDSCH/DLSCH with input size = %"PRIu16", pdsch_start %d, G %d, nb_rb %"PRIu16", rb0 %x, rb1 %x, TBS %"PRIu16", pmi_alloc %"PRIx64", rv %"PRIu8" (round %"PRIu8")\n", eNB->Mod_id, dlsch->rnti,harq_pid, frame, subframe, input_buffer_length, dlsch_harq->pdsch_start, @@ -332,42 +334,50 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, } - LOG_D(PHY,"Generating DLSCH/PDSCH %d\n",ra_flag); + LOG_D(PHY,"Generating DLSCH/PDSCH pdu:%p pdsch_start:%d frame:%d subframe:%d nb_rb:%d rb_alloc:%d Qm:%d Nl:%d round:%d\n", + dlsch_harq->pdu,dlsch_harq->pdsch_start,frame,subframe,dlsch_harq->nb_rb,dlsch_harq->rb_alloc[0],dlsch_harq->Qm,dlsch_harq->Nl,dlsch_harq->round); // 36-212 - start_meas(&eNB->dlsch_encoding_stats); - AssertFatal(dlsch_harq->pdu!=NULL,"dlsch_harq->pdu == NULL (rnti %x)\n",dlsch->rnti); - eNB->te(eNB, - dlsch_harq->pdu, - dlsch_harq->pdsch_start, - dlsch, - frame,subframe, - &eNB->dlsch_rate_matching_stats, - &eNB->dlsch_turbo_encoding_stats, - &eNB->dlsch_interleaving_stats); - stop_meas(&eNB->dlsch_encoding_stats); + if (nfapi_mode == 0 || nfapi_mode == 1) { // monolthic OR PNF - do not need turbo encoding on VNF + + if (dlsch_harq->pdu==NULL){ + LOG_E(PHY,"dlsch_harq->pdu == NULL SFN/SF:%04d%d dlsch[rnti:%x] dlsch_harq[pdu:%p pdsch_start:%d Qm:%d Nl:%d round:%d nb_rb:%d rb_alloc[0]:%d]\n", frame,subframe,dlsch->rnti, dlsch_harq->pdu,dlsch_harq->pdsch_start,dlsch_harq->Qm,dlsch_harq->Nl,dlsch_harq->round,dlsch_harq->nb_rb,dlsch_harq->rb_alloc[0]); + return; + } + + start_meas(&eNB->dlsch_encoding_stats); + + eNB->te(eNB, + dlsch_harq->pdu, + dlsch_harq->pdsch_start, + dlsch, + frame,subframe, + &eNB->dlsch_rate_matching_stats, + &eNB->dlsch_turbo_encoding_stats, + &eNB->dlsch_interleaving_stats); + stop_meas(&eNB->dlsch_encoding_stats); // 36-211 - start_meas(&eNB->dlsch_scrambling_stats); - dlsch_scrambling(fp, - 0, - dlsch, - harq_pid, - get_G(fp, - dlsch_harq->nb_rb, - dlsch_harq->rb_alloc, - dlsch_harq->Qm, - dlsch_harq->Nl, - dlsch_harq->pdsch_start, - frame,subframe, - 0), - 0, - frame, - subframe<<1); - stop_meas(&eNB->dlsch_scrambling_stats); + start_meas(&eNB->dlsch_scrambling_stats); + dlsch_scrambling(fp, + 0, + dlsch, + harq_pid, + get_G(fp, + dlsch_harq->nb_rb, + dlsch_harq->rb_alloc, + dlsch_harq->Qm, + dlsch_harq->Nl, + dlsch_harq->pdsch_start, + frame,subframe, + 0), + 0, + frame, + subframe<<1); + stop_meas(&eNB->dlsch_scrambling_stats); + + start_meas(&eNB->dlsch_modulation_stats); + - start_meas(&eNB->dlsch_modulation_stats); - - - dlsch_modulation(eNB, + dlsch_modulation(eNB, eNB->common_vars.txdataF, AMP, subframe, @@ -375,10 +385,13 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, dlsch, dlsch1); - stop_meas(&eNB->dlsch_modulation_stats); + stop_meas(&eNB->dlsch_modulation_stats); + } dlsch->active = 0; dlsch_harq->round++; + + LOG_D(PHY,"Generating DLSCH/PDSCH dlsch_harq[round:%d]\n",dlsch_harq->round); } @@ -416,12 +429,14 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, } - if (is_pmch_subframe(frame,subframe,fp)) { - pmch_procedures(eNB,proc,rn,r_type); - } - else { - // this is not a pmch subframe, so generate PSS/SSS/PBCH - common_signal_procedures(eNB,proc); + if (nfapi_mode == 0 || nfapi_mode == 1) { + if (is_pmch_subframe(frame,subframe,fp)) { + pmch_procedures(eNB,proc,rn,r_type); + } + else { + // this is not a pmch subframe, so generate PSS/SSS/PBCH + common_signal_procedures(eNB,proc->frame_tx, proc->subframe_tx); + } } // clear existing ulsch dci allocations before applying info from MAC (this is table @@ -475,30 +490,36 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, num_dci = eNB->pdcch_vars[subframe&1].num_dci; // LOG_D(PHY,"num_pdcch_symbols %"PRIu8",(dci common %"PRIu8", dci uespec %"PRIu8"\n",num_pdcch_symbols, // DCI_pdu->Num_common_dci,DCI_pdu->Num_ue_spec_dci); - LOG_D(PHY,"num_pdcch_symbols %"PRIu8",(number dci %"PRIu8"\n",num_pdcch_symbols, - num_dci); + //LOG_D(PHY,"num_pdcch_symbols %"PRIu8",number dci %"PRIu8"\n",num_pdcch_symbols, num_dci); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,num_pdcch_symbols); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,(frame*10)+subframe); if (num_dci > 0) - LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_top (pdcch) (num_dci %"PRIu8")\n",eNB->Mod_id,frame, subframe, - num_dci); - + { + //LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_top (pdcch) (num_dci %"PRIu8") num_pdcch_symbols:%d\n",eNB->Mod_id,frame, subframe, num_dci, num_pdcch_symbols); + } - generate_dci_top(num_pdcch_symbols, - num_dci, - &eNB->pdcch_vars[subframe&1].dci_alloc[0], - 0, - AMP, - fp, - eNB->common_vars.txdataF, - subframe); - + //LOG_D(PHY,"Before generate_dci_top num_pdcch_symbols:%d num_dci:%d dci_alloc:dci_length:%d\n", num_pdcch_symbols, num_dci, eNB->pdcch_vars[subframe&1].dci_alloc[0].dci_length); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,1); + + if (nfapi_mode == 0 || nfapi_mode == 1) { + generate_dci_top(num_pdcch_symbols, + num_dci, + &eNB->pdcch_vars[subframe&1].dci_alloc[0], + 0, + AMP, + fp, + eNB->common_vars.txdataF, + subframe); + } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,0); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,1); // Now scan UE specific DLSCH LTE_eNB_DLSCH_t *dlsch0,*dlsch1; for (UE_id=0; UE_idharq_ids[subframe]; AssertFatal(harq_pid>=0,"harq_pid is negative\n"); - // generate pdsch - pdsch_procedures(eNB, - proc, - harq_pid, - dlsch0, - dlsch1, - &eNB->UE_stats[(uint32_t)UE_id], - 0); + + if (harq_pid>=8) + { + LOG_E(PHY,"harq_pid:%d corrupt must be 0-7 UE_id:%d frame:%d subframe:%d rnti:%x\n", harq_pid,UE_id,frame,subframe,dlsch0->rnti); + } + else + { + // generate pdsch + pdsch_procedures(eNB, + proc, + harq_pid, + dlsch0, + dlsch1, + &eNB->UE_stats[(uint32_t)UE_id], + 0); + } } else if ((dlsch0)&& - (dlsch0->rnti>0)&& - (dlsch0->active == 0)) { + (dlsch0->rnti>0)&& + (dlsch0->active == 0)) { - // clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later) - dlsch0->subframe_tx[subframe]=0; + // clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later) + dlsch0->subframe_tx[subframe]=0; } } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,0); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_PHICH,1); generate_phich_top(eNB, proc, AMP); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_PHICH,0); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX+offset,0); if (do_meas==1) stop_meas(&eNB->phy_proc_tx); @@ -561,14 +593,14 @@ void prach_procedures(PHY_VARS_eNB *eNB, subframe = eNB->proc.subframe_prach_br; frame = eNB->proc.frame_prach_br; pthread_mutex_lock(&eNB->UL_INFO_mutex); - eNB->UL_INFO.rach_ind_br.number_of_preambles=0; + eNB->UL_INFO.rach_ind_br.rach_indication_body.number_of_preambles=0; pthread_mutex_unlock(&eNB->UL_INFO_mutex); } else #endif { pthread_mutex_lock(&eNB->UL_INFO_mutex); - eNB->UL_INFO.rach_ind.number_of_preambles=0; + eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles=0; pthread_mutex_unlock(&eNB->UL_INFO_mutex); subframe = eNB->proc.subframe_prach; frame = eNB->proc.frame_prach; @@ -608,20 +640,22 @@ void prach_procedures(PHY_VARS_eNB *eNB, ); //#ifdef DEBUG_PHY_PROC - LOG_D(PHY,"[RAPROC] Frame %d, subframe %d : Most likely preamble %d, energy %d dB delay %d\n", + if (max_preamble_energy[0]/10 > 32) + LOG_E(PHY,"[RAPROC] Frame %d, subframe %d : Most likely preamble %d, energy %d dB delay %d\n", frame,subframe, - max_preamble[0], + max_preamble[0], max_preamble_energy[0]/10, max_preamble_delay[0]); //q#endif #ifdef Rel14 if (br_flag==1) { + int prach_mask; prach_mask = is_prach_subframe(&eNB->frame_parms,eNB->proc.frame_prach_br,eNB->proc.subframe_prach_br); - eNB->UL_INFO.rach_ind_br.preamble_list = eNB->preamble_list_br; + eNB->UL_INFO.rach_ind_br.rach_indication_body.preamble_list = eNB->preamble_list_br; int ind=0; int ce_level=0; /* Save for later, it doesn't work @@ -635,7 +669,7 @@ void prach_procedures(PHY_VARS_eNB *eNB, if (eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0]==1){ if ((eNB->prach_energy_counter == 100) && (max_preamble_energy[0] > eNB->measurements.prach_I0 + 100)) { - eNB->UL_INFO.rach_ind_br.number_of_preambles++; + eNB->UL_INFO.rach_ind_br.rach_indication_body.number_of_preambles++; eNB->preamble_list_br[ind].preamble_rel8.timing_advance = max_preamble_delay[ind];// eNB->preamble_list_br[ind].preamble_rel8.preamble = max_preamble[ind]; @@ -665,7 +699,7 @@ void prach_procedures(PHY_VARS_eNB *eNB, if ((eNB->prach_energy_counter == 100) && (max_preamble_energy[0] > eNB->measurements.prach_I0+100)) { - LOG_D(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", + LOG_E(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", eNB->Mod_id, eNB->CC_id, frame, @@ -680,20 +714,33 @@ void prach_procedures(PHY_VARS_eNB *eNB, pthread_mutex_lock(&eNB->UL_INFO_mutex); - eNB->UL_INFO.rach_ind.number_of_preambles = 1; - eNB->UL_INFO.rach_ind.preamble_list = eNB->preamble_list; + eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles = 1; + eNB->UL_INFO.rach_ind.rach_indication_body.preamble_list = &eNB->preamble_list[0]; + eNB->UL_INFO.rach_ind.rach_indication_body.tl.tag = NFAPI_RACH_INDICATION_BODY_TAG; + eNB->UL_INFO.rach_ind.header.message_id = NFAPI_RACH_INDICATION; + eNB->UL_INFO.rach_ind.sfn_sf = frame<<4 | subframe; + eNB->preamble_list[0].preamble_rel8.tl.tag = NFAPI_PREAMBLE_REL8_TAG; eNB->preamble_list[0].preamble_rel8.timing_advance = max_preamble_delay[0]; eNB->preamble_list[0].preamble_rel8.preamble = max_preamble[0]; eNB->preamble_list[0].preamble_rel8.rnti = 1+subframe; // note: fid is implicitly 0 here eNB->preamble_list[0].preamble_rel13.rach_resource_type = 0; eNB->preamble_list[0].instance_length = 0; //don't know exactly what this is - LOG_D(PHY,"Filling NFAPI indication for RACH : TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", - eNB->preamble_list[0].preamble_rel8.timing_advance, - eNB->preamble_list[0].preamble_rel8.preamble, - eNB->preamble_list[0].preamble_rel8.rnti, - eNB->preamble_list[0].preamble_rel13.rach_resource_type); + if (nfapi_mode == 1) { // If NFAPI PNF then we need to send the message to the VNF + + LOG_E(PHY,"Filling NFAPI indication for RACH : SFN_SF:%d TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", + NFAPI_SFNSF2DEC(eNB->UL_INFO.rach_ind.sfn_sf), + eNB->preamble_list[0].preamble_rel8.timing_advance, + eNB->preamble_list[0].preamble_rel8.preamble, + eNB->preamble_list[0].preamble_rel8.rnti, + eNB->preamble_list[0].preamble_rel13.rach_resource_type); + + oai_nfapi_rach_ind(&eNB->UL_INFO.rach_ind); + + eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles = 0; + } + pthread_mutex_unlock(&eNB->UL_INFO_mutex); } // max_preamble_energy > prach_I0 + 100 @@ -742,21 +789,31 @@ void srs_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) { void fill_sr_indication(PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat) { pthread_mutex_lock(&eNB->UL_INFO_mutex); - nfapi_sr_indication_pdu_t *pdu = &eNB->UL_INFO.sr_ind.sr_pdu_list[eNB->UL_INFO.sr_ind.number_of_srs]; + nfapi_sr_indication_t *sr_ind = &eNB->UL_INFO.sr_ind; + nfapi_sr_indication_body_t *sr_ind_body = &sr_ind->sr_indication_body; + nfapi_sr_indication_pdu_t *pdu = &sr_ind_body->sr_pdu_list[sr_ind_body->number_of_srs]; + + sr_ind->sfn_sf = frame<<4|subframe; + sr_ind->header.message_id = NFAPI_RX_SR_INDICATION; + + sr_ind_body->tl.tag = NFAPI_SR_INDICATION_BODY_TAG; pdu->instance_length = 0; // don't know what to do with this // pdu->rx_ue_information.handle = handle; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; pdu->rx_ue_information.rnti = rnti; int SNRtimes10 = dB_fixed_times10(stat) - 200;//(10*eNB->measurements.n0_power_dB[0]); + pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG; + if (SNRtimes10 < -640) pdu->ul_cqi_information.ul_cqi=0; else if (SNRtimes10 > 635) pdu->ul_cqi_information.ul_cqi=255; else pdu->ul_cqi_information.ul_cqi=(640+SNRtimes10)/5; pdu->ul_cqi_information.channel = 0; - eNB->UL_INFO.sr_ind.number_of_srs++; + sr_ind_body->number_of_srs++; pthread_mutex_unlock(&eNB->UL_INFO_mutex); } @@ -1082,7 +1139,7 @@ void uci_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) } } uci->stat = max_metric; - fill_uci_harq_indication(eNB,uci,frame,subframe,harq_ack,1,tdd_multiplexing_mask); // multiplexing mode + fill_uci_harq_indication(eNB,uci,frame,subframe,harq_ack,1,tdd_multiplexing_mask); // multiplexing mode } } //else if ((uci->tdd_bundling == 0) && (res==3)) else if ((uci->tdd_bundling == 0) && (uci->num_pucch_resources==4)){ // multiplexing + no SR, implement Table 10.1.3-7 (Rel14) for multiplexing with M=4 @@ -1243,14 +1300,14 @@ void uci_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) } if (SR_payload == 1) { - LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Got SR for PUSCH, transmitting to MAC\n",eNB->Mod_id, + LOG_E(PHY,"[eNB %d][SR %x] Frame %d subframe %d Got SR for PUSCH, transmitting to MAC\n",eNB->Mod_id, uci->rnti,frame,subframe); if (eNB->first_sr[i] == 1) { // this is the first request for uplink after Connection Setup, so clear HARQ process 0 use for Msg4 eNB->first_sr[i] = 0; eNB->dlsch[i][0]->harq_processes[0]->round=0; eNB->dlsch[i][0]->harq_processes[0]->status=SCH_IDLE; - LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d First SR\n", + LOG_E(PHY,"[eNB %d][SR %x] Frame %d subframe %d First SR\n", eNB->Mod_id, eNB->ulsch[i]->rnti,frame,subframe); } @@ -1267,81 +1324,80 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; LTE_eNB_ULSCH_t *ulsch; LTE_UL_eNB_HARQ_t *ulsch_harq; + struct timespec t_decode, t_crc,t_rx_ind,t_rx_ind_b,t_harq_a,t_harq_b,t_end; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; - + if (fp->frame_type == FDD) harq_pid = ((10*frame) + subframe)&7; else harq_pid = subframe%10; for (i=0; iulsch[i]; ulsch_harq = ulsch->harq_processes[harq_pid]; - if (ulsch->rnti>0) LOG_D(PHY,"Frame %d, subframe %d: PUSCH procedures, harq_pid %d, UE %d/%x\n", - frame,subframe,harq_pid,i,ulsch->rnti); - + if (ulsch->rnti>0) LOG_D(PHY,"eNB->ulsch[%d]->harq_processes[harq_pid:%d] SFN/SF:%04d%d: PUSCH procedures, UE %d/%x ulsch_harq[status:%d SFN/SF:%04d%d handled:%d]\n", + i, harq_pid, frame,subframe,i,ulsch->rnti, + ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->handled); + if ((ulsch) && (ulsch->rnti>0) && (ulsch_harq->status == ACTIVE) && - (ulsch_harq->frame == frame) && - (ulsch_harq->subframe == subframe) && + (ulsch_harq->frame == frame) && + (ulsch_harq->subframe == subframe) && (ulsch_harq->handled == 0)) { - + // UE has ULSCH scheduling for (int rb=0; rb<=ulsch_harq->nb_rb; - rb++) { - int rb2 = rb+ulsch_harq->first_rb; - eNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31)); + rb++) { + int rb2 = rb+ulsch_harq->first_rb; + eNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31)); } - LOG_D(PHY,"[eNB %d] frame %d, subframe %d: Scheduling ULSCH Reception for UE %d \n", - eNB->Mod_id, - frame, - subframe, - i); + //LOG_D(PHY,"[eNB %d] frame %d, subframe %d: Scheduling ULSCH Reception for UE %d \n", eNB->Mod_id, frame, subframe, i); nPRS = fp->pusch_config_common.ul_ReferenceSignalsPUSCH.nPRS[subframe<<1]; ulsch->cyclicShift = (ulsch_harq->n_DMRS2 + - fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift + - nPRS)%12; + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift + + nPRS)%12; - LOG_D(PHY, - "[eNB %d][PUSCH %d] Frame %d Subframe %d Demodulating PUSCH: dci_alloc %d, rar_alloc %d, round %d, first_rb %d, nb_rb %d, Qm %d, TBS %d, rv %d, cyclic_shift %d (n_DMRS2 %d, cyclicShift_common %d, nprs %d), O_ACK %d, beta_cqi %d \n", - eNB->Mod_id,harq_pid,frame,subframe, - ulsch_harq->dci_alloc, - ulsch_harq->rar_alloc, - ulsch_harq->round, - ulsch_harq->first_rb, - ulsch_harq->nb_rb, - ulsch_harq->Qm, - ulsch_harq->TBS, - ulsch_harq->rvidx, - ulsch->cyclicShift, - ulsch_harq->n_DMRS2, - fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift, - nPRS, - ulsch_harq->O_ACK, - ulsch->beta_offset_cqi_times8); + if(0)LOG_D(PHY, + "[eNB %d][PUSCH %d] Frame %d Subframe %d Demodulating PUSCH: dci_alloc %d, rar_alloc %d, round %d, first_rb %d, nb_rb %d, Qm %d, TBS %d, rv %d, cyclic_shift %d (n_DMRS2 %d, cyclicShift_common %d, ), O_ACK %d, beta_cqi %d \n", + eNB->Mod_id,harq_pid,frame,subframe, + ulsch_harq->dci_alloc, + ulsch_harq->rar_alloc, + ulsch_harq->round, + ulsch_harq->first_rb, + ulsch_harq->nb_rb, + ulsch_harq->Qm, + ulsch_harq->TBS, + ulsch_harq->rvidx, + ulsch->cyclicShift, + ulsch_harq->n_DMRS2, + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift, + ulsch_harq->O_ACK, + ulsch->beta_offset_cqi_times8); - start_meas(&eNB->ulsch_demodulation_stats); + start_meas(&eNB->ulsch_demodulation_stats); rx_ulsch(eNB,proc, i); - stop_meas(&eNB->ulsch_demodulation_stats); + stop_meas(&eNB->ulsch_demodulation_stats); - start_meas(&eNB->ulsch_decoding_stats); + clock_gettime(CLOCK_MONOTONIC,&t_decode); - ret = ulsch_decoding(eNB,proc, - i, - 0, // control_only_flag - ulsch_harq->V_UL_DAI, - ulsch_harq->nb_rb>20 ? 1 : 0); + start_meas(&eNB->ulsch_decoding_stats); - stop_meas(&eNB->ulsch_decoding_stats); + ret = ulsch_decoding(eNB,proc, + i, + 0, // control_only_flag + ulsch_harq->V_UL_DAI, + ulsch_harq->nb_rb>20 ? 1 : 0); - LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d\n", + stop_meas(&eNB->ulsch_decoding_stats); + + LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d ulsch_harq->cqi_crc_status:%d ackBits:%d ulsch_decoding_stats[t:%lld max:%lld]\n", eNB->Mod_id,harq_pid, frame,subframe, ulsch->rnti, @@ -1351,51 +1407,55 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) 20,//eNB->measurements.n0_power_dB[1], ulsch_harq->o_ACK[0], ulsch_harq->o_ACK[1], - ret); + ret, + ulsch_harq->cqi_crc_status, + ulsch_harq->O_ACK, + eNB->ulsch_decoding_stats.diff_now, eNB->ulsch_decoding_stats.max); - //compute the expected ULSCH RX power (for the stats) - ulsch_harq->delta_TF = get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 0); // 0 means bw_factor is not considered + //compute the expected ULSCH RX power (for the stats) + ulsch_harq->delta_TF = get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 0); // 0 means bw_factor is not considered - if (ulsch_harq->cqi_crc_status == 1) { + if (ulsch_harq->cqi_crc_status == 1) { #ifdef DEBUG_PHY_PROC - //if (((frame%10) == 0) || (frame < 50)) - print_CQI(ulsch_harq->o,ulsch_harq->uci_format,0,fp->N_RB_DL); + //if (((frame%10) == 0) || (frame < 50)) + print_CQI(ulsch_harq->o,ulsch_harq->uci_format,0,fp->N_RB_DL); #endif - fill_ulsch_cqi_indication(eNB,frame,subframe, - ulsch_harq, - ulsch->rnti); + fill_ulsch_cqi_indication(eNB,frame,subframe, + ulsch_harq, + ulsch->rnti); } - + if (ret == (1+MAX_TURBO_ITERATIONS)) { T(T_ENB_PHY_ULSCH_UE_NACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(ulsch->rnti), T_INT(harq_pid)); - fill_crc_indication(eNB,i,frame,subframe,1); // indicate NAK to MAC - fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC + fill_crc_indication(eNB,i,frame,subframe,1); // indicate NAK to MAC + fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC + + LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d Error receiving ULSCH, round %d/%d (ACK %d,%d)\n", + eNB->Mod_id,harq_pid, + frame,subframe, i, + ulsch_harq->round-1, + ulsch->Mlimit, + ulsch_harq->o_ACK[0], + ulsch_harq->o_ACK[1]); - LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d Error receiving ULSCH, round %d/%d (ACK %d,%d)\n", - eNB->Mod_id,harq_pid, - frame,subframe, i, - ulsch_harq->round-1, - ulsch->Mlimit, - ulsch_harq->o_ACK[0], - ulsch_harq->o_ACK[1]); if (ulsch_harq->round >= 3) { ulsch_harq->status = SCH_IDLE; ulsch_harq->handled = 0; ulsch->harq_mask &= ~(1 << harq_pid); ulsch_harq->round = 0; - } + } #if defined(MESSAGE_CHART_GENERATOR_PHY) MSC_LOG_RX_DISCARDED_MESSAGE( - MSC_PHY_ENB,MSC_PHY_UE, - NULL,0, - "%05u:%02u ULSCH received rnti %x harq id %u round %d", - frame,subframe, - ulsch->rnti,harq_pid, - ulsch_harq->round-1 - ); + MSC_PHY_ENB,MSC_PHY_UE, + NULL,0, + "%05u:%02u ULSCH received rnti %x harq id %u round %d", + frame,subframe, + ulsch->rnti,harq_pid, + ulsch_harq->round-1 + ); #endif /* Mark the HARQ process to release it later if max transmission reached @@ -1406,8 +1466,12 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) ulsch_harq->handled = 1; } // ulsch in error else { - fill_crc_indication(eNB,i,frame,subframe,0); // indicate ACK to MAC - fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC + clock_gettime(CLOCK_MONOTONIC,&t_crc); + + fill_crc_indication(eNB,i,frame,subframe,0); // indicate ACK to MAC + clock_gettime(CLOCK_MONOTONIC,&t_rx_ind); + fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC + clock_gettime(CLOCK_MONOTONIC,&t_rx_ind_b); ulsch_harq->status = SCH_IDLE; ulsch->harq_mask &= ~(1 << harq_pid); @@ -1416,29 +1480,31 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) T_INT(harq_pid)); #if defined(MESSAGE_CHART_GENERATOR_PHY) - MSC_LOG_RX_MESSAGE( - MSC_PHY_ENB,MSC_PHY_UE, - NULL,0, - "%05u:%02u ULSCH received rnti %x harq id %u", - frame,subframe, - ulsch->rnti,harq_pid - ); + MSC_LOG_RX_MESSAGE( + MSC_PHY_ENB,MSC_PHY_UE, + NULL,0, + "%05u:%02u ULSCH received rnti %x harq id %u", + frame,subframe, + ulsch->rnti,harq_pid + ); #endif #ifdef DEBUG_PHY_PROC #ifdef DEBUG_ULSCH - LOG_D(PHY,"[eNB] Frame %d, Subframe %d : ULSCH SDU (RX harq_pid %d) %d bytes:",frame,subframe, - harq_pid,ulsch_harq->TBS>>3); + LOG_D(PHY,"[eNB] Frame %d, Subframe %d : ULSCH SDU (RX harq_pid %d) %d bytes:",frame,subframe, + harq_pid,ulsch_harq->TBS>>3); - for (j=0; jTBS>>3; j++) - LOG_T(PHY,"%x.",ulsch->harq_processes[harq_pid]->b[j]); + for (j=0; jTBS>>3; j++) + LOG_T(PHY,"%x.",ulsch->harq_processes[harq_pid]->b[j]); - LOG_T(PHY,"\n"); + LOG_T(PHY,"\n"); #endif #endif - } // ulsch not in error + } // ulsch not in error + clock_gettime(CLOCK_MONOTONIC,&t_harq_a); if (ulsch_harq->O_ACK>0) fill_ulsch_harq_indication(eNB,ulsch_harq,ulsch->rnti,frame,subframe,ulsch->bundling); + clock_gettime(CLOCK_MONOTONIC,&t_harq_b); LOG_D(PHY,"[eNB %d] Frame %d subframe %d: received ULSCH harq_pid %d for UE %d, ret = %d, CQI CRC Status %d, ACK %d,%d, ulsch_errors %d/%d\n", eNB->Mod_id,frame,subframe, @@ -1459,14 +1525,23 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) (ulsch_harq->frame == frame) && (ulsch_harq->subframe == subframe) && (ulsch_harq->handled == 1)) { - // this harq process is stale, kill it, this 1024 frames later (10s), consider reducing that - ulsch_harq->status = SCH_IDLE; + // this harq process is stale, kill it, this 1024 frames later (10s), consider reducing that + ulsch_harq->status = SCH_IDLE; ulsch_harq->handled = 0; ulsch->harq_mask &= ~(1 << harq_pid); LOG_W(PHY,"Removing stale ULSCH config for UE %x harq_pid %d (harq_mask is now 0x%2.2x)\n", ulsch->rnti, harq_pid, ulsch->harq_mask); } - } // for (i=0; iframe_parms, - frame,subframe); + frame,subframe); pthread_mutex_lock(&eNB->UL_INFO_mutex); - pdu = &eNB->UL_INFO.rx_ind.rx_pdu_list[eNB->UL_INFO.rx_ind.number_of_pdus]; + + eNB->UL_INFO.rx_ind.sfn_sf = frame<<4| subframe; + eNB->UL_INFO.rx_ind.rx_indication_body.tl.tag = NFAPI_RX_INDICATION_BODY_TAG; + + pdu = &eNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list[eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus]; // pdu->rx_ue_information.handle = eNB->ulsch[UE_id]->handle; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; pdu->rx_ue_information.rnti = eNB->ulsch[UE_id]->rnti; + pdu->rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG; pdu->rx_indication_rel8.length = eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3; - pdu->rx_indication_rel8.offset = 0; // filled in at the end of the UL_INFO formation - pdu->data = eNB->ulsch[UE_id]->harq_processes[harq_pid]->b; + pdu->rx_indication_rel8.offset = 1; // DJP - I dont understand - but broken unless 1 ???? 0; // filled in at the end of the UL_INFO formation + pdu->data = eNB->ulsch[UE_id]->harq_processes[harq_pid]->b; // estimate timing advance for MAC sync_pos = lte_est_timing_advance_pusch(eNB,UE_id); timing_advance_update = sync_pos; // - eNB->frame_parms.nb_prefix_samples/4; //to check @@ -1550,11 +1631,12 @@ void fill_rx_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe) else if (SNRtimes10 > 635) pdu->rx_indication_rel8.ul_cqi=255; else pdu->rx_indication_rel8.ul_cqi=(640+SNRtimes10)/5; - LOG_D(PHY,"[PUSCH %d] Filling RX_indication with SNR %d (%d), timing_advance %d (update %d)\n", - harq_pid,SNRtimes10,pdu->rx_indication_rel8.ul_cqi,pdu->rx_indication_rel8.timing_advance, - timing_advance_update); + LOG_D(PHY,"[PUSCH %d] Frame %d Subframe %d Filling RX_indication with SNR %d (%d), timing_advance %d (update %d)\n", + harq_pid,frame,subframe,SNRtimes10,pdu->rx_indication_rel8.ul_cqi,pdu->rx_indication_rel8.timing_advance, + timing_advance_update); - eNB->UL_INFO.rx_ind.number_of_pdus++; + eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus++; + eNB->UL_INFO.rx_ind.sfn_sf = frame<<4 | subframe; pthread_mutex_unlock(&eNB->UL_INFO_mutex); } @@ -1649,11 +1731,13 @@ void fill_ulsch_cqi_indication(PHY_VARS_eNB *eNB,uint16_t frame,uint8_t subframe nfapi_cqi_indication_pdu_t *pdu = &eNB->UL_INFO.cqi_ind.cqi_pdu_list[eNB->UL_INFO.cqi_ind.number_of_cqis]; nfapi_cqi_indication_raw_pdu_t *raw_pdu = &eNB->UL_INFO.cqi_ind.cqi_raw_pdu_list[eNB->UL_INFO.cqi_ind.number_of_cqis]; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; pdu->rx_ue_information.rnti = rnti; if (ulsch_harq->cqi_crc_status != 1) pdu->cqi_indication_rel9.data_offset = 0; else pdu->cqi_indication_rel9.data_offset = 1; // fill in after all cqi_indications have been generated when non-zero // by default set O to rank 1 value + pdu->cqi_indication_rel9.tl.tag = NFAPI_CQI_INDICATION_REL9_TAG; pdu->cqi_indication_rel9.length = (ulsch_harq->Or1>>3) + ((ulsch_harq->Or1&7) > 0 ? 1 : 0); pdu->cqi_indication_rel9.ri[0] = 0; @@ -1668,6 +1752,8 @@ void fill_ulsch_cqi_indication(PHY_VARS_eNB *eNB,uint16_t frame,uint8_t subframe pdu->ul_cqi_information.channel = 1; // PUSCH memcpy((void*)raw_pdu->pdu,ulsch_harq->o,pdu->cqi_indication_rel9.length); eNB->UL_INFO.cqi_ind.number_of_cqis++; + LOG_D(PHY,"eNB->UL_INFO.cqi_ind.number_of_cqis:%d\n", eNB->UL_INFO.cqi_ind.number_of_cqis); + pthread_mutex_unlock(&eNB->UL_INFO_mutex); } @@ -1675,18 +1761,33 @@ void fill_ulsch_cqi_indication(PHY_VARS_eNB *eNB,uint16_t frame,uint8_t subframe void fill_ulsch_harq_indication(PHY_VARS_eNB *eNB,LTE_UL_eNB_HARQ_t *ulsch_harq,uint16_t rnti, int frame,int subframe,int bundling) { int UE_id = find_dlsch(rnti,eNB,SEARCH_EXIST); - AssertFatal(UE_id>=0,"UE_id doesn't exist\n"); + //AssertFatal(UE_id>=0,"UE_id doesn't exist\n"); + + if (UE_id < 0) + { + LOG_E(PHY,"%s(eNB, ulsch_harq, rnti:%04x, frame:%d, subframe:%d, bundling:%d) harq_pdus:%d - Could not find rnti - abort fill of ulsch harq ind\n", __FUNCTION__, rnti, frame, subframe, bundling,eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs); + return; + } + + LOG_I(PHY,"%s(eNB, ulsch_harq, rnti:%04x, frame:%d, subframe:%d, bundling:%d) harq_pdus:%d O_ACK:%d\n", __FUNCTION__, rnti, frame, subframe, bundling,eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs,ulsch_harq->O_ACK); pthread_mutex_lock(&eNB->UL_INFO_mutex); - nfapi_harq_indication_pdu_t *pdu = &eNB->UL_INFO.harq_ind.harq_pdu_list[eNB->UL_INFO.harq_ind.number_of_harqs]; + nfapi_harq_indication_pdu_t *pdu = &eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list[eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs]; int M; int i; + eNB->UL_INFO.harq_ind.header.message_id = NFAPI_HARQ_INDICATION; + eNB->UL_INFO.harq_ind.sfn_sf = frame<<4|subframe; + + eNB->UL_INFO.harq_ind.harq_indication_body.tl.tag = NFAPI_HARQ_INDICATION_BODY_TAG; + pdu->instance_length = 0; // don't know what to do with this // pdu->rx_ue_information.handle = handle; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; pdu->rx_ue_information.rnti = rnti; if (eNB->frame_parms.frame_type == FDD) { + pdu->harq_indication_fdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_FDD_REL13_TAG; pdu->harq_indication_fdd_rel13.mode = 0; pdu->harq_indication_fdd_rel13.number_of_ack_nack = ulsch_harq->O_ACK; @@ -1712,8 +1813,9 @@ void fill_ulsch_harq_indication(PHY_VARS_eNB *eNB,LTE_UL_eNB_HARQ_t *ulsch_harq, M=ul_ACK_subframe2_M(&eNB->frame_parms, subframe); - pdu->harq_indication_fdd_rel13.mode = 1-bundling; - pdu->harq_indication_fdd_rel13.number_of_ack_nack = ulsch_harq->O_ACK; + pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG; + pdu->harq_indication_tdd_rel13.mode = 1-bundling; + pdu->harq_indication_tdd_rel13.number_of_ack_nack = ulsch_harq->O_ACK; for (i=0;iO_ACK;i++) { AssertFatal(ulsch_harq->o_ACK[i] == 0 || ulsch_harq->o_ACK[i] == 1, "harq_ack[%d] is %d, should be 1,2 or 4\n",i,ulsch_harq->o_ACK[i]); @@ -1731,7 +1833,9 @@ void fill_ulsch_harq_indication(PHY_VARS_eNB *eNB,LTE_UL_eNB_HARQ_t *ulsch_harq, } } - eNB->UL_INFO.harq_ind.number_of_harqs++; + //LOG_E(PHY,"eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs:%d\n", eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs); + eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs++; + pthread_mutex_unlock(&eNB->UL_INFO_mutex); } @@ -1744,17 +1848,30 @@ void fill_uci_harq_indication(PHY_VARS_eNB *eNB, uint16_t tdd_multiplexing_mask) { int UE_id=find_dlsch(uci->rnti,eNB,SEARCH_EXIST); - AssertFatal(UE_id>=0,"UE_id doesn't exist\n"); - + //AssertFatal(UE_id>=0,"UE_id doesn't exist rnti:%x\n", uci->rnti); + if (UE_id < 0) { + LOG_E(PHY,"SFN/SF:%04d%d Unable to find rnti:%x do not send HARQ\n", frame, subframe, uci->rnti); + return; + } pthread_mutex_lock(&eNB->UL_INFO_mutex); - nfapi_harq_indication_pdu_t *pdu = &eNB->UL_INFO.harq_ind.harq_pdu_list[eNB->UL_INFO.harq_ind.number_of_harqs]; + nfapi_harq_indication_t *ind = &eNB->UL_INFO.harq_ind; + nfapi_harq_indication_body_t *body = &ind->harq_indication_body; + nfapi_harq_indication_pdu_t *pdu = &body->harq_pdu_list[eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs]; + + ind->sfn_sf = frame<<4|subframe; + ind->header.message_id = NFAPI_HARQ_INDICATION; + + body->tl.tag = NFAPI_HARQ_INDICATION_BODY_TAG; + pdu->instance_length = 0; // don't know what to do with this // pdu->rx_ue_information.handle = handle; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; pdu->rx_ue_information.rnti = uci->rnti; // estimate UL_CQI for MAC (from antenna port 0 only) + pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG; int SNRtimes10 = dB_fixed_times10(uci->stat) - 200;//(10*eNB->measurements.n0_power_dB[0]); if (SNRtimes10 < -100) LOG_I(PHY,"uci->stat %d \n",uci->stat); @@ -1766,6 +1883,7 @@ void fill_uci_harq_indication(PHY_VARS_eNB *eNB, if (eNB->frame_parms.frame_type == FDD) { if (uci->pucch_fmt == pucch_format1a) { + pdu->harq_indication_fdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_FDD_REL13_TAG; pdu->harq_indication_fdd_rel13.mode = 0; pdu->harq_indication_fdd_rel13.number_of_ack_nack = 1; @@ -1784,6 +1902,7 @@ void fill_uci_harq_indication(PHY_VARS_eNB *eNB, #endif } else if (uci->pucch_fmt == pucch_format1b) { + pdu->harq_indication_fdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_FDD_REL13_TAG; pdu->harq_indication_fdd_rel13.mode = 0; pdu->harq_indication_fdd_rel13.number_of_ack_nack = 2; AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[1] == 4, "harq_ack[0] is %d, should be 0,1 or 4\n",harq_ack[0]); @@ -1801,12 +1920,14 @@ void fill_uci_harq_indication(PHY_VARS_eNB *eNB, AssertFatal(tdd_mapping_mode==0 || tdd_mapping_mode==1 || tdd_mapping_mode==2, "Illegal tdd_mapping_mode %d\n",tdd_mapping_mode); + pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG; pdu->harq_indication_tdd_rel13.mode = tdd_mapping_mode; switch (tdd_mapping_mode) { case 0: // bundling if (uci->pucch_fmt == pucch_format1a) { + pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG; pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1; AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[0] == 4, "harq_ack[0] is %d, should be 1,2 or 4\n",harq_ack[0]); pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = harq_ack[0]; @@ -1817,6 +1938,7 @@ void fill_uci_harq_indication(PHY_VARS_eNB *eNB, pdu->harq_indication_tdd_rel13.number_of_ack_nack = 2; AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[1] == 4, "harq_ack[0] is %d, should be 0,1 or 4\n",harq_ack[0]); AssertFatal(harq_ack[1] == 1 || harq_ack[1] == 2 || harq_ack[1] == 4, "harq_ack[1] is %d, should be 0,1 or 4\n",harq_ack[1]); + pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG; pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = harq_ack[0]; pdu->harq_indication_tdd_rel13.harq_data[1].bundling.value_0 = harq_ack[1]; // release all DLSCH if needed @@ -1828,6 +1950,7 @@ void fill_uci_harq_indication(PHY_VARS_eNB *eNB, AssertFatal(uci->pucch_fmt == pucch_format1b,"uci->pucch_format %d is not format1b\n",uci->pucch_fmt); if (uci->num_pucch_resources == 1 && uci->pucch_fmt == pucch_format1a) { + pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG; pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1; AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[0] == 4, "harq_ack[0] is %d, should be 1,2 or 4\n",harq_ack[0]); pdu->harq_indication_tdd_rel13.harq_data[0].multiplex.value_0 = harq_ack[0]; @@ -1835,6 +1958,7 @@ void fill_uci_harq_indication(PHY_VARS_eNB *eNB, if (harq_ack[0] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff); } else if (uci->num_pucch_resources == 1 && uci->pucch_fmt == pucch_format1b) { + pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG; pdu->harq_indication_tdd_rel13.number_of_ack_nack = 2; AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[1] == 4, "harq_ack[0] is %d, should be 0,1 or 4\n",harq_ack[0]); AssertFatal(harq_ack[1] == 1 || harq_ack[1] == 2 || harq_ack[1] == 4, "harq_ack[1] is %d, should be 0,1 or 4\n",harq_ack[1]); @@ -1845,6 +1969,7 @@ void fill_uci_harq_indication(PHY_VARS_eNB *eNB, if (harq_ack[1] == 1) release_harq(eNB,UE_id,1,frame,subframe,0xffff); } else { // num_pucch_resources (M) > 1 + pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG; pdu->harq_indication_tdd_rel13.number_of_ack_nack = uci->num_pucch_resources; pdu->harq_indication_tdd_rel13.harq_data[0].multiplex.value_0 = harq_ack[0]; @@ -1857,6 +1982,7 @@ void fill_uci_harq_indication(PHY_VARS_eNB *eNB, } break; case 2: // special bundling (SR collision) + pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG; pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1; int tdd_config5_sf2scheds=0; if (eNB->frame_parms.tdd_config==5) tdd_config5_sf2scheds = getM(eNB,frame,subframe); @@ -1892,7 +2018,8 @@ void fill_uci_harq_indication(PHY_VARS_eNB *eNB, } //TDD - eNB->UL_INFO.harq_ind.number_of_harqs++; + eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs++; + LOG_D(PHY,"Incremented eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs:%d\n", eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs); pthread_mutex_unlock(&eNB->UL_INFO_mutex); } @@ -1901,14 +2028,23 @@ void fill_uci_harq_indication(PHY_VARS_eNB *eNB, void fill_crc_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe,uint8_t crc_flag) { pthread_mutex_lock(&eNB->UL_INFO_mutex); - nfapi_crc_indication_pdu_t *pdu = &eNB->UL_INFO.crc_ind.crc_pdu_list[eNB->UL_INFO.crc_ind.number_of_crcs]; + nfapi_crc_indication_pdu_t *pdu = &eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list[eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs]; + + eNB->UL_INFO.crc_ind.sfn_sf = frame<<4 | subframe; + eNB->UL_INFO.crc_ind.header.message_id = NFAPI_CRC_INDICATION; + eNB->UL_INFO.crc_ind.crc_indication_body.tl.tag = NFAPI_CRC_INDICATION_BODY_TAG; pdu->instance_length = 0; // don't know what to do with this // pdu->rx_ue_information.handle = handle; + pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; pdu->rx_ue_information.rnti = eNB->ulsch[UE_id]->rnti; + pdu->crc_indication_rel8.tl.tag = NFAPI_CRC_INDICATION_REL8_TAG; pdu->crc_indication_rel8.crc_flag = crc_flag; - eNB->UL_INFO.crc_ind.number_of_crcs++; + eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs++; + + //LOG_D(PHY, "%s() rnti:%04x crcs:%d crc_flag:%d\n", __FUNCTION__, pdu->rx_ue_information.rnti, eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs, crc_flag); + pthread_mutex_unlock(&eNB->UL_INFO_mutex); } @@ -1931,17 +2067,13 @@ void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,const VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 1 ); - LOG_D(PHY,"[eNB %d] Frame %d: Doing phy_procedures_eNB_uespec_RX(%d)\n",eNB->Mod_id,frame, subframe); + //LOG_D(PHY,"[eNB %d] Frame %d: Doing phy_procedures_eNB_uespec_RX(%d)\n",eNB->Mod_id,frame, subframe); eNB->rb_mask_ul[0]=0; eNB->rb_mask_ul[1]=0; eNB->rb_mask_ul[2]=0; eNB->rb_mask_ul[3]=0; - // Fix me here, these should be locked - eNB->UL_INFO.rx_ind.number_of_pdus = 0; - eNB->UL_INFO.crc_ind.number_of_crcs = 0; - // Call SRS first since all others depend on presence of SRS or lack thereof srs_procedures(eNB,proc); @@ -1949,7 +2081,9 @@ void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,const uci_procedures(eNB,proc); - pusch_procedures(eNB,proc); + if (nfapi_mode == 0 || nfapi_mode == 1) { // If PNF or monolithic + pusch_procedures(eNB,proc); + } lte_eNB_I0_measurements(eNB, subframe, @@ -1967,13 +2101,8 @@ void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,const LOG_I(PHY,"max_I0 %d, min_I0 %d\n",max_I0,min_I0); } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 0 ); stop_meas(&eNB->phy_proc_rx); } - - - - diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 6094f52940..869723391e 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -75,7 +75,8 @@ fifo_dump_emos_UE emos_dump_UE; extern double cpuf; - +void Msg1_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); +void Msg3_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); #if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) extern uint32_t downlink_frequency[MAX_NUM_CCs][4]; diff --git a/openair1/SCHED/ru_procedures.c b/openair1/SCHED/ru_procedures.c index e04ef3456e..ce49d72c68 100644 --- a/openair1/SCHED/ru_procedures.c +++ b/openair1/SCHED/ru_procedures.c @@ -74,9 +74,12 @@ void feptx0(RU_t *ru,int slot) { ((fp->Ncp==1) ? 6 : 7); int subframe = ru->proc.subframe_tx; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+slot , 1 ); + slot_offset = subframe*fp->samples_per_tti + (slot*(fp->samples_per_tti>>1)); - // LOG_D(HW,"Frame %d: Generating slot %d\n",frame,next_slot); + //LOG_D(PHY,"SFN/SF:RU:TX:%d/%d Generating slot %d\n",ru->proc.frame_tx, ru->proc.subframe_tx,slot); for (aa=0; aanb_tx; aa++) { if (fp->Ncp == EXTENDED) PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot*slot_sizeF], @@ -132,6 +135,7 @@ void feptx0(RU_t *ru,int slot) { } } } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+slot , 0); } static void *feptx_thread(void *param) { @@ -302,11 +306,11 @@ void feptx_ofdm(RU_t *ru) { } txdata = (int16_t*)&ru->common.txdata[aa][0]; for (j=0; i<(len<<1); i++,j++) { - txdata[j++] = ((int16_t*)dummy_tx_b)[i]; + txdata[j++] = ((int16_t*)dummy_tx_b)[i]; } } else { - LOG_D(PHY,"feptx_ofdm: Writing to position %d\n",slot_offset); + //LOG_D(PHY,"feptx_ofdm: Writing to position %d\n",slot_offset); tx_offset = (int)slot_offset; txdata = (int16_t*)&ru->common.txdata[aa][tx_offset]; @@ -325,9 +329,9 @@ void feptx_ofdm(RU_t *ru) { */ if ((fp->frame_type == TDD) && ((fp->tdd_config==0) || - (fp->tdd_config==1) || - (fp->tdd_config==2) || - (fp->tdd_config==6)) && + (fp->tdd_config==1) || + (fp->tdd_config==2) || + (fp->tdd_config==6)) && ((subframe==0) || (subframe==5))) { // turn on tx switch N_TA_offset before //LOG_D(HW,"subframe %d, time to switch to tx (N_TA_offset %d, slot_offset %d) \n",subframe,ru->N_TA_offset,slot_offset); @@ -363,10 +367,24 @@ void feptx_prec(RU_t *ru) { eNB = eNB_list[0]; fp = &eNB->frame_parms; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC , 1); + + //LOG_D(PHY, "%s() subframe:%d\n", __FUNCTION__, subframe); + + if (0) LOG_E(PHY,"%s() run->nb_tx:%u subframe:%u fp->symbols_per_tti:%u fp->ofdm_symbol_size:%u symbols:(%d, %d), (%d,%d)\n", + __FUNCTION__, ru->nb_tx, subframe, fp->symbols_per_tti, fp->ofdm_symbol_size, + ((short*)&eNB->common_vars.txdataF[0][1])[0], + ((short*)&eNB->common_vars.txdataF[0][1])[1], + ((short*)&eNB->common_vars.txdataF[0][2])[0], + ((short*)&eNB->common_vars.txdataF[0][2])[1] + ); + for (aa=0;aanb_tx;aa++) memcpy((void*)ru->common.txdataF_BF[aa], (void*)&eNB->common_vars.txdataF[aa][subframe*fp->symbols_per_tti*fp->ofdm_symbol_size], fp->symbols_per_tti*fp->ofdm_symbol_size*sizeof(int32_t)); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC , 0); } else { for (i=0;inum_eNB;i++) { @@ -385,9 +403,11 @@ void feptx_prec(RU_t *ru) { aa); } } +#if 0 LOG_D(PHY,"feptx_prec: frame %d, subframe %d: txp (freq) %d dB\n", ru->proc.frame_tx,subframe, dB_fixed(signal_energy_nodc(ru->common.txdataF_BF[0],2*fp->symbols_per_tti*fp->ofdm_symbol_size))); +#endif } } } @@ -400,6 +420,8 @@ void fep0(RU_t *ru,int slot) { // printf("fep0: slot %d\n",slot); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+slot, 1); + remove_7_5_kHz(ru,(slot&1)+(proc->subframe_rx<<1)); for (l=0; lsymbols_per_tti/2; l++) { slot_fep_ul(ru, @@ -408,6 +430,7 @@ void fep0(RU_t *ru,int slot) { 0 ); } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+slot, 0); } @@ -588,4 +611,3 @@ void do_prach_ru(RU_t *ru) { } } - diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index a163b031c9..1699eaad55 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -304,10 +304,14 @@ void *eNB_app_task(void *args_p) itti_mark_task_ready (TASK_ENB_APP); + LOG_I(PHY, "%s() Task ready initialise structures\n", __FUNCTION__); + RCconfig_L1(); RCconfig_macrlc(); + LOG_I(PHY, "%s() RC.nb_L1_inst:%d\n", __FUNCTION__, RC.nb_L1_inst); + if (RC.nb_L1_inst>0) AssertFatal(l1_north_init_eNB()==0,"could not initialize L1 north interface\n"); # if defined(ENABLE_ITTI) @@ -330,9 +334,11 @@ void *eNB_app_task(void *args_p) LOG_I(ENB_APP,"Allocating eNB_RRC_INST for %d instances\n",RC.nb_inst); RC.rrc = (eNB_RRC_INST **)malloc(RC.nb_inst*sizeof(eNB_RRC_INST *)); + LOG_I(PHY, "%s() RC.nb_inst:%d RC.rrc:%p\n", __FUNCTION__, RC.nb_inst, RC.rrc); for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { RC.rrc[enb_id] = (eNB_RRC_INST*)malloc(sizeof(eNB_RRC_INST)); + LOG_I(PHY, "%s() Creating RRC instance RC.rrc[%d]:%p (%d of %d)\n", __FUNCTION__, enb_id, RC.rrc[enb_id], enb_id+1, enb_id_end); memset((void *)RC.rrc[enb_id],0,sizeof(eNB_RRC_INST)); configure_rrc(enb_id); } diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index f2f89ad1ca..01872c0697 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -50,15 +50,16 @@ #include "sctp_default_values.h" #include "SystemInformationBlockType2.h" #include "LAYER2/MAC/extern.h" +#include "LAYER2/MAC/proto.h" #include "PHY/extern.h" #include "targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h" +#include "nfapi_vnf.h" +#include "nfapi_pnf.h" + #include "enb_paramdef.h" #include "common/config/config_userapi.h" - -int RCconfig_RRC(MessageDef *msg_p, uint32_t i, eNB_RRC_INST *rrc); -int RCconfig_S1(MessageDef *msg_p, uint32_t i); - +extern uint16_t sf_ahead; static int enb_check_band_frequencies(char* lib_config_file_name_pP, int ind, @@ -102,11 +103,6 @@ static int enb_check_band_frequencies(char* lib_config_file_name_pP, } - - - - - /* --------------------------------------------------------*/ /* from here function to use configuration module */ void RCconfig_RU(void) { @@ -124,7 +120,6 @@ void RCconfig_RU(void) { if ( RUParamList.numelt > 0) { - RC.ru = (RU_t**)malloc(RC.nb_RU*sizeof(RU_t*)); @@ -139,6 +134,8 @@ void RCconfig_RU(void) { memset((void*)RC.ru[j],0,sizeof(RU_t)); RC.ru[j]->idx = j; + printf("Creating RC.ru[%d]:%p\n", j, RC.ru[j]); + RC.ru[j]->if_timing = synch_to_ext_device; if (RC.nb_L1_inst >0) RC.ru[j]->num_eNB = RUParamList.paramarray[j][RU_ENB_LIST_IDX].numelt; @@ -237,48 +234,47 @@ void RCconfig_RU(void) { } -void RCconfig_L1() { +void RCconfig_L1(void) { int i,j; paramdef_t L1_Params[] = L1PARAMS_DESC; paramlist_def_t L1_ParamList = {CONFIG_STRING_L1_LIST,NULL,0}; + if (RC.eNB == NULL) { + RC.eNB = (PHY_VARS_eNB ***)malloc((1+MAX_NUM_CCs)*sizeof(PHY_VARS_eNB**)); + LOG_I(PHY,"RC.eNB = %p\n",RC.eNB); + memset(RC.eNB,0,(1+NUMBER_OF_eNB_MAX)*sizeof(PHY_VARS_eNB***)); + RC.nb_L1_CC = malloc((1+RC.nb_L1_inst)*sizeof(int)); + } + config_getlist( &L1_ParamList,L1_Params,sizeof(L1_Params)/sizeof(paramdef_t), NULL); if (L1_ParamList.numelt > 0) { - if (RC.eNB == NULL) { - RC.eNB = (PHY_VARS_eNB ***)malloc((1+NUMBER_OF_eNB_MAX)*sizeof(PHY_VARS_eNB***)); - LOG_I(PHY,"RC.eNB = %p\n",RC.eNB); - memset(RC.eNB,0,(1+NUMBER_OF_eNB_MAX)*sizeof(PHY_VARS_eNB***)); - RC.nb_L1_CC = malloc((1+RC.nb_L1_inst)*sizeof(int)); - } - for (j = 0; j < RC.nb_L1_inst; j++) { RC.nb_L1_CC[j] = *(L1_ParamList.paramarray[j][L1_CC_IDX].uptr); - if (RC.eNB[j] == NULL) { RC.eNB[j] = (PHY_VARS_eNB **)malloc((1+MAX_NUM_CCs)*sizeof(PHY_VARS_eNB**)); LOG_I(PHY,"RC.eNB[%d] = %p\n",j,RC.eNB[j]); memset(RC.eNB[j],0,(1+MAX_NUM_CCs)*sizeof(PHY_VARS_eNB***)); } - for (i=0;iMod_id = j; - RC.eNB[j][i]->CC_id = i; - } + if (RC.eNB[j][i] == NULL) { + RC.eNB[j][i] = (PHY_VARS_eNB *)malloc(sizeof(PHY_VARS_eNB)); + memset((void*)RC.eNB[j][i],0,sizeof(PHY_VARS_eNB)); + LOG_I(PHY,"RC.eNB[%d][%d] = %p\n",j,i,RC.eNB[j][i]); + RC.eNB[j][i]->Mod_id = j; + RC.eNB[j][i]->CC_id = i; + } } if (strcmp(*(L1_ParamList.paramarray[j][L1_TRANSPORT_N_PREFERENCE_IDX].strptr), "local_mac") == 0) { + sf_ahead = 4; // Need 4 subframe gap between RX and TX } else if (strcmp(*(L1_ParamList.paramarray[j][L1_TRANSPORT_N_PREFERENCE_IDX].strptr), "nfapi") == 0) { - RC.eNB[j][0]->eth_params_n.local_if_name = strdup(*(L1_ParamList.paramarray[j][L1_LOCAL_N_IF_NAME_IDX].strptr)); + RC.eNB[j][0]->eth_params_n.local_if_name = strdup(*(L1_ParamList.paramarray[j][L1_LOCAL_N_IF_NAME_IDX].strptr)); RC.eNB[j][0]->eth_params_n.my_addr = strdup(*(L1_ParamList.paramarray[j][L1_LOCAL_N_ADDRESS_IDX].strptr)); RC.eNB[j][0]->eth_params_n.remote_addr = strdup(*(L1_ParamList.paramarray[j][L1_REMOTE_N_ADDRESS_IDX].strptr)); RC.eNB[j][0]->eth_params_n.my_portc = *(L1_ParamList.paramarray[j][L1_LOCAL_N_PORTC_IDX].iptr); @@ -286,8 +282,25 @@ void RCconfig_L1() { RC.eNB[j][0]->eth_params_n.my_portd = *(L1_ParamList.paramarray[j][L1_LOCAL_N_PORTD_IDX].iptr); RC.eNB[j][0]->eth_params_n.remote_portd = *(L1_ParamList.paramarray[j][L1_REMOTE_N_PORTD_IDX].iptr); RC.eNB[j][0]->eth_params_n.transp_preference = ETH_UDP_MODE; + + sf_ahead = 2; // Cannot cope with 4 subframes betweem RX and TX - set it to 2 + + RC.nb_macrlc_inst = 1; // This is used by mac_top_init_eNB() + + // This is used by init_eNB_afterRU() + RC.nb_CC = (int *)malloc((1+RC.nb_inst)*sizeof(int)); + RC.nb_CC[0]=1; + + RC.nb_inst =1; // DJP - feptx_prec uses num_eNB but phy_init_RU uses nb_inst + + LOG_I(PHY,"%s() NFAPI PNF mode - RC.nb_inst=1 this is because phy_init_RU() uses that to index and not RC.num_eNB - why the 2 similar variables?\n", __FUNCTION__); + LOG_I(PHY,"%s() NFAPI PNF mode - RC.nb_CC[0]=%d for init_eNB_afterRU()\n", __FUNCTION__, RC.nb_CC[0]); + LOG_I(PHY,"%s() NFAPI PNF mode - RC.nb_macrlc_inst:%d because used by mac_top_init_eNB()\n", __FUNCTION__, RC.nb_macrlc_inst); + + mac_top_init_eNB(); + + configure_nfapi_pnf(RC.eNB[j][0]->eth_params_n.remote_addr, RC.eNB[j][0]->eth_params_n.remote_portc, RC.eNB[j][0]->eth_params_n.my_addr, RC.eNB[j][0]->eth_params_n.my_portd, RC.eNB[j][0]->eth_params_n .remote_portd); } - else { // other midhaul } }// j=0..num_inst @@ -295,6 +308,30 @@ void RCconfig_L1() { l1_north_init_eNB(); } else { LOG_I(PHY,"No " CONFIG_STRING_L1_LIST " configuration found"); + + // DJP need to create some structures for VNF + + j = 0; + + RC.nb_L1_CC = malloc((1+RC.nb_L1_inst)*sizeof(int)); // DJP - 1 lot then??? + + RC.nb_L1_CC[j]=1; // DJP - hmmm + + if (RC.eNB[j] == NULL) { + RC.eNB[j] = (PHY_VARS_eNB **)malloc((1+MAX_NUM_CCs)*sizeof(PHY_VARS_eNB**)); + LOG_I(PHY,"RC.eNB[%d] = %p\n",j,RC.eNB[j]); + memset(RC.eNB[j],0,(1+MAX_NUM_CCs)*sizeof(PHY_VARS_eNB***)); + } + + for (i=0;iMod_id = j; + RC.eNB[j][i]->CC_id = i; + } + } } } @@ -307,7 +344,6 @@ void RCconfig_macrlc() { config_getlist( &MacRLC_ParamList,MacRLC_Params,sizeof(MacRLC_Params)/sizeof(paramdef_t), NULL); - if ( MacRLC_ParamList.numelt > 0) { RC.nb_macrlc_inst=MacRLC_ParamList.numelt; @@ -342,6 +378,12 @@ void RCconfig_macrlc() { RC.mac[j]->eth_params_s.my_portd = *(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_PORTD_IDX].iptr); RC.mac[j]->eth_params_s.remote_portd = *(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_PORTD_IDX].iptr); RC.mac[j]->eth_params_s.transp_preference = ETH_UDP_MODE; + + sf_ahead = 2; // Cannot cope with 4 subframes betweem RX and TX - set it to 2 + + printf("**************** vnf_port:%d\n", RC.mac[j]->eth_params_s.my_portc); + configure_nfapi_vnf(RC.mac[j]->eth_params_s.my_addr, RC.mac[j]->eth_params_s.my_portc); + printf("**************** RETURNED FROM configure_nfapi_vnf() vnf_port:%d\n", RC.mac[j]->eth_params_s.my_portc); } else { // other midhaul AssertFatal(1==0,"MACRLC %d: %s unknown southbound midhaul\n",j,*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr)); } @@ -424,7 +466,7 @@ int RCconfig_RRC(MessageDef *msg_p, uint32_t i, eNB_RRC_INST *rrc) { int32_t rach_powerRampingStep = 0; int32_t rach_preambleInitialReceivedTargetPower = 0; int32_t rach_preambleTransMax = 0; - int32_t rach_raResponseWindowSize = 0; + int32_t rach_raResponseWindowSize = 10; int32_t rach_macContentionResolutionTimer = 0; int32_t rach_maxHARQ_Msg3Tx = 0; int32_t pcch_defaultPagingCycle = 0; diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index 764c762f6a..1aa3a85636 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -58,6 +58,12 @@ #endif extern RAN_CONTEXT_t RC; +extern int l2_init_eNB(void); +extern void mac_top_init_eNB(void); +extern void mac_init_cell_params(int Mod_idP,int CC_idP); +extern void phy_reset_ue(module_id_t Mod_id,uint8_t CC_id,uint8_t eNB_index); + +extern uint8_t nfapi_mode; /* sec 5.9, 36.321: MAC Reset Procedure */ void ue_mac_reset(module_id_t module_idP, uint8_t eNB_index) @@ -212,51 +218,115 @@ int32_t get_uldl_offset(int eutra_bandP) return (eutra_bandtable[i].dl_min - eutra_bandtable[i].ul_min); } -uint32_t bw_table[6] = - { 6 * 180, 15 * 180, 25 * 180, 50 * 180, 75 * 180, 100 * 180 }; +uint32_t bw_table[6] = {6*180,15*180,25*180,50*180,75*180,100*180}; -void -config_mib(int Mod_idP, - int CC_idP, - int eutra_bandP, - int dl_BandwidthP, - PHICH_Config_t * phich_configP, - int Nid_cellP, - int NcpP, - int p_eNBP, - uint32_t dl_CarrierFreqP, - uint32_t ul_CarrierFreqP, uint32_t pbch_repetitionP) -{ +void config_mib(int Mod_idP, + int CC_idP, + int eutra_bandP, + int dl_BandwidthP, + PHICH_Config_t *phich_configP, + int Nid_cellP, + int NcpP, + int p_eNBP, + uint32_t dl_CarrierFreqP, + uint32_t ul_CarrierFreqP, + uint32_t pbch_repetitionP) { - nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; + nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; - cfg->subframe_config.pcfich_power_offset.value = 6000; // 0dB - cfg->subframe_config.dl_cyclic_prefix_type.value = NcpP; - cfg->subframe_config.ul_cyclic_prefix_type.value = NcpP; + cfg->num_tlv=0; + + cfg->subframe_config.pcfich_power_offset.value = 6000; // 0dB + cfg->subframe_config.pcfich_power_offset.tl.tag = NFAPI_SUBFRAME_CONFIG_PCFICH_POWER_OFFSET_TAG; + cfg->num_tlv++; - LOG_I(MAC, "Ncp %d,p_eNB %d\n", NcpP, p_eNBP); + cfg->subframe_config.dl_cyclic_prefix_type.value = NcpP; + cfg->subframe_config.dl_cyclic_prefix_type.tl.tag = NFAPI_SUBFRAME_CONFIG_DL_CYCLIC_PREFIX_TYPE_TAG; + cfg->num_tlv++; - cfg->rf_config.dl_channel_bandwidth.value = dl_BandwidthP; - cfg->rf_config.ul_channel_bandwidth.value = dl_BandwidthP; - cfg->rf_config.tx_antenna_ports.value = p_eNBP; - cfg->rf_config.rx_antenna_ports.value = 2; + cfg->subframe_config.ul_cyclic_prefix_type.value = NcpP; + cfg->subframe_config.ul_cyclic_prefix_type.tl.tag = NFAPI_SUBFRAME_CONFIG_UL_CYCLIC_PREFIX_TYPE_TAG; + cfg->num_tlv++; + + cfg->rf_config.dl_channel_bandwidth.value = to_prb(dl_BandwidthP); + cfg->rf_config.dl_channel_bandwidth.tl.tag = NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG; + cfg->num_tlv++; +LOG_E(PHY,"%s() dl_BandwidthP:%d\n", __FUNCTION__, dl_BandwidthP); - cfg->nfapi_config.earfcn.value = - to_earfcn(eutra_bandP, dl_CarrierFreqP, - bw_table[dl_BandwidthP] / 100); - cfg->nfapi_config.rf_bands.number_rf_bands = 1; - cfg->nfapi_config.rf_bands.rf_band[0] = eutra_bandP; - cfg->phich_config.phich_resource.value = phich_configP->phich_Resource; - cfg->phich_config.phich_duration.value = phich_configP->phich_Duration; - cfg->phich_config.phich_power_offset.value = 6000; // 0dB + cfg->rf_config.ul_channel_bandwidth.value = to_prb(dl_BandwidthP); + cfg->rf_config.ul_channel_bandwidth.tl.tag = NFAPI_RF_CONFIG_UL_CHANNEL_BANDWIDTH_TAG; + cfg->num_tlv++; - cfg->sch_config.primary_synchronization_signal_epre_eprers.value = 6000; // 0dB - cfg->sch_config.secondary_synchronization_signal_epre_eprers.value = 6000; // 0dB - cfg->sch_config.physical_cell_id.value = Nid_cellP; + cfg->rf_config.tx_antenna_ports.value = p_eNBP; + cfg->rf_config.tx_antenna_ports.tl.tag = NFAPI_RF_CONFIG_TX_ANTENNA_PORTS_TAG; + cfg->num_tlv++; + + cfg->rf_config.rx_antenna_ports.value = 2; + cfg->rf_config.rx_antenna_ports.tl.tag = NFAPI_RF_CONFIG_RX_ANTENNA_PORTS_TAG; + cfg->num_tlv++; + + cfg->nfapi_config.earfcn.value = to_earfcn(eutra_bandP,dl_CarrierFreqP,bw_table[dl_BandwidthP]/100); + cfg->nfapi_config.earfcn.tl.tag = NFAPI_NFAPI_EARFCN_TAG; + cfg->num_tlv++; + + cfg->nfapi_config.rf_bands.number_rf_bands = 1; + cfg->nfapi_config.rf_bands.rf_band[0] = eutra_bandP; + cfg->nfapi_config.rf_bands.tl.tag = NFAPI_PHY_RF_BANDS_TAG; + cfg->num_tlv++; + + cfg->phich_config.phich_resource.value = phich_configP->phich_Resource; + cfg->phich_config.phich_resource.tl.tag = NFAPI_PHICH_CONFIG_PHICH_RESOURCE_TAG; + cfg->num_tlv++; + + cfg->phich_config.phich_duration.value = phich_configP->phich_Duration; + cfg->phich_config.phich_duration.tl.tag = NFAPI_PHICH_CONFIG_PHICH_DURATION_TAG; + cfg->num_tlv++; + + cfg->phich_config.phich_power_offset.value = 6000; // 0dB + cfg->phich_config.phich_power_offset.tl.tag = NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG; + cfg->num_tlv++; + + cfg->sch_config.primary_synchronization_signal_epre_eprers.value = 6000; // 0dB + cfg->sch_config.primary_synchronization_signal_epre_eprers.tl.tag = NFAPI_SCH_CONFIG_PRIMARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG; + cfg->num_tlv++; + + cfg->sch_config.secondary_synchronization_signal_epre_eprers.value = 6000; // 0dB + cfg->sch_config.secondary_synchronization_signal_epre_eprers.tl.tag = NFAPI_SCH_CONFIG_SECONDARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG; + cfg->num_tlv++; + + cfg->sch_config.physical_cell_id.value = Nid_cellP; + cfg->sch_config.physical_cell_id.tl.tag = NFAPI_SCH_CONFIG_PHYSICAL_CELL_ID_TAG; + cfg->num_tlv++; #ifdef Rel14 - cfg->emtc_config.pbch_repetitions_enable_r13.value = pbch_repetitionP; -#endif + cfg->emtc_config.pbch_repetitions_enable_r13.value = pbch_repetitionP; + cfg->emtc_config.pbch_repetitions_enable_r13.tl.tag = NFAPI_EMTC_CONFIG_PBCH_REPETITIONS_ENABLE_R13_TAG; + cfg->num_tlv++; +#endif + + LOG_I(MAC, + "%s() NFAPI_CONFIG_REQUEST(num_tlv:%u) DL_BW:%u UL_BW:%u Ncp %d,p_eNB %d,earfcn %d,band %d,phich_resource %u phich_duration %u phich_power_offset %u PSS %d SSS %d PCI %d" +#ifdef Rel14 + " PBCH repetition %d" +#endif + "\n" + ,__FUNCTION__ + ,cfg->num_tlv + ,cfg->rf_config.dl_channel_bandwidth.value + ,cfg->rf_config.ul_channel_bandwidth.value + ,NcpP,p_eNBP + ,cfg->nfapi_config.earfcn.value + ,cfg->nfapi_config.rf_bands.rf_band[0] + ,cfg->phich_config.phich_resource.value + ,cfg->phich_config.phich_duration.value + ,cfg->phich_config.phich_power_offset.value + ,cfg->sch_config.primary_synchronization_signal_epre_eprers.value + ,cfg->sch_config.secondary_synchronization_signal_epre_eprers.value + ,cfg->sch_config.physical_cell_id.value +#ifdef Rel14 + ,cfg->emtc_config.pbch_repetitions_enable_r13.value +#endif + ); } void config_sib1(int Mod_idP, int CC_idP, TDD_Config_t * tdd_ConfigP) @@ -264,18 +334,25 @@ void config_sib1(int Mod_idP, int CC_idP, TDD_Config_t * tdd_ConfigP) nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; - if (tdd_ConfigP) { //TDD - cfg->subframe_config.duplex_mode.value = 0; - cfg->tdd_frame_structure_config.subframe_assignment.value = - tdd_ConfigP->subframeAssignment; - cfg->tdd_frame_structure_config.special_subframe_patterns.value = - tdd_ConfigP->specialSubframePatterns; - } else { // FDD - cfg->subframe_config.duplex_mode.value = 1; - // Note no half-duplex here - } + if (tdd_ConfigP) { //TDD + cfg->subframe_config.duplex_mode.value = 0; + cfg->subframe_config.duplex_mode.tl.tag = NFAPI_SUBFRAME_CONFIG_DUPLEX_MODE_TAG; + cfg->num_tlv++; + cfg->tdd_frame_structure_config.subframe_assignment.value = tdd_ConfigP->subframeAssignment; + cfg->tdd_frame_structure_config.subframe_assignment.tl.tag = NFAPI_TDD_FRAME_STRUCTURE_SUBFRAME_ASSIGNMENT_TAG; + cfg->num_tlv++; + cfg->tdd_frame_structure_config.special_subframe_patterns.value = tdd_ConfigP->specialSubframePatterns; + cfg->tdd_frame_structure_config.special_subframe_patterns.tl.tag = NFAPI_TDD_FRAME_STRUCTURE_SPECIAL_SUBFRAME_PATTERNS_TAG; + cfg->num_tlv++; + } + else { // FDD + cfg->subframe_config.duplex_mode.value = 1; + cfg->subframe_config.duplex_mode.tl.tag = NFAPI_SUBFRAME_CONFIG_DUPLEX_MODE_TAG; + cfg->num_tlv++; + // Note no half-duplex here + } } int power_off_dB[6] = { 78, 118, 140, 170, 188, 200 }; @@ -287,248 +364,326 @@ config_sib2(int Mod_idP, #ifdef Rel14 RadioResourceConfigCommonSIB_t * radioResourceConfigCommon_BRP, #endif - ARFCN_ValueEUTRA_t * ul_CArrierFreqP, - long *ul_BandwidthP, - AdditionalSpectrumEmission_t * - additionalSpectrumEmissionP, - struct MBSFN_SubframeConfigList *mbsfn_SubframeConfigListP) -{ + ARFCN_ValueEUTRA_t *ul_CArrierFreqP, + long *ul_BandwidthP, + AdditionalSpectrumEmission_t *additionalSpectrumEmissionP, + struct MBSFN_SubframeConfigList *mbsfn_SubframeConfigListP) { - nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; + nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; - cfg->subframe_config.pb.value = - radioResourceConfigCommonP->pdsch_ConfigCommon.p_b; - cfg->rf_config.reference_signal_power.value = - radioResourceConfigCommonP->pdsch_ConfigCommon. - referenceSignalPower; - cfg->nfapi_config.max_transmit_power.value = - cfg->rf_config.reference_signal_power.value + - power_off_dB[cfg->rf_config.dl_channel_bandwidth.value]; + cfg->subframe_config.pb.value = radioResourceConfigCommonP->pdsch_ConfigCommon.p_b; + cfg->subframe_config.pb.tl.tag = NFAPI_SUBFRAME_CONFIG_PB_TAG; + cfg->num_tlv++; - cfg->prach_config.configuration_index.value = - radioResourceConfigCommonP->prach_Config. - prach_ConfigInfo.prach_ConfigIndex; - cfg->prach_config.root_sequence_index.value = - radioResourceConfigCommonP->prach_Config.rootSequenceIndex; - cfg->prach_config.zero_correlation_zone_configuration.value = - radioResourceConfigCommonP->prach_Config. - prach_ConfigInfo.zeroCorrelationZoneConfig; - cfg->prach_config.high_speed_flag.value = - radioResourceConfigCommonP->prach_Config.prach_ConfigInfo. - highSpeedFlag; - cfg->prach_config.frequency_offset.value = - radioResourceConfigCommonP->prach_Config. - prach_ConfigInfo.prach_FreqOffset; + cfg->rf_config.reference_signal_power.value = radioResourceConfigCommonP->pdsch_ConfigCommon.referenceSignalPower; + cfg->rf_config.reference_signal_power.tl.tag = NFAPI_RF_CONFIG_REFERENCE_SIGNAL_POWER_TAG; + cfg->num_tlv++; - cfg->pusch_config.hopping_mode.value = - radioResourceConfigCommonP->pusch_ConfigCommon. - pusch_ConfigBasic.hoppingMode; - cfg->pusch_config.number_of_subbands.value = - radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic. - n_SB; - cfg->pusch_config.hopping_offset.value = - radioResourceConfigCommonP->pusch_ConfigCommon. - pusch_ConfigBasic.pusch_HoppingOffset; + cfg->nfapi_config.max_transmit_power.value = cfg->rf_config.reference_signal_power.value + power_off_dB[cfg->rf_config.dl_channel_bandwidth.value]; + cfg->nfapi_config.max_transmit_power.tl.tag = NFAPI_NFAPI_MAXIMUM_TRANSMIT_POWER_TAG; + cfg->num_tlv++; + + cfg->prach_config.configuration_index.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.prach_ConfigIndex; + cfg->prach_config.configuration_index.tl.tag = NFAPI_PRACH_CONFIG_CONFIGURATION_INDEX_TAG; + cfg->num_tlv++; + + cfg->prach_config.root_sequence_index.value = radioResourceConfigCommonP->prach_Config.rootSequenceIndex; + cfg->prach_config.root_sequence_index.tl.tag = NFAPI_PRACH_CONFIG_ROOT_SEQUENCE_INDEX_TAG; + cfg->num_tlv++; + + cfg->prach_config.zero_correlation_zone_configuration.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig; + cfg->prach_config.zero_correlation_zone_configuration.tl.tag = NFAPI_PRACH_CONFIG_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG; + cfg->num_tlv++; + + cfg->prach_config.high_speed_flag.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.highSpeedFlag; + cfg->prach_config.high_speed_flag.tl.tag = NFAPI_PRACH_CONFIG_HIGH_SPEED_FLAG_TAG; + cfg->num_tlv++; + + cfg->prach_config.frequency_offset.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.prach_FreqOffset; + cfg->prach_config.frequency_offset.tl.tag = NFAPI_PRACH_CONFIG_FREQUENCY_OFFSET_TAG; + cfg->num_tlv++; + cfg->pusch_config.hopping_mode.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode; + cfg->pusch_config.hopping_mode.tl.tag = NFAPI_PUSCH_CONFIG_HOPPING_MODE_TAG; + cfg->num_tlv++; - cfg->pucch_config.delta_pucch_shift.value = - radioResourceConfigCommonP->pucch_ConfigCommon.deltaPUCCH_Shift; - cfg->pucch_config.n_cqi_rb.value = - radioResourceConfigCommonP->pucch_ConfigCommon.nRB_CQI; - cfg->pucch_config.n_an_cs.value = - radioResourceConfigCommonP->pucch_ConfigCommon.nCS_AN; - cfg->pucch_config.n1_pucch_an.value = - radioResourceConfigCommonP->pucch_ConfigCommon.n1PUCCH_AN; + cfg->pusch_config.number_of_subbands.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.n_SB; + cfg->pusch_config.number_of_subbands.tl.tag = NFAPI_PUSCH_CONFIG_NUMBER_OF_SUBBANDS_TAG; + cfg->num_tlv++; - if (radioResourceConfigCommonP-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled == - true) - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 1; - else if (radioResourceConfigCommonP-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. - sequenceHoppingEnabled == true) - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 2; - else // No hopping - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 0; + cfg->pusch_config.hopping_offset.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset; + cfg->pusch_config.hopping_offset.tl.tag = NFAPI_PUSCH_CONFIG_HOPPING_OFFSET_TAG; + cfg->num_tlv++; - cfg->uplink_reference_signal_config.group_assignment.value = - radioResourceConfigCommonP-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH; - cfg->uplink_reference_signal_config.cyclic_shift_1_for_drms.value = - radioResourceConfigCommonP-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift; + cfg->pucch_config.delta_pucch_shift.value = radioResourceConfigCommonP->pucch_ConfigCommon.deltaPUCCH_Shift; + cfg->pucch_config.delta_pucch_shift.tl.tag = NFAPI_PUCCH_CONFIG_DELTA_PUCCH_SHIFT_TAG; + cfg->num_tlv++; - // how to enable/disable SRS? - if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.present == - SoundingRS_UL_ConfigCommon_PR_setup) { - cfg->srs_config.bandwidth_configuration.value = - radioResourceConfigCommonP->soundingRS_UL_ConfigCommon. - choice.setup.srs_BandwidthConfig; - cfg->srs_config.srs_subframe_configuration.value = - radioResourceConfigCommonP->soundingRS_UL_ConfigCommon. - choice.setup.srs_SubframeConfig; - cfg->srs_config.srs_acknack_srs_simultaneous_transmission.value = - radioResourceConfigCommonP->soundingRS_UL_ConfigCommon. - choice.setup.ackNackSRS_SimultaneousTransmission; + cfg->pucch_config.n_cqi_rb.value = radioResourceConfigCommonP->pucch_ConfigCommon.nRB_CQI; + cfg->pucch_config.n_cqi_rb.tl.tag = NFAPI_PUCCH_CONFIG_N_CQI_RB_TAG; + cfg->num_tlv++; - if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon. - choice.setup.srs_MaxUpPts) - cfg->srs_config.max_up_pts.value = 1; - else - cfg->srs_config.max_up_pts.value = 0; + cfg->pucch_config.n_an_cs.value = radioResourceConfigCommonP->pucch_ConfigCommon.nCS_AN; + cfg->pucch_config.n_an_cs.tl.tag = NFAPI_PUCCH_CONFIG_N_AN_CS_TAG; + cfg->num_tlv++; + + cfg->pucch_config.n1_pucch_an.value = radioResourceConfigCommonP->pucch_ConfigCommon.n1PUCCH_AN; + cfg->pucch_config.n1_pucch_an.tl.tag = NFAPI_PUCCH_CONFIG_N1_PUCCH_AN_TAG; + cfg->num_tlv++; + + if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled == true) + { + cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 1; + } + else if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled == true) + { + cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 2; + } + else // No hopping + { + cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 0; + } + cfg->uplink_reference_signal_config.uplink_rs_hopping.tl.tag = NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_UPLINK_RS_HOPPING_TAG; + cfg->num_tlv++; + + cfg->uplink_reference_signal_config.group_assignment.value = radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH; + cfg->uplink_reference_signal_config.group_assignment.tl.tag = NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_GROUP_ASSIGNMENT_TAG; + cfg->num_tlv++; + + cfg->uplink_reference_signal_config.cyclic_shift_1_for_drms.value = radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift; + cfg->uplink_reference_signal_config.cyclic_shift_1_for_drms.tl.tag = NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_CYCLIC_SHIFT_1_FOR_DRMS_TAG; + cfg->num_tlv++; + + + // how to enable/disable SRS? + if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.present==SoundingRS_UL_ConfigCommon_PR_setup) { + cfg->srs_config.bandwidth_configuration.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_BandwidthConfig; + cfg->srs_config.bandwidth_configuration.tl.tag = NFAPI_SRS_CONFIG_BANDWIDTH_CONFIGURATION_TAG; + cfg->num_tlv++; + + cfg->srs_config.srs_subframe_configuration.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig; + cfg->srs_config.srs_subframe_configuration.tl.tag = NFAPI_SRS_CONFIG_SRS_SUBFRAME_CONFIGURATION_TAG; + cfg->num_tlv++; + + cfg->srs_config.srs_acknack_srs_simultaneous_transmission.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; + cfg->srs_config.srs_acknack_srs_simultaneous_transmission.tl.tag = NFAPI_SRS_CONFIG_SRS_ACKNACK_SRS_SIMULTANEOUS_TRANSMISSION_TAG; + cfg->num_tlv++; + + + if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts) { + cfg->srs_config.max_up_pts.value = 1; } + else { + cfg->srs_config.max_up_pts.value = 0; + } + cfg->srs_config.max_up_pts.tl.tag = NFAPI_SRS_CONFIG_MAX_UP_PTS_TAG; + cfg->num_tlv++; + } + #ifdef Rel14 - if (RC.mac[Mod_idP]->common_channels[CC_idP].mib-> - message.schedulingInfoSIB1_BR_r13 > 0) { - AssertFatal(radioResourceConfigCommon_BRP != NULL, - "radioResource rou is missing\n"); - AssertFatal(radioResourceConfigCommon_BRP->ext4 != NULL, - "ext4 is missing\n"); - cfg->emtc_config.prach_catm_root_sequence_index.value = - radioResourceConfigCommon_BRP->prach_Config.rootSequenceIndex; - cfg->emtc_config.prach_catm_zero_correlation_zone_configuration. - value = - radioResourceConfigCommon_BRP->prach_Config. - prach_ConfigInfo.zeroCorrelationZoneConfig; - cfg->emtc_config.prach_catm_high_speed_flag.value = - radioResourceConfigCommon_BRP->prach_Config. - prach_ConfigInfo.highSpeedFlag; + if (RC.mac[Mod_idP]->common_channels[CC_idP].mib->message.schedulingInfoSIB1_BR_r13>0) { + AssertFatal(radioResourceConfigCommon_BRP!=NULL,"radioResource rou is missing\n"); + AssertFatal(radioResourceConfigCommon_BRP->ext4!=NULL,"ext4 is missing\n"); + cfg->emtc_config.prach_catm_root_sequence_index.value = radioResourceConfigCommon_BRP->prach_Config.rootSequenceIndex; + cfg->emtc_config.prach_catm_root_sequence_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CATM_ROOT_SEQUENCE_INDEX_TAG; + cfg->num_tlv++; - struct PRACH_ConfigSIB_v1310 *ext4_prach = - radioResourceConfigCommon_BRP->ext4->prach_ConfigCommon_v1310; + cfg->emtc_config.prach_catm_zero_correlation_zone_configuration.value = radioResourceConfigCommon_BRP->prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig; + cfg->emtc_config.prach_catm_zero_correlation_zone_configuration.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CATM_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG; + cfg->num_tlv++; - PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13 = - &ext4_prach->prach_ParametersListCE_r13; + cfg->emtc_config.prach_catm_high_speed_flag.value = radioResourceConfigCommon_BRP->prach_Config.prach_ConfigInfo.highSpeedFlag; + cfg->emtc_config.prach_catm_high_speed_flag.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CATM_HIGH_SPEED_FLAG; + cfg->num_tlv++; + + struct PRACH_ConfigSIB_v1310 *ext4_prach=radioResourceConfigCommon_BRP->ext4->prach_ConfigCommon_v1310; - PRACH_ParametersCE_r13_t *p; - cfg->emtc_config.prach_ce_level_0_enable.value = 0; - cfg->emtc_config.prach_ce_level_1_enable.value = 0; - cfg->emtc_config.prach_ce_level_2_enable.value = 0; - cfg->emtc_config.prach_ce_level_3_enable.value = 0; - switch (prach_ParametersListCE_r13->list.count) { - case 4: - p = prach_ParametersListCE_r13->list.array[3]; - cfg->emtc_config.prach_ce_level_3_enable.value = 1; - cfg->emtc_config.prach_ce_level_3_configuration_index.value = - p->prach_ConfigIndex_r13; - cfg->emtc_config.prach_ce_level_3_frequency_offset.value = - p->prach_FreqOffset_r13; - cfg-> - emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt. - value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) - cfg-> - emtc_config.prach_ce_level_3_starting_subframe_periodicity. - value = *p->prach_StartingSubframe_r13; - cfg->emtc_config.prach_ce_level_3_hopping_enable.value = - p->prach_HoppingConfig_r13; - cfg->emtc_config.prach_ce_level_3_hopping_offset.value = - cfg->rf_config.ul_channel_bandwidth.value - 6; - case 3: - p = prach_ParametersListCE_r13->list.array[2]; - cfg->emtc_config.prach_ce_level_2_enable.value = 1; - cfg->emtc_config.prach_ce_level_2_configuration_index.value = - p->prach_ConfigIndex_r13; - cfg->emtc_config.prach_ce_level_2_frequency_offset.value = - p->prach_FreqOffset_r13; - cfg-> - emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt. - value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) - cfg-> - emtc_config.prach_ce_level_2_starting_subframe_periodicity. - value = *p->prach_StartingSubframe_r13; - cfg->emtc_config.prach_ce_level_2_hopping_enable.value = - p->prach_HoppingConfig_r13; - cfg->emtc_config.prach_ce_level_2_hopping_offset.value = - cfg->rf_config.ul_channel_bandwidth.value - 6; - case 2: - p = prach_ParametersListCE_r13->list.array[1]; - cfg->emtc_config.prach_ce_level_1_enable.value = 1; - cfg->emtc_config.prach_ce_level_1_configuration_index.value = - p->prach_ConfigIndex_r13; - cfg->emtc_config.prach_ce_level_1_frequency_offset.value = - p->prach_FreqOffset_r13; - cfg-> - emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt. - value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) - cfg-> - emtc_config.prach_ce_level_1_starting_subframe_periodicity. - value = *p->prach_StartingSubframe_r13; - cfg->emtc_config.prach_ce_level_1_hopping_enable.value = - p->prach_HoppingConfig_r13; - cfg->emtc_config.prach_ce_level_1_hopping_offset.value = - cfg->rf_config.ul_channel_bandwidth.value - 6; - case 1: - p = prach_ParametersListCE_r13->list.array[0]; - cfg->emtc_config.prach_ce_level_0_enable.value = 1; - cfg->emtc_config.prach_ce_level_0_configuration_index.value = - p->prach_ConfigIndex_r13; - cfg->emtc_config.prach_ce_level_0_frequency_offset.value = - p->prach_FreqOffset_r13; - cfg-> - emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt. - value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) - cfg-> - emtc_config.prach_ce_level_0_starting_subframe_periodicity. - value = *p->prach_StartingSubframe_r13; - cfg->emtc_config.prach_ce_level_0_hopping_enable.value = - p->prach_HoppingConfig_r13; - cfg->emtc_config.prach_ce_level_0_hopping_offset.value = - cfg->rf_config.ul_channel_bandwidth.value - 6; - } + PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13; - struct FreqHoppingParameters_r13 *ext4_freqHoppingParameters = - radioResourceConfigCommonP->ext4->freqHoppingParameters_r13; - if ((ext4_freqHoppingParameters) - && - (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13)) - { - switch - (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13-> - present) { - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_NOTHING: /* No components present */ - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_FDD_r13: - cfg->emtc_config. - pucch_interval_ulhoppingconfigcommonmodea.value = - ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13-> - choice.interval_FDD_r13; - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_TDD_r13: - cfg->emtc_config. - pucch_interval_ulhoppingconfigcommonmodea.value = - ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13-> - choice.interval_TDD_r13; - break; - } - } - if ((ext4_freqHoppingParameters) && - (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13)) - { - switch - (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> - present) { - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_NOTHING: /* No components present */ - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_FDD_r13: - cfg->emtc_config. - pucch_interval_ulhoppingconfigcommonmodeb.value = - ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> - choice.interval_FDD_r13; - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_TDD_r13: - cfg->emtc_config. - pucch_interval_ulhoppingconfigcommonmodeb.value = - ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> - choice.interval_TDD_r13; - break; - } - } + PRACH_ParametersCE_r13_t *p; + cfg->emtc_config.prach_ce_level_0_enable.value=0; + cfg->emtc_config.prach_ce_level_0_enable.tl.tag=NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_ENABLE_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_1_enable.value=0; + cfg->emtc_config.prach_ce_level_1_enable.tl.tag=NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_ENABLE_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_2_enable.value=0; + cfg->emtc_config.prach_ce_level_2_enable.tl.tag=NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_ENABLE_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_3_enable.value=0; + cfg->emtc_config.prach_ce_level_3_enable.tl.tag=NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_ENABLE_TAG; + cfg->num_tlv++; + + switch (prach_ParametersListCE_r13->list.count) { + case 4: + p=prach_ParametersListCE_r13->list.array[3]; + cfg->emtc_config.prach_ce_level_3_enable.value = 1; + cfg->emtc_config.prach_ce_level_3_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_ENABLE_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_3_configuration_index.value = p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_3_configuration_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_CONFIGURATION_INDEX_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_3_frequency_offset.value = p->prach_FreqOffset_r13; + cfg->emtc_config.prach_ce_level_3_frequency_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_FREQUENCY_OFFSET_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; + cfg->emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + cfg->num_tlv++; + + if (p->prach_StartingSubframe_r13) { + cfg->emtc_config.prach_ce_level_3_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_3_starting_subframe_periodicity.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_STARTING_SUBFRAME_PERIODICITY_TAG; + cfg->num_tlv++; + } + + cfg->emtc_config.prach_ce_level_3_hopping_enable.value = p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_3_hopping_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_ENABLE_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_3_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value-6; + cfg->emtc_config.prach_ce_level_3_hopping_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_OFFSET_TAG; + cfg->num_tlv++; + + case 3: + p=prach_ParametersListCE_r13->list.array[2]; + cfg->emtc_config.prach_ce_level_2_enable.value = 1; + cfg->emtc_config.prach_ce_level_2_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_ENABLE_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_2_configuration_index.value = p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_2_configuration_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_CONFIGURATION_INDEX_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_2_frequency_offset.value = p->prach_FreqOffset_r13; + cfg->emtc_config.prach_ce_level_2_frequency_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_FREQUENCY_OFFSET_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; + cfg->emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + cfg->num_tlv++; + + if (p->prach_StartingSubframe_r13) { + cfg->emtc_config.prach_ce_level_2_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_2_starting_subframe_periodicity.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_STARTING_SUBFRAME_PERIODICITY_TAG; + cfg->num_tlv++; + } + + cfg->emtc_config.prach_ce_level_2_hopping_enable.value = p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_2_hopping_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_ENABLE_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_2_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value-6; + cfg->emtc_config.prach_ce_level_2_hopping_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_OFFSET_TAG; + cfg->num_tlv++; + + case 2: + p=prach_ParametersListCE_r13->list.array[1]; + cfg->emtc_config.prach_ce_level_1_enable.value = 1; + cfg->emtc_config.prach_ce_level_1_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_ENABLE_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_1_configuration_index.value = p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_1_configuration_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_CONFIGURATION_INDEX_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_1_frequency_offset.value = p->prach_FreqOffset_r13; + cfg->emtc_config.prach_ce_level_1_frequency_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_FREQUENCY_OFFSET_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; + cfg->emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + cfg->num_tlv++; + + if (p->prach_StartingSubframe_r13) { + cfg->emtc_config.prach_ce_level_1_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_1_starting_subframe_periodicity.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_STARTING_SUBFRAME_PERIODICITY_TAG; + cfg->num_tlv++; + } + + cfg->emtc_config.prach_ce_level_1_hopping_enable.value = p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_1_hopping_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_ENABLE_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_1_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value-6; + cfg->emtc_config.prach_ce_level_1_hopping_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_OFFSET_TAG; + cfg->num_tlv++; + + case 1: + p=prach_ParametersListCE_r13->list.array[0]; + cfg->emtc_config.prach_ce_level_0_enable.value = 1; + cfg->emtc_config.prach_ce_level_0_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_ENABLE_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_0_configuration_index.value = p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_0_configuration_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_CONFIGURATION_INDEX_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_0_frequency_offset.value = p->prach_FreqOffset_r13; + cfg->emtc_config.prach_ce_level_0_frequency_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_FREQUENCY_OFFSET_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; + cfg->emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + cfg->num_tlv++; + + if (p->prach_StartingSubframe_r13) { + cfg->emtc_config.prach_ce_level_0_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_0_starting_subframe_periodicity.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_STARTING_SUBFRAME_PERIODICITY_TAG; + cfg->num_tlv++; + } + + cfg->emtc_config.prach_ce_level_0_hopping_enable.value = p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_0_hopping_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_ENABLE_TAG; + cfg->num_tlv++; + + cfg->emtc_config.prach_ce_level_0_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value-6; + cfg->emtc_config.prach_ce_level_0_hopping_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_OFFSET_TAG; + cfg->num_tlv++; } + + struct FreqHoppingParameters_r13 *ext4_freqHoppingParameters = radioResourceConfigCommonP->ext4->freqHoppingParameters_r13; + if ((ext4_freqHoppingParameters) && + (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13)){ + switch(ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13->present) { + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_NOTHING: /* No components present */ + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_FDD_r13: + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodea.value = ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13->choice.interval_FDD_r13; + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodea.tl.tag = NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEA_TAG; + cfg->num_tlv++; + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_TDD_r13: + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodea.value = ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13->choice.interval_TDD_r13; + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodea.tl.tag = NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEA_TAG; + cfg->num_tlv++; + break; + } + } + if ((ext4_freqHoppingParameters) && + (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13)){ + switch(ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13->present) { + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_NOTHING: /* No components present */ + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_FDD_r13: + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodeb.value = ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13->choice.interval_FDD_r13; + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodeb.tl.tag = NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEB_TAG; + cfg->num_tlv++; + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_TDD_r13: + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodeb.value = ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13->choice.interval_TDD_r13; + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodeb.tl.tag = NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEB_TAG; + cfg->num_tlv++; + break; + } + } + } #endif } @@ -597,66 +752,67 @@ rrc_mac_config_req_eNB(module_id_t Mod_idP, SystemInformationBlockType1_v1310_IEs_t * sib1_v13ext #endif - ) -{ + ) { + + int i; - int i; + int UE_id = -1; + eNB_MAC_INST *eNB = RC.mac[Mod_idP]; + UE_list_t *UE_list= &eNB->UE_list; - int UE_id = -1; - eNB_MAC_INST *eNB = RC.mac[Mod_idP]; - UE_list_t *UE_list = &eNB->UE_list; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN); + LOG_E(MAC, "RC.mac:%p mib:%p\n", RC.mac, mib); + if (mib != NULL) { + if (RC.mac == NULL) + l2_init_eNB(); - if (mib != NULL) { - if (RC.mac == NULL) - l2_init_eNB(); + mac_top_init_eNB(); - mac_top_init_eNB(); + RC.mac[Mod_idP]->common_channels[CC_idP].mib = mib; + RC.mac[Mod_idP]->common_channels[CC_idP].physCellId = physCellId; + RC.mac[Mod_idP]->common_channels[CC_idP].p_eNB = p_eNB; + RC.mac[Mod_idP]->common_channels[CC_idP].Ncp = Ncp; + RC.mac[Mod_idP]->common_channels[CC_idP].eutra_band = eutra_band; + RC.mac[Mod_idP]->common_channels[CC_idP].dl_CarrierFreq = dl_CarrierFreq; - RC.mac[Mod_idP]->common_channels[CC_idP].mib = mib; - RC.mac[Mod_idP]->common_channels[CC_idP].physCellId = physCellId; - RC.mac[Mod_idP]->common_channels[CC_idP].p_eNB = p_eNB; - RC.mac[Mod_idP]->common_channels[CC_idP].Ncp = Ncp; - RC.mac[Mod_idP]->common_channels[CC_idP].eutra_band = eutra_band; - RC.mac[Mod_idP]->common_channels[CC_idP].dl_CarrierFreq = - dl_CarrierFreq; + LOG_I(MAC, + "Configuring MIB for instance %d, CCid %d : (band %d,N_RB_DL %d,Nid_cell %d,p %d,DL freq %u,phich_config.resource %d, phich_config.duration %d)\n", + Mod_idP, + CC_idP, + eutra_band, + to_prb((int)mib->message.dl_Bandwidth), + physCellId, + p_eNB, + dl_CarrierFreq, + (int)mib->message.phich_Config.phich_Resource, + (int)mib->message.phich_Config.phich_Duration); - LOG_I(MAC, - "Configuring MIB for instance %d, CCid %d : (band %d,N_RB_DL %d,Nid_cell %d,p %d,DL freq %u,phich_config.resource %d, phich_config.duration %d)\n", - Mod_idP, - CC_idP, - eutra_band, - to_prb((int) mib->message.dl_Bandwidth), - physCellId, - p_eNB, - dl_CarrierFreq, - (int) mib->message.phich_Config.phich_Resource, - (int) mib->message.phich_Config.phich_Duration); - - config_mib(Mod_idP, CC_idP, - eutra_band, - mib->message.dl_Bandwidth, - &mib->message.phich_Config, - physCellId, Ncp, p_eNB, dl_CarrierFreq, ul_CarrierFreq + config_mib(Mod_idP,CC_idP, + eutra_band, + mib->message.dl_Bandwidth, + &mib->message.phich_Config, + physCellId, + Ncp, + p_eNB, + dl_CarrierFreq, + ul_CarrierFreq #ifdef Rel14 , pbch_repetition #endif - ); + ); - mac_init_cell_params(Mod_idP, CC_idP); - } - if (schedulingInfoList != NULL) { - RC.mac[Mod_idP]->common_channels[CC_idP].tdd_Config = tdd_Config; - RC.mac[Mod_idP]->common_channels[CC_idP].schedulingInfoList = - schedulingInfoList; - config_sib1(Mod_idP, CC_idP, tdd_Config); + mac_init_cell_params(Mod_idP,CC_idP); + + if (schedulingInfoList!=NULL) { + RC.mac[Mod_idP]->common_channels[CC_idP].tdd_Config = tdd_Config; + RC.mac[Mod_idP]->common_channels[CC_idP].schedulingInfoList = schedulingInfoList; + config_sib1(Mod_idP,CC_idP,tdd_Config); } #ifdef Rel14 if (sib1_v13ext != NULL) { - RC.mac[Mod_idP]->common_channels[CC_idP].sib1_v13ext = sib1_v13ext; + RC.mac[Mod_idP]->common_channels[CC_idP].sib1_v13ext = sib1_v13ext; } #endif if (radioResourceConfigCommon != NULL) { @@ -719,53 +875,52 @@ rrc_mac_config_req_eNB(module_id_t Mod_idP, NULL, ul_Bandwidth, additionalSpectrumEmission, mbsfn_SubframeConfigList); - } - // SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup - if (logicalChannelConfig != NULL) { // check for eMTC specific things - UE_id = find_UE_id(Mod_idP, rntiP); + } // mib != NULL - if (UE_id == -1) { - LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, - __LINE__, __FUNCTION__); - } else { - if (logicalChannelConfig) - UE_list-> - UE_template[CC_idP][UE_id].lcgidmap - [logicalChannelIdentity] = - *logicalChannelConfig-> - ul_SpecificParameters->logicalChannelGroup; - else - UE_list-> - UE_template[CC_idP][UE_id].lcgidmap - [logicalChannelIdentity] = 0; - } + // SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup + if (logicalChannelConfig != NULL) { // check for eMTC specific things + UE_id = find_UE_id(Mod_idP, rntiP); + + if (UE_id == -1) { + LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, + __LINE__, __FUNCTION__); + } else { + if (logicalChannelConfig) + UE_list-> + UE_template[CC_idP][UE_id].lcgidmap + [logicalChannelIdentity] = + *logicalChannelConfig-> + ul_SpecificParameters->logicalChannelGroup; + else + UE_list-> + UE_template[CC_idP][UE_id].lcgidmap + [logicalChannelIdentity] = 0; } + } - if (physicalConfigDedicated != NULL) { - UE_id = find_UE_id(Mod_idP, rntiP); + if (physicalConfigDedicated != NULL) { + UE_id = find_UE_id(Mod_idP, rntiP); - if (UE_id == -1) - LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, - __LINE__, __FUNCTION__); - else - UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated = - physicalConfigDedicated; - } + if (UE_id == -1) + LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, __LINE__, __FUNCTION__); + else + UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated = physicalConfigDedicated; + } #if defined(Rel10) || defined(Rel14) - if (sCellToAddMod_r10 != NULL) { - UE_id = find_UE_id(Mod_idP, rntiP); - if (UE_id == -1) - LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, - __LINE__, __FUNCTION__); - else + if (sCellToAddMod_r10 != NULL) { + UE_id = find_UE_id(Mod_idP, rntiP); + if (UE_id == -1) + LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, + __LINE__, __FUNCTION__); + else config_dedicated_scell(Mod_idP, rntiP, sCellToAddMod_r10); - } + } #endif @@ -795,25 +950,18 @@ rrc_mac_config_req_eNB(module_id_t Mod_idP, } #if defined(Rel10) || defined(Rel14) - if (mbsfn_AreaInfoList != NULL) { - // One eNB could be part of multiple mbsfn syc area, this could change over time so reset each time - LOG_I(MAC, "[eNB %d][CONFIG] Received %d MBSFN Area Info\n", - Mod_idP, mbsfn_AreaInfoList->list.count); - RC.mac[Mod_idP]->common_channels[0].num_active_mbsfn_area = - mbsfn_AreaInfoList->list.count; - - for (i = 0; i < mbsfn_AreaInfoList->list.count; i++) { - RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i] = - mbsfn_AreaInfoList->list.array[i]; - LOG_I(MAC, - "[eNB %d][CONFIG] MBSFN_AreaInfo[%d]: MCCH Repetition Period = %ld\n", - Mod_idP, i, - RC.mac[Mod_idP]->common_channels[0]. - mbsfn_AreaInfo[i]->mcch_Config_r9. - mcch_RepetitionPeriod_r9); - // config_sib13(Mod_idP,0,i,RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i]->mbsfn_AreaId_r9); - } + if (mbsfn_AreaInfoList != NULL) { + // One eNB could be part of multiple mbsfn syc area, this could change over time so reset each time + LOG_I(MAC,"[eNB %d][CONFIG] Received %d MBSFN Area Info\n", Mod_idP, mbsfn_AreaInfoList->list.count); + RC.mac[Mod_idP]->common_channels[0].num_active_mbsfn_area = mbsfn_AreaInfoList->list.count; + + for (i =0; i< mbsfn_AreaInfoList->list.count; i++) { + RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i] = mbsfn_AreaInfoList->list.array[i]; + LOG_I(MAC,"[eNB %d][CONFIG] MBSFN_AreaInfo[%d]: MCCH Repetition Period = %ld\n", Mod_idP,i, + RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i]->mcch_Config_r9.mcch_RepetitionPeriod_r9); + // config_sib13(Mod_idP,0,i,RC.mac[Mod_idP]->common_channels[0].mbsfn_AreaInfo[i]->mbsfn_AreaId_r9); } + } if (pmch_InfoList != NULL) { @@ -849,21 +997,32 @@ rrc_mac_config_req_eNB(module_id_t Mod_idP, } #endif - if (radioResourceConfigCommon != NULL) { - AssertFatal(RC.mac[Mod_idP]->if_inst->PHY_config_req != NULL, - "if_inst->phy_config_request is null\n"); - PHY_Config_t phycfg; - phycfg.Mod_id = Mod_idP; - phycfg.CC_id = CC_idP; - phycfg.cfg = &RC.mac[Mod_idP]->config[CC_idP]; + LOG_E(MAC, "%s() %s:%d RC.mac[Mod_idP]->if_inst->PHY_config_req:%p\n", __FUNCTION__, __FILE__, __LINE__, RC.mac[Mod_idP]->if_inst->PHY_config_req); - if (RC.mac[Mod_idP]->if_inst->PHY_config_req) - RC.mac[Mod_idP]->if_inst->PHY_config_req(&phycfg); + // if in nFAPI mode + if ( + (nfapi_mode == 1 || nfapi_mode == 2) && + (RC.mac[Mod_idP]->if_inst->PHY_config_req == NULL) + ) { + while(RC.mac[Mod_idP]->if_inst->PHY_config_req == NULL) { + // DJP AssertFatal(RC.mac[Mod_idP]->if_inst->PHY_config_req != NULL,"if_inst->phy_config_request is null\n"); + usleep(100 * 1000); + printf("Waiting for PHY_config_req\n"); + } } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); - return (0); + if (radioResourceConfigCommon != NULL) { + PHY_Config_t phycfg; + phycfg.Mod_id = Mod_idP; + phycfg.CC_id = CC_idP; + phycfg.cfg = &RC.mac[Mod_idP]->config[CC_idP]; + + if (RC.mac[Mod_idP]->if_inst->PHY_config_req) RC.mac[Mod_idP]->if_inst->PHY_config_req(&phycfg); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); + } + + return(0); } int diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 2c3b88306a..4d95cf6c62 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -145,7 +145,7 @@ schedule_SRS(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) if (((10 * frameP + subframeP) % srsPeriodicity) == srsOffset) { - // Prorgram SRS + // Program SRS ul_req->srs_present = 1; nfapi_ul_config_request_pdu_t * ul_config_pdu = @@ -161,6 +161,7 @@ schedule_SRS(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) 2 + (uint8_t) (2 + sizeof (nfapi_ul_config_srs_pdu)); + ul_config_pdu->srs_pdu.srs_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL8_TAG; ul_config_pdu->srs_pdu.srs_pdu_rel8.size = (uint8_t) sizeof(nfapi_ul_config_srs_pdu);; @@ -196,6 +197,7 @@ schedule_SRS(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) // ul_config_pdu->srs_pdu.srs_pdu_rel13.number_of_combs = ;// RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; + RC.mac[module_idP]->UL_req[CC_id].header.message_id = NFAPI_UL_CONFIG_REQUEST; ul_req->number_of_pdus++; } // if (((10*frameP+subframeP) % srsPeriodicity) == srsOffset) } // if (soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) @@ -269,9 +271,11 @@ schedule_CSI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) 2 + (uint8_t) (2 + sizeof (nfapi_ul_config_uci_cqi_pdu)); + ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; ul_config_pdu->uci_cqi_pdu. ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; + ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG; ul_config_pdu->uci_cqi_pdu. cqi_information.cqi_information_rel8. pucch_index = @@ -285,6 +289,7 @@ schedule_CSI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) get_tmode(module_idP, CC_id, UE_id), cqi_ReportPeriodic); ul_req->number_of_pdus++; + ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; #if defined(Rel10) || defined(Rel14) // PUT rel10-13 UCI options here @@ -305,9 +310,11 @@ schedule_CSI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) 2 + (uint8_t) (2 + sizeof (nfapi_ul_config_uci_cqi_pdu)); + ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; ul_config_pdu->uci_cqi_pdu. ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; + ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG; ul_config_pdu->uci_cqi_pdu. cqi_information.cqi_information_rel8. pucch_index = @@ -319,6 +326,7 @@ schedule_CSI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; ul_req->number_of_pdus++; + ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; } } // if ((cqi_ReportPeriodic = cqi_ReportConfig->cqi_ReportPeriodic)!=NULL) { @@ -332,7 +340,8 @@ schedule_SR(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) { eNB_MAC_INST *eNB = RC.mac[module_idP]; UE_list_t *UE_list = &eNB->UE_list; - nfapi_ul_config_request_body_t *ul_req; + nfapi_ul_config_request_t *ul_req; + nfapi_ul_config_request_body_t *ul_req_body; int CC_id; int UE_id; SchedulingRequestConfig_t *SRconfig; @@ -349,8 +358,8 @@ schedule_SR(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) if (RC.mac[module_idP]->UE_list.active[UE_id] != TRUE) continue; - ul_req = - &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body; + ul_req = &RC.mac[module_idP]->UL_req[CC_id]; + ul_req_body = &ul_req->ul_config_request_body; // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet if (mac_eNB_get_rrc_status @@ -397,28 +406,18 @@ schedule_SR(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) skip_ue = 0; is_harq = 0; // check that there is no existing UL grant for ULSCH which overrides the SR - for (i = 0; i < ul_req->number_of_pdus; i++) { - if (((ul_req->ul_config_pdu_list[i].pdu_type == - NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) - || (ul_req->ul_config_pdu_list[i].pdu_type == - NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE) - || (ul_req->ul_config_pdu_list[i].pdu_type == - NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) - || (ul_req->ul_config_pdu_list[i].pdu_type == - NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE)) - && (ul_req->ul_config_pdu_list[i]. - ulsch_pdu.ulsch_pdu_rel8.rnti == - UE_list->UE_template[CC_id][UE_id].rnti)) { + for (i = 0; i < ul_req_body->number_of_pdus; i++) { + if (((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) || + (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE) || + (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) || + (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE)) && + (ul_req_body->ul_config_pdu_list[i].ulsch_pdu.ulsch_pdu_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) { skip_ue = 1; break; } /* if there is already an HARQ pdu, convert to SR_HARQ */ - else if ((ul_req->ul_config_pdu_list[i].pdu_type == - NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) - && (ul_req->ul_config_pdu_list[i]. - uci_harq_pdu.ue_information. - ue_information_rel8.rnti == - UE_list->UE_template[CC_id][UE_id].rnti)) { + else if ((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) && + (ul_req_body->ul_config_pdu_list[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) { is_harq = 1; break; } @@ -428,10 +427,7 @@ schedule_SR(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) if (skip_ue == 1) continue; - LOG_D(MAC, - "Frame %d, Subframe %d : Scheduling SR for UE %d/%x\n", - frameP, subframeP, UE_id, - UE_list->UE_template[CC_id][UE_id].rnti); + LOG_D(MAC,"Frame %d, Subframe %d : Scheduling SR for UE %d/%x is_harq:%d\n",frameP,subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].rnti, is_harq); // check Rel10 or Rel8 SR #if defined(Rel10) || defined(Rel14) @@ -443,49 +439,48 @@ schedule_SR(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) && (UE_list-> UE_template[CC_id][UE_id].physicalConfigDedicated-> ext2->schedulingRequestConfig_v1020)) { + sr.sr_information_rel10.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL10_TAG; sr.sr_information_rel10.number_of_pucch_resources = 1; sr.sr_information_rel10.pucch_index_p1 = *UE_list-> UE_template[CC_id][UE_id].physicalConfigDedicated-> ext2-> schedulingRequestConfig_v1020->sr_PUCCH_ResourceIndexP1_r10; + LOG_D(MAC,"REL10 PUCCH INDEX P1:%d\n", sr.sr_information_rel10.pucch_index_p1); } else #endif { + sr.sr_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL8_TAG; sr.sr_information_rel8.pucch_index = UE_list-> UE_template[CC_id][UE_id].physicalConfigDedicated-> schedulingRequestConfig->choice.setup. sr_PUCCH_ResourceIndex; + LOG_D(MAC,"REL8 PUCCH INDEX:%d\n", sr.sr_information_rel8.pucch_index); } /* if there is already an HARQ pdu, convert to SR_HARQ */ if (is_harq) { - nfapi_ul_config_harq_information h = - ul_req->ul_config_pdu_list[i].uci_harq_pdu. - harq_information; - ul_req->ul_config_pdu_list[i].pdu_type = - NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; - ul_req->ul_config_pdu_list[i].uci_sr_harq_pdu. - sr_information = sr; - ul_req->ul_config_pdu_list[i].uci_sr_harq_pdu. - harq_information = h; + nfapi_ul_config_harq_information h = ul_req_body->ul_config_pdu_list[i].uci_harq_pdu.harq_information; + ul_req_body->ul_config_pdu_list[i].pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; + ul_req_body->ul_config_pdu_list[i].uci_sr_harq_pdu.sr_information = sr; + ul_req_body->ul_config_pdu_list[i].uci_sr_harq_pdu.harq_information = h; } else { - ul_req->ul_config_pdu_list[ul_req->number_of_pdus]. - pdu_type = NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE; - ul_req->ul_config_pdu_list[ul_req-> - number_of_pdus].uci_sr_pdu. - ue_information.ue_information_rel8.rnti = - UE_list->UE_template[CC_id][UE_id].rnti; - ul_req->ul_config_pdu_list[ul_req-> - number_of_pdus].uci_sr_pdu. - sr_information = sr; - ul_req->number_of_pdus++; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].pdu_type = NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel11.tl.tag = 0; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel13.tl.tag = 0; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.sr_information = sr; + ul_req_body->number_of_pdus++; } /* if (is_harq) */ + ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; } // for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) } // for (CC_id=0; CC_idpdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = @@ -532,6 +528,7 @@ check_ul_failure(module_id_t module_idP, int CC_id, int UE_id, pdcch_order_table[cc[CC_id].mib->message.dl_Bandwidth]; DL_req[CC_id].dl_config_request_body.number_dci++; DL_req[CC_id].dl_config_request_body.number_pdu++; + DL_req[CC_id].dl_config_request_body.tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; LOG_I(MAC, "UE %d rnti %x: sending PDCCH order for RAPROC (failure timer %d), resource_block_coding %d \n", UE_id, rnti, @@ -572,55 +569,72 @@ clear_nfapi_information(eNB_MAC_INST * eNB, int CC_idP, nfapi_hi_dci0_request_t *HI_DCI0_req = &eNB->HI_DCI0_req[0]; nfapi_tx_request_t *TX_req = &eNB->TX_req[0]; - eNB->pdu_index[CC_idP] = 0; - DL_req[CC_idP].dl_config_request_body.number_pdcch_ofdm_symbols = 1; - DL_req[CC_idP].dl_config_request_body.number_dci = 0; - DL_req[CC_idP].dl_config_request_body.number_pdu = 0; - DL_req[CC_idP].dl_config_request_body.number_pdsch_rnti = 0; - DL_req[CC_idP].dl_config_request_body.transmission_power_pcfich = 6000; - HI_DCI0_req[CC_idP].hi_dci0_request_body.sfnsf = - subframeP + (frameP << 4); - HI_DCI0_req[CC_idP].hi_dci0_request_body.number_of_dci = 0; + if (nfapi_mode==0 || nfapi_mode == 1) { // monolithic or PNF + + DL_req[CC_idP].dl_config_request_body.number_pdcch_ofdm_symbols = 1; + DL_req[CC_idP].dl_config_request_body.number_dci = 0; + DL_req[CC_idP].dl_config_request_body.number_pdu = 0; + DL_req[CC_idP].dl_config_request_body.number_pdsch_rnti = 0; + DL_req[CC_idP].dl_config_request_body.transmission_power_pcfich = 6000; + + HI_DCI0_req[CC_idP].hi_dci0_request_body.sfnsf = subframeP + (frameP<<4); + HI_DCI0_req[CC_idP].hi_dci0_request_body.number_of_dci = 0; - UL_req[CC_idP].ul_config_request_body.number_of_pdus = 0; - UL_req[CC_idP].ul_config_request_body.rach_prach_frequency_resources = 0; // ignored, handled by PHY for now - UL_req[CC_idP].ul_config_request_body.srs_present = 0; // ignored, handled by PHY for now - - - TX_req[CC_idP].tx_request_body.number_of_pdus = 0; + UL_req[CC_idP].ul_config_request_body.number_of_pdus = 0; + UL_req[CC_idP].ul_config_request_body.rach_prach_frequency_resources = 0; // ignored, handled by PHY for now + UL_req[CC_idP].ul_config_request_body.srs_present = 0; // ignored, handled by PHY for now + TX_req[CC_idP].tx_request_body.number_of_pdus = 0; + if (0) LOG_D(MAC,"%s() SFN_SF:%d%d ZERO PDUs of TX_req:(SFN_SF:%d):%d UL_req:(SFN_SF:%d):%d HI_DCI0_req:(SFN_SF:%d):dci:%d hi:%d DL:(SFN_SF:%d):dci:%d DL:pdu:%d\n", + __FUNCTION__, + frameP, subframeP, + NFAPI_SFNSF2DEC(TX_req[CC_idP].sfn_sf), + TX_req[CC_idP].tx_request_body.number_of_pdus, + NFAPI_SFNSF2DEC(UL_req[CC_idP].sfn_sf), + UL_req[CC_idP].ul_config_request_body.number_of_pdus, + NFAPI_SFNSF2DEC(HI_DCI0_req[CC_idP].sfn_sf), + HI_DCI0_req[CC_idP].hi_dci0_request_body.number_of_dci, + HI_DCI0_req[CC_idP].hi_dci0_request_body.number_of_hi, + NFAPI_SFNSF2DEC(DL_req[CC_idP].sfn_sf), + DL_req[CC_idP].dl_config_request_body.number_dci, + DL_req[CC_idP].dl_config_request_body.number_pdu); + } } void copy_ulreq(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) { int CC_id; - eNB_MAC_INST *eNB; - nfapi_ul_config_request_body_t *ul_req_tmp; - nfapi_ul_config_request_body_t *ul_req; - - eNB = RC.mac[module_idP]; + eNB_MAC_INST *mac = RC.mac[module_idP]; for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - ul_req_tmp = - &eNB->UL_req_tmp[CC_id][subframeP].ul_config_request_body; - ul_req = &eNB->UL_req[CC_id].ul_config_request_body; + nfapi_ul_config_request_t *ul_req_tmp = &mac->UL_req_tmp[CC_id][subframeP]; + nfapi_ul_config_request_t *ul_req = &mac->UL_req[CC_id]; + nfapi_ul_config_request_pdu_t *ul_req_pdu = ul_req->ul_config_request_body.ul_config_pdu_list; - eNB->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; - ul_req->number_of_pdus = ul_req_tmp->number_of_pdus; - ul_req_tmp->number_of_pdus = 0; + *ul_req = *ul_req_tmp; - memcpy((void *) ul_req->ul_config_pdu_list, - (void *) ul_req_tmp->ul_config_pdu_list, - ul_req->number_of_pdus * - sizeof(nfapi_ul_config_request_pdu_t)); + // Restore the pointer + ul_req->ul_config_request_body.ul_config_pdu_list = ul_req_pdu; - } + ul_req->sfn_sf = (frameP<<4) + subframeP; + + ul_req_tmp->ul_config_request_body.number_of_pdus = 0; + + if (ul_req->ul_config_request_body.number_of_pdus>0) + { + LOG_D(PHY, "%s() active NOW (frameP:%d subframeP:%d) pdus:%d\n", __FUNCTION__, frameP, subframeP, ul_req->ul_config_request_body.number_of_pdus); + } + + memcpy((void*)ul_req->ul_config_request_body.ul_config_pdu_list, + (void*)ul_req_tmp->ul_config_request_body.ul_config_pdu_list, + ul_req->ul_config_request_body.number_of_pdus*sizeof(nfapi_ul_config_request_pdu_t)); + } } void diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c index 327f5faafe..14cdb4b5f3 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c @@ -65,6 +65,37 @@ #include "T.h" +extern uint8_t nfapi_mode; +extern int oai_nfapi_hi_dci0_req(nfapi_hi_dci0_request_t *hi_dci0_req); + +void add_subframe(uint16_t *frameP, uint16_t *subframeP, int offset) +{ + *frameP = *frameP + ((*subframeP + offset) / 10); + + *subframeP = ((*subframeP + offset) % 10); +} + +uint16_t sfnsf_add_subframe(uint16_t frameP, uint16_t subframeP, int offset) +{ + add_subframe(&frameP, &subframeP, offset); + return frameP<<4|subframeP; +} + +void subtract_subframe(uint16_t *frameP, uint16_t *subframeP, int offset) +{ + if (*subframeP < offset) + { + *frameP = (*frameP+1024-1)%1024; + } + *subframeP = (*subframeP+10-offset)%10; +} + +uint16_t sfnsf_subtract_subframe(uint16_t frameP, uint16_t subframeP, int offset) +{ + subtract_subframe(&frameP, &subframeP, offset); + return frameP<<4|subframeP; +} + void add_msg3(module_id_t module_idP, int CC_id, RA_t * ra, frame_t frameP, sub_frame_t subframeP) @@ -73,15 +104,15 @@ add_msg3(module_id_t module_idP, int CC_id, RA_t * ra, frame_t frameP, COMMON_channels_t *cc = &mac->common_channels[CC_id]; uint8_t j; nfapi_ul_config_request_t *ul_req; - nfapi_ul_config_request_pdu_t *ul_config_pdu; nfapi_ul_config_request_body_t *ul_req_body; - nfapi_hi_dci0_request_body_t *hi_dci0_req; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu; + nfapi_ul_config_request_pdu_t *ul_config_pdu; + nfapi_hi_dci0_request_t *hi_dci0_req = &mac->HI_DCI0_req[CC_id]; + nfapi_hi_dci0_request_body_t *hi_dci0_req_body = &hi_dci0_req->hi_dci0_request_body; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu; uint8_t rvseq[4] = { 0, 2, 3, 1 }; - hi_dci0_req = &mac->HI_DCI0_req[CC_id].hi_dci0_request_body; ul_req = &mac->UL_req_tmp[CC_id][ra->Msg3_subframe]; ul_req_body = &ul_req->ul_config_request_body; AssertFatal(ra->state != IDLE, "RA is not active for RA %X\n", @@ -108,6 +139,7 @@ add_msg3(module_id_t module_idP, int CC_id, RA_t * ra, frame_t frameP, ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu)); ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = mac->ul_handle++; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = ra->rnti; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = narrowband_to_first_rb(cc, @@ -132,6 +164,7 @@ add_msg3(module_id_t module_idP, int CC_id, RA_t * ra, frame_t frameP, ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = get_TBS_UL(ra->msg3_mcs, ra->msg3_nb_rb); // Re13 fields + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL13_TAG; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.ue_type = ra->rach_resource_type > 2 ? 2 : 1; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13. @@ -141,6 +174,9 @@ add_msg3(module_id_t module_idP, int CC_id, RA_t * ra, frame_t frameP, initial_transmission_sf_io = (ra->Msg3_frame * 10) + ra->Msg3_subframe; ul_req_body->number_of_pdus++; + ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + ul_req->sfn_sf = ra->Msg3_frame<<4|ra->Msg3_subframe; + ul_req->header.message_id = NFAPI_UL_CONFIG_REQUEST; } // if (ra->rach_resource_type>0) { else #endif @@ -163,6 +199,7 @@ add_msg3(module_id_t module_idP, int CC_id, RA_t * ra, frame_t frameP, ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu)); + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = mac->ul_handle++; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = ra->rnti; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = @@ -187,24 +224,41 @@ add_msg3(module_id_t module_idP, int CC_id, RA_t * ra, frame_t frameP, ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = get_TBS_UL(10, ra->msg3_nb_rb); ul_req_body->number_of_pdus++; + ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + ul_req->sfn_sf = ra->Msg3_frame<<4|ra->Msg3_subframe; + ul_req->header.message_id = NFAPI_UL_CONFIG_REQUEST; // save UL scheduling information for preprocessor for (j = 0; j < ra->msg3_nb_rb; j++) cc->vrb_map_UL[ra->msg3_first_rb + j] = 1; + LOG_D(MAC, "MSG3: UL_CONFIG SFN/SF:%d number_of_pdus:%d ra->msg3_round:%d\n", NFAPI_SFNSF2DEC(ul_req->sfn_sf), ul_req_body->number_of_pdus, ra->msg3_round); if (ra->msg3_round != 0) { // program HI too - hi_dci0_pdu = - &hi_dci0_req->hi_dci0_pdu_list[hi_dci0_req->number_of_dci + - hi_dci0_req->number_of_hi]; + hi_dci0_pdu = &hi_dci0_req_body->hi_dci0_pdu_list[hi_dci0_req_body->number_of_dci + hi_dci0_req_body->number_of_hi]; memset((void *) hi_dci0_pdu, 0, sizeof(nfapi_hi_dci0_request_pdu_t)); hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; hi_dci0_pdu->pdu_size = 2 + sizeof(nfapi_hi_dci0_hi_pdu); + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_HI_PDU_REL8_TAG; hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = ra->msg3_first_rb; hi_dci0_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = 0; hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 0; - hi_dci0_req->number_of_hi++; + hi_dci0_req_body->number_of_hi++; + + hi_dci0_req_body->sfnsf = sfnsf_add_subframe(ra->Msg3_frame, ra->Msg3_subframe, 0); + hi_dci0_req_body->tl.tag = NFAPI_HI_DCI0_REQUEST_BODY_TAG; + + hi_dci0_req->sfn_sf = sfnsf_add_subframe(ra->Msg3_frame, ra->Msg3_subframe, 4); + hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST; + + if (nfapi_mode) { + oai_nfapi_hi_dci0_req(hi_dci0_req); + hi_dci0_req_body->number_of_hi=0; + } + + LOG_D(MAC, "MSG3: HI_DCI0 SFN/SF:%d number_of_dci:%d number_of_hi:%d\n", NFAPI_SFNSF2DEC(hi_dci0_req->sfn_sf), hi_dci0_req_body->number_of_dci, hi_dci0_req_body->number_of_hi); + // save UL scheduling information for preprocessor for (j = 0; j < ra->msg3_nb_rb; j++) cc->vrb_map_UL[ra->msg3_first_rb + j] = 1; @@ -251,6 +305,8 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, uint16_t absSF = (10 * frameP) + subframeP; uint16_t absSF_Msg2 = (10 * ra->Msg2_frame) + ra->Msg2_subframe; + LOG_D(MAC,"absSF:%d absSF_Msg2:%d ra->rach_resource_type:%d\n",absSF,absSF_Msg2,ra->rach_resource_type); + if (absSF > absSF_Msg2) return; // we're not ready yet, need to be to start == @@ -325,6 +381,7 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_mpdcch_pdu)); + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_MPDCCH_PDU_REL13_TAG; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = (ra->rach_resource_type > 1) ? 11 : 10; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = @@ -397,8 +454,11 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, number_of_tx_antenna_ports = 1; ra->msg2_mpdcch_repetition_cnt++; dl_req->number_pdu++; + dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; ra->Msg2_subframe = (ra->Msg2_subframe + 9) % 10; + mac->DL_req[CC_idP].sfn_sf = sfnsf_add_subframe(ra->Msg2_frame, ra->Msg2_subframe, 4); // nFAPI is runnning at TX SFN/SF - ie 4 ahead + mac->DL_req[CC_idP].header.message_id = NFAPI_DL_CONFIG_REQUEST; } //repetition_count==0 && SF condition met if (ra->msg2_mpdcch_repetition_cnt > 0) { // we're in a stream of repetitions LOG_D(MAC, @@ -427,6 +487,7 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, "[eNB %d][RAPROC] Frame %d, Subframe %d : In generate_Msg2, Programming PDSCH\n", module_idP, frameP, subframeP); ra->state = WAITMSG3; + LOG_I(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:WAITMSG3\n", module_idP, frameP, subframeP); dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; @@ -435,6 +496,7 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = mac->pdu_index[CC_idP]; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = ra->RA_rnti; @@ -472,11 +534,13 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; // Rel10 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = cc[CC_idP]. sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13-> startSymbolBR_r13; // Rel13 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = (ra->rach_resource_type < 3) ? 1 : 2;; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not SI message @@ -486,6 +550,11 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, 0; dl_req->number_pdu++; + mac->DL_req[CC_idP].sfn_sf = (frameP<<4)+subframeP; + mac->DL_req[CC_idP].header.message_id = NFAPI_DL_CONFIG_REQUEST; + + LOG_E(MAC,"DL_CONFIG SFN/SF:%d/%d MESSAGE2\n", frameP, subframeP); + // Program UL processing for Msg3, same as regular LTE get_Msg3alloc(&cc[CC_idP], subframeP, frameP, &ra->Msg3_frame, &ra->Msg3_subframe); @@ -494,6 +563,8 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, cc[CC_idP].RAR_pdu.payload, ra->rach_resource_type - 1); // DL request + mac->TX_req[CC_idP].tx_request_body.tl.tag = NFAPI_TX_REQUEST_BODY_TAG; + mac->TX_req[CC_idP].header.message_id = NFAPI_TX_REQUEST; mac->TX_req[CC_idP].sfn_sf = (frameP << 4) + subframeP; TX_req = &mac->TX_req[CC_idP].tx_request_body.tx_pdu_list[mac-> @@ -531,6 +602,7 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = @@ -570,6 +642,7 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = mac->pdu_index[CC_idP]; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = ra->RA_rnti; @@ -605,6 +678,7 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; dl_req->number_pdu++; + mac->DL_req[CC_idP].sfn_sf = frameP<<4 | subframeP; // Program UL processing for Msg3 get_Msg3alloc(&cc[CC_idP], subframeP, frameP, @@ -619,6 +693,7 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, cc[CC_idP].RAR_pdu.payload, N_RB_DL, 7); add_msg3(module_idP, CC_idP, ra, frameP, subframeP); ra->state = WAITMSG3; + LOG_I(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:WAITMSG3\n", module_idP, frameP, subframeP); // DL request mac->TX_req[CC_idP].sfn_sf = (frameP << 4) + subframeP; @@ -638,7 +713,6 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, } // Msg2 frame/subframe condition } // else BL/CE } - void generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, sub_frame_t subframeP, RA_t * ra) @@ -653,17 +727,19 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, uint16_t msg4_post_padding; uint16_t msg4_header; - uint8_t *vrb_map; - int first_rb; - int N_RB_DL; - nfapi_dl_config_request_pdu_t *dl_config_pdu; - nfapi_ul_config_request_pdu_t *ul_config_pdu; - nfapi_tx_request_pdu_t *TX_req; - UE_list_t *UE_list = &mac->UE_list; - nfapi_dl_config_request_body_t *dl_req; - nfapi_ul_config_request_body_t *ul_req; - uint8_t lcid; - uint8_t offset; + uint8_t *vrb_map; + int first_rb; + int N_RB_DL; + nfapi_dl_config_request_pdu_t *dl_config_pdu; + nfapi_ul_config_request_pdu_t *ul_config_pdu; + nfapi_tx_request_pdu_t *TX_req; + UE_list_t *UE_list=&mac->UE_list; + nfapi_dl_config_request_t *dl_req; + nfapi_dl_config_request_body_t *dl_req_body; + nfapi_ul_config_request_body_t *ul_req_body; + nfapi_ul_config_request_t *ul_req; + uint8_t lcid; + uint8_t offset; #ifdef Rel14 @@ -750,8 +826,9 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, vrb_map = cc[CC_idP].vrb_map; - dl_req = &mac->DL_req[CC_idP].dl_config_request_body; - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + dl_req = &mac->DL_req[CC_idP]; + dl_req_body = &dl_req->dl_config_request_body; + dl_config_pdu = &dl_req_body->dl_config_pdu_list[dl_req_body->number_pdu]; N_RB_DL = to_prb(cc[CC_idP].mib->message.dl_Bandwidth); UE_id = find_UE_id(module_idP, ra->rnti); @@ -764,7 +841,6 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, else ra->harq_pid = ((frameP * 10) + subframeP) & 7; - // Get RRCConnectionSetup for Piggyback rrc_sdu_length = mac_rrc_data_req(module_idP, CC_idP, frameP, CCCH, 1, // 1 transport block &cc[CC_idP].CCCH_pdu.payload[0], ENB_FLAG_YES, module_idP, 0); // not used in this case @@ -813,6 +889,7 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_mpdcch_pdu)); + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_MPDCCH_PDU_REL13_TAG; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = (ra->rach_resource_type > 1) ? 11 : 10; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = @@ -885,7 +962,11 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. number_of_tx_antenna_ports = 1; ra->msg4_mpdcch_repetition_cnt++; - dl_req->number_pdu++; + dl_req_body->number_pdu++; + dl_req_body->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + + dl_req->sfn_sf = (ra->Msg4_frame<<4)+ra->Msg4_subframe; + dl_req->header.message_id = NFAPI_DL_CONFIG_REQUEST; } //repetition_count==0 && SF condition met else if (ra->msg4_mpdcch_repetition_cnt > 0) { // we're in a stream of repetitions @@ -915,12 +996,13 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, AssertFatal(1 == 0, "Msg4 generation not finished for BL/CE UE\n"); dl_config_pdu = - &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + &dl_req_body->dl_config_pdu_list[dl_req_body->number_pdu]; memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = mac->pdu_index[CC_idP]; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = ra->rnti; @@ -955,11 +1037,13 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = cc[CC_idP]. sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13-> startSymbolBR_r13; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = (ra->rach_resource_type < 3) ? 1 : 2; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not SI message @@ -967,9 +1051,14 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, initial_transmission_sf_io = (10 * frameP) + subframeP; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = 0; - dl_req->number_pdu++; + dl_req_body->number_pdu++; + dl_req_body->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + mac->DL_req[CC_idP].sfn_sf = (frameP<<4)+subframeP; + mac->DL_req[CC_idP].header.message_id = NFAPI_DL_CONFIG_REQUEST; + ra->state = WAITMSG4ACK; + LOG_I(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:WAITMSG4ACK\n", module_idP, frameP, subframeP); lcid = 0; @@ -1012,6 +1101,9 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, // DL request mac->TX_req[CC_idP].sfn_sf = (frameP << 4) + subframeP; + mac->TX_req[CC_idP].tx_request_body.tl.tag = NFAPI_TX_REQUEST_BODY_TAG; + mac->TX_req[CC_idP].header.message_id = NFAPI_TX_REQUEST; + TX_req = &mac->TX_req[CC_idP].tx_request_body.tx_pdu_list[mac-> TX_req @@ -1032,19 +1124,19 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, int ackNAK_absSF = absSF + reps + 4; AssertFatal(reps > 2, "Have to handle programming of ACK when PDSCH repetitions is > 2\n"); - ul_req = - &mac->UL_req_tmp[CC_idP][ackNAK_absSF % - 10].ul_config_request_body; - ul_config_pdu = - &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; + ul_req = &mac->UL_req_tmp[CC_idP][ackNAK_absSF % 10]; + ul_req_body = &ul_req->ul_config_request_body; + ul_config_pdu = &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus]; ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE; ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_uci_harq_pdu)); + ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.handle = 0; // don't know how to use this ul_config_pdu->uci_harq_pdu. ue_information.ue_information_rel8.rnti = ra->rnti; + ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL13_TAG; ul_config_pdu->uci_harq_pdu. ue_information.ue_information_rel13.ue_type = (ra->rach_resource_type < 3) ? 1 : 2; @@ -1056,8 +1148,17 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, ul_config_pdu->uci_harq_pdu. ue_information.ue_information_rel13.repetition_number = 0; + + ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + + ul_req->sfn_sf = sfnsf_add_subframe(ra->Msg3_frame, ra->Msg3_subframe, 4); + ul_req->header.message_id = NFAPI_UL_CONFIG_REQUEST; + + LOG_D(MAC,"UL_req_tmp[CC_idP:%d][ackNAK_absSF mod 10:%d] ra->Msg3_frame:%d ra->Msg3_subframe:%d + 4 sfn_sf:%d\n", CC_idP, ackNAK_absSF%10, ra->Msg3_frame, ra->Msg3_subframe, NFAPI_SFNSF2DEC(ul_req->sfn_sf)); + // Note need to keep sending this across reptitions!!!! Not really for PUCCH, to ask small-cell forum, we'll see for the other messages, maybe parameters change across repetitions and FAPI has to provide for that if (cc[CC_idP].tdd_Config == NULL) { // FDD case + ul_config_pdu->uci_harq_pdu.harq_information.harq_information_rel8_fdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL8_FDD_TAG; ul_config_pdu->uci_harq_pdu. harq_information.harq_information_rel8_fdd. n_pucch_1_0 = @@ -1071,7 +1172,7 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, AssertFatal(1 == 0, "PUCCH configuration for ACK/NAK not handled yet for TDD BL/CE case\n"); } - ul_req->number_of_pdus++; + ul_req_body->number_of_pdus++; T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_idP), T_INT(ra->rnti), T_INT(frameP), T_INT(subframeP), T_INT(0 /*harq_pid always 0? */ ), @@ -1145,9 +1246,10 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, 1, // ndi 0, // rv 0); // vrb_flag + LOG_D(MAC, "Frame %d, subframe %d: Msg4 DCI pdu_num %d (rnti %x,rnti_type %d,harq_pid %d, resource_block_coding (%p) %d\n", - frameP, subframeP, dl_req->number_pdu, + frameP, subframeP, dl_req_body->number_pdu, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process, @@ -1164,10 +1266,11 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, (module_idP, CC_idP, 1, subframeP, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. aggregation_level, ra->rnti)) { - dl_req->number_dci++; - dl_req->number_pdu++; + dl_req_body->number_dci++; + dl_req_body->number_pdu++; ra->state = WAITMSG4ACK; + LOG_I(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:WAITMSG4ACK\n", module_idP, frameP, subframeP); // increment Absolute subframe by 8 for Msg4 retransmission LOG_D(MAC, @@ -1226,7 +1329,7 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, &cc[CC_idP].CCCH_pdu.payload[0], rrc_sdu_length); // DLSCH Config - fill_nfapi_dlsch_config(mac, dl_req, ra->msg4_TBsize, mac->pdu_index[CC_idP], ra->rnti, 2, // resource_allocation_type : format 1A/1B/1D + fill_nfapi_dlsch_config(mac, dl_req_body, ra->msg4_TBsize, mac->pdu_index[CC_idP], ra->rnti, 2, // resource_allocation_type : format 1A/1B/1D 0, // virtual_resource_block_assignment_flag : localized getRIV(N_RB_DL, first_rb, 4), // resource_block_coding : RIV, 4 PRB 2, // modulation: QPSK @@ -1247,9 +1350,9 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, 1); // num_bf_vector LOG_D(MAC, "Filled DLSCH config, pdu number %d, non-dci pdu_index %d\n", - dl_req->number_pdu, mac->pdu_index[CC_idP]); + dl_req_body->number_pdu, mac->pdu_index[CC_idP]); - // DL request + // Tx request mac->TX_req[CC_idP].sfn_sf = fill_nfapi_tx_req(&mac->TX_req[CC_idP].tx_request_body, (frameP * 10) + subframeP, @@ -1261,6 +1364,8 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, [0]); mac->pdu_index[CC_idP]++; + dl_req->sfn_sf = mac->TX_req[CC_idP].sfn_sf; + LOG_D(MAC, "Filling UCI ACK/NAK information, cce_idx %d\n", dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx); // Program PUCCH1a for ACK/NAK @@ -1312,7 +1417,8 @@ check_Msg4_retransmission(module_id_t module_idP, int CC_idP, int N_RB_DL; nfapi_dl_config_request_pdu_t *dl_config_pdu; UE_list_t *UE_list = &mac->UE_list; - nfapi_dl_config_request_body_t *dl_req; + nfapi_dl_config_request_t *dl_req; + nfapi_dl_config_request_body_t *dl_req_body; int round; /* @@ -1358,8 +1464,9 @@ check_Msg4_retransmission(module_id_t module_idP, int CC_idP, round = UE_list->UE_sched_ctrl[UE_id].round[CC_idP][ra->harq_pid]; vrb_map = cc[CC_idP].vrb_map; - dl_req = &mac->DL_req[CC_idP].dl_config_request_body; - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + dl_req = &mac->DL_req[CC_idP]; + dl_req_body = &dl_req->dl_config_request_body; + dl_config_pdu = &dl_req_body->dl_config_pdu_list[dl_req_body->number_pdu]; N_RB_DL = to_prb(cc[CC_idP].mib->message.dl_Bandwidth); LOG_D(MAC, @@ -1381,6 +1488,8 @@ check_Msg4_retransmission(module_id_t module_idP, int CC_idP, //ra->wait_ack_Msg4++; // we have to schedule a retransmission + dl_req->sfn_sf = frameP<<4 | subframeP; + first_rb = 0; vrb_map[first_rb] = 1; vrb_map[first_rb + 1] = 1; @@ -1402,14 +1511,16 @@ check_Msg4_retransmission(module_id_t module_idP, int CC_idP, (module_idP, CC_idP, 1, subframeP, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. aggregation_level, ra->rnti)) { - dl_req->number_dci++; - dl_req->number_pdu++; + dl_req_body->number_dci++; + dl_req_body->number_pdu++; + dl_req_body->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; LOG_D(MAC, "msg4 retransmission for rnti %x (round %d) fsf %d/%d\n", ra->rnti, round, frameP, subframeP); // DLSCH Config - fill_nfapi_dlsch_config(mac, dl_req, ra->msg4_TBsize, + //DJP - fix this pdu_index = -1 + fill_nfapi_dlsch_config(mac, dl_req_body, ra->msg4_TBsize, -1 /* retransmission, no pdu_index */ , ra->rnti, 2, // resource_allocation_type : format 1A/1B/1D @@ -1464,6 +1575,7 @@ check_Msg4_retransmission(module_id_t module_idP, int CC_idP, "[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d : Msg4 acknowledged\n", module_idP, CC_idP, frameP, subframeP); ra->state = IDLE; + LOG_I(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:IDLE\n", module_idP, frameP, subframeP); UE_id = find_UE_id(module_idP, ra->rnti); DevAssert(UE_id != -1); mac->UE_list.UE_template[UE_PCCID(module_idP, UE_id)][UE_id]. @@ -1494,6 +1606,8 @@ schedule_RA(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) ra = (RA_t *) & cc[CC_id].ra[i]; + //LOG_D(MAC,"RA[state:%d]\n",ra->state); + if (ra->state == MSG2) generate_Msg2(module_idP, CC_id, frameP, subframeP, ra); else if (ra->state == MSG4) @@ -1548,6 +1662,10 @@ initiate_ra_proc(module_id_t module_idP, module_idP, CC_id, frameP, subframeP, rach_resource_type); #endif + uint16_t msg2_frame = frameP; + uint16_t msg2_subframe = subframeP; + int offset; + if (prach_ParametersListCE_r13 && prach_ParametersListCE_r13->list.count < rach_resource_type) { LOG_E(MAC, @@ -1575,9 +1693,22 @@ initiate_ra_proc(module_id_t module_idP, ra[i].msg2_mpdcch_repetition_cnt = 0; ra[i].msg4_mpdcch_repetition_cnt = 0; #endif - ra[i].Msg2_frame = frameP + ((subframeP > 5) ? 1 : 0); - ra[i].Msg2_subframe = (subframeP + 4) % 10; - /* TODO: find better procedure to allocate RNTI */ + + // DJP - this is because VNF is 2 subframes ahead of PNF and TX needs 4 subframes + if (nfapi_mode) + offset = 7; + else + offset = 5; + + add_subframe(&msg2_frame, &msg2_subframe, offset); + + ra[i].Msg2_frame = msg2_frame; + ra[i].Msg2_subframe = msg2_subframe; + + LOG_D(MAC,"%s() Msg2[%04d%d] SFN/SF:%04d%d offset:%d\n", __FUNCTION__,ra[i].Msg2_frame,ra[i].Msg2_subframe,frameP,subframeP,offset); + + ra[i].Msg2_subframe = (subframeP + offset) % 10; + /* TODO: find better procedure to allocate RNTI */ do { #if defined(USRP_REC_PLAY) // deterministic rnti in usrp record/playback mode static int drnti[NUMBER_OF_UE_MAX] = { 0xbda7, 0x71da, 0x9c40, 0xc350, 0x2710, 0x4e20, 0x7530, 0x1388, 0x3a98, 0x61a8, 0x88b8, 0xafc8, 0xd6d8, 0x1b58, 0x4268, 0x6978 }; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_bch.c b/openair2/LAYER2/MAC/eNB_scheduler_bch.c index 71be9f9b9d..777d8b6061 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_bch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_bch.c @@ -100,6 +100,7 @@ schedule_SIB1_BR(module_id_t module_idP, int n_NB = 0; int TBS; int k = 0, rvidx; + uint16_t sfn_sf = frameP<<4|subframeP; for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { @@ -236,6 +237,7 @@ schedule_SIB1_BR(module_id_t module_idP, dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = TBS; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; @@ -265,14 +267,17 @@ schedule_SIB1_BR(module_id_t module_idP, dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; // Rel10 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = 3; // Rel13 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 1; // CEModeA UE dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 0; // SIB1-BR dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = 0xFFFF; // absolute SFx // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; dl_req->number_pdu++; + dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; // Program TX Request TX_req = @@ -284,9 +289,10 @@ schedule_SIB1_BR(module_id_t module_idP, TX_req->num_segments = 1; TX_req->segments[0].segment_length = bcch_sdu_length; TX_req->segments[0].segment_data = cc->BCCH_BR_pdu[0].payload; - eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; - - + eNB->TX_req[CC_id].sfn_sf = sfn_sf; + eNB->TX_req[CC_id].tx_request_body.tl.tag = NFAPI_TX_REQUEST_BODY_TAG; + eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; + eNB->TX_req[CC_id].header.message_id = NFAPI_TX_REQUEST; if (opt_enabled == 1) { trace_pdu(1, @@ -306,10 +312,7 @@ schedule_SIB1_BR(module_id_t module_idP, "[eNB] Frame %d : Scheduling BCCH-BR 0->DLSCH (FDD) for CC_id %d SIB1-BR %d bytes\n", frameP, CC_id, bcch_sdu_length); } - } - - return; } int si_WindowLength_BR_r13tab @@ -324,7 +327,6 @@ schedule_SI_BR(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) //------------------------------------------------------------------------------ { - int8_t bcch_sdu_length; int CC_id; eNB_MAC_INST *eNB = RC.mac[module_idP]; @@ -338,6 +340,7 @@ schedule_SI_BR(module_id_t module_idP, frame_t frameP, int i; int rvidx; int absSF = (frameP * 10) + subframeP; + uint16_t sfn_sf = frameP << 4 | subframeP; for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { @@ -472,6 +475,7 @@ schedule_SI_BR(module_id_t module_idP, frame_t frameP, dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = si_TBS_r13 >> 3; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = @@ -513,11 +517,13 @@ schedule_SI_BR(module_id_t module_idP, frame_t frameP, dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. num_bf_vector = 1; // Rel10 fields (for PDSCH starting symbol) + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10. pdsch_start = cc[CC_id]. sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; // Rel13 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 1; // CEModeA UE dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 1; // SI-BR dl_config_pdu->dlsch_pdu. @@ -526,6 +532,7 @@ schedule_SI_BR(module_id_t module_idP, frame_t frameP, // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; dl_req->number_pdu++; + dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; // Program TX Request TX_req = @@ -541,6 +548,9 @@ schedule_SI_BR(module_id_t module_idP, frame_t frameP, cc->BCCH_BR_pdu[i + 1].payload; eNB->TX_req[CC_id].tx_request_body. number_of_pdus++; + eNB->TX_req[CC_id].sfn_sf = sfn_sf; + eNB->TX_req[CC_id].tx_request_body.tl.tag = NFAPI_TX_REQUEST_BODY_TAG; + eNB->TX_req[CC_id].header.message_id = NFAPI_TX_REQUEST; if (opt_enabled == 1) { trace_pdu(1, @@ -583,26 +593,26 @@ schedule_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) nfapi_tx_request_pdu_t *TX_req; int mib_sdu_length; int CC_id; + nfapi_dl_config_request_t *dl_config_request; nfapi_dl_config_request_body_t *dl_req; + uint16_t sfn_sf = frameP << 4 | subframeP; AssertFatal(subframeP == 0, "Subframe must be 0\n"); AssertFatal((frameP & 3) == 0, "Frame must be a multiple of 4\n"); for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - dl_req = &eNB->DL_req[CC_id].dl_config_request_body; + dl_config_request = &eNB->DL_req[CC_id]; + dl_req = &dl_config_request->dl_config_request_body; cc = &eNB->common_channels[CC_id]; mib_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, MIBCH, 1, &cc->MIB_pdu.payload[0], 1, module_idP, 0); // not used in this case - LOG_D(MAC, "Frame %d, subframe %d: BCH PDU length %d\n", - frameP, subframeP, mib_sdu_length); + //LOG_D(MAC, "Frame %d, subframe %d: BCH PDU length %d\n", frameP, subframeP, mib_sdu_length); if (mib_sdu_length > 0) { - LOG_D(MAC, - "Frame %d, subframe %d: Adding BCH PDU in position %d (length %d)\n", - frameP, subframeP, dl_req->number_pdu, mib_sdu_length); + //LOG_D(MAC, "Frame %d, subframe %d: Adding BCH PDU in position %d (length %d)\n", frameP, subframeP, dl_req->number_pdu, mib_sdu_length); if ((frameP & 1023) < 40) LOG_D(MAC, @@ -617,14 +627,18 @@ schedule_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_BCH_PDU_TYPE, dl_config_pdu->pdu_size = 2 + sizeof(nfapi_dl_config_bch_pdu); + dl_config_pdu->bch_pdu.bch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_BCH_PDU_REL8_TAG; dl_config_pdu->bch_pdu.bch_pdu_rel8.length = mib_sdu_length; dl_config_pdu->bch_pdu.bch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; dl_config_pdu->bch_pdu.bch_pdu_rel8.transmission_power = 6000; + dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; dl_req->number_pdu++; - LOG_D(MAC, "eNB->DL_req[0].number_pdu %d (%p)\n", - dl_req->number_pdu, &dl_req->number_pdu); + dl_config_request->header.message_id = NFAPI_DL_CONFIG_REQUEST; + dl_config_request->sfn_sf = sfn_sf; + + //LOG_D(MAC, "eNB->DL_req[0].number_pdu %d (%p)\n", dl_req->number_pdu, &dl_req->number_pdu); // DL request TX_req = @@ -633,9 +647,12 @@ schedule_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) TX_req->pdu_length = 3; TX_req->pdu_index = eNB->pdu_index[CC_id]++; TX_req->num_segments = 1; - TX_req->segments[0].segment_length = 0; + TX_req->segments[0].segment_length = 3; TX_req->segments[0].segment_data = cc[CC_id].MIB_pdu.payload; eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; + eNB->TX_req[CC_id].sfn_sf = sfn_sf; + eNB->TX_req[CC_id].tx_request_body.tl.tag = NFAPI_TX_REQUEST_BODY_TAG; + eNB->TX_req[CC_id].header.message_id = NFAPI_TX_REQUEST; } } } @@ -655,9 +672,11 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) uint8_t *vrb_map; int first_rb = -1; int N_RB_DL; - nfapi_dl_config_request_pdu_t *dl_config_pdu; + nfapi_dl_config_request_t *dl_config_request; + nfapi_dl_config_request_pdu_t *dl_config_pdu; nfapi_tx_request_pdu_t *TX_req; nfapi_dl_config_request_body_t *dl_req; + uint16_t sfn_sf = frameP << 4 | subframeP; start_meas(&eNB->schedule_si); @@ -669,15 +688,14 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) cc = &eNB->common_channels[CC_id]; vrb_map = (void *) &cc->vrb_map; N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); + dl_config_request = &eNB->DL_req[CC_id]; dl_req = &eNB->DL_req[CC_id].dl_config_request_body; bcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, BCCH, 1, &cc->BCCH_pdu.payload[0], 1, module_idP, 0); // not used in this case if (bcch_sdu_length > 0) { - LOG_D(MAC, - "[eNB %d] Frame %d : BCCH->DLSCH CC_id %d, Received %d bytes \n", - module_idP, frameP, CC_id, bcch_sdu_length); + //LOG_D(MAC, "[eNB %d] Frame %d : BCCH->DLSCH CC_id %d, Received %d bytes \n", module_idP, frameP, CC_id, bcch_sdu_length); // Allocate 4 PRBs in a random location /* @@ -742,6 +760,7 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. @@ -761,21 +780,13 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) dl_config_pdu->dci_dl_pdu. dci_dl_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 4); - - // Rel10 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = 3; - // Rel13 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 0; // regular UE - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not BR - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = 0xFFFF; // absolute SF + dl_config_request->sfn_sf = sfn_sf; if (!CCE_allocation_infeasible (module_idP, CC_id, 0, subframeP, dl_config_pdu->dci_dl_pdu. dci_dl_pdu_rel8.aggregation_level, SI_RNTI)) { - LOG_D(MAC, - "Frame %d: Subframe %d : Adding common DCI for S_RNTI\n", - frameP, subframeP); + //LOG_D(MAC, "Frame %d: Subframe %d : Adding common DCI for S_RNTI\n", frameP, subframeP); dl_req->number_dci++; dl_req->number_pdu++; dl_config_pdu = @@ -788,6 +799,8 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = bcch_sdu_length; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFF; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized @@ -825,6 +838,18 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; dl_req->number_pdu++; + // Rel10 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = 3; + // Rel13 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 0; // regular UE + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not BR + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = 0xFFFF; // absolute SF + + dl_config_request->header.message_id = NFAPI_DL_CONFIG_REQUEST; + dl_config_request->sfn_sf = sfn_sf; + // Program TX Request TX_req = &eNB->TX_req[CC_id]. @@ -837,6 +862,9 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) TX_req->segments[0].segment_data = cc->BCCH_pdu.payload; eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; + eNB->TX_req[CC_id].sfn_sf = sfn_sf; + eNB->TX_req[CC_id].tx_request_body.tl.tag = NFAPI_TX_REQUEST_BODY_TAG; + eNB->TX_req[CC_id].header.message_id = NFAPI_TX_REQUEST; } else { LOG_E(MAC, @@ -860,9 +888,7 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) "[eNB] Frame %d : Scheduling BCCH->DLSCH (TDD) for CC_id %d SI %d bytes (mcs %d, rb 3)\n", frameP, CC_id, bcch_sdu_length, mcs); } else { - LOG_D(MAC, - "[eNB] Frame %d : Scheduling BCCH->DLSCH (FDD) for CC_id %d SI %d bytes (mcs %d, rb 3)\n", - frameP, CC_id, bcch_sdu_length, mcs); + //LOG_D(MAC, "[eNB] Frame %d : Scheduling BCCH->DLSCH (FDD) for CC_id %d SI %d bytes (mcs %d, rb 3)\n", frameP, CC_id, bcch_sdu_length, mcs); } @@ -881,6 +907,5 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) schedule_SI_BR(module_idP, frameP, subframeP); #endif - stop_meas(&eNB->schedule_si); - return; + stop_meas(&eNB->schedule_si); } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 9dbbb39d03..5687889e96 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -63,6 +63,7 @@ //#define DEBUG_eNB_SCHEDULER 1 extern RAN_CONTEXT_t RC; +extern uint8_t nfapi_mode; //------------------------------------------------------------------------------ void @@ -71,6 +72,7 @@ add_ue_dlsch_info(module_id_t module_idP, int UE_id, sub_frame_t subframeP, UE_DLSCH_STATUS status) //------------------------------------------------------------------------------ { + //LOG_D(MAC, "%s(module_idP:%d, CC_id:%d, UE_id:%d, subframeP:%d, status:%d) serving_num:%d rnti:%x\n", __FUNCTION__, module_idP, CC_id, UE_id, subframeP, status, eNB_dlsch_info[module_idP][CC_id][UE_id].serving_num, UE_RNTI(module_idP,UE_id)); eNB_dlsch_info[module_idP][CC_id][UE_id].rnti = UE_RNTI(module_idP, UE_id); @@ -545,7 +547,7 @@ schedule_ue_spec(module_id_t module_idP, (VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_OUT); for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n", CC_id); + //LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n", CC_id); dl_req = &eNB->DL_req[CC_id].dl_config_request_body; @@ -654,8 +656,12 @@ schedule_ue_spec(module_id_t module_idP, DevCheck(((eNB_UE_stats->dl_cqi < MIN_CQI_VALUE) || (eNB_UE_stats->dl_cqi > MAX_CQI_VALUE)), eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE); */ - eNB_UE_stats->dlsch_mcs1 = - cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]]; + if (nfapi_mode) { + eNB_UE_stats->dlsch_mcs1 = 10;//cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]]; + } + else { + eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]]; + } eNB_UE_stats->dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1; //cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); @@ -669,7 +675,7 @@ schedule_ue_spec(module_id_t module_idP, = 0; } - LOG_D(MAC, + LOG_I(MAC, "[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n", module_idP, frameP, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb, ue_sched_ctl->dl_cqi[CC_id], @@ -755,6 +761,8 @@ schedule_ue_spec(module_id_t module_idP, case 2: case 7: default: + LOG_I(MAC,"retransmission DL_REQ: rnti:%x\n",rnti); + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req-> number_pdu]; @@ -765,6 +773,7 @@ schedule_ue_spec(module_id_t module_idP, dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. dci_format = NFAPI_DL_DCI_FORMAT_1; dl_config_pdu->dci_dl_pdu. @@ -820,6 +829,10 @@ schedule_ue_spec(module_id_t module_idP, dci_dl_pdu_rel8.aggregation_level, rnti)) { dl_req->number_dci++; dl_req->number_pdu++; + dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + + eNB->DL_req[CC_id].sfn_sf = frameP<<4 | subframeP; + eNB->DL_req[CC_id].header.message_id = NFAPI_DL_CONFIG_REQUEST; fill_nfapi_dlsch_config(eNB, dl_req, TBS, -1 /* retransmission, no pdu_index */ @@ -1210,8 +1223,8 @@ schedule_ue_spec(module_id_t module_idP, padding, post_padding); //#ifdef DEBUG_eNB_SCHEDULER - if (ta_update != 31) { - LOG_D(MAC, + if (1 || ta_update != 31) { + LOG_I(MAC, "[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n", module_idP, frameP, UE_id, CC_id, sdu_length_total, num_sdus, sdu_lengths[0], @@ -1364,6 +1377,7 @@ schedule_ue_spec(module_id_t module_idP, get_aggregation(get_bw_index(module_idP, CC_id), ue_sched_ctl->dl_cqi[CC_id], format1); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power @@ -1410,6 +1424,10 @@ schedule_ue_spec(module_id_t module_idP, ue_sched_ctl->round[CC_id][harq_pid] = 0; dl_req->number_dci++; dl_req->number_pdu++; + dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + + eNB->DL_req[CC_id].sfn_sf = frameP<<4 | subframeP; + eNB->DL_req[CC_id].header.message_id = NFAPI_DL_CONFIG_REQUEST; // Toggle NDI for next time LOG_D(MAC, @@ -1535,7 +1553,7 @@ fill_DLSCH_dci(module_id_t module_idP, (VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI, VCD_FUNCTION_IN); for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - LOG_D(MAC, "Doing fill DCI for CC_id %d\n", CC_id); + //LOG_D(MAC, "Doing fill DCI for CC_id %d\n", CC_id); if (mbsfn_flagP[CC_id] > 0) continue; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index df84675dc1..7bba9145fc 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -1013,6 +1013,7 @@ get_rel8_dl_cqi_pmi_size(UE_sched_ctrl * sched_ctl, int CC_idP, else return (7 + Ltab[cc->mib->message.dl_Bandwidth]); } + AssertFatal(1 == 0, "Shouldn't get here : cqi_ReportPeriodic->present %d\n", cqi_ReportPeriodic->choice. @@ -1035,6 +1036,8 @@ fill_nfapi_dl_dci_1A(nfapi_dl_config_request_pdu_t * dl_config_pdu, dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = + NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = @@ -1129,6 +1132,7 @@ program_dlsch_acknak(module_id_t module_idP, int CC_idP, int UE_idP, &ul_config_pdu->ulsch_harq_pdu.harq_information; ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE; + ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.tl.tag=NFAPI_UL_CONFIG_REQUEST_INITIAL_TRANSMISSION_PARAMETERS_REL8_TAG; ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial = 0; // last symbol not punctured ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks = ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks; // we don't change the number of resource blocks across retransmissions yet LOG_D(MAC, @@ -1159,6 +1163,7 @@ program_dlsch_acknak(module_id_t module_idP, int CC_idP, int UE_idP, * Those two types are not compatible. 'initial_transmission_parameters' is not at the * place in both. */ + ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.tl.tag=NFAPI_UL_CONFIG_REQUEST_INITIAL_TRANSMISSION_PARAMETERS_REL8_TAG; ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial = 0; // last symbol not punctured ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks = ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks; // we don't change the number of resource blocks across retransmissions yet break; @@ -1358,6 +1363,7 @@ fill_nfapi_harq_information(module_id_t module_idP, "physicalConfigDedicated for rnti %x is null\n", rntiP); #endif + harq_information->harq_information_rel11.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL11_TAG; harq_information->harq_information_rel11.num_ant_ports = 1; switch (get_tmode(module_idP, CC_idP, UE_id)) { @@ -1386,12 +1392,14 @@ fill_nfapi_harq_information(module_id_t module_idP, harq_information->harq_information_rel10_tdd.harq_size = 1; // 1-bit ACK/NAK harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling } + harq_information->harq_information_rel10_tdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG; harq_information->harq_information_rel10_tdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon. n1PUCCH_AN + cce_idxP; harq_information-> harq_information_rel10_tdd.number_of_pucch_resources = 1; } else { + harq_information->harq_information_rel9_fdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG; harq_information-> harq_information_rel9_fdd.number_of_pucch_resources = 1; harq_information->harq_information_rel9_fdd.harq_size = 1; // 1-bit ACK/NAK @@ -1419,6 +1427,7 @@ fill_nfapi_harq_information(module_id_t module_idP, } else { harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling } + harq_information->harq_information_rel10_tdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG; harq_information->harq_information_rel10_tdd.harq_size = 2; harq_information->harq_information_rel10_tdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon. @@ -1426,6 +1435,7 @@ fill_nfapi_harq_information(module_id_t module_idP, harq_information-> harq_information_rel10_tdd.number_of_pucch_resources = 1; } else { + harq_information->harq_information_rel9_fdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG; harq_information-> harq_information_rel9_fdd.number_of_pucch_resources = 1; harq_information->harq_information_rel9_fdd.ack_nack_mode = 0; // 1a/b @@ -1447,16 +1457,17 @@ fill_nfapi_uci_acknak(module_id_t module_idP, COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; int ackNAK_absSF = get_pucch1_absSF(cc, absSFP); - nfapi_ul_config_request_body_t *ul_req = - &eNB->UL_req_tmp[CC_idP][ackNAK_absSF % 10].ul_config_request_body; + nfapi_ul_config_request_t *ul_req = &eNB->UL_req_tmp[CC_idP][ackNAK_absSF % 10]; + nfapi_ul_config_request_body_t *ul_req_body = &ul_req->ul_config_request_body; nfapi_ul_config_request_pdu_t *ul_config_pdu = - &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; + &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus]; memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t)); ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE; ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_uci_harq_pdu)); + ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.handle = 0; // don't know how to use this ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti = rntiP; @@ -1473,7 +1484,11 @@ fill_nfapi_uci_acknak(module_id_t module_idP, ul_config_pdu->uci_harq_pdu. harq_information.harq_information_rel9_fdd.n_pucch_1_0); - ul_req->number_of_pdus++; + ul_req_body->number_of_pdus++; + ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + + ul_req->header.message_id = NFAPI_UL_CONFIG_REQUEST; + ul_req->sfn_sf = (ackNAK_absSF/10) << 4 | ackNAK_absSF%10; return (((ackNAK_absSF / 10) << 4) + (ackNAK_absSF % 10)); } @@ -1513,6 +1528,7 @@ fill_nfapi_dlsch_config(eNB_MAC_INST * eNB, dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = length; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = pdu_index; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = rnti; @@ -1567,6 +1583,7 @@ fill_nfapi_tx_req(nfapi_tx_request_body_t * tx_req_body, TX_req->num_segments = 1; TX_req->segments[0].segment_length = pdu_length; TX_req->segments[0].segment_data = pdu; + tx_req_body->tl.tag = NFAPI_TX_REQUEST_BODY_TAG; tx_req_body->number_of_pdus++; return (((absSF / 10) << 4) + (absSF % 10)); @@ -1601,6 +1618,7 @@ fill_nfapi_ulsch_config_request_rel8(nfapi_ul_config_request_pdu_t * ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu)); + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = handle; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = rnti; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = @@ -1635,6 +1653,7 @@ fill_nfapi_ulsch_config_request_rel8(nfapi_ul_config_request_pdu_t * ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE; ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_cqi_ri_pdu)); + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL9_TAG; ul_config_pdu->ulsch_cqi_ri_pdu. cqi_ri_information.cqi_ri_information_rel9.report_type = 1; ul_config_pdu->ulsch_cqi_ri_pdu. @@ -1700,6 +1719,7 @@ fill_nfapi_ulsch_config_request_emtc(nfapi_ul_config_request_pdu_t * { // Re13 fields + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL13_TAG; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.ue_type = ue_type; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.total_number_of_repetitions = total_number_of_repetitions; @@ -2010,8 +2030,7 @@ get_aggregation(uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt) LOG_W(MAC, "unsupported DCI format %d\n", dci_fmt); } - LOG_D(MAC, "Aggregation level %d (cqi %d, bw_index %d, format %d)\n", - 1 << aggregation, cqi, bw_index, dci_fmt); + //LOG_D(MAC, "Aggregation level %d (cqi %d, bw_index %d, format %d)\n", 1 << aggregation, cqi, bw_index, dci_fmt); return 1 << aggregation; } @@ -3081,10 +3100,11 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) int i, j, idci; int nCCE = 0; - LOG_D(MAC, - "Allocate CCEs subframe %d, test %d : (DL PDU %d, DL DCI %d, UL %d)\n", - subframeP, test_onlyP, DL_req->number_pdu, DL_req->number_dci, - HI_DCI0_req->number_of_dci); + if (0 && (DL_req->number_pdu || DL_req->number_dci || HI_DCI0_req->number_of_dci)) + LOG_D(MAC, + "Allocate CCEs subframe %d, test %d : (DL PDU %d, DL DCI %d, UL %d)\n", + subframeP, test_onlyP, DL_req->number_pdu, DL_req->number_dci, + HI_DCI0_req->number_of_dci); DL_req->number_pdcch_ofdm_symbols = 1; try_again: @@ -3096,6 +3116,7 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) && (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type == 2)) { +#if 0 LOG_D(MAC, "Trying to allocate COMMON DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", idci, DL_req->number_dci + HI_DCI0_req->number_of_dci, @@ -3104,6 +3125,7 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) dl_config_pdu[i].dci_dl_pdu. dci_dl_pdu_rel8.aggregation_level, nCCE, nCCE_max, DL_req->number_pdcch_ofdm_symbols); +#endif if (nCCE + (dl_config_pdu[i].dci_dl_pdu. @@ -3175,14 +3197,16 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) nCCE += dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8. aggregation_level; - LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); + //LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); if (test_onlyP == 0) { dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = fCCE; +#if 0 LOG_D(MAC, "Allocate COMMON DCI CCEs subframe %d, test %d => L %d fCCE %d\n", subframeP, test_onlyP, dl_config_pdu[i].dci_dl_pdu. dci_dl_pdu_rel8.aggregation_level, fCCE); +#endif } idci++; } @@ -3269,7 +3293,7 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) // the allocation is feasible, rnti rule passes nCCE += hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level; - LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); + //LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); if (test_onlyP == 0) { hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.cce_index = fCCE; LOG_D(MAC, "Allocate CCEs subframe %d, test %d\n", @@ -3284,6 +3308,7 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) && (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type == 1)) { +#if 0 LOG_D(MAC, "Trying to allocate DL UE-SPECIFIC DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", idci, DL_req->number_dci + HI_DCI0_req->number_of_dci, @@ -3292,6 +3317,7 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) dl_config_pdu[i].dci_dl_pdu. dci_dl_pdu_rel8.aggregation_level, nCCE, nCCE_max, DL_req->number_pdcch_ofdm_symbols); +#endif if (nCCE + (dl_config_pdu[i].dci_dl_pdu. @@ -3364,7 +3390,7 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) nCCE += dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8. aggregation_level; - LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); + //LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); if (test_onlyP == 0) { dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = fCCE; LOG_D(MAC, "Allocate CCEs subframe %d, test %d\n", @@ -3532,6 +3558,7 @@ CCE_allocation_infeasible(int module_idP, "Subframe %d: FAPI DL structure is full, skip scheduling UE %d\n", subframe, rnti); } else { + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = @@ -3539,6 +3566,7 @@ CCE_allocation_infeasible(int module_idP, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = aggregation; DL_req->number_pdu++; +#if 0 LOG_D(MAC, "Subframe %d: Checking CCE feasibility format %d : (%x,%d) (%x,%d,%d)\n", subframe, format_flag, rnti, aggregation, @@ -3546,6 +3574,7 @@ CCE_allocation_infeasible(int module_idP, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. aggregation_level, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type); +#endif ret = allocate_CCEs(module_idP, CC_idP, subframe, 0); if (ret == -1) res = TRUE; @@ -3559,6 +3588,7 @@ CCE_allocation_infeasible(int module_idP, subframe, rnti); } else { hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL8_TAG; hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti = rnti; hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level = aggregation; @@ -3644,6 +3674,8 @@ extract_harq(module_id_t mod_idP, int CC_idP, int UE_id, uint8_t harq_pid = ((10 * frameP) + subframeP + 10236) & 7; + LOG_I(MAC,"frame %d subframe %d harq_pid %d mode %d tmode[0] %d num_ack_nak %d round %d\n",frameP,subframeP,harq_pid,harq_indication_fdd->mode,tmode[0],num_ack_nak,sched_ctl->round[CC_idP][harq_pid]); + switch (harq_indication_fdd->mode) { case 0: // Format 1a/b (10.1.2.1) AssertFatal(numCC == 1, @@ -3652,8 +3684,8 @@ extract_harq(module_id_t mod_idP, int CC_idP, int UE_id, if (tmode[0] == 1 || tmode[0] == 2 || tmode[0] == 5 || tmode[0] == 6 || tmode[0] == 7) { // NOTE: have to handle the case of TM9-10 with 1 antenna port // single ACK/NAK bit AssertFatal(num_ack_nak == 1, - "num_ack_nak %d > 1 for 1 CC and single-layer transmission\n", - num_ack_nak); + "num_ack_nak %d > 1 for 1 CC and single-layer transmission frame:%d subframe:%d\n", + num_ack_nak,frameP,subframeP); AssertFatal(sched_ctl->round[CC_idP][harq_pid] < 8, "Got ACK/NAK for inactive harq_pid %d for UE %d/%x\n", harq_pid, UE_id, rnti); @@ -4336,6 +4368,8 @@ cqi_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, if (UE_id >= 0) { + LOG_E(MAC,"%s() UE_id:%d channel:%d cqi:%d\n", __FUNCTION__, UE_id, ul_cqi_information->channel, ul_cqi_information->ul_cqi); + if (ul_cqi_information->channel == 0) { // PUCCH // extract pucch csi information before changing RI information @@ -4442,7 +4476,7 @@ harq_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; // extract HARQ Information - LOG_D(MAC, + LOG_I(MAC, "Frame %d, subframe %d: Received harq indication (%d) from UE %d/%x, ul_cqi %d\n", frameP, subframeP, channel, UE_id, rnti, ul_cqi); if (cc->tdd_Config) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 421eab7cd7..405c7d2a75 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -62,6 +62,14 @@ #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_eNB_SCHEDULER 1 +extern int oai_nfapi_hi_dci0_req(nfapi_hi_dci0_request_t *hi_dci0_req); +extern void add_subframe(uint16_t *frameP, uint16_t *subframeP, int offset); +extern uint16_t sfnsf_add_subframe(uint16_t frameP, uint16_t subframeP, int offset); +extern int oai_nfapi_ul_config_req(nfapi_ul_config_request_t *ul_config_req); +extern uint8_t nfapi_mode; + +extern uint8_t nfapi_mode; + // This table holds the allowable PRB sizes for ULSCH transmissions uint8_t rb_table[34] = { 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, @@ -751,18 +759,22 @@ rx_sdu(const module_id_t enb_mod_idP, LOG_D(MAC, "Programming PHICH ACK for rnti %x harq_pid %d (first_rb %d)\n", current_rnti, harq_pid, first_rb); - nfapi_hi_dci0_request_body_t *hi_dci0_req = - &mac->HI_DCI0_req[CC_idP].hi_dci0_request_body; + nfapi_hi_dci0_request_t *hi_dci0_req = &mac->HI_DCI0_req[CC_idP]; + nfapi_hi_dci0_request_body_t *hi_dci0_req_body = &hi_dci0_req->hi_dci0_request_body; nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = - &hi_dci0_req->hi_dci0_pdu_list[hi_dci0_req->number_of_dci + - hi_dci0_req->number_of_hi]; + &hi_dci0_req_body->hi_dci0_pdu_list[hi_dci0_req_body->number_of_dci + hi_dci0_req_body->number_of_hi]; memset((void *) hi_dci0_pdu, 0, sizeof(nfapi_hi_dci0_request_pdu_t)); hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; hi_dci0_pdu->pdu_size = 2 + sizeof(nfapi_hi_dci0_hi_pdu); + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_HI_PDU_REL8_TAG; hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = first_rb; hi_dci0_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = 0; hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 1; - hi_dci0_req->number_of_hi++; + hi_dci0_req_body->number_of_hi++; + hi_dci0_req_body->sfnsf = sfnsf_add_subframe(frameP,subframeP, 0); + hi_dci0_req_body->tl.tag = NFAPI_HI_DCI0_REQUEST_BODY_TAG; + hi_dci0_req->sfn_sf = sfnsf_add_subframe(frameP,subframeP, 4); + hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST; /* NN--> FK: we could either check the payload, or use a phy helper to detect a false msg3 */ if ((num_sdu == 0) && (num_ce == 0)) { @@ -1024,7 +1036,6 @@ schedule_ulsch(module_id_t module_idP, frame_t frameP, // Msg3 is using 1 PRB so we need to increase first_rb accordingly // not sure about the break (can there be more than 1 active RA procedure?) - for (i = 0; i < NB_RA_PROC_MAX; i++) { if ((cc->ra[i].state == WAITMSG3) && (cc->ra[i].Msg3_subframe == sched_subframe)) { @@ -1073,19 +1084,19 @@ schedule_ulsch_rnti(module_id_t module_idP, if (sched_subframeP < subframeP) sched_frame++; - nfapi_hi_dci0_request_body_t *hi_dci0_req = - &mac->HI_DCI0_req[CC_id].hi_dci0_request_body; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu; + nfapi_hi_dci0_request_t *hi_dci0_req = &mac->HI_DCI0_req[CC_id]; + nfapi_hi_dci0_request_body_t *hi_dci0_req_body = &hi_dci0_req->hi_dci0_request_body; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu; - nfapi_ul_config_request_body_t *ul_req_tmp = - &mac->UL_req_tmp[CC_id][sched_subframeP].ul_config_request_body; + nfapi_ul_config_request_t *ul_req_tmp = &mac->UL_req_tmp[CC_id][sched_subframeP]; + nfapi_ul_config_request_body_t *ul_req_tmp_body = &ul_req_tmp->ul_config_request_body; - LOG_D(MAC, "entering ulsch preprocesor\n"); + //LOG_D(MAC, "entering ulsch preprocesor\n"); ulsch_scheduler_pre_processor(module_idP, frameP, subframeP, first_rb); - LOG_D(MAC, "exiting ulsch preprocesor\n"); + //LOG_D(MAC, "exiting ulsch preprocesor\n"); - mac->HI_DCI0_req[CC_id].sfn_sf = (frameP << 4) + subframeP; + hi_dci0_req->sfn_sf = (frameP << 4) + subframeP; // loop over all active UEs for (UE_id = UE_list->head_ul; UE_id >= 0; @@ -1210,7 +1221,11 @@ schedule_ulsch_rnti(module_id_t module_idP, if (status < RRC_CONNECTED) cqi_req = 0; else if (UE_sched_ctrl->cqi_req_timer > 30) { - cqi_req = 1; + if (nfapi_mode) { + cqi_req = 0; + } else { + cqi_req = 1; + } UE_sched_ctrl->cqi_req_timer = 0; } else cqi_req = 0; @@ -1220,7 +1235,7 @@ schedule_ulsch_rnti(module_id_t module_idP, // this is the normalized RX power and this should be constant (regardless of mcs normalized_rx_power = UE_sched_ctrl->pusch_snr[CC_id]; - target_rx_power = 178; + target_rx_power = 204; // this assumes accumulated tpc // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out @@ -1343,20 +1358,13 @@ schedule_ulsch_rnti(module_id_t module_idP, // save it for a potential retransmission UE_template->cshift[harq_pid] = cshift; - hi_dci0_pdu = - &hi_dci0_req->hi_dci0_pdu_list[mac->HI_DCI0_req - [CC_id]. - hi_dci0_request_body. - number_of_dci + - mac->HI_DCI0_req - [CC_id]. - hi_dci0_request_body. - number_of_hi]; + hi_dci0_pdu = &hi_dci0_req_body->hi_dci0_pdu_list[hi_dci0_req_body->number_of_dci + hi_dci0_req_body->number_of_hi]; memset((void *) hi_dci0_pdu, 0, sizeof(nfapi_hi_dci0_request_pdu_t)); hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE; hi_dci0_pdu->pdu_size = 2 + sizeof(nfapi_hi_dci0_dci_pdu); + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL8_TAG; hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dci_format = NFAPI_UL_DCI_FORMAT_0; hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level = @@ -1383,8 +1391,13 @@ schedule_ulsch_rnti(module_id_t module_idP, hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dl_assignment_index = UE_template->DAI_ul[sched_subframeP]; - mac->HI_DCI0_req[CC_id].hi_dci0_request_body. - number_of_dci++; + hi_dci0_req_body->number_of_dci++; + hi_dci0_req_body->sfnsf = sfnsf_add_subframe(frameP, subframeP, 4); + hi_dci0_req_body->tl.tag = NFAPI_HI_DCI0_REQUEST_BODY_TAG; + + hi_dci0_req->sfn_sf = frameP<<4|subframeP; // sfnsf_add_subframe(sched_frame, sched_subframeP, 0); // sunday! + hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST; + LOG_D(MAC, "[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n", @@ -1392,7 +1405,7 @@ schedule_ulsch_rnti(module_id_t module_idP, sched_frame, sched_subframeP); // Add UL_config PDUs - fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], cqi_req, cc, UE_template->physicalConfigDedicated, get_tmode(module_idP, CC_id, UE_id), mac->ul_handle, rnti, first_rb[CC_id], // resource_block_start + fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp_body->ul_config_pdu_list[ul_req_tmp_body->number_of_pdus], cqi_req, cc, UE_template->physicalConfigDedicated, get_tmode(module_idP, CC_id, UE_id), mac->ul_handle, rnti, first_rb[CC_id], // resource_block_start rb_table[rb_table_index], // number_of_resource_blocks UE_template->mcs_UL[harq_pid], cshift, // cyclic_shift_2_for_drms 0, // frequency_hopping_enabled_flag @@ -1410,23 +1423,30 @@ schedule_ulsch_rnti(module_id_t module_idP, [rb_table_index])); #ifdef Rel14 if (UE_template->rach_resource_type > 0) { // This is a BL/CE UE allocation - fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], UE_template->rach_resource_type > 2 ? 2 : 1, 1, //total_number_of_repetitions + fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp_body->ul_config_pdu_list[ul_req_tmp_body->number_of_pdus], UE_template->rach_resource_type > 2 ? 2 : 1, 1, //total_number_of_repetitions 1, //repetition_number (frameP * 10) + subframeP); } #endif - ul_req_tmp->number_of_pdus++; + ul_req_tmp->header.message_id = NFAPI_UL_CONFIG_REQUEST; + ul_req_tmp_body->number_of_pdus++; + ul_req_tmp_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; mac->ul_handle++; + uint16_t ul_sched_frame = sched_frame; + uint16_t ul_sched_subframeP = sched_subframeP; + + add_subframe(&ul_sched_frame, &ul_sched_subframeP, 2); + ul_req_tmp->sfn_sf = ul_sched_frame<<4|ul_sched_subframeP; + add_ue_ulsch_info(module_idP, CC_id, UE_id, subframeP, S_UL_SCHEDULED); - LOG_D(MAC, - "[eNB %d] CC_id %d Frame %d, subframeP %d: Generated ULSCH DCI for next UE_id %d, format 0\n", - module_idP, CC_id, frameP, subframeP, UE_id); + //LOG_D(MAC, "[eNB %d] CC_id %d Frame %d, subframeP %d: Generated ULSCH DCI for next UE_id %d, format 0\n", module_idP, CC_id, frameP, subframeP, UE_id); + LOG_D(MAC,"[PUSCH %d] SFN/SF:%04d%d UL_CFG:SFN/SF:%04d%d CQI:%d for UE %d/%x\n", harq_pid,frameP,subframeP,ul_sched_frame,ul_sched_subframeP,cqi_req,UE_id,rnti); // increment first rb for next UE allocation first_rb[CC_id] += rb_table[rb_table_index]; @@ -1440,23 +1460,24 @@ schedule_ulsch_rnti(module_id_t module_idP, // fill in NAK information - hi_dci0_pdu = - &hi_dci0_req->hi_dci0_pdu_list[hi_dci0_req-> - number_of_dci + - hi_dci0_req-> - number_of_hi]; + hi_dci0_pdu = &hi_dci0_req_body->hi_dci0_pdu_list[hi_dci0_req_body->number_of_dci + hi_dci0_req_body->number_of_hi]; memset((void *) hi_dci0_pdu, 0, sizeof(nfapi_hi_dci0_request_pdu_t)); hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; hi_dci0_pdu->pdu_size = 2 + sizeof(nfapi_hi_dci0_hi_pdu); + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_HI_PDU_REL8_TAG; hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = UE_template->first_rb_ul[harq_pid]; hi_dci0_pdu->hi_pdu.hi_pdu_rel8. cyclic_shift_2_for_drms = UE_template->cshift[harq_pid]; hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 0; - hi_dci0_req->number_of_hi++; + hi_dci0_req_body->number_of_hi++; + hi_dci0_req_body->sfnsf = sfnsf_add_subframe(sched_frame, sched_subframeP, 0); + hi_dci0_req->sfn_sf = frameP<<4|subframeP; + hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST; + LOG_D(MAC, "[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled (PHICH) UE %d (mcs %d, first rb %d, nb_rb %d, TBS %d, round %d)\n", module_idP, harq_pid, rnti, CC_id, frameP, @@ -1469,7 +1490,7 @@ schedule_ulsch_rnti(module_id_t module_idP, "[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n", harq_pid, frameP, subframeP, UE_id, rnti, sched_frame, sched_subframeP); - fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], cqi_req, cc, UE_template->physicalConfigDedicated, get_tmode(module_idP, CC_id, UE_id), mac->ul_handle, rnti, UE_template->first_rb_ul[harq_pid], // resource_block_start + fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp_body->ul_config_pdu_list[ul_req_tmp_body->number_of_pdus], cqi_req, cc, UE_template->physicalConfigDedicated, get_tmode(module_idP, CC_id, UE_id), mac->ul_handle, rnti, UE_template->first_rb_ul[harq_pid], // resource_block_start UE_template->nb_rb_ul[harq_pid], // number_of_resource_blocks UE_template->mcs_UL[harq_pid], cshift, // cyclic_shift_2_for_drms 0, // frequency_hopping_enabled_flag @@ -1484,16 +1505,23 @@ schedule_ulsch_rnti(module_id_t module_idP, TBS_UL[harq_pid]); #ifdef Rel14 if (UE_template->rach_resource_type > 0) { // This is a BL/CE UE allocation - fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp->ul_config_pdu_list[ul_req_tmp->number_of_pdus], UE_template->rach_resource_type > 2 ? 2 : 1, 1, //total_number_of_repetitions + fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp_body->ul_config_pdu_list[ul_req_tmp_body->number_of_pdus], UE_template->rach_resource_type > 2 ? 2 : 1, 1, //total_number_of_repetitions 1, //repetition_number (frameP * 10) + subframeP); } #endif - ul_req_tmp->number_of_pdus++; + ul_req_tmp_body->number_of_pdus++; mac->ul_handle++; + ul_req_tmp_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + + ul_req_tmp->sfn_sf = sched_frame<<4|sched_subframeP; + ul_req_tmp->header.message_id = NFAPI_UL_CONFIG_REQUEST; + + LOG_D(MAC,"[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d cqi_req %d\n", + harq_pid,frameP,subframeP,UE_id,rnti,sched_frame,sched_subframeP,cqi_req); } /* else if (round > 0) { //we schedule a retransmission diff --git a/openair2/LAYER2/MAC/main.c b/openair2/LAYER2/MAC/main.c index 534f603dfd..0feea028aa 100644 --- a/openair2/LAYER2/MAC/main.c +++ b/openair2/LAYER2/MAC/main.c @@ -47,6 +47,7 @@ #include "common/ran_context.h" extern RAN_CONTEXT_t RC; +extern void openair_rrc_top_init_ue( int eMBMS_active, char* uecap_xer, uint8_t cba_group_active, uint8_t HO_active); void dl_phy_sync_success(module_id_t module_idP, frame_t frameP, unsigned char eNB_index, uint8_t first_sync) //init as MR { @@ -118,7 +119,7 @@ mac_top_init_ue(int eMBMS_active, char *uecap_xer, } -void mac_top_init_eNB() +void mac_top_init_eNB(void) { module_id_t i, j; @@ -275,7 +276,7 @@ l2_init_ue(int eMBMS_active, char *uecap_xer, uint8_t cba_group_active, return (1); } -int l2_init_eNB() +int l2_init_eNB(void) { diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 23d3f3bd60..11fd11e4b8 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -1234,8 +1234,7 @@ dlsch_scheduler_pre_processor_reset(int module_idP, break; } } - LOG_D(MAC, "Frame %d Subframe %d CC_id %d RBG %i : rb_alloc %d\n", - frameP, subframeP, CC_id, i, rballoc_sub[CC_id][i]); + //LOG_D(MAC, "Frame %d Subframe %d CC_id %d RBG %i : rb_alloc %d\n", frameP, subframeP, CC_id, i, rballoc_sub[CC_id][i]); MIMO_mode_indicator[CC_id][i] = 2; } } @@ -1340,11 +1339,11 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, UE_TEMPLATE *UE_template = 0; int N_RB_DL; int N_RB_UL; - LOG_D(MAC, "In ulsch_preprocessor: assign max mcs min rb\n"); + //LOG_D(MAC, "In ulsch_preprocessor: assign max mcs min rb\n"); // maximize MCS and then allocate required RB according to the buffer occupancy with the limit of max available UL RB assign_max_mcs_min_rb(module_idP, frameP, subframeP, first_rb); - LOG_D(MAC, "In ulsch_preprocessor: sort ue \n"); + //LOG_D(MAC, "In ulsch_preprocessor: sort ue \n"); // sort ues sort_ue_ul(module_idP, frameP, subframeP); @@ -1367,7 +1366,7 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, } } - LOG_D(MAC, "In ulsch_preprocessor: step2 \n"); + //LOG_D(MAC, "In ulsch_preprocessor: step2 \n"); // step 2: calculate the average rb per UE total_ue_count = 0; max_num_ue_to_be_scheduled = 0; @@ -1385,12 +1384,11 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, UE_id = i; - LOG_D(MAC, "In ulsch_preprocessor: handling UE %d/%x\n", UE_id, - rnti); + //LOG_D(MAC, "In ulsch_preprocessor: handling UE %d/%x\n", UE_id, rnti); for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { // This is the actual CC_id in the list CC_id = UE_list->ordered_ULCCids[n][UE_id]; - LOG_D(MAC, + if(0)LOG_D(MAC, "In ulsch_preprocessor: handling UE %d/%x CCid %d\n", UE_id, rnti, CC_id); UE_template = &UE_list->UE_template[CC_id][UE_id]; @@ -1470,7 +1468,7 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, } total_allocated_rbs[CC_id] += nb_allocated_rbs[CC_id][UE_id]; - LOG_D(MAC, + if(0)LOG_D(MAC, "In ulsch_preprocessor: assigning %d RBs for UE %d/%x CCid %d, harq_pid %d\n", nb_allocated_rbs[CC_id][UE_id], UE_id, rnti, CC_id, harq_pid); diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index 6dffada99d..e65bbf1db0 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -92,6 +92,8 @@ extern Packet_OTG_List_t *otg_pdcp_buffer; # include "gtpv1u_eNB_defs.h" #endif +extern int gtpv1u_new_data_req( uint8_t enb_module_idP, rnti_t ue_rntiP, uint8_t rab_idP, uint8_t *buffer_pP, uint32_t buf_lenP, uint32_t buf_offsetP); + /* Prevent de-queueing the same PDCP SDU from the queue twice * by multiple threads. This has happened in TDD when thread-odd * is flushing a PDCP SDU after UE_RX() processing; whereas diff --git a/openair2/PHY_INTERFACE/IF_Module.c b/openair2/PHY_INTERFACE/IF_Module.c index ab6551f61c..6402f3322f 100644 --- a/openair2/PHY_INTERFACE/IF_Module.c +++ b/openair2/PHY_INTERFACE/IF_Module.c @@ -10,21 +10,29 @@ IF_Module_t *if_inst[MAX_IF_MODULES]; Sched_Rsp_t Sched_INFO[MAX_IF_MODULES][MAX_NUM_CCs]; +extern int oai_nfapi_harq_indication(nfapi_harq_indication_t *harq_ind); +extern int oai_nfapi_crc_indication(nfapi_crc_indication_t *crc_ind); +extern int oai_nfapi_cqi_indication(nfapi_cqi_indication_t *cqi_ind); +extern int oai_nfapi_sr_indication(nfapi_sr_indication_t *ind); +extern int oai_nfapi_rx_ind(nfapi_rx_indication_t *ind); +extern uint8_t nfapi_mode; +extern uint16_t sf_ahead; + void handle_rach(UL_IND_t *UL_info) { int i; - if (UL_info->rach_ind.number_of_preambles>0) { + if (UL_info->rach_ind.rach_indication_body.number_of_preambles>0) { - AssertFatal(UL_info->rach_ind.number_of_preambles==1,"More than 1 preamble not supported\n"); - UL_info->rach_ind.number_of_preambles=0; - LOG_D(MAC,"Frame %d, Subframe %d Calling initiate_ra_proc\n",UL_info->frame,UL_info->subframe); + AssertFatal(UL_info->rach_ind.rach_indication_body.number_of_preambles==1,"More than 1 preamble not supported\n"); + UL_info->rach_ind.rach_indication_body.number_of_preambles=0; + LOG_D(MAC,"UL_info[Frame %d, Subframe %d] Calling initiate_ra_proc RACH:SFN/SF:%d\n",UL_info->frame,UL_info->subframe, NFAPI_SFNSF2DEC(UL_info->rach_ind.sfn_sf)); initiate_ra_proc(UL_info->module_id, UL_info->CC_id, - UL_info->frame, - UL_info->subframe, - UL_info->rach_ind.preamble_list[0].preamble_rel8.preamble, - UL_info->rach_ind.preamble_list[0].preamble_rel8.timing_advance, - UL_info->rach_ind.preamble_list[0].preamble_rel8.rnti + NFAPI_SFNSF2SFN(UL_info->rach_ind.sfn_sf), + NFAPI_SFNSF2SF(UL_info->rach_ind.sfn_sf), + UL_info->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.preamble, + UL_info->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.timing_advance, + UL_info->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.rnti #ifdef Rel14 ,0 #endif @@ -32,24 +40,24 @@ void handle_rach(UL_IND_t *UL_info) { } #ifdef Rel14 - if (UL_info->rach_ind_br.number_of_preambles>0) { + if (UL_info->rach_ind_br.rach_indication_body.number_of_preambles>0) { - AssertFatal(UL_info->rach_ind_br.number_of_preambles<5,"More than 4 preambles not supported\n"); - for (i=0;irach_ind_br.number_of_preambles;i++) { - AssertFatal(UL_info->rach_ind_br.preamble_list[i].preamble_rel13.rach_resource_type>0, + AssertFatal(UL_info->rach_ind_br.rach_indication_body.number_of_preambles<5,"More than 4 preambles not supported\n"); + for (i=0;irach_ind_br.rach_indication_body.number_of_preambles;i++) { + AssertFatal(UL_info->rach_ind_br.rach_indication_body.preamble_list[i].preamble_rel13.rach_resource_type>0, "Got regular PRACH preamble, not BL/CE\n"); LOG_D(MAC,"Frame %d, Subframe %d Calling initiate_ra_proc (CE_level %d)\n",UL_info->frame,UL_info->subframe, - UL_info->rach_ind_br.preamble_list[i].preamble_rel13.rach_resource_type-1); + UL_info->rach_ind_br.rach_indication_body.preamble_list[i].preamble_rel13.rach_resource_type-1); initiate_ra_proc(UL_info->module_id, UL_info->CC_id, UL_info->frame, UL_info->subframe, - UL_info->rach_ind_br.preamble_list[i].preamble_rel8.preamble, - UL_info->rach_ind_br.preamble_list[i].preamble_rel8.timing_advance, - UL_info->rach_ind_br.preamble_list[i].preamble_rel8.rnti, - UL_info->rach_ind_br.preamble_list[i].preamble_rel13.rach_resource_type); + UL_info->rach_ind_br.rach_indication_body.preamble_list[i].preamble_rel8.preamble, + UL_info->rach_ind_br.rach_indication_body.preamble_list[i].preamble_rel8.timing_advance, + UL_info->rach_ind_br.rach_indication_body.preamble_list[i].preamble_rel8.rnti, + UL_info->rach_ind_br.rach_indication_body.preamble_list[i].preamble_rel13.rach_resource_type); } - UL_info->rach_ind.number_of_preambles=0; + UL_info->rach_ind_br.rach_indication_body.number_of_preambles=0; } #endif } @@ -58,91 +66,166 @@ void handle_sr(UL_IND_t *UL_info) { int i; - for (i=0;isr_ind.number_of_srs;i++) - SR_indication(UL_info->module_id, - UL_info->CC_id, - UL_info->frame, - UL_info->subframe, - UL_info->sr_ind.sr_pdu_list[i].rx_ue_information.rnti, - UL_info->sr_ind.sr_pdu_list[i].ul_cqi_information.ul_cqi); + if (nfapi_mode == 1) // PNF + { + if (UL_info->sr_ind.sr_indication_body.number_of_srs>0) + { + oai_nfapi_sr_indication(&UL_info->sr_ind); + } + } + else + { + for (i=0;isr_ind.sr_indication_body.number_of_srs;i++) + SR_indication(UL_info->module_id, + UL_info->CC_id, + UL_info->frame, + UL_info->subframe, + UL_info->sr_ind.sr_indication_body.sr_pdu_list[i].rx_ue_information.rnti, + UL_info->sr_ind.sr_indication_body.sr_pdu_list[i].ul_cqi_information.ul_cqi); + } - UL_info->sr_ind.number_of_srs=0; + UL_info->sr_ind.sr_indication_body.number_of_srs=0; } void handle_cqi(UL_IND_t *UL_info) { int i; - for (i=0;icqi_ind.number_of_cqis;i++) - cqi_indication(UL_info->module_id, - UL_info->CC_id, - UL_info->frame, - UL_info->subframe, - UL_info->cqi_ind.cqi_pdu_list[i].rx_ue_information.rnti, - &UL_info->cqi_ind.cqi_pdu_list[i].cqi_indication_rel9, - UL_info->cqi_ind.cqi_raw_pdu_list[i].pdu, - &UL_info->cqi_ind.cqi_pdu_list[i].ul_cqi_information); + if (nfapi_mode == 1) + { + if (UL_info->cqi_ind.number_of_cqis>0) + { + LOG_D(PHY,"UL_info->cqi_ind.number_of_cqis:%d\n", UL_info->cqi_ind.number_of_cqis); + nfapi_cqi_indication_t ind; - UL_info->cqi_ind.number_of_cqis=0; + ind.header.message_id = NFAPI_RX_CQI_INDICATION; + ind.sfn_sf = UL_info->frame<<4 | UL_info->subframe; + ind.cqi_indication_body = UL_info->cqi_ind; + + oai_nfapi_cqi_indication(&ind); + + UL_info->cqi_ind.number_of_cqis=0; + } + } + else + { + for (i=0;icqi_ind.number_of_cqis;i++) + cqi_indication(UL_info->module_id, + UL_info->CC_id, + UL_info->frame, + UL_info->subframe, + UL_info->cqi_ind.cqi_pdu_list[i].rx_ue_information.rnti, + &UL_info->cqi_ind.cqi_pdu_list[i].cqi_indication_rel9, + UL_info->cqi_ind.cqi_raw_pdu_list[i].pdu, + &UL_info->cqi_ind.cqi_pdu_list[i].ul_cqi_information); + + UL_info->cqi_ind.number_of_cqis=0; + } } void handle_harq(UL_IND_t *UL_info) { int i; - for (i=0;iharq_ind.number_of_harqs;i++) - harq_indication(UL_info->module_id, - UL_info->CC_id, - UL_info->frame, - UL_info->subframe, - &UL_info->harq_ind.harq_pdu_list[i]); + //if (UL_info->harq_ind.number_of_harqs>0) - UL_info->harq_ind.number_of_harqs=0; + if (nfapi_mode == 1 && UL_info->harq_ind.harq_indication_body.number_of_harqs>0) // PNF + { + //LOG_D(PHY, "UL_info->harq_ind.harq_indication_body.number_of_harqs:%d Send to VNF\n", UL_info->harq_ind.harq_indication_body.number_of_harqs); + + int retval = oai_nfapi_harq_indication(&UL_info->harq_ind); + + if (retval!=0) + { + LOG_E(PHY, "Failed to encode NFAPI HARQ_IND retval:%d\n", retval); + } + + UL_info->harq_ind.harq_indication_body.number_of_harqs = 0; + } + else + { + for (i=0;iharq_ind.harq_indication_body.number_of_harqs;i++) + harq_indication(UL_info->module_id, + UL_info->CC_id, + NFAPI_SFNSF2SFN(UL_info->harq_ind.sfn_sf), + NFAPI_SFNSF2SF(UL_info->harq_ind.sfn_sf), + &UL_info->harq_ind.harq_indication_body.harq_pdu_list[i]); + + UL_info->harq_ind.harq_indication_body.number_of_harqs=0; + } } void handle_ulsch(UL_IND_t *UL_info) { int i,j; - for (i=0;irx_ind.number_of_pdus;i++) { + if(nfapi_mode == 1) + { + if (UL_info->crc_ind.crc_indication_body.number_of_crcs>0) + { + //LOG_D(PHY,"UL_info->crc_ind.crc_indication_body.number_of_crcs:%d CRC_IND:SFN/SF:%d\n", UL_info->crc_ind.crc_indication_body.number_of_crcs, NFAPI_SFNSF2DEC(UL_info->crc_ind.sfn_sf)); - for (j=0;jcrc_ind.number_of_crcs;j++) { - // find crc_indication j corresponding rx_indication i - if (UL_info->crc_ind.crc_pdu_list[j].rx_ue_information.rnti == - UL_info->rx_ind.rx_pdu_list[i].rx_ue_information.rnti) { - if (UL_info->crc_ind.crc_pdu_list[j].crc_indication_rel8.crc_flag == 1) { // CRC error indication - LOG_D(MAC,"Frame %d, Subframe %d Calling rx_sdu (CRC error) \n",UL_info->frame,UL_info->subframe); - rx_sdu(UL_info->module_id, - UL_info->CC_id, - UL_info->frame, - UL_info->subframe, - UL_info->rx_ind.rx_pdu_list[i].rx_ue_information.rnti, - (uint8_t *)NULL, - UL_info->rx_ind.rx_pdu_list[i].rx_indication_rel8.length, - UL_info->rx_ind.rx_pdu_list[i].rx_indication_rel8.timing_advance, - UL_info->rx_ind.rx_pdu_list[i].rx_indication_rel8.ul_cqi); - } - else { - LOG_D(MAC,"Frame %d, Subframe %d Calling rx_sdu (CRC ok) \n",UL_info->frame,UL_info->subframe); - rx_sdu(UL_info->module_id, - UL_info->CC_id, - UL_info->frame, - UL_info->subframe, - UL_info->rx_ind.rx_pdu_list[i].rx_ue_information.rnti, - UL_info->rx_ind.rx_pdu_list[i].data, - UL_info->rx_ind.rx_pdu_list[i].rx_indication_rel8.length, - UL_info->rx_ind.rx_pdu_list[i].rx_indication_rel8.timing_advance, - UL_info->rx_ind.rx_pdu_list[i].rx_indication_rel8.ul_cqi); - } - break; - } //if (UL_info->crc_ind.crc_pdu_list[j].rx_ue_information.rnti == - // UL_info->rx_ind.rx_pdu_list[i].rx_ue_information.rnti) { - } // for (j=0;jcrc_ind.number_of_crcs;j++) { - AssertFatal(jcrc_ind.number_of_crcs,"Couldn't find matchin CRC indication\n"); - } // for (i=0;irx_ind.number_of_pdus;i++) { - - UL_info->rx_ind.number_of_pdus=0; - UL_info->crc_ind.number_of_crcs=0; + oai_nfapi_crc_indication(&UL_info->crc_ind); + + UL_info->crc_ind.crc_indication_body.number_of_crcs = 0; + } + + if (UL_info->rx_ind.rx_indication_body.number_of_pdus>0) + { + //LOG_D(PHY,"UL_info->rx_ind.number_of_pdus:%d RX_IND:SFN/SF:%d\n", UL_info->rx_ind.rx_indication_body.number_of_pdus, NFAPI_SFNSF2DEC(UL_info->rx_ind.sfn_sf)); + oai_nfapi_rx_ind(&UL_info->rx_ind); + UL_info->rx_ind.rx_indication_body.number_of_pdus = 0; + } + } + else + { + if (UL_info->rx_ind.rx_indication_body.number_of_pdus>0 && UL_info->crc_ind.crc_indication_body.number_of_crcs>0) { + for (i=0;irx_ind.rx_indication_body.number_of_pdus;i++) { + for (j=0;jcrc_ind.crc_indication_body.number_of_crcs;j++) { + // find crc_indication j corresponding rx_indication i + LOG_D(PHY,"UL_info->crc_ind.crc_indication_body.crc_pdu_list[%d].rx_ue_information.rnti:%04x UL_info->rx_ind.rx_indication_body.rx_pdu_list[%d].rx_ue_information.rnti:%04x\n", j, UL_info->crc_ind.crc_indication_body.crc_pdu_list[j].rx_ue_information.rnti, i, UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_ue_information.rnti); + if (UL_info->crc_ind.crc_indication_body.crc_pdu_list[j].rx_ue_information.rnti == + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_ue_information.rnti) { + LOG_D(PHY, "UL_info->crc_ind.crc_indication_body.crc_pdu_list[%d].crc_indication_rel8.crc_flag:%d\n", j, UL_info->crc_ind.crc_indication_body.crc_pdu_list[j].crc_indication_rel8.crc_flag); + if (UL_info->crc_ind.crc_indication_body.crc_pdu_list[j].crc_indication_rel8.crc_flag == 1) { // CRC error indication + LOG_D(MAC,"Frame %d, Subframe %d Calling rx_sdu (CRC error) \n",UL_info->frame,UL_info->subframe); + rx_sdu(UL_info->module_id, + UL_info->CC_id, + NFAPI_SFNSF2SFN(UL_info->rx_ind.sfn_sf), //UL_info->frame, + NFAPI_SFNSF2SF(UL_info->rx_ind.sfn_sf), //UL_info->subframe, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_ue_information.rnti, + (uint8_t *)NULL, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.length, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.timing_advance, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.ul_cqi); + } + else { + LOG_D(MAC,"Frame %d, Subframe %d Calling rx_sdu (CRC ok) \n",UL_info->frame,UL_info->subframe); + rx_sdu(UL_info->module_id, + UL_info->CC_id, + NFAPI_SFNSF2SFN(UL_info->rx_ind.sfn_sf), //UL_info->frame, + NFAPI_SFNSF2SF(UL_info->rx_ind.sfn_sf), //UL_info->subframe, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_ue_information.rnti, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].data, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.length, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.timing_advance, + UL_info->rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.ul_cqi); + } + break; + } //if (UL_info->crc_ind.crc_pdu_list[j].rx_ue_information.rnti == + // UL_info->rx_ind.rx_pdu_list[i].rx_ue_information.rnti) + } // for (j=0;jcrc_ind.crc_indication_body.number_of_crcs;j++) + } // for (i=0;irx_ind.number_of_pdus;i++) + UL_info->crc_ind.crc_indication_body.number_of_crcs=0; + UL_info->rx_ind.rx_indication_body.number_of_pdus = 0; + } // UL_info->rx_ind.rx_indication_body.number_of_pdus>0 && UL_info->subframe && UL_info->crc_ind.crc_indication_body.number_of_crcs>0 + else if (UL_info->rx_ind.rx_indication_body.number_of_pdus!=0 || UL_info->crc_ind.crc_indication_body.number_of_crcs!=0) { + LOG_E(PHY,"hoping not to have mis-match between CRC ind and RX ind - hopefully the missing message is coming shortly rx_ind:%d(SFN/SF:%05d) crc_ind:%d(SFN/SF:%05d) UL_info(SFN/SF):%04d%d\n", + UL_info->rx_ind.rx_indication_body.number_of_pdus, NFAPI_SFNSF2DEC(UL_info->rx_ind.sfn_sf), + UL_info->crc_ind.crc_indication_body.number_of_crcs, NFAPI_SFNSF2DEC(UL_info->crc_ind.sfn_sf), + UL_info->frame, UL_info->subframe); + } + } } /****************************************************************************/ @@ -203,22 +286,22 @@ static void dump_ul(UL_IND_t *u) A("XXXX UL mod %d CC %d f.sf %d.%d\n", u->module_id, u->CC_id, u->frame, u->subframe); - A("XXXX harq_ind %d\n", u->harq_ind.number_of_harqs); - for (i = 0; i < u->harq_ind.number_of_harqs; i++) { - nfapi_harq_indication_pdu_t *v = &u->harq_ind.harq_pdu_list[i]; + A("XXXX harq_ind %d\n", u->harq_ind.harq_indication_body.number_of_harqs); + for (i = 0; i < u->harq_ind.harq_indication_body.number_of_harqs; i++) { + nfapi_harq_indication_pdu_t *v = &u->harq_ind.harq_indication_body.harq_pdu_list[i]; A("XXXX harq ind %d\n", i); - A("XXXX rnti %d\n", v->rx_ue_information.rnti); - A("XXXX tb1 %d tb2 %d\n", v->harq_indication_fdd_rel8.harq_tb1, - v->harq_indication_fdd_rel8.harq_tb2); - A("XXXX number_of_ack_nack %d\n", - v->harq_indication_fdd_rel9.number_of_ack_nack); + A("XXXX rnti %d\n", v->rx_ue_information.rnti); + A("XXXX tb1 %d tb2 %d\n", v->harq_indication_fdd_rel8.harq_tb1, + v->harq_indication_fdd_rel8.harq_tb2); + A("XXXX number_of_ack_nack %d\n", + v->harq_indication_fdd_rel9.number_of_ack_nack); A("XXXX harq[0] = %d\n", v->harq_indication_fdd_rel9.harq_tb_n[0]); A("XXXX harq ul_cqi %d channel %d\n", v->ul_cqi_information.ul_cqi, - v->ul_cqi_information.channel); + v->ul_cqi_information.channel); } - A("XXXX crc_ind %d\n", u->crc_ind.number_of_crcs); + A("XXXX crc_ind %d\n", u->crc_ind.crc_indication_body.number_of_crcs); A("XXXX sr_ind %d\n", u->sr_ind.number_of_srs); @@ -230,11 +313,11 @@ static void dump_ul(UL_IND_t *u) v->ul_cqi_information.channel); } - A("XXXX rach_ind %d\n", u->rach_ind.number_of_preambles); + A("XXXX rach_ind %d\n", u->rach_ind.rach_indication_body.number_of_preambles); - A("XXXX rx_ind %d\n", u->rx_ind.number_of_pdus); - for (i = 0; i < u->rx_ind.number_of_pdus; i++) { - nfapi_rx_indication_pdu_t *v = &u->rx_ind.rx_pdu_list[i]; + A("XXXX rx_ind %d\n", u->rx_ind.rx_indication_body.number_of_pdus); + for (i = 0; i < u->rx_ind.rx_indication_body.number_of_pdus; i++) { + nfapi_rx_indication_pdu_t *v = &u->rx_ind.rx_indication_body.rx_pdu_list[i]; A("XXXX rx ind %d\n", i); A("XXXX timing_advance %d\n", v->rx_indication_rel8.timing_advance); @@ -461,25 +544,38 @@ void UL_indication(UL_IND_t *UL_info) IF_Module_t *ifi = if_inst[module_id]; eNB_MAC_INST *mac = RC.mac[module_id]; - LOG_D(PHY,"UL_Indication: frame %d, subframe %d, module_id %d, CC_id %d\n", - UL_info->frame,UL_info->subframe, - module_id,CC_id); + if (UL_info->rx_ind.rx_indication_body.number_of_pdus || + UL_info->harq_ind.harq_indication_body.number_of_harqs || + UL_info->crc_ind.crc_indication_body.number_of_crcs || + UL_info->cqi_ind.number_of_cqis || + UL_info->rach_ind.rach_indication_body.number_of_preambles || + UL_info->sr_ind.sr_indication_body.number_of_srs) { + LOG_D(PHY,"SFN/SF:%d%d module_id:%d CC_id:%d UL_info[rx_ind:%d harqs:%d crcs:%d cqis:%d preambles:%d sr_ind:%d]\n", + UL_info->frame,UL_info->subframe, + module_id,CC_id, + UL_info->rx_ind.rx_indication_body.number_of_pdus, UL_info->harq_ind.harq_indication_body.number_of_harqs, UL_info->crc_ind.crc_indication_body.number_of_crcs, UL_info->cqi_ind.number_of_cqis, UL_info->rach_ind.rach_indication_body.number_of_preambles, UL_info->sr_ind.sr_indication_body.number_of_srs); + } - if (ifi->CC_mask==0) { - ifi->current_frame = UL_info->frame; - ifi->current_subframe = UL_info->subframe; + if (nfapi_mode != 1) + { + if (ifi->CC_mask==0) { + ifi->current_frame = UL_info->frame; + ifi->current_subframe = UL_info->subframe; + } + else { + AssertFatal(UL_info->frame != ifi->current_frame,"CC_mask %x is not full and frame has changed\n",ifi->CC_mask); + AssertFatal(UL_info->subframe != ifi->current_subframe,"CC_mask %x is not full and subframe has changed\n",ifi->CC_mask); + } + ifi->CC_mask |= (1<frame != ifi->current_frame,"CC_mask %x is not full and frame has changed\n",ifi->CC_mask); - AssertFatal(UL_info->subframe != ifi->current_subframe,"CC_mask %x is not full and subframe has changed\n",ifi->CC_mask); - } - ifi->CC_mask |= (1<frame, UL_info->subframe); // clear DL/UL info for new scheduling round clear_nfapi_information(RC.mac[module_id],CC_id, UL_info->frame,UL_info->subframe); - + //LOG_D(PHY,"%s() SFN_SF:%d%d Returned from call clear_nfapi_information()\n", __FUNCTION__, UL_info->frame, UL_info->subframe); handle_rach(UL_info); @@ -489,61 +585,69 @@ void UL_indication(UL_IND_t *UL_info) handle_harq(UL_info); - // clear HI prior to hanling ULSCH + // clear HI prior to handling ULSCH mac->HI_DCI0_req[CC_id].hi_dci0_request_body.number_of_hi = 0; handle_ulsch(UL_info); - if (ifi->CC_mask == ((1<CC_mask == ((1<frame+((UL_info->subframe>5)?1:0)) % 1024, - (UL_info->subframe+4)%10); + eNB_dlsch_ulsch_scheduler(module_id, + (UL_info->frame+((UL_info->subframe>(9-sf_ahead))?1:0)) % 1024, + (UL_info->subframe+sf_ahead)%10); - ifi->CC_mask = 0; + ifi->CC_mask = 0; - sched_info->module_id = module_id; - sched_info->CC_id = CC_id; - sched_info->frame = (UL_info->frame + ((UL_info->subframe>5) ? 1 : 0)) % 1024; - sched_info->subframe = (UL_info->subframe+4)%10; - sched_info->DL_req = &mac->DL_req[CC_id]; - sched_info->HI_DCI0_req = &mac->HI_DCI0_req[CC_id]; - if ((mac->common_channels[CC_id].tdd_Config==NULL) || - (is_UL_sf(&mac->common_channels[CC_id],(sched_info->subframe+4)%10)>0)) - sched_info->UL_req = &mac->UL_req[CC_id]; - else - sched_info->UL_req = NULL; + sched_info->module_id = module_id; + sched_info->CC_id = CC_id; + sched_info->frame = (UL_info->frame + ((UL_info->subframe>(9-sf_ahead)) ? 1 : 0)) % 1024; + sched_info->subframe = (UL_info->subframe+sf_ahead)%10; + sched_info->DL_req = &mac->DL_req[CC_id]; + sched_info->HI_DCI0_req = &mac->HI_DCI0_req[CC_id]; + if ((mac->common_channels[CC_id].tdd_Config==NULL) || + (is_UL_sf(&mac->common_channels[CC_id],(sched_info->subframe+sf_ahead)%10)>0)) + sched_info->UL_req = &mac->UL_req[CC_id]; + else + sched_info->UL_req = NULL; - sched_info->TX_req = &mac->TX_req[CC_id]; + sched_info->TX_req = &mac->TX_req[CC_id]; #ifdef DUMP_FAPI - dump_dl(sched_info); + dump_dl(sched_info); #endif - AssertFatal(ifi->schedule_response!=NULL, - "UL_indication is null (mod %d, cc %d)\n", - module_id, - CC_id); - ifi->schedule_response(sched_info); + if (ifi->schedule_response) + { + AssertFatal(ifi->schedule_response!=NULL, + "schedule_response is null (mod %d, cc %d)\n", + module_id, + CC_id); + ifi->schedule_response(sched_info); + } - LOG_D(PHY,"Schedule_response: frame %d, subframe %d (dl_pdus %d / %p)\n",sched_info->frame,sched_info->subframe,sched_info->DL_req->dl_config_request_body.number_pdu, - &sched_info->DL_req->dl_config_request_body.number_pdu); - } + if (sched_info->DL_req->dl_config_request_body.number_pdu) + LOG_D(PHY,"Schedule_response: SFN_SF:%d%d dl_pdus:%d\n",sched_info->frame,sched_info->subframe,sched_info->DL_req->dl_config_request_body.number_pdu); + } + } } IF_Module_t *IF_Module_init(int Mod_id){ AssertFatal(Mod_id %d\n",Mod_id,MAX_IF_MODULES); + LOG_D(PHY,"Installing callbacks for IF_Module - UL_indication\n"); + if (if_inst[Mod_id]==NULL) { if_inst[Mod_id] = (IF_Module_t*)malloc(sizeof(IF_Module_t)); memset((void*)if_inst[Mod_id],0,sizeof(IF_Module_t)); - + if_inst[Mod_id]->CC_mask=0; if_inst[Mod_id]->UL_indication = UL_indication; AssertFatal(pthread_mutex_init(&if_inst[Mod_id]->if_mutex,NULL)==0, - "allocation of if_inst[%d]->if_mutex fails\n",Mod_id); + "allocation of if_inst[%d]->if_mutex fails\n",Mod_id); } return if_inst[Mod_id]; } diff --git a/openair2/PHY_INTERFACE/IF_Module.h b/openair2/PHY_INTERFACE/IF_Module.h index e33a8291e2..7baae6c3b6 100644 --- a/openair2/PHY_INTERFACE/IF_Module.h +++ b/openair2/PHY_INTERFACE/IF_Module.h @@ -61,30 +61,30 @@ typedef struct{ sub_frame_t subframe; /// harq indication list - nfapi_harq_indication_body_t harq_ind; + nfapi_harq_indication_t harq_ind; /// crc indication list - nfapi_crc_indication_body_t crc_ind; + nfapi_crc_indication_t crc_ind; /// SR indication list - nfapi_sr_indication_body_t sr_ind; + nfapi_sr_indication_t sr_ind; /// CQI indication list nfapi_cqi_indication_body_t cqi_ind; /// RACH indication list - nfapi_rach_indication_body_t rach_ind; + nfapi_rach_indication_t rach_ind; #ifdef Rel14 /// RACH indication list for BR UEs - nfapi_rach_indication_body_t rach_ind_br; + nfapi_rach_indication_t rach_ind_br; #endif /// SRS indication list nfapi_srs_indication_body_t srs_ind; /// RX indication - nfapi_rx_indication_body_t rx_ind; + nfapi_rx_indication_t rx_ind; } UL_IND_t; diff --git a/openair2/RRC/LITE/L2_interface.c b/openair2/RRC/LITE/L2_interface.c index 504bf8ee9b..23232f563d 100644 --- a/openair2/RRC/LITE/L2_interface.c +++ b/openair2/RRC/LITE/L2_interface.c @@ -81,7 +81,6 @@ mac_rrc_data_req( uint8_t sfn = (uint8_t)((frameP>>2)&0xff); - #ifdef DEBUG_RRC int i; LOG_I(RRC,"[eNB %d] mac_rrc_data_req to SRB ID=%d\n",Mod_idP,Srb_id); @@ -148,6 +147,7 @@ mac_rrc_data_req( return (RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB1); } // All RFN mod 8 transmit SIB2-3 in SF 5 else if ((frameP%8) == 1) { + //LOG_D(RRC, "%s() frameP mod 8==1 (frameP:%d) copy into buffer SIB23 size:%d\n", __FUNCTION__, frameP, RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB23); memcpy(&buffer_pP[0], RC.rrc[Mod_idP]->carrier[CC_id].SIB23, RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB23); @@ -197,7 +197,7 @@ mac_rrc_data_req( (void*)mib, carrier->MIB, 24); - LOG_D(RRC,"Encoded MIB for frame %d (%p), bits %lu\n",sfn,carrier->MIB,enc_rval.encoded); + //LOG_D(RRC,"Encoded MIB for frame %d (%p), bits %lu\n",sfn,carrier->MIB,enc_rval.encoded); buffer_pP[0]=carrier->MIB[0]; buffer_pP[1]=carrier->MIB[1]; buffer_pP[2]=carrier->MIB[2]; @@ -312,7 +312,7 @@ mac_rrc_data_req( RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB1_BR); return (RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB1_BR); } - + if ((Srb_id & RAB_OFFSET) == BCCH_SI_BR){ // First SI message with SIB2/3 memcpy(&buffer_pP[0], RC.rrc[Mod_idP]->carrier[CC_id].SIB23_BR, diff --git a/openair2/RRC/LITE/rrc_common.c b/openair2/RRC/LITE/rrc_common.c index 0e836f5677..65e1a25b17 100644 --- a/openair2/RRC/LITE/rrc_common.c +++ b/openair2/RRC/LITE/rrc_common.c @@ -65,7 +65,7 @@ openair_rrc_on( int CC_id; if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" OPENAIR RRC IN....\n", + LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" ENB:OPENAIR RRC IN....\n", PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { rrc_config_buffer (&RC.rrc[ctxt_pP->module_id]->carrier[CC_id].SI, BCCH, 1); @@ -74,7 +74,7 @@ openair_rrc_on( RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Active = 1; } } else { - LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" OPENAIR RRC IN....\n", + LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" UE?:OPENAIR RRC IN....\n", PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); for (i = 0; i < NB_eNB_INST; i++) { diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index c8b42d41b3..15a60a6902 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -135,6 +135,8 @@ init_SI( SystemInformationBlockType1_v1310_IEs_t *sib1_v13ext=(SystemInformationBlockType1_v1310_IEs_t *)NULL; #endif + LOG_E(RRC,"%s()\n\n\n\n",__FUNCTION__); + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].MIB = (uint8_t*) malloc16(4); // copy basic parameters RC.rrc[ctxt_pP->module_id]->carrier[CC_id].physCellId = configuration->Nid_cell[CC_id]; @@ -282,6 +284,8 @@ init_SI( } #endif + LOG_E(RRC, "About to call rrc_mac_config_req_eNB\n"); + rrc_mac_config_req_eNB(ctxt_pP->module_id, CC_id, RC.rrc[ctxt_pP->module_id]->carrier[CC_id].physCellId, RC.rrc[ctxt_pP->module_id]->carrier[CC_id].p_eNB, @@ -4798,6 +4802,7 @@ rrc_eNB_decode_dcch( T(T_ENB_RRC_UL_INFORMATION_TRANSFER, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + LOG_D(RRC,"[MSG] RRC UL Information Transfer \n"); #ifdef RRC_MSG_PRINT LOG_F(RRC,"[MSG] RRC UL Information Transfer \n"); diff --git a/openair2/UTIL/LOG/log.c b/openair2/UTIL/LOG/log.c index f3bd04754b..47ff5d0fce 100644 --- a/openair2/UTIL/LOG/log.c +++ b/openair2/UTIL/LOG/log.c @@ -528,8 +528,340 @@ int logInit (void) return 0; } +void nfapi_log(char *file, char *func, int line, int comp, int level, const char* format, va_list args) +{ + //logRecord_mt(file,func,line, pthread_self(), comp, level, format, ##args) + int len = 0; + log_component_t *c; + char *log_start; + char *log_end; + /* The main difference with the version above is the use of this local log_buffer. + * The other difference is the return value of snprintf which was not used + * correctly. It was not a big problem because in practice MAX_LOG_TOTAL is + * big enough so that the buffer is never full. + */ + char log_buffer[MAX_LOG_TOTAL]; + + /* for no gcc warnings */ + (void)log_start; + (void)log_end; + + c = &g_log->log_component[comp]; + + // do not apply filtering for LOG_F + // only log messages which are enabled and are below the global log level and component's level threshold + if ((level != LOG_FILE) && ((level > c->level) || (level > g_log->level))) { + /* if ((level != LOG_FILE) && + ((level > c->level) || + (level > g_log->level) || + ( c->level > g_log->level))) { + */ + return; + } + + //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD, VCD_FUNCTION_IN); + + // adjust syslog level for TRACE messages + if (g_log->syslog) { + if (g_log->level > LOG_DEBUG) { + g_log->level = LOG_DEBUG; + } + } + + // make sure that for log trace the extra info is only printed once, reset when the level changes + if ((level == LOG_FILE) || (c->flag == LOG_NONE) || (level == LOG_TRACE)) { + log_start = log_buffer; + len = vsnprintf(log_buffer, MAX_LOG_TOTAL, format, args); + if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; + log_end = log_buffer + len; + } else { + if ( (g_log->flag & FLAG_COLOR) || (c->flag & FLAG_COLOR) ) { + len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "%s", + log_level_highlight_start[level]); + if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; + } + + log_start = log_buffer + len; + + if ( (g_log->flag & FLAG_COMP) || (c->flag & FLAG_COMP) ) { + len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s]", + g_log->log_component[comp].name); + if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; + } + + if ( (g_log->flag & FLAG_LEVEL) || (c->flag & FLAG_LEVEL) ) { + len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s]", + g_log->level2string[level]); + if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; + } + + if ( (g_log->flag & FLAG_THREAD) || (c->flag & FLAG_THREAD) ) { +# define THREAD_NAME_LEN 128 + char threadname[THREAD_NAME_LEN]; + if (pthread_getname_np(pthread_self(), threadname, THREAD_NAME_LEN) != 0) + { + perror("pthread_getname_np : "); + } else { + len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s]", threadname); + if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; + } +# undef THREAD_NAME_LEN + } + + if ( (g_log->flag & FLAG_FUNCT) || (c->flag & FLAG_FUNCT) ) { + len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s] ", + func); + if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; + } + + if ( (g_log->flag & FLAG_FILE_LINE) || (c->flag & FLAG_FILE_LINE) ) { + len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s:%d]", + file, line); + if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; + } + + //len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%08lx]", thread_id); + //if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; + + len += vsnprintf(&log_buffer[len], MAX_LOG_TOTAL - len, format, args); + if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; + log_end = log_buffer + len; + + if ( (g_log->flag & FLAG_COLOR) || (c->flag & FLAG_COLOR) ) { + len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "%s", + log_level_highlight_end[level]); + if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; + } + } + + va_end(args); + + // OAI printf compatibility + if ((g_log->onlinelog == 1) && (level != LOG_FILE)) +#ifdef RTAI + if (len > MAX_LOG_TOTAL) { + rt_printk ("[OPENAIR] FIFO_PRINTF WROTE OUTSIDE ITS MEMORY BOUNDARY : ERRORS WILL OCCUR\n"); + } + + if (len > 0) { + rtf_put (FIFO_PRINTF_NO, log_buffer, len); + } + +#else + fwrite(log_buffer, len, 1, stdout); +#endif + +#ifndef RTAI + + if (g_log->syslog) { + syslog(g_log->level, "%s", log_buffer); + } + + if (g_log->filelog) { + if (write(gfd, log_buffer, len) < len) { + // TODO assert ? + } + } + + if ((g_log->log_component[comp].filelog) && (level == LOG_FILE)) { + if (write(g_log->log_component[comp].fd, log_buffer, len) < len) { + // TODO assert ? + } + } + +#else + + // online print messges + if ((g_log->log_component[comp].filelog) && (level == LOG_FILE)) { + printf(log_buffer); + } + +#endif + +#if defined(ENABLE_ITTI) + + if (level <= LOG_DEBUG) { + task_id_t origin_task_id = TASK_UNKNOWN; + MessagesIds messages_id; + MessageDef *message_p; + size_t message_string_size; + char *message_msg_p; + + message_string_size = log_end - log_start; + +#if !defined(DISABLE_ITTI_DETECT_SUB_TASK_ID) + + /* Try to identify sub task ID from log information (comp, log_instance_type) */ + switch (comp) { + case PHY: + switch (log_instance_type) { + case LOG_INSTANCE_ENB: + origin_task_id = TASK_PHY_ENB; + break; + + case LOG_INSTANCE_UE: + origin_task_id = TASK_PHY_UE; + break; + + default: + break; + } + + break; + + case MAC: + switch (log_instance_type) { + case LOG_INSTANCE_ENB: + origin_task_id = TASK_MAC_ENB; + break; + + case LOG_INSTANCE_UE: + origin_task_id = TASK_MAC_UE; + + default: + break; + } + + break; + + case RLC: + switch (log_instance_type) { + case LOG_INSTANCE_ENB: + origin_task_id = TASK_RLC_ENB; + break; + + case LOG_INSTANCE_UE: + origin_task_id = TASK_RLC_UE; + + default: + break; + } + + break; + + case PDCP: + switch (log_instance_type) { + case LOG_INSTANCE_ENB: + origin_task_id = TASK_PDCP_ENB; + break; + + case LOG_INSTANCE_UE: + origin_task_id = TASK_PDCP_UE; + + default: + break; + } + + break; + + default: + break; + } + +#endif + + switch (level) { + case LOG_EMERG: + case LOG_ALERT: + case LOG_CRIT: + case LOG_ERR: + messages_id = ERROR_LOG; + break; + + case LOG_WARNING: + messages_id = WARNING_LOG; + break; + + case LOG_NOTICE: + messages_id = NOTICE_LOG; + break; + + case LOG_INFO: + messages_id = INFO_LOG; + break; + + default: + messages_id = DEBUG_LOG; + break; + } + + message_p = itti_alloc_new_message_sized(origin_task_id, messages_id, message_string_size); + + switch (level) { + case LOG_EMERG: + case LOG_ALERT: + case LOG_CRIT: + case LOG_ERR: + message_msg_p = (char *) &message_p->ittiMsg.error_log; + break; + + case LOG_WARNING: + message_msg_p = (char *) &message_p->ittiMsg.warning_log; + break; + + case LOG_NOTICE: + message_msg_p = (char *) &message_p->ittiMsg.notice_log; + break; + + case LOG_INFO: + message_msg_p = (char *) &message_p->ittiMsg.info_log; + break; + + default: + message_msg_p = (char *) &message_p->ittiMsg.debug_log; + break; + } + + memcpy(message_msg_p, log_start, message_string_size); + + itti_send_msg_to_task(TASK_UNKNOWN, INSTANCE_DEFAULT, message_p); + } + +#endif +#if 0 + LOG_params log_params; + int len; + + len = vsnprintf(log_params.l_buff_info, MAX_LOG_INFO-1, format, args); + + //2 first parameters must be passed as 'const' to the thread function + log_params.file = strdup(file); + log_params.func = strdup(func); + log_params.line = line; + log_params.comp = PHY;//comp; + log_params.level = 6; // INFO - level; + log_params.format = format; + log_params.len = len; + + if (pthread_mutex_lock(&log_lock) != 0) { + return; + } + + log_list_tail++; + log_list[log_list_tail - 1] = log_params; + + if (log_list_tail >= 1000) { + log_list_tail = 0; + } + + if (log_list_nb_elements < 1000) { + log_list_nb_elements++; + } + + if(pthread_cond_signal(&log_notify) != 0) { + pthread_mutex_unlock(&log_lock); + return; + } + + if(pthread_mutex_unlock(&log_lock) != 0) { + return; + } + +#endif +} + //log record: add to a list -void logRecord(const char *file, const char *func, int line, int comp, +void logRecord(const char *file, const char *func, int line, pthread_t thread_id, int comp, int level, const char *format, ...) { va_list args; @@ -544,6 +876,7 @@ void logRecord(const char *file, const char *func, int line, int comp, log_params.file = strdup(file); log_params.func = strdup(func); log_params.line = line; + log_params.thread_id = thread_id; log_params.comp = comp; log_params.level = level; log_params.format = format; @@ -582,7 +915,7 @@ void logRecord(const char *file, const char *func, int line, int comp, } void logRecord_thread_safe(const char *file, const char *func, - int line, int comp, int level, + int line, pthread_t thread_id, int comp, int level, int len, const char *params_string) { log_component_t *c; @@ -634,6 +967,8 @@ void logRecord_thread_safe(const char *file, const char *func, func); } + //total_len += snprintf(&log_buffer[total_len], MAX_LOG_TOTAL - total_len, "[%08lx] ", thread_id); + if ((g_log->flag & FLAG_FILE_LINE) || (c->flag & FLAG_FILE_LINE) ) { total_len += snprintf(&log_buffer[total_len], MAX_LOG_TOTAL - total_len, "[%s:%d]", file, line); @@ -733,6 +1068,7 @@ void *log_thread_function(void *list) logRecord_thread_safe(log_params.file, log_params.func, log_params.line, + log_params.thread_id, log_params.comp, log_params.level, log_params.len, @@ -1021,8 +1357,8 @@ void logRecord_mt(const char *file, const char *func, int line, int comp, #endif /* #if 0 */ //log record, format, and print: executed in the main thread (mt) -void logRecord_mt(const char *file, const char *func, int line, int comp, - int level, const char *format, ...) +void logRecord_mt(const char *file, const char *func, int line, + pthread_t thread_id, int comp, int level, const char *format, ...) { int len = 0; va_list args; @@ -1053,8 +1389,7 @@ void logRecord_mt(const char *file, const char *func, int line, int comp, return; } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD, - VCD_FUNCTION_IN); + //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD, VCD_FUNCTION_IN); va_start(args, format); @@ -1117,13 +1452,16 @@ void logRecord_mt(const char *file, const char *func, int line, int comp, if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; } + //len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%08lx]", thread_id); + //if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; + len += vsnprintf(&log_buffer[len], MAX_LOG_TOTAL - len, format, args); if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; log_end = log_buffer + len; if ( (g_log->flag & FLAG_COLOR) || (c->flag & FLAG_COLOR) ) { len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "%s", - log_level_highlight_end[level]); + log_level_highlight_end[level]); if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; } } @@ -1142,7 +1480,7 @@ void logRecord_mt(const char *file, const char *func, int line, int comp, } #else - fwrite(log_buffer, len, 1, stdout); + fwrite(log_buffer, len, 1, stdout); #endif #ifndef RTAI diff --git a/openair2/UTIL/LOG/log.h b/openair2/UTIL/LOG/log.h index 1d795740b6..4cc5291774 100644 --- a/openair2/UTIL/LOG/log.h +++ b/openair2/UTIL/LOG/log.h @@ -240,6 +240,7 @@ typedef struct LOG_params { const char *file; const char *func; int line; + pthread_t thread_id; int comp; int level; const char *format; @@ -262,8 +263,8 @@ void log_set_instance_type (log_instance_type_t instance); # include "log_if.h" /*----------------------------------------------------------------------------*/ int logInit (void); -void logRecord_mt(const char *file, const char *func, int line,int comp, int level, const char *format, ...) __attribute__ ((format (printf, 6, 7))); -void logRecord(const char *file, const char *func, int line,int comp, int level, const char *format, ...) __attribute__ ((format (printf, 6, 7))); +void logRecord_mt(const char *file, const char *func, int line,pthread_t thread_id, int comp, int level, const char *format, ...) __attribute__ ((format (printf, 7, 8))); +void logRecord(const char *file, const char *func, int line, pthread_t thread_id, int comp, int level, const char *format, ...) __attribute__ ((format (printf, 7, 8))); int set_comp_log(int component, int level, int verbosity, int interval); int set_log(int component, int level, int interval); void set_glog(int level, int verbosity); @@ -285,15 +286,15 @@ void *log_thread_function(void * list); #ifdef USER_MODE //#define logIt(component, level, format, args...) do {logRecord(__FILE__, __FUNCTION__, __LINE__, component, level, format, ##args);} while(0); #ifdef LOG_NO_THREAD -#define logIt(component, level, format, args...) logRecord_mt(__FILE__, __FUNCTION__, __LINE__, component, level, format, ##args) +#define logIt(component, level, format, args...) logRecord_mt(__FILE__, __FUNCTION__, __LINE__, pthread_self(), component, level, format, ##args) #else //default -#define logIt(component, level, format, args...) logRecord(__FILE__, __FUNCTION__, __LINE__, component, level, format, ##args) +#define logIt(component, level, format, args...) logRecord(__FILE__, __FUNCTION__, __LINE__, pthread_self(), component, level, format, ##args) #endif #else #ifdef LOG_NO_THREAD -#define logIt(component, level, format, args...) logRecord_mt(NULL, __FUNCTION__, __LINE__, component, level, format, ##args) +#define logIt(component, level, format, args...) logRecord_mt(NULL, __FUNCTION__, __LINE__, pthread_self(), component, level, format, ##args) #else // default -#define logIt(component, level, format, args...) logRecord(NULL, __FUNCTION__, __LINE__, component, level, format, ##args) +#define logIt(component, level, format, args...) logRecord(NULL, __FUNCTION__, __LINE__, pthread_self(), component, level, format, ##args) #endif #endif /* @}*/ @@ -352,6 +353,19 @@ void *log_thread_function(void * list); # define LOG_N(c, x...) /* */ # define LOG_F(c, x...) /* */ # else /*DISABLE_LOG_X*/ +#if 0 + extern log_t *g_log; +# define LOG_G(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_EMERG > g_log->log_component[c].level || LOG_EMERG > g_log->level) logIt(c, LOG_EMERG, x); } while(0) +# define LOG_A(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_ALERT > g_log->log_component[c].level || LOG_ALERT > g_log->level) logIt(c, LOG_ALERT, x); } while(0) +# define LOG_C(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_CRIT > g_log->log_component[c].level || LOG_CRIT > g_log->level) logIt(c, LOG_CRIT, x); } while(0) +# define LOG_E(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_ERR > g_log->log_component[c].level || LOG_ERR > g_log->level) logIt(c, LOG_ERR, x); } while(0) +# define LOG_W(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_WARNING > g_log->log_component[c].level || LOG_WARNING > g_log->level) logIt(c, LOG_WARNING, x); } while(0) +# define LOG_N(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_NOTICE > g_log->log_component[c].level || LOG_NOTICE > g_log->level) logIt(c, LOG_NOTICE, x); } while(0) +# define LOG_I(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_INFO > g_log->log_component[c].level || LOG_INFO > g_log->level) logIt(c, LOG_INFO, x); } while(0) +# define LOG_D(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_DEBUG > g_log->log_component[c].level || LOG_DEBUG > g_log->level) logIt(c, LOG_DEBUG, x); } while(0) +# define LOG_F(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_FILE > g_log->log_component[c].level || LOG_FILE > g_log->level) logIt(c, LOG_FILE, x); } while(0) +# define LOG_T(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_TRACE > g_log->log_component[c].level || LOG_TRACE > g_log->level) logIt(c, LOG_TRACE, x); } while(0) +#else # define LOG_G(c, x...) logIt(c, LOG_EMERG, x) # define LOG_A(c, x...) logIt(c, LOG_ALERT, x) # define LOG_C(c, x...) logIt(c, LOG_CRIT, x) @@ -362,6 +376,7 @@ void *log_thread_function(void * list); # define LOG_D(c, x...) logIt(c, LOG_DEBUG, x) # define LOG_F(c, x...) logIt(c, LOG_FILE, x) // log to a file, useful for the MSC chart generation # define LOG_T(c, x...) logIt(c, LOG_TRACE, x) +# endif /* 0 */ # endif /*DISABLE_LOG_X*/ # endif /* T_TRACER */ #else /* USER_MODE */ diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.c b/openair2/UTIL/LOG/vcd_signal_dumper.c index e0c20f9243..08d4e61497 100644 --- a/openair2/UTIL/LOG/vcd_signal_dumper.c +++ b/openair2/UTIL/LOG/vcd_signal_dumper.c @@ -399,6 +399,17 @@ const char* eurecomFunctionsNames[] = { "compress_if", "decompress_if", + + "nfapi_subframe", + "generate_pcfich", + "generate_dci0", + "generate_dlsch", + "generate_phich", + "pdcch_scrambling", + "pdcch_modulation", + "pdcch_interleaving", + "pdcch_tx", + }; struct vcd_module_s vcd_modules[] = { diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.h b/openair2/UTIL/LOG/vcd_signal_dumper.h index 2e7f7ee792..a4c8cd2476 100644 --- a/openair2/UTIL/LOG/vcd_signal_dumper.h +++ b/openair2/UTIL/LOG/vcd_signal_dumper.h @@ -376,6 +376,16 @@ typedef enum { VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_COMPR_IF, VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_DECOMPR_IF, + VCD_SIGNAL_DUMPER_FUNCTIONS_NFAPI, + VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_PCFICH, + VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DCI0, + VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH, + VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_PHICH, + VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_SCRAMBLING, + VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_MODULATION, + VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_INTERLEAVING, + VCD_SIGNAL_DUMPER_FUNCTIONS_PDCCH_TX, + VCD_SIGNAL_DUMPER_FUNCTIONS_END } vcd_signal_dump_functions; diff --git a/openair3/GTPV1-U/gtpv1u_eNB.c b/openair3/GTPV1-U/gtpv1u_eNB.c index f70fe9cf2b..aacfa561fd 100644 --- a/openair3/GTPV1-U/gtpv1u_eNB.c +++ b/openair3/GTPV1-U/gtpv1u_eNB.c @@ -49,6 +49,7 @@ #include "COMMON/platform_constants.h" #include "UTIL/LOG/vcd_signal_dumper.h" #include "common/ran_context.h" +#include "gtpv1u_eNB_defs.h" #undef GTP_DUMP_SOCKET diff --git a/openair3/UDP/udp_eNB_task.c b/openair3/UDP/udp_eNB_task.c index bd7b804a67..868d86ad9c 100644 --- a/openair3/UDP/udp_eNB_task.c +++ b/openair3/UDP/udp_eNB_task.c @@ -427,7 +427,7 @@ on_error: return NULL; } -int udp_enb_init() +int udp_enb_init(void) { LOG_I(UDP_, "Initializing UDP task interface\n"); STAILQ_INIT(&udp_socket_list); diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index 8b62a8e698..8e747e46f5 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -420,10 +420,10 @@ static void trx_usrp_end(openair0_device *device) { /*! \brief Called to send samples to the USRP RF target @param device pointer to the device structure specific to the RF hardware target - @param timestamp The timestamp at whicch the first sample MUST be sent + @param timestamp The timestamp at which the first sample MUST be sent @param buff Buffer which holds the samples @param nsamps number of samples to be sent - @param antenna_id index of the antenna if the device has multiple anteannas + @param antenna_id index of the antenna if the device has multiple antennas @param flags flags must be set to TRUE if timestamp parameter needs to be applied */ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) { @@ -1012,9 +1012,9 @@ extern "C" { //s->usrp->set_master_clock_rate(usrp_master_clock); openair0_cfg[0].rx_gain_calib_table = calib_table_x310; -#if defined(USRP_REC_PLAY) - std::cerr << "-- Using calibration table: calib_table_x310" << std::endl; // Bell Labs info -#endif + + LOG_I(PHY,"%s() sample_rate:%u\n", __FUNCTION__, (int)openair0_cfg[0].sample_rate); + switch ((int)openair0_cfg[0].sample_rate) { case 30720000: // from usrp_time_offset @@ -1157,6 +1157,8 @@ extern "C" { s->usrp->set_tx_rate(openair0_cfg[0].sample_rate,i); s->usrp->set_tx_freq(openair0_cfg[0].tx_freq[i],i); s->usrp->set_tx_gain(gain_range_tx.stop()-openair0_cfg[0].tx_gain[i],i); + + LOG_I(PHY,"USRP TX_GAIN:%3.2lf gain_range:%3.2lf tx_gain:%3.2lf\n", gain_range_tx.stop()-openair0_cfg[0].tx_gain[i], gain_range_tx.stop(), openair0_cfg[0].tx_gain[i]); } } diff --git a/targets/COMMON/create_tasks.c b/targets/COMMON/create_tasks.c index 7d6ea9be0a..35b29e31b4 100644 --- a/targets/COMMON/create_tasks.c +++ b/targets/COMMON/create_tasks.c @@ -42,6 +42,8 @@ int create_tasks(uint32_t enb_nb, uint32_t ue_nb) { + LOG_E(ENB_APP, "%s(enb_nb:%d ue_nb:%d)\n", __FUNCTION__, enb_nb, ue_nb); + itti_wait_ready(1); if (itti_create_task (TASK_L2L1, l2l1_task, NULL) < 0) { LOG_E(PDCP, "Create task for L2L1 failed\n"); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf index ff302811e9..3a9276008b 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf @@ -17,7 +17,8 @@ eNBs = mobile_country_code = "208"; - mobile_network_code = "93"; + #mobile_network_code = "93"; + mobile_network_code = "92"; tr_s_preference = "local_mac" @@ -36,13 +37,14 @@ eNBs = downlink_frequency = 2685000000L; uplink_frequency_offset = -120000000; Nid_cell = 0; +#N_RB_DL = 25; N_RB_DL = 50; Nid_cell_mbsfn = 0; nb_antenna_ports = 1; nb_antennas_tx = 1; nb_antennas_rx = 1; tx_gain = 90; - rx_gain = 125; + rx_gain = 115; pbch_repetition = "FALSE"; prach_root = 0; prach_config_index = 0; @@ -73,7 +75,7 @@ eNBs = pusch_p0_Nominal = -96; pusch_alpha = "AL1"; - pucch_p0_Nominal = -104; + pucch_p0_Nominal = -96; msg3_delta_Preamble = 6; pucch_deltaF_Format1 = "deltaF2"; pucch_deltaF_Format1b = "deltaF3"; @@ -140,7 +142,7 @@ eNBs = ////////// MME parameters: - mme_ip_address = ( { ipv4 = "192.168.12.26"; + mme_ip_address = ( { ipv4 = "192.168.1.78"; ipv6 = "192:168:30::17"; active = "yes"; preference = "ipv4"; @@ -150,10 +152,10 @@ eNBs = NETWORK_INTERFACES : { - ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.19/24"; - ENB_INTERFACE_NAME_FOR_S1U = "eth0"; - ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.19/24"; + ENB_INTERFACE_NAME_FOR_S1_MME = "eno1"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.1.78/24"; + ENB_INTERFACE_NAME_FOR_S1U = "eno1"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.1.74/24"; ENB_PORT_FOR_S1U = 2152; # Spec 2152 }; } @@ -176,34 +178,33 @@ L1s = ( RUs = ( { - local_rf = "yes" - nb_tx = 1 - nb_rx = 1 - att_tx = 0 - att_rx = 0; - bands = [7]; - max_pdschReferenceSignalPower = -27; - max_rxgain = 125; - eNB_instances = [0]; - + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [7]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 105; + eNB_instances = [0]; } ); log_config : { - global_log_level ="info"; + global_log_level ="debug"; global_log_verbosity ="medium"; hw_log_level ="info"; hw_log_verbosity ="medium"; phy_log_level ="info"; - phy_log_verbosity ="medium"; + phy_log_verbosity ="low"; mac_log_level ="info"; - mac_log_verbosity ="high"; + mac_log_verbosity ="medium"; rlc_log_level ="info"; - rlc_log_verbosity ="medium"; + rlc_log_verbosity ="high"; pdcp_log_level ="info"; pdcp_log_verbosity ="medium"; rrc_log_level ="info"; - rrc_log_verbosity ="medium"; + rrc_log_verbosity ="high"; }; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/oaiL1.nfapi.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/oaiL1.nfapi.usrpb210.conf index f97cd0ad8b..f2e37638ab 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/oaiL1.nfapi.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/oaiL1.nfapi.usrpb210.conf @@ -1,14 +1,31 @@ +log_config = { + global_log_level ="debug"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="low"; + mac_log_level ="info"; + mac_log_verbosity ="medium"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; +}; + L1s = ( { num_cc = 1; tr_n_preference = "nfapi"; - local_n_if_name = "lo"; - remote_n_address = "127.0.0.2"; - local_n_address = "127.0.0.1"; - local_n_portc = 50000; - remote_n_portc = 50000; - local_n_portd = 50001; - remote_n_portd = 50001; + local_n_if_name = "eno1"; + remote_n_address = "192.168.1.28"; + local_n_address = "192.168.1.74"; + local_n_portc = 50000; + remote_n_portc = 50001; + local_n_portd = 50010; + remote_n_portd = 50011; } ); @@ -17,11 +34,10 @@ RUs = ( local_rf = "yes" nb_tx = 1 nb_rx = 1 - att_tx = 0 + att_tx = 90 att_rx = 0; bands = [7,38,42,43]; max_pdschReferenceSignalPower = -27; - max_rxgain = 125; - eNB_instances = [0]; + max_rxgain = 115; } -); +); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf index c9102b9b08..88aacde36b 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf @@ -17,7 +17,8 @@ eNBs = mobile_country_code = "208"; - mobile_network_code = "93"; + #mobile_network_code = "93"; + mobile_network_code = "92"; tr_s_preference = "local_mac" @@ -36,7 +37,8 @@ eNBs = downlink_frequency = 2685000000L; uplink_frequency_offset = -120000000; Nid_cell = 0; - N_RB_DL = 50; + #N_RB_DL = 50; + N_RB_DL = 25; Nid_cell_mbsfn = 0; nb_antenna_ports = 1; nb_antennas_tx = 1; @@ -71,9 +73,9 @@ eNBs = srs_ackNackST =; srs_MaxUpPts =;*/ - pusch_p0_Nominal = -96; + pusch_p0_Nominal = -86; pusch_alpha = "AL1"; - pucch_p0_Nominal = -104; + pucch_p0_Nominal = -96; msg3_delta_Preamble = 6; pucch_deltaF_Format1 = "deltaF2"; pucch_deltaF_Format1b = "deltaF3"; @@ -89,7 +91,8 @@ eNBs = rach_messagePowerOffsetGroupB = ; */ rach_powerRampingStep = 4; - rach_preambleInitialReceivedTargetPower = -108; + #rach_preambleInitialReceivedTargetPower = -108; + rach_preambleInitialReceivedTargetPower = -104; rach_preambleTransMax = 10; rach_raResponseWindowSize = 10; rach_macContentionResolutionTimer = 48; @@ -140,7 +143,7 @@ eNBs = ////////// MME parameters: - mme_ip_address = ( { ipv4 = "127.0.0.3"; + mme_ip_address = ( { ipv4 = "192.168.1.78"; ipv6 = "192:168:30::17"; active = "yes"; preference = "ipv4"; @@ -150,45 +153,47 @@ eNBs = NETWORK_INTERFACES : { - ENB_INTERFACE_NAME_FOR_S1_MME = "lo"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "127.0.0.2/24"; - ENB_INTERFACE_NAME_FOR_S1U = "lo"; - ENB_IPV4_ADDRESS_FOR_S1U = "127.0.0.5/24"; + ENB_INTERFACE_NAME_FOR_S1_MME = "eno1"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.1.28/24"; + ENB_INTERFACE_NAME_FOR_S1U = "eno1"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.1.28/24"; ENB_PORT_FOR_S1U = 2152; # Spec 2152 }; - log_config : - { - global_log_level ="info"; - global_log_verbosity ="medium"; - hw_log_level ="info"; - hw_log_verbosity ="medium"; - phy_log_level ="info"; - phy_log_verbosity ="medium"; - mac_log_level ="info"; - mac_log_verbosity ="high"; - rlc_log_level ="info"; - rlc_log_verbosity ="medium"; - pdcp_log_level ="info"; - pdcp_log_verbosity ="medium"; - rrc_log_level ="info"; - rrc_log_verbosity ="medium"; - }; } ); MACRLCs = ( { num_cc = 1; - local_s_if_name = "lo"; - remote_s_address = "127.0.0.1"; - local_s_address = "127.0.0.2"; - local_s_portc = 50000; + local_s_if_name = "eno1"; + remote_s_address = "192.168.1.74"; + #local_s_address = "192.168.1.78"; + local_s_address = "192.168.1.28"; + local_s_portc = 50001; remote_s_portc = 50000; - local_s_portd = 50001; - remote_s_portd = 50001; + local_s_portd = 50011; + remote_s_portd = 50010; tr_s_preference = "nfapi"; tr_n_preference = "local_RRC"; } ); + log_config : + { + global_log_level ="debug"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="medium"; + rlc_log_level ="info"; + rlc_log_verbosity ="high"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="high"; + }; + diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 33e6b0684b..d50cbbb854 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -121,11 +121,14 @@ extern int transmission_mode; extern int oaisim_flag; +uint16_t sf_ahead=4; + //pthread_t main_eNB_thread; time_stats_t softmodem_stats_mt; // main thread time_stats_t softmodem_stats_hw; // hw acquisition time_stats_t softmodem_stats_rxtx_sf; // total tx time +time_stats_t nfapi_meas; // total tx time time_stats_t softmodem_stats_rx_sf; // total rx time /* mutex, cond and variable to serialize phy proc TX calls @@ -151,49 +154,153 @@ void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe); void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe); #endif +extern uint8_t nfapi_mode; +extern void oai_subframe_ind(uint16_t sfn, uint16_t sf); +extern void add_subframe(uint16_t *frameP, uint16_t *subframeP, int offset); + +//#define TICK_TO_US(ts) (ts.diff) +#define TICK_TO_US(ts) (ts.trials==0?0:ts.diff/ts.trials) + + static inline int rxtx(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, char *thread_name) { + static double cpu_freq_GHz = 0.0; + + if (cpu_freq_GHz == 0.0) + cpu_freq_GHz = get_cpu_freq_GHz(); + + start_meas(&softmodem_stats_rxtx_sf); + // ******************************************************************* + + if (nfapi_mode == 1) { + + // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick + uint16_t frame = proc->frame_rx; + uint16_t subframe = proc->subframe_rx; + + //add_subframe(&frame, &subframe, 4); + + //oai_subframe_ind(proc->frame_tx, proc->subframe_tx); + //LOG_D(PHY, "oai_subframe_ind(frame:%u, subframe:%d) - NOT CALLED ********\n", frame, subframe); + start_meas(&nfapi_meas); + oai_subframe_ind(frame, subframe); + stop_meas(&nfapi_meas); + + if (eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus|| + eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs || + eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs || + eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles || + eNB->UL_INFO.cqi_ind.number_of_cqis + ) { + LOG_D(PHY, "UL_info[rx_ind:%05d:%d harqs:%05d:%d crcs:%05d:%d preambles:%05d:%d cqis:%d] RX:%04d%d TX:%04d%d num_pdcch_symbols:%d\n", + NFAPI_SFNSF2DEC(eNB->UL_INFO.rx_ind.sfn_sf), eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus, + NFAPI_SFNSF2DEC(eNB->UL_INFO.harq_ind.sfn_sf), eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs, + NFAPI_SFNSF2DEC(eNB->UL_INFO.crc_ind.sfn_sf), eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs, + NFAPI_SFNSF2DEC(eNB->UL_INFO.rach_ind.sfn_sf), eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles, + eNB->UL_INFO.cqi_ind.number_of_cqis, + proc->frame_rx, proc->subframe_rx, + proc->frame_tx, proc->subframe_tx, eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols); + } + } + + if (nfapi_mode == 1 && eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0) { + LOG_E(PHY, "eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0"); + return 0; + } + // **************************************** // Common RX procedures subframe n T(T_ENB_PHY_DL_TICK, T_INT(eNB->Mod_id), T_INT(proc->frame_tx), T_INT(proc->subframe_tx)); // if this is IF5 or 3GPP_eNB - if (eNB->RU_list[0]->function < NGFI_RAU_IF4p5) { + if (eNB && eNB->RU_list && eNB->RU_list[0] && eNB->RU_list[0]->function < NGFI_RAU_IF4p5) { + //LOG_D(PHY,"%s:%s() %u/%u Before wakeup_prach_eNB() proc->instance_cnt_rxtx:%d\n", thread_name, __FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->instance_cnt_rxtx); wakeup_prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx); + //LOG_D(PHY,"%s:%s() %u/%u Before wakeup_prach_eNB_br() proc->instance_cnt_rxtx:%d\n", thread_name, __FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->instance_cnt_rxtx); #ifdef Rel14 wakeup_prach_eNB_br(eNB,NULL,proc->frame_rx,proc->subframe_rx); + //LOG_D(PHY,"%s:%s() %u/%u proc->instance_cnt_rxtx:%d\n", thread_name, __FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->instance_cnt_rxtx); #endif } + // UE-specific RX processing for subframe n - phy_procedures_eNB_uespec_RX(eNB, proc, no_relay ); + if (nfapi_mode == 0 || nfapi_mode == 1) { + phy_procedures_eNB_uespec_RX(eNB, proc, no_relay ); + } pthread_mutex_lock(&eNB->UL_INFO_mutex); + eNB->UL_INFO.frame = proc->frame_rx; eNB->UL_INFO.subframe = proc->subframe_rx; eNB->UL_INFO.module_id = eNB->Mod_id; eNB->UL_INFO.CC_id = eNB->CC_id; + eNB->if_inst->UL_indication(&eNB->UL_INFO); + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + // ***************************************** - // TX processing for subframe n+4 + // TX processing for subframe n+sf_ahead // run PHY TX procedures the one after the other for all CCs to avoid race conditions // (may be relaxed in the future for performance reasons) // ***************************************** //if (wait_CCs(proc)<0) return(-1); - - if (oai_exit) return(-1); phy_procedures_eNB_TX(eNB, proc, no_relay, NULL, 1); - - if (release_thread(&proc->mutex_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) return(-1); stop_meas( &softmodem_stats_rxtx_sf ); + + LOG_D(PHY,"%s() Exit proc[rx:%d%d tx:%d%d]\n", __FUNCTION__, proc->frame_rx, proc->subframe_rx, proc->frame_tx, proc->subframe_tx); + +#if 0 + LOG_D(PHY, "rxtx:%lld nfapi:%lld phy:%lld tx:%lld rx:%lld prach:%lld ofdm:%lld ", + softmodem_stats_rxtx_sf.diff_now, nfapi_meas.diff_now, + TICK_TO_US(eNB->phy_proc), + TICK_TO_US(eNB->phy_proc_tx), + TICK_TO_US(eNB->phy_proc_rx), + TICK_TO_US(eNB->rx_prach), + TICK_TO_US(eNB->ofdm_mod_stats), + softmodem_stats_rxtx_sf.diff_now, nfapi_meas.diff_now); + LOG_D(PHY, + "dlsch[enc:%lld mod:%lld scr:%lld rm:%lld t:%lld i:%lld] rx_dft:%lld ", + TICK_TO_US(eNB->dlsch_encoding_stats), + TICK_TO_US(eNB->dlsch_modulation_stats), + TICK_TO_US(eNB->dlsch_scrambling_stats), + TICK_TO_US(eNB->dlsch_rate_matching_stats), + TICK_TO_US(eNB->dlsch_turbo_encoding_stats), + TICK_TO_US(eNB->dlsch_interleaving_stats), + TICK_TO_US(eNB->rx_dft_stats)); + + LOG_D(PHY," ulsch[ch:%lld freq:%lld dec:%lld demod:%lld ru:%lld ", + TICK_TO_US(eNB->ulsch_channel_estimation_stats), + TICK_TO_US(eNB->ulsch_freq_offset_estimation_stats), + TICK_TO_US(eNB->ulsch_decoding_stats), + TICK_TO_US(eNB->ulsch_demodulation_stats), + TICK_TO_US(eNB->ulsch_rate_unmatching_stats)); + + LOG_D(PHY, "td:%lld dei:%lld dem:%lld llr:%lld tci:%lld ", + TICK_TO_US(eNB->ulsch_turbo_decoding_stats), + TICK_TO_US(eNB->ulsch_deinterleaving_stats), + TICK_TO_US(eNB->ulsch_demultiplexing_stats), + TICK_TO_US(eNB->ulsch_llr_stats), + TICK_TO_US(eNB->ulsch_tc_init_stats)); + LOG_D(PHY, "tca:%lld tcb:%lld tcg:%lld tce:%lld l1:%lld l2:%lld]\n\n", + TICK_TO_US(eNB->ulsch_tc_alpha_stats), + TICK_TO_US(eNB->ulsch_tc_beta_stats), + TICK_TO_US(eNB->ulsch_tc_gamma_stats), + TICK_TO_US(eNB->ulsch_tc_ext_stats), + TICK_TO_US(eNB->ulsch_tc_intl1_stats), + TICK_TO_US(eNB->ulsch_tc_intl2_stats) + ); +#endif + //softmodem_stats_rxtx_sf.in, softmodem_stats_rxtx_sf.diff_now, softmodem_stats_rxtx_sf.max, + return(0); } @@ -213,28 +320,40 @@ static void* eNB_thread_rxtx( void* param ) { char thread_name[100]; + //LOG_D(PHY,"%s()\n", __FUNCTION__); // set default return value eNB_thread_rxtx_status = 0; - sprintf(thread_name,"RXn_TXnp4_%d\n",&eNB->proc.proc_rxtx[0] == proc ? 0 : 1); + sprintf(thread_name,"RXn_TXnp4_%d",&eNB->proc.proc_rxtx[0] == proc ? 0 : 1); thread_top_init(thread_name,1,850000L,1000000L,2000000L); + //LOG_D(PHY,"%s() thread_name:%s\n", __FUNCTION__, thread_name); + while (!oai_exit) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); + //LOG_D(PHY,"%s:%s() TX:%u/%u About to wait on proc->instance_cnt_rxtx:%d\n", thread_name, __FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->instance_cnt_rxtx); if (wait_on_condition(&proc->mutex_rxtx,&proc->cond_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) break; + //LOG_D(PHY,"%s:%s() TX:%u/%u - WOKEN on proc->instance_cnt_rxtx proc->instance_cnt_rxtx:%d \n", thread_name, __FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->instance_cnt_rxtx); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 1 ); - - if (oai_exit) break; + //LOG_D(PHY,"%s:%s() TX:%u/%u About to rxtx()\n", thread_name, __FUNCTION__, proc->frame_tx, proc->subframe_tx); if (eNB->CC_id==0) + { if (rxtx(eNB,proc,thread_name) < 0) break; + } + + //LOG_D(PHY,"%s:%s() TX:%u/%u DONE rxtx()\n", thread_name, __FUNCTION__, proc->frame_tx, proc->subframe_tx); + + if (release_thread(&proc->mutex_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) break; + } // while !oai_exit VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); @@ -278,21 +397,20 @@ void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string) proc->subframe_rx = subframe_rx; if (!oai_exit) { - LOG_D(PHY,"eNB_top in %p (proc %p, CC_id %d), frame %d, subframe %d, instance_cnt_prach %d\n", - (void*)pthread_self(), proc, eNB->CC_id, proc->frame_rx,proc->subframe_rx,proc->instance_cnt_prach); + //LOG_D(PHY,"eNB_top in %p (proc %p, CC_id %d), frame %d, subframe %d, instance_cnt_prach %d\n", + //(void*)pthread_self(), proc, eNB->CC_id, proc->frame_rx,proc->subframe_rx,proc->instance_cnt_prach); T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->subframe_rx)); proc_rxtx->subframe_rx = proc->subframe_rx; proc_rxtx->frame_rx = proc->frame_rx; - proc_rxtx->subframe_tx = (proc->subframe_rx+4)%10; - proc_rxtx->frame_tx = (proc->subframe_rx>5) ? (1+proc->frame_rx)&1023 : proc->frame_rx; + proc_rxtx->subframe_tx = (proc->subframe_rx+sf_ahead)%10; + proc_rxtx->frame_tx = (proc->subframe_rx>(9-sf_ahead)) ? (1+proc->frame_rx)&1023 : proc->frame_rx; proc->frame_tx = proc_rxtx->frame_tx; proc_rxtx->timestamp_tx = proc->timestamp_tx; if (rxtx(eNB,proc_rxtx,string) < 0) LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id); - LOG_D(PHY,"eNB_top out %p (proc %p, CC_id %d), frame %d, subframe %d, instance_cnt_prach %d\n", - (void*)pthread_self(), proc, eNB->CC_id, proc->frame_rx,proc->subframe_rx,proc->instance_cnt_prach); + //LOG_D(PHY,"eNB_top out %p (proc %p, CC_id %d), frame %d, subframe %d, instance_cnt_prach %d\n", (void*)pthread_self(), proc, eNB->CC_id, proc->frame_rx,proc->subframe_rx,proc->instance_cnt_prach); } } @@ -308,9 +426,14 @@ int wakeup_rxtx(PHY_VARS_eNB *eNB,RU_t *ru) { int i; struct timespec wait; + LOG_D(PHY,"About to wake RUs\n"); + pthread_mutex_lock(&proc->mutex_RU); + LOG_D(PHY,"eNB->num_RU:%d\n", eNB->num_RU); for (i=0;inum_RU;i++) { + LOG_D(PHY,"eNB->RU_list[%d]:%p\n",i,eNB->RU_list[i]); if (ru == eNB->RU_list[i]) { + LOG_D(PHY,"proc->RU_mask:%02x\n", proc->RU_mask); if ((proc->RU_mask&(1< 0) LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n", eNB->Mod_id,proc->frame_rx,proc->subframe_rx,ru->idx,eNB->num_RU,proc->RU_mask); @@ -318,6 +441,7 @@ int wakeup_rxtx(PHY_VARS_eNB *eNB,RU_t *ru) { } } if (proc->RU_mask != (1<num_RU)-1) { // not all RUs have provided their information so return + LOG_E(PHY,"Not all RUs have provided their info\n"); pthread_mutex_unlock(&proc->mutex_RU); return(0); } @@ -332,17 +456,19 @@ int wakeup_rxtx(PHY_VARS_eNB *eNB,RU_t *ru) { wait.tv_sec=0; wait.tv_nsec=5000000L; +#if 0 /* accept some delay in processing - up to 5ms */ for (i = 0; i < 10 && proc_rxtx->instance_cnt_rxtx == 0; i++) { - LOG_W( PHY,"[eNB] Frame %d, eNB RXn-TXnp4 thread busy!! (cnt_rxtx %i)\n", proc_rxtx->frame_tx, proc_rxtx->instance_cnt_rxtx); + LOG_W( PHY,"[eNB] Frame %d Subframe %d, eNB RXn-TXnp4 thread busy!! (cnt_rxtx %i)\n", proc_rxtx->frame_tx, proc_rxtx->subframe_tx, proc_rxtx->instance_cnt_rxtx); usleep(500); } if (proc_rxtx->instance_cnt_rxtx == 0) { - exit_fun( "TX thread busy" ); + //exit_fun( "TX thread busy" ); - DJP - this is commented out just whilst I work out what has gone wrong return(-1); } +#endif - // wake up TX for subframe n+4 + // wake up TX for subframe n+2 // lock the TX mutex and make sure the thread is ready if (pthread_mutex_timedlock(&proc_rxtx->mutex_rxtx,&wait) != 0) { LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB RXTX thread %d (IC %d)\n", proc_rxtx->subframe_rx&1,proc_rxtx->instance_cnt_rxtx ); @@ -351,19 +477,22 @@ int wakeup_rxtx(PHY_VARS_eNB *eNB,RU_t *ru) { } ++proc_rxtx->instance_cnt_rxtx; + LOG_D(PHY,"%s() %u/%u Just incremented proc->instance_cnt_rxtx:%d\n", __FUNCTION__, proc_rxtx->frame_tx, proc_rxtx->subframe_tx, proc_rxtx->instance_cnt_rxtx); // We have just received and processed the common part of a subframe, say n. // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired // transmitted timestamp of the next TX slot (first). // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, - // we want to generate subframe (n+4), so TS_tx = TX_rx+4*samples_per_tti, - // and proc->subframe_tx = proc->subframe_rx+4 - proc_rxtx->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_tti); + // we want to generate subframe (n+sf_ahead), so TS_tx = TX_rx+sf_ahead*samples_per_tti, + // and proc->subframe_tx = proc->subframe_rx+sf_ahead + proc_rxtx->timestamp_tx = proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); proc_rxtx->frame_rx = proc->frame_rx; proc_rxtx->subframe_rx = proc->subframe_rx; - proc_rxtx->frame_tx = (proc_rxtx->subframe_rx > 5) ? (proc_rxtx->frame_rx+1)&1023 : proc_rxtx->frame_rx; - proc_rxtx->subframe_tx = (proc_rxtx->subframe_rx + 4)%10; + proc_rxtx->frame_tx = (proc_rxtx->subframe_rx > (9-sf_ahead)) ? (proc_rxtx->frame_rx+1)&1023 : proc_rxtx->frame_rx; + proc_rxtx->subframe_tx = (proc_rxtx->subframe_rx + sf_ahead)%10; + LOG_D(PHY,"Signal &proc_rxtx->cond_rxtx\n"); + // the thread can now be woken up if (pthread_cond_signal(&proc_rxtx->cond_rxtx) != 0) { LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB RXn-TXnp4 thread\n"); @@ -405,7 +534,7 @@ void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { // check if we have to detect PRACH first if (is_prach_subframe(fp,frame,subframe)>0) { - LOG_D(PHY,"Triggering prach processing, frame %d, subframe %d\n",frame,subframe); + //LOG_D(PHY,"Triggering prach processing, frame %d, subframe %d\n",frame,subframe); if (proc->instance_cnt_prach == 0) { LOG_W(PHY,"[eNB] Frame %d Subframe %d, dropping PRACH\n", frame,subframe); return; @@ -521,7 +650,7 @@ static void* eNB_thread_prach( void* param ) { if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break; - LOG_D(PHY,"Running eNB prach procedures\n"); + //LOG_D(PHY,"Running eNB prach procedures\n"); prach_procedures(eNB #ifdef Rel14 ,0 @@ -562,7 +691,7 @@ static void* eNB_thread_prach_br( void* param ) { if (wait_on_condition(&proc->mutex_prach_br,&proc->cond_prach_br,&proc->instance_cnt_prach_br,"eNB_prach_thread_br") < 0) break; - LOG_D(PHY,"Running eNB prach procedures for BL/CE UEs\n"); + //LOG_D(PHY,"Running eNB prach procedures for BL/CE UEs\n"); prach_procedures(eNB,1); if (release_thread(&proc->mutex_prach_br,&proc->instance_cnt_prach_br,"eNB_prach_thread_br") < 0) break; @@ -593,10 +722,12 @@ void init_eNB_proc(int inst) { pthread_attr_t *attr_prach_br=NULL; #endif + LOG_I(PHY,"%s(inst:%d) RC.nb_CC[inst]:%d \n",__FUNCTION__,inst,RC.nb_CC[inst]); + for (CC_id=0; CC_idproc; @@ -652,6 +783,8 @@ void init_eNB_proc(int inst) { // attr_te = &proc->attr_te; #endif + LOG_I(PHY,"eNB->single_thread_flag:%d\n", eNB->single_thread_flag); + if (eNB->single_thread_flag==0) { pthread_create( &proc_rxtx[0].pthread_rxtx, attr0, eNB_thread_rxtx, &proc_rxtx[0] ); pthread_create( &proc_rxtx[1].pthread_rxtx, attr1, eNB_thread_rxtx, &proc_rxtx[1] ); @@ -787,6 +920,8 @@ void init_transport(PHY_VARS_eNB *eNB) { int j; LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; + LOG_E(PHY, "Initialise transport\n"); + for (i=0; i %p\n",i,j,eNB->dlsch[i][j]); eNB->dlsch[i][j]->rnti=0; + LOG_D(PHY,"dlsch[%d][%d] => %p rnti:%d\n",i,j,eNB->dlsch[i][j], eNB->dlsch[i][j]->rnti); } } @@ -849,20 +984,33 @@ void init_eNB_afterRU(void) { int inst,CC_id,ru_id,i,aa; PHY_VARS_eNB *eNB; + LOG_I(PHY,"%s() RC.nb_inst:%d\n", __FUNCTION__, RC.nb_inst); for (inst=0;instnum_RU>0,"Number of RU attached to eNB %d is zero\n",eNB->Mod_id); + if (0) AssertFatal(eNB->num_RU>0,"Number of RU attached to eNB %d is zero\n",eNB->Mod_id); LOG_I(PHY,"Mapping RX ports from %d RUs to eNB %d\n",eNB->num_RU,eNB->Mod_id); eNB->frame_parms.nb_antennas_rx = 0; + + LOG_E(PHY,"Overwriting eNB->prach_vars.rxsigF[0]:%p\n", eNB->prach_vars.rxsigF[0]); + eNB->prach_vars.rxsigF[0] = (int16_t**)malloc16(64*sizeof(int16_t*)); #ifdef Rel14 - for (int ce_level=0;ce_level<4;ce_level++) - eNB->prach_vars_br.rxsigF[ce_level] = (int16_t**)malloc16(64*sizeof(int16_t*)); + for (int ce_level=0;ce_level<4;ce_level++) { + LOG_E(PHY,"Overwriting eNB->prach_vars_br.rxsigF.rxsigF[0]:%p\n", eNB->prach_vars_br.rxsigF[ce_level]); + eNB->prach_vars_br.rxsigF[ce_level] = (int16_t**)malloc16(64*sizeof(int16_t*)); + } #endif + + LOG_I(PHY,"eNB->num_RU:%d\n", eNB->num_RU); + for (ru_id=0,aa=0;ru_idnum_RU;ru_id++) { eNB->frame_parms.nb_antennas_rx += eNB->RU_list[ru_id]->nb_rx; @@ -884,6 +1032,33 @@ void init_eNB_afterRU(void) { eNB->common_vars.rxdataF[aa] = eNB->RU_list[ru_id]->common.rxdataF[i]; } } + + + + + if (eNB->frame_parms.nb_antennas_rx < 1) + { + LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_rx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_rx); + eNB->frame_parms.nb_antennas_rx = 1; + } + else + { + LOG_I(PHY," Delete code\n"); + } + + if (eNB->frame_parms.nb_antennas_tx < 1) + { + LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_tx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_tx); + eNB->frame_parms.nb_antennas_tx = 1; + } + else + { + LOG_I(PHY," Delete code\n"); + } + + + + AssertFatal(eNB->frame_parms.nb_antennas_rx >0, "inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx); LOG_I(PHY,"inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx); @@ -891,9 +1066,12 @@ void init_eNB_afterRU(void) { init_transport(eNB); //init_precoding_weights(RC.eNB[inst][CC_id]); } + printf("RC.nb_CC[inst:%d]:%d CC_id:%d AFTER LOOP - About to init_eNB_proc\n", inst, RC.nb_CC[inst], CC_id); init_eNB_proc(inst); } + printf("%s() RC.nb_inst:%d AFTER LOOP\n", __FUNCTION__, RC.nb_inst); + printf("%s:%d RC.nb_RU:%d\n", __FILE__, __LINE__, RC.nb_RU); for (ru_id=0;ru_idwakeup_prach_eNB_br = wakeup_prach_eNB_br; RC.ru[ru_id]->eNB_top = eNB_top; } + + LOG_I(PHY,"%s() Exitting\n", __FUNCTION__); } void init_eNB(int single_thread_flag,int wait_for_sync) { @@ -911,7 +1091,10 @@ void init_eNB(int single_thread_flag,int wait_for_sync) { int inst; PHY_VARS_eNB *eNB; + LOG_I(PHY,"[lte-softmodem.c] eNB structure about to allocated RC.nb_L1_inst:%d RC.nb_L1_CC[0]:%d\n",RC.nb_L1_inst,RC.nb_L1_CC[0]); + if (RC.eNB == NULL) RC.eNB = (PHY_VARS_eNB***) malloc(RC.nb_L1_inst*sizeof(PHY_VARS_eNB **)); + LOG_I(PHY,"[lte-softmodem.c] eNB structure RC.eNB allocated\n"); for (inst=0;instsingle_thread_flag = single_thread_flag; + LOG_I(PHY,"Initializing eNB %d CC_id %d single_thread_flag:%d\n",inst,CC_id,single_thread_flag); #ifndef OCP_FRAMEWORK LOG_I(PHY,"Initializing eNB %d CC_id %d\n",inst,CC_id); #endif @@ -937,10 +1121,10 @@ void init_eNB(int single_thread_flag,int wait_for_sync) { memset((void*)&eNB->UL_INFO,0,sizeof(eNB->UL_INFO)); memset((void*)&eNB->Sched_INFO,0,sizeof(eNB->Sched_INFO)); LOG_I(PHY,"Setting indication lists\n"); - eNB->UL_INFO.rx_ind.rx_pdu_list = eNB->rx_pdu_list; - eNB->UL_INFO.crc_ind.crc_pdu_list = eNB->crc_pdu_list; - eNB->UL_INFO.sr_ind.sr_pdu_list = eNB->sr_pdu_list; - eNB->UL_INFO.harq_ind.harq_pdu_list = eNB->harq_pdu_list; + eNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list = eNB->rx_pdu_list; + eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = eNB->crc_pdu_list; + eNB->UL_INFO.sr_ind.sr_indication_body.sr_pdu_list = eNB->sr_pdu_list; + eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = eNB->harq_pdu_list; eNB->UL_INFO.cqi_ind.cqi_pdu_list = eNB->cqi_pdu_list; eNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = eNB->cqi_raw_pdu_list; eNB->prach_energy_counter = 0; @@ -948,11 +1132,7 @@ void init_eNB(int single_thread_flag,int wait_for_sync) { } - LOG_I(PHY,"[lte-softmodem.c] eNB structure allocated\n"); - - - } diff --git a/targets/RT/USER/lte-ran.c b/targets/RT/USER/lte-ran.c index 597ceb0654..4f9f45df86 100644 --- a/targets/RT/USER/lte-ran.c +++ b/targets/RT/USER/lte-ran.c @@ -1278,6 +1278,8 @@ void init_eNB_proc(int inst) { eNB_rxtx_proc_t *proc_rxtx; pthread_attr_t *attr0=NULL,*attr1=NULL,*attr_prach=NULL,*attr_asynch=NULL,*attr_single=NULL,*attr_fep=NULL,*attr_td=NULL,*attr_te; + printf("%s()\n", __FUNCTION__); + for (CC_id=0; CC_idnode_function],eNB_timing[eNB->node_timing]); @@ -1673,10 +1675,15 @@ void init_RAN(RAN_CONTEXT *rc,eNB_func_t node_function[], eNB_timing_t node_timi PHY_VARS_eNB *eNB; int ret; + printf("%s() rc->nb_inst:%d\n", __FUNCTION__, rc->nb_inst); + for (inst=0;instnb_inst;inst++) { + printf("%s() rc->nb_inst:%d rc->nb_CC:%d\n", __FUNCTION__, rc->nb_inst, rc->nb_CC); for (CC_id=0;CC_idnb_CC;CC_id++) { eNB = rc->eNB[inst][CC_id]; + printf("%s() rc->nb_inst:%d rc->nb_CC:%d eNB:%p rc->eNB[%d][%d]:%p\n", __FUNCTION__, rc->nb_inst, rc->nb_CC, eNB, inst, CC_id, rc->eNB[inst][CC_id]); if (eNB) { + eNB->node_function = node_function[CC_id]; eNB->node_timing = node_timing[CC_id]; eNB->abstraction_flag = 0; diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 54693f43c8..66cd5daffa 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -129,6 +129,7 @@ int attach_rru(RU_t *ru); int connect_rau(RU_t *ru); +extern uint16_t sf_ahead; /*************************************************************/ /* Functions to attach and configure RRU */ @@ -388,8 +389,8 @@ void fh_if4p5_south_in(RU_t *ru,int *frame,int *subframe) { proc->frame_rx = f; proc->timestamp_rx = ((proc->frame_rx * 10) + proc->subframe_rx ) * fp->samples_per_tti ; // proc->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_tti); - proc->subframe_tx = (sf+4)%10; - proc->frame_tx = (sf>5) ? (f+1)&1023 : f; + proc->subframe_tx = (sf+sf_ahead)%10; + proc->frame_tx = (sf>(9-sf_ahead)) ? (f+1)&1023 : f; if (proc->first_rx == 0) { if (proc->subframe_rx != *subframe){ @@ -591,6 +592,7 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { uint32_t symbol_number,symbol_mask,symbol_mask_full; int subframe_tx,frame_tx; +LOG_E(PHY, "%s(ru:%p frame, subframe)\n", __FUNCTION__, ru); symbol_number = 0; symbol_mask = 0; symbol_mask_full = ((subframe_select(fp,*subframe) == SF_S) ? (1<dl_symbols_in_S_subframe) : (1<symbols_per_tti))-1; @@ -667,6 +669,7 @@ void fh_if4p5_north_out(RU_t *ru) { stop_meas(&ru->tx_fhaul); } + void rx_rf(RU_t *ru,int *frame,int *subframe) { RU_proc_t *proc = &ru->proc; @@ -678,7 +681,7 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { for (i=0; inb_rx; i++) rxp[i] = (void*)&ru->common.rxdata[i][*subframe*fp->samples_per_tti]; - + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 ); old_ts = proc->timestamp_rx; @@ -693,8 +696,9 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { proc->timestamp_rx = ts-ru->ts_offset; - AssertFatal(rxs == fp->samples_per_tti, - "rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_tti,rxs); + //AssertFatal(rxs == fp->samples_per_tti, + //"rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_tti,rxs); + if (rxs != fp->samples_per_tti) LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_tti,rxs); if (proc->first_rx == 1) { ru->ts_offset = proc->timestamp_rx; @@ -712,15 +716,17 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10; // synchronize first reception to frame 0 subframe 0 - proc->timestamp_tx = proc->timestamp_rx+(4*fp->samples_per_tti); - proc->subframe_tx = (proc->subframe_rx+4)%10; - proc->frame_tx = (proc->subframe_rx>5) ? (proc->frame_rx+1)&1023 : proc->frame_rx; + proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti); + proc->subframe_tx = (proc->subframe_rx+sf_ahead)%10; + proc->frame_tx = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx; +#if 0 LOG_D(PHY,"RU %d/%d TS %llu (off %d), frame %d, subframe %d\n", ru->idx, 0, (unsigned long long int)proc->timestamp_rx, (int)ru->ts_offset,proc->frame_rx,proc->subframe_rx); +#endif // dump VCD output for first RU in list if (ru == RC.ru[0]) { @@ -751,10 +757,9 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff ); if (rxs != fp->samples_per_tti) - exit_fun( "problem receiving samples" ); - - - + { + //exit_fun( "problem receiving samples" ); + } } @@ -777,7 +782,6 @@ void tx_rf(RU_t *ru) { if ((SF_type == SF_DL) || (SF_type == SF_S)) { - int siglen=fp->samples_per_tti,flags=1; if (SF_type == SF_S) { @@ -815,8 +819,8 @@ void tx_rf(RU_t *ru) { ru->nb_tx, flags); - LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx, - (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx); + //LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx, + //(long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); @@ -944,22 +948,26 @@ static void* ru_thread_prach( void* param ) { thread_top_init("ru_thread_prach",1,500000L,1000000L,20000000L); +LOG_E(PHY,"In rach thread\n"); + + while (RC.ru_mask>0) { + usleep(1e6); + LOG_I(PHY,"%s() RACH waiting for RU to be configured\n", __FUNCTION__); + } + LOG_I(PHY,"%s() RU configured - RACH processing thread running\n", __FUNCTION__); + while (!oai_exit) { if (oai_exit) break; if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 ); - rx_prach(NULL, - ru, - NULL, - NULL, - NULL, - proc->frame_prach, - 0 + prach_procedures( + ru->eNB_list[0] #ifdef Rel14 - ,0 + ,0 #endif - ); + ); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0 ); if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break; } @@ -1109,21 +1117,29 @@ void wakeup_eNBs(RU_t *ru) { int i; PHY_VARS_eNB **eNB_list = ru->eNB_list; - LOG_D(PHY,"wakeup_eNBs (num %d) for RU %d\n",ru->num_eNB,ru->idx); + //LOG_D(PHY,"wakeup_eNBs (num %d) for RU %d ru->eNB_top:%p\n",ru->num_eNB,ru->idx, ru->eNB_top); - if (ru->num_eNB==1) { + if (ru->num_eNB==1 && ru->eNB_top!=0) { // call eNB function directly char string[20]; sprintf(string,"Incoming RU %d",ru->idx); - LOG_D(PHY,"RU %d Waking up eNB\n",ru->idx); + //LOG_D(PHY,"RU %d Call eNB_top\n",ru->idx); ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.subframe_rx,string); } else { + LOG_D(PHY,"ru->num_eNB:%d\n", ru->num_eNB); + for (i=0;inum_eNB;i++) - if (ru->wakeup_rxtx(eNB_list[i],ru) < 0) + { + LOG_D(PHY,"ru->wakeup_rxtx:%p\n", ru->wakeup_rxtx); + + if (ru->wakeup_rxtx!=0 && ru->wakeup_rxtx(eNB_list[i],ru) < 0) + { LOG_E(PHY,"could not wakeup eNB rxtx process for subframe %d\n", ru->proc.subframe_rx); + } + } } } @@ -1144,7 +1160,11 @@ static inline int wakeup_prach_ru(RU_t *ru) { ru->proc.frame_prach = ru->proc.frame_rx; ru->proc.subframe_prach = ru->proc.subframe_rx; - LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx); + // DJP - think prach_procedures() is looking at eNB frame_prach + ru->eNB_list[0]->proc.frame_prach = ru->proc.frame_rx; + ru->eNB_list[0]->proc.subframe_prach = ru->proc.subframe_rx; + + //LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx); // the thread can now be woken up AssertFatal(pthread_cond_signal(&ru->proc.cond_prach) == 0, "ERROR pthread_cond_signal for RU prach thread\n"); } @@ -1183,6 +1203,40 @@ static inline int wakeup_prach_ru_br(RU_t *ru) { } #endif +#if 0 +static inline int wakeup_nfapi_subframe_thread(RU_t *ru) { + + int i; + PHY_VARS_eNB **eNB_list = ru->eNB_list; + + LOG_D(PHY,"wakeup_nfapi_subframe_thread (num %d) for RU %d ru->eNB_top:%p\n",ru->num_eNB,ru->idx, ru->eNB_top); + + if (ru->num_eNB==1 && ru->eNB_top!=0) { + // call eNB function directly + + char string[20]; + sprintf(string,"Incoming RU %d",ru->idx); + //LOG_D(PHY,"RU %d Call eNB_top\n",ru->idx); + ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.subframe_rx,string); + } + else { + + LOG_D(PHY,"ru->num_eNB:%d\n", ru->num_eNB); + + for (i=0;inum_eNB;i++) + { + LOG_D(PHY,"ru->wakeup_rxtx:%p\n", ru->wakeup_rxtx); + + if (ru->wakeup_rxtx!=0 && ru->wakeup_rxtx(eNB_list[i],ru) < 0) + { + LOG_E(PHY,"could not wakeup eNB rxtx process for subframe %d\n", ru->proc.subframe_rx); + } + } + } +} +#endif + + // this is for RU with local RF unit void fill_rf_config(RU_t *ru, char *rf_config_file) { @@ -1370,7 +1424,6 @@ static void* ru_thread( void* param ) { init_frame_parms(&ru->frame_parms,1); phy_init_RU(ru); - ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); } if (setup_RU_buffers(ru)!=0) { @@ -1426,23 +1479,30 @@ static void* ru_thread( void* param ) { subframe++; } - LOG_D(PHY,"RU thread (proc %p), frame %d (%p), subframe %d (%p)\n", - proc, frame,&frame,subframe,&subframe); - - // synchronization on input FH interface, acquire signals/data and block if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&subframe); else AssertFatal(1==0, "No fronthaul interface at south port"); + LOG_D(PHY,"AFTER fh_south_in - SFN/SF:%d%d RU->proc[RX:%d%d TX:%d%d] RC.eNB[0][0]:[RX:%d%d TX(SFN):%d]\n", + frame,subframe, + proc->frame_rx,proc->subframe_rx, + proc->frame_tx,proc->subframe_tx, + RC.eNB[0][0]->proc.frame_rx,RC.eNB[0][0]->proc.subframe_rx, + RC.eNB[0][0]->proc.frame_tx); - LOG_D(PHY,"RU thread (do_prach %d, is_prach_subframe %d), received frame %d, subframe %d\n", - ru->do_prach, - is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx), - proc->frame_rx,proc->subframe_rx); + if (0 && is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)) + LOG_D(PHY,"RU thread (do_prach %d, is_prach_subframe %d), received frame %d, subframe %d\n", + ru->do_prach, + is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx), + proc->frame_rx,proc->subframe_rx); - if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)==1)) wakeup_prach_ru(ru); + if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)==1)) { + wakeup_prach_ru(ru); + } #ifdef Rel14 - else if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)>1)) wakeup_prach_ru_br(ru); + else if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)>1)) { + wakeup_prach_ru_br(ru); + } #endif // adjust for timing offset between RU @@ -1456,12 +1516,15 @@ static void* ru_thread( void* param ) { // If this proc is to provide synchronization, do so wakeup_slaves(proc); + //LOG_E(PHY,"RU %d/%d frame_tx %d, subframe_tx %d - wakeup_eNBs...\n",0,ru->idx,proc->frame_tx,proc->subframe_tx); // wakeup all eNB processes waiting for this RU if (ru->num_eNB>0) wakeup_eNBs(ru); - // wait until eNBs are finished subframe RX n and TX n+4 + //LOG_E(PHY,"%s() Before wait_on_condition()\n", __FUNCTION__); + // wait until eNBs are finished subframe RX n and TX n+sf_ahead wait_on_condition(&proc->mutex_eNBs,&proc->cond_eNBs,&proc->instance_cnt_eNBs,"ru_thread"); + //LOG_E(PHY,"%s() AFTER wait_on_condition() ru->feptx_prec:%p ru->fh_north_asynch_in:%p ru->feptx_ofdm:%p ru->fh_south_out:%p ru->fh_north_out:%p\n", __FUNCTION__, ru->feptx_prec, ru->fh_north_asynch_in, ru->feptx_ofdm, ru->fh_south_out, ru->fh_north_out); // do TX front-end processing if needed (precoding and/or IDFTs) if (ru->feptx_prec) ru->feptx_prec(ru); @@ -1472,7 +1535,6 @@ static void* ru_thread( void* param ) { if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru); if (ru->fh_north_out) ru->fh_north_out(ru); - } @@ -1592,6 +1654,7 @@ void init_RU_proc(RU_t *ru) { #endif char name[100]; + LOG_E(PHY,"Initializing RU proc %d (%s,%s),\n",ru->idx,eNB_functions[ru->function],eNB_timing[ru->if_timing]); #ifndef OCP_FRAMEWORK LOG_I(PHY,"Initializing RU proc %d (%s,%s),\n",ru->idx,eNB_functions[ru->function],eNB_timing[ru->if_timing]); #endif @@ -1646,6 +1709,8 @@ void init_RU_proc(RU_t *ru) { pthread_create( &proc->pthread_FH, attr_FH, ru_thread, (void*)ru ); + LOG_E(PHY,"%s() DJP - ru->function:%d\n", __FUNCTION__, ru->function); + if (ru->function == NGFI_RRU_IF4p5) { pthread_create( &proc->pthread_prach, attr_prach, ru_thread_prach, (void*)ru ); #ifdef Rel14 @@ -1662,6 +1727,10 @@ void init_RU_proc(RU_t *ru) { pthread_setname_np( proc->pthread_FH, name ); } + else if (ru->function == eNodeB_3GPP && ru->if_south == LOCAL_RF) { // DJP - need something else to distinguish between monolithic and PNF + LOG_E(PHY,"%s() DJP - added creation of pthread_prach\n", __FUNCTION__); + pthread_create( &proc->pthread_prach, attr_prach, ru_thread_prach, (void*)ru ); + } if (get_nprocs()>=2) { if (ru->feprx) init_fep_thread(ru,NULL); @@ -1671,10 +1740,6 @@ void init_RU_proc(RU_t *ru) { } - - - - int check_capabilities(RU_t *ru,RRU_capabilities_t *cap) { FH_fmt_options_t fmt = cap->FH_fmt; @@ -1872,10 +1937,13 @@ void init_RU(char *rf_config_file) { RCconfig_RU(); LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",RC.nb_L1_inst,RC.nb_RU,get_nprocs()); - for (i=0;inum_RU=0; + if (RC.nb_CC != 0) + for (i=0;inum_RU=0; +LOG_E(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU); for (ru_id=0;ru_idrf_config_file = rf_config_file; ru->idx = ru_id; @@ -1883,24 +1951,47 @@ void init_RU(char *rf_config_file) { // use eNB_list[0] as a reference for RU frame parameters // NOTE: multiple CC_id are not handled here yet! - + printf("%s() RC.ru[%d].num_eNB:%d ru->eNB_list[0]:%p RC.eNB[0][0]:%p rf_config_file:%s\n", __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file); + + if (ru->eNB_list[0] == 0) + { + LOG_E(PHY,"%s() DJP - ru->eNB_list ru->num_eNB are not initialized - so do it manually\n", __FUNCTION__); + ru->eNB_list[0] = RC.eNB[0][0]; + ru->num_eNB=1; + // + // DJP - feptx_prec() / feptx_ofdm() parses the eNB_list (based on num_eNB) and copies the txdata_F to txdata in RU + // + } + else + { + LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__); + } + eNB0 = ru->eNB_list[0]; - if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5)) - AssertFatal(eNB0!=NULL,"eNB0 is null!\n"); + printf("RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south); + printf("eNB0:%p\n", eNB0); + if (eNB0) + { + if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5)) + AssertFatal(eNB0!=NULL,"eNB0 is null!\n"); - if (eNB0) { - LOG_I(PHY,"Copying frame parms from eNB %d to ru %d\n",eNB0->Mod_id,ru->idx); - memcpy((void*)&ru->frame_parms,(void*)&eNB0->frame_parms,sizeof(LTE_DL_FRAME_PARMS)); + if (eNB0) { + LOG_I(PHY,"Copying frame parms from eNB %d to ru %d\n",eNB0->Mod_id,ru->idx); + memcpy((void*)&ru->frame_parms,(void*)&eNB0->frame_parms,sizeof(LTE_DL_FRAME_PARMS)); - // attach all RU to all eNBs in its list/ - for (i=0;inum_eNB;i++) { - eNB0 = ru->eNB_list[i]; - eNB0->RU_list[eNB0->num_RU++] = ru; + // attach all RU to all eNBs in its list/ + LOG_E(PHY,"ru->num_eNB:%d eNB0->num_RU:%d\n", ru->num_eNB, eNB0->num_RU); + for (i=0;inum_eNB;i++) { + eNB0 = ru->eNB_list[i]; + eNB0->RU_list[eNB0->num_RU++] = ru; + } } } // LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n",ru_id,ru_if_types[ru->if_south],eNB_timing[ru->if_timing],ru->function); - + +LOG_E(PHY,"ru->if_south:%d\n", ru->if_south); + switch (ru->if_south) { case LOCAL_RF: // this is an RU with integrated RF (RRU, eNB) if (ru->function == NGFI_RRU_IF5) { // IF5 RRU @@ -1979,7 +2070,8 @@ void init_RU(char *rf_config_file) { if (setup_RU_buffers(ru)!=0) { printf("Exiting, cannot initialize RU Buffers\n"); exit(-1); - }*/ + } + */ break; case REMOTE_IF5: // the remote unit is IF5 RRU diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index e90fc4335c..c786a62e2e 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -101,7 +101,6 @@ unsigned short config_frames[4] = {2,9,11,13}; #endif #include "lte-softmodem.h" - #ifdef XFORMS // current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0) // at eNB 0, an UL scope for every UE @@ -113,9 +112,16 @@ unsigned char scope_enb_num_ue = 2; static pthread_t forms_thread; //xforms #endif //XFORMS +pthread_cond_t nfapi_sync_cond; +pthread_mutex_t nfapi_sync_mutex; +int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex + +uint8_t nfapi_mode = 0; // Default to monolithic mode + pthread_cond_t sync_cond; pthread_mutex_t sync_mutex; int sync_var=-1; //!< protected by mutex \ref sync_mutex. +int config_sync_var=-1; uint16_t runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] uint16_t runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] @@ -205,6 +211,12 @@ uint64_t num_missed_slots=0; // counter for the number of missed slots extern void reset_opp_meas(void); extern void print_opp_meas(void); +extern PHY_VARS_UE* init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms, + uint8_t UE_id, + uint8_t abstraction_flag); + +extern void init_eNB_afterRU(void); + int transmission_mode=1; @@ -839,7 +851,7 @@ void init_openair0() { void wait_RUs(void) { - LOG_I(PHY,"Waiting for RUs to be configured ...\n"); + LOG_I(PHY,"Waiting for RUs to be configured ... RC.ru_mask:%02lx\n", RC.ru_mask); // wait for all RUs to be configured over fronthaul pthread_mutex_lock(&RC.ru_mutex); @@ -848,6 +860,7 @@ void wait_RUs(void) { while (RC.ru_mask>0) { pthread_cond_wait(&RC.ru_cond,&RC.ru_mutex); + printf("RC.ru_mask:%02lx\n", RC.ru_mask); } LOG_I(PHY,"RUs configured\n"); @@ -861,18 +874,36 @@ void wait_eNBs(void) { while (waiting==1) { printf("Waiting for eNB L1 instances to all get configured ... sleeping 500ms (nb_L1_inst %d)\n",RC.nb_L1_inst); - usleep(500000); + usleep(5000000); waiting=0; - for (i=0;iconfigured==0) { waiting=1; break; - } + } + } + } } printf("eNB L1 are configured\n"); } +static inline void wait_nfapi_init(char *thread_name) { + + printf( "waiting for NFAPI PNF connection and population of global structure (%s)\n",thread_name); + pthread_mutex_lock( &nfapi_sync_mutex ); + + while (nfapi_sync_var<0) + pthread_cond_wait( &nfapi_sync_cond, &nfapi_sync_mutex ); + + pthread_mutex_unlock(&nfapi_sync_mutex); + + printf( "NFAPI: got sync (%s)\n", thread_name); +} + int main( int argc, char **argv ) { int i; @@ -974,6 +1005,7 @@ int main( int argc, char **argv ) log_set_instance_type (LOG_INSTANCE_ENB); } + printf("ITTI init\n"); itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info, messages_definition_xml, itti_dump_file); // initialize mscgen log after ITTI @@ -993,6 +1025,7 @@ int main( int argc, char **argv ) } #ifdef PDCP_USE_NETLINK + printf("PDCP netlink\n"); netlink_init(); #if defined(PDCP_USE_NETLINK_QUEUES) pdcp_netlink_init(); @@ -1026,6 +1059,7 @@ int main( int argc, char **argv ) + printf("Before CC \n"); for (CC_id=0; CC_id2 */ cpu_set_t cpuset; @@ -1162,6 +1198,8 @@ int main( int argc, char **argv ) #ifdef XFORMS int UE_id; + printf("XFORMS\n"); + if (do_forms==1) { fl_initialize (&argc, argv, NULL, 0, 0); @@ -1218,6 +1256,35 @@ int main( int argc, char **argv ) rt_sleep_ns(10*100000000ULL); + if (nfapi_mode) { + + printf("NFAPI*** - mutex and cond created - will block shortly for completion of PNF connection\n"); + pthread_cond_init(&sync_cond,NULL); + pthread_mutex_init(&sync_mutex, NULL); + } + + const char *nfapi_mode_str = ""; + + switch(nfapi_mode) { + case 0: + nfapi_mode_str = "MONOLITHIC"; + break; + case 1: + nfapi_mode_str = "PNF"; + break; + case 2: + nfapi_mode_str = "VNF"; + break; + default: + nfapi_mode_str = ""; + break; + } + printf("NFAPI MODE:%s\n", nfapi_mode_str); + + if (nfapi_mode==2) // VNF + wait_nfapi_init("main?"); + + printf("START MAIN THREADS\n"); // start the main threads if (UE_flag == 1) { @@ -1238,15 +1305,18 @@ int main( int argc, char **argv ) } else { number_of_cards = 1; + printf("RC.nb_L1_inst:%d\n", RC.nb_L1_inst); if (RC.nb_L1_inst > 0) { - printf("Initializing eNB threads\n"); + printf("Initializing eNB threads single_thread_flag:%d wait_for_sync:%d\n", single_thread_flag,wait_for_sync); init_eNB(single_thread_flag,wait_for_sync); // for (inst=0;inst0) { printf("Initializing RU threads\n"); init_RU(rf_config_file); @@ -1256,10 +1326,30 @@ int main( int argc, char **argv ) } } + config_sync_var=0; + + if (nfapi_mode==1) { // PNF + wait_nfapi_init("main?"); + } + + printf("wait RUs\n"); wait_RUs(); + printf("ALL RUs READY!\n"); + printf("RC.nb_RU:%d\n", RC.nb_RU); // once all RUs are ready intiailize the rest of the eNBs ((dependence on final RU parameters after configuration) - init_eNB_afterRU(); + printf("ALL RUs ready - init eNBs\n"); + + if (nfapi_mode != 1 && nfapi_mode != 2) + { + printf("Not NFAPI mode - call init_eNB_afterRU()\n"); + init_eNB_afterRU(); + } + else + { + printf("NFAPI mode - DO NOT call init_eNB_afterRU()\n"); + } + printf("ALL RUs ready - ALL eNBs ready\n"); } @@ -1293,38 +1383,35 @@ int main( int argc, char **argv ) //p_exmimo_config->framing.tdd_config = TXRXSWITCH_TESTRX; } else { - - - + printf("eNB mode\n"); } - - - printf("Sending sync to all threads\n"); - - pthread_mutex_lock(&sync_mutex); sync_var=0; pthread_cond_broadcast(&sync_cond); pthread_mutex_unlock(&sync_mutex); + printf("About to call end_configmodule() from %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); end_configmodule(); + printf("Called end_configmodule() from %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); // wait for end of program printf("TYPE TO TERMINATE\n"); //getchar(); - #if defined(ENABLE_ITTI) printf("Entering ITTI signals handler\n"); itti_wait_tasks_end(); + printf("Returned from ITTI signal handler\n"); oai_exit=1; + printf("oai_exit=%d\n",oai_exit); #else while (oai_exit==0) rt_sleep_ns(100000000ULL); + printf("Terminating application - oai_exit=%d\n",oai_exit); #endif @@ -1367,6 +1454,9 @@ int main( int argc, char **argv ) pthread_cond_destroy(&sync_cond); pthread_mutex_destroy(&sync_mutex); + pthread_cond_destroy(&nfapi_sync_cond); + pthread_mutex_destroy(&nfapi_sync_mutex); + // *** Handle per CC_id openair0 diff --git a/targets/RT/USER/pnf.gtkw b/targets/RT/USER/pnf.gtkw new file mode 100644 index 0000000000..979d632138 --- /dev/null +++ b/targets/RT/USER/pnf.gtkw @@ -0,0 +1,54 @@ +[*] +[*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI +[*] Tue Jul 25 20:26:12 2017 +[*] +[dumpfile] "/tmp/openair_dump_eNB.vcd" +[dumpfile_mtime] "Tue Jul 25 20:11:55 2017" +[dumpfile_size] 19201475 +[savefile] "/home/papillon/openairinterface5g/targets/RT/USER/eNB_usrp.gtkw" +[timestart] 29023604000 +[size] 1236 578 +[pos] 309 0 +*-20.793451 29026062100 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[sst_width] 386 +[signals_width] 262 +[sst_expanded] 1 +[sst_vpaned_height] 146 +@28 +functions.trx_read +functions.trx_write +@24 +variables.trx_ts[63:0] +variables.trx_tst[63:0] +@25 +variables.frame_number_RX0_RU[63:0] +variables.subframe_number_RX0_RU[63:0] +@25 +variables.frame_number_TX0_RU[63:0] +variables.subframe_number_TX0_RU[63:0] +@24 +functions.phy_procedures_ru_feprx0 +functions.phy_procedures_ru_feprx1 +functions.phy_procedures_eNb_rx_uespec0 +functions.phy_procedures_eNb_tx0 +functions.eNB_thread_rxtx1 +functions.phy_enb_prach_rx +functions.phy_enb_rs_tx +functions.phy_enb_pdcch_tx +functions.nfapi_subframe +functions.generate_pcfich +functions.generate_dci0 +functions.pdcch_scrambling +functions.pdcch_modulation +functions.pdcch_interleaving +functions.pdcch_tx +functions.generate_dlsch +functions.generate_phich +functions.udp_enb_task +functions.phy_procedures_ru_feptx_ofdm0 +functions.phy_procedures_ru_feptx_ofdm1 +functions.phy_procedures_ru_feptx_prec0 +functions.phy_procedures_ru_feptx_prec1 +functions.phy_enb_prach_rx +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/targets/RT/USER/rt_wrapper.c b/targets/RT/USER/rt_wrapper.c index 8751e3c816..c1e5996d44 100644 --- a/targets/RT/USER/rt_wrapper.c +++ b/targets/RT/USER/rt_wrapper.c @@ -345,6 +345,8 @@ void thread_top_init(char *thread_name, exit_fun("Error getting thread priority"); } + pthread_setname_np(pthread_self(), thread_name); + LOG_I(HW, "[SCHED][eNB] %s started on CPU %d, sched_policy = %s , priority = %d, CPU Affinity=%s \n",thread_name,sched_getcpu(), (policy == SCHED_FIFO) ? "SCHED_FIFO" : (policy == SCHED_RR) ? "SCHED_RR" : From 922b5b595a0492eea7edca41b25d656774cc1380 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 15 Jan 2018 15:24:50 +0100 Subject: [PATCH 140/284] Fix NFAPI integration This commit fixes issues introduced by the previous commit. Summary of work: - cleanup: - fix LOG_XX to be less verbose - fix cmake_targets/CMakeLists.txt - fix oaienv - remove dead code - bug fixes: - in openair1/SCHED/fapi_l1.c we had: eNB->pdcch_vars[subframe&1].num_dci = number_dci; should be: eNB->pdcch_vars[subframe&1].num_dci = 0; This bug let the PHY send more DCIs than what should have been sent because num_dci is incremented later on in the code. This fix may be a problem for fapi mode, to be checked. - add new T VCD traces - revert openair1/PHY/TOOLS/file_output.c to 'develop' version - remove thread_id in logRecord/logRecord_mt - revert (and adapt) configuration files - be careful when doing frame++, we need to % 1024 - revert target_rx_power in openair2/LAYER2/MAC/eNB_scheduler_ulsch.c - NFAPI: - the open-nFAPI code has been included in the repository. See nfapi/README. Maybe we should "git clone" the Cisco repository instead. We have to be careful of availability though. What has been tested: - monolithic eNB FDD 5/10MHz with one UE, iperf UDP/TCP uplink/downlink Anything else may fail to work, especially the FAPI mode, which has not been tested at all. --- cmake_targets/CMakeLists.txt | 57 +- common/utils/T/T_defs.h | 2 +- common/utils/T/T_messages.txt | 36 + nfapi/README | 15 + nfapi/open-nFAPI/.travis.yml | 36 + nfapi/open-nFAPI/CHANGELOG.md | 0 nfapi/open-nFAPI/LICENSE.md | 201 + nfapi/open-nFAPI/Makefile.am | 15 + nfapi/open-nFAPI/README.md | 138 + nfapi/open-nFAPI/common/Makefile.am | 31 + nfapi/open-nFAPI/common/public_inc/debug.h | 51 + nfapi/open-nFAPI/common/src/debug.c | 76 + nfapi/open-nFAPI/configure.ac | 45 + nfapi/open-nFAPI/docs/Doxyfile | 1720 +++++ nfapi/open-nFAPI/docs/Doxyfile.in | 1720 +++++ nfapi/open-nFAPI/docs/Makefile.am | 35 + nfapi/open-nFAPI/docs/doxygen.h | 327 + .../open-nFAPI/integration_tests/Makefile.am | 29 + nfapi/open-nFAPI/integration_tests/main.cpp | 269 + nfapi/open-nFAPI/nfapi/Makefile.am | 30 + nfapi/open-nFAPI/nfapi/inc/nfapi.h | 91 + .../nfapi/public_inc/nfapi_interface.h | 3855 ++++++++++ nfapi/open-nFAPI/nfapi/src/nfapi.c | 860 +++ nfapi/open-nFAPI/nfapi/src/nfapi_p4.c | 2084 ++++++ nfapi/open-nFAPI/nfapi/src/nfapi_p5.c | 1799 +++++ nfapi/open-nFAPI/nfapi/src/nfapi_p7.c | 6184 +++++++++++++++++ nfapi/open-nFAPI/nfapi/tests/Makefile.am | 36 + .../open-nFAPI/nfapi/tests/nfapi_cunit_main.c | 5511 +++++++++++++++ nfapi/open-nFAPI/pnf/Makefile.am | 32 + nfapi/open-nFAPI/pnf/inc/pnf.h | 49 + nfapi/open-nFAPI/pnf/inc/pnf_p7.h | 126 + .../pnf/public_inc/nfapi_pnf_interface.h | 803 +++ nfapi/open-nFAPI/pnf/src/pnf.c | 1598 +++++ nfapi/open-nFAPI/pnf/src/pnf_interface.c | 432 ++ nfapi/open-nFAPI/pnf/src/pnf_p7.c | 1769 +++++ nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c | 225 + nfapi/open-nFAPI/pnf/tests/Makefile.am | 28 + nfapi/open-nFAPI/pnf/tests/pnf_cunit_main.c | 2365 +++++++ nfapi/open-nFAPI/pnf_sim/Makefile.am | 22 + nfapi/open-nFAPI/pnf_sim/inc/fapi_interface.h | 1800 +++++ nfapi/open-nFAPI/pnf_sim/inc/fapi_stub.h | 76 + nfapi/open-nFAPI/pnf_sim/src/fapi_stub.cpp | 642 ++ nfapi/open-nFAPI/pnf_sim/src/main.cpp | 2285 ++++++ nfapi/open-nFAPI/sim_common/Makefile.am | 31 + nfapi/open-nFAPI/sim_common/inc/pool.h | 186 + nfapi/open-nFAPI/sim_common/inc/vendor_ext.h | 71 + nfapi/open-nFAPI/sim_common/src/pool.cpp | 15 + nfapi/open-nFAPI/vnf/Makefile.am | 43 + nfapi/open-nFAPI/vnf/inc/vnf.h | 46 + nfapi/open-nFAPI/vnf/inc/vnf_p7.h | 136 + .../vnf/public_inc/nfapi_vnf_interface.h | 995 +++ nfapi/open-nFAPI/vnf/src/vnf.c | 1123 +++ nfapi/open-nFAPI/vnf/src/vnf_interface.c | 676 ++ nfapi/open-nFAPI/vnf/src/vnf_p7.c | 1599 +++++ nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c | 562 ++ nfapi/open-nFAPI/vnf/tests/Makefile.am | 30 + nfapi/open-nFAPI/vnf/tests/vnf_cunit_main.c | 1497 ++++ nfapi/open-nFAPI/vnf_sim/Makefile.am | 22 + nfapi/open-nFAPI/vnf_sim/inc/mac.h | 60 + nfapi/open-nFAPI/vnf_sim/src/mac.cpp | 1327 ++++ nfapi/open-nFAPI/vnf_sim/src/main.cpp | 1525 ++++ nfapi/open-nFAPI/xml/pnf_phy_1_A.xml | 88 + nfapi/open-nFAPI/xml/pnf_phy_1_A_ws.xml | 90 + nfapi/open-nFAPI/xml/pnf_phy_1_B.xml | 88 + nfapi/open-nFAPI/xml/pnf_phy_2_A.xml | 90 + nfapi/open-nFAPI/xml/vnf_A.xml | 21 + nfapi/open-nFAPI/xml/vnf_A_ws.xml | 23 + oaienv | 11 - openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c | 2 +- openair1/PHY/LTE_TRANSPORT/dci.c | 5 - openair1/PHY/LTE_TRANSPORT/dci_tools.c | 29 +- openair1/PHY/LTE_TRANSPORT/pucch.c | 4 +- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 2 +- .../PHY/LTE_TRANSPORT/ulsch_demodulation.c | 7 - openair1/PHY/TOOLS/file_output.c | 6 +- openair1/PHY/defs.h | 2 - openair1/SCHED/fapi_l1.c | 9 +- openair1/SCHED/fapi_l1.h | 2 +- openair1/SCHED/phy_procedures_lte_eNb.c | 55 +- openair1/SCHED/ru_procedures.c | 10 - openair2/ENB_APP/enb_config.c | 10 +- openair2/LAYER2/MAC/eNB_scheduler.c | 13 - openair2/LAYER2/MAC/eNB_scheduler_RA.c | 18 +- openair2/LAYER2/MAC/eNB_scheduler_bch.c | 12 +- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 12 +- .../LAYER2/MAC/eNB_scheduler_primitives.c | 27 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 10 +- openair2/LAYER2/MAC/pre_processor.c | 16 +- openair2/PHY_INTERFACE/IF_Module.c | 27 +- openair2/RRC/LITE/L2_interface.c | 5 +- openair2/RRC/LITE/rrc_eNB.c | 4 +- openair2/UTIL/LOG/log.c | 22 +- openair2/UTIL/LOG/log.h | 27 +- targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp | 4 + targets/COMMON/create_tasks.c | 2 +- .../CONF/enb.band7.tm1.50PRB.usrpb210.conf | 47 +- .../CONF/oaiL1.nfapi.usrpb210.conf | 21 +- .../CONF/rcc.band7.tm1.50PRB.nfapi.conf | 66 +- targets/RT/USER/lte-enb.c | 58 +- targets/RT/USER/lte-ran.c | 7 - targets/RT/USER/lte-ru.c | 76 +- targets/RT/USER/lte-softmodem.c | 6 +- 102 files changed, 48002 insertions(+), 481 deletions(-) create mode 100644 nfapi/README create mode 100644 nfapi/open-nFAPI/.travis.yml create mode 100644 nfapi/open-nFAPI/CHANGELOG.md create mode 100644 nfapi/open-nFAPI/LICENSE.md create mode 100644 nfapi/open-nFAPI/Makefile.am create mode 100644 nfapi/open-nFAPI/README.md create mode 100644 nfapi/open-nFAPI/common/Makefile.am create mode 100644 nfapi/open-nFAPI/common/public_inc/debug.h create mode 100644 nfapi/open-nFAPI/common/src/debug.c create mode 100644 nfapi/open-nFAPI/configure.ac create mode 100644 nfapi/open-nFAPI/docs/Doxyfile create mode 100644 nfapi/open-nFAPI/docs/Doxyfile.in create mode 100644 nfapi/open-nFAPI/docs/Makefile.am create mode 100644 nfapi/open-nFAPI/docs/doxygen.h create mode 100644 nfapi/open-nFAPI/integration_tests/Makefile.am create mode 100644 nfapi/open-nFAPI/integration_tests/main.cpp create mode 100644 nfapi/open-nFAPI/nfapi/Makefile.am create mode 100644 nfapi/open-nFAPI/nfapi/inc/nfapi.h create mode 100644 nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h create mode 100644 nfapi/open-nFAPI/nfapi/src/nfapi.c create mode 100644 nfapi/open-nFAPI/nfapi/src/nfapi_p4.c create mode 100644 nfapi/open-nFAPI/nfapi/src/nfapi_p5.c create mode 100644 nfapi/open-nFAPI/nfapi/src/nfapi_p7.c create mode 100644 nfapi/open-nFAPI/nfapi/tests/Makefile.am create mode 100644 nfapi/open-nFAPI/nfapi/tests/nfapi_cunit_main.c create mode 100644 nfapi/open-nFAPI/pnf/Makefile.am create mode 100644 nfapi/open-nFAPI/pnf/inc/pnf.h create mode 100644 nfapi/open-nFAPI/pnf/inc/pnf_p7.h create mode 100644 nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h create mode 100644 nfapi/open-nFAPI/pnf/src/pnf.c create mode 100644 nfapi/open-nFAPI/pnf/src/pnf_interface.c create mode 100644 nfapi/open-nFAPI/pnf/src/pnf_p7.c create mode 100644 nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c create mode 100644 nfapi/open-nFAPI/pnf/tests/Makefile.am create mode 100644 nfapi/open-nFAPI/pnf/tests/pnf_cunit_main.c create mode 100644 nfapi/open-nFAPI/pnf_sim/Makefile.am create mode 100644 nfapi/open-nFAPI/pnf_sim/inc/fapi_interface.h create mode 100644 nfapi/open-nFAPI/pnf_sim/inc/fapi_stub.h create mode 100644 nfapi/open-nFAPI/pnf_sim/src/fapi_stub.cpp create mode 100644 nfapi/open-nFAPI/pnf_sim/src/main.cpp create mode 100644 nfapi/open-nFAPI/sim_common/Makefile.am create mode 100644 nfapi/open-nFAPI/sim_common/inc/pool.h create mode 100644 nfapi/open-nFAPI/sim_common/inc/vendor_ext.h create mode 100644 nfapi/open-nFAPI/sim_common/src/pool.cpp create mode 100644 nfapi/open-nFAPI/vnf/Makefile.am create mode 100644 nfapi/open-nFAPI/vnf/inc/vnf.h create mode 100644 nfapi/open-nFAPI/vnf/inc/vnf_p7.h create mode 100644 nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h create mode 100644 nfapi/open-nFAPI/vnf/src/vnf.c create mode 100644 nfapi/open-nFAPI/vnf/src/vnf_interface.c create mode 100644 nfapi/open-nFAPI/vnf/src/vnf_p7.c create mode 100644 nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c create mode 100644 nfapi/open-nFAPI/vnf/tests/Makefile.am create mode 100644 nfapi/open-nFAPI/vnf/tests/vnf_cunit_main.c create mode 100644 nfapi/open-nFAPI/vnf_sim/Makefile.am create mode 100644 nfapi/open-nFAPI/vnf_sim/inc/mac.h create mode 100644 nfapi/open-nFAPI/vnf_sim/src/mac.cpp create mode 100644 nfapi/open-nFAPI/vnf_sim/src/main.cpp create mode 100644 nfapi/open-nFAPI/xml/pnf_phy_1_A.xml create mode 100644 nfapi/open-nFAPI/xml/pnf_phy_1_A_ws.xml create mode 100644 nfapi/open-nFAPI/xml/pnf_phy_1_B.xml create mode 100644 nfapi/open-nFAPI/xml/pnf_phy_2_A.xml create mode 100644 nfapi/open-nFAPI/xml/vnf_A.xml create mode 100644 nfapi/open-nFAPI/xml/vnf_A_ws.xml diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 7b4e30b030..32f06de025 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -27,8 +27,8 @@ cmake_minimum_required (VERSION 2.8) # Base directories, compatible with legacy OAI building ################################################ set (OPENAIR_DIR $ENV{OPENAIR_DIR}) -set (NFAPI_DIR $ENV{NFAPI_DIR}) -set (NFAPI_USER_DIR ${OPENAIR_DIR}/nfapi) +set (NFAPI_DIR ${OPENAIR_DIR}/nfapi/open-nFAPI) +set (NFAPI_USER_DIR ${OPENAIR_DIR}/nfapi/oai_integration) set (OPENAIR1_DIR ${OPENAIR_DIR}/openair1) set (OPENAIR2_DIR ${OPENAIR_DIR}/openair2) set (OPENAIR3_DIR ${OPENAIR_DIR}/openair3) @@ -1061,9 +1061,9 @@ include_directories(${NFAPI_DIR}/vnf/inc) # nFAPI user defined code ############################# set(NFAPI_USER_SRC -${NFAPI_USER_DIR}/nfapi.c -${NFAPI_USER_DIR}/nfapi_pnf.c -${NFAPI_USER_DIR}/nfapi_vnf.c + ${NFAPI_USER_DIR}/nfapi.c + ${NFAPI_USER_DIR}/nfapi_pnf.c + ${NFAPI_USER_DIR}/nfapi_vnf.c ) add_library(NFAPI_USER_LIB ${NFAPI_USER_SRC}) include_directories(${NFAPI_USER_DIR}) @@ -1740,26 +1740,6 @@ endif() add_definitions("-DNETTLE_VERSION_MAJOR=${NETTLE_VERSION_MAJOR}") add_definitions("-DNETTLE_VERSION_MINOR=${NETTLE_VERSION_MINOR}") -#pkg_search_module(NFAPI nfapi) -#if(NOT ${NFAPI_FOUND}) - #message( FATAL_ERROR "PACKAGE nfapi not found: some targets will fail. Run build_oai -I again!") -#else() - #include_directories(${NFAPI_INCLUDE_DIRS}) - #message( "PACKAGE nfapi!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") - #message( "${NFAPI_INCLUDE_DIR}") - #message( "${NFAPI_COMMON_INCLUDE_DIR}") - #message( "${NFAPI_VNF_INCLUDE_DIR}") - #message( "${NFAPI_PNF_INCLUDE_DIR}") - #message( "XXX") - #message( "${NFAPI_LIBRARY}") - #message( "${NFAPI_COMMON_LIBRARY}") - #message( "${NFAPI_PNF_LIBRARY}") - #message( "XXX") - #message( "${NFAPI_LIBRARIES}") - #message( "XXX") -#endif() - - pkg_search_module(XPM xpm) if(NOT ${XPM_FOUND}) message("PACKAGE xpm not found: some targets will fail") @@ -1815,12 +1795,6 @@ if (${T_TRACER}) set (T_LIB "rt") endif (${T_TRACER}) -#if (${NFAPI_DIR}) -#set (NFAPI_PNF_LIB "nfapi_pnf") -#set (NFAPI_LIB "nfapi") -#set (NFAPI_COMMON_LIB "nfapi_common") -#endif (${NFAPI_DIR}) -# #Some files in the T directory are generated. #This rule and the following deal with it. add_custom_command ( @@ -2005,27 +1979,6 @@ add_executable(oaisim ${SHLIB_LOADER_SOURCES} ) -#add_library( imp_nfapi STATIC IMPORTED) -#set_property(TARGET imp_nfapi PROPERTY IMPORTED_LOCATION ${NFAPI_DIR}/libnfapi.a) -#set_property(TARGET imp_nfapi PROPERTY IMPORTED_IMPLIB ${NFAPI_DIR}/libnfapi.a) -#target_link_libraries(oaisim imp_nfapi) - -#add_library( imp_nfapi_common STATIC IMPORTED) -#set_property(TARGET imp_nfapi_common PROPERTY IMPORTED_LOCATION ${NFAPI_DIR}/common/libnfapi_common.a) -#set_property(TARGET imp_nfapi_common PROPERTY IMPORTED_IMPLIB ${NFAPI_DIR}/common/libnfapi_common.a) -#target_link_libraries(oaisim imp_nfapi_common) - -#add_library( imp_nfapi_pnf STATIC IMPORTED) -#set_property(TARGET imp_nfapi_pnf PROPERTY IMPORTED_LOCATION ${NFAPI_DIR}/pnf/libnfapi_pnf.a) -#set_property(TARGET imp_nfapi_pnf PROPERTY IMPORTED_IMPLIB ${NFAPI_DIR}/pnf/libnfapi_pnf.a) -#target_link_libraries(oaisim imp_nfapi_pnf) - -# -#add_library (imp_nfapi_common STATIC IMPORTED) -#set_target_properties(imp_nfapi_common PROPERTIES IMPORTED_LOCATION ${NFAPI_DIR}/common/libnfapi_common.a -#set_target_properties(oaisim PROPERTIES LINK_FLAGS ${NFAPI_DIR}/nfapi/libnfapi.a ${NFAPI_DIR}/pnf/libnfapi_pnf.a ${NFAPI_DIR}/common/libnfapi_common.a) - - target_include_directories(oaisim PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim diff --git a/common/utils/T/T_defs.h b/common/utils/T/T_defs.h index 24845b6b9e..6bdda0edac 100644 --- a/common/utils/T/T_defs.h +++ b/common/utils/T/T_defs.h @@ -29,7 +29,7 @@ typedef struct { #define T_SHM_FILENAME "/T_shm_segment" /* number of VCD functions (to be kept up to date! see in T_messages.txt) */ -#define VCD_NUM_FUNCTIONS 178 +#define VCD_NUM_FUNCTIONS 187 /* number of VCD variables (to be kept up to date! see in T_messages.txt) */ #define VCD_NUM_VARIABLES 128 diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index 3e37b5ea15..3009cc3305 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -2157,3 +2157,39 @@ ID = VCD_FUNCTION_TRX_DECOMPR_IF DESC = VCD function TRX_DECOMPR_IF GROUP = ALL:VCD:ENB:VCD_FUNCTION FORMAT = int,value +ID = VCD_FUNCTION_NFAPI + DESC = VCD function NFAPI + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_GENERATE_PCFICH + DESC = VCD function GENERATE_PCFICH + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_GENERATE_DCI0 + DESC = VCD function GENERATE_DCI0 + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_GENERATE_DLSCH + DESC = VCD function GENERATE_DLSCH + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_GENERATE_PHICH + DESC = VCD function GENERATE_PHICH + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PDCCH_SCRAMBLING + DESC = VCD function PDCCH_SCRAMBLING + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PDCCH_MODULATION + DESC = VCD function PDCCH_MODULATION + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PDCCH_INTERLEAVING + DESC = VCD function PDCCH_INTERLEAVING + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PDCCH_TX + DESC = VCD function PDCCH_TX + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value diff --git a/nfapi/README b/nfapi/README new file mode 100644 index 0000000000..b2e1321532 --- /dev/null +++ b/nfapi/README @@ -0,0 +1,15 @@ +This directory contains the NFAPI code. + +It comes in two parts: + +1 - open-nFAPI + + This is a clone of the github repository + (https://github.com/cisco/open-nFAPI, + commit b3bc579b1697eab829d5d8a2de59c93a61b88fa4). + The patch open-nfapi.oai.patch has then been applied. + +2 - oai_integration + + This is code written by David Price from Cisco to integrate + open-nFAPI into OpenAirInterface. diff --git a/nfapi/open-nFAPI/.travis.yml b/nfapi/open-nFAPI/.travis.yml new file mode 100644 index 0000000000..ce2faea923 --- /dev/null +++ b/nfapi/open-nFAPI/.travis.yml @@ -0,0 +1,36 @@ + +env: + global: + # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created + # via the "travis encrypt" command using the project repo's public key + - secure: "oNj8JhGBN/zjzrAU7y2Nn/wxSxA/MDp2Y8fVLLp6fhx+y2mWdlMZhgCjeKSpdbGtroUnxErX1P8t+8EPz2+mMoq+G809Q9t7eJjd1+6nkVhEEfDXN83BmJkvIylC0/IKJiT2wCa8LzbdhpQUFyZ1Gk1WKZozAW5HotfFjm6/NFi/GX4uA7S0tU5E4yC3r4yqH9cLZ+arWMOEY/X0lrx0n6tLjDe921kFwkZQGFzAzrbXN2fZXKQ3xFcpREWEgEWsY7H2n4T7oJI3nEPY4P/4kvCjeQMjnlATEwtcciBiUbHRew4WWSTndF54crRlqFlzFcEf/Ouz27U/d2xYHJWcWNi88l+/qsb+V0uobwhiGUJGbVhf9IkgEO3tr/zbwkPDFrXpa/1xuSoc6jDm8i61gKQkcBhQsRFXlciPvwLhiL07gzeAfZD1Yke3tE+0geHPbEA0czzwtHe35jorAKYWsFXOXmcoK9t9SpnvBRFz6JuEsHPooafze43sTJg3qkgBszkU+U38CneeAVwo/uTA3Zw1ZrtOQv56v0UvAHze/VAF5z3rFJPl1oJl60OI8V5UBg4yIa2bySKhO//zwd4MGmsBpcWwDuu2BHUVasfk0vaetVxVVtdXG/2BuBP+IXinpJtI48NSFs6PT82dHz4cDF/iLDs0hPC6sbV258PY8F0=" + +language: cpp + +dist: trusty +sudo: required + +compiler: + - g++ + +before_install: + - sudo apt-get install doxygen + - sudo apt-get install libcunit1-dev + - sudo apt-get install libz-dev + - sudo apt-get install libsctp-dev + - sudo apt-get install libboost-all-dev + - autoreconf -i + +addons: + coverity_scan: + project: + name: cisco-open-nFAPI + version: 1.0 + description: Build submitted via Travis CI + notification_email: xxx@cisco.com + build_command_prepend: ./configure + build_command: make + branch_pattern: coverity_scan + +script: + - ./configure && make && make check diff --git a/nfapi/open-nFAPI/CHANGELOG.md b/nfapi/open-nFAPI/CHANGELOG.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/nfapi/open-nFAPI/LICENSE.md b/nfapi/open-nFAPI/LICENSE.md new file mode 100644 index 0000000000..5e0fd33cbb --- /dev/null +++ b/nfapi/open-nFAPI/LICENSE.md @@ -0,0 +1,201 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all +other entities that control, are controlled by, or are under common +control with that entity. For the purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation +source, and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or +Object form, made available under the License, as indicated by a +copyright notice that is included in or attached to the work +(an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object +form, that is based on (or derived from) the Work and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. For the purposes +of this License, Derivative Works shall not include works that remain +separable from, or merely link (or bind by name) to the interfaces of, +the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including +the original version of the Work and any modifications or additions +to that Work or Derivative Works thereof, that is intentionally +submitted to Licensor for inclusion in the Work by the copyright owner +or by an individual or Legal Entity authorized to submit on behalf of +the copyright owner. For the purposes of this definition, "submitted" +means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, +and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work, +where such license applies only to those patent claims licensable +by such Contributor that are necessarily infringed by their +Contribution(s) alone or by combination of their Contribution(s) +with the Work to which such Contribution(s) was submitted. If You +institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work +or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate +as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You +meet the following conditions: + +(a) You must give any other recipients of the Work or +Derivative Works a copy of this License; and + +(b) You must cause any modified files to carry prominent notices +stating that You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works +that You distribute, all copyright, patent, trademark, and +attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of +the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its +distribution, then any Derivative Works that You distribute must +include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not +pertain to any part of the Derivative Works, in at least one +of the following places: within a NOTICE text file distributed +as part of the Derivative Works; within the Source form or +documentation, if provided along with the Derivative Works; or, +within a display generated by the Derivative Works, if and +wherever such third-party notices normally appear. The contents +of the NOTICE file are for informational purposes only and +do not modify the License. You may add Your own attribution +notices within Derivative Works that You distribute, alongside +or as an addendum to the NOTICE text from the Work, provided +that such additional attribution notices cannot be construed +as modifying the License. + +You may add Your own copyright statement to Your modifications and +may provide additional or different license terms and conditions +for use, reproduction, or distribution of Your modifications, or +for any such Derivative Works as a whole, provided Your use, +reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "{}" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + +Copyright {yyyy} {name of copyright owner} + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/nfapi/open-nFAPI/Makefile.am b/nfapi/open-nFAPI/Makefile.am new file mode 100644 index 0000000000..900cf2bbcf --- /dev/null +++ b/nfapi/open-nFAPI/Makefile.am @@ -0,0 +1,15 @@ +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS =common/ \ + sim_common/ \ + nfapi/ \ + pnf/ \ + vnf/ \ + nfapi/tests \ + pnf/tests \ + vnf/tests \ + pnf_sim/ \ + vnf_sim/ \ + integration_tests/ \ + docs/ \ + $(NULL) diff --git a/nfapi/open-nFAPI/README.md b/nfapi/open-nFAPI/README.md new file mode 100644 index 0000000000..f3132c78d6 --- /dev/null +++ b/nfapi/open-nFAPI/README.md @@ -0,0 +1,138 @@ +[![Build Status](https://travis-ci.org/cisco/open-nFAPI.svg?branch=master)](https://travis-ci.org/cisco/open-nFAPI) +[![Coverity Status](https://scan.coverity.com/projects/11791/badge.svg)](https://scan.coverity.com/projects/cisco-open-nfapi) + +# open-nFAPI + +Open-nFAPI is implementation of the Small Cell Forum's network functional API or nFAPI for short. +nFAPI defines a network protocol that is used to connect a Physical Network Function (PNF) +running LTE Layer 1 to a Virtual Network Function (VNF) running LTE layer 2 and above. The specification +can be found at http://scf.io/documents/082. + +The aim of open-nFAPI is to provide an open interface between LTE layer 1 and layer 2 to allow for +interoperability between the PNF and VNF & also to facilitate the sharing of PNF's between +different VNF's + +Open-nFAPI implements the P4, P5 and P7 interfaces as defined by the nFAPI specification. +* The P5 interface allows the VNF to query and configure the 'resources' of the PNF; i.e slice it into + 1 or more PHY instances. +* The P7 interface is used to send the subframe information between the PNF and VNF for a PHY instance +* The P4 interface allows the VNF to request the PNF PHY instance to perform measurements of the surrounding network + +The remaining interfaces are currently outside of the scope of this project. + +Supports release 082.09.05 of the nFAPI specification + +**The Small Cell Forum cordially requests that any derivative work that looks to +extend the nFAPI libraries use the specified vendor extension techniques, +so ensuring the widest interoperability of the baseline nFAPI specification +in those derivative works.** + +## Awards + +The Open-nFAPI project has won the Small Cell Forum Judges Choice award 2017. (http://www.smallcellforum.org/awards-2/winners-2017/) + +## Licensing + +The open-nFAPI libraries are release by CISCO under an Apache 2 license. See `LICENSE.md` file for details + +## Downloading + +The open-nFAPI project can be pulled from git hub + +``` +git clone https://github.com/cisco/open-nFAPI.git nfapi +``` + +The following dependencies are required. These are based on a fresh ubuntu installation. + +``` +sudo apt-get install autoconf +sudo apt-get install gcc +sudo apt-get install g++ +sudo apt-get install libtool +sudo apt-get install make +sudo apt-get install doxygen +sudo apt-get install libcunit1-dev +sudo apt-get install libz-dev +sudo apt-get install libsctp-dev +sudo apt-get install libboost-all-dev +``` + + + +## Building + +To build the open-nFAPI project + +``` +autoreconf -i +./configure +make +``` + +To run the unit and integration tests + +``` +make check +``` + +You may notice in the console output of the final integration tests the following + +``` +*** Missing subframe 123 125 +``` + +Out of the box the machine on which you are running has not be configured for real time operation as a result +the vnf may not be scheduled at the correct times and hence it may risk 'missing' subframe opportunities. This +warning indicates this has happened. + +## Running the simulator + +The vnf and pnf simulator can be run using the following commands. The pnf and vnf simulator support sourcing and sinking +data over udp. Review the xml configuration files for the details of the port and address to configure. Console logging will show +which address:port is being used + +Note : Pinning the simulators to unused cores will produce more consistent behaviour. + +Note : You may have to run the processes with sudo to be able to set the real time scheduling and priority + +### vnf simulator + +To run the vnf simulator you need to specify the port the vnf will listen for p5 connection request upon and also the xml configuration file + +``` +vnfsim +``` + +### pnf simulator + +To run the vnf simulator you need to specify the addrss & port the pnf will connect to the vnf on and also the xml configuration file + +``` +pnfsim
    +``` + + +## Directory structure + +``` +docs doxgen documentation +common common code used by the nfapi libraries +nfapi the nfapi library including message definitions & encode/decode functions +pnf the pnf library for p4, p5, & p7 interfaces +vnf the vnf library for p4, p5, & p7 interfaces +sim_common common simulation for used by the vnf and pnf sim +vnf_sim a vnf simulator including a stub mac implementation +pnf_sim a pnf simualtor including a fapi interface defintion and stub implementation +xml xml configuration files for the vnf and pnf simulator +wireshark code for a wireshark dissector for the nFAPI protocol +``` + +## Coverity + +Coverity runs on the coverity-scan branch. Changes must be merged to the coverity-scan branch to be checked. + + +## eNB Integration - Open Air Interface + +The open-nFAPI implementation has been integrated with the Open Air Interface solution here (https://gitlab.eurecom.fr/oai/openairinterface5g) and is (at the time of writing) here (https://gitlab.eurecom.fr/daveprice/openairinterface5g/tree/nfapi-ru-rau-split). The open-nFAPI implementation is integrated with the source eNB implementation with any changes required applied as a patch on top of the baseline open-nFAPI library. Any extensions required must be implemented through the vendor extensions as specified by the Small Cell Forum documentation. Any integration wrapping of functionality must be done within the target environment as shown in the Open Air Interface implementation nfapi directory which is defined by the $NFAPI_DIR location at the top level. diff --git a/nfapi/open-nFAPI/common/Makefile.am b/nfapi/open-nFAPI/common/Makefile.am new file mode 100644 index 0000000000..3e3326ea2c --- /dev/null +++ b/nfapi/open-nFAPI/common/Makefile.am @@ -0,0 +1,31 @@ +# +# Copyright 2017 Cisco Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +AM_CPPFLAGS = -I$(top_srcdir)/common/public_inc -g -Wall -Werror + +noinst_LIBRARIES =libnfapi_common.a + +libnfapi_common_a_SOURCES = src/debug.c + +libnfapi_common_a_CFLAGS =$(AM_CFLAGS) + +lib_LTLIBRARIES =libnfapi_common.la + +libnfapi_common_la_SOURCES = src/debug.c + + + + diff --git a/nfapi/open-nFAPI/common/public_inc/debug.h b/nfapi/open-nFAPI/common/public_inc/debug.h new file mode 100644 index 0000000000..14f97a17f6 --- /dev/null +++ b/nfapi/open-nFAPI/common/public_inc/debug.h @@ -0,0 +1,51 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +/*! The trace levels used by the nfapi libraries */ +typedef enum nfapi_trace_level +{ + NFAPI_TRACE_ERROR = 1, + NFAPI_TRACE_WARN, + NFAPI_TRACE_NOTE, + NFAPI_TRACE_INFO, + + NFAPI_TRACE_LEVEL_MAX +} nfapi_trace_level_t; + +/*! The trace function pointer */ +typedef void (*nfapi_trace_fn_t)(nfapi_trace_level_t level, const char* format, ...); + +/*! Global trace function */ +extern nfapi_trace_fn_t nfapi_trace_g; + +/*! Global trace level */ +extern nfapi_trace_level_t nfapi_trace_level_g; + +/*! NFAPI trace macro */ +//#define NFAPI_TRACE(level, format, ...) { if(nfapi_trace_g && ((nfapi_trace_level_t)level <= nfapi_trace_level_g)) (*nfapi_trace_g)(level, format, ##__VA_ARGS__); } +#define NFAPI_TRACE(level, format, ...) { if (nfapi_trace_g) (*nfapi_trace_g)(level, format, ##__VA_ARGS__); } + +/*! Function to change the trace level + * \param new_level The modified trace level + */ + +void nfapi_set_trace_level(nfapi_trace_level_t new_level); + +#endif /* _DEBUG_H_ */ diff --git a/nfapi/open-nFAPI/common/src/debug.c b/nfapi/open-nFAPI/common/src/debug.c new file mode 100644 index 0000000000..a45d41d7d7 --- /dev/null +++ b/nfapi/open-nFAPI/common/src/debug.c @@ -0,0 +1,76 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MAX_MSG_LENGTH 2096 +#define TRACE_HEADER_LENGTH 44 + +void nfapi_trace_dbg(nfapi_trace_level_t level, const char *format, ...); + +// initialize the trace function to 0 +void (*nfapi_trace_g)(nfapi_trace_level_t level, const char* format, ...) = &nfapi_trace_dbg; + +nfapi_trace_level_t nfapi_trace_level_g = NFAPI_TRACE_INFO; +//nfapi_trace_level_t nfapi_trace_level_g = NFAPI_TRACE_WARN; + +void nfapi_set_trace_level(nfapi_trace_level_t new_level) +{ + nfapi_trace_level_g = new_level; +} + +void nfapi_trace_dbg(nfapi_trace_level_t level, const char *format, ...) +{ + char trace_buff[MAX_MSG_LENGTH + TRACE_HEADER_LENGTH]; + uint32_t num_chars; + va_list p_args; + struct timeval tv; + pthread_t tid = pthread_self(); + + (void)gettimeofday(&tv, NULL); + + num_chars = (uint32_t)snprintf(trace_buff, TRACE_HEADER_LENGTH, "%04u.%06u: 0x%02x: %10u: ", ((uint32_t)tv.tv_sec) & 0x1FFF, (uint32_t)tv.tv_usec, (uint32_t)level, (uint32_t)tid); + + if (num_chars > TRACE_HEADER_LENGTH) + { + printf("trace_dbg: Error, num_chars is too large: %d", num_chars); + return; + } + + va_start(p_args, format); + if ((num_chars = (uint32_t)vsnprintf(&trace_buff[num_chars], MAX_MSG_LENGTH, format, p_args))) + { + if (level <= NFAPI_TRACE_WARN) + { + printf("%s", trace_buff); + } + printf("%s", trace_buff); + } + va_end(p_args); +} diff --git a/nfapi/open-nFAPI/configure.ac b/nfapi/open-nFAPI/configure.ac new file mode 100644 index 0000000000..fd3b387ee5 --- /dev/null +++ b/nfapi/open-nFAPI/configure.ac @@ -0,0 +1,45 @@ +AC_INIT([open-nFAPI], [1.0]) + +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE([subdir-objects -Wall -Werror foreign serial-tests]) +AM_PROG_AR + +LT_INIT([shared static]) + +# Dependencies +AC_PROG_CC +AC_PROG_CXX +AC_PROG_AWK +AC_CONFIG_HEADERS([config.h]) + +AC_PROG_LIBTOOL + +AC_CHECK_FILE([/usr/include/CUnit/CUnit.h], + [CFLAGS_CUNIT=-I/usr/include/CUnit AC_SUBST(CFLAGS_CUNIT)], + [AC_MSG_NOTICE([Have cunit *************])]) + +# Need doxygen +AC_CHECK_PROGS([DOXYGEN], [doxygen]) +if test -z "$DOXYGEN"; + then AC_MSG_WARN([Doxygen not found - continuing without Doxygen support]) +fi +AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"])AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([docs/Doxyfile])]) + +AC_REQUIRE_AUX_FILE([tap-driver.sh]) + +AC_CONFIG_FILES([Makefile + sim_common/Makefile + common/Makefile + nfapi/Makefile + pnf/Makefile + vnf/Makefile + nfapi/tests/Makefile + pnf/tests/Makefile + vnf/tests/Makefile + pnf_sim/Makefile + vnf_sim/Makefile + integration_tests/Makefile + docs/Makefile +]) +AC_OUTPUT diff --git a/nfapi/open-nFAPI/docs/Doxyfile b/nfapi/open-nFAPI/docs/Doxyfile new file mode 100644 index 0000000000..9491727d2b --- /dev/null +++ b/nfapi/open-nFAPI/docs/Doxyfile @@ -0,0 +1,1720 @@ +# Doxyfile 1.7.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = open-nFAPI + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 1.0 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../nfapi/public_inc ../pnf/public_inc ../vnf/public_inc ../docs/doxygen.h + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is adviced to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# If the HTML_TIMESTAMP tag is set to YES then the generated HTML documentation will contain the timesstamp. + +HTML_TIMESTAMP = NO + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called Helvetica to the output +# directory and reference it in all dot files that doxygen generates. +# When you want a differently looking font you can specify the font name +# using DOT_FONTNAME. You need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/nfapi/open-nFAPI/docs/Doxyfile.in b/nfapi/open-nFAPI/docs/Doxyfile.in new file mode 100644 index 0000000000..74d405ad00 --- /dev/null +++ b/nfapi/open-nFAPI/docs/Doxyfile.in @@ -0,0 +1,1720 @@ +# Doxyfile 1.7.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = @PACKAGE_NAME@ + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @PACKAGE_VERSION@ + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @top_srcdir@/nfapi/public_inc @top_srcdir@/pnf/public_inc @top_srcdir@/vnf/public_inc @top_srcdir@/docs/doxygen.h + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is adviced to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# If the HTML_TIMESTAMP tag is set to YES then the generated HTML documentation will contain the timesstamp. + +HTML_TIMESTAMP = NO + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called Helvetica to the output +# directory and reference it in all dot files that doxygen generates. +# When you want a differently looking font you can specify the font name +# using DOT_FONTNAME. You need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/nfapi/open-nFAPI/docs/Makefile.am b/nfapi/open-nFAPI/docs/Makefile.am new file mode 100644 index 0000000000..9530fa844d --- /dev/null +++ b/nfapi/open-nFAPI/docs/Makefile.am @@ -0,0 +1,35 @@ +# +# Copyright 2017 Cisco Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +if HAVE_DOXYGEN +directory = $(top_srcdir)/docs/man/man3/ + +dist_man_MANS = $(directory)/man_page_1.3 $(directory)/man_page_2.3 +$(directory)/man_page_1.3: doxyfile.stamp +$(directory)/man_page_2.3: doxyfile.stamp + +doxyfile.stamp: + $(DOXYGEN) Doxyfile + echo Timestamp > doxyfile.stamp + +CLEANFILES = doxyfile.stamp + +all-local: doxyfile.stamp +clean-local: + rm -rf $(top_srcdir)/docs/man + rm -rf $(top_srcdir)/docs/html + rm -rf $(top_srcdir)/docs/latex +endif diff --git a/nfapi/open-nFAPI/docs/doxygen.h b/nfapi/open-nFAPI/docs/doxygen.h new file mode 100644 index 0000000000..ae815e68d6 --- /dev/null +++ b/nfapi/open-nFAPI/docs/doxygen.h @@ -0,0 +1,327 @@ +/*! \mainpage Open Network Function Application Platform Interface (Open-nFAPI) + * + * \section intro_sec Introduction + * + * Open-nFAPI is implementation of the Small Cell Forum's network femto API or nFAPI for short. + * nFAPI defines a network protocol that is used to connect a Physical Network Function (PNF) + * running LTE Layer 1 to a Virtual Network Function (VNF) running LTE Layer 2 and above. The specification + * can be found at http://scf.io/documents/082. + * + * The aim of Open-nFAPI is to provide an open interface between LTE Layer 1 and Layer 2 to allow for + * interoperability between the PNF and VNF & also to facilitate the sharing of PNF's between + * different VNF's + * + * Open-nFAPI implements the P4, P5 and P7 interfaces as defined by the nFAPI specification. + * - The P5 interface allows the VNF to query and configure the 'resources' of the PNF; slicing it into + * 1 or more phy instances. + * - The P7 interface is used to send the subframe information between the PNF and VNF for 1 or more phy instances + * - The P4 interface allows the VNF to request the PNF phy instances to perform measurements of the surrounding network + * + * The remaining interfaces are currently outside of the scope of this project. + * + * The best place to start is by reviewing the detailed nFAPI call flow which can be \ref nfapi_call_flow "here" + * + * \section contrib Contibuting + * + * The Small Cell Forum cordially requests that any derivative work that looks to extend + * the nFAPI libraries use the specified vendor extension techniques, so ensuring + *the widest interoperability of the baseline nFAPI specification in those derivative works. + * + * \section install_sec Installation + * + * \subsection step1 Step 1: Opening the box + * + * etc... + * + * \section dir_struct Directory Structure + * \code + + * nfapi + * |- common Common functions for the nfapi project + * | |- src + * | |- public-inc + * |- nfapi The NFAPI lib + * | |- inc + * | |- src + * | |- public-inc Public interface for the nfapi library + * | |- tests Unit test for the nfapi lib + * |- pnf The PNF lib + * | |- inc + * | |- src + * | |- public-inc Public interface for the pnf library + * | |- tests Unit test for the pnf lib + * |- vnf The VNF lib + * | |- inc + * | |- src + * | |- public-inc Public interface for the vnf library + * | |- tests Unit test for the vnf lib + * |- sim_common Common functions for the nfapi simulators + * | |- inc + * | |- src + * |- pnf_sim The PNF simulator + * | |- inc + * | |- src + * |- vnf_sim The VNF simulator + * | |- inc + * | |- src + * |- integration_tests Integration tests that run both VNF & PNF simulators + * | |- inc + * | |- src + * |- docs Documentation + * |- xml Xml configuration for the simulator + + * \endcode + * \section building Building + * To build the nfapi project and run the unit test you will need to + * \code + * autoreconf -i + * ./configure + * make + * make check + * \endcode + * The following dependencies will be required + * - Boost. Need to build the simulators + * - STCP. Need to run the simulators + * - + * \section simulators Running the simulators + * Once you have build the nfapi project you can run the PNF/VNF simulators on either the same + * of seperate linux machines. + * + * To run the VNF from the vnf_sim directory. + * \code + * ./vnfsim 4242 ../xml/vnf_A.xml + * [MAC] Rx Data from 8891 + * [MAC] Tx Data to 10.231.16.80.8892 + * Calling nfapi_vnf_start + * 2035.854438: 0x04: 773068608: nfapi_vnf_start() + * 2035.854450: 0x04: 773068608: Starting P5 VNF connection on port 4242 + * 2035.854472: 0x04: 773068608: P5 socket created... 3 + * 2035.854478: 0x03: 773068608: VNF Setting the SCTP_INITMSG + * 2035.854481: 0x04: 773068608: IPV4 binding to port 4242 + * 2035.854485: 0x04: 773068608: bind succeeded..3. + * 2035.854497: 0x04: 773068608: listen succeeded... + * \endcode + * + * + * To run the PNF from the pnf_sim directory + * \code + * ./pnfsim 127.0.01 4242 ../xml/pnf_phy_1_A.xml + * nfapi_pnf_start + * Starting P5 PNF connection to VNF at 127.0.0.1:4242 + * Host address info 0 Family:IPV4 Address:127.0.0.1 + * PNF Setting the SCTP_INITMSG + * P5 socket created... + * Socket CONNECTED + * PNF_PARAM.request received + * [PNF_SIM] pnf param request + * PNF_CONFIG.request received + * [PNF_SIM] pnf config request + * .... and so on + * \endcode + * + * You can Ctrl-C to exit the simulators. + * + + */ + +/*! \page nfapi_call_flow NFAPI Call Flow + * + * \section seq_diag Sequence diagram + * + * The follow sequence digram show how the nFAPI api will be used to bring up + * the PNF and then the PNF PHY and initiate subframe message exchange + * The names of the CLIENT callbacks are placeholders for the functions that + * the CLIENT will provide. + * + * \msc + * + * width="1750"; + * FAPI, PNF_P7_CLIENT, PNF_P7_LIB, PNF_P5_CLIENT, PNF_P5_LIB, VNF_P5_LIB, VNF_P5_CLIENT, VNF_P7_LIB, VNF_P7_CLIENT, MAC; + * VNF_P5_CLIENT=>VNF_P5_LIB [label="nfapi_vnf_config_create", URL="\ref nfapi_vnf_config_create"]; + * VNF_P5_CLIENT=>VNF_P5_LIB [label="nfapi_vnf_start", URL="\ref nfapi_vnf_start"]; + * VNF_P5_LIB note VNF_P5_LIB [label="Listening for PNF connection"]; + * PNF_P5_CLIENT note PNF_P5_CLIENT [label="P9 has provided the address of the VNF"]; + * PNF_P5_CLIENT=>PNF_P5_LIB [label="nfapi_pnf_config_create", URL="\ref nfapi_pnf_config_create"]; + * PNF_P5_CLIENT=>PNF_P5_LIB [label="nfapi_pnf_start", URL="\ref nfapi_pnf_start"]; + * PNF_P5_LIB note PNF_P5_LIB [label="PNF STATE : PNF IDLE"]; + * PNF_P5_LIB->VNF_P5_LIB [label=""]; + * VNF_P5_LIB=>VNF_P5_CLIENT [label="pnf_connection_indication", URL="\ref nfapi_vnf_config::pnf_connection_indication"]; + * + * VNF_P5_LIB<=VNF_P5_CLIENT [label="nfapi_vnf_pnf_param_req", URL="\ref nfapi_vnf_pnf_param_req"]; + * VNF_P5_LIB->PNF_P5_LIB [label="PNF_PARAM.request"]; + * PNF_P5_LIB=>PNF_P5_CLIENT [label="pnf_param_request", URL="\ref nfapi_pnf_config::pnf_param_req"]; + * PNF_P5_LIB<=PNF_P5_CLIENT [label="nfapi_pnf_pnf_param_response", URL="\ref nfapi_pnf_pnf_param_resp"]; + * VNF_P5_LIB<-PNF_P5_LIB [label="PNF_PARAM.response"]; + * VNF_P5_LIB=>VNF_P5_CLIENT [label="pnf_param_response", URL="\ref nfapi_vnf_config::pnf_param_resp"]; + * + * VNF_P5_LIB<=VNF_P5_CLIENT [label="nfapi_vnf_pnf_config_req", URL="\ref nfapi_vnf_pnf_config_req"]; + * VNF_P5_LIB->PNF_P5_LIB [label="PNF_CONFIG.request"]; + * PNF_P5_LIB=>PNF_P5_CLIENT [label="pnf_config_request", URL="\ref nfapi_pnf_config::pnf_config_req"]; + * PNF_P5_LIB<=PNF_P5_CLIENT [label="nfapi_pnf_pnf_config_response", URL="\ref nfapi_pnf_pnf_config_resp"]; + * PNF_P5_LIB note PNF_P5_LIB [label="PNF STATE : PNF CONFIGURED"]; + * VNF_P5_LIB<-PNF_P5_LIB [label="PNF_CONFIG.response"]; + * VNF_P5_LIB=>VNF_P5_CLIENT [label="pnf_config_response", URL="\ref nfapi_vnf_config::pnf_config_resp"]; + * + * VNF_P5_LIB<=VNF_P5_CLIENT [label="nfapi_vnf_pnf_start_req", URL="\ref nfapi_vnf_pnf_start_req"]; + * VNF_P5_LIB->PNF_P5_LIB [label="PNF_START.request"]; + * PNF_P5_LIB=>PNF_P5_CLIENT [label="pnf_start_request", URL="\ref nfapi_pnf_config::pnf_start_req"]; + * PNF_P5_CLIENT=>FAPI [label=""]; + * FAPI note FAPI [label="FAPI STATE : IDLE"]; + * PNF_P5_LIB<=PNF_P5_CLIENT [label="nfapi_pnf_pnf_start_response", URL="\ref nfapi_pnf_pnf_start_resp"]; + * PNF_P5_LIB note PNF_P5_LIB [label="PNF STATE : PNF RUNNING"]; + * VNF_P5_LIB<-PNF_P5_LIB [label="PNF_START.response"]; + * VNF_P5_LIB=>VNF_P5_CLIENT [label="pnf_start_response", URL="\ref nfapi_vnf_config::pnf_param_resp"]; + * + * --- [ label="If vnf p7 instance not already running"]; + * VNF_P5_CLIENT=>VNF_P5_LIB [label="nfapi_vnf_allocate_phy", URL="\ref nfapi_vnf_allocate_phy"]; + * VNF_P5_CLIENT=>VNF_P7_CLIENT [label=""]; + * VNF_P7_CLIENT=>VNF_P7_LIB [label="nfapi_vnf_p7_config_create", URL="\ref nfapi_vnf_p7_config_create"]; + * VNF_P7_CLIENT=>VNF_P7_LIB [label="nfapi_vnf_p7_start", URL="\ref nfapi_vnf_p7_start"]; + * ---; + * + * VNF_P5_LIB<=VNF_P5_CLIENT [label="nfapi_vnf_param_request", URL="\ref nfapi_vnf_param_req"]; + * VNF_P5_LIB->PNF_P5_LIB [label="PARAM.request"]; + * PNF_P5_LIB=>PNF_P5_CLIENT [label="param_request", URL="\ref nfapi_pnf_config::param_req"]; + * PNF_P5_CLIENT=>FAPI [label="fapi_param_request"]; + * PNF_P5_CLIENT<=FAPI [label="fapi_param_response"]; + * PNF_P5_CLIENT=>PNF_P7_CLIENT [label=""]; + * PNF_P7_CLIENT=>PNF_P7_LIB [label="nfapi_pnf_p7_create", URL="\ref nfapi_pnf_p7_config_create"]; + * PNF_P7_CLIENT=>PNF_P7_LIB [label="nfapi_pnf_p7_start", URL="\ref nfapi_pnf_p7_start"]; + * PNF_P5_LIB<=PNF_P5_CLIENT [label="nfapi_pnf_param_response", URL="\ref nfapi_pnf_param_resp"]; + * VNF_P5_LIB<-PNF_P5_LIB [label="PARAM.response"]; + * VNF_P5_LIB=>VNF_P5_CLIENT [label="param_response", URL="\ref nfapi_vnf_config::param_resp"]; + * + * VNF_P5_LIB<=VNF_P5_CLIENT [label="nfapi_vnf_config_request", URL="\ref nfapi_vnf_config_req"]; + * VNF_P5_LIB->PNF_P5_LIB [label="CONFIG.request"]; + * PNF_P5_LIB=>PNF_P5_CLIENT [label="config_request", URL="\ref nfapi_pnf_config::config_req"]; + * PNF_P5_CLIENT=>FAPI [label="fapi_config_request"]; + * FAPI note FAPI [label="FAPI STATE : CONFIGURED"]; + * PNF_P5_CLIENT<=FAPI [label="fapi_config_response"]; + * PNF_P5_LIB<=PNF_P5_CLIENT [label="nfapi_pnf_config_response", URL="\ref nfapi_pnf_param_resp"]; + * VNF_P5_LIB<-PNF_P5_LIB [label="CONFIG.response"]; + * VNF_P5_LIB=>VNF_P5_CLIENT [label="config_response", URL="\ref nfapi_vnf_config::config_resp"]; + * + * VNF_P5_LIB<=VNF_P5_CLIENT [label="nfapi_vnf_start_request", URL="\ref nfapi_vnf_start_req"]; + * VNF_P5_LIB->PNF_P5_LIB [label="START.request"]; + * PNF_P5_LIB=>PNF_P5_CLIENT [label="start_request", URL="\ref nfapi_pnf_config::start_req"]; + * PNF_P5_CLIENT=>FAPI [label="fapi_start_request"]; + * FAPI note FAPI [label="FAPI STATE : RUNNING"]; + * FAPI note FAPI [label="FAPI will start sending subframe indications"]; + * + * --- [ label="For each 'phy' subframe"]; + * FAPI=>PNF_P7_CLIENT [label="fapi_subframe_indication"]; + * PNF_P7_CLIENT=>PNF_P7_LIB [label="nfapi_pnf_p7_subframe_ind", URL="\ref nfapi_pnf_p7_subframe_ind"]; + * ---; + * PNF_P7_CLIENT=>PNF_P5_CLIENT [label=""]; + * + * PNF_P5_LIB<=PNF_P5_CLIENT [label="nfapi_pnf_start_response", URL="\ref nfapi_pnf_start_resp"]; + * VNF_P5_LIB<-PNF_P5_LIB [label="START.response"]; + * VNF_P5_LIB=>VNF_P5_CLIENT [label="start_response", URL="\ref nfapi_vnf_config::start_resp"]; + * VNF_P5_CLIENT=>VNF_P7_CLIENT [label=""]; + * VNF_P7_CLIENT=>VNF_P7_LIB [label="nfapi_vnf_p7_add_pnf", URL="\ref nfapi_vnf_p7_add_pnf"]; + * + * VNF_P7_LIB->PNF_P7_LIB [label="DL_NODE_SYNC"]; + * VNF_P7_LIB<-PNF_P7_LIB [label="UL_NODE_SYNC"]; + * VNF_P7_LIB<-PNF_P7_LIB [label="TIMING_INFO"]; + * VNF_P7_LIB note VNF_P7_LIB [label="When sync is achieved"]; + * + * VNF_P7_LIB=>VNF_P7_CLIENT [label="sync_indication", URL="\ref nfapi_vnf_p7_config::sync_indication"]; + * + * --- [ label="For each 'vnf phy' subframe"]; + * VNF_P7_LIB=>VNF_P7_CLIENT [label="subframe_indication(tti=x)", URL="\ref nfapi_vnf_p7_config::subframe_indication"]; + * VNF_P7_CLIENT=>MAC [label="subframe_indication"]; + * VNF_P7_CLIENT<=MAC [label="dl_config_req"]; + * VNF_P7_CLIENT=>VNF_P7_LIB [label="nfapi_vnf_p7_dl_config_req", URL="\ref nfapi_vnf_p7_dl_config_req"]; + * VNF_P7_LIB->PNF_P7_LIB [label="DL_CONFIG.request"]; + * PNF_P7_LIB note PNF_P7_LIB [label="Store in subframe buffer for tti x"]; + * VNF_P7_CLIENT<=MAC [label="ul_config_req"]; + * VNF_P7_CLIENT=>VNF_P7_LIB [label="nfapi_vnf_p7_ul_config_req", URL="\ref nfapi_vnf_p7_ul_config_req"]; + * VNF_P7_LIB->PNF_P7_LIB [label="UL_CONFIG.request"]; + * PNF_P7_LIB note PNF_P7_LIB [label="Store in subframe buffer for tti x"]; + * VNF_P7_CLIENT<=MAC [label="hi_dci0_req"]; + * VNF_P7_CLIENT=>VNF_P7_LIB [label="nfapi_vnf_p7_hi_dci0_req", URL="\ref nfapi_vnf_p7_hi_dci0_req"]; + * VNF_P7_LIB->PNF_P7_LIB [label="HI_DCI0.request"]; + * PNF_P7_LIB note PNF_P7_LIB [label="Store in subframe buffer for tti x"]; + * VNF_P7_CLIENT<=MAC [label="tx_req"]; + * VNF_P7_CLIENT=>VNF_P7_LIB [label="nfapi_vnf_p7_tx_req", URL="\ref nfapi_vnf_p7_tx_req"]; + * VNF_P7_LIB->PNF_P7_LIB [label="TX.request"]; + * PNF_P7_LIB note PNF_P7_LIB [label="Store in subframe buffer for tti x"]; + * ---; + * + * + * --- [ label="For each 'phy' subframe"]; + * + * FAPI=>PNF_P7_CLIENT [label="harq_indication"]; + * PNF_P7_CLIENT=>PNF_P7_LIB [label="nfapi_pnf_p7_harq_ind", URL="\ref nfapi_pnf_p7_harq_ind"]; + * PNF_P7_LIB->VNF_P7_LIB [label="HARQ.ind"]; + * VNF_P7_LIB=>VNF_P7_CLIENT [label="harq_ind", URL="\ref nfapi_vnf_p7_config::harq_indication"]; + * VNF_P7_CLIENT=>MAC [label="harq_ind"]; + * + * FAPI=>PNF_P7_CLIENT [label="subframe_indication(tti=x)"]; + * PNF_P7_CLIENT=>PNF_P7_LIB [label="nfapi_pnf_p7_subframe_ind", URL="\ref nfapi_pnf_p7_subframe_ind"]; + * PNF_P7_LIB note PNF_P7_LIB [label="Send data from subframe buffer for tti x"]; + * PNF_P7_LIB=>PNF_P7_CLIENT [label="dl_config_req", URL="\ref nfapi_pnf_p7_config::dl_config_req"]; + * PNF_P7_CLIENT=>FAPI [label="dl_config_req"]; + * PNF_P7_LIB=>PNF_P7_CLIENT [label="ul_config_req", URL="\ref nfapi_pnf_p7_config::ul_config_req"]; + * PNF_P7_CLIENT=>FAPI [label="ul_config_req"]; + * PNF_P7_LIB=>PNF_P7_CLIENT [label="hi_dci0_req", URL="\ref nfapi_pnf_p7_config::hi_dci0_req"]; + * PNF_P7_CLIENT=>FAPI [label="hi_dci0_req"]; + * PNF_P7_LIB=>PNF_P7_CLIENT [label="tx_req", URL="\ref nfapi_pnf_p7_config::tx_req"]; + * PNF_P7_CLIENT=>FAPI [label="tx_req"]; + * ---; + * + * \endmsc + * + * \section seq_diag_bca BCA + * + * -# The VNF_P5_CLIENT is created. If it left to the VRAN partner to define how that is done. The client is responsiable to creation of the thread with the correct priorities within the wider system. + * -# The VNF_P5_CLIENT creates and initializes the VNF_P5_LIB (nfapi_vnf_config_create & nfapi_vnf_start) providing the address that it should listen on for incoming SCTP connections. It is expected that this would be provided by some VNF management system. The VNF_P5_CLIENT also provides information on the callbacks that the VNF_P5_LIB will use to inform the VNF_P5_CLIENT of the received messages + * \code + * nfapi_vnf_config_t* vnf_config = nfapi_vnf_config_create(); + * vnf_config->pnf_connection_indication = &pnf_connection_indication; + * vnf_config->pnf_param_resp = &pnf_param_resp; + * nfapi_vnf_start(vnf_config); + * \endcode + * -# It is FFS how the address information of the VNF P5 is passed to the PNF over P9, but assuming that has been done + * -# The PNF_P5_CLIENT is created and then creates the PNF_P5_LIB (nfapi_pnf_init & nfapi_pnf_start) passing the address of the VNF to connect to. The PNF_P5_CLIENT also provides information on the callbacks that the PNF_P5_LIB will use to inform the PNF_P5_CLIENT of the received messages + * \code + * nfapi_pnf_config_t* pnf_config = nfapi_pnf_config_create(); + * pnf_config->pnf_param_req = &pnf_param_req; + * nfapi_pnf_start(pnf_config); + * \endcode + * -# The PNF_P5_LIB attempts to establish connection to the VNF_P5 endpoint + * -# The VNF_P5_LIB receives the STCP connection request and indicates this to the VNF_P5_CLIENT (pnf_connection_indication). The VNF_P5_CLIENT can decide to accept or reject the connection. + * \code + * int pnf_connection_indication(nfapi_vnf_config_t* config, int p5_idx) { + * // send the PNF_PARAM.request + * nfapi_pnf_param_request_t req; + * memset(&req, 0, sizeof(req)); + * req.header.message_id = NFAPI_PNF_PARAM_REQUEST; + * nfapi_vnf_pnf_param_req(config, p5_idx, req); + * return 0; + * } + * \endcode + + * -# The VNF and PNF then proceed to exchange the NFAPI PNF messages (PNF_PARAM, PNF_CONFIG and PNF_START). At each stage the LIB’s invoke callbacks on the CLIENT’s for them to handle message the return the appropriate response. + * -# Finally the VNF will send the PNF_START.req which will invoke the PNF_P5_CLIENT nfapi_pnf_start_request callback. This is the point at which it is expect that the PNF_CLIENT will create the FAPI module. The PNF_P5_CLIENT will need to perform the translation between NFAPI structures and vendor specific FAPI structures for messages sent between the PNF_P5_LIB and the FAPI interface. + * -# The PNF_START.response will sent back to the VNF and at this point the VNF_P5_CLIENT will need to decide which VNF_P7 instance will handle the P7 connection. i.e. it needs to determine the IP address and port number of the P7 VNF instance. + * -# A new VNF_P7_CLIENT & VNF_P7_LIB should be configured and started if necessary. + * -# The VNF_P5 will then send the PARAM.request to the PNF_P5 which will forward it onto the FAPI interface. This PARAM.request includes the VNF_P7 address. The PNF_P7_CLIENT must decide on the PNF P7 address. This information is used to create and initialize the PNF_P7_LIB. The PNF_P7 address is then returned by the PNF_P5 to the VNF_P5 in the PARAM.response. + * -# The VNF_P5 will then exchange with the PNF_P5 the CONFIG.request/response which will be used to configure the PNF FAPI instance. + * -# The VNF_P5 will then decide to start the PNF_P7 by sending the START.request. + * -# The PNF_P5_CLIENT need to send the start request to the FAPI instance. The response which is the start of subframe indications from the FAPI. In receipt of the first subframe indication the PNF_P5_CLIENT will send the START.response to the VNF_P5 via the PNF_P5_LIB + * -# The FAPI subframe indications should be forwarded to the PNF_P7_LIB by the PNF_P7_CLIENT. Until the VNF_P7 instance has sent the subframe configuration messages (dl_config, ul_config, etc) the PNF_P7_LIB will send ‘dummy’ subframe configuration messages. The contents of which are configurable by the PNF_P7_CLIENT. + * -# When the VNF_P5_CLIENT receives the START.response it will need to ‘communicate’ with the VNF_P7_CLIENT to inform it that the PNF_P7 instance has started. The VNF_P7_CLIENT will call the nfapi_vnf_P7_add_pnf function passing the address details of the PNF_P7 instance. + * -# The VNF_P7_LIB will then start the sync procedure to establish sub frame synchronization between the PNF_P7 and VNF_P7 instances. This involves sending the DL_NODE_SYNC and UL_NODE_SYNC to determine network latency and PNF processing latency to be able to request MAC generate sub frames in advance on when they are required by the FAPI interface. + * -# When sync is achieved the VNF_P7_LIB will send the nfapi_sync_indication to the VNF_P7_CLIENT. + * -# The VNF_P7_LIB will then start issuing sub frame indications to the VNF_P7_CLIENT. The logical intent is that they indications are sent every millisecond. However due to the scheduling jitter that may be seen by the VNF these subframe indications may be less than or more than 1ms apart. How this is handled is one of the critical functions of the VNF_P7_LIB and may require specialization or requirements on the VNF environment i.e. CPU pinning. + * -# The VNF_P7_LIB will send the subframe_indication to the VNF_P7_CLIENT for ‘x’ subframe’s inadvance of the current TTI at the PNF. The delta ‘x’ will be determined by the sync procedure and how far in advance the FAPI needs to receive messages before RF transmission. + * -# The VNF_P7_CLIENT is then responsible for communicating to the MAC layer to prepare the dl_config_request, ul_config_request, hi_dci0_request, tx_req in a timely manner and sending them to the VNF_P7_LIB + * -# The VNF_P7_LIB will send them to the VNF_P7_LIB. + * -# The PNF_P7_LIB will store these messages in a subframe buffer or playout buffer in advance of when they are required by FAPI. + * -# The PNF_P7_LIB will monitor to see if these messages arrive too late and if they do trigger a TIMING_INFO response to the VNF_P7_LIB to reassess if the sync is still valid. + * -# As some time in the future the FAPI will send a subframe indication for the TTI that the VNF_P7_LIB had previously requested. + * -# The PNF_P7_LIB will then use the messages in the subframe buffer and send them too the FAPI interface for transmission. The PNF_P7_CLIENT will need to perform the translation between NFAPI structure and vendor specific FAPI structures + * -# This subframe exchange will continue and allow high layer MAC and RRC function to bringup the cell and connect UE’s + + */ diff --git a/nfapi/open-nFAPI/integration_tests/Makefile.am b/nfapi/open-nFAPI/integration_tests/Makefile.am new file mode 100644 index 0000000000..2413590182 --- /dev/null +++ b/nfapi/open-nFAPI/integration_tests/Makefile.am @@ -0,0 +1,29 @@ +# +# Copyright 2017 Cisco Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +#vnf unit test +AM_CPPFLAGS = -I../nfapi/inc -I../nfapi/public_inc -I../common/public_inc -I../vnf/public_inc $(CFLAGS_CUNIT) -Wall -Werror + +export LD_LIBRARY_PATH=/opt/gcc-4.7.3/lib +check_PROGRAMS= nfapi_integration_tests +nfapi_integration_tests_SOURCES = main.cpp ../common/src/debug.c +nfapi_integration_tests_LDADD= -L$(libdir) -lpthread -lrt -lcunit + + + +LOG_DRIVER = $(top_srcdir)/tap-driver.sh +TESTS=nfapi_integration_tests +EXTRA_DIST=$(TESTS) diff --git a/nfapi/open-nFAPI/integration_tests/main.cpp b/nfapi/open-nFAPI/integration_tests/main.cpp new file mode 100644 index 0000000000..83c48afec3 --- /dev/null +++ b/nfapi/open-nFAPI/integration_tests/main.cpp @@ -0,0 +1,269 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CUnit.h" +#include "Basic.h" +#include "Automated.h" + +#include +#include +#include +#include + +int start_vnf_proc(int port) +{ + char port_str[10]; + sprintf(port_str, "%d", port); + + const char *argv[] = {"vnfsim", port_str, "../xml/vnf_A.xml", NULL}; + int pid = fork(); + + if(pid == 0) + { + int result = execv("../vnf_sim/vnfsim", (char* const*)argv); //, env_args); + if(result == -1) + { + printf("Failed to exec vnf process %d\n", errno); + } + exit(0); + } + else + { + return pid; + } +} + +int start_pnf_proc(const char* addr, int port, const char* file) +{ + char port_str[10]; + sprintf(port_str, "%d", port); + + char filename[256]; + sprintf(filename, "../xml/%s", file); + + const char * argv[] = {"pnfsim", addr, port_str, filename, NULL}; + int pid = fork(); + + if(pid == 0) + { + int result = execv("../pnf_sim/pnfsim", (char* const*)argv); //, env_args); + if(result == -1) + { + printf("Failed to exec pnf process %d\n", errno); + } + exit(0); + } + else + { + return pid; + } +} + +int kill_proc(int pid) +{ + kill(pid, SIGKILL); + + int status; + int waitpid_result = waitpid(pid, &status, 0); + + return waitpid_result; +} + + +void test_1() +{ + + int pnf_port = 5655; + const char* pnf_addr = "localhost"; + + printf("**** starting vnf *****\n"); + int vnf_pid = start_vnf_proc(pnf_port); + + printf("**** starting pnf *****\n"); + int pnf1_pid = start_pnf_proc(pnf_addr, pnf_port, "pnf_phy_1_A.xml"); + + + sleep(10); + + printf ("*** Terminating ****\n"); + kill_proc(vnf_pid); + kill_proc(pnf1_pid); +} +void test_1a() +{ + + int pnf_port = 5655; + const char* pnf_addr = "localhost"; + + printf("**** starting vnf *****\n"); + int vnf_pid = start_vnf_proc(pnf_port); + + printf("**** starting pnf *****\n"); + int pnf1_pid = start_pnf_proc(pnf_addr, pnf_port, "pnf_phy_2_A.xml"); + + + sleep(10); + + printf ("*** Terminating ****\n"); + kill_proc(vnf_pid); + kill_proc(pnf1_pid); +} + + +void test_2() +{ + int pnf_port = 5655; + const char* pnf_addr = "127.0.0.1"; + + int vnf_pid = start_vnf_proc(pnf_port); + sleep(2); + + int pnf1_pid = start_pnf_proc(pnf_addr, pnf_port, "pnf_phy_1_A.xml"); + int pnf2_pid = start_pnf_proc(pnf_addr, pnf_port, "pnf_phy_1_A.xml"); + + sleep(2); + + kill_proc(pnf2_pid); + kill_proc(pnf1_pid); + kill_proc(vnf_pid); +} + +void test_32() +{ + int pnf_count = 32; + int pnf_pid[pnf_count]; + + int pnf_port = 5655; + const char* pnf_addr = "127.0.0.1"; + + int vnf_pid = start_vnf_proc(pnf_port); + sleep(2); + + for(int i = 0; i < pnf_count; ++i) + { + pnf_pid[i] = start_pnf_proc(pnf_addr, pnf_port, "pnf_phy_1_A.xml"); + } + + sleep(5); + + printf ("*** Terminating pnfs\n"); + + for(int i = 0; i < pnf_count; ++i) + { + kill_proc(pnf_pid[i]); + } + printf ("*** Terminating vnf\n"); + kill_proc(vnf_pid); +} + + +int init_suite() +{ + return 0; +} + +int clean_suite() +{ + return 0; +} + +int main ( void ) +{ + CU_pSuite pSuite = NULL; + + /* initialize the CUnit test registry */ + if ( CUE_SUCCESS != CU_initialize_registry() ) + return CU_get_error(); + + /* add a suite to the registry */ + pSuite = CU_add_suite( "integration_test_suite", init_suite, clean_suite ); + if ( NULL == pSuite ) + { + CU_cleanup_registry(); + return CU_get_error(); + } + + //(NULL == CU_add_test(pSuite, "vnf_test_start_connect_2", vnf_test_start_connect_2)) + /* add the tests to the suite */ + if ( (NULL == CU_add_test(pSuite, "test_1a", test_1a)) +// (NULL == CU_add_test(pSuite, "test_2", test_2)) || +// (NULL == CU_add_test(pSuite, "test_32", test_32)) + ) + { + CU_cleanup_registry(); + return CU_get_error(); + } + + // Run all tests using the basic interface + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_set_output_filename("vnf_unit_test_results.xml"); + CU_basic_run_tests(); + + CU_pSuite s = CU_get_registry()->pSuite; + int count = 0; + while(s) + { + CU_pTest t = s->pTest; + while(t) + { + count++; + t = t->pNext; + } + s = s->pNext; + } + + printf("%d..%d\n", 1, count); + + + + s = CU_get_registry()->pSuite; + count = 1; + while(s) + { + CU_pTest t = s->pTest; + while(t) + { + int pass = 1; + CU_FailureRecord* failures = CU_get_failure_list(); + while(failures) + { + if(strcmp(failures->pSuite->pName, s->pName) == 0 && + strcmp(failures->pTest->pName, t->pName) == 0) + { + pass = 0; + failures = 0; + } + else + { + failures = failures->pNext; + } + } + + if(pass) + printf("ok %d - %s:%s\n", count, s->pName, t->pName); + else + printf("not ok %d - %s:%s\n", count, s->pName, t->pName); + + count++; + t = t->pNext; + } + s = s->pNext; + } + + CU_cleanup_registry(); + return CU_get_error(); + +} diff --git a/nfapi/open-nFAPI/nfapi/Makefile.am b/nfapi/open-nFAPI/nfapi/Makefile.am new file mode 100644 index 0000000000..853ee9ff80 --- /dev/null +++ b/nfapi/open-nFAPI/nfapi/Makefile.am @@ -0,0 +1,30 @@ +# +# Copyright 2017 Cisco Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +AUTOMAKE_OPTIONS=subdir-objects +AM_CPPFLAGS = -I$(top_srcdir)/nfapi/inc -I$(top_srcdir)/nfapi/public_inc -I$(top_srcdir)/common/public_inc -I$(top_srcdir)/pnf/public_inc $(BOOST_CPPFLAGS) -Wall -Werror -g + +noinst_LIBRARIES = libnfapi.a + +libnfapi_a_SOURCES = src/nfapi.c src/nfapi_p5.c src/nfapi_p7.c src/nfapi_p4.c +libnfapi_a_CFLAGS =$(AM_CFLAGS) + +lib_LTLIBRARIES = libnfapi.la +libnfapi_la_SOURCES = src/nfapi.c src/nfapi_p5.c src/nfapi_p7.c src/nfapi_p4.c + + +LDADD= ../pnf/src/libnfapi_pnf.a ../vnf/src/libnfapi_vnf.a ../common/bin/libnfapi_common.a + diff --git a/nfapi/open-nFAPI/nfapi/inc/nfapi.h b/nfapi/open-nFAPI/nfapi/inc/nfapi.h new file mode 100644 index 0000000000..65ad4dd160 --- /dev/null +++ b/nfapi/open-nFAPI/nfapi/inc/nfapi.h @@ -0,0 +1,91 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef _NFAPI_H_ +#define _NFAPI_H_ + +#if defined(__cplusplus) +extern "C" { +#endif + +// todo : move to public_inc so can be used by vendor extensions + +#define MAX_BAD_TAG 3 + +uint8_t push8(uint8_t in, uint8_t **out, uint8_t *end); +uint8_t pushs8(int8_t in, uint8_t **out, uint8_t *end); +uint8_t push16(uint16_t in, uint8_t **out, uint8_t *end); +uint8_t pushs16(int16_t in, uint8_t **out, uint8_t *end); +uint8_t push32(uint32_t in, uint8_t **out, uint8_t *end); +uint8_t pushs32(int32_t in, uint8_t **out, uint8_t *end); + +uint8_t pull8(uint8_t **in, uint8_t *out, uint8_t *end); +uint8_t pulls8(uint8_t **in, int8_t *out, uint8_t *end); +uint8_t pull16(uint8_t **in, uint16_t *out, uint8_t *end); +uint8_t pulls16(uint8_t **in, int16_t *out, uint8_t *end); +uint8_t pull32(uint8_t **in, uint32_t *out, uint8_t *end); +uint8_t pulls32(uint8_t **in, int32_t *out, uint8_t *end); + + +uint32_t pullarray8(uint8_t **in, uint8_t out[], uint32_t max_len, uint32_t len, uint8_t *end); +uint32_t pullarray16(uint8_t **in, uint16_t out[], uint32_t max_len, uint32_t len, uint8_t *end); +uint32_t pullarrays16(uint8_t **in, int16_t out[], uint32_t max_len, uint32_t len, uint8_t *end); + +uint32_t pusharray8(uint8_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end); +uint32_t pusharray16(uint16_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end); +uint32_t pusharrays16(int16_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end); + +typedef uint8_t (*pack_array_elem_fn)(void* elem, uint8_t **ppWritePackedMsg, uint8_t *end); +uint8_t packarray(void* array, uint16_t elem_size, uint16_t max_count, uint16_t count, uint8_t **ppWritePackedMsg, uint8_t *end, pack_array_elem_fn fn); + +typedef uint8_t (*unpack_array_elem_fn)(void* elem, uint8_t **ppReadPackedMsg, uint8_t *end); +uint8_t unpackarray(uint8_t **ppReadPackedMsg, void* array, uint16_t elem_size, uint16_t max_count, uint16_t count, uint8_t *end, unpack_array_elem_fn fn); + +uint8_t pack_tl(nfapi_tl_t *tl, uint8_t **ppWritePackedMsg, uint8_t *end); +uint8_t unpack_tl(uint8_t **ppReadPackedMsg, nfapi_tl_t *tl, uint8_t *end); + +typedef uint8_t (*pack_tlv_fn)(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end); +uint8_t pack_tlv(uint16_t tag, void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end, pack_tlv_fn fn); + +uint32_t pack_vendor_extension_tlv(nfapi_tl_t* ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config); +int unpack_vendor_extension(nfapi_tl_t* tl, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config, nfapi_tl_t** ve_tlv); + +typedef uint8_t (*unpack_tlv_fn)(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end); +typedef struct +{ + uint16_t tag; + void* tlv; + unpack_tlv_fn unpack_func; +} unpack_tlv_t; + +int unpack_tlv_list(unpack_tlv_t unpack_fns[], uint16_t size, uint8_t **ppReadPackedMsg, uint8_t* packedMsgEnd, nfapi_p4_p5_codec_config_t* config, nfapi_tl_t** ve); + +uint32_t pack_p7_vendor_extension_tlv(nfapi_tl_t *ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config); +typedef uint8_t (*unpack_p7_tlv_fn)(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t*); +typedef struct +{ + uint16_t tag; + void* tlv; + unpack_p7_tlv_fn unpack_func; +} unpack_p7_tlv_t; +int unpack_p7_tlv_list(unpack_p7_tlv_t unpack_fns[], uint16_t size, uint8_t **ppReadPackedMsg, uint8_t* packedMsgEnd, nfapi_p7_codec_config_t* config, nfapi_tl_t** ve); + +#if defined(__cplusplus) +} +#endif + +#endif /* _NFAPI_H_ */ diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h new file mode 100644 index 0000000000..f665d11c89 --- /dev/null +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h @@ -0,0 +1,3855 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef _NFAPI_INTERFACE_H_ +#define _NFAPI_INTERFACE_H_ + +#include "stddef.h" + +// Constants - update based on implementation +#define NFAPI_MAX_PHY_RF_INSTANCES 2 +#define NFAPI_PNF_PARAM_GENERAL_LOCATION_LENGTH 16 +#define NFAPI_PNF_PARAM_GENERAL_OUI_LENGTH 3 +#define NFAPI_MAX_NUM_RF_BANDS 16 + +// The following definition control the size of arrays used in the interface. +// These may be changed if desired. They are used in the encoder to make sure +// that the user has not specified a 'count' larger than the max array, and also +// used by the decoder when decode an array. If the 'count' received is larger +// than the array it is to be stored in the decode fails. +#define NFAPI_MAX_NUM_ANTENNAS 8 +#define NFAPI_MAX_NUM_SUBBANDS 13 +#define NFAPI_MAX_BF_VECTORS 8 +#define NFAPI_MAX_CC 1 +#define NFAPI_MAX_NUM_PHYSICAL_ANTENNAS 8 +#define NFAPI_MAX_RSSI 8 +#define NFAPI_MAX_PSC_LIST 32 +#define NFAPI_MAX_PCI_LIST 32 +#define NFAPI_MAX_CARRIER_LIST 32 +#define NFAPI_MAX_ARFCN_LIST 128 +#define NFAPI_MAX_LTE_CELLS_FOUND 8 +#define NFAPI_MAX_UTRAN_CELLS_FOUND 8 +#define NFAPI_MAX_GSM_CELLS_FOUND 8 +#define NFAPI_MAX_NB_IOT_CELLS_FOUND 8 +#define NFAPI_MAX_SI_PERIODICITY 8 +#define NFAPI_MAX_SI_INDEX 8 +#define NFAPI_MAX_MIB_LENGTH 32 +#define NFAPI_MAX_SIB_LENGTH 256 +#define NFAPI_MAX_SI_LENGTH 256 +#define NFAPI_MAX_OPAQUE_DATA 64 +#define NFAPI_MAX_NUM_SCHEDULED_UES 8 // Used in the TPM structure +#define NFAPI_MAX_PNF_PHY 5 +#define NFAPI_MAX_PNF_PHY_RF_CONFIG 5 +#define NFAPI_MAX_PNF_RF 5 +#define NFAPI_MAX_NMM_FREQUENCY_BANDS 32 +#define NFAPI_MAX_RECEIVED_INTERFERENCE_POWER_RESULTS 100 +#define NFAPI_MAX_UL_DL_CONFIGURATIONS 5 +#define NFAPI_MAX_CSI_RS_RESOURCE_CONFIG 4 +#define NFAPI_MAX_ANTENNA_PORT_COUNT 8 +#define NFAPI_MAX_EPDCCH_PRB 8 +#define NFAPI_MAX_TX_PHYSICAL_ANTENNA_PORTS 8 +#define NFAPI_MAX_NUMBER_ACK_NACK_TDD 8 +#define NFAPI_MAX_RO_DL 8 + +#define NFAPI_HEADER_LENGTH 8 +#define NFAPI_P7_HEADER_LENGTH 16 + +#define NFAPI_VENDOR_EXTENSION_MIN_TAG_VALUE 0xF000 +#define NFAPI_VENDOR_EXTENSION_MAX_TAG_VALUE 0xFFFF + +#define NFAPI_VERSION_3_0_11 0x000 +#define NFAPI_VERSION_3_0_12 0x001 + +// The IANA agreed port definition of the P5 SCTP VNF enpoint +// http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=7701 +#define NFAPI_P5_SCTP_PORT 7701 + +typedef unsigned int uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; +typedef signed int int32_t; +typedef signed short int16_t; +typedef signed char int8_t; + +typedef struct { + uint16_t phy_id; + uint16_t message_id; + uint16_t message_length; + uint16_t spare; +} nfapi_p4_p5_message_header_t; + +typedef struct { + uint16_t phy_id; + uint16_t message_id; + uint16_t message_length; + uint16_t m_segment_sequence; /* This consists of 3 fields - namely, M, Segement & Sequence number*/ + uint32_t checksum; + uint32_t transmit_timestamp; +} nfapi_p7_message_header_t; + +#define NFAPI_PHY_ID_NA 0 + +//#define NFAPI_P7_GET_MORE(_mss) ( ((_mss) & 0x80) >> 7 ) +//#define NFAPI_P7_GET_SEGMENT(_mss) ( ((_mss) & 0x70) >> 4 ) +#define NFAPI_P7_GET_MORE(_mss) ( ((_mss) & 0x8000) >> 15 ) +#define NFAPI_P7_GET_SEGMENT(_mss) ( ((_mss) & 0x7F00) >> 8 ) +#define NFAPI_P7_GET_SEQUENCE(_mss) ( (_mss) & 0x00FF ) +#define NFAPI_P7_SET_MSS(_more, _segm, _sequ) ( (((_more) & 0x1) << 7) | (((_segm) & 0x7) << 4) | ((_sequ) & 0xF) ) + +typedef struct { + uint16_t tag; + uint16_t length; +} nfapi_tl_t; +#define NFAPI_TAG_LENGTH_PACKED_LEN 4 + +// Convenience methods to convert between SFN/SFN formats +#define NFAPI_SFNSF2DEC(_sfnsf) ((((_sfnsf) >> 4) * 10) + ((_sfnsf) & 0xF)) +#define NFAPI_SFNSFDEC2SFNSF(_sfnsf_dec) ((((_sfnsf_dec) / 10) << 4) | (((_sfnsf_dec) - (((_sfnsf_dec) / 10) * 10)) & 0xF)) + +#define NFAPI_SFNSF2SFN(_sfnsf) ((_sfnsf) >> 4) +#define NFAPI_SFNSF2SF(_sfnsf) ((_sfnsf) & 0xF) + +#define NFAPI_MAX_SFNSFDEC 10240 + +typedef nfapi_tl_t* nfapi_vendor_extension_tlv_t; + + +// nFAPI Message IDs +typedef enum { + NFAPI_DL_CONFIG_REQUEST = 0x0080, + NFAPI_UL_CONFIG_REQUEST, + NFAPI_SUBFRAME_INDICATION, + NFAPI_HI_DCI0_REQUEST, + NFAPI_TX_REQUEST, + NFAPI_HARQ_INDICATION, + NFAPI_CRC_INDICATION, + NFAPI_RX_ULSCH_INDICATION, + NFAPI_RACH_INDICATION, + NFAPI_SRS_INDICATION, + NFAPI_RX_SR_INDICATION, + NFAPI_RX_CQI_INDICATION, + NFAPI_LBT_DL_CONFIG_REQUEST, + NFAPI_LBT_DL_INDICATION, + NFAPI_NB_HARQ_INDICATION, + NFAPI_NRACH_INDICATION, + + NFAPI_PNF_PARAM_REQUEST = 0x0100, + NFAPI_PNF_PARAM_RESPONSE, + NFAPI_PNF_CONFIG_REQUEST, + NFAPI_PNF_CONFIG_RESPONSE, + NFAPI_PNF_START_REQUEST, + NFAPI_PNF_START_RESPONSE, + NFAPI_PNF_STOP_REQUEST, + NFAPI_PNF_STOP_RESPONSE, + NFAPI_PARAM_REQUEST, + NFAPI_PARAM_RESPONSE, + NFAPI_CONFIG_REQUEST, + NFAPI_CONFIG_RESPONSE, + NFAPI_START_REQUEST, + NFAPI_START_RESPONSE, + NFAPI_STOP_REQUEST, + NFAPI_STOP_RESPONSE, + NFAPI_MEASUREMENT_REQUEST, + NFAPI_MEASUREMENT_RESPONSE, + + NFAPI_UL_NODE_SYNC = 0x0180, + NFAPI_DL_NODE_SYNC, + NFAPI_TIMING_INFO, + + + NFAPI_RSSI_REQUEST = 0x0200, + NFAPI_RSSI_RESPONSE, + NFAPI_RSSI_INDICATION, + NFAPI_CELL_SEARCH_REQUEST, + NFAPI_CELL_SEARCH_RESPONSE, + NFAPI_CELL_SEARCH_INDICATION, + NFAPI_BROADCAST_DETECT_REQUEST, + NFAPI_BROADCAST_DETECT_RESPONSE, + NFAPI_BROADCAST_DETECT_INDICATION, + NFAPI_SYSTEM_INFORMATION_SCHEDULE_REQUEST, + NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE, + NFAPI_SYSTEM_INFORMATION_SCHEDULE_INDICATION, + NFAPI_SYSTEM_INFORMATION_REQUEST, + NFAPI_SYSTEM_INFORMATION_RESPONSE, + NFAPI_SYSTEM_INFORMATION_INDICATION, + NFAPI_NMM_STOP_REQUEST, + NFAPI_NMM_STOP_RESPONSE, + + NFAPI_VENDOR_EXT_MSG_MIN = 0x0300, + NFAPI_VENDOR_EXT_MSG_MAX = 0x03FF, + + + NFAPI_MAX_MESSAGE_ID, +} nfapi_message_id_e; + +// nFAPI Error Codes +typedef enum { + NFAPI_MSG_OK = 0, + NFAPI_MSG_INVALID_STATE, + NFAPI_MSG_INVALID_CONFIG, + NFAPI_SFN_OUT_OF_SYNC, + NFAPI_MSG_SUBFRAME_ERR, + NFAPI_MSG_BCH_MISSING, + NFAPI_MSG_INVALID_SFN, + NFAPI_MSG_HI_ERR, + NFAPI_MSG_TX_ERR, + + NFAPI_LBT_NO_PDU_IN_DL_REQ, + NFAPI_LBT_NO_VALID_CONFIG_REQ_RECEIVED, + NFAPI_FAPI_E_LBT_SF_SFN_PASSED_END_SF_SFN, + NFAPI_FAPI_E_LBT_OVERLAP, + NFAPI_MSG_BCH_PRESENT, + + NFAPI_NBIOT_UNEXPECTED_REQ, + + // This is special return code that indicates that a response has + // been send via P9 + NFAPI_MSG_P9_RESPONSE = 0xAA +} nfapi_error_code_e; + + +typedef enum { + NFAPI_P4_MSG_OK = 100, + NFAPI_P4_MSG_INVALID_STATE = 101, + NFAPI_P4_MSG_INVALID_CONFIG = 102, + NFAPI_P4_MSG_RAT_NOT_SUPPORTED = 103, + NFAPI_P4_MSG_NMM_STOP_OK = 200, + NFAPI_P4_MSG_NMM_STOP_IGNOREDED = 201, + NFAPI_P4_MSG_NMM_STOP_INVALID_STATE = 202, + NFAPI_P4_MSG_PROCEDURE_COMPLETE = 300, + NFAPI_P4_MSG_PROCEDURE_STOPPED = 301, + NFAPI_P4_MSG_PARTIAL_RESULTS = 302, + NFAPI_P4_MSG_TIMEOUT = 303 +} nfapi_p4_error_code_e; + +// nFAPI enums +typedef enum { + NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE = 0, + NFAPI_DL_CONFIG_BCH_PDU_TYPE, + NFAPI_DL_CONFIG_MCH_PDU_TYPE, + NFAPI_DL_CONFIG_DLSCH_PDU_TYPE, + NFAPI_DL_CONFIG_PCH_PDU_TYPE, + NFAPI_DL_CONFIG_PRS_PDU_TYPE, + NFAPI_DL_CONFIG_CSI_RS_PDU_TYPE, + NFAPI_DL_CONFIG_EPDCCH_DL_PDU_TYPE, + NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE, + NFAPI_DL_CONFIG_NBCH_PDU_TYPE, + NFAPI_DL_CONFIG_NPDCCH_PDU_TYPE, + NFAPI_DL_CONFIG_NDLSCH_PDU_TYPE +} nfapi_dl_config_pdu_type_e; + +typedef enum { + NFAPI_DL_DCI_FORMAT_1 = 0, + NFAPI_DL_DCI_FORMAT_1A, + NFAPI_DL_DCI_FORMAT_1B, + NFAPI_DL_DCI_FORMAT_1C, + NFAPI_DL_DCI_FORMAT_1D, + NFAPI_DL_DCI_FORMAT_2, + NFAPI_DL_DCI_FORMAT_2A, + NFAPI_DL_DCI_FORMAT_2B, + NFAPI_DL_DCI_FORMAT_2C +} nfapi_dl_dci_format_e; + +typedef enum { + NFAPI_UL_DCI_FORMAT_0 = 0, + NFAPI_UL_DCI_FORMAT_3, + NFAPI_UL_DCI_FORMAT_3A, + NFAPI_UL_DCI_FORMAT_4 +} nfapi_ul_dci_format_e; + +typedef enum { + NFAPI_UL_CONFIG_ULSCH_PDU_TYPE = 0, + NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE, + NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE, + NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE, + NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE, + NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE, + NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE, + NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE, + NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE, + NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE, + NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE, + NFAPI_UL_CONFIG_SRS_PDU_TYPE, + NFAPI_UL_CONFIG_HARQ_BUFFER_PDU_TYPE, + NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE, + NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE, + NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE, + NFAPI_UL_CONFIG_NULSCH_PDU_TYPE, + NFAPI_UL_CONFIG_NRACH_PDU_TYPE, +} nfapi_ul_config_pdu_type_e; + +typedef enum { + NFAPI_HI_DCI0_HI_PDU_TYPE = 0, + NFAPI_HI_DCI0_DCI_PDU_TYPE, + NFAPI_HI_DCI0_EPDCCH_DCI_PDU_TYPE, + NFAPI_HI_DCI0_MPDCCH_DCI_PDU_TYPE, + NFAPI_HI_DCI0_NPDCCH_DCI_PDU_TYPE, +} nfapi_hi_dci0_pdu_type_e; + +typedef enum { + NFAPI_HARQ_ACK = 1, + NFAPI_HARQ_NACK, + NFAPI_HARQ_ACK_OR_NACK, + NFAPI_HARQ_DTX, + NFAPI_HARQ_ACK_OR_DTX, + NFAPI_HARQ_NACK_OR_DTX, + NFAPI_HARQ_ACK_OR_NACK_OR_DTX +} nfapi_harq_type_e; + +typedef enum { + NFAPI_CSI_REPORT_TYPE_PERIODIC = 0, + NFAPI_CSI_REPORT_TYPE_APERIODIC +} nfapi_csi_report_type_e; + +typedef enum { + NFAPI_DL_BW_SUPPORTED_6 = 1, + NFAPI_DL_BW_SUPPORTED_15 = 2, + NFAPI_DL_BW_SUPPORTED_25 = 4, + NFAPI_DL_BW_SUPPORTED_50 = 8, + NFAPI_DL_BW_SUPPORTED_75 = 16, + NFAPI_DL_BW_SUPPORTED_100 = 32 +} nfapi_dl_bandwith_supported_e; + +typedef enum { + NFAPI_UL_BW_SUPPORTED_6 = 1, + NFAPI_UL_BW_SUPPORTED_15 = 2, + NFAPI_UL_BW_SUPPORTED_25 = 4, + NFAPI_UL_BW_SUPPORTED_50 = 8, + NFAPI_UL_BW_SUPPORTED_75 = 16, + NFAPI_UL_BW_SUPPORTED_100 = 32 +} nfapi_ul_bandwith_supported_e; + +typedef enum { + NFAPI_3GPP_REL_SUPPORTED_8 = 0, + NFAPI_3GPP_REL_SUPPORTED_9 = 1, + NFAPI_3GPP_REL_SUPPORTED_10 = 2, + NFAPI_3GPP_REL_SUPPORTED_11 = 4, + NFAPI_3GPP_REL_SUPPORTED_12 = 8 +} nfapi_3gpp_release_supported_e; + + +typedef enum { + NFAPI_DUPLEXING_MODE_TDD = 0, + NFAPI_DUPLEXING_MODE_FDD = 1, + NFAPI_DUPLEXING_MODE_HD_FDD = 2, +} nfapi_duplexing_mode_e; + +typedef enum { + NFAPI_CP_NORMAL = 0, + NFAPI_CP_EXTENDED = 1 +} nfapi_cyclic_prefix_type_e; + +typedef enum { + NFAPI_RAT_TYPE_LTE = 0, + NFAPI_RAT_TYPE_UTRAN = 1, + NFAPI_RAT_TYPE_GERAN = 2, + NFAPI_RAT_TYPE_NB_IOT = 3 +} nfapi_rat_type_e; + +typedef enum { + NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_BUNDLING, + NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_MULIPLEXING, + NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_SPECIAL_BUNDLING, + NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_CHANNEL_SELECTION, + NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_3, + NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_4, + NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_5 +} nfapi_harq_indication_tdd_ack_nackformat_e; + + +typedef enum { + NFAPI_LBT_DL_CONFIG_REQUEST_PDSCH_PDU_TYPE = 0, + NFAPI_LBT_DL_CONFIG_REQUEST_DRS_PDU_TYPE +} nfapi_lbt_dl_config_pdu_type_e; + +typedef enum { + NFAPI_LBT_DL_RSP_PDSCH_PDU_TYPE = 0, + NFAPI_LBT_DL_RSP_DRS_PDU_TYPE +} nfapi_lbt_dl_rsp_pdu_type_e; + +typedef struct { + nfapi_tl_t tl; + uint32_t length; + uint8_t value[NFAPI_MAX_OPAQUE_DATA]; +} nfapi_opaqaue_data_t; + +// Utility functions to turn enums into char* +const char* nfapi_error_code_to_str(nfapi_error_code_e value); + + +// P5 Sub Structures +typedef struct { + nfapi_tl_t tl; + uint8_t nfapi_sync_mode; + uint8_t location_mode; + uint16_t location_coordinates_length; + uint8_t location_coordinates[NFAPI_PNF_PARAM_GENERAL_LOCATION_LENGTH]; + uint32_t dl_config_timing; + uint32_t tx_timing; + uint32_t ul_config_timing; + uint32_t hi_dci0_timing; + uint16_t maximum_number_phys; + uint16_t maximum_total_bandwidth; + uint8_t maximum_total_number_dl_layers; + uint8_t maximum_total_number_ul_layers; + uint8_t shared_bands; + uint8_t shared_pa; + int16_t maximum_total_power; + uint8_t oui[NFAPI_PNF_PARAM_GENERAL_OUI_LENGTH]; +} nfapi_pnf_param_general_t; +#define NFAPI_PNF_PARAM_GENERAL_TAG 0x1000 + + + + + +typedef struct { + uint16_t rf_config_index; +} nfapi_rf_config_info_t; + +typedef struct { + uint16_t phy_config_index; + uint16_t number_of_rfs; + nfapi_rf_config_info_t rf_config[NFAPI_MAX_PNF_PHY_RF_CONFIG]; + uint16_t number_of_rf_exclusions; + nfapi_rf_config_info_t excluded_rf_config[NFAPI_MAX_PNF_PHY_RF_CONFIG]; + uint16_t downlink_channel_bandwidth_supported; + uint16_t uplink_channel_bandwidth_supported; + uint8_t number_of_dl_layers_supported; + uint8_t number_of_ul_layers_supported; + uint16_t maximum_3gpp_release_supported; + uint8_t nmm_modes_supported; +} nfapi_pnf_phy_info_t; + + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_phys; + nfapi_pnf_phy_info_t phy[NFAPI_MAX_PNF_PHY]; +} nfapi_pnf_phy_t; +#define NFAPI_PNF_PHY_TAG 0x1001 + +typedef struct { + uint16_t phy_config_index; + uint16_t transmission_mode_7_supported; + uint16_t transmission_mode_8_supported; + uint16_t two_antenna_ports_for_pucch; + uint16_t transmission_mode_9_supported; + uint16_t simultaneous_pucch_pusch; + uint16_t four_layer_tx_with_tm3_and_tm4; +} nfapi_pnf_phy_rel10_info_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_phys; + nfapi_pnf_phy_rel10_info_t phy[NFAPI_MAX_PNF_PHY]; +} nfapi_pnf_phy_rel10_t; +#define NFAPI_PNF_PHY_REL10_TAG 0x100A + +typedef struct { + uint16_t phy_config_index; + uint16_t edpcch_supported; + uint16_t multi_ack_csi_reporting; + uint16_t pucch_tx_diversity; + uint16_t ul_comp_supported; + uint16_t transmission_mode_5_supported; +} nfapi_pnf_phy_rel11_info_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_phys; + nfapi_pnf_phy_rel11_info_t phy[NFAPI_MAX_PNF_PHY]; +} nfapi_pnf_phy_rel11_t; +#define NFAPI_PNF_PHY_REL11_TAG 0x100B + + +typedef struct { + uint16_t phy_config_index; + uint16_t csi_subframe_set; + uint16_t enhanced_4tx_codebook; + uint16_t drs_supported; + uint16_t ul_64qam_supported; + uint16_t transmission_mode_10_supported; + uint16_t alternative_bts_indices; +} nfapi_pnf_phy_rel12_info_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_phys; + nfapi_pnf_phy_rel12_info_t phy[NFAPI_MAX_PNF_PHY]; +} nfapi_pnf_phy_rel12_t; +#define NFAPI_PNF_PHY_REL12_TAG 0x100C + +typedef struct { + uint16_t phy_config_index; + uint16_t pucch_format4_supported; + uint16_t pucch_format5_supported; + uint16_t more_than_5_ca_support; + uint16_t laa_supported; + uint16_t laa_ending_in_dwpts_supported; + uint16_t laa_starting_in_second_slot_supported; + uint16_t beamforming_supported; + uint16_t csi_rs_enhancement_supported; + uint16_t drms_enhancement_supported; + uint16_t srs_enhancement_supported; +} nfapi_pnf_phy_rel13_info_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_phys; + nfapi_pnf_phy_rel13_info_t phy[NFAPI_MAX_PNF_PHY]; +} nfapi_pnf_phy_rel13_t; +#define NFAPI_PNF_PHY_REL13_TAG 0x100D + +typedef struct { + uint16_t phy_config_index; + uint16_t number_of_rfs; + nfapi_rf_config_info_t rf_config[NFAPI_MAX_PNF_PHY_RF_CONFIG]; + uint16_t number_of_rf_exclusions; + nfapi_rf_config_info_t excluded_rf_config[NFAPI_MAX_PNF_PHY_RF_CONFIG]; + uint8_t number_of_dl_layers_supported; + uint8_t number_of_ul_layers_supported; + uint16_t maximum_3gpp_release_supported; + uint8_t nmm_modes_supported; +} nfapi_pnf_phy_rel13_nb_iot_info_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_phys; + nfapi_pnf_phy_rel13_nb_iot_info_t phy[NFAPI_MAX_PNF_PHY]; +} nfapi_pnf_phy_rel13_nb_iot_t; +#define NFAPI_PNF_PHY_REL13_NB_IOT_TAG 0x100E + + + +typedef struct { + uint16_t rf_config_index; + uint16_t band; + int16_t maximum_transmit_power; + int16_t minimum_transmit_power; + uint8_t number_of_antennas_suppported; + uint32_t minimum_downlink_frequency; + uint32_t maximum_downlink_frequency; + uint32_t minimum_uplink_frequency; + uint32_t maximum_uplink_frequency; +} nfapi_pnf_rf_info_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_rfs; + nfapi_pnf_rf_info_t rf[NFAPI_MAX_PNF_RF]; +} nfapi_pnf_rf_t; +#define NFAPI_PNF_RF_TAG 0x1002 + +typedef struct { + uint16_t phy_id; + uint16_t phy_config_index; + uint16_t rf_config_index; +} nfapi_phy_rf_config_info_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t number_phy_rf_config_info; + nfapi_phy_rf_config_info_t phy_rf_config[NFAPI_MAX_PHY_RF_INSTANCES]; +} nfapi_pnf_phy_rf_config_t; +#define NFAPI_PNF_PHY_RF_TAG 0x1003 + +// Generic strucutre for single tlv value. +typedef struct { + nfapi_tl_t tl; + uint16_t value; +} nfapi_uint16_tlv_t; + +typedef struct { + nfapi_tl_t tl; + int16_t value; +} nfapi_int16_tlv_t; + +typedef struct { + nfapi_tl_t tl; + uint8_t value; +} nfapi_uint8_tlv_t; + +typedef struct { + nfapi_uint16_tlv_t phy_state; +} nfapi_l1_status; + +#define NFAPI_L1_STATUS_PHY_STATE_TAG 0x00FA + +typedef struct { + nfapi_uint16_tlv_t dl_bandwidth_support; + nfapi_uint16_tlv_t ul_bandwidth_support; + nfapi_uint16_tlv_t dl_modulation_support; + nfapi_uint16_tlv_t ul_modulation_support; + nfapi_uint16_tlv_t phy_antenna_capability; + nfapi_uint16_tlv_t release_capability; + nfapi_uint16_tlv_t mbsfn_capability; +} nfapi_phy_capabilities_t; + +#define NFAPI_PHY_CAPABILITIES_DL_BANDWIDTH_SUPPORT_TAG 0x00C8 +#define NFAPI_PHY_CAPABILITIES_UL_BANDWIDTH_SUPPORT_TAG 0x00C9 +#define NFAPI_PHY_CAPABILITIES_DL_MODULATION_SUPPORT_TAG 0x00CA +#define NFAPI_PHY_CAPABILITIES_UL_MODULATION_SUPPORT_TAG 0x00CB +#define NFAPI_PHY_CAPABILITIES_PHY_ANTENNA_CAPABILITY_TAG 0x00CC +#define NFAPI_PHY_CAPABILITIES_RELEASE_CAPABILITY_TAG 0x00CD +#define NFAPI_PHY_CAPABILITIES_MBSFN_CAPABILITY_TAG 0x00CE + + +typedef struct { + nfapi_uint16_tlv_t data_report_mode; + nfapi_uint16_tlv_t sfnsf; +} nfapi_l23_config_t; + + +#define NFAPI_L23_CONFIG_DATA_REPORT_MODE_TAG 0x00F0 +#define NFAPI_L23_CONFIG_SFNSF_TAG 0x00F1 + +typedef struct { + nfapi_uint16_tlv_t duplex_mode; + nfapi_uint16_tlv_t pcfich_power_offset; + nfapi_uint16_tlv_t pb; + nfapi_uint16_tlv_t dl_cyclic_prefix_type; + nfapi_uint16_tlv_t ul_cyclic_prefix_type; +} nfapi_subframe_config_t; + +#define NFAPI_SUBFRAME_CONFIG_DUPLEX_MODE_TAG 0x0001 +#define NFAPI_SUBFRAME_CONFIG_PCFICH_POWER_OFFSET_TAG 0x0002 +#define NFAPI_SUBFRAME_CONFIG_PB_TAG 0x0003 +#define NFAPI_SUBFRAME_CONFIG_DL_CYCLIC_PREFIX_TYPE_TAG 0x0004 +#define NFAPI_SUBFRAME_CONFIG_UL_CYCLIC_PREFIX_TYPE_TAG 0x0005 + +typedef struct { + nfapi_uint16_tlv_t dl_channel_bandwidth; + nfapi_uint16_tlv_t ul_channel_bandwidth; + nfapi_uint16_tlv_t reference_signal_power; + nfapi_uint16_tlv_t tx_antenna_ports; + nfapi_uint16_tlv_t rx_antenna_ports; +} nfapi_rf_config_t; + +#define NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG 0x000A +#define NFAPI_RF_CONFIG_UL_CHANNEL_BANDWIDTH_TAG 0x000B +#define NFAPI_RF_CONFIG_REFERENCE_SIGNAL_POWER_TAG 0x000C +#define NFAPI_RF_CONFIG_TX_ANTENNA_PORTS_TAG 0x000D +#define NFAPI_RF_CONFIG_RX_ANTENNA_PORTS_TAG 0x000E + +typedef struct { + nfapi_uint16_tlv_t phich_resource; + nfapi_uint16_tlv_t phich_duration; + nfapi_uint16_tlv_t phich_power_offset; +} nfapi_phich_config_t; + +#define NFAPI_PHICH_CONFIG_PHICH_RESOURCE_TAG 0x0014 +#define NFAPI_PHICH_CONFIG_PHICH_DURATION_TAG 0x0015 +#define NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG 0x0016 + +typedef struct { + nfapi_uint16_tlv_t primary_synchronization_signal_epre_eprers; + nfapi_uint16_tlv_t secondary_synchronization_signal_epre_eprers; + nfapi_uint16_tlv_t physical_cell_id; +} nfapi_sch_config_t; + +#define NFAPI_SCH_CONFIG_PRIMARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG 0x001E +#define NFAPI_SCH_CONFIG_SECONDARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG 0x001F +#define NFAPI_SCH_CONFIG_PHYSICAL_CELL_ID_TAG 0x0020 + +typedef struct { + nfapi_uint16_tlv_t configuration_index; + nfapi_uint16_tlv_t root_sequence_index; + nfapi_uint16_tlv_t zero_correlation_zone_configuration; + nfapi_uint16_tlv_t high_speed_flag; + nfapi_uint16_tlv_t frequency_offset; +} nfapi_prach_config_t; + +#define NFAPI_PRACH_CONFIG_CONFIGURATION_INDEX_TAG 0x0028 +#define NFAPI_PRACH_CONFIG_ROOT_SEQUENCE_INDEX_TAG 0x0029 +#define NFAPI_PRACH_CONFIG_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG 0x002A +#define NFAPI_PRACH_CONFIG_HIGH_SPEED_FLAG_TAG 0x002B +#define NFAPI_PRACH_CONFIG_FREQUENCY_OFFSET_TAG 0x002C + +typedef struct { + nfapi_uint16_tlv_t hopping_mode; + nfapi_uint16_tlv_t hopping_offset; + nfapi_uint16_tlv_t number_of_subbands; +} nfapi_pusch_config_t; + +#define NFAPI_PUSCH_CONFIG_HOPPING_MODE_TAG 0x0032 +#define NFAPI_PUSCH_CONFIG_HOPPING_OFFSET_TAG 0x0033 +#define NFAPI_PUSCH_CONFIG_NUMBER_OF_SUBBANDS_TAG 0x0034 + +typedef struct { + nfapi_uint16_tlv_t delta_pucch_shift; + nfapi_uint16_tlv_t n_cqi_rb; + nfapi_uint16_tlv_t n_an_cs; + nfapi_uint16_tlv_t n1_pucch_an; +} nfapi_pucch_config_t; + +#define NFAPI_PUCCH_CONFIG_DELTA_PUCCH_SHIFT_TAG 0x003C +#define NFAPI_PUCCH_CONFIG_N_CQI_RB_TAG 0x003D +#define NFAPI_PUCCH_CONFIG_N_AN_CS_TAG 0x003E +#define NFAPI_PUCCH_CONFIG_N1_PUCCH_AN_TAG 0x003F + +typedef struct { + nfapi_uint16_tlv_t bandwidth_configuration; + nfapi_uint16_tlv_t max_up_pts; + nfapi_uint16_tlv_t srs_subframe_configuration; + nfapi_uint16_tlv_t srs_acknack_srs_simultaneous_transmission; +} nfapi_srs_config_t; + +#define NFAPI_SRS_CONFIG_BANDWIDTH_CONFIGURATION_TAG 0x0046 +#define NFAPI_SRS_CONFIG_MAX_UP_PTS_TAG 0x0047 +#define NFAPI_SRS_CONFIG_SRS_SUBFRAME_CONFIGURATION_TAG 0x0048 +#define NFAPI_SRS_CONFIG_SRS_ACKNACK_SRS_SIMULTANEOUS_TRANSMISSION_TAG 0x0049 + +typedef struct { + nfapi_uint16_tlv_t uplink_rs_hopping; + nfapi_uint16_tlv_t group_assignment; + nfapi_uint16_tlv_t cyclic_shift_1_for_drms; +} nfapi_uplink_reference_signal_config_t; + +#define NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_UPLINK_RS_HOPPING_TAG 0x0050 +#define NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_GROUP_ASSIGNMENT_TAG 0x0051 +#define NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_CYCLIC_SHIFT_1_FOR_DRMS_TAG 0x0052 + + +typedef struct { + nfapi_uint16_tlv_t ed_threshold_lbt_pdsch; + nfapi_uint16_tlv_t ed_threshold_lbt_drs; + nfapi_uint16_tlv_t pd_threshold; + nfapi_uint16_tlv_t multi_carrier_type; + nfapi_uint16_tlv_t multi_carrier_tx; + nfapi_uint16_tlv_t multi_carrier_freeze; + nfapi_uint16_tlv_t tx_antenna_ports_drs; + nfapi_uint16_tlv_t tx_power_drs; +} nfapi_laa_config_t; + +#define NFAPI_LAA_CONFIG_ED_THRESHOLD_FOR_LBT_FOR_PDSCH_TAG 0x0064 +#define NFAPI_LAA_CONFIG_ED_THRESHOLD_FOR_LBT_FOR_DRS_TAG 0x0065 +#define NFAPI_LAA_CONFIG_PD_THRESHOLD_TAG 0x0066 +#define NFAPI_LAA_CONFIG_MULTI_CARRIER_TYPE_TAG 0x0067 +#define NFAPI_LAA_CONFIG_MULTI_CARRIER_TX_TAG 0x0068 +#define NFAPI_LAA_CONFIG_MULTI_CARRIER_FREEZE_TAG 0x0069 +#define NFAPI_LAA_CONFIG_TX_ANTENNA_PORTS_FOR_DRS_TAG 0x006A +#define NFAPI_LAA_CONFIG_TRANSMISSION_POWER_FOR_DRS_TAG 0x006B + +typedef struct { + + nfapi_uint16_tlv_t pbch_repetitions_enable_r13; + nfapi_uint16_tlv_t prach_catm_root_sequence_index; + nfapi_uint16_tlv_t prach_catm_zero_correlation_zone_configuration; + nfapi_uint16_tlv_t prach_catm_high_speed_flag; + nfapi_uint16_tlv_t prach_ce_level_0_enable; + nfapi_uint16_tlv_t prach_ce_level_0_configuration_index; + nfapi_uint16_tlv_t prach_ce_level_0_frequency_offset; + nfapi_uint16_tlv_t prach_ce_level_0_number_of_repetitions_per_attempt; + nfapi_uint16_tlv_t prach_ce_level_0_starting_subframe_periodicity; + nfapi_uint16_tlv_t prach_ce_level_0_hopping_enable; + nfapi_uint16_tlv_t prach_ce_level_0_hopping_offset; + nfapi_uint16_tlv_t prach_ce_level_1_enable; + nfapi_uint16_tlv_t prach_ce_level_1_configuration_index; + nfapi_uint16_tlv_t prach_ce_level_1_frequency_offset; + nfapi_uint16_tlv_t prach_ce_level_1_number_of_repetitions_per_attempt; + nfapi_uint16_tlv_t prach_ce_level_1_starting_subframe_periodicity; + nfapi_uint16_tlv_t prach_ce_level_1_hopping_enable; + nfapi_uint16_tlv_t prach_ce_level_1_hopping_offset; + nfapi_uint16_tlv_t prach_ce_level_2_enable; + nfapi_uint16_tlv_t prach_ce_level_2_configuration_index; + nfapi_uint16_tlv_t prach_ce_level_2_frequency_offset; + nfapi_uint16_tlv_t prach_ce_level_2_number_of_repetitions_per_attempt; + nfapi_uint16_tlv_t prach_ce_level_2_starting_subframe_periodicity; + nfapi_uint16_tlv_t prach_ce_level_2_hopping_enable; + nfapi_uint16_tlv_t prach_ce_level_2_hopping_offset; + nfapi_uint16_tlv_t prach_ce_level_3_enable; + nfapi_uint16_tlv_t prach_ce_level_3_configuration_index; + nfapi_uint16_tlv_t prach_ce_level_3_frequency_offset; + nfapi_uint16_tlv_t prach_ce_level_3_number_of_repetitions_per_attempt; + nfapi_uint16_tlv_t prach_ce_level_3_starting_subframe_periodicity; + nfapi_uint16_tlv_t prach_ce_level_3_hopping_enable; + nfapi_uint16_tlv_t prach_ce_level_3_hopping_offset; + nfapi_uint16_tlv_t pucch_interval_ulhoppingconfigcommonmodea; + nfapi_uint16_tlv_t pucch_interval_ulhoppingconfigcommonmodeb; +} nfapi_emtc_config_t; + +#define NFAPI_EMTC_CONFIG_PBCH_REPETITIONS_ENABLE_R13_TAG 0x0078 +#define NFAPI_EMTC_CONFIG_PRACH_CATM_ROOT_SEQUENCE_INDEX_TAG 0x0079 +#define NFAPI_EMTC_CONFIG_PRACH_CATM_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG 0x007A +#define NFAPI_EMTC_CONFIG_PRACH_CATM_HIGH_SPEED_FLAG 0x007B +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_ENABLE_TAG 0x007C +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_CONFIGURATION_INDEX_TAG 0x007D +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_FREQUENCY_OFFSET_TAG 0x007E +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x007F +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_STARTING_SUBFRAME_PERIODICITY_TAG 0x0080 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_ENABLE_TAG 0x0081 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_OFFSET_TAG 0x0082 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_ENABLE_TAG 0x0083 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_CONFIGURATION_INDEX_TAG 0x0084 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_FREQUENCY_OFFSET_TAG 0x0085 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x0086 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_STARTING_SUBFRAME_PERIODICITY_TAG 0x0087 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_ENABLE_TAG 0x0088 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_OFFSET_TAG 0x0089 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_ENABLE_TAG 0x008A +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_CONFIGURATION_INDEX_TAG 0x008B +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_FREQUENCY_OFFSET_TAG 0x008C +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x008D +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_STARTING_SUBFRAME_PERIODICITY_TAG 0x008E +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_ENABLE_TAG 0x008F +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_OFFSET_TAG 0x0090 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_ENABLE_TAG 0x0091 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_CONFIGURATION_INDEX_TAG 0x0092 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_FREQUENCY_OFFSET_TAG 0x0093 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x0094 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_STARTING_SUBFRAME_PERIODICITY_TAG 0x0095 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_ENABLE_TAG 0x0096 +#define NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_OFFSET_TAG 0x0097 +#define NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEA_TAG 0x0098 +#define NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEB_TAG 0x0099 + +typedef struct { + nfapi_uint16_tlv_t operating_mode; + nfapi_uint16_tlv_t anchor; + nfapi_uint16_tlv_t prb_index; + nfapi_uint16_tlv_t control_region_size; + nfapi_uint16_tlv_t assumed_crs_aps; + nfapi_uint16_tlv_t nprach_config_0_enabled; + nfapi_uint16_tlv_t nprach_config_0_sf_periodicity; + nfapi_uint16_tlv_t nprach_config_0_start_time; + nfapi_uint16_tlv_t nprach_config_0_subcarrier_offset; + nfapi_uint16_tlv_t nprach_config_0_number_of_subcarriers; + nfapi_uint16_tlv_t nprach_config_0_cp_length; + nfapi_uint16_tlv_t nprach_config_0_number_of_repetitions_per_attempt; + nfapi_uint16_tlv_t nprach_config_1_enabled; + nfapi_uint16_tlv_t nprach_config_1_sf_periodicity; + nfapi_uint16_tlv_t nprach_config_1_start_time; + nfapi_uint16_tlv_t nprach_config_1_subcarrier_offset; + nfapi_uint16_tlv_t nprach_config_1_number_of_subcarriers; + nfapi_uint16_tlv_t nprach_config_1_cp_length; + nfapi_uint16_tlv_t nprach_config_1_number_of_repetitions_per_attempt; + nfapi_uint16_tlv_t nprach_config_2_enabled; + nfapi_uint16_tlv_t nprach_config_2_sf_periodicity; + nfapi_uint16_tlv_t nprach_config_2_start_time; + nfapi_uint16_tlv_t nprach_config_2_subcarrier_offset; + nfapi_uint16_tlv_t nprach_config_2_number_of_subcarriers; + nfapi_uint16_tlv_t nprach_config_2_cp_length; + nfapi_uint16_tlv_t nprach_config_2_number_of_repetitions_per_attempt; + nfapi_uint16_tlv_t three_tone_base_sequence; + nfapi_uint16_tlv_t six_tone_base_sequence; + nfapi_uint16_tlv_t twelve_tone_base_sequence; + nfapi_uint16_tlv_t three_tone_cyclic_shift; + nfapi_uint16_tlv_t six_tone_cyclic_shift; + nfapi_uint16_tlv_t dl_gap_config_enable; + nfapi_uint16_tlv_t dl_gap_threshold; + nfapi_uint16_tlv_t dl_gap_periodicity; + nfapi_uint16_tlv_t dl_gap_duration_coefficient; +} nfapi_nb_iot_config_t; + +#define NFAPI_NB_IOT_CONFIG_OPERATING_MODE_TAG 0x00A5 +#define NFAPI_NB_IOT_CONFIG_ANCHOR_TAG 0x00A6 +#define NFAPI_NB_IOT_CONFIG_PRB_INDEX_TAG 0x00A7 +#define NFAPI_NB_IOT_CONFIG_CONTROL_REGION_SIZE_TAG 0x00A8 +#define NFAPI_NB_IOT_CONFIG_ASSUMED_CRS_APS_TAG 0x00A9 +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_ENABLED_TAG 0x00AA +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_SF_PERIODICITY_TAG 0x00AB +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_START_TIME_TAG 0x00AC +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_SUBCARRIER_OFFSET_TAG 0x00AD +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_NUMBER_OF_SUBCARRIERS_TAG 0x00AE +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_CP_LENGTH_TAG 0x00AF +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x00B0 +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_ENABLED_TAG 0x00B1 +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_SF_PERIODICITY_TAG 0x00B2 +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_START_TIME_TAG 0x00B3 +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_SUBCARRIER_OFFSET_TAG 0x00B4 +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_NUMBER_OF_SUBCARRIERS_TAG 0x00B5 +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_CP_LENGTH_TAG 0x00B6 +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x00B7 +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_ENABLED_TAG 0x00B8 +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_SF_PERIODICITY_TAG 0x00B9 +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_START_TIME_TAG 0x00BA +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_SUBCARRIER_OFFSET_TAG 0x00BB +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_NUMBER_OF_SUBCARRIERS_TAG 0x00BC +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_CP_LENGTH_TAG 0x00BD +#define NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x00BE +#define NFAPI_NB_IOT_CONFIG_THREE_TONE_BASE_SEQUENCE_TAG 0x00BF +#define NFAPI_NB_IOT_CONFIG_SIX_TONE_BASE_SEQUENCE_TAG 0x00C0 +#define NFAPI_NB_IOT_CONFIG_TWELVE_TONE_BASE_SEQUENCE_TAG 0x00C1 +#define NFAPI_NB_IOT_CONFIG_THREE_TONE_CYCLIC_SHIFT_TAG 0x00C2 +#define NFAPI_NB_IOT_CONFIG_SIX_TONE_CYCLIC_SHIFT_TAG 0x00C3 +#define NFAPI_NB_IOT_CONFIG_DL_GAP_CONFIG_ENABLE_TAG 0x00C4 +#define NFAPI_NB_IOT_CONFIG_DL_GAP_THRESHOLD_TAG 0x00C5 +#define NFAPI_NB_IOT_CONFIG_DL_GAP_PERIODICITY_TAG 0x00C6 +#define NFAPI_NB_IOT_CONFIG_DL_GAP_DURATION_COEFFICIENT_TAG 0x00C7 + +typedef struct { + nfapi_uint16_tlv_t laa_support; + nfapi_uint16_tlv_t pd_sensing_lbt_support; + nfapi_uint16_tlv_t multi_carrier_lbt_support; + nfapi_uint16_tlv_t partial_sf_support; +} nfapi_laa_capability_t; + +#define NFAPI_LAA_CAPABILITY_LAA_SUPPORT_TAG 0x00D1 +#define NFAPI_LAA_CAPABILITY_PD_SENSING_LBT_SUPPORT_TAG 0x00D2 +#define NFAPI_LAA_CAPABILITY_MULTI_CARRIER_LBT_SUPPORT_TAG 0x00D3 +#define NFAPI_LAA_CAPABILITY_PARTIAL_SF_SUPPORT_TAG 0x00D4 + +typedef struct { + nfapi_uint16_tlv_t nb_iot_support; + nfapi_uint16_tlv_t nb_iot_operating_mode_capability; +} nfapi_nb_iot_capability_t; + +#define NFAPI_LAA_CAPABILITY_NB_IOT_SUPPORT_TAG 0x00D5 +#define NFAPI_LAA_CAPABILITY_NB_IOT_OPERATING_MODE_CAPABILITY_TAG 0x00D6 + +typedef struct { + nfapi_uint16_tlv_t subframe_assignment; + nfapi_uint16_tlv_t special_subframe_patterns; +} nfapi_tdd_frame_structure_t; + +#define NFAPI_TDD_FRAME_STRUCTURE_SUBFRAME_ASSIGNMENT_TAG 0x005A +#define NFAPI_TDD_FRAME_STRUCTURE_SPECIAL_SUBFRAME_PATTERNS_TAG 0x005B + +typedef struct { + nfapi_tl_t tl; + uint16_t number_rf_bands; + uint16_t rf_band[NFAPI_MAX_NUM_RF_BANDS]; +} nfapi_rf_bands_t; +#define NFAPI_PHY_RF_BANDS_TAG 0x0114 + +#define NFAPI_IPV4_ADDRESS_LENGTH 4 +#define NFAPI_IPV6_ADDRESS_LENGTH 16 + +// Convience enum to allow the ip addres type to be distinguished +typedef enum { + NFAPI_IP_ADDRESS_IPV4 = 0, + NFAPI_IP_ADDRESS_IPV6 +} nfapi_ip_address_type_e; + +// The type could be infered from the length, but it is clearer in +// code to have a type variable set +typedef struct { + nfapi_tl_t tl; + uint8_t type; + union { + uint8_t ipv4_address[NFAPI_IPV4_ADDRESS_LENGTH]; + uint8_t ipv6_address[NFAPI_IPV6_ADDRESS_LENGTH]; + } u; +} nfapi_ip_address_t; + +typedef struct { + nfapi_tl_t tl; + uint8_t address[NFAPI_IPV4_ADDRESS_LENGTH]; +} nfapi_ipv4_address_t; + +typedef struct { + nfapi_tl_t tl; + uint8_t address[NFAPI_IPV6_ADDRESS_LENGTH]; +} nfapi_ipv6_address_t; + + + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_rf_bands; + uint16_t bands[NFAPI_MAX_NMM_FREQUENCY_BANDS]; +} nfapi_nmm_frequency_bands_t; + +//These TLVs are used exclusively by nFAPI +typedef struct +{ + // These TLVs are used to setup the transport connection between VNF and PNF + nfapi_ipv4_address_t p7_vnf_address_ipv4; + nfapi_ipv6_address_t p7_vnf_address_ipv6; + nfapi_uint16_tlv_t p7_vnf_port; + + nfapi_ipv4_address_t p7_pnf_address_ipv4; + nfapi_ipv6_address_t p7_pnf_address_ipv6; + nfapi_uint16_tlv_t p7_pnf_port; + + // These TLVs are used to setup the transport connection between VNF and PNF + nfapi_uint8_tlv_t dl_ue_per_sf; + nfapi_uint8_tlv_t ul_ue_per_sf; + + // These TLVs are used by PNF to report its RF capabilities to the VNF software + nfapi_rf_bands_t rf_bands; + + // These TLVs are used by the VNF to configure the synchronization with the PNF. + nfapi_uint8_tlv_t timing_window; + nfapi_uint8_tlv_t timing_info_mode; + nfapi_uint8_tlv_t timing_info_period; + + // These TLVs are used by the VNF to configure the RF in the PNF + nfapi_uint16_tlv_t max_transmit_power; + nfapi_uint16_tlv_t earfcn; + + nfapi_nmm_frequency_bands_t nmm_gsm_frequency_bands; + nfapi_nmm_frequency_bands_t nmm_umts_frequency_bands; + nfapi_nmm_frequency_bands_t nmm_lte_frequency_bands; + nfapi_uint8_tlv_t nmm_uplink_rssi_supported; + +} nfapi_nfapi_t; + +#define NFAPI_NFAPI_P7_VNF_ADDRESS_IPV4_TAG 0x0100 +#define NFAPI_NFAPI_P7_VNF_ADDRESS_IPV6_TAG 0x0101 +#define NFAPI_NFAPI_P7_VNF_PORT_TAG 0x0102 +#define NFAPI_NFAPI_P7_PNF_ADDRESS_IPV4_TAG 0x0103 +#define NFAPI_NFAPI_P7_PNF_ADDRESS_IPV6_TAG 0x0104 +#define NFAPI_NFAPI_P7_PNF_PORT_TAG 0x0105 + +#define NFAPI_NFAPI_DOWNLINK_UES_PER_SUBFRAME_TAG 0x010A +#define NFAPI_NFAPI_UPLINK_UES_PER_SUBFRAME_TAG 0x010B +#define NFAPI_NFAPI_RF_BANDS_TAG 0x0114 +#define NFAPI_NFAPI_TIMING_WINDOW_TAG 0x011E +#define NFAPI_NFAPI_TIMING_INFO_MODE_TAG 0x011F +#define NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG 0x0120 +#define NFAPI_NFAPI_MAXIMUM_TRANSMIT_POWER_TAG 0x0128 +#define NFAPI_NFAPI_EARFCN_TAG 0x0129 +#define NFAPI_NFAPI_NMM_GSM_FREQUENCY_BANDS_TAG 0x0130 +#define NFAPI_NFAPI_NMM_UMTS_FREQUENCY_BANDS_TAG 0x0131 +#define NFAPI_NFAPI_NMM_LTE_FREQUENCY_BANDS_TAG 0x0132 +#define NFAPI_NFAPI_NMM_UPLINK_RSSI_SUPPORTED_TAG 0x0133 + + +// P5 Message Structures +typedef struct { + nfapi_p4_p5_message_header_t header; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_pnf_param_request_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_pnf_param_general_t pnf_param_general; + nfapi_pnf_phy_t pnf_phy; + nfapi_pnf_rf_t pnf_rf; + nfapi_pnf_phy_rel10_t pnf_phy_rel10; + nfapi_pnf_phy_rel11_t pnf_phy_rel11; + nfapi_pnf_phy_rel12_t pnf_phy_rel12; + nfapi_pnf_phy_rel13_t pnf_phy_rel13; + nfapi_pnf_phy_rel13_nb_iot_t pnf_phy_rel13_nb_iot; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_pnf_param_response_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + nfapi_pnf_phy_rf_config_t pnf_phy_rf_config; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_pnf_config_request_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_pnf_config_response_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_pnf_start_request_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_pnf_start_response_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_pnf_stop_request_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_pnf_stop_response_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_param_request_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint8_t error_code; + uint8_t num_tlv; + // fdd or tdd in idle or configured tlvs + nfapi_l1_status l1_status; + nfapi_phy_capabilities_t phy_capabilities; + nfapi_laa_capability_t laa_capability; + nfapi_nb_iot_capability_t nb_iot_capability; + + nfapi_subframe_config_t subframe_config; + nfapi_rf_config_t rf_config; + nfapi_phich_config_t phich_config; + nfapi_sch_config_t sch_config; + nfapi_prach_config_t prach_config; + nfapi_pusch_config_t pusch_config; + nfapi_pucch_config_t pucch_config; + nfapi_srs_config_t srs_config; + nfapi_uplink_reference_signal_config_t uplink_reference_signal_config; + nfapi_tdd_frame_structure_t tdd_frame_structure_config; + nfapi_l23_config_t l23_config; + nfapi_nb_iot_config_t nb_iot_config; + + // addition nfapi tlvs as per table 2-16 in idle or configure + nfapi_nfapi_t nfapi_config; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_param_response_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint8_t num_tlv; + nfapi_subframe_config_t subframe_config; + nfapi_rf_config_t rf_config; + nfapi_phich_config_t phich_config; + nfapi_sch_config_t sch_config; + nfapi_prach_config_t prach_config; + nfapi_pusch_config_t pusch_config; + nfapi_pucch_config_t pucch_config; + nfapi_srs_config_t srs_config; + nfapi_uplink_reference_signal_config_t uplink_reference_signal_config; + nfapi_laa_config_t laa_config; + nfapi_emtc_config_t emtc_config; + nfapi_tdd_frame_structure_t tdd_frame_structure_config; + nfapi_l23_config_t l23_config; + nfapi_nb_iot_config_t nb_iot_config; + + // addition nfapi tlvs as per table 2-16 in idle or configure + nfapi_nfapi_t nfapi_config; + + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_config_request_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_config_response_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_start_request_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_start_response_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_stop_request_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_stop_response_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + nfapi_uint16_tlv_t dl_rs_tx_power; + nfapi_uint16_tlv_t received_interference_power; + nfapi_uint16_tlv_t thermal_noise_power; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_measurement_request_t; + +#define NFAPI_MEASUREMENT_REQUEST_DL_RS_XTX_POWER_TAG 0x1004 +#define NFAPI_MEASUREMENT_REQUEST_RECEIVED_INTERFERENCE_POWER_TAG 0x1005 +#define NFAPI_MEASUREMENT_REQUEST_THERMAL_NOISE_POWER_TAG 0x1006 + + + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_resource_blocks; + int16_t received_interference_power[NFAPI_MAX_RECEIVED_INTERFERENCE_POWER_RESULTS]; +} nfapi_received_interference_power_measurement_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_int16_tlv_t dl_rs_tx_power_measurement; + nfapi_received_interference_power_measurement_t received_interference_power_measurement; + nfapi_int16_tlv_t thermal_noise_power_measurement; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_measurement_response_t; + +#define NFAPI_MEASUREMENT_RESPONSE_DL_RS_POWER_MEASUREMENT_TAG 0x1007 +#define NFAPI_MEASUREMENT_RESPONSE_RECEIVED_INTERFERENCE_POWER_MEASUREMENT_TAG 0x1008 +#define NFAPI_MEASUREMENT_RESPONSE_THERMAL_NOISE_MEASUREMENT_TAG 0x1009 + +// P7 Sub Structures +typedef struct { + nfapi_tl_t tl; + uint8_t dci_format; + uint8_t cce_idx; + uint8_t aggregation_level; + uint16_t rnti; + uint8_t resource_allocation_type; + uint8_t virtual_resource_block_assignment_flag; + uint32_t resource_block_coding; + uint8_t mcs_1; + uint8_t redundancy_version_1; + uint8_t new_data_indicator_1; + uint8_t transport_block_to_codeword_swap_flag; + uint8_t mcs_2; + uint8_t redundancy_version_2; + uint8_t new_data_indicator_2; + uint8_t harq_process; + uint8_t tpmi; + uint8_t pmi; + uint8_t precoding_information; + uint8_t tpc; + uint8_t downlink_assignment_index; + uint8_t ngap; + uint8_t transport_block_size_index; + uint8_t downlink_power_offset; + uint8_t allocate_prach_flag; + uint8_t preamble_index; + uint8_t prach_mask_index; + uint8_t rnti_type; + uint16_t transmission_power; +} nfapi_dl_config_dci_dl_pdu_rel8_t; +#define NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG 0x2001 + +typedef struct { + nfapi_tl_t tl; + uint8_t mcch_flag; + uint8_t mcch_change_notification; + uint8_t scrambling_identity; +} nfapi_dl_config_dci_dl_pdu_rel9_t; +#define NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL9_TAG 0x2002 + +typedef struct { + nfapi_tl_t tl; + uint8_t cross_carrier_scheduling_flag; + uint8_t carrier_indicator; + uint8_t srs_flag; + uint8_t srs_request; + uint8_t antenna_ports_scrambling_and_layers; + uint8_t total_dci_length_including_padding; + uint8_t n_dl_rb; +} nfapi_dl_config_dci_dl_pdu_rel10_t; +#define NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL10_TAG 0x2003 + + +typedef struct { + nfapi_tl_t tl; + uint8_t harq_ack_resource_offset; + uint8_t pdsch_re_mapping_quasi_co_location_indicator; +} nfapi_dl_config_dci_dl_pdu_rel11_t; + +#define NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL11_TAG 0x2039 + + + +typedef struct { + nfapi_tl_t tl; + uint8_t primary_cell_type; + uint8_t ul_dl_configuration_flag; + uint8_t number_ul_dl_configurations; + uint8_t ul_dl_configuration_indication[NFAPI_MAX_UL_DL_CONFIGURATIONS]; +} nfapi_dl_config_dci_dl_pdu_rel12_t; + +#define NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL12_TAG 0x203a + + + +typedef struct { + uint8_t subband_index; + uint8_t scheduled_ues; + uint16_t precoding_value[NFAPI_MAX_NUM_PHYSICAL_ANTENNAS][NFAPI_MAX_NUM_SCHEDULED_UES]; +} nfapi_dl_config_dci_dl_tpm_subband_info_t; + +typedef struct { + uint8_t num_prb_per_subband; + uint8_t number_of_subbands; + uint8_t num_antennas; + nfapi_dl_config_dci_dl_tpm_subband_info_t subband_info[NFAPI_MAX_NUM_SUBBANDS]; +} nfapi_dl_config_dci_dl_tpm_t; + +typedef struct { + nfapi_tl_t tl; + uint8_t laa_end_partial_sf_flag; + uint8_t laa_end_partial_sf_configuration; + uint8_t initial_lbt_sf; + uint8_t codebook_size_determination; + uint8_t drms_table_flag; + uint8_t tpm_struct_flag; + nfapi_dl_config_dci_dl_tpm_t tpm; +} nfapi_dl_config_dci_dl_pdu_rel13_t; + +#define NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL13_TAG 0x203b + +typedef struct { + nfapi_dl_config_dci_dl_pdu_rel8_t dci_dl_pdu_rel8; + nfapi_dl_config_dci_dl_pdu_rel9_t dci_dl_pdu_rel9; + nfapi_dl_config_dci_dl_pdu_rel10_t dci_dl_pdu_rel10; + nfapi_dl_config_dci_dl_pdu_rel11_t dci_dl_pdu_rel11; + nfapi_dl_config_dci_dl_pdu_rel12_t dci_dl_pdu_rel12; + nfapi_dl_config_dci_dl_pdu_rel13_t dci_dl_pdu_rel13; +} nfapi_dl_config_dci_dl_pdu; + +typedef struct { + nfapi_tl_t tl; + uint16_t length; + uint16_t pdu_index; + uint16_t transmission_power; +} nfapi_dl_config_bch_pdu_rel8_t; +#define NFAPI_DL_CONFIG_REQUEST_BCH_PDU_REL8_TAG 0x2004 + +typedef struct { + nfapi_dl_config_bch_pdu_rel8_t bch_pdu_rel8; +} nfapi_dl_config_bch_pdu; + +typedef struct { + nfapi_tl_t tl; + uint16_t length; + uint16_t pdu_index; + uint16_t rnti; + uint8_t resource_allocation_type; + uint32_t resource_block_coding; + uint8_t modulation; + uint16_t transmission_power; + uint16_t mbsfn_area_id; +} nfapi_dl_config_mch_pdu_rel8_t; +#define NFAPI_DL_CONFIG_REQUEST_MCH_PDU_REL8_TAG 0x2005 + +typedef struct { + nfapi_dl_config_mch_pdu_rel8_t mch_pdu_rel8; +} nfapi_dl_config_mch_pdu; + + +typedef struct { + uint8_t subband_index; + uint8_t num_antennas; + uint16_t bf_value[NFAPI_MAX_NUM_ANTENNAS]; +} nfapi_bf_vector_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t length; + uint16_t pdu_index; + uint16_t rnti; + uint8_t resource_allocation_type; + uint8_t virtual_resource_block_assignment_flag; + uint32_t resource_block_coding; + uint8_t modulation; + uint8_t redundancy_version; + uint8_t transport_blocks; + uint8_t transport_block_to_codeword_swap_flag; + uint8_t transmission_scheme; + uint8_t number_of_layers; + uint8_t number_of_subbands; + uint8_t codebook_index[NFAPI_MAX_NUM_SUBBANDS]; + uint8_t ue_category_capacity; + uint8_t pa; + uint8_t delta_power_offset_index; + uint8_t ngap; + uint8_t nprb; + uint8_t transmission_mode; + uint8_t num_bf_prb_per_subband; + uint8_t num_bf_vector; + nfapi_bf_vector_t bf_vector[NFAPI_MAX_BF_VECTORS]; +} nfapi_dl_config_dlsch_pdu_rel8_t; +#define NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG 0x2006 + +typedef struct { + nfapi_tl_t tl; + uint8_t nscid; +} nfapi_dl_config_dlsch_pdu_rel9_t; +#define NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL9_TAG 0x2007 + +typedef struct { + nfapi_tl_t tl; + uint8_t csi_rs_flag; + uint8_t csi_rs_resource_config_r10; + uint16_t csi_rs_zero_tx_power_resource_config_bitmap_r10; + uint8_t csi_rs_number_nzp_configuration; + uint8_t csi_rs_resource_config[NFAPI_MAX_CSI_RS_RESOURCE_CONFIG]; + uint8_t pdsch_start; +} nfapi_dl_config_dlsch_pdu_rel10_t; +#define NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG 0x2008 + +typedef struct { + nfapi_tl_t tl; + uint8_t drms_config_flag; + uint16_t drms_scrambling; + uint8_t csi_config_flag; + uint16_t csi_scrambling; + uint8_t pdsch_re_mapping_flag; + uint8_t pdsch_re_mapping_atenna_ports; + uint8_t pdsch_re_mapping_freq_shift; +} nfapi_dl_config_dlsch_pdu_rel11_t; +#define NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL11_TAG 0x203C + +typedef struct { + nfapi_tl_t tl; + uint8_t altcqi_table_r12; + uint8_t maxlayers; + uint8_t n_dl_harq; +} nfapi_dl_config_dlsch_pdu_rel12_t; +#define NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL12_TAG 0x203D + +typedef struct { + nfapi_tl_t tl; + uint8_t dwpts_symbols; + uint8_t initial_lbt_sf; + uint8_t ue_type; + uint8_t pdsch_payload_type; + uint16_t initial_transmission_sf_io; + uint8_t drms_table_flag; +} nfapi_dl_config_dlsch_pdu_rel13_t; +#define NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG 0x203E + +typedef struct { + nfapi_dl_config_dlsch_pdu_rel8_t dlsch_pdu_rel8; + nfapi_dl_config_dlsch_pdu_rel9_t dlsch_pdu_rel9; + nfapi_dl_config_dlsch_pdu_rel10_t dlsch_pdu_rel10; + nfapi_dl_config_dlsch_pdu_rel11_t dlsch_pdu_rel11; + nfapi_dl_config_dlsch_pdu_rel12_t dlsch_pdu_rel12; + nfapi_dl_config_dlsch_pdu_rel13_t dlsch_pdu_rel13; +} nfapi_dl_config_dlsch_pdu; + +typedef struct { + nfapi_tl_t tl; + uint16_t length; + uint16_t pdu_index; + uint16_t p_rnti; + uint8_t resource_allocation_type; + uint8_t virtual_resource_block_assignment_flag; + uint32_t resource_block_coding; + uint8_t mcs; + uint8_t redundancy_version; + uint8_t number_of_transport_blocks; + uint8_t transport_block_to_codeword_swap_flag; + uint8_t transmission_scheme; + uint8_t number_of_layers; + uint8_t codebook_index; + uint8_t ue_category_capacity; + uint8_t pa; + uint16_t transmission_power; + uint8_t nprb; + uint8_t ngap; +} nfapi_dl_config_pch_pdu_rel8_t; +#define NFAPI_DL_CONFIG_REQUEST_PCH_PDU_REL8_TAG 0x2009 + +typedef struct { + nfapi_tl_t tl; + uint8_t ue_mode; + uint16_t initial_transmission_sf_io; +} nfapi_dl_config_pch_pdu_rel13_t; +#define NFAPI_DL_CONFIG_REQUEST_PCH_PDU_REL13_TAG 0x203F + +typedef struct { + nfapi_dl_config_pch_pdu_rel8_t pch_pdu_rel8; + nfapi_dl_config_pch_pdu_rel13_t pch_pdu_rel13; +} nfapi_dl_config_pch_pdu; + +typedef struct { + nfapi_tl_t tl; + uint16_t transmission_power; + uint8_t prs_bandwidth; + uint8_t prs_cyclic_prefix_type; + uint8_t prs_muting; +} nfapi_dl_config_prs_pdu_rel9_t; +#define NFAPI_DL_CONFIG_REQUEST_PRS_PDU_REL9_TAG 0x200A + +typedef struct { + nfapi_dl_config_prs_pdu_rel9_t prs_pdu_rel9; +} nfapi_dl_config_prs_pdu; + +typedef struct { + nfapi_tl_t tl; + uint8_t csi_rs_antenna_port_count_r10; + uint8_t csi_rs_resource_config_r10; + uint16_t transmission_power; + uint16_t csi_rs_zero_tx_power_resource_config_bitmap_r10; + uint8_t csi_rs_number_of_nzp_configuration; + uint8_t csi_rs_resource_config[NFAPI_MAX_CSI_RS_RESOURCE_CONFIG]; +} nfapi_dl_config_csi_rs_pdu_rel10_t; +#define NFAPI_DL_CONFIG_REQUEST_CSI_RS_PDU_REL10_TAG 0x200B + +typedef struct { + nfapi_tl_t tl; + uint8_t csi_rs_class; + uint8_t cdm_type; + uint8_t num_bf_vector; + struct { + uint8_t csi_rs_resource_index; + uint16_t bf_value[NFAPI_MAX_ANTENNA_PORT_COUNT]; + } bf_vector[NFAPI_MAX_BF_VECTORS]; + +}nfapi_dl_config_csi_rs_pdu_rel13_t; +#define NFAPI_DL_CONFIG_REQUEST_CSI_RS_PDU_REL13_TAG 0x2040 + +typedef struct { + nfapi_dl_config_csi_rs_pdu_rel10_t csi_rs_pdu_rel10; + nfapi_dl_config_csi_rs_pdu_rel13_t csi_rs_pdu_rel13; +} nfapi_dl_config_csi_rs_pdu; + +#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL8_TAG 0x2001 +#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL9_TAG 0x2002 +#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL10_TAG 0x2003 +#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL11_TAG 0x2039 +#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL12_TAG 0x203a +#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL13_TAG 0x203b + +typedef struct { + nfapi_tl_t tl; + uint8_t epdcch_resource_assignment_flag; + uint16_t epdcch_id; + uint8_t epdcch_start_symbol; + uint8_t epdcch_num_prb; + uint8_t epdcch_prb_index[NFAPI_MAX_EPDCCH_PRB]; + nfapi_bf_vector_t bf_vector; +} nfapi_dl_config_epdcch_parameters_rel11_t; +#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PARAM_REL11_TAG 0x2041 + +typedef struct { + nfapi_tl_t tl; + uint8_t dwpts_symbols; + uint8_t initial_lbt_sf; +} nfapi_dl_config_epdcch_parameters_rel13_t; +#define NFAPI_DL_CONFIG_REQUEST_EPDCCH_PARAM_REL13_TAG 0x2042 + +typedef struct { + nfapi_dl_config_dci_dl_pdu_rel8_t epdcch_pdu_rel8; + nfapi_dl_config_dci_dl_pdu_rel9_t epdcch_pdu_rel9; + nfapi_dl_config_dci_dl_pdu_rel10_t epdcch_pdu_rel10; + nfapi_dl_config_dci_dl_pdu_rel11_t epdcch_pdu_rel11; + nfapi_dl_config_dci_dl_pdu_rel12_t epdcch_pdu_rel12; + nfapi_dl_config_dci_dl_pdu_rel13_t epdcch_pdu_rel13; + nfapi_dl_config_epdcch_parameters_rel11_t epdcch_params_rel11; + nfapi_dl_config_epdcch_parameters_rel13_t epdcch_params_rel13; +} nfapi_dl_config_epdcch_pdu; + + +typedef struct { + nfapi_tl_t tl; + uint8_t mpdcch_narrow_band; + uint8_t number_of_prb_pairs; + uint8_t resource_block_assignment; + uint8_t mpdcch_tansmission_type; + uint8_t start_symbol; + uint8_t ecce_index; + uint8_t aggregation_level; + uint8_t rnti_type; + uint16_t rnti; + uint8_t ce_mode; + uint16_t drms_scrambling_init; + uint16_t initial_transmission_sf_io; + uint16_t transmission_power; + uint8_t dci_format; + uint16_t resource_block_coding; + uint8_t mcs; + uint8_t pdsch_reptition_levels; + uint8_t redundancy_version; + uint8_t new_data_indicator; + uint8_t harq_process; + uint8_t tpmi_length; + uint8_t tpmi; + uint8_t pmi_flag; + uint8_t pmi; + uint8_t harq_resource_offset; + uint8_t dci_subframe_repetition_number; + uint8_t tpc; + uint8_t downlink_assignment_index_length; + uint8_t downlink_assignment_index; + uint8_t allocate_prach_flag; + uint8_t preamble_index; + uint8_t prach_mask_index; + uint8_t starting_ce_level; + uint8_t srs_request; + uint8_t antenna_ports_and_scrambling_identity_flag; + uint8_t antenna_ports_and_scrambling_identity; + uint8_t frequency_hopping_enabled_flag; + uint8_t paging_direct_indication_differentiation_flag; + uint8_t direct_indication; + uint8_t total_dci_length_including_padding; + uint8_t number_of_tx_antenna_ports; + uint16_t precoding_value[NFAPI_MAX_TX_PHYSICAL_ANTENNA_PORTS]; +} nfapi_dl_config_mpdcch_pdu_rel13_t; +#define NFAPI_DL_CONFIG_REQUEST_MPDCCH_PDU_REL13_TAG 0x205B + + +typedef struct { + nfapi_dl_config_mpdcch_pdu_rel13_t mpdcch_pdu_rel13; +} nfapi_dl_config_mpdcch_pdu; + +typedef struct { + nfapi_tl_t tl; + uint16_t length; + uint16_t pdu_index; + uint16_t transmission_power; + uint16_t hyper_sfn_2_lsbs; +} nfapi_dl_config_nbch_pdu_rel13_t; + +#define NFAPI_DL_CONFIG_REQUEST_NBCH_PDU_REL13_TAG 0x205C + +typedef struct { + nfapi_dl_config_nbch_pdu_rel13_t nbch_pdu_rel13; +} nfapi_dl_config_nbch_pdu; + +typedef struct { + nfapi_tl_t tl; + uint16_t length; + uint16_t pdu_index; + uint8_t ncce_index; + uint8_t aggregation_level; + uint8_t start_symbol; + uint8_t rnti_type; + uint16_t rnti; + uint8_t scrambling_reinitialization_batch_index; + uint8_t nrs_antenna_ports_assumed_by_the_ue; + uint8_t dci_format; + uint8_t scheduling_delay; + uint8_t resource_assignment; + uint8_t repetition_number; + uint8_t mcs; + uint8_t new_data_indicator; + uint8_t harq_ack_resource; + uint8_t npdcch_order_indication; + uint8_t starting_number_of_nprach_repetitions; + uint8_t subcarrier_indication_of_nprach; + uint8_t paging_direct_indication_differentation_flag; + uint8_t direct_indication; + uint8_t dci_subframe_repetition_number; + uint8_t total_dci_length_including_padding; +} nfapi_dl_config_npdcch_pdu_rel13_t; + +#define NFAPI_DL_CONFIG_REQUEST_NPDCCH_PDU_REL13_TAG 0x205D + +typedef struct { + nfapi_dl_config_npdcch_pdu_rel13_t npdcch_pdu_rel13; +} nfapi_dl_config_npdcch_pdu; + +typedef struct { + nfapi_tl_t tl; + uint16_t length; + uint16_t pdu_index; + uint8_t start_symbol; + uint8_t rnti_type; + uint16_t rnti; + uint16_t resource_assignment; + uint16_t repetition_number; + uint8_t modulation; + uint8_t number_of_subframes_for_resource_assignment; + uint8_t scrambling_sequence_initialization_cinit; + uint16_t sf_idx; + uint8_t nrs_antenna_ports_assumed_by_the_ue; +} nfapi_dl_config_ndlsch_pdu_rel13_t; + +#define NFAPI_DL_CONFIG_REQUEST_NDLSCH_PDU_REL13_TAG 0x205E + +typedef struct { + nfapi_dl_config_ndlsch_pdu_rel13_t ndlsch_pdu_rel13; +} nfapi_dl_config_ndlsch_pdu; + + +typedef struct { + uint8_t pdu_type; + uint8_t pdu_size; + union { + nfapi_dl_config_dci_dl_pdu dci_dl_pdu; + nfapi_dl_config_bch_pdu bch_pdu; + nfapi_dl_config_mch_pdu mch_pdu; + nfapi_dl_config_dlsch_pdu dlsch_pdu; + nfapi_dl_config_pch_pdu pch_pdu; + nfapi_dl_config_prs_pdu prs_pdu; + nfapi_dl_config_csi_rs_pdu csi_rs_pdu; + nfapi_dl_config_epdcch_pdu epdcch_pdu; + nfapi_dl_config_mpdcch_pdu mpdcch_pdu; + nfapi_dl_config_nbch_pdu nbch_pdu; + nfapi_dl_config_npdcch_pdu npdcch_pdu; + nfapi_dl_config_ndlsch_pdu ndlsch_pdu; + }; +} nfapi_dl_config_request_pdu_t; + +#define NFAPI_DL_CONFIG_MAX_PDU 100 +typedef struct { + nfapi_tl_t tl; + uint8_t number_pdcch_ofdm_symbols; + uint8_t number_dci; + uint16_t number_pdu; + uint8_t number_pdsch_rnti; + uint16_t transmission_power_pcfich; + nfapi_dl_config_request_pdu_t* dl_config_pdu_list; +} nfapi_dl_config_request_body_t; +#define NFAPI_DL_CONFIG_REQUEST_BODY_TAG 0x2000 + +typedef struct { + nfapi_tl_t tl; + uint32_t handle; + uint16_t size; + uint16_t rnti; + uint8_t resource_block_start; + uint8_t number_of_resource_blocks; + uint8_t modulation_type; + uint8_t cyclic_shift_2_for_drms; + uint8_t frequency_hopping_enabled_flag; + uint8_t frequency_hopping_bits; + uint8_t new_data_indication; + uint8_t redundancy_version; + uint8_t harq_process_number; + uint8_t ul_tx_mode; + uint8_t current_tx_nb; + uint8_t n_srs; +} nfapi_ul_config_ulsch_pdu_rel8_t; +#define NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG 0x200D + +typedef struct { + nfapi_tl_t tl; + uint8_t resource_allocation_type; + uint32_t resource_block_coding; + uint8_t transport_blocks; + uint8_t transmission_scheme; + uint8_t number_of_layers; + uint8_t codebook_index; + uint8_t disable_sequence_hopping_flag; +} nfapi_ul_config_ulsch_pdu_rel10_t; +#define NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL10_TAG 0x200E + + +typedef struct { + nfapi_tl_t tl; + uint8_t virtual_cell_id_enabled_flag; + uint16_t npusch_identity; + uint8_t dmrs_config_flag; + uint16_t ndmrs_csh_identity; +} nfapi_ul_config_ulsch_pdu_rel11_t; + +#define NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL11_TAG 0x2043 + +typedef struct { + nfapi_tl_t tl; + uint8_t ue_type; + uint16_t total_number_of_repetitions; + uint16_t repetition_number; + uint16_t initial_transmission_sf_io; + uint8_t empty_symbols_due_to_re_tunning; +} nfapi_ul_config_ulsch_pdu_rel13_t; +#define NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL13_TAG 0x2044 + +typedef struct { + nfapi_ul_config_ulsch_pdu_rel8_t ulsch_pdu_rel8; + nfapi_ul_config_ulsch_pdu_rel10_t ulsch_pdu_rel10; + nfapi_ul_config_ulsch_pdu_rel11_t ulsch_pdu_rel11; + nfapi_ul_config_ulsch_pdu_rel13_t ulsch_pdu_rel13; +} nfapi_ul_config_ulsch_pdu; + +typedef struct { + nfapi_tl_t tl; + uint8_t dl_cqi_pmi_size_rank_1; + uint8_t dl_cqi_pmi_size_rank_greater_1; + uint8_t ri_size; + uint8_t delta_offset_cqi; + uint8_t delta_offset_ri; +} nfapi_ul_config_cqi_ri_information_rel8_t; +#define NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL8_TAG 0x2010 + +typedef struct { + uint8_t dl_cqi_pmi_ri_size; + uint8_t control_type; +} nfapi_ul_config_periodic_cqi_pmi_ri_report_t; + +typedef struct { + uint8_t number_of_cc; + struct { + uint8_t ri_size; + uint8_t dl_cqi_pmi_size[8]; + } cc[NFAPI_MAX_CC]; +} nfapi_ul_config_aperiodic_cqi_pmi_ri_report_t; + +typedef struct { + nfapi_tl_t tl; + uint8_t report_type; + uint8_t delta_offset_cqi; + uint8_t delta_offset_ri; + union { + nfapi_ul_config_periodic_cqi_pmi_ri_report_t periodic_cqi_pmi_ri_report; + nfapi_ul_config_aperiodic_cqi_pmi_ri_report_t aperiodic_cqi_pmi_ri_report; + }; +} nfapi_ul_config_cqi_ri_information_rel9_t; +#define NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL9_TAG 0x2011 + +typedef struct { + uint16_t dl_cqi_pmi_ri_size_2; +} nfapi_ul_config_periodic_cqi_pmi_ri_report_re13_t; + +typedef struct { +} nfapi_ul_config_aperiodic_cqi_pmi_ri_report_re13_t; + +typedef struct { + nfapi_tl_t tl; + uint8_t report_type; // Convience parameter, not sent on the wire + union { + nfapi_ul_config_periodic_cqi_pmi_ri_report_re13_t periodic_cqi_pmi_ri_report; + nfapi_ul_config_aperiodic_cqi_pmi_ri_report_re13_t aperiodic_cqi_pmi_ri_report; + }; +} nfapi_ul_config_cqi_ri_information_rel13_t; +#define NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL13_TAG 0x2045 + +typedef struct { + nfapi_ul_config_cqi_ri_information_rel8_t cqi_ri_information_rel8; + nfapi_ul_config_cqi_ri_information_rel9_t cqi_ri_information_rel9; + nfapi_ul_config_cqi_ri_information_rel13_t cqi_ri_information_rel13; +} nfapi_ul_config_cqi_ri_information; + +typedef struct { + nfapi_tl_t tl; + uint8_t harq_size; + uint8_t delta_offset_harq; + uint8_t ack_nack_mode; +} nfapi_ul_config_ulsch_harq_information_rel10_t; +#define NFAPI_UL_CONFIG_REQUEST_ULSCH_HARQ_INFORMATION_REL10_TAG 0x2012 + +typedef struct { + nfapi_tl_t tl; + uint16_t harq_size_2; + uint8_t delta_offset_harq_2; +} nfapi_ul_config_ulsch_harq_information_rel13_t; +#define NFAPI_UL_CONFIG_REQUEST_ULSCH_HARQ_INFORMATION_REL13_TAG 0x2046 + +typedef struct { + nfapi_ul_config_ulsch_harq_information_rel10_t harq_information_rel10; + nfapi_ul_config_ulsch_harq_information_rel13_t harq_information_rel13; +} nfapi_ul_config_ulsch_harq_information; + +typedef struct { + nfapi_tl_t tl; + uint8_t n_srs_initial; + uint8_t initial_number_of_resource_blocks; +} nfapi_ul_config_initial_transmission_parameters_rel8_t; +#define NFAPI_UL_CONFIG_REQUEST_INITIAL_TRANSMISSION_PARAMETERS_REL8_TAG 0x200F + +typedef struct { + nfapi_ul_config_initial_transmission_parameters_rel8_t initial_transmission_parameters_rel8; +} nfapi_ul_config_initial_transmission_parameters; + +typedef struct { + nfapi_ul_config_ulsch_pdu ulsch_pdu; + nfapi_ul_config_cqi_ri_information cqi_ri_information; + nfapi_ul_config_initial_transmission_parameters initial_transmission_parameters; +} nfapi_ul_config_ulsch_cqi_ri_pdu; + +typedef struct { + nfapi_ul_config_ulsch_pdu ulsch_pdu; + nfapi_ul_config_ulsch_harq_information harq_information; + nfapi_ul_config_initial_transmission_parameters initial_transmission_parameters; +} nfapi_ul_config_ulsch_harq_pdu; + +typedef struct { + nfapi_ul_config_ulsch_pdu ulsch_pdu; + nfapi_ul_config_cqi_ri_information cqi_ri_information; + nfapi_ul_config_ulsch_harq_information harq_information; + nfapi_ul_config_initial_transmission_parameters initial_transmission_parameters; +} nfapi_ul_config_ulsch_cqi_harq_ri_pdu; + + +typedef struct { + nfapi_tl_t tl; + uint32_t handle; + uint16_t rnti; +} nfapi_ul_config_ue_information_rel8_t; +#define NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG 0x2013 + +typedef struct { + nfapi_tl_t tl; + uint8_t virtual_cell_id_enabled_flag; + uint16_t npusch_identity; +} nfapi_ul_config_ue_information_rel11_t; + +#define NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL11_TAG 0x2047 + +typedef struct { + nfapi_tl_t tl; + uint8_t ue_type; + uint8_t empty_symbols; + uint16_t total_number_of_repetitions; + uint16_t repetition_number; +} nfapi_ul_config_ue_information_rel13_t; + +#define NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL13_TAG 0x2048 + +typedef struct { + nfapi_ul_config_ue_information_rel8_t ue_information_rel8; + nfapi_ul_config_ue_information_rel11_t ue_information_rel11; + nfapi_ul_config_ue_information_rel13_t ue_information_rel13; +} nfapi_ul_config_ue_information; + +typedef struct { + nfapi_tl_t tl; + uint16_t pucch_index; + uint8_t dl_cqi_pmi_size; +} nfapi_ul_config_cqi_information_rel8_t; +#define NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG 0x2014 + +typedef struct { + nfapi_tl_t tl; + uint8_t number_of_pucch_resource; + uint16_t pucch_index_p1; +} nfapi_ul_config_cqi_information_rel10_t; +#define NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL10_TAG 0x2015 + +typedef struct { + nfapi_tl_t tl; + uint8_t csi_mode; + uint16_t dl_cqi_pmi_size_2; + uint8_t starting_prb; + uint8_t n_prb; + uint8_t cdm_index; + uint8_t n_srs; +} nfapi_ul_config_cqi_information_rel13_t; +#define NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL13_TAG 0x2049 + +typedef struct { + nfapi_ul_config_cqi_information_rel8_t cqi_information_rel8; + nfapi_ul_config_cqi_information_rel10_t cqi_information_rel10; + nfapi_ul_config_cqi_information_rel13_t cqi_information_rel13; +} nfapi_ul_config_cqi_information; + +typedef struct { + nfapi_tl_t tl; + uint16_t pucch_index; +} nfapi_ul_config_sr_information_rel8_t; +#define NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL8_TAG 0x2016 + +typedef struct { + nfapi_tl_t tl; + uint8_t number_of_pucch_resources; + uint16_t pucch_index_p1; +} nfapi_ul_config_sr_information_rel10_t; +#define NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL10_TAG 0x2017 + +typedef struct { + nfapi_ul_config_sr_information_rel8_t sr_information_rel8; + nfapi_ul_config_sr_information_rel10_t sr_information_rel10; +} nfapi_ul_config_sr_information; + +typedef struct { + nfapi_tl_t tl; + uint8_t harq_size; + uint8_t ack_nack_mode; + uint8_t number_of_pucch_resources; + uint16_t n_pucch_1_0; + uint16_t n_pucch_1_1; + uint16_t n_pucch_1_2; + uint16_t n_pucch_1_3; +} nfapi_ul_config_harq_information_rel10_tdd_t; +#define NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG 0x2018 + + +typedef struct { + nfapi_tl_t tl; + uint16_t n_pucch_1_0; + uint8_t harq_size; +} nfapi_ul_config_harq_information_rel8_fdd_t; +#define NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL8_FDD_TAG 0x2019 + +typedef struct { + nfapi_tl_t tl; + uint8_t harq_size; + uint8_t ack_nack_mode; + uint8_t number_of_pucch_resources; + uint16_t n_pucch_1_0; + uint16_t n_pucch_1_1; + uint16_t n_pucch_1_2; + uint16_t n_pucch_1_3; +} nfapi_ul_config_harq_information_rel9_fdd_t; +#define NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG 0x201a + +typedef struct { + nfapi_tl_t tl; + uint8_t num_ant_ports; + uint16_t n_pucch_2_0; + uint16_t n_pucch_2_1; + uint16_t n_pucch_2_2; + uint16_t n_pucch_2_3; +} nfapi_ul_config_harq_information_rel11_t; +#define NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL11_TAG 0x204A + +typedef struct { + nfapi_tl_t tl; + uint16_t harq_size_2; + uint8_t starting_prb; + uint8_t n_prb; + uint8_t cdm_index; + uint8_t n_srs; +} nfapi_ul_config_harq_information_rel13_t; +#define NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL13_TAG 0x204B + +typedef struct { + nfapi_ul_config_harq_information_rel10_tdd_t harq_information_rel10_tdd; + nfapi_ul_config_harq_information_rel8_fdd_t harq_information_rel8_fdd; + nfapi_ul_config_harq_information_rel9_fdd_t harq_information_rel9_fdd; + nfapi_ul_config_harq_information_rel11_t harq_information_rel11; + nfapi_ul_config_harq_information_rel13_t harq_information_rel13; +} nfapi_ul_config_harq_information; + +typedef struct { + nfapi_tl_t tl; + uint32_t handle; + uint16_t size; + uint16_t rnti; + uint8_t srs_bandwidth; + uint8_t frequency_domain_position; + uint8_t srs_hopping_bandwidth; + uint8_t transmission_comb; + uint16_t i_srs; + uint8_t sounding_reference_cyclic_shift; +} nfapi_ul_config_srs_pdu_rel8_t; +#define NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL8_TAG 0x201b + +typedef struct { + nfapi_tl_t tl; + uint8_t antenna_port; +} nfapi_ul_config_srs_pdu_rel10_t; +#define NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL10_TAG 0x201c + +typedef struct { + nfapi_tl_t tl; + uint8_t number_of_combs; +} nfapi_ul_config_srs_pdu_rel13_t; +#define NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL13_TAG 0x204c + +typedef struct { + nfapi_ul_config_srs_pdu_rel8_t srs_pdu_rel8; + nfapi_ul_config_srs_pdu_rel10_t srs_pdu_rel10; + nfapi_ul_config_srs_pdu_rel13_t srs_pdu_rel13; +} nfapi_ul_config_srs_pdu; + +typedef struct { + nfapi_ul_config_ue_information ue_information; + nfapi_ul_config_cqi_information cqi_information; +} nfapi_ul_config_uci_cqi_pdu; + +typedef struct { + nfapi_ul_config_ue_information ue_information; + nfapi_ul_config_sr_information sr_information; +} nfapi_ul_config_uci_sr_pdu; + +typedef struct { + nfapi_ul_config_ue_information ue_information; + nfapi_ul_config_harq_information harq_information; +} nfapi_ul_config_uci_harq_pdu; + +typedef struct { + nfapi_ul_config_ue_information ue_information; + nfapi_ul_config_sr_information sr_information; + nfapi_ul_config_harq_information harq_information; +} nfapi_ul_config_uci_sr_harq_pdu; + +typedef struct { + nfapi_ul_config_ue_information ue_information; + nfapi_ul_config_cqi_information cqi_information; + nfapi_ul_config_harq_information harq_information; +} nfapi_ul_config_uci_cqi_harq_pdu; + +typedef struct { + nfapi_ul_config_ue_information ue_information; + nfapi_ul_config_cqi_information cqi_information; + nfapi_ul_config_sr_information sr_information; +} nfapi_ul_config_uci_cqi_sr_pdu; + +typedef struct { + nfapi_ul_config_ue_information ue_information; + nfapi_ul_config_cqi_information cqi_information; + nfapi_ul_config_sr_information sr_information; + nfapi_ul_config_harq_information harq_information; +} nfapi_ul_config_uci_cqi_sr_harq_pdu; + +typedef struct { + nfapi_ul_config_ue_information ue_information; +} nfapi_ul_config_harq_buffer_pdu; + +typedef struct { + nfapi_ul_config_ulsch_pdu ulsch_pdu; + nfapi_ul_config_cqi_information csi_information; +} nfapi_ul_config_ulsch_uci_csi_pdu; + +typedef struct { + nfapi_ul_config_ulsch_pdu ulsch_pdu; + nfapi_ul_config_harq_information harq_information; +} nfapi_ul_config_ulsch_uci_harq_pdu; + +typedef struct { + nfapi_ul_config_ulsch_pdu ulsch_pdu; + nfapi_ul_config_cqi_information csi_information; + nfapi_ul_config_harq_information harq_information; +} nfapi_ul_config_ulsch_csi_uci_harq_pdu; + +typedef struct { + nfapi_tl_t tl; + uint8_t harq_ack_resource; +} nfapi_ul_config_nb_harq_information_rel13_fdd_t; +#define NFAPI_UL_CONFIG_REQUEST_NB_HARQ_INFORMATION_REL13_FDD_TAG 0x2061 + +typedef struct { + nfapi_ul_config_nb_harq_information_rel13_fdd_t nb_harq_information_rel13_fdd; +} nfapi_ul_config_nb_harq_information; + +typedef struct { + nfapi_tl_t tl; + uint8_t nulsch_format; + uint32_t handle; + uint16_t size; + uint16_t rnti; + uint8_t subcarrier_indication; + uint8_t resource_assignment; + uint8_t mcs; + uint8_t redudancy_version; + uint8_t repetition_number; + uint8_t new_data_indication; + uint8_t n_srs; + uint16_t scrambling_sequence_initialization_cinit; + uint16_t sf_idx; + nfapi_ul_config_ue_information ue_information; + nfapi_ul_config_nb_harq_information nb_harq_information; +} nfapi_ul_config_nulsch_pdu_rel13_t; +#define NFAPI_UL_CONFIG_REQUEST_NULSCH_PDU_REL13_TAG 0x205F + +typedef struct { + nfapi_ul_config_nulsch_pdu_rel13_t nulsch_pdu_rel13; +} nfapi_ul_config_nulsch_pdu; + + +typedef struct { + nfapi_tl_t tl; + uint8_t nprach_config_0; + uint8_t nprach_config_1; + uint8_t nprach_config_2; +} nfapi_ul_config_nrach_pdu_rel13_t; +#define NFAPI_UL_CONFIG_REQUEST_NRACH_PDU_REL13_TAG 0x2067 + +typedef struct { + nfapi_ul_config_nrach_pdu_rel13_t nrach_pdu_rel13; +} nfapi_ul_config_nrach_pdu; + +typedef struct { + uint8_t pdu_type; + uint8_t pdu_size; + union { + nfapi_ul_config_ulsch_pdu ulsch_pdu; + nfapi_ul_config_ulsch_cqi_ri_pdu ulsch_cqi_ri_pdu; + nfapi_ul_config_ulsch_harq_pdu ulsch_harq_pdu; + nfapi_ul_config_ulsch_cqi_harq_ri_pdu ulsch_cqi_harq_ri_pdu; + nfapi_ul_config_uci_cqi_pdu uci_cqi_pdu; + nfapi_ul_config_uci_sr_pdu uci_sr_pdu; + nfapi_ul_config_uci_harq_pdu uci_harq_pdu; + nfapi_ul_config_uci_sr_harq_pdu uci_sr_harq_pdu; + nfapi_ul_config_uci_cqi_harq_pdu uci_cqi_harq_pdu; + nfapi_ul_config_uci_cqi_sr_pdu uci_cqi_sr_pdu; + nfapi_ul_config_uci_cqi_sr_harq_pdu uci_cqi_sr_harq_pdu; + nfapi_ul_config_srs_pdu srs_pdu; + nfapi_ul_config_harq_buffer_pdu harq_buffer_pdu; + nfapi_ul_config_ulsch_uci_csi_pdu ulsch_uci_csi_pdu; + nfapi_ul_config_ulsch_uci_harq_pdu ulsch_uci_harq_pdu; + nfapi_ul_config_ulsch_csi_uci_harq_pdu ulsch_csi_uci_harq_pdu; + nfapi_ul_config_nulsch_pdu nulsch_pdu; + nfapi_ul_config_nrach_pdu nrach_pdu; + }; +} nfapi_ul_config_request_pdu_t; + +#define NFAPI_UL_CONFIG_MAX_PDU 100 +typedef struct { + nfapi_tl_t tl; + uint8_t number_of_pdus; + uint8_t rach_prach_frequency_resources; + uint8_t srs_present; + nfapi_ul_config_request_pdu_t* ul_config_pdu_list; +} nfapi_ul_config_request_body_t; +#define NFAPI_UL_CONFIG_REQUEST_BODY_TAG 0x200C + +typedef struct { + nfapi_tl_t tl; + uint8_t resource_block_start; + uint8_t cyclic_shift_2_for_drms; + uint8_t hi_value; + uint8_t i_phich; + uint16_t transmission_power; +} nfapi_hi_dci0_hi_pdu_rel8_t; +#define NFAPI_HI_DCI0_REQUEST_HI_PDU_REL8_TAG 0x201e + +typedef struct { + nfapi_tl_t tl; + uint8_t flag_tb2; + uint8_t hi_value_2; +} nfapi_hi_dci0_hi_pdu_rel10_t; +#define NFAPI_HI_DCI0_REQUEST_HI_PDU_REL10_TAG 0x201f + +typedef struct { + nfapi_hi_dci0_hi_pdu_rel8_t hi_pdu_rel8; + nfapi_hi_dci0_hi_pdu_rel10_t hi_pdu_rel10; +} nfapi_hi_dci0_hi_pdu; + +typedef struct { + nfapi_tl_t tl; + uint8_t dci_format; + uint8_t cce_index; + uint8_t aggregation_level; + uint16_t rnti; + uint8_t resource_block_start; + uint8_t number_of_resource_block; + uint8_t mcs_1; + uint8_t cyclic_shift_2_for_drms; + uint8_t frequency_hopping_enabled_flag; + uint8_t frequency_hopping_bits; + uint8_t new_data_indication_1; + uint8_t ue_tx_antenna_seleciton; + uint8_t tpc; + uint8_t cqi_csi_request; + uint8_t ul_index; + uint8_t dl_assignment_index; + uint32_t tpc_bitmap; + uint16_t transmission_power; +} nfapi_hi_dci0_dci_pdu_rel8_t; +#define NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL8_TAG 0x2020 + +typedef struct { + nfapi_tl_t tl; + uint8_t cross_carrier_scheduling_flag; + uint8_t carrier_indicator; + uint8_t size_of_cqi_csi_feild; + uint8_t srs_flag; + uint8_t srs_request; + uint8_t resource_allocation_flag; + uint8_t resource_allocation_type; + uint32_t resource_block_coding; + uint8_t mcs_2; + uint8_t new_data_indication_2; + uint8_t number_of_antenna_ports; + uint8_t tpmi; + uint8_t total_dci_length_including_padding; + uint8_t n_ul_rb; +} nfapi_hi_dci0_dci_pdu_rel10_t; +#define NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL10_TAG 0x2021 + +typedef struct { + nfapi_tl_t tl; + uint8_t pscch_resource; + uint8_t time_resource_pattern; +} nfapi_hi_dci0_dci_pdu_rel12_t; + +#define NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL12_TAG 0x204D + +typedef struct { + nfapi_hi_dci0_dci_pdu_rel8_t dci_pdu_rel8; + nfapi_hi_dci0_dci_pdu_rel10_t dci_pdu_rel10; + nfapi_hi_dci0_dci_pdu_rel12_t dci_pdu_rel12; +} nfapi_hi_dci0_dci_pdu; + +typedef nfapi_hi_dci0_dci_pdu_rel8_t nfapi_hi_dci0_epdcch_dci_pdu_rel8_t; +#define NFAPI_HI_DCI0_REQUEST_EPDCCH_DCI_PDU_REL8_TAG 0x2020 + +typedef nfapi_hi_dci0_dci_pdu_rel10_t nfapi_hi_dci0_epdcch_dci_pdu_rel10_t; +#define NFAPI_HI_DCI0_REQUEST_EPDCCH_DCI_PDU_REL10_TAG 0x2021 + +typedef nfapi_dl_config_epdcch_parameters_rel11_t nfapi_hi_dci0_epdcch_parameters_rel11_t; +#define NFAPI_HI_DCI0_REQUEST_EPDCCH_PARAMETERS_REL11_TAG 0x2041 + +typedef struct { + nfapi_hi_dci0_epdcch_dci_pdu_rel8_t epdcch_dci_pdu_rel8; + nfapi_hi_dci0_epdcch_dci_pdu_rel10_t epdcch_dci_pdu_rel10; + nfapi_hi_dci0_epdcch_parameters_rel11_t epdcch_parameters_rel11; +} nfapi_hi_dci0_epdcch_dci_pdu; + + +typedef struct { + nfapi_tl_t tl; + uint8_t mpdcch_narrowband; + uint8_t number_of_prb_pairs; + uint8_t resource_block_assignment; + uint8_t mpdcch_transmission_type; + uint8_t start_symbol; + uint8_t ecce_index; + uint8_t aggreagation_level; + uint8_t rnti_type; + uint16_t rnti; + uint8_t ce_mode; + uint16_t drms_scrambling_init; + uint16_t initial_transmission_sf_io; + uint16_t transmission_power; + uint8_t dci_format; + uint8_t resource_block_start; + uint8_t number_of_resource_blocks; + uint8_t mcs; + uint8_t pusch_repetition_levels; + uint8_t frequency_hopping_flag; + uint8_t new_data_indication; + uint8_t harq_process; + uint8_t redudency_version; + uint8_t tpc; + uint8_t csi_request; + uint8_t ul_inex; + uint8_t dai_presence_flag; + uint8_t dl_assignment_index; + uint8_t srs_request; + uint8_t dci_subframe_repetition_number; + uint32_t tcp_bitmap; + uint8_t total_dci_length_include_padding; + uint8_t number_of_tx_antenna_ports; + uint16_t precoding_value[NFAPI_MAX_ANTENNA_PORT_COUNT]; +} nfapi_hi_dci0_mpdcch_dci_pdu_rel13_t; +#define NFAPI_HI_DCI0_REQUEST_MPDCCH_DCI_PDU_REL13_TAG 0x204E + +typedef struct { + nfapi_hi_dci0_mpdcch_dci_pdu_rel13_t mpdcch_dci_pdu_rel13; +} nfapi_hi_dci0_mpdcch_dci_pdu; + +typedef struct { + nfapi_tl_t tl; + uint8_t ncce_index; + uint8_t aggregation_level; + uint8_t start_symbol; + uint16_t rnti; + uint8_t scrambling_reinitialization_batch_index; + uint8_t nrs_antenna_ports_assumed_by_the_ue; + uint8_t subcarrier_indication; + uint8_t resource_assignment; + uint8_t scheduling_delay; + uint8_t mcs; + uint8_t redudancy_version; + uint8_t repetition_number; + uint8_t new_data_indicator; + uint8_t dci_subframe_repetition_number; +} nfapi_hi_dci0_npdcch_dci_pdu_rel13_t; + +#define NFAPI_HI_DCI0_REQUEST_NPDCCH_DCI_PDU_REL13_TAG 0x2062 + +typedef struct { + nfapi_hi_dci0_npdcch_dci_pdu_rel13_t npdcch_dci_pdu_rel13; +} nfapi_hi_dci0_npdcch_dci_pdu; + +typedef struct { + uint8_t pdu_type; + uint8_t pdu_size; + union { + nfapi_hi_dci0_hi_pdu hi_pdu; + nfapi_hi_dci0_dci_pdu dci_pdu; + nfapi_hi_dci0_epdcch_dci_pdu epdcch_dci_pdu; + nfapi_hi_dci0_mpdcch_dci_pdu mpdcch_dci_pdu; + nfapi_hi_dci0_npdcch_dci_pdu npdcch_dci_pdu; + }; +} nfapi_hi_dci0_request_pdu_t; + +#define NFAPI_HI_DCI0_MAX_PDU 100 +typedef struct { + nfapi_tl_t tl; + uint16_t sfnsf; + uint8_t number_of_dci; + uint8_t number_of_hi; + nfapi_hi_dci0_request_pdu_t* hi_dci0_pdu_list; +} nfapi_hi_dci0_request_body_t; +#define NFAPI_HI_DCI0_REQUEST_BODY_TAG 0x201D + +#define NFAPI_TX_MAX_SEGMENTS 32 +typedef struct { + uint16_t pdu_length; + uint16_t pdu_index; + uint8_t num_segments; + struct { + uint32_t segment_length; + uint8_t* segment_data; + } segments[NFAPI_TX_MAX_SEGMENTS]; +} nfapi_tx_request_pdu_t; + +#define NFAPI_TX_MAX_PDU 100 +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_pdus; + nfapi_tx_request_pdu_t* tx_pdu_list; +} nfapi_tx_request_body_t; +#define NFAPI_TX_REQUEST_BODY_TAG 0x2022 + +// P7 Message Structures +typedef struct { + nfapi_p7_message_header_t header; + uint32_t t1; + int32_t delta_sfn_sf; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_dl_node_sync_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint32_t t1; + uint32_t t2; + uint32_t t3; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_ul_node_sync_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint32_t last_sfn_sf; + uint32_t time_since_last_timing_info; + uint32_t dl_config_jitter; + uint32_t tx_request_jitter; + uint32_t ul_config_jitter; + uint32_t hi_dci0_jitter; + int32_t dl_config_latest_delay; + int32_t tx_request_latest_delay; + int32_t ul_config_latest_delay; + int32_t hi_dci0_latest_delay; + int32_t dl_config_earliest_arrival; + int32_t tx_request_earliest_arrival; + int32_t ul_config_earliest_arrival; + int32_t hi_dci0_earliest_arrival; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_timing_info_t; + +typedef struct { + nfapi_tl_t tl; + uint32_t handle; + uint16_t rnti; +} nfapi_rx_ue_information; +#define NFAPI_RX_UE_INFORMATION_TAG 0x2038 + +typedef struct { + uint8_t value_0; + uint8_t value_1; +} nfapi_harq_indication_tdd_harq_data_bundling_t; + +typedef struct { + uint8_t value_0; + uint8_t value_1; + uint8_t value_2; + uint8_t value_3; +} nfapi_harq_indication_tdd_harq_data_multiplexing_t; + +typedef struct { + uint8_t value_0; +} nfapi_harq_indication_tdd_harq_data_special_bundling_t; + +typedef struct { + uint8_t value_0; +} nfapi_harq_indication_tdd_harq_data_t; + +typedef struct { + nfapi_tl_t tl; + uint8_t mode; + uint8_t number_of_ack_nack; + union{ + nfapi_harq_indication_tdd_harq_data_bundling_t bundling; + nfapi_harq_indication_tdd_harq_data_multiplexing_t multiplex; + nfapi_harq_indication_tdd_harq_data_special_bundling_t special_bundling; + } harq_data; +} nfapi_harq_indication_tdd_rel8_t; +#define NFAPI_HARQ_INDICATION_TDD_REL8_TAG 0x2027 + +typedef struct { + nfapi_tl_t tl; + uint8_t mode; + uint8_t number_of_ack_nack; + union{ + nfapi_harq_indication_tdd_harq_data_t bundling; + nfapi_harq_indication_tdd_harq_data_t multiplex; + nfapi_harq_indication_tdd_harq_data_special_bundling_t special_bundling; + nfapi_harq_indication_tdd_harq_data_t channel_selection; + nfapi_harq_indication_tdd_harq_data_t format_3; + } harq_data[NFAPI_MAX_NUMBER_ACK_NACK_TDD]; +} nfapi_harq_indication_tdd_rel9_t; +#define NFAPI_HARQ_INDICATION_TDD_REL9_TAG 0x2028 + +typedef struct { + nfapi_tl_t tl; + uint8_t mode; + uint16_t number_of_ack_nack; + union{ + nfapi_harq_indication_tdd_harq_data_t bundling; + nfapi_harq_indication_tdd_harq_data_t multiplex; + nfapi_harq_indication_tdd_harq_data_special_bundling_t special_bundling; + nfapi_harq_indication_tdd_harq_data_t channel_selection; + nfapi_harq_indication_tdd_harq_data_t format_3; + nfapi_harq_indication_tdd_harq_data_t format_4; + nfapi_harq_indication_tdd_harq_data_t format_5; + } harq_data[NFAPI_MAX_NUMBER_ACK_NACK_TDD]; +} nfapi_harq_indication_tdd_rel13_t; +#define NFAPI_HARQ_INDICATION_TDD_REL13_TAG 0x204F + +typedef struct { + nfapi_tl_t tl; + uint8_t harq_tb1; + uint8_t harq_tb2; +} nfapi_harq_indication_fdd_rel8_t; +#define NFAPI_HARQ_INDICATION_FDD_REL8_TAG 0x2029 + +#define NFAPI_HARQ_ACK_NACK_REL9_MAX 10 +typedef struct { + nfapi_tl_t tl; + uint8_t mode; + uint8_t number_of_ack_nack; + uint8_t harq_tb_n[NFAPI_HARQ_ACK_NACK_REL9_MAX]; +} nfapi_harq_indication_fdd_rel9_t; +#define NFAPI_HARQ_INDICATION_FDD_REL9_TAG 0x202a + +#define NFAPI_HARQ_ACK_NACK_REL13_MAX 22 // Need to check this max? +typedef struct { + nfapi_tl_t tl; + uint8_t mode; + uint16_t number_of_ack_nack; + uint8_t harq_tb_n[NFAPI_HARQ_ACK_NACK_REL13_MAX]; +} nfapi_harq_indication_fdd_rel13_t; +#define NFAPI_HARQ_INDICATION_FDD_REL13_TAG 0x2050 + +typedef struct { + nfapi_tl_t tl; + uint8_t ul_cqi; + uint8_t channel; +} nfapi_ul_cqi_information_t; +#define NFAPI_UL_CQI_INFORMATION_TAG 0x2052 + +// Only expect 1 harq_indication TLV.tag to be set +// Would this be a better a an union, but not clear which combinations +// are valid +typedef struct { + uint16_t instance_length; + nfapi_rx_ue_information rx_ue_information; + nfapi_harq_indication_tdd_rel8_t harq_indication_tdd_rel8; + nfapi_harq_indication_tdd_rel9_t harq_indication_tdd_rel9; + nfapi_harq_indication_tdd_rel13_t harq_indication_tdd_rel13; + nfapi_harq_indication_fdd_rel8_t harq_indication_fdd_rel8; + nfapi_harq_indication_fdd_rel9_t harq_indication_fdd_rel9; + nfapi_harq_indication_fdd_rel13_t harq_indication_fdd_rel13; + nfapi_ul_cqi_information_t ul_cqi_information; +} nfapi_harq_indication_pdu_t; + +#define NFAPI_HARQ_IND_MAX_PDU 100 +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_harqs; + nfapi_harq_indication_pdu_t* harq_pdu_list; +} nfapi_harq_indication_body_t; +#define NFAPI_HARQ_INDICATION_BODY_TAG 0x2026 + +typedef struct { + nfapi_tl_t tl; + uint8_t crc_flag; +} nfapi_crc_indication_rel8_t; +#define NFAPI_CRC_INDICATION_REL8_TAG 0x202c + +typedef struct { + uint16_t instance_length; + nfapi_rx_ue_information rx_ue_information; + nfapi_crc_indication_rel8_t crc_indication_rel8; +} nfapi_crc_indication_pdu_t; + +#define NFAPI_CRC_IND_MAX_PDU 100 +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_crcs; + nfapi_crc_indication_pdu_t* crc_pdu_list; +} nfapi_crc_indication_body_t; +#define NFAPI_CRC_INDICATION_BODY_TAG 0x202b + +typedef struct { + uint16_t instance_length; + nfapi_rx_ue_information rx_ue_information; + nfapi_ul_cqi_information_t ul_cqi_information; +} nfapi_sr_indication_pdu_t; + +#define NFAPI_SR_IND_MAX_PDU 100 +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_srs; // Question : should this be srs + nfapi_sr_indication_pdu_t* sr_pdu_list; +} nfapi_sr_indication_body_t; +#define NFAPI_SR_INDICATION_BODY_TAG 0x202d + +// The data offset should be set to 0 or 1 before encoding +// If it is set to 1 the nfapi library will detemine the correct offset + +typedef struct { + nfapi_tl_t tl; + uint16_t length; + uint16_t data_offset; + uint8_t ul_cqi; + uint8_t ri; + uint16_t timing_advance; +} nfapi_cqi_indication_rel8_t; +#define NFAPI_CQI_INDICATION_REL8_TAG 0x202f + +#define NFAPI_CC_MAX 4 +typedef struct { + nfapi_tl_t tl; + uint16_t length; + uint16_t data_offset; + uint8_t ul_cqi; + uint8_t number_of_cc_reported; + uint8_t ri[NFAPI_CC_MAX]; + uint16_t timing_advance; + uint16_t timing_advance_r9; +} nfapi_cqi_indication_rel9_t; +#define NFAPI_CQI_INDICATION_REL9_TAG 0x2030 + +typedef struct { + uint16_t instance_length; + nfapi_rx_ue_information rx_ue_information; + nfapi_cqi_indication_rel8_t cqi_indication_rel8; + nfapi_cqi_indication_rel9_t cqi_indication_rel9; + nfapi_ul_cqi_information_t ul_cqi_information; +} nfapi_cqi_indication_pdu_t; + +#define NFAPI_CQI_RAW_MAX_LEN 12 +typedef struct { + uint8_t pdu[NFAPI_CQI_RAW_MAX_LEN]; +} nfapi_cqi_indication_raw_pdu_t; + +#define NFAPI_CQI_IND_MAX_PDU 100 +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_cqis; + nfapi_cqi_indication_pdu_t* cqi_pdu_list; + nfapi_cqi_indication_raw_pdu_t* cqi_raw_pdu_list; +} nfapi_cqi_indication_body_t; +#define NFAPI_CQI_INDICATION_BODY_TAG 0x202e + +typedef struct { + nfapi_tl_t tl; + uint16_t rnti; + uint8_t preamble; + uint16_t timing_advance; +} nfapi_preamble_pdu_rel8_t; +#define NFAPI_PREAMBLE_REL8_TAG 0x2032 + +typedef struct { + nfapi_tl_t tl; + uint16_t timing_advance_r9; +} nfapi_preamble_pdu_rel9_t; +#define NFAPI_PREAMBLE_REL9_TAG 0x2033 + +typedef struct { + nfapi_tl_t tl; + uint8_t rach_resource_type; +} nfapi_preamble_pdu_rel13_t; +#define NFAPI_PREAMBLE_REL13_TAG 0x2051 + +typedef struct { + uint16_t instance_length; + nfapi_preamble_pdu_rel8_t preamble_rel8; + nfapi_preamble_pdu_rel9_t preamble_rel9; + nfapi_preamble_pdu_rel13_t preamble_rel13; +} nfapi_preamble_pdu_t; + +#define NFAPI_PREAMBLE_MAX_PDU 100 +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_preambles; + nfapi_preamble_pdu_t* preamble_list; +} nfapi_rach_indication_body_t; +#define NFAPI_RACH_INDICATION_BODY_TAG 0x2031 + +#define NFAPI_NUM_RB_MAX 1000 +typedef struct { + nfapi_tl_t tl; + uint16_t doppler_estimation; + uint16_t timing_advance; + uint8_t number_of_resource_blocks; + uint8_t rb_start; + uint8_t snr[NFAPI_NUM_RB_MAX]; +} nfapi_srs_indication_fdd_rel8_t; +#define NFAPI_SRS_INDICATION_FDD_REL8_TAG 0x2035 + +typedef struct { + nfapi_tl_t tl; + uint16_t timing_advance_r9; +} nfapi_srs_indication_fdd_rel9_t; +#define NFAPI_SRS_INDICATION_FDD_REL9_TAG 0x2036 + +typedef struct { + nfapi_tl_t tl; + uint8_t uppts_symbol; +} nfapi_srs_indication_ttd_rel10_t; +#define NFAPI_SRS_INDICATION_TDD_REL10_TAG 0x2037 + +typedef struct { + nfapi_tl_t tl; + uint16_t ul_rtoa; +} nfapi_srs_indication_fdd_rel11_t; +#define NFAPI_SRS_INDICATION_FDD_REL11_TAG 0x2053 + + +typedef struct { + nfapi_tl_t tl; + uint8_t num_prb_per_subband; + uint8_t number_of_subbands; + uint8_t num_atennas; + struct { + uint8_t subband_index; + uint16_t channel[NFAPI_MAX_NUM_PHYSICAL_ANTENNAS]; + } subands[NFAPI_MAX_NUM_SUBBANDS]; +} nfapi_tdd_channel_measurement_t; +#define NFAPI_TDD_CHANNEL_MEASUREMENT_TAG 0x2054 + +typedef struct { + uint16_t instance_length; + nfapi_rx_ue_information rx_ue_information; + nfapi_srs_indication_fdd_rel8_t srs_indication_fdd_rel8; + nfapi_srs_indication_fdd_rel9_t srs_indication_fdd_rel9; + nfapi_srs_indication_ttd_rel10_t srs_indication_tdd_rel10; + nfapi_srs_indication_fdd_rel11_t srs_indication_fdd_rel11; + nfapi_tdd_channel_measurement_t tdd_channel_measurement; +} nfapi_srs_indication_pdu_t; + +#define NFAPI_SRS_IND_MAX_PDU 16 +typedef struct { + nfapi_tl_t tl; + uint8_t number_of_ues; + nfapi_srs_indication_pdu_t* srs_pdu_list; +} nfapi_srs_indication_body_t; +#define NFAPI_SRS_INDICATION_BODY_TAG 0x2034 + +typedef struct { + nfapi_tl_t tl; + uint16_t length; + uint16_t offset; + uint8_t ul_cqi; + uint16_t timing_advance; +} nfapi_rx_indication_rel8_t; +#define NFAPI_RX_INDICATION_REL8_TAG 0x2024 + +typedef struct { + nfapi_tl_t tl; + uint16_t timing_advance_r9; + } nfapi_rx_indication_rel9_t; +#define NFAPI_RX_INDICATION_REL9_TAG 0x2025 + +typedef struct { + nfapi_rx_ue_information rx_ue_information; + nfapi_rx_indication_rel8_t rx_indication_rel8; + nfapi_rx_indication_rel9_t rx_indication_rel9; + uint8_t* data; +} nfapi_rx_indication_pdu_t; + +#define NFAPI_RX_IND_MAX_PDU 100 +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_pdus; + nfapi_rx_indication_pdu_t* rx_pdu_list; +} nfapi_rx_indication_body_t; +#define NFAPI_RX_INDICATION_BODY_TAG 0x2023 + +typedef struct { + nfapi_tl_t tl; + uint8_t harq_tb1; +} nfapi_nb_harq_indication_fdd_rel13_t; +#define NFAPI_NB_HARQ_INDICATION_FDD_REL13_TAG 0x2064 + +typedef struct { + uint16_t instance_length; + nfapi_rx_ue_information rx_ue_information; + nfapi_nb_harq_indication_fdd_rel13_t nb_harq_indication_fdd_rel13; + nfapi_ul_cqi_information_t ul_cqi_information; +} nfapi_nb_harq_indication_pdu_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_harqs; + nfapi_nb_harq_indication_pdu_t* nb_harq_pdu_list; +} nfapi_nb_harq_indication_body_t; +#define NFAPI_NB_HARQ_INDICATION_BODY_TAG 0x2063 + +typedef struct { + nfapi_tl_t tl; + uint16_t rnti; + uint8_t initial_sc; + uint16_t timing_advance; + uint8_t nrach_ce_level; +} nfapi_nrach_indication_pdu_rel13_t; +#define NFAPI_NRACH_INDICATION_REL13_TAG 0x2066 + +typedef struct { + nfapi_nrach_indication_pdu_rel13_t nrach_indication_rel13; +} nfapi_nrach_indication_pdu_t; + +typedef struct { + nfapi_tl_t tl; + uint8_t number_of_initial_scs_detected; + nfapi_nrach_indication_pdu_t* nrach_pdu_list; +} nfapi_nrach_indication_body_t; +#define NFAPI_NRACH_INDICATION_BODY_TAG 0x2065 + +typedef struct { + nfapi_tl_t tl; + uint32_t handle; + uint32_t mp_cca; + uint32_t n_cca; + uint32_t offset; + uint32_t lte_txop_sf; + uint16_t txop_sfn_sf_end; + uint32_t lbt_mode; +} nfapi_lbt_pdsch_req_pdu_rel13_t; +#define NFAPI_LBT_PDSCH_REQ_PDU_REL13_TAG 0x2056 + +typedef struct { + nfapi_lbt_pdsch_req_pdu_rel13_t lbt_pdsch_req_pdu_rel13; +} nfapi_lbt_pdsch_req_pdu; + +typedef struct { + nfapi_tl_t tl; + uint32_t handle; + uint32_t offset; + uint16_t sfn_sf_end; + uint32_t lbt_mode; +} nfapi_lbt_drs_req_pdu_rel13_t; +#define NFAPI_LBT_DRS_REQ_PDU_REL13_TAG 0x2057 + +typedef struct { + nfapi_lbt_drs_req_pdu_rel13_t lbt_drs_req_pdu_rel13; +} nfapi_lbt_drs_req_pdu; + +typedef struct { + uint8_t pdu_type; + uint8_t pdu_size; + union { + nfapi_lbt_pdsch_req_pdu lbt_pdsch_req_pdu; + nfapi_lbt_drs_req_pdu lbt_drs_req_pdu; + }; +} nfapi_lbt_dl_config_request_pdu_t; + +#define NFAPI_LBT_DL_CONFIG_REQ_MAX_PDU 16 +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_pdus; + nfapi_lbt_dl_config_request_pdu_t* lbt_dl_config_req_pdu_list; +} nfapi_lbt_dl_config_request_body_t; +#define NFAPI_LBT_DL_CONFIG_REQUEST_BODY_TAG 0x2055 + + +typedef struct { + nfapi_tl_t tl; + uint32_t handle; + uint32_t result; + uint32_t lte_txop_symbols; + uint32_t initial_partial_sf; +} nfapi_lbt_pdsch_rsp_pdu_rel13_t; +#define NFAPI_LBT_PDSCH_RSP_PDU_REL13_TAG 0x2059 + +typedef struct { + nfapi_lbt_pdsch_rsp_pdu_rel13_t lbt_pdsch_rsp_pdu_rel13; +} nfapi_lbt_pdsch_rsp_pdu; + +typedef struct { + nfapi_tl_t tl; + uint32_t handle; + uint32_t result; +} nfapi_lbt_drs_rsp_pdu_rel13_t; +#define NFAPI_LBT_DRS_RSP_PDU_REL13_TAG 0x205A + +typedef struct { + nfapi_lbt_drs_rsp_pdu_rel13_t lbt_drs_rsp_pdu_rel13; +} nfapi_lbt_drs_rsp_pdu; + + +typedef struct { + uint8_t pdu_type; + uint8_t pdu_size; + union { + nfapi_lbt_pdsch_rsp_pdu lbt_pdsch_rsp_pdu; + nfapi_lbt_drs_rsp_pdu lbt_drs_rsp_pdu; + }; +} nfapi_lbt_dl_indication_pdu_t; + +#define NFAPI_LBT_IND_MAX_PDU 16 +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_pdus; + nfapi_lbt_dl_indication_pdu_t* lbt_indication_pdu_list; +} nfapi_lbt_dl_indication_body_t; +#define NFAPI_LBT_DL_INDICATION_BODY_TAG 0x2058 + +typedef struct { +} nfapi_error_indication_msg_invalid_state; + +typedef struct { +} nfapi_error_indication_msg_bch_missing; + +typedef struct { + uint16_t recieved_sfn_sf; + uint16_t expected_sfn_sf; +} nfapi_error_indication_sfn_out_of_sync; + +typedef struct { + uint8_t sub_error_code; + uint8_t direction; + uint16_t rnti; + uint8_t pdu_type; +} nfapi_error_indication_msg_pdu_err; + +typedef struct { + uint16_t recieved_sfn_sf; + uint16_t expected_sfn_sf; +} nfapi_error_indication_msg_invalid_sfn; + +typedef struct { + uint8_t sub_error_code; + uint8_t phich_lowest_ul_rb_index; +} nfapi_error_indication_msg_hi_err; + +typedef struct { + uint8_t sub_error_code; + uint16_t pdu_index; +} nfapi_error_indication_msg_tx_err; + +// +// P4 Message Structures +// + +typedef struct { + nfapi_tl_t tl; + uint8_t frequency_band_indicator; + uint16_t measurement_period; + uint8_t bandwidth; + uint32_t timeout; + uint8_t number_of_earfcns; + uint16_t earfcn[NFAPI_MAX_CARRIER_LIST]; +} nfapi_lte_rssi_request_t; + +#define NFAPI_LTE_RSSI_REQUEST_TAG 0x3000 + +#define NFAPI_P4_START_TAG NFAPI_LTE_RSSI_REQUEST_TAG + +typedef struct { + nfapi_tl_t tl; + uint8_t frequency_band_indicator; + uint16_t measurement_period; + uint32_t timeout; + uint8_t number_of_uarfcns; + uint16_t uarfcn[NFAPI_MAX_CARRIER_LIST]; +} nfapi_utran_rssi_request_t; + +#define NFAPI_UTRAN_RSSI_REQUEST_TAG 0x3001 + +typedef struct { + uint16_t arfcn; + uint8_t direction; +} nfapi_arfcn_t; + +typedef struct { + nfapi_tl_t tl; + uint8_t frequency_band_indicator; + uint16_t measurement_period; + uint32_t timeout; + uint8_t number_of_arfcns; + nfapi_arfcn_t arfcn[NFAPI_MAX_CARRIER_LIST]; +} nfapi_geran_rssi_request_t; + +#define NFAPI_GERAN_RSSI_REQUEST_TAG 0x3002 + + + +typedef struct { + uint16_t earfcn; + uint8_t number_of_ro_dl; + uint8_t ro_dl[NFAPI_MAX_RO_DL]; +} nfapi_earfcn_t; + +typedef struct { + nfapi_tl_t tl; + uint8_t frequency_band_indicator; + uint16_t measurement_period; + uint32_t timeout; + uint8_t number_of_earfcns; + nfapi_earfcn_t earfcn[NFAPI_MAX_CARRIER_LIST]; +} nfapi_nb_iot_rssi_request_t; + +#define NFAPI_NB_IOT_RSSI_REQUEST_TAG 0x3020 + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_rssi; + int16_t rssi[NFAPI_MAX_RSSI]; +} nfapi_rssi_indication_body_t; + +#define NFAPI_RSSI_INDICATION_TAG 0x3003 + +typedef struct { + nfapi_tl_t tl; + uint16_t earfcn; + uint8_t measurement_bandwidth; + uint8_t exhaustive_search; + uint32_t timeout; + uint8_t number_of_pci; + uint16_t pci[NFAPI_MAX_PCI_LIST]; +} nfapi_lte_cell_search_request_t; + +#define NFAPI_LTE_CELL_SEARCH_REQUEST_TAG 0x3004 + +typedef struct { + nfapi_tl_t tl; + uint16_t uarfcn; + uint8_t exhaustive_search; + uint32_t timeout; + uint8_t number_of_psc; + uint16_t psc[NFAPI_MAX_PSC_LIST]; +} nfapi_utran_cell_search_request_t; + +#define NFAPI_UTRAN_CELL_SEARCH_REQUEST_TAG 0x3005 + +typedef struct { + nfapi_tl_t tl; + uint32_t timeout; + uint8_t number_of_arfcn; + uint16_t arfcn[NFAPI_MAX_ARFCN_LIST]; +} nfapi_geran_cell_search_request_t; + +#define NFAPI_GERAN_CELL_SEARCH_REQUEST_TAG 0x3006 + +typedef struct { + nfapi_tl_t tl; + uint16_t earfcn; + uint8_t ro_dl; + uint8_t exhaustive_search; + uint32_t timeout; + uint8_t number_of_pci; + uint16_t pci[NFAPI_MAX_PCI_LIST]; +} nfapi_nb_iot_cell_search_request_t; + +#define NFAPI_NB_IOT_CELL_SEARCH_REQUEST_TAG 0x3021 + +typedef struct { + uint16_t pci; + uint8_t rsrp; + uint8_t rsrq; + int16_t frequency_offset; +} nfapi_lte_found_cell_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_lte_cells_found; + nfapi_lte_found_cell_t lte_found_cells[NFAPI_MAX_LTE_CELLS_FOUND]; +} nfapi_lte_cell_search_indication_t; + +#define NFAPI_LTE_CELL_SEARCH_INDICATION_TAG 0x3007 + +typedef struct { + uint16_t psc; + uint8_t rscp; + uint8_t ecno; + int16_t frequency_offset; +} nfapi_utran_found_cell_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_utran_cells_found; + nfapi_utran_found_cell_t utran_found_cells[NFAPI_MAX_UTRAN_CELLS_FOUND]; +} nfapi_utran_cell_search_indication_t; + +#define NFAPI_UTRAN_CELL_SEARCH_INDICATION_TAG 0x3008 + +typedef struct { + uint16_t arfcn; + uint8_t bsic; + uint8_t rxlev; + uint8_t rxqual; + int16_t frequency_offset; + uint32_t sfn_offset; +} nfapi_gsm_found_cell_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_gsm_cells_found; + nfapi_gsm_found_cell_t gsm_found_cells[NFAPI_MAX_GSM_CELLS_FOUND]; +} nfapi_geran_cell_search_indication_t; + +#define NFAPI_GERAN_CELL_SEARCH_INDICATION_TAG 0x3009 + +typedef struct { + uint16_t pci; + uint8_t rsrp; + uint8_t rsrq; + int16_t frequency_offset; +} nfapi_nb_iot_found_cell_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_nb_iot_cells_found; + nfapi_nb_iot_found_cell_t nb_iot_found_cells[NFAPI_MAX_NB_IOT_CELLS_FOUND]; +} nfapi_nb_iot_cell_search_indication_t; + +#define NFAPI_NB_IOT_CELL_SEARCH_INDICATION_TAG 0x3022 + +typedef nfapi_opaqaue_data_t nfapi_pnf_cell_search_state_t; + +#define NFAPI_PNF_CELL_SEARCH_STATE_TAG 0x300A + +typedef struct { + nfapi_tl_t tl; + uint16_t earfcn; + uint16_t pci; + uint32_t timeout; +} nfapi_lte_broadcast_detect_request_t; + +#define NFAPI_LTE_BROADCAST_DETECT_REQUEST_TAG 0x300B + +typedef struct { + nfapi_tl_t tl; + uint16_t uarfcn; + uint16_t psc; + uint32_t timeout; +} nfapi_utran_broadcast_detect_request_t; + +#define NFAPI_UTRAN_BROADCAST_DETECT_REQUEST_TAG 0x300C + +typedef struct { + nfapi_tl_t tl; + uint16_t earfcn; + uint8_t ro_dl; + uint16_t pci; + uint32_t timeout; +} nfapi_nb_iot_broadcast_detect_request_t; + +#define NFAPI_NB_IOT_BROADCAST_DETECT_REQUEST_TAG 0x3023 + +typedef struct { + nfapi_tl_t tl; + uint8_t number_of_tx_antenna; + uint16_t mib_length; + uint8_t mib[NFAPI_MAX_MIB_LENGTH]; + uint32_t sfn_offset; +} nfapi_lte_broadcast_detect_indication_t; + +#define NFAPI_LTE_BROADCAST_DETECT_INDICATION_TAG 0x300E + +typedef struct { + nfapi_tl_t tl; + uint16_t mib_length; + uint8_t mib[NFAPI_MAX_MIB_LENGTH]; + uint32_t sfn_offset; +} nfapi_utran_broadcast_detect_indication_t; + +#define NFAPI_UTRAN_BROADCAST_DETECT_INDICATION_TAG 0x300F + + +typedef struct { + nfapi_tl_t tl; + uint8_t number_of_tx_antenna; + uint16_t mib_length; + uint8_t mib[NFAPI_MAX_MIB_LENGTH]; + uint32_t sfn_offset; +} nfapi_nb_iot_broadcast_detect_indication_t; + +#define NFAPI_NB_IOT_BROADCAST_DETECT_INDICATION_TAG 0x3024 + +#define NFAPI_PNF_CELL_BROADCAST_STATE_TAG 0x3010 + +typedef struct { + nfapi_tl_t tl; + uint16_t earfcn; + uint16_t pci; + uint16_t downlink_channel_bandwidth; + uint8_t phich_configuration; + uint8_t number_of_tx_antenna; + uint8_t retry_count; + uint32_t timeout; +} nfapi_lte_system_information_schedule_request_t; + +#define NFAPI_LTE_SYSTEM_INFORMATION_SCHEDULE_REQUEST_TAG 0x3011 + + +typedef struct { + nfapi_tl_t tl; + uint16_t earfcn; + uint8_t ro_dl; + uint16_t pci; + uint8_t scheduling_info_sib1_nb; + uint32_t timeout; +} nfapi_nb_iot_system_information_schedule_request_t; + +#define NFAPI_NB_IOT_SYSTEM_INFORMATION_SCHEDULE_REQUEST_TAG 0x3025 + +typedef nfapi_opaqaue_data_t nfapi_pnf_cell_broadcast_state_t; + +typedef struct { + uint8_t si_periodicity; + uint8_t si_index; +} nfapi_lte_system_information_si_periodicity_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t earfcn; + uint16_t pci; + uint16_t downlink_channel_bandwidth; + uint8_t phich_configuration; + uint8_t number_of_tx_antenna; + uint8_t number_of_si_periodicity; + nfapi_lte_system_information_si_periodicity_t si_periodicity[NFAPI_MAX_SI_PERIODICITY]; + uint8_t si_window_length; + uint32_t timeout; +} nfapi_lte_system_information_request_t; + +#define NFAPI_LTE_SYSTEM_INFORMATION_REQUEST_TAG 0x3014 + +typedef struct { + nfapi_tl_t tl; + uint16_t uarfcn; + uint16_t psc; + uint32_t timeout; +} nfapi_utran_system_information_request_t; + +#define NFAPI_UTRAN_SYSTEM_INFORMATION_REQUEST_TAG 0x3015 + +typedef struct { + nfapi_tl_t tl; + uint16_t arfcn; + uint8_t bsic; + uint32_t timeout; +} nfapi_geran_system_information_request_t; + +#define NFAPI_GERAN_SYSTEM_INFORMATION_REQUEST_TAG 0x3016 + +typedef struct { + uint8_t si_periodicity; + uint8_t si_repetition_pattern; + uint8_t si_tb_size; + uint8_t number_of_si_index; + uint8_t si_index[NFAPI_MAX_SI_INDEX]; +} nfapi_nb_iot_system_information_si_periodicity_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t earfcn; + uint8_t ro_dl; + uint16_t pci; + uint8_t number_of_si_periodicity; + nfapi_nb_iot_system_information_si_periodicity_t si_periodicity[NFAPI_MAX_SI_PERIODICITY]; + uint8_t si_window_length; + uint32_t timeout; +} nfapi_nb_iot_system_information_request_t; + +#define NFAPI_NB_IOT_SYSTEM_INFORMATION_REQUEST_TAG 0x3027 + +typedef struct { + nfapi_tl_t tl; + uint8_t sib_type; + uint16_t sib_length; + uint8_t sib[NFAPI_MAX_SIB_LENGTH]; +} nfapi_lte_system_information_indication_t; + +#define NFAPI_LTE_SYSTEM_INFORMATION_INDICATION_TAG 0x3018 + +typedef struct { + nfapi_tl_t tl; + uint16_t sib_length; + uint8_t sib[NFAPI_MAX_SIB_LENGTH]; +} nfapi_utran_system_information_indication_t; + +#define NFAPI_UTRAN_SYSTEM_INFORMATION_INDICATION_TAG 0x3019 + +typedef struct { + nfapi_tl_t tl; + uint16_t si_length; + uint8_t si[NFAPI_MAX_SI_LENGTH]; +} nfapi_geran_system_information_indication_t; + +#define NFAPI_GERAN_SYSTEM_INFORMATION_INDICATION_TAG 0x301a + +typedef struct { + nfapi_tl_t tl; + uint8_t sib_type; + uint16_t sib_length; + uint8_t sib[NFAPI_MAX_SIB_LENGTH]; +} nfapi_nb_iot_system_information_indication_t; + +#define NFAPI_NB_IOT_SYSTEM_INFORMATION_INDICATION_TAG 0x3026 + + +// +// Top level NFAP messages +// + +// +// P7 +// + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_dl_config_request_body_t dl_config_request_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_dl_config_request_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_ul_config_request_body_t ul_config_request_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_ul_config_request_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_hi_dci0_request_body_t hi_dci0_request_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_hi_dci0_request_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_tx_request_body_t tx_request_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_tx_request_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; +} nfapi_subframe_indication_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_harq_indication_body_t harq_indication_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_harq_indication_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_crc_indication_body_t crc_indication_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_crc_indication_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_sr_indication_body_t sr_indication_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_sr_indication_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_cqi_indication_body_t cqi_indication_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_cqi_indication_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_rach_indication_body_t rach_indication_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_rach_indication_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_srs_indication_body_t srs_indication_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_srs_indication_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_rx_indication_body_t rx_indication_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_rx_indication_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_nb_harq_indication_body_t nb_harq_indication_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_nb_harq_indication_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_nrach_indication_body_t nrach_indication_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_nrach_indication_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_lbt_dl_config_request_body_t lbt_dl_config_request_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_lbt_dl_config_request_t; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t sfn_sf; + nfapi_lbt_dl_indication_body_t lbt_dl_indication_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_lbt_dl_indication_t; + + +typedef struct { + nfapi_p7_message_header_t header; + uint8_t message_id; + uint8_t error_code; + union { + nfapi_error_indication_msg_invalid_state msg_invalid_state; + nfapi_error_indication_msg_bch_missing msg_bch_missing; + nfapi_error_indication_sfn_out_of_sync sfn_out_of_sync; + nfapi_error_indication_msg_pdu_err msg_pdu_err; + nfapi_error_indication_msg_invalid_sfn msg_invalid_sfn; + nfapi_error_indication_msg_hi_err msg_hi_err; + nfapi_error_indication_msg_tx_err msg_tx_err; + }; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_error_indication_t; + +// +// P4 Messages +// + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint8_t rat_type; + union { + nfapi_lte_rssi_request_t lte_rssi_request; + nfapi_utran_rssi_request_t utran_rssi_request; + nfapi_geran_rssi_request_t geran_rssi_request; + nfapi_nb_iot_rssi_request_t nb_iot_rssi_request; + }; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_rssi_request_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_rssi_response_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_rssi_indication_body_t rssi_indication_body; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_rssi_indication_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint8_t rat_type; + union { + nfapi_lte_cell_search_request_t lte_cell_search_request; + nfapi_utran_cell_search_request_t utran_cell_search_request; + nfapi_geran_cell_search_request_t geran_cell_search_request; + nfapi_nb_iot_cell_search_request_t nb_iot_cell_search_request; + }; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_cell_search_request_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_cell_search_response_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_lte_cell_search_indication_t lte_cell_search_indication; + nfapi_utran_cell_search_indication_t utran_cell_search_indication; + nfapi_geran_cell_search_indication_t geran_cell_search_indication; + nfapi_pnf_cell_search_state_t pnf_cell_search_state; + nfapi_nb_iot_cell_search_indication_t nb_iot_cell_search_indication; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_cell_search_indication_t; + + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint8_t rat_type; + union { + nfapi_lte_broadcast_detect_request_t lte_broadcast_detect_request; + nfapi_utran_broadcast_detect_request_t utran_broadcast_detect_request; + nfapi_nb_iot_broadcast_detect_request_t nb_iot_broadcast_detect_request; + }; + nfapi_pnf_cell_search_state_t pnf_cell_search_state; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_broadcast_detect_request_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_broadcast_detect_response_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_lte_broadcast_detect_indication_t lte_broadcast_detect_indication; + nfapi_utran_broadcast_detect_indication_t utran_broadcast_detect_indication; + nfapi_nb_iot_broadcast_detect_indication_t nb_iot_broadcast_detect_indication; + nfapi_pnf_cell_broadcast_state_t pnf_cell_broadcast_state; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_broadcast_detect_indication_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint8_t rat_type; + union { + nfapi_lte_system_information_schedule_request_t lte_system_information_schedule_request; + nfapi_nb_iot_system_information_schedule_request_t nb_iot_system_information_schedule_request; + }; + nfapi_pnf_cell_broadcast_state_t pnf_cell_broadcast_state; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_system_information_schedule_request_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_system_information_schedule_response_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_lte_system_information_indication_t lte_system_information_indication; + nfapi_nb_iot_system_information_indication_t nb_iot_system_information_indication; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_system_information_schedule_indication_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint8_t rat_type; + union { + nfapi_lte_system_information_request_t lte_system_information_request; + nfapi_utran_system_information_request_t utran_system_information_request; + nfapi_geran_system_information_request_t geran_system_information_request; + nfapi_nb_iot_system_information_request_t nb_iot_system_information_request; + }; + nfapi_pnf_cell_broadcast_state_t pnf_cell_broadcast_state; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_system_information_request_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_system_information_response_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_lte_system_information_indication_t lte_system_information_indication; + nfapi_utran_system_information_indication_t utran_system_information_indication; + nfapi_geran_system_information_indication_t geran_system_information_indication; + nfapi_nb_iot_system_information_indication_t nb_iot_system_information_indication; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_system_information_indication_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_nmm_stop_request_t; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint32_t error_code; + nfapi_vendor_extension_tlv_t vendor_extension; +} nfapi_nmm_stop_response_t; + +// +// Configuration options for the encode decode functions +// + +/*! Configuration options for the p7 pack unpack functions + * + */ +typedef struct nfapi_p7_codec_config { + + /*! Optional call back to allow the user to define the memory allocator. + * \param size The size of the memory to allocate + * \return a pointer to a valid memory block or 0 if it has failed. + * + * If not set the nfapi unpack functions will use malloc + */ + void* (*allocate)(size_t size); + + /*! Optional call back to allow the user to define the memory deallocator. + * \param ptr A poiner to a memory block allocated by the allocate callback + * + * If not set the client should use free + */ + void (*deallocate)(void* ptr); + + /*! Optional call back function to handle unpacking vendor extension tlv. + * \param tl A pointer to a decoded tag length structure + * \param ppReadPackedMsg A handle to the read buffer. + * \param end The end of the read buffer + * \param ve A handle to a vendor extention structure that the call back should allocate if the structure can be decoded + * \param config A pointer to the p7 codec configuration + * \return return 0 if packed successfully, -1 if failed. + * + * If not set the tlv will be skipped + * + * Client should use the help methods in nfapi.h to decode the vendor extention. + * + * \todo Add code example + */ + int (*unpack_vendor_extension_tlv)(nfapi_tl_t* tl, uint8_t **ppReadPackedMsg, uint8_t *end, void** ve, struct nfapi_p7_codec_config* config); + + /*! Optional call back function to handle packing vendor extension tlv. + * \param ve A pointer to a vendor extention structure. + * \param ppWritePackedMsg A handle to the write buffer + * \param end The end of the write buffer. The callee should make sure not to write beyond the end + * \param config A pointer to the p7 codec configuration + * \return return 0 if packed successfully, -1 if failed. + * + * If not set the the tlv will be skipped + * + * Client should use the help methods in nfapi.h to encode the vendor extention + * + * \todo Add code example + */ + int (*pack_vendor_extension_tlv)(void* ve, uint8_t **ppWritePackedMsg, uint8_t *end, struct nfapi_p7_codec_config* config); + + /*! Optional call back function to handle unpacking vendor extension messages. + * \param header A pointer to a decode P7 message header for the vendor extention message + * \param ppReadPackedMsg A handle to the encoded data buffer + * \param end A pointer to the end of the encoded data buffer + * \param config A pointer to the p7 codec configuration + * \return 0 if unpacked successfully, -1 if failed + * + * If not set the message will be ignored + * + * If the message if is unknown the function should return -1 + */ + int (*unpack_p7_vendor_extension)(nfapi_p7_message_header_t* header, uint8_t **ppReadPackedMsg, uint8_t *end, struct nfapi_p7_codec_config* config); + + /*! Optional call back function to handle packing vendor extension messages. + * \param header A poiner to a P7 message structure for the venfor extention message + * \param ppWritePackedmsg A handle to the buffer to write the encoded message into + * \param end A pointer to the end of the buffer + * \param cofig A pointer to the p7 codec configuration + * \return 0 if packed successfully, -1 if failed + * + * If not set the the message will be ingored + * + * If the message if is unknown the function should return -1 + */ + int (*pack_p7_vendor_extension)(nfapi_p7_message_header_t* header, uint8_t **ppWritePackedmsg, uint8_t *end, struct nfapi_p7_codec_config* config); + + /*! Optional user data that will be passed back with callbacks + */ + void* user_data; + +} nfapi_p7_codec_config_t; + +/*! Configuration options for the p4 & p5 pack unpack functions + * + */ +typedef struct nfapi_p4_p5_codec_config { + + /*! Optional call back to allow the user to define the memory allocator. + * \param size The size of the memory to allocate + * \return a pointer to a valid memory block or 0 if it has failed. + * + * If not set the nfapi unpack functions will use malloc + */ + void* (*allocate)(size_t size); + + /*! Optional call back to allow the user to define the memory deallocator. + * \param ptr A poiner to a memory block allocated by the allocate callback + * + * If not set free will be used + */ + void (*deallocate)(void* ptr); + + /*! Optional call back function to handle unpacking vendor extension tlv. + * \param tl A pointer to a decoded tag length structure + * \param ppReadPackedMsg A handle to the data buffer to decode + * \param end A pointer to the end of the buffer + * \param ve A handle to a vendor extention structure that will be allocated by this callback + * \param config A pointer to the P4/P5 codec configuration + * \return 0 if unpacked successfully, -1 if failed + * + * If not set the tlv will be skipped + */ + int (*unpack_vendor_extension_tlv)(nfapi_tl_t* tl, uint8_t **ppReadPackedMsg, uint8_t *end, void** ve, struct nfapi_p4_p5_codec_config* config); + + /*! Optional call back function to handle packing vendor extension tlv. + * \param ve + * \param ppWritePackedMsg A handle to the data buffer pack the tlv into + * \param end A pointer to the end of the buffer + * \param config A pointer to the P4/P5 codec configuration + * \return 0 if packed successfully, -1 if failed + * + * If not set the the tlv will be skipped + */ + int (*pack_vendor_extension_tlv)(void* ve, uint8_t **ppWritePackedMsg, uint8_t *end, struct nfapi_p4_p5_codec_config* config); + + /*! Optional call back function to handle unpacking vendor extension messages. + * \param header A pointer to a decode P4/P5 message header + * \param ppReadPackgedMsg A handle to the data buffer to decode + * \param end A pointer to the end of the buffer + * \param config A pointer to the P4/P5 codec configuration + * \return 0 if packed successfully, -1 if failed + * + * If not set the message will be ignored + */ + int (*unpack_p4_p5_vendor_extension)(nfapi_p4_p5_message_header_t* header, uint8_t **ppReadPackedMsg, uint8_t *end, struct nfapi_p4_p5_codec_config* config); + + /*! Optional call back function to handle packing vendor extension messages. + * \param header A pointer to the P4/P5 message header to be encoded + * \param ppWritePackedMsg A handle to the data buffer pack the message into + * \param end A pointer to the end of the buffer + * \param config A pointer to the P4/P5 codec configuration + * \return 0 if packed successfully, -1 if failed + * + * If not set the the message will be ingored + */ + int (*pack_p4_p5_vendor_extension)(nfapi_p4_p5_message_header_t* header, uint8_t **ppwritepackedmsg, uint8_t *end, struct nfapi_p4_p5_codec_config* config); + + /*! Optional user data that will be passed back with callbacks + */ + void* user_data; + +} nfapi_p4_p5_codec_config_t; + +// +// Functions +// + +/*! \brief Encodes an NFAPI P4 message to a buffer + * \param pMessageBuf A pointer to a nfapi p4 message structure + * \param messageBufLen The size of the p4 message structure + * \param pPackedBuf A pointer to the buffer that the p4 message will be packed into + * \param packedBufLen The size of the buffer + * \param config A pointer to the nfapi configuration structure + * \return 0 means success, -1 means failure. + * + * The function will encode a nFAPI P4 message structure pointed to be pMessageBuf into a byte stream pointed to by pPackedBuf. + * + */ +int nfapi_p4_message_pack(void *pMessageBuf, uint32_t messageBufLen, void *pPackedBuf, uint32_t packedBufLen, nfapi_p4_p5_codec_config_t* config); + +/*! \brief Decodes a NFAPI P4 message header + * \param pMessageBuf A pointer to an encoded P4 message header + * \param messageBufLen The size of the encoded P4 message header + * \param pUnpackedBuf A pointer to the nfapi_message_header + * \param unpackedBufLen The size of nfapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return 0 means success, -1 means failure. + * + * The function will decode a byte stream pointed to by pMessageBuf into a nfapi_p4_p5_message_header structure pointer to by pUnpackedBuf + */ +int nfapi_p4_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t* config); + +/*! \brief Decodes a NFAPI P4 message + * \param pMessageBuf A pointer to an encoded P4 message + * \param messageBufLen The size of the encoded P4 message + * \param pUnpackedBuf A pointer to the nfapi_message_header + * \param unpackedBufLen The size of nfapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return 0 means success, -1 means failure. + * + * The function will decode a byte stream pointed to by pMessageBuf into a nfapi p4 message structure pointer to by pUnpackedBuf + */ +int nfapi_p4_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t* config); + +/*! \brief Encodes an NFAPI P5 message to a buffer + * \param pMessageBuf A pointer to a nfapi p5 message structure + * \param messageBufLen The size of the p5 message structure + * \param pPackedBuf A pointer to the buffer that the p5 message will be packed into + * \param packedBufLen The size of the buffer + * \param config A pointer to the nfapi configuration structure + * \return 0 means success, -1 means failure. + * + * The function will encode a nFAPI P5 message structure pointed to be pMessageBuf into a byte stream pointed to by pPackedBuf. + * + */ +int nfapi_p5_message_pack(void *pMessageBuf, uint32_t messageBufLen, void *pPackedBuf, uint32_t packedBufLen, nfapi_p4_p5_codec_config_t* config); + +/*! \brief Decodes an NFAPI P5 message header + * \param pMessageBuf A pointer to an encoded P5 message header + * \param messageBufLen The size of the encoded P5 message header + * \param pUnpackedBuf A pointer to the nfapi_message_header + * \param unpackedBufLen The size of nfapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return 0 means success, -1 means failure. + * + * The function will decode a byte stream pointed to by pMessageBuf into a nfapi_p4_p5_message_header structure pointer to by pUnpackedBuf + */ +int nfapi_p5_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t* config); + +/*! \brief Decodes a NFAPI P5 message + * \param pMessageBuf A pointer to an encoded P5 message + * \param messageBufLen The size of the encoded P5 message + * \param pUnpackedBuf A pointer to the nfapi_message_header + * \param unpackedBufLen The size of nfapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return 0 means success, -1 means failure. + * + * The function will decode a byte stream pointed to by pMessageBuf into a nfapi p5 message structure pointer to by pUnpackedBuf + */ +int nfapi_p5_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t* config); + +/*! \brief Encodes an NFAPI P7 message to a buffer + * \param pMessageBuf A pointer to a nfapi p7 message structure + * \param pPackedBuf A pointer to the buffer that the p7 message will be packed into + * \param packedBufLen The size of the buffer + * \param config A pointer to the nfapi configuration structure + * \return 0 means success, -1 means failure. + * + * The function will encode a nFAPI P7 message structure pointed to be pMessageBuf into a byte stream pointed to by pPackedBuf. + * + */ +int nfapi_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen, nfapi_p7_codec_config_t* config); + +/*! \brief Decodes an NFAPI P7 message header + * \param pMessageBuf A pointer to an encoded P7 message header + * \param messageBufLen The size of the encoded P7 message header + * \param pUnpackedBuf A pointer to the nfapi_message_header + * \param unpackedBufLen The size of nfapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return 0 means success, -1 means failure. + * + * The function will decode a byte stream pointed to by pMessageBuf into a nfapi_p7_message_header structure pointer to by pUnpackedBuf + + */ +int nfapi_p7_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p7_codec_config_t* config); + +/*! \brief Decodes a NFAPI P7 message + * \param pMessageBuf A pointer to an encoded P7 message + * \param messageBufLen The size of the encoded P7 message + * \param pUnpackedBuf A pointer to the nfapi_message_header + * \param unpackedBufLen The size of nfapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return 0 means success, -1 means failure. + * + * The function will decode a byte stream pointed to by pMessageBuf into a nfapi p7 message structure pointer to by pUnpackedBuf + */ +int nfapi_p7_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p7_codec_config_t* config); + +/*! \brief Calculates the checksum of a message + * + * \param buffer Pointer to the packed message + * \param len The length of the message + * \return The checksum. If there is an error the function with return -1 + */ +uint32_t nfapi_p7_calculate_checksum(uint8_t* buffer, uint32_t len); + +/*! \brief Calculates & updates the checksum in the message + * + * \param buffer Pointer to the packed message + * \param len The length of the message + * \return 0 means success, -1 means failure. + */ +int nfapi_p7_update_checksum(uint8_t* buffer, uint32_t len); + +/*! \brief Updates the transmition time stamp in the p7 message header + * + * \param buffer Pointer to the packed message + * \param timestamp The time stamp value + * \return 0 means success, -1 means failure. + */ +int nfapi_p7_update_transmit_timestamp(uint8_t* buffer, uint32_t timestamp); + +#endif /* _NFAPI_INTERFACE_H_ */ diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi.c b/nfapi/open-nFAPI/nfapi/src/nfapi.c new file mode 100644 index 0000000000..3f017bc9a4 --- /dev/null +++ b/nfapi/open-nFAPI/nfapi/src/nfapi.c @@ -0,0 +1,860 @@ +/* + * Copyright (c) 2001-2016, Cisco Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * Neither the name of the Cisco Systems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +// Fundamental routines + +uint8_t push8(uint8_t in, uint8_t **out, uint8_t *end) +{ + uint8_t *pOut = *out; + + if((end - pOut) >= 1) + { + pOut[0] = in; + + (*out)+=1; + + return 1; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } + +} + +uint8_t pushs8(int8_t in, uint8_t **out, uint8_t *end) +{ + uint8_t *pOut = *out; + + if((end - pOut) >= 1) + { + pOut[0] = in; + + (*out)+=1; + + return 1; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint8_t push16(uint16_t in, uint8_t **out, uint8_t *end) +{ + uint8_t *pOut = *out; + + if((end - pOut) >= 2) + { + pOut[0] = (in & 0xFF00) >> 8; + pOut[1] = (in & 0xFF); + + (*out)+=2; + + return 2; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint8_t pushs16(int16_t in, uint8_t **out, uint8_t *end) +{ + uint8_t *pOut = *out; + + if((end - pOut) >= 2) + { + pOut[0] = (in & 0xFF00) >> 8; + pOut[1] = (in & 0xFF); + + (*out)+=2; + + return 2; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint8_t push32(uint32_t in, uint8_t **out, uint8_t *end) +{ + uint8_t *pOut = *out; + if((end - pOut) >= 4) + { + pOut[0] = (in & 0xFF000000) >> 24; + pOut[1] = (in & 0xFF0000) >> 16; + pOut[2] = (in & 0xFF00) >> 8; + pOut[3] = (in & 0xFF); + + (*out)+=4; + + return 4; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint8_t pushs32(int32_t in, uint8_t **out, uint8_t *end) +{ + uint8_t *pOut = *out; + + if((end - pOut) >= 4) + { + pOut[0] = (in & 0xFF000000) >> 24; + pOut[1] = (in & 0xFF0000) >> 16; + pOut[2] = (in & 0xFF00) >> 8; + pOut[3] = (in & 0xFF); + + (*out)+=4; + + return 4; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint8_t pull8(uint8_t **in, uint8_t *out, uint8_t *end) +{ + uint8_t *pIn = *in; + + if((end - pIn) >= 1 ) + { + *out = *pIn; + + (*in)+=1; + + return 1; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint8_t pulls8(uint8_t **in, int8_t *out, uint8_t *end) +{ + uint8_t *pIn = *in; + + if((end - pIn) >= 1 ) + { + *out = *pIn; + + (*in)+=1; + + return 1; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint8_t pull16(uint8_t **in, uint16_t *out, uint8_t *end) +{ + uint8_t *pIn = *in; + + if((end - pIn) >=2 ) + { + *out = ((pIn[0]) << 8) | pIn[1]; + (*in)+=2; + + return 2; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint8_t pulls16(uint8_t **in, int16_t *out, uint8_t *end) +{ + uint8_t *pIn = *in; + + if((end - pIn) >=2 ) + { + *out = ((pIn[0]) << 8) | pIn[1]; + + (*in)+=2; + + return 2; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint8_t pull32(uint8_t **in, uint32_t *out, uint8_t *end) +{ + uint8_t *pIn = *in; + + if((end - pIn) >=4 ) + { + *out = (pIn[0] << 24) | (pIn[1] << 16) | (pIn[2] << 8) | pIn[3]; + + (*in)+=4; + + return 4; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint8_t pulls32(uint8_t **in, int32_t *out, uint8_t *end) +{ + uint8_t *pIn = *in; + + if((end - pIn) >=4 ) + { + *out = (pIn[0] << 24) | (pIn[1] << 16) | (pIn[2] << 8) | pIn[3]; + + (*in)+=4; + + return 4; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +/* +inline void pusharray16(uint8_t **, uint16_t, uint32_t len) +{ +} +*/ + +uint32_t pullarray16(uint8_t **in, uint16_t out[], uint32_t max_len, uint32_t len, uint8_t *end) +{ + if(len == 0) + return 1; + + if(len > max_len) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s exceed array size (%d > %d)\n", __FUNCTION__, len, max_len); + return 0; + } + + if((end - (*in)) >= sizeof(uint16_t) * len) + { + uint32_t idx; + for(idx = 0; idx < len; ++idx) + { + if(!pull16(in, &out[idx], end)) + return 0; + } + + return sizeof(uint16_t) * len; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint32_t pullarrays16(uint8_t **in, int16_t out[], uint32_t max_len, uint32_t len, uint8_t *end) +{ + if(len == 0) + return 1; + + if(len > max_len) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s exceed array size (%d > %d)\n", __FUNCTION__, len, max_len); + return 0; + } + + if((end - (*in)) >= sizeof(uint16_t) * len) + { + uint32_t idx; + for(idx = 0; idx < len; ++idx) + { + if(!pulls16(in, &out[idx], end)) + return 0; + } + + return sizeof(uint16_t) * len; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} +uint32_t pusharray16(uint16_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end) +{ + if(len == 0) + return 1; + + if(len > max_len) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s exceed array size (%d > %d)\n", __FUNCTION__, len, max_len); + return 0; + } + + if((end - (*out)) >= sizeof(uint16_t) * len) + { + uint32_t idx; + for(idx = 0; idx < len; ++idx) + { + if(!push16(in[idx], out, end)) + return 0; + } + return sizeof(uint16_t) * len; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} +uint32_t pusharrays16(int16_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end) +{ + if(len == 0) + return 1; + + if(len > max_len) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s exceed array size (%d > %d)\n", __FUNCTION__, len, max_len); + return 0; + } + + if((end - (*out)) >= sizeof(uint16_t) * len) + { + uint32_t idx; + for(idx = 0; idx < len; ++idx) + { + pushs16(in[idx], out, end); + } + return sizeof(uint16_t) * len; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint32_t pullarray8(uint8_t **in, uint8_t out[], uint32_t max_len, uint32_t len, uint8_t *end) +{ + if(len == 0) + return 1; + + if(len > max_len) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s exceed array size (%d > %d)\n", __FUNCTION__, len, max_len); + return 0; + } + + if((end - out) >= sizeof(uint8_t) * len) + { + memcpy(out, (*in), len); + (*in)+=len; + + return sizeof(uint8_t) * len; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint32_t pusharray8(uint8_t in[], uint32_t max_len, uint32_t len, uint8_t **out, uint8_t *end) +{ + if(len == 0) + return 1; + + if(len > max_len) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s exceed array size (%d > %d)\n", __FUNCTION__, len, max_len); + return 0; + } + + if((end - (*out)) >= sizeof(uint8_t) * len) + { + memcpy((*out), in, len); + (*out)+=len; + + return sizeof(uint8_t) * len; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + return 0; + } +} + +uint8_t packarray(void* array, uint16_t array_element_size, uint16_t max_count, uint16_t count, uint8_t **ppwritepackedmsg, uint8_t *end, pack_array_elem_fn fn) +{ + if(count > max_count) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s exceed array size (%d > %d)\n", __FUNCTION__, count, max_count); + return 0; + } + + uint16_t i = 0; + for(i = 0; i < count; ++i) + { + if((fn)(array, ppwritepackedmsg, end) == 0) + return 0; + + array += array_element_size; + } + + return 1; +} + +uint8_t unpackarray(uint8_t **ppReadPackedMsg, void* array, uint16_t array_element_size, uint16_t max_count, uint16_t count, uint8_t *end, unpack_array_elem_fn fn) +{ + if(count > max_count) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s exceed array size (%d > %d)\n", __FUNCTION__, count, max_count); + return 0; + } + + uint16_t i = 0; + for(i = 0; i < count; ++i) + { + if((fn)(array, ppReadPackedMsg, end) == 0) + return 0; + + array += array_element_size; + } + + return 1; +} + + +uint32_t pack_vendor_extension_tlv(nfapi_tl_t* ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + if(ve != 0 && config != 0) + { + if(config->pack_vendor_extension_tlv) + { + + uint8_t* pStartOfTlv = *ppWritePackedMsg; + if(pack_tl(ve, ppWritePackedMsg, end) == 0) + return 0; + + uint8_t* pStartOfValue = *ppWritePackedMsg; + if((config->pack_vendor_extension_tlv)(ve, ppWritePackedMsg, end, config) == 0) + return 0; + + ve->length = (*ppWritePackedMsg) - pStartOfValue; + + pack_tl(ve, &pStartOfTlv, end); + + return 1; + + } + } + return 1; +} + +uint32_t unpack_vendor_extension_tlv(nfapi_tl_t* tl, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config, nfapi_tl_t** ve_tlv) +{ + if(ve_tlv != 0 && config != 0) + { + if(config->unpack_vendor_extension_tlv) + { + return (config->unpack_vendor_extension_tlv)(tl, ppReadPackedMsg, end, (void**)ve_tlv, config); + } + } + return 1; +} + +uint32_t pack_p7_vendor_extension_tlv(nfapi_tl_t *ve, uint8_t **ppWritePackedMsg, uint8_t *end ,nfapi_p7_codec_config_t* config) +{ + if(ve != 0 && config != 0) + { + if(config->pack_vendor_extension_tlv) + { + uint8_t* pStartOfTlv = *ppWritePackedMsg; + if(pack_tl(ve, ppWritePackedMsg, end) == 0) + return 0; + + uint8_t* pStartOfValue = *ppWritePackedMsg; + if((config->pack_vendor_extension_tlv)(ve, ppWritePackedMsg, end, config) == 0) + return 0; + + ve->length = (*ppWritePackedMsg) - pStartOfValue; + + pack_tl(ve, &pStartOfTlv, end); + + return 1; + + } + } + return 1; +} + +int unpack_p7_vendor_extension_tlv(nfapi_tl_t* tl, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config, nfapi_tl_t** ve_tlv) +{ + if(ve_tlv != 0 && config != 0) + { + if(config->unpack_vendor_extension_tlv) + { + return (config->unpack_vendor_extension_tlv)(tl, ppReadPackedMsg, end, (void**)ve_tlv, config); + } + } + return 1; +} + + +uint8_t pack_tl(nfapi_tl_t *tl, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + return (push16(tl->tag, ppWritePackedMsg, end) && + push16(tl->length, ppWritePackedMsg, end)); +} + +uint8_t unpack_tl(uint8_t **ppReadPackedMsg, nfapi_tl_t *tl, uint8_t *end) +{ + return (pull16(ppReadPackedMsg, &tl->tag, end) && + pull16(ppReadPackedMsg, &tl->length, end)); +} + +int unpack_tlv_list(unpack_tlv_t unpack_fns[], uint16_t size, uint8_t **ppReadPackedMsg, uint8_t* end, nfapi_p4_p5_codec_config_t* config, nfapi_tl_t** ve) +{ + nfapi_tl_t generic_tl; + uint8_t numBadTags = 0; + uint16_t idx = 0; + + while ((uint8_t*)(*ppReadPackedMsg) < end) + { + // unpack the tl and process the values accordingly + if(unpack_tl(ppReadPackedMsg, &generic_tl, end) == 0) + return 0; + + uint8_t tagMatch = 0; + + uint8_t* pStartOfValue = *ppReadPackedMsg; + + for(idx = 0; idx < size; ++idx) + { + if(unpack_fns[idx].tag == generic_tl.tag) + { + tagMatch = 1; + nfapi_tl_t* tl = (nfapi_tl_t*)(unpack_fns[idx].tlv); + tl->tag = generic_tl.tag; + tl->length = generic_tl.length; + + int result = (*unpack_fns[idx].unpack_func)(tl, ppReadPackedMsg, end); + + if(result == 0) + { + return 0; + } + + // check if the length was right; + if(tl->length != (*ppReadPackedMsg - pStartOfValue)) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Warning tlv tag 0x%x length %d not equal to unpack %d\n", tl->tag, tl->length, (*ppReadPackedMsg - pStartOfValue)); + } + } + } + + if(tagMatch == 0) + { + + if(generic_tl.tag >= NFAPI_VENDOR_EXTENSION_MIN_TAG_VALUE && + generic_tl.tag <= NFAPI_VENDOR_EXTENSION_MAX_TAG_VALUE) + { + int result = unpack_vendor_extension_tlv(&generic_tl, ppReadPackedMsg, end, config, ve); + if(result == 0) + { + // got tot the end. + return 0; + } + else if(result < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unknown VE TAG value: 0x%04x\n", generic_tl.tag); + + if (++numBadTags > MAX_BAD_TAG) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Supplied message has had too many bad tags\n"); + return 0; + } + + if((end - *ppReadPackedMsg) >= generic_tl.length) + { + // Advance past the unknown TLV + (*ppReadPackedMsg) += generic_tl.length; + } + else + { + // go to the end + return 0; + } + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unknown TAG value: 0x%04x\n", generic_tl.tag); + + if (++numBadTags > MAX_BAD_TAG) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Supplied message has had too many bad tags\n"); + return 0; + } + + if((end - *ppReadPackedMsg) >= generic_tl.length) + { + // Advance past the unknown TLV + (*ppReadPackedMsg) += generic_tl.length; + } + else + { + // go to the end + return 0; + } + } + + } + } + + return 1; +} +int unpack_p7_tlv_list(unpack_p7_tlv_t unpack_fns[], uint16_t size, uint8_t **ppReadPackedMsg, uint8_t* end, nfapi_p7_codec_config_t* config, nfapi_tl_t** ve) +{ + nfapi_tl_t generic_tl; + uint8_t numBadTags = 0; + uint16_t idx = 0; + + while ((uint8_t*)(*ppReadPackedMsg) < end) + { + // unpack the tl and process the values accordingly + if(unpack_tl(ppReadPackedMsg, &generic_tl, end) == 0) + return 0; + + uint8_t tagMatch = 0; + + uint8_t* pStartOfValue = *ppReadPackedMsg; + + for(idx = 0; idx < size; ++idx) + { + if(unpack_fns[idx].tag == generic_tl.tag) + { + tagMatch = 1; + nfapi_tl_t* tl = (nfapi_tl_t*)(unpack_fns[idx].tlv); + tl->tag = generic_tl.tag; + tl->length = generic_tl.length; + + int result = (*unpack_fns[idx].unpack_func)(tl, ppReadPackedMsg, end , config); + + if(result == 0) + { + return 0; + } + + // check if the length was right; + if(tl->length != (*ppReadPackedMsg - pStartOfValue)) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Warning tlv tag 0x%x length %d not equal to unpack %d\n", tl->tag, tl->length, (*ppReadPackedMsg - pStartOfValue)); + } + } + } + + if(tagMatch == 0) + { + + if(generic_tl.tag >= NFAPI_VENDOR_EXTENSION_MIN_TAG_VALUE && + generic_tl.tag <= NFAPI_VENDOR_EXTENSION_MAX_TAG_VALUE) + { + int result = unpack_p7_vendor_extension_tlv(&generic_tl, ppReadPackedMsg, end, config, ve); + if(result == 0) + { + // got to end + return 0; + } + else if(result < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unknown TAG value: 0x%04x\n", generic_tl.tag); + + if (++numBadTags > MAX_BAD_TAG) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Supplied message has had too many bad tags\n"); + return -1; + } + + if((end - *ppReadPackedMsg) >= generic_tl.length) + { + // Advance past the unknown TLV + (*ppReadPackedMsg) += generic_tl.length; + } + else + { + // got ot the dn + return 0; + } + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unknown TAG value: 0x%04x\n", generic_tl.tag); + + if (++numBadTags > MAX_BAD_TAG) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Supplied message has had too many bad tags\n"); + return -1; + } + + if((end - *ppReadPackedMsg) >= generic_tl.length) + { + // Advance past the unknown TLV + (*ppReadPackedMsg) += generic_tl.length; + } + else + { + // got ot the dn + return 0; + } + + } + + } + } + + return 1; +} + +// This intermediate function deals with calculating the length of the value +// and writing into the tlv header. +uint8_t pack_tlv(uint16_t tag, void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end, pack_tlv_fn fn) +{ + nfapi_tl_t* tl = (nfapi_tl_t*)tlv; + + // If the tag is defined + if(tl->tag == tag) + { + uint8_t* pStartOfTlv = *ppWritePackedMsg; + + // write a dumy tlv header + if(pack_tl(tl, ppWritePackedMsg, end) == 0) + return 0; + + // Record the start of the value + uint8_t* pStartOfValue = *ppWritePackedMsg; + + // pack the tlv value + if(fn(tlv, ppWritePackedMsg, end) == 0) + return 0; + + // calculate the length of the value and rewrite the tl header + tl->length = (*ppWritePackedMsg) - pStartOfValue; + + // rewrite the header with the correct length + pack_tl(tl, &pStartOfTlv, end); + } + else + { + if(tl->tag != 0) + { + NFAPI_TRACE(NFAPI_TRACE_WARN, "Warning pack_tlv tag 0x%x does not match expected 0x%x\n", tl->tag, tag); + } + else + { + //NFAPI_TRACE(NFAPI_TRACE_ERROR, "Warning pack_tlv tag 0x%x ZERO does not match expected 0x%x\n", tl->tag, tag); + } + } + + return 1; +} + +const char* nfapi_error_code_to_str(nfapi_error_code_e value) +{ + switch(value) + { + case NFAPI_MSG_OK: + return "NFAPI_MSG_OK"; + case NFAPI_MSG_INVALID_STATE: + return "NFAPI_MSG_INVALID_STATE"; + case NFAPI_MSG_INVALID_CONFIG: + return "NFAPI_MSG_INVALID_CONFIG"; + case NFAPI_SFN_OUT_OF_SYNC: + return "NFAPI_SFN_OUT_OF_SYNC"; + case NFAPI_MSG_SUBFRAME_ERR: + return "NFAPI_MSG_SUBFRAME_ERR"; + case NFAPI_MSG_BCH_MISSING: + return "NFAPI_MSG_BCH_MISSING"; + case NFAPI_MSG_INVALID_SFN: + return "NFAPI_MSG_INVALID_SFN"; + case NFAPI_MSG_HI_ERR: + return "NFAPI_MSG_HI_ERR"; + case NFAPI_MSG_TX_ERR: + return "NFAPI_MSG_TX_ERR"; + default: + return "UNKNOWN"; + } +} diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p4.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p4.c new file mode 100644 index 0000000000..1eb85e6254 --- /dev/null +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p4.c @@ -0,0 +1,2084 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include // need for uintptr_t? + +#include +#include +#include +#include + +#include +#include +#include + +static uint32_t get_packed_msg_len(uintptr_t msgHead, uintptr_t msgEnd) +{ + if (msgEnd < msgHead) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "get_packed_msg_len: Error in pointers supplied %d, %d\n", msgHead, msgEnd); + return 0; + } + + return (msgEnd - msgHead); +} + +static uint8_t pack_opaque_data_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_opaqaue_data_t* value = (nfapi_opaqaue_data_t*)tlv; + return pusharray8(value->value, NFAPI_MAX_OPAQUE_DATA, value->length, ppWritePackedMsg, end); +} + +static uint8_t unpack_opaque_data_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_opaqaue_data_t* value = (nfapi_opaqaue_data_t*)tlv; + value->length = value->tl.length; + if(value->length <= NFAPI_MAX_OPAQUE_DATA) + { + if(!pullarray8(ppReadPackedMsg, value->value, NFAPI_MAX_OPAQUE_DATA, value->length, end)) + return 0; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Opaque date to long %d \n", value->length); + return 0; + } + + return 1; + +} + +static uint8_t pack_lte_rssi_request_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_lte_rssi_request_t* value = (nfapi_lte_rssi_request_t*)tlv; + + return (push8(value->frequency_band_indicator, ppWritePackedMsg, end) && + push16(value->measurement_period, ppWritePackedMsg, end) && + push8(value->bandwidth, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end) && + push8(value->number_of_earfcns, ppWritePackedMsg, end) && + pusharray16(value->earfcn, NFAPI_MAX_CARRIER_LIST, value->number_of_earfcns, ppWritePackedMsg, end)); +} + +static uint8_t pack_utran_rssi_request_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_utran_rssi_request_t* value = (nfapi_utran_rssi_request_t*)tlv; + + return (push8(value->frequency_band_indicator, ppWritePackedMsg, end) && + push16(value->measurement_period, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end) && + push8(value->number_of_uarfcns, ppWritePackedMsg, end) && + pusharray16(value->uarfcn, NFAPI_MAX_CARRIER_LIST, value->number_of_uarfcns, ppWritePackedMsg, end)); +} + +static uint8_t pack_geran_rssi_request_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_geran_rssi_request_t* value = (nfapi_geran_rssi_request_t*)tlv; + uint16_t idx = 0; + + if(!(push8(value->frequency_band_indicator, ppWritePackedMsg, end) && + push16(value->measurement_period, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end) && + push8(value->number_of_arfcns, ppWritePackedMsg, end))) + return 0; + + for(;idx < value->number_of_arfcns; ++idx) + { + if(!(push16(value->arfcn[idx].arfcn, ppWritePackedMsg, end) && + push8(value->arfcn[idx].direction, ppWritePackedMsg, end))) + return 0; + } + + return 1; +} + +static uint8_t pack_nb_iot_rssi_request_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nb_iot_rssi_request_t* value = (nfapi_nb_iot_rssi_request_t*)tlv; + uint16_t idx = 0; + + if(!(push8(value->frequency_band_indicator, ppWritePackedMsg, end) && + push16(value->measurement_period, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end) && + push8(value->number_of_earfcns, ppWritePackedMsg, end))) + return 0; + + for(;idx < value->number_of_earfcns; ++idx) + { + if(!(push16(value->earfcn[idx].earfcn, ppWritePackedMsg, end) && + push8(value->earfcn[idx].number_of_ro_dl, ppWritePackedMsg, end))) + return 0; + + uint8_t ro_dl_idx = 0; + for(ro_dl_idx = 0; ro_dl_idx < value->earfcn[idx].number_of_ro_dl; ++ro_dl_idx) + { + if(!push8(value->earfcn[idx].ro_dl[ro_dl_idx], ppWritePackedMsg, end)) + return 0; + } + } + + return 1; +} + + + +static uint8_t pack_rssi_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_rssi_request_t *pNfapiMsg = (nfapi_rssi_request_t*)msg; + + if(push8(pNfapiMsg->rat_type, ppWritePackedMsg, end) == 0) + return 0; + + switch(pNfapiMsg->rat_type) + { + case NFAPI_RAT_TYPE_LTE: + if(pack_tlv(NFAPI_LTE_RSSI_REQUEST_TAG, &pNfapiMsg->lte_rssi_request, ppWritePackedMsg, end, &pack_lte_rssi_request_value) == 0) + return 0; + break; + case NFAPI_RAT_TYPE_UTRAN: + if(pack_tlv(NFAPI_UTRAN_RSSI_REQUEST_TAG, &pNfapiMsg->utran_rssi_request, ppWritePackedMsg, end, &pack_utran_rssi_request_value) == 0) + return 0; + break; + case NFAPI_RAT_TYPE_GERAN: + if(pack_tlv(NFAPI_GERAN_RSSI_REQUEST_TAG, &pNfapiMsg->geran_rssi_request, ppWritePackedMsg, end, &pack_geran_rssi_request_value) == 0) + return 0; + break; + case NFAPI_RAT_TYPE_NB_IOT: + if(pack_tlv(NFAPI_NB_IOT_RSSI_REQUEST_TAG, &pNfapiMsg->nb_iot_rssi_request, ppWritePackedMsg, end, &pack_nb_iot_rssi_request_value) == 0) + return 0; + break; + } + + return pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config); +} + +static uint8_t pack_rssi_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_rssi_response_t *pNfapiMsg = (nfapi_rssi_response_t*)msg; + + return (push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_rssi_indication_body_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_rssi_indication_body_t* value = (nfapi_rssi_indication_body_t*)tlv; + + return (push16(value->number_of_rssi, ppWritePackedMsg, end) && + pusharrays16(value->rssi, NFAPI_MAX_RSSI, value->number_of_rssi, ppWritePackedMsg, end)); +} + +static uint8_t pack_rssi_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_rssi_indication_t *pNfapiMsg = (nfapi_rssi_indication_t*)msg; + + return (push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_tlv(NFAPI_RSSI_INDICATION_TAG, &pNfapiMsg->rssi_indication_body, ppWritePackedMsg, end, &pack_rssi_indication_body_value) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + + +static uint8_t pack_lte_cell_search_request_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_lte_cell_search_request_t* value = (nfapi_lte_cell_search_request_t*)msg; + + return (push16(value->earfcn, ppWritePackedMsg, end) && + push8(value->measurement_bandwidth, ppWritePackedMsg, end) && + push8(value->exhaustive_search, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end) && + push8(value->number_of_pci, ppWritePackedMsg, end) && + pusharray16(value->pci, NFAPI_MAX_PCI_LIST, value->number_of_pci, ppWritePackedMsg, end)); +} + +static uint8_t pack_utran_cell_search_request_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_utran_cell_search_request_t* value = (nfapi_utran_cell_search_request_t*)msg; + + return (push16(value->uarfcn, ppWritePackedMsg, end) && + push8(value->exhaustive_search, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end) && + push8(value->number_of_psc, ppWritePackedMsg, end) && + pusharray16(value->psc, NFAPI_MAX_PSC_LIST, value->number_of_psc, ppWritePackedMsg, end)); +} + +static uint8_t pack_geran_cell_search_request_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_geran_cell_search_request_t* value = (nfapi_geran_cell_search_request_t*)msg; + + return (push32(value->timeout, ppWritePackedMsg, end) && + push8(value->number_of_arfcn, ppWritePackedMsg, end) && + pusharray16(value->arfcn, NFAPI_MAX_ARFCN_LIST, value->number_of_arfcn, ppWritePackedMsg, end)); +} + +static uint8_t pack_nb_iot_cell_search_request_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nb_iot_cell_search_request_t* value = (nfapi_nb_iot_cell_search_request_t*)msg; + + return (push16(value->earfcn, ppWritePackedMsg, end) && + push8(value->ro_dl, ppWritePackedMsg, end) && + push8(value->exhaustive_search, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end) && + push8(value->number_of_pci, ppWritePackedMsg, end) && + pusharray16(value->pci, NFAPI_MAX_PCI_LIST, value->number_of_pci, ppWritePackedMsg, end)); +} + + +static uint8_t pack_cell_search_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_cell_search_request_t *pNfapiMsg = (nfapi_cell_search_request_t*)msg; + + if(push8(pNfapiMsg->rat_type, ppWritePackedMsg, end) == 0) + return 0; + + switch(pNfapiMsg->rat_type) + { + case NFAPI_RAT_TYPE_LTE: + { + if(pack_tlv(NFAPI_LTE_CELL_SEARCH_REQUEST_TAG, &pNfapiMsg->lte_cell_search_request, ppWritePackedMsg, end, &pack_lte_cell_search_request_value) == 0) + return 0; + } + break; + case NFAPI_RAT_TYPE_UTRAN: + { + if(pack_tlv(NFAPI_UTRAN_CELL_SEARCH_REQUEST_TAG, &pNfapiMsg->utran_cell_search_request, ppWritePackedMsg, end, &pack_utran_cell_search_request_value) == 0) + return 0; + } + break; + case NFAPI_RAT_TYPE_GERAN: + { + if(pack_tlv(NFAPI_GERAN_CELL_SEARCH_REQUEST_TAG, &pNfapiMsg->geran_cell_search_request, ppWritePackedMsg, end, &pack_geran_cell_search_request_value) == 0) + return 0; + } + break; + case NFAPI_RAT_TYPE_NB_IOT: + { + if(pack_tlv(NFAPI_NB_IOT_CELL_SEARCH_REQUEST_TAG, &pNfapiMsg->nb_iot_cell_search_request, ppWritePackedMsg, end, &pack_nb_iot_cell_search_request_value) == 0) + return 0; + } + break; + }; + + return (pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_cell_search_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_cell_search_response_t *pNfapiMsg = (nfapi_cell_search_response_t*)msg; + + return (push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_lte_cell_search_indication_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_lte_cell_search_indication_t* value = (nfapi_lte_cell_search_indication_t*)msg; + uint16_t idx = 0; + + if(push16(value->number_of_lte_cells_found, ppWritePackedMsg, end) == 0) + return 0; + + for(idx = 0; idx < value->number_of_lte_cells_found; ++idx) + { + if(!(push16(value->lte_found_cells[idx].pci, ppWritePackedMsg, end) && + push8(value->lte_found_cells[idx].rsrp, ppWritePackedMsg, end) && + push8(value->lte_found_cells[idx].rsrq, ppWritePackedMsg, end) && + pushs16(value->lte_found_cells[idx].frequency_offset, ppWritePackedMsg, end))) + return 0; + } + return 1; +} + +static uint8_t pack_utran_cell_search_indication_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_utran_cell_search_indication_t* value = (nfapi_utran_cell_search_indication_t*)msg; + uint16_t idx = 0; + + if(push16(value->number_of_utran_cells_found, ppWritePackedMsg, end) == 0) + return 0; + + for(idx = 0; idx < value->number_of_utran_cells_found; ++idx) + { + if(!(push16(value->utran_found_cells[idx].psc, ppWritePackedMsg, end) && + push8(value->utran_found_cells[idx].rscp, ppWritePackedMsg, end) && + push8(value->utran_found_cells[idx].ecno, ppWritePackedMsg, end) && + pushs16(value->utran_found_cells[idx].frequency_offset, ppWritePackedMsg, end))) + return 0; + } + + return 1; +} + +static uint8_t pack_geran_cell_search_indication_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_geran_cell_search_indication_t* value = (nfapi_geran_cell_search_indication_t*)msg; + uint16_t idx = 0; + + if(push16(value->number_of_gsm_cells_found, ppWritePackedMsg, end) == 0) + return 0; + + for(idx = 0; idx < value->number_of_gsm_cells_found; ++idx) + { + if(!(push16(value->gsm_found_cells[idx].arfcn, ppWritePackedMsg, end) && + push8(value->gsm_found_cells[idx].bsic, ppWritePackedMsg, end) && + push8(value->gsm_found_cells[idx].rxlev, ppWritePackedMsg, end) && + push8(value->gsm_found_cells[idx].rxqual, ppWritePackedMsg, end) && + pushs16(value->gsm_found_cells[idx].frequency_offset, ppWritePackedMsg, end) && + push32(value->gsm_found_cells[idx].sfn_offset, ppWritePackedMsg, end))) + return 0; + } + + return 1; +} + +static uint8_t pack_nb_iot_cell_search_indication_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nb_iot_cell_search_indication_t* value = (nfapi_nb_iot_cell_search_indication_t*)msg; + uint16_t idx = 0; + + if(push16(value->number_of_nb_iot_cells_found, ppWritePackedMsg, end) == 0) + return 0; + + for(idx = 0; idx < value->number_of_nb_iot_cells_found; ++idx) + { + if(!(push16(value->nb_iot_found_cells[idx].pci, ppWritePackedMsg, end) && + push8(value->nb_iot_found_cells[idx].rsrp, ppWritePackedMsg, end) && + push8(value->nb_iot_found_cells[idx].rsrq, ppWritePackedMsg, end) && + pushs16(value->nb_iot_found_cells[idx].frequency_offset, ppWritePackedMsg, end))) + return 0; + } + + return 1; +} +static uint8_t pack_cell_search_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_cell_search_indication_t *pNfapiMsg = (nfapi_cell_search_indication_t*)msg; + + return (push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_tlv(NFAPI_LTE_CELL_SEARCH_INDICATION_TAG, &pNfapiMsg->lte_cell_search_indication, ppWritePackedMsg, end, &pack_lte_cell_search_indication_value) && + pack_tlv(NFAPI_UTRAN_CELL_SEARCH_INDICATION_TAG, &pNfapiMsg->utran_cell_search_indication, ppWritePackedMsg, end, &pack_utran_cell_search_indication_value) && + pack_tlv(NFAPI_GERAN_CELL_SEARCH_INDICATION_TAG, &pNfapiMsg->geran_cell_search_indication, ppWritePackedMsg, end, &pack_geran_cell_search_indication_value) && + pack_tlv(NFAPI_PNF_CELL_SEARCH_STATE_TAG, &pNfapiMsg->pnf_cell_search_state, ppWritePackedMsg, end, &pack_opaque_data_value) && + pack_tlv(NFAPI_NB_IOT_CELL_SEARCH_INDICATION_TAG, &pNfapiMsg->nb_iot_cell_search_indication, ppWritePackedMsg, end, &pack_nb_iot_cell_search_indication_value) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); + +} + +static uint8_t pack_lte_broadcast_detect_request_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_lte_broadcast_detect_request_t* value = (nfapi_lte_broadcast_detect_request_t*)msg; + + return (push16(value->earfcn, ppWritePackedMsg, end) && + push16(value->pci, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end)); +} + +static uint8_t pack_utran_broadcast_detect_request_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_utran_broadcast_detect_request_t* value = (nfapi_utran_broadcast_detect_request_t*)msg; + + return (push16(value->uarfcn, ppWritePackedMsg, end) && + push16(value->psc, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end)); +} + +static uint8_t pack_nb_iot_broadcast_detect_request_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nb_iot_broadcast_detect_request_t* value = (nfapi_nb_iot_broadcast_detect_request_t*)msg; + + return (push16(value->earfcn, ppWritePackedMsg, end) && + push8(value->ro_dl, ppWritePackedMsg, end) && + push16(value->pci, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end)); +} + +static uint8_t pack_broadcast_detect_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t * end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_broadcast_detect_request_t *pNfapiMsg = (nfapi_broadcast_detect_request_t*)msg; + + if(push8(pNfapiMsg->rat_type, ppWritePackedMsg, end) == 0) + return 0; + + switch(pNfapiMsg->rat_type) + { + case NFAPI_RAT_TYPE_LTE: + if(pack_tlv(NFAPI_LTE_BROADCAST_DETECT_REQUEST_TAG, &pNfapiMsg->lte_broadcast_detect_request, ppWritePackedMsg, end ,&pack_lte_broadcast_detect_request_value) == 0) + return 0; + break; + case NFAPI_RAT_TYPE_UTRAN: + if(pack_tlv(NFAPI_UTRAN_BROADCAST_DETECT_REQUEST_TAG, &pNfapiMsg->utran_broadcast_detect_request, ppWritePackedMsg, end, &pack_utran_broadcast_detect_request_value) == 0) + return 0; + break; + case NFAPI_RAT_TYPE_NB_IOT: + if(pack_tlv(NFAPI_NB_IOT_BROADCAST_DETECT_REQUEST_TAG, &pNfapiMsg->nb_iot_broadcast_detect_request, ppWritePackedMsg, end, &pack_nb_iot_broadcast_detect_request_value) == 0) + return 0; + break; + + } + + return (pack_tlv(NFAPI_PNF_CELL_SEARCH_STATE_TAG, &pNfapiMsg->pnf_cell_search_state, ppWritePackedMsg, end, &pack_opaque_data_value) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_broadcast_detect_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_broadcast_detect_response_t *pNfapiMsg = (nfapi_broadcast_detect_response_t*)msg; + + return (push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_lte_broadcast_detect_indication_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_lte_broadcast_detect_indication_t* value = (nfapi_lte_broadcast_detect_indication_t*)msg; + + return (push8(value->number_of_tx_antenna, ppWritePackedMsg, end) && + push16(value->mib_length, ppWritePackedMsg, end) && + pusharray8(value->mib, NFAPI_MAX_MIB_LENGTH, value->mib_length, ppWritePackedMsg, end) && + push32(value->sfn_offset, ppWritePackedMsg, end)); +} + +static uint8_t pack_utran_broadcast_detect_indication_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_utran_broadcast_detect_indication_t* value = (nfapi_utran_broadcast_detect_indication_t*)msg; + + return (push16(value->mib_length, ppWritePackedMsg, end) && + pusharray8(value->mib, NFAPI_MAX_MIB_LENGTH, value->mib_length, ppWritePackedMsg, end) && + push32(value->sfn_offset, ppWritePackedMsg, end)); +} + +static uint8_t pack_nb_iot_broadcast_detect_indication_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nb_iot_broadcast_detect_indication_t* value = (nfapi_nb_iot_broadcast_detect_indication_t*)msg; + + return (push8(value->number_of_tx_antenna, ppWritePackedMsg, end) && + push16(value->mib_length, ppWritePackedMsg, end) && + pusharray8(value->mib, NFAPI_MAX_MIB_LENGTH, value->mib_length, ppWritePackedMsg, end) && + push32(value->sfn_offset, ppWritePackedMsg, end)); +} + +static uint8_t pack_broadcast_detect_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_broadcast_detect_indication_t *pNfapiMsg = (nfapi_broadcast_detect_indication_t*)msg; + + return (push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_tlv(NFAPI_LTE_BROADCAST_DETECT_INDICATION_TAG, &pNfapiMsg->lte_broadcast_detect_indication, ppWritePackedMsg, end, &pack_lte_broadcast_detect_indication_value) && + pack_tlv(NFAPI_UTRAN_BROADCAST_DETECT_INDICATION_TAG, &pNfapiMsg->utran_broadcast_detect_indication, ppWritePackedMsg, end, &pack_utran_broadcast_detect_indication_value) && + pack_tlv(NFAPI_PNF_CELL_BROADCAST_STATE_TAG, &pNfapiMsg->pnf_cell_broadcast_state, ppWritePackedMsg, end, &pack_opaque_data_value) && + pack_tlv(NFAPI_NB_IOT_BROADCAST_DETECT_INDICATION_TAG, &pNfapiMsg->nb_iot_broadcast_detect_indication, ppWritePackedMsg, end, &pack_nb_iot_broadcast_detect_indication_value) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_lte_system_information_schedule_request_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_lte_system_information_schedule_request_t* value = (nfapi_lte_system_information_schedule_request_t*)msg; + + return (push16(value->earfcn, ppWritePackedMsg, end) && + push16(value->pci, ppWritePackedMsg, end) && + push16(value->downlink_channel_bandwidth, ppWritePackedMsg, end) && + push8(value->phich_configuration, ppWritePackedMsg, end) && + push8(value->number_of_tx_antenna, ppWritePackedMsg, end) && + push8(value->retry_count, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end)); +} + +static uint8_t pack_nb_iot_system_information_schedule_request_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nb_iot_system_information_schedule_request_t* value = (nfapi_nb_iot_system_information_schedule_request_t*)msg; + + return (push16(value->earfcn, ppWritePackedMsg, end) && + push8(value->ro_dl, ppWritePackedMsg, end) && + push16(value->pci, ppWritePackedMsg, end) && + push8(value->scheduling_info_sib1_nb, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end)); +} + + +static uint8_t pack_system_information_schedule_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_system_information_schedule_request_t *pNfapiMsg = (nfapi_system_information_schedule_request_t*)msg; + + if(push8(pNfapiMsg->rat_type, ppWritePackedMsg, end) == 0) + return 0; + + switch(pNfapiMsg->rat_type) + { + case NFAPI_RAT_TYPE_LTE: + if(pack_tlv(NFAPI_LTE_SYSTEM_INFORMATION_SCHEDULE_REQUEST_TAG, &pNfapiMsg->lte_system_information_schedule_request, ppWritePackedMsg, end, &pack_lte_system_information_schedule_request_value) == 0) + return 0; + break; + case NFAPI_RAT_TYPE_NB_IOT: + if(pack_tlv(NFAPI_NB_IOT_SYSTEM_INFORMATION_SCHEDULE_REQUEST_TAG, &pNfapiMsg->nb_iot_system_information_schedule_request, ppWritePackedMsg, end, &pack_nb_iot_system_information_schedule_request_value) == 0) + return 0; + break; + } + + return (pack_tlv(NFAPI_PNF_CELL_BROADCAST_STATE_TAG, &pNfapiMsg->pnf_cell_broadcast_state, ppWritePackedMsg, end, &pack_opaque_data_value) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); + +} + +static uint8_t pack_system_information_schedule_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_system_information_schedule_response_t *pNfapiMsg = (nfapi_system_information_schedule_response_t*)msg; + + return (push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_lte_system_information_indication_value(void* msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_lte_system_information_indication_t* value = (nfapi_lte_system_information_indication_t*)msg; + + return (push8(value->sib_type, ppWritePackedMsg, end) && + push16(value->sib_length, ppWritePackedMsg, end) && + pusharray8(value->sib, NFAPI_MAX_SIB_LENGTH, value->sib_length, ppWritePackedMsg, end)); +} + +static uint8_t pack_nb_iot_system_information_indication_value(void* msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nb_iot_system_information_indication_t* value = (nfapi_nb_iot_system_information_indication_t*)msg; + + return (push8(value->sib_type, ppWritePackedMsg, end) && + push16(value->sib_length, ppWritePackedMsg, end) && + pusharray8(value->sib, NFAPI_MAX_SIB_LENGTH, value->sib_length, ppWritePackedMsg, end)); +} + +static uint8_t pack_system_information_schedule_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_system_information_schedule_indication_t *pNfapiMsg = (nfapi_system_information_schedule_indication_t*)msg; + + return (push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_tlv(NFAPI_LTE_SYSTEM_INFORMATION_INDICATION_TAG, &pNfapiMsg->lte_system_information_indication, ppWritePackedMsg, end, &pack_lte_system_information_indication_value) && + pack_tlv(NFAPI_NB_IOT_SYSTEM_INFORMATION_INDICATION_TAG, &pNfapiMsg->nb_iot_system_information_indication, ppWritePackedMsg, end, &pack_nb_iot_system_information_indication_value) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_lte_system_information_request_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_lte_system_information_request_t* value = (nfapi_lte_system_information_request_t*)msg; + uint16_t idx = 0; + + if(!(push16(value->earfcn, ppWritePackedMsg, end) && + push16(value->pci, ppWritePackedMsg, end) && + push16(value->downlink_channel_bandwidth, ppWritePackedMsg, end) && + push8(value->phich_configuration, ppWritePackedMsg, end) && + push8(value->number_of_tx_antenna, ppWritePackedMsg, end) && + push8(value->number_of_si_periodicity, ppWritePackedMsg, end))) + return 0; + + for(idx = 0; idx < value->number_of_si_periodicity; ++idx) + { + if(!(push8(value->si_periodicity[idx].si_periodicity, ppWritePackedMsg, end) && + push8(value->si_periodicity[idx].si_index, ppWritePackedMsg, end))) + return 0; + } + + return (push8(value->si_window_length, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end)); +} +static uint8_t pack_utran_system_information_request_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_utran_system_information_request_t* value = (nfapi_utran_system_information_request_t*)msg; + + return (push16(value->uarfcn, ppWritePackedMsg, end) && + push16(value->psc, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end)); +} +static uint8_t pack_geran_system_information_request_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_geran_system_information_request_t* value = (nfapi_geran_system_information_request_t*)msg; + + return (push16(value->arfcn, ppWritePackedMsg, end) && + push8(value->bsic, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end)); +} +static uint8_t pack_nb_iot_system_information_request_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nb_iot_system_information_request_t* value = (nfapi_nb_iot_system_information_request_t*)msg; + uint16_t idx = 0; + + if(!(push16(value->earfcn, ppWritePackedMsg, end) && + push8(value->ro_dl, ppWritePackedMsg, end) && + push16(value->pci, ppWritePackedMsg, end) && + push8(value->number_of_si_periodicity, ppWritePackedMsg, end))) + return 0; + + for(idx = 0; idx < value->number_of_si_periodicity; ++idx) + { + if(!(push8(value->si_periodicity[idx].si_periodicity, ppWritePackedMsg, end) && + push8(value->si_periodicity[idx].si_repetition_pattern, ppWritePackedMsg, end) && + push8(value->si_periodicity[idx].si_tb_size, ppWritePackedMsg, end) && + push8(value->si_periodicity[idx].number_of_si_index, ppWritePackedMsg, end))) + return 0; + + uint8_t si_idx; + for(si_idx = 0; si_idx < value->si_periodicity[idx].number_of_si_index; ++si_idx) + { + if(!(push8(value->si_periodicity[idx].si_index[si_idx], ppWritePackedMsg, end))) + return 0; + } + } + + return (push8(value->si_window_length, ppWritePackedMsg, end) && + push32(value->timeout, ppWritePackedMsg, end)); +} + + +static uint8_t pack_system_information_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_system_information_request_t *pNfapiMsg = (nfapi_system_information_request_t*)msg; + + if(push8(pNfapiMsg->rat_type, ppWritePackedMsg, end) == 0) + return 0; + + switch(pNfapiMsg->rat_type) + { + case NFAPI_RAT_TYPE_LTE: + if(pack_tlv(NFAPI_LTE_SYSTEM_INFORMATION_REQUEST_TAG, &pNfapiMsg->lte_system_information_request, ppWritePackedMsg, end, &pack_lte_system_information_request_value) == 0) + return 0; + break; + case NFAPI_RAT_TYPE_UTRAN: + if(pack_tlv(NFAPI_UTRAN_SYSTEM_INFORMATION_REQUEST_TAG, &pNfapiMsg->utran_system_information_request, ppWritePackedMsg, end, &pack_utran_system_information_request_value) == 0) + return 0; + break; + case NFAPI_RAT_TYPE_GERAN: + if(pack_tlv(NFAPI_GERAN_SYSTEM_INFORMATION_REQUEST_TAG, &pNfapiMsg->geran_system_information_request, ppWritePackedMsg, end, &pack_geran_system_information_request_value) == 0) + return 0; + break; + case NFAPI_RAT_TYPE_NB_IOT: + if(pack_tlv(NFAPI_NB_IOT_SYSTEM_INFORMATION_REQUEST_TAG, &pNfapiMsg->nb_iot_system_information_request, ppWritePackedMsg, end, &pack_nb_iot_system_information_request_value) == 0) + return 0; + break; + } + + return (pack_tlv(NFAPI_PNF_CELL_BROADCAST_STATE_TAG, &pNfapiMsg->pnf_cell_broadcast_state, ppWritePackedMsg, end, &pack_opaque_data_value) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_system_information_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_system_information_response_t *pNfapiMsg = (nfapi_system_information_response_t*)msg; + + return (push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_utran_system_information_indication_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_utran_system_information_indication_t* value = (nfapi_utran_system_information_indication_t*)msg; + + return (push16(value->sib_length, ppWritePackedMsg, end) && + pusharray8(value->sib, NFAPI_MAX_SIB_LENGTH, value->sib_length, ppWritePackedMsg, end)); +} + +static uint8_t pack_geran_system_information_indication_value(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_geran_system_information_indication_t* value = (nfapi_geran_system_information_indication_t*)msg; + + return (push16(value->si_length, ppWritePackedMsg, end) && + pusharray8(value->si, NFAPI_MAX_SIB_LENGTH, value->si_length, ppWritePackedMsg, end)); +} + +static uint8_t pack_system_information_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_system_information_indication_t *pNfapiMsg = (nfapi_system_information_indication_t*)msg; + + return (push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_tlv(NFAPI_LTE_SYSTEM_INFORMATION_INDICATION_TAG, &pNfapiMsg->lte_system_information_indication, ppWritePackedMsg, end, &pack_lte_system_information_indication_value) && + pack_tlv(NFAPI_UTRAN_SYSTEM_INFORMATION_INDICATION_TAG, &pNfapiMsg->utran_system_information_indication, ppWritePackedMsg, end, &pack_utran_system_information_indication_value) && + pack_tlv(NFAPI_GERAN_SYSTEM_INFORMATION_INDICATION_TAG, &pNfapiMsg->geran_system_information_indication, ppWritePackedMsg, end, &pack_geran_system_information_indication_value) && + pack_tlv(NFAPI_NB_IOT_SYSTEM_INFORMATION_INDICATION_TAG, &pNfapiMsg->nb_iot_system_information_indication, ppWritePackedMsg, end, &pack_nb_iot_system_information_indication_value) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_nmm_stop_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_nmm_stop_request_t *pNfapiMsg = (nfapi_nmm_stop_request_t*)msg; + + return (pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_nmm_stop_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_nmm_stop_response_t *pNfapiMsg = (nfapi_nmm_stop_response_t*)msg; + + return (push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t unpack_lte_rssi_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + //int result = 0; + nfapi_lte_rssi_request_t* value = (nfapi_lte_rssi_request_t*)tlv; + + if(!(pull8(ppReadPackedMsg, &value->frequency_band_indicator, end) && + pull16(ppReadPackedMsg, &value->measurement_period, end) && + pull8(ppReadPackedMsg, &value->bandwidth, end) && + pull32(ppReadPackedMsg, &value->timeout, end) && + pull8(ppReadPackedMsg, &value->number_of_earfcns, end))) + return 0; + + if(value->number_of_earfcns <= NFAPI_MAX_CARRIER_LIST) + { + if(pullarray16(ppReadPackedMsg, value->earfcn, NFAPI_MAX_CARRIER_LIST, value->number_of_earfcns, end) == 0) + return 0; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More EARFCN's than we can decode %d \n", value->number_of_earfcns); + return 0; + } + + return 1; + +} + +static uint8_t unpack_utran_rssi_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_utran_rssi_request_t* value = (nfapi_utran_rssi_request_t*)tlv; + + if(!(pull8(ppReadPackedMsg, &value->frequency_band_indicator, end) && + pull16(ppReadPackedMsg, &value->measurement_period, end) && + pull32(ppReadPackedMsg, &value->timeout, end) && + pull8(ppReadPackedMsg, &value->number_of_uarfcns, end))) + return 0; + + if(value->number_of_uarfcns <= NFAPI_MAX_CARRIER_LIST) + { + if(pullarray16(ppReadPackedMsg, value->uarfcn, NFAPI_MAX_CARRIER_LIST, value->number_of_uarfcns, end) == 0) + return 0; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More UARFCN's than we can decode %d \n", value->number_of_uarfcns); + return 0; + } + + return 1; +} + +static uint8_t unpack_geran_rssi_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_geran_rssi_request_t* value = (nfapi_geran_rssi_request_t*)tlv; + uint16_t idx = 0; + + if(!(pull8(ppReadPackedMsg, &value->frequency_band_indicator, end) && + pull16(ppReadPackedMsg, &value->measurement_period, end) && + pull32(ppReadPackedMsg, &value->timeout, end) && + pull8(ppReadPackedMsg, &value->number_of_arfcns, end))) + return 0; + + if(value->number_of_arfcns <= NFAPI_MAX_CARRIER_LIST) + { + for(idx = 0; idx < value->number_of_arfcns; ++idx) + { + if(!(pull16(ppReadPackedMsg, &value->arfcn[idx].arfcn, end) && + pull8(ppReadPackedMsg, &value->arfcn[idx].direction, end))) + return 0; + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More ARFCN's than we can decode %d \n", value->number_of_arfcns); + return 0; + } + + return 1; +} + +static uint8_t unpack_nb_iot_rssi_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nb_iot_rssi_request_t* value = (nfapi_nb_iot_rssi_request_t*)tlv; + uint16_t idx = 0; + + if(!(pull8(ppReadPackedMsg, &value->frequency_band_indicator, end) && + pull16(ppReadPackedMsg, &value->measurement_period, end) && + pull32(ppReadPackedMsg, &value->timeout, end) && + pull8(ppReadPackedMsg, &value->number_of_earfcns, end))) + return 0; + + if(value->number_of_earfcns <= NFAPI_MAX_CARRIER_LIST) + { + for(idx = 0; idx < value->number_of_earfcns; ++idx) + { + if(!(pull16(ppReadPackedMsg, &value->earfcn[idx].earfcn, end) && + pull8(ppReadPackedMsg, &value->earfcn[idx].number_of_ro_dl, end))) + return 0; + + if(value->earfcn[idx].number_of_ro_dl <= NFAPI_MAX_RO_DL) + { + uint8_t ro_dl_idx = 0; + for(ro_dl_idx = 0; ro_dl_idx < value->earfcn[idx].number_of_ro_dl; ++ro_dl_idx) + { + if(!pull8(ppReadPackedMsg, &value->earfcn[idx].ro_dl[ro_dl_idx], end)) + return 0; + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More ROdl's than we can decode %d \n", value->earfcn[idx].number_of_ro_dl); + return 0; + } + + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More EARFCN's than we can decode %d \n", value->number_of_earfcns); + return 0; + } + + return 1; +} + +static uint8_t unpack_rssi_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_rssi_request_t *pNfapiMsg = (nfapi_rssi_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_LTE_RSSI_REQUEST_TAG, &pNfapiMsg->lte_rssi_request, &unpack_lte_rssi_request_value}, + { NFAPI_UTRAN_RSSI_REQUEST_TAG, &pNfapiMsg->utran_rssi_request, &unpack_utran_rssi_request_value}, + { NFAPI_GERAN_RSSI_REQUEST_TAG, &pNfapiMsg->geran_rssi_request, &unpack_geran_rssi_request_value}, + { NFAPI_NB_IOT_RSSI_REQUEST_TAG, &pNfapiMsg->nb_iot_rssi_request, &unpack_nb_iot_rssi_request_value}, + }; + + int result = 0; + + result = (pull8(ppReadPackedMsg, &pNfapiMsg->rat_type, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension))); + + + // Verify that the rat type and the tlv match + if(result == 1 && + !((pNfapiMsg->rat_type == NFAPI_RAT_TYPE_LTE && pNfapiMsg->lte_rssi_request.tl.tag == NFAPI_LTE_RSSI_REQUEST_TAG) || + (pNfapiMsg->rat_type == NFAPI_RAT_TYPE_UTRAN && pNfapiMsg->utran_rssi_request.tl.tag == NFAPI_UTRAN_RSSI_REQUEST_TAG) || + (pNfapiMsg->rat_type == NFAPI_RAT_TYPE_GERAN && pNfapiMsg->geran_rssi_request.tl.tag == NFAPI_GERAN_RSSI_REQUEST_TAG) || + (pNfapiMsg->rat_type == NFAPI_RAT_TYPE_NB_IOT && pNfapiMsg->nb_iot_rssi_request.tl.tag == NFAPI_NB_IOT_RSSI_REQUEST_TAG))) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Mismatch RAT Type: %d and TAG value: 0x%04x \n", pNfapiMsg->rat_type, pNfapiMsg->lte_rssi_request.tl.tag); + result = 0; + } + + return result; +} + +static uint8_t unpack_rssi_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_rssi_response_t *pNfapiMsg = (nfapi_rssi_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return (pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension))); +} + +static uint8_t unpack_rssi_indication_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_rssi_indication_body_t* value = (nfapi_rssi_indication_body_t*)tlv; + + if(pull16(ppReadPackedMsg, &value->number_of_rssi, end) == 0) + return 0; + + if(value->number_of_rssi <= NFAPI_MAX_RSSI) + { + if(pullarrays16(ppReadPackedMsg, value->rssi, NFAPI_MAX_RSSI, value->number_of_rssi, end) == 0) + return 0; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More RSSI's than we can decode %d \n", value->number_of_rssi); + return 0; + } + + return 1; +} + +static uint8_t unpack_rssi_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_rssi_indication_t *pNfapiMsg = (nfapi_rssi_indication_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_RSSI_INDICATION_TAG, &pNfapiMsg->rssi_indication_body, &unpack_rssi_indication_value}, + }; + + return (pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_lte_cell_search_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_lte_cell_search_request_t* value = (nfapi_lte_cell_search_request_t*)tlv; + + if(!(pull16(ppReadPackedMsg, &value->earfcn, end) && + pull8(ppReadPackedMsg, &value->measurement_bandwidth, end) && + pull8(ppReadPackedMsg, &value->exhaustive_search, end) && + pull32(ppReadPackedMsg, &value->timeout, end) && + pull8(ppReadPackedMsg, &value->number_of_pci, end))) + return 0; + + if(value->number_of_pci <= NFAPI_MAX_PCI_LIST) + { + if(pullarray16(ppReadPackedMsg, value->pci, NFAPI_MAX_PCI_LIST, value->number_of_pci, end) == 0) + return 0; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More PCI's than we can decode %d \n", value->number_of_pci); + return 0; + } + return 1; +} + +static uint8_t unpack_utran_cell_search_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_utran_cell_search_request_t* value = (nfapi_utran_cell_search_request_t*)tlv; + + if(!(pull16(ppReadPackedMsg, &value->uarfcn, end) && + pull8(ppReadPackedMsg, &value->exhaustive_search, end) && + pull32(ppReadPackedMsg, &value->timeout, end) && + pull8(ppReadPackedMsg, &value->number_of_psc, end))) + return 0; + + if(value->number_of_psc <= NFAPI_MAX_PSC_LIST) + { + if(pullarray16(ppReadPackedMsg, value->psc, NFAPI_MAX_PSC_LIST, value->number_of_psc, end) == 0) + return 0; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More PSC's than we can decode %d \n", value->number_of_psc); + return 0; + } + return 1; +} + +static uint8_t unpack_geran_cell_search_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_geran_cell_search_request_t* value = (nfapi_geran_cell_search_request_t*)tlv; + + if(!(pull32(ppReadPackedMsg, &value->timeout, end) && + pull8(ppReadPackedMsg, &value->number_of_arfcn, end))) + return 0; + + if(value->number_of_arfcn <= NFAPI_MAX_ARFCN_LIST) + { + if(pullarray16(ppReadPackedMsg, value->arfcn, NFAPI_MAX_ARFCN_LIST, value->number_of_arfcn, end) == 0) + return 0; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More ARFCN's than we can decode %d \n", value->number_of_arfcn); + return 0; + } + return 1; +} + +static uint8_t unpack_nb_iot_cell_search_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nb_iot_cell_search_request_t* value = (nfapi_nb_iot_cell_search_request_t*)tlv; + + if(!(pull16(ppReadPackedMsg, &value->earfcn, end) && + pull8(ppReadPackedMsg, &value->ro_dl, end) && + pull8(ppReadPackedMsg, &value->exhaustive_search, end) && + pull32(ppReadPackedMsg, &value->timeout, end) && + pull8(ppReadPackedMsg, &value->number_of_pci, end))) + return 0; + + if(value->number_of_pci <= NFAPI_MAX_PCI_LIST) + { + if(pullarray16(ppReadPackedMsg, value->pci, NFAPI_MAX_PCI_LIST, value->number_of_pci, end) == 0) + return 0; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More PCI's than we can decode %d \n", value->number_of_pci); + return 0; + } + return 1; +} + +static uint8_t unpack_cell_search_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_cell_search_request_t *pNfapiMsg = (nfapi_cell_search_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_LTE_CELL_SEARCH_REQUEST_TAG, &pNfapiMsg->lte_cell_search_request, &unpack_lte_cell_search_request_value}, + { NFAPI_UTRAN_CELL_SEARCH_REQUEST_TAG, &pNfapiMsg->utran_cell_search_request, &unpack_utran_cell_search_request_value}, + { NFAPI_GERAN_CELL_SEARCH_REQUEST_TAG, &pNfapiMsg->geran_cell_search_request, &unpack_geran_cell_search_request_value}, + { NFAPI_NB_IOT_CELL_SEARCH_REQUEST_TAG, &pNfapiMsg->nb_iot_cell_search_request, &unpack_nb_iot_cell_search_request_value}, + }; + + int result = (pull8(ppReadPackedMsg, &pNfapiMsg->rat_type, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); + + // Verify that the rat type and the tlv match + if(result == 1 && + !((pNfapiMsg->rat_type == NFAPI_RAT_TYPE_LTE && pNfapiMsg->lte_cell_search_request.tl.tag == NFAPI_LTE_CELL_SEARCH_REQUEST_TAG) || + (pNfapiMsg->rat_type == NFAPI_RAT_TYPE_UTRAN && pNfapiMsg->utran_cell_search_request.tl.tag == NFAPI_UTRAN_CELL_SEARCH_REQUEST_TAG) || + (pNfapiMsg->rat_type == NFAPI_RAT_TYPE_GERAN && pNfapiMsg->geran_cell_search_request.tl.tag == NFAPI_GERAN_CELL_SEARCH_REQUEST_TAG) || + (pNfapiMsg->rat_type == NFAPI_RAT_TYPE_NB_IOT && pNfapiMsg->nb_iot_cell_search_request.tl.tag == NFAPI_NB_IOT_CELL_SEARCH_REQUEST_TAG))) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Mismatch RAT Type: %d and TAG value: 0x%04x \n", pNfapiMsg->rat_type, pNfapiMsg->lte_cell_search_request.tl.tag); + result = 0; + } + + return result; +} + +static uint8_t unpack_cell_search_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_cell_search_response_t *pNfapiMsg = (nfapi_cell_search_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return (pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_lte_cell_search_indication_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_lte_cell_search_indication_t* value = (nfapi_lte_cell_search_indication_t*)tlv; + + uint16_t idx = 0; + if(pull16(ppReadPackedMsg, &value->number_of_lte_cells_found, end) == 0) + return 0; + + if(value->number_of_lte_cells_found <= NFAPI_MAX_LTE_CELLS_FOUND) + { + for(idx = 0; idx < value->number_of_lte_cells_found; ++idx) + { + if(!(pull16(ppReadPackedMsg, &value->lte_found_cells[idx].pci, end) && + pull8(ppReadPackedMsg, &value->lte_found_cells[idx].rsrp, end) && + pull8(ppReadPackedMsg, &value->lte_found_cells[idx].rsrq, end) && + pulls16(ppReadPackedMsg, &value->lte_found_cells[idx].frequency_offset, end))) + return 0; + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More found LTE cells than we can decode %d \n", value->number_of_lte_cells_found); + return 0; + } + return 1; +} + +static uint8_t unpack_utran_cell_search_indication_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_utran_cell_search_indication_t* value = (nfapi_utran_cell_search_indication_t*)tlv; + + uint16_t idx = 0; + if(pull16(ppReadPackedMsg, &value->number_of_utran_cells_found, end) == 0) + return 0; + + if(value->number_of_utran_cells_found <= NFAPI_MAX_UTRAN_CELLS_FOUND) + { + for(idx = 0; idx < value->number_of_utran_cells_found; ++idx) + { + if(!(pull16(ppReadPackedMsg, &value->utran_found_cells[idx].psc, end) && + pull8(ppReadPackedMsg, &value->utran_found_cells[idx].rscp, end) && + pull8(ppReadPackedMsg, &value->utran_found_cells[idx].ecno, end) && + pulls16(ppReadPackedMsg, &value->utran_found_cells[idx].frequency_offset, end))) + return 0; + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More found UTRAN cells than we can decode %d \n", value->number_of_utran_cells_found); + return 0; + } + return 1; +} + +static uint8_t unpack_geran_cell_search_indication_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_geran_cell_search_indication_t* value = (nfapi_geran_cell_search_indication_t*)tlv; + + uint16_t idx = 0; + if(pull16(ppReadPackedMsg, &value->number_of_gsm_cells_found, end) == 0) + return 0; + + if(value->number_of_gsm_cells_found <= NFAPI_MAX_GSM_CELLS_FOUND) + { + for(idx = 0; idx < value->number_of_gsm_cells_found; ++idx) + { + if(!(pull16(ppReadPackedMsg, &value->gsm_found_cells[idx].arfcn, end) && + pull8(ppReadPackedMsg, &value->gsm_found_cells[idx].bsic, end) && + pull8(ppReadPackedMsg, &value->gsm_found_cells[idx].rxlev, end) && + pull8(ppReadPackedMsg, &value->gsm_found_cells[idx].rxqual, end) && + pulls16(ppReadPackedMsg, &value->gsm_found_cells[idx].frequency_offset, end) && + pull32(ppReadPackedMsg, &value->gsm_found_cells[idx].sfn_offset, end))) + return 0; + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More found GSM cells than we can decode %d \n", value->number_of_gsm_cells_found); + return 0; + } + return 1; +} + +static uint8_t unpack_nb_iot_cell_search_indication_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nb_iot_cell_search_indication_t* value = (nfapi_nb_iot_cell_search_indication_t*)tlv; + + uint16_t idx = 0; + if(pull16(ppReadPackedMsg, &value->number_of_nb_iot_cells_found, end) == 0) + return 0; + + if(value->number_of_nb_iot_cells_found <= NFAPI_MAX_NB_IOT_CELLS_FOUND) + { + for(idx = 0; idx < value->number_of_nb_iot_cells_found; ++idx) + { + if(!(pull16(ppReadPackedMsg, &value->nb_iot_found_cells[idx].pci, end) && + pull8(ppReadPackedMsg, &value->nb_iot_found_cells[idx].rsrp, end) && + pull8(ppReadPackedMsg, &value->nb_iot_found_cells[idx].rsrq, end) && + pulls16(ppReadPackedMsg, &value->nb_iot_found_cells[idx].frequency_offset, end))) + return 0; + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More found NB_IOT cells than we can decode %d \n", value->number_of_nb_iot_cells_found); + return 0; + } + return 1; +} + +static uint8_t unpack_cell_search_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_cell_search_indication_t *pNfapiMsg = (nfapi_cell_search_indication_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_LTE_CELL_SEARCH_INDICATION_TAG, &pNfapiMsg->lte_cell_search_indication, &unpack_lte_cell_search_indication_value}, + { NFAPI_UTRAN_CELL_SEARCH_INDICATION_TAG, &pNfapiMsg->utran_cell_search_indication, &unpack_utran_cell_search_indication_value}, + { NFAPI_GERAN_CELL_SEARCH_INDICATION_TAG, &pNfapiMsg->geran_cell_search_indication, &unpack_geran_cell_search_indication_value}, + { NFAPI_PNF_CELL_SEARCH_STATE_TAG, &pNfapiMsg->pnf_cell_search_state, &unpack_opaque_data_value}, + { NFAPI_NB_IOT_CELL_SEARCH_INDICATION_TAG, &pNfapiMsg->nb_iot_cell_search_indication, &unpack_nb_iot_cell_search_indication_value}, + }; + + return (pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); + +} + +static uint8_t unpack_lte_broadcast_detect_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_lte_broadcast_detect_request_t* value = (nfapi_lte_broadcast_detect_request_t*)tlv; + + return (pull16(ppReadPackedMsg, &value->earfcn, end) && + pull16(ppReadPackedMsg, &value->pci, end) && + pull32(ppReadPackedMsg, &value->timeout, end)); +} + +static uint8_t unpack_utran_broadcast_detect_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_utran_broadcast_detect_request_t* value = (nfapi_utran_broadcast_detect_request_t*)tlv; + + return (pull16(ppReadPackedMsg, &value->uarfcn, end) && + pull16(ppReadPackedMsg, &value->psc, end) && + pull32(ppReadPackedMsg, &value->timeout, end)); +} + +static uint8_t unpack_nb_iot_broadcast_detect_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nb_iot_broadcast_detect_request_t* value = (nfapi_nb_iot_broadcast_detect_request_t*)tlv; + + return (pull16(ppReadPackedMsg, &value->earfcn, end) && + pull8(ppReadPackedMsg, &value->ro_dl, end) && + pull16(ppReadPackedMsg, &value->pci, end) && + pull32(ppReadPackedMsg, &value->timeout, end)); +} + +static uint8_t unpack_broadcast_detect_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_broadcast_detect_request_t *pNfapiMsg = (nfapi_broadcast_detect_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_LTE_BROADCAST_DETECT_REQUEST_TAG, &pNfapiMsg->lte_broadcast_detect_request, &unpack_lte_broadcast_detect_request_value}, + { NFAPI_UTRAN_BROADCAST_DETECT_REQUEST_TAG, &pNfapiMsg->utran_broadcast_detect_request, &unpack_utran_broadcast_detect_request_value}, + { NFAPI_PNF_CELL_SEARCH_STATE_TAG, &pNfapiMsg->pnf_cell_search_state, &unpack_opaque_data_value}, + { NFAPI_NB_IOT_BROADCAST_DETECT_REQUEST_TAG, &pNfapiMsg->nb_iot_broadcast_detect_request, &unpack_nb_iot_broadcast_detect_request_value} + }; + + return (pull8(ppReadPackedMsg, &pNfapiMsg->rat_type, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_broadcast_detect_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_broadcast_detect_response_t *pNfapiMsg = (nfapi_broadcast_detect_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return (pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_lte_broadcast_detect_indication_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_lte_broadcast_detect_indication_t* value = (nfapi_lte_broadcast_detect_indication_t*)tlv; + + if(!(pull8(ppReadPackedMsg, &value->number_of_tx_antenna, end) && + pull16(ppReadPackedMsg, &value->mib_length, end))) + return 0; + + if(value->mib_length > NFAPI_MAX_MIB_LENGTH) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "MIB too long %d \n", value->mib_length); + return 0; + } + + return (pullarray8(ppReadPackedMsg, value->mib, NFAPI_MAX_MIB_LENGTH, value->mib_length, end) && + pull32(ppReadPackedMsg, &value->sfn_offset, end)); +} + +static uint8_t unpack_utran_broadcast_detect_indication_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_utran_broadcast_detect_indication_t* value = (nfapi_utran_broadcast_detect_indication_t*)tlv; + + if(pull16(ppReadPackedMsg, &value->mib_length, end) == 0) + return 0; + + if(value->mib_length > NFAPI_MAX_MIB_LENGTH) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "MIB too long %d \n", value->mib_length); + return 0; + } + + return (pullarray8(ppReadPackedMsg, value->mib, NFAPI_MAX_MIB_LENGTH, value->mib_length, end) && + pull32(ppReadPackedMsg, &value->sfn_offset, end)); +} + +static uint8_t unpack_nb_iot_broadcast_detect_indication_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nb_iot_broadcast_detect_indication_t* value = (nfapi_nb_iot_broadcast_detect_indication_t*)tlv; + + if(!(pull8(ppReadPackedMsg, &value->number_of_tx_antenna, end) && + pull16(ppReadPackedMsg, &value->mib_length, end))) + return 0; + + if(value->mib_length > NFAPI_MAX_MIB_LENGTH) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "MIB too long %d \n", value->mib_length); + return 0; + } + + return (pullarray8(ppReadPackedMsg, value->mib, NFAPI_MAX_MIB_LENGTH, value->mib_length, end) && + pull32(ppReadPackedMsg, &value->sfn_offset, end)); +} + +static uint8_t unpack_broadcast_detect_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_broadcast_detect_indication_t *pNfapiMsg = (nfapi_broadcast_detect_indication_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_LTE_BROADCAST_DETECT_INDICATION_TAG, &pNfapiMsg->lte_broadcast_detect_indication, &unpack_lte_broadcast_detect_indication_value}, + { NFAPI_UTRAN_BROADCAST_DETECT_INDICATION_TAG, &pNfapiMsg->utran_broadcast_detect_indication, &unpack_utran_broadcast_detect_indication_value}, + { NFAPI_NB_IOT_BROADCAST_DETECT_INDICATION_TAG, &pNfapiMsg->nb_iot_broadcast_detect_indication, &unpack_nb_iot_broadcast_detect_indication_value}, + { NFAPI_PNF_CELL_BROADCAST_STATE_TAG, &pNfapiMsg->pnf_cell_broadcast_state, &unpack_opaque_data_value} + }; + + return (pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_lte_system_information_schedule_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_lte_system_information_schedule_request_t* value = (nfapi_lte_system_information_schedule_request_t*)tlv; + + return (pull16(ppReadPackedMsg, &value->earfcn, end) && + pull16(ppReadPackedMsg, &value->pci, end) && + pull16(ppReadPackedMsg, &value->downlink_channel_bandwidth, end) && + pull8(ppReadPackedMsg, &value->phich_configuration, end) && + pull8(ppReadPackedMsg, &value->number_of_tx_antenna, end) && + pull8(ppReadPackedMsg, &value->retry_count, end) && + pull32(ppReadPackedMsg, &value->timeout, end)); +} + +static uint8_t unpack_nb_iot_system_information_schedule_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nb_iot_system_information_schedule_request_t* value = (nfapi_nb_iot_system_information_schedule_request_t*)tlv; + + return (pull16(ppReadPackedMsg, &value->earfcn, end) && + pull8(ppReadPackedMsg, &value->ro_dl, end) && + pull16(ppReadPackedMsg, &value->pci, end) && + pull8(ppReadPackedMsg, &value->scheduling_info_sib1_nb, end) && + pull32(ppReadPackedMsg, &value->timeout, end)); +} + +static uint8_t unpack_system_information_schedule_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_system_information_schedule_request_t *pNfapiMsg = (nfapi_system_information_schedule_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_LTE_SYSTEM_INFORMATION_SCHEDULE_REQUEST_TAG, &pNfapiMsg->lte_system_information_schedule_request, &unpack_lte_system_information_schedule_request_value}, + { NFAPI_NB_IOT_SYSTEM_INFORMATION_SCHEDULE_REQUEST_TAG, &pNfapiMsg->nb_iot_system_information_schedule_request, &unpack_nb_iot_system_information_schedule_request_value}, + { NFAPI_PNF_CELL_BROADCAST_STATE_TAG, &pNfapiMsg->pnf_cell_broadcast_state, &unpack_opaque_data_value} + }; + + return (pull8(ppReadPackedMsg, &pNfapiMsg->rat_type, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_system_information_schedule_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_system_information_schedule_response_t *pNfapiMsg = (nfapi_system_information_schedule_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return (pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_lte_system_information_indication_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_lte_system_information_indication_t* value = (nfapi_lte_system_information_indication_t*)tlv; + + if(!(pull8(ppReadPackedMsg, &value->sib_type, end) && + pull16(ppReadPackedMsg, &value->sib_length, end))) + return 0; + + if(value->sib_length > NFAPI_MAX_SIB_LENGTH) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "SIB too long %d \n", value->sib_length); + return 0; + } + + if(pullarray8(ppReadPackedMsg, value->sib, NFAPI_MAX_SIB_LENGTH, value->sib_length, end) == 0) + return 0; + + return 1; +} + +static uint8_t unpack_nb_iot_system_information_indication_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nb_iot_system_information_indication_t* value = (nfapi_nb_iot_system_information_indication_t*)tlv; + + if(!(pull8(ppReadPackedMsg, &value->sib_type, end) && + pull16(ppReadPackedMsg, &value->sib_length, end))) + return 0; + + if(value->sib_length > NFAPI_MAX_SIB_LENGTH) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "SIB too long %d \n", value->sib_length); + return 0; + } + + if(pullarray8(ppReadPackedMsg, value->sib, NFAPI_MAX_SIB_LENGTH, value->sib_length, end) == 0) + return 0; + + return 1; +} + +static uint8_t unpack_system_information_schedule_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_system_information_schedule_indication_t *pNfapiMsg = (nfapi_system_information_schedule_indication_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_LTE_SYSTEM_INFORMATION_INDICATION_TAG, &pNfapiMsg->lte_system_information_indication, &unpack_lte_system_information_indication_value}, + { NFAPI_NB_IOT_SYSTEM_INFORMATION_INDICATION_TAG, &pNfapiMsg->nb_iot_system_information_indication, &unpack_nb_iot_system_information_indication_value}, + }; + + return (pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_lte_system_information_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_lte_system_information_request_t* value = (nfapi_lte_system_information_request_t*)tlv; + uint16_t idx = 0; + + if(!(pull16(ppReadPackedMsg, &value->earfcn, end) && + pull16(ppReadPackedMsg, &value->pci, end) && + pull16(ppReadPackedMsg, &value->downlink_channel_bandwidth, end) && + pull8(ppReadPackedMsg, &value->phich_configuration, end) && + pull8(ppReadPackedMsg, &value->number_of_tx_antenna, end) && + pull8(ppReadPackedMsg, &value->number_of_si_periodicity, end))) + return 0; + + if(value->number_of_si_periodicity > NFAPI_MAX_SI_PERIODICITY) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More found SI periodicity than we can decode %d \n", value->number_of_si_periodicity); + return 0; + } + + for(idx = 0; idx < value->number_of_si_periodicity; ++idx) + { + if(!(pull8(ppReadPackedMsg, &value->si_periodicity[idx].si_periodicity, end) && + pull8(ppReadPackedMsg, &value->si_periodicity[idx].si_index, end))) + return 0; + } + + if(!(pull8(ppReadPackedMsg, &value->si_window_length, end) && + pull32(ppReadPackedMsg, &value->timeout, end))) + return 0; + + return 1; +} + +static uint8_t unpack_utran_system_information_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_utran_system_information_request_t* value = (nfapi_utran_system_information_request_t*)tlv; + + return (pull16(ppReadPackedMsg, &value->uarfcn, end) && + pull16(ppReadPackedMsg, &value->psc, end) && + pull32(ppReadPackedMsg, &value->timeout, end)); +} + +static uint8_t unpack_geran_system_information_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_geran_system_information_request_t* value = (nfapi_geran_system_information_request_t*)tlv; + + return (pull16(ppReadPackedMsg, &value->arfcn, end) && + pull8(ppReadPackedMsg, &value->bsic, end) && + pull32(ppReadPackedMsg, &value->timeout, end)); +} + +static uint8_t unpack_nb_iot_system_information_request_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nb_iot_system_information_request_t* value = (nfapi_nb_iot_system_information_request_t*)tlv; + uint16_t idx = 0; + + if(!(pull16(ppReadPackedMsg, &value->earfcn, end) && + pull8(ppReadPackedMsg, &value->ro_dl, end) && + pull16(ppReadPackedMsg, &value->pci, end) && + pull8(ppReadPackedMsg, &value->number_of_si_periodicity, end))) + return 0; + + if(value->number_of_si_periodicity > NFAPI_MAX_SI_PERIODICITY) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "More found SI periodicity than we can decode %d \n", value->number_of_si_periodicity); + return 0; + } + + for(idx = 0; idx < value->number_of_si_periodicity; ++idx) + { + if(!(pull8(ppReadPackedMsg, &value->si_periodicity[idx].si_periodicity, end) && + pull8(ppReadPackedMsg, &value->si_periodicity[idx].si_repetition_pattern, end) && + pull8(ppReadPackedMsg, &value->si_periodicity[idx].si_tb_size, end) && + pull8(ppReadPackedMsg, &value->si_periodicity[idx].number_of_si_index, end))) + return 0; + + uint8_t si_idx; + for(si_idx = 0; si_idx < value->si_periodicity[idx].number_of_si_index; ++si_idx) + { + if(!(pull8(ppReadPackedMsg, &value->si_periodicity[idx].si_index[si_idx], end))) + return 0; + + } + } + + if(!(pull8(ppReadPackedMsg, &value->si_window_length, end) && + pull32(ppReadPackedMsg, &value->timeout, end))) + return 0; + + return 1; +} + +static uint8_t unpack_system_information_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_system_information_request_t *pNfapiMsg = (nfapi_system_information_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_LTE_SYSTEM_INFORMATION_REQUEST_TAG, &pNfapiMsg->lte_system_information_request, &unpack_lte_system_information_request_value}, + { NFAPI_UTRAN_SYSTEM_INFORMATION_REQUEST_TAG, &pNfapiMsg->utran_system_information_request, &unpack_utran_system_information_request_value}, + { NFAPI_GERAN_SYSTEM_INFORMATION_REQUEST_TAG, &pNfapiMsg->geran_system_information_request, &unpack_geran_system_information_request_value}, + { NFAPI_NB_IOT_SYSTEM_INFORMATION_REQUEST_TAG, &pNfapiMsg->nb_iot_system_information_request, &unpack_nb_iot_system_information_request_value}, + { NFAPI_PNF_CELL_BROADCAST_STATE_TAG, &pNfapiMsg->pnf_cell_broadcast_state, &unpack_opaque_data_value} + }; + + + int result = (pull8(ppReadPackedMsg, &pNfapiMsg->rat_type, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); + + // Verify that the rat type and the tlv match + if(result == 1 && + !((pNfapiMsg->rat_type == NFAPI_RAT_TYPE_LTE && pNfapiMsg->lte_system_information_request.tl.tag == NFAPI_LTE_SYSTEM_INFORMATION_REQUEST_TAG) || + (pNfapiMsg->rat_type == NFAPI_RAT_TYPE_UTRAN && pNfapiMsg->utran_system_information_request.tl.tag == NFAPI_UTRAN_SYSTEM_INFORMATION_REQUEST_TAG) || + (pNfapiMsg->rat_type == NFAPI_RAT_TYPE_GERAN && pNfapiMsg->geran_system_information_request.tl.tag == NFAPI_GERAN_SYSTEM_INFORMATION_REQUEST_TAG))) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Mismatch RAT Type: %d and TAG value: 0x%04x \n", pNfapiMsg->rat_type, pNfapiMsg->lte_system_information_request.tl.tag); + result = 0; + } + + return result; +} + +static uint8_t unpack_system_information_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_system_information_response_t *pNfapiMsg = (nfapi_system_information_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return (pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_utran_system_information_indication_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_utran_system_information_indication_t* value = (nfapi_utran_system_information_indication_t*)tlv; + + if(pull16(ppReadPackedMsg, &value->sib_length, end) == 0) + return 0; + + if(value->sib_length > NFAPI_MAX_SIB_LENGTH) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "SIB too long %d \n", value->sib_length); + return 0; + } + + if(pullarray8(ppReadPackedMsg, value->sib, NFAPI_MAX_SIB_LENGTH, value->sib_length, end) == 0) + return 0; + + return 1; +} + +static uint8_t unpack_geran_system_information_indication_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_geran_system_information_indication_t* value = (nfapi_geran_system_information_indication_t*)tlv; + + if(pull16(ppReadPackedMsg, &value->si_length, end) == 0) + return 0; + + if(value->si_length > NFAPI_MAX_SI_LENGTH) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "SIB too long %d \n", value->si_length); + return 0; + } + + if(pullarray8(ppReadPackedMsg, value->si, NFAPI_MAX_SI_LENGTH, value->si_length, end) == 0) + return 0; + + return 1; +} + +static uint8_t unpack_system_information_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_system_information_indication_t *pNfapiMsg = (nfapi_system_information_indication_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_LTE_SYSTEM_INFORMATION_INDICATION_TAG, &pNfapiMsg->lte_system_information_indication, &unpack_lte_system_information_indication_value}, + { NFAPI_UTRAN_SYSTEM_INFORMATION_INDICATION_TAG, &pNfapiMsg->utran_system_information_indication, &unpack_utran_system_information_indication_value}, + { NFAPI_GERAN_SYSTEM_INFORMATION_INDICATION_TAG, &pNfapiMsg->geran_system_information_indication, &unpack_geran_system_information_indication_value}, + { NFAPI_NB_IOT_SYSTEM_INFORMATION_INDICATION_TAG, &pNfapiMsg->nb_iot_system_information_indication, &unpack_nb_iot_system_information_indication_value}, + }; + + return (pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); + +} + +static uint8_t unpack_nmm_stop_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_nmm_stop_request_t *pNfapiMsg = (nfapi_nmm_stop_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension); +} + +static uint8_t unpack_nmm_stop_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_nmm_stop_response_t *pNfapiMsg = (nfapi_nmm_stop_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return (pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + + +static int check_unpack_length(nfapi_message_id_e msgId, uint32_t unpackedBufLen) +{ + int retLen = 0; + + switch (msgId) + { + case NFAPI_RSSI_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_rssi_request_t)) + retLen = sizeof(nfapi_rssi_request_t); + break; + + case NFAPI_RSSI_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_rssi_response_t)) + retLen = sizeof(nfapi_rssi_response_t); + break; + + case NFAPI_RSSI_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_rssi_indication_t)) + retLen = sizeof(nfapi_rssi_indication_t); + break; + + case NFAPI_CELL_SEARCH_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_cell_search_request_t)) + retLen = sizeof(nfapi_cell_search_request_t); + break; + + case NFAPI_CELL_SEARCH_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_cell_search_response_t)) + retLen = sizeof(nfapi_cell_search_response_t); + break; + + case NFAPI_CELL_SEARCH_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_cell_search_indication_t)) + retLen = sizeof(nfapi_cell_search_indication_t); + break; + + case NFAPI_BROADCAST_DETECT_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_broadcast_detect_request_t)) + retLen = sizeof(nfapi_broadcast_detect_request_t); + break; + + case NFAPI_BROADCAST_DETECT_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_broadcast_detect_response_t)) + retLen = sizeof(nfapi_broadcast_detect_response_t); + break; + + case NFAPI_BROADCAST_DETECT_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_broadcast_detect_indication_t)) + retLen = sizeof(nfapi_broadcast_detect_indication_t); + break; + + case NFAPI_SYSTEM_INFORMATION_SCHEDULE_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_system_information_schedule_request_t)) + retLen = sizeof(nfapi_system_information_schedule_request_t); + break; + + case NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_system_information_schedule_response_t)) + retLen = sizeof(nfapi_system_information_schedule_response_t); + break; + + case NFAPI_SYSTEM_INFORMATION_SCHEDULE_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_system_information_schedule_indication_t)) + retLen = sizeof(nfapi_system_information_schedule_indication_t); + break; + + case NFAPI_SYSTEM_INFORMATION_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_system_information_request_t)) + retLen = sizeof(nfapi_system_information_request_t); + break; + + case NFAPI_SYSTEM_INFORMATION_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_system_information_response_t)) + retLen = sizeof(nfapi_system_information_response_t); + break; + + case NFAPI_SYSTEM_INFORMATION_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_system_information_indication_t)) + retLen = sizeof(nfapi_system_information_indication_t); + break; + + case NFAPI_NMM_STOP_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_nmm_stop_request_t)) + retLen = sizeof(nfapi_nmm_stop_request_t); + break; + + case NFAPI_NMM_STOP_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_nmm_stop_response_t)) + retLen = sizeof(nfapi_nmm_stop_response_t); + break; + + default: + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unknown message ID %d\n", msgId); + break; + } + + return retLen; +} + +int nfapi_p4_message_pack(void *pMessageBuf, uint32_t messageBufLen, void *pPackedBuf, uint32_t packedBufLen, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_p4_p5_message_header_t *pMessageHeader = pMessageBuf; + uint8_t *end = pPackedBuf + packedBufLen; + uint8_t *pWritePackedMessage = pPackedBuf; + uint8_t *pPackedLengthField = &pWritePackedMessage[4]; + uint32_t packedMsgLen; + uint16_t packedMsgLen16; + + if (pMessageBuf == NULL || pPackedBuf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P4 Pack supplied pointers are null\n"); + return -1; + } + + // process the header + if(!(push16(pMessageHeader->phy_id, &pWritePackedMessage, end) && + push16(pMessageHeader->message_id, &pWritePackedMessage, end) && + push16(0/*pMessageHeader->message_length*/, &pWritePackedMessage, end) && + push16(pMessageHeader->spare, &pWritePackedMessage, end))) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to pack p4 message header\n"); + return -1; + } + + // look for the specific message + uint8_t result = 0; + switch (pMessageHeader->message_id) + { + case NFAPI_RSSI_REQUEST: + result = pack_rssi_request(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_RSSI_RESPONSE: + result = pack_rssi_response(pMessageHeader, &pWritePackedMessage, end,config); + break; + + case NFAPI_RSSI_INDICATION: + result = pack_rssi_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_CELL_SEARCH_REQUEST: + result = pack_cell_search_request(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_CELL_SEARCH_RESPONSE: + result = pack_cell_search_response(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_CELL_SEARCH_INDICATION: + result = pack_cell_search_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_BROADCAST_DETECT_REQUEST: + result = pack_broadcast_detect_request(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_BROADCAST_DETECT_RESPONSE: + result = pack_broadcast_detect_response(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_BROADCAST_DETECT_INDICATION: + result = pack_broadcast_detect_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_SYSTEM_INFORMATION_SCHEDULE_REQUEST: + result = pack_system_information_schedule_request(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE: + result = pack_system_information_schedule_response(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_SYSTEM_INFORMATION_SCHEDULE_INDICATION: + result = pack_system_information_schedule_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_SYSTEM_INFORMATION_REQUEST: + result = pack_system_information_request(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_SYSTEM_INFORMATION_RESPONSE: + result = pack_system_information_response(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_SYSTEM_INFORMATION_INDICATION: + result = pack_system_information_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_NMM_STOP_REQUEST: + result = pack_nmm_stop_request(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_NMM_STOP_RESPONSE: + result = pack_nmm_stop_response(pMessageHeader, &pWritePackedMessage, end, config); + break; + + default: + { + if(pMessageHeader->message_id >= NFAPI_VENDOR_EXT_MSG_MIN && + pMessageHeader->message_id <= NFAPI_VENDOR_EXT_MSG_MIN) + { + if(config && config->pack_p4_p5_vendor_extension) + { + result =(config->pack_p4_p5_vendor_extension)(pMessageHeader, &pWritePackedMessage, end, config); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s VE NFAPI message ID %d. No ve encoder provided\n", __FUNCTION__, pMessageHeader->message_id); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s NFAPI Unknown message ID %d\n", __FUNCTION__, pMessageHeader->message_id); + } + } + break; + } + + // return the packed length + if(result == 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Result is 0\n"); + return -1; + } + + + // check for a valid message length + packedMsgLen = get_packed_msg_len((uintptr_t)pPackedBuf, (uintptr_t)pWritePackedMessage); + if (packedMsgLen > 0xFFFF || packedMsgLen > packedBufLen) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Packed message length error %d, buffer supplied %d\n", packedMsgLen, packedBufLen); + return -1; + } + else + { + packedMsgLen16 = (uint16_t)packedMsgLen; + } + + // Update the message length in the header + if(push16(packedMsgLen16, &pPackedLengthField, end) == 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to pack p4 message header lengt\n"); + return -1; + } + + return (packedMsgLen); + +} + +// Main unpack functions - public + +int nfapi_p4_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_p4_p5_message_header_t *pMessageHeader = pUnpackedBuf; + uint8_t *pReadPackedMessage = pMessageBuf; + uint8_t *end = pMessageBuf + messageBufLen; + + if (pMessageBuf == NULL || pUnpackedBuf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P4 header unpack supplied pointers are null\n"); + return -1; + } + + if (messageBufLen < NFAPI_HEADER_LENGTH || unpackedBufLen < sizeof(nfapi_p4_p5_message_header_t)) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P5 header unpack supplied message buffer is too small %d, %d\n", messageBufLen, unpackedBufLen); + return -1; + } + + // process the headei + if (pull16(&pReadPackedMessage, &pMessageHeader->phy_id, end) && + pull16(&pReadPackedMessage, &pMessageHeader->message_id, end) && + pull16(&pReadPackedMessage, &pMessageHeader->message_length, end) && + pull16(&pReadPackedMessage, &pMessageHeader->spare, end)) + return -1; + + return 0; +} + +int nfapi_p4_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t* config) +{ + int result = 0; + nfapi_p4_p5_message_header_t *pMessageHeader = pUnpackedBuf; + uint8_t *pReadPackedMessage = pMessageBuf; + uint8_t *end = pMessageBuf + messageBufLen; + + if (pMessageBuf == NULL || pUnpackedBuf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P4 unpack supplied pointers are null\n"); + return -1; + } + + if (messageBufLen < NFAPI_HEADER_LENGTH || unpackedBufLen < sizeof(nfapi_p4_p5_message_header_t)) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P4 unpack supplied message buffer is too small %d, %d\n", messageBufLen, unpackedBufLen); + return -1; + } + + // clean the supplied buffer for - tag value blanking + (void)memset(pUnpackedBuf, 0, unpackedBufLen); + + // process the header + if(!(pull16(&pReadPackedMessage, &pMessageHeader->phy_id, end) && + pull16(&pReadPackedMessage, &pMessageHeader->message_id, end) && + pull16(&pReadPackedMessage, &pMessageHeader->message_length, end) && + pull16(&pReadPackedMessage, &pMessageHeader->spare, end))) + return -1; + + // look for the specific message + switch (pMessageHeader->message_id) + { + case NFAPI_RSSI_REQUEST: + if (check_unpack_length(NFAPI_RSSI_REQUEST, unpackedBufLen)) + result = unpack_rssi_request(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_RSSI_RESPONSE: + if (check_unpack_length(NFAPI_RSSI_RESPONSE, unpackedBufLen)) + result = unpack_rssi_response(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_RSSI_INDICATION: + if (check_unpack_length(NFAPI_RSSI_INDICATION, unpackedBufLen)) + result = unpack_rssi_indication(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_CELL_SEARCH_REQUEST: + if (check_unpack_length(NFAPI_CELL_SEARCH_REQUEST, unpackedBufLen)) + result = unpack_cell_search_request(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_CELL_SEARCH_RESPONSE: + if (check_unpack_length(NFAPI_CELL_SEARCH_RESPONSE, unpackedBufLen)) + result = unpack_cell_search_response(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_CELL_SEARCH_INDICATION: + if (check_unpack_length(NFAPI_CELL_SEARCH_INDICATION, unpackedBufLen)) + result = unpack_cell_search_indication(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_BROADCAST_DETECT_REQUEST: + if (check_unpack_length(NFAPI_BROADCAST_DETECT_REQUEST, unpackedBufLen)) + result = unpack_broadcast_detect_request(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_BROADCAST_DETECT_RESPONSE: + if (check_unpack_length(NFAPI_BROADCAST_DETECT_RESPONSE, unpackedBufLen)) + result = unpack_broadcast_detect_response(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_BROADCAST_DETECT_INDICATION: + if (check_unpack_length(NFAPI_BROADCAST_DETECT_INDICATION, unpackedBufLen)) + result = unpack_broadcast_detect_indication(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_SYSTEM_INFORMATION_SCHEDULE_REQUEST: + if (check_unpack_length(NFAPI_SYSTEM_INFORMATION_SCHEDULE_REQUEST, unpackedBufLen)) + result = unpack_system_information_schedule_request(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE: + if (check_unpack_length(NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE, unpackedBufLen)) + result = unpack_system_information_schedule_response(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_SYSTEM_INFORMATION_SCHEDULE_INDICATION: + if (check_unpack_length(NFAPI_SYSTEM_INFORMATION_SCHEDULE_INDICATION, unpackedBufLen)) + result = unpack_system_information_schedule_indication(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_SYSTEM_INFORMATION_REQUEST: + if (check_unpack_length(NFAPI_SYSTEM_INFORMATION_REQUEST, unpackedBufLen)) + result = unpack_system_information_request(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_SYSTEM_INFORMATION_RESPONSE: + if (check_unpack_length(NFAPI_SYSTEM_INFORMATION_RESPONSE, unpackedBufLen)) + result = unpack_system_information_response(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_SYSTEM_INFORMATION_INDICATION: + if (check_unpack_length(NFAPI_SYSTEM_INFORMATION_INDICATION, unpackedBufLen)) + result = unpack_system_information_indication(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_NMM_STOP_REQUEST: + if (check_unpack_length(NFAPI_NMM_STOP_REQUEST, unpackedBufLen)) + result = unpack_nmm_stop_request(&pReadPackedMessage, end, pMessageHeader, config); + else + result = -1; + break; + + case NFAPI_NMM_STOP_RESPONSE: + if (check_unpack_length(NFAPI_NMM_STOP_RESPONSE, unpackedBufLen)) + result = unpack_nmm_stop_response(&pReadPackedMessage, end , pMessageHeader, config); + else + result = -1; + break; + + default: + if(pMessageHeader->message_id >= NFAPI_VENDOR_EXT_MSG_MIN && + pMessageHeader->message_id <= NFAPI_VENDOR_EXT_MSG_MAX) + { + if(config && config->unpack_p4_p5_vendor_extension) + { + result = (config->unpack_p4_p5_vendor_extension)(pMessageHeader, &pReadPackedMessage, end, config); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s VE NFAPI message ID %d. No ve decoder provided\n", __FUNCTION__, pMessageHeader->message_id); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s NFAPI Unknown P4 message ID %d\n", __FUNCTION__, pMessageHeader->message_id); + } + break; + } + + if(result == 0) + return -1; + + return result; +} diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c new file mode 100644 index 0000000000..b3b9b53491 --- /dev/null +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c @@ -0,0 +1,1799 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +// Pack routines + +static uint8_t pack_pnf_param_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t* end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_param_request_t* request = (nfapi_pnf_param_request_t*)msg; + return pack_vendor_extension_tlv(request->vendor_extension, ppWritePackedMsg, end, config); +} + +static uint8_t pack_pnf_param_general_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_pnf_param_general_t* value = (nfapi_pnf_param_general_t*)tlv; + + return ( push8(value->nfapi_sync_mode, ppWritePackedMsg, end) && + push8(value->location_mode, ppWritePackedMsg, end) && + push16(value->location_coordinates_length, ppWritePackedMsg, end) && + pusharray8(value->location_coordinates, NFAPI_PNF_PARAM_GENERAL_LOCATION_LENGTH, value->location_coordinates_length, ppWritePackedMsg, end) && + push32(value->dl_config_timing, ppWritePackedMsg, end) && + push32(value->tx_timing, ppWritePackedMsg, end) && + push32(value->ul_config_timing, ppWritePackedMsg, end) && + push32(value->hi_dci0_timing, ppWritePackedMsg, end) && + push16(value->maximum_number_phys, ppWritePackedMsg, end) && + push16(value->maximum_total_bandwidth, ppWritePackedMsg, end) && + push8(value->maximum_total_number_dl_layers, ppWritePackedMsg, end) && + push8(value->maximum_total_number_ul_layers, ppWritePackedMsg, end) && + push8(value->shared_bands, ppWritePackedMsg, end) && + push8(value->shared_pa, ppWritePackedMsg, end) && + pushs16(value->maximum_total_power, ppWritePackedMsg, end) && + pusharray8(value->oui, NFAPI_PNF_PARAM_GENERAL_OUI_LENGTH, NFAPI_PNF_PARAM_GENERAL_OUI_LENGTH, ppWritePackedMsg, end)); +} + +static uint8_t pack_rf_config_info(void* elem, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_rf_config_info_t* rf = (nfapi_rf_config_info_t*)elem; + + return (push16(rf->rf_config_index, ppWritePackedMsg, end)); +} + + +static uint8_t pack_pnf_phy_info(void* elem, uint8_t **ppWritePackedMsg, uint8_t* end) +{ + nfapi_pnf_phy_info_t* phy = (nfapi_pnf_phy_info_t*)elem; + + return ( push16(phy->phy_config_index, ppWritePackedMsg, end) && + push16(phy->number_of_rfs, ppWritePackedMsg, end) && + packarray(phy->rf_config, sizeof(nfapi_rf_config_info_t), NFAPI_MAX_PNF_PHY_RF_CONFIG, phy->number_of_rfs, ppWritePackedMsg, end, &pack_rf_config_info) && + push16(phy->number_of_rf_exclusions, ppWritePackedMsg, end) && + packarray(phy->excluded_rf_config, sizeof(nfapi_rf_config_info_t), NFAPI_MAX_PNF_PHY_RF_CONFIG, phy->number_of_rf_exclusions, ppWritePackedMsg, end, &pack_rf_config_info) && + push16(phy->downlink_channel_bandwidth_supported, ppWritePackedMsg, end) && + push16(phy->uplink_channel_bandwidth_supported, ppWritePackedMsg, end) && + push8(phy->number_of_dl_layers_supported, ppWritePackedMsg, end) && + push8(phy->number_of_ul_layers_supported, ppWritePackedMsg, end) && + push16(phy->maximum_3gpp_release_supported, ppWritePackedMsg, end) && + push8(phy->nmm_modes_supported, ppWritePackedMsg, end)); + + +} + +static uint8_t pack_pnf_phy_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_t* value = (nfapi_pnf_phy_t*)tlv; + + return ( push16(value->number_of_phys, ppWritePackedMsg, end) && + packarray(value->phy, sizeof(nfapi_pnf_phy_info_t), NFAPI_MAX_PNF_PHY, value->number_of_phys, ppWritePackedMsg, end, &pack_pnf_phy_info)); +} + +static uint8_t pack_pnf_rf_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_pnf_rf_t* value = (nfapi_pnf_rf_t*)tlv; + uint16_t rf_index = 0; + + if(push16(value->number_of_rfs, ppWritePackedMsg, end) == 0) + return 0; + + for(; rf_index < value->number_of_rfs; ++rf_index) + { + if( !(push16(value->rf[rf_index].rf_config_index, ppWritePackedMsg, end) && + push16(value->rf[rf_index].band, ppWritePackedMsg, end) && + pushs16(value->rf[rf_index].maximum_transmit_power, ppWritePackedMsg, end) && + pushs16(value->rf[rf_index].minimum_transmit_power, ppWritePackedMsg, end) && + push8(value->rf[rf_index].number_of_antennas_suppported, ppWritePackedMsg, end) && + push32(value->rf[rf_index].minimum_downlink_frequency, ppWritePackedMsg, end) && + push32(value->rf[rf_index].maximum_downlink_frequency, ppWritePackedMsg, end) && + push32(value->rf[rf_index].minimum_uplink_frequency, ppWritePackedMsg, end) && + push32(value->rf[rf_index].maximum_uplink_frequency, ppWritePackedMsg, end))) + return 0; + } + + return 1; +} +static uint8_t pack_pnf_phy_rel10_info(void* elem, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel10_info_t* phy = (nfapi_pnf_phy_rel10_info_t*)elem; + + return(push16(phy->phy_config_index, ppWritePackedMsg, end) && + push16(phy->transmission_mode_7_supported, ppWritePackedMsg, end) && + push16(phy->transmission_mode_8_supported, ppWritePackedMsg, end) && + push16(phy->two_antenna_ports_for_pucch, ppWritePackedMsg, end) && + push16(phy->transmission_mode_9_supported, ppWritePackedMsg, end) && + push16(phy->simultaneous_pucch_pusch, ppWritePackedMsg, end) && + push16(phy->four_layer_tx_with_tm3_and_tm4, ppWritePackedMsg, end)); +} + +static uint8_t pack_pnf_phy_rel10_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel10_t* value = (nfapi_pnf_phy_rel10_t*)tlv; + + return (push16(value->number_of_phys, ppWritePackedMsg, end) && + packarray(value->phy, sizeof(nfapi_pnf_phy_rel10_info_t), NFAPI_MAX_PNF_PHY, value->number_of_phys, ppWritePackedMsg, end, &pack_pnf_phy_rel10_info)); + +} + +static uint8_t pack_pnf_phy_rel11_info(void* elem, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel11_info_t* phy = (nfapi_pnf_phy_rel11_info_t*)elem; + + return (push16(phy->phy_config_index, ppWritePackedMsg, end) && + push16(phy->edpcch_supported, ppWritePackedMsg, end) && + push16(phy->multi_ack_csi_reporting, ppWritePackedMsg, end) && + push16(phy->pucch_tx_diversity, ppWritePackedMsg, end) && + push16(phy->ul_comp_supported, ppWritePackedMsg, end) && + push16(phy->transmission_mode_5_supported, ppWritePackedMsg, end )); +} +static uint8_t pack_pnf_phy_rel11_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel11_t* value = (nfapi_pnf_phy_rel11_t*)tlv; + + return (push16(value->number_of_phys, ppWritePackedMsg, end) && + packarray(value->phy, sizeof(nfapi_pnf_phy_rel11_info_t), NFAPI_MAX_PNF_PHY, value->number_of_phys, ppWritePackedMsg, end, &pack_pnf_phy_rel11_info)); +} +static uint8_t pack_pnf_phy_rel12_info(void* elem, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel12_info_t* phy = (nfapi_pnf_phy_rel12_info_t*)elem; + + return( push16(phy->phy_config_index, ppWritePackedMsg, end) && + push16(phy->csi_subframe_set, ppWritePackedMsg, end) && + push16(phy->enhanced_4tx_codebook, ppWritePackedMsg, end) && + push16(phy->drs_supported, ppWritePackedMsg, end) && + push16(phy->ul_64qam_supported, ppWritePackedMsg, end) && + push16(phy->transmission_mode_10_supported, ppWritePackedMsg, end) && + push16(phy->alternative_bts_indices, ppWritePackedMsg, end)); +} +static uint8_t pack_pnf_phy_rel12_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel12_t* value = (nfapi_pnf_phy_rel12_t*)tlv; + + return (push16(value->number_of_phys, ppWritePackedMsg, end) && + packarray(value->phy, sizeof(nfapi_pnf_phy_rel12_info_t), NFAPI_MAX_PNF_PHY, value->number_of_phys, ppWritePackedMsg, end, &pack_pnf_phy_rel12_info)); + +} + +static uint8_t pack_pnf_phy_rel13_info(void* elem, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel13_info_t* phy = (nfapi_pnf_phy_rel13_info_t*)elem; + + return( push16(phy->phy_config_index, ppWritePackedMsg, end) && + push16(phy->pucch_format4_supported, ppWritePackedMsg, end) && + push16(phy->pucch_format5_supported, ppWritePackedMsg, end) && + push16(phy->more_than_5_ca_support, ppWritePackedMsg, end) && + push16(phy->laa_supported, ppWritePackedMsg, end) && + push16(phy->laa_ending_in_dwpts_supported, ppWritePackedMsg, end) && + push16(phy->laa_starting_in_second_slot_supported, ppWritePackedMsg, end) && + push16(phy->beamforming_supported, ppWritePackedMsg, end) && + push16(phy->csi_rs_enhancement_supported, ppWritePackedMsg, end) && + push16(phy->drms_enhancement_supported, ppWritePackedMsg, end) && + push16(phy->srs_enhancement_supported, ppWritePackedMsg, end) ); +} + +static uint8_t pack_pnf_phy_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel13_t* value = (nfapi_pnf_phy_rel13_t*)tlv; + + return (push16(value->number_of_phys, ppWritePackedMsg, end) && + packarray(value->phy, sizeof(nfapi_pnf_phy_rel13_info_t), NFAPI_MAX_PNF_PHY, value->number_of_phys, ppWritePackedMsg, end, &pack_pnf_phy_rel13_info)); +} + +static uint8_t pack_pnf_phy_rel13_nb_iot_info(void* elem, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel13_nb_iot_info_t* phy = (nfapi_pnf_phy_rel13_nb_iot_info_t*)elem; + + return( push16(phy->phy_config_index, ppWritePackedMsg, end) && + push16(phy->number_of_rfs, ppWritePackedMsg, end) && + packarray(phy->rf_config, sizeof(nfapi_rf_config_info_t), NFAPI_MAX_PNF_PHY_RF_CONFIG, phy->number_of_rfs, ppWritePackedMsg, end, &pack_rf_config_info) && + push16(phy->number_of_rf_exclusions, ppWritePackedMsg, end) && + packarray(phy->excluded_rf_config, sizeof(nfapi_rf_config_info_t), NFAPI_MAX_PNF_PHY_RF_CONFIG, phy->number_of_rf_exclusions, ppWritePackedMsg, end, &pack_rf_config_info) && + push8(phy->number_of_dl_layers_supported, ppWritePackedMsg, end) && + push8(phy->number_of_ul_layers_supported, ppWritePackedMsg, end) && + push16(phy->maximum_3gpp_release_supported, ppWritePackedMsg, end) && + push8(phy->nmm_modes_supported, ppWritePackedMsg, end)); +} + +static uint8_t pack_pnf_phy_rel13_nb_iot_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel13_nb_iot_t* value = (nfapi_pnf_phy_rel13_nb_iot_t*)tlv; + + return (push16(value->number_of_phys, ppWritePackedMsg, end) && + packarray(value->phy, sizeof(nfapi_pnf_phy_rel13_nb_iot_info_t), NFAPI_MAX_PNF_PHY, value->number_of_phys, ppWritePackedMsg, end, &pack_pnf_phy_rel13_nb_iot_info)); +} + + +static uint8_t pack_pnf_param_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_param_response_t *pNfapiMsg = (nfapi_pnf_param_response_t*)msg; + + return (push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_tlv(NFAPI_PNF_PARAM_GENERAL_TAG, &pNfapiMsg->pnf_param_general, ppWritePackedMsg, end, &pack_pnf_param_general_value) && + pack_tlv(NFAPI_PNF_PHY_TAG, &pNfapiMsg->pnf_phy, ppWritePackedMsg, end, &pack_pnf_phy_value) && + pack_tlv(NFAPI_PNF_RF_TAG, &pNfapiMsg->pnf_rf, ppWritePackedMsg, end, &pack_pnf_rf_value) && + pack_tlv(NFAPI_PNF_PHY_REL10_TAG, &pNfapiMsg->pnf_phy_rel10, ppWritePackedMsg, end, &pack_pnf_phy_rel10_value) && + pack_tlv(NFAPI_PNF_PHY_REL11_TAG, &pNfapiMsg->pnf_phy_rel11, ppWritePackedMsg, end, &pack_pnf_phy_rel11_value) && + pack_tlv(NFAPI_PNF_PHY_REL12_TAG, &pNfapiMsg->pnf_phy_rel12, ppWritePackedMsg, end, &pack_pnf_phy_rel12_value) && + pack_tlv(NFAPI_PNF_PHY_REL13_TAG, &pNfapiMsg->pnf_phy_rel13, ppWritePackedMsg, end, &pack_pnf_phy_rel13_value) && + pack_tlv(NFAPI_PNF_PHY_REL13_NB_IOT_TAG, &pNfapiMsg->pnf_phy_rel13_nb_iot, ppWritePackedMsg, end, &pack_pnf_phy_rel13_nb_iot_value) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_phy_rf_config_info(void* elem, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_phy_rf_config_info_t* rf = (nfapi_phy_rf_config_info_t*)elem; + + return (push16(rf->phy_id, ppWritePackedMsg, end) && + push16(rf->phy_config_index, ppWritePackedMsg, end) && + push16(rf->rf_config_index, ppWritePackedMsg, end)); +} + + +static uint8_t pack_pnf_phy_rf_config_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rf_config_t *value = (nfapi_pnf_phy_rf_config_t*)tlv; + + return(push16(value->number_phy_rf_config_info, ppWritePackedMsg, end) && + packarray(value->phy_rf_config, sizeof(nfapi_phy_rf_config_info_t), NFAPI_MAX_PHY_RF_INSTANCES, value->number_phy_rf_config_info, ppWritePackedMsg, end, &pack_phy_rf_config_info)); + +} + +static uint8_t pack_pnf_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_config_request_t *pNfapiMsg = (nfapi_pnf_config_request_t*)msg; + return ( pack_tlv(NFAPI_PNF_PHY_RF_TAG, &pNfapiMsg->pnf_phy_rf_config, ppWritePackedMsg, end, &pack_pnf_phy_rf_config_value) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end , config)); +} + + +static uint8_t pack_pnf_config_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t* end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_config_response_t *pNfapiMsg = (nfapi_pnf_config_response_t*)msg; + + return ( push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_pnf_start_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t* end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_start_request_t *pNfapiMsg = (nfapi_pnf_start_request_t*)msg; + return ( pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_pnf_start_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t* end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_start_response_t *pNfapiMsg = (nfapi_pnf_start_response_t*)msg; + + return( push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_pnf_stop_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t* end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_stop_request_t *pNfapiMsg = (nfapi_pnf_stop_request_t*)msg; + return ( pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config) ); +} + +static uint8_t pack_pnf_stop_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t* end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_stop_response_t *pNfapiMsg = (nfapi_pnf_stop_response_t*)msg; + + return ( push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_param_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t* end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_param_request_t *pNfapiMsg = (nfapi_param_request_t*)msg; + return (pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_uint16_tlv_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_uint16_tlv_t* value = (nfapi_uint16_tlv_t*)tlv; + return push16(value->value, ppWritePackedMsg, end); +} + +static uint8_t unpack_uint16_tlv_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_uint16_tlv_t* value = (nfapi_uint16_tlv_t*)tlv; + return pull16(ppReadPackedMsg, &value->value, end); +} +static uint8_t pack_int16_tlv_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_int16_tlv_t* value = (nfapi_int16_tlv_t*)tlv; + return pushs16(value->value, ppWritePackedMsg, end); +} + +static uint8_t unpack_int16_tlv_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_int16_tlv_t* value = (nfapi_int16_tlv_t*)tlv; + return pulls16(ppReadPackedMsg, &value->value, end); +} + +static uint8_t pack_uint8_tlv_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_uint8_tlv_t* value = (nfapi_uint8_tlv_t*)tlv; + return push8(value->value, ppWritePackedMsg, end); +} +static uint8_t unpack_uint8_tlv_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_uint8_tlv_t* value = (nfapi_uint8_tlv_t*)tlv; + return pull8(ppReadPackedMsg, &value->value, end); +} + +static uint8_t pack_ipv4_address_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ipv4_address_t* value = (nfapi_ipv4_address_t*)tlv; + return pusharray8(value->address, NFAPI_IPV4_ADDRESS_LENGTH, NFAPI_IPV4_ADDRESS_LENGTH, ppWritePackedMsg, end); +} +static uint8_t unpack_ipv4_address_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ipv4_address_t* value = (nfapi_ipv4_address_t*)tlv; + return pullarray8(ppReadPackedMsg, value->address, NFAPI_IPV4_ADDRESS_LENGTH, NFAPI_IPV4_ADDRESS_LENGTH, end); +} +static uint8_t pack_ipv6_address_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ipv6_address_t* value = (nfapi_ipv6_address_t*)tlv; + return pusharray8(value->address, NFAPI_IPV6_ADDRESS_LENGTH, NFAPI_IPV6_ADDRESS_LENGTH, ppWritePackedMsg, end); +} +static uint8_t unpack_ipv6_address_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ipv4_address_t* value = (nfapi_ipv4_address_t*)tlv; + return pullarray8(ppReadPackedMsg, value->address, NFAPI_IPV6_ADDRESS_LENGTH, NFAPI_IPV6_ADDRESS_LENGTH, end); +} + +static uint8_t pack_rf_bands_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_rf_bands_t* value = (nfapi_rf_bands_t*)tlv; + + return ( push16(value->number_rf_bands, ppWritePackedMsg, end) && + pusharray16(value->rf_band, NFAPI_MAX_NUM_RF_BANDS, value->number_rf_bands, ppWritePackedMsg, end)); +} +static uint8_t unpack_rf_bands_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t* end) +{ + nfapi_rf_bands_t* value = (nfapi_rf_bands_t*)tlv; + + return ( pull16(ppReadPackedMsg, &value->number_rf_bands, end) && + pullarray16(ppReadPackedMsg, value->rf_band, NFAPI_MAX_NUM_RF_BANDS, value->number_rf_bands, end)); +} + +static uint8_t pack_nmm_frequency_bands_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nmm_frequency_bands_t* value = (nfapi_nmm_frequency_bands_t*)tlv; + + return( push16(value->number_of_rf_bands, ppWritePackedMsg, end) && + pusharray16(value->bands, NFAPI_MAX_NMM_FREQUENCY_BANDS, value->number_of_rf_bands, ppWritePackedMsg, end)); +} +static uint8_t unpack_nmm_frequency_bands_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nmm_frequency_bands_t* value = (nfapi_nmm_frequency_bands_t*)tlv; + + return ( pull16(ppReadPackedMsg, &value->number_of_rf_bands, end) && + pullarray16(ppReadPackedMsg, value->bands, NFAPI_MAX_NMM_FREQUENCY_BANDS, value->number_of_rf_bands, end)); +} + +static uint8_t pack_param_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_param_response_t *pNfapiMsg = (nfapi_param_response_t*)msg; + + return( push8(pNfapiMsg->error_code, ppWritePackedMsg, end) && + push8(pNfapiMsg->num_tlv, ppWritePackedMsg, end) && + pack_tlv(NFAPI_L1_STATUS_PHY_STATE_TAG, &pNfapiMsg->l1_status.phy_state, ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + // Do we check the phy state and then just fill those sepecified, however + // we do not know the duplex mode, so just attempt to pack all and assumme + // that the callee has set the right tlvs + + pack_tlv(NFAPI_PHY_CAPABILITIES_DL_BANDWIDTH_SUPPORT_TAG, &(pNfapiMsg->phy_capabilities.dl_bandwidth_support), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PHY_CAPABILITIES_UL_BANDWIDTH_SUPPORT_TAG, &(pNfapiMsg->phy_capabilities.ul_bandwidth_support), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PHY_CAPABILITIES_DL_MODULATION_SUPPORT_TAG, &(pNfapiMsg->phy_capabilities.dl_modulation_support), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PHY_CAPABILITIES_UL_MODULATION_SUPPORT_TAG, &(pNfapiMsg->phy_capabilities.ul_modulation_support), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PHY_CAPABILITIES_PHY_ANTENNA_CAPABILITY_TAG, &(pNfapiMsg->phy_capabilities.phy_antenna_capability), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PHY_CAPABILITIES_RELEASE_CAPABILITY_TAG, &(pNfapiMsg->phy_capabilities.release_capability), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PHY_CAPABILITIES_MBSFN_CAPABILITY_TAG, &(pNfapiMsg->phy_capabilities.mbsfn_capability), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + // laa capability + + pack_tlv(NFAPI_SUBFRAME_CONFIG_DUPLEX_MODE_TAG, &(pNfapiMsg->subframe_config.duplex_mode), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SUBFRAME_CONFIG_PCFICH_POWER_OFFSET_TAG, &(pNfapiMsg->subframe_config.pcfich_power_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value)&& + pack_tlv(NFAPI_SUBFRAME_CONFIG_PB_TAG, &(pNfapiMsg->subframe_config.pb), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SUBFRAME_CONFIG_DL_CYCLIC_PREFIX_TYPE_TAG, &(pNfapiMsg->subframe_config.dl_cyclic_prefix_type), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SUBFRAME_CONFIG_UL_CYCLIC_PREFIX_TYPE_TAG, &(pNfapiMsg->subframe_config.ul_cyclic_prefix_type), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG, &(pNfapiMsg->rf_config.dl_channel_bandwidth), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_RF_CONFIG_UL_CHANNEL_BANDWIDTH_TAG, &(pNfapiMsg->rf_config.ul_channel_bandwidth), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_RF_CONFIG_REFERENCE_SIGNAL_POWER_TAG, &(pNfapiMsg->rf_config.reference_signal_power), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_RF_CONFIG_TX_ANTENNA_PORTS_TAG, &(pNfapiMsg->rf_config.tx_antenna_ports), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_RF_CONFIG_RX_ANTENNA_PORTS_TAG, &(pNfapiMsg->rf_config.rx_antenna_ports), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_PHICH_CONFIG_PHICH_RESOURCE_TAG, &(pNfapiMsg->phich_config.phich_resource), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PHICH_CONFIG_PHICH_DURATION_TAG, &(pNfapiMsg->phich_config.phich_duration), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG, &(pNfapiMsg->phich_config.phich_power_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_SCH_CONFIG_PRIMARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG, &(pNfapiMsg->sch_config.primary_synchronization_signal_epre_eprers), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SCH_CONFIG_SECONDARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG, &(pNfapiMsg->sch_config.secondary_synchronization_signal_epre_eprers), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SCH_CONFIG_PHYSICAL_CELL_ID_TAG, &(pNfapiMsg->sch_config.physical_cell_id), ppWritePackedMsg, end ,&pack_uint16_tlv_value) && + + pack_tlv(NFAPI_PRACH_CONFIG_CONFIGURATION_INDEX_TAG, &(pNfapiMsg->prach_config.configuration_index), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PRACH_CONFIG_ROOT_SEQUENCE_INDEX_TAG, &(pNfapiMsg->prach_config.root_sequence_index), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PRACH_CONFIG_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG, &(pNfapiMsg->prach_config.zero_correlation_zone_configuration), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PRACH_CONFIG_HIGH_SPEED_FLAG_TAG, &(pNfapiMsg->prach_config.high_speed_flag), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PRACH_CONFIG_FREQUENCY_OFFSET_TAG, &(pNfapiMsg->prach_config.frequency_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_PUSCH_CONFIG_HOPPING_MODE_TAG, &(pNfapiMsg->pusch_config.hopping_mode), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PUSCH_CONFIG_HOPPING_OFFSET_TAG, &(pNfapiMsg->pusch_config.hopping_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PUSCH_CONFIG_NUMBER_OF_SUBBANDS_TAG, &(pNfapiMsg->pusch_config.number_of_subbands), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_PUCCH_CONFIG_DELTA_PUCCH_SHIFT_TAG, &(pNfapiMsg->pucch_config.delta_pucch_shift), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PUCCH_CONFIG_N_CQI_RB_TAG, &(pNfapiMsg->pucch_config.n_cqi_rb), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PUCCH_CONFIG_N_AN_CS_TAG, &(pNfapiMsg->pucch_config.n_an_cs), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PUCCH_CONFIG_N1_PUCCH_AN_TAG, &(pNfapiMsg->pucch_config.n1_pucch_an), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_SRS_CONFIG_BANDWIDTH_CONFIGURATION_TAG, &(pNfapiMsg->srs_config.bandwidth_configuration), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SRS_CONFIG_MAX_UP_PTS_TAG, &(pNfapiMsg->srs_config.max_up_pts), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SRS_CONFIG_SRS_SUBFRAME_CONFIGURATION_TAG, &(pNfapiMsg->srs_config.srs_subframe_configuration), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SRS_CONFIG_SRS_ACKNACK_SRS_SIMULTANEOUS_TRANSMISSION_TAG, &(pNfapiMsg->srs_config.srs_acknack_srs_simultaneous_transmission), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_UPLINK_RS_HOPPING_TAG, &(pNfapiMsg->uplink_reference_signal_config.uplink_rs_hopping), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_GROUP_ASSIGNMENT_TAG, &(pNfapiMsg->uplink_reference_signal_config.group_assignment), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_CYCLIC_SHIFT_1_FOR_DRMS_TAG, &(pNfapiMsg->uplink_reference_signal_config.cyclic_shift_1_for_drms), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_TDD_FRAME_STRUCTURE_SUBFRAME_ASSIGNMENT_TAG, &(pNfapiMsg->tdd_frame_structure_config.subframe_assignment), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_TDD_FRAME_STRUCTURE_SPECIAL_SUBFRAME_PATTERNS_TAG, &(pNfapiMsg->tdd_frame_structure_config.special_subframe_patterns), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_L23_CONFIG_DATA_REPORT_MODE_TAG, &(pNfapiMsg->l23_config.data_report_mode), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_L23_CONFIG_SFNSF_TAG, &(pNfapiMsg->l23_config.sfnsf), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_NFAPI_P7_VNF_ADDRESS_IPV4_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv4), ppWritePackedMsg, end, &pack_ipv4_address_value) && + pack_tlv(NFAPI_NFAPI_P7_VNF_ADDRESS_IPV6_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv6), ppWritePackedMsg, end, &pack_ipv6_address_value) && + + pack_tlv(NFAPI_NFAPI_P7_VNF_PORT_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_port), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_NFAPI_P7_PNF_ADDRESS_IPV4_TAG, &(pNfapiMsg->nfapi_config.p7_pnf_address_ipv4), ppWritePackedMsg, end, &pack_ipv4_address_value) && + pack_tlv(NFAPI_NFAPI_P7_PNF_ADDRESS_IPV6_TAG, &(pNfapiMsg->nfapi_config.p7_pnf_address_ipv6), ppWritePackedMsg, end, &pack_ipv6_address_value) && + + pack_tlv(NFAPI_NFAPI_P7_PNF_PORT_TAG, &(pNfapiMsg->nfapi_config.p7_pnf_port), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_NFAPI_DOWNLINK_UES_PER_SUBFRAME_TAG, &(pNfapiMsg->nfapi_config.dl_ue_per_sf), ppWritePackedMsg, end, &pack_uint8_tlv_value) && + pack_tlv(NFAPI_NFAPI_UPLINK_UES_PER_SUBFRAME_TAG, &(pNfapiMsg->nfapi_config.ul_ue_per_sf), ppWritePackedMsg, end, &pack_uint8_tlv_value) && + + pack_tlv(NFAPI_NFAPI_RF_BANDS_TAG, &(pNfapiMsg->nfapi_config.rf_bands), ppWritePackedMsg, end, &pack_rf_bands_value) && + + pack_tlv(NFAPI_NFAPI_TIMING_WINDOW_TAG, &(pNfapiMsg->nfapi_config.timing_window), ppWritePackedMsg, end, &pack_uint8_tlv_value) && + pack_tlv(NFAPI_NFAPI_TIMING_INFO_MODE_TAG, &(pNfapiMsg->nfapi_config.timing_info_mode), ppWritePackedMsg, end, &pack_uint8_tlv_value) && + pack_tlv(NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG, &(pNfapiMsg->nfapi_config.timing_info_period), ppWritePackedMsg, end, &pack_uint8_tlv_value) && + + pack_tlv(NFAPI_NFAPI_MAXIMUM_TRANSMIT_POWER_TAG, &(pNfapiMsg->nfapi_config.max_transmit_power), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_NFAPI_EARFCN_TAG, &(pNfapiMsg->nfapi_config.earfcn), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + + pack_tlv(NFAPI_NFAPI_NMM_GSM_FREQUENCY_BANDS_TAG, &(pNfapiMsg->nfapi_config.nmm_gsm_frequency_bands), ppWritePackedMsg, end, &pack_nmm_frequency_bands_value) && + pack_tlv(NFAPI_NFAPI_NMM_UMTS_FREQUENCY_BANDS_TAG, &(pNfapiMsg->nfapi_config.nmm_umts_frequency_bands), ppWritePackedMsg, end, &pack_nmm_frequency_bands_value) && + pack_tlv(NFAPI_NFAPI_NMM_LTE_FREQUENCY_BANDS_TAG, &(pNfapiMsg->nfapi_config.nmm_lte_frequency_bands), ppWritePackedMsg, end, &pack_nmm_frequency_bands_value) && + pack_tlv(NFAPI_NFAPI_NMM_UPLINK_RSSI_SUPPORTED_TAG, &(pNfapiMsg->nfapi_config.nmm_uplink_rssi_supported), ppWritePackedMsg, end, &pack_uint8_tlv_value) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config) ); + +} + +static uint8_t pack_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_config_request_t *pNfapiMsg = (nfapi_config_request_t*)msg; + + return ( push8(pNfapiMsg->num_tlv, ppWritePackedMsg, end) && + + // Do we check the phy state and then just fill those sepecified, however + // we do not know the duplex mode, so just attempt to pack all and assumme + // that the callee has set the right tlvs + + pack_tlv(NFAPI_SUBFRAME_CONFIG_DUPLEX_MODE_TAG, &(pNfapiMsg->subframe_config.duplex_mode), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SUBFRAME_CONFIG_PCFICH_POWER_OFFSET_TAG, &(pNfapiMsg->subframe_config.pcfich_power_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SUBFRAME_CONFIG_PB_TAG, &(pNfapiMsg->subframe_config.pb), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SUBFRAME_CONFIG_DL_CYCLIC_PREFIX_TYPE_TAG, &(pNfapiMsg->subframe_config.dl_cyclic_prefix_type), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SUBFRAME_CONFIG_UL_CYCLIC_PREFIX_TYPE_TAG, &(pNfapiMsg->subframe_config.ul_cyclic_prefix_type), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG, &(pNfapiMsg->rf_config.dl_channel_bandwidth), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_RF_CONFIG_UL_CHANNEL_BANDWIDTH_TAG, &(pNfapiMsg->rf_config.ul_channel_bandwidth), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_RF_CONFIG_REFERENCE_SIGNAL_POWER_TAG, &(pNfapiMsg->rf_config.reference_signal_power), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_RF_CONFIG_TX_ANTENNA_PORTS_TAG, &(pNfapiMsg->rf_config.tx_antenna_ports), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_RF_CONFIG_RX_ANTENNA_PORTS_TAG, &(pNfapiMsg->rf_config.rx_antenna_ports), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_PHICH_CONFIG_PHICH_RESOURCE_TAG, &(pNfapiMsg->phich_config.phich_resource), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PHICH_CONFIG_PHICH_DURATION_TAG, &(pNfapiMsg->phich_config.phich_duration), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG, &(pNfapiMsg->phich_config.phich_power_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_SCH_CONFIG_PRIMARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG, &(pNfapiMsg->sch_config.primary_synchronization_signal_epre_eprers), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SCH_CONFIG_SECONDARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG, &(pNfapiMsg->sch_config.secondary_synchronization_signal_epre_eprers), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SCH_CONFIG_PHYSICAL_CELL_ID_TAG, &(pNfapiMsg->sch_config.physical_cell_id), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_PRACH_CONFIG_CONFIGURATION_INDEX_TAG, &(pNfapiMsg->prach_config.configuration_index), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PRACH_CONFIG_ROOT_SEQUENCE_INDEX_TAG, &(pNfapiMsg->prach_config.root_sequence_index), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PRACH_CONFIG_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG, &(pNfapiMsg->prach_config.zero_correlation_zone_configuration), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PRACH_CONFIG_HIGH_SPEED_FLAG_TAG, &(pNfapiMsg->prach_config.high_speed_flag), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PRACH_CONFIG_FREQUENCY_OFFSET_TAG, &(pNfapiMsg->prach_config.frequency_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_PUSCH_CONFIG_HOPPING_MODE_TAG, &(pNfapiMsg->pusch_config.hopping_mode), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PUSCH_CONFIG_HOPPING_OFFSET_TAG, &(pNfapiMsg->pusch_config.hopping_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PUSCH_CONFIG_NUMBER_OF_SUBBANDS_TAG, &(pNfapiMsg->pusch_config.number_of_subbands), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_PUCCH_CONFIG_DELTA_PUCCH_SHIFT_TAG, &(pNfapiMsg->pucch_config.delta_pucch_shift), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PUCCH_CONFIG_N_CQI_RB_TAG, &(pNfapiMsg->pucch_config.n_cqi_rb), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PUCCH_CONFIG_N_AN_CS_TAG, &(pNfapiMsg->pucch_config.n_an_cs), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_PUCCH_CONFIG_N1_PUCCH_AN_TAG, &(pNfapiMsg->pucch_config.n1_pucch_an), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_SRS_CONFIG_BANDWIDTH_CONFIGURATION_TAG, &(pNfapiMsg->srs_config.bandwidth_configuration), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SRS_CONFIG_MAX_UP_PTS_TAG, &(pNfapiMsg->srs_config.max_up_pts), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SRS_CONFIG_SRS_SUBFRAME_CONFIGURATION_TAG, &(pNfapiMsg->srs_config.srs_subframe_configuration), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_SRS_CONFIG_SRS_ACKNACK_SRS_SIMULTANEOUS_TRANSMISSION_TAG, &(pNfapiMsg->srs_config.srs_acknack_srs_simultaneous_transmission), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_UPLINK_RS_HOPPING_TAG, &(pNfapiMsg->uplink_reference_signal_config.uplink_rs_hopping), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_GROUP_ASSIGNMENT_TAG, &(pNfapiMsg->uplink_reference_signal_config.group_assignment), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_CYCLIC_SHIFT_1_FOR_DRMS_TAG, &(pNfapiMsg->uplink_reference_signal_config.cyclic_shift_1_for_drms), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_LAA_CONFIG_ED_THRESHOLD_FOR_LBT_FOR_PDSCH_TAG, &(pNfapiMsg->laa_config.ed_threshold_lbt_pdsch), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_LAA_CONFIG_ED_THRESHOLD_FOR_LBT_FOR_DRS_TAG, &(pNfapiMsg->laa_config.ed_threshold_lbt_drs), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_LAA_CONFIG_PD_THRESHOLD_TAG, &(pNfapiMsg->laa_config.pd_threshold), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_LAA_CONFIG_MULTI_CARRIER_TYPE_TAG, &(pNfapiMsg->laa_config.multi_carrier_type), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_LAA_CONFIG_MULTI_CARRIER_TX_TAG, &(pNfapiMsg->laa_config.multi_carrier_tx), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_LAA_CONFIG_MULTI_CARRIER_FREEZE_TAG, &(pNfapiMsg->laa_config.multi_carrier_freeze), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_LAA_CONFIG_TX_ANTENNA_PORTS_FOR_DRS_TAG, &(pNfapiMsg->laa_config.tx_antenna_ports_drs), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_LAA_CONFIG_TRANSMISSION_POWER_FOR_DRS_TAG, &(pNfapiMsg->laa_config.tx_power_drs), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_EMTC_CONFIG_PBCH_REPETITIONS_ENABLE_R13_TAG, &(pNfapiMsg->emtc_config.pbch_repetitions_enable_r13), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CATM_ROOT_SEQUENCE_INDEX_TAG, &(pNfapiMsg->emtc_config.prach_catm_root_sequence_index), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CATM_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG, &(pNfapiMsg->emtc_config.prach_catm_zero_correlation_zone_configuration), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CATM_HIGH_SPEED_FLAG, &(pNfapiMsg->emtc_config.prach_catm_high_speed_flag), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_ENABLE_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_0_enable), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_CONFIGURATION_INDEX_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_0_configuration_index), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_FREQUENCY_OFFSET_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_0_frequency_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_STARTING_SUBFRAME_PERIODICITY_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_0_starting_subframe_periodicity), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_ENABLE_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_0_hopping_enable), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_OFFSET_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_0_hopping_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_ENABLE_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_1_enable), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_CONFIGURATION_INDEX_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_1_configuration_index), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_FREQUENCY_OFFSET_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_1_frequency_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_STARTING_SUBFRAME_PERIODICITY_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_1_starting_subframe_periodicity), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_ENABLE_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_1_hopping_enable), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_OFFSET_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_1_hopping_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_ENABLE_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_2_enable), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_CONFIGURATION_INDEX_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_2_configuration_index), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_FREQUENCY_OFFSET_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_2_frequency_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_STARTING_SUBFRAME_PERIODICITY_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_2_starting_subframe_periodicity), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_ENABLE_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_2_hopping_enable), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_OFFSET_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_2_hopping_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_ENABLE_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_3_enable), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_CONFIGURATION_INDEX_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_3_configuration_index), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_FREQUENCY_OFFSET_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_3_frequency_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_STARTING_SUBFRAME_PERIODICITY_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_3_starting_subframe_periodicity), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_ENABLE_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_3_hopping_enable), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_OFFSET_TAG, &(pNfapiMsg->emtc_config.prach_ce_level_3_hopping_offset), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEA_TAG, &(pNfapiMsg->emtc_config.pucch_interval_ulhoppingconfigcommonmodea), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEB_TAG, &(pNfapiMsg->emtc_config.pucch_interval_ulhoppingconfigcommonmodeb), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_TDD_FRAME_STRUCTURE_SUBFRAME_ASSIGNMENT_TAG, &(pNfapiMsg->tdd_frame_structure_config.subframe_assignment), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_TDD_FRAME_STRUCTURE_SPECIAL_SUBFRAME_PATTERNS_TAG, &(pNfapiMsg->tdd_frame_structure_config.special_subframe_patterns), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + pack_tlv(NFAPI_L23_CONFIG_DATA_REPORT_MODE_TAG, &(pNfapiMsg->l23_config.data_report_mode), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_L23_CONFIG_SFNSF_TAG, &(pNfapiMsg->l23_config.sfnsf), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + + pack_tlv(NFAPI_NFAPI_P7_VNF_ADDRESS_IPV4_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv4), ppWritePackedMsg, end, &pack_ipv4_address_value) && + pack_tlv(NFAPI_NFAPI_P7_VNF_ADDRESS_IPV6_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv6), ppWritePackedMsg, end, &pack_ipv6_address_value) && + pack_tlv(NFAPI_NFAPI_P7_VNF_PORT_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_port), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_NFAPI_P7_PNF_ADDRESS_IPV4_TAG, &(pNfapiMsg->nfapi_config.p7_pnf_address_ipv4), ppWritePackedMsg, end, &pack_ipv4_address_value) && + pack_tlv(NFAPI_NFAPI_P7_PNF_ADDRESS_IPV6_TAG, &(pNfapiMsg->nfapi_config.p7_pnf_address_ipv6), ppWritePackedMsg, end, &pack_ipv6_address_value) && + pack_tlv(NFAPI_NFAPI_P7_PNF_PORT_TAG, &(pNfapiMsg->nfapi_config.p7_pnf_port), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_NFAPI_DOWNLINK_UES_PER_SUBFRAME_TAG, &(pNfapiMsg->nfapi_config.dl_ue_per_sf), ppWritePackedMsg, end, &pack_uint8_tlv_value) && + pack_tlv(NFAPI_NFAPI_UPLINK_UES_PER_SUBFRAME_TAG, &(pNfapiMsg->nfapi_config.ul_ue_per_sf), ppWritePackedMsg, end, &pack_uint8_tlv_value) && + + pack_tlv(NFAPI_PHY_RF_BANDS_TAG, &(pNfapiMsg->nfapi_config.rf_bands), ppWritePackedMsg, end, &pack_rf_bands_value) && + + pack_tlv(NFAPI_NFAPI_TIMING_WINDOW_TAG, &(pNfapiMsg->nfapi_config.timing_window), ppWritePackedMsg, end, &pack_uint8_tlv_value) && + pack_tlv(NFAPI_NFAPI_TIMING_INFO_MODE_TAG, &(pNfapiMsg->nfapi_config.timing_info_mode), ppWritePackedMsg, end, &pack_uint8_tlv_value) && + pack_tlv(NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG, &(pNfapiMsg->nfapi_config.timing_info_period), ppWritePackedMsg, end, &pack_uint8_tlv_value) && + + pack_tlv(NFAPI_NFAPI_MAXIMUM_TRANSMIT_POWER_TAG, &(pNfapiMsg->nfapi_config.max_transmit_power), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_NFAPI_EARFCN_TAG, &(pNfapiMsg->nfapi_config.earfcn), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + + + pack_tlv(NFAPI_NFAPI_NMM_GSM_FREQUENCY_BANDS_TAG, &(pNfapiMsg->nfapi_config.nmm_gsm_frequency_bands), ppWritePackedMsg, end, &pack_nmm_frequency_bands_value) && + pack_tlv(NFAPI_NFAPI_NMM_UMTS_FREQUENCY_BANDS_TAG, &(pNfapiMsg->nfapi_config.nmm_umts_frequency_bands), ppWritePackedMsg, end, &pack_nmm_frequency_bands_value) && + pack_tlv(NFAPI_NFAPI_NMM_LTE_FREQUENCY_BANDS_TAG, &(pNfapiMsg->nfapi_config.nmm_lte_frequency_bands), ppWritePackedMsg, end, &pack_nmm_frequency_bands_value) && + pack_tlv(NFAPI_NFAPI_NMM_UPLINK_RSSI_SUPPORTED_TAG, &(pNfapiMsg->nfapi_config.nmm_uplink_rssi_supported), ppWritePackedMsg, end, &pack_uint8_tlv_value) && + + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config) ); +} + +static uint8_t pack_config_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_config_response_t *pNfapiMsg = (nfapi_config_response_t*)msg; + + return ( push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config) ); +} + +static uint8_t pack_start_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_start_request_t *pNfapiMsg = (nfapi_start_request_t*)msg; + return pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config); +} + +static uint8_t pack_start_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_start_response_t *pNfapiMsg = (nfapi_start_response_t*)msg; + + return ( push32(pNfapiMsg->error_code, ppWritePackedMsg, end ) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config) ); +} + +static uint8_t pack_stop_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_stop_request_t *pNfapiMsg = (nfapi_stop_request_t*)msg; + return pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config); +} + +static uint8_t pack_stop_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_stop_response_t *pNfapiMsg = (nfapi_stop_response_t*)msg; + + return ( push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config) ); +} + +static uint8_t pack_measurement_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_measurement_request_t *pNfapiMsg = (nfapi_measurement_request_t*)msg; + + return( pack_tlv(NFAPI_MEASUREMENT_REQUEST_DL_RS_XTX_POWER_TAG, &(pNfapiMsg->dl_rs_tx_power), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_MEASUREMENT_REQUEST_RECEIVED_INTERFERENCE_POWER_TAG, &(pNfapiMsg->received_interference_power), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_tlv(NFAPI_MEASUREMENT_REQUEST_THERMAL_NOISE_POWER_TAG, &(pNfapiMsg->thermal_noise_power), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_recevied_interference_power_measurement_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_received_interference_power_measurement_t* value = (nfapi_received_interference_power_measurement_t*)tlv; + + return ( push16(value->number_of_resource_blocks, ppWritePackedMsg, end) && + pusharrays16(value->received_interference_power, NFAPI_MAX_RECEIVED_INTERFERENCE_POWER_RESULTS, value->number_of_resource_blocks, ppWritePackedMsg, end)); +} + +static uint8_t pack_measurement_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_measurement_response_t *pNfapiMsg = (nfapi_measurement_response_t*)msg; + + return( push32(pNfapiMsg->error_code, ppWritePackedMsg, end) && + pack_tlv(NFAPI_MEASUREMENT_RESPONSE_DL_RS_POWER_MEASUREMENT_TAG, &(pNfapiMsg->dl_rs_tx_power_measurement), ppWritePackedMsg, end, &pack_int16_tlv_value) && + pack_tlv(NFAPI_MEASUREMENT_RESPONSE_RECEIVED_INTERFERENCE_POWER_MEASUREMENT_TAG, &(pNfapiMsg->received_interference_power_measurement), ppWritePackedMsg, end, &pack_recevied_interference_power_measurement_value) && + pack_tlv(NFAPI_MEASUREMENT_RESPONSE_THERMAL_NOISE_MEASUREMENT_TAG, &(pNfapiMsg->thermal_noise_power_measurement), ppWritePackedMsg, end, &pack_uint16_tlv_value) && + pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_p5_message_body(nfapi_p4_p5_message_header_t *header, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + uint8_t result = 0; + // look for the specific message + switch (header->message_id) + { + case NFAPI_PNF_PARAM_REQUEST: + result = pack_pnf_param_request(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_PNF_PARAM_RESPONSE: + result = pack_pnf_param_response(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_PNF_CONFIG_REQUEST: + result = pack_pnf_config_request(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_PNF_CONFIG_RESPONSE: + result = pack_pnf_config_response(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_PNF_START_REQUEST: + result = pack_pnf_start_request(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_PNF_START_RESPONSE: + result = pack_pnf_start_response(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_PNF_STOP_REQUEST: + result = pack_pnf_stop_request(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_PNF_STOP_RESPONSE: + result = pack_pnf_stop_response(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_PARAM_REQUEST: + result = pack_param_request(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_PARAM_RESPONSE: + result = pack_param_response(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_CONFIG_REQUEST: + result = pack_config_request(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_CONFIG_RESPONSE: + result = pack_config_response(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_START_REQUEST: + result = pack_start_request(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_START_RESPONSE: + result = pack_start_response(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_STOP_REQUEST: + result = pack_stop_request(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_STOP_RESPONSE: + result = pack_stop_response(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_MEASUREMENT_REQUEST: + result = pack_measurement_request(header, ppWritePackedMsg, end, config); + break; + + case NFAPI_MEASUREMENT_RESPONSE: + result = pack_measurement_response(header, ppWritePackedMsg, end, config); + break; + + default: + { + if(header->message_id >= NFAPI_VENDOR_EXT_MSG_MIN && + header->message_id <= NFAPI_VENDOR_EXT_MSG_MAX) + { + if(config && config->pack_p4_p5_vendor_extension) + { + result = (config->pack_p4_p5_vendor_extension)(header, ppWritePackedMsg, end, config); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s VE NFAPI message ID %d. No ve ecoder provided\n", __FUNCTION__, header->message_id); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s NFAPI Unknown message ID %d\n", __FUNCTION__, header->message_id); + } + } + break; + } + + return result; +} + + +// helper function for message length calculation - +// takes the pointers to the start of message to end of message + +static uint32_t get_packed_msg_len(uintptr_t msgHead, uintptr_t msgEnd) +{ + if (msgEnd < msgHead) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "get_packed_msg_len: Error in pointers supplied %d, %d\n", msgHead, msgEnd); + return 0; + } + + return (msgEnd - msgHead); +} + +// Main pack function - public + +int nfapi_p5_message_pack(void *pMessageBuf, uint32_t messageBufLen, void *pPackedBuf, uint32_t packedBufLen, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_p4_p5_message_header_t *pMessageHeader = pMessageBuf; + uint8_t *pWritePackedMessage = pPackedBuf; + uint8_t *pPackMessageEnd = pPackedBuf + packedBufLen; + uint8_t *pPackedLengthField = &pWritePackedMessage[4]; + uint32_t packedMsgLen; + uint16_t packedMsgLen16; + + if (pMessageBuf == NULL || pPackedBuf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P5 Pack supplied pointers are null\n"); + return -1; + } + + // pack the message + if(push16(pMessageHeader->phy_id, &pWritePackedMessage, pPackMessageEnd) && + push16(pMessageHeader->message_id, &pWritePackedMessage, pPackMessageEnd) && + push16(0/*pMessageHeader->message_length*/, &pWritePackedMessage, pPackMessageEnd) && + push16(pMessageHeader->spare, &pWritePackedMessage, pPackMessageEnd) && + pack_p5_message_body(pMessageHeader, &pWritePackedMessage, pPackMessageEnd, config)) + { + // check for a valid message length + packedMsgLen = get_packed_msg_len((uintptr_t)pPackedBuf, (uintptr_t)pWritePackedMessage); + if (packedMsgLen > 0xFFFF || packedMsgLen > packedBufLen) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Packed message length error %d, buffer supplied %d\n", packedMsgLen, packedBufLen); + return -1; + } + else + { + packedMsgLen16 = (uint16_t)packedMsgLen; + } + + // Update the message length in the header + if(!push16(packedMsgLen16, &pPackedLengthField, pPackMessageEnd)) + return -1; + + // return the packed length + return (packedMsgLen); + } + else + { + // Failed to pack the meassage + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P5 Failed to pack message\n"); + return -1; + } + +} + + + +// Unpack routines +static uint8_t unpack_pnf_param_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_param_request_t *pNfapiMsg = (nfapi_pnf_param_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_pnf_param_general_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_param_general_t* value = (nfapi_pnf_param_general_t*)tlv; + + return( pull8(ppReadPackedMsg, &value->nfapi_sync_mode, end) && + pull8(ppReadPackedMsg, &value->location_mode, end) && + pull16(ppReadPackedMsg, &value->location_coordinates_length, end) && + pullarray8(ppReadPackedMsg, value->location_coordinates, NFAPI_PNF_PARAM_GENERAL_LOCATION_LENGTH, value->location_coordinates_length, end) && + pull32(ppReadPackedMsg, &value->dl_config_timing, end) && + pull32(ppReadPackedMsg, &value->tx_timing, end) && + pull32(ppReadPackedMsg, &value->ul_config_timing, end) && + pull32(ppReadPackedMsg, &value->hi_dci0_timing, end) && + pull16(ppReadPackedMsg, &value->maximum_number_phys, end) && + pull16(ppReadPackedMsg, &value->maximum_total_bandwidth, end) && + pull8(ppReadPackedMsg, &value->maximum_total_number_dl_layers, end) && + pull8(ppReadPackedMsg, &value->maximum_total_number_ul_layers, end) && + pull8(ppReadPackedMsg, &value->shared_bands, end) && + pull8(ppReadPackedMsg, &value->shared_pa, end) && + pulls16(ppReadPackedMsg, &value->maximum_total_power, end) && + pullarray8(ppReadPackedMsg, value->oui, NFAPI_PNF_PARAM_GENERAL_OUI_LENGTH, NFAPI_PNF_PARAM_GENERAL_OUI_LENGTH, end)); +} + +static uint8_t unpack_rf_config_info(void* elem, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_rf_config_info_t* info = (nfapi_rf_config_info_t*)elem; + return pull16(ppReadPackedMsg, &info->rf_config_index, end); +} + +static uint8_t unpack_pnf_phy_info(void* elem, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_info_t* phy = (nfapi_pnf_phy_info_t*)elem; + + return ( pull16(ppReadPackedMsg, &phy->phy_config_index, end) && + pull16(ppReadPackedMsg, &phy->number_of_rfs, end) && + unpackarray(ppReadPackedMsg, phy->rf_config, sizeof(nfapi_rf_config_info_t), NFAPI_MAX_PNF_PHY_RF_CONFIG, phy->number_of_rfs, end, &unpack_rf_config_info) && + pull16(ppReadPackedMsg, &phy->number_of_rf_exclusions, end) && + unpackarray(ppReadPackedMsg, phy->excluded_rf_config, sizeof(nfapi_rf_config_info_t), NFAPI_MAX_PNF_PHY_RF_CONFIG, phy->number_of_rf_exclusions, end, &unpack_rf_config_info) && + pull16(ppReadPackedMsg, &phy->downlink_channel_bandwidth_supported, end) && + pull16(ppReadPackedMsg, &phy->uplink_channel_bandwidth_supported, end) && + pull8(ppReadPackedMsg, &phy->number_of_dl_layers_supported, end) && + pull8(ppReadPackedMsg, &phy->number_of_ul_layers_supported, end) && + pull16(ppReadPackedMsg, &phy->maximum_3gpp_release_supported, end) && + pull8(ppReadPackedMsg, &phy->nmm_modes_supported, end)); +} + + +static uint8_t unpack_pnf_phy_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_t* value = (nfapi_pnf_phy_t*)tlv; + return ( pull16(ppReadPackedMsg, &value->number_of_phys, end) && + unpackarray(ppReadPackedMsg, value->phy, sizeof(nfapi_pnf_phy_info_t), NFAPI_MAX_PNF_PHY, value->number_of_phys, end, &unpack_pnf_phy_info)); +} + +static uint8_t unpack_pnf_rf_info(void* elem, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_rf_info_t* rf = (nfapi_pnf_rf_info_t*)elem; + + return( pull16(ppReadPackedMsg, &rf->rf_config_index, end) && + pull16(ppReadPackedMsg, &rf->band, end) && + pulls16(ppReadPackedMsg, &rf->maximum_transmit_power, end) && + pulls16(ppReadPackedMsg, &rf->minimum_transmit_power, end) && + pull8(ppReadPackedMsg, &rf->number_of_antennas_suppported, end) && + pull32(ppReadPackedMsg, &rf->minimum_downlink_frequency, end) && + pull32(ppReadPackedMsg, &rf->maximum_downlink_frequency, end) && + pull32(ppReadPackedMsg, &rf->minimum_uplink_frequency, end) && + pull32(ppReadPackedMsg, &rf->maximum_uplink_frequency, end)); + +} +static uint8_t unpack_pnf_rf_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_rf_t* value = (nfapi_pnf_rf_t*)tlv; + + return ( pull16(ppReadPackedMsg, &value->number_of_rfs, end) && + unpackarray(ppReadPackedMsg, value->rf, sizeof(nfapi_pnf_rf_info_t), NFAPI_MAX_PNF_RF, value->number_of_rfs, end, &unpack_pnf_rf_info)); +} + +static uint8_t unpack_pnf_phy_rel10_info(void* elem, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel10_info_t* phy = (nfapi_pnf_phy_rel10_info_t*)elem; + + return( pull16(ppReadPackedMsg, &phy->phy_config_index, end) && + pull16(ppReadPackedMsg, &phy->transmission_mode_7_supported, end) && + pull16(ppReadPackedMsg, &phy->transmission_mode_8_supported, end) && + pull16(ppReadPackedMsg, &phy->two_antenna_ports_for_pucch, end) && + pull16(ppReadPackedMsg, &phy->transmission_mode_9_supported, end) && + pull16(ppReadPackedMsg, &phy->simultaneous_pucch_pusch, end) && + pull16(ppReadPackedMsg, &phy->four_layer_tx_with_tm3_and_tm4, end)); + + +} +static uint8_t unpack_pnf_phy_rel10_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel10_t* value = (nfapi_pnf_phy_rel10_t*)tlv; + + return ( pull16(ppReadPackedMsg, &value->number_of_phys, end) && + unpackarray(ppReadPackedMsg, value->phy, sizeof(nfapi_pnf_phy_rel10_info_t), NFAPI_MAX_PNF_PHY, value->number_of_phys, end, &unpack_pnf_phy_rel10_info)); + +} + + +static uint8_t unpack_pnf_phy_rel11_info(void* elem, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel11_info_t* phy = (nfapi_pnf_phy_rel11_info_t*)elem; + + return( pull16(ppReadPackedMsg, &phy->phy_config_index, end) && + pull16(ppReadPackedMsg, &phy->edpcch_supported, end) && + pull16(ppReadPackedMsg, &phy->multi_ack_csi_reporting, end ) && + pull16(ppReadPackedMsg, &phy->pucch_tx_diversity, end) && + pull16(ppReadPackedMsg, &phy->ul_comp_supported, end) && + pull16(ppReadPackedMsg, &phy->transmission_mode_5_supported, end)); +} + +static uint8_t unpack_pnf_phy_rel11_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel11_t* value = (nfapi_pnf_phy_rel11_t*)tlv; + + return ( pull16(ppReadPackedMsg, &value->number_of_phys, end) && + unpackarray(ppReadPackedMsg, value->phy, sizeof(nfapi_pnf_phy_rel11_info_t), NFAPI_MAX_PNF_PHY, value->number_of_phys, end, &unpack_pnf_phy_rel11_info)); + +} + +static uint8_t unpack_phy_phy_rel12_info(void* elem, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel12_info_t* phy = (nfapi_pnf_phy_rel12_info_t*)elem; + + return( pull16(ppReadPackedMsg, &phy->phy_config_index, end) && + pull16(ppReadPackedMsg, &phy->csi_subframe_set, end) && + pull16(ppReadPackedMsg, &phy->enhanced_4tx_codebook, end) && + pull16(ppReadPackedMsg, &phy->drs_supported, end) && + pull16(ppReadPackedMsg, &phy->ul_64qam_supported, end) && + pull16(ppReadPackedMsg, &phy->transmission_mode_10_supported, end) && + pull16(ppReadPackedMsg, &phy->alternative_bts_indices, end)); +} + +static uint8_t unpack_pnf_phy_rel12_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel12_t* value = (nfapi_pnf_phy_rel12_t*)tlv; + + return (pull16(ppReadPackedMsg, &value->number_of_phys, end) && + unpackarray(ppReadPackedMsg, value->phy, sizeof(nfapi_pnf_phy_rel12_t), NFAPI_MAX_PNF_PHY, value->number_of_phys, end, &unpack_phy_phy_rel12_info)); + +} + +static uint8_t unpack_pnf_phy_rel13_info(void *elem, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel13_info_t* phy = (nfapi_pnf_phy_rel13_info_t*)elem; + + return( pull16(ppReadPackedMsg, &phy->phy_config_index, end) && + pull16(ppReadPackedMsg, &phy->pucch_format4_supported, end) && + pull16(ppReadPackedMsg, &phy->pucch_format5_supported, end) && + pull16(ppReadPackedMsg, &phy->more_than_5_ca_support, end) && + pull16(ppReadPackedMsg, &phy->laa_supported, end) && + pull16(ppReadPackedMsg, &phy->laa_ending_in_dwpts_supported, end) && + pull16(ppReadPackedMsg, &phy->laa_starting_in_second_slot_supported, end) && + pull16(ppReadPackedMsg, &phy->beamforming_supported, end) && + pull16(ppReadPackedMsg, &phy->csi_rs_enhancement_supported, end) && + pull16(ppReadPackedMsg, &phy->drms_enhancement_supported, end) && + pull16(ppReadPackedMsg, &phy->srs_enhancement_supported, end)); +} + +static uint8_t unpack_pnf_phy_rel13_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel13_t* value = (nfapi_pnf_phy_rel13_t*)tlv; + + return ( pull16(ppReadPackedMsg, &value->number_of_phys, end) && + unpackarray(ppReadPackedMsg, value->phy, sizeof(nfapi_pnf_phy_rel13_info_t), NFAPI_MAX_PNF_PHY, value->number_of_phys, end, &unpack_pnf_phy_rel13_info)); +} + +static uint8_t unpack_pnf_phy_rel13_nb_info_info(void *elem, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel13_nb_iot_info_t* phy = (nfapi_pnf_phy_rel13_nb_iot_info_t*)elem; + + return( pull16(ppReadPackedMsg, &phy->phy_config_index, end) && + pull16(ppReadPackedMsg, &phy->number_of_rfs, end) && + unpackarray(ppReadPackedMsg, phy->rf_config, sizeof(nfapi_rf_config_info_t), NFAPI_MAX_PNF_PHY_RF_CONFIG, phy->number_of_rfs, end, &unpack_rf_config_info) && + pull16(ppReadPackedMsg, &phy->number_of_rf_exclusions, end) && + unpackarray(ppReadPackedMsg, phy->excluded_rf_config, sizeof(nfapi_rf_config_info_t), NFAPI_MAX_PNF_PHY_RF_CONFIG, phy->number_of_rf_exclusions, end, &unpack_rf_config_info) && + pull8(ppReadPackedMsg, &phy->number_of_dl_layers_supported, end) && + pull8(ppReadPackedMsg, &phy->number_of_ul_layers_supported, end) && + pull16(ppReadPackedMsg, &phy->maximum_3gpp_release_supported, end) && + pull8(ppReadPackedMsg, &phy->nmm_modes_supported, end)); +} + +static uint8_t unpack_pnf_phy_rel13_nb_iot_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rel13_nb_iot_t* value = (nfapi_pnf_phy_rel13_nb_iot_t*)tlv; + + return ( pull16(ppReadPackedMsg, &value->number_of_phys, end) && + unpackarray(ppReadPackedMsg, value->phy, sizeof(nfapi_pnf_phy_rel13_nb_iot_info_t), NFAPI_MAX_PNF_PHY, value->number_of_phys, end, &unpack_pnf_phy_rel13_nb_info_info)); +} + + + +static uint8_t unpack_pnf_param_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_param_response_t *pNfapiMsg = (nfapi_pnf_param_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_PNF_PARAM_GENERAL_TAG, &pNfapiMsg->pnf_param_general, &unpack_pnf_param_general_value}, + { NFAPI_PNF_PHY_TAG, &pNfapiMsg->pnf_phy, &unpack_pnf_phy_value}, + { NFAPI_PNF_RF_TAG, &pNfapiMsg->pnf_rf, &unpack_pnf_rf_value}, + { NFAPI_PNF_PHY_REL10_TAG, &pNfapiMsg->pnf_phy_rel10, &unpack_pnf_phy_rel10_value}, + { NFAPI_PNF_PHY_REL11_TAG, &pNfapiMsg->pnf_phy_rel11, &unpack_pnf_phy_rel11_value}, + { NFAPI_PNF_PHY_REL12_TAG, &pNfapiMsg->pnf_phy_rel12, &unpack_pnf_phy_rel12_value}, + { NFAPI_PNF_PHY_REL13_TAG, &pNfapiMsg->pnf_phy_rel13, &unpack_pnf_phy_rel13_value}, + { NFAPI_PNF_PHY_REL13_NB_IOT_TAG, &pNfapiMsg->pnf_phy_rel13_nb_iot, &unpack_pnf_phy_rel13_nb_iot_value}, + }; + + return ( pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_phy_rf_config_info(void* elem, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_phy_rf_config_info_t* rf = (nfapi_phy_rf_config_info_t*)elem; + + return( pull16(ppReadPackedMsg, &rf->phy_id, end) && + pull16(ppReadPackedMsg, &rf->phy_config_index, end) && + pull16(ppReadPackedMsg, &rf->rf_config_index, end)); + +} + +static uint8_t unpack_pnf_phy_rf_config_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_pnf_phy_rf_config_t* value = (nfapi_pnf_phy_rf_config_t*)tlv; + + return ( pull16(ppReadPackedMsg, &value->number_phy_rf_config_info, end) && + unpackarray(ppReadPackedMsg, value->phy_rf_config, sizeof(nfapi_phy_rf_config_info_t), NFAPI_MAX_PHY_RF_INSTANCES, value->number_phy_rf_config_info, end, &unpack_phy_rf_config_info)); +} + +static uint8_t unpack_pnf_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_config_request_t *pNfapiMsg = (nfapi_pnf_config_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_PNF_PHY_RF_TAG, &pNfapiMsg->pnf_phy_rf_config, &unpack_pnf_phy_rf_config_value}, + }; + + return unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension); +} + +static uint8_t unpack_pnf_config_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_config_response_t *pNfapiMsg = (nfapi_pnf_config_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return ( pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension))); + +} + +static uint8_t unpack_pnf_start_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_start_request_t *pNfapiMsg = (nfapi_pnf_start_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_pnf_start_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_start_response_t *pNfapiMsg = (nfapi_pnf_start_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return ( pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end ) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension))); +} + +static uint8_t unpack_pnf_stop_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_stop_request_t *pNfapiMsg = (nfapi_pnf_stop_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_pnf_stop_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_pnf_stop_response_t *pNfapiMsg = (nfapi_pnf_stop_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return ( pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension))); + +} + +static uint8_t unpack_param_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_param_request_t *pNfapiMsg = (nfapi_param_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_param_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_param_response_t *pNfapiMsg = (nfapi_param_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_L1_STATUS_PHY_STATE_TAG, &pNfapiMsg->l1_status.phy_state, &unpack_uint16_tlv_value}, + + { NFAPI_PHY_CAPABILITIES_DL_BANDWIDTH_SUPPORT_TAG, &pNfapiMsg->phy_capabilities.dl_bandwidth_support, &unpack_uint16_tlv_value}, + { NFAPI_PHY_CAPABILITIES_UL_BANDWIDTH_SUPPORT_TAG, &pNfapiMsg->phy_capabilities.ul_bandwidth_support, &unpack_uint16_tlv_value}, + { NFAPI_PHY_CAPABILITIES_DL_MODULATION_SUPPORT_TAG, &pNfapiMsg->phy_capabilities.dl_modulation_support, &unpack_uint16_tlv_value}, + { NFAPI_PHY_CAPABILITIES_UL_MODULATION_SUPPORT_TAG, &pNfapiMsg->phy_capabilities.ul_modulation_support, &unpack_uint16_tlv_value}, + { NFAPI_PHY_CAPABILITIES_PHY_ANTENNA_CAPABILITY_TAG, &pNfapiMsg->phy_capabilities.phy_antenna_capability, &unpack_uint16_tlv_value}, + { NFAPI_PHY_CAPABILITIES_RELEASE_CAPABILITY_TAG, &pNfapiMsg->phy_capabilities.release_capability, &unpack_uint16_tlv_value}, + { NFAPI_PHY_CAPABILITIES_MBSFN_CAPABILITY_TAG, &pNfapiMsg->phy_capabilities.mbsfn_capability, &unpack_uint16_tlv_value}, + + { NFAPI_LAA_CAPABILITY_LAA_SUPPORT_TAG, &pNfapiMsg->laa_capability.laa_support, &unpack_uint16_tlv_value}, + { NFAPI_LAA_CAPABILITY_PD_SENSING_LBT_SUPPORT_TAG, &pNfapiMsg->laa_capability.pd_sensing_lbt_support, &unpack_uint16_tlv_value}, + { NFAPI_LAA_CAPABILITY_MULTI_CARRIER_LBT_SUPPORT_TAG, &pNfapiMsg->laa_capability.multi_carrier_lbt_support, &unpack_uint16_tlv_value}, + { NFAPI_LAA_CAPABILITY_PARTIAL_SF_SUPPORT_TAG, &pNfapiMsg->laa_capability.partial_sf_support, &unpack_uint16_tlv_value}, + + { NFAPI_SUBFRAME_CONFIG_DUPLEX_MODE_TAG, &pNfapiMsg->subframe_config.duplex_mode, &unpack_uint16_tlv_value}, + { NFAPI_SUBFRAME_CONFIG_PCFICH_POWER_OFFSET_TAG, &pNfapiMsg->subframe_config.pcfich_power_offset, &unpack_uint16_tlv_value}, + { NFAPI_SUBFRAME_CONFIG_PB_TAG, &pNfapiMsg->subframe_config.pb, &unpack_uint16_tlv_value}, + { NFAPI_SUBFRAME_CONFIG_DL_CYCLIC_PREFIX_TYPE_TAG, &pNfapiMsg->subframe_config.dl_cyclic_prefix_type, &unpack_uint16_tlv_value}, + { NFAPI_SUBFRAME_CONFIG_UL_CYCLIC_PREFIX_TYPE_TAG, &pNfapiMsg->subframe_config.ul_cyclic_prefix_type, &unpack_uint16_tlv_value}, + + { NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG, &pNfapiMsg->rf_config.dl_channel_bandwidth, &unpack_uint16_tlv_value}, + { NFAPI_RF_CONFIG_UL_CHANNEL_BANDWIDTH_TAG, &pNfapiMsg->rf_config.ul_channel_bandwidth, &unpack_uint16_tlv_value}, + { NFAPI_RF_CONFIG_REFERENCE_SIGNAL_POWER_TAG, &pNfapiMsg->rf_config.reference_signal_power, &unpack_uint16_tlv_value}, + { NFAPI_RF_CONFIG_TX_ANTENNA_PORTS_TAG, &pNfapiMsg->rf_config.tx_antenna_ports, &unpack_uint16_tlv_value}, + { NFAPI_RF_CONFIG_RX_ANTENNA_PORTS_TAG, &pNfapiMsg->rf_config.rx_antenna_ports, &unpack_uint16_tlv_value}, + + { NFAPI_PHICH_CONFIG_PHICH_RESOURCE_TAG, &pNfapiMsg->phich_config.phich_resource, &unpack_uint16_tlv_value}, + { NFAPI_PHICH_CONFIG_PHICH_DURATION_TAG, &pNfapiMsg->phich_config.phich_duration, &unpack_uint16_tlv_value}, + { NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG, &pNfapiMsg->phich_config.phich_power_offset, &unpack_uint16_tlv_value}, + + { NFAPI_SCH_CONFIG_PRIMARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG, &pNfapiMsg->sch_config.primary_synchronization_signal_epre_eprers, &unpack_uint16_tlv_value}, + { NFAPI_SCH_CONFIG_SECONDARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG, &pNfapiMsg->sch_config.secondary_synchronization_signal_epre_eprers, &unpack_uint16_tlv_value}, + { NFAPI_SCH_CONFIG_PHYSICAL_CELL_ID_TAG, &pNfapiMsg->sch_config.physical_cell_id, &unpack_uint16_tlv_value}, + + { NFAPI_PRACH_CONFIG_CONFIGURATION_INDEX_TAG, &pNfapiMsg->prach_config.configuration_index, &unpack_uint16_tlv_value}, + { NFAPI_PRACH_CONFIG_ROOT_SEQUENCE_INDEX_TAG, &pNfapiMsg->prach_config.root_sequence_index, &unpack_uint16_tlv_value}, + { NFAPI_PRACH_CONFIG_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG, &pNfapiMsg->prach_config.zero_correlation_zone_configuration, &unpack_uint16_tlv_value}, + { NFAPI_PRACH_CONFIG_HIGH_SPEED_FLAG_TAG, &pNfapiMsg->prach_config.high_speed_flag, &unpack_uint16_tlv_value}, + { NFAPI_PRACH_CONFIG_FREQUENCY_OFFSET_TAG, &pNfapiMsg->prach_config.frequency_offset, &unpack_uint16_tlv_value}, + + { NFAPI_PUSCH_CONFIG_HOPPING_MODE_TAG, &pNfapiMsg->pusch_config.hopping_mode, &unpack_uint16_tlv_value}, + { NFAPI_PUSCH_CONFIG_HOPPING_OFFSET_TAG, &pNfapiMsg->pusch_config.hopping_offset, &unpack_uint16_tlv_value}, + { NFAPI_PUSCH_CONFIG_NUMBER_OF_SUBBANDS_TAG, &pNfapiMsg->pusch_config.number_of_subbands, &unpack_uint16_tlv_value}, + + { NFAPI_PUCCH_CONFIG_DELTA_PUCCH_SHIFT_TAG, &pNfapiMsg->pucch_config.delta_pucch_shift, &unpack_uint16_tlv_value}, + { NFAPI_PUCCH_CONFIG_N_CQI_RB_TAG, &pNfapiMsg->pucch_config.n_cqi_rb, &unpack_uint16_tlv_value}, + { NFAPI_PUCCH_CONFIG_N_AN_CS_TAG, &pNfapiMsg->pucch_config.n_an_cs, &unpack_uint16_tlv_value}, + { NFAPI_PUCCH_CONFIG_N1_PUCCH_AN_TAG, &pNfapiMsg->pucch_config.n1_pucch_an, &unpack_uint16_tlv_value}, + + { NFAPI_SRS_CONFIG_BANDWIDTH_CONFIGURATION_TAG, &pNfapiMsg->srs_config.bandwidth_configuration, &unpack_uint16_tlv_value}, + { NFAPI_SRS_CONFIG_MAX_UP_PTS_TAG, &pNfapiMsg->srs_config.max_up_pts, &unpack_uint16_tlv_value}, + { NFAPI_SRS_CONFIG_SRS_SUBFRAME_CONFIGURATION_TAG, &pNfapiMsg->srs_config.srs_subframe_configuration, &unpack_uint16_tlv_value}, + { NFAPI_SRS_CONFIG_SRS_ACKNACK_SRS_SIMULTANEOUS_TRANSMISSION_TAG, &pNfapiMsg->srs_config.srs_acknack_srs_simultaneous_transmission, &unpack_uint16_tlv_value}, + + { NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_UPLINK_RS_HOPPING_TAG, &pNfapiMsg->uplink_reference_signal_config.uplink_rs_hopping, &unpack_uint16_tlv_value}, + { NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_GROUP_ASSIGNMENT_TAG, &pNfapiMsg->uplink_reference_signal_config.group_assignment, &unpack_uint16_tlv_value}, + { NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_CYCLIC_SHIFT_1_FOR_DRMS_TAG, &pNfapiMsg->uplink_reference_signal_config.cyclic_shift_1_for_drms, &unpack_uint16_tlv_value}, + + { NFAPI_TDD_FRAME_STRUCTURE_SUBFRAME_ASSIGNMENT_TAG, &pNfapiMsg->tdd_frame_structure_config.subframe_assignment, &unpack_uint16_tlv_value}, + { NFAPI_TDD_FRAME_STRUCTURE_SPECIAL_SUBFRAME_PATTERNS_TAG, &pNfapiMsg->tdd_frame_structure_config.special_subframe_patterns, &unpack_uint16_tlv_value}, + + { NFAPI_L23_CONFIG_DATA_REPORT_MODE_TAG, &pNfapiMsg->l23_config.data_report_mode, &unpack_uint16_tlv_value}, + { NFAPI_L23_CONFIG_SFNSF_TAG, &pNfapiMsg->l23_config.sfnsf, &unpack_uint16_tlv_value}, + + { NFAPI_NFAPI_P7_VNF_ADDRESS_IPV4_TAG, &pNfapiMsg->nfapi_config.p7_vnf_address_ipv4, &unpack_ipv4_address_value}, + { NFAPI_NFAPI_P7_VNF_ADDRESS_IPV6_TAG, &pNfapiMsg->nfapi_config.p7_vnf_address_ipv6, &unpack_ipv6_address_value}, + { NFAPI_NFAPI_P7_VNF_PORT_TAG, &pNfapiMsg->nfapi_config.p7_vnf_port, &unpack_uint16_tlv_value}, + { NFAPI_NFAPI_P7_PNF_ADDRESS_IPV4_TAG, &pNfapiMsg->nfapi_config.p7_pnf_address_ipv4, &unpack_ipv4_address_value}, + { NFAPI_NFAPI_P7_PNF_ADDRESS_IPV6_TAG, &pNfapiMsg->nfapi_config.p7_pnf_address_ipv6, &unpack_ipv6_address_value}, + { NFAPI_NFAPI_P7_PNF_PORT_TAG, &pNfapiMsg->nfapi_config.p7_pnf_port, &unpack_uint16_tlv_value}, + { NFAPI_NFAPI_DOWNLINK_UES_PER_SUBFRAME_TAG, &pNfapiMsg->nfapi_config.dl_ue_per_sf, &unpack_uint8_tlv_value}, + { NFAPI_NFAPI_UPLINK_UES_PER_SUBFRAME_TAG, &pNfapiMsg->nfapi_config.ul_ue_per_sf, &unpack_uint8_tlv_value}, + { NFAPI_NFAPI_RF_BANDS_TAG, &pNfapiMsg->nfapi_config.rf_bands, &unpack_rf_bands_value}, + { NFAPI_NFAPI_TIMING_WINDOW_TAG, &pNfapiMsg->nfapi_config.timing_window, &unpack_uint8_tlv_value}, + { NFAPI_NFAPI_TIMING_INFO_MODE_TAG, &pNfapiMsg->nfapi_config.timing_info_mode, &unpack_uint8_tlv_value}, + { NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG, &pNfapiMsg->nfapi_config.timing_info_period, &unpack_uint8_tlv_value}, + { NFAPI_NFAPI_MAXIMUM_TRANSMIT_POWER_TAG, &pNfapiMsg->nfapi_config.max_transmit_power, &unpack_uint16_tlv_value}, + { NFAPI_NFAPI_EARFCN_TAG, &pNfapiMsg->nfapi_config.earfcn, &unpack_uint16_tlv_value}, + { NFAPI_NFAPI_NMM_GSM_FREQUENCY_BANDS_TAG, &pNfapiMsg->nfapi_config.nmm_gsm_frequency_bands, &unpack_nmm_frequency_bands_value}, + { NFAPI_NFAPI_NMM_UMTS_FREQUENCY_BANDS_TAG, &pNfapiMsg->nfapi_config.nmm_umts_frequency_bands, &unpack_nmm_frequency_bands_value}, + { NFAPI_NFAPI_NMM_LTE_FREQUENCY_BANDS_TAG, &pNfapiMsg->nfapi_config.nmm_lte_frequency_bands, &unpack_nmm_frequency_bands_value}, + { NFAPI_NFAPI_NMM_UPLINK_RSSI_SUPPORTED_TAG, &pNfapiMsg->nfapi_config.nmm_uplink_rssi_supported, &unpack_uint8_tlv_value}, + + }; + + return ( pull8(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + pull8(ppReadPackedMsg, &pNfapiMsg->num_tlv, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); + +} + +static uint8_t unpack_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_config_request_t *pNfapiMsg = (nfapi_config_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_SUBFRAME_CONFIG_DUPLEX_MODE_TAG, &pNfapiMsg->subframe_config.duplex_mode, &unpack_uint16_tlv_value}, + { NFAPI_SUBFRAME_CONFIG_PCFICH_POWER_OFFSET_TAG, &pNfapiMsg->subframe_config.pcfich_power_offset, &unpack_uint16_tlv_value}, + { NFAPI_SUBFRAME_CONFIG_PB_TAG, &pNfapiMsg->subframe_config.pb, &unpack_uint16_tlv_value}, + { NFAPI_SUBFRAME_CONFIG_DL_CYCLIC_PREFIX_TYPE_TAG, &pNfapiMsg->subframe_config.dl_cyclic_prefix_type, &unpack_uint16_tlv_value}, + { NFAPI_SUBFRAME_CONFIG_UL_CYCLIC_PREFIX_TYPE_TAG, &pNfapiMsg->subframe_config.ul_cyclic_prefix_type, &unpack_uint16_tlv_value}, + + { NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG, &pNfapiMsg->rf_config.dl_channel_bandwidth, &unpack_uint16_tlv_value}, + { NFAPI_RF_CONFIG_UL_CHANNEL_BANDWIDTH_TAG, &pNfapiMsg->rf_config.ul_channel_bandwidth, &unpack_uint16_tlv_value}, + { NFAPI_RF_CONFIG_REFERENCE_SIGNAL_POWER_TAG, &pNfapiMsg->rf_config.reference_signal_power, &unpack_uint16_tlv_value}, + { NFAPI_RF_CONFIG_TX_ANTENNA_PORTS_TAG, &pNfapiMsg->rf_config.tx_antenna_ports, &unpack_uint16_tlv_value}, + { NFAPI_RF_CONFIG_RX_ANTENNA_PORTS_TAG, &pNfapiMsg->rf_config.rx_antenna_ports, &unpack_uint16_tlv_value}, + + { NFAPI_PHICH_CONFIG_PHICH_RESOURCE_TAG, &pNfapiMsg->phich_config.phich_resource, &unpack_uint16_tlv_value}, + { NFAPI_PHICH_CONFIG_PHICH_DURATION_TAG, &pNfapiMsg->phich_config.phich_duration, &unpack_uint16_tlv_value}, + { NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG, &pNfapiMsg->phich_config.phich_power_offset, &unpack_uint16_tlv_value}, + + { NFAPI_SCH_CONFIG_PRIMARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG, &pNfapiMsg->sch_config.primary_synchronization_signal_epre_eprers, &unpack_uint16_tlv_value}, + { NFAPI_SCH_CONFIG_SECONDARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG, &pNfapiMsg->sch_config.secondary_synchronization_signal_epre_eprers, &unpack_uint16_tlv_value}, + { NFAPI_SCH_CONFIG_PHYSICAL_CELL_ID_TAG, &pNfapiMsg->sch_config.physical_cell_id, &unpack_uint16_tlv_value}, + + { NFAPI_PRACH_CONFIG_CONFIGURATION_INDEX_TAG, &pNfapiMsg->prach_config.configuration_index, &unpack_uint16_tlv_value}, + { NFAPI_PRACH_CONFIG_ROOT_SEQUENCE_INDEX_TAG, &pNfapiMsg->prach_config.root_sequence_index, &unpack_uint16_tlv_value}, + { NFAPI_PRACH_CONFIG_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG, &pNfapiMsg->prach_config.zero_correlation_zone_configuration, &unpack_uint16_tlv_value}, + { NFAPI_PRACH_CONFIG_HIGH_SPEED_FLAG_TAG, &pNfapiMsg->prach_config.high_speed_flag, &unpack_uint16_tlv_value}, + { NFAPI_PRACH_CONFIG_FREQUENCY_OFFSET_TAG, &pNfapiMsg->prach_config.frequency_offset, &unpack_uint16_tlv_value}, + + { NFAPI_PUSCH_CONFIG_HOPPING_MODE_TAG, &pNfapiMsg->pusch_config.hopping_mode, &unpack_uint16_tlv_value}, + { NFAPI_PUSCH_CONFIG_HOPPING_OFFSET_TAG, &pNfapiMsg->pusch_config.hopping_offset, &unpack_uint16_tlv_value}, + { NFAPI_PUSCH_CONFIG_NUMBER_OF_SUBBANDS_TAG, &pNfapiMsg->pusch_config.number_of_subbands, &unpack_uint16_tlv_value}, + + { NFAPI_PUCCH_CONFIG_DELTA_PUCCH_SHIFT_TAG, &pNfapiMsg->pucch_config.delta_pucch_shift, &unpack_uint16_tlv_value}, + { NFAPI_PUCCH_CONFIG_N_CQI_RB_TAG, &pNfapiMsg->pucch_config.n_cqi_rb, &unpack_uint16_tlv_value}, + { NFAPI_PUCCH_CONFIG_N_AN_CS_TAG, &pNfapiMsg->pucch_config.n_an_cs, &unpack_uint16_tlv_value}, + { NFAPI_PUCCH_CONFIG_N1_PUCCH_AN_TAG, &pNfapiMsg->pucch_config.n1_pucch_an, &unpack_uint16_tlv_value}, + + { NFAPI_SRS_CONFIG_BANDWIDTH_CONFIGURATION_TAG, &pNfapiMsg->srs_config.bandwidth_configuration, &unpack_uint16_tlv_value}, + { NFAPI_SRS_CONFIG_MAX_UP_PTS_TAG, &pNfapiMsg->srs_config.max_up_pts, &unpack_uint16_tlv_value}, + { NFAPI_SRS_CONFIG_SRS_SUBFRAME_CONFIGURATION_TAG, &pNfapiMsg->srs_config.srs_subframe_configuration, &unpack_uint16_tlv_value}, + { NFAPI_SRS_CONFIG_SRS_ACKNACK_SRS_SIMULTANEOUS_TRANSMISSION_TAG, &pNfapiMsg->srs_config.srs_acknack_srs_simultaneous_transmission, &unpack_uint16_tlv_value}, + + { NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_UPLINK_RS_HOPPING_TAG, &pNfapiMsg->uplink_reference_signal_config.uplink_rs_hopping, &unpack_uint16_tlv_value}, + { NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_GROUP_ASSIGNMENT_TAG, &pNfapiMsg->uplink_reference_signal_config.group_assignment, &unpack_uint16_tlv_value}, + { NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_CYCLIC_SHIFT_1_FOR_DRMS_TAG, &pNfapiMsg->uplink_reference_signal_config.cyclic_shift_1_for_drms, &unpack_uint16_tlv_value}, + + + { NFAPI_LAA_CONFIG_ED_THRESHOLD_FOR_LBT_FOR_PDSCH_TAG, &pNfapiMsg->laa_config.ed_threshold_lbt_pdsch, &unpack_uint16_tlv_value}, + { NFAPI_LAA_CONFIG_ED_THRESHOLD_FOR_LBT_FOR_DRS_TAG, &pNfapiMsg->laa_config.ed_threshold_lbt_drs, &unpack_uint16_tlv_value}, + { NFAPI_LAA_CONFIG_PD_THRESHOLD_TAG, &pNfapiMsg->laa_config.pd_threshold, &unpack_uint16_tlv_value}, + { NFAPI_LAA_CONFIG_MULTI_CARRIER_TYPE_TAG, &pNfapiMsg->laa_config.multi_carrier_type, &unpack_uint16_tlv_value}, + { NFAPI_LAA_CONFIG_MULTI_CARRIER_TX_TAG, &pNfapiMsg->laa_config.multi_carrier_tx, &unpack_uint16_tlv_value}, + { NFAPI_LAA_CONFIG_MULTI_CARRIER_FREEZE_TAG, &pNfapiMsg->laa_config.multi_carrier_freeze, &unpack_uint16_tlv_value}, + { NFAPI_LAA_CONFIG_TX_ANTENNA_PORTS_FOR_DRS_TAG, &pNfapiMsg->laa_config.tx_antenna_ports_drs, &unpack_uint16_tlv_value}, + { NFAPI_LAA_CONFIG_TRANSMISSION_POWER_FOR_DRS_TAG, &pNfapiMsg->laa_config.tx_power_drs, &unpack_uint16_tlv_value}, + + { NFAPI_EMTC_CONFIG_PBCH_REPETITIONS_ENABLE_R13_TAG, &pNfapiMsg->emtc_config.pbch_repetitions_enable_r13, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CATM_ROOT_SEQUENCE_INDEX_TAG, &pNfapiMsg->emtc_config.prach_catm_root_sequence_index, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CATM_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG, &pNfapiMsg->emtc_config.prach_catm_zero_correlation_zone_configuration, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CATM_HIGH_SPEED_FLAG, &pNfapiMsg->emtc_config.prach_catm_high_speed_flag, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_ENABLE_TAG, &pNfapiMsg->emtc_config.prach_ce_level_0_enable, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_CONFIGURATION_INDEX_TAG, &pNfapiMsg->emtc_config.prach_ce_level_0_configuration_index, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_FREQUENCY_OFFSET_TAG, &pNfapiMsg->emtc_config.prach_ce_level_0_frequency_offset, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG, &pNfapiMsg->emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_STARTING_SUBFRAME_PERIODICITY_TAG, &pNfapiMsg->emtc_config.prach_ce_level_0_starting_subframe_periodicity, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_ENABLE_TAG, &pNfapiMsg->emtc_config.prach_ce_level_0_hopping_enable, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_OFFSET_TAG, &pNfapiMsg->emtc_config.prach_ce_level_0_hopping_offset, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_ENABLE_TAG, &pNfapiMsg->emtc_config.prach_ce_level_1_enable, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_CONFIGURATION_INDEX_TAG, &pNfapiMsg->emtc_config.prach_ce_level_1_configuration_index, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_FREQUENCY_OFFSET_TAG, &pNfapiMsg->emtc_config.prach_ce_level_1_frequency_offset, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG, &pNfapiMsg->emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_STARTING_SUBFRAME_PERIODICITY_TAG, &pNfapiMsg->emtc_config.prach_ce_level_1_starting_subframe_periodicity, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_ENABLE_TAG, &pNfapiMsg->emtc_config.prach_ce_level_1_hopping_enable, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_OFFSET_TAG, &pNfapiMsg->emtc_config.prach_ce_level_1_hopping_offset, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_ENABLE_TAG, &pNfapiMsg->emtc_config.prach_ce_level_2_enable, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_CONFIGURATION_INDEX_TAG, &pNfapiMsg->emtc_config.prach_ce_level_2_configuration_index, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_FREQUENCY_OFFSET_TAG, &pNfapiMsg->emtc_config.prach_ce_level_2_frequency_offset, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG, &pNfapiMsg->emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_STARTING_SUBFRAME_PERIODICITY_TAG, &pNfapiMsg->emtc_config.prach_ce_level_2_starting_subframe_periodicity, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_ENABLE_TAG, &pNfapiMsg->emtc_config.prach_ce_level_2_hopping_enable, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_OFFSET_TAG, &pNfapiMsg->emtc_config.prach_ce_level_2_hopping_offset, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_ENABLE_TAG, &pNfapiMsg->emtc_config.prach_ce_level_3_enable, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_CONFIGURATION_INDEX_TAG, &pNfapiMsg->emtc_config.prach_ce_level_3_configuration_index, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_FREQUENCY_OFFSET_TAG, &pNfapiMsg->emtc_config.prach_ce_level_3_frequency_offset, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG, &pNfapiMsg->emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_STARTING_SUBFRAME_PERIODICITY_TAG, &pNfapiMsg->emtc_config.prach_ce_level_3_starting_subframe_periodicity, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_ENABLE_TAG, &pNfapiMsg->emtc_config.prach_ce_level_3_hopping_enable, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_OFFSET_TAG, &pNfapiMsg->emtc_config.prach_ce_level_3_hopping_offset, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEA_TAG, &pNfapiMsg->emtc_config.pucch_interval_ulhoppingconfigcommonmodea, &unpack_uint16_tlv_value}, + { NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEB_TAG, &pNfapiMsg->emtc_config.pucch_interval_ulhoppingconfigcommonmodeb, &unpack_uint16_tlv_value}, + + { NFAPI_TDD_FRAME_STRUCTURE_SUBFRAME_ASSIGNMENT_TAG, &pNfapiMsg->tdd_frame_structure_config.subframe_assignment, &unpack_uint16_tlv_value}, + { NFAPI_TDD_FRAME_STRUCTURE_SPECIAL_SUBFRAME_PATTERNS_TAG, &pNfapiMsg->tdd_frame_structure_config.special_subframe_patterns, &unpack_uint16_tlv_value}, + + { NFAPI_L23_CONFIG_DATA_REPORT_MODE_TAG, &pNfapiMsg->l23_config.data_report_mode, &unpack_uint16_tlv_value}, + { NFAPI_L23_CONFIG_SFNSF_TAG, &pNfapiMsg->l23_config.sfnsf, &unpack_uint16_tlv_value}, + + { NFAPI_NFAPI_P7_VNF_ADDRESS_IPV4_TAG, &pNfapiMsg->nfapi_config.p7_vnf_address_ipv4, &unpack_ipv4_address_value}, + { NFAPI_NFAPI_P7_VNF_ADDRESS_IPV6_TAG, &pNfapiMsg->nfapi_config.p7_vnf_address_ipv6, &unpack_ipv6_address_value}, + { NFAPI_NFAPI_P7_VNF_PORT_TAG, &pNfapiMsg->nfapi_config.p7_vnf_port, &unpack_uint16_tlv_value}, + { NFAPI_NFAPI_P7_PNF_ADDRESS_IPV4_TAG, &pNfapiMsg->nfapi_config.p7_pnf_address_ipv4, &unpack_ipv4_address_value}, + { NFAPI_NFAPI_P7_PNF_ADDRESS_IPV6_TAG, &pNfapiMsg->nfapi_config.p7_pnf_address_ipv6, &unpack_ipv6_address_value}, + { NFAPI_NFAPI_P7_PNF_PORT_TAG, &pNfapiMsg->nfapi_config.p7_pnf_port, &unpack_uint16_tlv_value}, + { NFAPI_NFAPI_DOWNLINK_UES_PER_SUBFRAME_TAG, &pNfapiMsg->nfapi_config.dl_ue_per_sf, &unpack_uint8_tlv_value}, + { NFAPI_NFAPI_UPLINK_UES_PER_SUBFRAME_TAG, &pNfapiMsg->nfapi_config.ul_ue_per_sf, &unpack_uint8_tlv_value}, + { NFAPI_NFAPI_RF_BANDS_TAG, &pNfapiMsg->nfapi_config.rf_bands, &unpack_rf_bands_value}, + { NFAPI_NFAPI_TIMING_WINDOW_TAG, &pNfapiMsg->nfapi_config.timing_window, &unpack_uint8_tlv_value}, + { NFAPI_NFAPI_TIMING_INFO_MODE_TAG, &pNfapiMsg->nfapi_config.timing_info_mode, &unpack_uint8_tlv_value}, + { NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG, &pNfapiMsg->nfapi_config.timing_info_period, &unpack_uint8_tlv_value}, + { NFAPI_NFAPI_MAXIMUM_TRANSMIT_POWER_TAG, &pNfapiMsg->nfapi_config.max_transmit_power, &unpack_uint16_tlv_value}, + { NFAPI_NFAPI_EARFCN_TAG, &pNfapiMsg->nfapi_config.earfcn, &unpack_uint16_tlv_value}, + { NFAPI_NFAPI_NMM_GSM_FREQUENCY_BANDS_TAG, &pNfapiMsg->nfapi_config.nmm_gsm_frequency_bands, &unpack_nmm_frequency_bands_value}, + { NFAPI_NFAPI_NMM_UMTS_FREQUENCY_BANDS_TAG, &pNfapiMsg->nfapi_config.nmm_umts_frequency_bands, &unpack_nmm_frequency_bands_value}, + { NFAPI_NFAPI_NMM_LTE_FREQUENCY_BANDS_TAG, &pNfapiMsg->nfapi_config.nmm_lte_frequency_bands, &unpack_nmm_frequency_bands_value}, + { NFAPI_NFAPI_NMM_UPLINK_RSSI_SUPPORTED_TAG, &pNfapiMsg->nfapi_config.nmm_uplink_rssi_supported, &unpack_uint8_tlv_value}, + + }; + + return ( pull8(ppReadPackedMsg, &pNfapiMsg->num_tlv, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); + +} + +static uint8_t unpack_config_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_config_response_t *pNfapiMsg = (nfapi_config_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return ( pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension))); +} + +static uint8_t unpack_start_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_start_request_t *pNfapiMsg = (nfapi_start_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_start_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_start_response_t *pNfapiMsg = (nfapi_start_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return ( pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension))); + +} + +static uint8_t unpack_stop_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_stop_request_t *pNfapiMsg = (nfapi_stop_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_stop_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_stop_response_t *pNfapiMsg = (nfapi_stop_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + }; + + return ( pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension))); + +} +static uint8_t unpack_measurement_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_measurement_request_t *pNfapiMsg = (nfapi_measurement_request_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_MEASUREMENT_REQUEST_DL_RS_XTX_POWER_TAG, &pNfapiMsg->dl_rs_tx_power, &unpack_uint16_tlv_value}, + { NFAPI_MEASUREMENT_REQUEST_RECEIVED_INTERFERENCE_POWER_TAG, &pNfapiMsg->received_interference_power, &unpack_uint16_tlv_value}, + { NFAPI_MEASUREMENT_REQUEST_THERMAL_NOISE_POWER_TAG, &pNfapiMsg->thermal_noise_power, &unpack_uint16_tlv_value}, + }; + + return unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension)); + +} + +static uint8_t unpack_received_interference_power_measurement_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_received_interference_power_measurement_t* value = (nfapi_received_interference_power_measurement_t*)tlv; + + return ( pull16(ppReadPackedMsg, &value->number_of_resource_blocks, end) && + pullarrays16(ppReadPackedMsg, value->received_interference_power, NFAPI_MAX_RECEIVED_INTERFERENCE_POWER_RESULTS, value->number_of_resource_blocks, end)); +} + + +static uint8_t unpack_measurement_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_measurement_response_t *pNfapiMsg = (nfapi_measurement_response_t*)msg; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_MEASUREMENT_RESPONSE_DL_RS_POWER_MEASUREMENT_TAG, &pNfapiMsg->dl_rs_tx_power_measurement, &unpack_int16_tlv_value}, + { NFAPI_MEASUREMENT_RESPONSE_RECEIVED_INTERFERENCE_POWER_MEASUREMENT_TAG, &pNfapiMsg->received_interference_power_measurement, &unpack_received_interference_power_measurement_value}, + { NFAPI_MEASUREMENT_RESPONSE_THERMAL_NOISE_MEASUREMENT_TAG, &pNfapiMsg->thermal_noise_power_measurement, &unpack_int16_tlv_value}, + }; + + return ( pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) && + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); + +} + +// unpack length check + +static int check_unpack_length(nfapi_message_id_e msgId, uint32_t unpackedBufLen) +{ + int retLen = 0; + + switch (msgId) + { + case NFAPI_PNF_PARAM_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_pnf_param_request_t)) + retLen = sizeof(nfapi_pnf_param_request_t); + break; + + case NFAPI_PNF_PARAM_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_pnf_param_response_t)) + retLen = sizeof(nfapi_pnf_param_response_t); + break; + + case NFAPI_PNF_CONFIG_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_pnf_config_request_t)) + retLen = sizeof(nfapi_pnf_config_request_t); + break; + + case NFAPI_PNF_CONFIG_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_pnf_config_response_t)) + retLen = sizeof(nfapi_pnf_config_response_t); + break; + + case NFAPI_PNF_START_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_pnf_start_request_t)) + retLen = sizeof(nfapi_pnf_start_request_t); + break; + + case NFAPI_PNF_START_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_pnf_start_response_t)) + retLen = sizeof(nfapi_pnf_start_response_t); + break; + + case NFAPI_PNF_STOP_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_pnf_stop_request_t)) + retLen = sizeof(nfapi_pnf_stop_request_t); + break; + + case NFAPI_PNF_STOP_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_pnf_stop_response_t)) + retLen = sizeof(nfapi_pnf_stop_response_t); + break; + + case NFAPI_PARAM_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_param_request_t)) + retLen = sizeof(nfapi_param_request_t); + break; + + case NFAPI_PARAM_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_param_response_t)) + retLen = sizeof(nfapi_param_response_t); + break; + + case NFAPI_CONFIG_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_config_request_t)) + retLen = sizeof(nfapi_config_request_t); + break; + + case NFAPI_CONFIG_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_config_response_t)) + retLen = sizeof(nfapi_config_response_t); + break; + + case NFAPI_START_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_start_request_t)) + retLen = sizeof(nfapi_start_request_t); + break; + + case NFAPI_START_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_start_response_t)) + retLen = sizeof(nfapi_start_response_t); + break; + + case NFAPI_STOP_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_stop_request_t)) + retLen = sizeof(nfapi_stop_request_t); + break; + + case NFAPI_STOP_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_stop_response_t)) + retLen = sizeof(nfapi_stop_response_t); + break; + + case NFAPI_MEASUREMENT_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_measurement_request_t)) + retLen = sizeof(nfapi_measurement_request_t); + break; + + case NFAPI_MEASUREMENT_RESPONSE: + if (unpackedBufLen >= sizeof(nfapi_measurement_response_t)) + retLen = sizeof(nfapi_measurement_response_t); + break; + + default: + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s Unknown message ID %d\n", __FUNCTION__, msgId); + break; + } + + return retLen; +} + + +// Main unpack functions - public + +int nfapi_p5_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_p4_p5_message_header_t *pMessageHeader = pUnpackedBuf; + uint8_t *pReadPackedMessage = pMessageBuf; + uint8_t *end = pMessageBuf + messageBufLen; + + if (pMessageBuf == NULL || pUnpackedBuf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P5 header unpack supplied pointers are null\n"); + return -1; + } + + if (messageBufLen < NFAPI_HEADER_LENGTH || unpackedBufLen < sizeof(nfapi_p4_p5_message_header_t)) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P5 header unpack supplied message buffer is too small %d, %d\n", messageBufLen, unpackedBufLen); + return -1; + } + + // process the header + return ( pull16(&pReadPackedMessage, &pMessageHeader->phy_id, end) && + pull16(&pReadPackedMessage, &pMessageHeader->message_id, end) && + pull16(&pReadPackedMessage, &pMessageHeader->message_length, end) && + pull16(&pReadPackedMessage, &pMessageHeader->spare, end) ); + +} + +int nfapi_p5_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t* config) +{ + nfapi_p4_p5_message_header_t *pMessageHeader = pUnpackedBuf; + uint8_t *pReadPackedMessage = pMessageBuf; + uint8_t *end = pMessageBuf + messageBufLen; + + if (pMessageBuf == NULL || pUnpackedBuf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P5 unpack supplied pointers are null\n"); + return -1; + } + + if (messageBufLen < NFAPI_HEADER_LENGTH || unpackedBufLen < sizeof(nfapi_p4_p5_message_header_t)) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P5 unpack supplied message buffer is too small %d, %d\n", messageBufLen, unpackedBufLen); + return -1; + } + + // clean the supplied buffer for - tag value blanking + (void)memset(pUnpackedBuf, 0, unpackedBufLen); + + // process the header + if( !(pull16(&pReadPackedMessage, &pMessageHeader->phy_id, end ) && + pull16(&pReadPackedMessage, &pMessageHeader->message_id, end) && + pull16(&pReadPackedMessage, &pMessageHeader->message_length, end) && + pull16(&pReadPackedMessage, &pMessageHeader->spare, end))) + { + // failed to read the header + return -1; + } + + int result = -1; + + + if(check_unpack_length(pMessageHeader->message_id, unpackedBufLen) == 0) + { + // the unpack buffer is not big enough for the struct + return -1; + } + + // look for the specific message + switch (pMessageHeader->message_id) + { + case NFAPI_PNF_PARAM_REQUEST: + result = unpack_pnf_param_request(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_PNF_PARAM_RESPONSE: + result = unpack_pnf_param_response(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_PNF_CONFIG_REQUEST: + result = unpack_pnf_config_request(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_PNF_CONFIG_RESPONSE: + result = unpack_pnf_config_response(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_PNF_START_REQUEST: + result = unpack_pnf_start_request(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_PNF_START_RESPONSE: + result = unpack_pnf_start_response(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_PNF_STOP_REQUEST: + result = unpack_pnf_stop_request(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_PNF_STOP_RESPONSE: + result = unpack_pnf_stop_response(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_PARAM_REQUEST: + result = unpack_param_request(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_PARAM_RESPONSE: + result = unpack_param_response(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_CONFIG_REQUEST: + result = unpack_config_request(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_CONFIG_RESPONSE: + result = unpack_config_response(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_START_REQUEST: + result = unpack_start_request(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_START_RESPONSE: + result = unpack_start_response(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_STOP_REQUEST: + result = unpack_stop_request(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_STOP_RESPONSE: + result = unpack_stop_response(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_MEASUREMENT_REQUEST: + result = unpack_measurement_request(&pReadPackedMessage, end, pMessageHeader, config); + break; + + case NFAPI_MEASUREMENT_RESPONSE: + result = unpack_measurement_response(&pReadPackedMessage, end, pMessageHeader, config); + break; + + default: + if(pMessageHeader->message_id >= NFAPI_VENDOR_EXT_MSG_MIN && + pMessageHeader->message_id <= NFAPI_VENDOR_EXT_MSG_MAX) + { + if(config && config->unpack_p4_p5_vendor_extension) + { + result = (config->unpack_p4_p5_vendor_extension)(pMessageHeader, &pReadPackedMessage, end, config); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s VE NFAPI message ID %d. No ve decoder provided\n", __FUNCTION__, pMessageHeader->message_id); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s NFAPI Unknown P5 message ID %d\n", __FUNCTION__, pMessageHeader->message_id); + } + break; + } + + return result; +} + diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c new file mode 100644 index 0000000000..69ff860774 --- /dev/null +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c @@ -0,0 +1,6184 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +extern int nfapi_unpack_p7_vendor_extension(nfapi_p7_message_header_t* header, uint8_t **ppReadPackedMsg, void* user_data); +extern int nfapi_pack_p7_vendor_extension(nfapi_p7_message_header_t* header, uint8_t **ppWritePackedMsg, void* user_data); + +uint32_t nfapi_calculate_checksum(uint8_t* buffer, uint16_t len) +{ + uint32_t chksum = 0; + // calcaulte upto the checksum + chksum = crc32(chksum, buffer, 8); + + // skip the checksum + uint8_t zeros[4] = {0, 0, 0, 0}; + chksum = crc32(chksum, zeros, 4); + + // continu with the rest of the mesage + chksum = crc32(chksum, &buffer[NFAPI_P7_HEADER_LENGTH], len - NFAPI_P7_HEADER_LENGTH); + + // return the inverse + return ~(chksum); +} + +int nfapi_p7_update_checksum(uint8_t* buffer, uint32_t len) +{ + uint32_t checksum = nfapi_calculate_checksum(buffer, len); + + uint8_t* p_write = &buffer[8]; + return (push32(checksum, &p_write, buffer + len) > 0 ? 0 : -1); +} + +int nfapi_p7_update_transmit_timestamp(uint8_t* buffer, uint32_t timestamp) +{ + uint8_t* p_write = &buffer[12]; + return (push32(timestamp, &p_write, buffer + 16) > 0 ? 0 : -1); +} + +uint32_t nfapi_p7_calculate_checksum(uint8_t* buffer, uint32_t len) +{ + return nfapi_calculate_checksum(buffer, len); +} + +void* nfapi_p7_allocate(size_t size, nfapi_p7_codec_config_t* config) +{ + if(size == 0) + return 0; + + if(config && config->allocate) + { + return (config->allocate)(size); + } + else + { + return calloc(1, size); + } +} + +void nfapi_p7_deallocate(void* ptr, nfapi_p7_codec_config_t* config) +{ + if(ptr == NULL) + return; + + if(config && config->deallocate) + { + return (config->deallocate)(ptr); + } + else + { + return free(ptr); + } +} +// Pack routines + + +static uint8_t pack_dl_config_dci_dl_pdu_rel8_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_dci_dl_pdu_rel8_t* value = (nfapi_dl_config_dci_dl_pdu_rel8_t*)tlv; + + //NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() dci_format:%u\n", __FUNCTION__, value->dci_format); + + return ( push8(value->dci_format, ppWritePackedMsg, end) && + push8(value->cce_idx, ppWritePackedMsg, end) && + push8(value->aggregation_level, ppWritePackedMsg, end) && + push16(value->rnti, ppWritePackedMsg, end) && + push8(value->resource_allocation_type, ppWritePackedMsg, end) && + push8(value->virtual_resource_block_assignment_flag, ppWritePackedMsg, end) && + push32(value->resource_block_coding, ppWritePackedMsg, end) && + push8(value->mcs_1, ppWritePackedMsg, end) && + push8(value->redundancy_version_1, ppWritePackedMsg, end) && + push8(value->new_data_indicator_1, ppWritePackedMsg, end) && + push8(value->transport_block_to_codeword_swap_flag, ppWritePackedMsg, end) && + push8(value->mcs_2, ppWritePackedMsg, end) && + push8(value->redundancy_version_2, ppWritePackedMsg, end) && + push8(value->new_data_indicator_2, ppWritePackedMsg, end) && + push8(value->harq_process, ppWritePackedMsg, end) && + push8(value->tpmi, ppWritePackedMsg, end) && + push8(value->pmi, ppWritePackedMsg, end) && + push8(value->precoding_information, ppWritePackedMsg, end) && + push8(value->tpc, ppWritePackedMsg, end) && + push8(value->downlink_assignment_index, ppWritePackedMsg, end) && + push8(value->ngap, ppWritePackedMsg, end) && + push8(value->transport_block_size_index, ppWritePackedMsg, end) && + push8(value->downlink_power_offset, ppWritePackedMsg, end) && + push8(value->allocate_prach_flag, ppWritePackedMsg, end) && + push8(value->preamble_index, ppWritePackedMsg, end) && + push8(value->prach_mask_index, ppWritePackedMsg, end) && + push8(value->rnti_type, ppWritePackedMsg, end) && + push16(value->transmission_power, ppWritePackedMsg, end)); +} + +static uint8_t pack_dl_config_dci_dl_pdu_rel9_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_dci_dl_pdu_rel9_t* value = (nfapi_dl_config_dci_dl_pdu_rel9_t*)tlv; + + return( push8(value->mcch_flag, ppWritePackedMsg, end) && + push8(value->mcch_change_notification, ppWritePackedMsg, end) && + push8(value->scrambling_identity, ppWritePackedMsg, end)); +} + +static uint8_t pack_dl_config_dci_dl_pdu_rel10_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_dci_dl_pdu_rel10_t* value = (nfapi_dl_config_dci_dl_pdu_rel10_t*)tlv; + + return ( push8(value->cross_carrier_scheduling_flag, ppWritePackedMsg, end) && + push8(value->carrier_indicator, ppWritePackedMsg, end) && + push8(value->srs_flag, ppWritePackedMsg, end) && + push8(value->srs_request, ppWritePackedMsg, end) && + push8(value->antenna_ports_scrambling_and_layers, ppWritePackedMsg, end) && + push8(value->total_dci_length_including_padding, ppWritePackedMsg, end) && + push8(value->n_dl_rb, ppWritePackedMsg, end)); +} + +static uint8_t pack_dl_config_dci_dl_pdu_rel11_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_dci_dl_pdu_rel11_t* value = (nfapi_dl_config_dci_dl_pdu_rel11_t*)tlv; + + return ( push8(value->harq_ack_resource_offset, ppWritePackedMsg, end) && + push8(value->pdsch_re_mapping_quasi_co_location_indicator, ppWritePackedMsg, end)); +} + +static uint8_t pack_dl_config_dci_dl_pdu_rel12_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_dci_dl_pdu_rel12_t* value = (nfapi_dl_config_dci_dl_pdu_rel12_t*)tlv; + + return ( push8(value->primary_cell_type, ppWritePackedMsg, end) && + push8(value->ul_dl_configuration_flag, ppWritePackedMsg, end) && + push8(value->number_ul_dl_configurations, ppWritePackedMsg, end) && + pusharray8(value->ul_dl_configuration_indication, NFAPI_MAX_UL_DL_CONFIGURATIONS, value->number_ul_dl_configurations, ppWritePackedMsg, end)); +} + +static uint8_t pack_tpm_value(nfapi_dl_config_dci_dl_tpm_t* value, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + if (!( push8(value->num_prb_per_subband, ppWritePackedMsg, end) && + push8(value->number_of_subbands, ppWritePackedMsg, end) && + push8(value->num_antennas, ppWritePackedMsg, end))) + return 0; + + uint8_t idx = 0; + for(idx = 0; idx < value->number_of_subbands; ++idx) + { + nfapi_dl_config_dci_dl_tpm_subband_info_t* subband_info = &(value->subband_info[idx]); + + if(!(push8(subband_info->subband_index, ppWritePackedMsg, end) && + push8(subband_info->scheduled_ues, ppWritePackedMsg, end))) + return 0; + + + uint8_t antenna_idx = 0; + uint8_t scheduled_ue_idx = 0; + + for(antenna_idx = 0; antenna_idx < value->num_antennas; ++antenna_idx) + { + for(scheduled_ue_idx = 0; scheduled_ue_idx < subband_info->scheduled_ues; ++scheduled_ue_idx) + { + if(!push16(subband_info->precoding_value[antenna_idx][scheduled_ue_idx], ppWritePackedMsg, end)) + return 0; + } + } + + } + + + return 1; + +} + +static uint8_t pack_dl_config_dci_dl_pdu_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_dci_dl_pdu_rel13_t* value = (nfapi_dl_config_dci_dl_pdu_rel13_t*)tlv; + + return( push8(value->laa_end_partial_sf_flag, ppWritePackedMsg, end) && + push8(value->laa_end_partial_sf_configuration, ppWritePackedMsg, end) && + push8(value->initial_lbt_sf, ppWritePackedMsg, end) && + push8(value->codebook_size_determination, ppWritePackedMsg, end) && + push8(value->drms_table_flag, ppWritePackedMsg, end) && + push8(value->tpm_struct_flag, ppWritePackedMsg, end) && + (value->tpm_struct_flag == 1 ? pack_tpm_value(&(value->tpm), ppWritePackedMsg, end) : 1)); +} + +static uint8_t pack_dl_config_bch_pdu_rel8_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_bch_pdu_rel8_t* value = (nfapi_dl_config_bch_pdu_rel8_t*)tlv; + + //NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s()\n", __FUNCTION__); + + return( push16(value->length, ppWritePackedMsg, end) && + push16(value->pdu_index, ppWritePackedMsg, end) && + push16(value->transmission_power, ppWritePackedMsg, end)); +} +static uint8_t pack_dl_config_mch_pdu_rel8_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_mch_pdu_rel8_t* value = (nfapi_dl_config_mch_pdu_rel8_t*)tlv; + + return ( push16(value->length, ppWritePackedMsg, end) && + push16(value->pdu_index, ppWritePackedMsg, end) && + push16(value->rnti, ppWritePackedMsg, end) && + push8(value->resource_allocation_type, ppWritePackedMsg, end) && + push32(value->resource_block_coding, ppWritePackedMsg, end) && + push8(value->modulation, ppWritePackedMsg, end) && + push16(value->transmission_power, ppWritePackedMsg, end) && + push16(value->mbsfn_area_id, ppWritePackedMsg, end)); +} + +static uint8_t pack_bf_vector_info(void* elem, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_bf_vector_t* bf = (nfapi_bf_vector_t*)elem; + + return ( push8(bf->subband_index, ppWritePackedMsg, end) && + push8(bf->num_antennas, ppWritePackedMsg, end) && + pusharray16(bf->bf_value, NFAPI_MAX_NUM_ANTENNAS, bf->num_antennas, ppWritePackedMsg, end)); + + +} +static uint8_t pack_dl_config_dlsch_pdu_rel8_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_dlsch_pdu_rel8_t* value = (nfapi_dl_config_dlsch_pdu_rel8_t*)tlv; + + return ( push16(value->length, ppWritePackedMsg, end) && + push16(value->pdu_index, ppWritePackedMsg, end) && + push16(value->rnti, ppWritePackedMsg, end) && + push8(value->resource_allocation_type, ppWritePackedMsg, end) && + push8(value->virtual_resource_block_assignment_flag, ppWritePackedMsg, end) && + push32(value->resource_block_coding, ppWritePackedMsg, end) && + push8(value->modulation, ppWritePackedMsg, end) && + push8(value->redundancy_version, ppWritePackedMsg, end) && + push8(value->transport_blocks, ppWritePackedMsg, end) && + push8(value->transport_block_to_codeword_swap_flag, ppWritePackedMsg, end) && + push8(value->transmission_scheme, ppWritePackedMsg, end) && + push8(value->number_of_layers, ppWritePackedMsg, end) && + push8(value->number_of_subbands, ppWritePackedMsg, end) && + pusharray8(value->codebook_index, NFAPI_MAX_NUM_SUBBANDS, value->number_of_subbands, ppWritePackedMsg, end) && + push8(value->ue_category_capacity, ppWritePackedMsg, end) && + push8(value->pa, ppWritePackedMsg, end) && + push8(value->delta_power_offset_index, ppWritePackedMsg, end) && + push8(value->ngap, ppWritePackedMsg, end) && + push8(value->nprb, ppWritePackedMsg, end) && + push8(value->transmission_mode, ppWritePackedMsg, end) && + push8(value->num_bf_prb_per_subband, ppWritePackedMsg, end) && + push8(value->num_bf_vector, ppWritePackedMsg, end) && + packarray(value->bf_vector, sizeof(nfapi_bf_vector_t), NFAPI_MAX_BF_VECTORS, value->num_bf_vector, ppWritePackedMsg, end, &pack_bf_vector_info)); + +} +static uint8_t pack_dl_config_dlsch_pdu_rel9_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_dlsch_pdu_rel9_t* value = (nfapi_dl_config_dlsch_pdu_rel9_t*)tlv; + return ( push8(value->nscid, ppWritePackedMsg, end) ); +} +static uint8_t pack_dl_config_dlsch_pdu_rel10_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_dlsch_pdu_rel10_t* value = (nfapi_dl_config_dlsch_pdu_rel10_t*)tlv; + + return ( push8(value->csi_rs_flag, ppWritePackedMsg, end) && + push8(value->csi_rs_resource_config_r10, ppWritePackedMsg, end) && + push16(value->csi_rs_zero_tx_power_resource_config_bitmap_r10, ppWritePackedMsg, end) && + push8(value->csi_rs_number_nzp_configuration, ppWritePackedMsg, end) && + pusharray8(value->csi_rs_resource_config, NFAPI_MAX_CSI_RS_RESOURCE_CONFIG, value->csi_rs_number_nzp_configuration, ppWritePackedMsg, end) && + push8(value->pdsch_start, ppWritePackedMsg, end)); +} +static uint8_t pack_dl_config_dlsch_pdu_rel11_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_dlsch_pdu_rel11_t* value = (nfapi_dl_config_dlsch_pdu_rel11_t*)tlv; + + return( push8(value->drms_config_flag, ppWritePackedMsg, end) && + push16(value->drms_scrambling, ppWritePackedMsg, end) && + push8(value->csi_config_flag, ppWritePackedMsg, end) && + push16(value->csi_scrambling, ppWritePackedMsg, end) && + push8(value->pdsch_re_mapping_flag, ppWritePackedMsg, end) && + push8(value->pdsch_re_mapping_atenna_ports, ppWritePackedMsg, end) && + push8(value->pdsch_re_mapping_freq_shift, ppWritePackedMsg, end)); +} +static uint8_t pack_dl_config_dlsch_pdu_rel12_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_dlsch_pdu_rel12_t* value = (nfapi_dl_config_dlsch_pdu_rel12_t*)tlv; + + return( push8(value->altcqi_table_r12, ppWritePackedMsg, end) && + push8(value->maxlayers, ppWritePackedMsg, end) && + push8(value->n_dl_harq, ppWritePackedMsg, end)); +} +static uint8_t pack_dl_config_dlsch_pdu_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_dlsch_pdu_rel13_t* value = (nfapi_dl_config_dlsch_pdu_rel13_t*)tlv; + + return( push8(value->dwpts_symbols, ppWritePackedMsg, end) && + push8(value->initial_lbt_sf, ppWritePackedMsg, end) && + push8(value->ue_type, ppWritePackedMsg, end) && + push8(value->pdsch_payload_type, ppWritePackedMsg, end) && + push16(value->initial_transmission_sf_io, ppWritePackedMsg, end) && + push8(value->drms_table_flag, ppWritePackedMsg, end)); +} +static uint8_t pack_dl_config_pch_pdu_rel8_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_pch_pdu_rel8_t* value = (nfapi_dl_config_pch_pdu_rel8_t*)tlv; + + return( push16(value->length, ppWritePackedMsg, end) && + push16(value->pdu_index, ppWritePackedMsg, end) && + push16(value->p_rnti, ppWritePackedMsg, end) && + push8(value->resource_allocation_type, ppWritePackedMsg, end) && + push8(value->virtual_resource_block_assignment_flag, ppWritePackedMsg, end) && + push32(value->resource_block_coding, ppWritePackedMsg, end) && + push8(value->mcs, ppWritePackedMsg, end) && + push8(value->redundancy_version, ppWritePackedMsg, end) && + push8(value->number_of_transport_blocks, ppWritePackedMsg, end) && + push8(value->transport_block_to_codeword_swap_flag, ppWritePackedMsg, end) && + push8(value->transmission_scheme, ppWritePackedMsg, end) && + push8(value->number_of_layers, ppWritePackedMsg, end) && + push8(value->codebook_index, ppWritePackedMsg, end) && + push8(value->ue_category_capacity, ppWritePackedMsg, end) && + push8(value->pa, ppWritePackedMsg, end) && + push16(value->transmission_power, ppWritePackedMsg, end) && + push8(value->nprb, ppWritePackedMsg, end) && + push8(value->ngap, ppWritePackedMsg, end)); +} +static uint8_t pack_dl_config_pch_pdu_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_pch_pdu_rel13_t* value = (nfapi_dl_config_pch_pdu_rel13_t*)tlv; + + return ( push8(value->ue_mode, ppWritePackedMsg, end) && + push16(value->initial_transmission_sf_io, ppWritePackedMsg, end)); +} +static uint8_t pack_dl_config_prs_pdu_rel9_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_prs_pdu_rel9_t* value = (nfapi_dl_config_prs_pdu_rel9_t*)tlv; + + return( push16(value->transmission_power, ppWritePackedMsg, end) && + push8(value->prs_bandwidth, ppWritePackedMsg, end) && + push8(value->prs_cyclic_prefix_type, ppWritePackedMsg, end) && + push8(value->prs_muting, ppWritePackedMsg, end)); +} +static uint8_t pack_dl_config_csi_rs_pdu_rel10_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_csi_rs_pdu_rel10_t* value = (nfapi_dl_config_csi_rs_pdu_rel10_t*)tlv; + + return( push8(value->csi_rs_antenna_port_count_r10, ppWritePackedMsg, end) && + push8(value->csi_rs_resource_config_r10, ppWritePackedMsg, end) && + push16(value->transmission_power, ppWritePackedMsg, end) && + push16(value->csi_rs_zero_tx_power_resource_config_bitmap_r10, ppWritePackedMsg, end) && + push8(value->csi_rs_number_of_nzp_configuration, ppWritePackedMsg, end) && + pusharray8(value->csi_rs_resource_config, NFAPI_MAX_CSI_RS_RESOURCE_CONFIG, value->csi_rs_number_of_nzp_configuration, ppWritePackedMsg, end)); +} +static uint8_t pack_dl_config_csi_rs_pdu_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_csi_rs_pdu_rel13_t* value = (nfapi_dl_config_csi_rs_pdu_rel13_t*)tlv; + + if(!(push8(value->csi_rs_class, ppWritePackedMsg, end) && + push8(value->cdm_type, ppWritePackedMsg, end) && + push8(value->num_bf_vector, ppWritePackedMsg, end))) + { + return 0; + } + + uint16_t i; + for(i = 0; i < value->num_bf_vector; ++i) + { + if(!(push8(value->bf_vector[i].csi_rs_resource_index, ppWritePackedMsg, end) && + pusharray16(value->bf_vector[i].bf_value, NFAPI_MAX_ANTENNA_PORT_COUNT, NFAPI_MAX_ANTENNA_PORT_COUNT, ppWritePackedMsg, end))) + return 0; + } + + return 1; +} +static uint8_t pack_bf_vector(nfapi_bf_vector_t* vector, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + return ( push8(vector->subband_index, ppWritePackedMsg, end) && + push8(vector->num_antennas, ppWritePackedMsg, end) && + pusharray16(vector->bf_value, NFAPI_MAX_NUM_ANTENNAS, vector->num_antennas, ppWritePackedMsg, end)); +} + +static uint8_t pack_dl_config_epdcch_parameters_rel11_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_epdcch_parameters_rel11_t* value = (nfapi_dl_config_epdcch_parameters_rel11_t*)tlv; + + return ( push8(value->epdcch_resource_assignment_flag, ppWritePackedMsg, end) && + push16(value->epdcch_id, ppWritePackedMsg, end) && + push8(value->epdcch_start_symbol, ppWritePackedMsg, end) && + push8(value->epdcch_num_prb, ppWritePackedMsg, end) && + pusharray8(value->epdcch_prb_index, NFAPI_MAX_EPDCCH_PRB, value->epdcch_num_prb, ppWritePackedMsg, end) && + pack_bf_vector(&value->bf_vector, ppWritePackedMsg, end)); +} +static uint8_t pack_dl_config_epdcch_parameters_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_epdcch_parameters_rel13_t* value = (nfapi_dl_config_epdcch_parameters_rel13_t*)tlv; + + return (push8(value->dwpts_symbols, ppWritePackedMsg, end) && + push8(value->initial_lbt_sf, ppWritePackedMsg, end)); +} +static uint8_t pack_dl_config_mpdcch_pdu_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_mpdcch_pdu_rel13_t* value = (nfapi_dl_config_mpdcch_pdu_rel13_t*)tlv; + + return ( push8(value->mpdcch_narrow_band, ppWritePackedMsg, end) && + push8(value->number_of_prb_pairs, ppWritePackedMsg, end) && + push8(value->resource_block_assignment, ppWritePackedMsg, end) && + push8(value->mpdcch_tansmission_type, ppWritePackedMsg, end) && + push8(value->start_symbol, ppWritePackedMsg, end) && + push8(value->ecce_index, ppWritePackedMsg, end) && + push8(value->aggregation_level, ppWritePackedMsg, end) && + push8(value->rnti_type, ppWritePackedMsg, end) && + push16(value->rnti, ppWritePackedMsg, end) && + push8(value->ce_mode, ppWritePackedMsg, end) && + push16(value->drms_scrambling_init, ppWritePackedMsg, end) && + push16(value->initial_transmission_sf_io, ppWritePackedMsg, end) && + push16(value->transmission_power, ppWritePackedMsg, end) && + push8(value->dci_format, ppWritePackedMsg, end) && + push16(value->resource_block_coding, ppWritePackedMsg, end) && + push8(value->mcs, ppWritePackedMsg, end) && + push8(value->pdsch_reptition_levels, ppWritePackedMsg, end) && + push8(value->redundancy_version, ppWritePackedMsg, end) && + push8(value->new_data_indicator, ppWritePackedMsg, end) && + push8(value->harq_process, ppWritePackedMsg, end) && + push8(value->tpmi_length, ppWritePackedMsg, end) && + push8(value->tpmi, ppWritePackedMsg, end) && + push8(value->pmi_flag, ppWritePackedMsg, end) && + push8(value->pmi, ppWritePackedMsg, end) && + push8(value->harq_resource_offset, ppWritePackedMsg, end) && + push8(value->dci_subframe_repetition_number, ppWritePackedMsg, end) && + push8(value->tpc, ppWritePackedMsg, end) && + push8(value->downlink_assignment_index_length, ppWritePackedMsg, end) && + push8(value->downlink_assignment_index, ppWritePackedMsg, end) && + push8(value->allocate_prach_flag, ppWritePackedMsg, end) && + push8(value->preamble_index, ppWritePackedMsg, end) && + push8(value->prach_mask_index, ppWritePackedMsg, end) && + push8(value->starting_ce_level, ppWritePackedMsg, end) && + push8(value->srs_request, ppWritePackedMsg, end) && + push8(value->antenna_ports_and_scrambling_identity_flag, ppWritePackedMsg, end) && + push8(value->antenna_ports_and_scrambling_identity, ppWritePackedMsg, end) && + push8(value->frequency_hopping_enabled_flag, ppWritePackedMsg, end) && + push8(value->paging_direct_indication_differentiation_flag, ppWritePackedMsg, end) && + push8(value->direct_indication, ppWritePackedMsg, end) && + push8(value->total_dci_length_including_padding, ppWritePackedMsg, end) && + push8(value->number_of_tx_antenna_ports, ppWritePackedMsg, end) && + pusharray16(value->precoding_value, NFAPI_MAX_TX_PHYSICAL_ANTENNA_PORTS, value->number_of_tx_antenna_ports, ppWritePackedMsg, end)); +} + + +static uint8_t pack_dl_config_nbch_pdu_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_nbch_pdu_rel13_t* value = (nfapi_dl_config_nbch_pdu_rel13_t*)tlv; + + return (push16(value->length, ppWritePackedMsg, end) && + push16(value->pdu_index, ppWritePackedMsg, end) && + push16(value->transmission_power, ppWritePackedMsg, end) && + push16(value->hyper_sfn_2_lsbs, ppWritePackedMsg, end)); +} + + +static uint8_t pack_dl_config_npdcch_pdu_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_npdcch_pdu_rel13_t* value = (nfapi_dl_config_npdcch_pdu_rel13_t*)tlv; + + return (push16(value->length, ppWritePackedMsg, end) && + push16(value->pdu_index, ppWritePackedMsg, end) && + push8(value->ncce_index, ppWritePackedMsg, end) && + push8(value->aggregation_level, ppWritePackedMsg, end) && + push8(value->start_symbol, ppWritePackedMsg, end) && + push8(value->rnti_type, ppWritePackedMsg, end) && + push16(value->rnti, ppWritePackedMsg, end) && + push8(value->scrambling_reinitialization_batch_index, ppWritePackedMsg, end) && + push8(value->nrs_antenna_ports_assumed_by_the_ue, ppWritePackedMsg, end) && + push8(value->dci_format, ppWritePackedMsg, end) && + push8(value->scheduling_delay, ppWritePackedMsg, end) && + push8(value->resource_assignment, ppWritePackedMsg, end) && + push8(value->repetition_number, ppWritePackedMsg, end) && + push8(value->mcs, ppWritePackedMsg, end) && + push8(value->new_data_indicator, ppWritePackedMsg, end) && + push8(value->harq_ack_resource, ppWritePackedMsg, end) && + push8(value->npdcch_order_indication, ppWritePackedMsg, end) && + push8(value->starting_number_of_nprach_repetitions, ppWritePackedMsg, end) && + push8(value->subcarrier_indication_of_nprach, ppWritePackedMsg, end) && + push8(value->paging_direct_indication_differentation_flag, ppWritePackedMsg, end) && + push8(value->direct_indication, ppWritePackedMsg, end) && + push8(value->dci_subframe_repetition_number, ppWritePackedMsg, end) && + push8(value->total_dci_length_including_padding, ppWritePackedMsg, end)); +} + +static uint8_t pack_dl_config_ndlsch_pdu_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_ndlsch_pdu_rel13_t* value = (nfapi_dl_config_ndlsch_pdu_rel13_t*)tlv; + + return (push16(value->length, ppWritePackedMsg, end) && + push16(value->pdu_index, ppWritePackedMsg, end) && + push8(value->start_symbol, ppWritePackedMsg, end) && + push8(value->rnti_type, ppWritePackedMsg, end) && + push16(value->rnti, ppWritePackedMsg, end) && + push16(value->resource_assignment, ppWritePackedMsg, end) && + push16(value->repetition_number, ppWritePackedMsg, end) && + push8(value->modulation, ppWritePackedMsg, end) && + push8(value->number_of_subframes_for_resource_assignment, ppWritePackedMsg, end) && + push8(value->scrambling_sequence_initialization_cinit, ppWritePackedMsg, end) && + push16(value->sf_idx, ppWritePackedMsg, end) && + push8(value->nrs_antenna_ports_assumed_by_the_ue, ppWritePackedMsg, end)); +} + +static uint8_t pack_dl_config_request_body_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_dl_config_request_body_t* value = (nfapi_dl_config_request_body_t*)tlv; + + //NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() dci:%u pdu:%u pdsch:%u rnti:%u pcfich:%u\n", __FUNCTION__, value->number_dci, value->number_pdu, value->number_pdsch_rnti, value->transmission_power_pcfich); + + if(!(push8(value->number_pdcch_ofdm_symbols, ppWritePackedMsg, end) && + push8(value->number_dci, ppWritePackedMsg, end) && + push16(value->number_pdu, ppWritePackedMsg, end) && + push8(value->number_pdsch_rnti, ppWritePackedMsg, end) && + push16(value->transmission_power_pcfich, ppWritePackedMsg, end))) + { + return 0; + } + + uint16_t i = 0; + uint16_t total_number_of_pdus = value->number_pdu; + for(; i < total_number_of_pdus; ++i) + { + nfapi_dl_config_request_pdu_t* pdu = &(value->dl_config_pdu_list[i]); + + if(push8(pdu->pdu_type, ppWritePackedMsg, end) == 0) + return 0; + + // Put a 0 size in and then determine the size after the pdu + // has been writen and write the calculated size + uint8_t* pWritePackedMsgPduSize = *ppWritePackedMsg; + pdu->pdu_size = 0; + if(push8(pdu->pdu_size, ppWritePackedMsg, end) == 0) + return 0; + + switch(pdu->pdu_type) + { + case NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE: + { + //NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE\n", __FUNCTION__); + + if(!(pack_tlv(NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel8, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel8_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL9_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel9, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel9_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL10_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel10, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel10_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL11_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel11, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel11_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL12_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel12, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel12_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL13_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel13, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel13_value))) + { + return 0; + } + } + break; + case NFAPI_DL_CONFIG_BCH_PDU_TYPE: + { + //NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() NFAPI_DL_CONFIG_BCH_PDU_TYPE\n", __FUNCTION__); + + if(!(pack_tlv(NFAPI_DL_CONFIG_REQUEST_BCH_PDU_REL8_TAG, &pdu->bch_pdu.bch_pdu_rel8, ppWritePackedMsg, end, &pack_dl_config_bch_pdu_rel8_value))) + return 0; + } + break; + case NFAPI_DL_CONFIG_MCH_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_DL_CONFIG_REQUEST_MCH_PDU_REL8_TAG, &pdu->mch_pdu.mch_pdu_rel8, ppWritePackedMsg, end, &pack_dl_config_mch_pdu_rel8_value))) + return 0; + } + break; + case NFAPI_DL_CONFIG_DLSCH_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG, &pdu->dlsch_pdu.dlsch_pdu_rel8, ppWritePackedMsg, end, &pack_dl_config_dlsch_pdu_rel8_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL9_TAG, &pdu->dlsch_pdu.dlsch_pdu_rel9, ppWritePackedMsg, end, &pack_dl_config_dlsch_pdu_rel9_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG, &pdu->dlsch_pdu.dlsch_pdu_rel10, ppWritePackedMsg, end, &pack_dl_config_dlsch_pdu_rel10_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL11_TAG, &pdu->dlsch_pdu.dlsch_pdu_rel11, ppWritePackedMsg, end, &pack_dl_config_dlsch_pdu_rel11_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL12_TAG, &pdu->dlsch_pdu.dlsch_pdu_rel12, ppWritePackedMsg, end, &pack_dl_config_dlsch_pdu_rel12_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG, &pdu->dlsch_pdu.dlsch_pdu_rel13, ppWritePackedMsg, end, &pack_dl_config_dlsch_pdu_rel13_value))) + return 0; + } + break; + case NFAPI_DL_CONFIG_PCH_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_DL_CONFIG_REQUEST_PCH_PDU_REL8_TAG, &pdu->pch_pdu.pch_pdu_rel8, ppWritePackedMsg, end, &pack_dl_config_pch_pdu_rel8_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_PCH_PDU_REL13_TAG, &pdu->pch_pdu.pch_pdu_rel13, ppWritePackedMsg, end, &pack_dl_config_pch_pdu_rel13_value))) + return 0; + } + break; + case NFAPI_DL_CONFIG_PRS_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_DL_CONFIG_REQUEST_PRS_PDU_REL9_TAG, &pdu->prs_pdu.prs_pdu_rel9, ppWritePackedMsg, end, &pack_dl_config_prs_pdu_rel9_value))) + return 0; + } + break; + case NFAPI_DL_CONFIG_CSI_RS_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_DL_CONFIG_REQUEST_CSI_RS_PDU_REL10_TAG, &pdu->csi_rs_pdu.csi_rs_pdu_rel10, ppWritePackedMsg, end, &pack_dl_config_csi_rs_pdu_rel10_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_CSI_RS_PDU_REL13_TAG, &pdu->csi_rs_pdu.csi_rs_pdu_rel13, ppWritePackedMsg, end, &pack_dl_config_csi_rs_pdu_rel13_value))) + return 0; + } + break; + case NFAPI_DL_CONFIG_EPDCCH_DL_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL8_TAG, &pdu->epdcch_pdu.epdcch_pdu_rel8, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel8_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL9_TAG, &pdu->epdcch_pdu.epdcch_pdu_rel9, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel9_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL10_TAG, &pdu->epdcch_pdu.epdcch_pdu_rel10, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel10_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL11_TAG, &pdu->epdcch_pdu.epdcch_pdu_rel11, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel11_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL12_TAG, &pdu->epdcch_pdu.epdcch_pdu_rel12, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel12_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL13_TAG, &pdu->epdcch_pdu.epdcch_pdu_rel13, ppWritePackedMsg, end, &pack_dl_config_dci_dl_pdu_rel13_value) && + pack_tlv(NFAPI_DL_CONFIG_REQUEST_EPDCCH_PARAM_REL11_TAG, &pdu->epdcch_pdu.epdcch_params_rel11, ppWritePackedMsg, end, &pack_dl_config_epdcch_parameters_rel11_value) & + pack_tlv(NFAPI_DL_CONFIG_REQUEST_EPDCCH_PARAM_REL13_TAG, &pdu->epdcch_pdu.epdcch_params_rel13, ppWritePackedMsg, end, &pack_dl_config_epdcch_parameters_rel13_value))) + return 0; + } + break; + case NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_DL_CONFIG_REQUEST_MPDCCH_PDU_REL13_TAG, &pdu->mpdcch_pdu.mpdcch_pdu_rel13, ppWritePackedMsg, end, &pack_dl_config_mpdcch_pdu_rel13_value))) + return 0; + } + break; + case NFAPI_DL_CONFIG_NBCH_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_DL_CONFIG_REQUEST_NBCH_PDU_REL13_TAG, &pdu->nbch_pdu.nbch_pdu_rel13, ppWritePackedMsg, end, &pack_dl_config_nbch_pdu_rel13_value))) + return 0; + } + break; + case NFAPI_DL_CONFIG_NPDCCH_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_DL_CONFIG_REQUEST_NPDCCH_PDU_REL13_TAG, &pdu->npdcch_pdu.npdcch_pdu_rel13, ppWritePackedMsg, end, &pack_dl_config_npdcch_pdu_rel13_value))) + return 0; + } + break; + case NFAPI_DL_CONFIG_NDLSCH_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_DL_CONFIG_REQUEST_NDLSCH_PDU_REL13_TAG, &pdu->ndlsch_pdu.ndlsch_pdu_rel13, ppWritePackedMsg, end, &pack_dl_config_ndlsch_pdu_rel13_value))) + return 0; + } + break; + default: + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "FIXME : Invalid pdu type %d \n", pdu->pdu_type ); + } + break; + }; + + // add 1 for the pdu_type. The delta will include the pdu_size + pdu->pdu_size = 1 + (*ppWritePackedMsg - pWritePackedMsgPduSize); + push8(pdu->pdu_size, &pWritePackedMsgPduSize, end); + } + + return 1; +} + +static uint8_t pack_dl_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_dl_config_request_t *pNfapiMsg = (nfapi_dl_config_request_t*)msg; + + //return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && + //pack_tlv(NFAPI_DL_CONFIG_REQUEST_BODY_TAG, &pNfapiMsg->dl_config_request_body, ppWritePackedMsg, end, &pack_dl_config_request_body_value) && + //pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); + { + uint8_t x = push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end); + uint8_t y = pack_tlv(NFAPI_DL_CONFIG_REQUEST_BODY_TAG, &pNfapiMsg->dl_config_request_body, ppWritePackedMsg, end, &pack_dl_config_request_body_value); + uint8_t z = pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config); + + if (!x || !y || !z) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() NFAPI_DL_CONFIG_REQUEST x:%u y:%u z:%u \n", __FUNCTION__,x,y,z); + } + + return x && y && z; + } +} + +static uint8_t pack_ul_config_request_ulsch_rel8_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t * end) +{ + nfapi_ul_config_ulsch_pdu_rel8_t* ulsch_pdu_rel8 = (nfapi_ul_config_ulsch_pdu_rel8_t*)tlv; + + return( push32(ulsch_pdu_rel8->handle, ppWritePackedMsg, end) && + push16(ulsch_pdu_rel8->size, ppWritePackedMsg, end) && + push16(ulsch_pdu_rel8->rnti, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel8->resource_block_start, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel8->number_of_resource_blocks, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel8->modulation_type, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel8->cyclic_shift_2_for_drms, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel8->frequency_hopping_enabled_flag, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel8->frequency_hopping_bits, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel8->new_data_indication, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel8->redundancy_version, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel8->harq_process_number, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel8->ul_tx_mode, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel8->current_tx_nb, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel8->n_srs, ppWritePackedMsg, end)); +} +static uint8_t pack_ul_config_request_ulsch_rel10_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_ulsch_pdu_rel10_t* ulsch_pdu_rel10 = (nfapi_ul_config_ulsch_pdu_rel10_t*)tlv; + + return (push8(ulsch_pdu_rel10->resource_allocation_type, ppWritePackedMsg, end) && + push32(ulsch_pdu_rel10->resource_block_coding, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel10->transport_blocks, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel10->transmission_scheme, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel10->number_of_layers, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel10->codebook_index, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel10->disable_sequence_hopping_flag, ppWritePackedMsg, end)); +} + +static uint8_t pack_ul_config_request_ulsch_rel11_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_ulsch_pdu_rel11_t* ulsch_pdu_rel11 = (nfapi_ul_config_ulsch_pdu_rel11_t*)tlv; + + return (push8(ulsch_pdu_rel11->virtual_cell_id_enabled_flag, ppWritePackedMsg, end) && + push16(ulsch_pdu_rel11->npusch_identity, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel11->dmrs_config_flag, ppWritePackedMsg, end) && + push16(ulsch_pdu_rel11->ndmrs_csh_identity, ppWritePackedMsg, end)); +} + +static uint8_t pack_ul_config_request_ulsch_rel13_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_ulsch_pdu_rel13_t* ulsch_pdu_rel13 = (nfapi_ul_config_ulsch_pdu_rel13_t*)tlv; + + return (push8(ulsch_pdu_rel13->ue_type, ppWritePackedMsg, end) && + push16(ulsch_pdu_rel13->total_number_of_repetitions, ppWritePackedMsg, end) && + push16(ulsch_pdu_rel13->repetition_number, ppWritePackedMsg, end) && + push16(ulsch_pdu_rel13->initial_transmission_sf_io, ppWritePackedMsg, end) && + push8(ulsch_pdu_rel13->empty_symbols_due_to_re_tunning, ppWritePackedMsg, end)); +} + +static uint8_t pack_ul_config_request_ulsch_pdu(nfapi_ul_config_ulsch_pdu* ulsch_pdu, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + return ( pack_tlv(NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG, &ulsch_pdu->ulsch_pdu_rel8, ppWritePackedMsg, end, &pack_ul_config_request_ulsch_rel8_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL10_TAG, &ulsch_pdu->ulsch_pdu_rel10, ppWritePackedMsg, end, &pack_ul_config_request_ulsch_rel10_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL11_TAG, &ulsch_pdu->ulsch_pdu_rel11, ppWritePackedMsg, end, &pack_ul_config_request_ulsch_rel11_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL13_TAG, &ulsch_pdu->ulsch_pdu_rel13, ppWritePackedMsg, end, &pack_ul_config_request_ulsch_rel13_value)); +} + +static uint8_t pack_ul_config_request_cqi_ri_rel8_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_cqi_ri_information_rel8_t* cqi_ri_info_rel8 = (nfapi_ul_config_cqi_ri_information_rel8_t*)tlv; + + return ( push8(cqi_ri_info_rel8->dl_cqi_pmi_size_rank_1, ppWritePackedMsg, end) && + push8(cqi_ri_info_rel8->dl_cqi_pmi_size_rank_greater_1, ppWritePackedMsg, end) && + push8(cqi_ri_info_rel8->ri_size, ppWritePackedMsg, end) && + push8(cqi_ri_info_rel8->delta_offset_cqi, ppWritePackedMsg, end) && + push8(cqi_ri_info_rel8->delta_offset_ri, ppWritePackedMsg, end)); +} + +static uint8_t pack_ul_config_request_cqi_ri_rel9_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_cqi_ri_information_rel9_t* cqi_ri_info_rel9 = (nfapi_ul_config_cqi_ri_information_rel9_t*)tlv; + + if(!(push8(cqi_ri_info_rel9->report_type, ppWritePackedMsg, end) && + push8(cqi_ri_info_rel9->delta_offset_cqi, ppWritePackedMsg, end) && + push8(cqi_ri_info_rel9->delta_offset_ri, ppWritePackedMsg, end))) + { + return 0; + } + + switch(cqi_ri_info_rel9->report_type) + { + case NFAPI_CSI_REPORT_TYPE_PERIODIC: + { + if(!(push8(cqi_ri_info_rel9->periodic_cqi_pmi_ri_report.dl_cqi_pmi_ri_size, ppWritePackedMsg, end) && + push8(cqi_ri_info_rel9->periodic_cqi_pmi_ri_report.control_type, ppWritePackedMsg, end))) + { + return 0; + } + } + break; + case NFAPI_CSI_REPORT_TYPE_APERIODIC: + { + if(push8(cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.number_of_cc, ppWritePackedMsg, end) == 0) + return 0; + + uint8_t i; + for(i = 0; i < cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.number_of_cc; ++i) + { + if(push8(cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.cc[i].ri_size, ppWritePackedMsg, end) == 0) + return 0; + + uint8_t j; + for(j = 0; j < 8; ++j) + { + if(push8(cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.cc[i].dl_cqi_pmi_size[j], ppWritePackedMsg, end) == 0) + return 0; + } + } + } + break; + default: + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "FIXME : Invalid report type %d \n", cqi_ri_info_rel9->report_type ); + } + break; + }; + + return 1; +} + +static uint8_t pack_ul_config_request_cqi_ri_rel13_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_cqi_ri_information_rel13_t* cqi_ri_info_rel13 = (nfapi_ul_config_cqi_ri_information_rel13_t*)tlv; + + switch(cqi_ri_info_rel13->report_type) + { + case NFAPI_CSI_REPORT_TYPE_PERIODIC: + { + if(push16(cqi_ri_info_rel13->periodic_cqi_pmi_ri_report.dl_cqi_pmi_ri_size_2, ppWritePackedMsg, end) == 0) + return 0; + } + break; + case NFAPI_CSI_REPORT_TYPE_APERIODIC: + { + // No parameters + } + break; + default: + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "FIXME : Invalid report type %d \n", cqi_ri_info_rel13->report_type ); + } + break; + }; + + return 1; +} + +static uint8_t pack_ul_config_request_cqi_ri_information(nfapi_ul_config_cqi_ri_information* cqi_ri_info, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + return (pack_tlv(NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL8_TAG, &cqi_ri_info->cqi_ri_information_rel8, ppWritePackedMsg, end, &pack_ul_config_request_cqi_ri_rel8_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL9_TAG, &cqi_ri_info->cqi_ri_information_rel9, ppWritePackedMsg, end, &pack_ul_config_request_cqi_ri_rel9_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL13_TAG, &cqi_ri_info->cqi_ri_information_rel13, ppWritePackedMsg, end, &pack_ul_config_request_cqi_ri_rel13_value)); + +} + +static uint8_t pack_ul_config_request_init_tx_params_rel8_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_initial_transmission_parameters_rel8_t* init_tx_params_rel8 = (nfapi_ul_config_initial_transmission_parameters_rel8_t*)tlv; + + return (push8(init_tx_params_rel8->n_srs_initial, ppWritePackedMsg, end) && + push8(init_tx_params_rel8->initial_number_of_resource_blocks, ppWritePackedMsg, end)); +} + +static uint8_t pack_ul_config_request_initial_transmission_parameters(nfapi_ul_config_initial_transmission_parameters* init_tx_params, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + return pack_tlv(NFAPI_UL_CONFIG_REQUEST_INITIAL_TRANSMISSION_PARAMETERS_REL8_TAG, &init_tx_params->initial_transmission_parameters_rel8, ppWritePackedMsg, end, &pack_ul_config_request_init_tx_params_rel8_value); +} + +static uint8_t pack_ul_config_request_ulsch_harq_info_rel10_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_ulsch_harq_information_rel10_t* harq_info_rel10 = (nfapi_ul_config_ulsch_harq_information_rel10_t*)tlv; + + return (push8(harq_info_rel10->harq_size, ppWritePackedMsg, end) && + push8(harq_info_rel10->delta_offset_harq, ppWritePackedMsg, end) && + push8(harq_info_rel10->ack_nack_mode, ppWritePackedMsg, end)); +} +static uint8_t pack_ul_config_request_ulsch_harq_info_rel13_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_ulsch_harq_information_rel13_t* harq_info_rel13 = (nfapi_ul_config_ulsch_harq_information_rel13_t*)tlv; + + return (push16(harq_info_rel13->harq_size_2, ppWritePackedMsg, end) && + push8(harq_info_rel13->delta_offset_harq_2, ppWritePackedMsg, end)); +} + +static uint8_t pack_ul_config_request_ulsch_harq_information(nfapi_ul_config_ulsch_harq_information* harq_info, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + return ( pack_tlv(NFAPI_UL_CONFIG_REQUEST_ULSCH_HARQ_INFORMATION_REL10_TAG, &harq_info->harq_information_rel10, ppWritePackedMsg, end, &pack_ul_config_request_ulsch_harq_info_rel10_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_ULSCH_HARQ_INFORMATION_REL13_TAG, &harq_info->harq_information_rel13, ppWritePackedMsg, end, &pack_ul_config_request_ulsch_harq_info_rel13_value)); +} + +static uint8_t pack_ul_config_request_ue_info_rel8_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_ue_information_rel8_t* ue_info_rel8 = (nfapi_ul_config_ue_information_rel8_t*)tlv; + + return ( push32(ue_info_rel8->handle, ppWritePackedMsg, end) && + push16(ue_info_rel8->rnti, ppWritePackedMsg, end)); +} +static uint8_t pack_ul_config_request_ue_info_rel11_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_ue_information_rel11_t* ue_info_rel11 = (nfapi_ul_config_ue_information_rel11_t*)tlv; + + return ( push8(ue_info_rel11->virtual_cell_id_enabled_flag, ppWritePackedMsg, end) && + push16(ue_info_rel11->npusch_identity, ppWritePackedMsg, end)); +} +static uint8_t pack_ul_config_request_ue_info_rel13_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_ue_information_rel13_t* ue_info_rel13 = (nfapi_ul_config_ue_information_rel13_t*)tlv; + + return ( push8(ue_info_rel13->ue_type, ppWritePackedMsg, end) && + push8(ue_info_rel13->empty_symbols, ppWritePackedMsg, end) && + push16(ue_info_rel13->total_number_of_repetitions, ppWritePackedMsg, end) && + push16(ue_info_rel13->repetition_number, ppWritePackedMsg, end)); +} + +static uint8_t pack_ul_config_request_ue_information(nfapi_ul_config_ue_information* ue_info, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + return ( pack_tlv(NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG, &ue_info->ue_information_rel8, ppWritePackedMsg, end, &pack_ul_config_request_ue_info_rel8_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL11_TAG, &ue_info->ue_information_rel11, ppWritePackedMsg, end, &pack_ul_config_request_ue_info_rel11_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL13_TAG, &ue_info->ue_information_rel13, ppWritePackedMsg, end, &pack_ul_config_request_ue_info_rel13_value)); +} + +static uint8_t pack_ul_config_request_harq_info_rel10_tdd_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_harq_information_rel10_tdd_t* harq_info_rel10_tdd = (nfapi_ul_config_harq_information_rel10_tdd_t*)tlv; + + return ( push8(harq_info_rel10_tdd->harq_size, ppWritePackedMsg, end) && + push8(harq_info_rel10_tdd->ack_nack_mode, ppWritePackedMsg, end) && + push8(harq_info_rel10_tdd->number_of_pucch_resources, ppWritePackedMsg, end) && + push16(harq_info_rel10_tdd->n_pucch_1_0, ppWritePackedMsg, end) && + push16(harq_info_rel10_tdd->n_pucch_1_1, ppWritePackedMsg, end) && + push16(harq_info_rel10_tdd->n_pucch_1_2, ppWritePackedMsg, end) && + push16(harq_info_rel10_tdd->n_pucch_1_3, ppWritePackedMsg, end)); +} +static uint8_t pack_ul_config_request_harq_info_rel8_fdd_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_harq_information_rel8_fdd_t* harq_info_rel8_fdd = (nfapi_ul_config_harq_information_rel8_fdd_t*)tlv; + + return ( push16(harq_info_rel8_fdd->n_pucch_1_0, ppWritePackedMsg, end) && + push8(harq_info_rel8_fdd->harq_size, ppWritePackedMsg, end)); +} +static uint8_t pack_ul_config_request_harq_info_rel9_fdd_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_harq_information_rel9_fdd_t* harq_info_rel9_fdd = (nfapi_ul_config_harq_information_rel9_fdd_t*)tlv; + + return ( push8(harq_info_rel9_fdd->harq_size, ppWritePackedMsg, end) && + push8(harq_info_rel9_fdd->ack_nack_mode, ppWritePackedMsg, end) && + push8(harq_info_rel9_fdd->number_of_pucch_resources, ppWritePackedMsg, end) && + push16(harq_info_rel9_fdd->n_pucch_1_0, ppWritePackedMsg, end) && + push16(harq_info_rel9_fdd->n_pucch_1_1, ppWritePackedMsg, end) && + push16(harq_info_rel9_fdd->n_pucch_1_2, ppWritePackedMsg, end) && + push16(harq_info_rel9_fdd->n_pucch_1_3, ppWritePackedMsg, end)); +} +static uint8_t pack_ul_config_request_harq_info_rel11_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_harq_information_rel11_t* harq_info_rel11 = (nfapi_ul_config_harq_information_rel11_t*)tlv; + + return ( push8(harq_info_rel11->num_ant_ports, ppWritePackedMsg, end) && + push16(harq_info_rel11->n_pucch_2_0, ppWritePackedMsg, end) && + push16(harq_info_rel11->n_pucch_2_1, ppWritePackedMsg, end) && + push16(harq_info_rel11->n_pucch_2_2, ppWritePackedMsg, end) && + push16(harq_info_rel11->n_pucch_2_3, ppWritePackedMsg, end)); +} +static uint8_t pack_ul_config_request_harq_info_rel13_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_harq_information_rel13_t* harq_info_rel13 = (nfapi_ul_config_harq_information_rel13_t*)tlv; + + return ( push16(harq_info_rel13->harq_size_2, ppWritePackedMsg, end) && + push8(harq_info_rel13->starting_prb, ppWritePackedMsg, end) && + push8(harq_info_rel13->n_prb, ppWritePackedMsg, end) && + push8(harq_info_rel13->cdm_index, ppWritePackedMsg, end) && + push8(harq_info_rel13->n_srs, ppWritePackedMsg, end)); +} + +static uint8_t pack_ul_config_request_harq_information(nfapi_ul_config_harq_information* harq_info, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + return ( pack_tlv(NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG, &harq_info->harq_information_rel10_tdd, ppWritePackedMsg, end, &pack_ul_config_request_harq_info_rel10_tdd_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL8_FDD_TAG, &harq_info->harq_information_rel8_fdd, ppWritePackedMsg, end, &pack_ul_config_request_harq_info_rel8_fdd_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG, &harq_info->harq_information_rel9_fdd, ppWritePackedMsg, end, &pack_ul_config_request_harq_info_rel9_fdd_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL11_TAG, &harq_info->harq_information_rel11, ppWritePackedMsg, end, &pack_ul_config_request_harq_info_rel11_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL13_TAG, &harq_info->harq_information_rel13, ppWritePackedMsg, end, &pack_ul_config_request_harq_info_rel13_value)); + +} + +static uint8_t pack_ul_config_request_cqi_info_rel8_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_cqi_information_rel8_t* cqi_info_rel8 = (nfapi_ul_config_cqi_information_rel8_t*)tlv; + + return ( push16(cqi_info_rel8->pucch_index, ppWritePackedMsg, end) && + push8(cqi_info_rel8->dl_cqi_pmi_size, ppWritePackedMsg, end)); +} +static uint8_t pack_ul_config_request_cqi_info_rel10_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_cqi_information_rel10_t* cqi_info_rel10 = (nfapi_ul_config_cqi_information_rel10_t*)tlv; + + return ( push8(cqi_info_rel10->number_of_pucch_resource, ppWritePackedMsg, end) && + push16(cqi_info_rel10->pucch_index_p1, ppWritePackedMsg, end)); +} +static uint8_t pack_ul_config_request_cqi_info_rel13_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_cqi_information_rel13_t* cqi_info_rel13 = (nfapi_ul_config_cqi_information_rel13_t*)tlv; + + return ( push8(cqi_info_rel13->csi_mode, ppWritePackedMsg, end) && + push16(cqi_info_rel13->dl_cqi_pmi_size_2, ppWritePackedMsg, end) && + push8(cqi_info_rel13->starting_prb, ppWritePackedMsg, end) && + push8(cqi_info_rel13->n_prb, ppWritePackedMsg, end) && + push8(cqi_info_rel13->cdm_index, ppWritePackedMsg, end) && + push8(cqi_info_rel13->n_srs, ppWritePackedMsg, end)); +} + +static uint8_t pack_ul_config_request_cqi_information(nfapi_ul_config_cqi_information* cqi_info, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + return ( pack_tlv(NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG, &cqi_info->cqi_information_rel8, ppWritePackedMsg, end, &pack_ul_config_request_cqi_info_rel8_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL10_TAG, &cqi_info->cqi_information_rel10, ppWritePackedMsg, end, &pack_ul_config_request_cqi_info_rel10_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL13_TAG, &cqi_info->cqi_information_rel13, ppWritePackedMsg, end, &pack_ul_config_request_cqi_info_rel13_value)); + +} + +static uint8_t pack_ul_config_request_sr_info_rel8_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_sr_information_rel8_t* sr_info_rel8 = (nfapi_ul_config_sr_information_rel8_t*)tlv; + return push16(sr_info_rel8->pucch_index, ppWritePackedMsg, end); +} +static uint8_t pack_ul_config_request_sr_info_rel10_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_sr_information_rel10_t* sr_info_rel10 = (nfapi_ul_config_sr_information_rel10_t*)tlv; + + return ( push8(sr_info_rel10->number_of_pucch_resources, ppWritePackedMsg, end) && + push16(sr_info_rel10->pucch_index_p1, ppWritePackedMsg, end)); +} + +static uint8_t pack_ul_config_request_sr_information(nfapi_ul_config_sr_information* sr_info, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + return ( pack_tlv(NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL8_TAG, &sr_info->sr_information_rel8, ppWritePackedMsg, end, &pack_ul_config_request_sr_info_rel8_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL10_TAG, &sr_info->sr_information_rel10, ppWritePackedMsg, end, &pack_ul_config_request_sr_info_rel10_value)); +} + +static uint8_t pack_ul_config_request_srs_pdu_rel8_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_srs_pdu_rel8_t* srs_pdu_rel8 = (nfapi_ul_config_srs_pdu_rel8_t*)tlv; + + return (push32(srs_pdu_rel8->handle, ppWritePackedMsg, end) && + push16(srs_pdu_rel8->size, ppWritePackedMsg, end) && + push16(srs_pdu_rel8->rnti, ppWritePackedMsg, end) && + push8(srs_pdu_rel8->srs_bandwidth, ppWritePackedMsg, end) && + push8(srs_pdu_rel8->frequency_domain_position, ppWritePackedMsg, end) && + push8(srs_pdu_rel8->srs_hopping_bandwidth, ppWritePackedMsg, end) && + push8(srs_pdu_rel8->transmission_comb, ppWritePackedMsg, end) && + push16(srs_pdu_rel8->i_srs, ppWritePackedMsg, end) && + push8(srs_pdu_rel8->sounding_reference_cyclic_shift, ppWritePackedMsg, end)); +} + +static uint8_t pack_ul_config_request_srs_pdu_rel10_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_srs_pdu_rel10_t* srs_pdu_rel10 = (nfapi_ul_config_srs_pdu_rel10_t*)tlv; + return push8(srs_pdu_rel10->antenna_port, ppWritePackedMsg, end); +} + +static uint8_t pack_ul_config_request_srs_pdu_rel13_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_srs_pdu_rel13_t* srs_pdu_rel13 = (nfapi_ul_config_srs_pdu_rel13_t*)tlv; + + return ( push8(srs_pdu_rel13->number_of_combs, ppWritePackedMsg, end)); +} + +static uint8_t pack_ul_config_request_nb_harq_rel13_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_nb_harq_information_rel13_fdd_t* nb_harq_pdu_rel13 = (nfapi_ul_config_nb_harq_information_rel13_fdd_t*)tlv; + + return ( push8(nb_harq_pdu_rel13->harq_ack_resource, ppWritePackedMsg, end)); +} + +static uint8_t pack_ul_config_request_nulsch_pdu_rel13_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_nulsch_pdu_rel13_t* nulsch_pdu_rel13 = (nfapi_ul_config_nulsch_pdu_rel13_t*)tlv; + + return (push8(nulsch_pdu_rel13->nulsch_format, ppWritePackedMsg, end) && + push32(nulsch_pdu_rel13->handle, ppWritePackedMsg, end) && + push16(nulsch_pdu_rel13->size, ppWritePackedMsg, end) && + push16(nulsch_pdu_rel13->rnti, ppWritePackedMsg, end) && + push8(nulsch_pdu_rel13->subcarrier_indication, ppWritePackedMsg, end) && + push8(nulsch_pdu_rel13->resource_assignment, ppWritePackedMsg, end) && + push8(nulsch_pdu_rel13->mcs, ppWritePackedMsg, end) && + push8(nulsch_pdu_rel13->redudancy_version, ppWritePackedMsg, end) && + push8(nulsch_pdu_rel13->repetition_number, ppWritePackedMsg, end) && + push8(nulsch_pdu_rel13->new_data_indication, ppWritePackedMsg, end) && + push8(nulsch_pdu_rel13->n_srs, ppWritePackedMsg, end) && + push16(nulsch_pdu_rel13->scrambling_sequence_initialization_cinit, ppWritePackedMsg, end) && + push16(nulsch_pdu_rel13->sf_idx, ppWritePackedMsg, end) && + pack_ul_config_request_ue_information(&(nulsch_pdu_rel13->ue_information), ppWritePackedMsg, end) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_NB_HARQ_INFORMATION_REL13_FDD_TAG, &nulsch_pdu_rel13->nb_harq_information.nb_harq_information_rel13_fdd, ppWritePackedMsg, end, &pack_ul_config_request_nb_harq_rel13_value)); +} +static uint8_t pack_ul_config_request_nrach_pdu_rel13_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_nrach_pdu_rel13_t* nrach_pdu_rel13 = (nfapi_ul_config_nrach_pdu_rel13_t*)tlv; + + return ( push8(nrach_pdu_rel13->nprach_config_0, ppWritePackedMsg, end) && + push8(nrach_pdu_rel13->nprach_config_1, ppWritePackedMsg, end) && + push8(nrach_pdu_rel13->nprach_config_2, ppWritePackedMsg, end)); + +} + +static uint8_t pack_ul_config_request_body_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_config_request_body_t* value = (nfapi_ul_config_request_body_t*)tlv; + + if(!(push8(value->number_of_pdus, ppWritePackedMsg, end) && + push8(value->rach_prach_frequency_resources, ppWritePackedMsg, end) && + push8(value->srs_present, ppWritePackedMsg, end))) + return 0; + + uint16_t i = 0; + for(i = 0; i < value->number_of_pdus; ++i) + { + nfapi_ul_config_request_pdu_t* pdu = &(value->ul_config_pdu_list[i]); + + if(push8(pdu->pdu_type, ppWritePackedMsg, end) == 0) + return 0; + + // Put a 0 size in and then determine the size after the pdu + // has been writen and write the calculated size + uint8_t* pWritePackedMsgPduSize = *ppWritePackedMsg; + pdu->pdu_size = 0; + if(push8(pdu->pdu_size, ppWritePackedMsg, end) == 0) + return 0; + + switch(pdu->pdu_type) + { + case NFAPI_UL_CONFIG_ULSCH_PDU_TYPE: + { + if(!pack_ul_config_request_ulsch_pdu(&(pdu->ulsch_pdu), ppWritePackedMsg, end)) + return 0; + } + break; + case NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE: + { + if(!(pack_ul_config_request_ulsch_pdu(&(pdu->ulsch_cqi_ri_pdu.ulsch_pdu), ppWritePackedMsg, end) && + pack_ul_config_request_cqi_ri_information(&(pdu->ulsch_cqi_ri_pdu.cqi_ri_information), ppWritePackedMsg, end) && + pack_ul_config_request_initial_transmission_parameters(&(pdu->ulsch_cqi_ri_pdu.initial_transmission_parameters), ppWritePackedMsg, end))) + return 0; + } + break; + case NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE: + { + if(!(pack_ul_config_request_ulsch_pdu(&(pdu->ulsch_harq_pdu.ulsch_pdu), ppWritePackedMsg, end) && + pack_ul_config_request_ulsch_harq_information(&(pdu->ulsch_harq_pdu.harq_information), ppWritePackedMsg, end) && + pack_ul_config_request_initial_transmission_parameters(&(pdu->ulsch_harq_pdu.initial_transmission_parameters), ppWritePackedMsg, end))) + return 0; + } + break; + case NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE: + { + if(!(pack_ul_config_request_ulsch_pdu(&(pdu->ulsch_cqi_harq_ri_pdu.ulsch_pdu), ppWritePackedMsg, end) && + pack_ul_config_request_cqi_ri_information(&(pdu->ulsch_cqi_harq_ri_pdu.cqi_ri_information), ppWritePackedMsg, end) && + pack_ul_config_request_ulsch_harq_information(&(pdu->ulsch_cqi_harq_ri_pdu.harq_information), ppWritePackedMsg, end) && + pack_ul_config_request_initial_transmission_parameters(&(pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters), ppWritePackedMsg, end))) + return 0; + } + break; + case NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE: + { + if(!(pack_ul_config_request_ue_information(&(pdu->uci_cqi_pdu.ue_information), ppWritePackedMsg, end) && + pack_ul_config_request_cqi_information(&(pdu->uci_cqi_pdu.cqi_information), ppWritePackedMsg, end))) + return 0; + } + break; + case NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE: + { + if(!(pack_ul_config_request_ue_information(&(pdu->uci_sr_pdu.ue_information), ppWritePackedMsg, end) && + pack_ul_config_request_sr_information(&(pdu->uci_sr_pdu.sr_information), ppWritePackedMsg, end))) + return 0; + } + break; + case NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE: + { + if(!(pack_ul_config_request_ue_information(&(pdu->uci_harq_pdu.ue_information), ppWritePackedMsg, end) && + pack_ul_config_request_harq_information(&(pdu->uci_harq_pdu.harq_information), ppWritePackedMsg, end))) + return 0; + } + break; + case NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE: + { + if(!(pack_ul_config_request_ue_information(&(pdu->uci_sr_harq_pdu.ue_information), ppWritePackedMsg, end) && + pack_ul_config_request_sr_information(&(pdu->uci_sr_harq_pdu.sr_information), ppWritePackedMsg, end) && + pack_ul_config_request_harq_information(&(pdu->uci_sr_harq_pdu.harq_information), ppWritePackedMsg, end))) + return 0; + } + break; + case NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE: + { + if(!(pack_ul_config_request_ue_information(&(pdu->uci_cqi_harq_pdu.ue_information), ppWritePackedMsg, end) && + pack_ul_config_request_cqi_information(&(pdu->uci_cqi_harq_pdu.cqi_information), ppWritePackedMsg, end) && + pack_ul_config_request_harq_information(&(pdu->uci_cqi_harq_pdu.harq_information), ppWritePackedMsg, end))) + return 0; + } + break; + case NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE: + { + if(!(pack_ul_config_request_ue_information(&(pdu->uci_cqi_sr_pdu.ue_information), ppWritePackedMsg, end) && + pack_ul_config_request_cqi_information(&(pdu->uci_cqi_sr_pdu.cqi_information), ppWritePackedMsg, end) && + pack_ul_config_request_sr_information(&(pdu->uci_cqi_sr_pdu.sr_information), ppWritePackedMsg, end))) + return 0; + } + break; + case NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE: + { + if(!(pack_ul_config_request_ue_information(&(pdu->uci_cqi_sr_harq_pdu.ue_information), ppWritePackedMsg, end) && + pack_ul_config_request_cqi_information(&(pdu->uci_cqi_sr_harq_pdu.cqi_information), ppWritePackedMsg, end) && + pack_ul_config_request_sr_information(&(pdu->uci_cqi_sr_harq_pdu.sr_information), ppWritePackedMsg, end) && + pack_ul_config_request_harq_information(&(pdu->uci_cqi_sr_harq_pdu.harq_information), ppWritePackedMsg, end))) + return 0; + } + break; + case NFAPI_UL_CONFIG_SRS_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL8_TAG, &pdu->srs_pdu.srs_pdu_rel8, ppWritePackedMsg, end, &pack_ul_config_request_srs_pdu_rel8_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL10_TAG, &pdu->srs_pdu.srs_pdu_rel10, ppWritePackedMsg, end, &pack_ul_config_request_srs_pdu_rel10_value) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL13_TAG, &pdu->srs_pdu.srs_pdu_rel13, ppWritePackedMsg, end, &pack_ul_config_request_srs_pdu_rel13_value))) + return 0; + } + break; + case NFAPI_UL_CONFIG_HARQ_BUFFER_PDU_TYPE: + { + if(!(pack_ul_config_request_ue_information(&(pdu->harq_buffer_pdu.ue_information), ppWritePackedMsg, end))) + return 0; + } + break; + case NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE: + { + if(!(pack_ul_config_request_ulsch_pdu(&(pdu->ulsch_uci_csi_pdu.ulsch_pdu), ppWritePackedMsg, end) && + pack_ul_config_request_cqi_information(&(pdu->ulsch_uci_csi_pdu.csi_information), ppWritePackedMsg, end))) + return 0; + } + break; + case NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE: + { + if(!(pack_ul_config_request_ulsch_pdu(&(pdu->ulsch_uci_harq_pdu.ulsch_pdu), ppWritePackedMsg, end) && + pack_ul_config_request_harq_information(&(pdu->ulsch_uci_harq_pdu.harq_information), ppWritePackedMsg, end))) + return 0; + } + break; + case NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE: + { + if(!(pack_ul_config_request_ulsch_pdu(&(pdu->ulsch_csi_uci_harq_pdu.ulsch_pdu), ppWritePackedMsg, end) && + pack_ul_config_request_cqi_information(&(pdu->ulsch_csi_uci_harq_pdu.csi_information), ppWritePackedMsg, end) && + pack_ul_config_request_harq_information(&(pdu->ulsch_csi_uci_harq_pdu.harq_information), ppWritePackedMsg, end))) + return 0; + } + break; + case NFAPI_UL_CONFIG_NULSCH_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_UL_CONFIG_REQUEST_NULSCH_PDU_REL13_TAG, &pdu->nulsch_pdu.nulsch_pdu_rel13, ppWritePackedMsg, end, &pack_ul_config_request_nulsch_pdu_rel13_value))) + return 0; + } + break; + case NFAPI_UL_CONFIG_NRACH_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_UL_CONFIG_REQUEST_NRACH_PDU_REL13_TAG, &pdu->nrach_pdu.nrach_pdu_rel13, ppWritePackedMsg, end, &pack_ul_config_request_nrach_pdu_rel13_value))) + return 0; + } + break; + default: + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "FIXME : Invalid pdu type %d \n", pdu->pdu_type ); + } + break; + }; + + // add 1 for the pdu_type. The delta will include the pdu_size + pdu->pdu_size = 1 + (*ppWritePackedMsg - pWritePackedMsgPduSize); + push8(pdu->pdu_size, &pWritePackedMsgPduSize, end); + + } + return 1; +} + +static uint8_t pack_ul_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_ul_config_request_t *pNfapiMsg = (nfapi_ul_config_request_t*)msg; + + return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && + pack_tlv(NFAPI_UL_CONFIG_REQUEST_BODY_TAG, &pNfapiMsg->ul_config_request_body, ppWritePackedMsg, end, &pack_ul_config_request_body_value) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)) ; +} + +static uint8_t pack_hi_dci0_hi_rel8_pdu_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_hi_pdu_rel8_t* hi_pdu_rel8 = (nfapi_hi_dci0_hi_pdu_rel8_t*)tlv; + + return ( push8(hi_pdu_rel8->resource_block_start, ppWritePackedMsg, end) && + push8(hi_pdu_rel8->cyclic_shift_2_for_drms, ppWritePackedMsg, end) && + push8(hi_pdu_rel8->hi_value, ppWritePackedMsg, end) && + push8(hi_pdu_rel8->i_phich, ppWritePackedMsg, end) && + push16(hi_pdu_rel8->transmission_power, ppWritePackedMsg, end)); +} + +static uint8_t pack_hi_dci0_hi_rel10_pdu_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_hi_pdu_rel10_t* hi_pdu_rel10 = (nfapi_hi_dci0_hi_pdu_rel10_t*)tlv; + + return ( push8(hi_pdu_rel10->flag_tb2, ppWritePackedMsg, end) && + push8(hi_pdu_rel10->hi_value_2, ppWritePackedMsg, end)); +} + +static uint8_t pack_hi_dci0_dci_rel8_pdu_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_dci_pdu_rel8_t* dci_pdu_rel8 = (nfapi_hi_dci0_dci_pdu_rel8_t*)tlv; + + return ( push8(dci_pdu_rel8->dci_format, ppWritePackedMsg, end) && + push8(dci_pdu_rel8->cce_index, ppWritePackedMsg, end) && + push8(dci_pdu_rel8->aggregation_level, ppWritePackedMsg, end) && + push16(dci_pdu_rel8->rnti, ppWritePackedMsg, end) && + push8(dci_pdu_rel8->resource_block_start, ppWritePackedMsg, end) && + push8(dci_pdu_rel8->number_of_resource_block, ppWritePackedMsg, end) && + push8(dci_pdu_rel8->mcs_1, ppWritePackedMsg, end) && + push8(dci_pdu_rel8->cyclic_shift_2_for_drms, ppWritePackedMsg, end) && + push8(dci_pdu_rel8->frequency_hopping_enabled_flag, ppWritePackedMsg, end) && + push8(dci_pdu_rel8->frequency_hopping_bits, ppWritePackedMsg, end) && + push8(dci_pdu_rel8->new_data_indication_1, ppWritePackedMsg, end) && + push8(dci_pdu_rel8->ue_tx_antenna_seleciton, ppWritePackedMsg, end) && + push8(dci_pdu_rel8->tpc, ppWritePackedMsg, end) && + push8(dci_pdu_rel8->cqi_csi_request, ppWritePackedMsg, end) && + push8(dci_pdu_rel8->ul_index, ppWritePackedMsg, end) && + push8(dci_pdu_rel8->dl_assignment_index, ppWritePackedMsg, end) && + push32(dci_pdu_rel8->tpc_bitmap, ppWritePackedMsg, end) && + push16(dci_pdu_rel8->transmission_power, ppWritePackedMsg, end)); +} + +static uint8_t pack_hi_dci0_dci_rel10_pdu_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_dci_pdu_rel10_t* dci_pdu_rel10 = (nfapi_hi_dci0_dci_pdu_rel10_t*)tlv; + + return ( push8(dci_pdu_rel10->cross_carrier_scheduling_flag, ppWritePackedMsg, end) && + push8(dci_pdu_rel10->carrier_indicator, ppWritePackedMsg, end) && + push8(dci_pdu_rel10->size_of_cqi_csi_feild, ppWritePackedMsg, end) && + push8(dci_pdu_rel10->srs_flag, ppWritePackedMsg, end) && + push8(dci_pdu_rel10->srs_request, ppWritePackedMsg, end) && + push8(dci_pdu_rel10->resource_allocation_flag, ppWritePackedMsg, end) && + push8(dci_pdu_rel10->resource_allocation_type, ppWritePackedMsg, end) && + push32(dci_pdu_rel10->resource_block_coding, ppWritePackedMsg, end) && + push8(dci_pdu_rel10->mcs_2, ppWritePackedMsg, end) && + push8(dci_pdu_rel10->new_data_indication_2, ppWritePackedMsg, end) && + push8(dci_pdu_rel10->number_of_antenna_ports, ppWritePackedMsg, end) && + push8(dci_pdu_rel10->tpmi, ppWritePackedMsg, end) && + push8(dci_pdu_rel10->total_dci_length_including_padding, ppWritePackedMsg, end) && + push8(dci_pdu_rel10->n_ul_rb, ppWritePackedMsg, end)); +} + +static uint8_t pack_hi_dci0_dci_rel12_pdu_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_dci_pdu_rel12_t* dci_pdu_rel12 = (nfapi_hi_dci0_dci_pdu_rel12_t*)tlv; + + return ( push8(dci_pdu_rel12->pscch_resource, ppWritePackedMsg, end) && + push8(dci_pdu_rel12->time_resource_pattern, ppWritePackedMsg, end)); +} + +static uint8_t pack_hi_dci0_mpdcch_dci_rel13_pdu_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_mpdcch_dci_pdu_rel13_t* mpdcch_dci_pdu_rel13 = (nfapi_hi_dci0_mpdcch_dci_pdu_rel13_t*)tlv; + + return ( push8(mpdcch_dci_pdu_rel13->mpdcch_narrowband, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->number_of_prb_pairs, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->resource_block_assignment, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->mpdcch_transmission_type, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->start_symbol, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->ecce_index, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->aggreagation_level, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->rnti_type, ppWritePackedMsg, end) && + push16(mpdcch_dci_pdu_rel13->rnti, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->ce_mode, ppWritePackedMsg, end) && + push16(mpdcch_dci_pdu_rel13->drms_scrambling_init, ppWritePackedMsg, end) && + push16(mpdcch_dci_pdu_rel13->initial_transmission_sf_io, ppWritePackedMsg, end) && + push16(mpdcch_dci_pdu_rel13->transmission_power, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->dci_format, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->resource_block_start, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->number_of_resource_blocks, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->mcs, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->pusch_repetition_levels, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->frequency_hopping_flag, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->new_data_indication, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->harq_process, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->redudency_version, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->tpc, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->csi_request, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->ul_inex, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->dai_presence_flag, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->dl_assignment_index, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->srs_request, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->dci_subframe_repetition_number, ppWritePackedMsg, end) && + push32(mpdcch_dci_pdu_rel13->tcp_bitmap, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->total_dci_length_include_padding, ppWritePackedMsg, end) && + push8(mpdcch_dci_pdu_rel13->number_of_tx_antenna_ports, ppWritePackedMsg, end) && + pusharray16(mpdcch_dci_pdu_rel13->precoding_value, NFAPI_MAX_TX_PHYSICAL_ANTENNA_PORTS, mpdcch_dci_pdu_rel13->number_of_tx_antenna_ports, ppWritePackedMsg, end)); + +} + +static uint8_t pack_hi_dci0_npdcch_dci_rel13_pdu_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_npdcch_dci_pdu_rel13_t* npdcch_dci_pdu_rel13 = (nfapi_hi_dci0_npdcch_dci_pdu_rel13_t*)tlv; + + return ( push8(npdcch_dci_pdu_rel13->ncce_index, ppWritePackedMsg, end) && + push8(npdcch_dci_pdu_rel13->aggregation_level, ppWritePackedMsg, end) && + push8(npdcch_dci_pdu_rel13->start_symbol, ppWritePackedMsg, end) && + push16(npdcch_dci_pdu_rel13->rnti, ppWritePackedMsg, end) && + push8(npdcch_dci_pdu_rel13->scrambling_reinitialization_batch_index, ppWritePackedMsg, end) && + push8(npdcch_dci_pdu_rel13->nrs_antenna_ports_assumed_by_the_ue, ppWritePackedMsg, end) && + push8(npdcch_dci_pdu_rel13->subcarrier_indication, ppWritePackedMsg, end) && + push8(npdcch_dci_pdu_rel13->resource_assignment, ppWritePackedMsg, end) && + push8(npdcch_dci_pdu_rel13->scheduling_delay, ppWritePackedMsg, end) && + push8(npdcch_dci_pdu_rel13->mcs, ppWritePackedMsg, end) && + push8(npdcch_dci_pdu_rel13->redudancy_version, ppWritePackedMsg, end) && + push8(npdcch_dci_pdu_rel13->repetition_number, ppWritePackedMsg, end) && + push8(npdcch_dci_pdu_rel13->new_data_indicator, ppWritePackedMsg, end) && + push8(npdcch_dci_pdu_rel13->dci_subframe_repetition_number, ppWritePackedMsg, end)); +} + + +static uint8_t pack_hi_dci0_request_body_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_request_body_t* value = (nfapi_hi_dci0_request_body_t*)tlv; + + if(!(push16(value->sfnsf, ppWritePackedMsg, end) && + push8(value->number_of_dci, ppWritePackedMsg, end) && + push8(value->number_of_hi, ppWritePackedMsg, end))) + return 0; + + uint16_t i = 0; + uint16_t total_number_of_pdus = value->number_of_dci + value->number_of_hi; + for(i = 0; i < total_number_of_pdus; ++i) + { + nfapi_hi_dci0_request_pdu_t* pdu = &(value->hi_dci0_pdu_list[i]); + + if(push8(pdu->pdu_type, ppWritePackedMsg, end) == 0) + return 0; + + // Put a 0 size in and then determine the size after the pdu + // has been writen and write the calculated size + uint8_t* pWritePackedMsgPduSize = *ppWritePackedMsg; + pdu->pdu_size = 0; + if(push8(pdu->pdu_size, ppWritePackedMsg, end) == 0) + return 0; + + switch(pdu->pdu_type) + { + case NFAPI_HI_DCI0_HI_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_HI_DCI0_REQUEST_HI_PDU_REL8_TAG, &pdu->hi_pdu.hi_pdu_rel8, ppWritePackedMsg, end, pack_hi_dci0_hi_rel8_pdu_value) && + pack_tlv(NFAPI_HI_DCI0_REQUEST_HI_PDU_REL10_TAG, &pdu->hi_pdu.hi_pdu_rel10, ppWritePackedMsg, end, pack_hi_dci0_hi_rel10_pdu_value))) + return 0; + } + break; + case NFAPI_HI_DCI0_DCI_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL8_TAG, &pdu->dci_pdu.dci_pdu_rel8, ppWritePackedMsg, end, pack_hi_dci0_dci_rel8_pdu_value) && + pack_tlv(NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL10_TAG, &pdu->dci_pdu.dci_pdu_rel10, ppWritePackedMsg, end, pack_hi_dci0_dci_rel10_pdu_value) && + pack_tlv(NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL12_TAG, &pdu->dci_pdu.dci_pdu_rel12, ppWritePackedMsg, end, pack_hi_dci0_dci_rel12_pdu_value))) + return 0; + } + break; + case NFAPI_HI_DCI0_EPDCCH_DCI_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_HI_DCI0_REQUEST_EPDCCH_DCI_PDU_REL8_TAG, &pdu->epdcch_dci_pdu.epdcch_dci_pdu_rel8, ppWritePackedMsg, end, pack_hi_dci0_dci_rel8_pdu_value) && + pack_tlv(NFAPI_HI_DCI0_REQUEST_EPDCCH_DCI_PDU_REL10_TAG, &pdu->epdcch_dci_pdu.epdcch_dci_pdu_rel10, ppWritePackedMsg, end, pack_hi_dci0_dci_rel10_pdu_value) && + pack_tlv(NFAPI_HI_DCI0_REQUEST_EPDCCH_PARAMETERS_REL11_TAG, &pdu->epdcch_dci_pdu.epdcch_parameters_rel11, ppWritePackedMsg, end, pack_dl_config_epdcch_parameters_rel11_value))) + return 0; + } + break; + case NFAPI_HI_DCI0_MPDCCH_DCI_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_HI_DCI0_REQUEST_MPDCCH_DCI_PDU_REL13_TAG, &pdu->mpdcch_dci_pdu.mpdcch_dci_pdu_rel13, ppWritePackedMsg, end, pack_hi_dci0_mpdcch_dci_rel13_pdu_value))) + return 0; + } + break; + case NFAPI_HI_DCI0_NPDCCH_DCI_PDU_TYPE: + { + if(!(pack_tlv(NFAPI_HI_DCI0_REQUEST_NPDCCH_DCI_PDU_REL13_TAG, &pdu->npdcch_dci_pdu.npdcch_dci_pdu_rel13, ppWritePackedMsg, end, pack_hi_dci0_npdcch_dci_rel13_pdu_value))) + return 0; + } + break; + default: + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "FIXME : Invalid pdu type %d \n", pdu->pdu_type ); + } + break; + }; + + // add 1 for the pdu_type. The delta will include the pdu_size + pdu->pdu_size = 1 + (*ppWritePackedMsg - pWritePackedMsgPduSize); + push8(pdu->pdu_size, &pWritePackedMsgPduSize, end); + + } + + return 1; +} + +static uint8_t pack_hi_dci0_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_hi_dci0_request_t *pNfapiMsg = (nfapi_hi_dci0_request_t*)msg; + + return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && + pack_tlv(NFAPI_HI_DCI0_REQUEST_BODY_TAG, &pNfapiMsg->hi_dci0_request_body, ppWritePackedMsg, end, &pack_hi_dci0_request_body_value) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_tx_request_body_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_tx_request_body_t* value = (nfapi_tx_request_body_t*)tlv; + + if(push16(value->number_of_pdus, ppWritePackedMsg, end) == 0) + return 0; + + uint16_t i = 0; + uint16_t total_number_of_pdus = value->number_of_pdus; + for(; i < total_number_of_pdus; ++i) + { + nfapi_tx_request_pdu_t* pdu = &(value->tx_pdu_list[i]); + + if(!(push16(pdu->pdu_length, ppWritePackedMsg, end) && + push16(pdu->pdu_index, ppWritePackedMsg, end))) + return 0; + + uint8_t j; + for(j = 0; j < pdu->num_segments; ++j) + { + // Use -1 as it is unbounded + // DJP - does not handle -1 + // DJP - if(pusharray8(pdu->segments[j].segment_data, (uint32_t)(-1), pdu->segments[j].segment_length, ppWritePackedMsg, end) == 0) + int push_ret = pusharray8(pdu->segments[j].segment_data, 65535, pdu->segments[j].segment_length, ppWritePackedMsg, end); + + if (0 && pdu->segments[j].segment_length == 3) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() BCH? segment_data:%x %x %x\n", __FUNCTION__, + pdu->segments[j].segment_data[0], + pdu->segments[j].segment_data[1], + pdu->segments[j].segment_data[2] + ); + } + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() segment_data:%p segment_length:%u pusharray8()=%d\n", __FUNCTION__, pdu->segments[j].segment_data, pdu->segments[j].segment_length, push_ret); + + if (push_ret == 0) + { + return 0; + } + } + } + + return 1; +} + +static uint8_t pack_tx_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_tx_request_t *pNfapiMsg = (nfapi_tx_request_t*)msg; + + int x = push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end); + int y = pack_tlv(NFAPI_TX_REQUEST_BODY_TAG, &pNfapiMsg->tx_request_body, ppWritePackedMsg, end, &pack_tx_request_body_value); + int z = pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config); + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() x:%d y:%d z:%d\n", __FUNCTION__, x, y, z); + + return x && y && z; +} + +static uint8_t pack_rx_ue_information_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_rx_ue_information* value = (nfapi_rx_ue_information*)tlv; + + return ( push32(value->handle, ppWritePackedMsg, end) && + push16(value->rnti, ppWritePackedMsg, end) ); +} + +static uint8_t unpack_rx_ue_information_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_rx_ue_information* value = (nfapi_rx_ue_information*)tlv; + + return ( pull32(ppReadPackedMsg, &value->handle, end) && + pull16(ppReadPackedMsg, &value->rnti, end)); +} + +static uint8_t pack_harq_indication_tdd_harq_data_bundling(nfapi_harq_indication_tdd_harq_data_bundling_t* data, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + return ( push8(data->value_0, ppWritePackedMsg, end) && + push8(data->value_1, ppWritePackedMsg, end)); +} + +static uint8_t pack_harq_indication_tdd_harq_data_multiplexing(nfapi_harq_indication_tdd_harq_data_multiplexing_t* data, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + return ( push8(data->value_0, ppWritePackedMsg, end) && + push8(data->value_1, ppWritePackedMsg, end) && + push8(data->value_2, ppWritePackedMsg, end) && + push8(data->value_3, ppWritePackedMsg, end)); +} + +static uint8_t pack_harq_indication_tdd_harq_data_special_bundling(nfapi_harq_indication_tdd_harq_data_special_bundling_t* data, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + return ( push8(data->value_0, ppWritePackedMsg, end) ); +} + +static uint8_t pack_harq_indication_tdd_harq_data(nfapi_harq_indication_tdd_harq_data_t* data, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + return ( push8(data->value_0, ppWritePackedMsg, end) ); +} + +static uint8_t pack_harq_indication_tdd_rel8_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_harq_indication_tdd_rel8_t* harq_indication_tdd_rel8 = (nfapi_harq_indication_tdd_rel8_t*)tlv; + + if(!(push8(harq_indication_tdd_rel8->mode, ppWritePackedMsg, end) && + push8(harq_indication_tdd_rel8->number_of_ack_nack, ppWritePackedMsg, end))) + return 0; + + uint8_t result = 0; + switch(harq_indication_tdd_rel8->mode) + { + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_BUNDLING: + result = pack_harq_indication_tdd_harq_data_bundling(&harq_indication_tdd_rel8->harq_data.bundling, ppWritePackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_MULIPLEXING: + result = pack_harq_indication_tdd_harq_data_multiplexing(&harq_indication_tdd_rel8->harq_data.multiplex, ppWritePackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_SPECIAL_BUNDLING: + result = pack_harq_indication_tdd_harq_data_special_bundling(&harq_indication_tdd_rel8->harq_data.special_bundling, ppWritePackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_CHANNEL_SELECTION: + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_3: + result = 1; + break; + default: + // err.... + break; + } + + return result; + +} + +static uint8_t pack_harq_indication_tdd_rel9_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_harq_indication_tdd_rel9_t* harq_indication_tdd_rel9 = (nfapi_harq_indication_tdd_rel9_t*)tlv; + + if(!(push8(harq_indication_tdd_rel9->mode, ppWritePackedMsg, end) && + push8(harq_indication_tdd_rel9->number_of_ack_nack, ppWritePackedMsg, end))) + return 0; + + uint8_t idx; + for(idx = 0; idx < harq_indication_tdd_rel9->number_of_ack_nack; ++idx) + { + uint8_t result = 0; + + switch(harq_indication_tdd_rel9->mode) + { + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_BUNDLING: + result = pack_harq_indication_tdd_harq_data(&(harq_indication_tdd_rel9->harq_data[idx].bundling), ppWritePackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_MULIPLEXING: + result = pack_harq_indication_tdd_harq_data(&harq_indication_tdd_rel9->harq_data[idx].multiplex, ppWritePackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_SPECIAL_BUNDLING: + result = pack_harq_indication_tdd_harq_data_special_bundling(&harq_indication_tdd_rel9->harq_data[idx].special_bundling, ppWritePackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_CHANNEL_SELECTION: + result = pack_harq_indication_tdd_harq_data(&harq_indication_tdd_rel9->harq_data[idx].channel_selection, ppWritePackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_3: + result = pack_harq_indication_tdd_harq_data(&harq_indication_tdd_rel9->harq_data[idx].format_3, ppWritePackedMsg, end); + break; + default: + // err.... + break; + } + + if(result == 0) + return 0; + } + + return 1; +} + +static uint8_t pack_harq_indication_tdd_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_harq_indication_tdd_rel13_t* harq_indication_tdd_rel13 = (nfapi_harq_indication_tdd_rel13_t*)tlv; + + if(!(push8(harq_indication_tdd_rel13->mode, ppWritePackedMsg, end) && + push16(harq_indication_tdd_rel13->number_of_ack_nack, ppWritePackedMsg, end))) + return 0; + + uint8_t idx; + for(idx = 0; idx < harq_indication_tdd_rel13->number_of_ack_nack; ++idx) + { + uint8_t result = 0; + switch(harq_indication_tdd_rel13->mode) + { + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_BUNDLING: + result = pack_harq_indication_tdd_harq_data(&harq_indication_tdd_rel13->harq_data[idx].bundling, ppWritePackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_MULIPLEXING: + result = pack_harq_indication_tdd_harq_data(&harq_indication_tdd_rel13->harq_data[idx].multiplex, ppWritePackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_SPECIAL_BUNDLING: + result = pack_harq_indication_tdd_harq_data_special_bundling(&harq_indication_tdd_rel13->harq_data[idx].special_bundling, ppWritePackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_CHANNEL_SELECTION: + result = pack_harq_indication_tdd_harq_data(&harq_indication_tdd_rel13->harq_data[idx].channel_selection, ppWritePackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_3: + result = pack_harq_indication_tdd_harq_data(&harq_indication_tdd_rel13->harq_data[idx].format_3, ppWritePackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_4: + result = pack_harq_indication_tdd_harq_data(&harq_indication_tdd_rel13->harq_data[idx].format_4, ppWritePackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_5: + result = pack_harq_indication_tdd_harq_data(&harq_indication_tdd_rel13->harq_data[idx].format_5, ppWritePackedMsg, end); + break; + default: + // err.... + break; + } + + if(result == 0) + return 0; + } + + return 1; +} + +static uint8_t pack_harq_indication_fdd_rel8_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_harq_indication_fdd_rel8_t* harq_indication_fdd_rel8 = (nfapi_harq_indication_fdd_rel8_t*)tlv; + + return ( push8(harq_indication_fdd_rel8->harq_tb1, ppWritePackedMsg, end) && + push8(harq_indication_fdd_rel8->harq_tb2, ppWritePackedMsg, end)); +} + +static uint8_t pack_harq_indication_fdd_rel9_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_harq_indication_fdd_rel9_t* harq_indication_fdd_rel9 = (nfapi_harq_indication_fdd_rel9_t*)tlv; + + return ( push8(harq_indication_fdd_rel9->mode, ppWritePackedMsg, end) && + push8(harq_indication_fdd_rel9->number_of_ack_nack, ppWritePackedMsg, end) && + pusharray8(harq_indication_fdd_rel9->harq_tb_n, NFAPI_HARQ_ACK_NACK_REL9_MAX, harq_indication_fdd_rel9->number_of_ack_nack, ppWritePackedMsg, end)); +} + +static uint8_t pack_harq_indication_fdd_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_harq_indication_fdd_rel13_t* harq_indication_fdd_rel13 = (nfapi_harq_indication_fdd_rel13_t*)tlv; + + return ( push8(harq_indication_fdd_rel13->mode, ppWritePackedMsg, end) && + push16(harq_indication_fdd_rel13->number_of_ack_nack, ppWritePackedMsg, end) && + pusharray8(harq_indication_fdd_rel13->harq_tb_n, NFAPI_HARQ_ACK_NACK_REL13_MAX, harq_indication_fdd_rel13->number_of_ack_nack, ppWritePackedMsg, end)); +} + +static uint8_t pack_ul_cqi_information_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_ul_cqi_information_t* value = (nfapi_ul_cqi_information_t*)tlv; + + return ( push8(value->ul_cqi, ppWritePackedMsg, end) && + push8(value->channel, ppWritePackedMsg, end)); + +} + +static uint8_t pack_harq_indication_body_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_harq_indication_body_t* value = (nfapi_harq_indication_body_t*)tlv; + + if(push16(value->number_of_harqs, ppWritePackedMsg, end) == 0) + return 0; + + uint16_t i = 0; + uint16_t total_number_of_pdus = value->number_of_harqs; + for(; i < total_number_of_pdus; ++i) + { + nfapi_harq_indication_pdu_t* pdu = &(value->harq_pdu_list[i]); + + uint8_t* instance_length_p = *ppWritePackedMsg; + if(!push16(pdu->instance_length, ppWritePackedMsg, end)) + return 0; + + if(!(pack_tlv(NFAPI_RX_UE_INFORMATION_TAG, &pdu->rx_ue_information, ppWritePackedMsg, end, pack_rx_ue_information_value) && + pack_tlv(NFAPI_HARQ_INDICATION_TDD_REL8_TAG, &pdu->harq_indication_tdd_rel8, ppWritePackedMsg, end, pack_harq_indication_tdd_rel8_value) && + pack_tlv(NFAPI_HARQ_INDICATION_TDD_REL9_TAG, &pdu->harq_indication_tdd_rel9, ppWritePackedMsg, end, pack_harq_indication_tdd_rel9_value) && + pack_tlv(NFAPI_HARQ_INDICATION_TDD_REL13_TAG, &pdu->harq_indication_tdd_rel13, ppWritePackedMsg, end, pack_harq_indication_tdd_rel13_value) && + pack_tlv(NFAPI_HARQ_INDICATION_FDD_REL8_TAG, &pdu->harq_indication_fdd_rel8, ppWritePackedMsg, end, pack_harq_indication_fdd_rel8_value) && + pack_tlv(NFAPI_HARQ_INDICATION_FDD_REL9_TAG, &pdu->harq_indication_fdd_rel9, ppWritePackedMsg, end, pack_harq_indication_fdd_rel9_value) && + pack_tlv(NFAPI_HARQ_INDICATION_FDD_REL13_TAG, &pdu->harq_indication_fdd_rel13, ppWritePackedMsg, end, pack_harq_indication_fdd_rel13_value) && + pack_tlv(NFAPI_UL_CQI_INFORMATION_TAG, &pdu->ul_cqi_information, ppWritePackedMsg, end, pack_ul_cqi_information_value))) + return 0; + + // calculate the instance length subtracting the size of the instance + // length feild + uint16_t instance_length = *ppWritePackedMsg - instance_length_p - 2; + push16(instance_length, &instance_length_p, end); + } + + return 1; +} + +static uint8_t pack_harq_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_harq_indication_t *pNfapiMsg = (nfapi_harq_indication_t*)msg; + + return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && + pack_tlv(NFAPI_HARQ_INDICATION_BODY_TAG, &pNfapiMsg->harq_indication_body, ppWritePackedMsg, end, pack_harq_indication_body_value) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_crc_indication_rel8_body(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_crc_indication_rel8_t* crc_indication_rel8 = (nfapi_crc_indication_rel8_t*)tlv; + + return ( push8(crc_indication_rel8->crc_flag, ppWritePackedMsg, end) ); +} + +static uint8_t pack_crc_indication_body_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_crc_indication_body_t* value = (nfapi_crc_indication_body_t*)tlv; + + if(push16(value->number_of_crcs, ppWritePackedMsg, end) == 0) + return 0; + + uint16_t i = 0; + uint16_t total_number_of_pdus = value->number_of_crcs; + for(; i < total_number_of_pdus; ++i) + { + nfapi_crc_indication_pdu_t* pdu = &(value->crc_pdu_list[i]); + + uint8_t* instance_length_p = *ppWritePackedMsg; + if(!push16(pdu->instance_length, ppWritePackedMsg, end)) + return 0; + + if(!(pack_tlv(NFAPI_RX_UE_INFORMATION_TAG, &pdu->rx_ue_information, ppWritePackedMsg, end, pack_rx_ue_information_value) && + pack_tlv(NFAPI_CRC_INDICATION_REL8_TAG, &pdu->crc_indication_rel8, ppWritePackedMsg, end, pack_crc_indication_rel8_body))) + return 0; + + // calculate the instance length subtracting the size of the instance + // length feild + uint16_t instance_length = *ppWritePackedMsg - instance_length_p - 2; + push16(instance_length, &instance_length_p, end); + } + return 1; +} + +static uint8_t pack_crc_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_crc_indication_t *pNfapiMsg = (nfapi_crc_indication_t*)msg; + + return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && + pack_tlv(NFAPI_CRC_INDICATION_BODY_TAG, &pNfapiMsg->crc_indication_body, ppWritePackedMsg, end, &pack_crc_indication_body_value) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); + +} +static uint8_t pack_rx_indication_rel8_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_rx_indication_rel8_t* value = (nfapi_rx_indication_rel8_t*)tlv; + + return ( push16(value->length, ppWritePackedMsg, end) && + push16(value->offset, ppWritePackedMsg, end) && + push8(value->ul_cqi, ppWritePackedMsg, end) && + push16(value->timing_advance, ppWritePackedMsg, end)); +} +static uint8_t pack_rx_indication_rel9_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_rx_indication_rel9_t* value = (nfapi_rx_indication_rel9_t*)tlv; + + return ( push16(value->timing_advance_r9, ppWritePackedMsg, end)); +} + +static uint8_t pack_rx_ulsch_indication_body_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_rx_indication_body_t* value = (nfapi_rx_indication_body_t*)tlv; + + //printf("RX ULSCH BODY\n"); + + if( push16(value->number_of_pdus, ppWritePackedMsg, end) == 0) + return 0; + + // need to calculate the data offset's. + uint16_t i = 0; + uint16_t offset = 2; // taking into account the number_of_pdus + uint16_t total_number_of_pdus = value->number_of_pdus; + //printf("ULSCH:pdus:%d\n", total_number_of_pdus); + + for(i = 0; i < total_number_of_pdus; ++i) + { + nfapi_rx_indication_pdu_t* pdu = &(value->rx_pdu_list[i]); + if(pdu->rx_ue_information.tl.tag == NFAPI_RX_UE_INFORMATION_TAG) + { + //printf("NFAPI_RX_UE_INFORMATION_TAG\n"); + offset += 4 + 6; + } + + if(pdu->rx_indication_rel8.tl.tag == NFAPI_RX_INDICATION_REL8_TAG) + { + //printf("NFAPI_RX_INDICATION_REL8_TAG\n"); + offset += 4 + 7; + } + + if(pdu->rx_indication_rel9.tl.tag == NFAPI_RX_INDICATION_REL9_TAG) + { + //printf("NFAPI_RX_INDICATION_REL9_TAG\n"); + offset += 4 + 2; + } + } + + // Now update the structure to include the offset + for(i =0; i < total_number_of_pdus; ++i) + { + nfapi_rx_indication_pdu_t* pdu = &(value->rx_pdu_list[i]); + + if(pdu->rx_indication_rel8.tl.tag == NFAPI_RX_INDICATION_REL8_TAG) + { + if(pdu->rx_indication_rel8.offset == 1) + { + pdu->rx_indication_rel8.offset = offset; + offset += pdu->rx_indication_rel8.length; + } + } + } + + // Write out the pdu + for(i = 0; i < total_number_of_pdus; ++i) + { + nfapi_rx_indication_pdu_t* pdu = &(value->rx_pdu_list[i]); + if(!(pack_tlv(NFAPI_RX_UE_INFORMATION_TAG, &pdu->rx_ue_information, ppWritePackedMsg, end, pack_rx_ue_information_value) && + pack_tlv(NFAPI_RX_INDICATION_REL8_TAG, &pdu->rx_indication_rel8, ppWritePackedMsg, end, pack_rx_indication_rel8_value) && + pack_tlv(NFAPI_RX_INDICATION_REL9_TAG, &pdu->rx_indication_rel9, ppWritePackedMsg, end, pack_rx_indication_rel9_value))) + return 0; + } + + // Write out the pdu data + for(i = 0; i < total_number_of_pdus; ++i) + { + uint16_t length = 0; + nfapi_rx_indication_pdu_t* pdu = &(value->rx_pdu_list[i]); + + if(pdu->rx_indication_rel8.tl.tag == NFAPI_RX_INDICATION_REL8_TAG) + { + length = pdu->rx_indication_rel8.length; + } + + if( pusharray8(value->rx_pdu_list[i].data, length, length, ppWritePackedMsg, end) == 0) + return 0; + } + return 1; +} + + +static uint8_t pack_rx_ulsch_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_rx_indication_t *pNfapiMsg = (nfapi_rx_indication_t*)msg; + + return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && + pack_tlv(NFAPI_RX_INDICATION_BODY_TAG, &pNfapiMsg->rx_indication_body, ppWritePackedMsg, end, pack_rx_ulsch_indication_body_value) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_preamble_pdu_rel8_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_preamble_pdu_rel8_t* preamble_rel8 = (nfapi_preamble_pdu_rel8_t*)tlv; + + return ( push16(preamble_rel8->rnti, ppWritePackedMsg, end) && + push8(preamble_rel8->preamble, ppWritePackedMsg, end) && + push16(preamble_rel8->timing_advance, ppWritePackedMsg, end)); +} +static uint8_t pack_preamble_pdu_rel9_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_preamble_pdu_rel9_t* preamble_rel9 = (nfapi_preamble_pdu_rel9_t*)tlv; + + return ( push16(preamble_rel9->timing_advance_r9, ppWritePackedMsg, end) ); +} +static uint8_t pack_preamble_pdu_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_preamble_pdu_rel13_t* preamble_rel13 = (nfapi_preamble_pdu_rel13_t*)tlv; + + return ( push8(preamble_rel13->rach_resource_type, ppWritePackedMsg, end) ); +} + +static uint8_t pack_rach_indication_body_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_rach_indication_body_t* value = (nfapi_rach_indication_body_t*)tlv; + + if( push16(value->number_of_preambles, ppWritePackedMsg, end) == 0) + return 0; + + uint16_t i = 0; + uint16_t total_number_of_pdus = value->number_of_preambles; + for(; i < total_number_of_pdus; ++i) + { + nfapi_preamble_pdu_t* pdu = &(value->preamble_list[i]); + + uint8_t* instance_length_p = *ppWritePackedMsg; + if(!push16(pdu->instance_length, ppWritePackedMsg, end)) + return 0; + + if(!(pack_tlv(NFAPI_PREAMBLE_REL8_TAG, &pdu->preamble_rel8, ppWritePackedMsg, end, pack_preamble_pdu_rel8_value) && + pack_tlv(NFAPI_PREAMBLE_REL9_TAG, &pdu->preamble_rel9, ppWritePackedMsg, end, pack_preamble_pdu_rel9_value) && + pack_tlv(NFAPI_PREAMBLE_REL13_TAG, &pdu->preamble_rel13, ppWritePackedMsg, end, pack_preamble_pdu_rel13_value))) + return 0; + + // calculate the instance length subtracting the size of the instance + // length feild + uint16_t instance_length = *ppWritePackedMsg - instance_length_p - 2; + push16(instance_length, &instance_length_p, end); + } + + return 1; +} + +static uint8_t pack_rach_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_rach_indication_t *pNfapiMsg = (nfapi_rach_indication_t*)msg; + + return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && + pack_tlv(NFAPI_RACH_INDICATION_BODY_TAG, &pNfapiMsg->rach_indication_body, ppWritePackedMsg, end, pack_rach_indication_body_value) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_srs_indication_fdd_rel8_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_srs_indication_fdd_rel8_t* srs_pdu_rel8 = (nfapi_srs_indication_fdd_rel8_t*)tlv; + + return ( push16(srs_pdu_rel8->doppler_estimation, ppWritePackedMsg, end) && + push16(srs_pdu_rel8->timing_advance, ppWritePackedMsg, end) && + push8(srs_pdu_rel8->number_of_resource_blocks, ppWritePackedMsg, end) && + push8(srs_pdu_rel8->rb_start, ppWritePackedMsg, end) && + pusharray8(srs_pdu_rel8->snr, NFAPI_NUM_RB_MAX, srs_pdu_rel8->number_of_resource_blocks, ppWritePackedMsg, end)); +} + +static uint8_t pack_srs_indication_fdd_rel9_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_srs_indication_fdd_rel9_t* srs_pdu_rel9 = (nfapi_srs_indication_fdd_rel9_t*)tlv; + + return ( push16(srs_pdu_rel9->timing_advance_r9, ppWritePackedMsg, end) ); +} + +static uint8_t pack_srs_indication_tdd_rel10_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_srs_indication_ttd_rel10_t* srs_pdu_rel10 = (nfapi_srs_indication_ttd_rel10_t*)tlv; + + return ( push8(srs_pdu_rel10->uppts_symbol, ppWritePackedMsg, end) ); + +} + +static uint8_t pack_srs_indication_fdd_rel11_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_srs_indication_fdd_rel11_t* srs_pdu_rel11 = (nfapi_srs_indication_fdd_rel11_t*)tlv; + + return ( push16(srs_pdu_rel11->ul_rtoa, ppWritePackedMsg, end) ) ; +} + +static uint8_t pack_tdd_channel_measurement_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_tdd_channel_measurement_t* value = (nfapi_tdd_channel_measurement_t*)tlv; + + if(!(push8(value->num_prb_per_subband, ppWritePackedMsg, end) && + push8(value->number_of_subbands, ppWritePackedMsg, end) && + push8(value->num_atennas, ppWritePackedMsg, end))) + return 0; + + uint8_t idx = 0; + for(idx = 0; idx < value->number_of_subbands; ++idx) + { + if(!(push8(value->subands[idx].subband_index, ppWritePackedMsg, end) && + pusharray16(value->subands[idx].channel, NFAPI_MAX_NUM_PHYSICAL_ANTENNAS, value->num_atennas, ppWritePackedMsg, end))) + return 0; + } + + return 1; +} + +static uint8_t pack_srs_indication_body_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_srs_indication_body_t *value = (nfapi_srs_indication_body_t*)tlv; + + if( push8(value->number_of_ues, ppWritePackedMsg, end) == 0) + return 0; + + uint16_t i = 0; + uint16_t total_number_of_pdus = value->number_of_ues; + for(; i < total_number_of_pdus; ++i) + { + nfapi_srs_indication_pdu_t* pdu = &(value->srs_pdu_list[i]); + + uint8_t* instance_length_p = *ppWritePackedMsg; + if(!push16(pdu->instance_length, ppWritePackedMsg, end)) + return 0; + + if(!(pack_tlv(NFAPI_RX_UE_INFORMATION_TAG, &pdu->rx_ue_information, ppWritePackedMsg, end, &pack_rx_ue_information_value) && + pack_tlv(NFAPI_SRS_INDICATION_FDD_REL8_TAG, &pdu->srs_indication_fdd_rel8, ppWritePackedMsg, end, &pack_srs_indication_fdd_rel8_value) && + pack_tlv(NFAPI_SRS_INDICATION_FDD_REL9_TAG, &pdu->srs_indication_fdd_rel9, ppWritePackedMsg, end, &pack_srs_indication_fdd_rel9_value) && + pack_tlv(NFAPI_SRS_INDICATION_TDD_REL10_TAG, &pdu->srs_indication_tdd_rel10, ppWritePackedMsg, end, &pack_srs_indication_tdd_rel10_value) && + pack_tlv(NFAPI_SRS_INDICATION_FDD_REL11_TAG, &pdu->srs_indication_fdd_rel11, ppWritePackedMsg, end, &pack_srs_indication_fdd_rel11_value) && + pack_tlv(NFAPI_TDD_CHANNEL_MEASUREMENT_TAG, &pdu->tdd_channel_measurement, ppWritePackedMsg, end, &pack_tdd_channel_measurement_value))) + return 0; + + // calculate the instance length subtracting the size of the instance + // length feild + uint16_t instance_length = *ppWritePackedMsg - instance_length_p - 2; + push16(instance_length, &instance_length_p, end); + } + + return 1; +} + +static uint8_t pack_srs_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_srs_indication_t *pNfapiMsg = (nfapi_srs_indication_t*)msg; + + return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && + pack_tlv(NFAPI_SRS_INDICATION_BODY_TAG, &pNfapiMsg->srs_indication_body, ppWritePackedMsg, end, &pack_srs_indication_body_value) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); + +} + +static uint8_t pack_sr_indication_body_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_sr_indication_body_t* value = (nfapi_sr_indication_body_t*)tlv; + + if(push16(value->number_of_srs, ppWritePackedMsg, end) == 0) + return 0; + + uint16_t i = 0; + uint16_t total_number_of_pdus = value->number_of_srs; + for(; i < total_number_of_pdus; ++i) + { + nfapi_sr_indication_pdu_t* pdu = &(value->sr_pdu_list[i]); + + uint8_t* instance_length_p = *ppWritePackedMsg; + if(!push16(pdu->instance_length, ppWritePackedMsg, end)) + return 0; + + if(!(pack_tlv(NFAPI_RX_UE_INFORMATION_TAG, &pdu->rx_ue_information, ppWritePackedMsg, end, pack_rx_ue_information_value) && + pack_tlv(NFAPI_UL_CQI_INFORMATION_TAG, &pdu->ul_cqi_information, ppWritePackedMsg, end, pack_ul_cqi_information_value))) + return 0; + + // calculate the instance length subtracting the size of the instance + // length feild + uint16_t instance_length = *ppWritePackedMsg - instance_length_p - 2; + push16(instance_length, &instance_length_p, end); + } + return 1; +} + +static uint8_t pack_sr_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_sr_indication_t *pNfapiMsg = (nfapi_sr_indication_t*)msg; + + return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && + pack_tlv(NFAPI_SR_INDICATION_BODY_TAG, &pNfapiMsg->sr_indication_body, ppWritePackedMsg, end, &pack_sr_indication_body_value) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); + +} + +static uint8_t pack_cqi_indication_rel8_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_cqi_indication_rel8_t* cqi_pdu_rel8 = (nfapi_cqi_indication_rel8_t*)tlv; + + return ( push16(cqi_pdu_rel8->length, ppWritePackedMsg, end) && + push16(cqi_pdu_rel8->data_offset, ppWritePackedMsg, end) && + push8(cqi_pdu_rel8->ul_cqi, ppWritePackedMsg, end) && + push8(cqi_pdu_rel8->ri, ppWritePackedMsg, end) && + push16(cqi_pdu_rel8->timing_advance, ppWritePackedMsg, end)); +} + +static uint8_t pack_cqi_indication_rel9_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_cqi_indication_rel9_t* cqi_pdu_rel9 = (nfapi_cqi_indication_rel9_t*)tlv; + + return ( push16(cqi_pdu_rel9->length, ppWritePackedMsg, end) && + push16(cqi_pdu_rel9->data_offset, ppWritePackedMsg, end) && + push8(cqi_pdu_rel9->ul_cqi, ppWritePackedMsg, end) && + push8(cqi_pdu_rel9->number_of_cc_reported, ppWritePackedMsg, end) && + pusharray8(cqi_pdu_rel9->ri, NFAPI_CC_MAX, cqi_pdu_rel9->number_of_cc_reported, ppWritePackedMsg, end) && + push16(cqi_pdu_rel9->timing_advance, ppWritePackedMsg, end) && + push16(cqi_pdu_rel9->timing_advance_r9, ppWritePackedMsg, end)); +} + +static uint8_t pack_cqi_indication_body_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_cqi_indication_body_t* value = (nfapi_cqi_indication_body_t*)tlv; + + if( push16(value->number_of_cqis, ppWritePackedMsg, end) == 0) + return 0; + + // need to calculate the data offset's. This very bittle due the hardcoding + // of the sizes. can not use the sizeof as we have an array for the Rel9 + // info + uint16_t i = 0; + uint16_t offset = 2; // taking into account the number_of_cqis + uint16_t total_number_of_pdus = value->number_of_cqis; + for(i = 0; i < total_number_of_pdus; ++i) + { + nfapi_cqi_indication_pdu_t* pdu = &(value->cqi_pdu_list[i]); + + offset += 2; // for the instance length + + if(pdu->rx_ue_information.tl.tag == NFAPI_RX_UE_INFORMATION_TAG) + { + offset += 4 + 6; // sizeof(nfapi_rx_ue_information) - sizeof(nfapi_tl_t) + } + + if(pdu->cqi_indication_rel8.tl.tag == NFAPI_CQI_INDICATION_REL8_TAG) + { + offset += 4 + 8; + } + + if(pdu->cqi_indication_rel9.tl.tag == NFAPI_CQI_INDICATION_REL9_TAG) + { + offset += 4 + 10 + pdu->cqi_indication_rel9.number_of_cc_reported; + } + + if(pdu->ul_cqi_information.tl.tag == NFAPI_UL_CQI_INFORMATION_TAG) + { + offset += 4 + 2; + } + } + + // Now update the structure to include the offset + for(i =0; i < total_number_of_pdus; ++i) + { + nfapi_cqi_indication_pdu_t* pdu = &(value->cqi_pdu_list[i]); + + if(pdu->cqi_indication_rel8.tl.tag == NFAPI_CQI_INDICATION_REL8_TAG) + { + if(pdu->cqi_indication_rel8.data_offset == 1) + { + pdu->cqi_indication_rel8.data_offset = offset; + offset += pdu->cqi_indication_rel8.length; + } + } + + if(pdu->cqi_indication_rel9.tl.tag == NFAPI_CQI_INDICATION_REL9_TAG) + { + if(pdu->cqi_indication_rel9.data_offset == 1) + { + pdu->cqi_indication_rel9.data_offset = offset; + offset += pdu->cqi_indication_rel9.length; + } + } + + } + + // Write out the cqi information + for(i = 0; i < total_number_of_pdus; ++i) + { + nfapi_cqi_indication_pdu_t* pdu = &(value->cqi_pdu_list[i]); + + uint8_t* instance_length_p = *ppWritePackedMsg; + if(!push16(pdu->instance_length, ppWritePackedMsg, end)) + return 0; + + if(!(pack_tlv(NFAPI_RX_UE_INFORMATION_TAG, &pdu->rx_ue_information, ppWritePackedMsg, end ,pack_rx_ue_information_value) && + pack_tlv(NFAPI_CQI_INDICATION_REL8_TAG, &pdu->cqi_indication_rel8, ppWritePackedMsg, end, pack_cqi_indication_rel8_value) && + pack_tlv(NFAPI_CQI_INDICATION_REL9_TAG, &pdu->cqi_indication_rel9, ppWritePackedMsg, end, pack_cqi_indication_rel9_value) && + pack_tlv(NFAPI_UL_CQI_INFORMATION_TAG, &pdu->ul_cqi_information, ppWritePackedMsg, end, pack_ul_cqi_information_value))) + return 0; + + // calculate the instance length subtracting the size of the instance + // length feild + uint16_t instance_length = *ppWritePackedMsg - instance_length_p - 2; + push16(instance_length, &instance_length_p, end); + + } + + // Write out the cqi raw data + for(i = 0; i < total_number_of_pdus; ++i) + { + uint16_t length = 0; + nfapi_cqi_indication_pdu_t* pdu = &(value->cqi_pdu_list[i]); + + if(pdu->cqi_indication_rel8.tl.tag == NFAPI_CQI_INDICATION_REL8_TAG) + { + length = pdu->cqi_indication_rel8.length; + } + + if(pdu->cqi_indication_rel9.tl.tag == NFAPI_CQI_INDICATION_REL9_TAG) + { + length = pdu->cqi_indication_rel9.length; + } + + if( pusharray8(value->cqi_raw_pdu_list[i].pdu, NFAPI_CQI_RAW_MAX_LEN, length, ppWritePackedMsg, end) == 0) + return 0; + } + + return 1; +} + +static uint8_t pack_cqi_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_cqi_indication_t *pNfapiMsg = (nfapi_cqi_indication_t*)msg; + + return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && + pack_tlv(NFAPI_CQI_INDICATION_BODY_TAG, &pNfapiMsg->cqi_indication_body, ppWritePackedMsg, end, pack_cqi_indication_body_value) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); + +} + +static uint8_t pack_lbt_pdsch_req_pdu_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_lbt_pdsch_req_pdu_rel13_t* value = (nfapi_lbt_pdsch_req_pdu_rel13_t*)tlv; + + return ( push32(value->handle, ppWritePackedMsg, end) && + push32(value->mp_cca, ppWritePackedMsg, end) && + push32(value->n_cca, ppWritePackedMsg, end) && + push32(value->offset, ppWritePackedMsg, end) && + push32(value->lte_txop_sf, ppWritePackedMsg, end) && + push16(value->txop_sfn_sf_end, ppWritePackedMsg, end) && + push32(value->lbt_mode, ppWritePackedMsg, end)); +} + +static uint8_t pack_lbt_drs_req_pdu_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_lbt_drs_req_pdu_rel13_t* value = (nfapi_lbt_drs_req_pdu_rel13_t*)tlv; + + return ( push32(value->handle, ppWritePackedMsg, end) && + push32(value->offset, ppWritePackedMsg, end) && + push16(value->sfn_sf_end, ppWritePackedMsg, end) && + push32(value->lbt_mode, ppWritePackedMsg, end)); +} + +static uint8_t pack_lbt_dl_config_request_body_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_lbt_dl_config_request_body_t* value = (nfapi_lbt_dl_config_request_body_t*)tlv; + + if( push16(value->number_of_pdus, ppWritePackedMsg, end) == 0) + return 0; + + uint16_t i = 0; + uint16_t total_number_of_pdus = value->number_of_pdus; + for(; i < total_number_of_pdus; ++i) + { + nfapi_lbt_dl_config_request_pdu_t* pdu = &(value->lbt_dl_config_req_pdu_list[i]); + + if( push8(pdu->pdu_type, ppWritePackedMsg, end) == 0) + return 0; + + // Put a 0 size in and then determine the size after the pdu + // has been writen and write the calculated size + uint8_t* pWritePackedMsgPduSize = *ppWritePackedMsg; + pdu->pdu_size = 0; + if( push8(pdu->pdu_size, ppWritePackedMsg, end) == 0) + return 0; + + switch(pdu->pdu_type) + { + case NFAPI_LBT_DL_CONFIG_REQUEST_PDSCH_PDU_TYPE: + { + if( pack_tlv(NFAPI_LBT_PDSCH_REQ_PDU_REL13_TAG, &pdu->lbt_pdsch_req_pdu.lbt_pdsch_req_pdu_rel13, ppWritePackedMsg, end, pack_lbt_pdsch_req_pdu_rel13_value) == 0) + return 0; + } + break; + case NFAPI_LBT_DL_CONFIG_REQUEST_DRS_PDU_TYPE: + { + if(pack_tlv(NFAPI_LBT_DRS_REQ_PDU_REL13_TAG, &pdu->lbt_drs_req_pdu.lbt_drs_req_pdu_rel13, ppWritePackedMsg, end, pack_lbt_drs_req_pdu_rel13_value) == 0) + return 0; + } + break; + default: + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "LBT_DL_CONFIG.request invalid pdu type %d \n", pdu->pdu_type ); + } + break; + }; + + // add 1 for the pdu_type. The delta will include the pdu_size + pdu->pdu_size = 1 + (*ppWritePackedMsg - pWritePackedMsgPduSize); + push8(pdu->pdu_size, &pWritePackedMsgPduSize, end); + } + + return 1; +} + +static uint8_t pack_lbt_pdsch_rsp_pdu_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_lbt_pdsch_rsp_pdu_rel13_t* value = (nfapi_lbt_pdsch_rsp_pdu_rel13_t*)tlv; + + return ( push32(value->handle, ppWritePackedMsg, end) && + push32(value->result, ppWritePackedMsg, end) && + push32(value->lte_txop_symbols, ppWritePackedMsg, end) && + push32(value->initial_partial_sf, ppWritePackedMsg, end)); +} + +static uint8_t pack_lbt_drs_rsp_pdu_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_lbt_drs_rsp_pdu_rel13_t* value = (nfapi_lbt_drs_rsp_pdu_rel13_t*)tlv; + + return ( push32(value->handle, ppWritePackedMsg, end) && + push32(value->result, ppWritePackedMsg, end)); +} + +static uint8_t pack_lbt_dl_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_lbt_dl_config_request_t *pNfapiMsg = (nfapi_lbt_dl_config_request_t*)msg; + + return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && + pack_tlv(NFAPI_LBT_DL_CONFIG_REQUEST_BODY_TAG, &pNfapiMsg->lbt_dl_config_request_body, ppWritePackedMsg, end, &pack_lbt_dl_config_request_body_value) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_lbt_dl_config_indication_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_lbt_dl_indication_body_t* value = (nfapi_lbt_dl_indication_body_t*)tlv; + + if( push16(value->number_of_pdus, ppWritePackedMsg, end) == 0) + return 0; + + uint16_t i = 0; + uint16_t total_number_of_pdus = value->number_of_pdus; + for(; i < total_number_of_pdus; ++i) + { + nfapi_lbt_dl_indication_pdu_t* pdu = &(value->lbt_indication_pdu_list[i]); + + if( push8(pdu->pdu_type, ppWritePackedMsg, end) == 0) + return 0; + + // Put a 0 size in and then determine the size after the pdu + // has been writen and write the calculated size + uint8_t* pWritePackedMsgPduSize = *ppWritePackedMsg; + pdu->pdu_size = 0; + + if(push8(pdu->pdu_size, ppWritePackedMsg, end) == 0) + return 0; + + switch(pdu->pdu_type) + { + case NFAPI_LBT_DL_RSP_PDSCH_PDU_TYPE: + { + if( pack_tlv(NFAPI_LBT_PDSCH_RSP_PDU_REL13_TAG, &pdu->lbt_pdsch_rsp_pdu.lbt_pdsch_rsp_pdu_rel13, ppWritePackedMsg, end, pack_lbt_pdsch_rsp_pdu_rel13_value) == 0) + return 0; + } + break; + case NFAPI_LBT_DL_RSP_DRS_PDU_TYPE: + { + if( pack_tlv(NFAPI_LBT_DRS_RSP_PDU_REL13_TAG, &pdu->lbt_drs_rsp_pdu.lbt_drs_rsp_pdu_rel13, ppWritePackedMsg, end, pack_lbt_drs_rsp_pdu_rel13_value) == 0) + return 0; + } + break; + default: + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "LBT_DL.indication body invalid pdu type %d \n", pdu->pdu_type ); + } + break; + }; + + // add 1 for the pdu_type. The delta will include the pdu_size + pdu->pdu_size = 1 + (*ppWritePackedMsg - pWritePackedMsgPduSize); + push8(pdu->pdu_size, &pWritePackedMsgPduSize, end); + } + + return 1; +} + +static uint8_t pack_lbt_dl_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_lbt_dl_indication_t *pNfapiMsg = (nfapi_lbt_dl_indication_t*)msg; + + return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && + pack_tlv(NFAPI_LBT_DL_INDICATION_BODY_TAG, &pNfapiMsg->lbt_dl_indication_body, ppWritePackedMsg, end, &pack_lbt_dl_config_indication_value) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_nb_harq_indication_fdd_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nb_harq_indication_fdd_rel13_t* nb_harq_indication_fdd_rel13 = (nfapi_nb_harq_indication_fdd_rel13_t*)tlv; + + return ( push8(nb_harq_indication_fdd_rel13->harq_tb1, ppWritePackedMsg, end) ); +} + +static uint8_t pack_nb_harq_indication_body_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nb_harq_indication_body_t* value = (nfapi_nb_harq_indication_body_t*)tlv; + + if( push16(value->number_of_harqs, ppWritePackedMsg, end) == 0) + return 0; + + uint16_t i = 0; + uint16_t total_number_of_harqs = value->number_of_harqs; + for(; i < total_number_of_harqs; ++i) + { + nfapi_nb_harq_indication_pdu_t* pdu = &(value->nb_harq_pdu_list[i]); + + uint8_t* instance_length_p = *ppWritePackedMsg; + if(!push16(pdu->instance_length, ppWritePackedMsg, end)) + return 0; + + if(!(pack_tlv(NFAPI_RX_UE_INFORMATION_TAG, &pdu->rx_ue_information, ppWritePackedMsg, end, pack_rx_ue_information_value) && + pack_tlv(NFAPI_NB_HARQ_INDICATION_FDD_REL13_TAG, &pdu->nb_harq_indication_fdd_rel13, ppWritePackedMsg, end, pack_nb_harq_indication_fdd_rel13_value) && + pack_tlv(NFAPI_UL_CQI_INFORMATION_TAG, &pdu->ul_cqi_information, ppWritePackedMsg, end, pack_ul_cqi_information_value))) + return 0; + + // calculate the instance length subtracting the size of the instance + // length feild + uint16_t instance_length = *ppWritePackedMsg - instance_length_p - 2; + push16(instance_length, &instance_length_p, end); + } + + return 1; +} + + +static uint8_t pack_nb_harq_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_nb_harq_indication_t *pNfapiMsg = (nfapi_nb_harq_indication_t*)msg; + + return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && + pack_tlv(NFAPI_NB_HARQ_INDICATION_BODY_TAG, &pNfapiMsg->nb_harq_indication_body, ppWritePackedMsg, end, &pack_nb_harq_indication_body_value) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_nrach_indication_rel13_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nrach_indication_pdu_rel13_t* nrach_indication_fdd_rel13 = (nfapi_nrach_indication_pdu_rel13_t*)tlv; + + return ( push16(nrach_indication_fdd_rel13->rnti, ppWritePackedMsg, end) && + push8(nrach_indication_fdd_rel13->initial_sc, ppWritePackedMsg, end) && + push16(nrach_indication_fdd_rel13->timing_advance, ppWritePackedMsg, end) && + push8(nrach_indication_fdd_rel13->nrach_ce_level, ppWritePackedMsg, end)); +} + + +static uint8_t pack_nrach_indication_body_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nrach_indication_body_t* value = (nfapi_nrach_indication_body_t*)tlv; + + if( push8(value->number_of_initial_scs_detected, ppWritePackedMsg, end) == 0) + return 0; + + uint16_t i = 0; + uint16_t total_number_of_initial_scs_detected = value->number_of_initial_scs_detected; + for(; i < total_number_of_initial_scs_detected; ++i) + { + nfapi_nrach_indication_pdu_t* pdu = &(value->nrach_pdu_list[i]); + + //uint8_t* instance_length_p = *ppWritePackedMsg; + //if(!push16(pdu->instance_length, ppWritePackedMsg, end)) + // return 0; + + if(!(pack_tlv(NFAPI_NRACH_INDICATION_REL13_TAG, &pdu->nrach_indication_rel13, ppWritePackedMsg, end, pack_nrach_indication_rel13_value))) + return 0; + + // calculate the instance length subtracting the size of the instance + // length feild + //uint16_t instance_length = *ppWritePackedMsg - instance_length_p - 2; + //push16(instance_length, &instance_length_p, end); + } + + return 1; +} + +static uint8_t pack_nrach_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_nrach_indication_t *pNfapiMsg = (nfapi_nrach_indication_t*)msg; + + return ( push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end) && + pack_tlv(NFAPI_NRACH_INDICATION_BODY_TAG, &pNfapiMsg->nrach_indication_body, ppWritePackedMsg, end, &pack_nrach_indication_body_value) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_dl_node_sync(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_dl_node_sync_t *pNfapiMsg = (nfapi_dl_node_sync_t*)msg; + + return ( push32(pNfapiMsg->t1, ppWritePackedMsg, end) && + pushs32(pNfapiMsg->delta_sfn_sf, ppWritePackedMsg, end) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_ul_node_sync(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_ul_node_sync_t *pNfapiMsg = (nfapi_ul_node_sync_t*)msg; + + return (push32(pNfapiMsg->t1, ppWritePackedMsg, end) && + push32(pNfapiMsg->t2, ppWritePackedMsg, end) && + push32(pNfapiMsg->t3, ppWritePackedMsg, end) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + +static uint8_t pack_timing_info(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_timing_info_t *pNfapiMsg = (nfapi_timing_info_t*)msg; + + return (push32(pNfapiMsg->last_sfn_sf, ppWritePackedMsg, end) && + push32(pNfapiMsg->time_since_last_timing_info, ppWritePackedMsg, end) && + push32(pNfapiMsg->dl_config_jitter, ppWritePackedMsg, end) && + push32(pNfapiMsg->tx_request_jitter, ppWritePackedMsg, end) && + push32(pNfapiMsg->ul_config_jitter, ppWritePackedMsg, end) && + push32(pNfapiMsg->hi_dci0_jitter, ppWritePackedMsg, end) && + pushs32(pNfapiMsg->dl_config_latest_delay, ppWritePackedMsg, end) && + pushs32(pNfapiMsg->tx_request_latest_delay, ppWritePackedMsg, end) && + pushs32(pNfapiMsg->ul_config_latest_delay, ppWritePackedMsg, end) && + pushs32(pNfapiMsg->hi_dci0_latest_delay, ppWritePackedMsg, end) && + pushs32(pNfapiMsg->dl_config_earliest_arrival, ppWritePackedMsg, end) && + pushs32(pNfapiMsg->tx_request_earliest_arrival, ppWritePackedMsg, end) && + pushs32(pNfapiMsg->ul_config_earliest_arrival, ppWritePackedMsg, end) && + pushs32(pNfapiMsg->hi_dci0_earliest_arrival, ppWritePackedMsg, end) && + pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)); +} + + +// Main pack function - public + +int nfapi_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen, nfapi_p7_codec_config_t* config) +{ + nfapi_p7_message_header_t *pMessageHeader = pMessageBuf; + uint8_t *pWritePackedMessage = pPackedBuf; + uint8_t *pPackedLengthField = &pWritePackedMessage[4]; + uint8_t *end = pPackedBuf + packedBufLen; + + if (pMessageBuf == NULL || pPackedBuf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 Pack supplied pointers are null\n"); + return -1; + } + + // process the header + if(!(push16(pMessageHeader->phy_id, &pWritePackedMessage, end) && + push16(pMessageHeader->message_id, &pWritePackedMessage, end) && + push16(0/*pMessageHeader->message_length*/, &pWritePackedMessage, end) && + push16(pMessageHeader->m_segment_sequence, &pWritePackedMessage, end) && + push32(0/*pMessageHeader->checksum*/, &pWritePackedMessage, end) && + push32(pMessageHeader->transmit_timestamp, &pWritePackedMessage, end))) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 Pack header failed\n"); + return -1; + } + + if (pMessageHeader->message_id != NFAPI_TIMING_INFO) + { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() message_id:0x%04x phy_id:%u m_segment_sequence:%u timestamp:%u\n", __FUNCTION__, pMessageHeader->message_id, pMessageHeader->phy_id, pMessageHeader->m_segment_sequence, pMessageHeader->transmit_timestamp); + } + // look for the specific message + uint8_t result = 0; + switch (pMessageHeader->message_id) + { + case NFAPI_DL_CONFIG_REQUEST: + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() NFAPI_DL_CONFIG_REQUEST\n", __FUNCTION__); + result = pack_dl_config_request(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_UL_CONFIG_REQUEST: + result = pack_ul_config_request(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_HI_DCI0_REQUEST: + result = pack_hi_dci0_request(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_TX_REQUEST: + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() NFAPI_TX_REQUEST\n", __FUNCTION__); + result = pack_tx_request(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_HARQ_INDICATION: + result = pack_harq_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_CRC_INDICATION: + result = pack_crc_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_RX_ULSCH_INDICATION: + //printf("RX ULSCH\n"); + result = pack_rx_ulsch_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_RACH_INDICATION: + result = pack_rach_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_SRS_INDICATION: + result = pack_srs_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_RX_SR_INDICATION: + result = pack_sr_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_RX_CQI_INDICATION: + result = pack_cqi_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_LBT_DL_CONFIG_REQUEST: + result = pack_lbt_dl_config_request(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_LBT_DL_INDICATION: + result = pack_lbt_dl_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_NB_HARQ_INDICATION: + result = pack_nb_harq_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_NRACH_INDICATION: + result = pack_nrach_indication(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_DL_NODE_SYNC: + result = pack_dl_node_sync(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_UL_NODE_SYNC: + result = pack_ul_node_sync(pMessageHeader, &pWritePackedMessage, end, config); + break; + + case NFAPI_TIMING_INFO: + result = pack_timing_info(pMessageHeader, &pWritePackedMessage, end, config); + break; + + default: + { + if(pMessageHeader->message_id >= NFAPI_VENDOR_EXT_MSG_MIN && + pMessageHeader->message_id <= NFAPI_VENDOR_EXT_MSG_MAX) + { + if(config && config->pack_p7_vendor_extension) + { + result = (config->pack_p7_vendor_extension)(pMessageHeader, &pWritePackedMessage, end, config); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s VE NFAPI message ID %d. No ve ecoder provided\n", __FUNCTION__, pMessageHeader->message_id); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s NFAPI Unknown message ID %d\n", __FUNCTION__, pMessageHeader->message_id); + } + } + break; + } + + if(result == 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 Pack failed to pack message\n"); + return -1; + } + + // check for a valid message length + uintptr_t msgHead = (uintptr_t)pPackedBuf; + uintptr_t msgEnd = (uintptr_t)pWritePackedMessage; + uint32_t packedMsgLen = msgEnd - msgHead; + uint16_t packedMsgLen16; + if (packedMsgLen > 0xFFFF || packedMsgLen > packedBufLen) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Packed message length error %d, buffer supplied %d\n", packedMsgLen, packedBufLen); + return -1; + } + else + { + packedMsgLen16 = (uint16_t)packedMsgLen; + } + + // Update the message length in the header + pMessageHeader->message_length = packedMsgLen16; + + if(!push16(packedMsgLen16, &pPackedLengthField, end)) + return -1; + + if(1) + { + //quick test + if(pMessageHeader->message_length != packedMsgLen) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi packedMsgLen(%d) != message_length(%d) id %d\n", packedMsgLen, pMessageHeader->message_length, pMessageHeader->message_id); + } + } + + return (packedMsgLen); +} + + + +// Unpack routines + +static uint8_t unpack_dl_config_dci_dl_pdu_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_dci_dl_pdu_rel8_t* dci_dl_pdu_rel8 = (nfapi_dl_config_dci_dl_pdu_rel8_t*)tlv; + + return (pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->dci_format, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->cce_idx, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->aggregation_level, end) && + pull16(ppReadPackedMsg, &dci_dl_pdu_rel8->rnti, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->resource_allocation_type, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->virtual_resource_block_assignment_flag, end) && + pull32(ppReadPackedMsg, &dci_dl_pdu_rel8->resource_block_coding, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->mcs_1, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->redundancy_version_1, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->new_data_indicator_1, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->transport_block_to_codeword_swap_flag, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->mcs_2, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->redundancy_version_2, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->new_data_indicator_2, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->harq_process, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->tpmi, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->pmi, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->precoding_information, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->tpc, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->downlink_assignment_index, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->ngap, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->transport_block_size_index, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->downlink_power_offset, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->allocate_prach_flag, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->preamble_index, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->prach_mask_index, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel8->rnti_type, end) && + pull16(ppReadPackedMsg, &dci_dl_pdu_rel8->transmission_power, end)); + +} + +static uint8_t unpack_dl_config_dci_dl_pdu_rel9_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_dci_dl_pdu_rel9_t* dci_dl_pdu_rel9 = (nfapi_dl_config_dci_dl_pdu_rel9_t*)tlv; + + return ( pull8(ppReadPackedMsg, &dci_dl_pdu_rel9->mcch_flag, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel9->mcch_change_notification, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel9->scrambling_identity, end)); +} + +static uint8_t unpack_dl_config_dci_dl_pdu_rel10_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_dci_dl_pdu_rel10_t* dci_dl_pdu_rel10 = (nfapi_dl_config_dci_dl_pdu_rel10_t*)tlv; + + return (pull8(ppReadPackedMsg, &dci_dl_pdu_rel10->cross_carrier_scheduling_flag, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel10->carrier_indicator, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel10->srs_flag, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel10->srs_request, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel10->antenna_ports_scrambling_and_layers, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel10->total_dci_length_including_padding, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel10->n_dl_rb, end)); +} + +static uint8_t unpack_dl_config_dci_dl_pdu_rel11_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_dci_dl_pdu_rel11_t* dci_dl_pdu_rel11 = (nfapi_dl_config_dci_dl_pdu_rel11_t*)tlv; + + return (pull8(ppReadPackedMsg, &dci_dl_pdu_rel11->harq_ack_resource_offset, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel11->pdsch_re_mapping_quasi_co_location_indicator, end)); +} + +static uint8_t unpack_dl_config_dci_dl_pdu_rel12_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_dci_dl_pdu_rel12_t* dci_dl_pdu_rel12 = (nfapi_dl_config_dci_dl_pdu_rel12_t*)tlv; + + return (pull8(ppReadPackedMsg, &dci_dl_pdu_rel12->primary_cell_type, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel12->ul_dl_configuration_flag, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel12->number_ul_dl_configurations, end) && + pullarray8(ppReadPackedMsg, dci_dl_pdu_rel12->ul_dl_configuration_indication, NFAPI_MAX_UL_DL_CONFIGURATIONS, dci_dl_pdu_rel12->number_ul_dl_configurations, end)); +} + +static uint8_t unpack_tpm_value(uint8_t **ppReadPackedMsg, nfapi_dl_config_dci_dl_tpm_t *value, uint8_t *end) +{ + if(!(pull8(ppReadPackedMsg, &value->num_prb_per_subband, end) && + pull8(ppReadPackedMsg, &value->number_of_subbands, end) && + pull8(ppReadPackedMsg, &value->num_antennas, end))) + return 0; + + + uint8_t idx = 0; + for(idx = 0; idx < value->number_of_subbands; ++idx) + { + nfapi_dl_config_dci_dl_tpm_subband_info_t* subband_info = &(value->subband_info[idx]); + + if(!(pull8(ppReadPackedMsg, &subband_info->subband_index, end) && + pull8(ppReadPackedMsg, &subband_info->scheduled_ues, end))) + return 0; + + uint8_t antenna_idx = 0; + uint8_t scheduled_ue_idx = 0; + + for(antenna_idx = 0; antenna_idx < value->num_antennas; ++antenna_idx) + { + for(scheduled_ue_idx = 0; scheduled_ue_idx < subband_info->scheduled_ues; ++scheduled_ue_idx) + { + if(!pull16(ppReadPackedMsg, &(subband_info->precoding_value[antenna_idx][scheduled_ue_idx]), end)) + return 0; + } + } + + } + + + return 1; + +} + + +static uint8_t unpack_dl_config_dci_dl_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_dci_dl_pdu_rel13_t* dci_dl_pdu_rel13 = (nfapi_dl_config_dci_dl_pdu_rel13_t*)tlv; + + // If the length is greater than 5 then the TPM struct flag and possiably the TPM structure have been + // added + uint8_t tpm_struct_flag_present = dci_dl_pdu_rel13->tl.length > 5; + dci_dl_pdu_rel13->tpm_struct_flag = 0; + + return (pull8(ppReadPackedMsg, &dci_dl_pdu_rel13->laa_end_partial_sf_flag, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel13->laa_end_partial_sf_configuration, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel13->initial_lbt_sf, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel13->codebook_size_determination, end) && + pull8(ppReadPackedMsg, &dci_dl_pdu_rel13->drms_table_flag, end) && + ( (tpm_struct_flag_present == 1) ? pull8(ppReadPackedMsg, &dci_dl_pdu_rel13->tpm_struct_flag, end) : 1) && + ( (tpm_struct_flag_present == 1 && dci_dl_pdu_rel13->tpm_struct_flag == 1) ? unpack_tpm_value(ppReadPackedMsg, &dci_dl_pdu_rel13->tpm, end) : 1)); + +} + +static uint8_t unpack_dl_config_bch_pdu_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_bch_pdu_rel8_t* bch_pdu_rel8 = (nfapi_dl_config_bch_pdu_rel8_t*)tlv; + + return ( pull16(ppReadPackedMsg, &bch_pdu_rel8->length, end) && + pull16(ppReadPackedMsg, &bch_pdu_rel8->pdu_index, end) && + pull16(ppReadPackedMsg, &bch_pdu_rel8->transmission_power, end)); +} + +static uint8_t unpack_dl_config_mch_pdu_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_mch_pdu_rel8_t* mch_pdu_rel8 = (nfapi_dl_config_mch_pdu_rel8_t*)tlv; + + return (pull16(ppReadPackedMsg, &mch_pdu_rel8->length, end) && + pull16(ppReadPackedMsg, &mch_pdu_rel8->pdu_index, end) && + pull16(ppReadPackedMsg, &mch_pdu_rel8->rnti, end) && + pull8(ppReadPackedMsg, &mch_pdu_rel8->resource_allocation_type, end) && + pull32(ppReadPackedMsg, &mch_pdu_rel8->resource_block_coding, end) && + pull8(ppReadPackedMsg, &mch_pdu_rel8->modulation, end) && + pull16(ppReadPackedMsg, &mch_pdu_rel8->transmission_power, end) && + pull16(ppReadPackedMsg, &mch_pdu_rel8->mbsfn_area_id, end)); +} + +static uint8_t unpack_dl_config_dlsch_pdu_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_dlsch_pdu_rel8_t* dlsch_pdu_rel8 = (nfapi_dl_config_dlsch_pdu_rel8_t*)tlv; + + if (!(pull16(ppReadPackedMsg, &dlsch_pdu_rel8->length, end) && + pull16(ppReadPackedMsg, &dlsch_pdu_rel8->pdu_index, end) && + pull16(ppReadPackedMsg, &dlsch_pdu_rel8->rnti, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->resource_allocation_type, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->virtual_resource_block_assignment_flag, end) && + pull32(ppReadPackedMsg, &dlsch_pdu_rel8->resource_block_coding, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->modulation, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->redundancy_version, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->transport_blocks, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->transport_block_to_codeword_swap_flag, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->transmission_scheme, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->number_of_layers, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->number_of_subbands, end) && + pullarray8(ppReadPackedMsg, dlsch_pdu_rel8->codebook_index, NFAPI_MAX_NUM_SUBBANDS, dlsch_pdu_rel8->number_of_subbands, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->ue_category_capacity, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->pa, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->delta_power_offset_index, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->ngap, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->nprb, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->transmission_mode, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->num_bf_prb_per_subband, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->num_bf_vector, end))) + return 0; + + uint16_t j = 0; + for(j = 0; j < dlsch_pdu_rel8->num_bf_vector; ++j) + { + if(!(pull8(ppReadPackedMsg, &dlsch_pdu_rel8->bf_vector[j].subband_index, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel8->bf_vector[j].num_antennas, end) && + pullarray16(ppReadPackedMsg, dlsch_pdu_rel8->bf_vector[j].bf_value, NFAPI_MAX_NUM_ANTENNAS, dlsch_pdu_rel8->bf_vector[j].num_antennas, end))) + return 0; + } + return 1; +} +static uint8_t unpack_dl_config_dlsch_pdu_rel9_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_dlsch_pdu_rel9_t* dlsch_pdu_rel9 = (nfapi_dl_config_dlsch_pdu_rel9_t*)tlv; + return ( pull8(ppReadPackedMsg, &dlsch_pdu_rel9->nscid, end) ); +} +static uint8_t unpack_dl_config_dlsch_pdu_rel10_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_dlsch_pdu_rel10_t* dlsch_pdu_rel10 = (nfapi_dl_config_dlsch_pdu_rel10_t*)tlv; + + return ( pull8(ppReadPackedMsg, &dlsch_pdu_rel10->csi_rs_flag, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel10->csi_rs_resource_config_r10, end) && + pull16(ppReadPackedMsg, &dlsch_pdu_rel10->csi_rs_zero_tx_power_resource_config_bitmap_r10, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel10->csi_rs_number_nzp_configuration, end) && + pullarray8(ppReadPackedMsg, dlsch_pdu_rel10->csi_rs_resource_config, NFAPI_MAX_CSI_RS_RESOURCE_CONFIG, dlsch_pdu_rel10->csi_rs_number_nzp_configuration, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel10->pdsch_start, end)) ; +} +static uint8_t unpack_dl_config_dlsch_pdu_rel11_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_dlsch_pdu_rel11_t* dlsch_pdu_rel11 = (nfapi_dl_config_dlsch_pdu_rel11_t*)tlv; + + return ( pull8(ppReadPackedMsg, &dlsch_pdu_rel11->drms_config_flag, end) && + pull16(ppReadPackedMsg, &dlsch_pdu_rel11->drms_scrambling, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel11->csi_config_flag, end) && + pull16(ppReadPackedMsg, &dlsch_pdu_rel11->csi_scrambling, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel11->pdsch_re_mapping_flag, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel11->pdsch_re_mapping_atenna_ports, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel11->pdsch_re_mapping_freq_shift, end)); +} +static uint8_t unpack_dl_config_dlsch_pdu_rel12_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_dlsch_pdu_rel12_t* dlsch_pdu_rel12 = (nfapi_dl_config_dlsch_pdu_rel12_t*)tlv; + + return ( pull8(ppReadPackedMsg, &dlsch_pdu_rel12->altcqi_table_r12, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel12->maxlayers, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel12->n_dl_harq, end)); +} +static uint8_t unpack_dl_config_dlsch_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_dlsch_pdu_rel13_t* dlsch_pdu_rel13 = (nfapi_dl_config_dlsch_pdu_rel13_t*)tlv; + + return ( pull8(ppReadPackedMsg, &dlsch_pdu_rel13->dwpts_symbols, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel13->initial_lbt_sf, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel13->ue_type, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel13->pdsch_payload_type, end) && + pull16(ppReadPackedMsg, &dlsch_pdu_rel13->initial_transmission_sf_io, end) && + pull8(ppReadPackedMsg, &dlsch_pdu_rel13->drms_table_flag, end)); +} + +static uint8_t unpack_dl_config_pch_pdu_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_pch_pdu_rel8_t* pch_pdu_rel8 = (nfapi_dl_config_pch_pdu_rel8_t*)tlv; + + return ( pull16(ppReadPackedMsg, &pch_pdu_rel8->length, end) && + pull16(ppReadPackedMsg, &pch_pdu_rel8->pdu_index, end) && + pull16(ppReadPackedMsg, &pch_pdu_rel8->p_rnti, end) && + pull8(ppReadPackedMsg, &pch_pdu_rel8->resource_allocation_type, end) && + pull8(ppReadPackedMsg, &pch_pdu_rel8->virtual_resource_block_assignment_flag, end) && + pull32(ppReadPackedMsg, &pch_pdu_rel8->resource_block_coding, end) && + pull8(ppReadPackedMsg, &pch_pdu_rel8->mcs, end) && + pull8(ppReadPackedMsg, &pch_pdu_rel8->redundancy_version, end) && + pull8(ppReadPackedMsg, &pch_pdu_rel8->number_of_transport_blocks, end) && + pull8(ppReadPackedMsg, &pch_pdu_rel8->transport_block_to_codeword_swap_flag, end) && + pull8(ppReadPackedMsg, &pch_pdu_rel8->transmission_scheme, end) && + pull8(ppReadPackedMsg, &pch_pdu_rel8->number_of_layers, end) && + pull8(ppReadPackedMsg, &pch_pdu_rel8->codebook_index, end) && + pull8(ppReadPackedMsg, &pch_pdu_rel8->ue_category_capacity, end) && + pull8(ppReadPackedMsg, &pch_pdu_rel8->pa, end) && + pull16(ppReadPackedMsg, &pch_pdu_rel8->transmission_power, end) && + pull8(ppReadPackedMsg, &pch_pdu_rel8->nprb, end) && + pull8(ppReadPackedMsg, &pch_pdu_rel8->ngap, end)); +} +static uint8_t unpack_dl_config_pch_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_pch_pdu_rel13_t* pch_pdu_rel13 = (nfapi_dl_config_pch_pdu_rel13_t*)tlv; + + return ( pull8(ppReadPackedMsg, &pch_pdu_rel13->ue_mode, end) && + pull16(ppReadPackedMsg, &pch_pdu_rel13->initial_transmission_sf_io, end)); +} + +static uint8_t unpack_dl_config_prs_pdu_rel9_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_prs_pdu_rel9_t* prs_pdu_rel9 = (nfapi_dl_config_prs_pdu_rel9_t*)tlv; + + return ( pull16(ppReadPackedMsg, &prs_pdu_rel9->transmission_power, end) && + pull8(ppReadPackedMsg, &prs_pdu_rel9->prs_bandwidth, end) && + pull8(ppReadPackedMsg, &prs_pdu_rel9->prs_cyclic_prefix_type, end) && + pull8(ppReadPackedMsg, &prs_pdu_rel9->prs_muting, end)); +} + +static uint8_t unpack_dl_config_csi_rs_pdu_rel10_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_csi_rs_pdu_rel10_t* csi_rs_pdu_rel10 = (nfapi_dl_config_csi_rs_pdu_rel10_t*)tlv; + + return ( pull8(ppReadPackedMsg, &csi_rs_pdu_rel10->csi_rs_antenna_port_count_r10, end) && + pull8(ppReadPackedMsg, &csi_rs_pdu_rel10->csi_rs_resource_config_r10, end) && + pull16(ppReadPackedMsg, &csi_rs_pdu_rel10->transmission_power, end) && + pull16(ppReadPackedMsg, &csi_rs_pdu_rel10->csi_rs_zero_tx_power_resource_config_bitmap_r10, end) && + pull8(ppReadPackedMsg, &csi_rs_pdu_rel10->csi_rs_number_of_nzp_configuration, end) && + pullarray8(ppReadPackedMsg, csi_rs_pdu_rel10->csi_rs_resource_config, NFAPI_MAX_CSI_RS_RESOURCE_CONFIG, csi_rs_pdu_rel10->csi_rs_number_of_nzp_configuration, end)); +} + +static uint8_t unpack_dl_config_csi_rs_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_csi_rs_pdu_rel13_t* csi_rs_pdu_rel13 = (nfapi_dl_config_csi_rs_pdu_rel13_t*)tlv; + + if (!(pull8(ppReadPackedMsg, &csi_rs_pdu_rel13->csi_rs_class, end) && + pull8(ppReadPackedMsg, &csi_rs_pdu_rel13->cdm_type, end) && + pull8(ppReadPackedMsg, &csi_rs_pdu_rel13->num_bf_vector, end))) + return 0; + + + uint16_t idx =0; + for(idx = 0; idx < csi_rs_pdu_rel13->num_bf_vector; ++idx) + { + if(!(pull8(ppReadPackedMsg, &csi_rs_pdu_rel13->bf_vector[idx].csi_rs_resource_index, end))) + return 0; + NFAPI_TRACE(NFAPI_TRACE_ERROR, "FIXME : HOW TO DECODE BF VALUE \n"); + //pullarray16(ppReadPackedMsg, &csi_rs_pdu_rel13->bf_vector[idx].bf_vector, ??); + } + return 1; +} + +static uint8_t unpack_dl_config_epdcch_params_rel11_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_epdcch_parameters_rel11_t* epdcch_params_rel11 = (nfapi_dl_config_epdcch_parameters_rel11_t*)tlv; + + return (pull8(ppReadPackedMsg, &epdcch_params_rel11->epdcch_resource_assignment_flag, end) && + pull16(ppReadPackedMsg, &epdcch_params_rel11->epdcch_id, end) && + pull8(ppReadPackedMsg, &epdcch_params_rel11->epdcch_start_symbol, end) && + pull8(ppReadPackedMsg, &epdcch_params_rel11->epdcch_num_prb, end) && + pullarray8(ppReadPackedMsg, epdcch_params_rel11->epdcch_prb_index, NFAPI_MAX_EPDCCH_PRB, epdcch_params_rel11->epdcch_num_prb, end) && + pull8(ppReadPackedMsg, &epdcch_params_rel11->bf_vector.subband_index, end) && + pull8(ppReadPackedMsg, &epdcch_params_rel11->bf_vector.num_antennas, end) && + pullarray16(ppReadPackedMsg, epdcch_params_rel11->bf_vector.bf_value, NFAPI_MAX_NUM_ANTENNAS, epdcch_params_rel11->bf_vector.num_antennas, end)); +} + +static uint8_t unpack_dl_config_epdcch_params_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_epdcch_parameters_rel13_t* epdcch_params_rel13 = (nfapi_dl_config_epdcch_parameters_rel13_t*)tlv; + + return ( pull8(ppReadPackedMsg, &epdcch_params_rel13->dwpts_symbols, end) && + pull8(ppReadPackedMsg, &epdcch_params_rel13->initial_lbt_sf, end)); +} + +static uint8_t unpack_dl_config_mpdcch_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_mpdcch_pdu_rel13_t* mpdcch_params_rel13 = (nfapi_dl_config_mpdcch_pdu_rel13_t*)tlv; + + + return ( pull8(ppReadPackedMsg, &mpdcch_params_rel13->mpdcch_narrow_band, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->number_of_prb_pairs, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->resource_block_assignment, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->mpdcch_tansmission_type, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->start_symbol, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->ecce_index, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->aggregation_level, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->rnti_type, end) && + pull16(ppReadPackedMsg, &mpdcch_params_rel13->rnti, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->ce_mode, end) && + pull16(ppReadPackedMsg, &mpdcch_params_rel13->drms_scrambling_init, end) && + pull16(ppReadPackedMsg, &mpdcch_params_rel13->initial_transmission_sf_io, end) && + pull16(ppReadPackedMsg, &mpdcch_params_rel13->transmission_power, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->dci_format, end) && + pull16(ppReadPackedMsg, &mpdcch_params_rel13->resource_block_coding, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->mcs, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->pdsch_reptition_levels, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->redundancy_version, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->new_data_indicator, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->harq_process, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->tpmi_length, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->tpmi, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->pmi_flag, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->pmi, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->harq_resource_offset, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->dci_subframe_repetition_number, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->tpc, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->downlink_assignment_index_length, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->downlink_assignment_index, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->allocate_prach_flag, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->preamble_index, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->prach_mask_index, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->starting_ce_level, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->srs_request, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->antenna_ports_and_scrambling_identity_flag, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->antenna_ports_and_scrambling_identity, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->frequency_hopping_enabled_flag, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->paging_direct_indication_differentiation_flag, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->direct_indication, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->total_dci_length_including_padding, end) && + pull8(ppReadPackedMsg, &mpdcch_params_rel13->number_of_tx_antenna_ports, end) && + pullarray16(ppReadPackedMsg, mpdcch_params_rel13->precoding_value, NFAPI_MAX_TX_PHYSICAL_ANTENNA_PORTS, mpdcch_params_rel13->number_of_tx_antenna_ports, end)); +} + + +static uint8_t unpack_dl_config_nbch_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_nbch_pdu_rel13_t* nbch_params_rel13 = (nfapi_dl_config_nbch_pdu_rel13_t*)tlv; + + return ( pull16(ppReadPackedMsg, &nbch_params_rel13->length, end) && + pull16(ppReadPackedMsg, &nbch_params_rel13->pdu_index, end) && + pull16(ppReadPackedMsg, &nbch_params_rel13->transmission_power, end) && + pull16(ppReadPackedMsg, &nbch_params_rel13->hyper_sfn_2_lsbs, end)); +} + +static uint8_t unpack_dl_config_npdcch_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_npdcch_pdu_rel13_t* npdcch_params_rel13 = (nfapi_dl_config_npdcch_pdu_rel13_t*)tlv; + + return ( pull16(ppReadPackedMsg, &npdcch_params_rel13->length, end) && + pull16(ppReadPackedMsg, &npdcch_params_rel13->pdu_index, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->ncce_index, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->aggregation_level, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->start_symbol, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->rnti_type, end) && + pull16(ppReadPackedMsg, &npdcch_params_rel13->rnti, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->scrambling_reinitialization_batch_index, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->nrs_antenna_ports_assumed_by_the_ue, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->dci_format, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->scheduling_delay, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->resource_assignment, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->repetition_number, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->mcs, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->new_data_indicator, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->harq_ack_resource, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->npdcch_order_indication, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->starting_number_of_nprach_repetitions, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->subcarrier_indication_of_nprach, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->paging_direct_indication_differentation_flag, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->direct_indication, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->dci_subframe_repetition_number, end) && + pull8(ppReadPackedMsg, &npdcch_params_rel13->total_dci_length_including_padding, end)); +} + +static uint8_t unpack_dl_config_ndlsch_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_dl_config_ndlsch_pdu_rel13_t* ndlsch_params_rel13 = (nfapi_dl_config_ndlsch_pdu_rel13_t*)tlv; + + return ( pull16(ppReadPackedMsg, &ndlsch_params_rel13->length, end) && + pull16(ppReadPackedMsg, &ndlsch_params_rel13->pdu_index, end) && + pull8(ppReadPackedMsg, &ndlsch_params_rel13->start_symbol, end) && + pull8(ppReadPackedMsg, &ndlsch_params_rel13->rnti_type, end) && + pull16(ppReadPackedMsg, &ndlsch_params_rel13->rnti, end) && + pull16(ppReadPackedMsg, &ndlsch_params_rel13->resource_assignment, end) && + pull16(ppReadPackedMsg, &ndlsch_params_rel13->repetition_number, end) && + pull8(ppReadPackedMsg, &ndlsch_params_rel13->modulation, end) && + pull8(ppReadPackedMsg, &ndlsch_params_rel13->number_of_subframes_for_resource_assignment, end) && + pull8(ppReadPackedMsg, &ndlsch_params_rel13->scrambling_sequence_initialization_cinit, end) && + pull16(ppReadPackedMsg, &ndlsch_params_rel13->sf_idx, end) && + pull8(ppReadPackedMsg, &ndlsch_params_rel13->nrs_antenna_ports_assumed_by_the_ue, end)); +} + + +static uint8_t unpack_dl_config_request_body_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_dl_config_request_body_t* value = (nfapi_dl_config_request_body_t*)tlv; + + if(!(pull8(ppReadPackedMsg, &value->number_pdcch_ofdm_symbols, end) && + pull8(ppReadPackedMsg, &value->number_dci, end) && + pull16(ppReadPackedMsg, &value->number_pdu, end) && + pull8(ppReadPackedMsg, &value->number_pdsch_rnti, end) && + pull16(ppReadPackedMsg, &value->transmission_power_pcfich, end))) + return 0; + + if(value->number_pdu > NFAPI_DL_CONFIG_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of dl config pdu's exceed maxium (count:%d max:%d)\n", __FUNCTION__, value->number_pdu, NFAPI_DL_CONFIG_MAX_PDU); + return 0; + } + + if(value->number_pdu) + { + value->dl_config_pdu_list = (nfapi_dl_config_request_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_dl_config_request_pdu_t) * value->number_pdu, config); + if(value->dl_config_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate dl config pdu list (count:%d)\n", __FUNCTION__, value->number_pdu); + return 0; + } + } + else + { + value->dl_config_pdu_list = 0; + } + + uint16_t i; + uint16_t total_number_of_pdus = value->number_pdu; + for(i = 0; i < total_number_of_pdus; ++i) + { + nfapi_dl_config_request_pdu_t* pdu = &(value->dl_config_pdu_list[i]); + + if(!(pull8(ppReadPackedMsg, &pdu->pdu_type, end) && + pull8(ppReadPackedMsg, &pdu->pdu_size, end))) + return 0; + + uint8_t *packedPduEnd = (*ppReadPackedMsg) + pdu->pdu_size - 2; + + if(packedPduEnd > end) + { + // pdu end of beyond buffer end + return 0; + } + + switch(pdu->pdu_type) + { + case NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel8, &unpack_dl_config_dci_dl_pdu_rel8_value}, + { NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL9_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel9, &unpack_dl_config_dci_dl_pdu_rel9_value}, + { NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL10_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel10, &unpack_dl_config_dci_dl_pdu_rel10_value}, + { NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL11_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel11, &unpack_dl_config_dci_dl_pdu_rel11_value}, + { NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL12_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel12, &unpack_dl_config_dci_dl_pdu_rel12_value}, + { NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL13_TAG, &pdu->dci_dl_pdu.dci_dl_pdu_rel13, &unpack_dl_config_dci_dl_pdu_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_DL_CONFIG_BCH_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_DL_CONFIG_REQUEST_BCH_PDU_REL8_TAG, &pdu->bch_pdu.bch_pdu_rel8, &unpack_dl_config_bch_pdu_rel8_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_DL_CONFIG_MCH_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_DL_CONFIG_REQUEST_MCH_PDU_REL8_TAG, &pdu->mch_pdu.mch_pdu_rel8, &unpack_dl_config_mch_pdu_rel8_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_DL_CONFIG_DLSCH_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG, &pdu->dlsch_pdu.dlsch_pdu_rel8, &unpack_dl_config_dlsch_pdu_rel8_value}, + { NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL9_TAG, &pdu->dlsch_pdu.dlsch_pdu_rel9, &unpack_dl_config_dlsch_pdu_rel9_value}, + { NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG, &pdu->dlsch_pdu.dlsch_pdu_rel10, &unpack_dl_config_dlsch_pdu_rel10_value}, + { NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL11_TAG, &pdu->dlsch_pdu.dlsch_pdu_rel11, &unpack_dl_config_dlsch_pdu_rel11_value}, + { NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL12_TAG, &pdu->dlsch_pdu.dlsch_pdu_rel12, &unpack_dl_config_dlsch_pdu_rel12_value}, + { NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG, &pdu->dlsch_pdu.dlsch_pdu_rel13, &unpack_dl_config_dlsch_pdu_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_DL_CONFIG_PCH_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_DL_CONFIG_REQUEST_PCH_PDU_REL8_TAG, &pdu->pch_pdu.pch_pdu_rel8, &unpack_dl_config_pch_pdu_rel8_value}, + { NFAPI_DL_CONFIG_REQUEST_PCH_PDU_REL13_TAG, &pdu->pch_pdu.pch_pdu_rel13, &unpack_dl_config_pch_pdu_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_DL_CONFIG_PRS_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_DL_CONFIG_REQUEST_PRS_PDU_REL9_TAG, &pdu->prs_pdu.prs_pdu_rel9, &unpack_dl_config_prs_pdu_rel9_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_DL_CONFIG_CSI_RS_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_DL_CONFIG_REQUEST_CSI_RS_PDU_REL10_TAG, &pdu->csi_rs_pdu.csi_rs_pdu_rel10, &unpack_dl_config_csi_rs_pdu_rel10_value}, + { NFAPI_DL_CONFIG_REQUEST_CSI_RS_PDU_REL13_TAG, &pdu->csi_rs_pdu.csi_rs_pdu_rel13, &unpack_dl_config_csi_rs_pdu_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_DL_CONFIG_EPDCCH_DL_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL8_TAG, &pdu->epdcch_pdu.epdcch_pdu_rel8, &unpack_dl_config_dci_dl_pdu_rel8_value}, + { NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL9_TAG, &pdu->epdcch_pdu.epdcch_pdu_rel9, &unpack_dl_config_dci_dl_pdu_rel9_value}, + { NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL10_TAG, &pdu->epdcch_pdu.epdcch_pdu_rel10, &unpack_dl_config_dci_dl_pdu_rel10_value}, + { NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL11_TAG, &pdu->epdcch_pdu.epdcch_pdu_rel11, &unpack_dl_config_dci_dl_pdu_rel11_value}, + { NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL12_TAG, &pdu->epdcch_pdu.epdcch_pdu_rel12, &unpack_dl_config_dci_dl_pdu_rel12_value}, + { NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL13_TAG, &pdu->epdcch_pdu.epdcch_pdu_rel13, &unpack_dl_config_dci_dl_pdu_rel13_value}, + { NFAPI_DL_CONFIG_REQUEST_EPDCCH_PARAM_REL11_TAG, &pdu->epdcch_pdu.epdcch_params_rel11, &unpack_dl_config_epdcch_params_rel11_value}, + { NFAPI_DL_CONFIG_REQUEST_EPDCCH_PARAM_REL13_TAG, &pdu->epdcch_pdu.epdcch_params_rel13, &unpack_dl_config_epdcch_params_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_DL_CONFIG_REQUEST_MPDCCH_PDU_REL13_TAG, &pdu->mpdcch_pdu.mpdcch_pdu_rel13, &unpack_dl_config_mpdcch_pdu_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_DL_CONFIG_NBCH_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_DL_CONFIG_REQUEST_NBCH_PDU_REL13_TAG, &pdu->nbch_pdu.nbch_pdu_rel13, &unpack_dl_config_nbch_pdu_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_DL_CONFIG_NPDCCH_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_DL_CONFIG_REQUEST_NPDCCH_PDU_REL13_TAG, &pdu->npdcch_pdu.npdcch_pdu_rel13, &unpack_dl_config_npdcch_pdu_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + + } + break; + case NFAPI_DL_CONFIG_NDLSCH_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_DL_CONFIG_REQUEST_NDLSCH_PDU_REL13_TAG, &pdu->ndlsch_pdu.ndlsch_pdu_rel13, &unpack_dl_config_ndlsch_pdu_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + + } + break; + default: + // Need to log an error + break; + } + } + + return 1; +} + +static uint8_t unpack_dl_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_dl_config_request_t *pNfapiMsg = (nfapi_dl_config_request_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + { NFAPI_DL_CONFIG_REQUEST_BODY_TAG, &pNfapiMsg->dl_config_request_body, &unpack_dl_config_request_body_value}, + }; + + return ( pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_ul_config_ulsch_pdu_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_ulsch_pdu_rel8_t* ulsch_pdu_rel8 = (nfapi_ul_config_ulsch_pdu_rel8_t*)tlv; + + return (pull32(ppReadPackedMsg, &ulsch_pdu_rel8->handle, end) && + pull16(ppReadPackedMsg, &ulsch_pdu_rel8->size, end) && + pull16(ppReadPackedMsg, &ulsch_pdu_rel8->rnti, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel8->resource_block_start, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel8->number_of_resource_blocks, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel8->modulation_type, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel8->cyclic_shift_2_for_drms, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel8->frequency_hopping_enabled_flag, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel8->frequency_hopping_bits, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel8->new_data_indication, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel8->redundancy_version, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel8->harq_process_number, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel8->ul_tx_mode, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel8->current_tx_nb, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel8->n_srs, end )); +} +static uint8_t unpack_ul_config_ulsch_pdu_rel10_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_ulsch_pdu_rel10_t* ulsch_pdu_rel10 = (nfapi_ul_config_ulsch_pdu_rel10_t*)tlv; + + return (pull8(ppReadPackedMsg, &ulsch_pdu_rel10->resource_allocation_type, end) && + pull32(ppReadPackedMsg, &ulsch_pdu_rel10->resource_block_coding, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel10->transport_blocks, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel10->transmission_scheme, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel10->number_of_layers, end) & + pull8(ppReadPackedMsg, &ulsch_pdu_rel10->codebook_index, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel10->disable_sequence_hopping_flag, end)); +} +static uint8_t unpack_ul_config_ulsch_pdu_rel11_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_ulsch_pdu_rel11_t* ulsch_pdu_rel11 = (nfapi_ul_config_ulsch_pdu_rel11_t*)tlv; + + return ( pull8(ppReadPackedMsg, &ulsch_pdu_rel11->virtual_cell_id_enabled_flag, end) && + pull16(ppReadPackedMsg, &ulsch_pdu_rel11->npusch_identity, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel11->dmrs_config_flag, end) && + pull16(ppReadPackedMsg, &ulsch_pdu_rel11->ndmrs_csh_identity, end)); +} +static uint8_t unpack_ul_config_ulsch_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_ulsch_pdu_rel13_t* ulsch_pdu_rel13 = (nfapi_ul_config_ulsch_pdu_rel13_t*)tlv; + + return (pull8(ppReadPackedMsg, &ulsch_pdu_rel13->ue_type, end) && + pull16(ppReadPackedMsg, &ulsch_pdu_rel13->total_number_of_repetitions, end) && + pull16(ppReadPackedMsg, &ulsch_pdu_rel13->repetition_number, end) && + pull16(ppReadPackedMsg, &ulsch_pdu_rel13->initial_transmission_sf_io, end) && + pull8(ppReadPackedMsg, &ulsch_pdu_rel13->empty_symbols_due_to_re_tunning, end)); +} +static uint8_t unpack_ul_config_cqi_ri_info_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_cqi_ri_information_rel8_t* cqi_ri_info_rel8 = (nfapi_ul_config_cqi_ri_information_rel8_t*)tlv; + + return (pull8(ppReadPackedMsg, &cqi_ri_info_rel8->dl_cqi_pmi_size_rank_1, end) && + pull8(ppReadPackedMsg, &cqi_ri_info_rel8->dl_cqi_pmi_size_rank_greater_1, end) && + pull8(ppReadPackedMsg, &cqi_ri_info_rel8->ri_size, end) && + pull8(ppReadPackedMsg, &cqi_ri_info_rel8->delta_offset_cqi, end) && + pull8(ppReadPackedMsg, &cqi_ri_info_rel8->delta_offset_ri, end)); +} + +static uint8_t unpack_ul_config_cqi_ri_info_rel9_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_cqi_ri_information_rel9_t* cqi_ri_info_rel9 = (nfapi_ul_config_cqi_ri_information_rel9_t*)tlv; + + if(!(pull8(ppReadPackedMsg, &cqi_ri_info_rel9->report_type, end) && + pull8(ppReadPackedMsg, &cqi_ri_info_rel9->delta_offset_cqi, end) && + pull8(ppReadPackedMsg, &cqi_ri_info_rel9->delta_offset_ri, end))) + return 0; + + switch(cqi_ri_info_rel9->report_type) + { + case NFAPI_CSI_REPORT_TYPE_PERIODIC: + { + if(!(pull8(ppReadPackedMsg, &cqi_ri_info_rel9->periodic_cqi_pmi_ri_report.dl_cqi_pmi_ri_size, end) && + pull8(ppReadPackedMsg, &cqi_ri_info_rel9->periodic_cqi_pmi_ri_report.control_type, end))) + return 0; + } + break; + case NFAPI_CSI_REPORT_TYPE_APERIODIC: + { + if(pull8(ppReadPackedMsg, &cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.number_of_cc, end) ==0) + return 0; + + uint8_t i; + for(i = 0; i < cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.number_of_cc; ++i) + { + if(pull8(ppReadPackedMsg, &cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.cc[i].ri_size, end) == 0) + return 0; + + uint8_t j; + for(j = 0; j < 8; ++j) + { + if(pull8(ppReadPackedMsg, &cqi_ri_info_rel9->aperiodic_cqi_pmi_ri_report.cc[i].dl_cqi_pmi_size[j], end) == 0) + return 0; + } + } + } + break; + default: + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "FIXME : Invalid report type %d \n", cqi_ri_info_rel9->report_type ); + return 0; + } + break; + }; + return 1; +} + +// NOTE : This function is a little unconventional as we uese the side to +// determine the report type +static uint8_t unpack_ul_config_cqi_ri_info_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_cqi_ri_information_rel13_t* cqi_ri_info_rel13 = (nfapi_ul_config_cqi_ri_information_rel13_t*)tlv; + if(cqi_ri_info_rel13->tl.length == 0) + { + cqi_ri_info_rel13->report_type = NFAPI_CSI_REPORT_TYPE_APERIODIC; + } + else + { + cqi_ri_info_rel13->report_type = NFAPI_CSI_REPORT_TYPE_PERIODIC; + if(pull16(ppReadPackedMsg, &cqi_ri_info_rel13->periodic_cqi_pmi_ri_report.dl_cqi_pmi_ri_size_2, end) == 0) + return 0; + } + return 1; +} +static uint8_t unpack_ul_config_cqi_init_tx_params_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_initial_transmission_parameters_rel8_t* init_tx_params_rel8 = (nfapi_ul_config_initial_transmission_parameters_rel8_t*)tlv; + + return (pull8(ppReadPackedMsg, &init_tx_params_rel8->n_srs_initial, end) && + pull8(ppReadPackedMsg, &init_tx_params_rel8->initial_number_of_resource_blocks, end)); +} +static uint8_t unpack_ul_config_ulsch_harq_info_rel10_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_ulsch_harq_information_rel10_t* harq_info_rel10 = (nfapi_ul_config_ulsch_harq_information_rel10_t*)tlv; + + return (pull8(ppReadPackedMsg, &harq_info_rel10->harq_size, end) && + pull8(ppReadPackedMsg, &harq_info_rel10->delta_offset_harq, end) && + pull8(ppReadPackedMsg, &harq_info_rel10->ack_nack_mode, end)); +} + +static uint8_t unpack_ul_config_ulsch_harq_info_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_ulsch_harq_information_rel13_t* harq_info_rel13 = (nfapi_ul_config_ulsch_harq_information_rel13_t*)tlv; + + return (pull16(ppReadPackedMsg, &harq_info_rel13->harq_size_2, end) && + pull8(ppReadPackedMsg, &harq_info_rel13->delta_offset_harq_2, end)); +} + +static uint8_t unpack_ul_config_ue_info_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_ue_information_rel8_t* ue_info_rel8 = (nfapi_ul_config_ue_information_rel8_t*)tlv; + + return (pull32(ppReadPackedMsg, &ue_info_rel8->handle, end) && + pull16(ppReadPackedMsg, &ue_info_rel8->rnti, end)); +} +static uint8_t unpack_ul_config_ue_info_rel11_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_ue_information_rel11_t* ue_info_rel11 = (nfapi_ul_config_ue_information_rel11_t*)tlv; + + return (pull8(ppReadPackedMsg, &ue_info_rel11->virtual_cell_id_enabled_flag, end) && + pull16(ppReadPackedMsg, &ue_info_rel11->npusch_identity, end)); +} +static uint8_t unpack_ul_config_ue_info_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_ue_information_rel13_t* ue_info_rel13 = (nfapi_ul_config_ue_information_rel13_t*)tlv; + + return (pull8(ppReadPackedMsg, &ue_info_rel13->ue_type, end) && + pull8(ppReadPackedMsg, &ue_info_rel13->empty_symbols, end) && + pull16(ppReadPackedMsg, &ue_info_rel13->total_number_of_repetitions, end) && + pull16(ppReadPackedMsg, &ue_info_rel13->repetition_number, end)); +} + +static uint8_t unpack_ul_config_cqi_info_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_cqi_information_rel8_t* cqi_info_rel8 = (nfapi_ul_config_cqi_information_rel8_t*)tlv; + + return ( pull16(ppReadPackedMsg, &cqi_info_rel8->pucch_index, end) && + pull8(ppReadPackedMsg, &cqi_info_rel8->dl_cqi_pmi_size, end)); +} +static uint8_t unpack_ul_config_cqi_info_rel10_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_cqi_information_rel10_t* cqi_info_rel10 = (nfapi_ul_config_cqi_information_rel10_t*)tlv; + + return (pull8(ppReadPackedMsg, &cqi_info_rel10->number_of_pucch_resource, end) && + pull16(ppReadPackedMsg, &cqi_info_rel10->pucch_index_p1, end)); +} +static uint8_t unpack_ul_config_cqi_info_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_cqi_information_rel13_t* cqi_info_rel13 = (nfapi_ul_config_cqi_information_rel13_t*)tlv; + + return (pull8(ppReadPackedMsg, &cqi_info_rel13->csi_mode, end) && + pull16(ppReadPackedMsg, &cqi_info_rel13->dl_cqi_pmi_size_2, end) && + pull8(ppReadPackedMsg, &cqi_info_rel13->starting_prb, end) && + pull8(ppReadPackedMsg, &cqi_info_rel13->n_prb, end) && + pull8(ppReadPackedMsg, &cqi_info_rel13->cdm_index, end) && + pull8(ppReadPackedMsg, &cqi_info_rel13->n_srs, end)); +} + +static uint8_t unpack_ul_config_sr_info_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_sr_information_rel8_t* sr_info_rel8 = (nfapi_ul_config_sr_information_rel8_t*)tlv; + + return ( pull16(ppReadPackedMsg, &sr_info_rel8->pucch_index, end)); +} + +static uint8_t unpack_ul_config_sr_info_rel10_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_sr_information_rel10_t* sr_info_rel10 = (nfapi_ul_config_sr_information_rel10_t*)tlv; + + return (pull8(ppReadPackedMsg, &sr_info_rel10->number_of_pucch_resources, end) && + pull16(ppReadPackedMsg, &sr_info_rel10->pucch_index_p1, end)); +} + +static uint8_t unpack_ul_config_harq_info_rel10_tdd_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_harq_information_rel10_tdd_t* harq_info_tdd_rel10 = (nfapi_ul_config_harq_information_rel10_tdd_t*)tlv; + + return (pull8(ppReadPackedMsg, &harq_info_tdd_rel10->harq_size, end) && + pull8(ppReadPackedMsg, &harq_info_tdd_rel10->ack_nack_mode, end) && + pull8(ppReadPackedMsg, &harq_info_tdd_rel10->number_of_pucch_resources, end) && + pull16(ppReadPackedMsg, &harq_info_tdd_rel10->n_pucch_1_0, end) && + pull16(ppReadPackedMsg, &harq_info_tdd_rel10->n_pucch_1_1, end) && + pull16(ppReadPackedMsg, &harq_info_tdd_rel10->n_pucch_1_2, end) && + pull16(ppReadPackedMsg, &harq_info_tdd_rel10->n_pucch_1_3, end)); +} + +static uint8_t unpack_ul_config_harq_info_rel8_fdd_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_harq_information_rel8_fdd_t* harq_info_fdd_rel8 = (nfapi_ul_config_harq_information_rel8_fdd_t*)tlv; + + return (pull16(ppReadPackedMsg, &harq_info_fdd_rel8->n_pucch_1_0, end) && + pull8(ppReadPackedMsg, &harq_info_fdd_rel8->harq_size, end)); +} + +static uint8_t unpack_ul_config_harq_info_rel9_fdd_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_harq_information_rel9_fdd_t* harq_info_fdd_rel9 = (nfapi_ul_config_harq_information_rel9_fdd_t*)tlv; + + return (pull8(ppReadPackedMsg, &harq_info_fdd_rel9->harq_size, end) && + pull8(ppReadPackedMsg, &harq_info_fdd_rel9->ack_nack_mode, end) && + pull8(ppReadPackedMsg, &harq_info_fdd_rel9->number_of_pucch_resources, end) && + pull16(ppReadPackedMsg, &harq_info_fdd_rel9->n_pucch_1_0, end) && + pull16(ppReadPackedMsg, &harq_info_fdd_rel9->n_pucch_1_1, end) && + pull16(ppReadPackedMsg, &harq_info_fdd_rel9->n_pucch_1_2, end) && + pull16(ppReadPackedMsg, &harq_info_fdd_rel9->n_pucch_1_3, end)); +} + +static uint8_t unpack_ul_config_harq_info_rel11_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_harq_information_rel11_t* harq_info_rel11 = (nfapi_ul_config_harq_information_rel11_t*)tlv; + + return (pull8(ppReadPackedMsg, &harq_info_rel11->num_ant_ports, end) && + pull16(ppReadPackedMsg, &harq_info_rel11->n_pucch_2_0, end) && + pull16(ppReadPackedMsg, &harq_info_rel11->n_pucch_2_1, end) && + pull16(ppReadPackedMsg, &harq_info_rel11->n_pucch_2_2, end) && + pull16(ppReadPackedMsg, &harq_info_rel11->n_pucch_2_3, end)); +} + +static uint8_t unpack_ul_config_harq_info_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_harq_information_rel13_t* harq_info_rel13 = (nfapi_ul_config_harq_information_rel13_t*)tlv; + + return (pull16(ppReadPackedMsg, &harq_info_rel13->harq_size_2, end) && + pull8(ppReadPackedMsg, &harq_info_rel13->starting_prb, end) && + pull8(ppReadPackedMsg, &harq_info_rel13->n_prb, end) && + pull8(ppReadPackedMsg, &harq_info_rel13->cdm_index, end) && + pull8(ppReadPackedMsg, &harq_info_rel13->n_srs, end)); +} + + +static uint8_t unpack_ul_config_srs_pdu_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_srs_pdu_rel8_t* srs_pdu_rel8 = (nfapi_ul_config_srs_pdu_rel8_t*)tlv; + + return (pull32(ppReadPackedMsg, &srs_pdu_rel8->handle, end) && + pull16(ppReadPackedMsg, &srs_pdu_rel8->size, end) && + pull16(ppReadPackedMsg, &srs_pdu_rel8->rnti, end) && + pull8(ppReadPackedMsg, &srs_pdu_rel8->srs_bandwidth, end) && + pull8(ppReadPackedMsg, &srs_pdu_rel8->frequency_domain_position, end) && + pull8(ppReadPackedMsg, &srs_pdu_rel8->srs_hopping_bandwidth, end) && + pull8(ppReadPackedMsg, &srs_pdu_rel8->transmission_comb, end) && + pull16(ppReadPackedMsg, &srs_pdu_rel8->i_srs, end) && + pull8(ppReadPackedMsg, &srs_pdu_rel8->sounding_reference_cyclic_shift, end)); +} + +static uint8_t unpack_ul_config_srs_pdu_rel10_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_srs_pdu_rel10_t* srs_pdu_rel10 = (nfapi_ul_config_srs_pdu_rel10_t*)tlv; + return pull8(ppReadPackedMsg, &srs_pdu_rel10->antenna_port, end); +} + +static uint8_t unpack_ul_config_srs_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_srs_pdu_rel13_t* srs_pdu_rel13 = (nfapi_ul_config_srs_pdu_rel13_t*)tlv; + + return (pull8(ppReadPackedMsg, &srs_pdu_rel13->number_of_combs, end)); +} + +static uint8_t unpack_ul_nb_harq_info_rel13_fdd_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_nb_harq_information_rel13_fdd_t* nb_harq_info_fdd_rel13 = (nfapi_ul_config_nb_harq_information_rel13_fdd_t*)tlv; + + return (pull8(ppReadPackedMsg, &nb_harq_info_fdd_rel13->harq_ack_resource, end)); +} + +static uint8_t unpack_ul_config_nulsch_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_nulsch_pdu_rel13_t* nulsch_pdu_rel13 = (nfapi_ul_config_nulsch_pdu_rel13_t*)tlv; + + if(!(pull8(ppReadPackedMsg, &nulsch_pdu_rel13->nulsch_format, end) && + pull32(ppReadPackedMsg, &nulsch_pdu_rel13->handle, end) && + pull16(ppReadPackedMsg, &nulsch_pdu_rel13->size, end) && + pull16(ppReadPackedMsg, &nulsch_pdu_rel13->rnti, end) && + pull8(ppReadPackedMsg, &nulsch_pdu_rel13->subcarrier_indication, end) && + pull8(ppReadPackedMsg, &nulsch_pdu_rel13->resource_assignment, end) && + pull8(ppReadPackedMsg, &nulsch_pdu_rel13->mcs, end) && + pull8(ppReadPackedMsg, &nulsch_pdu_rel13->redudancy_version, end) && + pull8(ppReadPackedMsg, &nulsch_pdu_rel13->repetition_number, end) && + pull8(ppReadPackedMsg, &nulsch_pdu_rel13->new_data_indication, end) && + pull8(ppReadPackedMsg, &nulsch_pdu_rel13->n_srs, end) && + pull16(ppReadPackedMsg, &nulsch_pdu_rel13->scrambling_sequence_initialization_cinit, end) && + pull16(ppReadPackedMsg, &nulsch_pdu_rel13->sf_idx, end))) + return 0; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG, &nulsch_pdu_rel13->ue_information.ue_information_rel8, &unpack_ul_config_ue_info_rel8_value}, + { NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL11_TAG, &nulsch_pdu_rel13->ue_information.ue_information_rel11, &unpack_ul_config_ue_info_rel11_value}, + { NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL13_TAG, &nulsch_pdu_rel13->ue_information.ue_information_rel13, &unpack_ul_config_ue_info_rel13_value}, + { NFAPI_UL_CONFIG_REQUEST_NB_HARQ_INFORMATION_REL13_FDD_TAG, &nulsch_pdu_rel13->nb_harq_information.nb_harq_information_rel13_fdd, &unpack_ul_nb_harq_info_rel13_fdd_value}, + }; + + return unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, 0, 0); +} + +static uint8_t unpack_ul_config_nrach_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_config_nrach_pdu_rel13_t* nrach_pdu_rel13 = (nfapi_ul_config_nrach_pdu_rel13_t*)tlv; + + return (pull8(ppReadPackedMsg, &nrach_pdu_rel13->nprach_config_0, end) && + pull8(ppReadPackedMsg, &nrach_pdu_rel13->nprach_config_1, end) && + pull8(ppReadPackedMsg, &nrach_pdu_rel13->nprach_config_2, end)); +} + + +static uint8_t unpack_ul_config_request_body_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + #define UL_CONFIG_ULSCH_PDU_UNPACK_FNS(_pdu) \ + { NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG, &_pdu.ulsch_pdu_rel8, &unpack_ul_config_ulsch_pdu_rel8_value}, \ + { NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL10_TAG, &_pdu.ulsch_pdu_rel10, &unpack_ul_config_ulsch_pdu_rel10_value}, \ + { NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL11_TAG, &_pdu.ulsch_pdu_rel11, &unpack_ul_config_ulsch_pdu_rel11_value}, \ + { NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL13_TAG, &_pdu.ulsch_pdu_rel13, &unpack_ul_config_ulsch_pdu_rel13_value}, + + #define UL_CONFIG_CQI_RI_INFO_UNPACK_FNS(_pdu) \ + { NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL8_TAG, &_pdu.cqi_ri_information_rel8, &unpack_ul_config_cqi_ri_info_rel8_value}, \ + { NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL9_TAG, &_pdu.cqi_ri_information_rel9, &unpack_ul_config_cqi_ri_info_rel9_value}, \ + { NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL13_TAG, &_pdu.cqi_ri_information_rel13, &unpack_ul_config_cqi_ri_info_rel13_value}, + + #define UL_CONFIG_ULSCH_HARQ_INFO_UNPACK_FNS(_pdu) \ + { NFAPI_UL_CONFIG_REQUEST_ULSCH_HARQ_INFORMATION_REL10_TAG, &_pdu.harq_information_rel10, &unpack_ul_config_ulsch_harq_info_rel10_value},\ + { NFAPI_UL_CONFIG_REQUEST_ULSCH_HARQ_INFORMATION_REL13_TAG, &_pdu.harq_information_rel13, &unpack_ul_config_ulsch_harq_info_rel13_value}, + + #define UL_CONFIG_INIT_TX_PARAMS_UNPACK_FNS(_pdu) \ + { NFAPI_UL_CONFIG_REQUEST_INITIAL_TRANSMISSION_PARAMETERS_REL8_TAG, &_pdu.initial_transmission_parameters_rel8, &unpack_ul_config_cqi_init_tx_params_rel8_value}, + + #define UL_CONFIG_UCI_UE_INFO_UNPACK_FNS(_pdu) \ + { NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG, &_pdu.ue_information_rel8, &unpack_ul_config_ue_info_rel8_value}, \ + { NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL11_TAG, &_pdu.ue_information_rel11, &unpack_ul_config_ue_info_rel11_value}, \ + { NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL13_TAG, &_pdu.ue_information_rel13, &unpack_ul_config_ue_info_rel13_value}, + + #define UL_CONFIG_UCI_CQI_INFO_UNPACK_FNS(_pdu) \ + { NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG, &_pdu.cqi_information_rel8, &unpack_ul_config_cqi_info_rel8_value}, \ + { NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL10_TAG, &_pdu.cqi_information_rel10, &unpack_ul_config_cqi_info_rel10_value}, \ + { NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL13_TAG, &_pdu.cqi_information_rel13, &unpack_ul_config_cqi_info_rel13_value}, + + #define UL_CONFIG_UCI_SR_INFO_UNPACK_FNS(_pdu) \ + { NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL8_TAG, &_pdu.sr_information_rel8, &unpack_ul_config_sr_info_rel8_value}, \ + { NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL10_TAG, &_pdu.sr_information_rel10, &unpack_ul_config_sr_info_rel10_value}, + + #define UL_CONFIG_UCI_HARQ_INFO_UNPACK_FNS(_pdu) \ + { NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG, &_pdu.harq_information_rel10_tdd, &unpack_ul_config_harq_info_rel10_tdd_value}, \ + { NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL8_FDD_TAG, &_pdu.harq_information_rel8_fdd, &unpack_ul_config_harq_info_rel8_fdd_value}, \ + { NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG, &_pdu.harq_information_rel9_fdd, &unpack_ul_config_harq_info_rel9_fdd_value}, \ + { NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL11_TAG, &_pdu.harq_information_rel11, &unpack_ul_config_harq_info_rel11_value}, \ + { NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL13_TAG, &_pdu.harq_information_rel13, &unpack_ul_config_harq_info_rel13_value}, + + #define UL_CONFIG_SRS_PDU_UNPACK_FNS(_pdu) \ + { NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL8_TAG, &_pdu.srs_pdu_rel8, &unpack_ul_config_srs_pdu_rel8_value}, \ + { NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL10_TAG, &_pdu.srs_pdu_rel10, &unpack_ul_config_srs_pdu_rel10_value}, \ + { NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL13_TAG, &_pdu.srs_pdu_rel13, &unpack_ul_config_srs_pdu_rel13_value}, + + #define UL_CONFIG_NULSCH_PDU_UNPACK_FNS(_pdu) \ + { NFAPI_UL_CONFIG_REQUEST_NULSCH_PDU_REL13_TAG, &_pdu.nulsch_pdu_rel13, &unpack_ul_config_nulsch_pdu_rel13_value}, + + #define UL_CONFIG_NRACH_PDU_UNPACK_FNS(_pdu) \ + { NFAPI_UL_CONFIG_REQUEST_NRACH_PDU_REL13_TAG, &_pdu.nrach_pdu_rel13, &unpack_ul_config_nrach_pdu_rel13_value}, + + + nfapi_ul_config_request_body_t* value = (nfapi_ul_config_request_body_t*)tlv; + + if(!(pull8(ppReadPackedMsg, &value->number_of_pdus, end) && + pull8(ppReadPackedMsg, &value->rach_prach_frequency_resources, end) && + pull8(ppReadPackedMsg, &value->srs_present, end))) + return 0; + + if(value->number_of_pdus > NFAPI_UL_CONFIG_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of ul config pdus exceed maxium (count:%d max:%d)\n", __FUNCTION__, value->number_of_pdus, NFAPI_UL_CONFIG_MAX_PDU); + return 0; + } + + if(value->number_of_pdus > 0) + { + value->ul_config_pdu_list = (nfapi_ul_config_request_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_ul_config_request_pdu_t) * value->number_of_pdus, config); + + if(value->ul_config_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate ul config pdu list (count:%d)\n", __FUNCTION__, value->number_of_pdus); + return 0; + } + } + else + { + value->ul_config_pdu_list = 0; + } + + + uint16_t i; + uint16_t total_number_of_pdus = value->number_of_pdus; + for(i = 0; i < total_number_of_pdus; ++i) + { + nfapi_ul_config_request_pdu_t* pdu = &(value->ul_config_pdu_list[i]); + + if(!(pull8(ppReadPackedMsg, &pdu->pdu_type, end) && + pull8(ppReadPackedMsg, &pdu->pdu_size, end))) + return 0; + + uint8_t *packedPduEnd = (*ppReadPackedMsg) + pdu->pdu_size - 2; + + if(packedPduEnd > end) + { + // pdu end is past buffer end + return 0; + } + + switch(pdu->pdu_type) + { + case NFAPI_UL_CONFIG_ULSCH_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_ULSCH_PDU_UNPACK_FNS(pdu->ulsch_pdu) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + + case NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_ULSCH_PDU_UNPACK_FNS(pdu->ulsch_cqi_ri_pdu.ulsch_pdu) + UL_CONFIG_CQI_RI_INFO_UNPACK_FNS(pdu->ulsch_cqi_ri_pdu.cqi_ri_information) + UL_CONFIG_INIT_TX_PARAMS_UNPACK_FNS(pdu->ulsch_cqi_ri_pdu.initial_transmission_parameters) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_ULSCH_PDU_UNPACK_FNS(pdu->ulsch_harq_pdu.ulsch_pdu) + UL_CONFIG_ULSCH_HARQ_INFO_UNPACK_FNS(pdu->ulsch_harq_pdu.harq_information) + UL_CONFIG_INIT_TX_PARAMS_UNPACK_FNS(pdu->ulsch_harq_pdu.initial_transmission_parameters) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_ULSCH_PDU_UNPACK_FNS(pdu->ulsch_cqi_harq_ri_pdu.ulsch_pdu) + UL_CONFIG_CQI_RI_INFO_UNPACK_FNS(pdu->ulsch_cqi_harq_ri_pdu.cqi_ri_information) + UL_CONFIG_ULSCH_HARQ_INFO_UNPACK_FNS(pdu->ulsch_cqi_harq_ri_pdu.harq_information) + UL_CONFIG_INIT_TX_PARAMS_UNPACK_FNS(pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_UCI_UE_INFO_UNPACK_FNS(pdu->uci_cqi_pdu.ue_information) + UL_CONFIG_UCI_CQI_INFO_UNPACK_FNS(pdu->uci_cqi_pdu.cqi_information) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_UCI_UE_INFO_UNPACK_FNS(pdu->uci_sr_pdu.ue_information) + UL_CONFIG_UCI_SR_INFO_UNPACK_FNS(pdu->uci_sr_pdu.sr_information) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_UCI_UE_INFO_UNPACK_FNS(pdu->uci_harq_pdu.ue_information) + UL_CONFIG_UCI_HARQ_INFO_UNPACK_FNS(pdu->uci_harq_pdu.harq_information) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_UCI_UE_INFO_UNPACK_FNS(pdu->uci_sr_harq_pdu.ue_information) + UL_CONFIG_UCI_SR_INFO_UNPACK_FNS(pdu->uci_sr_harq_pdu.sr_information) + UL_CONFIG_UCI_HARQ_INFO_UNPACK_FNS(pdu->uci_sr_harq_pdu.harq_information) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_UCI_UE_INFO_UNPACK_FNS(pdu->uci_cqi_harq_pdu.ue_information) + UL_CONFIG_UCI_CQI_INFO_UNPACK_FNS(pdu->uci_cqi_harq_pdu.cqi_information) + UL_CONFIG_UCI_HARQ_INFO_UNPACK_FNS(pdu->uci_cqi_harq_pdu.harq_information) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_UCI_UE_INFO_UNPACK_FNS(pdu->uci_cqi_sr_pdu.ue_information) + UL_CONFIG_UCI_CQI_INFO_UNPACK_FNS(pdu->uci_cqi_sr_pdu.cqi_information) + UL_CONFIG_UCI_SR_INFO_UNPACK_FNS(pdu->uci_cqi_sr_pdu.sr_information) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_UCI_UE_INFO_UNPACK_FNS(pdu->uci_cqi_sr_harq_pdu.ue_information) + UL_CONFIG_UCI_CQI_INFO_UNPACK_FNS(pdu->uci_cqi_sr_harq_pdu.cqi_information) + UL_CONFIG_UCI_SR_INFO_UNPACK_FNS(pdu->uci_cqi_sr_harq_pdu.sr_information) + UL_CONFIG_UCI_HARQ_INFO_UNPACK_FNS(pdu->uci_cqi_sr_harq_pdu.harq_information) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_SRS_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_SRS_PDU_UNPACK_FNS(pdu->srs_pdu) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_HARQ_BUFFER_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_UCI_UE_INFO_UNPACK_FNS(pdu->harq_buffer_pdu.ue_information) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_ULSCH_PDU_UNPACK_FNS(pdu->ulsch_uci_csi_pdu.ulsch_pdu) + UL_CONFIG_UCI_CQI_INFO_UNPACK_FNS(pdu->ulsch_uci_csi_pdu.csi_information) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_ULSCH_PDU_UNPACK_FNS(pdu->ulsch_uci_harq_pdu.ulsch_pdu) + UL_CONFIG_UCI_HARQ_INFO_UNPACK_FNS(pdu->ulsch_uci_harq_pdu.harq_information) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_ULSCH_PDU_UNPACK_FNS(pdu->ulsch_csi_uci_harq_pdu.ulsch_pdu) + UL_CONFIG_UCI_CQI_INFO_UNPACK_FNS(pdu->ulsch_csi_uci_harq_pdu.csi_information) + UL_CONFIG_UCI_HARQ_INFO_UNPACK_FNS(pdu->ulsch_csi_uci_harq_pdu.harq_information) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_NULSCH_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_NULSCH_PDU_UNPACK_FNS(pdu->nulsch_pdu) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_UL_CONFIG_NRACH_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + UL_CONFIG_NRACH_PDU_UNPACK_FNS(pdu->nrach_pdu) + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + } + } + return 1; +} + + +static uint8_t unpack_ul_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_ul_config_request_t *pNfapiMsg = (nfapi_ul_config_request_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + { NFAPI_UL_CONFIG_REQUEST_BODY_TAG, &pNfapiMsg->ul_config_request_body, &unpack_ul_config_request_body_value}, + }; + + return (pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_hi_dci0_hi_pdu_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_hi_pdu_rel8_t* hi_pdu_rel8 = (nfapi_hi_dci0_hi_pdu_rel8_t*)tlv; + + return( pull8(ppReadPackedMsg, &hi_pdu_rel8->resource_block_start, end) && + pull8(ppReadPackedMsg, &hi_pdu_rel8->cyclic_shift_2_for_drms, end) && + pull8(ppReadPackedMsg, &hi_pdu_rel8->hi_value, end) && + pull8(ppReadPackedMsg, &hi_pdu_rel8->i_phich, end) && + pull16(ppReadPackedMsg, &hi_pdu_rel8->transmission_power, end)); +} + +static uint8_t unpack_hi_dci0_hi_pdu_rel10_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_hi_pdu_rel10_t* hi_pdu_rel10 = (nfapi_hi_dci0_hi_pdu_rel10_t*)tlv; + + return (pull8(ppReadPackedMsg, &hi_pdu_rel10->flag_tb2, end) && + pull8(ppReadPackedMsg, &hi_pdu_rel10->hi_value_2, end)); +} + +static uint8_t unpack_hi_dci0_dci_pdu_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_dci_pdu_rel8_t* dci_pdu_rel8 = (nfapi_hi_dci0_dci_pdu_rel8_t*)tlv; + + return (pull8(ppReadPackedMsg, &dci_pdu_rel8->dci_format, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel8->cce_index, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel8->aggregation_level, end) && + pull16(ppReadPackedMsg, &dci_pdu_rel8->rnti, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel8->resource_block_start, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel8->number_of_resource_block, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel8->mcs_1, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel8->cyclic_shift_2_for_drms, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel8->frequency_hopping_enabled_flag, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel8->frequency_hopping_bits, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel8->new_data_indication_1, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel8->ue_tx_antenna_seleciton, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel8->tpc, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel8->cqi_csi_request, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel8->ul_index, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel8->dl_assignment_index, end) && + pull32(ppReadPackedMsg, &dci_pdu_rel8->tpc_bitmap, end) && + pull16(ppReadPackedMsg, &dci_pdu_rel8->transmission_power, end)); +} + +static uint8_t unpack_hi_dci0_dci_pdu_rel10_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_dci_pdu_rel10_t* dci_pdu_rel10 = (nfapi_hi_dci0_dci_pdu_rel10_t*)tlv; + + return (pull8(ppReadPackedMsg, &dci_pdu_rel10->cross_carrier_scheduling_flag, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel10->carrier_indicator, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel10->size_of_cqi_csi_feild, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel10->srs_flag, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel10->srs_request, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel10->resource_allocation_flag, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel10->resource_allocation_type, end) && + pull32(ppReadPackedMsg, &dci_pdu_rel10->resource_block_coding, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel10->mcs_2, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel10->new_data_indication_2, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel10->number_of_antenna_ports, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel10->tpmi, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel10->total_dci_length_including_padding, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel10->n_ul_rb, end)); +} + +static uint8_t unpack_hi_dci0_dci_pdu_rel12_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_dci_pdu_rel12_t* dci_pdu_rel12 = (nfapi_hi_dci0_dci_pdu_rel12_t*)tlv; + + return ( pull8(ppReadPackedMsg, &dci_pdu_rel12->pscch_resource, end) && + pull8(ppReadPackedMsg, &dci_pdu_rel12->time_resource_pattern, end)); +} + +static uint8_t unpack_hi_dci0_mpdcch_dci_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_mpdcch_dci_pdu_rel13_t* value = (nfapi_hi_dci0_mpdcch_dci_pdu_rel13_t*)tlv; + + return (pull8(ppReadPackedMsg, &value->mpdcch_narrowband, end) && + pull8(ppReadPackedMsg, &value->number_of_prb_pairs, end) && + pull8(ppReadPackedMsg, &value->resource_block_assignment, end) && + pull8(ppReadPackedMsg, &value->mpdcch_transmission_type, end) && + pull8(ppReadPackedMsg, &value->start_symbol, end) && + pull8(ppReadPackedMsg, &value->ecce_index, end) && + pull8(ppReadPackedMsg, &value->aggreagation_level, end) && + pull8(ppReadPackedMsg, &value->rnti_type, end) && + pull16(ppReadPackedMsg, &value->rnti, end) && + pull8(ppReadPackedMsg, &value->ce_mode, end) && + pull16(ppReadPackedMsg, &value->drms_scrambling_init, end) && + pull16(ppReadPackedMsg, &value->initial_transmission_sf_io, end) && + pull16(ppReadPackedMsg, &value->transmission_power, end) && + pull8(ppReadPackedMsg, &value->dci_format, end) && + pull8(ppReadPackedMsg, &value->resource_block_start, end) && + pull8(ppReadPackedMsg, &value->number_of_resource_blocks, end) && + pull8(ppReadPackedMsg, &value->mcs, end) && + pull8(ppReadPackedMsg, &value->pusch_repetition_levels, end) && + pull8(ppReadPackedMsg, &value->frequency_hopping_flag, end) && + pull8(ppReadPackedMsg, &value->new_data_indication, end) && + pull8(ppReadPackedMsg, &value->harq_process, end) && + pull8(ppReadPackedMsg, &value->redudency_version, end) && + pull8(ppReadPackedMsg, &value->tpc, end) && + pull8(ppReadPackedMsg, &value->csi_request, end) && + pull8(ppReadPackedMsg, &value->ul_inex, end) && + pull8(ppReadPackedMsg, &value->dai_presence_flag, end) && + pull8(ppReadPackedMsg, &value->dl_assignment_index, end) && + pull8(ppReadPackedMsg, &value->srs_request, end) && + pull8(ppReadPackedMsg, &value->dci_subframe_repetition_number, end) && + pull32(ppReadPackedMsg, &value->tcp_bitmap, end) && + pull8(ppReadPackedMsg, &value->total_dci_length_include_padding, end) && + pull8(ppReadPackedMsg, &value->number_of_tx_antenna_ports, end) && + pullarray16(ppReadPackedMsg, value->precoding_value, NFAPI_MAX_TX_PHYSICAL_ANTENNA_PORTS, value->number_of_tx_antenna_ports, end)); +} + +static uint8_t unpack_hi_dci0_npdcch_dci_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_hi_dci0_npdcch_dci_pdu_rel13_t* value = (nfapi_hi_dci0_npdcch_dci_pdu_rel13_t*)tlv; + + return (pull8(ppReadPackedMsg, &value->ncce_index, end) && + pull8(ppReadPackedMsg, &value->aggregation_level, end) && + pull8(ppReadPackedMsg, &value->start_symbol, end) && + pull16(ppReadPackedMsg, &value->rnti, end) && + pull8(ppReadPackedMsg, &value->scrambling_reinitialization_batch_index, end) && + pull8(ppReadPackedMsg, &value->nrs_antenna_ports_assumed_by_the_ue, end) && + pull8(ppReadPackedMsg, &value->subcarrier_indication, end) && + pull8(ppReadPackedMsg, &value->resource_assignment, end) && + pull8(ppReadPackedMsg, &value->scheduling_delay, end) && + pull8(ppReadPackedMsg, &value->mcs, end) && + pull8(ppReadPackedMsg, &value->redudancy_version, end) && + pull8(ppReadPackedMsg, &value->repetition_number, end) && + pull8(ppReadPackedMsg, &value->new_data_indicator, end) && + pull8(ppReadPackedMsg, &value->dci_subframe_repetition_number, end)); +} + +static uint8_t unpack_hi_dci0_request_body_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_hi_dci0_request_body_t* value = (nfapi_hi_dci0_request_body_t*)tlv; + + if(!(pull16(ppReadPackedMsg, &value->sfnsf, end) && + pull8(ppReadPackedMsg, &value->number_of_dci, end) && + pull8(ppReadPackedMsg, &value->number_of_hi, end))) + return 0; + + uint8_t totalNumPdus = value->number_of_hi + value->number_of_dci; + + if(totalNumPdus > NFAPI_HI_DCI0_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of dci0 pdu's exceed maxium (count:%d max:%d)\n", __FUNCTION__, totalNumPdus, NFAPI_HI_DCI0_MAX_PDU); + return 0; + } + + if(totalNumPdus > 0) + { + value->hi_dci0_pdu_list = (nfapi_hi_dci0_request_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_hi_dci0_request_pdu_t) * totalNumPdus, config); + if(value->hi_dci0_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate hi dci0 pdu list (count:%d)\n", __FUNCTION__, totalNumPdus); + return 0; + } + } + else + { + value->hi_dci0_pdu_list = 0; + } + + uint8_t i; + for(i = 0; i < totalNumPdus; ++i) + { + nfapi_hi_dci0_request_pdu_t* pdu = &(value->hi_dci0_pdu_list[i]); + + if(!(pull8(ppReadPackedMsg, &pdu->pdu_type, end) && + pull8(ppReadPackedMsg, &pdu->pdu_size, end))) + return 0; + + uint8_t *packedPduEnd = (*ppReadPackedMsg) + pdu->pdu_size - 2; + + if(packedPduEnd > end) + { + // pdu end if past buffer end + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s pdu size to big %d %d\n", __FUNCTION__, packedPduEnd, end); + return 0; + } + + switch(pdu->pdu_type) + { + case NFAPI_HI_DCI0_HI_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_HI_DCI0_REQUEST_HI_PDU_REL8_TAG, &pdu->hi_pdu.hi_pdu_rel8, &unpack_hi_dci0_hi_pdu_rel8_value}, + { NFAPI_HI_DCI0_REQUEST_HI_PDU_REL10_TAG, &pdu->hi_pdu.hi_pdu_rel10, &unpack_hi_dci0_hi_pdu_rel10_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_HI_DCI0_DCI_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL8_TAG, &pdu->dci_pdu.dci_pdu_rel8, &unpack_hi_dci0_dci_pdu_rel8_value}, + { NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL10_TAG, &pdu->dci_pdu.dci_pdu_rel10, &unpack_hi_dci0_dci_pdu_rel10_value}, + { NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL12_TAG, &pdu->dci_pdu.dci_pdu_rel12, &unpack_hi_dci0_dci_pdu_rel12_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_HI_DCI0_EPDCCH_DCI_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_HI_DCI0_REQUEST_EPDCCH_DCI_PDU_REL8_TAG, &pdu->epdcch_dci_pdu.epdcch_dci_pdu_rel8, &unpack_hi_dci0_dci_pdu_rel8_value}, + { NFAPI_HI_DCI0_REQUEST_EPDCCH_DCI_PDU_REL10_TAG, &pdu->epdcch_dci_pdu.epdcch_dci_pdu_rel10, &unpack_hi_dci0_dci_pdu_rel10_value}, + { NFAPI_HI_DCI0_REQUEST_EPDCCH_PARAMETERS_REL11_TAG, &pdu->epdcch_dci_pdu.epdcch_parameters_rel11, &unpack_dl_config_epdcch_params_rel11_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_HI_DCI0_MPDCCH_DCI_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_HI_DCI0_REQUEST_MPDCCH_DCI_PDU_REL13_TAG, &pdu->mpdcch_dci_pdu.mpdcch_dci_pdu_rel13, &unpack_hi_dci0_mpdcch_dci_pdu_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_HI_DCI0_NPDCCH_DCI_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_HI_DCI0_REQUEST_NPDCCH_DCI_PDU_REL13_TAG, &pdu->npdcch_dci_pdu.npdcch_dci_pdu_rel13, &unpack_hi_dci0_npdcch_dci_pdu_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + default: + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "FIXME : Invalid pdu type %d \n", pdu->pdu_type ); + } + break; + }; + } + + return 1; +} + +static uint8_t unpack_hi_dci0_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_hi_dci0_request_t *pNfapiMsg = (nfapi_hi_dci0_request_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + { NFAPI_HI_DCI0_REQUEST_BODY_TAG, &pNfapiMsg->hi_dci0_request_body, &unpack_hi_dci0_request_body_value}, + }; + + return (pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); + +} + +static uint8_t unpack_tx_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + uint8_t proceed = 1; + nfapi_tx_request_t *pNfapiMsg = (nfapi_tx_request_t*)msg; + + if(pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) == 0) + return 0; + + while (((uint8_t*)(*ppReadPackedMsg) < end) && proceed) + { + nfapi_tl_t generic_tl; + if(unpack_tl(ppReadPackedMsg, &generic_tl, end) == 0) + return 0; + + switch(generic_tl.tag) + { + case NFAPI_TX_REQUEST_BODY_TAG: + { + pNfapiMsg->tx_request_body.tl = generic_tl; + + if( pull16(ppReadPackedMsg, &pNfapiMsg->tx_request_body.number_of_pdus, end) == 0) + return 0; + + if(pNfapiMsg->tx_request_body.number_of_pdus > NFAPI_TX_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of tx pdu's exceed maxium (count:%d max:%d)\n", __FUNCTION__, pNfapiMsg->tx_request_body.number_of_pdus, NFAPI_TX_MAX_PDU); + return 0; + } + + if(pNfapiMsg->tx_request_body.number_of_pdus > 0) + { + pNfapiMsg->tx_request_body.tx_pdu_list = (nfapi_tx_request_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_tx_request_pdu_t) * pNfapiMsg->tx_request_body.number_of_pdus, config); + if(pNfapiMsg->tx_request_body.tx_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate tx pdu list (count:%d)\n", __FUNCTION__, pNfapiMsg->tx_request_body.number_of_pdus); + return 0; + } + } + else + { + pNfapiMsg->tx_request_body.tx_pdu_list = 0; + } + + + uint16_t i; + uint16_t totalNumPdus = pNfapiMsg->tx_request_body.number_of_pdus; + for(i = 0; i < totalNumPdus; ++i) + { + nfapi_tx_request_pdu_t* pdu = &(pNfapiMsg->tx_request_body.tx_pdu_list[i]); + + uint16_t length = 0; + uint16_t index = 0; + + if(!(pull16(ppReadPackedMsg, &length, end) && + pull16(ppReadPackedMsg, &index, end))) + return 0; + + pdu->pdu_length = length; + pdu->pdu_index = index; + + + // TODO : May need to rethink this bit + pdu->num_segments = 1; + pdu->segments[0].segment_length = pdu->pdu_length; + pdu->segments[0].segment_data = nfapi_p7_allocate(pdu->pdu_length, config); + + if(pdu->segments[0].segment_data) + { + if(!pullarray8(ppReadPackedMsg, pdu->segments[0].segment_data, pdu->segments[0].segment_length, pdu->segments[0].segment_length, end)) + return 0; + if (0 && pdu->segments[0].segment_length == 3) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() BCH? segment_data:%x %x %x\n", __FUNCTION__, + pdu->segments[0].segment_data[0], + pdu->segments[0].segment_data[1], + pdu->segments[0].segment_data[2] + ); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "unpack_tx_request: Failed to allocate pdu (len:%d) %d/%d %d\n", pdu->pdu_length, totalNumPdus, i, pdu->pdu_index); + } + } + } + break; + default: + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "unpack_tx_request FIXME : Invalid pdu type %d \n", generic_tl.tag ); + } + break; + }; + } + + return 1; +} + +static uint8_t unpack_harq_indication_tdd_harq_data_bundling(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_harq_indication_tdd_harq_data_bundling_t* value = (nfapi_harq_indication_tdd_harq_data_bundling_t*)tlv; + + return (pull8(ppReadPackedMsg, &value->value_0, end) && + pull8(ppReadPackedMsg, &value->value_1, end)); +} + +static uint8_t unpack_harq_indication_tdd_harq_data_multiplexing(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_harq_indication_tdd_harq_data_multiplexing_t* value = (nfapi_harq_indication_tdd_harq_data_multiplexing_t*)tlv; + + return (pull8(ppReadPackedMsg, &value->value_0, end) && + pull8(ppReadPackedMsg, &value->value_1, end) && + pull8(ppReadPackedMsg, &value->value_2, end) && + pull8(ppReadPackedMsg, &value->value_3, end)); +} +static uint8_t unpack_harq_indication_tdd_harq_data_special_bundling(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_harq_indication_tdd_harq_data_special_bundling_t* value = (nfapi_harq_indication_tdd_harq_data_special_bundling_t*)tlv; + return ( pull8(ppReadPackedMsg, &value->value_0, end)); +} +static uint8_t unpack_harq_indication_tdd_harq_data(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_harq_indication_tdd_harq_data_t* value = (nfapi_harq_indication_tdd_harq_data_t*)tlv; + return (pull8(ppReadPackedMsg, &value->value_0, end)); +} + +static uint8_t unpack_harq_indication_tdd_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_harq_indication_tdd_rel8_t* value = (nfapi_harq_indication_tdd_rel8_t*)tlv; + + if(!(pull8(ppReadPackedMsg, &value->mode, end) && + pull8(ppReadPackedMsg, &value->number_of_ack_nack, end))) + return 0; + + uint8_t result = 0; + switch(value->mode) + { + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_BUNDLING: + result = unpack_harq_indication_tdd_harq_data_bundling(&value->harq_data.bundling, ppReadPackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_MULIPLEXING: + result = unpack_harq_indication_tdd_harq_data_multiplexing(&value->harq_data.multiplex, ppReadPackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_SPECIAL_BUNDLING: + result = unpack_harq_indication_tdd_harq_data_special_bundling(&value->harq_data.special_bundling, ppReadPackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_3: + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_CHANNEL_SELECTION: + result = 1; + break; + default: + // TODO add error message + return 0; + break; + } + return result; +} + +static uint8_t unpack_harq_indication_tdd_rel9_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_harq_indication_tdd_rel9_t* value = (nfapi_harq_indication_tdd_rel9_t*)tlv; + + if(!(pull8(ppReadPackedMsg, &value->mode, end) && + pull8(ppReadPackedMsg, &value->number_of_ack_nack, end))) + return 0; + + if(value->number_of_ack_nack > NFAPI_MAX_NUMBER_ACK_NACK_TDD) + { + // TODO : add error message + return 0; + } + + uint16_t idx = 0; + for(idx = 0; idx < value->number_of_ack_nack; ++idx) + { + uint8_t result = 0; + switch(value->mode) + { + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_BUNDLING: + result = unpack_harq_indication_tdd_harq_data(&value->harq_data[idx].bundling, ppReadPackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_MULIPLEXING: + result = unpack_harq_indication_tdd_harq_data(&value->harq_data[idx].multiplex, ppReadPackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_SPECIAL_BUNDLING: + result = unpack_harq_indication_tdd_harq_data_special_bundling(&value->harq_data[idx].special_bundling, ppReadPackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_CHANNEL_SELECTION: + result = unpack_harq_indication_tdd_harq_data(&value->harq_data[idx].channel_selection, ppReadPackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_3: + result = unpack_harq_indication_tdd_harq_data(&value->harq_data[idx].format_3, ppReadPackedMsg, end); + break; + default: + // TODO add error message + return 0; + break; + } + + if(result == 0) + return 0; + } + return 1; +} + +static uint8_t unpack_harq_indication_tdd_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_harq_indication_tdd_rel13_t* value = (nfapi_harq_indication_tdd_rel13_t*)tlv; + + if(!(pull8(ppReadPackedMsg, &value->mode, end) && + pull16(ppReadPackedMsg, &value->number_of_ack_nack, end))) + return 0; + + if(value->number_of_ack_nack > NFAPI_MAX_NUMBER_ACK_NACK_TDD) + { + // TODO : add error message + return 0; + } + + uint16_t idx = 0; + for(idx = 0; idx < value->number_of_ack_nack; ++idx) + { + uint8_t result = 0; + switch(value->mode) + { + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_BUNDLING: + result = unpack_harq_indication_tdd_harq_data(&value->harq_data[idx].bundling, ppReadPackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_MULIPLEXING: + result = unpack_harq_indication_tdd_harq_data(&value->harq_data[idx].multiplex, ppReadPackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_SPECIAL_BUNDLING: + result = unpack_harq_indication_tdd_harq_data_special_bundling(&value->harq_data[idx].special_bundling, ppReadPackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_CHANNEL_SELECTION: + result = unpack_harq_indication_tdd_harq_data(&value->harq_data[idx].channel_selection, ppReadPackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_3: + result = unpack_harq_indication_tdd_harq_data(&value->harq_data[idx].format_3, ppReadPackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_4: + result = unpack_harq_indication_tdd_harq_data(&value->harq_data[idx].format_4, ppReadPackedMsg, end); + break; + case NFAPI_HARQ_INDICATION_TDD_HARQ_ACK_NACK_FORMAT_FORMAT_5: + result = unpack_harq_indication_tdd_harq_data(&value->harq_data[idx].format_5, ppReadPackedMsg, end); + break; + default: + // TODO add error message + return 0; + break; + } + + if(result == 0) + return 0; + } + return 1; +} + +static uint8_t unpack_harq_indication_fdd_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_harq_indication_fdd_rel8_t* value = (nfapi_harq_indication_fdd_rel8_t*)tlv; + return (pull8(ppReadPackedMsg, &value->harq_tb1, end) && + pull8(ppReadPackedMsg, &value->harq_tb2, end)); +} + +static uint8_t unpack_harq_indication_fdd_rel9_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_harq_indication_fdd_rel9_t* value = (nfapi_harq_indication_fdd_rel9_t*)tlv; + + return (pull8(ppReadPackedMsg, &value->mode, end) && + pull8(ppReadPackedMsg, &value->number_of_ack_nack, end) && + pullarray8(ppReadPackedMsg, value->harq_tb_n, NFAPI_HARQ_ACK_NACK_REL9_MAX, value->number_of_ack_nack, end)); +} + +static uint8_t unpack_harq_indication_fdd_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_harq_indication_fdd_rel13_t* value = (nfapi_harq_indication_fdd_rel13_t*)tlv; + + return (pull8(ppReadPackedMsg, &value->mode, end) && + pull16(ppReadPackedMsg, &value->number_of_ack_nack, end) && + pullarray8(ppReadPackedMsg, value->harq_tb_n, NFAPI_HARQ_ACK_NACK_REL13_MAX, value->number_of_ack_nack, end)); +} + +static uint8_t unpack_ul_cqi_information_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_ul_cqi_information_t* value = (nfapi_ul_cqi_information_t*)tlv; + + return (pull8(ppReadPackedMsg, &value->ul_cqi, end) && + pull8(ppReadPackedMsg, &value->channel, end)); +} + + + +static uint8_t unpack_harq_indication_body_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_harq_indication_body_t* value = (nfapi_harq_indication_body_t*)tlv; + uint8_t* harqBodyEnd = *ppReadPackedMsg + value->tl.length; + + if(harqBodyEnd > end) + return 0; + + if(pull16(ppReadPackedMsg, &value->number_of_harqs, end) == 0) + return 0; + + if(value->number_of_harqs > NFAPI_HARQ_IND_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of harq ind pdus exceed maxium (count:%d max:%d)\n", __FUNCTION__, value->number_of_harqs, NFAPI_HARQ_IND_MAX_PDU); + return 0; + } + + value->harq_pdu_list = (nfapi_harq_indication_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_harq_indication_pdu_t) * value->number_of_harqs, config); + if(value->harq_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate harq ind pdu list (count:%d)\n", __FUNCTION__, value->number_of_harqs); + return 0; + } + + uint8_t i = 0; + for(i = 0; i < value->number_of_harqs; ++i) + { + nfapi_harq_indication_pdu_t* pdu = &(value->harq_pdu_list[i]); + if(pull16(ppReadPackedMsg, &pdu->instance_length, end) == 0) + return 0; + + uint8_t* harqPduInstanceEnd = *ppReadPackedMsg + pdu->instance_length; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_RX_UE_INFORMATION_TAG, &pdu->rx_ue_information, unpack_rx_ue_information_value }, + { NFAPI_HARQ_INDICATION_TDD_REL8_TAG, &pdu->harq_indication_tdd_rel8, &unpack_harq_indication_tdd_rel8_value}, + { NFAPI_HARQ_INDICATION_TDD_REL9_TAG, &pdu->harq_indication_tdd_rel9, &unpack_harq_indication_tdd_rel9_value}, + { NFAPI_HARQ_INDICATION_TDD_REL13_TAG, &pdu->harq_indication_tdd_rel13, &unpack_harq_indication_tdd_rel13_value}, + { NFAPI_HARQ_INDICATION_FDD_REL8_TAG, &pdu->harq_indication_fdd_rel8, &unpack_harq_indication_fdd_rel8_value}, + { NFAPI_HARQ_INDICATION_FDD_REL9_TAG, &pdu->harq_indication_fdd_rel9, &unpack_harq_indication_fdd_rel9_value}, + { NFAPI_HARQ_INDICATION_FDD_REL13_TAG, &pdu->harq_indication_fdd_rel13, &unpack_harq_indication_fdd_rel13_value}, + { NFAPI_UL_CQI_INFORMATION_TAG, &pdu->ul_cqi_information, &unpack_ul_cqi_information_value} + }; + + if(unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, harqPduInstanceEnd, 0, 0) == 0) + return 0; + + } + + return 1; +} + +static uint8_t unpack_harq_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_harq_indication_t *pNfapiMsg = (nfapi_harq_indication_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + { NFAPI_HARQ_INDICATION_BODY_TAG, &pNfapiMsg->harq_indication_body, &unpack_harq_indication_body_value}, + }; + + return (pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_crc_indication_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_crc_indication_rel8_t* crc_pdu_rel8 = (nfapi_crc_indication_rel8_t*)tlv; + return ( pull8(ppReadPackedMsg, &crc_pdu_rel8->crc_flag, end) ); +} + +static uint8_t unpack_crc_indication_body_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_crc_indication_body_t* value = (nfapi_crc_indication_body_t*)tlv; + uint8_t* crcBodyEnd = *ppReadPackedMsg + value->tl.length; + + if(crcBodyEnd > end) + return 0; + + if(pull16(ppReadPackedMsg, &value->number_of_crcs, end) == 0) + return 0; + + if(value->number_of_crcs > NFAPI_CRC_IND_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of crc ind pdu's exceed maxium (count:%d max:%d)\n", __FUNCTION__, value->number_of_crcs, NFAPI_CRC_IND_MAX_PDU); + return 0; + } + + if(value->number_of_crcs > 0) + { + value->crc_pdu_list = (nfapi_crc_indication_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_crc_indication_pdu_t) * value->number_of_crcs, config); + if(value->crc_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate crc ind pdu list (count:%d)\n", __FUNCTION__, value->number_of_crcs); + return 0; + } + } + else + { + value->crc_pdu_list = 0; + } + + + uint8_t i = 0; + for(i = 0; i < value->number_of_crcs; ++i) + { + nfapi_crc_indication_pdu_t* pdu = &(value->crc_pdu_list[i]); + + if(pull16(ppReadPackedMsg, &pdu->instance_length, end) == 0) + return 0; + + uint8_t* crcPduInstanceEnd = *ppReadPackedMsg + pdu->instance_length; + + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_RX_UE_INFORMATION_TAG, &pdu->rx_ue_information, unpack_rx_ue_information_value }, + { NFAPI_CRC_INDICATION_REL8_TAG, &pdu->crc_indication_rel8, unpack_crc_indication_rel8_value }, + }; + + if(unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, crcPduInstanceEnd, 0, 0) == 0) + return 0; + } + + return 1; +} + +static uint8_t unpack_crc_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_crc_indication_t *pNfapiMsg = (nfapi_crc_indication_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + { NFAPI_CRC_INDICATION_BODY_TAG, &pNfapiMsg->crc_indication_body, &unpack_crc_indication_body_value}, + }; + + return (pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_rx_indication_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_rx_indication_rel8_t* value = (nfapi_rx_indication_rel8_t*)tlv; + + return (pull16(ppReadPackedMsg, &value->length, end) && + pull16(ppReadPackedMsg, &value->offset, end) && + pull8(ppReadPackedMsg, &value->ul_cqi, end) && + pull16(ppReadPackedMsg, &value->timing_advance, end)); +} +static uint8_t unpack_rx_indication_rel9_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_rx_indication_rel9_t* value = (nfapi_rx_indication_rel9_t*)tlv; + return (pull16(ppReadPackedMsg, &value->timing_advance_r9, end)); +} + +static uint8_t unpack_rx_indication_body_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_rx_indication_body_t* value = (nfapi_rx_indication_body_t*)tlv; + + // the rxBodyEnd points to the end of the cqi PDU's + uint8_t* rxBodyEnd = *ppReadPackedMsg + value->tl.length; + uint8_t* rxPduEnd = rxBodyEnd; + + uint8_t* numberOfPdusAddress = *ppReadPackedMsg; + + if(rxBodyEnd > end) + { + // pdu end is past buffer end + return 0; + } + + if(pull16(ppReadPackedMsg, &value->number_of_pdus, end) == 0) + return 0; + + if(value->number_of_pdus > NFAPI_RX_IND_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of rx ind pdu's exceed maxium (count:%d max:%d)\n", __FUNCTION__, value->number_of_pdus, NFAPI_RX_IND_MAX_PDU); + return 0; + } + + if(value->number_of_pdus > 0) + { + value->rx_pdu_list = (nfapi_rx_indication_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_rx_indication_pdu_t) * value->number_of_pdus, config); + if(value->rx_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate rx ind pdu list (count:%d)\n", __FUNCTION__, value->number_of_pdus); + return 0; + } + } + else + { + value->rx_pdu_list = 0; + } + + uint8_t i = 0; + nfapi_rx_indication_pdu_t* pdu = 0; + while((uint8_t*)(*ppReadPackedMsg) < rxBodyEnd && (uint8_t*)(*ppReadPackedMsg) < rxPduEnd) + { + nfapi_tl_t generic_tl; + if( unpack_tl(ppReadPackedMsg, &generic_tl, end) == 0) + return 0; + + switch(generic_tl.tag) + { + case NFAPI_RX_UE_INFORMATION_TAG: + { + pdu = &(value->rx_pdu_list[i++]); + pdu->rx_ue_information.tl = generic_tl; + if(unpack_rx_ue_information_value(&pdu->rx_ue_information, ppReadPackedMsg, end) == 0) + return 0; + } + break; + case NFAPI_RX_INDICATION_REL8_TAG: + { + if(pdu != 0) + { + pdu->rx_indication_rel8.tl = generic_tl; + if(unpack_rx_indication_rel8_value(&pdu->rx_indication_rel8, ppReadPackedMsg, end) == 0) + return 0; + + if(pdu->rx_indication_rel8.offset > 0) + { + // Need to check that the data is within the tlv + if(numberOfPdusAddress + pdu->rx_indication_rel8.offset + pdu->rx_indication_rel8.length <= rxBodyEnd) + { + // If this the first pdu set the rxPduEnd + if(numberOfPdusAddress + pdu->rx_indication_rel8.offset < rxPduEnd) + { + rxPduEnd = numberOfPdusAddress + pdu->rx_indication_rel8.offset; + + if(rxPduEnd > end) + { + // pdu end is past buffer end + return 0; + } + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "FIXME: the rx data is outside of the tlv\n"); + } + } + } + } + break; + case NFAPI_RX_INDICATION_REL9_TAG: + { + if(pdu != 0) + { + pdu->rx_indication_rel9.tl = generic_tl; + if(unpack_rx_indication_rel9_value(&pdu->rx_indication_rel9, ppReadPackedMsg, end) == 0) + return 0; + } + } + break; + default: + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "RX_ULSCH.indication Invalid pdu type %d \n", generic_tl.tag ); + } + break; + } + } + + uint8_t idx = 0; + for(idx = 0; idx < value->number_of_pdus; ++idx) + { + if(value->rx_pdu_list[idx].rx_indication_rel8.tl.tag == NFAPI_RX_INDICATION_REL8_TAG) + { + uint32_t length = value->rx_pdu_list[idx].rx_indication_rel8.length; + value->rx_pdu_list[idx].data = nfapi_p7_allocate(length, config); + if(pullarray8(ppReadPackedMsg, value->rx_pdu_list[idx].data, length, length, end) == 0) + { + return 0; + } + } + } + + return 1; +} + +static uint8_t unpack_rx_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_rx_indication_t *pNfapiMsg = (nfapi_rx_indication_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + { NFAPI_RX_INDICATION_BODY_TAG, &pNfapiMsg->rx_indication_body, &unpack_rx_indication_body_value}, + }; + + return (pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_preamble_pdu_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_preamble_pdu_rel8_t* preamble_pdu_rel8 = (nfapi_preamble_pdu_rel8_t*)tlv; + + return (pull16(ppReadPackedMsg, &preamble_pdu_rel8->rnti, end) && + pull8(ppReadPackedMsg, &preamble_pdu_rel8->preamble, end) && + pull16(ppReadPackedMsg, &preamble_pdu_rel8->timing_advance, end)); +} + +static uint8_t unpack_preamble_pdu_rel9_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_preamble_pdu_rel9_t* preamble_pdu_rel9 = (nfapi_preamble_pdu_rel9_t*)tlv; + return pull16(ppReadPackedMsg, &preamble_pdu_rel9->timing_advance_r9, end); +} + +static uint8_t unpack_preamble_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_preamble_pdu_rel13_t* preamble_pdu_rel13 = (nfapi_preamble_pdu_rel13_t*)tlv; + return pull8(ppReadPackedMsg, &preamble_pdu_rel13->rach_resource_type, end); +} + +static uint8_t unpack_rach_indication_body_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_rach_indication_body_t* value = (nfapi_rach_indication_body_t*)tlv; + uint8_t* rachBodyEnd = *ppReadPackedMsg + value->tl.length; + + if(rachBodyEnd > end) + return 0; + + if(pull16(ppReadPackedMsg, &value->number_of_preambles, end) == 0) + return 0; + + if(value->number_of_preambles > NFAPI_PREAMBLE_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of preamble du's exceed maxium (count:%d max:%d)\n", __FUNCTION__, value->number_of_preambles, NFAPI_PREAMBLE_MAX_PDU); + return 0; + } + + if(value->number_of_preambles > 0) + { + value->preamble_list = (nfapi_preamble_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_preamble_pdu_t) * value->number_of_preambles, config); + if(value->preamble_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate preamble pdu list (count:%d)\n", __FUNCTION__, value->number_of_preambles); + return 0; + } + } + else + { + value->preamble_list = 0; + } + + + uint8_t i = 0; + for(i = 0; i < value->number_of_preambles; ++i) + { + nfapi_preamble_pdu_t* pdu = &(value->preamble_list[i]); + + if(pull16(ppReadPackedMsg, &pdu->instance_length, end) == 0) + return 0; + + uint8_t* preamblePduInstanceEnd = *ppReadPackedMsg + pdu->instance_length; + + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_PREAMBLE_REL8_TAG, &pdu->preamble_rel8, unpack_preamble_pdu_rel8_value }, + { NFAPI_PREAMBLE_REL9_TAG, &pdu->preamble_rel9, unpack_preamble_pdu_rel9_value }, + { NFAPI_PREAMBLE_REL13_TAG, &pdu->preamble_rel13, unpack_preamble_pdu_rel13_value }, + }; + + if(unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, preamblePduInstanceEnd, 0, 0) == 0) + return 0; + } + return 1; +} + +static uint8_t unpack_rach_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_rach_indication_t *pNfapiMsg = (nfapi_rach_indication_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + { NFAPI_RACH_INDICATION_BODY_TAG, &pNfapiMsg->rach_indication_body, &unpack_rach_indication_body_value}, + }; + + return (pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_srs_indication_fdd_rel8_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_srs_indication_fdd_rel8_t* srs_pdu_fdd_rel8 = (nfapi_srs_indication_fdd_rel8_t*)tlv; + + if(!(pull16(ppReadPackedMsg, &srs_pdu_fdd_rel8->doppler_estimation, end) && + pull16(ppReadPackedMsg, &srs_pdu_fdd_rel8->timing_advance, end) && + pull8(ppReadPackedMsg, &srs_pdu_fdd_rel8->number_of_resource_blocks, end) && + pull8(ppReadPackedMsg, &srs_pdu_fdd_rel8->rb_start, end) && + pullarray8(ppReadPackedMsg, srs_pdu_fdd_rel8->snr, NFAPI_NUM_RB_MAX, srs_pdu_fdd_rel8->number_of_resource_blocks, end))) + return 0; + return 1; +} + +static uint8_t unpack_srs_indication_fdd_rel9_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_srs_indication_fdd_rel9_t* srs_pdu_fdd_rel9 = (nfapi_srs_indication_fdd_rel9_t*)tlv; + return (pull16(ppReadPackedMsg, &srs_pdu_fdd_rel9->timing_advance_r9, end)); +} + +static uint8_t unpack_srs_indication_tdd_rel10_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_srs_indication_ttd_rel10_t* srs_pdu_tdd_rel10 = (nfapi_srs_indication_ttd_rel10_t*)tlv; + return (pull8(ppReadPackedMsg, &srs_pdu_tdd_rel10->uppts_symbol, end)); +} + +static uint8_t unpack_srs_indication_fdd_rel11_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_srs_indication_fdd_rel11_t* srs_pdu_fdd_rel11 = (nfapi_srs_indication_fdd_rel11_t*)tlv; + return ( pull16(ppReadPackedMsg, &srs_pdu_fdd_rel11->ul_rtoa, end)); +} + +static uint8_t unpack_tdd_channel_measurement_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_tdd_channel_measurement_t* value = (nfapi_tdd_channel_measurement_t*)tlv; + + if(!(pull8(ppReadPackedMsg, &value->num_prb_per_subband, end) && + pull8(ppReadPackedMsg, &value->number_of_subbands, end) && + pull8(ppReadPackedMsg, &value->num_atennas, end))) + return 0; + + if(value->number_of_subbands > NFAPI_MAX_NUM_SUBBANDS) + { + // todo : add error + return 0; + } + + if(value->num_atennas > NFAPI_MAX_NUM_PHYSICAL_ANTENNAS) + { + // todo : add error + return 0; + } + + uint8_t idx = 0; + for(idx = 0; idx < value->number_of_subbands; ++idx) + { + if(!(pull8(ppReadPackedMsg, &value->subands[idx].subband_index, end) && + pullarray16(ppReadPackedMsg, value->subands[idx].channel, NFAPI_MAX_NUM_PHYSICAL_ANTENNAS, value->num_atennas, end))) + return 0; + } + + return 1; +} + + +static uint8_t unpack_srs_indication_body_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_srs_indication_body_t* value = (nfapi_srs_indication_body_t*)tlv; + uint8_t* srsBodyEnd = *ppReadPackedMsg + value->tl.length; + + if(srsBodyEnd > end) + return 0; + + if(pull8(ppReadPackedMsg, &value->number_of_ues, end) == 0) + return 0; + + if(value->number_of_ues > NFAPI_SRS_IND_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of srs ind pdu's exceed maxium (count:%d max:%d)\n", __FUNCTION__, value->number_of_ues, NFAPI_SRS_IND_MAX_PDU); + return 0; + } + + if(value->number_of_ues > 0) + { + value->srs_pdu_list = (nfapi_srs_indication_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_srs_indication_pdu_t) * value->number_of_ues, config); + if(value->srs_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate srs ind pdu list (count:%d)\n", __FUNCTION__, value->number_of_ues); + return 0; + } + } + else + { + value->srs_pdu_list = 0; + } + + + + uint8_t i = 0; + for(i = 0; i < value->number_of_ues; ++i) + { + nfapi_srs_indication_pdu_t* pdu = &(value->srs_pdu_list[i]); + + + if(pull16(ppReadPackedMsg, &pdu->instance_length, end) == 0) + return 0; + + uint8_t* srsPduInstanceEnd = *ppReadPackedMsg + pdu->instance_length; + + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_RX_UE_INFORMATION_TAG, &pdu->rx_ue_information, unpack_rx_ue_information_value }, + { NFAPI_SRS_INDICATION_FDD_REL8_TAG, &pdu->srs_indication_fdd_rel8, unpack_srs_indication_fdd_rel8_value}, + { NFAPI_SRS_INDICATION_FDD_REL9_TAG, &pdu->srs_indication_fdd_rel9, unpack_srs_indication_fdd_rel9_value}, + { NFAPI_SRS_INDICATION_TDD_REL10_TAG, &pdu->srs_indication_tdd_rel10, unpack_srs_indication_tdd_rel10_value}, + { NFAPI_SRS_INDICATION_FDD_REL11_TAG, &pdu->srs_indication_fdd_rel11, unpack_srs_indication_fdd_rel11_value}, + { NFAPI_TDD_CHANNEL_MEASUREMENT_TAG, &pdu->tdd_channel_measurement, unpack_tdd_channel_measurement_value}, + }; + + if(unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, srsPduInstanceEnd, 0, 0) == 0) + return 0; + } + return 1; +} + +static uint8_t unpack_srs_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_srs_indication_t *pNfapiMsg = (nfapi_srs_indication_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + { NFAPI_SRS_INDICATION_BODY_TAG, &pNfapiMsg->srs_indication_body, &unpack_srs_indication_body_value}, + }; + + return (pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + + +static uint8_t unpack_sr_indication_body_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_sr_indication_body_t* value = (nfapi_sr_indication_body_t*)tlv; + uint8_t* srBodyEnd = *ppReadPackedMsg + value->tl.length; + + if(srBodyEnd > end) + return 0; + + if(pull16(ppReadPackedMsg, &value->number_of_srs, end) == 0) + return 0; + + if(value->number_of_srs > NFAPI_SR_IND_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of sr ind pdu's exceed maxium (count:%d max:%d)\n", __FUNCTION__, value->number_of_srs, NFAPI_SR_IND_MAX_PDU); + return 0; + } + + if(value->number_of_srs > 0) + { + value->sr_pdu_list = (nfapi_sr_indication_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_sr_indication_pdu_t) * value->number_of_srs, config); + if(value->sr_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate sr ind pdu list (count:%d)\n", __FUNCTION__, value->number_of_srs); + return 0; + } + } + else + { + value->sr_pdu_list = 0; + } + + uint8_t i = 0; + for(i = 0; i < value->number_of_srs; ++i) + { + nfapi_sr_indication_pdu_t* pdu = &(value->sr_pdu_list[i]); + + if(pull16(ppReadPackedMsg, &pdu->instance_length, end) == 0) + return 0; + + uint8_t* srPduInstanceEnd = *ppReadPackedMsg + pdu->instance_length; + + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_RX_UE_INFORMATION_TAG, &pdu->rx_ue_information, unpack_rx_ue_information_value }, + { NFAPI_UL_CQI_INFORMATION_TAG, &pdu->ul_cqi_information, unpack_ul_cqi_information_value }, + }; + + if(unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, srPduInstanceEnd, 0, 0) == 0) + return 0; + } + + return 1; + +} + +static int unpack_sr_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_sr_indication_t *pNfapiMsg = (nfapi_sr_indication_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + { NFAPI_SR_INDICATION_BODY_TAG, &pNfapiMsg->sr_indication_body, &unpack_sr_indication_body_value}, + }; + + return (pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} +static uint8_t unpack_cqi_indication_rel8_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_cqi_indication_rel8_t* cqi_pdu_rel8 = (nfapi_cqi_indication_rel8_t*)tlv; + + return (pull16(ppReadPackedMsg, &cqi_pdu_rel8->length, end) && + pull16(ppReadPackedMsg, &cqi_pdu_rel8->data_offset, end) && + pull8(ppReadPackedMsg, &cqi_pdu_rel8->ul_cqi, end) && + pull8(ppReadPackedMsg, &cqi_pdu_rel8->ri, end) && + pull16(ppReadPackedMsg, &cqi_pdu_rel8->timing_advance, end)); + +} + +static uint8_t unpack_cqi_indication_rel9_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_cqi_indication_rel9_t* cqi_pdu_rel9 = (nfapi_cqi_indication_rel9_t*)tlv; + + if(!(pull16(ppReadPackedMsg, &cqi_pdu_rel9->length, end) && + pull16(ppReadPackedMsg, &cqi_pdu_rel9->data_offset, end) && + pull8(ppReadPackedMsg, &cqi_pdu_rel9->ul_cqi, end) && + pull8(ppReadPackedMsg, &cqi_pdu_rel9->number_of_cc_reported, end))) + return 0; + + if(cqi_pdu_rel9->number_of_cc_reported > NFAPI_CC_MAX) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "FIXME : out of bound array\n"); + return 0; + } + + if(!(pullarray8(ppReadPackedMsg, cqi_pdu_rel9->ri, NFAPI_CC_MAX, cqi_pdu_rel9->number_of_cc_reported, end) && + pull16(ppReadPackedMsg, &cqi_pdu_rel9->timing_advance, end) && + pull16(ppReadPackedMsg, &cqi_pdu_rel9->timing_advance_r9, end))) + return 0; + + return 1; +} + +static uint8_t unpack_cqi_indication_body_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_cqi_indication_body_t* value = (nfapi_cqi_indication_body_t*)tlv; + + // the cqiBodyEnd points to the end of the cqi PDU's + uint8_t* cqiBodyEnd = *ppReadPackedMsg + value->tl.length; + + //uint8_t* cqiPduEnd = cqiBodyEnd; + //uint8_t* numberOfPdusAddress = *ppReadPackedMsg; + + if(cqiBodyEnd > end) + return 0; + + if(pull16(ppReadPackedMsg, &value->number_of_cqis, end) == 0) + return 0; + + if(value->number_of_cqis > NFAPI_CQI_IND_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of cqi ind pdu's exceed maxium (count:%d max:%d)\n", __FUNCTION__, value->number_of_cqis, NFAPI_CQI_IND_MAX_PDU); + return -1; + } + + if(value->number_of_cqis > 0) + { + value->cqi_pdu_list = (nfapi_cqi_indication_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_cqi_indication_pdu_t) * value->number_of_cqis, config); + if(value->cqi_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate cqi ind pdu list (count:%d)\n", __FUNCTION__, value->number_of_cqis); + return 0; + } + } + else + { + value->cqi_pdu_list = 0; + } + + if(value->number_of_cqis > 0) + { + value->cqi_raw_pdu_list = (nfapi_cqi_indication_raw_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_cqi_indication_raw_pdu_t) * value->number_of_cqis, config); + if(value->cqi_raw_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate raw cqi ind pdu list (count:%d)\n", __FUNCTION__, value->number_of_cqis); + return 0; + } + } + else + { + value->cqi_raw_pdu_list = 0; + } + + uint8_t i = 0; + for(i = 0; i < value->number_of_cqis; ++i) + { + nfapi_cqi_indication_pdu_t* pdu = &(value->cqi_pdu_list[i]); + memset(pdu, 0, sizeof(nfapi_cqi_indication_pdu_t)); + + if(pull16(ppReadPackedMsg, &pdu->instance_length, end) == 0) + return 0; + + uint8_t* cqiPduInstanceEnd = *ppReadPackedMsg + pdu->instance_length; + + + while((uint8_t*)(*ppReadPackedMsg) < cqiPduInstanceEnd) + { + nfapi_tl_t generic_tl; + if(unpack_tl(ppReadPackedMsg, &generic_tl, end) == 0) + return 0; + + switch(generic_tl.tag) + { + case NFAPI_RX_UE_INFORMATION_TAG: + pdu->rx_ue_information.tl = generic_tl; + if(unpack_rx_ue_information_value(&pdu->rx_ue_information, ppReadPackedMsg, end) == 0) + return 0; + break; + case NFAPI_CQI_INDICATION_REL8_TAG: + pdu->cqi_indication_rel8.tl = generic_tl; + if(unpack_cqi_indication_rel8_value(&pdu->cqi_indication_rel8, ppReadPackedMsg, end) == 0) + return 0; + + break; + case NFAPI_CQI_INDICATION_REL9_TAG: + pdu->cqi_indication_rel9.tl = generic_tl; + if(unpack_cqi_indication_rel9_value(&pdu->cqi_indication_rel9, ppReadPackedMsg, end) == 0) + return 0; + + break; + case NFAPI_UL_CQI_INFORMATION_TAG: + pdu->ul_cqi_information.tl = generic_tl; + if(unpack_ul_cqi_information_value(&pdu->ul_cqi_information, ppReadPackedMsg, end) == 0) + return 0; + break; + default: + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "RX_CQI.indication Invalid pdu type %d \n", generic_tl.tag ); + } + break; + + }; + } + } + + uint8_t idx = 0; + for(idx = 0; idx < value->number_of_cqis; ++idx) + { + if(value->cqi_pdu_list[idx].cqi_indication_rel8.tl.tag == NFAPI_CQI_INDICATION_REL8_TAG) + { + if(pullarray8(ppReadPackedMsg, &(value->cqi_raw_pdu_list[idx].pdu[0]), NFAPI_CQI_RAW_MAX_LEN, value->cqi_pdu_list[idx].cqi_indication_rel8.length, end) == 0) + return 0; + } + else if(value->cqi_pdu_list[idx].cqi_indication_rel9.tl.tag == NFAPI_CQI_INDICATION_REL9_TAG) + { + if(pullarray8(ppReadPackedMsg, &(value->cqi_raw_pdu_list[idx].pdu[0]), NFAPI_CQI_RAW_MAX_LEN, value->cqi_pdu_list[idx].cqi_indication_rel9.length, end) == 0) + return 0; + } + } + + + return 1; + +} + +static uint8_t unpack_cqi_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_cqi_indication_t *pNfapiMsg = (nfapi_cqi_indication_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + { NFAPI_CQI_INDICATION_BODY_TAG, &pNfapiMsg->cqi_indication_body, &unpack_cqi_indication_body_value}, + }; + + return (pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} +static uint8_t unpack_lbt_pdsch_req_pdu_rel13_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_lbt_pdsch_req_pdu_rel13_t* value = (nfapi_lbt_pdsch_req_pdu_rel13_t*)tlv; + + return (pull32(ppReadPackedMsg, &value->handle, end) && + pull32(ppReadPackedMsg, &value->mp_cca, end) && + pull32(ppReadPackedMsg, &value->n_cca, end) && + pull32(ppReadPackedMsg, &value->offset, end) && + pull32(ppReadPackedMsg, &value->lte_txop_sf, end) && + pull16(ppReadPackedMsg, &value->txop_sfn_sf_end, end) && + pull32(ppReadPackedMsg, &value->lbt_mode, end)); +} + +static uint8_t unpack_lbt_drs_req_pdu_rel13_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_lbt_drs_req_pdu_rel13_t* value = (nfapi_lbt_drs_req_pdu_rel13_t*)tlv; + + return (pull32(ppReadPackedMsg, &value->handle, end) && + pull32(ppReadPackedMsg, &value->offset, end) && + pull16(ppReadPackedMsg, &value->sfn_sf_end, end) && + pull32(ppReadPackedMsg, &value->lbt_mode, end)); +} + + +static uint8_t unpack_lbt_config_request_body_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_lbt_dl_config_request_body_t* value = (nfapi_lbt_dl_config_request_body_t*)tlv; + + if(pull16(ppReadPackedMsg, &value->number_of_pdus, end) == 0) + return 0; + + if(value->number_of_pdus > NFAPI_LBT_DL_CONFIG_REQ_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of lbt dl config pdu's exceed maxium (count:%d max:%d)\n", __FUNCTION__, value->number_of_pdus, NFAPI_LBT_DL_CONFIG_REQ_MAX_PDU); + return 0; + } + + if(value->number_of_pdus) + { + value->lbt_dl_config_req_pdu_list = (nfapi_lbt_dl_config_request_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_lbt_dl_config_request_pdu_t) * value->number_of_pdus, config); + if(value->lbt_dl_config_req_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate lbt dl config pdu list (count:%d)\n", __FUNCTION__, value->number_of_pdus); + return 0; + } + } + else + { + value->lbt_dl_config_req_pdu_list = 0; + } + + + uint16_t i; + uint16_t total_number_of_pdus = value->number_of_pdus; + for(i = 0; i < total_number_of_pdus; ++i) + { + nfapi_lbt_dl_config_request_pdu_t* pdu = &(value->lbt_dl_config_req_pdu_list[i]); + + if(!(pull8(ppReadPackedMsg, &pdu->pdu_type, end) && + pull8(ppReadPackedMsg, &pdu->pdu_size, end))) + return 0; + + uint8_t *packedPduEnd = (*ppReadPackedMsg) + pdu->pdu_size - 2; + + if(packedPduEnd > end) + return 0; + + switch(pdu->pdu_type) + { + case NFAPI_LBT_DL_CONFIG_REQUEST_PDSCH_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_LBT_PDSCH_REQ_PDU_REL13_TAG, &pdu->lbt_pdsch_req_pdu.lbt_pdsch_req_pdu_rel13, &unpack_lbt_pdsch_req_pdu_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_LBT_DL_CONFIG_REQUEST_DRS_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_LBT_DRS_REQ_PDU_REL13_TAG, &pdu->lbt_drs_req_pdu.lbt_drs_req_pdu_rel13, &unpack_lbt_drs_req_pdu_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + default: + NFAPI_TRACE(NFAPI_TRACE_ERROR, "LBT_DL_CONFIG.request body invalid pdu type %d\n", pdu->pdu_type); + return 0; + } + } + + return 1; +} +static uint8_t unpack_lbt_dl_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_lbt_dl_config_request_t *pNfapiMsg = (nfapi_lbt_dl_config_request_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + { NFAPI_LBT_DL_CONFIG_REQUEST_BODY_TAG, &pNfapiMsg->lbt_dl_config_request_body, &unpack_lbt_config_request_body_value}, + }; + + return (pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_lbt_pdsch_rsp_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_lbt_pdsch_rsp_pdu_rel13_t* value = (nfapi_lbt_pdsch_rsp_pdu_rel13_t*)tlv; + + return (pull32(ppReadPackedMsg, &value->handle, end) && + pull32(ppReadPackedMsg, &value->result, end) && + pull32(ppReadPackedMsg, &value->lte_txop_symbols, end) && + pull32(ppReadPackedMsg, &value->initial_partial_sf, end)); + +} +static uint8_t unpack_lbt_drs_rsp_pdu_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_lbt_drs_rsp_pdu_rel13_t* value = (nfapi_lbt_drs_rsp_pdu_rel13_t*)tlv; + + return (pull32(ppReadPackedMsg, &value->handle, end) && + pull32(ppReadPackedMsg, &value->result, end)); +} + +static uint8_t unpack_lbt_indication_body_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_lbt_dl_indication_body_t* value = (nfapi_lbt_dl_indication_body_t*)tlv; + + if(pull16(ppReadPackedMsg, &value->number_of_pdus, end) == 0) + return 0; + + if(value->number_of_pdus > NFAPI_LBT_IND_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of lbt dl ind pdu's exceed maxium (count:%d max:%d)\n", __FUNCTION__, value->number_of_pdus, NFAPI_LBT_IND_MAX_PDU); + return 0; + } + + if(value->number_of_pdus > 0) + { + value->lbt_indication_pdu_list = (nfapi_lbt_dl_indication_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_lbt_dl_indication_pdu_t) * value->number_of_pdus, config); + if(value->lbt_indication_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate lbt dl ind config pdu list (count:%d)\n", __FUNCTION__, value->number_of_pdus); + return 0; + } + } + else + { + value->lbt_indication_pdu_list = 0; + } + + uint16_t i; + uint16_t total_number_of_pdus = value->number_of_pdus; + for(i = 0; i < total_number_of_pdus; ++i) + { + nfapi_lbt_dl_indication_pdu_t* pdu = &(value->lbt_indication_pdu_list[i]); + + if(!(pull8(ppReadPackedMsg, &pdu->pdu_type, end) && + pull8(ppReadPackedMsg, &pdu->pdu_size, end))) + return 0; + + uint8_t *packedPduEnd = (*ppReadPackedMsg) + pdu->pdu_size - 2; + + if(packedPduEnd > end) + return 0; + + switch(pdu->pdu_type) + { + case NFAPI_LBT_DL_RSP_PDSCH_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_LBT_PDSCH_RSP_PDU_REL13_TAG, &pdu->lbt_pdsch_rsp_pdu.lbt_pdsch_rsp_pdu_rel13, &unpack_lbt_pdsch_rsp_pdu_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + case NFAPI_LBT_DL_RSP_DRS_PDU_TYPE: + { + unpack_tlv_t unpack_fns[] = + { + { NFAPI_LBT_DRS_RSP_PDU_REL13_TAG, &pdu->lbt_drs_rsp_pdu.lbt_drs_rsp_pdu_rel13, &unpack_lbt_drs_rsp_pdu_rel13_value}, + }; + + unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, packedPduEnd, 0, 0); + } + break; + default: + NFAPI_TRACE(NFAPI_TRACE_ERROR, "LBT_DL.indication body invalid pdu type %d\n", pdu->pdu_type); + return 0; + } + } + + return 1; +} +static uint8_t unpack_lbt_dl_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_lbt_dl_indication_t *pNfapiMsg = (nfapi_lbt_dl_indication_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + { NFAPI_LBT_DL_INDICATION_BODY_TAG, &pNfapiMsg->lbt_dl_indication_body, &unpack_lbt_indication_body_value}, + }; + + return (pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_nb_harq_indication_fdd_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nb_harq_indication_fdd_rel13_t* value = (nfapi_nb_harq_indication_fdd_rel13_t*)tlv; + return (pull8(ppReadPackedMsg, &value->harq_tb1, end)); +} + + +static uint8_t unpack_nb_harq_indication_body_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_nb_harq_indication_body_t* value = (nfapi_nb_harq_indication_body_t*)tlv; + uint8_t* nbharqBodyEnd = *ppReadPackedMsg + value->tl.length; + + if(nbharqBodyEnd > end) + return 0; + + if(pull16(ppReadPackedMsg, &value->number_of_harqs, end) == 0) + return 0; + + if(value->number_of_harqs > NFAPI_HARQ_IND_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of harq ind pdus exceed maxium (count:%d max:%d)\n", __FUNCTION__, value->number_of_harqs, NFAPI_HARQ_IND_MAX_PDU); + return 0; + } + + value->nb_harq_pdu_list = (nfapi_nb_harq_indication_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_nb_harq_indication_pdu_t) * value->number_of_harqs, config); + if(value->nb_harq_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate harq ind pdu list (count:%d)\n", __FUNCTION__, value->number_of_harqs); + return 0; + } + + uint8_t i = 0; + for(i = 0; i < value->number_of_harqs; ++i) + { + nfapi_nb_harq_indication_pdu_t* pdu = &(value->nb_harq_pdu_list[i]); + if(pull16(ppReadPackedMsg, &pdu->instance_length, end) == 0) + return 0; + + uint8_t* harqPduInstanceEnd = *ppReadPackedMsg + pdu->instance_length; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_RX_UE_INFORMATION_TAG, &pdu->rx_ue_information, unpack_rx_ue_information_value }, + { NFAPI_NB_HARQ_INDICATION_FDD_REL13_TAG, &pdu->nb_harq_indication_fdd_rel13, &unpack_nb_harq_indication_fdd_rel13_value}, + { NFAPI_UL_CQI_INFORMATION_TAG, &pdu->ul_cqi_information, &unpack_ul_cqi_information_value} + }; + + if(unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, harqPduInstanceEnd, 0, 0) == 0) + return 0; + + } + + return 1; +} + +static uint8_t unpack_nb_harq_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_nb_harq_indication_t *pNfapiMsg = (nfapi_nb_harq_indication_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + { NFAPI_NB_HARQ_INDICATION_BODY_TAG, &pNfapiMsg->nb_harq_indication_body, &unpack_nb_harq_indication_body_value}, + }; + + return (pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_nrach_indication_rel13_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nrach_indication_pdu_rel13_t* value = (nfapi_nrach_indication_pdu_rel13_t*)tlv; + + return (pull16(ppReadPackedMsg, &value->rnti, end) && + pull8(ppReadPackedMsg, &value->initial_sc, end) && + pull16(ppReadPackedMsg, &value->timing_advance, end) && + pull8(ppReadPackedMsg, &value->nrach_ce_level, end)); +} + + +static uint8_t unpack_nrach_indication_body_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + nfapi_nrach_indication_body_t* value = (nfapi_nrach_indication_body_t*)tlv; + uint8_t* nrachBodyEnd = *ppReadPackedMsg + value->tl.length; + + if(nrachBodyEnd > end) + return 0; + + if(pull8(ppReadPackedMsg, &value->number_of_initial_scs_detected, end) == 0) + return 0; + + if(value->number_of_initial_scs_detected > NFAPI_PREAMBLE_MAX_PDU) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of detected scs ind pdus exceed maxium (count:%d max:%d)\n", __FUNCTION__, value->number_of_initial_scs_detected, NFAPI_PREAMBLE_MAX_PDU); + return 0; + } + + value->nrach_pdu_list = (nfapi_nrach_indication_pdu_t*)nfapi_p7_allocate(sizeof(nfapi_nrach_indication_pdu_t) * value->number_of_initial_scs_detected, config); + if(value->nrach_pdu_list == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to allocate nrach ind pdu list (count:%d)\n", __FUNCTION__, value->number_of_initial_scs_detected); + return 0; + } + + uint8_t i = 0; + for(i = 0; i < value->number_of_initial_scs_detected; ++i) + { + nfapi_nrach_indication_pdu_t* pdu = &(value->nrach_pdu_list[i]); + + uint8_t* nrachPduInstanceEnd = *ppReadPackedMsg + 4 + 6; + + unpack_tlv_t unpack_fns[] = + { + { NFAPI_NRACH_INDICATION_REL13_TAG, &pdu->nrach_indication_rel13, &unpack_nrach_indication_rel13_value}, + }; + + if(unpack_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, nrachPduInstanceEnd, 0, 0) == 0) + return 0; + + } + + return 1; +} + +static uint8_t unpack_nrach_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_nrach_indication_t *pNfapiMsg = (nfapi_nrach_indication_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + { NFAPI_NRACH_INDICATION_BODY_TAG, &pNfapiMsg->nrach_indication_body, &unpack_nrach_indication_body_value}, + }; + + return (pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_dl_node_sync(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_dl_node_sync_t *pNfapiMsg = (nfapi_dl_node_sync_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + }; + + return (pull32(ppReadPackedMsg, &pNfapiMsg->t1, end) && + pulls32(ppReadPackedMsg, &pNfapiMsg->delta_sfn_sf, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_ul_node_sync(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_ul_node_sync_t *pNfapiMsg = (nfapi_ul_node_sync_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + }; + + return (pull32(ppReadPackedMsg, &pNfapiMsg->t1, end) && + pull32(ppReadPackedMsg, &pNfapiMsg->t2, end) && + pull32(ppReadPackedMsg, &pNfapiMsg->t3, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + +static uint8_t unpack_timing_info(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config) +{ + nfapi_timing_info_t *pNfapiMsg = (nfapi_timing_info_t*)msg; + + unpack_p7_tlv_t unpack_fns[] = + { + }; + + return (pull32(ppReadPackedMsg, &pNfapiMsg->last_sfn_sf, end) && + pull32(ppReadPackedMsg, &pNfapiMsg->time_since_last_timing_info, end) && + pull32(ppReadPackedMsg, &pNfapiMsg->dl_config_jitter, end) && + pull32(ppReadPackedMsg, &pNfapiMsg->tx_request_jitter, end) && + pull32(ppReadPackedMsg, &pNfapiMsg->ul_config_jitter, end) && + pull32(ppReadPackedMsg, &pNfapiMsg->hi_dci0_jitter, end) && + pulls32(ppReadPackedMsg, &pNfapiMsg->dl_config_latest_delay, end) && + pulls32(ppReadPackedMsg, &pNfapiMsg->tx_request_latest_delay, end) && + pulls32(ppReadPackedMsg, &pNfapiMsg->ul_config_latest_delay, end) && + pulls32(ppReadPackedMsg, &pNfapiMsg->hi_dci0_latest_delay, end) && + pulls32(ppReadPackedMsg, &pNfapiMsg->dl_config_earliest_arrival, end) && + pulls32(ppReadPackedMsg, &pNfapiMsg->tx_request_earliest_arrival, end) && + pulls32(ppReadPackedMsg, &pNfapiMsg->ul_config_earliest_arrival, end) && + pulls32(ppReadPackedMsg, &pNfapiMsg->hi_dci0_earliest_arrival, end) && + unpack_p7_tlv_list(unpack_fns, sizeof(unpack_fns)/sizeof(unpack_tlv_t), ppReadPackedMsg, end, config, &pNfapiMsg->vendor_extension)); +} + + +// unpack length check + +static int check_unpack_length(nfapi_message_id_e msgId, uint32_t unpackedBufLen) +{ + int retLen = 0; + + switch (msgId) + { + case NFAPI_DL_CONFIG_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_dl_config_request_t)) + retLen = sizeof(nfapi_dl_config_request_t); + break; + + case NFAPI_UL_CONFIG_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_ul_config_request_t)) + retLen = sizeof(nfapi_ul_config_request_t); + break; + + case NFAPI_SUBFRAME_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_subframe_indication_t)) + retLen = sizeof(nfapi_subframe_indication_t); + break; + + case NFAPI_HI_DCI0_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_hi_dci0_request_t)) + retLen = sizeof(nfapi_hi_dci0_request_t); + break; + + case NFAPI_TX_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_tx_request_t)) + retLen = sizeof(nfapi_tx_request_t); + break; + + case NFAPI_HARQ_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_harq_indication_t)) + retLen = sizeof(nfapi_harq_indication_t); + break; + + case NFAPI_CRC_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_crc_indication_t)) + retLen = sizeof(nfapi_crc_indication_t); + break; + + case NFAPI_RX_ULSCH_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_rx_indication_t)) + retLen = sizeof(nfapi_rx_indication_t); + break; + + case NFAPI_RACH_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_rach_indication_t)) + retLen = sizeof(nfapi_rach_indication_t); + break; + + case NFAPI_SRS_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_srs_indication_t)) + retLen = sizeof(nfapi_srs_indication_t); + break; + + case NFAPI_RX_SR_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_sr_indication_t)) + retLen = sizeof(nfapi_sr_indication_t); + break; + + case NFAPI_RX_CQI_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_cqi_indication_t)) + retLen = sizeof(nfapi_cqi_indication_t); + break; + + case NFAPI_LBT_DL_CONFIG_REQUEST: + if (unpackedBufLen >= sizeof(nfapi_lbt_dl_config_request_t)) + retLen = sizeof(nfapi_lbt_dl_config_request_t); + break; + + case NFAPI_LBT_DL_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_lbt_dl_indication_t)) + retLen = sizeof(nfapi_lbt_dl_indication_t); + break; + + case NFAPI_NB_HARQ_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_nb_harq_indication_t)) + retLen = sizeof(nfapi_nb_harq_indication_t); + break; + + case NFAPI_NRACH_INDICATION: + if (unpackedBufLen >= sizeof(nfapi_nrach_indication_t)) + retLen = sizeof(nfapi_nrach_indication_t); + break; + + case NFAPI_DL_NODE_SYNC: + if (unpackedBufLen >= sizeof(nfapi_dl_node_sync_t)) + retLen = sizeof(nfapi_dl_node_sync_t); + break; + + case NFAPI_UL_NODE_SYNC: + if (unpackedBufLen >= sizeof(nfapi_ul_node_sync_t)) + retLen = sizeof(nfapi_ul_node_sync_t); + break; + + case NFAPI_TIMING_INFO: + if (unpackedBufLen >= sizeof(nfapi_timing_info_t)) + retLen = sizeof(nfapi_timing_info_t); + break; + + default: + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unknown message ID %d\n", msgId); + break; + } + + return retLen; +} + + +// Main unpack functions - public + +int nfapi_p7_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p7_codec_config_t* config) +{ + nfapi_p7_message_header_t *pMessageHeader = pUnpackedBuf; + uint8_t *pReadPackedMessage = pMessageBuf; + uint8_t *end = pMessageBuf + messageBufLen; + + if (pMessageBuf == NULL || pUnpackedBuf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 header unpack supplied pointers are null\n"); + return -1; + } + + if (messageBufLen < NFAPI_P7_HEADER_LENGTH || unpackedBufLen < sizeof(nfapi_p7_message_header_t)) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 header unpack supplied message buffer is too small %d, %d\n", messageBufLen, unpackedBufLen); + return -1; + } + + // process the header + if(!(pull16(&pReadPackedMessage, &pMessageHeader->phy_id, end) && + pull16(&pReadPackedMessage, &pMessageHeader->message_id, end) && + pull16(&pReadPackedMessage, &pMessageHeader->message_length, end) && + pull16(&pReadPackedMessage, &pMessageHeader->m_segment_sequence, end) && + pull32(&pReadPackedMessage, &pMessageHeader->checksum, end) && + pull32(&pReadPackedMessage, &pMessageHeader->transmit_timestamp, end))) + return -1; + + return 0; +} + +int nfapi_p7_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p7_codec_config_t* config) +{ + int result = 0; + nfapi_p7_message_header_t *pMessageHeader = (nfapi_p7_message_header_t*)pUnpackedBuf; + uint8_t *pReadPackedMessage = pMessageBuf; + uint8_t *end = pMessageBuf + messageBufLen; + + if (pMessageBuf == NULL || pUnpackedBuf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 unpack supplied pointers are null\n"); + return -1; + } + + if (messageBufLen < NFAPI_P7_HEADER_LENGTH || unpackedBufLen < sizeof(nfapi_p7_message_header_t)) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 unpack supplied message buffer is too small %d, %d\n", messageBufLen, unpackedBufLen); + return -1; + } + + // clean the supplied buffer for - tag value blanking + (void)memset(pUnpackedBuf, 0, unpackedBufLen); + + // process the header + if(!(pull16(&pReadPackedMessage, &pMessageHeader->phy_id, end) && + pull16(&pReadPackedMessage, &pMessageHeader->message_id, end) && + pull16(&pReadPackedMessage, &pMessageHeader->message_length, end) && + pull16(&pReadPackedMessage, &pMessageHeader->m_segment_sequence, end) && + pull32(&pReadPackedMessage, &pMessageHeader->checksum, end) && + pull32(&pReadPackedMessage, &pMessageHeader->transmit_timestamp, end))) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 unpack header failed\n"); + return -1; + } + + if((uint8_t*)(pMessageBuf + pMessageHeader->message_length) > end) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 unpack message length is greater than the message buffer \n"); + return -1; + } + + /* + if(check_unpack_length(pMessageHeader->message_id, unpackedBufLen) == 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 unpack unpack buffer is not large enough \n"); + return -1; + } + */ + + // look for the specific message + switch (pMessageHeader->message_id) + { + case NFAPI_DL_CONFIG_REQUEST: + if (check_unpack_length(NFAPI_DL_CONFIG_REQUEST, unpackedBufLen)) + result = unpack_dl_config_request(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_UL_CONFIG_REQUEST: + if (check_unpack_length(NFAPI_UL_CONFIG_REQUEST, unpackedBufLen)) + result = unpack_ul_config_request(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_HI_DCI0_REQUEST: + if (check_unpack_length(NFAPI_HI_DCI0_REQUEST, unpackedBufLen)) + result = unpack_hi_dci0_request(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_TX_REQUEST: + if (check_unpack_length(NFAPI_TX_REQUEST, unpackedBufLen)) + result = unpack_tx_request(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_HARQ_INDICATION: + if (check_unpack_length(NFAPI_HARQ_INDICATION, unpackedBufLen)) + result = unpack_harq_indication(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_CRC_INDICATION: + if (check_unpack_length(NFAPI_CRC_INDICATION, unpackedBufLen)) + result = unpack_crc_indication(&pReadPackedMessage,end , pMessageHeader, config); + else + return -1; + break; + + case NFAPI_RX_ULSCH_INDICATION: + if (check_unpack_length(NFAPI_RX_ULSCH_INDICATION, unpackedBufLen)) + result = unpack_rx_indication(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_RACH_INDICATION: + if (check_unpack_length(NFAPI_RACH_INDICATION, unpackedBufLen)) + result = unpack_rach_indication(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_SRS_INDICATION: + if (check_unpack_length(NFAPI_SRS_INDICATION, unpackedBufLen)) + result = unpack_srs_indication(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_RX_SR_INDICATION: + if (check_unpack_length(NFAPI_RX_SR_INDICATION, unpackedBufLen)) + result = unpack_sr_indication(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_RX_CQI_INDICATION: + if (check_unpack_length(NFAPI_RX_CQI_INDICATION, unpackedBufLen)) + result = unpack_cqi_indication(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_LBT_DL_CONFIG_REQUEST: + if (check_unpack_length(NFAPI_LBT_DL_CONFIG_REQUEST, unpackedBufLen)) + result = unpack_lbt_dl_config_request(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_LBT_DL_INDICATION: + if (check_unpack_length(NFAPI_LBT_DL_INDICATION, unpackedBufLen)) + result = unpack_lbt_dl_indication(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_NB_HARQ_INDICATION: + if (check_unpack_length(NFAPI_NB_HARQ_INDICATION, unpackedBufLen)) + result = unpack_nb_harq_indication(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_NRACH_INDICATION: + if (check_unpack_length(NFAPI_NRACH_INDICATION, unpackedBufLen)) + result = unpack_nrach_indication(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_DL_NODE_SYNC: + if (check_unpack_length(NFAPI_DL_NODE_SYNC, unpackedBufLen)) + result = unpack_dl_node_sync(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + case NFAPI_UL_NODE_SYNC: + if (check_unpack_length(NFAPI_UL_NODE_SYNC, unpackedBufLen)) + result = unpack_ul_node_sync(&pReadPackedMessage, end , pMessageHeader, config); + else + return -1; + break; + + case NFAPI_TIMING_INFO: + if (check_unpack_length(NFAPI_TIMING_INFO, unpackedBufLen)) + result = unpack_timing_info(&pReadPackedMessage, end, pMessageHeader, config); + else + return -1; + break; + + default: + + if(pMessageHeader->message_id >= NFAPI_VENDOR_EXT_MSG_MIN && + pMessageHeader->message_id <= NFAPI_VENDOR_EXT_MSG_MAX) + { + if(config && config->unpack_p7_vendor_extension) + { + result = (config->unpack_p7_vendor_extension)(pMessageHeader, &pReadPackedMessage, end, config); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s VE NFAPI message ID %d. No ve decoder provided\n", __FUNCTION__, pMessageHeader->message_id); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s NFAPI Unknown message ID %d\n", __FUNCTION__, pMessageHeader->message_id); + } + break; + } + + if(result == 0) + return -1; + else + return 0; +} + diff --git a/nfapi/open-nFAPI/nfapi/tests/Makefile.am b/nfapi/open-nFAPI/nfapi/tests/Makefile.am new file mode 100644 index 0000000000..46785869b0 --- /dev/null +++ b/nfapi/open-nFAPI/nfapi/tests/Makefile.am @@ -0,0 +1,36 @@ +# +# Copyright 2017 Cisco Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +#nfapi unit test +AUTOMAKE_OPTIONS=subdir-objects + +AM_CPPFLAGS = -I$(top_srcdir)/nfapi/inc -I$(top_srcdir)/nfapi/public_inc -I$(top_srcdir)/common/public_inc -I$(top_srcdir)pnf/public_inc $(CFLAGS_CUNIT) -Wall -Werror +AM_CFLAGS = -I$(top_srcdir)/nfapi/inc -I$(top_srcdir)/nfapi/public_inc -I$(top_srcdir)/common/public_inc -I$(top_srcdir)/pnf/public_inc $(CFLAGS_CUNIT) -Wall -Werror + +check_PROGRAMS= test_nfapi +test_nfapi_SOURCES = nfapi_cunit_main.c ../src/nfapi.c ../src/nfapi_p7.c ../../common/src/debug.c ../src/nfapi_p5.c ../src/nfapi_p4.c +test_nfapi_LDADD=$(top_builddir)/pnf/libnfapi_pnf.a -L$(libdir) -lpthread -lrt -lsctp -lz -lcunit + + +#jTEST_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/tap-driver.sh --ingore-exit +#TEST_ENVIRONMENT = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/tap-driver.sh + +#AM_TESTS_ENVIRONMENT = env AM_TAP_AWK='$(AWK)' $(SHELL); +LOG_DRIVER = $(top_srcdir)/tap-driver.sh +#AM_LOG_FLAGS = -- test_nfapi + +TESTS=$(check_PROGRAMS) +EXTRA_DIST = $(TESTS) diff --git a/nfapi/open-nFAPI/nfapi/tests/nfapi_cunit_main.c b/nfapi/open-nFAPI/nfapi/tests/nfapi_cunit_main.c new file mode 100644 index 0000000000..daaf65a3ff --- /dev/null +++ b/nfapi/open-nFAPI/nfapi/tests/nfapi_cunit_main.c @@ -0,0 +1,5511 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CUnit.h" +#include "Basic.h" +#include "Automated.h" +//#include "CUnit/Console.h" + +#include "nfapi_interface.h" +#include "nfapi.h" +#include // for printf +#include +#include "debug.h" +#include "nfapi_interface.h" +/* Test Suite setup and cleanup functions: */ + +int init_suite(void) { return 0; } +int clean_suite(void) { return 0; } + +#define MAX_PACKED_MESSAGE_SIZE 8192 + +#define IN_OUT_ASSERT(_V) { CU_ASSERT_EQUAL(in._V, out._V); } + +typedef struct +{ + nfapi_tl_t tl; + uint16_t value1; + uint32_t value2; +} my_vendor_extention; + +extern void* nfapi_allocate_pdu(size_t size) +{ + return malloc(size); +} + +extern int nfapi_test_unpack_vendor_extension_tlv(nfapi_tl_t* tl, uint8_t **ppReadPackedMsg, uint8_t *end, void** ve, nfapi_p4_p5_codec_config_t* config) +{ + printf("nfapi_unpack_vendor_extension_tlv\n"); + + if(tl->tag == NFAPI_VENDOR_EXTENSION_MIN_TAG_VALUE) + { + my_vendor_extention* mve = (my_vendor_extention*)malloc(sizeof(my_vendor_extention)); + mve->tl.tag = NFAPI_VENDOR_EXTENSION_MIN_TAG_VALUE; + + if(!(pull16(ppReadPackedMsg, &mve->value1, end) && + pull32(ppReadPackedMsg, &mve->value2, end))) + { + free(mve); + return 0; + } + + (*ve) = mve; + + } + + return 1; +} + +int nfapi_pack_vendor_extension_tlv_called = 0; +extern int nfapi_test_pack_vendor_extension_tlv(void* ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + printf("nfapi_pack_vendor_extension_tlv\n"); + nfapi_pack_vendor_extension_tlv_called++; + + my_vendor_extention* mve = (my_vendor_extention*)ve; + + return (push16(mve->value1, ppWritePackedMsg, end) && + push32(mve->value2, ppWritePackedMsg, end)); + +} + +uint8_t gTestNfapiMessageTx[MAX_PACKED_MESSAGE_SIZE]; + + +uint8_t rand8(uint8_t min, uint8_t max) +{ + return ((rand() % (max + 1 - min)) + min); +} + +/************* Test case functions ****************/ + +void test_case_sample(void) +{ + /*Sample assert function, use as per your test case scenario.*/ + CU_ASSERT(CU_TRUE); + CU_ASSERT_NOT_EQUAL(2, -1); + CU_ASSERT_STRING_EQUAL("string #1", "string #1"); + CU_ASSERT_STRING_NOT_EQUAL("string #1", "string #2"); + + CU_ASSERT(CU_FALSE); + CU_ASSERT_EQUAL(2, 3); + CU_ASSERT_STRING_NOT_EQUAL("string #1", "string #1"); + CU_ASSERT_STRING_EQUAL("string #1", "string #2"); +} + + +int nfapi_test_verify_configreq_params(nfapi_pnf_config_request_t pnfConfigRequest_in, nfapi_pnf_config_request_t pnfConfigRequest_out) +{ + int i=0; + if(memcmp(&pnfConfigRequest_in, &pnfConfigRequest_out, sizeof(nfapi_pnf_config_request_t)) == 0) + { + /*packed and unpacked phy config request are matched.*/ + + printf("Success: packed and unpacked phy config request are matched\n"); + return 1; + } + else + { + if (pnfConfigRequest_in.header.message_id != pnfConfigRequest_out.header.message_id) + { + printf("Mismatch: packed message id %d, unpacked message id %d\n", + pnfConfigRequest_in.header.message_id, pnfConfigRequest_out.header.message_id); + } + if (pnfConfigRequest_in.header.message_length != pnfConfigRequest_out.header.message_length) + { + printf("Mismatch: packed message_length %d, unpacked message_length %d\n", + pnfConfigRequest_in.header.message_length, pnfConfigRequest_out.header.message_length); + } + if (pnfConfigRequest_in.header.phy_id != pnfConfigRequest_out.header.phy_id) + { + printf("Mismatch: packed phy_id %d, unpacked phy_id %d\n", + pnfConfigRequest_in.header.phy_id, pnfConfigRequest_out.header.phy_id); + } + if (pnfConfigRequest_in.pnf_phy_rf_config.number_phy_rf_config_info != pnfConfigRequest_out.pnf_phy_rf_config.number_phy_rf_config_info) + { + printf("Mismatch: packed number_phy_rf_config_info %d, unpacked number_phy_rf_config_info %d\n", + pnfConfigRequest_in.pnf_phy_rf_config.number_phy_rf_config_info, pnfConfigRequest_out.pnf_phy_rf_config.number_phy_rf_config_info); + } + + for (i=0; i < NFAPI_MAX_PHY_RF_INSTANCES; i++) + { + if (pnfConfigRequest_in.pnf_phy_rf_config.phy_rf_config[i].phy_id != pnfConfigRequest_out.pnf_phy_rf_config.phy_rf_config[i].phy_id) + { + printf("Mismatch: rf idx %d, packed phy id %d, unpacked phy id %d\n", + i, pnfConfigRequest_in.pnf_phy_rf_config.phy_rf_config[i].phy_id, pnfConfigRequest_out.pnf_phy_rf_config.phy_rf_config[i].phy_id); + } + if (pnfConfigRequest_in.pnf_phy_rf_config.phy_rf_config[i].phy_config_index!= pnfConfigRequest_out.pnf_phy_rf_config.phy_rf_config[i].phy_config_index) + { + printf("Mismatch: rf idx %d, packed phy_config_index %d, unpacked phy_config_index %d\n", + i, pnfConfigRequest_in.pnf_phy_rf_config.phy_rf_config[i].phy_config_index, pnfConfigRequest_out.pnf_phy_rf_config.phy_rf_config[i].phy_config_index); + } + if (pnfConfigRequest_in.pnf_phy_rf_config.phy_rf_config[i].rf_config_index != pnfConfigRequest_out.pnf_phy_rf_config.phy_rf_config[i].rf_config_index) + { + printf("Mismatch: rf idx %d, packed rf_config_index %d, unpacked rf_config_index %d\n", + i, pnfConfigRequest_in.pnf_phy_rf_config.phy_rf_config[i].rf_config_index, pnfConfigRequest_out.pnf_phy_rf_config.phy_rf_config[i].rf_config_index); + } + } + return 0; + } + +} + + +void nfapi_test_pnf_config_req(void) +{ + + nfapi_pnf_config_request_t pnfConfigRequest_out; + nfapi_pnf_config_request_t pnfConfigRequest_in; + int packedMessageLength =0; + + printf(" nfapi_test_pnf_config_req run \n"); + + /* Build phy config req */ + pnfConfigRequest_in.header.phy_id = NFAPI_PHY_ID_NA; + pnfConfigRequest_in.header.message_id = NFAPI_PNF_CONFIG_REQUEST; + pnfConfigRequest_in.header.message_length = 22; + pnfConfigRequest_in.header.spare = 0; + + pnfConfigRequest_in.pnf_phy_rf_config.tl.tag = NFAPI_PNF_PHY_RF_TAG; + pnfConfigRequest_in.pnf_phy_rf_config.tl.length = 0; + pnfConfigRequest_in.pnf_phy_rf_config.number_phy_rf_config_info = 2; + pnfConfigRequest_in.pnf_phy_rf_config.phy_rf_config[0].phy_id = 4; + pnfConfigRequest_in.pnf_phy_rf_config.phy_rf_config[0].phy_config_index = 1; + pnfConfigRequest_in.pnf_phy_rf_config.phy_rf_config[0].rf_config_index = 1; + pnfConfigRequest_in.pnf_phy_rf_config.phy_rf_config[1].phy_id = 5; + pnfConfigRequest_in.pnf_phy_rf_config.phy_rf_config[1].phy_config_index = 2; + pnfConfigRequest_in.pnf_phy_rf_config.phy_rf_config[1].rf_config_index = 2; + + /*Pack pnf config req*/ + packedMessageLength = nfapi_p5_message_pack(&pnfConfigRequest_in, sizeof(nfapi_pnf_config_request_t), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + /*Unpack pnf config request*/ + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &pnfConfigRequest_out, sizeof(nfapi_pnf_config_request_t), 0); + + /*Verify unpacked message*/ + CU_ASSERT_EQUAL(nfapi_test_verify_configreq_params(pnfConfigRequest_in, pnfConfigRequest_out), 1); + +} + +void nfapi_test_2(void) { + /*Sample test function*/ + CU_ASSERT_EQUAL( 0, 0); +} + +void nfapi_test_rssi_request_lte() +{ + uint16_t idx; + nfapi_rssi_request_t in; + nfapi_rssi_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_RSSI_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_LTE; + + in.lte_rssi_request.tl.tag = NFAPI_LTE_RSSI_REQUEST_TAG; + in.lte_rssi_request.frequency_band_indicator = 0; + in.lte_rssi_request.bandwidth = 0; + in.lte_rssi_request.timeout = 0; + in.lte_rssi_request.number_of_earfcns = 4; + in.lte_rssi_request.earfcn[0] = 42; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + int upack_result = nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_NOT_EQUAL(packedMessageLength, -1); + CU_ASSERT_NOT_EQUAL(packedMessageLength, 0); + CU_ASSERT_NOT_EQUAL(upack_result, 0); + CU_ASSERT_NOT_EQUAL(upack_result, -1); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.lte_rssi_request.frequency_band_indicator, out.lte_rssi_request.frequency_band_indicator); + CU_ASSERT_EQUAL(in.lte_rssi_request.bandwidth, out.lte_rssi_request.bandwidth); + CU_ASSERT_EQUAL(in.lte_rssi_request.timeout, out.lte_rssi_request.timeout); + CU_ASSERT_EQUAL(in.lte_rssi_request.number_of_earfcns, out.lte_rssi_request.number_of_earfcns); + + for(idx = 0; idx < out.lte_rssi_request.number_of_earfcns; ++idx) + { + CU_ASSERT_EQUAL(in.lte_rssi_request.earfcn[idx], out.lte_rssi_request.earfcn[idx]); + } +} + +void nfapi_test_rssi_request_lte2() +{ + uint16_t idx; + nfapi_rssi_request_t in; + nfapi_rssi_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_RSSI_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_LTE; + + in.lte_rssi_request.tl.tag = NFAPI_LTE_RSSI_REQUEST_TAG; + in.lte_rssi_request.frequency_band_indicator = 0; + in.lte_rssi_request.bandwidth = 0; + in.lte_rssi_request.timeout = 0; + in.lte_rssi_request.number_of_earfcns = 4; + in.lte_rssi_request.earfcn[0] = 42; + + // try and pak with a buffer that is too small + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, NFAPI_HEADER_LENGTH + 4, 0); + CU_ASSERT_EQUAL(packedMessageLength, -1); + + // pack correctly + packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + // unpack with a small bufer + int upack_result = nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength - 1, &out, sizeof(out), 0); + + upack_result = nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_NOT_EQUAL(packedMessageLength, -1); + CU_ASSERT_NOT_EQUAL(packedMessageLength, 0); + CU_ASSERT_NOT_EQUAL(upack_result, 0); + CU_ASSERT_NOT_EQUAL(upack_result, -1); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.lte_rssi_request.frequency_band_indicator, out.lte_rssi_request.frequency_band_indicator); + CU_ASSERT_EQUAL(in.lte_rssi_request.bandwidth, out.lte_rssi_request.bandwidth); + CU_ASSERT_EQUAL(in.lte_rssi_request.timeout, out.lte_rssi_request.timeout); + CU_ASSERT_EQUAL(in.lte_rssi_request.number_of_earfcns, out.lte_rssi_request.number_of_earfcns); + + for(idx = 0; idx < out.lte_rssi_request.number_of_earfcns; ++idx) + { + CU_ASSERT_EQUAL(in.lte_rssi_request.earfcn[idx], out.lte_rssi_request.earfcn[idx]); + } +} + + + +// Test decoding of message which has a large number if earfcn which could +// cause a buffer over run if not handled +void nfapi_test_rssi_request_lte_overrun() +{ + nfapi_rssi_request_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t* end = p + 1024; + push16(0, &p, end); + push16(NFAPI_RSSI_REQUEST, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push8(NFAPI_RAT_TYPE_LTE, &p, end); + push16(NFAPI_LTE_RSSI_REQUEST_TAG, &p, end); + push16(11, &p, end); + + push8(0, &p, end); + push16(0, &p, end); + push8(0, &p, end); + push32(0, &p, end); + push8(123, &p, end); // to many EARFCN's + push16(16, &p, end); + + int result = nfapi_p4_message_unpack(buffer, sizeof(buffer), &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} + +void nfapi_test_rssi_request_lte_rat_type_mismatch() +{ + nfapi_rssi_request_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_RSSI_REQUEST, &p, end); + push16(16, &p, end); + push16(0, &p, end); + + push8(NFAPI_RAT_TYPE_GERAN, &p, end); + + push16(NFAPI_LTE_RSSI_REQUEST_TAG, &p, end); + push16(11, &p, end); + + push8(0, &p, end); + push16(0, &p, end); + push8(0, &p, end); + push32(0, &p, end); + push8(1, &p, end); + push16(16, &p, end); + + int result = nfapi_p4_message_unpack(buffer, sizeof(buffer), &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} + +void nfapi_test_rssi_request_utran() +{ + uint16_t idx; + nfapi_rssi_request_t in; + nfapi_rssi_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_RSSI_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_UTRAN; + + + in.utran_rssi_request.tl.tag = NFAPI_UTRAN_RSSI_REQUEST_TAG; + in.utran_rssi_request.frequency_band_indicator = 0; + in.utran_rssi_request.measurement_period = 0; + in.utran_rssi_request.timeout = 0; + in.utran_rssi_request.number_of_uarfcns = 3; + in.utran_rssi_request.uarfcn[0] = 42; + in.utran_rssi_request.uarfcn[1] = 42; + in.utran_rssi_request.uarfcn[2] = 42; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.utran_rssi_request.frequency_band_indicator, out.utran_rssi_request.frequency_band_indicator); + CU_ASSERT_EQUAL(in.utran_rssi_request.measurement_period, out.utran_rssi_request.measurement_period); + CU_ASSERT_EQUAL(in.utran_rssi_request.timeout, out.utran_rssi_request.timeout); + CU_ASSERT_EQUAL(in.utran_rssi_request.number_of_uarfcns, out.utran_rssi_request.number_of_uarfcns); + + for(idx = 0; idx < out.utran_rssi_request.number_of_uarfcns; ++idx) + { + CU_ASSERT_EQUAL(in.utran_rssi_request.uarfcn[idx], out.utran_rssi_request.uarfcn[idx]); + } + +} + +void nfapi_test_rssi_request_geran() +{ + uint16_t idx; + nfapi_rssi_request_t in; + nfapi_rssi_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_RSSI_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_GERAN; + + in.geran_rssi_request.tl.tag = NFAPI_GERAN_RSSI_REQUEST_TAG; + in.geran_rssi_request.frequency_band_indicator = 0; + in.geran_rssi_request.measurement_period = 0; + in.geran_rssi_request.timeout = 0; + in.geran_rssi_request.number_of_arfcns = 3; + in.geran_rssi_request.arfcn[0].arfcn = 42; + in.geran_rssi_request.arfcn[0].direction = 0; + in.geran_rssi_request.arfcn[1].arfcn = 42; + in.geran_rssi_request.arfcn[1].direction = 1; + in.geran_rssi_request.arfcn[2].arfcn = 42; + in.geran_rssi_request.arfcn[2].direction = 1; + + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.geran_rssi_request.frequency_band_indicator, out.geran_rssi_request.frequency_band_indicator); + CU_ASSERT_EQUAL(in.geran_rssi_request.measurement_period, out.geran_rssi_request.measurement_period); + CU_ASSERT_EQUAL(in.geran_rssi_request.timeout, out.geran_rssi_request.timeout); + CU_ASSERT_EQUAL(in.geran_rssi_request.number_of_arfcns, out.geran_rssi_request.number_of_arfcns); + + for(idx = 0; idx < out.geran_rssi_request.number_of_arfcns; ++idx) + { + CU_ASSERT_EQUAL(in.geran_rssi_request.arfcn[idx].arfcn, out.geran_rssi_request.arfcn[idx].arfcn); + CU_ASSERT_EQUAL(in.geran_rssi_request.arfcn[idx].direction, out.geran_rssi_request.arfcn[idx].direction); + } +} + +void nfapi_test_rssi_request_nb_iot() +{ + uint16_t idx, idx2; + nfapi_rssi_request_t in; + nfapi_rssi_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_RSSI_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_NB_IOT; + + in.nb_iot_rssi_request.tl.tag = NFAPI_NB_IOT_RSSI_REQUEST_TAG; + in.nb_iot_rssi_request.frequency_band_indicator = 34; + in.nb_iot_rssi_request.measurement_period = 900; + in.nb_iot_rssi_request.timeout = 4321; + in.nb_iot_rssi_request.number_of_earfcns = 3; + in.nb_iot_rssi_request.earfcn[0].earfcn = 42; + in.nb_iot_rssi_request.earfcn[0].number_of_ro_dl = 1; + in.nb_iot_rssi_request.earfcn[0].ro_dl[0] = 2; + in.nb_iot_rssi_request.earfcn[1].earfcn = 43; + in.nb_iot_rssi_request.earfcn[1].number_of_ro_dl = 0; + in.nb_iot_rssi_request.earfcn[2].earfcn = 44; + in.nb_iot_rssi_request.earfcn[2].number_of_ro_dl = 2; + in.nb_iot_rssi_request.earfcn[2].ro_dl[0] = 0; + in.nb_iot_rssi_request.earfcn[2].ro_dl[1] = 4; + + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + IN_OUT_ASSERT(header.message_id); + IN_OUT_ASSERT(rat_type); + IN_OUT_ASSERT(nb_iot_rssi_request.frequency_band_indicator); + IN_OUT_ASSERT(nb_iot_rssi_request.measurement_period); + IN_OUT_ASSERT(nb_iot_rssi_request.timeout); + IN_OUT_ASSERT(nb_iot_rssi_request.number_of_earfcns); + + for(idx = 0; idx < out.nb_iot_rssi_request.number_of_earfcns; ++idx) + { + IN_OUT_ASSERT(nb_iot_rssi_request.earfcn[idx].earfcn); + IN_OUT_ASSERT(nb_iot_rssi_request.earfcn[idx].number_of_ro_dl); + + for(idx2 = 0; idx2 < out.nb_iot_rssi_request.earfcn[idx].number_of_ro_dl; ++idx2) + IN_OUT_ASSERT(nb_iot_rssi_request.earfcn[idx].ro_dl[idx2]); + } +} + + +void nfapi_test_rssi_response() +{ + nfapi_rssi_response_t in; + nfapi_rssi_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_RSSI_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_RAT_NOT_SUPPORTED; + + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + +} + +void nfapi_test_rssi_indication() +{ + uint16_t idx = 0; + nfapi_rssi_indication_t in; + nfapi_rssi_indication_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_RSSI_INDICATION; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_OK; + in.rssi_indication_body.tl.tag = NFAPI_RSSI_INDICATION_TAG; + in.rssi_indication_body.tl.length = 0; + in.rssi_indication_body.number_of_rssi = 4; + in.rssi_indication_body.rssi[0] = 2; + in.rssi_indication_body.rssi[1] = 0; + in.rssi_indication_body.rssi[2] = -23; + in.rssi_indication_body.rssi[3] = -18000; + + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.rssi_indication_body.tl.tag, out.rssi_indication_body.tl.tag); + CU_ASSERT_EQUAL(in.rssi_indication_body.number_of_rssi, out.rssi_indication_body.number_of_rssi); + + for(idx = 0; idx < out.rssi_indication_body.number_of_rssi; ++idx) + { + CU_ASSERT_EQUAL(in.rssi_indication_body.rssi[idx], out.rssi_indication_body.rssi[idx]); + } + +} +void nfapi_test_rssi_indication_overrun() +{ + nfapi_rssi_indication_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_RSSI_INDICATION, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push32(0, &p, end); // error code + + push16(NFAPI_RSSI_INDICATION_TAG, &p, end); + push16(11, &p, end); + + push16(NFAPI_MAX_RSSI + 23, &p, end); // to many EARFCN's + push16(16, &p, end); + + int result = nfapi_p4_message_unpack(buffer, sizeof(buffer), &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} + +void nfapi_test_cell_search_request_lte() +{ + uint16_t idx; + nfapi_cell_search_request_t in; + nfapi_cell_search_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_CELL_SEARCH_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_LTE; + + in.lte_cell_search_request.tl.tag = NFAPI_LTE_CELL_SEARCH_REQUEST_TAG; + in.lte_cell_search_request.earfcn = 213; + in.lte_cell_search_request.measurement_bandwidth = 1; + in.lte_cell_search_request.exhaustive_search = 0; + in.lte_cell_search_request.timeout = 123; + in.lte_cell_search_request.number_of_pci = 3; + in.lte_cell_search_request.pci[0] = 3; + in.lte_cell_search_request.pci[1] = 6; + in.lte_cell_search_request.pci[2] = 9; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.lte_cell_search_request.earfcn, out.lte_cell_search_request.earfcn); + CU_ASSERT_EQUAL(in.lte_cell_search_request.measurement_bandwidth, out.lte_cell_search_request.measurement_bandwidth); + CU_ASSERT_EQUAL(in.lte_cell_search_request.exhaustive_search, out.lte_cell_search_request.exhaustive_search); + CU_ASSERT_EQUAL(in.lte_cell_search_request.timeout, out.lte_cell_search_request.timeout); + CU_ASSERT_EQUAL(in.lte_cell_search_request.number_of_pci, out.lte_cell_search_request.number_of_pci); + + for(idx = 0; idx < out.lte_cell_search_request.number_of_pci; ++idx) + { + CU_ASSERT_EQUAL(in.lte_cell_search_request.pci[idx], out.lte_cell_search_request.pci[idx]); + } +} + +void nfapi_test_cell_search_request_utran() +{ + uint16_t idx; + nfapi_cell_search_request_t in; + nfapi_cell_search_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_CELL_SEARCH_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_UTRAN; + + in.utran_cell_search_request.tl.tag = NFAPI_UTRAN_CELL_SEARCH_REQUEST_TAG; + in.utran_cell_search_request.uarfcn = 213; + in.utran_cell_search_request.exhaustive_search = 0; + in.utran_cell_search_request.timeout = 123; + in.utran_cell_search_request.number_of_psc = 3; + in.utran_cell_search_request.psc[0] = 3; + in.utran_cell_search_request.psc[1] = 6; + in.utran_cell_search_request.psc[2] = 9; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + int unpackResult = nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + CU_ASSERT_NOT_EQUAL(unpackResult, -1); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.utran_cell_search_request.uarfcn, out.utran_cell_search_request.uarfcn); + CU_ASSERT_EQUAL(in.utran_cell_search_request.exhaustive_search, out.utran_cell_search_request.exhaustive_search); + CU_ASSERT_EQUAL(in.utran_cell_search_request.timeout, out.utran_cell_search_request.timeout); + CU_ASSERT_EQUAL(in.utran_cell_search_request.number_of_psc, out.utran_cell_search_request.number_of_psc); + + for(idx = 0; idx < out.utran_cell_search_request.number_of_psc; ++idx) + { + CU_ASSERT_EQUAL(in.utran_cell_search_request.psc[idx], out.utran_cell_search_request.psc[idx]); + } +} + +void nfapi_test_cell_search_request_geran() +{ + uint16_t idx; + nfapi_cell_search_request_t in; + nfapi_cell_search_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_CELL_SEARCH_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_GERAN; + + in.geran_cell_search_request.tl.tag = NFAPI_GERAN_CELL_SEARCH_REQUEST_TAG; + in.geran_cell_search_request.timeout = 123; + in.geran_cell_search_request.number_of_arfcn = 3; + in.geran_cell_search_request.arfcn[0] = 3; + in.geran_cell_search_request.arfcn[1] = 6; + in.geran_cell_search_request.arfcn[2] = 9; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + int unpackResult = nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + CU_ASSERT_NOT_EQUAL(unpackResult, -1); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.geran_cell_search_request.timeout, out.geran_cell_search_request.timeout); + CU_ASSERT_EQUAL(in.geran_cell_search_request.number_of_arfcn, out.geran_cell_search_request.number_of_arfcn); + + for(idx = 0; idx < out.geran_cell_search_request.number_of_arfcn; ++idx) + { + CU_ASSERT_EQUAL(in.geran_cell_search_request.arfcn[idx], out.geran_cell_search_request.arfcn[idx]); + } +} + +void nfapi_test_cell_search_request_nb_iot() +{ + uint16_t idx; + nfapi_cell_search_request_t in; + nfapi_cell_search_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_CELL_SEARCH_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_NB_IOT; + + in.nb_iot_cell_search_request.tl.tag = NFAPI_NB_IOT_CELL_SEARCH_REQUEST_TAG; + in.nb_iot_cell_search_request.earfcn = 54; + in.nb_iot_cell_search_request.ro_dl = 3; + in.nb_iot_cell_search_request.exhaustive_search = 1; + in.nb_iot_cell_search_request.timeout = 123; + in.nb_iot_cell_search_request.number_of_pci = 3; + in.nb_iot_cell_search_request.pci[0] = 3; + in.nb_iot_cell_search_request.pci[1] = 6; + in.nb_iot_cell_search_request.pci[2] = 9; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + int unpackResult = nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + CU_ASSERT_NOT_EQUAL(unpackResult, -1); + + IN_OUT_ASSERT(header.message_id); + IN_OUT_ASSERT(rat_type); + IN_OUT_ASSERT(nb_iot_cell_search_request.earfcn); + IN_OUT_ASSERT(nb_iot_cell_search_request.ro_dl); + IN_OUT_ASSERT(nb_iot_cell_search_request.exhaustive_search); + IN_OUT_ASSERT(nb_iot_cell_search_request.timeout); + IN_OUT_ASSERT(nb_iot_cell_search_request.number_of_pci); + + for(idx = 0; idx < out.nb_iot_cell_search_request.number_of_pci; ++idx) + { + IN_OUT_ASSERT(nb_iot_cell_search_request.pci[idx]); + } +} + +void nfapi_test_cell_search_response() +{ + nfapi_cell_search_response_t in; + nfapi_cell_search_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_CELL_SEARCH_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_RAT_NOT_SUPPORTED; + + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); +} + +void nfapi_test_cell_search_indication_lte() +{ + uint16_t idx = 0; + nfapi_cell_search_indication_t in; + nfapi_cell_search_indication_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_CELL_SEARCH_INDICATION; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_OK; + in.lte_cell_search_indication.tl.tag = NFAPI_LTE_CELL_SEARCH_INDICATION_TAG; + in.lte_cell_search_indication.number_of_lte_cells_found = 2; + in.lte_cell_search_indication.lte_found_cells[0].pci = 0; + in.lte_cell_search_indication.lte_found_cells[0].rsrp = 42; + in.lte_cell_search_indication.lte_found_cells[0].rsrq= 11; + in.lte_cell_search_indication.lte_found_cells[0].frequency_offset = -100; + + in.lte_cell_search_indication.lte_found_cells[1].pci = 123; + in.lte_cell_search_indication.lte_found_cells[1].rsrp = 2; + in.lte_cell_search_indication.lte_found_cells[1].rsrq= 17; + in.lte_cell_search_indication.lte_found_cells[1].frequency_offset = 123; + + in.utran_cell_search_indication.tl.tag = 0; + in.geran_cell_search_indication.tl.tag = 0; + in.nb_iot_cell_search_indication.tl.tag = 0; + in.pnf_cell_search_state.tl.tag = 0; + + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.lte_cell_search_indication.tl.tag, out.lte_cell_search_indication.tl.tag); + CU_ASSERT_EQUAL(in.lte_cell_search_indication.number_of_lte_cells_found, out.lte_cell_search_indication.number_of_lte_cells_found); + + for(idx = 0; idx < out.lte_cell_search_indication.number_of_lte_cells_found; ++idx) + { + CU_ASSERT_EQUAL(in.lte_cell_search_indication.lte_found_cells[idx].pci, out.lte_cell_search_indication.lte_found_cells[idx].pci); + CU_ASSERT_EQUAL(in.lte_cell_search_indication.lte_found_cells[idx].rsrp, out.lte_cell_search_indication.lte_found_cells[idx].rsrp); + CU_ASSERT_EQUAL(in.lte_cell_search_indication.lte_found_cells[idx].rsrq, out.lte_cell_search_indication.lte_found_cells[idx].rsrq); + CU_ASSERT_EQUAL(in.lte_cell_search_indication.lte_found_cells[idx].frequency_offset, out.lte_cell_search_indication.lte_found_cells[idx].frequency_offset); + } + + + CU_ASSERT_EQUAL(in.utran_cell_search_indication.tl.tag, out.utran_cell_search_indication.tl.tag); + CU_ASSERT_EQUAL(in.geran_cell_search_indication.tl.tag, out.geran_cell_search_indication.tl.tag); + CU_ASSERT_EQUAL(in.pnf_cell_search_state.tl.tag, out.pnf_cell_search_state.tl.tag); +} +void nfapi_test_cell_search_indication_utran() +{ + uint16_t idx = 0; + nfapi_cell_search_indication_t in; + nfapi_cell_search_indication_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_CELL_SEARCH_INDICATION; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_OK; + in.utran_cell_search_indication.tl.tag = NFAPI_UTRAN_CELL_SEARCH_INDICATION_TAG; + in.utran_cell_search_indication.number_of_utran_cells_found = 1; + in.utran_cell_search_indication.utran_found_cells[0].psc = 123; + in.utran_cell_search_indication.utran_found_cells[0].rscp = 2; + in.utran_cell_search_indication.utran_found_cells[0].ecno = 89; + in.utran_cell_search_indication.utran_found_cells[0].frequency_offset = -1000; + + in.lte_cell_search_indication.tl.tag = 0; + in.geran_cell_search_indication.tl.tag = 0; + in.nb_iot_cell_search_indication.tl.tag = 0; + in.pnf_cell_search_state.tl.tag = NFAPI_PNF_CELL_SEARCH_STATE_TAG; + in.pnf_cell_search_state.length = 12; + in.pnf_cell_search_state.value[0] = 34; + in.pnf_cell_search_state.value[1] = 35; + in.pnf_cell_search_state.value[2] = 36; + in.pnf_cell_search_state.value[3] = 37; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.utran_cell_search_indication.tl.tag, out.utran_cell_search_indication.tl.tag); + CU_ASSERT_EQUAL(in.utran_cell_search_indication.number_of_utran_cells_found, out.utran_cell_search_indication.number_of_utran_cells_found); + + for(idx = 0; idx < out.utran_cell_search_indication.number_of_utran_cells_found; ++idx) + { + CU_ASSERT_EQUAL(in.utran_cell_search_indication.utran_found_cells[idx].psc, out.utran_cell_search_indication.utran_found_cells[idx].psc); + CU_ASSERT_EQUAL(in.utran_cell_search_indication.utran_found_cells[idx].rscp, out.utran_cell_search_indication.utran_found_cells[idx].rscp); + CU_ASSERT_EQUAL(in.utran_cell_search_indication.utran_found_cells[idx].ecno, out.utran_cell_search_indication.utran_found_cells[idx].ecno); + CU_ASSERT_EQUAL(in.utran_cell_search_indication.utran_found_cells[idx].frequency_offset, out.utran_cell_search_indication.utran_found_cells[idx].frequency_offset); + } + + CU_ASSERT_EQUAL(in.lte_cell_search_indication.tl.tag, out.lte_cell_search_indication.tl.tag); + CU_ASSERT_EQUAL(in.geran_cell_search_indication.tl.tag, out.geran_cell_search_indication.tl.tag); + CU_ASSERT_EQUAL(in.pnf_cell_search_state.tl.tag, out.pnf_cell_search_state.tl.tag); + CU_ASSERT_EQUAL(in.pnf_cell_search_state.length, out.pnf_cell_search_state.length); + + for(idx = 0; idx < out.pnf_cell_search_state.length; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_cell_search_state.value[idx], out.pnf_cell_search_state.value[idx]); + } +} +void nfapi_test_cell_search_indication_geran() +{ + uint16_t idx = 0; + nfapi_cell_search_indication_t in; + nfapi_cell_search_indication_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_CELL_SEARCH_INDICATION; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_OK; + in.geran_cell_search_indication.tl.tag = NFAPI_GERAN_CELL_SEARCH_INDICATION_TAG; + in.geran_cell_search_indication.number_of_gsm_cells_found = 1; + in.geran_cell_search_indication.gsm_found_cells[0].arfcn = 123; + in.geran_cell_search_indication.gsm_found_cells[0].bsic = 2; + in.geran_cell_search_indication.gsm_found_cells[0].rxlev = 89; + in.geran_cell_search_indication.gsm_found_cells[0].rxqual = 12; + in.geran_cell_search_indication.gsm_found_cells[0].frequency_offset = 2389; + in.geran_cell_search_indication.gsm_found_cells[0].sfn_offset = 23; + + in.lte_cell_search_indication.tl.tag = 0; + in.utran_cell_search_indication.tl.tag = 0; + in.nb_iot_cell_search_indication.tl.tag = 0; + in.pnf_cell_search_state.tl.tag = NFAPI_PNF_CELL_SEARCH_STATE_TAG; + in.pnf_cell_search_state.length = 63; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.geran_cell_search_indication.tl.tag, out.geran_cell_search_indication.tl.tag); + CU_ASSERT_EQUAL(in.geran_cell_search_indication.number_of_gsm_cells_found, out.geran_cell_search_indication.number_of_gsm_cells_found); + + for(idx = 0; idx < out.geran_cell_search_indication.number_of_gsm_cells_found; ++idx) + { + CU_ASSERT_EQUAL(in.geran_cell_search_indication.gsm_found_cells[idx].arfcn, out.geran_cell_search_indication.gsm_found_cells[idx].arfcn); + CU_ASSERT_EQUAL(in.geran_cell_search_indication.gsm_found_cells[idx].bsic, out.geran_cell_search_indication.gsm_found_cells[idx].bsic); + CU_ASSERT_EQUAL(in.geran_cell_search_indication.gsm_found_cells[idx].rxlev, out.geran_cell_search_indication.gsm_found_cells[idx].rxlev); + CU_ASSERT_EQUAL(in.geran_cell_search_indication.gsm_found_cells[idx].rxqual, out.geran_cell_search_indication.gsm_found_cells[idx].rxqual); + CU_ASSERT_EQUAL(in.geran_cell_search_indication.gsm_found_cells[idx].frequency_offset, out.geran_cell_search_indication.gsm_found_cells[idx].frequency_offset); + CU_ASSERT_EQUAL(in.geran_cell_search_indication.gsm_found_cells[idx].sfn_offset, out.geran_cell_search_indication.gsm_found_cells[idx].sfn_offset); + } + + CU_ASSERT_EQUAL(in.lte_cell_search_indication.tl.tag, out.lte_cell_search_indication.tl.tag); + CU_ASSERT_EQUAL(in.utran_cell_search_indication.tl.tag, out.utran_cell_search_indication.tl.tag); + CU_ASSERT_EQUAL(in.nb_iot_cell_search_indication.tl.tag, out.nb_iot_cell_search_indication.tl.tag); + CU_ASSERT_EQUAL(in.pnf_cell_search_state.tl.tag, out.pnf_cell_search_state.tl.tag); + CU_ASSERT_EQUAL(in.pnf_cell_search_state.length, out.pnf_cell_search_state.length); + + for(idx = 0; idx < out.pnf_cell_search_state.length; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_cell_search_state.value[idx], out.pnf_cell_search_state.value[idx]); + } +} + +void nfapi_test_cell_search_indication_nb_iot() +{ + uint16_t idx = 0; + nfapi_cell_search_indication_t in; + nfapi_cell_search_indication_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_CELL_SEARCH_INDICATION; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_OK; + in.nb_iot_cell_search_indication.tl.tag = NFAPI_NB_IOT_CELL_SEARCH_INDICATION_TAG; + in.nb_iot_cell_search_indication.number_of_nb_iot_cells_found = 1; + in.nb_iot_cell_search_indication.nb_iot_found_cells[0].pci = 123; + in.nb_iot_cell_search_indication.nb_iot_found_cells[0].rsrp = 2; + in.nb_iot_cell_search_indication.nb_iot_found_cells[0].rsrq = 89; + in.nb_iot_cell_search_indication.nb_iot_found_cells[0].frequency_offset = 2389; + + in.lte_cell_search_indication.tl.tag = 0; + in.utran_cell_search_indication.tl.tag = 0; + in.geran_cell_search_indication.tl.tag = 0; + + in.pnf_cell_search_state.tl.tag = NFAPI_PNF_CELL_SEARCH_STATE_TAG; + in.pnf_cell_search_state.length = 63; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + IN_OUT_ASSERT(header.message_id); + IN_OUT_ASSERT(error_code); + IN_OUT_ASSERT(nb_iot_cell_search_indication.tl.tag); + IN_OUT_ASSERT(nb_iot_cell_search_indication.number_of_nb_iot_cells_found); + + for(idx = 0; idx < out.nb_iot_cell_search_indication.number_of_nb_iot_cells_found; ++idx) + { + IN_OUT_ASSERT(nb_iot_cell_search_indication.nb_iot_found_cells[idx].pci); + IN_OUT_ASSERT(nb_iot_cell_search_indication.nb_iot_found_cells[idx].rsrp); + IN_OUT_ASSERT(nb_iot_cell_search_indication.nb_iot_found_cells[idx].rsrq); + IN_OUT_ASSERT(nb_iot_cell_search_indication.nb_iot_found_cells[idx].frequency_offset); + } + + IN_OUT_ASSERT(lte_cell_search_indication.tl.tag); + IN_OUT_ASSERT(utran_cell_search_indication.tl.tag); + IN_OUT_ASSERT(geran_cell_search_indication.tl.tag); + IN_OUT_ASSERT(pnf_cell_search_state.tl.tag); + IN_OUT_ASSERT(pnf_cell_search_state.length); + + for(idx = 0; idx < out.pnf_cell_search_state.length; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_cell_search_state.value[idx], out.pnf_cell_search_state.value[idx]); + } +} + +void nfapi_test_cell_search_request_lte_overrun() +{ + nfapi_cell_search_request_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_CELL_SEARCH_REQUEST, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push8(0, &p, end); // rat_type + + push16(NFAPI_LTE_CELL_SEARCH_REQUEST_TAG, &p, end); + push16(8, &p, end); + + push16(11, &p, end); + push8(11, &p, end); + push8(11, &p, end); + push32(11, &p, end); + push8(NFAPI_MAX_PCI_LIST + 1, &p, end); + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); + +} +void nfapi_test_cell_search_request_utran_overrun() +{ + nfapi_cell_search_request_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_CELL_SEARCH_REQUEST, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push8(NFAPI_RAT_TYPE_UTRAN, &p, end); // rat_type + + push16(NFAPI_UTRAN_CELL_SEARCH_REQUEST_TAG, &p, end); + push16(8, &p, end); + + push16(11, &p, end); + push8(11, &p, end); + push32(11, &p, end); + push8(NFAPI_MAX_PSC_LIST + 1, &p, end); + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} +void nfapi_test_cell_search_request_geran_overrun() +{ + nfapi_cell_search_request_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_CELL_SEARCH_REQUEST, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push8(NFAPI_RAT_TYPE_GERAN, &p, end); // rat_type + + push16(NFAPI_GERAN_CELL_SEARCH_REQUEST_TAG, &p, end); + push16(8, &p, end); + + push32(11, &p, end); + push8(NFAPI_MAX_ARFCN_LIST + 1, &p, end); + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} +void nfapi_test_cell_search_indication_lte_overrun() +{ + nfapi_cell_search_indication_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_CELL_SEARCH_INDICATION, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push32(0, &p, end); // error_code + + push16(NFAPI_LTE_CELL_SEARCH_INDICATION_TAG, &p, end); + push16(8, &p, end); + + push16(NFAPI_MAX_LTE_CELLS_FOUND + 1, &p, end); + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} +void nfapi_test_cell_search_indication_utran_overrun() +{ + nfapi_cell_search_indication_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_CELL_SEARCH_INDICATION, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push32(0, &p, end); // error_code + + push16(NFAPI_UTRAN_CELL_SEARCH_INDICATION_TAG, &p, end); + push16(8, &p, end); + + push16(NFAPI_MAX_UTRAN_CELLS_FOUND + 1, &p, end); + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} +void nfapi_test_cell_search_indication_geran_overrun() +{ + nfapi_cell_search_indication_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_CELL_SEARCH_INDICATION, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push32(0, &p, end); // error_code + + push16(NFAPI_GERAN_CELL_SEARCH_INDICATION_TAG, &p, end); + push16(8, &p, end); + + push16(NFAPI_MAX_GSM_CELLS_FOUND + 1, &p, end); + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} +void nfapi_test_cell_search_indication_state_overrun() +{ + nfapi_cell_search_indication_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_CELL_SEARCH_INDICATION, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push32(0, &p, end); // error_code + + push16(NFAPI_GERAN_CELL_SEARCH_INDICATION_TAG, &p, end); + push16(13, &p, end); + + push16(1, &p, end); + if(1) + { + push16(42, &p, end); + push8(42, &p, end); + push8(42, &p, end); + push8(42, &p, end); + pushs16(42, &p, end); + push32(42, &p, end); + } + + push16(NFAPI_PNF_CELL_SEARCH_STATE_TAG, &p, end); + push16(NFAPI_MAX_OPAQUE_DATA + 12, &p, end); + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} +void nfapi_test_broadcast_detect_request_lte() +{ + nfapi_broadcast_detect_request_t in; + nfapi_broadcast_detect_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_BROADCAST_DETECT_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_LTE; + + in.lte_broadcast_detect_request.tl.tag = NFAPI_LTE_BROADCAST_DETECT_REQUEST_TAG; + in.lte_broadcast_detect_request.earfcn = 123; + in.lte_broadcast_detect_request.pci = 12; + in.lte_broadcast_detect_request.timeout = 1246; + + in.pnf_cell_search_state.tl.tag = 0; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + int unpackResult = nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + CU_ASSERT_NOT_EQUAL(unpackResult, -1); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.lte_broadcast_detect_request.earfcn, out.lte_broadcast_detect_request.earfcn); + CU_ASSERT_EQUAL(in.lte_broadcast_detect_request.pci, out.lte_broadcast_detect_request.pci); + CU_ASSERT_EQUAL(in.lte_broadcast_detect_request.timeout, out.lte_broadcast_detect_request.timeout); + +} +void nfapi_test_broadcast_detect_request_utran() +{ + uint16_t idx; + nfapi_broadcast_detect_request_t in; + memset(&in, 0, sizeof(in)); + nfapi_broadcast_detect_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_BROADCAST_DETECT_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_UTRAN; + + in.utran_broadcast_detect_request.tl.tag = NFAPI_UTRAN_BROADCAST_DETECT_REQUEST_TAG; + in.utran_broadcast_detect_request.uarfcn = 123; + in.utran_broadcast_detect_request.psc = 12; + in.utran_broadcast_detect_request.timeout = 1246; + + in.pnf_cell_search_state.tl.tag = NFAPI_PNF_CELL_SEARCH_STATE_TAG; + in.pnf_cell_search_state.length = 60; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + CU_ASSERT_NOT_EQUAL(packedMessageLength, 0); + CU_ASSERT_NOT_EQUAL(packedMessageLength, -1); + + int unpackResult = nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + CU_ASSERT_NOT_EQUAL(unpackResult, 0); + CU_ASSERT_NOT_EQUAL(unpackResult, -1); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.utran_broadcast_detect_request.uarfcn, out.utran_broadcast_detect_request.uarfcn); + CU_ASSERT_EQUAL(in.utran_broadcast_detect_request.psc, out.utran_broadcast_detect_request.psc); + CU_ASSERT_EQUAL(in.utran_broadcast_detect_request.timeout, out.utran_broadcast_detect_request.timeout); + + CU_ASSERT_EQUAL(in.pnf_cell_search_state.length, out.pnf_cell_search_state.length); + + for(idx = 0; idx < out.pnf_cell_search_state.length; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_cell_search_state.value[idx], out.pnf_cell_search_state.value[idx]); + } + +} + +void nfapi_test_broadcast_detect_request_nb_iot() +{ + uint16_t idx; + nfapi_broadcast_detect_request_t in; + memset(&in, 0, sizeof(in)); + nfapi_broadcast_detect_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_BROADCAST_DETECT_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_NB_IOT; + + in.nb_iot_broadcast_detect_request.tl.tag = NFAPI_NB_IOT_BROADCAST_DETECT_REQUEST_TAG; + in.nb_iot_broadcast_detect_request.earfcn = 123; + in.nb_iot_broadcast_detect_request.ro_dl = 12; + in.nb_iot_broadcast_detect_request.pci = 12; + in.nb_iot_broadcast_detect_request.timeout = 1246; + + in.pnf_cell_search_state.tl.tag = NFAPI_PNF_CELL_SEARCH_STATE_TAG; + in.pnf_cell_search_state.length = 60; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + CU_ASSERT_NOT_EQUAL(packedMessageLength, 0); + CU_ASSERT_NOT_EQUAL(packedMessageLength, -1); + + int unpackResult = nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + CU_ASSERT_NOT_EQUAL(unpackResult, 0); + CU_ASSERT_NOT_EQUAL(unpackResult, -1); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.nb_iot_broadcast_detect_request.earfcn, out.nb_iot_broadcast_detect_request.earfcn); + CU_ASSERT_EQUAL(in.nb_iot_broadcast_detect_request.ro_dl, out.nb_iot_broadcast_detect_request.ro_dl); + CU_ASSERT_EQUAL(in.nb_iot_broadcast_detect_request.pci, out.nb_iot_broadcast_detect_request.pci); + CU_ASSERT_EQUAL(in.nb_iot_broadcast_detect_request.timeout, out.nb_iot_broadcast_detect_request.timeout); + + CU_ASSERT_EQUAL(in.pnf_cell_search_state.length, out.pnf_cell_search_state.length); + + for(idx = 0; idx < out.pnf_cell_search_state.length; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_cell_search_state.value[idx], out.pnf_cell_search_state.value[idx]); + } + +} + + +void nfapi_test_broadcast_detect_request_state_overrun() +{ + nfapi_broadcast_detect_request_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_BROADCAST_DETECT_REQUEST, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push8(NFAPI_RAT_TYPE_UTRAN, &p, end); // error_code + + push16(NFAPI_UTRAN_BROADCAST_DETECT_REQUEST_TAG, &p, end); + push16(8, &p, end); + + push16(42, &p, end); + push16(42, &p, end); + push32(42, &p, end); + + push16(NFAPI_PNF_CELL_SEARCH_STATE_TAG, &p, end); + push16(NFAPI_MAX_OPAQUE_DATA + 12, &p, end); + + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} + +void nfapi_test_broadcast_detect_response() +{ + nfapi_broadcast_detect_response_t in; + nfapi_broadcast_detect_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_BROADCAST_DETECT_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_RAT_NOT_SUPPORTED; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + +} +void nfapi_test_broadcast_detect_indication_lte() +{ + uint16_t idx; + nfapi_broadcast_detect_indication_t in; + nfapi_broadcast_detect_indication_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_BROADCAST_DETECT_INDICATION; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_RAT_NOT_SUPPORTED; + + in.lte_broadcast_detect_indication.tl.tag = NFAPI_LTE_BROADCAST_DETECT_INDICATION_TAG; + in.lte_broadcast_detect_indication.number_of_tx_antenna = 1; + in.lte_broadcast_detect_indication.mib_length = 8; + in.lte_broadcast_detect_indication.sfn_offset = 4; + in.utran_broadcast_detect_indication.tl.tag = 0; + in.pnf_cell_broadcast_state.tl.tag = NFAPI_PNF_CELL_BROADCAST_STATE_TAG; + in.pnf_cell_broadcast_state.length = 23; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.lte_broadcast_detect_indication.tl.tag, out.lte_broadcast_detect_indication.tl.tag); + CU_ASSERT_EQUAL(in.lte_broadcast_detect_indication.number_of_tx_antenna, out.lte_broadcast_detect_indication.number_of_tx_antenna); + CU_ASSERT_EQUAL(in.lte_broadcast_detect_indication.mib_length, out.lte_broadcast_detect_indication.mib_length); + for(idx = 0; idx < out.lte_broadcast_detect_indication.mib_length; ++idx) + { + CU_ASSERT_EQUAL(in.lte_broadcast_detect_indication.mib[idx], out.lte_broadcast_detect_indication.mib[idx]); + } + CU_ASSERT_EQUAL(in.lte_broadcast_detect_indication.sfn_offset, out.lte_broadcast_detect_indication.sfn_offset); + + + CU_ASSERT_EQUAL(in.utran_broadcast_detect_indication.tl.tag, out.utran_broadcast_detect_indication.tl.tag); + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.tl.tag, out.pnf_cell_broadcast_state.tl.tag); + for(idx = 0; idx < out.pnf_cell_broadcast_state.length; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.value[idx], out.pnf_cell_broadcast_state.value[idx]); + } +} +void nfapi_test_broadcast_detect_indication_lte_overrun() +{ + nfapi_broadcast_detect_indication_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_BROADCAST_DETECT_INDICATION, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push32(0, &p, end); // error_code + + push16(NFAPI_LTE_BROADCAST_DETECT_INDICATION_TAG, &p, end); + push16(8, &p, end); + + push8(1, &p, end); + push16(NFAPI_MAX_MIB_LENGTH + 1, &p, end); + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out) ,0); + CU_ASSERT_EQUAL(result, -1); +} +void nfapi_test_broadcast_detect_indication_utran() +{ + uint16_t idx; + nfapi_broadcast_detect_indication_t in; + nfapi_broadcast_detect_indication_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_BROADCAST_DETECT_INDICATION; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_RAT_NOT_SUPPORTED; + + in.lte_broadcast_detect_indication.tl.tag = 0; + in.utran_broadcast_detect_indication.tl.tag = NFAPI_UTRAN_BROADCAST_DETECT_INDICATION_TAG; + in.utran_broadcast_detect_indication.mib_length = 16; + in.utran_broadcast_detect_indication.sfn_offset = 4; + in.pnf_cell_broadcast_state.tl.tag = 0; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.lte_broadcast_detect_indication.tl.tag, out.lte_broadcast_detect_indication.tl.tag); + CU_ASSERT_EQUAL(in.utran_broadcast_detect_indication.tl.tag, out.utran_broadcast_detect_indication.tl.tag); + CU_ASSERT_EQUAL(in.utran_broadcast_detect_indication.mib_length, out.utran_broadcast_detect_indication.mib_length); + for(idx = 0; idx < out.utran_broadcast_detect_indication.mib_length; ++idx) + { + CU_ASSERT_EQUAL(in.utran_broadcast_detect_indication.mib[idx], out.utran_broadcast_detect_indication.mib[idx]); + } + CU_ASSERT_EQUAL(in.utran_broadcast_detect_indication.sfn_offset, out.utran_broadcast_detect_indication.sfn_offset); + + + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.tl.tag, out.pnf_cell_broadcast_state.tl.tag); +} +void nfapi_test_broadcast_detect_indication_nb_iot() +{ + uint16_t idx; + nfapi_broadcast_detect_indication_t in; + nfapi_broadcast_detect_indication_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_BROADCAST_DETECT_INDICATION; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_RAT_NOT_SUPPORTED; + + in.lte_broadcast_detect_indication.tl.tag = 0; + in.utran_broadcast_detect_indication.tl.tag = 0; + in.nb_iot_broadcast_detect_indication.tl.tag = NFAPI_NB_IOT_BROADCAST_DETECT_INDICATION_TAG; + in.nb_iot_broadcast_detect_indication.number_of_tx_antenna = 2; + in.nb_iot_broadcast_detect_indication.mib_length = 16; + in.nb_iot_broadcast_detect_indication.sfn_offset = 4; + in.pnf_cell_broadcast_state.tl.tag = 0; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.lte_broadcast_detect_indication.tl.tag, out.lte_broadcast_detect_indication.tl.tag); + CU_ASSERT_EQUAL(in.utran_broadcast_detect_indication.tl.tag, out.utran_broadcast_detect_indication.tl.tag); + CU_ASSERT_EQUAL(in.nb_iot_broadcast_detect_indication.tl.tag, out.nb_iot_broadcast_detect_indication.tl.tag); + CU_ASSERT_EQUAL(in.nb_iot_broadcast_detect_indication.number_of_tx_antenna, out.nb_iot_broadcast_detect_indication.number_of_tx_antenna); + CU_ASSERT_EQUAL(in.nb_iot_broadcast_detect_indication.mib_length, out.nb_iot_broadcast_detect_indication.mib_length); + for(idx = 0; idx < out.nb_iot_broadcast_detect_indication.mib_length; ++idx) + { + CU_ASSERT_EQUAL(in.nb_iot_broadcast_detect_indication.mib[idx], out.nb_iot_broadcast_detect_indication.mib[idx]); + } + CU_ASSERT_EQUAL(in.nb_iot_broadcast_detect_indication.sfn_offset, out.nb_iot_broadcast_detect_indication.sfn_offset); + + + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.tl.tag, out.pnf_cell_broadcast_state.tl.tag); +} +void nfapi_test_broadcast_detect_indication_utran_overrun() +{ + nfapi_broadcast_detect_indication_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_BROADCAST_DETECT_INDICATION, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push32(0, &p, end); // error_code + + push16(NFAPI_UTRAN_BROADCAST_DETECT_INDICATION_TAG, &p, end); + push16(8, &p, end); + + push16(NFAPI_MAX_MIB_LENGTH + 1, &p, end); + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} +void nfapi_test_broadcast_detect_indication_state_overrun() +{ +} +void nfapi_test_system_information_schedule_request_lte() +{ + uint16_t idx; + nfapi_system_information_schedule_request_t in; + nfapi_system_information_schedule_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_SYSTEM_INFORMATION_SCHEDULE_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_LTE; + + in.nb_iot_system_information_schedule_request.tl.tag = 0; + + in.lte_system_information_schedule_request.tl.tag = NFAPI_LTE_SYSTEM_INFORMATION_SCHEDULE_REQUEST_TAG; + in.lte_system_information_schedule_request.earfcn = 16; + in.lte_system_information_schedule_request.pci = 4; + in.lte_system_information_schedule_request.downlink_channel_bandwidth = 20; + in.lte_system_information_schedule_request.phich_configuration = 1; + in.lte_system_information_schedule_request.number_of_tx_antenna = 2; + in.lte_system_information_schedule_request.retry_count = 4; + in.lte_system_information_schedule_request.timeout = 0; + in.pnf_cell_broadcast_state.tl.tag = NFAPI_PNF_CELL_BROADCAST_STATE_TAG; + in.pnf_cell_broadcast_state.length = 7; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.lte_system_information_schedule_request.tl.tag, out.lte_system_information_schedule_request.tl.tag); + CU_ASSERT_EQUAL(in.lte_system_information_schedule_request.earfcn, out.lte_system_information_schedule_request.earfcn); + CU_ASSERT_EQUAL(in.lte_system_information_schedule_request.pci, out.lte_system_information_schedule_request.pci); + CU_ASSERT_EQUAL(in.lte_system_information_schedule_request.downlink_channel_bandwidth, out.lte_system_information_schedule_request.downlink_channel_bandwidth); + CU_ASSERT_EQUAL(in.lte_system_information_schedule_request.downlink_channel_bandwidth, out.lte_system_information_schedule_request.downlink_channel_bandwidth); + CU_ASSERT_EQUAL(in.lte_system_information_schedule_request.number_of_tx_antenna, out.lte_system_information_schedule_request.number_of_tx_antenna); + CU_ASSERT_EQUAL(in.lte_system_information_schedule_request.retry_count, out.lte_system_information_schedule_request.retry_count); + CU_ASSERT_EQUAL(in.lte_system_information_schedule_request.timeout, out.lte_system_information_schedule_request.timeout); + + + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.tl.tag, out.pnf_cell_broadcast_state.tl.tag); + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.length, out.pnf_cell_broadcast_state.length); + for(idx = 0; idx < out.pnf_cell_broadcast_state.length; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.value[idx], out.pnf_cell_broadcast_state.value[idx]); + } +} + +void nfapi_test_system_information_schedule_request_nb_iot() +{ + uint16_t idx; + nfapi_system_information_schedule_request_t in; + nfapi_system_information_schedule_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_SYSTEM_INFORMATION_SCHEDULE_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_NB_IOT; + + in.lte_system_information_schedule_request.tl.tag = 0; + in.nb_iot_system_information_schedule_request.tl.tag = NFAPI_NB_IOT_SYSTEM_INFORMATION_SCHEDULE_REQUEST_TAG; + in.nb_iot_system_information_schedule_request.earfcn = 16; + in.nb_iot_system_information_schedule_request.ro_dl = 4; + in.nb_iot_system_information_schedule_request.pci = 4; + in.nb_iot_system_information_schedule_request.scheduling_info_sib1_nb = 4; + in.nb_iot_system_information_schedule_request.timeout = 0; + in.pnf_cell_broadcast_state.tl.tag = NFAPI_PNF_CELL_BROADCAST_STATE_TAG; + in.pnf_cell_broadcast_state.length = 7; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.lte_system_information_schedule_request.tl.tag, out.lte_system_information_schedule_request.tl.tag); + CU_ASSERT_EQUAL(in.nb_iot_system_information_schedule_request.tl.tag, out.nb_iot_system_information_schedule_request.tl.tag); + CU_ASSERT_EQUAL(in.nb_iot_system_information_schedule_request.earfcn, out.nb_iot_system_information_schedule_request.earfcn); + CU_ASSERT_EQUAL(in.nb_iot_system_information_schedule_request.ro_dl, out.nb_iot_system_information_schedule_request.ro_dl); + CU_ASSERT_EQUAL(in.nb_iot_system_information_schedule_request.pci, out.nb_iot_system_information_schedule_request.pci); + CU_ASSERT_EQUAL(in.nb_iot_system_information_schedule_request.scheduling_info_sib1_nb, out.nb_iot_system_information_schedule_request.scheduling_info_sib1_nb); + CU_ASSERT_EQUAL(in.nb_iot_system_information_schedule_request.timeout, out.nb_iot_system_information_schedule_request.timeout); + + + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.tl.tag, out.pnf_cell_broadcast_state.tl.tag); + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.length, out.pnf_cell_broadcast_state.length); + for(idx = 0; idx < out.pnf_cell_broadcast_state.length; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.value[idx], out.pnf_cell_broadcast_state.value[idx]); + } +} + +void nfapi_test_system_information_schedule_request_state_overrun() +{ + nfapi_system_information_schedule_request_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_SYSTEM_INFORMATION_SCHEDULE_REQUEST, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push8(0, &p, end); // rat type + + push16(NFAPI_LTE_SYSTEM_INFORMATION_SCHEDULE_REQUEST_TAG, &p, end); + push16(13, &p, end); + + push16(1, &p, end); + push16(1, &p, end); + push16(1, &p, end); + push8(142, &p, end); + push8(142, &p, end); + push8(142, &p, end); + push32(42, &p, end); + + push16(NFAPI_PNF_CELL_BROADCAST_STATE_TAG, &p, end); + push16(NFAPI_MAX_OPAQUE_DATA + 1, &p, end); + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); + +} +void nfapi_test_system_information_schedule_response() +{ + nfapi_system_information_schedule_response_t in; + nfapi_system_information_schedule_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_RAT_NOT_SUPPORTED; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); +} +void nfapi_test_system_information_schedule_indication_lte() +{ + uint16_t idx; + nfapi_system_information_schedule_indication_t in; + nfapi_system_information_schedule_indication_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_SYSTEM_INFORMATION_SCHEDULE_INDICATION; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = 0; + + in.nb_iot_system_information_indication.tl.tag = 0; + in.lte_system_information_indication.tl.tag = NFAPI_LTE_SYSTEM_INFORMATION_INDICATION_TAG; + in.lte_system_information_indication.sib_type = 16; + in.lte_system_information_indication.sib_length = 4; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.lte_system_information_indication.tl.tag, out.lte_system_information_indication.tl.tag); + CU_ASSERT_EQUAL(in.lte_system_information_indication.sib_type, out.lte_system_information_indication.sib_type); + CU_ASSERT_EQUAL(in.lte_system_information_indication.sib_length, out.lte_system_information_indication.sib_length); + + for(idx = 0; idx < out.lte_system_information_indication.sib_length; ++idx) + { + CU_ASSERT_EQUAL(in.lte_system_information_indication.sib[idx], out.lte_system_information_indication.sib[idx]); + } +} +void nfapi_test_system_information_schedule_indication_nb_iot() +{ + uint16_t idx; + nfapi_system_information_schedule_indication_t in; + nfapi_system_information_schedule_indication_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_SYSTEM_INFORMATION_SCHEDULE_INDICATION; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = 0; + + in.lte_system_information_indication.tl.tag = 0; + in.nb_iot_system_information_indication.tl.tag = NFAPI_NB_IOT_SYSTEM_INFORMATION_INDICATION_TAG; + in.nb_iot_system_information_indication.sib_type = 16; + in.nb_iot_system_information_indication.sib_length = 4; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.lte_system_information_indication.tl.tag, out.lte_system_information_indication.tl.tag); + CU_ASSERT_EQUAL(in.nb_iot_system_information_indication.tl.tag, out.nb_iot_system_information_indication.tl.tag); + CU_ASSERT_EQUAL(in.nb_iot_system_information_indication.sib_type, out.nb_iot_system_information_indication.sib_type); + CU_ASSERT_EQUAL(in.nb_iot_system_information_indication.sib_length, out.nb_iot_system_information_indication.sib_length); + + for(idx = 0; idx < out.nb_iot_system_information_indication.sib_length; ++idx) + { + CU_ASSERT_EQUAL(in.nb_iot_system_information_indication.sib[idx], out.nb_iot_system_information_indication.sib[idx]); + } +} +void nfapi_test_system_information_request_lte() +{ + uint16_t idx; + nfapi_system_information_request_t in; + nfapi_system_information_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_SYSTEM_INFORMATION_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_LTE; + + in.lte_system_information_request.tl.tag = NFAPI_LTE_SYSTEM_INFORMATION_REQUEST_TAG; + in.lte_system_information_request.earfcn = 16; + in.lte_system_information_request.pci = 4; + in.lte_system_information_request.downlink_channel_bandwidth = 20; + in.lte_system_information_request.phich_configuration = 1; + in.lte_system_information_request.number_of_tx_antenna = 2; + in.lte_system_information_request.number_of_si_periodicity = 1; + in.lte_system_information_request.si_periodicity[0].si_periodicity = 3; + in.lte_system_information_request.si_periodicity[0].si_index = 0; + in.lte_system_information_request.si_window_length = 0; + in.lte_system_information_request.timeout = 2000; + + in.pnf_cell_broadcast_state.tl.tag = NFAPI_PNF_CELL_BROADCAST_STATE_TAG; + in.pnf_cell_broadcast_state.length = 7; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.lte_system_information_request.tl.tag, out.lte_system_information_request.tl.tag); + CU_ASSERT_EQUAL(in.lte_system_information_request.earfcn, out.lte_system_information_request.earfcn); + CU_ASSERT_EQUAL(in.lte_system_information_request.pci, out.lte_system_information_request.pci); + CU_ASSERT_EQUAL(in.lte_system_information_request.downlink_channel_bandwidth, out.lte_system_information_request.downlink_channel_bandwidth); + CU_ASSERT_EQUAL(in.lte_system_information_request.downlink_channel_bandwidth, out.lte_system_information_request.downlink_channel_bandwidth); + CU_ASSERT_EQUAL(in.lte_system_information_request.number_of_tx_antenna, out.lte_system_information_request.number_of_tx_antenna); + CU_ASSERT_EQUAL(in.lte_system_information_request.number_of_si_periodicity, out.lte_system_information_request.number_of_si_periodicity); + for(idx = 0; idx < in.lte_system_information_request.number_of_si_periodicity; ++idx) + { + CU_ASSERT_EQUAL(in.lte_system_information_request.si_periodicity[idx].si_periodicity, out.lte_system_information_request.si_periodicity[idx].si_periodicity); + CU_ASSERT_EQUAL(in.lte_system_information_request.si_periodicity[idx].si_index, out.lte_system_information_request.si_periodicity[idx].si_index); + } + + CU_ASSERT_EQUAL(in.lte_system_information_request.si_window_length, out.lte_system_information_request.si_window_length); + CU_ASSERT_EQUAL(in.lte_system_information_request.timeout, out.lte_system_information_request.timeout); + + + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.tl.tag, out.pnf_cell_broadcast_state.tl.tag); + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.length, out.pnf_cell_broadcast_state.length); + for(idx = 0; idx < out.pnf_cell_broadcast_state.length; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.value[idx], out.pnf_cell_broadcast_state.value[idx]); + } +} +void nfapi_test_system_information_request_lte_overrun() +{ + nfapi_system_information_request_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_SYSTEM_INFORMATION_REQUEST, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push8(NFAPI_RAT_TYPE_LTE, &p, end); + + push16(NFAPI_LTE_SYSTEM_INFORMATION_REQUEST_TAG, &p, end); + push16(8, &p, end); + + push16(8, &p, end); + push16(8, &p, end); + push16(8, &p, end); + push8(8, &p, end); + push8(8, &p, end); + push8(NFAPI_MAX_SI_PERIODICITY + 1, &p, end); + + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} +void nfapi_test_system_information_request_utran() +{ + nfapi_system_information_request_t in; + nfapi_system_information_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_SYSTEM_INFORMATION_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_UTRAN; + + in.utran_system_information_request.tl.tag = NFAPI_UTRAN_SYSTEM_INFORMATION_REQUEST_TAG; + in.utran_system_information_request.uarfcn = 16; + in.utran_system_information_request.psc = 4; + in.utran_system_information_request.timeout = 2000; + + in.pnf_cell_broadcast_state.tl.tag = 0; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.utran_system_information_request.tl.tag, out.utran_system_information_request.tl.tag); + CU_ASSERT_EQUAL(in.utran_system_information_request.uarfcn, out.utran_system_information_request.uarfcn); + CU_ASSERT_EQUAL(in.utran_system_information_request.psc, out.utran_system_information_request.psc); + CU_ASSERT_EQUAL(in.utran_system_information_request.timeout, out.utran_system_information_request.timeout); + + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.tl.tag, out.pnf_cell_broadcast_state.tl.tag); +} +void nfapi_test_system_information_request_geran() +{ + nfapi_system_information_request_t in; + nfapi_system_information_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_SYSTEM_INFORMATION_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_GERAN; + + in.geran_system_information_request.tl.tag = NFAPI_GERAN_SYSTEM_INFORMATION_REQUEST_TAG; + in.geran_system_information_request.arfcn = 16; + in.geran_system_information_request.bsic = 4; + in.geran_system_information_request.timeout = 2000; + + in.pnf_cell_broadcast_state.tl.tag = 0; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.rat_type, out.rat_type); + CU_ASSERT_EQUAL(in.geran_system_information_request.tl.tag, out.geran_system_information_request.tl.tag); + CU_ASSERT_EQUAL(in.geran_system_information_request.arfcn, out.geran_system_information_request.arfcn); + CU_ASSERT_EQUAL(in.geran_system_information_request.bsic, out.geran_system_information_request.bsic); + CU_ASSERT_EQUAL(in.geran_system_information_request.timeout, out.geran_system_information_request.timeout); + + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.tl.tag, out.pnf_cell_broadcast_state.tl.tag); +} +void nfapi_test_system_information_request_state_overrun() +{ + nfapi_system_information_request_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_SYSTEM_INFORMATION_REQUEST, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push8(NFAPI_RAT_TYPE_LTE, &p, end); + + push16(NFAPI_LTE_SYSTEM_INFORMATION_REQUEST_TAG, &p, end); + push16(16, &p, end); + + push16(8, &p, end); + push16(8, &p, end); + push16(8, &p, end); + push8(8, &p, end); + push8(8, &p, end); + push8(1, &p, end); + { + push8(1, &p, end); + push8(1, &p, end); + } + push8(1, &p, end); + push32(1, &p, end); + + push16(NFAPI_PNF_CELL_BROADCAST_STATE_TAG, &p, end); + push16(NFAPI_MAX_OPAQUE_DATA + 1, &p, end); + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} + +void nfapi_test_system_information_request_nb_iot() +{ + uint16_t idx, idx2; + nfapi_system_information_request_t in; + nfapi_system_information_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_SYSTEM_INFORMATION_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.rat_type = NFAPI_RAT_TYPE_NB_IOT; + + in.nb_iot_system_information_request.tl.tag = NFAPI_NB_IOT_SYSTEM_INFORMATION_REQUEST_TAG; + in.nb_iot_system_information_request.earfcn = 16; + in.nb_iot_system_information_request.ro_dl = 1; + in.nb_iot_system_information_request.pci = 4; + in.nb_iot_system_information_request.number_of_si_periodicity = 1; + in.nb_iot_system_information_request.si_periodicity[0].si_periodicity = 3; + in.nb_iot_system_information_request.si_periodicity[0].si_repetition_pattern = 0; + in.nb_iot_system_information_request.si_periodicity[0].si_tb_size = 0; + in.nb_iot_system_information_request.si_periodicity[0].number_of_si_index = 2; + in.nb_iot_system_information_request.si_periodicity[0].si_index[0] = 2; + in.nb_iot_system_information_request.si_periodicity[0].si_index[1] = 20; + in.nb_iot_system_information_request.si_window_length = 0; + in.nb_iot_system_information_request.timeout = 2000; + + in.pnf_cell_broadcast_state.tl.tag = NFAPI_PNF_CELL_BROADCAST_STATE_TAG; + in.pnf_cell_broadcast_state.length = 7; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + IN_OUT_ASSERT(header.message_id); + IN_OUT_ASSERT(rat_type); + IN_OUT_ASSERT(nb_iot_system_information_request.tl.tag); + IN_OUT_ASSERT(nb_iot_system_information_request.earfcn); + IN_OUT_ASSERT(nb_iot_system_information_request.ro_dl); + IN_OUT_ASSERT(nb_iot_system_information_request.pci); + IN_OUT_ASSERT(nb_iot_system_information_request.number_of_si_periodicity); + + for(idx = 0; idx < in.nb_iot_system_information_request.number_of_si_periodicity; ++idx) + { + IN_OUT_ASSERT(nb_iot_system_information_request.si_periodicity[idx].si_periodicity); + IN_OUT_ASSERT(nb_iot_system_information_request.si_periodicity[idx].si_repetition_pattern); + IN_OUT_ASSERT(nb_iot_system_information_request.si_periodicity[idx].si_tb_size); + IN_OUT_ASSERT(nb_iot_system_information_request.si_periodicity[idx].number_of_si_index); + + for(idx2 = 0; idx2 < in.nb_iot_system_information_request.si_periodicity[idx].number_of_si_index; ++idx2) + IN_OUT_ASSERT(nb_iot_system_information_request.si_periodicity[idx].si_index[idx2]); + } + + IN_OUT_ASSERT(nb_iot_system_information_request.si_window_length); + IN_OUT_ASSERT(nb_iot_system_information_request.timeout); + + + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.tl.tag, out.pnf_cell_broadcast_state.tl.tag); + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.length, out.pnf_cell_broadcast_state.length); + for(idx = 0; idx < out.pnf_cell_broadcast_state.length; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_cell_broadcast_state.value[idx], out.pnf_cell_broadcast_state.value[idx]); + } +} + + +void nfapi_test_system_information_response() +{ + nfapi_system_information_response_t in; + nfapi_system_information_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_SYSTEM_INFORMATION_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_RAT_NOT_SUPPORTED; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); +} +void nfapi_test_system_information_indication_lte() +{ + uint16_t idx; + nfapi_system_information_indication_t in; + nfapi_system_information_indication_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_SYSTEM_INFORMATION_INDICATION; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_RAT_NOT_SUPPORTED; + in.lte_system_information_indication.tl.tag = NFAPI_LTE_SYSTEM_INFORMATION_INDICATION_TAG; + in.lte_system_information_indication.sib_type = 2; + in.lte_system_information_indication.sib_length = 15; + + in.utran_system_information_indication.tl.tag = 0; + in.geran_system_information_indication.tl.tag = 0; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.lte_system_information_indication.tl.tag, out.lte_system_information_indication.tl.tag); + CU_ASSERT_EQUAL(in.lte_system_information_indication.sib_type, out.lte_system_information_indication.sib_type); + CU_ASSERT_EQUAL(in.lte_system_information_indication.sib_length, out.lte_system_information_indication.sib_length); + + for(idx = 0; idx < out.lte_system_information_indication.sib_length; ++idx) + { + CU_ASSERT_EQUAL(in.lte_system_information_indication.sib[idx], out.lte_system_information_indication.sib[idx]); + } + + CU_ASSERT_EQUAL(in.utran_system_information_indication.tl.tag, out.utran_system_information_indication.tl.tag); + CU_ASSERT_EQUAL(in.geran_system_information_indication.tl.tag, out.geran_system_information_indication.tl.tag); + +} +void nfapi_test_system_information_indication_lte_overrun() +{ + nfapi_system_information_indication_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_SYSTEM_INFORMATION_INDICATION, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push32(0, &p, end); // error code + + push16(NFAPI_LTE_SYSTEM_INFORMATION_INDICATION_TAG, &p, end); + push16(8, &p, end); + + push8(1, &p, end); + push16(NFAPI_MAX_SIB_LENGTH + 1, &p, end); + + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} +void nfapi_test_system_information_indication_utran() +{ + uint16_t idx; + nfapi_system_information_indication_t in; + nfapi_system_information_indication_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_SYSTEM_INFORMATION_INDICATION; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_RAT_NOT_SUPPORTED; + in.lte_system_information_indication.tl.tag = 0; + + in.utran_system_information_indication.tl.tag = NFAPI_UTRAN_SYSTEM_INFORMATION_INDICATION_TAG; + in.utran_system_information_indication.sib_length = 25; + + in.geran_system_information_indication.tl.tag = 0; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.lte_system_information_indication.tl.tag, out.lte_system_information_indication.tl.tag); + CU_ASSERT_EQUAL(in.utran_system_information_indication.tl.tag, out.utran_system_information_indication.tl.tag); + CU_ASSERT_EQUAL(in.utran_system_information_indication.sib_length, out.utran_system_information_indication.sib_length); + + for(idx = 0; idx < out.utran_system_information_indication.sib_length; ++idx) + { + CU_ASSERT_EQUAL(in.utran_system_information_indication.sib[idx], out.utran_system_information_indication.sib[idx]); + } + + CU_ASSERT_EQUAL(in.geran_system_information_indication.tl.tag, out.geran_system_information_indication.tl.tag); + +} +void nfapi_test_system_information_indication_utran_overrun() +{ + nfapi_system_information_indication_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_SYSTEM_INFORMATION_INDICATION, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push32(0, &p, end); // error code + + push16(NFAPI_UTRAN_SYSTEM_INFORMATION_INDICATION_TAG, &p, end); + push16(8, &p, end); + + push16(NFAPI_MAX_SIB_LENGTH + 1, &p, end); + + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} +void nfapi_test_system_information_indication_geran() +{ + uint16_t idx; + nfapi_system_information_indication_t in; + nfapi_system_information_indication_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_SYSTEM_INFORMATION_INDICATION; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_RAT_NOT_SUPPORTED; + in.lte_system_information_indication.tl.tag = 0; + in.utran_system_information_indication.tl.tag = 0; + + in.geran_system_information_indication.tl.tag = NFAPI_GERAN_SYSTEM_INFORMATION_INDICATION_TAG; + in.geran_system_information_indication.si_length = 25; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.lte_system_information_indication.tl.tag, out.lte_system_information_indication.tl.tag); + CU_ASSERT_EQUAL(in.utran_system_information_indication.tl.tag, out.utran_system_information_indication.tl.tag); + CU_ASSERT_EQUAL(in.geran_system_information_indication.tl.tag, out.geran_system_information_indication.tl.tag); + CU_ASSERT_EQUAL(in.geran_system_information_indication.si_length, out.geran_system_information_indication.si_length); + + for(idx = 0; idx < out.geran_system_information_indication.si_length; ++idx) + { + CU_ASSERT_EQUAL(in.geran_system_information_indication.si[idx], out.geran_system_information_indication.si[idx]); + } + +} +void nfapi_test_system_information_indication_geran_overrun() +{ + nfapi_system_information_indication_t out; + + uint8_t buffer[1024]; + uint8_t* p = &buffer[0]; + uint8_t *end = p + 1024; + push16(0, &p, end); + push16(NFAPI_SYSTEM_INFORMATION_INDICATION, &p, end); + push16(64, &p, end); + push16(0, &p, end); + + push32(0, &p, end); // error code + + push16(NFAPI_GERAN_SYSTEM_INFORMATION_INDICATION_TAG, &p, end); + push16(8, &p, end); + + push16(NFAPI_MAX_SI_LENGTH + 1, &p, end); + + + int result = nfapi_p4_message_unpack(buffer, 34, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(result, -1); +} + +void nfapi_test_system_information_indication_nb_iot() +{ + uint16_t idx; + nfapi_system_information_indication_t in; + nfapi_system_information_indication_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_SYSTEM_INFORMATION_INDICATION; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_RAT_NOT_SUPPORTED; + in.nb_iot_system_information_indication.tl.tag = NFAPI_NB_IOT_SYSTEM_INFORMATION_INDICATION_TAG; + in.nb_iot_system_information_indication.sib_type = 2; + in.nb_iot_system_information_indication.sib_length = 15; + + in.lte_system_information_indication.tl.tag = 0; + in.utran_system_information_indication.tl.tag = 0; + in.geran_system_information_indication.tl.tag = 0; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.nb_iot_system_information_indication.tl.tag, out.nb_iot_system_information_indication.tl.tag); + CU_ASSERT_EQUAL(in.nb_iot_system_information_indication.sib_type, out.nb_iot_system_information_indication.sib_type); + CU_ASSERT_EQUAL(in.nb_iot_system_information_indication.sib_length, out.nb_iot_system_information_indication.sib_length); + + for(idx = 0; idx < out.nb_iot_system_information_indication.sib_length; ++idx) + { + CU_ASSERT_EQUAL(in.nb_iot_system_information_indication.sib[idx], out.nb_iot_system_information_indication.sib[idx]); + } + + CU_ASSERT_EQUAL(in.lte_system_information_indication.tl.tag, out.lte_system_information_indication.tl.tag); + CU_ASSERT_EQUAL(in.utran_system_information_indication.tl.tag, out.utran_system_information_indication.tl.tag); + CU_ASSERT_EQUAL(in.geran_system_information_indication.tl.tag, out.geran_system_information_indication.tl.tag); + +} + +void nfapi_test_nmm_stop_request() +{ + nfapi_nmm_stop_request_t in; + nfapi_nmm_stop_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_NMM_STOP_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); +} +void nfapi_test_nmm_stop_response() +{ + nfapi_nmm_stop_response_t in; + nfapi_nmm_stop_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_NMM_STOP_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_P4_MSG_RAT_NOT_SUPPORTED; + + int packedMessageLength = nfapi_p4_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p4_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); +} + + +void nfapi_test_pnf_param_request() +{ + nfapi_pnf_param_request_t in; + memset(&in, 0, sizeof(in)); + nfapi_pnf_param_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_PNF_PARAM_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); +} +void nfapi_test_pnf_param_request_ve() +{ + nfapi_pnf_param_request_t in; + memset(&in, 0, sizeof(in)); + nfapi_pnf_param_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_PNF_PARAM_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + my_vendor_extention ve; + ve.tl.tag = NFAPI_VENDOR_EXTENSION_MIN_TAG_VALUE; + ve.value1 = 56; + ve.value2 = 1234; + in.vendor_extension = (void*)&ve; + + nfapi_p4_p5_codec_config_t codec; + memset(&codec, 0, sizeof(codec)); + codec.unpack_vendor_extension_tlv = &nfapi_test_unpack_vendor_extension_tlv; + codec.pack_vendor_extension_tlv = &nfapi_test_pack_vendor_extension_tlv; + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, &codec); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), &codec); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + + CU_ASSERT_NOT_EQUAL(in.vendor_extension, 0); + CU_ASSERT_EQUAL(((my_vendor_extention*)(out.vendor_extension))->tl.tag, ve.tl.tag); + CU_ASSERT_EQUAL(((my_vendor_extention*)(out.vendor_extension))->value1, ve.value1); + CU_ASSERT_EQUAL(((my_vendor_extention*)(out.vendor_extension))->value2, ve.value2); + + free(out.vendor_extension); +} +void nfapi_test_pnf_param_response() +{ + uint16_t idx = 0; + uint16_t idx2 = 0; + nfapi_pnf_param_response_t in; + memset(&in, 0, sizeof(in)); + nfapi_pnf_param_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_PNF_PARAM_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = 0; + in.pnf_param_general.tl.tag = NFAPI_PNF_PARAM_GENERAL_TAG; + in.pnf_param_general.nfapi_sync_mode = 2; + in.pnf_param_general.location_mode = 1; + in.pnf_param_general.location_coordinates_length = 1; + in.pnf_param_general.location_coordinates[0] = 123; + in.pnf_param_general.dl_config_timing = 12; + in.pnf_param_general.tx_timing = 12; + in.pnf_param_general.ul_config_timing = 12; + in.pnf_param_general.hi_dci0_timing = 12; + in.pnf_param_general.maximum_number_phys = 2; + in.pnf_param_general.maximum_total_bandwidth = 100; + in.pnf_param_general.maximum_total_number_dl_layers = 2; + in.pnf_param_general.maximum_total_number_ul_layers = 2; + in.pnf_param_general.shared_bands = 0; + in.pnf_param_general.shared_pa = 0; + in.pnf_param_general.maximum_total_power = -190; + in.pnf_param_general.oui[0] = 88; + + in.pnf_phy.tl.tag = NFAPI_PNF_PHY_TAG; + in.pnf_phy.number_of_phys = 2; + in.pnf_phy.phy[0].phy_config_index = 0; + in.pnf_phy.phy[0].number_of_rfs = 2; + in.pnf_phy.phy[0].rf_config[0].rf_config_index = 0; + in.pnf_phy.phy[0].number_of_rf_exclusions = 1; + in.pnf_phy.phy[0].rf_config[0].rf_config_index = 1; + in.pnf_phy.phy[0].downlink_channel_bandwidth_supported = 20; + in.pnf_phy.phy[0].uplink_channel_bandwidth_supported = 20; + in.pnf_phy.phy[0].number_of_dl_layers_supported = 2; + in.pnf_phy.phy[0].number_of_ul_layers_supported = 1; + in.pnf_phy.phy[0].maximum_3gpp_release_supported = 3; + in.pnf_phy.phy[0].nmm_modes_supported = 2; + + in.pnf_rf.tl.tag = NFAPI_PNF_RF_TAG; + in.pnf_rf.number_of_rfs = 2; + in.pnf_rf.rf[0].rf_config_index = 0; + in.pnf_rf.rf[0].band = 1; + in.pnf_rf.rf[0].maximum_transmit_power = -100; + in.pnf_rf.rf[0].minimum_transmit_power = -90; + in.pnf_rf.rf[0].number_of_antennas_suppported = 4; + in.pnf_rf.rf[0].minimum_downlink_frequency = 100; + in.pnf_rf.rf[0].maximum_downlink_frequency = 2132; + in.pnf_rf.rf[0].minimum_uplink_frequency = 1231; + in.pnf_rf.rf[0].maximum_uplink_frequency = 123; + + + in.pnf_phy_rel10.tl.tag = NFAPI_PNF_PHY_REL10_TAG; + in.pnf_phy_rel10.number_of_phys = 2; + in.pnf_phy_rel10.phy[0].phy_config_index = 0; + in.pnf_phy_rel10.phy[0].transmission_mode_7_supported = 1; + in.pnf_phy_rel10.phy[0].transmission_mode_8_supported = 2; + in.pnf_phy_rel10.phy[0].two_antenna_ports_for_pucch = 3; + in.pnf_phy_rel10.phy[0].transmission_mode_9_supported = 4; + in.pnf_phy_rel10.phy[0].simultaneous_pucch_pusch = 5; + in.pnf_phy_rel10.phy[0].four_layer_tx_with_tm3_and_tm4 = 6; + + in.pnf_phy_rel11.tl.tag = NFAPI_PNF_PHY_REL11_TAG; + in.pnf_phy_rel11.number_of_phys = 2; + in.pnf_phy_rel11.phy[0].phy_config_index = 0; + in.pnf_phy_rel11.phy[0].edpcch_supported = 1; + in.pnf_phy_rel11.phy[0].multi_ack_csi_reporting = 2; + in.pnf_phy_rel11.phy[0].pucch_tx_diversity = 3; + in.pnf_phy_rel11.phy[0].ul_comp_supported = 4; + in.pnf_phy_rel11.phy[0].transmission_mode_5_supported = 5; + + in.pnf_phy_rel12.tl.tag = NFAPI_PNF_PHY_REL12_TAG; + in.pnf_phy_rel12.number_of_phys = 2; + in.pnf_phy_rel12.phy[0].phy_config_index = 0; + in.pnf_phy_rel12.phy[0].csi_subframe_set = 1; + in.pnf_phy_rel12.phy[0].enhanced_4tx_codebook = 2; + in.pnf_phy_rel12.phy[0].drs_supported = 3; + in.pnf_phy_rel12.phy[0].ul_64qam_supported = 4; + in.pnf_phy_rel12.phy[0].transmission_mode_10_supported = 5; + in.pnf_phy_rel12.phy[0].alternative_bts_indices = 6; + + in.pnf_phy_rel13.tl.tag = NFAPI_PNF_PHY_REL13_TAG; + in.pnf_phy_rel13.number_of_phys = 2; + in.pnf_phy_rel13.phy[0].phy_config_index = 0; + in.pnf_phy_rel13.phy[0].pucch_format4_supported = 1; + in.pnf_phy_rel13.phy[0].pucch_format5_supported = 2; + in.pnf_phy_rel13.phy[0].more_than_5_ca_support = 3; + in.pnf_phy_rel13.phy[0].laa_supported = 4; + in.pnf_phy_rel13.phy[0].laa_ending_in_dwpts_supported = 5; + in.pnf_phy_rel13.phy[0].laa_starting_in_second_slot_supported = 6; + in.pnf_phy_rel13.phy[0].beamforming_supported = 7; + in.pnf_phy_rel13.phy[0].csi_rs_enhancement_supported = 8; + in.pnf_phy_rel13.phy[0].drms_enhancement_supported = 9; + in.pnf_phy_rel13.phy[0].srs_enhancement_supported = 10; + + in.pnf_phy_rel13_nb_iot.tl.tag = NFAPI_PNF_PHY_REL13_NB_IOT_TAG; + in.pnf_phy_rel13_nb_iot.number_of_phys = 2; + in.pnf_phy_rel13_nb_iot.phy[0].phy_config_index = 0; + in.pnf_phy_rel13_nb_iot.phy[0].number_of_rfs = 2; + in.pnf_phy_rel13_nb_iot.phy[0].rf_config[0].rf_config_index = 0; + in.pnf_phy_rel13_nb_iot.phy[0].number_of_rf_exclusions = 1; + in.pnf_phy_rel13_nb_iot.phy[0].rf_config[0].rf_config_index = 1; + in.pnf_phy_rel13_nb_iot.phy[0].number_of_dl_layers_supported = 2; + in.pnf_phy_rel13_nb_iot.phy[0].number_of_ul_layers_supported = 1; + in.pnf_phy_rel13_nb_iot.phy[0].maximum_3gpp_release_supported = 3; + in.pnf_phy_rel13_nb_iot.phy[0].nmm_modes_supported = 2; + + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + int unpack_result = nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(unpack_result, 1); + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.pnf_param_general.tl.tag, out.pnf_param_general.tl.tag); + CU_ASSERT_EQUAL(in.pnf_param_general.nfapi_sync_mode, out.pnf_param_general.nfapi_sync_mode); + CU_ASSERT_EQUAL(in.pnf_param_general.location_mode, out.pnf_param_general.location_mode); + + for(idx = 0; idx < NFAPI_PNF_PARAM_GENERAL_LOCATION_LENGTH; ++idx) + CU_ASSERT_EQUAL(in.pnf_param_general.location_coordinates[idx], out.pnf_param_general.location_coordinates[idx]); + + CU_ASSERT_EQUAL(in.pnf_param_general.dl_config_timing, out.pnf_param_general.dl_config_timing); + CU_ASSERT_EQUAL(in.pnf_param_general.tx_timing, out.pnf_param_general.tx_timing); + CU_ASSERT_EQUAL(in.pnf_param_general.ul_config_timing, out.pnf_param_general.ul_config_timing); + CU_ASSERT_EQUAL(in.pnf_param_general.hi_dci0_timing, out.pnf_param_general.hi_dci0_timing); + CU_ASSERT_EQUAL(in.pnf_param_general.maximum_number_phys, out.pnf_param_general.maximum_number_phys); + CU_ASSERT_EQUAL(in.pnf_param_general.maximum_total_bandwidth, out.pnf_param_general.maximum_total_bandwidth); + CU_ASSERT_EQUAL(in.pnf_param_general.maximum_total_number_dl_layers, out.pnf_param_general.maximum_total_number_dl_layers); + CU_ASSERT_EQUAL(in.pnf_param_general.maximum_total_number_ul_layers, out.pnf_param_general.maximum_total_number_ul_layers); + CU_ASSERT_EQUAL(in.pnf_param_general.shared_bands, out.pnf_param_general.shared_bands); + CU_ASSERT_EQUAL(in.pnf_param_general.shared_pa, out.pnf_param_general.shared_pa); + CU_ASSERT_EQUAL(in.pnf_param_general.maximum_total_power, out.pnf_param_general.maximum_total_power); + for(idx = 0; idx < NFAPI_PNF_PARAM_GENERAL_OUI_LENGTH; ++idx) + CU_ASSERT_EQUAL(in.pnf_param_general.oui[idx], out.pnf_param_general.oui[idx]); + + CU_ASSERT_EQUAL(in.pnf_phy.tl.tag, out.pnf_phy.tl.tag); + CU_ASSERT_EQUAL(in.pnf_phy.number_of_phys, out.pnf_phy.number_of_phys); + + for(idx = 0; idx < out.pnf_phy.number_of_phys; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_phy.phy[idx].phy_config_index, out.pnf_phy.phy[idx].phy_config_index); + CU_ASSERT_EQUAL(in.pnf_phy.phy[idx].number_of_rfs, out.pnf_phy.phy[idx].number_of_rfs); + + + for(idx2 = 0; idx2 < out.pnf_phy.phy[idx].number_of_rfs; ++idx2) + { + CU_ASSERT_EQUAL(in.pnf_phy.phy[idx].rf_config[idx2].rf_config_index, out.pnf_phy.phy[idx].rf_config[idx2].rf_config_index); + } + CU_ASSERT_EQUAL(in.pnf_phy.phy[idx].number_of_rf_exclusions, out.pnf_phy.phy[idx].number_of_rf_exclusions); + + for(idx2 = 0; idx2 < out.pnf_phy.phy[idx].number_of_rf_exclusions; ++idx2) + { + CU_ASSERT_EQUAL(in.pnf_phy.phy[idx].excluded_rf_config[idx2].rf_config_index, out.pnf_phy.phy[idx].excluded_rf_config[idx2].rf_config_index); + } + + + CU_ASSERT_EQUAL(in.pnf_phy.phy[idx].downlink_channel_bandwidth_supported, out.pnf_phy.phy[idx].downlink_channel_bandwidth_supported); + CU_ASSERT_EQUAL(in.pnf_phy.phy[idx].uplink_channel_bandwidth_supported, out.pnf_phy.phy[idx].uplink_channel_bandwidth_supported); + CU_ASSERT_EQUAL(in.pnf_phy.phy[idx].number_of_dl_layers_supported, out.pnf_phy.phy[idx].number_of_dl_layers_supported); + CU_ASSERT_EQUAL(in.pnf_phy.phy[idx].number_of_ul_layers_supported, out.pnf_phy.phy[idx].number_of_ul_layers_supported); + CU_ASSERT_EQUAL(in.pnf_phy.phy[idx].maximum_3gpp_release_supported, out.pnf_phy.phy[idx].maximum_3gpp_release_supported); + CU_ASSERT_EQUAL(in.pnf_phy.phy[idx].nmm_modes_supported, out.pnf_phy.phy[idx].nmm_modes_supported); + } + + CU_ASSERT_EQUAL(in.pnf_rf.tl.tag, out.pnf_rf.tl.tag); + CU_ASSERT_EQUAL(in.pnf_rf.number_of_rfs, out.pnf_rf.number_of_rfs); + for(idx = 0; idx < out.pnf_rf.number_of_rfs; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_rf.rf[idx].rf_config_index, out.pnf_rf.rf[idx].rf_config_index); + CU_ASSERT_EQUAL(in.pnf_rf.rf[idx].band, out.pnf_rf.rf[idx].band); + CU_ASSERT_EQUAL(in.pnf_rf.rf[idx].maximum_transmit_power, out.pnf_rf.rf[idx].maximum_transmit_power); + CU_ASSERT_EQUAL(in.pnf_rf.rf[idx].minimum_transmit_power, out.pnf_rf.rf[idx].minimum_transmit_power); + CU_ASSERT_EQUAL(in.pnf_rf.rf[idx].number_of_antennas_suppported, out.pnf_rf.rf[idx].number_of_antennas_suppported); + CU_ASSERT_EQUAL(in.pnf_rf.rf[idx].minimum_downlink_frequency, out.pnf_rf.rf[idx].minimum_downlink_frequency); + CU_ASSERT_EQUAL(in.pnf_rf.rf[idx].maximum_downlink_frequency, out.pnf_rf.rf[idx].maximum_downlink_frequency); + CU_ASSERT_EQUAL(in.pnf_rf.rf[idx].minimum_uplink_frequency, out.pnf_rf.rf[idx].minimum_uplink_frequency); + CU_ASSERT_EQUAL(in.pnf_rf.rf[idx].maximum_uplink_frequency, out.pnf_rf.rf[idx].maximum_uplink_frequency); + } + + + CU_ASSERT_EQUAL(in.pnf_phy_rel10.tl.tag, out.pnf_phy_rel10.tl.tag); + CU_ASSERT_EQUAL(in.pnf_phy_rel10.number_of_phys, out.pnf_phy_rel10.number_of_phys); + for(idx = 0; idx < out.pnf_phy_rel10.number_of_phys; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_phy_rel10.phy[idx].phy_config_index, out.pnf_phy_rel10.phy[idx].phy_config_index); + CU_ASSERT_EQUAL(in.pnf_phy_rel10.phy[idx].transmission_mode_7_supported, out.pnf_phy_rel10.phy[idx].transmission_mode_7_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel10.phy[idx].transmission_mode_8_supported, out.pnf_phy_rel10.phy[idx].transmission_mode_8_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel10.phy[idx].two_antenna_ports_for_pucch, out.pnf_phy_rel10.phy[idx].two_antenna_ports_for_pucch); + CU_ASSERT_EQUAL(in.pnf_phy_rel10.phy[idx].transmission_mode_9_supported, out.pnf_phy_rel10.phy[idx].transmission_mode_9_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel10.phy[idx].simultaneous_pucch_pusch, out.pnf_phy_rel10.phy[idx].simultaneous_pucch_pusch); + CU_ASSERT_EQUAL(in.pnf_phy_rel10.phy[idx].four_layer_tx_with_tm3_and_tm4, out.pnf_phy_rel10.phy[idx].four_layer_tx_with_tm3_and_tm4); + } + + CU_ASSERT_EQUAL(in.pnf_phy_rel11.tl.tag, out.pnf_phy_rel11.tl.tag); + CU_ASSERT_EQUAL(in.pnf_phy_rel11.number_of_phys, out.pnf_phy_rel11.number_of_phys); + for(idx = 0; idx < out.pnf_phy_rel11.number_of_phys; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_phy_rel11.phy[idx].phy_config_index, out.pnf_phy_rel11.phy[idx].phy_config_index); + CU_ASSERT_EQUAL(in.pnf_phy_rel11.phy[idx].edpcch_supported, out.pnf_phy_rel11.phy[idx].edpcch_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel11.phy[idx].multi_ack_csi_reporting, out.pnf_phy_rel11.phy[idx].multi_ack_csi_reporting); + CU_ASSERT_EQUAL(in.pnf_phy_rel11.phy[idx].pucch_tx_diversity, out.pnf_phy_rel11.phy[idx].pucch_tx_diversity); + CU_ASSERT_EQUAL(in.pnf_phy_rel11.phy[idx].ul_comp_supported, out.pnf_phy_rel11.phy[idx].ul_comp_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel11.phy[idx].transmission_mode_5_supported, out.pnf_phy_rel11.phy[idx].transmission_mode_5_supported); + } + + CU_ASSERT_EQUAL(in.pnf_phy_rel12.tl.tag, out.pnf_phy_rel12.tl.tag); + CU_ASSERT_EQUAL(in.pnf_phy_rel12.number_of_phys, out.pnf_phy_rel12.number_of_phys); + for(idx = 0; idx < out.pnf_phy_rel12.number_of_phys; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_phy_rel12.phy[idx].phy_config_index, out.pnf_phy_rel12.phy[idx].phy_config_index); + CU_ASSERT_EQUAL(in.pnf_phy_rel12.phy[idx].csi_subframe_set, out.pnf_phy_rel12.phy[idx].csi_subframe_set); + CU_ASSERT_EQUAL(in.pnf_phy_rel12.phy[idx].enhanced_4tx_codebook, out.pnf_phy_rel12.phy[idx].enhanced_4tx_codebook); + CU_ASSERT_EQUAL(in.pnf_phy_rel12.phy[idx].drs_supported, out.pnf_phy_rel12.phy[idx].drs_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel12.phy[idx].ul_64qam_supported, out.pnf_phy_rel12.phy[idx].ul_64qam_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel12.phy[idx].transmission_mode_10_supported, out.pnf_phy_rel12.phy[idx].transmission_mode_10_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel12.phy[idx].alternative_bts_indices, out.pnf_phy_rel12.phy[idx].alternative_bts_indices); + } + + CU_ASSERT_EQUAL(in.pnf_phy_rel13.tl.tag, out.pnf_phy_rel13.tl.tag); + CU_ASSERT_EQUAL(in.pnf_phy_rel13.number_of_phys, out.pnf_phy_rel13.number_of_phys); + for(idx = 0; idx < out.pnf_phy_rel13.number_of_phys; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_phy_rel13.phy[idx].phy_config_index, out.pnf_phy_rel13.phy[idx].phy_config_index); + CU_ASSERT_EQUAL(in.pnf_phy_rel13.phy[idx].pucch_format4_supported, out.pnf_phy_rel13.phy[idx].pucch_format4_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel13.phy[idx].pucch_format5_supported, out.pnf_phy_rel13.phy[idx].pucch_format5_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel13.phy[idx].more_than_5_ca_support, out.pnf_phy_rel13.phy[idx].more_than_5_ca_support); + CU_ASSERT_EQUAL(in.pnf_phy_rel13.phy[idx].laa_supported, out.pnf_phy_rel13.phy[idx].laa_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel13.phy[idx].laa_ending_in_dwpts_supported, out.pnf_phy_rel13.phy[idx].laa_ending_in_dwpts_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel13.phy[idx].laa_starting_in_second_slot_supported, out.pnf_phy_rel13.phy[idx].laa_starting_in_second_slot_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel13.phy[idx].beamforming_supported, out.pnf_phy_rel13.phy[idx].beamforming_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel13.phy[idx].csi_rs_enhancement_supported, out.pnf_phy_rel13.phy[idx].csi_rs_enhancement_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel13.phy[idx].drms_enhancement_supported, out.pnf_phy_rel13.phy[idx].drms_enhancement_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel13.phy[idx].srs_enhancement_supported, out.pnf_phy_rel13.phy[idx].srs_enhancement_supported); + } + + CU_ASSERT_EQUAL(in.pnf_phy_rel13_nb_iot.tl.tag, out.pnf_phy_rel13_nb_iot.tl.tag); + CU_ASSERT_EQUAL(in.pnf_phy_rel13_nb_iot.number_of_phys, out.pnf_phy_rel13_nb_iot.number_of_phys); + + for(idx = 0; idx < out.pnf_phy_rel13_nb_iot.number_of_phys; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_phy_rel13_nb_iot.phy[idx].phy_config_index, out.pnf_phy_rel13_nb_iot.phy[idx].phy_config_index); + CU_ASSERT_EQUAL(in.pnf_phy_rel13_nb_iot.phy[idx].number_of_rfs, out.pnf_phy_rel13_nb_iot.phy[idx].number_of_rfs); + + + for(idx2 = 0; idx2 < out.pnf_phy_rel13_nb_iot.phy[idx].number_of_rfs; ++idx2) + { + CU_ASSERT_EQUAL(in.pnf_phy_rel13_nb_iot.phy[idx].rf_config[idx2].rf_config_index, out.pnf_phy_rel13_nb_iot.phy[idx].rf_config[idx2].rf_config_index); + } + CU_ASSERT_EQUAL(in.pnf_phy_rel13_nb_iot.phy[idx].number_of_rf_exclusions, out.pnf_phy_rel13_nb_iot.phy[idx].number_of_rf_exclusions); + + for(idx2 = 0; idx2 < out.pnf_phy_rel13_nb_iot.phy[idx].number_of_rf_exclusions; ++idx2) + { + CU_ASSERT_EQUAL(in.pnf_phy_rel13_nb_iot.phy[idx].excluded_rf_config[idx2].rf_config_index, out.pnf_phy_rel13_nb_iot.phy[idx].excluded_rf_config[idx2].rf_config_index); + } + + + CU_ASSERT_EQUAL(in.pnf_phy_rel13_nb_iot.phy[idx].number_of_dl_layers_supported, out.pnf_phy_rel13_nb_iot.phy[idx].number_of_dl_layers_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel13_nb_iot.phy[idx].number_of_ul_layers_supported, out.pnf_phy_rel13_nb_iot.phy[idx].number_of_ul_layers_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel13_nb_iot.phy[idx].maximum_3gpp_release_supported, out.pnf_phy_rel13_nb_iot.phy[idx].maximum_3gpp_release_supported); + CU_ASSERT_EQUAL(in.pnf_phy_rel13_nb_iot.phy[idx].nmm_modes_supported, out.pnf_phy_rel13_nb_iot.phy[idx].nmm_modes_supported); + } + + +} + +void nfapi_test_pnf_config_request() +{ + uint16_t idx; + nfapi_pnf_config_request_t in; + nfapi_pnf_config_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_PNF_CONFIG_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + in.pnf_phy_rf_config.tl.tag = NFAPI_PNF_PHY_RF_TAG; + in.pnf_phy_rf_config.number_phy_rf_config_info = 2; + in.pnf_phy_rf_config.phy_rf_config[0].phy_id = 0; + in.pnf_phy_rf_config.phy_rf_config[0].phy_config_index = 0; + in.pnf_phy_rf_config.phy_rf_config[0].rf_config_index = 0; + + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + int unpack_result = nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(unpack_result, 1); + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + //CU_ASSERT_EQUAL(in.error_code, out.error_code); + + CU_ASSERT_EQUAL(in.pnf_phy_rf_config.tl.tag, out.pnf_phy_rf_config.tl.tag); + CU_ASSERT_EQUAL(in.pnf_phy_rf_config.number_phy_rf_config_info, out.pnf_phy_rf_config.number_phy_rf_config_info); + + for(idx = 0; idx < out.pnf_phy_rf_config.number_phy_rf_config_info; ++idx) + { + CU_ASSERT_EQUAL(in.pnf_phy_rf_config.phy_rf_config[idx].phy_id, out.pnf_phy_rf_config.phy_rf_config[idx].phy_id); + CU_ASSERT_EQUAL(in.pnf_phy_rf_config.phy_rf_config[idx].phy_config_index, out.pnf_phy_rf_config.phy_rf_config[idx].phy_config_index); + CU_ASSERT_EQUAL(in.pnf_phy_rf_config.phy_rf_config[idx].rf_config_index, out.pnf_phy_rf_config.phy_rf_config[idx].rf_config_index); + } +} + + + +void nfapi_test_pnf_config_response() +{ + nfapi_pnf_config_response_t in; + memset(&in, 0, sizeof(in)); + nfapi_pnf_config_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_PNF_CONFIG_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_MSG_OK; + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); +} +void nfapi_test_pnf_config_response1() +{ + uint8_t buffer[NFAPI_HEADER_LENGTH + 1]; + + nfapi_pnf_config_response_t in; + memset(&in, 0, sizeof(in)); + //nfapi_pnf_config_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_PNF_CONFIG_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_MSG_OK; + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), buffer, sizeof(buffer), 0); + CU_ASSERT_EQUAL(packedMessageLength, -1); + + //nfapi_p5_message_unpack(buffer, sizeof(buffer), &out, sizeof(out), 0); + //CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + //CU_ASSERT_EQUAL(in.error_code, out.error_code); +} +void nfapi_test_pnf_start_request() +{ + nfapi_pnf_start_request_t in; + memset(&in, 0, sizeof(in)); + nfapi_pnf_start_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_PNF_START_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); +} + +void nfapi_test_pnf_start_response() +{ + nfapi_pnf_start_response_t in; + memset(&in, 0, sizeof(in)); + nfapi_pnf_start_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_PNF_START_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_MSG_OK; + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); +} +void nfapi_test_pnf_stop_request() +{ + nfapi_pnf_stop_request_t in; + memset(&in, 0, sizeof(in)); + nfapi_pnf_stop_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_PNF_STOP_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); +} +void nfapi_test_pnf_stop_response() +{ + nfapi_pnf_stop_response_t in; + memset(&in, 0, sizeof(in)); + nfapi_pnf_stop_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_PNF_STOP_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_MSG_OK; + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); +} + +void nfapi_test_param_request() +{ + nfapi_param_request_t in; + memset(&in, 0, sizeof(in)); + nfapi_param_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_PARAM_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); +} +void nfapi_test_param_response() +{ + #define SET_TLV(_TLV, _TAG, _VALUE) { _TLV.tl.tag = _TAG; _TLV.value = _VALUE; num_tlv++; } + #define ASSERT_TLV(IN_TLV, OUT_TLV) { CU_ASSERT_EQUAL(IN_TLV.tl.tag, OUT_TLV.tl.tag); CU_ASSERT_EQUAL(IN_TLV.value, OUT_TLV.value);} + + nfapi_param_response_t in; + memset(&in, 0, sizeof(in)); + nfapi_param_response_t out; + memset(&out, 0, sizeof(out)); + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_PARAM_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_MSG_OK; + + uint16_t idx = 0; + uint16_t num_tlv = 0; // Bit of a hack, it is incremented in the SET_UINT16_TLV macro + + SET_TLV(in.l1_status.phy_state, NFAPI_L1_STATUS_PHY_STATE_TAG, 1); + SET_TLV(in.phy_capabilities.dl_bandwidth_support, NFAPI_PHY_CAPABILITIES_DL_BANDWIDTH_SUPPORT_TAG, 63); + SET_TLV(in.phy_capabilities.ul_bandwidth_support, NFAPI_PHY_CAPABILITIES_UL_BANDWIDTH_SUPPORT_TAG, 63); + SET_TLV(in.phy_capabilities.dl_modulation_support, NFAPI_PHY_CAPABILITIES_DL_MODULATION_SUPPORT_TAG, 3); + SET_TLV(in.phy_capabilities.ul_modulation_support, NFAPI_PHY_CAPABILITIES_UL_MODULATION_SUPPORT_TAG, 3); + SET_TLV(in.phy_capabilities.phy_antenna_capability, NFAPI_PHY_CAPABILITIES_PHY_ANTENNA_CAPABILITY_TAG, 8); + SET_TLV(in.phy_capabilities.release_capability, NFAPI_PHY_CAPABILITIES_RELEASE_CAPABILITY_TAG, 63); + SET_TLV(in.phy_capabilities.mbsfn_capability, NFAPI_PHY_CAPABILITIES_MBSFN_CAPABILITY_TAG, 0); + + SET_TLV(in.laa_capability.laa_support, NFAPI_LAA_CAPABILITY_LAA_SUPPORT_TAG, 1); + SET_TLV(in.laa_capability.pd_sensing_lbt_support, NFAPI_LAA_CAPABILITY_PD_SENSING_LBT_SUPPORT_TAG, 0); + SET_TLV(in.laa_capability.multi_carrier_lbt_support, NFAPI_LAA_CAPABILITY_MULTI_CARRIER_LBT_SUPPORT_TAG, 3); + SET_TLV(in.laa_capability.partial_sf_support, NFAPI_LAA_CAPABILITY_PARTIAL_SF_SUPPORT_TAG, 2); + + SET_TLV(in.subframe_config.duplex_mode, NFAPI_SUBFRAME_CONFIG_DUPLEX_MODE_TAG, 1); + SET_TLV(in.subframe_config.pcfich_power_offset, NFAPI_SUBFRAME_CONFIG_PCFICH_POWER_OFFSET_TAG, 1000); + SET_TLV(in.subframe_config.pb, NFAPI_SUBFRAME_CONFIG_PB_TAG, 1); + SET_TLV(in.subframe_config.dl_cyclic_prefix_type, NFAPI_SUBFRAME_CONFIG_DL_CYCLIC_PREFIX_TYPE_TAG, 0); + SET_TLV(in.subframe_config.ul_cyclic_prefix_type, NFAPI_SUBFRAME_CONFIG_UL_CYCLIC_PREFIX_TYPE_TAG, 0); + + SET_TLV(in.rf_config.dl_channel_bandwidth, NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG, 50); + SET_TLV(in.rf_config.ul_channel_bandwidth, NFAPI_RF_CONFIG_UL_CHANNEL_BANDWIDTH_TAG, 50); + SET_TLV(in.rf_config.reference_signal_power, NFAPI_RF_CONFIG_REFERENCE_SIGNAL_POWER_TAG, 120); + SET_TLV(in.rf_config.tx_antenna_ports, NFAPI_RF_CONFIG_TX_ANTENNA_PORTS_TAG, 2); + SET_TLV(in.rf_config.rx_antenna_ports, NFAPI_RF_CONFIG_RX_ANTENNA_PORTS_TAG, 2); + + SET_TLV(in.phich_config.phich_resource, NFAPI_PHICH_CONFIG_PHICH_RESOURCE_TAG, 3); + SET_TLV(in.phich_config.phich_duration, NFAPI_PHICH_CONFIG_PHICH_DURATION_TAG, 0); + SET_TLV(in.phich_config.phich_power_offset, NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG, 500); + + SET_TLV(in.sch_config.primary_synchronization_signal_epre_eprers, NFAPI_SCH_CONFIG_PRIMARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG, 1000); + SET_TLV(in.sch_config.secondary_synchronization_signal_epre_eprers, NFAPI_SCH_CONFIG_SECONDARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG, 2000); + SET_TLV(in.sch_config.physical_cell_id, NFAPI_SCH_CONFIG_PHYSICAL_CELL_ID_TAG, 12344); + + + SET_TLV(in.prach_config.configuration_index, NFAPI_PRACH_CONFIG_CONFIGURATION_INDEX_TAG, 63); + SET_TLV(in.prach_config.root_sequence_index, NFAPI_PRACH_CONFIG_ROOT_SEQUENCE_INDEX_TAG, 800); + SET_TLV(in.prach_config.zero_correlation_zone_configuration, NFAPI_PRACH_CONFIG_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG, 14); + SET_TLV(in.prach_config.high_speed_flag, NFAPI_PRACH_CONFIG_HIGH_SPEED_FLAG_TAG, 0); + SET_TLV(in.prach_config.frequency_offset, NFAPI_PRACH_CONFIG_FREQUENCY_OFFSET_TAG, 23); + + SET_TLV(in.pusch_config.hopping_mode, NFAPI_PUSCH_CONFIG_HOPPING_MODE_TAG, 0); + SET_TLV(in.pusch_config.hopping_offset, NFAPI_PUSCH_CONFIG_HOPPING_OFFSET_TAG, 55); + SET_TLV(in.pusch_config.number_of_subbands, NFAPI_PUSCH_CONFIG_NUMBER_OF_SUBBANDS_TAG, 1); + + SET_TLV(in.pucch_config.delta_pucch_shift, NFAPI_PUCCH_CONFIG_DELTA_PUCCH_SHIFT_TAG, 2); + SET_TLV(in.pucch_config.n_cqi_rb, NFAPI_PUCCH_CONFIG_N_CQI_RB_TAG, 88); + SET_TLV(in.pucch_config.n_an_cs, NFAPI_PUCCH_CONFIG_N_AN_CS_TAG, 3); + SET_TLV(in.pucch_config.n1_pucch_an, NFAPI_PUCCH_CONFIG_N1_PUCCH_AN_TAG, 2015); + + SET_TLV(in.srs_config.bandwidth_configuration, NFAPI_SRS_CONFIG_BANDWIDTH_CONFIGURATION_TAG, 3); + SET_TLV(in.srs_config.max_up_pts, NFAPI_SRS_CONFIG_MAX_UP_PTS_TAG, 0); + SET_TLV(in.srs_config.srs_subframe_configuration, NFAPI_SRS_CONFIG_SRS_SUBFRAME_CONFIGURATION_TAG, 11); + SET_TLV(in.srs_config.srs_acknack_srs_simultaneous_transmission, NFAPI_SRS_CONFIG_SRS_ACKNACK_SRS_SIMULTANEOUS_TRANSMISSION_TAG, 1); + + SET_TLV(in.uplink_reference_signal_config.uplink_rs_hopping, NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_UPLINK_RS_HOPPING_TAG, 2); + SET_TLV(in.uplink_reference_signal_config.group_assignment, NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_GROUP_ASSIGNMENT_TAG, 22); + SET_TLV(in.uplink_reference_signal_config.cyclic_shift_1_for_drms, NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_CYCLIC_SHIFT_1_FOR_DRMS_TAG, 2); + + SET_TLV(in.tdd_frame_structure_config.subframe_assignment, NFAPI_TDD_FRAME_STRUCTURE_SUBFRAME_ASSIGNMENT_TAG, 5); + SET_TLV(in.tdd_frame_structure_config.special_subframe_patterns, NFAPI_TDD_FRAME_STRUCTURE_SPECIAL_SUBFRAME_PATTERNS_TAG, 3); + + SET_TLV(in.l23_config.data_report_mode, NFAPI_L23_CONFIG_DATA_REPORT_MODE_TAG, 1); + SET_TLV(in.l23_config.sfnsf, NFAPI_L23_CONFIG_SFNSF_TAG, 12354); + + in.nfapi_config.p7_vnf_address_ipv4.tl.tag = NFAPI_NFAPI_P7_VNF_ADDRESS_IPV4_TAG; + num_tlv++; + + in.nfapi_config.p7_vnf_address_ipv6.tl.tag = NFAPI_NFAPI_P7_VNF_ADDRESS_IPV6_TAG; + num_tlv++; + + SET_TLV(in.nfapi_config.p7_vnf_port, NFAPI_NFAPI_P7_VNF_PORT_TAG, 1111); + + in.nfapi_config.p7_pnf_address_ipv4.tl.tag = NFAPI_NFAPI_P7_PNF_ADDRESS_IPV4_TAG; + num_tlv++; + + in.nfapi_config.p7_pnf_address_ipv6.tl.tag = NFAPI_NFAPI_P7_PNF_ADDRESS_IPV6_TAG; + num_tlv++; + + SET_TLV(in.nfapi_config.p7_pnf_port, NFAPI_NFAPI_P7_PNF_PORT_TAG, 9999); + SET_TLV(in.nfapi_config.dl_ue_per_sf, NFAPI_NFAPI_DOWNLINK_UES_PER_SUBFRAME_TAG, 4); + SET_TLV(in.nfapi_config.ul_ue_per_sf, NFAPI_NFAPI_UPLINK_UES_PER_SUBFRAME_TAG, 4); + + in.nfapi_config.rf_bands.tl.tag = NFAPI_PHY_RF_BANDS_TAG; + in.nfapi_config.rf_bands.number_rf_bands = 2; + in.nfapi_config.rf_bands.rf_band[0] = 783; + num_tlv++; + + SET_TLV(in.nfapi_config.timing_window, NFAPI_NFAPI_TIMING_WINDOW_TAG, 29); + SET_TLV(in.nfapi_config.timing_info_mode, NFAPI_NFAPI_TIMING_INFO_MODE_TAG, 2); + SET_TLV(in.nfapi_config.timing_info_period, NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG, 23); + SET_TLV(in.nfapi_config.max_transmit_power, NFAPI_NFAPI_MAXIMUM_TRANSMIT_POWER_TAG, 123); + SET_TLV(in.nfapi_config.earfcn, NFAPI_NFAPI_EARFCN_TAG, 1800); + + in.nfapi_config.nmm_gsm_frequency_bands.tl.tag = NFAPI_NFAPI_NMM_GSM_FREQUENCY_BANDS_TAG; + in.nfapi_config.nmm_gsm_frequency_bands.number_of_rf_bands = 2; + num_tlv++; + + in.nfapi_config.nmm_umts_frequency_bands.tl.tag = NFAPI_NFAPI_NMM_UMTS_FREQUENCY_BANDS_TAG; + in.nfapi_config.nmm_umts_frequency_bands.number_of_rf_bands = 3; + num_tlv++; + + in.nfapi_config.nmm_lte_frequency_bands.tl.tag = NFAPI_NFAPI_NMM_LTE_FREQUENCY_BANDS_TAG; + in.nfapi_config.nmm_lte_frequency_bands.number_of_rf_bands = 1; + num_tlv++; + + SET_TLV(in.nfapi_config.nmm_uplink_rssi_supported, NFAPI_NFAPI_NMM_UPLINK_RSSI_SUPPORTED_TAG, 1); + + + in.num_tlv = num_tlv; + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + CU_ASSERT_EQUAL(in.num_tlv, out.num_tlv); + + ASSERT_TLV(in.l1_status.phy_state, out.l1_status.phy_state); + ASSERT_TLV(in.phy_capabilities.dl_bandwidth_support, out.phy_capabilities.dl_bandwidth_support); + ASSERT_TLV(in.phy_capabilities.ul_bandwidth_support, out.phy_capabilities.ul_bandwidth_support); + ASSERT_TLV(in.phy_capabilities.dl_modulation_support, out.phy_capabilities.dl_modulation_support); + ASSERT_TLV(in.phy_capabilities.ul_modulation_support, out.phy_capabilities.ul_modulation_support); + ASSERT_TLV(in.phy_capabilities.phy_antenna_capability, out.phy_capabilities.phy_antenna_capability); + ASSERT_TLV(in.phy_capabilities.release_capability, out.phy_capabilities.release_capability); + ASSERT_TLV(in.phy_capabilities.mbsfn_capability, out.phy_capabilities.mbsfn_capability); + + ASSERT_TLV(in.laa_capability.laa_support, in.laa_capability.laa_support); + ASSERT_TLV(in.laa_capability.pd_sensing_lbt_support, in.laa_capability.pd_sensing_lbt_support); + ASSERT_TLV(in.laa_capability.multi_carrier_lbt_support, in.laa_capability.multi_carrier_lbt_support); + ASSERT_TLV(in.laa_capability.partial_sf_support, in.laa_capability.partial_sf_support); + + ASSERT_TLV(in.subframe_config.duplex_mode, out.subframe_config.duplex_mode); + ASSERT_TLV(in.subframe_config.pcfich_power_offset, out.subframe_config.pcfich_power_offset); + ASSERT_TLV(in.subframe_config.pb, out.subframe_config.pb); + ASSERT_TLV(in.subframe_config.dl_cyclic_prefix_type, out.subframe_config.dl_cyclic_prefix_type); + ASSERT_TLV(in.subframe_config.ul_cyclic_prefix_type, out.subframe_config.ul_cyclic_prefix_type); + + ASSERT_TLV(in.rf_config.dl_channel_bandwidth, out.rf_config.dl_channel_bandwidth); + ASSERT_TLV(in.rf_config.ul_channel_bandwidth, out.rf_config.ul_channel_bandwidth); + ASSERT_TLV(in.rf_config.reference_signal_power, out.rf_config.reference_signal_power); + ASSERT_TLV(in.rf_config.tx_antenna_ports, out.rf_config.tx_antenna_ports); + ASSERT_TLV(in.rf_config.rx_antenna_ports, out.rf_config.rx_antenna_ports); + + ASSERT_TLV(in.phich_config.phich_resource, out.phich_config.phich_resource); + ASSERT_TLV(in.phich_config.phich_duration, out.phich_config.phich_duration); + ASSERT_TLV(in.phich_config.phich_power_offset, out.phich_config.phich_power_offset); + + ASSERT_TLV(in.sch_config.primary_synchronization_signal_epre_eprers, out.sch_config.primary_synchronization_signal_epre_eprers); + ASSERT_TLV(in.sch_config.secondary_synchronization_signal_epre_eprers, out.sch_config.secondary_synchronization_signal_epre_eprers); + ASSERT_TLV(in.sch_config.physical_cell_id, out.sch_config.physical_cell_id); + + + ASSERT_TLV(in.prach_config.configuration_index, out.prach_config.configuration_index); + ASSERT_TLV(in.prach_config.root_sequence_index, out.prach_config.root_sequence_index); + ASSERT_TLV(in.prach_config.zero_correlation_zone_configuration, out.prach_config.zero_correlation_zone_configuration); + ASSERT_TLV(in.prach_config.high_speed_flag, out.prach_config.high_speed_flag); + ASSERT_TLV(in.prach_config.frequency_offset, out.prach_config.frequency_offset); + + ASSERT_TLV(in.pusch_config.hopping_mode, in.pusch_config.hopping_mode); + ASSERT_TLV(in.pusch_config.hopping_offset, in.pusch_config.hopping_offset); + ASSERT_TLV(in.pusch_config.number_of_subbands, in.pusch_config.number_of_subbands); + + ASSERT_TLV(in.pucch_config.delta_pucch_shift, out.pucch_config.delta_pucch_shift); + ASSERT_TLV(in.pucch_config.n_cqi_rb, out.pucch_config.n_cqi_rb); + ASSERT_TLV(in.pucch_config.n_an_cs, out.pucch_config.n_an_cs); + ASSERT_TLV(in.pucch_config.n1_pucch_an, out.pucch_config.n1_pucch_an); + + ASSERT_TLV(in.srs_config.bandwidth_configuration, out.srs_config.bandwidth_configuration); + ASSERT_TLV(in.srs_config.max_up_pts, out.srs_config.max_up_pts); + ASSERT_TLV(in.srs_config.srs_subframe_configuration, out.srs_config.srs_subframe_configuration); + ASSERT_TLV(in.srs_config.srs_acknack_srs_simultaneous_transmission, out.srs_config.srs_acknack_srs_simultaneous_transmission); + + ASSERT_TLV(in.uplink_reference_signal_config.uplink_rs_hopping, out.uplink_reference_signal_config.uplink_rs_hopping); + ASSERT_TLV(in.uplink_reference_signal_config.group_assignment, out.uplink_reference_signal_config.group_assignment); + ASSERT_TLV(in.uplink_reference_signal_config.cyclic_shift_1_for_drms, out.uplink_reference_signal_config.cyclic_shift_1_for_drms); + + ASSERT_TLV(in.tdd_frame_structure_config.subframe_assignment, out.tdd_frame_structure_config.subframe_assignment); + ASSERT_TLV(in.tdd_frame_structure_config.special_subframe_patterns, out.tdd_frame_structure_config.special_subframe_patterns); + + ASSERT_TLV(in.l23_config.data_report_mode, out.l23_config.data_report_mode); + ASSERT_TLV(in.l23_config.sfnsf, out.l23_config.sfnsf); + + CU_ASSERT_EQUAL(in.nfapi_config.p7_vnf_address_ipv4.tl.tag, out.nfapi_config.p7_vnf_address_ipv4.tl.tag); + for(idx = 0; idx < NFAPI_IPV4_ADDRESS_LENGTH; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.p7_vnf_address_ipv4.address[idx], out.nfapi_config.p7_vnf_address_ipv4.address[idx]); + } + + CU_ASSERT_EQUAL(in.nfapi_config.p7_vnf_address_ipv6.tl.tag, out.nfapi_config.p7_vnf_address_ipv6.tl.tag); + for(idx = 0; idx < NFAPI_IPV6_ADDRESS_LENGTH; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.p7_vnf_address_ipv6.address[idx], out.nfapi_config.p7_vnf_address_ipv6.address[idx]); + } + + ASSERT_TLV(in.nfapi_config.p7_vnf_port, out.nfapi_config.p7_vnf_port); + + CU_ASSERT_EQUAL(in.nfapi_config.p7_pnf_address_ipv4.tl.tag, out.nfapi_config.p7_pnf_address_ipv4.tl.tag); + for(idx = 0; idx < NFAPI_IPV4_ADDRESS_LENGTH; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.p7_pnf_address_ipv4.address[idx], out.nfapi_config.p7_pnf_address_ipv4.address[idx]); + } + + CU_ASSERT_EQUAL(in.nfapi_config.p7_pnf_address_ipv6.tl.tag, out.nfapi_config.p7_pnf_address_ipv6.tl.tag); + for(idx = 0; idx < NFAPI_IPV6_ADDRESS_LENGTH; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.p7_pnf_address_ipv6.address[idx], out.nfapi_config.p7_pnf_address_ipv6.address[idx]); + } + + ASSERT_TLV(in.nfapi_config.p7_pnf_port, out.nfapi_config.p7_pnf_port); + ASSERT_TLV(in.nfapi_config.dl_ue_per_sf, out.nfapi_config.dl_ue_per_sf); + ASSERT_TLV(in.nfapi_config.ul_ue_per_sf, out.nfapi_config.ul_ue_per_sf); + + CU_ASSERT_EQUAL(in.nfapi_config.rf_bands.tl.tag, out.nfapi_config.rf_bands.tl.tag); + CU_ASSERT_EQUAL(in.nfapi_config.rf_bands.number_rf_bands, out.nfapi_config.rf_bands.number_rf_bands); + for(idx = 0; idx < out.nfapi_config.rf_bands.number_rf_bands; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.rf_bands.rf_band[idx], out.nfapi_config.rf_bands.rf_band[idx]); + } + + ASSERT_TLV(in.nfapi_config.timing_window, out.nfapi_config.timing_window); + ASSERT_TLV(in.nfapi_config.timing_info_mode, out.nfapi_config.timing_info_mode); + ASSERT_TLV(in.nfapi_config.timing_info_period, out.nfapi_config.timing_info_period); + ASSERT_TLV(in.nfapi_config.max_transmit_power, out.nfapi_config.max_transmit_power); + ASSERT_TLV(in.nfapi_config.earfcn, out.nfapi_config.earfcn); + + CU_ASSERT_EQUAL(in.nfapi_config.nmm_gsm_frequency_bands.tl.tag, out.nfapi_config.nmm_gsm_frequency_bands.tl.tag); + CU_ASSERT_EQUAL(in.nfapi_config.nmm_gsm_frequency_bands.number_of_rf_bands, out.nfapi_config.nmm_gsm_frequency_bands.number_of_rf_bands); + for(idx = 0; idx < out.nfapi_config.nmm_gsm_frequency_bands.number_of_rf_bands; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.nmm_gsm_frequency_bands.bands[idx], out.nfapi_config.nmm_gsm_frequency_bands.bands[idx]); + } + + CU_ASSERT_EQUAL(in.nfapi_config.nmm_umts_frequency_bands.tl.tag, out.nfapi_config.nmm_umts_frequency_bands.tl.tag); + CU_ASSERT_EQUAL(in.nfapi_config.nmm_umts_frequency_bands.number_of_rf_bands, out.nfapi_config.nmm_umts_frequency_bands.number_of_rf_bands); + for(idx = 0; idx < out.nfapi_config.nmm_umts_frequency_bands.number_of_rf_bands; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.nmm_umts_frequency_bands.bands[idx], out.nfapi_config.nmm_umts_frequency_bands.bands[idx]); + } + + CU_ASSERT_EQUAL(in.nfapi_config.nmm_lte_frequency_bands.tl.tag, out.nfapi_config.nmm_lte_frequency_bands.tl.tag); + CU_ASSERT_EQUAL(in.nfapi_config.nmm_lte_frequency_bands.number_of_rf_bands, out.nfapi_config.nmm_lte_frequency_bands.number_of_rf_bands); + for(idx = 0; idx < out.nfapi_config.nmm_lte_frequency_bands.number_of_rf_bands; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.nmm_lte_frequency_bands.bands[idx], out.nfapi_config.nmm_lte_frequency_bands.bands[idx]); + } + + ASSERT_TLV(in.nfapi_config.nmm_uplink_rssi_supported, out.nfapi_config.nmm_uplink_rssi_supported); +} +void nfapi_test_config_request() +{ + #define SET_TLV(_TLV, _TAG, _VALUE) { _TLV.tl.tag = _TAG; _TLV.value = _VALUE; num_tlv++; } + #define ASSERT_TLV(IN_TLV, OUT_TLV) { CU_ASSERT_EQUAL(IN_TLV.tl.tag, OUT_TLV.tl.tag); CU_ASSERT_EQUAL(IN_TLV.value, OUT_TLV.value);} + + nfapi_config_request_t in; + memset(&in, 0, sizeof(in)); + nfapi_config_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_CONFIG_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + + uint16_t idx = 0; + uint16_t num_tlv = 0; // Bit of a hack, it is incremented in the SET_UINT16_TLV macro + + SET_TLV(in.subframe_config.duplex_mode, NFAPI_SUBFRAME_CONFIG_DUPLEX_MODE_TAG, 1); + SET_TLV(in.subframe_config.pcfich_power_offset, NFAPI_SUBFRAME_CONFIG_PCFICH_POWER_OFFSET_TAG, 1000); + SET_TLV(in.subframe_config.pb, NFAPI_SUBFRAME_CONFIG_PB_TAG, 1); + SET_TLV(in.subframe_config.dl_cyclic_prefix_type, NFAPI_SUBFRAME_CONFIG_DL_CYCLIC_PREFIX_TYPE_TAG, 0); + SET_TLV(in.subframe_config.ul_cyclic_prefix_type, NFAPI_SUBFRAME_CONFIG_UL_CYCLIC_PREFIX_TYPE_TAG, 0); + + SET_TLV(in.rf_config.dl_channel_bandwidth, NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG, 50); + SET_TLV(in.rf_config.ul_channel_bandwidth, NFAPI_RF_CONFIG_UL_CHANNEL_BANDWIDTH_TAG, 50); + SET_TLV(in.rf_config.reference_signal_power, NFAPI_RF_CONFIG_REFERENCE_SIGNAL_POWER_TAG, 120); + SET_TLV(in.rf_config.tx_antenna_ports, NFAPI_RF_CONFIG_TX_ANTENNA_PORTS_TAG, 2); + SET_TLV(in.rf_config.rx_antenna_ports, NFAPI_RF_CONFIG_RX_ANTENNA_PORTS_TAG, 2); + + SET_TLV(in.phich_config.phich_resource, NFAPI_PHICH_CONFIG_PHICH_RESOURCE_TAG, 3); + SET_TLV(in.phich_config.phich_duration, NFAPI_PHICH_CONFIG_PHICH_DURATION_TAG, 0); + SET_TLV(in.phich_config.phich_power_offset, NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG, 500); + + SET_TLV(in.sch_config.primary_synchronization_signal_epre_eprers, NFAPI_SCH_CONFIG_PRIMARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG, 1000); + SET_TLV(in.sch_config.secondary_synchronization_signal_epre_eprers, NFAPI_SCH_CONFIG_SECONDARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG, 2000); + SET_TLV(in.sch_config.physical_cell_id, NFAPI_SCH_CONFIG_PHYSICAL_CELL_ID_TAG, 12344); + + + SET_TLV(in.prach_config.configuration_index, NFAPI_PRACH_CONFIG_CONFIGURATION_INDEX_TAG, 63); + SET_TLV(in.prach_config.root_sequence_index, NFAPI_PRACH_CONFIG_ROOT_SEQUENCE_INDEX_TAG, 800); + SET_TLV(in.prach_config.zero_correlation_zone_configuration, NFAPI_PRACH_CONFIG_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG, 14); + SET_TLV(in.prach_config.high_speed_flag, NFAPI_PRACH_CONFIG_HIGH_SPEED_FLAG_TAG, 0); + SET_TLV(in.prach_config.frequency_offset, NFAPI_PRACH_CONFIG_FREQUENCY_OFFSET_TAG, 23); + + SET_TLV(in.pusch_config.hopping_mode, NFAPI_PUSCH_CONFIG_HOPPING_MODE_TAG, 0); + SET_TLV(in.pusch_config.hopping_offset, NFAPI_PUSCH_CONFIG_HOPPING_OFFSET_TAG, 55); + SET_TLV(in.pusch_config.number_of_subbands, NFAPI_PUSCH_CONFIG_NUMBER_OF_SUBBANDS_TAG, 1); + + SET_TLV(in.pucch_config.delta_pucch_shift, NFAPI_PUCCH_CONFIG_DELTA_PUCCH_SHIFT_TAG, 2); + SET_TLV(in.pucch_config.n_cqi_rb, NFAPI_PUCCH_CONFIG_N_CQI_RB_TAG, 88); + SET_TLV(in.pucch_config.n_an_cs, NFAPI_PUCCH_CONFIG_N_AN_CS_TAG, 3); + SET_TLV(in.pucch_config.n1_pucch_an, NFAPI_PUCCH_CONFIG_N1_PUCCH_AN_TAG, 2015); + + SET_TLV(in.srs_config.bandwidth_configuration, NFAPI_SRS_CONFIG_BANDWIDTH_CONFIGURATION_TAG, 3); + SET_TLV(in.srs_config.max_up_pts, NFAPI_SRS_CONFIG_MAX_UP_PTS_TAG, 0); + SET_TLV(in.srs_config.srs_subframe_configuration, NFAPI_SRS_CONFIG_SRS_SUBFRAME_CONFIGURATION_TAG, 11); + SET_TLV(in.srs_config.srs_acknack_srs_simultaneous_transmission, NFAPI_SRS_CONFIG_SRS_ACKNACK_SRS_SIMULTANEOUS_TRANSMISSION_TAG, 1); + + SET_TLV(in.uplink_reference_signal_config.uplink_rs_hopping, NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_UPLINK_RS_HOPPING_TAG, 2); + SET_TLV(in.uplink_reference_signal_config.group_assignment, NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_GROUP_ASSIGNMENT_TAG, 22); + SET_TLV(in.uplink_reference_signal_config.cyclic_shift_1_for_drms, NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_CYCLIC_SHIFT_1_FOR_DRMS_TAG, 2); + + + // laa config + SET_TLV(in.laa_config.ed_threshold_lbt_pdsch, NFAPI_LAA_CONFIG_ED_THRESHOLD_FOR_LBT_FOR_PDSCH_TAG, 45); + SET_TLV(in.laa_config.ed_threshold_lbt_drs, NFAPI_LAA_CONFIG_ED_THRESHOLD_FOR_LBT_FOR_DRS_TAG, 69); + SET_TLV(in.laa_config.pd_threshold, NFAPI_LAA_CONFIG_PD_THRESHOLD_TAG, 65535); + SET_TLV(in.laa_config.multi_carrier_type, NFAPI_LAA_CONFIG_MULTI_CARRIER_TYPE_TAG, 3); + SET_TLV(in.laa_config.multi_carrier_tx, NFAPI_LAA_CONFIG_MULTI_CARRIER_TX_TAG, 1); + SET_TLV(in.laa_config.multi_carrier_freeze, NFAPI_LAA_CONFIG_MULTI_CARRIER_FREEZE_TAG, 0); + SET_TLV(in.laa_config.tx_antenna_ports_drs, NFAPI_LAA_CONFIG_TX_ANTENNA_PORTS_FOR_DRS_TAG, 4); + SET_TLV(in.laa_config.tx_power_drs, NFAPI_LAA_CONFIG_TRANSMISSION_POWER_FOR_DRS_TAG, 10000); + // + // emtc config + SET_TLV(in.emtc_config.pbch_repetitions_enable_r13, NFAPI_EMTC_CONFIG_PBCH_REPETITIONS_ENABLE_R13_TAG, 1); + SET_TLV(in.emtc_config.prach_catm_root_sequence_index, NFAPI_EMTC_CONFIG_PRACH_CATM_ROOT_SEQUENCE_INDEX_TAG, 837); + SET_TLV(in.emtc_config.prach_catm_zero_correlation_zone_configuration, NFAPI_EMTC_CONFIG_PRACH_CATM_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG, 15); + SET_TLV(in.emtc_config.prach_catm_high_speed_flag, NFAPI_EMTC_CONFIG_PRACH_CATM_HIGH_SPEED_FLAG, 15); + SET_TLV(in.emtc_config.prach_ce_level_0_enable, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_ENABLE_TAG, 1); + SET_TLV(in.emtc_config.prach_ce_level_0_configuration_index, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_CONFIGURATION_INDEX_TAG, 60); + SET_TLV(in.emtc_config.prach_ce_level_0_frequency_offset, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_FREQUENCY_OFFSET_TAG, 90); + SET_TLV(in.emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG, 128); + SET_TLV(in.emtc_config.prach_ce_level_0_starting_subframe_periodicity, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_STARTING_SUBFRAME_PERIODICITY_TAG, 256); + SET_TLV(in.emtc_config.prach_ce_level_0_hopping_enable, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_ENABLE_TAG, 1); + SET_TLV(in.emtc_config.prach_ce_level_0_hopping_offset, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_OFFSET_TAG, 0); + SET_TLV(in.emtc_config.prach_ce_level_1_enable, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_ENABLE_TAG, 1); + SET_TLV(in.emtc_config.prach_ce_level_1_configuration_index, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_CONFIGURATION_INDEX_TAG, 45); + SET_TLV(in.emtc_config.prach_ce_level_1_frequency_offset, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_FREQUENCY_OFFSET_TAG, 88); + SET_TLV(in.emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG, 64); + SET_TLV(in.emtc_config.prach_ce_level_1_starting_subframe_periodicity, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_STARTING_SUBFRAME_PERIODICITY_TAG, 0xFFFF); + SET_TLV(in.emtc_config.prach_ce_level_1_hopping_enable, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_ENABLE_TAG, 1); + SET_TLV(in.emtc_config.prach_ce_level_1_hopping_offset, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_OFFSET_TAG, 22); + SET_TLV(in.emtc_config.prach_ce_level_2_enable, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_ENABLE_TAG, 1); + SET_TLV(in.emtc_config.prach_ce_level_2_configuration_index, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_CONFIGURATION_INDEX_TAG, 63); + SET_TLV(in.emtc_config.prach_ce_level_2_frequency_offset, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_FREQUENCY_OFFSET_TAG, 22); + SET_TLV(in.emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG, 8); + SET_TLV(in.emtc_config.prach_ce_level_2_starting_subframe_periodicity, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_STARTING_SUBFRAME_PERIODICITY_TAG, 64) + SET_TLV(in.emtc_config.prach_ce_level_2_hopping_enable, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_ENABLE_TAG, 1); + SET_TLV(in.emtc_config.prach_ce_level_2_hopping_offset, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_OFFSET_TAG, 45); + SET_TLV(in.emtc_config.prach_ce_level_3_enable, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_ENABLE_TAG, 0); + SET_TLV(in.emtc_config.prach_ce_level_3_configuration_index, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_CONFIGURATION_INDEX_TAG, 45); + SET_TLV(in.emtc_config.prach_ce_level_3_frequency_offset, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_FREQUENCY_OFFSET_TAG, 22); + SET_TLV(in.emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG, 4); + SET_TLV(in.emtc_config.prach_ce_level_3_starting_subframe_periodicity, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_STARTING_SUBFRAME_PERIODICITY_TAG, 4); + SET_TLV(in.emtc_config.prach_ce_level_3_hopping_enable, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_ENABLE_TAG, 0); + SET_TLV(in.emtc_config.prach_ce_level_3_hopping_offset, NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_OFFSET_TAG, 0); + SET_TLV(in.emtc_config.pucch_interval_ulhoppingconfigcommonmodea, NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEA_TAG, 8); + SET_TLV(in.emtc_config.pucch_interval_ulhoppingconfigcommonmodeb, NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEB_TAG, 8); + + + SET_TLV(in.tdd_frame_structure_config.subframe_assignment, NFAPI_TDD_FRAME_STRUCTURE_SUBFRAME_ASSIGNMENT_TAG, 5); + SET_TLV(in.tdd_frame_structure_config.special_subframe_patterns, NFAPI_TDD_FRAME_STRUCTURE_SPECIAL_SUBFRAME_PATTERNS_TAG, 3); + + SET_TLV(in.l23_config.data_report_mode, NFAPI_L23_CONFIG_DATA_REPORT_MODE_TAG, 1); + SET_TLV(in.l23_config.sfnsf, NFAPI_L23_CONFIG_SFNSF_TAG, 12354); + + in.nfapi_config.p7_vnf_address_ipv4.tl.tag = NFAPI_NFAPI_P7_VNF_ADDRESS_IPV4_TAG; + num_tlv++; + + in.nfapi_config.p7_vnf_address_ipv6.tl.tag = NFAPI_NFAPI_P7_VNF_ADDRESS_IPV6_TAG; + num_tlv++; + + SET_TLV(in.nfapi_config.p7_vnf_port, NFAPI_NFAPI_P7_VNF_PORT_TAG, 1111); + + in.nfapi_config.p7_pnf_address_ipv4.tl.tag = NFAPI_NFAPI_P7_PNF_ADDRESS_IPV4_TAG; + num_tlv++; + + in.nfapi_config.p7_pnf_address_ipv6.tl.tag = NFAPI_NFAPI_P7_PNF_ADDRESS_IPV6_TAG; + for(idx = 0; idx < NFAPI_IPV6_ADDRESS_LENGTH; ++idx) + { + in.nfapi_config.p7_pnf_address_ipv6.address[idx] = idx; + } + num_tlv++; + + SET_TLV(in.nfapi_config.p7_pnf_port, NFAPI_NFAPI_P7_PNF_PORT_TAG, 9999); + SET_TLV(in.nfapi_config.dl_ue_per_sf, NFAPI_NFAPI_DOWNLINK_UES_PER_SUBFRAME_TAG, 4); + SET_TLV(in.nfapi_config.ul_ue_per_sf, NFAPI_NFAPI_UPLINK_UES_PER_SUBFRAME_TAG, 4); + + in.nfapi_config.rf_bands.tl.tag = NFAPI_PHY_RF_BANDS_TAG; + in.nfapi_config.rf_bands.number_rf_bands = 2; + in.nfapi_config.rf_bands.rf_band[0] = 783; + num_tlv++; + + SET_TLV(in.nfapi_config.timing_window, NFAPI_NFAPI_TIMING_WINDOW_TAG, 29); + SET_TLV(in.nfapi_config.timing_info_mode, NFAPI_NFAPI_TIMING_INFO_MODE_TAG, 2); + SET_TLV(in.nfapi_config.timing_info_period, NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG, 23); + SET_TLV(in.nfapi_config.max_transmit_power, NFAPI_NFAPI_MAXIMUM_TRANSMIT_POWER_TAG, 123); + SET_TLV(in.nfapi_config.earfcn, NFAPI_NFAPI_EARFCN_TAG, 1800); + + in.nfapi_config.nmm_gsm_frequency_bands.tl.tag = NFAPI_NFAPI_NMM_GSM_FREQUENCY_BANDS_TAG; + in.nfapi_config.nmm_gsm_frequency_bands.number_of_rf_bands = 2; + num_tlv++; + + in.nfapi_config.nmm_umts_frequency_bands.tl.tag = NFAPI_NFAPI_NMM_UMTS_FREQUENCY_BANDS_TAG; + in.nfapi_config.nmm_umts_frequency_bands.number_of_rf_bands = 3; + num_tlv++; + + in.nfapi_config.nmm_lte_frequency_bands.tl.tag = NFAPI_NFAPI_NMM_LTE_FREQUENCY_BANDS_TAG; + in.nfapi_config.nmm_lte_frequency_bands.number_of_rf_bands = 1; + num_tlv++; + + SET_TLV(in.nfapi_config.nmm_uplink_rssi_supported, NFAPI_NFAPI_NMM_UPLINK_RSSI_SUPPORTED_TAG, 1); + + + in.num_tlv = num_tlv; + + in.vendor_extension = 0; + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.num_tlv, out.num_tlv); + + ASSERT_TLV(in.subframe_config.duplex_mode, out.subframe_config.duplex_mode); + ASSERT_TLV(in.subframe_config.pcfich_power_offset, out.subframe_config.pcfich_power_offset); + ASSERT_TLV(in.subframe_config.pb, out.subframe_config.pb); + ASSERT_TLV(in.subframe_config.dl_cyclic_prefix_type, out.subframe_config.dl_cyclic_prefix_type); + ASSERT_TLV(in.subframe_config.ul_cyclic_prefix_type, out.subframe_config.ul_cyclic_prefix_type); + + ASSERT_TLV(in.rf_config.dl_channel_bandwidth, out.rf_config.dl_channel_bandwidth); + ASSERT_TLV(in.rf_config.ul_channel_bandwidth, out.rf_config.ul_channel_bandwidth); + ASSERT_TLV(in.rf_config.reference_signal_power, out.rf_config.reference_signal_power); + ASSERT_TLV(in.rf_config.tx_antenna_ports, out.rf_config.tx_antenna_ports); + ASSERT_TLV(in.rf_config.rx_antenna_ports, out.rf_config.rx_antenna_ports); + + ASSERT_TLV(in.phich_config.phich_resource, out.phich_config.phich_resource); + ASSERT_TLV(in.phich_config.phich_duration, out.phich_config.phich_duration); + ASSERT_TLV(in.phich_config.phich_power_offset, out.phich_config.phich_power_offset); + + ASSERT_TLV(in.sch_config.primary_synchronization_signal_epre_eprers, out.sch_config.primary_synchronization_signal_epre_eprers); + ASSERT_TLV(in.sch_config.secondary_synchronization_signal_epre_eprers, out.sch_config.secondary_synchronization_signal_epre_eprers); + ASSERT_TLV(in.sch_config.physical_cell_id, out.sch_config.physical_cell_id); + + + ASSERT_TLV(in.prach_config.configuration_index, out.prach_config.configuration_index); + ASSERT_TLV(in.prach_config.root_sequence_index, out.prach_config.root_sequence_index); + ASSERT_TLV(in.prach_config.zero_correlation_zone_configuration, out.prach_config.zero_correlation_zone_configuration); + ASSERT_TLV(in.prach_config.high_speed_flag, out.prach_config.high_speed_flag); + ASSERT_TLV(in.prach_config.frequency_offset, out.prach_config.frequency_offset); + + ASSERT_TLV(in.pusch_config.hopping_mode, in.pusch_config.hopping_mode); + ASSERT_TLV(in.pusch_config.hopping_offset, in.pusch_config.hopping_offset); + ASSERT_TLV(in.pusch_config.number_of_subbands, in.pusch_config.number_of_subbands); + + ASSERT_TLV(in.pucch_config.delta_pucch_shift, out.pucch_config.delta_pucch_shift); + ASSERT_TLV(in.pucch_config.n_cqi_rb, out.pucch_config.n_cqi_rb); + ASSERT_TLV(in.pucch_config.n_an_cs, out.pucch_config.n_an_cs); + ASSERT_TLV(in.pucch_config.n1_pucch_an, out.pucch_config.n1_pucch_an); + + ASSERT_TLV(in.srs_config.bandwidth_configuration, out.srs_config.bandwidth_configuration); + ASSERT_TLV(in.srs_config.max_up_pts, out.srs_config.max_up_pts); + ASSERT_TLV(in.srs_config.srs_subframe_configuration, out.srs_config.srs_subframe_configuration); + ASSERT_TLV(in.srs_config.srs_acknack_srs_simultaneous_transmission, out.srs_config.srs_acknack_srs_simultaneous_transmission); + + ASSERT_TLV(in.uplink_reference_signal_config.uplink_rs_hopping, out.uplink_reference_signal_config.uplink_rs_hopping); + ASSERT_TLV(in.uplink_reference_signal_config.group_assignment, out.uplink_reference_signal_config.group_assignment); + ASSERT_TLV(in.uplink_reference_signal_config.cyclic_shift_1_for_drms, out.uplink_reference_signal_config.cyclic_shift_1_for_drms); + + ASSERT_TLV(in.tdd_frame_structure_config.subframe_assignment, out.tdd_frame_structure_config.subframe_assignment); + ASSERT_TLV(in.tdd_frame_structure_config.special_subframe_patterns, out.tdd_frame_structure_config.special_subframe_patterns); + + // laa config + ASSERT_TLV(in.laa_config.ed_threshold_lbt_pdsch, out.laa_config.ed_threshold_lbt_pdsch); + ASSERT_TLV(in.laa_config.ed_threshold_lbt_drs, out.laa_config.ed_threshold_lbt_drs); + ASSERT_TLV(in.laa_config.pd_threshold, out.laa_config.pd_threshold); + ASSERT_TLV(in.laa_config.multi_carrier_type, out.laa_config.multi_carrier_type); + ASSERT_TLV(in.laa_config.multi_carrier_tx, out.laa_config.multi_carrier_tx); + ASSERT_TLV(in.laa_config.multi_carrier_freeze, out.laa_config.multi_carrier_freeze); + ASSERT_TLV(in.laa_config.tx_antenna_ports_drs, out.laa_config.tx_antenna_ports_drs); + ASSERT_TLV(in.laa_config.tx_power_drs, out.laa_config.tx_power_drs); + // emtc config + ASSERT_TLV(in.emtc_config.pbch_repetitions_enable_r13, out.emtc_config.pbch_repetitions_enable_r13); + ASSERT_TLV(in.emtc_config.prach_catm_root_sequence_index, out.emtc_config.prach_catm_root_sequence_index); + ASSERT_TLV(in.emtc_config.prach_catm_zero_correlation_zone_configuration, out.emtc_config.prach_catm_zero_correlation_zone_configuration); + ASSERT_TLV(in.emtc_config.prach_catm_high_speed_flag, out.emtc_config.prach_catm_high_speed_flag); + ASSERT_TLV(in.emtc_config.prach_ce_level_0_enable, out.emtc_config.prach_ce_level_0_enable); + ASSERT_TLV(in.emtc_config.prach_ce_level_0_configuration_index, out.emtc_config.prach_ce_level_0_configuration_index); + ASSERT_TLV(in.emtc_config.prach_ce_level_0_frequency_offset, out.emtc_config.prach_ce_level_0_frequency_offset); + ASSERT_TLV(in.emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt, out.emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt); + ASSERT_TLV(in.emtc_config.prach_ce_level_0_starting_subframe_periodicity, out.emtc_config.prach_ce_level_0_starting_subframe_periodicity); + ASSERT_TLV(in.emtc_config.prach_ce_level_0_hopping_enable, out.emtc_config.prach_ce_level_0_hopping_enable); + ASSERT_TLV(in.emtc_config.prach_ce_level_0_hopping_offset, out.emtc_config.prach_ce_level_0_hopping_offset); + ASSERT_TLV(in.emtc_config.prach_ce_level_1_enable, out.emtc_config.prach_ce_level_1_enable); + ASSERT_TLV(in.emtc_config.prach_ce_level_1_configuration_index, out.emtc_config.prach_ce_level_1_configuration_index); + ASSERT_TLV(in.emtc_config.prach_ce_level_1_frequency_offset, out.emtc_config.prach_ce_level_1_frequency_offset); + ASSERT_TLV(in.emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt, out.emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt); + ASSERT_TLV(in.emtc_config.prach_ce_level_1_starting_subframe_periodicity, out.emtc_config.prach_ce_level_1_starting_subframe_periodicity); + ASSERT_TLV(in.emtc_config.prach_ce_level_1_hopping_enable, out.emtc_config.prach_ce_level_1_hopping_enable); + ASSERT_TLV(in.emtc_config.prach_ce_level_1_hopping_offset, out.emtc_config.prach_ce_level_1_hopping_offset); + ASSERT_TLV(in.emtc_config.prach_ce_level_2_enable, out.emtc_config.prach_ce_level_2_enable); + ASSERT_TLV(in.emtc_config.prach_ce_level_2_configuration_index, out.emtc_config.prach_ce_level_2_configuration_index); + ASSERT_TLV(in.emtc_config.prach_ce_level_2_frequency_offset, out.emtc_config.prach_ce_level_2_frequency_offset); + ASSERT_TLV(in.emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt, out.emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt); + ASSERT_TLV(in.emtc_config.prach_ce_level_2_starting_subframe_periodicity, out.emtc_config.prach_ce_level_2_starting_subframe_periodicity); + ASSERT_TLV(in.emtc_config.prach_ce_level_2_hopping_enable, out.emtc_config.prach_ce_level_2_hopping_enable); + ASSERT_TLV(in.emtc_config.prach_ce_level_2_hopping_offset, out.emtc_config.prach_ce_level_2_hopping_offset); + ASSERT_TLV(in.emtc_config.prach_ce_level_3_enable, out.emtc_config.prach_ce_level_3_enable); + ASSERT_TLV(in.emtc_config.prach_ce_level_3_configuration_index, out.emtc_config.prach_ce_level_3_configuration_index); + ASSERT_TLV(in.emtc_config.prach_ce_level_3_frequency_offset, out.emtc_config.prach_ce_level_3_frequency_offset); + ASSERT_TLV(in.emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt, out.emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt); + ASSERT_TLV(in.emtc_config.prach_ce_level_3_starting_subframe_periodicity, out.emtc_config.prach_ce_level_3_starting_subframe_periodicity); + ASSERT_TLV(in.emtc_config.prach_ce_level_3_hopping_enable, out.emtc_config.prach_ce_level_3_hopping_enable); + ASSERT_TLV(in.emtc_config.prach_ce_level_3_hopping_offset, out.emtc_config.prach_ce_level_3_hopping_offset); + ASSERT_TLV(in.emtc_config.pucch_interval_ulhoppingconfigcommonmodea, out.emtc_config.pucch_interval_ulhoppingconfigcommonmodea); + ASSERT_TLV(in.emtc_config.pucch_interval_ulhoppingconfigcommonmodeb, out.emtc_config.pucch_interval_ulhoppingconfigcommonmodeb); + + ASSERT_TLV(in.l23_config.data_report_mode, out.l23_config.data_report_mode); + ASSERT_TLV(in.l23_config.sfnsf, out.l23_config.sfnsf); + + CU_ASSERT_EQUAL(in.nfapi_config.p7_vnf_address_ipv4.tl.tag, out.nfapi_config.p7_vnf_address_ipv4.tl.tag); + for(idx = 0; idx < NFAPI_IPV4_ADDRESS_LENGTH; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.p7_vnf_address_ipv4.address[idx], out.nfapi_config.p7_vnf_address_ipv4.address[idx]); + } + + CU_ASSERT_EQUAL(in.nfapi_config.p7_vnf_address_ipv6.tl.tag, out.nfapi_config.p7_vnf_address_ipv6.tl.tag); + for(idx = 0; idx < NFAPI_IPV6_ADDRESS_LENGTH; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.p7_vnf_address_ipv6.address[idx], out.nfapi_config.p7_vnf_address_ipv6.address[idx]); + } + + ASSERT_TLV(in.nfapi_config.p7_vnf_port, out.nfapi_config.p7_vnf_port); + + CU_ASSERT_EQUAL(in.nfapi_config.p7_pnf_address_ipv4.tl.tag, out.nfapi_config.p7_pnf_address_ipv4.tl.tag); + for(idx = 0; idx < NFAPI_IPV4_ADDRESS_LENGTH; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.p7_pnf_address_ipv4.address[idx], out.nfapi_config.p7_pnf_address_ipv4.address[idx]); + } + + CU_ASSERT_EQUAL(in.nfapi_config.p7_pnf_address_ipv6.tl.tag, out.nfapi_config.p7_pnf_address_ipv6.tl.tag); + for(idx = 0; idx < NFAPI_IPV6_ADDRESS_LENGTH; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.p7_pnf_address_ipv6.address[idx], out.nfapi_config.p7_pnf_address_ipv6.address[idx]); + } + + ASSERT_TLV(in.nfapi_config.p7_pnf_port, out.nfapi_config.p7_pnf_port); + ASSERT_TLV(in.nfapi_config.dl_ue_per_sf, out.nfapi_config.dl_ue_per_sf); + ASSERT_TLV(in.nfapi_config.ul_ue_per_sf, out.nfapi_config.ul_ue_per_sf); + + CU_ASSERT_EQUAL(in.nfapi_config.rf_bands.tl.tag, out.nfapi_config.rf_bands.tl.tag); + CU_ASSERT_EQUAL(in.nfapi_config.rf_bands.number_rf_bands, out.nfapi_config.rf_bands.number_rf_bands); + for(idx = 0; idx < out.nfapi_config.rf_bands.number_rf_bands; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.rf_bands.rf_band[idx], out.nfapi_config.rf_bands.rf_band[idx]); + } + + ASSERT_TLV(in.nfapi_config.timing_window, out.nfapi_config.timing_window); + ASSERT_TLV(in.nfapi_config.timing_info_mode, out.nfapi_config.timing_info_mode); + ASSERT_TLV(in.nfapi_config.timing_info_period, out.nfapi_config.timing_info_period); + ASSERT_TLV(in.nfapi_config.max_transmit_power, out.nfapi_config.max_transmit_power); + ASSERT_TLV(in.nfapi_config.earfcn, out.nfapi_config.earfcn); + + CU_ASSERT_EQUAL(in.nfapi_config.nmm_gsm_frequency_bands.tl.tag, out.nfapi_config.nmm_gsm_frequency_bands.tl.tag); + CU_ASSERT_EQUAL(in.nfapi_config.nmm_gsm_frequency_bands.number_of_rf_bands, out.nfapi_config.nmm_gsm_frequency_bands.number_of_rf_bands); + for(idx = 0; idx < out.nfapi_config.nmm_gsm_frequency_bands.number_of_rf_bands; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.nmm_gsm_frequency_bands.bands[idx], out.nfapi_config.nmm_gsm_frequency_bands.bands[idx]); + } + + CU_ASSERT_EQUAL(in.nfapi_config.nmm_umts_frequency_bands.tl.tag, out.nfapi_config.nmm_umts_frequency_bands.tl.tag); + CU_ASSERT_EQUAL(in.nfapi_config.nmm_umts_frequency_bands.number_of_rf_bands, out.nfapi_config.nmm_umts_frequency_bands.number_of_rf_bands); + for(idx = 0; idx < out.nfapi_config.nmm_umts_frequency_bands.number_of_rf_bands; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.nmm_umts_frequency_bands.bands[idx], out.nfapi_config.nmm_umts_frequency_bands.bands[idx]); + } + + CU_ASSERT_EQUAL(in.nfapi_config.nmm_lte_frequency_bands.tl.tag, out.nfapi_config.nmm_lte_frequency_bands.tl.tag); + CU_ASSERT_EQUAL(in.nfapi_config.nmm_lte_frequency_bands.number_of_rf_bands, out.nfapi_config.nmm_lte_frequency_bands.number_of_rf_bands); + for(idx = 0; idx < out.nfapi_config.nmm_lte_frequency_bands.number_of_rf_bands; ++idx) + { + CU_ASSERT_EQUAL(in.nfapi_config.nmm_lte_frequency_bands.bands[idx], out.nfapi_config.nmm_lte_frequency_bands.bands[idx]); + } + + ASSERT_TLV(in.nfapi_config.nmm_uplink_rssi_supported, out.nfapi_config.nmm_uplink_rssi_supported); +} +void nfapi_test_config_response() +{ + nfapi_config_response_t in; + memset(&in, 0, sizeof(in)); + nfapi_config_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_CONFIG_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_MSG_OK; + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); +} +void nfapi_test_start_request() +{ + nfapi_start_request_t in; + memset(&in, 0, sizeof(in)); + nfapi_start_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_START_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); +} +void nfapi_test_start_response() +{ + nfapi_start_response_t in; + memset(&in, 0, sizeof(in)); + nfapi_start_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_START_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_MSG_OK; + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); +} +void nfapi_test_stop_request() +{ + nfapi_stop_request_t in; + memset(&in, 0, sizeof(in)); + nfapi_stop_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_STOP_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + +} +void nfapi_test_stop_response() +{ + nfapi_stop_response_t in; + memset(&in, 0, sizeof(in)); + nfapi_stop_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_STOP_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_MSG_OK; + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); +} +void nfapi_test_measurement_request() +{ +// #define SET_TLV(_TLV, _TAG, _VALUE) { _TLV.tl.tag = _TAG; _TLV.value = _VALUE; } +// #define ASSERT_TLV(IN_TLV, OUT_TLV) { CU_ASSERT_EQUAL(IN_TLV.tl.tag, OUT_TLV.tl.tag); CU_ASSERT_EQUAL(IN_TLV.value, OUT_TLV.value);} + uint16_t num_tlv = 0; + nfapi_measurement_request_t in; + memset(&in, 0, sizeof(in)); + nfapi_measurement_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_MEASUREMENT_REQUEST; + in.header.message_length = 0; + in.header.spare = 0; + + SET_TLV(in.dl_rs_tx_power, NFAPI_MEASUREMENT_REQUEST_DL_RS_XTX_POWER_TAG, 1); + SET_TLV(in.received_interference_power, NFAPI_MEASUREMENT_REQUEST_RECEIVED_INTERFERENCE_POWER_TAG, 123); + SET_TLV(in.thermal_noise_power, NFAPI_MEASUREMENT_REQUEST_THERMAL_NOISE_POWER_TAG, 255); + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + + + ASSERT_TLV(in.dl_rs_tx_power, out.dl_rs_tx_power); + ASSERT_TLV(in.received_interference_power, out.received_interference_power); + ASSERT_TLV(in.thermal_noise_power, out.thermal_noise_power); +} +void nfapi_test_measurement_response() +{ + uint16_t num_tlv = 0; + nfapi_measurement_response_t in; + memset(&in, 0, sizeof(in)); + nfapi_measurement_response_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_MEASUREMENT_RESPONSE; + in.header.message_length = 0; + in.header.spare = 0; + + in.error_code = NFAPI_MSG_OK; + + SET_TLV(in.dl_rs_tx_power_measurement, NFAPI_MEASUREMENT_RESPONSE_DL_RS_POWER_MEASUREMENT_TAG, -400); + + in.received_interference_power_measurement.tl.tag = NFAPI_MEASUREMENT_RESPONSE_RECEIVED_INTERFERENCE_POWER_MEASUREMENT_TAG; + in.received_interference_power_measurement.number_of_resource_blocks = 100; + in.received_interference_power_measurement.received_interference_power[0] = -8767; + + SET_TLV(in.thermal_noise_power_measurement, NFAPI_MEASUREMENT_RESPONSE_THERMAL_NOISE_MEASUREMENT_TAG, -8900); + + int packedMessageLength = nfapi_p5_message_pack(&in, sizeof(in), gTestNfapiMessageTx, MAX_PACKED_MESSAGE_SIZE, 0); + + nfapi_p5_message_unpack(gTestNfapiMessageTx, packedMessageLength, &out, sizeof(out), 0); + + CU_ASSERT_EQUAL(in.header.message_id, out.header.message_id); + CU_ASSERT_EQUAL(in.error_code, out.error_code); + + ASSERT_TLV(in.dl_rs_tx_power_measurement, out.dl_rs_tx_power_measurement); + CU_ASSERT_EQUAL(in.received_interference_power_measurement.tl.tag, out.received_interference_power_measurement.tl.tag); + CU_ASSERT_EQUAL(in.received_interference_power_measurement.number_of_resource_blocks, out.received_interference_power_measurement.number_of_resource_blocks); + // check array + ASSERT_TLV(in.thermal_noise_power_measurement, out.thermal_noise_power_measurement); +} + +void nfapi_test_dl_config_request() +{ + + + uint16_t idx = 0; + nfapi_dl_config_request_t in; + memset(&in, 0, sizeof(in)); + nfapi_dl_config_request_t out; + + in.header.phy_id = NFAPI_PHY_ID_NA; + in.header.message_id = NFAPI_DL_CONFIG_REQUEST; + in.header.message_length = 0; + in.header.m_segment_sequence = 0xDDDD; + in.header.checksum = 0xEEEEEEEE; + + in.sfn_sf = 0x3FFF; + + in.dl_config_request_body.tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + in.dl_config_request_body.number_pdcch_ofdm_symbols = 4; + in.dl_config_request_body.number_dci = 255; + in.dl_config_request_body.number_pdu = 0; + in.dl_config_request_body.number_pdsch_rnti = 0; + in.dl_config_request_body.transmission_power_pcfich = 10000; + + in.dl_config_request_body.dl_config_pdu_list = (nfapi_dl_config_request_pdu_t*)(malloc(sizeof(nfapi_dl_config_request_pdu_t) * 12)); + + in.dl_config_request_body.dl_config_pdu_list[0].pdu_type = 0; + in.dl_config_request_body.dl_config_pdu_list[0].pdu_size = 123; + in.dl_config_request_body.dl_config_pdu_list[0].dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; + in.dl_config_request_body.dl_config_pdu_list[0].dci_dl_pdu.dci_dl_pdu_rel9.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL9_TAG; + in.dl_config_request_body.dl_config_pdu_list[0].dci_dl_pdu.dci_dl_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL10_TAG; + in.dl_config_request_body.dl_config_pdu_list[0].dci_dl_pdu.dci_dl_pdu_rel11.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL11_TAG; + in.dl_config_request_body.dl_config_pdu_list[0].dci_dl_pdu.dci_dl_pdu_rel12.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL12_TAG; + in.dl_config_request_body.dl_config_pdu_list[0].dci_dl_pdu.dci_dl_pdu_rel12.primary_cell_type = rand8(0, 2); + in.dl_config_request_body.dl_config_pdu_list[0].dci_dl_pdu.dci_dl_pdu_rel12.ul_dl_configuration_flag = rand8(0, 1); + in.dl_config_request_body.dl_config_pdu_list[0].dci_dl_pdu.dci_dl_pdu_rel12.number_ul_dl_configurations = rand8(0, 5); + for(idx = 0; idx pSuite; + int count = 0; + while(s) + { + CU_pTest t = s->pTest; + while(t) + { + count++; + t = t->pNext; + } + s = s->pNext; + } + + printf("%d..%d\n", 1, count); + + + + s = CU_get_registry()->pSuite; + count = 1; + while(s) + { + CU_pTest t = s->pTest; + while(t) + { + int pass = 1; + CU_FailureRecord* failures = CU_get_failure_list(); + while(failures) + { + if(strcmp(failures->pSuite->pName, s->pName) == 0 && + strcmp(failures->pTest->pName, t->pName) == 0) + { + pass = 0; + failures = 0; + } + else + { + failures = failures->pNext; + } + } + + if(pass) + printf("ok %d - %s:%s\n", count, s->pName, t->pName); + else + printf("not ok %d - %s:%s\n", count, s->pName, t->pName); + + count++; + t = t->pNext; + } + s = s->pNext; + } + + /* + s = CU_get_registry()->pSuite; + while(s) + { + printf("Suite %s\n", s->pName); + CU_pTest t = s->pTest; + while(t) + { + printf(" Test %s\n", t->pName); + i//CU_ErrorCode e = CU_basic_run_test(s, t); + + t = t->pNext; + } + s = s->pNext; + } + */ + + + + //printf("CU_basic_run_tests completed \n"); + //CU_basic_show_failures(CU_get_failure_list()); + //printf("CU_basic_show_failures completed\n\n"); + /* + // Run all tests using the automated interface + CU_automated_run_tests(); + CU_list_tests_to_file(); + + // Run all tests using the console interface + CU_console_run_tests(); + */ + /* Clean up registry and return */ + + + CU_cleanup_registry(); + return CU_get_error(); + +} diff --git a/nfapi/open-nFAPI/pnf/Makefile.am b/nfapi/open-nFAPI/pnf/Makefile.am new file mode 100644 index 0000000000..663d96b6dd --- /dev/null +++ b/nfapi/open-nFAPI/pnf/Makefile.am @@ -0,0 +1,32 @@ +# +# Copyright 2017 Cisco Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +AUTOMAKE_OPTIONS=subdir-objects + +AM_CPPFLAGS = -I$(top_srcdir)/pnf/inc -I$(top_srcdir)/pnf/public_inc -I$(top_srcdir)/nfapi/public_inc -I$(top_srcdir)/common/public_inc -g -Wall -Werror + + +noinst_LIBRARIES = libnfapi_pnf.a + +libnfapi_pnf_a_SOURCES = src/pnf.c\ + src/pnf_interface.c\ + src/pnf_p7.c\ + src/pnf_p7_interface.c + +LDADD = -lsctp + + + diff --git a/nfapi/open-nFAPI/pnf/inc/pnf.h b/nfapi/open-nFAPI/pnf/inc/pnf.h new file mode 100644 index 0000000000..ab38c66e09 --- /dev/null +++ b/nfapi/open-nFAPI/pnf/inc/pnf.h @@ -0,0 +1,49 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef _PNF_H_ +#define _PNF_H_ + +#include "nfapi_pnf_interface.h" + +#define NFAPI_MAX_PACKED_MESSAGE_SIZE 8192 + +typedef struct { + + nfapi_pnf_config_t _public; + + int p5_sock; + uint8_t tx_message_buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE]; + + uint8_t sctp; + + uint8_t terminate; + +} pnf_t; + + +int pnf_connect(pnf_t *pnf); +int pnf_message_pump(pnf_t *pnf); + +int pnf_pack_and_send_p5_message(pnf_t* pnf, nfapi_p4_p5_message_header_t* msg, uint32_t msg_len); +int pnf_pack_and_send_p4_message(pnf_t* pnf, nfapi_p4_p5_message_header_t* msg, uint32_t msg_len); +int pnf_send_message(pnf_t* pnf, uint8_t* msg, uint32_t msg_len, uint16_t stream_id); + +nfapi_pnf_phy_config_t* nfapi_pnf_phy_config_find(nfapi_pnf_config_t* config, uint16_t phy_id); + +#endif // _PNF_H_ + diff --git a/nfapi/open-nFAPI/pnf/inc/pnf_p7.h b/nfapi/open-nFAPI/pnf/inc/pnf_p7.h new file mode 100644 index 0000000000..3f08d85e6b --- /dev/null +++ b/nfapi/open-nFAPI/pnf/inc/pnf_p7.h @@ -0,0 +1,126 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +#ifndef _PNF_P7_H_ +#define _PNF_P7_H_ + +#define TIMEHR_SEC(_time_hr) ((uint32_t)(_time_hr) >> 20) +#define TIMEHR_USEC(_time_hr) ((uint32_t)(_time_hr) & 0xFFFFF) +#define TIME2TIMEHR(_time) (((uint32_t)(_time.tv_sec) & 0xFFF) << 20 | ((uint32_t)(_time.tv_usec) & 0xFFFFF)) + +#include "nfapi_pnf_interface.h" + +#define NFAPI_MAX_PACKED_MESSAGE_SIZE 8192 + +typedef struct { + uint16_t dl_conf_ontime; + uint16_t dl_conf_late; + uint16_t ul_conf_ontime; + uint16_t ul_conf_late; + uint16_t hi_dci0_ontime; + uint16_t hi_dci0_late; + uint16_t tx_ontime; + uint16_t tx_late; +} pnf_p7_stats_t; + +typedef struct { + uint8_t* buffer; + uint16_t length; +} pnf_p7_rx_message_segment_t; + +typedef struct pnf_p7_rx_message pnf_p7_rx_message_t; + +typedef struct pnf_p7_rx_message { + uint8_t sequence_number; + uint8_t num_segments_received; + uint8_t num_segments_expected; + + // the spec allows of upto 128 segments, this does seem excessive + pnf_p7_rx_message_segment_t segments[128]; + + uint32_t rx_hr_time; + + pnf_p7_rx_message_t* next; +} pnf_p7_rx_message_t; + +typedef struct { + + pnf_p7_rx_message_t* msg_queue; + +} pnf_p7_rx_reassembly_queue_t; + + +typedef struct { + + nfapi_pnf_p7_config_t _public; + + //private data + int p7_sock; + + uint8_t terminate; + + uint8_t tx_message_buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE]; + uint8_t* rx_message_buffer; + uint16_t rx_message_buffer_size; + + pthread_mutex_t mutex; // should we allow the client to specifiy + pthread_mutex_t pack_mutex; // should we allow the client to specifiy + + nfapi_pnf_p7_subframe_buffer_t subframe_buffer[30/*NFAPI_MAX_TIMING_WINDOW_SIZE*/]; + + uint32_t sequence_number; + uint16_t max_num_segments; + + pnf_p7_rx_reassembly_queue_t reassembly_queue; + + uint8_t* reassemby_buffer; + uint32_t reassemby_buffer_size; + + uint16_t sfn_sf; + uint32_t sf_start_time_hr; + int32_t sfn_sf_shift; + + uint8_t timing_info_period_counter; + uint8_t timing_info_aperiodic_send; // 0:false 1:true + + uint32_t timing_info_ms_counter; // number of ms since last timing info + + uint32_t dl_config_jitter; + uint32_t ul_config_jitter; + uint32_t hi_dci0_jitter; + uint32_t tx_jitter; + + uint32_t tick; + pnf_p7_stats_t stats; + +} pnf_p7_t; + +int pnf_p7_message_pump(pnf_p7_t* pnf_p7); + +int pnf_p7_pack_and_send_p7_message(pnf_p7_t* pnf_p7, nfapi_p7_message_header_t* msg, uint32_t msg_len); +int pnf_p7_send_message(pnf_p7_t* pnf_p7, uint8_t* msg, uint32_t msg_len); + + +int pnf_p7_subframe_ind(pnf_p7_t* config, uint16_t phy_id, uint16_t sfn_sf); + +pnf_p7_rx_message_t* pnf_p7_rx_reassembly_queue_add_segment(pnf_p7_t* pnf_p7, pnf_p7_rx_reassembly_queue_t* queue, uint32_t rx_hr_time, uint16_t sequence_number, uint16_t segment_number, uint8_t m, uint8_t* data, uint16_t data_len); +void pnf_p7_rx_reassembly_queue_remove_msg(pnf_p7_t* pnf_p7, pnf_p7_rx_reassembly_queue_t* queue, pnf_p7_rx_message_t* msg); +void pnf_p7_rx_reassembly_queue_remove_old_msgs(pnf_p7_t* pnf_p7, pnf_p7_rx_reassembly_queue_t* queue, uint32_t rx_hr_time, uint32_t delta); + +#endif /* _PNF_P7_H_ */ + diff --git a/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h b/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h new file mode 100644 index 0000000000..b25caf2876 --- /dev/null +++ b/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h @@ -0,0 +1,803 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef _NFAPI_PNF_INTERFACE_H_ +#define _NFAPI_PNF_INTERFACE_H_ + +#if defined(__cplusplus) +extern "C" { +#endif + +#include "nfapi_interface.h" +#include "debug.h" + +#include + +/*! This enum is used to describe the states of the pnf + */ +typedef enum +{ + NFAPI_PNF_IDLE = 0, + NFAPI_PNF_CONFIGURED, + NFAPI_PNF_RUNNING +} nfapi_pnf_state_e; + +/*! This enum is used to describe the states of a phy instance of a pnf + */ +typedef enum +{ + NFAPI_PNF_PHY_IDLE = 0, + NFAPI_PNF_PHY_CONFIGURED = 1, + NFAPI_PNF_PHY_RUNNING = 2 +} nfapi_pnf_phy_state_e; + +typedef struct nfapi_pnf_phy_config nfapi_pnf_phy_config_t; + +/*! Configuration information for a pnf phy instance + */ +typedef struct nfapi_pnf_phy_config +{ + /*! The PHY id*/ + uint16_t phy_id; + + /*! The state of the PNF PHY instance*/ + nfapi_pnf_phy_state_e state; + + /*! Optional user defined data that will be passed back in the callbacks*/ + void* user_data; + + /*! Pointer for use in a linked list */ + struct nfapi_pnf_phy_config* next; +} nfapi_pnf_phy_config_t; + +typedef struct nfapi_pnf_config nfapi_pnf_config_t; + +/*! Configuration information for the pnf created by calling nfapi_pnf_create + */ +typedef struct nfapi_pnf_config +{ + /*! A user define callback to override the default memory allocation + * \param size The size of the data buffer to allocate + * \return A pointer to a data buffer + */ + void* (*malloc)(size_t size); + + /*! A user define callback to override the default memory deallocation + * \param ptr Pointer to a data buffer to be deallocated + */ + void (*free)(void* ptr); + + /*! A user define callback to handle trace from the pnf + * \param level The trace level + * \param message The trace string + * + * This is a vardic function. + */ + void (*trace)(nfapi_trace_level_t level, const char* message, ...); + + /*! The ip address of the VNF + * + */ + char* vnf_ip_addr; + + /*! The ip port of the VNF + */ + int vnf_p5_port; + + /*! The state of the PNF */ + nfapi_pnf_state_e state; + + /*! List of PHY instances configured for this PNF */ + nfapi_pnf_phy_config_t* phys; + + /*! Configuation option of the p4 p5 encode decode functions */ + nfapi_p4_p5_codec_config_t codec_config; + + /*! Optional user defined data that will be passed back in the callbacks*/ + void* user_data; + + + /*! A callback for the PNF_PARAM.request + * \param config A pointer to the pnf configuration + * \param req A data structure for the decoded PNF_PARAM.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the PNF_PARAM.response after receiving the + * PNF_PARAM.request. This can be done in the call back. + */ + int (*pnf_param_req)(nfapi_pnf_config_t* config, nfapi_pnf_param_request_t* req); + + /*! A callback for the PNF_CONFIG.request + * \param config A pointer to the pnf configuration + * \param req A data structure for the decoded PNF_CONFIG.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the PNF_CONFIG.response after receiving the + * PNF_CONFIG.request. This can be done in the call back. + */ + int (*pnf_config_req)(nfapi_pnf_config_t* config, nfapi_pnf_config_request_t* req); + + /*! A callback for the PNF_START.request + * \param config A pointer to the pnf configuration + * \param req A data structure for the decoded PNF_CONFIG.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the PNF_START.response after receiving the + * PNF_START.request. This can be done in the call back. + */ + int (*pnf_start_req)(nfapi_pnf_config_t* config, nfapi_pnf_start_request_t* req); + + /*! A callback for the PNF_STOP.request + * \param config A pointer to the pnf configuration + * \param req A data structure for the decoded PNF_STOP.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the PNF_STOP.response after receiving the + * PNF_STOP.request. This can be done in the call back. + */ + int (*pnf_stop_req)(nfapi_pnf_config_t* config, nfapi_pnf_stop_request_t* req); + + /*! A callback for the PARAM.request + * \param config A pointer to the pnf configuration + * \param phy A pointer to the pnf phy configuration + * \param req A data structure for the decoded PARAM.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the PARAM.response after receiving the + * PARAM.request. This can be done in the call back. + */ + int (*param_req)(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_param_request_t* req); + + /*! A callback for the CONFIG.request + * \param config A pointer to the pnf configuration + * \param phy A pointer to the pnf phy configuration + * \param req A data structure for the decoded CONFIG.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the CONFIG.response after receiving the + * CONFIG.request. This can be done in the call back. + */ + int (*config_req)(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_config_request_t* req); + + /*! A callback for the START.request + * \param config A pointer to the pnf configuration + * \param phy A pointer to the pnf phy configuration + * \param req A data structure for the decoded START.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the START.response after the client has received the + * first subframe indication from FAPI. + */ + int (*start_req)(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_start_request_t* req); + + /*! A callback for the STOP.request + * \param config A pointer to the pnf configuration + * \param phy A pointer to the pnf phy configuration + * \param req A data structure for the decoded STOP.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the STOP.response after receiving the + * STOP.request. This can be done in the call back. + */ + int (*stop_req)(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_stop_request_t* req); + + /*! A callback for the MEASUREMENT.request + * \param config A pointer to the pnf configuration + * \param phy A pointer to the pnf phy configuration + * \param req A data structure for the decoded MEASUREMENT.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the MEASUREMENT.response after receiving the + * MEASUREMENT.request. This can be done in the call back. + */ + int (*measurement_req)(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_measurement_request_t* req); + + /*! A callback for the RSSI.request + * \param config A pointer to the pnf configuration + * \param phy A pointer to the pnf phy configuration + * \param req A data structure for the decoded RSSI.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the RSSI.response after receiving the + * RSSI.request. This can be done in the call back. + */ + int (*rssi_req)(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_rssi_request_t* req); + + /*! A callback for the CELL_SEARCH.request + * \param config A pointer to the pnf configuration + * \param phy A pointer to the pnf phy configuration + * \param req A data structure for the decoded CELL_SEARCH.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the CELL_SEARCH.response after receiving the + * CELL_SEARCH.request. This can be done in the call back. + */ + int (*cell_search_req)(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_cell_search_request_t* req); + + /*! A callback for the BROADCAST_DETECT.request + * \param config A pointer to the pnf configuration + * \param phy A pointer to the pnf phy configuration + * \param req A data structure for the decoded BROADCAST_DETECT.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the BROADCAST_DETECT.response after receiving the + * BROADCAST_DETECT.request. This can be done in the call back. + */ + int (*broadcast_detect_req)(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_broadcast_detect_request_t* req); + + /*! A callback for the SYSTEM_INFORMATION_SCHEDULE.request + * \param config A pointer to the pnf configuration + * \param phy A pointer to the pnf phy configuration + * \param req A data structure for the decoded SYSTEM_INFORMATION_SCHEDULE.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the SYSTEM_INFORMATION_SCHEDULE.response after receiving the + * SYSTEM_INFORMATION_SCHEDULE.request. This can be done in the call back. + */ + int (*system_information_schedule_req)(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_system_information_schedule_request_t* req); + + /*! A callback for the SYSTEM_INFORMATION.request + * \param config A pointer to the pnf configuration + * \param phy A pointer to the pnf phy configuration + * \param req A data structure for the decoded SYSTEM_INFORMATION.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the SYSTEM_INFORMATION.response after receiving the + * SYSTEM_INFORMATION.request. This can be done in the call back. + */ + int (*system_information_req)(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_system_information_request_t* req); + + /*! A callback for the NMM_STOP.request + * \param config A pointer to the pnf configuration + * \param phy A pointer to the pnf phy configuration + * \param req A data structure for the decoded NMM_STOP.request. This will have + * been allocated on the stack + * \return not currently used + * + * The client is expected to send the NMM_STOP.response after receiving the + * NMM_STOP.request. This can be done in the call back. + */ + int (*nmm_stop_req)(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_nmm_stop_request_t* req); + + /*! A callback for any vendor extension messages recevied + * \param config A pointer to the pnf configuration + * \param msg A pointer to the decode P4/P5 message + * \return not current used + */ + int (*vendor_ext)(nfapi_pnf_config_t* config, nfapi_p4_p5_message_header_t* msg); + + /*! A callback to allocate vendor extension message + * \param message_id The message id from the decode P4/P5 message header + * \param msg_size A pointer a the size of the allocated message structure. The callee should set this + * \return A pointer to a allocated P4/P5 message structure + */ + nfapi_p4_p5_message_header_t* (*allocate_p4_p5_vendor_ext)(uint16_t message_id, uint16_t* msg_size); + + /*! A callback to deallocate vendor extension message + * \param header A pointer to an P4/P5 message structure + */ + void (*deallocate_p4_p5_vendor_ext)(nfapi_p4_p5_message_header_t* header); + + + +} nfapi_pnf_config_t; + +/*! Create a pnf configuration + * \return A pointer to a pnf configuration struture + * + * This function will create and initialize a pnf instance. It is expected that + * the client will set the callback and parameters need before calling nfapi_pnf_start + * + * 0 will be returned if it fails. + * + * \code + * nfapi_pnf_config_t* config = nfapi_pnf_config_create(void); + * \endcode + */ +nfapi_pnf_config_t* nfapi_pnf_config_create(void); + +/*! Delete a pnf configuration + * \param config A pointer to a pnf configuraiton + * \return 0 is success, -1 for failure + */ +int nfapi_pnf_config_destroy(nfapi_pnf_config_t* config); + +/*! Start the PNF library. + * \param config A pointer to the pnf configuration + * \return 0 is success, -1 for failure + * + * This function will not return until nfapi_pnf_stop is called + * + * \code + * // Create the pnf config + * nfapi_pnf_config_t* config = nfapi_pnf_config_create(); + * + * // Assumed that the vnf_address and vnf_port are provided over the P9 interface + * config->vnf_ip_addr = vnf_address; + * config->vnf_p5_port = vnf_port; + * + * // Set the required callbacks + * config->pnf_param_req = &pnf_param_request; + * ... + * + * // Call start for the PNF to initiate a connection to the VNF + * nfai_pnf_start(config); + * + * \endcode + */ +int nfapi_pnf_start(nfapi_pnf_config_t* config); + +/*! Stop the PNF library. + * \param config A pointer to the pnf configuration + * \return 0 is success, -1 for failure + * + * This function will cause the nfapi_pnf_start function to return + */ +int nfapi_pnf_stop(nfapi_pnf_config_t* config); + +/*! Send the PNF_PARAM.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_pnf_param_resp(nfapi_pnf_config_t* config, nfapi_pnf_param_response_t* resp); + +/*! Send the PNF_CONFIG.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_pnf_config_resp(nfapi_pnf_config_t* config, nfapi_pnf_config_response_t* resp); + +/*! Send the PNF_START.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_pnf_start_resp(nfapi_pnf_config_t* config, nfapi_pnf_start_response_t* resp); + +/*! Send the PNF_STOP.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_pnf_stop_resp(nfapi_pnf_config_t* config, nfapi_pnf_stop_response_t* resp); + +/*! Send the PARAM.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_param_resp(nfapi_pnf_config_t* config, nfapi_param_response_t* resp); + +/*! Send the CONFIG.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_config_resp(nfapi_pnf_config_t* config, nfapi_config_response_t* resp); + +/*! Send the START.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_start_resp(nfapi_pnf_config_t* config, nfapi_start_response_t* resp); + +/*! Send the STOP.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_stop_resp(nfapi_pnf_config_t* config, nfapi_stop_response_t* resp); + +/*! Send the MEASUREMENT.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_measurement_resp(nfapi_pnf_config_t* config, nfapi_measurement_response_t* resp); + +/*! Send the RSSI.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_rssi_resp(nfapi_pnf_config_t* config, nfapi_rssi_response_t* resp); + +/*! Send the RSSI.indication + * \param config A pointer to a pnf configuraiton + * \param ind A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_rssi_ind(nfapi_pnf_config_t* config, nfapi_rssi_indication_t* ind); + +/*! Send the CELL_SEARCH.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_cell_search_resp(nfapi_pnf_config_t* config, nfapi_cell_search_response_t* resp); + +/*! Send the CELL_SEARCH.indication + * \param config A pointer to a pnf configuraiton + * \param ind A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_cell_search_ind(nfapi_pnf_config_t* config, nfapi_cell_search_indication_t* ind); + +/*! Send the BROADCAST_DETECT.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_broadcast_detect_resp(nfapi_pnf_config_t* config, nfapi_broadcast_detect_response_t* resp); + +/*! Send the BROADCAST_DETECT.indication + * \param config A pointer to a pnf configuraiton + * \param ind A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_broadcast_detect_ind(nfapi_pnf_config_t* config, nfapi_broadcast_detect_indication_t* ind); + +/*! Send the SYSTEM_INFORMATION_SCHEDULE.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_system_information_schedule_resp(nfapi_pnf_config_t* config, nfapi_system_information_schedule_response_t* resp); + +/*! Send the SYSTEM_INFORMATION_SCHEDULE.indication + * \param config A pointer to a pnf configuraiton + * \param ind A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_system_information_schedule_ind(nfapi_pnf_config_t* config, nfapi_system_information_schedule_indication_t* ind); + +/*! Send the SYSTEM_INFORMATION.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_system_information_resp(nfapi_pnf_config_t* config, nfapi_system_information_response_t* resp); + +/*! Send the SYSTEM_INFORMATION.indication + * \param config A pointer to a pnf configuraiton + * \param ind A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_system_information_ind(nfapi_pnf_config_t* config, nfapi_system_information_indication_t* ind); + +/*! Send the NMM_STOP.response + * \param config A pointer to a pnf configuraiton + * \param resp A pointer to the message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_nmm_stop_resp(nfapi_pnf_config_t* config, nfapi_nmm_stop_response_t* resp); + +/*! Send a vendor extension message + * \param config A pointer to a pnf configuraiton + * \param msg A pointer to the vendor extention message structure + * \param msg_len The size of the vendor extention message structure + * \return 0 for success, -1 for failure + * + */ +int nfapi_pnf_vendor_extension(nfapi_pnf_config_t* config, nfapi_p4_p5_message_header_t* msg, uint32_t msg_len); + +//-------------------------- + +/*! A subframe buffer structure which can be used by the client to + * to configure the dummy information + */ +typedef struct +{ + uint16_t sfn_sf; + + nfapi_dl_config_request_t* dl_config_req; + nfapi_ul_config_request_t* ul_config_req; + nfapi_hi_dci0_request_t* hi_dci0_req; + nfapi_tx_request_t* tx_req; + nfapi_lbt_dl_config_request_t* lbt_dl_config_req; + +} nfapi_pnf_p7_subframe_buffer_t; + +typedef struct nfapi_pnf_p7_config nfapi_pnf_p7_config_t; + +/*! The nfapi PNF PHY P7 configuration information created using the nfapi_pnf_p7_create function + */ +typedef struct nfapi_pnf_p7_config +{ + /*! A user define callback to override the default memory allocation + * \param size The size of the buffer to allocate + * \return An allocated buffer. 0 in the case of failure + * + * If not set malloc will be used + */ + void* (*malloc)(size_t size); + + /*! A user define callback to override the default memory deallocation + * \param ptr Pointer to a buffer to dellocate + * + * If not set free will be used + */ + void (*free)(void* ptr); + + /*! A user define callback to handle trace from the pnf + * \param level The trace level + * \param message The message string + */ + void (*trace)(nfapi_trace_level_t level, const char* message, ...); + + /*! The PHY id*/ + uint16_t phy_id; + + // remote + /*! The VNF P7 UDP port */ + int remote_p7_port; + /*! The VNF P7 UDP address */ + char* remote_p7_addr; + + // local + /*! The PNF P7 UDP port */ + int local_p7_port; + /*! The PNF P7 UDP address */ + char* local_p7_addr; + + /*! Flag to indicate of the pnf should use the P7 checksum */ + uint8_t checksum_enabled; + + /*! The maxium size of a P7 segement. If a message is large that this it + * will be segemented */ + uint16_t segment_size; + + /*! The dummy subframe buffer structure that should be used in case there + * are no 'valid' subframe messages */ + nfapi_pnf_p7_subframe_buffer_t dummy_subframe; + + /*! Configuration options for the p7 pack unpack functions*/ + nfapi_p7_codec_config_t codec_config; + + /*! Optional userdata that will be passed back in the callbacks*/ + void* user_data; + + // tdb : if these should be public + uint16_t subframe_buffer_size; + uint8_t timing_info_mode_periodic; // 0:false 1:true + uint8_t timing_info_mode_aperiodic; // 0:false 1:true + uint8_t timing_info_period; // 1..225 in subframes + + /*! A callback for the DL_CONFIG.request + * \param config A poiner to the PNF P7 config + * \param req A pointer to the dl config request message structure + * \return not currently used + */ + int (*dl_config_req)(nfapi_pnf_p7_config_t* config, nfapi_dl_config_request_t* req); + + /*! A callback for the UL_CONFIG.request + * \param config A poiner to the PNF P7 config + * \param req A pointer to the ul config request message structure + * \return not currently used + */ + int (*ul_config_req)(nfapi_pnf_p7_config_t* config, nfapi_ul_config_request_t* req); + + /*! A callback for the HI_DCI0.request + * \param config A poiner to the PNF P7 config + * \param req A pointer to the hi dci0 request message structure + * \return not currently used + */ + int (*hi_dci0_req)(nfapi_pnf_p7_config_t* config, nfapi_hi_dci0_request_t* req); + + /*! A callback for the TX_REQ.request + * \param config A poiner to the PNF P7 config + * \param req A pointer to the tx request message structure + * \return not currently used + * + * The TX request contains pointers to the downlink PDUs to be sent. In the case that the FAPI interface + * will 'keep' the pointers until they are transmitted the callee should set the pointers in the req to 0 + * and then use the p7 codec config free function to release the pdu's when appropriate. + */ + int (*tx_req)(nfapi_pnf_p7_config_t* config, nfapi_tx_request_t* req); + + /*! A callback for the LBT_DL_CONFIG.request + * \param config A poiner to the PNF P7 config + * \param req A pointer to the lbt dl request message structure + * \return not currently used + */ + int (*lbt_dl_config_req)(nfapi_pnf_p7_config_t* config, nfapi_lbt_dl_config_request_t* req); + + /*! A callback for vendor extension messages + * \param config A poiner to the PNF P7 config + * \param msg A pointer to a decode vendor extention message + * \return not currently used + */ + int (*vendor_ext)(nfapi_pnf_p7_config_t* config, nfapi_p7_message_header_t* msg); + + /*! A callback to allocate vendor extension message + * \param message_id The vendor extention message id from the decode message header + * \param msg_size A pointer to size of the allocate vendor extention message. Set by the callee + * \return A pointer to an allocated vendor extention message structure. 0 if failed + * + * + */ + nfapi_p7_message_header_t* (*allocate_p7_vendor_ext)(uint16_t message_id, uint16_t* msg_size); + + /*! A callback to deallocate vendor extension message + * \param header A pointer to a p7 vendor extention message + */ + void (*deallocate_p7_vendor_ext)(nfapi_p7_message_header_t* header); + + + +} nfapi_pnf_p7_config_t; + +/*! Create and initialise a nfapi_pnf_p7_config structure + * \return A pointer to a PNF P7 config structure + */ +nfapi_pnf_p7_config_t* nfapi_pnf_p7_config_create(void); + +/*! Delete an nfapi_pnf_p7_config structure + * \param config + */ +int nfapi_pnf_p7_config_destroy(nfapi_pnf_p7_config_t* config); + + +/*! Start the PNF P7 library. + * \param config A pointer to a PNF P7 config + * \return 0 means success, -1 means failure + * + * This function will not return until nfapi_pnf_p7_stop is called. + */ +int nfapi_pnf_p7_start(nfapi_pnf_p7_config_t* config); + +/*! Stop the PNF P7 library. + * \param config A pointer to a PNF P7 config + * \return 0 means success, -1 means failure + * + * This function will cause the nfapi_pnf_p7_start to return + */ +int nfapi_pnf_p7_stop(nfapi_pnf_p7_config_t* config); + +/*! Subframe indication + * \param config A pointer to a PNF P7 config + * \param phy_id The phy_id for the phy instance + * \param sfn_sf The SFN and SF in the format of FAPI + * \return 0 means success, -1 means failure + * + * The client should call the subframe indication every 1ms. The PNF will + * respond by invoking the pnf p7 subframe callbacks with the messages from the subframe buffer + * + * If messages are not in the subframe buffer, they dummy subframe messages will be sent + */ +int nfapi_pnf_p7_subframe_ind(nfapi_pnf_p7_config_t* config, uint16_t phy_id, uint16_t sfn_sf); + +/*! Send the HARQ.indication + * \param config A pointer to a PNF P7 config + * \param ind A pointer to the harq indication message structure + * \return 0 means success, -1 means failure + */ +int nfapi_pnf_p7_harq_ind(nfapi_pnf_p7_config_t* config, nfapi_harq_indication_t* ind); + +/*! Send the CRC.indication + * \param config A pointer to a PNF P7 config + * \param ind A pointer to the crc indication message structure + * \return 0 means success, -1 means failure + */ +int nfapi_pnf_p7_crc_ind(nfapi_pnf_p7_config_t* config, nfapi_crc_indication_t* ind); + +/*! Send the RX.indication + * \param config A pointer to a PNF P7 config + * \param ind A pointer to the rx indication message structure + * \return 0 means success, -1 means failure + */ +int nfapi_pnf_p7_rx_ind(nfapi_pnf_p7_config_t* config, nfapi_rx_indication_t* ind); + +/*! Send the RACH.indication + * \param config A pointer to a PNF P7 config + * \param ind A pointer to the rach indication message structure + * \return 0 means success, -1 means failure + */ +int nfapi_pnf_p7_rach_ind(nfapi_pnf_p7_config_t* config, nfapi_rach_indication_t* ind); + +/*! Send the SRS.indication + * \param config A pointer to a PNF P7 config + * \param ind A pointer to the srs indication message structure + * \return 0 means success, -1 means failure + */ +int nfapi_pnf_p7_srs_ind(nfapi_pnf_p7_config_t* config, nfapi_srs_indication_t* ind); + +/*! Send the SR.indication + * \param config A pointer to a PNF P7 config + * \param ind A pointer to the sr indication message structure + * \return 0 means success, -1 means failure + */ +int nfapi_pnf_p7_sr_ind(nfapi_pnf_p7_config_t* config, nfapi_sr_indication_t* ind); + +/*! Send the CQI.indication + * \param config A pointer to a PNF P7 config + * \param ind A pointer to the cqi indication message structure + * \return 0 means success, -1 means failure + */ +int nfapi_pnf_p7_cqi_ind(nfapi_pnf_p7_config_t* config, nfapi_cqi_indication_t* ind); + +/*! Send the LBT_DL.indication + * \param config A pointer to a PNF P7 config + * \param ind A pointer to the lbt dl indication message structure + * \return 0 means success, -1 means failure + */ +int nfapi_pnf_p7_lbt_dl_ind(nfapi_pnf_p7_config_t* config, nfapi_lbt_dl_indication_t* ind); + +/*! Send the NB_HARQ.indication + * \param config A pointer to a PNF P7 config + * \param ind A pointer to the lbt dl indication message structure + * \return 0 means success, -1 means failure + */ +int nfapi_pnf_p7_nb_harq_ind(nfapi_pnf_p7_config_t* config, nfapi_nb_harq_indication_t* ind); + +/*! Send the NRACH.indication + * \param config A pointer to a PNF P7 config + * \param ind A pointer to the lbt dl indication message structure + * \return 0 means success, -1 means failure + */ +int nfapi_pnf_p7_nrach_ind(nfapi_pnf_p7_config_t* config, nfapi_nrach_indication_t* ind); + + +/*! Send a vendor exntesion message + * \param config A pointer to a PNF P7 config + * \param msg A pointer to the lbt dl indication message structure + * \return 0 means success, -1 means failure + */ +int nfapi_pnf_p7_vendor_extension(nfapi_pnf_p7_config_t* config, nfapi_p7_message_header_t* msg); + +#if defined(__cplusplus) +} +#endif + +#endif // _NFAPI_PNF_INTERFACE_H_ diff --git a/nfapi/open-nFAPI/pnf/src/pnf.c b/nfapi/open-nFAPI/pnf/src/pnf.c new file mode 100644 index 0000000000..d0a7fa6fd1 --- /dev/null +++ b/nfapi/open-nFAPI/pnf/src/pnf.c @@ -0,0 +1,1598 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pnf.h" + +#define MAX_SCTP_STREAMS 16 + +void nfapi_pnf_phy_config_delete_all(nfapi_pnf_config_t* config) +{ + nfapi_pnf_phy_config_t* curr = config->phys; + while(curr != 0) + { + nfapi_pnf_phy_config_t* to_delete = curr; + curr = curr->next; + free(to_delete); + } + + config->phys = 0; +} + +void nfapi_pnf_phy_config_add(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy) +{ + phy->next = config->phys; + config->phys = phy; +} + +nfapi_pnf_phy_config_t* nfapi_pnf_phy_config_find(nfapi_pnf_config_t* config, uint16_t phy_id) +{ + nfapi_pnf_phy_config_t* curr = config->phys; + while(curr != 0) + { + if(curr->phy_id == phy_id) + return curr; + + curr = curr->next; + } + return 0; +} + +void pnf_handle_pnf_param_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + // ensure it's valid + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_pnf_param_request_t req; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF_PARAM.request received\n"); + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(nfapi_pnf_param_request_t), &pnf->_public.codec_config) >= 0) + { + if(pnf->_public.state == NFAPI_PNF_IDLE) + { + if(pnf->_public.pnf_param_req) + { + (pnf->_public.pnf_param_req)(&pnf->_public, &req); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: PNF not in IDLE state\n", __FUNCTION__); + + nfapi_pnf_param_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_PARAM_RESPONSE; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_pnf_param_resp(&pnf->_public, &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + } +} + +void pnf_handle_pnf_config_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + + + // ensure it's valid + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_pnf_config_request_t req; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF_CONFIG.request received\n"); + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &pnf->_public.codec_config) >= 0) + { + // ensure correct state + if(pnf->_public.state != NFAPI_PNF_RUNNING) + { + // delete the phy records + nfapi_pnf_phy_config_delete_all(&pnf->_public); + + // create the phy records + if (req.pnf_phy_rf_config.tl.tag == NFAPI_PNF_PHY_RF_TAG) + { + int i = 0; + for(i = 0; i < req.pnf_phy_rf_config.number_phy_rf_config_info; ++i) + { + nfapi_pnf_phy_config_t* phy = (nfapi_pnf_phy_config_t*)malloc(sizeof(nfapi_pnf_phy_config_t)); + memset(phy, 0, sizeof(nfapi_pnf_phy_config_t)); + + phy->state = NFAPI_PNF_PHY_IDLE; + phy->phy_id = req.pnf_phy_rf_config.phy_rf_config[i].phy_id; + + nfapi_pnf_phy_config_add(&(pnf->_public), phy); + } + } + + if(pnf->_public.pnf_config_req) + { + (pnf->_public.pnf_config_req)(&(pnf->_public), &req); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: PNF not in correct state: %d\n", __FUNCTION__, pnf->_public.state); + + nfapi_pnf_config_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_CONFIG_RESPONSE; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_pnf_config_resp(&(pnf->_public), &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + } +} + +void pnf_handle_pnf_start_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + // ensure it's valid + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_pnf_start_request_t req; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF_START.request Received\n"); + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &pnf->_public.codec_config) >= 0) + { + if(pnf->_public.state == NFAPI_PNF_CONFIGURED) + { + if(pnf->_public.pnf_start_req) + { + (pnf->_public.pnf_start_req)(&(pnf->_public), &req); + } + } + else + { + nfapi_pnf_start_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_START_RESPONSE; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_pnf_start_resp(&(pnf->_public), &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + } +} + +void pnf_handle_pnf_stop_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + // ensure it's valid + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_pnf_stop_request_t req; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF_STOP.request Received\n"); + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &pnf->_public.codec_config) >= 0) + { + if(pnf->_public.state == NFAPI_PNF_RUNNING) + { + if(pnf->_public.pnf_stop_req) + { + (pnf->_public.pnf_stop_req)(&(pnf->_public), &req); + } + } + else + { + nfapi_pnf_stop_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_STOP_RESPONSE; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_pnf_stop_resp(&(pnf->_public), &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + } +} + +void pnf_handle_param_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + // ensure it's valid + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_param_request_t req; + + nfapi_pnf_config_t* config = &(pnf->_public); + + NFAPI_TRACE(NFAPI_TRACE_INFO, "PARAM.request received\n"); + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + { + if(config->state == NFAPI_PNF_RUNNING) + { + nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, req.header.phy_id); + if(phy) + { + if(phy->state == NFAPI_PNF_PHY_IDLE) + { + if(config->param_req) + { + (config->param_req)(config, phy, &req); + } + } + else + { + nfapi_param_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PARAM_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_param_resp(config, &resp); + } + } + else + { + nfapi_param_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PARAM_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_CONFIG; + nfapi_pnf_param_resp(config, &resp); + } + + } + else + { + nfapi_param_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PARAM_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_param_resp(config, &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + + } +} + +void pnf_handle_config_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + + // ensure it's valid + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_config_request_t req; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "CONFIG.request received\n"); + + nfapi_pnf_config_t* config = &(pnf->_public); + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + { + if(config->state == NFAPI_PNF_RUNNING) + { + nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, req.header.phy_id); + if(phy) + { + if(phy->state != NFAPI_PNF_PHY_RUNNING) + { + if(config->config_req) + { + (config->config_req)(config, phy, &req); + } + } + else + { + nfapi_config_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_CONFIG_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_config_resp(config, &resp); + } + } + else + { + nfapi_config_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_CONFIG_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_CONFIG; + nfapi_pnf_config_resp(config, &resp); + } + } + else + { + nfapi_config_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_CONFIG_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_config_resp(config, &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + } +} + +void pnf_handle_start_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + // ensure it's valid + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_start_request_t req; + + nfapi_pnf_config_t* config = &(pnf->_public); + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() START.request received state:%d\n", __FUNCTION__, config->state); + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + { + if(config->state == NFAPI_PNF_RUNNING) + { + nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, req.header.phy_id); + if(phy) + { + if(phy->state != NFAPI_PNF_PHY_RUNNING) + { + if(config->start_req) + { + (config->start_req)(config, phy, &req); + } + } + else + { + nfapi_start_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_START_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_start_resp(config, &resp); + } + } + else + { + nfapi_start_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_START_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_CONFIG; + nfapi_pnf_start_resp(config, &resp); + } + } + else + { + nfapi_start_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_START_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_start_resp(config, &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + + } +} + +void pnf_handle_stop_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + // ensure it's valid + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_stop_request_t req; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "STOP.request received\n"); + + nfapi_pnf_config_t* config = &(pnf->_public); + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + { + if(config->state == NFAPI_PNF_RUNNING) + { + nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, req.header.phy_id); + if(phy) + { + if(phy->state != NFAPI_PNF_PHY_RUNNING) + { + if(config->stop_req) + { + (config->stop_req)(config, phy, &req); + } + } + else + { + nfapi_stop_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_STOP_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_stop_resp(config, &resp); + } + } + else + { + nfapi_stop_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_STOP_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_CONFIG; + nfapi_pnf_stop_resp(config, &resp); + } + } + else + { + nfapi_stop_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_STOP_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_stop_resp(config, &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + + } +} + +void pnf_handle_measurement_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + // ensure it's valid + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_measurement_request_t req; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "MEASUREMENT.request received\n"); + + nfapi_pnf_config_t* config = &(pnf->_public); + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + { + if(config->state == NFAPI_PNF_RUNNING) + { + nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, req.header.phy_id); + if(phy) + { + if(phy->state != NFAPI_PNF_PHY_RUNNING) + { + if(config->measurement_req) + { + (config->measurement_req)(config, phy, &req); + } + } + else + { + nfapi_measurement_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_MEASUREMENT_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_measurement_resp(config, &resp); + } + } + else + { + nfapi_measurement_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_MEASUREMENT_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_CONFIG; + nfapi_pnf_measurement_resp(config, &resp); + } + } + else + { + nfapi_measurement_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_MEASUREMENT_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_measurement_resp(config, &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + } +} + +void pnf_handle_rssi_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + + + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_rssi_request_t req; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "RSSI.request received\n"); + + nfapi_pnf_config_t* config = &(pnf->_public); + + // unpack the message + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + { + if(config->state == NFAPI_PNF_RUNNING) + { + nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, req.header.phy_id); + if(phy) + { + if(phy->state == NFAPI_PNF_PHY_RUNNING) + { + if(config->rssi_req) + { + (config->rssi_req)(config, phy, &req); + } + } + else + { + nfapi_rssi_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_RSSI_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_rssi_resp(config, &resp); + } + } + else + { + nfapi_rssi_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_RSSI_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_CONFIG; + nfapi_pnf_rssi_resp(config, &resp); + } + } + else + { + nfapi_rssi_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_RSSI_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_rssi_resp(config, &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + + } +} + +void pnf_handle_cell_search_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_cell_search_request_t req; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "CELL_SEARCH.request received\n"); + + nfapi_pnf_config_t* config = &(pnf->_public); + + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + { + if(config->state == NFAPI_PNF_RUNNING) + { + nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, req.header.phy_id); + if(phy) + { + if(phy->state == NFAPI_PNF_PHY_RUNNING) + { + if(config->cell_search_req) + { + (config->cell_search_req)(config, phy, &req); + } + } + else + { + nfapi_cell_search_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_CELL_SEARCH_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_cell_search_resp(config, &resp); + } + } + else + { + nfapi_cell_search_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_CELL_SEARCH_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_CONFIG; + nfapi_pnf_cell_search_resp(config, &resp); + } + } + else + { + nfapi_cell_search_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_CELL_SEARCH_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_cell_search_resp(config, &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + } + +} + +void pnf_handle_broadcast_detect_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_broadcast_detect_request_t req; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "BROADCAST_DETECT.request received\n"); + + nfapi_pnf_config_t* config = &(pnf->_public); + + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + { + if(config->state == NFAPI_PNF_RUNNING) + { + nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, req.header.phy_id); + if(phy) + { + if(phy->state == NFAPI_PNF_PHY_RUNNING) + { + if(config->broadcast_detect_req) + { + (config->broadcast_detect_req)(config, phy, &req); + } + } + else + { + nfapi_broadcast_detect_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_BROADCAST_DETECT_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_broadcast_detect_resp(config, &resp); + } + } + else + { + nfapi_broadcast_detect_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_BROADCAST_DETECT_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_CONFIG; + nfapi_pnf_broadcast_detect_resp(config, &resp); + } + } + else + { + nfapi_broadcast_detect_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_BROADCAST_DETECT_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_broadcast_detect_resp(config, &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + + } +} + +void pnf_handle_system_information_schedule_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_system_information_schedule_request_t req; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "SYSTEM_INFORMATION_SCHEDULE.request received\n"); + + nfapi_pnf_config_t* config = &(pnf->_public); + + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + { + if(config->state == NFAPI_PNF_RUNNING) + { + nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, req.header.phy_id); + if(phy) + { + if(phy->state == NFAPI_PNF_PHY_RUNNING) + { + if(config->system_information_schedule_req) + { + (config->system_information_schedule_req)(config, phy, &req); + } + } + else + { + nfapi_system_information_schedule_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_system_information_schedule_resp(config, &resp); + } + } + else + { + nfapi_system_information_schedule_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_CONFIG; + nfapi_pnf_system_information_schedule_resp(config, &resp); + } + } + else + { + nfapi_system_information_schedule_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_system_information_schedule_resp(config, &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + } +} + +void pnf_handle_system_information_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_system_information_request_t req; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "SYSTEM_INFORMATION.request received\n"); + + nfapi_pnf_config_t* config = &(pnf->_public); + + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + { + if(config->state == NFAPI_PNF_RUNNING) + { + nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, req.header.phy_id); + if(phy) + { + if(phy->state == NFAPI_PNF_PHY_RUNNING) + { + if(config->system_information_req) + { + (config->system_information_req)(config, phy, &req); + } + } + else + { + nfapi_system_information_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_SYSTEM_INFORMATION_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_system_information_resp(config, &resp); + } + } + else + { + nfapi_system_information_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_SYSTEM_INFORMATION_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_CONFIG; + nfapi_pnf_system_information_resp(config, &resp); + } + } + else + { + nfapi_system_information_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_SYSTEM_INFORMATION_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_system_information_resp(config, &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + } + +} + +void pnf_handle_nmm_stop_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_nmm_stop_request_t req; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "NMM_STOP.request received\n"); + + nfapi_pnf_config_t* config = &(pnf->_public); + + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + { + if(config->state == NFAPI_PNF_RUNNING) + { + nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, req.header.phy_id); + if(phy) + { + if(phy->state != NFAPI_PNF_PHY_RUNNING) + { + if(config->nmm_stop_req) + { + (config->nmm_stop_req)(config, phy, &req); + } + } + else + { + nfapi_nmm_stop_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_NMM_STOP_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_nmm_stop_resp(config, &resp); + } + } + else + { + nfapi_nmm_stop_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_NMM_STOP_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_CONFIG; + nfapi_pnf_nmm_stop_resp(config, &resp); + } + } + else + { + nfapi_nmm_stop_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_NMM_STOP_RESPONSE; + resp.header.phy_id = req.header.phy_id; + resp.error_code = NFAPI_MSG_INVALID_STATE; + nfapi_pnf_nmm_stop_resp(config, &resp); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(req.vendor_extension) + pnf->_public.codec_config.deallocate(req.vendor_extension); + } +} + + +void pnf_handle_vendor_extension(void* pRecvMsg, int recvMsgLen, pnf_t* pnf, uint16_t message_id) +{ + if (pRecvMsg == NULL || pnf == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_pnf_config_t* config = &(pnf->_public); + + if(config->allocate_p4_p5_vendor_ext) + { + uint16_t msg_size; + nfapi_p4_p5_message_header_t* msg = config->allocate_p4_p5_vendor_ext(message_id, &msg_size); + + if(msg == 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to allocate vendor extention structure\n"); + return; + } + + + int unpack_result = nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, msg, msg_size, &config->codec_config); + + if(unpack_result == 0) + { + if(config->vendor_ext) + config->vendor_ext(config, msg); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + if(config->deallocate_p4_p5_vendor_ext) + config->deallocate_p4_p5_vendor_ext(msg); + + } + } +} + + + +void pnf_handle_p5_message(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) +{ + nfapi_p4_p5_message_header_t messageHeader; + + // validate the input params + if(pRecvMsg == NULL || recvMsgLen < NFAPI_HEADER_LENGTH) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return; + } + + // unpack the message header + if (nfapi_p5_message_header_unpack(pRecvMsg, recvMsgLen, &messageHeader, sizeof(nfapi_p4_p5_message_header_t), &pnf->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); + return; + } + + switch (messageHeader.message_id) + { + case NFAPI_PNF_PARAM_REQUEST: + pnf_handle_pnf_param_request(pnf, pRecvMsg, recvMsgLen); + break; + + case NFAPI_PNF_CONFIG_REQUEST: + pnf_handle_pnf_config_request(pnf, pRecvMsg, recvMsgLen); + break; + + case NFAPI_PNF_START_REQUEST: + pnf_handle_pnf_start_request(pnf, pRecvMsg, recvMsgLen); + break; + + case NFAPI_PNF_STOP_REQUEST: + pnf_handle_pnf_stop_request(pnf, pRecvMsg, recvMsgLen); + break; + + case NFAPI_PARAM_REQUEST: + pnf_handle_param_request(pnf, pRecvMsg, recvMsgLen); + break; + + case NFAPI_CONFIG_REQUEST: + pnf_handle_config_request(pnf, pRecvMsg, recvMsgLen); + break; + + case NFAPI_START_REQUEST: + pnf_handle_start_request(pnf, pRecvMsg, recvMsgLen); + break; + + case NFAPI_STOP_REQUEST: + pnf_handle_stop_request(pnf, pRecvMsg, recvMsgLen); + break; + + case NFAPI_MEASUREMENT_REQUEST: + pnf_handle_measurement_request(pnf, pRecvMsg, recvMsgLen); + break; + + case NFAPI_RSSI_REQUEST: + pnf_handle_rssi_request(pnf, pRecvMsg, recvMsgLen); + break; + + case NFAPI_CELL_SEARCH_REQUEST: + pnf_handle_cell_search_request(pnf, pRecvMsg, recvMsgLen); + break; + + case NFAPI_BROADCAST_DETECT_REQUEST: + pnf_handle_broadcast_detect_request(pnf, pRecvMsg, recvMsgLen); + break; + + case NFAPI_SYSTEM_INFORMATION_SCHEDULE_REQUEST: + pnf_handle_system_information_schedule_request(pnf, pRecvMsg, recvMsgLen); + break; + + case NFAPI_SYSTEM_INFORMATION_REQUEST: + pnf_handle_system_information_request(pnf, pRecvMsg, recvMsgLen); + break; + + case NFAPI_NMM_STOP_REQUEST: + pnf_handle_nmm_stop_request(pnf, pRecvMsg, recvMsgLen); + break; + + default: + { + if(messageHeader.message_id >= NFAPI_VENDOR_EXT_MSG_MIN && + messageHeader.message_id <= NFAPI_VENDOR_EXT_MSG_MAX) + { + pnf_handle_vendor_extension(pRecvMsg, recvMsgLen, pnf, messageHeader.message_id); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s P5 Unknown message ID %d\n", __FUNCTION__, messageHeader.message_id); + } + } + break; + } +} + +int pnf_pack_and_send_p5_message(pnf_t* pnf, nfapi_p4_p5_message_header_t* msg, uint32_t msg_len) +{ + int packed_len = nfapi_p5_message_pack(msg, msg_len, + pnf->tx_message_buffer, + sizeof(pnf->tx_message_buffer), + &pnf->_public.codec_config); + + if (packed_len < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p5_message_pack failed (%d)\n", packed_len); + return -1; + } + + return pnf_send_message(pnf, pnf->tx_message_buffer, packed_len, 0/*msg->stream_id*/); +} + +int pnf_pack_and_send_p4_message(pnf_t* pnf, nfapi_p4_p5_message_header_t* msg, uint32_t msg_len) +{ + int packed_len = nfapi_p4_message_pack(msg, msg_len, + pnf->tx_message_buffer, + sizeof(pnf->tx_message_buffer), + &pnf->_public.codec_config); + + if (packed_len < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p4_message_pack failed (%d)\n", packed_len); + return -1; + } + + return pnf_send_message(pnf, pnf->tx_message_buffer, packed_len, 0/*msg->stream_id*/); +} + + + +int pnf_connect(pnf_t* pnf) +{ + struct sockaddr_in servaddr; + uint8_t socketConnected = 0; + + if(pnf->_public.vnf_ip_addr == 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "vnfIpAddress is null\n"); + return -1; + } + + + (void)memset(&servaddr, 0, sizeof(struct sockaddr_in)); + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Starting P5 PNF connection to VNF at %s:%u\n", pnf->_public.vnf_ip_addr, pnf->_public.vnf_p5_port); + + // todo split the vnf address list. currently only supporting 1 + + struct addrinfo hints, *servinfo; + memset(&hints, 0, sizeof(hints)); + + hints.ai_socktype = SOCK_STREAM; // For SCTP we are only interested in SOCK_STREAM + // todo : allow the client to restrict IPV4 or IPV6 + // todo : randomize which address to connect to? + + char port_str[8]; + snprintf(port_str, sizeof(port_str), "%d", pnf->_public.vnf_p5_port); + if(getaddrinfo(pnf->_public.vnf_ip_addr, port_str, &hints, &servinfo) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to get host (%s) addr info h_errno:%d \n", pnf->_public.vnf_ip_addr, h_errno); + return -1; + } + + struct addrinfo *p = servinfo; + int i = 0; + int connected = 0; + + while(p != NULL && connected == 0) + { + char* family = "Unknown"; + char* address = "Unknown"; + char _addr[128]; + + if(p->ai_family == AF_INET6) + { + family = "IPV6"; + struct sockaddr_in6* addr = (struct sockaddr_in6*)p->ai_addr; + inet_ntop(AF_INET6, &addr->sin6_addr, _addr, sizeof(_addr)); + address = &_addr[0]; + } + else if(p->ai_family == AF_INET) + { + family = "IPV4"; + struct sockaddr_in* addr = (struct sockaddr_in*)p->ai_addr; + address = inet_ntoa(addr->sin_addr); + } + + NFAPI_TRACE(NFAPI_TRACE_NOTE, "Host address info %d Family:%s Address:%s\n", i++, family, address); + + if (pnf->sctp) + { + // open the SCTP socket + if ((pnf->p5_sock = socket(p->ai_family, SOCK_STREAM, IPPROTO_SCTP)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P5 socket errno: %d\n", errno); + freeaddrinfo(servinfo); + return -1; + } + int noDelay; + struct sctp_initmsg initMsg; + + (void)memset(&initMsg, 0, sizeof(struct sctp_initmsg)); + + // configure the socket options + NFAPI_TRACE(NFAPI_TRACE_NOTE, "PNF Setting the SCTP_INITMSG\n"); + initMsg.sinit_num_ostreams = 5; //MAX_SCTP_STREAMS; // number of output streams can be greater + initMsg.sinit_max_instreams = 5; //MAX_SCTP_STREAMS; // number of output streams can be greater + if (setsockopt(pnf->p5_sock, IPPROTO_SCTP, SCTP_INITMSG, &initMsg, sizeof(initMsg)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt errno: %d\n", errno); + freeaddrinfo(servinfo); + return -1; + } + noDelay = 1; + if (setsockopt(pnf->p5_sock, IPPROTO_SCTP, SCTP_NODELAY, &noDelay, sizeof(noDelay)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt errno: %d\n", errno); + freeaddrinfo(servinfo); + return -1; + + } + + struct sctp_event_subscribe events; + memset( (void *)&events, 0, sizeof(events) ); + events.sctp_data_io_event = 1; + + if(setsockopt(pnf->p5_sock, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt errno: %d\n", errno); + freeaddrinfo(servinfo); + return -1; + } + } + else + { + // Create an IP socket point + if ((pnf->p5_sock = socket(p->ai_family, SOCK_STREAM, IPPROTO_IP)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P5 socket errno: %d\n", errno); + freeaddrinfo(servinfo); + return -1; + } + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "P5 socket created...\n"); + + if (connect(pnf->p5_sock, p->ai_addr, p->ai_addrlen ) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After connect (address:%s port:%d) errno: %d\n", + pnf->_public.vnf_ip_addr, pnf->_public.vnf_p5_port, errno); + + if(errno == EINVAL) + { + freeaddrinfo(servinfo); + return -1; + } + else + { + if(pnf->terminate != 0) + { + freeaddrinfo(servinfo); + return 0; + } + else + { + close(pnf->p5_sock); + sleep(1); + } + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "connect succeeded...\n"); + + connected = 1; + } + + p = p->ai_next; + } + + freeaddrinfo(servinfo); + + // If we have failed to connect return 0 and it is retry + if(connected == 0) + return 0; + + + NFAPI_TRACE(NFAPI_TRACE_NOTE, "After connect loop\n"); + if (pnf->sctp) + { + socklen_t optLen; + struct sctp_status status; + + (void)memset(&status, 0, sizeof(struct sctp_status)); + + // check the connection status + optLen = (socklen_t) sizeof(struct sctp_status); + if (getsockopt(pnf->p5_sock, IPPROTO_SCTP, SCTP_STATUS, &status, &optLen) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After getsockopt errno: %d\n", errno); + return -1; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Association ID = %d\n", status.sstat_assoc_id); + NFAPI_TRACE(NFAPI_TRACE_INFO, "Receiver window size = %d\n", status.sstat_rwnd); + NFAPI_TRACE(NFAPI_TRACE_INFO, "In Streams = %d\n", status.sstat_instrms); + NFAPI_TRACE(NFAPI_TRACE_INFO, "Out Streams = %d\n", status.sstat_outstrms); + + socketConnected = 1; + } + } + + NFAPI_TRACE(NFAPI_TRACE_NOTE, "Socket %s\n", socketConnected ? "CONNECTED" : "NOT_CONNECTED"); + return socketConnected; +} + +int pnf_send_message(pnf_t* pnf, uint8_t *msg, uint32_t len, uint16_t stream) +{ + if (pnf->sctp) + { + if (sctp_sendmsg(pnf->p5_sock, msg, len, NULL, 0, 42/*config->sctp_stream_number*/, 0, stream/*P5_STREAM_ID*/, 0, 0) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "sctp_sendmsg failed errno: %d\n", errno); + return -1; + } + } + else + { + if (write(pnf->p5_sock, msg, len) != len) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "read failed errno: %d\n", errno); + return -1; + } + } + return 0; +} + + +int pnf_read_dispatch_message(pnf_t* pnf) +{ + int socket_connected = 1; + + // 1. Peek the message header + // 2. If the message is larger than the stack buffer then create a dynamic buffer + // 3. Read the buffer + // 4. Handle the p5 message + + uint32_t header_buffer_size = NFAPI_HEADER_LENGTH; + uint8_t header_buffer[header_buffer_size]; + + uint32_t stack_buffer_size = 32; //should it be the size of then sctp_notificatoin structure + uint8_t stack_buffer[stack_buffer_size]; + + uint8_t* dynamic_buffer = 0; + + uint8_t* read_buffer = &stack_buffer[0]; + uint32_t message_size = 0; + + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + + struct sctp_sndrcvinfo sndrcvinfo; + (void)memset(&sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); + + { + int flags = MSG_PEEK; + message_size = sctp_recvmsg(pnf->p5_sock, header_buffer, header_buffer_size, /*(struct sockaddr*)&addr, &addr_len*/ 0, 0, &sndrcvinfo, &flags); + + if(message_size == -1) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF Failed to peek sctp message size errno:%d\n", errno); + return 0; + } + + nfapi_p4_p5_message_header_t header; + int unpack_result = nfapi_p5_message_header_unpack(header_buffer, header_buffer_size, &header, sizeof(header), 0); + if(unpack_result < 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF Failed to unpack p5 message header\n"); + return 0; + } + message_size = header.message_length; + + // now have the size of the mesage + } + + if(message_size > stack_buffer_size) + { + dynamic_buffer = (uint8_t*)malloc(message_size); + + if(dynamic_buffer == NULL) + { + // todo : add error mesage + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF Failed to allocate dynamic buffer for sctp_recvmsg size:%d\n", message_size); + return -1; + } + + read_buffer = dynamic_buffer; + } + + { + int flags = 0; + (void)memset(&sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); + + int recvmsg_result = sctp_recvmsg(pnf->p5_sock, read_buffer, message_size, (struct sockaddr*)&addr, &addr_len, &sndrcvinfo, &flags); + if(recvmsg_result == -1) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Failed to read sctp message size errno:%d\n", errno); + } + else + { + if (flags & MSG_NOTIFICATION) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Notification received from %s:%u\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + // todo - handle the events + } + else + { + /* + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received message fd:%d from %s:%u assoc:%d on stream %d, PPID %d, length %d, flags 0x%x\n", + pnf->p5_sock, + inet_ntoa(addr.sin_addr), + ntohs(addr.sin_port), + sndrcvinfo.sinfo_assoc_id, + sndrcvinfo.sinfo_stream, + ntohl(sndrcvinfo.sinfo_ppid), + message_size, + flags); + */ + + // handle now if complete message in one or more segments + if ((flags & 0x80) == 0x80) + { + pnf_handle_p5_message(pnf, read_buffer, message_size); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_WARN, "sctp_recvmsg: unhandled mode with flags 0x%x\n", flags); + + // assume socket disconnected + NFAPI_TRACE(NFAPI_TRACE_WARN, "Disconnected socket\n"); + socket_connected = 0; + } + + + } + } + } + + if(dynamic_buffer) + { + free(dynamic_buffer); + } + + return socket_connected; + + +} + + +int pnf_message_pump(pnf_t* pnf) +{ + uint8_t socketConnected = 1; + + while(socketConnected && pnf->terminate == 0) + { + fd_set rfds; + int selectRetval = 0; + + // select on a timeout and then get the message + FD_ZERO(&rfds); + FD_SET(pnf->p5_sock, &rfds); + + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + selectRetval = select(pnf->p5_sock+1, &rfds, NULL, NULL, &timeout); + + if(selectRetval == 0) + { + // timeout + continue; + } + else if (selectRetval == -1 && (errno == EINTR)) + { + // interrupted by signal + NFAPI_TRACE(NFAPI_TRACE_WARN, "P5 Signal Interrupt %d\n", errno); + continue; + } + else if (selectRetval == -1) + { + NFAPI_TRACE(NFAPI_TRACE_WARN, "P5 select() failed\n"); + sleep(1); + continue; + } + + if(FD_ISSET(pnf->p5_sock, &rfds)) + { + socketConnected = pnf_read_dispatch_message(pnf); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_WARN, "Why are we here\n"); + } + } + + // Drop back to idle if we have lost connection + pnf->_public.state = NFAPI_PNF_PHY_IDLE; + + + // close the connection and socket + if (close(pnf->p5_sock) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "close(sctpSock) failed errno: %d\n", errno); + } + + return 0; + +} + diff --git a/nfapi/open-nFAPI/pnf/src/pnf_interface.c b/nfapi/open-nFAPI/pnf/src/pnf_interface.c new file mode 100644 index 0000000000..7310fc0c66 --- /dev/null +++ b/nfapi/open-nFAPI/pnf/src/pnf_interface.c @@ -0,0 +1,432 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "pnf.h" +#include +#include +#include + +nfapi_pnf_config_t* nfapi_pnf_config_create() +{ + pnf_t* _this = (pnf_t*)malloc(sizeof(pnf_t)); + + if(_this == 0) + return 0; + + memset(_this, 0, sizeof(pnf_t)); + + _this->sctp = 1; // enable sctp + + _this->_public.vnf_p5_port = NFAPI_P5_SCTP_PORT; + + _this->_public.malloc = &malloc; + _this->_public.free = &free; + + _this->_public.codec_config.allocate = &malloc; + _this->_public.codec_config.deallocate = &free; + + return &(_this->_public); +} + +void nfapi_pnf_config_destory(nfapi_pnf_config_t* config) +{ + free(config); +} + +int nfapi_pnf_start(nfapi_pnf_config_t* config) +{ + // Verify that config is not null + if(config == 0) + return -1; + + // Make sure to set the defined trace function before using NFAPI_TRACE + if(config->trace) + nfapi_trace_g = config->trace; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + + pnf_t* _this = (pnf_t*)(config); + + while (_this->terminate == 0) + { + int connect_result = pnf_connect(_this); + + if(connect_result > 0) + { + pnf_message_pump(_this); + } + else if(connect_result < 0) + { + return connect_result; + } + + sleep(1); + } + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() terminate=1 - EXITTING............\n", __FUNCTION__); + + return 0; +} + +int nfapi_pnf_stop(nfapi_pnf_config_t* config) +{ + // Verify that config is not null + if(config == 0) + return -1; + + + pnf_t* _this = (pnf_t*)(config); + _this->terminate = 1; + + // todo wait for the pnf to stop before returning + + return 0; +} + +int nfapi_pnf_pnf_param_resp(nfapi_pnf_config_t* config, nfapi_pnf_param_response_t* resp) +{ + // ensure it's valid + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_pnf_param_response_t)); +} + +int nfapi_pnf_pnf_config_resp(nfapi_pnf_config_t* config, nfapi_pnf_config_response_t* resp) +{ + // ensure it's valid + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + if(resp->error_code == NFAPI_MSG_OK) + { + config->state = NFAPI_PNF_CONFIGURED; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_pnf_config_response_t)); +} + +int nfapi_pnf_pnf_start_resp(nfapi_pnf_config_t* config, nfapi_pnf_start_response_t* resp) +{ + // ensure it's valid + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + if(resp->error_code == NFAPI_MSG_OK) + { + config->state = NFAPI_PNF_RUNNING; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_pnf_start_response_t)); +} + +int nfapi_pnf_pnf_stop_resp(nfapi_pnf_config_t* config, nfapi_pnf_stop_response_t* resp) +{ + // ensure it's valid + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + if(resp->error_code == NFAPI_MSG_OK) + { + config->state = NFAPI_PNF_CONFIGURED; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_pnf_stop_response_t)); +} + +int nfapi_pnf_param_resp(nfapi_pnf_config_t* config, nfapi_param_response_t* resp) +{ + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_param_response_t)); +} + +int nfapi_pnf_config_resp(nfapi_pnf_config_t* config, nfapi_config_response_t* resp) +{ + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, resp->header.phy_id); + + if(phy) + { + if(resp->error_code == NFAPI_MSG_OK) + { + phy->state = NFAPI_PNF_PHY_CONFIGURED; + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: unknow phy id %d\n", __FUNCTION__, resp->header.phy_id); + return -1; + } + + return pnf_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_config_response_t)); +} + +int nfapi_pnf_start_resp(nfapi_pnf_config_t* config, nfapi_start_response_t* resp) +{ + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, resp->header.phy_id); + if(phy) + { + if(resp->error_code == NFAPI_MSG_OK) + { + phy->state = NFAPI_PNF_PHY_RUNNING; + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: unknown phy id %d\n", __FUNCTION__, resp->header.phy_id); + return -1; + } + + return pnf_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_start_response_t)); +} + +int nfapi_pnf_stop_resp(nfapi_pnf_config_t* config, nfapi_stop_response_t* resp) +{ + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, resp->header.phy_id); + if(phy) + { + if(resp->error_code == NFAPI_MSG_OK) + { + phy->state = NFAPI_PNF_PHY_CONFIGURED; + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: unknow phy id %d\n", __FUNCTION__, resp->header.phy_id); + return -1; + } + + + return pnf_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_stop_response_t)); +} + +int nfapi_pnf_measurement_resp(nfapi_pnf_config_t* config, nfapi_measurement_response_t* resp) +{ + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_measurement_response_t)); +} + + +int nfapi_pnf_rssi_resp(nfapi_pnf_config_t* config, nfapi_rssi_response_t* resp) +{ + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p4_message(_this, &(resp->header), sizeof(nfapi_rssi_response_t)); +} + +int nfapi_pnf_rssi_ind(nfapi_pnf_config_t* config, nfapi_rssi_indication_t* ind) +{ + if (config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p4_message(_this, &(ind->header), sizeof(nfapi_rssi_indication_t)); +} +int nfapi_pnf_cell_search_resp(nfapi_pnf_config_t* config, nfapi_cell_search_response_t* resp) +{ + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Send CELL_SEARCH.response\n"); + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p4_message(_this, &(resp->header), sizeof(nfapi_cell_search_response_t)); +} +int nfapi_pnf_cell_search_ind(nfapi_pnf_config_t* config, nfapi_cell_search_indication_t* ind) +{ + if (config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p4_message(_this, &(ind->header), sizeof(nfapi_cell_search_indication_t)); +} +int nfapi_pnf_broadcast_detect_resp(nfapi_pnf_config_t* config, nfapi_broadcast_detect_response_t* resp) +{ + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p4_message(_this, &(resp->header), sizeof(nfapi_broadcast_detect_response_t)); +} +int nfapi_pnf_broadcast_detect_ind(nfapi_pnf_config_t* config, nfapi_broadcast_detect_indication_t* ind) +{ + if (config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p4_message(_this, &(ind->header), sizeof(nfapi_broadcast_detect_indication_t)); +} +int nfapi_pnf_system_information_schedule_resp(nfapi_pnf_config_t* config, nfapi_system_information_schedule_response_t* resp) +{ + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1;; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p4_message(_this, &(resp->header), sizeof(nfapi_system_information_schedule_response_t)); +} + +int nfapi_pnf_system_information_schedule_ind(nfapi_pnf_config_t* config, nfapi_system_information_schedule_indication_t* ind) +{ + if (config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p4_message(_this, &(ind->header), sizeof(nfapi_system_information_schedule_indication_t)); +} +int nfapi_pnf_system_information_resp(nfapi_pnf_config_t* config, nfapi_system_information_response_t* resp) +{ + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p4_message(_this, &(resp->header), sizeof(nfapi_system_information_response_t)); +} + +int nfapi_pnf_system_information_ind(nfapi_pnf_config_t* config, nfapi_system_information_indication_t* ind) +{ + if (config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p4_message(_this, &(ind->header), sizeof(nfapi_system_information_indication_t)); +} +int nfapi_pnf_nmm_stop_resp(nfapi_pnf_config_t* config, nfapi_nmm_stop_response_t* resp) +{ + // ensure it's valid + if (config == NULL || resp == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p4_message(_this, &(resp->header), sizeof(nfapi_nmm_stop_request_t)); +} + +int nfapi_pnf_vendor_extension(nfapi_pnf_config_t* config, nfapi_p4_p5_message_header_t* msg, uint32_t msg_len) +{ + // ensure it's valid + if (config == NULL || msg == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return -1; + } + + pnf_t* _this = (pnf_t*)(config); + + return pnf_pack_and_send_p5_message(_this, msg, msg_len); +} + diff --git a/nfapi/open-nFAPI/pnf/src/pnf_p7.c b/nfapi/open-nFAPI/pnf/src/pnf_p7.c new file mode 100644 index 0000000000..02b828d382 --- /dev/null +++ b/nfapi/open-nFAPI/pnf/src/pnf_p7.c @@ -0,0 +1,1769 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pnf_p7.h" + +#define FAPI2_IP_DSCP 0 + +extern uint16_t sf_ahead; +//uint16_t sf_ahead=4; + +void add_sf(uint16_t *frameP, uint16_t *subframeP, int offset) +{ + *frameP = *frameP + ((*subframeP + offset) / 10); + + *subframeP = ((*subframeP + offset) % 10); +} + +void subtract_sf(uint16_t *frameP, uint16_t *subframeP, int offset) +{ + if (*subframeP < offset) + { + *frameP = (*frameP+1024-1)%1024; + } + *subframeP = (*subframeP+10-offset)%10; +} + +uint16_t sfnsf_add_sf(uint16_t sfnsf, int offset) +{ + uint16_t new_sfnsf; + uint16_t sfn = NFAPI_SFNSF2SFN(sfnsf); + uint16_t sf = NFAPI_SFNSF2SF(sfnsf); + + //printf("%s() sfn:%u sf:%u\n", __FUNCTION__, sfn, sf); + add_sf(&sfn, &sf, offset); + + new_sfnsf = sfn<<4|sf; + + //printf("%s() sfn:%u sf:%u offset:%d sfnsf:%d(DEC:%d) new:%d(DEC:%d)\n", __FUNCTION__, sfn, sf, offset, sfnsf, NFAPI_SFNSF2DEC(sfnsf), new_sfnsf, NFAPI_SFNSF2DEC(new_sfnsf)); + + return new_sfnsf; +} + +uint16_t sfnsf_subtract_sf(uint16_t sfnsf, int offset) +{ + uint16_t new_sfnsf; + uint16_t sfn = NFAPI_SFNSF2SFN(sfnsf); + uint16_t sf = NFAPI_SFNSF2SF(sfnsf); + + //printf("%s() sfn:%u sf:%u\n", __FUNCTION__, sfn, sf); + subtract_sf(&sfn, &sf, offset); + + new_sfnsf = sfn<<4|sf; + + //printf("%s() offset:%d sfnsf:%d(DEC:%d) new:%d(DEC:%d)\n", __FUNCTION__, offset, sfnsf, NFAPI_SFNSF2DEC(sfnsf), new_sfnsf, NFAPI_SFNSF2DEC(new_sfnsf)); + + return new_sfnsf; +} + +uint32_t pnf_get_current_time_hr(void) +{ + struct timeval now; + (void)gettimeofday(&now, NULL); + uint32_t time_hr = TIME2TIMEHR(now); + return time_hr; +} + +void* pnf_p7_malloc(pnf_p7_t* pnf_p7, size_t size) +{ + if(pnf_p7->_public.malloc) + { + return (pnf_p7->_public.malloc)(size); + } + else + { + return calloc(1, size); + } +} +void pnf_p7_free(pnf_p7_t* pnf_p7, void* ptr) +{ + if(pnf_p7->_public.free) + { + return (pnf_p7->_public.free)(ptr); + } + else + { + return free(ptr); + } +} + +// todo : for now these just malloc/free need to move to a memory cache +nfapi_dl_config_request_t* allocate_nfapi_dl_config_request(pnf_p7_t* pnf_p7) +{ + void *ptr= pnf_p7_malloc(pnf_p7, sizeof(nfapi_dl_config_request_t)); + //printf("%s() ptr:%p\n", __FUNCTION__, ptr); + return ptr; +} + +void deallocate_nfapi_dl_config_request(nfapi_dl_config_request_t* req, pnf_p7_t* pnf_p7) +{ + //printf("%s() SFN/SF:%d %s req:%p pdu_list:%p\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), pnf_p7->_public.codec_config.deallocate ? "DEALLOCATE" : "FREE", req, req->dl_config_request_body.dl_config_pdu_list); + if(pnf_p7->_public.codec_config.deallocate) + { + (pnf_p7->_public.codec_config.deallocate)(req->dl_config_request_body.dl_config_pdu_list); + } + else + { + free(req->dl_config_request_body.dl_config_pdu_list); + } + req->dl_config_request_body.dl_config_pdu_list=0; + + pnf_p7_free(pnf_p7, req); +} + +nfapi_ul_config_request_t* allocate_nfapi_ul_config_request(pnf_p7_t* pnf_p7) +{ + void *ptr= pnf_p7_malloc(pnf_p7, sizeof(nfapi_ul_config_request_t)); + //printf("%s() ptr:%p\n", __FUNCTION__, ptr); + return ptr; +} + +void deallocate_nfapi_ul_config_request(nfapi_ul_config_request_t* req, pnf_p7_t* pnf_p7) +{ + //printf("%s() SFN/SF:%d %s req:%p pdu_list:%p\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), pnf_p7->_public.codec_config.deallocate ? "DEALLOCATE" : "FREE", req, req->ul_config_request_body.ul_config_pdu_list); + if(pnf_p7->_public.codec_config.deallocate) + { + (pnf_p7->_public.codec_config.deallocate)(req->ul_config_request_body.ul_config_pdu_list); + } + else + { + free(req->ul_config_request_body.ul_config_pdu_list); + } + req->ul_config_request_body.ul_config_pdu_list=0; + + pnf_p7_free(pnf_p7, req); +} + +nfapi_hi_dci0_request_t* allocate_nfapi_hi_dci0_request(pnf_p7_t* pnf_p7) +{ + return pnf_p7_malloc(pnf_p7, sizeof(nfapi_hi_dci0_request_t)); +} + +void deallocate_nfapi_hi_dci0_request(nfapi_hi_dci0_request_t* req, pnf_p7_t* pnf_p7) +{ + //printf("%s() SFN/SF:%d %s req:%p pdu_list:%p\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), pnf_p7->_public.codec_config.deallocate ? "DEALLOCATE" : "FREE", req, req->hi_dci0_request_body.hi_dci0_pdu_list); + if(pnf_p7->_public.codec_config.deallocate) + { + (pnf_p7->_public.codec_config.deallocate)(req->hi_dci0_request_body.hi_dci0_pdu_list); + } + else + { + free(req->hi_dci0_request_body.hi_dci0_pdu_list); + } + req->hi_dci0_request_body.hi_dci0_pdu_list=0; + + pnf_p7_free(pnf_p7, req); +} + +nfapi_tx_request_t* allocate_nfapi_tx_request(pnf_p7_t* pnf_p7) +{ + return pnf_p7_malloc(pnf_p7, sizeof(nfapi_tx_request_t)); +} + +void deallocate_nfapi_tx_request(nfapi_tx_request_t* req, pnf_p7_t* pnf_p7) +{ + int i = 0; + + //printf("%s() SFN/SF:%d %s req:%p pdu[0]:data:%p\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), pnf_p7->_public.codec_config.deallocate ? "DEALLOCATE" : "FREE", req, req->tx_request_body.tx_pdu_list[i].segments[0].segment_data); + + for(i = 0; i < req->tx_request_body.number_of_pdus; ++i) + { + void* data = req->tx_request_body.tx_pdu_list[i].segments[0].segment_data; + + if(pnf_p7->_public.codec_config.deallocate) + { + (pnf_p7->_public.codec_config.deallocate)(data); + } + else + { + free(data); + } + data=0; + } + + + if(pnf_p7->_public.codec_config.deallocate) + { + (pnf_p7->_public.codec_config.deallocate)(req->tx_request_body.tx_pdu_list); + } + else + { + free(req->tx_request_body.tx_pdu_list); + } + req->tx_request_body.tx_pdu_list=0; + + pnf_p7_free(pnf_p7, req); +} + +nfapi_lbt_dl_config_request_t* allocate_nfapi_lbt_dl_config_request(pnf_p7_t* pnf_p7) +{ + return pnf_p7_malloc(pnf_p7, sizeof(nfapi_lbt_dl_config_request_t)); +} + +void deallocate_nfapi_lbt_dl_config_request(nfapi_lbt_dl_config_request_t* req, pnf_p7_t* pnf_p7) +{ + if(pnf_p7->_public.codec_config.deallocate) + { + (pnf_p7->_public.codec_config.deallocate)(req->lbt_dl_config_request_body.lbt_dl_config_req_pdu_list); + } + else + { + free(req->lbt_dl_config_request_body.lbt_dl_config_req_pdu_list); + } + req->lbt_dl_config_request_body.lbt_dl_config_req_pdu_list=0; + + pnf_p7_free(pnf_p7, req); +} + +pnf_p7_rx_message_t* pnf_p7_rx_reassembly_queue_add_segment(pnf_p7_t* pnf_p7, pnf_p7_rx_reassembly_queue_t* queue, uint32_t rx_hr_time, uint16_t sequence_number, uint16_t segment_number, uint8_t m, uint8_t* data, uint16_t data_len) +{ + pnf_p7_rx_message_t* msg = 0; + // attempt to find a entry for this segment + pnf_p7_rx_message_t* iterator = queue->msg_queue; + while(iterator != 0) + { + if(iterator->sequence_number == sequence_number) + { + msg = iterator; + break; + } + + iterator = iterator->next; + } + + // if found then copy data to message + if(msg != 0) + { + + msg->segments[segment_number].buffer = (uint8_t*)pnf_p7_malloc(pnf_p7, data_len); + memcpy(msg->segments[segment_number].buffer, data, data_len); + msg->segments[segment_number].length = data_len; + + msg->num_segments_received++; + + // set the segement number if we have the last segment + if(m == 0) + msg->num_segments_expected = segment_number + 1; + } + // else add new rx message entry + else + { + // create a new message + msg = (pnf_p7_rx_message_t*)(pnf_p7_malloc(pnf_p7, sizeof(pnf_p7_rx_message_t))); + memset(msg, 0, sizeof(pnf_p7_rx_message_t)); + + msg->sequence_number = sequence_number; + msg->num_segments_expected = m ? 255 : segment_number + 1; + msg->num_segments_received = 1; + msg->rx_hr_time = rx_hr_time; + + msg->segments[segment_number].buffer = (uint8_t*)pnf_p7_malloc(pnf_p7, data_len); + memcpy(msg->segments[segment_number].buffer, data, data_len); + msg->segments[segment_number].length = data_len; + + // place the message at the head of the queue + msg->next = queue->msg_queue; + queue->msg_queue = msg; + } + + return msg; +} + +void pnf_p7_rx_reassembly_queue_remove_msg(pnf_p7_t* pnf_p7, pnf_p7_rx_reassembly_queue_t* queue, pnf_p7_rx_message_t* msg) +{ + // remove message if it has the same sequence number + pnf_p7_rx_message_t* iterator = queue->msg_queue; + pnf_p7_rx_message_t* previous = 0; + + while(iterator != 0) + { + if(iterator->sequence_number == msg->sequence_number) + { + if(previous == 0) + { + queue->msg_queue = iterator->next; + } + else + { + previous->next = iterator->next; + } + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "Deleting reassembly message\n"); + // delete the message + uint16_t i; + for(i = 0; i < 128; ++i) + { + if(iterator->segments[i].buffer) + pnf_p7_free(pnf_p7, iterator->segments[i].buffer); + } + pnf_p7_free(pnf_p7, iterator); + + break; + } + + previous = iterator; + iterator = iterator->next; + } +} + +void pnf_p7_rx_reassembly_queue_remove_old_msgs(pnf_p7_t* pnf_p7, pnf_p7_rx_reassembly_queue_t* queue, uint32_t rx_hr_time, uint32_t delta) +{ + // remove all messages that are too old + pnf_p7_rx_message_t* iterator = queue->msg_queue; + pnf_p7_rx_message_t* previous = 0; + + while(iterator != 0) + { + if(rx_hr_time - iterator->rx_hr_time > delta) + { + if(previous == 0) + { + queue->msg_queue = iterator->next; + } + else + { + previous->next = iterator->next; + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Deleting stale reassembly message (%u %u %d)\n", iterator->rx_hr_time, rx_hr_time, delta); + + pnf_p7_rx_message_t* to_delete = iterator; + iterator = iterator->next; + + // delete the message + uint16_t i; + for(i = 0; i < 128; ++i) + { + if(to_delete->segments[i].buffer) + pnf_p7_free(pnf_p7, to_delete->segments[i].buffer); + } + pnf_p7_free(pnf_p7, to_delete); + + } + else + { + previous = iterator; + iterator = iterator->next; + } + } +} + + +static uint32_t get_sf_time(uint32_t now_hr, uint32_t sf_start_hr) +{ + if(now_hr < sf_start_hr) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "now is earlier than start of subframe now_hr:%u sf_start_hr:%u\n", now_hr, sf_start_hr); + return 0; + } + else + { + uint32_t now_us = TIMEHR_USEC(now_hr); + uint32_t sf_start_us = TIMEHR_USEC(sf_start_hr); + + // if the us have wrapped adjust for it + if(now_hr < sf_start_us) + { + now_us += 1000000; + } + + return now_us - sf_start_us; + } +} + +int pnf_p7_send_message(pnf_p7_t* pnf_p7, uint8_t* msg, uint32_t len) +{ + // todo : consider how to do this only once + struct sockaddr_in remote_addr; + memset((char*)&remote_addr, 0, sizeof(struct sockaddr_in)); + remote_addr.sin_family = AF_INET; + remote_addr.sin_port = htons(pnf_p7->_public.remote_p7_port); + //remote_addr.sin_addr.s_addr = inet_addr(pnf_p7->_public.remote_p7_addr); + if(inet_aton(pnf_p7->_public.remote_p7_addr, &remote_addr.sin_addr) == -1) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "inet_aton failed %d\n", errno); + return -1; + } + + socklen_t remote_addr_len = sizeof(struct sockaddr_in); + + int sendto_result; + if ((sendto_result = sendto((int)pnf_p7->p7_sock, (const char*)msg, len, 0, (const struct sockaddr*)&remote_addr, remote_addr_len)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s %s:%d sendto(%d, %p, %d) %d failed errno: %d\n", __FUNCTION__, pnf_p7->_public.remote_p7_addr, pnf_p7->_public.remote_p7_port, (int)pnf_p7->p7_sock, (const char*)msg, len, remote_addr_len, errno); + return -1; + } + + if(sendto_result != len) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s sendto failed to send the entire message %d %d\n", __FUNCTION__, sendto_result, len); + } + return 0; +} + +int pnf_p7_pack_and_send_p7_message(pnf_p7_t* pnf_p7, nfapi_p7_message_header_t* header, uint32_t msg_len) +{ + header->m_segment_sequence = NFAPI_P7_SET_MSS(0, 0, pnf_p7->sequence_number); + + // Need to guard against different threads calling the encode function at the same time + if(pthread_mutex_lock(&(pnf_p7->pack_mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to lock mutex\n"); + return -1; + } + + int len = nfapi_p7_message_pack(header, pnf_p7->tx_message_buffer, sizeof(pnf_p7->tx_message_buffer), &pnf_p7->_public.codec_config); + + if (len < 0) + { + if(pthread_mutex_unlock(&(pnf_p7->pack_mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); + return -1; + } + + NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p7_message_pack failed with return %d\n", len ); + return -1; + } + + if(len > pnf_p7->_public.segment_size) + { + int msg_body_len = len - NFAPI_P7_HEADER_LENGTH ; + int seg_body_len = pnf_p7->_public.segment_size - NFAPI_P7_HEADER_LENGTH ; + int segment_count = (msg_body_len / (seg_body_len)) + ((msg_body_len % seg_body_len) ? 1 : 0); + + int segment = 0; + int offset = NFAPI_P7_HEADER_LENGTH; + uint8_t buffer[pnf_p7->_public.segment_size]; + for(segment = 0; segment < segment_count; ++segment) + { + uint8_t last = 0; + uint16_t size = pnf_p7->_public.segment_size - NFAPI_P7_HEADER_LENGTH; + if(segment + 1 == segment_count) + { + last = 1; + size = (msg_body_len) - (seg_body_len * segment); + } + + uint16_t segment_size = size + NFAPI_P7_HEADER_LENGTH; + + // Update the header with the m and segement + memcpy(&buffer[0], pnf_p7->tx_message_buffer, NFAPI_P7_HEADER_LENGTH); + + // set the segment length + buffer[4] = (segment_size & 0xFF00) >> 8; + buffer[5] = (segment_size & 0xFF); + + // set the m & segment number + buffer[6] = ((!last) << 7) + segment; + + memcpy(&buffer[NFAPI_P7_HEADER_LENGTH], pnf_p7->tx_message_buffer + offset, size); + offset += size; + + if(pnf_p7->_public.checksum_enabled) + { + nfapi_p7_update_checksum(buffer, segment_size); + } + + + pnf_p7_send_message(pnf_p7, &buffer[0], segment_size); + } + } + else + { + if(pnf_p7->_public.checksum_enabled) + { + nfapi_p7_update_checksum(pnf_p7->tx_message_buffer, len); + } + + // simple case that the message fits in a single segment + pnf_p7_send_message(pnf_p7, pnf_p7->tx_message_buffer, len); + } + + pnf_p7->sequence_number++; + + if(pthread_mutex_unlock(&(pnf_p7->pack_mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); + return -1; + } + + return 0; +} + +void pnf_pack_and_send_timing_info(pnf_p7_t* pnf_p7) +{ + nfapi_timing_info_t timing_info; + memset(&timing_info, 0, sizeof(timing_info)); + timing_info.header.message_id = NFAPI_TIMING_INFO; + timing_info.header.phy_id = pnf_p7->_public.phy_id; + + timing_info.last_sfn_sf = pnf_p7->sfn_sf; + timing_info.time_since_last_timing_info = pnf_p7->timing_info_ms_counter; + + timing_info.dl_config_jitter = pnf_p7->dl_config_jitter; + timing_info.tx_request_jitter = pnf_p7->tx_jitter; + timing_info.ul_config_jitter = pnf_p7->ul_config_jitter; + timing_info.hi_dci0_jitter = pnf_p7->hi_dci0_jitter; + + timing_info.dl_config_latest_delay = 0; + timing_info.tx_request_latest_delay = 0; + timing_info.ul_config_latest_delay = 0; + timing_info.hi_dci0_latest_delay = 0; + + timing_info.dl_config_earliest_arrival = 0; + timing_info.tx_request_earliest_arrival = 0; + timing_info.ul_config_earliest_arrival = 0; + timing_info.hi_dci0_earliest_arrival = 0; + + + pnf_p7_pack_and_send_p7_message(pnf_p7, &(timing_info.header), sizeof(timing_info)); + + pnf_p7->timing_info_ms_counter = 0; +} + +void send_dummy_subframe(pnf_p7_t* pnf_p7, uint16_t sfn_sf) +{ + struct timespec t; + clock_gettime( CLOCK_MONOTONIC, &t); + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(sfn_sf:%d) t:%ld.%09ld\n", __FUNCTION__, NFAPI_SFNSF2DEC(sfn_sf), t.tv_sec, t.tv_nsec); + + if(pnf_p7->_public.tx_req && pnf_p7->_public.dummy_subframe.tx_req) + { + pnf_p7->_public.dummy_subframe.tx_req->sfn_sf = sfn_sf; + //NFAPI_TRACE(NFAPI_TRACE_INFO, "Dummy tx_req - enter\n"); + (pnf_p7->_public.tx_req)(&pnf_p7->_public, pnf_p7->_public.dummy_subframe.tx_req); + //NFAPI_TRACE(NFAPI_TRACE_INFO, "Dummy tx_req - exit\n"); + } + if(pnf_p7->_public.dl_config_req && pnf_p7->_public.dummy_subframe.dl_config_req) + { + pnf_p7->_public.dummy_subframe.dl_config_req->sfn_sf = sfn_sf; + //NFAPI_TRACE(NFAPI_TRACE_INFO, "Dummy dl_config_req - enter\n"); + (pnf_p7->_public.dl_config_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.dl_config_req); + //NFAPI_TRACE(NFAPI_TRACE_INFO, "Dummy dl_config_req - exit\n"); + } + if(pnf_p7->_public.ul_config_req && pnf_p7->_public.dummy_subframe.ul_config_req) + { + pnf_p7->_public.dummy_subframe.ul_config_req->sfn_sf = sfn_sf; + NFAPI_TRACE(NFAPI_TRACE_INFO, "Dummy ul_config_req - enter\n"); + (pnf_p7->_public.ul_config_req)(&pnf_p7->_public, pnf_p7->_public.dummy_subframe.ul_config_req); + } + if(pnf_p7->_public.hi_dci0_req && pnf_p7->_public.dummy_subframe.hi_dci0_req) + { + pnf_p7->_public.dummy_subframe.hi_dci0_req->sfn_sf = sfn_sf; + NFAPI_TRACE(NFAPI_TRACE_INFO, "Dummy hi_dci0 - enter\n"); + (pnf_p7->_public.hi_dci0_req)(&pnf_p7->_public, pnf_p7->_public.dummy_subframe.hi_dci0_req); + } + if(pnf_p7->_public.lbt_dl_config_req && pnf_p7->_public.dummy_subframe.lbt_dl_config_req) + { + pnf_p7->_public.dummy_subframe.lbt_dl_config_req->sfn_sf = sfn_sf; + NFAPI_TRACE(NFAPI_TRACE_INFO, "Dummy lbt - enter\n"); + (pnf_p7->_public.lbt_dl_config_req)(&pnf_p7->_public, pnf_p7->_public.dummy_subframe.lbt_dl_config_req); + } +} + +int pnf_p7_subframe_ind(pnf_p7_t* pnf_p7, uint16_t phy_id, uint16_t sfn_sf) +{ + // We could either send an event to the p7 thread have have it run the + // subframe or we could handle it here and lock access to the subframe + // buffers. If we do it on the p7 thread then we run the risk of blocking + // on the udp send. + // + // todo : start a timer to give us more of the 1 ms tick before send back + // the frame + + // todo : consider a more efficent lock mechasium + if(pthread_mutex_lock(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to lock mutex\n"); + return -1; + } + +#if 1 + // save the curren time and sfn_sf + pnf_p7->sf_start_time_hr = pnf_get_current_time_hr(); + pnf_p7->sfn_sf = sfn_sf; + + uint32_t sfn_sf_tx = sfnsf_add_sf(sfn_sf, sf_ahead); + uint32_t tx_sfn_sf_dec = NFAPI_SFNSF2DEC(sfn_sf_tx); + + // If the subframe_buffer has been configured + if(pnf_p7->_public.subframe_buffer_size != 0) + { + + // apply the shift to the incoming sfn_sf + if(pnf_p7->sfn_sf_shift != 0) + { + int32_t sfn_sf_dec = NFAPI_SFNSF2DEC(sfn_sf); + + int32_t shifted_sfn_sf = sfn_sf_dec += pnf_p7->sfn_sf_shift; + + // adjust for wrap-around + if(shifted_sfn_sf < 0) + shifted_sfn_sf += NFAPI_MAX_SFNSFDEC; + else if(shifted_sfn_sf > NFAPI_MAX_SFNSFDEC) + shifted_sfn_sf -= NFAPI_MAX_SFNSFDEC; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Applying shift %d to sfn/sf (%d -> %d)\n", pnf_p7->sfn_sf_shift, NFAPI_SFNSF2DEC(sfn_sf), shifted_sfn_sf); + sfn_sf = shifted_sfn_sf; + + // + // DJP - why does the shift not apply to pnf_p7->sfn_sf??? + // + + pnf_p7->sfn_sf_shift = 0; + } + + uint32_t sfn_sf_dec = NFAPI_SFNSF2DEC(sfn_sf); + uint8_t buffer_index = sfn_sf_dec % pnf_p7->_public.subframe_buffer_size; + + nfapi_pnf_p7_subframe_buffer_t* subframe_buffer = &(pnf_p7->subframe_buffer[buffer_index]); + + uint8_t tx_buffer_index = tx_sfn_sf_dec % pnf_p7->_public.subframe_buffer_size; + nfapi_pnf_p7_subframe_buffer_t* tx_subframe_buffer = &(pnf_p7->subframe_buffer[tx_buffer_index]); + + //printf("sfn_sf_dec:%d tx_sfn_sf_dec:%d\n", sfn_sf_dec, tx_sfn_sf_dec); + + if (0) NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() shift:%d subframe_buffer->sfn_sf:%d tx_subframe_buffer->sfn_sf:%d sfn_sf:%d subframe_buffer[buffer_index:%u dl_config_req:%p tx_req:%p] " + "TX:sfn_sf:%d:tx_buffer_index:%d[dl_config_req:%p tx_req:%p]\n", + __FUNCTION__, + pnf_p7->sfn_sf_shift, + NFAPI_SFNSF2DEC(subframe_buffer->sfn_sf), + NFAPI_SFNSF2DEC(tx_subframe_buffer->sfn_sf), + sfn_sf_dec, buffer_index, subframe_buffer->dl_config_req, subframe_buffer->tx_req, + tx_sfn_sf_dec, tx_buffer_index, tx_subframe_buffer->dl_config_req, tx_subframe_buffer->tx_req); + + // if the subframe buffer sfn sf is set then we have atlease 1 message + // from the vnf. + // todo : how to handle the messages we don't have, send dummies for + // now + + //printf("tx_subframe_buffer->sfn_sf:%d sfn_sf_tx:%d\n", tx_subframe_buffer->sfn_sf, sfn_sf_tx); + //printf("subframe_buffer->sfn_sf:%d sfn_sf:%d\n", subframe_buffer->sfn_sf, sfn_sf); + if(tx_subframe_buffer->sfn_sf == sfn_sf_tx) + { + if(tx_subframe_buffer->tx_req != 0) + { + if(pnf_p7->_public.tx_req) + (pnf_p7->_public.tx_req)(&(pnf_p7->_public), tx_subframe_buffer->tx_req); + + //deallocate_nfapi_tx_request(subframe_buffer->tx_req, pnf_p7); + } + else + { + // send dummy + if(pnf_p7->_public.tx_req && pnf_p7->_public.dummy_subframe.tx_req) + { + pnf_p7->_public.dummy_subframe.tx_req->sfn_sf = sfn_sf_tx; + (pnf_p7->_public.tx_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.tx_req); + } + } + + if(tx_subframe_buffer->dl_config_req != 0) + { + if(pnf_p7->_public.dl_config_req) + (pnf_p7->_public.dl_config_req)(&(pnf_p7->_public), tx_subframe_buffer->dl_config_req); + + //deallocate_nfapi_dl_config_request(subframe_buffer->dl_config_req, pnf_p7); + } + else + { + // send dummy + if(pnf_p7->_public.dl_config_req && pnf_p7->_public.dummy_subframe.dl_config_req) + { + pnf_p7->_public.dummy_subframe.dl_config_req->sfn_sf = sfn_sf_tx; + (pnf_p7->_public.dl_config_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.dl_config_req); + } + } + + if(tx_subframe_buffer->hi_dci0_req != 0) + { + if(pnf_p7->_public.hi_dci0_req) + (pnf_p7->_public.hi_dci0_req)(&(pnf_p7->_public), tx_subframe_buffer->hi_dci0_req); + + //deallocate_nfapi_hi_dci0_request(subframe_buffer->hi_dci0_req, pnf_p7); + } + else + { + //send dummy + if(pnf_p7->_public.hi_dci0_req && pnf_p7->_public.dummy_subframe.hi_dci0_req) + { + pnf_p7->_public.dummy_subframe.hi_dci0_req->sfn_sf = sfn_sf_tx; + (pnf_p7->_public.hi_dci0_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.hi_dci0_req); + } + } + + if(tx_subframe_buffer->dl_config_req != 0) + { + deallocate_nfapi_dl_config_request(tx_subframe_buffer->dl_config_req, pnf_p7); + tx_subframe_buffer->dl_config_req = 0; + } + if(tx_subframe_buffer->tx_req != 0) + { + deallocate_nfapi_tx_request(tx_subframe_buffer->tx_req, pnf_p7); + tx_subframe_buffer->tx_req = 0; + } + if(tx_subframe_buffer->hi_dci0_req != 0) + { + deallocate_nfapi_hi_dci0_request(tx_subframe_buffer->hi_dci0_req, pnf_p7); + tx_subframe_buffer->hi_dci0_req = 0; + } + } + else + { + // If we ever need to "send" a dummy ul_config this won't work!!! + send_dummy_subframe(pnf_p7, sfn_sf_tx); + } + + if(subframe_buffer->sfn_sf == sfn_sf) + { + + if(subframe_buffer->ul_config_req != 0) + { + if(pnf_p7->_public.ul_config_req) + (pnf_p7->_public.ul_config_req)(&(pnf_p7->_public), subframe_buffer->ul_config_req); + + //deallocate_nfapi_ul_config_request(subframe_buffer->ul_config_req, pnf_p7); + } + else + { + // send dummy + if(pnf_p7->_public.ul_config_req && pnf_p7->_public.dummy_subframe.ul_config_req) + { + pnf_p7->_public.dummy_subframe.ul_config_req->sfn_sf = sfn_sf; + (pnf_p7->_public.ul_config_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.ul_config_req); + } + } + + if(subframe_buffer->lbt_dl_config_req != 0) + { + if(pnf_p7->_public.lbt_dl_config_req) + (pnf_p7->_public.lbt_dl_config_req)(&(pnf_p7->_public), subframe_buffer->lbt_dl_config_req); + + //deallocate_nfapi_lbt_dl_config_request(subframe_buffer->lbt_dl_config_req, pnf_p7); + } + else + { + // send dummy + if(pnf_p7->_public.lbt_dl_config_req && pnf_p7->_public.dummy_subframe.lbt_dl_config_req) + { + pnf_p7->_public.dummy_subframe.lbt_dl_config_req->sfn_sf = sfn_sf; + (pnf_p7->_public.lbt_dl_config_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.lbt_dl_config_req); + } + + } + + //if(subframe_buffer->dl_config_req != 0) + //deallocate_nfapi_dl_config_request(subframe_buffer->dl_config_req, pnf_p7); + //if(subframe_buffer->tx_req != 0) + //deallocate_nfapi_tx_request(subframe_buffer->tx_req, pnf_p7); + if(subframe_buffer->ul_config_req != 0) + { + deallocate_nfapi_ul_config_request(subframe_buffer->ul_config_req, pnf_p7); + subframe_buffer->ul_config_req = 0; + + } + //if(subframe_buffer->hi_dci0_req != 0) + //deallocate_nfapi_hi_dci0_request(subframe_buffer->hi_dci0_req, pnf_p7); + if(subframe_buffer->lbt_dl_config_req != 0) + { + deallocate_nfapi_lbt_dl_config_request(subframe_buffer->lbt_dl_config_req, pnf_p7); + subframe_buffer->lbt_dl_config_req = 0; + } + } // sfn_sf match + + if (subframe_buffer->dl_config_req == 0 && subframe_buffer->tx_req == 0 && subframe_buffer->ul_config_req == 0 && subframe_buffer->lbt_dl_config_req == 0) + { + memset(&(pnf_p7->subframe_buffer[buffer_index]), 0, sizeof(nfapi_pnf_p7_subframe_buffer_t)); + pnf_p7->subframe_buffer[buffer_index].sfn_sf = -1; + } + + //printf("pnf_p7->_public.timing_info_mode_periodic:%d pnf_p7->timing_info_period_counter:%d pnf_p7->_public.timing_info_period:%d\n", pnf_p7->_public.timing_info_mode_periodic, pnf_p7->timing_info_period_counter, pnf_p7->_public.timing_info_period); + //printf("pnf_p7->_public.timing_info_mode_aperiodic:%d pnf_p7->timing_info_aperiodic_send:%d\n", pnf_p7->_public.timing_info_mode_aperiodic, pnf_p7->timing_info_aperiodic_send); + //printf("pnf_p7->timing_info_ms_counter:%d\n", pnf_p7->timing_info_ms_counter); + + // send the periodic timing info if configured + if(pnf_p7->_public.timing_info_mode_periodic && (pnf_p7->timing_info_period_counter++) == pnf_p7->_public.timing_info_period) + { + pnf_pack_and_send_timing_info(pnf_p7); + + pnf_p7->timing_info_period_counter = 0; + } + else if(pnf_p7->_public.timing_info_mode_aperiodic && pnf_p7->timing_info_aperiodic_send) + { + pnf_pack_and_send_timing_info(pnf_p7); + + pnf_p7->timing_info_aperiodic_send = 0; + } + else + { + pnf_p7->timing_info_ms_counter++; + } + } + else + { + //send_dummy_subframe(pnf_p7, sfn_sf_tx); + } + + + //printf("pnf_p7->tick:%d\n", pnf_p7->tick); + if(pnf_p7->tick == 1000) + { + + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF P7:%d] (ONTIME/LATE) DL:(%d/%d) UL:(%d/%d) HI:(%d/%d) TX:(%d/%d)\n", pnf_p7->_public.phy_id, + pnf_p7->stats.dl_conf_ontime, pnf_p7->stats.dl_conf_late, + pnf_p7->stats.ul_conf_ontime, pnf_p7->stats.ul_conf_late, + pnf_p7->stats.hi_dci0_ontime, pnf_p7->stats.hi_dci0_late, + pnf_p7->stats.tx_ontime, pnf_p7->stats.tx_late); + pnf_p7->tick = 0; + memset(&pnf_p7->stats, 0, sizeof(pnf_p7->stats)); + } + pnf_p7->tick++; +#endif + + if(pthread_mutex_unlock(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); + return -1; + } + + return 0; +} + + + +// return 1 if in window +// return 0 if out of window +uint8_t is_p7_request_in_window(uint16_t sfnsf, const char* name, pnf_p7_t* phy) +{ + uint32_t recv_sfn_sf_dec = NFAPI_SFNSF2DEC(sfnsf); + uint32_t current_sfn_sf_dec = NFAPI_SFNSF2DEC(phy->sfn_sf); + + uint8_t in_window = 0; + uint8_t timing_window = phy->_public.subframe_buffer_size; + + if(recv_sfn_sf_dec <= current_sfn_sf_dec) + { + // Need to check for wrap in window + if(((current_sfn_sf_dec + timing_window) % NFAPI_MAX_SFNSFDEC) < current_sfn_sf_dec) + { + if(recv_sfn_sf_dec > ((current_sfn_sf_dec + timing_window) % NFAPI_MAX_SFNSFDEC)) + { + // out of window + NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] %s is late %d (with wrap)\n", current_sfn_sf_dec, name, recv_sfn_sf_dec); + } + else + { + // ok + //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] %s is in window %d (with wrap)\n", current_sfn_sf_dec, name, recv_sfn_sf_dec); + in_window = 1; + } + } + else + { + // too late + NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] %s is in late %d (delta:%d)\n", current_sfn_sf_dec, name, recv_sfn_sf_dec, (current_sfn_sf_dec - recv_sfn_sf_dec)); + } + + } + else + { + // Need to check it is in window + if((recv_sfn_sf_dec - current_sfn_sf_dec) <= timing_window) + { + // in window + //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] %s is in window %d\n", current_sfn_sf_dec, name, recv_sfn_sf_dec); + in_window = 1; + } + else + { + // too far in the future + NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] %s is out of window %d (delta:%d) [max:%d]\n", current_sfn_sf_dec, name, recv_sfn_sf_dec, (recv_sfn_sf_dec - current_sfn_sf_dec), timing_window); + } + + } + + return in_window; +} + + +// P7 messages +// +void pnf_handle_dl_config_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "DL_CONFIG.req Received\n"); + + nfapi_dl_config_request_t* req = allocate_nfapi_dl_config_request(pnf_p7); + + if(req == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to alloced nfapi_dl_config_request structure\n"); + return; + } + + int unpack_result = nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, req, sizeof(nfapi_dl_config_request_t), &(pnf_p7->_public.codec_config)); + + if(unpack_result == 0) + { + if(pthread_mutex_lock(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to lock mutex\n"); + return; + } + + if ( + 0 && + (NFAPI_SFNSF2DEC(req->sfn_sf) % 100 ==0 || + NFAPI_SFNSF2DEC(req->sfn_sf) % 105 ==0 + ) + ) + NFAPI_TRACE(NFAPI_TRACE_INFO, "DL_CONFIG.req sfn_sf:%d pdcch:%u dci:%u pdu:%u pdsch_rnti:%u pcfich:%u\n", + NFAPI_SFNSF2DEC(req->sfn_sf), + req->dl_config_request_body.number_pdcch_ofdm_symbols, + req->dl_config_request_body.number_dci, + req->dl_config_request_body.number_pdu, + req->dl_config_request_body.number_pdsch_rnti, + req->dl_config_request_body.transmission_power_pcfich + ); + + if(is_p7_request_in_window(req->sfn_sf, "dl_config_request", pnf_p7)) + { + uint32_t sfn_sf_dec = NFAPI_SFNSF2DEC(req->sfn_sf); + uint8_t buffer_index = sfn_sf_dec % pnf_p7->_public.subframe_buffer_size; + + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + + NFAPI_TRACE(NFAPI_TRACE_INFO,"%s() %ld.%09ld POPULATE DL_CONFIG_REQ sfn_sf:%d buffer_index:%d\n", __FUNCTION__, t.tv_sec, t.tv_nsec, sfn_sf_dec, buffer_index); + + // if there is already an dl_config_req make sure we free it. + if(pnf_p7->subframe_buffer[buffer_index].dl_config_req != 0) + { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "%s() is_p7_request_in_window()=TRUE buffer_index occupied - free it first sfn_sf:%d buffer_index:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), buffer_index); + //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] Freeing dl_config_req at index %d (%d/%d)", + // pMyPhyInfo->sfnSf, bufferIdx, + // SFNSF2SFN(dreq->sfn_sf), SFNSF2SF(dreq->sfn_sf)); + deallocate_nfapi_dl_config_request(pnf_p7->subframe_buffer[buffer_index].dl_config_req, pnf_p7); + } + + // saving dl_config_request in subframe buffer + pnf_p7->subframe_buffer[buffer_index].sfn_sf = req->sfn_sf; + pnf_p7->subframe_buffer[buffer_index].dl_config_req = req; + + pnf_p7->stats.dl_conf_ontime++; + + } + else + { + //NFAPI_TRACE(NFAPI_TRACE_NOTE, "NOT storing dl_config_req SFN/SF %d\n", req->sfn_sf); + deallocate_nfapi_dl_config_request(req, pnf_p7); + + if(pnf_p7->_public.timing_info_mode_aperiodic) + { + pnf_p7->timing_info_aperiodic_send = 1; + } + + pnf_p7->stats.dl_conf_late++; + } + + if(pthread_mutex_unlock(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); + return; + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to unpack dl_config_req"); + deallocate_nfapi_dl_config_request(req, pnf_p7); + } +} + +void pnf_handle_ul_config_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "UL_CONFIG.req Received\n"); + + nfapi_ul_config_request_t* req = allocate_nfapi_ul_config_request(pnf_p7); + + if(req == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to alloced nfapi_ul_config_request structure\n"); + return; + } + + int unpack_result = nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, req, sizeof(nfapi_ul_config_request_t), &(pnf_p7->_public.codec_config)); + + if(unpack_result == 0) + { + if(pthread_mutex_lock(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to lock mutex\n"); + return; + } + + if(is_p7_request_in_window(req->sfn_sf, "ul_config_request", pnf_p7)) + { + uint32_t sfn_sf_dec = NFAPI_SFNSF2DEC(req->sfn_sf); + uint8_t buffer_index = sfn_sf_dec % pnf_p7->_public.subframe_buffer_size; + + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + + NFAPI_TRACE(NFAPI_TRACE_INFO,"%s() %ld.%09ld POPULATE UL_CONFIG_REQ sfn_sf:%d buffer_index:%d\n", __FUNCTION__, t.tv_sec, t.tv_nsec, sfn_sf_dec, buffer_index); + + if(pnf_p7->subframe_buffer[buffer_index].ul_config_req != 0) + { + //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] Freeing ul_config_req at index %d (%d/%d)", + // pMyPhyInfo->sfnSf, bufferIdx, + // SFNSF2SFN(dreq->sfn_sf), SFNSF2SF(dreq->sfn_sf)); + + deallocate_nfapi_ul_config_request(pnf_p7->subframe_buffer[buffer_index].ul_config_req, pnf_p7); + } + + pnf_p7->subframe_buffer[buffer_index].sfn_sf = req->sfn_sf; + pnf_p7->subframe_buffer[buffer_index].ul_config_req = req; + + pnf_p7->stats.ul_conf_ontime++; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] NOT storing ul_config_req OUTSIDE OF TRANSMIT BUFFER WINDOW SFN/SF %d\n", NFAPI_SFNSF2DEC(pnf_p7->sfn_sf), NFAPI_SFNSF2DEC(req->sfn_sf)); + deallocate_nfapi_ul_config_request(req, pnf_p7); + + if(pnf_p7->_public.timing_info_mode_aperiodic) + { + pnf_p7->timing_info_aperiodic_send = 1; + } + + pnf_p7->stats.ul_conf_late++; + } + + if(pthread_mutex_unlock(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); + return; + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to unpack ul_config_req\n"); + deallocate_nfapi_ul_config_request(req, pnf_p7); + } +} + +void pnf_handle_hi_dci0_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "HI_DCI0.req Received\n"); + + nfapi_hi_dci0_request_t* req = allocate_nfapi_hi_dci0_request(pnf_p7); + + if(req == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to alloced nfapi_hi_dci0_request structure\n"); + return; + } + + int unpack_result = nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, req, sizeof(nfapi_hi_dci0_request_t), &pnf_p7->_public.codec_config); + + if(unpack_result == 0) + { + if(pthread_mutex_lock(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to lock mutex\n"); + return; + } + + if(is_p7_request_in_window(req->sfn_sf, "hi_dci0_request", pnf_p7)) + { + uint32_t sfn_sf_dec = NFAPI_SFNSF2DEC(req->sfn_sf); + uint8_t buffer_index = sfn_sf_dec % pnf_p7->_public.subframe_buffer_size; + + if(pnf_p7->subframe_buffer[buffer_index].hi_dci0_req!= 0) + { + //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] Freeing hi_dci0_req at index %d (%d/%d)", + // pMyPhyInfo->sfnSf, bufferIdx, + // SFNSF2SFN(dreq->sfn_sf), SFNSF2SF(dreq->sfn_sf)); + + deallocate_nfapi_hi_dci0_request(pnf_p7->subframe_buffer[buffer_index].hi_dci0_req, pnf_p7); + } + + pnf_p7->subframe_buffer[buffer_index].sfn_sf = req->sfn_sf; + pnf_p7->subframe_buffer[buffer_index].hi_dci0_req = req; + + pnf_p7->stats.hi_dci0_ontime++; + + } + else + { + //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] NOT storing hi_dci0_req SFN/SF %d/%d\n", pMyPhyInfo->sfnSf, SFNSF2SFN(req->sfn_sf), SFNSF2SF(req->sfn_sf)); + deallocate_nfapi_hi_dci0_request(req, pnf_p7); + + if(pnf_p7->_public.timing_info_mode_aperiodic) + { + pnf_p7->timing_info_aperiodic_send = 1; + } + + pnf_p7->stats.hi_dci0_late++; + } + + if(pthread_mutex_unlock(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); + return; + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to unpack hi_dci0_req\n"); + deallocate_nfapi_hi_dci0_request(req, pnf_p7); + } +} + +void pnf_handle_tx_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "TX.req Received\n"); + + nfapi_tx_request_t* req = allocate_nfapi_tx_request(pnf_p7); + + if(req == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to alloced nfapi_tx_request structure\n"); + return; + } + + int unpack_result = nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, req, sizeof(nfapi_tx_request_t), &pnf_p7->_public.codec_config); + if(unpack_result == 0) + { + if(pthread_mutex_lock(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to lock mutex\n"); + return; + } + + if(is_p7_request_in_window(req->sfn_sf, "tx_request", pnf_p7)) + { + uint32_t sfn_sf_dec = NFAPI_SFNSF2DEC(req->sfn_sf); + uint8_t buffer_index = sfn_sf_dec % pnf_p7->_public.subframe_buffer_size; + + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + + NFAPI_TRACE(NFAPI_TRACE_INFO,"%s() %ld.%09ld POPULATE TX_REQ sfn_sf:%d buffer_index:%d\n", __FUNCTION__, t.tv_sec, t.tv_nsec, sfn_sf_dec, buffer_index); + + if (0 && NFAPI_SFNSF2DEC(req->sfn_sf)%100==0) NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() TX_REQ.req sfn_sf:%d pdus:%d - TX_REQ is within window\n", + __FUNCTION__, + NFAPI_SFNSF2DEC(req->sfn_sf), + req->tx_request_body.number_of_pdus); + + if(pnf_p7->subframe_buffer[buffer_index].tx_req != 0) + { + //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] Freeing tx_req at index %d (%d/%d)", + // pMyPhyInfo->sfnSf, bufferIdx, + // SFNSF2SFN(dreq->sfn_sf), SFNSF2SF(dreq->sfn_sf)); + + deallocate_nfapi_tx_request(pnf_p7->subframe_buffer[buffer_index].tx_req, pnf_p7); + } + + pnf_p7->subframe_buffer[buffer_index].sfn_sf = req->sfn_sf; + pnf_p7->subframe_buffer[buffer_index].tx_req = req; + + pnf_p7->stats.tx_ontime++; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO,"%s() TX_REQUEST Request is outside of window REQ:SFN_SF:%d CURR:SFN_SF:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), NFAPI_SFNSF2DEC(pnf_p7->sfn_sf)); + + deallocate_nfapi_tx_request(req, pnf_p7); + + if(pnf_p7->_public.timing_info_mode_aperiodic) + { + pnf_p7->timing_info_aperiodic_send = 1; + } + + pnf_p7->stats.tx_late++; + } + + if(pthread_mutex_unlock(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); + return; + } + } + else + { + deallocate_nfapi_tx_request(req, pnf_p7); + } +} + +void pnf_handle_lbt_dl_config_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7) +{ + nfapi_lbt_dl_config_request_t* req = allocate_nfapi_lbt_dl_config_request(pnf_p7); + + if(req == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to alloced nfapi_lbt_dl_config_request structure\n"); + return; + } + + int unpack_result = nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, req, sizeof(nfapi_lbt_dl_config_request_t), &pnf_p7->_public.codec_config); + + if(unpack_result == 0) + { + if(pthread_mutex_lock(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to lock mutex\n"); + return; + } + + if(is_p7_request_in_window(req->sfn_sf, "lbt_dl_request", pnf_p7)) + { + uint32_t sfn_sf_dec = NFAPI_SFNSF2DEC(req->sfn_sf); + uint8_t buffer_index = sfn_sf_dec % pnf_p7->_public.subframe_buffer_size; + + if(pnf_p7->subframe_buffer[buffer_index].lbt_dl_config_req != 0) + { + //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[%d] Freeing tx_req at index %d (%d/%d)", + // pMyPhyInfo->sfnSf, bufferIdx, + // SFNSF2SFN(dreq->sfn_sf), SFNSF2SF(dreq->sfn_sf)); + + deallocate_nfapi_lbt_dl_config_request(pnf_p7->subframe_buffer[buffer_index].lbt_dl_config_req, pnf_p7); + } + + pnf_p7->subframe_buffer[buffer_index].sfn_sf = req->sfn_sf; + pnf_p7->subframe_buffer[buffer_index].lbt_dl_config_req = req; + } + else + { + deallocate_nfapi_lbt_dl_config_request(req, pnf_p7); + + if(pnf_p7->_public.timing_info_mode_aperiodic) + { + pnf_p7->timing_info_aperiodic_send = 1; + } + } + + if(pthread_mutex_unlock(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); + return; + } + } + else + { + deallocate_nfapi_lbt_dl_config_request(req, pnf_p7); + } + +} + +void pnf_handle_p7_vendor_extension(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7, uint16_t message_id) +{ + if(pnf_p7->_public.allocate_p7_vendor_ext) + { + uint16_t msg_size; + nfapi_p7_message_header_t* msg = pnf_p7->_public.allocate_p7_vendor_ext(message_id, &msg_size); + + if(msg == 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to allocate vendor extention structure\n"); + return; + } + + int unpack_result = nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, msg, msg_size, &pnf_p7->_public.codec_config); + + if(unpack_result == 0) + { + if(pnf_p7->_public.vendor_ext) + pnf_p7->_public.vendor_ext(&(pnf_p7->_public), msg); + } + + if(pnf_p7->_public.deallocate_p7_vendor_ext) + pnf_p7->_public.deallocate_p7_vendor_ext(msg); + + } + +} + + +uint32_t calculate_t2(uint32_t now_time_hr, uint16_t sfn_sf, uint32_t sf_start_time_hr) +{ + uint32_t sf_time_us = get_sf_time(now_time_hr, sf_start_time_hr); + uint32_t t2 = (NFAPI_SFNSF2DEC(sfn_sf) * 1000) + sf_time_us; + + if (0) + { + static uint32_t prev_t2 = 0; + + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s(now_time_hr:%u sfn_sf:%d sf_start_time_Hr:%u) sf_time_us:%u t2:%u prev_t2:%u diff:%u\n", + __FUNCTION__, + now_time_hr, NFAPI_SFNSF2DEC(sfn_sf), sf_start_time_hr, + sf_time_us, + t2, + prev_t2, + t2-prev_t2); + + prev_t2 = t2; + } + + return t2; +} + +uint32_t calculate_t3(uint16_t sfn_sf, uint32_t sf_start_time_hr) +{ + uint32_t now_time_hr = pnf_get_current_time_hr(); + + uint32_t sf_time_us = get_sf_time(now_time_hr, sf_start_time_hr); + + uint32_t t3 = (NFAPI_SFNSF2DEC(sfn_sf) * 1000) + sf_time_us; + + return t3; +} + +void pnf_handle_dl_node_sync(void *pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7, uint32_t rx_hr_time) +{ + nfapi_dl_node_sync_t dl_node_sync; + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "DL_NODE_SYNC Received\n"); + + if (pRecvMsg == NULL || pnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + return; + } + + // unpack the message + if (nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, &dl_node_sync, sizeof(dl_node_sync), &pnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + return; + } + + if(pthread_mutex_lock(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to lock mutex\n"); + return; + } + + + if (dl_node_sync.delta_sfn_sf != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Will shift SF timing by %d on next subframe\n", dl_node_sync.delta_sfn_sf); + + pnf_p7->sfn_sf_shift = dl_node_sync.delta_sfn_sf; + } + + nfapi_ul_node_sync_t ul_node_sync; + memset(&ul_node_sync, 0, sizeof(ul_node_sync)); + ul_node_sync.header.message_id = NFAPI_UL_NODE_SYNC; + ul_node_sync.header.phy_id = dl_node_sync.header.phy_id; + ul_node_sync.t1 = dl_node_sync.t1; + ul_node_sync.t2 = calculate_t2(rx_hr_time, pnf_p7->sfn_sf, pnf_p7->sf_start_time_hr); + ul_node_sync.t3 = calculate_t3(pnf_p7->sfn_sf, pnf_p7->sf_start_time_hr); + + if(pthread_mutex_unlock(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); + return; + } + + pnf_p7_pack_and_send_p7_message(pnf_p7, &(ul_node_sync.header), sizeof(ul_node_sync)); +} + +void pnf_dispatch_p7_message(void *pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7, uint32_t rx_hr_time) +{ + nfapi_p7_message_header_t header; + + // validate the input params + if(pRecvMsg == NULL || recvMsgLen < 4 || pnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return; + } + + // unpack the message header + if (nfapi_p7_message_header_unpack(pRecvMsg, recvMsgLen, &header, sizeof(header), &pnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); + return; + } + + // ensure the message is sensible + if (recvMsgLen < 8 || pRecvMsg == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_WARN, "Invalid message size: %d, ignoring\n", recvMsgLen); + return; + } + + switch (header.message_id) + { + case NFAPI_DL_NODE_SYNC: + pnf_handle_dl_node_sync(pRecvMsg, recvMsgLen, pnf_p7, rx_hr_time); + break; + + case NFAPI_DL_CONFIG_REQUEST: + pnf_handle_dl_config_request(pRecvMsg, recvMsgLen, pnf_p7); + break; + + case NFAPI_UL_CONFIG_REQUEST: + pnf_handle_ul_config_request(pRecvMsg, recvMsgLen, pnf_p7); + break; + + case NFAPI_HI_DCI0_REQUEST: + pnf_handle_hi_dci0_request(pRecvMsg, recvMsgLen, pnf_p7); + break; + + case NFAPI_TX_REQUEST: + pnf_handle_tx_request(pRecvMsg, recvMsgLen, pnf_p7); + break; + + case NFAPI_LBT_DL_CONFIG_REQUEST: + pnf_handle_lbt_dl_config_request(pRecvMsg, recvMsgLen, pnf_p7); + break; + + default: + { + if(header.message_id >= NFAPI_VENDOR_EXT_MSG_MIN && + header.message_id <= NFAPI_VENDOR_EXT_MSG_MAX) + { + pnf_handle_p7_vendor_extension(pRecvMsg, recvMsgLen, pnf_p7, header.message_id); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s P7 Unknown message ID %d\n", __FUNCTION__, header.message_id); + } + } + break; + } +} + +void pnf_handle_p7_message(void *pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7, uint32_t rx_hr_time) +{ + nfapi_p7_message_header_t messageHeader; + + // validate the input params + if(pRecvMsg == NULL || recvMsgLen < 4 || pnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "pnf_handle_p7_message: invalid input params (%d %d %d)\n", pRecvMsg, recvMsgLen, pnf_p7); + return; + } + + // unpack the message header + if (nfapi_p7_message_header_unpack(pRecvMsg, recvMsgLen, &messageHeader, sizeof(nfapi_p7_message_header_t), &pnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); + return; + } + + uint8_t m = NFAPI_P7_GET_MORE(messageHeader.m_segment_sequence); + uint8_t sequence_num = NFAPI_P7_GET_SEQUENCE(messageHeader.m_segment_sequence); + uint8_t segment_num = NFAPI_P7_GET_SEGMENT(messageHeader.m_segment_sequence); + + if(pnf_p7->_public.checksum_enabled) + { + uint32_t checksum = nfapi_p7_calculate_checksum(pRecvMsg, recvMsgLen); + if(checksum != messageHeader.checksum) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Checksum verification failed %d %d\n", checksum, messageHeader.checksum); + return; + } + } + + if(m == 0 && segment_num == 0) + { + // we have a complete message + // ensure the message is sensible + if (recvMsgLen < 8 || pRecvMsg == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_WARN, "Invalid message size: %d, ignoring\n", recvMsgLen); + return; + } + + pnf_dispatch_p7_message(pRecvMsg, recvMsgLen, pnf_p7, rx_hr_time); + } + else + { + pnf_p7_rx_message_t* rx_msg = pnf_p7_rx_reassembly_queue_add_segment(pnf_p7, &(pnf_p7->reassembly_queue), rx_hr_time, sequence_num, segment_num, m, pRecvMsg, recvMsgLen); + + if(rx_msg->num_segments_received == rx_msg->num_segments_expected) + { + // send the buffer on + uint16_t i = 0; + uint16_t length = 0; + for(i = 0; i < rx_msg->num_segments_expected; ++i) + { + length += rx_msg->segments[i].length - (i > 0 ? NFAPI_P7_HEADER_LENGTH : 0); + } + + if(pnf_p7->reassemby_buffer_size < length) + { + pnf_p7_free(pnf_p7, pnf_p7->reassemby_buffer); + pnf_p7->reassemby_buffer = 0; + } + + if(pnf_p7->reassemby_buffer == 0) + { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "Resizing PNF_P7 Reassembly buffer %d->%d\n", pnf_p7->reassemby_buffer_size, length); + pnf_p7->reassemby_buffer = (uint8_t*)pnf_p7_malloc(pnf_p7, length); + + if(pnf_p7->reassemby_buffer == 0) + { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "Failed to allocate PNF_P7 reassemby buffer len:%d\n", length); + return; + } + + pnf_p7->reassemby_buffer_size = length; + } + + uint16_t offset = 0; + for(i = 0; i < rx_msg->num_segments_expected; ++i) + { + if(i == 0) + { + memcpy(pnf_p7->reassemby_buffer, rx_msg->segments[i].buffer, rx_msg->segments[i].length); + offset += rx_msg->segments[i].length; + } + else + { + memcpy(pnf_p7->reassemby_buffer + offset, rx_msg->segments[i].buffer + NFAPI_P7_HEADER_LENGTH, rx_msg->segments[i].length - NFAPI_P7_HEADER_LENGTH); + offset += rx_msg->segments[i].length - NFAPI_P7_HEADER_LENGTH; + } + } + + + pnf_dispatch_p7_message(pnf_p7->reassemby_buffer, length, pnf_p7, rx_msg->rx_hr_time); + + + // delete the structure + pnf_p7_rx_reassembly_queue_remove_msg(pnf_p7, &(pnf_p7->reassembly_queue), rx_msg); + } + } + + pnf_p7_rx_reassembly_queue_remove_old_msgs(pnf_p7, &(pnf_p7->reassembly_queue), rx_hr_time, 1000); + +} +void pnf_nfapi_p7_read_dispatch_message(pnf_p7_t* pnf_p7, uint32_t now_hr_time) +{ + int recvfrom_result = 0; + struct sockaddr_in remote_addr; + socklen_t remote_addr_size = sizeof(remote_addr); + + do + { + // peek the header + uint8_t header_buffer[NFAPI_P7_HEADER_LENGTH]; + recvfrom_result = recvfrom(pnf_p7->p7_sock, header_buffer, NFAPI_P7_HEADER_LENGTH, MSG_DONTWAIT | MSG_PEEK, (struct sockaddr*)&remote_addr, &remote_addr_size); + + if(recvfrom_result > 0) + { + // get the segment size + nfapi_p7_message_header_t header; + nfapi_p7_message_header_unpack(header_buffer, NFAPI_P7_HEADER_LENGTH, &header, 34, 0); + + // resize the buffer if we have a large segment + if(header.message_length > pnf_p7->rx_message_buffer_size) + { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "reallocing rx buffer %d\n", header.message_length); + pnf_p7->rx_message_buffer = realloc(pnf_p7->rx_message_buffer, header.message_length); + pnf_p7->rx_message_buffer_size = header.message_length; + } + + // read the segment + recvfrom_result = recvfrom(pnf_p7->p7_sock, pnf_p7->rx_message_buffer, header.message_length, MSG_DONTWAIT, (struct sockaddr*)&remote_addr, &remote_addr_size); + + now_hr_time = pnf_get_current_time_hr(); //DJP - moved to here - get closer timestamp??? + + if(recvfrom_result > 0) + { + pnf_handle_p7_message(pnf_p7->rx_message_buffer, recvfrom_result, pnf_p7, now_hr_time); + } + } + else if(recvfrom_result == 0) + { + // recv zero length message + recvfrom_result = recvfrom(pnf_p7->p7_sock, header_buffer, 0, MSG_DONTWAIT, (struct sockaddr*)&remote_addr, &remote_addr_size); + } + + if(recvfrom_result == -1) + { + if(errno == EAGAIN || errno == EWOULDBLOCK) + { + // return to the select + //NFAPI_TRACE(NFAPI_TRACE_WARN, "%s recvfrom would block :%d\n", __FUNCTION__, errno); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_WARN, "%s recvfrom failed errno:%d\n", __FUNCTION__, errno); + } + } + + // need to update the time as we would only use the value from the + // select +#if 0 +// DJP - why do this here and not on return from recv??? + now_hr_time = pnf_get_current_time_hr(); +#endif + } + while(recvfrom_result > 0); +} + +int pnf_p7_message_pump(pnf_p7_t* pnf_p7) +{ + + // initialize the mutex lock + if(pthread_mutex_init(&(pnf_p7->mutex), NULL) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P7 mutex init: %d\n", errno); + return -1; + } + + if(pthread_mutex_init(&(pnf_p7->pack_mutex), NULL) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P7 mutex init: %d\n", errno); + return -1; + } + + // create the pnf p7 socket + if ((pnf_p7->p7_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P7 socket errno: %d\n", errno); + return -1; + } + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 socket created (%d)...\n", pnf_p7->p7_sock); + + // configure the UDP socket options + int reuseaddr_enable = 1; + if (setsockopt(pnf_p7->p7_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_enable, sizeof(int)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF P7 setsockopt (SOL_SOCKET, SO_REUSEADDR) failed errno: %d\n", errno); + return -1; + } + +/* + int reuseport_enable = 1; + if (setsockopt(pnf_p7->p7_sock, SOL_SOCKET, SO_REUSEPORT, &reuseport_enable, sizeof(int)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF P7 setsockopt (SOL_SOCKET, SO_REUSEPORT) failed errno: %d\n", errno); + return -1; + } +*/ + + int iptos_value = FAPI2_IP_DSCP << 2; + if (setsockopt(pnf_p7->p7_sock, IPPROTO_IP, IP_TOS, &iptos_value, sizeof(iptos_value)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF P7 setsockopt (IPPROTO_IP, IP_TOS) failed errno: %d\n", errno); + return -1; + } + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(pnf_p7->_public.local_p7_port); + + if(pnf_p7->_public.local_p7_addr == 0) + { + addr.sin_addr.s_addr = INADDR_ANY; + } + else + { + //addr.sin_addr.s_addr = inet_addr(pnf_p7->_public.local_p7_addr); + if(inet_aton(pnf_p7->_public.local_p7_addr, &addr.sin_addr) == -1) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "inet_aton failed\n"); + } + } + + + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 binding %d too %s:%d\n", pnf_p7->p7_sock, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + if (bind(pnf_p7->p7_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF_P7 bind error fd:%d errno: %d\n", pnf_p7->p7_sock, errno); + return -1; + } + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 bind succeeded...\n"); + + while(pnf_p7->terminate == 0) + { + fd_set rfds; + int selectRetval = 0; + + // select on a timeout and then get the message + FD_ZERO(&rfds); + FD_SET(pnf_p7->p7_sock, &rfds); + + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + selectRetval = select(pnf_p7->p7_sock+1, &rfds, NULL, NULL, &timeout); + + uint32_t now_hr_time = pnf_get_current_time_hr(); + + if(selectRetval == 0) + { + // timeout + continue; + } + else if (selectRetval == -1 && (errno == EINTR)) + { + // interrupted by signal + NFAPI_TRACE(NFAPI_TRACE_WARN, "PNF P7 Signal Interrupt %d\n", errno); + continue; + } + else if (selectRetval == -1) + { + NFAPI_TRACE(NFAPI_TRACE_WARN, "PNF P7 select() failed\n"); + sleep(1); + continue; + } + + if(FD_ISSET(pnf_p7->p7_sock, &rfds)) + { + pnf_nfapi_p7_read_dispatch_message(pnf_p7, now_hr_time); + } + } + NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF_P7 Terminating..\n"); + + // close the connection and socket + if (close(pnf_p7->p7_sock) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "close failed errno: %d\n", errno); + } + + if(pthread_mutex_destroy(&(pnf_p7->pack_mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "mutex destroy failed errno: %d\n", errno); + } + + if(pthread_mutex_destroy(&(pnf_p7->mutex)) != 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "mutex destroy failed errno: %d\n", errno); + } + + return 0; +} diff --git a/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c b/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c new file mode 100644 index 0000000000..74de5e5d78 --- /dev/null +++ b/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c @@ -0,0 +1,225 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "pnf_p7.h" +#include +#include + +nfapi_pnf_p7_config_t* nfapi_pnf_p7_config_create() +{ + pnf_p7_t* _this = (pnf_p7_t*)calloc(1, sizeof(pnf_p7_t)); + + if(_this == 0) + return 0; + + + // set the default parameters + _this->_public.segment_size = 1400; + _this->max_num_segments = 8; + + _this->_public.subframe_buffer_size = 8; + _this->_public.timing_info_mode_periodic = 1; + _this->_public.timing_info_period = 32; + _this->_public.timing_info_mode_aperiodic = 1; + + _this->_public.checksum_enabled = 1; + + _this->_public.malloc = &malloc; + _this->_public.free = &free; + + _this->_public.codec_config.allocate = &malloc; + _this->_public.codec_config.deallocate = &free; + + return &(_this->_public); +} + +void nfapi_pnf_p7_config_destory(nfapi_pnf_p7_config_t* config) +{ + if(config == 0) + return ; + + free(config); +} + + + +int nfapi_pnf_p7_start(nfapi_pnf_p7_config_t* config) +{ + // Verify that config is not null + if(config == 0) + return -1; + + // Make sure to set the defined trace function before using NFAPI_TRACE + if(config->trace) + nfapi_trace_g = config->trace; + + pnf_p7_t* _this = (pnf_p7_t*)(config); + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + + pnf_p7_message_pump(_this); + + return 0; +} + +int nfapi_pnf_p7_stop(nfapi_pnf_p7_config_t* config) +{ + // Verify that config is not null + if(config == 0) + return -1; + + pnf_p7_t* _this = (pnf_p7_t*)(config); + _this->terminate = 1; + + return 0; +} + + +int nfapi_pnf_p7_subframe_ind(nfapi_pnf_p7_config_t* config, uint16_t phy_id, uint16_t sfn_sf) +{ + // Verify that config is not null + if(config == 0) + return -1; + + pnf_p7_t* _this = (pnf_p7_t*)(config); + + return pnf_p7_subframe_ind(_this, phy_id, sfn_sf); +} + +int nfapi_pnf_p7_harq_ind(nfapi_pnf_p7_config_t* config, nfapi_harq_indication_t* ind) +{ + if(config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return -1; + } + + pnf_p7_t* _this = (pnf_p7_t*)(config); + + return pnf_p7_pack_and_send_p7_message(_this, (nfapi_p7_message_header_t*)ind, sizeof(nfapi_harq_indication_t)); +} +int nfapi_pnf_p7_crc_ind(nfapi_pnf_p7_config_t* config, nfapi_crc_indication_t* ind) +{ + if(config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return -1; + } + + pnf_p7_t* _this = (pnf_p7_t*)(config); + return pnf_p7_pack_and_send_p7_message(_this, (nfapi_p7_message_header_t*)ind, sizeof(nfapi_crc_indication_t)); +} +int nfapi_pnf_p7_rx_ind(nfapi_pnf_p7_config_t* config, nfapi_rx_indication_t* ind) +{ + if(config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return -1; + } + + pnf_p7_t* _this = (pnf_p7_t*)(config); + return pnf_p7_pack_and_send_p7_message(_this, (nfapi_p7_message_header_t*)ind, sizeof(nfapi_rx_indication_t)); +} +int nfapi_pnf_p7_rach_ind(nfapi_pnf_p7_config_t* config, nfapi_rach_indication_t* ind) +{ + if(config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return -1; + } + + pnf_p7_t* _this = (pnf_p7_t*)(config); + return pnf_p7_pack_and_send_p7_message(_this, (nfapi_p7_message_header_t*)ind, sizeof(nfapi_rach_indication_t)); +} +int nfapi_pnf_p7_srs_ind(nfapi_pnf_p7_config_t* config, nfapi_srs_indication_t* ind) +{ + if(config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return -1; + } + + pnf_p7_t* _this = (pnf_p7_t*)(config); + return pnf_p7_pack_and_send_p7_message(_this, (nfapi_p7_message_header_t*)ind, sizeof(nfapi_srs_indication_t)); +} +int nfapi_pnf_p7_sr_ind(nfapi_pnf_p7_config_t* config, nfapi_sr_indication_t* ind) +{ + if(config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return -1; + } + + pnf_p7_t* _this = (pnf_p7_t*)(config); + return pnf_p7_pack_and_send_p7_message(_this, (nfapi_p7_message_header_t*)ind, sizeof(nfapi_sr_indication_t)); +} +int nfapi_pnf_p7_cqi_ind(nfapi_pnf_p7_config_t* config, nfapi_cqi_indication_t* ind) +{ + if(config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return -1; + } + + pnf_p7_t* _this = (pnf_p7_t*)(config); + return pnf_p7_pack_and_send_p7_message(_this, (nfapi_p7_message_header_t*)ind, sizeof(nfapi_cqi_indication_t)); +} +int nfapi_pnf_p7_lbt_dl_ind(nfapi_pnf_p7_config_t* config, nfapi_lbt_dl_indication_t* ind) +{ + if(config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return -1; + } + + pnf_p7_t* _this = (pnf_p7_t*)(config); + return pnf_p7_pack_and_send_p7_message(_this, (nfapi_p7_message_header_t*)ind, sizeof(nfapi_lbt_dl_indication_t)); +} +int nfapi_pnf_p7_nb_harq_ind(nfapi_pnf_p7_config_t* config, nfapi_nb_harq_indication_t* ind) +{ + if(config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return -1; + } + + pnf_p7_t* _this = (pnf_p7_t*)(config); + return pnf_p7_pack_and_send_p7_message(_this, (nfapi_p7_message_header_t*)ind, sizeof(nfapi_nb_harq_indication_t)); +} +int nfapi_pnf_p7_nrach_ind(nfapi_pnf_p7_config_t* config, nfapi_nrach_indication_t* ind) +{ + if(config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return -1; + } + + pnf_p7_t* _this = (pnf_p7_t*)(config); + return pnf_p7_pack_and_send_p7_message(_this, (nfapi_p7_message_header_t*)ind, sizeof(nfapi_nrach_indication_t)); +} +int nfapi_pnf_p7_vendor_extension(nfapi_pnf_p7_config_t* config, nfapi_p7_message_header_t* msg) +{ + if(config == NULL || msg == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return -1; + } + + pnf_p7_t* _this = (pnf_p7_t*)(config); + return pnf_p7_pack_and_send_p7_message(_this, msg, 0); +} + diff --git a/nfapi/open-nFAPI/pnf/tests/Makefile.am b/nfapi/open-nFAPI/pnf/tests/Makefile.am new file mode 100644 index 0000000000..4dcdea0511 --- /dev/null +++ b/nfapi/open-nFAPI/pnf/tests/Makefile.am @@ -0,0 +1,28 @@ +# +# Copyright 2017 Cisco Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +#nfapi unit test +AUTOMAKE_OPTIONS=subdir-objects +AM_CPPFLAGS = -I$(top_srcdir)/nfapi/inc -I$(top_srcdir)/nfapi/public_inc -I$(top_srcdir)/common/public_inc -I$(top_srcdir)/pnf/public_inc $(CFLAGS_CUNIT) -Wall -Werror + +check_PROGRAMS= test_pnf + +test_pnf_SOURCES = pnf_cunit_main.c ../../common/src/debug.c +test_pnf_LDADD=$(top_builddir)/pnf/libnfapi_pnf.a $(top_builddir)/nfapi/libnfapi.a -L$(libdir) -lpthread -lrt -lsctp -lz -lcunit + +LOG_DRIVER = $(top_srcdir)/tap-driver.sh +TESTS=$(check_PROGRAMS) +EXTRA_DIST = $(TESTS) diff --git a/nfapi/open-nFAPI/pnf/tests/pnf_cunit_main.c b/nfapi/open-nFAPI/pnf/tests/pnf_cunit_main.c new file mode 100644 index 0000000000..d2ab031ad4 --- /dev/null +++ b/nfapi/open-nFAPI/pnf/tests/pnf_cunit_main.c @@ -0,0 +1,2365 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CUnit.h" + +#include "Basic.h" +#include "Automated.h" +//#include "CUnit/Console.h" + +#include "nfapi_interface.h" +#include "nfapi_pnf_interface.h" +#include "nfapi.h" +#include // for printf +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "debug.h" + +/* Test Suite setup and cleanup functions: */ + +int init_suite(void) { return 0; } +int clean_suite(void) { return 0; } + +#define MAX_PACKED_MESSAGE_SIZE 8192 + +typedef struct phy_info +{ + uint8_t enabled; + uint16_t phy_id; + uint16_t sfn_sf; + + pthread_t thread; + + int pnf_p7_port; + char* pnf_p7_addr; + + int vnf_p7_port; + char* vnf_p7_addr; + + nfapi_pnf_p7_config_t* config; + +} phy_info_t; + +typedef struct pnf_info +{ + uint8_t num_phys; + phy_info_t phys[8]; + +} pnf_info_t; + +phy_info_t* find_phy_info(pnf_info_t* pnf, uint16_t phy_id) +{ + int i = 0; + for(i = 0; i < 8; ++i) + { + if(pnf->phys[i].enabled == 1 && pnf->phys[i].phy_id == phy_id) + { + return &(pnf->phys[i]); + } + } + return 0; +} + + + +/************* Test case functions ****************/ + +void pnf_test_start_no_config(void) +{ + int result = nfapi_pnf_start(0); + CU_ASSERT_EQUAL(result, -1); +} + +void test_trace(nfapi_trace_level_t level, const char* message, ...) +{ + printf("%s", message); +} + + +void* pnf_test_start_thread(void* ptr) +{ + int result = nfapi_pnf_start((nfapi_pnf_config_t*)ptr); + return (void*)(intptr_t)result; +} + +void* pnf_test_start_p7_thread(void* ptr) +{ + int result = nfapi_pnf_p7_start((nfapi_pnf_p7_config_t*)ptr); + return (void*)(intptr_t)result; +} + +void pnf_test_start_no_connection(void) +{ + char* vnf_addr = "127.127.0.1"; + nfapi_pnf_config_t* config = nfapi_pnf_config_create(); + config->vnf_ip_addr = vnf_addr; + + pthread_t thread; + pthread_create(&thread, NULL, &pnf_test_start_thread, config); + + sleep(1); + + nfapi_pnf_stop(config); + + int* result; + pthread_join(thread, (void**)&result); + CU_ASSERT_EQUAL(result, 0); +} + +void pnf_test_start_no_ip(void) +{ + nfapi_pnf_config_t* config = nfapi_pnf_config_create(); + + pthread_t thread; + pthread_create(&thread, NULL, &pnf_test_start_thread, config); + + sleep(2); + + nfapi_pnf_stop(config); + + intptr_t result; + pthread_join(thread, (void**)&result); + CU_ASSERT_EQUAL((int)result, -1); +} + +void pnf_test_start_invalid_ip(void) +{ + char* vnf_addr = "not.an.ip.address"; + nfapi_pnf_config_t* config = nfapi_pnf_config_create(); + config->vnf_ip_addr = vnf_addr; + + pthread_t thread; + pthread_create(&thread, NULL, &pnf_test_start_thread, config); + + sleep(2); + + nfapi_pnf_stop(config); + + intptr_t result; + pthread_join(thread, (void**)&result); + CU_ASSERT_EQUAL((int)result, -1); +} + +int create_p5_listen_socket(char* ip, int port) +{ + int p5ListenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + // bind to the configured address and port + bind(p5ListenSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + + return p5ListenSock; +} +int create_p5_ipv6_listen_socket(char* ip, int port) +{ + struct addrinfo hints, *servinfo; + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; // For SCTP we are only interested in SOCK_STREAM + hints.ai_family= AF_INET6; + + char port_str[8]; + snprintf(port_str, sizeof(port_str), "%d", port); + getaddrinfo(ip, port_str, &hints, &servinfo); + + + int p5ListenSock = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP); + //printf("Socket result %d\n", p5ListenSock); + + // bind to the configured address and port + /*int bind_result = */ + bind(p5ListenSock, servinfo->ai_addr, servinfo->ai_addrlen); + //printf("Bind result %d (errno:%d)\n", bind_result, errno); + + freeaddrinfo(servinfo); + + return p5ListenSock; +} + +/* +int wait_for_pnf_connection(int p5ListenSock) +{ + listen(p5ListenSock, 2); + socklen_t addrSize; + int p5Sock = accept(p5ListenSock, (struct sockaddr *)&addr, &addrSize); + + return p5Sock; +} +*/ + +int test_param_request_called = 0; +int test_pnf_param_request(nfapi_pnf_config_t* config, nfapi_pnf_param_request_t* req) +{ + printf("test_pnf_param_request called.... ;-)\n"); + + nfapi_pnf_param_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_PARAM_RESPONSE; + + resp.pnf_param_general.tl.tag = NFAPI_PNF_PARAM_GENERAL_TAG; + resp.pnf_param_general.nfapi_sync_mode = 2; + resp.pnf_param_general.location_mode = 1; + resp.pnf_param_general.location_coordinates[0] = 123; + resp.pnf_param_general.dl_config_timing = 12; + resp.pnf_param_general.tx_timing = 12; + resp.pnf_param_general.ul_config_timing = 12; + resp.pnf_param_general.hi_dci0_timing = 12; + resp.pnf_param_general.maximum_number_phys = 2; + resp.pnf_param_general.maximum_total_bandwidth = 100; + resp.pnf_param_general.maximum_total_number_dl_layers = 2; + resp.pnf_param_general.maximum_total_number_ul_layers = 2; + resp.pnf_param_general.shared_bands = 0; + resp.pnf_param_general.shared_pa = 0; + resp.pnf_param_general.maximum_total_power = -190; + resp.pnf_param_general.oui[0] = 88; +/* + in.pnf_phy.tl.tag = NFAPI_PNF_PHY_TAG; + in.pnf_phy.number_of_phys = 2; + in.pnf_phy.phy[0].phy_config_index = 0; + in.pnf_phy.phy[0].number_of_rfs = 2; + in.pnf_phy.phy[0].rf_config[0].rf_config_index = 0; + in.pnf_phy.phy[0].number_of_rf_exclusions = 1; + in.pnf_phy.phy[0].rf_config[0].rf_config_index = 1; + in.pnf_phy.phy[0].downlink_channel_bandwidth_supported = 20; + in.pnf_phy.phy[0].uplink_channel_bandwidth_supported = 20; + in.pnf_phy.phy[0].number_of_dl_layers_supported = 2; + in.pnf_phy.phy[0].number_of_ul_layers_supported = 1; + in.pnf_phy.phy[0].maximum_3gpp_release_supported = 3; + in.pnf_phy.phy[0].nmm_modes_supported = 2; + + in.pnf_rf.tl.tag = NFAPI_PNF_RF_TAG; + in.pnf_rf.number_of_rfs = 2; + in.pnf_rf.rf[0].rf_config_index = 0; + in.pnf_rf.rf[0].band = 1; + in.pnf_rf.rf[0].maximum_transmit_power = -100; + in.pnf_rf.rf[0].minimum_transmit_power = -90; + in.pnf_rf.rf[0].number_of_antennas_suppported = 4; + in.pnf_rf.rf[0].minimum_downlink_frequency = 100; + in.pnf_rf.rf[0].maximum_downlink_frequency = 2132; + in.pnf_rf.rf[0].minimum_uplink_frequency = 1231; + in.pnf_rf.rf[0].maximum_uplink_frequency = 123; + + + in.pnf_phy_rel10.tl.tag = NFAPI_PNF_PHY_REL10_TAG; + in.pnf_phy_rel10.number_of_phys = 2; + in.pnf_phy_rel10.phy[0].phy_config_index = 0; + in.pnf_phy_rel10.phy[0].transmission_mode_7_supported = 1; + in.pnf_phy_rel10.phy[0].transmission_mode_8_supported = 2; + in.pnf_phy_rel10.phy[0].two_antenna_ports_for_pucch = 3; + in.pnf_phy_rel10.phy[0].transmission_mode_9_supported = 4; + in.pnf_phy_rel10.phy[0].simultaneous_pucch_pusch = 5; + in.pnf_phy_rel10.phy[0].four_layer_tx_with_tm3_and_tm4 = 6; + + in.pnf_phy_rel11.tl.tag = NFAPI_PNF_PHY_REL11_TAG; + in.pnf_phy_rel11.number_of_phys = 2; + in.pnf_phy_rel11.phy[0].phy_config_index = 0; + in.pnf_phy_rel11.phy[0].edpcch_supported = 1; + in.pnf_phy_rel11.phy[0].multi_ack_csi_reporting = 2; + in.pnf_phy_rel11.phy[0].pucch_tx_diversity = 3; + in.pnf_phy_rel11.phy[0].ul_comp_supported = 4; + in.pnf_phy_rel11.phy[0].transmission_mode_5_supported = 5; + + in.pnf_phy_rel12.tl.tag = NFAPI_PNF_PHY_REL12_TAG; + in.pnf_phy_rel12.number_of_phys = 2; + in.pnf_phy_rel12.phy[0].phy_config_index = 0; + in.pnf_phy_rel12.phy[0].csi_subframe_set = 1; + in.pnf_phy_rel12.phy[0].enhanced_4tx_codebook = 2; + in.pnf_phy_rel12.phy[0].drs_supported = 3; + in.pnf_phy_rel12.phy[0].ul_64qam_supported = 4; + in.pnf_phy_rel12.phy[0].transmission_mode_10_supported = 5; + in.pnf_phy_rel12.phy[0].alternative_bts_indices = 6; + + in.pnf_phy_rel13.tl.tag = NFAPI_PNF_PHY_REL13_TAG; + in.pnf_phy_rel13.number_of_phys = 2; + in.pnf_phy_rel13.phy[0].phy_config_index = 0; + in.pnf_phy_rel13.phy[0].pucch_format4_supported = 1; + in.pnf_phy_rel13.phy[0].pucch_format5_supported = 2; + in.pnf_phy_rel13.phy[0].more_than_5_ca_support = 3; + in.pnf_phy_rel13.phy[0].laa_supported = 4; + in.pnf_phy_rel13.phy[0].laa_ending_in_dwpts_supported = 5; + in.pnf_phy_rel13.phy[0].laa_starting_in_second_slot_supported = 6; + in.pnf_phy_rel13.phy[0].beamforming_supported = 7; + in.pnf_phy_rel13.phy[0].csi_rs_enhancement_supported = 8; + in.pnf_phy_rel13.phy[0].drms_enhancement_supported = 9; + in.pnf_phy_rel13.phy[0].srs_enhancement_supported = 10; +*/ + test_param_request_called++; + + nfapi_pnf_pnf_param_resp(config, &resp); + return 0; +} + +int test_config_request_called = 0; +int test_pnf_config_request(nfapi_pnf_config_t* config, nfapi_pnf_config_request_t* req) +{ + printf("test_pnf_config_request called.... ;-)\n"); + + CU_ASSERT_EQUAL(req->pnf_phy_rf_config.tl.tag, NFAPI_PNF_PHY_RF_TAG); + + if(config->user_data != 0) + { + pnf_info_t* pnf = (pnf_info_t*)(config->user_data); + int i = 0; + for(i = 0; i < req->pnf_phy_rf_config.number_phy_rf_config_info; ++i) + { + pnf->phys[i].enabled = 1; + pnf->phys[i].phy_id = req->pnf_phy_rf_config.phy_rf_config[i].phy_id; + printf("test_pnf_config_request creating phy %d\n", pnf->phys[i].phy_id); + + } + } + + nfapi_pnf_config_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_CONFIG_RESPONSE; + resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_pnf_config_resp(config, &resp); + + test_config_request_called++; + return 0; +} +int test_pnf_start_request(nfapi_pnf_config_t* config, nfapi_pnf_start_request_t* req) +{ + printf("test_pnf_start_request called.... ;-)\n"); + + nfapi_pnf_start_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_START_RESPONSE; + resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_pnf_start_resp(config, &resp); + return 0; +} +int test_pnf_stop_request(nfapi_pnf_config_t* config, nfapi_pnf_stop_request_t* req) +{ + printf("test_pnf_stop_request called.... ;-)\n"); + + nfapi_pnf_stop_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_STOP_RESPONSE; + resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_pnf_stop_resp(config, &resp); + return 0; +} +int test_param_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_param_request_t* req) +{ + printf("test_param_request called.... ;-)\n"); + + nfapi_param_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PARAM_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_MSG_OK; + + if(config->user_data != 0) + { + phy_info_t* phy_info = find_phy_info((pnf_info_t*)(config->user_data), req->header.phy_id); + + resp.nfapi_config.p7_pnf_port.tl.tag = NFAPI_NFAPI_P7_PNF_PORT_TAG; + resp.nfapi_config.p7_pnf_port.value = phy_info->pnf_p7_port; + resp.num_tlv++; + + resp.nfapi_config.p7_pnf_address_ipv4.tl.tag = NFAPI_NFAPI_P7_PNF_PORT_TAG; + struct sockaddr_in pnf_p7_sockaddr; + pnf_p7_sockaddr.sin_addr.s_addr = inet_addr(phy_info->pnf_p7_addr); + memcpy(&(resp.nfapi_config.p7_pnf_address_ipv4.address[0]), &pnf_p7_sockaddr.sin_addr.s_addr, 4); + resp.num_tlv++; + } + + + + + nfapi_pnf_param_resp(config, &resp); + return 0; +} +int test_config_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_config_request_t* req) +{ + printf("test_config_request called.... ;-)\n"); + + if(config->user_data != 0) + { + phy_info_t* phy_info = find_phy_info((pnf_info_t*)(config->user_data), req->header.phy_id); + + if(req->nfapi_config.p7_vnf_port.tl.tag == NFAPI_NFAPI_P7_VNF_PORT_TAG) + { + phy_info->vnf_p7_port = req->nfapi_config.p7_vnf_port.value; + printf("vnf_p7_port %d\n", phy_info->vnf_p7_port); + } + + if(req->nfapi_config.p7_vnf_address_ipv4.tl.tag == NFAPI_NFAPI_P7_VNF_ADDRESS_IPV4_TAG) + { + struct sockaddr_in addr; + memcpy(&addr.sin_addr.s_addr, req->nfapi_config.p7_vnf_address_ipv4.address, 4); + char* ip = inet_ntoa(addr.sin_addr); + phy_info->vnf_p7_addr = ip; + printf("vnf_p7_addr %s\n", phy_info->vnf_p7_addr); + } + + + } + + nfapi_config_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_CONFIG_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_config_resp(config, &resp); + return 0; +} +int test_dl_config_req(nfapi_pnf_p7_config_t* config, nfapi_dl_config_request_t* req) +{ + printf("test_dl_config_req called.... ;-)\n"); + return 0; +} + +int test_ul_config_req(nfapi_pnf_p7_config_t* config, nfapi_ul_config_request_t* req) +{ + printf("test_ul_config_req called.... ;-)\n"); + return 0; +} +int test_hi_dci0_req(nfapi_pnf_p7_config_t* config, nfapi_hi_dci0_request_t* req) +{ + printf("test_hi_dci0_req called.... ;-)\n"); + return 0; +} +int test_tx_req(nfapi_pnf_p7_config_t* config, nfapi_tx_request_t* req) +{ + printf("test_tx_req called.... ;-)\n"); + return 0; +} +int test_lbt_dl_config_req(nfapi_pnf_p7_config_t* config, nfapi_lbt_dl_config_request_t* req) +{ + printf("test_lbt_dl_req called.... ;-)\n"); + return 0; +} +int test_start_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_start_request_t* req) +{ + printf("test_start_request called.... ;-)\n"); + + + if(config->user_data != 0) + { + phy_info_t* phy_info = find_phy_info((pnf_info_t*)(config->user_data), req->header.phy_id); + + phy_info->config = nfapi_pnf_p7_config_create(); + phy_info->config->local_p7_port = phy_info->pnf_p7_port; + + phy_info->config->remote_p7_port = phy_info->vnf_p7_port; + phy_info->config->remote_p7_addr = phy_info->vnf_p7_addr; + + phy_info->config->dl_config_req = &test_dl_config_req; + phy_info->config->ul_config_req = &test_ul_config_req; + phy_info->config->hi_dci0_req = &test_hi_dci0_req; + phy_info->config->tx_req = &test_tx_req; + phy_info->config->lbt_dl_config_req = &test_lbt_dl_config_req; + + //phy_info->config->subframe_buffer_size = 8; + //phy_info->config->timing_info_mode_periodic = 1; + //phy_info->config->timing_info_period = 32; + //phy_info->config->timing_info_mode_aperiodic = 1; + + phy_info->config->segment_size = 1400; + phy_info->config->checksum_enabled = 0; + + + pthread_create(&phy_info->thread, NULL, &pnf_test_start_p7_thread, phy_info->config); + } + + nfapi_start_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_START_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_start_resp(config, &resp); + return 0; +} +int test_stop_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_stop_request_t* req) +{ + printf("test_stop_request called.... ;-)\n"); + + nfapi_stop_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_STOP_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_stop_resp(config, &resp); + return 0; +} + +int send_p5_message(int p5Sock, nfapi_p4_p5_message_header_t* msg, unsigned msg_size, struct sockaddr* addr, socklen_t addr_size) +{ + char buffer[256]; + int encoded_size = nfapi_p5_message_pack(msg, msg_size, buffer, sizeof(buffer), 0); + int result = sendto(p5Sock, buffer, encoded_size, 0, addr, addr_size); + return result; +} + +int send_p7_message(int p7Sock, nfapi_p7_message_header_t* msg, unsigned msg_size, struct sockaddr_in* addr, socklen_t addr_size) +{ + char buffer[256]; + int encoded_size = nfapi_p7_message_pack(msg, buffer, sizeof(buffer), 0); + int result = sendto(p7Sock, buffer, encoded_size, 0, (struct sockaddr*)addr, addr_size); + + printf("send_p7_message result %d\n", result); + return result; +} +int send_p7_segmented_message(int p7Sock, nfapi_p7_message_header_t* msg, unsigned msg_size, struct sockaddr_in* addr, socklen_t addr_size) +{ + char buffer[1024 * 10]; + int encoded_size = nfapi_p7_message_pack(msg, buffer, sizeof(buffer), 0); + + uint16_t segment_size = 256; + + if(encoded_size < segment_size) + { + int result = sendto(p7Sock, buffer, encoded_size, 0, (struct sockaddr*)addr, addr_size); + return result; + } + else + { + // printf("Segmenting p7 message %d\n", encoded_size); + + uint8_t segment_count = 0; + uint8_t buffer2[segment_size]; + uint32_t offset = 0; + uint16_t msg_size; + //uint8_t m = 1; + + do{ + + if(segment_count == 0) + { + msg_size = segment_size; + memcpy(&buffer2[0], &buffer[0], msg_size); + // M = 1 + buffer2[6] = (1 << 7) | (segment_count & 0x7F); + + offset = msg_size; + } + else + { + memcpy(&buffer2[0], &buffer[0], NFAPI_P7_HEADER_LENGTH); + + if(encoded_size - offset > segment_size) + { + // M = 1 + buffer2[6] = (1 << 7) | (segment_count & 0x7F); + msg_size = segment_size; + } + else + { + // M = 0 + buffer2[6] = (0 << 7) | (segment_count & 0x7F); + msg_size = encoded_size - offset + NFAPI_P7_HEADER_LENGTH; + } + + + memcpy(&buffer2[NFAPI_P7_HEADER_LENGTH], &buffer[offset], msg_size - NFAPI_P7_HEADER_LENGTH); + + offset += msg_size - NFAPI_P7_HEADER_LENGTH; + } + + uint8_t* p = &buffer2[4]; + push16(msg_size, &p, &buffer2[segment_size]); + + //printf("Segmenting p7 message %d %di %d\n", segment_count, msg_size, offset); + /*int result = */sendto(p7Sock, buffer2, msg_size, 0, (struct sockaddr*)addr, addr_size); + + segment_count++; + + }while(offset < encoded_size); + + } + + return 0; +} +int send_p7_segmented_message_outoforder(int p7Sock, nfapi_p7_message_header_t* msg, unsigned msg_size, struct sockaddr_in* addr, socklen_t addr_size) +{ + char buffer[1024 * 10]; + int encoded_size = nfapi_p7_message_pack(msg, buffer, sizeof(buffer), 0); + + uint16_t segment_size = 256; + + if(encoded_size < segment_size) + { + int result = sendto(p7Sock, buffer, encoded_size, 0, (struct sockaddr*)addr, addr_size); + return result; + } + else + { + // printf("Segmenting p7 message %d\n", encoded_size); + + uint8_t segment_count = 0; + uint8_t buffer2[128][segment_size]; + uint32_t offset = 0; + uint16_t msg_size[128]; + uint8_t i = 0; + + do{ + + if(segment_count == 0) + { + msg_size[i] = segment_size; + memcpy(&buffer2[i][0], &buffer[0], msg_size[i]); + // M = 1 + buffer2[i][6] = (1 << 7) | (segment_count & 0x7F); + + offset = msg_size[i]; + } + else + { + memcpy(&buffer2[i][0], &buffer[0], NFAPI_P7_HEADER_LENGTH); + + if(encoded_size - offset > segment_size) + { + // M = 1 + buffer2[i][6] = (1 << 7) | (segment_count & 0x7F); + msg_size[i] = segment_size; + } + else + { + // M = 0 + buffer2[i][6] = (0 << 7) | (segment_count & 0x7F); + msg_size[i] = encoded_size - offset + NFAPI_P7_HEADER_LENGTH; + } + + + memcpy(&buffer2[i][NFAPI_P7_HEADER_LENGTH], &buffer[offset], msg_size[i] - NFAPI_P7_HEADER_LENGTH); + + offset += msg_size[i] - NFAPI_P7_HEADER_LENGTH; + } + + uint8_t* p = &buffer2[i][4]; + push16(msg_size[i], &p, &buffer2[i][segment_size]); + + + segment_count++; + i++; + + }while(offset < encoded_size); + + // send all odd then send event + uint8_t e = 0; + uint8_t o = 1; + while(o <= i) + { + sendto(p7Sock, &buffer2[o][0], msg_size[o], 0, (struct sockaddr*)addr, addr_size); + o += 2; + } + while(e <= i) + { + sendto(p7Sock, &buffer2[e][0], msg_size[e], 0, (struct sockaddr*)addr, addr_size); + e += 2; + } + + } + + return 0; +} + +int get_p7_segmented_message(int p7Sock, nfapi_p7_message_header_t* msg, unsigned _msg_size, struct sockaddr_in* addr, socklen_t addr_size, uint8_t (buffer2)[][256], uint16_t msg_size[256], uint8_t i) +{ + char buffer[1024 * 10]; + int encoded_size = nfapi_p7_message_pack(msg, buffer, sizeof(buffer), 0); + + uint16_t segment_size = 256; + + printf("get_p7_segmented_message size %d\n", encoded_size); + + if(encoded_size < segment_size) + { + msg_size[i] = encoded_size; + memcpy(&buffer2[i][0], &buffer[0], msg_size[i]); + i++; + } + else + { + uint8_t segment_count = 0; + uint32_t offset = 0; + + do{ + + if(segment_count == 0) + { + msg_size[i] = segment_size; + memcpy(&buffer2[i][0], &buffer[0], msg_size[i]); + // M = 1 + (buffer2[i][6]) = (1 << 7) | (segment_count & 0x7F); + + offset = msg_size[i]; + } + else + { + memcpy(&buffer2[i][0], &buffer[0], NFAPI_P7_HEADER_LENGTH); + + if(encoded_size - offset > segment_size) + { + // M = 1 + (buffer2[i][6]) = (1 << 7) | (segment_count & 0x7F); + msg_size[i] = segment_size; + } + else + { + // M = 0 + (buffer2[i][6]) = (0 << 7) | (segment_count & 0x7F); + msg_size[i] = encoded_size - offset + NFAPI_P7_HEADER_LENGTH; + } + + + memcpy(&buffer2[i][NFAPI_P7_HEADER_LENGTH], &buffer[offset], msg_size[i] - NFAPI_P7_HEADER_LENGTH); + + offset += msg_size[i] - NFAPI_P7_HEADER_LENGTH; + } + + uint8_t* p = &buffer2[i][4]; + push16(msg_size[i], &p, &buffer2[i][segment_size]); + + + segment_count++; + i++; + + }while(offset < encoded_size); + + } + + return i; +} + + +int recv_p5_message(int p5Sock, nfapi_p4_p5_message_header_t* msg, unsigned msg_size) +{ + //struct sockaddr_in addr2; + //socklen_t addr2len; + char buffer2[1024]; + int result2 = recv(p5Sock, buffer2, sizeof(buffer2), 0); //, (struct sockaddr*)&addr2, &addr2len); + + if(result2 == -1) + { + printf("%s recvfrom failed errno:%d\n", __FUNCTION__, errno); + } + else + { + /*int unpack_result =*/ nfapi_p5_message_unpack(buffer2, result2, msg, msg_size, 0); //, sizeof(resp)); + } + return 0; +} + +int recv_p7_message(int p7Sock, nfapi_p7_message_header_t* msg, unsigned msg_size) +{ + char buffer2[2560]; + int result2 = recvfrom(p7Sock, buffer2, sizeof(buffer2), 0, 0, 0); + + if(result2 == -1) + { + printf("%s recvfrom failed errno:%d\n", __FUNCTION__, errno); + } + else + { + /*int unpack_result =*/ nfapi_p7_message_unpack(buffer2, result2, msg, msg_size, 0); //, sizeof(resp)); + } + return 0; +} + +int send_pnf_param_request(int p5Sock, struct sockaddr* addr, socklen_t addr_size) +{ + printf("%s\n", __FUNCTION__); + nfapi_pnf_param_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PNF_PARAM_REQUEST; + req.header.message_length = 0; + + send_p5_message(p5Sock, &(req.header), sizeof(req), addr, addr_size); + return 0; +} + +int receive_pnf_param_response(int p5Sock, uint8_t error_code) +{ + nfapi_pnf_param_response_t resp; + recv_p5_message(p5Sock, &(resp.header), sizeof(resp)); + + printf("0x%x\n", resp.header.message_id); + CU_ASSERT_EQUAL(resp.header.message_id, NFAPI_PNF_PARAM_RESPONSE); + if(resp.header.message_id == NFAPI_PNF_PARAM_RESPONSE) + { + printf("decoded nfapi_pnf_param_response\n"); + CU_ASSERT_EQUAL(resp.error_code, error_code); + if(error_code == NFAPI_MSG_OK) + { + CU_ASSERT_EQUAL(resp.pnf_param_general.tl.tag, NFAPI_PNF_PARAM_GENERAL_TAG); + CU_ASSERT_EQUAL(resp.pnf_param_general.nfapi_sync_mode, 2); + CU_ASSERT_EQUAL(resp.pnf_param_general.location_mode, 1); + } + } + return 0; +} + +int send_pnf_config_request(int p5Sock, struct sockaddr* addr, socklen_t addr_size) +{ + nfapi_pnf_config_request_t req; + req.header.message_id = NFAPI_PNF_CONFIG_REQUEST; + req.header.message_length = 0; + + req.pnf_phy_rf_config.tl.tag = NFAPI_PNF_PHY_RF_TAG; + req.pnf_phy_rf_config.number_phy_rf_config_info = 1; + req.pnf_phy_rf_config.phy_rf_config[0].phy_id = 0; + + send_p5_message(p5Sock, &(req.header), sizeof(req), addr, addr_size); + return 0; +} + +int receive_pnf_config_response(int p5Sock) +{ + nfapi_pnf_config_response_t resp; + recv_p5_message(p5Sock, &(resp.header), sizeof(resp)); + + CU_ASSERT_EQUAL(resp.header.message_id, NFAPI_PNF_CONFIG_RESPONSE); + if(resp.header.message_id == NFAPI_PNF_CONFIG_RESPONSE) + { + printf("decoded nfapi_pnf_config_response\n"); + } + return 0; +} + +void send_pnf_start_request(int p5Sock, struct sockaddr* addr, socklen_t addr_size) +{ + nfapi_pnf_start_request_t req; + req.header.message_id = NFAPI_PNF_START_REQUEST; + req.header.message_length = 0; + + send_p5_message(p5Sock, &(req.header), sizeof(req), addr, addr_size); +} + +void receive_pnf_start_response(int p5Sock) +{ + nfapi_pnf_start_response_t resp; + recv_p5_message(p5Sock, &(resp.header), sizeof(resp)); + + CU_ASSERT_EQUAL(resp.header.message_id, NFAPI_PNF_START_RESPONSE); + if(resp.header.message_id == NFAPI_PNF_START_RESPONSE) + { + printf("decoded nfapi_pnf_start_response\n"); + } +} + +void send_pnf_stop_request(int p5Sock, struct sockaddr* addr, socklen_t addr_size) +{ + nfapi_pnf_stop_request_t req; + req.header.message_id = NFAPI_PNF_STOP_REQUEST; + req.header.message_length = 0; + + send_p5_message(p5Sock, &(req.header), sizeof(req), addr, addr_size); +} + +void receive_pnf_stop_response(int p5Sock) +{ + nfapi_pnf_stop_response_t resp; + recv_p5_message(p5Sock, &(resp.header), sizeof(resp)); + + CU_ASSERT_EQUAL(resp.header.message_id, NFAPI_PNF_STOP_RESPONSE); + if(resp.header.message_id == NFAPI_PNF_STOP_RESPONSE) + { + printf("decoded nfapi_pnf_stop_response\n"); + } +} + +void send_param_request(int p5Sock, int phy_id, struct sockaddr* addr, socklen_t addr_size) +{ + nfapi_param_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PARAM_REQUEST; + req.header.phy_id = phy_id; + + send_p5_message(p5Sock, &(req.header), sizeof(req), addr, addr_size); +} +void receive_param_response(int p5Sock) +{ + nfapi_pnf_stop_response_t resp; + recv_p5_message(p5Sock, &(resp.header), sizeof(resp)); + + CU_ASSERT_EQUAL(resp.header.message_id, NFAPI_PARAM_RESPONSE); + if(resp.header.message_id == NFAPI_PARAM_RESPONSE) + { + printf("decoded nfapi_param_response\n"); + } +} +void send_config_request(int p5Sock, int phy_id, struct sockaddr* addr, socklen_t addr_size, pnf_info_t* pnf_info) +{ + nfapi_config_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_CONFIG_REQUEST; + req.header.phy_id = phy_id; + + phy_info_t* phy_info = find_phy_info(pnf_info, phy_id); + + req.nfapi_config.p7_vnf_port.tl.tag = NFAPI_NFAPI_P7_VNF_PORT_TAG; + req.nfapi_config.p7_vnf_port.value = phy_info->vnf_p7_port; + req.num_tlv++; + + //req.nfapi_config.p7_vnf_address_ipv4.tl.tag = NFAPI_NFAPI_P7_VNF_ADDRESS_IPV4_TAG; + //req.num_tlv++; + + send_p5_message(p5Sock, &(req.header), sizeof(req), addr, addr_size); +} +void receive_config_response(int p5Sock) +{ + nfapi_pnf_stop_response_t resp; + recv_p5_message(p5Sock, &(resp.header), sizeof(resp)); + + CU_ASSERT_EQUAL(resp.header.message_id, NFAPI_CONFIG_RESPONSE); + if(resp.header.message_id == NFAPI_CONFIG_RESPONSE) + { + printf("decoded nfapi_config_response\n"); + } +} +void send_start_request(int p5Sock, int phy_id, struct sockaddr* addr, socklen_t addr_size) +{ + nfapi_start_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_START_REQUEST; + req.header.phy_id = phy_id; + + send_p5_message(p5Sock, &(req.header), sizeof(req), addr, addr_size); +} +void receive_start_response(int p5Sock) +{ + nfapi_pnf_start_response_t resp; + recv_p5_message(p5Sock, &(resp.header), sizeof(resp)); + + CU_ASSERT_EQUAL(resp.header.message_id, NFAPI_START_RESPONSE); + if(resp.header.message_id == NFAPI_START_RESPONSE) + { + printf("decoded nfapi_start_response\n"); + } +} +void send_stop_request(int p5Sock, int phy_id, struct sockaddr* addr, socklen_t addr_size) +{ + nfapi_start_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_STOP_REQUEST; + req.header.phy_id = phy_id; + + send_p5_message(p5Sock, &(req.header), sizeof(req), addr, addr_size); +} + +void receive_stop_response(int p5Sock) +{ + nfapi_pnf_stop_response_t resp; + recv_p5_message(p5Sock, &(resp.header), sizeof(resp)); + + CU_ASSERT_EQUAL(resp.header.message_id, NFAPI_STOP_RESPONSE); + if(resp.header.message_id == NFAPI_STOP_RESPONSE) + { + printf("decoded nfapi_stop_response\n"); + } +} + +void send_dl_node_sync(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size) +{ + nfapi_dl_node_sync_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_DL_NODE_SYNC; + req.header.phy_id = phy_id; + req.t1 = 1977; + req.delta_sfn_sf = 5000; + + send_p7_message(p7Sock, &(req.header), sizeof(req), addr, addr_size); +} +void receive_ul_node_sync(int p7Sock) +{ + nfapi_ul_node_sync_t sync; + recv_p7_message(p7Sock, &(sync.header), sizeof(sync)); + + CU_ASSERT_EQUAL(sync.header.message_id, NFAPI_UL_NODE_SYNC); + if(sync.header.message_id == NFAPI_UL_NODE_SYNC) + { + printf("decoded nfapi_ul_node_sync t1:%d t2:%d t3:%d\n", + sync.t1, sync.t2, sync.t3); + } +} + +void receive_timing_info(int p7Sock) +{ + nfapi_timing_info_t timing_info; + recv_p7_message(p7Sock, &(timing_info.header), sizeof(timing_info)); + + CU_ASSERT_EQUAL(timing_info.header.message_id, NFAPI_TIMING_INFO); + if(timing_info.header.message_id == NFAPI_TIMING_INFO) + { + printf("decoded nfapi_timing_info\n"); + } + else + { + printf("decoded ?? 0x%x\n", timing_info.header.message_id); + } +} +void send_dl_config_req(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size, uint16_t sfn_sf) +{ + nfapi_dl_config_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_DL_CONFIG_REQUEST; + req.header.phy_id = phy_id; + req.sfn_sf = sfn_sf; + + send_p7_message(p7Sock, &(req.header), sizeof(req), addr, addr_size); +} +void send_ul_config_req(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size, uint16_t sfn_sf) +{ + nfapi_ul_config_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_UL_CONFIG_REQUEST; + req.header.phy_id = phy_id; + req.sfn_sf = sfn_sf; + + send_p7_message(p7Sock, &(req.header), sizeof(req), addr, addr_size); +} +void send_hi_dci0_req(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size, uint16_t sfn_sf) +{ + nfapi_hi_dci0_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_HI_DCI0_REQUEST; + req.header.phy_id = phy_id; + req.sfn_sf = sfn_sf; + + send_p7_message(p7Sock, &(req.header), sizeof(req), addr, addr_size); +} +void send_tx_req(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size, uint16_t sfn_sf) +{ + nfapi_tx_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_TX_REQUEST; + req.header.phy_id = phy_id; + req.sfn_sf = sfn_sf; + send_p7_message(p7Sock, &(req.header), sizeof(req), addr, addr_size); +} + +void send_tx_req_1(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size, uint16_t sfn_sf) +{ + nfapi_tx_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_TX_REQUEST; + req.header.phy_id = phy_id; + req.sfn_sf = sfn_sf; + req.tx_request_body.tl.tag = NFAPI_TX_REQUEST_BODY_TAG; + req.tx_request_body.number_of_pdus = 8; + req.tx_request_body.tx_pdu_list = (nfapi_tx_request_pdu_t*)(malloc(sizeof(nfapi_tx_request_t) * 8)); + uint8_t i = 0; + uint8_t test_pdu[1200]; + + for(i = 0; i < 8; i++) + { + req.tx_request_body.tx_pdu_list[i].pdu_length = sizeof(test_pdu); + req.tx_request_body.tx_pdu_list[i].pdu_index = i; + req.tx_request_body.tx_pdu_list[i].num_segments =1; + req.tx_request_body.tx_pdu_list[i].segments[0].segment_length = sizeof(test_pdu); + req.tx_request_body.tx_pdu_list[i].segments[0].segment_data = (void*)&test_pdu; + } + + send_p7_segmented_message(p7Sock, &(req.header), sizeof(req), addr, addr_size); + + free(req.tx_request_body.tx_pdu_list); + +} + +void send_tx_req_2(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size, uint16_t sfn_sf) +{ + nfapi_tx_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_TX_REQUEST; + req.header.phy_id = phy_id; + req.sfn_sf = sfn_sf; + req.tx_request_body.tl.tag = NFAPI_TX_REQUEST_BODY_TAG; + req.tx_request_body.number_of_pdus = 8; + req.tx_request_body.tx_pdu_list = (nfapi_tx_request_pdu_t*)(malloc(sizeof(nfapi_tx_request_t) * 8)); + uint8_t i = 0; + uint8_t test_pdu[1200]; + + for(i = 0; i < 8; i++) + { + req.tx_request_body.tx_pdu_list[i].pdu_length = sizeof(test_pdu); + req.tx_request_body.tx_pdu_list[i].pdu_index = i; + req.tx_request_body.tx_pdu_list[i].num_segments =1; + req.tx_request_body.tx_pdu_list[i].segments[0].segment_length = sizeof(test_pdu); + req.tx_request_body.tx_pdu_list[i].segments[0].segment_data = (void*)&test_pdu; + } + + send_p7_segmented_message_outoforder(p7Sock, &(req.header), sizeof(req), addr, addr_size); + + free(req.tx_request_body.tx_pdu_list); + +} +void send_dl_subframe_msgs_interleaved(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size, uint16_t sfn_sf) +{ + + uint8_t buffer[256][256]; + uint16_t msg_size[256]; + uint16_t count = 0; + + { + nfapi_dl_config_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_DL_CONFIG_REQUEST; + req.header.phy_id = phy_id; + req.header.m_segment_sequence = 34; + req.sfn_sf = sfn_sf; + req.dl_config_request_body.tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + req.dl_config_request_body.number_pdu = 8; + req.dl_config_request_body.dl_config_pdu_list = (nfapi_dl_config_request_pdu_t*)malloc(sizeof(nfapi_dl_config_request_pdu_t) * 8); + + uint8_t i = 0; + for(i = 0; i < 8; i++) + { + nfapi_dl_config_request_pdu_t* pdu = &(req.dl_config_request_body.dl_config_pdu_list[i]); + pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; + } + + + count = get_p7_segmented_message(p7Sock, &(req.header), sizeof(req), addr, addr_size, buffer, msg_size, count); + } + + { + nfapi_ul_config_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_UL_CONFIG_REQUEST; + req.header.phy_id = phy_id; + req.header.m_segment_sequence = 35; + req.sfn_sf = sfn_sf; + + count = get_p7_segmented_message(p7Sock, &(req.header), sizeof(req), addr, addr_size, buffer, msg_size, count); + } + + { + nfapi_hi_dci0_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_HI_DCI0_REQUEST; + req.header.phy_id = phy_id; + req.header.m_segment_sequence = 36; + req.sfn_sf = sfn_sf; + count = get_p7_segmented_message(p7Sock, &(req.header), sizeof(req), addr, addr_size, buffer, msg_size, count); + } + + { + nfapi_tx_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_TX_REQUEST; + req.header.phy_id = phy_id; + req.header.m_segment_sequence = 37; + req.sfn_sf = sfn_sf; + req.tx_request_body.tl.tag = NFAPI_TX_REQUEST_BODY_TAG; + req.tx_request_body.number_of_pdus = 8; + req.tx_request_body.tx_pdu_list = (nfapi_tx_request_pdu_t*)(malloc(sizeof(nfapi_tx_request_t) * 8)); + uint8_t i = 0; + uint8_t test_pdu[1200]; + + for(i = 0; i < 8; i++) + { + req.tx_request_body.tx_pdu_list[i].pdu_length = sizeof(test_pdu); + req.tx_request_body.tx_pdu_list[i].pdu_index = i; + req.tx_request_body.tx_pdu_list[i].num_segments =1; + req.tx_request_body.tx_pdu_list[i].segments[0].segment_length = sizeof(test_pdu); + req.tx_request_body.tx_pdu_list[i].segments[0].segment_data = (void*)&test_pdu; + } + + count = get_p7_segmented_message(p7Sock, &(req.header), sizeof(req), addr, addr_size, buffer, msg_size, count); + } + + // send all odd then send event + uint8_t e = 0; + uint8_t o = 1; + while(o <= count) + { + if(msg_size[o] == 0) + printf("**** Sending a zero length msg %d\n", o); + sendto(p7Sock, &buffer[o][0], msg_size[o], 0, (struct sockaddr*)addr, addr_size); + o += 2; + } + while(e <= count) + { + if(msg_size[e] == 0) + printf("**** Sending a zero length msg %d\n", e); + + sendto(p7Sock, &buffer[e][0], msg_size[e], 0, (struct sockaddr*)addr, addr_size); + e += 2; + } + //free(req.tx_request_body.tx_pdu_list); +} + +void send_subframe_indication(phy_info_t* phy_info) +{ + nfapi_pnf_p7_subframe_ind(phy_info->config, phy_info->phy_id, phy_info->sfn_sf); +} + +void send_harq_ind(phy_info_t* phy_info, uint16_t sfn_sf) +{ + nfapi_harq_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_HARQ_INDICATION; + ind.header.phy_id = phy_info->phy_id; + ind.sfn_sf = sfn_sf; + + nfapi_pnf_p7_harq_ind((phy_info->config), &ind); +} +void recieve_harq_ind(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size) +{ + nfapi_harq_indication_t ind; + recv_p7_message(p7Sock, &(ind.header), sizeof(ind)); + + CU_ASSERT_EQUAL(ind.header.message_id, NFAPI_HARQ_INDICATION); + if(ind.header.message_id == NFAPI_HARQ_INDICATION) + { + printf("decoded nfapi_harq_indication\n"); + } + else + { + printf("decoded ?? 0x%x\n", ind.header.message_id); + } +} + +void send_crc_ind(phy_info_t* phy_info, uint16_t sfn_sf) +{ + nfapi_crc_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_CRC_INDICATION; + ind.header.phy_id = phy_info->phy_id; + ind.sfn_sf = sfn_sf; + + nfapi_pnf_p7_crc_ind((phy_info->config), &ind); + +} +void recieve_crc_ind(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size) +{ + nfapi_crc_indication_t ind; + recv_p7_message(p7Sock, &(ind.header), sizeof(ind)); + + CU_ASSERT_EQUAL(ind.header.message_id, NFAPI_CRC_INDICATION); + if(ind.header.message_id == NFAPI_CRC_INDICATION) + { + printf("decoded nfapi_crc_indication\n"); + } +} + +void send_rx_ind(phy_info_t* phy_info, uint16_t sfn_sf) +{ + nfapi_rx_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_RX_ULSCH_INDICATION; + ind.header.phy_id = phy_info->phy_id; + ind.sfn_sf = sfn_sf; + + nfapi_pnf_p7_rx_ind((phy_info->config), &ind); +} +void recieve_rx_ind(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size) +{ + nfapi_rx_indication_t ind; + recv_p7_message(p7Sock, &(ind.header), sizeof(ind)); + + CU_ASSERT_EQUAL(ind.header.message_id, NFAPI_RX_ULSCH_INDICATION); + if(ind.header.message_id == NFAPI_RX_ULSCH_INDICATION) + { + printf("decoded nfapi_rx_indication\n"); + } +} + +void send_rach_ind(phy_info_t* phy_info, uint16_t sfn_sf) +{ + nfapi_rach_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_RACH_INDICATION; + ind.header.phy_id = phy_info->phy_id; + ind.sfn_sf = sfn_sf; + + nfapi_pnf_p7_rach_ind((phy_info->config), &ind); +} +void recieve_rach_ind(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size) +{ + nfapi_rach_indication_t ind; + recv_p7_message(p7Sock, &(ind.header), sizeof(ind)); + + CU_ASSERT_EQUAL(ind.header.message_id, NFAPI_RACH_INDICATION); + if(ind.header.message_id == NFAPI_RACH_INDICATION) + { + printf("decoded nfapi_rach_indication\n"); + } +} + +void send_srs_ind(phy_info_t* phy_info, uint16_t sfn_sf) +{ + nfapi_srs_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_SRS_INDICATION; + ind.header.phy_id = phy_info->phy_id; + ind.sfn_sf = sfn_sf; + + nfapi_pnf_p7_srs_ind((phy_info->config), &ind); +} +void recieve_srs_ind(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size) +{ + nfapi_srs_indication_t ind; + recv_p7_message(p7Sock, &(ind.header), sizeof(ind)); + + CU_ASSERT_EQUAL(ind.header.message_id, NFAPI_SRS_INDICATION); + if(ind.header.message_id == NFAPI_SRS_INDICATION) + { + printf("decoded nfapi_srs_indication\n"); + } +} + +void send_sr_ind(phy_info_t* phy_info, uint16_t sfn_sf) +{ + nfapi_sr_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_RX_SR_INDICATION; + ind.header.phy_id = phy_info->phy_id; + ind.sfn_sf = sfn_sf; + + nfapi_pnf_p7_sr_ind((phy_info->config), &ind); +} +void recieve_sr_ind(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size) +{ + nfapi_sr_indication_t ind; + recv_p7_message(p7Sock, &(ind.header), sizeof(ind)); + + CU_ASSERT_EQUAL(ind.header.message_id, NFAPI_RX_SR_INDICATION); + if(ind.header.message_id == NFAPI_RX_SR_INDICATION) + { + printf("decoded nfapi_sr_indication\n"); + } +} + +void send_cqi_ind(phy_info_t* phy_info, uint16_t sfn_sf) +{ + nfapi_cqi_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_RX_CQI_INDICATION; + ind.header.phy_id = phy_info->phy_id; + ind.sfn_sf = sfn_sf; + + nfapi_pnf_p7_cqi_ind((phy_info->config), &ind); +} +void recieve_cqi_ind(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size) +{ + nfapi_cqi_indication_t ind; + recv_p7_message(p7Sock, &(ind.header), sizeof(ind)); + + CU_ASSERT_EQUAL(ind.header.message_id, NFAPI_RX_CQI_INDICATION); + if(ind.header.message_id == NFAPI_RX_CQI_INDICATION) + { + printf("decoded nfapi_cqi_indication\n"); + } +} + +void send_lbt_dl_ind(phy_info_t* phy_info, uint16_t sfn_sf) +{ + nfapi_lbt_dl_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_LBT_DL_INDICATION; + ind.header.phy_id = phy_info->phy_id; + ind.sfn_sf = sfn_sf; + + nfapi_pnf_p7_lbt_dl_ind((phy_info->config), &ind); +} +void recieve_lbt_dl_ind(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size) +{ + nfapi_lbt_dl_indication_t ind; + recv_p7_message(p7Sock, &(ind.header), sizeof(ind)); + + CU_ASSERT_EQUAL(ind.header.message_id, NFAPI_LBT_DL_INDICATION); + if(ind.header.message_id == NFAPI_LBT_DL_INDICATION) + { + printf("decoded nfapi_lbt_dl_indication\n"); + } +} + +void send_nb_harq_ind(phy_info_t* phy_info, uint16_t sfn_sf) +{ + nfapi_nb_harq_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_NB_HARQ_INDICATION; + ind.header.phy_id = phy_info->phy_id; + ind.sfn_sf = sfn_sf; + + nfapi_pnf_p7_nb_harq_ind((phy_info->config), &ind); +} +void recieve_nb_harq_ind(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size) +{ + nfapi_nb_harq_indication_t ind; + recv_p7_message(p7Sock, &(ind.header), sizeof(ind)); + + CU_ASSERT_EQUAL(ind.header.message_id, NFAPI_NB_HARQ_INDICATION); + if(ind.header.message_id == NFAPI_NB_HARQ_INDICATION) + { + printf("decoded nfapi_nb_harq_indication\n"); + } +} + +void send_nrach_ind(phy_info_t* phy_info, uint16_t sfn_sf) +{ + nfapi_nrach_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_NRACH_INDICATION; + ind.header.phy_id = phy_info->phy_id; + ind.sfn_sf = sfn_sf; + + nfapi_pnf_p7_nrach_ind((phy_info->config), &ind); +} +void recieve_nrach_ind(int p7Sock, int phy_id, struct sockaddr_in* addr, socklen_t addr_size) +{ + nfapi_nrach_indication_t ind; + recv_p7_message(p7Sock, &(ind.header), sizeof(ind)); + + CU_ASSERT_EQUAL(ind.header.message_id, NFAPI_NRACH_INDICATION); + if(ind.header.message_id == NFAPI_NRACH_INDICATION) + { + printf("decoded nfapi_nrach_indication\n"); + } +} + +void pnf_test_start_connect(void) +{ + pnf_info_t pnf_info; + pnf_info.num_phys = 1; + pnf_info.phys[0].pnf_p7_port = 9345; + pnf_info.phys[0].pnf_p7_addr = "127.0.0.1"; + pnf_info.phys[0].vnf_p7_port = 8875; + pnf_info.phys[0].vnf_p7_addr = "127.0.0.1"; + + char* vnf_addr = "127.0.0.1"; + int vnf_port = 6699; + + int p5ListenSock = create_p5_listen_socket(vnf_addr, vnf_port); + printf("p5ListenSock %d %d\n", p5ListenSock, errno); + listen(p5ListenSock, 2); + + test_param_request_called = 0; + test_config_request_called = 0; + + nfapi_pnf_config_t* config = nfapi_pnf_config_create(); + config->vnf_ip_addr = vnf_addr; + config->vnf_p5_port = vnf_port; + config->pnf_param_req = &test_pnf_param_request; + config->pnf_config_req = &test_pnf_config_request; + config->pnf_start_req = &test_pnf_start_request; + config->pnf_stop_req = &test_pnf_stop_request; + config->param_req = &test_param_request; + config->config_req = &test_config_request; + config->start_req = &test_start_request; + config->stop_req = &test_stop_request; + + config->user_data = &pnf_info; + + pthread_t thread; + pthread_create(&thread, NULL, &pnf_test_start_thread, config); + + struct sockaddr_in addr; + socklen_t addrSize = sizeof(addr);; + int p5Sock = accept(p5ListenSock, (struct sockaddr *)&addr, &addrSize); + printf("p5 connection accepted %d %d\n", p5Sock, errno); + + send_pnf_param_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_param_response(p5Sock, NFAPI_MSG_OK); + + send_pnf_config_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_config_response(p5Sock); + + send_pnf_start_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_start_response(p5Sock); + + send_param_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize); + receive_param_response(p5Sock); + + + send_config_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize, &pnf_info); + receive_config_response(p5Sock); + + send_start_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize); + receive_start_response(p5Sock); + + sleep(2); + + int p7Sock = socket(AF_INET, SOCK_DGRAM, 0); + + { + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(pnf_info.phys[0].vnf_p7_port); + addr.sin_addr.s_addr = INADDR_ANY; + + bind(p7Sock, (struct sockaddr*)&addr, sizeof(addr)); + } + + printf("Sending p7 messages too %s:%d\n", pnf_info.phys[0].pnf_p7_addr, pnf_info.phys[0].pnf_p7_port); + + struct sockaddr_in p7_addr; + p7_addr.sin_family = AF_INET; + p7_addr.sin_port = htons(pnf_info.phys[0].pnf_p7_port); + p7_addr.sin_addr.s_addr = inet_addr(pnf_info.phys[0].pnf_p7_addr); + socklen_t p7_addrSize = sizeof(p7_addr); + + send_dl_node_sync(p7Sock, 0, &p7_addr, p7_addrSize); + receive_ul_node_sync(p7Sock); + + +#define SFNSF(_sfn, _sf) ((_sfn << 4) + _sf) + + uint16_t sfn_sf = SFNSF(500, 3); // sfn:500 sf:3 + pnf_info.phys[0].sfn_sf = sfn_sf; + send_subframe_indication(&(pnf_info.phys[0])); + + // should generate dummy messages + + usleep(500); + + sfn_sf = SFNSF(500, 4); // sfn:500 sf:4 + pnf_info.phys[0].sfn_sf = sfn_sf; + + send_dl_config_req(p7Sock, 0, &p7_addr, p7_addrSize, sfn_sf); + send_ul_config_req(p7Sock, 0, &p7_addr, p7_addrSize, sfn_sf); + send_hi_dci0_req(p7Sock, 0, &p7_addr, p7_addrSize, sfn_sf); + send_tx_req(p7Sock, 0, &p7_addr, p7_addrSize, sfn_sf); + + + usleep(500); + + send_subframe_indication(&(pnf_info.phys[0])); + // should send the cached messages + + send_harq_ind(&pnf_info.phys[0], sfn_sf); + recieve_harq_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_crc_ind(&pnf_info.phys[0], sfn_sf); + recieve_crc_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_rx_ind(&pnf_info.phys[0], sfn_sf); + recieve_rx_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_rach_ind(&pnf_info.phys[0], sfn_sf); + recieve_rach_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_srs_ind(&pnf_info.phys[0], sfn_sf); + recieve_srs_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_sr_ind(&pnf_info.phys[0], sfn_sf); + recieve_sr_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_cqi_ind(&pnf_info.phys[0], sfn_sf); + recieve_cqi_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_lbt_dl_ind(&pnf_info.phys[0], sfn_sf); + recieve_lbt_dl_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_nb_harq_ind(&pnf_info.phys[0], sfn_sf); + recieve_nb_harq_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_nrach_ind(&pnf_info.phys[0], sfn_sf); + recieve_nrach_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + + // send out of window dl_config, should expect the timing info + send_dl_config_req(p7Sock, 0, &p7_addr, p7_addrSize, SFNSF(600, 0)); + + sfn_sf = SFNSF(500, 5); // sfn:500 sf:4 + pnf_info.phys[0].sfn_sf = sfn_sf; + usleep(500); + + send_subframe_indication(&(pnf_info.phys[0])); + receive_timing_info(p7Sock); + + send_stop_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize); + receive_stop_response(p5Sock); + + + + send_pnf_stop_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_stop_response(p5Sock); + + nfapi_pnf_stop(config); + + int* result; + pthread_join(thread, (void**)&result); + //CU_ASSERT_NOT_EQUAL(*result, -1); + CU_ASSERT_EQUAL(test_param_request_called, 1); + CU_ASSERT_EQUAL(test_config_request_called, 1); + + close(p5Sock); + close(p5ListenSock); + +} +void pnf_test_start_connect_ipv6(void) +{ + pnf_info_t pnf_info; + pnf_info.num_phys = 1; + pnf_info.phys[0].pnf_p7_port = 9345; + pnf_info.phys[0].pnf_p7_addr = "::1"; + pnf_info.phys[0].vnf_p7_port = 8875; + pnf_info.phys[0].vnf_p7_addr = "::1"; + + char* vnf_addr = "::1"; + int vnf_port = 6698; + + int p5ListenSock = create_p5_ipv6_listen_socket(vnf_addr, vnf_port); + printf("p5ListenSock ipv6 %d %d\n", p5ListenSock, errno); + int listen_result = listen(p5ListenSock, 2); + printf("Listen result %d\n", listen_result); + + test_param_request_called = 0; + test_config_request_called = 0; + + nfapi_pnf_config_t* config = nfapi_pnf_config_create(); + config->vnf_ip_addr = vnf_addr; + config->vnf_p5_port = vnf_port; + config->pnf_param_req = &test_pnf_param_request; + config->pnf_config_req = &test_pnf_config_request; + config->pnf_start_req = &test_pnf_start_request; + config->pnf_stop_req = &test_pnf_stop_request; + config->param_req = &test_param_request; + config->config_req = &test_config_request; + config->start_req = &test_start_request; + config->stop_req = &test_stop_request; + + config->user_data = &pnf_info; + + pthread_t thread; + pthread_create(&thread, NULL, &pnf_test_start_thread, config); + + struct sockaddr_in6 addr; + socklen_t addrSize = sizeof(addr);; + int p5Sock = accept(p5ListenSock, (struct sockaddr *)&addr, &addrSize); + printf("p5 connection accepted %d %d\n", p5Sock, errno); + + send_pnf_param_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_param_response(p5Sock, NFAPI_MSG_OK); + + send_pnf_config_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_config_response(p5Sock); + + send_pnf_start_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_start_response(p5Sock); + + send_param_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize); + receive_param_response(p5Sock); +} + +void pnf_test_state_pnf_config_invalid_state() +{ + char* vnf_addr = "127.0.0.1"; + int vnf_port = 4546; + + int p5ListenSock = create_p5_listen_socket(vnf_addr, vnf_port); + + test_param_request_called = 0; + test_config_request_called = 0; + + nfapi_pnf_config_t* config = nfapi_pnf_config_create(); + config->vnf_ip_addr = vnf_addr; + config->vnf_p5_port = vnf_port; + config->pnf_param_req = &test_pnf_param_request; + config->pnf_config_req = &test_pnf_config_request; + + pthread_t thread; + pthread_create(&thread, NULL, &pnf_test_start_thread, config); + + listen(p5ListenSock, 2); + struct sockaddr_in addr; + socklen_t addrSize = sizeof(addr); + int p5Sock = accept(p5ListenSock, (struct sockaddr *)&addr, &addrSize); + printf("%s p5Sock %d errno %d\n", __FUNCTION__, p5Sock, errno); + + send_pnf_param_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_param_response(p5Sock, NFAPI_MSG_OK); + + send_pnf_config_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_config_response(p5Sock); + + send_pnf_param_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_param_response(p5Sock, NFAPI_MSG_INVALID_STATE); + + nfapi_pnf_stop(config); + + int* result; + pthread_join(thread, (void**)&result); + CU_ASSERT_EQUAL(result, 0); + CU_ASSERT_EQUAL(test_param_request_called, 1); + CU_ASSERT_EQUAL(test_config_request_called, 1); + + close(p5Sock); + close(p5ListenSock); + +} + +void pnf_test_state_pnf_param_invalid_state() +{ + pnf_info_t pnf_info; + + char* vnf_addr = "127.0.0.1"; + int vnf_port = 4547; + + int p5ListenSock = create_p5_listen_socket(vnf_addr, vnf_port); + + test_param_request_called = 0; + test_config_request_called = 0; + + nfapi_pnf_config_t* config = nfapi_pnf_config_create(); + config->vnf_ip_addr = vnf_addr; + config->vnf_p5_port = vnf_port; + config->pnf_param_req = &test_pnf_param_request; + config->pnf_config_req = &test_pnf_config_request; + + config->user_data = &pnf_info; + + pthread_t thread; + pthread_create(&thread, NULL, &pnf_test_start_thread, config); + + listen(p5ListenSock, 2); + struct sockaddr_in addr; + socklen_t addrSize = sizeof(addr); + int p5Sock = accept(p5ListenSock, (struct sockaddr *)&addr, &addrSize); + + send_pnf_param_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_param_response(p5Sock, NFAPI_MSG_OK); + + send_pnf_config_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_config_response(p5Sock); + + send_pnf_config_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_config_response(p5Sock); + + nfapi_pnf_stop(config); + + int* result; + pthread_join(thread, (void**)&result); + CU_ASSERT_EQUAL(result, 0); + CU_ASSERT_EQUAL(test_param_request_called, 1); + CU_ASSERT_EQUAL(test_config_request_called, 2); + + close(p5Sock); + close(p5ListenSock); + +} +void pnf_test_p7_segmentation_test_1(void) +{ + pnf_info_t pnf_info; + pnf_info.num_phys = 1; + pnf_info.phys[0].pnf_p7_port = 9348; + pnf_info.phys[0].pnf_p7_addr = "127.0.0.1"; + pnf_info.phys[0].vnf_p7_port = 8878; + pnf_info.phys[0].vnf_p7_addr = "127.0.0.1"; + + char* vnf_addr = "127.0.0.1"; + int vnf_port = 6699; + + int p5ListenSock = create_p5_listen_socket(vnf_addr, vnf_port); + printf("p5ListenSock %d %d\n", p5ListenSock, errno); + listen(p5ListenSock, 2); + + test_param_request_called = 0; + test_config_request_called = 0; + + nfapi_pnf_config_t* config = nfapi_pnf_config_create(); + config->vnf_ip_addr = vnf_addr; + config->vnf_p5_port = vnf_port; + config->pnf_param_req = &test_pnf_param_request; + config->pnf_config_req = &test_pnf_config_request; + config->pnf_start_req = &test_pnf_start_request; + config->pnf_stop_req = &test_pnf_stop_request; + config->param_req = &test_param_request; + config->config_req = &test_config_request; + config->start_req = &test_start_request; + config->stop_req = &test_stop_request; + + config->user_data = &pnf_info; + + pthread_t thread; + pthread_create(&thread, NULL, &pnf_test_start_thread, config); + + struct sockaddr_in addr; + socklen_t addrSize = sizeof(addr);; + int p5Sock = accept(p5ListenSock, (struct sockaddr *)&addr, &addrSize); + printf("p5 connection accepted %d %d\n", p5Sock, errno); + + send_pnf_param_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_param_response(p5Sock, NFAPI_MSG_OK); + + send_pnf_config_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_config_response(p5Sock); + + send_pnf_start_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_start_response(p5Sock); + + send_param_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize); + receive_param_response(p5Sock); + + + send_config_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize, &pnf_info); + receive_config_response(p5Sock); + + send_start_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize); + receive_start_response(p5Sock); + + sleep(2); + + int p7Sock = socket(AF_INET, SOCK_DGRAM, 0); + + { + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(pnf_info.phys[0].vnf_p7_port); + addr.sin_addr.s_addr = INADDR_ANY; + + bind(p7Sock, (struct sockaddr*)&addr, sizeof(addr)); + } + + printf("Sending p7 messages too %s:%d\n", pnf_info.phys[0].pnf_p7_addr, pnf_info.phys[0].pnf_p7_port); + + struct sockaddr_in p7_addr; + p7_addr.sin_family = AF_INET; + p7_addr.sin_port = htons(pnf_info.phys[0].pnf_p7_port); + p7_addr.sin_addr.s_addr = inet_addr(pnf_info.phys[0].pnf_p7_addr); + socklen_t p7_addrSize = sizeof(p7_addr); + + send_dl_node_sync(p7Sock, 0, &p7_addr, p7_addrSize); + receive_ul_node_sync(p7Sock); + + +#define SFNSF(_sfn, _sf) ((_sfn << 4) + _sf) + + uint16_t sfn_sf = SFNSF(500, 3); // sfn:500 sf:3 + pnf_info.phys[0].sfn_sf = sfn_sf; + send_subframe_indication(&(pnf_info.phys[0])); + + // should generate dummy messages + + usleep(500); + + sfn_sf = SFNSF(500, 4); // sfn:500 sf:4 + pnf_info.phys[0].sfn_sf = sfn_sf; + + send_dl_config_req(p7Sock, 0, &p7_addr, p7_addrSize, sfn_sf); + send_ul_config_req(p7Sock, 0, &p7_addr, p7_addrSize, sfn_sf); + send_hi_dci0_req(p7Sock, 0, &p7_addr, p7_addrSize, sfn_sf); + send_tx_req_1(p7Sock, 0, &p7_addr, p7_addrSize, sfn_sf); + + + usleep(500); + + send_subframe_indication(&(pnf_info.phys[0])); + // should send the cached messages + + send_harq_ind(&pnf_info.phys[0], sfn_sf); + recieve_harq_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_crc_ind(&pnf_info.phys[0], sfn_sf); + recieve_crc_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_rx_ind(&pnf_info.phys[0], sfn_sf); + recieve_rx_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_rach_ind(&pnf_info.phys[0], sfn_sf); + recieve_rach_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_srs_ind(&pnf_info.phys[0], sfn_sf); + recieve_srs_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_sr_ind(&pnf_info.phys[0], sfn_sf); + recieve_sr_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_cqi_ind(&pnf_info.phys[0], sfn_sf); + recieve_cqi_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_lbt_dl_ind(&pnf_info.phys[0], sfn_sf); + recieve_lbt_dl_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_nb_harq_ind(&pnf_info.phys[0], sfn_sf); + recieve_nb_harq_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_nrach_ind(&pnf_info.phys[0], sfn_sf); + recieve_nrach_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + + // send out of window dl_config, should expect the timing info + send_dl_config_req(p7Sock, 0, &p7_addr, p7_addrSize, SFNSF(600, 0)); + + sfn_sf = SFNSF(500, 5); // sfn:500 sf:4 + pnf_info.phys[0].sfn_sf = sfn_sf; + usleep(500); + + send_subframe_indication(&(pnf_info.phys[0])); + receive_timing_info(p7Sock); + + nfapi_pnf_p7_stop(pnf_info.phys[0].config); + int* result; + pthread_join(pnf_info.phys[0].thread, (void**)&result); + close(p7Sock); + + send_stop_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize); + receive_stop_response(p5Sock); + + send_pnf_stop_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_stop_response(p5Sock); + + nfapi_pnf_stop(config); + + pthread_join(thread, (void**)&result); + //CU_ASSERT_NOT_EQUAL(*result, -1); + CU_ASSERT_EQUAL(test_param_request_called, 1); + CU_ASSERT_EQUAL(test_config_request_called, 1); + + close(p5Sock); + close(p5ListenSock); + +} +void pnf_test_p7_segmentation_test_2(void) +{ + pnf_info_t pnf_info; + pnf_info.num_phys = 1; + pnf_info.phys[0].pnf_p7_port = 9348; + pnf_info.phys[0].pnf_p7_addr = "127.0.0.1"; + pnf_info.phys[0].vnf_p7_port = 8878; + pnf_info.phys[0].vnf_p7_addr = "127.0.0.1"; + + char* vnf_addr = "127.0.0.1"; + int vnf_port = 6699; + + int p5ListenSock = create_p5_listen_socket(vnf_addr, vnf_port); + printf("p5ListenSock %d %d\n", p5ListenSock, errno); + listen(p5ListenSock, 2); + + test_param_request_called = 0; + test_config_request_called = 0; + + nfapi_pnf_config_t* config = nfapi_pnf_config_create(); + config->vnf_ip_addr = vnf_addr; + config->vnf_p5_port = vnf_port; + config->pnf_param_req = &test_pnf_param_request; + config->pnf_config_req = &test_pnf_config_request; + config->pnf_start_req = &test_pnf_start_request; + config->pnf_stop_req = &test_pnf_stop_request; + config->param_req = &test_param_request; + config->config_req = &test_config_request; + config->start_req = &test_start_request; + config->stop_req = &test_stop_request; + + config->user_data = &pnf_info; + + pthread_t thread; + pthread_create(&thread, NULL, &pnf_test_start_thread, config); + + struct sockaddr_in addr; + socklen_t addrSize = sizeof(addr);; + int p5Sock = accept(p5ListenSock, (struct sockaddr *)&addr, &addrSize); + printf("p5 connection accepted %d %d\n", p5Sock, errno); + + send_pnf_param_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_param_response(p5Sock, NFAPI_MSG_OK); + + send_pnf_config_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_config_response(p5Sock); + + send_pnf_start_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_start_response(p5Sock); + + send_param_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize); + receive_param_response(p5Sock); + + + send_config_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize, &pnf_info); + receive_config_response(p5Sock); + + send_start_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize); + receive_start_response(p5Sock); + + sleep(2); + + int p7Sock = socket(AF_INET, SOCK_DGRAM, 0); + + { + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(pnf_info.phys[0].vnf_p7_port); + addr.sin_addr.s_addr = INADDR_ANY; + + bind(p7Sock, (struct sockaddr*)&addr, sizeof(addr)); + } + + printf("Sending p7 messages too %s:%d\n", pnf_info.phys[0].pnf_p7_addr, pnf_info.phys[0].pnf_p7_port); + + struct sockaddr_in p7_addr; + p7_addr.sin_family = AF_INET; + p7_addr.sin_port = htons(pnf_info.phys[0].pnf_p7_port); + p7_addr.sin_addr.s_addr = inet_addr(pnf_info.phys[0].pnf_p7_addr); + socklen_t p7_addrSize = sizeof(p7_addr); + + send_dl_node_sync(p7Sock, 0, &p7_addr, p7_addrSize); + receive_ul_node_sync(p7Sock); + + +#define SFNSF(_sfn, _sf) ((_sfn << 4) + _sf) + + uint16_t sfn_sf = SFNSF(500, 3); // sfn:500 sf:3 + pnf_info.phys[0].sfn_sf = sfn_sf; + send_subframe_indication(&(pnf_info.phys[0])); + + // should generate dummy messages + + usleep(500); + + sfn_sf = SFNSF(500, 4); // sfn:500 sf:4 + pnf_info.phys[0].sfn_sf = sfn_sf; + + send_dl_config_req(p7Sock, 0, &p7_addr, p7_addrSize, sfn_sf); + send_ul_config_req(p7Sock, 0, &p7_addr, p7_addrSize, sfn_sf); + send_hi_dci0_req(p7Sock, 0, &p7_addr, p7_addrSize, sfn_sf); + send_tx_req_2(p7Sock, 0, &p7_addr, p7_addrSize, sfn_sf); + + + usleep(500); + + send_subframe_indication(&(pnf_info.phys[0])); + // should send the cached messages + + send_harq_ind(&pnf_info.phys[0], sfn_sf); + recieve_harq_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_crc_ind(&pnf_info.phys[0], sfn_sf); + recieve_crc_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_rx_ind(&pnf_info.phys[0], sfn_sf); + recieve_rx_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_rach_ind(&pnf_info.phys[0], sfn_sf); + recieve_rach_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_srs_ind(&pnf_info.phys[0], sfn_sf); + recieve_srs_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_sr_ind(&pnf_info.phys[0], sfn_sf); + recieve_sr_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_cqi_ind(&pnf_info.phys[0], sfn_sf); + recieve_cqi_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_lbt_dl_ind(&pnf_info.phys[0], sfn_sf); + recieve_lbt_dl_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + // send out of window dl_config, should expect the timing info + send_dl_config_req(p7Sock, 0, &p7_addr, p7_addrSize, SFNSF(600, 0)); + + sfn_sf = SFNSF(500, 5); // sfn:500 sf:4 + pnf_info.phys[0].sfn_sf = sfn_sf; + usleep(500); + + send_subframe_indication(&(pnf_info.phys[0])); + receive_timing_info(p7Sock); + + send_stop_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize); + receive_stop_response(p5Sock); + + nfapi_pnf_p7_stop(pnf_info.phys[0].config); + int* result; + pthread_join(pnf_info.phys[0].thread, (void**)&result); + close(p7Sock); + + + send_pnf_stop_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_stop_response(p5Sock); + + nfapi_pnf_stop(config); + + pthread_join(thread, (void**)&result); + //CU_ASSERT_NOT_EQUAL(*result, -1); + CU_ASSERT_EQUAL(test_param_request_called, 1); + CU_ASSERT_EQUAL(test_config_request_called, 1); + + close(p5Sock); + close(p5ListenSock); + +} +void pnf_test_p7_segmentation_test_3(void) +{ + pnf_info_t pnf_info; + pnf_info.num_phys = 1; + pnf_info.phys[0].pnf_p7_port = 9348; + pnf_info.phys[0].pnf_p7_addr = "127.0.0.1"; + pnf_info.phys[0].vnf_p7_port = 8878; + pnf_info.phys[0].vnf_p7_addr = "127.0.0.1"; + + char* vnf_addr = "127.0.0.1"; + int vnf_port = 6699; + + int p5ListenSock = create_p5_listen_socket(vnf_addr, vnf_port); + printf("p5ListenSock %d %d\n", p5ListenSock, errno); + listen(p5ListenSock, 2); + + test_param_request_called = 0; + test_config_request_called = 0; + + nfapi_pnf_config_t* config = nfapi_pnf_config_create(); + config->vnf_ip_addr = vnf_addr; + config->vnf_p5_port = vnf_port; + config->pnf_param_req = &test_pnf_param_request; + config->pnf_config_req = &test_pnf_config_request; + config->pnf_start_req = &test_pnf_start_request; + config->pnf_stop_req = &test_pnf_stop_request; + config->param_req = &test_param_request; + config->config_req = &test_config_request; + config->start_req = &test_start_request; + config->stop_req = &test_stop_request; + + config->user_data = &pnf_info; + + pthread_t thread; + pthread_create(&thread, NULL, &pnf_test_start_thread, config); + + struct sockaddr_in addr; + socklen_t addrSize = sizeof(addr);; + int p5Sock = accept(p5ListenSock, (struct sockaddr *)&addr, &addrSize); + printf("p5 connection accepted %d %d\n", p5Sock, errno); + + send_pnf_param_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_param_response(p5Sock, NFAPI_MSG_OK); + + send_pnf_config_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_config_response(p5Sock); + + send_pnf_start_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_start_response(p5Sock); + + send_param_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize); + receive_param_response(p5Sock); + + + send_config_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize, &pnf_info); + receive_config_response(p5Sock); + + send_start_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize); + receive_start_response(p5Sock); + + sleep(2); + + int p7Sock = socket(AF_INET, SOCK_DGRAM, 0); + + { + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(pnf_info.phys[0].vnf_p7_port); + addr.sin_addr.s_addr = INADDR_ANY; + + bind(p7Sock, (struct sockaddr*)&addr, sizeof(addr)); + } + + printf("Sending p7 messages too %s:%d\n", pnf_info.phys[0].pnf_p7_addr, pnf_info.phys[0].pnf_p7_port); + + struct sockaddr_in p7_addr; + p7_addr.sin_family = AF_INET; + p7_addr.sin_port = htons(pnf_info.phys[0].pnf_p7_port); + p7_addr.sin_addr.s_addr = inet_addr(pnf_info.phys[0].pnf_p7_addr); + socklen_t p7_addrSize = sizeof(p7_addr); + + send_dl_node_sync(p7Sock, 0, &p7_addr, p7_addrSize); + receive_ul_node_sync(p7Sock); + + +#define SFNSF(_sfn, _sf) ((_sfn << 4) + _sf) + + uint16_t sfn_sf = SFNSF(500, 3); // sfn:500 sf:3 + pnf_info.phys[0].sfn_sf = sfn_sf; + send_subframe_indication(&(pnf_info.phys[0])); + + // should generate dummy messages + + usleep(500); + + sfn_sf = SFNSF(500, 4); // sfn:500 sf:4 + pnf_info.phys[0].sfn_sf = sfn_sf; + + + send_dl_subframe_msgs_interleaved(p7Sock, 0, &p7_addr, p7_addrSize, sfn_sf); + + + usleep(500); + + send_subframe_indication(&(pnf_info.phys[0])); + // should send the cached messages + + send_harq_ind(&pnf_info.phys[0], sfn_sf); + recieve_harq_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_crc_ind(&pnf_info.phys[0], sfn_sf); + recieve_crc_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_rx_ind(&pnf_info.phys[0], sfn_sf); + recieve_rx_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_rach_ind(&pnf_info.phys[0], sfn_sf); + recieve_rach_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_srs_ind(&pnf_info.phys[0], sfn_sf); + recieve_srs_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_sr_ind(&pnf_info.phys[0], sfn_sf); + recieve_sr_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_cqi_ind(&pnf_info.phys[0], sfn_sf); + recieve_cqi_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + send_lbt_dl_ind(&pnf_info.phys[0], sfn_sf); + recieve_lbt_dl_ind(p7Sock, 0, &p7_addr, p7_addrSize); + + // send out of window dl_config, should expect the timing info + printf("Sending late dl config req\n"); + send_dl_config_req(p7Sock, 0, &p7_addr, p7_addrSize, SFNSF(600, 0)); + + sfn_sf = SFNSF(500, 5); // sfn:500 sf:4 + pnf_info.phys[0].sfn_sf = sfn_sf; + sleep(2); + + printf("Sending subframe indication\n"); + send_subframe_indication(&(pnf_info.phys[0])); + printf("Waitning for timing info\n"); + receive_timing_info(p7Sock); + + printf("Sending stop request\n"); + send_stop_request(p5Sock, 0, (struct sockaddr*)&addr, addrSize); + receive_stop_response(p5Sock); + + printf("Waiting for P7 thread to stop\n"); + nfapi_pnf_p7_stop(pnf_info.phys[0].config); + int* result; + pthread_join(pnf_info.phys[0].thread, (void**)&result); + close(p7Sock); + + + send_pnf_stop_request(p5Sock, (struct sockaddr*)&addr, addrSize); + receive_pnf_stop_response(p5Sock); + + nfapi_pnf_stop(config); + + pthread_join(thread, (void**)&result); + //CU_ASSERT_NOT_EQUAL(*result, -1); + CU_ASSERT_EQUAL(test_param_request_called, 1); + CU_ASSERT_EQUAL(test_config_request_called, 1); + + close(p5Sock); + close(p5ListenSock); + +} + +/************* Test Runner Code goes here **************/ + +int main ( void ) +{ + CU_pSuite pSuite = NULL; + + /* initialize the CUnit test registry */ + if ( CUE_SUCCESS != CU_initialize_registry() ) + return CU_get_error(); + + /* add a suite to the registry */ + pSuite = CU_add_suite( "pnf_test_suite", init_suite, clean_suite ); + if ( NULL == pSuite ) { + CU_cleanup_registry(); + return CU_get_error(); + } + + /* add the tests to the suite */ + if ( (NULL == CU_add_test(pSuite, "pnf_test_start_no_config", pnf_test_start_no_config)) || + (NULL == CU_add_test(pSuite, "pnf_test_start_no_ip", pnf_test_start_no_ip)) || + (NULL == CU_add_test(pSuite, "pnf_test_start_invalid_ip", pnf_test_start_invalid_ip)) || + (NULL == CU_add_test(pSuite, "pnf_test_start_no_connection", pnf_test_start_no_connection)) || + (NULL == CU_add_test(pSuite, "pnf_test_start_connect", pnf_test_start_connect)) || + (NULL == CU_add_test(pSuite, "pnf_test_start_pnf_config_invalid_state", pnf_test_state_pnf_config_invalid_state)) || + (NULL == CU_add_test(pSuite, "pnf_test_start_pnf_param_invalid_state", pnf_test_state_pnf_param_invalid_state)) || + (NULL == CU_add_test(pSuite, "pnf_test_p7_segmentation_test_1", pnf_test_p7_segmentation_test_1)) || + (NULL == CU_add_test(pSuite, "pnf_test_p7_segmentation_test_2", pnf_test_p7_segmentation_test_2)) || + (NULL == CU_add_test(pSuite, "pnf_test_p7_segmentation_test_3", pnf_test_p7_segmentation_test_3)) + ) + { + CU_cleanup_registry(); + return CU_get_error(); + } + + //(NULL == CU_add_test(pSuite, "pnf_test_start_connect_ipv6", pnf_test_start_connect_ipv6)) || + + // Run all tests using the basic interface + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_set_output_filename("pnf_unit_test_results.xml"); + CU_basic_run_tests(); + + CU_pSuite s = CU_get_registry()->pSuite; + int count = 0; + while(s) + { + CU_pTest t = s->pTest; + while(t) + { + count++; + t = t->pNext; + } + s = s->pNext; + } + + printf("%d..%d\n", 1, count); + + + + s = CU_get_registry()->pSuite; + count = 1; + while(s) + { + CU_pTest t = s->pTest; + while(t) + { + int pass = 1; + CU_FailureRecord* failures = CU_get_failure_list(); + while(failures) + { + if(strcmp(failures->pSuite->pName, s->pName) == 0 && + strcmp(failures->pTest->pName, t->pName) == 0) + { + pass = 0; + failures = 0; + } + else + { + failures = failures->pNext; + } + } + + if(pass) + printf("ok %d - %s:%s\n", count, s->pName, t->pName); + else + printf("not ok %d - %s:%s\n", count, s->pName, t->pName); + + count++; + t = t->pNext; + } + s = s->pNext; + } + + // Clean up registry and return + CU_cleanup_registry(); + return CU_get_error(); + +} diff --git a/nfapi/open-nFAPI/pnf_sim/Makefile.am b/nfapi/open-nFAPI/pnf_sim/Makefile.am new file mode 100644 index 0000000000..c8d9d8ddd4 --- /dev/null +++ b/nfapi/open-nFAPI/pnf_sim/Makefile.am @@ -0,0 +1,22 @@ +# +# Copyright 2017 Cisco Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +AUTOMAKE_OPTIONS=subdir-objects +AM_CPPFLAGS = -I$(top_srcdir)/pnf_sim/inc -I$(top_srcdir)/sim_common/inc -I$(top_srcdir)/pnf/public_inc -I$(top_srcdir)/common/inc -I$(top_srcdir)/common/public_inc -I$(top_srcdir)/nfapi/public_inc -I$(top_srcdir)/nfapi/inc $(XML_CFLAGS) -g +AM_CXXFLAGS = -I$(top_srcdir)/pnf_sim/inc -I$(top_srcdir)/sim_common/inc -I$(top_srcdir)/pnf/public_inc -I$(top_srcdir)/common/inc -I$(top_srcdir)/common/public_inc -I$(top_srcdir)/nfapi/public_inc -I$(top_srcdir)/nfapi/inc $(XML_CFLAGS) -std=c++11 $(BOOST_CPPFLAGS) -g +bin_PROGRAMS = pnfsim +pnfsim_SOURCES = src/main.cpp src/fapi_stub.cpp +LDADD= $(top_builddir)/pnf/libnfapi_pnf.a $(top_builddir)/common/libnfapi_common.a $(top_builddir)/nfapi/libnfapi.a $(top_builddir)/sim_common/libnfapi_sim_common.a -L$(libdir) -lpthread -lrt -lsctp -lz diff --git a/nfapi/open-nFAPI/pnf_sim/inc/fapi_interface.h b/nfapi/open-nFAPI/pnf_sim/inc/fapi_interface.h new file mode 100644 index 0000000000..b1d44eab8b --- /dev/null +++ b/nfapi/open-nFAPI/pnf_sim/inc/fapi_interface.h @@ -0,0 +1,1800 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef _FAPI_INTERFACE_H_ +#define _FAPI_INTERFACE_H_ + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int16_t; +typedef unsigned short uint16_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; + +#define FAPI_PARAM_REQUEST 0x00 +#define FAPI_PARAM_RESPONSE 0x01 +#define FAPI_CONFIG_REQUEST 0x02 +#define FAPI_CONFIG_RESPONSE 0x03 +#define FAPI_START_REQUEST 0x04 +#define FAPI_STOP_REQUEST 0x05 +#define FAPI_STOP_INDICATION 0x06 +#define FAPI_UE_CONFIG_REQUEST 0x07 +#define FAPI_UE_CONFIG_RESPONSE 0x08 +#define FAPI_ERROR_INDICATION 0x09 +#define FAPI_UE_RELEASE_REQUEST 0x0A +#define FAPI_UE_RELEASE_RESPONSE 0x0B +#define FAPI_DL_CONFIG_REQUEST 0x80 +#define FAPI_UL_CONFIG_REQUEST 0x81 +#define FAPI_SUBFRAME_INDICATION 0x82 +#define FAPI_HI_DCI0_REQUEST 0x83 +#define FAPI_TX_REQUEST 0x84 +#define FAPI_HARQ_INDICATION 0x85 +#define FAPI_CRC_INDICATION 0x86 +#define FAPI_RX_ULSCH_INDICATION 0x87 +#define FAPI_RACH_INDICATION 0x88 +#define FAPI_SRS_INDICATION 0x89 +#define FAPI_RX_SR_INDICATION 0x8A +#define FAPI_RX_CQI_INDICATION 0x8B +#define FAPI_LBT_DL_CONFIG_REQUEST 0x8C +#define FAPI_LBT_DL_INDICATION 0x8D +#define FAPI_NB_HARQ_INDICATION 0x8E +#define FAPI_NRACH_INDICATION 0x8F + + + + +#define FAPI_SUBFRAME_DUPLEX_MODE_TAG 0x01 +#define FAPI_SUBFRAME_PCFICH_POWER_OFFSET_TAG 0x02 +#define FAPI_SUBFRAME_PB_TAG 0x03 +#define FAPI_SUBFRAME_DL_CYCLIC_PREFIX_TYPE_TAG 0x04 +#define FAPI_SUBFRAME_UL_CYCLIC_PREFIX_TYPE_TAG 0x05 +#define FAPI_RF_DL_CHANNEL_BANDWIDTH_TAG 0x0A +#define FAPI_RF_UL_CHANNEL_BANDWIDTH_TAG 0x0B +#define FAPI_RF_REFERENCE_SIGNAL_POWER_TAG 0x0C +#define FAPI_RF_TX_ANTENNA_PORTS_TAG 0x0D +#define FAPI_RF_RX_ANTENNA_PORTS_TAG 0x0E +#define FAPI_PHICH_RESOURCE_TAG 0x14 +#define FAPI_PHICH_DURATION_TAG 0x15 +#define FAPI_PHICH_POWER_OFFSET_TAG 0x16 +#define FAPI_SCH_PRIMARY_SYNC_SIGNAL_TAG 0x1E +#define FAPI_SCH_SECONDARY_SYNC_SIGNAL_TAG 0x1F +#define FAPI_SCH_PHYSICAL_CELL_ID_TAG 0x20 +#define FAPI_PRACH_CONFIGURATION_INDEX_TAG 0x28 +#define FAPI_PRACH_ROOT_SEQUENCE_INDEX_TAG 0x29 +#define FAPI_PRACH_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG 0x2A +#define FAPI_PRACH_HIGH_SPEED_FLAG_TAG 0x2B +#define FAPI_PRACH_FREQUENCY_OFFSET_TAG 0x2C +#define FAPI_PUSCH_HOPPING_MODE_TAG 0x32 +#define FAPI_PUSCH_HOPPING_OFFSET_TAG 0x33 +#define FAPI_PUSCH_NUMBER_OF_SUBBANDS_TAG 0x34 +#define FAPI_PUCCH_DELTA_PUCCH_SHIFT_TAG 0x3C +#define FAPI_PUCCH_N_CQI_RB_TAG 0x3D +#define FAPI_PUCCH_N_AN_CS_TAG 0x3E +#define FAPI_PUCCH_N1_PUCCH_AN_TAG 0x3F +#define FAPI_SRS_BANDWIDTH_CONFIGURATION_TAG 0x46 +#define FAPI_SRS_MAX_UP_PTS_TAG 0x47 +#define FAPI_SRS_SUBFRAME_CONFIGURATION_TAG 0x48 +#define FAPI_SRS_ACK_NACK_SRS_SIMULTANEOUS_TX_TAG 0x49 +#define FAPI_UL_REF_SIG_UPLINK_RS_HOPPING_TAG 0x50 +#define FAPI_UL_REF_SIG_GROUP_ASSIGNMENT_TAG 0x51 +#define FAPI_UL_REF_SIG_CYCLIC_SHIFT_1_FOR_DRMS_TAG 0x52 +#define FAPI_TDD_SUBFRAME_ASSIGNMENT_TAG 0x5A +#define FAPI_TDD_SPECIAL_SUBFRAME_PATTERNS_TAG 0x5B + +#define FAPI_LAA_CONFIG_ED_THRESHOLD_FOR_LBT_FOR_PDSCH_TAG 0x64 +#define FAPI_LAA_CONFIG_ED_THRESHOLD_FOR_LBT_FOR_DRS_TAG 0x65 +#define FAPI_LAA_CONFIG_PD_THRESHOLD_TAG 0x66 +#define FAPI_LAA_CONFIG_MULTI_CARRIER_TYPE_TAG 0x67 +#define FAPI_LAA_CONFIG_MULTI_CARRIER_TX_TAG 0x68 +#define FAPI_LAA_CONFIG_MULTI_CARRIER_FREEZE_TAG 0x69 +#define FAPI_LAA_CONFIG_TX_ANTENNA_PORTS_FOR_DRS_TAG 0x6A +#define FAPI_LAA_CONFIG_TRANSMISSION_POWER_FOR_DRS_TAG 0x6B + +#define FAPI_EMTC_CONFIG_PBCH_REPETITIONS_ENABLED_R13_TAG 0x78 +#define FAPI_EMTC_CONFIG_PRACH_CAT_M_ROOT_SEQUENCY_INDEX_TAG 0x79 +#define FAPI_EMTC_CONFIG_PRACH_CAT_M_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG 0x7A +#define FAPI_EMTC_CONFIG_PRACH_CAT_M_HIGH_SPEED_FLAG_TAG 0x7B +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_ENABLE_TAG 0x7C +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_CONFIGURATION_INDEX_TAG 0x7D +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_FREQUENCY_OFFSET_TAG 0x7E +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x7F +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_STARTING_SUBFRAME_PERIODICITY_TAG 0x80 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_ENABLE_TAG 0x81 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_OFFSET_TAG 0x82 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_ENABLE_TAG 0x83 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_CONFIGURATION_INDEX_TAG 0x84 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_FREQUENCY_OFFSET_TAG 0x85 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x86 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_STARTING_SUBFRAME_PERIODICITY_TAG 0x87 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_ENABLE_TAG 0x88 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_OFFSET_TAG 0x89 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_ENABLE_TAG 0x8A +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_CONFIGURATION_INDEX_TAG 0x8B +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_FREQUENCY_OFFSET_TAG 0x8C +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x8D +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_STARTING_SUBFRAME_PERIODICITY_TAG 0x8E +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_ENABLE_TAG 0x8F +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_OFFSET_TAG 0x90 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_ENABLE_TAG 0x91 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_CONFIGURATION_INDEX_TAG 0x92 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_FREQUENCY_OFFSET_TAG 0x93 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0x94 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_STARTING_SUBFRAME_PERIODICITY_TAG 0x95 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_ENABLE_TAG 0x96 +#define FAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_OFFSET_TAG 0x97 +#define FAPI_EMTC_CONFIG_PRACH_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEA_TAG 0x98 +#define FAPI_EMTC_CONFIG_PRACH_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEB_TAG 0x99 + +#define FAPI_NB_IOT_OPERATING_MODE_TAG 0xA5 +#define FAPI_NB_IOT_ANCHOR_TAG 0xA6 +#define FAPI_NB_IOT_PRB_INDEX_TAG 0xA7 +#define FAPI_NB_IOT_CONTROL_REGION_SIZE_TAG 0xA8 +#define FAPI_NB_IOT_ASSUMED_CRS_APS_TAG 0xA9 +#define FAPI_NB_IOT_NPRACH_CONFIG_0_ENABLE_TAG 0xAA +#define FAPI_NB_IOT_NPRACH_CONFIG_0_SF_PERIODCITY_TAG 0xAB +#define FAPI_NB_IOT_NPRACH_CONFIG_0_START_TIME_TAG 0xAC +#define FAPI_NB_IOT_NPRACH_CONFIG_0_SUBCARRIER_OFFSET_TAG 0xAD +#define FAPI_NB_IOT_NPRACH_CONFIG_0_NUMBER_OF_SUBCARRIERS_TAG 0xAE +#define FAPI_NB_IOT_NPRACH_CONFIG_0_CP_LENGTH_TAG 0xAD +#define FAPI_NB_IOT_NPRACH_CONFIG_0_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0xB0 +#define FAPI_NB_IOT_NPRACH_CONFIG_1_ENABLE_TAG 0xB1 +#define FAPI_NB_IOT_NPRACH_CONFIG_1_SF_PERIODCITY_TAG 0xB2 +#define FAPI_NB_IOT_NPRACH_CONFIG_1_START_TIME_TAG 0xB3 +#define FAPI_NB_IOT_NPRACH_CONFIG_1_SUBCARRIER_OFFSET_TAG 0xB4 +#define FAPI_NB_IOT_NPRACH_CONFIG_1_NUMBER_OF_SUBCARRIERS_TAG 0xB5 +#define FAPI_NB_IOT_NPRACH_CONFIG_1_CP_LENGTH_TAG 0xB6 +#define FAPI_NB_IOT_NPRACH_CONFIG_1_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0xB7 +#define FAPI_NB_IOT_NPRACH_CONFIG_2_ENABLE_TAG 0xB8 +#define FAPI_NB_IOT_NPRACH_CONFIG_2_SF_PERIODCITY_TAG 0xB9 +#define FAPI_NB_IOT_NPRACH_CONFIG_2_START_TIME_TAG 0xBA +#define FAPI_NB_IOT_NPRACH_CONFIG_2_SUBCARRIER_OFFSET_TAG 0xBB +#define FAPI_NB_IOT_NPRACH_CONFIG_2_NUMBER_OF_SUBCARRIERS_TAG 0xBC +#define FAPI_NB_IOT_NPRACH_CONFIG_2_CP_LENGTH_TAG 0xBD +#define FAPI_NB_IOT_NPRACH_CONFIG_2_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG 0xBE + +#define FAPI_NB_IOT_THREE_TONE_BASE_SEQUENCE_TAG 0xBF +#define FAPI_NB_IOT_SIX_TONE_BASE_SEQUENCE_TAG 0xC0 +#define FAPI_NB_IOT_TWELVE_TONE_BASE_SEQUENCE_TAG 0xC1 +#define FAPI_NB_IOT_THREE_TONE_CYCLIC_SHIFT_TAG 0xC2 +#define FAPI_NB_IOT_SIX_TONE_CYCLIC_SHIFT_TAG 0xC3 +#define FAPI_NB_IOT_DL_GAP_CONFIG_ENABLE_TAG 0xC4 +#define FAPI_NB_IOT_DL_GAP_THRESHOLD_TAG 0xC5 +#define FAPI_NB_IOT_DL_GAP_PERIODICITY_TAG 0xC6 +#define FAPI_NB_IOT_DL_GAP_DURATION_COEFFICIENT_TAG 0xC7 + +//... +#define FAPI_PHY_CAPABILITIES_DL_BANDWIDTH_SUPPORT_TAG 0xC8 +#define FAPI_PHY_CAPABILITIES_UL_BANDWIDTH_SUPPORT_TAG 0xC9 +#define FAPI_PHY_CAPABILITIES_DL_MODULATION_SUPPORT_TAG 0xCA +#define FAPI_PHY_CAPABILITIES_UL_MODULATION_SUPPORT_TAG 0xCB +#define FAPI_PHY_CAPABILITIES_PHY_ANTENNA_CAPABILITY_TAG 0xCC +#define FAPI_PHY_CAPABILITIES_RELEASE_CAPABILITY_TAG 0xCD +#define FAPI_PHY_CAPABILITIES_MBSFN_CAPABILITY_TAG 0xCE +#define FAPI_PHY_CAPABILITIES_LAA_SUPPORT_TAG 0xD1 +#define FAPI_PHY_CAPABILITIES_LAA_PD_SENSING_LBT_SUPPORT_TAG 0xD2 +#define FAPI_PHY_CAPABILITIES_LAA_MULTI_CARRIER_LBT_SUPPORT_TAG 0xD3 +#define FAPI_PHY_CAPABILITIES_LAA_PARTIAL_SF_SUPPORT_TAG 0xD4 +#define FAPI_PHY_CAPABILITIES_NB_IOT_SUPPORT_TAG 0xD5 +#define FAPI_PHY_CAPABILITIES_NB_IOT_OPERATING_MODE_CAPABILITY_TAG 0xD6 + +#define FAPI_PHY_CAPABILITIES_DATA_REPORT_MODE_TAG 0xF0 +#define FAPI_PHY_SFN_SF_TAG 0xF1 +#define FAPI_PHY_STATE_TAG 0xFA + +#define FAPI_MSG_OK 0x0 +#define FAPI_MSG_INVALID_STATE 0x1 +#define FAPI_MSG_INVALID_CONFIG 0x2 +#define FAPI_MSG_SFN_OUT_OF_SYNC 0x3 +#define FAPI_MSG_SUBFRAME_ERR 0x4 +#define FAPI_MSG_BCH_MISSING 0x5 +#define FAPI_MSG_INVALID_SFN 0x6 +#define FAPI_MSG_HI_ERR 0x7 +#define FAPI_MSG_TX_ERR 0x8 + +#define FAPI_MSG_LBT_NO_PDU_IN_DL_REQ 0x9 +#define FAPI_MSG_LBT_NO_VALID_CONFIG_REQ_RECIEVED 0xA +#define FAPI_MSG_FAPI_E_LBT_SF_SFN_PASSED_END_SF_SFN 0xB +#define FAPI_MSG_FAPI_E_LBT_OVERLAP 0xC +#define FAPI_MSG_BCH_PRESENT 0xD +#define FAPI_MSG_NBIOT_UNEXPECTED_REQ 0xE + + +// TODO : Work out what the correct maximums should be + +// Number of UL/DL configurations, I, as defined by 36.212 section 5.3.3.1.4 +// todo : work out what the max is +#define FAPI_MAX_UL_DL_CONFIGURATIONS 4 +#define FAPI_MAX_NUM_PHYSICAL_ANTENNAS 4 +#define FAPI_MAX_NUM_SCHEDULED_UES 8 +#define FAPI_MAX_NUM_SUBBANDS 8 +#define FAPI_MAX_ANTENNA_PORT_COUNT 2 + + +typedef struct { + uint8_t message_id; + uint16_t length; +} fapi_header_t; + +typedef struct { + uint8_t tag; + uint8_t length; + uint16_t value; +} fapi_tlv_t; + +typedef struct { + fapi_header_t header; +} fapi_param_req_t; + +typedef struct { + fapi_header_t header; + uint8_t error_code; + uint8_t number_of_tlvs; + fapi_tlv_t tlvs[255]; +} fapi_param_resp_t; + +typedef struct { + fapi_header_t header; + uint8_t number_of_tlvs; + fapi_tlv_t tlvs[255]; +} fapi_config_req_t; + +typedef struct { + fapi_header_t header; + uint8_t error_code; + uint8_t number_of_invalid_tlvs; + uint8_t number_of_missing_tlvs; + fapi_tlv_t tlvs[255]; +} fapi_config_resp_t; + +typedef struct { + fapi_header_t header; +} fapi_start_req_t; + +typedef struct { + fapi_header_t header; +} fapi_stop_req_t; + +typedef struct { + fapi_header_t header; +} fapi_stop_ind_t; + +typedef struct { + uint16_t received_sfn_sf; + uint16_t expected_sfn_sf; +} fapi_sfn_out_of_sync_error_ind_t; + +typedef struct { + uint16_t received_sfn_sf; + uint16_t expected_sfn_sf; +} fapi_invalid_sfn_error_ind_t; + +typedef struct { + uint8_t sub_error_code; + uint8_t direction; + uint16_t rnti; + uint8_t pdu_type; +} fapi_pdu_error_ind_t; + +typedef struct { + uint8_t sub_error_code; + uint8_t phich_lowest_ul_rb_index; +} fapi_hi_error_ind_t; + +typedef struct { + uint8_t sub_error_code; + uint8_t pdu_index; +} fapi_tx_error_ind_t; + +typedef struct { + fapi_header_t header; + uint8_t message_id; + uint8_t error_code; + union + { + fapi_sfn_out_of_sync_error_ind_t out_of_sync_err; + fapi_invalid_sfn_error_ind_t invalid_sfn_err; + fapi_pdu_error_ind_t pdu_err; + fapi_hi_error_ind_t hi_err; + fapi_tx_error_ind_t tx_err; + }; +} fapi_error_ind_t; + +typedef struct { + uint32_t handle; + uint16_t rnti; +} fapi_rx_ue_information_t; + +typedef struct { + uint8_t ul_cqi; + uint8_t channel; +} fapi_ul_cqi_information_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; +} fapi_subframe_ind_t; + +typedef struct { + uint8_t value_0; + uint8_t value_1; +} fapi_harq_ind_rel8_tdd_harq_data_bundling_t; + +typedef struct { + uint8_t value_0; + uint8_t value_1; + uint8_t value_2; + uint8_t value_3; +} fapi_harq_ind_rel8_tdd_harq_data_multiplexing_t; + +typedef struct { + uint8_t value_0; +} fapi_harq_ind_rel8_tdd_harq_data_special_bundling_t; + +typedef struct { + uint8_t mode; + uint8_t number_of_ack_nack; + union{ + fapi_harq_ind_rel8_tdd_harq_data_bundling_t bundling; + fapi_harq_ind_rel8_tdd_harq_data_multiplexing_t multiplex; + fapi_harq_ind_rel8_tdd_harq_data_special_bundling_t special_bundling; + } harq_data; +} fapi_harq_ind_rel8_tdd_pdu_t; + +typedef struct { + uint8_t value_0; +} fapi_harq_ind_rel8_tdd_harq_data_t; + + +typedef struct { + uint8_t mode; + uint8_t number_of_ack_nack; + union{ + fapi_harq_ind_rel8_tdd_harq_data_t bundling; + fapi_harq_ind_rel8_tdd_harq_data_t multiplex; + fapi_harq_ind_rel8_tdd_harq_data_special_bundling_t special_bundling; + fapi_harq_ind_rel8_tdd_harq_data_t channel_selection; + fapi_harq_ind_rel8_tdd_harq_data_t format_3; + } harq_data[21]; +} fapi_harq_ind_rel9_tdd_pdu_t; + +typedef struct { + uint8_t mode; + uint16_t number_of_ack_nack; + union{ + fapi_harq_ind_rel8_tdd_harq_data_t bundling; + fapi_harq_ind_rel8_tdd_harq_data_t multiplex; + fapi_harq_ind_rel8_tdd_harq_data_special_bundling_t special_bundling; + fapi_harq_ind_rel8_tdd_harq_data_t channel_selection; + fapi_harq_ind_rel8_tdd_harq_data_t format_3; + fapi_harq_ind_rel8_tdd_harq_data_t format_4; + fapi_harq_ind_rel8_tdd_harq_data_t format_5; + } harq_data[22]; +} fapi_harq_ind_rel13_tdd_pdu_t; + +typedef struct { + uint8_t harq_tb_1; + uint8_t harq_tb_2; +} fapi_harq_ind_rel8_fdd_pdu_t; + +typedef struct { + uint8_t mode; + uint8_t number_of_ack_nack; + uint8_t harq_tb_n[10]; +} fapi_harq_ind_rel9_fdd_pdu_t; + +typedef struct { + uint8_t mode; + uint16_t number_of_ack_nack; + uint8_t harq_tb_n[22]; +} fapi_harq_ind_rel13_fdd_pdu_t; + +typedef struct { + fapi_rx_ue_information_t rx_ue_info; + union { + fapi_harq_ind_rel8_tdd_pdu_t rel8_tdd_pdu; + fapi_harq_ind_rel9_tdd_pdu_t rel9_tdd_pdu; + fapi_harq_ind_rel13_tdd_pdu_t rel13_tdd_pdu; + fapi_harq_ind_rel8_fdd_pdu_t rel8_fdd_pdu; + fapi_harq_ind_rel9_fdd_pdu_t rel9_fdd_pdu; + fapi_harq_ind_rel13_fdd_pdu_t rel13_fdd_pdu; + }; + fapi_ul_cqi_information_t ul_cqi_info; +} fapi_harq_ind_pdu_t; + +typedef struct { + uint16_t number_of_harqs; + fapi_harq_ind_pdu_t pdus[32]; +} fapi_harq_ind_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + fapi_harq_ind_body_t body; +} fapi_harq_ind_t; + +typedef struct { + uint8_t crc_flag; +} fapi_crc_ind_rel8_pdu_t; + +typedef struct { + fapi_rx_ue_information_t rx_ue_info; + fapi_crc_ind_rel8_pdu_t rel8_pdu; +} fapi_crc_ind_pdu_t; + +typedef struct { + uint16_t number_of_crcs; + fapi_crc_ind_pdu_t pdus[32]; +} fapi_crc_ind_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + fapi_crc_ind_body_t body; +} fapi_crc_ind_t; + +typedef struct { + uint16_t length; + uint16_t data_offset; + uint8_t ul_cqi; + uint16_t timing_advance; +} fapi_rx_ulsch_ind_rel8_pdu_t; + +typedef struct { + uint16_t timing_advance_r9; +} fapi_rx_ulsch_ind_rel9_pdu_t; + +typedef struct { + fapi_rx_ue_information_t rx_ue_info; + fapi_rx_ulsch_ind_rel8_pdu_t rel8_pdu; + fapi_rx_ulsch_ind_rel9_pdu_t rel9_pdu; +} fapi_rx_ulsch_ind_pdu_t; + +typedef struct { + uint16_t number_of_pdus; + fapi_rx_ulsch_ind_pdu_t pdus[32]; + void* data[32]; +} fapi_rx_ulsch_ind_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + fapi_rx_ulsch_ind_body_t body; +} fapi_rx_ulsch_ind_t; + +typedef struct { + uint16_t length; + uint16_t data_offset; + uint8_t ul_cqi; + uint8_t ri; + uint16_t timing_advance; +} fapi_rx_cqi_ind_rel8_pdu_t; + +typedef struct { + uint16_t length; + uint16_t data_offset; + uint8_t ul_cqi; + uint8_t number_of_cc_reported; + uint8_t ri[5]; + uint16_t timing_advance; + uint16_t timing_advance_r9; +} fapi_rx_cqi_ind_rel9_pdu_t; + +typedef struct { + fapi_rx_ue_information_t rx_ue_info; + fapi_rx_cqi_ind_rel8_pdu_t rel8_pdu; + fapi_rx_cqi_ind_rel9_pdu_t rel9_pdu; + fapi_ul_cqi_information_t ul_cqi_info; +} fapi_rx_cqi_ind_pdu_t; + +typedef struct { + uint16_t number_of_pdus; + fapi_rx_cqi_ind_pdu_t pdus[32]; + uint8_t* data[32]; +} fapi_rx_cqi_ind_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + fapi_rx_cqi_ind_body_t body; +} fapi_rx_cqi_ind_t; + +typedef struct { + fapi_rx_ue_information_t rx_ue_info; + fapi_ul_cqi_information_t ul_cqi_info; +} fapi_rx_sr_ind_pdu_t; + +typedef struct { + uint16_t number_of_srs; + fapi_rx_sr_ind_pdu_t pdus[32]; +} fapi_rx_sr_ind_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + fapi_rx_sr_ind_body_t body; +} fapi_rx_sr_ind_t; + +typedef struct { + uint16_t rnti; + uint8_t preamble; + uint16_t timing_advance; +} fapi_rach_ind_pdu_rel8_t; + +typedef struct { + uint16_t timing_advance_r9; +} fapi_rach_ind_pdu_rel9_t; + +typedef struct { + uint8_t rach_resource_type; +} fapi_rach_ind_pdu_rel13_t; + +typedef struct { + fapi_rach_ind_pdu_rel8_t rel8_pdu; + fapi_rach_ind_pdu_rel9_t rel9_pdu; + fapi_rach_ind_pdu_rel13_t rel13_pdu; +} fapi_rach_ind_pdu_t; + +typedef struct { + uint8_t number_of_preambles; + fapi_rach_ind_pdu_t pdus[32]; +} fapi_rach_ind_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + fapi_rach_ind_body_t body; +} fapi_rach_ind_t; + + +typedef struct { + uint16_t doppler_estimation; + uint16_t timing_advance; + uint8_t number_of_resource_blocks; + uint8_t rb_start; + uint8_t snr[100]; +} fapi_srs_ind_rel8_pdu_t; + +typedef struct { + uint16_t timing_advance_r9; +} fapi_srs_ind_rel9_pdu_t; + +typedef struct { + uint8_t uppts_symbol; +} fapi_srs_ind_rel10_tdd_pdu_t; + +typedef struct { + uint16_t ul_rtoa; +} fapi_srs_ind_rel11_pdu_t; + +typedef struct { + uint8_t num_prb_per_subband; + uint8_t number_of_subbands; + uint8_t num_atennas; + struct { + uint8_t subband_index; + uint16_t channel[FAPI_MAX_NUM_PHYSICAL_ANTENNAS]; + } subands[FAPI_MAX_NUM_SUBBANDS]; +} fapi_ttd_channel_measurement_t; + +typedef struct { + fapi_rx_ue_information_t rx_ue_info; + fapi_srs_ind_rel8_pdu_t rel8_pdu; + fapi_srs_ind_rel9_pdu_t rel9_pdu; + fapi_srs_ind_rel10_tdd_pdu_t rel10_tdd_pdu; + fapi_srs_ind_rel11_pdu_t rel11_pdu; + fapi_ttd_channel_measurement_t tdd_channel_measurement; +} fapi_srs_ind_pdu_t; + +typedef struct { + uint8_t number_of_ues; + fapi_srs_ind_pdu_t pdus[32]; +} fapi_srs_ind_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + fapi_srs_ind_body_t body; +} fapi_srs_ind_t; + + +typedef struct { + uint32_t handle; + uint32_t result; + uint32_t lte_txop_symbols; + uint32_t initial_partial_sf; +} fapi_lbt_dl_pdsch_rsp_rel13_pdu_t; + +typedef struct { + fapi_lbt_dl_pdsch_rsp_rel13_pdu_t rel13_pdu; +} fapi_lbt_dl_pdsch_rsp_pdu_t; + +typedef struct { + uint32_t handle; + uint32_t result; +} fapi_lbt_dl_drs_rsp_rel13_pdu_t; + +typedef struct { + fapi_lbt_dl_drs_rsp_rel13_pdu_t rel13_pdu; +} fapi_lbt_dl_drs_rsp_pdu_t; + +typedef struct { + uint8_t pdu_type; + uint8_t pdu_size; + union { + fapi_lbt_dl_pdsch_rsp_pdu_t lbt_pdsch_rsp_pdu; + fapi_lbt_dl_drs_rsp_pdu_t lbt_drs_rsp_pdu; + }; +} fapi_lbt_dl_ind_pdu_t; + +typedef struct { + uint16_t number_of_pdus; + fapi_lbt_dl_ind_pdu_t pdus[32]; +} fapi_lbt_dl_ind_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + fapi_lbt_dl_ind_body_t body; +} fapi_lbt_dl_ind_t; + +typedef struct { + uint8_t harq_tb1; +} fapi_nb_harq_ind_rel13_pdu_t; + +typedef struct { + fapi_rx_ue_information_t rx_ue_info; + union { + fapi_nb_harq_ind_rel13_pdu_t rel13_pdu; + }; + fapi_ul_cqi_information_t ul_cqi_info; +} fapi_nb_harq_ind_pdu_t; + +typedef struct { + uint16_t number_of_harqs; + fapi_nb_harq_ind_pdu_t pdus[32]; +} fapi_nb_harq_ind_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + fapi_nb_harq_ind_body_t body; +} fapi_nb_harq_ind_t; + +typedef struct { + uint16_t rnti; + uint8_t initial_sc; + uint16_t timing_advance; + uint8_t nrach_cs_level; +} fapi_nrach_ind_rel13_pdu_t; + +typedef struct { + fapi_rx_ue_information_t rx_ue_info; + union { + fapi_nrach_ind_rel13_pdu_t rel13_pdu; + }; + fapi_ul_cqi_information_t ul_cqi_info; +} fapi_nrach_ind_pdu_t; + +typedef struct { + uint16_t number_of_initial_scs_detected; + fapi_nrach_ind_pdu_t pdus[32]; +} fapi_nrach_ind_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + fapi_nrach_ind_body_t body; +} fapi_nrach_ind_t; + +//------------------------------------------------------------------------------ + +typedef struct { + uint8_t dci_format; + uint8_t cce_index; + uint8_t aggregation_level; + uint16_t rnti; + uint8_t resource_allocation_type; + uint8_t virtual_resource_block_assignment_flag; + uint32_t resource_block_coding; + uint8_t mcs_1; + uint8_t redundancy_version_1; + uint8_t new_data_indicator_1; + uint8_t transport_block_to_codeword_swap_flag; + uint8_t mcs_2; + uint8_t redundancy_version_2; + uint8_t new_data_indictor_2; + uint8_t harq_process; + uint8_t tpmi; + uint8_t pmi; + uint8_t precoding_information; + uint8_t tpc; + uint8_t downlink_assignment_index; + uint8_t n_gap; + uint8_t transport_block_size_index; + uint8_t downlink_power_offset; + uint8_t allocate_prach_flag; + uint8_t preamble_index; + uint8_t prach_mask_index; + uint8_t rnti_type; + uint16_t transmission_power; +} fapi_dl_config_dci_rel8_pdu_t; + +typedef struct { + uint8_t mcch_flag; + uint8_t mcch_change_notification; + uint8_t scrambling_identity; +} fapi_dl_config_dci_rel9_pdu_t; + +typedef struct { + uint8_t cross_carrier_scheduling_flag; + uint8_t carrier_indicator; + uint8_t srs_flag; + uint8_t srs_request; + uint8_t antenna_ports_scrambling_and_layers; + uint8_t total_dci_length_including_padding; + uint8_t n_dl_rb; +} fapi_dl_config_dci_rel10_pdu_t; + +typedef struct { + uint8_t harq_ack_resource_offset; + uint8_t pdsch_re_mapping_quasi_co_location_indicator; +} fapi_dl_config_dci_rel11_pdu_t; + +typedef struct { + uint8_t primary_cell_type; + uint8_t ul_dl_configuration_flag; + uint8_t number_ul_dl_configurations; + uint8_t ul_dl_configuration_indication[FAPI_MAX_UL_DL_CONFIGURATIONS]; +} fapi_dl_config_dci_rel12_pdu_t; + + +typedef struct { + uint8_t subband_index; + uint8_t scheduled_ues; + uint16_t precoding_value[FAPI_MAX_NUM_PHYSICAL_ANTENNAS][FAPI_MAX_NUM_SCHEDULED_UES]; +} fapi_dl_config_dci_dl_tpm_subband_info_t; + +typedef struct { + uint8_t num_prb_per_subband; + uint8_t number_of_subbands; + uint8_t num_antennas; + fapi_dl_config_dci_dl_tpm_subband_info_t subband_info[FAPI_MAX_NUM_SUBBANDS]; +} fapi_dl_config_dci_dl_tpm_t; + +typedef struct { + uint8_t laa_end_partial_sf_flag; + uint8_t laa_end_partial_sf_configuration; + uint8_t initial_lbt_sf; + uint8_t codebook_size_determination; + uint8_t drms_table_flag; + uint8_t tpm_struct_flag; + fapi_dl_config_dci_dl_tpm_t tpm; +} fapi_dl_config_dci_rel13_pdu_t; + +typedef struct { + fapi_dl_config_dci_rel8_pdu_t rel8_pdu; + fapi_dl_config_dci_rel9_pdu_t rel9_pdu; + fapi_dl_config_dci_rel10_pdu_t rel10_pdu; + fapi_dl_config_dci_rel11_pdu_t rel11_pdu; + fapi_dl_config_dci_rel12_pdu_t rel12_pdu; + fapi_dl_config_dci_rel13_pdu_t rel13_pdu; +} fapi_dl_config_dci_pdu_t; + +typedef struct { + uint16_t length; + uint16_t pdu_index; + uint16_t transmission_power; +} fapi_dl_config_bch_rel8_pdu_t; + +typedef struct { + fapi_dl_config_bch_rel8_pdu_t rel8_pdu; +} fapi_dl_config_bch_pdu_t; + +typedef struct { + uint16_t length; + uint16_t pdu_index; + uint16_t rnti; + uint8_t resource_allocation_type; + uint32_t resource_block_coding; + uint8_t modulation; + uint16_t transmission_power; + uint16_t mbsfn_area_id; +} fapi_dl_config_mch_rel8_pdu_t; + +typedef struct { + fapi_dl_config_mch_rel8_pdu_t rel8_pdu; +} fapi_dl_config_mch_pdu_t; + +typedef struct { + uint8_t subband_index; + uint8_t num_atennas; + uint16_t bf_value[8]; +} fapi_dl_config_bf_vector_t; + +typedef struct { + uint16_t length; + uint16_t pdu_index; + uint16_t rnti; + uint8_t resource_allocation_type; + uint8_t virtual_resource_block_assignment_flag; + uint32_t resource_block_coding; + uint8_t modulation; + uint8_t redundacy_version; + uint8_t transport_blocks; + uint8_t transport_block_codeword_swap_flag; + uint8_t transmission_scheme; + uint8_t number_of_layers; + uint8_t nunber_of_subands; + uint8_t codebook_index[13]; + uint8_t ue_category_capacity; + uint8_t p_a; + uint8_t delta_power_offset_index; + uint8_t n_gap; + uint8_t n_prb; + uint8_t transmission_mode; + uint8_t num_bf_prb_per_subband; + uint8_t num_bf_vecitor; + fapi_dl_config_bf_vector_t bf_vector[8]; +} fapi_dl_config_dlsch_rel8_pdu_t; + +typedef struct { + uint8_t nscid; +} fapi_dl_config_dlsch_rel9_pdu_t; + +typedef struct { + uint8_t csi_rs_flag; + uint8_t csi_rs_resource_config_r10; + uint16_t csi_rs_zero_tx_power_resource_config_bitmap_r10; + uint8_t csi_rs_number_nzp_configuration; + uint8_t csi_rs_resource_config[4]; + uint8_t pdsch_start; +} fapi_dl_config_dlsch_rel10_pdu_t; + +typedef struct { + uint8_t drms_config_flag; + uint16_t drms_scrambling; + uint8_t csi_config_flag; + uint16_t csi_scrambling; + uint8_t pdsch_re_mapping_flag; + uint8_t pdsch_re_mapping_atenna_ports; + uint8_t pdsch_re_mapping_freq_shift; +} fapi_dl_config_dlsch_rel11_pdu_t; + +typedef struct { + uint8_t altcqi_table_r12; + uint8_t maxlayers; + uint8_t n_dl_harq; +} fapi_dl_config_dlsch_rel12_pdu_t; + +typedef struct { + uint8_t dwpts_symbols; + uint8_t initial_lbt_sf; + uint8_t ue_type; + uint8_t pdsch_payload_type; + uint16_t initial_transmission_sf_io; + uint8_t drms_table_flag; +} fapi_dl_config_dlsch_rel13_pdu_t; + +typedef struct { + fapi_dl_config_dlsch_rel8_pdu_t rel8_pdu; + fapi_dl_config_dlsch_rel9_pdu_t rel9_pdu; + fapi_dl_config_dlsch_rel10_pdu_t rel10_pdu; + fapi_dl_config_dlsch_rel11_pdu_t rel11_pdu; + fapi_dl_config_dlsch_rel12_pdu_t rel12_pdu; + fapi_dl_config_dlsch_rel13_pdu_t rel13_pdu; +} fapi_dl_config_dlsch_pdu_t; + +typedef struct { + uint16_t length; + uint16_t pdu_index; + uint16_t p_rnti; + uint8_t resource_allocation_type; + uint8_t virtual_resource_block_assignment_flag; + uint32_t resource_block_coding; + uint8_t mcs; + uint8_t redudancy_version; + uint8_t number_of_transport_blocks; + uint8_t transport_block_to_codeword_swap_flag; + uint8_t transmission_scheme; + uint8_t number_of_layers; + uint8_t codebook_index; + uint8_t ue_category_capacity; + uint8_t p_a; + uint16_t transmission_power; + uint8_t n_prb; + uint8_t n_gap; +} fapi_dl_config_pch_rel8_pdu_t; + +typedef struct { + uint8_t ue_mode; + uint16_t initial_transmission_sf_io; +} fapi_dl_config_pch_rel13_pdu_t; + +typedef struct { + fapi_dl_config_pch_rel8_pdu_t rel8_pdu; + fapi_dl_config_pch_rel13_pdu_t rel13_pdu; +} fapi_dl_config_pch_pdu_t; + +typedef struct { + uint16_t transmission_power; + uint8_t prs_bandwidth; + uint8_t prs_cyclic_prefix_type; + uint8_t prs_muting; +} fapi_dl_config_prs_rel9_pdu_t; + +typedef struct { + fapi_dl_config_prs_rel9_pdu_t rel9_pdu; +} fapi_dl_config_prs_pdu_t; + +typedef struct { + uint8_t csi_rs_antenna_port_count_r10; + uint8_t csi_rs_resource_config_r10; + uint16_t transmission_power; + uint16_t csi_rs_zero_tx_power_resource_config_bitmap_r10; + uint8_t csi_rs_number_of_nzp_configuration; + uint8_t csi_rs_resource_config[8]; +} fapi_dl_config_csi_rs_rel10_pdu_t; + +typedef struct { + uint8_t csi_rs_class; + uint8_t cdm_type; + uint8_t num_bf_vector; + struct { + uint8_t csi_rs_resource_index; + uint16_t bf_value[FAPI_MAX_ANTENNA_PORT_COUNT]; + } bf_vector[8]; +}fapi_dl_config_csi_rs_rel13_pdu_t; + +typedef struct { + fapi_dl_config_csi_rs_rel10_pdu_t rel10_pdu; + fapi_dl_config_csi_rs_rel13_pdu_t rel13_pdu; +} fapi_dl_config_csi_rs_pdu_t; + +typedef struct { + uint8_t edpcch_resource_assigenment_flag; + uint16_t edpcch_id; + uint8_t epdcch_start_symbol; + uint8_t epdcch_num_prb; + uint8_t epdcch_prb_index[8]; + fapi_dl_config_bf_vector_t bf_vector; +} fapi_dl_config_edpcch_rel11_params_t; + +typedef struct { + uint8_t dwpts_symbols; + uint8_t initial_lbt_sf; +} fapi_dl_config_edpcch_rel13_params_t; + +typedef struct { + fapi_dl_config_dci_rel8_pdu_t rel8_pdu; + fapi_dl_config_dci_rel9_pdu_t rel9_pdu; + fapi_dl_config_dci_rel10_pdu_t rel10_pdu; + fapi_dl_config_dci_rel11_pdu_t rel11_pdu; + fapi_dl_config_dci_rel12_pdu_t rel12_pdu; + fapi_dl_config_dci_rel13_pdu_t rel13_pdu; + fapi_dl_config_edpcch_rel11_params_t rel8_params; + fapi_dl_config_edpcch_rel13_params_t rel13_params; +} fapi_dl_config_edpcch_pdu_t; + +typedef struct { + uint8_t mpdcch_narrow_band; + uint8_t number_of_prb_pairs; + uint8_t resource_block_assignment; + uint8_t mpdcch_tansmission_type; + uint8_t start_symbol; + uint8_t ecce_index; + uint8_t aggregation_level; + uint8_t rnti_type; + uint16_t rnti; + uint8_t ce_mode; + uint16_t drms_scrambling_init; + uint16_t initial_transmission_sf_io; + uint16_t transmission_power; + uint8_t dci_format; + uint16_t resource_block_coding; + uint8_t mcs; + uint8_t pdsch_reptition_levels; + uint8_t redundancy_version; + uint8_t new_data_indicator; + uint8_t harq_process; + uint8_t tpmi_length; + uint8_t tpmi; + uint8_t pmi_flag; + uint8_t pmi; + uint8_t harq_resource_offset; + uint8_t dci_subframe_repetition_number; + uint8_t tpc; + uint8_t downlink_assignment_index_length; + uint8_t downlink_assignment_index; + uint8_t allocate_prach_flag; + uint8_t preamble_index; + uint8_t prach_mask_index; + uint8_t starting_ce_level; + uint8_t srs_request; + uint8_t antenna_ports_and_scrambling_identity_flag; + uint8_t antenna_ports_and_scrambling_identity; + uint8_t frequency_hopping_enabled_flag; + uint8_t paging_direct_indication_differentiation_flag; + uint8_t direct_indication; + uint8_t total_dci_length_including_padding; + uint8_t number_of_tx_antenna_ports; + uint16_t precoding_value[8]; +} fapi_dl_config_mdpcch_rel13_pdu_t; + +typedef struct { + fapi_dl_config_mdpcch_rel13_pdu_t rel13_pdu; +} fapi_dl_config_mdpcch_pdu_t; + +typedef struct { + uint16_t length; + uint16_t pdu_index; + uint16_t transmission_power; + uint16_t hyper_sfn_2_lsbs; +} fapi_dl_config_nbch_rel13_pdu_t; + +typedef struct { + fapi_dl_config_nbch_rel13_pdu_t rel13_pdu; +} fapi_dl_config_nbch_pdu_t; + +typedef struct { + uint16_t length; + uint16_t pdu_index; + uint8_t ncce_index; + uint8_t aggregation_level; + uint8_t start_symbol; + uint8_t rnti_type; + uint16_t rnti; + uint8_t scrambling_reinitialization_batch_index; + uint8_t nrs_antenna_ports_assumed_by_the_ue; + uint8_t dci_format; + uint8_t scheduling_delay; + uint8_t resource_assignment; + uint8_t repetition_number; + uint8_t mcs; + uint8_t new_data_indicator; + uint8_t harq_ack_resource; + uint8_t npdcch_order_indication; + uint8_t starting_number_of_nprach_repetitions; + uint8_t subcarrier_indication_of_nprach; + uint8_t paging_direct_indication_differentation_flag; + uint8_t direct_indication; + uint8_t dci_subframe_repetition_number; + uint8_t total_dci_length_including_padding; +} fapi_dl_config_npdcch_rel13_pdu_t; + +typedef struct { + fapi_dl_config_npdcch_rel13_pdu_t rel13_pdu; +} fapi_dl_config_npdcch_pdu_t; + +typedef struct { + uint16_t length; + uint16_t pdu_index; + uint8_t start_symbol; + uint8_t rnti_type; + uint16_t rnti; + uint16_t resource_assignment; + uint16_t repetition_number; + uint8_t modulation; + uint8_t number_of_subframes_for_resource_assignment; + uint8_t scrambling_sequence_initialization_cinit; + uint16_t sf_idx; + uint8_t nrs_antenna_ports_assumed_by_the_ue; +} fapi_dl_config_ndlsch_rel13_pdu_t; + +typedef struct { + fapi_dl_config_ndlsch_rel13_pdu_t rel13_pdu; +} fapi_dl_config_ndlsch_pdu_t; + +typedef struct { + uint8_t pdu_type; + uint8_t pdu_size; + union + { + fapi_dl_config_dci_pdu_t dci_dl_pdu; + fapi_dl_config_bch_pdu_t bch_pdu; + fapi_dl_config_mch_pdu_t mch_pdu; + fapi_dl_config_dlsch_pdu_t dlsch_pdu; + fapi_dl_config_pch_pdu_t pch_pdu; + fapi_dl_config_prs_pdu_t prs_pdu; + fapi_dl_config_csi_rs_pdu_t csirs_pdu; + fapi_dl_config_edpcch_pdu_t edpcch_pdu; + fapi_dl_config_mdpcch_pdu_t mdpcch_pdu; + fapi_dl_config_nbch_pdu_t nbch_pdu; + fapi_dl_config_npdcch_pdu_t npdcch_pdu; + fapi_dl_config_ndlsch_pdu_t ndlsch_pdu; + }; +} fapi_dl_config_req_pdu_t; + +typedef struct { + uint8_t number_of_pdcch_ofdm_symbols; + uint8_t number_of_dcis; + uint16_t number_of_pdus; + uint8_t number_of_pdsch_rntis; + uint16_t transmission_power_for_pcfich; + fapi_dl_config_req_pdu_t pdus[32]; +} fapi_dl_config_req_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + uint16_t length; + fapi_dl_config_req_body_t body; +} fapi_dl_config_req_t; + +typedef struct { + uint32_t handle; + uint16_t size; + uint16_t rnti; + uint8_t resource_block_start; + uint8_t number_of_resource_blocks; + uint8_t modulation_type; + uint8_t cyclic_shift_2_for_drms; + uint8_t frequency_hopping_enabled_flag; + uint8_t frequency_hopping_bits; + uint8_t new_data_indication; + uint8_t redundancy_version; + uint8_t harq_process_number; + uint8_t ul_tx_mode; + uint8_t current_tx_nb; + uint8_t n_srs; +} fapi_ul_config_req_ulsch_rel8_pdu_t; + +typedef struct { + uint8_t resource_allocation_type; + uint32_t resource_block_coding; + uint8_t transport_blocks; + uint8_t transmission_scheme; + uint8_t number_of_layers; + uint8_t codebook_index; + uint8_t disable_sequence_hopping_flag; +} fapi_ul_config_req_ulsch_rel10_pdu_t; + +typedef struct { + uint8_t virtual_cell_id_enabled_flag; + uint16_t npusch_identity; + uint8_t dmrs_config_flag; + uint16_t ndmrs_csh_identity; +} fapi_ul_config_req_ulsch_rel11_pdu_t; + +typedef struct { + uint8_t ue_type; + uint16_t total_number_of_repetitions; + uint16_t repetition_number; + uint16_t initial_transmission_sf_io; + uint8_t empty_symbols_due_to_re_tunning; +} fapi_ul_config_req_ulsch_rel13_pdu_t; + +typedef struct { + fapi_ul_config_req_ulsch_rel8_pdu_t rel8_pdu; + fapi_ul_config_req_ulsch_rel10_pdu_t rel10_pdu; + fapi_ul_config_req_ulsch_rel11_pdu_t rel11_pdu; + fapi_ul_config_req_ulsch_rel13_pdu_t rel13_pdu; +} fapi_ul_config_req_ulsch_pdu_t; + +typedef struct { + uint8_t dl_cqi_pmi_size_rank_1; + uint8_t dl_cqi_pmi_size_rank_greater_1; + uint8_t ri_size; + uint8_t delta_offset_cqi; + uint8_t delta_offset_ri; +} fapi_ul_config_cqi_ri_rel8_information_t; + +typedef struct { + uint8_t dl_cqi_pmi_ri_size; + uint8_t control_type; +} fapi_ul_config_periodic_cqi_pmi_ri_report_t; + +typedef struct { + uint8_t number_of_cc; + struct { + uint8_t ri_size; + uint8_t dl_cqi_pmi_size; + } cc[5]; +} fapi_ul_config_aperiodic_cqi_pmi_ri_report_t; + +typedef struct { + uint8_t report_type; + uint8_t delta_offset_cqi; + uint8_t delta_offset_ri; + union { + fapi_ul_config_periodic_cqi_pmi_ri_report_t periodic_cqi_pmi_ri_report; + fapi_ul_config_aperiodic_cqi_pmi_ri_report_t aperiodic_cqi_pmi_ri_report; + }; +} fapi_ul_config_cqi_ri_rel9_information_t; + +typedef struct { + uint16_t dl_cqi_pmi_ri_size_2; +} fapi_ul_config_periodic_cqi_pmi_ri_report_re13_t; + +typedef struct { +} fapi_ul_config_aperiodic_cqi_pmi_ri_report_re13_t; + + +typedef struct { + union { + fapi_ul_config_periodic_cqi_pmi_ri_report_re13_t periodic_cqi_pmi_ri_report; + fapi_ul_config_aperiodic_cqi_pmi_ri_report_re13_t aperiodic_cqi_pmi_ri_report; + }; +} fapi_ul_config_cqi_ri_rel13_information_t; + +typedef struct { + fapi_ul_config_cqi_ri_rel8_information_t rel8_info; + fapi_ul_config_cqi_ri_rel9_information_t rel9_cqi_ri_info; + fapi_ul_config_cqi_ri_rel13_information_t rel13_cqi_ri_info; +} fapi_ul_config_cqi_ri_information_t; + +typedef struct { + uint8_t n_srs_initial; + uint8_t initial_number_of_resource_blocks; +} fapi_ul_config_init_tx_rel8_params_t; + +typedef struct { + fapi_ul_config_init_tx_rel8_params_t rel8_params; +} fapi_ul_config_init_tx_params_t; + +typedef struct { + uint8_t harq_size; + uint8_t delta_offset_harq; + uint8_t ack_nack_mode; +} fapi_ul_config_harq_rel10_information_t; + +typedef struct { + uint16_t harq_size_2; + uint8_t delta_offset_harq_2; +} fapi_ul_config_harq_rel13_information_t; + +typedef struct { + fapi_ul_config_harq_rel10_information_t rel10_info; + fapi_ul_config_harq_rel13_information_t rel13_info; +} fapi_ul_config_harq_information_t; + +typedef struct { + uint32_t handle; + uint16_t rnti; +} fapi_ul_config_req_ue_rel8_info_t; + +typedef struct { + uint8_t virtual_cell_id_enabled_flag; + uint16_t npusch_identity; +} fapi_ul_config_req_ue_rel11_info_t; + +typedef struct { + uint8_t ue_type; + uint8_t empty_symbols; + uint16_t total_number_of_repetitions; + uint16_t repetition_number; +} fapi_ul_config_req_ue_rel13_info_t; + +typedef struct { + fapi_ul_config_req_ue_rel8_info_t rel8_info; + fapi_ul_config_req_ue_rel11_info_t rel11_info; + fapi_ul_config_req_ue_rel13_info_t rel13_info; +} fapi_ul_config_req_ue_info_t; + +typedef struct { + uint16_t pucch_index; + uint8_t dl_cqi_pmi_size; +} fapi_ul_config_req_cqi_rel8_info_t; + +typedef struct { + uint8_t number_of_pucch_resource; + uint16_t pucch_index_p1; +} fapi_ul_config_req_cqi_rel10_info_t; + +typedef struct { + uint8_t csi_mode; + uint16_t dl_cqi_pmi_size_2; + uint8_t starting_prb; + uint8_t n_prb; + uint8_t cdm_index; + uint8_t n_srs; +} fapi_ul_config_req_cqi_rel13_info_t; + +typedef struct { + fapi_ul_config_req_cqi_rel8_info_t rel8_info; + fapi_ul_config_req_cqi_rel10_info_t rel10_info; + fapi_ul_config_req_cqi_rel13_info_t rel13_info; +} fapi_ul_config_req_cqi_info_t; + +typedef struct { + uint16_t pucch_index; +} fapi_ul_config_req_sr_rel8_info_t; + +typedef struct { + uint8_t number_of_pucch_resources; + uint16_t pucch_index_p1; +} fapi_ul_config_req_sr_rel10_info_t; + +typedef struct { + fapi_ul_config_req_sr_rel8_info_t rel8_info; + fapi_ul_config_req_sr_rel10_info_t rel10_info; +} fapi_ul_config_req_sr_info_t; + +typedef struct { + uint8_t harq_size; + uint8_t ack_nack_mode; + uint8_t number_of_pucch_resources; + uint16_t n_pucch_1_0; + uint16_t n_pucch_1_1; + uint16_t n_pucch_1_2; + uint16_t n_pucch_1_3; +} fapi_ul_config_req_harq_rel10_tdd_info_t; + +typedef struct { + uint16_t n_pucch_1_0; + uint8_t harq_size; +} fapi_ul_config_req_harq_rel8_fdd_info_t; + +typedef struct { + uint8_t harq_size; + uint8_t ack_nack_mode; + uint8_t number_of_pucch_resources; + uint16_t n_pucch_1_0; + uint16_t n_pucch_1_1; + uint16_t n_pucch_1_2; + uint16_t n_pucch_1_3; +} fapi_ul_config_req_harq_rel9_fdd_info_t; + +typedef struct { + uint8_t num_ant_ports; + uint16_t n_pucch_2_0; + uint16_t n_pucch_2_1; + uint16_t n_pucch_2_2; + uint16_t n_pucch_2_3; +} fapi_ul_config_req_harq_rel11_fdd_tdd_info_t; + +typedef struct { + uint16_t harq_size_2; + uint8_t starting_prb; + uint8_t n_prb; + uint8_t cdm_index; + uint8_t n_srs; +} fapi_ul_config_req_harq_rel13_fdd_tdd_info_t; + +typedef struct { + fapi_ul_config_req_harq_rel10_tdd_info_t rel10_tdd_info; + fapi_ul_config_req_harq_rel8_fdd_info_t rel8_fdd_info; + fapi_ul_config_req_harq_rel9_fdd_info_t rel9_fdd_info; + fapi_ul_config_req_harq_rel11_fdd_tdd_info_t rel11_fdd_tdd_info; + fapi_ul_config_req_harq_rel13_fdd_tdd_info_t rel13_fdd_tdd_info; +} fapi_ul_config_req_harq_info_t; + +typedef struct { + fapi_ul_config_req_ulsch_pdu_t ulsch_pdu; + fapi_ul_config_cqi_ri_information_t cqi_ri_info; + fapi_ul_config_init_tx_params_t init_tx_params; +} fapi_ul_config_req_ulsch_cqi_ri_pdu_t; + +typedef struct { + fapi_ul_config_req_ulsch_pdu_t ulsch_pdu; + fapi_ul_config_harq_information_t harq_info; + fapi_ul_config_init_tx_params_t init_tx_params; +} fapi_ul_config_req_ulsch_harq_pdu_t; + +typedef struct { + fapi_ul_config_req_ulsch_pdu_t ulsch_pdu; + fapi_ul_config_cqi_ri_information_t cqi_ri_info; + fapi_ul_config_harq_information_t harq_info; + fapi_ul_config_init_tx_params_t init_tx_params; +} fapi_ul_config_req_ulsch_cqi_harq_pdu_t; + +typedef struct { + fapi_ul_config_req_ue_info_t ue_info; + fapi_ul_config_req_cqi_info_t cqi_info; +} fapi_ul_config_req_uci_cqi_pdu_t; + +typedef struct { + fapi_ul_config_req_ue_info_t ue_info; + fapi_ul_config_req_sr_info_t sr_info; +} fapi_ul_config_req_uci_sr_pdu_t; + +typedef struct { + fapi_ul_config_req_ue_info_t ue_info; + fapi_ul_config_req_harq_info_t harq_info; +} fapi_ul_config_req_uci_harq_pdu_t; + +typedef struct { + fapi_ul_config_req_ue_info_t ue_info; + fapi_ul_config_req_sr_info_t sr_info; + fapi_ul_config_req_harq_info_t harq_info; +} fapi_ul_config_req_uci_sr_harq_pdu_t; + +typedef struct { + fapi_ul_config_req_ue_info_t ue_info; + fapi_ul_config_req_cqi_info_t cqi_info; + fapi_ul_config_req_harq_info_t harq_info; +} fapi_ul_config_req_uci_cqi_harq_pdu_t; + +typedef struct { + fapi_ul_config_req_ue_info_t ue_info; + fapi_ul_config_req_cqi_info_t cqi_info; + fapi_ul_config_req_sr_info_t sr_info; +} fapi_ul_config_req_uci_cqi_sr_pdu_t; + +typedef struct { + fapi_ul_config_req_ue_info_t ue_info; + fapi_ul_config_req_cqi_info_t cqi_info; + fapi_ul_config_req_sr_info_t sr_info; + fapi_ul_config_req_harq_info_t harq_info; +} fapi_ul_config_req_uci_cqi_sr_harq_pdu_t; + +typedef struct { + uint32_t handle; + uint16_t size; + uint16_t rnti; + uint8_t srs_bandwidth; + uint8_t frqeuency_domain_position; + uint8_t srs_hopping_bandwidth; + uint8_t transmission_comb; + uint16_t srs_config_index; + uint8_t sounding_reference_cyclic_shift; +} fapi_ul_config_req_srs_rel8_pdu_t; + +typedef struct { + uint8_t antenna_port; +} fapi_ul_config_req_srs_rel10_pdu_t; + +typedef struct { + uint8_t number_of_combs; +} fapi_ul_config_req_srs_rel13_pdu_t; + +typedef struct { + fapi_ul_config_req_srs_rel8_pdu_t rel8_pdu; + fapi_ul_config_req_srs_rel10_pdu_t rel10_pdu; + fapi_ul_config_req_srs_rel13_pdu_t rel13_pdu; +} fapi_ul_config_req_srs_pdu_t; + +typedef struct { + fapi_ul_config_req_ue_info_t ue_info; +} fapi_ul_config_req_harq_buffer_pdu_t; + +typedef struct { + fapi_ul_config_req_ulsch_pdu_t ulsch_pdu; + fapi_ul_config_req_cqi_info_t csi_information; +} fapi_ul_config_req_ulsch_uci_csi_pdu_t; + +typedef struct { + fapi_ul_config_req_ulsch_pdu_t ulsch_pdu; + fapi_ul_config_req_harq_info_t harq_information; +} fapi_ul_config_req_ulsch_uci_harq_pdu_t; + +typedef struct { + fapi_ul_config_req_ulsch_pdu_t ulsch_pdu; + fapi_ul_config_req_cqi_info_t csi_information; + fapi_ul_config_req_harq_info_t harq_information; +} fapi_ul_config_req_ulsch_csi_uci_harq_pdu_t; + +typedef struct { + uint8_t harq_ack_resource; +} fapi_ul_config_req_nb_harq_rel13_info_t; + +typedef struct { + fapi_ul_config_req_nb_harq_rel13_info_t nb_harq_pdu_rel13; +} fapi_ul_config_req_nb_harq_info_t; + +typedef struct { + uint8_t nulsch_format; + uint32_t handle; + uint16_t size; + uint16_t rnti; + uint8_t subcarrier_indication; + uint8_t resource_assignment; + uint8_t mcs; + uint8_t redudancy_version; + uint8_t repetition_number; + uint8_t new_data_indication; + uint8_t n_srs; + uint16_t scrambling_sequence_initialization_cinit; + uint16_t sf_idx; + fapi_ul_config_req_ue_info_t ue_information; + fapi_ul_config_req_nb_harq_info_t nb_harq_information; +} fapi_ul_config_req_nulsch_rel13_pdu_t; + +typedef struct { + fapi_ul_config_req_nulsch_rel13_pdu_t nulsch_pdu_rel13; +} fapi_ul_config_req_nulsch_pdu_t; + +typedef struct { + uint8_t nprach_config_0; + uint8_t nprach_config_1; + uint8_t nprach_config_2; +} fapi_ul_config_req_nrach_rel13_pdu_t; + +typedef struct { + fapi_ul_config_req_nrach_rel13_pdu_t nrach_pdu_rel13; +} fapi_ul_config_req_nrach_pdu_t; + +typedef struct { + uint8_t pdu_type; + uint8_t pdu_size; + union + { + fapi_ul_config_req_ulsch_pdu_t ulsch_pdu; + fapi_ul_config_req_ulsch_cqi_ri_pdu_t ulsch_cqi_ri_pdu; + fapi_ul_config_req_ulsch_harq_pdu_t ulsch_harq_pdu; + fapi_ul_config_req_ulsch_cqi_harq_pdu_t ulsch_cqi_harq_pdu; + fapi_ul_config_req_uci_cqi_pdu_t uci_cqi_pdu; + fapi_ul_config_req_uci_sr_pdu_t uci_sr_pdu; + fapi_ul_config_req_uci_harq_pdu_t uci_harq_pdu; + fapi_ul_config_req_uci_sr_harq_pdu_t uci_sr_harq_pdu; + fapi_ul_config_req_uci_cqi_harq_pdu_t uci_cqi_harq_pdu; + fapi_ul_config_req_uci_cqi_sr_pdu_t uci_cqi_sr_pdu; + fapi_ul_config_req_uci_cqi_sr_harq_pdu_t uci_cqi_sr_harq_pdu; + fapi_ul_config_req_srs_pdu_t srs_pdu; + fapi_ul_config_req_harq_buffer_pdu_t harq_buffer_pdu; + fapi_ul_config_req_ulsch_uci_csi_pdu_t ulsch_uci_csi_pdu; + fapi_ul_config_req_ulsch_uci_harq_pdu_t ulsch_uci_harq_pdu; + fapi_ul_config_req_ulsch_csi_uci_harq_pdu_t ulsch_csi_uci_harq_pdu; + fapi_ul_config_req_nulsch_pdu_t nulsch_pdu; + fapi_ul_config_req_nrach_pdu_t nrach_pdu; + }; +} fapi_ul_config_req_pdu_t; + +typedef struct { + uint8_t number_of_pdus; + uint8_t rach_prach_frequency_resources; + uint8_t srs_present; + fapi_ul_config_req_pdu_t* pdus; +} fapi_ul_config_req_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + uint16_t length; + fapi_ul_config_req_body_t body; +} fapi_ul_config_req_t; + +typedef struct { + uint8_t dci_format; + uint8_t cce_index; + uint8_t aggregation_level; + uint8_t rnti; + uint8_t resource_block_start; + uint8_t number_of_resource_blocks; + uint8_t mcs_1; + uint8_t cyclic_shift_2_for_drms; + uint8_t frequency_hopping_enabled_flag; + uint8_t frequency_hopping_flags; + uint8_t new_data_indication_1; + uint8_t ue_tx_antenna_selection; + uint8_t tpc; + uint8_t cqi_csi_request; + uint8_t ul_index; + uint8_t dl_assignment_index; + uint32_t tpc_bitmap; + uint16_t transmission_power; +} fapi_hi_dci0_req_dci0_rel8_pdu_t; + +typedef struct { + uint8_t cross_carrier_scheduling_flag; + uint8_t carrier_indicator; + uint8_t size_of_cqi_csi_feild; + uint8_t srs_flag; + uint8_t srs_request; + uint8_t resource_allocation_flag; + uint8_t resource_allocation_type; + uint32_t resource_block_coding; + uint8_t mcs_2; + uint8_t new_data_indication_2; + uint8_t number_of_antenna_ports; + uint8_t tpmi; + uint8_t total_dci_length_including_padding; + uint8_t n_ul_rb; +} fapi_hi_dci0_req_dci0_rel10_pdu_t; + +typedef struct { + uint8_t pscch_resource; + uint8_t time_resource_pattern; +} fapi_hi_dci0_req_dci0_rel12_pdu_t; + +typedef struct { + fapi_hi_dci0_req_dci0_rel8_pdu_t rel8_pdu; + fapi_hi_dci0_req_dci0_rel10_pdu_t rel10_pdu; + fapi_hi_dci0_req_dci0_rel12_pdu_t rel12_pdu; +} fapi_hi_dci0_req_dci0_pdu_t; + +typedef struct { + uint8_t resource_block_start; + uint8_t cyclic_shift_2_for_drms; + uint8_t hi_value; + uint8_t i_phich; + uint16_t transmission_power; +} fapi_hi_dci0_req_hi_rel8_pdu_t; + +typedef struct { + uint8_t flag_tb2; + uint8_t hi_value_2; +} fapi_hi_dci0_req_hi_rel10_pdu_t; + +typedef struct { + fapi_hi_dci0_req_hi_rel8_pdu_t rel8_pdu; + fapi_hi_dci0_req_hi_rel10_pdu_t rel10_pdu; +} fapi_hi_dci0_req_hi_pdu_t; + +typedef struct { + fapi_dl_config_dci_rel8_pdu_t edpcch_dci_pdu_rel8; + fapi_dl_config_dci_rel10_pdu_t edpcch_dci_pdu_rel10; + fapi_dl_config_edpcch_rel11_params_t edpcch_parameters_rel11; +} fapi_hi_dci0_req_epdcch_dci_ul_pdu_t; + +typedef struct { + uint8_t mpdcch_narrowband; + uint8_t number_of_prb_pairs; + uint8_t resource_block_assignment; + uint8_t mpdcch_transmission_type; + uint8_t start_symbol; + uint8_t ecce_index; + uint8_t aggreagation_level; + uint8_t rnti_type; + uint16_t rnti; + uint8_t ce_mode; + uint16_t drms_scrambling_init; + uint16_t initial_transmission_sf_io; + uint16_t transmission_power; + uint8_t dci_format; + uint8_t resource_block_start; + uint8_t number_of_resource_blocks; + uint8_t mcs; + uint8_t pusch_repetition_levels; + uint8_t frequency_hopping_flag; + uint8_t new_data_indication; + uint8_t harq_process; + uint8_t redudency_version; + uint8_t tpc; + uint8_t csi_request; + uint8_t ul_inex; + uint8_t dai_presence_flag; + uint8_t dl_assignment_index; + uint8_t srs_request; + uint8_t dci_subframe_repetition_number; + uint32_t tcp_bitmap; + uint8_t total_dci_length_include_padding; + uint8_t number_of_tx_antenna_ports; + uint16_t precoding_value[FAPI_MAX_ANTENNA_PORT_COUNT]; +} fapi_hi_dci0_req_mpdcch_dci_ul_rel13_pdu_t; + +typedef struct { + fapi_hi_dci0_req_mpdcch_dci_ul_rel13_pdu_t mpdcch_dci_pdu_rel13; +} fapi_hi_dci0_req_mpdcch_dci_ul_pdu_t; + +typedef struct { + uint8_t ncce_index; + uint8_t aggregation_level; + uint8_t start_symbol; + uint16_t rnti; + uint8_t scrambling_reinitialization_batch_index; + uint8_t nrs_antenna_ports_assumed_by_the_ue; + uint8_t subcarrier_indication; + uint8_t resource_assignment; + uint8_t scheduling_delay; + uint8_t mcs; + uint8_t redudancy_version; + uint8_t repetition_number; + uint8_t new_data_indicator; + uint8_t dci_subframe_repetition_number; +} fapi_hi_dci0_req_npdcch_dci_ul_rel13_pdu_t; + +typedef struct { + fapi_hi_dci0_req_npdcch_dci_ul_rel13_pdu_t npdcch_dci_pdu_rel13; +} fapi_hi_dci0_req_npdcch_dci_ul_pdu_t; + +typedef struct { + uint8_t pdu_type; + uint8_t pdu_size; + union + { + fapi_hi_dci0_req_hi_pdu_t hi_pdu; + fapi_hi_dci0_req_dci0_pdu_t dci0_pdu; + fapi_hi_dci0_req_epdcch_dci_ul_pdu_t edpcch_dci_ul_pdu; + fapi_hi_dci0_req_mpdcch_dci_ul_pdu_t mdpcch_dci_ul_pdu; + fapi_hi_dci0_req_npdcch_dci_ul_pdu_t ndpcch_dci_ul_pdu; + }; +} fapi_hi_dci0_req_pdu_t; + +typedef struct { + uint16_t sfn_sf; + uint8_t number_of_dci; + uint8_t number_of_hi; + fapi_hi_dci0_req_pdu_t* pdus; +} fapi_hi_dci0_req_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + fapi_hi_dci0_req_body_t body; +} fapi_hi_dci0_req_t; + +typedef struct { + uint16_t tag; + uint16_t length; + uint32_t* value; +} fapi_tx_req_pdu_tlv_t; + +typedef struct { + uint16_t pdu_length; + uint16_t pdu_index; + uint32_t num_tlv; + fapi_tx_req_pdu_tlv_t tlvs[32]; +} fapi_tx_req_pdu_t; + +typedef struct { + uint16_t number_of_pdus; + fapi_tx_req_pdu_t* pdus; +} fapi_tx_req_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + fapi_tx_req_body_t body; +} fapi_tx_req_t; + +typedef struct { + uint32_t handle; + uint32_t mp_cca; + uint32_t n_cca; + uint32_t offset; + uint32_t lte_txop_sf; + uint16_t txop_sfn_sf_end; + uint32_t lbt_mode; +} fapi_lbt_pdsch_req_rel13_pdu_t; + +typedef struct { + fapi_lbt_pdsch_req_rel13_pdu_t rel13_pdu; +} fapi_lbt_pdsch_req_pdu_t; + +typedef struct { + uint32_t handle; + uint32_t offset; + uint16_t sfn_sf_end; + uint32_t lbt_mode; +} fapi_lbt_drs_req_rel13_pdu_t; + +typedef struct { + fapi_lbt_drs_req_rel13_pdu_t rel13_pdu; +} fapi_lbt_drs_req_pdu_t; + +typedef struct { + uint8_t pdu_type; + uint8_t pdu_size; + union { + fapi_lbt_pdsch_req_pdu_t lbt_pdsch_req_pdu; + fapi_lbt_drs_req_pdu_t lbt_drs_req_pdu; + }; +} fapi_lbt_dl_config_req_pdu_t; + +typedef struct { + uint16_t number_of_pdus; + fapi_lbt_dl_config_req_pdu_t pdus[32]; +} fapi_lbt_dl_config_req_body_t; + +typedef struct { + fapi_header_t header; + uint16_t sfn_sf; + uint16_t length; + fapi_lbt_dl_config_req_body_t body; +} fapi_lbt_dl_config_req_t; + +//------------------------------------------------------------------------------ + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/nfapi/open-nFAPI/pnf_sim/inc/fapi_stub.h b/nfapi/open-nFAPI/pnf_sim/inc/fapi_stub.h new file mode 100644 index 0000000000..10df46e7ab --- /dev/null +++ b/nfapi/open-nFAPI/pnf_sim/inc/fapi_stub.h @@ -0,0 +1,76 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _FAPI_STUB_H_ +#define _FAPI_STUB_H_ + +#include "fapi_interface.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef struct fapi fapi_t; + +typedef struct fapi { + void* user_data; +} fapi_t; + +typedef struct { + int (*fapi_param_response)(fapi_t* fapi, fapi_param_resp_t* resp); + int (*fapi_config_response)(fapi_t* fapi, fapi_config_resp_t* resp); + + int (*fapi_subframe_ind)(fapi_t* fapi, fapi_subframe_ind_t* ind); + + int (*fapi_harq_ind)(fapi_t* fapi, fapi_harq_ind_t* ind); + int (*fapi_crc_ind)(fapi_t* fapi, fapi_crc_ind_t* ind); + int (*fapi_rx_ulsch_ind)(fapi_t* fapi, fapi_rx_ulsch_ind_t* ind); + int (*fapi_rx_cqi_ind)(fapi_t* fapi, fapi_rx_cqi_ind_t* ind); + int (*fapi_rx_sr_ind)(fapi_t* fapi, fapi_rx_sr_ind_t* ind); + int (*fapi_rach_ind)(fapi_t* fapi, fapi_rach_ind_t* ind); + int (*fapi_srs_ind)(fapi_t* fapi, fapi_srs_ind_t* ind); + + int (*fapi_lbt_dl_ind)(fapi_t* fapi, fapi_lbt_dl_ind_t* ind); + int (*fapi_nb_harq_ind)(fapi_t* fapi, fapi_nb_harq_ind_t* ind); + int (*fapi_nrach_ind)(fapi_t* fapi, fapi_nrach_ind_t* ind); + +} fapi_cb_t; + +typedef struct { + + uint16_t duplex_mode; + uint16_t dl_channel_bw_support; + uint16_t ul_channel_bw_support; +} fapi_config_t; + +fapi_t* fapi_create(fapi_cb_t* callbacks, fapi_config_t* config); + +void fapi_start_data(fapi_t* fapi, unsigned rx_port, const char* tx_address, unsigned tx_port); + +int fapi_param_request(fapi_t* fapi, fapi_param_req_t* req); +int fapi_config_request(fapi_t* fapi, fapi_config_req_t* req); +int fapi_start_request(fapi_t* fapi, fapi_start_req_t* req); + +int fapi_dl_config_request(fapi_t* fapi, fapi_dl_config_req_t* req); +int fapi_ul_config_request(fapi_t* fapi, fapi_ul_config_req_t* req); +int fapi_hi_dci0_request(fapi_t* fapi, fapi_hi_dci0_req_t* req); +int fapi_tx_request(fapi_t* fapi, fapi_tx_req_t* req); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/nfapi/open-nFAPI/pnf_sim/src/fapi_stub.cpp b/nfapi/open-nFAPI/pnf_sim/src/fapi_stub.cpp new file mode 100644 index 0000000000..df0ca12305 --- /dev/null +++ b/nfapi/open-nFAPI/pnf_sim/src/fapi_stub.cpp @@ -0,0 +1,642 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fapi_stub.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct phy_pdu +{ + phy_pdu() : buffer_len(1500), buffer(0), len(0) + { + buffer = (char*) malloc(buffer_len); + } + + virtual ~phy_pdu() + { + free(buffer); + } + + + unsigned buffer_len; + char* buffer; + unsigned len; +}; + +class fapi_private +{ + std::mutex mutex; + std::queue rx_buffer; + + std::queue free_store; + public: + + fapi_private() + : byte_count(0), tick(0), first_dl_config(false) + { + } + + phy_pdu* allocate_phy_pdu() + { + phy_pdu* pdu = 0; + mutex.lock(); + if(free_store.empty()) + { + pdu = new phy_pdu(); + } + else + { + pdu = free_store.front(); + free_store.pop(); + } + mutex.unlock(); + return pdu; + } + + void release_phy_pdu(phy_pdu* pdu) + { + mutex.lock(); + free_store.push(pdu); + mutex.unlock(); + } + + bool rx_buffer_empty() + { + bool empty; + mutex.lock(); + empty = rx_buffer.empty(); + mutex.unlock(); + + return empty; + } + + + void push_rx_buffer(phy_pdu* buff) + { + mutex.lock(); + rx_buffer.push(buff); + mutex.unlock(); + } + + phy_pdu* pop_rx_buffer() + { + phy_pdu* buff = 0; + mutex.lock(); + if(!rx_buffer.empty()) + { + buff = rx_buffer.front(); + rx_buffer.pop(); + } + mutex.unlock(); + return buff; + } + + uint32_t byte_count; + uint32_t tick; + bool first_dl_config; + +}; + +extern "C" +{ + typedef struct fapi_internal + { + fapi_t _public; + + fapi_cb_t callbacks; + + uint8_t state; + fapi_config_t config; + + int rx_sock; + int tx_sock; + struct sockaddr_in tx_addr; + + uint32_t tx_byte_count; + uint32_t tick; + + fapi_private* fapi; + + } fapi_internal_t; +} + +extern void set_thread_priority(int); +/* +{ + pthread_attr_t ptAttr; + + struct sched_param schedParam; + schedParam.__sched_priority = 79; + sched_setscheduler(0, SCHED_RR, &schedParam); + + pthread_attr_setschedpolicy(&ptAttr, SCHED_RR); + + pthread_attr_setinheritsched(&ptAttr, PTHREAD_EXPLICIT_SCHED); + + struct sched_param thread_params; + thread_params.sched_priority = 20; + pthread_attr_setschedparam(&ptAttr, &thread_params); +} +*/ + +void send_uplink_indications(fapi_internal_t* instance, uint16_t sfn_sf) +{ + fapi_harq_ind_t harq_ind; + (instance->callbacks.fapi_harq_ind)(&(instance->_public), &harq_ind); + + fapi_crc_ind_t crc_ind; + crc_ind.header.message_id = FAPI_CRC_INDICATION; + crc_ind.header.length = 0; //??; + crc_ind.sfn_sf = sfn_sf; + crc_ind.body.number_of_crcs = 1; + crc_ind.body.pdus[0].rx_ue_info.handle = 0; //?? + crc_ind.body.pdus[0].rx_ue_info.rnti = 0; //?? + crc_ind.body.pdus[0].rel8_pdu.crc_flag = 1; + + (instance->callbacks.fapi_crc_ind)(&(instance->_public), &crc_ind); + + if(!instance->fapi->rx_buffer_empty()) + { + fapi_rx_ulsch_ind_t rx_ind; + memset(&rx_ind, 0, sizeof(rx_ind)); + rx_ind.header.message_id = FAPI_RX_ULSCH_INDICATION; + rx_ind.sfn_sf = sfn_sf; + + + phy_pdu* buff = 0; + int i = 0; + std::list free_list; + do + { + buff = instance->fapi->pop_rx_buffer(); + if(buff != 0) + { + if(buff->len == 0) + { + printf("[FAPI] Buffer length = 0\n"); + } + + rx_ind.body.pdus[i].rx_ue_info.handle = 0xDEADBEEF; + rx_ind.body.pdus[i].rx_ue_info.rnti = 0x4242; + + rx_ind.body.pdus[i].rel8_pdu.length = buff->len; + //rx_ind.pdus[i].rel8_pdu.data_offset; + //rx_ind.pdus[i].rel8_pdu.ul_cqi; + //rx_ind.pdus[i].rel8_pdu.timing_advance; + + rx_ind.body.data[i] = buff->buffer; + + rx_ind.body.number_of_pdus++; + i++; + + instance->fapi->byte_count += buff->len; + + free_list.push_back(buff); + } + }while(buff != 0 && i < 8); + + (instance->callbacks.fapi_rx_ulsch_ind)(&(instance->_public), &rx_ind); + + for(phy_pdu* pdu : free_list) + { + instance->fapi->release_phy_pdu(pdu); + //free(tx_req.tx_request_body.tx_pdu_list[j].segments[0].segment_data); + } + } + else + { + fapi_rx_ulsch_ind_t rx_ind; + memset(&rx_ind, 0, sizeof(rx_ind)); + rx_ind.header.message_id = FAPI_RX_ULSCH_INDICATION; + rx_ind.sfn_sf = sfn_sf; + (instance->callbacks.fapi_rx_ulsch_ind)(&(instance->_public), &rx_ind); + } + + + fapi_rx_cqi_ind_t cqi_ind; + cqi_ind.sfn_sf = sfn_sf; + (instance->callbacks.fapi_rx_cqi_ind)(&(instance->_public), &cqi_ind); + + fapi_rx_sr_ind_t sr_ind; + sr_ind.sfn_sf = sfn_sf; + (instance->callbacks.fapi_rx_sr_ind)(&(instance->_public), &sr_ind); + + fapi_rach_ind_t rach_ind; + rach_ind.sfn_sf = sfn_sf; + (instance->callbacks.fapi_rach_ind)(&(instance->_public), &rach_ind); + + fapi_srs_ind_t srs_ind; + srs_ind.sfn_sf = sfn_sf; + (instance->callbacks.fapi_srs_ind)(&(instance->_public), &srs_ind); + /* + nfapi_lbt_dl_indication_t lbt_ind; + memset(&lbt_ind, 0, sizeof(lbt_ind)); + lbt_ind.header.message_id = NFAPI_LBT_DL_INDICATION; + lbt_ind.header.phy_id = config->phy_id; + lbt_ind.sfn_sf = sfn_sf; + nfapi_pnf_p7_lbt_dl_ind(config, &lbt_ind); + + vendor_ext_p7_ind ve_p7_ind; + memset(&ve_p7_ind, 0, sizeof(ve_p7_ind)); + ve_p7_ind.header.message_id = P7_VENDOR_EXT_IND; + ve_p7_ind.header.phy_id = config->phy_id; + ve_p7_ind.error_code = NFAPI_MSG_OK; + nfapi_pnf_p7_vendor_extension(config, &(ve_p7_ind.header)); + */ + + fapi_nb_harq_ind_t nb_harq_ind; + nb_harq_ind.sfn_sf = sfn_sf; + (instance->callbacks.fapi_nb_harq_ind)(&(instance->_public), &nb_harq_ind); + + fapi_nrach_ind_t nrach_ind; + nrach_ind.sfn_sf = sfn_sf; + (instance->callbacks.fapi_nrach_ind)(&(instance->_public), &nrach_ind); + +} + +void* fapi_thread_start(void* ptr) +{ + set_thread_priority(81); + + fapi_internal_t* instance = (fapi_internal_t*)ptr; + uint16_t sfn_sf_dec = 0; + uint32_t last_tv_usec = 0; + uint32_t last_tv_sec = 0; + + uint32_t millisec; + uint32_t last_millisec = -1; + uint16_t catchup = 0; + + while(1) + { + // get the time + struct timeval sf_start; + (void)gettimeofday(&sf_start, NULL); + + uint16_t sfn_sf = ((((sfn_sf_dec) / 10) << 4) | (((sfn_sf_dec) - (((sfn_sf_dec) / 10) * 10)) & 0xF)); + // increment the sfn/sf - for the next subframe + sfn_sf_dec++; + if(sfn_sf_dec > 10239) + sfn_sf_dec = 0; + + + fapi_subframe_ind_t ind; + ind.sfn_sf = sfn_sf; + + if(instance->fapi->first_dl_config) + send_uplink_indications(instance, sfn_sf); + + if(instance->tick == 1000) + { + if(instance->tx_byte_count > 0) + { + printf("[FAPI] Tx rate %d bytes/sec\n", instance->tx_byte_count); + instance->tx_byte_count = 0; + } + + instance->tick = 0; + } + + instance->tick++; + + (instance->callbacks.fapi_subframe_ind)(&(instance->_public), &ind); + + { + phy_pdu* pdu = instance->fapi->allocate_phy_pdu(); + int len = recvfrom(instance->rx_sock, pdu->buffer, pdu->buffer_len, MSG_DONTWAIT, 0, 0); + if(len > 0) + { + pdu->len = len; + instance->fapi->push_rx_buffer(pdu); + } + else + { + instance->fapi->release_phy_pdu(pdu); + } + } + + + if(catchup) + { + catchup--; + } + else + { + struct timespec now_ts; + struct timespec sleep_ts; + struct timespec sleep_rem_ts; + + // get the current time + clock_gettime(CLOCK_MONOTONIC, &now_ts); + + + // determine how long to sleep before the start of the next 1ms + sleep_ts.tv_sec = 0; + sleep_ts.tv_nsec = 1e6 - (now_ts.tv_nsec % 1000000); + + int nanosleep_result = nanosleep(&sleep_ts, &sleep_rem_ts); + + if(nanosleep_result != 0) + printf("*** nanosleep failed or was interrupted\n"); + + + clock_gettime(CLOCK_MONOTONIC, &now_ts); + millisec = now_ts.tv_nsec / 1e6; + + if(last_millisec != -1 && ((last_millisec + 1 ) % 1000) != millisec) + { + printf("*** missing millisec %d %d\n", last_millisec, millisec); + catchup = millisec - last_millisec - 1; + } + + last_millisec = millisec; + } + } +} + +extern "C" +{ + fapi_t* fapi_create(fapi_cb_t* callbacks, fapi_config_t* config) + { + fapi_internal_t* instance = (fapi_internal*)calloc(1, sizeof(fapi_internal_t)); + instance->callbacks = *callbacks; + instance->config = *config; + instance->state = 0; + + instance->fapi = new fapi_private(); + + return (fapi_t*)instance; + } + + void fapi_destroy(fapi_t* fapi) + { + fapi_internal_t* instance = (fapi_internal_t*)fapi; + + delete instance->fapi; + free(instance); + } + + void* fapi_rx_thread_start(void* ptr) + { + set_thread_priority(60); + + fapi_internal_t* instance = (fapi_internal_t*)ptr; + + while(1) + { + phy_pdu* pdu = instance->fapi->allocate_phy_pdu(); + int len = recvfrom(instance->rx_sock, pdu->buffer, pdu->buffer_len, 0, 0, 0); + if(len > 0) + { + pdu->len = len; + instance->fapi->push_rx_buffer(pdu); + } + else + { + instance->fapi->release_phy_pdu(pdu); + } + + } + } + + void fapi_start_data(fapi_t* fapi, unsigned rx_port, const char* tx_address, unsigned tx_port) + { + fapi_internal_t* instance = (fapi_internal_t*)fapi; + + printf("[FAPI] Rx Data from %d\n", rx_port); + printf("[FAPI] Tx Data to %s:%d\n", tx_address, tx_port); + + instance->rx_sock = socket(AF_INET, SOCK_DGRAM, 0); + + if(instance->rx_sock < 0) + { + printf("[FAPI] Failed to create socket\n"); + return; + } + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(rx_port); + addr.sin_addr.s_addr = INADDR_ANY; + + int bind_result = bind(instance->rx_sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + + if(bind_result == -1) + { + printf("[FAPI] Failed to bind to port %d\n", rx_port); + close(instance->rx_sock); + return ; + } + + instance->tx_sock = socket(AF_INET, SOCK_DGRAM, 0); + instance->tx_addr.sin_family = AF_INET; + instance->tx_addr.sin_port = htons(tx_port); + instance->tx_addr.sin_addr.s_addr = inet_addr(tx_address); + + } + + + void fill_tlv(fapi_tlv_t tlvs[], uint8_t count, uint8_t tag, uint8_t len, uint16_t value) + { + tlvs[count].tag = tag; + tlvs[count].value = value; + tlvs[count].length = len; + + } + + int fapi_param_request(fapi_t* fapi, fapi_param_req_t* req) + { + fapi_internal_t* instance = (fapi_internal_t*)fapi; + + fapi_param_resp_t resp; + resp.header.message_id = FAPI_PARAM_RESPONSE; + + resp.error_code = FAPI_MSG_OK; + + resp.number_of_tlvs = 0; + fill_tlv(resp.tlvs, resp.number_of_tlvs++, FAPI_PHY_STATE_TAG, 2, instance->state); + + + if(instance->state == 0) + { + if(instance->config.duplex_mode == 0) + { + // -- TDD + // Downlink Bandwidth Support + // Uplink Bandwidth Support + // Downlink Modulation Support + // Uplink Modulation Support + // PHY Antenna Capability + // Release Capability + // MBSFN Capability + } + else if(instance->config.duplex_mode == 1) + { + // -- FDD + // Downlink Bandwidth Support + fill_tlv(resp.tlvs, resp.number_of_tlvs++, FAPI_PHY_CAPABILITIES_DL_BANDWIDTH_SUPPORT_TAG, 2, instance->config.dl_channel_bw_support); + // Uplink Bandwidth Support + fill_tlv(resp.tlvs, resp.number_of_tlvs++, FAPI_PHY_CAPABILITIES_UL_BANDWIDTH_SUPPORT_TAG, 2, instance->config.ul_channel_bw_support); + // Downlink Modulation Support + // Uplink Modulation Support + // PHY Antenna Capability + // Release Capability + // MBSFN Capability + // LAA Capability + } + } + else + { + if(instance->config.duplex_mode == 0) + { + // -- TDD + // Downlink Bandwidth Support + // Uplink Bandwidth Support + // Downlink Modulation Support + // Uplink Modulation Support + // PHY Antenna Capability + // Release Capability + // MBSFN Capability + // Duplexing Mode + // PCFICH Power Offset + // P-B + // DL Cyclic Prefix Type + // UL Cyclic Prefix Type + // RF Config + // PHICH Config + // SCH Config + // PRACH Config + // PUSCH Config + // PUCCH Config + // SRS Config + // Uplink Reference Signal Config + // TDD Frame Structure Config + // Data Report Mode + } + else if(instance->config.duplex_mode == 1) + { + // FDD + // Downlink Bandwidth Support + // Uplink Bandwidth Support + // Downlink Modulation Support + // Uplink Modulation Support + // PHY Antenna Capability + // Release Capability + // MBSFN Capability + // LAA Capability + // Duplexing Mode + // PCFICH Power Offset + // P-B + // DL Cyclic Prefix Type + // UL Cyclic Prefix Type + // RF Config + // PHICH Config + // SCH Config + // PRACH Config + // PUSCH Config + // PUCCH Config + // SRS Config + // Uplink Reference Signal Config + // Data Report Mode + } + } + + + //todo fill + (instance->callbacks.fapi_param_response)(fapi, &resp); + + return 0; + } + + int fapi_config_request(fapi_t* fapi, fapi_config_req_t* req) + { + fapi_internal_t* instance = (fapi_internal_t*)fapi; + + fapi_config_resp_t resp; + resp.header.message_id = FAPI_CONFIG_RESPONSE; + resp.error_code = FAPI_MSG_OK; + + (instance->callbacks.fapi_config_response)(fapi, &resp); + return 0; + } + + int fapi_start_request(fapi_t* fapi, fapi_start_req_t* req) + { + fapi_internal_t* instance = (fapi_internal_t*)fapi; + + pthread_t fapi_thread; + pthread_create(&fapi_thread, NULL, &fapi_thread_start, instance); + + return 0; + } + + int fapi_dl_config_request(fapi_t* fapi, fapi_dl_config_req_t* req) + { + fapi_internal_t* instance = (fapi_internal_t*)fapi; + instance->fapi->first_dl_config = true; + return 0; + } + int fapi_ul_config_request(fapi_t* fapi, fapi_ul_config_req_t* req) + { + fapi_internal_t* instance = (fapi_internal_t*)fapi; + return 0; + } + int fapi_hi_dci0_request(fapi_t* fapi, fapi_hi_dci0_req_t* req) + { + fapi_internal_t* instance = (fapi_internal_t*)fapi; + return 0; + } + int fapi_tx_request(fapi_t* fapi, fapi_tx_req_t* req) + { + fapi_internal_t* instance = (fapi_internal_t*)fapi; + + for(int i = 0; i < req->body.number_of_pdus; ++i) + { + uint16_t len = req->body.pdus[i].pdu_length; + uint32_t* data = req->body.pdus[i].tlvs[0].value; + //printf("[FAPI] sfnsf:%d len:%d\n", req->sfn_sf,len); + // + instance->tx_byte_count += len; + + int sendto_result = sendto(instance->tx_sock, data, len, 0, (struct sockaddr*)&(instance->tx_addr), sizeof(instance->tx_addr)); + + if(sendto_result == -1) + { + // error + } + } + + return 0; + } +} + diff --git a/nfapi/open-nFAPI/pnf_sim/src/main.cpp b/nfapi/open-nFAPI/pnf_sim/src/main.cpp new file mode 100644 index 0000000000..e2622cf3c3 --- /dev/null +++ b/nfapi/open-nFAPI/pnf_sim/src/main.cpp @@ -0,0 +1,2285 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include "debug.h" +#include "nfapi_pnf_interface.h" +#include "nfapi.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include + +#include "fapi_stub.h" +#include "pool.h" + + +#include +#include +#include +#include +#include +#include +#include + +#define NUM_P5_PHY 2 + +uint16_t phy_antenna_capability_values[] = { 1, 2, 4, 8, 16 }; + +static uint32_t rand_range(uint32_t min, uint32_t max) +{ + return ((rand() % (max + 1 - min)) + min); +} + + + +extern "C" nfapi_pnf_param_response_t g_pnf_param_resp; + +extern "C" { + + +void* pnf_allocate(size_t size) +{ + return (void*)memory_pool::allocate(size); +} + +void pnf_deallocate(void* ptr) +{ + memory_pool::deallocate((uint8_t*)ptr); +} + + +int read_xml(const char *xml_file); + +}; + +class udp_data +{ + public: + bool enabled; + uint32_t rx_port; + uint32_t tx_port; + std::string tx_addr; +}; + +class phy_info +{ + public: + + phy_info() + : first_subframe_ind(0), fapi(0), + dl_ues_per_subframe(0), ul_ues_per_subframe(0), + timing_window(0), timing_info_mode(0), timing_info_period(0) + { + index = 0; + id = 0; + + local_port = 0; + remote_addr = 0; + remote_port = 0; + + duplex_mode = 0; + dl_channel_bw_support = 0; + ul_channel_bw_support = 0; + num_dl_layers_supported = 0; + num_ul_layers_supported = 0; + release_supported = 0; + nmm_modes_supported = 0; + } + + uint16_t index; + uint16_t id; + std::vector rfs; + std::vector excluded_rfs; + + udp_data udp; + + std::string local_addr; + int local_port; + + char* remote_addr; + int remote_port; + + uint8_t duplex_mode; + uint16_t dl_channel_bw_support; + uint16_t ul_channel_bw_support; + uint8_t num_dl_layers_supported; + uint8_t num_ul_layers_supported; + uint16_t release_supported; + uint8_t nmm_modes_supported; + + uint8_t dl_ues_per_subframe; + uint8_t ul_ues_per_subframe; + + uint8_t first_subframe_ind; + + // timing information recevied from the vnf + uint8_t timing_window; + uint8_t timing_info_mode; + uint8_t timing_info_period; + + fapi_t* fapi; + +}; + +class rf_info +{ + public: + uint16_t index; + uint16_t band; + int16_t max_transmit_power; + int16_t min_transmit_power; + uint8_t num_antennas_supported; + uint32_t min_downlink_frequency; + uint32_t max_downlink_frequency; + uint32_t max_uplink_frequency; + uint32_t min_uplink_frequency; +}; + + +class pnf_info +{ + public: + + pnf_info() + : release(13), wireshark_test_mode(0), + max_total_power(0), oui(0) + + { + release = 0; + + sync_mode = 0; + location_mode = 0; + dl_config_timing = 0; + ul_config_timing = 0; + tx_timing = 0; + hi_dci0_timing = 0; + + max_phys = 0; + max_total_bw = 0; + max_total_dl_layers = 0; + max_total_ul_layers = 0; + shared_bands = 0; + shared_pa = 0; + + } + + int release; + std::vector phys; + std::vector rfs; + + uint8_t sync_mode; + uint8_t location_mode; + uint8_t location_coordinates[6]; + uint32_t dl_config_timing; + uint32_t ul_config_timing; + uint32_t tx_timing; + uint32_t hi_dci0_timing; + + uint16_t max_phys; + uint16_t max_total_bw; + uint16_t max_total_dl_layers; + uint16_t max_total_ul_layers; + uint8_t shared_bands; + uint8_t shared_pa; + int16_t max_total_power; + uint8_t oui; + + uint8_t wireshark_test_mode; + +}; + +struct pnf_phy_user_data_t +{ + uint16_t phy_id; + nfapi_pnf_config_t* config; + phy_info* phy; + nfapi_pnf_p7_config_t* p7_config; +}; + +int read_pnf_xml(pnf_info& pnf, const char* xml_file) +{ + try + { + std::ifstream input(xml_file); + + using boost::property_tree::ptree; + ptree pt; + + read_xml(input, pt); + + pnf.wireshark_test_mode = pt.get("pnf.wireshark_test_mode", 0); + + + pnf.sync_mode = pt.get("pnf.sync_mode"); + pnf.location_mode= pt.get("pnf.location_mode"); + //pnf.sync_mode = pt.get("pnf.location_coordinates"); + + pnf.dl_config_timing= pt.get("pnf.dl_config_timing"); + pnf.ul_config_timing = pt.get("pnf.ul_config_timing"); + pnf.tx_timing = pt.get("pnf.tx_timing"); + pnf.hi_dci0_timing = pt.get("pnf.hi_dci0_timing"); + + pnf.max_phys = pt.get("pnf.max_phys"); + pnf.max_total_bw = pt.get("pnf.max_total_bandwidth"); + pnf.max_total_dl_layers = pt.get("pnf.max_total_num_dl_layers"); + pnf.max_total_ul_layers = pt.get("pnf.max_total_num_ul_layers"); + + pnf.shared_bands = pt.get("pnf.shared_bands"); + pnf.shared_pa = pt.get("pnf.shared_pas"); + + pnf.max_total_power = pt.get("pnf.maximum_total_power"); + + //"oui"); + + for(const auto& v : pt.get_child("pnf.phys")) + { + if(v.first == "phy") + { + phy_info phy; + + + + phy.index = v.second.get("index"); + phy.local_port = v.second.get("port"); + phy.local_addr = v.second.get("address"); + phy.duplex_mode = v.second.get("duplex_mode"); + + phy.dl_channel_bw_support = v.second.get("downlink_channel_bandwidth_support"); + phy.ul_channel_bw_support = v.second.get("uplink_channel_bandwidth_support"); + phy.num_dl_layers_supported = v.second.get("number_of_dl_layers"); + phy.num_ul_layers_supported = v.second.get("number_of_ul_layers"); + phy.release_supported = v.second.get("3gpp_release_supported"); + phy.nmm_modes_supported = v.second.get("nmm_modes_supported"); + + for(const auto& v2 : v.second.get_child("rfs")) + { + if(v2.first == "index") + phy.rfs.push_back(v2.second.get_value()); + } + for(const auto& v2 : v.second.get_child("excluded_rfs")) + { + if(v2.first == "index") + phy.excluded_rfs.push_back(v2.second.get_value()); + } + + boost::optional d = v.second.get_child_optional("data.udp"); + if(d.is_initialized()) + { + phy.udp.enabled = true; + phy.udp.rx_port = d.get().get("rx_port"); + phy.udp.tx_port = d.get().get("tx_port"); + phy.udp.tx_addr = d.get().get("tx_addr"); + } + else + { + phy.udp.enabled = false; + } + + phy.dl_ues_per_subframe = v.second.get("dl_ues_per_subframe"); + phy.ul_ues_per_subframe = v.second.get("ul_ues_per_subframe"); + + pnf.phys.push_back(phy); + } + } + for(const auto& v : pt.get_child("pnf.rfs")) + { + if(v.first == "rf") + { + rf_info rf; + + rf.index = v.second.get("index"); + rf.band = v.second.get("band"); + rf.max_transmit_power = v.second.get("max_transmit_power"); + rf.min_transmit_power = v.second.get("min_transmit_power"); + rf.num_antennas_supported = v.second.get("num_antennas_supported"); + rf.min_downlink_frequency = v.second.get("min_downlink_frequency"); + rf.max_downlink_frequency = v.second.get("max_downlink_frequency"); + rf.min_uplink_frequency = v.second.get("max_uplink_frequency"); + rf.max_uplink_frequency = v.second.get("min_uplink_frequency"); + + pnf.rfs.push_back(rf); + } + } + } + catch(std::exception& e) + { + printf("%s", e.what()); + return -1; + } + catch(boost::exception& e) + { + printf("%s", boost::diagnostic_information(e).c_str()); + return -1; + } + + return 0; +} + + + +void pnf_sim_trace(nfapi_trace_level_t level, const char* message, ...) +{ + va_list args; + va_start(args, message); + vprintf(message, args); + va_end(args); +} + +void set_thread_priority(int priority) +{ + //printf("%s(priority:%d)\n", __FUNCTION__, priority); + + pthread_attr_t ptAttr; + + struct sched_param schedParam; + schedParam.__sched_priority = priority; //79; + if(sched_setscheduler(0, SCHED_RR, &schedParam) != 0) + { + printf("failed to set SCHED_RR\n"); + } + + if(pthread_attr_setschedpolicy(&ptAttr, SCHED_RR) != 0) + { + printf("failed to set pthread SCHED_RR %d\n", errno); + } + + pthread_attr_setinheritsched(&ptAttr, PTHREAD_EXPLICIT_SCHED); + + struct sched_param thread_params; + thread_params.sched_priority = 20; + if(pthread_attr_setschedparam(&ptAttr, &thread_params) != 0) + { + printf("failed to set sched param\n"); + } +} + + +void* pnf_p7_thread_start(void* ptr) +{ + set_thread_priority(79); + + nfapi_pnf_p7_config_t* config = (nfapi_pnf_p7_config_t*)ptr; + nfapi_pnf_p7_start(config); + + return 0; +} + + + +int pnf_param_request(nfapi_pnf_config_t* config, nfapi_pnf_param_request_t* req) +{ + printf("[PNF_SIM] pnf param request\n"); + + nfapi_pnf_param_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_PARAM_RESPONSE; + resp.error_code = NFAPI_MSG_OK; + + pnf_info* pnf = (pnf_info*)(config->user_data); + + resp.pnf_param_general.tl.tag = NFAPI_PNF_PARAM_GENERAL_TAG; + resp.pnf_param_general.nfapi_sync_mode = pnf->sync_mode; + resp.pnf_param_general.location_mode = pnf->location_mode; + //uint8_t location_coordinates[NFAPI_PNF_PARAM_GENERAL_LOCATION_LENGTH]; + resp.pnf_param_general.dl_config_timing = pnf->dl_config_timing; + resp.pnf_param_general.tx_timing = pnf->tx_timing; + resp.pnf_param_general.ul_config_timing = pnf->ul_config_timing; + resp.pnf_param_general.hi_dci0_timing = pnf->hi_dci0_timing; + resp.pnf_param_general.maximum_number_phys = pnf->max_phys; + resp.pnf_param_general.maximum_total_bandwidth = pnf->max_total_bw; + resp.pnf_param_general.maximum_total_number_dl_layers = pnf->max_total_dl_layers; + resp.pnf_param_general.maximum_total_number_ul_layers = pnf->max_total_ul_layers; + resp.pnf_param_general.shared_bands = pnf->shared_bands; + resp.pnf_param_general.shared_pa = pnf->shared_pa; + resp.pnf_param_general.maximum_total_power = pnf->max_total_power; + //uint8_t oui[NFAPI_PNF_PARAM_GENERAL_OUI_LENGTH]; + + resp.pnf_phy.tl.tag = NFAPI_PNF_PHY_TAG; + resp.pnf_phy.number_of_phys = pnf->phys.size(); + + for(int i = 0; i < pnf->phys.size(); ++i) + { + resp.pnf_phy.phy[i].phy_config_index = pnf->phys[i].index; + resp.pnf_phy.phy[i].downlink_channel_bandwidth_supported = pnf->phys[i].dl_channel_bw_support; + resp.pnf_phy.phy[i].uplink_channel_bandwidth_supported = pnf->phys[i].ul_channel_bw_support; + resp.pnf_phy.phy[i].number_of_dl_layers_supported = pnf->phys[i].num_dl_layers_supported; + resp.pnf_phy.phy[i].number_of_ul_layers_supported = pnf->phys[i].num_ul_layers_supported; + resp.pnf_phy.phy[i].maximum_3gpp_release_supported = pnf->phys[i].release_supported; + resp.pnf_phy.phy[i].nmm_modes_supported = pnf->phys[i].nmm_modes_supported; + + resp.pnf_phy.phy[i].number_of_rfs = pnf->phys[i].rfs.size(); + for(int j = 0; j < pnf->phys[i].rfs.size(); ++j) + { + resp.pnf_phy.phy[i].rf_config[j].rf_config_index = pnf->phys[i].rfs[j]; + } + + resp.pnf_phy.phy[i].number_of_rf_exclusions = pnf->phys[i].excluded_rfs.size(); + for(int j = 0; j < pnf->phys[i].excluded_rfs.size(); ++j) + { + resp.pnf_phy.phy[i].excluded_rf_config[j].rf_config_index = pnf->phys[i].excluded_rfs[j]; + } + } + + + resp.pnf_rf.tl.tag = NFAPI_PNF_RF_TAG; + resp.pnf_rf.number_of_rfs = pnf->rfs.size(); + + for(int i = 0; i < pnf->rfs.size(); ++i) + { + resp.pnf_rf.rf[i].rf_config_index = pnf->rfs[i].index; + resp.pnf_rf.rf[i].band = pnf->rfs[i].band; + resp.pnf_rf.rf[i].maximum_transmit_power = pnf->rfs[i].max_transmit_power; + resp.pnf_rf.rf[i].minimum_transmit_power = pnf->rfs[i].min_transmit_power; + resp.pnf_rf.rf[i].number_of_antennas_suppported = pnf->rfs[i].num_antennas_supported; + resp.pnf_rf.rf[i].minimum_downlink_frequency = pnf->rfs[i].min_downlink_frequency; + resp.pnf_rf.rf[i].maximum_downlink_frequency = pnf->rfs[i].max_downlink_frequency; + resp.pnf_rf.rf[i].minimum_uplink_frequency = pnf->rfs[i].min_uplink_frequency; + resp.pnf_rf.rf[i].maximum_uplink_frequency = pnf->rfs[i].max_uplink_frequency; + } + + if(pnf->release >= 10) + { + resp.pnf_phy_rel10.tl.tag = NFAPI_PNF_PHY_REL10_TAG; + resp.pnf_phy_rel10.number_of_phys = pnf->phys.size(); + + for(int i = 0; i < pnf->phys.size(); ++i) + { + resp.pnf_phy_rel10.phy[i].phy_config_index = pnf->phys[i].index; + resp.pnf_phy_rel10.phy[i].transmission_mode_7_supported = 0; + resp.pnf_phy_rel10.phy[i].transmission_mode_8_supported = 1; + resp.pnf_phy_rel10.phy[i].two_antenna_ports_for_pucch = 0; + resp.pnf_phy_rel10.phy[i].transmission_mode_9_supported = 1; + resp.pnf_phy_rel10.phy[i].simultaneous_pucch_pusch = 0; + resp.pnf_phy_rel10.phy[i].four_layer_tx_with_tm3_and_tm4 = 1; + + } + } + + if(pnf->release >= 11) + { + resp.pnf_phy_rel11.tl.tag = NFAPI_PNF_PHY_REL11_TAG; + resp.pnf_phy_rel11.number_of_phys = pnf->phys.size(); + + for(int i = 0; i < pnf->phys.size(); ++i) + { + resp.pnf_phy_rel11.phy[i].phy_config_index = pnf->phys[i].index; + resp.pnf_phy_rel11.phy[i].edpcch_supported = 0; + resp.pnf_phy_rel11.phy[i].multi_ack_csi_reporting = 1; + resp.pnf_phy_rel11.phy[i].pucch_tx_diversity = 0; + resp.pnf_phy_rel11.phy[i].ul_comp_supported = 1; + resp.pnf_phy_rel11.phy[i].transmission_mode_5_supported = 0; + } + } + + if(pnf->release >= 12) + { + resp.pnf_phy_rel12.tl.tag = NFAPI_PNF_PHY_REL12_TAG; + resp.pnf_phy_rel12.number_of_phys = pnf->phys.size(); + + for(int i = 0; i < pnf->phys.size(); ++i) + { + resp.pnf_phy_rel12.phy[i].phy_config_index = pnf->phys[i].index; + resp.pnf_phy_rel12.phy[i].csi_subframe_set = 0; + resp.pnf_phy_rel12.phy[i].enhanced_4tx_codebook = 2; // yes this is invalid + resp.pnf_phy_rel12.phy[i].drs_supported = 0; + resp.pnf_phy_rel12.phy[i].ul_64qam_supported = 1; + resp.pnf_phy_rel12.phy[i].transmission_mode_10_supported = 0; + resp.pnf_phy_rel12.phy[i].alternative_bts_indices = 1; + } + } + + if(pnf->release >= 13) + { + resp.pnf_phy_rel13.tl.tag = NFAPI_PNF_PHY_REL13_TAG; + resp.pnf_phy_rel13.number_of_phys = pnf->phys.size(); + + for(int i = 0; i < pnf->phys.size(); ++i) + { + resp.pnf_phy_rel13.phy[i].phy_config_index = pnf->phys[i].index; + resp.pnf_phy_rel13.phy[i].pucch_format4_supported = 0; + resp.pnf_phy_rel13.phy[i].pucch_format5_supported = 1; + resp.pnf_phy_rel13.phy[i].more_than_5_ca_support = 0; + resp.pnf_phy_rel13.phy[i].laa_supported = 1; + resp.pnf_phy_rel13.phy[i].laa_ending_in_dwpts_supported = 0; + resp.pnf_phy_rel13.phy[i].laa_starting_in_second_slot_supported = 1; + resp.pnf_phy_rel13.phy[i].beamforming_supported = 0; + resp.pnf_phy_rel13.phy[i].csi_rs_enhancement_supported = 1; + resp.pnf_phy_rel13.phy[i].drms_enhancement_supported = 0; + resp.pnf_phy_rel13.phy[i].srs_enhancement_supported = 1; + } + + resp.pnf_phy_rel13_nb_iot.tl.tag = NFAPI_PNF_PHY_REL13_NB_IOT_TAG; + resp.pnf_phy_rel13_nb_iot.number_of_phys = pnf->phys.size(); + + for(int i = 0; i < pnf->phys.size(); ++i) + { + resp.pnf_phy_rel13_nb_iot.phy[i].phy_config_index = pnf->phys[i].index; + + resp.pnf_phy_rel13_nb_iot.phy[i].number_of_rfs = pnf->phys[i].rfs.size(); + for(int j = 0; j < pnf->phys[i].rfs.size(); ++j) + { + resp.pnf_phy_rel13_nb_iot.phy[i].rf_config[j].rf_config_index = pnf->phys[i].rfs[j]; + } + + resp.pnf_phy_rel13_nb_iot.phy[i].number_of_rf_exclusions = pnf->phys[i].excluded_rfs.size(); + for(int j = 0; j < pnf->phys[i].excluded_rfs.size(); ++j) + { + resp.pnf_phy_rel13_nb_iot.phy[i].excluded_rf_config[j].rf_config_index = pnf->phys[i].excluded_rfs[j]; + } + + resp.pnf_phy_rel13_nb_iot.phy[i].number_of_dl_layers_supported = pnf->phys[i].num_dl_layers_supported; + resp.pnf_phy_rel13_nb_iot.phy[i].number_of_ul_layers_supported = pnf->phys[i].num_ul_layers_supported; + resp.pnf_phy_rel13_nb_iot.phy[i].maximum_3gpp_release_supported = pnf->phys[i].release_supported; + resp.pnf_phy_rel13_nb_iot.phy[i].nmm_modes_supported = pnf->phys[i].nmm_modes_supported; + + } + } + + + nfapi_pnf_pnf_param_resp(config, &resp); + + return 0; +} + +int pnf_config_request(nfapi_pnf_config_t* config, nfapi_pnf_config_request_t* req) +{ + printf("[PNF_SIM] pnf config request\n"); + + pnf_info* pnf = (pnf_info*)(config->user_data); + + for(int i = 0; i < req->pnf_phy_rf_config.number_phy_rf_config_info; ++i) + { + auto found = std::find_if(pnf->phys.begin(), pnf->phys.end(), [&](phy_info& item) + { return item.index == req->pnf_phy_rf_config.phy_rf_config[i].phy_config_index; }); + + if(found != pnf->phys.end()) + { + phy_info& phy = (*found); + phy.id = req->pnf_phy_rf_config.phy_rf_config[i].phy_id; + printf("[PNF_SIM] pnf config request assigned phy_id %d to phy_config_index %d\n", phy.id, req->pnf_phy_rf_config.phy_rf_config[i].phy_config_index); + } + else + { + // did not find the phy + printf("[PNF_SIM] pnf config request did not find phy_config_index %d\n", req->pnf_phy_rf_config.phy_rf_config[i].phy_config_index); + } + + } + + nfapi_pnf_config_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_CONFIG_RESPONSE; + resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_pnf_config_resp(config, &resp); + + return 0; +} + +int fapi_param_response(fapi_t* fapi, fapi_param_resp_t* resp) +{ + printf("[PNF_SIM] fapi param response\n"); + pnf_phy_user_data_t* data = (pnf_phy_user_data_t*)(fapi->user_data); + + nfapi_param_response_t nfapi_resp; + + memset(&nfapi_resp, 0, sizeof(nfapi_resp)); + nfapi_resp.header.message_id = NFAPI_PARAM_RESPONSE; + nfapi_resp.header.phy_id = data->phy_id; + nfapi_resp.error_code = resp->error_code; + + for(int i = 0; i < resp->number_of_tlvs; ++i) + { + switch(resp->tlvs[i].tag) + { + case FAPI_PHY_STATE_TAG: + nfapi_resp.l1_status.phy_state.tl.tag = NFAPI_L1_STATUS_PHY_STATE_TAG; + nfapi_resp.l1_status.phy_state.value = resp->tlvs[i].value; + nfapi_resp.num_tlv++; + break; + + case FAPI_PHY_CAPABILITIES_DL_BANDWIDTH_SUPPORT_TAG: + nfapi_resp.phy_capabilities.dl_bandwidth_support.tl.tag = NFAPI_PHY_CAPABILITIES_DL_BANDWIDTH_SUPPORT_TAG; + nfapi_resp.phy_capabilities.dl_bandwidth_support.value = resp->tlvs[i].value; + nfapi_resp.num_tlv++; + break; + + case FAPI_PHY_CAPABILITIES_UL_BANDWIDTH_SUPPORT_TAG: + nfapi_resp.phy_capabilities.ul_bandwidth_support.tl.tag = NFAPI_PHY_CAPABILITIES_UL_BANDWIDTH_SUPPORT_TAG; + nfapi_resp.phy_capabilities.ul_bandwidth_support.value = resp->tlvs[i].value; + nfapi_resp.num_tlv++; + break; + } + } + + if(1) + { + // just code to populate all the tlv for testing with wireshark + // todo : these should be move up so that they are populated by fapi + + nfapi_resp.phy_capabilities.dl_modulation_support.tl.tag = NFAPI_PHY_CAPABILITIES_DL_MODULATION_SUPPORT_TAG; + nfapi_resp.phy_capabilities.dl_modulation_support.value = rand_range(0, 0x0F); + nfapi_resp.num_tlv++; + nfapi_resp.phy_capabilities.ul_modulation_support.tl.tag = NFAPI_PHY_CAPABILITIES_UL_MODULATION_SUPPORT_TAG; + nfapi_resp.phy_capabilities.ul_modulation_support.value = rand_range(0, 0x07); + nfapi_resp.num_tlv++; + nfapi_resp.phy_capabilities.phy_antenna_capability.tl.tag = NFAPI_PHY_CAPABILITIES_PHY_ANTENNA_CAPABILITY_TAG; + nfapi_resp.phy_capabilities.phy_antenna_capability.value = phy_antenna_capability_values[rand_range(0, 4)]; + nfapi_resp.num_tlv++; + nfapi_resp.phy_capabilities.release_capability.tl.tag = NFAPI_PHY_CAPABILITIES_RELEASE_CAPABILITY_TAG; + nfapi_resp.phy_capabilities.release_capability.value = rand_range(0, 0x3F); + nfapi_resp.num_tlv++; + nfapi_resp.phy_capabilities.mbsfn_capability.tl.tag = NFAPI_PHY_CAPABILITIES_MBSFN_CAPABILITY_TAG; + nfapi_resp.phy_capabilities.mbsfn_capability.value = rand_range(0, 1); + nfapi_resp.num_tlv++; + + + nfapi_resp.laa_capability.laa_support.tl.tag = NFAPI_LAA_CAPABILITY_LAA_SUPPORT_TAG; + nfapi_resp.laa_capability.laa_support.value = rand_range(0, 1); + nfapi_resp.num_tlv++; + nfapi_resp.laa_capability.pd_sensing_lbt_support.tl.tag = NFAPI_LAA_CAPABILITY_PD_SENSING_LBT_SUPPORT_TAG; + nfapi_resp.laa_capability.pd_sensing_lbt_support.value = rand_range(0, 1); + nfapi_resp.num_tlv++; + nfapi_resp.laa_capability.multi_carrier_lbt_support.tl.tag = NFAPI_LAA_CAPABILITY_MULTI_CARRIER_LBT_SUPPORT_TAG; + nfapi_resp.laa_capability.multi_carrier_lbt_support.value = rand_range(0, 0x0F); + nfapi_resp.num_tlv++; + nfapi_resp.laa_capability.partial_sf_support.tl.tag = NFAPI_LAA_CAPABILITY_PARTIAL_SF_SUPPORT_TAG; + nfapi_resp.laa_capability.partial_sf_support.value = rand_range(0, 1); + nfapi_resp.num_tlv++; + + nfapi_resp.nb_iot_capability.nb_iot_support.tl.tag = NFAPI_LAA_CAPABILITY_NB_IOT_SUPPORT_TAG; + nfapi_resp.nb_iot_capability.nb_iot_support.value = rand_range(0, 2); + nfapi_resp.num_tlv++; + nfapi_resp.nb_iot_capability.nb_iot_operating_mode_capability.tl.tag = NFAPI_LAA_CAPABILITY_NB_IOT_OPERATING_MODE_CAPABILITY_TAG; + nfapi_resp.nb_iot_capability.nb_iot_operating_mode_capability.value = rand_range(0, 1); + nfapi_resp.num_tlv++; + + nfapi_resp.subframe_config.duplex_mode.tl.tag = NFAPI_SUBFRAME_CONFIG_DUPLEX_MODE_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.subframe_config.pcfich_power_offset.tl.tag = NFAPI_SUBFRAME_CONFIG_PCFICH_POWER_OFFSET_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.subframe_config.pb.tl.tag = NFAPI_SUBFRAME_CONFIG_PB_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.subframe_config.dl_cyclic_prefix_type.tl.tag = NFAPI_SUBFRAME_CONFIG_DL_CYCLIC_PREFIX_TYPE_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.subframe_config.ul_cyclic_prefix_type.tl.tag = NFAPI_SUBFRAME_CONFIG_UL_CYCLIC_PREFIX_TYPE_TAG; + nfapi_resp.num_tlv++; + + nfapi_resp.rf_config.dl_channel_bandwidth.tl.tag = NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.rf_config.ul_channel_bandwidth.tl.tag = NFAPI_RF_CONFIG_UL_CHANNEL_BANDWIDTH_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.rf_config.reference_signal_power.tl.tag = NFAPI_RF_CONFIG_REFERENCE_SIGNAL_POWER_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.rf_config.tx_antenna_ports.tl.tag = NFAPI_RF_CONFIG_TX_ANTENNA_PORTS_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.rf_config.rx_antenna_ports.tl.tag = NFAPI_RF_CONFIG_RX_ANTENNA_PORTS_TAG; + nfapi_resp.num_tlv++; + + nfapi_resp.phich_config.phich_resource.tl.tag = NFAPI_PHICH_CONFIG_PHICH_RESOURCE_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.phich_config.phich_duration.tl.tag = NFAPI_PHICH_CONFIG_PHICH_DURATION_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.phich_config.phich_power_offset.tl.tag = NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG; + nfapi_resp.num_tlv++; + + nfapi_resp.sch_config.primary_synchronization_signal_epre_eprers.tl.tag = NFAPI_SCH_CONFIG_PRIMARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.sch_config.secondary_synchronization_signal_epre_eprers.tl.tag = NFAPI_SCH_CONFIG_SECONDARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.sch_config.physical_cell_id.tl.tag = NFAPI_SCH_CONFIG_PHYSICAL_CELL_ID_TAG; + nfapi_resp.num_tlv++; + + nfapi_resp.prach_config.configuration_index.tl.tag = NFAPI_PRACH_CONFIG_CONFIGURATION_INDEX_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.prach_config.root_sequence_index.tl.tag = NFAPI_PRACH_CONFIG_ROOT_SEQUENCE_INDEX_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.prach_config.zero_correlation_zone_configuration.tl.tag = NFAPI_PRACH_CONFIG_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.prach_config.high_speed_flag.tl.tag = NFAPI_PRACH_CONFIG_HIGH_SPEED_FLAG_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.prach_config.frequency_offset.tl.tag = NFAPI_PRACH_CONFIG_FREQUENCY_OFFSET_TAG; + nfapi_resp.num_tlv++; + + nfapi_resp.pusch_config.hopping_mode.tl.tag = NFAPI_PUSCH_CONFIG_HOPPING_MODE_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.pusch_config.hopping_offset.tl.tag = NFAPI_PUSCH_CONFIG_HOPPING_OFFSET_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.pusch_config.number_of_subbands.tl.tag = NFAPI_PUSCH_CONFIG_NUMBER_OF_SUBBANDS_TAG; + nfapi_resp.num_tlv++; + + nfapi_resp.pucch_config.delta_pucch_shift.tl.tag = NFAPI_PUCCH_CONFIG_DELTA_PUCCH_SHIFT_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.pucch_config.n_cqi_rb.tl.tag = NFAPI_PUCCH_CONFIG_N_CQI_RB_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.pucch_config.n_an_cs.tl.tag = NFAPI_PUCCH_CONFIG_N_AN_CS_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.pucch_config.n1_pucch_an.tl.tag = NFAPI_PUCCH_CONFIG_N1_PUCCH_AN_TAG; + nfapi_resp.num_tlv++; + + nfapi_resp.srs_config.bandwidth_configuration.tl.tag = NFAPI_SRS_CONFIG_BANDWIDTH_CONFIGURATION_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.srs_config.max_up_pts.tl.tag = NFAPI_SRS_CONFIG_MAX_UP_PTS_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.srs_config.srs_subframe_configuration.tl.tag = NFAPI_SRS_CONFIG_SRS_SUBFRAME_CONFIGURATION_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.srs_config.srs_acknack_srs_simultaneous_transmission.tl.tag = NFAPI_SRS_CONFIG_SRS_ACKNACK_SRS_SIMULTANEOUS_TRANSMISSION_TAG; + nfapi_resp.num_tlv++; + + nfapi_resp.uplink_reference_signal_config.uplink_rs_hopping.tl.tag = NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_UPLINK_RS_HOPPING_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.uplink_reference_signal_config.group_assignment.tl.tag = NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_GROUP_ASSIGNMENT_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.uplink_reference_signal_config.cyclic_shift_1_for_drms.tl.tag = NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_CYCLIC_SHIFT_1_FOR_DRMS_TAG; + nfapi_resp.num_tlv++; + + nfapi_resp.tdd_frame_structure_config.subframe_assignment.tl.tag = NFAPI_TDD_FRAME_STRUCTURE_SUBFRAME_ASSIGNMENT_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.tdd_frame_structure_config.special_subframe_patterns.tl.tag = NFAPI_TDD_FRAME_STRUCTURE_SPECIAL_SUBFRAME_PATTERNS_TAG; + nfapi_resp.num_tlv++; + + nfapi_resp.l23_config.data_report_mode.tl.tag = NFAPI_L23_CONFIG_DATA_REPORT_MODE_TAG; + nfapi_resp.num_tlv++; + nfapi_resp.l23_config.sfnsf.tl.tag = NFAPI_L23_CONFIG_SFNSF_TAG; + nfapi_resp.num_tlv++; + } + + + { + //if(phy->state == NFAPI_PNF_PHY_IDLE) + //if(nfapi_resp.l1_status.phy_state.value == NFAPI_PNF_PHY_IDLE) + { + // -- NFAPI + // Downlink UEs per Subframe + nfapi_resp.nfapi_config.dl_ue_per_sf.tl.tag = NFAPI_NFAPI_DOWNLINK_UES_PER_SUBFRAME_TAG; + nfapi_resp.nfapi_config.dl_ue_per_sf.value = data->phy->dl_ues_per_subframe; + nfapi_resp.num_tlv++; + // Uplink UEs per Subframe + nfapi_resp.nfapi_config.ul_ue_per_sf.tl.tag = NFAPI_NFAPI_UPLINK_UES_PER_SUBFRAME_TAG; + nfapi_resp.nfapi_config.ul_ue_per_sf.value = data->phy->ul_ues_per_subframe; + nfapi_resp.num_tlv++; + // nFAPI RF Bands + nfapi_resp.nfapi_config.rf_bands.tl.tag = NFAPI_PHY_RF_BANDS_TAG; + nfapi_resp.nfapi_config.rf_bands.number_rf_bands = 2; + nfapi_resp.nfapi_config.rf_bands.rf_band[0] = 23; + nfapi_resp.nfapi_config.rf_bands.rf_band[1] = 7; + + // P7 PNF Address IPv4 + nfapi_resp.nfapi_config.p7_pnf_address_ipv4.tl.tag = NFAPI_NFAPI_P7_PNF_ADDRESS_IPV4_TAG; + struct sockaddr_in pnf_p7_sockaddr; + pnf_p7_sockaddr.sin_addr.s_addr = inet_addr(data->phy->local_addr.c_str()); + memcpy(&(nfapi_resp.nfapi_config.p7_pnf_address_ipv4.address[0]), &pnf_p7_sockaddr.sin_addr.s_addr, 4); + nfapi_resp.num_tlv++; + // P7 PNF Address IPv6 + // P7 PNF Port + nfapi_resp.nfapi_config.p7_pnf_port.tl.tag = NFAPI_NFAPI_P7_PNF_PORT_TAG; + nfapi_resp.nfapi_config.p7_pnf_port.value = data->phy->local_port; + nfapi_resp.num_tlv++; + // NMM GSM Frequency Bands + nfapi_resp.nfapi_config.nmm_gsm_frequency_bands.tl.tag = NFAPI_NFAPI_NMM_GSM_FREQUENCY_BANDS_TAG; + nfapi_resp.nfapi_config.nmm_gsm_frequency_bands.number_of_rf_bands = 1; + nfapi_resp.nfapi_config.nmm_gsm_frequency_bands.bands[0] = 23; + nfapi_resp.num_tlv++; + // NMM UMTS Frequency Bands + nfapi_resp.nfapi_config.nmm_umts_frequency_bands.tl.tag = NFAPI_NFAPI_NMM_UMTS_FREQUENCY_BANDS_TAG; + nfapi_resp.nfapi_config.nmm_umts_frequency_bands.number_of_rf_bands = 1; + nfapi_resp.nfapi_config.nmm_umts_frequency_bands.bands[0] = 23; + nfapi_resp.num_tlv++; + // NMM LTE Frequency Bands + nfapi_resp.nfapi_config.nmm_lte_frequency_bands.tl.tag = NFAPI_NFAPI_NMM_LTE_FREQUENCY_BANDS_TAG; + nfapi_resp.nfapi_config.nmm_lte_frequency_bands.number_of_rf_bands = 1; + nfapi_resp.nfapi_config.nmm_lte_frequency_bands.bands[0] = 23; + nfapi_resp.num_tlv++; + // NMM Uplink RSSI supported + nfapi_resp.nfapi_config.nmm_uplink_rssi_supported.tl.tag = NFAPI_NFAPI_NMM_UPLINK_RSSI_SUPPORTED_TAG; + nfapi_resp.nfapi_config.nmm_uplink_rssi_supported.value = 1; + nfapi_resp.num_tlv++; + + } + } + + + + nfapi_pnf_param_resp(data->config, &nfapi_resp); + + return 0; +} + +int fapi_config_response(fapi_t* fapi, fapi_config_resp_t* resp) +{ + pnf_phy_user_data_t* data = (pnf_phy_user_data_t*)(fapi->user_data); + + nfapi_config_response_t nfapi_resp; + memset(&nfapi_resp, 0, sizeof(nfapi_resp)); + nfapi_resp.header.message_id = NFAPI_CONFIG_RESPONSE; + nfapi_resp.header.phy_id = data->phy_id; + nfapi_resp.error_code = resp->error_code; + nfapi_pnf_config_resp(data->config, &nfapi_resp); + + return 0; +} + +int fapi_subframe_ind(fapi_t* fapi, fapi_subframe_ind_t* resp) +{ + pnf_phy_user_data_t* data = (pnf_phy_user_data_t*)(fapi->user_data); + + if(data->phy->first_subframe_ind == 0) + { + printf("Sending nfapi_pnf_start_resp phy_id:%d\n", data->phy_id); + nfapi_start_response_t start_resp; + memset(&start_resp, 0, sizeof(start_resp)); + start_resp.header.message_id = NFAPI_START_RESPONSE; + start_resp.header.phy_id = data->phy_id; + start_resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_start_resp(data->config, &start_resp); + + data->phy->first_subframe_ind = 1; + + if(data->phy->udp.enabled) + { + fapi_start_data(fapi, + data->phy->udp.rx_port, + data->phy->udp.tx_addr.c_str(), + data->phy->udp.tx_port); + } + + } + + + nfapi_pnf_p7_subframe_ind(data->p7_config, data->phy_id, resp->sfn_sf); + + return 0; + +} + +int fapi_harq_ind(fapi_t* fapi, fapi_harq_ind_t* ind) +{ + pnf_phy_user_data_t* data = (pnf_phy_user_data_t*)(fapi->user_data); + + nfapi_harq_indication_t harq_ind; + memset(&harq_ind, 0, sizeof(harq_ind)); + harq_ind.header.message_id = NFAPI_HARQ_INDICATION; + harq_ind.header.phy_id = data->p7_config->phy_id; + harq_ind.sfn_sf = ind->sfn_sf; + + if(((pnf_info*)(data->config->user_data))->wireshark_test_mode) + { + harq_ind.harq_indication_body.tl.tag = NFAPI_HARQ_INDICATION_BODY_TAG; + harq_ind.harq_indication_body.number_of_harqs = 1; + + nfapi_harq_indication_pdu_t pdus[harq_ind.harq_indication_body.number_of_harqs]; + memset(&pdus, 0, sizeof(pdus)); + + pdus[0].rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdus[0].rx_ue_information.handle = rand_range(0, 9999); + pdus[0].rx_ue_information.rnti = rand_range(1, 65535); + + + + pdus[0].harq_indication_tdd_rel8.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL8_TAG; + pdus[0].harq_indication_tdd_rel8.mode = rand_range(0, 4); + pdus[0].harq_indication_tdd_rel8.number_of_ack_nack = rand_range(1, 4); + + switch(pdus[0].harq_indication_tdd_rel8.mode) + { + case 0: + { + pdus[0].harq_indication_tdd_rel8.harq_data.bundling.value_0 = rand_range(1, 7); + pdus[0].harq_indication_tdd_rel8.harq_data.bundling.value_1 = rand_range(1, 7); + } + break; + case 1: + { + pdus[0].harq_indication_tdd_rel8.harq_data.multiplex.value_0 = rand_range(1, 7); + pdus[0].harq_indication_tdd_rel8.harq_data.multiplex.value_1 = rand_range(1, 7); + pdus[0].harq_indication_tdd_rel8.harq_data.multiplex.value_2 = rand_range(1, 7); + pdus[0].harq_indication_tdd_rel8.harq_data.multiplex.value_3 = rand_range(1, 7); + } + break; + case 2: + { + pdus[0].harq_indication_tdd_rel8.harq_data.special_bundling.value_0 = rand_range(1, 7); + } + break; + }; + + + pdus[0].harq_indication_tdd_rel9.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL9_TAG; + pdus[0].harq_indication_tdd_rel9.mode = rand_range(0, 4); + pdus[0].harq_indication_tdd_rel9.number_of_ack_nack = 1; + + switch(pdus[0].harq_indication_tdd_rel9.mode) + { + case 0: + { + pdus[0].harq_indication_tdd_rel9.harq_data[0].bundling.value_0 = rand_range(1, 7); + } + break; + case 1: + { + pdus[0].harq_indication_tdd_rel9.harq_data[0].multiplex.value_0 = rand_range(1, 7); + } + break; + case 2: + { + pdus[0].harq_indication_tdd_rel9.harq_data[0].special_bundling.value_0 = rand_range(1, 7); + } + break; + case 3: + { + pdus[0].harq_indication_tdd_rel9.harq_data[0].channel_selection.value_0 = rand_range(1, 7); + } + break; + case 4: + { + pdus[0].harq_indication_tdd_rel9.harq_data[0].format_3.value_0 = rand_range(1, 7); + } + break; + }; + + + + pdus[0].harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG; + pdus[0].harq_indication_tdd_rel13.mode = rand_range(0, 6); + pdus[0].harq_indication_tdd_rel13.number_of_ack_nack = 1; + + switch(pdus[0].harq_indication_tdd_rel13.mode) + { + case 0: + { + pdus[0].harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = rand_range(1, 7); + } + break; + case 1: + { + pdus[0].harq_indication_tdd_rel13.harq_data[0].multiplex.value_0 = rand_range(1, 7); + } + break; + case 2: + { + pdus[0].harq_indication_tdd_rel13.harq_data[0].special_bundling.value_0 = rand_range(1, 7); + } + break; + case 3: + { + pdus[0].harq_indication_tdd_rel13.harq_data[0].channel_selection.value_0 = rand_range(1, 7); + } + break; + case 4: + { + pdus[0].harq_indication_tdd_rel13.harq_data[0].format_3.value_0 = rand_range(1, 7); + } + break; + case 5: + { + pdus[0].harq_indication_tdd_rel13.harq_data[0].format_4.value_0 = rand_range(1, 7); + } + break; + case 6: + { + pdus[0].harq_indication_tdd_rel13.harq_data[0].format_5.value_0 = rand_range(1, 7); + } + break; + }; + + pdus[0].harq_indication_fdd_rel8.tl.tag = NFAPI_HARQ_INDICATION_FDD_REL8_TAG; + pdus[0].harq_indication_fdd_rel8.harq_tb1 = rand_range(1, 7); + pdus[0].harq_indication_fdd_rel8.harq_tb2 = rand_range(1, 7); + + pdus[0].harq_indication_fdd_rel9.tl.tag = NFAPI_HARQ_INDICATION_FDD_REL9_TAG; + pdus[0].harq_indication_fdd_rel9.mode = rand_range(0, 2); + pdus[0].harq_indication_fdd_rel9.number_of_ack_nack = 2; + pdus[0].harq_indication_fdd_rel9.harq_tb_n[0] = rand_range(1, 7); + pdus[0].harq_indication_fdd_rel9.harq_tb_n[1] = rand_range(1, 7); + + pdus[0].harq_indication_fdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_FDD_REL13_TAG; + pdus[0].harq_indication_fdd_rel13.mode = rand_range(0, 2); + pdus[0].harq_indication_fdd_rel13.number_of_ack_nack = 2; + pdus[0].harq_indication_fdd_rel13.harq_tb_n[0] = rand_range(1, 7); + pdus[0].harq_indication_fdd_rel13.harq_tb_n[1] = rand_range(1, 7); + + pdus[0].ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG; + pdus[0].ul_cqi_information.ul_cqi = rand_range(0,255); + pdus[0].ul_cqi_information.channel = rand_range(0, 1); + + harq_ind.harq_indication_body.harq_pdu_list = pdus; + + nfapi_pnf_p7_harq_ind(data->p7_config, &harq_ind); + } + else + { + + harq_ind.harq_indication_body.tl.tag = NFAPI_HARQ_INDICATION_BODY_TAG; + harq_ind.harq_indication_body.number_of_harqs = 8; + + nfapi_harq_indication_pdu_t pdus[8]; + memset(&pdus, 0, sizeof(pdus)); + + for(int i = 0; i < 8; ++i) + { + pdus[i].rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdus[i].rx_ue_information.handle = 0xFF; + pdus[i].rx_ue_information.rnti = i; + + pdus[i].harq_indication_fdd_rel8.tl.tag = NFAPI_HARQ_INDICATION_FDD_REL8_TAG; + pdus[i].harq_indication_fdd_rel8.harq_tb1 = 1; + pdus[i].harq_indication_fdd_rel8.harq_tb2 = 2; + } + + harq_ind.harq_indication_body.harq_pdu_list = pdus; + + nfapi_pnf_p7_harq_ind(data->p7_config, &harq_ind); + } + + return 0; +} + +int fapi_crc_ind(fapi_t* fapi, fapi_crc_ind_t* ind) +{ + pnf_phy_user_data_t* data = (pnf_phy_user_data_t*)(fapi->user_data); + + nfapi_crc_indication_t crc_ind; + memset(&crc_ind, 0, sizeof(crc_ind)); + crc_ind.header.message_id = NFAPI_CRC_INDICATION; + crc_ind.header.phy_id = data->p7_config->phy_id; + crc_ind.sfn_sf = ind->sfn_sf; + + + if(((pnf_info*)(data->config->user_data))->wireshark_test_mode) + { + crc_ind.crc_indication_body.tl.tag = NFAPI_CRC_INDICATION_BODY_TAG; + crc_ind.crc_indication_body.number_of_crcs = 1; + + nfapi_crc_indication_pdu_t pdus[crc_ind.crc_indication_body.number_of_crcs]; + memset(&pdus, 0, sizeof(pdus)); + + pdus[0].rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdus[0].rx_ue_information.handle = rand_range(0, 9999); + pdus[0].rx_ue_information.rnti = rand_range(1, 65535); + + pdus[0].crc_indication_rel8.tl.tag = NFAPI_CRC_INDICATION_REL8_TAG; + pdus[0].crc_indication_rel8.crc_flag = rand_range(0, 1); + + crc_ind.crc_indication_body.crc_pdu_list = pdus; + nfapi_pnf_p7_crc_ind(data->p7_config, &crc_ind); + } + else + { + crc_ind.crc_indication_body.tl.tag = NFAPI_CRC_INDICATION_BODY_TAG; + crc_ind.crc_indication_body.number_of_crcs = ind->body.number_of_crcs; + + crc_ind.crc_indication_body.crc_pdu_list = (nfapi_crc_indication_pdu_t*)malloc(sizeof(nfapi_crc_indication_pdu_t) * ind->body.number_of_crcs); + + for(int i = 0; i < ind->body.number_of_crcs; ++i) + { + crc_ind.crc_indication_body.crc_pdu_list[i].rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + crc_ind.crc_indication_body.crc_pdu_list[i].rx_ue_information.handle = ind->body.pdus[i].rx_ue_info.handle; + crc_ind.crc_indication_body.crc_pdu_list[i].rx_ue_information.rnti = ind->body.pdus[i].rx_ue_info.rnti; + crc_ind.crc_indication_body.crc_pdu_list[i].crc_indication_rel8.tl.tag = NFAPI_CRC_INDICATION_REL8_TAG; + crc_ind.crc_indication_body.crc_pdu_list[i].crc_indication_rel8.crc_flag = ind->body.pdus[i].rel8_pdu.crc_flag; + } + + nfapi_pnf_p7_crc_ind(data->p7_config, &crc_ind); + + free(crc_ind.crc_indication_body.crc_pdu_list); + } + + return 0; +} +int fapi_rx_ulsch_ind(fapi_t* fapi, fapi_rx_ulsch_ind_t* ind) +{ + pnf_phy_user_data_t* data = (pnf_phy_user_data_t*)(fapi->user_data); + + nfapi_rx_indication_t rx_ind; + memset(&rx_ind, 0, sizeof(rx_ind)); + rx_ind.header.message_id = NFAPI_RX_ULSCH_INDICATION; + rx_ind.header.phy_id = data->p7_config->phy_id; + rx_ind.sfn_sf = ind->sfn_sf; + + if(1)//((pnf_info*)(data->config->user_data))->wireshark_test_mode) + { + rx_ind.rx_indication_body.tl.tag = NFAPI_RX_INDICATION_BODY_TAG; + rx_ind.rx_indication_body.number_of_pdus = 1; + + uint8_t rx_data[1024]; + + nfapi_rx_indication_pdu_t pdus[rx_ind.rx_indication_body.number_of_pdus]; + memset(&pdus, 0, sizeof(pdus)); + + strcpy((char*)rx_data, (char*)"123456789"); + + for(int i = 0; i < rx_ind.rx_indication_body.number_of_pdus;++i) + { + + pdus[i].rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdus[i].rx_ue_information.handle = rand_range(0, 9999); + pdus[i].rx_ue_information.rnti = rand_range(1, 65535); + + pdus[i].rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG; + pdus[i].rx_indication_rel8.length = 10;//rand_range(0, 1024); + pdus[i].rx_indication_rel8.offset = 0;//djp - 1; + pdus[i].rx_indication_rel8.ul_cqi = rand_range(0, 255); + pdus[i].rx_indication_rel8.timing_advance = rand_range(0, 63); + + //pdus[i].rx_indication_rel9.tl.tag = NFAPI_RX_INDICATION_REL9_TAG; + //pdus[i].rx_indication_rel9.timing_advance_r9 = rand_range(0, 7690); + + pdus[i].data = &rx_data[0]; + } + + rx_ind.rx_indication_body.rx_pdu_list = pdus; + + nfapi_pnf_p7_rx_ind(data->p7_config, &rx_ind); + } + else + { + + rx_ind.rx_indication_body.tl.tag = NFAPI_RX_INDICATION_BODY_TAG; + rx_ind.rx_indication_body.number_of_pdus = ind->body.number_of_pdus; + + rx_ind.rx_indication_body.rx_pdu_list = (nfapi_rx_indication_pdu_t*)malloc(sizeof(nfapi_rx_indication_pdu_t) * ind->body.number_of_pdus); + + for(int i = 0; i < ind->body.number_of_pdus; ++i) + { + rx_ind.rx_indication_body.rx_pdu_list[i].rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + rx_ind.rx_indication_body.rx_pdu_list[i].rx_ue_information.handle = ind->body.pdus[i].rx_ue_info.handle; + rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG; + rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.length = ind->body.pdus[i].rel8_pdu.length; + rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel8.offset = 1; + rx_ind.rx_indication_body.rx_pdu_list[i].rx_indication_rel9.tl.tag = 0; + rx_ind.rx_indication_body.rx_pdu_list[i].data = (uint8_t*)ind->body.data[i]; + + } + + nfapi_pnf_p7_rx_ind(data->p7_config, &rx_ind); + + free(rx_ind.rx_indication_body.rx_pdu_list); + } + + return 0; + +} +int fapi_rx_cqi_ind(fapi_t* fapi, fapi_rx_cqi_ind_t* ind) +{ + pnf_phy_user_data_t* data = (pnf_phy_user_data_t*)(fapi->user_data); + + nfapi_cqi_indication_t cqi_ind; + memset(&cqi_ind, 0, sizeof(cqi_ind)); + cqi_ind.header.message_id = NFAPI_RX_CQI_INDICATION; + cqi_ind.header.phy_id = data->p7_config->phy_id; + cqi_ind.sfn_sf = ind->sfn_sf; + + if(((pnf_info*)(data->config->user_data))->wireshark_test_mode) + { + cqi_ind.cqi_indication_body.tl.tag = NFAPI_CQI_INDICATION_BODY_TAG; + cqi_ind.cqi_indication_body.number_of_cqis = 3; + + nfapi_cqi_indication_pdu_t cqi_pdu_list[cqi_ind.cqi_indication_body.number_of_cqis]; + memset(&cqi_pdu_list, 0, sizeof(cqi_pdu_list)); + nfapi_cqi_indication_raw_pdu_t cqi_raw_pdu_list[cqi_ind.cqi_indication_body.number_of_cqis]; + //memset(&cqi_raw_pdu_list, 0, sizeof(cqi_raw_pdu_list)); + + + for(int i = 0; i < cqi_ind.cqi_indication_body.number_of_cqis; ++i) + { + cqi_pdu_list[i].rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + cqi_pdu_list[i].rx_ue_information.handle = rand_range(0, 9999); + cqi_pdu_list[i].rx_ue_information.rnti = rand_range(1, 65535); + + uint8_t rel8_or_9 = rand_range(0, 1); + + if(rel8_or_9) + { + cqi_pdu_list[i].cqi_indication_rel8.tl.tag = NFAPI_CQI_INDICATION_REL8_TAG; + cqi_pdu_list[i].cqi_indication_rel8.length = 8; //rand_range(1, 12); + cqi_pdu_list[i].cqi_indication_rel8.data_offset = 1; //rand_range(0, 1); + cqi_pdu_list[i].cqi_indication_rel8.ul_cqi = 0; + cqi_pdu_list[i].cqi_indication_rel8.ri = rand_range(0, 4); + cqi_pdu_list[i].cqi_indication_rel8.timing_advance = rand_range(0, 63); + } + else + { + cqi_pdu_list[i].cqi_indication_rel9.tl.tag = NFAPI_CQI_INDICATION_REL9_TAG; + cqi_pdu_list[i].cqi_indication_rel9.length = 8; //rand_range(1, 12); + cqi_pdu_list[i].cqi_indication_rel9.data_offset = 1; //rand_range(0, 1); + cqi_pdu_list[i].cqi_indication_rel9.ul_cqi = 0; //rand_range(0, 1); + cqi_pdu_list[i].cqi_indication_rel9.number_of_cc_reported = 1; + cqi_pdu_list[i].cqi_indication_rel9.ri[0] = rand_range(0, 8); + cqi_pdu_list[i].cqi_indication_rel9.timing_advance = rand_range(0, 63); + cqi_pdu_list[i].cqi_indication_rel9.timing_advance_r9 = rand_range(0, 7690); + } + + cqi_pdu_list[i].ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG; + cqi_pdu_list[i].ul_cqi_information.ul_cqi = rand_range(0,255); + cqi_pdu_list[i].ul_cqi_information.channel = rand_range(0, 1); + } + + cqi_ind.cqi_indication_body.cqi_pdu_list = cqi_pdu_list; + cqi_ind.cqi_indication_body.cqi_raw_pdu_list = cqi_raw_pdu_list; + + nfapi_pnf_p7_cqi_ind(data->p7_config, &cqi_ind); + } + else + { + nfapi_pnf_p7_cqi_ind(data->p7_config, &cqi_ind); + } + + return 0; +} +int fapi_rx_sr_ind(fapi_t* fapi, fapi_rx_sr_ind_t* ind) +{ + pnf_phy_user_data_t* data = (pnf_phy_user_data_t*)(fapi->user_data); + + nfapi_sr_indication_t sr_ind; + memset(&sr_ind, 0, sizeof(sr_ind)); + sr_ind.header.message_id = NFAPI_RX_SR_INDICATION; + sr_ind.header.phy_id = data->p7_config->phy_id; + sr_ind.sfn_sf = ind->sfn_sf; + + if(((pnf_info*)(data->config->user_data))->wireshark_test_mode) + { + sr_ind.sr_indication_body.tl.tag = NFAPI_SR_INDICATION_BODY_TAG; + sr_ind.sr_indication_body.number_of_srs = 1; + + nfapi_sr_indication_pdu_t pdus[sr_ind.sr_indication_body.number_of_srs]; + memset(&pdus, 0, sizeof(pdus)); + + pdus[0].rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdus[0].rx_ue_information.handle = rand_range(0, 9999); + pdus[0].rx_ue_information.rnti = rand_range(1, 65535); + + pdus[0].ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG; + pdus[0].ul_cqi_information.ul_cqi = rand_range(0,255); + pdus[0].ul_cqi_information.channel = rand_range(0, 1); + + sr_ind.sr_indication_body.sr_pdu_list = pdus; + + nfapi_pnf_p7_sr_ind(data->p7_config, &sr_ind); + } + else + { + nfapi_pnf_p7_sr_ind(data->p7_config, &sr_ind); + } + + return 0; +} + +int fapi_rach_ind(fapi_t* fapi, fapi_rach_ind_t* ind) +{ + pnf_phy_user_data_t* data = (pnf_phy_user_data_t*)(fapi->user_data); + + nfapi_rach_indication_t rach_ind; + memset(&rach_ind, 0, sizeof(rach_ind)); + rach_ind.header.message_id = NFAPI_RACH_INDICATION; + rach_ind.header.phy_id = data->p7_config->phy_id; + rach_ind.sfn_sf = ind->sfn_sf; + + if(((pnf_info*)(data->config->user_data))->wireshark_test_mode) + { + rach_ind.rach_indication_body.tl.tag = NFAPI_RACH_INDICATION_BODY_TAG; + rach_ind.rach_indication_body.number_of_preambles = 1; + + nfapi_preamble_pdu_t pdus[rach_ind.rach_indication_body.number_of_preambles]; + memset(&pdus, 0, sizeof(pdus)); + + pdus[0].preamble_rel8.tl.tag = NFAPI_PREAMBLE_REL8_TAG; + pdus[0].preamble_rel8.rnti = rand_range(1, 65535); + pdus[0].preamble_rel8.preamble = rand_range(0, 63); + pdus[0].preamble_rel8.timing_advance = rand_range(0, 1282); + pdus[0].preamble_rel9.tl.tag = NFAPI_PREAMBLE_REL9_TAG; + pdus[0].preamble_rel9.timing_advance_r9 = rand_range(0, 7690); + pdus[0].preamble_rel13.tl.tag = NFAPI_PREAMBLE_REL13_TAG; + pdus[0].preamble_rel13.rach_resource_type = rand_range(0, 4); + + rach_ind.rach_indication_body.preamble_list = pdus; + nfapi_pnf_p7_rach_ind(data->p7_config, &rach_ind); + } + else + { + nfapi_pnf_p7_rach_ind(data->p7_config, &rach_ind); + } + + return 0; +} + +int fapi_srs_ind(fapi_t* fapi, fapi_srs_ind_t* ind) +{ + pnf_phy_user_data_t* data = (pnf_phy_user_data_t*)(fapi->user_data); + + nfapi_srs_indication_t srs_ind; + memset(&srs_ind, 0, sizeof(srs_ind)); + srs_ind.header.message_id = NFAPI_SRS_INDICATION; + srs_ind.header.phy_id = data->p7_config->phy_id; + srs_ind.sfn_sf = ind->sfn_sf; + + if(((pnf_info*)(data->config->user_data))->wireshark_test_mode) + { + srs_ind.srs_indication_body.tl.tag = NFAPI_SRS_INDICATION_BODY_TAG; + srs_ind.srs_indication_body.number_of_ues = 1; + + nfapi_srs_indication_pdu_t pdus[srs_ind.srs_indication_body.number_of_ues]; + memset(&pdus, 0, sizeof(pdus)); + + pdus[0].rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdus[0].rx_ue_information.handle = rand_range(0, 9999); + pdus[0].rx_ue_information.rnti = rand_range(1, 65535); + + pdus[0].srs_indication_fdd_rel8.tl.tag = NFAPI_SRS_INDICATION_FDD_REL8_TAG; + pdus[0].srs_indication_fdd_rel8.doppler_estimation = rand_range(0, 255); + pdus[0].srs_indication_fdd_rel8.timing_advance = rand_range(0, 63); + pdus[0].srs_indication_fdd_rel8.number_of_resource_blocks = 2; //rand_range(0, 255); + pdus[0].srs_indication_fdd_rel8.rb_start = rand_range(0, 245); + pdus[0].srs_indication_fdd_rel8.snr[0] = rand_range(0, 255); + pdus[0].srs_indication_fdd_rel8.snr[1] = rand_range(0, 255); + + pdus[0].srs_indication_fdd_rel9.tl.tag = NFAPI_SRS_INDICATION_FDD_REL9_TAG; + pdus[0].srs_indication_fdd_rel9.timing_advance_r9 = rand_range(0, 7690); + + pdus[0].srs_indication_tdd_rel10.tl.tag = NFAPI_SRS_INDICATION_TDD_REL10_TAG; + pdus[0].srs_indication_tdd_rel10.uppts_symbol = rand_range(0, 1); + + pdus[0].srs_indication_fdd_rel11.tl.tag = NFAPI_SRS_INDICATION_FDD_REL11_TAG; + pdus[0].srs_indication_fdd_rel11.ul_rtoa; + + pdus[0].tdd_channel_measurement.tl.tag = NFAPI_TDD_CHANNEL_MEASUREMENT_TAG; + pdus[0].tdd_channel_measurement.num_prb_per_subband = rand_range(0, 255); + pdus[0].tdd_channel_measurement.number_of_subbands = 1; + pdus[0].tdd_channel_measurement.num_atennas = 2; + pdus[0].tdd_channel_measurement.subands[0].subband_index = rand_range(0, 255); + pdus[0].tdd_channel_measurement.subands[0].channel[0] = rand_range(0, 9999); + pdus[0].tdd_channel_measurement.subands[0].channel[1] = rand_range(0, 9999); + + srs_ind.srs_indication_body.srs_pdu_list = pdus; + nfapi_pnf_p7_srs_ind(data->p7_config, &srs_ind); + } + else + { + nfapi_pnf_p7_srs_ind(data->p7_config, &srs_ind); + } + + return 0; +} + +int fapi_lbt_dl_ind(fapi_t* fapi, fapi_lbt_dl_ind_t* ind) +{ + pnf_phy_user_data_t* data = (pnf_phy_user_data_t*)(fapi->user_data); + + nfapi_lbt_dl_indication_t lbt_dl_ind; + memset(&lbt_dl_ind, 0, sizeof(lbt_dl_ind)); + lbt_dl_ind.header.message_id = NFAPI_LBT_DL_INDICATION; + lbt_dl_ind.header.phy_id = data->p7_config->phy_id; + lbt_dl_ind.sfn_sf = ind->sfn_sf; + + if(((pnf_info*)(data->config->user_data))->wireshark_test_mode) + { + lbt_dl_ind.lbt_dl_indication_body.tl.tag = NFAPI_LBT_DL_INDICATION_BODY_TAG; + lbt_dl_ind.lbt_dl_indication_body.number_of_pdus = 2; + + nfapi_lbt_dl_indication_pdu_t pdus[lbt_dl_ind.lbt_dl_indication_body.number_of_pdus]; + memset(&pdus, 0, sizeof(pdus)); + + pdus[0].pdu_type = 0; // LBT_PDSCH_RSP PDU + pdus[0].pdu_size = 0; + pdus[0].lbt_pdsch_rsp_pdu.lbt_pdsch_rsp_pdu_rel13.tl.tag = NFAPI_LBT_PDSCH_RSP_PDU_REL13_TAG; + pdus[0].lbt_pdsch_rsp_pdu.lbt_pdsch_rsp_pdu_rel13.handle = 0xABCD; + pdus[0].lbt_pdsch_rsp_pdu.lbt_pdsch_rsp_pdu_rel13.result = rand_range(0, 1); + pdus[0].lbt_pdsch_rsp_pdu.lbt_pdsch_rsp_pdu_rel13.lte_txop_symbols = rand_range(0, 0xFFFF); + pdus[0].lbt_pdsch_rsp_pdu.lbt_pdsch_rsp_pdu_rel13.initial_partial_sf = rand_range(0, 1); + + pdus[1].pdu_type = 1; // LBT_DRS_RSP PDU + pdus[1].pdu_size = 0; + pdus[1].lbt_drs_rsp_pdu.lbt_drs_rsp_pdu_rel13.tl.tag = NFAPI_LBT_DRS_RSP_PDU_REL13_TAG; + pdus[1].lbt_drs_rsp_pdu.lbt_drs_rsp_pdu_rel13.handle = 0xABCD; + pdus[1].lbt_drs_rsp_pdu.lbt_drs_rsp_pdu_rel13.result = rand_range(0, 1); + + lbt_dl_ind.lbt_dl_indication_body.lbt_indication_pdu_list = pdus; + nfapi_pnf_p7_lbt_dl_ind(data->p7_config, &lbt_dl_ind); + } + else + { + nfapi_pnf_p7_lbt_dl_ind(data->p7_config, &lbt_dl_ind); + } + + return 0; +} + +int fapi_nb_harq_ind(fapi_t* fapi, fapi_nb_harq_ind_t* ind) +{ + pnf_phy_user_data_t* data = (pnf_phy_user_data_t*)(fapi->user_data); + + nfapi_nb_harq_indication_t nb_harq_ind; + memset(&nb_harq_ind, 0, sizeof(nb_harq_ind)); + nb_harq_ind.header.message_id = NFAPI_NB_HARQ_INDICATION; + nb_harq_ind.header.phy_id = data->p7_config->phy_id; + nb_harq_ind.sfn_sf = ind->sfn_sf; + + if(((pnf_info*)(data->config->user_data))->wireshark_test_mode) + { + + nb_harq_ind.nb_harq_indication_body.tl.tag = NFAPI_NB_HARQ_INDICATION_BODY_TAG; + nb_harq_ind.nb_harq_indication_body.number_of_harqs = 1; + + nfapi_nb_harq_indication_pdu_t pdus[nb_harq_ind.nb_harq_indication_body.number_of_harqs]; + memset(&pdus, 0, sizeof(pdus)); + + pdus[0].rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + pdus[0].rx_ue_information.handle = rand_range(0, 0xFFFF); + pdus[0].rx_ue_information.rnti = rand_range(0, 65535); + + pdus[0].nb_harq_indication_fdd_rel13.tl.tag = NFAPI_NB_HARQ_INDICATION_FDD_REL13_TAG; + pdus[0].nb_harq_indication_fdd_rel13.harq_tb1 = rand_range(1, 7); + + pdus[0].ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG; + pdus[0].ul_cqi_information.ul_cqi = rand_range(0, 255); + pdus[0].ul_cqi_information.channel = rand_range(0, 1); + + nb_harq_ind.nb_harq_indication_body.nb_harq_pdu_list = pdus; + nfapi_pnf_p7_nb_harq_ind(data->p7_config, &nb_harq_ind); + } + else + { + nfapi_pnf_p7_nb_harq_ind(data->p7_config, &nb_harq_ind); + } + + return 0; +} + +int fapi_nrach_ind(fapi_t* fapi, fapi_nrach_ind_t* ind) +{ + pnf_phy_user_data_t* data = (pnf_phy_user_data_t*)(fapi->user_data); + + nfapi_nrach_indication_t nrach_ind; + memset(&nrach_ind, 0, sizeof(nrach_ind)); + nrach_ind.header.message_id = NFAPI_NRACH_INDICATION; + nrach_ind.header.phy_id = data->p7_config->phy_id; + nrach_ind.sfn_sf = ind->sfn_sf; + + if(((pnf_info*)(data->config->user_data))->wireshark_test_mode) + { + nrach_ind.nrach_indication_body.tl.tag = NFAPI_NRACH_INDICATION_BODY_TAG; + nrach_ind.nrach_indication_body.number_of_initial_scs_detected = 1; + + nfapi_nrach_indication_pdu_t pdus[nrach_ind.nrach_indication_body.number_of_initial_scs_detected]; + memset(&pdus, 0, sizeof(pdus)); + + pdus[0].nrach_indication_rel13.tl.tag = NFAPI_NRACH_INDICATION_REL13_TAG; + pdus[0].nrach_indication_rel13.rnti = rand_range(1, 65535); + pdus[0].nrach_indication_rel13.initial_sc = rand_range(0, 47); + pdus[0].nrach_indication_rel13.timing_advance = rand_range(0, 3840); + pdus[0].nrach_indication_rel13.nrach_ce_level = rand_range(0, 2); + + nrach_ind.nrach_indication_body.nrach_pdu_list = pdus; + + nfapi_pnf_p7_nrach_ind(data->p7_config, &nrach_ind); + } + else + { + nfapi_pnf_p7_nrach_ind(data->p7_config, &nrach_ind); + } + + return 0; +} + +int pnf_start_request(nfapi_pnf_config_t* config, nfapi_pnf_start_request_t* req) +{ + + pnf_info* pnf = (pnf_info*)(config->user_data); + + // start all phys that have been configured + for(phy_info& phy : pnf->phys) + { + if(phy.id != 0) + { + //auto found = std::find_if(pnf->phys.begin(), pnf->phys.end(), [&](phy_info& item) + // { return item.id == req->header.phy_id; }); +// +// if(found != pnf->phys.end()) +// { +// phy_info& phy = (*found); + + fapi_cb_t cb; + cb.fapi_param_response = &fapi_param_response; + cb.fapi_config_response = &fapi_config_response; + cb.fapi_subframe_ind = &fapi_subframe_ind; + cb.fapi_harq_ind = fapi_harq_ind; + cb.fapi_crc_ind = fapi_crc_ind; + cb.fapi_rx_ulsch_ind = fapi_rx_ulsch_ind; + cb.fapi_rx_cqi_ind = fapi_rx_cqi_ind; + cb.fapi_rx_sr_ind = fapi_rx_sr_ind; + cb.fapi_rach_ind = fapi_rach_ind; + cb.fapi_srs_ind = fapi_srs_ind; + + cb.fapi_lbt_dl_ind = fapi_lbt_dl_ind; + cb.fapi_nb_harq_ind = fapi_nb_harq_ind; + cb.fapi_nrach_ind = fapi_nrach_ind; + + + + fapi_config_t c; + c.duplex_mode = phy.duplex_mode; + c.dl_channel_bw_support = phy.dl_channel_bw_support; + c.ul_channel_bw_support = phy.ul_channel_bw_support; + + phy.fapi = fapi_create(&cb, &c); + printf("[PNF_SIM] staring fapi %p phy_id:%d\n", phy.fapi, phy.id); + + pnf_phy_user_data_t* data = (pnf_phy_user_data_t*)malloc(sizeof(pnf_phy_user_data_t)); + data->phy_id = phy.id; + data->config = config; + data->phy = &phy; + + phy.fapi->user_data = data; + } + + } + + nfapi_pnf_start_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_START_RESPONSE; + resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_pnf_start_resp(config, &resp); + + return 0; +} + +int pnf_stop_request(nfapi_pnf_config_t* config, nfapi_pnf_stop_request_t* req) +{ + printf("[PNF_SIM] pnf stop request\n"); + + nfapi_pnf_stop_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_STOP_RESPONSE; + resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_pnf_stop_resp(config, &resp); + + return 0; +} + +int param_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_param_request_t* req) +{ + printf("[PNF_SIM] param request phy_id:%d\n", req->header.phy_id); + + pnf_info* pnf = (pnf_info*)(config->user_data); + + auto found = std::find_if(pnf->phys.begin(), pnf->phys.end(), [&](phy_info& item) + { return item.id == req->header.phy_id; }); + + if(found != pnf->phys.end()) + { + phy_info& phy_info = (*found); + + fapi_param_req_t fapi_req; + fapi_req.header.message_id = req->header.message_id; + fapi_req.header.length = 0; + + // convert nfapi to fapi + + fapi_param_request(phy_info.fapi, &fapi_req); + + } + else + { + // did not find the phy + } + + + printf("[PNF_SIM] param request .. exit\n"); + + + return 0; +} + +int config_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_config_request_t* req) +{ + printf("[PNF_SIM] config request phy_id:%d\n", req->header.phy_id); + + pnf_info* pnf = (pnf_info*)(config->user_data); + + auto found = std::find_if(pnf->phys.begin(), pnf->phys.end(), [&](phy_info& item) + { return item.id == req->header.phy_id; }); + + if(found != pnf->phys.end()) + { + phy_info& phy_info = (*found); + + + if(req->nfapi_config.timing_window.tl.tag == NFAPI_NFAPI_TIMING_WINDOW_TAG) + { + phy_info.timing_window = req->nfapi_config.timing_window.value; + } + + if(req->nfapi_config.timing_info_mode.tl.tag == NFAPI_NFAPI_TIMING_INFO_MODE_TAG) + { + printf("timing info mode provided\n"); + phy_info.timing_info_mode = req->nfapi_config.timing_info_mode.value; + } + else + { + phy_info.timing_info_mode = 0; + printf("NO timing info mode provided\n"); + } + + if(req->nfapi_config.timing_info_period.tl.tag == NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG) + { + printf("timing info period provided\n"); + phy_info.timing_info_period = req->nfapi_config.timing_info_period.value; + } + else + { + phy_info.timing_info_period = 0; + } + + phy_info.remote_port = req->nfapi_config.p7_vnf_port.value; + + struct sockaddr_in vnf_p7_sockaddr; + memcpy(&vnf_p7_sockaddr.sin_addr.s_addr, &(req->nfapi_config.p7_vnf_address_ipv4.address[0]), 4); + phy_info.remote_addr = inet_ntoa(vnf_p7_sockaddr.sin_addr); + + printf("[PNF_SIM] %d vnf p7 %s:%d timing %d %d %d\n", phy_info.id, phy_info.remote_addr, phy_info.remote_port, + phy_info.timing_window, phy_info.timing_info_mode, phy_info.timing_info_period); + + fapi_config_req_t fapi_req; + fapi_config_request(phy_info.fapi, &fapi_req); + } + + return 0; +} + +nfapi_p7_message_header_t* phy_allocate_p7_vendor_ext(uint16_t message_id, uint16_t* msg_size) +{ + if(message_id == P7_VENDOR_EXT_REQ) + { + (*msg_size) = sizeof(vendor_ext_p7_req); + return (nfapi_p7_message_header_t*)malloc(sizeof(vendor_ext_p7_req)); + } + + return 0; +} + +void phy_deallocate_p7_vendor_ext(nfapi_p7_message_header_t* header) +{ + free(header); +} + +int phy_dl_config_req(nfapi_pnf_p7_config_t* pnf_p7, nfapi_dl_config_request_t* req) +{ + //printf("[PNF_SIM] dl config request\n"); + + if(req->vendor_extension) + free(req->vendor_extension); + + phy_info* phy = (phy_info*)(pnf_p7->user_data); + + fapi_dl_config_req_t fapi_req; + // convert + fapi_dl_config_request(phy->fapi, &fapi_req); + + return 0; +} +int phy_ul_config_req(nfapi_pnf_p7_config_t* pnf_p7, nfapi_ul_config_request_t* req) +{ + //printf("[PNF_SIM] ul config request\n"); + phy_info* phy = (phy_info*)(pnf_p7->user_data); + + fapi_ul_config_req_t fapi_req; + // convert + fapi_ul_config_request(phy->fapi, &fapi_req); + + return 0; +} +int phy_hi_dci0_req(nfapi_pnf_p7_config_t* pnf_p7, nfapi_hi_dci0_request_t* req) +{ + //printf("[PNF_SIM] hi dci0 request\n"); + phy_info* phy = (phy_info*)(pnf_p7->user_data); + + fapi_hi_dci0_req_t fapi_req; + // convert + fapi_hi_dci0_request(phy->fapi, &fapi_req); + return 0; +} +int phy_tx_req(nfapi_pnf_p7_config_t* pnf_p7, nfapi_tx_request_t* req) +{ + //printf("[PNF_SIM] tx request\n"); + phy_info* phy = (phy_info*)(pnf_p7->user_data); + + fapi_tx_req_t fapi_req; + fapi_req.header.message_id = FAPI_TX_REQUEST; + fapi_req.sfn_sf = req->sfn_sf; + fapi_req.body.number_of_pdus = req->tx_request_body.number_of_pdus; + + fapi_tx_req_pdu_t pdus[8]; + fapi_req.body.pdus = &pdus[0]; + + for(int i = 0; i < fapi_req.body.number_of_pdus; ++i) + { + fapi_req.body.pdus[i].pdu_length = req->tx_request_body.tx_pdu_list[i].pdu_length; + fapi_req.body.pdus[i].pdu_index = req->tx_request_body.tx_pdu_list[i].pdu_index; + fapi_req.body.pdus[i].num_tlv = 1; + fapi_req.body.pdus[i].tlvs[0].value = (uint32_t*)req->tx_request_body.tx_pdu_list[i].segments[0].segment_data; + + //if the pnf wants to retain the pointer then req->tx_request_body.tx_pdu_list[i].segments[0].segment_data should be set to 0 + + + } + + fapi_tx_request(phy->fapi, &fapi_req); +/* + if(fapi_req.body.number_of_pdus > 0) + { + for(int i = 0; i < fapi_req.body.number_of_pdus; ++i) + { + //printf("freeing tx pdu %p\n", fapi_req.body.pdus[i].tlvs[0].value); + if(0) + { + free(fapi_req.body.pdus[i].tlvs[0].value); + } + else + { + pnf_deallocate(fapi_req.body.pdus[i].tlvs[0].value); + } + } + } +*/ + + return 0; +} +int phy_lbt_dl_config_req(nfapi_pnf_p7_config_t*, nfapi_lbt_dl_config_request_t* req) +{ + //printf("[PNF_SIM] lbt dl config request\n"); + return 0; +} + +int phy_vendor_ext(nfapi_pnf_p7_config_t* config, nfapi_p7_message_header_t* msg) +{ + if(msg->message_id == P7_VENDOR_EXT_REQ) + { + vendor_ext_p7_req* req = (vendor_ext_p7_req*)msg; + //printf("[PNF_SIM] vendor request (1:%d 2:%d)\n", req->dummy1, req->dummy2); + } + else + { + printf("[PNF_SIM] unknown vendor ext\n"); + } + return 0; +} + + + +int phy_pack_p7_vendor_extension(nfapi_p7_message_header_t* header, uint8_t** ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* codex) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if(header->message_id == P7_VENDOR_EXT_IND) + { + vendor_ext_p7_ind* ind = (vendor_ext_p7_ind*)(header); + if(!push16(ind->error_code, ppWritePackedMsg, end)) + return 0; + + return 1; + } + return -1; +} + +int phy_unpack_p7_vendor_extension(nfapi_p7_message_header_t* header, uint8_t** ppReadPackedMessage, uint8_t *end, nfapi_p7_codec_config_t* codec) +{ + if(header->message_id == P7_VENDOR_EXT_REQ) + { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + vendor_ext_p7_req* req = (vendor_ext_p7_req*)(header); + if(!(pull16(ppReadPackedMessage, &req->dummy1, end) && + pull16(ppReadPackedMessage, &req->dummy2, end))) + return 0; + return 1; + } + return -1; +} + +int phy_unpack_vendor_extension_tlv(nfapi_tl_t* tl, uint8_t **ppReadPackedMessage, uint8_t* end, void** ve, nfapi_p7_codec_config_t* config) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "phy_unpack_vendor_extension_tlv\n"); + + switch(tl->tag) + { + case VENDOR_EXT_TLV_1_TAG: + *ve = malloc(sizeof(vendor_ext_tlv_1)); + if(!pull32(ppReadPackedMessage, &((vendor_ext_tlv_1*)(*ve))->dummy, end)) + return 0; + + return 1; + break; + } + + return -1; +} + +int phy_pack_vendor_extention_tlv(void* ve, uint8_t **ppWritePackedMsg, uint8_t* end, nfapi_p7_codec_config_t* config) +{ + //printf("%s\n", __FUNCTION__); + (void)ve; + (void)ppWritePackedMsg; + return -1; +} + +int pnf_sim_unpack_vendor_extension_tlv(nfapi_tl_t* tl, uint8_t **ppReadPackedMessage, uint8_t *end, void** ve, nfapi_p4_p5_codec_config_t* config) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "pnf_sim_unpack_vendor_extension_tlv\n"); + + switch(tl->tag) + { + case VENDOR_EXT_TLV_2_TAG: + *ve = malloc(sizeof(vendor_ext_tlv_2)); + if(!pull32(ppReadPackedMessage, &((vendor_ext_tlv_2*)(*ve))->dummy, end)) + return 0; + + return 1; + break; + } + + return -1; +} + +int pnf_sim_pack_vendor_extention_tlv(void* ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + //printf("%s\n", __FUNCTION__); + (void)ve; + (void)ppWritePackedMsg; + return -1; +} +int start_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_start_request_t* req) +{ + printf("[PNF_SIM] start request phy_id:%d\n", req->header.phy_id); + + pnf_info* pnf = (pnf_info*)(config->user_data); + + auto found = std::find_if(pnf->phys.begin(), pnf->phys.end(), [&](phy_info& item) + { return item.id == req->header.phy_id; }); + + if(found != pnf->phys.end()) + { + phy_info& phy_info = (*found); + + + nfapi_pnf_p7_config_t* p7_config = nfapi_pnf_p7_config_create(); + + p7_config->phy_id = phy->phy_id; + + p7_config->remote_p7_port = phy_info.remote_port; + p7_config->remote_p7_addr = phy_info.remote_addr; + p7_config->local_p7_port = phy_info.local_port; + p7_config->local_p7_addr = (char*)phy_info.local_addr.c_str(); + p7_config->user_data = &phy_info; + + p7_config->malloc = &pnf_allocate; + p7_config->free = &pnf_deallocate; + p7_config->codec_config.allocate = &pnf_allocate; + p7_config->codec_config.deallocate = &pnf_deallocate; + + p7_config->trace = &pnf_sim_trace; + + phy->user_data = p7_config; + + p7_config->subframe_buffer_size = phy_info.timing_window; + if(phy_info.timing_info_mode & 0x1) + { + p7_config->timing_info_mode_periodic = 1; + p7_config->timing_info_period = phy_info.timing_info_period; + } + + if(phy_info.timing_info_mode & 0x2) + { + p7_config->timing_info_mode_aperiodic = 1; + } + + p7_config->dl_config_req = &phy_dl_config_req; + p7_config->ul_config_req = &phy_ul_config_req; + p7_config->hi_dci0_req = &phy_hi_dci0_req; + p7_config->tx_req = &phy_tx_req; + p7_config->lbt_dl_config_req = &phy_lbt_dl_config_req; + + p7_config->vendor_ext = &phy_vendor_ext; + + p7_config->allocate_p7_vendor_ext = &phy_allocate_p7_vendor_ext; + p7_config->deallocate_p7_vendor_ext = &phy_deallocate_p7_vendor_ext; + + p7_config->codec_config.unpack_p7_vendor_extension = &phy_unpack_p7_vendor_extension; + p7_config->codec_config.pack_p7_vendor_extension = &phy_pack_p7_vendor_extension; + p7_config->codec_config.unpack_vendor_extension_tlv = &phy_unpack_vendor_extension_tlv; + p7_config->codec_config.pack_vendor_extension_tlv = &phy_pack_vendor_extention_tlv; + + pthread_t p7_thread; + pthread_create(&p7_thread, NULL, &pnf_p7_thread_start, p7_config); + + + ((pnf_phy_user_data_t*)(phy_info.fapi->user_data))->p7_config = p7_config; + + fapi_start_req_t fapi_req; + fapi_start_request(phy_info.fapi, &fapi_req); + + } + + return 0; +} + +int measurement_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_measurement_request_t* req) +{ + nfapi_measurement_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_MEASUREMENT_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_MSG_OK; + nfapi_pnf_measurement_resp(config, &resp); + return 0; +} +int rssi_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_rssi_request_t* req) +{ + nfapi_rssi_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_RSSI_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_P4_MSG_OK; + nfapi_pnf_rssi_resp(config, &resp); + + nfapi_rssi_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_RSSI_INDICATION; + ind.header.phy_id = req->header.phy_id; + ind.error_code = NFAPI_P4_MSG_OK; + ind.rssi_indication_body.tl.tag = NFAPI_RSSI_INDICATION_TAG; + ind.rssi_indication_body.number_of_rssi = 1; + ind.rssi_indication_body.rssi[0] = -42; + nfapi_pnf_rssi_ind(config, &ind); + return 0; +} +int cell_search_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_cell_search_request_t* req) +{ + nfapi_cell_search_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_CELL_SEARCH_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_P4_MSG_OK; + nfapi_pnf_cell_search_resp(config, &resp); + + nfapi_cell_search_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_CELL_SEARCH_INDICATION; + ind.header.phy_id = req->header.phy_id; + ind.error_code = NFAPI_P4_MSG_OK; + + switch(req->rat_type) + { + case NFAPI_RAT_TYPE_LTE: + { + ind.lte_cell_search_indication.tl.tag = NFAPI_LTE_CELL_SEARCH_INDICATION_TAG; + ind.lte_cell_search_indication.number_of_lte_cells_found = 1; + ind.lte_cell_search_indication.lte_found_cells[0].pci = 123; + ind.lte_cell_search_indication.lte_found_cells[0].rsrp = 123; + ind.lte_cell_search_indication.lte_found_cells[0].rsrq = 123; + ind.lte_cell_search_indication.lte_found_cells[0].frequency_offset = 123; + } + break; + case NFAPI_RAT_TYPE_UTRAN: + { + ind.utran_cell_search_indication.tl.tag = NFAPI_UTRAN_CELL_SEARCH_INDICATION_TAG; + ind.utran_cell_search_indication.number_of_utran_cells_found = 1; + ind.utran_cell_search_indication.utran_found_cells[0].psc = 89; + ind.utran_cell_search_indication.utran_found_cells[0].rscp = 89; + ind.utran_cell_search_indication.utran_found_cells[0].ecno = 89; + ind.utran_cell_search_indication.utran_found_cells[0].frequency_offset = -89; + + } + break; + case NFAPI_RAT_TYPE_GERAN: + { + ind.geran_cell_search_indication.tl.tag = NFAPI_GERAN_CELL_SEARCH_INDICATION_TAG; + ind.geran_cell_search_indication.number_of_gsm_cells_found = 1; + ind.geran_cell_search_indication.gsm_found_cells[0].bsic = 23; + ind.geran_cell_search_indication.gsm_found_cells[0].rxlev = 23; + ind.geran_cell_search_indication.gsm_found_cells[0].rxqual = 23; + ind.geran_cell_search_indication.gsm_found_cells[0].frequency_offset = -23; + ind.geran_cell_search_indication.gsm_found_cells[0].sfn_offset = 230; + + } + break; + } + + ind.pnf_cell_search_state.tl.tag = NFAPI_PNF_CELL_SEARCH_STATE_TAG; + ind.pnf_cell_search_state.length = 3; + + nfapi_pnf_cell_search_ind(config, &ind); + return 0; +} +int broadcast_detect_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_broadcast_detect_request_t* req) +{ + nfapi_broadcast_detect_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_BROADCAST_DETECT_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_P4_MSG_OK; + nfapi_pnf_broadcast_detect_resp(config, &resp); + + nfapi_broadcast_detect_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_BROADCAST_DETECT_INDICATION; + ind.header.phy_id = req->header.phy_id; + ind.error_code = NFAPI_P4_MSG_OK; + + switch(req->rat_type) + { + case NFAPI_RAT_TYPE_LTE: + { + ind.lte_broadcast_detect_indication.tl.tag = NFAPI_LTE_BROADCAST_DETECT_INDICATION_TAG; + ind.lte_broadcast_detect_indication.number_of_tx_antenna = 1; + ind.lte_broadcast_detect_indication.mib_length = 4; + //ind.lte_broadcast_detect_indication.mib... + ind.lte_broadcast_detect_indication.sfn_offset = 77; + + } + break; + case NFAPI_RAT_TYPE_UTRAN: + { + ind.utran_broadcast_detect_indication.tl.tag = NFAPI_UTRAN_BROADCAST_DETECT_INDICATION_TAG; + ind.utran_broadcast_detect_indication.mib_length = 4; + //ind.utran_broadcast_detect_indication.mib... + ind.utran_broadcast_detect_indication.sfn_offset; + + } + break; + } + + ind.pnf_cell_broadcast_state.tl.tag = NFAPI_PNF_CELL_BROADCAST_STATE_TAG; + ind.pnf_cell_broadcast_state.length = 3; + + nfapi_pnf_broadcast_detect_ind(config, &ind); + return 0; +} +int system_information_schedule_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_system_information_schedule_request_t* req) +{ + nfapi_system_information_schedule_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_P4_MSG_OK; + nfapi_pnf_system_information_schedule_resp(config, &resp); + + nfapi_system_information_schedule_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_SYSTEM_INFORMATION_SCHEDULE_INDICATION; + ind.header.phy_id = req->header.phy_id; + ind.error_code = NFAPI_P4_MSG_OK; + + ind.lte_system_information_indication.tl.tag = NFAPI_LTE_SYSTEM_INFORMATION_INDICATION_TAG; + ind.lte_system_information_indication.sib_type = 3; + ind.lte_system_information_indication.sib_length = 5; + //ind.lte_system_information_indication.sib... + + nfapi_pnf_system_information_schedule_ind(config, &ind); + return 0; +} +int system_information_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_system_information_request_t* req) +{ + nfapi_system_information_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_SYSTEM_INFORMATION_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_P4_MSG_OK; + nfapi_pnf_system_information_resp(config, &resp); + + nfapi_system_information_indication_t ind; + memset(&ind, 0, sizeof(ind)); + ind.header.message_id = NFAPI_SYSTEM_INFORMATION_INDICATION; + ind.header.phy_id = req->header.phy_id; + ind.error_code = NFAPI_P4_MSG_OK; + + switch(req->rat_type) + { + case NFAPI_RAT_TYPE_LTE: + { + ind.lte_system_information_indication.tl.tag = NFAPI_LTE_SYSTEM_INFORMATION_INDICATION_TAG; + ind.lte_system_information_indication.sib_type = 1; + ind.lte_system_information_indication.sib_length = 3; + //ind.lte_system_information_indication.sib... + } + break; + case NFAPI_RAT_TYPE_UTRAN: + { + ind.utran_system_information_indication.tl.tag = NFAPI_UTRAN_SYSTEM_INFORMATION_INDICATION_TAG; + ind.utran_system_information_indication.sib_length = 3; + //ind.utran_system_information_indication.sib... + + } + break; + case NFAPI_RAT_TYPE_GERAN: + { + ind.geran_system_information_indication.tl.tag = NFAPI_GERAN_SYSTEM_INFORMATION_INDICATION_TAG; + ind.geran_system_information_indication.si_length = 3; + //ind.geran_system_information_indication.si... + + } + break; + } + + + nfapi_pnf_system_information_ind(config, &ind); + + return 0; +} +int nmm_stop_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi_nmm_stop_request_t* req) +{ + nfapi_nmm_stop_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_NMM_STOP_RESPONSE; + resp.header.phy_id = req->header.phy_id; + resp.error_code = NFAPI_P4_MSG_OK; + nfapi_pnf_nmm_stop_resp(config, &resp); + return 0; +} + +int vendor_ext(nfapi_pnf_config_t* config, nfapi_p4_p5_message_header_t* msg) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF_SIM] P5 %s %p\n", __FUNCTION__, msg); + + switch(msg->message_id) + { + case P5_VENDOR_EXT_REQ: + { + vendor_ext_p5_req* req = (vendor_ext_p5_req*)msg; + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF_SIM] P5 Vendor Ext Req (%d %d)\n", req->dummy1, req->dummy2); + // send back the P5_VENDOR_EXT_RSP + vendor_ext_p5_rsp rsp; + memset(&rsp, 0, sizeof(rsp)); + rsp.header.message_id = P5_VENDOR_EXT_RSP; + rsp.error_code = NFAPI_MSG_OK; + nfapi_pnf_vendor_extension(config, &rsp.header, sizeof(vendor_ext_p5_rsp)); + } + break; + } + + return 0; +} + +nfapi_p4_p5_message_header_t* pnf_sim_allocate_p4_p5_vendor_ext(uint16_t message_id, uint16_t* msg_size) +{ + if(message_id == P5_VENDOR_EXT_REQ) + { + (*msg_size) = sizeof(vendor_ext_p5_req); + return (nfapi_p4_p5_message_header_t*)malloc(sizeof(vendor_ext_p5_req)); + } + + return 0; +} + +void pnf_sim_deallocate_p4_p5_vendor_ext(nfapi_p4_p5_message_header_t* header) +{ + free(header); +} + + +int pnf_sim_pack_p4_p5_vendor_extension(nfapi_p4_p5_message_header_t* header, uint8_t** ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* config) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if(header->message_id == P5_VENDOR_EXT_RSP) + { + vendor_ext_p5_rsp* rsp = (vendor_ext_p5_rsp*)(header); + return (!push16(rsp->error_code, ppWritePackedMsg, end)); + } + return 0; +} + +int pnf_sim_unpack_p4_p5_vendor_extension(nfapi_p4_p5_message_header_t* header, uint8_t** ppReadPackedMessage, uint8_t *end, nfapi_p4_p5_codec_config_t* codec) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if(header->message_id == P5_VENDOR_EXT_REQ) + { + vendor_ext_p5_req* req = (vendor_ext_p5_req*)(header); + return (!(pull16(ppReadPackedMessage, &req->dummy1, end) && + pull16(ppReadPackedMessage, &req->dummy2, end))); + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s (%d %d)\n", __FUNCTION__, req->dummy1, req->dummy2); + } + return 0; +} +int main(int argc, char *argv[]) +{ + if (argc < 3) + { + printf("Use parameters: \n"); + return 0; + } + + set_thread_priority(50); + + pnf_info pnf; + if(read_pnf_xml(pnf, argv[3]) < 0) + { + printf("Failed to read xml file>\n"); + return 0; + } + + + nfapi_pnf_config_t* config = nfapi_pnf_config_create(); + + config->vnf_ip_addr = argv[1]; + config->vnf_p5_port = atoi(argv[2]); + + config->pnf_param_req = &pnf_param_request; + config->pnf_config_req = &pnf_config_request; + config->pnf_start_req = &pnf_start_request; + config->pnf_stop_req = &pnf_stop_request; + config->param_req = ¶m_request; + config->config_req = &config_request; + config->start_req = &start_request; + + config->measurement_req = &measurement_request; + config->rssi_req = &rssi_request; + config->cell_search_req = &cell_search_request; + config->broadcast_detect_req = &broadcast_detect_request; + config->system_information_schedule_req = &system_information_schedule_request; + config->system_information_req = &system_information_request; + config->nmm_stop_req = &nmm_stop_request; + + config->vendor_ext = &vendor_ext; + + config->trace = &pnf_sim_trace; + + config->user_data = &pnf; + + // To allow custom vendor extentions to be added to nfapi + config->codec_config.unpack_vendor_extension_tlv = &pnf_sim_unpack_vendor_extension_tlv; + config->codec_config.pack_vendor_extension_tlv = &pnf_sim_pack_vendor_extention_tlv; + + config->allocate_p4_p5_vendor_ext = &pnf_sim_allocate_p4_p5_vendor_ext; + config->deallocate_p4_p5_vendor_ext = &pnf_sim_deallocate_p4_p5_vendor_ext; + + config->codec_config.unpack_p4_p5_vendor_extension = &pnf_sim_unpack_p4_p5_vendor_extension; + config->codec_config.pack_p4_p5_vendor_extension = &pnf_sim_pack_p4_p5_vendor_extension; + + return nfapi_pnf_start(config); + +} diff --git a/nfapi/open-nFAPI/sim_common/Makefile.am b/nfapi/open-nFAPI/sim_common/Makefile.am new file mode 100644 index 0000000000..771b768a16 --- /dev/null +++ b/nfapi/open-nFAPI/sim_common/Makefile.am @@ -0,0 +1,31 @@ +# +# Copyright 2017 Cisco Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +AUTOMAKE_OPTIONS=subdir-objects + +AM_CFLAGS = -I$(top_srcdir)/sim_common/public_inc -I$(top_srcdir)/common/public_inc -I$(top_srcdir)/nfapi/public_inc -g -Wall -Werror + +AM_CXXFLAGS = -I$(top_srcdir)/sim_common/public_inc -I$(top_srcdir)/common/public_inc -std=c++11 -I$(top_srcdir)/nfapi/public_inc $(BOOST_CPPFLAGS) -g -Wall -Werror +noinst_LIBRARIES =libnfapi_sim_common.a +#libnfapi_sim_common_a_SOURCES = src/xml_property_tree.cpp src/pool.cpp +libnfapi_sim_common_a_SOURCES = src/pool.cpp + +libnfapi_sim_common_a_CFLAGS =$(AM_CFLAGS) +libnfapi_sim_common_a_CXXFLAGS =$(AM_CXXFLAGS) + +lib_LTLIBRARIES =libnfapi_sim_common.la +#libnfapi_sim_common_la_SOURCES = src/xml_property_tree.cpp +libnfapi_sim_common_la_SOURCES = src/pool.cpp diff --git a/nfapi/open-nFAPI/sim_common/inc/pool.h b/nfapi/open-nFAPI/sim_common/inc/pool.h new file mode 100644 index 0000000000..8591d939f9 --- /dev/null +++ b/nfapi/open-nFAPI/sim_common/inc/pool.h @@ -0,0 +1,186 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _POOL_H_ +#define _POOL_H_ + +#include +#include +#include +#include + + +class pool_config +{ + public: + + size_t size; + uint16_t initial_count; +}; + +class memory_pool +{ + std::mutex mutex; + std::map> free_store; + std::map allocated_store; + + void init(std::vector config) + { + printf("memory_pool::init\n"); + + for(pool_config c : config) + { + // todo : use the initial count to allocate initial pool memory + free_store.insert(std::pair> + (c.size, std::queue())); + allocated_store.insert(std::pair(c.size, 0)); + } + } + + memory_pool() + { + std::vector config + { + {8, 0}, {32, 0}, {64, 0}, {128, 0}, {256, 0}, + {1024, 0}, {4096, 0}, {8912, 0} + + }; + + init(config); + } + + + uint16_t determine_pool_size(size_t size) + { + for(auto pool : free_store) + { + if(pool.first >= size) + return pool.first; + } + + return 0; + } + + uint8_t* alloc(size_t size) + { + if(size == 0) + return 0; + + uint8_t* ptr = 0; + size_t psize = determine_pool_size(size + 4); + + if(psize == 0) + { + ptr = (uint8_t*)malloc(size + 4); + memset(ptr, 0, size + 4); + } + else + { + mutex.lock(); + + auto it = free_store.find(psize); + + if(it == free_store.end()) + { + // Unknown pool size + ptr = (uint8_t*)malloc(psize + 4); + memcpy(ptr, &psize, 4); + } + else + { + if(it->second.size() > 0) + { + // Take from the pool + ptr = (uint8_t*)(it->second.front()); + it->second.pop(); + } + else + { + // No memory left in pool + ptr = (uint8_t*)malloc(psize + 4); + memcpy(ptr, &psize, 4); + } + } + + mutex.unlock(); + } + + return (ptr + 4); + } + + void dealloc(uint8_t* ptr) + { + if(ptr == 0) + return; + + uint8_t* _ptr = (uint8_t*)ptr; + + size_t psize; + memcpy(&psize, _ptr - 4, 4); + + if(psize == 0) + { + free(_ptr - 4); + } + else + { + mutex.lock(); + + auto it = free_store.find(psize); + if(it == free_store.end()) + { + free(_ptr - 4); + } + else + { + assert((_ptr - 4) != 0); + it->second.push(_ptr - 4); + } + + mutex.unlock(); + } + + } + + public: + + memory_pool(memory_pool const&) = delete; + void operator=(memory_pool const&) = delete; + + /*! Get the memory_pool instance */ + static memory_pool& instance() + { + static memory_pool instance; + return instance; + } + + /*! Allocate a buffer from the memory_pool is at least size */ + static uint8_t* allocate(size_t size) + { + return instance().alloc(size); + } + + /*! Return the buffer to the memory_pool */ + static void deallocate(uint8_t* ptr) + { + return instance().dealloc(ptr); + } + + +}; + +#endif // _POOL_H_ diff --git a/nfapi/open-nFAPI/sim_common/inc/vendor_ext.h b/nfapi/open-nFAPI/sim_common/inc/vendor_ext.h new file mode 100644 index 0000000000..d0fd57837d --- /dev/null +++ b/nfapi/open-nFAPI/sim_common/inc/vendor_ext.h @@ -0,0 +1,71 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _VENDOR_EXT_H_ +#define _VENDOR_EXT_H_ + +#include "nfapi_interface.h" + +typedef enum +{ + P5_VENDOR_EXT_REQ = NFAPI_VENDOR_EXT_MSG_MIN, + P5_VENDOR_EXT_RSP, + + P7_VENDOR_EXT_REQ, + P7_VENDOR_EXT_IND + +} vendor_ext_message_id_e; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint16_t dummy1; + uint16_t dummy2; +} vendor_ext_p5_req; + +typedef struct { + nfapi_p4_p5_message_header_t header; + uint16_t error_code; +} vendor_ext_p5_rsp; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t dummy1; + uint16_t dummy2; +} vendor_ext_p7_req; + +typedef struct { + nfapi_p7_message_header_t header; + uint16_t error_code; +} vendor_ext_p7_ind; + +typedef struct { + nfapi_tl_t tl; + uint32_t dummy; +} vendor_ext_tlv_1; + +#define VENDOR_EXT_TLV_1_TAG 0xF001 + +typedef struct { + nfapi_tl_t tl; + uint32_t dummy; +} vendor_ext_tlv_2; + +#define VENDOR_EXT_TLV_2_TAG 0xF002 + + + + +#endif // _VENDOR_EXT_ diff --git a/nfapi/open-nFAPI/sim_common/src/pool.cpp b/nfapi/open-nFAPI/sim_common/src/pool.cpp new file mode 100644 index 0000000000..47d9cfa992 --- /dev/null +++ b/nfapi/open-nFAPI/sim_common/src/pool.cpp @@ -0,0 +1,15 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/nfapi/open-nFAPI/vnf/Makefile.am b/nfapi/open-nFAPI/vnf/Makefile.am new file mode 100644 index 0000000000..ae8d2bb3d6 --- /dev/null +++ b/nfapi/open-nFAPI/vnf/Makefile.am @@ -0,0 +1,43 @@ +# +# Copyright 2017 Cisco Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +AUTOMAKE_OPTIONS=subdir-objects + +AM_CPPFLAGS = -I$(top_srcdir)/vnf/inc\ + -I$(top_srcdir)/vnf/public_inc\ + -I$(top_srcdir)/nfapi/public_inc\ + -I$(top_srcdir)/common/public_inc\ + -Wall -Werror -g + + +noinst_LIBRARIES = libnfapi_vnf.a + +libnfapi_vnf_a_SOURCES = src/vnf.c\ + src/vnf_p7.c\ + src/vnf_interface.c\ + src/vnf_p7_interface.c + +LDADD = -lsctp ../common/bin/libnfapi_common.a + +libnfapi_vnf_a_CFLAGS =$(AM_CFLAGS) + +lib_LTLIBRARIES = libnfapi_vnf.la + +libnfapi_vnf_la_SOURCES = src/vnf.c\ + src/vnf_p7.c\ + src/vnf_interface.c\ + src/vnf_p7_interface.c diff --git a/nfapi/open-nFAPI/vnf/inc/vnf.h b/nfapi/open-nFAPI/vnf/inc/vnf.h new file mode 100644 index 0000000000..4fd8d2b91d --- /dev/null +++ b/nfapi/open-nFAPI/vnf/inc/vnf.h @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef _VNF_H_ +#define _VNF_H_ + +#include "nfapi_vnf_interface.h" + +typedef struct +{ + + nfapi_vnf_config_t _public; + + uint8_t terminate; + uint8_t sctp; + + uint8_t tx_message_buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE]; + uint16_t next_phy_id; + +} vnf_t; + + +int vnf_pack_and_send_p5_message(vnf_t* vnf, uint16_t p5_idx, nfapi_p4_p5_message_header_t* msg, uint16_t msg_len); +int vnf_pack_and_send_p4_message(vnf_t* vnf, uint16_t p5_idx, nfapi_p4_p5_message_header_t* msg, uint16_t msg_len); + +int vnf_read_dispatch_message(nfapi_vnf_config_t* config, nfapi_vnf_pnf_info_t* pnf); + +void nfapi_vnf_phy_info_list_add(nfapi_vnf_config_t* config, nfapi_vnf_phy_info_t* info); +nfapi_vnf_phy_info_t* nfapi_vnf_phy_info_list_find(nfapi_vnf_config_t* config, uint16_t phy_id); +void nfapi_vnf_pnf_list_add(nfapi_vnf_config_t* config, nfapi_vnf_pnf_info_t* node); +nfapi_vnf_pnf_info_t* nfapi_vnf_pnf_list_find(nfapi_vnf_config_t* config, int p5_idx); +#endif // _VNF_H_ diff --git a/nfapi/open-nFAPI/vnf/inc/vnf_p7.h b/nfapi/open-nFAPI/vnf/inc/vnf_p7.h new file mode 100644 index 0000000000..fc2ab4e6b5 --- /dev/null +++ b/nfapi/open-nFAPI/vnf/inc/vnf_p7.h @@ -0,0 +1,136 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef _VNF_P7_H_ +#define _VNF_P7_H_ + +#include "nfapi_vnf_interface.h" + +#define TIMEHR_SEC(_time_hr) ((uint32_t)(_time_hr) >> 20) +#define TIMEHR_USEC(_time_hr) ((uint32_t)(_time_hr) & 0xFFFFF) +#define TIME2TIMEHR(_time) (((uint32_t)(_time.tv_sec) & 0xFFF) << 20 | ((uint32_t)(_time.tv_usec) & 0xFFFFF)) + + + +typedef struct { + uint8_t* buffer; + uint16_t length; +} vnf_p7_rx_message_segment_t; + +typedef struct vnf_p7_rx_message vnf_p7_rx_message_t; + +typedef struct vnf_p7_rx_message { + uint8_t sequence_number; + uint8_t num_segments_received; + uint8_t num_segments_expected; + + // the spec allows of upto 128 segments, this does seem excessive + vnf_p7_rx_message_segment_t segments[128]; + + uint32_t rx_hr_time; + + vnf_p7_rx_message_t* next; +} vnf_p7_rx_message_t; + +typedef struct { + + vnf_p7_rx_message_t* msg_queue; + +} vnf_p7_rx_reassembly_queue_t; + +typedef struct nfapi_vnf_p7_connection_info { + + /*! The PHY id */ + int phy_id; + + + // this does not belong here... + uint8_t stream_id; + + /*! Flag indicating the sync state of the P7 conenction */ + uint8_t in_sync; + + int dl_out_sync_offset; + int dl_out_sync_period; // ms (as a pow2) + + int dl_in_sync_offset; + int dl_in_sync_period; // ms (as a pow2) + + uint8_t filtered_adjust; + uint16_t min_sync_cycle_count; + uint32_t latency[8]; + uint32_t average_latency; + int32_t sf_offset_filtered; + int32_t sf_offset_trend; + int32_t sf_offset; + uint16_t zero_count; + int32_t adjustment; + int32_t insync_minor_adjustment; + int32_t insync_minor_adjustment_duration; + + uint32_t previous_t1; + uint32_t previous_t2; + int32_t previous_sf_offset_filtered; + + int sfn_sf; + + int socket; + struct sockaddr_in local_addr; + struct sockaddr_in remote_addr; + + vnf_p7_rx_reassembly_queue_t reassembly_queue; + uint8_t* reassembly_buffer; + uint32_t reassembly_buffer_size; + + uint32_t sequence_number; + + struct nfapi_vnf_p7_connection_info* next; + +} nfapi_vnf_p7_connection_info_t; + +typedef struct { + + nfapi_vnf_p7_config_t _public; + + // private data + uint8_t terminate; + nfapi_vnf_p7_connection_info_t* p7_connections; + int socket; + uint32_t sf_start_time_hr; + uint8_t* rx_message_buffer; // would this be better put in the p7 conenction info? + uint16_t rx_message_buffer_size; + +} vnf_p7_t; + +uint32_t vnf_get_current_time_hr(void); + +uint16_t increment_sfn_sf(uint16_t sfn_sf); +int vnf_sync(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* p7_info); +int send_mac_subframe_indications(vnf_p7_t* config); +int vnf_p7_read_dispatch_message(vnf_p7_t* vnf_p7 ); + +void vnf_p7_connection_info_list_add(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* node); +nfapi_vnf_p7_connection_info_t* vnf_p7_connection_info_list_find(vnf_p7_t* vnf_p7, uint16_t phy_id); +nfapi_vnf_p7_connection_info_t* vnf_p7_connection_info_list_delete(vnf_p7_t* vnf_p7, uint16_t phy_id); + +int vnf_p7_pack_and_send_p7_msg(vnf_p7_t* vnf_p7, nfapi_p7_message_header_t* header); + +void vnf_p7_release_msg(vnf_p7_t* vnf_p7, nfapi_p7_message_header_t* header); +void vnf_p7_release_pdu(vnf_p7_t* vnf_p7, void* pdu); + + +#endif // _VNF_P7_H_ diff --git a/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h b/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h new file mode 100644 index 0000000000..462901391a --- /dev/null +++ b/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h @@ -0,0 +1,995 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _NFAPI_VNF_INTERFACE_H_ +#define _NFAPI_VNF_INTERFACE_H_ + +#include "nfapi_interface.h" +#include "debug.h" + +#include "netinet/in.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#define NFAPI_MAX_PACKED_MESSAGE_SIZE 8192 + +/*! The nfapi VNF phy configuration information + */ +typedef struct nfapi_vnf_phy_info +{ + /*! The P5 Index */ + int p5_idx; //which p5 connection + /*! The PHY ID */ + int phy_id; //phy_id + + /*! Timing window */ + uint8_t timing_window; + /*! Timing info mode */ + uint8_t timing_info_mode; + /*! Timing info period */ + uint8_t timing_info_period; + + /*! P7 UDP socket information for the pnf */ + struct sockaddr_in p7_pnf_address; + /*! P7 UDP socket information for the vnf */ + struct sockaddr_in p7_vnf_address; + + struct nfapi_vnf_phy_info* next; +} nfapi_vnf_phy_info_t; + +/*! The nfapi VNF pnf configuration information + */ +typedef struct nfapi_vnf_pnf_info +{ + /*! The P5 Index */ + int p5_idx; + /*! The P5 socket */ + int p5_sock; + /*! Flag indicating if the pnf is connected */ + uint8_t connected; + + /*! P5 SCTP socket information for the pnf */ + struct sockaddr_in p5_pnf_sockaddr; + + /*! Flag indicating if this pnf should be deleted */ + uint8_t to_delete; + + struct nfapi_vnf_pnf_info* next; + +} nfapi_vnf_pnf_info_t; + +typedef struct nfapi_vnf_config nfapi_vnf_config_t; + +/*! The nfapi VNF configuration information + */ +typedef struct nfapi_vnf_config +{ + /*! A user define callback to override the default memory allocation */ + void* (*malloc)(size_t size); + /*! A user define callback to override the default memory deallocation */ + void (*free)(void*); + /*! A user define callback to handle trace from the pnf */ + void (*trace)(nfapi_trace_level_t level, const char* message, ...); + + /*! The port the VNF P5 SCTP connection listens on + * + * By default this will be set to 7701. However this can be changed if + * required. + */ + int vnf_p5_port; + + // todo : for enabling ipv4/ipv6 + int vnf_ipv4; + int vnf_ipv6; + + /*! List of connected pnfs */ + nfapi_vnf_pnf_info_t* pnf_list; + + /*! List of configured phys */ + nfapi_vnf_phy_info_t* phy_list; + + /*! Configuration options for the p4 p5 pack unpack functions */ + nfapi_p4_p5_codec_config_t codec_config; + + /*! Optional user defined data that will be avaliable in the callbacks*/ + void* user_data; + + /*! \brief Callback indicating that a pnf has established connection + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 used to indicate this pnf p5 connection + * + * The client is expected to send the PNF_PARAM.request in response to + * the connection indication + * + * \todo Do we need to send the address information of the PNF? + */ + int (*pnf_connection_indication)(nfapi_vnf_config_t* config, int p5_idx); + + /*! \brief Callback indicating that a pnf has lost connection + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 used to indicate this pnf p5 connection + * + * The p5_idx may be used for future new p5 connections + * + * The client is responsiable for communicating to the p7 instance(s) that + * may be associated with this p5 that they should be deleted using the + * nfapi_vnf_p7_del_pnf functon + * + */ + int (*pnf_disconnect_indication)(nfapi_vnf_config_t* config, int p5_idx); + + // p5 interface functions + + /*! \brief A callback to handle the PNF_PARAM.resp + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded PNF_PARAM.response. This will + * have been allocated on the stack. + * \return not currently used. + * + * The PNF_PARAM.resp contains the capability of the PNF identified by the + * p5_idx. + * + * The client is expected to send the PNF_CONFIG.request after receiving the + * PNF_PARAM.resp. This can be done in the call back. + * + * It is expected that the client when building the PNF_CONFIG.request will + * used the nfapi_vnf_allocate_phy() to allocate unique phy id for each FAPI + * instance the client wishes to create. + * + * The resp may contain pointers to dyanmically allocated sub structures + * such as the vendor_extention. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*pnf_param_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_param_response_t* resp); + + /*! A callback for the PNF_CONFIG.resp + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded PNF_CONFIG.response. This will + * have been allocated on the stack. + * \return not currently used. + * + * The PNF_CONFIG.resp contains the result of the PNF_CONFIG.request for the + * PNF identified by the p5_idx. + * + * The client is expected to send the PNF_START.request after receiving the + * PNF_PARAM.resp. This can be done in the call back. + * + * The resp may contain pointers to dyanmically allocated sub structures + * such as the vendor_extention. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*pnf_config_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_config_response_t* resp); + + /*! A callback for the PNF_START.resp + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded PNF_START.response. This will + * have been allocated on the stack. + * \return not currently used. + * + * The PNF_START.resp contains the result of the PNF_START.request for the + * PNF identified by the p5_idx. + * + * The client is expected to send the PARAM.request for each FAPI instance + * that has been created in the PNF. + * + * The resp may contain pointers to dyanmically allocated sub structures + * such as the vendor_extention. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*pnf_start_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_start_response_t* resp); + + /*! A callback for the PNF_STOP.resp + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded PNF_STOP.response. This will + * have been allocated on the stack. + * \return not currently used. + * + * The PNF_STOP.response contains the result of the PNF_STOP.request for the + * PNF identified by the p5_idx. + * + * The resp may contain pointers to dyanmically allocated sub structures + * such as the vendor_extention. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*pnf_stop_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_stop_response_t* resp); + + /*! A callback for the PARAM.resp + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded PARAM.resposne. This will + * have been allocated on the stack. + * \return not currently used. + * + * The PARAM.request contains the capabilities of the FAPI instance identified + * by the phy_id + * + * The client is expected to send the CONFIG.request after receiving the + * PARAM.response. This can be done in the call back. The PARAM.response + * contains the PNF P7 address (ipv4 or ipv6) and port. This information + * is used when calling the nfapi_vnf_p7_add_pnf() + * + * The client is responsible for identifing the VNF P7 ip address + * (ipv4 or ipv6) and port for the VNF P7 entity which will be sent to the + * PNF P7 entity. That endpoint should be valid before send the + * CONFIG.request. + * + * The resp may contain pointers to dyanmically allocated sub structures + * such as the vendor_extention. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*param_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_param_response_t* resp); + + /*! A callback for the CONFIG.response + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded CONFIG.response This will + * have been allocated on the stack. + * \return not currently used. + * + * The CONFIG.response contains the result of the CONFIG.request + * + * + * The resp may contain pointers to dyanmically allocated sub structures + * such as the vendor_extention. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*config_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_config_response_t* resp); + + /*! A callback for the START.resp + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded START.response This will + * have been allocated on the stack. + * \return not currently used. + * + * The START.response contains the result of the START.request + * + * + * The resp may contain pointers to dyanmically allocated sub structures + * such as the vendor_extention. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*start_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_start_response_t* resp); + + /*! A callback for the STOP.resp + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded STOP.response This will + * have been allocated on the stack. + * \return not currently used. + * + * The STOP.response contains the result of the STOP.request + * + * + * The resp may contain pointers to dyanmically allocated sub structures + * such as the vendor_extention. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*stop_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_stop_response_t* resp); + + /*! A callback for the MEASUREMENT.resp + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded MEASUREMENT.response This will + * have been allocated on the stack. + * \return not currently used. + * + * The MEASUREMENT.response contains the result of the MEASUREMENT.request + * + * The resp may contain pointers to dyanmically allocated sub structures + * such as the vendor_extention. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*measurement_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_measurement_response_t* resp); + + // p4 interface functions + /*! A callback for the RSSI.resp + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded RSSI.response This will + * have been allocated on the stack. + * \return not currently used. + */ + int (*rssi_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_rssi_response_t* resp); + + /*! A callback for the RSSI.indication + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded RSSI.indication This will + * have been allocated on the stack. + * \return not currently used. + */ + int (*rssi_ind)(nfapi_vnf_config_t* config, int p5_idx, nfapi_rssi_indication_t* ind); + + /*! A callback for the CELL_SEARCH.response + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded CELL_SEARCH.response This will + * have been allocated on the stack. + * \return not currently used. + */ + int (*cell_search_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_cell_search_response_t* resp); + + /*! A callback for the CELL_SEARCH.indication + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded CELL_SEARCH.indication This will + * have been allocated on the stack. + * \return not currently used. + */ + int (*cell_search_ind)(nfapi_vnf_config_t* config, int p5_idx, nfapi_cell_search_indication_t* ind); + + /*! A callback for the BROADCAST_DETECT.response + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded BROADCAST_DETECT.response This will + * have been allocated on the stack. + * \return not currently used. */ + int (*broadcast_detect_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_broadcast_detect_response_t* resp); + + /*! A callback for the BROADCAST_DETECT.indication + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded BROADCAST_DETECT.indication This will + * have been allocated on the stack. + * \return not currently used. + */ + int (*broadcast_detect_ind)(nfapi_vnf_config_t* config, int p5_idx, nfapi_broadcast_detect_indication_t* ind); + + /*! A callback for the SYSTEM_INFORMATION_SCHEUDLE.response + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded SYSTEM_INFORMATION_SCHEUDLE.response This will + * have been allocated on the stack. + * \return not currently used. + */ + int (*system_information_schedule_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_schedule_response_t* resp); + + /*! A callback for the SYSTEM_INFORMATION_SCHEUDLE.indication + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded SYSTEM_INFORMATION_SCHEUDLE.indication This will + * have been allocated on the stack. + * \return not currently used. + */ + int (*system_information_schedule_ind)(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_schedule_indication_t* ind); + + /*! A callback for the SYSTEM_INFORMATION.response + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded SYSTEM_INFORMATION.response This will + * have been allocated on the stack. + * \return not currently used. + */ + int (*system_information_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_response_t* resp); + + /*! A callback for the SYSTEM_INFORMATION.indication + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded SYSTEM_INFORMATION.indication This will + * have been allocated on the stack. + * \return not currently used. + */ + int (*system_information_ind)(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_indication_t* ind); + + /*! A callback for the NMM_STOP.response + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded NMM_STOP.response This will + * have been allocated on the stack. + * \return not currently used. + */ + int (*nmm_stop_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_nmm_stop_response_t* resp); + + + /*! A callback for any vendor extension message received + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param resp A data structure for the decoded vendor extention message + * \return not currently used. + */ + int (*vendor_ext)(nfapi_vnf_config_t* config, int p5_idx, nfapi_p4_p5_message_header_t* msg); + + /*! A callback to allocate vendor extension messages + * \param message_id The message is taken from the message header + * \param msg_size The is the vendor extention message that has been allocated. + * The callee must set this value + * \return A pointer to an allocated vendor extention message + */ + nfapi_p4_p5_message_header_t* (*allocate_p4_p5_vendor_ext)(uint16_t message_id, uint16_t* msg_size); + + /*! A callback to deallocate vendor extension messages + * \param header A pointer to an allocated vendor extention message + */ + void (*deallocate_p4_p5_vendor_ext)(nfapi_p4_p5_message_header_t* header); + + + + + + +} nfapi_vnf_config_t; + +/*! Creates and initialise the vnf config structure before use + * \return A pointer to a vnf config structure + */ +nfapi_vnf_config_t* nfapi_vnf_config_create(void); + +/*! Delete an vnf config + */ +void nfapi_vnf_config_destory(nfapi_vnf_config_t* config); + + +/*! Start the VNF library. + * \param config A pointer to a vnf config + * \return 0 means success, -1 failure + * + * The config should be initailize with port the vnf should listen on and + * the callback set to functions that will be called when a nFAPI message is + * recevied before calling nfapi_vnf_start. + * + * This function will not return untill nfapi_vnf_stop is called + */ +int nfapi_vnf_start(nfapi_vnf_config_t* config); + +/*! Stop the VNF library. + * \param config A pointer to a vnf config + * \return 0 means success, -1 failure + * + * This function will cause the nfapi_vnf_start function to return + */ +int nfapi_vnf_stop(nfapi_vnf_config_t* config); + +/*! Allocates a PHY ID for the PNF PHY instance managed by this VNF + * \param config A pointer to a vnf config + * \param p5_idx The P5 index return by the callbacks + * \param phy_id A pointer to a phy_id that will be set by this function + * \return 0 means success, -1 failure + * + * Called before nfapi_vnf_config_req to allocate a vnf phy instance. This + * function will return unqiue phy_id to be used for this identify the phy + * + */ +int nfapi_vnf_allocate_phy(nfapi_vnf_config_t* config, int p5_idx, uint16_t* phy_id); + +// P5 Request functions +// +/*! Send the PNF_PARAM.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a PNF_PARAM.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_pnf_param_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_param_request_t* req); + +/*! Send the PNF_CONFIG.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a PNF_CONFIG.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_pnf_config_req(nfapi_vnf_config_t* config,int p5_idx, nfapi_pnf_config_request_t* req); + +/*! Send the PNF_START.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a PNF_START.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_pnf_start_req(nfapi_vnf_config_t* config,int p5_idx, nfapi_pnf_start_request_t* req); + +/*! Send the PNF_STOP.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a PNF_STOP.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_pnf_stop_req(nfapi_vnf_config_t* config,int p5_idx, nfapi_pnf_stop_request_t* req); + +/*! Send the PARAM.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a PARAM.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_param_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_param_request_t* req); + +/*! Send the CONFIG.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a CONFIG.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_config_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_config_request_t* req); + +/*! Send the START.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a START.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_start_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_start_request_t* req); + +/*! Send the STOP.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a STOP.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_stop_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_stop_request_t* req); + +/*! Send the MEASUREMENT.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a MEASUREMENT.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_measurement_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_measurement_request_t* req); + +// P4 Request functions +/*! Send the RSSI.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a RSSI.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_rssi_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_rssi_request_t* req); + +/*! Send the CELL_SEARCH.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a CELL_SEARCH.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_cell_search_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_cell_search_request_t* req); + +/*! Send the BROADCAST_DETECT.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a BROADCAST_DETECT.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_broadcast_detect_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_broadcast_detect_request_t* req); + +/*! Send the SYSTEM_INFORMATION_SCHEDULE.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a SYSTEM_INFORMATION_SCHEDULE.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_system_information_schedule_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_schedule_request_t* req); + +/*! Send the SYSTEM_INFORMATION.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a SYSTEM_INFORMATION.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_system_information_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_request_t* req); + +/*! Send the NMM_STOP.request + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param req A pointer to a NMM_STOP.request message structure + * \return 0 means success, -1 failure + */ +int nfapi_vnf_nmm_stop_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_nmm_stop_request_t* req); + +/*! Send a vendor extension message + * \param config A pointer to a vnf config + * \param p5_idx The P5 index + * \param msg A poiner to a vendor extention message + * \return 0 means success, -1 failure + */ +int nfapi_vnf_vendor_extension(nfapi_vnf_config_t* config, int p5_idx, nfapi_p4_p5_message_header_t* msg); + +//----------------------------------------------------------------------------- + +/*! The nfapi VNF P7 connection information + */ +typedef struct nfapi_vnf_p7_config nfapi_vnf_p7_config_t; + +/*! The nfapi VNF P7 configuration information + */ +typedef struct nfapi_vnf_p7_config +{ + /*! A user define callback to override the default memory allocation + * \param size Size of the memory block to allocate + * \return a pointer to a memory block + * + * If not set the vnf p7 library will use malloc + */ + void* (*malloc)(size_t size); + + /*! A user define callback to override the default memory deallocation + * \param ptr Pointer to a memory block to deallocate + * + * If not set the vnf p7 library will use free + */ + void (*free)(void*); + + /*! A user define callback to handle trace from the pnf + * \param level The trace level + * \param message The trace string + */ + void (*trace)(nfapi_trace_level_t level, const char* message, ...); + + /*! The port the vnf p7 will receive on */ + int port; + + /*! Flag to indicate of the pnf should use the P7 checksum */ + uint8_t checksum_enabled; + + /*! The maxium size of a P7 segement. If a message is large that this it + * will be segemented */ + uint16_t segment_size; + uint16_t max_num_segments; + + /*! Configuration option for the p7 pack unpack functions*/ + nfapi_p7_codec_config_t codec_config; + + /* ! Call back to indicate the sync state with the PNF PHY + * \param config A pointer to the vnf p7 configuration + * \param sync Indicating if the pnf is in sync or not + * \return not currently used + * + * sync = 0 : in sync + * sync != 0 : out of sync + */ + int (*sync_indication)(struct nfapi_vnf_p7_config* config, uint8_t sync); + + /*! A callback for the subframe indication + * \param config A pointer to the vnf p7 configuration + * \param phy_id The ID for the PNF PHY instance + * \param sfn_sf The SFN SF number formated as per the FAPI specification + * \return not currently used + * + * This callback is an indication for the VNF to generate the downlink subframe messages + * for sfn/sf. This indicatoin is called every millisecond + * + * The VNF P7 Lib will adjust the subframe timing to 'catch-up' or 'slow-down' with the PNF PHY's + * + * \todo Need some way the tell the VNF how long it has + */ + + int (*subframe_indication)(struct nfapi_vnf_p7_config* config, uint16_t phy_id, uint16_t sfn_sf); + + /*! A callback for the HARQ.indication + * \param config A pointer to the vnf p7 configuration + * \param ind A data structure for the decoded HARQ.indication This will + * have been allocated on the stack. + * \return not currently used. + * + * The ind may contain pointers to dyanmically allocated sub structures + * such as the pdu. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*harq_indication)(struct nfapi_vnf_p7_config* config, nfapi_harq_indication_t* ind); + + /*! A callback for the CRC.ind + * \param config A pointer to the vnf p7 configuration + * \param ind A data structure for the decoded CRC.indication This will + * have been allocated on the stack. + * \return not currently used. + * + * The ind may contain pointers to dyanmically allocated sub structures + * such as the pdu. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*crc_indication)(struct nfapi_vnf_p7_config* config, nfapi_crc_indication_t* ind); + + /*! A callback for the RX_ULSCH.indication + * \param config A pointer to the vnf p7 configuration + * \param ind A data structure for the decoded RX_ULSCH.indication This will + * have been allocated on the stack. + * \return not currently used. + * + * The ind may contain pointers to dyanmically allocated sub structures + * such as the pdu. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + * + * Note that the rx_indication may hold one or many uplink pdus in the + * ind.rx_indication_body.rx_pdu_list + */ + int (*rx_indication)(struct nfapi_vnf_p7_config* config, nfapi_rx_indication_t* ind); + + /*! A callback for the RACH.indication + * \param config A pointer to the vnf p7 configuration + * \param ind A data structure for the decoded RACH.indication This will + * have been allocated on the stack. + * \return not currently used. + * + * The ind may contain pointers to dyanmically allocated sub structures + * such as the pdu. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*rach_indication)(struct nfapi_vnf_p7_config* config, nfapi_rach_indication_t* ind); + + /*! A callback for the SRS.indication + * \param config A pointer to the vnf p7 configuration + * \param ind A data structure for the decoded SRS.indication This will + * have been allocated on the stack. + * \return not currently used. + * + * The ind may contain pointers to dyanmically allocated sub structures + * such as the pdu. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*srs_indication)(struct nfapi_vnf_p7_config* config, nfapi_srs_indication_t* ind); + + /*! A callback for the RX_SR.indication + * \param config A pointer to the vnf p7 configuration + * \param ind A data structure for the decoded RX_SR.indication This will + * have been allocated on the stack. + * \return not currently used. + * + * The ind may contain pointers to dyanmically allocated sub structures + * such as the pdu. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*sr_indication)(struct nfapi_vnf_p7_config* config, nfapi_sr_indication_t* ind); + + /*! A callback for the RX_CQI.indication + * \param config A pointer to the vnf p7 configuration + * \param ind A data structure for the decoded RX_CQI.indication This will + * have been allocated on the stack. + * \return not currently used. + * + * The ind may contain pointers to dyanmically allocated sub structures + * such as the pdu. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*cqi_indication)(struct nfapi_vnf_p7_config* config, nfapi_cqi_indication_t* ind); + + /*! A callback for the LBT_DL.indication + * \param config A pointer to the vnf p7 configuration + * \param ind A data structure for the decoded LBT_DL.indication This will + * have been allocated on the stack. + * \return not currently used. + * + * The ind may contain pointers to dyanmically allocated sub structures + * such as the pdu. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*lbt_dl_indication)(struct nfapi_vnf_p7_config* config, nfapi_lbt_dl_indication_t* ind); + + /*! A callback for the NB_HARQ.indication + * \param config A pointer to the vnf p7 configuration + * \param ind A data structure for the decoded LBT_DL.indication This will + * have been allocated on the stack. + * \return not currently used. + * + * The ind may contain pointers to dyanmically allocated sub structures + * such as the pdu. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*nb_harq_indication)(struct nfapi_vnf_p7_config* config, nfapi_nb_harq_indication_t* ind); + + /*! A callback for the NRACH.indication + * \param config A pointer to the vnf p7 configuration + * \param ind A data structure for the decoded LBT_DL.indication This will + * have been allocated on the stack. + * \return not currently used. + * + * The ind may contain pointers to dyanmically allocated sub structures + * such as the pdu. The dyanmically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*nrach_indication)(struct nfapi_vnf_p7_config* config, nfapi_nrach_indication_t* ind); + + /*! A callback for any vendor extension messages + * \param config A pointer to the vnf p7 configuration + * \param msg A data structure for the decoded vendor extention message allocated + * using the allocate_p7_vendor_ext callback + * \return not currently used. + */ + int (*vendor_ext)(struct nfapi_vnf_p7_config* config, nfapi_p7_message_header_t* msg); + + /*! Optional userdata that will be passed back in the callbacks*/ + void* user_data; + + /*! A callback to allocate a memory for a vendor extension message + * \param message_id The message is taken from the p7 message header + * \param msg_size The is the vendor extention message that has been allocated. + * The callee must set this value + * \return A pointer to an allocated vendor extention message + */ + nfapi_p7_message_header_t* (*allocate_p7_vendor_ext)(uint16_t message_id, uint16_t* msg_size); + + /*! A callback to deallocate a vendor extension message + * \param header A pointer to an allocated vendor extention message + */ + void (*deallocate_p7_vendor_ext)(nfapi_p7_message_header_t* header); + + +} nfapi_vnf_p7_config_t; + +/*! Creates and initializes the nfapi_vnf_p7_config structure before use + * \return A pointer to an allocated vnf p7 configuration + */ +nfapi_vnf_p7_config_t* nfapi_vnf_p7_config_create(void); + +/*! Cleanup and delete nfapi_vnf_p7_config structure + * \param config A pointer to an vnf p7 configuration structure + * + * The pointer to the config will not long be valid after this call + */ + +void nfapi_vnf_p7_config_destory(nfapi_vnf_p7_config_t* config); + +/*! Start the VNF P7 library. + * \param config A pointer to an vnf p7 configuration structure + * \return A status value. 0 equal success, -1 indicates failure + * + * This function is blocking and will not return until the nfapi_vnf_p7_stop + * function is called. + */ + +int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config); + +/*! Stop the VNF P7 library. + * \param config A pointer to an vnf p7 configuration structure + * \return A status value. 0 equal success, -1 indicates failure + * + * This function will cause the nfapi_vnf_p7_start function to return + */ +int nfapi_vnf_p7_stop(nfapi_vnf_p7_config_t* config); + +/*! Release a P7 message back to the vnf_p7 library. This should be used if the + * callback return 0 in the case where MAC wants to keep the message for + * futher processing. + * This function will release any pdu's is they are non-null. If the uplink + * PDU need to be kept then they pdu pointer should be set to 0 in the message + * and then the nfapi_vnf_p7_release_pdu message can be used to release the + * pdu later. + */ +int nfapi_vnf_p7_release_msg(nfapi_vnf_p7_config_t* config, nfapi_p7_message_header_t*); + +/*! Release a P7 pdu's back to the vnf_p7 library. + */ +int nfapi_vnf_p7_release_pdu(nfapi_vnf_p7_config_t* config, void*); + +/*! Add a vnf p7 instance to the vnf p7 module + * \param config A pointer to the vnf p7 configuration + * \param pnf_p7_addr The udp address the pnf p7 entity has chosen + * \param pnf_p7_port The udp port the pnf p7 entity has chosen + * \param phy_id The unique phy id for the pnf p7 entity + * \return A status value. 0 equal success, -1 indicates failure + * + * This function should be used to each pnf p7 entity that is to be added to this + * vnf p7 entity. Once added the vnf p7 entity will start establish sync with the + * pnf p7 entity and that has been sucessfull will generate subframe indications for it + */ +int nfapi_vnf_p7_add_pnf(nfapi_vnf_p7_config_t* config, const char* pnf_p7_addr, int pnf_p7_port, int phy_id); + +/*! Delete a vnf p7 instance to the vnf p7 module + * \param config A pointer to the vnf p7 configuration + * \param phy_id The unique phy id for the pnf p7 entity + * \return A status value. 0 equal success, -1 indicates failure + * + * This function should be used to remove a pnf p7 entity from the vnf p7 entity + */ +int nfapi_vnf_p7_del_pnf(nfapi_vnf_p7_config_t* config, int phy_id); + +/*! Send the DL_CONFIG.request + * \param config A pointer to the vnf p7 configuration + * \param req A data structure for the decoded DL_CONFIG.request. + * \return A status value. 0 equal success, -1 indicates failure + * + * The caller is responsiable for memory management of any pointers set in the req, which + * may be released after this function call has returned or at a later pointer + */ +int nfapi_vnf_p7_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_dl_config_request_t* req); + +/*! Send the UL_CONFIG.request + * \param config A pointer to the vnf p7 configuration + * \param req A data structure for the decoded UL_CONFIG.request. + * \return A status value. 0 equal success, -1 indicates failure + * + * The caller is responsiable for memory management of any pointers set in the req, which + * may be released after this function call has returned or at a later pointer + */ +int nfapi_vnf_p7_ul_config_req(nfapi_vnf_p7_config_t* config, nfapi_ul_config_request_t* req); + +/*! Send the HI_DCI0.request + * \param config A pointer to the vnf p7 configuration + * \param req A data structure for the decoded HI_DCI0.request. + * \return A status value. 0 equal success, -1 indicates failure + * + * The caller is responsiable for memory management of any pointers set in the req, which + * may be released after this function call has returned or at a later pointer + */ +int nfapi_vnf_p7_hi_dci0_req(nfapi_vnf_p7_config_t* config, nfapi_hi_dci0_request_t* req); + +/*! Send the TX.req + * \param config A pointer to the vnf p7 configuration + * \param req A data structure for the decoded HI_DCI0.request. + * \return A status value. 0 equal success, -1 indicates failure + * + * The caller is responsiable for memory management of any pointers set in the req, which + * may be released after this function call has returned or at a later pointer + */ +int nfapi_vnf_p7_tx_req(nfapi_vnf_p7_config_t* config, nfapi_tx_request_t* req); + +/*! Send the LBT_DL_CONFIG.requst + * \param config A pointer to the vnf p7 configuration + * \param req A data structure for the decoded LBT_DL_CONFIG.request. + * \return A status value. 0 equal success, -1 indicates failure + * + * The caller is responsiable for memory management of any pointers set in the req, which + * may be released after this function call has returned or at a later pointer + */ +int nfapi_vnf_p7_lbt_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_lbt_dl_config_request_t* req); + +/*! Send a vendor extension message + * \param config A pointer to the vnf p7 configuration + * \param msg A data structure for the decoded vendor extention message + * \return A status value. 0 equal success, -1 indicates failure + * + * The caller is responsiable for memory management of any pointers set in the req, which + * may be released after this function call has returned or at a later pointer + */ +int nfapi_vnf_p7_vendor_extension(nfapi_vnf_p7_config_t* config, nfapi_p7_message_header_t* msg); + +#if defined(__cplusplus) +} +#endif + +#endif // _NFAPI_PNF_INTERFACE_H_ diff --git a/nfapi/open-nFAPI/vnf/src/vnf.c b/nfapi/open-nFAPI/vnf/src/vnf.c new file mode 100644 index 0000000000..6800ee21d2 --- /dev/null +++ b/nfapi/open-nFAPI/vnf/src/vnf.c @@ -0,0 +1,1123 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include "vnf.h" + + +void* vnf_malloc(nfapi_vnf_config_t* config, size_t size) +{ + if(config->malloc) + { + return (config->malloc)(size); + } + else + { + return calloc(1, size); + } +} +void vnf_free(nfapi_vnf_config_t* config, void* ptr) +{ + if(config->free) + { + return (config->free)(ptr); + } + else + { + return free(ptr); + } +} + +void nfapi_vnf_phy_info_list_add(nfapi_vnf_config_t* config, nfapi_vnf_phy_info_t* info) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "Adding phy p5_idx:%d phy_id:%d\n", info->p5_idx, info->phy_id); + info->next = config->phy_list; + config->phy_list = info; +} + +nfapi_vnf_phy_info_t* nfapi_vnf_phy_info_list_find(nfapi_vnf_config_t* config, uint16_t phy_id) +{ + nfapi_vnf_phy_info_t* curr = config->phy_list; + while(curr != 0) + { + if(curr->phy_id == phy_id) + return curr; + + curr = curr->next; + } + + return 0; +} + + + + +void nfapi_vnf_pnf_list_add(nfapi_vnf_config_t* config, nfapi_vnf_pnf_info_t* node) +{ + node->next = config->pnf_list; + config->pnf_list = node; +} + + +nfapi_vnf_pnf_info_t* nfapi_vnf_pnf_list_find(nfapi_vnf_config_t* config, int p5_idx) +{ + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s : config->pnf_list:%p\n", __FUNCTION__, config->pnf_list); + + nfapi_vnf_pnf_info_t* curr = config->pnf_list; + while(curr != 0) + { + if(curr->p5_idx == p5_idx) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s : curr->p5_idx:%d p5_idx:%d\n", __FUNCTION__, curr->p5_idx, p5_idx); + return curr; + } + + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s : curr->next:%p\n", __FUNCTION__, curr->next); + + curr = curr->next; + } + + return 0; +} + +void vnf_handle_pnf_param_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s : NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received PNF_PARAM.reponse\n"); + + nfapi_pnf_param_response_t msg; + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + // Invoke the call back + if(config->pnf_param_resp) + { + (config->pnf_param_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_pnf_config_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received PNF_CONFIG_RESPONSE\n"); + + nfapi_pnf_config_response_t msg; + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + // Invoke the call back + if(config->pnf_config_resp) + { + (config->pnf_config_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_pnf_start_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received PNF_START_RESPONSE\n"); + + nfapi_pnf_start_response_t msg; + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + if(config->pnf_start_resp) + { + (config->pnf_start_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_pnf_stop_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received PNF_STOP_RESPONSE\n"); + + nfapi_pnf_stop_response_t msg; + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + if(config->pnf_stop_resp) + { + (config->pnf_stop_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + + } +} + +void vnf_handle_param_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received PARAM_RESPONSE\n"); + + nfapi_param_response_t msg; + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + + if (msg.error_code == NFAPI_MSG_OK) + { + nfapi_vnf_phy_info_t* phy_info = nfapi_vnf_phy_info_list_find(config, msg.header.phy_id); + + if(msg.nfapi_config.p7_pnf_address_ipv4.tl.tag) + { + struct sockaddr_in sockAddr; + + (void)memcpy(&sockAddr.sin_addr.s_addr, msg.nfapi_config.p7_pnf_address_ipv4.address, NFAPI_IPV4_ADDRESS_LENGTH); + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 IPv4 address: %s\n", inet_ntoa(sockAddr.sin_addr)); + + // store address + phy_info->p7_pnf_address.sin_addr = sockAddr.sin_addr; + } + + if(msg.nfapi_config.p7_pnf_address_ipv6.tl.tag) + { + struct sockaddr_in6 sockAddr6; + char addr6[64]; + (void)memcpy(&sockAddr6.sin6_addr, msg.nfapi_config.p7_pnf_address_ipv6.address, NFAPI_IPV6_ADDRESS_LENGTH); + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 IPv6 address: %s\n", inet_ntop(AF_INET6, &sockAddr6.sin6_addr, addr6, sizeof(addr6))); + } + + if (msg.nfapi_config.p7_pnf_port.tl.tag) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 Port: %d\n", msg.nfapi_config.p7_pnf_port.value); + + // store port + phy_info->p7_pnf_address.sin_port = htons(msg.nfapi_config.p7_pnf_port.value); + } + } + + if(config->param_resp) + { + (config->param_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_config_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received CONFIG_RESPONSE\n"); + + nfapi_config_response_t msg; + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >=0 ) + { + if(config->config_resp) + { + (config->config_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_start_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received START_RESPONSE\n"); + + nfapi_start_response_t msg; + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + if(config->start_resp) + { + (config->start_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_stop_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received STOP.response\n"); + + nfapi_stop_response_t msg; + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + if(config->stop_resp) + { + (config->stop_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_measurement_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received MEASUREMENT.response\n"); + + nfapi_measurement_response_t msg; + + // unpack the message + if (nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + if(config->measurement_resp) + { + (config->measurement_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_rssi_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received RSSI.response\n"); + + nfapi_rssi_response_t msg; + + // unpack the message + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + if(config->rssi_resp) + { + (config->rssi_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_rssi_indication(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received RSSI.indication\n"); + + nfapi_rssi_indication_t msg; + + // unpack the message + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + if(config->rssi_ind) + { + (config->rssi_ind)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_cell_search_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received CELL_SEARCH.response\n"); + + nfapi_cell_search_response_t msg; + + // unpack the message + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + if(config->cell_search_resp) + { + (config->cell_search_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_cell_search_indication(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "vnf_handle_cell_search_indication: NULL parameters\n"); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received CELL_SEARCH.indication\n"); + + nfapi_cell_search_indication_t msg; + + // unpack the message + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + if(config->cell_search_ind) + { + (config->cell_search_ind)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "vnf_handle_cell_search_response: Unpack message failed, ignoring\n"); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_broadcast_detect_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received BROADCAST_DETECT.response\n"); + + nfapi_broadcast_detect_response_t msg; + + // unpack the message + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + if(config->broadcast_detect_resp) + { + (config->broadcast_detect_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_broadcast_detect_indication(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received BROADCAST_DETECT.indication\n"); + + nfapi_broadcast_detect_indication_t msg; + + // unpack the message + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + if(config->broadcast_detect_ind) + { + (config->broadcast_detect_ind)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + return; + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_system_information_schedule_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received SYSTEM_INFORMATION_SCHEDULE.response\n"); + + nfapi_system_information_schedule_response_t msg; + + // unpack the message + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + if(config->system_information_schedule_resp) + { + (config->system_information_schedule_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_system_information_schedule_indication(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received SYSTEM_INFORMATION_SCHEDULE.indication\n"); + + nfapi_system_information_schedule_indication_t msg; + + // unpack the message + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + if(config->system_information_schedule_ind) + { + (config->system_information_schedule_ind)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_system_information_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received SYSTEM_INFORMATION.response\n"); + + nfapi_system_information_response_t msg; + + // unpack the message + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + { + if(config->system_information_resp) + { + (config->system_information_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_system_information_indication(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received SYSTEM_INFORMATION.indication\n"); + + nfapi_system_information_indication_t msg; + + // unpack the message + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + return; + } + + if(config->system_information_ind) + { + (config->system_information_ind)(config, p5_idx, &msg); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + +void vnf_handle_nmm_stop_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received NMM_STOP.response\n"); + + nfapi_nmm_stop_response_t msg; + + // unpack the message + if (nfapi_p4_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(nfapi_nmm_stop_response_t), &config->codec_config) >= 0) + { + if(config->nmm_stop_resp) + { + (config->nmm_stop_resp)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dyanmic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } + +} + +void vnf_handle_vendor_extension(void* pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx, uint16_t message_id) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + + if(config->allocate_p4_p5_vendor_ext && config->deallocate_p4_p5_vendor_ext) + { + uint16_t msg_size; + + nfapi_p4_p5_message_header_t* msg = config->allocate_p4_p5_vendor_ext(message_id, &msg_size); + + if(msg) + { + if(nfapi_p5_message_unpack(pRecvMsg, recvMsgLen, msg, msg_size, &config->codec_config) >= 0) + { + if(config->vendor_ext) + config->vendor_ext(config, p5_idx, msg); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + config->deallocate_p4_p5_vendor_ext(msg); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to allocate vendor extention structure\n"); + } + } +} + +void vnf_handle_p4_p5_message(void *pRecvMsg, int recvMsgLen, int p5_idx, nfapi_vnf_config_t* config) +{ + nfapi_p4_p5_message_header_t messageHeader; + + // validate the input params + if(pRecvMsg == NULL || recvMsgLen < NFAPI_HEADER_LENGTH || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "vnf_handle_p4_p5_message: invalid input params\n"); + return; + } + + // unpack the message header + if (nfapi_p5_message_header_unpack(pRecvMsg, recvMsgLen, &messageHeader, sizeof(nfapi_p4_p5_message_header_t), &config->codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); + return; + } + + switch (messageHeader.message_id) + { + case NFAPI_PNF_PARAM_RESPONSE: + vnf_handle_pnf_param_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_PNF_CONFIG_RESPONSE: + vnf_handle_pnf_config_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_PNF_START_RESPONSE: + vnf_handle_pnf_start_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_PNF_STOP_RESPONSE: + vnf_handle_pnf_stop_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_PARAM_RESPONSE: + vnf_handle_param_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_CONFIG_RESPONSE: + vnf_handle_config_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_START_RESPONSE: + vnf_handle_start_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_STOP_RESPONSE: + vnf_handle_stop_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_MEASUREMENT_RESPONSE: + vnf_handle_measurement_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_RSSI_RESPONSE: + vnf_handle_rssi_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_RSSI_INDICATION: + vnf_handle_rssi_indication(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_CELL_SEARCH_RESPONSE: + vnf_handle_cell_search_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_CELL_SEARCH_INDICATION: + vnf_handle_cell_search_indication(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_BROADCAST_DETECT_RESPONSE: + vnf_handle_broadcast_detect_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_BROADCAST_DETECT_INDICATION: + vnf_handle_broadcast_detect_indication(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_SYSTEM_INFORMATION_SCHEDULE_RESPONSE: + vnf_handle_system_information_schedule_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_SYSTEM_INFORMATION_SCHEDULE_INDICATION: + vnf_handle_system_information_schedule_indication(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_SYSTEM_INFORMATION_RESPONSE: + vnf_handle_system_information_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_SYSTEM_INFORMATION_INDICATION: + vnf_handle_system_information_indication(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + case NFAPI_NMM_STOP_RESPONSE: + vnf_handle_nmm_stop_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; + + default: + { + if(messageHeader.message_id >= NFAPI_VENDOR_EXT_MSG_MIN && + messageHeader.message_id <= NFAPI_VENDOR_EXT_MSG_MAX) + { + vnf_handle_vendor_extension(pRecvMsg, recvMsgLen, config, p5_idx, messageHeader.message_id); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s P5 Unknown message ID %d\n", __FUNCTION__, messageHeader.message_id); + } + } + break; + } +} +int vnf_read_dispatch_message(nfapi_vnf_config_t* config, nfapi_vnf_pnf_info_t* pnf) +{ + if(1) + { + int socket_connected = 1; + + // 1. Peek the message header + // 2. If the message is larger than the stack buffer then create a dynamic buffer + // 3. Read the buffer + // 4. Handle the p5 message + + uint32_t header_buffer_size = NFAPI_HEADER_LENGTH; + uint8_t header_buffer[header_buffer_size]; + + uint32_t stack_buffer_size = 32; //should it be the size of then sctp_notificatoin structure + uint8_t stack_buffer[stack_buffer_size]; + + uint8_t* dynamic_buffer = 0; + + uint8_t* read_buffer = &stack_buffer[0]; + uint32_t message_size = 0; + + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + + struct sctp_sndrcvinfo sndrcvinfo; + (void)memset(&sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); + + { + int flags = MSG_PEEK; + message_size = sctp_recvmsg(pnf->p5_sock, header_buffer, header_buffer_size, (struct sockaddr*)&addr, &addr_len, &sndrcvinfo, &flags); + + if(message_size == -1) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Failed to peek sctp message size errno:%d\n", errno); + return 0; + } + + nfapi_p4_p5_message_header_t header; + int unpack_result = nfapi_p5_message_header_unpack(header_buffer, header_buffer_size, &header, sizeof(header), 0); + if(unpack_result < 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Failed to decode message header %d\n", unpack_result); + return 0; + } + message_size = header.message_length; + + // now have the size of the mesage + } + + if(message_size > stack_buffer_size) + { + dynamic_buffer = (uint8_t*)malloc(message_size); + + if(dynamic_buffer == NULL) + { + // todo : add error mesage + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Failed to allocate dynamic buffer for sctp_recvmsg size:%d\n", message_size); + return -1; + } + + read_buffer = dynamic_buffer; + } + + { + int flags = 0; + (void)memset(&sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); + + int recvmsg_result = sctp_recvmsg(pnf->p5_sock, read_buffer, message_size, (struct sockaddr*)&addr, &addr_len, &sndrcvinfo, &flags); + if(recvmsg_result == -1) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Failed to read sctp message size errno:%d\n", errno); + } + else + { + if (flags & MSG_NOTIFICATION) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Notification received from %s:%u\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + // todo - handle the events + } + else + { + /* + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received message fd:%d from %s:%u assoc:%d on stream %d, PPID %d, length %d, flags 0x%x\n", + pnf->p5_sock, + inet_ntoa(addr.sin_addr), + ntohs(addr.sin_port), + sndrcvinfo.sinfo_assoc_id, + sndrcvinfo.sinfo_stream, + ntohl(sndrcvinfo.sinfo_ppid), + message_size, + flags); + */ + + // handle now if complete message in one or more segments + if ((flags & 0x80) == 0x80) + { + vnf_handle_p4_p5_message(read_buffer, message_size, pnf->p5_idx, config); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_WARN, "sctp_recvmsg: unhandled mode with flags 0x%x\n", flags); + + // assume socket disconnected + NFAPI_TRACE(NFAPI_TRACE_WARN, "Disconnected socket\n"); + socket_connected = 0; + } + + + } + } + } + + if(dynamic_buffer) + { + free(dynamic_buffer); + } + + return socket_connected; + } +} + +static int vnf_send_p5_msg(nfapi_vnf_pnf_info_t* pnf, const void *msg, int len, uint8_t stream) +{ + //NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s len:%d stream:%d\n", __FUNCTION__, len, stream); + + int result = sctp_sendmsg(pnf->p5_sock, msg, len, (struct sockaddr*)&pnf->p5_pnf_sockaddr, sizeof(pnf->p5_pnf_sockaddr),1, 0, stream, 0, 4); + + if(result != len) + { + if(result < 0) + { + // error + NFAPI_TRACE(NFAPI_TRACE_ERROR, "sctp sendto failed errno: %d\n", errno); + } + else + { + // did not send all the message + } + } + + return 0; +} + + +int vnf_pack_and_send_p5_message(vnf_t* vnf, uint16_t p5_idx, nfapi_p4_p5_message_header_t* msg, uint16_t msg_len) +{ + nfapi_vnf_pnf_info_t* pnf = nfapi_vnf_pnf_list_find(&(vnf->_public), p5_idx); + + if(pnf) + { + // pack the message for transmission + int packedMessageLength = nfapi_p5_message_pack(msg, msg_len, vnf->tx_message_buffer, sizeof(vnf->tx_message_buffer), &vnf->_public.codec_config); + + if (packedMessageLength < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p5_message_pack failed with return %d\n", packedMessageLength); + return -1; + } + + return vnf_send_p5_msg(pnf, vnf->tx_message_buffer, packedMessageLength, 0/*msg->phy_id*/); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() cannot find pnf info for p5_idx:%d\n", __FUNCTION__, p5_idx); + return -1; + } +} + + +int vnf_pack_and_send_p4_message(vnf_t* vnf, uint16_t p5_idx, nfapi_p4_p5_message_header_t* msg, uint16_t msg_len) +{ + nfapi_vnf_pnf_info_t* pnf = nfapi_vnf_pnf_list_find(&(vnf->_public), p5_idx); + + if(pnf) + { + // pack the message for transmission + int packedMessageLength = nfapi_p4_message_pack(msg, msg_len, vnf->tx_message_buffer, sizeof(vnf->tx_message_buffer), &vnf->_public.codec_config); + + if (packedMessageLength < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p4_message_pack failed with return %d\n", packedMessageLength); + return -1; + } + + return vnf_send_p5_msg(pnf, vnf->tx_message_buffer, packedMessageLength, 0/*msg->phy_id*/); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() cannot find pnf info for p5_idx:%d\n", __FUNCTION__, p5_idx); + return -1; + } +} + diff --git a/nfapi/open-nFAPI/vnf/src/vnf_interface.c b/nfapi/open-nFAPI/vnf/src/vnf_interface.c new file mode 100644 index 0000000000..0aba0a29f5 --- /dev/null +++ b/nfapi/open-nFAPI/vnf/src/vnf_interface.c @@ -0,0 +1,676 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "vnf.h" + + + +nfapi_vnf_config_t* nfapi_vnf_config_create() +{ + vnf_t* _this = (vnf_t*)calloc(1, sizeof(vnf_t)); + + if(_this == 0) + return 0; + + _this->sctp = 1; + + _this->next_phy_id = 1; + + // Set the default P5 port + _this->_public.vnf_p5_port = NFAPI_P5_SCTP_PORT; + + // set the default memory allocation + _this->_public.malloc = &malloc; + _this->_public.free = &free; + + // set the default memory allocation + _this->_public.codec_config.allocate = &malloc; + _this->_public.codec_config.deallocate = &free; + + + return &(_this->_public); +} + +void nfapi_vnf_config_destory(nfapi_vnf_config_t* config) +{ + free(config); +} + +int nfapi_vnf_start(nfapi_vnf_config_t* config) +{ + // Verify that config is not null + if(config == 0) + return -1; + + // Make sure to set the defined trace function before using NFAPI_TRACE + if(config->trace) + nfapi_trace_g = (nfapi_trace_fn_t)config->trace; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__); + + int p5ListenSock, p5Sock; + + struct sockaddr_in addr; + socklen_t addrSize; + + struct sockaddr_in6 addr6; + + struct sctp_event_subscribe events; + struct sctp_initmsg initMsg; + int noDelay; + + (void)memset(&addr, 0, sizeof(struct sockaddr_in)); + (void)memset(&addr6, 0, sizeof(struct sockaddr_in6)); + (void)memset(&events, 0, sizeof(struct sctp_event_subscribe)); + (void)memset(&initMsg, 0, sizeof(struct sctp_initmsg)); + + vnf_t* vnf = (vnf_t*)(config); + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Starting P5 VNF connection on port %u\n", config->vnf_p5_port); + + /* + char * host = 0; + char * port = "4242"; + struct addrinfo hints; + bzero(&hints, sizeof(struct addrinfo)); + //hints.ai_flags=AI_PASSIVE; + //hints.ai_flags=AI_DEFAULT; + hints.ai_family=AF_UNSPEC; + //hints.ai_family=AF_INET6; + hints.ai_socktype=SOCK_STREAM; + //hints.ai_protocol=IPPROTO_SCTP + + struct addrinfo *aiHead = 0; + + + + int result = getaddrinfo(host, port, &hints, &aiHead); + NFAPI_TRACE(NFAPI_TRACE_INFO, "getaddrinfo return %d %d\n", result, errno); + + while(aiHead->ai_next != NULL) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "addr info %d (IP %d UDP %d SCTP %d)\n %d (%d)\n", + aiHead->ai_protocol, IPPROTO_IP, IPPROTO_UDP, IPPROTO_SCTP, + aiHead->ai_flags, AI_PASSIVE); + + char hostBfr[ NI_MAXHOST ]; + char servBfr[ NI_MAXSERV ]; + + getnameinfo(aiHead->ai_addr, + aiHead->ai_addrlen, + hostBfr, + sizeof( hostBfr ), + servBfr, + sizeof( servBfr ), + NI_NUMERICHOST | NI_NUMERICSERV ); + + switch(aiHead->ai_family) + { + case PF_INET: + { + struct sockaddr_in *pSadrIn = (struct sockaddr_in*) aiHead->ai_addr; + printf( + " ai_addr = sin_family: %d (AF_INET = %d, " + "AF_INET6 = %d)\n" + " sin_addr: %s\n" + " sin_port: %s\n", + pSadrIn->sin_family, + AF_INET, + AF_INET6, + hostBfr, + servBfr ); + } + break; + case PF_INET6: + { + struct sockaddr_in6 *pSadrIn6 = (struct sockaddr_in6*) aiHead->ai_addr; + fprintf( stderr, + " ai_addr = sin6_family: %d (AF_INET = %d, " + "AF_INET6 = %d) \n" + " sin6_addr: %s\n" + " sin6_port: %s\n" + " sin6_flowinfo: %d\n" + " sin6_scope_id: %d\n", + pSadrIn6->sin6_family, + AF_INET, + AF_INET6, + hostBfr, + servBfr, + pSadrIn6->sin6_flowinfo, + pSadrIn6->sin6_scope_id); + } + break; + default: + NFAPI_TRACE(NFAPI_TRACE_INFO, "Not ment to be here\n"); + break; + } + + aiHead = aiHead->ai_next; + } + */ + + { + int protocol; + int domain; + + if (vnf->sctp) + protocol = IPPROTO_SCTP; + else + protocol = IPPROTO_IP; + + if(config->vnf_ipv6) + { + domain = PF_INET6; + } + else + { + domain = AF_INET; + } + + // open the SCTP socket + if ((p5ListenSock = socket(domain, SOCK_STREAM, protocol)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P5 socket errno: %d\n", errno); + return 0; + } + NFAPI_TRACE(NFAPI_TRACE_INFO, "P5 socket created... %d\n", p5ListenSock); + } + + if (vnf->sctp) + { + // configure for MSG_NOTIFICATION + if (setsockopt(p5ListenSock, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(struct sctp_event_subscribe)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (SCTP_EVENTS) errno: %d\n", errno); + close(p5ListenSock); + return 0; + } + NFAPI_TRACE(NFAPI_TRACE_NOTE, "VNF Setting the SCTP_INITMSG\n"); + // configure the SCTP socket options + initMsg.sinit_num_ostreams = 5; //MAX_SCTP_STREAMS; // number of output streams can be greater + initMsg.sinit_max_instreams = 5; //MAX_SCTP_STREAMS; // number of output streams can be greater + if (setsockopt(p5ListenSock, IPPROTO_SCTP, SCTP_INITMSG, &initMsg, sizeof(initMsg)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (SCTP_INITMSG) errno: %d\n", errno) + close(p5ListenSock); + return 0; + } + noDelay = 1; + if (setsockopt(p5ListenSock, IPPROTO_SCTP, SCTP_NODELAY, &noDelay, sizeof(noDelay)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (STCP_NODELAY) errno: %d\n", errno); + close(p5ListenSock); + return 0; + } + struct sctp_event_subscribe events; + memset( (void *)&events, 0, sizeof(events) ); + events.sctp_data_io_event = 1; + + if(setsockopt(p5ListenSock, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt errno: %d\n", errno); + close(p5ListenSock); + return -1; + } + + } + + + if(config->vnf_ipv6) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "IPV6 binding to port %d %d\n", config->vnf_p5_port, p5ListenSock); + addr6.sin6_family = AF_INET6; + addr6.sin6_port = htons(config->vnf_p5_port); + addr6.sin6_addr = in6addr_any; + + // bind to the configured address and port + if (bind(p5ListenSock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After bind errno: %d\n", errno); + close(p5ListenSock); + return 0; + } + } + else if(config->vnf_ipv4) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "IPV4 binding to port %d\n", config->vnf_p5_port); + addr.sin_family = AF_INET; + addr.sin_port = htons(config->vnf_p5_port); + addr.sin_addr.s_addr = INADDR_ANY; + + // bind to the configured address and port + if (bind(p5ListenSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) + //if (sctp_bindx(p5ListenSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in), SCTP_BINDX_ADD_ADDR) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After bind errno: %d\n", errno); + close(p5ListenSock); + return 0; + } + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "bind succeeded..%d.\n", p5ListenSock); + + // put the socket into listen mode + if (listen(p5ListenSock, 2) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After listen errno: %d\n", errno); + close(p5ListenSock); + return 0; + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "listen succeeded...\n"); + + struct timeval tv; + fd_set read_fd_set; + + + int p5_idx = 0; + while(vnf->terminate == 0) + { + FD_ZERO(&read_fd_set); + + FD_SET(p5ListenSock, &read_fd_set); + int max_fd = p5ListenSock; + + tv.tv_sec = 5; + tv.tv_usec = 0; + + nfapi_vnf_pnf_info_t* pnf = config->pnf_list; + while(pnf != 0) + { + if(pnf->connected) + { + FD_SET(pnf->p5_sock, &read_fd_set); + if (pnf->p5_sock > max_fd) + { + max_fd = pnf->p5_sock; + } + } + + pnf = pnf->next; + } + + int select_result = select(max_fd + 1, &read_fd_set, 0, 0, &tv); + + if(select_result == -1) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "select result %d errno %d\n", select_result, errno); + close(p5ListenSock); + return 0; + } + else if(select_result) + { + if(FD_ISSET(p5ListenSock, &read_fd_set)) + { + addrSize = sizeof(struct sockaddr_in); + NFAPI_TRACE(NFAPI_TRACE_INFO, "Accepting connection from PNF...\n"); + + p5Sock = accept(p5ListenSock, (struct sockaddr *)&addr, &addrSize); + + if (p5Sock < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to accept PNF connection reason:%d\n", errno); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF connection (fd:%d) accepted from %s:%d \n", p5Sock, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + nfapi_vnf_pnf_info_t* pnf = (nfapi_vnf_pnf_info_t*)malloc(sizeof(nfapi_vnf_pnf_info_t)); + NFAPI_TRACE(NFAPI_TRACE_INFO, "MALLOC nfapi_vnf_pnf_info_t for pnf_list pnf:%p\n", pnf); + memset(pnf, 0, sizeof(nfapi_vnf_pnf_info_t)); + pnf->p5_sock = p5Sock; + pnf->p5_idx = p5_idx++; + pnf->p5_pnf_sockaddr = addr; + pnf->connected = 1; + + nfapi_vnf_pnf_list_add(config, pnf); + + // Inform mac that a pnf connection has been established + // todo : allow mac to 'accept' the connection. i.e. to + // reject it. + if(config->pnf_connection_indication != 0) + { + (config->pnf_connection_indication)(config, pnf->p5_idx); + } + + + // check the connection status + { + struct sctp_status status; + (void)memset(&status, 0, sizeof(struct sctp_status)); + socklen_t optLen = (socklen_t) sizeof(struct sctp_status); + if (getsockopt(p5Sock, IPPROTO_SCTP, SCTP_STATUS, &status, &optLen) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After getsockopt errno: %d\n", errno); + return -1; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Association ID = %d\n", status.sstat_assoc_id); + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Receiver window size = %d\n", status.sstat_rwnd); + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF In Streams = %d\n", status.sstat_instrms); + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Out Streams = %d\n", status.sstat_outstrms); + + } + } + } + } + else + { + uint8_t delete_pnfs = 0; + + nfapi_vnf_pnf_info_t* pnf = config->pnf_list; + while(pnf != 0) + { + if(FD_ISSET(pnf->p5_sock, &read_fd_set)) + { + if(vnf_read_dispatch_message(config, pnf) == 0) + { + if(config->pnf_disconnect_indication != 0) + { + (config->pnf_disconnect_indication)(config, pnf->p5_idx); + } + + close(pnf->p5_sock); + + pnf->to_delete = 1; + delete_pnfs = 1; + } + } + + pnf = pnf->next; + } + + if(delete_pnfs) + { + nfapi_vnf_pnf_info_t* pnf = config->pnf_list; + nfapi_vnf_pnf_info_t* prev = 0; + while(pnf != 0) + { + nfapi_vnf_pnf_info_t* curr = pnf; + + if(pnf->to_delete == 1) + { + if(prev == 0) + { + config->pnf_list = pnf->next; + } + else + { + prev->next = pnf->next; + } + + pnf = pnf->next; + + free(curr); + } + else + { + prev = pnf; + pnf = pnf->next; + } + + } + + } + } + + continue; + } + else + { + // timeout + + // Should we test for socket closure here every second? + + continue; + } + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Closing p5Sock socket's\n"); + { + nfapi_vnf_pnf_info_t* curr = config->pnf_list; + while(curr != NULL) + { + if(config->pnf_disconnect_indication) + { + (config->pnf_disconnect_indication)(config, curr->p5_idx); + } + + close(curr->p5_sock); + curr = curr->next; + } + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Closing p5Listen socket\n"); + close(p5ListenSock); + + return 0; + +} + +int nfapi_vnf_stop(nfapi_vnf_config_t* config) +{ + // Verify that config is not null + if(config == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + _this->terminate = 1; + return 0; +} + +int nfapi_vnf_pnf_param_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_param_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_pnf_param_request_t)); +} + +int nfapi_vnf_pnf_config_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_config_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_pnf_config_request_t)); +} + +int nfapi_vnf_pnf_start_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_start_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_pnf_start_request_t)); +} + +int nfapi_vnf_pnf_stop_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_stop_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_pnf_stop_request_t)); +} + +int nfapi_vnf_param_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_param_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_param_request_t)); +} +int nfapi_vnf_config_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_config_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + nfapi_vnf_phy_info_t* phy = nfapi_vnf_phy_info_list_find(config, req->header.phy_id); + + if(phy == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_WARN, "%s failed to find phy inforation phy_id:%d\n", __FUNCTION__, req->header.phy_id); + return -1; + } + + // set the timing parameters + req->nfapi_config.timing_window.tl.tag = NFAPI_NFAPI_TIMING_WINDOW_TAG; + req->nfapi_config.timing_window.value = phy->timing_window; + req->num_tlv++; + + req->nfapi_config.timing_info_mode.tl.tag = NFAPI_NFAPI_TIMING_INFO_MODE_TAG; + req->nfapi_config.timing_info_mode.value = phy->timing_info_mode; + req->num_tlv++; + + req->nfapi_config.timing_info_period.tl.tag = NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG; + req->nfapi_config.timing_info_period.value = phy->timing_info_period; + req->num_tlv++; + + return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_config_request_t)); +} +int nfapi_vnf_start_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_start_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_start_request_t)); +} +int nfapi_vnf_stop_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_stop_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_stop_request_t)); +} +int nfapi_vnf_measurement_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_measurement_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_measurement_request_t)); +} +int nfapi_vnf_rssi_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_rssi_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p4_message(_this, p5_idx, &req->header, sizeof(nfapi_rssi_request_t)); +} +int nfapi_vnf_cell_search_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_cell_search_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p4_message(_this, p5_idx, &req->header, sizeof(nfapi_cell_search_request_t)); +} +int nfapi_vnf_broadcast_detect_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_broadcast_detect_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p4_message(_this, p5_idx, &req->header, sizeof(nfapi_broadcast_detect_request_t)); +} +int nfapi_vnf_system_information_schedule_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_schedule_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p4_message(_this, p5_idx, &req->header, sizeof(nfapi_system_information_schedule_request_t)); +} +int nfapi_vnf_system_information_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_system_information_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p4_message(_this, p5_idx, &req->header, sizeof(nfapi_system_information_request_t)); +} +int nfapi_vnf_nmm_stop_request(nfapi_vnf_config_t* config, int p5_idx, nfapi_nmm_stop_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p4_message(_this, p5_idx, &req->header, sizeof(nfapi_nmm_stop_request_t)); +} +int nfapi_vnf_vendor_extension(nfapi_vnf_config_t* config, int p5_idx, nfapi_p4_p5_message_header_t* msg) +{ + if(config == 0 || msg == 0) + return -1; + + vnf_t* _this = (vnf_t*)(config); + + return vnf_pack_and_send_p5_message(_this, p5_idx, msg, sizeof(nfapi_p4_p5_message_header_t)); +} + +int nfapi_vnf_allocate_phy(nfapi_vnf_config_t* config, int p5_idx, uint16_t* phy_id) +{ + vnf_t* vnf = (vnf_t*)config; + + nfapi_vnf_phy_info_t* info = (nfapi_vnf_phy_info_t*)calloc(1, sizeof(nfapi_vnf_phy_info_t)); + info->p5_idx = p5_idx; + info->phy_id = vnf->next_phy_id++; + + info->timing_window = 30; // This seems to override what gets set by the user - why??? + info->timing_info_mode = 0x03; + info->timing_info_period = 128; + + nfapi_vnf_phy_info_list_add(config, info); + + (*phy_id) = info->phy_id; + + return 0; +} diff --git a/nfapi/open-nFAPI/vnf/src/vnf_p7.c b/nfapi/open-nFAPI/vnf/src/vnf_p7.c new file mode 100644 index 0000000000..1304176752 --- /dev/null +++ b/nfapi/open-nFAPI/vnf/src/vnf_p7.c @@ -0,0 +1,1599 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include + +#include +#include +#include +#include +#include + +#include "vnf_p7.h" + +#define SYNC_CYCLE_COUNT 2 + +void* vnf_p7_malloc(vnf_p7_t* vnf_p7, size_t size) +{ + if(vnf_p7->_public.malloc) + { + return (vnf_p7->_public.malloc)(size); + } + else + { + return calloc(1, size); + } +} +void vnf_p7_free(vnf_p7_t* vnf_p7, void* ptr) +{ + if(ptr == 0) + return; + + if(vnf_p7->_public.free) + { + (vnf_p7->_public.free)(ptr); + } + else + { + free(ptr); + } +} + +void vnf_p7_codec_free(vnf_p7_t* vnf_p7, void* ptr) +{ + if(ptr == 0) + return; + + if(vnf_p7->_public.codec_config.deallocate) + { + (vnf_p7->_public.codec_config.deallocate)(ptr); + } + else + { + free(ptr); + } +} + +void vnf_p7_connection_info_list_add(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* node) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__); + // todo : add mutex + node->next = vnf_p7->p7_connections; + vnf_p7->p7_connections = node; +} + +nfapi_vnf_p7_connection_info_t* vnf_p7_connection_info_list_find(vnf_p7_t* vnf_p7, uint16_t phy_id) +{ + nfapi_vnf_p7_connection_info_t* curr = vnf_p7->p7_connections; + while(curr != 0) + { + if(curr->phy_id == phy_id) + { + return curr; + } + curr = curr->next; + } + + return 0; +} + +nfapi_vnf_p7_connection_info_t* vnf_p7_connection_info_list_delete(vnf_p7_t* vnf_p7, uint16_t phy_id) +{ + nfapi_vnf_p7_connection_info_t* curr = vnf_p7->p7_connections; + nfapi_vnf_p7_connection_info_t* prev = 0; + + while(curr != 0) + { + if(curr->phy_id == phy_id) + { + if(prev == 0) + { + vnf_p7->p7_connections = curr->next; + } + else + { + prev->next = curr->next; + } + + return curr; + } + else + { + prev = curr; + curr = curr->next; + } + } + + return 0; +} + +vnf_p7_rx_message_t* vnf_p7_rx_reassembly_queue_add_segment(vnf_p7_t* vnf_p7, vnf_p7_rx_reassembly_queue_t* queue, uint16_t sequence_number, uint16_t segment_number, uint8_t m, uint8_t* data, uint16_t data_len) +{ + vnf_p7_rx_message_t* msg = 0; + // attempt to find a entry for this segment + vnf_p7_rx_message_t* iterator = queue->msg_queue; + while(iterator != 0) + { + if(iterator->sequence_number == sequence_number) + { + msg = iterator; + break; + } + + iterator = iterator->next; + } + + // if found then copy data to message + if(msg != 0) + { + + msg->segments[segment_number].buffer = (uint8_t*)vnf_p7_malloc(vnf_p7, data_len); + memcpy(msg->segments[segment_number].buffer, data, data_len); + msg->segments[segment_number].length = data_len; + + msg->num_segments_received++; + + // set the segement number if we have the last segment + if(m == 0) + msg->num_segments_expected = segment_number + 1; + } + // else add new rx message entry + else + { + // create a new message + msg = (vnf_p7_rx_message_t*)(vnf_p7_malloc(vnf_p7, sizeof(vnf_p7_rx_message_t))); + memset(msg, 0, sizeof(vnf_p7_rx_message_t)); + + msg->sequence_number = sequence_number; + msg->num_segments_expected = m ? 255 : segment_number + 1; + msg->num_segments_received = 1; + msg->rx_hr_time = vnf_get_current_time_hr(); + + msg->segments[segment_number].buffer = (uint8_t*)vnf_p7_malloc(vnf_p7, data_len); + memcpy(msg->segments[segment_number].buffer, data, data_len); + msg->segments[segment_number].length = data_len; + + // place the message at the head of the queue + msg->next = queue->msg_queue; + queue->msg_queue = msg; + } + + return msg; +} + +void vnf_p7_rx_reassembly_queue_remove_msg(vnf_p7_t* vnf_p7, vnf_p7_rx_reassembly_queue_t* queue, vnf_p7_rx_message_t* msg) +{ + // remove message if it has the same sequence number + vnf_p7_rx_message_t* iterator = queue->msg_queue; + vnf_p7_rx_message_t* previous = 0; + + while(iterator != 0) + { + if(iterator->sequence_number == msg->sequence_number) + { + if(previous == 0) + { + queue->msg_queue = iterator->next; + } + else + { + previous->next = iterator->next; + } + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "Deleting reassembly message\n"); + // delete the message + uint16_t i; + for(i = 0; i < 128; ++i) + { + if(iterator->segments[i].buffer) + vnf_p7_free(vnf_p7, iterator->segments[i].buffer); + } + vnf_p7_free(vnf_p7, iterator); + + break; + } + + previous = iterator; + iterator = iterator->next; + } +} + +void vnf_p7_rx_reassembly_queue_remove_old_msgs(vnf_p7_t* vnf_p7, vnf_p7_rx_reassembly_queue_t* queue, uint32_t delta) +{ + // remove all messages that are too old + vnf_p7_rx_message_t* iterator = queue->msg_queue; + vnf_p7_rx_message_t* previous = 0; + + uint32_t rx_hr_time = vnf_get_current_time_hr(); + + while(iterator != 0) + { + if(rx_hr_time - iterator->rx_hr_time > delta) + { + if(previous == 0) + { + queue->msg_queue = iterator->next; + } + else + { + previous->next = iterator->next; + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Deleting stale reassembly message (%u %u %d)\n", iterator->rx_hr_time, rx_hr_time, delta); + + vnf_p7_rx_message_t* to_delete = iterator; + iterator = iterator->next; + + // delete the message + uint16_t i; + for(i = 0; i < 128; ++i) + { + if(to_delete->segments[i].buffer) + vnf_p7_free(vnf_p7, to_delete->segments[i].buffer); + } + vnf_p7_free(vnf_p7, to_delete); + + } + else + { + previous = iterator; + iterator = iterator->next; + } + } +} + +uint32_t vnf_get_current_time_hr() +{ + struct timeval now; + (void)gettimeofday(&now, NULL); + uint32_t time_hr = TIME2TIMEHR(now); + return time_hr; +} + +uint16_t increment_sfn_sf(uint16_t sfn_sf) +{ + if((sfn_sf & 0xF) == 9) + { + sfn_sf += 0x0010; + sfn_sf &= 0x3FF0; + } + else if((sfn_sf & 0xF) > 9) + { + // error should not happen + } + else + { + sfn_sf++; + } + + return sfn_sf; +} + +struct timespec timespec_delta(struct timespec start, struct timespec end) +{ + struct timespec temp; + if ((end.tv_nsec-start.tv_nsec)<0) + { + temp.tv_sec = end.tv_sec-start.tv_sec-1; + temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; + } + else + { + temp.tv_sec = end.tv_sec-start.tv_sec; + temp.tv_nsec = end.tv_nsec-start.tv_nsec; + } + return temp; +} + +static uint32_t get_sf_time(uint32_t now_hr, uint32_t sf_start_hr) +{ + if(now_hr < sf_start_hr) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "now is earlier that start of subframe\n"); + return 0; + } + else + { + uint32_t now_us = TIMEHR_USEC(now_hr); + uint32_t sf_start_us = TIMEHR_USEC(sf_start_hr); + + // if the us have wrapped adjust for it + if(now_hr < sf_start_us) + { + now_us += 1000000; + } + + return now_us - sf_start_us; + } +} + +uint32_t calculate_t1(uint16_t sfn_sf, uint32_t sf_start_time_hr) +{ + uint32_t now_time_hr = vnf_get_current_time_hr(); + + uint32_t sf_time_us = get_sf_time(now_time_hr, sf_start_time_hr); + + uint32_t t1 = (NFAPI_SFNSF2DEC(sfn_sf) * 1000) + sf_time_us; + + return t1; +} + + +uint32_t calculate_t4(uint32_t now_time_hr, uint16_t sfn_sf, uint32_t sf_start_time_hr) +{ + uint32_t sf_time_us = get_sf_time(now_time_hr, sf_start_time_hr); + + uint32_t t4 = (NFAPI_SFNSF2DEC(sfn_sf) * 1000) + sf_time_us; + + return t4; + +} + + +uint32_t calculate_transmit_timestamp(uint16_t sfn_sf, uint32_t sf_start_time_hr) +{ + uint32_t now_time_hr = vnf_get_current_time_hr(); + + uint32_t sf_time_us = get_sf_time(now_time_hr, sf_start_time_hr); + + uint32_t tt = (NFAPI_SFNSF2DEC(sfn_sf) * 1000) + sf_time_us; + + return tt; +} + + +uint16_t increment_sfn_sf_by(uint16_t sfn_sf, uint8_t increment) +{ + while(increment > 0) + { + sfn_sf = increment_sfn_sf(sfn_sf); + --increment; + } + + return sfn_sf; +} + + +int send_mac_subframe_indications(vnf_p7_t* vnf_p7) +{ + nfapi_vnf_p7_connection_info_t* curr = vnf_p7->p7_connections; + while(curr != 0) + { + if(curr->in_sync == 1) + { + // ask for subframes in the future + uint16_t sfn_sf_adv = increment_sfn_sf_by(curr->sfn_sf, 2); + + vnf_p7->_public.subframe_indication(&(vnf_p7->_public), curr->phy_id, sfn_sf_adv); + } + + curr = curr->next; + } + + return 0; +} + +int vnf_send_p7_msg(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* p7_info, uint8_t* msg, const uint32_t len) +{ + int sendto_result = sendto(vnf_p7->socket, msg, len, 0, (struct sockaddr*)&(p7_info->remote_addr), sizeof(p7_info->remote_addr)); + + if(sendto_result != len) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() sendto_result %d %d\n", __FUNCTION__, sendto_result, errno); + } + + return 0; +} + +int vnf_p7_pack_and_send_p7_msg(vnf_p7_t* vnf_p7, nfapi_p7_message_header_t* header) +{ + + nfapi_vnf_p7_connection_info_t* p7_connection = vnf_p7_connection_info_list_find(vnf_p7, header->phy_id); + if(p7_connection) + { + int send_result = 0; + uint8_t buffer[1024 * 32]; + + header->m_segment_sequence = NFAPI_P7_SET_MSS(0, 0, p7_connection->sequence_number); + + int len = nfapi_p7_message_pack(header, buffer, sizeof(buffer), &vnf_p7->_public.codec_config); + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() phy_id:%d nfapi_p7_message_pack()=len=%d vnf_p7->_public.segment_size:%u\n", __FUNCTION__, header->phy_id, len, vnf_p7->_public.segment_size); + + if(len < 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() failed to pack p7 message phy_id:%d\n", __FUNCTION__, header->phy_id); + return -1; + } + + if(len > vnf_p7->_public.segment_size) + { + // todo : consider replacing with the sendmmsg call + // todo : worry about blocking writes? + + // segmenting the transmit + int msg_body_len = len - NFAPI_P7_HEADER_LENGTH ; + int seg_body_len = vnf_p7->_public.segment_size - NFAPI_P7_HEADER_LENGTH ; + int segment_count = (msg_body_len / (seg_body_len)) + ((msg_body_len % seg_body_len) ? 1 : 0); + + int segment = 0; + int offset = NFAPI_P7_HEADER_LENGTH; + uint8_t tx_buffer[vnf_p7->_public.segment_size]; + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() MORE THAN ONE SEGMENT phy_id:%d nfapi_p7_message_pack()=len=%d vnf_p7->_public.segment_size:%u\n", __FUNCTION__, header->phy_id, len, vnf_p7->_public.segment_size); + for(segment = 0; segment < segment_count; ++segment) + { + uint8_t last = 0; + uint16_t size = vnf_p7->_public.segment_size - NFAPI_P7_HEADER_LENGTH; + if(segment + 1 == segment_count) + { + last = 1; + size = (msg_body_len) - (seg_body_len * segment); + } + + uint16_t segment_size = size + NFAPI_P7_HEADER_LENGTH; + + // Update the header with the m and segement + memcpy(&tx_buffer[0], buffer, NFAPI_P7_HEADER_LENGTH); + + // set the segment length + tx_buffer[4] = (segment_size & 0xFF00) >> 8; + tx_buffer[5] = (segment_size & 0xFF); + + // set the m & segment number + tx_buffer[6] = ((!last) << 7) + segment; + + memcpy(&tx_buffer[NFAPI_P7_HEADER_LENGTH], &buffer[0] + offset, size); + offset += size; + + if(vnf_p7->_public.checksum_enabled) + { + nfapi_p7_update_checksum(tx_buffer, segment_size); + } + + nfapi_p7_update_transmit_timestamp(buffer, calculate_transmit_timestamp(p7_connection->sfn_sf, vnf_p7->sf_start_time_hr)); + + send_result = vnf_send_p7_msg(vnf_p7, p7_connection, &tx_buffer[0], segment_size); + } + } + else + { + if(vnf_p7->_public.checksum_enabled) + { + nfapi_p7_update_checksum(buffer, len); + } + + nfapi_p7_update_transmit_timestamp(buffer, calculate_transmit_timestamp(p7_connection->sfn_sf, vnf_p7->sf_start_time_hr)); + + // simple case that the message fits in a single segement + send_result = vnf_send_p7_msg(vnf_p7, p7_connection, &buffer[0], len); + } + + p7_connection->sequence_number++; + + return send_result; + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() cannot find p7 connection info for phy_id:%d\n", __FUNCTION__, header->phy_id); + return -1; + } +} + +int vnf_build_send_dl_node_sync(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* p7_info) +{ + nfapi_dl_node_sync_t dl_node_sync; + memset(&dl_node_sync, 0, sizeof(dl_node_sync)); + + dl_node_sync.header.phy_id = p7_info->phy_id; + dl_node_sync.header.message_id = NFAPI_DL_NODE_SYNC; + dl_node_sync.t1 = calculate_t1(p7_info->sfn_sf, vnf_p7->sf_start_time_hr); + dl_node_sync.delta_sfn_sf = 0; + + return vnf_p7_pack_and_send_p7_msg(vnf_p7, &dl_node_sync.header); +} + +int vnf_sync(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* p7_info) +{ + + if(p7_info->in_sync == 1) + { + uint16_t dl_sync_period_mask = p7_info->dl_in_sync_period-1; + uint16_t sfn_sf_dec = NFAPI_SFNSF2DEC(p7_info->sfn_sf); + + if ((((sfn_sf_dec + p7_info->dl_in_sync_offset) % NFAPI_MAX_SFNSFDEC) & dl_sync_period_mask) == 0) + { + vnf_build_send_dl_node_sync(vnf_p7, p7_info); + } + } + else + { + uint16_t dl_sync_period_mask = p7_info->dl_out_sync_period-1; + uint16_t sfn_sf_dec = NFAPI_SFNSF2DEC(p7_info->sfn_sf); + + if ((((sfn_sf_dec + p7_info->dl_out_sync_offset) % NFAPI_MAX_SFNSFDEC) & dl_sync_period_mask) == 0) + { + vnf_build_send_dl_node_sync(vnf_p7, p7_info); + } + } + return 0; +} + + +void vnf_handle_harq_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +{ + // ensure it's valid + if (pRecvMsg == NULL || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_harq_indication_t ind; + + if(nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); + } + else + { + if(vnf_p7->_public.harq_indication) + { + (vnf_p7->_public.harq_indication)(&(vnf_p7->_public), &ind); + } + } + + vnf_p7_codec_free(vnf_p7, ind.harq_indication_body.harq_pdu_list); + vnf_p7_codec_free(vnf_p7, ind.vendor_extension); + } +} + +void vnf_handle_crc_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +{ + // ensure it's valid + if (pRecvMsg == NULL || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_crc_indication_t ind; + + if(nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to message\n", __FUNCTION__); + } + else + { + if(vnf_p7->_public.crc_indication) + { + (vnf_p7->_public.crc_indication)(&(vnf_p7->_public), &ind); + } + } + + vnf_p7_codec_free(vnf_p7, ind.crc_indication_body.crc_pdu_list); + vnf_p7_codec_free(vnf_p7, ind.vendor_extension); + } +} + +void vnf_handle_rx_ulsch_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +{ + // ensure it's valid + if (pRecvMsg == NULL || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_rx_indication_t ind; + + if(nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); + } + else + { + if(vnf_p7->_public.rx_indication) + { + (vnf_p7->_public.rx_indication)(&(vnf_p7->_public), &ind); + } + } + + uint16_t i = 0; + for(i = 0; i < ind.rx_indication_body.number_of_pdus; ++i) + { + vnf_p7_codec_free(vnf_p7, ind.rx_indication_body.rx_pdu_list[i].data); + } + vnf_p7_codec_free(vnf_p7, ind.rx_indication_body.rx_pdu_list); + vnf_p7_codec_free(vnf_p7, ind.vendor_extension); + } + +} + +void vnf_handle_rach_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +{ + // ensure it's valid + if (pRecvMsg == NULL || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_rach_indication_t ind; + + if(nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to message\n", __FUNCTION__); + } + else + { + if(vnf_p7->_public.rach_indication) + { + (vnf_p7->_public.rach_indication)(&vnf_p7->_public, &ind); + } + } + + vnf_p7_codec_free(vnf_p7, ind.rach_indication_body.preamble_list); + vnf_p7_codec_free(vnf_p7, ind.vendor_extension); + + } +} + +void vnf_handle_srs_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +{ + // ensure it's valid + if (pRecvMsg == NULL || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_srs_indication_t ind; + + if(nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); + } + else + { + if(vnf_p7->_public.srs_indication) + { + (vnf_p7->_public.srs_indication)(&(vnf_p7->_public), &ind); + } + } + + vnf_p7_codec_free(vnf_p7, ind.srs_indication_body.srs_pdu_list); + vnf_p7_codec_free(vnf_p7, ind.vendor_extension); + } +} + +void vnf_handle_rx_sr_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +{ + // ensure it's valid + if (pRecvMsg == NULL || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_sr_indication_t ind; + + if(nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); + } + else + { + if(vnf_p7->_public.sr_indication) + { + (vnf_p7->_public.sr_indication)(&(vnf_p7->_public), &ind); + } + } + + vnf_p7_codec_free(vnf_p7, ind.sr_indication_body.sr_pdu_list); + vnf_p7_codec_free(vnf_p7, ind.vendor_extension); + } +} +void vnf_handle_rx_cqi_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +{ + // ensure it's valid + if (pRecvMsg == NULL || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_cqi_indication_t ind; + + if(nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); + } + else + { + if(vnf_p7->_public.cqi_indication) + { + (vnf_p7->_public.cqi_indication)(&(vnf_p7->_public), &ind); + } + } + + vnf_p7_codec_free(vnf_p7, ind.cqi_indication_body.cqi_pdu_list); + vnf_p7_codec_free(vnf_p7, ind.cqi_indication_body.cqi_raw_pdu_list); + vnf_p7_codec_free(vnf_p7, ind.vendor_extension); + + } + +} + +void vnf_handle_lbt_dl_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +{ + // ensure it's valid + if (pRecvMsg == NULL || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_lbt_dl_indication_t ind; + + if(nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); + } + else + { + if(vnf_p7->_public.lbt_dl_indication) + { + (vnf_p7->_public.lbt_dl_indication)(&(vnf_p7->_public), &ind); + } + } + + vnf_p7_codec_free(vnf_p7, ind.lbt_dl_indication_body.lbt_indication_pdu_list); + vnf_p7_codec_free(vnf_p7, ind.vendor_extension); + } +} + +void vnf_handle_nb_harq_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +{ + // ensure it's valid + if (pRecvMsg == NULL || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_nb_harq_indication_t ind; + + if(nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); + } + else + { + if(vnf_p7->_public.nb_harq_indication) + { + (vnf_p7->_public.nb_harq_indication)(&(vnf_p7->_public), &ind); + } + } + + vnf_p7_codec_free(vnf_p7, ind.nb_harq_indication_body.nb_harq_pdu_list); + vnf_p7_codec_free(vnf_p7, ind.vendor_extension); + } +} + +void vnf_handle_nrach_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +{ + // ensure it's valid + if (pRecvMsg == NULL || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + nfapi_nrach_indication_t ind; + + if(nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); + } + else + { + if(vnf_p7->_public.nrach_indication) + { + (vnf_p7->_public.nrach_indication)(&(vnf_p7->_public), &ind); + } + } + + vnf_p7_codec_free(vnf_p7, ind.nrach_indication_body.nrach_pdu_list); + vnf_p7_codec_free(vnf_p7, ind.vendor_extension); + } +} + +void vnf_handle_p7_vendor_extension(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7, uint16_t message_id) +{ + if (pRecvMsg == NULL || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else if(vnf_p7->_public.allocate_p7_vendor_ext) + { + uint16_t msg_size; + nfapi_p7_message_header_t* msg = vnf_p7->_public.allocate_p7_vendor_ext(message_id, &msg_size); + + if(msg == 0) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to allocate vendor extention structure\n", __FUNCTION__); + return; + } + + int unpack_result = nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, msg, msg_size, &vnf_p7->_public.codec_config); + + if(unpack_result == 0) + { + if(vnf_p7->_public.vendor_ext) + vnf_p7->_public.vendor_ext(&(vnf_p7->_public), msg); + } + + if(vnf_p7->_public.deallocate_p7_vendor_ext) + vnf_p7->_public.deallocate_p7_vendor_ext(msg); + + } +} + + +void vnf_handle_ul_node_sync(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +{ + uint32_t now_time_hr = vnf_get_current_time_hr(); + + if (pRecvMsg == NULL || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "vnf_handle_ul_node_sync: NULL parameters\n"); + return; + } + + nfapi_ul_node_sync_t ind; + if(nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(nfapi_ul_node_sync_t), &vnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to unpack ul_node_sync\n"); + return; + } + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "Received UL_NODE_SYNC phy_id:%d t1:%d t2:%d t3:%d\n", ind.header.phy_id, ind.t1, ind.t2, ind.t3); + + nfapi_vnf_p7_connection_info_t* phy = vnf_p7_connection_info_list_find(vnf_p7, ind.header.phy_id); + uint32_t t4 = calculate_t4(now_time_hr, phy->sfn_sf, vnf_p7->sf_start_time_hr); + + uint32_t tx_2_rx = t4>ind.t1 ? t4 - ind.t1 : t4 + NFAPI_MAX_SFNSFDEC - ind.t1 ; + uint32_t pnf_proc_time = ind.t3 - ind.t2; + + // divide by 2 using shift operator + uint32_t latency = (tx_2_rx - pnf_proc_time) >> 1; + + if(!(phy->filtered_adjust)) + { + phy->latency[phy->min_sync_cycle_count] = latency; + + NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%4d/%d) PNF to VNF !sync phy_id:%d (t1/2/3/4:%8u, %8u, %8u, %8u) txrx:%4u procT:%3u latency(us):%4d\n", + NFAPI_SFNSF2SFN(phy->sfn_sf), NFAPI_SFNSF2SF(phy->sfn_sf), ind.header.phy_id, ind.t1, ind.t2, ind.t3, t4, + tx_2_rx, pnf_proc_time, latency); + } + else + { + phy->latency[phy->min_sync_cycle_count] = latency; + + //if(phy->min_sync_cycle_count != SYNC_CYCLE_COUNT) + { + if (ind.t2 < phy->previous_t2 && ind.t1 > phy->previous_t1) + { + // Only t2 wrap has occurred!!! + phy->sf_offset = (NFAPI_MAX_SFNSFDEC + ind.t2) - ind.t1 - latency; + } + else if (ind.t2 > phy->previous_t2 && ind.t1 < phy->previous_t1) + { + // Only t1 wrap has occurred + phy->sf_offset = ind.t2 - ( ind.t1 + NFAPI_MAX_SFNSFDEC) - latency; + } + else + { + // Either no wrap or both have wrapped + phy->sf_offset = ind.t2 - ind.t1 - latency; + } + + if (phy->sf_offset_filtered == 0) + { + phy->sf_offset_filtered = phy->sf_offset; + } + else + { + int32_t oldFilteredValueShifted = phy->sf_offset_filtered << 5; + int32_t newOffsetShifted = phy->sf_offset << 5; + + // 1/8 of new and 7/8 of old + phy->sf_offset_filtered = ((newOffsetShifted >> 3) + ((oldFilteredValueShifted * 7) >> 3)) >> 5; + } + } + + if(1) + { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + + NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%4d/%1d) %d.%d PNF to VNF phy_id:%2d (t1/2/3/4:%8u, %8u, %8u, %8u) txrx:%4u procT:%3u latency(us):%4d(avg:%4d) offset(us):%8d filtered(us):%8d wrap[t1:%u t2:%u]\n", + NFAPI_SFNSF2SFN(phy->sfn_sf), NFAPI_SFNSF2SF(phy->sfn_sf), ts.tv_sec, ts.tv_nsec, ind.header.phy_id, + ind.t1, ind.t2, ind.t3, t4, + tx_2_rx, pnf_proc_time, latency, phy->average_latency, phy->sf_offset, phy->sf_offset_filtered, + (ind.t1previous_t1), (ind.t2previous_t2)); + } + + } + + if (phy->filtered_adjust && (phy->sf_offset_filtered > 1e6 || phy->sf_offset_filtered < -1e6)) + { + phy->filtered_adjust = 0; + phy->zero_count=0; + phy->min_sync_cycle_count = 2; + phy->in_sync = 0; + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s - ADJUST TOO BAD - go out of filtered phy->sf_offset_filtered:%d\n", __FUNCTION__, phy->sf_offset_filtered); + } + + if(phy->min_sync_cycle_count) + phy->min_sync_cycle_count--; + + if(phy->min_sync_cycle_count == 0) + { + uint32_t curr_sfn_sf = phy->sfn_sf; + int32_t sfn_sf_dec = NFAPI_SFNSF2DEC(phy->sfn_sf); + + if(!phy->filtered_adjust) + { + int i = 0; + //phy->average_latency = 0; + for(i = 0; i < SYNC_CYCLE_COUNT; ++i) + { + phy->average_latency += phy->latency[i]; + + } + phy->average_latency /= SYNC_CYCLE_COUNT; + + phy->sf_offset = ind.t2 - (ind.t1 - phy->average_latency); + + sfn_sf_dec += (phy->sf_offset / 1000); + } + else + { + sfn_sf_dec += ((phy->sf_offset_filtered + 500) / 1000); //Round up go from microsecond to subframe(1ms) + } + + if(sfn_sf_dec < 0) + { + sfn_sf_dec += NFAPI_MAX_SFNSFDEC; + } + else if( sfn_sf_dec >= NFAPI_MAX_SFNSFDEC) + { + sfn_sf_dec -= NFAPI_MAX_SFNSFDEC; + } + + uint16_t new_sfn_sf = NFAPI_SFNSFDEC2SFNSF(sfn_sf_dec); + + + { + phy->adjustment = NFAPI_SFNSF2DEC(new_sfn_sf) - NFAPI_SFNSF2DEC(curr_sfn_sf); + + NFAPI_TRACE(NFAPI_TRACE_NOTE, "PNF to VNF phy_id:%d adjustment%d phy->previous_sf_offset_filtered:%d phy->previous_sf_offset_filtered:%d phy->sf_offset_trend:%d\n", ind.header.phy_id, phy->adjustment, phy->previous_sf_offset_filtered, phy->previous_sf_offset_filtered, phy->sf_offset_trend); + + phy->previous_t1 = 0; + phy->previous_t2 = 0; + + if(phy->previous_sf_offset_filtered > 0) + { + if( phy->sf_offset_filtered > phy->previous_sf_offset_filtered) + { + // pnf is getting futher ahead of vnf + //phy->sf_offset_trend = phy->sf_offset_filtered - phy->previous_sf_offset_filtered; + phy->sf_offset_trend = (phy->sf_offset_filtered + phy->previous_sf_offset_filtered)/2; + } + else + { + // pnf is getting back in sync + } + } + else if(phy->previous_sf_offset_filtered < 0) + { + if(phy->sf_offset_filtered < phy->previous_sf_offset_filtered) + { + // vnf is getting future ahead of pnf + //phy->sf_offset_trend = -(phy->sf_offset_filtered - phy->previous_sf_offset_filtered); + phy->sf_offset_trend = (-(phy->sf_offset_filtered + phy->previous_sf_offset_filtered)) /2; + } + else + { + // vnf is getting back in sync + } + } + + + int insync_minor_adjustment_1 = phy->sf_offset_trend / 6; + int insync_minor_adjustment_2 = phy->sf_offset_trend / 2; + + + if(insync_minor_adjustment_1 == 0) + insync_minor_adjustment_1 = 2; + + if(insync_minor_adjustment_2 == 0) + insync_minor_adjustment_2 = 10; + + if(!phy->filtered_adjust) + { + if(phy->adjustment < 10) + { + phy->zero_count++; + + if(phy->zero_count >= 10) + { + phy->filtered_adjust = 1; + phy->zero_count = 0; + + NFAPI_TRACE(NFAPI_TRACE_NOTE, "***** Adjusting VNF SFN/SF switching to filtered mode\n"); + } + } + else + { + phy->zero_count = 0; + } + } + else + { + // Fine level of adjustment + if (phy->adjustment == 0) + { + if (phy->zero_count >= 10) + { + if(phy->in_sync == 0) + { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "VNF P7 In Sync with phy (phy_id:%d)\n", phy->phy_id); + + if(vnf_p7->_public.sync_indication) + (vnf_p7->_public.sync_indication)(&(vnf_p7->_public), 1); + } + + phy->in_sync = 1; + } + else + { + phy->zero_count++; + } + + if(phy->in_sync) + { + // in sync + if(phy->sf_offset_filtered > 250) + { + // VNF is slow + phy->insync_minor_adjustment = insync_minor_adjustment_1; //25; + phy->insync_minor_adjustment_duration = ((phy->sf_offset_filtered) / insync_minor_adjustment_1); + } + else if(phy->sf_offset_filtered < -250) + { + // VNF is fast + phy->insync_minor_adjustment = -(insync_minor_adjustment_1); //25; + phy->insync_minor_adjustment_duration = (((phy->sf_offset_filtered) / -(insync_minor_adjustment_1))); + } + else + { + phy->insync_minor_adjustment = 0; + } + + if(phy->insync_minor_adjustment != 0) + { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%4d/%d) VNF phy_id:%d Apply minor insync adjustment %dus for %d subframes (sf_offset_filtered:%d) %d %d %d NEW:%d CURR:%d adjustment:%d\n", + NFAPI_SFNSF2SFN(phy->sfn_sf), NFAPI_SFNSF2SF(phy->sfn_sf), ind.header.phy_id, + phy->insync_minor_adjustment, phy->insync_minor_adjustment_duration, + phy->sf_offset_filtered, + insync_minor_adjustment_1, insync_minor_adjustment_2, phy->sf_offset_trend, + NFAPI_SFNSF2DEC(new_sfn_sf), + NFAPI_SFNSF2DEC(curr_sfn_sf), + phy->adjustment); + } + } + } + else + { + if (phy->in_sync) + { + if(phy->adjustment == 0) + { + } + else if(phy->adjustment > 0) + { + // VNF is slow + //if(phy->adjustment == 1) + { + // + if(phy->sf_offset_filtered > 250) + { + // VNF is slow + phy->insync_minor_adjustment = insync_minor_adjustment_2; + phy->insync_minor_adjustment_duration = 2 * ((phy->sf_offset_filtered - 250) / insync_minor_adjustment_2); + } + else if(phy->sf_offset_filtered < -250) + { + // VNF is fast + phy->insync_minor_adjustment = -(insync_minor_adjustment_2); + phy->insync_minor_adjustment_duration = 2 * ((phy->sf_offset_filtered + 250) / -(insync_minor_adjustment_2)); + } + + } + //else + { + // out of sync? + } + + NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%4d/%d) VNF phy_id:%d Apply minor insync adjustment %dus for %d subframes (adjustment:%d sf_offset_filtered:%d) %d %d %d NEW:%d CURR:%d adj:%d\n", + NFAPI_SFNSF2SFN(phy->sfn_sf), NFAPI_SFNSF2SF(phy->sfn_sf), ind.header.phy_id, + phy->insync_minor_adjustment, phy->insync_minor_adjustment_duration, phy->adjustment, phy->sf_offset_filtered, + insync_minor_adjustment_1, insync_minor_adjustment_2, phy->sf_offset_trend, + NFAPI_SFNSF2DEC(new_sfn_sf), + NFAPI_SFNSF2DEC(curr_sfn_sf), + phy->adjustment); + + } + else if(phy->adjustment < 0) + { + // VNF is fast + //if(phy->adjustment == -1) + { + // + if(phy->sf_offset_filtered > 250) + { + // VNF is slow + phy->insync_minor_adjustment = insync_minor_adjustment_2; + phy->insync_minor_adjustment_duration = 2 * ((phy->sf_offset_filtered - 250) / insync_minor_adjustment_2); + } + else if(phy->sf_offset_filtered < -250) + { + // VNF is fast + phy->insync_minor_adjustment = -(insync_minor_adjustment_2); + phy->insync_minor_adjustment_duration = 2 * ((phy->sf_offset_filtered + 250) / -(insync_minor_adjustment_2)); + } + } + //else + { + // out of sync? + } + + NFAPI_TRACE(NFAPI_TRACE_NOTE, "(%d/%d) VNF phy_id:%d Apply minor insync adjustment %dus for %d subframes (adjustment:%d sf_offset_filtered:%d) %d %d %d\n", + NFAPI_SFNSF2SFN(phy->sfn_sf), NFAPI_SFNSF2SF(phy->sfn_sf), ind.header.phy_id, + phy->insync_minor_adjustment, phy->insync_minor_adjustment_duration, phy->adjustment, phy->sf_offset_filtered, + insync_minor_adjustment_1, insync_minor_adjustment_2, phy->sf_offset_trend); + } + + /* + if (phy->adjustment > 10 || phy->adjustment < -10) + { + phy->zero_count++; // Add one to the getting out of sync counter + } + else + { + phy->zero_count = 0; // Small error - zero the out of sync counter + } + + if (phy->zero_count >= 10) // If we have had 10 consecutive large errors - drop out of sync + { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "we have fallen out of sync...\n"); + //pP7SockInfo->syncAchieved = 0; + } + */ + } + } + } + + + if(phy->in_sync == 0) + { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "***** Adjusting VNF phy_id:%d SFN/SF (%s) from %d to %d (%d) mode:%s zeroCount:%u sync:%s\n", + ind.header.phy_id, (phy->in_sync ? "via sfn" : "now"), + NFAPI_SFNSF2DEC(curr_sfn_sf), NFAPI_SFNSF2DEC(new_sfn_sf), phy->adjustment, + phy->filtered_adjust ? "FILTERED" : "ABSOLUTE", + phy->zero_count, + phy->in_sync ? "IN_SYNC" : "OUT_OF_SYNC"); + + phy->sfn_sf = new_sfn_sf; + } + } + + // reset for next cycle + phy->previous_sf_offset_filtered = phy->sf_offset_filtered; + phy->min_sync_cycle_count = 2; + phy->sf_offset_filtered = 0; + phy->sf_offset = 0; + } + else + { + phy->previous_t1 = ind.t1; + phy->previous_t2 = ind.t2; + } +} + +void vnf_handle_timing_info(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +{ + if (pRecvMsg == NULL || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "vnf_handle_timing_info: NULL parameters\n"); + return; + } + + nfapi_timing_info_t ind; + if(nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(nfapi_timing_info_t), &vnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to unpack timing_info\n"); + return; + } + + if (vnf_p7 && vnf_p7->p7_connections) + { + int16_t vnf_pnf_sfnsf_delta = NFAPI_SFNSF2DEC(vnf_p7->p7_connections[0].sfn_sf) - NFAPI_SFNSF2DEC(ind.last_sfn_sf); + + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() PNF:SFN/SF:%d VNF:SFN/SF:%d deltaSFNSF:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind.last_sfn_sf), NFAPI_SFNSF2DEC(vnf_p7->p7_connections[0].sfn_sf), vnf_pnf_sfnsf_delta); + if (vnf_pnf_sfnsf_delta>1 || vnf_pnf_sfnsf_delta < -1) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() LARGE SFN/SF DELTA between PNF and VNF delta:%d VNF:%d PNF:%d\n\n\n\n\n\n\n\n\n", __FUNCTION__, vnf_pnf_sfnsf_delta, NFAPI_SFNSF2DEC(vnf_p7->p7_connections[0].sfn_sf), NFAPI_SFNSF2DEC(ind.last_sfn_sf)); + } + } +} + +void vnf_dispatch_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +{ + nfapi_p7_message_header_t header; + + // validate the input params + if(pRecvMsg == NULL || recvMsgLen < 4 || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return; + } + + // unpack the message header + if (nfapi_p7_message_header_unpack(pRecvMsg, recvMsgLen, &header, sizeof(header), &vnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); + return; + } + + // ensure the message is sensible + if (recvMsgLen < 8 || pRecvMsg == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_WARN, "Invalid message size: %d, ignoring\n", recvMsgLen); + return; + } + + switch (header.message_id) + { + case NFAPI_UL_NODE_SYNC: + vnf_handle_ul_node_sync(pRecvMsg, recvMsgLen, vnf_p7); + break; + + case NFAPI_TIMING_INFO: + vnf_handle_timing_info(pRecvMsg, recvMsgLen, vnf_p7); + break; + + case NFAPI_HARQ_INDICATION: + vnf_handle_harq_indication(pRecvMsg, recvMsgLen, vnf_p7); + break; + + case NFAPI_CRC_INDICATION: + vnf_handle_crc_indication(pRecvMsg, recvMsgLen, vnf_p7); + break; + + case NFAPI_RX_ULSCH_INDICATION: + vnf_handle_rx_ulsch_indication(pRecvMsg, recvMsgLen, vnf_p7); + break; + + case NFAPI_RACH_INDICATION: + vnf_handle_rach_indication(pRecvMsg, recvMsgLen, vnf_p7); + break; + + case NFAPI_SRS_INDICATION: + vnf_handle_srs_indication(pRecvMsg, recvMsgLen, vnf_p7); + break; + + case NFAPI_RX_SR_INDICATION: + vnf_handle_rx_sr_indication(pRecvMsg, recvMsgLen, vnf_p7); + break; + + case NFAPI_RX_CQI_INDICATION: + vnf_handle_rx_cqi_indication(pRecvMsg, recvMsgLen, vnf_p7); + break; + + case NFAPI_LBT_DL_INDICATION: + vnf_handle_lbt_dl_indication(pRecvMsg, recvMsgLen, vnf_p7); + break; + + case NFAPI_NB_HARQ_INDICATION: + vnf_handle_nb_harq_indication(pRecvMsg, recvMsgLen, vnf_p7); + break; + + case NFAPI_NRACH_INDICATION: + vnf_handle_nrach_indication(pRecvMsg, recvMsgLen, vnf_p7); + break; + + default: + { + if(header.message_id >= NFAPI_VENDOR_EXT_MSG_MIN && + header.message_id <= NFAPI_VENDOR_EXT_MSG_MAX) + { + vnf_handle_p7_vendor_extension(pRecvMsg, recvMsgLen, vnf_p7, header.message_id); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 Unknown message ID %d\n", header.message_id); + } + } + break; + } +} + +void vnf_handle_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +{ + nfapi_p7_message_header_t messageHeader; + + // validate the input params + if(pRecvMsg == NULL || recvMsgLen < 4 || vnf_p7 == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "vnf_handle_p7_message: invalid input params (%d %d %d)\n", pRecvMsg, recvMsgLen, vnf_p7); + return; + } + + // unpack the message header + if (nfapi_p7_message_header_unpack(pRecvMsg, recvMsgLen, &messageHeader, sizeof(nfapi_p7_message_header_t), &vnf_p7->_public.codec_config) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); + return; + } + + if(vnf_p7->_public.checksum_enabled) + { + uint32_t checksum = nfapi_p7_calculate_checksum(pRecvMsg, recvMsgLen); + if(checksum != messageHeader.checksum) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Checksum verification failed %d %d msg:%d len:%d\n", checksum, messageHeader.checksum, messageHeader.message_id, recvMsgLen); + return; + } + } + + uint8_t m = NFAPI_P7_GET_MORE(messageHeader.m_segment_sequence); + uint8_t segment_num = NFAPI_P7_GET_SEGMENT(messageHeader.m_segment_sequence); + uint8_t sequence_num = NFAPI_P7_GET_SEQUENCE(messageHeader.m_segment_sequence); + + + if(m == 0 && segment_num == 0) + { + // we have a complete message + // ensure the message is sensible + if (recvMsgLen < 8 || pRecvMsg == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_WARN, "Invalid message size: %d, ignoring\n", recvMsgLen); + return; + } + + //vnf_dispatch_p7_message(&messageHeader, pRecvMsg, recvMsgLen, vnf_p7); + vnf_dispatch_p7_message(pRecvMsg, recvMsgLen, vnf_p7); + } + else + { + nfapi_vnf_p7_connection_info_t* phy = vnf_p7_connection_info_list_find(vnf_p7, messageHeader.phy_id); + + if(phy) + { + vnf_p7_rx_message_t* rx_msg = vnf_p7_rx_reassembly_queue_add_segment(vnf_p7, &(phy->reassembly_queue), sequence_num, segment_num, m, pRecvMsg, recvMsgLen); + + if(rx_msg->num_segments_received == rx_msg->num_segments_expected) + { + // send the buffer on + uint16_t i = 0; + uint16_t length = 0; + for(i = 0; i < rx_msg->num_segments_expected; ++i) + { + length += rx_msg->segments[i].length - (i > 0 ? NFAPI_P7_HEADER_LENGTH : 0); + } + + if(phy->reassembly_buffer_size < length) + { + vnf_p7_free(vnf_p7, phy->reassembly_buffer); + phy->reassembly_buffer = 0; + } + + if(phy->reassembly_buffer == 0) + { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "Resizing VNF_P7 Reassembly buffer %d->%d\n", phy->reassembly_buffer_size, length); + phy->reassembly_buffer = (uint8_t*)vnf_p7_malloc(vnf_p7, length); + + if(phy->reassembly_buffer == 0) + { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "Failed to allocate VNF_P7 reassemby buffer len:%d\n", length); + return; + } + + phy->reassembly_buffer_size = length; + } + + uint16_t offset = 0; + for(i = 0; i < rx_msg->num_segments_expected; ++i) + { + if(i == 0) + { + memcpy(phy->reassembly_buffer, rx_msg->segments[i].buffer, rx_msg->segments[i].length); + offset += rx_msg->segments[i].length; + } + else + { + memcpy(phy->reassembly_buffer + offset, rx_msg->segments[i].buffer + NFAPI_P7_HEADER_LENGTH, rx_msg->segments[i].length - NFAPI_P7_HEADER_LENGTH); + offset += rx_msg->segments[i].length - NFAPI_P7_HEADER_LENGTH; + } + } + + + //pnf_dispatch_p7_message(pnf_p7->reassemby_buffer, length, pnf_p7, rx_msg->rx_hr_time); + vnf_dispatch_p7_message(phy->reassembly_buffer, length , vnf_p7); + + + // delete the structure + vnf_p7_rx_reassembly_queue_remove_msg(vnf_p7, &(phy->reassembly_queue), rx_msg); + } + + vnf_p7_rx_reassembly_queue_remove_old_msgs(vnf_p7, &(phy->reassembly_queue), 1000); + } + else + { + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Unknown phy id %d\n", messageHeader.phy_id); + } + } +} + +int vnf_p7_read_dispatch_message(vnf_p7_t* vnf_p7) +{ + int recvfrom_result = 0; + struct sockaddr_in remote_addr; + socklen_t remote_addr_size = sizeof(remote_addr); + + do + { + // peek the header + uint8_t header_buffer[NFAPI_P7_HEADER_LENGTH]; + recvfrom_result = recvfrom(vnf_p7->socket, header_buffer, NFAPI_P7_HEADER_LENGTH, MSG_DONTWAIT | MSG_PEEK, (struct sockaddr*)&remote_addr, &remote_addr_size); + + if(recvfrom_result > 0) + { + // get the segment size + nfapi_p7_message_header_t header; + if(nfapi_p7_message_header_unpack(header_buffer, NFAPI_P7_HEADER_LENGTH, &header, sizeof(header), 0) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); + return -1; + } + + // resize the buffer if we have a large segment + if(header.message_length > vnf_p7->rx_message_buffer_size) + { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "reallocing rx buffer %d\n", header.message_length); + vnf_p7->rx_message_buffer = realloc(vnf_p7->rx_message_buffer, header.message_length); + vnf_p7->rx_message_buffer_size = header.message_length; + } + + // read the segment + recvfrom_result = recvfrom(vnf_p7->socket, vnf_p7->rx_message_buffer, header.message_length, MSG_WAITALL, (struct sockaddr*)&remote_addr, &remote_addr_size); + + // todo : how to handle incomplete readfroms, need some sort of buffer/select + + if(recvfrom_result == 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "recvfrom returned 0\n"); + } + else if(recvfrom_result != header.message_length) + { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "did not receive the entire message %d %d\n", recvfrom_result, header.message_length); + + recvfrom_result += recvfrom(vnf_p7->socket, &vnf_p7->rx_message_buffer[recvfrom_result], header.message_length - recvfrom_result, MSG_WAITALL, (struct sockaddr*)&remote_addr, &remote_addr_size); + + } + + + if(recvfrom_result > 0) + { + vnf_handle_p7_message(vnf_p7->rx_message_buffer, recvfrom_result, vnf_p7); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "recvfrom failed %d %d\n", recvfrom_result, errno); + } + } + + if(recvfrom_result == -1) + { + if(errno == EAGAIN || errno == EWOULDBLOCK) + { + // return to the select + //NFAPI_TRACE(NFAPI_TRACE_WARN, "%s recvfrom would block :%d\n", __FUNCTION__, errno); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_WARN, "%s recvfrom failed errno:%d\n", __FUNCTION__, errno); + } + } + } + while(recvfrom_result > 0); + + return 0; +} + +void vnf_p7_release_msg(vnf_p7_t* vnf_p7, nfapi_p7_message_header_t* header) +{ + switch(header->message_id) + { + case NFAPI_HARQ_INDICATION: + { + vnf_p7_codec_free(vnf_p7, ((nfapi_harq_indication_t*)(header))->harq_indication_body.harq_pdu_list); + } + break; + case NFAPI_CRC_INDICATION: + { + vnf_p7_codec_free(vnf_p7, ((nfapi_crc_indication_t*)(header))->crc_indication_body.crc_pdu_list); + } + break; + case NFAPI_RX_ULSCH_INDICATION: + { + nfapi_rx_indication_t* rx_ind = (nfapi_rx_indication_t*)(header); + uint16_t i = 0; + for(i = 0; i < rx_ind->rx_indication_body.number_of_pdus; ++i) + { + vnf_p7_codec_free(vnf_p7, rx_ind->rx_indication_body.rx_pdu_list[i].data); + } + + vnf_p7_codec_free(vnf_p7, rx_ind->rx_indication_body.rx_pdu_list); + } + break; + case NFAPI_RACH_INDICATION: + { + vnf_p7_codec_free(vnf_p7, ((nfapi_rach_indication_t*)(header))->rach_indication_body.preamble_list); + } + break; + case NFAPI_SRS_INDICATION: + { + vnf_p7_codec_free(vnf_p7, ((nfapi_srs_indication_t*)(header))->srs_indication_body.srs_pdu_list); + } + break; + case NFAPI_RX_SR_INDICATION: + { + vnf_p7_codec_free(vnf_p7, ((nfapi_sr_indication_t*)(header))->sr_indication_body.sr_pdu_list); + } + break; + case NFAPI_RX_CQI_INDICATION: + { + vnf_p7_codec_free(vnf_p7, ((nfapi_cqi_indication_t*)(header))->cqi_indication_body.cqi_pdu_list); + vnf_p7_codec_free(vnf_p7, ((nfapi_cqi_indication_t*)(header))->cqi_indication_body.cqi_raw_pdu_list); + } + break; + } + + vnf_p7_free(vnf_p7, header); + +} + +void vnf_p7_release_pdu(vnf_p7_t* vnf_p7, void* pdu) +{ + vnf_p7_free(vnf_p7, pdu); +} + diff --git a/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c b/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c new file mode 100644 index 0000000000..a35d8e3c1d --- /dev/null +++ b/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c @@ -0,0 +1,562 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vnf_p7.h" + +#define FAPI2_IP_DSCP 0 + +nfapi_vnf_p7_config_t* nfapi_vnf_p7_config_create() +{ + vnf_p7_t* _this = (vnf_p7_t*)calloc(1, sizeof(vnf_p7_t)); + + if(_this == 0) + return 0; + + // todo : initialize + _this->_public.segment_size = 1400; + _this->_public.max_num_segments = 8; + _this->_public.checksum_enabled = 1; + + _this->_public.malloc = &malloc; + _this->_public.free = &free; + + _this->_public.codec_config.allocate = &malloc; + _this->_public.codec_config.deallocate = &free; + + + return &(_this->_public); +} + +void nfapi_vnf_p7_config_destory(nfapi_vnf_p7_config_t* config) +{ + free(config); +} + + +struct timespec timespec_add(struct timespec lhs, struct timespec rhs) +{ + struct timespec result; + + result.tv_sec = lhs.tv_sec + rhs.tv_sec; + result.tv_nsec = lhs.tv_nsec + rhs.tv_nsec; + + if(result.tv_nsec > 1e9) + { + result.tv_sec++; + result.tv_nsec-= 1e9; + } + + return result; +} + +struct timespec timespec_sub(struct timespec lhs, struct timespec rhs) +{ + struct timespec result; + if ((lhs.tv_nsec-rhs.tv_nsec)<0) + { + result.tv_sec = lhs.tv_sec-rhs.tv_sec-1; + result.tv_nsec = 1000000000+lhs.tv_nsec-rhs.tv_nsec; + } + else + { + result.tv_sec = lhs.tv_sec-rhs.tv_sec; + result.tv_nsec = lhs.tv_nsec-rhs.tv_nsec; + } + return result; +} + +// monitor the p7 endpoints and the timing loop and +// send indications to mac +int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config) +{ + if(config == 0) + return -1; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__); + + vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; + + // Create p7 receive udp port + // todo : this needs updating for Ipv6 + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Initialising VNF P7 port:%u\n", config->port); + + // open the UDP socket + if ((vnf_p7->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P7 socket errno: %d\n", errno); + return -1; + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 socket created...\n"); + + // configure the UDP socket options + int iptos_value = FAPI2_IP_DSCP << 2; + if (setsockopt(vnf_p7->socket, IPPROTO_IP, IP_TOS, &iptos_value, sizeof(iptos_value)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (IP_TOS) errno: %d\n", errno); + return -1; + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 setsockopt succeeded...\n"); + + // Create the address structure + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(config->port); + addr.sin_addr.s_addr = INADDR_ANY; + + // bind to the configured port + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 binding too %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + if (bind(vnf_p7->socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) + //if (sctp_bindx(config->socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in), 0) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After bind errno: %d\n", errno); + return -1; + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 bind succeeded...\n"); + + + //struct timespec original_pselect_timeout; + struct timespec pselect_timeout; + pselect_timeout.tv_sec = 0; + pselect_timeout.tv_nsec = 1000000; // ns in a 1 us + + + struct timespec pselect_start; + struct timespec pselect_stop; + + //struct timespec sf_end; + + long last_millisecond = -1; + + + struct timespec sf_duration; + sf_duration.tv_sec = 0; + sf_duration.tv_nsec = 1e6; // We want 1ms pause + + struct timespec sf_start; + clock_gettime(CLOCK_MONOTONIC, &sf_start); + long millisecond = sf_start.tv_nsec / 1e6; + sf_start = timespec_add(sf_start, sf_duration); + NFAPI_TRACE(NFAPI_TRACE_INFO, "next subframe will start at %d.%d\n", sf_start.tv_sec, sf_start.tv_nsec); + + while(vnf_p7->terminate == 0) + { + fd_set rfds; + int maxSock = 0; + FD_ZERO(&rfds); + int selectRetval = 0; + + // Add the p7 socket + FD_SET(vnf_p7->socket, &rfds); + maxSock = vnf_p7->socket; + + clock_gettime(CLOCK_MONOTONIC, &pselect_start); + //long millisecond = pselect_start.tv_nsec / 1e6; + + if((last_millisecond == -1) || (millisecond == last_millisecond) || (millisecond == (last_millisecond + 1) % 1000) ) + { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "pselect_start:%d.%d sf_start:%d.%d\n", pselect_start.tv_sec, pselect_start.tv_nsec, sf_start.tv_sec, sf_start.tv_nsec); + + + if((pselect_start.tv_sec > sf_start.tv_sec) || + ((pselect_start.tv_sec == sf_start.tv_sec) && (pselect_start.tv_nsec > sf_start.tv_nsec))) + { + // overran the end of the subframe we do not want to wait + pselect_timeout.tv_sec = 0; + pselect_timeout.tv_nsec = 0; + + //struct timespec overrun = timespec_sub(pselect_start, sf_start); + //NFAPI_TRACE(NFAPI_TRACE_INFO, "Subframe overrun detected of %d.%d running to catchup\n", overrun.tv_sec, overrun.tv_nsec); + } + else + { + // still time before the end of the subframe wait + pselect_timeout = timespec_sub(sf_start, pselect_start); + +#if 0 + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() sf_start:%d.%ld pselect_start:%d.%ld pseclect_timeout:%d.%ld\n", + __FUNCTION__, + sf_start.tv_sec, sf_start.tv_nsec, + pselect_start.tv_sec, pselect_start.tv_nsec, + pselect_timeout.tv_sec, pselect_timeout.tv_nsec); +#endif + } + +//original_pselect_timeout = pselect_timeout; + + // detemine how long to sleep in ns before the start of the next 1ms + //pselect_timeout.tv_nsec = 1e6 - (pselect_start.tv_nsec % 1000000); + + //uint8_t underrun_possible =0; + + // if we are not sleeping until the next milisecond due to the + // insycn minor adjment flag it so we don't consider it an error + //uint8_t underrun_possible =0; + /* + { + nfapi_vnf_p7_connection_info_t* phy = vnf_p7->p7_connections; + if(phy && phy->in_sync && phy->insync_minor_adjustment != 0 && phy->insync_minor_adjustment_duration > 0 && pselect_start.tv_nsec != 0) + { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "[VNF] Subframe minor adjustment %d (%d->%d)\n", phy->insync_minor_adjustment, + pselect_timeout.tv_nsec, pselect_timeout.tv_nsec - (phy->insync_minor_adjustment * 1000)) + if(phy->insync_minor_adjustment > 0) + { + // todo check we don't go below 0 + if((phy->insync_minor_adjustment * 1000) > pselect_timeout.tv_nsec) + pselect_timeout.tv_nsec = 0; + else + pselect_timeout.tv_nsec = pselect_timeout.tv_nsec - (phy->insync_minor_adjustment * 1000); + + + //underrun_possible = 1; + } + else if(phy->insync_minor_adjustment < 0) + { + // todo check we don't go below 0 + pselect_timeout.tv_nsec = pselect_timeout.tv_nsec - (phy->insync_minor_adjustment * 1000); + } + + //phy->insync_minor_adjustment = 0; + phy->insync_minor_adjustment_duration--; + } + } + */ + + +//long wraps = pselect_timeout.tv_nsec % 1e9; + + + selectRetval = pselect(maxSock+1, &rfds, NULL, NULL, &pselect_timeout, NULL); + + clock_gettime(CLOCK_MONOTONIC, &pselect_stop); + + nfapi_vnf_p7_connection_info_t* phy = vnf_p7->p7_connections; + +if (selectRetval==-1 && errno == 22) +{ + NFAPI_TRACE(NFAPI_TRACE_ERROR, "INVAL: pselect_timeout:%d.%ld adj[dur:%d adj:%d], sf_dur:%d.%ld\n", + pselect_timeout.tv_sec, pselect_timeout.tv_nsec, + phy->insync_minor_adjustment_duration, phy->insync_minor_adjustment, + sf_duration.tv_sec, sf_duration.tv_nsec); +} +#if 0 + if (selectRetval != 0 || phy->insync_minor_adjustment_duration != 0) + NFAPI_TRACE(NFAPI_TRACE_NOTE, "pselect()=%d maxSock:%d vnf_p7->socket:%d pselect_timeout:%u.%u original_pselect_timeout:%u.%u\n", + selectRetval, maxSock, vnf_p7->socket, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, + original_pselect_timeout.tv_sec, original_pselect_timeout.tv_nsec); +#endif + + if(selectRetval == 0) + { + // calculate the start of the next subframe + sf_start = timespec_add(sf_start, sf_duration); + //NFAPI_TRACE(NFAPI_TRACE_INFO, "next subframe will start at %d.%d\n", sf_start.tv_sec, sf_start.tv_nsec); + + if(phy && phy->in_sync && phy->insync_minor_adjustment != 0 && phy->insync_minor_adjustment_duration > 0) + { + long insync_minor_adjustment_ns = (phy->insync_minor_adjustment * 1000); + + sf_start.tv_nsec -= insync_minor_adjustment_ns; + +#if 1 + if (sf_start.tv_nsec > 1e9) + { + sf_start.tv_sec++; + sf_start.tv_nsec-=1e9; + } + else if (sf_start.tv_nsec < 0) + { + sf_start.tv_sec--; + sf_start.tv_nsec+=1e9; + } +#else + //NFAPI_TRACE(NFAPI_TRACE_NOTE, "[VNF] BEFORE adjustment - Subframe minor adjustment %dus sf_start.tv_nsec:%d\n", phy->insync_minor_adjustment, sf_start.tv_nsec); + if(phy->insync_minor_adjustment > 0) + { + // decrease the subframe duration a little + if (sf_start.tv_nsec > insync_minor_adjustment_ns) + sf_start.tv_nsec -= insync_minor_adjustment_ns; + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "[VNF] Adjustment would make it negative sf:%d.%ld adjust:%ld\n\n\n", sf_start.tv_sec, sf_start.tv_nsec, insync_minor_adjustment_ns); + sf_start.tv_sec--; + sf_start.tv_nsec += 1e9 - insync_minor_adjustment_ns; + } + } + else if(phy->insync_minor_adjustment < 0) + { + // todo check we don't go below 0 + // increase the subframe duration a little + sf_start.tv_nsec += insync_minor_adjustment_ns; + + if (sf_start.tv_nsec < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "[VNF] OVERFLOW %d.%ld\n\n\n\n", sf_start.tv_sec, sf_start.tv_nsec); + sf_start.tv_sec++; + sf_start.tv_nsec += 1e9; + } + } +#endif + + //phy->insync_minor_adjustment = 0; + phy->insync_minor_adjustment_duration--; + + NFAPI_TRACE(NFAPI_TRACE_NOTE, "[VNF] AFTER adjustment - Subframe minor adjustment %dus sf_start.tv_nsec:%d duration:%u\n", + phy->insync_minor_adjustment, sf_start.tv_nsec, phy->insync_minor_adjustment_duration); + + if (phy->insync_minor_adjustment_duration==0) + { + phy->insync_minor_adjustment = 0; + } + } + /* + long pselect_stop_millisecond = pselect_stop.tv_nsec / 1e6; + if(millisecond == pselect_stop_millisecond) + { + // we have woke up in the same subframe + if(underrun_possible == 0) + NFAPI_TRACE(NFAPI_TRACE_WARN, "subframe pselect underrun %ld (%d.%d)\n", millisecond, pselect_stop.tv_sec, pselect_stop.tv_nsec); + } + else if(((millisecond + 1) % 1000) != pselect_stop_millisecond) + { + // we have overrun the subframe + NFAPI_TRACE(NFAPI_TRACE_WARN, "subframe pselect overrun %ld %ld\n", millisecond, pselect_stop_millisecond); + NFAPI_TRACE(NFAPI_TRACE_WARN, "subframe underrun %ld\n", millisecond); + } + last_millisecond = millisecond; + */ + + millisecond ++; + } + } + else + { + // we have overrun the subframe advance to go and collect $200 + if((millisecond - last_millisecond) > 3) + NFAPI_TRACE(NFAPI_TRACE_WARN, "subframe overrun %ld %ld (%ld)\n", millisecond, last_millisecond, millisecond - last_millisecond + 1); + + last_millisecond = ( last_millisecond + 1 ) % 1000; + selectRetval = 0; + } + + if(selectRetval == 0) + { + vnf_p7->sf_start_time_hr = vnf_get_current_time_hr(); + + // pselect timed out + nfapi_vnf_p7_connection_info_t* curr = vnf_p7->p7_connections; + + while(curr != 0) + { + curr->sfn_sf = increment_sfn_sf(curr->sfn_sf); + + vnf_sync(vnf_p7, curr); + + curr = curr->next; + } + + send_mac_subframe_indications(vnf_p7); + + } + else if(selectRetval > 0) + { + // have a p7 message + if(FD_ISSET(vnf_p7->socket, &rfds)) + { + vnf_p7_read_dispatch_message(vnf_p7); + } + } + else + { + // pselect error + if(selectRetval == -1 && errno == EINTR) + { + // a sigal was received. + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "P7 select failed result %d errno %d timeout:%d.%d orginal:%d.%d last_ms:%ld ms:%ld\n", selectRetval, errno, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, last_millisecond, millisecond); + // should we exit now? + if (selectRetval == -1 && errno == 22) // invalid argument??? not sure about timeout duration + { + usleep(100000); + } + } + } + + } + + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Closing p7 socket\n"); + close(vnf_p7->socket); + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() returning\n", __FUNCTION__); + + return 0; +} + +int nfapi_vnf_p7_stop(nfapi_vnf_p7_config_t* config) +{ + if(config == 0) + return -1; + + vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; + vnf_p7->terminate =1; + return 0; +} + +int nfapi_vnf_p7_add_pnf(nfapi_vnf_p7_config_t* config, const char* pnf_p7_addr, int pnf_p7_port, int phy_id) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(config:%p phy_id:%d pnf_addr:%s pnf_p7_port:%d)\n", __FUNCTION__, config, phy_id, pnf_p7_addr, pnf_p7_port); + + if(config == 0) + { + return -1; + } + + vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; + + nfapi_vnf_p7_connection_info_t* node = (nfapi_vnf_p7_connection_info_t*)malloc(sizeof(nfapi_vnf_p7_connection_info_t)); + + memset(node, 0, sizeof(nfapi_vnf_p7_connection_info_t)); + node->phy_id = phy_id; + node->in_sync = 0; + node->dl_out_sync_offset = 30; + node->dl_out_sync_period = 10; + node->dl_in_sync_offset = 30; + node->dl_in_sync_period = 512; + node->sfn_sf = 0; + + node->min_sync_cycle_count = 8; + + // save the remote endpoint information + node->remote_addr.sin_family = AF_INET; + node->remote_addr.sin_port = htons(pnf_p7_port); + node->remote_addr.sin_addr.s_addr = inet_addr(pnf_p7_addr); + + vnf_p7_connection_info_list_add(vnf_p7, node); + + return 0; +} + +int nfapi_vnf_p7_del_pnf(nfapi_vnf_p7_config_t* config, int phy_id) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(phy_id:%d)\n", __FUNCTION__, phy_id); + + if(config == 0) + return -1; + + vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; + + nfapi_vnf_p7_connection_info_t* to_delete = vnf_p7_connection_info_list_delete(vnf_p7, phy_id); + + if(to_delete) + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(phy_id:%d) deleting connection info\n", __FUNCTION__, phy_id); + free(to_delete); + } + + return 0; +} +int nfapi_vnf_p7_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_dl_config_request_t* req) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(config:%p req:%p)\n", __FUNCTION__, config, req); + + if(config == 0 || req == 0) + return -1; + + vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; + return vnf_p7_pack_and_send_p7_msg(vnf_p7, &req->header); +} + +int nfapi_vnf_p7_ul_config_req(nfapi_vnf_p7_config_t* config, nfapi_ul_config_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; + return vnf_p7_pack_and_send_p7_msg(vnf_p7, &req->header); +} +int nfapi_vnf_p7_hi_dci0_req(nfapi_vnf_p7_config_t* config, nfapi_hi_dci0_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; + return vnf_p7_pack_and_send_p7_msg(vnf_p7, &req->header); +} +int nfapi_vnf_p7_tx_req(nfapi_vnf_p7_config_t* config, nfapi_tx_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; + return vnf_p7_pack_and_send_p7_msg(vnf_p7, &req->header); +} +int nfapi_vnf_p7_lbt_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_lbt_dl_config_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; + return vnf_p7_pack_and_send_p7_msg(vnf_p7, &req->header); +} +int nfapi_vnf_p7_vendor_extension(nfapi_vnf_p7_config_t* config, nfapi_p7_message_header_t* header) +{ + if(config == 0 || header == 0) + return -1; + + vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; + return vnf_p7_pack_and_send_p7_msg(vnf_p7, header); +} + + +int nfapi_vnf_p7_release_msg(nfapi_vnf_p7_config_t* config, nfapi_p7_message_header_t* header) +{ + if(config == 0 || header == 0) + return -1; + + vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; + vnf_p7_release_msg(vnf_p7, header); + + return 0; + +} + +int nfapi_vnf_p7_release_pdu(nfapi_vnf_p7_config_t* config, void* pdu) +{ + if(config == 0 || pdu == 0) + return -1; + + vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; + vnf_p7_release_pdu(vnf_p7, pdu); + + return 0; +} diff --git a/nfapi/open-nFAPI/vnf/tests/Makefile.am b/nfapi/open-nFAPI/vnf/tests/Makefile.am new file mode 100644 index 0000000000..0c8163102c --- /dev/null +++ b/nfapi/open-nFAPI/vnf/tests/Makefile.am @@ -0,0 +1,30 @@ +# +# Copyright 2017 Cisco Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +#vnf unit test +#AUTOMAKE_OPTIONS=subdir-objects + +AM_CPPFLAGS = -I$(top_srcdir)/nfapi/inc -I$(top_srcdir)/nfapi/public_inc -I$(top_srcdir)/common/public_inc -I$(top_srcdir)/vnf/public_inc $(CFLAGS_CUNIT) -Wall -Werror + +check_PROGRAMS= test_vnf + +test_vnf_SOURCES = vnf_cunit_main.c ../..//common/src/debug.c +test_vnf_LDADD=$(top_builddir)/vnf/libnfapi_vnf.a $(top_builddir)/nfapi/libnfapi.a -L$(libdir) -lpthread -lrt -lsctp -lz -lcunit + +LOG_DRIVER = $(top_srcdir)/tap-driver.sh +TESTS=test_vnf +EXTRA_DIST = $(TESTS) + diff --git a/nfapi/open-nFAPI/vnf/tests/vnf_cunit_main.c b/nfapi/open-nFAPI/vnf/tests/vnf_cunit_main.c new file mode 100644 index 0000000000..4df5da7c26 --- /dev/null +++ b/nfapi/open-nFAPI/vnf/tests/vnf_cunit_main.c @@ -0,0 +1,1497 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "CUnit.h" +#include "Basic.h" +#include "Automated.h" +//#include "CUnit/Console.h" + +#include "nfapi_interface.h" +#include "nfapi_vnf_interface.h" +#include "nfapi.h" +#include // for printf +#include +#include +#include +#include +#include +#include +#include +#include "debug.h" +#include +#include + +/* Test Suite setup and cleanup functions: */ + +int init_suite(void) { return 0; } +int clean_suite(void) { return 0; } + +#define MAX_PACKED_MESSAGE_SIZE 8192 + +#define SFNSF2SFN(_sfnsf) ((_sfnsf) >> 4) +#define SFNSF2SF(_sfnsf) ((_sfnsf) & 0xF) + +typedef struct +{ + uint8_t enabled; + uint8_t started; + uint16_t phy_id; + + int p7_rx_port; + char* p7_rx_addr; + + struct sockaddr_in p7_rx_sockaddr; + int p7_rx_sock; + + struct sockaddr_in p7_tx_sockaddr; + int p7_tx_sock; +} pnf_test_config_phy_t; + +typedef struct +{ + uint8_t enabled; + + char* vnf_p5_addr; + int vnf_p5_port; + + struct sockaddr_in p5_tx_sockaddr; + int p5_sock; + + int p7_rx_port_base; + + pnf_test_config_phy_t phys[4]; + +} pnf_test_config_t; + +pnf_test_config_t pnf_test_config[5]; + +typedef struct +{ + uint8_t enabled; + uint8_t state; + uint16_t p5_idx; + uint16_t phy_id; + + uint8_t vnf_idx; + //struct sockaddr_in p7_rx_sockaddr; + struct sockaddr_in p7_tx_sockaddr; + +} vnf_test_config_phy_t; + +typedef struct +{ + uint8_t enabled; + pthread_t thread; + + char* vnf_p7_addr; + int vnf_p7_port; + + struct sockaddr_in p7_rx_sockaddr; + + nfapi_vnf_p7_config_t* config; + + uint8_t max_phys; + uint8_t phy_count; + //uint8_t phy_ids[4]; + +} vnf_test_config_vnf_t; + +typedef struct +{ + char* p5_addr; + int p5_port; + + pthread_t thread; + + vnf_test_config_vnf_t vnfs[2]; + + uint8_t phy_count; + vnf_test_config_phy_t phys[5]; + + nfapi_vnf_config_t* p5_vnf_config; + +} vnf_test_config_t; + +vnf_test_config_t vnf_test_config[5]; + +void reset_test_configs() +{ + memset(&pnf_test_config, 0, sizeof(pnf_test_config)); + memset(&vnf_test_config, 0, sizeof(vnf_test_config)); +} + +void pnf_create_p5_sock(pnf_test_config_t* config) +{ + config->p5_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); + + config->p5_tx_sockaddr.sin_family = AF_INET; + config->p5_tx_sockaddr.sin_port = htons(config->vnf_p5_port); + config->p5_tx_sockaddr.sin_addr.s_addr = inet_addr(config->vnf_p5_addr); +} + +void pnf_p5_connect(pnf_test_config_t* config) +{ + int connect_result = connect(config->p5_sock, (struct sockaddr *)&config->p5_tx_sockaddr, sizeof(config->p5_tx_sockaddr) ); + + printf("connect_result %d %d\n", connect_result, errno); +} + +pnf_test_config_phy_t* find_pnf_phy_config(pnf_test_config_t* config, uint16_t phy_id) +{ + int i = 0; + for(i = 0; i < 4; ++i) + { + if(config->phys[i].phy_id == phy_id) + return &(config->phys[i]); + } + + return 0; +} + +vnf_test_config_phy_t* find_vnf_phy_config(vnf_test_config_t* config, uint16_t phy_id) +{ + int i = 0; + for(i = 0; i < 4; ++i) + { + if(config->phys[i].phy_id == phy_id) + return &(config->phys[i]); + } + + return 0; +} + + + + +/************* Test case functions ****************/ + + +void vnf_test_start_no_config(void) +{ + int result = nfapi_vnf_start(0); + CU_ASSERT_EQUAL(result, -1); +} + +void* vnf_test_start_thread(void* ptr) +{ + int result = nfapi_vnf_start((nfapi_vnf_config_t*)ptr); + return (void*)(intptr_t)result; +} + +int pnf_connection_indication_called = 0; +int pnf_connection_indication(nfapi_vnf_config_t* config, int p5_idx) +{ + printf("[VNF] pnf_connection_indication p5_idx:%d\n", p5_idx); + pnf_connection_indication_called++; + + nfapi_pnf_param_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PNF_PARAM_REQUEST; + req.header.message_length = 0; + + nfapi_vnf_pnf_param_req(config, p5_idx, &req); + + return 1; +} + +int pnf_disconnect_indication(nfapi_vnf_config_t* config, int p5_idx) +{ + printf("[VNF] pnf_disconnect_indication p5_idx:%d\n", p5_idx); + pnf_connection_indication_called++; + + vnf_test_config_t* test_config = (vnf_test_config_t*)(config->user_data); + printf("[VNF] pnf_disconnect_indication user_data %p\n", config->user_data); + + int i = 0; + for(i = 0; i < test_config->phy_count; ++i) + { + vnf_test_config_phy_t* phy = &test_config->phys[i]; + vnf_test_config_vnf_t* vnf = &test_config->vnfs[phy->p5_idx]; + + // need to send stop request/response + + nfapi_vnf_p7_del_pnf((vnf->config), phy->phy_id); + vnf->phy_count--; + } + + + for(i = 0; i < 2; ++i) + { + vnf_test_config_vnf_t* vnf = &test_config->vnfs[i]; + printf("[VNF] pnf_disconnect_indication phy_count:%d\n", vnf->phy_count); + if(vnf->enabled == 1) + { + nfapi_vnf_p7_stop(vnf->config); + //vnf->config->terminate = 1; + + int* result; + printf("[VNF] waiting for vnf p7 thread to exit\n"); + pthread_join((vnf->thread), (void**)&result); + CU_ASSERT_EQUAL(result, 0); + + vnf->enabled = 0; + } + } + + return 1; +} + +int send_p5_message(int p5Sock, nfapi_p4_p5_message_header_t* msg, unsigned msg_size, struct sockaddr_in* addr, socklen_t addr_size) +{ + char buffer[256]; + int encoded_size = nfapi_p5_message_pack(msg, msg_size, buffer, sizeof(buffer), 0); + int result = sendto(p5Sock, buffer, encoded_size, 0, (struct sockaddr*)addr, addr_size); + (void)result; + return 0; +} + +int recv_p5_message(int p5Sock, nfapi_p4_p5_message_header_t* msg, unsigned msg_size) +{ + struct sockaddr_in addr2; + socklen_t addr2len; + char buffer2[256]; + int result2 = recvfrom(p5Sock, buffer2, sizeof(buffer2), 0, (struct sockaddr*)&addr2, &addr2len); + + int unpack_result = nfapi_p5_message_unpack(buffer2, result2, msg, msg_size, 0); //, sizeof(resp)); + (void)unpack_result; + return 0; +} + +int send_pnf_param_response(pnf_test_config_t* config) //int p5Sock, struct sockaddr_in* addr, socklen_t addr_size) +{ + nfapi_pnf_param_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_PARAM_RESPONSE; + + resp.header.message_length = 0; + resp.error_code = NFAPI_MSG_OK; + + //send_p5_message(p5Sock, &resp, sizeof(resp), addr, addr_size); + send_p5_message(config->p5_sock, &resp.header, sizeof(resp), &(config->p5_tx_sockaddr), sizeof(config->p5_tx_sockaddr)); + return 0; +} + +int create_p7_rx_socket(const char* addr, int port) +{ + int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + struct sockaddr_in sock_addr; + sock_addr.sin_family = AF_INET; + sock_addr.sin_port = htons(port); + + if(addr == 0) + sock_addr.sin_addr.s_addr = INADDR_ANY; + else + sock_addr.sin_addr.s_addr = inet_addr(addr); + + int bind_result = bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); + if(bind_result != 0) + { + printf("Failed to bind p7 rx socket %d(%d) to %s:%d\n", bind_result, errno, addr, port); + } + + + return fd; +} + +int create_p7_tx_socket() +{ + int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + return fd; +} + +int send_param_response(pnf_test_config_t* config, uint16_t phy_id) +{ + nfapi_param_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PARAM_RESPONSE; + resp.header.phy_id = phy_id; + + pnf_test_config_phy_t* phy = find_pnf_phy_config(config, phy_id); + + resp.error_code = NFAPI_MSG_OK; + + resp.nfapi_config.p7_pnf_port.tl.tag = NFAPI_NFAPI_P7_PNF_PORT_TAG; + resp.nfapi_config.p7_pnf_port.value = phy->p7_rx_port; + + struct sockaddr_in pnf_p7_sockaddr; + pnf_p7_sockaddr.sin_addr.s_addr = inet_addr(phy->p7_rx_addr); + + resp.nfapi_config.p7_pnf_address_ipv4.tl.tag = NFAPI_NFAPI_P7_PNF_ADDRESS_IPV4_TAG; + memcpy(&resp.nfapi_config.p7_pnf_address_ipv4.address[0], &pnf_p7_sockaddr.sin_addr.s_addr, 4); + + send_p5_message(config->p5_sock, &resp.header, sizeof(resp), &(config->p5_tx_sockaddr), sizeof(config->p5_tx_sockaddr)); + return 0; +} + +int receive_pnf_param_request(pnf_test_config_t* config) +{ + nfapi_pnf_param_request_t req; + recv_p5_message(config->p5_sock, &req.header, sizeof(req)); + + CU_ASSERT_EQUAL(req.header.message_id, NFAPI_PNF_PARAM_REQUEST); + if(req.header.message_id == NFAPI_PNF_PARAM_REQUEST) + { + printf("[PNF] nfapi_pnf_param_request\n"); + } + return 0; +} + +int receive_param_request(pnf_test_config_t* config) +{ + nfapi_param_request_t req; + recv_p5_message(config->p5_sock, &req.header, sizeof(req)); + + CU_ASSERT_EQUAL(req.header.message_id, NFAPI_PARAM_REQUEST); + if(req.header.message_id == NFAPI_PARAM_REQUEST) + { + printf("[PNF] nfapi_param_request phy_id:%d\n", req.header.phy_id); + } + else + { + printf("[PNF] ERROR, unexpected message %d phy_id:%d\n", req.header.message_id, req.header.phy_id); + } + return req.header.phy_id; +} + +int send_pnf_config_response(pnf_test_config_t* config) +{ + nfapi_pnf_config_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_CONFIG_RESPONSE; + resp.header.message_length = 0; + resp.error_code = NFAPI_MSG_OK; + + send_p5_message(config->p5_sock, &resp.header, sizeof(resp), &(config->p5_tx_sockaddr), sizeof(config->p5_tx_sockaddr)); + return 0; +} + +int send_config_response(pnf_test_config_t* config, uint16_t phy_id) +{ + nfapi_config_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_CONFIG_RESPONSE; + resp.header.message_length = 0; + resp.header.phy_id = phy_id; + resp.error_code = NFAPI_MSG_OK; + + send_p5_message(config->p5_sock, &resp.header, sizeof(resp), &(config->p5_tx_sockaddr), sizeof(config->p5_tx_sockaddr)); + return 0; +} + + +int receive_pnf_config_request(pnf_test_config_t* config) +{ + nfapi_pnf_config_request_t req; + recv_p5_message(config->p5_sock, &req.header, sizeof(req)); + + CU_ASSERT_EQUAL(req.header.message_id, NFAPI_PNF_CONFIG_REQUEST); + if(req.header.message_id == NFAPI_PNF_CONFIG_REQUEST) + { + printf("decoded nfapi_pnf_config_request\n"); + + int i = 0; + for(i = 0; i < req.pnf_phy_rf_config.number_phy_rf_config_info; ++i) + { + nfapi_phy_rf_config_info_t* info = &(req.pnf_phy_rf_config.phy_rf_config[i]); + printf("adding pnf phy %d id %d\n", i, info->phy_id); + + config->phys[i].enabled = 1; + config->phys[i].phy_id = info->phy_id; + } + } + return 0; +} + +int receive_config_request(pnf_test_config_t* config) +{ + nfapi_config_request_t req; + recv_p5_message(config->p5_sock, &req.header, sizeof(req)); + + CU_ASSERT_EQUAL(req.header.message_id, NFAPI_CONFIG_REQUEST); + if(req.header.message_id == NFAPI_CONFIG_REQUEST) + { + printf("[PNF] nfapi_config_request phy_id:%d\n", req.header.phy_id); + + pnf_test_config_phy_t* phy = find_pnf_phy_config(config, req.header.phy_id); + + // todo verify that this is the same as a vnf config? + phy->p7_tx_sockaddr.sin_family = AF_INET; + phy->p7_tx_sockaddr.sin_port = htons(req.nfapi_config.p7_vnf_port.value); + memcpy(&phy->p7_tx_sockaddr.sin_addr.s_addr, &req.nfapi_config.p7_vnf_address_ipv4.address, 4); + phy->p7_tx_sock = create_p7_tx_socket(); + + + printf("[PNF] vnf p7 address %s:%d\n", inet_ntoa(phy->p7_tx_sockaddr.sin_addr), ntohs(phy->p7_tx_sockaddr.sin_port)); + + return req.header.phy_id; + } + + return NFAPI_PHY_ID_NA; +} + +int send_pnf_start_response(pnf_test_config_t* config) +{ + nfapi_pnf_start_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_START_RESPONSE; + resp.header.message_length = 0; + resp.error_code = NFAPI_MSG_OK; + + send_p5_message(config->p5_sock, &resp.header, sizeof(resp), &(config->p5_tx_sockaddr), sizeof(config->p5_tx_sockaddr)); + return 0; +} + +int send_start_response(pnf_test_config_t* config, uint16_t phy_id) +{ + nfapi_start_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_START_RESPONSE; + resp.header.message_length = 0; + resp.header.phy_id = phy_id; + resp.error_code = NFAPI_MSG_OK; + + send_p5_message(config->p5_sock, &resp.header, sizeof(resp), &(config->p5_tx_sockaddr), sizeof(config->p5_tx_sockaddr)); + return 0; +} + +int receive_pnf_start_request(pnf_test_config_t* config) +{ + nfapi_pnf_start_request_t req; + recv_p5_message(config->p5_sock, &req.header, sizeof(req)); + + CU_ASSERT_EQUAL(req.header.message_id, NFAPI_PNF_START_REQUEST); + if(req.header.message_id == NFAPI_PNF_START_REQUEST) + { + printf("decoded nfapi_pnf_start_request\n"); + + int phy_idx = 0; + for(phy_idx = 0; phy_idx < 4; ++phy_idx) + { + if(config->phys[phy_idx].enabled) + { + pnf_test_config_phy_t* phy = &(config->phys[phy_idx]); + phy->p7_rx_port = config->p7_rx_port_base + phy_idx; + phy->p7_rx_addr = "127.0.0.1"; + } + } + } + return 0; +} + +int receive_start_request(pnf_test_config_t* config) +{ + nfapi_start_request_t req; + recv_p5_message(config->p5_sock, &req.header, sizeof(req)); + + CU_ASSERT_EQUAL(req.header.message_id, NFAPI_START_REQUEST); + if(req.header.message_id == NFAPI_START_REQUEST) + { + printf("[PNF] nfapi_start_request\n"); + + pnf_test_config_phy_t* phy = find_pnf_phy_config(config, req.header.phy_id); + printf("[PNF] creating p7 rx socket %s:%d\n", phy->p7_rx_addr, phy->p7_rx_port); + phy->p7_rx_sock = create_p7_rx_socket(phy->p7_rx_addr, phy->p7_rx_port); + phy->started = 1; + + } + + return req.header.phy_id; +} + +int send_pnf_stop_response(pnf_test_config_t* config, uint16_t phy_id) +{ + printf("pnf_stop_response\n"); + nfapi_pnf_stop_response_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_PNF_STOP_RESPONSE; + resp.header.message_length = 0; + resp.error_code = NFAPI_MSG_OK; + + send_p5_message(config->p5_sock, &resp.header, sizeof(resp), &(config->p5_tx_sockaddr), sizeof(config->p5_tx_sockaddr)); + return 0; +} + +int receive_pnf_stop_request(pnf_test_config_t* config) +{ + printf("pnf_stop_request\n"); + nfapi_pnf_stop_request_t req; + recv_p5_message(config->p5_sock, &req.header, sizeof(req)); + + CU_ASSERT_EQUAL(req.header.message_id, NFAPI_PNF_STOP_REQUEST); + if(req.header.message_id == NFAPI_PNF_STOP_REQUEST) + { + printf("decoded nfapi_pnf_stop_request\n"); + } + return 0; +} +int pnf_param_response(nfapi_vnf_config_t* config, int p5_idx,nfapi_pnf_param_response_t* response) +{ + printf("[VNF] pnf_param_response p5_idx:%d\n", p5_idx); + CU_ASSERT_EQUAL(response->error_code, NFAPI_MSG_OK); + + uint16_t phy_id; + nfapi_vnf_allocate_phy(config, p5_idx, &phy_id); + + nfapi_pnf_config_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PNF_CONFIG_REQUEST; + req.header.message_length = 0; + req.header.phy_id = NFAPI_PHY_ID_NA; + + req.pnf_phy_rf_config.tl.tag = NFAPI_PNF_PHY_RF_TAG; + req.pnf_phy_rf_config.number_phy_rf_config_info = 2; + nfapi_vnf_allocate_phy(config, p5_idx, &req.pnf_phy_rf_config.phy_rf_config[0].phy_id); + nfapi_vnf_allocate_phy(config, p5_idx, &req.pnf_phy_rf_config.phy_rf_config[1].phy_id); + + uint16_t i = vnf_test_config[0].phy_count; + + vnf_test_config[0].phys[i].enabled = 1; + vnf_test_config[0].phys[i].p5_idx = p5_idx; + vnf_test_config[0].phys[i].phy_id = req.pnf_phy_rf_config.phy_rf_config[0].phy_id; + + i++; + + vnf_test_config[0].phys[i].enabled = 1; + vnf_test_config[0].phys[i].p5_idx = p5_idx; + vnf_test_config[0].phys[i].phy_id = req.pnf_phy_rf_config.phy_rf_config[1].phy_id; + + i++; + + vnf_test_config[0].phy_count = i; + + nfapi_vnf_pnf_config_req(config, p5_idx, &req); + + return 0; +} + +int pnf_config_response(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_config_response_t* response) +{ + printf("pnf_config_response\n"); + CU_ASSERT_EQUAL(response->error_code, NFAPI_MSG_OK); + + nfapi_pnf_start_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PNF_START_REQUEST; + req.header.message_length = 0; + req.header.phy_id = response->header.phy_id; + + nfapi_vnf_pnf_start_req(config, p5_idx, &req); + + return 0; +} + + +void* vnf_test_start_p7_thread(void* ptr) +{ + int result = nfapi_vnf_p7_start((nfapi_vnf_p7_config_t*)ptr); + (void)result; + return 0; +} + +int test_subframe_indication(nfapi_vnf_p7_config_t* config, uint16_t phy_id, uint16_t sfn_sf) +{ + //printf("[VNF:%d] (%d:%d) SUBFRAME_IND\n", phy_id, SFNSF2SFN(sfn_sf), SFNSF2SF(sfn_sf)); + + nfapi_dl_config_request_t dl_config_req; + memset(&dl_config_req, 0, sizeof(dl_config_req)); + dl_config_req.header.message_id = NFAPI_DL_CONFIG_REQUEST; + dl_config_req.header.phy_id = phy_id; + dl_config_req.sfn_sf = sfn_sf; + nfapi_vnf_p7_dl_config_req(config, &dl_config_req); + + nfapi_ul_config_request_t ul_config_req; + memset(&ul_config_req, 0, sizeof(ul_config_req)); + ul_config_req.header.message_id = NFAPI_UL_CONFIG_REQUEST; + ul_config_req.header.phy_id = phy_id; + ul_config_req.sfn_sf = sfn_sf; + nfapi_vnf_p7_ul_config_req(config, &ul_config_req); + + nfapi_hi_dci0_request_t hi_dci0_req; + memset(&hi_dci0_req, 0, sizeof(hi_dci0_req)); + hi_dci0_req.header.message_id = NFAPI_HI_DCI0_REQUEST; + hi_dci0_req.header.phy_id = phy_id; + hi_dci0_req.sfn_sf = sfn_sf; + nfapi_vnf_p7_hi_dci0_req(config, &hi_dci0_req); + + + nfapi_tx_request_t tx_req; + memset(&tx_req, 0, sizeof(tx_req)); + tx_req.header.message_id = NFAPI_TX_REQUEST; + tx_req.header.phy_id = phy_id; + tx_req.sfn_sf = sfn_sf; + nfapi_vnf_p7_tx_req(config, &tx_req); + return 0; +} + +int test_harq_indication(nfapi_vnf_p7_config_t* config, nfapi_harq_indication_t* ind) +{ + //printf("[VNF:%d] (%d:%d) HARQ_IND\n", ind->header.phy_id, SFNSF2SFN(ind->sfn_sf), SFNSF2SF(ind->sfn_sf)); + return 0; +} + +int test_nb_harq_indication(nfapi_vnf_p7_config_t* config, nfapi_nb_harq_indication_t* ind) +{ + //printf("[VNF:%d] (%d:%d) HARQ_IND\n", ind->header.phy_id, SFNSF2SFN(ind->sfn_sf), SFNSF2SF(ind->sfn_sf)); + return 0; +} + + +int test_crc_indication(nfapi_vnf_p7_config_t* config, nfapi_crc_indication_t* ind) +{ + //printf("[VNF:%d] (%d:%d) CRC_IND\n", ind->header.phy_id, SFNSF2SFN(ind->sfn_sf), SFNSF2SF(ind->sfn_sf)); + return 0; +} +int test_rx_indication(nfapi_vnf_p7_config_t* config, nfapi_rx_indication_t* ind) +{ + //printf("[VNF:%d] (%d:%d) RX_IND\n", ind->header.phy_id, SFNSF2SFN(ind->sfn_sf), SFNSF2SF(ind->sfn_sf)); + return 0; +} +int test_rach_indication(nfapi_vnf_p7_config_t* config, nfapi_rach_indication_t* ind) +{ + //printf("[VNF:%d] (%d:%d) RACH_IND\n", ind->header.phy_id, SFNSF2SFN(ind->sfn_sf), SFNSF2SF(ind->sfn_sf)); + return 0; +} +int test_nrach_indication(nfapi_vnf_p7_config_t* config, nfapi_nrach_indication_t* ind) +{ + //printf("[VNF:%d] (%d:%d) RACH_IND\n", ind->header.phy_id, SFNSF2SFN(ind->sfn_sf), SFNSF2SF(ind->sfn_sf)); + return 0; +} +int test_srs_indication(nfapi_vnf_p7_config_t* config, nfapi_srs_indication_t* ind) +{ + //printf("[VNF:%d] (%d:%d) SRS_IND\n", ind->header.phy_id, SFNSF2SFN(ind->sfn_sf), SFNSF2SF(ind->sfn_sf)); + return 0; +} +int test_sr_indication(nfapi_vnf_p7_config_t* config, nfapi_sr_indication_t* ind) +{ + //printf("[VNF:%d] (%d:%d) SR_IND\n", ind->header.phy_id, SFNSF2SFN(ind->sfn_sf), SFNSF2SF(ind->sfn_sf)); + return 0; +} +int test_cqi_indication(nfapi_vnf_p7_config_t* config, nfapi_cqi_indication_t* ind) +{ + //printf("[VNF:%d] (%d:%d) CQI_IND\n", ind->header.phy_id, SFNSF2SFN(ind->sfn_sf), SFNSF2SF(ind->sfn_sf)); + return 0; +} + +int pnf_start_response(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_start_response_t* response) +{ + printf("[VNF] pnf_start_response p5_idx:%d\n", p5_idx); + CU_ASSERT_EQUAL(response->error_code, NFAPI_MSG_OK); + + return 0; +} + +int pnf_stop_response(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_stop_response_t* response) +{ + printf("pnf_stop_response\n"); + CU_ASSERT_EQUAL(response->error_code, NFAPI_MSG_OK); + + nfapi_vnf_p7_stop(vnf_test_config[0].vnfs[0].config); + return 0; +} + +int param_response(nfapi_vnf_config_t* config, int p5_idx, nfapi_param_response_t* response) +{ + printf("[VNF] param_response p5_idx:%d phy_id:%d\n", p5_idx, response->header.phy_id); + CU_ASSERT_EQUAL(response->error_code, NFAPI_MSG_OK); + + struct sockaddr_in addr; + memcpy(&addr.sin_addr.s_addr, &response->nfapi_config.p7_pnf_address_ipv4.address, 4); + printf("[VNF] param_response pnf p7 %s:%d\n", inet_ntoa(addr.sin_addr), response->nfapi_config.p7_pnf_port.value); + + // find the vnf phy configuration + vnf_test_config_phy_t* phy = find_vnf_phy_config(&(vnf_test_config[0]), response->header.phy_id); + + // save the pnf p7 connection information + phy->p7_tx_sockaddr.sin_port = response->nfapi_config.p7_pnf_port.value; + memcpy(&phy->p7_tx_sockaddr.sin_addr.s_addr, &response->nfapi_config.p7_pnf_address_ipv4.address, 4); + + nfapi_config_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_CONFIG_REQUEST; + req.header.phy_id = response->header.phy_id; + + vnf_test_config_vnf_t* vnf = &(vnf_test_config[0].vnfs[phy->vnf_idx]); + req.nfapi_config.p7_vnf_address_ipv4.tl.tag = NFAPI_NFAPI_P7_VNF_ADDRESS_IPV4_TAG; + memcpy(&req.nfapi_config.p7_vnf_address_ipv4.address, &vnf->p7_rx_sockaddr.sin_addr.s_addr, 4); + + req.nfapi_config.p7_vnf_port.tl.tag = NFAPI_NFAPI_P7_VNF_PORT_TAG; + req.nfapi_config.p7_vnf_port.value = vnf->p7_rx_sockaddr.sin_port; + + nfapi_vnf_config_req(config, p5_idx, &req); + return 0; +} + +int config_response(nfapi_vnf_config_t* config, int p5_idx, nfapi_config_response_t* response) +{ + printf("[VNF] config_response p5_idx:%d phy_id:%d\n", p5_idx, response->header.phy_id); + return 0; + CU_ASSERT_EQUAL(response->error_code, NFAPI_MSG_OK); + +} + +int send_vnf_start_req(vnf_test_config_t* config, vnf_test_config_phy_t* phy) +{ + nfapi_start_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_START_REQUEST; + req.header.phy_id = phy->phy_id; + + nfapi_vnf_start_req(config->p5_vnf_config, phy->p5_idx, &req); + return 0; +} + +int start_response(nfapi_vnf_config_t* config, int p5_idx, nfapi_start_response_t* response) +{ + printf("[VNF] start_response p5_idx:%d phy_id:%d\n", p5_idx, response->header.phy_id); + CU_ASSERT_EQUAL(response->error_code, NFAPI_MSG_OK); + + sleep(1); + + vnf_test_config_phy_t* phy = find_vnf_phy_config(&(vnf_test_config[0]), response->header.phy_id); + + char* addr = inet_ntoa(phy->p7_tx_sockaddr.sin_addr); + int port = phy->p7_tx_sockaddr.sin_port; + + vnf_test_config_vnf_t* vnf = &(vnf_test_config[0].vnfs[phy->vnf_idx]); + + nfapi_vnf_p7_add_pnf(vnf->config, addr, port, response->header.phy_id); + return 0; +} + +int stop_response(nfapi_vnf_config_t* config, int p5_idx, nfapi_stop_response_t* response) +{ + printf("stop_response p5_idx:%d phy_id:%d\n", p5_idx, response->header.phy_id); + CU_ASSERT_EQUAL(response->error_code, NFAPI_MSG_OK); + return 0; +} + +void start_vnf_p5(vnf_test_config_t* test_config) +{ + test_config->p5_vnf_config = nfapi_vnf_config_create(); + + test_config->p5_vnf_config->vnf_p5_port = test_config->p5_port; + test_config->p5_vnf_config->vnf_ipv4 = 1; + test_config->p5_vnf_config->pnf_connection_indication = &pnf_connection_indication; + test_config->p5_vnf_config->pnf_disconnect_indication = &pnf_disconnect_indication; + test_config->p5_vnf_config->pnf_param_resp = &pnf_param_response; + test_config->p5_vnf_config->pnf_config_resp = &pnf_config_response; + test_config->p5_vnf_config->pnf_start_resp = &pnf_start_response; + test_config->p5_vnf_config->pnf_stop_resp = &pnf_stop_response; + test_config->p5_vnf_config->param_resp = ¶m_response; + test_config->p5_vnf_config->config_resp = &config_response; + test_config->p5_vnf_config->start_resp = &start_response; + test_config->p5_vnf_config->stop_resp = &stop_response; + + test_config->p5_vnf_config->user_data = test_config; + + pthread_create(&test_config->thread, NULL, &vnf_test_start_thread, test_config->p5_vnf_config); + + sleep(1); + +} + +void start_vnf_p7(vnf_test_config_vnf_t* vnf) +{ + + // todo : select which vnf to use for these phy's + vnf->enabled = 1; + + vnf->p7_rx_sockaddr.sin_addr.s_addr = inet_addr(vnf->vnf_p7_addr); + vnf->p7_rx_sockaddr.sin_port = vnf->vnf_p7_port; + + + vnf->config = nfapi_vnf_p7_config_create(); + vnf->config->checksum_enabled = 0; + vnf->config->port = vnf->vnf_p7_port; + vnf->config->subframe_indication = &test_subframe_indication; + vnf->config->harq_indication = &test_harq_indication; + vnf->config->crc_indication = &test_crc_indication; + vnf->config->rx_indication = &test_rx_indication; + vnf->config->rach_indication = &test_rach_indication; + vnf->config->srs_indication = &test_srs_indication; + vnf->config->sr_indication = &test_sr_indication; + vnf->config->cqi_indication = &test_cqi_indication; + + vnf->config->nb_harq_indication = &test_nb_harq_indication; + vnf->config->nrach_indication = &test_nrach_indication; + + + vnf->config->segment_size = 1400; + vnf->config->max_num_segments = 6; + + pthread_create(&(vnf->thread), NULL, &vnf_test_start_p7_thread, vnf->config); + + vnf->enabled = 1; + + //vnf->phy_count++; + + sleep(1); +} + +void send_p7_segmented_msg(int sock, char* msg, int len, int segment_size, struct sockaddr* addr, socklen_t addr_len) +{ + static uint8_t sequence_num = 0; + if(len < segment_size) + { + msg[7] = sequence_num; + sendto(sock, msg, len, 0, addr, addr_len); + } + else + { + int msg_body_len = len - 12 ; + int seg_body_len = segment_size - 12 ; + int segments = (msg_body_len / (seg_body_len)) + ((msg_body_len % seg_body_len) ? 1 : 0); + + //printf("sending segmented message len:%d seg_size:%d count:%d\n", len, segment_size, segments); + + int segment = 0; + int offset = 12; + for(segment = 0; segment < segments; ++segment) + { + uint8_t last = 0; + uint16_t size = segment_size - 12; + if(segment + 1 == segments) + { + last = 1; + size = (msg_body_len) - (seg_body_len * segment); + } + + char buffer[segment_size]; + + memcpy(&buffer[0], msg, 12); + buffer[6] = ((!last) << 7) + segment; + buffer[7] = sequence_num; + + // msg length + uint8_t* p = (uint8_t*)&buffer[4]; + push16(size + 12, &p, (uint8_t*)&buffer[size + 12]); + + memcpy(&buffer[12], msg + offset, size); + offset += size; + + sendto(sock, &buffer[0], size + 12, 0, addr, addr_len); + + } + + + } + + sequence_num++; +} + +void start_phy(vnf_test_config_phy_t* phy) +{ + + nfapi_param_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PARAM_REQUEST; + req.header.phy_id = phy->phy_id; + + nfapi_vnf_config_t* p5_vnf_config = (vnf_test_config[0].p5_vnf_config); + + + nfapi_vnf_param_req(p5_vnf_config, phy->p5_idx, &req); + +} + + +void vnf_test_start_connect(void) +{ + reset_test_configs(); + + int segment_size = 256; + + vnf_test_config[0].p5_addr = "127.0.0.1"; + vnf_test_config[0].p5_port = 4242; + + vnf_test_config[0].vnfs[0].enabled = 0; + vnf_test_config[0].vnfs[0].vnf_p7_addr = "127.0.0.1"; + vnf_test_config[0].vnfs[0].vnf_p7_port = 7878; + vnf_test_config[0].vnfs[0].max_phys = 1; + + vnf_test_config[0].vnfs[1].enabled = 0; + vnf_test_config[0].vnfs[1].vnf_p7_addr = "127.0.0.1"; + vnf_test_config[0].vnfs[1].vnf_p7_port = 7879; + vnf_test_config[0].vnfs[1].max_phys = 1; + + + // this is the action that p9 would take to set the vnf p5 address/port + pnf_test_config[0].enabled = 1; + pnf_test_config[0].vnf_p5_port = vnf_test_config[0].p5_port; + pnf_test_config[0].vnf_p5_addr = vnf_test_config[0].p5_addr; + pnf_test_config[0].p7_rx_port_base = 8000; + + pnf_test_config[1].enabled = 1; + pnf_test_config[1].vnf_p5_port = vnf_test_config[0].p5_port; + pnf_test_config[1].vnf_p5_addr = vnf_test_config[0].p5_addr; + pnf_test_config[1].p7_rx_port_base = 8100; + + pnf_connection_indication_called = 0; + + start_vnf_p5(&vnf_test_config[0]); + + + pnf_create_p5_sock(&pnf_test_config[0]); + pnf_p5_connect(&pnf_test_config[0]); + + receive_pnf_param_request(&pnf_test_config[0]); + send_pnf_param_response(&pnf_test_config[0]); + + receive_pnf_config_request(&pnf_test_config[0]); + send_pnf_config_response(&pnf_test_config[0]); + + receive_pnf_start_request(&pnf_test_config[0]); + send_pnf_start_response(&pnf_test_config[0]); + + pnf_create_p5_sock(&pnf_test_config[1]); + + pnf_p5_connect(&pnf_test_config[1]); + + receive_pnf_param_request(&pnf_test_config[1]); + send_pnf_param_response(&pnf_test_config[1]); + + receive_pnf_config_request(&pnf_test_config[1]); + send_pnf_config_response(&pnf_test_config[1]); + + receive_pnf_start_request(&pnf_test_config[1]); + send_pnf_start_response(&pnf_test_config[1]); + + // start the vnf_p7 thread and assign by phys to that instance + + start_vnf_p7(&vnf_test_config[0].vnfs[0]); + //start_vnf_p7(&vnf_test_config[0].vnfs[1]); + + printf("---- configuring phy %d -----\n", vnf_test_config[0].phys[0].phy_id); + vnf_test_config[0].phys[0].vnf_idx = 0; + start_phy(&vnf_test_config[0].phys[0]); + + int phy_id = receive_param_request(&pnf_test_config[0]); + send_param_response(&pnf_test_config[0], phy_id); + + phy_id = receive_config_request(&pnf_test_config[0]); + send_config_response(&pnf_test_config[0], phy_id); + + printf("---- configuring phy %d -----\n", vnf_test_config[0].phys[2].phy_id); + vnf_test_config[0].phys[2].vnf_idx = 0; + start_phy(&vnf_test_config[0].phys[2]); + + phy_id = receive_param_request(&pnf_test_config[1]); + send_param_response(&pnf_test_config[1], phy_id); + + phy_id = receive_config_request(&pnf_test_config[1]); + send_config_response(&pnf_test_config[1], phy_id); + + printf("---- configuring phy %d -----\n", vnf_test_config[0].phys[1].phy_id); + + vnf_test_config[0].phys[1].vnf_idx = 0; + start_phy(&vnf_test_config[0].phys[1]); + + phy_id = receive_param_request(&pnf_test_config[0]); + send_param_response(&pnf_test_config[0], phy_id); + + phy_id = receive_config_request(&pnf_test_config[0]); + send_config_response(&pnf_test_config[0], phy_id); + + //------------- + printf("---- starting phy %d -----\n", vnf_test_config[0].phys[0].phy_id); + + send_vnf_start_req(&vnf_test_config[0], &vnf_test_config[0].phys[0]); + phy_id = receive_start_request(&pnf_test_config[0]); + send_start_response(&pnf_test_config[0], phy_id); +/* + printf("---- starting phy %d -----\n", vnf_test_config[0].phys[2].phy_id); + + send_vnf_start_req(&vnf_test_config[0], &vnf_test_config[0].phys[2]); + phy_id = receive_start_request(&pnf_test_config[1]); + send_start_response(&pnf_test_config[1], phy_id); + + printf("---- starting phy %d -----\n", vnf_test_config[0].phys[1].phy_id); + + send_vnf_start_req(&vnf_test_config[0], &vnf_test_config[0].phys[1]); + phy_id = receive_start_request(&pnf_test_config[0]); + send_start_response(&pnf_test_config[0], phy_id); +*/ + //close(pnf_test_config[0].p5_sock); + + char buffer[2048]; + int buffer_size = sizeof(buffer); + + + fd_set rdfs; + int exit = 0; + while(exit != 1) + { + int pnf_idx, phy_idx; + int max_fd = 0; + FD_ZERO(&rdfs); + + for(pnf_idx = 0; pnf_idx < 4; ++pnf_idx) + { + if(pnf_test_config[pnf_idx].enabled) + { + FD_SET(pnf_test_config[pnf_idx].p5_sock, &rdfs); + if(pnf_test_config[pnf_idx].p5_sock > max_fd) + max_fd = pnf_test_config[pnf_idx].p5_sock; + } + + for(phy_idx = 0; phy_idx < 4; ++phy_idx) + { + pnf_test_config_phy_t* phy_info = &(pnf_test_config[pnf_idx].phys[phy_idx]); + + if(phy_info->started == 1 && phy_info->enabled == 1) + { + //////////////////printf("adding %d/%d %d %d\n", pnf_idx, phy_idx, phy_info->phy_id, phy_info->p7_rx_sock); + FD_SET(phy_info->p7_rx_sock, &rdfs); + if(phy_info->p7_rx_sock > max_fd) + max_fd = phy_info->p7_rx_sock; + } + } + } + + + // changed to select, + int select_result = select(max_fd + 1, &rdfs, NULL, NULL, NULL); + (void)select_result; + + for(pnf_idx = 0; pnf_idx < 4; ++pnf_idx) + { + if(pnf_test_config[pnf_idx].enabled) + { + //pnf_test_config_t* pnf_config = &(pnf_test_config[pnf_idx]); + } + + for(phy_idx = 0; phy_idx < 4; ++phy_idx) + { + pnf_test_config_phy_t* phy_info = &(pnf_test_config[pnf_idx].phys[phy_idx]); + + if(phy_info->enabled) + { + if(FD_ISSET(phy_info->p7_rx_sock, &rdfs)) + { + //struct sockaddr_in recv_addr; + //memset(&recv_addr, 0, sizeof(recv_addr)); + //socklen_t recv_addr_size; + int len = recvfrom(phy_info->p7_rx_sock, &buffer[0], buffer_size, 0, 0, 0);// (struct sockaddr*)&recv_addr, &recv_addr_size); + + if(len == -1) + { + printf("recvfrom %d failed %d\n", phy_info->p7_rx_sock, errno); + continue; + } + + nfapi_p7_message_header_t header; + nfapi_p7_message_header_unpack(buffer, len, &header, sizeof(header), 0); + + switch(header.message_id) + { + case NFAPI_DL_NODE_SYNC: + { + nfapi_dl_node_sync_t msg; + nfapi_p7_message_unpack(buffer, len, &msg, sizeof(msg), 0); + printf("[PNF:%d] NFAPI_DL_NODE_SYNC t1:%d\n", msg.header.phy_id, msg.t1); + + nfapi_ul_node_sync_t resp; + memset(&resp, 0, sizeof(resp)); + resp.header.message_id = NFAPI_UL_NODE_SYNC; + resp.header.phy_id = msg.header.phy_id; + resp.t1 = msg.t1; + usleep(50); + resp.t2 = msg.t1 + 50; // 50 us rx latency + resp.t3 = msg.t1 + 10; // 10 us pnf proc + + usleep(50); + + len = nfapi_p7_message_pack(&resp, buffer, buffer_size, 0); + // send ul node sycn + send_p7_segmented_msg(phy_info->p7_tx_sock, &buffer[0], len, segment_size, (struct sockaddr*)&phy_info->p7_tx_sockaddr, sizeof(phy_info->p7_tx_sockaddr)); + } + break; + case NFAPI_DL_CONFIG_REQUEST: + { + nfapi_dl_config_request_t msg; + nfapi_p7_message_unpack(buffer, len, &msg, sizeof(msg), 0); + //printf("[PNF:%d] (%d/%d) NFAPI_DL_CONFIG_REQUEST\n", header.phy_id, SFNSF2SFN(msg.sfn_sf), SFNSF2SF(msg.sfn_sf)); + + if(SFNSF2SFN(msg.sfn_sf) == 500) + exit = 1; + // simulate the uplink messages + + nfapi_harq_indication_t harq_ind; + memset(&harq_ind, 0, sizeof(harq_ind)); + harq_ind.header.message_id = NFAPI_HARQ_INDICATION; + harq_ind.header.phy_id = msg.header.phy_id; + harq_ind.sfn_sf = msg.sfn_sf; + harq_ind.harq_indication_body.tl.tag = NFAPI_HARQ_INDICATION_BODY_TAG; + harq_ind.harq_indication_body.number_of_harqs = 2; + + harq_ind.harq_indication_body.harq_pdu_list = (nfapi_harq_indication_pdu_t*)(malloc(sizeof(nfapi_harq_indication_pdu_t) * harq_ind.harq_indication_body.number_of_harqs)); + + int i = 0; + for(i = 0; i < harq_ind.harq_indication_body.number_of_harqs; ++i) + { + harq_ind.harq_indication_body.harq_pdu_list[i].rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + } + len = nfapi_p7_message_pack(&harq_ind, buffer, buffer_size, 0); + //sendto(phy_info->p7_tx_sock, &buffer[0], len, 0, (struct sockaddr*)&phy_info->p7_tx_sockaddr, sizeof(phy_info->p7_tx_sockaddr)); + send_p7_segmented_msg(phy_info->p7_tx_sock, &buffer[0], len, segment_size, (struct sockaddr*)&phy_info->p7_tx_sockaddr, sizeof(phy_info->p7_tx_sockaddr)); + + + + //sendto(phy_info->p7_tx_sock, &buffer[0], len, 0, (struct sockaddr*)&phy_info->p7_tx_sockaddr, sizeof(phy_info->p7_tx_sockaddr)); + + free(harq_ind.harq_indication_body.harq_pdu_list); + + nfapi_crc_indication_t crc_ind; + memset(&crc_ind, 0, sizeof(crc_ind)); + crc_ind.header.message_id = NFAPI_CRC_INDICATION; + crc_ind.header.phy_id = msg.header.phy_id; + crc_ind.sfn_sf = msg.sfn_sf; + len = nfapi_p7_message_pack(&crc_ind, buffer, buffer_size, 0); + send_p7_segmented_msg(phy_info->p7_tx_sock, &buffer[0], len, segment_size, (struct sockaddr*)&phy_info->p7_tx_sockaddr, sizeof(phy_info->p7_tx_sockaddr)); + + nfapi_sr_indication_t sr_ind; + memset(&sr_ind, 0, sizeof(sr_ind)); + sr_ind.header.message_id = NFAPI_RX_SR_INDICATION; + sr_ind.header.phy_id = msg.header.phy_id; + sr_ind.sfn_sf = msg.sfn_sf; + len = nfapi_p7_message_pack(&sr_ind, buffer, buffer_size, 0); + send_p7_segmented_msg(phy_info->p7_tx_sock, &buffer[0], len, segment_size, (struct sockaddr*)&phy_info->p7_tx_sockaddr, sizeof(phy_info->p7_tx_sockaddr)); + + nfapi_cqi_indication_t cqi_ind; + memset(&cqi_ind, 0, sizeof(cqi_ind)); + cqi_ind.header.message_id = NFAPI_RX_CQI_INDICATION; + cqi_ind.header.phy_id = msg.header.phy_id; + cqi_ind.sfn_sf = msg.sfn_sf; + len = nfapi_p7_message_pack(&cqi_ind, buffer, buffer_size, 0); + send_p7_segmented_msg(phy_info->p7_tx_sock, &buffer[0], len, segment_size, (struct sockaddr*)&phy_info->p7_tx_sockaddr, sizeof(phy_info->p7_tx_sockaddr)); + + nfapi_rach_indication_t rach_ind; + memset(&rach_ind, 0, sizeof(rach_ind)); + rach_ind.header.message_id = NFAPI_RACH_INDICATION; + rach_ind.header.phy_id = msg.header.phy_id; + rach_ind.sfn_sf = msg.sfn_sf; + len = nfapi_p7_message_pack(&rach_ind, buffer, buffer_size, 0); + send_p7_segmented_msg(phy_info->p7_tx_sock, &buffer[0], len, segment_size, (struct sockaddr*)&phy_info->p7_tx_sockaddr, sizeof(phy_info->p7_tx_sockaddr)); + + nfapi_srs_indication_t srs_ind; + memset(&srs_ind, 0, sizeof(srs_ind)); + srs_ind.header.message_id = NFAPI_SRS_INDICATION; + srs_ind.header.phy_id = msg.header.phy_id; + srs_ind.sfn_sf = msg.sfn_sf; + len = nfapi_p7_message_pack(&srs_ind, buffer, buffer_size, 0); + send_p7_segmented_msg(phy_info->p7_tx_sock, &buffer[0], len, segment_size, (struct sockaddr*)&phy_info->p7_tx_sockaddr, sizeof(phy_info->p7_tx_sockaddr)); + + nfapi_rx_indication_t rx_ind; + memset(&rx_ind, 0, sizeof(rx_ind)); + rx_ind.header.message_id = NFAPI_RX_ULSCH_INDICATION; + rx_ind.header.phy_id = msg.header.phy_id; + rx_ind.sfn_sf = msg.sfn_sf; + len = nfapi_p7_message_pack(&rx_ind, buffer, buffer_size, 0); + send_p7_segmented_msg(phy_info->p7_tx_sock, &buffer[0], len, segment_size, (struct sockaddr*)&phy_info->p7_tx_sockaddr, sizeof(phy_info->p7_tx_sockaddr)); + + if(msg.sfn_sf % 5 == 0) + { + // periodically send the timing info + nfapi_timing_info_t timing_info; + memset(&timing_info, 0, sizeof(timing_info)); + timing_info.header.message_id = NFAPI_TIMING_INFO; + timing_info.header.phy_id = msg.header.phy_id; + len = nfapi_p7_message_pack(&timing_info, buffer, buffer_size, 0); + send_p7_segmented_msg(phy_info->p7_tx_sock, &buffer[0], len, segment_size, (struct sockaddr*)&phy_info->p7_tx_sockaddr, sizeof(phy_info->p7_tx_sockaddr)); + } + + nfapi_nb_harq_indication_t nb_harq_ind; + memset(&nb_harq_ind, 0, sizeof(nb_harq_ind)); + nb_harq_ind.header.message_id = NFAPI_NB_HARQ_INDICATION; + nb_harq_ind.header.phy_id = msg.header.phy_id; + nb_harq_ind.sfn_sf = msg.sfn_sf; + len = nfapi_p7_message_pack(&nb_harq_ind, buffer, buffer_size, 0); + send_p7_segmented_msg(phy_info->p7_tx_sock, &buffer[0], len, segment_size, (struct sockaddr*)&phy_info->p7_tx_sockaddr, sizeof(phy_info->p7_tx_sockaddr)); + + nfapi_nrach_indication_t nrach_ind; + memset(&nrach_ind, 0, sizeof(nrach_ind)); + nrach_ind.header.message_id = NFAPI_NRACH_INDICATION; + nrach_ind.header.phy_id = msg.header.phy_id; + nrach_ind.sfn_sf = msg.sfn_sf; + len = nfapi_p7_message_pack(&nrach_ind, buffer, buffer_size, 0); + send_p7_segmented_msg(phy_info->p7_tx_sock, &buffer[0], len, segment_size, (struct sockaddr*)&phy_info->p7_tx_sockaddr, sizeof(phy_info->p7_tx_sockaddr)); + + } + break; + case NFAPI_UL_CONFIG_REQUEST: + { + nfapi_ul_config_request_t msg; + nfapi_p7_message_unpack(buffer, len, &msg, sizeof(msg), 0); + //printf("[PNF:%d] (%d/%d) NFAPI_UL_CONFIG_REQUEST\n", header.phy_id, SFNSF2SFN(msg.sfn_sf), SFNSF2SF(msg.sfn_sf)); + } + break; + case NFAPI_HI_DCI0_REQUEST: + { + nfapi_hi_dci0_request_t msg; + nfapi_p7_message_unpack(buffer, len, &msg, sizeof(msg), 0); + //printf("[PNF:%d] (%d/%d) NFAPI_HI_DCI0_REQUEST\n", header.phy_id, SFNSF2SFN(msg.sfn_sf), SFNSF2SF(msg.sfn_sf)); + } + break; + case NFAPI_TX_REQUEST: + { + nfapi_tx_request_t msg; + nfapi_p7_message_unpack(buffer, len, &msg, sizeof(msg), 0); + //printf("[PNF:%d] (%d/%d) NFAPI_TX_REQUEST\n", header.phy_id, SFNSF2SFN(msg.sfn_sf), SFNSF2SF(msg.sfn_sf)); + } + break; + } + + } + } + } + } + } + + printf("Triggering p5 shutdown\n"); + + // vnf p5 trigger shutdown + nfapi_pnf_stop_request_t stop_req; + memset(&stop_req, 0, sizeof(stop_req)); + stop_req.header.message_id = NFAPI_PNF_STOP_REQUEST; + nfapi_vnf_pnf_stop_req(vnf_test_config[0].p5_vnf_config, 0, &stop_req); + + phy_id = receive_pnf_stop_request(&pnf_test_config[0]); + send_pnf_stop_response(&pnf_test_config[0], phy_id); + + + nfapi_vnf_stop(vnf_test_config[0].p5_vnf_config); + + + + int* result; + pthread_join((vnf_test_config[0].thread), (void**)&result); + CU_ASSERT_EQUAL(result, 0); + //CU_ASSERT_EQUAL(pnf_connection_indication_called, 1); + + + close(pnf_test_config[0].p5_sock); +} + +void vnf_test_start_connect_ipv6(void) +{ + char* vnf_addr = "::1"; + int vnf_port = 4242; + pnf_connection_indication_called = 0; + + nfapi_vnf_config_t* config = nfapi_vnf_config_create(); + config->vnf_p5_port = vnf_port; + config->vnf_ipv4 = 0; + config->vnf_ipv6 = 1; + config->pnf_connection_indication = &pnf_connection_indication; + config->pnf_disconnect_indication = &pnf_disconnect_indication; + config->pnf_param_resp = &pnf_param_response; + config->pnf_config_resp = &pnf_config_response; + config->pnf_start_resp = &pnf_start_response; + + pthread_t thread; + pthread_create(&thread, NULL, &vnf_test_start_thread, config); + + sleep(1); + + + int p5Sock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); + + struct sockaddr_in6 addr; + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(vnf_port); + //addr.sin6_addr = inet_addr(vnf_addr); + inet_pton(AF_INET6, vnf_addr, &addr.sin6_addr); + + + /* + int connect_result = connect(p5Sock, (struct sockaddr *)&addr, sizeof(addr) ); + + printf("connect_result %d %d\n", connect_result, errno); + + receive_pnf_param_request(p5Sock); + send_pnf_param_response(p5Sock, &addr, sizeof(addr)); + + receive_pnf_config_request(p5Sock); + send_pnf_config_response(p5Sock, &addr, sizeof(addr)); + + receive_pnf_start_request(p5Sock); + send_pnf_start_response(p5Sock, &addr, sizeof(addr)); + */ + sleep(4); + nfapi_vnf_stop(config); + + int* result; + pthread_join(thread, (void**)&result); + CU_ASSERT_EQUAL(result, 0); + CU_ASSERT_EQUAL(pnf_connection_indication_called, 1); + + + close(p5Sock); +} +void vnf_test_start_connect_2(void) +{ + char* vnf_addr = "127.0.0.1"; + int vnf_port = 4242; + pnf_connection_indication_called = 0; + + nfapi_vnf_config_t * config = nfapi_vnf_config_create(); + config->vnf_p5_port = vnf_port; + config->pnf_connection_indication = &pnf_connection_indication; + + pthread_t thread; + pthread_create(&thread, NULL, &vnf_test_start_thread, config); + + sleep(1); + + + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(vnf_port); + addr.sin_addr.s_addr = inet_addr(vnf_addr); + + + int p5Sock1 = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); + + int connect_result_1 = connect(p5Sock1, (struct sockaddr *)&addr, sizeof(addr) ); + + printf("connect_result_1 %d %d\n", connect_result_1, errno); + + int p5Sock2 = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); + + int connect_result_2 = connect(p5Sock2, (struct sockaddr *)&addr, sizeof(addr) ); + + printf("connect_result_2 %d %d\n", connect_result_2, errno); + + sleep(1); + + close(p5Sock1); + + sleep(1); + + close(p5Sock2); + + sleep(1); + + nfapi_vnf_stop(config); + + int* result; + pthread_join(thread, (void**)&result); + CU_ASSERT_EQUAL(result, 0); + CU_ASSERT_EQUAL(pnf_connection_indication_called, 2); + + + close(p5Sock1); + close(p5Sock2); +} + +void vnf_test_p7_segmentation_test1(void) +{ + +} + + +/************* Test Runner Code goes here **************/ + +int main ( void ) +{ + CU_pSuite pSuite = NULL; + + /* initialize the CUnit test registry */ + if ( CUE_SUCCESS != CU_initialize_registry() ) + return CU_get_error(); + + /* add a suite to the registry */ + pSuite = CU_add_suite( "vnf_test_suite", init_suite, clean_suite ); + if ( NULL == pSuite ) + { + CU_cleanup_registry(); + return CU_get_error(); + } + + //(NULL == CU_add_test(pSuite, "vnf_test_start_connect_2", vnf_test_start_connect_2)) + /* add the tests to the suite */ + if ( (NULL == CU_add_test(pSuite, "vnf_test_start_no_config", vnf_test_start_no_config)) || + (NULL == CU_add_test(pSuite, "vnf_test_start_connect", vnf_test_start_connect)) || + (NULL == CU_add_test(pSuite, "vnf_test_p7_segmentation_test1", vnf_test_p7_segmentation_test1)) + ) + { + CU_cleanup_registry(); + return CU_get_error(); + } + + // Run all tests using the basic interface + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_set_output_filename("vnf_unit_test_results.xml"); + CU_basic_run_tests(); + + CU_pSuite s = CU_get_registry()->pSuite; + int count = 0; + while(s) + { + CU_pTest t = s->pTest; + while(t) + { + count++; + t = t->pNext; + } + s = s->pNext; + } + + printf("%d..%d\n", 1, count); + + + + s = CU_get_registry()->pSuite; + count = 1; + while(s) + { + CU_pTest t = s->pTest; + while(t) + { + int pass = 1; + CU_FailureRecord* failures = CU_get_failure_list(); + while(failures) + { + if(strcmp(failures->pSuite->pName, s->pName) == 0 && + strcmp(failures->pTest->pName, t->pName) == 0) + { + pass = 0; + failures = 0; + } + else + { + failures = failures->pNext; + } + } + + if(pass) + printf("ok %d - %s:%s\n", count, s->pName, t->pName); + else + printf("not ok %d - %s:%s\n", count, s->pName, t->pName); + + count++; + t = t->pNext; + } + s = s->pNext; + } + + CU_cleanup_registry(); + return CU_get_error(); + +} diff --git a/nfapi/open-nFAPI/vnf_sim/Makefile.am b/nfapi/open-nFAPI/vnf_sim/Makefile.am new file mode 100644 index 0000000000..c3e42cebf3 --- /dev/null +++ b/nfapi/open-nFAPI/vnf_sim/Makefile.am @@ -0,0 +1,22 @@ +# +# Copyright 2017 Cisco Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +AUTOMAKE_OPTIONS=subdir-objects +AM_CPPFLAGS = -I$(top_srcdir)/vnf_sim/inc -I$(top_srcdir)/sim_common/inc -I$(top_srcdir)/common/public_inc -I$(top_srcdir)/nfapi/inc -I$(top_srcdir)/nfapi/public_inc -I$(top_srcdir)/vnf/inc -I$(top_srcdir)/vnf/public_inc $(XML_CFLAGS) -Wall -Werror -g +AM_CXXFLAGS = -I$(top_srcidr)/vnf_sim/inc -I$(top_srcdir)/sim_common/inc -I$(top_srcdir)/common/public_inc -I$(top_srcdir)/nfapi/inc -I$(top_srcdir)/nfapi/public_inc -I$(top_srcdir)/vnf/inc -I$(top_srcdir)/vnf/public_inc $(XML_CFLAGS) -std=c++11 $(BOOST_CPPFLAGS) -g +bin_PROGRAMS = vnfsim +vnfsim_SOURCES = src/main.cpp src/mac.cpp +LDADD= $(top_builddir)/vnf/libnfapi_vnf.a $(top_builddir)/common/libnfapi_common.a $(top_builddir)/nfapi/libnfapi.a $(top_builddir)/sim_common/libnfapi_sim_common.a -L$(libdir) -lpthread -lrt -lsctp -lz diff --git a/nfapi/open-nFAPI/vnf_sim/inc/mac.h b/nfapi/open-nFAPI/vnf_sim/inc/mac.h new file mode 100644 index 0000000000..eac5b3b2ac --- /dev/null +++ b/nfapi/open-nFAPI/vnf_sim/inc/mac.h @@ -0,0 +1,60 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MAC_H_ +#define _MAC_H_ + +#include "nfapi_interface.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef struct mac mac_t; + +typedef struct mac +{ + void* user_data; + + void (*dl_config_req)(mac_t* mac, nfapi_dl_config_request_t* req); + void (*ul_config_req)(mac_t* mac, nfapi_ul_config_request_t* req); + void (*hi_dci0_req)(mac_t* mac, nfapi_hi_dci0_request_t* req); + void (*tx_req)(mac_t* mac, nfapi_tx_request_t* req); +} mac_t; + +mac_t* mac_create(uint8_t wireshark_test_mode); +void mac_destroy(mac_t* mac); + +void mac_start_data(mac_t* mac, unsigned rx_port, const char* tx_addres, unsigned tx_port); + +void mac_subframe_ind(mac_t* mac, uint16_t phy_id, uint16_t sfn_sf); +void mac_harq_ind(mac_t* mac, nfapi_harq_indication_t* ind); +void mac_crc_ind(mac_t* mac, nfapi_crc_indication_t* ind); +void mac_rx_ind(mac_t* mac, nfapi_rx_indication_t* ind); +void mac_rach_ind(mac_t* mac, nfapi_rach_indication_t* ind); +void mac_srs_ind(mac_t* mac, nfapi_srs_indication_t* ind); +void mac_sr_ind(mac_t* mac, nfapi_sr_indication_t* ind); +void mac_cqi_ind(mac_t* mac, nfapi_cqi_indication_t* ind); +void mac_lbt_dl_ind(mac_t* mac, nfapi_lbt_dl_indication_t* ind); +void mac_nb_harq_ind(mac_t* mac, nfapi_nb_harq_indication_t* ind); +void mac_nrach_ind(mac_t* mac, nfapi_nrach_indication_t* ind); + + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/nfapi/open-nFAPI/vnf_sim/src/mac.cpp b/nfapi/open-nFAPI/vnf_sim/src/mac.cpp new file mode 100644 index 0000000000..fa6f487be8 --- /dev/null +++ b/nfapi/open-nFAPI/vnf_sim/src/mac.cpp @@ -0,0 +1,1327 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mac.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +uint32_t rand_range(uint32_t min, uint32_t max) +{ + return ((rand() % (max + 1 - min)) + min); +} + +struct mac_pdu +{ + mac_pdu() : buffer_len(1500), buffer(0), len(0) + { + buffer = (char*) malloc(buffer_len); + } + + virtual ~mac_pdu() + { + free(buffer); + } + + unsigned buffer_len; + char* buffer; + unsigned len; +}; + +class mac_private +{ + std::mutex mutex; + std::queue rx_buffer; + + std::queue free_store; + public: + + mac_private(bool _wireshark_test_mode) + : byte_count(0), tick(0), wireshark_test_mode(_wireshark_test_mode) + { + + } + + mac_pdu* allocate_mac_pdu() + { + mac_pdu* pdu = 0; + mutex.lock(); + if(free_store.empty()) + { + pdu = new mac_pdu(); + } + else + { + pdu = free_store.front(); + free_store.pop(); + } + mutex.unlock(); + return pdu; + } + + void release_mac_pdu(mac_pdu* pdu) + { + mutex.lock(); + free_store.push(pdu); + mutex.unlock(); + } + + + + void push_rx_buffer(mac_pdu* buff) + { + mutex.lock(); + rx_buffer.push(buff); + mutex.unlock(); + } + + mac_pdu* pop_rx_buffer() + { + mac_pdu* buff = 0; + mutex.lock(); + if(!rx_buffer.empty()) + { + buff = rx_buffer.front(); + rx_buffer.pop(); + } + mutex.unlock(); + return buff; + } + + uint32_t byte_count; + uint32_t tick; + + bool wireshark_test_mode; + +}; + +extern "C" +{ + typedef struct { + mac_t _public; + + int rx_sock; + int tx_sock; + struct sockaddr_in tx_addr; + + uint32_t tx_byte_count; + + mac_private* mac; + + } mac_internal_t; + + mac_t* mac_create(uint8_t wireshark_test_mode) + { + mac_internal_t* instance = (mac_internal_t*)malloc(sizeof(mac_internal_t)); + instance->mac = new mac_private((wireshark_test_mode >= 1)); + return (mac_t*)instance; + } + + void mac_destroy(mac_t* mac) + { + mac_internal_t* instance = (mac_internal_t*)mac; + delete instance->mac; + free(instance); + } + + void* mac_rx_thread_start(void* ptr) + { + mac_internal_t* instance = (mac_internal_t*)ptr; + + while(1) + { + mac_pdu* pdu = instance->mac->allocate_mac_pdu(); + int len = recvfrom(instance->rx_sock, pdu->buffer, pdu->buffer_len, 0, 0, 0); + if(len > 0) + { + pdu->len = len; + instance->mac->push_rx_buffer(pdu); + } + else + { + instance->mac->release_mac_pdu(pdu); + } + } + return 0; + } + + void mac_start_data(mac_t* mac, unsigned rx_port, const char* tx_address, unsigned tx_port) + { + mac_internal_t* instance = (mac_internal_t*)mac; + + printf("[MAC] Rx Data from %d\n", rx_port); + printf("[MAC] Tx Data to %s.%d\n", tx_address, tx_port); + + instance->rx_sock = socket(AF_INET, SOCK_DGRAM, 0); + + if(instance->rx_sock < 0) + { + printf("[MAC] Failed to create socket\n"); + return; + } + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(0)); + addr.sin_family = AF_INET; + addr.sin_port = htons(rx_port); + addr.sin_addr.s_addr = INADDR_ANY; + + if(bind(instance->rx_sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) + { + printf("[MAC] Failed to bind to %d\n", rx_port); + close(instance->rx_sock); + return; + } + + pthread_t mac_rx_thread; + pthread_create(&mac_rx_thread, NULL, &mac_rx_thread_start, instance); + + instance->tx_sock = socket(AF_INET, SOCK_DGRAM, 0); + instance->tx_addr.sin_family = AF_INET; + instance->tx_addr.sin_port = htons(tx_port); + instance->tx_addr.sin_addr.s_addr = inet_addr(tx_address); + } + + + + void generate_test_subframe(mac_t *mac, uint16_t phy_id, uint16_t sfn_sf) + { + //mac_internal_t* instance = (mac_internal_t*)mac; + + uint8_t max_num_dl_pdus = 50; + nfapi_dl_config_request_pdu_t dl_config_pdus[max_num_dl_pdus]; + memset(&dl_config_pdus, 0, sizeof(dl_config_pdus)); + + nfapi_dl_config_request_t dl_config_req; + memset(&dl_config_req, 0, sizeof(dl_config_req)); + dl_config_req.header.message_id = NFAPI_DL_CONFIG_REQUEST; + dl_config_req.header.phy_id = phy_id; + dl_config_req.sfn_sf = sfn_sf; + dl_config_req.dl_config_request_body.tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + + dl_config_req.dl_config_request_body.number_pdu = rand_range(4, max_num_dl_pdus); + + uint16_t i = 0; + for(i = 0; i < dl_config_req.dl_config_request_body.number_pdu; ++i) + { + dl_config_pdus[i].pdu_type = rand_range(0, 11); + + switch(dl_config_pdus[i].pdu_type) + { + case NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE: + { + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.dci_format = rand_range(0, 9); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = rand_range(0, 255); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = rand_range(0, 32); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti = rand_range(0, (uint16_t)-1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.resource_allocation_type = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = rand_range(0, 320000); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = rand_range(0, 31); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = rand_range(0, 3); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.transport_block_to_codeword_swap_flag = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.mcs_2 = rand_range(0, 31); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_2 = rand_range(0, 31); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_2 = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.harq_process = rand_range(0, 31); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.tpmi = rand_range(0, 15); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.pmi = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.precoding_information = rand_range(0, 63); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.tpc = rand_range(0, 3); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.downlink_assignment_index = rand_range(0, 15); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.ngap = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.transport_block_size_index = rand_range(0, 31); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.downlink_power_offset = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.allocate_prach_flag = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.preamble_index = rand_range(0, 63); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.prach_mask_index = rand_range(0, 15); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = rand_range(0, 3); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = rand_range(0, 10000); + + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel9.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL9_TAG; + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel9.mcch_flag = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel9.mcch_change_notification = rand_range(0, 255); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel9.scrambling_identity = rand_range(0, 1); + + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL10_TAG; + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel10.cross_carrier_scheduling_flag = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel10.carrier_indicator = rand_range(0, 7); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel10.srs_flag = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel10.srs_request = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel10.antenna_ports_scrambling_and_layers = rand_range(0, 15); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel10.total_dci_length_including_padding = rand_range(0, 255); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel10.n_dl_rb = rand_range(0, 100); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel11.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL11_TAG; + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel11.harq_ack_resource_offset = rand_range(0, 3); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel11.pdsch_re_mapping_quasi_co_location_indicator = rand_range(0, 3); + + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel12.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL12_TAG; + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel12.primary_cell_type = rand_range(0, 2); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel12.ul_dl_configuration_flag = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel12.number_ul_dl_configurations = 2; + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel12.ul_dl_configuration_indication[0] = rand_range(1, 5); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel12.ul_dl_configuration_indication[1] = rand_range(1, 5); + + + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL13_TAG; + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.laa_end_partial_sf_flag = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.laa_end_partial_sf_configuration = rand_range(0, 255); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.initial_lbt_sf = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.codebook_size_determination = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.drms_table_flag = rand_range(0, 1); + + // if the tpm extention is present of not. + if(rand_range(0, 1)) + { + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.tpm_struct_flag = rand_range(0, 1); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.tpm.num_prb_per_subband = rand_range(0, 8); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.tpm.number_of_subbands = rand_range(0, 13); + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.tpm.num_antennas = 1; // rand_range(0, 8); + + for(int j = 0; j < dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.tpm.number_of_subbands; ++j) + { + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.tpm.subband_info[j].subband_index = j; + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.tpm.subband_info[j].scheduled_ues = 1; //rand_range(1, 4); + + for(int k = 0; k < dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.tpm.num_antennas; ++k) + for(int l = 0; l < dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.tpm.subband_info[j].scheduled_ues; ++l) + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.tpm.subband_info[j].precoding_value[k][l] = rand_range(0, 65535); + } + } + else + { + dl_config_pdus[i].dci_dl_pdu.dci_dl_pdu_rel13.tpm_struct_flag = 0; + } + + } + break; + + case NFAPI_DL_CONFIG_BCH_PDU_TYPE: + { + dl_config_pdus[i].bch_pdu.bch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_BCH_PDU_REL8_TAG; + dl_config_pdus[i].bch_pdu.bch_pdu_rel8.length = rand_range(0, 42); + dl_config_pdus[i].bch_pdu.bch_pdu_rel8.pdu_index = rand_range(0, 65535); + dl_config_pdus[i].bch_pdu.bch_pdu_rel8.transmission_power = rand_range(0, 10000); + } + break; + + case NFAPI_DL_CONFIG_MCH_PDU_TYPE: + { + dl_config_pdus[i].mch_pdu.mch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_MCH_PDU_REL8_TAG; + dl_config_pdus[i].mch_pdu.mch_pdu_rel8.length = rand_range(0, 42); + dl_config_pdus[i].mch_pdu.mch_pdu_rel8.pdu_index = rand_range(0, 65535); + dl_config_pdus[i].mch_pdu.mch_pdu_rel8.rnti = 0xFFFD; + dl_config_pdus[i].mch_pdu.mch_pdu_rel8.resource_allocation_type = 0; + dl_config_pdus[i].mch_pdu.mch_pdu_rel8.resource_block_coding = 0; + dl_config_pdus[i].mch_pdu.mch_pdu_rel8.modulation = rand_range(0, 8); + dl_config_pdus[i].mch_pdu.mch_pdu_rel8.transmission_power = rand_range(0, 10000); + dl_config_pdus[i].mch_pdu.mch_pdu_rel8.mbsfn_area_id = rand_range(0, 255); + } + break; + + case NFAPI_DL_CONFIG_DLSCH_PDU_TYPE: + { + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.length = rand_range(0, 42); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.pdu_index = rand_range(0, 65535); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.rnti = rand_range(1, 65535); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = rand_range(0, 5); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = rand_range(0, 1); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = rand_range(0, 32000); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.modulation = rand_range(2, 8); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.redundancy_version = rand_range(0, 3); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.transport_blocks = rand_range(1, 2); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = rand_range(0, 1); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = rand_range(0, 13); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.number_of_layers = rand_range(1, 8); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 2; //rand_range(0, 13); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.codebook_index[0] = rand_range(0, 15); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.codebook_index[1] = rand_range(0, 15); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = rand_range(0, 14); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.pa = rand_range(0, 7); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = rand_range(0, 1); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.ngap = rand_range(0, 1); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.nprb = rand_range(0, 1); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.transmission_mode = rand_range(1, 10); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 2; //rand_range(0, 1); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 2; //rand_range(0, 1); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.bf_vector[0].subband_index = rand_range(0, 4); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.bf_vector[0].num_antennas = 1; + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.bf_vector[0].bf_value[0] = rand_range(0, 128); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.bf_vector[1].subband_index = rand_range(0, 4); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.bf_vector[1].num_antennas = 1; + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel8.bf_vector[1].bf_value[0] = rand_range(0, 128); + + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel9.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL9_TAG; + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel9.nscid = rand_range(0, 1); + + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG; + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel10.csi_rs_flag = rand_range(0, 1); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel10.csi_rs_resource_config_r10 = 0; + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel10.csi_rs_zero_tx_power_resource_config_bitmap_r10 = rand_range(0, 65535); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel10.csi_rs_number_nzp_configuration = 1; + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel10.csi_rs_resource_config[0] = rand_range(0, 31); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel10.pdsch_start = rand_range(0, 4); + + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel11.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL11_TAG; + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel11.drms_config_flag = rand_range(0, 1); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel11.drms_scrambling = rand_range(0, 503); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel11.csi_config_flag = rand_range(0, 1); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel11.csi_scrambling = rand_range(0, 503); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel11.pdsch_re_mapping_flag = rand_range(0, 1); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel11.pdsch_re_mapping_atenna_ports = rand_range(1,4); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel11.pdsch_re_mapping_freq_shift = rand_range(0, 5); + + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel12.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL12_TAG; + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel12.altcqi_table_r12 = rand_range(0, 1); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel12.maxlayers = rand_range(1, 8); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel12.n_dl_harq = rand_range(0, 255); + + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel13.dwpts_symbols = rand_range(3, 14); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel13.initial_lbt_sf = rand_range(0, 1); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel13.ue_type = rand_range(0, 2); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = rand_range(0, 2); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = rand_range(0, 10239); + dl_config_pdus[i].dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = rand_range(0, 1); + } + break; + + case NFAPI_DL_CONFIG_PCH_PDU_TYPE: + { + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_PCH_PDU_REL8_TAG; + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.length = rand_range(0, 42); + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.pdu_index = rand_range(0, 65535); + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.p_rnti = 0xFFFE; + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.resource_allocation_type = rand_range(2, 6); + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.virtual_resource_block_assignment_flag = rand_range(0, 1); + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.resource_block_coding = rand_range(0, 34000); + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.mcs = 0; + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.redundancy_version = 0; + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.number_of_transport_blocks = 1; + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.transmission_scheme = rand_range(1, 6); + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.number_of_layers = rand_range(1, 4); + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.codebook_index = 0; + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.ue_category_capacity = rand_range(0, 14); + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.pa = rand_range(0, 7); + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.transmission_power = rand_range(0, 10000); + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.nprb = rand_range(0, 1); + dl_config_pdus[i].pch_pdu.pch_pdu_rel8.ngap = rand_range(0, 1); + dl_config_pdus[i].pch_pdu.pch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_PCH_PDU_REL13_TAG; + dl_config_pdus[i].pch_pdu.pch_pdu_rel13.ue_mode = rand_range(0, 1); + dl_config_pdus[i].pch_pdu.pch_pdu_rel13.initial_transmission_sf_io = rand_range(0, 10239); + } + break; + + case NFAPI_DL_CONFIG_PRS_PDU_TYPE: + { + dl_config_pdus[i].prs_pdu.prs_pdu_rel9.tl.tag = NFAPI_DL_CONFIG_REQUEST_PRS_PDU_REL9_TAG; + dl_config_pdus[i].prs_pdu.prs_pdu_rel9.transmission_power = rand_range(0, 10000); + dl_config_pdus[i].prs_pdu.prs_pdu_rel9.prs_bandwidth = rand_range(6, 100); + dl_config_pdus[i].prs_pdu.prs_pdu_rel9.prs_cyclic_prefix_type = rand_range(0, 1); + dl_config_pdus[i].prs_pdu.prs_pdu_rel9.prs_muting = rand_range(0, 1); + } + break; + + case NFAPI_DL_CONFIG_CSI_RS_PDU_TYPE: + { + dl_config_pdus[i].csi_rs_pdu.csi_rs_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_CSI_RS_PDU_REL10_TAG; + dl_config_pdus[i].csi_rs_pdu.csi_rs_pdu_rel10.csi_rs_antenna_port_count_r10 = rand_range(1, 16); + dl_config_pdus[i].csi_rs_pdu.csi_rs_pdu_rel10.csi_rs_resource_config_r10 = 0; + dl_config_pdus[i].csi_rs_pdu.csi_rs_pdu_rel10.transmission_power = rand_range(0, 10000); + dl_config_pdus[i].csi_rs_pdu.csi_rs_pdu_rel10.csi_rs_zero_tx_power_resource_config_bitmap_r10 = rand_range(0, 8); + dl_config_pdus[i].csi_rs_pdu.csi_rs_pdu_rel10.csi_rs_number_of_nzp_configuration = 2; + dl_config_pdus[i].csi_rs_pdu.csi_rs_pdu_rel10.csi_rs_resource_config[0] = rand_range(0, 31); + dl_config_pdus[i].csi_rs_pdu.csi_rs_pdu_rel10.csi_rs_resource_config[1] = rand_range(0, 31); + dl_config_pdus[i].csi_rs_pdu.csi_rs_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_CSI_RS_PDU_REL13_TAG; + dl_config_pdus[i].csi_rs_pdu.csi_rs_pdu_rel13.csi_rs_class = rand_range(0, 2); + dl_config_pdus[i].csi_rs_pdu.csi_rs_pdu_rel13.cdm_type = rand_range(0, 1); + dl_config_pdus[i].csi_rs_pdu.csi_rs_pdu_rel13.num_bf_vector = 0; // set to zero as not clear how to handle bf value array + dl_config_pdus[i].csi_rs_pdu.csi_rs_pdu_rel13.bf_vector[0].csi_rs_resource_index = rand_range(0, 7); + dl_config_pdus[i].csi_rs_pdu.csi_rs_pdu_rel13.bf_vector[0].bf_value[0] = 42; + } + break; + + case NFAPI_DL_CONFIG_EPDCCH_DL_PDU_TYPE: + { + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL8_TAG; + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.dci_format = rand_range(0, 9); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.cce_idx = rand_range(0, 255); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.aggregation_level = rand_range(0, 32); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.rnti = rand_range(0, (uint16_t)-1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.resource_allocation_type = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.virtual_resource_block_assignment_flag = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.resource_block_coding = rand_range(0, 320000); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.mcs_1 = rand_range(0, 31); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.redundancy_version_1 = rand_range(0, 3); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.new_data_indicator_1 = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.transport_block_to_codeword_swap_flag = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.mcs_2 = rand_range(0, 31); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.redundancy_version_2 = rand_range(0, 31); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.new_data_indicator_2 = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.harq_process = rand_range(0, 31); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.tpmi = rand_range(0, 15); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.pmi = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.precoding_information = rand_range(0, 63); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.tpc = rand_range(0, 3); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.downlink_assignment_index = rand_range(0, 15); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.ngap = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.transport_block_size_index = rand_range(0, 31); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.downlink_power_offset = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.allocate_prach_flag = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.preamble_index = rand_range(0, 63); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.prach_mask_index = rand_range(0, 15); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.rnti_type = rand_range(0, 3); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel8.transmission_power = rand_range(0, 10000); + + + + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel9.tl.tag = NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL9_TAG; + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel9.mcch_flag = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel9.mcch_change_notification = rand_range(0, 255); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel9.scrambling_identity = rand_range(0, 1); + + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL10_TAG; + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel10.cross_carrier_scheduling_flag = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel10.carrier_indicator = rand_range(0, 7); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel10.srs_flag = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel10.srs_request = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel10.antenna_ports_scrambling_and_layers = rand_range(0, 15); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel10.total_dci_length_including_padding = rand_range(0, 255); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel10.n_dl_rb = rand_range(0, 100); + + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel11.tl.tag = NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL11_TAG; + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel11.harq_ack_resource_offset = rand_range(0, 3); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel11.pdsch_re_mapping_quasi_co_location_indicator = rand_range(0, 3); + + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel12.tl.tag = NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL12_TAG; + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel12.primary_cell_type = rand_range(0, 2); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel12.ul_dl_configuration_flag = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel12.number_ul_dl_configurations = 2; + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel12.ul_dl_configuration_indication[0] = rand_range(1, 5); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel12.ul_dl_configuration_indication[1] = rand_range(1, 5); + + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_EPDCCH_PDU_REL13_TAG; + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel13.laa_end_partial_sf_flag = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel13.laa_end_partial_sf_configuration = rand_range(0, 255); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel13.initial_lbt_sf = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel13.codebook_size_determination = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_pdu_rel13.drms_table_flag = rand_range(0, 1); + + dl_config_pdus[i].epdcch_pdu.epdcch_params_rel11.tl.tag = NFAPI_DL_CONFIG_REQUEST_EPDCCH_PARAM_REL11_TAG; + dl_config_pdus[i].epdcch_pdu.epdcch_params_rel11.epdcch_resource_assignment_flag = rand_range(0, 1); + dl_config_pdus[i].epdcch_pdu.epdcch_params_rel11.epdcch_id = rand_range(0, 503); + dl_config_pdus[i].epdcch_pdu.epdcch_params_rel11.epdcch_start_symbol = rand_range(1, 4); + dl_config_pdus[i].epdcch_pdu.epdcch_params_rel11.epdcch_num_prb = rand_range(2, 8); + for(int j = 0; j < dl_config_pdus[i].epdcch_pdu.epdcch_params_rel11.epdcch_num_prb; ++j) + dl_config_pdus[i].epdcch_pdu.epdcch_params_rel11.epdcch_prb_index[j] = rand_range(0, 99); + dl_config_pdus[i].epdcch_pdu.epdcch_params_rel11.bf_vector.subband_index = rand_range(0, 25); + dl_config_pdus[i].epdcch_pdu.epdcch_params_rel11.bf_vector.num_antennas= rand_range(1, 4); + for(int j = 0; j < dl_config_pdus[i].epdcch_pdu.epdcch_params_rel11.epdcch_num_prb; ++j) + dl_config_pdus[i].epdcch_pdu.epdcch_params_rel11.bf_vector.bf_value[j] = rand_range(0, 65535); + + + dl_config_pdus[i].epdcch_pdu.epdcch_params_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_EPDCCH_PARAM_REL13_TAG; + dl_config_pdus[i].epdcch_pdu.epdcch_params_rel13.dwpts_symbols = rand_range(3, 14); + dl_config_pdus[i].epdcch_pdu.epdcch_params_rel13.initial_lbt_sf = rand_range(0, 1); + } + break; + + case NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE: + { + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_MPDCCH_PDU_REL13_TAG; + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = rand_range(0, 15); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.number_of_prb_pairs = rand_range(2, 6); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment = rand_range(0, 14); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_tansmission_type = rand_range(0, 1); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.start_symbol = rand_range(1, 4); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.ecce_index = rand_range(0, 22); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level = rand_range(2, 24); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.rnti_type = rand_range(0, 4); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.rnti = rand_range(1, 65535); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = rand_range(1, 2); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.drms_scrambling_init = rand_range(0, 503); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.initial_transmission_sf_io = rand_range(0, 10239); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.transmission_power = rand_range(0, 10000); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.dci_format = rand_range(10, 12); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding = rand_range(0, 0xFFFF); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.mcs = rand_range(0, 15); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels = rand_range(1, 8); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version = rand_range(0, 3); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator = rand_range(0, 1); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.harq_process = rand_range(0, 15); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length = rand_range(0, 4); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.tpmi = rand_range(0, 15); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag = rand_range(0, 1); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.pmi = rand_range(0, 1); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.harq_resource_offset = rand_range(0, 3); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.dci_subframe_repetition_number = rand_range(1, 4); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.tpc = rand_range(0, 3); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index_length = rand_range(0, 4); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index = rand_range(0, 15); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.allocate_prach_flag = rand_range(0, 63); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.preamble_index = rand_range(0, 15); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index = rand_range(0, 3); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level = rand_range(0, 1); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.srs_request = rand_range(0, 1); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag = rand_range(0, 1); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity = rand_range(0, 3); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.frequency_hopping_enabled_flag = rand_range(0, 1); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag = rand_range(0, 1); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.direct_indication = rand_range(0, 255); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding = rand_range(0, 1); + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.number_of_tx_antenna_ports = rand_range(0, 8); + for(int j = 0 ; j < dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.number_of_tx_antenna_ports; ++j) + dl_config_pdus[i].mpdcch_pdu.mpdcch_pdu_rel13.precoding_value[j] = rand_range(0, 65535); + } + break; + + case NFAPI_DL_CONFIG_NBCH_PDU_TYPE: + { + dl_config_pdus[i].nbch_pdu.nbch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_NBCH_PDU_REL13_TAG; + dl_config_pdus[i].nbch_pdu.nbch_pdu_rel13.length = rand_range(0, 5555); + dl_config_pdus[i].nbch_pdu.nbch_pdu_rel13.pdu_index = rand_range(0, 65535); + dl_config_pdus[i].nbch_pdu.nbch_pdu_rel13.transmission_power = rand_range(0, 10000); + dl_config_pdus[i].nbch_pdu.nbch_pdu_rel13.hyper_sfn_2_lsbs = rand_range(0, 3); + } + break; + + case NFAPI_DL_CONFIG_NPDCCH_PDU_TYPE: + { + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_NPDCCH_PDU_REL13_TAG; + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.length = rand_range(0, 5555); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.pdu_index = rand_range(0, 65535); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.ncce_index = rand_range(0, 1); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.aggregation_level = rand_range(1, 2); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.start_symbol = rand_range(0, 4); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.rnti_type = rand_range(0, 3); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.rnti = rand_range(1, 65535); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.scrambling_reinitialization_batch_index = rand_range(1, 4); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.nrs_antenna_ports_assumed_by_the_ue = rand_range(1, 2); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.dci_format = rand_range(0, 1); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.scheduling_delay = rand_range(0, 7); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.resource_assignment = rand_range(0, 7); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.repetition_number = rand_range(0, 15); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.mcs = rand_range(0, 13); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.new_data_indicator = rand_range(0, 1); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.harq_ack_resource = rand_range(0, 15); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.npdcch_order_indication = rand_range(0, 1); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.starting_number_of_nprach_repetitions = rand_range(0, 3); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.subcarrier_indication_of_nprach = rand_range(0, 63); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.paging_direct_indication_differentation_flag = rand_range(0, 1); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.direct_indication = rand_range(0, 255); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.dci_subframe_repetition_number = rand_range(0, 7); + dl_config_pdus[i].npdcch_pdu.npdcch_pdu_rel13.total_dci_length_including_padding = rand_range(0, 255); + } + break; + + case NFAPI_DL_CONFIG_NDLSCH_PDU_TYPE: + { + dl_config_pdus[i].ndlsch_pdu.ndlsch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_NDLSCH_PDU_REL13_TAG; + dl_config_pdus[i].ndlsch_pdu.ndlsch_pdu_rel13.length = rand_range(0, 5555); + dl_config_pdus[i].ndlsch_pdu.ndlsch_pdu_rel13.pdu_index = rand_range(0, 65535); + dl_config_pdus[i].ndlsch_pdu.ndlsch_pdu_rel13.start_symbol = rand_range(0, 4); + dl_config_pdus[i].ndlsch_pdu.ndlsch_pdu_rel13.rnti_type = rand_range(0, 1); + dl_config_pdus[i].ndlsch_pdu.ndlsch_pdu_rel13.rnti = rand_range(1, 65535); + dl_config_pdus[i].ndlsch_pdu.ndlsch_pdu_rel13.resource_assignment = rand_range(0, 7); + dl_config_pdus[i].ndlsch_pdu.ndlsch_pdu_rel13.repetition_number = rand_range(0, 15); + dl_config_pdus[i].ndlsch_pdu.ndlsch_pdu_rel13.modulation = 2; + dl_config_pdus[i].ndlsch_pdu.ndlsch_pdu_rel13.number_of_subframes_for_resource_assignment = rand_range(1, 10); + dl_config_pdus[i].ndlsch_pdu.ndlsch_pdu_rel13.scrambling_sequence_initialization_cinit = rand_range(0, 65535); + dl_config_pdus[i].ndlsch_pdu.ndlsch_pdu_rel13.sf_idx = rand_range(1, 10240); + dl_config_pdus[i].ndlsch_pdu.ndlsch_pdu_rel13.nrs_antenna_ports_assumed_by_the_ue = rand_range(1, 2); + } + break; + + }; + } + + + dl_config_req.dl_config_request_body.dl_config_pdu_list = dl_config_pdus; + mac->dl_config_req(mac, &dl_config_req); + + uint8_t num_ul_pdus = 18; + nfapi_ul_config_request_pdu_t ul_config_pdus[num_ul_pdus]; + memset(&ul_config_pdus, 0, sizeof(ul_config_pdus)); + + nfapi_ul_config_request_t ul_config_req; + memset(&ul_config_req, 0, sizeof(ul_config_req)); + ul_config_req.header.message_id = NFAPI_UL_CONFIG_REQUEST; + ul_config_req.header.phy_id = phy_id; + ul_config_req.sfn_sf = sfn_sf; + ul_config_req.ul_config_request_body.tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + ul_config_req.ul_config_request_body.number_of_pdus = num_ul_pdus; + ul_config_req.ul_config_request_body.rach_prach_frequency_resources = rand_range(0, 255); + ul_config_req.ul_config_request_body.srs_present = rand_range(0, 1); + + auto ul_config_ulsch_pdu_test_gen = [](nfapi_ul_config_ulsch_pdu& ulsch_pdu) + { + ulsch_pdu.ulsch_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG; + ulsch_pdu.ulsch_pdu_rel8.handle = rand_range(0, 50000); + ulsch_pdu.ulsch_pdu_rel8.size = rand_range(0, 32000); + ulsch_pdu.ulsch_pdu_rel8.rnti = rand_range(1, 65535); + ulsch_pdu.ulsch_pdu_rel8.resource_block_start = rand_range(0, 99); + ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = rand_range(1, 100); + ulsch_pdu.ulsch_pdu_rel8.modulation_type = rand_range(2, 6); + ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = rand_range(0, 7); + ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_enabled_flag = rand_range(0, 1); + ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = rand_range(0, 3); + ulsch_pdu.ulsch_pdu_rel8.new_data_indication = rand_range(0, 1); + ulsch_pdu.ulsch_pdu_rel8.redundancy_version = rand_range(0, 3); + ulsch_pdu.ulsch_pdu_rel8.harq_process_number = rand_range(0, 15); + ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = rand_range(0, 1); + ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = rand_range(0, 5); + ulsch_pdu.ulsch_pdu_rel8.n_srs = rand_range(0, 1); + ulsch_pdu.ulsch_pdu_rel10.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL10_TAG; + ulsch_pdu.ulsch_pdu_rel10.resource_allocation_type = rand_range(0, 1); + ulsch_pdu.ulsch_pdu_rel10.resource_block_coding = rand_range(0, 35000); + ulsch_pdu.ulsch_pdu_rel10.transport_blocks = rand_range(1, 2); + ulsch_pdu.ulsch_pdu_rel10.transmission_scheme = rand_range(0, 1); + ulsch_pdu.ulsch_pdu_rel10.number_of_layers = rand_range(1, 4); + ulsch_pdu.ulsch_pdu_rel10.codebook_index = rand_range(0, 23); + ulsch_pdu.ulsch_pdu_rel10.disable_sequence_hopping_flag = rand_range(0, 1); + ulsch_pdu.ulsch_pdu_rel11.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL11_TAG; + ulsch_pdu.ulsch_pdu_rel11.virtual_cell_id_enabled_flag = rand_range(0, 1); + ulsch_pdu.ulsch_pdu_rel11.npusch_identity = rand_range(0, 509); + ulsch_pdu.ulsch_pdu_rel11.dmrs_config_flag = rand_range(0, 1); + ulsch_pdu.ulsch_pdu_rel11.ndmrs_csh_identity = rand_range(0, 509); + ulsch_pdu.ulsch_pdu_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL13_TAG; + ulsch_pdu.ulsch_pdu_rel13.ue_type = rand_range(0, 2); + ulsch_pdu.ulsch_pdu_rel13.total_number_of_repetitions = rand_range(1, 2048); + ulsch_pdu.ulsch_pdu_rel13.repetition_number = rand_range(1, 2048); + ulsch_pdu.ulsch_pdu_rel13.initial_transmission_sf_io = rand_range(0, 10239); + ulsch_pdu.ulsch_pdu_rel13.empty_symbols_due_to_re_tunning = rand_range(0, 8); + }; + + auto ul_config_cqi_ri_info_test_gen = [](nfapi_ul_config_cqi_ri_information& cqi_ri_information) + { + cqi_ri_information.cqi_ri_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL8_TAG; + cqi_ri_information.cqi_ri_information_rel8.dl_cqi_pmi_size_rank_1 = rand_range(0, 255); + cqi_ri_information.cqi_ri_information_rel8.dl_cqi_pmi_size_rank_greater_1 = rand_range(0, 255); + cqi_ri_information.cqi_ri_information_rel8.ri_size = rand_range(0, 3); + cqi_ri_information.cqi_ri_information_rel8.delta_offset_cqi = rand_range(0, 15); + cqi_ri_information.cqi_ri_information_rel8.delta_offset_ri = rand_range(0, 15); + + cqi_ri_information.cqi_ri_information_rel9.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL9_TAG; + cqi_ri_information.cqi_ri_information_rel9.report_type = 1; // rand_range(0, 1); + cqi_ri_information.cqi_ri_information_rel9.delta_offset_cqi = rand_range(0, 15); + cqi_ri_information.cqi_ri_information_rel9.delta_offset_ri = rand_range(0, 15); + + if(cqi_ri_information.cqi_ri_information_rel9.report_type == 0) + { + cqi_ri_information.cqi_ri_information_rel9.periodic_cqi_pmi_ri_report.dl_cqi_pmi_ri_size = rand_range(0, 255); + cqi_ri_information.cqi_ri_information_rel9.periodic_cqi_pmi_ri_report.control_type = rand_range(0, 1); + } + else + { + cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.number_of_cc = 1; + cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = rand_range(0, 3); + cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[0] = rand_range(0, 255); + } + + cqi_ri_information.cqi_ri_information_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL13_TAG; + cqi_ri_information.cqi_ri_information_rel13.report_type = rand_range(0, 1); + + if(cqi_ri_information.cqi_ri_information_rel13.report_type == 0) + { + cqi_ri_information.cqi_ri_information_rel13.periodic_cqi_pmi_ri_report.dl_cqi_pmi_ri_size_2 = rand_range(255, 10000); + } + }; + + auto ul_config_init_tx_params_test_gen = [](nfapi_ul_config_initial_transmission_parameters& initial_transmission_parameters) + { + initial_transmission_parameters.initial_transmission_parameters_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_INITIAL_TRANSMISSION_PARAMETERS_REL8_TAG; + initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial = rand_range(0, 1); + initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks = rand_range(1, 100); + }; + + auto ul_config_harqinfo_test_gen = [](nfapi_ul_config_ulsch_harq_information& harq_information) + { + harq_information.harq_information_rel10.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_HARQ_INFORMATION_REL10_TAG; + harq_information.harq_information_rel10.harq_size = rand_range(0, 21); + harq_information.harq_information_rel10.delta_offset_harq = rand_range(0, 15); + harq_information.harq_information_rel10.ack_nack_mode = rand_range(0, 5); + harq_information.harq_information_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_HARQ_INFORMATION_REL13_TAG; + harq_information.harq_information_rel13.harq_size_2 = rand_range(0, 21); + harq_information.harq_information_rel13.delta_offset_harq_2 = rand_range(0, 15); + }; + + auto ul_config_sr_info_test_gen = [](nfapi_ul_config_sr_information& sr_info) + { + sr_info.sr_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL8_TAG; + sr_info.sr_information_rel8.pucch_index = rand_range(0, 2047); + sr_info.sr_information_rel10.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL10_TAG; + sr_info.sr_information_rel10.number_of_pucch_resources = rand_range(1, 2); + sr_info.sr_information_rel10.pucch_index_p1 = rand_range(0, 2047); + }; + + auto ul_config_ue_info_test_gen = [](nfapi_ul_config_ue_information& ue_information) + { + ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; + ue_information.ue_information_rel8.handle = rand_range(0, 99999); + ue_information.ue_information_rel8.rnti = rand_range(1, 65535); + ue_information.ue_information_rel11.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL11_TAG; + ue_information.ue_information_rel11.virtual_cell_id_enabled_flag = rand_range(0, 1); + ue_information.ue_information_rel11.npusch_identity = rand_range(0, 503); + ue_information.ue_information_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL13_TAG; + ue_information.ue_information_rel13.ue_type = rand_range(0, 2); + ue_information.ue_information_rel13.empty_symbols = rand_range(0, 2); + ue_information.ue_information_rel13.total_number_of_repetitions = rand_range(1, 32); + ue_information.ue_information_rel13.repetition_number = rand_range(1, 32); + }; + + auto ul_config_cqi_info_test_gen = [](nfapi_ul_config_cqi_information& cqi_information) + { + cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG; + cqi_information.cqi_information_rel8.pucch_index = rand_range(0, 1184); + cqi_information.cqi_information_rel8.dl_cqi_pmi_size = rand_range(0, 255); + cqi_information.cqi_information_rel10.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL10_TAG; + cqi_information.cqi_information_rel10.number_of_pucch_resource = rand_range(1, 2); + cqi_information.cqi_information_rel10.pucch_index_p1 = rand_range(0, 1184); + cqi_information.cqi_information_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL13_TAG; + cqi_information.cqi_information_rel13.csi_mode = rand_range(0, 2); + cqi_information.cqi_information_rel13.dl_cqi_pmi_size_2 = rand_range(0, 999); + cqi_information.cqi_information_rel13.starting_prb = rand_range(0, 109); + cqi_information.cqi_information_rel13.n_prb = rand_range(0, 7); + cqi_information.cqi_information_rel13.cdm_index = rand_range(0, 1); + cqi_information.cqi_information_rel13.n_srs = rand_range(0, 1); + }; + + auto ul_config_harq_info_test_gen = [](nfapi_ul_config_harq_information& harq_information) + { + harq_information.harq_information_rel10_tdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG; + harq_information.harq_information_rel10_tdd.harq_size = rand_range(0, 21); + harq_information.harq_information_rel10_tdd.ack_nack_mode = rand_range(0, 5); + harq_information.harq_information_rel10_tdd.number_of_pucch_resources = rand_range(0, 4); + harq_information.harq_information_rel10_tdd.n_pucch_1_0 = rand_range(0, 2047); + harq_information.harq_information_rel10_tdd.n_pucch_1_1 = rand_range(0, 2047); + harq_information.harq_information_rel10_tdd.n_pucch_1_2 = rand_range(0, 2047); + harq_information.harq_information_rel10_tdd.n_pucch_1_3 = rand_range(0, 2047); + harq_information.harq_information_rel8_fdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL8_FDD_TAG; + harq_information.harq_information_rel8_fdd.n_pucch_1_0 = rand_range(0, 2047); + harq_information.harq_information_rel8_fdd.harq_size = rand_range(1, 2); + harq_information.harq_information_rel9_fdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG; + harq_information.harq_information_rel9_fdd.harq_size = rand_range(1, 10); + harq_information.harq_information_rel9_fdd.ack_nack_mode = rand_range(0, 4); + harq_information.harq_information_rel9_fdd.number_of_pucch_resources = rand_range(0, 4); + harq_information.harq_information_rel9_fdd.n_pucch_1_0 = rand_range(0, 2047); + harq_information.harq_information_rel9_fdd.n_pucch_1_1 = rand_range(0, 2047); + harq_information.harq_information_rel9_fdd.n_pucch_1_2 = rand_range(0, 2047); + harq_information.harq_information_rel9_fdd.n_pucch_1_3 = rand_range(0, 2047); + harq_information.harq_information_rel11.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL11_TAG; + harq_information.harq_information_rel11.num_ant_ports = rand_range(1, 2); + harq_information.harq_information_rel11.n_pucch_2_0 = rand_range(0, 2047); + harq_information.harq_information_rel11.n_pucch_2_1 = rand_range(0, 2047); + harq_information.harq_information_rel11.n_pucch_2_2 = rand_range(0, 2047); + harq_information.harq_information_rel11.n_pucch_2_3 = rand_range(0, 2047); + harq_information.harq_information_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL13_TAG; + harq_information.harq_information_rel13.harq_size_2 = rand_range(0, 999); + harq_information.harq_information_rel13.starting_prb = rand_range(0, 109); + harq_information.harq_information_rel13.n_prb = rand_range(0, 7); + harq_information.harq_information_rel13.cdm_index = rand_range(0, 1); + harq_information.harq_information_rel13.n_srs = rand_range(0, 1); + }; + + + ul_config_pdus[0].pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; + ul_config_ulsch_pdu_test_gen(ul_config_pdus[0].ulsch_pdu); + + ul_config_pdus[1].pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE; + ul_config_ulsch_pdu_test_gen(ul_config_pdus[1].ulsch_cqi_ri_pdu.ulsch_pdu); + ul_config_cqi_ri_info_test_gen(ul_config_pdus[1].ulsch_cqi_ri_pdu.cqi_ri_information); + ul_config_init_tx_params_test_gen(ul_config_pdus[1].ulsch_cqi_ri_pdu.initial_transmission_parameters); + + ul_config_pdus[2].pdu_type = NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE; + ul_config_ulsch_pdu_test_gen(ul_config_pdus[2].ulsch_harq_pdu.ulsch_pdu); + ul_config_harqinfo_test_gen(ul_config_pdus[2].ulsch_harq_pdu.harq_information); + ul_config_init_tx_params_test_gen(ul_config_pdus[2].ulsch_harq_pdu.initial_transmission_parameters); + + ul_config_pdus[3].pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE; + ul_config_ulsch_pdu_test_gen(ul_config_pdus[3].ulsch_cqi_harq_ri_pdu.ulsch_pdu); + ul_config_cqi_ri_info_test_gen(ul_config_pdus[3].ulsch_cqi_harq_ri_pdu.cqi_ri_information); + ul_config_harqinfo_test_gen(ul_config_pdus[3].ulsch_cqi_harq_ri_pdu.harq_information); + ul_config_init_tx_params_test_gen(ul_config_pdus[3].ulsch_cqi_harq_ri_pdu.initial_transmission_parameters); + + + ul_config_pdus[4].pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; + ul_config_ue_info_test_gen(ul_config_pdus[4].uci_cqi_pdu.ue_information); + ul_config_cqi_info_test_gen(ul_config_pdus[4].uci_cqi_pdu.cqi_information); + + ul_config_pdus[5].pdu_type = NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE; + ul_config_ue_info_test_gen(ul_config_pdus[5].uci_sr_pdu.ue_information); + ul_config_sr_info_test_gen(ul_config_pdus[5].uci_sr_pdu.sr_information); + + + ul_config_pdus[6].pdu_type = NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE; + ul_config_ue_info_test_gen(ul_config_pdus[6].uci_harq_pdu.ue_information); + ul_config_harq_info_test_gen(ul_config_pdus[6].uci_harq_pdu.harq_information); + + + ul_config_pdus[7].pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; + ul_config_ue_info_test_gen(ul_config_pdus[7].uci_sr_harq_pdu.ue_information); + ul_config_sr_info_test_gen(ul_config_pdus[7].uci_sr_harq_pdu.sr_information); + ul_config_harq_info_test_gen(ul_config_pdus[7].uci_sr_harq_pdu.harq_information); + + ul_config_pdus[8].pdu_type = NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE; + ul_config_ue_info_test_gen(ul_config_pdus[8].uci_cqi_harq_pdu.ue_information); + ul_config_cqi_info_test_gen(ul_config_pdus[8].uci_cqi_harq_pdu.cqi_information); + ul_config_harq_info_test_gen(ul_config_pdus[8].uci_cqi_harq_pdu.harq_information); + + ul_config_pdus[9].pdu_type = NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE; + ul_config_ue_info_test_gen(ul_config_pdus[9].uci_cqi_sr_pdu.ue_information); + ul_config_cqi_info_test_gen(ul_config_pdus[9].uci_cqi_sr_pdu.cqi_information); + ul_config_sr_info_test_gen(ul_config_pdus[9].uci_cqi_sr_pdu.sr_information); + + ul_config_pdus[10].pdu_type = NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE; + ul_config_ue_info_test_gen(ul_config_pdus[10].uci_cqi_sr_harq_pdu.ue_information); + ul_config_cqi_info_test_gen(ul_config_pdus[10].uci_cqi_sr_harq_pdu.cqi_information); + ul_config_sr_info_test_gen(ul_config_pdus[10].uci_cqi_sr_harq_pdu.sr_information); + ul_config_harq_info_test_gen(ul_config_pdus[10].uci_cqi_sr_harq_pdu.harq_information); + + ul_config_pdus[11].pdu_type = NFAPI_UL_CONFIG_SRS_PDU_TYPE; + ul_config_pdus[11].srs_pdu.srs_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL8_TAG; + ul_config_pdus[11].srs_pdu.srs_pdu_rel8.handle = rand_range(0, 9999); + ul_config_pdus[11].srs_pdu.srs_pdu_rel8.size = rand_range(1, 999); + ul_config_pdus[11].srs_pdu.srs_pdu_rel8.rnti = rand_range(1, 65535); + ul_config_pdus[11].srs_pdu.srs_pdu_rel8.srs_bandwidth = rand_range(0, 3); + ul_config_pdus[11].srs_pdu.srs_pdu_rel8.frequency_domain_position = rand_range(0, 23); + ul_config_pdus[11].srs_pdu.srs_pdu_rel8.srs_hopping_bandwidth = rand_range(0, 3); + ul_config_pdus[11].srs_pdu.srs_pdu_rel8.transmission_comb = rand_range(0, 3); + ul_config_pdus[11].srs_pdu.srs_pdu_rel8.i_srs = rand_range(0, 1023); + ul_config_pdus[11].srs_pdu.srs_pdu_rel8.sounding_reference_cyclic_shift = rand_range(0, 11); + ul_config_pdus[11].srs_pdu.srs_pdu_rel10.tl.tag = NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL10_TAG; + ul_config_pdus[11].srs_pdu.srs_pdu_rel10.antenna_port = rand_range(0, 2); + ul_config_pdus[11].srs_pdu.srs_pdu_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL13_TAG; + ul_config_pdus[11].srs_pdu.srs_pdu_rel13.number_of_combs = rand_range(0, 1); + + ul_config_pdus[12].pdu_type = NFAPI_UL_CONFIG_HARQ_BUFFER_PDU_TYPE; + ul_config_ue_info_test_gen(ul_config_pdus[12].harq_buffer_pdu.ue_information); + + ul_config_pdus[13].pdu_type = NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE; + ul_config_ulsch_pdu_test_gen(ul_config_pdus[13].ulsch_uci_csi_pdu.ulsch_pdu); + ul_config_cqi_info_test_gen(ul_config_pdus[13].ulsch_uci_csi_pdu.csi_information); + + ul_config_pdus[14].pdu_type = NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE; + ul_config_ulsch_pdu_test_gen(ul_config_pdus[14].ulsch_uci_harq_pdu.ulsch_pdu); + ul_config_harq_info_test_gen(ul_config_pdus[14].ulsch_uci_harq_pdu.harq_information); + + ul_config_pdus[15].pdu_type = NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE; + ul_config_ulsch_pdu_test_gen(ul_config_pdus[15].ulsch_csi_uci_harq_pdu.ulsch_pdu); + ul_config_cqi_info_test_gen(ul_config_pdus[15].ulsch_csi_uci_harq_pdu.csi_information); + ul_config_harq_info_test_gen(ul_config_pdus[15].ulsch_csi_uci_harq_pdu.harq_information); + + ul_config_pdus[16].pdu_type = NFAPI_UL_CONFIG_NULSCH_PDU_TYPE; + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_NULSCH_PDU_REL13_TAG; + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.nulsch_format = rand_range(0, 1); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.handle = rand_range(0, 0xFFFF); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.size = rand_range(0, 65535); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.rnti = rand_range(1, 65535); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.subcarrier_indication = rand_range(0, 47); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.resource_assignment = rand_range(0, 7); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.mcs = rand_range(0, 12); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.redudancy_version = rand_range(0, 1); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.repetition_number = rand_range(0, 7); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.new_data_indication = rand_range(0, 1); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.n_srs = rand_range(0, 1); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.scrambling_sequence_initialization_cinit = rand_range(0, 65535); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.sf_idx = rand_range(0, 40960); + + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.ue_information.ue_information_rel8.handle = rand_range(0, 0xFF); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.ue_information.ue_information_rel8.rnti = rand_range(1, 65535); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.ue_information.ue_information_rel11.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL11_TAG; + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.ue_information.ue_information_rel11.virtual_cell_id_enabled_flag = rand_range(0, 1); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.ue_information.ue_information_rel11.npusch_identity = rand_range(0, 503); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.ue_information.ue_information_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL13_TAG; + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.ue_information.ue_information_rel13.ue_type = rand_range(0, 2); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.ue_information.ue_information_rel13.empty_symbols = rand_range(0, 0x3); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.ue_information.ue_information_rel13.total_number_of_repetitions = rand_range(1, 32); + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.ue_information.ue_information_rel13.repetition_number = rand_range(1, 32); + + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.nb_harq_information.nb_harq_information_rel13_fdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_NB_HARQ_INFORMATION_REL13_FDD_TAG; + ul_config_pdus[16].nulsch_pdu.nulsch_pdu_rel13.nb_harq_information.nb_harq_information_rel13_fdd.harq_ack_resource = rand_range(0, 15); + + ul_config_pdus[17].pdu_type = NFAPI_UL_CONFIG_NRACH_PDU_TYPE; + ul_config_pdus[17].nrach_pdu.nrach_pdu_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_NRACH_PDU_REL13_TAG; + ul_config_pdus[17].nrach_pdu.nrach_pdu_rel13.nprach_config_0 = rand_range(0, 1); + ul_config_pdus[17].nrach_pdu.nrach_pdu_rel13.nprach_config_1 = rand_range(0, 1); + ul_config_pdus[17].nrach_pdu.nrach_pdu_rel13.nprach_config_2 = rand_range(0, 1); + + ul_config_req.ul_config_request_body.ul_config_pdu_list = ul_config_pdus; + mac->ul_config_req(mac, &ul_config_req); + + + uint8_t num_dci_pdus = 4; + uint8_t num_hi_pdus = 1; + nfapi_hi_dci0_request_pdu_t hi_dci0_pdus[num_dci_pdus + num_hi_pdus]; + memset(&hi_dci0_pdus, 0, sizeof(hi_dci0_pdus)); + + nfapi_hi_dci0_request_t hi_dci0_req; + memset(&hi_dci0_req, 0, sizeof(hi_dci0_req)); + hi_dci0_req.header.message_id = NFAPI_HI_DCI0_REQUEST; + hi_dci0_req.header.phy_id = phy_id; + hi_dci0_req.sfn_sf = sfn_sf; + + hi_dci0_req.hi_dci0_request_body.tl.tag = NFAPI_HI_DCI0_REQUEST_BODY_TAG; + hi_dci0_req.hi_dci0_request_body.sfnsf = sfn_sf; + hi_dci0_req.hi_dci0_request_body.number_of_dci = num_dci_pdus; + hi_dci0_req.hi_dci0_request_body.number_of_hi = num_hi_pdus; + + hi_dci0_pdus[0].pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; + hi_dci0_pdus[0].hi_pdu.hi_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_HI_PDU_REL8_TAG; + hi_dci0_pdus[0].hi_pdu.hi_pdu_rel8.resource_block_start = rand_range(0, 100); + hi_dci0_pdus[0].hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = rand_range(0, 7); + hi_dci0_pdus[0].hi_pdu.hi_pdu_rel8.hi_value = rand_range(0, 1); + hi_dci0_pdus[0].hi_pdu.hi_pdu_rel8.i_phich = rand_range(0, 1); + hi_dci0_pdus[0].hi_pdu.hi_pdu_rel8.transmission_power = rand_range(0, 10000); + hi_dci0_pdus[0].hi_pdu.hi_pdu_rel10.tl.tag = NFAPI_HI_DCI0_REQUEST_HI_PDU_REL10_TAG; + hi_dci0_pdus[0].hi_pdu.hi_pdu_rel10.flag_tb2 = rand_range(0, 1); + hi_dci0_pdus[0].hi_pdu.hi_pdu_rel10.hi_value_2 = rand_range(0, 1); + + hi_dci0_pdus[1].pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE; + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL8_TAG; + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.dci_format = rand_range(0, 4); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.cce_index = rand_range(0, 88); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.aggregation_level = rand_range(1, 8); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.rnti = rand_range(1, 65535); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.resource_block_start = rand_range(0, 100); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.number_of_resource_block = rand_range(0, 100); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.mcs_1 = rand_range(0, 31); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.cyclic_shift_2_for_drms = rand_range(0, 7); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.frequency_hopping_enabled_flag = rand_range(0, 1); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.frequency_hopping_bits = rand_range(0, 3); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.new_data_indication_1 = rand_range(0, 1); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.ue_tx_antenna_seleciton = rand_range(0, 2); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.tpc = rand_range(0, 3); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.cqi_csi_request = rand_range(0, 7); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.ul_index = rand_range(0, 3); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.dl_assignment_index = rand_range(1, 4); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.tpc_bitmap = rand_range(0, 9999); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel8.transmission_power = rand_range(0, 10000); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.tl.tag = NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL10_TAG; + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.cross_carrier_scheduling_flag = rand_range(0, 1); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.carrier_indicator = rand_range(0, 7); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.size_of_cqi_csi_feild = rand_range(0, 2); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.srs_flag = rand_range(0, 1); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.srs_request = rand_range(0, 1); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.resource_allocation_flag = rand_range(0, 1); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.resource_allocation_type = rand_range(0, 1); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.resource_block_coding = rand_range(0, 9999); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.mcs_2 = rand_range(0, 31); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.new_data_indication_2 = rand_range(0, 1); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.number_of_antenna_ports = rand_range(0, 2); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.tpmi = rand_range(0, 63); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.total_dci_length_including_padding = rand_range(0, 255); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel10.n_ul_rb = rand_range(6, 100); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel12.tl.tag = NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL12_TAG; + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel12.pscch_resource = rand_range(0, 16); + hi_dci0_pdus[1].dci_pdu.dci_pdu_rel12.time_resource_pattern = rand_range(0, 32); + + + hi_dci0_pdus[2].pdu_type = NFAPI_HI_DCI0_EPDCCH_DCI_PDU_TYPE; + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_EPDCCH_DCI_PDU_REL8_TAG; + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.dci_format = rand_range(0, 4); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.cce_index = rand_range(0, 88); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.aggregation_level = rand_range(1, 8); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.rnti = rand_range(1, 65535); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.resource_block_start = rand_range(0, 100); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.number_of_resource_block = rand_range(0, 100); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.mcs_1 = rand_range(0, 31); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.cyclic_shift_2_for_drms = rand_range(0, 7); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.frequency_hopping_enabled_flag = rand_range(0, 1); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.frequency_hopping_bits = rand_range(0, 3); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.new_data_indication_1 = rand_range(0, 1); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.ue_tx_antenna_seleciton = rand_range(0, 2); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.tpc = rand_range(0, 3); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.cqi_csi_request = rand_range(0, 7); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.ul_index = rand_range(0, 3); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.dl_assignment_index = rand_range(1, 4); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.tpc_bitmap = rand_range(0, 9999); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel8.transmission_power = rand_range(0, 10000); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.tl.tag = NFAPI_HI_DCI0_REQUEST_EPDCCH_DCI_PDU_REL10_TAG; + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.cross_carrier_scheduling_flag = rand_range(0, 1); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.carrier_indicator = rand_range(0, 7); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.size_of_cqi_csi_feild = rand_range(0, 2); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.srs_flag = rand_range(0, 1); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.srs_request = rand_range(0, 1); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.resource_allocation_flag = rand_range(0, 1); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.resource_allocation_type = rand_range(0, 1); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.resource_block_coding = rand_range(0, 9999); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.mcs_2 = rand_range(0, 31); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.new_data_indication_2 = rand_range(0, 1); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.number_of_antenna_ports = rand_range(0, 2); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.tpmi = rand_range(0, 63); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.total_dci_length_including_padding = rand_range(0, 255); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_dci_pdu_rel10.n_ul_rb = rand_range(6, 100); + hi_dci0_pdus[2].epdcch_dci_pdu.epdcch_parameters_rel11.tl.tag = NFAPI_HI_DCI0_REQUEST_EPDCCH_PARAMETERS_REL11_TAG; + + hi_dci0_pdus[3].pdu_type = NFAPI_HI_DCI0_MPDCCH_DCI_PDU_TYPE; + hi_dci0_pdus[3].mpdcch_dci_pdu.mpdcch_dci_pdu_rel13.tl.tag = NFAPI_HI_DCI0_REQUEST_MPDCCH_DCI_PDU_REL13_TAG; + + hi_dci0_pdus[4].pdu_type = NFAPI_HI_DCI0_NPDCCH_DCI_PDU_TYPE; + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.tl.tag = NFAPI_HI_DCI0_REQUEST_NPDCCH_DCI_PDU_REL13_TAG; + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.ncce_index = rand_range(0, 1); + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.aggregation_level = rand_range(1, 2); + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.start_symbol = rand_range(0, 4); + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.rnti = rand_range(1, 65535); + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.scrambling_reinitialization_batch_index = rand_range(1, 4); + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.nrs_antenna_ports_assumed_by_the_ue = rand_range(1, 2); + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.subcarrier_indication = rand_range(0, 63); + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.resource_assignment = rand_range(0, 7); + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.scheduling_delay = rand_range(0, 3); + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.mcs = rand_range(0, 12); + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.redudancy_version = rand_range(0, 1); + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.repetition_number = rand_range(0, 7); + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.new_data_indicator = rand_range(0, 1); + hi_dci0_pdus[4].npdcch_dci_pdu.npdcch_dci_pdu_rel13.dci_subframe_repetition_number = rand_range(0, 3); + + hi_dci0_req.hi_dci0_request_body.hi_dci0_pdu_list = hi_dci0_pdus; + mac->hi_dci0_req(mac, &hi_dci0_req); + + uint8_t num_tx_pdus = 2; + nfapi_tx_request_pdu_t tx_pdus[num_tx_pdus]; + memset(&tx_pdus, 0, sizeof(tx_pdus)); + + nfapi_tx_request_t tx_req; + memset(&tx_req, 0, sizeof(tx_req)); + tx_req.header.message_id = NFAPI_TX_REQUEST; + tx_req.header.phy_id = phy_id; + tx_req.sfn_sf = sfn_sf; + + tx_req.tx_request_body.tl.tag = NFAPI_TX_REQUEST_BODY_TAG; + tx_req.tx_request_body.number_of_pdus = num_tx_pdus; + + uint32_t data[2]; + data[0] = 0x11223344; + data[1] = 0x55667788; + + tx_pdus[0].pdu_length = 8; + tx_pdus[0].pdu_index = 1; + tx_pdus[0].num_segments = 2; + tx_pdus[0].segments[0].segment_length = 4; + tx_pdus[0].segments[0].segment_data = (uint8_t*)&data[0]; + tx_pdus[0].segments[1].segment_length = 4; + tx_pdus[0].segments[1].segment_data = (uint8_t*)&data[1]; + + tx_pdus[1].pdu_length = 8; + tx_pdus[1].pdu_index = 2; + tx_pdus[1].num_segments = 2; + tx_pdus[1].segments[0].segment_length = 4; + tx_pdus[1].segments[0].segment_data = (uint8_t*)&data[0]; + tx_pdus[1].segments[1].segment_length = 4; + tx_pdus[1].segments[1].segment_data = (uint8_t*)&data[1]; + + + tx_req.tx_request_body.tx_pdu_list = tx_pdus; + mac->tx_req(mac, &tx_req); + } + + void generate_subframe(mac_t *mac, uint16_t phy_id, uint16_t sfn_sf) + { + mac_internal_t* instance = (mac_internal_t*)mac; + + nfapi_dl_config_request_t dl_config_req; + memset(&dl_config_req, 0, sizeof(dl_config_req)); + dl_config_req.header.message_id = NFAPI_DL_CONFIG_REQUEST; + dl_config_req.header.phy_id = phy_id; + dl_config_req.sfn_sf = sfn_sf; + + dl_config_req.dl_config_request_body.tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + dl_config_req.dl_config_request_body.number_pdu = 8; + + nfapi_dl_config_request_pdu_t pdus[8]; + memset(&pdus, 0, sizeof(pdus)); + for(int i = 0; i < 8; i++) + { + pdus[i].pdu_type = NFAPI_DL_CONFIG_BCH_PDU_TYPE; + + pdus[i].bch_pdu.bch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_BCH_PDU_REL8_TAG; + pdus[i].bch_pdu.bch_pdu_rel8.length = 42; + pdus[i].bch_pdu.bch_pdu_rel8.pdu_index = i; + pdus[i].bch_pdu.bch_pdu_rel8.transmission_power = 56; + + } + + dl_config_req.dl_config_request_body.dl_config_pdu_list = pdus; + + /* + vendor_ext_tlv_1 ve; + ve.tl.tag = VENDOR_EXT_TLV_1_TAG; + ve.dummy = 999; + dl_config_req.vendor_extension = &ve.tl; + */ + + mac->dl_config_req(mac, &dl_config_req); + + + nfapi_ul_config_request_t ul_config_req; + memset(&ul_config_req, 0, sizeof(ul_config_req)); + ul_config_req.header.message_id = NFAPI_UL_CONFIG_REQUEST; + ul_config_req.header.phy_id = phy_id; + ul_config_req.sfn_sf = sfn_sf; + mac->ul_config_req(mac, &ul_config_req); + + nfapi_hi_dci0_request_t hi_dci0_req; + memset(&hi_dci0_req, 0, sizeof(hi_dci0_req)); + hi_dci0_req.header.message_id = NFAPI_HI_DCI0_REQUEST; + hi_dci0_req.header.phy_id = phy_id; + hi_dci0_req.sfn_sf = sfn_sf; + mac->hi_dci0_req(mac, &hi_dci0_req); + + + + nfapi_tx_request_t tx_req; + memset(&tx_req, 0, sizeof(tx_req)); + tx_req.header.message_id = NFAPI_TX_REQUEST; + tx_req.header.phy_id = phy_id; + tx_req.sfn_sf = sfn_sf; + + nfapi_tx_request_pdu_t tx_pdus[8]; + + tx_req.tx_request_body.tl.tag = NFAPI_TX_REQUEST_BODY_TAG; + tx_req.tx_request_body.number_of_pdus = 0; + tx_req.tx_request_body.tx_pdu_list = &tx_pdus[0]; + + mac_pdu* buff = 0; + int i = 0; + std::list free_list; + do + { + buff = instance->mac->pop_rx_buffer(); + if(buff != 0) + { + if(buff->len == 0) + { + printf("[MAC] Buffer length = 0\n"); + } + + tx_req.tx_request_body.tx_pdu_list[i].pdu_length = buff->len; + tx_req.tx_request_body.tx_pdu_list[i].pdu_index = i; + tx_req.tx_request_body.tx_pdu_list[i].num_segments = 1; + tx_req.tx_request_body.tx_pdu_list[i].segments[0].segment_length = buff->len; + tx_req.tx_request_body.tx_pdu_list[i].segments[0].segment_data = (uint8_t*)buff->buffer; + + tx_req.tx_request_body.number_of_pdus++; + i++; + + instance->mac->byte_count += buff->len; + + free_list.push_back(buff); + } + }while(buff != 0 && i < 8); + + mac->tx_req(mac, &tx_req); + + //for(int j = 0; j < tx_req.tx_request_body.number_of_pdus; ++j) + for(mac_pdu* pdu : free_list) + { + instance->mac->release_mac_pdu(pdu); + //free(tx_req.tx_request_body.tx_pdu_list[j].segments[0].segment_data); + } + } + + void mac_subframe_ind(mac_t *mac, uint16_t phy_id, uint16_t sfn_sf) + { + + + //printf("[MAC] subframe indication phyid:%d sfnsf:%d\n", phy_id, sfn_sf); + mac_internal_t* instance = (mac_internal_t*)mac; + + if(instance->mac->tick == 1000) + { + if(instance->mac->byte_count > 0) + { + printf("[MAC] Rx rate %d bytes/sec\n", instance->mac->byte_count); + instance->mac->byte_count = 0; + } + instance->mac->tick = 0; + } + instance->mac->tick++; + + if(instance->mac->wireshark_test_mode) + { + generate_test_subframe(mac, phy_id, sfn_sf); + } + else + { + generate_subframe(mac, phy_id, sfn_sf); + } + } + + void mac_harq_ind(mac_t* mac, nfapi_harq_indication_t* ind) + { + } + void mac_crc_ind(mac_t* mac, nfapi_crc_indication_t* ind) + { + } + void mac_rx_ind(mac_t* mac, nfapi_rx_indication_t* ind) + { + mac_internal_t* instance = (mac_internal_t*)mac; + + for(int i = 0; i < ind->rx_indication_body.number_of_pdus; ++i) + { + uint16_t len = ind->rx_indication_body.rx_pdu_list[i].rx_indication_rel8.length; + uint8_t* data = ind->rx_indication_body.rx_pdu_list[i].data; + //printf("[MAC] sfnsf:%d len:%d\n", ind->sfn_sf,len); + // + instance->tx_byte_count += len; + + int sendto_result = sendto(instance->tx_sock, data, len, 0, (struct sockaddr*)&(instance->tx_addr), sizeof(instance->tx_addr)); + + if(sendto_result < 0) + { + // error + } + } + + } + void mac_rach_ind(mac_t* mac, nfapi_rach_indication_t* ind) + { + } + void mac_srs_ind(mac_t* mac, nfapi_srs_indication_t* ind) + { + } + void mac_sr_ind(mac_t* mac, nfapi_sr_indication_t* ind) + { + } + void mac_cqi_ind(mac_t* mac, nfapi_cqi_indication_t* ind) + { + } + void mac_lbt_dl_ind(mac_t* mac, nfapi_lbt_dl_indication_t* ind) + { + } + void mac_nb_harq_ind(mac_t* mac, nfapi_nb_harq_indication_t* ind) + { + } + void mac_nrach_ind(mac_t* mac, nfapi_nrach_indication_t* ind) + { + } +} + diff --git a/nfapi/open-nFAPI/vnf_sim/src/main.cpp b/nfapi/open-nFAPI/vnf_sim/src/main.cpp new file mode 100644 index 0000000000..5dc7161157 --- /dev/null +++ b/nfapi/open-nFAPI/vnf_sim/src/main.cpp @@ -0,0 +1,1525 @@ +/* + * Copyright 2017 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include + +#include +#include "debug.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pool.h" + +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +#include "mac.h" + +#include + +//int vnf_main(int iPortP5, int, int); +int start_simulated_mac(int*, int*); +int read_xml(const char *xml_file); + +} + +static uint32_t rand_range(uint32_t min, uint32_t max) +{ + return ((rand() % (max + 1 - min)) + min); +} + + +void* vnf_allocate(size_t size) +{ + return (void*)memory_pool::allocate(size); +} + +void vnf_deallocate(void* ptr) +{ + memory_pool::deallocate((uint8_t*)ptr); +} + + + +class udp_data +{ + public: + bool enabled; + uint32_t rx_port; + uint32_t tx_port; + std::string tx_addr; +}; + + +class phy_info +{ + public: + + uint16_t index; + uint16_t id; + + std::vector rfs; + std::vector excluded_rfs; + + int remote_port; + std::string remote_addr; + + uint16_t earfcn; + +}; + +class rf_info +{ + public: + + uint16_t index; + uint16_t band; +}; + +class pnf_info +{ + public: + + std::vector phys; + std::vector rfs; +}; + +class vnf_p7_info +{ + public: + + vnf_p7_info() + : thread_started(false), + config(nfapi_vnf_p7_config_create(), + [] (nfapi_vnf_p7_config_t* f) { nfapi_vnf_p7_config_destory(f); }), + mac(0) + { + local_port = 0; + + timing_window = 0; + periodic_timing_enabled = 0; + aperiodic_timing_enabled = 0; + periodic_timing_period = 0; + + //config = nfapi_vnf_p7_config_create(); + } + + vnf_p7_info(const vnf_p7_info& other) = default; + + vnf_p7_info(vnf_p7_info&& other) = default; + + vnf_p7_info& operator=(const vnf_p7_info&) = default; + + vnf_p7_info& operator=(vnf_p7_info&&) = default; + + + + virtual ~vnf_p7_info() + { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "*** vnf_p7_info delete ***\n"); + + //nfapi_vnf_p7_config_destory(config); + + // should we delete the mac? + } + + + int local_port; + std::string local_addr; + + unsigned timing_window; + unsigned periodic_timing_enabled; + unsigned aperiodic_timing_enabled; + unsigned periodic_timing_period; + + // This is not really the right place if we have multiple PHY, + // should be part of the phy struct + udp_data udp; + + bool thread_started; + + //nfapi_vnf_p7_config_t* config; + std::shared_ptr config; + + mac_t* mac; + + +}; + +class vnf_info +{ + public: + + uint8_t wireshark_test_mode; + + std::map pnfs; + + std::vector p7_vnfs; + +}; + + +/// maybe these should be in the mac file... +int phy_unpack_vendor_extension_tlv(nfapi_tl_t* tl, uint8_t **ppReadPackedMessage, uint8_t *end, void** ve, nfapi_p7_codec_config_t* codec) +{ + (void)tl; + (void)ppReadPackedMessage; + (void)ve; + return -1; +} + +int phy_pack_vendor_extension_tlv(void* ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* codec) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "phy_pack_vendor_extension_tlv\n"); + + nfapi_tl_t* tlv = (nfapi_tl_t*)ve; + switch(tlv->tag) + { + case VENDOR_EXT_TLV_1_TAG: + { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "Packing VENDOR_EXT_TLV_1\n"); + vendor_ext_tlv_1* ve = (vendor_ext_tlv_1*)tlv; + if(!push32(ve->dummy, ppWritePackedMsg, end)) + return 0; + return 1; + } + break; + default: + return -1; + break; + } +} + +int vnf_sim_pack_vendor_extension_tlv(void* ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* codec) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "pnf_sim_pack_vendor_extension_tlv\n"); + nfapi_tl_t* tlv = (nfapi_tl_t*)ve; + switch(tlv->tag) + { + case VENDOR_EXT_TLV_2_TAG: + { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "Packing VENDOR_EXT_TLV_2\n"); + vendor_ext_tlv_2* ve = (vendor_ext_tlv_2*)tlv; + if(!push32(ve->dummy, ppWritePackedMsg, end)) + return 0; + return 1; + } + break; + } + return -1; +} + +int vnf_sim_unpack_vendor_extension_tlv(nfapi_tl_t* tl, uint8_t **ppReadPackedMessage, uint8_t *end, void** ve, nfapi_p4_p5_codec_config_t* codec) +{ + return -1; +} + + + + +int phy_unpack_p7_vendor_extension(nfapi_p7_message_header_t* header, uint8_t** ppReadPackedMessage, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if(header->message_id == P7_VENDOR_EXT_IND) + { + vendor_ext_p7_ind* req = (vendor_ext_p7_ind*)(header); + if(!pull16(ppReadPackedMessage, &req->error_code, end)) + return 0; + } + return 1; +} + +int phy_pack_p7_vendor_extension(nfapi_p7_message_header_t* header, uint8_t** ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if(header->message_id == P7_VENDOR_EXT_REQ) + { + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + vendor_ext_p7_req* req = (vendor_ext_p7_req*)(header); + if(!(push16(req->dummy1, ppWritePackedMsg, end) && + push16(req->dummy2, ppWritePackedMsg, end))) + return 0; + } + return 1; +} + +int vnf_sim_unpack_p4_p5_vendor_extension(nfapi_p4_p5_message_header_t* header, uint8_t** ppReadPackedMessage, uint8_t *end, nfapi_p4_p5_codec_config_t* codec) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if(header->message_id == P5_VENDOR_EXT_RSP) + { + vendor_ext_p5_rsp* req = (vendor_ext_p5_rsp*)(header); + return(!pull16(ppReadPackedMessage, &req->error_code, end)); + } + return 0; +} + +int vnf_sim_pack_p4_p5_vendor_extension(nfapi_p4_p5_message_header_t* header, uint8_t** ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t* codec) +{ + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if(header->message_id == P5_VENDOR_EXT_REQ) + { + vendor_ext_p5_req* req = (vendor_ext_p5_req*)(header); + //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s %d %d\n", __FUNCTION__, req->dummy1, req->dummy2); + return (!(push16(req->dummy1, ppWritePackedMsg, end) && + push16(req->dummy2, ppWritePackedMsg, end))); + } + return 0; +} + +void vnf_sim_trace(nfapi_trace_level_t level, const char* message, ...) +{ + va_list args; + va_start(args, message); + vprintf(message, args); + va_end(args); +} + +void mac_dl_config_req(mac_t* mac, nfapi_dl_config_request_t* req) +{ + vnf_p7_info* info = (vnf_p7_info*)(mac->user_data); + + nfapi_vnf_p7_dl_config_req(info->config.get(), req); +} + +void mac_ul_config_req(mac_t* mac, nfapi_ul_config_request_t* req) +{ + vnf_p7_info* info = (vnf_p7_info*)(mac->user_data); + + nfapi_vnf_p7_ul_config_req(info->config.get(), req); +} + +void mac_hi_dci0_req(mac_t* mac, nfapi_hi_dci0_request_t* req) +{ + vnf_p7_info* info = (vnf_p7_info*)(mac->user_data); + + nfapi_vnf_p7_hi_dci0_req(info->config.get(), req); +} + +void mac_tx_req(mac_t* mac, nfapi_tx_request_t* req) +{ + vnf_p7_info* info = (vnf_p7_info*)(mac->user_data); + + nfapi_vnf_p7_tx_req(info->config.get(), req); +} + +int phy_subframe_indication(struct nfapi_vnf_p7_config* config, uint16_t phy_id, uint16_t sfn_sf) +{ + //printf("[VNF_SIM] subframe indication %d\n", sfn_sf); + vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + mac_subframe_ind(p7_vnf->mac, phy_id, sfn_sf); + return 0; +} +int phy_harq_indication(struct nfapi_vnf_p7_config* config, nfapi_harq_indication_t* ind) +{ + vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + mac_harq_ind(p7_vnf->mac, ind); + return 1; +} +int phy_crc_indication(struct nfapi_vnf_p7_config* config, nfapi_crc_indication_t* ind) +{ + vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + mac_crc_ind(p7_vnf->mac, ind); + return 1; +} +int phy_rx_indication(struct nfapi_vnf_p7_config* config, nfapi_rx_indication_t* ind) +{ + vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + mac_rx_ind(p7_vnf->mac, ind); + return 1; +} +int phy_rach_indication(struct nfapi_vnf_p7_config* config, nfapi_rach_indication_t* ind) +{ + vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + mac_rach_ind(p7_vnf->mac, ind); + return 1; +} +int phy_srs_indication(struct nfapi_vnf_p7_config* config, nfapi_srs_indication_t* ind) +{ + vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + mac_srs_ind(p7_vnf->mac, ind); + return 1; +} +int phy_sr_indication(struct nfapi_vnf_p7_config* config, nfapi_sr_indication_t* ind) +{ + vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + mac_sr_ind(p7_vnf->mac, ind); + return 1; +} +int phy_cqi_indication(struct nfapi_vnf_p7_config* config, nfapi_cqi_indication_t* ind) +{ + vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + mac_cqi_ind(p7_vnf->mac, ind); + return 1; +} +int phy_lbt_dl_indication(struct nfapi_vnf_p7_config* config, nfapi_lbt_dl_indication_t* ind) +{ + vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + mac_lbt_dl_ind(p7_vnf->mac, ind); + return 1; +} +int phy_nb_harq_indication(struct nfapi_vnf_p7_config* config, nfapi_nb_harq_indication_t* ind) +{ + vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + mac_nb_harq_ind(p7_vnf->mac, ind); + return 1; +} +int phy_nrach_indication(struct nfapi_vnf_p7_config* config, nfapi_nrach_indication_t* ind) +{ + vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + mac_nrach_ind(p7_vnf->mac, ind); + return 1; +} +int phy_vendor_ext(struct nfapi_vnf_p7_config* config, nfapi_p7_message_header_t* msg) +{ + if(msg->message_id == P7_VENDOR_EXT_IND) + { + //vendor_ext_p7_ind* ind = (vendor_ext_p7_ind*)msg; + //printf("[VNF_SIM] vendor_ext (error_code:%d)\n", ind->error_code); + } + else + { + printf("[VNF_SIM] unknown %d\n", msg->message_id); + } + return 0; +} +nfapi_p7_message_header_t* phy_allocate_p7_vendor_ext(uint16_t message_id, uint16_t* msg_size) +{ + if(message_id == P7_VENDOR_EXT_IND) + { + *msg_size = sizeof(vendor_ext_p7_ind); + return (nfapi_p7_message_header_t*)malloc(sizeof(vendor_ext_p7_ind)); + } + return 0; +} +void phy_deallocate_p7_vendor_ext(nfapi_p7_message_header_t* header) +{ + free(header); +} + +//static pthread_t vnf_start_pthread; +static pthread_t vnf_p7_start_pthread; +void* vnf_p7_start_thread(void *ptr) +{ + printf("%s()\n", __FUNCTION__); + + //std::shared_ptr config = std::shared_ptr(ptr); + nfapi_vnf_p7_config_t *config = (nfapi_vnf_p7_config_t *)ptr; + + nfapi_vnf_p7_start(config); + + return 0; +} + +void set_thread_priority(int priority) +{ + //printf("%s(priority:%d)\n", __FUNCTION__, priority); + + pthread_attr_t ptAttr; + + struct sched_param schedParam; + schedParam.__sched_priority = priority; //79; + if(sched_setscheduler(0, SCHED_RR, &schedParam) != 0) + { + printf("Failed to set scheduler to SCHED_RR\n"); + } + + if(pthread_attr_setschedpolicy(&ptAttr, SCHED_RR) != 0) + { + printf("Failed to set pthread sched policy SCHED_RR\n"); + } + + pthread_attr_setinheritsched(&ptAttr, PTHREAD_EXPLICIT_SCHED); + + struct sched_param thread_params; + thread_params.sched_priority = 20; + if(pthread_attr_setschedparam(&ptAttr, &thread_params) != 0) + { + printf("failed to set sched param\n"); + } +} + +void* vnf_p7_thread_start(void* ptr) +{ + printf("%s()\n", __FUNCTION__); + + set_thread_priority(79); + + vnf_p7_info* p7_vnf = (vnf_p7_info*)ptr; + + p7_vnf->config->port = p7_vnf->local_port; + p7_vnf->config->subframe_indication = &phy_subframe_indication; + p7_vnf->config->harq_indication = &phy_harq_indication; + p7_vnf->config->crc_indication = &phy_crc_indication; + p7_vnf->config->rx_indication = &phy_rx_indication; + p7_vnf->config->rach_indication = &phy_rach_indication; + p7_vnf->config->srs_indication = &phy_srs_indication; + p7_vnf->config->sr_indication = &phy_sr_indication; + p7_vnf->config->cqi_indication = &phy_cqi_indication; + p7_vnf->config->lbt_dl_indication = &phy_lbt_dl_indication; + p7_vnf->config->nb_harq_indication = &phy_nb_harq_indication; + p7_vnf->config->nrach_indication = &phy_nrach_indication; + p7_vnf->config->malloc = &vnf_allocate; + p7_vnf->config->free = &vnf_deallocate; + + p7_vnf->config->trace = &vnf_sim_trace; + + p7_vnf->config->vendor_ext = &phy_vendor_ext; + p7_vnf->config->user_data = p7_vnf; + + p7_vnf->mac->user_data = p7_vnf; + + p7_vnf->config->codec_config.unpack_p7_vendor_extension = &phy_unpack_p7_vendor_extension; + p7_vnf->config->codec_config.pack_p7_vendor_extension = &phy_pack_p7_vendor_extension; + p7_vnf->config->codec_config.unpack_vendor_extension_tlv = &phy_unpack_vendor_extension_tlv; + p7_vnf->config->codec_config.pack_vendor_extension_tlv = &phy_pack_vendor_extension_tlv; + p7_vnf->config->codec_config.allocate = &vnf_allocate; + p7_vnf->config->codec_config.deallocate = &vnf_deallocate; + + p7_vnf->config->allocate_p7_vendor_ext = &phy_allocate_p7_vendor_ext; + p7_vnf->config->deallocate_p7_vendor_ext = &phy_deallocate_p7_vendor_ext; + + printf("[VNF] Creating VNF NFAPI start thread %s\n", __FUNCTION__); + pthread_create(&vnf_p7_start_pthread, NULL, &vnf_p7_start_thread, p7_vnf->config.get()); + + return 0; +} + +int pnf_connection_indication_cb(nfapi_vnf_config_t* config, int p5_idx) +{ + printf("[VNF_SIM] pnf connection indication idx:%d\n", p5_idx); + + pnf_info pnf; + vnf_info* vnf = (vnf_info*)(config->user_data); + vnf->pnfs.insert(std::pair(p5_idx, pnf)); + + nfapi_pnf_param_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PNF_PARAM_REQUEST; + nfapi_vnf_pnf_param_req(config, p5_idx, &req); + return 0; +} +int pnf_disconnection_indication_cb(nfapi_vnf_config_t* config, int p5_idx) +{ + printf("[VNF_SIM] pnf disconnection indication idx:%d\n", p5_idx); + + + vnf_info* vnf = (vnf_info*)(config->user_data); + auto find_result = vnf->pnfs.find(p5_idx); + + if(find_result != vnf->pnfs.end()) + { + pnf_info& pnf = find_result->second; + + for(phy_info& phy : pnf.phys) + { + vnf_p7_info& p7_vnf = vnf->p7_vnfs[0]; + nfapi_vnf_p7_del_pnf((p7_vnf.config.get()), phy.id); + } + } + + return 0; +} + +int pnf_param_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_param_response_t* resp) +{ + printf("[VNF_SIM] pnf param response idx:%d error:%d\n", p5_idx, resp->error_code); + + vnf_info* vnf = (vnf_info*)(config->user_data); + + auto find_result = vnf->pnfs.find(p5_idx); + if(find_result != vnf->pnfs.end()) + { + pnf_info& pnf = find_result->second; + + for(int i = 0; i < resp->pnf_phy.number_of_phys; ++i) + { + phy_info phy; + phy.index = resp->pnf_phy.phy[i].phy_config_index; + + printf("[VNF_SIM] (PHY:%d) phy_config_idx:%d\n", i, resp->pnf_phy.phy[i].phy_config_index); + + nfapi_vnf_allocate_phy(config, p5_idx, &(phy.id)); + + + + for(int j = 0; j < resp->pnf_phy.phy[i].number_of_rfs; ++j) + { + printf("[VNF_SIM] (PHY:%d) (RF%d) %d\n", i, j, resp->pnf_phy.phy[i].rf_config[j].rf_config_index); + phy.rfs.push_back(resp->pnf_phy.phy[i].rf_config[j].rf_config_index); + } + + + pnf.phys.push_back(phy); + } + for(int i = 0; i < resp->pnf_rf.number_of_rfs; ++i) + { + rf_info rf; + rf.index = resp->pnf_rf.rf[i].rf_config_index; + + printf("[VNF_SIM] (RF:%d) rf_config_idx:%d\n", i, resp->pnf_rf.rf[i].rf_config_index); + + pnf.rfs.push_back(rf); + } + + nfapi_pnf_config_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PNF_CONFIG_REQUEST; + + req.pnf_phy_rf_config.tl.tag = NFAPI_PNF_PHY_RF_TAG; + req.pnf_phy_rf_config.number_phy_rf_config_info = pnf.phys.size(); + + for(unsigned i = 0; i < pnf.phys.size(); ++i) + { + req.pnf_phy_rf_config.phy_rf_config[i].phy_id = pnf.phys[i].id; + req.pnf_phy_rf_config.phy_rf_config[i].phy_config_index = pnf.phys[i].index; + req.pnf_phy_rf_config.phy_rf_config[i].rf_config_index = pnf.phys[i].rfs[0]; + } + + + nfapi_vnf_pnf_config_req(config, p5_idx, &req); + } + return 0; +} + +int pnf_config_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_config_response_t* resp) +{ + printf("[VNF_SIM] pnf config response idx:%d\n", p5_idx); + + if(1) + { + vnf_info* vnf = (vnf_info*)(config->user_data); + auto find_result = vnf->pnfs.find(p5_idx); + if(find_result != vnf->pnfs.end()) + { + //pnf_info& pnf = find_result->second; + + nfapi_pnf_start_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PNF_START_REQUEST; + nfapi_vnf_pnf_start_req(config, p5_idx, &req); + } + } + else + { + // Rather than send the pnf_start_request we will demonstrate + // sending a vendor extention message. The start request will be + // send when the vendor extension response is received + + //vnf_info* vnf = (vnf_info*)(config->user_data); + vendor_ext_p5_req req; + memset(&req, 0, sizeof(req)); + req.header.message_id = P5_VENDOR_EXT_REQ; + req.dummy1 = 45; + req.dummy2 = 1977; + nfapi_vnf_vendor_extension(config, p5_idx, &req.header); + } + return 0; +} + +int pnf_start_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_start_response_t* resp) +{ + printf("[VNF_SIM] pnf start response idx:%d\n", p5_idx); + + vnf_info* vnf = (vnf_info*)(config->user_data); + vnf_p7_info& p7_vnf = vnf->p7_vnfs[0]; + + if(p7_vnf.thread_started == false) + { + pthread_t vnf_p7_thread; + pthread_create(&vnf_p7_thread, NULL, &vnf_p7_thread_start, &p7_vnf); + p7_vnf.thread_started = true; + } + else + { + // P7 thread already running. + } + + // start all the phys in the pnf. + + auto find_result = vnf->pnfs.find(p5_idx); + if(find_result != vnf->pnfs.end()) + { + pnf_info& pnf = find_result->second; + + for(unsigned i = 0; i < pnf.phys.size(); ++i) + { + pnf_info& pnf = find_result->second; + + nfapi_param_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PARAM_REQUEST; + req.header.phy_id = pnf.phys[i].id; + nfapi_vnf_param_req(config, p5_idx, &req); + } + } + + return 0; +} +int param_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_param_response_t* resp) +{ + printf("[VNF_SIM] param response idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id); + + vnf_info* vnf = (vnf_info*)(config->user_data); + + auto find_result = vnf->pnfs.find(p5_idx); + if(find_result != vnf->pnfs.end()) + { + pnf_info& pnf = find_result->second; + + + auto found = std::find_if(pnf.phys.begin(), pnf.phys.end(), [&](phy_info& item) + { return item.id == resp->header.phy_id; }); + + if(found != pnf.phys.end()) + { + phy_info& phy = (*found); + + phy.remote_port = resp->nfapi_config.p7_pnf_port.value; + + struct sockaddr_in pnf_p7_sockaddr; + memcpy(&pnf_p7_sockaddr.sin_addr.s_addr, &(resp->nfapi_config.p7_pnf_address_ipv4.address[0]), 4); + + phy.remote_addr = inet_ntoa(pnf_p7_sockaddr.sin_addr); + + // for now just 1 + vnf_p7_info& p7_vnf = vnf->p7_vnfs[0]; + + printf("[VNF_SIM] %d.%d pnf p7 %s:%d timing %d %d %d %d\n", p5_idx, phy.id, phy.remote_addr.c_str(), phy.remote_port, p7_vnf.timing_window, p7_vnf.periodic_timing_period, p7_vnf.aperiodic_timing_enabled, p7_vnf.periodic_timing_period); + + + nfapi_config_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_CONFIG_REQUEST; + req.header.phy_id = phy.id; + + + req.nfapi_config.p7_vnf_port.tl.tag = NFAPI_NFAPI_P7_VNF_PORT_TAG; + req.nfapi_config.p7_vnf_port.value = p7_vnf.local_port; + req.num_tlv++; + + req.nfapi_config.p7_vnf_address_ipv4.tl.tag = NFAPI_NFAPI_P7_VNF_ADDRESS_IPV4_TAG; + struct sockaddr_in vnf_p7_sockaddr; + vnf_p7_sockaddr.sin_addr.s_addr = inet_addr(p7_vnf.local_addr.c_str()); + memcpy(&(req.nfapi_config.p7_vnf_address_ipv4.address[0]), &vnf_p7_sockaddr.sin_addr.s_addr, 4); + req.num_tlv++; + + req.nfapi_config.timing_window.tl.tag = NFAPI_NFAPI_TIMING_WINDOW_TAG; + req.nfapi_config.timing_window.value = p7_vnf.timing_window; + req.num_tlv++; + + if(p7_vnf.periodic_timing_enabled || p7_vnf.aperiodic_timing_enabled) + { + req.nfapi_config.timing_info_mode.tl.tag = NFAPI_NFAPI_TIMING_INFO_MODE_TAG; + req.nfapi_config.timing_info_mode.value = (p7_vnf.aperiodic_timing_enabled << 1) | (p7_vnf.periodic_timing_enabled); + req.num_tlv++; + + if(p7_vnf.periodic_timing_enabled) + { + req.nfapi_config.timing_info_period.tl.tag = NFAPI_NFAPI_TIMING_INFO_PERIOD_TAG; + req.nfapi_config.timing_info_period.value = p7_vnf.periodic_timing_period; + req.num_tlv++; + } + } + + req.nfapi_config.earfcn.tl.tag = NFAPI_NFAPI_EARFCN_TAG; + req.nfapi_config.earfcn.value = phy.earfcn; + req.num_tlv++; + + + if(1) + { + // Poplate all tlv for wireshark testing + req.subframe_config.duplex_mode.tl.tag = NFAPI_SUBFRAME_CONFIG_DUPLEX_MODE_TAG; + req.num_tlv++; + + req.subframe_config.pcfich_power_offset.tl.tag = NFAPI_SUBFRAME_CONFIG_PCFICH_POWER_OFFSET_TAG; + req.num_tlv++; + req.subframe_config.pb.tl.tag = NFAPI_SUBFRAME_CONFIG_PB_TAG; + req.num_tlv++; + req.subframe_config.dl_cyclic_prefix_type.tl.tag = NFAPI_SUBFRAME_CONFIG_DL_CYCLIC_PREFIX_TYPE_TAG; + req.num_tlv++; + req.subframe_config.ul_cyclic_prefix_type.tl.tag = NFAPI_SUBFRAME_CONFIG_UL_CYCLIC_PREFIX_TYPE_TAG; + req.num_tlv++; + + req.rf_config.dl_channel_bandwidth.tl.tag = NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG; + req.num_tlv++; + req.rf_config.ul_channel_bandwidth.tl.tag = NFAPI_RF_CONFIG_UL_CHANNEL_BANDWIDTH_TAG; + req.num_tlv++; + req.rf_config.reference_signal_power.tl.tag = NFAPI_RF_CONFIG_REFERENCE_SIGNAL_POWER_TAG; + req.num_tlv++; + req.rf_config.tx_antenna_ports.tl.tag = NFAPI_RF_CONFIG_TX_ANTENNA_PORTS_TAG; + req.num_tlv++; + req.rf_config.rx_antenna_ports.tl.tag = NFAPI_RF_CONFIG_RX_ANTENNA_PORTS_TAG; + req.num_tlv++; + + req.phich_config.phich_resource.tl.tag = NFAPI_PHICH_CONFIG_PHICH_RESOURCE_TAG; + req.num_tlv++; + req.phich_config.phich_duration.tl.tag = NFAPI_PHICH_CONFIG_PHICH_DURATION_TAG; + req.num_tlv++; + req.phich_config.phich_power_offset.tl.tag = NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG; + req.num_tlv++; + + req.sch_config.primary_synchronization_signal_epre_eprers.tl.tag = NFAPI_SCH_CONFIG_PRIMARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG; + req.num_tlv++; + req.sch_config.secondary_synchronization_signal_epre_eprers.tl.tag = NFAPI_SCH_CONFIG_SECONDARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG; + req.num_tlv++; + req.sch_config.physical_cell_id.tl.tag = NFAPI_SCH_CONFIG_PHYSICAL_CELL_ID_TAG; + req.num_tlv++; + + req.prach_config.configuration_index.tl.tag = NFAPI_PRACH_CONFIG_CONFIGURATION_INDEX_TAG; + req.num_tlv++; + req.prach_config.root_sequence_index.tl.tag = NFAPI_PRACH_CONFIG_ROOT_SEQUENCE_INDEX_TAG; + req.num_tlv++; + req.prach_config.zero_correlation_zone_configuration.tl.tag = NFAPI_PRACH_CONFIG_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG; + req.num_tlv++; + req.prach_config.high_speed_flag.tl.tag = NFAPI_PRACH_CONFIG_HIGH_SPEED_FLAG_TAG; + req.num_tlv++; + req.prach_config.frequency_offset.tl.tag = NFAPI_PRACH_CONFIG_FREQUENCY_OFFSET_TAG; + req.num_tlv++; + + req.pusch_config.hopping_mode.tl.tag = NFAPI_PUSCH_CONFIG_HOPPING_MODE_TAG; + req.num_tlv++; + req.pusch_config.hopping_offset.tl.tag = NFAPI_PUSCH_CONFIG_HOPPING_OFFSET_TAG; + req.num_tlv++; + req.pusch_config.number_of_subbands.tl.tag = NFAPI_PUSCH_CONFIG_NUMBER_OF_SUBBANDS_TAG; + req.num_tlv++; + + req.pucch_config.delta_pucch_shift.tl.tag = NFAPI_PUCCH_CONFIG_DELTA_PUCCH_SHIFT_TAG; + req.num_tlv++; + req.pucch_config.n_cqi_rb.tl.tag = NFAPI_PUCCH_CONFIG_N_CQI_RB_TAG; + req.num_tlv++; + req.pucch_config.n_an_cs.tl.tag = NFAPI_PUCCH_CONFIG_N_AN_CS_TAG; + req.num_tlv++; + req.pucch_config.n1_pucch_an.tl.tag = NFAPI_PUCCH_CONFIG_N1_PUCCH_AN_TAG; + req.num_tlv++; + + req.srs_config.bandwidth_configuration.tl.tag = NFAPI_SRS_CONFIG_BANDWIDTH_CONFIGURATION_TAG; + req.num_tlv++; + req.srs_config.max_up_pts.tl.tag = NFAPI_SRS_CONFIG_MAX_UP_PTS_TAG; + req.num_tlv++; + req.srs_config.srs_subframe_configuration.tl.tag = NFAPI_SRS_CONFIG_SRS_SUBFRAME_CONFIGURATION_TAG; + req.num_tlv++; + req.srs_config.srs_acknack_srs_simultaneous_transmission.tl.tag = NFAPI_SRS_CONFIG_SRS_ACKNACK_SRS_SIMULTANEOUS_TRANSMISSION_TAG; + req.num_tlv++; + + req.uplink_reference_signal_config.uplink_rs_hopping.tl.tag = NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_UPLINK_RS_HOPPING_TAG; + req.num_tlv++; + req.uplink_reference_signal_config.group_assignment.tl.tag = NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_GROUP_ASSIGNMENT_TAG; + req.num_tlv++; + req.uplink_reference_signal_config.cyclic_shift_1_for_drms.tl.tag = NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_CYCLIC_SHIFT_1_FOR_DRMS_TAG; + req.num_tlv++; + + req.laa_config.ed_threshold_lbt_pdsch.tl.tag = NFAPI_LAA_CONFIG_ED_THRESHOLD_FOR_LBT_FOR_PDSCH_TAG; + req.num_tlv++; + req.laa_config.ed_threshold_lbt_drs.tl.tag = NFAPI_LAA_CONFIG_ED_THRESHOLD_FOR_LBT_FOR_DRS_TAG; + req.num_tlv++; + req.laa_config.pd_threshold.tl.tag = NFAPI_LAA_CONFIG_PD_THRESHOLD_TAG; + req.num_tlv++; + req.laa_config.multi_carrier_type.tl.tag = NFAPI_LAA_CONFIG_MULTI_CARRIER_TYPE_TAG; + req.num_tlv++; + req.laa_config.multi_carrier_tx.tl.tag = NFAPI_LAA_CONFIG_MULTI_CARRIER_TX_TAG; + req.num_tlv++; + req.laa_config.multi_carrier_freeze.tl.tag = NFAPI_LAA_CONFIG_MULTI_CARRIER_FREEZE_TAG; + req.num_tlv++; + req.laa_config.tx_antenna_ports_drs.tl.tag = NFAPI_LAA_CONFIG_TX_ANTENNA_PORTS_FOR_DRS_TAG; + req.num_tlv++; + req.laa_config.tx_power_drs.tl.tag = NFAPI_LAA_CONFIG_TRANSMISSION_POWER_FOR_DRS_TAG; + req.num_tlv++; + + req.emtc_config.pbch_repetitions_enable_r13.tl.tag = NFAPI_EMTC_CONFIG_PBCH_REPETITIONS_ENABLE_R13_TAG; + req.num_tlv++; + req.emtc_config.prach_catm_root_sequence_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CATM_ROOT_SEQUENCE_INDEX_TAG; + req.num_tlv++; + req.emtc_config.prach_catm_zero_correlation_zone_configuration.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CATM_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG; + req.num_tlv++; + req.emtc_config.prach_catm_high_speed_flag.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CATM_HIGH_SPEED_FLAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_0_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_ENABLE_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_0_configuration_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_CONFIGURATION_INDEX_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_0_frequency_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_FREQUENCY_OFFSET_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_0_starting_subframe_periodicity.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_STARTING_SUBFRAME_PERIODICITY_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_0_hopping_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_ENABLE_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_0_hopping_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_OFFSET_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_1_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_ENABLE_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_1_configuration_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_CONFIGURATION_INDEX_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_1_frequency_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_FREQUENCY_OFFSET_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_1_starting_subframe_periodicity.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_STARTING_SUBFRAME_PERIODICITY_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_1_hopping_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_ENABLE_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_1_hopping_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_OFFSET_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_2_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_ENABLE_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_2_configuration_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_CONFIGURATION_INDEX_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_2_frequency_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_FREQUENCY_OFFSET_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_2_starting_subframe_periodicity.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_STARTING_SUBFRAME_PERIODICITY_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_2_hopping_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_ENABLE_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_2_hopping_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_OFFSET_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_3_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_ENABLE_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_3_configuration_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_CONFIGURATION_INDEX_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_3_frequency_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_FREQUENCY_OFFSET_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_3_starting_subframe_periodicity.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_STARTING_SUBFRAME_PERIODICITY_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_3_hopping_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_ENABLE_TAG; + req.num_tlv++; + req.emtc_config.prach_ce_level_3_hopping_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_OFFSET_TAG; + req.num_tlv++; + req.emtc_config.pucch_interval_ulhoppingconfigcommonmodea.tl.tag = NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEA_TAG; + req.num_tlv++; + req.emtc_config.pucch_interval_ulhoppingconfigcommonmodeb.tl.tag = NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEB_TAG; + req.num_tlv++; + + req.nb_iot_config.operating_mode.tl.tag = NFAPI_NB_IOT_CONFIG_OPERATING_MODE_TAG; + req.nb_iot_config.operating_mode.value = rand_range(0, 3); + req.num_tlv++; + req.nb_iot_config.anchor.tl.tag = NFAPI_NB_IOT_CONFIG_ANCHOR_TAG; + req.nb_iot_config.anchor.value = rand_range(0, 1); + req.num_tlv++; + req.nb_iot_config.prb_index.tl.tag = NFAPI_NB_IOT_CONFIG_PRB_INDEX_TAG; + req.nb_iot_config.prb_index.value = rand_range(0, 0x1F); + req.num_tlv++; + req.nb_iot_config.control_region_size.tl.tag = NFAPI_NB_IOT_CONFIG_CONTROL_REGION_SIZE_TAG; + req.nb_iot_config.control_region_size.value = rand_range(1, 4); + req.num_tlv++; + req.nb_iot_config.assumed_crs_aps.tl.tag = NFAPI_NB_IOT_CONFIG_ASSUMED_CRS_APS_TAG; + req.nb_iot_config.assumed_crs_aps.value = rand_range(0, 1); + req.num_tlv++; + req.nb_iot_config.nprach_config_0_enabled.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_ENABLED_TAG; + req.nb_iot_config.nprach_config_0_enabled.value = rand_range(0, 1); + req.num_tlv++; + req.nb_iot_config.nprach_config_0_sf_periodicity.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_SF_PERIODICITY_TAG; + req.nb_iot_config.nprach_config_0_sf_periodicity.value = rand_range(0, 7); + req.num_tlv++; + req.nb_iot_config.nprach_config_0_start_time.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_START_TIME_TAG; + req.nb_iot_config.nprach_config_0_start_time.value = rand_range(0, 7); + req.num_tlv++; + req.nb_iot_config.nprach_config_0_subcarrier_offset.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_SUBCARRIER_OFFSET_TAG; + req.nb_iot_config.nprach_config_0_subcarrier_offset.value = rand_range(0, 6); + req.num_tlv++; + req.nb_iot_config.nprach_config_0_number_of_subcarriers.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_NUMBER_OF_SUBCARRIERS_TAG; + req.nb_iot_config.nprach_config_0_number_of_subcarriers.value = rand_range(0, 3); + req.num_tlv++; + req.nb_iot_config.nprach_config_0_cp_length.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_CP_LENGTH_TAG; + req.nb_iot_config.nprach_config_0_cp_length.value = rand_range(0, 1); + req.num_tlv++; + req.nb_iot_config.nprach_config_0_number_of_repetitions_per_attempt.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_0_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + req.nb_iot_config.nprach_config_0_number_of_repetitions_per_attempt.value = rand_range(0, 7); + req.num_tlv++; + req.nb_iot_config.nprach_config_1_enabled.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_ENABLED_TAG; + req.nb_iot_config.nprach_config_1_enabled.value = rand_range(0, 1); + req.num_tlv++; + req.nb_iot_config.nprach_config_1_sf_periodicity.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_SF_PERIODICITY_TAG; + req.nb_iot_config.nprach_config_1_sf_periodicity.value = rand_range(0, 7); + req.num_tlv++; + req.nb_iot_config.nprach_config_1_start_time.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_START_TIME_TAG; + req.nb_iot_config.nprach_config_1_start_time.value = rand_range(0, 7); + req.num_tlv++; + req.nb_iot_config.nprach_config_1_subcarrier_offset.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_SUBCARRIER_OFFSET_TAG; + req.nb_iot_config.nprach_config_1_subcarrier_offset.value = rand_range(0, 6); + req.num_tlv++; + req.nb_iot_config.nprach_config_1_number_of_subcarriers.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_NUMBER_OF_SUBCARRIERS_TAG; + req.nb_iot_config.nprach_config_1_number_of_subcarriers.value = rand_range(0, 3); + req.num_tlv++; + req.nb_iot_config.nprach_config_1_cp_length.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_CP_LENGTH_TAG; + req.nb_iot_config.nprach_config_1_cp_length.value = rand_range(0, 1); + req.num_tlv++; + req.nb_iot_config.nprach_config_1_number_of_repetitions_per_attempt.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_1_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + req.nb_iot_config.nprach_config_1_number_of_repetitions_per_attempt.value = rand_range(0, 7); + req.num_tlv++; + req.nb_iot_config.nprach_config_2_enabled.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_ENABLED_TAG; + req.nb_iot_config.nprach_config_2_enabled.value = rand_range(0, 1); + req.num_tlv++; + req.nb_iot_config.nprach_config_2_sf_periodicity.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_SF_PERIODICITY_TAG; + req.nb_iot_config.nprach_config_2_sf_periodicity.value = rand_range(0, 7); + req.num_tlv++; + req.nb_iot_config.nprach_config_2_start_time.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_START_TIME_TAG; + req.nb_iot_config.nprach_config_2_start_time.value = rand_range(0, 7); + req.num_tlv++; + req.nb_iot_config.nprach_config_2_subcarrier_offset.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_SUBCARRIER_OFFSET_TAG; + req.nb_iot_config.nprach_config_2_subcarrier_offset.value = rand_range(0, 6); + req.num_tlv++; + req.nb_iot_config.nprach_config_2_number_of_subcarriers.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_NUMBER_OF_SUBCARRIERS_TAG; + req.nb_iot_config.nprach_config_2_number_of_subcarriers.value = rand_range(0, 3); + req.num_tlv++; + req.nb_iot_config.nprach_config_2_cp_length.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_CP_LENGTH_TAG; + req.nb_iot_config.nprach_config_2_cp_length.value = rand_range(0, 1); + req.num_tlv++; + req.nb_iot_config.nprach_config_2_number_of_repetitions_per_attempt.tl.tag = NFAPI_NB_IOT_CONFIG_NPRACH_CONFIG_2_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + req.nb_iot_config.nprach_config_2_number_of_repetitions_per_attempt.value = rand_range(0, 7); + req.num_tlv++; + req.nb_iot_config.three_tone_base_sequence.tl.tag = NFAPI_NB_IOT_CONFIG_THREE_TONE_BASE_SEQUENCE_TAG; + req.nb_iot_config.three_tone_base_sequence.value = rand_range(0, 0x0F); + req.num_tlv++; + req.nb_iot_config.six_tone_base_sequence.tl.tag = NFAPI_NB_IOT_CONFIG_SIX_TONE_BASE_SEQUENCE_TAG; + req.nb_iot_config.six_tone_base_sequence.value = rand_range(0, 0x03); + req.num_tlv++; + req.nb_iot_config.twelve_tone_base_sequence.tl.tag = NFAPI_NB_IOT_CONFIG_TWELVE_TONE_BASE_SEQUENCE_TAG; + req.nb_iot_config.twelve_tone_base_sequence.value = rand_range(0, 0x1F); + req.num_tlv++; + req.nb_iot_config.three_tone_cyclic_shift.tl.tag = NFAPI_NB_IOT_CONFIG_THREE_TONE_CYCLIC_SHIFT_TAG; + req.nb_iot_config.three_tone_cyclic_shift.value = rand_range(0, 5); // what is the max + req.num_tlv++; + req.nb_iot_config.six_tone_cyclic_shift.tl.tag = NFAPI_NB_IOT_CONFIG_SIX_TONE_CYCLIC_SHIFT_TAG; + req.nb_iot_config.six_tone_cyclic_shift.value = rand_range(0, 5); // what is the max + req.num_tlv++; + req.nb_iot_config.dl_gap_config_enable.tl.tag = NFAPI_NB_IOT_CONFIG_DL_GAP_CONFIG_ENABLE_TAG; + req.nb_iot_config.dl_gap_config_enable.value = rand_range(0, 1); + req.num_tlv++; + req.nb_iot_config.dl_gap_threshold.tl.tag = NFAPI_NB_IOT_CONFIG_DL_GAP_THRESHOLD_TAG; + req.nb_iot_config.dl_gap_threshold.value = rand_range(0, 3); + req.num_tlv++; + req.nb_iot_config.dl_gap_periodicity.tl.tag = NFAPI_NB_IOT_CONFIG_DL_GAP_PERIODICITY_TAG; + req.nb_iot_config.dl_gap_periodicity.value = rand_range(0, 3); + req.num_tlv++; + req.nb_iot_config.dl_gap_duration_coefficient.tl.tag = NFAPI_NB_IOT_CONFIG_DL_GAP_DURATION_COEFFICIENT_TAG; + req.nb_iot_config.dl_gap_duration_coefficient.value = rand_range(0, 3); + req.num_tlv++; + + req.tdd_frame_structure_config.subframe_assignment.tl.tag = NFAPI_TDD_FRAME_STRUCTURE_SUBFRAME_ASSIGNMENT_TAG; + req.num_tlv++; + req.tdd_frame_structure_config.special_subframe_patterns.tl.tag = NFAPI_TDD_FRAME_STRUCTURE_SPECIAL_SUBFRAME_PATTERNS_TAG; + req.num_tlv++; + + req.l23_config.data_report_mode.tl.tag = NFAPI_L23_CONFIG_DATA_REPORT_MODE_TAG; + req.num_tlv++; + req.l23_config.sfnsf.tl.tag = NFAPI_L23_CONFIG_SFNSF_TAG; + req.num_tlv++; + } + + vendor_ext_tlv_2 ve2; + memset(&ve2, 0, sizeof(ve2)); + ve2.tl.tag = VENDOR_EXT_TLV_2_TAG; + ve2.dummy = 2016; + req.vendor_extension = &ve2.tl; + + nfapi_vnf_config_req(config, p5_idx, &req); + } + else + { + printf("[VNF_SIM] param response failed to find pnf %d phy %d\n", p5_idx, resp->header.phy_id); + } + } + else + { + printf("[VNF_SIM] param response failed to find pnf %d\n", p5_idx); + } + + return 0; +} + +int config_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_config_response_t* resp) +{ + printf("[VNF_SIM] config response idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id); + + + nfapi_start_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_START_REQUEST; + req.header.phy_id = resp->header.phy_id; + nfapi_vnf_start_req(config, p5_idx, &req); + + return 0; +} + +void test_p4_requests(nfapi_vnf_config_t* config, int p5_idx, int phy_id) +{ + { + nfapi_measurement_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_MEASUREMENT_REQUEST; + req.header.phy_id = phy_id; + + req.dl_rs_tx_power.tl.tag = NFAPI_MEASUREMENT_REQUEST_DL_RS_XTX_POWER_TAG; + req.dl_rs_tx_power.value = 42; + req.received_interference_power.tl.tag = NFAPI_MEASUREMENT_REQUEST_RECEIVED_INTERFERENCE_POWER_TAG; + req.received_interference_power.value = 42; + req.thermal_noise_power.tl.tag = NFAPI_MEASUREMENT_REQUEST_THERMAL_NOISE_POWER_TAG; + req.thermal_noise_power.value = 42; + + nfapi_vnf_measurement_req(config, p5_idx, &req); + } + { + nfapi_rssi_request_t lte_req; + memset(<e_req, 0, sizeof(lte_req)); + lte_req.header.message_id = NFAPI_RSSI_REQUEST; + lte_req.header.phy_id = phy_id; + + lte_req.rat_type = NFAPI_RAT_TYPE_LTE; + lte_req.lte_rssi_request.tl.tag = NFAPI_LTE_RSSI_REQUEST_TAG; + lte_req.lte_rssi_request.frequency_band_indicator = 2; + lte_req.lte_rssi_request.measurement_period = 1000; + lte_req.lte_rssi_request.bandwidth = 50; + lte_req.lte_rssi_request.timeout = 0; + lte_req.lte_rssi_request.number_of_earfcns = 2; + lte_req.lte_rssi_request.earfcn[0] = 389; + lte_req.lte_rssi_request.earfcn[1] = 123; + + nfapi_vnf_rssi_request(config, p5_idx, <e_req); + + nfapi_rssi_request_t utran_req; + memset(&utran_req, 0, sizeof(utran_req)); + utran_req.header.message_id = NFAPI_RSSI_REQUEST; + utran_req.header.phy_id = phy_id; + + utran_req.rat_type = NFAPI_RAT_TYPE_UTRAN; + utran_req.utran_rssi_request.tl.tag = NFAPI_UTRAN_RSSI_REQUEST_TAG; + utran_req.utran_rssi_request.frequency_band_indicator = 2; + utran_req.utran_rssi_request.measurement_period = 1000; + utran_req.utran_rssi_request.timeout = 0; + utran_req.utran_rssi_request.number_of_uarfcns = 2; + utran_req.utran_rssi_request.uarfcn[0] = 2348; + utran_req.utran_rssi_request.uarfcn[1] = 52; + + nfapi_vnf_rssi_request(config, p5_idx, &utran_req); + + + nfapi_rssi_request_t geran_req; + memset(&geran_req, 0, sizeof(geran_req)); + geran_req.header.message_id = NFAPI_RSSI_REQUEST; + geran_req.header.phy_id = phy_id; + + geran_req.rat_type = NFAPI_RAT_TYPE_GERAN; + geran_req.geran_rssi_request.tl.tag = NFAPI_GERAN_RSSI_REQUEST_TAG; + geran_req.geran_rssi_request.frequency_band_indicator = 2; + geran_req.geran_rssi_request.measurement_period = 1000; + geran_req.geran_rssi_request.timeout = 0; + geran_req.geran_rssi_request.number_of_arfcns = 1; + geran_req.geran_rssi_request.arfcn[0].arfcn = 34; + geran_req.geran_rssi_request.arfcn[0].direction = 0; + + nfapi_vnf_rssi_request(config, p5_idx, &geran_req); + } + { + nfapi_cell_search_request_t lte_req; + memset(<e_req, 0, sizeof(lte_req)); + lte_req.header.message_id = NFAPI_CELL_SEARCH_REQUEST; + lte_req.header.phy_id = phy_id; + + lte_req.rat_type = NFAPI_RAT_TYPE_LTE; + lte_req.lte_cell_search_request.tl.tag = NFAPI_LTE_CELL_SEARCH_REQUEST_TAG; + lte_req.lte_cell_search_request.earfcn = 1234; + lte_req.lte_cell_search_request.measurement_bandwidth = 50; + lte_req.lte_cell_search_request.exhaustive_search = 1; + lte_req.lte_cell_search_request.timeout = 1000; + lte_req.lte_cell_search_request.number_of_pci = 1; + lte_req.lte_cell_search_request.pci[0] = 234; + + nfapi_vnf_cell_search_request(config, p5_idx, <e_req); + + nfapi_cell_search_request_t utran_req; + memset(&utran_req, 0, sizeof(utran_req)); + utran_req.header.message_id = NFAPI_CELL_SEARCH_REQUEST; + utran_req.header.phy_id = phy_id; + + utran_req.rat_type = NFAPI_RAT_TYPE_UTRAN; + utran_req.utran_cell_search_request.tl.tag = NFAPI_UTRAN_CELL_SEARCH_REQUEST_TAG; + utran_req.utran_cell_search_request.uarfcn = 1234; + utran_req.utran_cell_search_request.exhaustive_search = 0; + utran_req.utran_cell_search_request.timeout = 1000; + utran_req.utran_cell_search_request.number_of_psc = 1; + utran_req.utran_cell_search_request.psc[0] = 234; + + nfapi_vnf_cell_search_request(config, p5_idx, &utran_req); + + nfapi_cell_search_request_t geran_req; + memset(&geran_req, 0, sizeof(geran_req)); + geran_req.header.message_id = NFAPI_CELL_SEARCH_REQUEST; + geran_req.header.phy_id = phy_id; + + geran_req.rat_type = NFAPI_RAT_TYPE_GERAN; + geran_req.geran_cell_search_request.tl.tag = NFAPI_GERAN_CELL_SEARCH_REQUEST_TAG; + geran_req.geran_cell_search_request.timeout = 1000; + geran_req.geran_cell_search_request.number_of_arfcn = 1; + geran_req.geran_cell_search_request.arfcn[0] = 8765; + + nfapi_vnf_cell_search_request(config, p5_idx, &geran_req); + } + { + nfapi_broadcast_detect_request_t lte_req; + memset(<e_req, 0, sizeof(lte_req)); + lte_req.header.message_id = NFAPI_BROADCAST_DETECT_REQUEST; + lte_req.header.phy_id = phy_id; + + lte_req.rat_type = NFAPI_RAT_TYPE_LTE; + lte_req.lte_broadcast_detect_request.tl.tag = NFAPI_LTE_BROADCAST_DETECT_REQUEST_TAG; + lte_req.lte_broadcast_detect_request.earfcn = 1234; + lte_req.lte_broadcast_detect_request.pci = 50; + lte_req.lte_broadcast_detect_request.timeout = 1000; + + lte_req.pnf_cell_search_state.tl.tag = NFAPI_PNF_CELL_SEARCH_STATE_TAG; + lte_req.pnf_cell_search_state.length = 3; + + nfapi_vnf_broadcast_detect_request(config, p5_idx, <e_req); + + nfapi_broadcast_detect_request_t utran_req; + memset(&utran_req, 0, sizeof(utran_req)); + utran_req.header.message_id = NFAPI_BROADCAST_DETECT_REQUEST; + utran_req.header.phy_id = phy_id; + + utran_req.rat_type = NFAPI_RAT_TYPE_LTE; + utran_req.utran_broadcast_detect_request.tl.tag = NFAPI_UTRAN_BROADCAST_DETECT_REQUEST_TAG; + utran_req.utran_broadcast_detect_request.uarfcn = 1234; + utran_req.utran_broadcast_detect_request.psc = 50; + utran_req.utran_broadcast_detect_request.timeout = 1000; + + utran_req.pnf_cell_search_state.tl.tag = NFAPI_PNF_CELL_SEARCH_STATE_TAG; + utran_req.pnf_cell_search_state.length = 3; + + nfapi_vnf_broadcast_detect_request(config, p5_idx, &utran_req); + } + { + nfapi_system_information_schedule_request_t lte_req; + memset(<e_req, 0, sizeof(lte_req)); + lte_req.header.message_id = NFAPI_SYSTEM_INFORMATION_SCHEDULE_REQUEST; + lte_req.header.phy_id = phy_id; + + lte_req.rat_type = NFAPI_RAT_TYPE_LTE; + lte_req.lte_system_information_schedule_request.tl.tag = NFAPI_LTE_SYSTEM_INFORMATION_SCHEDULE_REQUEST_TAG; + lte_req.lte_system_information_schedule_request.earfcn = 1234; + lte_req.lte_system_information_schedule_request.pci = 50; + lte_req.lte_system_information_schedule_request.downlink_channel_bandwidth = 100; + lte_req.lte_system_information_schedule_request.phich_configuration = 3; + lte_req.lte_system_information_schedule_request.number_of_tx_antenna = 2; + lte_req.lte_system_information_schedule_request.retry_count = 4; + lte_req.lte_system_information_schedule_request.timeout = 1000; + + lte_req.pnf_cell_broadcast_state.tl.tag = NFAPI_PNF_CELL_BROADCAST_STATE_TAG; + lte_req.pnf_cell_broadcast_state.length = 3; + + nfapi_vnf_system_information_schedule_request(config, p5_idx, <e_req); + } + { + nfapi_system_information_request_t lte_req; + memset(<e_req, 0, sizeof(lte_req)); + lte_req.header.message_id = NFAPI_SYSTEM_INFORMATION_REQUEST; + lte_req.header.phy_id = phy_id; + + lte_req.rat_type = NFAPI_RAT_TYPE_LTE; + lte_req.lte_system_information_request.tl.tag = NFAPI_LTE_SYSTEM_INFORMATION_REQUEST_TAG; + lte_req.lte_system_information_request.earfcn = 1234; + lte_req.lte_system_information_request.pci= 456; + lte_req.lte_system_information_request.downlink_channel_bandwidth = 5; + lte_req.lte_system_information_request.phich_configuration = 2; + lte_req.lte_system_information_request.number_of_tx_antenna = 2; + lte_req.lte_system_information_request.number_of_si_periodicity = 1; + lte_req.lte_system_information_request.si_periodicity[0].si_periodicity = 3; + lte_req.lte_system_information_request.si_periodicity[0].si_index = 3; + lte_req.lte_system_information_request.si_window_length = 15; + lte_req.lte_system_information_request.timeout = 1000; + + nfapi_vnf_system_information_request(config, p5_idx, <e_req); + + nfapi_system_information_request_t utran_req; + memset(&utran_req, 0, sizeof(utran_req)); + utran_req.header.message_id = NFAPI_SYSTEM_INFORMATION_REQUEST; + utran_req.header.phy_id = phy_id; + + utran_req.rat_type = NFAPI_RAT_TYPE_UTRAN; + utran_req.utran_system_information_request.tl.tag = NFAPI_UTRAN_SYSTEM_INFORMATION_REQUEST_TAG; + utran_req.utran_system_information_request.uarfcn = 1234; + utran_req.utran_system_information_request.psc = 456; + utran_req.utran_system_information_request.timeout = 1000; + + nfapi_vnf_system_information_request(config, p5_idx, &utran_req); + + nfapi_system_information_request_t geran_req; + memset(&geran_req, 0, sizeof(geran_req)); + geran_req.header.message_id = NFAPI_SYSTEM_INFORMATION_REQUEST; + geran_req.header.phy_id = phy_id; + + geran_req.rat_type = NFAPI_RAT_TYPE_GERAN; + geran_req.geran_system_information_request.tl.tag = NFAPI_GERAN_SYSTEM_INFORMATION_REQUEST_TAG; + geran_req.geran_system_information_request.arfcn = 1234; + geran_req.geran_system_information_request.bsic = 21; + geran_req.geran_system_information_request.timeout = 1000; + + nfapi_vnf_system_information_request(config, p5_idx, &geran_req); + } + { + nfapi_nmm_stop_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_NMM_STOP_REQUEST; + req.header.phy_id = phy_id; + nfapi_vnf_nmm_stop_request(config, p5_idx, &req); + } +} + + +int start_resp_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_start_response_t* resp) +{ + printf("[VNF_SIM] start response idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id); + + vnf_info* vnf = (vnf_info*)(config->user_data); + + if(vnf->wireshark_test_mode) + test_p4_requests(config, p5_idx, resp->header.phy_id); + + auto find_result = vnf->pnfs.find(p5_idx); + if(find_result != vnf->pnfs.end()) + { + pnf_info& pnf = find_result->second; + + + auto found = std::find_if(pnf.phys.begin(), pnf.phys.end(), [&](phy_info& item) + { return item.id == resp->header.phy_id; }); + + if(found != pnf.phys.end()) + { + phy_info& phy = (*found); + + vnf_p7_info& p7_vnf = vnf->p7_vnfs[0]; + + nfapi_vnf_p7_add_pnf((p7_vnf.config.get()), phy.remote_addr.c_str(), phy.remote_port, phy.id); + + + } + + + } + return 0; +} + + +nfapi_p4_p5_message_header_t* vnf_sim_allocate_p4_p5_vendor_ext(uint16_t message_id, uint16_t* msg_size) +{ + if(message_id == P5_VENDOR_EXT_RSP) + { + *msg_size = sizeof(vendor_ext_p5_rsp); + return (nfapi_p4_p5_message_header_t*)malloc(sizeof(vendor_ext_p5_rsp)); + } + return 0; +} +void vnf_sim_deallocate_p4_p5_vendor_ext(nfapi_p4_p5_message_header_t* header) +{ + free(header); +} +int vendor_ext_cb(nfapi_vnf_config_t* config, int p5_idx, nfapi_p4_p5_message_header_t* msg) +{ + printf("[VNF_SIM] %s\n", __FUNCTION__); + + switch(msg->message_id) + { + case P5_VENDOR_EXT_RSP: + { + vendor_ext_p5_rsp* rsp = (vendor_ext_p5_rsp*)msg; + printf("[VNF_SIM] P5_VENDOR_EXT_RSP error_code:%d\n", rsp->error_code); + + // send the start request + + nfapi_pnf_start_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PNF_START_REQUEST; + nfapi_vnf_pnf_start_req(config, p5_idx, &req); + } + break; + + } + + return 0; +} + +int read_vnf_xml(vnf_info& vnf, const char* xml_file) +{ + try + { + + std::ifstream input(xml_file); + + using boost::property_tree::ptree; + ptree pt; + + read_xml(input, pt); + + + + for(const auto& v : pt.get_child("vnf.vnf_p7_list")) + { + if(v.first == "vnf_p7") + { + vnf_p7_info vnf_p7; + vnf_p7.local_port = v.second.get("port"); + vnf_p7.local_addr = v.second.get("address"); + + vnf_p7.timing_window = v.second.get("timing_window"); + vnf_p7.periodic_timing_enabled = v.second.get("periodic_timing_enabled"); + vnf_p7.aperiodic_timing_enabled = v.second.get("aperiodic_timing_enabled"); + vnf_p7.periodic_timing_period = v.second.get("periodic_timing_window"); + + + boost::optional d = v.second.get_child_optional("data.udp"); + if(d.is_initialized()) + { + vnf_p7.udp.enabled = true; + vnf_p7.udp.rx_port = d.get().get("rx_port"); + vnf_p7.udp.tx_port = d.get().get("tx_port"); + vnf_p7.udp.tx_addr = d.get().get("tx_addr"); + } + else + { + vnf_p7.udp.enabled = false; + } + + vnf.wireshark_test_mode = v.second.get("wireshark_test_mode", 0); + + vnf_p7.mac = mac_create(vnf.wireshark_test_mode); + vnf_p7.mac->dl_config_req = &mac_dl_config_req; + vnf_p7.mac->ul_config_req = &mac_ul_config_req; + vnf_p7.mac->hi_dci0_req = &mac_hi_dci0_req; + vnf_p7.mac->tx_req = &mac_tx_req; + + if(vnf_p7.udp.enabled) + { + mac_start_data(vnf_p7.mac, + vnf_p7.udp.rx_port, + vnf_p7.udp.tx_addr.c_str(), + vnf_p7.udp.tx_port); + } + + vnf.p7_vnfs.push_back(vnf_p7); + } + } + } + catch(std::exception& e) + { + printf("%s", e.what()); + return -1; + } + catch(boost::exception& e) + { + printf("%s", boost::diagnostic_information(e).c_str()); + } + + struct ifaddrs *ifaddr; + getifaddrs(&ifaddr); + + + while(ifaddr) + { + int family = ifaddr->ifa_addr->sa_family; + if(family == AF_INET) + { + char host[128]; + getnameinfo(ifaddr->ifa_addr, sizeof(sockaddr_in), host, sizeof(host), NULL, 0, 0); + printf("%s\n", host); + } + ifaddr = ifaddr->ifa_next; + } + + return 0; + +} + + +int main(int argc, char *argv[]) +{ + if (argc < 3) + { + printf("Use parameters: \n"); + return 0; + } + + set_thread_priority(50); + + vnf_info vnf; + + if(read_vnf_xml(vnf, argv[2]) < 0) + { + printf("Failed to read xml file>\n"); + return 0; + } + + nfapi_vnf_config_t* config = nfapi_vnf_config_create(); + + config->vnf_ipv4 = 1; + config->vnf_p5_port = atoi(argv[1]); + config->pnf_connection_indication = &pnf_connection_indication_cb; + config->pnf_disconnect_indication = &pnf_disconnection_indication_cb; + config->pnf_param_resp = &pnf_param_resp_cb; + config->pnf_config_resp = &pnf_config_resp_cb; + config->pnf_start_resp = &pnf_start_resp_cb; + config->param_resp = ¶m_resp_cb; + config->config_resp = &config_resp_cb; + config->start_resp = &start_resp_cb; + config->vendor_ext = &vendor_ext_cb; + + + + config->trace = &vnf_sim_trace; + + config->malloc = &vnf_allocate; + config->free = &vnf_deallocate; + + config->user_data = &vnf; + + config->codec_config.unpack_vendor_extension_tlv = &vnf_sim_unpack_vendor_extension_tlv; + config->codec_config.pack_vendor_extension_tlv = &vnf_sim_pack_vendor_extension_tlv; + + config->codec_config.unpack_p4_p5_vendor_extension = &vnf_sim_unpack_p4_p5_vendor_extension; + config->codec_config.pack_p4_p5_vendor_extension = &vnf_sim_pack_p4_p5_vendor_extension; + config->allocate_p4_p5_vendor_ext = &vnf_sim_allocate_p4_p5_vendor_ext; + config->deallocate_p4_p5_vendor_ext = &vnf_sim_deallocate_p4_p5_vendor_ext; + config->codec_config.allocate = &vnf_allocate; + config->codec_config.deallocate = &vnf_deallocate; + + + printf("Calling nfapi_vnf_start\n"); + return nfapi_vnf_start(config); +} diff --git a/nfapi/open-nFAPI/xml/pnf_phy_1_A.xml b/nfapi/open-nFAPI/xml/pnf_phy_1_A.xml new file mode 100644 index 0000000000..45f8f46831 --- /dev/null +++ b/nfapi/open-nFAPI/xml/pnf_phy_1_A.xml @@ -0,0 +1,88 @@ + + + 0 + 0 + + + 500 + 500 + 500 + 500 + + 1 + 30 + 1 + 1 + + 0 + 0 + + 0 + + ALPHA + + + + + 88 + 2500 +
    192.168.1.74
    + + 1 + + 22 + 22 + + 1 + 1 + + <3gpp_release_supported>31 + + 0 + + 8 + 8 + + + + + 0 + + + 1 + + + + + 5201 + 192.168.1.28 + 5200 + + +
    +
    + + + 0 + 2 + -30 + -230 + 2 + 1890 + 1890 + 1890 + 1890 + + + 1 + 3 + -30 + -230 + 2 + 1890 + 1890 + 1890 + 1890 + + +
    diff --git a/nfapi/open-nFAPI/xml/pnf_phy_1_A_ws.xml b/nfapi/open-nFAPI/xml/pnf_phy_1_A_ws.xml new file mode 100644 index 0000000000..5eb0284148 --- /dev/null +++ b/nfapi/open-nFAPI/xml/pnf_phy_1_A_ws.xml @@ -0,0 +1,90 @@ + + + 1 + + 0 + 0 + + + 500 + 500 + 500 + 500 + + 1 + 30 + 1 + 1 + + 0 + 0 + + 0 + + ALPHA + + + + + 88 + 2500 +
    127.0.0.1
    + + 1 + + 22 + 22 + + 1 + 1 + + <3gpp_release_supported>31 + + 0 + + 8 + 8 + + + + + 0 + + + 1 + + + + + 7722 + 127.0.0.1 + 7733 + + +
    +
    + + + 0 + 2 + -30 + -230 + 2 + 1890 + 1890 + 1890 + 1890 + + + 1 + 3 + -30 + -230 + 2 + 1890 + 1890 + 1890 + 1890 + + +
    diff --git a/nfapi/open-nFAPI/xml/pnf_phy_1_B.xml b/nfapi/open-nFAPI/xml/pnf_phy_1_B.xml new file mode 100644 index 0000000000..302e1e19c5 --- /dev/null +++ b/nfapi/open-nFAPI/xml/pnf_phy_1_B.xml @@ -0,0 +1,88 @@ + + + 0 + 0 + + + 500 + 500 + 500 + 500 + + 1 + 30 + 1 + 1 + + 0 + 0 + + 0 + + ALPHA + + + + + 89 + 2510 +
    127.0.0.1
    + + 1 + + 22 + 22 + + 1 + 1 + + <3gpp_release_supported>31 + + 0 + + 8 + 8 + + + + + 0 + + + 1 + + + + + 7744 + 127.0.0.1 + 7755 + + +
    +
    + + + 0 + 2 + -30 + -230 + 2 + 1890 + 1890 + 1890 + 1890 + + + 1 + 3 + -30 + -230 + 2 + 1890 + 1890 + 1890 + 1890 + + +
    diff --git a/nfapi/open-nFAPI/xml/pnf_phy_2_A.xml b/nfapi/open-nFAPI/xml/pnf_phy_2_A.xml new file mode 100644 index 0000000000..b820fa135e --- /dev/null +++ b/nfapi/open-nFAPI/xml/pnf_phy_2_A.xml @@ -0,0 +1,90 @@ + + + 0 + 0 + + + 500 + 500 + 500 + 500 + + 1 + 30 + 1 + 1 + + 0 + 0 + + 0 + + ALPHA + + + + 88 + 2500 +
    127.0.0.1
    + + 1 + 22 + 22 + 1 + 1 + <3gpp_release_supported>31 + 0 + 8 + 8 + + + 0 + + +
    + + 44 + 2600 +
    127.0.0.1
    + + 1 + 22 + 22 + 1 + 1 + <3gpp_release_supported>31 + 0 + 8 + 8 + + + 1 + + +
    +
    + + + 0 + 2 + -30 + -230 + 2 + 1890 + 1890 + 1890 + 1890 + + + 1 + 4 + -30 + -230 + 2 + 1890 + 1890 + 1890 + 1890 + + +
    diff --git a/nfapi/open-nFAPI/xml/vnf_A.xml b/nfapi/open-nFAPI/xml/vnf_A.xml new file mode 100644 index 0000000000..3791239ce7 --- /dev/null +++ b/nfapi/open-nFAPI/xml/vnf_A.xml @@ -0,0 +1,21 @@ + + + + + 5201 +
    192.168.1.28
    + 10 + 0 + 0 + 0 + + + + 8891 + 192.168.1.28 + 8892 + + +
    +
    +
    diff --git a/nfapi/open-nFAPI/xml/vnf_A_ws.xml b/nfapi/open-nFAPI/xml/vnf_A_ws.xml new file mode 100644 index 0000000000..c26adc3cfa --- /dev/null +++ b/nfapi/open-nFAPI/xml/vnf_A_ws.xml @@ -0,0 +1,23 @@ + + + + + + 1 + 5200 +
    127.0.0.1
    + 10 + 0 + 0 + 0 + + + + 8891 + 127.0.0.1 + 8892 + + +
    +
    +
    diff --git a/oaienv b/oaienv index 2e5ce16960..f6b298debf 100644 --- a/oaienv +++ b/oaienv @@ -17,14 +17,3 @@ alias oait='cd $OPENAIR_TARGETS' alias oailte='cd $OPENAIR_TARGETS/RT/USER' alias oais='cd $OPENAIR_TARGETS/SIMU/USER' alias oaiex='cd $OPENAIR_TARGETS/SIMU/EXAMPLES' - -export NFAPI_DIR=${HOME}/open-nFAPI - -alias bld='cd $OPENAIR_HOME/cmake_targets ; ./build_oai --eNB -w USRP' -alias b='cd $OPENAIR_HOME/cmake_targets ; ./build_oai --eNB -w USRP' -alias run='cd $OPENAIR_HOME/cmake_targets/lte_build_oai/build' -alias nf='cd $OPENAIR_HOME/nfapi' -alias conf='cd $OPENAIR_HOME/targets/PROJECTS/GENERIC-LTE-EPC/CONF' - -alias ttracer='cd $OPENAIR_HOME/cmake_targets ; ./build_oai --eNB -x -w USRP --T-tracer' -alias rec='cd $OPENAIR_HOME/common/utils/T/tracer ; ./record -d ../T_messages.txt -o record.raw -ON -off VCD -off HEAVY -off LEGACY_GROUP_TRACE -off LEGACY_GROUP_DEBUG' diff --git a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c index f852235c18..cd032e688f 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync.c @@ -258,7 +258,7 @@ int lte_est_timing_advance_pusch(PHY_VARS_eNB* eNB,uint8_t UE_id) max_pos = max_pos-frame_parms->ofdm_symbol_size; //#ifdef DEBUG_PHY - //LOG_D(PHY,"frame %d: max_pos = %d, sync_pos=%d\n",eNB->proc.frame_rx,max_pos,sync_pos); + LOG_D(PHY,"frame %d: max_pos = %d, sync_pos=%d\n",eNB->proc.frame_rx,max_pos,sync_pos); //#endif //DEBUG_PHY return max_pos - sync_pos; diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index 6ec745293f..36638f383b 100755 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -2219,11 +2219,6 @@ uint8_t generate_dci_top(uint8_t num_pdcch_symbols, int Msymb2; int split_flag=0; - if (num_dci>0) - { - //LOG_D(PHY,"%s(num_pdcch_symbols:%d num_dci:%d dci_alloc:%p n_rnti:%04x amp:%d frame_parms:%p txdataF:%p subframe:%d)\n", __FUNCTION__, num_pdcch_symbols, num_dci, dci_alloc, n_rnti, amp, frame_parms, txdataF, subframe); - } - switch (frame_parms->N_RB_DL) { case 100: Msymb2 = Msymb; diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index bab605b573..50ee086884 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -801,28 +801,6 @@ void generate_RIV_tables() // n_tilde_PRB(0,1) = (0,2) -void check_dlsch(char *file, int line) -{ - PHY_VARS_eNB *eNB = RC.eNB[0][0]; - static char oldbuf[13*NUMBER_OF_UE_MAX+100]=""; - char buf[13*NUMBER_OF_UE_MAX+100]; - char *pbuf=buf; - - for (int i=0; idlsch[i][0]->harq_mask, eNB->dlsch[i][0]->rnti); - } - - int diff_size = memcmp(oldbuf, buf, strlen(buf)); - - if (diff_size!=0) - { - LOG_I(PHY,"check_dlsch:%s:%d:%s\n", file, line, buf); - LOG_I(PHY,"check_dlsch:%s:%d:%s\n", file, line, oldbuf); - } - - memcpy(oldbuf, buf, sizeof(buf)); -} - int8_t find_dlsch(uint16_t rnti, PHY_VARS_eNB *eNB,find_type_t type) { uint8_t i; @@ -2444,8 +2422,7 @@ void fill_dci0(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc, void *dci_pdu = (void*)dci_alloc->dci_pdu; - if (cqi_req) - LOG_W(PHY,"SFN/SF:%04d%d DCI0[rnti %x cqi %d mcs %d hopping %d rballoc %x (%d,%d) ndi %d TPC %d cshift %d]\n", + LOG_D(PHY,"SFN/SF:%04d%d DCI0[rnti %x cqi %d mcs %d hopping %d rballoc %x (%d,%d) ndi %d TPC %d cshift %d]\n", frame,subframe, pdu->dci_pdu_rel8.rnti,cqi_req, mcs,hopping,rballoc, pdu->dci_pdu_rel8.resource_block_start, @@ -2764,7 +2741,7 @@ int dump_dci(LTE_DL_FRAME_PARMS *frame_parms, DCI_ALLOC_t *dci) break; case 25: - LOG_I(PHY,"DCI format0 (FDD, 5MHz), rnti %x (%x): hopping %d, rb_alloc %x, mcs %d, ndi %d, TPC %d, cshift %d, cqi_req %d\n", + LOG_D(PHY,"DCI format0 (FDD, 5MHz), rnti %x (%x): hopping %d, rb_alloc %x, mcs %d, ndi %d, TPC %d, cshift %d, cqi_req %d\n", dci->rnti, ((uint32_t*)&dci->dci_pdu[0])[0], ((DCI0_5MHz_FDD_t *)&dci->dci_pdu[0])->hopping, @@ -6574,7 +6551,7 @@ uint32_t pdcch_alloc2ul_frame(LTE_DL_FRAME_PARMS *frame_parms,uint32_t frame, ui else ul_frame = (frame+(n>=6 ? 1 : 0)); - //LOG_D(PHY, "frame %d subframe %d: PUSCH frame = %d\n", frame, n, ul_frame); + LOG_D(PHY, "frame %d subframe %d: PUSCH frame = %d\n", frame, n, ul_frame); return ul_frame % 1024; } diff --git a/openair1/PHY/LTE_TRANSPORT/pucch.c b/openair1/PHY/LTE_TRANSPORT/pucch.c index c8da27bcb8..9a19b0ddaf 100644 --- a/openair1/PHY/LTE_TRANSPORT/pucch.c +++ b/openair1/PHY/LTE_TRANSPORT/pucch.c @@ -2455,9 +2455,9 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB, *(1+payload) = (stat_im<0) ? 1 : 2; } else { // insufficient energy on PUCCH so NAK #if defined(USRP_REC_PLAY) - LOG_I(PHY,"PUCCH 1a/b: NAK subframe %d : sigma2_dB %d, stat_max %d, pucch1_thres %d\n",subframe,sigma2_dB,dB_fixed(stat_max),pucch1_thres); + LOG_D(PHY,"PUCCH 1a/b: NAK subframe %d : sigma2_dB %d, stat_max %d, pucch1_thres %d\n",subframe,sigma2_dB,dB_fixed(stat_max),pucch1_thres); #else - LOG_I(PHY,"PUCCH 1a/b: subframe %d : sigma2_dB %d, stat_max %d, pucch1_thres %d\n",subframe,sigma2_dB,dB_fixed(stat_max),pucch1_thres); + LOG_D(PHY,"PUCCH 1a/b: subframe %d : sigma2_dB %d, stat_max %d, pucch1_thres %d\n",subframe,sigma2_dB,dB_fixed(stat_max),pucch1_thres); #endif *payload = 4; // DTX ((int16_t*)&eNB->pucch1ab_stats[UE_id][(subframe<<10) + (eNB->pucch1ab_stats_cnt[UE_id][subframe])])[0] = (int16_t)(stat_re); diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index edbca69433..1b3e634e6c 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -1577,7 +1577,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, #endif } - LOG_I(PHY,"frame %d subframe %d O_ACK:%d o_ACK[]=%d:%d:%d:%d\n",frame,subframe,ulsch_harq->O_ACK,ulsch_harq->o_ACK[0],ulsch_harq->o_ACK[1],ulsch_harq->o_ACK[2],ulsch_harq->o_ACK[3]); + LOG_D(PHY,"frame %d subframe %d O_ACK:%d o_ACK[]=%d:%d:%d:%d\n",frame,subframe,ulsch_harq->O_ACK,ulsch_harq->o_ACK[0],ulsch_harq->o_ACK[1],ulsch_harq->o_ACK[2],ulsch_harq->o_ACK[3]); // Do ULSCH Decoding for data portion diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c index 5f05d33f60..795ed5896b 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c @@ -1192,13 +1192,6 @@ void rx_ulsch(PHY_VARS_eNB *eNB, pusch_vars->ulsch_power[i] = signal_energy_nodc(pusch_vars->drs_ch_estimates[i], ulsch[UE_id]->harq_processes[harq_pid]->nb_rb*12)/correction_factor; - if(0)LOG_E(PHY,"rx_ulsch() i:%i drs: UE_id:%d harq_pid:%d nb_rb:%d correction_factor:%d\n", - i, - //pusch_vars->drs_ch_estimates[i], - UE_id, - harq_pid, - ulsch[UE_id]->harq_processes[harq_pid]->nb_rb, - correction_factor); /* printf("%4.4d.%d power harq_pid %d rb %2.2d TBS %2.2d (MPR_times_Ks %d correction %d) power %d dBtimes10\n", proc->frame_rx, proc->subframe_rx, harq_pid, ulsch[UE_id]->harq_processes[harq_pid]->nb_rb, ulsch[UE_id]->harq_processes[harq_pid]->TBS,MPR_times_100Ks,correction_factor,dB_fixed_times10(pusch_vars->ulsch_power[i])); */ } diff --git a/openair1/PHY/TOOLS/file_output.c b/openair1/PHY/TOOLS/file_output.c index c2256707b5..1a4adb04cd 100644 --- a/openair1/PHY/TOOLS/file_output.c +++ b/openair1/PHY/TOOLS/file_output.c @@ -33,7 +33,7 @@ int write_output(const char *fname,const char *vname,void *data,int length,int d int i; - //printf("Writing %d elements of type %d to %s\n",length,format,fname); + printf("Writing %d elements of type %d to %s\n",length,format,fname); if (format == 10 || format ==11 || format == 12 || format == 13 || format == 14) { @@ -68,11 +68,9 @@ int write_output(const char *fname,const char *vname,void *data,int length,int d case 15: for (i=0; iO_RI>1) ulsch_harq->Or2 = rel9->aperiodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[1]; ulsch->beta_offset_ri_times8 = to_beta_offset_ri[rel9->delta_offset_ri]; ulsch->beta_offset_cqi_times8 = to_beta_offset_cqi[rel9->delta_offset_cqi]; - LOG_E(PHY,"Filling ulsch_cqi_ri information for frame %d, subframe %d : O_RI %d, Or1 %d, beta_offset_cqi_times8 %d (%d)\n", + LOG_D(PHY,"Filling ulsch_cqi_ri information for frame %d, subframe %d : O_RI %d, Or1 %d, beta_offset_cqi_times8 %d (%d)\n", frame,subframe,ulsch_harq->O_RI,ulsch_harq->Or1,ulsch->beta_offset_cqi_times8, rel9->delta_offset_cqi); } @@ -622,7 +622,6 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) // DJP - AssertFatal(proc->subframe_tx == subframe, "Current subframe %d != NFAPI subframe %d\n",proc->subframe_tx,subframe); // DJP - AssertFatal(proc->subframe_tx == subframe, "Current frame %d != NFAPI frame %d\n",proc->frame_tx,frame); - uint8_t number_dci = DL_req->dl_config_request_body.number_dci; uint8_t number_pdcch_ofdm_symbols = DL_req->dl_config_request_body.number_pdcch_ofdm_symbols; uint8_t number_dl_pdu = DL_req->dl_config_request_body.number_pdu; @@ -636,18 +635,16 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) int i; eNB->pdcch_vars[subframe&1].num_pdcch_symbols = number_pdcch_ofdm_symbols; - eNB->pdcch_vars[subframe&1].num_dci = number_dci; + eNB->pdcch_vars[subframe&1].num_dci = 0; eNB->phich_vars[subframe&1].num_hi = 0; - if (number_dl_pdu || TX_req->tx_request_body.number_of_pdus || number_hi_dci0_pdu || number_ul_pdu) { - LOG_D(PHY,"NFAPI: Sched_INFO:SFN/SF:%04d%d DL_req:SFN/SF:%04d%d:dl_pdu:%d tx_req:SFN/SF:%04d%d:pdus:%d hi_dci0:SFN/SF:%04d%d:pdus:%d ul_cfg:SFN/SF:%04d%d:pdus:%d num_pdcch_symbols:%d\n", + LOG_D(PHY,"NFAPI: Sched_INFO:SFN/SF:%04d%d DL_req:SFN/SF:%04d%d:dl_pdu:%d tx_req:SFN/SF:%04d%d:pdus:%d hi_dci0:SFN/SF:%04d%d:pdus:%d ul_cfg:SFN/SF:%04d%d:pdus:%d num_pdcch_symbols:%d\n", frame,subframe, NFAPI_SFNSF2SFN(DL_req->sfn_sf),NFAPI_SFNSF2SF(DL_req->sfn_sf),number_dl_pdu, NFAPI_SFNSF2SFN(TX_req->sfn_sf),NFAPI_SFNSF2SF(TX_req->sfn_sf),TX_req->tx_request_body.number_of_pdus, NFAPI_SFNSF2SFN(HI_DCI0_req->sfn_sf),NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf),number_hi_dci0_pdu, NFAPI_SFNSF2SFN(UL_req->sfn_sf),NFAPI_SFNSF2SF(UL_req->sfn_sf),number_ul_pdu, eNB->pdcch_vars[subframe&1].num_pdcch_symbols); - } int do_oai =0; int dont_send =0; diff --git a/openair1/SCHED/fapi_l1.h b/openair1/SCHED/fapi_l1.h index a912fa9f01..725bb31c45 100644 --- a/openair1/SCHED/fapi_l1.h +++ b/openair1/SCHED/fapi_l1.h @@ -48,7 +48,7 @@ void handle_nfapi_hi_dci0_dci_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_r nfapi_hi_dci0_request_pdu_t *hi_dci0_config_pdu); void handle_nfapi_hi_dci0_hi_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc, nfapi_hi_dci0_request_pdu_t *hi_dci0_config_pdu); -void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc, +void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc, nfapi_dl_config_request_pdu_t *dl_config_pdu, uint8_t codeword_index, uint8_t *sdu); diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 5c0b8cd7fd..db729187cb 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -271,8 +271,7 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, int input_buffer_length = dlsch_harq->TBS/8; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - if (1){ - //if (dlsch->rnti == 0x02) {//frame < 200) { + if (dlsch->rnti == 0x02) {//frame < 200) { LOG_D(PHY, "[eNB %"PRIu8"][PDSCH %"PRIx16"/%"PRIu8"] Frame %d, subframe %d: Generating PDSCH/DLSCH with input size = %"PRIu16", pdsch_start %d, G %d, nb_rb %"PRIu16", rb0 %x, rb1 %x, TBS %"PRIu16", pmi_alloc %"PRIx64", rv %"PRIu8" (round %"PRIu8")\n", @@ -490,17 +489,15 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, num_dci = eNB->pdcch_vars[subframe&1].num_dci; // LOG_D(PHY,"num_pdcch_symbols %"PRIu8",(dci common %"PRIu8", dci uespec %"PRIu8"\n",num_pdcch_symbols, // DCI_pdu->Num_common_dci,DCI_pdu->Num_ue_spec_dci); - //LOG_D(PHY,"num_pdcch_symbols %"PRIu8",number dci %"PRIu8"\n",num_pdcch_symbols, num_dci); + LOG_D(PHY,"num_pdcch_symbols %"PRIu8",number dci %"PRIu8"\n",num_pdcch_symbols, num_dci); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,num_pdcch_symbols); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,(frame*10)+subframe); if (num_dci > 0) - { - //LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_top (pdcch) (num_dci %"PRIu8") num_pdcch_symbols:%d\n",eNB->Mod_id,frame, subframe, num_dci, num_pdcch_symbols); - } - + LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_top (pdcch) (num_dci %"PRIu8") num_pdcch_symbols:%d\n",eNB->Mod_id,frame, subframe, num_dci, num_pdcch_symbols); + //LOG_D(PHY,"Before generate_dci_top num_pdcch_symbols:%d num_dci:%d dci_alloc:dci_length:%d\n", num_pdcch_symbols, num_dci, eNB->pdcch_vars[subframe&1].dci_alloc[0].dci_length); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,1); @@ -640,8 +637,7 @@ void prach_procedures(PHY_VARS_eNB *eNB, ); //#ifdef DEBUG_PHY_PROC - if (max_preamble_energy[0]/10 > 32) - LOG_E(PHY,"[RAPROC] Frame %d, subframe %d : Most likely preamble %d, energy %d dB delay %d\n", + LOG_D(PHY,"[RAPROC] Frame %d, subframe %d : Most likely preamble %d, energy %d dB delay %d\n", frame,subframe, max_preamble[0], max_preamble_energy[0]/10, @@ -699,7 +695,7 @@ void prach_procedures(PHY_VARS_eNB *eNB, if ((eNB->prach_energy_counter == 100) && (max_preamble_energy[0] > eNB->measurements.prach_I0+100)) { - LOG_E(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", + LOG_D(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", eNB->Mod_id, eNB->CC_id, frame, @@ -729,7 +725,7 @@ void prach_procedures(PHY_VARS_eNB *eNB, if (nfapi_mode == 1) { // If NFAPI PNF then we need to send the message to the VNF - LOG_E(PHY,"Filling NFAPI indication for RACH : SFN_SF:%d TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", + LOG_D(PHY,"Filling NFAPI indication for RACH : SFN_SF:%d TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", NFAPI_SFNSF2DEC(eNB->UL_INFO.rach_ind.sfn_sf), eNB->preamble_list[0].preamble_rel8.timing_advance, eNB->preamble_list[0].preamble_rel8.preamble, @@ -1300,14 +1296,14 @@ void uci_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) } if (SR_payload == 1) { - LOG_E(PHY,"[eNB %d][SR %x] Frame %d subframe %d Got SR for PUSCH, transmitting to MAC\n",eNB->Mod_id, + LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Got SR for PUSCH, transmitting to MAC\n",eNB->Mod_id, uci->rnti,frame,subframe); if (eNB->first_sr[i] == 1) { // this is the first request for uplink after Connection Setup, so clear HARQ process 0 use for Msg4 eNB->first_sr[i] = 0; eNB->dlsch[i][0]->harq_processes[0]->round=0; eNB->dlsch[i][0]->harq_processes[0]->status=SCH_IDLE; - LOG_E(PHY,"[eNB %d][SR %x] Frame %d subframe %d First SR\n", + LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d First SR\n", eNB->Mod_id, eNB->ulsch[i]->rnti,frame,subframe); } @@ -1324,7 +1320,6 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; LTE_eNB_ULSCH_t *ulsch; LTE_UL_eNB_HARQ_t *ulsch_harq; - struct timespec t_decode, t_crc,t_rx_ind,t_rx_ind_b,t_harq_a,t_harq_b,t_end; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; @@ -1354,7 +1349,7 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) eNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31)); } - //LOG_D(PHY,"[eNB %d] frame %d, subframe %d: Scheduling ULSCH Reception for UE %d \n", eNB->Mod_id, frame, subframe, i); + LOG_D(PHY,"[eNB %d] frame %d, subframe %d: Scheduling ULSCH Reception for UE %d \n", eNB->Mod_id, frame, subframe, i); nPRS = fp->pusch_config_common.ul_ReferenceSignalsPUSCH.nPRS[subframe<<1]; @@ -1362,7 +1357,7 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift + nPRS)%12; - if(0)LOG_D(PHY, + LOG_D(PHY, "[eNB %d][PUSCH %d] Frame %d Subframe %d Demodulating PUSCH: dci_alloc %d, rar_alloc %d, round %d, first_rb %d, nb_rb %d, Qm %d, TBS %d, rv %d, cyclic_shift %d (n_DMRS2 %d, cyclicShift_common %d, ), O_ACK %d, beta_cqi %d \n", eNB->Mod_id,harq_pid,frame,subframe, ulsch_harq->dci_alloc, @@ -1385,8 +1380,6 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) stop_meas(&eNB->ulsch_demodulation_stats); - clock_gettime(CLOCK_MONOTONIC,&t_decode); - start_meas(&eNB->ulsch_decoding_stats); ret = ulsch_decoding(eNB,proc, @@ -1440,7 +1433,6 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) ulsch->Mlimit, ulsch_harq->o_ACK[0], ulsch_harq->o_ACK[1]); - if (ulsch_harq->round >= 3) { ulsch_harq->status = SCH_IDLE; ulsch_harq->handled = 0; @@ -1466,12 +1458,8 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) ulsch_harq->handled = 1; } // ulsch in error else { - clock_gettime(CLOCK_MONOTONIC,&t_crc); - fill_crc_indication(eNB,i,frame,subframe,0); // indicate ACK to MAC - clock_gettime(CLOCK_MONOTONIC,&t_rx_ind); fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC - clock_gettime(CLOCK_MONOTONIC,&t_rx_ind_b); ulsch_harq->status = SCH_IDLE; ulsch->harq_mask &= ~(1 << harq_pid); @@ -1502,9 +1490,7 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) #endif } // ulsch not in error - clock_gettime(CLOCK_MONOTONIC,&t_harq_a); if (ulsch_harq->O_ACK>0) fill_ulsch_harq_indication(eNB,ulsch_harq,ulsch->rnti,frame,subframe,ulsch->bundling); - clock_gettime(CLOCK_MONOTONIC,&t_harq_b); LOG_D(PHY,"[eNB %d] Frame %d subframe %d: received ULSCH harq_pid %d for UE %d, ret = %d, CQI CRC Status %d, ACK %d,%d, ulsch_errors %d/%d\n", eNB->Mod_id,frame,subframe, @@ -1533,15 +1519,6 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) ulsch->rnti, harq_pid, ulsch->harq_mask); } } // for (i=0; iUL_INFO.harq_ind.harq_indication_body.number_of_harqs,ulsch_harq->O_ACK); + LOG_D(PHY,"%s(eNB, ulsch_harq, rnti:%04x, frame:%d, subframe:%d, bundling:%d) harq_pdus:%d O_ACK:%d\n", __FUNCTION__, rnti, frame, subframe, bundling,eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs,ulsch_harq->O_ACK); pthread_mutex_lock(&eNB->UL_INFO_mutex); nfapi_harq_indication_pdu_t *pdu = &eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list[eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs]; @@ -2038,7 +2015,7 @@ void fill_crc_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe,uint // pdu->rx_ue_information.handle = handle; pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; pdu->rx_ue_information.rnti = eNB->ulsch[UE_id]->rnti; - pdu->crc_indication_rel8.tl.tag = NFAPI_CRC_INDICATION_REL8_TAG; + pdu->crc_indication_rel8.tl.tag = NFAPI_CRC_INDICATION_REL8_TAG; pdu->crc_indication_rel8.crc_flag = crc_flag; eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs++; @@ -2067,13 +2044,17 @@ void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,const VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 1 ); - //LOG_D(PHY,"[eNB %d] Frame %d: Doing phy_procedures_eNB_uespec_RX(%d)\n",eNB->Mod_id,frame, subframe); + LOG_D(PHY,"[eNB %d] Frame %d: Doing phy_procedures_eNB_uespec_RX(%d)\n",eNB->Mod_id,frame, subframe); eNB->rb_mask_ul[0]=0; eNB->rb_mask_ul[1]=0; eNB->rb_mask_ul[2]=0; eNB->rb_mask_ul[3]=0; + // Fix me here, these should be locked + eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus = 0; + eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs = 0; + // Call SRS first since all others depend on presence of SRS or lack thereof srs_procedures(eNB,proc); diff --git a/openair1/SCHED/ru_procedures.c b/openair1/SCHED/ru_procedures.c index ce49d72c68..d9943f03d9 100644 --- a/openair1/SCHED/ru_procedures.c +++ b/openair1/SCHED/ru_procedures.c @@ -369,16 +369,6 @@ void feptx_prec(RU_t *ru) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC , 1); - //LOG_D(PHY, "%s() subframe:%d\n", __FUNCTION__, subframe); - - if (0) LOG_E(PHY,"%s() run->nb_tx:%u subframe:%u fp->symbols_per_tti:%u fp->ofdm_symbol_size:%u symbols:(%d, %d), (%d,%d)\n", - __FUNCTION__, ru->nb_tx, subframe, fp->symbols_per_tti, fp->ofdm_symbol_size, - ((short*)&eNB->common_vars.txdataF[0][1])[0], - ((short*)&eNB->common_vars.txdataF[0][1])[1], - ((short*)&eNB->common_vars.txdataF[0][2])[0], - ((short*)&eNB->common_vars.txdataF[0][2])[1] - ); - for (aa=0;aanb_tx;aa++) memcpy((void*)ru->common.txdataF_BF[aa], (void*)&eNB->common_vars.txdataF[aa][subframe*fp->symbols_per_tti*fp->ofdm_symbol_size], diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index 01872c0697..c7585521f1 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -241,22 +241,22 @@ void RCconfig_L1(void) { if (RC.eNB == NULL) { - RC.eNB = (PHY_VARS_eNB ***)malloc((1+MAX_NUM_CCs)*sizeof(PHY_VARS_eNB**)); + RC.eNB = (PHY_VARS_eNB ***)malloc((1+NUMBER_OF_eNB_MAX)*sizeof(PHY_VARS_eNB**)); LOG_I(PHY,"RC.eNB = %p\n",RC.eNB); - memset(RC.eNB,0,(1+NUMBER_OF_eNB_MAX)*sizeof(PHY_VARS_eNB***)); + memset(RC.eNB,0,(1+NUMBER_OF_eNB_MAX)*sizeof(PHY_VARS_eNB**)); RC.nb_L1_CC = malloc((1+RC.nb_L1_inst)*sizeof(int)); } - config_getlist( &L1_ParamList,L1_Params,sizeof(L1_Params)/sizeof(paramdef_t), NULL); + config_getlist( &L1_ParamList,L1_Params,sizeof(L1_Params)/sizeof(paramdef_t), NULL); if (L1_ParamList.numelt > 0) { for (j = 0; j < RC.nb_L1_inst; j++) { RC.nb_L1_CC[j] = *(L1_ParamList.paramarray[j][L1_CC_IDX].uptr); if (RC.eNB[j] == NULL) { - RC.eNB[j] = (PHY_VARS_eNB **)malloc((1+MAX_NUM_CCs)*sizeof(PHY_VARS_eNB**)); + RC.eNB[j] = (PHY_VARS_eNB **)malloc((1+MAX_NUM_CCs)*sizeof(PHY_VARS_eNB*)); LOG_I(PHY,"RC.eNB[%d] = %p\n",j,RC.eNB[j]); - memset(RC.eNB[j],0,(1+MAX_NUM_CCs)*sizeof(PHY_VARS_eNB***)); + memset(RC.eNB[j],0,(1+MAX_NUM_CCs)*sizeof(PHY_VARS_eNB*)); } for (i=0;istate = WAITMSG3; - LOG_I(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:WAITMSG3\n", module_idP, frameP, subframeP); + LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:WAITMSG3\n", module_idP, frameP, subframeP); dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; @@ -553,7 +553,7 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, mac->DL_req[CC_idP].sfn_sf = (frameP<<4)+subframeP; mac->DL_req[CC_idP].header.message_id = NFAPI_DL_CONFIG_REQUEST; - LOG_E(MAC,"DL_CONFIG SFN/SF:%d/%d MESSAGE2\n", frameP, subframeP); + LOG_D(MAC,"DL_CONFIG SFN/SF:%d/%d MESSAGE2\n", frameP, subframeP); // Program UL processing for Msg3, same as regular LTE get_Msg3alloc(&cc[CC_idP], subframeP, frameP, @@ -693,7 +693,7 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, cc[CC_idP].RAR_pdu.payload, N_RB_DL, 7); add_msg3(module_idP, CC_idP, ra, frameP, subframeP); ra->state = WAITMSG3; - LOG_I(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:WAITMSG3\n", module_idP, frameP, subframeP); + LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:WAITMSG3\n", module_idP, frameP, subframeP); // DL request mac->TX_req[CC_idP].sfn_sf = (frameP << 4) + subframeP; @@ -828,7 +828,7 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, dl_req = &mac->DL_req[CC_idP]; dl_req_body = &dl_req->dl_config_request_body; - dl_config_pdu = &dl_req_body->dl_config_pdu_list[dl_req_body->number_pdu]; + dl_config_pdu = &dl_req_body->dl_config_pdu_list[dl_req_body->number_pdu]; N_RB_DL = to_prb(cc[CC_idP].mib->message.dl_Bandwidth); UE_id = find_UE_id(module_idP, ra->rnti); @@ -1058,7 +1058,7 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, mac->DL_req[CC_idP].header.message_id = NFAPI_DL_CONFIG_REQUEST; ra->state = WAITMSG4ACK; - LOG_I(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:WAITMSG4ACK\n", module_idP, frameP, subframeP); + LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:WAITMSG4ACK\n", module_idP, frameP, subframeP); lcid = 0; @@ -1270,7 +1270,7 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, dl_req_body->number_pdu++; ra->state = WAITMSG4ACK; - LOG_I(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:WAITMSG4ACK\n", module_idP, frameP, subframeP); + LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:WAITMSG4ACK\n", module_idP, frameP, subframeP); // increment Absolute subframe by 8 for Msg4 retransmission LOG_D(MAC, @@ -1575,7 +1575,7 @@ check_Msg4_retransmission(module_id_t module_idP, int CC_idP, "[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d : Msg4 acknowledged\n", module_idP, CC_idP, frameP, subframeP); ra->state = IDLE; - LOG_I(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:IDLE\n", module_idP, frameP, subframeP); + LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:IDLE\n", module_idP, frameP, subframeP); UE_id = find_UE_id(module_idP, ra->rnti); DevAssert(UE_id != -1); mac->UE_list.UE_template[UE_PCCID(module_idP, UE_id)][UE_id]. @@ -1653,7 +1653,7 @@ initiate_ra_proc(module_id_t module_idP, prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13; } - LOG_I(MAC, + LOG_D(MAC, "[eNB %d][RAPROC] CC_id %d Frame %d, Subframe %d Initiating RA procedure for preamble index %d\n", module_idP, CC_id, frameP, subframeP, preamble_index); #ifdef Rel14 diff --git a/openair2/LAYER2/MAC/eNB_scheduler_bch.c b/openair2/LAYER2/MAC/eNB_scheduler_bch.c index 777d8b6061..5b0fc58bb7 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_bch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_bch.c @@ -608,11 +608,11 @@ schedule_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) mib_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, MIBCH, 1, &cc->MIB_pdu.payload[0], 1, module_idP, 0); // not used in this case - //LOG_D(MAC, "Frame %d, subframe %d: BCH PDU length %d\n", frameP, subframeP, mib_sdu_length); + LOG_D(MAC, "Frame %d, subframe %d: BCH PDU length %d\n", frameP, subframeP, mib_sdu_length); if (mib_sdu_length > 0) { - //LOG_D(MAC, "Frame %d, subframe %d: Adding BCH PDU in position %d (length %d)\n", frameP, subframeP, dl_req->number_pdu, mib_sdu_length); + LOG_D(MAC, "Frame %d, subframe %d: Adding BCH PDU in position %d (length %d)\n", frameP, subframeP, dl_req->number_pdu, mib_sdu_length); if ((frameP & 1023) < 40) LOG_D(MAC, @@ -638,7 +638,7 @@ schedule_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) dl_config_request->header.message_id = NFAPI_DL_CONFIG_REQUEST; dl_config_request->sfn_sf = sfn_sf; - //LOG_D(MAC, "eNB->DL_req[0].number_pdu %d (%p)\n", dl_req->number_pdu, &dl_req->number_pdu); + LOG_D(MAC, "eNB->DL_req[0].number_pdu %d (%p)\n", dl_req->number_pdu, &dl_req->number_pdu); // DL request TX_req = @@ -695,7 +695,7 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) bcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, BCCH, 1, &cc->BCCH_pdu.payload[0], 1, module_idP, 0); // not used in this case if (bcch_sdu_length > 0) { - //LOG_D(MAC, "[eNB %d] Frame %d : BCCH->DLSCH CC_id %d, Received %d bytes \n", module_idP, frameP, CC_id, bcch_sdu_length); + LOG_D(MAC, "[eNB %d] Frame %d : BCCH->DLSCH CC_id %d, Received %d bytes \n", module_idP, frameP, CC_id, bcch_sdu_length); // Allocate 4 PRBs in a random location /* @@ -786,7 +786,7 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) (module_idP, CC_id, 0, subframeP, dl_config_pdu->dci_dl_pdu. dci_dl_pdu_rel8.aggregation_level, SI_RNTI)) { - //LOG_D(MAC, "Frame %d: Subframe %d : Adding common DCI for S_RNTI\n", frameP, subframeP); + LOG_D(MAC, "Frame %d: Subframe %d : Adding common DCI for S_RNTI\n", frameP, subframeP); dl_req->number_dci++; dl_req->number_pdu++; dl_config_pdu = @@ -888,7 +888,7 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) "[eNB] Frame %d : Scheduling BCCH->DLSCH (TDD) for CC_id %d SI %d bytes (mcs %d, rb 3)\n", frameP, CC_id, bcch_sdu_length, mcs); } else { - //LOG_D(MAC, "[eNB] Frame %d : Scheduling BCCH->DLSCH (FDD) for CC_id %d SI %d bytes (mcs %d, rb 3)\n", frameP, CC_id, bcch_sdu_length, mcs); + LOG_D(MAC, "[eNB] Frame %d : Scheduling BCCH->DLSCH (FDD) for CC_id %d SI %d bytes (mcs %d, rb 3)\n", frameP, CC_id, bcch_sdu_length, mcs); } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 5687889e96..fe6c045fe7 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -547,7 +547,7 @@ schedule_ue_spec(module_id_t module_idP, (VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_OUT); for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - //LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n", CC_id); + LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n", CC_id); dl_req = &eNB->DL_req[CC_id].dl_config_request_body; @@ -675,7 +675,7 @@ schedule_ue_spec(module_id_t module_idP, = 0; } - LOG_I(MAC, + LOG_D(MAC, "[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n", module_idP, frameP, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb, ue_sched_ctl->dl_cqi[CC_id], @@ -761,7 +761,7 @@ schedule_ue_spec(module_id_t module_idP, case 2: case 7: default: - LOG_I(MAC,"retransmission DL_REQ: rnti:%x\n",rnti); + LOG_D(MAC,"retransmission DL_REQ: rnti:%x\n",rnti); dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req-> @@ -1223,8 +1223,8 @@ schedule_ue_spec(module_id_t module_idP, padding, post_padding); //#ifdef DEBUG_eNB_SCHEDULER - if (1 || ta_update != 31) { - LOG_I(MAC, + if (ta_update != 31) { + LOG_D(MAC, "[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n", module_idP, frameP, UE_id, CC_id, sdu_length_total, num_sdus, sdu_lengths[0], @@ -1553,7 +1553,7 @@ fill_DLSCH_dci(module_id_t module_idP, (VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI, VCD_FUNCTION_IN); for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - //LOG_D(MAC, "Doing fill DCI for CC_id %d\n", CC_id); + LOG_D(MAC, "Doing fill DCI for CC_id %d\n", CC_id); if (mbsfn_flagP[CC_id] > 0) continue; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 7bba9145fc..1bffb83d49 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -1036,7 +1036,7 @@ fill_nfapi_dl_dci_1A(nfapi_dl_config_request_pdu_t * dl_config_pdu, dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; @@ -2030,7 +2030,7 @@ get_aggregation(uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt) LOG_W(MAC, "unsupported DCI format %d\n", dci_fmt); } - //LOG_D(MAC, "Aggregation level %d (cqi %d, bw_index %d, format %d)\n", 1 << aggregation, cqi, bw_index, dci_fmt); + LOG_D(MAC, "Aggregation level %d (cqi %d, bw_index %d, format %d)\n", 1 << aggregation, cqi, bw_index, dci_fmt); return 1 << aggregation; } @@ -3100,8 +3100,7 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) int i, j, idci; int nCCE = 0; - if (0 && (DL_req->number_pdu || DL_req->number_dci || HI_DCI0_req->number_of_dci)) - LOG_D(MAC, + LOG_D(MAC, "Allocate CCEs subframe %d, test %d : (DL PDU %d, DL DCI %d, UL %d)\n", subframeP, test_onlyP, DL_req->number_pdu, DL_req->number_dci, HI_DCI0_req->number_of_dci); @@ -3116,7 +3115,6 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) && (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type == 2)) { -#if 0 LOG_D(MAC, "Trying to allocate COMMON DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", idci, DL_req->number_dci + HI_DCI0_req->number_of_dci, @@ -3125,7 +3123,6 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) dl_config_pdu[i].dci_dl_pdu. dci_dl_pdu_rel8.aggregation_level, nCCE, nCCE_max, DL_req->number_pdcch_ofdm_symbols); -#endif if (nCCE + (dl_config_pdu[i].dci_dl_pdu. @@ -3197,16 +3194,14 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) nCCE += dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8. aggregation_level; - //LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); + LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); if (test_onlyP == 0) { dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = fCCE; -#if 0 LOG_D(MAC, "Allocate COMMON DCI CCEs subframe %d, test %d => L %d fCCE %d\n", subframeP, test_onlyP, dl_config_pdu[i].dci_dl_pdu. dci_dl_pdu_rel8.aggregation_level, fCCE); -#endif } idci++; } @@ -3293,7 +3288,7 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) // the allocation is feasible, rnti rule passes nCCE += hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level; - //LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); + LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); if (test_onlyP == 0) { hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.cce_index = fCCE; LOG_D(MAC, "Allocate CCEs subframe %d, test %d\n", @@ -3308,7 +3303,6 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) && (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type == 1)) { -#if 0 LOG_D(MAC, "Trying to allocate DL UE-SPECIFIC DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", idci, DL_req->number_dci + HI_DCI0_req->number_of_dci, @@ -3317,7 +3311,6 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) dl_config_pdu[i].dci_dl_pdu. dci_dl_pdu_rel8.aggregation_level, nCCE, nCCE_max, DL_req->number_pdcch_ofdm_symbols); -#endif if (nCCE + (dl_config_pdu[i].dci_dl_pdu. @@ -3390,7 +3383,7 @@ allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) nCCE += dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8. aggregation_level; - //LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); + LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); if (test_onlyP == 0) { dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = fCCE; LOG_D(MAC, "Allocate CCEs subframe %d, test %d\n", @@ -3566,7 +3559,6 @@ CCE_allocation_infeasible(int module_idP, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = aggregation; DL_req->number_pdu++; -#if 0 LOG_D(MAC, "Subframe %d: Checking CCE feasibility format %d : (%x,%d) (%x,%d,%d)\n", subframe, format_flag, rnti, aggregation, @@ -3574,7 +3566,6 @@ CCE_allocation_infeasible(int module_idP, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. aggregation_level, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type); -#endif ret = allocate_CCEs(module_idP, CC_idP, subframe, 0); if (ret == -1) res = TRUE; @@ -3674,7 +3665,7 @@ extract_harq(module_id_t mod_idP, int CC_idP, int UE_id, uint8_t harq_pid = ((10 * frameP) + subframeP + 10236) & 7; - LOG_I(MAC,"frame %d subframe %d harq_pid %d mode %d tmode[0] %d num_ack_nak %d round %d\n",frameP,subframeP,harq_pid,harq_indication_fdd->mode,tmode[0],num_ack_nak,sched_ctl->round[CC_idP][harq_pid]); + LOG_D(MAC,"frame %d subframe %d harq_pid %d mode %d tmode[0] %d num_ack_nak %d round %d\n",frameP,subframeP,harq_pid,harq_indication_fdd->mode,tmode[0],num_ack_nak,sched_ctl->round[CC_idP][harq_pid]); switch (harq_indication_fdd->mode) { case 0: // Format 1a/b (10.1.2.1) @@ -4368,7 +4359,7 @@ cqi_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, if (UE_id >= 0) { - LOG_E(MAC,"%s() UE_id:%d channel:%d cqi:%d\n", __FUNCTION__, UE_id, ul_cqi_information->channel, ul_cqi_information->ul_cqi); + LOG_D(MAC,"%s() UE_id:%d channel:%d cqi:%d\n", __FUNCTION__, UE_id, ul_cqi_information->channel, ul_cqi_information->ul_cqi); if (ul_cqi_information->channel == 0) { // PUCCH @@ -4476,7 +4467,7 @@ harq_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; // extract HARQ Information - LOG_I(MAC, + LOG_D(MAC, "Frame %d, subframe %d: Received harq indication (%d) from UE %d/%x, ul_cqi %d\n", frameP, subframeP, channel, UE_id, rnti, ul_cqi); if (cc->tdd_Config) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 405c7d2a75..def57639f6 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -185,7 +185,7 @@ rx_sdu(const module_id_t enb_mod_idP, maxHARQ_Msg3Tx); LOG_D(MAC, - "[eNB %d][PUSCH %d] CC_id %d Received ULSCH sdu round %d from PHY (rnti %x, RA_id %d) ul_cqi %d\n", + "[eNB %d][PUSCH %d] CC_id %d [RAPROC Msg3] Received ULSCH sdu round %d from PHY (rnti %x, RA_id %d) ul_cqi %d\n", enb_mod_idP, harq_pid, CC_idP, ra[RA_id].msg3_round, current_rnti, RA_id, ul_cqi); @@ -211,10 +211,8 @@ rx_sdu(const module_id_t enb_mod_idP, first_rb_ul[harq_pid]; ra[RA_id].msg3_round++; // prepare handling of retransmission - ra[RA_id].Msg3_frame += - ((ra[RA_id].Msg3_subframe > 1) ? 1 : 0); - ra[RA_id].Msg3_subframe = - (ra[RA_id].Msg3_subframe + 8) % 10; + ra[RA_id].Msg3_frame = (ra[RA_id].Msg3_frame + ((ra[RA_id].Msg3_subframe > 1) ? 1 : 0)) % 1024; + ra[RA_id].Msg3_subframe = (ra[RA_id].Msg3_subframe + 8) % 10; add_msg3(enb_mod_idP, CC_idP, &ra[RA_id], frameP, subframeP); } @@ -1235,7 +1233,7 @@ schedule_ulsch_rnti(module_id_t module_idP, // this is the normalized RX power and this should be constant (regardless of mcs normalized_rx_power = UE_sched_ctrl->pusch_snr[CC_id]; - target_rx_power = 204; + target_rx_power = 178; // this assumes accumulated tpc // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 11fd11e4b8..23d3f3bd60 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -1234,7 +1234,8 @@ dlsch_scheduler_pre_processor_reset(int module_idP, break; } } - //LOG_D(MAC, "Frame %d Subframe %d CC_id %d RBG %i : rb_alloc %d\n", frameP, subframeP, CC_id, i, rballoc_sub[CC_id][i]); + LOG_D(MAC, "Frame %d Subframe %d CC_id %d RBG %i : rb_alloc %d\n", + frameP, subframeP, CC_id, i, rballoc_sub[CC_id][i]); MIMO_mode_indicator[CC_id][i] = 2; } } @@ -1339,11 +1340,11 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, UE_TEMPLATE *UE_template = 0; int N_RB_DL; int N_RB_UL; - //LOG_D(MAC, "In ulsch_preprocessor: assign max mcs min rb\n"); + LOG_D(MAC, "In ulsch_preprocessor: assign max mcs min rb\n"); // maximize MCS and then allocate required RB according to the buffer occupancy with the limit of max available UL RB assign_max_mcs_min_rb(module_idP, frameP, subframeP, first_rb); - //LOG_D(MAC, "In ulsch_preprocessor: sort ue \n"); + LOG_D(MAC, "In ulsch_preprocessor: sort ue \n"); // sort ues sort_ue_ul(module_idP, frameP, subframeP); @@ -1366,7 +1367,7 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, } } - //LOG_D(MAC, "In ulsch_preprocessor: step2 \n"); + LOG_D(MAC, "In ulsch_preprocessor: step2 \n"); // step 2: calculate the average rb per UE total_ue_count = 0; max_num_ue_to_be_scheduled = 0; @@ -1384,11 +1385,12 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, UE_id = i; - //LOG_D(MAC, "In ulsch_preprocessor: handling UE %d/%x\n", UE_id, rnti); + LOG_D(MAC, "In ulsch_preprocessor: handling UE %d/%x\n", UE_id, + rnti); for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { // This is the actual CC_id in the list CC_id = UE_list->ordered_ULCCids[n][UE_id]; - if(0)LOG_D(MAC, + LOG_D(MAC, "In ulsch_preprocessor: handling UE %d/%x CCid %d\n", UE_id, rnti, CC_id); UE_template = &UE_list->UE_template[CC_id][UE_id]; @@ -1468,7 +1470,7 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, } total_allocated_rbs[CC_id] += nb_allocated_rbs[CC_id][UE_id]; - if(0)LOG_D(MAC, + LOG_D(MAC, "In ulsch_preprocessor: assigning %d RBs for UE %d/%x CCid %d, harq_pid %d\n", nb_allocated_rbs[CC_id][UE_id], UE_id, rnti, CC_id, harq_pid); diff --git a/openair2/PHY_INTERFACE/IF_Module.c b/openair2/PHY_INTERFACE/IF_Module.c index 6402f3322f..d0b8e57558 100644 --- a/openair2/PHY_INTERFACE/IF_Module.c +++ b/openair2/PHY_INTERFACE/IF_Module.c @@ -75,7 +75,7 @@ void handle_sr(UL_IND_t *UL_info) { } else { - for (i=0;isr_ind.sr_indication_body.number_of_srs;i++) + for (i=0;isr_ind.sr_indication_body.number_of_srs;i++) SR_indication(UL_info->module_id, UL_info->CC_id, UL_info->frame, @@ -127,8 +127,6 @@ void handle_harq(UL_IND_t *UL_info) { int i; - //if (UL_info->harq_ind.number_of_harqs>0) - if (nfapi_mode == 1 && UL_info->harq_ind.harq_indication_body.number_of_harqs>0) // PNF { //LOG_D(PHY, "UL_info->harq_ind.harq_indication_body.number_of_harqs:%d Send to VNF\n", UL_info->harq_ind.harq_indication_body.number_of_harqs); @@ -144,7 +142,7 @@ void handle_harq(UL_IND_t *UL_info) { } else { - for (i=0;iharq_ind.harq_indication_body.number_of_harqs;i++) + for (i=0;iharq_ind.harq_indication_body.number_of_harqs;i++) harq_indication(UL_info->module_id, UL_info->CC_id, NFAPI_SFNSF2SFN(UL_info->harq_ind.sfn_sf), @@ -303,7 +301,7 @@ static void dump_ul(UL_IND_t *u) A("XXXX crc_ind %d\n", u->crc_ind.crc_indication_body.number_of_crcs); - A("XXXX sr_ind %d\n", u->sr_ind.number_of_srs); + A("XXXX sr_ind %d\n", u->sr_ind.sr_indication_body.number_of_srs); A("XXXX cqi_ind %d\n", u->cqi_ind.number_of_cqis); for (i = 0; i < u->cqi_ind.number_of_cqis; i++) { @@ -544,17 +542,10 @@ void UL_indication(UL_IND_t *UL_info) IF_Module_t *ifi = if_inst[module_id]; eNB_MAC_INST *mac = RC.mac[module_id]; - if (UL_info->rx_ind.rx_indication_body.number_of_pdus || - UL_info->harq_ind.harq_indication_body.number_of_harqs || - UL_info->crc_ind.crc_indication_body.number_of_crcs || - UL_info->cqi_ind.number_of_cqis || - UL_info->rach_ind.rach_indication_body.number_of_preambles || - UL_info->sr_ind.sr_indication_body.number_of_srs) { - LOG_D(PHY,"SFN/SF:%d%d module_id:%d CC_id:%d UL_info[rx_ind:%d harqs:%d crcs:%d cqis:%d preambles:%d sr_ind:%d]\n", + LOG_D(PHY,"SFN/SF:%d%d module_id:%d CC_id:%d UL_info[rx_ind:%d harqs:%d crcs:%d cqis:%d preambles:%d sr_ind:%d]\n", UL_info->frame,UL_info->subframe, module_id,CC_id, UL_info->rx_ind.rx_indication_body.number_of_pdus, UL_info->harq_ind.harq_indication_body.number_of_harqs, UL_info->crc_ind.crc_indication_body.number_of_crcs, UL_info->cqi_ind.number_of_cqis, UL_info->rach_ind.rach_indication_body.number_of_preambles, UL_info->sr_ind.sr_indication_body.number_of_srs); - } if (nfapi_mode != 1) { @@ -570,12 +561,9 @@ void UL_indication(UL_IND_t *UL_info) } - //LOG_D(PHY,"%s() SFN_SF:%d%d About to call clear_nfapi_information()\n", __FUNCTION__, UL_info->frame, UL_info->subframe); - // clear DL/UL info for new scheduling round clear_nfapi_information(RC.mac[module_id],CC_id, UL_info->frame,UL_info->subframe); - //LOG_D(PHY,"%s() SFN_SF:%d%d Returned from call clear_nfapi_information()\n", __FUNCTION__, UL_info->frame, UL_info->subframe); handle_rach(UL_info); @@ -607,7 +595,7 @@ void UL_indication(UL_IND_t *UL_info) sched_info->DL_req = &mac->DL_req[CC_id]; sched_info->HI_DCI0_req = &mac->HI_DCI0_req[CC_id]; if ((mac->common_channels[CC_id].tdd_Config==NULL) || - (is_UL_sf(&mac->common_channels[CC_id],(sched_info->subframe+sf_ahead)%10)>0)) + (is_UL_sf(&mac->common_channels[CC_id],(sched_info->subframe+sf_ahead)%10)>0)) sched_info->UL_req = &mac->UL_req[CC_id]; else sched_info->UL_req = NULL; @@ -627,9 +615,8 @@ void UL_indication(UL_IND_t *UL_info) ifi->schedule_response(sched_info); } - if (sched_info->DL_req->dl_config_request_body.number_pdu) - LOG_D(PHY,"Schedule_response: SFN_SF:%d%d dl_pdus:%d\n",sched_info->frame,sched_info->subframe,sched_info->DL_req->dl_config_request_body.number_pdu); - } + LOG_D(PHY,"Schedule_response: SFN_SF:%d%d dl_pdus:%d\n",sched_info->frame,sched_info->subframe,sched_info->DL_req->dl_config_request_body.number_pdu); + } } } diff --git a/openair2/RRC/LITE/L2_interface.c b/openair2/RRC/LITE/L2_interface.c index 23232f563d..3077b9ba80 100644 --- a/openair2/RRC/LITE/L2_interface.c +++ b/openair2/RRC/LITE/L2_interface.c @@ -147,7 +147,6 @@ mac_rrc_data_req( return (RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB1); } // All RFN mod 8 transmit SIB2-3 in SF 5 else if ((frameP%8) == 1) { - //LOG_D(RRC, "%s() frameP mod 8==1 (frameP:%d) copy into buffer SIB23 size:%d\n", __FUNCTION__, frameP, RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB23); memcpy(&buffer_pP[0], RC.rrc[Mod_idP]->carrier[CC_id].SIB23, RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB23); @@ -197,7 +196,7 @@ mac_rrc_data_req( (void*)mib, carrier->MIB, 24); - //LOG_D(RRC,"Encoded MIB for frame %d (%p), bits %lu\n",sfn,carrier->MIB,enc_rval.encoded); + LOG_D(RRC,"Encoded MIB for frame %d (%p), bits %lu\n",sfn,carrier->MIB,enc_rval.encoded); buffer_pP[0]=carrier->MIB[0]; buffer_pP[1]=carrier->MIB[1]; buffer_pP[2]=carrier->MIB[2]; @@ -312,7 +311,7 @@ mac_rrc_data_req( RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB1_BR); return (RC.rrc[Mod_idP]->carrier[CC_id].sizeof_SIB1_BR); } - + if ((Srb_id & RAB_OFFSET) == BCCH_SI_BR){ // First SI message with SIB2/3 memcpy(&buffer_pP[0], RC.rrc[Mod_idP]->carrier[CC_id].SIB23_BR, diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 15a60a6902..ad9b63c798 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -135,7 +135,7 @@ init_SI( SystemInformationBlockType1_v1310_IEs_t *sib1_v13ext=(SystemInformationBlockType1_v1310_IEs_t *)NULL; #endif - LOG_E(RRC,"%s()\n\n\n\n",__FUNCTION__); + LOG_D(RRC,"%s()\n\n\n\n",__FUNCTION__); RC.rrc[ctxt_pP->module_id]->carrier[CC_id].MIB = (uint8_t*) malloc16(4); // copy basic parameters @@ -284,7 +284,7 @@ init_SI( } #endif - LOG_E(RRC, "About to call rrc_mac_config_req_eNB\n"); + LOG_D(RRC, "About to call rrc_mac_config_req_eNB\n"); rrc_mac_config_req_eNB(ctxt_pP->module_id, CC_id, RC.rrc[ctxt_pP->module_id]->carrier[CC_id].physCellId, diff --git a/openair2/UTIL/LOG/log.c b/openair2/UTIL/LOG/log.c index 47ff5d0fce..08672022d4 100644 --- a/openair2/UTIL/LOG/log.c +++ b/openair2/UTIL/LOG/log.c @@ -861,7 +861,7 @@ void nfapi_log(char *file, char *func, int line, int comp, int level, const char } //log record: add to a list -void logRecord(const char *file, const char *func, int line, pthread_t thread_id, int comp, +void logRecord(const char *file, const char *func, int line, int comp, int level, const char *format, ...) { va_list args; @@ -876,7 +876,6 @@ void logRecord(const char *file, const char *func, int line, pthread_t thread_id log_params.file = strdup(file); log_params.func = strdup(func); log_params.line = line; - log_params.thread_id = thread_id; log_params.comp = comp; log_params.level = level; log_params.format = format; @@ -915,7 +914,7 @@ void logRecord(const char *file, const char *func, int line, pthread_t thread_id } void logRecord_thread_safe(const char *file, const char *func, - int line, pthread_t thread_id, int comp, int level, + int line, int comp, int level, int len, const char *params_string) { log_component_t *c; @@ -967,8 +966,6 @@ void logRecord_thread_safe(const char *file, const char *func, func); } - //total_len += snprintf(&log_buffer[total_len], MAX_LOG_TOTAL - total_len, "[%08lx] ", thread_id); - if ((g_log->flag & FLAG_FILE_LINE) || (c->flag & FLAG_FILE_LINE) ) { total_len += snprintf(&log_buffer[total_len], MAX_LOG_TOTAL - total_len, "[%s:%d]", file, line); @@ -1068,7 +1065,6 @@ void *log_thread_function(void *list) logRecord_thread_safe(log_params.file, log_params.func, log_params.line, - log_params.thread_id, log_params.comp, log_params.level, log_params.len, @@ -1357,8 +1353,8 @@ void logRecord_mt(const char *file, const char *func, int line, int comp, #endif /* #if 0 */ //log record, format, and print: executed in the main thread (mt) -void logRecord_mt(const char *file, const char *func, int line, - pthread_t thread_id, int comp, int level, const char *format, ...) +void logRecord_mt(const char *file, const char *func, int line, int comp, + int level, const char *format, ...) { int len = 0; va_list args; @@ -1389,7 +1385,8 @@ void logRecord_mt(const char *file, const char *func, int line, return; } - //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD, VCD_FUNCTION_IN); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD, + VCD_FUNCTION_IN); va_start(args, format); @@ -1452,16 +1449,13 @@ void logRecord_mt(const char *file, const char *func, int line, if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; } - //len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%08lx]", thread_id); - //if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; - len += vsnprintf(&log_buffer[len], MAX_LOG_TOTAL - len, format, args); if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; log_end = log_buffer + len; if ( (g_log->flag & FLAG_COLOR) || (c->flag & FLAG_COLOR) ) { len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "%s", - log_level_highlight_end[level]); + log_level_highlight_end[level]); if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; } } @@ -1480,7 +1474,7 @@ void logRecord_mt(const char *file, const char *func, int line, } #else - fwrite(log_buffer, len, 1, stdout); + fwrite(log_buffer, len, 1, stdout); #endif #ifndef RTAI diff --git a/openair2/UTIL/LOG/log.h b/openair2/UTIL/LOG/log.h index 4cc5291774..1d795740b6 100644 --- a/openair2/UTIL/LOG/log.h +++ b/openair2/UTIL/LOG/log.h @@ -240,7 +240,6 @@ typedef struct LOG_params { const char *file; const char *func; int line; - pthread_t thread_id; int comp; int level; const char *format; @@ -263,8 +262,8 @@ void log_set_instance_type (log_instance_type_t instance); # include "log_if.h" /*----------------------------------------------------------------------------*/ int logInit (void); -void logRecord_mt(const char *file, const char *func, int line,pthread_t thread_id, int comp, int level, const char *format, ...) __attribute__ ((format (printf, 7, 8))); -void logRecord(const char *file, const char *func, int line, pthread_t thread_id, int comp, int level, const char *format, ...) __attribute__ ((format (printf, 7, 8))); +void logRecord_mt(const char *file, const char *func, int line,int comp, int level, const char *format, ...) __attribute__ ((format (printf, 6, 7))); +void logRecord(const char *file, const char *func, int line,int comp, int level, const char *format, ...) __attribute__ ((format (printf, 6, 7))); int set_comp_log(int component, int level, int verbosity, int interval); int set_log(int component, int level, int interval); void set_glog(int level, int verbosity); @@ -286,15 +285,15 @@ void *log_thread_function(void * list); #ifdef USER_MODE //#define logIt(component, level, format, args...) do {logRecord(__FILE__, __FUNCTION__, __LINE__, component, level, format, ##args);} while(0); #ifdef LOG_NO_THREAD -#define logIt(component, level, format, args...) logRecord_mt(__FILE__, __FUNCTION__, __LINE__, pthread_self(), component, level, format, ##args) +#define logIt(component, level, format, args...) logRecord_mt(__FILE__, __FUNCTION__, __LINE__, component, level, format, ##args) #else //default -#define logIt(component, level, format, args...) logRecord(__FILE__, __FUNCTION__, __LINE__, pthread_self(), component, level, format, ##args) +#define logIt(component, level, format, args...) logRecord(__FILE__, __FUNCTION__, __LINE__, component, level, format, ##args) #endif #else #ifdef LOG_NO_THREAD -#define logIt(component, level, format, args...) logRecord_mt(NULL, __FUNCTION__, __LINE__, pthread_self(), component, level, format, ##args) +#define logIt(component, level, format, args...) logRecord_mt(NULL, __FUNCTION__, __LINE__, component, level, format, ##args) #else // default -#define logIt(component, level, format, args...) logRecord(NULL, __FUNCTION__, __LINE__, pthread_self(), component, level, format, ##args) +#define logIt(component, level, format, args...) logRecord(NULL, __FUNCTION__, __LINE__, component, level, format, ##args) #endif #endif /* @}*/ @@ -353,19 +352,6 @@ void *log_thread_function(void * list); # define LOG_N(c, x...) /* */ # define LOG_F(c, x...) /* */ # else /*DISABLE_LOG_X*/ -#if 0 - extern log_t *g_log; -# define LOG_G(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_EMERG > g_log->log_component[c].level || LOG_EMERG > g_log->level) logIt(c, LOG_EMERG, x); } while(0) -# define LOG_A(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_ALERT > g_log->log_component[c].level || LOG_ALERT > g_log->level) logIt(c, LOG_ALERT, x); } while(0) -# define LOG_C(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_CRIT > g_log->log_component[c].level || LOG_CRIT > g_log->level) logIt(c, LOG_CRIT, x); } while(0) -# define LOG_E(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_ERR > g_log->log_component[c].level || LOG_ERR > g_log->level) logIt(c, LOG_ERR, x); } while(0) -# define LOG_W(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_WARNING > g_log->log_component[c].level || LOG_WARNING > g_log->level) logIt(c, LOG_WARNING, x); } while(0) -# define LOG_N(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_NOTICE > g_log->log_component[c].level || LOG_NOTICE > g_log->level) logIt(c, LOG_NOTICE, x); } while(0) -# define LOG_I(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_INFO > g_log->log_component[c].level || LOG_INFO > g_log->level) logIt(c, LOG_INFO, x); } while(0) -# define LOG_D(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_DEBUG > g_log->log_component[c].level || LOG_DEBUG > g_log->level) logIt(c, LOG_DEBUG, x); } while(0) -# define LOG_F(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_FILE > g_log->log_component[c].level || LOG_FILE > g_log->level) logIt(c, LOG_FILE, x); } while(0) -# define LOG_T(c, x...) do { if (g_log->log_component[c].level > g_log->level || LOG_TRACE > g_log->log_component[c].level || LOG_TRACE > g_log->level) logIt(c, LOG_TRACE, x); } while(0) -#else # define LOG_G(c, x...) logIt(c, LOG_EMERG, x) # define LOG_A(c, x...) logIt(c, LOG_ALERT, x) # define LOG_C(c, x...) logIt(c, LOG_CRIT, x) @@ -376,7 +362,6 @@ void *log_thread_function(void * list); # define LOG_D(c, x...) logIt(c, LOG_DEBUG, x) # define LOG_F(c, x...) logIt(c, LOG_FILE, x) // log to a file, useful for the MSC chart generation # define LOG_T(c, x...) logIt(c, LOG_TRACE, x) -# endif /* 0 */ # endif /*DISABLE_LOG_X*/ # endif /* T_TRACER */ #else /* USER_MODE */ diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index 8e747e46f5..358186dca3 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -1013,6 +1013,10 @@ extern "C" { openair0_cfg[0].rx_gain_calib_table = calib_table_x310; +#if defined(USRP_REC_PLAY) + std::cerr << "-- Using calibration table: calib_table_x310" << std::endl; // Bell Labs info +#endif + LOG_I(PHY,"%s() sample_rate:%u\n", __FUNCTION__, (int)openair0_cfg[0].sample_rate); switch ((int)openair0_cfg[0].sample_rate) { diff --git a/targets/COMMON/create_tasks.c b/targets/COMMON/create_tasks.c index 35b29e31b4..b911fbc5a4 100644 --- a/targets/COMMON/create_tasks.c +++ b/targets/COMMON/create_tasks.c @@ -42,7 +42,7 @@ int create_tasks(uint32_t enb_nb, uint32_t ue_nb) { - LOG_E(ENB_APP, "%s(enb_nb:%d ue_nb:%d)\n", __FUNCTION__, enb_nb, ue_nb); + LOG_D(ENB_APP, "%s(enb_nb:%d ue_nb:%d)\n", __FUNCTION__, enb_nb, ue_nb); itti_wait_ready(1); if (itti_create_task (TASK_L2L1, l2l1_task, NULL) < 0) { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf index 3a9276008b..ff302811e9 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf @@ -17,8 +17,7 @@ eNBs = mobile_country_code = "208"; - #mobile_network_code = "93"; - mobile_network_code = "92"; + mobile_network_code = "93"; tr_s_preference = "local_mac" @@ -37,14 +36,13 @@ eNBs = downlink_frequency = 2685000000L; uplink_frequency_offset = -120000000; Nid_cell = 0; -#N_RB_DL = 25; N_RB_DL = 50; Nid_cell_mbsfn = 0; nb_antenna_ports = 1; nb_antennas_tx = 1; nb_antennas_rx = 1; tx_gain = 90; - rx_gain = 115; + rx_gain = 125; pbch_repetition = "FALSE"; prach_root = 0; prach_config_index = 0; @@ -75,7 +73,7 @@ eNBs = pusch_p0_Nominal = -96; pusch_alpha = "AL1"; - pucch_p0_Nominal = -96; + pucch_p0_Nominal = -104; msg3_delta_Preamble = 6; pucch_deltaF_Format1 = "deltaF2"; pucch_deltaF_Format1b = "deltaF3"; @@ -142,7 +140,7 @@ eNBs = ////////// MME parameters: - mme_ip_address = ( { ipv4 = "192.168.1.78"; + mme_ip_address = ( { ipv4 = "192.168.12.26"; ipv6 = "192:168:30::17"; active = "yes"; preference = "ipv4"; @@ -152,10 +150,10 @@ eNBs = NETWORK_INTERFACES : { - ENB_INTERFACE_NAME_FOR_S1_MME = "eno1"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.1.78/24"; - ENB_INTERFACE_NAME_FOR_S1U = "eno1"; - ENB_IPV4_ADDRESS_FOR_S1U = "192.168.1.74/24"; + ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.19/24"; + ENB_INTERFACE_NAME_FOR_S1U = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.19/24"; ENB_PORT_FOR_S1U = 2152; # Spec 2152 }; } @@ -178,33 +176,34 @@ L1s = ( RUs = ( { - local_rf = "yes" - nb_tx = 1 - nb_rx = 1 - att_tx = 0 - att_rx = 0; - bands = [7]; - max_pdschReferenceSignalPower = -27; - max_rxgain = 105; - eNB_instances = [0]; + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [7]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 125; + eNB_instances = [0]; + } ); log_config : { - global_log_level ="debug"; + global_log_level ="info"; global_log_verbosity ="medium"; hw_log_level ="info"; hw_log_verbosity ="medium"; phy_log_level ="info"; - phy_log_verbosity ="low"; + phy_log_verbosity ="medium"; mac_log_level ="info"; - mac_log_verbosity ="medium"; + mac_log_verbosity ="high"; rlc_log_level ="info"; - rlc_log_verbosity ="high"; + rlc_log_verbosity ="medium"; pdcp_log_level ="info"; pdcp_log_verbosity ="medium"; rrc_log_level ="info"; - rrc_log_verbosity ="high"; + rrc_log_verbosity ="medium"; }; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/oaiL1.nfapi.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/oaiL1.nfapi.usrpb210.conf index f2e37638ab..9393872b30 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/oaiL1.nfapi.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/oaiL1.nfapi.usrpb210.conf @@ -19,13 +19,13 @@ L1s = ( { num_cc = 1; tr_n_preference = "nfapi"; - local_n_if_name = "eno1"; - remote_n_address = "192.168.1.28"; - local_n_address = "192.168.1.74"; - local_n_portc = 50000; - remote_n_portc = 50001; - local_n_portd = 50010; - remote_n_portd = 50011; + local_n_if_name = "lo"; + remote_n_address = "127.0.0.2"; + local_n_address = "127.0.0.1"; + local_n_portc = 50000; + remote_n_portc = 50001; + local_n_portd = 50010; + remote_n_portd = 50011; } ); @@ -34,10 +34,11 @@ RUs = ( local_rf = "yes" nb_tx = 1 nb_rx = 1 - att_tx = 90 + att_tx = 0 att_rx = 0; bands = [7,38,42,43]; max_pdschReferenceSignalPower = -27; - max_rxgain = 115; + max_rxgain = 125; + eNB_instances = [0]; } -); +); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf index 88aacde36b..1c9ad09141 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf @@ -17,8 +17,7 @@ eNBs = mobile_country_code = "208"; - #mobile_network_code = "93"; - mobile_network_code = "92"; + mobile_network_code = "93"; tr_s_preference = "local_mac" @@ -37,8 +36,7 @@ eNBs = downlink_frequency = 2685000000L; uplink_frequency_offset = -120000000; Nid_cell = 0; - #N_RB_DL = 50; - N_RB_DL = 25; + N_RB_DL = 50; Nid_cell_mbsfn = 0; nb_antenna_ports = 1; nb_antennas_tx = 1; @@ -73,9 +71,9 @@ eNBs = srs_ackNackST =; srs_MaxUpPts =;*/ - pusch_p0_Nominal = -86; + pusch_p0_Nominal = -96; pusch_alpha = "AL1"; - pucch_p0_Nominal = -96; + pucch_p0_Nominal = -104; msg3_delta_Preamble = 6; pucch_deltaF_Format1 = "deltaF2"; pucch_deltaF_Format1b = "deltaF3"; @@ -91,8 +89,7 @@ eNBs = rach_messagePowerOffsetGroupB = ; */ rach_powerRampingStep = 4; - #rach_preambleInitialReceivedTargetPower = -108; - rach_preambleInitialReceivedTargetPower = -104; + rach_preambleInitialReceivedTargetPower = -108; rach_preambleTransMax = 10; rach_raResponseWindowSize = 10; rach_macContentionResolutionTimer = 48; @@ -143,7 +140,7 @@ eNBs = ////////// MME parameters: - mme_ip_address = ( { ipv4 = "192.168.1.78"; + mme_ip_address = ( { ipv4 = "127.0.0.3"; ipv6 = "192:168:30::17"; active = "yes"; preference = "ipv4"; @@ -153,23 +150,21 @@ eNBs = NETWORK_INTERFACES : { - ENB_INTERFACE_NAME_FOR_S1_MME = "eno1"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.1.28/24"; - ENB_INTERFACE_NAME_FOR_S1U = "eno1"; - ENB_IPV4_ADDRESS_FOR_S1U = "192.168.1.28/24"; + ENB_INTERFACE_NAME_FOR_S1_MME = "lo"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "127.0.0.2/24"; + ENB_INTERFACE_NAME_FOR_S1U = "lo"; + ENB_IPV4_ADDRESS_FOR_S1U = "127.0.0.5/24"; ENB_PORT_FOR_S1U = 2152; # Spec 2152 }; - } ); MACRLCs = ( { num_cc = 1; - local_s_if_name = "eno1"; - remote_s_address = "192.168.1.74"; - #local_s_address = "192.168.1.78"; - local_s_address = "192.168.1.28"; + local_s_if_name = "lo"; + remote_s_address = "127.0.0.1"; + local_s_address = "127.0.0.2"; local_s_portc = 50001; remote_s_portc = 50000; local_s_portd = 50011; @@ -179,21 +174,20 @@ MACRLCs = ( } ); - log_config : - { - global_log_level ="debug"; - global_log_verbosity ="medium"; - hw_log_level ="info"; - hw_log_verbosity ="medium"; - phy_log_level ="info"; - phy_log_verbosity ="medium"; - mac_log_level ="info"; - mac_log_verbosity ="medium"; - rlc_log_level ="info"; - rlc_log_verbosity ="high"; - pdcp_log_level ="info"; - pdcp_log_verbosity ="medium"; - rrc_log_level ="info"; - rrc_log_verbosity ="high"; - }; - +log_config = + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index d50cbbb854..79973d3814 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -217,12 +217,9 @@ static inline int rxtx(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, char *thread_nam // if this is IF5 or 3GPP_eNB if (eNB && eNB->RU_list && eNB->RU_list[0] && eNB->RU_list[0]->function < NGFI_RAU_IF4p5) { - //LOG_D(PHY,"%s:%s() %u/%u Before wakeup_prach_eNB() proc->instance_cnt_rxtx:%d\n", thread_name, __FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->instance_cnt_rxtx); wakeup_prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx); - //LOG_D(PHY,"%s:%s() %u/%u Before wakeup_prach_eNB_br() proc->instance_cnt_rxtx:%d\n", thread_name, __FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->instance_cnt_rxtx); #ifdef Rel14 wakeup_prach_eNB_br(eNB,NULL,proc->frame_rx,proc->subframe_rx); - //LOG_D(PHY,"%s:%s() %u/%u proc->instance_cnt_rxtx:%d\n", thread_name, __FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->instance_cnt_rxtx); #endif } @@ -299,8 +296,6 @@ static inline int rxtx(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, char *thread_nam ); #endif - //softmodem_stats_rxtx_sf.in, softmodem_stats_rxtx_sf.diff_now, softmodem_stats_rxtx_sf.max, - return(0); } @@ -320,7 +315,6 @@ static void* eNB_thread_rxtx( void* param ) { char thread_name[100]; - //LOG_D(PHY,"%s()\n", __FUNCTION__); // set default return value eNB_thread_rxtx_status = 0; @@ -329,29 +323,21 @@ static void* eNB_thread_rxtx( void* param ) { sprintf(thread_name,"RXn_TXnp4_%d",&eNB->proc.proc_rxtx[0] == proc ? 0 : 1); thread_top_init(thread_name,1,850000L,1000000L,2000000L); - //LOG_D(PHY,"%s() thread_name:%s\n", __FUNCTION__, thread_name); - while (!oai_exit) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); - //LOG_D(PHY,"%s:%s() TX:%u/%u About to wait on proc->instance_cnt_rxtx:%d\n", thread_name, __FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->instance_cnt_rxtx); if (wait_on_condition(&proc->mutex_rxtx,&proc->cond_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) break; - //LOG_D(PHY,"%s:%s() TX:%u/%u - WOKEN on proc->instance_cnt_rxtx proc->instance_cnt_rxtx:%d \n", thread_name, __FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->instance_cnt_rxtx); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 1 ); if (oai_exit) break; - //LOG_D(PHY,"%s:%s() TX:%u/%u About to rxtx()\n", thread_name, __FUNCTION__, proc->frame_tx, proc->subframe_tx); if (eNB->CC_id==0) { if (rxtx(eNB,proc,thread_name) < 0) break; } - //LOG_D(PHY,"%s:%s() TX:%u/%u DONE rxtx()\n", thread_name, __FUNCTION__, proc->frame_tx, proc->subframe_tx); - if (release_thread(&proc->mutex_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) break; } // while !oai_exit @@ -397,9 +383,6 @@ void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string) proc->subframe_rx = subframe_rx; if (!oai_exit) { - //LOG_D(PHY,"eNB_top in %p (proc %p, CC_id %d), frame %d, subframe %d, instance_cnt_prach %d\n", - //(void*)pthread_self(), proc, eNB->CC_id, proc->frame_rx,proc->subframe_rx,proc->instance_cnt_prach); - T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->subframe_rx)); proc_rxtx->subframe_rx = proc->subframe_rx; @@ -410,7 +393,6 @@ void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string) proc_rxtx->timestamp_tx = proc->timestamp_tx; if (rxtx(eNB,proc_rxtx,string) < 0) LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id); - //LOG_D(PHY,"eNB_top out %p (proc %p, CC_id %d), frame %d, subframe %d, instance_cnt_prach %d\n", (void*)pthread_self(), proc, eNB->CC_id, proc->frame_rx,proc->subframe_rx,proc->instance_cnt_prach); } } @@ -426,14 +408,9 @@ int wakeup_rxtx(PHY_VARS_eNB *eNB,RU_t *ru) { int i; struct timespec wait; - LOG_D(PHY,"About to wake RUs\n"); - pthread_mutex_lock(&proc->mutex_RU); - LOG_D(PHY,"eNB->num_RU:%d\n", eNB->num_RU); for (i=0;inum_RU;i++) { - LOG_D(PHY,"eNB->RU_list[%d]:%p\n",i,eNB->RU_list[i]); if (ru == eNB->RU_list[i]) { - LOG_D(PHY,"proc->RU_mask:%02x\n", proc->RU_mask); if ((proc->RU_mask&(1< 0) LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n", eNB->Mod_id,proc->frame_rx,proc->subframe_rx,ru->idx,eNB->num_RU,proc->RU_mask); @@ -456,19 +433,17 @@ int wakeup_rxtx(PHY_VARS_eNB *eNB,RU_t *ru) { wait.tv_sec=0; wait.tv_nsec=5000000L; -#if 0 /* accept some delay in processing - up to 5ms */ for (i = 0; i < 10 && proc_rxtx->instance_cnt_rxtx == 0; i++) { LOG_W( PHY,"[eNB] Frame %d Subframe %d, eNB RXn-TXnp4 thread busy!! (cnt_rxtx %i)\n", proc_rxtx->frame_tx, proc_rxtx->subframe_tx, proc_rxtx->instance_cnt_rxtx); usleep(500); } if (proc_rxtx->instance_cnt_rxtx == 0) { - //exit_fun( "TX thread busy" ); - DJP - this is commented out just whilst I work out what has gone wrong + exit_fun( "TX thread busy" ); return(-1); } -#endif - // wake up TX for subframe n+2 + // wake up TX for subframe n+sf_ahead // lock the TX mutex and make sure the thread is ready if (pthread_mutex_timedlock(&proc_rxtx->mutex_rxtx,&wait) != 0) { LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB RXTX thread %d (IC %d)\n", proc_rxtx->subframe_rx&1,proc_rxtx->instance_cnt_rxtx ); @@ -477,7 +452,6 @@ int wakeup_rxtx(PHY_VARS_eNB *eNB,RU_t *ru) { } ++proc_rxtx->instance_cnt_rxtx; - LOG_D(PHY,"%s() %u/%u Just incremented proc->instance_cnt_rxtx:%d\n", __FUNCTION__, proc_rxtx->frame_tx, proc_rxtx->subframe_tx, proc_rxtx->instance_cnt_rxtx); // We have just received and processed the common part of a subframe, say n. // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired @@ -490,8 +464,6 @@ int wakeup_rxtx(PHY_VARS_eNB *eNB,RU_t *ru) { proc_rxtx->subframe_rx = proc->subframe_rx; proc_rxtx->frame_tx = (proc_rxtx->subframe_rx > (9-sf_ahead)) ? (proc_rxtx->frame_rx+1)&1023 : proc_rxtx->frame_rx; proc_rxtx->subframe_tx = (proc_rxtx->subframe_rx + sf_ahead)%10; - - LOG_D(PHY,"Signal &proc_rxtx->cond_rxtx\n"); // the thread can now be woken up if (pthread_cond_signal(&proc_rxtx->cond_rxtx) != 0) { @@ -534,7 +506,7 @@ void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { // check if we have to detect PRACH first if (is_prach_subframe(fp,frame,subframe)>0) { - //LOG_D(PHY,"Triggering prach processing, frame %d, subframe %d\n",frame,subframe); + LOG_D(PHY,"Triggering prach processing, frame %d, subframe %d\n",frame,subframe); if (proc->instance_cnt_prach == 0) { LOG_W(PHY,"[eNB] Frame %d Subframe %d, dropping PRACH\n", frame,subframe); return; @@ -650,7 +622,7 @@ static void* eNB_thread_prach( void* param ) { if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break; - //LOG_D(PHY,"Running eNB prach procedures\n"); + LOG_D(PHY,"Running eNB prach procedures\n"); prach_procedures(eNB #ifdef Rel14 ,0 @@ -691,7 +663,7 @@ static void* eNB_thread_prach_br( void* param ) { if (wait_on_condition(&proc->mutex_prach_br,&proc->cond_prach_br,&proc->instance_cnt_prach_br,"eNB_prach_thread_br") < 0) break; - //LOG_D(PHY,"Running eNB prach procedures for BL/CE UEs\n"); + LOG_D(PHY,"Running eNB prach procedures for BL/CE UEs\n"); prach_procedures(eNB,1); if (release_thread(&proc->mutex_prach_br,&proc->instance_cnt_prach_br,"eNB_prach_thread_br") < 0) break; @@ -920,7 +892,7 @@ void init_transport(PHY_VARS_eNB *eNB) { int j; LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; - LOG_E(PHY, "Initialise transport\n"); + LOG_I(PHY, "Initialise transport\n"); for (i=0; inum_RU,eNB->Mod_id); eNB->frame_parms.nb_antennas_rx = 0; - LOG_E(PHY,"Overwriting eNB->prach_vars.rxsigF[0]:%p\n", eNB->prach_vars.rxsigF[0]); + LOG_I(PHY,"Overwriting eNB->prach_vars.rxsigF[0]:%p\n", eNB->prach_vars.rxsigF[0]); eNB->prach_vars.rxsigF[0] = (int16_t**)malloc16(64*sizeof(int16_t*)); #ifdef Rel14 for (int ce_level=0;ce_level<4;ce_level++) { - LOG_E(PHY,"Overwriting eNB->prach_vars_br.rxsigF.rxsigF[0]:%p\n", eNB->prach_vars_br.rxsigF[ce_level]); + LOG_I(PHY,"Overwriting eNB->prach_vars_br.rxsigF.rxsigF[0]:%p\n", eNB->prach_vars_br.rxsigF[ce_level]); eNB->prach_vars_br.rxsigF[ce_level] = (int16_t**)malloc16(64*sizeof(int16_t*)); } #endif @@ -1035,7 +1007,10 @@ void init_eNB_afterRU(void) { - + /* TODO: review this code, there is something wrong. + * In monolithic mode, we come here with nb_antennas_rx == 0 + * (not tested in other modes). + */ if (eNB->frame_parms.nb_antennas_rx < 1) { LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_rx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_rx); @@ -1043,7 +1018,7 @@ void init_eNB_afterRU(void) { } else { - LOG_I(PHY," Delete code\n"); + //LOG_I(PHY," Delete code\n"); } if (eNB->frame_parms.nb_antennas_tx < 1) @@ -1053,7 +1028,7 @@ void init_eNB_afterRU(void) { } else { - LOG_I(PHY," Delete code\n"); + //LOG_I(PHY," Delete code\n"); } @@ -1066,12 +1041,9 @@ void init_eNB_afterRU(void) { init_transport(eNB); //init_precoding_weights(RC.eNB[inst][CC_id]); } - printf("RC.nb_CC[inst:%d]:%d CC_id:%d AFTER LOOP - About to init_eNB_proc\n", inst, RC.nb_CC[inst], CC_id); init_eNB_proc(inst); } - printf("%s() RC.nb_inst:%d AFTER LOOP\n", __FUNCTION__, RC.nb_inst); - printf("%s:%d RC.nb_RU:%d\n", __FILE__, __LINE__, RC.nb_RU); for (ru_id=0;ru_idwakeup_prach_eNB_br = wakeup_prach_eNB_br; RC.ru[ru_id]->eNB_top = eNB_top; } - - LOG_I(PHY,"%s() Exitting\n", __FUNCTION__); } void init_eNB(int single_thread_flag,int wait_for_sync) { diff --git a/targets/RT/USER/lte-ran.c b/targets/RT/USER/lte-ran.c index 4f9f45df86..597ceb0654 100644 --- a/targets/RT/USER/lte-ran.c +++ b/targets/RT/USER/lte-ran.c @@ -1278,8 +1278,6 @@ void init_eNB_proc(int inst) { eNB_rxtx_proc_t *proc_rxtx; pthread_attr_t *attr0=NULL,*attr1=NULL,*attr_prach=NULL,*attr_asynch=NULL,*attr_single=NULL,*attr_fep=NULL,*attr_td=NULL,*attr_te; - printf("%s()\n", __FUNCTION__); - for (CC_id=0; CC_idnode_function],eNB_timing[eNB->node_timing]); @@ -1675,15 +1673,10 @@ void init_RAN(RAN_CONTEXT *rc,eNB_func_t node_function[], eNB_timing_t node_timi PHY_VARS_eNB *eNB; int ret; - printf("%s() rc->nb_inst:%d\n", __FUNCTION__, rc->nb_inst); - for (inst=0;instnb_inst;inst++) { - printf("%s() rc->nb_inst:%d rc->nb_CC:%d\n", __FUNCTION__, rc->nb_inst, rc->nb_CC); for (CC_id=0;CC_idnb_CC;CC_id++) { eNB = rc->eNB[inst][CC_id]; - printf("%s() rc->nb_inst:%d rc->nb_CC:%d eNB:%p rc->eNB[%d][%d]:%p\n", __FUNCTION__, rc->nb_inst, rc->nb_CC, eNB, inst, CC_id, rc->eNB[inst][CC_id]); if (eNB) { - eNB->node_function = node_function[CC_id]; eNB->node_timing = node_timing[CC_id]; eNB->abstraction_flag = 0; diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 66cd5daffa..9f67e75b1c 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -592,7 +592,7 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { uint32_t symbol_number,symbol_mask,symbol_mask_full; int subframe_tx,frame_tx; -LOG_E(PHY, "%s(ru:%p frame, subframe)\n", __FUNCTION__, ru); + LOG_D(PHY, "%s(ru:%p frame, subframe)\n", __FUNCTION__, ru); symbol_number = 0; symbol_mask = 0; symbol_mask_full = ((subframe_select(fp,*subframe) == SF_S) ? (1<dl_symbols_in_S_subframe) : (1<symbols_per_tti))-1; @@ -720,13 +720,11 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { proc->subframe_tx = (proc->subframe_rx+sf_ahead)%10; proc->frame_tx = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx; -#if 0 LOG_D(PHY,"RU %d/%d TS %llu (off %d), frame %d, subframe %d\n", ru->idx, 0, (unsigned long long int)proc->timestamp_rx, (int)ru->ts_offset,proc->frame_rx,proc->subframe_rx); -#endif // dump VCD output for first RU in list if (ru == RC.ru[0]) { @@ -759,6 +757,7 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) { if (rxs != fp->samples_per_tti) { //exit_fun( "problem receiving samples" ); + LOG_E(PHY, "problem receiving samples"); } } @@ -819,8 +818,8 @@ void tx_rf(RU_t *ru) { ru->nb_tx, flags); - //LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx, - //(long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx); + LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx, + (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); @@ -948,8 +947,6 @@ static void* ru_thread_prach( void* param ) { thread_top_init("ru_thread_prach",1,500000L,1000000L,20000000L); -LOG_E(PHY,"In rach thread\n"); - while (RC.ru_mask>0) { usleep(1e6); LOG_I(PHY,"%s() RACH waiting for RU to be configured\n", __FUNCTION__); @@ -1117,14 +1114,14 @@ void wakeup_eNBs(RU_t *ru) { int i; PHY_VARS_eNB **eNB_list = ru->eNB_list; - //LOG_D(PHY,"wakeup_eNBs (num %d) for RU %d ru->eNB_top:%p\n",ru->num_eNB,ru->idx, ru->eNB_top); + LOG_D(PHY,"wakeup_eNBs (num %d) for RU %d ru->eNB_top:%p\n",ru->num_eNB,ru->idx, ru->eNB_top); if (ru->num_eNB==1 && ru->eNB_top!=0) { // call eNB function directly char string[20]; sprintf(string,"Incoming RU %d",ru->idx); - //LOG_D(PHY,"RU %d Call eNB_top\n",ru->idx); + LOG_D(PHY,"RU %d Call eNB_top\n",ru->idx); ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.subframe_rx,string); } else { @@ -1164,7 +1161,7 @@ static inline int wakeup_prach_ru(RU_t *ru) { ru->eNB_list[0]->proc.frame_prach = ru->proc.frame_rx; ru->eNB_list[0]->proc.subframe_prach = ru->proc.subframe_rx; - //LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx); + LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx); // the thread can now be woken up AssertFatal(pthread_cond_signal(&ru->proc.cond_prach) == 0, "ERROR pthread_cond_signal for RU prach thread\n"); } @@ -1203,40 +1200,6 @@ static inline int wakeup_prach_ru_br(RU_t *ru) { } #endif -#if 0 -static inline int wakeup_nfapi_subframe_thread(RU_t *ru) { - - int i; - PHY_VARS_eNB **eNB_list = ru->eNB_list; - - LOG_D(PHY,"wakeup_nfapi_subframe_thread (num %d) for RU %d ru->eNB_top:%p\n",ru->num_eNB,ru->idx, ru->eNB_top); - - if (ru->num_eNB==1 && ru->eNB_top!=0) { - // call eNB function directly - - char string[20]; - sprintf(string,"Incoming RU %d",ru->idx); - //LOG_D(PHY,"RU %d Call eNB_top\n",ru->idx); - ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.subframe_rx,string); - } - else { - - LOG_D(PHY,"ru->num_eNB:%d\n", ru->num_eNB); - - for (i=0;inum_eNB;i++) - { - LOG_D(PHY,"ru->wakeup_rxtx:%p\n", ru->wakeup_rxtx); - - if (ru->wakeup_rxtx!=0 && ru->wakeup_rxtx(eNB_list[i],ru) < 0) - { - LOG_E(PHY,"could not wakeup eNB rxtx process for subframe %d\n", ru->proc.subframe_rx); - } - } - } -} -#endif - - // this is for RU with local RF unit void fill_rf_config(RU_t *ru, char *rf_config_file) { @@ -1490,13 +1453,12 @@ static void* ru_thread( void* param ) { RC.eNB[0][0]->proc.frame_rx,RC.eNB[0][0]->proc.subframe_rx, RC.eNB[0][0]->proc.frame_tx); - if (0 && is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)) LOG_D(PHY,"RU thread (do_prach %d, is_prach_subframe %d), received frame %d, subframe %d\n", ru->do_prach, is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx), proc->frame_rx,proc->subframe_rx); - if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)==1)) { + if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)==1)) { wakeup_prach_ru(ru); } #ifdef Rel14 @@ -1516,15 +1478,12 @@ static void* ru_thread( void* param ) { // If this proc is to provide synchronization, do so wakeup_slaves(proc); - //LOG_E(PHY,"RU %d/%d frame_tx %d, subframe_tx %d - wakeup_eNBs...\n",0,ru->idx,proc->frame_tx,proc->subframe_tx); // wakeup all eNB processes waiting for this RU if (ru->num_eNB>0) wakeup_eNBs(ru); - //LOG_E(PHY,"%s() Before wait_on_condition()\n", __FUNCTION__); // wait until eNBs are finished subframe RX n and TX n+sf_ahead wait_on_condition(&proc->mutex_eNBs,&proc->cond_eNBs,&proc->instance_cnt_eNBs,"ru_thread"); - //LOG_E(PHY,"%s() AFTER wait_on_condition() ru->feptx_prec:%p ru->fh_north_asynch_in:%p ru->feptx_ofdm:%p ru->fh_south_out:%p ru->fh_north_out:%p\n", __FUNCTION__, ru->feptx_prec, ru->fh_north_asynch_in, ru->feptx_ofdm, ru->fh_south_out, ru->fh_north_out); // do TX front-end processing if needed (precoding and/or IDFTs) if (ru->feptx_prec) ru->feptx_prec(ru); @@ -1654,7 +1613,6 @@ void init_RU_proc(RU_t *ru) { #endif char name[100]; - LOG_E(PHY,"Initializing RU proc %d (%s,%s),\n",ru->idx,eNB_functions[ru->function],eNB_timing[ru->if_timing]); #ifndef OCP_FRAMEWORK LOG_I(PHY,"Initializing RU proc %d (%s,%s),\n",ru->idx,eNB_functions[ru->function],eNB_timing[ru->if_timing]); #endif @@ -1709,8 +1667,6 @@ void init_RU_proc(RU_t *ru) { pthread_create( &proc->pthread_FH, attr_FH, ru_thread, (void*)ru ); - LOG_E(PHY,"%s() DJP - ru->function:%d\n", __FUNCTION__, ru->function); - if (ru->function == NGFI_RRU_IF4p5) { pthread_create( &proc->pthread_prach, attr_prach, ru_thread_prach, (void*)ru ); #ifdef Rel14 @@ -1728,7 +1684,7 @@ void init_RU_proc(RU_t *ru) { } else if (ru->function == eNodeB_3GPP && ru->if_south == LOCAL_RF) { // DJP - need something else to distinguish between monolithic and PNF - LOG_E(PHY,"%s() DJP - added creation of pthread_prach\n", __FUNCTION__); + LOG_I(PHY,"%s() DJP - added creation of pthread_prach\n", __FUNCTION__); pthread_create( &proc->pthread_prach, attr_prach, ru_thread_prach, (void*)ru ); } @@ -1941,9 +1897,9 @@ void init_RU(char *rf_config_file) { for (i=0;inum_RU=0; -LOG_E(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU); + LOG_D(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU); for (ru_id=0;ru_idrf_config_file = rf_config_file; ru->idx = ru_id; @@ -1951,7 +1907,7 @@ LOG_E(PHY,"Process RC.ru[%d]\n",ru_id); // use eNB_list[0] as a reference for RU frame parameters // NOTE: multiple CC_id are not handled here yet! - printf("%s() RC.ru[%d].num_eNB:%d ru->eNB_list[0]:%p RC.eNB[0][0]:%p rf_config_file:%s\n", __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file); + LOG_D(PHY, "%s() RC.ru[%d].num_eNB:%d ru->eNB_list[0]:%p RC.eNB[0][0]:%p rf_config_file:%s\n", __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file); if (ru->eNB_list[0] == 0) { @@ -1968,8 +1924,8 @@ LOG_E(PHY,"Process RC.ru[%d]\n",ru_id); } eNB0 = ru->eNB_list[0]; - printf("RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south); - printf("eNB0:%p\n", eNB0); + LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south); + LOG_D(PHY, "eNB0:%p\n", eNB0); if (eNB0) { if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5)) @@ -1980,7 +1936,7 @@ LOG_E(PHY,"Process RC.ru[%d]\n",ru_id); memcpy((void*)&ru->frame_parms,(void*)&eNB0->frame_parms,sizeof(LTE_DL_FRAME_PARMS)); // attach all RU to all eNBs in its list/ - LOG_E(PHY,"ru->num_eNB:%d eNB0->num_RU:%d\n", ru->num_eNB, eNB0->num_RU); + LOG_D(PHY,"ru->num_eNB:%d eNB0->num_RU:%d\n", ru->num_eNB, eNB0->num_RU); for (i=0;inum_eNB;i++) { eNB0 = ru->eNB_list[i]; eNB0->RU_list[eNB0->num_RU++] = ru; @@ -1990,7 +1946,7 @@ LOG_E(PHY,"Process RC.ru[%d]\n",ru_id); // LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n",ru_id,ru_if_types[ru->if_south],eNB_timing[ru->if_timing],ru->function); -LOG_E(PHY,"ru->if_south:%d\n", ru->if_south); + LOG_D(PHY,"ru->if_south:%d\n", ru->if_south); switch (ru->if_south) { case LOCAL_RF: // this is an RU with integrated RF (RRU, eNB) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index c786a62e2e..792f16e92a 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -873,8 +873,8 @@ void wait_eNBs(void) { while (waiting==1) { - printf("Waiting for eNB L1 instances to all get configured ... sleeping 500ms (nb_L1_inst %d)\n",RC.nb_L1_inst); - usleep(5000000); + printf("Waiting for eNB L1 instances to all get configured ... sleeping 50ms (nb_L1_inst %d)\n",RC.nb_L1_inst); + usleep(50*1000); waiting=0; for (i=0;i Date: Mon, 15 Jan 2018 18:47:07 +0100 Subject: [PATCH 141/284] Fix #582, RTAI, RTAI_ENABLED, ENABLE_RTAI_CLOCK, RTAI_ISNT_POSIX, _RTAI_MATH_H, CELLULAR, TIMER_ONESHOT_MODE, EMOS, EMOS_CHANNEL, OAI_EMU, OPENAIR_EMU, PHY_ABSTRACTION, PHY_ABSTRACTION_UL removed --- cmake_targets/CMakeLists.txt | 32 +- cmake_targets/epc_test/CMakeLists.template | 4 - .../oaisim_build_oai/CMakeLists.template | 4 - .../oaisim_mme_build_oai/CMakeLists.template | 4 - .../oaisim_noS1_build_oai/CMakeLists.template | 4 - .../s1c_mme_test/CMakeLists.template | 4 - common/utils/itti/intertask_interface.c | 233 +-- common/utils/itti/intertask_interface.h | 6 - common/utils/itti/intertask_interface_dump.c | 85 - common/utils/itti/memory_pools.c | 37 - openair1/Makefile | 121 -- openair1/PHY/LTE_ESTIMATION/defs.h | 18 - .../lte_dl_channel_estimation_emos.c | 149 -- openair1/PHY/LTE_ESTIMATION/lte_sync_time.c | 27 - openair1/PHY/LTE_TRANSPORT/dci.c | 30 - openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c | 307 ---- openair1/PHY/LTE_TRANSPORT/pbch.c | 46 - openair1/PHY/LTE_TRANSPORT/proto.h | 8 +- openair1/PHY/LTE_TRANSPORT/ulsch_coding.c | 74 - openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 452 ----- .../PHY/LTE_TRANSPORT/ulsch_demodulation.c | 1 - openair1/PHY/TOOLS/defs.h | 14 - openair1/PHY/impl_defs_lte.h | 2 + openair1/PHY/impl_defs_top.h | 4 - openair1/SCHED/defs.h | 7 +- openair1/SCHED/extern.h | 6 - openair1/SCHED/fapi_l1.c | 4 + openair1/SCHED/phy_mac_stub.c | 182 -- openair1/SCHED/phy_procedures_emos.h | 108 -- openair1/SCHED/phy_procedures_lte_eNb.c | 7 +- openair1/SCHED/phy_procedures_lte_ue.c | 64 - openair1/SCHED/rt_compat.h | 138 -- openair1/SCHED/ru_procedures.c | 4 - openair1/SIMULATION/LTE_PHY/Makefile | 202 --- openair1/SIMULATION/LTE_PHY/mbmssim.c | 3 - openair1/SIMULATION/LTE_PHY/pbchsim.c | 6 - openair1/SIMULATION/LTE_PHY/pdcchsim.c | 3 - openair1/SIMULATION/LTE_PHY/prachsim.c | 7 - openair1/SIMULATION/LTE_PHY/pucchsim.c | 6 - openair1/SIMULATION/LTE_PHY/scansim.c | 6 - openair1/SIMULATION/LTE_PHY/syncsim.c | 45 - openair1/SIMULATION/LTE_PHY/ulsim2.c | 9 - openair1/SIMULATION/TOOLS/taus.c | 5 - openair2/COMMON/mac_rrc_primitives.h | 8 - openair2/COMMON/openair_types.h | 25 - openair2/COMMON/platform_types.h | 26 +- openair2/COMMON/rtos_header.h | 18 +- openair2/ENB_APP/enb_app.c | 30 - openair2/ENB_APP/enb_config.c | 4 - openair2/LAYER2/Makefile.inc | 4 - openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 68 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 148 -- openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c | 22 - openair2/LAYER2/PDCP_v10.1.0/pdcp_thread.c | 2 - openair2/LAYER2/RLC/rlc.c | 10 - openair2/LAYER2/RLC/rlc_mac.c | 44 - openair2/LAYER2/RLC/rlc_rrc.c | 24 - openair2/LAYER2/register.c | 41 - openair2/Makefile | 254 --- .../NAS/DRIVER/CELLULAR/CTL_TOOL/Makefile | 48 - .../DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.c | 859 --------- .../DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.h | 49 - openair2/NAS/DRIVER/CELLULAR/NASMT/Makefile | 79 - .../DRIVER/CELLULAR/NASMT/nasmt_ascontrol.c | 1152 ------------ .../DRIVER/CELLULAR/NASMT/nasmt_classifier.c | 884 --------- .../NAS/DRIVER/CELLULAR/NASMT/nasmt_common.c | 542 ------ .../DRIVER/CELLULAR/NASMT/nasmt_constant.h | 210 --- .../NAS/DRIVER/CELLULAR/NASMT/nasmt_device.c | 565 ------ .../DRIVER/CELLULAR/NASMT/nasmt_iocontrol.c | 764 -------- .../DRIVER/CELLULAR/NASMT/nasmt_iocontrol.h | 211 --- .../NAS/DRIVER/CELLULAR/NASMT/nasmt_netlink.c | 233 --- .../NAS/DRIVER/CELLULAR/NASMT/nasmt_proto.h | 122 -- .../NAS/DRIVER/CELLULAR/NASMT/nasmt_sap.h | 73 - .../NAS/DRIVER/CELLULAR/NASMT/nasmt_tool.c | 494 ----- .../DRIVER/CELLULAR/NASMT/nasmt_variables.h | 173 -- openair2/NAS/DRIVER/CELLULAR/NASRG/Makefile | 79 - .../DRIVER/CELLULAR/NASRG/nasrg_ascontrol.c | 1494 --------------- .../DRIVER/CELLULAR/NASRG/nasrg_classifier.c | 1139 ------------ .../NAS/DRIVER/CELLULAR/NASRG/nasrg_common.c | 628 ------- .../DRIVER/CELLULAR/NASRG/nasrg_constant.h | 220 --- .../NAS/DRIVER/CELLULAR/NASRG/nasrg_device.c | 549 ------ .../DRIVER/CELLULAR/NASRG/nasrg_iocontrol.c | 906 ---------- .../DRIVER/CELLULAR/NASRG/nasrg_iocontrol.h | 251 --- .../NAS/DRIVER/CELLULAR/NASRG/nasrg_netlink.c | 246 --- .../NAS/DRIVER/CELLULAR/NASRG/nasrg_proto.h | 135 -- .../NAS/DRIVER/CELLULAR/NASRG/nasrg_sap.h | 77 - .../NAS/DRIVER/CELLULAR/NASRG/nasrg_tool.c | 478 ----- .../DRIVER/CELLULAR/NASRG/nasrg_variables.h | 214 --- .../NAS/DRIVER/CELLULAR/NETLTEST/Makefile | 48 - .../NAS/DRIVER/CELLULAR/NETLTEST/netltest | Bin 12462 -> 0 bytes .../NAS/DRIVER/CELLULAR/NETLTEST/netltest.c | 213 --- .../DRIVER/CELLULAR/NETLTEST/nettestPDCP.c | 149 -- openair2/NAS/DRIVER/CELLULAR/readme.txt | 157 -- .../NAS/DRIVER/CELLULAR/start_mt_cellular | 13 - .../DRIVER/CELLULAR/start_rg_cellular_noradvd | 17 - .../DRIVER/CELLULAR/start_rg_cellular_radvd | 17 - openair2/NAS/DRIVER/CELLULAR/stop_mt_cellular | 5 - openair2/NAS/DRIVER/CELLULAR/stop_rg_cellular | 2 - openair2/NAS/Makefile.inc | 6 - openair2/NAS/SIMU_CELLULAR/Makefile | 62 - openair2/NAS/SIMU_CELLULAR/nas_simu_proto.h | 54 - openair2/NAS/SIMU_CELLULAR/nasrg_simu_meas.c | 646 ------- .../NAS/SIMU_CELLULAR/rrm_fifo_standalone.c | 378 ---- openair2/NETWORK_DRIVER/LITE/Makefile | 72 - openair2/NETWORK_DRIVER/LITE/device.c | 24 - openair2/NETWORK_DRIVER/MESH/Makefile | 70 - openair2/NETWORK_DRIVER/MESH/common.c | 4 - openair2/NETWORK_DRIVER/MESH/device.c | 25 +- openair2/NETWORK_DRIVER/UE_IP/Makefile | 49 - openair2/NETWORK_DRIVER/UE_IP/device.c | 7 - openair2/RRC/LITE/MESSAGES/Makefile | 31 - openair2/RRC/LITE/MESSAGES/rtai_mem.c | 146 -- openair2/RRC/LITE/MESSAGES/rtai_mem.h | 44 - openair2/RRC/LITE/mesh_top.c | 39 - openair2/RRC/LITE/rrc_UE.c | 27 - openair2/RRC/LITE/rrc_eNB.c | 17 - openair2/UTIL/LOG/log.c | 89 - openair2/UTIL/LOG/vcd_signal_dumper.c | 13 - openair2/UTIL/MATH/taus.c | 9 - openair2/UTIL/OCG/makefile | 2 - openair2/UTIL/OMG/makefile | 2 - openair2/UTIL/OMG/makefile_old | 2 - openair2/UTIL/OPT/probe.c | 10 - openair2/X2AP/x2ap.h | 3 - openair3/S1AP/s1ap_eNB.c | 3 - openair3/S1AP/s1ap_eNB.h | 6 +- targets/Makefile | 35 - targets/RT/Makefile | 124 -- targets/RT/USER/Makefile | 447 ----- targets/RT/USER/Makefile.agilent | 243 --- targets/RT/USER/Makefile.msg_many | 21 - targets/RT/USER/condtest.c | 173 -- targets/RT/USER/emos-raw.c | 1603 ----------------- targets/RT/USER/init_rtai.sh | 5 - targets/RT/USER/make_for_usrp.sh | 36 - targets/RT/USER/msg_helper.c | 87 - targets/RT/USER/msg_many.c | 181 -- targets/RT/USER/msg_many.h | 53 - targets/RT/USER/sleeptest.c | 302 ---- targets/RT/USER/synctest.c | 1318 -------------- targets/SIMU/USER/Makefile | 13 +- targets/SIMU/USER/channel_sim.c | 43 - targets/SIMU/USER/oaisim_functions.c | 160 -- targets/SIMU/USER/sinr_sim.c | 117 -- targets/TEST/AT_COMMANDS/Makefile | 2 - targets/TEST/PACKET_TRACER/Makefile | 8 +- targets/TEST/PDCP/Makefile | 2 - .../TEST/PDCP/with_rlc/Makefile.data_bearer | 2 - targets/TEST/RLC_AM_V9.3.0/Makefile | 12 +- targets/TEST/RLC_UM_V9.3.0/Makefile | 12 +- 150 files changed, 45 insertions(+), 23495 deletions(-) delete mode 100644 openair1/Makefile delete mode 100644 openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation_emos.c delete mode 100644 openair1/SCHED/phy_procedures_emos.h delete mode 100644 openair1/SCHED/rt_compat.h delete mode 100644 openair1/SIMULATION/LTE_PHY/Makefile delete mode 100644 openair2/COMMON/openair_types.h delete mode 100644 openair2/LAYER2/register.c delete mode 100755 openair2/Makefile delete mode 100755 openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/Makefile delete mode 100644 openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.h delete mode 100755 openair2/NAS/DRIVER/CELLULAR/NASMT/Makefile delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_ascontrol.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_classifier.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_common.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_constant.h delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_device.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.h delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_netlink.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_proto.h delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_sap.h delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_tool.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_variables.h delete mode 100755 openair2/NAS/DRIVER/CELLULAR/NASRG/Makefile delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_ascontrol.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_classifier.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_common.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_constant.h delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_device.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.h delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_netlink.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_proto.h delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_sap.h delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_tool.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_variables.h delete mode 100755 openair2/NAS/DRIVER/CELLULAR/NETLTEST/Makefile delete mode 100755 openair2/NAS/DRIVER/CELLULAR/NETLTEST/netltest delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NETLTEST/netltest.c delete mode 100644 openair2/NAS/DRIVER/CELLULAR/NETLTEST/nettestPDCP.c delete mode 100755 openair2/NAS/DRIVER/CELLULAR/readme.txt delete mode 100755 openair2/NAS/DRIVER/CELLULAR/start_mt_cellular delete mode 100755 openair2/NAS/DRIVER/CELLULAR/start_rg_cellular_noradvd delete mode 100755 openair2/NAS/DRIVER/CELLULAR/start_rg_cellular_radvd delete mode 100755 openair2/NAS/DRIVER/CELLULAR/stop_mt_cellular delete mode 100755 openair2/NAS/DRIVER/CELLULAR/stop_rg_cellular delete mode 100644 openair2/NAS/Makefile.inc delete mode 100755 openair2/NAS/SIMU_CELLULAR/Makefile delete mode 100644 openair2/NAS/SIMU_CELLULAR/nas_simu_proto.h delete mode 100644 openair2/NAS/SIMU_CELLULAR/nasrg_simu_meas.c delete mode 100644 openair2/NAS/SIMU_CELLULAR/rrm_fifo_standalone.c delete mode 100755 openair2/NETWORK_DRIVER/LITE/Makefile delete mode 100755 openair2/NETWORK_DRIVER/MESH/Makefile delete mode 100755 openair2/NETWORK_DRIVER/UE_IP/Makefile delete mode 100644 openair2/RRC/LITE/MESSAGES/Makefile delete mode 100644 openair2/RRC/LITE/MESSAGES/rtai_mem.c delete mode 100644 openair2/RRC/LITE/MESSAGES/rtai_mem.h delete mode 100644 openair2/RRC/LITE/mesh_top.c delete mode 100644 targets/Makefile delete mode 100644 targets/RT/Makefile delete mode 100644 targets/RT/USER/Makefile delete mode 100644 targets/RT/USER/Makefile.agilent delete mode 100644 targets/RT/USER/Makefile.msg_many delete mode 100644 targets/RT/USER/condtest.c delete mode 100644 targets/RT/USER/emos-raw.c delete mode 100755 targets/RT/USER/init_rtai.sh delete mode 100755 targets/RT/USER/make_for_usrp.sh delete mode 100644 targets/RT/USER/msg_helper.c delete mode 100644 targets/RT/USER/msg_many.c delete mode 100644 targets/RT/USER/msg_many.h delete mode 100644 targets/RT/USER/sleeptest.c delete mode 100644 targets/RT/USER/synctest.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index f788f95f3c..8737df7ea0 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -262,9 +262,6 @@ if (${ENABLE_ITTI}) set(GTPU_need_ITTI ${OPENAIR3_DIR}/GTPV1-U/gtpv1u_eNB.c) endif (${ENABLE_ITTI}) -add_boolean_option(RTAI False "Use RTAI") - - ############################# # ASN.1 grammar C code generation & dependancies ################################ @@ -594,7 +591,7 @@ add_boolean_option(DISABLE_USE_NAS False "???") add_boolean_option(DEADLINE_SCHEDULER True "Use the Linux scheduler SCHED_DEADLINE: kernel >= 3.14") add_boolean_option(CPU_AFFINITY False "Enable CPU Affinity of threads (only valid without deadline scheduler). It is enabled only with >2 CPUs") add_boolean_option(NAS_ADDRESS_FIX False "specific to oaisim: for nasmesh driver") -add_boolean_option(NAS_NETLINK False "???? Must be True to compile nasmesh driver without rtai") +add_boolean_option(NAS_NETLINK False "useless ??? Must be True to compile nasmesh driver without rtai ????") add_boolean_option(OAISIM False "specific to oaisim") add_boolean_option(OAI_NW_DRIVER_USE_NETLINK True "????") @@ -616,9 +613,6 @@ add_boolean_option(ENB_MODE True "Swap the include directories between openair2 ########################## add_boolean_option(ENABLE_PGM_TRANSPORT False "specific to oaisim, emulation through ethernet, reliable multicast") add_boolean_option(ADDR_CONF False "specific to oaisim, IP autoconf of user-plane IP interface") -add_boolean_option(OPENAIR_EMU False "specific to oaisim") -add_boolean_option(OAI_EMU False "specific to oaisim") -add_boolean_option(PHY_ABSTRACTION False "specific to oaisim") ########################## # SCHEDULING/REAL-TIME/PERF options @@ -733,16 +727,7 @@ add_boolean_option(RRC_DEFAULT_RAB_IS_AM False "Otherwise it is UM, confi add_boolean_option(SPECTRA False "???") add_boolean_option(MIH_C_MEDIEVAL_EXTENSIONS False "EXTENSIONS TO MIH 802.21 IN CONTEXT OF IST PROJECT CALLED MEDIEVAL") - - -add_boolean_option(EMOS False "????") -if(${EMOS}) - add_definitions("-D_FILE_OFFSET_BITS=64") - set(EMOS_LIB gps) -endif(${EMOS}) - - - # add the binary tree to the search path for include files +# add the binary tree to the search path for include files ####################################################### # We will find ConfigOAI.h after generation in target directory include_directories("${OPENAIR_BIN_DIR}") @@ -770,7 +755,6 @@ else() endif() include_directories("${NFAPI_DIR}") include_directories("${OPENAIR1_DIR}") -include_directories("${OPENAIR2_DIR}/NAS") include_directories("${OPENAIR2_DIR}") include_directories("${OPENAIR2_DIR}/LAYER2/RLC") include_directories("${OPENAIR2_DIR}/LAYER2/RLC/AM_v9.3.0") @@ -1776,7 +1760,6 @@ add_executable(lte-softmodem ${OPENAIR_DIR}/common/utils/utils.c ${OPENAIR_DIR}/common/utils/system.c ${GTPU_need_ITTI} - ${RTAI_SOURCE} ${XFORMS_SOURCE} ${XFORMS_SOURCE_SOFTMODEM} ${T_SOURCE} @@ -1813,7 +1796,6 @@ add_executable(lte-softmodem-nos1 ${OPENAIR2_DIR}/RRC/NAS/rb_config.c ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c ${OPENAIR_DIR}/common/utils/system.c - ${RTAI_SOURCE} ${XFORMS_SOURCE} ${XFORMS_SOURCE_SOFTMODEM} ${T_SOURCE} @@ -2166,15 +2148,7 @@ endfunction(make_driver name dir src) # nashmesh module ################ list(APPEND nasmesh_src device.c common.c ioctl.c classifier.c tool.c mesh.c) -# Actually nasty stuff to be FIXED: the hereafter flag is for RTAI compilation in the driver, -# but has different meaning in the other parts of the code -# We should change the constant name to xxx_RTAI or likely -if(NOT ${module_cc_opt} MATCHES "DRTAI") - set(module_cc_opt "${module_cc_opt} -DNAS_NETLINK") -else() - string(REPLACE "-DNAS_NETLINK" "" tmp "${module_cc_opt}") - set(module_cc_opt ${tmp}) -endif() +set(module_cc_opt "${module_cc_opt} -DNAS_NETLINK -DPDCP_USE_NETLINK") # legacy Makefile was using NAS_NETLINK flag, but other drivers the hereafter flag # so, this cmake use OAI_NW_DRIVER_USE_NETLINK everywhere if (OAI_NW_DRIVER_USE_NETLINK) diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index 15fec380e9..6209cc9f0e 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -6,7 +6,6 @@ set ( ADDR_CONF False ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 True ) -set ( EMOS False ) set ( EMIT_ASN_DEBUG False ) set ( ENABLE_FXP True ) set ( ENABLE_ITTI True ) @@ -45,7 +44,6 @@ set ( NB_ANTENNAS_TX "2" ) set ( NB_ANTENNAS_TXRX "2" ) set ( NEW_FFT True ) set ( NO_RRM True ) -set ( OAI_EMU False ) set ( OAISIM False ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) set ( OAI_NW_DRIVER_USE_NETLINK True ) @@ -59,7 +57,6 @@ set ( PC_DSP True ) set ( PC_TARGET True ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) -set ( PHY_ABSTRACTION True ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) @@ -70,7 +67,6 @@ set ( RLC_STOP_ON_LOST_PDU False ) set ( RRC_ASN1_VERSION "Rel10" ) set ( RRC_DEFAULT_RAB_IS_AM True) set ( RRC_MSG_PRINT False ) -set ( RTAI False ) set ( SECU False ) set ( SMBV False ) set ( TEST_OMG False ) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index 80d2b60500..3d88fb39ae 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -5,7 +5,6 @@ set ( ADDR_CONF False ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 True ) -set ( EMOS False ) set ( ENABLE_FXP True ) set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING True ) @@ -44,7 +43,6 @@ set ( NB_ANTENNAS_TX "2" ) set ( NB_ANTENNAS_TXRX "2" ) set ( NEW_FFT True ) set ( NO_RRM True ) -set ( OAI_EMU True ) set ( OAISIM True ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) set ( OAI_NW_DRIVER_USE_NETLINK True ) @@ -58,7 +56,6 @@ set ( PC_DSP True ) set ( PC_TARGET True ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) -set ( PHY_ABSTRACTION True ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) @@ -69,7 +66,6 @@ set ( RLC_STOP_ON_LOST_PDU False ) set ( RRC_ASN1_VERSION "Rel10" ) set ( RRC_DEFAULT_RAB_IS_AM True) set ( RRC_MSG_PRINT False ) -set ( RTAI False ) set ( SECU False ) set ( SMBV False ) set ( SPECTRA False ) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index 0a11b8a249..528e09556d 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -5,7 +5,6 @@ set ( ADDR_CONF False ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 False ) -set ( EMOS False ) set ( ENABLE_FXP False ) set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING False ) @@ -45,7 +44,6 @@ set ( NB_ANTENNAS_TX "2" ) set ( NB_ANTENNAS_TXRX "2" ) set ( NEW_FFT False ) set ( NO_RRM False ) -set ( OAI_EMU False ) set ( OAISIM False ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) set ( OAI_NW_DRIVER_USE_NETLINK False ) @@ -59,7 +57,6 @@ set ( PC_DSP False ) set ( PC_TARGET False ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) -set ( PHY_ABSTRACTION False ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM False ) @@ -69,7 +66,6 @@ set ( RF_BOARD "False" ) set ( RRC_ASN1_VERSION "Rel10" ) set ( RLC_STOP_ON_LOST_PDU False ) set ( RRC_MSG_PRINT False ) -set ( RTAI False ) set ( SECU False ) set ( SMBV False ) set ( SPECTRA False ) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 510744cd7b..09c389fbcc 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -4,7 +4,6 @@ set ( ADDR_CONF False ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 True ) -set ( EMOS False ) set ( ENABLE_FXP True ) set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING False ) @@ -45,7 +44,6 @@ set ( NB_ANTENNAS_TX "2" ) set ( NB_ANTENNAS_TXRX "2" ) set ( NEW_FFT True ) set ( NO_RRM True ) -set ( OAI_EMU True ) set ( OAISIM True ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) set ( OAI_NW_DRIVER_USE_NETLINK True ) @@ -60,7 +58,6 @@ set ( PC_DSP True ) set ( PC_TARGET True ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) -set ( PHY_ABSTRACTION True ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) @@ -70,7 +67,6 @@ set ( RF_BOARD "False" ) set ( RRC_ASN1_VERSION "Rel10" ) set ( RLC_STOP_ON_LOST_PDU False ) set ( RRC_MSG_PRINT False ) -set ( RTAI False ) set ( SECU False ) set ( SMBV False ) set ( SPECTRA False ) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index 2bbf7bc536..0d8ec5e67a 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -5,7 +5,6 @@ set ( ADDR_CONF False ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 True ) -set ( EMOS False ) set ( ENABLE_FXP True ) set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING True ) @@ -45,7 +44,6 @@ set ( NB_ANTENNAS_TX "2" ) set ( NB_ANTENNAS_TXRX "2" ) set ( NEW_FFT True ) set ( NO_RRM True ) -set ( OAI_EMU True ) set ( OAISIM True ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) set ( OAI_NW_DRIVER_USE_NETLINK True ) @@ -59,7 +57,6 @@ set ( PC_DSP True ) set ( PC_TARGET True ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) -set ( PHY_ABSTRACTION True ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) @@ -70,7 +67,6 @@ set ( RLC_STOP_ON_LOST_PDU False ) set ( RRC_ASN1_VERSION "Rel10" ) set ( RRC_DEFAULT_RAB_IS_AM True) set ( RRC_MSG_PRINT False ) -set ( RTAI False ) set ( SECU False ) set ( SMBV False ) set ( SPECTRA False ) diff --git a/common/utils/itti/intertask_interface.c b/common/utils/itti/intertask_interface.c index 6c9a95732b..449fa434af 100644 --- a/common/utils/itti/intertask_interface.c +++ b/common/utils/itti/intertask_interface.c @@ -31,10 +31,6 @@ #include #include -#ifdef RTAI -# include -#endif - #if !defined(TRUE) #define TRUE 1 #endif @@ -45,11 +41,6 @@ #include "intertask_interface.h" #include "intertask_interface_dump.h" -#if defined(OAI_EMU) || defined(RTAI) -# include "memory_pools.h" -# include "vcd_signal_dumper.h" -#endif - #if T_TRACER #include "T.h" #endif @@ -64,14 +55,6 @@ #include "signals.h" #include "timer.h" -#ifdef RTAI -# include -# include -# define FIFO_PRINTF_MAX_STRING_SIZE 1000 -# define FIFO_PRINTF_NO 62 -# define FIFO_PRINTF_SIZE 65536 -#endif - /* ITTI DEBUG groups */ #define ITTI_DEBUG_POLL (1<<0) #define ITTI_DEBUG_SEND (1<<1) @@ -83,22 +66,12 @@ const int itti_debug = (ITTI_DEBUG_ISSUES | ITTI_DEBUG_MP_STATISTICS); -/* Don't flush if using RTAI */ -#ifdef RTAI -# define ITTI_DEBUG(m, x, args...) do { if ((m) & itti_debug) rt_log_debug (x, ##args); } while(0); -#else # define ITTI_DEBUG(m, x, args...) do { if ((m) & itti_debug) {fprintf(stdout, "[ITTI][D]"x, ##args); fflush (stdout);} } while(0); -#endif #define ITTI_ERROR(x, args...) do { fprintf(stdout, "[ITTI][E]"x, ##args); fflush (stdout); } while(0); /* Global message size */ #define MESSAGE_SIZE(mESSAGEiD) (sizeof(MessageHeader) + itti_desc.messages_info[mESSAGEiD].size) -#ifdef RTAI -# define ITTI_MEM_PAGE_SIZE (1024) -# define ITTI_MEM_SIZE (16 * 1024 * 1024) -#endif - typedef enum task_state_s { TASK_STATE_NOT_CONFIGURED, TASK_STATE_STARTING, TASK_STATE_READY, TASK_STATE_ENDED, TASK_STATE_MAX, } task_state_t; @@ -137,13 +110,11 @@ typedef struct thread_desc_s { int epoll_nb_events; - //#ifdef RTAI /* Flag to mark real time thread */ unsigned real_time; - /* Counter to indicate from RTAI threads that messages are pending for the thread */ + /* Counter to indicate that messages are pending for the thread */ unsigned messages_pending; - //#endif } thread_desc_t; typedef struct task_desc_s { @@ -175,17 +146,6 @@ typedef struct itti_desc_s { volatile uint32_t created_tasks; volatile uint32_t ready_tasks; volatile int wait_tasks; -#ifdef RTAI - pthread_t rt_relay_thread; -#endif - -#if defined(OAI_EMU) || defined(RTAI) - memory_pools_handle_t memory_pools_handle; - - uint64_t vcd_poll_msg; - uint64_t vcd_receive_msg; - uint64_t vcd_send_msg; -#endif } itti_desc_t; static itti_desc_t itti_desc; @@ -194,20 +154,8 @@ void *itti_malloc(task_id_t origin_task_id, task_id_t destination_task_id, ssize { void *ptr = NULL; -#if defined(OAI_EMU) || defined(RTAI) - ptr = memory_pools_allocate (itti_desc.memory_pools_handle, size, origin_task_id, destination_task_id); - - if (ptr == NULL) { - char *statistics = memory_pools_statistics (itti_desc.memory_pools_handle); - - ITTI_ERROR (" Memory pools statistics:\n%s", statistics); - free (statistics); - } - -#else ptr = malloc (size); if (ptr) memset(ptr,0,size); -#endif AssertFatal (ptr != NULL, "Memory allocation of %d bytes failed (%d -> %d)!\n", (int) size, origin_task_id, destination_task_id); @@ -219,13 +167,7 @@ int itti_free(task_id_t task_id, void *ptr) int result = EXIT_SUCCESS; AssertFatal (ptr != NULL, "Trying to free a NULL pointer (%d)!\n", task_id); -#if defined(OAI_EMU) || defined(RTAI) - result = memory_pools_free (itti_desc.memory_pools_handle, ptr, task_id); - - AssertError (result == EXIT_SUCCESS, {}, "Failed to free memory at %p (%d)!\n", ptr, task_id); -#else free (ptr); -#endif return (result); } @@ -281,27 +223,6 @@ static task_id_t itti_get_current_task_id(void) return TASK_UNKNOWN; } -#ifdef RTAI -static void rt_log_debug(char *format, ...) -{ - task_id_t task_id; - va_list args; - char log_buffer[FIFO_PRINTF_MAX_STRING_SIZE]; - int len; - - task_id = itti_get_current_task_id (); - len = snprintf(log_buffer, FIFO_PRINTF_MAX_STRING_SIZE-1, "[ITTI][D][%s]", itti_get_task_name(task_id)); - va_start(args, format); - len += vsnprintf(&log_buffer[len], FIFO_PRINTF_MAX_STRING_SIZE-1-len, format, args); - va_end (args); - - if (task_id != TASK_UNKNOWN) - fwrite(log_buffer, len, 1, stdout); - else - rtf_put (FIFO_PRINTF_NO, log_buffer, len); -} -#endif - void itti_update_lte_time(uint32_t frame, uint8_t slot) { itti_desc.lte_time.frame = frame; @@ -358,10 +279,6 @@ MessageDef *itti_alloc_new_message_sized(task_id_t origin_task_id, MessagesIds m AssertFatal (message_id < itti_desc.messages_id_max, "Message id (%d) is out of range (%d)!\n", message_id, itti_desc.messages_id_max); -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_ITTI_ALLOC_MSG, size); -#endif - if (origin_task_id == TASK_UNKNOWN) { /* Try to identify real origin task ID */ origin_task_id = itti_get_current_task_id(); @@ -373,10 +290,6 @@ MessageDef *itti_alloc_new_message_sized(task_id_t origin_task_id, MessagesIds m temp->ittiMsgHeader.originTaskId = origin_task_id; temp->ittiMsgHeader.ittiMsgSize = size; -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_ITTI_ALLOC_MSG, 0); -#endif - return temp; } @@ -394,11 +307,6 @@ int itti_send_msg_to_task(task_id_t destination_task_id, instance_t instance, Me message_number_t message_number; uint32_t message_id; -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_ITTI_SEND_MSG, - __sync_or_and_fetch (&itti_desc.vcd_send_msg, 1L << destination_task_id)); -#endif - AssertFatal (message != NULL, "Message is NULL!\n"); AssertFatal (destination_task_id < itti_desc.task_max, "Destination task id (%d) is out of range (%d)\n", destination_task_id, itti_desc.task_max); @@ -421,11 +329,6 @@ int itti_send_msg_to_task(task_id_t destination_task_id, instance_t instance, Me sizeof(MessageHeader) + message->ittiMsgHeader.ittiMsgSize); if (destination_task_id != TASK_UNKNOWN) { -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_ENQUEUE_MESSAGE, VCD_FUNCTION_IN); - - memory_pools_set_info (itti_desc.memory_pools_handle, message, 1, destination_task_id); -#endif if (itti_desc.threads[destination_thread_id].task_state == TASK_STATE_ENDED) { ITTI_DEBUG(ITTI_DEBUG_ISSUES, " Message %s, number %lu with priority %d can not be sent from %s to queue (%u:%s), ended destination task!\n", @@ -458,17 +361,6 @@ int itti_send_msg_to_task(task_id_t destination_task_id, instance_t instance, Me AssertFatal(0, "Error: lfds611_queue_enqueue returns 0, queue is full, exiting\n"); } -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_ENQUEUE_MESSAGE, VCD_FUNCTION_OUT); -#endif - -#ifdef RTAI - - if (itti_desc.threads[TASK_GET_THREAD_ID(origin_task_id)].real_time) { - /* This is a RT task, increase destination task messages pending counter */ - __sync_fetch_and_add (&itti_desc.threads[destination_thread_id].messages_pending, 1); - } else -#endif { /* Only use event fd for tasks, subtasks will pool the queue */ if (TASK_GET_PARENT_TASK_ID(destination_task_id) == TASK_UNKNOWN) { @@ -496,11 +388,6 @@ int itti_send_msg_to_task(task_id_t destination_task_id, instance_t instance, Me AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); } -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_ITTI_SEND_MSG, - __sync_and_and_fetch (&itti_desc.vcd_send_msg, ~(1L << destination_task_id))); -#endif - return 0; } @@ -645,17 +532,9 @@ static inline void itti_receive_msg_internal_event_fd(task_id_t task_id, uint8_t void itti_receive_msg(task_id_t task_id, MessageDef **received_msg) { -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_ITTI_RECV_MSG, - __sync_and_and_fetch (&itti_desc.vcd_receive_msg, ~(1L << task_id))); -#endif itti_receive_msg_internal_event_fd(task_id, 0, received_msg); -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_ITTI_RECV_MSG, - __sync_or_and_fetch (&itti_desc.vcd_receive_msg, 1L << task_id)); -#endif } void itti_poll_msg(task_id_t task_id, MessageDef **received_msg) @@ -664,11 +543,6 @@ void itti_poll_msg(task_id_t task_id, MessageDef **received_msg) *received_msg = NULL; -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_ITTI_POLL_MSG, - __sync_or_and_fetch (&itti_desc.vcd_poll_msg, 1L << task_id)); -#endif - { struct message_list_s *message; @@ -685,10 +559,6 @@ void itti_poll_msg(task_id_t task_id, MessageDef **received_msg) ITTI_DEBUG(ITTI_DEBUG_POLL, " No message in queue[(%u:%s)]\n", task_id, itti_get_task_name(task_id)); } -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_ITTI_POLL_MSG, - __sync_and_and_fetch (&itti_desc.vcd_poll_msg, ~(1L << task_id))); -#endif } int itti_create_task(task_id_t task_id, void *(*start_routine)(void *), void *args_p) @@ -720,7 +590,6 @@ int itti_create_task(task_id_t task_id, void *(*start_routine)(void *), void *ar return 0; } -//#ifdef RTAI void itti_set_task_real_time(task_id_t task_id) { thread_id_t thread_id = TASK_GET_THREAD_ID(task_id); @@ -729,7 +598,6 @@ void itti_set_task_real_time(task_id_t task_id) itti_desc.threads[thread_id].real_time = TRUE; } -//#endif void itti_wait_ready(int wait_tasks) { @@ -757,15 +625,6 @@ void itti_mark_task_ready(task_id_t task_id) /* Mark the thread as using LFDS queue */ lfds611_queue_use(itti_desc.tasks[task_id].message_queue); -#ifdef RTAI - /* Assign low priority to created threads */ - { - struct sched_param sched_param; - sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 1; - sched_setscheduler(0, SCHED_FIFO, &sched_param); - } -#endif - itti_desc.threads[thread_id].task_state = TASK_STATE_READY; itti_desc.ready_tasks ++; @@ -778,15 +637,6 @@ void itti_mark_task_ready(task_id_t task_id) void itti_exit_task(void) { -#if defined(OAI_EMU) || defined(RTAI) - task_id_t task_id = itti_get_current_task_id(); - - if (task_id > TASK_UNKNOWN) { - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_ITTI_RECV_MSG, - __sync_and_and_fetch (&itti_desc.vcd_receive_msg, ~(1L << task_id))); - } - -#endif pthread_exit (NULL); } @@ -802,45 +652,6 @@ void itti_terminate_tasks(task_id_t task_id) pthread_exit (NULL); } -#ifdef RTAI -static void *itti_rt_relay_thread(void *arg) -{ - thread_id_t thread_id; - unsigned pending_messages; - - while (itti_desc.running) { - usleep (200); // Poll for messages a little more than 2 time by slot to get a small latency between RT and other tasks - -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_RELAY_THREAD, VCD_FUNCTION_IN); -#endif - - /* Checks for all non real time tasks if they have pending messages */ - for (thread_id = THREAD_FIRST; thread_id < itti_desc.thread_max; thread_id++) { - if ((itti_desc.threads[thread_id].task_state == TASK_STATE_READY) - && (itti_desc.threads[thread_id].real_time == FALSE)) { - pending_messages = __sync_fetch_and_and (&itti_desc.threads[thread_id].messages_pending, 0); - - if (pending_messages > 0) { - ssize_t write_ret; - eventfd_t sem_counter = pending_messages; - - /* Call to write for an event fd must be of 8 bytes */ - write_ret = write (itti_desc.threads[thread_id].task_event_fd, &sem_counter, sizeof(sem_counter)); - DevCheck(write_ret == sizeof(sem_counter), write_ret, sem_counter, thread_id); - } - } - } - -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_RELAY_THREAD, VCD_FUNCTION_OUT); -#endif - } - - return NULL; -} -#endif - int itti_init(task_id_t task_max, thread_id_t thread_max, MessagesIds messages_id_max, const task_info_t *tasks_info, const message_info_t *messages_info, const char * const messages_definition_xml, const char * const dump_file_name) { @@ -921,45 +732,12 @@ int itti_init(task_id_t task_max, thread_id_t thread_max, MessagesIds messages_i ITTI_DEBUG(ITTI_DEBUG_EVEN_FD, " Successfully subscribed fd %d for thread %d\n", itti_desc.threads[thread_id].task_event_fd, thread_id); -#ifdef RTAI - itti_desc.threads[thread_id].real_time = FALSE; - itti_desc.threads[thread_id].messages_pending = 0; -#endif } itti_desc.running = 1; itti_desc.wait_tasks = 0; itti_desc.created_tasks = 0; itti_desc.ready_tasks = 0; -#ifdef RTAI - /* Start RT relay thread */ - DevAssert(pthread_create (&itti_desc.rt_relay_thread, NULL, itti_rt_relay_thread, NULL) >= 0); - - rt_global_heap_open(); -#endif - -#if defined(OAI_EMU) || defined(RTAI) - itti_desc.memory_pools_handle = memory_pools_create (5); - memory_pools_add_pool (itti_desc.memory_pools_handle, 1000 + ITTI_QUEUE_MAX_ELEMENTS, 50); - memory_pools_add_pool (itti_desc.memory_pools_handle, 1000 + (2 * ITTI_QUEUE_MAX_ELEMENTS), 100); - memory_pools_add_pool (itti_desc.memory_pools_handle, 10000, 1000); - memory_pools_add_pool (itti_desc.memory_pools_handle, 400, 20050); - memory_pools_add_pool (itti_desc.memory_pools_handle, 100, 30050); - - { - char *statistics = memory_pools_statistics (itti_desc.memory_pools_handle); - - ITTI_DEBUG(ITTI_DEBUG_MP_STATISTICS, " Memory pools statistics:\n%s", statistics); - free (statistics); - } -#endif - -#if defined(OAI_EMU) || defined(RTAI) - itti_desc.vcd_poll_msg = 0; - itti_desc.vcd_receive_msg = 0; - itti_desc.vcd_send_msg = 0; -#endif - itti_dump_init (messages_definition_xml, dump_file_name); CHECK_INIT_RETURN(timer_init ()); @@ -1022,15 +800,6 @@ void itti_wait_tasks_end(void) itti_desc.running = 0; -#if defined(OAI_EMU) || defined(RTAI) - { - char *statistics = memory_pools_statistics (itti_desc.memory_pools_handle); - - ITTI_DEBUG(ITTI_DEBUG_MP_STATISTICS, " Memory pools statistics:\n%s", statistics); - free (statistics); - } -#endif - if (ready_tasks > 0) { ITTI_DEBUG(ITTI_DEBUG_ISSUES, " Some threads are still running, force exit\n"); exit (0); diff --git a/common/utils/itti/intertask_interface.h b/common/utils/itti/intertask_interface.h index 191d9199c3..606c851d1d 100644 --- a/common/utils/itti/intertask_interface.h +++ b/common/utils/itti/intertask_interface.h @@ -27,10 +27,6 @@ #include -#ifdef RTAI -# include -#endif - #ifndef INTERTASK_INTERFACE_H_ #define INTERTASK_INTERFACE_H_ @@ -155,12 +151,10 @@ int itti_create_task(task_id_t task_id, void *(*start_routine) (void *), void *args_p); -//#ifdef RTAI /** \brief Mark the task as a real time task * \param task_id task to mark as real time **/ void itti_set_task_real_time(task_id_t task_id); -//#endif /** \brief Indicates to ITTI if newly created tasks should wait for all tasks to be ready * \param wait_tasks non 0 to make new created tasks to wait, 0 to let created tasks to run diff --git a/common/utils/itti/intertask_interface_dump.c b/common/utils/itti/intertask_interface_dump.c index a06b97c63b..bb77509726 100644 --- a/common/utils/itti/intertask_interface_dump.c +++ b/common/utils/itti/intertask_interface_dump.c @@ -51,23 +51,14 @@ #include "intertask_interface.h" #include "intertask_interface_dump.h" -#if defined(OAI_EMU) || defined(RTAI) -#include "vcd_signal_dumper.h" -#endif - #if T_TRACER #include "T.h" #endif static const int itti_dump_debug = 0; // 0x8 | 0x4 | 0x2; -#ifdef RTAI -# define ITTI_DUMP_DEBUG(m, x, args...) do { if ((m) & itti_dump_debug) rt_printk("[ITTI_DUMP][D]"x, ##args); } \ - while(0) -#else # define ITTI_DUMP_DEBUG(m, x, args...) do { if ((m) & itti_dump_debug) fprintf(stdout, "[ITTI_DUMP][D]"x, ##args); } \ while(0) -#endif #define ITTI_DUMP_ERROR(x, args...) do { fprintf(stdout, "[ITTI_DUMP][E]"x, ##args); } \ while(0) @@ -99,13 +90,8 @@ typedef struct itti_desc_s { int nb_connected; -#ifndef RTAI /* Event fd used to notify new messages (semaphore) */ int event_fd; -#else - unsigned long messages_in_queue __attribute__((aligned(8))); -#endif - int itti_listen_socket; itti_client_desc_t itti_clients[ITTI_DUMP_MAX_CON]; @@ -194,9 +180,7 @@ static int itti_dump_fwrite_message(itti_dump_queue_item_t *message) fwrite (&new_message_header, sizeof(itti_dump_message_t), 1, dump_file); fwrite (message->data, message->data_size, 1, dump_file); fwrite (&itti_dump_message_type_end, sizeof(itti_message_types_t), 1, dump_file); - // #if !defined(RTAI) fflush (dump_file); - // #endif return (1); } @@ -280,10 +264,6 @@ static int itti_dump_enqueue_message(itti_dump_queue_item_t *new, uint32_t messa int overwrite_flag; AssertFatal (new != NULL, "Message to queue is NULL!\n"); -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE, VCD_FUNCTION_IN); -#endif - new->message_type = message_type; new->message_size = message_size; @@ -303,9 +283,6 @@ static int itti_dump_enqueue_message(itti_dump_queue_item_t *new, uint32_t messa lfds611_ringbuffer_put_write_element(itti_dump_queue.itti_message_queue, new_queue_element); if (overwrite_flag == 0) { -#ifdef RTAI - __sync_fetch_and_add (&itti_dump_queue.messages_in_queue, 1); -#else { ssize_t write_ret; eventfd_t sem_counter = 1; @@ -314,25 +291,18 @@ static int itti_dump_enqueue_message(itti_dump_queue_item_t *new, uint32_t messa write_ret = write(itti_dump_queue.event_fd, &sem_counter, sizeof(sem_counter)); AssertFatal (write_ret == sizeof(sem_counter), "Write to dump event failed (%d/%d)!\n", (int) write_ret, (int) sizeof(sem_counter)); } -#endif // add one to pending_messages, atomically __sync_fetch_and_add (&pending_messages, 1); } ITTI_DUMP_DEBUG (0x2, " Added element to queue %p %p, pending %u, type %u\n", new_queue_element, new, pending_messages, message_type); -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE, VCD_FUNCTION_OUT); -#endif - return 0; } static void itti_dump_socket_exit(void) { -#ifndef RTAI close(itti_dump_queue.event_fd); -#endif close(itti_dump_queue.itti_listen_socket); /* Leave the thread as we detected end signal */ @@ -346,10 +316,6 @@ static int itti_dump_flush_ring_buffer(int flush_all) int j; int consumer; -#ifdef RTAI - unsigned long number_of_messages; -#endif - /* Check if there is a least one consumer */ consumer = 0; @@ -365,18 +331,6 @@ static int itti_dump_flush_ring_buffer(int flush_all) } if (consumer > 0) { -#ifdef RTAI - number_of_messages = itti_dump_queue.messages_in_queue; - - ITTI_DUMP_DEBUG(0x4, "%lu elements in queue\n", number_of_messages); - - if (number_of_messages == 0) { - return (consumer); - } - - __sync_sub_and_fetch(&itti_dump_queue.messages_in_queue, number_of_messages); -#endif - do { /* Acquire the ring element */ lfds611_ringbuffer_get_read_element(itti_dump_queue.itti_message_queue, &element); @@ -419,9 +373,6 @@ static int itti_dump_flush_ring_buffer(int flush_all) lfds611_ringbuffer_put_read_element(itti_dump_queue.itti_message_queue, element); } } while(flush_all -#ifdef RTAI - && --number_of_messages -#endif ); } @@ -478,9 +429,6 @@ static void *itti_dump_socket(void *arg_p) struct sockaddr_in servaddr; /* socket address structure */ struct timeval *timeout_p = NULL; -#ifdef RTAI - struct timeval timeout; -#endif ITTI_DUMP_DEBUG(0x2, " Creating TCP dump socket on port %u\n", ITTI_PORT); @@ -536,15 +484,11 @@ static void *itti_dump_socket(void *arg_p) /* Add the listener */ FD_SET(itti_listen_socket, &read_set); -#ifndef RTAI /* Add the event fd */ FD_SET(itti_dump_queue.event_fd, &read_set); /* Max of both sd */ max_sd = itti_listen_socket > itti_dump_queue.event_fd ? itti_listen_socket : itti_dump_queue.event_fd; -#else - max_sd = itti_listen_socket; -#endif itti_dump_queue.itti_listen_socket = itti_listen_socket; @@ -557,14 +501,7 @@ static void *itti_dump_socket(void *arg_p) int i; memcpy(&working_set, &read_set, sizeof(read_set)); -#ifdef RTAI - timeout.tv_sec = 0; - timeout.tv_usec = 100000; - - timeout_p = &timeout; -#else timeout_p = NULL; -#endif /* No timeout: select blocks till a new event has to be handled * on sd's. @@ -592,8 +529,6 @@ static void *itti_dump_socket(void *arg_p) if (FD_ISSET(i, &working_set)) { desc_ready -= 1; -#ifndef RTAI - if (i == itti_dump_queue.event_fd) { /* Notification of new element to dump from other tasks */ eventfd_t sem_counter; @@ -613,7 +548,6 @@ static void *itti_dump_socket(void *arg_p) if (itti_dump_running) { ITTI_DUMP_DEBUG (0x4, " No messages consumers, waiting ...\n"); usleep(100 * 1000); -#ifndef RTAI { ssize_t write_ret; @@ -622,7 +556,6 @@ static void *itti_dump_socket(void *arg_p) write_ret = write(itti_dump_queue.event_fd, &sem_counter, sizeof(sem_counter)); AssertFatal (write_ret == sizeof(sem_counter), "Failed to write to dump event FD (%d/%d)!\n", (int) write_ret, (int) sem_counter); } -#endif } else { itti_dump_socket_exit(); } @@ -630,7 +563,6 @@ static void *itti_dump_socket(void *arg_p) ITTI_DUMP_DEBUG(0x1, " Write element to file\n"); } } else -#endif if (i == itti_listen_socket) { do { client_socket = accept(itti_listen_socket, NULL, NULL); @@ -719,21 +651,9 @@ int itti_dump_queue_message(task_id_t sender_task, AssertFatal (message_name != NULL, "Message name is NULL!\n"); AssertFatal (message_p != NULL, "Message is NULL!\n"); -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE_MALLOC, VCD_FUNCTION_IN); -#endif new = itti_malloc(sender_task, TASK_MAX, sizeof(itti_dump_queue_item_t)); -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE_MALLOC, VCD_FUNCTION_OUT); -#endif -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE_MALLOC, VCD_FUNCTION_IN); -#endif new->data = itti_malloc(sender_task, TASK_MAX, message_size); -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ITTI_DUMP_ENQUEUE_MESSAGE_MALLOC, VCD_FUNCTION_OUT); -#endif memcpy(new->data, message_p, message_size); new->data_size = message_size; @@ -791,9 +711,6 @@ int itti_dump_init(const char * const messages_definition_xml, const char * cons AssertFatal (0, " Failed to create ring buffer!\n"); } -#ifdef RTAI - itti_dump_queue.messages_in_queue = 0; -#else itti_dump_queue.event_fd = eventfd(0, EFD_SEMAPHORE); if (itti_dump_queue.event_fd == -1) { @@ -801,8 +718,6 @@ int itti_dump_init(const char * const messages_definition_xml, const char * cons AssertFatal (0, "eventfd failed: %s!\n", strerror(errno)); } -#endif - itti_dump_queue.nb_connected = 0; for(i = 0; i < ITTI_DUMP_MAX_CON; i++) { diff --git a/common/utils/itti/memory_pools.c b/common/utils/itti/memory_pools.c index 23c53b71ae..78b6923dc8 100644 --- a/common/utils/itti/memory_pools.c +++ b/common/utils/itti/memory_pools.c @@ -19,15 +19,8 @@ * contact@openairinterface.org */ -#ifdef RTAI -# include -#endif - #include "assertions.h" #include "memory_pools.h" -#if defined(OAI_EMU) || defined(RTAI) -# include "vcd_signal_dumper.h" -#endif #if T_TRACER #include @@ -37,18 +30,8 @@ /*------------------------------------------------------------------------------*/ const static int mp_debug = 0; -#ifdef RTAI -# define MP_DEBUG(x, args...) do { if (mp_debug) rt_printk("[MP][D]"x, ##args); } \ - while(0) -#else # define MP_DEBUG(x, args...) do { if (mp_debug) fprintf(stdout, "[MP][D]"x, ##args); fflush (stdout); } \ while(0) -#endif - -#if defined(OAI_EMU) || defined(RTAI) -uint64_t vcd_mp_alloc; -uint64_t vcd_mp_free; -#endif /*------------------------------------------------------------------------------*/ #ifndef CHARS_TO_UINT32 @@ -414,11 +397,6 @@ memory_pool_item_handle_t memory_pools_allocate (memory_pools_handle_t memory_po pool_id_t pool; items_group_index_t item_index = ITEMS_GROUP_INDEX_INVALID; -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_MP_ALLOC, - __sync_or_and_fetch (&vcd_mp_alloc, 1L << info_0)); -#endif - /* Recover memory_pools */ memory_pools = memory_pools_from_handler (memory_pools_handle); AssertError (memory_pools != NULL, {}, "Failed to retrieve memory pool for handle %p!\n", memory_pools_handle); @@ -464,11 +442,6 @@ memory_pool_item_handle_t memory_pools_allocate (memory_pools_handle_t memory_po MP_DEBUG(" Alloc [--][------]{------}, %3u %3u, %6u, failed!\n", info_0, info_1, item_size); } -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_MP_ALLOC, - __sync_and_and_fetch (&vcd_mp_alloc, ~(1L << info_0))); -#endif - return memory_pool_item_handle; } @@ -493,11 +466,6 @@ int memory_pools_free (memory_pools_handle_t memory_pools_handle, memory_pool_it info_1 = memory_pool_item->start.info[1]; -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_MP_FREE, - __sync_or_and_fetch (&vcd_mp_free, 1L << info_1)); -#endif - /* Recover pool index */ pool = memory_pool_item->start.pool_id; AssertFatal (pool < memory_pools->pools_defined, "Pool index is invalid (%u/%u)!\n", pool, memory_pools->pools_defined); @@ -531,11 +499,6 @@ int memory_pools_free (memory_pools_handle_t memory_pools_handle, memory_pool_it AssertError (result == EXIT_SUCCESS, {}, "Failed to free memory pool item (pool %u, item %d)!\n", pool, item_index); -#if defined(OAI_EMU) || defined(RTAI) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLE_MP_FREE, - __sync_and_and_fetch (&vcd_mp_free, ~(1L << info_1))); -#endif - return (result); } diff --git a/openair1/Makefile b/openair1/Makefile deleted file mode 100644 index 04be9ff8b0..0000000000 --- a/openair1/Makefile +++ /dev/null @@ -1,121 +0,0 @@ -# command line flags are automatically exported and thus passed down to any sub-make. -# here we set the default flags in case on command line flags are provided -# these flags have to be explicitely exported so that the sub-make is aware of them - - -include $(OPENAIR_DIR)/common/utils/Makefile.inc -ifndef OPENAIR_LTE -export OPENAIR_LTE=1 -endif - -ifndef OPENAIR1 -export OPENAIR1=1 -endif - -ifndef OPENAIR2 -export OPENAIR2=0 -endif - -ifndef EMOS -export EMOS=0 -endif - -ifndef FIRMWARE2010 -export FIRMWARE2010=0 -endif - -all: openair_rf_cbmimo1_softmodem.ko asn1_msg_kern.ko - -openair_rf_cbmimo1_softmodem.ko: - (cd ARCH/CBMIMO1/DEVICE_DRIVER && $(MAKE) -C $(KERNEL_DIR)/build V=1 M=`pwd` RTAI=1 CBMIMO1=1 && mv openair_rf.ko openair_rf_softmodem.ko) - -oai_user_cbmimo1.ko: - (cd ARCH/CBMIMO1/DEVICE_DRIVER && $(MAKE) -C $(KERNEL_DIR)/build V=1 M=`pwd` RTAI=1 CBMIMO1=1 BIT8_TX=1 OPENAIR1=0 OPENAIR2=0 && mv openair_rf.ko openair_rf_softmodem.ko) - -oai_user_exmimo.ko: - (cd ARCH/CBMIMO1/DEVICE_DRIVER && $(MAKE) -C $(KERNEL_DIR)/build V=1 M=`pwd` RTAI=1 CBMIMO1=1 OPENAIR1=0 OPENAIR2=0 && mv openair_rf.ko openair_rf_softmodem.ko) - -asn1_msg_kern.ko: - (cd ../openair2/RRC/LITE/MESSAGES && $(MAKE) -C $(KERNEL_DIR) V=0 M=`pwd` RTAI=1 -j2) - -#Remove all but source files -cleanall: - find -name '*.o' -delete -print; \ - find -name '*.ko' -delete -print; \ - find -name '*.bak' -delete -print; \ - find -name '*.cmd' -delete -print; \ - find -name '*~' -delete -print; \ - find -name octave-core -delete -print; \ - -#Remove files created by SVN, dangerous!!! DO NOT RUN ON YOUR WORKING REPOSITORY! -#FK: Don't do this! Use svn export instead. -#cleansvn: -# rm -rf `find -name *.svn* -print`; \ -# find -name *.svn* -delete -print - -tgz: - mkdir /tmp/openair1_tmp; \ - $(MAKE) cleanall; \ - cp -r . /tmp/openair1_tmp; \ - (cd /tmp/openair1_tmp && $(MAKE) cleansvn && cd .. && tar czfv openair1.tgz openair1_tmp) ; \ - cp /tmp/openair1.tgz . ;\ - rm -rf /tmp/openair1_tmp - -fifos: - @for i in `seq 0 64`;\ - do \ - have_rtfX=`ls /dev/ |grep -c rtf$$i`;\ - if [ "$$have_rtfX" -eq 0 ] ;then \ - mknod -m 666 /dev/rtf$$i c 150 $$i; \ - fi;\ - done - -openair0: - mknod /dev/openair0 c 127 0 - chmod a+rw /dev/openair0 - -install_oai_user: - make fifos - insmod ARCH/CBMIMO1/DEVICE_DRIVER/openair_rf_softmodem.ko - -updatefw: - USERSPACE_TOOLS/OAI_FW_INIT/updatefw -f $$OPENAIR0_DIR/express-mimo/software/sdr_exmimo2/main -s 0x43fffff0 - -boot_exmimo: - sudo make install_oai_user - USERSPACE_TOOLS/OAI_FW_INIT/updatefw -f $$OPENAIR0_DIR/express-mimo/software/sdr/main -s 0x43fffff0 - sudo rmmod openair_rf - sudo make install_oai_user - -reboot_exmimo: - USERSPACE_TOOLS/OAI_FW_INIT/updatefw -f $$OPENAIR0_DIR/express-mimo/software/sdr/main -s 0x43fffff0 -b - rmmod openair_rf - make install_oai_user - USERSPACE_TOOLS/OAI_FW_INIT/updatefw -f $$OPENAIR0_DIR/express-mimo/software/sdr/main -s 0x43fffff0 - rmmod openair_rf - make install_oai_user - -install_softmodem: - make fifos -ifeq ($(OPENAIR2),1) - insmod ../openair2/RRC/LITE/MESSAGES/asn1_msg_kern.ko -endif - insmod ARCH/CBMIMO1/DEVICE_DRIVER/openair_rf_softmodem.ko ; \ - -remove: - rmmod openair_rf -ifeq ($(OPENAIR2),1) - rmmod asn1_msg_kern -endif - -test: - (cd ARCH/CBMIMO1/DEVICE_DRIVER && $(MAKE) test RTAI=1 CBMIMO1=1) - (cd ../openair2/RRC/LITE/MESSAGES && $(MAKE) test) - -clean: clean_l1 - -clean_l1: - (cd ARCH/CBMIMO1/DEVICE_DRIVER && $(MAKE) clean RTAI=1 CBMIMO1=1) - -clean_asn1: - (cd ../openair2/RRC/LITE/MESSAGES && $(MAKE) clean) diff --git a/openair1/PHY/LTE_ESTIMATION/defs.h b/openair1/PHY/LTE_ESTIMATION/defs.h index aae97ecd9e..a7b5d14701 100644 --- a/openair1/PHY/LTE_ESTIMATION/defs.h +++ b/openair1/PHY/LTE_ESTIMATION/defs.h @@ -23,12 +23,6 @@ #define __LTE_ESTIMATION_DEFS__H__ #include "PHY/defs.h" -/* -#ifdef EMOS -#include "SCHED/phy_procedures_emos.h" -#endif - */ - /** @addtogroup _PHY_PARAMETER_ESTIMATION_BLOCKS_ * @{ */ @@ -136,18 +130,6 @@ int lte_dl_mbsfn_channel_estimation(PHY_VARS_UE *phy_vars_ue, int subframe, unsigned char l); -/* -#ifdef EMOS -int lte_dl_channel_estimation_emos(int dl_ch_estimates_emos[NB_ANTENNAS_RX*NB_ANTENNAS_TX][N_RB_DL_EMOS*N_PILOTS_PER_RB*N_SLOTS_EMOS], - int **rxdataF, - LTE_DL_FRAME_PARMS *frame_parms, - unsigned char Ns, - unsigned char p, - unsigned char l, - unsigned char sector); -#endif - */ - /*! \brief Frequency offset estimation for LTE We estimate the frequency offset by calculating the phase difference between channel estimates for symbols carrying pilots (l==0 or l==3/4). We take a moving average of the phase difference. diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation_emos.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation_emos.c deleted file mode 100644 index 4f1015a0e1..0000000000 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation_emos.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#include -#include "defs.h" -#include "PHY/defs.h" -#include "SCHED/phy_procedures_emos.h" - -// TODO: make channel estimation possible for multiple sectors (Gold sequences for pilots) - -//#define DEBUG_CH -int lte_dl_channel_estimation_emos(int dl_ch_estimates_emos[NB_ANTENNAS_RX*NB_ANTENNAS_TX][N_RB_DL_EMOS*N_PILOTS_PER_RB*N_SLOTS_EMOS], - int **rxdataF, - LTE_DL_FRAME_PARMS *frame_parms, - unsigned char Ns, - unsigned char p, - unsigned char l, - unsigned char sector) -{ - - int pilot[2][200] __attribute__((aligned(16))); - unsigned char nu,aarx; - unsigned short k; - unsigned int rb,pilot_cnt; - short ch[2],*pil,*rxF,*dl_ch,*dl_ch_prev; //*f,*f2,*fl,*f2l2,*fr,*f2r2; - int ch_offset,symbol_offset; - unsigned int n; - int i; - - unsigned char symbol = l+((7-frame_parms->Ncp)*(Ns&1)); ///symbol within sub-frame - - if ((p==0) && (l==0) ) - nu = 0; - else if ((p==0) && (l>0)) - nu = 3; - else if ((p==1) && (l==0)) - nu = 3; - else if ((p==1) && (l>0)) - nu = 0; - else { - msg("lte_dl_channel_estimation_emos: p %d, l %d -> ERROR\n",p,l); - return(-1); - } - - if (sector > 2) { - msg("lte_dl_channel_estimation_emos: sector must be 0,1, or 2\n"); - return(-1); - } - - switch (Ns) { - case 0: - ch_offset = ((l==0)?0:1)*2*frame_parms->N_RB_DL; - break; - - case 1: - ch_offset = ((l==0)?2:3)*2*frame_parms->N_RB_DL; - break; - - case 12: - ch_offset = ((l==0)?4:5)*2*frame_parms->N_RB_DL; - break; - - case 13: - ch_offset = ((l==0)?6:7)*2*frame_parms->N_RB_DL; - break; - - default: - msg("lte_dl_channel_estimation_emos: Ns must be 0, 1, 12, or 13\n"); - return(-1); - break; - - } - - symbol_offset = symbol*frame_parms->ofdm_symbol_size; // offset within rxdataF - - k = nu + sector; - - if (k > 6) - k -=6; - -#ifdef DEBUG_CH - printf("Channel Estimation : ch_offset %d, OFDM size %d, Ncp=%d, l=%d, Ns=%d, k=%d, symbol=%d\n",ch_offset,frame_parms->ofdm_symbol_size,frame_parms->Ncp,l,Ns,k,symbol); -#endif - - // generate pilot - lte_dl_cell_spec_rx(&pilot[p][0], - frame_parms, - Ns, - (l==0)?0:1, - p); - - - for (aarx=0; aarxnb_antennas_rx; aarx++) { - - pil = (short *)&pilot[p][0]; - rxF = (short *)&rxdataF[aarx][((symbol_offset+k+frame_parms->first_carrier_offset)<<1)]; - dl_ch = (short *)&dl_ch_estimates_emos[(p<<1)+aarx][ch_offset]; - memset(dl_ch,0,frame_parms->N_RB_DL); - - for (pilot_cnt=0; pilot_cntN_RB_DL; pilot_cnt++) { - - dl_ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); - dl_ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); - - pil+=2; // Re Im - rxF+=24; // remember replicated format (Re0 Im0 Re0 Im0) !!! - dl_ch+=2; - - } - - // printf("Second half\n"); - // Second half of RBs - rxF = (short *)&rxdataF[aarx][((symbol_offset+1+k)<<1)]; - - for (pilot_cnt=0; pilot_cntN_RB_DL; pilot_cnt++) { - - - dl_ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); - dl_ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); - - pil+=2; - rxF+=24; - dl_ch+=2; - - } - - } - - return(0); -} - diff --git a/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c b/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c index c7625ba083..2525f19b0d 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c @@ -578,30 +578,3 @@ int lte_sync_time_eNB(int32_t **rxdata, ///rx data in time domain } -#ifdef PHY_ABSTRACTION -#include "SIMULATION/TOOLS/defs.h" -#include "SIMULATION/RF/defs.h" -//extern channel_desc_t *UE2eNB[NUMBER_OF_UE_MAX][NUMBER_OF_eNB_MAX]; - -int lte_sync_time_eNB_emul(PHY_VARS_eNB *phy_vars_eNB, - uint8_t sect_id, - int32_t *sync_val) -{ - - uint8_t UE_id; - uint8_t CC_id = phy_vars_eNB->CC_id; - - LOG_E(PHY,"[PHY] EMUL lte_sync_time_eNB_emul eNB %d, sect_id %d\n",phy_vars_eNB->Mod_id,sect_id); - *sync_val = 0; - - for (UE_id=0; UE_idMod_id,UE_id,PHY_vars_UE_g[UE_id]->generate_prach,UE2eNB[UE_id][phy_vars_eNB->Mod_id]->path_loss_dB); - if ((PHY_vars_UE_g[UE_id][CC_id]->generate_prach == 1) && (phy_vars_eNB->Mod_id == (UE_id % NB_eNB_INST))) { - *sync_val = 1; - return(0); - } - } - - return(-1); -} -#endif diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index b74e05ab1b..fae1077763 100755 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -4206,33 +4206,3 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *ue, return(dci_cnt); } - -#ifdef PHY_ABSTRACTION -uint16_t dci_decoding_procedure_emul(LTE_UE_PDCCH **pdcch_vars, - uint8_t num_ue_spec_dci, - uint8_t num_common_dci, - DCI_ALLOC_t *dci_alloc_tx, - DCI_ALLOC_t *dci_alloc_rx, - int16_t eNB_id) -{ - - uint8_t dci_cnt=0,i; - - memcpy(dci_alloc_rx,dci_alloc_tx,num_common_dci*sizeof(DCI_ALLOC_t)); - dci_cnt = num_common_dci; - LOG_D(PHY,"[DCI][EMUL] : num_common_dci %d\n",num_common_dci); - - for (i=num_common_dci; i<(num_ue_spec_dci+num_common_dci); i++) { - LOG_D(PHY,"[DCI][EMUL] Checking dci %d => %x format %d (bit 0 %d)\n",i,pdcch_vars[eNB_id]->crnti,dci_alloc_tx[i].format, - dci_alloc_tx[i].dci_pdu[0]&0x80); - - if (dci_alloc_tx[i].rnti == pdcch_vars[eNB_id]->crnti) { - memcpy(dci_alloc_rx+dci_cnt,dci_alloc_tx+i,sizeof(DCI_ALLOC_t)); - dci_cnt++; - } - } - - - return(dci_cnt); -} -#endif diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c index 384c633fdc..7acf6480eb 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c @@ -758,310 +758,3 @@ uint32_t dlsch_decoding(PHY_VARS_UE *phy_vars_ue, return(ret); } -#ifdef PHY_ABSTRACTION -#include "SIMULATION/TOOLS/defs.h" -#ifdef OPENAIR2 -#include "LAYER2/MAC/extern.h" -#include "LAYER2/MAC/defs.h" -#endif - -int dlsch_abstraction_EESM(double* sinr_dB, uint8_t TM, uint32_t rb_alloc[4], uint8_t mcs, uint8_t dl_power_off) -{ - - int ii; - double sinr_eff = 0; - int rb_count = 0; - int offset; - double bler = 0; - - if(TM==5 && dl_power_off==1) { - //do nothing -- means there is no second UE and TM 5 is behaving like TM 6 for a singal user - } else - TM = TM-1; - - for (offset = 0; offset <= 24; offset++) { - if (rb_alloc[0] & (1<qpsk_max) - I += 1; - else - I += (q_qpsk[0]*pow(x,7) + q_qpsk[1]*pow(x,6) + q_qpsk[2]*pow(x,5) + q_qpsk[3]*pow(x,4) + q_qpsk[4]*pow(x,3) + q_qpsk[5]*pow(x,2) + q_qpsk[6]*x + q_qpsk[7]); - } else if(mcs>9 && mcs<17) { - if(x>qam16_max) - I += 1; - else - I += (q_qam16[0]*pow(x,7) + q_qam16[1]*pow(x,6) + q_qam16[2]*pow(x,5) + q_qam16[3]*pow(x,4) + q_qam16[4]*pow(x,3) + q_qam16[5]*pow(x,2) + q_qam16[6]*x + q_qam16[7]); - } else if(mcs>16 && mcs<23) { - - if(x>qam64_max) - I += 1; - else - I += (q_qam64[0]*pow(x,7) + q_qam64[1]*pow(x,6) + q_qam64[2]*pow(x,5) + q_qam64[3]*pow(x,4) + q_qam64[4]*pow(x,3) + q_qam64[5]*pow(x,2) + q_qam64[6]*x + q_qam64[7]); - } - } - } - } - } - - // averaging of accumulated MI - I = I/(12*rb_count); - //Now I->SINR_effective Mapping - - if(mcs<10) { - sinr_eff = (p_qpsk[0]*pow(I,7) + p_qpsk[1]*pow(I,6) + p_qpsk[2]*pow(I,5) + p_qpsk[3]*pow(I,4) + p_qpsk[4]*pow(I,3) + p_qpsk[5]*pow(I,2) + p_qpsk[6]*I + p_qpsk[7]); - } else if(mcs>9 && mcs<17) { - sinr_eff = (p_qam16[0]*pow(I,7) + p_qam16[1]*pow(I,6) + p_qam16[2]*pow(I,5) + p_qam16[3]*pow(I,4) + p_qam16[4]*pow(I,3) + p_qam16[5]*pow(I,2) + p_qam16[6]*I + p_qam16[7]); - } else if(mcs>16 && mcs<23) { - sinr_eff = (p_qam64[0]*pow(I,7) + p_qam64[1]*pow(I,6) + p_qam64[2]*pow(I,5) + p_qam64[3]*pow(I,4) + p_qam64[4]*pow(I,3) + p_qam64[5]*pow(I,2) + p_qam64[6]*I + p_qam64[7]); - } - - //sinr_eff = sinr_eff + 10*log10(beta2_dlsch_MI[TM][mcs]); - LOG_D(OCM,"SINR_Eff = %e\n",sinr_eff); - - bler = interp(sinr_eff,&sinr_bler_map[mcs][0][0],&sinr_bler_map[mcs][1][0],table_length[mcs]); - - if (uniformrandom() < bler) { - LOG_N(OCM,"abstraction_decoding failed (mcs=%d, sinr_eff=%f, bler=%f)\n",mcs,sinr_eff,bler); - return(0); - } else { - LOG_I(OCM,"abstraction_decoding successful (mcs=%d, sinr_eff=%f, bler=%f)\n",mcs,sinr_eff,bler); - return(1); - } -} - -/* -uint32_t dlsch_decoding_emul(PHY_VARS_UE *phy_vars_ue, - uint8_t subframe, - PDSCH_t dlsch_id, - uint8_t eNB_id) -{ - - LTE_UE_DLSCH_t *dlsch_ue; - LTE_eNB_DLSCH_t *dlsch_eNB; - uint8_t harq_pid; - uint32_t eNB_id2; - uint32_t ue_id; -#ifdef DEBUG_DLSCH_DECODING - uint16_t i; -#endif - uint8_t CC_id = phy_vars_ue->CC_id; - - // may not be necessary for PMCH?? - for (eNB_id2=0; eNB_id2frame_parms.Nid_cell == phy_vars_ue->frame_parms.Nid_cell) - break; - } - - AssertFatal(eNB_id2!=NB_eNB_INST, - "FATAL : Could not find attached eNB for DLSCH emulation !!!!\n"); - - LOG_D(PHY,"[UE] dlsch_decoding_emul : subframe %d, eNB_id %d, dlsch_id %d\n",subframe,eNB_id2,dlsch_id); - - // printf("dlsch_eNB_ra->harq_processes[0] %p\n",PHY_vars_eNB_g[eNB_id]->dlsch_eNB_ra->harq_processes[0]); - - - switch (dlsch_id) { - case SI_PDSCH: // SI - dlsch_ue = phy_vars_ue->dlsch_SI[eNB_id]; - dlsch_eNB = RC.eNB[eNB_id2][CC_id]->dlsch_SI; - // printf("Doing SI: TBS %d\n",dlsch_ue->harq_processes[0]->TBS>>3); - memcpy(dlsch_ue->harq_processes[0]->b,dlsch_eNB->harq_processes[0]->b,dlsch_ue->harq_processes[0]->TBS>>3); -#ifdef DEBUG_DLSCH_DECODING - LOG_D(PHY,"SI Decoded\n"); - - for (i=0; iharq_processes[0]->TBS>>3; i++) - LOG_T(PHY,"%x.",dlsch_eNB->harq_processes[0]->b[i]); - - LOG_T(PHY,"\n"); -#endif - return(1); - break; - - case RA_PDSCH: // RA - dlsch_ue = phy_vars_ue->dlsch_ra[eNB_id]; - dlsch_eNB = RC.eNB[eNB_id2][CC_id]->dlsch_ra; - memcpy(dlsch_ue->harq_processes[0]->b,dlsch_eNB->harq_processes[0]->b,dlsch_ue->harq_processes[0]->TBS>>3); -#ifdef DEBUG_DLSCH_DECODING - LOG_D(PHY,"RA Decoded\n"); - - for (i=0; iharq_processes[0]->TBS>>3; i++) - LOG_T(PHY,"%x.",dlsch_eNB->harq_processes[0]->b[i]); - - LOG_T(PHY,"\n"); -#endif - return(1); - break; - - case PDSCH: // TB0 - dlsch_ue = phy_vars_ue->dlsch[phy_vars_ue->current_thread_id[subframe]][eNB_id][0]; - harq_pid = dlsch_ue->current_harq_pid; - ue_id= (uint32_t)find_ue((int16_t)phy_vars_ue->pdcch_vars[phy_vars_ue->current_thread_id[subframe]][(uint32_t)eNB_id]->crnti,RC.eNB[eNB_id2][CC_id]); - DevAssert( ue_id != (uint32_t)-1 ); - dlsch_eNB = RC.eNB[eNB_id2][CC_id]->dlsch[ue_id][0]; - -#ifdef DEBUG_DLSCH_DECODING - - for (i=0; iharq_processes[harq_pid]->TBS>>3; i++) - LOG_T(PHY,"%x.",dlsch_eNB->harq_processes[harq_pid]->b[i]); - - LOG_T(PHY,"\n current harq pid is %d ue id %d \n", harq_pid, ue_id); -#endif - - if (dlsch_abstraction_MIESM(phy_vars_ue->sinr_dB, - phy_vars_ue->transmission_mode[eNB_id], - dlsch_eNB->harq_processes[harq_pid]->rb_alloc, - dlsch_eNB->harq_processes[harq_pid]->mcs, - RC.eNB[eNB_id][CC_id]->mu_mimo_mode[ue_id].dl_pow_off) == 1) { - // reset HARQ - dlsch_ue->harq_processes[harq_pid]->status = SCH_IDLE; - dlsch_ue->harq_processes[harq_pid]->round = 0; - dlsch_ue->harq_ack[subframe].ack = 1; - dlsch_ue->harq_ack[subframe].harq_id = harq_pid; - dlsch_ue->harq_ack[subframe].send_harq_status = 1; - - if (dlsch_ue->harq_processes[harq_pid]->round == 0) - memcpy(dlsch_ue->harq_processes[harq_pid]->b, - dlsch_eNB->harq_processes[harq_pid]->b, - dlsch_ue->harq_processes[harq_pid]->TBS>>3); - - return(1); - } else { - // retransmission - dlsch_ue->harq_processes[harq_pid]->status = ACTIVE; - dlsch_ue->harq_processes[harq_pid]->round++; - dlsch_ue->harq_ack[subframe].ack = 0; - dlsch_ue->harq_ack[subframe].harq_id = harq_pid; - dlsch_ue->harq_ack[subframe].send_harq_status = 1; - dlsch_ue->last_iteration_cnt = 1+dlsch_ue->max_turbo_iterations; - return(1+dlsch_ue->max_turbo_iterations); - } - - break; - - case PDSCH1: { // TB1 - dlsch_ue = phy_vars_ue->dlsch[phy_vars_ue->current_thread_id[subframe]][eNB_id][1]; - harq_pid = dlsch_ue->current_harq_pid; - int8_t UE_id = find_ue( phy_vars_ue->pdcch_vars[phy_vars_ue->current_thread_id[subframe]][eNB_id]->crnti, RC.eNB[eNB_id2][CC_id] ); - - DevAssert( UE_id != -1 ); - dlsch_eNB = RC.eNB[eNB_id2][CC_id]->dlsch[UE_id][1]; - // reset HARQ - dlsch_ue->harq_processes[harq_pid]->status = SCH_IDLE; - dlsch_ue->harq_processes[harq_pid]->round = 0; - dlsch_ue->harq_ack[subframe].ack = 1; - dlsch_ue->harq_ack[subframe].harq_id = harq_pid; - dlsch_ue->harq_ack[subframe].send_harq_status = 1; - - if (dlsch_ue->harq_processes[harq_pid]->round == 0) - memcpy(dlsch_eNB->harq_processes[harq_pid]->b,dlsch_ue->harq_processes[harq_pid]->b,dlsch_ue->harq_processes[harq_pid]->TBS>>3); - - break; - } - - case PMCH: // PMCH - - dlsch_ue = phy_vars_ue->dlsch_MCH[eNB_id]; - dlsch_eNB = RC.eNB[eNB_id2][CC_id]->dlsch_MCH; - - LOG_D(PHY,"decoding pmch emul (size is %d, enb %d %d)\n", dlsch_ue->harq_processes[0]->TBS>>3, eNB_id, eNB_id2); -#ifdef DEBUG_DLSCH_DECODING - - for (i=0; iharq_processes[0]->TBS>>3; i++) - printf("%x.",dlsch_eNB->harq_processes[0]->b[i]); - - printf("\n"); -#endif - - - // if (dlsch_abstraction_MIESM(phy_vars_ue->sinr_dB, phy_vars_ue->transmission_mode[eNB_id], dlsch_eNB->rb_alloc, - // dlsch_eNB->harq_processes[0]->mcs,RC.eNB[eNB_id]->mu_mimo_mode[ue_id].dl_pow_off) == 1) { - - if (1) { - // reset HARQ - dlsch_ue->harq_processes[0]->status = SCH_IDLE; - dlsch_ue->harq_processes[0]->round = 0; - memcpy(dlsch_ue->harq_processes[0]->b, - dlsch_eNB->harq_processes[0]->b, - dlsch_ue->harq_processes[0]->TBS>>3); - dlsch_ue->last_iteration_cnt = 1; - return(1); - } else { - // retransmission - dlsch_ue->last_iteration_cnt = 1+dlsch_ue->max_turbo_iterations; - return(1+dlsch_ue->max_turbo_iterations); - } - - break; - - default: - dlsch_ue = phy_vars_ue->dlsch[phy_vars_ue->current_thread_id[subframe]][eNB_id][0]; - LOG_E(PHY,"dlsch_decoding_emul: FATAL, unknown DLSCH_id %d\n",dlsch_id); - dlsch_ue->last_iteration_cnt = 1+dlsch_ue->max_turbo_iterations; - return(1+dlsch_ue->max_turbo_iterations); - } - - LOG_E(PHY,"[FATAL] dlsch_decoding.c: Should never exit here ...\n"); - return(0); - }*/ -#endif - diff --git a/openair1/PHY/LTE_TRANSPORT/pbch.c b/openair1/PHY/LTE_TRANSPORT/pbch.c index 4fbaf3f111..d2632f5b3b 100644 --- a/openair1/PHY/LTE_TRANSPORT/pbch.c +++ b/openair1/PHY/LTE_TRANSPORT/pbch.c @@ -37,11 +37,6 @@ #include "PHY/extern.h" #include "PHY/sse_intrin.h" -#ifdef PHY_ABSTRACTION -#include "SIMULATION/TOOLS/defs.h" -#endif - - //#define DEBUG_PBCH 1 //#define DEBUG_PBCH_ENCODING //#define INTERFERENCE_MITIGATION 1 @@ -1016,44 +1011,3 @@ uint16_t rx_pbch(LTE_UE_COMMON *lte_ue_common_vars, } - -#ifdef PHY_ABSTRACTION -uint16_t rx_pbch_emul(PHY_VARS_UE *phy_vars_ue, - uint8_t eNB_id, - uint8_t pbch_phase) -{ - - double bler=0.0;//, x=0.0; - double sinr=0.0; - uint16_t nb_rb = phy_vars_ue->frame_parms.N_RB_DL; - int16_t f; - uint8_t CC_id=phy_vars_ue->CC_id; - int frame_rx = phy_vars_ue->proc.proc_rxtx[0].frame_rx; - - // compute effective sinr - // TODO: adapt this to varible bandwidth - for (f=(nb_rb*6-3*12); f<(nb_rb*6+3*12); f++) { - if (f!=0) //skip DC - sinr += pow(10, 0.1*(phy_vars_ue->sinr_dB[f])); - } - - sinr = 10*log10(sinr/(6*12)); - - bler = pbch_bler(sinr); - - LOG_D(PHY,"EMUL UE rx_pbch_emul: eNB_id %d, pbch_phase %d, sinr %f dB, bler %f \n", - eNB_id, - pbch_phase, - sinr, - bler); - - if (pbch_phase == (frame_rx % 4)) { - if (uniformrandom() >= bler) { - memcpy(phy_vars_ue->pbch_vars[eNB_id]->decoded_output,RC.eNB[eNB_id][CC_id]->pbch_pdu,PBCH_PDU_SIZE); - return(RC.eNB[eNB_id][CC_id]->frame_parms.nb_antenna_ports_eNB); - } else - return(-1); - } else - return(-1); -} -#endif diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 8a0e160f23..748d25fcbb 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -2149,9 +2149,13 @@ void rx_prach(PHY_VARS_eNB *phy_vars_eNB,RU_t *ru, uint16_t *max_preamble, uint16_t *max_preamble_energy, uint16_t *max_preamble_delay, +#ifdef Rel14 uint16_t Nf, uint8_t tdd_mapindex, - uint8_t br_flag); - + uint8_t br_flag +#else + uint16_t Nf, uint8_t tdd_mapindex +#endif + ); /*! \brief Helper for MAC, returns number of available PRACH in TDD for a particular configuration index @param frame_parms Pointer to LTE_DL_FRAME_PARMS structure diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c index 71c36f7c3c..87209e190b 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c @@ -953,77 +953,3 @@ uint32_t ulsch_encoding(uint8_t *a, return(0); } - -#ifdef PHY_ABSTRACTION -#ifdef OPENAIR2 -#include "LAYER2/MAC/extern.h" -#include "LAYER2/MAC/defs.h" -#endif -int ulsch_encoding_emul(uint8_t *ulsch_buffer, - PHY_VARS_UE *ue, - uint8_t eNB_id, - uint8_t subframe_rx, - uint8_t harq_pid, - uint8_t control_only_flag) -{ - - LTE_UE_ULSCH_t *ulsch = ue->ulsch[eNB_id]; - LTE_UE_DLSCH_t **dlsch = ue->dlsch[0][eNB_id]; - PHY_MEASUREMENTS *meas = &ue->measurements; - uint8_t tmode = ue->transmission_mode[eNB_id]; - uint16_t rnti=ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->crnti; - LOG_D(PHY,"EMUL UE ulsch_encoding for eNB %d,mod_id %d, harq_pid %d rnti %x, ACK(%d,%d) \n", - eNB_id,ue->Mod_id, harq_pid, rnti,ulsch->o_ACK[0],ulsch->o_ACK[1]); - - if (ulsch->O>0) { - /* - if(flag_LA==1) - sinr_eff = sinr_eff_cqi_calc(ue, eNB_id); - else - sinr_eff = meas->wideband_cqi_avg[eNB_id]; - */ - - fill_CQI(ulsch,meas,eNB_id,harq_pid,ue->frame_parms.N_RB_DL,rnti,tmode,ue->sinr_eff); - //LOG_D(PHY,"UE CQI\n"); - // print_CQI(ulsch->o,ulsch->uci_format,eNB_id); - - // save PUSCH pmi for later (transmission modes 4,5,6) - // printf("ulsch: saving pmi for DL %x\n",pmi2hex_2Ar1(((wideband_cqi_rank1_2A_5MHz *)ulsch->o)->pmi)); - // if (ulsch->uci_format != HLC_subband_cqi_mcs_CBA) - dlsch[0]->harq_processes[harq_pid]->pmi_alloc = ((wideband_cqi_rank1_2A_5MHz *)ulsch->o)->pmi; - } - - memcpy(ue->ulsch[eNB_id]->harq_processes[harq_pid]->b, - ulsch_buffer, - ue->ulsch[eNB_id]->harq_processes[harq_pid]->TBS>>3); - - - //memcpy(&UE_transport_info[ue->Mod_id].transport_blocks[UE_transport_info_TB_index[ue->Mod_id]], - memcpy(&UE_transport_info[ue->Mod_id][ue->CC_id].transport_blocks, - ulsch_buffer, - ue->ulsch[eNB_id]->harq_processes[harq_pid]->TBS>>3); - //UE_transport_info_TB_index[ue->Mod_id]+=ue->ulsch[eNB_id]->harq_processes[harq_pid]->TBS>>3; - // navid: currently more than one eNB is not supported in the code - UE_transport_info[ue->Mod_id][ue->CC_id].num_eNB = 1; - UE_transport_info[ue->Mod_id][ue->CC_id].rnti[0] = ue->pdcch_vars[ue->current_thread_id[subframe_rx]][0]->crnti; - UE_transport_info[ue->Mod_id][ue->CC_id].eNB_id[0] = eNB_id; - UE_transport_info[ue->Mod_id][ue->CC_id].harq_pid[0] = harq_pid; - UE_transport_info[ue->Mod_id][ue->CC_id].tbs[0] = ue->ulsch[eNB_id]->harq_processes[harq_pid]->TBS>>3 ; - // printf("\nue->Mod_id%d\n",ue->Mod_id); - - UE_transport_info[ue->Mod_id][ue->CC_id].cntl.pusch_flag = 1; - //UE_transport_info[ue->Mod_id].cntl.pusch_uci = *(uint32_t *)ulsch->o; - memcpy(UE_transport_info[ue->Mod_id][ue->CC_id].cntl.pusch_uci, - ulsch->o, - MAX_CQI_BYTES); - // printf("[UE]cqi is %d \n", ((HLC_subband_cqi_rank1_2A_5MHz *)ulsch->o)->cqi1); - - UE_transport_info[ue->Mod_id][ue->CC_id].cntl.length_uci = ulsch->O; - UE_transport_info[ue->Mod_id][ue->CC_id].cntl.uci_format = ulsch->uci_format; - UE_transport_info[ue->Mod_id][ue->CC_id].cntl.pusch_ri = (ulsch->o_RI[0]&1)+((ulsch->o_RI[1]&1)<<1); - UE_transport_info[ue->Mod_id][ue->CC_id].cntl.pusch_ack = (ulsch->o_ACK[0]&1) + ((ulsch->o_ACK[1]&1)<<1); - //printf("ack is %d %d %d\n",UE_transport_info[ue->Mod_id].cntl.pusch_ack, (ulsch->o_ACK[1]&1)<<1, ulsch->o_ACK[0]&1); - return(0); - -} -#endif diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index dcf94c4826..bf7d2603f7 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -44,11 +44,6 @@ #include "PHY_INTERFACE/extern.h" #endif -#ifdef PHY_ABSTRACTION -#include "UTIL/OCG/OCG.h" -#include "UTIL/OCG/OCG_extern.h" -#endif - #include "UTIL/LOG/vcd_signal_dumper.h" //#define DEBUG_ULSCH_DECODING @@ -1582,450 +1577,3 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, return(ret); } -#ifdef PHY_ABSTRACTION - -#ifdef PHY_ABSTRACTION_UL -int ulsch_abstraction(double* sinr_dB, uint8_t TM, uint8_t mcs,uint16_t nrb, uint16_t frb) -{ - - int index,ii; - double sinr_eff = 0; - int rb_count = 0; - int offset; - double bler = 0; - TM = TM-1; - sinr_eff = sinr_dB[frb]; //the single sinr_eff value we calculated with MMSE FDE formula in init_snr_up function - - - sinr_eff *= 10; - sinr_eff = floor(sinr_eff); - sinr_eff /= 10; - - LOG_D(PHY,"[ABSTRACTION] sinr_eff after rounding = %f\n",sinr_eff); - - for (index = 0; index < 16; index++) { - if(index == 0) { - if (sinr_eff < sinr_bler_map_up[mcs][0][index]) { - bler = 1; - break; - } - } - - if (sinr_eff == sinr_bler_map_up[mcs][0][index]) { - bler = sinr_bler_map_up[mcs][1][index]; - } - } - - if (uniformrandom() < bler) { - LOG_I(OCM,"abstraction_decoding failed (mcs=%d, sinr_eff=%f, bler=%f)\n",mcs,sinr_eff,bler); - return(0); - } else { - LOG_I(OCM,"abstraction_decoding successful (mcs=%d, sinr_eff=%f, bler=%f)\n",mcs,sinr_eff,bler); - return(1); - } -} - - - - - - - -int ulsch_abstraction_MIESM(double* sinr_dB,uint8_t TM, uint8_t mcs,uint16_t nrb, uint16_t frb) -{ - int index; - double sinr_eff = 0; - double sinr_db1 = 0; - double sinr_db2 = 0; - double SI=0; - double RBIR=0; - int rb_count = 0; - int offset, M=0; - double bler = 0; - int start,middle,end; - TM = TM-1; - - for (offset = frb; offset <= (frb + nrb -1); offset++) { - - rb_count++; - - //we need to do the table lookups here for the mutual information corresponding to the certain sinr_dB. - - sinr_db1 = sinr_dB[offset*2]; - sinr_db2 = sinr_dB[offset*2+1]; - - printf("sinr_db1=%f\n,sinr_db2=%f\n",sinr_db1,sinr_db2); - - //rounding up for the table lookup - sinr_db1 *= 10; - sinr_db2 *= 10; - - sinr_db1 = floor(sinr_db1); - sinr_db2 = floor(sinr_db2); - - if ((int)sinr_db1%2) { - sinr_db1 += 1; - } - - if ((int)sinr_db2%2) { - sinr_db2 += 1; - } - - sinr_db1 /= 10; - sinr_db2 /= 10; - - if(mcs<10) { - //for sinr_db1 - for (index = 0; index < 162; index++) { - if (sinr_db1 < MI_map_4qam[0][0]) { - SI += (MI_map_4qam[1][0]/beta1_dlsch_MI[TM][mcs]); - M +=2; - break; - } - - if (sinr_db1 > MI_map_4qam[0][161]) { - SI += (MI_map_4qam[1][161]/beta1_dlsch_MI[TM][mcs]); - M +=2; - break; - } - - if (sinr_db1 == MI_map_4qam[0][index]) { - SI += (MI_map_4qam[1][index]/beta1_dlsch_MI[TM][mcs]); - M +=2; - break; - } - } - - //for sinr_db2 - for (index = 0; index < 162; index++) { - if (sinr_db2 < MI_map_4qam[0][0]) { - SI += (MI_map_4qam[1][0]/beta1_dlsch_MI[TM][mcs]); - M +=2; - break; - } - - if (sinr_db2 > MI_map_4qam[0][161]) { - SI += (MI_map_4qam[1][161]/beta1_dlsch_MI[TM][mcs]); - M +=2; - break; - } - - if (sinr_db2 == MI_map_4qam[0][index]) { - SI += (MI_map_4qam[1][index]/beta1_dlsch_MI[TM][mcs]); - M +=2; - break; - } - } - - } else if(mcs>9 && mcs<17) { - //for sinr_db1 - for (index = 0; index < 197; index++) { - if (sinr_db1 < MI_map_16qam[0][0]) { - SI += (MI_map_16qam[1][0]/beta1_dlsch_MI[TM][mcs]); - M +=4; - break; - } - - if (sinr_db1 > MI_map_16qam[0][196]) { - SI += (MI_map_16qam[1][196]/beta1_dlsch_MI[TM][mcs]); - M +=4; - break; - } - - if (sinr_db1 == MI_map_16qam[0][index]) { - SI += (MI_map_16qam[1][index]/beta1_dlsch_MI[TM][mcs]); - M +=4; - break; - } - } - - //for sinr_db2 - for (index = 0; index < 197; index++) { - if (sinr_db2 < MI_map_16qam[0][0]) { - SI += (MI_map_16qam[1][0]/beta1_dlsch_MI[TM][mcs]); - M +=4; - break; - } - - if (sinr_db2 > MI_map_16qam[0][196]) { - SI += (MI_map_16qam[1][196]/beta1_dlsch_MI[TM][mcs]); - M +=4; - break; - } - - if (sinr_db2 == MI_map_16qam[0][index]) { - SI += (MI_map_16qam[1][index]/beta1_dlsch_MI[TM][mcs]); - M +=4; - break; - } - } - - } else if(mcs>16 && mcs<22) { - //for sinr_db1 - for (index = 0; index < 227; index++) { - if (sinr_db1 < MI_map_64qam[0][0]) { - SI += (MI_map_64qam[1][0]/beta1_dlsch_MI[TM][mcs]); - M +=6; - break; - } - - if (sinr_db1 > MI_map_64qam[0][226]) { - SI += (MI_map_64qam[1][226]/beta1_dlsch_MI[TM][mcs]); - M +=6; - break; - } - - if (sinr_db1 == MI_map_64qam[0][index]) { - SI += (MI_map_64qam[1][index]/beta1_dlsch_MI[TM][mcs]); - M +=6; - break; - } - } - - //for sinr_db2 - for (index = 0; index < 227; index++) { - if (sinr_db2 < MI_map_64qam[0][0]) { - SI += (MI_map_64qam[1][0]/beta1_dlsch_MI[TM][mcs]); - M +=6; - break; - } - - if (sinr_db2 > MI_map_64qam[0][226]) { - SI += (MI_map_64qam[1][226]/beta1_dlsch_MI[TM][mcs]); - M +=6; - break; - } - - if (sinr_db2 == MI_map_64qam[0][index]) { - SI += (MI_map_64qam[1][index]/beta1_dlsch_MI[TM][mcs]); - M +=6; - break; - } - } - } - } - - // } - - RBIR = SI/M; - - //Now RBIR->SINR_effective Mapping - //binary search method is performed here - if(mcs<10) { - start = 0; - end = 161; - middle = end/2; - - if (RBIR <= MI_map_4qam[2][start]) { - sinr_eff = MI_map_4qam[0][start]; - } else { - if (RBIR >= MI_map_4qam[2][end]) - sinr_eff = MI_map_4qam[0][end]; - else { - //while((end-start > 1) && (RBIR >= MI_map_4qam[2])) - if (RBIR < MI_map_4qam[2][middle]) { - end = middle; - middle = end/2; - } else { - start = middle; - middle = (end-middle)/2; - } - } - - for (; end>start; end--) { - if ((RBIR < MI_map_4qam[2][end]) && (RBIR > MI_map_4qam[2][end-2])) { - sinr_eff = MI_map_4qam[0][end-1]; - break; - } - } - } - - sinr_eff = sinr_eff * beta2_dlsch_MI[TM][mcs]; - } - - - - else if (mcs>9 && mcs<17) { - - start = 0; - end = 196; - middle = end/2; - - if (RBIR <= MI_map_16qam[2][start]) { - sinr_eff = MI_map_16qam[0][start]; - } else { - if (RBIR >= MI_map_16qam[2][end]) - sinr_eff = MI_map_16qam[0][end]; - else { - //while((end-start > 1) && (RBIR >= MI_map_4qam[2])) - if (RBIR < MI_map_16qam[2][middle]) { - end = middle; - middle = end/2; - } else { - start = middle; - middle = (end-middle)/2; - } - } - - for (; end>start; end--) { - if ((RBIR < MI_map_16qam[2][end]) && (RBIR > MI_map_16qam[2][end-2])) { - sinr_eff = MI_map_16qam[0][end-1]; - break; - } - } - } - - sinr_eff = sinr_eff * beta2_dlsch_MI[TM][mcs]; - } else if (mcs>16) { - start = 0; - end = 226; - middle = end/2; - - if (RBIR <= MI_map_64qam[2][start]) { - sinr_eff = MI_map_64qam[0][start]; - } else { - if (RBIR >= MI_map_64qam[2][end]) - sinr_eff = MI_map_64qam[0][end]; - else { - //while((end-start > 1) && (RBIR >= MI_map_4qam[2])) - if (RBIR < MI_map_64qam[2][middle]) { - end = middle; - middle = end/2; - } else { - start = middle; - middle = (end-middle)/2; - } - } - - for (; end>start; end--) { - if ((RBIR < MI_map_64qam[2][end]) && (RBIR > MI_map_64qam[2][end-2])) { - sinr_eff = MI_map_64qam[0][end-1]; - break; - } - } - } - - sinr_eff = sinr_eff * beta2_dlsch_MI[TM][mcs]; - } - - printf("SINR_Eff = %e\n",sinr_eff); - - sinr_eff *= 10; - sinr_eff = floor(sinr_eff); - // if ((int)sinr_eff%2) { - // sinr_eff += 1; - // } - sinr_eff /= 10; - printf("sinr_eff after rounding = %f\n",sinr_eff); - - for (index = 0; index < 16; index++) { - if(index == 0) { - if (sinr_eff < sinr_bler_map_up[mcs][0][index]) { - bler = 1; - break; - } - } - - if (sinr_eff == sinr_bler_map_up[mcs][0][index]) { - bler = sinr_bler_map_up[mcs][1][index]; - } - } - - if (uniformrandom() < bler) { - printf("abstraction_decoding failed (mcs=%d, sinr_eff=%f, bler=%f)\n",mcs,sinr_eff,bler); - return(0); - } else { - printf("abstraction_decoding successful (mcs=%d, sinr_eff=%f, bler=%f)\n",mcs,sinr_eff,bler); - return(1); - } -} - -#endif - -uint32_t ulsch_decoding_emul(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, - uint8_t UE_index, - uint16_t *crnti) -{ - - uint8_t UE_id; - uint16_t rnti; - int subframe = proc->subframe_rx; - uint8_t harq_pid; - uint8_t CC_id = eNB->CC_id; - - harq_pid = subframe2harq_pid(&eNB->frame_parms,proc->frame_rx,subframe); - - rnti = eNB->ulsch[UE_index]->rnti; -#ifdef DEBUG_PHY - LOG_D(PHY,"[eNB %d] ulsch_decoding_emul : subframe %d UE_index %d harq_pid %d rnti %x\n",eNB->Mod_id,subframe,UE_index,harq_pid,rnti); -#endif - - for (UE_id=0; UE_idpdcch_vars[PHY_vars_UE_g[UE_id][CC_id]->current_thread_id[subframe]][0]->crnti) - break; - - } - - if (UE_id==NB_UE_INST) { - LOG_W(PHY,"[eNB %d] ulsch_decoding_emul: FATAL, didn't find UE with rnti %x (UE index %d)\n", - eNB->Mod_id, rnti, UE_index); - return(1+eNB->ulsch[UE_id]->max_turbo_iterations); - } else { - LOG_D(PHY,"[eNB %d] Found UE with rnti %x => UE_id %d\n",eNB->Mod_id, rnti, UE_id); - } - - if (PHY_vars_UE_g[UE_id][CC_id]->ulsch[0]->harq_processes[harq_pid]->status == CBA_ACTIVE) { - *crnti = rnti; - PHY_vars_UE_g[UE_id][CC_id]->ulsch[0]->harq_processes[harq_pid]->status=IDLE; - } else - *crnti = 0x0; - - if (1) { - LOG_D(PHY,"ulsch_decoding_emul abstraction successful\n"); - - memcpy(eNB->ulsch[UE_index]->harq_processes[harq_pid]->b, - PHY_vars_UE_g[UE_id][CC_id]->ulsch[0]->harq_processes[harq_pid]->b, - eNB->ulsch[UE_index]->harq_processes[harq_pid]->TBS>>3); - - // get local ue's ack - if ((UE_index >= oai_emulation.info.first_ue_local) ||(UE_index <(oai_emulation.info.first_ue_local+oai_emulation.info.nb_ue_local))) { - get_ack(&eNB->frame_parms, - PHY_vars_UE_g[UE_id][CC_id]->dlsch[0][0][0]->harq_ack, - proc->subframe_tx, - proc->subframe_rx, - eNB->ulsch[UE_index]->harq_processes[harq_pid]->o_ACK,0); - } else { // get remote UEs' ack - eNB->ulsch[UE_index]->harq_processes[harq_pid]->o_ACK[0] = PHY_vars_UE_g[UE_id][CC_id]->ulsch[0]->o_ACK[0]; - eNB->ulsch[UE_index]->harq_processes[harq_pid]->o_ACK[1] = PHY_vars_UE_g[UE_id][CC_id]->ulsch[0]->o_ACK[1]; - } - - // Do abstraction of PUSCH feedback -#ifdef DEBUG_PHY - LOG_D(PHY,"[eNB %d][EMUL] ue index %d UE_id %d: subframe %d : o_ACK (%d %d), cqi (val %d, len %d)\n", - eNB->Mod_id,UE_index, UE_id, subframe,eNB->ulsch[UE_index]->harq_processes[harq_pid]->o_ACK[0], - eNB->ulsch[UE_index]->harq_processes[harq_pid]->o_ACK[1], - ((HLC_subband_cqi_rank1_2A_5MHz *)PHY_vars_UE_g[UE_id][CC_id]->ulsch[0]->o)->cqi1, - PHY_vars_UE_g[UE_id][CC_id]->ulsch[0]->O); -#endif - - eNB->ulsch[UE_index]->harq_processes[harq_pid]->Or1 = PHY_vars_UE_g[UE_id][CC_id]->ulsch[0]->O; - eNB->ulsch[UE_index]->harq_processes[harq_pid]->Or2 = PHY_vars_UE_g[UE_id][CC_id]->ulsch[0]->O; - - eNB->ulsch[UE_index]->harq_processes[harq_pid]->uci_format = PHY_vars_UE_g[UE_id][CC_id]->ulsch[0]->uci_format; - memcpy(eNB->ulsch[UE_index]->harq_processes[harq_pid]->o,PHY_vars_UE_g[UE_id][CC_id]->ulsch[0]->o,MAX_CQI_BYTES); - memcpy(eNB->ulsch[UE_index]->harq_processes[harq_pid]->o_RI,PHY_vars_UE_g[UE_id][CC_id]->ulsch[0]->o_RI,2); - - eNB->ulsch[UE_index]->harq_processes[harq_pid]->cqi_crc_status = 1; - - return(1); - } else { - LOG_W(PHY,"[eNB %d] ulsch_decoding_emul abstraction failed for UE %d\n",eNB->Mod_id,UE_index); - - eNB->ulsch[UE_index]->harq_processes[harq_pid]->cqi_crc_status = 0; - - // retransmission - return(1+eNB->ulsch[UE_index]->max_turbo_iterations); - } - -} -#endif diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c index 795ed5896b..93c1af8d91 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c @@ -1360,7 +1360,6 @@ void rx_ulsch_emul(PHY_VARS_eNB *eNB, subframe,harq_pid,eNB->ulsch[UE_id]->harq_processes[harq_pid]->nb_rb, eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS,eNB->ulsch[UE_id]->harq_processes[harq_pid]->Qm, eNB->ulsch[UE_id]->harq_processes[harq_pid]->Nsymb_pusch); - //#ifndef OAI_EMU write_output("/tmp/ulsch_d.m","ulsch_dseq",&eNB->ulsch[UE_id]->harq_processes[harq_pid]->d[0][96], eNB->ulsch[UE_id]->harq_processes[harq_pid]->Kplus*3,1,0); if (eNB->common_vars.rxdata) write_output("/tmp/rxsig0.m","rxs0", &eNB->common_vars.rxdata[0][0],eNB->frame_parms.samples_per_tti*10,1,1); diff --git a/openair1/PHY/TOOLS/defs.h b/openair1/PHY/TOOLS/defs.h index 5e215bfef1..b92c2a4236 100644 --- a/openair1/PHY/TOOLS/defs.h +++ b/openair1/PHY/TOOLS/defs.h @@ -34,13 +34,10 @@ #include "PHY/sse_intrin.h" -//defined in rtai_math.h -#ifndef _RTAI_MATH_H struct complex { double x; double y; }; -#endif struct complexf { float r; @@ -359,17 +356,6 @@ int16_t dB_fixed_times10(uint32_t x); int32_t phy_phase_compensation_top (uint32_t pilot_type, uint32_t initial_pilot, uint32_t last_pilot, int32_t ignore_prefix); -/*!\fn void phy_phase_compensation (int16_t *ref_sch, int16_t *tgt_sch, int16_t *out_sym, int32_t ignore_prefix, int32_t aa, struct complex16 *perror_out); -This function is used by the EMOS to compensate the phase rotation of the RF. It has been designed for symbols of type CHSCH or SCH, but cannot be used for the data channels. -@param ref_sch reference symbol -@param tgt_sch target symbol -@param out_sym output of the operation -@param ignore_prefix set to 1 if cyclic prefix has not been removed (by the hardware) -@param aa antenna index -@param perror_out phase error (output parameter) -*/ -void phy_phase_compensation (int16_t *ref_sch, int16_t *tgt_sch, int16_t *out_sym, int32_t ignore_prefix, int32_t aa, struct complex16 *perror_out ); - int32_t dot_product(int16_t *x, int16_t *y, uint32_t N, //must be a multiple of 8 diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h index e16409a6a1..2ff778907d 100644 --- a/openair1/PHY/impl_defs_lte.h +++ b/openair1/PHY/impl_defs_lte.h @@ -153,7 +153,9 @@ typedef struct { /// prach_Config_enabled=1 means enabled. \vr{[0..1]} uint8_t prach_Config_enabled; /// PRACH Configuration Information +#ifdef Rel14 PRACH_eMTC_CONFIG_INFO prach_ConfigInfo; +#endif } PRACH_eMTC_CONFIG_COMMON; /// Enumeration for parameter \f$N_\text{ANRep}\f$ \ref PUCCH_CONFIG_DEDICATED::repetitionFactor. diff --git a/openair1/PHY/impl_defs_top.h b/openair1/PHY/impl_defs_top.h index 6fe6b46a38..60d3fec5f4 100644 --- a/openair1/PHY/impl_defs_top.h +++ b/openair1/PHY/impl_defs_top.h @@ -125,10 +125,6 @@ #define FIRST_CARRIER_OFFSET (HALF_NUMBER_OF_USEFUL_CARRIERS+NUMBER_OF_ZERO_CARRIERS) #define NUMBER_OF_OFDM_SYMBOLS_PER_SLOT (NUMBER_OF_SYMBOLS_PER_FRAME/LTE_SLOTS_PER_FRAME) -#ifdef EMOS -#define EMOS_SCH_INDEX 1 -#endif //EMOS - #define EXTENSION_TYPE (PHY_config->PHY_framing.Extension_type) #define NUMBER_OF_OFDM_CARRIERS_BYTES NUMBER_OF_OFDM_CARRIERS*4 diff --git a/openair1/SCHED/defs.h b/openair1/SCHED/defs.h index e29bbf7aad..003929a5e6 100644 --- a/openair1/SCHED/defs.h +++ b/openair1/SCHED/defs.h @@ -208,11 +208,12 @@ void phy_procedures_eNB_S_RX(PHY_VARS_eNB *phy_vars_eNB,eNB_rxtx_proc_t *proc,re @param phy_vars_eNB Pointer to eNB variables on which to act @param br_flag indicator for eMTC PRACH */ -void prach_procedures(PHY_VARS_eNB *eNB, #ifdef Rel14 - int br_flag +void prach_procedures(PHY_VARS_eNB *eNB, + int br_flag); +#else +void prach_procedures(PHY_VARS_eNB *eNB); #endif - ); /*! \brief Function to compute subframe type as a function of Frame type and TDD Configuration (implements Table 4.2.2 from 36.211, p.11 from version 8.6) and subframe index. @param frame_parms Pointer to DL frame parameter descriptor @param subframe Subframe index diff --git a/openair1/SCHED/extern.h b/openair1/SCHED/extern.h index 98d4703be8..b1e8df67ef 100644 --- a/openair1/SCHED/extern.h +++ b/openair1/SCHED/extern.h @@ -37,11 +37,5 @@ extern int synch_wait_cnt; extern int16_t hundred_times_delta_TF[100]; extern uint16_t hundred_times_log10_NPRB[100]; -/* -#ifdef EMOS -extern fifo_dump_emos_UE emos_dump_UE; -extern fifo_dump_emos_eNB emos_dump_eNB; -#endif -*/ #endif /*__SCHED_EXTERN_H__ */ diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c index 8aff92d485..70c4ea03fc 100644 --- a/openair1/SCHED/fapi_l1.c +++ b/openair1/SCHED/fapi_l1.c @@ -51,6 +51,7 @@ void handle_nfapi_dci_dl_pdu(PHY_VARS_eNB *eNB, fill_dci_and_dlsch(eNB,proc,&pdcch_vars->dci_alloc[pdcch_vars->num_dci],pdu); } +#ifdef Rel14 void handle_nfapi_mpdcch_pdu(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, nfapi_dl_config_request_pdu_t *dl_config_pdu) @@ -64,6 +65,7 @@ void handle_nfapi_mpdcch_pdu(PHY_VARS_eNB *eNB, // copy dci configuration into eNB structure fill_mdci_and_dlsch(eNB,proc,&mpdcch_vars->mdci_alloc[mpdcch_vars->num_dci],pdu); } +#endif void handle_nfapi_hi_dci0_dci_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, nfapi_hi_dci0_request_pdu_t *hi_dci0_config_pdu) @@ -679,10 +681,12 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) case NFAPI_DL_CONFIG_EPDCCH_DL_PDU_TYPE: // handle_nfapi_epdcch_pdu(eNB,dl_config_pdu); break; +#ifdef Rel14 case NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE: handle_nfapi_mpdcch_pdu(eNB,proc,dl_config_pdu); eNB->mpdcch_vars[subframe&1].num_dci++; break; +#endif } } diff --git a/openair1/SCHED/phy_mac_stub.c b/openair1/SCHED/phy_mac_stub.c index 15c6fa7557..664791f7c4 100644 --- a/openair1/SCHED/phy_mac_stub.c +++ b/openair1/SCHED/phy_mac_stub.c @@ -36,10 +36,6 @@ #include "SCHED/extern.h" #include "LAYER2/MAC/extern.h" -#ifdef EMOS -#include "SCHED/phy_procedures_emos.h" -#endif - /* SYRTEM */ uint8_t dci_ndi_toggle_even[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t dci_ndi_toggle_odd[8] = {0, 0, 0, 0, 0, 0, 0, 0}; @@ -733,181 +729,3 @@ void fill_dci(DCI_PDU *DCI_pdu,PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) } */ } - -void fill_dci_emos(DCI_PDU *DCI_pdu, uint8_t subframe, PHY_VARS_eNB *eNB) -{ - - //uint8_t cooperation_flag = eNB->cooperation_flag; - uint8_t transmission_mode = eNB->transmission_mode[0]; - - //uint32_t rballoc = 0x00F0; - //uint32_t rballoc2 = 0x000F; - /* - uint32_t rand = taus(); - if ((subframe==8) || (subframe==9) || (subframe==0)) - rand = (rand%5)+5; - else - rand = (rand%4)+5; - */ - - DCI_pdu->Num_dci = 0; - - switch (subframe) { - case 5: - DCI_pdu->Num_dci = 1; - - if (transmission_mode<3) { - //user 1 - DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1_5MHz_TDD_t; - DCI_pdu->dci_alloc[0].L = 2; - DCI_pdu->dci_alloc[0].rnti = 0x1235; - DCI_pdu->dci_alloc[0].format = format1; - DCI_pdu->dci_alloc[0].ra_flag = 0; - DCI_pdu->dci_alloc[0].search_space = DCI_UE_SPACE; - - DLSCH_alloc_pdu.rballoc = eNB->ue_dl_rb_alloc; - DLSCH_alloc_pdu.TPC = 0; - DLSCH_alloc_pdu.dai = 0; - DLSCH_alloc_pdu.harq_pid = 1; - DLSCH_alloc_pdu.mcs = eNB->target_ue_dl_mcs; - DLSCH_alloc_pdu.ndi = 1; - DLSCH_alloc_pdu.rv = 0; - memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&DLSCH_alloc_pdu,sizeof(DCI1_5MHz_TDD_t)); - - /* - //user2 - DCI_pdu->dci_alloc[1].dci_length = sizeof_DCI1_5MHz_TDD_t; - DCI_pdu->dci_alloc[1].L = 2; - DCI_pdu->dci_alloc[1].rnti = 0x1236; - DCI_pdu->dci_alloc[1].format = format1; - DCI_pdu->dci_alloc[1].ra_flag = 0; - DCI_pdu->dci_alloc[1].search_space = DCI_UE_SPACE; - - DLSCH_alloc_pdu.rballoc = rballoc2; - DLSCH_alloc_pdu.TPC = 0; - DLSCH_alloc_pdu.dai = 0; - DLSCH_alloc_pdu.harq_pid = 1; - DLSCH_alloc_pdu.mcs = eNB->target_ue_dl_mcs; - DLSCH_alloc_pdu.ndi = 1; - DLSCH_alloc_pdu.rv = 0; - memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&DLSCH_alloc_pdu,sizeof(DCI1_5MHz_TDD_t)); - */ - } else if (transmission_mode==5) { - DCI_pdu->Num_dci = 2; - // user 1 - DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1E_5MHz_2A_M10PRB_TDD_t; - DCI_pdu->dci_alloc[0].L = 2; - DCI_pdu->dci_alloc[0].rnti = 0x1235; - DCI_pdu->dci_alloc[0].format = format1E_2A_M10PRB; - DCI_pdu->dci_alloc[0].ra_flag = 0; - DCI_pdu->dci_alloc[0].search_space = DCI_UE_SPACE; - - DLSCH_alloc_pdu1E.tpmi = 5; //5=use feedback - DLSCH_alloc_pdu1E.rv = 0; - DLSCH_alloc_pdu1E.ndi = 1; - DLSCH_alloc_pdu1E.mcs = eNB->target_ue_dl_mcs; - DLSCH_alloc_pdu1E.harq_pid = 1; - DLSCH_alloc_pdu1E.dai = 0; - DLSCH_alloc_pdu1E.TPC = 0; - DLSCH_alloc_pdu1E.rballoc = eNB->ue_dl_rb_alloc; - DLSCH_alloc_pdu1E.rah = 0; - DLSCH_alloc_pdu1E.dl_power_off = 0; //0=second user present - memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&DLSCH_alloc_pdu1E,sizeof(DCI1E_5MHz_2A_M10PRB_TDD_t)); - - //user 2 - DCI_pdu->dci_alloc[1].dci_length = sizeof_DCI1E_5MHz_2A_M10PRB_TDD_t; - DCI_pdu->dci_alloc[1].L = 2; - DCI_pdu->dci_alloc[1].rnti = 0x1236; - DCI_pdu->dci_alloc[1].format = format1E_2A_M10PRB; - DCI_pdu->dci_alloc[1].ra_flag = 0; - DCI_pdu->dci_alloc[1].search_space = DCI_UE_SPACE; - - memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&DLSCH_alloc_pdu1E,sizeof(DCI1E_5MHz_2A_M10PRB_TDD_t)); - - // set the precoder of the second UE orthogonal to the first - eNB->UE_stats[1].DL_pmi_single = (eNB->UE_stats[0].DL_pmi_single ^ 0x1555); - } - - break; - - case 7: - DCI_pdu->Num_dci = 1; - DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1A_5MHz_TDD_1_6_t; - DCI_pdu->dci_alloc[0].L = 2; - DCI_pdu->dci_alloc[0].rnti = 0xbeef; - DCI_pdu->dci_alloc[0].format = format1A; - DCI_pdu->dci_alloc[0].ra_flag = 1; - DCI_pdu->dci_alloc[0].search_space = DCI_COMMON_SPACE; - - RA_alloc_pdu.type = 1; - RA_alloc_pdu.vrb_type = 0; - RA_alloc_pdu.rballoc = computeRIV(25,12,3); - RA_alloc_pdu.ndi = 1; - RA_alloc_pdu.rv = 1; - RA_alloc_pdu.mcs = 4; - RA_alloc_pdu.harq_pid = 0; - RA_alloc_pdu.TPC = 1; - - memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],&RA_alloc_pdu,sizeof(DCI1A_5MHz_TDD_1_6_t)); - break; - - case 9: - DCI_pdu->Num_dci = 1; - - //user 1 - DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI0_5MHz_TDD_1_6_t ; - DCI_pdu->dci_alloc[0].L = 2; - DCI_pdu->dci_alloc[0].rnti = 0x1235; - DCI_pdu->dci_alloc[0].format = format0; - DCI_pdu->dci_alloc[0].ra_flag = 0; - DCI_pdu->dci_alloc[0].search_space = DCI_UE_SPACE; - - UL_alloc_pdu.type = 0; - UL_alloc_pdu.hopping = 0; - UL_alloc_pdu.rballoc = computeRIV(25,0,eNB->ue_ul_nb_rb); - UL_alloc_pdu.mcs = eNB->target_ue_ul_mcs; - UL_alloc_pdu.ndi = 1; - UL_alloc_pdu.TPC = 0; - UL_alloc_pdu.cshift = 0; - UL_alloc_pdu.dai = 0; - UL_alloc_pdu.cqi_req = 1; - memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&UL_alloc_pdu,sizeof(DCI0_5MHz_TDD_1_6_t)); - - /* - //user 2 - DCI_pdu->dci_alloc[1].dci_length = sizeof_DCI0_5MHz_TDD_1_6_t ; - DCI_pdu->dci_alloc[1].L = 2; - DCI_pdu->dci_alloc[1].rnti = 0x1236; - DCI_pdu->dci_alloc[1].format = format0; - DCI_pdu->dci_alloc[1].ra_flag = 0; - - UL_alloc_pdu.type = 0; - UL_alloc_pdu.hopping = 0; - if (cooperation_flag==0) - UL_alloc_pdu.rballoc = computeRIV(25,2+eNB->ue_ul_nb_rb,eNB->ue_ul_nb_rb); - else - UL_alloc_pdu.rballoc = computeRIV(25,0,eNB->ue_ul_nb_rb); - UL_alloc_pdu.mcs = eNB->target_ue_ul_mcs; - UL_alloc_pdu.ndi = 1; - UL_alloc_pdu.TPC = 0; - if ((cooperation_flag==0) || (cooperation_flag==1)) - UL_alloc_pdu.cshift = 0; - else - UL_alloc_pdu.cshift = 1; - UL_alloc_pdu.dai = 0; - UL_alloc_pdu.cqi_req = 1; - memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&UL_alloc_pdu,sizeof(DCI0_5MHz_TDD_1_6_t)); - */ - break; - - default: - break; - } - /* - DCI_pdu->nCCE = 0; - - for (i=0; iNum_dci; i++) { - DCI_pdu->nCCE += (1<<(DCI_pdu->dci_alloc[i].L)); - } - */ -} diff --git a/openair1/SCHED/phy_procedures_emos.h b/openair1/SCHED/phy_procedures_emos.h deleted file mode 100644 index 266a95b3c9..0000000000 --- a/openair1/SCHED/phy_procedures_emos.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#ifndef __PHY_PROCEDURES_EMOS_H__ -#define __PHY_PROCEDURES_EMOS_H__ - -/* -#ifndef RTAI -typedef uint64_t RTIME; -#else -*/ -#ifdef RTAI -#include -#include -#endif - -//#include "PHY/TOOLS/defs.h" -#include "PHY/defs.h" -#define CHANSOUNDER_FIFO_SIZE 10485760 // 10 Mbytes FIFO -//#define CHANSOUNDER_FIFO_SIZE 20971520 // 20 Mbytes FIFO -#define CHANSOUNDER_FIFO_MINOR 4 // minor of the FIFO device - this is /dev/rtf3 -#define CHANSOUNDER_FIFO_DEV "/dev/rtf4" - -#define NUMBER_OF_OFDM_CARRIERS_EMOS 512 // the number of OFDM carriers used for channel sounding -#define NUMBER_OF_USEFUL_CARRIERS_EMOS 300 // the number of OFDM carriers that contain data - -#define N_RB_UL_EMOS 25 -#define N_PILOTS_DL_EMOS 2 // ofdm symbols with pilots per slot -#define N_PILOTS_UL_EMOS 2 // ofdm symbols with pilots per subframe -#define N_SLOTS_DL_EMOS 2 // we take slots 14,15 -#define N_SUBFRAMES_UL_EMOS 1 // we take subframes 4 -#define NB_ANTENNAS_TX_EMOS 2 -#define NB_ANTENNAS_RX_EMOS 2 - -struct fifo_dump_emos_struct_UE { - // RX - uint64_t timestamp; //! Timestamp of the receiver - unsigned int frame_tx; //! Framenumber of the TX (encoded in the BCH) - unsigned int frame_rx; //! Framenumber of the RX - UE_MODE_t UE_mode; - PHY_MEASUREMENTS PHY_measurements; //! Structure holding all PHY measurements (one for every slot) - unsigned int pbch_errors; /// Total number of errors on PBCH - unsigned int pbch_errors_last; /// Total number of errors on PBCH 100 frames ago - unsigned int pbch_errors_conseq; /// Total number of consecutive errors on PBCH - unsigned int pbch_fer; /// PBCH FER (in percent) - unsigned int dlsch_errors; /// Total number of error on the DLSCH (data) - unsigned int dlsch_errors_last; - unsigned int dlsch_received; - unsigned int dlsch_received_last; - unsigned int dlsch_fer; - unsigned int dlsch_cntl_errors; /// Total number of error on the DLSCH (control) - unsigned int dlsch_ra_errors; /// Total number of error on the DLSCH (random access) - unsigned int total_TBS; - unsigned int total_TBS_last; - unsigned int bitrate; - unsigned int total_received_bits; - int timing_offset; /// Timing offset - int timing_advance; /// Timing advance - int freq_offset; /// Frequency offset - int use_ia_receiver; - unsigned short pmi_saved; - unsigned short mcs; - unsigned int rx_total_gain_dB; /// Total gain - unsigned char eNb_id; /// eNb_id UE is synched to - unsigned char mimo_mode; /// Transmission mode -#ifdef EMOS_CHANNEL - int channel[NB_ANTENNAS_RX_EMOS][NB_ANTENNAS_TX_EMOS][NUMBER_OF_OFDM_CARRIERS_EMOS*N_PILOTS_DL_EMOS*N_SLOTS_DL_EMOS]; -#endif -}; - -typedef struct fifo_dump_emos_struct_UE fifo_dump_emos_UE; - - -struct fifo_dump_emos_struct_eNB { - // TX - uint64_t timestamp; //! Timestamp of the receiver - unsigned int frame_tx; //! Framenumber of the TX - unsigned char mimo_mode; /// Transmission mode - // RX - PHY_MEASUREMENTS_eNB PHY_measurements_eNB; /// UL measurements - LTE_eNB_UE_stats eNB_UE_stats[NUMBER_OF_UE_MAX]; /// Contains received feedback - unsigned int rx_total_gain_dB; /// Total gain -#ifdef EMOS_CHANNEL - int channel[NB_ANTENNAS_RX_EMOS][N_RB_UL_EMOS*12*N_PILOTS_UL_EMOS*N_SUBFRAMES_UL_EMOS]; ///UL channel estimate -#endif -}; - -typedef struct fifo_dump_emos_struct_eNB fifo_dump_emos_eNB; - -#endif diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index c99776e7e5..179f37507a 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -547,11 +547,12 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, } -void prach_procedures(PHY_VARS_eNB *eNB, #ifdef Rel14 - int br_flag +void prach_procedures(PHY_VARS_eNB *eNB, + int br_flag) { +#else +void prach_procedures(PHY_VARS_eNB *eNB) { #endif - ) { uint16_t max_preamble[4],max_preamble_energy[4],max_preamble_delay[4]; uint16_t i; int frame,subframe; diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 1a1dcc9abd..0e978b12ce 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -51,10 +51,6 @@ #include "LAYER2/MAC/defs.h" #include "UTIL/LOG/log.h" -#ifdef EMOS -fifo_dump_emos_UE emos_dump_UE; -#endif - #include "UTIL/LOG/vcd_signal_dumper.h" #include "UTIL/OPT/opt.h" @@ -1194,38 +1190,6 @@ uint16_t get_n1_pucch(PHY_VARS_UE *ue, } -#ifdef EMOS -/* - void phy_procedures_emos_UE_TX(uint8_t next_slot,uint8_t eNB_id) { - uint8_t harq_pid; - - - if (next_slot%2==0) { - // get harq_pid from subframe relationship - harq_pid = subframe2harq_pid(&ue->frame_parms,ue->frame,(next_slot>>1)); - if (harq_pid==255) { - LOG_E(PHY,"[UE%d] Frame %d : FATAL ERROR: illegal harq_pid, returning\n", - 0,ue->frame); - return; - } - - if (ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag == 1) { - emos_dump_UE.uci_cnt[next_slot>>1] = 1; - memcpy(emos_dump_UE.UCI_data[0][next_slot>>1].o,ulsch[eNB_id]->o,MAX_CQI_BITS*sizeof(char)); - emos_dump_UE.UCI_data[0][next_slot>>1].O = ulsch[eNB_id]->O; - memcpy(emos_dump_UE.UCI_data[0][next_slot>>1].o_RI,ulsch[eNB_id]->o_RI,2*sizeof(char)); - emos_dump_UE.UCI_data[0][next_slot>>1].O_RI = ulsch[eNB_id]->O_RI; - memcpy(emos_dump_UE.UCI_data[0][next_slot>>1].o_ACK,ulsch[eNB_id]->o_ACK,4*sizeof(char)); - emos_dump_UE.UCI_data[0][next_slot>>1].O_ACK = ulsch[eNB_id]->harq_processes[harq_pid]->O_ACK; - } - else { - emos_dump_UE.uci_cnt[next_slot>>1] = 0; - } - } - } -*/ -#endif - void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empty_subframe) { int aa; @@ -1425,9 +1389,6 @@ void ue_prach_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin ue->prach_cnt=0; #ifdef SMBV ue->prach_resources[eNB_id]->ra_PreambleIndex = 19; -#endif -#ifdef OAI_EMU - ue->prach_PreambleIndex=ue->prach_resources[eNB_id]->ra_PreambleIndex; #endif LOG_I(PHY,"mode %d\n",mode); @@ -1835,12 +1796,6 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB } } -#ifdef PHY_ABSTRACTION - else { - ulsch_encoding_emul(ulsch_input_buffer,ue,eNB_id,proc->subframe_rx,harq_pid,0); - } - -#endif #if UE_TIMING_TRACE stop_meas(&ue->ulsch_encoding_stats); #endif @@ -2391,10 +2346,6 @@ void phy_procedures_UE_TX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,ui start_meas(&ue->phy_proc_tx); #endif -#ifdef EMOS - //phy_procedures_emos_UE_TX(next_slot); -#endif - ue->tx_power_dBm[subframe_tx]=-127; @@ -2675,11 +2626,6 @@ void ue_pbch_procedures(uint8_t eNB_id,PHY_VARS_UE *ue,UE_rxtx_proc_t *proc, uin ue->UE_mode[eNB_id]==NOT_SYNCHED ? 1 : 0); } -#ifdef EMOS - //emos_dump_UE.frame_tx = frame_tx; - //emos_dump_UE.mimo_mode = ue->pbch_vars[eNB_id]->decoded_output[1]; -#endif - if (first_run) { first_run = 0; @@ -4677,11 +4623,6 @@ int phy_procedures_slot_parallelization_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *pr } -#ifdef EMOS - phy_procedures_emos_UE_RX(ue,slot,eNB_id); -#endif - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_OUT); #if UE_TIMING_TRACE @@ -5161,11 +5102,6 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id, printf("after tubo until end of Rx %5.2f \n",ue->generic_stat.p_time/(cpuf*1000.0)); #endif -#ifdef EMOS - phy_procedures_emos_UE_RX(ue,slot,eNB_id); -#endif - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_OUT); #if UE_TIMING_TRACE diff --git a/openair1/SCHED/rt_compat.h b/openair1/SCHED/rt_compat.h deleted file mode 100644 index 35e99098fa..0000000000 --- a/openair1/SCHED/rt_compat.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/* Header file for making PLATON work on both RTLinux and RTAI using pthreads -* Copyright Frank Wartena, 2004 -* Version: 0.1 January 28th, 2004 ## First version for scheduling test -* 0.2 February 20th, 2004 ## All PLATON functions added -* It is mostly a conversion from RTLinux to RTAI, because PLATON was written -* for RTLinux. -* Not all necessary conversions can be done in this header file, other -* adjustments in the code are also necessary. -*/ - -#ifndef _RT_COMPAT_H_ -#define _RT_COMPAT_H_ - -#ifdef RTAI_ENABLED -//the conversions from RTLinux to RTAI - -//variable for containing times -#define hrtime_t RTIME - -//function for making a thread periodic -#define pthread_make_periodic_np(x,y,z) rt_task_make_periodic(x,rt_get_time(),nano2count(z)) - -//function for printing to the kernel log -#define rtl_printf printk - -//function for determining the current cpu -#define rtl_getcpuid hard_cpu_id - -//function for initialising a mutex -#define pthread_mutex_init pthread_mutex_init_rt - -//function for initialising a mutex attribute -#define pthread_mutexattr_init pthread_mutexattr_init_rt - -//function for setting a mutex protocol, does not exist in RTAI -#define pthread_mutexattr_setprotocol(x,y); - -//function for locking a mutex -#define pthread_mutex_lock pthread_mutex_lock_rt - -//function for unlocking a mutex -#define pthread_mutex_unlock pthread_mutex_unlock_rt - -//function for destroying a mutex -#define pthread_mutex_destroy pthread_mutex_destroy_rt - -//function for getting the current time -#define clock_gethrtime(x) rt_get_time_ns() -#define gethrtime rt_get_time_ns - -//function for initialising a condition -#define pthread_cond_init pthread_cond_init_rt - -//function for waiting on a condition -#define pthread_cond_wait pthread_cond_wait_rt - -//function for signalling a condition -#define pthread_cond_signal pthread_cond_signal_rt - -//function for destroying a condition -#define pthread_cond_destroy pthread_cond_destroy_rt - -//function for waking up a thread -#define pthread_wakeup_np rt_task_resume - -//function for getting the current thread -#define pthread_self rt_whoami - -//function for initialising an attribute -#define pthread_attr_init pthread_attr_init_rt - -//function for setting a schedparam -#define pthread_attr_setschedparam pthread_attr_setschedparam_rt - -//funcion for setting a schedpolicy -#define pthread_attr_setschedpolicy pthread_attr_setschedpolicy_rt - -//function for creating a thread -#define pthread_create pthread_create_rt - -//function for cancelling a thread -#define pthread_cancel pthread_cancel_rt - -//function for deleting a thread, in RTAI both by calling cancel -#define pthread_delete_np pthread_cancel_rt - -//testing if a cpuid exists -#define rtl_cpu_exists(x) x #include -#ifdef RTAI_ENABLED -#include -#include -#endif - #include "SIMULATION/TOOLS/defs.h" #include "SIMULATION/RF/defs.h" #include "PHY/types.h" @@ -44,9 +39,6 @@ #ifdef IFFT_FPGA #include "PHY/LTE_REFSIG/mod_table.h" #endif -#ifdef EMOS -#include "SCHED/phy_procedures_emos.h" -#endif #include "SCHED/defs.h" #include "SCHED/vars.h" #include "ARCH/CBMIMO1/DEVICE_DRIVER/vars.h" @@ -381,9 +373,6 @@ int main(int argc, char **argv) uint8_t extended_prefix_flag=0,frame_type=1; int8_t interf1=-21,interf2=-21; LTE_DL_FRAME_PARMS *frame_parms; -#ifdef EMOS - fifo_dump_emos emos_dump; -#endif FILE *input_fd=NULL,*pbch_file_fd=NULL; char input_val_str[50],input_val_str2[50]; @@ -430,13 +419,6 @@ int main(int argc, char **argv) int rx_offset_mod; -#ifdef RTAI_ENABLED - int period; - RTIME expected; - RT_TASK *task; -#define PERIOD 1000000000 -#endif - logInit(); number_of_cards = 1; @@ -694,23 +676,6 @@ int main(int argc, char **argv) } } -#ifdef RTAI_ENABLED - - if (!(task = rt_task_init_schmod(nam2num("SYNCSIM"), 0, 0, 0, SCHED_FIFO, 0xF))) { - printf("CANNOT INIT MASTER TASK\n"); - exit(1); - } - - rt_set_periodic_mode(); - - period = start_rt_timer(nano2count(PERIOD)); - - mlockall(MCL_CURRENT | MCL_FUTURE); - - rt_make_hard_real_time(); - rt_task_make_periodic(task, expected = rt_get_time() + 10*period, period); -#endif - #ifdef XFORMS if (do_forms==1) { @@ -1374,11 +1339,6 @@ int main(int argc, char **argv) for (trial=0; trial1) sigma2_dB = atoi(argv[1]); diff --git a/openair1/SIMULATION/TOOLS/taus.c b/openair1/SIMULATION/TOOLS/taus.c index 8b5ad7dfaf..0be7952da7 100644 --- a/openair1/SIMULATION/TOOLS/taus.c +++ b/openair1/SIMULATION/TOOLS/taus.c @@ -21,11 +21,6 @@ #include #include -#ifdef RTAI_ENABLED -#include -#include -#define time(x) (unsigned int)(rt_get_time_ns()) -#endif unsigned int s0, s1, s2, b; diff --git a/openair2/COMMON/mac_rrc_primitives.h b/openair2/COMMON/mac_rrc_primitives.h index 8df0970ba0..3a73000e50 100644 --- a/openair2/COMMON/mac_rrc_primitives.h +++ b/openair2/COMMON/mac_rrc_primitives.h @@ -244,9 +244,7 @@ typedef struct { LCHAN_DESC Lchan_desc[2]; /*!< \brief Logical Channel QoS Descriptor (MAC component) */ uint8_t L3_info_type; uint8_t L3_info[16]; - //#ifndef CELLULAR unsigned short UE_eNB_index; - //#endif } __attribute__ ((__packed__)) MAC_CONFIG_REQ; #define MAC_CONFIG_REQ_SIZE sizeof(MAC_CONFIG_REQ) @@ -314,18 +312,12 @@ typedef struct { #ifndef OPENAIR2_IN -#ifndef CELLULAR -//#include "L3_rrc_defs.h" -#endif - typedef struct { //RRC_INTERFACE_FUNCTIONS unsigned int Frame_index; unsigned short UE_index[NB_MODULES_MAX][NB_SIG_CNX_UE]; uint8_t eNB_id[NB_MODULES_MAX][NB_CNX_UE]; -#ifndef CELLULAR // L2_ID UE_id[NB_MODULES_MAX][NB_CNX_CH]; uint8_t UE_id[NB_MODULES_MAX][NB_CNX_CH][5]; -#endif void (*openair_rrc_top_init)(void); char (*openair_rrc_eNB_init)(uint8_t ); char (*openair_rrc_UE_init)(uint8_t, uint8_t); diff --git a/openair2/COMMON/openair_types.h b/openair2/COMMON/openair_types.h deleted file mode 100644 index 1ae2a2cefa..0000000000 --- a/openair2/COMMON/openair_types.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#ifndef __openair_TYPES_H__ -#define __openair_TYPES_H__ - -#endif /*__openair_TYPES_H__ */ diff --git a/openair2/COMMON/platform_types.h b/openair2/COMMON/platform_types.h index c0ee976fdd..1ce10c56bc 100644 --- a/openair2/COMMON/platform_types.h +++ b/openair2/COMMON/platform_types.h @@ -30,7 +30,9 @@ #ifndef __PLATFORM_TYPES_H__ # define __PLATFORM_TYPES_H__ +#if !defined(NAS_NETLINK) #include +#endif #if defined(ENABLE_ITTI) #include "itti_types.h" @@ -269,29 +271,5 @@ typedef struct protocol_ctxt_s { (CTXT_Pp)->module_id, \ (CTXT_Pp)->rnti -#ifdef OAI_EMU -#define CHECK_CTXT_ARGS(CTXT_Pp) \ - if ((CTXT_Pp)->enb_flag) {\ - AssertFatal (((CTXT_Pp)->module_id >= oai_emulation.info.first_enb_local) && (oai_emulation.info.nb_enb_local > 0),\ - "eNB module id is too low (%u/%d/%d)!\n",\ - (CTXT_Pp)->module_id,\ - oai_emulation.info.first_enb_local,\ - oai_emulation.info.nb_enb_local);\ - AssertFatal (((CTXT_Pp)->module_id < (oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local)) && (oai_emulation.info.nb_enb_local > 0),\ - "eNB module id is too high (%u/%d)!\n",\ - (CTXT_Pp)->module_id,\ - oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local);\ - } else {\ - AssertFatal ((CTXT_Pp)->module_id < (oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local),\ - "UE module id is too high (%u/%d)!\n",\ - (CTXT_Pp)->module_id,\ - oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local);\ - AssertFatal ((CTXT_Pp)->module_id >= oai_emulation.info.first_ue_local,\ - "UE module id is too low (%u/%d)!\n",\ - (CTXT_Pp)->module_id,\ - oai_emulation.info.first_ue_local);\ - } -#else #define CHECK_CTXT_ARGS(CTXT_Pp) #endif -#endif diff --git a/openair2/COMMON/rtos_header.h b/openair2/COMMON/rtos_header.h index 2ba3534d7e..05fc33463d 100644 --- a/openair2/COMMON/rtos_header.h +++ b/openair2/COMMON/rtos_header.h @@ -20,13 +20,13 @@ */ #ifndef _RTOS_HEADER_H_ -# define _RTOS_HEADER_H_ -# include -# include -# include -# include -# include -# include -# define rtf_get read -# define rtf_put write +#define _RTOS_HEADER_H_ +#include +#include +#include +#include +#include +#include +#define rtf_get read +#define rtf_put write #endif diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index a163b031c9..504dd6b8f4 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -36,10 +36,6 @@ #include "common/ran_context.h" #include "log.h" -#if defined(OAI_EMU) -# include "OCG.h" -# include "OCG_extern.h" -#endif #if defined(ENABLE_ITTI) # include "intertask_interface.h" @@ -215,9 +211,6 @@ static uint32_t eNB_app_register(uint32_t enb_id_start, uint32_t enb_id_end)//, uint32_t register_enb_pending = 0; for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { -# if defined(OAI_EMU) - if (oai_emulation.info.cli_start_enb[enb_id] == 1) -# endif { s1ap_register_enb_req_t *s1ap_register_eNB; @@ -310,19 +303,6 @@ void *eNB_app_task(void *args_p) if (RC.nb_L1_inst>0) AssertFatal(l1_north_init_eNB()==0,"could not initialize L1 north interface\n"); - # if defined(ENABLE_ITTI) -# if defined(OAI_EMU) - enb_nb = oai_emulation.info.nb_enb_local; - enb_id_start = oai_emulation.info.first_enb_local; - enb_id_end = oai_emulation.info.first_enb_local + enb_nb; - - AssertFatal (enb_id_end <= NUMBER_OF_eNB_MAX, - "Last eNB index is greater or equal to maximum eNB index (%d/%d)!", - enb_id_end, NUMBER_OF_eNB_MAX); -# endif - # endif - - AssertFatal (enb_nb <= RC.nb_inst, "Number of eNB is greater than eNB defined in configuration file (%d/%d)!", enb_nb, RC.nb_inst); @@ -396,16 +376,6 @@ void *eNB_app_task(void *args_p) msg_init_p = itti_alloc_new_message (TASK_ENB_APP, INITIALIZE_MESSAGE); itti_send_msg_to_task (TASK_L2L1, INSTANCE_DEFAULT, msg_init_p); -# if defined(OAI_EMU) - - /* Also inform all NAS UE tasks */ - for (instance = NB_eNB_INST + oai_emulation.info.first_ue_local; - instance < (NB_eNB_INST + oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local); instance ++) { - msg_init_p = itti_alloc_new_message (TASK_ENB_APP, INITIALIZE_MESSAGE); - itti_send_msg_to_task (TASK_NAS_UE, instance, msg_init_p); - } - -# endif } else { uint32_t not_associated = enb_nb - registered_enb; diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index f2f89ad1ca..610ee4a787 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -36,10 +36,6 @@ #include "enb_config.h" #include "UTIL/OTG/otg.h" #include "UTIL/OTG/otg_externs.h" -#if defined(OAI_EMU) -# include "OCG.h" -# include "OCG_extern.h" -#endif #if defined(ENABLE_ITTI) # include "intertask_interface.h" # if defined(ENABLE_USE_MME) diff --git a/openair2/LAYER2/Makefile.inc b/openair2/LAYER2/Makefile.inc index c0e4df5617..2f5cea7555 100644 --- a/openair2/LAYER2/Makefile.inc +++ b/openair2/LAYER2/Makefile.inc @@ -54,10 +54,6 @@ SOURCES_L2 += $(RLC_UM_DIR)/rlc_um_reassembly.c SOURCES_L2 += $(RLC_UM_DIR)/rlc_um_receiver.c SOURCES_L2 += $(RLC_UM_DIR)/rlc_um_dar.c -ifeq ($(OPENAIR_EMU),1) -SOURCES_L2 += $(RLC_UM_DIR)/rlc_um_very_simple_test.c -endif - SOURCES_L2 += $(RLC_DIR)/rlc_mac.c SOURCES_L2 += $(RLC_DIR)/rlc.c SOURCES_L2 += $(RLC_DIR)/rlc_rrc.c diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 8bb04c37b8..0db15ffd59 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -61,10 +61,7 @@ # include "gtpv1u.h" #endif -#ifndef OAI_EMU extern int otg_enabled; -#endif - //----------------------------------------------------------------------------- /* @@ -436,11 +433,6 @@ pdcp_data_ind( VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_IN); -#ifdef OAI_EMU - - CHECK_CTXT_ARGS(ctxt_pP); - -#endif #ifdef PDCP_MSG_PRINT int i=0; LOG_F(PDCP,"[MSG] PDCP UL %s PDU on rb_id %d\n", (srb_flagP)? "CONTROL" : "DATA", rb_idP); @@ -688,49 +680,6 @@ pdcp_data_ind( payload_offset=0; } -#if defined(OAI_EMU) - - if (oai_emulation.info.otg_enabled == 1) { - //unsigned int dst_instance; - int ctime; - - if ((pdcp_p->rlc_mode == RLC_MODE_AM)&&(MBMS_flagP==0) ) { - pdcp_p->last_submitted_pdcp_rx_sn = sequence_number; - } - -#if defined(DEBUG_PDCP_PAYLOAD) - rlc_util_print_hex_octets(PDCP, - (unsigned char*)&sdu_buffer_pP->data[payload_offset], - sdu_buffer_sizeP - payload_offset); -#endif - - ctime = oai_emulation.info.time_ms; // avg current simulation time in ms : we may get the exact time through OCG? - if (MBMS_flagP == 0){ - LOG_D(PDCP, - PROTOCOL_PDCP_CTXT_FMT"Check received buffer : (dst %d)\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), - ctxt_pP->instance); - } - if (otg_rx_pkt( - ctxt_pP->instance, - ctime, - (const char*)(&sdu_buffer_pP->data[payload_offset]), - sdu_buffer_sizeP - payload_offset ) == 0 ) { - free_mem_block(sdu_buffer_pP, __func__); - - if (ctxt_pP->enb_flag) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); - return TRUE; - } - } - -#else - if (otg_enabled==1) { LOG_D(OTG,"Discarding received packed\n"); free_mem_block(sdu_buffer_pP, __func__); @@ -745,9 +694,6 @@ pdcp_data_ind( return TRUE; } -#endif - - // XXX Decompression would be done at this point /* @@ -806,22 +752,15 @@ pdcp_data_ind( // set ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst for IP layer here if (ctxt_pP->enb_flag == ENB_FLAG_NO) { ((pdcp_data_ind_header_t *) new_sdu_p->data)->rb_id = rb_id; -#if defined(OAI_EMU) - ((pdcp_data_ind_header_t*) new_sdu_p->data)->inst = ctxt_pP->module_id + oai_emulation.info.nb_enb_local - oai_emulation.info.first_ue_local; -#else -# if defined(ENABLE_USE_MME) +#if defined(ENABLE_USE_MME) /* for the UE compiled in S1 mode, we need 1 here * for the UE compiled in noS1 mode, we need 0 * TODO: be sure of this */ ((pdcp_data_ind_header_t*) new_sdu_p->data)->inst = 1; -# endif #endif } else { ((pdcp_data_ind_header_t*) new_sdu_p->data)->rb_id = rb_id + (ctxt_pP->module_id * maxDRB); -#if defined(OAI_EMU) - ((pdcp_data_ind_header_t*) new_sdu_p->data)->inst = ctxt_pP->module_id - oai_emulation.info.first_enb_local; -#endif } #ifdef DEBUG_PDCP_FIFO_FLUSH_SDU static uint32_t pdcp_inst = 0; @@ -978,11 +917,6 @@ pdcp_run ( itti_send_msg_to_task(TASK_MAC_ENB, 3, msg_resp_p); } # endif -#endif - -#if defined(OAI_EMU) - pdcp_fifo_read_input_sdus_from_otg(ctxt_pP); - #endif // IP/NAS -> PDCP traffic : TX, read the pkt from the upper layer buffer diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index c19adb6753..a5f400b4c2 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -33,9 +33,7 @@ #define PDCP_DEBUG 1 //#define DEBUG_PDCP_FIFO_FLUSH_SDU -#ifndef OAI_EMU extern int otg_enabled; -#endif #include "pdcp.h" #include "pdcp_primitives.h" @@ -162,11 +160,6 @@ int pdcp_fifo_flush_sdus(const protocol_ctxt_t* const ctxt_pP) threadname, ctxt_pP->frame, ctxt_pP->subframe, ((pdcp_data_ind_header_t*) sdu_p->data)->inst, ((pdcp_data_ind_header_t *) sdu_p->data)->data_size); -#else -#if ! defined(OAI_EMU) - /* TODO: do we have to reset to 0 or not? not for a scenario with 1 UE at least */ -// ((pdcp_data_ind_header_t *)(sdu_p->data))->inst = 0; -#endif #endif #if defined(LINK_ENB_PDCP_TO_GTPV1U) @@ -547,29 +540,6 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const ctxt_pP) nas_nlh_rx->nlmsg_len - sizeof(struct nlmsghdr)); #endif -#ifdef OAI_EMU - - // overwrite function input parameters, because only one netlink socket for all instances - if (pdcp_read_header_g.inst < oai_emulation.info.nb_enb_local) { - ctxt.frame = ctxt_cpy.frame; - ctxt.enb_flag = ENB_FLAG_YES; - ctxt.module_id = pdcp_read_header_g.inst + oai_emulation.info.first_enb_local; - ctxt.rnti = oai_emulation.info.eNB_ue_module_id_to_rnti[ctxt.module_id ][pdcp_read_header_g.rb_id / maxDRB + oai_emulation.info.first_ue_local]; - rab_id = pdcp_read_header_g.rb_id % maxDRB; - } else { - ctxt.frame = ctxt_cpy.frame; - ctxt.enb_flag = ENB_FLAG_NO; - ctxt.module_id = pdcp_read_header_g.inst - oai_emulation.info.nb_enb_local + oai_emulation.info.first_ue_local; - ctxt.rnti = pdcp_UE_UE_module_id_to_rnti[ctxt.module_id]; - rab_id = pdcp_read_header_g.rb_id % maxDRB; - } - - CHECK_CTXT_ARGS(&ctxt); - AssertFatal (rab_id < maxDRB, "RB id is too high (%u/%d)!\n", rab_id, maxDRB); - /*LGpdcp_read_header.inst = (pdcp_read_header_g.inst >= oai_emulation.info.nb_enb_local) ? \ - pdcp_read_header_g.inst - oai_emulation.info.nb_enb_local+ NB_eNB_INST + oai_emulation.info.first_ue_local : - pdcp_read_header_g.inst + oai_emulation.info.first_enb_local;*/ -#else // OAI_EMU /* TODO: do we have to reset to 0 or not? not for a scenario with 1 UE at least */ // pdcp_read_header_g.inst = 0; //#warning "TO DO CORRCT VALUES FOR ue mod id, enb mod id" @@ -590,9 +560,6 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const ctxt_pP) ctxt.rnti = pdcp_UE_UE_module_id_to_rnti[ctxt.module_id]; } - -#endif - if (ctxt.enb_flag) { if (rab_id != 0) { rab_id = rab_id % maxDRB; @@ -804,121 +771,8 @@ void pdcp_fifo_read_input_sdus_from_otg (const protocol_ctxt_t* const ctxt_pP) module_id_t dst_id; // dst for otg rb_id_t rb_id; unsigned int pkt_size=0; -#if defined(OAI_EMU) - module_id_t src_id; - static unsigned int pkt_cnt_enb=0, pkt_cnt_ue=0; - - Packet_otg_elt_t *otg_pkt_info=NULL; - int result; - uint8_t pdcp_mode, is_ue=0; -#endif protocol_ctxt_t ctxt; // we need to add conditions to avoid transmitting data when the UE is not RRC connected. -#if defined(OAI_EMU) - - if (oai_emulation.info.otg_enabled ==1 ) { - // module_id is source id - while ((otg_pkt_info = pkt_list_remove_head(&(otg_pdcp_buffer[ctxt_pP->instance]))) != NULL) { - LOG_I(OTG,"Mod_id %d Frame %d Got a packet (%p), HEAD of otg_pdcp_buffer[%d] is %p and Nb elements is %d\n", - ctxt_pP->module_id, - ctxt_pP->frame, - otg_pkt_info, - ctxt_pP->instance, - pkt_list_get_head(&(otg_pdcp_buffer[ctxt_pP->instance])), - otg_pdcp_buffer[ctxt_pP->instance].nb_elements); - //otg_pkt_info = pkt_list_remove_head(&(otg_pdcp_buffer[module_id])); - dst_id = (otg_pkt_info->otg_pkt).dst_id; // type is module_id_t - src_id = (otg_pkt_info->otg_pkt).module_id; // type is module_id_t - rb_id = (otg_pkt_info->otg_pkt).rb_id; - is_ue = (otg_pkt_info->otg_pkt).is_ue; - pdcp_mode = (otg_pkt_info->otg_pkt).mode; - // LOG_I(PDCP,"pdcp_fifo, pdcp mode is= %d\n",pdcp_mode); - - // generate traffic if the ue is rrc reconfigured state - // if (mac_get_rrc_status(module_id, ctxt_pP->enb_flag, dst_id ) > 2 /*RRC_CONNECTED*/) { // not needed: this test is already done in update_otg_enb - otg_pkt = (unsigned char*) (otg_pkt_info->otg_pkt).sdu_buffer; - pkt_size = (otg_pkt_info->otg_pkt).sdu_buffer_size; - - if (otg_pkt != NULL) { - if (is_ue == 0 ) { - PROTOCOL_CTXT_SET_BY_MODULE_ID( - &ctxt, - src_id, - ENB_FLAG_YES, - oai_emulation.info.eNB_ue_module_id_to_rnti[ctxt.module_id][dst_id], - ctxt_pP->frame, - ctxt_pP->subframe, - src_id); - - LOG_D(OTG,"[eNB %d] Frame %d sending packet %d from module %d on rab id %d (src %d, dst %d/%x) pkt size %d for pdcp mode %d\n", - ctxt.module_id, - ctxt.frame, - pkt_cnt_enb++, - src_id, - rb_id, - src_id, - dst_id, - oai_emulation.info.eNB_ue_module_id_to_rnti[ctxt.module_id][dst_id], - pkt_size, - pdcp_mode); - result = pdcp_data_req(&ctxt, - SRB_FLAG_NO, - rb_id, - RLC_MUI_UNDEFINED, - RLC_SDU_CONFIRM_NO, - pkt_size, - otg_pkt, - pdcp_mode); - if (result != TRUE) { - LOG_W(OTG,"PDCP data request failed!\n"); - } - } else { - //rb_id= eNB_index * MAX_NUM_RB + DTCH; - - - LOG_D(OTG,"[UE %d] Frame %d: sending packet %d from module %d on rab id %d (src %d/%x, dst %d) pkt size %d\n", - ctxt_pP->module_id, - ctxt_pP->frame, - pkt_cnt_ue++, - ctxt_pP->module_id, - rb_id, - src_id, - pdcp_UE_UE_module_id_to_rnti[ctxt_pP->module_id], // [src_id] - dst_id, - pkt_size); - PROTOCOL_CTXT_SET_BY_MODULE_ID( - &ctxt, - ctxt_pP->module_id, //src_id, - ENB_FLAG_NO, - pdcp_UE_UE_module_id_to_rnti[ctxt_pP->module_id],// [src_id] - ctxt_pP->frame, - ctxt_pP->subframe, - dst_id); - - result = pdcp_data_req( &ctxt, - SRB_FLAG_NO, - rb_id, - RLC_MUI_UNDEFINED, - RLC_SDU_CONFIRM_NO, - pkt_size, - otg_pkt, - PDCP_TRANSMISSION_MODE_DATA); - if (result != TRUE) { - LOG_W(OTG,"PDCP data request failed!\n"); - } - } - - free(otg_pkt); - otg_pkt = NULL; - } - - // } //else LOG_D(OTG,"ctxt_pP->frame %d enb %d-> ue %d link not yet established state %d \n", ctxt_pP->frame, eNB_index,dst_id - NB_eNB_INST, mac_get_rrc_status(module_id, ctxt_pP->enb_flag, dst_id - NB_eNB_INST)); - - } - } - -#else - if ((otg_enabled==1) && (ctxt_pP->enb_flag == ENB_FLAG_YES)) { // generate DL traffic unsigned int ctime=0; ctime = ctxt_pP->frame * 100; @@ -967,6 +821,4 @@ void pdcp_fifo_read_input_sdus_from_otg (const protocol_ctxt_t* const ctxt_pP) } } } - -#endif } diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c index e0a0c062d7..0df8e59e6d 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c @@ -101,13 +101,8 @@ pdcp_netlink_init( struct sched_param sched_param; reset_meas(&ip_pdcp_stats_tmp); -#if defined(OAI_EMU) - nb_inst_enb = oai_emulation.info.nb_enb_local; - nb_inst_ue = oai_emulation.info.nb_ue_local; -#else nb_inst_enb = 1; nb_inst_ue = 1; -#endif #if defined(LINK_ENB_PDCP_TO_GTPV1U) nb_inst_enb = 0; @@ -259,24 +254,7 @@ void *pdcp_netlink_thread_fct(void *arg) } } else { pdcp_thread_read_state = 0; - -#ifdef OAI_EMU - - // LG: new_data_p->pdcp_read_header.inst will contain in fact a module id - if (new_data_p->pdcp_read_header.inst >= oai_emulation.info.nb_enb_local) { - module_id = new_data_p->pdcp_read_header.inst - - oai_emulation.info.nb_enb_local + - + oai_emulation.info.first_ue_local; - eNB_flag = 0; - } else { - module_id = new_data_p->pdcp_read_header.inst - + oai_emulation.info.first_enb_local; - eNB_flag = 1; - } - -#else module_id = 0; -#endif new_data_p->data = malloc(sizeof(uint8_t) * new_data_p->pdcp_read_header.data_size); /* Copy the data */ memcpy(new_data_p->data, NLMSG_DATA(nas_nlh_rx), new_data_p->pdcp_read_header.data_size); diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_thread.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_thread.c index 0200ffdbf8..0b6be93d59 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_thread.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_thread.c @@ -110,9 +110,7 @@ int init_pdcp_thread(void) p.sched_priority = OPENAIR_THREAD_PRIORITY; pthread_attr_setschedparam (&pdcp_thread_attr, &p); -#ifndef RTAI_ISNT_POSIX pthread_attr_setschedpolicy (&pdcp_thread_attr, SCHED_FIFO); -#endif pthread_mutex_init(&pdcp_mutex,NULL); pthread_cond_init(&pdcp_cond,NULL); diff --git a/openair2/LAYER2/RLC/rlc.c b/openair2/LAYER2/RLC/rlc.c index d70d85f2d5..d27d46ff42 100644 --- a/openair2/LAYER2/RLC/rlc.c +++ b/openair2/LAYER2/RLC/rlc.c @@ -135,11 +135,6 @@ rlc_op_status_t rlc_stat_req ( hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; -#ifdef OAI_EMU - - CHECK_CTXT_ARGS(ctxt_pP) - -#endif AssertFatal (rb_idP < NB_RB_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX); key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p); @@ -346,11 +341,6 @@ rlc_op_status_t rlc_data_req (const protocol_ctxt_t* const ctxt_pP, #else AssertFatal(MBMS_flagP == 0, "MBMS_flagP %u", MBMS_flagP); #endif -#ifdef OAI_EMU - - CHECK_CTXT_ARGS(ctxt_pP) - -#endif #if T_TRACER if (ctxt_pP->enb_flag) diff --git a/openair2/LAYER2/RLC/rlc_mac.c b/openair2/LAYER2/RLC/rlc_mac.c index 6793e71c54..497937d073 100644 --- a/openair2/LAYER2/RLC/rlc_mac.c +++ b/openair2/LAYER2/RLC/rlc_mac.c @@ -157,13 +157,6 @@ tbs_size_t mac_rlc_data_req( AssertFatal (channel_idP < NB_RB_MAX, "channel id is too high (%u/%d)!\n", channel_idP, NB_RB_MAX); } -#ifdef OAI_EMU - CHECK_CTXT_ARGS(&ctxt); - //printf("MBMS_flagP %d, MBMS_FLAG_NO %d \n",MBMS_flagP, MBMS_FLAG_NO); - // AssertFatal (MBMS_flagP == MBMS_FLAG_NO ," MBMS FLAG SHOULD NOT BE SET IN mac_rlc_data_req in UE\n"); - -#endif - if (MBMS_flagP) { if (enb_flagP) { mbms_id_p = &rlc_mbms_lcid2service_session_id_eNB[module_idP][channel_idP]; @@ -256,18 +249,6 @@ void mac_rlc_data_ind ( } #endif // DEBUG_MAC_INTERFACE -#ifdef OAI_EMU - - if (MBMS_flagP) - AssertFatal (channel_idP < RLC_MAX_MBMS_LC, "channel id is too high (%u/%d)!\n", - channel_idP, RLC_MAX_MBMS_LC); - else - AssertFatal (channel_idP < NB_RB_MAX, "channel id is too high (%u/%d)!\n", - channel_idP, NB_RB_MAX); - - CHECK_CTXT_ARGS(&ctxt); - -#endif #if T_TRACER if (enb_flagP) @@ -347,31 +328,6 @@ mac_rlc_status_resp_t mac_rlc_status_ind( memset (&mac_rlc_status_resp, 0, sizeof(mac_rlc_status_resp_t)); memset (&tx_status , 0, sizeof(struct mac_status_ind)); -#ifdef OAI_EMU - - if (MBMS_flagP) - AssertFatal (channel_idP < RLC_MAX_MBMS_LC, - "%s channel id is too high (%u/%d) enb module id %u ue %u!\n", - (enb_flagP) ? "eNB" : "UE", - channel_idP, - RLC_MAX_MBMS_LC, - module_idP, - rntiP); - else - AssertFatal (channel_idP < NB_RB_MAX, - "%s channel id is too high (%u/%d) enb module id %u ue %u!\n", - (enb_flagP) ? "eNB" : "UE", - channel_idP, - NB_RB_MAX, - module_idP, - rntiP); - - CHECK_CTXT_ARGS(&ctxt); - -#endif - - - if (MBMS_flagP) { if (enb_flagP) { mbms_id_p = &rlc_mbms_lcid2service_session_id_eNB[module_idP][channel_idP]; diff --git a/openair2/LAYER2/RLC/rlc_rrc.c b/openair2/LAYER2/RLC/rlc_rrc.c index 68f5971bf1..dee6ba7000 100644 --- a/openair2/LAYER2/RLC/rlc_rrc.c +++ b/openair2/LAYER2/RLC/rlc_rrc.c @@ -33,9 +33,6 @@ #include "rlc_um.h" #include "rlc_tm.h" #include "UTIL/LOG/log.h" -#ifdef OAI_EMU -#include "UTIL/OCG/OCG_vars.h" -#endif #include "RLC-Config.h" #include "DRB-ToAddMod.h" #include "DRB-ToAddModList.h" @@ -88,12 +85,6 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP LOG_D(RLC, PROTOCOL_CTXT_FMT" CONFIG REQ ASN1 \n", PROTOCOL_CTXT_ARGS(ctxt_pP)); -#ifdef OAI_EMU - - CHECK_CTXT_ARGS(ctxt_pP) - -#endif - if (srb2add_listP != NULL) { for (cnt=0; cntlist.count; cnt++) { rb_id = srb2add_listP->list.array[cnt]->srb_Identity; @@ -489,10 +480,6 @@ rlc_op_status_t rrc_rlc_remove_rlc ( rlc_union_t *rlc_union_p = NULL; #if defined(Rel10) || defined(Rel14) rlc_mbms_id_t *mbms_id_p = NULL; -#endif -#ifdef OAI_EMU - CHECK_CTXT_ARGS(ctxt_pP) - #endif /* for no gcc warnings */ @@ -597,12 +584,6 @@ rlc_union_t* rrc_rlc_add_rlc ( logical_chan_id_t lcid = 0; #endif -#ifdef OAI_EMU - - CHECK_CTXT_ARGS(ctxt_pP) - -#endif - if (MBMS_flagP == FALSE) { AssertFatal (rb_idP < NB_RB_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX); AssertFatal (chan_idP < RLC_MAX_LC, "LC id is too high (%u/%d)!\n", chan_idP, RLC_MAX_LC); @@ -706,11 +687,6 @@ rlc_op_status_t rrc_rlc_config_req ( PROTOCOL_CTXT_ARGS(ctxt_pP), rb_idP); -#ifdef OAI_EMU - - CHECK_CTXT_ARGS(ctxt_pP) - -#endif AssertFatal (rb_idP < NB_RB_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX); switch (actionP) { diff --git a/openair2/LAYER2/register.c b/openair2/LAYER2/register.c deleted file mode 100644 index 6d869a9508..0000000000 --- a/openair2/LAYER2/register.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*________________________rrc_register.c________________________ - - Authors : Hicham Anouar, Raymond Knopp - Company : EURECOM - Emails : anouar@eurecom.fr, knopp@eurecom.fr -________________________________________________________________*/ - - -#include -#include - -#include - -#include "COMMON/openair_types.h" -#include "MAC/extern.h" - -#include - - - diff --git a/openair2/Makefile b/openair2/Makefile deleted file mode 100755 index 2fbeb193a6..0000000000 --- a/openair2/Makefile +++ /dev/null @@ -1,254 +0,0 @@ -#/* -# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more -# * contributor license agreements. See the NOTICE file distributed with -# * this work for additional information regarding copyright ownership. -# * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.1 (the "License"); you may not use this file -# * except in compliance with the License. -# * You may obtain a copy of the License at -# * -# * http://www.openairinterface.org/?page_id=698 -# * -# * Unless required by applicable law or agreed to in writing, software -# * distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. -# *------------------------------------------------------------------------------- -# * For more information about the OpenAirInterface (OAI) Software Alliance: -# * contact@openairinterface.org -# */ - -#################################################### -# USER SPACE CODE GENERATION -#################################################### - -#--------------------------------------------------- -# -#--------------------------------------------------- - - -#LM_LICENSE_FILE= -#export LM_LICENSE_FILE -include $(OPENAIR_DIR)/common/utils/Makefile.inc - -KERNEL_NAME:=$(shell uname -r) -NUM_CORES=$(shell getconf _NPROCESSORS_CONF) - -export SET_UM=$(shell if grep --silent User\ Mode\ Linux /proc/cpuinfo ; then echo "ARCH=um" ; else echo ""; fi) - -#SUBDIRS_openair_USERRF = $(MAIN_RT_DIR) $(CONFIG_DIR) - -#openair_USERRFDIR = openair_RFOBJS -#openair_USERRFLIBS = $(addsuffix /${openair_USERRFDIR}/Lib.a, ${SUBDIRS_openair_USERRF}) -#openair_USERRFOBJS = $(addsuffix /${openair_USERRFDIR}/*.o, ${SUBDIRS_openair_USERRF}) -#openair_USERRFDEPS = $(addsuffix /${openair_USERRFDIR}/*.d, ${SUBDIRS_openair_USERRF}) - -mac_sim_no_netlink: - ( cd SIMULATION/USER_TOOLS/LAYER2_SIM && make mac_sim MASTER=1) - -mac_sim: - ( cd SIMULATION/USER_TOOLS/LAYER2_SIM && make mac_sim MASTER=1 NETLINK=1 NO_RRM=1) - -mac_sim_rrm: - ( cd SIMULATION/USER_TOOLS/LAYER2_SIM && make mac_sim_rrm MASTER=1 NETLINK=1) - -mac_sim_mt_cellular: - ( cd SIMULATION/USER_TOOLS/LAYER2_SIM && make mac_sim_mt CELLULAR=1 NO_RRM=1) - -mac_sim_rg_cellular: - ( cd SIMULATION/USER_TOOLS/LAYER2_SIM && make mac_sim_rg MASTER=1 CELLULAR=1 NO_RRM=1) - -openair_layer2_emul.ko: - (cd LAYER2 && $(MAKE) V=1 -C $(KERNEL_DIR)/build M=`pwd` NO_RRM=1 PCTARGET=1 RTAI=1 MASTER=1 OPEN_AIR=1 PHYEMUL=1 && mv openair_l2.ko openair_layer2.ko) - -openair_layer2_emul_rrm.ko: - (cd LAYER2 && $(MAKE) V=1 -C $(KERNEL_DIR)/build M=`pwd` PCTARGET=1 RTAI=1 MASTER=1 OPEN_AIR=1 PHYEMUL=1 && mv openair_l2.ko openair_layer2.ko) - - -openair_layer2.ko: - (cd LAYER2 && $(MAKE) V=1 -C $(KERNEL_DIR)/build M=`pwd` NO_RRM=1 PCTARGET=1 RTAI=1 MASTER=1 OPEN_AIR=1 OPENAIR1=1 && mv openair_l2.ko openair_layer2.ko) - -openair_layer2_rrm.ko: - (cd LAYER2 && $(MAKE) V=1 -C $(KERNEL_DIR)/build M=`pwd` PCTARGET=1 RTAI=1 MASTER=1 OPEN_AIR=1 OPENAIR1=1 && mv openair_l2.ko openair_layer2.ko) - -openair_layer2_2615.ko: - (cd LAYER2 && $(MAKE) V=1 -C $(KERNEL_DIR)/build M=`pwd` PCTARGET=1 RTAI=1 MASTER=1 OPEN_AIR=1 OPENAIR1=1 && mv openair_l2.ko openair_layer2_2615.ko) - - -openair_rrc.ko: - (cd RRC/MESH && $(MAKE) V=1 -C $(KERNEL_DIR)/build M=`pwd` PCTARGET=1 RTAI=1 OPEN_AIR=1 MASTER=1 NO_RRM=1 && mv openair_rrc.ko openair_RRC.ko) - -openair_rrc_rrm.ko: - (cd RRC/MESH && $(MAKE) V=1 -C $(KERNEL_DIR)/build M=`pwd` PCTARGET=1 RTAI=1 OPEN_AIR=1 MASTER=1 && mv openair_rrc.ko openair_RRC.ko) - - -openair_rrc_2615.ko: - (cd RRC/MESH && $(MAKE) V=1 -C $(KERNEL_DIR)/build M=`pwd` PCTARGET=1 RTAI=1 OPEN_AIR=1 MASTER=1 && mv openair_rrc.ko openair_RRC_2615.ko) - -openair_rrc_emul.ko: - (cd RRC/MESH && $(MAKE) V=1 -C $(KERNEL_DIR)/build M=`pwd` PCTARGET=1 RTAI=1 OPEN_AIR=1 MASTER=1 PHYEMUL=1 NO_RRM=1) - -openair_rrc_emul_rrm.ko: - (cd RRC/MESH && $(MAKE) V=1 -C $(KERNEL_DIR)/build M=`pwd` PCTARGET=1 RTAI=1 OPEN_AIR=1 MASTER=1 PHYEMUL=1) - - -openair_emul.ko: - (cd SIMULATION/PHY_EMULATION/DEVICE_DRIVER/ && $(MAKE) V=1 -C $(KERNEL_DIR)/build M=`pwd` PCTARGET=1 RTAI=1 OPEN_AIR=1 MASTER=1 NO_RRM=1) - -openair_emul_rrm.ko: - (cd SIMULATION/PHY_EMULATION/DEVICE_DRIVER/ && $(MAKE) V=1 -C $(KERNEL_DIR)/build M=`pwd` PCTARGET=1 RTAI=1 OPEN_AIR=1 MASTER=1) - - - -create_device: - rm -f /dev/openair0 - mknod /dev/openair0 c 127 0 - chmod a+rw /dev/openair0 - - -install_emul: - make devs - make fifos - (insmod SIMULATION/PHY_EMULATION/DEVICE_DRIVER/openair_emul.ko) - (insmod LAYER2/openair_layer2.ko) - (insmod RRC/MESH/openair_rrc.ko) - (insmod NETWORK_DRIVER/MESH/nasmesh.ko) - -remove_emul: - rmmod nasmesh - sleep 1 - rmmod openair_rrc - sleep 1 - rmmod openair_l2 - sleep 1 - rmmod openair_emul - - -clean_nasmesh: - (cd NETWORK_DRIVER/MESH && $(MAKE) V=1 -C $(KERNEL_DIR)/build M=`pwd` clean) - -nasmesh_address_fix.ko: - (cd NETWORK_DRIVER/MESH && $(MAKE) -j$(NUM_CORES) $(SET_UM) V=1 ADDRESS_FIX=1 -C $(KERNEL_DIR)/build M=`pwd`) - -nasmesh.ko: - (cd NETWORK_DRIVER/MESH && $(MAKE) -j$(NUM_CORES) $(SET_UM) V=1 -C $(KERNEL_DIR)/build M=`pwd`) - -# automatically detect the linux header files for driver compilation -nasmesh_netlink.ko: - (cd NETWORK_DRIVER/MESH && $(MAKE) -j$(NUM_CORES) $(SET_UM) PDCP_USE_NETLINK=1 V=1 -C $(KERNEL_DIR)/build M=`pwd` modules) - -naslite_netlink_ether.ko: - (cd NETWORK_DRIVER/LITE && $(MAKE) -j$(NUM_CORES) $(SET_UM) OAI_NW_DRIVER_TYPE_ETHERNET=1 PDCP_USE_NETLINK=1 OAI_NW_DRIVER_USE_NETLINK=1 V=1 -C $(KERNEL_DIR)/build M=`pwd` modules) - -oai_nw_ether.ko: - (cd NETWORK_DRIVER/LITE && $(MAKE) -j$(NUM_CORES) $(SET_UM) OAI_NW_DRIVER_TYPE_ETHERNET=1 PDCP_USE_NETLINK=1 OAI_NW_DRIVER_USE_NETLINK=1 V=1 -C $(KERNEL_DIR)/build M=`pwd` modules) - -oai_nw_drv.ko: - (cd NETWORK_DRIVER/LITE && $(MAKE) -j$(NUM_CORES) $(SET_UM) OAI_NW_DRIVER_TYPE_ETHERNET=1 PDCP_USE_NETLINK=1 OAI_NW_DRIVER_USE_NETLINK=1 V=1 -C $(KERNEL_DIR)/build M=`pwd` modules) - -nasmesh_netlink_address_fix.ko: - (cd NETWORK_DRIVER/MESH && $(MAKE) -j$(NUM_CORES) $(SET_UM) PDCP_USE_NETLINK=1 ADDRESS_FIX=1 V=1 -C $(KERNEL_DIR)/build M=`pwd` modules) - - -nasmesh_netlink_loopback.ko: - (cd NETWORK_DRIVER/MESH && $(MAKE) $(SET_UM) PDCP_USE_NETLINK=1 LOOPBACK=1 V=1 -C $(KERNEL_DIR)/build M=`pwd` modules) - -# drivers cellular version -nascellmt_netlink.ko: - (cd NAS/DRIVER/CELLULAR/NASMT && $(MAKE) -j$(NUM_CORES) $(SET_UM) NAS_DRIVER_TYPE_ETHERNET=1 PDCP_USE_NETLINK=1 V=1 -C $(KERNEL_DIR)/build M=`pwd` modules) - -nascellmt_clean.ko: - (cd NAS/DRIVER/CELLULAR/NASMT && $(MAKE) -j$(NUM_CORES) $(SET_UM) NAS_DRIVER_TYPE_ETHERNET=1 PDCP_USE_NETLINK=1 V=1 -C $(KERNEL_DIR)/build M=`pwd` clean) - -nascellrg_netlink.ko: - (cd NAS/DRIVER/CELLULAR/NASRG && $(MAKE) -j$(NUM_CORES) $(SET_UM) NAS_DRIVER_TYPE_ETHERNET=1 PDCP_USE_NETLINK=1 V=1 -C $(KERNEL_DIR)/build M=`pwd` modules) - -nascellrg_clean.ko: - (cd NAS/DRIVER/CELLULAR/NASRG && $(MAKE) -j$(NUM_CORES) $(SET_UM) NAS_DRIVER_TYPE_ETHERNET=1 PDCP_USE_NETLINK=1 V=1 -C $(KERNEL_DIR)/build M=`pwd` clean) - -# Driver for UE using LTE core network (MME, S+P-GW) -ue_ip.ko: - (cd NETWORK_DRIVER/UE_IP && $(MAKE) -j$(NUM_CORES) $(SET_UM) PDCP_USE_NETLINK=1 OAI_NW_DRIVER_USE_NETLINK=1 V=1 -C $(KERNEL_DIR)/build M=`pwd` modules) - - -rt_emul: - (cd SIMULATION/USER_TOOLS/RT_EMUL_LAUNCHER && $(MAKE)) - -bypass_phy: - (cd SIMULATION/PHY_EMULATION/TRANSPORT/KERNEL_INTERFACE && $(MAKE)) - -rb_tool: - (cd NETWORK_DRIVER/MESH/RB_TOOL && $(MAKE)) - - -fifos: - @for i in `seq 0 64`;\ - do \ - have_rtfX=`ls /dev/ |grep -c rtf$$i`;\ - if [ "$$have_rtfX" -eq 0 ] ;then \ - mknod -m 666 /dev/rtf$$i c 150 $$i; \ - fi;\ - done - -# cp arch/openair_CardBus_MIMO1/device_driver/openair_rf.ko $(KERNEL_DIR)/openair/ -# depmod -aq - -devs: - if ! test -a /dev/openair0;\ - then \ - mknod /dev/openair0 c 127 0;\ - chmod a+rw /dev/openair0;\ - fi; - -load_sounder_ue: install_cbmimo1_ublaze - insmod mac/chansounder/openair_chansounder_ue.ko - -load_sounder_nodeb: install_platon - (cd openair_rf && ./openair_rf_platon 1917600 0 ../arch/platon/rbt_files/DAQ_B.rbt 30p 15p 10p 25p && ./openair_rf_platon 1917600 0 ../arch/platon/rbt_files/daq_platon_11_2005.rbt 30p 15p 10p 25p) - - -stop_sounder: - rmmod openair_chansounder - rmmod openair_rf - -stop_sounder_nodeb: - (cd openair_rf && ./openair_rf_platon 1907600 4) - rmmod openair_chansounder - rmmod openair_rf - - -emul_rt: - (cd SIMULATION/USER_TOOLS/RT_EMUL_LAUNCHER && $(MAKE)) - -clean: - (cd NETWORK_DRIVER/MESH && $(MAKE) clean) - (cd NETWORK_DRIVER/LITE && $(MAKE) clean) - rm -rf NETWORK_DRIVER/MESH/RB_TOOL/rb_tool - rm -rf NETWORK_DRIVER/LITE/RB_TOOL/rb_tool - -cleanall: - find -name *.o -delete -print - find -name *.ko -delete -print - find -name *~ -delete -print - find -name *.bak -delete -print - rm -rf NETWORK_DRIVER/MESH/RB_TOOL/rb_tool - rm -rf NETWORK_DRIVER/LITE/RB_TOOL/rb_tool - - -cleansvn: - rm -rf `find -name *.svn* -print` ; \ - find -name *.svn* -delete -print - -tgz: - mkdir /tmp/openair2_tmp; \ - $(MAKE) cleanall; \ - cp -r . /tmp/openair2_tmp; \ - (cd /tmp/openair2_tmp && $(MAKE) cleansvn && cd .. && tar czfv openair2.tgz openair2_tmp) ; \ - cp /tmp/openair2.tgz . ;\ - rm -rf /tmp/openair2_tmp - -print: - @echo $(IS_KERNEL_OPENAIRINTERFACE) - @echo $(KERNEL_DIR) - @echo $(IS_LINUX) diff --git a/openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/Makefile b/openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/Makefile deleted file mode 100755 index 427a9fad51..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -# Lines starting with the pound sign are comments. -# -# These things are options that you might need -# to tweak. - -# You can modify the below as well, but probably -# won't need to. - -#CC = egcs - -#UPDIR := $(shell /bin/pwd) -#GRAAL_DIR =$(UPDIR)/.. -#RRC_DIR =$(UPDIR)/../../../AS/L3/RRC - -CELL_UPDIR := $(shell /bin/pwd) -NAS_DIR := $(OPENAIR2_DIR)/NAS/DRIVER/CELLULAR/NASMT -RRC_DIR := $(OPENAIR2_DIR)/RRC/CELLULAR -EXTRA_CFLAGS += -I$(RRC_DIR) -DNODE_MT - -CFLAGS = -Wall -g -I$(NAS_DIR) -I$(RRC_DIR) - -COMPILE = $(CC) $(CFLAGS) -c - -OBJS = nascell_ioctl.o - -EXECUTABLE = gioctl - -# "all" is the default target. Simply make it point to myprogram. - -all: $(EXECUTABLE) - -# Define the components of the program, and how to link them together. -# These components are defined as dependencies; that is, they must be -# made up-to-date before the code is linked. - -$(EXECUTABLE): $(OBJS) - $(CC) $(CFLAGS) -o $(EXECUTABLE) $(OBJS) - -# Add any special rules here. - -# Specify that all .o files depend on .c files, and indicate how -# the .c files are converted (compiled) to the .o files. - -%.o: %.c - $(COMPILE) -o $@ $< - -clean: - -rm $(OBJS) $(EXECUTABLE) diff --git a/openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.c b/openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.c deleted file mode 100644 index 0b520ed151..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/CTL_TOOL/nascell_ioctl.c +++ /dev/null @@ -1,859 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#include "nascell_ioctl.h" -#include "rrc_nas_primitives.h" -//#include "rrc_qos.h" -//#include "graal_local.h" -#include "nasmt_constant.h" -#include "nasmt_iocontrol.h" -#define USHRT_MAX 255 -//--------------------------------------------------------------------------- -void print_error(int status) -{ - //--------------------------------------------------------------------------- - switch(status) { - case -NAS_ERROR_NOMEMORY: - printf(" The memory is low\n"); - break; - - case -NAS_ERROR_NORB: - printf(" The radio bearer is not identified\n"); - break; - - case -NAS_ERROR_NOTMT: - printf(" The entity must be a mobile\n"); - break; - - case -NAS_ERROR_NOTRG: - printf(" The entity must be an access router\n"); - break; - - case -NAS_ERROR_NOTIDLE: - printf(" The selected connection or radio bearer must be IDLE\n"); - break; - - case -NAS_ERROR_NOTCONNECTED: - printf(" The selected connection or radio bearer must be CONNECTED\n"); - break; - - case -NAS_ERROR_NOTCORRECTLCR: - printf(" The LCR value is not correct\n"); - break; - - case -NAS_ERROR_NOTCORRECTDIR: - printf(" The DIR value is not correct\n"); - break; - - case -NAS_ERROR_NOTCORRECTDSCP: - printf(" The DSCP value is not correct\n"); - break; - - case -NAS_ERROR_NOTCORRECTVERSION: - printf(" The version value is not correct\n"); - break; - - case -NAS_ERROR_NOTCORRECTRABI: - printf(" The rab_id value is not correct\n"); - break; - - case -NAS_ERROR_ALREADYEXIST: - printf(" Some components must not be duplicated\n"); - break; - - default: - printf(" Unknown error cause %d\n", status); - } -} - -//--------------------------------------------------------------------------- -void print_state(uint8_t state) -{ - //--------------------------------------------------------------------------- - switch(state) { - case NAS_IDLE: - printf("NAS_IDLE\n"); - return; - - // case NAS_STATE_CONNECTED:printf("NAS_STATE_CONNECTED\n");return; - // case NAS_STATE_ESTABLISHMENT_REQUEST:printf("NAS_STATE_ESTABLISHMENT_REQUEST\n");return; - // case NAS_STATE_ESTABLISHMENT_FAILURE:printf("NAS_STATE_ESTABLISHMENT_FAILURE\n");return; - // case NAS_STATE_RELEASE_FAILURE:printf("NAS_STATE_RELEASE_FAILURE\n");return; - case NAS_CX_FACH: - printf("NAS_CX_FACH\n"); - return; - - case NAS_CX_DCH: - printf("NAS_CX_DCH\n"); - return; - - case NAS_CX_RECEIVED: - printf("NAS_CX_RECEIVED\n"); - return; - - case NAS_CX_CONNECTING: - printf("NAS_CX_CONNECTING\n"); - return; - - case NAS_CX_RELEASING: - printf("NAS_CX_RELEASING\n"); - return; - - case NAS_CX_CONNECTING_FAILURE: - printf("NAS_CX_CONNECTING_FAILURE\n"); - return; - - case NAS_CX_RELEASING_FAILURE: - printf("NAS_CX_RELEASING_FAILURE\n"); - return; - - case NAS_RB_ESTABLISHING: - printf("NAS_RB_ESTABLISHING\n"); - return; - - case NAS_RB_RELEASING: - printf("NAS_RB_RELEASING\n"); - return; - - default: - printf(" Unknown state\n"); - } -} - -//--------------------------------------------------------------------------- -void print_usage_class() -{ - //--------------------------------------------------------------------------- - printf("Usage: gioctl class add {send |receive} -f {qos |del|ctl|dc} -cr [-dscp ] [-ip {6|4} ] [-p {tcp|udp|icmp4|icmp6} ]\n"); - printf("Usage: gioctl class del {send |receive} -cr [-dscp ] \n"); - printf("Usage: gioctl class list {send |receive} [-dscp ]\n"); -} -//--------------------------------------------------------------------------- -void print_usage_cx() -{ - //--------------------------------------------------------------------------- - printf("Usage: gioctl cx add \n"); - printf("Usage: gioctl cx del \n"); - printf("Usage: gioctl cx list\n"); -} -//--------------------------------------------------------------------------- -void print_usage_rb() -{ - //--------------------------------------------------------------------------- - printf("Usage: gioctl rb add \n"); - printf("Usage: gioctl rb list \n"); -} - -//--------------------------------------------------------------------------- -int main(int argc, char *argv[]) -{ - //--------------------------------------------------------------------------- - struct nas_ioctl gifr; - int err, fd; - - // Invalid number of arguments - if (argc<2) { - printf("Usage: gioctl statistic\n"); - print_usage_cx(); - print_usage_rb(); - print_usage_class(); - return -1; - } - - // Get an UDP IPv6 socket ?? - fd=socket(AF_INET6, SOCK_DGRAM, 0); - - if (fd<0) { - printf("Error opening socket\n"); - return 0; - } - - strcpy(gifr.name, "oai0"); - printf("Socket opened successfully\n"); - - /***************************/ - if (strcmp(argv[1], "statistic")==0) { - struct nas_msg_statistic_reply *msgrep; - gifr.type=NAS_MSG_STATISTIC_REQUEST; - gifr.msg=(char *)malloc(sizeof(msgrep)); - msgrep=(struct nas_msg_statistic_reply *)(gifr.msg); - printf(" Statistics requested\n"); - err=ioctl(fd, NASMT_IOCTL_RAL, &gifr); - - if (err<0) { - printf("IOCTL error, err=%d\n",err); - return -1; - } - - printf("tx_packets = %u, rx_packets = %u\n", msgrep->tx_packets, msgrep->rx_packets); - printf("tx_bytes = %u, rx_bytes = %u\n", msgrep->tx_bytes, msgrep->rx_bytes); - printf("tx_errors = %u, rx_errors = %u\n", msgrep->tx_errors, msgrep->rx_errors); - printf("tx_dropped = %u, rx_dropped = %u\n", msgrep->tx_dropped, msgrep->rx_dropped); - return 0; - } - - /***************************/ - if (strcmp(argv[1], "cx")==0) { - if (argc<3) { - print_usage_cx(); - return -1; - } - - /***/ - // printf("Usage: gioctl cx add \n"); - if (strcmp(argv[2], "add")==0) { - struct nas_msg_cx_establishment_request *msgreq; - struct nas_msg_cx_establishment_reply *msgrep; - - if (argc<5) { - print_usage_cx(); - return -1; - } - - gifr.type=NAS_MSG_CX_ESTABLISHMENT_REQUEST; - gifr.msg=(char *)malloc(sizeof(msgrep)lcr=strtoul(argv[3], NULL, 0); - msgreq->cellid=strtoul(argv[4], NULL, 0); - // - printf(" Connection establishment requested\n"); - err=ioctl(fd, NASMT_IOCTL_RAL, &gifr); - - if (err<0) { - printf("IOCTL error, err=%d\n",err); - perror("Connection establishment IOCTL error\n"); - return -1; - } - - if (msgrep->status<0) { - printf(" Connexion establishment failure: "); - print_error(msgrep->status); - return -1; - } - - return 0; - } - - /***/ - // printf("Usage: gioctl cx del \n"); - if (strcmp(argv[2], "del")==0) { - struct nas_msg_cx_release_request *msgreq; - struct nas_msg_cx_release_reply *msgrep; - - if (argc<4) { - print_usage_cx(); - return -1; - } - - gifr.type=NAS_MSG_CX_RELEASE_REQUEST; - gifr.msg=(char *)malloc(sizeof(msgrep)lcr=strtoul(argv[3], NULL, 0); - // - printf(" Connexion release requested\n"); - err=ioctl(fd, NASMT_IOCTL_RAL, &gifr); - - if (err<0) { - printf("IOCTL error, err=%d\n",err); - return -1; - } - - if (msgrep->status<0) { - printf(" Connexion release failure: "); - print_error(msgrep->status); - return -1; - } - - return 0; - } - - /***/ - // printf("Usage: gioctl cx list\n"); - if (strcmp(argv[2], "list")==0) { - uint8_t *msgrep; - uint8_t i; - struct nas_msg_cx_list_reply *list; - uint8_t lcr; - gifr.type=NAS_MSG_CX_LIST_REQUEST; - gifr.msg=(char *)malloc(NAS_LIST_CX_MAX*sizeof(struct nas_msg_cx_list_reply)+1); - msgrep=(uint8_t *)(gifr.msg); - // - printf(" Connexion list requested\n"); - err=ioctl(fd, NASMT_IOCTL_RAL, &gifr); - - if (err<0) { - printf("IOCTL error, err=%d\n",err); - return -1; - } - - printf("Lcr\t\tCellId\tIID4\tIID6\t\t\tnrb\tnsclass\tState\n"); - list=(struct nas_msg_cx_list_reply *)(msgrep+1); - - for(lcr=0; lcr \n"); - if (strcmp(argv[2], "add")==0) { - struct nas_msg_rb_establishment_request *msgreq; - struct nas_msg_rb_establishment_reply *msgrep; - - if (argc<6) { - print_usage_rb(); - return -1; - } - - gifr.type=NAS_MSG_RB_ESTABLISHMENT_REQUEST; - gifr.msg=(char *)malloc(sizeof(msgrep)lcr=strtoul(argv[3], NULL, 0); - msgreq->rab_id=strtoul(argv[4], NULL, 0); - msgreq->qos=strtoul(argv[5], NULL, 0); - // - printf(" Radio bearer establishment requested\n"); - err=ioctl(fd, NASMT_IOCTL_RAL, &gifr); - - if (err<0) { - printf("IOCTL error, err=%d\n",err); - return -1; - } - - if (msgrep->status<0) { - printf(" Radio bearer establishment failure: "); - print_error(msgrep->status); - return -1; - } - - return 0; - } - - /***/ - if (strcmp(argv[2], "del")==0) { - struct nas_msg_rb_release_request *msgreq; - struct nas_msg_rb_release_reply *msgrep; - - if (argc<5) { - print_usage_rb(); - return -1; - } - - gifr.type=NAS_MSG_RB_RELEASE_REQUEST; - gifr.msg=(char *)malloc(sizeof(msgrep)lcr=strtoul(argv[3], NULL, 0); - msgreq->rab_id=strtoul(argv[4], NULL, 0); - // - printf(" Radio Bearer release requested\n"); - err=ioctl(fd, NASMT_IOCTL_RAL, &gifr); - - if (err<0) { - printf("IOCTL error, err=%d\n",err); - return -1; - } - - if (msgrep->status<0) { - printf(" Radio bearer release failure: "); - print_error(msgrep->status); - return -1; - } - - return 0; - } - - /***/ - // printf("Usage: gioctl rb list \n"); - if (strcmp(argv[2], "list")==0) { - uint8_t *msgrep; - uint8_t rbi; - struct nas_msg_rb_list_reply *list; - struct nas_msg_rb_list_request *msgreq; - - if (argc<4) { - print_usage_rb(); - return -1; - } - - gifr.type=NAS_MSG_RB_LIST_REQUEST; - gifr.msg=(char *)malloc(NAS_LIST_RB_MAX*sizeof(struct nas_msg_rb_list_reply)+1); - msgreq=(struct nas_msg_rb_list_request *)(gifr.msg); - msgrep=(uint8_t *)(gifr.msg); - msgreq->lcr=strtoul(argv[3], NULL, 0); - // - printf(" Radio bearer list requested\n"); - err=ioctl(fd, NASMT_IOCTL_RAL, &gifr); - - if (err<0) { - printf("IOCTL error, err=%d\n",err); - return -1; - } - - printf("rab_id\t\tSapi\t\tQoS\t\tState\n"); - list=(struct nas_msg_rb_list_reply *)(msgrep+1); - - for(rbi=0; rbidir=NAS_DIRECTION_SEND; - msgreq->lcr=strtoul(argv[++i], NULL, 0); - ++i; - } else { - if (strcmp(argv[i], "receive")==0) { - msgreq->dir=NAS_DIRECTION_RECEIVE; - ++i; - } else { - print_usage_class(); - return -1; - } - } - - msgreq->classref=USHRT_MAX; - msgreq->dscp=NAS_DSCP_DEFAULT; - msgreq->version=NAS_VERSION_DEFAULT; - msgreq->protocol=NAS_PROTOCOL_DEFAULT; - msgreq->sport=NAS_PORT_DEFAULT; - msgreq->dport=NAS_PORT_DEFAULT; - msgreq->fct=0; - - while (iclassref=strtoul(argv[++i], NULL, 0); - ++i; - continue; - } - - if (strcmp(argv[i], "-dscp")==0) { - msgreq->dscp=strtoul(argv[++i], NULL, 0); - ++i; - continue; - } - - if (strcmp(argv[i], "-f")==0) { - ++i; - - if (strcmp(argv[i], "qos")==0) { - msgreq->fct=NAS_FCT_QOS_SEND; - msgreq->rab_id=strtoul(argv[++i], NULL, 0); - ++i; - continue; - } - - if (strcmp(argv[i], "del")==0) { - msgreq->fct=NAS_FCT_DEL_SEND; - msgreq->rab_id=0; - ++i; - continue; - } - - if (strcmp(argv[i], "ctl")==0) { - msgreq->fct=NAS_FCT_CTL_SEND; - msgreq->rab_id=0; - ++i; - continue; - } - - if (strcmp(argv[i], "dc")==0) { - msgreq->fct=NAS_FCT_DC_SEND; - msgreq->rab_id=0; - ++i; - continue; - } - - print_usage_class(); - return -1; - } - - if (strcmp(argv[i], "-ip")==0) { - ++i; - - if (strcmp(argv[i], "4")==0) { - if (msgreq->version!=NAS_VERSION_DEFAULT) { - print_usage_class(); - return -1; - } - - msgreq->version=NAS_VERSION_4; - inet_pton(AF_INET, argv[++i], (void *)(&msgreq->saddr)); - msgreq->splen=strtoul(argv[++i], NULL, 0); - inet_pton(AF_INET, argv[++i], (void *)(&msgreq->daddr)); - msgreq->dplen=strtoul(argv[++i], NULL, 0); - ++i; - continue; - } - - if (strcmp(argv[i], "6")==0) { - if (msgreq->version!=NAS_VERSION_DEFAULT) { - print_usage_class(); - return -1; - } - - msgreq->version=NAS_VERSION_6; - inet_pton(AF_INET6, argv[++i], (void *)(&msgreq->saddr)); - msgreq->splen=strtoul(argv[++i], NULL, 0); - inet_pton(AF_INET6, argv[++i], (void *)(&msgreq->daddr)); - msgreq->dplen=strtoul(argv[++i], NULL, 0); - ++i; - continue; - } - - print_usage_class(); - return -1; - } - - if (strcmp(argv[i], "-p")==0) { - ++i; - - if (strcmp(argv[i], "tcp")==0) { - if (msgreq->protocol!=NAS_PROTOCOL_DEFAULT) { - print_usage_class(); - return -1; - } - - msgreq->protocol=NAS_PROTOCOL_TCP; - msgreq->sport=strtoul(argv[++i], NULL, 0); - msgreq->dport=strtoul(argv[++i], NULL, 0); - ++i; - continue; - } - - if (strcmp(argv[i], "udp")==0) { - if (msgreq->protocol!=NAS_PROTOCOL_DEFAULT) { - print_usage_class(); - return -1; - } - - msgreq->protocol=NAS_PROTOCOL_UDP; - msgreq->sport=strtoul(argv[++i], NULL, 0); - msgreq->dport=strtoul(argv[++i], NULL, 0); - ++i; - continue; - } - - if (strcmp(argv[i], "icmp4")==0) { - if (msgreq->protocol!=NAS_PROTOCOL_DEFAULT) { - print_usage_class(); - return -1; - } - - msgreq->protocol=NAS_PROTOCOL_ICMP4; - msgreq->sport=strtoul(argv[++i], NULL, 0); - msgreq->dport=strtoul(argv[++i], NULL, 0); - ++i; - continue; - } - - if (strcmp(argv[i], "icmp6")==0) { - if (msgreq->protocol!=NAS_PROTOCOL_DEFAULT) { - print_usage_class(); - return -1; - } - - msgreq->protocol=NAS_PROTOCOL_ICMP6; - msgreq->sport=strtoul(argv[++i], NULL, 0); - msgreq->dport=strtoul(argv[++i], NULL, 0); - ++i; - continue; - } - - print_usage_class(); - return -1; - } - - print_usage_class(); - return -1; - } - - if ((msgreq->classref==USHRT_MAX)||(msgreq->fct==0)) { - print_usage_class(); - return -1; - } - - printf(" Class add requested\n"); - err=ioctl(fd, NASMT_IOCTL_RAL, &gifr); - - if (err<0) { - printf("IOCTL error, err=%d\n",err); - return -1; - } - - if (msgrep->status<0) { - printf(" Class add failure: "); - print_error(msgrep->status); - return -1; - } - - return 0; - } - - /***/ - if (strcmp(argv[2], "del")==0) { - uint8_t i; - struct nas_msg_class_del_request *msgreq; - struct nas_msg_class_del_reply *msgrep; - gifr.type=NAS_MSG_CLASS_DEL_REQUEST; - gifr.msg=(char *)malloc(sizeof(msgrep)dir=NAS_DIRECTION_SEND; - msgreq->lcr=strtoul(argv[++i], NULL, 0); - ++i; - } else { - if (strcmp(argv[i], "receive")==0) { - msgreq->dir=NAS_DIRECTION_RECEIVE; - ++i; - } else { - print_usage_class(); - return -1; - } - } - - msgreq->classref=USHRT_MAX; - msgreq->dscp=NAS_DSCP_DEFAULT; - - while (iclassref=strtoul(argv[++i], NULL, 0); - ++i; - continue; - } - - if (strcmp(argv[i], "-dscp")==0) { - msgreq->dscp=strtoul(argv[++i], NULL, 0); - ++i; - continue; - } - - print_usage_class(); - return -1; - } - - if (msgreq->classref==USHRT_MAX) { - print_usage_class(); - return -1; - } - - printf(" Class del requested\n"); - err=ioctl(fd, NASMT_IOCTL_RAL, &gifr); - - if (err<0) { - printf("IOCTL error, err=%d\n",err); - return -1; - } - - if (msgrep->status<0) { - printf(" Class add failure: "); - print_error(msgrep->status); - return -1; - } - - return 0; - } - - /***/ - if (strcmp(argv[2], "list")==0) { - uint8_t *msgrep; - uint8_t cli, i; - struct nas_msg_class_list_reply *list; - struct nas_msg_class_list_request *msgreq; - char addr[45]; - - if (argc<4) { - print_usage_class(); - return -1; - } - - gifr.type=NAS_MSG_CLASS_LIST_REQUEST; - gifr.msg=(char *)malloc(NAS_LIST_CLASS_MAX*sizeof(struct nas_msg_class_list_reply)+1); - - if (gifr.msg==NULL) { - printf(" No memory\n"); - return -1; - } - - msgreq=(struct nas_msg_class_list_request *)(gifr.msg); - msgrep=(uint8_t *)(gifr.msg); - i=3; - - if (strcmp(argv[i], "send")==0) { - msgreq->dir=NAS_DIRECTION_SEND; - msgreq->lcr=strtoul(argv[++i], NULL, 0); - ++i; - } else { - if (strcmp(argv[i], "receive")==0) { - msgreq->dir=NAS_DIRECTION_RECEIVE; - msgreq->lcr=0; - ++i; - } else { - print_usage_class(); - return -1; - } - } - - msgreq->dscp=NAS_DSCP_DEFAULT; - - while (idscp=strtoul(argv[++i], NULL, 0); - } - - printf(" Classifier list requested\n"); - err=ioctl(fd, NASMT_IOCTL_RAL, &gifr); - - // - if (err<0) { - printf("IOCTL error, err=%d\n",err); - return -1; - } - - printf("Lcr\trab_id\tCref\tFct\t(Vers., saddr, daddr)\t\t\t\t(Proto., Sport, Dport)\n"); - list=(struct nas_msg_class_list_reply *)(msgrep+1); - - for(cli=0; cli -#include -#include -#include -#include -#include -#include -#include -//#include - -//#include -//#define GRAAL_STATE_IDLE 0 -//#define GRAAL_STATE_CONNECTED 1 -//#define GRAAL_STATE_ESTABLISHMENT_REQUEST 2 -//#define GRAAL_STATE_ESTABLISHMENT_FAILURE 3 -//#define GRAAL_STATE_RELEASE_FAILURE 4 - -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; - -extern int inet_pton(int af, const char *src, void *dst); -extern char *inet_ntop(int af, const void *src, char *dst, size_t sise); - -#endif //_IOCTL_H diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/Makefile b/openair2/NAS/DRIVER/CELLULAR/NASMT/Makefile deleted file mode 100755 index ec14990d63..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/Makefile +++ /dev/null @@ -1,79 +0,0 @@ -# NAS CELLULAR Driver makefile -# -include $(OPENAIR_DIR)/common/utils/Makefile.inc -NAS_UPDIR := $(shell /bin/pwd) - -#################################################### -# D E B U G F L A G S -#################################################### - -#################################################### -# EXTRA COMPILER FLAGS -#################################################### -EXTRA_CFLAGS = -fno-common -fno-stack-protector -mpreferred-stack-boundary=4 $(if $(SET_X64),-DARCH_64,) $(if $(SET_X64),-mcmodel=kernel,) $(if $(SET_X64),-m64,) - -ifdef ADDRCONF -EXTRA_CFLAGS += -DADDRCONF -endif - -ifdef NAS_DRIVER_TYPE_ETHERNET -EXTRA_CFLAGS += -DNAS_DRIVER_TYPE_ETHERNET -endif - - -ifdef PDCP_USE_NETLINK -EXTRA_CFLAGS += -DPDCP_USE_NETLINK -else -EXTRA_CFLAGS += $(shell rtai-config --module-cflags) -DRTAI -D__IN_RTAI__ -Wall -endif - -ifdef LOOPBACK -EXTRA_CFLAGS += -DLOOPBACK_TEST -endif - -ifdef ADDRESS_FIX -EXTRA_CFLAGS += -DNAS_ADDRESS_FIX -endif - -#################################################### -# NASMTCELL extra compilation flags -#################################################### -#RTAI=1 -RRC_DIR := $(OPENAIR2_DIR)/RRC/CELLULAR -EXTRA_CFLAGS += -I$(RRC_DIR) -DNODE_MT - -#################################################### -# LOADABLE MODULE GOALS -#################################################### -obj-m += nascellmt.o -nascellmt-objs += nasmt_device.o -nascellmt-objs += nasmt_common.o -nascellmt-objs += nasmt_iocontrol.o -nascellmt-objs += nasmt_classifier.o -nascellmt-objs += nasmt_tool.o -nascellmt-objs += nasmt_ascontrol.o -ifdef PDCP_USE_NETLINK -nascellmt-objs += nasmt_netlink.o -endif - -#################################################### -# REVOIR LE CLEAN -#################################################### - -#netlink.ko: - #make $(x)$(y) PDCP_USE_NETLINK=1 V=1 -C $(KERNEL_DIR) M=`pwd` modules - -#nasmesh.ko: -# make V=1 -C $(KERNEL_DIR) M=`pwd` modules -print: - @echo subversion : $(SUBVERSION) - @echo RRC_DIR $(RRC_DIR) -clean: - rm -f *.ko - rm -f .*.ko.cmd - rm -f .*.o.cmd - rm -f *.o - rm -f *.mod.c - find . -name *.ko -delete - find . -name *.o -delete - find . -name *.mod.c -delete diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_ascontrol.c b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_ascontrol.c deleted file mode 100644 index 666cbb1a04..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_ascontrol.c +++ /dev/null @@ -1,1152 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasmt_ascontrol.c -* \brief Access Stratum Control functions for OpenAirInterface CELLULAR version - MT -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#ifdef NODE_MT -#include "nasmt_variables.h" -#include "nasmt_proto.h" - -//--------------------------------------------------------------------------- -void nasmt_ASCTL_init(void) -{ - //--------------------------------------------------------------------------- - // struct cx_entity *cx; - int i; - gpriv->next_sclassref = NASMT_DEFAULTRAB_CLASSREF; - - for (i = 0; icx->joined_services[i]= -1; - } - - printk("nasmt_ASCTL_init Complete\n"); -} - -//--------------------------------------------------------------------------- -int nasmt_ASCTL_write(int sap, unsigned char *data_buffer, unsigned int data_length) -{ - //--------------------------------------------------------------------------- - int bytes_wrote = 0; -#ifdef PDCP_USE_NETLINK - unsigned char xmit_buffer [NAS_MESSAGE_MAXLEN]; - //MT xmit on DC-SAP only - xmit_buffer[0] = RRC_NAS_DC0_IN; - memcpy (&((char*)xmit_buffer)[1], data_buffer, data_length); - bytes_wrote = nasmt_netlink_send(xmit_buffer,data_length, NASNL_DEST_RRC); -#else - //bytes_wrote = rtf_put(cx->sap[NAS_DC_INPUT_SAPI], p, p->length); //original version - bytes_wrote = rtf_put(sap, data_buffer, data_length); -#endif //PDCP_USE_NETLINK - return bytes_wrote; -} - -//--------------------------------------------------------------------------- -//For demo, add automatically a classifier -//Equivalent to class add send 0 -f qos -cr 0 -void nasmt_ASCTL_start_default_sclassifier(struct cx_entity *cx,struct rb_entity *rb) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *gc; - - // Start debug information -#ifdef NAS_DEBUG_CLASS - printk("\nnasmt_ASCTL_start_default_sclass - begin \n"); -#endif - - if (!cx || !rb) { - printk("nasmt_ASCTL_start_default_sclass - input parameter cx or rb is NULL \n"); - return; - } - - // End debug information - // - gc=nasmt_CLASS_add_sclassifier(cx, NAS_DSCP_DEFAULT, gpriv->next_sclassref); - - // gc=nasmt_CLASS_add_sclassifier(cx, 5, 0); - if (gc==NULL) { - printk("nasmt_ASCTL_start_default_sclass - Error - Classifier not added \n"); - return; - } - - gc->fct = nasmt_COMMON_QOS_send; - gc->rab_id =rb->rab_id; - gc->rb= rb; - gc->version = NASMT_DEFAULTRAB_IPVERSION; - gc->protocol= NAS_PROTOCOL_DEFAULT; - gc->dplen= NAS_DEFAULT_IPv6_PREFIX_LENGTH; - //gc->daddr.ipv6.s6_addr32[2] = cx->iid6[0]; - //gc->daddr.ipv6.s6_addr32[3] = cx->iid6[1]; - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_ASCTL_start_default_sclass - end \n"); - nasmt_TOOL_print_classifier(gc); -#endif -} - -//--------------------------------------------------------------------------- -//For demo, add automatically a classifier -//Equivalent to class add send 0 -f qos -cr 0 -void nasmt_ASCTL_start_sclassifier(struct cx_entity *cx,struct rb_entity *rb) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *gc; - - // Start debug information -#ifdef NAS_DEBUG_CLASS - printk("\nnasmt_ASCTL_start_sclass - begin \n"); -#endif - - if (cx==NULL) { - printk("nasmt_ASCTL_start_sclass - input parameter cx is NULL \n"); - return; - } - - if (rb==NULL) { - printk("nasmt_ASCTL_start_sclass - input parameter rb is NULL \n"); - return; - } - - // End debug information - // - gc=nasmt_CLASS_add_sclassifier(cx, rb->dscp, gpriv->next_sclassref); - - // gc=nasmt_CLASS_add_sclassifier(cx, 5, 0); - if (gc==NULL) { - printk("nasmt_ASCTL_start_sclass - Error - Classifier not added \n"); - return; - } - - gc->fct = nasmt_COMMON_QOS_send; - gc->rab_id =rb->rab_id; - gc->rb= rb; - gc->version = NASMT_DEFAULTRAB_IPVERSION; - gc->protocol= NAS_PROTOCOL_DEFAULT; - gc->dplen= NAS_DEFAULT_IPv6_PREFIX_LENGTH; - gc->daddr.ipv6.s6_addr32[2] = cx->iid6[0]; - gc->daddr.ipv6.s6_addr32[3] = cx->iid6[1]; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_ASCTL_start_sclass - end \n"); - nasmt_TOOL_print_classifier(gc); -#endif -} - -//--------------------------------------------------------------------------- -void nasmt_ASCTL_timer(unsigned long data) -{ - //--------------------------------------------------------------------------- - uint8_t cxi; - struct cx_entity *cx; - struct rb_entity *rb; - spin_lock(&gpriv->lock); -#ifdef NAS_DEBUG_TIMER - printk("nasmt_ASCTL_timer - begin \n"); -#endif - (gpriv->timer).function=nasmt_ASCTL_timer; - (gpriv->timer).expires=jiffies+NAS_TIMER_TICK; - (gpriv->timer).data=0L; - - for (cxi=0; cxicx+cxi; - - if (cx==NULL) { -#ifdef NAS_DEBUG_TIMER - printk("nasmt_ASCTL_timer - No pointer for connection %d \n", cxi); -#endif - continue; - } - - if (cx->countimer!=NAS_TIMER_IDLE) { -#ifdef NAS_DEBUG_TIMER - printk("nasmt_ASCTL_timer: lcr %u, countimer %u\n", cx->lcr, cx->countimer); -#endif - - if (cx->countimer==0) { - switch (cx->state) { - case NAS_CX_CONNECTING: - case NAS_CX_CONNECTING_FAILURE: - if (cx->retryretry_limit) - nasmt_ASCTL_DC_send_cx_establish_request(cx); - else { - printk("nasmt_ASCTL_timer: Establishment failure\n"); - cx->state=NAS_IDLE; - cx->retry=0; - cx->countimer=NAS_TIMER_IDLE; - } - - break; - - case NAS_CX_RELEASING_FAILURE: - nasmt_ASCTL_DC_send_cx_release_request(cx); - break; - - default: - printk("nasmt_ASCTL_timer: default value\n"); - cx->countimer=NAS_TIMER_IDLE; - } - } else - --cx->countimer; - } - - for (rb=cx->rb; rb!=NULL; rb=rb->next) { - if (rb->countimer!=NAS_TIMER_IDLE) { -#ifdef NAS_DEBUG_TIMER - printk("nasmt_ASCTL_timer : rb countimer %d, rb state %d\n", rb->countimer, rb->state); -#endif - - if (rb->countimer==0) { - switch (rb->state) { - case NAS_RB_DCH: -#ifdef DEMO_3GSM - if (cx->num_rb == 1) { - nasmt_ASCTL_start_default_sclassifier(cx, rb); - } - -#endif - nasmt_ASCTL_start_sclassifier(cx, rb); - rb->countimer=NAS_TIMER_IDLE; - break; - - default: - rb->countimer=NAS_TIMER_IDLE; - } - } else { - --rb->countimer; - printk("nasmt_ASCTL_timer : rb countimer-- %d, rb state %d\n", rb->countimer, rb->state); - } - } - } - } - - add_timer(&gpriv->timer); - spin_unlock(&gpriv->lock); -} - -//--------------------------------------------------------------------------- -// Request the sleep of a connexion -int nasmt_ASCTL_enter_sleep_mode(struct cx_entity *cx) -{ - //--------------------------------------------------------------------------- - uint8_t sig_category; - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_enter_sleep_mode - begin \n"); -#endif - - if (!cx) { - printk("nasmt_ASCTL_enter_sleep_mode - input parameter cx is NULL \n"); - return NAS_ERROR_NOTCORRECTVALUE; - } - - // End debug information - // send peer message to NASRG - sig_category = NAS_CMD_ENTER_SLEEP; - printk("nasmt_ASCTL_enter_sleep_mode - sig_category %u \n", sig_category); - nasmt_ASCTL_DC_send_peer_sig_data_request(cx, sig_category); - cx->state=NAS_CX_RELEASING; - return 0; -} - -//--------------------------------------------------------------------------- -// Request to reactivate a connexion -int nasmt_ASCTL_leave_sleep_mode(struct cx_entity *cx) -{ - //--------------------------------------------------------------------------- - uint8_t sig_category; - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_leave_sleep_mode - begin \n"); -#endif - - if (!cx) { - printk("nasmt_ASCTL_leave_sleep_mode - input parameter cx is NULL \n"); - return NAS_ERROR_NOTCORRECTVALUE; - } - - // End debug information - cx->state=NAS_CX_DCH; - // send peer message to NASRG - sig_category = NAS_CMD_LEAVE_SLEEP; - printk("nasmt_ASCTL_leave_sleep_mode - sig_category %u \n", sig_category); - nasmt_ASCTL_DC_send_peer_sig_data_request(cx, sig_category); - return 0; -} - -/*********************************************** - * Transmit Functions * - ***********************************************/ - -//--------------------------------------------------------------------------- -// Request the establishment of a connexion (DC channel) -int nasmt_ASCTL_DC_send_cx_establish_request(struct cx_entity *cx) -{ - //--------------------------------------------------------------------------- - struct nas_ue_dc_element *p; - int bytes_wrote = 0; - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_send_cx_establish - begin \n"); -#endif - - if (!cx) { - printk("nasmt_ASCTL_DC_send_cx_establish - input parameter cx is NULL \n"); - return NAS_ERROR_NOTCORRECTVALUE; - } - - // End debug information - - switch (cx->state) { - case NAS_CX_CONNECTING: - case NAS_CX_CONNECTING_FAILURE: - case NAS_IDLE: - p= (struct nas_ue_dc_element *)(gpriv->xbuffer); - p->type = CONN_ESTABLISH_REQ; - p->length = NAS_TL_SIZE + sizeof(struct NASConnEstablishReq); - p->nasUEDCPrimitive.conn_establish_req.localConnectionRef = cx->lcr; - p->nasUEDCPrimitive.conn_establish_req.cellId = cx->cellid; -#ifdef NAS_DEBUG_DC - printk ("\nCONN_ESTABLISH_REQ Buffer to Xmit: "); - nasmt_TOOL_print_buffer((char *)p,p->length); -#endif - ++cx->retry; - - //bytes_wrote = rtf_put(cx->sap[GRAAL_DC_INPUT_SAPI], p, p->length); //original version - bytes_wrote = nasmt_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (unsigned char *)p, p->length); - //printk("nasmt_ASCTL_DC_send_cx_establish_request - Wrote %d bytes to RRC NAS_DC_INPUT_SAPI\n", bytes_wrote); - - cx->countimer=gpriv->timer_establishment; - - if (bytes_wrote==p->length) { - cx->state=NAS_CX_CONNECTING; -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_send_cx_establish - Message sent successfully in DC-FIFO\n"); - printk(" Local Connection reference %u\n", p->nasUEDCPrimitive.conn_establish_req.localConnectionRef); - printk(" Cell Identification %u\n", p->nasUEDCPrimitive.conn_establish_req.cellId); - nasmt_TOOL_print_state(cx->state); -#endif - } else { - cx->state=NAS_CX_CONNECTING_FAILURE; - printk("nasmt_ASCTL_DC_send_cx_establish - Message sent failure in DC-FIFO\n"); - nasmt_TOOL_print_state(cx->state); - } - - return bytes_wrote; - - default: - return -NAS_ERROR_NOTIDLE; -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_send_cx_establish - NAS_ERROR_NOTIDLE \n"); -#endif - } -} - -//--------------------------------------------------------------------------- -// Request the release of a connexion (DC channel) -int nasmt_ASCTL_DC_send_cx_release_request(struct cx_entity *cx) -{ - //--------------------------------------------------------------------------- - struct nas_ue_dc_element *p; - int bytes_wrote = 0; - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_send_cx_release - begin \n"); -#endif - - if (cx==NULL) { - printk("nasmt_ASCTL_DC_send_cx_release - input parameter cx is NULL \n"); - return NAS_ERROR_NOTCORRECTVALUE; - } - - // End debug information - switch (cx->state) { - case NAS_CX_RELEASING_FAILURE: - case NAS_CX_DCH: - p= (struct nas_ue_dc_element *)(gpriv->xbuffer); - p->type = CONN_RELEASE_REQ; - p->length = NAS_TL_SIZE + sizeof(struct NASConnReleaseReq); - p->nasUEDCPrimitive.conn_release_req.localConnectionRef = cx->lcr; - p->nasUEDCPrimitive.conn_release_req.releaseCause = NAS_CX_RELEASE_UNDEF_CAUSE; - - //bytes_wrote = rtf_put(cx->sap[NAS_DC_INPUT_SAPI], p, p->length); //original version - bytes_wrote = nasmt_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (unsigned char *)p, p->length); - //printk("nasmt_ASCTL_DC_send_cx_release - Wrote %d bytes to RRC NAS_DC_INPUT_SAPI\n", bytes_wrote); - - if (bytes_wrote==p->length) { - cx->state=NAS_IDLE; - cx->iid4=0; - // nasmt_TOOL_imei2iid(NAS_NULL_IMEI, (uint8_t *)cx->iid6); - nasmt_COMMON_flush_rb(cx); - nasmt_CLASS_flush_sclassifier(cx); - -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_send_cx_release - Message sent successfully in DC-FIFO\n"); - printk(" Local Connection Reference %u\n", p->nasUEDCPrimitive.conn_release_req.localConnectionRef); - printk(" Release Cause %u\n", p->nasUEDCPrimitive.conn_release_req.releaseCause); - nasmt_TOOL_print_state(cx->state); -#endif - } else { - ++cx->retry; - cx->countimer=gpriv->timer_release; - cx->state=NAS_CX_RELEASING_FAILURE; - printk("nasmt_ASCTL_DC_send_cx_release - Message sent failure in DC-FIFO\n"); - nasmt_TOOL_print_state(cx->state); - } - - return bytes_wrote; - - default: - return -NAS_ERROR_NOTCONNECTED; -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_send_cx_release - NAS_ERROR_NOTCONNECTED \n"); -#endif - } -} - -//--------------------------------------------------------------------------- -// Request the transfer of data (DC SAP) -void nasmt_ASCTL_DC_send_sig_data_request(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc) -{ - //--------------------------------------------------------------------------- - struct nas_ue_dc_element *p; - char data_type = 'A'; - int bytes_wrote = 0; -#ifdef PDCP_USE_NETLINK - unsigned char xbuffer[NAS_MESSAGE_MAXLEN]; - int count=0; -#endif - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_send_sig_data - begin \n"); -#endif - - if (!skb || !gc || !cx) { - printk("nasmt_ASCTL_DC_send_sig_data - input parameter skb, gc or cx is NULL \n"); - return; - } - - // End debug information - if (cx->state!=NAS_CX_DCH) { - printk("nasmt_ASCTL_DC_send_sig_data - Not connected, so the message is dropped\n"); - ++gpriv->stats.tx_dropped; - return; - } - - p = (struct nas_ue_dc_element *)(gpriv->xbuffer); - p->type = DATA_TRANSFER_REQ; - p->length = NAS_TL_SIZE + sizeof(struct NASDataReq); - p->nasUEDCPrimitive.data_transfer_req.localConnectionRef = cx->lcr; - p->nasUEDCPrimitive.data_transfer_req.priority = 3; // TBD - p->nasUEDCPrimitive.data_transfer_req.nasDataLength = (skb->len)+1; //adds category character - - //bytes_wrote = rtf_put(cx->sap[NAS_DC_INPUT_SAPI], p, p->length); //original version -#ifdef PDCP_USE_NETLINK - memcpy(xbuffer,(unsigned char *)p, p->length); - count = p->length; - bytes_wrote = count; -#else - bytes_wrote = nasmt_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (unsigned char *)p, p->length); -#endif - //printk("nasmt_ASCTL_DC_send_sig_data - Wrote %d bytes to RRC NAS_DC_INPUT_SAPI\n", bytes_wrote); - - if (bytes_wrote!=p->length) { - printk("nasmt_ASCTL_DC_send_sig_data - Header sent failure in DC-FIFO\n"); - return; - } - -#ifdef PDCP_USE_NETLINK - memcpy(&(xbuffer[count]),(unsigned char *)&data_type, 1); - count += 1; - bytes_wrote = count; -#else - bytes_wrote += nasmt_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (unsigned char *)&data_type, 1); -#endif - -#ifdef PDCP_USE_NETLINK - memcpy(&(xbuffer[count]),(unsigned char *)skb->data, skb->len); - count += skb->len; - bytes_wrote = nasmt_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], xbuffer, count); -#else - bytes_wrote += nasmt_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (unsigned char *)skb->data, skb->len); -#endif - - if (bytes_wrote != p->length + skb->len + 1) { - printk("nasmt_ASCTL_DC_send_sig_data - Data sent failure in DC-FIFO\n"); - return; - } - - gpriv->stats.tx_bytes += skb->len; - gpriv->stats.tx_packets ++; -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_send_sig_data - end \n"); -#endif -} - -//--------------------------------------------------------------------------- -// Request the transfer of data (DC SAP) -void nasmt_ASCTL_DC_send_peer_sig_data_request(struct cx_entity *cx, uint8_t sig_category) -{ - //--------------------------------------------------------------------------- - struct nas_ue_dc_element *p; - uint8_t nasmt_data[10]; - unsigned int nasmt_length; - char data_type = 'Z'; - int bytes_wrote = 0; -#ifdef PDCP_USE_NETLINK - unsigned char xbuffer[NAS_MESSAGE_MAXLEN]; - int count=0; -#endif - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_send_peer_sig_data - begin \n"); -#endif - - if (!cx) { - printk("nasmt_ASCTL_DC_send_peer_sig_data - input parameter cx is NULL \n"); - return; - } - - // End debug information - - if (cx->state!=NAS_CX_DCH) { - printk("nasmt_ASCTL_DC_send_peer_sig_data: Not connected, so the message is dropped\n"); - return; - } - - // Initialize peer message - nasmt_length = 10; - memset (nasmt_data, 0, nasmt_length); - nasmt_data[0]= sig_category; - // - p = (struct nas_ue_dc_element *)(gpriv->xbuffer); - p->type = DATA_TRANSFER_REQ; - p->length = NAS_TL_SIZE + sizeof(struct NASDataReq); - p->nasUEDCPrimitive.data_transfer_req.localConnectionRef = cx->lcr; - p->nasUEDCPrimitive.data_transfer_req.priority = 3; // TBD - p->nasUEDCPrimitive.data_transfer_req.nasDataLength = (nasmt_length)+1; //adds category character - - //bytes_wrote = rtf_put(cx->sap[NAS_DC_INPUT_SAPI], p, p->length); //original version -#ifdef PDCP_USE_NETLINK - memcpy(xbuffer,(unsigned char *)p, p->length); - count = p->length; - bytes_wrote = count; -#else - bytes_wrote = nasmt_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (unsigned char *)p, p->length); -#endif - //printk("nasmt_ASCTL_DC_send_sig_data - Wrote %d bytes to RRC NAS_DC_INPUT_SAPI\n", bytes_wrote); - - if (bytes_wrote!=p->length) { - printk("nasmt_ASCTL_DC_send_peer_sig_data - Header sent failure in DC-FIFO\n"); - return; - } - -#ifdef PDCP_USE_NETLINK - memcpy(&(xbuffer[count]),(unsigned char *)&data_type, 1); - count += 1; -#else - bytes_wrote += nasmt_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (unsigned char *)&data_type, 1); -#endif - -#ifdef PDCP_USE_NETLINK - memcpy(&(xbuffer[count]),(unsigned char *)nasmt_data, nasmt_length); - count += nasmt_length; - bytes_wrote = nasmt_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], xbuffer, count); -#else - bytes_wrote += nasmt_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (char *)nasmt_data, nasmt_length); -#endif - - if (bytes_wrote != p->length + nasmt_length + 1) { - printk("nasmt_ASCTL_DC_send_peer_sig_data - Data sent failure in DC-FIFO\n"); - return; - } - -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_send_peer_sig_data - end \n"); -#endif -} - -/*************************************************************************** - Reception side - ***************************************************************************/ -//--------------------------------------------------------------------------- -// Decode CONN_ESTABLISH_RESP message from RRC -void nasmt_ASCTL_DC_decode_cx_establish_resp(struct cx_entity *cx, struct nas_ue_dc_element *p) -{ - //--------------------------------------------------------------------------- - - uint8_t sig_category; - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_decode_cx_establish - begin \n"); -#endif - - if (!cx || !p) { - printk("nasmt_ASCTL_DC_decode_cx_establish - input parameter cx or p is NULL \n"); - return; - } - - // End debug information - cx->retry=0; - - if (p->nasUEDCPrimitive.conn_establish_resp.status == TERMINATED) { - cx->state=NAS_CX_DCH; //to be changed to NAS_CX_FACH - cx->iid4=1; - nasmt_TOOL_imei2iid(NAS_RG_IMEI, (uint8_t *)cx->iid6); - sig_category = NAS_CMD_OPEN_RB; - //For demo, add automatically a radio bearer -#ifdef DEMO_3GSM - printk("nasmt_ASCTL_DC_decode_cx_establish - sig_category %u \n", sig_category); - nasmt_ASCTL_DC_send_peer_sig_data_request(cx, sig_category); -#endif - } else { - cx->state=NAS_IDLE; - } - -#ifdef NAS_DEBUG_DC - printk(" nasmt_ASCTL_DC_decode_cx_establish: CONN_ESTABLISH_RESP\n"); - printk(" Local Connection reference %u\n",p->nasUEDCPrimitive.conn_establish_resp.localConnectionRef); - printk(" Connection Establishment status %u\n",p->nasUEDCPrimitive.conn_establish_resp.status); - nasmt_TOOL_print_state(cx->state); -#endif -} - -//--------------------------------------------------------------------------- -// Decode CONN_LOSS_IND message from RRC -void nasmt_ASCTL_DC_decode_cx_loss_ind(struct cx_entity *cx, struct nas_ue_dc_element *p) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_decode_cx_loss - begin \n"); -#endif - - if (cx==NULL) { - printk("nasmt_ASCTL_DC_decode_cx_loss - input parameter cx is NULL \n"); - return; - } - - if (p==NULL) { - printk("nasmt_ASCTL_DC_decode_cx_loss - input parameter p is NULL \n"); - return; - } - - // End debug information - cx->state=NAS_IDLE; - cx->iid4=0; - //nasmt_TOOL_imei2iid(NAS_NULL_IMEI, (uint8_t *)cx->iid6); - nasmt_COMMON_flush_rb(cx); -#ifdef NAS_DEBUG_DC - printk(" nasmt_ASCTL_DC_decode_cx_loss: CONN_LOSS_IND reception\n"); - printk(" Local Connection reference %u\n", p->nasUEDCPrimitive.conn_loss_ind.localConnectionRef); - nasmt_TOOL_print_state(cx->state); -#endif -} - -//--------------------------------------------------------------------------- -// Decode CONN_RELEASE_IND message from RRC -//void nasmt_ASCTL_DC_decode_cx_release_ind(struct cx_entity *cx, struct nas_ue_dc_element *p){ -//--------------------------------------------------------------------------- -// printk("\t\tCONN_RELEASE_IND\n"); -// printk("\t\tLocal Connection reference %u\n", p->nasUEDCPrimitive.conn_release_ind.localConnectionRef); -// printk("\t\tRelease cause %u\n", p->nasRGDCPrimitive.conn_release_ind.releaseCause); -// if (gpriv->cx[cxi].state==NAS_CX_DCH) -// { -// gpriv->cx[cxi].state=NAS_IDLE; -// printk("\t\tMobile no more connected\n"); -// return bytes_read; -// } -// printk("\t\tIncoherent state %u\n", gpriv->cx[cxi].state); -// return bytes_read; -//} - -//--------------------------------------------------------------------------- -// Decode DATA_TRANSFER_IND message from RRC -void nasmt_ASCTL_DC_decode_sig_data_ind(struct cx_entity *cx, struct nas_ue_dc_element *p) -{ - //--------------------------------------------------------------------------- - // struct pdcp_data_ind_header_t *pdcph; - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_decode_sig_data - begin \n"); -#endif - - if (!cx || !p) { - printk("nasmt_ASCTL_DC_decode_sig_data - input parameter cx or p is NULL \n"); - return; - } - - // End debug information - -#ifdef NAS_DEBUG_DC - printk(" nasmt_ASCTL_DC_decode_sig_data: DATA_TRANSFER_IND reception\n"); - printk(" Local Connection reference %u\n",p->nasUEDCPrimitive.data_transfer_ind.localConnectionRef); - printk(" Signaling Priority %u\n",p->nasUEDCPrimitive.data_transfer_ind.priority); - printk(" NAS Data length %u\n",p->nasUEDCPrimitive.data_transfer_ind.nasDataLength); - printk(" NAS Data string %s\n", (uint8_t *)p+p->length); -#endif - - //nasmt_COMMON_receive(p->length, p->nasUEDCPrimitive.data_transfer_ind.nasDataLength, cx->sap[GRAAL_DC_OUTPUT_SAPI]); // original -#ifndef PDCP_USE_NETLINK - //void nasmt_COMMON_receive(uint16_t bytes_read, uint16_t payload_length, void *data_buffer, int rb_id, int sap); - // data_buffer is NULL because FIFO should be read directly in the skbuff (LITE has an intermediary buffer) - nasmt_COMMON_receive(p->length, p->nasUEDCPrimitive.data_transfer_ind.nasDataLength, NULL, 2, cx->sap[NAS_DC_OUTPUT_SAPI]); -#else - nasmt_COMMON_receive(p->length, p->nasUEDCPrimitive.data_transfer_ind.nasDataLength, (unsigned char *)p+p->length, 2, 0); -#endif - -} -//--------------------------------------------------------------------------- -// Decode RB_ESTABLISH_IND message from RRC -void nasmt_ASCTL_DC_decode_rb_establish_ind(struct cx_entity *cx, struct nas_ue_dc_element *p) -{ - //--------------------------------------------------------------------------- - struct rb_entity *rb; - int hard_coded_rbId = 3; - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_decode_rb_establish - begin \n"); -#endif - - if (cx==NULL) { - printk("nasmt_ASCTL_DC_decode_rb_establish - input parameter cx is NULL \n"); - return; - } - - if (p==NULL) { - printk("nasmt_ASCTL_DC_decode_rb_establish - input parameter p is NULL \n"); - return; - } - - // End debug information - // TEMP -MW - 26/9/13- Overwrite the rb_id sent by RRC - p->nasUEDCPrimitive.rb_establish_ind.rbId = hard_coded_rbId; - // TEMP -MW - 26/9/13- Rest should be kept unchanged - rb=nasmt_COMMON_search_rb(cx, p->nasUEDCPrimitive.rb_establish_ind.rbId); - - if (rb==NULL) { - rb=nasmt_COMMON_add_rb(cx, p->nasUEDCPrimitive.rb_establish_ind.rbId, p->nasUEDCPrimitive.rb_establish_ind.QoSclass); - rb->state=NAS_RB_DCH; - cx->state=NAS_CX_DCH; - rb->dscp = p->nasUEDCPrimitive.rb_establish_ind.dscp; - rb->sapi = p->nasUEDCPrimitive.rb_establish_ind.sapId; - rb->countimer=1; -#ifdef NAS_DEBUG_DC - printk(" nasmt_ASCTL_DC_decode_rb_establish: RB_ESTABLISH_IND reception\n"); - printk(" Local Connection reference %u\n",p->nasUEDCPrimitive.rb_establish_ind.localConnectionRef); - printk(" Radio Bearer Identity %u \n",p->nasUEDCPrimitive.rb_establish_ind.rbId); - printk(" QoS Traffic Class %u\n",p->nasUEDCPrimitive.rb_establish_ind.QoSclass); - printk(" DSCP Code %u\n",p->nasUEDCPrimitive.rb_establish_ind.dscp); - printk(" SAP Id %u\n",p->nasUEDCPrimitive.rb_establish_ind.sapId); - nasmt_TOOL_print_state(cx->state); - nasmt_TOOL_print_rb_entity(rb); -#endif - } else - printk("NAS_MT_DC_DECODE_RB_ESTABLISH_IND: RB_ESTABLISH_IND reception, Radio bearer already opened\n"); -} - -//--------------------------------------------------------------------------- -// Decode RB_RELEASE_IND message from RRC -void nasmt_ASCTL_DC_decode_rb_release_ind(struct cx_entity *cx, struct nas_ue_dc_element *p) -{ - //--------------------------------------------------------------------------- - struct rb_entity *rb; - uint8_t dscp; - int hard_coded_rbId = 3; - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_decode_rb_release - begin \n"); -#endif - - if (!cx || !p) { - printk("nasmt_ASCTL_DC_decode_rb_release - input parameter is NULL \n"); - return; - } - - // End debug information - // TEMP -MW - 26/9/13- Overwrite the rb_id sent by RRC - p->nasUEDCPrimitive.rb_release_ind.rbId = hard_coded_rbId; - // TEMP -MW - 26/9/13- Rest should be kept unchanged - rb=nasmt_COMMON_search_rb(cx, p->nasUEDCPrimitive.rb_release_ind.rbId); - - if (rb!=NULL) { -#ifdef NAS_DEBUG_DC - printk(" nasmt_ASCTL_DC_decode_rb_release : RB_RELEASE_IND reception\n"); - printk(" Local Connection reference %u\n",p->nasUEDCPrimitive.rb_release_ind.localConnectionRef); - printk(" Radio Bearer Identity %u\n",p->nasUEDCPrimitive.rb_release_ind.rbId); - nasmt_TOOL_print_state(cx->state); -#endif - // rb->state=NAS_IDLE; - dscp = rb->dscp; - nasmt_COMMON_del_rb(cx, p->nasUEDCPrimitive.rb_release_ind.rbId, dscp); - } else - printk("nasmt_ASCTL_DC_decode_rb_release: RB_RELEASE_IND reception, No corresponding radio bearer\n"); - -} -//--------------------------------------------------------------------------- -// Decode MEASUREMENT_IND message from RRC -void nasmt_ASCTL_DC_decode_measurement_ind(struct cx_entity *cx, struct nas_ue_dc_element *p) -{ - //--------------------------------------------------------------------------- - uint8_t i; - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_decode_measurement - begin \n"); -#endif - - if (cx==NULL) { - printk("nasmt_ASCTL_DC_decode_measurement - input parameter cx is NULL \n"); - return; - } - - if (p==NULL) { - printk("nasmt_ASCTL_DC_decode_measurement - input parameter p is NULL \n"); - return; - } - - // End debug information -#ifdef NAS_DEBUG_DC_MEASURE - printk(" nasmt_ASCTL_DC_decode_measurement : MEASUREMENT_IND reception\n"); - printk(" Local Connection reference: %u\n", p->nasUEDCPrimitive.measurement_ind.localConnectionRef); - printk(" Number of RGs: %u\n", p->nasUEDCPrimitive.measurement_ind.nb_rg); - nasmt_TOOL_print_state(cx->state); - - for (i=0; inasUEDCPrimitive.measurement_ind.nb_rg; ++i) { - printk(" RG[%u]: Cell_Id %u, Level: %u\n", i, - p->nasUEDCPrimitive.measurement_ind.measures[i].cell_id, - p->nasUEDCPrimitive.measurement_ind.measures[i].level); - } - -#endif -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_decode_measurement - Local cell %d\n",p->nasUEDCPrimitive.measurement_ind.measures[0].cell_id); -#endif - cx->num_measures = p->nasUEDCPrimitive.measurement_ind.nb_rg; - - for (i=0; inum_measures; i++) { - cx->meas_cell_id[i]= (int)(p->nasUEDCPrimitive.measurement_ind.measures[i].cell_id); - cx->meas_level[i] = (int)(p->nasUEDCPrimitive.measurement_ind.measures[i].level); - //npriv->provider_id[i]=; - } - - cx->provider_id[0]=25; - cx->provider_id[1]=1; - cx->provider_id[2]=25; - -} - -//--------------------------------------------------------------------------- -// Decode MBMS_UE_NOTIFY_IND message from RRC -void nasmt_ASCTL_DC_decode_mbms_ue_notify_ind(struct cx_entity *cx, struct nas_ue_dc_element *p) -{ - //--------------------------------------------------------------------------- - uint8_t i, j, k; - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasmt_ASCTL_DC_decode_mbms_ue_notify - begin \n"); -#endif - - if (!cx || !p) { - printk("nasmt_ASCTL_DC_decode_mbms_ue_notify - input parameter is NULL \n"); - return; - } - - for (i = 0; inasUEDCPrimitive.mbms_ue_notify_ind.joined_services[i].mbms_serviceId >=0) { - for (j = 0; jjoined_services[j] ==-1) { - cx->joined_services[j]= p->nasUEDCPrimitive.mbms_ue_notify_ind.joined_services[i].mbms_serviceId; - break; - } - } - } - - if (p->nasUEDCPrimitive.mbms_ue_notify_ind.left_services[i].mbms_serviceId >=0) { - for (k = 0; kjoined_services[k] == p->nasUEDCPrimitive.mbms_ue_notify_ind.left_services[i].mbms_serviceId) { - cx->joined_services[k]=-1; - break; - } - } - } - } - - // End debug information -#ifdef NAS_DEBUG_DC - printk(" nasmt_ASCTL_DC_decode_mbms_ue_notify : MBMS_UE_NOTIFY_IND reception\n"); - printk(" Local Connection reference: %u\n", p->nasUEDCPrimitive.mbms_ue_notify_ind.localConnectionRef); - nasmt_TOOL_print_state(cx->state); - printk("Joined services: "); - - for (i = 0; inasUEDCPrimitive.mbms_ue_notify_ind.joined_services[i].mbms_serviceId) >= 0; i++) - printk("%d ", (p->nasUEDCPrimitive.mbms_ue_notify_ind.joined_services[i].mbms_serviceId)); - - printk("\n"); - printk("Left services: "); - - for (i = 0; inasUEDCPrimitive.mbms_ue_notify_ind.left_services[i].mbms_serviceId) >= 0; i++) - printk("%d ", (p->nasUEDCPrimitive.mbms_ue_notify_ind.left_services[i].mbms_serviceId)); - - printk("\n"); -#endif -} - -//--------------------------------------------------------------------------- -// Check if anything in DC FIFO and decode it (MT) -int nasmt_ASCTL_DC_receive(struct cx_entity *cx, char *buffer) -{ - //--------------------------------------------------------------------------- - int bytes_read=0; - - // Start debug information -#ifdef NAS_DEBUG_DC_DETAIL - printk("nasmt_ASCTL_DC_receive - begin \n"); -#endif - - if (!cx) { - printk("nasmt_ASCTL_DC_receive - input parameter cx is NULL \n"); - return NAS_ERROR_NOTCORRECTVALUE; - } - - // End debug information - -#ifndef PDCP_USE_NETLINK - bytes_read = rtf_get(cx->sap[NAS_DC_OUTPUT_SAPI] , gpriv->rbuffer, NAS_TL_SIZE); -#else - bytes_read = NAS_TL_SIZE; -#endif - - // - if (bytes_read>0) { - struct nas_ue_dc_element *p; - -#ifndef PDCP_USE_NETLINK - p= (struct nas_ue_dc_element *)(gpriv->rbuffer); - //get the rest of the primitive - bytes_read += rtf_get(cx->sap[NAS_DC_OUTPUT_SAPI], (uint8_t *)p+NAS_TL_SIZE, p->length-NAS_TL_SIZE); - - if (bytes_read!=p->length) { - printk("nasmt_ASCTL_DC_receive: Problem while reading primitive header\n"); - return bytes_read; - } - -#else - p= (struct nas_ue_dc_element *)(buffer); -#endif - - switch (p->type) { - case CONN_ESTABLISH_RESP : - if (p->nasUEDCPrimitive.conn_establish_resp.localConnectionRef!=cx->lcr) - printk("nasmt_ASCTL_DC_receive: CONN_ESTABLISH_RESP, Local connection reference not correct %u\n",p->nasUEDCPrimitive.conn_establish_resp.localConnectionRef); - else { - switch (cx->state) { - case NAS_CX_CONNECTING: - nasmt_ASCTL_DC_decode_cx_establish_resp(cx,p); // process message - break; - - default: - printk("nasmt_ASCTL_DC_receive: CONN_ESTABLISH_RESP reception, Invalid state %u\n", cx->state); - } - } - - break; - - case CONN_LOSS_IND : - if (p->nasUEDCPrimitive.conn_loss_ind.localConnectionRef!=cx->lcr) - printk("nasmt_ASCTL_DC_receive: CONN_LOSS_IND reception, Local connection reference not correct %u\n", p->nasUEDCPrimitive.conn_loss_ind.localConnectionRef); - else { - switch (cx->state) { - case NAS_CX_RELEASING_FAILURE: - cx->retry=0; - - case NAS_CX_DCH: - nasmt_ASCTL_DC_decode_cx_loss_ind(cx,p); // process message - break; - - default: - printk("nasmt_ASCTL_DC_receive: CONN_LOSS_IND reception, Invalid state %u", cx->state); - } - } - - break; - - // case CONN_RELEASE_IND : - // break; - case DATA_TRANSFER_IND : - if (p->nasUEDCPrimitive.data_transfer_ind.localConnectionRef!=cx->lcr) - printk("nasmt_ASCTL_DC_receive: DATA_TRANSFER_IND reception, Local connection reference not correct %u\n", p->nasUEDCPrimitive.conn_loss_ind.localConnectionRef); - else { - switch (cx->state) { - case NAS_CX_FACH: - case NAS_CX_DCH: - nasmt_ASCTL_DC_decode_sig_data_ind(cx,p); // process message - break; - - default: - printk("nasmt_ASCTL_DC_receive: DATA_TRANSFER_IND reception, Invalid state %u", cx->state); - } - } - - break; - - case RB_ESTABLISH_IND : - if (p->nasUEDCPrimitive.rb_establish_ind.localConnectionRef!=cx->lcr) - printk("nasmt_ASCTL_DC_receive: RB_ESTABLISH_IND reception, Local connexion reference not correct %u\n", p->nasUEDCPrimitive.rb_establish_ind.localConnectionRef); - else { - switch (cx->state) { - case NAS_CX_FACH: - case NAS_CX_DCH: - nasmt_ASCTL_DC_decode_rb_establish_ind(cx,p); // process message - break; - - default: - printk("nasmt_ASCTL_DC_receive: RB_ESTABLISH_IND reception, Invalid state %u", cx->state); - } - } - - break; - - case RB_RELEASE_IND : - if (p->nasUEDCPrimitive.rb_release_ind.localConnectionRef!=cx->lcr) - printk("nasmt_ASCTL_DC_receive: RB_RELEASE_IND reception, Local connection reference not correct %u\n", p->nasUEDCPrimitive.rb_release_ind.localConnectionRef); - else { - switch (cx->state) { - case NAS_CX_DCH: - nasmt_ASCTL_DC_decode_rb_release_ind(cx,p); // process message - break; - - default: - printk("nasmt_ASCTL_DC_receive: RB_RELEASE_IND reception, Invalid state %u", cx->state); - } - } - - break; - - case MEASUREMENT_IND : - if (p->nasUEDCPrimitive.measurement_ind.localConnectionRef!=cx->lcr) - printk("nasmt_ASCTL_DC_receive: MEASUREMENT_IND reception, Local connection reference not correct %u\n", p->nasUEDCPrimitive.measurement_ind.localConnectionRef); - else { - nasmt_ASCTL_DC_decode_measurement_ind(cx,p); - } - - break; - - case MBMS_UE_NOTIFY_IND : - if (p->nasUEDCPrimitive.rb_release_ind.localConnectionRef!=cx->lcr) - printk("nasmt_ASCTL_DC_receive: MBMS_UE_NOTIFY_IND reception, Local connection reference not correct %u\n", p->nasUEDCPrimitive.rb_release_ind.localConnectionRef); - else { - switch (cx->state) { - case NAS_CX_DCH: - nasmt_ASCTL_DC_decode_mbms_ue_notify_ind(cx,p); // process message - break; - - default: - printk("nasmt_ASCTL_DC_receive: MBMS_UE_NOTIFY_IND reception, Invalid state %u", cx->state); - } - } - - break; - - default : - printk("nasmt_ASCTL_DC_receive: Invalid message received\n"); - } - } - -#ifdef NAS_DEBUG_DC_DETAIL - printk("nasmt_ASCTL_DC_receive - end \n"); -#endif - return bytes_read; -} - -//--------------------------------------------------------------------------- -// Check if anything in GC FIFO and decode it (MT) -int nasmt_ASCTL_GC_receive(char *buffer) -{ - //--------------------------------------------------------------------------- - int bytes_read = 0; - -#ifdef NAS_DEBUG_GC - printk("nasmt_ASCTL_GC_receive - begin \n"); -#endif - // End debug information - -#ifndef PDCP_USE_NETLINK - bytes_read = rtf_get(gpriv->sap[NAS_GC_SAPI], gpriv->rbuffer, NAS_TL_SIZE); -#else - bytes_read = NAS_TL_SIZE; -#endif - - // - if (bytes_read>0) { - struct nas_ue_gc_element *p; -#ifndef PDCP_USE_NETLINK - p= (struct nas_ue_gc_element *)(gpriv->rbuffer); - //get the rest of the primitive - bytes_read += rtf_get(gpriv->sap[NAS_GC_SAPI], (uint8_t *)p+NAS_TL_SIZE, p->length-NAS_TL_SIZE); - - if (bytes_read!=p->length) { - printk("nasmt_ASCTL_GC_receive: Problem while reading primitive's header\n"); - return bytes_read; - } - -#else - p= (struct nas_ue_gc_element *)(buffer); - bytes_read = p->length; -#endif - - // start decoding message - switch (p->type) { - case INFO_BROADCAST_IND : -#ifndef PDCP_USE_NETLINK - bytes_read += rtf_get(gpriv->sap[NAS_GC_SAPI], (uint8_t *)p+p->length, p->nasUEGCPrimitive.broadcast_ind.nasDataLength); - - if (bytes_read!=p->length+p->nasUEGCPrimitive.broadcast_ind.nasDataLength) { - printk("nasmt_ASCTL_GC_receive: INFO_BROADCAST_IND reception, Problem while reading primitive's data\n"); - return bytes_read; - } - -#endif -#ifdef NAS_DEBUG_GC - printk(" nasmt_ASCTL_GC_receive : INFO_BROADCAST_IND reception\n"); - printk(" Primitive length %d \n", (int)(p->type)); - printk(" Data length %u\n", p->nasUEGCPrimitive.broadcast_ind.nasDataLength); - printk(" Data string %s\n", (uint8_t *)p+p->length); -#endif - return bytes_read; - - default : - printk("nasmt_ASCTL_GC_receive: Invalid message received, type %d\n", p->type); - nasmt_TOOL_print_buffer(buffer, 16); - return -1; - } - } else - return -1; -} - -#endif diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_classifier.c b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_classifier.c deleted file mode 100644 index 3cc1ac0879..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_classifier.c +++ /dev/null @@ -1,884 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasmt_classifier.c -* \brief Flow classification functions for OpenAirInterface CELLULAR version - MT -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#include "nasmt_variables.h" -#include "nasmt_proto.h" - -#include -#include - -#define IN_CLASSA(a) ((((long int) (a)) & 0x80000000) == 0) -#define IN_CLASSB(a) ((((long int) (a)) & 0xc0000000) == 0x80000000) -#define IN_CLASSC(a) ((((long int) (a)) & 0xe0000000) == 0xc0000000) -#define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000) - -/* Address to accept any incoming messages. */ -#define INADDR_ANY ((unsigned long int) 0x00000000) - -#define NIPADDR(addr) \ - (uint8_t)(addr & 0x000000FF), \ - (uint8_t)((addr & 0x0000FF00) >> 8), \ - (uint8_t)((addr & 0x00FF0000) >> 16), \ - (uint8_t)((addr & 0xFF000000) >> 24) - -#define NIP6ADDR(addr) \ - ntohs((addr)->s6_addr16[0]), \ - ntohs((addr)->s6_addr16[1]), \ - ntohs((addr)->s6_addr16[2]), \ - ntohs((addr)->s6_addr16[3]), \ - ntohs((addr)->s6_addr16[4]), \ - ntohs((addr)->s6_addr16[5]), \ - ntohs((addr)->s6_addr16[6]), \ - ntohs((addr)->s6_addr16[7]) - - -#define IN6_IS_ADDR_UNSPECIFIED(a) \ - (((__const uint32_t *) (a))[0] == 0 \ - && ((__const uint32_t *) (a))[1] == 0 \ - && ((__const uint32_t *) (a))[2] == 0 \ - && ((__const uint32_t *) (a))[3] == 0) - -#define IN6_ARE_ADDR_MASKED_EQUAL(a,b,m) \ - (((((__const uint32_t *) (a))[0] & (((__const uint32_t *) (m))[0])) == (((__const uint32_t *) (b))[0] & (((__const uint32_t *) (m))[0]))) \ - && ((((__const uint32_t *) (a))[1] & (((__const uint32_t *) (m))[1])) == (((__const uint32_t *) (b))[1] & (((__const uint32_t *) (m))[1]))) \ - && ((((__const uint32_t *) (a))[2] & (((__const uint32_t *) (m))[2])) == (((__const uint32_t *) (b))[2] & (((__const uint32_t *) (m))[2]))) \ - && ((((__const uint32_t *) (a))[3] & (((__const uint32_t *) (m))[3])) == (((__const uint32_t *) (b))[3] & (((__const uint32_t *) (m))[3])))) - -#define IN_ARE_ADDR_MASKED_EQUAL(a,b,m) \ - (((((__const uint8_t *) (a))[0] & (((__const uint8_t *) (m))[0])) == (((__const uint8_t *) (b))[0] & (((__const uint8_t *) (m))[0]))) \ - && ((((__const uint8_t *) (a))[1] & (((__const uint8_t *) (m))[1])) == (((__const uint8_t *) (b))[1] & (((__const uint8_t *) (m))[1]))) \ - && ((((__const uint8_t *) (a))[2] & (((__const uint8_t *) (m))[2])) == (((__const uint8_t *) (b))[2] & (((__const uint8_t *) (m))[2]))) \ - && ((((__const uint8_t *) (a))[3] & (((__const uint8_t *) (m))[3])) == (((__const uint8_t *) (b))[3] & (((__const uint8_t *) (m))[3])))) - -//--------------------------------------------------------------------------- -void nasmt_create_mask_ipv6_addr(struct in6_addr *masked_addrP, int prefix_len) -{ - //--------------------------------------------------------------------------- - int u6_addr8_index; - int u6_addr1_index; - int index; - - masked_addrP->s6_addr32[0] = 0xFFFFFFFF; - masked_addrP->s6_addr32[1] = 0xFFFFFFFF; - masked_addrP->s6_addr32[2] = 0xFFFFFFFF; - masked_addrP->s6_addr32[3] = 0xFFFFFFFF; - - u6_addr8_index = prefix_len >> 3; - u6_addr1_index = prefix_len & 0x07; - - for (index = u6_addr8_index + 1; index < 16; index++) { - masked_addrP->s6_addr[index] = 0; - } - - if (u6_addr1_index > 0) { - masked_addrP->s6_addr[u6_addr8_index] = 0xFF << (8-u6_addr1_index); - } -} -//--------------------------------------------------------------------------- -void nasmt_create_mask_ipv4_addr(struct in_addr *masked_addrP, int prefix_len) -{ - //--------------------------------------------------------------------------- - if (prefix_len > 32) { - prefix_len = 32; - } - - masked_addrP->s_addr = 0xFFFFFFFF << (32 - prefix_len); - return; -} - -//--------------------------------------------------------------------------- -// Add a new classifier rule (send direction) -struct classifier_entity *nasmt_CLASS_add_sclassifier(struct cx_entity *cx, uint8_t dscp, uint16_t classref) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *gc; - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_add_sclassifier: begin for dscp %d, classref %d\n", dscp,classref); -#endif - - if (cx==NULL) { - printk("nasmt_CLASS_add_sclassifier - input parameter cx is NULL \n"); - return NULL; - } - - //*** - for (gc=cx->sclassifier[dscp]; gc!=NULL; gc=gc->next) { - if (gc->classref==classref) { -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_add_sclassifier: classifier already exist for dscp %d, classref %d\n",dscp,classref); -#endif - return gc; - } - } - - gc=(struct classifier_entity *)kmalloc(sizeof(struct classifier_entity), GFP_ATOMIC); - - if (gc==NULL) - return NULL; - - memset(gc, 0, sizeof(struct classifier_entity)); - gc->next=cx->sclassifier[dscp]; - gc->classref=classref; - cx->sclassifier[dscp]=gc; - ++cx->nsclassifier; - ++gpriv->next_sclassref; //increment send classref index - MW 15/01/07 -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_add_sclassifier: classifier created for dscp %d, classref %d\n",dscp,classref); -#endif - return gc; -} - -//--------------------------------------------------------------------------- -// Add a new classifier rule (receive direction) -struct classifier_entity *nasmt_CLASS_add_rclassifier(uint8_t dscp, uint16_t classref) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *gc; - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_add_rclassifier: begin\n"); -#endif - - //*** - for (gc=gpriv->rclassifier[dscp]; gc!=NULL; gc=gc->next) { - if (gc->classref==classref) { -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_add_rclassifier: classifier already exist for dscp %d, classref %d\n",dscp,classref); -#endif - return gc; - } - } - - gc=(struct classifier_entity *)kmalloc(sizeof(struct classifier_entity), GFP_KERNEL); - - if (gc==NULL) - return NULL; - - gc->next=gpriv->rclassifier[dscp]; - gc->classref=classref; - gpriv->rclassifier[dscp]=gc; - ++gpriv->nrclassifier; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_add_rclassifier: classifier created for dscp %d, classref %d\n",dscp,classref); -#endif - return gc; -} - -//--------------------------------------------------------------------------- -void nasmt_CLASS_flush_sclassifier(struct cx_entity *cx) -{ - //--------------------------------------------------------------------------- - uint8_t dscpi; - struct classifier_entity *gc; - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_flush_sclassifier: begin\n"); -#endif - - if (cx==NULL) { - printk("nasmt_CLASS_flush_sclassifier - input parameter cx is NULL \n"); - return; - } - - //*** - for (dscpi=0; dscpisclassifier[dscpi]; gc!=NULL; gc=cx->sclassifier[dscpi]) { - cx->sclassifier[dscpi]=gc->next; - kfree(gc); - } - } - - cx->nsclassifier=0; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_flush_sclassifier: end\n"); -#endif -} - -//--------------------------------------------------------------------------- -void nasmt_CLASS_flush_rclassifier() -{ - //--------------------------------------------------------------------------- - uint8_t dscpi; - struct classifier_entity *gc; - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_flush_rclassifier: begin\n"); -#endif - - //*** - for (dscpi=0; dscpirclassifier[dscpi]; gc!=NULL; gc=gpriv->rclassifier[dscpi]) { - gpriv->rclassifier[dscpi]=gc->next; - kfree(gc); - } - } - - gpriv->nrclassifier=0; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_flush_rclassifier: end\n"); -#endif -} - -//--------------------------------------------------------------------------- -// Delete a classifier rule (send direction) -void nasmt_CLASS_del_sclassifier(struct cx_entity *cx, uint8_t dscp, uint16_t classref) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *p,*np; - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_del_sclassifier: begin\n"); -#endif - - if (cx==NULL) { - printk("nasmt_CLASS_del_sclassifier - input parameter cx is NULL \n"); - return; - } - - //*** - p=cx->sclassifier[dscp]; - - if (p==NULL) - return; - - if (p->classref==classref) { - cx->sclassifier[dscp]=p->next; - kfree(p); - --cx->nsclassifier; - return; - } - - for (np=p->next; np!=NULL; p=np) { - if (np->classref==classref) { - p->next=np->next; - kfree(np); - --cx->nsclassifier; - return; - } - } - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_del_sclassifier: end\n"); -#endif -} - -//--------------------------------------------------------------------------- -// Delete a classifier rule (receive direction) -void nasmt_CLASS_del_rclassifier(uint8_t dscp, uint16_t classref) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *p,*np; - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_del_rclassifier: begin\n"); -#endif - //*** - p=gpriv->rclassifier[dscp]; - - if (p==NULL) - return; - - if (p->classref==classref) { - gpriv->rclassifier[dscp]=p->next; - kfree(p); - --gpriv->nrclassifier; - return; - } - - for (np=p->next; np!=NULL; p=np) { - if (np->classref==classref) { - p->next=np->next; - kfree(np); - --gpriv->nrclassifier; - return; - } - } - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_del_rclassifier: end\n"); -#endif -} - -/* ORIGINAL VERSION -//--------------------------------------------------------------------------- -// Search the entity with the IPv6 address 'addr' -struct cx_entity *nasmt_CLASS_cx6(struct sk_buff *skb){ -//--------------------------------------------------------------------------- - uint8_t cxi; - #ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_cx6: begin\n"); - #endif - cxi=0; - return gpriv->cx+cxi; -}*/ - -//--------------------------------------------------------------------------- -// Search the entity with the IPv6 address 'addr' -// Navid: the ipv6 classifier is not fully tested -struct cx_entity *nasmt_CLASS_cx6(struct sk_buff *skb, unsigned char dscp, int *paddr_type, unsigned char *cx_index) -{ - //--------------------------------------------------------------------------- - uint8_t cxi; - struct cx_entity *cx = NULL; - struct classifier_entity *sclassifier= NULL; - uint32_t mc_addr_hdr; - struct in6_addr masked_addr; - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_cx6: begin\n"); -#endif - - if (skb) { -#ifdef NAS_DEBUG_CLASS - printk("SOURCE ADDR %X:%X:%X:%X:%X:%X:%X:%X",NIP6ADDR(&(ipv6_hdr(skb)->saddr))); - printk(" DEST ADDR %X:%X:%X:%X:%X:%X:%X:%X\n",NIP6ADDR(&(ipv6_hdr(skb)->daddr))); -#endif - mc_addr_hdr = ntohl(ipv6_hdr(skb)->daddr.in6_u.u6_addr32[0]); - - // First check if multicast [1st octet is FF] - if ((mc_addr_hdr & 0xFF000000) == 0xFF000000) { - // packet type according to the scope of the multicast packet - // we don't consider RPT bits in second octet [maybe done later if needed] - switch(mc_addr_hdr & 0x000F0000) { - case (0x00020000): - *paddr_type = NAS_IPV6_ADDR_MC_SIGNALLING; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_cx6: multicast packet - signalling \n"); -#endif - break; - - default: - printk("nasmt_CLASS_cx6: default multicast\n"); - *paddr_type = NAS_IPV6_ADDR_UNKNOWN; - } - } else { - // This is not multicast, so we should be able to identify the MT - *paddr_type = NAS_IPV6_ADDR_UNICAST; - cxi = 0; - (*cx_index)++; - sclassifier = gpriv->cx[cxi].sclassifier[dscp]; - - while (sclassifier!=NULL) { - // verify that this is an IPv6 classifier - if ((sclassifier->version == NAS_VERSION_6) || (sclassifier->version == NAS_VERSION_DEFAULT)) { - /*LGif (IN6_IS_ADDR_UNSPECIFIED(&(sclassifier->daddr.ipv6))) { - printk("nas_CLASS_cx6: addr is null \n"); - sclassifier = sclassifier->next; - continue; - }*/ -#ifdef NAS_DEBUG_CLASS - printk("cx %d : DSCP %d %X:%X:%X:%X:%X:%X:%X:%X\n",cxi, dscp, NIP6ADDR(&(sclassifier->daddr.ipv6))); -#endif //NAS_DEBUG_CLASS - - //if ((dst = (unsigned int*)&(((struct rt6_info *)skbdst)->rt6i_gateway)) == 0){ - // LG: STRANGE - if (IN6_IS_ADDR_UNSPECIFIED(&ipv6_hdr(skb)->daddr)) { - printk("nasmt_CLASS_cx6: dst addr is null \n"); - sclassifier = sclassifier->next; - continue; - } - - nasmt_create_mask_ipv6_addr(&masked_addr, sclassifier->dplen); - // Modified MW to check only the iid6 - masked_addr.s6_addr32[0] = 0x00000000; - masked_addr.s6_addr32[1] = 0x00000000; - - if (IN6_ARE_ADDR_MASKED_EQUAL(&ipv6_hdr(skb)->daddr, &(sclassifier->daddr.ipv6), &masked_addr)) { -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_cx6: found cx %d: %X:%X:%X:%X:%X:%X:%X:%X\n",cxi, NIP6ADDR(&(sclassifier->daddr.ipv6))); -#endif //NAS_DEBUG_CLASS - return &gpriv->cx[cxi]; - } - } - - // Go to next classifier entry for connection - sclassifier = sclassifier->next; - } - } - } - - //printk("nas_CLASS_cx6 NOT FOUND: %X:%X:%X:%X:%X:%X:%X:%X\n",NIP6ADDR(&ipv6_hdr(skb)->daddr)); - return cx; -} - -/* ORIGINAL VERSION -//--------------------------------------------------------------------------- -// Search the entity with the IPv4 address 'addr' -struct cx_entity *nasmt_CLASS_cx4(struct sk_buff *skb){ -//--------------------------------------------------------------------------- - uint8_t cxi; - #ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_cx4: begin\n"); - #endif - cxi=0; - return gpriv->cx+cxi; -}*/ - -//--------------------------------------------------------------------------- -// Search the entity with the IPv4 address 'addr' -struct cx_entity *nasmt_CLASS_cx4(struct sk_buff *skb, unsigned char dscp, int *paddr_type, unsigned char *cx_index) -{ - //--------------------------------------------------------------------------- - unsigned char cxi; - uint32_t daddr; - struct cx_entity *cx=NULL; - struct classifier_entity *pclassifier=NULL; - struct in_addr masked_addr; - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_cx4: begin\n"); -#endif - - if (skb!=NULL) { - daddr = ((struct iphdr*)(skb_network_header(skb)))->daddr; - - if (daddr != INADDR_ANY) { -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_cx4: SOURCE ADDR %d.%d.%d.%d",NIPADDR(ip_hdr(skb)->saddr)); - printk(" DEST ADDR %d.%d.%d.%d\n",NIPADDR(ip_hdr(skb)->daddr)); -#endif - - if (ipv4_is_multicast(ip_hdr(skb)->daddr)) { - // TO BE CHECKED - *paddr_type = NAS_IPV4_ADDR_MC_SIGNALLING; - } else { - if (ipv4_is_lbcast(ip_hdr(skb)->daddr)) { - // TO BE CHECKED - *paddr_type = NAS_IPV4_ADDR_BROADCAST; - } else { - if (IN_CLASSA(ip_hdr(skb)->daddr) || IN_CLASSB(ip_hdr(skb)->daddr) || IN_CLASSC(ip_hdr(skb)->daddr)) { - *paddr_type = NAS_IPV4_ADDR_UNICAST; - cxi = 0; - (*cx_index)++; - pclassifier = gpriv->cx[cxi].sclassifier[dscp]; - - while (pclassifier!=NULL) { - // verify that this is an IPv4 classifier - if ((pclassifier->version == NAS_VERSION_4) || (pclassifier->version == NAS_VERSION_DEFAULT)) { - nasmt_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen); - - if (IN_ARE_ADDR_MASKED_EQUAL(&ip_hdr(skb)->daddr, &(pclassifier->daddr.ipv4), &masked_addr)) { -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_cx4: IP MASK MATCHED: found cx %d: %d.%d.%d.%d/%d\n",cxi, NIPADDR(pclassifier->daddr.ipv4), pclassifier->dplen); -#endif - return &gpriv->cx[cxi]; - } - } - - // goto to next classification rule for the connection - pclassifier = pclassifier->next; - } - } else { - *paddr_type = NAS_IPV4_ADDR_UNKNOWN; - } - } - } - } - } - - return cx; -} - -//--------------------------------------------------------------------------- -// Search the sending function for IP Packet -void nasmt_CLASS_send(struct sk_buff *skb) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *pclassifier, *sp; - uint8_t *protocolh = NULL; - uint8_t version; - uint8_t protocol, dscp; - uint16_t classref; - struct cx_entity *cx; -#ifdef NAS_DEBUG_CLASS - char sfct[10], sprotocol[10]; -#endif - struct net_device *dev = gdev; - unsigned char cx_index,no_connection; - int addr_type; - struct in6_addr masked6_addr; - struct in_addr masked_addr; - // RARP vars - struct arphdr *rarp; - unsigned char *rarp_ptr; - /* s for "source", t for "target" */ - __be32 sip, tip; - unsigned char *sha, *tha; - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send: begin -\n"); -#endif - - if (skb==NULL) { - printk("nasmt_CLASS_send - input parameter skb is NULL \n"); - return; - } - - //*** -#ifdef NAS_DEBUG_SEND - printk("nasmt_CLASS_send - Received IP packet to transmit:"); - - if ((skb->data) != NULL) { - if (skb->len<100) - nasmt_TOOL_print_buffer(skb->data,skb->len); - else - nasmt_TOOL_print_buffer(skb->data,100); - } - -#endif - //*** - // find all connections related to socket - cx_index = 0; - no_connection = 1; - cx = NULL; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send: [before switch on IP protocol version] \n"); -#endif - - - // Get mobile connexion entity, protocol and dscp from IP packet - switch (ntohs(skb->protocol)) { - case ETH_P_IPV6: -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send : skb->protocol : IPv6 \n"); -#endif - version = NAS_VERSION_6; - addr_type = NAS_IPV6_ADDR_UNKNOWN; - protocolh = nasmt_TOOL_get_protocol6(ipv6_hdr(skb), &protocol); - dscp = nasmt_TOOL_get_dscp6 (ipv6_hdr(skb)); - cx = nasmt_CLASS_cx6 (skb, dscp, &addr_type, &cx_index); -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send - ETH_P_IPV6 skb %p dscp %d gpriv %p cx_index %p \n",skb, dscp, gpriv, &cx_index); -#endif - - // find in default DSCP a valid classification - if (cx == NULL) { - switch (addr_type) { - case NAS_IPV6_ADDR_MC_SIGNALLING: - case NAS_IPV6_ADDR_UNICAST: - pclassifier=(&gpriv->cx[0])->sclassifier[NAS_DSCP_DEFAULT]; - - while (pclassifier!=NULL) { - if ((pclassifier->version == NAS_VERSION_6) || (pclassifier->version == NAS_VERSION_DEFAULT)) { - // ok found default classifier for this packet - nasmt_create_mask_ipv6_addr(&masked6_addr, pclassifier->dplen); - - if (IN6_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv6, &ipv6_hdr(skb)->daddr, &masked6_addr)) { - // then force dscp - cx = &gpriv->cx[0]; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send - ETH_P_IPV6 FOUND NAS_DSCP_DEFAULT with IN6_ARE_ADDR_MASKED_EQUAL(%d bits)\n",pclassifier->dplen); -#endif - dscp = NAS_DSCP_DEFAULT; - break; - } else { - if(IN6_IS_ADDR_UNSPECIFIED(&pclassifier->daddr.ipv6)) { - cx = &gpriv->cx[0]; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send - ETH_P_IPV6 FOUND NAS_DSCP_DEFAULT with IN6_IS_ADDR_UNSPECIFIED\n"); -#endif - dscp = NAS_DSCP_DEFAULT; - break; - } - } - } - - pclassifier = pclassifier->next; - } - - break; - - // should have found a valid classification rule - case NAS_IPV6_ADDR_UNKNOWN: - default: - printk("nasmt_CLASS_send: No corresponding address type\n"); - } - } - - break; - - case ETH_P_ARP: -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send : skb->protocol : ARP \n"); -#endif - version = NAS_VERSION_4; - addr_type = NAS_IPV4_ADDR_BROADCAST; - dscp = 0; - cx = NULL; - // Basic sanity checks can be done without the lock - rarp = (struct arphdr *)skb_network_header(skb); - - if (rarp) { - if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) { - printk("nasmt_CLASS_send: ARP PACKET WRONG ADDR LEN or WRONG ARP HEADER TYPE\n"); - break; - } - } else { - printk("nasmt_CLASS_send: ARP HEADER POINTER IS NULL\n"); - break; - } - - // If it's not Ethernet, delete it. - if (rarp->ar_pro != htons(ETH_P_IP)) { - printk("nasmt_CLASS_send: ARP PACKET PROTOCOL IS NOT ETHERNET\n"); - break; - } - - rarp_ptr = (unsigned char *) (rarp + 1); - sha = rarp_ptr; - rarp_ptr += dev->addr_len; - memcpy(&sip, rarp_ptr, 4); - rarp_ptr += 4; - tha = rarp_ptr; - rarp_ptr += dev->addr_len; - memcpy(&tip, rarp_ptr, 4); -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send: ARP DEST IP transport IP = %d.%d.%d.%d\n",NIPADDR(tip)); -#endif - pclassifier=(&gpriv->cx[0])->sclassifier[NAS_DSCP_DEFAULT]; - - while (pclassifier!=NULL) { - if ((pclassifier->version == NAS_VERSION_4) || (pclassifier->version == NAS_VERSION_DEFAULT)) { - // ok found default classifier for this packet - nasmt_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen); -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send: MASK = %d.%d.%d.%d\n",NIPADDR(masked_addr.s_addr)); -#endif - - // - if (IN_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv4, &tip, &masked_addr.s_addr)) { - // then force dscp - cx = &gpriv->cx[0]; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send: ETH_P_ARP FOUND NAS_DSCP_DEFAULT with IN_ARE_ADDR_MASKED_EQUAL(%d bits)\n", pclassifier->dplen); -#endif - dscp = NAS_DSCP_DEFAULT; - break; - } else { - if (INADDR_ANY == pclassifier->daddr.ipv4) { - cx = &gpriv->cx[0]; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send: ETH_P_ARP FOUND NAS_DSCP_DEFAULT with INADDR_ANY\n"); -#endif - dscp = NAS_DSCP_DEFAULT; - break; - } - } - } - - pclassifier = pclassifier->next; - } - - break; - - case ETH_P_IP: -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send : skb->protocol : IPv4 \n"); -#endif - version = NAS_VERSION_4; - addr_type = NAS_IPV4_ADDR_UNKNOWN; - dscp = nasmt_TOOL_get_dscp4((struct iphdr *)(skb_network_header(skb))); - cx = nasmt_CLASS_cx4(skb, dscp, &addr_type, &cx_index); - protocolh = nasmt_TOOL_get_protocol4((struct iphdr *)(skb_network_header(skb)), &protocol); - - // find in default DSCP a valid classification - if (cx == NULL) { - switch (addr_type) { - case NAS_IPV4_ADDR_MC_SIGNALLING: - case NAS_IPV4_ADDR_UNICAST: - case NAS_IPV4_ADDR_BROADCAST: - pclassifier=(&gpriv->cx[0])->sclassifier[NAS_DSCP_DEFAULT]; - - while (pclassifier != NULL) { - if ((pclassifier->version == NAS_VERSION_4) || (pclassifier->version == NAS_VERSION_DEFAULT)) { - // ok found default classifier for this packet - nasmt_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen); -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send : MASK = %d.%d.%d.%d\n", NIPADDR(masked_addr.s_addr)); -#endif - - if (IN_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv4, &ip_hdr(skb)->daddr, &masked_addr.s_addr)) { - // then force dscp - cx = &gpriv->cx[0]; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send : ETH_P_IP FOUND NAS_DSCP_DEFAULT with IN_ARE_ADDR_MASKED_EQUAL(%d bits)\n",pclassifier->dplen); -#endif - dscp = NAS_DSCP_DEFAULT; - break; - } else { - if(INADDR_ANY == pclassifier->daddr.ipv4) { - cx = &gpriv->cx[0]; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send : ETH_P_IP FOUND NAS_DSCP_DEFAULT with INADDR_ANY\n"); -#endif - dscp = NAS_DSCP_DEFAULT; - break; - } - } - } - - pclassifier = pclassifier->next; - } - - break; - - // should have found a valid classification rule - case NAS_IPV4_ADDR_UNKNOWN: - default: - printk("nasmt_CLASS_send: No corresponding address type\n"); - } - } - -#ifdef NAS_DEBUG_CLASS - - //printk("nasmt_CLASS_send: ETH_P_IP Received IPv4 packet (%02X), dscp = %d, cx = %08X\n",ntohs(skb->protocol),dscp,cx); - if (cx) - printk("nasmt_CLASS_send: ETH_P_IP Received IPv4 packet (%02X), dscp = %d, cx = %d\n",ntohs(skb->protocol),dscp,cx->lcr); - else - printk("nasmt_CLASS_send: ETH_P_IP Received IPv4 packet (%02X), dscp = %d, No valid connection\n",ntohs(skb->protocol),dscp); - -#endif - break; - - default: - printk("nasmt_CLASS_send: Unknown IP version protocol\n"); - version = 0; - return; - } - -#ifdef NAS_DEBUG_SEND_DETAIL - printk("nasmt_CLASS_send: [before if (cx != NULL)]\n"); -#endif - - // If a valid connection for the DSCP/EXP with destination address - // is found scan all protocol-based classification rules - if (cx != NULL) { - classref = 0; - sp = NULL; - - if (cx->state!=NAS_CX_DCH) { -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send: UE not connected, in state %d. Packet is dropped\n",cx->state); -#endif - return; - } - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send: DSCP %d version %d: looking for classifier entry\n",dscp, version); -#endif - - for (pclassifier=cx->sclassifier[dscp]; pclassifier!=NULL; pclassifier=pclassifier->next) { -#ifdef NAS_DEBUG_CLASS - printk("nasmt_CLASS_send: DSCP %d p->classref=%d,p->protocol=%d,p->version=%d\n",dscp,pclassifier->classref,pclassifier->protocol,pclassifier->version); -#endif - - // normal rule checks that network protocol version matches - if ((pclassifier->version == version) || (pclassifier->version == NAS_VERSION_DEFAULT)) { - //printk("nasmt_CLASS_send: IP version are equals\n"); - sp=pclassifier; - classref=sp->classref; -#ifdef NAS_DEBUG_SEND_DETAIL - printk("nasmt_CLASS_send: classifier found for dscp %u \n", dscp); -#endif - break; - } - } - - if (sp!=NULL) { -#ifdef NAS_DEBUG_CLASS - - //char sfct[10], sprotocol[10]; - // classifier entity found. Print its parameters - if (sp->fct==nasmt_COMMON_QOS_send) - strcpy(sfct, "data xfer"); - - if (sp->fct==nasmt_CTL_send) - strcpy(sfct, "iocontrol"); - - if (sp->fct==nasmt_COMMON_del_send) - strcpy(sfct, "delete"); - - if (sp->fct==nasmt_ASCTL_DC_send_sig_data_request) - strcpy(sfct, "DC-SAP"); - - switch(protocol) { - case NAS_PROTOCOL_UDP: - strcpy(sprotocol, "udp"); - printk("udp packet\n"); - break; - - case NAS_PROTOCOL_TCP: - strcpy(sprotocol, "tcp"); - printk("tcp packet\n"); - break; - - case NAS_PROTOCOL_ICMP4: - strcpy(sprotocol, "icmp4"); - printk("icmp4 packet\n"); - break; - - case NAS_PROTOCOL_ICMP6: - strcpy(sprotocol, "icmp6"); - nasmt_TOOL_pk_icmp6((struct icmp6hdr*)protocolh); - break; - - default: - strcpy(sprotocol, "other L4"); - break; - } - - printk("nasmt_CLASS_send: (dscp %u, %s) received, (classref %u, fct %s, drb_id %u) classifier rule\n", - dscp, sprotocol, sp->classref, sfct, sp->rab_id); -#endif - - //forward packet to the correct entity - if (sp->fct!=NULL) { - sp->fct(skb, cx, sp); - } else { - printk("\n\nnasmt_CLASS_send: ERROR : CLASSIFIER FUNCTION IS NULL\n\n"); - } - - no_connection = 0; - // end : if classifier entry match found - } else { - printk("nasmt_CLASS_send: no corresponding item in the classifier list, so the message is dropped\n"); - printk("nasmt_CLASS_send: packet parameters: dscp %u, %s\n", dscp, sprotocol); - nasmt_COMMON_del_send(skb, cx, NULL); // Note MW: LG has commented this line. Why? - } - } // if connection found - -#ifdef NAS_DEBUG_CLASS - - if (no_connection == 1) { - printk("nasmt_CLASS_send: no corresponding connection, so the message is dropped\n"); - } - - printk("nasmt_CLASS_send: end\n"); -#endif -} diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_common.c b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_common.c deleted file mode 100644 index bbafa86ad1..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_common.c +++ /dev/null @@ -1,542 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasmt_common.c -* \brief Common functions for OpenAirInterface CELLULAR version - MT -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#include "nasmt_variables.h" -#include "nasmt_proto.h" - -#include -#ifdef NAS_DRIVER_TYPE_ETHERNET -#include -#endif - -//--------------------------------------------------------------------------- -// Receive data from FIFO (QOS or DC) -//void nasmt_COMMON_receive(uint16_t hlen, uint16_t dlen, int sap){ -//void nasmt_COMMON_receive(uint16_t hlen, uint16_t dlen, void *pdcp_sdu, int sap){ -void nasmt_COMMON_receive(uint16_t bytes_read, uint16_t payload_length, void *data_buffer, int rb_id, int sap) -{ - //--------------------------------------------------------------------------- - struct sk_buff *skb; - struct ipversion *ipv; - unsigned int hard_header_len; - uint16_t *p_ether_type; - uint16_t ether_type; - -#ifdef NAS_DEBUG_RECEIVE - printk("nasmt_COMMON_receive: begin\n"); -#endif -#ifdef PDCP_USE_NETLINK - - // data_buffer is NULL if FIFOs - if (!data_buffer) { - printk("nasmt_COMMON_receive - input parameter data_buffer is NULL \n"); - return; - } - -#endif - - skb = dev_alloc_skb( payload_length + 2 ); - - if(!skb) { - printk("nasmt_COMMON_receive: low on memory\n"); - ++gpriv->stats.rx_dropped; - return; - } - - skb_reserve(skb,2); - -#ifndef PDCP_USE_NETLINK - bytes_read += rtf_get(sap, skb_put(skb, payload_length), payload_length); - - if (bytes_read != NAS_PDCPH_SIZE + payload_length) { - printk("nasmt_COMMON_receive: problem while reading DC sap\n"); - kfree(skb->data); - dev_kfree_skb(skb); - return; - } - -#else - memcpy(skb_put(skb, payload_length), data_buffer, payload_length); - bytes_read += payload_length; -#endif - -#ifdef NAS_DEBUG_RECEIVE - printk("nasmt_COMMON_receive: received packet from PDCP, length %d\n", bytes_read); -#endif - - skb->dev = gdev; - hard_header_len = gdev->hard_header_len; - skb->mac_header = skb->data; - skb->pkt_type = PACKET_HOST; - skb->ip_summed = CHECKSUM_UNNECESSARY; - - ipv = (struct ipversion *)&(skb->data[hard_header_len]); - - switch (ipv->version) { - case 6: -#ifdef NAS_DEBUG_RECEIVE_BASIC - printk("nasmt_COMMON_receive: receive IPv6 message\n"); -#endif - skb->network_header = &skb->data[hard_header_len]; - // set protocol default value - skb->protocol = htons(ETH_P_IPV6); - // If type Ethernet, correct it -#ifdef NAS_DRIVER_TYPE_ETHERNET - skb->protocol = eth_type_trans(skb, gdev); -#endif - break; - - case 4: -#ifdef NAS_DEBUG_RECEIVE_BASIC - printk("nasmt_COMMON_receive: receive IPv4 message\n"); -#endif - -#ifdef NAS_DEBUG_RECEIVE - addr = (unsigned char *)&((struct iphdr *)&skb->data[hard_header_len])->saddr; - - if (addr) { - printk("nasmt_COMMON_receive: Source %d.%d.%d.%d\n",addr[0],addr[1],addr[2],addr[3]); - } - - addr = (unsigned char *)&((struct iphdr *)&skb->data[hard_header_len])->daddr; - - if (addr) { - printk("[NAS][COMMON][RECEIVE] Dest %d.%d.%d.%d\n",addr[0],addr[1],addr[2],addr[3]); - } - - printk("[NAS][COMMON][RECEIVE] protocol %d\n",((struct iphdr *)&skb->data[hard_header_len])->protocol); -#endif - - skb->network_header = &skb->data[hard_header_len]; - // set protocol default value - skb->protocol = htons(ETH_P_IP); - // If type Ethernet, correct it -#ifdef NAS_DRIVER_TYPE_ETHERNET - skb->protocol = eth_type_trans(skb, gdev); -#endif - break; - - default: - printk("nasmt_COMMON_receive: Packet is not IPv4 or IPv6 (version=%d)\n", ipv->version); - -#ifdef NAS_DRIVER_TYPE_ETHERNET -#ifdef NAS_DEBUG_RECEIVE - printk("nasmt_COMMON_receive: ether_type=%04X\n", ether_type); -#endif - skb->protocol = eth_type_trans(skb, gdev); - // minus 1(short) instead of 2(bytes) because uint16_t* - p_ether_type = (uint16_t *)&(skb->mac_header[hard_header_len-2]); - ether_type = ntohs(*p_ether_type); -#ifdef NAS_DEBUG_RECEIVE - printk("nasmt_COMMON_receive: ether_type=%04X\n", ether_type); -#endif - - switch (ether_type) { - case ETH_P_ARP: - printk("[NAS][COMMON] ether_type = ETH_P_ARP\n"); - skb->protocol = htons(ETH_P_ARP); - skb->network_header = &skb->mac_header[hard_header_len]; - break; - - default: - break; - } - -#endif - } - - ++gpriv->stats.rx_packets; - gpriv->stats.rx_bytes += bytes_read; -#ifdef NAS_DEBUG_RECEIVE - printk("nasmt_COMMON_receive: forwarding packet of size %d to kernel\n",skb->len); -#endif - - netif_rx(skb); -#ifdef NAS_DEBUG_RECEIVE - printk("nasmt_COMMON_receive: end\n"); -#endif -} - -//--------------------------------------------------------------------------- -// Delete the data -void nasmt_COMMON_del_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *sp) -{ - //--------------------------------------------------------------------------- -#ifdef NAS_DEBUG_SEND - printk("nasmt_COMMON_del_send - updating statistics \n"); -#endif - ++gpriv->stats.tx_dropped; -} - -//--------------------------------------------------------------------------- -// Request the transfer of data (QoS SAP) -void nasmt_COMMON_QOS_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc) -{ - //--------------------------------------------------------------------------- - //struct pdcp_data_req pdcph; - struct pdcp_data_req_header_t pdcph; - int bytes_wrote = 0; - - // Start debug information -#ifdef NAS_DEBUG_SEND - printk("nasmt_COMMON_QOS_send - begin \n"); -#endif - - // if (cx->state!=NAS_STATE_CONNECTED) // <--- A REVOIR - // { - // gpriv->stats.tx_dropped ++; - // printk("NAS_QOS_SEND: No connected, so message are dropped \n"); - // return; - // } - if (!skb || !gc || !cx) { - printk("nasmt_COMMON_QOS_send - input parameter skb|gc|cx is NULL \n"); - return; - } - - // End debug information - - if (gc->rb==NULL) { - gc->rb = nasmt_COMMON_search_rb(cx, gc->rab_id); - - if (gc->rb==NULL) { - ++gpriv->stats.tx_dropped; - printk("nasmt_COMMON_QOS_send: No corresponding Radio Bearer, so message is dropped, rab_id=%u \n", gc->rab_id); - return; - } - } - -#ifdef NAS_DEBUG_SEND - printk("nasmt_COMMON_QOS_send #1 :"); - printk("lcr %u, rab_id %u, rab_id %u\n", cx->lcr, (gc->rb)->rab_id, gc->rab_id); - nasmt_TOOL_print_classifier(gc); -#endif - - pdcph.data_size = skb->len; - pdcph.rb_id = ((gc->rb)->rab_id+(32*cx->lcr))-NAS_SIG_NUM_SRB; - pdcph.inst = 0; - -#ifdef PDCP_USE_NETLINK - bytes_wrote = nasmt_netlink_send((unsigned char *)&pdcph,NAS_PDCPH_SIZE, NASNL_DEST_PDCP); - //printk("nasmt_COMMON_QOS_send - Wrote %d bytes (header for %d byte skb) to PDCP via netlink\n", bytes_wrote,skb->len); -#else - //bytes_wrote = rtf_put(gpriv->sap[(gc->rb)->sapi], &pdcph, NAS_PDCPH_SIZE); - bytes_wrote = rtf_put(NAS2PDCP_FIFO, &pdcph, NAS_PDCPH_SIZE); - //printk("nasmt_COMMON_QOS_send - Wrote %d bytes (header for %d byte skb) to PDCP fifo\n", bytes_wrote,skb->len); -#endif //PDCP_USE_NETLINK - - if (bytes_wrote != NAS_PDCPH_SIZE) { - printk("nasmt_COMMON_QOS_send: problem while writing PDCP's header\n"); - printk("rb_id %d, SAP index %d, Wrote %d to fifo %d, Header Size %d \n", pdcph.rb_id , (gc->rb)->sapi, bytes_wrote, NAS2PDCP_FIFO, NAS_PDCPH_SIZE); - gpriv->stats.tx_dropped ++; - return; - } - -#ifdef PDCP_USE_NETLINK - bytes_wrote += nasmt_netlink_send((unsigned char *)skb->data,skb->len, NASNL_DEST_PDCP); -#else - //bytes_wrote += rtf_put(gpriv->sap[(gc->rb)->sapi], skb->data, skb->len); - bytes_wrote += rtf_put(NAS2PDCP_FIFO, skb->data, skb->len); -#endif //PDCP_USE_NETLINK - - if (bytes_wrote != skb->len + NAS_PDCPH_SIZE) { - printk("nasmt_COMMON_QOS_send: problem while writing PDCP's data\n"); // congestion - printk("rb_id %d, SAP index %d, Wrote %d to fifo %d, Header Size %d \n", pdcph.rb_id , (gc->rb)->sapi, bytes_wrote, NAS2PDCP_FIFO, NAS_PDCPH_SIZE); - gpriv->stats.tx_dropped ++; - return; - } - -#ifdef NAS_DEBUG_SEND - printk("nasmt_COMMON_QOS_send - %d bytes wrote to rb_id %d, sap %d \n", bytes_wrote, pdcph.rb_id,NAS2PDCP_FIFO); -#endif - gpriv->stats.tx_bytes += skb->len; - gpriv->stats.tx_packets ++; -#ifdef NAS_DEBUG_SEND - printk("nasmt_COMMON_QOS_send - end \n"); -#endif -} - -#ifndef PDCP_USE_NETLINK -//--------------------------------------------------------------------------- -void nasmt_COMMON_QOS_receive(struct cx_entity *cx) -{ - //--------------------------------------------------------------------------- - uint8_t sapi; - //struct pdcp_data_ind pdcph; - struct pdcp_data_ind_header_t pdcph; - int bytes_read = 0; - - // Start debug information -#ifdef NAS_DEBUG_RECEIVE - printk("nasmt_COMMON_QOS_receive - begin \n"); -#endif - - if (!cx) { - printk("nasmt_COMMON_QOS_receive - input parameter cx is NULL \n"); - return; - } - - // End debug information - - // LG force the use of only 1 rt fifo - sapi = NAS_DRB_OUTPUT_SAPI; - - bytes_read = rtf_get(gpriv->sap[sapi], &pdcph, NAS_PDCPH_SIZE); - - while (bytes_read>0) { - if (bytes_read != NAS_PDCPH_SIZE) { - printk("nasmt_COMMON_QOS_receive: problem while reading PDCP header\n"); - return; - } - - //void nasmt_COMMON_receive(uint16_t bytes_read, uint16_t payload_length, void *data_buffer, int rb_id, int sap); - // data_buffer is NULL because FIFO should be read directly in the skbuff (LITE has an intermediary buffer) - nasmt_COMMON_receive(NAS_PDCPH_SIZE, pdcph.data_size, NULL, pdcph->rb_id, gpriv->sap[sapi]); - // check if another frame is in the FIFO, otherwise return - bytes_read = rtf_get(gpriv->sap[sapi], &pdcph, NAS_PDCPH_SIZE); - } - -#ifdef NAS_DEBUG_RECEIVE - printk("nasmt_COMMON_QOS_receive - end \n"); -#endif -} - -#else -//--------------------------------------------------------------------------- -void nasmt_COMMON_QOS_receive(struct nlmsghdr *nlh) -{ - //--------------------------------------------------------------------------- - - struct pdcp_data_ind_header_t *pdcph; - - // Start debug information -#ifdef NAS_DEBUG_RECEIVE - printk("nasmt_COMMON_QOS_receive - begin \n"); -#endif - - if (!nlh) { - printk("nasmt_COMMON_QOS_receive - input parameter nlh is NULL \n"); - return; - } - - // End debug information - pdcph = (struct pdcp_data_ind_header_t *)NLMSG_DATA(nlh); - -#ifdef NAS_DEBUG_RECEIVE - printk("nasmt_COMMON_QOS_receive - receive from PDCP, size %d, rab %d\\n", pdcph->data_size, pdcph->rb_id); -#endif //NAS_DEBUG_RECEIVE - - //void nasmt_COMMON_receive(uint16_t bytes_read, uint16_t payload_length, void *data_buffer, int rb_id, int sap); - nasmt_COMMON_receive(NAS_PDCPH_SIZE + pdcph->data_size, pdcph->data_size, (unsigned char *)NLMSG_DATA(nlh) + NAS_PDCPH_SIZE, pdcph->rb_id, 0); - -} -#endif //PDCP_USE_NETLINK - - -//--------------------------------------------------------------------------- -struct cx_entity *nasmt_COMMON_search_cx(nasLocalConnectionRef_t lcr) -{ - //--------------------------------------------------------------------------- -#ifdef NAS_DEBUG_CLASS - printk("nasmt_COMMON_search_cx - lcr %d\n",lcr); -#endif - - if (lcrcx+lcr; - else - return NULL; -} - -//--------------------------------------------------------------------------- -// Search a Radio Bearer -struct rb_entity *nasmt_COMMON_search_rb(struct cx_entity *cx, nasRadioBearerId_t rab_id) -{ - //--------------------------------------------------------------------------- - struct rb_entity *rb; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_COMMON_search_rb - rab_id %d\n", rab_id); -#endif - - if (!cx) { - printk("nasmt_COMMON_search_rb - input parameter cx is NULL \n"); - return NULL; - } - - for (rb=cx->rb; rb!=NULL; rb=rb->next) { - if (rb->rab_id==rab_id) - return rb; - } - - return NULL; -} - -//--------------------------------------------------------------------------- -struct rb_entity *nasmt_COMMON_add_rb(struct cx_entity *cx, nasRadioBearerId_t rab_id, nasQoSTrafficClass_t qos) -{ - //--------------------------------------------------------------------------- - struct rb_entity *rb; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_COMMON_add_rb - begin for rab_id %d , qos %d\n", rab_id, qos ); -#endif - - if (cx==NULL) { - printk("nasmt_COMMON_add_rb - input parameter cx is NULL \n"); - return NULL; - } - - rb=nasmt_COMMON_search_rb(cx, rab_id); - - if (rb==NULL) { - rb=(struct rb_entity *)kmalloc(sizeof(struct rb_entity), GFP_KERNEL); - - if (rb!=NULL) { - rb->retry=0; - rb->countimer=NAS_TIMER_IDLE; - rb->rab_id=rab_id; - // rb->rab_id=rab_id+(32*cx->lcr); -#ifdef NAS_DEBUG_DC - printk("nasmt_COMMON_add_rb: rb rab_id=%u, rab_id=%u, mt_id=%u\n",rb->rab_id,rab_id, cx->lcr); -#endif - rb->qos=qos; - rb->sapi=NAS_DRB_INPUT_SAPI; - // LG force the use of only one rt-fifo rb->sapi=NAS_BA_INPUT_SAPI; - rb->state=NAS_IDLE; - rb->next=cx->rb; - cx->rb=rb; - ++cx->num_rb; - } else - printk("nasmt_COMMON_add_rb: no memory\n"); - } - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_COMMON_add_rb - end \n" ); -#endif - return rb; -} - -//--------------------------------------------------------------------------- -// free the memory that has previously been allocated to rb and remove from linked list -void nasmt_COMMON_del_rb(struct cx_entity *cx, nasRadioBearerId_t rab_id, nasIPdscp_t dscp) -{ - //--------------------------------------------------------------------------- - struct rb_entity *rb, *curr_rb, *prev_rb; - struct classifier_entity *p; - uint16_t classref=0; - - // Start debug information -#ifdef NAS_DEBUG_CLASS - printk("nasmt_COMMON_del_rb - begin\n"); -#endif - - if (cx==NULL) { - printk("nasmt_COMMON_del_rb - input parameter cx is NULL \n"); - return; - } - - // End debug information - - // Clear the associated classifier - for (p=cx->sclassifier[dscp]; p!=NULL; p=p->next) { - if (p->classref>=classref) { - classref=p->classref; -#ifdef NAS_DEBUG_CLASS - printk("nasmt_COMMON_del_rb: classifier found for dscp %u \n", dscp); -#endif - } - } - - nasmt_CLASS_del_sclassifier(cx, dscp, classref); - - // Now, delete the RB - curr_rb = NULL; - prev_rb = NULL; - - for (rb=cx->rb; rb!=NULL; rb=rb->next) { - if (rb->rab_id == rab_id) { - curr_rb = rb; - - if (prev_rb!=NULL) { - prev_rb->next = rb->next; - } else { - cx->rb=rb->next; - } - - break; - } else { - prev_rb = rb; - } - } - - if (curr_rb!= NULL) { - printk("nasmt_COMMON_del_rb: del rab_id %u\n", rb->rab_id); - kfree(rb); - (cx->num_rb)--; - } else { - printk("\n\n--nasmt_COMMON_del_rb: ERROR, invalid rab_id %u\n", rb->rab_id); - } - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_COMMON_del_rb - end\n"); -#endif -} - -//--------------------------------------------------------------------------- -void nasmt_COMMON_flush_rb(struct cx_entity *cx) -{ - //--------------------------------------------------------------------------- - struct rb_entity *rb; - struct classifier_entity *gc; - uint8_t dscp; - // Start debug information -#ifdef NAS_DEBUG_CLASS - printk("nasmt_COMMON_flush_rb - begin\n"); -#endif - - if (cx==NULL) { - printk("nasmt_COMMON_flush_rb - input parameter cx is NULL \n"); - return; - } - - // End debug information - for (rb=cx->rb; rb!=NULL; rb=cx->rb) { - printk("nasmt_COMMON_flush_rb: del rab_id %u\n", rb->rab_id); - cx->rb=rb->next; - kfree(rb); - } - - cx->num_rb=0; - cx->rb=NULL; - - for(dscp=0; dscpsclassifier[dscp]; gc!=NULL; gc=gc->next) - gc->rb=NULL; - } - -#ifdef NAS_DEBUG_CLASS - printk("nasmt_COMMON_flush_rb - end\n"); -#endif -} diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_constant.h b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_constant.h deleted file mode 100644 index bdba11ff79..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_constant.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasmt_constant.h -* \brief Defines all constants for OpenAirInterface CELLULAR version - MT -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#ifndef _NASMTD_CST -#define _NASMTD_CST - -//Debug flags -#define NAS_DEBUG_DC -//#define NAS_DEBUG_DC_DETAIL // detail of DC-SAP operation -#define NAS_DEBUG_SEND -#define NAS_DEBUG_SEND_DETAIL // detail of packet transmission -//#define NAS_DEBUG_RECEIVE -#define NAS_DEBUG_RECEIVE_BASIC -#define NAS_DEBUG_CLASS -//#define NAS_DEBUG_GC -//#define NAS_DEBUG_DC_MEASURE -//#define NAS_DEBUG_TIMER -#define NAS_DEBUG_DEVICE -//#define NAS_DEBUG_INTERRUPT -//#define NAS_DEBUG_TOOL -#define NETLINK_DEBUG -//#define NAS_DEBUG_RRCNL // RRC netlink socket - -// Other flags -#define DEMO_3GSM -#define ENABLE_SLEEP_MODE - -// Parameters for the default RAB started after attachment (needs DEMO_3GSM defined) -#define NASMT_DEFAULTRAB_CLASSREF 1 //MW-01/01/07- -#define NASMT_DEFAULTRAB_DSCP 0 //MW-01/01/07- -#define NASMT_DEFAULTRAB_IPVERSION NAS_VERSION_DEFAULT //MW-01/01/07- - -#define NAS_DEFAULT_IPv6_PREFIX_LENGTH 128 // used to compare destination address - - -// General Constants -#define NAS_MTU 1500 -#define NAS_TX_QUEUE_LEN 100 -#define NAS_ADDR_LEN 8 -#define NAS_INET6_ADDRSTRLEN 46 -#define NAS_INET_ADDRSTRLEN 16 - -#define NAS_RESET_RX_FLAGS 0 - -#define NAS_CX_MAX 1 -//#define NAS_CX_MULTICAST_ALLNODE 2 -#define NASMT_MBMS_SVCES_MAX 4 // Identical to RRC constant - -#define NAS_RETRY_LIMIT_DEFAULT 5 - -#define NAS_MESSAGE_MAXLEN 1600 - -// UMTS -#define NAS_SIG_SRB3 3 -#define NAS_SIG_SRB4 3 // not used yet -//LTE -#define NAS_SIG_NUM_SRB 3 // number of srbs in LTE to send Rb_Id to PDCP - -//peer-to-peer messages between NAS entities -#define NAS_CMD_OPEN_RB 1 -#define NAS_CMD_ENTER_SLEEP 2 -#define NAS_CMD_LEAVE_SLEEP 3 - -//#define NAS_IID1_CONTROL 0x0 -//#define NAS_IID2_CONTROL __constant_htonl(0xffffffff) - -//#define NAS_STATE_IDLE 0 -//#define NAS_STATE_CONNECTED 1 -//#define NAS_STATE_ESTABLISHMENT_REQUEST 2 -//#define NAS_STATE_ESTABLISHMENT_FAILURE 3 -//#define NAS_STATE_RELEASE_FAILURE 4 -#define NAS_CX_RELEASE_UNDEF_CAUSE 1 - -// MT+RG NAS States -#define NAS_IDLE 0x01 -// Connection -#define NAS_CX_FACH 0x06 -#define NAS_CX_DCH 0x0A -#define NAS_CX_RECEIVED 0x10 -#define NAS_CX_CONNECTING 0x04 -#define NAS_CX_RELEASING 0x08 -#define NAS_CX_CONNECTING_FAILURE 0x14 -#define NAS_CX_RELEASING_FAILURE 0x18 -// Radio Bearers -#define NAS_RB_ESTABLISHING 0x24 -#define NAS_RB_RELEASING 0x28 -#define NAS_RB_DCH 0x2A - - -#define NAS_TIMER_ESTABLISHMENT_DEFAULT 12 -#define NAS_TIMER_RELEASE_DEFAULT 2 -#define NAS_TIMER_IDLE UINT_MAX -#define NAS_TIMER_TICK HZ - -#define NAS_PDCPH_SIZE sizeof(struct pdcp_data_req_header_t) -#define NAS_IPV4_SIZE 20 -#define NAS_IPV6_SIZE 40 - -#define NAS_DIRECTION_SEND 0 -#define NAS_DIRECTION_RECEIVE 1 - -// function number -#define NAS_FCT_DEL_SEND 1 -#define NAS_FCT_QOS_SEND 2 -#define NAS_FCT_DC_SEND 3 -#define NAS_FCT_CTL_SEND 4 - -// type of IOCTL command -#define NASMT_IOCTL_RAL 0x89F0 - -// Error cause -#define NAS_ERROR_ALREADYEXIST 1 -#define NAS_ERROR_NOMEMORY 3 -#define NAS_ERROR_NOTMT 9 -#define NAS_ERROR_NOTRG 10 -#define NAS_ERROR_NOTIDLE 11 -#define NAS_ERROR_NOTCONNECTED 12 -#define NAS_ERROR_NORB 14 -#define NAS_ERROR_NOTCORRECTVALUE 32 -#define NAS_ERROR_NOTCORRECTLCR 33 -#define NAS_ERROR_NOTCORRECTDIR 34 -#define NAS_ERROR_NOTCORRECTDSCP 35 -#define NAS_ERROR_NOTCORRECTVERSION 36 -#define NAS_ERROR_NOTCORRECTRABI 37 - - -/**********************************************************/ -/* Constants related with IP protocols */ -/**********************************************************/ -// Destination address types -#define NAS_IPV6_ADDR_UNICAST 1 -#define NAS_IPV6_ADDR_MC_SIGNALLING 2 -#define NAS_IPV6_ADDR_MC_MBMS 3 -#define NAS_IPV6_ADDR_UNKNOWN 4 - -#define NAS_IPV4_ADDR_UNICAST 5 -#define NAS_IPV4_ADDR_MC_SIGNALLING 6 -#define NAS_IPV4_ADDR_BROADCAST 7 -#define NAS_IPV4_ADDR_UNKNOWN 8 - - -//#define NAS_PORT_CONTROL __constant_htons(0xc45) -//#define NAS_PORT_AUTHENTICATION __constant_htons(1811) - -//#define NAS_TRAFFICCLASS_MASK __constant_htonl(0x0fc00000) //Yan -#define NAS_TRAFFICCLASS_MASK __constant_htonl(0x0ff00000) - -// Network control codepoint 111000 + IP version 6 -#define NAS_FLOWINFO_NCONTROL __constant_htonl(0x6e000000) -// network control codepoint 111000 -#define NAS_DSCP_NCONTROL 56 //0x38 -// default codepoint 1000000 -#define NAS_DSCP_DEFAULT 64 -#define NAS_DSCP_MAX 65 - -#define NAS_PROTOCOL_DEFAULT 0 -#define NAS_PROTOCOL_TCP IPPROTO_TCP -#define NAS_PROTOCOL_UDP IPPROTO_UDP -#define NAS_PROTOCOL_ICMP4 IPPROTO_ICMP -#define NAS_PROTOCOL_ICMP6 IPPROTO_ICMPV6 - -#define NAS_PORT_DEFAULT __constant_htons(65535) -#define NAS_PORT_HTTP __constant_htons(80) - -#define NAS_VERSION_DEFAULT 0 -#define NAS_VERSION_4 4 -#define NAS_VERSION_6 6 //?MW - -/**********************************************************/ -/* Constants related with Netlink sockets */ -/**********************************************************/ -#define OAI_IP_DRIVER_NETLINK_ID 31 -#define NL_DEST_PID 1 - -// defined in rrc_nas_sap.h -//#define NAS_RRCNL_ID 30 -//#define NL_DEST_RRC_PID 2 - -#define NASNL_DEST_PDCP 0 -#define NASNL_DEST_RRC 1 - -#endif - - - diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_device.c b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_device.c deleted file mode 100644 index efc8562bf9..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_device.c +++ /dev/null @@ -1,565 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasmt_device.c -* \brief Networking Device Driver for OpenAirInterface CELLULAR version - MT -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#ifndef PDCP_USE_NETLINK -#ifdef RTAI -#include "rtai_posix.h" -#define RTAI_IRQ 30 //try to get this irq with RTAI -#endif // RTAI -#endif // PDCP_USE_NETLINK -//:::::::::::::::::::::::::::::::::::::::;; -#include "nasmt_variables.h" -#include "nasmt_proto.h" -//:::::::::::::::::::::::::::::::::::::::;; -//#include -#include -#include -#include -#include -#include - -#ifdef NAS_DRIVER_TYPE_ETHERNET -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef NAS_DRIVER_TYPE_ETHERNET -#include -#endif -//:::::::::::::::::::::::::::::::::::::::;; -struct net_device *gdev; -struct nas_priv *gpriv; -//int bytes_wrote; -//int bytes_read; -uint8_t NAS_NULL_IMEI[14]= {0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00}; -uint8_t NAS_RG_IMEI[14]= {0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x01}; - -// TEMP -//uint8_t nas_IMEI[14]; -static unsigned char nas_IMEI[14]; -static int m_arg=0; - - -#ifdef PDCP_USE_NETLINK -extern void nasmt_netlink_release(void); -extern int nasmt_netlink_init(void); -#endif -extern void nasmt_ASCTL_timer(unsigned long data); - - -#ifndef PDCP_USE_NETLINK -//--------------------------------------------------------------------------- -//void nasmt_interrupt(void){ -void *nasmt_interrupt(void) -{ - //--------------------------------------------------------------------------- - uint8_t cxi; - char *buffer = NULL; -#ifdef NAS_DEBUG_INTERRUPT - printk("nasmt_interrupt - begin\n"); -#endif - //spin_lock(&gpriv->lock); - cxi=0; - nasmt_COMMON_QOS_receive(gpriv->cx+cxi); - nasmt_ASCTL_GC_receive(buffer); - nasmt_ASCTL_DC_receive(gpriv->cx+cxi, buffer); - //spin_unlock(&gpriv->lock); -#ifdef NAS_DEBUG_INTERRUPT - printk("nasmt_interrupt: end\n"); -#endif -} -#endif //NETLINK - -//--------------------------------------------------------------------------- -// Called by ifconfig when the device is activated by ifconfig -int nasmt_open(struct net_device *dev) -{ - //--------------------------------------------------------------------------- - printk("nasmt_open: begin\n"); - - gpriv=netdev_priv(dev); - - // Address has already been set at init -#ifndef PDCP_USE_NETLINK - - if (gpriv->irq==-EBUSY) { - printk("nasmt_open: irq failure\n"); - return -EBUSY; - } - -#endif //NETLINK - - // next lines prevent compilation of the driver with kernel version under 2.6.29 - // ATTENTION !!!!!! NASMT is not usable with these versions - - if(!netif_queue_stopped(dev)) - netif_start_queue(dev); - else - netif_wake_queue(dev); - - // - init_timer(&gpriv->timer); - (gpriv->timer).expires=jiffies+NAS_TIMER_TICK; - (gpriv->timer).data=0L; - (gpriv->timer).function=nasmt_ASCTL_timer; - // ??LITE comments: add_timer(&gpriv->timer); - add_timer(&gpriv->timer); - // - printk("nasmt_open: name = %s, end\n", dev->name); - return 0; -} - -//--------------------------------------------------------------------------- -// Called by ifconfig when the device is desactivated by ifconfig -int nasmt_stop(struct net_device *dev) -{ - //--------------------------------------------------------------------------- - struct nas_priv *priv = netdev_priv(dev); - printk("nasmt_stop: begin\n"); - del_timer(&priv->timer); - netif_stop_queue(dev); - - printk("nasmt_stop: name = %s, end\n", dev->name); - return 0; -} - -//--------------------------------------------------------------------------- -void nasmt_teardown(struct net_device *dev) -{ - //--------------------------------------------------------------------------- - int cxi; -#ifndef PDCP_USE_NETLINK - struct nas_priv *priv = netdev_priv(dev); -#endif //PDCP_USE_NETLINK - - printk("nasmt_teardown: begin\n"); - // priv=(struct nas_priv *)(gdev.priv); - - if (dev) { -#ifndef PDCP_USE_NETLINK - - if (priv->irq!=-EBUSY) { - *pt_nas_ue_irq=-1; - rt_free_srq(priv->irq); - } - -#endif //PDCP_USE_NETLINK - -#ifdef PDCP_USE_NETLINK - nasmt_netlink_release(); -#endif //PDCP_USE_NETLINK - // for (sapi=0; sapisap[sapi]); - nasmt_CLASS_flush_rclassifier(); - cxi=0; - nasmt_COMMON_flush_rb(gpriv->cx+cxi); - nasmt_CLASS_flush_sclassifier(gpriv->cx+cxi); - // for (sapi=0; sapicx[cxi].sap[sapi]); - } // check dev - else { - printk("nasmt_teardown: Device is null\n"); - } - - printk("nasmt_teardown: end\n"); -} - -//--------------------------------------------------------------------------- -int nasmt_set_config(struct net_device *dev, struct ifmap *map) -{ - //--------------------------------------------------------------------------- - printk("nasmt_set_config: begin\n"); - - if (dev->flags & IFF_UP) - return -EBUSY; - - if (map->base_addr != dev->base_addr) { - printk(KERN_WARNING "nasmt_set_config: Can't change I/O address\n"); - return -EOPNOTSUPP; - } - - if (map->irq != dev->irq) - dev->irq = map->irq; - - printk("nasmt_set_config: end\n"); - return 0; -} - -//--------------------------------------------------------------------------- -// -int nasmt_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_DEVICE - printk("nasmt_hard_start_xmit: begin\n"); -#endif - - if ((!skb)||(!dev)) { - printk("nasmt_hard_start_xmit - input parameter skb or dev is NULL \n"); - return -1; - } - - // End debug information - netif_stop_queue(dev); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) - netif_trans_update(dev); -#else - dev->trans_start = jiffies; -#endif -#ifdef NAS_DEBUG_SEND_DETAIL - printk("nasmt_hard_start_xmit: step 1\n"); -#endif - nasmt_CLASS_send(skb); -#ifdef NAS_DEBUG_SEND_DETAIL - printk("nasmt_hard_start_xmit: step 2\n"); -#endif - dev_kfree_skb(skb); -#ifdef NAS_DEBUG_SEND_DETAIL - printk("nasmt_hard_start_xmit: step 3\n"); -#endif - netif_wake_queue(dev); -#ifdef NAS_DEBUG_DEVICE - printk("nasmt_hard_start_xmit: end\n"); -#endif - return 0; -} - -//--------------------------------------------------------------------------- -struct net_device_stats *nasmt_get_stats(struct net_device *dev) -{ - //--------------------------------------------------------------------------- - // return &((struct nas_priv *)dev->priv)->stats; - struct nas_priv *npriv = netdev_priv(dev); - return &npriv->stats; -} - -//--------------------------------------------------------------------------- -// New function from LITE DRIVER -int nasmt_set_mac_address(struct net_device *dev, void *mac) -{ - //--------------------------------------------------------------------------- - struct sockaddr *addr = mac; - printk("nasmt_set_mac_address: begin\n"); - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - return 0; -} - - -//--------------------------------------------------------------------------- -int nasmt_change_mtu(struct net_device *dev, int mtu) -{ - //--------------------------------------------------------------------------- - printk("nasmt_change_mtu: begin\n"); - - if ((mtu<50) || (mtu>1500)) - // if ((mtu<1280) || (mtu>1500)) - return -EINVAL; - - dev->mtu = mtu; - return 0; -} - -//--------------------------------------------------------------------------- -int nasmt_change_rx_flags(struct net_device *dev, int flags) -{ - //--------------------------------------------------------------------------- - //struct nas_priv *priv = netdev_priv(dev); - printk("nasmt_change_rx_flags %08X\n", flags); - gpriv->rx_flags ^= flags; - return 0; -} - -//--------------------------------------------------------------------------- -void nasmt_tx_timeout(struct net_device *dev) -{ - //--------------------------------------------------------------------------- - /* Transmitter timeout, serious problems. */ - printk("nasmt_tx_timeout: begin\n"); - //((struct nas_priv *)(dev->priv))->stats.tx_errors++; - (gpriv->stats).tx_errors++; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) - netif_trans_update(dev); -#else - dev->trans_start = jiffies; -#endif - netif_wake_queue(dev); - printk("nasmt_tx_timeout: transmit timed out %s\n",dev->name); -} - -//--------------------------------------------------------------------------- -// Define pointers for the module -static const struct net_device_ops nasmt_netdev_ops = { - // ?? nasmt_interrupt - // - .ndo_open = nasmt_open, - .ndo_stop = nasmt_stop, - .ndo_start_xmit = nasmt_hard_start_xmit, - .ndo_validate_addr = NULL, - .ndo_get_stats = nasmt_get_stats, - //#ifdef KERNEL_VERSION_GREATER_THAN_32 - // .ndo_set_multicast_list = NULL, - .ndo_set_mac_address = nasmt_set_mac_address, - .ndo_set_config = nasmt_set_config, - .ndo_do_ioctl = nasmt_CTL_ioctl, - .ndo_change_mtu = nasmt_change_mtu, - .ndo_tx_timeout = nasmt_tx_timeout, - .ndo_change_rx_flags = nasmt_change_rx_flags, - //#endif -}; -//--------------------------------------------------------------------------- - -//--------------------------------------------------------------------------- -// Initialisation of the network device -void nasmt_init(struct net_device *dev) -{ - //--------------------------------------------------------------------------- - uint8_t cxi, dscpi; - - printk("nasmt_init: begin\n"); - - if (dev) { - gpriv=netdev_priv(dev); - memset(gpriv, 0, sizeof(struct nas_priv)); - // Initialize function pointers - dev->netdev_ops = &nasmt_netdev_ops; - -#ifndef NAS_DRIVER_TYPE_ETHERNET - // Update driver properties - dev->type = ARPHRD_EURUMTS; - dev->features = NETIF_F_NO_CSUM; - dev->hard_header_len = 0; - dev->addr_len = NAS_ADDR_LEN; - dev->flags = IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP; - dev->tx_queue_len = NAS_TX_QUEUE_LEN; - dev->mtu = NAS_MTU; -#endif - // Can be one of the following enum defined in include/linux/netdevice.h: - // enum netdev_state_t { - // __LINK_STATE_START, - // __LINK_STATE_PRESENT, - // __LINK_STATE_NOCARRIER, - // __LINK_STATE_LINKWATCH_PENDING, - // __LINK_STATE_DORMANT, - // }; - set_bit(__LINK_STATE_PRESENT, &dev->state); - -#ifdef NAS_DRIVER_TYPE_ETHERNET - // overwrite values written above ( header_ops,type,hard_header_len,mtu,addr_len,tx_queue_len,flags,broadcast) - printk("\nnasmt_init: WARNING Driver type ETHERNET\n"); - ether_setup(dev); -#endif - - // - // Initialize private structure - gpriv->rx_flags = NAS_RESET_RX_FLAGS; - - gpriv->sap[NAS_GC_SAPI] = RRC_DEVICE_GC; - gpriv->sap[NAS_NT_SAPI] = RRC_DEVICE_NT; - gpriv->cx[0].sap[NAS_DC_INPUT_SAPI] = RRC_DEVICE_DC_INPUT0; - gpriv->cx[0].sap[NAS_DC_OUTPUT_SAPI] = RRC_DEVICE_DC_OUTPUT0; - - //gpriv->sap[NAS_CO_INPUT_SAPI] = QOS_DEVICE_CONVERSATIONAL_INPUT; - //gpriv->sap[NAS_CO_OUTPUT_SAPI] = QOS_DEVICE_CONVERSATIONAL_OUTPUT; - gpriv->sap[NAS_DRB_INPUT_SAPI] = PDCP2PDCP_USE_RT_FIFO;//QOS_DEVICE_CONVERSATIONAL_INPUT; - gpriv->sap[NAS_DRB_OUTPUT_SAPI] = NAS2PDCP_FIFO;//QOS_DEVICE_STREAMING_INPUT; - - gpriv->retry_limit = NAS_RETRY_LIMIT_DEFAULT; - gpriv->timer_establishment = NAS_TIMER_ESTABLISHMENT_DEFAULT; - gpriv->timer_release = NAS_TIMER_RELEASE_DEFAULT; - - for (dscpi=0; dscpirclassifier[dscpi] = NULL; - - gpriv->nrclassifier = 0; - // - cxi=0; -#ifdef NAS_DEBUG_DEVICE - printk("nasmt_init: init classifiers, state and timer for MT %u\n", cxi); -#endif - gpriv->cx[cxi].state = NAS_IDLE; - gpriv->cx[cxi].countimer = NAS_TIMER_IDLE; - gpriv->cx[cxi].retry = 0; - gpriv->cx[cxi].lcr = cxi; - gpriv->cx[cxi].rb = NULL; - gpriv->cx[cxi].num_rb = 0; - - // initialisation of the classifiers - for (dscpi=0; dscpicx[cxi].sclassifier[dscpi]=NULL; - } - - gpriv->cx[cxi].nsclassifier=0; - // initialisation of the IP address - nasmt_TOOL_imei2iid(NAS_NULL_IMEI, (uint8_t *)gpriv->cx[cxi].iid6); - gpriv->cx[cxi].iid4=0; - // - spin_lock_init(&gpriv->lock); - printk("nasmt_init: init IMEI to IID\n"); - -#ifdef NAS_DRIVER_TYPE_ETHERNET - nasmt_TOOL_eth_imei2iid(nas_IMEI, dev->dev_addr ,(uint8_t *)gpriv->cx[0].iid6, dev->addr_len); -#else - nasmt_TOOL_imei2iid(nas_IMEI, dev->dev_addr);// IMEI to device address (for stateless autoconfiguration address) - nasmt_TOOL_imei2iid(nas_IMEI, (uint8_t *)gpriv->cx[0].iid6); -#endif - - nasmt_ASCTL_init(); - } else { - printk("\n\nnasmt_init: ERROR, Device is NULL!!\n"); - } - - printk("nasmt_init: end\n"); - return; -} - -//--------------------------------------------------------------------------- -int init_module (void) -{ - //--------------------------------------------------------------------------- - int err; - int inst = 0; - int index; - struct nas_priv *priv; - char devicename[100]; - - printk("\n\n\ninit_module: begin \n"); - - // check IMEI parameter - printk("number of IMEI parameters %d, IMEI ", m_arg); - - for (index = 0; index < m_arg; index++) { - printk("%02X ", nas_IMEI[index]); - } - - printk("\n"); - - -#ifndef PDCP_USE_NETLINK - - // Initialize parameters shared with RRC (done first to avoid going further) - if (pt_nas_ue_irq==NULL) { - printk("init_module: shared irq parameter not initialised\n"); - err = -EBUSY; - printk("init_module: returning %d \n\n", err); - return err; - } - - printk("init_module: pt_nas_ue_irq valid \n"); -#endif - - // Allocate device structure - sprintf(devicename,"oai%d",inst); -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) - gdev = alloc_netdev(sizeof(struct nas_priv), devicename, nasmt_init); -#else - gdev = alloc_netdev(sizeof(struct nas_priv), devicename, NET_NAME_PREDICTABLE, nasmt_init); -#endif - priv = netdev_priv(gdev); - //// -#ifndef PDCP_USE_NETLINK - priv->irq=rt_request_srq(0, nasmt_interrupt, NULL); - - if (priv->irq == -EBUSY || priv->irq == -EINVAL) { - printk("\n init_module: No interrupt resource available\n"); - - if (gdev) { - free_netdev(gdev); - printk("init_module: free_netdev ..\n"); - } - - return -EBUSY; - } else - printk("init_module: Interrupt %d, ret = %d \n", priv->irq , ret); - - if (pt_nas_ue_irq==NULL) { - printk("init_module: shared irq parameter has been reset\n"); - } else { - *pt_nas_ue_irq=priv->irq; - } - -#endif - -#ifdef PDCP_USE_NETLINK - - if ((err=nasmt_netlink_init()) == -1) - printk("init_module: NETLINK failed\n"); - - printk("init_module: NETLINK INIT successful\n"); -#endif //NETLINK - // - err= register_netdev(gdev); - - if (err) { - printk("init_module: error %i registering device %s\n", err, gdev->name); - } else { - printk("init_module: registering device %s, ifindex = %d\n\n",gdev->name, gdev->ifindex); - } - - return err; -} - -//--------------------------------------------------------------------------- -void cleanup_module(void) -{ - //--------------------------------------------------------------------------- - printk("nasmt_cleanup_module: begin\n"); - unregister_netdev(gdev); - nasmt_teardown(gdev); - free_netdev(gdev); - printk("nasmt_cleanup_module: end\n\n\n\n"); -} - -//--------------------------------------------------------------------------- -// Replaced by init_module and cleanup_module -//module_init (nasmt_init_module); -//module_exit (nasmt_cleanup_module); -//--------------------------------------------------------------------------- - -#define DRV_NAME "oai_nasmt" -#define DRV_VERSION "3.0.1"DRV_NAME -#define DRV_DESCRIPTION "OPENAIR CELLULAR LTE NASMT Device Driver" -#define DRV_COPYRIGHT "-Copyright(c) GNU GPL Eurecom 2013" -#define DRV_AUTHOR "Michelle Wetterwald "DRV_COPYRIGHT - -module_param_array_named(nas_IMEI,nas_IMEI,byte,&m_arg,0); -//module_param_array(oai_nw_drv_IMEI,byte,&m_arg,0444); -MODULE_PARM_DESC(nas_IMEI,"Terminal IMEI Identifier (14 digits, only first 10 significant if ETH option ON)"); - - -// MODULE_LICENSE("GPL"); -// MODULE_DESCRIPTION("LTE Driver for Mobile Terminal, playing as Non Access Stratum"); -// MODULE_AUTHOR("Michelle Wetterwald "); - diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.c b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.c deleted file mode 100644 index 296ae78866..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.c +++ /dev/null @@ -1,764 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasmt_iocontrol.c -* \brief I/O control functions for upper layers of driver for OpenAirInterface CELLULAR version - MT -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#include "nasmt_variables.h" -#include "nasmt_iocontrol.h" -#include "nasmt_proto.h" - -//#include -#include -#include -#include - -extern int nasmt_ASCTL_DC_send_cx_establish_request(struct cx_entity *cx); - -// Statistic -//--------------------------------------------------------------------------- -void nasmt_set_msg_statistic_reply(struct nas_msg_statistic_reply *msgrep) -{ - //--------------------------------------------------------------------------- - msgrep->rx_packets=gpriv->stats.rx_packets; - msgrep->tx_packets=gpriv->stats.tx_packets; - msgrep->rx_bytes=gpriv->stats.rx_bytes; - msgrep->tx_bytes=gpriv->stats.tx_bytes; - msgrep->rx_errors=gpriv->stats.rx_errors; - msgrep->tx_errors=gpriv->stats.tx_errors; - msgrep->rx_dropped=gpriv->stats.rx_dropped; - msgrep->tx_dropped=gpriv->stats.tx_dropped; -} - -//--------------------------------------------------------------------------- -int nasmt_ioCTL_statistic_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_statistic_reply msgrep; - printk("nasmt_ioCTL_statistic: stat requested\n"); - nasmt_set_msg_statistic_reply(&msgrep); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasmt_ioCTL_statistic: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Connections List -//--------------------------------------------------------------------------- -void nasmt_set_msg_cx_list_reply(uint8_t *msgrep) -{ - //--------------------------------------------------------------------------- - struct cx_entity *cx; - nasLocalConnectionRef_t lcr; - struct nas_msg_cx_list_reply *list; - msgrep[0]=NAS_CX_MAX; - list=(struct nas_msg_cx_list_reply *)(msgrep+1); - - for(lcr=0; lcrstate; - list[lcr].cellid=cx->cellid; - list[lcr].iid4=cx->iid4; - list[lcr].iid6[0]=cx->iid6[0]; - list[lcr].iid6[1]=cx->iid6[1]; - list[lcr].num_rb=cx->num_rb; - list[lcr].nsclassifier=cx->nsclassifier; - printk("nasmt_set_msg_cx_list_reply: nsc=%u\n",cx->nsclassifier); - } -} - -//--------------------------------------------------------------------------- -int nasmt_ioCTL_cx_list_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - uint8_t msgrep[NAS_CX_MAX*sizeof(struct nas_msg_cx_list_reply)+1]; - printk("nasmt_ioCTL_cx_list: connection list requested\n"); - nasmt_set_msg_cx_list_reply(msgrep); - - if (copy_to_user(gifr->msg, msgrep, NAS_CX_MAX*sizeof(struct nas_msg_cx_list_reply)+1)) { - printk("nasmt_ioCTL_cx_list: copy_to_user failure\n"); - return -EFAULT; - } - - printk("nasmt_ioCTL_cx_list: end\n"); - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Connection Establishment -//--------------------------------------------------------------------------- -void nasmt_set_msg_cx_establishment_reply(struct nas_msg_cx_establishment_reply *msgrep, struct nas_msg_cx_establishment_request *msgreq) -{ - //--------------------------------------------------------------------------- -#ifdef NODE_RG - msgrep->status=-NAS_ERROR_NOTMT; -#else - struct cx_entity *cx; - cx=nasmt_COMMON_search_cx(msgreq->lcr); - - if (cx!=NULL) { - if (cx->state == NAS_CX_RELEASING) { - msgrep->status=nasmt_ASCTL_leave_sleep_mode(cx); - } else { - cx->cellid=msgreq->cellid; - msgrep->status=nasmt_ASCTL_DC_send_cx_establish_request(cx); - } - } else - msgrep->status=-NAS_ERROR_NOTCORRECTLCR; - -#endif -} -//--------------------------------------------------------------------------- -int nasmt_ioCTL_cx_establishment_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_cx_establishment_request msgreq; - struct nas_msg_cx_establishment_reply msgrep; - printk("nasmt_ioCTL_cx_establishment: connection establishment requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasmt_ioCTL_cx_establishment: copy_from_user failure\n"); - return -EFAULT; - } - - nasmt_set_msg_cx_establishment_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasmt_ioCTL_cx_establishment: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Connection Release -//--------------------------------------------------------------------------- -void nasmt_set_msg_cx_release_reply(struct nas_msg_cx_release_reply *msgrep, struct nas_msg_cx_release_request *msgreq) -{ - //--------------------------------------------------------------------------- -#ifdef NODE_RG - msgrep->status=-NAS_ERROR_NOTMT; -#else - struct cx_entity *cx; - cx=nasmt_COMMON_search_cx(msgreq->lcr); - - if (cx!=NULL) { -#ifdef ENABLE_SLEEP_MODE - msgrep->status=nasmt_ASCTL_enter_sleep_mode(cx); -#endif -#ifndef ENABLE_SLEEP_MODE - msgrep->status=nasmt_ASCTL_DC_send_cx_release_request(cx); -#endif - } else - msgrep->status=-NAS_ERROR_NOTCORRECTLCR; - -#endif -} - -//--------------------------------------------------------------------------- -// Request the release of a connection -int nasmt_ioCTL_cx_release_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_cx_release_request msgreq; - struct nas_msg_cx_release_reply msgrep; - - printk("nasmt_ioCTL_cx_release: connection release requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasmt_ioCTL_cx_release: copy_from_user failure\n"); - return -EFAULT; - } - - nasmt_set_msg_cx_release_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasmt_ioCTL_cx_release: copy_to_user failure\n"); - return -EFAULT; - } - - printk("nasmt_ioCTL_cx_release: end\n"); - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Radio Bearer List -//--------------------------------------------------------------------------- -void nasmt_set_msg_rb_list_reply(uint8_t *msgrep, struct nas_msg_rb_list_request *msgreq) -{ - //--------------------------------------------------------------------------- - struct cx_entity *cx; - cx=nasmt_COMMON_search_cx(msgreq->lcr); - - if (cx!=NULL) { - uint8_t rbi; - struct rb_entity *rb; - struct nas_msg_rb_list_reply *list; - - if (cx->num_rb > NAS_LIST_RB_MAX) - msgrep[0] = NAS_LIST_RB_MAX; - else - msgrep[0] = cx->num_rb; - - list=(struct nas_msg_rb_list_reply *)(msgrep+1); - - for (rb=cx->rb, rbi=0; (rb!=NULL)&&(rbinext, ++rbi) { - list[rbi].state=rb->state; - list[rbi].rab_id=rb->rab_id; - list[rbi].sapi=rb->sapi; - list[rbi].qos=rb->qos; - } - } else - msgrep[0]=0; -} - -//--------------------------------------------------------------------------- -int nasmt_ioCTL_rb_list_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - uint8_t msgrep[NAS_LIST_RB_MAX*sizeof(struct nas_msg_rb_list_reply)+1]; - struct nas_msg_rb_list_request msgreq; - printk("nasmt_ioCTL_rb_list: Radio Bearer list requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasmt_ioCTL_rb_list: copy_from_user failure\n"); - return -EFAULT; - } - - nasmt_set_msg_rb_list_reply(msgrep, &msgreq); - - if (copy_to_user(gifr->msg, msgrep, NAS_LIST_RB_MAX*sizeof(struct nas_msg_rb_list_reply)+1)) { - printk("nasmt_ioCTL_rb_list: copy_to_user failure\n"); - return -EFAULT; - } - - printk("nasmt_ioCTL_rb_list: end\n"); - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Radio Bearer Establishment -//--------------------------------------------------------------------------- -void nasmt_set_msg_rb_establishment_reply(struct nas_msg_rb_establishment_reply *msgrep, struct nas_msg_rb_establishment_request *msgreq) -{ - //--------------------------------------------------------------------------- - msgrep->status=-NAS_ERROR_NOTRG; -} - -//--------------------------------------------------------------------------- -int nasmt_ioCTL_rb_establishment_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_rb_establishment_request msgreq; - struct nas_msg_rb_establishment_reply msgrep; - printk("nasmt_ioCTL_rb_establishment: Radio bearer establishment requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasmt_ioCTL_rb_establishment: copy_from_user failure\n"); - return -EFAULT; - } - - nasmt_set_msg_rb_establishment_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasmt_ioCTL_rb_establishment: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Radio Bearer Release -//--------------------------------------------------------------------------- -void nasmt_set_msg_rb_release_reply(struct nas_msg_rb_release_reply *msgrep, struct nas_msg_rb_release_request *msgreq) -{ - //--------------------------------------------------------------------------- - msgrep->status=-NAS_ERROR_NOTRG; -} - -//--------------------------------------------------------------------------- -int nasmt_ioCTL_rb_release_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_rb_release_request msgreq; - struct nas_msg_rb_release_reply msgrep; - printk("nasmt_ioCTL_rb_release: Radio bearer release requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasmt_ioCTL_rb_release: copy_from_user failure\n"); - return -EFAULT; - } - - nasmt_set_msg_rb_release_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasmt_ioCTL_rb_release: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Classifier List -//--------------------------------------------------------------------------- -void nasmt_set_msg_class_list_reply(uint8_t *msgrep, struct nas_msg_class_list_request *msgreq) -{ - //--------------------------------------------------------------------------- - struct cx_entity *cx; - struct classifier_entity *gc; - struct nas_msg_class_list_reply *list; - uint8_t cli; - list=(struct nas_msg_class_list_reply *)(msgrep+1); - - switch(msgreq->dir) { - case NAS_DIRECTION_SEND: - cx=nasmt_COMMON_search_cx(msgreq->lcr); - - if (cx==NULL) { - msgrep[0]=0; - return; - } - - gc=cx->sclassifier[msgreq->dscp]; - break; - - case NAS_DIRECTION_RECEIVE: - cx=NULL; - gc=gpriv->rclassifier[msgreq->dscp]; - break; - - default: - cx=NULL; - msgrep[0]=0; - return; - } - - for (cli=0; (gc!=NULL)&&(clinext, ++cli) { - list[cli].classref=gc->classref; - list[cli].lcr=msgreq->lcr; - list[cli].dir=msgreq->dir; - list[cli].dscp=msgreq->dscp; - list[cli].rab_id=gc->rab_id; - list[cli].version=gc->version; - - switch(gc->version) { - case 4: - list[cli].saddr.ipv4 = gc->saddr.ipv4; - list[cli].daddr.ipv4 = gc->daddr.ipv4; - break; - - case 6: - list[cli].saddr.ipv6 = gc->saddr.ipv6; - list[cli].daddr.ipv6 = gc->daddr.ipv6; - break; - } - - list[cli].protocol=gc->protocol; - list[cli].sport=ntohs(gc->sport); - list[cli].dport=ntohs(gc->dport); - list[cli].splen=gc->splen; - list[cli].dplen=gc->dplen; - list[cli].fct=nasmt_TOOL_invfct(gc); - } - - msgrep[0]=cli; -} - -//--------------------------------------------------------------------------- -int nasmt_ioCTL_class_list_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - uint8_t msgrep[NAS_LIST_CLASS_MAX*sizeof(struct nas_msg_class_list_reply)+1]; - struct nas_msg_class_list_request msgreq; - printk("nasmt_ioCTL_class_list: classifier list requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasmt_ioCTL_class_list: copy_from_user failure\n"); - return -EFAULT; - } - - nasmt_set_msg_class_list_reply(msgrep, &msgreq); - - if (copy_to_user(gifr->msg, msgrep, NAS_LIST_CLASS_MAX*sizeof(struct nas_msg_class_list_reply)+1)) { - printk("nasmt_ioCTL_class_list: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Request the addition of a classifier rule -//--------------------------------------------------------------------------- -void nasmt_set_msg_class_add_reply(struct nas_msg_class_add_reply *msgrep, struct nas_msg_class_add_request *msgreq) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *gc; - - if (msgreq->dscp>NAS_DSCP_DEFAULT) { - printk("nasmt_set_msg_class_add_reply: Incoherent parameter value\n"); - msgrep->status=-NAS_ERROR_NOTCORRECTDSCP; - return; - } - - if (msgreq->dir==NAS_DIRECTION_SEND) { - struct cx_entity *cx; - cx=nasmt_COMMON_search_cx(msgreq->lcr); - - if (cx!=NULL) { - printk("nasmt_set_msg_class_add_reply: DSCP %d, Classref %d\n",msgreq->dscp, msgreq->classref ); - gc=nasmt_CLASS_add_sclassifier(cx, msgreq->dscp, msgreq->classref); - printk("nasmt_set_msg_class_add_reply: %p %p\n" , msgreq, gc); - - if (gc==NULL) { - msgrep->status=-NAS_ERROR_NOMEMORY; - return; - } - } else { - msgrep->status=-NAS_ERROR_NOTCORRECTLCR; - return; - } - - gc->rab_id=msgreq->rab_id; - gc->rb=nasmt_COMMON_search_rb(cx, gc->rab_id); - } else { - if (msgreq->dir==NAS_DIRECTION_RECEIVE) { - gc=nasmt_CLASS_add_rclassifier(msgreq->dscp, msgreq->classref); - - if (gc==NULL) { - msgrep->status=-NAS_ERROR_NOMEMORY; - return; - } - } else { - msgrep->status=-NAS_ERROR_NOTCORRECTDIR; - return; - } - } - - nasmt_TOOL_fct(gc, msgreq->fct); - gc->version=msgreq->version; - - switch(gc->version) { - case 4: - gc->saddr.ipv4=msgreq->saddr.ipv4; - gc->daddr.ipv4=msgreq->daddr.ipv4; - gc->splen=msgreq->splen; - gc->dplen=msgreq->dplen; - break; - - case 6: - gc->saddr.ipv6=msgreq->saddr.ipv6; - gc->daddr.ipv6=msgreq->daddr.ipv6; - gc->splen=msgreq->splen; - gc->dplen=msgreq->dplen; - break; - - case 0: - gc->saddr.ipv6.s6_addr32[0]=0; - gc->daddr.ipv6.s6_addr32[1]=0; - gc->saddr.ipv6.s6_addr32[2]=0; - gc->daddr.ipv6.s6_addr32[3]=0; - gc->splen=0; - gc->dplen=0; - break; - - default: - msgrep->status=-NAS_ERROR_NOTCORRECTVERSION; - kfree(gc); - return; - } - - gc->protocol=msgreq->protocol; - gc->sport=htons(msgreq->sport); - gc->dport=htons(msgreq->dport); - msgrep->status=0; -} - -//--------------------------------------------------------------------------- -int nasmt_ioCTL_class_add_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_class_add_request msgreq; - struct nas_msg_class_add_reply msgrep; - printk("nasmt_ioCTL_class_add: Add classifier components requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasmt_ioCTL_class_add: copy_from_user failure\n"); - return -EFAULT; - } - - nasmt_set_msg_class_add_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasmt_ioCTL_class_add: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Request the deletion of a classifier rule -//--------------------------------------------------------------------------- -void nasmt_set_msg_class_del_reply(struct nas_msg_class_del_reply *msgrep, struct nas_msg_class_del_request *msgreq) -{ - //--------------------------------------------------------------------------- - if (msgreq->dscp>NAS_DSCP_DEFAULT) { - printk("nasmt_set_msg_class_del_reply: Incoherent parameter value\n"); - msgrep->status=-NAS_ERROR_NOTCORRECTDSCP; - return; - } - - if (msgreq->dir==NAS_DIRECTION_SEND) { - struct cx_entity *cx; - cx=nasmt_COMMON_search_cx(msgreq->lcr); - - if (cx!=NULL) - nasmt_CLASS_del_sclassifier(cx, msgreq->dscp, msgreq->classref); - else { - msgrep->status=-NAS_ERROR_NOTCORRECTLCR; - return; - } - } else { - if (msgreq->dir==NAS_DIRECTION_RECEIVE) - nasmt_CLASS_del_rclassifier(msgreq->dscp, msgreq->classref); - else { - msgrep->status=-NAS_ERROR_NOTCORRECTDIR; - return; - } - } - - msgrep->status=0; -} - -//--------------------------------------------------------------------------- -int nasmt_ioCTL_class_del_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_class_del_request msgreq; - struct nas_msg_class_del_reply msgrep; - printk("nasmt_ioCTL_class_del: Del classifier components requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasmt_ioCTL_class_del: copy_from_user failure\n"); - return -EFAULT; - } - - nasmt_set_msg_class_del_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasmt_ioCTL_class_del: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Measurement -// Messages for Measurement transfer - -//--------------------------------------------------------------------------- -void nasmt_set_msg_measure_reply(struct nas_msg_measure_reply *msgrep, struct nas_msg_measure_request *msgreq) -{ - //--------------------------------------------------------------------------- - struct cx_entity *cx; - int lcr=0; // Temp lcr->mt =0 - int i; - - cx = nasmt_COMMON_search_cx(lcr); - - if (cx!=NULL) { - msgrep->num_cells = cx->num_measures; - - for (i=0; inum_measures; i++) { - msgrep-> measures[i].cell_id = cx->meas_cell_id[i]; - msgrep-> measures[i].level = cx->meas_level[i]; - msgrep-> measures[i].provider_id = cx->provider_id[i]; - } - - msgrep->signal_lost_flag = 0; - } else { - // msgrep->status=-NAS_ERROR_NOTCORRECTLCR; - // return; - } -} -//--------------------------------------------------------------------------- -int nasmt_ioCTL_measure_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_measure_request msgreq; - struct nas_msg_measure_reply msgrep; - printk("nasmt_ioCTL_measure: Measurement requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasmt_ioCTL_measure: copy_from_user failure\n"); - return -EFAULT; - } - - nasmt_set_msg_measure_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasmt_ioCTL_measure: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// IMEI -// Messages for IMEI transfer -//--------------------------------------------------------------------------- -void nasmt_set_msg_imei_reply(struct nas_msg_l2id_reply *msgrep) -{ - //--------------------------------------------------------------------------- - struct cx_entity *cx; - int lcr=0; // Temp lcr->mt =0 - int i; - - cx=nasmt_COMMON_search_cx(lcr); - - if (cx!=NULL) { - msgrep->l2id[0] = cx->iid6[0]; - msgrep->l2id[1] = cx->iid6[1]; - } else { - // msgrep->status=-NAS_ERROR_NOTCORRECTLCR; - // return; - } -} -//--------------------------------------------------------------------------- -int nasmt_ioCTL_imei_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_l2id_reply msgrep; - printk("nasmt_ioCTL_imei: IMEI requested\n"); - nasmt_set_msg_imei_reply(&msgrep); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasmt_ioCTL_imei: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// IOCTL command -//--------------------------------------------------------------------------- -int nasmt_CTL_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - //--------------------------------------------------------------------------- - struct nas_ioctl *gifr; - int r; - printk("nasmt_CTL_ioctl: begin\n"); - - //spin_lock(&gpriv->lock); - switch(cmd) { - case NASMT_IOCTL_RAL: - gifr=(struct nas_ioctl *)ifr; - - switch(gifr->type) { - case NAS_MSG_STATISTIC_REQUEST: - r=nasmt_ioCTL_statistic_request(gifr); - break; - - case NAS_MSG_CX_ESTABLISHMENT_REQUEST: - r=nasmt_ioCTL_cx_establishment_request(gifr); - break; - - case NAS_MSG_CX_RELEASE_REQUEST: - r=nasmt_ioCTL_cx_release_request(gifr); - break; - - case NAS_MSG_CX_LIST_REQUEST: - r=nasmt_ioCTL_cx_list_request(gifr); - break; - - case NAS_MSG_RB_ESTABLISHMENT_REQUEST: - r=nasmt_ioCTL_rb_establishment_request(gifr); - break; - - case NAS_MSG_RB_RELEASE_REQUEST: - r= nasmt_ioCTL_rb_release_request(gifr); - break; - - case NAS_MSG_RB_LIST_REQUEST: - r=nasmt_ioCTL_rb_list_request(gifr); - break; - - case NAS_MSG_CLASS_ADD_REQUEST: - r=nasmt_ioCTL_class_add_request(gifr); - break; - - case NAS_MSG_CLASS_LIST_REQUEST: - r=nasmt_ioCTL_class_list_request(gifr); - break; - - case NAS_MSG_CLASS_DEL_REQUEST: - r=nasmt_ioCTL_class_del_request(gifr); - break; - - case NAS_MSG_MEAS_REQUEST: - r=nasmt_ioCTL_measure_request(gifr); - break; - - case NAS_MSG_IMEI_REQUEST: - r=nasmt_ioCTL_imei_request(gifr); - break; - - default: - printk("nasmt_CTL_ioctl: unkwon request type, type=%x\n", gifr->type); - r=-EFAULT; - } - - break; - - default: - printk("nasmt_CTL_ioctl: Unknown ioctl command, cmd=%x\n", cmd); - r=-EFAULT; - } - - //spin_unlock(&gpriv->lock); - printk("nasmt_CTL_ioctl: end\n"); - return r; -} - -//--------------------------------------------------------------------------- -void nasmt_CTL_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc) -{ - //--------------------------------------------------------------------------- - printk("nasmt_CTL_send - void \n"); -} - diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.h b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.h deleted file mode 100644 index 40118d8368..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_iocontrol.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasmt_iocontrol.h -* \brief I/O control constnats and structures for upper layers of driver for OpenAirInterface CELLULAR version - MT -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#ifndef NASMTD_CTL_H -#define NASMTD_CTL_H - -#include -#include -#include -#include - -#define NAS_MSG_MAXLEN 1100 - -// type of CTL message -#define NAS_MSG_STATISTIC_REQUEST 1 -#define NAS_MSG_STATISTIC_REPLY 2 -#define NAS_MSG_ECHO_REQUEST 3 -#define NAS_MSG_ECHO_REPLY 4 -#define NAS_MSG_CX_ESTABLISHMENT_REQUEST 5 -#define NAS_MSG_CX_ESTABLISHMENT_REPLY 6 -#define NAS_MSG_CX_RELEASE_REQUEST 7 -#define NAS_MSG_CX_RELEASE_REPLY 8 -#define NAS_MSG_CX_LIST_REQUEST 9 -#define NAS_MSG_CX_LIST_REPLY 10 -#define NAS_MSG_RB_ESTABLISHMENT_REQUEST 11 -#define NAS_MSG_RB_ESTABLISHMENT_REPLY 12 -#define NAS_MSG_RB_RELEASE_REQUEST 13 -#define NAS_MSG_RB_RELEASE_REPLY 14 -#define NAS_MSG_RB_LIST_REQUEST 15 -#define NAS_MSG_RB_LIST_REPLY 16 -#define NAS_MSG_CLASS_ADD_REQUEST 17 -#define NAS_MSG_CLASS_ADD_REPLY 18 -#define NAS_MSG_CLASS_DEL_REQUEST 19 -#define NAS_MSG_CLASS_DEL_REPLY 20 -#define NAS_MSG_CLASS_LIST_REQUEST 21 -#define NAS_MSG_CLASS_LIST_REPLY 22 -#define NAS_MSG_MEAS_REQUEST 23 -#define NAS_MSG_MEAS_REPLY 24 -#define NAS_MSG_IMEI_REQUEST 25 -#define NAS_MSG_IMEI_REPLY 26 - -// Max number of entry of a message list -#define NAS_LIST_CX_MAX 32 -#define NAS_LIST_RB_MAX 32 -#define NAS_LIST_CLASS_MAX 32 - -typedef uint16_t nasMsgType_t; - -struct nas_ioctl { - char name[IFNAMSIZ]; - nasMsgType_t type; - char *msg; -}; - -struct nas_msg_statistic_reply { - uint32_t rx_packets; - uint32_t tx_packets; - uint32_t rx_bytes; - uint32_t tx_bytes; - uint32_t rx_errors; - uint32_t tx_errors; - uint32_t rx_dropped; - uint32_t tx_dropped; -}; - -struct nas_msg_cx_list_reply { - nasLocalConnectionRef_t lcr; // Local Connection reference - uint8_t state; - nasCellID_t cellid; // cell identification - uint32_t iid6[2]; // IPv6 interface identification - uint8_t iid4; // IPv4 interface identification - uint16_t num_rb; - uint16_t nsclassifier; -}; -struct nas_msg_cx_establishment_reply { - int status; -}; -struct nas_msg_cx_establishment_request { - nasLocalConnectionRef_t lcr; // Local Connection reference - nasCellID_t cellid; // Cell identification -}; -struct nas_msg_cx_release_reply { - int status; -}; -struct nas_msg_cx_release_request { - nasLocalConnectionRef_t lcr; // Local Connection reference -}; - -struct nas_msg_rb_list_reply { - nasRadioBearerId_t rab_id; - nasSapId_t sapi; - nasQoSTrafficClass_t qos; - uint8_t state; -}; -struct nas_msg_rb_list_request { - nasLocalConnectionRef_t lcr; // Local Connection reference -}; -struct nas_msg_rb_establishment_reply { - int status; -}; -struct nas_msg_rb_establishment_request { - nasLocalConnectionRef_t lcr; // Local Connection reference - nasRadioBearerId_t rab_id; - nasQoSTrafficClass_t qos; -}; - -struct nas_msg_rb_release_reply { - int status; -}; -struct nas_msg_rb_release_request { - nasLocalConnectionRef_t lcr; // Local Connection reference - nasRadioBearerId_t rab_id; -}; - -struct nas_msg_class_add_request { - nasLocalConnectionRef_t lcr; // Local Connection reference - nasRadioBearerId_t rab_id; - uint8_t dir; // direction (send or receive) - uint8_t dscp; // codepoint - uint8_t fct; - uint16_t classref; - uint8_t version; - union { - struct in6_addr ipv6; - uint32_t ipv4; - } saddr; // IP source address - uint8_t splen; // prefix length - union { - struct in6_addr ipv6; - uint32_t ipv4; - } daddr; // IP destination address - uint8_t dplen; // prefix length - uint8_t protocol; // high layer protocol type - uint16_t sport; // source port - uint16_t dport; // destination port -}; -struct nas_msg_class_add_reply { - int status; -}; -struct nas_msg_class_del_request { - nasLocalConnectionRef_t lcr; // Local Connection reference - uint8_t dir; // direction (send or receive) - uint8_t dscp; // codepoint - uint16_t classref; -}; -struct nas_msg_class_del_reply { - int status; -}; -#define nas_msg_class_list_reply nas_msg_class_add_request -struct nas_msg_class_list_request { - nasLocalConnectionRef_t lcr; // Local Connection reference - uint8_t dir; - uint8_t dscp; -}; - - -// Messages for Measurement transfer - MW 01/04/2005 -typedef uint32_t nioctlProviderId_t; -typedef uint16_t nioctlSignalLoss_t; -typedef struct nioctlMeasures { - nasCellID_t cell_id; - nasSigLevel_t level; - nioctlProviderId_t provider_id; -} nioctlMeasures_t; - -struct nas_msg_measure_request { - nasNumRGsMeas_t num_cells; - nasCellID_t cellid[MAX_MEASURE_NB]; // Cell identification - uint16_t num_providers; - nioctlProviderId_t provider_id[MAX_MEASURE_NB]; // Provider identification -}; -struct nas_msg_measure_reply { - nasNumRGsMeas_t num_cells; - nioctlMeasures_t measures[MAX_MEASURE_NB]; - nioctlSignalLoss_t signal_lost_flag; -}; - -// Messages for L2Id transfer - MW -typedef uint32_t nioctlL2Id_t[2]; - -struct nas_msg_l2id_reply { - nioctlL2Id_t l2id; -}; - - -#endif diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_netlink.c b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_netlink.c deleted file mode 100644 index 2f92b94717..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_netlink.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasmt_netlink.c -* \brief Netlink socket functions for OpenAirInterface CELLULAR version - MT -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -//#include -#include -#include -#include -#include -#include -#include - -#include - -#include "nasmt_variables.h" -#include "nasmt_proto.h" - -static struct sock *nas_nl_sk = NULL; -static struct sock *nas_rrcnl_sk = NULL; - -//static int exit_netlink_thread=0; -static DEFINE_MUTEX(nasmt_mutex); - -// This can also be implemented using thread to get the data from PDCP without blocking. -//--------------------------------------------------------------------------- -// Function for transfer with PDCP (from NASLITE) -static void nasmt_nl_data_ready (struct sk_buff *skb) -{ - //--------------------------------------------------------------------------- - struct nlmsghdr *nlh = NULL; - - // Start debug information -#ifdef NETLINK_DEBUG - printk("nasmt_nl_data_ready - begin \n"); -#endif - - if (!skb) { - printk("nasmt_nl_data_ready - input parameter skb is NULL \n"); - return; - } - - // End debug information - -#ifdef NETLINK_DEBUG - printk("nasmt_nl_data_ready - Received socket from PDCP\n"); -#endif //NETLINK_DEBUG - nlh = (struct nlmsghdr *)skb->data; - nasmt_COMMON_QOS_receive(nlh); -} - -//--------------------------------------------------------------------------- -// Function for transfer with RRC -static void nasmt_rrcnl_data_ready (struct sk_buff *skb) -{ - //--------------------------------------------------------------------------- - struct nlmsghdr *nlh = NULL; - char target_sap; - uint8_t cxi = 0; - - // Start debug information -#ifdef NAS_DEBUG_RRCNL - printk("nasmt_rrcnl_data_ready - begin \n"); -#endif - - if (!skb) { - printk("nasmt_rrcnl_data_ready - input parameter skb is NULL \n"); - return; - } - - // End debug information - - nlh = (struct nlmsghdr *)skb->data; - //pdcph = (struct pdcp_data_ind_header_t *)NLMSG_DATA(nlh); - //nasmt_TOOL_print_buffer((char *)NLMSG_DATA(nlh), 48); - - target_sap = ((char*)NLMSG_DATA(nlh))[0]; -#ifdef NAS_DEBUG_RRCNL - printk("nasmt_rrcnl_data_ready - Received on socket from RRC, SAP %d\n", target_sap); -#endif //NAS_DEBUG_RRCNL - - switch (target_sap) { - case RRC_NAS_GC_OUT: - //printk("nasmt_rrcnl_data_ready - Calling nasmt_ASCTL_GC_receive\n"); - nasmt_ASCTL_GC_receive(&((char*)NLMSG_DATA(nlh))[1]); - break; - - case RRC_NAS_DC0_OUT: - //printk("nasmt_rrcnl_data_ready - Calling nasmt_ASCTL_DC_receive\n"); - nasmt_ASCTL_DC_receive(gpriv->cx+cxi, &((char*)NLMSG_DATA(nlh))[1]); - break; - - default: - printk("nasmt_rrcnl_data_ready - Invalid SAP value received\n"); - } - -} - -//--------------------------------------------------------------------------- -int nasmt_netlink_init(void) -{ - //--------------------------------------------------------------------------- - printk("nasmt_netlink_init - begin \n"); - - nas_nl_sk = netlink_kernel_create(&init_net,OAI_IP_DRIVER_NETLINK_ID, 0, nasmt_nl_data_ready, - &nasmt_mutex, // NULL - THIS_MODULE); - - if (!nas_nl_sk) { - printk("nasmt_netlink_init - netlink_kernel_create failed for PDCP socket\n"); - return(-1); - } - - nas_rrcnl_sk = netlink_kernel_create(&init_net,NAS_RRCNL_ID, 0, nasmt_rrcnl_data_ready, - &nasmt_mutex, // NULL - THIS_MODULE); - - if (!nas_rrcnl_sk) { - printk("nasmt_rrcnl_init - netlink_kernel_create failed for RRC socket\n"); - return(-1); - } - - return(0); -} - -//--------------------------------------------------------------------------- -void nasmt_netlink_release(void) -{ - //--------------------------------------------------------------------------- - printk("nasmt_netlink_release - begin \n"); - - //exit_netlink_thread=1; - printk("nasmt_netlink_release - Releasing netlink sockets\n"); - - if(nas_nl_sk) { - netlink_kernel_release(nas_nl_sk); - } - - if(nas_rrcnl_sk) { - netlink_kernel_release(nas_rrcnl_sk); - } - -} - -//--------------------------------------------------------------------------- -int nasmt_netlink_send(unsigned char *data_buffer, unsigned int data_length, int destination) -{ - //--------------------------------------------------------------------------- - struct sk_buff *nl_skb; - struct nlmsghdr *nlh; - int status; - // Start debug information -#ifdef NETLINK_DEBUG - printk("nasmt_netlink_send - begin \n"); -#endif - - if (!data_buffer) { - printk("nasmt_netlink_send - ERROR - input parameter data is NULL \n"); - return(0); - } - - if (!nas_nl_sk || !nas_rrcnl_sk) { - printk("nasmt_netlink_send - ERROR - socket is NULL\n"); - return(0); - } - - // End debug information - - nl_skb = alloc_skb(NLMSG_SPACE(data_length),GFP_ATOMIC); - - if (!nl_skb) { - printk("nasmt_netlink_send - ERROR - could not allocate skbuffer\n"); - return(0); - } - - nlh = (struct nlmsghdr *)nl_skb->data; - - // printk("nasmt_netlink_send Sending %d bytes (%d)\n",data_length,NLMSG_SPACE(data_length)); - skb_put(nl_skb, NLMSG_SPACE(data_length)); - memcpy(NLMSG_DATA(nlh), data_buffer, data_length); - nlh->nlmsg_len = NLMSG_SPACE(data_length); - - nlh->nlmsg_pid = 0; /* from kernel */ - NETLINK_CB(nl_skb).pid = 0; - - // destination 0 = PDCP, 1 = RRC - if (!destination) { -#ifdef NETLINK_DEBUG - printk("nasmt_netlink_send - nl_skb %p, nl_sk %p, nlh %p, nlh->nlmsg_len %d\n", nl_skb, nas_nl_sk, nlh, nlh->nlmsg_len); -#endif //DEBUG_NETLINK - status = netlink_unicast(nas_nl_sk, nl_skb, NL_DEST_PID, MSG_DONTWAIT); - } else { -#ifdef NAS_DEBUG_RRCNL - printk("nasmt_rrcnl_send - nl_skb %p, nas_rrcnl_sk %p, nlh %p, nlh->nlmsg_len %d\n", nl_skb, nas_rrcnl_sk, nlh, nlh->nlmsg_len); -#endif //NAS_DEBUG_RRCNL - status = netlink_unicast(nas_rrcnl_sk, nl_skb, NL_DEST_RRC_PID, MSG_DONTWAIT); - } - - if (status < 0) { - printk("nasmt_netlink_send - SEND status is %d\n",status); - return(0); - } else { -#ifdef NETLINK_DEBUG - printk("nasmt_netlink_send - SEND status is %d, data_length %d\n",status, data_length); -#endif - return data_length; - } -} - - diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_proto.h b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_proto.h deleted file mode 100644 index 3a6ffe4848..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_proto.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasmt_proto.h -* \brief Function prototypes for OpenAirInterface CELLULAR version - MT -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#ifndef _NASMTD_PROTO_H -#define _NASMTD_PROTO_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include - -//#include "rrc_nas_primitives.h" -//#include "protocol_vars_extern.h" -//#include "as_sap.h" -//#include "rrc_qos.h" -//#include "rrc_sap.h" - -// nasmt_netlink.c -void nasmt_netlink_release(void); -int nasmt_netlink_init(void); -int nasmt_netlink_send(unsigned char *data_buffer, unsigned int data_length, int destination); - -// nasmt_common.c -//void nasmt_COMMON_receive(uint16_t hlen, uint16_t dlength, int sap); -void nasmt_COMMON_receive(uint16_t bytes_read, uint16_t payload_length, void *data_buffer, int rb_id, int sap); - -void nasmt_COMMON_QOS_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc); -void nasmt_COMMON_del_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc); -#ifndef PDCP_USE_NETLINK -void nasmt_COMMON_QOS_receive(struct cx_entity *cx); -#else -void nasmt_COMMON_QOS_receive(struct nlmsghdr *nlh); -#endif -struct rb_entity *nasmt_COMMON_add_rb(struct cx_entity *cx, nasRadioBearerId_t rabi, nasQoSTrafficClass_t qos); -struct rb_entity *nasmt_COMMON_search_rb(struct cx_entity *cx, nasRadioBearerId_t rabi); -struct cx_entity *nasmt_COMMON_search_cx(nasLocalConnectionRef_t lcr); -void nasmt_COMMON_del_rb(struct cx_entity *cx, nasRadioBearerId_t rab_id, nasIPdscp_t dscp); -void nasmt_COMMON_flush_rb(struct cx_entity *cx); - - -//nasmt_ascontrol.c -void nasmt_ASCTL_init(void); -void nasmt_ASCTL_timer(unsigned long data); -int nasmt_ASCTL_DC_receive(struct cx_entity *cx, char *buffer); -int nasmt_ASCTL_GC_receive(char *buffer); -int nasmt_ASCTL_DC_send_cx_establish_request(struct cx_entity *cx); -int nasmt_ASCTL_DC_send_cx_release_request(struct cx_entity *cx); -void nasmt_ASCTL_DC_send_sig_data_request(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc); -void nasmt_ASCTL_DC_send_peer_sig_data_request(struct cx_entity *cx, uint8_t sig_category); -int nasmt_ASCTL_leave_sleep_mode(struct cx_entity *cx); -int nasmt_ASCTL_enter_sleep_mode(struct cx_entity *cx); - -// nasmt_iocontrol.c -void nasmt_CTL_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc); -int nasmt_CTL_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); - -// nasmt_classifier.c -void nasmt_CLASS_send(struct sk_buff *skb); -struct classifier_entity *nasmt_CLASS_add_sclassifier(struct cx_entity *cx, uint8_t dscp, uint16_t classref); -struct classifier_entity *nasmt_CLASS_add_rclassifier(uint8_t dscp, uint16_t classref); -void nasmt_CLASS_del_sclassifier(struct cx_entity *cx, uint8_t dscp, uint16_t classref); -void nasmt_CLASS_del_rclassifier(uint8_t dscp, uint16_t classref); -void nasmt_CLASS_flush_sclassifier(struct cx_entity *cx); -void nasmt_CLASS_flush_rclassifier(void); - -// nasmt_tool.c -uint8_t nasmt_TOOL_invfct(struct classifier_entity *gc); -void nasmt_TOOL_fct(struct classifier_entity *gc, uint8_t fct); -void nasmt_TOOL_imei2iid(uint8_t *imei, uint8_t *iid); - -void nasmt_TOOL_eth_imei2iid(unsigned char *imei, unsigned char *addr ,unsigned char *iid, unsigned char len); -uint8_t nasmt_TOOL_get_dscp6(struct ipv6hdr *iph); -uint8_t nasmt_TOOL_get_dscp4(struct iphdr *iph); -uint8_t *nasmt_TOOL_get_protocol6(struct ipv6hdr *iph, uint8_t *protocol); -uint8_t *nasmt_TOOL_get_protocol4(struct iphdr *iph, uint8_t *protocol); - -void nasmt_TOOL_pk_icmp6(struct icmp6hdr *icmph); - -void nasmt_TOOL_print_state(uint8_t state); -void nasmt_TOOL_print_buffer(unsigned char * buffer,int length); -void nasmt_TOOL_print_rb_entity(struct rb_entity *rb); -void nasmt_TOOL_print_classifier(struct classifier_entity *gc); - -#endif diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_sap.h b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_sap.h deleted file mode 100644 index c0934f4622..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_sap.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasmt_sap.h -* \brief SAP constants for OpenAirInterface CELLULAR version - MT -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#ifndef _NASMTD_SAP_H -#define _NASMTD_SAP_H - -// RT-FIFO identifiers ** must be identical to Access Stratum as_sap.h and rrc_sap.h -#define RRC_DEVICE_GC RRC_SAPI_UE_GCSAP -#define RRC_DEVICE_NT RRC_SAPI_UE_NTSAP -#define RRC_DEVICE_DC_INPUT0 RRC_SAPI_UE_DCSAP_IN -#define RRC_DEVICE_DC_OUTPUT0 RRC_SAPI_UE_DCSAP_OUT - -//#define QOS_DEVICE_CONVERSATIONAL_INPUT QOS_SAPI_CONVERSATIONAL_INPUT_MT -//#define QOS_DEVICE_CONVERSATIONAL_OUTPUT QOS_SAPI_CONVERSATIONAL_OUTPUT_MT - -#define PDCP2PDCP_USE_RT_FIFO 21 -#define NAS2PDCP_FIFO 22 - -//FIFO indexes in control blocks -#define NAS_DC_INPUT_SAPI 0 -#define NAS_DC_OUTPUT_SAPI 1 -#define NAS_SAPI_CX_MAX 2 - -#define NAS_GC_SAPI 0 -#define NAS_NT_SAPI 1 -#define NAS_DRB_INPUT_SAPI 2 //NAS_CO_INPUT_SAPI -#define NAS_DRB_OUTPUT_SAPI 3 //NAS_CO_OUTPUT_SAPI -#define NAS_SAPI_MAX 4 - -//#define NAS_QOS_CONVERSATIONAL UMTS_TRAFFIC_CONVERSATIONAL -// - -/* Defined in RRC -#define RRC_NAS_GC_IN 0 -#define RRC_NAS_GC_OUT 1 -#define RRC_NAS_NT_IN 2 -#define RRC_NAS_NT_OUT 3 -#define RRC_NAS_DC0_IN 4 -#define RRC_NAS_DC0_OUT 5 -#define RRC_NAS_DC1_IN 6 -#define RRC_NAS_DC1_OUT 7 -#define RRC_NAS_DC2_IN 8 -#define RRC_NAS_DC2_OUT 9 -*/ -#endif - - - diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_tool.c b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_tool.c deleted file mode 100644 index 4c5d3fcf6e..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_tool.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*************************************************************************** - nasmt_tool.c - description - *************************************************************************** - - ***************************************************************************/ -/*! \file nasmt_tool.c -* \brief Tool functions for OpenAirInterface CELLULAR version - MT -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ - -#include "nasmt_variables.h" -#include "nasmt_proto.h" - -//--------------------------------------------------------------------------- -// -void nasmt_TOOL_fct(struct classifier_entity *gc, uint8_t fct) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasmt_TOOL_fct - begin \n"); -#endif - - if (gc==NULL) { - printk("nasmt_TOOL_fct - input parameter gc is NULL \n"); - return; - } - - // End debug information - switch(fct) { - case NAS_FCT_QOS_SEND: - gc->fct=nasmt_COMMON_QOS_send; - break; - - case NAS_FCT_CTL_SEND: - gc->fct=nasmt_CTL_send; - break; - - case NAS_FCT_DC_SEND: - gc->fct=nasmt_ASCTL_DC_send_sig_data_request; - break; - - case NAS_FCT_DEL_SEND: - gc->fct=nasmt_COMMON_del_send; - break; - - default: - gc->fct=nasmt_COMMON_del_send; - } -} - -//--------------------------------------------------------------------------- -uint8_t nasmt_TOOL_invfct(struct classifier_entity *gc) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasmt_TOOL_invfct - begin \n"); -#endif - - if (gc==NULL) { - printk("nasmt_TOOL_invfct - input parameter gc is NULL \n"); - return 0; - } - - // End debug information - if (gc->fct==nasmt_COMMON_QOS_send) - return NAS_FCT_QOS_SEND; - - if (gc->fct==nasmt_CTL_send) - return NAS_FCT_CTL_SEND; - - if (gc->fct==nasmt_COMMON_del_send) - return NAS_FCT_DEL_SEND; - - if (gc->fct==nasmt_ASCTL_DC_send_sig_data_request) - return NAS_FCT_DC_SEND; - - return 0; -} - -//--------------------------------------------------------------------------- -uint8_t nasmt_TOOL_get_dscp6(struct ipv6hdr *iph) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasmt_TOOL_get_dscp6 - begin \n"); -#endif - - if (iph==NULL) { - printk("nasmt_TOOL_get_dscp6 - input parameter ipv6hdr is NULL \n"); - return 0; - } - - // End debug information - // return (ntohl(((*(__u32 *)iph)&NAS_TRAFFICCLASS_MASK)))>>22; //Yan - return (ntohl(((*(__u32 *)iph)&NAS_TRAFFICCLASS_MASK)))>>20; -} - -//--------------------------------------------------------------------------- -uint8_t nasmt_TOOL_get_dscp4(struct iphdr *iph) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasmt_TOOL_get_dscp4 - begin \n"); -#endif - - if (iph==NULL) { - printk("nasmt_TOOL_get_dscp4 - input parameter ipv4hdr is NULL \n"); - return 0; - } - - // End debug information - return ((iph->tos)>>5)<<3; -} - - -//--------------------------------------------------------------------------- -uint8_t *nasmt_TOOL_get_protocol6(struct ipv6hdr *iph, uint8_t *protocol) -{ - //--------------------------------------------------------------------------- - uint16_t size; - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasmt_TOOL_get_protocol6 - begin \n"); -#endif - - if (iph==NULL) { - printk("nasmt_TOOL_get_protocol6 - input parameter ipv6hdr is NULL \n"); - return NULL; - } - - if (protocol==NULL) { - printk("nasmt_TOOL_get_protocol6 - input parameter protocol is NULL \n"); - return NULL; - } - - // End debug information - *protocol=iph->nexthdr; - size=NAS_IPV6_SIZE; - - while (1) { - switch(*protocol) { - case IPPROTO_UDP: - case IPPROTO_TCP: - case IPPROTO_ICMPV6: - return (uint8_t *)((uint8_t *)iph+size); - - case IPPROTO_HOPOPTS: - case IPPROTO_ROUTING: - case IPPROTO_DSTOPTS: - *protocol=((uint8_t *)iph+size)[0]; - size+=((uint8_t *)iph+size)[1]*8+8; - break; - - case IPPROTO_FRAGMENT: - *protocol=((uint8_t *)iph+size)[0]; - size+=((uint8_t *)iph+size)[1]+8; - break; - - case IPPROTO_NONE: - case IPPROTO_AH: - case IPPROTO_ESP: - default: - return NULL; - } - } -} - -//--------------------------------------------------------------------------- -uint8_t *nasmt_TOOL_get_protocol4(struct iphdr *iph, uint8_t *protocol) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasmt_TOOL_get_protocol4 - begin \n"); -#endif - - if (iph==NULL) { - printk("nasmt_TOOL_get_protocol4 - input parameter iph is NULL \n"); - return NULL; - } - - if (protocol==NULL) { - printk("nasmt_TOOL_get_protocol4 - input parameter protocol is NULL \n"); - return NULL; - } - - // End debug information - *protocol=iph->protocol; - - switch(*protocol) { - case IPPROTO_UDP: - case IPPROTO_TCP: - case IPPROTO_ICMP: - return (uint8_t *)((uint8_t *)iph+iph->tot_len); - - default: - return NULL; - } -} - -//--------------------------------------------------------------------------- -// Convert the IMEI to iid -void nasmt_TOOL_imei2iid(uint8_t *imei, uint8_t *iid) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasmt_TOOL_imei2iid - begin \n"); -#endif - - if (imei==NULL) { - printk("nasmt_TOOL_imei2iid - input parameter imei is NULL \n"); - return; - } - - if (iid==NULL) { - printk("nasmt_TOOL_imei2iid - input parameter iid is NULL \n"); - return; - } - - // End debug information - memset(iid, 0, NAS_ADDR_LEN); - iid[0] = 0x03; - iid[1] = 16*imei[0]+imei[1]; - iid[2] = 16*imei[2]+imei[3]; - iid[3] = 16*imei[4]+imei[5]; - iid[4] = 16*imei[6]+imei[7]; - iid[5] = 16*imei[8]+imei[9]; - iid[6] = 16*imei[10]+imei[11]; - iid[7] = 16*imei[12]+imei[13]; -} - -//--------------------------------------------------------------------------- -// Convert the IMEI to iid -void nasmt_TOOL_eth_imei2iid(unsigned char *imei, unsigned char *addr ,unsigned char *iid, unsigned char len) -{ - //--------------------------------------------------------------------------- - unsigned int index; - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasmt_TOOL_eth_imei2iid - begin \n"); -#endif - - if (!imei || !addr || !iid) { - printk("OAI_NW_DRV_TOOL_eNB_IMEI2IID - input parameter imei, addr or iid is NULL \n"); - return; - } - - // End debug information - // set addr (should be device HW address) - memset(addr, 0, len); - addr[0] = 0x00; // to be compatible between link local and global - - // len -1 because of insertion of 0 above - for (index = 0; index < (len-1); index++) { - addr[index+1] = 16*imei[index*2]+imei[index*2+1]; - } - - // set iid6 - memset(iid, 0, NAS_ADDR_LEN); - iid[0] = 0x02; - iid[1] = 16*imei[0]+imei[1]; - iid[2] = 16*imei[2]+imei[3]; - iid[3] = 0xff; - iid[4] = 0xfe; - iid[5] = 16*imei[4]+imei[5]; - iid[6] = 16*imei[6]+imei[7]; - iid[7] = 16*imei[8]+imei[9]; - -} - -//--------------------------------------------------------------------------- -void nasmt_TOOL_pk_icmp6(struct icmp6hdr *icmph) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef GRAAL_DEBUG_TOOL - printk("nasmt_TOOL_pk_icmp6 - begin \n"); -#endif - - if (!icmph) { - printk("nasmt_TOOL_pk_icmp6 - input parameter icmph is NULL \n"); - return; - } - - // End debug information - printk("ICMPv6:\t type= %d, code = %d\n", icmph->icmp6_type, icmph->icmp6_code); - - switch(icmph->icmp6_type) { - case ICMPV6_DEST_UNREACH: - printk("Destination unreachable\n"); - break; - - case ICMPV6_PKT_TOOBIG: - printk("Packet too big\n"); - break; - - case ICMPV6_TIME_EXCEED: - printk("Time exceeded\n"); - break; - - case ICMPV6_PARAMPROB: - printk("Parameter problem\n"); - break; - - case ICMPV6_ECHO_REQUEST: - printk("Echo request\n"); - break; - - case ICMPV6_ECHO_REPLY: - printk("Echo reply\n"); - break; - - case ICMPV6_MGM_QUERY: - printk("Multicast listener query\n"); - break; - - case ICMPV6_MGM_REPORT: - printk("Multicast listener report\n"); - break; - - case ICMPV6_MGM_REDUCTION: - printk("Multicast listener done\n"); - break; - - case NDISC_ROUTER_SOLICITATION: - printk("Router solicitation\n"); - break; - - case NDISC_ROUTER_ADVERTISEMENT: - printk("Router advertisment\n"); - break; - - case NDISC_NEIGHBOUR_SOLICITATION: - printk("Neighbour solicitation\n"); - break; - - case NDISC_NEIGHBOUR_ADVERTISEMENT: - printk("Neighbour advertisment\n"); - break; - - case NDISC_REDIRECT: - printk("redirect message\n"); - break; - } -} - -//--------------------------------------------------------------------------- -void nasmt_TOOL_print_state(uint8_t state) -{ - //--------------------------------------------------------------------------- - switch(state) { - case NAS_IDLE: - printk("NAS_IDLE\n"); - return; - - case NAS_CX_FACH: - printk("NAS_CX_FACH\n"); - return; - - case NAS_CX_DCH: - printk("NAS_CX_DCH\n"); - return; - - case NAS_CX_RECEIVED: - printk("NAS_CX_RECEIVED\n"); - return; - - case NAS_CX_CONNECTING: - printk("NAS_CX_CONNECTING\n"); - return; - - case NAS_CX_RELEASING: - printk("NAS_CX_RELEASING\n"); - return; - - case NAS_CX_CONNECTING_FAILURE: - printk("NAS_CX_CONNECTING_FAILURE\n"); - return; - - case NAS_CX_RELEASING_FAILURE: - printk("NAS_CX_RELEASING_FAILURE\n"); - return; - - case NAS_RB_ESTABLISHING: - printk("NAS_RB_ESTABLISHING\n"); - return; - - case NAS_RB_RELEASING: - printk("NAS_RB_RELEASING\n"); - return; - - case NAS_RB_DCH: - printk("NAS_RB_DCH\n"); - return; - - default: - printk("nasmt_TOOL_print_state - Unknown state\n"); - } -} - -//----------------------------------------------------------------------------- -// Print the content of a buffer in hexadecimal -void nasmt_TOOL_print_buffer(unsigned char * buffer,int length) -{ - //----------------------------------------------------------------------------- - int i; - - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasmt_TOOL_print_buffer - begin \n"); -#endif - - if (buffer==NULL) { - printk("nasmt_TOOL_print_buffer - input parameter buffer is NULL \n"); - return; - } - - // End debug information - printk("\nBuffer content: "); - - for (i=0; irab_id, rb->sapi, rb->qos, rb->dscp); - printk("state %d, retry %d, countimer %d\n",rb->state, rb->retry, rb->countimer); -}; - -//----------------------------------------------------------------------------- -void nasmt_TOOL_print_classifier(struct classifier_entity *gc) -{ - //----------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasmt_TOOL_print_classifier - begin \n"); -#endif - - if (gc==NULL) { - printk("nasmt_TOOL_print_classifier - input parameter gc is NULL \n"); - return; - } - - // End debug information - printk("\nClassifier content: classref %d, version %d, splen %d, dplen %d,\n", gc->classref, gc->version, gc->splen, gc->dplen); - printk("protocol %d, sport %d, dport %d, rab_id %d\n", gc->protocol, gc->sport, gc->dport, gc->rab_id); - nasmt_TOOL_print_rb_entity(gc->rb); -}; - - diff --git a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_variables.h b/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_variables.h deleted file mode 100644 index c5754e948e..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASMT/nasmt_variables.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasmt_variables.h -* \brief Variable and structure definitions for OpenAirInterface CELLULAR version - MT -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#ifndef _NASMTD_VAR_H -#define _NASMTD_VAR_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include - -#include "rrc_nas_primitives.h" -#include "rrc_qos_classes.h" -#include "rrc_nas_sap.h" - -#include "nasmt_constant.h" -#include "nasmt_sap.h" - -struct cx_entity; - -struct rb_entity { - uint32_t cnxid; - nasRadioBearerId_t rab_id; //ue_rbId - nasSapId_t sapi; - nasQoSTrafficClass_t qos; - nasQoSTrafficClass_t RadioQosClass; - nasIPdscp_t dscp; - uint8_t state; - uint8_t result; - uint8_t retry; - uint32_t countimer; - struct rb_entity *next; -}; - -struct classifier_entity { - uint32_t classref; // classifier identity - uint8_t version; // IP version 4 or 6 - union { - struct in6_addr ipv6; - uint32_t ipv4; - } saddr; // IP source address - uint8_t splen; // IP prefix size - union { - struct in6_addr ipv6; - uint32_t ipv4; - } daddr; // IP destination address - uint8_t dplen; // IP prefix size - uint8_t protocol; // layer 4 protocol type (tcp, udp, ...) - uint16_t sport; // source port - uint16_t dport; // destination port - struct rb_entity *rb; - nasRadioBearerId_t rab_id; // RAB identification - void (*fct)(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc); - struct classifier_entity *next; -}; - - -struct cx_entity { - int sap[NAS_SAPI_CX_MAX]; - uint8_t state; // state of the connection - nasLocalConnectionRef_t lcr; // Local connection reference - nasCellID_t cellid; // cell identification - uint32_t countimer; // timeout's counter - uint8_t retry; // number of retransmissions - struct classifier_entity *sclassifier[NAS_DSCP_MAX]; // send classifiers table - uint16_t nsclassifier; - uint32_t iid6[2]; // IPv6 interface identification - uint8_t iid4; // IPv4 interface identification - struct rb_entity *rb; - uint16_t num_rb; - //measures - int req_prov_id[MAX_MEASURE_NB]; - int num_measures; - int meas_cell_id[MAX_MEASURE_NB]; - int meas_level[MAX_MEASURE_NB]; - int provider_id[MAX_MEASURE_NB]; - //MBMS - int joined_services[NASMT_MBMS_SVCES_MAX]; - -}; - -struct nas_priv { - int irq; - int rx_flags; - struct timer_list timer; - spinlock_t lock; - struct net_device_stats stats; - uint8_t retry_limit; - uint32_t timer_establishment; - uint32_t timer_release; - struct cx_entity cx[NAS_CX_MAX]; - struct classifier_entity *rclassifier[NAS_DSCP_MAX]; // receive classifier - uint16_t nrclassifier; - uint32_t next_sclassref; - int sap[NAS_SAPI_MAX]; - uint8_t xbuffer[NAS_MAX_LENGTH]; // transmission buffer - uint8_t rbuffer[NAS_MAX_LENGTH]; // reception buffer -}; - -struct ipversion { -#if defined(__LITTLE_ENDIAN_BITFIELD) - uint8_t reserved:4, - version:4; -#else - uint8_t version:4, - reserved:4; -#endif -}; - -typedef struct pdcp_data_req_header_t { - unsigned int rb_id; - unsigned int data_size; - int inst; -} pdcp_data_req_header_t; - -typedef struct pdcp_data_ind_header_t { - unsigned int rb_id; - unsigned int data_size; - int inst; -} pdcp_data_ind_header_t; -// - -extern struct nas_priv *gpriv; -extern struct net_device *gdev; -//extern int bytes_wrote; -//extern int bytes_read; - -extern uint8_t NAS_NULL_IMEI[14]; -extern uint8_t NAS_RG_IMEI[14]; - -//global variables shared with RRC -extern int *pt_nas_ue_irq; -//extern uint8_t nas_IMEI[14]; -#endif diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/Makefile b/openair2/NAS/DRIVER/CELLULAR/NASRG/Makefile deleted file mode 100755 index 758fa0420b..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/Makefile +++ /dev/null @@ -1,79 +0,0 @@ -# NAS CELLULAR Driver makefile -# -include $(OPENAIR_DIR)/common/utils/Makefile.inc - -NAS_UPDIR := $(shell /bin/pwd) - -#################################################### -# D E B U G F L A G S -#################################################### - -#################################################### -# EXTRA COMPILER FLAGS -#################################################### -EXTRA_CFLAGS = -fno-common -fno-stack-protector -mpreferred-stack-boundary=4 $(if $(SET_X64),-DARCH_64,) $(if $(SET_X64),-mcmodel=kernel,) $(if $(SET_X64),-m64,) - -ifdef ADDRCONF -EXTRA_CFLAGS += -DADDRCONF -endif - -ifdef NAS_DRIVER_TYPE_ETHERNET -EXTRA_CFLAGS += -DNAS_DRIVER_TYPE_ETHERNET -endif - - -ifdef PDCP_USE_NETLINK -EXTRA_CFLAGS += -DPDCP_USE_NETLINK -else -EXTRA_CFLAGS += $(shell rtai-config --module-cflags) -DRTAI -D__IN_RTAI__ -Wall -endif - -ifdef LOOPBACK -EXTRA_CFLAGS += -DLOOPBACK_TEST -endif - -ifdef ADDRESS_FIX -EXTRA_CFLAGS += -DNAS_ADDRESS_FIX -endif - -#################################################### -# NASRGCELL extra compilation flags -#################################################### -#RTAI=1 -RRC_DIR := $(OPENAIR2_DIR)/RRC/CELLULAR -EXTRA_CFLAGS += -I$(RRC_DIR) -DNODE_RG - -#################################################### -# LOADABLE MODULE GOALS -#################################################### -obj-m += nascellrg.o -nascellrg-objs += nasrg_device.o -nascellrg-objs += nasrg_common.o -nascellrg-objs += nasrg_iocontrol.o -nascellrg-objs += nasrg_classifier.o -nascellrg-objs += nasrg_tool.o -nascellrg-objs += nasrg_ascontrol.o -ifdef PDCP_USE_NETLINK -nascellrg-objs += nasrg_netlink.o -endif - -#################################################### -# REVOIR LE CLEAN -#################################################### - -#netlink.ko: - #make $(x)$(y) PDCP_USE_NETLINK=1 V=1 -C $(KERNEL_DIR) M=`pwd` modules - -#nasmesh.ko: -# make V=1 -C $(KERNEL_DIR) M=`pwd` modules -print: - @echo RRC_DIR $(RRC_DIR) -clean: - rm -f *.ko - rm -f .*.ko.cmd - rm -f .*.o.cmd - rm -f *.o - rm -f *.mod.c - find . -name *.ko -delete - find . -name *.o -delete - find . -name *.mod.c -delete diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_ascontrol.c b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_ascontrol.c deleted file mode 100644 index 4a6ef0e275..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_ascontrol.c +++ /dev/null @@ -1,1494 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasrg_ascontrol.c -* \brief Access Stratum Control functions for OpenAirInterface CELLULAR version - RG -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#ifdef NODE_RG -#include "nasrg_variables.h" -#include "nasrg_proto.h" - -//--------------------------------------------------------------------------- -void nasrg_ASCTL_init(void) -{ - //--------------------------------------------------------------------------- - int cxi, i; - - gpriv->next_sclassref = NASRG_DEFAULTRAB_CLASSREF; - - // Initialize MBMS services list in MT - for (cxi=0; cxicx[cxi].requested_joined_services[i]= -1; - gpriv->cx[cxi].requested_left_services[i]= -1; - gpriv->cx[cxi].joined_services[i]= -1; - } - } - - printk("nasrg_ASCTL_init Complete\n"); -} - -//--------------------------------------------------------------------------- -int nasrg_ASCTL_write(int sap, unsigned char *data_buffer, unsigned int data_length) -{ - //--------------------------------------------------------------------------- - int bytes_wrote = 0; -#ifdef PDCP_USE_NETLINK - unsigned char xmit_buffer [NAS_MESSAGE_MAXLEN]; - - //write SAP_Id - switch (sap) { - case RRC_DEVICE_GC: - xmit_buffer[0] = RRC_NAS_GC_IN; - break; - - case RRC_DEVICE_NT: - xmit_buffer[0] = RRC_NAS_NT_IN; - break; - - case RRC_DEVICE_DC_INPUT0: - xmit_buffer[0] = RRC_NAS_DC0_IN; - break; - - case RRC_DEVICE_DC_INPUT1: - xmit_buffer[0] = RRC_NAS_DC1_IN; - //case RRC_DEVICE_DC_INPUT2: - //xmit_buffer[0] = RRC_NAS_DC2_IN; - break; - - default: - printk("nasrg_ASCTL_write - ERROR - Invalid SAP %d\n", sap); - return 0; - break; - } - - memcpy (&((char*)xmit_buffer)[1], data_buffer, data_length); -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_write - Sending data to RRC, sap %d, length %d (including NETLINK SAP value)\n", sap, data_length+1); - nasrg_TOOL_print_buffer(xmit_buffer,data_length+1); -#endif - bytes_wrote = nasrg_netlink_send(xmit_buffer,data_length+1, NASNL_DEST_RRC); -#else - //bytes_wrote = rtf_put(cx->sap[NAS_DC_INPUT_SAPI], p, p->length); //original version - bytes_wrote = rtf_put(sap, data_buffer, data_length+1); -#endif //PDCP_USE_NETLINK - return bytes_wrote-1; -} - -//--------------------------------------------------------------------------- -//For demo, add automatically a radio bearer -//Equivalent to rb add send 0 5 2 -void nasrg_ASCTL_start_default_rb(struct cx_entity *cx) -{ - //--------------------------------------------------------------------------- -#ifdef DEMO_3GSM - struct rb_entity *rb; - int status; - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_start_default_rb - begin \n"); -#endif - - if (!cx) { - printk("nasrg_ASCTL_start_default_rb - input parameter cx is NULL \n"); - return; - } - - // End debug information - - rb = nasrg_COMMON_add_rb(cx, NASRG_DEFAULTRAB_RBID, NASRG_DEFAULTRAB_QoS); - - if (rb!=NULL) { - rb->cnxid = (NAS_RB_MAX_NUM * cx->lcr)+1; - //rb->default_rab =1; - rb->dscp = NASRG_DEFAULTRAB_DSCP; - rb->dscp_ul = NASRG_DEFAULTRAB_DSCP; - status=nasrg_ASCTL_DC_send_rb_establish_request(cx, rb); - } else - status=-NAS_ERROR_NOMEMORY; - -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_start_default_rb - end %d \n",status); -#endif -} -#endif - -//--------------------------------------------------------------------------- -//For demo, add automatically a classifier -//Equivalent to class add send 0 -f qos -cr 0 -void nasrg_ASCTL_start_default_sclassifier(struct cx_entity *cx,struct rb_entity *rb) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *gc; - - // Start debug information -#ifdef NAS_DEBUG_CLASS - printk("nasrg_ASCTL_start_default_sclassifier - begin \n"); -#endif - - if (!cx || !rb) { - printk("nasrg_ASCTL_start_default_sclassifier - input parameter is NULL \n"); - return; - } - - // End debug information - gc=nasrg_CLASS_add_sclassifier(cx, NAS_DSCP_DEFAULT, gpriv->next_sclassref); - - if (gc==NULL) { - printk("nasrg_ASCTL_start_default_sclassifier - Classifier pointer is null : not added \n"); - return; - } - - gc->fct = nasrg_COMMON_QOS_send; - gc->rab_id =rb->rab_id; - gc->rb= rb; - gc->version = NASRG_DEFAULTRAB_IPVERSION; - gc->protocol= NAS_PROTOCOL_DEFAULT; - gc->dplen= NAS_DEFAULT_IPv6_PREFIX_LENGTH; - // copy locator part of address into the gc structure - //gc->daddr.ipv6.s6_addr32[0] = 0; - //gc->daddr.ipv6.s6_addr32[1] = 0; - //gc->daddr.ipv6.s6_addr32[2] = 0; - //gc->daddr.ipv6.s6_addr32[3] = 0; - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_ASCTL_start_default_sclassifier - end \n"); - nasrg_TOOL_print_classifier(gc); -#endif -} - -//--------------------------------------------------------------------------- -//Add automatically a classifier on DSCP -//Equivalent to class add send 0 -f qos -cr 0 -void nasrg_ASCTL_start_sclassifier(struct cx_entity *cx,struct rb_entity *rb) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *gc; - - // Start debug information -#ifdef NAS_DEBUG_CLASS - printk("nasrg_ASCTL_start_sclassifier - begin \n"); -#endif - - if (!cx || !rb) { - printk("nasrg_ASCTL_start_sclassifier - input parameter is NULL \n"); - return; - } - - // End debug information - gc=nasrg_CLASS_add_sclassifier(cx, rb->dscp, gpriv->next_sclassref); - - if (gc==NULL) { - printk("nasrg_ASCTL_start_sclassifier - Classifier pointer is null : not added \n"); - return; - } - - gc->fct = nasrg_COMMON_QOS_send; - gc->rab_id =rb->rab_id; - gc->rb= rb; - gc->version = NASRG_DEFAULTRAB_IPVERSION; - gc->protocol= NAS_PROTOCOL_DEFAULT; - gc->dplen= NAS_DEFAULT_IPv6_PREFIX_LENGTH; - // copy locator part of address into the gc structure - gc->daddr.ipv6.s6_addr32[2] = cx->iid6[0]; - gc->daddr.ipv6.s6_addr32[3] = cx->iid6[1]; - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_ASCTL_start_sclassifier - end \n"); - nasrg_TOOL_print_classifier(gc); -#endif -} - -//--------------------------------------------------------------------------- -//Add automatically a classifier for mbms -void nasrg_ASCTL_start_mbmsclassifier(int mbms_ix,struct rb_entity *mbms_rb) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *gc; - - // Start debug information -#ifdef NAS_DEBUG_CLASS - printk("nasrg_ASCTL_start_mbmsclassifier - begin \n"); -#endif - - if (!mbms_rb) { - printk("nasrg_ASCTL_start_mbmsclassifier - input parameter is NULL \n"); - return; - } - - // End debug information - // - // gc=nasrg_CLASS_add_mbmsclassifier(mbms_ix, gpriv->next_mbmsclassref); - gc=nasrg_CLASS_add_mbmsclassifier(mbms_ix, gpriv->next_sclassref++); - - if (gc==NULL) { - printk("nasrg_ASCTL_start_mbmsclassifier - Classifier pointer is null : not added \n"); - return; - } - - gc->fct = nasrg_COMMON_QOS_send; - gc->rab_id =mbms_rb->mbms_rbId; - gc->rb= mbms_rb; - gc->version = NASRG_DEFAULTRAB_IPVERSION; - gc->protocol= NAS_PROTOCOL_DEFAULT; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_ASCTL_start_mbmsclassifier - end \n"); - nasrg_TOOL_print_classifier(gc); -#endif -} - -//--------------------------------------------------------------------------- -//Notifies automatically UE on default MBMS service -void nasrg_ASCTL_start_default_ue_notification(struct cx_entity *cx) -{ - //--------------------------------------------------------------------------- -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_start_default_ue_notification - begin \n"); -#endif - - if (!cx) { - printk("\nERROR nasrg_ASCTL_start_default_ue_notification - input parameter is NULL \n"); - return; - } - - // End debug information - // set value for default MBMS service - cx->requested_joined_services[0] = (NAS_CX_MAX*NAS_RB_MAX_NUM) +1; - nasrg_ASCTL_DC_send_mbms_ue_notify_req(cx); -} - -//--------------------------------------------------------------------------- -//Notifies automatically UE on default MBMS service -void nasrg_ASCTL_start_default_mbms_service(void) -{ - //--------------------------------------------------------------------------- - int mbms_ix=0; // should allocate index based on Service_id /cnxid / MC IP address -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_start_default_mbms_service - begin \n"); -#endif - - // Establish MBMS bearer if not already done - if ((gpriv->mbms_rb[mbms_ix].state != NAS_CX_DCH)&&(gpriv->mbms_rb[mbms_ix].state != NAS_RB_ESTABLISHING)) { - gpriv->mbms_rb[mbms_ix].cnxid = (NAS_CX_MAX*NAS_RB_MAX_NUM) +1; - gpriv->mbms_rb[mbms_ix].serviceId = (NAS_CX_MAX*NAS_RB_MAX_NUM) +1; - gpriv->mbms_rb[mbms_ix].sessionId = NASRG_TEMP_MBMS_SESSION_ID; //Temp hard coded - gpriv->mbms_rb[mbms_ix].mbms_rbId = NASRG_DEFAULTRAB_RBID; - gpriv->mbms_rb[mbms_ix].sapi = NAS_DC_INPUT_SAPI; -#ifdef NAS_DEBUG_MBMS_PROT - gpriv->mbms_rb[mbms_ix].sapi = NAS_DRB_INPUT_SAPI; //Only one RT-FIFO is used -#endif - gpriv->mbms_rb[mbms_ix].qos = 20; //from first version of MBMS traces - gpriv->mbms_rb[mbms_ix].dscp = 0; //maybe 7 - gpriv->mbms_rb[mbms_ix].duration = NASRG_TEMP_MBMS_DURATION; //Temp hard coded - //memcpy ((char *)&(gpriv->mbms_rb[mbms_ix].mcast_address),(char *)&(msgreq->mcast_group), 16); - gpriv->mbms_rb[mbms_ix].mcast_address[0] = 0xFF; - gpriv->mbms_rb[mbms_ix].mcast_address[1] = 0x0E; - nasrg_ASCTL_GC_send_mbms_bearer_establish_req(mbms_ix); - } else { -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_start_default_mbms_service - skipped, mbms_rb.state = %d \n", gpriv->mbms_rb[mbms_ix].state); -#endif - } -} -//--------------------------------------------------------------------------- -void nasrg_ASCTL_timer(unsigned long data) -{ - //--------------------------------------------------------------------------- - uint8_t cxi; - struct cx_entity *cx; - struct rb_entity *rb; - spin_lock(&gpriv->lock); -#ifdef NAS_DEBUG_TIMER - printk("nasrg_ASCTL_timer - begin \n"); -#endif - (gpriv->timer).function = nasrg_ASCTL_timer; - (gpriv->timer).expires=jiffies+NAS_TIMER_TICK; - (gpriv->timer).data=0L; - - for (cxi=0; cxicx+cxi; - - if (!cx) { - printk("nasrg_ASCTL_timer - No pointer for connection %d \n", cxi); - continue; - } - - for (rb=cx->rb; rb!=NULL; rb=rb->next) { - if (rb->countimer!=NAS_TIMER_IDLE) { -#ifdef NAS_DEBUG_TIMER - printk("nasrg_ASCTL_timer : rb countimer %d, rb state %d\n", rb->countimer, rb->state); -#endif - - if (rb->countimer==0) { - switch (rb->state) { - case NAS_CX_CONNECTING: - case NAS_CX_CONNECTING_FAILURE: // MW - 15/01/07 Useless, currently no retry if failure - if (rb->retryretry_limit) { - printk("nasrg_ASCTL_timer: Retry RB establishment %d\n", rb->retry); - nasrg_ASCTL_DC_send_rb_establish_request(cx, rb); - } else { - printk("nasrg_ASCTL_timer: RB Establishment failure\n"); - rb->state=NAS_IDLE; - rb->countimer=NAS_TIMER_IDLE; - } - - break; - - case NAS_CX_DCH: -#ifdef DEMO_3GSM - if (cx->num_rb == 1) { - nasrg_ASCTL_start_default_sclassifier(cx, rb); - } - -#endif - nasrg_ASCTL_start_sclassifier(cx, rb); - rb->countimer=NAS_TIMER_IDLE; - break; - - case NAS_CX_RELEASING_FAILURE: - nasrg_ASCTL_DC_send_rb_release_request(cx, rb); - break; - - default: - rb->countimer=NAS_TIMER_IDLE; - } - } else { - --rb->countimer; - printk("nasrg_ASCTL_timer : rb countimer-- %d, rb state %d\n", rb->countimer, rb->state); - } - } - } - } - - add_timer(&gpriv->timer); -#ifdef NAS_DEBUG_TIMER - printk("nasrg_ASCTL_timer - end \n"); -#endif - spin_unlock(&gpriv->lock); -} - - -/*************************************************************************** - Transmission side - ***************************************************************************/ -//--------------------------------------------------------------------------- -// Encode INFO_BROADCAST_REQ message -int nasrg_ASCTL_GC_send_broadcast_request(uint8_t category) -{ - //--------------------------------------------------------------------------- - char *xmit_data = "TESTING BROADCASTING ROUTER ADVERTISEMENT. TESTING BROADCASTING ROUTER ADVERTISEMENT. BROADCASTING ROUTER.\0"; - int bytes_wrote = 0; -#ifdef PDCP_USE_NETLINK - unsigned char xbuffer[NAS_MESSAGE_MAXLEN]; - int count=0; -#endif - - struct nas_rg_gc_element *p; - p= (struct nas_rg_gc_element *)(gpriv->xbuffer); - p->type = INFO_BROADCAST_REQ; - p->length = NAS_TL_SIZE + sizeof(struct NASInfoBroadcastReq); - // - p->nasRGGCPrimitive.broadcast_req.period = 0; - p->nasRGGCPrimitive.broadcast_req.category = category; - p->nasRGGCPrimitive.broadcast_req.nasDataLength = strlen(xmit_data)+1; // TBD - - //bytes_wrote = rtf_put(gpriv->sap[NAS_GC_SAPI], p, p->length); //original version -#ifdef PDCP_USE_NETLINK - memcpy(xbuffer,(unsigned char *)p, p->length); - count = p->length; - bytes_wrote = count; -#else - bytes_wrote = nasrg_ASCTL_write(gpriv->sap[NAS_GC_SAPI], (unsigned char *)p, p->length); -#endif - //printk("nasrg_ASCTL_GC_send_broadcast_request - Wrote %d bytes to RRC NAS_GC_SAPII\n", bytes_wrote); - - //bytes_wrote += rtf_put(gpriv->sap[NAS_GC_SAPI], xmit_data, p->nasRGGCPrimitive.broadcast_req.nasDataLength); -#ifdef PDCP_USE_NETLINK - memcpy(&(xbuffer[count]),(unsigned char *)xmit_data, p->nasRGGCPrimitive.broadcast_req.nasDataLength); - count += p->nasRGGCPrimitive.broadcast_req.nasDataLength; - bytes_wrote += nasrg_ASCTL_write(gpriv->sap[NAS_GC_SAPI], xbuffer, count); -#else - bytes_wrote += nasrg_ASCTL_write((gpriv->sap[NAS_GC_SAPI], xmit_data, p->nasRGGCPrimitive.broadcast_req.nasDataLength); -#endif - - if (bytes_wrote==p->length+p->nasRGGCPrimitive.broadcast_req.nasDataLength) { -#ifdef NAS_DEBUG_GC - printk("nasrg_ASCTL_GC_send_broadcast: INFO_BROADCAST_REQ primitive sent successfully in GC-FIFO\n"); -#endif - } else { - printk("nasrg_ASCTL_GC_send_broadcast: Message sent failure in GC-FIFO\n"); - } - return bytes_wrote; -} - - -//--------------------------------------------------------------------------- -// Encode INFO_BROADCAST_REQ message for RRC SIB1 -int nasrg_ASCTL_GC_send_SIB1_broadcast_request(struct sk_buff *skb) -{ - //--------------------------------------------------------------------------- - struct nas_rg_gc_element *p; - char sib1_flag; // will be used for reception in nas_ue - int bytes_wrote = 0; -#ifdef PDCP_USE_NETLINK - unsigned char xbuffer[NAS_MESSAGE_MAXLEN]; - int count=0; -#endif - - // Start debug information -#ifdef NAS_DEBUG_GC - printk("nasrg_ASCTL_GC_send_SIB1_broadcast_request - begin \n"); -#endif - - if (!skb) { - printk("nasrg_ASCTL_GC_send_SIB1_broadcast_request - input parameter is NULL \n"); - return 0; - } - - // End debug information - p= (struct nas_rg_gc_element *)(gpriv->xbuffer); - p->type = INFO_BROADCAST_REQ; - p->length = NAS_TL_SIZE + sizeof(struct NASInfoBroadcastReq); - // - p->nasRGGCPrimitive.broadcast_req.period = 10; // to be checked - p->nasRGGCPrimitive.broadcast_req.category = 1; - p->nasRGGCPrimitive.broadcast_req.nasDataLength = skb->len+1; // TBD - sib1_flag = 1; - // send header - //bytes_wrote = rtf_put(gpriv->sap[NAS_GC_SAPI], p, p->length); //original version -#ifdef PDCP_USE_NETLINK - memcpy(xbuffer,(unsigned char *)p, p->length); - count = p->length; - bytes_wrote = count; -#else - bytes_wrote = nasrg_ASCTL_write(gpriv->sap[NAS_GC_SAPI], (unsigned char *)p, p->length); -#endif - //printk("nasrg_ASCTL_GC_send_broadcast_request - Wrote %d bytes to RRC NAS_GC_SAPII\n", bytes_wrote); - - - if (bytes_wrote!=p->length) { - printk("nasrg_ASCTL_GC_send_SIB1_broadcast_request: Header send failure in GC-FIFO\n"); - return bytes_wrote; - } - - // send sib1_flag - //bytes_wrote += rtf_put(gpriv->sap[NAS_GC_SAPI], &sib1_flag, 1); -#ifdef PDCP_USE_NETLINK - memcpy(&(xbuffer[count]),(unsigned char *)&sib1_flag, 1); - count += 1; - bytes_wrote = count; -#else - bytes_wrote += nasrg_ASCTL_write(gpriv->sap[NAS_GC_SAPI], (unsigned char *)&sib1_flag, 1); -#endif - - if (bytes_wrote!=p->length+1) { - printk("nasrg_ASCTL_GC_send_SIB1_broadcast_request: sib1_flag send failure in GC-FIFO\n"); - return bytes_wrote; - } - - // send data - //bytes_wrote += rtf_put(gpriv->sap[NAS_GC_SAPI], skb->data, skb->len); -#ifdef PDCP_USE_NETLINK - memcpy(&(xbuffer[count]),skb->data, skb->len); - count += skb->len; - bytes_wrote = nasrg_ASCTL_write(gpriv->sap[NAS_GC_SAPI], xbuffer, count); -#else - bytes_wrote += nasrg_ASCTL_write(gpriv->sap[NAS_GC_SAPI], skb->data, skb->len); -#endif - - - if (bytes_wrote!=p->length+skb->len+1) { - printk("nasrg_ASCTL_GC_send_SIB1_broadcast_request: Data send failure in GC-FIFO\n"); - return bytes_wrote; - } - -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_GC_send_SIB1_broadcast_request - end \n"); -#endif - return bytes_wrote; -} - -//----------------------------------------------------------------------------- -// Encode MBMS_BEARER_ESTABLISH_REQ message -int nasrg_ASCTL_GC_send_mbms_bearer_establish_req(int mbms_ix ) -{ - //----------------------------------------------------------------------------- - struct nas_rg_gc_element *p; - int bytes_wrote = 0; - - p= (struct nas_rg_gc_element *)(gpriv->xbuffer); - p->type = MBMS_BEARER_ESTABLISH_REQ; - p->length = NAS_TL_SIZE + sizeof(struct NASMBMSBearerEstablishReq); - // - p->nasRGGCPrimitive.mbms_establish_req.mbms_serviceId = gpriv->mbms_rb[mbms_ix].serviceId; - p->nasRGGCPrimitive.mbms_establish_req.mbms_sessionId = gpriv->mbms_rb[mbms_ix].sessionId; - p->nasRGGCPrimitive.mbms_establish_req.mbms_rbId = gpriv->mbms_rb[mbms_ix].mbms_rbId; - p->nasRGGCPrimitive.mbms_establish_req.mbms_sapId = gpriv->mbms_rb[mbms_ix].sapi; - p->nasRGGCPrimitive.mbms_establish_req.mbms_QoSclass = gpriv->mbms_rb[mbms_ix].qos; - p->nasRGGCPrimitive.mbms_establish_req.mbms_duration = gpriv->mbms_rb[mbms_ix].duration; - gpriv->mbms_rb[mbms_ix].state = NAS_RB_ESTABLISHING; - // - //bytes_wrote = rtf_put(gpriv->sap[NAS_GC_SAPI], p, p->length); - bytes_wrote = nasrg_ASCTL_write(gpriv->sap[NAS_GC_SAPI], (unsigned char *)p, p->length); - - if (bytes_wrote==p->length) { -#ifdef NAS_DEBUG_GC - printk(" nasrg_ASCTL_GC_send_mbms_bearer_establish: MBMS_BEARER_ESTABLISH_REQ primitive sent successfully in GC-FIFO\n"); - printk(" ServiceId %d, RB_Id %d , qos class %d \n", - p->nasRGGCPrimitive.mbms_establish_req.mbms_serviceId, - p->nasRGGCPrimitive.mbms_establish_req.mbms_rbId, - p->nasRGGCPrimitive.mbms_establish_req.mbms_QoSclass); -#endif - } else { - printk("nasrg_ASCTL_GC_send_mbms_bearer_establish: Message sent failure in GC-FIFO\n"); - } - - return bytes_wrote; -} - -//----------------------------------------------------------------------------- -// HNN - Encode MBMS_BEARER_RELEASE_REQ message -int nasrg_ASCTL_GC_send_mbms_bearer_release_req(int mbms_ix) -{ - //----------------------------------------------------------------------------- - struct nas_rg_gc_element *p; - uint16_t classref=0; - int bytes_wrote = 0; - - p= (struct nas_rg_gc_element *)(gpriv->xbuffer); - - p->type = MBMS_BEARER_RELEASE_REQ; - p->length = NAS_TL_SIZE + sizeof(struct NASMBMSBearerReleaseReq); - // - p->nasRGGCPrimitive.mbms_release_req.mbms_serviceId = gpriv->mbms_rb[mbms_ix].serviceId; - p->nasRGGCPrimitive.mbms_release_req.mbms_sessionId = gpriv->mbms_rb[mbms_ix].sessionId; - p->nasRGGCPrimitive.mbms_release_req.mbms_rbId = gpriv->mbms_rb[mbms_ix].mbms_rbId; - //gpriv->mbms_rb[mbms_ix].state = NAS_RB_RELEASING; - // - //bytes_wrote = rtf_put(gpriv->sap[NAS_GC_SAPI], p, p->length); - bytes_wrote = nasrg_ASCTL_write(gpriv->sap[NAS_GC_SAPI], (unsigned char *)p, p->length); - - if (bytes_wrote==p->length) { -#ifdef NAS_DEBUG_GC - printk(" nasrg_ASCTL_GC_send_mbms_bearer_release: MBMS_BEARER_RELEASE_REQ primitive sent successfully in GC-FIFO\n"); - printk(" ServiceId %d, RB_Id %d \n", p->nasRGGCPrimitive.mbms_establish_req.mbms_serviceId, p->nasRGGCPrimitive.mbms_establish_req.mbms_rbId); -#endif - // clean NASRG private structures - classref = (gpriv->mbmsclassifier[mbms_ix])->classref; - nasrg_CLASS_del_mbmsclassifier(mbms_ix, classref); - //nasrg_CLASS_flush_mbmsclassifier(); - //gpriv->mbms_rb[mbms_ix].state = NAS_IDLE; - memset (&(gpriv->mbms_rb[mbms_ix]),0,sizeof (struct rb_entity)); - } else { - printk("nasrg_ASCTL_GC_send_mbms_bearer_release: Message sent failure in GC-FIFO\n"); - } - - return bytes_wrote; -} - -//--------------------------------------------------------------------------- -// Confirm the establishment of a connection (DC channel) -int nasrg_ASCTL_DC_send_cx_establish_confirm(struct cx_entity *cx, uint8_t response) -{ - //--------------------------------------------------------------------------- - struct nas_rg_dc_element *p; - int bytes_wrote = 0; - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_send_cx_establish - begin \n"); -#endif - - if (!cx) { - printk("nasrg_ASCTL_DC_send_cx_establish - input parameter cx is NULL \n"); - return NAS_ERROR_NOTCORRECTVALUE; - } - - // End debug information - p= (struct nas_rg_dc_element *)(gpriv->xbuffer); - p->type = CONN_ESTABLISH_CNF; - p->length = NAS_TL_SIZE + sizeof(struct NASConnEstablishConf); - p->nasRGDCPrimitive.conn_establish_conf.localConnectionRef = cx->lcr; - p->nasRGDCPrimitive.conn_establish_conf.status = response; // can be ACCEPTED or FAILURE - p->nasRGDCPrimitive.conn_establish_conf.num_RBs = 0; // Hard coded in first step - // - //bytes_wrote = rtf_put(cx->sap[NAS_DC_INPUT_SAPI], p, p->length); - bytes_wrote = nasrg_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (unsigned char *)p, p->length); - - if (bytes_wrote==p->length) { -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_send_cx_establish: CONN_ESTABLISH_CNF primitive sent successfully in DC-FIFO\n"); - printk(" lcr (Mobile_id) %u\n",p->nasRGDCPrimitive.conn_establish_conf.localConnectionRef); - printk(" Status %u\n",p->nasRGDCPrimitive.conn_establish_conf.status); -#endif - } else - printk("nasrg_ASCTL_DC_send_cx_establish: Message transmission failure to DC-FIFO\n"); - - return bytes_wrote; -} - -//--------------------------------------------------------------------------- -// Request the establishment of a radio bearer -int nasrg_ASCTL_DC_send_rb_establish_request(struct cx_entity *cx, struct rb_entity *rb) -{ - //--------------------------------------------------------------------------- - struct nas_rg_dc_element *p; - int bytes_wrote = 0; - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_send_rb_establish - begin \n"); -#endif - - if (!cx || !rb) { - printk("nasrg_ASCTL_DC_send_rb_establish - input parameter is NULL \n"); - return NAS_ERROR_NOTCORRECTVALUE; - } - - // End debug information - switch(rb->state) { - case NAS_CX_CONNECTING: - case NAS_CX_CONNECTING_FAILURE: - case NAS_IDLE: - ++rb->retry; - rb->countimer=gpriv->timer_establishment; - - if (cx->state==NAS_CX_DCH) { - p= (struct nas_rg_dc_element *)(gpriv->xbuffer); - p->type = RB_ESTABLISH_REQ; - p->length = NAS_TL_SIZE + sizeof(struct NASrbEstablishReq); - p->nasRGDCPrimitive.rb_establish_req.localConnectionRef = cx->lcr; - p->nasRGDCPrimitive.rb_establish_req.rbId = rb->rab_id + (NAS_RB_MAX_NUM * cx->lcr); - p->nasRGDCPrimitive.rb_establish_req.QoSclass = rb->qos; - p->nasRGDCPrimitive.rb_establish_req.dscp = rb->dscp_ul; - // - //bytes_wrote = rtf_put(cx->sap[NAS_DC_INPUT_SAPI], p, p->length); - bytes_wrote = nasrg_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (unsigned char *)p, p->length); - - if (bytes_wrote==p->length) { - rb->state=NAS_CX_CONNECTING; -#ifdef NAS_DEBUG_DC - printk(" nasrg_ASCTL_DC_send_rb_establish: RB_ESTABLISH_REQ primitive sent successfully in DC-FIFO\n"); - printk(" lcr (Mobile_id) %u\n",p->nasRGDCPrimitive.rb_establish_req.localConnectionRef); - printk(" Radio Bearer identification %u\n",p->nasRGDCPrimitive.rb_establish_req.rbId); - printk(" QoS %u\n",p->nasRGDCPrimitive.rb_establish_req.QoSclass); -#endif - } else { - rb->state=NAS_CX_CONNECTING_FAILURE; - printk("nasrg_ASCTL_DC_send_rb_establish: Message sent failure in DC-FIFO\n"); - } - - return bytes_wrote; - } else { - rb->state=NAS_CX_CONNECTING_FAILURE; - printk("nasrg_ASCTL_DC_send_rb_establish: Failure \n"); - return 0; - } - - default: - return -NAS_ERROR_NOTIDLE; - } -} - -//--------------------------------------------------------------------------- -// Request the release of a radio bearer -int nasrg_ASCTL_DC_send_rb_release_request(struct cx_entity *cx, struct rb_entity *rb) -{ - //--------------------------------------------------------------------------- - struct nas_rg_dc_element *p; - int bytes_wrote = 0; - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_send_rb_release - begin \n"); -#endif - - if (!cx || !rb) { - printk("nasrg_ASCTL_DC_send_rb_release - input parameter is NULL \n"); - return NAS_ERROR_NOTCORRECTVALUE; - } - - // End debug information - switch (rb->state) { - case NAS_CX_RELEASING_FAILURE: - case NAS_CX_DCH: - p= (struct nas_rg_dc_element *)(gpriv->xbuffer); - p->type = RB_RELEASE_REQ; - p->length = NAS_TL_SIZE + sizeof(struct NASrbReleaseReq); - p->nasRGDCPrimitive.rb_release_req.localConnectionRef = cx->lcr; - p->nasRGDCPrimitive.rb_release_req.rbId = rb->rab_id + (NAS_RB_MAX_NUM * cx->lcr); - // - //bytes_wrote = rtf_put(cx->sap[NAS_DC_INPUT_SAPI], p, p->length); - bytes_wrote = nasrg_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (unsigned char *)p, p->length); - - if (bytes_wrote) { - rb->state=NAS_IDLE; -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_send_rb_release: RB_RELEASE_REQ primitive sent successfully in DC-FIFO\n"); -#endif - } else { - ++rb->retry; - rb->countimer=gpriv->timer_release; - rb->state=NAS_CX_RELEASING_FAILURE; - printk("nasrg_ASCTL_DC_send_rb_release: Message sent failure in DC-FIFO\n"); - } - - return bytes_wrote; - - default: - return -NAS_ERROR_NOTCONNECTED; - } -} - -//----------------------------------------------------------------------------- -// Request the notification of a UE to joined or left services -int nasrg_ASCTL_DC_send_mbms_ue_notify_req(struct cx_entity *cx) -{ - //----------------------------------------------------------------------------- - struct nas_rg_dc_element *p; - int i; - int bytes_wrote = 0; - -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_send_mbms_ue_notify_req - begin \n"); -#endif - - if (!cx) { - printk("nasrg_ASCTL_DC_send_mbms_ue_notify_req - input parameter is NULL \n"); - return NAS_ERROR_NOTCORRECTVALUE; - } - - // End debug information - p= (struct nas_rg_dc_element *)(gpriv->xbuffer); - p->type = MBMS_UE_NOTIFY_REQ; - p->length = NAS_TL_SIZE + sizeof(struct NASMBMSUENotifyReq); - // - p->nasRGDCPrimitive.mbms_ue_notify_req.localConnectionRef = cx->lcr; - - // joined/left services are lists of MAX_MBMS_SERVICES - // -1 means the end of the list - for (i = 0; i < MAX_MBMS_SERVICES; i++) { - p->nasRGDCPrimitive.mbms_ue_notify_req.joined_services[i].mbms_serviceId = (nasMBMSServiceId_t)cx->requested_joined_services[i]; - p->nasRGDCPrimitive.mbms_ue_notify_req.left_services[i].mbms_serviceId = (nasMBMSServiceId_t)cx->requested_left_services[i]; - } - - // - //bytes_wrote = rtf_put(cx->sap[NAS_DC_INPUT_SAPI], p, p->length); - bytes_wrote = nasrg_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (unsigned char *)p, p->length); - - if (bytes_wrote==p->length) { -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_send_mbms_ue_notify_req: MBMS_UE_NOTIFY_REQ primitive sent successfully in DC-FIFO\n"); - printk(" lcr (Mobile_id) %u\n",p->nasRGDCPrimitive.mbms_ue_notify_req.localConnectionRef); - printk(" joined service %d, left service %d\n",cx->requested_joined_services[0], cx->requested_left_services[0] ); -#endif - } else - printk("nasrg_ASCTL_DC_send_mbms_ue_notify_req: Message transmission failure to DC-FIFO\n"); - - return bytes_wrote; -} - -//--------------------------------------------------------------------------- -// Request the transfer of data (DC SAP) -void nasrg_ASCTL_DC_send_sig_data_request(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc) -{ - //--------------------------------------------------------------------------- - struct nas_rg_dc_element *p; - int bytes_wrote = 0; -#ifdef PDCP_USE_NETLINK - unsigned char xbuffer[NAS_MESSAGE_MAXLEN]; - int count=0; -#endif - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_send_sig_data - begin \n"); -#endif - - if (!skb || !gc || !cx) { - printk("nasrg_ASCTL_DC_send_sig_data - input parameter is NULL \n"); - return; - } - - // End debug information - if (cx->state!=NAS_CX_DCH) { - printk("nasrg_ASCTL_DC_send_sig_data: Not connected, so the message is dropped\n"); - ++gpriv->stats.tx_dropped; - return; - } - - p = (struct nas_rg_dc_element *)(gpriv->xbuffer); - p->type = DATA_TRANSFER_REQ; - p->length = NAS_TL_SIZE + sizeof(struct NASDataReq); - p->nasRGDCPrimitive.data_transfer_req.localConnectionRef = cx->lcr; - p->nasRGDCPrimitive.data_transfer_req.priority = NAS_SIG_SRB3; - p->nasRGDCPrimitive.data_transfer_req.nasDataLength = skb->len; - // - //bytes_wrote = rtf_put(cx->sap[NAS_DC_INPUT_SAPI], p, p->length); -#ifdef PDCP_USE_NETLINK - memcpy(xbuffer,(unsigned char *)p, p->length); - count = p->length; - bytes_wrote = count; -#else - bytes_wrote = nasrg_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (unsigned char *)p, p->length); -#endif - - if (bytes_wrote!=p->length) { - printk("nasrg_ASCTL_DC_send_sig_data: Header sent failure in DC-FIFO\n"); - return; - } - - //bytes_wrote += rtf_put(cx->sap[NAS_DC_INPUT_SAPI], skb->data, skb->len); -#ifdef PDCP_USE_NETLINK - memcpy(&(xbuffer[count]),(unsigned char *)skb->data, skb->len); - count += skb->len; - bytes_wrote = nasrg_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], xbuffer, count); -#else - bytes_wrote += nasrg_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (unsigned char *)skb->data, skb->len); -#endif - - if (bytes_wrote!=p->length+skb->len) { - printk("nasrg_ASCTL_DC_send_sig_data: Data sent failure in DC-FIFO\n"); - return; - } - - gpriv->stats.tx_bytes += skb->len; - gpriv->stats.tx_packets ++; -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_send_sig_data - end \n"); -#endif -} - -//--------------------------------------------------------------------------- -// Confirm the establishment of a connection (DC channel) -int nasrg_ASCTL_DC_send_eNBmeasurement_req(struct cx_entity *cx) -{ - //--------------------------------------------------------------------------- - struct nas_rg_dc_element *p; - int bytes_wrote = 0; - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_send_eNBmeasurement_req - begin \n"); -#endif - - if (!cx) { - printk("nasrg_ASCTL_DC_send_eNBmeasurement_req - input parameter cx is NULL \n"); - return NAS_ERROR_NOTCORRECTVALUE; - } - - // End debug information - p= (struct nas_rg_dc_element *)(gpriv->xbuffer); - p->type = ENB_MEASUREMENT_REQ; - p->length = NAS_TL_SIZE + sizeof(struct NASENbMeasureReq); - p->nasRGDCPrimitive.eNBmeasurement_req.cell_id = cx->cellid; - // - //bytes_wrote = rtf_put(cx->sap[NAS_DC_INPUT_SAPI], p, p->length); - bytes_wrote = nasrg_ASCTL_write(cx->sap[NAS_DC_INPUT_SAPI], (unsigned char *)p, p->length); - - if (bytes_wrote==p->length) { -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_send_eNBmeasurement_req: ENB_MEASUREMENT_REQ primitive sent successfully in DC-FIFO\n"); - printk(" cell_id %u\n",p->nasRGDCPrimitive.eNBmeasurement_req.cell_id); -#endif - } else - printk("nasrg_ASCTL_DC_send_eNBmeasurement_req: Message transmission failure to DC-FIFO\n"); - - return bytes_wrote; -} - -/*************************************************************************** - Reception side - ***************************************************************************/ - -//--------------------------------------------------------------------------- -// Decode CONN_ESTABLISH_IND message from RRC -void nasrg_ASCTL_DC_decode_cx_establish_ind(struct cx_entity *cx, struct nas_rg_dc_element *p) -{ - //--------------------------------------------------------------------------- - int i; - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_decode_cx_establish - begin \n"); -#endif - - if (!cx || !p) { - printk("nasrg_ASCTL_DC_decode_cx_establish - input parameter is NULL \n"); - return; - } - - // End debug information - if (nasrg_ASCTL_DC_send_cx_establish_confirm(cx, ACCEPTED)>0) { - nasrg_TOOL_imei2iid(p->nasRGDCPrimitive.conn_establish_ind.InterfaceIMEI, (uint8_t *)cx->iid6); - cx->iid4=97; // A AUTOMATISER - cx->lcr = p->nasRGDCPrimitive.conn_establish_ind.localConnectionRef; - cx->state=NAS_CX_DCH; -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_decode_cx_establish: CONN_ESTABLISH_IND reception\n"); - printk(" primitive length %d\n",p->length); - printk(" Local Connection reference %d\n",p->nasRGDCPrimitive.conn_establish_ind.localConnectionRef); - printk(" IMEI "); - - for (i=0; i<14; ++i) - printk("%u",p->nasRGDCPrimitive.conn_establish_ind.InterfaceIMEI[i]); - - printk(" state "); - nasrg_TOOL_print_state(cx->state); -#endif - } -} - -//--------------------------------------------------------------------------- -// Decode CONN_RELEASE_IND message from RRC -void nasrg_ASCTL_DC_decode_cx_release_ind(struct cx_entity *cx, struct nas_rg_dc_element *p) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_decode_cx_release - begin \n"); -#endif - - if (!cx || !p) { - printk("nasrg_ASCTL_DC_decode_cx_release - input parameter is NULL \n"); - return; - } - - // End debug information - cx->state=NAS_IDLE; - cx->iid4=0; - nasrg_TOOL_imei2iid(NAS_NULL_IMEI, (uint8_t *)cx->iid6); - nasrg_COMMON_flush_rb(cx); - nasrg_CLASS_flush_sclassifier(cx); -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_decode_cx_release: CONN_RELEASE_IND reception\n"); - printk(" Primitive length %u\n",p->length); - printk(" Local Connection reference %u\n",p->nasRGDCPrimitive.conn_release_ind.localConnectionRef); - printk(" Release cause %u\n",p->nasRGDCPrimitive.conn_release_ind.releaseCause); - nasrg_TOOL_print_state(cx->state); -#endif -} - -//--------------------------------------------------------------------------- -// Decode CONN_LOSS_IND message from RRC -void nasrg_ASCTL_DC_decode_cx_loss_ind(struct cx_entity *cx, struct nas_rg_dc_element *p) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_decode_cx_loss - begin \n"); -#endif - - if (!cx || !p) { - printk("nasrg_ASCTL_DC_decode_cx_loss - input parameter is NULL \n"); - return; - } - - // End debug information - cx->state = NAS_IDLE; - cx->iid4=0; - nasrg_TOOL_imei2iid(NAS_NULL_IMEI, (uint8_t *)cx->iid6); - nasrg_COMMON_flush_rb(cx); -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_decode_cx_loss: CONN_LOSS_IND reception\n"); - printk(" Primitive length %u\n",(int)(p->length)); - printk(" Local Connection reference %u\n",p->nasRGDCPrimitive.conn_loss_ind.localConnectionRef); - nasrg_TOOL_print_state(cx->state); -#endif -} -//--------------------------------------------------------------------------- -// Decode RB_ESTABLISH_CNF message from RRC -void nasrg_ASCTL_DC_decode_rb_establish_cnf(struct cx_entity *cx, struct nas_rg_dc_element *p) -{ - //--------------------------------------------------------------------------- - struct rb_entity *rb; - int rb_id; - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_decode_rb_establish - begin \n"); -#endif - - if (!cx || !p) { - printk("nasrg_ASCTL_DC_decode_rb_establish - input parameter is NULL \n"); - return; - } - - // End debug information - rb_id = p->nasRGDCPrimitive.rb_establish_conf.rbId; - rb=nasrg_COMMON_search_rb(cx, rb_id - (NAS_RB_MAX_NUM * cx->lcr)); - - // - if (rb!=NULL) { - if (rb->state==NAS_CX_CONNECTING) { -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_decode_rb_establish: RB_ESTABLISH_CNF received\n"); - printk(" Primitive length %u\n", p->length); - printk(" Local Connection reference %u\n",p->nasRGDCPrimitive.rb_establish_conf.localConnectionRef); - printk(" RB Id %u\n",p->nasRGDCPrimitive.rb_establish_conf.rbId); - printk(" SAP Id %u\n",p->nasRGDCPrimitive.rb_establish_conf.sapId); - printk(" Status %u, Failure code %d, Cx state, RB state\n",p->nasRGDCPrimitive.rb_establish_conf.status, p->nasRGDCPrimitive.rb_establish_conf.fail_code); - nasrg_TOOL_print_state(cx->state); - nasrg_TOOL_print_state(rb->state); -#endif - - switch (p->nasRGDCPrimitive.rb_establish_conf.status) { - case ACCEPTED: - rb->state = NAS_CX_DCH; - rb->countimer=1; - break; - - case FAILURE: - printk("nasrg_ASCTL_DC_decode_rb_establish: RB_ESTABLISH_CNF rejected\n"); - rb->state = NAS_CX_CONNECTING_FAILURE; - //delete rb - break; - - default: - printk("nasrg_ASCTL_DC_decode_rb_establish: RB_ESTABLISH_CNF reception, invalid status\n"); - } - } else - printk("nasrg_ASCTL_DC_decode_rb_establish: invalid state %u\n", cx->state); - } else - printk("nasrg_ASCTL_DC_decode_rb_establish: RB_ESTABLISH_CNF, No corresponding radio bearer\n"); -} - -//--------------------------------------------------------------------------- -// Decode DATA_TRANSFER_IND message from RRC -void nasrg_ASCTL_DC_decode_data_transfer_ind(struct cx_entity *cx, struct nas_rg_dc_element *p, char *buffer) -{ - //--------------------------------------------------------------------------- - uint8_t nasrg_data[10]; - unsigned int nas_length; - char data_type; - int bytes_read=0; - unsigned int peer_command; - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_decode_data_transfer - begin \n"); -#endif - - if (!cx || !p) { - printk("nasrg_ASCTL_DC_decode_data_transfer - input parameter is NULL \n"); - return; - } - - // End debug information - - bytes_read=p->length; - // Get first character - nas_length = (p->nasRGDCPrimitive.data_transfer_ind.nasDataLength) -1; -#ifndef PDCP_USE_NETLINK - bytes_read += rtf_get(cx->sap[NAS_DC_OUTPUT_SAPI], &data_type, 1); -#else - memcpy (&data_type, (char *)(&buffer[bytes_read]), 1); - bytes_read ++; -#endif - - //check if peer message - if (data_type =='A') { - // receive in a skbuff - //nasrg_COMMON_receive((p->length) + 1, nas_length, cx->sap[NAS_DC_OUTPUT_SAPI]); // original -#ifndef PDCP_USE_NETLINK - //void nasrg_COMMON_receive(uint16_t bytes_read, uint16_t payload_length, void *data_buffer, int rb_id, int sap); - // data_buffer is NULL because FIFO should be read directly in the skbuff (LITE has an intermediary buffer) - nasrg_COMMON_receive((p->length) + 1, nas_length, NULL, 2, cx->sap[NAS_DC_OUTPUT_SAPI]); -#else - //nasrg_COMMON_receive((p->length) + 1, nas_length, (unsigned char *)p+p->length+1, 2, 0); - nasrg_COMMON_receive((p->length) + 1, nas_length, (unsigned char *)(&buffer[bytes_read]), 2, 0); -#endif - } else { - // if FIFO, empty remaining data -#ifndef PDCP_USE_NETLINK - bytes_read += rtf_get(cx->sap[NAS_DC_OUTPUT_SAPI], (gpriv->rbuffer)+ (p->length), nas_length); -#endif - - if (data_type=='Z') { -#ifndef PDCP_USE_NETLINK - memcpy (&nasrg_data, (char *)(gpriv->rbuffer)+ (p->length), 10); -#else - memcpy (&nasrg_data, (char *)(&buffer[bytes_read]), 10); -#endif - peer_command = (int)nasrg_data[0]; - printk("nasrg_ASCTL_DC_decode_data_transfer: Received peer message %d %d \n", nasrg_data[0], peer_command); - nasrg_TOOL_print_buffer(nasrg_data, 10); - - if (nasrg_data[0]== NAS_CMD_OPEN_RB) { - // open radio bearer - printk("nasrg_ASCTL_DC_decode_data_transfer: Opening Default Radio Bearer\n"); - nasrg_ASCTL_start_default_rb(cx); - } else if (nasrg_data[0]== NAS_CMD_ENTER_SLEEP) { - printk("nasrg_ASCTL_DC_decode_data_transfer: Entering Sleep Mode\n"); - cx->state = NAS_CX_RELEASING; - } else if (nasrg_data[0]== NAS_CMD_LEAVE_SLEEP) { - printk("nasrg_ASCTL_DC_decode_data_transfer: Leaving Sleep Mode\n"); - cx->state = NAS_CX_DCH; - } else { - printk("\n\nnasrg_ASCTL_DC_decode_data_transfer: Unknown peer command\n"); - } - } else - printk("nasrg_ASCTL_DC_decode_data_transfer: Error during reception of the message - Dropped\n"); - } - -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_decode_data_transfer: DATA_TRANSFER_IND reception\n"); - printk(" Primitive length %u\n", p->length); - printk(" Local Connection reference %u\n",p->nasRGDCPrimitive.data_transfer_ind.localConnectionRef); - printk(" Data Length %u\n", p->nasRGDCPrimitive.data_transfer_ind.nasDataLength); - nasrg_TOOL_print_state(cx->state); -#endif -} - -//--------------------------------------------------------------------------- -// Decode MBMS_BEARER_ESTABLISH_CNF message from RRC -void nasrg_ASCTL_DC_decode_mbms_bearer_establish_cnf(struct nas_rg_dc_element *p) -{ - //--------------------------------------------------------------------------- - int mbms_ix; - int rb_id; - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_decode_mbms_bearer_establish - begin \n"); -#endif - - if (!p) { - printk("nasrg_ASCTL_DC_decode_mbms_bearer_establish - input parameter is NULL \n"); - return; - } - - // End debug information - rb_id = p->nasRGDCPrimitive.mbms_establish_cnf.rbId; - mbms_ix = 0; // A revoir - find using cnxid... - - if (rb_id == gpriv->mbms_rb[mbms_ix].mbms_rbId) { - switch (p->nasRGDCPrimitive.mbms_establish_cnf.status) { - case ACCEPTED: - gpriv->mbms_rb[mbms_ix].state = NAS_CX_DCH; - gpriv->mbms_rb[mbms_ix].rab_id = gpriv->mbms_rb[mbms_ix].mbms_rbId; - nasrg_ASCTL_start_mbmsclassifier(mbms_ix,&(gpriv->mbms_rb[mbms_ix])); - break; - - case FAILURE: - printk("nasrg_ASCTL_DC_decode_mbms_bearer_establish: MBMS_BEARER_ESTABLISH_CNF rejected\n"); - gpriv->mbms_rb[mbms_ix].state = NAS_CX_CONNECTING_FAILURE; //supprimer l'entree - break; - - default: - printk("nasrg_ASCTL_DC_decode_mbms_bearer_establish: MBMS_BEARER_ESTABLISH_CNF reception, invalid status\n"); - } - } else - printk(" nasrg_ASCTL_DC_decode_mbms_bearer_establish: invalid RB_Id %d\n", rb_id); - -#ifdef NAS_DEBUG_DC - printk(" nasrg_ASCTL_DC_decode_mbms_bearer_establish: MBMS_BEARER_ESTABLISH_CNF reception\n"); - printk(" Primitive length %u\n",p->length); - printk(" rb_id %d, status %d\n",p->nasRGDCPrimitive.mbms_establish_cnf.rbId, p->nasRGDCPrimitive.mbms_establish_cnf.status); - nasrg_TOOL_print_state(gpriv->mbms_rb[mbms_ix].state); -#endif -} - -//--------------------------------------------------------------------------- -// Decode MBMS_UE_NOTIFY_CNF message from RRC -void nasrg_ASCTL_DC_decode_mbms_ue_notify_cnf(struct cx_entity *cx, struct nas_rg_dc_element *p) -{ - //--------------------------------------------------------------------------- - int i, j, k; - - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_decode_mbms_ue_notify - begin \n"); -#endif - - if (!cx || !p) { - printk("nasrg_ASCTL_DC_decode_mbms_ue_notify - input parameter is NULL \n"); - return; - } - - // End debug information - if (p->nasRGDCPrimitive.mbms_ue_notify_cnf.mbmsStatus == ACCEPTED) { - for (i = 0; irequested_joined_services[i] >=0) { - for (j = 0; jjoined_services[j] ==-1) { - cx->joined_services[j]= cx->requested_joined_services[i]; - cx->requested_joined_services[i]=-1; - break; - } - } - } - - if (cx->requested_left_services[i] >=0) { - for (k = 0; kjoined_services[k] == cx->requested_left_services[i]) { - cx->joined_services[k]=-1; - cx->requested_left_services[i]=-1; - break; - } - } - } - } - } - -#ifdef NAS_DEBUG_DC - printk(" nasrg_ASCTL_DC_decode_mbms_ue_notify: MBMS_UE_NOTIFY_CNF reception\n"); - printk(" Primitive length %u\n",p->length); - printk(" Local Connection reference %u\n",p->nasRGDCPrimitive.mbms_ue_notify_cnf.localConnectionRef); - printk(" MBMS Status: %d\n", p->nasRGDCPrimitive.mbms_ue_notify_cnf.mbmsStatus); - printk(" UE services currently joined \n"); - - for (i = 0; ijoined_services[i]); - - nasrg_TOOL_print_state(cx->state); -#endif -} -/* - msgToBuild->nasRgPrimitive.dc_sap_prim.nasRGDCPrimitive.eNBmeasurement_ind.cell_id = protocol_bs->rrc.rg_cell_id; - // next values are temp hard coded, to be replaced by real values - msgToBuild->nasRgPrimitive.dc_sap_prim.nasRGDCPrimitive.eNBmeasurement_ind.num_UEs = num_connected_UEs; - for (ix=0; ixnum_connected_UEs; ix++){ - msgToBuild->nasRgPrimitive.dc_sap_prim.nasRGDCPrimitive.eNBmeasurement_ind.measures[ix].rlcBufferOccupancy = 100 - (30*ix); - msgToBuild->nasRgPrimitive.dc_sap_prim.nasRGDCPrimitive.eNBmeasurement_ind.measures[ix].scheduledPRB = 500 - (200*ix); - msgToBuild->nasRgPrimitive.dc_sap_prim.nasRGDCPrimitive.eNBmeasurement_ind.measures[ix].totalDataVolume = 640000 + (160000*ix); - } - msgToBuild->nasRgPrimitive.dc_sap_prim.nasRGDCPrimitive.eNBmeasurement_ind.totalNumPRBs = 1000; - -*/ -//--------------------------------------------------------------------------- -// Decode ENB_MEASUREMENT_IND message from RRC -void nasrg_ASCTL_DC_decode_eNBmeasurement_ind(struct nas_rg_dc_element *p) -{ - //--------------------------------------------------------------------------- - uint8_t i; - // Start debug information -#ifdef NAS_DEBUG_DC - printk("nasrg_ASCTL_DC_decode_eNBmeasurement_ind - begin \n"); -#endif - - if (!p) { - printk("nasrg_ASCTL_DC_decode_eNBmeasurement_ind - input parameter p is NULL \n"); - return; - } - - // End debug information -#ifdef NAS_DEBUG_DC_DETAIL - printk(" nasrg_ASCTL_DC_decode_eNBmeasurement_ind : ENB_MEASUREMENT_IND reception\n"); - printk(" Measured Cell: %u\n", p->nasRGDCPrimitive.eNBmeasurement_ind.cell_id); - printk(" Number of Connected Mobiles: %u\n", p->nasRGDCPrimitive.eNBmeasurement_ind.num_UEs); - - for (i=0; inasRGDCPrimitive.eNBmeasurement_ind.num_UEs; ++i) { - printk(" UE[%u]: rlcBufferOccupancy %u, scheduledPRB: %u, totalDataVolume: %u\n", i, - p->nasRGDCPrimitive.eNBmeasurement_ind.measures[i].rlcBufferOccupancy, - p->nasRGDCPrimitive.eNBmeasurement_ind.measures[i].scheduledPRB, - p->nasRGDCPrimitive.eNBmeasurement_ind.measures[i].totalDataVolume); - } - - printk(" Total number of PRBs: %u\n", p->nasRGDCPrimitive.eNBmeasurement_ind.totalNumPRBs); -#endif - // store Measures - gpriv->measured_cell_id = p->nasRGDCPrimitive.eNBmeasurement_ind.cell_id; - gpriv->num_UEs = p->nasRGDCPrimitive.eNBmeasurement_ind.num_UEs; - - for (i=0; i num_UEs; ++i) { - gpriv->rlcBufferOccupancy[i] = p->nasRGDCPrimitive.eNBmeasurement_ind.measures[i].rlcBufferOccupancy; - gpriv->scheduledPRB[i] += p->nasRGDCPrimitive.eNBmeasurement_ind.measures[i].scheduledPRB; - gpriv->totalDataVolume[i] += p->nasRGDCPrimitive.eNBmeasurement_ind.measures[i].totalDataVolume; - } - - gpriv->totalNumPRBs += p->nasRGDCPrimitive.eNBmeasurement_ind.totalNumPRBs; -} - -//--------------------------------------------------------------------------- -// Check if anything in DC FIFO and process it (RG Finite State Machine) -int nasrg_ASCTL_DC_receive(struct cx_entity *cx, char *buffer) -{ - //--------------------------------------------------------------------------- - int bytes_read=0; - - // Start debug information -#ifdef NAS_DEBUG_DC_DETAIL - printk("nasrg_ASCTL_DC_receive - begin \n"); -#endif - - if (!cx) { - printk("nasrg_ASCTL_DC_receive - input parameter cx is NULL \n"); - return 0; - } - - // End debug information - -#ifndef PDCP_USE_NETLINK - bytes_read = rtf_get(cx->sap[NAS_DC_OUTPUT_SAPI] , gpriv->rbuffer, NAS_TL_SIZE); -#else - bytes_read = NAS_TL_SIZE; -#endif - - if (bytes_read>0) { - struct nas_rg_dc_element *p; -#ifndef PDCP_USE_NETLINK - p= (struct nas_rg_dc_element *)(gpriv->rbuffer); - //get the rest of the primitive - bytes_read += rtf_get(cx->sap[NAS_DC_OUTPUT_SAPI], (uint8_t *)p+NAS_TL_SIZE, p->length-NAS_TL_SIZE); - - if (bytes_read!=p->length) { - printk("nasrg_ASCTL_DC_receive: Problem while reading primitive's header\n"); - return bytes_read; - } - -#else - p= (struct nas_rg_dc_element *)(buffer); - bytes_read=p->length; -#endif - - switch (p->type) { - case CONN_ESTABLISH_IND : - if (p->nasRGDCPrimitive.conn_establish_ind.localConnectionRef!=cx->lcr) - printk("nasrg_ASCTL_DC_receive: CONN_ESTABLISH_IND reception, Local connection reference not correct %u\n", p->nasRGDCPrimitive.conn_establish_ind.localConnectionRef); - else { - switch(cx->state) { - case NAS_IDLE: - nasrg_ASCTL_DC_decode_cx_establish_ind(cx,p); - break; - - default: - printk("nasrg_ASCTL_DC_receive: CONN_ESTABLISH_IND reception, invalid state %u\n", cx->state); - } - } - - break; - - case CONN_RELEASE_IND : - if (p->nasRGDCPrimitive.conn_release_ind.localConnectionRef!=cx->lcr) - printk("nasrg_ASCTL_DC_receive: CONN_RELEASE_IND reception, Local connection reference not correct %u\n", p->nasRGDCPrimitive.conn_release_ind.localConnectionRef); - else { - switch(cx->state) { - case NAS_CX_DCH: - nasrg_ASCTL_DC_decode_cx_release_ind(cx,p); - break; - - default: - printk("nasrg_ASCTL_DC_receive: CONN_RELEASE_IND reception, invalid state %u\n", cx->state); - } - } - - break; - - case CONN_LOSS_IND: - if (p->nasRGDCPrimitive.conn_loss_ind.localConnectionRef!=cx->lcr) - printk("nasrg_ASCTL_DC_receive: CONN_LOSS_IND reception, Local connection reference not correct %u\n", p->nasRGDCPrimitive.conn_loss_ind.localConnectionRef); - else { - switch(cx->state) { - case NAS_CX_DCH: - nasrg_ASCTL_DC_decode_cx_loss_ind(cx,p); - break; - - default: - printk("nasrg_ASCTL_DC_receive: CONN_LOSS_IND reception, invalid state %u\n", cx->state); - } - } - - break; - - case RB_ESTABLISH_CNF: - if (p->nasRGDCPrimitive.rb_establish_conf.localConnectionRef!=cx->lcr) - printk("nasrg_ASCTL_DC_receive: RB_ESTABLISH_CNF reception, Local connection reference not correct %u\n", p->nasRGDCPrimitive.rb_establish_conf.localConnectionRef); - else { - switch(cx->state) { - case NAS_CX_DCH: - nasrg_ASCTL_DC_decode_rb_establish_cnf(cx,p); -#ifdef NAS_AUTO_MBMS - nasrg_ASCTL_start_default_ue_notification(cx); -#endif - break; - - default: - printk("nasrg_ASCTL_DC_receive: RB_ESTABLISH_CNF reception, invalid state %u\n", cx->state); - } - } - - break; - - case DATA_TRANSFER_IND: - if (p->nasRGDCPrimitive.data_transfer_ind.localConnectionRef!=cx->lcr) - printk("nasrg_ASCTL_DC_receive: DATA_TRANSFER_IND reception, Local connection reference not correct %u\n", p->nasRGDCPrimitive.rb_establish_conf.localConnectionRef); - else { - switch(cx->state) { - case NAS_CX_DCH: - case NAS_CX_RELEASING: - nasrg_ASCTL_DC_decode_data_transfer_ind(cx,p,buffer); - break; - - default: - printk("nasrg_ASCTL_DC_receive: DATA_TRANSFER_IND reception, invalid state %u\n", cx->state); - } - } - - break; - - // Temp - Should be in uplink GC-SAP - case MBMS_BEARER_ESTABLISH_CNF: - // if (p->nasRGDCPrimitive.mbms_ue_notify_cnf.localConnectionRef!=cx->lcr) - // printk("nasrg_ASCTL_DC_receive: MBMS_BEARER_ESTABLISH_CNF reception, Local connection reference not correct %u\n", p->nasRGDCPrimitive.rb_establish_conf.localConnectionRef); - // else - nasrg_ASCTL_DC_decode_mbms_bearer_establish_cnf(p); - break; - - case MBMS_UE_NOTIFY_CNF: - if (p->nasRGDCPrimitive.mbms_ue_notify_cnf.localConnectionRef!=cx->lcr) - printk("nasrg_ASCTL_DC_receive: MBMS_UE_NOTIFY_CNF reception, Local connection reference not correct %u\n", p->nasRGDCPrimitive.rb_establish_conf.localConnectionRef); - else { - switch(cx->state) { - case NAS_CX_DCH: - nasrg_ASCTL_DC_decode_mbms_ue_notify_cnf(cx,p); - /* //Temp - nasrg_ASCTL_start_default_mbms_service();*/ - break; - - default: - printk("nasrg_ASCTL_DC_receive: MBMS_UE_NOTIFY_CNF reception, invalid state %u\n", cx->state); - } - } - - break; - - // Temp - Should be in uplink GC-SAP - case ENB_MEASUREMENT_IND : - // if (p->nasRGDCPrimitive.eNBmeasurement_ind.localConnectionRef!=cx->lcr) - // printk("nasrg_ASCTL_DC_receive: ENB_MEASUREMENT_IND reception, Local connection reference not correct %u\n", p->nasRGDCPrimitive.eNBmeasurement_ind.localConnectionRef); - // else - nasrg_ASCTL_DC_decode_eNBmeasurement_ind(p); - break; - - default : - printk("nasrg_ASCTL_DC_receive: Invalid message received\n"); - } - } - - return bytes_read; -} - -#endif diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_classifier.c b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_classifier.c deleted file mode 100644 index 4c0cf8aa1e..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_classifier.c +++ /dev/null @@ -1,1139 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasrg_classifier.c -* \brief Flow classification functions for OpenAirInterface CELLULAR version - RG -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#include "nasrg_variables.h" -#include "nasrg_proto.h" - -#include -#include - -#define IN_CLASSA(a) ((((long int) (a)) & 0x80000000) == 0) -#define IN_CLASSB(a) ((((long int) (a)) & 0xc0000000) == 0x80000000) -#define IN_CLASSC(a) ((((long int) (a)) & 0xe0000000) == 0xc0000000) -#define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000) - -/* Address to accept any incoming messages. */ -#define INADDR_ANY ((unsigned long int) 0x00000000) - -#define NIPADDR(addr) \ - (uint8_t)(addr & 0x000000FF), \ - (uint8_t)((addr & 0x0000FF00) >> 8), \ - (uint8_t)((addr & 0x00FF0000) >> 16), \ - (uint8_t)((addr & 0xFF000000) >> 24) - -#define NIP6ADDR(addr) \ - ntohs((addr)->s6_addr16[0]), \ - ntohs((addr)->s6_addr16[1]), \ - ntohs((addr)->s6_addr16[2]), \ - ntohs((addr)->s6_addr16[3]), \ - ntohs((addr)->s6_addr16[4]), \ - ntohs((addr)->s6_addr16[5]), \ - ntohs((addr)->s6_addr16[6]), \ - ntohs((addr)->s6_addr16[7]) - - -#define IN6_IS_ADDR_UNSPECIFIED(a) \ - (((__const uint32_t *) (a))[0] == 0 \ - && ((__const uint32_t *) (a))[1] == 0 \ - && ((__const uint32_t *) (a))[2] == 0 \ - && ((__const uint32_t *) (a))[3] == 0) - -#define IN6_ARE_ADDR_MASKED_EQUAL(a,b,m) \ - (((((__const uint32_t *) (a))[0] & (((__const uint32_t *) (m))[0])) == (((__const uint32_t *) (b))[0] & (((__const uint32_t *) (m))[0]))) \ - && ((((__const uint32_t *) (a))[1] & (((__const uint32_t *) (m))[1])) == (((__const uint32_t *) (b))[1] & (((__const uint32_t *) (m))[1]))) \ - && ((((__const uint32_t *) (a))[2] & (((__const uint32_t *) (m))[2])) == (((__const uint32_t *) (b))[2] & (((__const uint32_t *) (m))[2]))) \ - && ((((__const uint32_t *) (a))[3] & (((__const uint32_t *) (m))[3])) == (((__const uint32_t *) (b))[3] & (((__const uint32_t *) (m))[3])))) - -#define IN_ARE_ADDR_MASKED_EQUAL(a,b,m) \ - (((((__const uint8_t *) (a))[0] & (((__const uint8_t *) (m))[0])) == (((__const uint8_t *) (b))[0] & (((__const uint8_t *) (m))[0]))) \ - && ((((__const uint8_t *) (a))[1] & (((__const uint8_t *) (m))[1])) == (((__const uint8_t *) (b))[1] & (((__const uint8_t *) (m))[1]))) \ - && ((((__const uint8_t *) (a))[2] & (((__const uint8_t *) (m))[2])) == (((__const uint8_t *) (b))[2] & (((__const uint8_t *) (m))[2]))) \ - && ((((__const uint8_t *) (a))[3] & (((__const uint8_t *) (m))[3])) == (((__const uint8_t *) (b))[3] & (((__const uint8_t *) (m))[3])))) - -//--------------------------------------------------------------------------- -void nasrg_create_mask_ipv6_addr(struct in6_addr *masked_addrP, int prefix_len) -{ - //--------------------------------------------------------------------------- - int u6_addr8_index; - int u6_addr1_index; - int index; - - masked_addrP->s6_addr32[0] = 0xFFFFFFFF; - masked_addrP->s6_addr32[1] = 0xFFFFFFFF; - masked_addrP->s6_addr32[2] = 0xFFFFFFFF; - masked_addrP->s6_addr32[3] = 0xFFFFFFFF; - - u6_addr8_index = prefix_len >> 3; - u6_addr1_index = prefix_len & 0x07; - - for (index = u6_addr8_index + 1; index < 16; index++) { - masked_addrP->s6_addr[index] = 0; - } - - if (u6_addr1_index > 0) { - masked_addrP->s6_addr[u6_addr8_index] = 0xFF << (8-u6_addr1_index); - } - -#ifdef NAS_DEBUG_CLASS - //printk("nasrg_create_mask_ipv6_addr: MASK = %X:%X:%X:%X:%X:%X:%X:%X\n",NIP6ADDR(masked_addrP)); -#endif -} -//--------------------------------------------------------------------------- -void nasrg_create_mask_ipv4_addr(struct in_addr *masked_addrP, int prefix_len) -{ - //--------------------------------------------------------------------------- - if (prefix_len > 32) { - prefix_len = 32; - } - - masked_addrP->s_addr = 0xFFFFFFFF << (32 - prefix_len); -#ifdef NAS_DEBUG_CLASS - //printk("nasrg_create_mask_ipv4_addr: MASK = %d.%d.%d.%d\n",NIPADDR(masked_addrP)); -#endif - return; -} - -//--------------------------------------------------------------------------- -// Add a new classifier rule (send direction) -struct classifier_entity *nasrg_CLASS_add_sclassifier(struct cx_entity *cx, uint8_t dscp, uint16_t classref) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *gc; - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_add_sclassifier: begin for dscp %d, classref %d\n", dscp,classref); -#endif - - if (cx==NULL) { - printk("nasrg_CLASS_add_sclassifier - input parameter cx is NULL \n"); - return NULL; - } - - //*** - for (gc=cx->sclassifier[dscp]; gc!=NULL; gc=gc->next) { - if (gc->classref==classref) { -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_add_sclassifier: classifier already exist for dscp %d, classref %d\n",dscp,classref); -#endif - return gc; - } - } - - gc=(struct classifier_entity *)kmalloc(sizeof(struct classifier_entity), GFP_ATOMIC); - - if (gc==NULL) - return NULL; - - memset(gc, 0, sizeof(struct classifier_entity)); - gc->next=cx->sclassifier[dscp]; - gc->classref=classref; - cx->sclassifier[dscp]=gc; - ++cx->nsclassifier; - ++gpriv->next_sclassref; //increment send classref index - MW 15/01/07 -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_add_sclassifier: classifier created for dscp %d, classref %d\n",dscp,classref); -#endif - return gc; -} - -//--------------------------------------------------------------------------- -// Add a new classifier rule (receive direction) -struct classifier_entity *nasrg_CLASS_add_rclassifier(uint8_t dscp, uint16_t classref) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *gc; - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_add_rclassifier: begin\n"); -#endif - - //*** - for (gc=gpriv->rclassifier[dscp]; gc!=NULL; gc=gc->next) { - if (gc->classref==classref) { -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_add_rclassifier: classifier already exist for dscp %d, classref %d\n",dscp,classref); -#endif - return gc; - } - } - - gc=(struct classifier_entity *)kmalloc(sizeof(struct classifier_entity), GFP_KERNEL); - - if (gc==NULL) - return NULL; - - gc->next=gpriv->rclassifier[dscp]; - gc->classref=classref; - gpriv->rclassifier[dscp]=gc; - ++gpriv->nrclassifier; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_add_rclassifier: classifier created for dscp %d, classref %d\n",dscp,classref); -#endif - return gc; -} - -//--------------------------------------------------------------------------- -// Add a new classifier rule (mbms direction) -struct classifier_entity *nasrg_CLASS_add_mbmsclassifier(int mbms_ix, uint16_t classref) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *gc; - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_add_mbmsclassifier: begin\n"); -#endif - - //*** - for (gc=gpriv->mbmsclassifier[mbms_ix]; gc!=NULL; gc=gc->next) { - if (gc->classref==classref) { -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_add_mbmsclassifier: classifier already exist for service %d, classref %d\n",mbms_ix,classref); -#endif - return gc; - } - } - - gc=(struct classifier_entity *)kmalloc(sizeof(struct classifier_entity), GFP_ATOMIC); - - if (gc==NULL) - return NULL; - - gc->next=gpriv->mbmsclassifier[mbms_ix]; - gc->classref=classref; - gpriv->mbmsclassifier[mbms_ix]=gc; - ++gpriv->nmbmsclassifier; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_add_mbmsclassifier: classifier created for service index %d, classref %d\n",mbms_ix,classref); -#endif - return gc; -} - -//--------------------------------------------------------------------------- -void nasrg_CLASS_flush_sclassifier(struct cx_entity *cx) -{ - //--------------------------------------------------------------------------- - uint8_t dscpi; - struct classifier_entity *gc; - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_flush_sclassifier: begin\n"); -#endif - - if (cx==NULL) { - printk("nasrg_CLASS_flush_sclassifier - input parameter cx is NULL \n"); - return; - } - - //*** - for (dscpi=0; dscpisclassifier[dscpi]; gc!=NULL; gc=cx->sclassifier[dscpi]) { - cx->sclassifier[dscpi]=gc->next; - kfree(gc); - } - } - - cx->nsclassifier=0; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_flush_sclassifier: end\n"); -#endif -} - -//--------------------------------------------------------------------------- -void nasrg_CLASS_flush_rclassifier() -{ - //--------------------------------------------------------------------------- - uint8_t dscpi; - struct classifier_entity *gc; - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_flush_rclassifier: begin\n"); -#endif - - //*** - for (dscpi=0; dscpirclassifier[dscpi]; gc!=NULL; gc=gpriv->rclassifier[dscpi]) { - gpriv->rclassifier[dscpi]=gc->next; - kfree(gc); - } - } - - gpriv->nrclassifier=0; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_flush_rclassifier: end\n"); -#endif -} - -//--------------------------------------------------------------------------- -void nasrg_CLASS_flush_mbmsclassifier() -{ - //--------------------------------------------------------------------------- - int mbmsi; - struct classifier_entity *gc; - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_flush_mbmsclassifier: begin\n"); -#endif - - //*** - for (mbmsi=0; mbmsimbmsclassifier[mbmsi]; gc!=NULL; gc=gpriv->mbmsclassifier[mbmsi]) { - gpriv->mbmsclassifier[mbmsi]=gc->next; - kfree(gc); - } - } - - gpriv->nmbmsclassifier=0; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_flush_mbmsclassifier: end\n"); -#endif -} - -//--------------------------------------------------------------------------- -// Delete a classifier rule (send direction) -void nasrg_CLASS_del_sclassifier(struct cx_entity *cx, uint8_t dscp, uint16_t classref) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *p,*np; - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_del_sclassifier: begin\n"); -#endif - - if (cx==NULL) { - printk("nasrg_CLASS_del_sclassifier - input parameter cx is NULL \n"); - return; - } - - //*** - p=cx->sclassifier[dscp]; - - if (p==NULL) - return; - - if (p->classref==classref) { - cx->sclassifier[dscp]=p->next; - kfree(p); - --cx->nsclassifier; - return; - } - - for (np=p->next; np!=NULL; p=np) { - if (np->classref==classref) { - p->next=np->next; - kfree(np); - --cx->nsclassifier; - return; - } - } - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_del_sclassifier: end\n"); -#endif -} - -//--------------------------------------------------------------------------- -// Delete a classifier rule (receive direction) -void nasrg_CLASS_del_rclassifier(uint8_t dscp, uint16_t classref) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *p,*np; - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_del_rclassifier: begin\n"); -#endif - //*** - p=gpriv->rclassifier[dscp]; - - if (p==NULL) - return; - - if (p->classref==classref) { - gpriv->rclassifier[dscp]=p->next; - kfree(p); - --gpriv->nrclassifier; - return; - } - - for (np=p->next; np!=NULL; p=np) { - if (np->classref==classref) { - p->next=np->next; - kfree(np); - --gpriv->nrclassifier; - return; - } - } - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_del_rclassifier: end\n"); -#endif -} - -//--------------------------------------------------------------------------- -// Delete a classifier rule (mbms direction) -void nasrg_CLASS_del_mbmsclassifier(int mbms_ix, uint16_t classref) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *p,*np; - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_del_mbmsclassifier: begin\n"); -#endif - //*** - p=gpriv->mbmsclassifier[mbms_ix]; - - if (p==NULL) - return; - - if (p->classref==classref) { - gpriv->mbmsclassifier[mbms_ix]=p->next; - kfree(p); - --gpriv->nmbmsclassifier; - return; - } - - for (np=p->next; np!=NULL; p=np) { - if (np->classref==classref) { - p->next=np->next; - kfree(np); - --gpriv->nmbmsclassifier; - return; - } - } - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_del_mbmsclassifier: end\n"); -#endif -} - -/* ORIGINAL VERSION -//--------------------------------------------------------------------------- -// Search the entity with the IPv4 address 'addr' -struct cx_entity *nasrg_CLASS_cx4(struct sk_buff *skb){ -//--------------------------------------------------------------------------- - uint8_t cxi; - #ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_cx4: begin\n"); - #endif - cxi=0; - return gpriv->cx+cxi; -//#endif -}*/ - -//--------------------------------------------------------------------------- -// Search the entity with the IPv4 address 'addr' -struct cx_entity *nasrg_CLASS_cx4(struct sk_buff *skb, unsigned char dscp, int *paddr_type, unsigned char *cx_index) -{ - //--------------------------------------------------------------------------- - unsigned char cxi; - uint32_t daddr; - struct cx_entity *cx=NULL; - struct classifier_entity *pclassifier=NULL; - struct in_addr masked_addr; - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_cx4: begin\n"); -#endif - - if (skb!=NULL) { - daddr = ((struct iphdr*)(skb_network_header(skb)))->daddr; - - if (daddr != INADDR_ANY) { -#ifdef NAS_DEBUG_CLASS - printk("SOURCE ADDR %d.%d.%d.%d",NIPADDR(ip_hdr(skb)->saddr)); - printk(" DEST ADDR %d.%d.%d.%d\n",NIPADDR(ip_hdr(skb)->daddr)); -#endif - - if (ipv4_is_multicast(ip_hdr(skb)->daddr)) { - // TO BE CHECKED - *paddr_type = NAS_IPV4_ADDR_MC_SIGNALLING; - } else { - if (ipv4_is_lbcast(ip_hdr(skb)->daddr)) { - // TO BE CHECKED - *paddr_type = NAS_IPV4_ADDR_BROADCAST; - } else { - if (IN_CLASSA(ip_hdr(skb)->daddr) || IN_CLASSB(ip_hdr(skb)->daddr) || IN_CLASSC(ip_hdr(skb)->daddr)) { - *paddr_type = NAS_IPV4_ADDR_UNICAST; - - for (cxi=*cx_index; cxicx[cxi].sclassifier[dscp]; - - while (pclassifier!=NULL) { - // verify that this is an IPv4 classifier - if ((pclassifier->version == NAS_VERSION_4) || (pclassifier->version == NAS_VERSION_DEFAULT)) { - nasrg_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen); - - if (IN_ARE_ADDR_MASKED_EQUAL(&ip_hdr(skb)->daddr, &(pclassifier->daddr.ipv4), &masked_addr)) { -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_cx4: IP MASK MATCHED: found cx %d: %d.%d.%d.%d/%d\n",cxi, NIPADDR(pclassifier->daddr.ipv4), pclassifier->dplen); -#endif - return &gpriv->cx[cxi]; - } - } - - // goto to next classification rule for the connection - pclassifier = pclassifier->next; - } - } - } else { - *paddr_type = NAS_IPV4_ADDR_UNKNOWN; - } - } - } - } - } - - return cx; -} - -/* ORIGINAL VERSION -//--------------------------------------------------------------------------- -// Search the entity corresponding to destination address in IPv6 header -struct cx_entity *nasrg_CLASS_cx6(struct sk_buff *skb, int* paddr_type, int* pmbms_ix){ -//--------------------------------------------------------------------------- - struct cx_entity * cx=NULL; - uint8_t cxi; - uint32_t mc_addr_hdr, uni_ifid1, uni_ifid2; - //int addr_type = NASRG_ADDR_UNKNOWN; - - #ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_cx6: begin\n"); - #endif - if (!skb){ - printk("nasrg_CLASS_cx6 - input parameter skb is NULL \n"); - return cx; - } - *paddr_type = NASRG_ADDR_UNKNOWN; - //mc_addr_hdr = ntohl(skb->nh.ipv6h->daddr.in6_u.u6_addr32[0]); - mc_addr_hdr = ntohl(ipv6_hdr(skb)->daddr.in6_u.u6_addr32[0]); - // First check if multicast [1st octet is FF] - if ((mc_addr_hdr & 0xFF000000) == 0xFF000000) { - // packet type according to the scope of the multicast packet - // we don't consider RPT bits in second octet [maybe done later if needed] - switch(mc_addr_hdr & 0x000F0000) { - case (0x00020000): - *paddr_type = NASRG_ADDR_MC_SIGNALLING; - #ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_cx6: multicast packet - signalling \n"); - #endif - break; - case (0x000E0000): - *paddr_type = NASRG_ADDR_MC_MBMS; - *pmbms_ix = 0; - cx=gpriv->cx; // MBMS associate to Mobile 0 - #ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_cx6: multicast packet - MBMS data \n"); - #endif - break; - default: - *paddr_type = NASRG_ADDR_UNKNOWN; - *pmbms_ix = NASRG_MBMS_SVCES_MAX; - } - // This is not multicast, so we should be able to identify the MT - }else{ - #ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_cx6: unicast packet\n"); - #endif - *paddr_type = NASRG_ADDR_UNICAST; - uni_ifid1 = ntohl(ipv6_hdr(skb)->daddr.in6_u.u6_addr32[2]); - uni_ifid2 = ntohl(ipv6_hdr(skb)->daddr.in6_u.u6_addr32[3]); - for (cxi=0; cxicx+cxi; - #ifdef NAS_DEBUG_SEND_DETAIL - printk("nasrg_CLASS_cx6: Compared addresses \n"); - printk(" Daddr[2] %ul, Daddr[3] %ul\n", - ipv6_hdr(skb)->daddr.in6_u.u6_addr32[2],ipv6_hdr(skb)->daddr.in6_u.u6_addr32[3]); - printk(" ntohl Daddr[2] %ul, Daddr[3] %ul\n",uni_ifid1,uni_ifid2); - printk(" IIF[0] %ul, IIF[1] %ul\n",cx->iid6[0],cx->iid6[1]); - printk(" htonl IIF[0] %ul, IIF[1] %ul\n",htonl(cx->iid6[0]),htonl(cx->iid6[1])); - #endif - if (((cx->iid6[0] == uni_ifid1)&&(cx->iid6[1] == uni_ifid2)) - || ((htonl(cx->iid6[0]) == uni_ifid1)&&(htonl(cx->iid6[1]) == uni_ifid2))){ - return cx; - } - } - } - return cx; -}*/ - -//--------------------------------------------------------------------------- -// Search the entity with the IPv6 address 'addr' -// Navid: the ipv6 classifier is not fully tested -struct cx_entity *nasrg_CLASS_cx6(struct sk_buff *skb, unsigned char dscp, int *paddr_type, unsigned char *cx_index, int* pmbms_ix) -{ - //--------------------------------------------------------------------------- - uint8_t cxi; - struct cx_entity *cx = NULL; - struct classifier_entity *sclassifier= NULL; - uint32_t mc_addr_hdr; - struct in6_addr masked_addr; - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_cx6: begin\n"); -#endif - - if (skb) { -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_cx6: SOURCE ADDR %X:%X:%X:%X:%X:%X:%X:%X",NIP6ADDR(&(ipv6_hdr(skb)->saddr))); - printk(" DEST ADDR %X:%X:%X:%X:%X:%X:%X:%X\n",NIP6ADDR(&(ipv6_hdr(skb)->daddr))); -#endif - mc_addr_hdr = ntohl(ipv6_hdr(skb)->daddr.in6_u.u6_addr32[0]); - - // First check if multicast [1st octet is FF] - if ((mc_addr_hdr & 0xFF000000) == 0xFF000000) { - // packet type according to the scope of the multicast packet - // we don't consider RPT bits in second octet [maybe done later if needed] - switch(mc_addr_hdr & 0x000F0000) { - case (0x00020000): - *paddr_type = NAS_IPV6_ADDR_MC_SIGNALLING; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_cx6: multicast packet - signalling \n"); -#endif - break; - - case (0x000E0000): - *paddr_type = NAS_IPV6_ADDR_MC_MBMS; - *pmbms_ix = 0; - cx=gpriv->cx; // MBMS associate to Mobile 0 -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_cx6: multicast packet - MBMS data \n"); -#endif - break; - - default: - printk("nasrg_CLASS_cx6: default multicast\n"); - *paddr_type = NAS_IPV6_ADDR_UNKNOWN; - *pmbms_ix = NASRG_MBMS_SVCES_MAX; - } - } else { - // This is not multicast, so we should be able to identify the MT - *paddr_type = NAS_IPV6_ADDR_UNICAST; - - for (cxi=*cx_index; cxicx[cxi].sclassifier[dscp]; - - while (sclassifier!=NULL) { - // verify that this is an IPv6 classifier - if ((sclassifier->version == NAS_VERSION_6) || (sclassifier->version == NAS_VERSION_DEFAULT)) { - /*LGif (IN6_IS_ADDR_UNSPECIFIED(&(sclassifier->daddr.ipv6))) { - printk("nas_CLASS_cx6: addr is null \n"); - sclassifier = sclassifier->next; - continue; - }*/ -#ifdef NAS_DEBUG_CLASS - printk("cx %d : DSCP %d %X:%X:%X:%X:%X:%X:%X:%X\n",cxi, dscp, NIP6ADDR(&(sclassifier->daddr.ipv6))); -#endif //NAS_DEBUG_CLASS - - //if ((dst = (unsigned int*)&(((struct rt6_info *)skbdst)->rt6i_gateway)) == 0){ - // LG: STRANGE - if (IN6_IS_ADDR_UNSPECIFIED(&ipv6_hdr(skb)->daddr)) { - printk("nasrg_CLASS_cx6: dst addr is null \n"); - sclassifier = sclassifier->next; - continue; - } - - nasrg_create_mask_ipv6_addr(&masked_addr, sclassifier->dplen); - // Modified MW to check only the iid6 - masked_addr.s6_addr32[0] = 0x00000000; - masked_addr.s6_addr32[1] = 0x00000000; - - if (IN6_ARE_ADDR_MASKED_EQUAL(&ipv6_hdr(skb)->daddr, &(sclassifier->daddr.ipv6), &masked_addr)) { -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_cx6: found cx %d: %X:%X:%X:%X:%X:%X:%X:%X\n",cxi, NIP6ADDR(&(sclassifier->daddr.ipv6))); -#endif //NAS_DEBUG_CLASS - return &gpriv->cx[cxi]; - } - } - - // Go to next classifier entry for connection - sclassifier = sclassifier->next; - } - } - } - } - - //printk("nas_CLASS_cx6 NOT FOUND: %X:%X:%X:%X:%X:%X:%X:%X\n",NIP6ADDR(&ipv6_hdr(skb)->daddr)); - return cx; -} - -//--------------------------------------------------------------------------- -// Search the sending function for IP Packet -void nasrg_CLASS_send(struct sk_buff *skb) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *pclassifier, *sp; - uint8_t *protocolh = NULL; - uint8_t version; - uint8_t protocol, dscp; - uint16_t classref; - struct cx_entity *cx; - unsigned int i; -#ifdef NAS_DEBUG_CLASS - char sfct[10], sprotocol[10]; -#endif - struct net_device *dev = gdev; - unsigned char cx_index,no_connection; - int addr_type; - int mbms_ix; - struct in6_addr masked6_addr; - struct in_addr masked_addr; - // RARP vars - struct arphdr *rarp; - unsigned char *rarp_ptr; - /* s for "source", t for "target" */ - __be32 sip, tip; - unsigned char *sha, *tha; - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send: begin -\n"); -#endif - - if (skb==NULL) { - printk("nasrg_CLASS_send - input parameter skb is NULL \n"); - return; - } - - //*** -#ifdef NAS_DEBUG_SEND - printk("nasrg_CLASS_send - Received IP packet to transmit, length %d\n", skb->len); -#endif -#ifdef NAS_DEBUG_SEND_DETAIL - - if ((skb->data) != NULL) { - if (skb->len<150) - nasrg_TOOL_print_buffer(skb->data,skb->len); - else - nasrg_TOOL_print_buffer(skb->data,150); - } - -#endif - //*** - // find all connections related to socket - cx_index = 0; - no_connection = 1; - cx = NULL; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send: [before switch on IP protocol version] \n"); -#endif - - - // Get mobile connexion entity, protocol and dscp from IP packet - switch (ntohs(skb->protocol)) { - case ETH_P_IPV6: -#ifdef NAS_DEBUG_CLASS_DETAIL - printk("nasrg_CLASS_send : skb->protocol : IPv6 \n"); -#endif - version = NAS_VERSION_6; - addr_type = NAS_IPV6_ADDR_UNKNOWN; - protocolh = nasrg_TOOL_get_protocol6(ipv6_hdr(skb), &protocol); - dscp = nasrg_TOOL_get_dscp6 (ipv6_hdr(skb)); - cx = nasrg_CLASS_cx6 (skb, dscp, &addr_type, &cx_index, &mbms_ix); -#ifdef NAS_DEBUG_CLASS_DETAIL - printk("nasrg_CLASS_send - ETH_P_IPV6 skb %p dscp %d gpriv %p cx_index %p \n",skb, dscp, gpriv, &cx_index); -#endif - - // find in default DSCP a valid classification - if (cx == NULL) { - switch (addr_type) { - case NAS_IPV6_ADDR_MC_SIGNALLING: - case NAS_IPV6_ADDR_UNICAST: -#ifdef NAS_DEBUG_CLASS_DETAIL - printk("nasrg_CLASS_send - case NAS_IPV6_ADDR_MC_SIGNALLING | NAS_IPV6_ADDR_UNICAST\n"); -#endif //NAS_DEBUG_CLASS - - for (i=0; icx[i])->sclassifier[NAS_DSCP_DEFAULT]; - - while (pclassifier!=NULL) { - if ((pclassifier->version == NAS_VERSION_6) || (pclassifier->version == NAS_VERSION_DEFAULT)) { - // ok found default classifier for this packet - nasrg_create_mask_ipv6_addr(&masked6_addr, pclassifier->dplen); - // Modified MW to let everything go (pb with signalling) - masked6_addr.s6_addr32[0] = 0x00000000; - masked6_addr.s6_addr32[1] = 0x00000000; -#ifdef NAS_DEBUG_CLASS_DETAIL - printk("nasrg_CLASS_send - cx %d : DSCP NAS_DSCP_DEFAULT %X:%X:%X:%X:%X:%X:%X:%X\n",i, NIP6ADDR(&(pclassifier->daddr.ipv6))); -#endif //NAS_DEBUG_CLASS - - if (IN6_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv6, &ipv6_hdr(skb)->daddr, &masked6_addr)) { - // then force dscp - cx = &gpriv->cx[i]; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send - ETH_P_IPV6 FOUND NAS_DSCP_DEFAULT with IN6_ARE_ADDR_MASKED_EQUAL(%d bits)\n",pclassifier->dplen); -#endif - dscp = NAS_DSCP_DEFAULT; - break; - } else { - if(IN6_IS_ADDR_UNSPECIFIED(&pclassifier->daddr.ipv6)) { - cx = &gpriv->cx[i]; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send - ETH_P_IPV6 FOUND NAS_DSCP_DEFAULT with IN6_IS_ADDR_UNSPECIFIED\n"); -#endif - dscp = NAS_DSCP_DEFAULT; - break; - } - } - } - - pclassifier = pclassifier->next; - } - } - - break; - - // MBMS is broken!!!! To be updated (these values will be over-ridden afterwards - case NAS_IPV6_ADDR_MC_MBMS: -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send - case NAS_IPV6_ADDR_MC_MBMS\n"); -#endif //NAS_DEBUG_CLASS - pclassifier = gpriv->mbmsclassifier[mbms_ix]; - printk("nasrg_CLASS_send: MBMS is broken!!!!\n\n\n"); - sp = gpriv->mbmsclassifier[mbms_ix]; - - if (sp!= NULL) { - classref=sp->classref; -#ifdef NAS_DEBUG_CLASS_DETAIL - printk("nasrg_CLASS_send: classifier found for multicast service %d \n", mbms_ix); -#endif - } else { - printk("nasrg_CLASS_send: No corresponding multicast bearer, so the message is dropped\n"); - return; - } - - break; - - // should have found a valid classification rule - case NAS_IPV6_ADDR_UNKNOWN: - default: - printk("nasrg_CLASS_send: No corresponding address type\n"); - } - } - - break; - - case ETH_P_ARP: -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send : skb->protocol : ARP \n"); -#endif - version = NAS_VERSION_4; - addr_type = NAS_IPV4_ADDR_BROADCAST; - dscp = 0; - cx = NULL; - // Basic sanity checks can be done without the lock - rarp = (struct arphdr *)skb_network_header(skb); - - if (rarp) { - if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) { - printk("nasrg_CLASS_send: ARP PACKET WRONG ADDR LEN or WRONG ARP HEADER TYPE\n"); - break; - } - } else { - printk("nasrg_CLASS_send: ARP HEADER POINTER IS NULL\n"); - break; - } - - // If it's not Ethernet, delete it. - if (rarp->ar_pro != htons(ETH_P_IP)) { - printk("nasrg_CLASS_send: ARP PACKET PROTOCOL IS NOT ETHERNET\n"); - break; - } - - rarp_ptr = (unsigned char *) (rarp + 1); - sha = rarp_ptr; - rarp_ptr += dev->addr_len; - memcpy(&sip, rarp_ptr, 4); - rarp_ptr += 4; - tha = rarp_ptr; - rarp_ptr += dev->addr_len; - memcpy(&tip, rarp_ptr, 4); -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send: ARP DEST IP transport IP = %d.%d.%d.%d\n",NIPADDR(tip)); -#endif - - for (i=0; icx[i])->sclassifier[NAS_DSCP_DEFAULT]; - - while (pclassifier!=NULL) { - if ((pclassifier->version == NAS_VERSION_4) || (pclassifier->version == NAS_VERSION_DEFAULT)) { - // ok found default classifier for this packet - nasrg_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen); -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send: MASK = %d.%d.%d.%d\n",NIPADDR(masked_addr.s_addr)); -#endif - - // - if (IN_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv4, &tip, &masked_addr.s_addr)) { - // then force dscp - cx = &gpriv->cx[i]; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send: ETH_P_ARP FOUND NAS_DSCP_DEFAULT with IN_ARE_ADDR_MASKED_EQUAL(%d bits)\n", pclassifier->dplen); -#endif - dscp = NAS_DSCP_DEFAULT; - break; - } else { - if (INADDR_ANY == pclassifier->daddr.ipv4) { - cx = &gpriv->cx[i]; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send: ETH_P_ARP FOUND NAS_DSCP_DEFAULT with INADDR_ANY\n"); -#endif - dscp = NAS_DSCP_DEFAULT; - break; - } - } - } - - pclassifier = pclassifier->next; - } - } - - break; - - case ETH_P_IP: -#ifdef NAS_DEBUG_CLASS_DETAIL - printk("nasrg_CLASS_send : skb->protocol : IPv4 \n"); -#endif - version = NAS_VERSION_4; - addr_type = NAS_IPV4_ADDR_UNKNOWN; - dscp = nasrg_TOOL_get_dscp4((struct iphdr *)(skb_network_header(skb))); - cx = nasrg_CLASS_cx4(skb, dscp, &addr_type, &cx_index); - protocolh = nasrg_TOOL_get_protocol4((struct iphdr *)(skb_network_header(skb)), &protocol); - - // find in default DSCP a valid classification - if (cx == NULL) { - switch (addr_type) { - case NAS_IPV4_ADDR_MC_SIGNALLING: - case NAS_IPV4_ADDR_UNICAST: - case NAS_IPV4_ADDR_BROADCAST: - for (i=0; icx[i])->sclassifier[NAS_DSCP_DEFAULT]; - - while (pclassifier != NULL) { - if ((pclassifier->version == NAS_VERSION_4) || (pclassifier->version == NAS_VERSION_DEFAULT)) { - // ok found default classifier for this packet - nasrg_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen); -#ifdef NAS_DEBUG_CLASS_DETAIL - printk("nasrg_CLASS_send : MASK = %d.%d.%d.%d\n", NIPADDR(masked_addr.s_addr)); -#endif - - if (IN_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv4, &ip_hdr(skb)->daddr, &masked_addr.s_addr)) { - // then force dscp - cx = &gpriv->cx[i]; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send : ETH_P_IP FOUND NAS_DSCP_DEFAULT with IN_ARE_ADDR_MASKED_EQUAL(%d bits)\n",pclassifier->dplen); -#endif - dscp = NAS_DSCP_DEFAULT; - break; - } else { - if(INADDR_ANY == pclassifier->daddr.ipv4) { - cx = &gpriv->cx[i]; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send : ETH_P_IP FOUND NAS_DSCP_DEFAULT with INADDR_ANY\n"); -#endif - dscp = NAS_DSCP_DEFAULT; - break; - } - } - } - - pclassifier = pclassifier->next; - } - } - - break; - - // should have found a valid classification rule - case NAS_IPV4_ADDR_UNKNOWN: - default: - printk("nasrg_CLASS_send: No corresponding address type\n"); - } - } - -#ifdef NAS_DEBUG_CLASS - - if (cx) - printk("nasrg_CLASS_send: ETH_P_IP Received IPv4 packet (%02X), dscp = %d, cx = %d\n",ntohs(skb->protocol),dscp,cx->lcr); - else - printk("nasrg_CLASS_send: ETH_P_IP Received IPv4 packet (%02X), dscp = %d, No valid connection\n",ntohs(skb->protocol),dscp); - -#endif - break; - - default: - printk("nasrg_CLASS_send: Unknown IP version protocol\n"); - version = 0; - return; - } - -#ifdef NAS_DEBUG_CLASS_DETAIL - printk("nasrg_CLASS_send: [before if (cx != NULL)]\n"); -#endif - - //Next lines bypass classifiers to test the netlink socket - //#define DEBUG_NETLINKRG_TEST -#ifdef DEBUG_NETLINKRG_TEST - nasrg_COMMON_QOS_send_test_netlink(skb); - return; -#endif - - // If a valid connection for the DSCP/EXP with destination address - // is found scan all protocol-based classification rules - if (cx != NULL) { - classref = 0; - sp = NULL; - - if (cx->state!=NAS_CX_DCH) { -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send: UE not connected, in state %d. Packet is dropped\n",cx->state); -#endif - return; - } - - if (addr_type==NAS_IPV6_ADDR_MC_MBMS) { - sp = gpriv->mbmsclassifier[mbms_ix]; - - if (sp!= NULL) { - classref=sp->classref; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send: classifier found for multicast index %d, service %d\n", mbms_ix, gpriv->mbms_rb[mbms_ix].cnxid); -#endif - } else { - // Temp MEDIEVAL : use default classifier - sp = cx->sclassifier[NAS_DSCP_DEFAULT]; - - if (sp!= NULL) { - classref=sp->classref; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_CLASS_send: classifier for multicast service %d replaced by default %d\n", mbms_ix, classref); -#endif -#ifdef NAS_AUTO_MBMS - nasrg_ASCTL_start_default_mbms_service(); -#endif - } else { - printk("nasrg_CLASS_send: No corresponding multicast bearer, so the message is dropped\n"); - return; - } - } - } else { -#ifdef NAS_DEBUG_CLASS_DETAIL - printk("nasrg_CLASS_send: DSCP %d version %d: looking for classifier entry\n",dscp, version); -#endif - - for (pclassifier=cx->sclassifier[dscp]; pclassifier!=NULL; pclassifier=pclassifier->next) { -#ifdef NAS_DEBUG_CLASS_DETAIL - printk("nasrg_CLASS_send: DSCP %d p->classref=%d,p->protocol=%d,p->version=%d\n",dscp,pclassifier->classref,pclassifier->protocol,pclassifier->version); -#endif - - // normal rule checks that network protocol version matches - if ((pclassifier->version == version) || (pclassifier->version == NAS_VERSION_DEFAULT)) { - //printk("nasrg_CLASS_send: IP version are equals\n"); - sp=pclassifier; - classref=sp->classref; -#ifdef NAS_DEBUG_CLASS_DETAIL - printk("nasrg_CLASS_send: classifier found for dscp %u \n", dscp); -#endif - break; - } - } - } - - if (sp!=NULL) { -#ifdef NAS_DEBUG_CLASS - - //char sfct[10], sprotocol[10]; - // classifier entity found. Print its parameters - if (sp->fct==nasrg_COMMON_QOS_send) - strcpy(sfct, "data xfer"); - - if (sp->fct==nasrg_CTL_send) - strcpy(sfct, "iocontrol"); - - if (sp->fct==nasrg_COMMON_del_send) - strcpy(sfct, "delete"); - - if (sp->fct==nasrg_ASCTL_DC_send_sig_data_request) - strcpy(sfct, "DC-SAP"); - - switch(protocol) { - case NAS_PROTOCOL_UDP: - strcpy(sprotocol, "udp"); - printk("udp packet\n"); - break; - - case NAS_PROTOCOL_TCP: - strcpy(sprotocol, "tcp"); - printk("tcp packet\n"); - break; - - case NAS_PROTOCOL_ICMP4: - strcpy(sprotocol, "icmp4"); - printk("icmp4 packet\n"); - break; - - case NAS_PROTOCOL_ICMP6: - strcpy(sprotocol, "icmp6"); - nasrg_TOOL_pk_icmp6((struct icmp6hdr*)protocolh); - break; - - default: - strcpy(sprotocol, "other L4"); - break; - } - - printk("nasrg_CLASS_send: (dscp %u, %s) received, (classref %u, fct %s, drb_id %u) classifier rule\n", - dscp, sprotocol, sp->classref, sfct, sp->rab_id); -#endif - - //forward packet to the correct entity - if (sp->fct!=NULL) { - sp->fct(skb, cx, sp); - } else { - printk("\n\nnasrg_CLASS_send: ERROR : CLASSIFIER FUNCTION IS NULL\n\n"); - } - - no_connection = 0; - // end : if classifier entry match found - } else { - printk("nasrg_CLASS_send: no corresponding item in the classifier list, so the message is dropped\n"); - printk("nasrg_CLASS_send: packet parameters: dscp %u, %s\n", dscp, sprotocol); - nasrg_COMMON_del_send(skb, cx, NULL); // Note MW: LG has commented this line. Why? - } - } // if connection found - -#ifdef NAS_DEBUG_CLASS - - if (no_connection == 1) { - printk("nasrg_CLASS_send: no corresponding connection, so the message is dropped\n"); - } - -#endif -#ifdef NAS_DEBUG_CLASS_DETAIL - printk("nasrg_CLASS_send: end\n"); -#endif -} diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_common.c b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_common.c deleted file mode 100644 index 6bfd77a17d..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_common.c +++ /dev/null @@ -1,628 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasrg_common.c -* \brief Common functions for OpenAirInterface CELLULAR version - RG -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#include "nasrg_variables.h" -#include "nasrg_proto.h" - -#include -#ifdef NAS_DRIVER_TYPE_ETHERNET -#include -#endif - -//--------------------------------------------------------------------------- -// Receive data from FIFO (QOS or DC) -//void nasrg_COMMON_receive(uint16_t hlen, uint16_t dlen, int sap){ -void nasrg_COMMON_receive(uint16_t bytes_read, uint16_t payload_length, void *data_buffer, int rb_id, int sap) -{ - //--------------------------------------------------------------------------- - struct sk_buff *skb; - struct ipversion *ipv; - unsigned int hard_header_len; - uint16_t *p_ether_type; - uint16_t ether_type; - -#ifdef NAS_DEBUG_RECEIVE - printk("nasrg_COMMON_receive: begin\n"); -#endif -#ifdef PDCP_USE_NETLINK - - // data_buffer is NULL if FIFOs - if (!data_buffer) { - printk("nasrg_COMMON_receive - input parameter data_buffer is NULL \n"); - return; - } - -#endif - - skb = dev_alloc_skb( payload_length + 2 ); - - if(!skb) { - printk("nasrg_COMMON_receive: low on memory\n"); - ++gpriv->stats.rx_dropped; - return; - } - - skb_reserve(skb,2); - -#ifndef PDCP_USE_NETLINK - bytes_read += rtf_get(sap, skb_put(skb, payload_length), payload_length); - - if (bytes_read != NAS_PDCPH_SIZE + payload_length) { - printk("nasrg_COMMON_receive: problem while reading rtf sap\n"); - kfree(skb->data); - dev_kfree_skb(skb); - return; - } - -#else - memcpy(skb_put(skb, payload_length), data_buffer, payload_length); - bytes_read += payload_length; -#endif - -#ifdef NAS_DEBUG_RECEIVE - printk("nasrg_COMMON_receive: received packet from PDCP, length %d\n", bytes_read); -#endif - - skb->dev = gdev; - hard_header_len = gdev->hard_header_len; - skb->mac_header = skb->data; - skb->pkt_type = PACKET_HOST; - skb->ip_summed = CHECKSUM_UNNECESSARY; - - ipv = (struct ipversion *)&(skb->data[hard_header_len]); - - switch (ipv->version) { - case 6: -#ifdef NAS_DEBUG_RECEIVE_BASIC - printk("nasrg_COMMON_receive: receive IPv6 message\n"); -#endif - skb->network_header = &skb->data[hard_header_len]; - // set protocol default value - skb->protocol = htons(ETH_P_IPV6); - // If type Ethernet, correct it -#ifdef NAS_DRIVER_TYPE_ETHERNET - skb->protocol = eth_type_trans(skb, gdev); -#endif - break; - - case 4: -#ifdef NAS_DEBUG_RECEIVE_BASIC - printk("nasrg_COMMON_receive: receive IPv4 message\n"); -#endif - -#ifdef NAS_DEBUG_RECEIVE - addr = (unsigned char *)&((struct iphdr *)&skb->data[hard_header_len])->saddr; - - if (addr) { - printk("nasrg_COMMON_receive: Source %d.%d.%d.%d\n",addr[0],addr[1],addr[2],addr[3]); - } - - addr = (unsigned char *)&((struct iphdr *)&skb->data[hard_header_len])->daddr; - - if (addr) { - printk("nasrg_COMMON_receive Dest %d.%d.%d.%d\n",addr[0],addr[1],addr[2],addr[3]); - } - - printk("nasrg_COMMON_receive protocol %d\n",((struct iphdr *)&skb->data[hard_header_len])->protocol); -#endif - - skb->network_header = &skb->data[hard_header_len]; - // set protocol default value - skb->protocol = htons(ETH_P_IP); - // If type Ethernet, correct it -#ifdef NAS_DRIVER_TYPE_ETHERNET - skb->protocol = eth_type_trans(skb, gdev); -#endif - break; - - default: - printk("nasrg_COMMON_receive: Packet is not IPv4 or IPv6 (version=%d)\n", ipv->version); - -#ifdef NAS_DRIVER_TYPE_ETHERNET -#ifdef NAS_DEBUG_RECEIVE - printk("nasrg_COMMON_receive: ether_type=%04X\n", ether_type); -#endif - skb->protocol = eth_type_trans(skb, gdev); - // minus 1(short) instead of 2(bytes) because uint16_t* - p_ether_type = (uint16_t *)&(skb->mac_header[hard_header_len-2]); - ether_type = ntohs(*p_ether_type); -#ifdef NAS_DEBUG_RECEIVE - printk("nasrg_COMMON_receive: ether_type=%04X\n", ether_type); -#endif - - switch (ether_type) { - case ETH_P_ARP: - printk("nasrg_COMMON_receive: ether_type = ETH_P_ARP\n"); - skb->protocol = htons(ETH_P_ARP); - skb->network_header = &skb->mac_header[hard_header_len]; - break; - - default: - break; - } - -#endif - } - - ++gpriv->stats.rx_packets; - gpriv->stats.rx_bytes += bytes_read; -#ifdef NAS_DEBUG_RECEIVE - printk("nasrg_COMMON_receive: forwarding packet of size %d to kernel\n",skb->len); -#endif - - netif_rx(skb); -#ifdef NAS_DEBUG_RECEIVE - printk("nasrg_COMMON_receive: end\n"); -#endif -} - -//--------------------------------------------------------------------------- -// Delete the data -void nasrg_COMMON_del_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *sp) -{ - //--------------------------------------------------------------------------- - ++gpriv->stats.tx_dropped; -} - -//--------------------------------------------------------------------------- -// Request the transfer of data (QoS SAP) -void nasrg_COMMON_QOS_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc) -{ - //--------------------------------------------------------------------------- - struct pdcp_data_req_header_t pdcph; - int bytes_wrote = 0; - - // Start debug information -#ifdef NAS_DEBUG_SEND - printk("nasrg_COMMON_QOS_send - begin \n"); -#endif - - // if (cx->state!=NAS_STATE_CONNECTED) // <--- A REVOIR - // { - // gpriv->stats.tx_dropped ++; - // printk("NAS_QOS_SEND: No connected, so message are dropped \n"); - // return; - // } - if (!skb || !gc || !cx) { - printk("nasrg_COMMON_QOS_send - input parameter skb|gc|cx is NULL \n"); - return; - } - - // End debug information - - if (gc->rb==NULL) { - gc->rb=nasrg_COMMON_search_rb(cx, gc->rab_id); - - if (gc->rb==NULL) { - ++gpriv->stats.tx_dropped; - printk("nasrg_COMMON_QOS_send: No corresponding Radio Bearer, so message is dropped, rab_id=%u \n", gc->rab_id); - return; - } - } - -#ifdef NAS_DEBUG_SEND - printk("nasrg_COMMON_QOS_send #1 :"); - printk("lcr %u, rab_id %u, rab_id %u\n", cx->lcr, (gc->rb)->rab_id, gc->rab_id); -#endif -#ifdef NAS_DEBUG_SEND_DETAIL - nasrg_TOOL_print_classifier(gc); -#endif - pdcph.data_size = skb->len; - //pdcph.rb_id = (gc->rb)->rab_id+(NAS_RB_MAX_NUM*cx->lcr); - pdcph.rb_id = ((gc->rb)->rab_id)-NAS_SIG_NUM_SRB; - pdcph.inst = 0; - -#ifdef PDCP_USE_NETLINK - bytes_wrote = nasrg_netlink_send((unsigned char *)&pdcph,NAS_PDCPH_SIZE, NASNL_DEST_PDCP); -#ifdef NAS_DEBUG_SEND_DETAIL - printk("nasrg_COMMON_QOS_send - Wrote %d bytes (header for %d byte skb) to PDCP via netlink\n", bytes_wrote,skb->len); -#endif -#else - //bytes_wrote = rtf_put(gpriv->sap[(gc->rb)->sapi], &pdcph, NAS_PDCPH_SIZE); - bytes_wrote = rtf_put(NAS2PDCP_FIFO, &pdcph, NAS_PDCPH_SIZE); -#ifdef NAS_DEBUG_SEND_DETAIL - printk("nasrg_COMMON_QOS_send - Wrote %d bytes (header for %d byte skb) to PDCP fifo\n", bytes_wrote,skb->len); -#endif -#endif //PDCP_USE_NETLINK - - if (bytes_wrote != NAS_PDCPH_SIZE) { - printk("nasrg_COMMON_QOS_send: problem while writing PDCP's header\n"); - printk("PDCP rb_id %d, SAP index %d, Wrote %d to fifo %d, Header Size %d \n", pdcph.rb_id , (gc->rb)->sapi, bytes_wrote, NAS2PDCP_FIFO, NAS_PDCPH_SIZE); - gpriv->stats.tx_dropped ++; - return; - } - -#ifdef NAS_DEBUG_SEND_DETAIL - printk("nasrg_COMMON_QOS_send #2 :"); - printk("Header bytes written : %d\n", bytes_wrote); -#endif - -#ifdef PDCP_USE_NETLINK - bytes_wrote += nasrg_netlink_send((unsigned char *)skb->data,skb->len, NASNL_DEST_PDCP); -#else - //bytes_wrote += rtf_put(gpriv->sap[(gc->rb)->sapi], skb->data, skb->len); - bytes_wrote += rtf_put(NAS2PDCP_FIFO, skb->data, skb->len); -#endif //PDCP_USE_NETLINK - - if (bytes_wrote != skb->len+NAS_PDCPH_SIZE) { - printk("nasrg_COMMON_QOS_send: problem while writing PDCP's data\n"); // congestion - printk("rb_id %d, SAP index %d, Wrote %d to fifo %d, Header Size %d \n", pdcph.rb_id , (gc->rb)->sapi, bytes_wrote, NAS2PDCP_FIFO, NAS_PDCPH_SIZE); - gpriv->stats.tx_dropped ++; - return; - } - -#ifdef NAS_DEBUG_SEND - printk("nasrg_COMMON_QOS_send #3 :"); - printk(" %d bytes written to rb_id %d, sap %d \n", bytes_wrote, pdcph.rb_id, NAS2PDCP_FIFO); -#endif - gpriv->stats.tx_bytes += skb->len; - gpriv->stats.tx_packets ++; -#ifdef NAS_DEBUG_SEND_DETAIL - printk("nasrg_COMMON_QOS_send - end \n"); -#endif -} - -//--------------------------------------------------------------------------- -// Request the transfer of data (QoS SAP) -void nasrg_COMMON_QOS_send_test_netlink(struct sk_buff *skb) -{ - //--------------------------------------------------------------------------- - struct pdcp_data_req_header_t pdcph; - int bytes_wrote = 0; - - // Start debug information -#ifdef NAS_DEBUG_SEND - printk("nasrg_COMMON_QOS_send - begin \n"); -#endif - - // if (cx->state!=NAS_STATE_CONNECTED) // <--- A REVOIR - // { - // gpriv->stats.tx_dropped ++; - // printk("NAS_QOS_SEND: No connected, so message are dropped \n"); - // return; - // } - if (!skb ) { - printk("nasrg_COMMON_QOS_send - input parameter skb|gc|cx is NULL \n"); - return; - } - - // End debug information - -#ifdef NAS_DEBUG_SEND - printk("nasrg_COMMON_QOS_send #1 :"); - // printk("lcr %u, rab_id %u, rab_id %u\n", cx->lcr, (gc->rb)->rab_id, gc->rab_id); - // nasrg_TOOL_print_classifier(gc); -#endif - pdcph.data_size = skb->len; - //pdcph.rb_id = (gc->rb)->rab_id+(NAS_RB_MAX_NUM*cx->lcr); - pdcph.rb_id = 6; - pdcph.inst = 0; - -#ifdef PDCP_USE_NETLINK - bytes_wrote = nasrg_netlink_send((unsigned char *)&pdcph,NAS_PDCPH_SIZE, NASNL_DEST_PDCP); - //printk("nasrg_COMMON_QOS_send - Wrote %d bytes (header for %d byte skb) to PDCP via netlink\n", bytes_wrote,skb->len); -#else - //bytes_wrote = rtf_put(gpriv->sap[(gc->rb)->sapi], &pdcph, NAS_PDCPH_SIZE); - bytes_wrote = rtf_put(NAS2PDCP_FIFO, &pdcph, NAS_PDCPH_SIZE); - //printk("nasrg_COMMON_QOS_send - Wrote %d bytes (header for %d byte skb) to PDCP fifo\n", bytes_wrote,skb->len); -#endif //PDCP_USE_NETLINK - - if (bytes_wrote != NAS_PDCPH_SIZE) { - printk("nasrg_COMMON_QOS_send: problem while writing PDCP's header\n"); - // printk("PDCP rb_id %d, SAP index %d, Wrote %d to fifo %d, Header Size %d \n", pdcph.rb_id , (gc->rb)->sapi, bytes_wrote, NAS2PDCP_FIFO, NAS_PDCPH_SIZE); - gpriv->stats.tx_dropped ++; - return; - } - -#ifdef NAS_DEBUG_SEND - printk("nasrg_COMMON_QOS_send #2 :"); - printk("Header bytes wrote : %d\n", bytes_wrote); -#endif - -#ifdef PDCP_USE_NETLINK - bytes_wrote += nasrg_netlink_send((unsigned char *)skb->data,skb->len, NASNL_DEST_PDCP); -#else - //bytes_wrote += rtf_put(gpriv->sap[(gc->rb)->sapi], skb->data, skb->len); - bytes_wrote += rtf_put(NAS2PDCP_FIFO, skb->data, skb->len); -#endif //PDCP_USE_NETLINK - - if (bytes_wrote != skb->len+NAS_PDCPH_SIZE) { - printk("nasrg_COMMON_QOS_send: problem while writing PDCP's data\n"); // congestion - // printk("rb_id %d, SAP index %d, Wrote %d to fifo %d, Header Size %d \n", pdcph.rb_id , (gc->rb)->sapi, bytes_wrote, NAS2PDCP_FIFO, NAS_PDCPH_SIZE); - gpriv->stats.tx_dropped ++; - return; - } - -#ifdef NAS_DEBUG_SEND - printk("nasrg_COMMON_QOS_send #3 :"); - printk(" %d bytes wrote to rb_id %d, sap %d \n", bytes_wrote, pdcph.rb_id, NAS2PDCP_FIFO); -#endif - gpriv->stats.tx_bytes += skb->len; - gpriv->stats.tx_packets ++; -#ifdef NAS_DEBUG_SEND - printk("nasrg_COMMON_QOS_send - end \n"); -#endif -} - -#ifndef PDCP_USE_NETLINK -//--------------------------------------------------------------------------- -void nasrg_COMMON_QOS_receive(struct cx_entity *cx) -{ - //--------------------------------------------------------------------------- - uint8_t sapi; - struct pdcp_data_ind_header_t pdcph; - int bytes_read = 0; - // Start debug information -#ifdef NAS_DEBUG_RECEIVE - printk("nasrg_COMMON_QOS_receive - begin \n"); -#endif - - if (!cx) { - printk("nasrg_COMMON_QOS_receive - input parameter cx is NULL \n"); - return; - } - - // End debug information - - // LG force the use of only 1 rt fifo - sapi = NAS_DRB_OUTPUT_SAPI; - - bytes_read = rtf_get(gpriv->sap[sapi], &pdcph, NAS_PDCPH_SIZE); - - while (bytes_read>0) { - if (bytes_read != NAS_PDCPH_SIZE) { - printk("nasrg_COMMON_QOS_receive: problem while reading PDCP header\n"); - return; - } - - // data_buffer is NULL because FIFO should be read directly in the skbuff (LITE has an intermediary buffer) - nasrg_COMMON_receive(NAS_PDCPH_SIZE, pdcph.data_size, NULL, pdcph->rb_id, gpriv->sap[sapi]); - // check if another frame is in the FIFO, otherwise return - bytes_read = rtf_get(gpriv->sap[sapi], &pdcph, NAS_PDCPH_SIZE); - } - -#ifdef NAS_DEBUG_RECEIVE - printk("nasrg_COMMON_QOS_receive - end \n"); -#endif -} -#else -//--------------------------------------------------------------------------- -void nasrg_COMMON_QOS_receive(struct nlmsghdr *nlh) -{ - //--------------------------------------------------------------------------- - - struct pdcp_data_ind_header_t *pdcph; - - // Start debug information -#ifdef NAS_DEBUG_RECEIVE - printk("nasrg_COMMON_QOS_receive - begin \n"); -#endif - - if (!nlh) { - printk("nasrg_COMMON_QOS_receive - input parameter nlh is NULL \n"); - return; - } - - // End debug information - pdcph = (struct pdcp_data_ind_header_t *)NLMSG_DATA(nlh); - -#ifdef NAS_DEBUG_RECEIVE - printk("nasrg_COMMON_QOS_receive - receive from PDCP, size %d, rab %d\\n", pdcph->data_size, pdcph->rb_id); -#endif //NAS_DEBUG_RECEIVE - - //void nasrg_COMMON_receive(uint16_t bytes_read, uint16_t payload_length, void *data_buffer, int rb_id, int sap); - nasrg_COMMON_receive(NAS_PDCPH_SIZE + pdcph->data_size, pdcph->data_size, (unsigned char *)NLMSG_DATA(nlh) + NAS_PDCPH_SIZE, pdcph->rb_id, 0); -} -#endif //PDCP_USE_NETLINK - -//--------------------------------------------------------------------------- -struct cx_entity *nasrg_COMMON_search_cx(nasLocalConnectionRef_t lcr) -{ - //--------------------------------------------------------------------------- -#ifdef NAS_DEBUG_CLASS - printk("nasrg_COMMON_search_cx - lcr %d\n",lcr); -#endif - - if (lcrcx+lcr; - else - return NULL; -} - -//--------------------------------------------------------------------------- -// Search a Radio Bearer -struct rb_entity *nasrg_COMMON_search_rb(struct cx_entity *cx, nasRadioBearerId_t rab_id) -{ - //--------------------------------------------------------------------------- - struct rb_entity *rb; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_COMMON_search_rb - rab_id %d\n", rab_id); -#endif - - if (cx==NULL) { - printk("nasrg_COMMON_search_rb - input parameter cx is NULL \n"); - return NULL; - } - - for (rb=cx->rb; rb!=NULL; rb=rb->next) { - if (rb->rab_id==rab_id) - return rb; - } - - return NULL; -} - -//--------------------------------------------------------------------------- -struct rb_entity *nasrg_COMMON_add_rb(struct cx_entity *cx, nasRadioBearerId_t rab_id, nasQoSTrafficClass_t qos) -{ - //--------------------------------------------------------------------------- - struct rb_entity *rb; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_COMMON_add_rb - begin for rab_id %d , qos %d\n", rab_id, qos ); -#endif - - if (cx==NULL) { - printk("nasrg_COMMON_add_rb - input parameter cx is NULL \n"); - return NULL; - } - - rb=nasrg_COMMON_search_rb(cx, rab_id); - - if (rb==NULL) { - rb=(struct rb_entity *)kmalloc(sizeof(struct rb_entity), GFP_KERNEL); - - if (rb!=NULL) { - rb->retry=0; - rb->countimer=NAS_TIMER_IDLE; - rb->rab_id=rab_id; - // rb->rab_id=rab_id+(32*cx->lcr); -#ifdef NAS_DEBUG_DC - printk("nasrg_COMMON_add_rb: rb rab_id=%u, rab_id=%u, mt_id=%u\n",rb->rab_id,rab_id, cx->lcr); -#endif - // rb->dscp = NASRG_TEMP_2NDRAB_DSCP; //TEMP - rb->qos=qos; - rb->sapi=NAS_DRB_INPUT_SAPI; - // LG force the use of only one rt-fifo - // rb->sapi=NAS_BA_INPUT_SAPI; - rb->state=NAS_IDLE; - rb->next=cx->rb; - cx->rb=rb; - (cx->num_rb)++; - } else - printk("nasrg_COMMON_add_rb: no memory\n"); - } - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_COMMON_add_rb - end \n" ); -#endif - return rb; -} - -//--------------------------------------------------------------------------- -// free the memory that has previously been allocated to rb and remove from linked list -void nasrg_COMMON_del_rb(struct cx_entity *cx, nasRadioBearerId_t rab_id, nasIPdscp_t dscp) -{ - //--------------------------------------------------------------------------- - struct rb_entity *rb, *curr_rb, *prev_rb; - struct classifier_entity *p; - uint16_t classref=0; - - // Start debug information -#ifdef NAS_DEBUG_CLASS - printk("nasrg_COMMON_del_rb - begin\n"); -#endif - - if (cx==NULL) { - printk("nasrg_COMMON_del_rb - input parameter cx is NULL \n"); - return; - } - - // End debug information - - // Clear the associated classifier - for (p=cx->sclassifier[dscp]; p!=NULL; p=p->next) { - if (p->classref>=classref) { - classref=p->classref; -#ifdef NAS_DEBUG_CLASS - printk("nasrg_COMMON_del_rb: classifier found for dscp %u \n", dscp); -#endif - } - } - - nasrg_CLASS_del_sclassifier(cx, dscp, classref); - - // Now, delete the RB - curr_rb = NULL; - prev_rb = NULL; - - for (rb=cx->rb; rb!=NULL; rb=rb->next) { - if (rb->rab_id == rab_id) { - curr_rb = rb; - - if (prev_rb!=NULL) { - prev_rb->next = rb->next; - } else { - cx->rb=rb->next; - } - - break; - } else { - prev_rb = rb; - } - } - - if (curr_rb!= NULL) { - printk("nasrg_COMMON_del_rb: del rab_id %u\n", rb->rab_id); - kfree(rb); - (cx->num_rb)--; - } else { - printk("\n\n--nasrg_COMMON_del_rb: ERROR, invalid rab_id %u\n", rb->rab_id); - } - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_COMMON_del_rb - end\n"); -#endif -} - -//--------------------------------------------------------------------------- -void nasrg_COMMON_flush_rb(struct cx_entity *cx) -{ - //--------------------------------------------------------------------------- - struct rb_entity *rb; - struct classifier_entity *gc; - uint8_t dscp; - - // Start debug information -#ifdef NAS_DEBUG_CLASS - printk("nasrg_COMMON_flush_rb - begin\n"); -#endif - - if (cx==NULL) { - printk("nasrg_COMMON_flush_rb - input parameter cx is NULL \n"); - return; - } - - // End debug information - for (rb=cx->rb; rb!=NULL; rb=cx->rb) { - printk("nasrg_COMMON_flush_rb: del rab_id %u\n", rb->rab_id); - cx->rb=rb->next; - kfree(rb); - } - - cx->num_rb=0; - cx->rb=NULL; - - for(dscp=0; dscpsclassifier[dscp]; gc!=NULL; gc=gc->next) - gc->rb=NULL; - } - -#ifdef NAS_DEBUG_CLASS - printk("nasrg_COMMON_flush_rb - end\n"); -#endif -} diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_constant.h b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_constant.h deleted file mode 100644 index 7a0e69cc48..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_constant.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasrg_constant.h -* \brief Defines all constants for OpenAirInterface CELLULAR version - RG -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#ifndef _NASRGD_CST -#define _NASRGD_CST - -//Debug flags -#define NAS_DEBUG_DC -//#define NAS_DEBUG_DC_DETAIL -#define NAS_DEBUG_SEND -//#define NAS_DEBUG_SEND_DETAIL // detail of packet transmission -//#define NAS_DEBUG_RECEIVE -#define NAS_DEBUG_RECEIVE_BASIC -#define NAS_DEBUG_CLASS -//#define NAS_DEBUG_CLASS_DETAIL -#define NAS_DEBUG_GC -//#define NAS_DEBUG_DC_MEASURE -//#define NAS_DEBUG_TIMER -#define NAS_DEBUG_DEVICE -//#define NAS_DEBUG_INTERRUPT -//#define NAS_DEBUG_TOOL -//#define NAS_DEBUG_MBMS_PROT //Only one RT-FIFO is used -#define NETLINK_DEBUG -#define NAS_DEBUG_RRCNL // RRC netlink socket - -// Other flags -#define DEMO_3GSM -//#define NODE_RG -//#define NAS_AUTO_MBMS - -// Begin default RAB -// Parameters for the default RAB started after network attachment (needs DEMO_3GSM defined) -// RBId value to be synchronized with RAL-RG -#define NASRG_DEFAULTRAB_RBID 6 //MW-01/01/07- RBID 5 => MBMS, 6 => DEFAULTRAB, 7+ => others -// Only one of next lines must be active - other values in l3/rrc/rrc_qos.h -#define NASRG_DEFAULTRAB_QoS 2 //MW-01/01/07- RRC_QOS_CONV_64_64 -//#define NASRG_DEFAULTRAB_QoS 3 //MW-01/01/07- RRC_QOS_CONV_128_128 -//#define NASRG_DEFAULTRAB_QoS 4 //MW-01/01/07- RRC_QOS_CONV_256_256 -//#define NASRG_DEFAULTRAB_QoS 5 //MW-01/01/07- RRC_QOS_CONV_320_320 -//#define NASRG_DEFAULTRAB_QoS 11 //LG RRC_QOS_INTER_128_64 -// -#define NASRG_DEFAULTRAB_CLASSREF 1 //MW-01/01/07 -#define NASRG_DEFAULTRAB_DSCP 0 //MW-01/01/07 -#define NASRG_DEFAULTRAB_IPVERSION NAS_VERSION_DEFAULT //MW-01/01/07 -// End default RAB - -//Temp - hard coded -#define NASRG_OWN_CELLID 5 -#define NASRG_TEMP_2NDRAB_DSCP 5 -#define NASRG_TEMP_MBMS_SESSION_ID 1 -#define NASRG_TEMP_MBMS_DURATION 999 -#define NAS_DEFAULT_IPv6_PREFIX_LENGTH 128 // used to compare destination address with MT's - -// General Constants -#define NAS_MTU 1500 -#define NAS_TX_QUEUE_LEN 100 -#define NAS_ADDR_LEN 8 -#define NAS_INET6_ADDRSTRLEN 46 -#define NAS_INET_ADDRSTRLEN 16 - -#define NAS_RESET_RX_FLAGS 0 - -#define NAS_CX_MAX 3 //Identical to RRC constant -//#define NAS_CX_MULTICAST_ALLNODE 2 - -#define NASRG_MBMS_SVCES_MAX 4 // Identical to RRC constant - -#define NAS_RB_MAX_NUM 32 // maximum number of RBs per MT - 25.331 -#define NAS_RETRY_LIMIT_DEFAULT 5 - -#define NAS_MESSAGE_MAXLEN 1600 - -// UMTS -#define NAS_SIG_SRB3 3 -#define NAS_SIG_SRB4 3 // not used yet -//LTE -#define NAS_SIG_NUM_SRB 3 // number of srbs in LTE to send Rb_Id to PDCP - - -//peer-to-peer messages between NAS entities -#define NAS_CMD_OPEN_RB 1 -#define NAS_CMD_ENTER_SLEEP 2 -#define NAS_CMD_LEAVE_SLEEP 3 - -#define NAS_CX_RELEASE_UNDEF_CAUSE 1 - -// MT+RG NAS States -#define NAS_IDLE 0x01 -// Connection -#define NAS_CX_FACH 0x06 -#define NAS_CX_DCH 0x0A -#define NAS_CX_RECEIVED 0x10 -#define NAS_CX_CONNECTING 0x04 -#define NAS_CX_RELEASING 0x08 -#define NAS_CX_CONNECTING_FAILURE 0x14 -#define NAS_CX_RELEASING_FAILURE 0x18 -// Radio Bearers -#define NAS_RB_ESTABLISHING 0x24 -#define NAS_RB_RELEASING 0x28 -#define NAS_RB_ESTABLISHED 0x2A - - -#define NAS_TIMER_ESTABLISHMENT_DEFAULT 12 -#define NAS_TIMER_RELEASE_DEFAULT 2 -#define NAS_TIMER_IDLE UINT_MAX -#define NAS_TIMER_TICK HZ - -#define NAS_PDCPH_SIZE sizeof(struct pdcp_data_req_header_t) -#define NAS_IPV4_SIZE 20 -#define NAS_IPV6_SIZE 40 - -#define NAS_DIRECTION_SEND 0 -#define NAS_DIRECTION_RECEIVE 1 - -// function number -#define NAS_FCT_DEL_SEND 1 -#define NAS_FCT_QOS_SEND 2 -#define NAS_FCT_DC_SEND 3 -#define NAS_FCT_CTL_SEND 4 - -// type of IOCTL command -#define NASRG_IOCTL_RAL 0x89F0 - -// Error cause -#define NAS_ERROR_ALREADYEXIST 1 -#define NAS_ERROR_NOMEMORY 3 -#define NAS_ERROR_NOTMT 9 -#define NAS_ERROR_NOTRG 10 -#define NAS_ERROR_NOTIDLE 11 -#define NAS_ERROR_NOTCONNECTED 12 -#define NAS_ERROR_NORB 14 -#define NAS_ERROR_NOTCORRECTVALUE 32 -#define NAS_ERROR_NOTCORRECTLCR 33 -#define NAS_ERROR_NOTCORRECTDIR 34 -#define NAS_ERROR_NOTCORRECTDSCP 35 -#define NAS_ERROR_NOTCORRECTVERSION 36 -#define NAS_ERROR_NOTCORRECTRABI 37 - - -/**********************************************************/ -/* Constants related with IP protocols */ -/**********************************************************/ - -// Destination address types -#define NAS_IPV6_ADDR_UNICAST 1 -#define NAS_IPV6_ADDR_MC_SIGNALLING 2 -#define NAS_IPV6_ADDR_MC_MBMS 3 -#define NAS_IPV6_ADDR_UNKNOWN 4 - -#define NAS_IPV4_ADDR_UNICAST 5 -#define NAS_IPV4_ADDR_MC_SIGNALLING 6 -#define NAS_IPV4_ADDR_BROADCAST 7 -#define NAS_IPV4_ADDR_UNKNOWN 8 - -//#define NAS_TRAFFICCLASS_MASK __constant_htonl(0x0fc00000) Yan -#define NAS_TRAFFICCLASS_MASK __constant_htonl(0x0ff00000) - -// Network control codepoint 111000 + IP version 6 -#define NAS_FLOWINFO_NCONTROL __constant_htonl(0x6e000000) -// network control codepoint 111000 -#define NAS_DSCP_NCONTROL 56 //0x38 -// default codepoint 1000000 -#define NAS_DSCP_DEFAULT 64 -#define NAS_DSCP_MAX 65 - -#define NAS_PROTOCOL_DEFAULT 0 -#define NAS_PROTOCOL_TCP IPPROTO_TCP -#define NAS_PROTOCOL_UDP IPPROTO_UDP -#define NAS_PROTOCOL_ICMP4 IPPROTO_ICMP -#define NAS_PROTOCOL_ICMP6 IPPROTO_ICMPV6 - -#define NAS_PORT_DEFAULT __constant_htons(65535) -#define NAS_PORT_HTTP __constant_htons(80) - -#define NAS_VERSION_DEFAULT 0 -#define NAS_VERSION_4 4 -#define NAS_VERSION_6 6 //?MW - -/**********************************************************/ -/* Constants related with Netlink sockets */ -/**********************************************************/ -#define OAI_IP_DRIVER_NETLINK_ID 31 -#define NL_DEST_PID 1 - -// defined in rrc_nas_sap.h -//#define NAS_RRCNL_ID 30 -//#define NL_DEST_RRC_PID 2 - -#define NASNL_DEST_PDCP 0 -#define NASNL_DEST_RRC 1 - -#endif - - - diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_device.c b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_device.c deleted file mode 100644 index 8fe2d48e3f..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_device.c +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasmt_device.c -* \brief Networking Device Driver for OpenAirInterface CELLULAR version - RG -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#ifndef PDCP_USE_NETLINK -#ifdef RTAI -#include "rtai_posix.h" -#define RTAI_IRQ 30 //try to get this irq with RTAI -#endif // RTAI -#endif // PDCP_USE_NETLINK -//:::::::::::::::::::::::::::::::::::::::;; -#include "nasrg_variables.h" -#include "nasrg_proto.h" -//:::::::::::::::::::::::::::::::::::::::;; -//#include -#include -#include -#include -#include -#ifdef NAS_DRIVER_TYPE_ETHERNET -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef NAS_DRIVER_TYPE_ETHERNET -#include -#endif -//:::::::::::::::::::::::::::::::::::::::;; -/* Global variables */ -struct net_device *gdev; -struct nas_priv *gpriv; -//int bytes_wrote; -//int bytes_read; -uint8_t NAS_RG_IMEI[14]= {0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x01}; -uint8_t NAS_NULL_IMEI[14]= {0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00}; - -uint16_t local_rg_cell_id; - -#ifdef PDCP_USE_NETLINK -extern void nasrg_netlink_release(void); -extern int nasrg_netlink_init(void); -#endif -extern void nasrg_ASCTL_timer(unsigned long data); - -#ifndef PDCP_USE_NETLINK -//--------------------------------------------------------------------------- -void *nasrg_interrupt(void) -{ - //--------------------------------------------------------------------------- - uint8_t cxi; -#ifdef NAS_DEBUG_INTERRUPT - printk("nasrg_interrupt - begin\n"); -#endif - - //spin_lock(&gpriv->lock); - for (cxi=0; cxicx+cxi); - - for (cxi=0; cxicx+cxi); - - //spin_unlock(&gpriv->lock); -#ifdef NAS_DEBUG_INTERRUPT - printk("nasrg_interrupt: end\n"); -#endif - // return 0; -} -#endif //NETLINK - -//--------------------------------------------------------------------------- -// Called by ifconfig when the device is activated by ifconfig -int nasrg_open(struct net_device *dev) -{ - //--------------------------------------------------------------------------- - printk("nasrg_open: begin\n"); - - gpriv=netdev_priv(dev); - - // Address has already been set at init -#ifndef PDCP_USE_NETLINK - - if (gpriv->irq==-EBUSY) { - printk("nasrg_open: irq failure\n"); - return -EBUSY; - } - -#endif //NETLINK - - if(!netif_queue_stopped(dev)) - netif_start_queue(dev); - else - netif_wake_queue(dev); - - // - init_timer(&gpriv->timer); - (gpriv->timer).expires=jiffies+NAS_TIMER_TICK; - (gpriv->timer).data=0L; - (gpriv->timer).function=nasrg_ASCTL_timer; - add_timer(&gpriv->timer); - // - printk("nasrg_open: name = %s, end\n", dev->name); - return 0; -} - -//--------------------------------------------------------------------------- -// Called by ifconfig when the device is desactivated by ifconfig -int nasrg_stop(struct net_device *dev) -{ - //--------------------------------------------------------------------------- - struct nas_priv *priv = netdev_priv(dev); - printk("nasrg_stop: begin\n"); - del_timer(&priv->timer); - netif_stop_queue(dev); - - printk("nasrg_stop: name = %s, end\n", dev->name); - return 0; -} - -//--------------------------------------------------------------------------- -void nasrg_teardown(struct net_device *dev) -{ - //--------------------------------------------------------------------------- - int cxi; -#ifndef PDCP_USE_NETLINK - struct nas_priv *priv = netdev_priv(dev); -#endif //PDCP_USE_NETLINK - - printk("nasrg_teardown: begin\n"); - - if (dev) { -#ifndef PDCP_USE_NETLINK - - if (priv->irq!=-EBUSY) { - *pt_nas_rg_irq=-1; - rt_free_srq(priv->irq); - } - -#endif //PDCP_USE_NETLINK - -#ifdef PDCP_USE_NETLINK - nasrg_netlink_release(); -#endif //PDCP_USE_NETLINK - - // for (sapi=0; sapisap[sapi]); - nasrg_CLASS_flush_rclassifier(); - nasrg_CLASS_flush_mbmsclassifier(); - - for (cxi=0; cxicx+cxi); - nasrg_CLASS_flush_sclassifier(gpriv->cx+cxi); - //for (sapi=0; sapicx[cxi].sap[sapi]); - } - } // check dev - else { - printk("nasmt_teardown: Device is null\n"); - } - - printk("nasrg_teardown: end\n"); -} - -//--------------------------------------------------------------------------- -int nasrg_set_config(struct net_device *dev, struct ifmap *map) -{ - //--------------------------------------------------------------------------- - printk("nasrg_set_config: begin\n"); - - if (dev->flags & IFF_UP) - return -EBUSY; - - if (map->base_addr != dev->base_addr) { - printk(KERN_WARNING "nasrg_set_config: Can't change I/O address\n"); - return -EOPNOTSUPP; - } - - if (map->irq != dev->irq) - dev->irq = map->irq; - - return 0; -} - -//--------------------------------------------------------------------------- -int nasrg_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_DEVICE - printk("nasrg_hard_start_xmit: begin\n"); -#endif - - if ((!skb )||(!dev)) { - printk("nasrg_hard_start_xmit - input parameter skb or dev is NULL \n"); - return -1; - } - - // End debug information - netif_stop_queue(dev); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) - netif_trans_update(dev); -#else - dev->trans_start = jiffies; -#endif -#ifdef NAS_DEBUG_SEND_DETAIL - printk("nasrg_hard_start_xmit: step 1\n"); -#endif - nasrg_CLASS_send(skb); -#ifdef NAS_DEBUG_SEND_DETAIL - printk("nasrg_hard_start_xmit: step 2\n"); -#endif - dev_kfree_skb(skb); -#ifdef NAS_DEBUG_SEND_DETAIL - printk("nasrg_hard_start_xmit: step 3\n"); -#endif - netif_wake_queue(dev); -#ifdef NAS_DEBUG_DEVICE - printk("nasrg_hard_start_xmit: end\n"); -#endif - return 0; -} - -//--------------------------------------------------------------------------- -struct net_device_stats *nasrg_get_stats(struct net_device *dev) -{ - //--------------------------------------------------------------------------- - struct nas_priv *npriv = netdev_priv(dev); - return &npriv->stats; -} - -//--------------------------------------------------------------------------- -// New function from LITE DRIVER -int nasrg_set_mac_address(struct net_device *dev, void *mac) -{ - //--------------------------------------------------------------------------- - struct sockaddr *addr = mac; - printk("nasrg_set_mac_address: begin\n"); - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - return 0; -} - -//--------------------------------------------------------------------------- -int nasrg_change_mtu(struct net_device *dev, int mtu) -{ - //--------------------------------------------------------------------------- - printk("nasrg_change_mtu: begin\n"); - - if ((mtu<50) || (mtu>1500)) - // if ((mtu<1280) || (mtu>1500)) - return -EINVAL; - - dev->mtu = mtu; - return 0; -} - -//--------------------------------------------------------------------------- -int nasrg_change_rx_flags(struct net_device *dev, int flags) -{ - //--------------------------------------------------------------------------- - //struct nas_priv *priv = netdev_priv(dev); - printk("nasrg_change_rx_flags %08X\n", flags); - gpriv->rx_flags ^= flags; - return 0; -} - -//--------------------------------------------------------------------------- -void nasrg_tx_timeout(struct net_device *dev) -{ - //--------------------------------------------------------------------------- - /* Transmitter timeout, serious problems. */ - printk("nasrg_tx_timeout: begin\n"); - // ((struct nas_priv *)(dev->priv))->stats.tx_errors++; - (gpriv->stats).tx_errors++; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) - netif_trans_update(dev); -#else - dev->trans_start = jiffies; -#endif - netif_wake_queue(dev); - printk("nasrg_tx_timeout: transmit timed out %s\n",dev->name); -} - -//--------------------------------------------------------------------------- -// Define pointers for the module -static const struct net_device_ops nasrg_netdev_ops = { - // ?? nasrg_ interrupt - // - .ndo_open = nasrg_open, - .ndo_stop = nasrg_stop, - .ndo_start_xmit = nasrg_hard_start_xmit, - .ndo_validate_addr = NULL, - .ndo_get_stats = nasrg_get_stats, - //#ifdef KERNEL_VERSION_GREATER_THAN_32 - // .ndo_set_multicast_list = NULL, - .ndo_set_mac_address = nasrg_set_mac_address, - .ndo_set_config = nasrg_set_config, - .ndo_do_ioctl = nasrg_CTL_ioctl, - .ndo_change_mtu = nasrg_change_mtu, - .ndo_tx_timeout = nasrg_tx_timeout, - .ndo_change_rx_flags = nasrg_change_rx_flags, - //#endif -}; -//--------------------------------------------------------------------------- - - -//--------------------------------------------------------------------------- -// Initialisation of the network device -void nasrg_init(struct net_device *dev) -{ - //--------------------------------------------------------------------------- - uint8_t cxi, dscpi; - - printk("nasrg_init: begin\n"); - - if (dev) { - gpriv=netdev_priv(dev); - - memset(gpriv, 0, sizeof(struct nas_priv)); - // Initialize function pointers - dev->netdev_ops = &nasrg_netdev_ops; - -#ifndef NAS_DRIVER_TYPE_ETHERNET - dev->type = ARPHRD_EURUMTS; - dev->features = NETIF_F_NO_CSUM; - dev->hard_header_len = 0; - dev->addr_len = NAS_ADDR_LEN; - dev->flags = IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP; - dev->tx_queue_len = NAS_TX_QUEUE_LEN; - dev->mtu = NAS_MTU; -#endif - // Can be one of the following enum defined in include/linux/netdevice.h: - // enum netdev_state_t { - // __LINK_STATE_START, - // __LINK_STATE_PRESENT, - // __LINK_STATE_NOCARRIER, - // __LINK_STATE_LINKWATCH_PENDING, - // __LINK_STATE_DORMANT, - // }; - set_bit(__LINK_STATE_PRESENT, &dev->state); - -#ifdef NAS_DRIVER_TYPE_ETHERNET - // overwrite values written above ( header_ops,type,hard_header_len,mtu,addr_len,tx_queue_len,flags,broadcast) - printk("\nnasrg_init: WARNING Driver type ETHERNET\n"); - ether_setup(dev); -#endif - // - // Initialize private structure - gpriv->rx_flags = NAS_RESET_RX_FLAGS; - - gpriv->sap[NAS_GC_SAPI] = RRC_DEVICE_GC; - gpriv->sap[NAS_NT_SAPI] = RRC_DEVICE_NT; - gpriv->cx[0].sap[NAS_DC_INPUT_SAPI] = RRC_DEVICE_DC_INPUT0; - gpriv->cx[0].sap[NAS_DC_OUTPUT_SAPI] = RRC_DEVICE_DC_OUTPUT0; - gpriv->cx[1].sap[NAS_DC_INPUT_SAPI] = RRC_DEVICE_DC_INPUT1; - gpriv->cx[1].sap[NAS_DC_OUTPUT_SAPI] = RRC_DEVICE_DC_OUTPUT1; - // gpriv->sap[NAS_CO_INPUT_SAPI] = QOS_DEVICE_CONVERSATIONAL_INPUT; - // gpriv->sap[NAS_CO_OUTPUT_SAPI] = QOS_DEVICE_CONVERSATIONAL_OUTPUT; - gpriv->sap[NAS_DRB_INPUT_SAPI] = PDCP2PDCP_USE_RT_FIFO;//QOS_DEVICE_CONVERSATIONAL_INPUT; - gpriv->sap[NAS_DRB_OUTPUT_SAPI] = NAS2PDCP_FIFO;//QOS_DEVICE_STREAMING_INPUT; - // - gpriv->retry_limit=NAS_RETRY_LIMIT_DEFAULT; - gpriv->timer_establishment=NAS_TIMER_ESTABLISHMENT_DEFAULT; - gpriv->timer_release=NAS_TIMER_RELEASE_DEFAULT; - - for (dscpi=0; dscpirclassifier[dscpi]=NULL; - - gpriv->nrclassifier=0; - - // - for(cxi=0; cxicx[cxi].state=NAS_IDLE; - gpriv->cx[cxi].countimer=NAS_TIMER_IDLE; - gpriv->cx[cxi].retry=0; - gpriv->cx[cxi].lcr=cxi; - gpriv->cx[cxi].rb=NULL; - gpriv->cx[cxi].num_rb=0; - - // initialisation of the classifier - for (dscpi=0; dscpicx[cxi].sclassifier[dscpi]=NULL; - - gpriv->cx[cxi].nsclassifier=0; - // initialisation of the IP address - nasrg_TOOL_imei2iid(NAS_NULL_IMEI, (uint8_t *)gpriv->cx[cxi].iid6); - gpriv->cx[cxi].iid4=0; - } - - spin_lock_init(&gpriv->lock); - - nasrg_TOOL_RGimei2iid(NAS_RG_IMEI, dev->dev_addr);// IMEI to device address (for stateless autoconfiguration address) - printk("nasrg_init: init IMEI to IID\n"); - nasrg_ASCTL_init(); - } else { - printk("\n\nnasmt_init: ERROR, Device is NULL!!\n"); - } - - printk("nasrg_init: end\n"); - return ; -} - -//--------------------------------------------------------------------------- -int init_module (void) -{ - //--------------------------------------------------------------------------- - int err; - int inst = 0; - struct nas_priv *priv; - char devicename[100]; - - printk("\n\n\n\nnasrg_init_module: begin \n"); - - // Initialize parameters shared with RRC -#ifndef PDCP_USE_NETLINK - - if (pt_nas_rg_irq==NULL) { - printk("nasrg_init_module: shared irq parameter not initialised\n"); - err = -EBUSY; - printk("nasrg_init_module: returning %d \n\n", err); - return err; - } - - printk("nasrg_init_module: pt_nas_rg_irq valid \n"); -#endif - - /* - if (pt_rg_own_cell_id==NULL){ - printk("nasrg_init_module: shared cell_id parameter not initialised\n"); - err = -EBUSY; - printk("nasrg_init_module: returning %d \n\n\n", err); - return err; - } - printk("nasrg_init_module: pt_rg_own_cell_id valid \n"); - *pt_rg_own_cell_id = NASRG_OWN_CELLID; - */ - local_rg_cell_id = NASRG_OWN_CELLID; - - // Allocate device structure - sprintf(devicename,"oai%d",inst); -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) - gdev = alloc_netdev(sizeof(struct nas_priv), devicename, nasrg_init); -#else - gdev = alloc_netdev(sizeof(struct nas_priv), devicename, NET_NAME_PREDICTABLE, nasrg_init); -#endif - printk("nasrg_init_module: after alloc_netdev \n"); - priv = netdev_priv(gdev); - //// - // -#ifndef PDCP_USE_NETLINK - priv->irq=rt_request_srq(0, nasrg_interrupt, NULL); - - if (priv->irq == -EBUSY || priv->irq == -EINVAL) { - printk("nasrg_init_module: No interrupt resource available\n"); - - if (gdev) { - free_netdev(gdev); - printk("nasrg_init_module: free_netdev ..\n"); - } - - return -EBUSY; - } else - printk("nasrg_init_module: Interrupt %d, ret = %d \n", priv->irq , ret); - - if (pt_nas_rg_irq==NULL) { - printk("nasmt_init_module: shared irq parameter has been reset\n"); - } else { - *pt_nas_rg_irq=priv->irq; - } - -#endif - // - ////// -#ifdef PDCP_USE_NETLINK - - if ((err=nasrg_netlink_init()) < 0) - printk("nasrg_init_module: NETLINK failed\n"); - - printk("nasrg_init_module: NETLINK INIT successful\n"); -#endif //NETLINK - - err= register_netdev(gdev); - - if (err) { - printk("nasrg_init_module: error %i registering device %s\n", err, gdev->name); - } else { - printk("nasrg_init_module: registering device %s, ifindex = %d\n\n",gdev->name, gdev->ifindex); - } - - return err; -} - -//--------------------------------------------------------------------------- -void cleanup_module(void) -{ - //--------------------------------------------------------------------------- - printk("nasrg_cleanup_module: begin\n"); - unregister_netdev(gdev); - nasrg_teardown(gdev); - free_netdev(gdev); - printk("nasrg_cleanup_module: end\n\n\n\n"); -} - -//--------------------------------------------------------------------------- -// Replaced by init_module and cleanup_module -//module_init (nasrg_init_module); -//module_exit (nasrg_cleanup_module); -//--------------------------------------------------------------------------- - -#define DRV_NAME "oai_nasrg" -#define DRV_VERSION "3.0.1"DRV_NAME -#define DRV_DESCRIPTION "OPENAIR CELLULAR LTE NASRG (eNodeB) Device Driver" -#define DRV_COPYRIGHT "-Copyright(c) GNU GPL Eurecom 2013" -#define DRV_AUTHOR "Michelle Wetterwald "DRV_COPYRIGHT - -// MODULE_LICENSE("GPL"); -// MODULE_DESCRIPTION("LTE Driver for eNodeB, playing as Non Access Stratum"); -// MODULE_AUTHOR("Michelle Wetterwald "); diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.c b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.c deleted file mode 100644 index 3c8f5d3cc6..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.c +++ /dev/null @@ -1,906 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasrg_iocontrol.c -* \brief I/O control functions for upper layers of driver for OpenAirInterface CELLULAR version - RG -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#include "nasrg_variables.h" -#include "nasrg_iocontrol.h" -#include "nasrg_proto.h" - -//#include -#include -#include -#include - -// Statistic -/////////////////////////////////////////////////////////////////////////////// - -//--------------------------------------------------------------------------- -void nasrg_set_msg_statistic_reply(struct nas_msg_statistic_reply *msgrep) -{ - //--------------------------------------------------------------------------- - msgrep->rx_packets=gpriv->stats.rx_packets; - msgrep->tx_packets=gpriv->stats.tx_packets; - msgrep->rx_bytes=gpriv->stats.rx_bytes; - msgrep->tx_bytes=gpriv->stats.tx_bytes; - msgrep->rx_errors=gpriv->stats.rx_errors; - msgrep->tx_errors=gpriv->stats.tx_errors; - msgrep->rx_dropped=gpriv->stats.rx_dropped; - msgrep->tx_dropped=gpriv->stats.tx_dropped; -} - -//--------------------------------------------------------------------------- -int nasrg_ioCTL_statistic_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_statistic_reply msgrep; - printk("nasrg_ioCTL_statistic: stat requested\n"); - nasrg_set_msg_statistic_reply(&msgrep); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasrg_ioCTL_statistic: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - - -/////////////////////////////////////////////////////////////////////////////// -// Connections List -//--------------------------------------------------------------------------- -void nasrg_set_msg_cx_list_reply(uint8_t *msgrep) -{ - //--------------------------------------------------------------------------- - struct cx_entity *cx; - nasLocalConnectionRef_t lcr; - struct nas_msg_cx_list_reply *list; - msgrep[0]=NAS_CX_MAX; - list=(struct nas_msg_cx_list_reply *)(msgrep+1); - - for(lcr=0; lcrstate; - list[lcr].cellid=cx->cellid; - list[lcr].iid4=cx->iid4; - list[lcr].iid6[0]=cx->iid6[0]; - list[lcr].iid6[1]=cx->iid6[1]; - list[lcr].num_rb=cx->num_rb; - list[lcr].nsclassifier=cx->nsclassifier; - printk("nasrg_set_msg_cx_list: nsc=%u\n",cx->nsclassifier); - } -} - -//--------------------------------------------------------------------------- -int nasrg_ioCTL_cx_list_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - uint8_t msgrep[NAS_CX_MAX*sizeof(struct nas_msg_cx_list_reply)+1]; - printk("nasrg_ioCTL_cx_list: connection list requested\n"); - nasrg_set_msg_cx_list_reply(msgrep); - - if (copy_to_user(gifr->msg, msgrep, NAS_CX_MAX*sizeof(struct nas_msg_cx_list_reply)+1)) { - printk("nasrg_ioCTL_cx_list: copy_to_user failure\n"); - return -EFAULT; - } - - printk("nasrg_ioCTL_cx_list: end\n"); - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Connection Establishment -//--------------------------------------------------------------------------- -void nasrg_set_msg_cx_establishment_reply(struct nas_msg_cx_establishment_reply *msgrep, struct nas_msg_cx_establishment_request *msgreq) -{ - //--------------------------------------------------------------------------- - msgrep->status=-NAS_ERROR_NOTMT; -} -//--------------------------------------------------------------------------- -int nasrg_ioCTL_cx_establishment_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_cx_establishment_request msgreq; - struct nas_msg_cx_establishment_reply msgrep; - printk("nasrg_ioCTL_cx_establishment: connection establishment requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasrg_ioCTL_cx_establishment: copy_from_user failure\n"); - return -EFAULT; - } - - nasrg_set_msg_cx_establishment_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasrg_ioCTL_cx_establishment: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Connection Release -//--------------------------------------------------------------------------- -void nasrg_set_msg_cx_release_reply(struct nas_msg_cx_release_reply *msgrep, struct nas_msg_cx_release_request *msgreq) -{ - //--------------------------------------------------------------------------- - msgrep->status=-NAS_ERROR_NOTMT; -} - -//--------------------------------------------------------------------------- -// Request the release of a connection -int nasrg_ioCTL_cx_release_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_cx_release_request msgreq; - struct nas_msg_cx_release_reply msgrep; - - printk("nasrg_set_msg_cx_release: connection release requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasrg_set_msg_cx_release: copy_from_user failure\n"); - return -EFAULT; - } - - nasrg_set_msg_cx_release_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasrg_set_msg_cx_release: copy_to_user failure\n"); - return -EFAULT; - } - - printk("nasrg_set_msg_cx_release: end\n"); - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Radio Bearer List -//--------------------------------------------------------------------------- -void nasrg_set_msg_rb_list_reply(uint8_t *msgrep, struct nas_msg_rb_list_request *msgreq) -{ - //--------------------------------------------------------------------------- - struct cx_entity *cx; - cx=nasrg_COMMON_search_cx(msgreq->lcr); - - if (cx!=NULL) { - uint8_t rbi; - struct rb_entity *rb; - struct nas_msg_rb_list_reply *list; - - if (cx->num_rb > NAS_LIST_RB_MAX) - msgrep[0] = NAS_LIST_RB_MAX; - else - msgrep[0] = cx->num_rb; - - list=(struct nas_msg_rb_list_reply *)(msgrep+1); - - // list all radio bearers - for (rb=cx->rb, rbi=0; (rb!=NULL)&&(rbinext, ++rbi) { - list[rbi].state=rb->state; - list[rbi].rab_id=rb->rab_id; - list[rbi].sapi=rb->sapi; - list[rbi].qos=rb->qos; - list[rbi].cnxid=rb->cnxid; - } - - // check if mt0 requested and multicast bearer started, then add it to the list - if ((msgreq->lcr==0)&&(gpriv->mbms_rb[0].mbms_rbId!=0)) { - printk("MT %d, MBMS bearer rb_id %d\n", msgreq->lcr, gpriv->mbms_rb[0].mbms_rbId); - //++rbi; - ++msgrep[0]; - list[rbi].state=gpriv->mbms_rb[0].state; - list[rbi].rab_id=gpriv->mbms_rb[0].mbms_rbId; - list[rbi].sapi=gpriv->mbms_rb[0].sapi; - list[rbi].qos=gpriv->mbms_rb[0].qos; - list[rbi].cnxid=gpriv->mbms_rb[0].cnxid; - printk("rab_id cnxid Sapi QoS State\n"); - printk("%u %u %u %u ", list[rbi].rab_id,list[rbi].cnxid, list[rbi].sapi, list[rbi].qos); - nasrg_TOOL_print_state(list[rbi].state); - printk("\n"); - } - } else - msgrep[0]=0; -} - -//--------------------------------------------------------------------------- -int nasrg_ioCTL_rb_list_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - uint8_t msgrep[NAS_LIST_RB_MAX*sizeof(struct nas_msg_rb_list_reply)+1]; - struct nas_msg_rb_list_request msgreq; - printk("nasrg_ioCTL_rb_list: Radio Bearer list requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasrg_ioCTL_rb_list: copy_from_user failure\n"); - return -EFAULT; - } - - nasrg_set_msg_rb_list_reply(msgrep, &msgreq); - - if (copy_to_user(gifr->msg, msgrep, NAS_LIST_RB_MAX*sizeof(struct nas_msg_rb_list_reply)+1)) { - printk("nasrg_ioCTL_rb_list: copy_to_user failure\n"); - return -EFAULT; - } - - printk("nasrg_ioCTL_rb_list: end\n"); - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Radio Bearer Establishment -//--------------------------------------------------------------------------- -void nasrg_set_msg_rb_establishment_reply(struct nas_msg_rb_establishment_reply *msgrep, struct nas_msg_rb_establishment_request *msgreq) -{ - //--------------------------------------------------------------------------- - if ((msgreq->rab_id<5)||(msgreq->rab_id>(NAS_RB_MAX_NUM-1))) - msgrep->status=-NAS_ERROR_NOTCORRECTRABI; - else { - struct cx_entity *cx; - cx=nasrg_COMMON_search_cx(msgreq->lcr); - - if (cx!=NULL) { //not multicast - struct rb_entity *rb; - rb=nasrg_COMMON_add_rb(cx, msgreq->rab_id, msgreq->qos); - - if (rb!=NULL) { - rb->cnxid = msgreq->cnxid; - rb->dscp = msgreq->dscp_dl; - rb->dscp_ul = msgreq->dscp_ul; - msgrep->status=nasrg_ASCTL_DC_send_rb_establish_request(cx, rb); - } else { - msgrep->status=-NAS_ERROR_NOMEMORY; - } - } else { //no MT found - if (msgreq->mcast_flag) { //multicast - int mbms_ix=0; // should allocate index based on Service_id /cnxid / MC IP address - // - gpriv->mbms_rb[mbms_ix].cnxid = msgreq->cnxid; - gpriv->mbms_rb[mbms_ix].serviceId = msgreq->cnxid; - gpriv->mbms_rb[mbms_ix].sessionId = NASRG_TEMP_MBMS_SESSION_ID; //Temp hard coded - gpriv->mbms_rb[mbms_ix].mbms_rbId = msgreq->rab_id; - gpriv->mbms_rb[mbms_ix].sapi = NAS_DC_INPUT_SAPI; -#ifdef NAS_DEBUG_MBMS_PROT - gpriv->mbms_rb[mbms_ix].sapi = NAS_DRB_INPUT_SAPI; //Only one RT-FIFO is used -#endif - gpriv->mbms_rb[mbms_ix].qos = msgreq->qos; - gpriv->mbms_rb[mbms_ix].dscp = msgreq->dscp_dl; - gpriv->mbms_rb[mbms_ix].duration = NASRG_TEMP_MBMS_DURATION; //Temp hard coded - memcpy ((char *)&(gpriv->mbms_rb[mbms_ix].mcast_address),(char *)&(msgreq->mcast_group), 16); - msgrep->status=nasrg_ASCTL_GC_send_mbms_bearer_establish_req(mbms_ix); - } else { - msgrep->status=-NAS_ERROR_NOTCORRECTLCR; - } - - msgrep->cnxid = msgreq->cnxid; - } - } -} - -//--------------------------------------------------------------------------- -int nasrg_ioCTL_rb_establishment_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_rb_establishment_request msgreq; - struct nas_msg_rb_establishment_reply msgrep; - printk("nasrg_ioCTL_rb_establishment: Radio bearer establishment requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasrg_ioCTL_rb_establishment: copy_from_user failure\n"); - return -EFAULT; - } - - nasrg_set_msg_rb_establishment_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasrg_ioCTL_rb_establishment: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Radio Bearer Release -//--------------------------------------------------------------------------- -void nasrg_set_msg_rb_release_reply(struct nas_msg_rb_release_reply *msgrep, struct nas_msg_rb_release_request *msgreq) -{ - //--------------------------------------------------------------------------- - if (msgreq->lcrrab_id!=NASRG_DEFAULTRAB_RBID) { - struct rb_entity *rb; - struct cx_entity *cx; - cx=nasrg_COMMON_search_cx(msgreq->lcr); - rb=nasrg_COMMON_search_rb(cx, msgreq->rab_id); - - if ((rb!=NULL)&&(cx!=NULL)) { - uint8_t dscp; - msgrep->status=nasrg_ASCTL_DC_send_rb_release_request(cx, rb); - dscp=rb->dscp; - nasrg_COMMON_del_rb(cx, msgreq->rab_id, dscp); - } else - msgrep->status=-NAS_ERROR_NOTCONNECTED; - - msgrep->cnxid = msgreq->cnxid; - } else { - msgrep->status=-NAS_ERROR_NOTCORRECTRABI; - } - } else { - if (msgreq->mcast_flag) { // multicast - int mbms_ix=0; // should search mbms_ix based on cnxid - msgrep->status=nasrg_ASCTL_GC_send_mbms_bearer_release_req(mbms_ix); - msgrep->cnxid = msgreq->cnxid; - } else { - msgrep->status=-NAS_ERROR_NOTCORRECTLCR; - } - } -} - -//--------------------------------------------------------------------------- -int nasrg_ioCTL_rb_release_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_rb_release_request msgreq; - struct nas_msg_rb_release_reply msgrep; - printk("nasrg_ioCTL_rb_release: Radio bearer release requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasrg_ioCTL_rb_release: copy_from_user failure\n"); - return -EFAULT; - } - - nasrg_set_msg_rb_release_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasrg_ioCTL_rb_release: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Classifier List -//--------------------------------------------------------------------------- -void nasrg_set_msg_class_list_reply(uint8_t *msgrep, struct nas_msg_class_list_request *msgreq) -{ - //--------------------------------------------------------------------------- - struct cx_entity *cx; - struct classifier_entity *gc; - struct nas_msg_class_list_reply *list; - uint8_t cli; - list=(struct nas_msg_class_list_reply *)(msgrep+1); - - switch(msgreq->dir) { - case NAS_DIRECTION_SEND: - cx=nasrg_COMMON_search_cx(msgreq->lcr); - - if (cx==NULL) { - msgrep[0]=0; - return; - } - - gc=cx->sclassifier[msgreq->dscp]; - break; - - case NAS_DIRECTION_RECEIVE: - cx=NULL; - gc=gpriv->rclassifier[msgreq->dscp]; - break; - - default: - cx=NULL; - msgrep[0]=0; - return; - } - - for (cli=0; (gc!=NULL)&&(clinext, ++cli) { - list[cli].classref=gc->classref; - list[cli].lcr=msgreq->lcr; - list[cli].dir=msgreq->dir; - list[cli].dscp=msgreq->dscp; - list[cli].rab_id=gc->rab_id; - list[cli].version=gc->version; - - switch(gc->version) { - case 4: - list[cli].saddr.ipv4 = gc->saddr.ipv4; - list[cli].daddr.ipv4 = gc->daddr.ipv4; - break; - - case 6: - list[cli].saddr.ipv6 = gc->saddr.ipv6; - list[cli].daddr.ipv6 = gc->daddr.ipv6; - break; - } - - list[cli].protocol=gc->protocol; - list[cli].sport=ntohs(gc->sport); - list[cli].dport=ntohs(gc->dport); - list[cli].splen=gc->splen; - list[cli].dplen=gc->dplen; - list[cli].fct=nasrg_TOOL_invfct(gc); - } - - msgrep[0]=cli; -} - -//--------------------------------------------------------------------------- -int nasrg_ioCTL_class_list_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - uint8_t msgrep[NAS_LIST_CLASS_MAX*sizeof(struct nas_msg_class_list_reply)+1]; - struct nas_msg_class_list_request msgreq; - printk("nasrg_ioCTL_class_list: classifier list requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasrg_ioCTL_class_list: copy_from_user failure\n"); - return -EFAULT; - } - - nasrg_set_msg_class_list_reply(msgrep, &msgreq); - - if (copy_to_user(gifr->msg, msgrep, NAS_LIST_CLASS_MAX*sizeof(struct nas_msg_class_list_reply)+1)) { - printk("nasrg_ioCTL_class_list: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Request the addition of a classifier rule -//--------------------------------------------------------------------------- -void nasrg_set_msg_class_add_reply(struct nas_msg_class_add_reply *msgrep, struct nas_msg_class_add_request *msgreq) -{ - //--------------------------------------------------------------------------- - struct classifier_entity *gc; - - if (msgreq->dscp>NAS_DSCP_DEFAULT) { - printk("nasrg_set_msg_class_add: Incoherent parameter value\n"); - msgrep->status=-NAS_ERROR_NOTCORRECTDSCP; - return; - } - - if (msgreq->dir==NAS_DIRECTION_SEND) { - struct cx_entity *cx; - cx=nasrg_COMMON_search_cx(msgreq->lcr); - - if (cx!=NULL) { - printk("nasrg_set_msg_class_add: DSCP %d, Classref %d\n",msgreq->dscp, msgreq->classref ); - gc=nasrg_CLASS_add_sclassifier(cx, msgreq->dscp, msgreq->classref); - printk("nasrg_set_msg_class_add: %p %p\n" , msgreq, gc); - - if (gc==NULL) { - msgrep->status=-NAS_ERROR_NOMEMORY; - return; - } - } else { - msgrep->status=-NAS_ERROR_NOTCORRECTLCR; - return; - } - - gc->rab_id=msgreq->rab_id; - gc->rb=nasrg_COMMON_search_rb(cx, gc->rab_id); - } else { - if (msgreq->dir==NAS_DIRECTION_RECEIVE) { - gc=nasrg_CLASS_add_rclassifier(msgreq->dscp, msgreq->classref); - - if (gc==NULL) { - msgrep->status=-NAS_ERROR_NOMEMORY; - return; - } - } else { - msgrep->status=-NAS_ERROR_NOTCORRECTDIR; - return; - } - } - - nasrg_TOOL_fct(gc, msgreq->fct); - gc->version=msgreq->version; - - switch(gc->version) { - case 4: - gc->saddr.ipv4=msgreq->saddr.ipv4; - gc->daddr.ipv4=msgreq->daddr.ipv4; - gc->splen=msgreq->splen; - gc->dplen=msgreq->dplen; - break; - - case 6: - gc->saddr.ipv6=msgreq->saddr.ipv6; - gc->daddr.ipv6=msgreq->daddr.ipv6; - gc->splen=msgreq->splen; - gc->dplen=msgreq->dplen; - break; - - case 0: - gc->saddr.ipv6.s6_addr32[0]=0; - gc->daddr.ipv6.s6_addr32[1]=0; - gc->saddr.ipv6.s6_addr32[2]=0; - gc->daddr.ipv6.s6_addr32[3]=0; - gc->splen=0; - gc->dplen=0; - break; - - default: - msgrep->status=-NAS_ERROR_NOTCORRECTVERSION; - kfree(gc); - return; - } - - gc->protocol=msgreq->protocol; - gc->sport=htons(msgreq->sport); - gc->dport=htons(msgreq->dport); - msgrep->status=0; -} - -//--------------------------------------------------------------------------- -int nasrg_ioCTL_class_add_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_class_add_request msgreq; - struct nas_msg_class_add_reply msgrep; - printk("nasrg_ioCTL_class_add: Add classifier components requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasrg_ioCTL_class_add: copy_from_user failure\n"); - return -EFAULT; - } - - nasrg_set_msg_class_add_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasrg_ioCTL_class_add: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// Request the deletion of a classifier rule -//--------------------------------------------------------------------------- -void nasrg_set_msg_class_del_reply(struct nas_msg_class_del_reply *msgrep, struct nas_msg_class_del_request *msgreq) -{ - //--------------------------------------------------------------------------- - if (msgreq->dscp>NAS_DSCP_DEFAULT) { - printk("nasrg_set_msg_class_del: Incoherent parameter value\n"); - msgrep->status=-NAS_ERROR_NOTCORRECTDSCP; - return; - } - - if (msgreq->dir==NAS_DIRECTION_SEND) { - struct cx_entity *cx; - cx=nasrg_COMMON_search_cx(msgreq->lcr); - - if (cx!=NULL) - nasrg_CLASS_del_sclassifier(cx, msgreq->dscp, msgreq->classref); - else { - msgrep->status=-NAS_ERROR_NOTCORRECTLCR; - return; - } - } else { - if (msgreq->dir==NAS_DIRECTION_RECEIVE) - nasrg_CLASS_del_rclassifier(msgreq->dscp, msgreq->classref); - else { - msgrep->status=-NAS_ERROR_NOTCORRECTDIR; - return; - } - } - - msgrep->status=0; -} - -//--------------------------------------------------------------------------- -int nasrg_ioCTL_class_del_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_class_del_request msgreq; - struct nas_msg_class_del_reply msgrep; - printk("nasrg_ioCTL_class_del: Del classifier components requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasrg_ioCTL_class_del: copy_from_user failure\n"); - return -EFAULT; - } - - nasrg_set_msg_class_del_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasrg_ioCTL_class_del: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// UE Multicast Join -//--------------------------------------------------------------------------- -void nasrg_set_ue_multicast_join_reply(struct nas_msg_mt_mcast_reply *msgrep, struct nas_msg_mt_mcast_join *msgreq) -{ - //--------------------------------------------------------------------------- - if (msgreq->ue_idue_id); - cx->requested_joined_services[0] = msgreq->cnxid; - msgrep->ue_id = msgreq->ue_id; - msgrep->result = nasrg_ASCTL_DC_send_mbms_ue_notify_req(cx); - msgrep->cnxid = msgreq->cnxid; - } else { - msgrep->result=-NAS_ERROR_NOTCORRECTLCR; - } -} - -//--------------------------------------------------------------------------- -int nasrg_ioCTL_ue_multicast_join_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_mt_mcast_join msgreq; - struct nas_msg_mt_mcast_reply msgrep; - printk("nasrg_ioCTL_ue_multicast_join: UE multicast join requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasrg_ioCTL_ue_multicast_join: copy_from_user failure\n"); - return -EFAULT; - } - - nasrg_set_ue_multicast_join_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasrg_ioCTL_ue_multicast_join: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// UE Multicast Leave -//--------------------------------------------------------------------------- -void nasrg_set_ue_multicast_leave_reply(struct nas_msg_mt_mcast_reply *msgrep, struct nas_msg_mt_mcast_leave *msgreq) -{ - //--------------------------------------------------------------------------- - if (msgreq->ue_idue_id); - cx->requested_left_services[0] = msgreq->cnxid; - msgrep->ue_id = msgreq->ue_id; - msgrep->result = nasrg_ASCTL_DC_send_mbms_ue_notify_req(cx); - msgrep->cnxid = msgreq->cnxid; - } else { - msgrep->result=-NAS_ERROR_NOTCORRECTLCR; - } -} - -//--------------------------------------------------------------------------- -int nasrg_ioCTL_ue_multicast_leave_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_mt_mcast_leave msgreq; - struct nas_msg_mt_mcast_reply msgrep; - printk("nasrg_ioCTL_ue_multicast_leave: UE multicast leave requested\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasrg_ioCTL_ue_multicast_leave: copy_from_user failure\n"); - return -EFAULT; - } - - nasrg_set_ue_multicast_leave_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasrg_ioCTL_ue_multicast_leave: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// ENB Measures -// Messages for triggering measurement -//--------------------------------------------------------------------------- -void nasrg_set_msg_eNBmeasure_trigger_reply(struct nas_msg_enb_measure_trigger_reply *msgrep, struct nas_msg_enb_measure_trigger *msgreq) -{ - //--------------------------------------------------------------------------- - struct cx_entity *cx; - int lcr=0; // Temp lcr->mt =0 (should be GC uplink) - - cx=nasrg_COMMON_search_cx(lcr); - - if (msgreq->cell_id != cx->cellid) - printk("\nERROR : invalid cell_id received\n\n"); - - if (nasrg_ASCTL_DC_send_eNBmeasurement_req(cx)>0) - msgrep->status = 0; - else - msgrep->status = NAS_ERROR_NOTCORRECTVALUE ; -} -//--------------------------------------------------------------------------- -int nasrg_ioCTL_eNBmeasure_trigger_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_enb_measure_trigger msgreq; - struct nas_msg_enb_measure_trigger_reply msgrep; - printk("nasrg_ioCTL_eNBmeasure_trigger_request: Measures triggered\n"); - - if (copy_from_user(&msgreq, gifr->msg, sizeof(msgreq))) { - printk("nasrg_ioCTL_eNBmeasure_trigger_request: copy_from_user failure\n"); - return -EFAULT; - } - - nasrg_set_msg_eNBmeasure_trigger_reply(&msgrep, &msgreq); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasrg_ioCTL_eNBmeasure_trigger_request: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// ENb Measurement -// Messages for Measurement retrieval -//--------------------------------------------------------------------------- -void nasrg_set_msg_eNBmeasure_retrieve_reply(struct nas_msg_enb_measure_retrieve *msgrep) -{ - //--------------------------------------------------------------------------- - int i; - - msgrep->cell_id = gpriv->measured_cell_id; - msgrep->num_UEs = gpriv->num_UEs; - - for (i=0; i num_UEs; i++) { - msgrep->measures[i].rlcBufferOccupancy = gpriv->rlcBufferOccupancy[i]; - msgrep->measures[i].scheduledPRB = gpriv->scheduledPRB[i]; - msgrep->measures[i].totalDataVolume = gpriv->totalDataVolume[i]; - //clean variables - gpriv->rlcBufferOccupancy[i] = 0; - gpriv->scheduledPRB[i] = 0; - gpriv->totalDataVolume[i] = 0; - } - - msgrep->totalNumPRBs = gpriv->totalNumPRBs; - //clean variable - gpriv->totalNumPRBs = 0; -} -//--------------------------------------------------------------------------- -int nasrg_ioCTL_eNBmeasure_retrieve_request(struct nas_ioctl *gifr) -{ - //--------------------------------------------------------------------------- - struct nas_msg_enb_measure_retrieve msgrep; - printk("nasrg_ioCTL_eNBmeasure_retrieve_request: Measurement requested\n"); - - nasrg_set_msg_eNBmeasure_retrieve_reply(&msgrep); - - if (copy_to_user(gifr->msg, &msgrep, sizeof(msgrep))) { - printk("nasrg_ioCTL_eNBmeasure_retrieve_request: copy_to_user failure\n"); - return -EFAULT; - } - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// IOCTL command -//--------------------------------------------------------------------------- -int nasrg_CTL_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - //--------------------------------------------------------------------------- - struct nas_ioctl *gifr; - int r; - printk("nasrg_CTL_ioctl: begin\n"); - spin_lock(&gpriv->lock); - - switch(cmd) { - case NASRG_IOCTL_RAL: - gifr=(struct nas_ioctl *)ifr; - - switch(gifr->type) { - case NAS_MSG_STATISTIC_REQUEST: - r=nasrg_ioCTL_statistic_request(gifr); - break; - - case NAS_MSG_CX_ESTABLISHMENT_REQUEST: - r=nasrg_ioCTL_cx_establishment_request(gifr); - break; - - case NAS_MSG_CX_RELEASE_REQUEST: - r=nasrg_ioCTL_cx_release_request(gifr); - break; - - case NAS_MSG_CX_LIST_REQUEST: - r=nasrg_ioCTL_cx_list_request(gifr); - break; - - case NAS_MSG_RB_ESTABLISHMENT_REQUEST: - r=nasrg_ioCTL_rb_establishment_request(gifr); - break; - - case NAS_MSG_RB_RELEASE_REQUEST: - r=nasrg_ioCTL_rb_release_request(gifr); - break; - - case NAS_MSG_RB_LIST_REQUEST: - r=nasrg_ioCTL_rb_list_request(gifr); - break; - - case NAS_MSG_CLASS_ADD_REQUEST: - r=nasrg_ioCTL_class_add_request(gifr); - break; - - case NAS_MSG_CLASS_LIST_REQUEST: - r=nasrg_ioCTL_class_list_request(gifr); - break; - - case NAS_MSG_CLASS_DEL_REQUEST: - r=nasrg_ioCTL_class_del_request(gifr); - break; - - case NAS_RG_MSG_MT_MCAST_JOIN: - r=nasrg_ioCTL_ue_multicast_join_request(gifr); - break; - - case NAS_RG_MSG_MT_MCAST_LEAVE: - r=nasrg_ioCTL_ue_multicast_leave_request(gifr); - break; - - case NAS_MSG_ENB_MEAS_TRIGGER: - r=nasrg_ioCTL_eNBmeasure_trigger_request(gifr); - break; - - case NAS_MSG_ENB_MEAS_RETRIEVE: - r=nasrg_ioCTL_eNBmeasure_retrieve_request(gifr); - break; - - default: - printk("nasrg_CTL_ioctl: unkwon request type, type=%x\n", gifr->type); - r=-EFAULT; - } - - break; - - default: - printk("nasrg_CTL_ioctl: Unknown ioctl command, cmd=%x\n", cmd); - r=-EFAULT; - } - - spin_unlock(&gpriv->lock); - printk("nasrg_CTL_ioctl: end\n"); - return r; -} - -//--------------------------------------------------------------------------- -void nasrg_CTL_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc) -{ - //--------------------------------------------------------------------------- - printk("nasrg_CTL_send - void \n"); -} - diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.h b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.h deleted file mode 100644 index bd7baac3b6..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_iocontrol.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasrg_iocontrol.h -* \brief I/O control constnats and structures for upper layers of driver for OpenAirInterface CELLULAR version - RG -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#ifndef NASRGD_CTL_H -#define NASRGD_CTL_H - -#include -#include -#include -#include - -#define NAS_MSG_MAXLEN 1100 - -// type of CTL message -#define NAS_MSG_STATISTIC_REQUEST 1 -#define NAS_MSG_STATISTIC_REPLY 2 -#define NAS_MSG_ECHO_REQUEST 3 -#define NAS_MSG_ECHO_REPLY 4 -#define NAS_MSG_CX_ESTABLISHMENT_REQUEST 5 -#define NAS_MSG_CX_ESTABLISHMENT_REPLY 6 -#define NAS_MSG_CX_RELEASE_REQUEST 7 -#define NAS_MSG_CX_RELEASE_REPLY 8 -#define NAS_MSG_CX_LIST_REQUEST 9 -#define NAS_MSG_CX_LIST_REPLY 10 -#define NAS_MSG_RB_ESTABLISHMENT_REQUEST 11 -#define NAS_MSG_RB_ESTABLISHMENT_REPLY 12 -#define NAS_MSG_RB_RELEASE_REQUEST 13 -#define NAS_MSG_RB_RELEASE_REPLY 14 -#define NAS_MSG_RB_LIST_REQUEST 15 -#define NAS_MSG_RB_LIST_REPLY 16 -#define NAS_MSG_CLASS_ADD_REQUEST 17 -#define NAS_MSG_CLASS_ADD_REPLY 18 -#define NAS_MSG_CLASS_DEL_REQUEST 19 -#define NAS_MSG_CLASS_DEL_REPLY 20 -#define NAS_MSG_CLASS_LIST_REQUEST 21 -#define NAS_MSG_CLASS_LIST_REPLY 22 -#define NAS_MSG_NEIGHBOUR_REQUEST 23 -#define NAS_MSG_NEIGHBOUR_REPLY 24 -//MBMS -#define NAS_RG_MSG_MT_MCAST_JOIN 30 -#define NAS_RG_MSG_MT_MCAST_LEAVE 31 -#define NAS_RG_MSG_MT_MCAST_REPLY 32 -// ENB MEASURES (MEDIEVAL DEMO 3) -#define NAS_MSG_ENB_MEAS_TRIGGER 33 -#define NAS_MSG_ENB_MEAS_RETRIEVE 34 - - -// Max number of entry of a message list -#define NAS_LIST_CX_MAX 32 -#define NAS_LIST_RB_MAX 32 -#define NAS_LIST_CLASS_MAX 32 - -typedef uint16_t nasMsgType_t; - -struct nas_ioctl { - char name[IFNAMSIZ]; - nasMsgType_t type; - char *msg; -}; - -//**** -struct nas_msg_statistic_reply { - uint32_t rx_packets; - uint32_t tx_packets; - uint32_t rx_bytes; - uint32_t tx_bytes; - uint32_t rx_errors; - uint32_t tx_errors; - uint32_t rx_dropped; - uint32_t tx_dropped; -}; - -//**** -struct nas_msg_cx_list_reply { - nasLocalConnectionRef_t lcr; // Local Connection reference - uint8_t state; - nasCellID_t cellid; // cell identification - uint32_t iid6[2]; // IPv6 interface identification - uint8_t iid4; // IPv4 interface identification - uint16_t num_rb; - uint16_t nsclassifier; -}; -//**** -struct nas_msg_cx_establishment_reply { - int status; -}; -struct nas_msg_cx_establishment_request { - nasLocalConnectionRef_t lcr; // Local Connection reference - nasCellID_t cellid; // Cell identification -}; -//**** -struct nas_msg_cx_release_reply { - int status; -}; -struct nas_msg_cx_release_request { - nasLocalConnectionRef_t lcr; // Local Connection reference -}; - -//**** -struct nas_msg_rb_list_reply { - nasRadioBearerId_t rab_id; - nasSapId_t sapi; - nasQoSTrafficClass_t qos; - uint8_t state; - uint32_t cnxid; -}; -struct nas_msg_rb_list_request { - nasLocalConnectionRef_t lcr; // Local Connection reference -}; -//**** -struct nas_msg_rb_establishment_reply { - int status; - uint32_t cnxid; -}; -struct nas_msg_rb_establishment_request { - nasLocalConnectionRef_t lcr; // Local Connection reference - nasRadioBearerId_t rab_id; - nasQoSTrafficClass_t qos; - uint16_t dscp_ul; - uint16_t dscp_dl; - uint16_t mcast_flag; - uint8_t mcast_group[16]; - uint32_t cnxid; -}; - -//**** -struct nas_msg_rb_release_reply { - int status; - uint32_t cnxid; -}; -struct nas_msg_rb_release_request { - nasLocalConnectionRef_t lcr; // Local Connection reference - nasRadioBearerId_t rab_id; - uint16_t mcast_flag; - uint32_t cnxid; -}; - -//**** -struct nas_msg_class_add_request { - nasLocalConnectionRef_t lcr; // Local Connection reference - nasRadioBearerId_t rab_id; - uint8_t dir; // direction (send or receive) - uint8_t dscp; // codepoint - uint8_t fct; - uint16_t classref; - uint8_t version; - union { - struct in6_addr ipv6; - uint32_t ipv4; - } saddr; // IP source address - uint8_t splen; // prefix length - union { - struct in6_addr ipv6; - uint32_t ipv4; - } daddr; // IP destination address - uint8_t dplen; // prefix length - uint8_t protocol; // high layer protocol type - uint16_t sport; // source port - uint16_t dport; // destination port -}; -struct nas_msg_class_add_reply { - int status; -}; -//**** -struct nas_msg_class_del_request { - nasLocalConnectionRef_t lcr; // Local Connection reference - uint8_t dir; // direction (send or receive) - uint8_t dscp; // codepoint - uint16_t classref; -}; -struct nas_msg_class_del_reply { - int status; -}; -//**** -#define nas_msg_class_list_reply nas_msg_class_add_request -struct nas_msg_class_list_request { - nasLocalConnectionRef_t lcr; // Local Connection reference - uint8_t dir; - uint8_t dscp; -}; - -//**** -struct nas_msg_neighbour_cell_list_reply { - nasCellID_t cellid; // cell identification - uint32_t iid6[4]; // IPv6 address of access router -}; - -//MBMS -//**** -struct nas_msg_mt_mcast_join { - nasLocalConnectionRef_t ue_id; - uint32_t cnxid; - nasRadioBearerId_t rab_id; -}; - -struct nas_msg_mt_mcast_leave { - nasLocalConnectionRef_t ue_id; - uint32_t cnxid; - nasRadioBearerId_t rab_id; -}; - -struct nas_msg_mt_mcast_reply { - nasLocalConnectionRef_t ue_id; - uint32_t cnxid; - int result; -}; -//**** - -//MEDIEVAL DEMO 3 -//**** -struct nas_msg_enb_measure_trigger { - nasCellID_t cell_id; -}; -struct nas_msg_enb_measure_trigger_reply { - int status; -}; - -struct nas_msg_enb_measure_retrieve { - nasCellID_t cell_id; - nasNumConnUEs_t num_UEs; - nasENbMeasures_t measures[MAX_MEASURE_UE]; - nasENbMeasure_t totalNumPRBs; -}; - - -#endif diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_netlink.c b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_netlink.c deleted file mode 100644 index d0a3516567..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_netlink.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasrg_netlink.c -* \brief Netlink socket functions for OpenAirInterface CELLULAR version - MT -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -//#include -#include -#include -#include -#include -#include -#include - -#include - -#include "nasrg_variables.h" -#include "nasrg_proto.h" - -static struct sock *nas_nl_sk = NULL; -static struct sock *nas_rrcnl_sk = NULL; - -//static int exit_netlink_thread=0; -static DEFINE_MUTEX(nasrg_mutex); - -// This can also be implemented using thread to get the data from PDCP without blocking. -//--------------------------------------------------------------------------- -// Function for transfer with PDCP (from NASLITE) -static void nasrg_nl_data_ready (struct sk_buff *skb) -{ - //--------------------------------------------------------------------------- - struct nlmsghdr *nlh = NULL; - - // Start debug information -#ifdef NETLINK_DEBUG - printk("nasrg_nl_data_ready - begin \n"); -#endif - - if (!skb) { - printk("nasrg_nl_data_ready - input parameter skb is NULL \n"); - return; - } - - // End debug information - -#ifdef NETLINK_DEBUG - printk("nasrg_nl_data_ready - Received socket from PDCP\n"); -#endif //NETLINK_DEBUG - nlh = (struct nlmsghdr *)skb->data; - nasrg_COMMON_QOS_receive(nlh); -} - -//--------------------------------------------------------------------------- -// Function for transfer with RRC -static void nasrg_rrcnl_data_ready (struct sk_buff *skb) -{ - //--------------------------------------------------------------------------- - struct nlmsghdr *nlh = NULL; - char target_sap; - uint8_t cxi; - - // Start debug information -#ifdef NAS_DEBUG_RRCNL - printk("nasrg_rrcnl_data_ready - begin \n"); -#endif - - if (!skb) { - printk("nasrg_rrcnl_data_ready - input parameter skb is NULL \n"); - return; - } - - // End debug information - - nlh = (struct nlmsghdr *)skb->data; - //pdcph = (struct pdcp_data_ind_header_t *)NLMSG_DATA(nlh); - //nasrg_TOOL_print_buffer((char *)NLMSG_DATA(nlh), 48); - - target_sap = ((char*)NLMSG_DATA(nlh))[0]; -#ifdef NAS_DEBUG_RRCNL - printk("nasrg_rrcnl_data_ready - Received on socket from RRC, SAP %d\n", target_sap); -#endif //NAS_DEBUG_RRCNL - - switch (target_sap) { - case RRC_NAS_DC0_OUT: - //printk("nasrg_rrcnl_data_ready - Calling nasrg_ASCTL_DC_receive\n"); - cxi = 0; - nasrg_ASCTL_DC_receive(gpriv->cx+cxi, &((char*)NLMSG_DATA(nlh))[1]); - break; - - case RRC_NAS_DC1_OUT: - //printk("nasrg_rrcnl_data_ready - Calling nasrg_ASCTL_DC_receive\n"); - cxi = 1; - nasrg_ASCTL_DC_receive(gpriv->cx+cxi, &((char*)NLMSG_DATA(nlh))[1]); - break; - - case RRC_NAS_DC2_OUT: - //printk("nasrg_rrcnl_data_ready - Calling nasrg_ASCTL_DC_receive\n"); - cxi = 2; - nasrg_ASCTL_DC_receive(gpriv->cx+cxi, &((char*)NLMSG_DATA(nlh))[1]); - break; - - default: - printk("nasrg_rrcnl_data_ready - Invalid SAP value received\n"); - } - -} - -//--------------------------------------------------------------------------- -int nasrg_netlink_init(void) -{ - //--------------------------------------------------------------------------- - printk("nasrg_netlink_init - begin \n"); - - nas_nl_sk = netlink_kernel_create(&init_net,OAI_IP_DRIVER_NETLINK_ID, 0, nasrg_nl_data_ready, - &nasrg_mutex, // NULL - THIS_MODULE); - - if (!nas_nl_sk) { - printk("nasrg_netlink_init - netlink_kernel_create failed for PDCP socket\n"); - // TEMP printk("nasrg_netlink_init - netlink_kernel_create failed for PDCP socket %d\n", errno); - return(-1); - } - - nas_rrcnl_sk = netlink_kernel_create(&init_net,NAS_RRCNL_ID, 0, nasrg_rrcnl_data_ready, - &nasrg_mutex, // NULL - THIS_MODULE); - - if (!nas_rrcnl_sk) { - printk("nasrg_rrcnl_init - netlink_kernel_create failed for RRC socket\n"); - return(-1); - } - - return(0); -} - -//--------------------------------------------------------------------------- -void nasrg_netlink_release(void) -{ - //--------------------------------------------------------------------------- - printk("nasrg_netlink_release - begin \n"); - - //exit_netlink_thread=1; - printk("nasrg_netlink_release - Releasing netlink sockets\n"); - - if(nas_nl_sk) { - netlink_kernel_release(nas_nl_sk); - } - - if(nas_rrcnl_sk) { - netlink_kernel_release(nas_rrcnl_sk); - } - -} - -//--------------------------------------------------------------------------- -int nasrg_netlink_send(unsigned char *data_buffer, unsigned int data_length, int destination) -{ - //--------------------------------------------------------------------------- - struct sk_buff *nl_skb; - struct nlmsghdr *nlh; - int status; - // Start debug information -#ifdef NETLINK_DEBUG - printk("nasrg_netlink_send - begin \n"); -#endif - - if (!data_buffer) { - printk("nasrg_netlink_send - ERROR - input parameter data is NULL \n"); - return(0); - } - - if (!nas_nl_sk || !nas_rrcnl_sk) { - printk("nasrg_netlink_send - ERROR - socket is NULL\n"); - return(0); - } - - // End debug information - - nl_skb = alloc_skb(NLMSG_SPACE(data_length),GFP_ATOMIC); - - if (!nl_skb) { - printk("nasrg_netlink_send - ERROR - could not allocate skbuffer\n"); - return(0); - } - - nlh = (struct nlmsghdr *)nl_skb->data; - - // printk("nasrg_netlink_send Sending %d bytes (%d)\n",data_length,NLMSG_SPACE(data_length)); - skb_put(nl_skb, NLMSG_SPACE(data_length)); - memcpy(NLMSG_DATA(nlh), data_buffer, data_length); - nlh->nlmsg_len = NLMSG_SPACE(data_length); - - nlh->nlmsg_pid = 0; /* from kernel */ - NETLINK_CB(nl_skb).pid = 0; - - // destination 0 = PDCP, 1 = RRC - if (destination== NASNL_DEST_PDCP) { -#ifdef NETLINK_DEBUG - printk("nasrg_netlink_send - Sending to PDCP - nl_skb %p, nl_sk %p, nlh %p, nlh->nlmsg_len %d\n", nl_skb, nas_nl_sk, nlh, nlh->nlmsg_len); -#ifdef NAS_DEBUG_SEND_DETAIL - nasrg_TOOL_print_buffer(NLMSG_DATA(nlh),48); -#endif -#endif //DEBUG_NETLINK - status = netlink_unicast(nas_nl_sk, nl_skb, NL_DEST_PID, MSG_DONTWAIT); - } else { -#ifdef NAS_DEBUG_RRCNL - printk("nasrg_netlink_send - Sending to RRC - nl_skb %p, nas_rrcnl_sk %p, nlh %p, nlh->nlmsg_len %d\n", nl_skb, nas_rrcnl_sk, nlh, nlh->nlmsg_len); - nasrg_TOOL_print_buffer(NLMSG_DATA(nlh),data_length); -#endif //NAS_DEBUG_RRCNL - status = netlink_unicast(nas_rrcnl_sk, nl_skb, NL_DEST_RRC_PID, MSG_DONTWAIT); - } - - if (status < 0) { - printk("nasrg_netlink_send - SEND status is %d\n",status); - return(0); - } else { -#ifdef NETLINK_DEBUG - printk("nasrg_netlink_send - SEND status is %d, data_length %d\n",status, data_length); -#endif - return data_length; - } -} - - diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_proto.h b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_proto.h deleted file mode 100644 index 9053c88a56..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_proto.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasrg_proto.h -* \brief Function prototypes for OpenAirInterface CELLULAR version - RG -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#ifndef _NASRGD_PROTO_H -#define _NASRGD_PROTO_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include - -// #include "rrc_nas_primitives.h" -// #include "protocol_vars_extern.h" -// #include "as_sap.h" -// #include "rrc_qos.h" -// #include "rrc_sap.h" - -// nasrg_netlink.c -void nasrg_netlink_release(void); -int nasrg_netlink_init(void); -int nasrg_netlink_send(unsigned char *data_buffer, unsigned int data_length, int destination); - -// nasrg_common.c -//void nasrg_COMMON_receive(uint16_t hlen, uint16_t dlength, int sap); -void nasrg_COMMON_receive(uint16_t bytes_read, uint16_t payload_length, void *data_buffer, int rb_id, int sap); - -void nasrg_COMMON_QOS_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc); -void nasrg_COMMON_QOS_send_test_netlink(struct sk_buff *skb); -void nasrg_COMMON_del_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc); -#ifndef PDCP_USE_NETLINK -void nasrg_COMMON_QOS_receive(struct cx_entity *cx); -#else -void nasrg_COMMON_QOS_receive(struct nlmsghdr *nlh); -#endif -struct rb_entity *nasrg_COMMON_add_rb(struct cx_entity *cx, nasRadioBearerId_t rabi, nasQoSTrafficClass_t qos); -struct rb_entity *nasrg_COMMON_search_rb(struct cx_entity *cx, nasRadioBearerId_t rabi); -struct cx_entity *nasrg_COMMON_search_cx(nasLocalConnectionRef_t lcr); -void nasrg_COMMON_del_rb(struct cx_entity *cx, nasRadioBearerId_t rab_id, nasIPdscp_t dscp); -void nasrg_COMMON_flush_rb(struct cx_entity *cx); - -//nasrg_ascontrol.c -void nasrg_ASCTL_init(void); -void nasrg_ASCTL_timer(unsigned long data); -void nasrg_ASCTL_DC_send_sig_data_request(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc); -//int nasrg_ASCTL_DC_receive(struct cx_entity *cx); -int nasrg_ASCTL_DC_receive(struct cx_entity *cx, char *buffer); -// -int nasrg_ASCTL_DC_send_cx_establish_confirm(struct cx_entity *cx, uint8_t response); -int nasrg_ASCTL_DC_send_rb_establish_request(struct cx_entity *cx, struct rb_entity *rb); -int nasrg_ASCTL_DC_send_rb_release_request(struct cx_entity *cx, struct rb_entity *rb); -int nasrg_ASCTL_GC_send_mbms_bearer_establish_req(int mbms_ix ); -int nasrg_ASCTL_GC_send_mbms_bearer_release_req(int mbms_ix); -int nasrg_ASCTL_DC_send_mbms_ue_notify_req(struct cx_entity *cx); -int nasrg_ASCTL_DC_send_eNBmeasurement_req(struct cx_entity *cx); - -void nasrg_ASCTL_start_default_mbms_service(void); - -// nasrg_iocontrol.c -void nasrg_CTL_send(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc); -int nasrg_CTL_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); - -// nasrg_classifier.c -void nasrg_CLASS_send(struct sk_buff *skb); -struct classifier_entity *nasrg_CLASS_add_sclassifier(struct cx_entity *cx, uint8_t dscp, uint16_t classref); -struct classifier_entity *nasrg_CLASS_add_rclassifier(uint8_t dscp, uint16_t classref); -struct classifier_entity *nasrg_CLASS_add_mbmsclassifier(int mbms_ix, uint16_t classref); -void nasrg_CLASS_del_sclassifier(struct cx_entity *cx, uint8_t dscp, uint16_t classref); -void nasrg_CLASS_del_rclassifier(uint8_t dscp, uint16_t classref); -void nasrg_CLASS_del_mbmsclassifier(int mbms_ix, uint16_t classref); -void nasrg_CLASS_flush_sclassifier(struct cx_entity *cx); -void nasrg_CLASS_flush_rclassifier(void); -void nasrg_CLASS_flush_mbmsclassifier(void); - -// nasrg_tool.c -uint8_t nasrg_TOOL_invfct(struct classifier_entity *gc); -void nasrg_TOOL_fct(struct classifier_entity *gc, uint8_t fct); -void nasrg_TOOL_imei2iid(uint8_t *imei, uint8_t *iid); -void nasrg_TOOL_RGimei2iid(uint8_t *imei, uint8_t *iid); -uint8_t nasrg_TOOL_get_dscp6(struct ipv6hdr *iph); -uint8_t nasrg_TOOL_get_dscp4(struct iphdr *iph); -uint8_t *nasrg_TOOL_get_protocol6(struct ipv6hdr *iph, uint8_t *protocol); -uint8_t *nasrg_TOOL_get_protocol4(struct iphdr *iph, uint8_t *protocol); -char *nasrg_TOOL_get_udpmsg(struct udphdr *udph); -uint16_t nasrg_TOOL_udpcksum(struct in6_addr *saddr, struct in6_addr *daddr, uint8_t proto, uint32_t udplen, void *data); -int nasrg_TOOL_network6(struct in6_addr *addr, struct in6_addr *prefix, uint8_t plen); -int nasrg_TOOL_network4(uint32_t *addr, uint32_t *prefix, uint8_t plen); - -void nasrg_TOOL_pk_icmp6(struct icmp6hdr *icmph); - -void nasrg_TOOL_pk_all(struct sk_buff *skb); -void nasrg_TOOL_pk_ipv6(struct ipv6hdr *iph); -void nasrg_TOOL_print_state(uint8_t state); -void nasrg_TOOL_print_buffer(unsigned char * buffer,int length); -void nasrg_TOOL_print_rb_entity(struct rb_entity *rb); -void nasrg_TOOL_print_classifier(struct classifier_entity *gc); - -#endif diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_sap.h b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_sap.h deleted file mode 100644 index e2835adf7d..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_sap.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasmt_sap.h -* \brief SAP constants for OpenAirInterface CELLULAR version - RG -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#ifndef _NASRGD_SAP_H -#define _NASRGD_SAP_H - - -// RT-FIFO identifiers ** must be identical to Access Stratum as_sap.h and rrc_sap.h - -#define RRC_DEVICE_GC RRC_SAPI_RG_GCSAP -#define RRC_DEVICE_NT RRC_SAPI_RG_NTSAP -#define RRC_DEVICE_DC_INPUT0 RRC_SAPI_RG_DCSAP0_IN -#define RRC_DEVICE_DC_INPUT1 RRC_SAPI_RG_DCSAP1_IN -#define RRC_DEVICE_DC_OUTPUT0 RRC_SAPI_RG_DCSAP0_OUT -#define RRC_DEVICE_DC_OUTPUT1 RRC_SAPI_RG_DCSAP1_OUT -// -//#define QOS_DEVICE_CONVERSATIONAL_INPUT QOS_SAPI_CONVERSATIONAL_INPUT_RG -//#define QOS_DEVICE_CONVERSATIONAL_OUTPUT QOS_SAPI_CONVERSATIONAL_OUTPUT_RG - -#define PDCP2PDCP_USE_RT_FIFO 21 -#define NAS2PDCP_FIFO 22 - -//FIFO indexes in control blocks -#define NAS_DC_INPUT_SAPI 0 -#define NAS_DC_OUTPUT_SAPI 1 -#define NAS_SAPI_CX_MAX 2 - -#define NAS_GC_SAPI 0 -#define NAS_NT_SAPI 1 -#define NAS_DRB_INPUT_SAPI 2 //NAS_CO_INPUT_SAPI -#define NAS_DRB_OUTPUT_SAPI 3 //NAS_CO_OUTPUT_SAPI -#define NAS_SAPI_MAX 4 - -//#define NAS_QOS_CONVERSATIONAL UMTS_TRAFFIC_CONVERSATIONAL -// - -/* Defined in RRC -#define RRC_NAS_GC_IN 0 -#define RRC_NAS_GC_OUT 1 -#define RRC_NAS_NT_IN 2 -#define RRC_NAS_NT_OUT 3 -#define RRC_NAS_DC0_IN 4 -#define RRC_NAS_DC0_OUT 5 -#define RRC_NAS_DC1_IN 6 -#define RRC_NAS_DC1_OUT 7 -#define RRC_NAS_DC2_IN 8 -#define RRC_NAS_DC2_OUT 9 -*/ -#endif - - - diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_tool.c b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_tool.c deleted file mode 100644 index 54324cf63f..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_tool.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#include "nasrg_variables.h" -#include "nasrg_proto.h" - -//--------------------------------------------------------------------------- -// -void nasrg_TOOL_fct(struct classifier_entity *gc, uint8_t fct) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasrg_TOOL_fct - begin \n"); -#endif - - if (gc==NULL) { - printk("nasrg_TOOL_fct - input parameter gc is NULL \n"); - return; - } - - // End debug information - switch(fct) { - case NAS_FCT_QOS_SEND: - gc->fct=nasrg_COMMON_QOS_send; - break; - - case NAS_FCT_CTL_SEND: - gc->fct=nasrg_CTL_send; - break; - - case NAS_FCT_DC_SEND: - gc->fct=nasrg_ASCTL_DC_send_sig_data_request; - break; - - case NAS_FCT_DEL_SEND: - gc->fct=nasrg_COMMON_del_send; - break; - - default: - gc->fct=nasrg_COMMON_del_send; - } -} - -//--------------------------------------------------------------------------- -uint8_t nasrg_TOOL_invfct(struct classifier_entity *gc) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasrg_TOOL_invfct - begin \n"); -#endif - - if (gc==NULL) { - printk("nasrg_TOOL_invfct - input parameter gc is NULL \n"); - return 0; - } - - // End debug information - if (gc->fct==nasrg_COMMON_QOS_send) - return NAS_FCT_QOS_SEND; - - if (gc->fct==nasrg_CTL_send) - return NAS_FCT_CTL_SEND; - - if (gc->fct==nasrg_COMMON_del_send) - return NAS_FCT_DEL_SEND; - - if (gc->fct==nasrg_ASCTL_DC_send_sig_data_request) - return NAS_FCT_DC_SEND; - - return 0; -} - -//--------------------------------------------------------------------------- -uint8_t nasrg_TOOL_get_dscp6(struct ipv6hdr *iph) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasrg_TOOL_get_dscp6 - begin \n"); -#endif - - if (iph==NULL) { - printk("nasrg_TOOL_get_dscp6 - input parameter iph is NULL \n"); - return 0; - } - - // End debug information - // return (ntohl(((*(__u32 *)iph)&NAS_TRAFFICCLASS_MASK)))>>22; //Yan - return (ntohl(((*(__u32 *)iph)&NAS_TRAFFICCLASS_MASK)))>>20; -} - -//--------------------------------------------------------------------------- -uint8_t nasrg_TOOL_get_dscp4(struct iphdr *iph) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasrg_TOOL_get_dscp4 - begin \n"); -#endif - - if (iph==NULL) { - printk("nasrg_TOOL_get_dscp4 - input parameter iph is NULL \n"); - return 0; - } - - // End debug information - return ((iph->tos)>>5)<<3; -} - -//--------------------------------------------------------------------------- -uint8_t *nasrg_TOOL_get_protocol6(struct ipv6hdr *iph, uint8_t *protocol) -{ - //--------------------------------------------------------------------------- - uint16_t size; - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasrg_TOOL_get_protocol6 - begin \n"); -#endif - - if (iph==NULL) { - printk("nasrg_TOOL_get_protocol6 - input parameter iph is NULL \n"); - return NULL; - } - - if (protocol==NULL) { - printk("nasrg_TOOL_get_protocol6 - input parameter protocol is NULL \n"); - return NULL; - } - - // End debug information - - *protocol=iph->nexthdr; - size=NAS_IPV6_SIZE; - - while (1) { - switch(*protocol) { - case IPPROTO_UDP: - case IPPROTO_TCP: - case IPPROTO_ICMPV6: - return (uint8_t *)((uint8_t *)iph+size); - - case IPPROTO_HOPOPTS: - case IPPROTO_ROUTING: - case IPPROTO_DSTOPTS: - *protocol=((uint8_t *)iph+size)[0]; - size+=((uint8_t *)iph+size)[1]*8+8; - break; - - case IPPROTO_FRAGMENT: - *protocol=((uint8_t *)iph+size)[0]; - size+=((uint8_t *)iph+size)[1]+8; - break; - - case IPPROTO_NONE: - case IPPROTO_AH: - case IPPROTO_ESP: - default: - return NULL; - } - } -} - -//--------------------------------------------------------------------------- -uint8_t *nasrg_TOOL_get_protocol4(struct iphdr *iph, uint8_t *protocol) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasrg_TOOL_get_protocol4 - begin \n"); -#endif - - if (iph==NULL) { - printk("nasrg_TOOL_get_protocol4 - input parameter iph is NULL \n"); - return NULL; - } - - if (protocol==NULL) { - printk("nasrg_TOOL_get_protocol4 - input parameter protocol is NULL \n"); - return NULL; - } - - // End debug information - *protocol=iph->protocol; - - switch(*protocol) { - case IPPROTO_UDP: - case IPPROTO_TCP: - case IPPROTO_ICMP: - return (uint8_t *)((uint8_t *)iph+iph->tot_len); - - default: - return NULL; - } -} - -//--------------------------------------------------------------------------- -// Convert the IMEI to iid -void nasrg_TOOL_imei2iid(uint8_t *imei, uint8_t *iid) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasrg_TOOL_imei2iid - begin \n"); -#endif - - if (imei==NULL) { - printk("nasrg_TOOL_imei2iid - input parameter imei is NULL \n"); - return; - } - - if (iid==NULL) { - printk("nasrg_TOOL_imei2iid - input parameter iid is NULL \n"); - return; - } - - // End debug information - memset(iid, 0, NAS_ADDR_LEN); - iid[0] = 0x03; -#ifdef NAS_DRIVER_TYPE_ETHERNET - iid[0] = 0x02; -#endif - iid[1] = 16*imei[0]+imei[1]; - iid[2] = 16*imei[2]+imei[3]; - iid[3] = 16*imei[4]+imei[5]; - iid[4] = 16*imei[6]+imei[7]; -#ifdef NAS_DRIVER_TYPE_ETHERNET - iid[3] = 0xff; - iid[4] = 0xfe; -#endif - iid[5] = 16*imei[8]+imei[9]; - iid[6] = 16*imei[10]+imei[11]; - iid[7] = 16*imei[12]+imei[13]; -} - -//--------------------------------------------------------------------------- -// Convert the RG IMEI to iid -void nasrg_TOOL_RGimei2iid(uint8_t *imei, uint8_t *iid) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasrg_TOOL_RGimei2iid - begin \n"); -#endif - - if (!imei || !iid) { - printk("nasrg_TOOL_RGimei2iid - input parameter imei or iid is NULL \n"); - return; - } - - // End debug information - memset(iid, 0, NAS_ADDR_LEN); - iid[0] = 0x00; // to be compatible between link local and global - iid[1] = 16*imei[0]+imei[1]; - iid[2] = 16*imei[2]+imei[3]; - iid[3] = 16*imei[4]+imei[5]; - iid[4] = 16*imei[6]+imei[7]; - iid[5] = 16*imei[8]+imei[9]; - iid[6] = 16*imei[10]+imei[11]; - iid[7] = 16*imei[12]+imei[13]; -} - -//--------------------------------------------------------------------------- -void nasrg_TOOL_pk_icmp6(struct icmp6hdr *icmph) -{ - //--------------------------------------------------------------------------- - // Start debug information -#ifdef GRAAL_DEBUG_TOOL - printk("nasrg_TOOL_pk_icmp6 - begin \n"); -#endif - - if (!icmph) { - printk("nasrg_TOOL_pk_icmp6 - input parameter icmph is NULL \n"); - return; - } - - // End debug information - printk("ICMPv6:\t type= %d, code = %d\n", icmph->icmp6_type, icmph->icmp6_code); - - switch(icmph->icmp6_type) { - case ICMPV6_DEST_UNREACH: - printk("Destination unreachable\n"); - break; - - case ICMPV6_PKT_TOOBIG: - printk("Packet too big\n"); - break; - - case ICMPV6_TIME_EXCEED: - printk("Time exceeded\n"); - break; - - case ICMPV6_PARAMPROB: - printk("Parameter problem\n"); - break; - - case ICMPV6_ECHO_REQUEST: - printk("Echo request\n"); - break; - - case ICMPV6_ECHO_REPLY: - printk("Echo reply\n"); - break; - - case ICMPV6_MGM_QUERY: - printk("Multicast listener query\n"); - break; - - case ICMPV6_MGM_REPORT: - printk("Multicast listener report\n"); - break; - - case ICMPV6_MGM_REDUCTION: - printk("Multicast listener done\n"); - break; - - case NDISC_ROUTER_SOLICITATION: - printk("Router solicitation\n"); - break; - - case NDISC_ROUTER_ADVERTISEMENT: - printk("Router advertisment\n"); - break; - - case NDISC_NEIGHBOUR_SOLICITATION: - printk("Neighbour solicitation\n"); - break; - - case NDISC_NEIGHBOUR_ADVERTISEMENT: - printk("Neighbour advertisment\n"); - break; - - case NDISC_REDIRECT: - printk("redirect message\n"); - break; - } -} - - -//--------------------------------------------------------------------------- -void nasrg_TOOL_print_state(uint8_t state) -{ - //--------------------------------------------------------------------------- - switch(state) { - case NAS_IDLE: - printk("NAS_IDLE\n"); - return; - - case NAS_CX_FACH: - printk("NAS_CX_FACH\n"); - return; - - case NAS_CX_DCH: - printk("NAS_CX_DCH\n"); - return; - - case NAS_CX_RECEIVED: - printk("NAS_CX_RECEIVED\n"); - return; - - case NAS_CX_CONNECTING: - printk("NAS_CX_CONNECTING\n"); - return; - - case NAS_CX_RELEASING: - printk("NAS_CX_RELEASING\n"); - return; - - case NAS_CX_CONNECTING_FAILURE: - printk("NAS_CX_CONNECTING_FAILURE\n"); - return; - - case NAS_CX_RELEASING_FAILURE: - printk("NAS_CX_RELEASING_FAILURE\n"); - return; - - case NAS_RB_ESTABLISHING: - printk("NAS_RB_ESTABLISHING\n"); - return; - - case NAS_RB_RELEASING: - printk("NAS_RB_RELEASING\n"); - return; - - case NAS_RB_ESTABLISHED: - printk("NAS_RB_ESTABLISHED\n"); - return; - - default: - printk(" Unknown state\n"); - } -} - -//----------------------------------------------------------------------------- -// Print the content of a buffer in hexadecimal -void nasrg_TOOL_print_buffer(unsigned char * buffer,int length) -{ - //----------------------------------------------------------------------------- - int i; - - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasrg_TOOL_print_buffer - begin \n"); -#endif - - if (buffer==NULL) { - printk("\n nasrg_TOOL_print_buffer - input parameter buffer is NULL \n"); - return; - } - - // End debug information - printk("Buffer content: "); - - for (i=0; irab_id, rb->sapi, rb->qos, rb->dscp); - printk("state %d, retry %d, countimer %d\n",rb->state, rb->retry, rb->countimer); -}; - -//----------------------------------------------------------------------------- -void nasrg_TOOL_print_classifier(struct classifier_entity *gc) -{ - //----------------------------------------------------------------------------- - // Start debug information -#ifdef NAS_DEBUG_TOOL - printk("nasrg_TOOL_print_classifier - begin \n"); -#endif - - if (gc==NULL) { - printk("\n nasrg_TOOL_print_classifier - input parameter gc is NULL \n"); - return; - } - - // End debug information - printk("\nClassifier content: classref %d, version %d, splen %d, dplen %d,\n", gc->classref, gc->version, gc->splen, gc->dplen); - printk("protocol %d, sport %d, dport %d, rab_id %d\n", gc->protocol, gc->sport, gc->dport, gc->rab_id); - nasrg_TOOL_print_rb_entity(gc->rb); -}; - - diff --git a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_variables.h b/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_variables.h deleted file mode 100644 index 7c2b69459c..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_variables.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file nasrg_variables.h -* \brief Variable and structure definitions for OpenAirInterface CELLULAR version - RG -* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier -* \company Eurecom -* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr -*/ -/*******************************************************************************/ -#ifndef _NASRGD_VAR_H -#define _NASRGD_VAR_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -#include -//#include -#include -#include -#include -#include -#include -#include - -#include "rrc_nas_primitives.h" -#include "rrc_qos_classes.h" -#include "rrc_nas_sap.h" - -#include "nasrg_constant.h" -#include "nasrg_sap.h" - -struct cx_entity; - -struct rb_entity { - // uint16_t default_rab; - uint32_t cnxid; - nasRadioBearerId_t rab_id; //ue_rbId - nasRadioBearerId_t rg_rbId; - nasRadioBearerId_t mbms_rbId; - nasSapId_t sapi; - nasQoSTrafficClass_t qos; - nasQoSTrafficClass_t RadioQosClass; - nasIPdscp_t dscp; //this is DL dscp - nasIPdscp_t dscp_ul; - uint8_t state; - uint8_t result; - uint8_t retry; - uint32_t countimer; - //for MBMS - uint16_t serviceId; - uint16_t sessionId; - uint16_t duration; - uint8_t mcast_address[16]; - // - struct rb_entity *next; -}; - -struct classifier_entity { - uint32_t classref; // classifier identity - uint8_t version; // IP version 4 or 6 - union { - struct in6_addr ipv6; - uint32_t ipv4; - } saddr; // IP source address - uint8_t splen; // IP prefix size - union { - struct in6_addr ipv6; - uint32_t ipv4; - } daddr; // IP destination address - uint8_t dplen; // IP prefix size - uint8_t protocol; // layer 4 protocol type (tcp, udp, ...) - uint16_t sport; // source port - uint16_t dport; // destination port - struct rb_entity *rb; - nasRadioBearerId_t rab_id; // RAB identification - void (*fct)(struct sk_buff *skb, struct cx_entity *cx, struct classifier_entity *gc); - struct classifier_entity *next; -}; - - -struct cx_entity { - int sap[NAS_SAPI_CX_MAX]; - uint8_t state; // state of the connection - nasLocalConnectionRef_t lcr; // Local connection reference - nasCellID_t cellid; // cell identification - uint32_t countimer; // timeout's counter - uint8_t retry; // number of retransmissions - struct classifier_entity *sclassifier[NAS_DSCP_MAX]; // send classifiers table - uint16_t nsclassifier; - uint32_t iid6[2]; // IPv6 interface identification - uint8_t iid4; // IPv4 interface identification - struct rb_entity *rb; // RB entities for RABs - uint16_t num_rb; - // MW - 17/5/05 - int ue_id; - int rrc_state; - // MBMS - int requested_joined_services[NASRG_MBMS_SVCES_MAX]; - int requested_left_services[NASRG_MBMS_SVCES_MAX]; - int joined_services[NASRG_MBMS_SVCES_MAX]; -}; - -//struct mbms_rb_entity{ -// uint32_t cnxid; -// nasRadioBearerId_t mbms_rbId; -// nasSapId_t sapi; -// nasQoSTrafficClass_t qos; -// nasQoSTrafficClass_t RadioQosClass; -// uint8_t state; -// uint8_t result; -// uint8_t retry; -// uint32_t countimer; -// -// uint16_t serviceId; -// uint16_t sessionId; -// uint16_t duration; -//}; -// - -struct nas_priv { - int irq; - int rx_flags; - struct timer_list timer; - spinlock_t lock; - struct net_device_stats stats; - uint8_t retry_limit; - uint32_t timer_establishment; - uint32_t timer_release; - struct cx_entity cx[NAS_CX_MAX]; - struct classifier_entity *rclassifier[NAS_DSCP_MAX]; // receive classifier - int nrclassifier; - uint32_t next_sclassref; - int sap[NAS_SAPI_MAX]; - uint8_t xbuffer[NAS_MAX_LENGTH]; // transmission buffer - uint8_t rbuffer[NAS_MAX_LENGTH]; // reception buffer - // MW - 17/5/05 - int broadcast_counter; - int SIB18_counter; - // MBMS - struct rb_entity mbms_rb[NASRG_MBMS_SVCES_MAX]; - struct classifier_entity *mbmsclassifier[NASRG_MBMS_SVCES_MAX]; // mbms classifier - int nmbmsclassifier; - uint32_t next_mbmsclassref; - //Added for demo 3 - MW - nasCellID_t measured_cell_id; - uint16_t num_UEs; - uint32_t rlcBufferOccupancy[NAS_CX_MAX]; - uint32_t scheduledPRB[NAS_CX_MAX]; - uint32_t totalDataVolume[NAS_CX_MAX]; - uint32_t totalNumPRBs; -}; - -struct ipversion { -#if defined(__LITTLE_ENDIAN_BITFIELD) - uint8_t reserved:4, - version:4; -#else - uint8_t version:4, - reserved:4; -#endif -}; - -typedef struct pdcp_data_req_header_t { - unsigned int rb_id; - unsigned int data_size; - int inst; -} pdcp_data_req_header_t; - -typedef struct pdcp_data_ind_header_t { - unsigned int rb_id; - unsigned int data_size; - int inst; -} pdcp_data_ind_header_t; -// -extern struct nas_priv *gpriv; -extern struct net_device *gdev; -//extern int bytes_wrote; -//extern int bytes_read; - -extern uint8_t NAS_RG_IMEI[14]; -extern uint8_t NAS_NULL_IMEI[14]; - -//global variables shared with RRC -extern int *pt_nas_rg_irq; -//extern uint16_t *pt_rg_own_cell_id; -extern uint16_t local_rg_cell_id; -#endif diff --git a/openair2/NAS/DRIVER/CELLULAR/NETLTEST/Makefile b/openair2/NAS/DRIVER/CELLULAR/NETLTEST/Makefile deleted file mode 100755 index eec82de367..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NETLTEST/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -# Lines starting with the pound sign are comments. -# -# These things are options that you might need -# to tweak. - -# You can modify the below as well, but probably -# won't need to. - -#CC = egcs - -#UPDIR := $(shell /bin/pwd) -#GRAAL_DIR =$(UPDIR)/.. -#RRC_DIR =$(UPDIR)/../../../AS/L3/RRC - -CELL_UPDIR := $(shell /bin/pwd) -NAS_DIR := $(OPENAIR2_DIR)/NAS/DRIVER/CELLULAR/NASMT -RRC_DIR := $(OPENAIR2_DIR)/RRC/CELLULAR -EXTRA_CFLAGS += -I$(RRC_DIR) -DNODE_MT - -CFLAGS = -Wall -g -I$(NAS_DIR) -I$(RRC_DIR) - -COMPILE = $(CC) $(CFLAGS) -c - -OBJS = netltest.o - -EXECUTABLE = netltest - -# "all" is the default target. Simply make it point to myprogram. - -all: $(EXECUTABLE) - -# Define the components of the program, and how to link them together. -# These components are defined as dependencies; that is, they must be -# made up-to-date before the code is linked. - -$(EXECUTABLE): $(OBJS) - $(CC) $(CFLAGS) -o $(EXECUTABLE) $(OBJS) - -# Add any special rules here. - -# Specify that all .o files depend on .c files, and indicate how -# the .c files are converted (compiled) to the .o files. - -%.o: %.c - $(COMPILE) -o $@ $< - -clean: - -rm $(OBJS) $(EXECUTABLE) diff --git a/openair2/NAS/DRIVER/CELLULAR/NETLTEST/netltest b/openair2/NAS/DRIVER/CELLULAR/NETLTEST/netltest deleted file mode 100755 index f44ea64b09862efd61f5e17082141e4be4e9a500..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12462 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 LQyn+T0Vn -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/******************** -// RRC definitions - ********************/ -#include "nasmt_constant.h" -#include "rrc_nas_sap.h" -#include "rrc_constant.h" -//----------------------------------------------------------------------------- -//#define MAX_PAYLOAD 4096 /* this sould cover the max mtu size*/ -struct nlmsghdr *rrcnl_nlh; -int rrcnl_sock_fd; -struct sockaddr_nl rrcnl_src_addr, rrcnl_dest_addr; -struct iovec rrcnl_iov; -struct msghdr rrcnl_msg; - -//----------------------------------------------------------------------------- -typedef unsigned int sdu_size_t; -typedef unsigned int rb_id_t; - -typedef struct pdcp_data_req_header_t { - rb_id_t rb_id; - sdu_size_t data_size; - int inst; -} pdcp_data_req_header_t; - -typedef struct pdcp_data_ind_header_t { - rb_id_t rb_id; - sdu_size_t data_size; - int inst; -} pdcp_data_ind_header_t; - -#define MAX_PAYLOAD 1024 /* maximum payload size*/ -struct sockaddr_nl src_addr, dest_addr; -struct nlmsghdr *nlh = NULL; -struct iovec iov; -int sock_fd; -struct msghdr msg; -#define OAI_IP_DRIVER_NETLINK_ID 31 -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -void foo( int sig ) -{ - //----------------------------------------------------------------------------- - printf("I got cntl-C, closing socket\n"); - close(sock_fd); - close(rrcnl_sock_fd); - exit(-1); -} - -//----------------------------------------------------------------------------- -int main() -{ - //----------------------------------------------------------------------------- - struct sigaction newaction; - int i=0; - int ret; - int len, count; - - newaction.sa_handler = foo; - - // register cntl-C handler - if ( sigaction( SIGINT, &newaction, NULL ) == -1) - perror("Could not install the new signal handler"); - - // create both sockets - sock_fd = socket(PF_NETLINK, SOCK_RAW,OAI_IP_DRIVER_NETLINK_ID); - printf("Opened socket with fd %d\n",sock_fd); - ret = fcntl(sock_fd,F_SETFL,O_NONBLOCK); - printf("fcntl returns %d\n",ret); - - rrcnl_sock_fd = socket(PF_NETLINK, SOCK_RAW, NAS_RRCNL_ID); - printf("rrc_ue_netlink_init - Opened socket with fd %d\n", rrcnl_sock_fd); - ret = fcntl(rrcnl_sock_fd,F_SETFL,O_NONBLOCK); - printf("rrc_ue_netlink_init - fcntl returns %d\n",ret); - - // set src addresses blocks - memset(&src_addr, 0, sizeof(src_addr)); - src_addr.nl_family = AF_NETLINK; - src_addr.nl_pid = 1;//getpid(); /* self pid */ - src_addr.nl_groups = 0; /* not in mcast groups */ - ret = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr)); - printf("bind returns %d\n",ret); - - memset(&rrcnl_src_addr, 0, sizeof(rrcnl_src_addr)); - rrcnl_src_addr.nl_family = AF_NETLINK; - rrcnl_src_addr.nl_pid = NL_DEST_RRC_PID;//getpid(); /* self pid */ - rrcnl_src_addr.nl_groups = 0; /* not in mcast groups */ - ret = bind(rrcnl_sock_fd, (struct sockaddr*)&rrcnl_src_addr, sizeof(rrcnl_src_addr)); - printf("rrc_ue_netlink_init - bind returns %d\n",ret); - - // set dest addresses blocks - memset(&dest_addr, 0, sizeof(dest_addr)); - dest_addr.nl_family = AF_NETLINK; - dest_addr.nl_pid = 0; /* For Linux Kernel */ - dest_addr.nl_groups = 0; /* unicast */ - - memset(&rrcnl_dest_addr, 0, sizeof(rrcnl_dest_addr)); - rrcnl_dest_addr.nl_family = AF_NETLINK; - rrcnl_dest_addr.nl_pid = 0; /* For Linux Kernel */ - rrcnl_dest_addr.nl_groups = 0; /* unicast */ - - // set nlh - nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)); - /* Fill the netlink message header */ - nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD); - nlh->nlmsg_pid = 1;//getpid(); /* self pid */ - nlh->nlmsg_flags = 0; - - rrcnl_nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(RRC_NAS_MAX_SIZE)); - //memset(rrcnl_nlh, 0, NLMSG_SPACE(MAX_PAYLOAD)); - /* Fill the netlink message header */ - rrcnl_nlh->nlmsg_len = NLMSG_SPACE(RRC_NAS_MAX_SIZE); - rrcnl_nlh->nlmsg_pid = NL_DEST_RRC_PID;//getpid(); /* self pid */ - rrcnl_nlh->nlmsg_flags = 0; - - // set iov - iov.iov_base = (void *)nlh; - iov.iov_len = nlh->nlmsg_len; - memset(&msg,0,sizeof(msg)); - msg.msg_name = (void *)&dest_addr; - msg.msg_namelen = sizeof(dest_addr); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - rrcnl_iov.iov_base = (void *)rrcnl_nlh; - rrcnl_iov.iov_len = rrcnl_nlh->nlmsg_len; - memset(&rrcnl_msg,0,sizeof(rrcnl_msg)); - rrcnl_msg.msg_name = (void *)&rrcnl_dest_addr; - rrcnl_msg.msg_namelen = sizeof(rrcnl_dest_addr); - rrcnl_msg.msg_iov = &rrcnl_iov; - rrcnl_msg.msg_iovlen = 1; - - /* Read message from kernel */ - memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD)); - - /* Read message from kernel */ - memset(rrcnl_nlh, 0, NLMSG_SPACE(MAX_PAYLOAD)); - - while (1) { - len = recvmsg(sock_fd, &msg, 0); - count = recvmsg(rrcnl_sock_fd, &rrcnl_msg, 0); - - if (len<0) { - // exit(-1); - } else { - printf("Received PDCP socket with length %d (nlmsg_len = %d)\n",len,nlh->nlmsg_len); - } - - if (count<0) { - // exit(-1); - } else { - printf("Received RRC socket with length %d (nlmsg_len = %d)\n",count,rrcnl_nlh->nlmsg_len); - } - - /* usleep(1000); - i=i+1; - if ((i % 100) == 0) - printf("%d\n",i);*/ - usleep(50); - i=i+1; - - if ((i % 1000) == 0) - printf("%d\n",i); - - /* - for (i=0;inlmsg_len - sizeof(struct nlmsghdr);i++) { - printf("%x ", - ((unsigned char *)NLMSG_DATA(nlh))[i]); - } - */ - } - - /* Close Netlink Socket */ - return 0; -} - - - - diff --git a/openair2/NAS/DRIVER/CELLULAR/NETLTEST/nettestPDCP.c b/openair2/NAS/DRIVER/CELLULAR/NETLTEST/nettestPDCP.c deleted file mode 100644 index 121d3bba8b..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/NETLTEST/nettestPDCP.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#include -#include -#include -#include -#include -#include -#include - -typedef unsigned int sdu_size_t; -typedef unsigned int rb_id_t; - -typedef struct pdcp_data_req_header_t { - rb_id_t rb_id; - sdu_size_t data_size; - int inst; -} pdcp_data_req_header_t; - -typedef struct pdcp_data_ind_header_t { - rb_id_t rb_id; - sdu_size_t data_size; - int inst; -} pdcp_data_ind_header_t; - -#define MAX_PAYLOAD 1024 /* maximum payload size*/ -struct sockaddr_nl src_addr, dest_addr; -struct nlmsghdr *nlh = NULL; -struct iovec iov; -int sock_fd; -struct msghdr msg; - - -void foo( int sig ) -{ - - printf("I got cntl-C, closing socket\n"); - - - close(sock_fd); - exit(-1); -} - - -#define OAI_IP_DRIVER_NETLINK_ID 31 - -void main() -{ - - - struct sigaction newaction; - int i=0; - int ret; - int len; - - newaction.sa_handler = foo; - - if ( sigaction( SIGINT, &newaction, NULL ) == -1) - perror("Could not install the new signal handler"); - - sock_fd = socket(PF_NETLINK, SOCK_RAW,OAI_IP_DRIVER_NETLINK_ID); - - printf("Opened socket with fd %d\n",sock_fd); - - ret = fcntl(sock_fd,F_SETFL,O_NONBLOCK); - printf("fcntl returns %d\n",ret); - - memset(&src_addr, 0, sizeof(src_addr)); - src_addr.nl_family = AF_NETLINK; - src_addr.nl_pid = 1;//getpid(); /* self pid */ - src_addr.nl_groups = 0; /* not in mcast groups */ - ret = bind(sock_fd, (struct sockaddr*)&src_addr, - sizeof(src_addr)); - printf("bind returns %d\n",ret); - - memset(&dest_addr, 0, sizeof(dest_addr)); - dest_addr.nl_family = AF_NETLINK; - dest_addr.nl_pid = 0; /* For Linux Kernel */ - dest_addr.nl_groups = 0; /* unicast */ - - nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)); - /* Fill the netlink message header */ - nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD); - nlh->nlmsg_pid = 1;//getpid(); /* self pid */ - nlh->nlmsg_flags = 0; - - iov.iov_base = (void *)nlh; - iov.iov_len = nlh->nlmsg_len; - memset(&msg,0,sizeof(msg)); - msg.msg_name = (void *)&dest_addr; - msg.msg_namelen = sizeof(dest_addr); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - - /* Read message from kernel */ - memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD)); - - while (1) { - len = recvmsg(sock_fd, &msg, 0); - - - if (len<0) { - - // exit(-1); - } else { - printf("Received socket with length %d (nlmsg_len = %d)\n",len,nlh->nlmsg_len); - } - - usleep(1000); - i=i+1; - - if ((i % 100) == 0) - printf("%d\n",i); - - /* - for (i=0;inlmsg_len - sizeof(struct nlmsghdr);i++) { - printf("%x ", - ((unsigned char *)NLMSG_DATA(nlh))[i]); - } - */ - } - - /* Close Netlink Socket */ - -} - - - - diff --git a/openair2/NAS/DRIVER/CELLULAR/readme.txt b/openair2/NAS/DRIVER/CELLULAR/readme.txt deleted file mode 100755 index fd4411a25b..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/readme.txt +++ /dev/null @@ -1,157 +0,0 @@ - --------------------------------- - | UMTS-TDD (TD-CDMA) NAS driver | - --------------------------------- - - - -1 - COMPILATION ---------------- -Pre-Req : - - RTAI installed and running - - IPv6 patched as described below (see 4 - Patching IPv6) - -From RHODOS26 directory: - - - make nasrg : creates the NAS RG driver (nasrg.ko) and copies it to the RHODOS26/bin directory - - - make cleannasrg : deletes all object and temporary files from the nasrg directory - - - make nasmt : creates the NAS MT driver (nasmt.ko) and copies it to the RHODOS26/bin directory - - - make cleannasmt : deletes all object and temporary files from the nasmt directory - - -2 - OPERATION - RG side ------------------------ - -A1 - Compile the Access Stratum (for IF mode) - -Pre-Req : RTAI installed and running - ICC 8.0 installed and running - - > make rgif - > make asrguserif - > make rrmumts - -A2 - Compile the Access Stratum (for RF mode) - -Pre-Req : RTAI installed and running - ICC 8.0 installed and running - - > make guimakefiles - > make rgrf - > make asrguserrfa2 - > make rrmumts - - -B - Start the Access Stratum - - (as root ) > cd <..>RHODOS26/bin - - (first install) > create_rtfifos - (first install) > mknod -m 666 /dev/daq0 c 127 1 - (after cleanas) > cp -../src/rrm_umts/congestion_control/resources_manager/rrm_master.properties . - - (-- ) > ./start_rtos - (-- ) > ./runrgif [for IF] [or ./runrga2 for RF] - - ==> to check correct operation: - (as root ) cat /dev/rtf62 - (as root ) tail -f /var/log/messages - -C - Start the NAS Driver - - (as root ) > cd <..>RHODOS26/bin - (-- ) > insmod nasrg.ko - (-- ) > ./access_router.up - -D - Stop the NAS Driver and the Access Stratum - - (-- ) > ./access_router.down - (-- ) > rmmod nasrg - (-- ) > on Acccess stratum window - (-- ) > ./stop_rtos - -E - Clean Access Stratum compilation - - > make cleanas - -3 - OPERATION - MT side ------------------------ - -A1 - Compile the Access Stratum (for IF mode) - -Pre-Req : RTAI installed and running - ICC 8.0 installed and running - file RHODOS26/src/access_stratum/l1/low/control/mmx.h copied in /usr/include - - > make mtif - > make asmtuserif - > make fpgatest - -A2 - Compile the Access Stratum (for RF mode) - -Pre-Req : RTAI installed and running - ICC 8.0 installed and running - file RHODOS26/src/access_stratum/l1/low/control/mmx.h copied in /usr/include - - > make guimakefiles - > make mtrf - > make asmtuserrf - > make fpgatest - - -B - Start the Access Stratum - - (as root ) > cd <..>RHODOS26/bin - - (first install) > create_rtfifos - (first install) > mknod -m 666 /dev/daq0 c 127 1 - - (-- ) > ./start_rtos - (-- ) > ./runrgif [for IF] [or ./runrga2 for RF] - - ==> to check correct operation: - (as root ) cat /dev/rtf62 - (as root ) tail -f /var/log/messages - -C - Start the NAS Driver - - (as root ) > cd <..>RHODOS26/bin - (-- ) > insmod nasmt.ko - (-- ) > ./mobile_node.up - -D - Stop the NAS Driver and the Access Stratum - - (-- ) > ./mobile_node.down - (-- ) > rmmod nasmt - (-- ) > on Acccess stratum window - (-- ) > ./stop_rtos - -E - Clean Access Stratum compilation - - > make cleanas - - -4 - Patching IPv6 ------------------------ - -For Linux with 2.6.xx kernel version (xx = 10 or 81): - -- move RHODOS26/non_access_stratum/driver/src/addrconf.c.26.xx to /usr/src/linux/net/ipv6/addrconf.c -- move RHODOS26/non_access_stratum/driver/src/if_arp.h.26.xx to /usr/src/linux/include/linux/if_arp.h -- recompile IPv6 (inside the kernel or as a module, as usual) - -5 - Start the MT connection ------------------------ - -You can use either the RAL-UMTS (RAL-CDMA) -- see corresponding documentation -- - -* OR * - -the tool provided with the driver (directory RHODOS26/src/non_access_stratum/driver/mt_tools). -Install the tool, update the Cell_id field if needed and click on the "Attach" button. - - - \ No newline at end of file diff --git a/openair2/NAS/DRIVER/CELLULAR/start_mt_cellular b/openair2/NAS/DRIVER/CELLULAR/start_mt_cellular deleted file mode 100755 index c89f19e9c0..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/start_mt_cellular +++ /dev/null @@ -1,13 +0,0 @@ -#xterm -hold "tail -f /var/log/messages" & -insmod ./NASMT/nascellmt.ko nas_IMEI=3,5,6,0,1,4,9,1,5,0,0,0,0,0 -#insmod ./NASMT/nascellmt.ko -sleep 2 -ifconfig oai0 10.0.1.2 netmask 255.255.255.0 broadcast 10.0.1.255 -#ifconfig oai0 add 2001:660:382:14:335:600:8014:9150/64 -#./bin/mobile_node.up -#sleep 3 -#./CTL_TOOL/gioctl cx add 0 5 -#xterm -hold -e ./bin/IALdummy & -#sleep 1 -#xterm -hold -e ./bin/tdcdma_gui & -#lsmod diff --git a/openair2/NAS/DRIVER/CELLULAR/start_rg_cellular_noradvd b/openair2/NAS/DRIVER/CELLULAR/start_rg_cellular_noradvd deleted file mode 100755 index 3d51140dcd..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/start_rg_cellular_noradvd +++ /dev/null @@ -1,17 +0,0 @@ - -#xterm -hold -e ant -buildfile rrm_umts.xml run & -#sleep 2 -insmod ./NASRG/nascellrg.ko -sleep 2 -#bin/access_router_noradvd.up -sysctl -w net.ipv6.conf.default.dad_transmits=0 -#sysctl -w net.ipv6.conf.all.forwarding=1 -#sysctl -w net.ipv4.conf.all.forwarding=1 - -#ifconfig oai0 192.168.14.100 -ifconfig oai0 10.0.1.3 netmask 255.255.255.0 broadcast 10.0.1.255 -ifconfig oai0 add 2001:660:382:14::1/64 -#ifconfig graal0 192.168.14.100 -#ifconfig graal0 add 2001:690:2380:7777::1/64 -#ifconfig graal0 add 2001:660:382:14::1/64 -#lsmod \ No newline at end of file diff --git a/openair2/NAS/DRIVER/CELLULAR/start_rg_cellular_radvd b/openair2/NAS/DRIVER/CELLULAR/start_rg_cellular_radvd deleted file mode 100755 index f57fb7712d..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/start_rg_cellular_radvd +++ /dev/null @@ -1,17 +0,0 @@ - -#xterm -hold -e ant -buildfile rrm_umts.xml run & -#sleep 2 -insmod ./NASRG/nascellrg.ko -sleep 2 -#bin/access_router_noradvd.up -sysctl -w net.ipv6.conf.default.dad_transmits=0 -sysctl -w net.ipv6.conf.all.forwarding=1 -#sysctl -w net.ipv4.conf.all.forwarding=1 - -#ifconfig oai0 192.168.14.100 -ifconfig oai0 10.0.1.3 netmask 255.255.255.0 broadcast 10.0.1.255 -ifconfig oai0 add 2001:660:382:14::1/64 - -#lsmod -sleep 4s -radvd diff --git a/openair2/NAS/DRIVER/CELLULAR/stop_mt_cellular b/openair2/NAS/DRIVER/CELLULAR/stop_mt_cellular deleted file mode 100755 index e7325cf40f..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/stop_mt_cellular +++ /dev/null @@ -1,5 +0,0 @@ -#killall -qw tdcdma_gui -#killall -qw IALdummy -#./bin/mobile_node.down -rmmod -w nascellmt - diff --git a/openair2/NAS/DRIVER/CELLULAR/stop_rg_cellular b/openair2/NAS/DRIVER/CELLULAR/stop_rg_cellular deleted file mode 100755 index 88d17a7e6b..0000000000 --- a/openair2/NAS/DRIVER/CELLULAR/stop_rg_cellular +++ /dev/null @@ -1,2 +0,0 @@ -ifconfig oai0 down -rmmod -w nascellrg diff --git a/openair2/NAS/Makefile.inc b/openair2/NAS/Makefile.inc deleted file mode 100644 index a06e8f690a..0000000000 --- a/openair2/NAS/Makefile.inc +++ /dev/null @@ -1,6 +0,0 @@ -NAS_UE_DIR = $(OPENAIR2_TOP)/NAS - -NAS_UE_OBJS = - -NAS_UE_incl = \ - -I$(NAS_UE_DIR) diff --git a/openair2/NAS/SIMU_CELLULAR/Makefile b/openair2/NAS/SIMU_CELLULAR/Makefile deleted file mode 100755 index 12070071a6..0000000000 --- a/openair2/NAS/SIMU_CELLULAR/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -# lines starting with the pound sign are comments. -# -# These things are options that you might need -# to tweak. - - -# You can modify the below as well, but probably -# won't need to. - -include $(OPENAIR_DIR)/common/utils/Makefile.inc -#UPDIR := /homes/mwett/rh_mw/RHODOS -COMMON_DIR = $(OPENAIR2_DIR)/COMMON -RRC_CELL_DIR = $(OPENAIR2_DIR)/RRC/CELLULAR -NAS_SIMU_DIR = $(OPENAIR2_DIR)/NAS/SIMU_CELLULAR -#ASN1_DIR = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES -ASN1_DIR = $(OPENAIR2_DIR) - -#UPDIR := $(EURECOM_SRC_PATH) -#GRAAL_DIR =$(UPDIR)/non_access_stratum/driver/nasmt -#RRC_DIR =$(UPDIR)/access_stratum/l3/rrc - -#CFLAGS += -Wall -g -DDEBUG_RRC_STATE -DNODE_RG -DNODE_MT -CFLAGS += -std=gnu99 -I$(KERNEL_DIR) -DNB_ANTENNAS_RX=1 - -ifdef CELL_RRM -CFLAGS += -DNODE_RG -OBJ +=rrm_fifo_standalone.o nasrg_simu_meas.o -else -ifdef MASTER -CFLAGS += -DNODE_RG -OBJ +=nasrg_simu_main.o nasrg_simu_control.o nasrg_simu_rrm_fifo.o nasrg_simu_meas.o -else -CFLAGS += -DNODE_MT -OBJ +=nasmt_simu_main.o nasmt_simu_control.o -endif -endif - -ifdef CELLULAR -CFLAGS += -DCELLULAR -DNO_RRM -I$(COMMON_DIR) -I$(RRC_CELL_DIR) -I$(NAS_SIMU_DIR) -I$(ASN1_DIR) -endif - - -$(OBJ) : %.o : %.c - $(CC) $(CFLAGS) -c -o $@ $< -pthread - -all: nasmt_simu nasrg_simu - -nasmt_sim : $(OBJ) - $(CC) -o nasmt_simu $(OBJ) $(CFLAGS) -lm -lrt -pthread - mv nasmt_simu $(OPENAIR_TARGETS)/SIMU/USER - -nasrg_sim : $(OBJ) - $(CC) -o nasrg_simu $(OBJ) $(CFLAGS) -lm -lrt -pthread - mv nasrg_simu $(OPENAIR_TARGETS)/SIMU/USER - -cell_rrm : $(OBJ) - $(CC) -o cell_rrm $(OBJ) $(CFLAGS) -lm -lrt -pthread - mv cell_rrm $(OPENAIR_TARGETS)/SIMU/USER - -clean: - -rm $(OBJ) $(EXECUTABLE) - diff --git a/openair2/NAS/SIMU_CELLULAR/nas_simu_proto.h b/openair2/NAS/SIMU_CELLULAR/nas_simu_proto.h deleted file mode 100644 index 86ab7a1ec5..0000000000 --- a/openair2/NAS/SIMU_CELLULAR/nas_simu_proto.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#ifndef __NAS_CONTROL_H__ -#define __NAS_CONTROL_H__ - -#ifdef NODE_MT -//----------------------------------------------------------------------------- -void nas_ue_control_init (void); -//int nas_ue_DC_attach(void); -//int nas_ue_DC_attach_complete(void); -int nas_ue_GC_Rcve_FIFO (void); -int nas_ue_NT_Rcve_FIFO (void); -int nas_ue_DC_Rcve_FIFO (void); -#endif - -#ifdef NODE_RG -//----------------------------------------------------------------------------- -void nas_rg_control_init (void); -//int nas_rg_DC_ConnectMs(void) ; -int nas_rg_DC_Rcve_FIFO (int time); - -int nasrg_rrm_socket_init(void); -void nasrg_rrm_fifos_init (void); -void nasrg_rrm_to_rrc_write (void); -void nasrg_rrm_from_rrc_read (void); - -int nasrg_meas_loop (int time, int UE_Id); -void nas_rg_print_buffer (char *buffer, int length); -/*void nasrg_print_meas_report (char *rrc_rrm_meas_payload, uint16_t type); -void nasrg_print_bs_meas_report (char *rrc_rrm_meas_payload, uint16_t type);*/ -void nasrg_print_meas_report (char *rrc_rrm_meas_payload, unsigned short type); -void nasrg_print_bs_meas_report (char *rrc_rrm_meas_payload, unsigned short type); -#endif - -#endif diff --git a/openair2/NAS/SIMU_CELLULAR/nasrg_simu_meas.c b/openair2/NAS/SIMU_CELLULAR/nasrg_simu_meas.c deleted file mode 100644 index a192b82d72..0000000000 --- a/openair2/NAS/SIMU_CELLULAR/nasrg_simu_meas.c +++ /dev/null @@ -1,646 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "openair_types.h" -#include "rrc_constant.h" - -#include "rrc_msg_constant.h" -#include "rrc_rrm_primitives.h" -#include "rrc_msg_ies.h" - -#include "nas_simu_proto.h" - -extern int rrc_rg_rrm_in_fifo; - -int sim_counter=0; - -/* Mobile Station */ -//------------------------------------------------------------------- -void nasrg_meas_if_setup (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - // measurement identity Intra-Frequency - rrm_control->type = IX_ifM; - // measurementCommand SETUP - rrm_control->command = MC_setup; - rrm_control->BaseStation = 0; - rrm_control->UE_Id = UE_Id; - rrm_control->amount = amount16; - rrm_control->period = int2000; -} - -//------------------------------------------------------------------- -void nasrg_meas_if_release (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - // measurement identity Intra-Frequency - rrm_control->type = IX_ifM; - // measurementCommand RELEASE - rrm_control->command = MC_release; - rrm_control->BaseStation = 0; - rrm_control->UE_Id = UE_Id; -} - -//------------------------------------------------------------------- -void nasrg_meas_tv_setup (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - // measurement identity Traffic Volume - rrm_control->type = IX_tvM; - // measurementCommand SETUP - rrm_control->command = MC_setup; - rrm_control->BaseStation = 0; - rrm_control->UE_Id = UE_Id; - rrm_control->amount = amount_inf; - rrm_control->period = int2000; -} - -//------------------------------------------------------------------- -void nasrg_meas_tv_release (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - // measurement identity Traffic Volume - rrm_control->type = IX_tvM; - // measurementCommand RELEASE - rrm_control->command = MC_release; - rrm_control->BaseStation = 0; - rrm_control->UE_Id = UE_Id; -} - -//------------------------------------------------------------------- -void nasrg_meas_q_setup (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - // measurement identity Quality - rrm_control->type = IX_qM; - // measurementCommand SETUP - rrm_control->command = MC_setup; - rrm_control->BaseStation = 0; - rrm_control->UE_Id = UE_Id; - rrm_control->amount = amount2; //for test - //rrm_control->amount = amount_inf; // for execution - rrm_control->period = int3000; -} - -//------------------------------------------------------------------- -void nasrg_meas_q_release (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - // measurement identity Quality - rrm_control->type = IX_qM; - // measurementCommand RELEASE - rrm_control->command = MC_release; - rrm_control->BaseStation = 0; - rrm_control->UE_Id = UE_Id; -} - -//------------------------------------------------------------------- -void nasrg_meas_int_ue_setup (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - // measurement identity Internal UE - rrm_control->type = IX_iueM; - // measurementCommand SETUP - rrm_control->command = MC_setup; - rrm_control->BaseStation = 0; - rrm_control->UE_Id = UE_Id; - rrm_control->amount = amount8; - rrm_control->period = int1000; -} - -//------------------------------------------------------------------- -void nasrg_meas_int_ue_release (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - // measurement identity Internal UE - rrm_control->type = IX_iueM; - // measurementCommand RELEASE - rrm_control->command = MC_release; - rrm_control->BaseStation = 0; - rrm_control->UE_Id = UE_Id; -} - - -/* Base Station */ -//------------------------------------------------------------------- -void nasrg_meas_bs_tv_setup (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - // measurement identity Traffic Volume - rrm_control->type = IX_tvbM; - // measurementCommand SETUP - rrm_control->command = MC_setup; - rrm_control->BaseStation = 1; - rrm_control->UE_Id = UE_Id; - rrm_control->amount = amount_inf; - rrm_control->period = int4000; -} - -//------------------------------------------------------------------- -void nasrg_meas_bs_tv_release (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - // measurement identity Traffic Volume - rrm_control->type = IX_tvbM; - // measurementCommand RELEASE - rrm_control->command = MC_release; - rrm_control->BaseStation = 1; - rrm_control->UE_Id = UE_Id; -} - -//------------------------------------------------------------------- -void nasrg_meas_bs_q_setup (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - // measurement identity Quality - rrm_control->type = IX_qbM; - // measurementCommand SETUP - rrm_control->command = MC_setup; - rrm_control->BaseStation = 1; - rrm_control->UE_Id = UE_Id; - rrm_control->amount = amount2; - rrm_control->period = int3000; -} - -//------------------------------------------------------------------- -void nasrg_meas_bs_q_release (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - // measurement identity Quality - rrm_control->type = IX_qbM; - // measurementCommand RELEASE - rrm_control->command = MC_release; - rrm_control->BaseStation = 1; - rrm_control->UE_Id = UE_Id; -} - -//------------------------------------------------------------------- -void nasrg_meas_int_bs_setup (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - // measurement identity Internal BS - rrm_control->type = IX_ibsM; - // measurementCommand SETUP - rrm_control->command = MC_setup; - rrm_control->BaseStation = 1; - rrm_control->UE_Id = maxUsers; //should not be set - rrm_control->amount = amount16; - rrm_control->period = int4000; -} - -//------------------------------------------------------------------- -void nasrg_meas_int_bs_release (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - // measurement identity Internal BS - rrm_control->type = IX_ibsM; - // measurementCommand RELEASE - rrm_control->command = MC_release; - rrm_control->BaseStation = 1; - rrm_control->UE_Id = maxUsers; //should not be set -} - -//------------------------------------------------------------------- -void nasrg_send_meas_request_to_rrc (int ue_id, struct rrc_rrm_measure_ctl *rrm_control) -{ - //------------------------------------------------------------------- - rpc_message rpc_mess; - measurement_request meas_request; - int count =0; - - printf ("[NASRG_MEAS_TEST] RPC_MEASUREMENT_REQUEST --> RRC\n "); - memset ((char*)& rpc_mess, 0, sizeof (rpc_message)); - memset ((char*)& meas_request, 0, sizeof (measurement_request)); - //build header - rpc_mess.type = RPC_MEASUREMENT_REQUEST; - rpc_mess.length = sizeof (measurement_request); - // build content - meas_request.measurement_type = rrm_control->type; - meas_request.measurement_command = rrm_control->command; - // different conding between RRM and RRC - // Mobile terminal RRC = 0, RRM = 1 - // Base Station RRC = 1, RRM = 2 - meas_request.equipment_type = rrm_control->BaseStation + 1; - meas_request.equipment_id = rrm_control->UE_Id; - meas_request.amount = rrm_control->amount; - meas_request.period = rrm_control->period; - - // send to RRC - count = write(rrc_rg_rrm_in_fifo, (uint8_t *) & rpc_mess, sizeof (rpc_message)); - count += write(rrc_rg_rrm_in_fifo, (uint8_t *) & meas_request, sizeof (measurement_request)); - - if (count > 0) { - printf ("RRM message sent successfully on RRM FIFO, length: %d\n", count); - } else { - printf ("RRM FIFO transmit failed"); - } - -#ifdef DEBUG_NAS_MEAS_SIMU - nas_rg_print_buffer ((char *) & rpc_mess, sizeof (rpc_message)); - nas_rg_print_buffer ((char *) & meas_request, sizeof (meas_request)); -#endif -} - -//------------------------------------------------------------------- -// in case not rrc_rg_meas_loop (time,UE_Id); -int nasrg_rrm_meas_stop (int time, int UE_Id) -{ - //------------------------------------------------------------------- - struct rrc_rrm_measure_ctl control; - - // Measurement Control - Stop Quality previously sent by RRM - nasrg_meas_q_release (UE_Id, &control); - //rrc_rrm_measure_request (control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - return 0; -} -//------------------------------------------------------------------- -// rrc_rg_meas_loop (time,UE_Id); -int nasrg_meas_loop (int time, int UE_Id) -{ - //------------------------------------------------------------------- - struct rrc_rrm_measure_ctl control; - - sim_counter++; - // if (time % 5 == 0) { -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n[NASRG_MEAS_TEST] Simu Measurement Time : %d, counter : %d\n", time, sim_counter); -#endif - - // } - if (sim_counter == 8) { - // Measurement Control - Stop Quality previously sent by RRM -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] NAS sends Measurement Control (Stop Quality) message at time : %d\n\n", sim_counter); -#endif - // setup if measurement for MT - nasrg_meas_q_release (UE_Id, &control); - //rrc_rrm_measure_request (control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - // Intra-Frequency - // if (sim_counter == 140) { - if (sim_counter == 16) { - // Measurement Control - Start Intra-frequency -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] RG sends Measurement Control (Start Intra-freq) message at time : %d\n\n", sim_counter); -#endif - // setup if measurement for MT - nasrg_meas_if_setup (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - // if (sim_counter == 700) { - if (sim_counter == 70) { - // Measurement Control - Stop Intra-frequency -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] RG sends Measurement Control (Stop Intra-freq) message at time : %d\n\n", sim_counter); -#endif - // setup if measurement for MT - nasrg_meas_if_release (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - // Traffic Volume - // if (sim_counter == 100) { - if (sim_counter == 12) { - // Measurement Control - Start Traffic Volume -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] RG sends Measurement Control (Start Traffic Volume) message at time : %d\n\n", sim_counter); -#endif - // setup if measurement for MT - nasrg_meas_tv_setup (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - // if (sim_counter == 990) { - if (sim_counter == 92) { - // Measurement Control - Stop Traffic Volume -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] RG sends Measurement Control (Stop Traffic Volume) message at time : %d\n\n", sim_counter); -#endif - // setup if measurement for MT - nasrg_meas_tv_release (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - // Quality - // if (sim_counter == 503) { - if (sim_counter == 50) { - // Measurement Control - Start Quality -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] RG sends Measurement Control (Start Quality) message at time : %d\n\n", sim_counter); -#endif - // setup if measurement for MT - nasrg_meas_q_setup (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - // if (sim_counter == 995) { - if (sim_counter == 96) { - // Measurement Control - Stop Quality -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] RG sends Measurement Control (Stop Quality) message at time : %d\n\n", sim_counter); -#endif - // setup if measurement for MT - nasrg_meas_q_release (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - // Internal UE - // if (sim_counter == 210) { - if (sim_counter == 20) { - // Measurement Control - Start Internal UE -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] RG sends Measurement Control (Start Int UE) message at time : %d\n\n", sim_counter); -#endif - // setup int_ue measurement for MT - nasrg_meas_int_ue_setup (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - // if (sim_counter == 999) { - if (sim_counter == 98) { - // Measurement Control - Stop Internal UE -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] RG sends Measurement Control (Stop Int UE) message at time : %d\n\n", sim_counter); -#endif - nasrg_meas_int_ue_release (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - // Internal BS - // if (sim_counter == 105) { - if (sim_counter == 14) { - // Measurement Control - Start Internal BS -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] RG starts internal Measurement (Int BS) at time : %d\n\n", sim_counter); -#endif - nasrg_meas_int_bs_setup (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - // if (sim_counter == 980) { - if (sim_counter == 86) { - // Measurement Control - Stop Internal BS -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] RG stops internal Measurement (Int BS) at time : %d\n\n", sim_counter); -#endif - nasrg_meas_int_bs_release (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - // Traffic Volume BS - // if (sim_counter == 220) { - if (sim_counter == 22) { - // Measurement Control - Start Traffic Volume BS -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] RG starts internal Measurement (Traffic Volume BS) at time : %d\n\n", sim_counter); -#endif - nasrg_meas_bs_tv_setup (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - // if (sim_counter == 900) { - if (sim_counter == 80) { - // Measurement Control - Stop Traffic Volume BS -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] RG stops internal Measurement (Traffic Volume BS) at time : %d\n\n", sim_counter); -#endif - nasrg_meas_bs_tv_release (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - // Quality BS - // if (sim_counter == 625) { - if (sim_counter == 62) { - // Measurement Control - Start Quality BS -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] RG starts internal Measurement (Quality BS) at time : %d\n\n", sim_counter); -#endif - nasrg_meas_bs_q_setup (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - // if (sim_counter == 989) { - if (sim_counter == 90) { - // Measurement Control - Stop Quality BS -#ifdef DEBUG_NAS_MEAS_SIMU - printf ("\n\n[NASRG_MEAS_TEST] RG stops internal Measurement (Quality BS) at time : %d\n\n", sim_counter); -#endif - nasrg_meas_bs_q_release (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - } - - return sim_counter; -} - -//----------------------------------------------------------------------------- -//void rrc_rg_print_meas_report (struct rrc_rg_mt_meas_rep *p){ -void nasrg_print_meas_report (char *rrc_rrm_meas_payload, uint16_t type) -{ - //----------------------------------------------------------------------------- - int i, j; - char *payload[20] = - { "pl0", "pl4", "pl8", "pl16", "pl32", "pl64", "pl128", "pl256", "pl512", "pl1024", "pl2k", "pl4k", "pl8k", "pl16k", "pl32k", "pl64k", "pl128k", "pl256k", "pl512k", "pl1024k" }; - char *average[20] = { - "pla0", "pla4", "pla8", "pla16", "pla32", "pla64", "pla128", "pla256", "pla512", "pla1024", "pla2k", - "pla4k", "pla8k", "pla16k", "pla32k", "pla64k", "pla128k", "pla256k", "pla512k","pla1024k" - }; - char *variance[14] = { "plv0", "plv4", "plv8", "plv16", "plv32", "plv64", "plv128", "plv256", "plv512", "plv1024", "plv2k", "plv4k", "plv8k", "plv16k" }; - - printf ("\n[NASRG-MEAS] ************** MT Measurement Report Message *****************\n"); - - switch (type) { - case RPC_L1_MEASUREMENT_MT_INTRA_FREQUENCY_REPORT: { - struct rrc_rrm_meas_report_mt_if *p; - p = (struct rrc_rrm_meas_report_mt_if *)rrc_rrm_meas_payload; - printf ("Intra Frequency Measurement\t Number of cells: %d\n", p->if_num_cells); - - for (i = 0; i < p->if_num_cells; i++) { - printf ("[NASRG-MEAS] Cell number: %d\tCell Identity: %d\tCell Parameters Id: %d\tP-CCPCH RSCP: %d\tPathloss: %d\n", i, p->if_cell_id[i], p->if_cell_parms_id[i], p->if_BCH_RSCP[i], p->if_pathloss[i]); - printf ("\tTimeslot ISCP for each slot:\t"); - - for (j = 0; j < JRRM_SLOTS_PER_FRAME; j++) - printf ("%d: %d, ", j, p->if_slot_iscp[i][j]); - - printf ("\n"); - } - } - break; - - case RPC_L1_MEASUREMENT_MT_TRAFFIC_VOLUME_REPORT: { - struct rrc_rrm_meas_report_mt_tv *p; - p = (struct rrc_rrm_meas_report_mt_tv *)rrc_rrm_meas_payload; - printf ("Traffic Volume Measurement -\t Number of RBs: %d\n", p->tv_num_rbs); - - for (i = 0; i < p->tv_num_rbs; i++) - printf ("[NASRG-MEAS] RB_Id : %d\t, RLC_BufferPayload : %s\t, Average : %s\t, Variance : %s\n", - p->tv_rbid[i], payload[p->tv_rb_payload[i]], average[p->tv_rb_average[i]], variance[p->tv_rb_variance[i]]); - } - break; - - case RPC_L1_MEASUREMENT_MT_QUALITY_REPORT: { - struct rrc_rrm_meas_report_mt_q *p; - p = (struct rrc_rrm_meas_report_mt_q *)rrc_rrm_meas_payload; - printf ("Quality Measurement -\t Number of Transport Channels : %d, Number of TFCS : %d\n", p->q_num_TrCH, p->q_num_tfcs); - printf ("[NASRG-MEAS] BLER for each Transport Channel:\t"); - - for (i = 0; i < p->q_num_TrCH; i++) - printf ("%d: %d, ", p->q_dl_TrCH_id[i], p->q_dl_TrCH_BLER[i]); - - printf ("\n"); - printf ("[NASRG-MEAS] SIR for each TFCS for each slot:\n"); - - for (i = 0; i < p->q_num_tfcs; i++) { - printf ("%d: ", p->q_tfcs_id[i]); - - for (j = 0; j < JRRM_SLOTS_PER_FRAME; j++) - printf ("%d, ", p->q_sir[i][j]); - - printf ("\n"); - } - } - break; - - case RPC_L1_MEASUREMENT_MT_INTERNAL_REPORT: { - struct rrc_rrm_meas_report_mt_int *p; - p = (struct rrc_rrm_meas_report_mt_int *)rrc_rrm_meas_payload; - printf ("UE internal Measurement\t Timing Advance: %d\n", p->int_timing_advance); - printf ("[NASRG-MEAS] Transmitted Power for each slot:\t"); - - for (j = 0; j < JRRM_SLOTS_PER_FRAME; j++) - printf ("%d: %d, ", j, p->int_xmit_power[j]); - - printf ("\n"); - } - break; - } - - printf ("[NASRG-MEAS] *****END********* Measurement Report Message *******\n\n"); -} - -//----------------------------------------------------------------------------- -void nasrg_print_bs_meas_report (char *rrc_rrm_meas_payload, uint16_t type) -{ - //----------------------------------------------------------------------------- - int i, j; - char *payload[20] = - { "pl0", "pl4", "pl8", "pl16", "pl32", "pl64", "pl128", "pl256", "pl512", "pl1024", "pl2k", "pl4k", "pl8k", "pl16k", "pl32k", "pl64k", "pl128k", "pl256k", "pl512k", "pl1024k" }; - char *average[20] = { - "pla0", "pla4", "pla8", "pla16", "pla32", "pla64", "pla128", "pla256", "pla512", "pla1024", "pla2k", - "pla4k", "pla8k", "pla16k", "pla32k", "pla64k", "pla128k", "pla256k", "pla512k", "pla1024k" - }; - char *variance[14] = { "plv0", "plv4", "plv8", "plv16", "plv32", "plv64", "plv128", "plv256", "plv512", "plv1024", "plv2k", "plv4k", "plv8k", "plv16k" }; - - printf ("\n[NASRG-MEAS] ************** BS Measurement Report Message *****************\n"); - - switch (type) { - case RPC_L1_MEASUREMENT_RG_TRAFFIC_VOLUME_REPORT: { - struct rrc_rrm_meas_report_bs_tv *p; - p = (struct rrc_rrm_meas_report_bs_tv *)rrc_rrm_meas_payload; - printf ("Traffic Volume Measurement -\t Number of RBs: %d\n", p->tv_num_rbs); - - for (i = 0; i < p->tv_num_rbs; i++) - printf ("[NASRG-MEAS] RB_Id : %d\t, RLC_BufferPayload : %s\t, Average : %s\t, Variance : %s\n", - p->tv_rbid[i], payload[p->tv_rb_payload[i]], average[p->tv_rb_average[i]], variance[p->tv_rb_variance[i]]); - } - break; - - case RPC_L1_MEASUREMENT_RG_QUALITY_REPORT: { - struct rrc_rrm_meas_report_bs_q *p; - p = (struct rrc_rrm_meas_report_bs_q *)rrc_rrm_meas_payload; - printf ("Quality Measurement -\t Number of Transport Channels : %d, Number of TFCS : %d\n", p->q_num_TrCH, p->q_num_tfcs); - printf ("[NASRG-MEAS] BLER for each Transport Channel:\t"); - - for (i = 0; i < p->q_num_TrCH; i++) - printf ("%d: %d, ", p->q_dl_TrCH_id[i], p->q_dl_TrCH_BLER[i]); - - printf ("\n"); - printf ("[NASRG-MEAS] SIR for each TFCS for each slot:\n"); - - for (i = 0; i < p->q_num_tfcs; i++) { - printf ("%d: ", p->q_tfcs_id[i]); - - for (j = 0; j < JRRM_SLOTS_PER_FRAME; j++) - printf ("%d, ", p->q_sir[i][j]); - - printf ("\n"); - } - } - break; - - case RPC_L1_MEASUREMENT_RG_INTERNAL_REPORT: { - struct rrc_rrm_meas_report_bs_int *p; - p = (struct rrc_rrm_meas_report_bs_int *)rrc_rrm_meas_payload; - printf ("BS internal Measurement\n"); - - for (i = 0; i < numANTENNAS; i++) { - printf ("[NASRG-MEAS] Transmitted Power for each slot on antenna %d : ", i); - - for (j = 0; j < JRRM_SLOTS_PER_FRAME; j++) - printf ("%d: %d, ", j, p->int_xmit_power[i][j]); - - printf ("\n"); - } - - for (i = 0; i < JRRM_SLOTS_PER_FRAME; i++) { - printf ("[NASRG-MEAS] RSCP for each channel on slot %d : ", i); - - for (j = 0; j < MAXCH; j++) - printf ("%d: %d, ", j, p->int_rscp[i][j]); - - printf ("\n"); - } - - for (i = 0; i < numANTENNAS; i++) { - printf ("[NASRG-MEAS] RSSI RF for each slot on antenna %d : ", i); - - for (j = 0; j < JRRM_SLOTS_PER_FRAME; j++) - printf ("%d: %d, ", j, p->int_rssi_rf[i][j]); - - printf ("\n"); - } - - for (i = 0; i < NUMSPARE; i++) { - printf ("[NASRG-MEAS] Spare value : %d: %d\n", i, p->int_spare[i]); - } - } - break; - } - - printf ("[NASRG-MEAS] *****END********* Measurement Report Message *******\n\n"); -} - diff --git a/openair2/NAS/SIMU_CELLULAR/rrm_fifo_standalone.c b/openair2/NAS/SIMU_CELLULAR/rrm_fifo_standalone.c deleted file mode 100644 index e9cefdd926..0000000000 --- a/openair2/NAS/SIMU_CELLULAR/rrm_fifo_standalone.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -// -#include -#include -#include -//----------------------------------------------------------------------------- -#include "openair_types.h" -#include "rrc_constant.h" -#include "nas_simu_proto.h" - -#include "rrc_rrm_sap.h" -#include "rrc_msg_constant.h" -#include "rrc_rrm_primitives.h" - -void nasrg_meas_q_setup (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control); -void nasrg_meas_q_release (int UE_Id, struct rrc_rrm_measure_ctl *rrm_control); -void nasrg_send_meas_request_to_rrc (int ue_id, struct rrc_rrm_measure_ctl *rrm_control); -//----------------------------------------------------------------------------- -int rrc_rg_rrm_in_fifo; -int rrc_rg_rrm_out_fifo; -int tXmit_id; -#define RRM_MSG_MAX_LENGTH 1500 -struct rrc_rrm_measure_ctl control; - -//----------------------------------------------------------------------------- -// Open FIFOs for RG RRC SAPs -void nasrg_rrm_fifos_init (void) -{ - //----------------------------------------------------------------------------- - int write_flag = O_WRONLY | O_NONBLOCK | O_NDELAY; - int read_flag = O_RDONLY | O_NONBLOCK | O_NDELAY; - - // Open FIFOs - - while ((rrc_rg_rrm_in_fifo = open (RRM_INPUT_SAPI, write_flag)) < 0) { - printf ("%s returned value %d\n", RRM_INPUT_SAPI, rrc_rg_rrm_in_fifo); - fflush(stdout); - sleep (1); - } - - while ((rrc_rg_rrm_out_fifo = open (RRM_OUTPUT_SAPI, read_flag)) < 0) { - printf ("%s returned value %d\n", RRM_OUTPUT_SAPI, rrc_rg_rrm_out_fifo); - fflush(stdout); - sleep (1); - } - - printf ("FIFO RRM_INPUT_SAPI, %d\n", rrc_rg_rrm_in_fifo); - printf ("FIFO RRM_OUTPUT_SAPI, %d\n", rrc_rg_rrm_out_fifo); -} - -//------------------------------------------------------------------- -void rrm_connection_response (void) -{ - //------------------------------------------------------------------- - rpc_message rpc_mess; - connection_response response; - int count=0; - char *sim_data = "Void configuration\0"; - - printf ("[CELL-RRM] RPC_CONNECTION_RESPONSE --> RRC\n "); - rpc_mess.type = RPC_CONNECTION_RESPONSE; - rpc_mess.length = sizeof (connection_response)+ strlen (sim_data); - response.equipment_id = 0; - response.status = STATUS_CONNECTION_ACCEPTED; - - //count = rtf_put (protocol_bs->rrc.rc_rrm.output_fifo, (uint8_t *) & rpc_mess, sizeof (rpc_message)); - //count = rtf_put (protocol_bs->rrc.rc_rrm.output_fifo, (uint8_t *) & confirm, sizeof (add_user_confirm)); - count = write(rrc_rg_rrm_in_fifo, (uint8_t *) & rpc_mess, sizeof (rpc_message)); - count += write(rrc_rg_rrm_in_fifo, (uint8_t *) & response, sizeof (connection_response)); - count += write(rrc_rg_rrm_in_fifo, (uint8_t *) sim_data, strlen (sim_data)); - - if (count > 0) { - printf ("RRM message sent successfully on RRM FIFO, length: %d\n", count); - } else { - printf ("RRM FIFO transmit failed"); - } -} - -//------------------------------------------------------------------- -void rrm_add_user_response (char *rcve_buffer) -{ - //------------------------------------------------------------------- - rpc_message rpc_mess; - add_user_response response; - add_user_request *request; - int count=0; - char *sim_data = "Void configuration\0"; - - request = (add_user_request *)rcve_buffer; - printf ("[CELL-RRM] RPC_ADD_USER_RESPONSE --> RRC\n "); - rpc_mess.type = RPC_ADD_USER_RESPONSE; - rpc_mess.length = sizeof (add_user_response)+ strlen (sim_data); - response.equipment_id = 0; - response.user_id = request->user_id; - response.tx_id = request->tx_id; - response.status = ADD_USER_SUCCESSFUL; - - //count = rtf_put (protocol_bs->rrc.rc_rrm.output_fifo, (uint8_t *) & rpc_mess, sizeof (rpc_message)); - //count = rtf_put (protocol_bs->rrc.rc_rrm.output_fifo, (uint8_t *) & confirm, sizeof (add_user_confirm)); - count = write(rrc_rg_rrm_in_fifo, (uint8_t *) & rpc_mess, sizeof (rpc_message)); - count += write(rrc_rg_rrm_in_fifo, (uint8_t *) & response, sizeof (add_user_response)); - count += write(rrc_rg_rrm_in_fifo, (uint8_t *) sim_data, strlen (sim_data)); - - if (count > 0) { - printf ("RRM message sent successfully on RRM FIFO, length: %d\n", count); - } else { - printf ("RRM FIFO transmit failed"); - } -} - -//------------------------------------------------------------------- -void rrm_remove_user_response (char *rcve_buffer) -{ - //------------------------------------------------------------------- - rpc_message rpc_mess; - remove_user_response response; - remove_user_request *request; - int count=0; - char *sim_data = "Void configuration\0"; - - request = (remove_user_request *)rcve_buffer; - printf ("[CELL-RRM] RPC_REMOVE_USER_RESPONSE --> RRC\n "); - rpc_mess.type = RPC_REMOVE_USER_RESPONSE; - rpc_mess.length = sizeof (remove_user_response)+ strlen (sim_data); - response.equipment_id = 0; - response.user_id = request->user_id; - response.tx_id = request->tx_id; - response.status = REMOVE_USER_SUCCESSFUL; - - //count = rtf_put (protocol_bs->rrc.rc_rrm.output_fifo, (uint8_t *) & rpc_mess, sizeof (rpc_message)); - //count = rtf_put (protocol_bs->rrc.rc_rrm.output_fifo, (uint8_t *) & confirm, sizeof (add_user_confirm)); - count = write(rrc_rg_rrm_in_fifo, (uint8_t *) & rpc_mess, sizeof (rpc_message)); - count += write(rrc_rg_rrm_in_fifo, (uint8_t *) & response, sizeof (remove_user_response)); - count += write(rrc_rg_rrm_in_fifo, (uint8_t *) sim_data, strlen (sim_data)); - - if (count > 0) { - printf ("RRM message sent successfully on RRM FIFO, length: %d\n", count); - } else { - printf ("RRM FIFO transmit failed"); - } - - /* Not sure it is really needed here - usleep (5000); //wait 5ms - // stop q measurement for MT - nasrg_meas_q_release (UE_Id, &control); - nasrg_send_meas_request_to_rrc (UE_Id, &control); - */ -} - -//------------------------------------------------------------------- -void rrm_add_radio_access_bearer_response (char *rcve_buffer) -{ - //------------------------------------------------------------------- - rpc_message rpc_mess; - add_radio_access_bearer_response response; - add_radio_access_bearer_request *request; - int count=0; - char *sim_data = "Void configuration\0"; - - request = (add_radio_access_bearer_request *)rcve_buffer; - printf ("[CELL-RRM] RPC_ADD_RADIO_ACCESS_BEARER_RESPONSE --> RRC\n "); - rpc_mess.type = RPC_ADD_RADIO_ACCESS_BEARER_RESPONSE; - rpc_mess.length = sizeof (add_radio_access_bearer_response)+ strlen (sim_data); - response.user_id = request->user_id; - response.rab_id = request->rab_id; - response.tx_id = request->tx_id; - response.status = ADD_RADIO_ACCESS_BEARER_SUCCESSFUL; - - //count = rtf_put (protocol_bs->rrc.rc_rrm.output_fifo, (uint8_t *) & rpc_mess, sizeof (rpc_message)); - //count = rtf_put (protocol_bs->rrc.rc_rrm.output_fifo, (uint8_t *) & confirm, sizeof (add_user_confirm)); - count = write(rrc_rg_rrm_in_fifo, (uint8_t *) & rpc_mess, sizeof (rpc_message)); - count += write(rrc_rg_rrm_in_fifo, (uint8_t *) & response, sizeof (add_radio_access_bearer_response)); - count += write(rrc_rg_rrm_in_fifo, (uint8_t *) sim_data, strlen (sim_data)); - - if (count > 0) { - printf ("RRM message sent successfully on RRM FIFO, length: %d\n", count); - } else { - printf ("RRM FIFO transmit failed"); - } -} - -//------------------------------------------------------------------- -void rrm_add_measurement_request (char *rcve_buffer) -{ - //------------------------------------------------------------------- - add_radio_access_bearer_confirm *confirm; - - confirm = (add_radio_access_bearer_confirm *)rcve_buffer; - printf ("[CELL-RRM] RPC_L1_MEASUREMENT_MT_QUALITY_REPORT --> RRC\n "); - - // TEMP removed the Meas request (causes bothe messages to be received together by RRC RG - // usleep (20000); //wait 5ms - // setup q measurement for MT - nasrg_meas_q_setup (confirm->user_id, &control); - nasrg_send_meas_request_to_rrc (confirm->user_id, &control); - -} - - -//------------------------------------------------------------------- -void rrm_remove_radio_access_bearer_response (char *rcve_buffer) -{ - //------------------------------------------------------------------- - rpc_message rpc_mess; - remove_radio_access_bearer_response response; - remove_radio_access_bearer_request *request; - int count=0; - char *sim_data = "Void configuration\0"; - - request = (remove_radio_access_bearer_request *)rcve_buffer; - printf ("[CELL-RRM] RPC_REMOVE_RADIO_ACCESS_BEARER_RESPONSE --> RRC\n "); - rpc_mess.type = RPC_REMOVE_RADIO_ACCESS_BEARER_RESPONSE; - rpc_mess.length = sizeof (remove_radio_access_bearer_response)+ strlen (sim_data); - response.user_id = request->user_id; - response.rab_id = request->rab_id; - response.tx_id = request->tx_id; - response.status = REMOVE_RADIO_ACCESS_BEARER_SUCCESSFUL; - - //count = rtf_put (protocol_bs->rrc.rc_rrm.output_fifo, (uint8_t *) & rpc_mess, sizeof (rpc_message)); - //count = rtf_put (protocol_bs->rrc.rc_rrm.output_fifo, (uint8_t *) & confirm, sizeof (add_user_confirm)); - count = write(rrc_rg_rrm_in_fifo, (uint8_t *) & rpc_mess, sizeof (rpc_message)); - count += write(rrc_rg_rrm_in_fifo, (uint8_t *) & response, sizeof (remove_radio_access_bearer_response)); - count += write(rrc_rg_rrm_in_fifo, (uint8_t *) sim_data, strlen (sim_data)); - - if (count > 0) { - printf ("RRM message sent successfully on RRM FIFO, length: %d\n", count); - } else { - printf ("RRM FIFO transmit failed"); - } - - usleep (20000); //wait 5ms - // stop q measurement for MT - nasrg_meas_q_release (request->user_id, &control); - nasrg_send_meas_request_to_rrc (request->user_id, &control); -} - - -//----------------------------------------------------------------------------- -// Check if anything in RRC FIFO and send it to RRM -void nasrg_rrm_from_rrc_read (void) -{ - //----------------------------------------------------------------------------- - char rcve_buffer[RRM_MSG_MAX_LENGTH]; - int rpc_header_size=0; - int count = 0; - rpc_message *rrc_rrm_mess; - char *rrc_rrm_meas_payload; - - memset (rcve_buffer, 0, RRM_MSG_MAX_LENGTH - 1); - rpc_header_size = sizeof (rpc_message); - rrc_rrm_mess = (rpc_message *) rcve_buffer; - - if ((count = read (rrc_rg_rrm_out_fifo, rcve_buffer, rpc_header_size)) > 0) { - //printf("\n RRM FIFO %d, bytes count %d", rrc_rg_rrm_out_fifo, count); -#ifdef DEBUG_RRC_RRM_INTF - printf ("\n [DEBUG]Message Received in RRM FIFO %d , length %d, type %d \n", rrc_rg_rrm_out_fifo, rrc_rrm_mess->length, rrc_rrm_mess->type); -#endif - //get the rest of the primitive - count += read (rrc_rg_rrm_out_fifo, &(rcve_buffer[rpc_header_size]), rrc_rrm_mess->length ); - - switch (rrc_rrm_mess->type) { - case RPC_CONNECTION_REQUEST: - printf ("\n[CELL-RRM]Received RPC_CONNECTION_REQUEST, length %d\n", rrc_rrm_mess->length); - rrm_connection_response(); - break; - - case RPC_ADD_USER_REQUEST: - printf ("\n[CELL-RRM]Received RPC_ADD_USER_REQUEST, length %d\n", rrc_rrm_mess->length); - rrm_add_user_response(&(rcve_buffer[rpc_header_size])); - break; - - case RPC_REMOVE_USER_REQUEST: - printf ("\n[CELL-RRM]Received RPC_REMOVE_USER_REQUEST, length %d\n", rrc_rrm_mess->length); - rrm_remove_user_response(&(rcve_buffer[rpc_header_size])); - break; - - case RPC_ADD_RADIO_ACCESS_BEARER_REQUEST: - printf ("\n[CELL-RRM]Received RPC_ADD_RADIO_ACCESS_BEARER_REQUEST, length %d\n", rrc_rrm_mess->length); - rrm_add_radio_access_bearer_response(&(rcve_buffer[rpc_header_size])); - break; - - case RPC_REMOVE_RADIO_ACCESS_BEARER_REQUEST: - printf ("\n[CELL-RRM]Received RPC_REMOVE_RADIO_ACCESS_BEARER_REQUEST, length %d\n", rrc_rrm_mess->length); - rrm_remove_radio_access_bearer_response(&(rcve_buffer[rpc_header_size])); - break; - - case RPC_ADD_USER_CONFIRM: - printf ("\n[CELL-RRM]Received RPC RPC_ADD_USER_CONFIRM , length %d\n", rrc_rrm_mess->length); - break; - - case RPC_ADD_RADIO_ACCESS_BEARER_CONFIRM: - printf ("\n[CELL-RRM]Received RPC RPC_ADD_RADIO_ACCESS_BEARER_CONFIRM , length %d\n", rrc_rrm_mess->length); - //rrm_add_measurement_request(&(rcve_buffer[rpc_header_size])); - break; - - case RPC_L1_MEASUREMENT_RG_INTERNAL_REPORT: - case RPC_L1_MEASUREMENT_RG_QUALITY_REPORT: - case RPC_L1_MEASUREMENT_RG_TRAFFIC_VOLUME_REPORT: - rrc_rrm_meas_payload = (char *)rcve_buffer +12; //12 = rpc_header + equipment_id - //nas_rg_print_buffer (rrc_rrm_meas_payload, rrc_rrm_mess->length); - nasrg_print_bs_meas_report (rrc_rrm_meas_payload,rrc_rrm_mess->type); - break; - - case RPC_L1_MEASUREMENT_MT_INTERNAL_REPORT: - case RPC_L1_MEASUREMENT_MT_QUALITY_REPORT: - case RPC_L1_MEASUREMENT_MT_TRAFFIC_VOLUME_REPORT: - case RPC_L1_MEASUREMENT_MT_INTRA_FREQUENCY_REPORT: - rrc_rrm_meas_payload = (char *)rcve_buffer +12; //12 = rpc_header + equipment_id - //nas_rg_print_buffer (rrc_rrm_meas_payload, rrc_rrm_mess->length); - nasrg_print_meas_report (rrc_rrm_meas_payload,rrc_rrm_mess->type); - break; - - default: - break; - } - - fflush(stdout); - } -} - - -//----------------------------------------------------------------------------- -int main (int argc, char **argv) -{ - //----------------------------------------------------------------------------- - int time = 0; - // int rc, sd_rrm; - // fd_set readfds; - // struct timeval tv; - tXmit_id =0; - nasrg_rrm_fifos_init (); - printf ("[RRM] RRM FIFOs ready\n"); - fflush(stdout); - - while (1) { - usleep (100000); - time ++; - //printf ("\n[RRM_TEST] Simu Measurement Time at Main: %d\n", time); - - // check RRM FIFO - nasrg_rrm_from_rrc_read(); - } -} diff --git a/openair2/NETWORK_DRIVER/LITE/Makefile b/openair2/NETWORK_DRIVER/LITE/Makefile deleted file mode 100755 index 76ba3b5bdb..0000000000 --- a/openair2/NETWORK_DRIVER/LITE/Makefile +++ /dev/null @@ -1,72 +0,0 @@ -# NASMESH Driver makefile -# -include $(OPENAIR_DIR)/common/utils/Makefile.inc -NAS_UPDIR := $(shell /bin/pwd) - -KERNEL_ARCH:=$(shell echo `uname -m`) -SET_X64:=$(shell if [ $(KERNEL_ARCH) = 'x86_64' ]; then echo true ; fi) - -#################################################### -# EXTRA COMPILER FLAGS -#################################################### -EXTRA_CFLAGS = -I$(OPENAIR2_DIR)/COMMON -fno-common -fno-stack-protector -mpreferred-stack-boundary=4 $(if $(SET_X64),-DARCH_64,) $(if $(SET_X64),-mcmodel=kernel,) - -ifdef ADDRCONF -EXTRA_CFLAGS += -DADDRCONF -endif - -ifdef OAI_NW_DRIVER_TYPE_ETHERNET -EXTRA_CFLAGS += -DOAI_NW_DRIVER_TYPE_ETHERNET -endif - -ifdef OAI_NW_DRIVER_USE_NETLINK -EXTRA_CFLAGS += -DOAI_NW_DRIVER_USE_NETLINK -else -EXTRA_CFLAGS += $(shell rtai-config --module-cflags) -DRTAI -D__IN_RTAI__ -Wall -endif - -ccflags-y= $(CFLAGS) $(EXTRA_CFLAGS) -CFLAGS= - -ifdef LOOPBACK -EXTRA_CFLAGS += -DLOOPBACK_TEST -endif - -ifdef ADDRESS_FIX -EXTRA_CFLAGS += -DNAS_ADDRESS_FIX -endif - -#################################################### -# LOADABLE MODULE GOALS -#################################################### -obj-m += oai_nw_drv.o -oai_nw_drv-objs += device.o -oai_nw_drv-objs += common.o -oai_nw_drv-objs += ioctl.o -oai_nw_drv-objs += classifier.o -oai_nw_drv-objs += tool.o -ifdef OAI_NW_DRIVER_USE_NETLINK -oai_nw_drv-objs += netlink.o -endif - -#################################################### -# REVOIR LE CLEAN -#################################################### - -#netlink.ko: - #make $(x)$(y) PDCP_USE_NETLINK=1 V=1 -C $(KERNEL_DIR) M=`pwd` modules - -#oai_nw_drv.ko: -# make V=1 -C $(KERNEL_DIR) M=`pwd` modules -print: - @echo subversion : $(SUBVERSION) -clean: - rm -f *.ko - rm -f .*.ko.cmd - rm -f .*.o.cmd - rm -f *.o - rm -f *.mod.c - find . -name *.ko -delete - find . -name .*.o -delete - find . -name *.o -delete - find . -name *.mod.c -delete diff --git a/openair2/NETWORK_DRIVER/LITE/device.c b/openair2/NETWORK_DRIVER/LITE/device.c index fe60d82c15..854c3bcc99 100644 --- a/openair2/NETWORK_DRIVER/LITE/device.c +++ b/openair2/NETWORK_DRIVER/LITE/device.c @@ -28,13 +28,6 @@ */ /*******************************************************************************/ -#ifndef OAI_NW_DRIVER_USE_NETLINK -#ifdef RTAI -#include "rtai_posix.h" -#define RTAI_IRQ 30 //try to get this irq with RTAI -#endif // RTAI -#endif // OAI_NW_DRIVER_USE_NETLINK - #include "constant.h" #include "local.h" #include "proto_extern.h" @@ -519,23 +512,12 @@ int init_module (void) #ifndef OAI_NW_DRIVER_USE_NETLINK -#ifdef RTAI //with RTAI you have to indicate which irq# you want - - pdcp_2_oai_nw_drv_irq=rt_request_srq(0, oai_nw_drv_interrupt, NULL); - -#endif - if (pdcp_2_oai_nw_drv_irq == -EBUSY || pdcp_2_oai_nw_drv_irq == -EINVAL) { printk("[OAI_IP_DRV][%s] No interrupt resource available\n", __FUNCTION__); return -EBUSY; } else printk("[OAI_IP_DRV][%s] Interrupt %d\n", __FUNCTION__, pdcp_2_oai_nw_drv_irq); - //rt_startup_irq(RTAI_IRQ); - - //rt_enable_irq(RTAI_IRQ); - - #endif //NETLINK for (inst=0; instirq, NULL); - // END V1 - rt_free_srq(pdcp_2_oai_nw_drv_irq); -#endif // Start IRQ linux //free_irq(priv->irq, NULL); // End IRQ linux diff --git a/openair2/NETWORK_DRIVER/MESH/Makefile b/openair2/NETWORK_DRIVER/MESH/Makefile deleted file mode 100755 index f4bf87f318..0000000000 --- a/openair2/NETWORK_DRIVER/MESH/Makefile +++ /dev/null @@ -1,70 +0,0 @@ -# NASMESH Driver makefile -# -include $(OPENAIR_DIR)/common/utils/Makefile.inc -NAS_UPDIR := $(shell /bin/pwd) - -#################################################### -# NASMESH compilation flags -#################################################### -#RTAI=1 - -#################################################### -# D E B U G F L A G S -#################################################### - -#################################################### -# EXTRA COMPILER FLAGS -#################################################### -#EXTRA_CFLAGS = -fno-common -fno-stack-protector -mpreferred-stack-boundary=4 $(if $(SET_X64),-DARCH_64,) $(if $(SET_X64),-mcmodel=kernel,) $(if $(SET_X64),-m64,) -EXTRA_CFLAGS += -I$(OPENAIR2_DIR) -ifdef PDCP_USE_NETLINK -EXTRA_CFLAGS += -DPDCP_USE_NETLINK -else -EXTRA_CFLAGS += $(shell rtai-config --module-cflags) -DRTAI -D__IN_RTAI__ -Wall -endif - -ifdef LOOPBACK -EXTRA_CFLAGS += -DLOOPBACK_TEST -endif - -ifdef ADDRESS_FIX -EXTRA_CFLAGS += -DNAS_ADDRESS_FIX -endif -ifdef NAS_DEBUG_RECEIVE -EXTRA_CFLAGS += -DNAS_DEBUG_RECEIVE -endif - -ifdef NAS_DEBUG_SEND -EXTRA_CFLAGS += -DNAS_DEBUG_SEND -endif - -ccflags-y := $(CFLAGS) $(EXTRA_CFLAGS) -CFLAGS= - -#################################################### -# LOADABLE MODULE GOALS -#################################################### -obj-m += nasmesh.o -nasmesh-objs += device.o -nasmesh-objs += common.o -nasmesh-objs += ioctl.o -nasmesh-objs += classifier.o -nasmesh-objs += tool.o -nasmesh-objs += mesh.o -ifdef PDCP_USE_NETLINK -nasmesh-objs += netlink.o -endif - -#################################################### -# REVOIR LE CLEAN -#################################################### - -#netlink.ko: -# make PDCP_USE_NETLINK=1 V=1 -C $(KERNEL_DIR) M=`pwd` modules - -#nasmesh.ko: -# make V=1 -C $(KERNEL_DIR) M=`pwd` modules - -clean: - rm -f $(nasmesh-objs) $(obj-m) -# make -C $(KERNEL_DIR) modules diff --git a/openair2/NETWORK_DRIVER/MESH/common.c b/openair2/NETWORK_DRIVER/MESH/common.c index 0eb7530ee6..d380b8a4d8 100644 --- a/openair2/NETWORK_DRIVER/MESH/common.c +++ b/openair2/NETWORK_DRIVER/MESH/common.c @@ -28,12 +28,8 @@ * \email: navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr */ -//#include "nas_common.h" #include "local.h" #include "proto_extern.h" -#ifdef RTAI -#include "rtai_fifos.h" -#endif //#define NAS_DEBUG_RECEIVE 1 //#define NAS_DEBUG_SEND 1 diff --git a/openair2/NETWORK_DRIVER/MESH/device.c b/openair2/NETWORK_DRIVER/MESH/device.c index f9bc592bce..086ec3909c 100644 --- a/openair2/NETWORK_DRIVER/MESH/device.c +++ b/openair2/NETWORK_DRIVER/MESH/device.c @@ -28,13 +28,6 @@ */ /*******************************************************************************/ -#ifndef PDCP_USE_NETLINK -#ifdef RTAI -#include "rtai_posix.h" -#define RTAI_IRQ 30 //try to get this irq with RTAI -#endif // RTAI -#endif // PDCP_USE_NETLINK - #include "constant.h" #include "local.h" #include "proto_extern.h" @@ -116,6 +109,7 @@ void *nas_interrupt(void) printk("INTERRUPT: end\n"); #endif // return 0; + return NULL; } #endif //NETLINK @@ -449,23 +443,12 @@ int init_module (void) #ifndef PDCP_USE_NETLINK -#ifdef RTAI //with RTAI you have to indicate which irq# you want - - pdcp_2_nas_irq=rt_request_srq(0, nas_interrupt, NULL); - -#endif - if (pdcp_2_nas_irq == -EBUSY || pdcp_2_nas_irq == -EINVAL) { printk("[NAS][INIT] No interrupt resource available\n"); return -EBUSY; } else printk("[NAS][INIT]: Interrupt %d\n", pdcp_2_nas_irq); - //rt_startup_irq(RTAI_IRQ); - - //rt_enable_irq(RTAI_IRQ); - - #endif //NETLINK for (inst=0; instirq, NULL); - // END V1 - rt_free_srq(pdcp_2_nas_irq); -#endif // Start IRQ linux // free_irq(priv->irq, NULL); // End IRQ linux diff --git a/openair2/NETWORK_DRIVER/UE_IP/Makefile b/openair2/NETWORK_DRIVER/UE_IP/Makefile deleted file mode 100755 index fbcf85fabb..0000000000 --- a/openair2/NETWORK_DRIVER/UE_IP/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -# UE IP Driver makefile -# -NAS_UPDIR := $(shell /bin/pwd) - -KERNEL_ARCH=$(shell echo `uname -m`) -SET_X64=$(shell if [ $(KERNEL_ARCH) = 'x86_64' ]; then echo true ; fi) - -#################################################### -# EXTRA COMPILER FLAGS -#################################################### -EXTRA_CFLAGS = -I$(OPENAIR2_DIR)/COMMON -fno-common -fno-stack-protector -mpreferred-stack-boundary=4 $(if $(SET_X64),-DARCH_64,) $(if $(SET_X64),-mcmodel=kernel,) $(if $(SET_X64),-m64,) - - - -ifdef OAI_NW_DRIVER_USE_NETLINK -EXTRA_CFLAGS += -DOAI_NW_DRIVER_USE_NETLINK -else -EXTRA_CFLAGS += $(shell rtai-config --module-cflags) -DRTAI -D__IN_RTAI__ -Wall -endif - - -#################################################### -# LOADABLE MODULE GOALS -#################################################### -obj-m += ue_ip.o -ue_ip-objs += device.o -ue_ip-objs += common.o -ifdef OAI_NW_DRIVER_USE_NETLINK -ue_ip-objs += netlink.o -endif - -#################################################### -# REVOIR LE CLEAN -#################################################### - - -print: - @echo SET_X64 : $(SET_X64) - -clean: - rm -f *.ko - rm -f .*.ko.cmd - rm -f .*.o.cmd - rm -f *.o - rm -f *.mod.c - find . -name *.ko -delete - find . -name .*.o -delete - find . -name *.o -delete - find . -name *.mod.c -delete diff --git a/openair2/NETWORK_DRIVER/UE_IP/device.c b/openair2/NETWORK_DRIVER/UE_IP/device.c index a4398e9d9e..29db4ae07a 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/device.c +++ b/openair2/NETWORK_DRIVER/UE_IP/device.c @@ -28,13 +28,6 @@ */ /*******************************************************************************/ -#ifndef OAI_NW_DRIVER_USE_NETLINK -#ifdef RTAI -#include "rtai_posix.h" -#define RTAI_IRQ 30 //try to get this irq with RTAI -#endif // RTAI -#endif // OAI_NW_DRIVER_USE_NETLINK - #include "constant.h" #include "local.h" #include "proto_extern.h" diff --git a/openair2/RRC/LITE/MESSAGES/Makefile b/openair2/RRC/LITE/MESSAGES/Makefile deleted file mode 100644 index bd99081ad2..0000000000 --- a/openair2/RRC/LITE/MESSAGES/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -include $(OPENAIR_DIR)/common/utils/Makefile.inc -OPENAIR2_TOP = ../../.. -include $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/Makefile.inc - - -EXTRA_CFLAGS += -I$(OPENAIR1_DIR) -I/usr/realtime/include -D__need_Emath -D__NO_ASSERT_H__ - -ifdef RTAI -# Get the RTAI variables -CCC = $(shell rtai-config --cc) -RTAI_SUBVERSION=$(shell rtai-config --version | sed -e 's/^..\(.\).*$$/\1/') -IS_RTAI_SUBVERSION_LESS_THAN_FIVE=$(shell if [ $(RTAI_SUBVERSION) -lt 5 ] ; then echo true ; fi) - -EXTRA_CFLAGS += -D__IN_RTAI__ $(shell rtai-config --module-cflags) -g -march=pentium4 -DNODE_RG -DBIGPHYSAREA -DRTAI -DRTAI_ENABLED -fno-stack-protector -DHW_PREFIX_REMOVAL -Wall -D__KERNEL__ -DMODULE -D_LOOSE_KERNEL_NAMES -DWIDENS_DLC -I$(KERNEL_DIR)/build/include -I$(KERNEL_DIR)/build/include/asm/mach-default -include $(KERNEL_DIR)/build/include/linux/autoconf.h $(if $(IS_RTAI_SUBVERSION_LESS_THAN_FIVE),-DRTAI_ISNT_POSIX,) -endif - - -obj-m = asn1_msg_kern.o -asn1_msg_kern-objs = $(ASN1_CONVERTER_OBJS) $(ASN1_MODULE_OBJS) bsearch.o rtai_mem.o - -clean: - rm -rf $(asn1_msg_kern-objs) $(obj-m) - -test: - echo $(asn1_msg_kern-objs) $(obj-m) - -regen: regenerate-from-asn1-source - -regenerate-from-asn1-source: - asn1c -gen-PER -fcompound-names -fnative-types -fskeletons-copy asn1c/ASN1_files/EUTRA-RRC-Definitions.asn - diff --git a/openair2/RRC/LITE/MESSAGES/rtai_mem.c b/openair2/RRC/LITE/MESSAGES/rtai_mem.c deleted file mode 100644 index c522a1f0bf..0000000000 --- a/openair2/RRC/LITE/MESSAGES/rtai_mem.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file rtai_mem.c -* \brief a wrapper for Unified RTAI real-time memory management. -* \author Florian Kaltenberger -* \date 2011-04-06 -* \version 0.1 -* \company Eurecom -* \email: florian.kaltenberger@eurecom.fr -* \note -* \bug -* \warning -*/ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -//#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include - -/* -void* rt_alloc_wrapper(int size) { - - unsigned long* tmp_ptr; - static unsigned long name = 0; - - rt_shm_free(name); - tmp_ptr = (unsigned long*) rt_shm_alloc(name,size+sizeof(unsigned long),GFP_KERNEL); - - if (!tmp_ptr) { - printk("rt_mem.c: failed to allocate %d bytes for name %ld at %p\n",size,name,tmp_ptr); - return NULL; - } - - printk("rt_mem.c: allocated %d bytes for name %ld at %p\n",size,name,tmp_ptr+1); - - tmp_ptr[0] = name; - name++; - - return (void*) (tmp_ptr+1); - -} - -int rt_free_wrapper(void* ptr) { - - unsigned long name; - - printk("rt_mem.c: freeing memory at %p, ",ptr); - - name = *(((unsigned long*) ptr)-1); - - printk("name %ld\n",name); - - return rt_shm_free(name); - -} - -void* rt_realloc_wrapper(void* oldptr, int size) { - - void* newptr; - - printk("rt_mem.c: reallocating %p with %d bytes\n",oldptr,size); - - if (oldptr==NULL) - newptr = rt_alloc_wrapper(size); - else { - newptr = rt_alloc_wrapper(size); - memcpy(newptr,oldptr,size); - rt_free_wrapper(oldptr); - } - - return newptr; -} -*/ - -void* rt_realloc(void* oldptr, int size) -{ - - void* newptr; - - printk("rt_mem.c: reallocating %p with %d bytes\n",oldptr,size); - - if (oldptr==NULL) { - newptr = rt_malloc(size); - } else { - newptr = rt_malloc(size); - memcpy(newptr,oldptr,size); - rt_free(oldptr); - } - - return newptr; -} - -void* rt_calloc(int nmemb, int size) -{ - - void* newptr; - - printk("rt_mem.c: allocating %d elements with %d bytes\n",nmemb,size); - - newptr = rt_malloc(nmemb*size); - memset(newptr,0,nmemb*size); - - return newptr; -} diff --git a/openair2/RRC/LITE/MESSAGES/rtai_mem.h b/openair2/RRC/LITE/MESSAGES/rtai_mem.h deleted file mode 100644 index 9efc24851f..0000000000 --- a/openair2/RRC/LITE/MESSAGES/rtai_mem.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file rtai_mem.h -* \brief a wrapper for Unified RTAI real-time memory management. -* \author Florian Kaltenberger -* \date 2011-04-06 -* \version 0.1 -* \company Eurecom -* \email: florian.kaltenberger@eurecom.fr -* \note -* \bug -* \warning -*/ - -/* -void* rt_alloc_wrapper(int size); - -int rt_free_wrapper(void* ptr); - -void* rt_realloc_wrapper(void* oldptr, int size); -*/ - -void* rt_realloc(void* oldptr, int size); - -void* rt_calloc(int nmemb, int size); diff --git a/openair2/RRC/LITE/mesh_top.c b/openair2/RRC/LITE/mesh_top.c deleted file mode 100644 index a2b4e0f7d0..0000000000 --- a/openair2/RRC/LITE/mesh_top.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*________________________openair_rrc_top.c________________________ - - Authors : Hicham Anouar - Company : EURECOM - Emails : anouar@eurecom.fr -________________________________________________________________*/ - - -#include "defs.h" -#include "vars.h" - -extern MAC_RLC_XFACE* mac_rrc_register(RRC_XFACE*); -extern int mac_rrc_unregister(RRC_XFACE *); - -extern void *bigphys_malloc(int); - - - diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index bae76203c6..d66025301f 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -62,10 +62,6 @@ #include "TDD-Config.h" #include "UECapabilityEnquiry.h" #include "UE-CapabilityRequest.h" -#ifdef PHY_ABSTRACTION -#include "OCG.h" -#include "OCG_extern.h" -#endif #include "RRC/NAS/nas_config.h" #include "RRC/NAS/rb_config.h" #if ENABLE_RAL @@ -728,13 +724,8 @@ rrc_ue_establish_drb( */ #ifdef PDCP_USE_NETLINK # if !defined(OAI_NW_DRIVER_TYPE_ETHERNET) && !defined(EXMIMO) && !defined(OAI_USRP) && !defined(OAI_BLADERF) && !defined(ETHERNET) && !defined(LINK_ENB_PDCP_TO_GTPV1U) -# ifdef OAI_EMU - ip_addr_offset3 = oai_emulation.info.nb_enb_local; - ip_addr_offset4 = NB_eNB_INST; -# else ip_addr_offset3 = 0; ip_addr_offset4 = 8; -# endif LOG_I(OIP,"[UE %d] trying to bring up the OAI interface oai%d, IP 10.0.%d.%d\n", ue_mod_idP, ip_addr_offset3+ue_mod_idP, ip_addr_offset3+ue_mod_idP+1,ip_addr_offset4+ue_mod_idP+1); oip_ifup=nas_config(ip_addr_offset3+ue_mod_idP, // interface_id @@ -742,9 +733,6 @@ rrc_ue_establish_drb( ip_addr_offset4+ue_mod_idP+1); // fourth_octet if (oip_ifup == 0 ) { // interface is up --> send a config the DRB -# ifdef OAI_EMU - oai_emulation.info.oai_ifup[ue_mod_idP]=1; -# endif LOG_I(OIP,"[UE %d] Config the oai%d to send/receive pkt on DRB %ld to/from the protocol stack\n", ue_mod_idP, ip_addr_offset3+ue_mod_idP, @@ -760,10 +748,6 @@ rrc_ue_establish_drb( LOG_D(RRC,"[UE %d] State = Attached (eNB %d)\n",ue_mod_idP,eNB_index); } -# else -# ifdef OAI_EMU - oai_emulation.info.oai_ifup[ue_mod_idP]=1; -# endif # endif #endif @@ -1538,17 +1522,6 @@ rrc_ue_process_radioResourceConfigDedicated( UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State = RRC_CONNECTED; LOG_I(RRC,"[UE %d] State = RRC_CONNECTED (eNB %d)\n",ctxt_pP->module_id,eNB_index); -#if !defined(ENABLE_USE_MME) && defined(OAI_EMU) -# ifdef OAI_EMU - rrc_eNB_emulation_notify_ue_module_id( - ctxt_pP->module_id, - ctxt_pP->rnti, - UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index]->cellAccessRelatedInfo.cellIdentity.buf[0], - UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index]->cellAccessRelatedInfo.cellIdentity.buf[1], - UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index]->cellAccessRelatedInfo.cellIdentity.buf[2], - UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index]->cellAccessRelatedInfo.cellIdentity.buf[3]); -# endif /* OAI_EMU */ -#endif } diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index e4c162d5f7..5a127fdfd7 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -796,14 +796,6 @@ rrc_eNB_free_UE(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_s* * in order to allow the UE to perform the NAS recovery * procedure, see TS 23.401 [17]. */ -#else -#if defined(OAI_EMU) - AssertFatal(ue_context_pP->local_uid < NUMBER_OF_UE_MAX, "local_uid invalid (%d<%d) for UE %x!", ue_context_pP->local_uid, NUMBER_OF_UE_MAX, rnti); - ue_module_id = oai_emulation.info.eNB_ue_local_uid_to_ue_module_id[enb_mod_idP][ue_context_pP->local_uid]; - AssertFatal(ue_module_id < NUMBER_OF_UE_MAX, "ue_module_id invalid (%d<%d) for UE %x!", ue_module_id, NUMBER_OF_UE_MAX, rnti); - oai_emulation.info.eNB_ue_local_uid_to_ue_module_id[enb_mod_idP][ue_context_pP->local_uid] = -1; - oai_emulation.info.eNB_ue_module_id_to_rnti[enb_mod_idP][ue_module_id] = NOT_A_RNTI; -#endif #endif rrc_mac_remove_ue(enb_mod_idP,rnti); @@ -3559,12 +3551,7 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( ctxt_pP->module_id + 1); // fourth octet if (oip_ifup == 0) { // interface is up --> send a config the DRB -# ifdef OAI_EMU - oai_emulation.info.oai_ifup[ctxt_pP->module_id] = 1; - dest_ip_offset = NB_eNB_INST; -# else dest_ip_offset = 8; -# endif LOG_I(OIP, "[eNB %d] Config the oai%d to send/receive pkt on DRB %ld to/from the protocol stack\n", ctxt_pP->module_id, ctxt_pP->module_id, @@ -3581,10 +3568,6 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( ctxt_pP->module_id, ue_context_pP->ue_context.rnti, ue_module_id); } -# else -# ifdef OAI_EMU - oai_emulation.info.oai_ifup[ctxt_pP->module_id] = 1; -# endif # endif #endif diff --git a/openair2/UTIL/LOG/log.c b/openair2/UTIL/LOG/log.c index 887ce5bff6..2c66f79521 100644 --- a/openair2/UTIL/LOG/log.c +++ b/openair2/UTIL/LOG/log.c @@ -44,13 +44,6 @@ # include # include -#ifdef RTAI -# include -# include -# define FIFO_PRINTF_MAX_STRING_SIZE 1000 -# define FIFO_PRINTF_NO 62 -# define FIFO_PRINTF_SIZE 65536 -#endif #include "common/config/config_userapi.h" // main log variables log_t *g_log; @@ -90,9 +83,7 @@ int log_list_head = 0; int log_shutdown; #endif -#ifndef RTAI static int gfd; -#endif static char *log_level_highlight_start[] = {LOG_RED, LOG_RED, LOG_RED, LOG_RED, LOG_ORANGE, LOG_BLUE, "", ""}; /*!< \brief Optional start-format strings for highlighting */ static char *log_level_highlight_end[] = {LOG_RESET, LOG_RESET, LOG_RESET, LOG_RESET, LOG_RESET,LOG_RESET, "",""}; /*!< \brief Optional end-format strings for highlighting */ @@ -162,9 +153,7 @@ void log_getconfig(log_t *g_log) { int logInit (void) { -#ifndef RTAI int i; -#endif g_log = calloc(1, sizeof(log_t)); if (g_log == NULL) { @@ -473,7 +462,6 @@ int logInit (void) g_log->level = LOG_TRACE; g_log->flag = LOG_LOW; -#ifndef RTAI g_log->config.remote_ip = 0; g_log->config.remote_level = LOG_EMERG; g_log->config.facility = LOG_LOCAL7; @@ -501,12 +489,6 @@ int logInit (void) } } -#else - g_log->syslog = 0; - g_log->filelog = 0; - rtf_create (FIFO_PRINTF_NO, FIFO_PRINTF_SIZE); -#endif - printf("log init done\n"); return 0; @@ -634,23 +616,9 @@ void logRecord_thread_safe(const char *file, const char *func, // OAI printf compatibility if ((g_log->onlinelog == 1) && (level != LOG_FILE)) { -#ifdef RTAI - - if (len > MAX_LOG_TOTAL) { - rt_printk ("[OPENAIR] FIFO_PRINTF WROTE OUTSIDE ITS MEMORY BOUNDARY : ERRORS WILL OCCUR\n"); - } - - if (len > 0) { - rtf_put (FIFO_PRINTF_NO, log_buffer, len); - } - -#else fprintf(stdout, "%s", log_buffer); -#endif } -#ifndef RTAI - if (g_log->syslog) { syslog(g_log->level, "%s", log_buffer); } @@ -667,8 +635,6 @@ void logRecord_thread_safe(const char *file, const char *func, } } -#endif - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD, VCD_FUNCTION_OUT); } @@ -818,20 +784,7 @@ void logRecord_mt(const char *file, const char *func, int line, int comp, // OAI printf compatibility if ((g_log->onlinelog == 1) && (level != LOG_FILE)) -#ifdef RTAI - if (len > MAX_LOG_TOTAL) { - rt_printk ("[OPENAIR] FIFO_PRINTF WROTE OUTSIDE ITS MEMORY BOUNDARY : ERRORS WILL OCCUR\n"); - } - - if (len > 0) { - rtf_put (FIFO_PRINTF_NO, c->log_buffer, len); - } - -#else fwrite(c->log_buffer, len, 1, stdout); -#endif - -#ifndef RTAI if (g_log->syslog) { syslog(g_log->level, "%s", c->log_buffer); @@ -849,15 +802,6 @@ void logRecord_mt(const char *file, const char *func, int line, int comp, } } -#else - - // online print messges - if ((g_log->log_component[comp].filelog) && (level == LOG_FILE)) { - printf(c->log_buffer); - } - -#endif - #if defined(ENABLE_ITTI) if (level <= LOG_DEBUG) { @@ -1116,20 +1060,7 @@ void logRecord_mt(const char *file, const char *func, int line, int comp, // OAI printf compatibility if ((g_log->onlinelog == 1) && (level != LOG_FILE)) -#ifdef RTAI - if (len > MAX_LOG_TOTAL) { - rt_printk ("[OPENAIR] FIFO_PRINTF WROTE OUTSIDE ITS MEMORY BOUNDARY : ERRORS WILL OCCUR\n"); - } - - if (len > 0) { - rtf_put (FIFO_PRINTF_NO, log_buffer, len); - } - -#else fwrite(log_buffer, len, 1, stdout); -#endif - -#ifndef RTAI if (g_log->syslog) { syslog(g_log->level, "%s", log_buffer); @@ -1147,15 +1078,6 @@ void logRecord_mt(const char *file, const char *func, int line, int comp, } } -#else - - // online print messges - if ((g_log->log_component[comp].filelog) && (level == LOG_FILE)) { - printf(log_buffer); - } - -#endif - #if defined(ENABLE_ITTI) if (level <= LOG_DEBUG) { @@ -1382,16 +1304,11 @@ void set_component_filelog(int comp) { if (g_log->log_component[comp].filelog == 0) { g_log->log_component[comp].filelog = 1; -#ifndef RTAI if (g_log->log_component[comp].fd == 0) { g_log->log_component[comp].fd = open(g_log->log_component[comp].filelog_name, O_WRONLY | O_CREAT | O_TRUNC, 0666); } - -#else - -#endif } } @@ -1447,9 +1364,6 @@ int is_newline( char *str, int size) void logClean (void) { -#ifdef RTAI - rtf_destroy (FIFO_PRINTF_NO); -#else int i; if (g_log->syslog) { @@ -1465,9 +1379,6 @@ void logClean (void) close(g_log->log_component[i].fd); } } - -#endif - } #if defined(ENABLE_ITTI) diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.c b/openair2/UTIL/LOG/vcd_signal_dumper.c index e0c20f9243..a9b91f3226 100644 --- a/openair2/UTIL/LOG/vcd_signal_dumper.c +++ b/openair2/UTIL/LOG/vcd_signal_dumper.c @@ -48,10 +48,6 @@ #include "vcd_signal_dumper.h" -#if defined(ENABLE_RTAI_CLOCK) -#include "rtai_lxrt.h" -#endif - #define VCDSIGNALDUMPER_VERSION_MAJOR 0 #define VCDSIGNALDUMPER_VERSION_MINOR 1 @@ -412,8 +408,6 @@ static inline unsigned long long int vcd_get_time(void); #if defined(ENABLE_USE_CPU_EXECUTION_TIME) struct timespec g_time_start; -#elif defined(ENABLE_RTAI_CLOCK) -RTIME start; #endif @@ -609,8 +603,6 @@ void vcd_signal_dumper_init(char *filename) #if defined(ENABLE_USE_CPU_EXECUTION_TIME) clock_gettime(CLOCK_MONOTONIC, &g_time_start); -#elif defined(ENABLE_RTAI_CLOCK) - start=rt_get_time_ns(); #endif vcd_signal_dumper_create_header(); @@ -663,9 +655,6 @@ static inline void vcd_signal_dumper_print_time_since_start(void) secondsSinceStart = (long long unsigned int)time.tv_sec - (long long unsigned int)g_time_start.tv_sec; /* Write time in nanoseconds */ fprintf(vcd_fd, "#%llu\n", nanosecondsSinceStart + (secondsSinceStart * 1000000000UL)); -#elif defined(ENABLE_RTAI_CLOCK) - /* Write time in nanoseconds */ - fprintf(vcd_fd, "#%llu\n",rt_get_time_ns()-start); #endif } } @@ -679,8 +668,6 @@ static inline unsigned long long int vcd_get_time(void) return (long long unsigned int)((time.tv_nsec - g_time_start.tv_nsec)) + ((long long unsigned int)time.tv_sec - (long long unsigned int)g_time_start.tv_sec) * 1000000000UL; -#elif defined(ENABLE_RTAI_CLOCK) - return rt_get_time_ns() - start; #endif } diff --git a/openair2/UTIL/MATH/taus.c b/openair2/UTIL/MATH/taus.c index 6e0fd84e66..632b1544dd 100644 --- a/openair2/UTIL/MATH/taus.c +++ b/openair2/UTIL/MATH/taus.c @@ -29,21 +29,12 @@ * @ingroup util */ -#ifndef RTAI_ENABLED #include #include #include #include #include #include "oml.h" -#else -#include -#include -#include -#include -#define time(x) (unsigned int)(rt_get_time_ns()) -#endif - unsigned int s0[MAX_NUM_COMPS], s1[MAX_NUM_COMPS], s2[MAX_NUM_COMPS], b[MAX_NUM_COMPS], r[MAX_NUM_COMPS]; diff --git a/openair2/UTIL/OCG/makefile b/openair2/UTIL/OCG/makefile index da28c888d4..578c2006cb 100644 --- a/openair2/UTIL/OCG/makefile +++ b/openair2/UTIL/OCG/makefile @@ -22,8 +22,6 @@ ifdef PDCP_USE_NETLINK CFLAGS += -DPDCP_USE_NETLINK -DLINUX -DDEBUG_CONTROL endif -CFLAGS += -DPHY_ABSTRACTION - #ifdef OCG CFLAGS += -I/usr/include/libxml2 -lxml2 #endif diff --git a/openair2/UTIL/OMG/makefile b/openair2/UTIL/OMG/makefile index 1fb0f3efd9..1aa3d2d451 100644 --- a/openair2/UTIL/OMG/makefile +++ b/openair2/UTIL/OMG/makefile @@ -75,8 +75,6 @@ ifdef PDCP_USE_NETLINK CFLAGS += -DPDCP_USE_NETLINK -DLINUX -DDEBUG_CONTROL endif -CFLAGS += -DPHY_ABSTRACTION - include $(OPENAIR1_DIR)/PHY/Makefile.inc include $(OPENAIR1_DIR)/SCHED/Makefile.inc include $(OPENAIR2_DIR)/LAYER2/Makefile.inc diff --git a/openair2/UTIL/OMG/makefile_old b/openair2/UTIL/OMG/makefile_old index 06d4a6f46f..aa622f8522 100644 --- a/openair2/UTIL/OMG/makefile_old +++ b/openair2/UTIL/OMG/makefile_old @@ -77,8 +77,6 @@ ifdef PDCP_USE_NETLINK CFLAGS += -DPDCP_USE_NETLINK -DLINUX -DDEBUG_CONTROL endif -CFLAGS += -DPHY_ABSTRACTION - include $(OPENAIR1_DIR)/PHY/Makefile.inc include $(OPENAIR1_DIR)/SCHED/Makefile.inc include $(OPENAIR2_DIR)/LAYER2/Makefile.inc diff --git a/openair2/UTIL/OPT/probe.c b/openair2/UTIL/OPT/probe.c index 711436d2cd..ebc52bb1e0 100644 --- a/openair2/UTIL/OPT/probe.c +++ b/openair2/UTIL/OPT/probe.c @@ -410,18 +410,8 @@ static int MAC_LTE_PCAP_WritePDU(MAC_Context_Info_t *context, /* PCAP Header */ /* TODO: Timestamp might want to be relative to a more sensible base time... */ -#if defined(RTAI) - { - unsigned long long int current_ns; - - current_ns = rt_get_time_ns(); - packet_header.ts_sec = current_ns / 1000000000UL; - packet_header.ts_usec = current_ns % 1000; - } -#else packet_header.ts_sec = context->subframesSinceCaptureStart / 1000; packet_header.ts_usec = (context->subframesSinceCaptureStart % 1000) * 1000; -#endif packet_header.incl_len = offset + length; packet_header.orig_len = offset + length; diff --git a/openair2/X2AP/x2ap.h b/openair2/X2AP/x2ap.h index 65529c7119..89e8540b97 100644 --- a/openair2/X2AP/x2ap.h +++ b/openair2/X2AP/x2ap.h @@ -33,10 +33,7 @@ typedef struct x2ap_config_s { } x2ap_config_t; -#if defined(OAI_EMU) -#else extern x2ap_config_t x2ap_config; -#endif void *x2ap_task(void *arg); diff --git a/openair3/S1AP/s1ap_eNB.c b/openair3/S1AP/s1ap_eNB.c index 08a18b629e..5b61f4ca79 100644 --- a/openair3/S1AP/s1ap_eNB.c +++ b/openair3/S1AP/s1ap_eNB.c @@ -65,10 +65,7 @@ #include "oaisim_mme_test_s1c.h" #endif - -#if !defined(OAI_EMU) s1ap_eNB_config_t s1ap_config; -#endif static int s1ap_eNB_generate_s1_setup_request( s1ap_eNB_instance_t *instance_p, s1ap_eNB_mme_data_t *s1ap_mme_data_p); diff --git a/openair3/S1AP/s1ap_eNB.h b/openair3/S1AP/s1ap_eNB.h index 85bf00a4fa..e122703d82 100644 --- a/openair3/S1AP/s1ap_eNB.h +++ b/openair3/S1AP/s1ap_eNB.h @@ -35,13 +35,9 @@ typedef struct s1ap_eNB_config_s { unsigned char mme_enabled; ///< MME enabled ? } s1ap_eNB_config_t; -#if defined(OAI_EMU) -# define EPC_MODE_ENABLED oai_emulation.info.s1ap_config.mme_enabled -#else extern s1ap_eNB_config_t s1ap_config; -# define EPC_MODE_ENABLED s1ap_config.mme_enabled -#endif +#define EPC_MODE_ENABLED s1ap_config.mme_enabled void *s1ap_eNB_task(void *arg); diff --git a/targets/Makefile b/targets/Makefile deleted file mode 100644 index b604898d2a..0000000000 --- a/targets/Makefile +++ /dev/null @@ -1,35 +0,0 @@ - - -build: - ./build_oai.bash -c -m - -build_rtai: - ./build_oai.bash -c -b -eRTAI -tSOFTMODEM -m - -build_usrp_rtai: - ./build_oai.bash -c -b -eRTAI -tSOFTMODEM -wUSRP -m - - -help: - @echo make check1 performs a simple sanity check - @echo make check2 performs another simple sanity check - @echo make check does both the above checks - -all: help - -check1: - @echo Doing 1 eNB 1 UE test - (cd SIMU/EXAMPLES/VIRT_EMUL_1eNB && make one_eNB_one_UE ) - -check2: - @echo Doing 1 eNB 4 UE test - (cd SIMU/EXAMPLES/VIRT_EMUL_1eNB && make one_eNB_four_UE ) - -install: - @echo Generating ASN1 files - @sh SCRIPTS/install_asn1.sh - -check: check1 check2 - -clean: - (cd SIMU/USER && make clean) diff --git a/targets/RT/Makefile b/targets/RT/Makefile deleted file mode 100644 index 1be49d2db8..0000000000 --- a/targets/RT/Makefile +++ /dev/null @@ -1,124 +0,0 @@ -# command line flags are automatically exported and thus passed down to any sub-make. -# here we set the default flags in case on command line flags are provided -# these flags have to be explicitely exported so that the sub-make is aware of them - - -include $(OPENAIR_DIR)/common/utils/Makefile.inc -ifndef OPENAIR_LTE -export OPENAIR_LTE=1 -export OPENAIR_EMU=0 -endif - -ifndef OPENAIR1 -export OPENAIR1=0 -endif - -ifndef OPENAIR2 -export OPENAIR2=0 -endif - -ifndef OPENAIR3 -export OPENAIR3=0 -endif - -ifndef EMOS -export EMOS=0 -endif - -ifndef rrc_cellular -export rrc_cellular = 0 -export rrc_cellular_eNB = 0 -export rrc_cellular_UE = 0 -else - export rrc_cellular = 1 - ifeq ($(eNB_flag),1) - export rrc_cellular_eNB=1 - endif - ifeq ($(UE_flag),1) - export rrc_cellular_UE=1 - endif -endif - -all: openair_rf_cbmimo1_softmodem.ko asn1_msg_kern.ko nasmesh.ko rb_tool openair_rf scope - -openair_rf_cbmimo1_softmodem.ko: - (cd $(OPENAIR1_DIR)/ARCH/CBMIMO1/DEVICE_DRIVER && $(MAKE) -C $(KERNEL_DIR)/build V=1 M=`pwd` RTAI=1 CBMIMO1=1 && mv openair_rf.ko $(CURDIR)/openair_rf_softmodem.ko) - -oai_user_cbmimo1.ko: - (cd $(OPENAIR1_DIR)/ARCH/CBMIMO1/DEVICE_DRIVER && $(MAKE) -C $(KERNEL_DIR)/build V=1 M=`pwd` RTAI=1 CBMIMO1=1 BIT8_TX=1 OPENAIR1=0 OPENAIR2=0 && mv openair_rf.ko $(CURDIR)/openair_rf_softmodem.ko) - -oai_user_exmimo.ko: - (cd $(OPENAIR1_DIR)/ARCH/CBMIMO1/DEVICE_DRIVER && $(MAKE) -C $(KERNEL_DIR)/build V=1 M=`pwd` RTAI=1 CBMIMO1=1 OPENAIR1=0 OPENAIR2=0 && mv openair_rf.ko $(CURDIR)/openair_rf_softmodem.ko) - -asn1_msg_kern.ko: - (cd $(OPENAIR2_DIR)/RRC/LITE/MESSAGES && $(MAKE) -C $(KERNEL_DIR)/build V=0 M=`pwd` RTAI=1 -j2 && mv asn1_msg_kern.ko $(CURDIR)/asn1_msg_kern.ko) - -nasmesh.ko: - (cd $(OPENAIR2_DIR)/NAS/DRIVER/MESH && $(MAKE) V=1 -C $(KERNEL_DIR)/build M=`pwd` && mv nasmesh.ko $(CURDIR)/nasmesh.ko) - -rb_tool: - (cd $(OPENAIR2_DIR)/NAS/DRIVER/MESH/RB_TOOL && $(MAKE)) - -openair_rf: - (cd $(OPENAIR1_DIR)/USERSPACE_TOOLS/OPENAIR_RF && $(MAKE) clean CBMIMO1=1 && $(MAKE) all CBMIMO1=1 && $(MAKE) clean CBMIMO1=1) - -scope: - (cd $(OPENAIR1_DIR)/USERSPACE_TOOLS/SCOPE && $(MAKE) clean && $(MAKE) all && $(MAKE) clean ) - -#Remove all but source files -cleanall: - (cd $(OPENAIR1_DIR) && $(MAKE) cleanall) - (cd $(OPENAIR2_DIR) && $(MAKE) cleanall) - -fifos: - @for i in `seq 0 64`;\ - do \ - have_rtfX=`ls /dev/ |grep -c rtf$$i`;\ - if [ "$$have_rtfX" -eq 0 ] ;then \ - mknod -m 666 /dev/rtf$$i c 150 $$i; \ - fi;\ - done - -openair0: - mknod /dev/openair0 c 127 0 - chmod a+rw /dev/openair0 - -install_oai_user: - make fifos - insmod openair_rf_softmodem.ko - -updatefw: - $(OPENAIR1_DIR)/USERSPACE_TOOLS/OAI_FW_INIT/updatefw -f $$OPENAIR0_DIR/express-mimo/software/sdr/main -s 0x43fffff0 - -boot_exmimo: - sudo make install_oai_user - $(OPENAIR1_DIR)/USERSPACE_TOOLS/OAI_FW_INIT/updatefw -f $$OPENAIR0_DIR/express-mimo/software/sdr/main -s 0x43fffff0 - sleep 1 - sudo rmmod openair_rf - sudo make install_oai_user - -reboot_exmimo: - $(OPENAIR1_DIR)/USERSPACE_TOOLS/OAI_FW_INIT/updatefw -f $$OPENAIR0_DIR/express-mimo/software/sdr/main -s 0x43fffff0 -b - sudo rmmod openair_rf - sudo make install_oai_user - -install_softmodem: - make fifos -ifeq ($(OPENAIR2),1) - insmod asn1_msg_kern.ko -endif - insmod openair_rf_softmodem.ko - -remove: - rmmod openair_rf -ifeq ($(OPENAIR2),1) - rmmod asn1_msg_kern -endif - -test: - (cd $(OPENAIR1_DIR)/ARCH/CBMIMO1/DEVICE_DRIVER && $(MAKE) test RTAI=1 CBMIMO1=1) - (cd $(OPENAIR2_DIR)/RRC/LITE/MESSAGES && $(MAKE) test) - -clean: - (cd $(OPENAIR1_DIR)/ARCH/CBMIMO1/DEVICE_DRIVER && $(MAKE) clean RTAI=1 CBMIMO1=1) - (cd $(OPENAIR2_DIR)/RRC/LITE/MESSAGES && $(MAKE) clean) diff --git a/targets/RT/USER/Makefile b/targets/RT/USER/Makefile deleted file mode 100644 index ae5e006d06..0000000000 --- a/targets/RT/USER/Makefile +++ /dev/null @@ -1,447 +0,0 @@ -# Include some shared directives -include $(OPENAIR_TARGETS)/Makerules - -default: lte-softmodem -all: lte-softmodem rrh - -include $(OPENAIR_TARGETS)/Makefile.common - -KERNEL_VERSION:=$(shell echo `uname -r | cut -d. -f-2`) -KERNEL_TYPE:=$(shell echo `uname -r | cut -d. -f-3 | cut -d- -f3`) -DEADLINE_SCHEDULER_KERNEL:=$(shell if [ $(KERNEL_TYPE) = "lowlatency" ]; then echo "1" ; else echo "0" ; fi) - -include $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/Makefile.inc - -ifdef EXMIMO -#ifdef DEADLINE_SCHEDULER # this ifdef is to be removed after the debugging -ifeq ($(DEADLINE_SCHEDULER_KERNEL),1) -CFLAGS+=-DDEADLINE_SCHEDULER -endif -#endif -endif - -ifndef USRP -USRP=0 -endif - -CFLAGS += -DDRIVER2013 -I$(OPENAIR_TARGETS)/ARCH/COMMON -I. - -ifndef OPENAIR2 -OPENAIR2=1 -endif - -ifdef DEBUG -DISABLE_XER_PRINT=0 -MSG_PRINT=1 -endif - -ifdef Rel10 -CFLAGS += -DRel10 -endif - -ifeq ($(EXMIMO),1) - CFLAGS += -I$(OPENAIR_TARGETS)/ARCH/EXMIMO/USERSPACE/LIB/ -I$(OPENAIR_TARGETS)/ARCH/EXMIMO/DEFS -DENABLE_VCD_FIFO -endif - -ifeq ($(ETHERNET),1) - CFLAGS += -I$(OPENAIR_TARGETS)/ARCH/ETHERNET/USERSPACE/LIB/ -DETHERNET -endif - -ifeq ($(DEBUG),1) -CFLAGS += -g -ggdb -#CFLAGS += -DRRC_MSG_PRINT -#CFLAGS += -DPDCP_MSG_PRINT -else -CFLAGS += -O2 -endif - -ifdef ($(MSG_PRINT),1) -CFLAGS += -DRRC_MSG_PRINT -CFLAGS += -DPDCP_MSG_PRINT -endif - -SRC = synctest.c condtest.c - -ifndef RTAI -RTAI=1 -endif - -ifeq ($(LOCALIZATION), 1) -CFLAGS += -DLOCALIZATION -endif - -ifeq ($(LINUX_LIST), 1) -CFLAGS += -DLINUX_LIST -endif - -ifeq ($(RTAI),1) -CFLAGS += -DENABLE_RTAI_CLOCK -CFLAGS += -DCONFIG_RTAI_LXRT_INLINE #remend the RTAI warning -RTAI_OBJ = sched_dlsch.o sched_rx_pdsch.o rt_wrapper.o -else #RTAI -CFLAGS += -DENABLE_USE_CPU_EXECUTION_TIME -OBJ += sched_dlsch.o sched_rx_pdsch.o rt_wrapper.o -endif - -OBJ += $(OPENAIR1_DIR)/SIMULATION/TOOLS/taus.o $(OPENAIR_TARGETS)/SIMU/USER/init_lte.o - -ifeq ($(EXMIMO),1) -OBJ += $(OPENAIR_TARGETS)/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.o $(OPENAIR_TARGETS)/ARCH/EXMIMO/USERSPACE/LIB/gain_control.o -CFLAGS += -DDRIVER2013 -I$(OPENAIR_TARGETS)/ARCH/EXMIMO/USERSPACE/LIB/ -I$(OPENAIR_TARGETS)/ARCH/EXMIMO/DEFS -endif - -CFLAGS += -DENABLE_VCD_FIFO - - -TOP_DIR = $(OPENAIR1_DIR) -include $(OPENAIR1_DIR)/PHY/Makefile.inc -include $(OPENAIR1_DIR)/SCHED/Makefile.inc - -OBJ += $(PHY_OBJS) -ifeq ($(RTAI),1) -RTAI_OBJ += $(SCHED_OBJS) -else -OBJ += $(SCHED_OBJS) -endif - -OPENAIR2_TOP = $(OPENAIR2_DIR) -include $(OPENAIR2_DIR)/LAYER2/Makefile.inc -include $(OPENAIR2_DIR)/UTIL/Makefile.inc -include $(OPENAIR2_DIR)/RRC/NAS/Makefile.inc -include $(OPENAIR2_DIR)/ENB_APP/Makefile.inc - -ifeq ($(USRP),1) - -include $(OPENAIR_TARGETS)/ARCH/USRP/USERSPACE/LIB/Makefile.inc -#CFLAGS += -I/opt/include/uhd -L/opt/lib -luhd -lpthread -lstdc++ -CFLAGS += -I/usr/include/uhd -L/usr/lib -luhd -lpthread -lstdc++ -CFLAGS += -DOAI_USRP -#LDFLAGS += -L/opt/lib -luhd -lpthread -lstdc++ -LDFLAGS += -L/usr/lib/ -luhd -lpthread -lstdc++ -endif - -ifeq ($(ETHERNET),1) -include $(OPENAIR_TARGETS)/ARCH/ETHERNET/USERSPACE/LIB/Makefile.inc -LDFLAGS += -lpthread -endif - -OBJ += $(ENB_APP_OBJS) - -ifeq ($(RTAI),1) -CFLAGS += -I/usr/realtime/include -I/usr/realtime/include/asm -LOG_OBJS= -RTAI_OBJ+=$(LOG_DIR)/vcd_signal_dumper.o -RTAI_OBJ+=$(LOG_DIR)/log.o -endif - - -OBJ += $(LOG_OBJS) - -ifeq ($(OPENAIR2),1) -ASN1_MSG_OBJS1=$(addprefix $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/, $(ASN1_MSG_OBJS)) -OBJ += $(L2_OBJS) $(LIST_OBJ) $(TIMER_OBJ) $(MEM_OBJ) $(OTG_OBJS) $(MATH_OBJS) $(OSA_OBJS) $(OPT_OBJS) -OBJ += $(OPENAIR1_DIR)/SIMULATION/ETH_TRANSPORT/netlink_init.o -#OBJ += $(PDCP_DIR)/pdcp_thread.o -CFLAGS += -DOPENAIR2 -DNO_RRM -DPUCCH -DMAC_CONTEXT=1 -endif - -#ifdef ENABLE_ITTI -RTAI_OBJ += $(UTILS_OBJS) -#else -#OBJ += $(UTILS_OBJS) -#endif - -ifdef SPECTRA -CFLAGS += -DSPECTRA -endif - -#ifdef ENABLE_ITTI -CFLAGS += -DEXMIMO_IOT -#endif - -CFLAGS += $(L2_incl) $(ENB_APP_incl) $(UTIL_incl) $(UTILS_incl) - -CFLAGS += -I$(OPENAIR1_DIR) -I$(OPENAIR2_DIR)/RRC/LITE/MESSAGES #-I$(OPENAIR3_DIR)/MESH -I$(OPENAIR3_DIR)/MESH/RRM - -CFLAGS += -DNEW_FFT -DLOG_NO_THREAD - -ifeq ($(XFORMS),1) -CFLAGS += -DXFORMS -I/usr/include/X11 -LDFLAGS += -lforms -OBJ += $(OPENAIR1_DIR)/PHY/TOOLS/lte_phy_scope.o -OBJ += stats.o -endif - -OBJ_SYNC = $(OPENAIR_TARGETS)/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.o rt_wrapper.o $(OPENAIR2_DIR)/UTIL/LOG/log.o $(OPENAIR2_DIR)/UTIL/LOG/vcd_signal_dumper.o - -ifdef SMBV -CFLAGS += -DSMBV -endif - -CFLAGS += -DPHYSIM -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DPHY_CONTEXT=1 -CFLAGS += -DOPENAIR_LTE -DENABLE_FXP -DOPENAIR1 #-DDLSCH_THREAD #-DULSCH_THREAD - - -ifeq ($(EXMIMO),1) -CFLAGS += -DEXMIMO -#CFLAGS += -DEXMIMO -DTIMING_ADVANCE_HW=138 #this is for ExpressMIMO 1 -#CFLAGS += -DEXMIMO -DTIMING_ADVANCE_HW=45 #this is for ExpressMIMO 2 -endif - -ifeq ($(HARD_RT),1) -CFLAGS += -DHARD_RT -endif - -ifeq ($(EMOS),1) -CFLAGS += -D_FILE_OFFSET_BITS=64 #-DEMOS -DEMOS_CHANNEL -LDFLAGS += -lgps -endif - - -ifeq ($(LINK_ENB_PDCP_TO_GTPV1U), 1) -CFLAGS += -DLINK_ENB_PDCP_TO_GTPV1U -endif - -ifeq ($(LINK_ENB_PDCP_TO_IP_DRIVER), 1) -CFLAGS += -DPDCP_USE_NETLINK -DLINUX -OBJ += $(NAS_OBJS) -NAS_FLAG=1 -endif - -LDFLAGS += -lpthread -lm -lforms -lconfig -lrt -ifeq ($(RTAI),1) -RTAI_CFLAGS += $(shell rtai-config --lxrt-cflags) -DRTAI -LDFLAGS += $(shell rtai-config --lxrt-ldflags) -endif - -#ifeq ($(USRP),1) -#CFLAGS += -I/opt/uhd/include -L/opt/uhd/lib -luhd -lpthread -lstdc++ -#CFLAGS += -DOAI_USRP -#endif -#CFLAGS += -I/usr/include/c++/4.6 -I/usr/include/c++/4.6/x86_64-linux-gnu -I/usr/include/rtai/ - -LFDS_OBJ_DIR = $(subst $(OPENAIR_DIR),$(OBJS_DIR),$(LFDS_DIR)) -LFDS_LIB = $(LFDS_OBJ_DIR)/bin/liblfds611.a -LIBS += $(LFDS_LIB) -SHARED_DEPENDENCIES += $(LFDS_LIB) - --include $(OBJ:.o=.d) --include $(ASN1_MSG_OBJS1:.o=.d) --include $(RTAI_OBJ:.o=.d) --include lte-softmodem.d --include lte-ue.d --include rrh.d - -$(LFDS_LIB): - @if [ ! -d $(LFDS_OBJ_DIR)/bin ]; then mkdir -p $(LFDS_OBJ_DIR)/bin; fi; - @if [ ! -d $(LFDS_OBJ_DIR)/obj ]; then mkdir -p $(LFDS_OBJ_DIR)/obj; fi; - $(MAKE) -C $(LFDS_DIR) -f makefile.linux OUTDIR=$(LFDS_OBJ_DIR) - -ifeq ($(USRP),1) -$(USRP_OBJ):$(USRP_FILE_OBJ) - @echo Compiling $< - @$(CXX) -c -g -ggdb $(USRP_CFLAGS) $(USRP_FILE_OBJ) -o $(USRP_OBJ) -endif - -ifeq ($(ETHERNET),1) -$(ETHERNET_OBJ):$(ETHERNET_FILE_OBJ) - @echo Compiling $< - @$(CC) -c -g -ggdb $(ETHERNET_CFLAGS) $(ETHERNET_FILE_OBJ) -o $(ETHERNET_OBJ) -endif - -ifeq ($(RTAI),1) -$(RTAI_OBJ) lte-softmodem.o lte-ue.o: %.o : %.c -else -$(RTAI_OBJ): %.o : %.c -endif - @echo Compiling $< ... - @$(CC) -c $(CFLAGS) $(EXTRA_CFLAGS) $(RTAI_CFLAGS) -o $@ $< - @$(CC) -MM $(CFLAGS) $(EXTRA_CFLAGS) $(RTAI_CFLAGS) $< > $*.d - @mv -f $*.d $*.d.tmp - @sed -e 's|.*:|$*.o:|' < $*.d.tmp > $*.d - @sed -e 's/.*://' -e 's/\\$$//' < $*.d.tmp | fmt -1 | \ - sed -e 's/^ *//' -e 's/$$/:/' >> $*.d - @rm -f $*.d.tmp - -ifdef ENABLE_ITTI -$(OBJ) $(RTAI_OBJ): $(ITTI_MESSAGES_H) -endif - -ifeq ($(RTAI),1) -$(OBJ) $(ASN1_MSG_OBJS1): %.o : %.c -else -$(OBJ) $(ASN1_MSG_OBJS1) lte-softmodem.o lte-ue.o: %.o : %.c -endif - -rrh.o: %.o : %.c - - @echo Compiling $< ... - @$(CC) -c $(CFLAGS) $(EXTRA_CFLAGS) -o $@ $< - @$(CC) -MM $(CFLAGS) $(EXTRA_CFLAGS) $< > $*.d - @mv -f $*.d $*.d.tmp - @sed -e 's|.*:|$*.o:|' < $*.d.tmp > $*.d - @sed -e 's/.*://' -e 's/\\$$//' < $*.d.tmp | fmt -1 | \ - sed -e 's/^ *//' -e 's/$$/:/' >> $*.d - @rm -f $*.d.tmp - -OBJ_EMOS = $(OPENAIR_TARGETS)/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.o $(OPENAIR_TARGETS)/ARCH/EXMIMO/USERSPACE/LIB/gain_control.o rt_wrapper.o $(OPENAIR2_DIR)/UTIL/LOG/log.o $(OPENAIR2_DIR)/UTIL/LOG/vcd_signal_dumper.o $(OPENAIR1_DIR)/PHY/TOOLS/signal_energy.o $(OPENAIR1_DIR)/PHY/TOOLS/dB_routines.o -ifeq ($(XFORMS),1) -OBJ_EMOS+=lte_scope.o -endif - -condtest: condtest.c - $(CC) $(CFLAGS) $(LDFLAGS) condtest.c -o condtest - -synctest: $(OBJ_SYNC) $(SHARED_DEPENDENCIES) synctest.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(RTAI_CFLAGS) $(OBJ_SYNC) -o synctest synctest.c $(LDFLAGS) $(LIBS) - -sleeptest: rt_wrapper.o sleeptest.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(RTAI_CFLAGS) rt_wrapper.o -o sleeptest sleeptest.c $(LDFLAGS) - -lte-softmodem: $(OBJ) $(USRP_OBJ) $(ETHERNET_OBJ) $(ASN1_MSG_OBJS1) $(RTAI_OBJ) lte-ue.o lte-softmodem.o $(SHARED_DEPENDENCIES) - @echo Linking $@ - @$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(OBJ) $(USRP_OBJ) $(ETHERNET_OBJ) $(RTAI_OBJ) $(ASN1_MSG_OBJS1) lte-ue.o lte-softmodem.o -o lte-softmodem $(LDFLAGS) $(LIBS) - -rrh: rrh.o - @$(CC) $(CFLAGS) $(EXTRA_CFLAGS) rrh.o -o rrh -lpthread -lrt - -emos-raw: $(SHARED_DEPENDENCIES) $(OBJ_EMOS) emos-raw.c - @$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(RTAI_CFLAGS) $(OBJ_EMOS) -o emos-raw emos-raw.c $(LDFLAGS) $(LIBS) - - -synctest_eNB: synctest - cp synctest synctest_eNB - -synctest_UE: synctest - cp synctest synctest_UE - -drivers: -# cd $(OPENAIR2_DIR) && make clean && make nasmesh_netlink.ko -# cd $(OPENAIR2_DIR)/NAS/DRIVER/MESH/RB_TOOL && make clean && make - cd $(OPENAIR_TARGETS)/ARCH/EXMIMO/DRIVER/eurecom && make clean && make - cd $(OPENAIR_TARGETS)/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT && make clean && make - cp $(OPENAIR_TARGETS)/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT/updatefw $(OPENAIR_TARGETS)/bin/. - -run: condtest - rtai-load condtest --verbose - -run_eNB_test: - rtai-load eNB_test --verbose - -run_eNB: - rtai-load eNB --verbose - -run_UE: - rtai-load UE --verbose - -run_UE0: - rtai-load UE0 --verbose - -run_UE0_smbv: - rtai-load UE0_smbv --verbose - -run_UE850: - rtai-load UE850 --verbose - -run_eNB850: - rtai-load eNB850 --verbose - -run_UE0prach: - rtai-load UE0prach --verbose - -run_UE1prach: - rtai-load UE1prach --verbose - -run_UE2prach: - rtai-load UE2prach --verbose - -run_UE0noL2: - rtai-load UE0noL2 -- verbose - -run_UE1noL2: - rtai-load UE1noL2 --verbose - -run_UE2noL2: - rtai-load UE2noL2 --verbose - -run_UE0calib: - rtai-load UE0calib --verbose - -run_UE0calibmed: - rtai-load UE0calibmed --verbose - -run_UE0calibbyp: - rtai-load UE0calibbyp --verbose - -run_UE1: - rtai-load UE1 --verbose - -run_UE2: - rtai-load UE2 --verbose - -run_eNB0: - rtai-load eNB0 --verbose - -run_eNB1: - rtai-load eNB1 --verbose - -run_eNB2: - rtai-load eNB2 --verbose - -clean: cleanmodem common-clean - -cleanmodem: - @$(RM_F_V) $(OBJ) $(RTAI_OBJ) $(OBJ_EMOS) $(OBJ_SYNC) $(USRP_OBJ) $(ETHERNET_OBJ) - @$(RM_F_V) $(OBJ:.o=.d) $(RTAI_OBJ:.o=.d) $(OBJ_EMOS:.o=.d) $(OBJ_SYNC:.o=.d) - @$(RM_F_V) $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/asn1_msg.o $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/asn1_msg.d - @$(RM_F_V) lte-ue.o lte-ue.d rrh.o rrh.d lte-softmodem.o lte-softmodem.d - @$(RM_F_V) rrh.o lte-ue.o lte-softmodem.o - -cleanasn1: - rm -f $(ASN1_MSG_OBJS1) - $(shell cd $(OPENAIR2_DIR)/RRC/LITE/MESSAGES ; rm -f $(ASN_MODULE_SOURCES) $(ASN_MODULE_HEADERS) *.o *.d ) - rm -f $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/Makefile.am.sample - rm -f $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/Makefile.inc.generated - rm -f $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/asn1c/ASN1_files/.lock-rel* - -cleancell: - rm -f $(OPENAIR2_DIR)/RRC/CELLULAR/*.o - rm -f $(OPENAIR2_DIR)/RRC/CELLULAR/*.d - rm -f $(OPENAIR2_DIR)/RRC/L2_INTERFACE/*.o - rm -f $(OPENAIR2_DIR)/RRC/L2_INTERFACE/*.d - rm -f $(OPENAIR2_DIR)/NAS/SIMU_CELLULAR/*.o - rm -f $(OPENAIR2_DIR)/NAS/SIMU_CELLULAR/*.d - -cleanalmostall: cleanmodem - rm -f $(ASN1_MSG_OBJS1) - rm -rf condtest synctest lte-softmodem rrh - rm -rf synctest_eNB synctest_UE - -cleanall: common-cleanall clean cleanasn1 - rm -rf condtest synctest lte-softmodem rrh - rm -rf synctest_eNB synctest_UE - -show: - @echo $(CFLAGS) - @echo $(EXTRA_CFLAGS) - @echo $(OBJ) $(RTAI_OBJ) - @echo $(USRP_OBJ) - @echo $(ETHERNET_OBJ) - @echo $(ETHERNET_FILE_OBJ) - @echo IS_REL8 is $(IS_REL8) - @echo IS_REL10 is $(IS_REL10) - @echo openssl $(OPENSSL_FOUND) - @echo nettle $(NETTLE_FOUND) - @echo lowlatency kernel: $(DEADLINE_SCHEDULER_KERNEL) - -beautiful: - astyle --style=gnu -s2 $(SRC) - -fifos: - @for i in `seq 0 64`;\ - do \ - have_rtfX=`ls /dev/ |grep -c rtf$$i`;\ - if [ "$$have_rtfX" -eq 0 ] ;then \ - mknod -m 666 /dev/rtf$$i c 150 $$i; \ - fi;\ - done diff --git a/targets/RT/USER/Makefile.agilent b/targets/RT/USER/Makefile.agilent deleted file mode 100644 index 31dd3b6e7f..0000000000 --- a/targets/RT/USER/Makefile.agilent +++ /dev/null @@ -1,243 +0,0 @@ -include $(OPENAIR_TARGETS)/Makerules - -include $(OPENAIR_TARGETS)/Makefile.common - -CFLAGS += -DDRIVER2013 -I$(OPENAIR_TARGETS)/ARCH/EXMIMO/USERSPACE/LIB/ -I$(OPENAIR_TARGETS)/ARCH/EXMIMO/DEFS -DENABLE_VCD_FIFO -DEXMIMO_IOT - -SRC = lte-enb.c - -ifndef RTAI -RTAI=1 -endif - -ifeq ($(RTAI),1) -CFLAGS += -DENABLE_RTAI_CLOCK -DRTAI -RTAI_OBJ = sched_dlsch.o sched_ulsch.o sched_rx_pdsch.o lte-enb.o rt_wrapper.o -else -OBJ = sched_dlsch.o sched_ulsch.o sched_rx_pdsch.o lte-enb.o rt_wrapper.o -CFLAGS += -DENABLE_USE_CPU_EXECUTION_TIME -endif - -OBJ += $(OPENAIR1_DIR)/SIMULATION/TOOLS/taus.o $(OPENAIR_TARGETS)/SIMU/USER/init_lte.o $(OPENAIR_TARGETS)/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.o - -TOP_DIR = $(OPENAIR1_DIR) -include $(OPENAIR1_DIR)/PHY/Makefile.inc -include $(OPENAIR1_DIR)/SCHED/Makefile.inc - -OBJ += $(PHY_OBJS) -ifeq ($(RTAI),1) -RTAI_OBJ += $(SCHED_OBJS) -else -OBJ += $(SCHED_OBJS) -endif - -#ifndef rrc_cellular -ifeq ($(rrc_cellular),0) -rrc_cellular = 0 -rrc_cellular_eNB = 0 -rrc_cellular_UE = 0 -else - ifeq ($(eNB_flag),1) - rrc_cellular_eNB=1 - endif - ifeq ($(UE_flag),1) - rrc_cellular_UE=1 - endif -endif - -export rrc_cellular - -OPENAIR2_TOP = $(OPENAIR2_DIR) -include $(OPENAIR2_DIR)/LAYER2/Makefile.inc -include $(OPENAIR2_DIR)/UTIL/Makefile.inc -include $(OPENAIR2_DIR)/RRC/NAS/Makefile.inc - -ifeq ($(RTAI),1) -LOG_OBJS= -RTAI_OBJ+=$(LOG_DIR)/vcd_signal_dumper.o -RTAI_OBJ+=$(LOG_DIR)/log.o -endif - -include $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/Makefile.inc - -OBJ += $(LOG_OBJS) - -ifndef OPENAIR2 -OPENAIR2=1 -endif -ifeq ($(OPENAIR2),1) -ASN1_MSG_OBJS1=$(addprefix $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/, $(ASN1_MSG_OBJS)) -OBJ += $(L2_OBJS) $(LIST_OBJ) $(TIMER_OBJ) $(MEM_OBJ) $(OTG_OBJS) $(MATH_OBJS) -OBJ += $(OPENAIR1_DIR)/SIMULATION/ETH_TRANSPORT/netlink_init.o -OBJ += $(PDCP_DIR)/pdcp_thread.o -CFLAGS += -DOPENAIR2 -DNO_RRM -DPUCCH -DMAC_CONTEXT=1 -endif - -CFLAGS += $(L2_incl) $(UTIL_incl) $(UTILS_incl) - -CFLAGS += -I$(OPENAIR1_DIR) -I$(OPENAIR2_DIR)/RRC/LITE/MESSAGES #-I$(OPENAIR3_DIR)/MESH -I$(OPENAIR3_DIR)/MESH/RRM - -CFLAGS += -DNEW_FFT -DLOG_NO_THREAD - -ifeq ($(XFORMS),1) -CFLAGS += -DXFORMS -I/usr/include/X11 -LDFLAGS += -lforms -OBJ += $(OPENAIR1_DIR)/PHY/TOOLS/lte_phy_scope.o -OBJ += stats.o -endif - -ifdef SMBV -CFLAGS += -DSMBV -endif - -CFLAGS += -DPHYSIM -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DPHY_CONTEXT=1 -CFLAGS += -DOPENAIR_LTE -DENABLE_FXP -DOPENAIR1 -DDLSCH_THREAD #-DULSCH_THREAD - -#only for CBMIMO1 -ifdef CBMIMO1 -CFLAGS += -DFW2011 -DBIT8_TX -DCBMIMO1 -else -#only for EXPRESS MIMO -CFLAGS += -DEXMIMO -#CFLAGS += -DEXMIMO -DTIMING_ADVANCE_HW=138 #this is for ExpressMIMO 1 -#CFLAGS += -DEXMIMO -DTIMING_ADVANCE_HW=45 #this is for ExpressMIMO 2 -endif - -ifndef HARD_RT -HARD_RT=1 -endif - -ifeq ($(HARD_RT),1) -CFLAGS += -DHARD_RT -endif - -ifeq ($(EMOS),1) -CFLAGS += -DEMOS -DEMOS_CHANNEL -LDFLAGS += -lgps -endif - -ifndef NAS -NAS=1 -endif - -ifeq ($(NAS),1) -CFLAGS += -DPDCP_USE_NETLINK -DLINUX -OBJ += $(NAS_OBJS) -endif - -RTAI_CFLAGS += $(shell rtai-config --lxrt-cflags) -CFLAGS += -I/usr/realtime/include -DRTAI -LDFLAGS += -lpthread -lm -lforms -ifeq ($(RTAI),1) -LDFLAGS += $(shell rtai-config --lxrt-ldflags) -else -LDFLAGS += -lrt -endif - -#ifndef USE_MME -# USE_MME=R8 -#endif - -ifdef USE_MME - include $(OPENAIR2_DIR)/S1AP/Makefile.inc - include $(OPENAIR2_DIR)/S1AP/MESSAGES/Makefile.inc - CFLAGS += -DENABLE_USE_MME -DENB_MODE - LDFLAGS += -lsctp - CFLAGS_S1AP += -DENB_MODE -DENABLE_USE_MME -DEMIT_ASN_DEBUG=1 - S1AP_BUILT_OBJS += $(S1AP_OBJS) $(addprefix $(OPENAIR2_DIR)/S1AP/MESSAGES/, $(S1AP_ASN_MODULE_SOURCES)) - S1AP_BUILT_OBJS += $(OPENAIR3_DIR)/OPENAIRMME/SCTP/sctp_primitives_client.o -endif - - -ASN1RELDIR=R9.8 -ifeq ($(USE_MME), R8) - ASN1RELDIR=R8.10 -else - CFLAGS_S1AP += -DUPDATE_RELEASE_9 -endif -S1AP_DIR=$(OPENAIR2_DIR)/S1AP -ASN1MESSAGESDIR=$(S1AP_DIR)/MESSAGES -ASN1DIR=$(ASN1MESSAGESDIR)/ASN1 - -all: lte-enb - -$(LFDS_DIR)/bin/liblfds611.a: - $(MAKE) -C $(LFDS_DIR) -f makefile.linux - - -$(RTAI_OBJ): %.o : %.c - @echo Compiling $< ... - @$(CC) -c $(CFLAGS) $(EXTRA_CFLAGS) $(RTAI_CFLAGS) -o $@ $< - -$(OBJ) $(ASN1_MSG_OBJS1): %.o : %.c - @echo Compiling $< ... - @$(CC) -c $(CFLAGS) $(EXTRA_CFLAGS) -o $@ $< - -$(S1AP_BUILT_OBJS): %.o : %.c - @echo Compiling $< - @$(CC) -Wall -c $(CFLAGS_S1AP) $(S1AP_Incl) $(UTIL_incl) -o $@ $< - -$(ASN1MESSAGESDIR)/s1ap_ieregen.stamp: $(ASN1DIR)/$(ASN1RELDIR)/S1AP-PDU-Contents.asn $(ASN1DIR)/asn1tostruct.py - echo Timestamp > $@ - (cd $(ASN1DIR) && python $(ASN1DIR)/asn1tostruct.py -f$<) - -$(ASN1MESSAGESDIR)/s1ap_asn1regen.stamp: $(ASN1DIR)/$(ASN1RELDIR)/S1AP-CommonDataTypes.asn $(ASN1DIR)/$(ASN1RELDIR)/S1AP-Constants.asn $(ASN1DIR)/$(ASN1RELDIR)/S1AP-IEs.asn $(ASN1DIR)/$(ASN1RELDIR)/S1AP-PDU.asn - echo Timestamp > $@ - (cd $(ASN1MESSAGESDIR) && asn1c -gen-PER -fnative-types -fskeletons-copy $^) - -$(S1AP_DIR)/libs1ap.a: $(ASN1MESSAGESDIR)/s1ap_ieregen.stamp $(ASN1MESSAGESDIR)/s1ap_asn1regen.stamp $(S1AP_BUILT_OBJS) - @echo Creating $@ - $(AR) rcs $@ $^ - -$(LFDS_DIR)/bin/liblfds611.a: - $(MAKE) -C $(LFDS_DIR) -f makefile.linux - -ifdef USE_MME - lte-enb: $(OBJ) $(S1AP_DIR)/libs1ap.a $(ASN1_MSG_OBJS1) $(RTAI_OBJ) $(LFDS_DIR)/bin/liblfds611.a -else - lte-enb: $(OBJ) $(ASN1_MSG_OBJS1) $(RTAI_OBJ) $(LFDS_DIR)/bin/liblfds611.a -endif - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(OBJ) $(RTAI_OBJ) $(ASN1_MSG_OBJS1) -o lte-enb $(LDFLAGS) $(LFDS_DIR)/bin/liblfds611.a - - - -nasmesh: - (cd $(OPENAIR2_DIR)/NAS/DRIVER/MESH/RB_TOOL && $(MAKE)) - (cd $(OPENAIR2_DIR) && $(MAKE) nasmesh_netlink.ko) - (sudo insmod $(OPENAIR2_DIR)/NAS/DRIVER/MESH/nasmesh.ko) -rb_tool: - (cd $(OPENAIR2_DIR)/NAS/DRIVER/MESH/RB_TOOL && $(MAKE)) - -nasmesh_install: - (sudo rmmod nasmesh) - (sudo insmod $(OPENAIR2_DIR)/NAS/DRIVER/MESH/nasmesh.ko) - -clean: - rm -rf $(OBJ) $(RTAI_OBJ) - rm -f $(S1AP_BUILT_OBJS) - rm -f $(ASN1MESSAGESDIR)/libs1ap.a - -cleanasn1: - rm -f $(ASN1_MSG_OBJS1) - $(shell cd $(OPENAIR2_DIR)/RRC/LITE/MESSAGES ; rm -f $(ASN_MODULE_SOURCES) $(ASN_MODULE_HEADERS) *.o *.d ) - rm -f $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/Makefile.am.sample - rm -f $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/Makefile.inc.generated - rm -f $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/asn1c/ASN1_files/.lock-rel8 - rm -f $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/asn1c/ASN1_files/.lock-rel10 - -cleanall: clean cleanasn1 - rm -rf condtest synctest lte-softmodem - rm -rf synctest_eNB synctest_UE - -show: - @echo $(CFLAGS) - @echo $(EXTRA_CFLAGS) - @echo $(OBJ) $(RTAI_OBJ) - @echo rrc_cellular variable is $(rrc_cellular) - @echo eNB_flag is $(eNB_flag) - @echo UE_flag is $(UE_flag) - @echo IS_REL8 is $(IS_REL8) - @echo IS_REL10 is $(IS_REL10) - -beautiful: - astyle --style=gnu -s2 $(SRC) diff --git a/targets/RT/USER/Makefile.msg_many b/targets/RT/USER/Makefile.msg_many deleted file mode 100644 index bc7840c1e5..0000000000 --- a/targets/RT/USER/Makefile.msg_many +++ /dev/null @@ -1,21 +0,0 @@ -CFLAGS = $(shell rtai-config --lxrt-cflags) -LDFLAGS = $(shell rtai-config --lxrt-ldflags) -lpthread -llxrt -lm - -CFLAGS += -D__IN_RTAI__ -Wall -O2 -I. - -OBJS = msg_many.o msg_helper.o - -all: msg_many - -msg_many: $(OBJS) - $(CC) $(LDFLAGS) -o $@ $(OBJS) - -$(OBJS): msg_many.h - -run: msg_many - rtai-load msg_many --verbose - -.PHONY: clean -clean: - rm -f msg_many $(OBJS) - diff --git a/targets/RT/USER/condtest.c b/targets/RT/USER/condtest.c deleted file mode 100644 index b6f00e80b3..0000000000 --- a/targets/RT/USER/condtest.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include - -#define PERIOD 100000000 -#define THRESHOLD 1 - -static SEM *mutex; -static CND *cond; - -static int thread0; -static int thread1; - -static int instance_cnt=-1; //0 means worker is busy, -1 means its free - -static void *fun0(void *arg) -{ - RT_TASK *task; - int done1=0, cnt1=0; - RTIME right_now; - int ret; - - task = rt_task_init_schmod(nam2num("TASK0"), 0, 0, 0, SCHED_FIFO, 0xF); - mlockall(MCL_CURRENT | MCL_FUTURE); - - rt_make_hard_real_time(); - - while (cnt1 < THRESHOLD) { - rt_sem_wait(mutex); - rt_printk("fun0: Hello World %d, instance_cnt %d!\n",cnt1,instance_cnt); - - while (instance_cnt<0) { - ret = rt_cond_wait(cond, mutex); - - if (ret != 0) { - rt_printk("error in rt_cond_wait, code %d\n",ret); - - switch (ret) { - case RTE_PERM: - rt_printk("error RTE_PERM %d\n",ret); - break; - - case RTE_UNBLKD: - rt_printk("error RTE_UNBLKD %d\n",ret); - break; - - case RTE_OBJREM: - rt_printk("error RTE_OBJREM %d\n",ret); - break; - - default: - rt_printk("unknown error code %d\n",ret); - break; - } - - break; - } - } - - rt_sem_signal(mutex); - - // do some work here - cnt1++; - - rt_sem_wait(mutex); - instance_cnt--; - rt_sem_signal(mutex); - - } - - // makes task soft real time - rt_make_soft_real_time(); - - printf("Back to soft RT\n"); - // clean task - rt_task_delete(task); - printf("Task deleted. returning\n"); - return 0; -} - - -int main(void) -{ - RT_TASK *task; - RTIME now; - int cnt=0; - - // make main thread LXRT soft realtime - task = rt_task_init_schmod(nam2num("MYTASK"), 9, 0, 0, SCHED_FIFO, 0xF); - mlockall(MCL_CURRENT | MCL_FUTURE); - - // start realtime timer and scheduler - //rt_set_oneshot_mode(); - rt_set_periodic_mode(); - start_rt_timer(0); - - now = rt_get_time() + 10*PERIOD; - rt_task_make_periodic(task, now, PERIOD); - - printf("Init mutex and cond.\n"); - mutex = rt_sem_init(nam2num("MUTEX"), 1); - - if (mutex==0) - printf("Error init mutex\n"); - - cond = rt_cond_init(nam2num("CONDITION")); - - if (cond==0) - printf("Error init cond\n"); - - thread0 = rt_thread_create(fun0, NULL, 10000); - //thread1 = rt_thread_create(fun1, NULL, 20000); - - //rt_sleep(PERIOD); - - while (cnt < THRESHOLD) { - rt_task_wait_period(); - rt_printk("main: Hello World %d!\n",cnt); - rt_sem_wait(mutex); //now the mutex should have value 0 - - if (instance_cnt==0) { - rt_sem_signal(mutex); //now the mutex should have vaule 1 - rt_printk("worker thread busy!\n"); - } else { - instance_cnt++; - rt_cond_signal(cond); - rt_sem_signal(mutex); //now the mutex should have vaule 1 - rt_printk("signaling worker thread to start!\n"); - } - - cnt++; - } - - // wait for end of program - printf("TYPE TO TERMINATE\n"); - getchar(); - - // cleanup - stop_rt_timer(); - return 0; -} diff --git a/targets/RT/USER/emos-raw.c b/targets/RT/USER/emos-raw.c deleted file mode 100644 index 2cf0e18c71..0000000000 --- a/targets/RT/USER/emos-raw.c +++ /dev/null @@ -1,1603 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file lte-softmodem.c -* \brief main program to control HW and scheduling -* \author R. Knopp, F. Kaltenberger -* \date 2012 -* \version 0.1 -* \company Eurecom -* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr -* \note -* \warning -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rt_wrapper.h" - -#include "PHY/types.h" -#include "PHY/TOOLS/defs.h" -#include "openair0_lib.h" - -#include "UTIL/LOG/log.h" -#include "UTIL/LOG/vcd_signal_dumper.h" - -#include "gain_control.h" - -#if defined(ENABLE_ITTI) -# include "intertask_interface_init.h" -# include "timer.h" -# if defined(ENABLE_USE_MME) -# include "s1ap_eNB.h" -# include "sctp_eNB_task.h" -# endif -#endif - -#define OPENAIR_THREAD_PRIORITY 255 -#define OPENAIR_THREAD_STACK_SIZE 8192 - -#ifdef XFORMS -/* -#include "PHY/TOOLS/lte_phy_scope.h" -#include "stats.h" -// current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0) -// at eNB 0, an UL scope for every UE -FD_lte_phy_scope_ue *form_ue[NUMBER_OF_UE_MAX]; -FD_lte_phy_scope_enb *form_enb[NUMBER_OF_UE_MAX]; -FD_stats_form *form_stats=NULL; -char title[255]; -unsigned char scope_enb_num_ue = 1; -*/ -#include "lte_scope.h" -FD_lte_scope *form_lte; -char title[255]; -#endif //XFORMS - -#ifdef EMOS -#include -struct gps_fix_t dummy_gps_data; -#ifdef RTAI -#include -#endif - -//#define CHANSOUNDER_FIFO_SIZE 10485760 // 10 Mbytes FIFO -//#define CHANSOUNDER_FIFO_SIZE 20971520 // 20 Mbytes FIFO -#define CHANSOUNDER_FIFO_SIZE 52428800 // 50 Mbytes FIFO -//#define CHANSOUNDER_FIFO_SIZE 104857600 // 100 Mbytes FIFO -//#define CHANSOUNDER_FIFO_SIZE 1073741824 // 1Gbyte FIFO -#define CHANSOUNDER_FIFO_MINOR 4 // minor of the FIFO device - this is /dev/rtf3 -#define CHANSOUNDER_FIFO_DEV "/dev/rtf4" -#endif - -#define FRAME_PERIOD 100000000ULL -#define DAQ_PERIOD 66667ULL -#define LTE_SLOTS_PER_FRAME 20 -//#define RESAMPLING_FACTOR 0 -#define SAMPLES_PER_SLOT 15360 -#define FRAME_LENGTH_COMPLEX_SAMPLES (SAMPLES_PER_SLOT*LTE_SLOTS_PER_FRAME) -#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all - -#ifdef RTAI -static SEM *mutex; -//static CND *cond; - -static long int thread0; -//static long int thread1; -//static long int sync_thread; -#else -pthread_t thread0; -//pthread_t thread1; -pthread_attr_t attr_dlsch_threads; -struct sched_param sched_param_dlsch; -#endif - -pthread_t thread2; //xforms -pthread_t thread3; //emos -pthread_t thread4; //GPS -pthread_t thread5; //log - -/* -static int instance_cnt=-1; //0 means worker is busy, -1 means its free -int instance_cnt_ptr_kern,*instance_cnt_ptr_user; -int pci_interface_ptr_kern; -*/ -//extern unsigned int bigphys_top; -//extern unsigned int mem_base; - -int number_of_cards = 1; -exmimo_config_t *p_exmimo_config; -exmimo_id_t *p_exmimo_id; -volatile unsigned int *DAQ_MBOX; - -int oai_exit = 0; - -//int time_offset[4] = {-138,-138,-138,-138}; -//int time_offset[4] = {-145,-145,-145,-145}; -int time_offset[4] = {0,0,0,0}; - -int fs4_test=0; -char UE_flag=0; -uint8_t eNB_id=0,UE_id=0; - -// this array sets the bandwidth used for each card (and applies to all chains on one card). -exmimo_bw_t bandwidth[MAX_CARDS] = {BW5,BW5,BW5,BW5}; -// the array carrier_freq sets the frequency for each chain of each card. A 0 means that the chain is disabled. -// Please make sure that the total number of channels enabled per card is in accordance with the following rules: -// BW20: one channel, BW10: 2 channels, BW5: 4 channels -//uint32_t carrier_freq[MAX_CARDS][4] = {{2590000000,0,0,0},{2590000000,0,0,0},{2605000000,2605000000,0,0},{0,0,0,0}}; -//uint32_t carrier_freq[MAX_CARDS][4] = {{2590000000,0,0,0},{2605000000,2605000000,0,0},{0,0,0,0},{0,0,0,0}}; -uint32_t carrier_freq[MAX_CARDS][4] = {{771500000,771500000,771500000,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}; - -// the following paramters set the aquisition time and period. These parameters have to be set in accordance with the write speed of your harddisk and the required throughput according to the setting above (see also channel_buffer_size which is computed later). -#define AQU_LENGTH_FRAMES 100 //Aquisition time in frames -#define AQU_PERIOD_FRAMES 100 //Repetition time of aquisition in frames -#define AQU_LENGTH_SLOTS (AQU_LENGTH_FRAMES*LTE_SLOTS_PER_FRAME) //Aquisition time in slots -#define AQU_PERIOD_SLOTS (AQU_PERIOD_FRAMES*LTE_SLOTS_PER_FRAME) //Repetition time of aquisition in slots - -int32_t rx_total_gain_dB[3] = {-112, -124, -136}; - -/* -// this array sets the bandwidth used for each card (and applies to all chains on one card). -exmimo_bw_t bandwidth[MAX_CARDS] = {BW20,BW20,BW10,BW5}; -// the array carrier_freq sets the frequency for each chain of each card. A 0 means that the chain is disabled. -// Please make sure that the total number of channels enabled per card is in accordance with the following rules: -// BW20: one channel, BW10: 2 channels, BW5: 4 channels -uint32_t carrier_freq[MAX_CARDS][4] = {{2590000000,0,0,0},{2590000000,0,0,0},{2605000000,2605000000,0,0},{0,0,0,0}}; -//uint32_t carrier_freq[MAX_CARDS][4] = {{2590000000,0,0,0},{2605000000,2605000000,0,0},{0,0,0,0},{0,0,0,0}}; -//uint32_t carrier_freq[MAX_CARDS][4] = {{2590000000,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}; - -// the following paramters set the aquisition time and period. These parameters have to be set in accordance with the write speed of your harddisk and the required throughput according to the setting above (see also channel_buffer_size which is computed later). -#define AQU_LENGTH_FRAMES 100 //Aquisition time in frames -#define AQU_PERIOD_FRAMES 200 //Repetition time of aquisition in frames -#define AQU_LENGTH_SLOTS (AQU_LENGTH_FRAMES*LTE_SLOTS_PER_FRAME) //Aquisition time in slots -#define AQU_PERIOD_SLOTS (AQU_PERIOD_FRAMES*LTE_SLOTS_PER_FRAME) //Repetition time of aquisition in slots - -int32_t rx_total_gain_dB[3] = {-105, -110, -115}; -*/ - -char dumpfile_dir[256] = "/mnt/emos"; - -char *conf_config_file_name = NULL; - -unsigned int lost_bytes=0; -unsigned int rssi_lin[MAX_CARDS][4],rssi_lin_max[MAX_CARDS],rssi_lin_avg[MAX_CARDS]; -uint8_t rssi_avg_dB[MAX_CARDS]; -long long unsigned int total_bytes=0; - -struct timing_info_t { - //unsigned int frame, hw_slot, last_slot, next_slot; - RTIME time_min, time_max, time_avg, time_last, time_now; - //unsigned int mbox0, mbox1, mbox2, mbox_target; - unsigned int n_samples; -} timing_info; - -extern int16_t* sync_corr_ue0; -extern int16_t prach_ifft[4][1024*2]; - -unsigned int frame; -int rx_input_level_dBm; -#ifdef XFORMS -extern int otg_enabled; -#else -int otg_enabled; -#endif - -int mbox_bounds[20] = {8,16,24,30,38,46,54,60,68,76,84,90,98,106,114,120,128,136,144, 0}; ///boundaries of slots in terms ob mbox counter rounded up to even numbers -//int mbox_bounds[20] = {6,14,22,28,36,44,52,58,66,74,82,88,96,104,112,118,126,134,142, 148}; ///boundaries of slots in terms ob mbox counter rounded up to even numbers - -//void setup_ue_buffers(PHY_VARS_UE *phy_vars_ue, LTE_DL_FRAME_PARMS *frame_parms, int carrier); -//void setup_eNB_buffers(PHY_VARS_eNB *phy_vars_eNB, LTE_DL_FRAME_PARMS *frame_parms, int carrier); -void test_config(int card, int ant, unsigned int rf_mode, int UE_flag); - -unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) -{ - return (txi + (txq<<6) + (rxi<<12) + (rxq<<18)); -} -unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) -{ - return (dcoff_i_rxfe + (dcoff_q_rxfe<<8)); -} - -void signal_handler(int sig) -{ - void *array[10]; - size_t size; - - if (sig==SIGSEGV) { - // get void*'s for all entries on the stack - size = backtrace(array, 10); - - // print out all the frames to stderr - fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, 2); - exit(-1); - } else { - oai_exit=1; - } -} - -void exit_fun(const char* s) -{ - void *array[10]; - size_t size; - - printf("Exiting: %s\n",s); - - oai_exit=1; - //rt_sleep_ns(FRAME_PERIOD); - - //exit (-1); -} - -#ifdef XFORMS -extern void ia_receiver_on_off( FL_OBJECT * form, long arg) {} - - -void *scope_thread(void *arg) -{ - int16_t prach_corr[1024]; - char stats_buffer[16384]; - //FILE *UE_stats, *eNB_stats; - int i,len=0; - float rxsig_t_dB[4][FRAME_LENGTH_COMPLEX_SAMPLES]; - float time[FRAME_LENGTH_COMPLEX_SAMPLES]; - struct sched_param sched_param; - int card,ant,idx; - - sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO)+1; - sched_setscheduler(0, SCHED_FIFO,&sched_param); - - printf("Scope thread has priority %d\n",sched_param.sched_priority); - - /* - if (UE_flag==1) - UE_stats = fopen("UE_stats.txt", "w"); - else - eNB_stats = fopen("eNB_stats.txt", "w"); - */ - - while (!oai_exit) { - /* - if (UE_flag==1) { - len = dump_ue_stats (PHY_vars_UE_g[0], stats_buffer, 0, mode,rx_input_level_dBm); - fl_set_object_label(form_stats->stats_text, stats_buffer); - //rewind (UE_stats); - //fwrite (stats_buffer, 1, len, UE_stats); - - phy_scope_UE(form_ue[UE_id], - PHY_vars_UE_g[UE_id], - eNB_id, - UE_id,7); - - } else { - len = dump_eNB_stats (PHY_vars_eNB_g[0], stats_buffer, 0); - fl_set_object_label(form_stats->stats_text, stats_buffer); - //rewind (eNB_stats); - //fwrite (stats_buffer, 1, len, eNB_stats); - for(UE_id=0;UE_idframing.resampling_factor[ant]); - - for (i=0; ichannel_t_re[idx],time,rxsig_t_dB[0],len,"","",""); - fl_set_xyplot_data(form_lte->channel_t_im[idx],time,rxsig_t_dB[1],len,"","",""); - idx++; - } - } - } - - //printf("doing forms\n"); - usleep(100000); - } - - //fclose (UE_stats); - //fclose (eNB_stats); - - pthread_exit((void*)arg); -} -#endif - -int dummy_tx_buffer[3840*4] __attribute__((aligned(16))); - - -#ifdef EMOS -void* gps_thread (void *arg) -{ - - struct gps_data_t gps_data; - struct gps_data_t *gps_data_ptr = &gps_data; - struct sched_param sched_param; - int ret; - - sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO)+1; - sched_setscheduler(0, SCHED_FIFO,&sched_param); - - printf("GPS thread has priority %d\n",sched_param.sched_priority); - - memset(&dummy_gps_data,0,sizeof(struct gps_fix_t)); - -#if GPSD_API_MAJOR_VERSION>=5 - ret = gps_open("127.0.0.1","2947",gps_data_ptr); - - if (ret!=0) -#else - gps_data_ptr = gps_open("127.0.0.1","2947"); - - if (gps_data_ptr == NULL) -#endif - { - printf("[EMOS] Could not open GPS\n"); - pthread_exit((void*)arg); - } - -#if GPSD_API_MAJOR_VERSION>=4 - else if (gps_stream(gps_data_ptr, WATCH_ENABLE,NULL) != 0) -#else - else if (gps_query(gps_data_ptr, "w+x") != 0) -#endif - { - printf("[EMOS] Error sending command to GPS\n"); - pthread_exit((void*) arg); - } else - printf("[EMOS] Opened GPS, gps_data=%p\n", gps_data_ptr); - - - while (!oai_exit) { - printf("[EMOS] polling data from gps\n"); -#if GPSD_API_MAJOR_VERSION>=5 - - if (gps_waiting(gps_data_ptr,500)) { - if (gps_read(gps_data_ptr) <= 0) { -#else - - if (gps_waiting(gps_data_ptr)) { - if (gps_poll(gps_data_ptr) != 0) { -#endif - printf("[EMOS] problem polling data from gps\n"); - } else { - memcpy(&dummy_gps_data,&(gps_data_ptr->fix),sizeof(struct gps_fix_t)); - printf("[EMOS] lat %g, lon %g\n",gps_data_ptr->fix.latitude,gps_data_ptr->fix.longitude); - } - } //gps_waiting - else { - printf("[EMOS] WARNING: No GPS data available, storing dummy packet\n"); - } - - //rt_sleep_ns(1000000000LL); - sleep(1); - } //oai_exit - - pthread_exit((void*) arg); - -} - -void *log_thread (void *arg) -{ - //struct tm now_sec; - struct timeval now; - int card; - FILE *logfile_id; - char logfile_name[1024]; - time_t starttime_tmp; - struct tm starttime; - - //open file - time(&starttime_tmp); - localtime_r(&starttime_tmp,&starttime); - snprintf(logfile_name,1024,"%s/%s_data_%d%02d%02d_%02d%02d%02d.log", - dumpfile_dir, - (UE_flag==0) ? "eNB" : "UE", - 1900+starttime.tm_year, starttime.tm_mon+1, starttime.tm_mday, starttime.tm_hour, starttime.tm_min, starttime.tm_sec); - logfile_id = fopen(logfile_name,"w"); - - if ((logfile_id == NULL)) { - fprintf(stderr, "[EMOS] Error opening logfile %s\n",logfile_name); - exit(EXIT_FAILURE); - } - - fprintf(logfile_id, - "#time, frame, total bytes wrote, total bytes lost, GPS time, GPS mode, lat, lon, alt, speed, rssi_lin_max[0], rssi_lin_avg[0], rssi_avg_dBm[0], rssi_avg_dB[0], rx_gain[0], LNA[0], ...\n"); - - while (!oai_exit) { - gettimeofday(&now,NULL); - //localtime_r(&(now.tv_sec),&now_sec); - fprintf(logfile_id,"%d.%06d, %d, %llu, %u, %e, %d, %e, %e, %e, %e, ", - (int) now.tv_sec, (int)now.tv_usec, - frame, total_bytes,lost_bytes, - dummy_gps_data.time, dummy_gps_data.mode, dummy_gps_data.latitude, dummy_gps_data.longitude, dummy_gps_data.altitude, dummy_gps_data.speed); - - for (card=0; cardrf.rf_mode[0] & LNAGAINMASK) >> 14)-1] - openair0_exmimo_pci[card].exmimo_config_ptr->rf.rx_gain[0][0], - rssi_avg_dB[card], openair0_exmimo_pci[card].exmimo_config_ptr->rf.rx_gain[0][0], (openair0_exmimo_pci[card].exmimo_config_ptr->rf.rf_mode[0] & LNAGAINMASK) >> 14); - - fprintf(logfile_id,"\n"); - usleep(10000); - } - - //close file - fclose(logfile_id); - - pthread_exit((void*) arg); - -} - -void *emos_thread (void *arg) -{ - char c; - char *fifo2file_buffer, *fifo2file_ptr; - - int fifo, counter=0, bytes; - - FILE *dumpfile_id; - char dumpfile_name[1024]; - time_t starttime_tmp; - struct tm starttime; - - //time_t timer; - struct tm now_sec; - struct timeval now; - - struct sched_param sched_param; - int ret; - - int card, ant; - int channel_buffer_size=0; //in bytes - - pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); - - sched_param.sched_priority = sched_get_priority_max(SCHED_FIFO)-1; - sched_setscheduler(0, SCHED_FIFO,&sched_param); - - printf("EMOS thread has priority %d\n",sched_param.sched_priority); - - //timer = time(NULL); - //now = localtime(&timer); - - for (card=0; cardframing.resampling_factor[ant]); - } - - channel_buffer_size *= 4; //4 bytes per sample - - // allocate memory for NO_FRAMES_DISK channes estimations - fifo2file_buffer = malloc(AQU_LENGTH_SLOTS*channel_buffer_size); - fifo2file_ptr = fifo2file_buffer; - - if (fifo2file_buffer == NULL) { - printf("[EMOS] Cound not allocate memory for fifo2file_buffer\n"); - exit(EXIT_FAILURE); - } - - if ((fifo = open(CHANSOUNDER_FIFO_DEV, O_RDONLY)) < 0) { - fprintf(stderr, "[EMOS] Error opening the fifo\n"); - exit(EXIT_FAILURE); - } - - - time(&starttime_tmp); - localtime_r(&starttime_tmp,&starttime); - snprintf(dumpfile_name,1024,"%s/%s_data_%d%02d%02d_%02d%02d%02d.EMOS", - dumpfile_dir, - (UE_flag==0) ? "eNB" : "UE", - 1900+starttime.tm_year, starttime.tm_mon+1, starttime.tm_mday, starttime.tm_hour, starttime.tm_min, starttime.tm_sec); - - dumpfile_id = fopen(dumpfile_name,"w"); - - if ((dumpfile_id == NULL)) { - fprintf(stderr, "[EMOS] Error opening dumpfile %s\n",dumpfile_name); - exit(EXIT_FAILURE); - } - - printf("[EMOS] starting dump, channel_buffer_size=%d ...\n",channel_buffer_size); - - while (!oai_exit) { - //bytes = rtf_read_timed(fifo, fifo2file_ptr, channel_buffer_size,100); - bytes = rtf_read_all_at_once(fifo, fifo2file_ptr, channel_buffer_size); - - if (bytes<=0) { - usleep(100); - continue; - } - - if (bytes != channel_buffer_size) { - printf("[EMOS] Frame %d: ERROR! Only got %d bytes instead of %d!\n",frame,bytes,channel_buffer_size); - } - - /* - if (UE_flag==0) - printf("eNB: count %d, frame %d, read: %d bytes from the fifo\n",counter, ((fifo_dump_emos_eNB*)fifo2file_ptr)->frame_tx,bytes); - else - printf("UE: count %d, frame %d, read: %d bytes from the fifo\n",counter, ((fifo_dump_emos_UE*)fifo2file_ptr)->frame_rx,bytes); - */ - - fifo2file_ptr += channel_buffer_size; - counter ++; - total_bytes += bytes; - - if ((counter%AQU_LENGTH_SLOTS)==0) { - //reset stuff - fifo2file_ptr = fifo2file_buffer; - //counter = 0; - - printf("[EMOS] Frame %d: start writing %d bytes to disk\n",frame,AQU_LENGTH_SLOTS*channel_buffer_size); - - //flush buffer to disk - if (fwrite(fifo2file_buffer, sizeof(char), AQU_LENGTH_SLOTS*channel_buffer_size, dumpfile_id) != AQU_LENGTH_SLOTS*channel_buffer_size) { - fprintf(stderr, "[EMOS] Error writing to dumpfile\n"); - exit(EXIT_FAILURE); - } else - printf("[EMOS] Frame %d: wrote %d bytes to disk\n",frame,AQU_LENGTH_SLOTS*channel_buffer_size); - - } - - if ((counter%AQU_LENGTH_SLOTS)==0) { - //time(&starttime_tmp); - gettimeofday(&now,NULL); - localtime_r(&(now.tv_sec),&now_sec); - printf("[EMOS] %02d:%02d:%02d.%03d, frame %d, total bytes wrote %llu, bytes lost %u\n", - now_sec.tm_hour, now_sec.tm_min, now_sec.tm_sec, (int)(now.tv_usec/1000), frame, total_bytes,lost_bytes); - - for (card=0; cardrf.rf_mode[0] & LNAGAINMASK) >> 14)-1] - openair0_exmimo_pci[card].exmimo_config_ptr->rf.rx_gain[0][0], - rssi_avg_dB[card], openair0_exmimo_pci[card].exmimo_config_ptr->rf.rx_gain[0][0], (openair0_exmimo_pci[card].exmimo_config_ptr->rf.rf_mode[0] & LNAGAINMASK) >> 14); - - //printf("[EMOS] %02d:%02d:%02d, frame %d, GPS time %e, GPS mode %d, lat %e, lon %e, alt %e, speed %e\n", starttime.tm_hour, starttime.tm_min, starttime.tm_sec, counter/20, dummy_gps_data.time, dummy_gps_data.mode, dummy_gps_data.latitude, dummy_gps_data.longitude, dummy_gps_data.altitude, dummy_gps_data.speed); - } - } - - free(fifo2file_buffer); - fclose(dumpfile_id); - close(fifo); - - pthread_exit((void*) arg); - -} -#endif - -/* This is the main eNB thread. It gets woken up by the kernel driver using the RTAI message mechanism (rt_send and rt_receive). */ -static void *eNB_thread(void *arg) -{ -#ifdef RTAI - RT_TASK *task; -#endif - unsigned char slot=0,last_slot, next_slot, hw_slot; - unsigned int msg1; - unsigned int aa,slot_offset, slot_offset_F; - int diff; - int delay_cnt; - RTIME time_in, time_diff; - int mbox_target=0,mbox_current=0; - int i,ret; - int tx_offset; - int bytes, bytes_tot=0, bytes_len; - long long int k1=1000; - long long int k2=1024-k1; - int ant,len,card = 0; - -#ifdef RTAI - task = rt_task_init_schmod(nam2num("TASK0"), 0, 0, 0, SCHED_FIFO, 0xF); - LOG_D(HW,"Started eNB thread (id %p)\n",task); -#endif - -#ifdef HARD_RT - rt_make_hard_real_time(); -#endif - - mlockall(MCL_CURRENT | MCL_FUTURE); - - timing_info.time_min = 100000000ULL; - timing_info.time_max = 0; - timing_info.time_avg = 0; - timing_info.n_samples = 0; - - while (!oai_exit) { - hw_slot = (((((volatile unsigned int *)DAQ_MBOX)[0]+1)%150)<<1)/15; - //LOG_D(HW,"eNB frame %d, time %llu: slot %d, hw_slot %d (mbox %d)\n",frame,rt_get_time_ns(),slot,hw_slot,((unsigned int *)DAQ_MBOX)[0]); - //this is the mbox counter where we should be - //mbox_target = ((((slot+1)%20)*15+1)>>1)%150; - mbox_target = mbox_bounds[slot]; - //this is the mbox counter where we are - mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0]; - - //this is the time we need to sleep in order to synchronize with the hw (in multiples of DAQ_PERIOD) - if ((mbox_current>=135) && (mbox_target<15)) //handle the frame wrap-arround - diff = 150-mbox_current+mbox_target; - else if ((mbox_current<15) && (mbox_target>=135)) - diff = -150+mbox_target-mbox_current; - else - diff = mbox_target - mbox_current; - - if (diff < (-7)) { - // at the eNB, even slots have double as much time since most of the processing is done here and almost nothing in odd slots - LOG_D(HW,"eNB Frame %d, time %llu: missed slot, proceeding with next one (slot %d, hw_slot %d, diff %d)\n",frame, rt_get_time_ns(), slot, hw_slot, diff); - slot++; - - //if (frame>0) - //oai_exit=1; - if (slot==20) { - slot=0; - frame++; - } - - continue; - } - - if (diff>8) - LOG_D(HW,"eNB Frame %d, time %llu: skipped slot, waiting for hw to catch up (slot %d, hw_slot %d, mbox_current %d, mbox_target %d, diff %d)\n",frame, rt_get_time_ns(), slot, hw_slot, mbox_current, - mbox_target, diff); - - delay_cnt = 0; - - while ((diff>0) && (!oai_exit)) { - time_in = rt_get_time_ns(); - //LOG_D(HW,"eNB Frame %d delaycnt %d : hw_slot %d (%d), slot %d, (slot+1)*15=%d, diff %d, time %llu\n",frame,delay_cnt,hw_slot,((unsigned int *)DAQ_MBOX)[0],slot,(((slot+1)*15)>>1),diff,time_in); - //LOG_D(HW,"eNB Frame %d, time %llu: sleeping for %llu (slot %d, hw_slot %d, diff %d, mbox %d, delay_cnt %d)\n", frame, time_in, diff*DAQ_PERIOD,slot,hw_slot,diff,((volatile unsigned int *)DAQ_MBOX)[0],delay_cnt); - ret = rt_sleep_ns(diff*DAQ_PERIOD); - - if (ret) - LOG_D(HW,"eNB Frame %d, time %llu: rt_sleep_ns returned %d\n",frame, time_in); - - hw_slot = (((((volatile unsigned int *)DAQ_MBOX)[0]+1)%150)<<1)/15; - //LOG_D(HW,"eNB Frame %d : hw_slot %d, time %llu\n",frame,hw_slot,rt_get_time_ns()); - delay_cnt++; - - if (delay_cnt == 10) { - oai_exit = 1; - LOG_D(HW,"eNB Frame %d: HW stopped ... \n",frame); - } - - mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0]; - - if ((mbox_current>=135) && (mbox_target<15)) //handle the frame wrap-arround - diff = 150-mbox_current+mbox_target; - else if ((mbox_current<15) && (mbox_target>=135)) - diff = -150+mbox_target-mbox_current; - else - diff = mbox_target - mbox_current; - } - - last_slot = (slot)%LTE_SLOTS_PER_FRAME; - - if (last_slot <0) - last_slot+=20; - - next_slot = (slot+3)%LTE_SLOTS_PER_FRAME; - - if (frame>=AQU_LENGTH_FRAMES) { - timing_info.time_last = timing_info.time_now; - timing_info.time_now = rt_get_time_ns(); - - if (timing_info.n_samples>0) { - time_diff = timing_info.time_now - timing_info.time_last; - - if (time_diff < timing_info.time_min) - timing_info.time_min = time_diff; - - if (time_diff > timing_info.time_max) - timing_info.time_max = time_diff; - - timing_info.time_avg += time_diff; - } - - timing_info.n_samples++; - - // do measurements for rssi - if (last_slot==0) { - for (card=0; cardframing.resampling_factor[0]); - rssi_lin_max[card] = 0; - - for (ant=0; ant<4; ant++) { - if (carrier_freq[card][ant] != 0) { - rssi_lin[card][ant] = signal_energy(&(((int32_t*) openair0_exmimo_pci[card].adc_head[ant])[last_slot*len]), len); - rssi_lin_max[card] = max(rssi_lin_max[card],rssi_lin[card][ant]); - } - } - - rssi_lin_avg[card] = (int) ((k1*((long long int)(rssi_lin_avg[card])) + (k2*((long long int)(rssi_lin_max[card]))))>>10); - rssi_avg_dB[card] = dB_fixed(rssi_lin_avg[card]); - - if (frame%100==0) { - gain_control_all(rssi_avg_dB[card],card); - //printf("AGC for card %d: rx_power_fil_dB=%d, rx_gain=%d, LNA=%d (1=Byp,2=Med,3=Max)\n",card,rssi_avg_dB,openair0_exmimo_pci[card].exmimo_config_ptr->rf.rx_gain[0][0],(openair0_exmimo_pci[card].exmimo_config_ptr->rf.rf_mode[0]&LNAGAINMASK)>>14); - } - } - } - -#ifdef EMOS - - // save raw samples here - if ((last_slot==0) && ((frame%AQU_PERIOD_FRAMES)==0)) { - printf("[EMOS] Frame %d: start writing to FIFO\n",frame); - bytes_tot=0; - } - - if ((frame%AQU_PERIOD_FRAMES)framing.resampling_factor[ant]); - bytes_len = len*4; - bytes = rtf_put(CHANSOUNDER_FIFO_MINOR, &(((int32_t*) openair0_exmimo_pci[card].adc_head[ant])[last_slot*len]), bytes_len); - bytes_tot += bytes; - - if (bytes!=bytes_len) { - lost_bytes += bytes_len - bytes; - LOG_W(PHY,"Frame %d, slot %d: Problem writing EMOS data to FIFO (bytes=%d, size=%d)\n", - frame, last_slot, bytes, bytes_len); - } - } - } - } - - if ((last_slot==19) && ((frame%AQU_PERIOD_FRAMES)==99)) - printf("[EMOS] Frame %d: sent %d bytes to FIFO\n",frame,bytes_tot); - - } - -#endif - } - - slot++; - - if (slot==20) { - slot=0; - frame++; - } - -#if defined(ENABLE_ITTI) - itti_update_lte_time(frame, slot); -#endif - } - - LOG_D(HW,"eNB_thread: finished, ran %d times.\n",frame); - -#ifdef HARD_RT - rt_make_soft_real_time(); -#endif - - // clean task -#ifdef RTAI - rt_task_delete(task); -#endif - LOG_D(HW,"Task deleted. returning\n"); - return 0; -} - - -int main(int argc, char **argv) -{ - -#ifdef RTAI - RT_TASK *task; -#endif - int i,j,aa; - void *status; - int card = 0; - - uint32_t rf_mode_base = TXLPFNORM + TXLPFEN + RXLPFNORM + RXLPFEN + LNA1ON +LNAMax + RFBBNORM; - uint32_t rf_local[4] = {8255000,8255000,8255000,8255000}; // UE zepto - //{8254617, 8254617, 8254617, 8254617}; //eNB khalifa - //{8255067,8254810,8257340,8257340}; // eNB PETRONAS - uint32_t rf_vcocal[4] = {910,910,910,910}; - uint32_t rf_vcocal_850[4] = {2015, 2015, 2015, 2015}; - uint32_t rf_rxdc[4] = {32896,32896,32896,32896}; - uint32_t rxgain[4] = {30,30,30,30}; - uint32_t txgain[4] = {0,0,0,0}; - - uint16_t Nid_cell = 0; - uint8_t cooperation_flag=0, transmission_mode=1, abstraction_flag=0; - uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2; - - int c; - char do_forms=0; - unsigned int fd; - unsigned int tcxo = 114; - - int amp; - uint8_t prach_fmt; - int N_ZC; - - char rxg_fname[100]; - char txg_fname[100]; - char rflo_fname[100]; - char rfdc_fname[100]; - FILE *rxg_fd=NULL; - FILE *txg_fd=NULL; - FILE *rflo_fd=NULL; - FILE *rfdc_fd=NULL; - unsigned int rxg_max[4]= {133,133,133,133}, rxg_med[4]= {127,127,127,127}, rxg_byp[4]= {120,120,120,120}; - int tx_max_power=0; - - char line[1000]; - int l; - int ret, ant; - int ant_offset=0; - - int error_code; - char *itti_dump_file = NULL; - - const struct option long_options[] = { - {"calib-ue-rx", required_argument, NULL, 256}, - {"calib-ue-rx-med", required_argument, NULL, 257}, - {"calib-ue-rx-byp", required_argument, NULL, 258}, - {"debug-ue-prach", no_argument, NULL, 259}, - {"no-L2-connect", no_argument, NULL, 260}, - {NULL, 0, NULL, 0} - }; - - //mode = normal_txrx; - - - while ((c = getopt_long (argc, argv, "C:K:O:ST:UdF:V",long_options,NULL)) != -1) { - switch (c) { - case 'V': - ouput_vcd = 1; - break; - - case 'd': - do_forms=1; - break; - - case 'U': - UE_flag = 1; - break; - - case 'C': - for (card=0; cardlog_component[HW].level = LOG_DEBUG; - g_log->log_component[HW].flag = LOG_HIGH; -#ifdef OPENAIR2 - g_log->log_component[PHY].level = LOG_INFO; -#else - g_log->log_component[PHY].level = LOG_DEBUG; -#endif - g_log->log_component[PHY].flag = LOG_HIGH; - g_log->log_component[MAC].level = LOG_INFO; - g_log->log_component[MAC].flag = LOG_HIGH; - g_log->log_component[RLC].level = LOG_INFO; - g_log->log_component[RLC].flag = LOG_HIGH; - g_log->log_component[PDCP].level = LOG_INFO; - g_log->log_component[PDCP].flag = LOG_HIGH; - g_log->log_component[OTG].level = LOG_INFO; - g_log->log_component[OTG].flag = LOG_HIGH; - g_log->log_component[RRC].level = LOG_INFO; - g_log->log_component[RRC].flag = LOG_HIGH; - - - // Initialize card - ret = openair0_open(); - - if ( ret != 0 ) { - if (ret == -1) - printf("Error opening /dev/openair0"); - - if (ret == -2) - printf("Error mapping bigshm"); - - if (ret == -3) - printf("Error mapping RX or TX buffer"); - - return(ret); - } - - number_of_cards = openair0_num_detected_cards; - - for (card=0; cardboard_exmimoversion, p_exmimo_id->board_hwrev, p_exmimo_id->board_swrev); - - if (p_exmimo_id->board_swrev>=BOARD_SWREV_CNTL2) - p_exmimo_config->framing.eNB_flag = 0; - else - p_exmimo_config->framing.eNB_flag = !UE_flag; - - if (card==0) - p_exmimo_config->framing.multicard_syncmode = SYNCMODE_MASTER; - else - p_exmimo_config->framing.multicard_syncmode = SYNCMODE_SLAVE; - - //p_exmimo_config->framing.multicard_syncmode = SYNCMODE_FREE; - - - p_exmimo_config->framing.tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_TESTRX; //TXRXSWITCH_LSB; - - /* - for (ant=0;antnb_antennas_tx,frame_parms->nb_antennas_rx);ant++) - p_exmimo_config->rf.rf_mode[ant] = rf_mode_base; - for (ant=0;antnb_antennas_tx;ant++) - p_exmimo_config->rf.rf_mode[ant] += (TXEN + DMAMODE_TX); - for (ant=0;antnb_antennas_rx;ant++) - p_exmimo_config->rf.rf_mode[ant] += (RXEN + DMAMODE_RX); - for (ant=max(frame_parms->nb_antennas_tx,frame_parms->nb_antennas_rx);ant<4;ant++) { - p_exmimo_config->rf.rf_mode[ant] = 0; - carrier_freq[ant] = 0; //this turns off all other LIMEs - } - */ - - for (ant=0; ant<4; ant++) { - if (carrier_freq[card][ant] != 0) { - p_exmimo_config->rf.rf_mode[ant] = rf_mode_base; - - switch (bandwidth[card]) { - case BW20: - p_exmimo_config->framing.resampling_factor[ant] = 0; - p_exmimo_config->rf.rf_mode[ant] += RXLPF10 + TXLPF10; - break; - - case BW10: - p_exmimo_config->framing.resampling_factor[ant] = 1; - p_exmimo_config->rf.rf_mode[ant] += RXLPF5 + TXLPF5; - break; - - case BW5: - p_exmimo_config->framing.resampling_factor[ant] = 2; - p_exmimo_config->rf.rf_mode[ant] += RXLPF25 + TXLPF25; - break; - } - - //p_exmimo_config->rf.rf_mode[ant] += (TXEN + DMAMODE_TX); - p_exmimo_config->rf.rf_mode[ant] += (RXEN + DMAMODE_RX); - } else { - p_exmimo_config->rf.rf_mode[ant] = 0; - } - } - - for (ant = 0; ant<4; ant++) { - p_exmimo_config->rf.do_autocal[ant] = 1; - p_exmimo_config->rf.rf_freq_rx[ant] = carrier_freq[card][ant]; - p_exmimo_config->rf.rf_freq_tx[ant] = carrier_freq[card][ant]; - p_exmimo_config->rf.rx_gain[ant][0] = rxgain[ant]; - p_exmimo_config->rf.tx_gain[ant][0] = txgain[ant]; - - p_exmimo_config->rf.rf_local[ant] = rf_local[ant]; - p_exmimo_config->rf.rf_rxdc[ant] = rf_rxdc[ant]; - - if ((carrier_freq[card][ant] >= 850000000) && (carrier_freq[card][ant] <= 865000000)) { - p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal_850[ant]; - p_exmimo_config->rf.rffe_band_mode[ant] = DD_TDD; - } else if ((carrier_freq[card][ant] >= 1900000000) && (carrier_freq[card][ant] <= 2000000000)) { - p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal[ant]; - p_exmimo_config->rf.rffe_band_mode[ant] = B19G_TDD; - } else { - p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal[ant]; - p_exmimo_config->rf.rffe_band_mode[ant] = 0; - } - - p_exmimo_config->rf.rffe_gain_txlow[ant] = 31; - p_exmimo_config->rf.rffe_gain_txhigh[ant] = 31; - p_exmimo_config->rf.rffe_gain_rxfinal[ant] = 52; - p_exmimo_config->rf.rffe_gain_rxlow[ant] = 31; - } - - - openair0_dump_config(card); - - printf("EXMIMO_CONFIG card %d: freq0..3 %u %u %u %u Hz, freqtx0..1 %u %u Hz, RX gain0..1 %d %d dB\n", - card, - p_exmimo_config->rf.rf_freq_rx[0], - p_exmimo_config->rf.rf_freq_rx[1], - p_exmimo_config->rf.rf_freq_rx[2], - p_exmimo_config->rf.rf_freq_rx[3], - p_exmimo_config->rf.rf_freq_tx[0], - p_exmimo_config->rf.rf_freq_tx[1], - p_exmimo_config->rf.rx_gain[0][0], - p_exmimo_config->rf.rx_gain[1][0]); - printf("EXMIMO_CONFIG card %d: rf_mode 0x %x %x %x %x, [0]: TXRXEn %d, TXLPFEn %d, TXLPF %d, RXLPFEn %d, RXLPF %d, RFBB %d, LNA %d, LNAGain %d, RXLPFMode %d, SWITCH %d, rf_rxdc %d, rf_local %d, rf_vcocal %d\n", - card, - p_exmimo_config->rf.rf_mode[0], - p_exmimo_config->rf.rf_mode[1], - p_exmimo_config->rf.rf_mode[2], - p_exmimo_config->rf.rf_mode[3], - (p_exmimo_config->rf.rf_mode[0]&3), // RXen+TXen - (p_exmimo_config->rf.rf_mode[0]&4)>>2, //TXLPFen - (p_exmimo_config->rf.rf_mode[0]&TXLPFMASK)>>3, //TXLPF - (p_exmimo_config->rf.rf_mode[0]&128)>>7, //RXLPFen - (p_exmimo_config->rf.rf_mode[0]&RXLPFMASK)>>8, //TXLPF - (p_exmimo_config->rf.rf_mode[0]&RFBBMASK)>>16, // RFBB mode - (p_exmimo_config->rf.rf_mode[0]&LNAMASK)>>12, // RFBB mode - (p_exmimo_config->rf.rf_mode[0]&LNAGAINMASK)>>14, // RFBB mode - (p_exmimo_config->rf.rf_mode[0]&RXLPFMODEMASK)>>19, // RXLPF mode - (p_exmimo_config->framing.tdd_config&TXRXSWITCH_MASK)>>1, // Switch mode - p_exmimo_config->rf.rf_rxdc[0], - p_exmimo_config->rf.rf_local[0], - p_exmimo_config->rf.rf_vcocal[0]); - - for (ant=0; ant<4; ant++) - p_exmimo_config->rf.do_autocal[ant] = 0; - } //card - - card=0; - -#ifdef EMOS - error_code = rtf_create(CHANSOUNDER_FIFO_MINOR,CHANSOUNDER_FIFO_SIZE); - - if (error_code==0) - printf("[OPENAIR][SCHED][INIT] Created EMOS FIFO %d\n",CHANSOUNDER_FIFO_MINOR); - else if (error_code==ENODEV) - printf("[OPENAIR][SCHED][INIT] Problem: EMOS FIFO %d is greater than or equal to RTF_NO\n",CHANSOUNDER_FIFO_MINOR); - else if (error_code==ENOMEM) - printf("[OPENAIR][SCHED][INIT] Problem: cannot allocate memory for EMOS FIFO %d\n",CHANSOUNDER_FIFO_MINOR); - else - printf("[OPENAIR][SCHED][INIT] Problem creating EMOS FIFO %d, error_code %d\n",CHANSOUNDER_FIFO_MINOR,error_code); - -#endif - - mlockall(MCL_CURRENT | MCL_FUTURE); - -#ifdef RTAI - // make main thread LXRT soft realtime - task = rt_task_init_schmod(nam2num("MYTASK"), 9, 0, 0, SCHED_FIFO, 0xF); - - // start realtime timer and scheduler - //rt_set_oneshot_mode(); - rt_set_periodic_mode(); - start_rt_timer(0); - - //now = rt_get_time() + 10*PERIOD; - //rt_task_make_periodic(task, now, PERIOD); - - printf("Init mutex\n"); - //mutex = rt_get_adr(nam2num("MUTEX")); - mutex = rt_sem_init(nam2num("MUTEX"), 1); - - if (mutex==0) { - printf("Error init mutex\n"); - exit(-1); - } else - printf("mutex=%p\n",mutex); - -#endif - - DAQ_MBOX = (volatile unsigned int *) openair0_exmimo_pci[0].rxcnt_ptr[0]; - - // this starts the DMA transfers - if (UE_flag!=1) - for (card=0; cardlte_phy_scope_ue, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); - } else { - for(UE_id=0;UE_idlte_phy_scope_enb, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); - } - } - fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats"); - if (UE_flag==0) { - for (UE_id=0;UE_idbutton_0,1); - fl_set_object_label(form_enb[UE_id]->button_0,"DL Traffic ON"); - } - else { - fl_set_button(form_enb[UE_id]->button_0,0); - fl_set_object_label(form_enb[UE_id]->button_0,"DL Traffic OFF"); - } - } - } - else { - if (openair_daq_vars.use_ia_receiver) { - fl_set_button(form_ue[UE_id]->button_0,1); - fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver ON"); - } - else { - fl_set_button(form_ue[UE_id]->button_0,0); - fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF"); - } - } - */ - form_lte = create_form_lte_scope(); - fl_show_form (form_lte->lte_scope, FL_PLACE_HOTSPOT, FL_FULLBORDER, "Scope"); - - ret = pthread_create(&thread2, NULL, scope_thread, NULL); - printf("Scope thread created, ret=%d\n",ret); - } - -#endif - -#ifdef EMOS - ret = pthread_create(&thread3, NULL, emos_thread, NULL); - printf("EMOS thread created, ret=%d\n",ret); - ret = pthread_create(&thread4, NULL, gps_thread, NULL); - printf("GPS thread created, ret=%d\n",ret); - ret = pthread_create(&thread5, NULL, log_thread, NULL); - printf("LOG thread created, ret=%d\n",ret); -#endif - - rt_sleep_ns(10*FRAME_PERIOD); - -#ifndef RTAI - pthread_attr_init (&attr_dlsch_threads); - pthread_attr_setstacksize(&attr_dlsch_threads,OPENAIR_THREAD_STACK_SIZE); - //attr_dlsch_threads.priority = 1; - sched_param_dlsch.sched_priority = sched_get_priority_max(SCHED_FIFO); //OPENAIR_THREAD_PRIORITY; - pthread_attr_setschedparam (&attr_dlsch_threads, &sched_param_dlsch); - pthread_attr_setschedpolicy (&attr_dlsch_threads, SCHED_FIFO); -#endif - - // start the main thread - if (UE_flag == 1) { - /* - #ifdef RTAI - thread1 = rt_thread_create(UE_thread, NULL, 100000000); - #else - error_code = pthread_create(&thread1, &attr_dlsch_threads, UE_thread, NULL); - if (error_code!= 0) { - LOG_D(HW,"[lte-softmodem.c] Could not allocate UE_thread, error %d\n",error_code); - return(error_code); - } - else { - LOG_D(HW,"[lte-softmodem.c] Allocate UE_thread successful\n"); - } - #endif - #ifdef DLSCH_THREAD - init_rx_pdsch_thread(); - rt_sleep_ns(FRAME_PERIOD/10); - init_dlsch_threads(); - #endif - printf("UE threads created\n"); - */ - } else { -#ifdef RTAI - thread0 = rt_thread_create(eNB_thread, NULL, 100000000); -#else - error_code = pthread_create(&thread0, &attr_dlsch_threads, eNB_thread, NULL); - - if (error_code!= 0) { - LOG_D(HW,"[lte-softmodem.c] Could not allocate eNB_thread, error %d\n",error_code); - return(error_code); - } else { - LOG_D(HW,"[lte-softmodem.c] Allocate eNB_thread successful\n"); - } - -#endif -#ifdef ULSCH_THREAD - init_ulsch_threads(); -#endif - printf("eNB threads created\n"); - } - - - // wait for end of program - printf("TYPE TO TERMINATE\n"); - - //getchar(); - while (oai_exit==0) - rt_sleep_ns(FRAME_PERIOD); - - // stop threads -#ifdef XFORMS - printf("waiting for XFORMS thread\n"); - - if (do_forms==1) { - pthread_join(thread2,&status); - /* - fl_hide_form(form_stats->stats_form); - fl_free_form(form_stats->stats_form); - if (UE_flag==1) { - fl_hide_form(form_ue[UE_id]->lte_phy_scope_ue); - fl_free_form(form_ue[UE_id]->lte_phy_scope_ue); - } else { - for(UE_id=0;UE_idlte_phy_scope_enb); - fl_free_form(form_enb[UE_id]->lte_phy_scope_enb); - } - } - */ - fl_hide_form(form_lte->lte_scope); - fl_free_form(form_lte->lte_scope); - } - -#endif - - printf("stopping MODEM threads\n"); - - // cleanup - if (UE_flag == 1) { - /* - #ifdef RTAI - rt_thread_join(thread1); - #else - pthread_join(thread1,&status); - #endif - #ifdef DLSCH_THREAD - cleanup_dlsch_threads(); - cleanup_rx_pdsch_thread(); - #endif - */ - } else { -#ifdef RTAI - rt_thread_join(thread0); -#else - pthread_join(thread0,&status); -#endif -#ifdef ULSCH_THREAD - cleanup_ulsch_threads(); -#endif - } - -#ifdef OPENAIR2 - //cleanup_pdcp_thread(); -#endif - -#ifdef RTAI - stop_rt_timer(); -#endif - - printf("stopping card\n"); - - for (card=0; card0) - error_code = rtf_destroy(CHANSOUNDER_FIFO_MINOR); - - printf("[OPENAIR][SCHED][CLEANUP] EMOS FIFO closed, error_code %d\n", error_code); -#endif - - if (ouput_vcd) - VCD_SIGNAL_DUMPER_CLOSE(); - - logClean(); - - return 0; -} - -void test_config(int card, int ant, unsigned int rf_mode, int UE_flag) -{ - p_exmimo_config->framing.eNB_flag = !UE_flag; - p_exmimo_config->framing.tdd_config = 0; - p_exmimo_config->framing.resampling_factor[ant] = 2; - - p_exmimo_config->rf.rf_freq_rx[ant] = 1907600000; - p_exmimo_config->rf.rf_freq_tx[ant] = 1907600000;; - p_exmimo_config->rf.rx_gain[ant][0] = 20; - p_exmimo_config->rf.tx_gain[ant][0] = 10; - p_exmimo_config->rf.rf_mode[ant] = rf_mode; - - p_exmimo_config->rf.rf_local[ant] = build_rflocal(20,25,26,04); - p_exmimo_config->rf.rf_rxdc[ant] = build_rfdc(128, 128); - p_exmimo_config->rf.rf_vcocal[ant] = (0xE<<6) + 0xE; -} - -/* -void setup_ue_buffers(PHY_VARS_UE *phy_vars_ue, LTE_DL_FRAME_PARMS *frame_parms, int carrier) { - - int i; - if (phy_vars_ue) { - - if ((frame_parms->nb_antennas_rx>1) && (carrier>0)) { - printf("RX antennas > 1 and carrier > 0 not possible\n"); - exit(-1); - } - - if ((frame_parms->nb_antennas_tx>1) && (carrier>0)) { - printf("TX antennas > 1 and carrier > 0 not possible\n"); - exit(-1); - } - - // replace RX signal buffers with mmaped HW versions - for (i=0;inb_antennas_rx;i++) { - free(phy_vars_ue->lte_ue_common_vars.rxdata[i]); - phy_vars_ue->lte_ue_common_vars.rxdata[i] = (int32_t*) openair0_exmimo_pci[card].adc_head[i+carrier]; - - - printf("rxdata[%d] @ %p\n",i,phy_vars_ue->lte_ue_common_vars.rxdata[i]); - } - for (i=0;inb_antennas_tx;i++) { - free(phy_vars_ue->lte_ue_common_vars.txdata[i]); - phy_vars_ue->lte_ue_common_vars.txdata[i] = (int32_t*) openair0_exmimo_pci[card].dac_head[i+carrier]; - - printf("txdata[%d] @ %p\n",i,phy_vars_ue->lte_ue_common_vars.txdata[i]); - } - } -} - -void setup_eNB_buffers(PHY_VARS_eNB *phy_vars_eNB, LTE_DL_FRAME_PARMS *frame_parms, int carrier) { - - int i,j; - - if (phy_vars_eNB) { - if ((frame_parms->nb_antennas_rx>1) && (carrier>0)) { - printf("RX antennas > 1 and carrier > 0 not possible\n"); - exit(-1); - } - - if ((frame_parms->nb_antennas_tx>1) && (carrier>0)) { - printf("TX antennas > 1 and carrier > 0 not possible\n"); - exit(-1); - } - - // replace RX signal buffers with mmaped HW versions - for (i=0;inb_antennas_rx;i++) { - free(phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i]); - phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i] = (int32_t*) openair0_exmimo_pci[card].adc_head[i+carrier]; - - printf("rxdata[%d] @ %p\n",i,phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i]); - for (j=0;j<16;j++) { - printf("rxbuffer %d: %x\n",j,phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i][j]); - phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i][j] = 16-j; - } - } - for (i=0;inb_antennas_tx;i++) { - free(phy_vars_eNB->lte_eNB_common_vars.txdata[0][i]); - phy_vars_eNB->lte_eNB_common_vars.txdata[0][i] = (int32_t*) openair0_exmimo_pci[card].dac_head[i+carrier]; - - printf("txdata[%d] @ %p\n",i,phy_vars_eNB->lte_eNB_common_vars.txdata[0][i]); - for (j=0;j<16;j++) { - printf("txbuffer %d: %x\n",j,phy_vars_eNB->lte_eNB_common_vars.txdata[0][i][j]); - phy_vars_eNB->lte_eNB_common_vars.txdata[0][i][j] = 16-j; - } - } - } -} -*/ diff --git a/targets/RT/USER/init_rtai.sh b/targets/RT/USER/init_rtai.sh deleted file mode 100755 index 69b127de33..0000000000 --- a/targets/RT/USER/init_rtai.sh +++ /dev/null @@ -1,5 +0,0 @@ -sudo insmod /usr/realtime/modules/rtai_hal.ko -sudo insmod /usr/realtime/modules/rtai_sched.ko -sudo insmod /usr/realtime/modules/rtai_sem.ko -sudo insmod /usr/realtime/modules/rtai_fifos.ko -sudo insmod /usr/realtime/modules/rtai_mbx.ko diff --git a/targets/RT/USER/make_for_usrp.sh b/targets/RT/USER/make_for_usrp.sh deleted file mode 100755 index 998cd7c462..0000000000 --- a/targets/RT/USER/make_for_usrp.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -############### make nasmesh.ko ############### -sudo rmmod nasmesh -#cd ${OPENAIR2_DIR} && make nasmesh_netlink.ko -#cd ${OPENAIR2_DIR}/NAS/DRIVER/MESH/RB_TOOL/ && make -#make all -sudo insmod $OPENAIR2_DIR/NAS/DRIVER/MESH/nasmesh.ko - -############## Ethernet config #################### -sudo ifconfig eth0 mtu 4000 -sudo sysctl -w net.core.wmem_max=1048576 -sudo sysctl -w net.core.rmem_max=50000000 - -############## rtai modules ################### -if test \! -c /dev/rtai_shm; then - sudo mknod -m 666 /dev/rtai_shm c 10 254 -fi -for n in `seq 0 9`; do - f=/dev/rtf$n - if test \! -c $f; then - sudo mknod -m 666 $f c 150 $n - fi -done -sudo modprobe rtai_hal -sudo modprobe rtai_sched -sudo modprobe rtai_fifos -sudo modprobe rtai_sem -sudo modprobe rtai_mbx -sudo modprobe rtai_msg - -############## make ################### -make lte-softmodem-usrp NAS=1 USRP=1 XFORMS=1 RTAI=1 HARD_RT=1 #DRIVER2013=1 -#make lte-softmodem NAS=1 XFORMS=1 USRP=0 RTAI=1 DRIVER2013=1 -echo DONE! -exit 0 diff --git a/targets/RT/USER/msg_helper.c b/targets/RT/USER/msg_helper.c deleted file mode 100644 index ac99e48ff7..0000000000 --- a/targets/RT/USER/msg_helper.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#include - -#include "msg_many.h" - -/* - * Add a task task to ri->worker. - * Return the used index in ri->worker on success - * Return -TM_WORKER_FULL_ERROR if ri->worker full - * Return -TM_WORKER_ERROR else -*/ -int tm_add_task(RT_TASK *task, run_info_t *ri) -{ - if(ri->used >= NUM_THREADS) - return -TM_WORKER_FULL_ERROR; - - rt_sem_wait(ri->update_sem); - (*ri->worker)[ri->used] = task; - ri->used++; - rt_sem_signal(ri->update_sem); - - return ri->used - 1; -} - -/* - * Remove the a hole in worker at index index by - * shift the next slots by one. - * This function assume that update_sem are locked. - * Return the new used counter. -*/ -int _tm_clean_worker(RT_TASK *(*worker)[], int index, int used) -{ - int i; - - for(i = index; i < used; i++) - (*worker)[i] = (*worker)[i + 1]; - - return used - 1; -} - -/* - * Remove a task from ri->worker a index task_index - * Return 0 on success - * Return -TM_WORKER_ERROR else -*/ -int tm_del_task(int task_index, run_info_t *ri) -{ - rt_sem_wait(ri->update_sem); - ri->used = _tm_clean_worker(ri->worker, task_index, ri->used); - rt_sem_signal(ri->update_sem); - - return 0; -} - -/* - * Return next index to use on ri->worker. - * It depends on the old_index and ri->used. - * Return -TM_WORKER_ERROR if ri->used == 0. -*/ -inline int tm_get_next_task_index(int old_index, run_info_t *ri) -{ - if(ri->used == 0) - return -TM_WORKER_ERROR; - - return (old_index + 1) % ri->used; -} - diff --git a/targets/RT/USER/msg_many.c b/targets/RT/USER/msg_many.c deleted file mode 100644 index 17e03c6c5a..0000000000 --- a/targets/RT/USER/msg_many.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "msg_many.h" - -static void *msg_test_thread(void *arg) -{ - RT_TASK *self; - RT_TASK *sender_task; - thread_info_t *ti = (thread_info_t *)arg; - run_info_t *ri = ti->ri; - unsigned int msg; - int counter = 0; - char name[6]; - int task_index; - - /* Build custom task name for each thread */ - snprintf(name, 6, "%s%03i", THREAD_NAME_PREFIX, ti->thread_num); - - self = rt_task_init_schmod(nam2num(name), 0, 0, 0, SCHED_FIFO, 0xF); - mlockall(MCL_CURRENT | MCL_FUTURE); - - rt_make_hard_real_time(); - - task_index = tm_add_task(self, ri); - - if(task_index != -TM_WORKER_FULL_ERROR) { - while (*(ri->exit_condition) == 0) { - // wait only one PERIOD to avoid wait for ever - sender_task = rt_receive_timed(ri->sender, &msg, ri->period); - - //sender_task = rt_receive(0, &msg); - if(sender_task == ri->sender) - counter++; - } - - rt_printk("%s: counter == %i\n", name, counter); - tm_del_task(task_index, ri); - } else { - rt_printk("%s: Worker array full!\n", name); - } - - rt_make_soft_real_time(); - - rt_task_delete(self); - - free((void *) ti); - - return 0; -} - - -int main(void) -{ - RT_TASK *self; - RT_TASK *tmp_worker_task; - RT_TASK *worker_tasks[NUM_THREADS]; - int worker_threads[NUM_THREADS]; - RTIME now; - unsigned int i, ii; - run_info_t ri; - thread_info_t *ti; - uint8_t exit_condition = 0; - int fail_count = 0; - int old_index = 0; - uint8_t lost; - - // make main thread LXRT soft realtime - self = rt_task_init_schmod(nam2num("MAINTK"), 10, 0, 0, SCHED_FIFO, 0xF); - mlockall(MCL_CURRENT | MCL_FUTURE); - - rt_make_hard_real_time(); - rt_set_periodic_mode(); - start_rt_timer(0); - - /* Build all information need to run in main and the thread */ - ri.sender = self; - ri.exit_condition = &exit_condition; - ri.period = nano2count(PERIOD); - ri.update_sem = rt_sem_init(nam2num("MUTEX"), 1); - - if(ri.update_sem == 0) - exit(-1); - - ri.used = 0; - ri.worker = &worker_tasks; - - now = rt_get_time() + ri.period; - rt_task_make_periodic(self, now, ri.period); - - /* start all threads */ - for(i = 0; i < NUM_THREADS; i++) { - ti = (thread_info_t *)malloc(sizeof(thread_info_t)); - - if(ti == NULL) { - rt_printk("MAINTK: can't get memory!\n"); - exit(-1); - } - - ti->ri = &ri; - ti->thread_num = i; - worker_threads[i] = rt_thread_create(msg_test_thread, ti , 10000); - } - - rt_sleep(NUM_THREADS * ri.period); - - rt_printk("start\n"); - - for(i = 0; i < THRESHOLD; i++) { - rt_task_wait_period(); - lost = 1; - - for(ii = 0; ii < ri.used; ii++) { - old_index = tm_get_next_task_index(old_index, &ri); - - if(old_index == -TM_WORKER_ERROR) { - rt_printk("MAINTK: No Tasks!\n"); - break; - } - - tmp_worker_task = rt_send_if(worker_tasks[old_index], i); - - if(tmp_worker_task == worker_tasks[old_index]) { - lost = 0; - break; - } - } - - if(lost) - fail_count++; - } - - rt_printk("fail_count == %i\n", fail_count); - - // cleanup - exit_condition = 1; - rt_make_soft_real_time(); - - rt_task_delete(self); - - /* wait for the worker threadss */ - for(ii = 0; ii < ri.used; ii++) { - rt_thread_join(worker_threads[ii]); - } - - stop_rt_timer(); - return 0; -} diff --git a/targets/RT/USER/msg_many.h b/targets/RT/USER/msg_many.h deleted file mode 100644 index 5b9d465e33..0000000000 --- a/targets/RT/USER/msg_many.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#ifndef __MSG_MANY_H__ -#define __MSG_MANY_H__ -#include - -#define PERIOD 500000 /* in nano seconds */ -#define THRESHOLD 1000000 -#define THREAD_NAME_PREFIX "TK" -#define NUM_THREADS 10 - -#define TM_WORKER_FULL_ERROR 1 -#define TM_WORKER_ERROR 2 - -typedef struct run_info { - RT_TASK *sender; - uint8_t *exit_condition; - long long period; - SEM *update_sem; /* protect the task array */ - int used; /* counter of used slots in worker */ - RT_TASK *(*worker)[]; /* declare worker as pointer to array of pointer to RT_TASK */ -} run_info_t; - -typedef struct thread_info { - run_info_t *ri; - uint8_t thread_num; -} thread_info_t; - -int tm_add_task(RT_TASK *task, run_info_t *ri); -int tm_del_task(int task_index, run_info_t *ri); -inline int tm_get_next_task_index(int old_index, run_info_t *ri); - -#endif - diff --git a/targets/RT/USER/sleeptest.c b/targets/RT/USER/sleeptest.c deleted file mode 100644 index ba5cb0ce15..0000000000 --- a/targets/RT/USER/sleeptest.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file lte-softmodem.c -* \brief main program to control HW and scheduling -* \author R. Knopp, F. Kaltenberger -* \date 2012 -* \version 0.1 -* \company Eurecom -* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr -* \note -* \warning -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rt_wrapper.h" - -#define TIMER_ONESHOT_MODE -#define FRAME_PERIOD 10000000ULL -#define DAQ_PERIOD 500000ULL -#define LTE_SLOTS_PER_FRAME 20 - -#ifdef RTAI -static SEM *mutex; -//static CND *cond; - -static long int thread0; -static long int thread1; -//static long int sync_thread; -#else -#define OPENAIR_THREAD_STACK_SIZE 8192 -#define OPENAIR_THREAD_PRIORITY 255 -pthread_t thread0; -//pthread_t thread1; -pthread_attr_t attr_dlsch_threads; -struct sched_param sched_param_dlsch; -#endif - -int oai_exit = 0; - -struct timing_info_t { - //unsigned int frame, hw_slot, last_slot, next_slot; - RTIME time_min, time_max, time_avg, time_last, time_now; - //unsigned int mbox0, mbox1, mbox2, mbox_target; - unsigned int n_samples; -} timing_info; - -void signal_handler(int sig) -{ - void *array[10]; - size_t size; - - if (sig==SIGSEGV) { - // get void*'s for all entries on the stack - size = backtrace(array, 10); - - // print out all the frames to stderr - fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, 2); - exit(-1); - } else { - oai_exit=1; - } -} - -void exit_fun(const char* s) -{ - void *array[10]; - size_t size; - - printf("Exiting: %s\n",s); - - oai_exit=1; - //rt_sleep_ns(FRAME_PERIOD); - - //exit (-1); -} - -int frame=0,slot=0; - -/* This is the main eNB thread. It gets woken up by the kernel driver using the RTAI message mechanism (rt_send and rt_receive). */ -static void *eNB_thread(void *arg) -{ -#ifdef RTAI - RT_TASK *task; - RTIME now; -#endif - unsigned char last_slot, next_slot; - RTIME time_in, time_diff; - int ret; - -#ifdef RTAI - task = rt_task_init_schmod(nam2num("TASK0"), 0, 0, 0, SCHED_FIFO, 0xF); - printf("Started eNB thread (id %p)\n",task); -#ifndef TIMER_ONESHOT_MODE - now = rt_get_time(); - ret = rt_task_make_periodic(task, now, nano2count(DAQ_PERIOD)); - - if (ret!=0) - printf("Problem with periodic timer\n"); - -#endif -#endif - -#ifdef HARD_RT - rt_make_hard_real_time(); -#endif - - mlockall(MCL_CURRENT | MCL_FUTURE); - - timing_info.time_min = 100000000ULL; - timing_info.time_max = 0; - timing_info.time_avg = 0; - timing_info.n_samples = 0; - - while (!oai_exit) { - time_in = rt_get_time_ns(); -#ifdef TIMER_ONESHOT_MODE - ret = rt_sleep_ns(DAQ_PERIOD); - - if (ret) - printf("eNB Frame %d, time %llu: rt_sleep_ns returned %d\n",frame,time_in,ret); - -#else - rt_task_wait_period(); -#endif - time_diff = rt_get_time_ns() - time_in; - - if (time_diff > timing_info.time_max) - timing_info.time_max = time_diff; - - if (time_diff < timing_info.time_min) - timing_info.time_min = time_diff; - - timing_info.time_avg = (timing_info.time_avg*timing_info.n_samples + time_diff)/(timing_info.n_samples+1); - timing_info.n_samples++; - - last_slot = (slot)%LTE_SLOTS_PER_FRAME; - - if (last_slot <0) - last_slot+=20; - - next_slot = (slot+3)%LTE_SLOTS_PER_FRAME; - - slot++; - - if (slot==20) { - slot=0; - frame++; - } - } - - printf("eNB_thread: finished, ran %d times.\n",frame); - -#ifdef HARD_RT - rt_make_soft_real_time(); -#endif - - // clean task -#ifdef RTAI - rt_task_delete(task); -#endif - printf("Task deleted. returning\n"); - return 0; -} - - -int main(int argc, char **argv) -{ - -#ifdef RTAI - RT_TASK *task; - RTIME period; -#else - int error_code; -#endif - int i,j,aa; - void *status; - - // to make a graceful exit when ctrl-c is pressed - signal(SIGSEGV, signal_handler); - signal(SIGINT, signal_handler); - -#ifndef RTAI - check_clock(); -#endif - - mlockall(MCL_CURRENT | MCL_FUTURE); - -#ifdef RTAI - // make main thread LXRT soft realtime - task = rt_task_init_schmod(nam2num("MYTASK"), 9, 0, 0, SCHED_FIFO, 0xF); - - // start realtime timer and scheduler -#ifdef TIMER_ONESHOT_MODE - rt_set_oneshot_mode(); - start_rt_timer(0); - printf("started RTAI timer in oneshot mode\n"); -#else - rt_set_periodic_mode(); - period = start_rt_timer(nano2count(500000)); - printf("started RTAI timer with period %llu ns\n",count2nano(period)); -#endif - - printf("Init mutex\n"); - //mutex = rt_get_adr(nam2num("MUTEX")); - mutex = rt_sem_init(nam2num("MUTEX"), 1); - - if (mutex==0) { - printf("Error init mutex\n"); - exit(-1); - } else - printf("mutex=%p\n",mutex); - -#endif - - rt_sleep_ns(10*FRAME_PERIOD); - -#ifndef RTAI - pthread_attr_init (&attr_dlsch_threads); - pthread_attr_setstacksize(&attr_dlsch_threads,OPENAIR_THREAD_STACK_SIZE); - //attr_dlsch_threads.priority = 1; - sched_param_dlsch.sched_priority = sched_get_priority_max(SCHED_FIFO); //OPENAIR_THREAD_PRIORITY; - pthread_attr_setschedparam (&attr_dlsch_threads, &sched_param_dlsch); - pthread_attr_setschedpolicy (&attr_dlsch_threads, SCHED_FIFO); -#endif - -#ifdef RTAI - thread0 = rt_thread_create(eNB_thread, NULL, 100000000); -#else - error_code = pthread_create(&thread0, &attr_dlsch_threads, eNB_thread, NULL); - - if (error_code!= 0) { - printf("[lte-softmodem.c] Could not allocate eNB_thread, error %d\n",error_code); - return(error_code); - } else { - printf("[lte-softmodem.c] Allocate eNB_thread successful\n"); - } - -#endif - printf("eNB threads created\n"); - - - - // wait for end of program - printf("TYPE TO TERMINATE\n"); - - //getchar(); - while (oai_exit==0) { - - printf("eNB Frame %d, hw_slot %d (time %llu): period %llu, sleep time (avg/min/max/samples) %llu / %llu / %llu / %d, ratio %f\n",frame,slot,rt_get_time_ns(),DAQ_PERIOD,timing_info.time_avg, - timing_info.time_min,timing_info.time_max,timing_info.n_samples,(double)timing_info.time_avg/DAQ_PERIOD); - - - rt_sleep_ns(100*FRAME_PERIOD); - } - - // stop threads -#ifdef RTAI - rt_thread_join(thread0); -#else - pthread_join(thread0,&status); -#endif - -#ifdef RTAI - stop_rt_timer(); -#endif - - return 0; -} - diff --git a/targets/RT/USER/synctest.c b/targets/RT/USER/synctest.c deleted file mode 100644 index ff65231df1..0000000000 --- a/targets/RT/USER/synctest.c +++ /dev/null @@ -1,1318 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file lte-softmodem.c -* \brief main program to control HW and scheduling -* \author R. Knopp, F. Kaltenberger -* \date 2012 -* \version 0.1 -* \company Eurecom -* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr -* \note -* \warning -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rt_wrapper.h" - -#include "PHY/types.h" -//#include "PHY/defs.h" -#include "openair0_lib.h" - -#include "UTIL/LOG/log.h" -#include "UTIL/LOG/vcd_signal_dumper.h" - -#if defined(ENABLE_ITTI) -# include "intertask_interface_init.h" -# include "timer.h" -# if defined(ENABLE_USE_MME) -# include "s1ap_eNB.h" -# include "sctp_eNB_task.h" -# endif -#endif - -#ifdef XFORMS -#include "PHY/TOOLS/lte_phy_scope.h" -#include "stats.h" -// current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0) -// at eNB 0, an UL scope for every UE -FD_lte_phy_scope_ue *form_ue[NUMBER_OF_UE_MAX]; -FD_lte_phy_scope_enb *form_enb[NUMBER_OF_UE_MAX]; -FD_stats_form *form_stats=NULL; -char title[255]; -unsigned char scope_enb_num_ue = 1; -#endif //XFORMS - -#ifdef EMOS -#include -#include - -//#define CHANSOUNDER_FIFO_SIZE 10485760 // 10 Mbytes FIFO -#define CHANSOUNDER_FIFO_SIZE 20971520 // 20 Mbytes FIFO -#define CHANSOUNDER_FIFO_MINOR 4 // minor of the FIFO device - this is /dev/rtf3 -#define CHANSOUNDER_FIFO_DEV "/dev/rtf4" -#endif - -#define TIMER_ONESHOT_MODE -#define FRAME_PERIOD 100000000ULL -#define DAQ_PERIOD 66667ULL -#define LTE_SLOTS_PER_FRAME 20 -#define RESAMPLING_FACTOR 2 -#define SAMPLES_PER_SLOT (15360/(1<stats_text, stats_buffer); - //rewind (UE_stats); - //fwrite (stats_buffer, 1, len, UE_stats); - - phy_scope_UE(form_ue[UE_id], - PHY_vars_UE_g[UE_id], - eNB_id, - UE_id,7); - - } else { - len = dump_eNB_stats (PHY_vars_eNB_g[0], stats_buffer, 0); - fl_set_object_label(form_stats->stats_text, stats_buffer); - - //rewind (eNB_stats); - //fwrite (stats_buffer, 1, len, eNB_stats); - for(UE_id=0; UE_id=5 - ret = gps_open("127.0.0.1","2947",gps_data); - - if (ret!=0) -#else - gps_data = gps_open("127.0.0.1","2947"); - - if (gps_data == NULL) -#endif - { - printf("[EMOS] Could not open GPS\n"); - //exit(-1); - } - -#if GPSD_API_MAJOR_VERSION>=4 - else if (gps_stream(gps_data, WATCH_ENABLE,NULL) != 0) -#else - else if (gps_query(gps_data, "w+x") != 0) -#endif - { - //sprintf(tmptxt,"Error sending command to GPS, gps_data = %x", gps_data); - printf("[EMOS] Error sending command to GPS\n"); - //exit(-1); - } else - printf("[EMOS] Opened GPS, gps_data=%p\n", gps_data); - - /* - if (UE_flag==0) - channel_buffer_size = sizeof(fifo_dump_emos_eNB); - else - channel_buffer_size = sizeof(fifo_dump_emos_UE); - */ - - // allocate memory for NO_FRAMES_DISK channes estimations - fifo2file_buffer = malloc(NO_ESTIMATES_DISK*channel_buffer_size); - fifo2file_ptr = fifo2file_buffer; - - if (fifo2file_buffer == NULL) { - printf("[EMOS] Cound not allocate memory for fifo2file_buffer\n"); - exit(EXIT_FAILURE); - } - - if ((fifo = open(CHANSOUNDER_FIFO_DEV, O_RDONLY)) < 0) { - fprintf(stderr, "[EMOS] Error opening the fifo\n"); - exit(EXIT_FAILURE); - } - - - time(&starttime_tmp); - localtime_r(&starttime_tmp,&starttime); - snprintf(dumpfile_name,1024,"/tmp/%s_data_%d%02d%02d_%02d%02d%02d.EMOS", - (UE_flag==0) ? "eNB" : "UE", - 1900+starttime.tm_year, starttime.tm_mon+1, starttime.tm_mday, starttime.tm_hour, starttime.tm_min, starttime.tm_sec); - - dumpfile_id = fopen(dumpfile_name,"w"); - - if (dumpfile_id == NULL) { - fprintf(stderr, "[EMOS] Error opening dumpfile %s\n",dumpfile_name); - exit(EXIT_FAILURE); - } - - - printf("[EMOS] starting dump, channel_buffer_size=%d ...\n",channel_buffer_size); - - while (!oai_exit) { - bytes = rtf_read_timed(fifo, fifo2file_ptr, channel_buffer_size,100); - - if (bytes<=0) - continue; - - /* - if (UE_flag==0) - printf("eNB: count %d, frame %d, read: %d bytes from the fifo\n",counter, ((fifo_dump_emos_eNB*)fifo2file_ptr)->frame_tx,bytes); - else - printf("UE: count %d, frame %d, read: %d bytes from the fifo\n",counter, ((fifo_dump_emos_UE*)fifo2file_ptr)->frame_rx,bytes); - */ - - fifo2file_ptr += channel_buffer_size; - counter ++; - total_bytes += bytes; - - if ((counter%NO_ESTIMATES_DISK)==0) { - //reset stuff - fifo2file_ptr = fifo2file_buffer; - //counter = 0; - - //flush buffer to disk - if (fwrite(fifo2file_buffer, sizeof(char), NO_ESTIMATES_DISK*channel_buffer_size, dumpfile_id) != NO_ESTIMATES_DISK*channel_buffer_size) { - fprintf(stderr, "[EMOS] Error writing to dumpfile\n"); - exit(EXIT_FAILURE); - } - - /* - if (gps_data) - { - if (gps_poll(gps_data) != 0) { - printf("[EMOS] problem polling data from gps\n"); - } - else { - printf("[EMOS] lat %g, lon %g\n",gps_data->fix.latitude,gps_data->fix.longitude); - } - if (fwrite(&(gps_data->fix), sizeof(char), sizeof(struct gps_fix_t), dumpfile_id) != sizeof(struct gps_fix_t)) - { - printf("[EMOS] Error writing to dumpfile, stopping recording\n"); - exit(EXIT_FAILURE); - } - } - else - { - printf("[EMOS] WARNING: No GPS data available, storing dummy packet\n"); - if (fwrite(&(dummy_gps_data), sizeof(char), sizeof(struct gps_fix_t), dumpfile_id) != sizeof(struct gps_fix_t)) - { - printf("[EMOS] Error writing to dumpfile, stopping recording\n"); - exit(EXIT_FAILURE); - } - } - */ - } - - if ((counter%2000)==0) - printf("[EMOS] count %d (%d sec), total bytes wrote %llu\n", counter, counter/2000, total_bytes); - } - - free(fifo2file_buffer); - fclose(dumpfile_id); - close(fifo); - - pthread_exit((void*) arg); - -} -#endif - -/* This is the main eNB thread. It gets woken up by the kernel driver using the RTAI message mechanism (rt_send and rt_receive). */ -static void *eNB_thread(void *arg) -{ -#ifdef RTAI - RT_TASK *task; - RTIME now; -#endif - unsigned char slot=0,last_slot, next_slot; - int hw_slot,frame=0; - unsigned int msg1; - unsigned int aa,slot_offset, slot_offset_F; - int diff; - int delay_cnt; - RTIME time_in, time_diff; - int mbox_target=0,mbox_current=0; - int i,ret; - int tx_offset; - int bytes; - -#ifdef RTAI - task = rt_task_init_schmod(nam2num("TASK0"), 0, 0, 0, SCHED_FIFO, 0xF); - LOG_D(HW,"Started eNB thread (id %p)\n",task); -#ifndef TIMER_ONESHOT_MODE - now = rt_get_time(); - ret = rt_task_make_periodic(task, now, nano2count(500000LL)); - - if (ret!=0) - LOG_E(HW,"Problem with periodic timer\n"); - -#endif -#endif - -#ifdef HARD_RT - rt_make_hard_real_time(); -#endif - - mlockall(MCL_CURRENT | MCL_FUTURE); - - timing_info.time_min = 100000000ULL; - timing_info.time_max = 0; - timing_info.time_avg = 0; - timing_info.n_samples = 0; - - while (!oai_exit) { - hw_slot = (((((volatile unsigned int *)DAQ_MBOX)[0]+1)%150)<<1)/15; - //LOG_D(HW,"eNB frame %d, time %llu: slot %d, hw_slot %d (mbox %d)\n",frame,rt_get_time_ns(),slot,hw_slot,((unsigned int *)DAQ_MBOX)[0]); - //this is the mbox counter where we should be - //mbox_target = ((((slot+1)%20)*15+1)>>1)%150; - mbox_target = mbox_bounds[slot]; - //this is the mbox counter where we are - mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0]; - - //this is the time we need to sleep in order to synchronize with the hw (in multiples of DAQ_PERIOD) - if ((mbox_current>=135) && (mbox_target<15)) //handle the frame wrap-arround - diff = 150-mbox_current+mbox_target; - else if ((mbox_current<15) && (mbox_target>=135)) - diff = -150+mbox_target-mbox_current; - else - diff = mbox_target - mbox_current; - - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_ENB, slot); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_ENB, frame); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *((volatile unsigned int *) openair0_exmimo_pci[card].rxcnt_ptr[0])); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DIFF, diff); - - time_in = rt_get_time_ns(); - //LOG_D(HW,"eNB Frame %d delaycnt %d : hw_slot %d (%d), slot %d, (slot+1)*15=%d, diff %d, time %llu\n",frame,delay_cnt,hw_slot,((unsigned int *)DAQ_MBOX)[0],slot,(((slot+1)*15)>>1),diff,time_in); - //LOG_D(HW,"eNB Frame %d, time %llu: sleeping for %llu (slot %d, hw_slot %d, diff %d, mbox %d, delay_cnt %d)\n", frame, time_in, diff*DAQ_PERIOD,slot,hw_slot,diff,((volatile unsigned int *)DAQ_MBOX)[0],delay_cnt); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RT_SLEEP,1); -#ifdef TIMER_ONESHOT_MODE - //ret = rt_sleep_ns(DAQ_PERIOD * (slot%4==0?6:8)); - ret = rt_sleep_ns(500000); - - if (ret) - LOG_D(HW,"eNB Frame %d, time %llu: rt_sleep_ns returned %d\n",frame, time_in); - -#else - rt_task_wait_period(); -#endif - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RT_SLEEP,0); - - //hw_slot = (((((volatile unsigned int *)DAQ_MBOX)[0]+1)%150)<<1)/15; - //LOG_D(HW,"eNB Frame %d : hw_slot %d, time %llu\n",frame,hw_slot,rt_get_time_ns()); - - mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0]; - - if ((mbox_current>=135) && (mbox_target<15)) //handle the frame wrap-arround - diff = 150-mbox_current+mbox_target; - else if ((mbox_current<15) && (mbox_target>=135)) - diff = -150+mbox_target-mbox_current; - else - diff = mbox_target - mbox_current; - - - last_slot = (slot)%LTE_SLOTS_PER_FRAME; - - if (last_slot <0) - last_slot+=20; - - next_slot = (slot+3)%LTE_SLOTS_PER_FRAME; - - slot++; - - if (slot==20) { - slot=0; - frame++; - } - - if (frame==1000) - oai_exit=1; - -#if defined(ENABLE_ITTI) - itti_update_lte_time(frame, slot); -#endif - } - - LOG_D(HW,"eNB_thread: finished, ran %d times.\n",frame); - -#ifdef HARD_RT - rt_make_soft_real_time(); -#endif - - // clean task -#ifdef RTAI - rt_task_delete(task); -#endif - LOG_D(HW,"Task deleted. returning\n"); - return 0; -} - - -int main(int argc, char **argv) -{ - -#ifdef RTAI - RT_TASK *task; - RTIME period; -#endif - int i,j,aa; - void *status; - - /* - uint32_t rf_mode_max[4] = {55759,55759,55759,55759}; - uint32_t rf_mode_med[4] = {39375,39375,39375,39375}; - uint32_t rf_mode_byp[4] = {22991,22991,22991,22991}; - */ - uint32_t my_rf_mode = RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM + DMAMODE_RX + DMAMODE_TX; - uint32_t rf_mode_base = TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM; - uint32_t rf_mode[4] = {my_rf_mode,0,0,0}; - uint32_t rf_local[4] = {8255000,8255000,8255000,8255000}; // UE zepto - //{8254617, 8254617, 8254617, 8254617}; //eNB khalifa - //{8255067,8254810,8257340,8257340}; // eNB PETRONAS - - uint32_t rf_vcocal[4] = {910,910,910,910}; - uint32_t rf_vcocal_850[4] = {2015, 2015, 2015, 2015}; - uint32_t rf_rxdc[4] = {32896,32896,32896,32896}; - uint32_t rxgain[4] = {20,20,20,20}; - uint32_t txgain[4] = {20,20,20,20}; - - uint16_t Nid_cell = 0; - uint8_t cooperation_flag=0, transmission_mode=1, abstraction_flag=0; - uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2; - - int c; - char do_forms=0; - unsigned int fd; - unsigned int tcxo = 114; - - int amp; - uint8_t prach_fmt; - int N_ZC; - - char rxg_fname[100]; - char txg_fname[100]; - char rflo_fname[100]; - char rfdc_fname[100]; - FILE *rxg_fd=NULL; - FILE *txg_fd=NULL; - FILE *rflo_fd=NULL; - FILE *rfdc_fd=NULL; - unsigned int rxg_max[4]= {133,133,133,133}, rxg_med[4]= {127,127,127,127}, rxg_byp[4]= {120,120,120,120}; - int tx_max_power=0; - - char line[1000]; - int l; - int ret, ant; - int ant_offset=0; - - int error_code; - char *itti_dump_file = NULL; - - const struct option long_options[] = { - {"calib-ue-rx", required_argument, NULL, 256}, - {"calib-ue-rx-med", required_argument, NULL, 257}, - {"calib-ue-rx-byp", required_argument, NULL, 258}, - {"debug-ue-prach", no_argument, NULL, 259}, - {"no-L2-connect", no_argument, NULL, 260}, - {NULL, 0, NULL, 0} - }; - - //mode = normal_txrx; - - - while ((c = getopt_long (argc, argv, "C:K:O:ST:UdF:V",long_options,NULL)) != -1) { - switch (c) { - case 'V': - ouput_vcd = 1; - break; - - case 'd': - do_forms=1; - break; - - case 'U': - UE_flag = 1; - break; - - case 'C': - carrier_freq[0] = atoi(optarg); - carrier_freq[1] = atoi(optarg); - carrier_freq[2] = atoi(optarg); - carrier_freq[3] = atoi(optarg); - break; - - case 'S': - fs4_test=1; - break; - - case 'T': - tcxo=atoi(optarg); - break; - - case 'K': -#if defined(ENABLE_ITTI) - itti_dump_file = strdup(optarg); -#else - printf("-K option is disabled when ENABLE_ITTI is not defined\n"); -#endif - break; - - case 'O': -#if defined(ENABLE_USE_MME) - EPC_MODE_ENABLED = 1; - - if (optarg == NULL) { /* No IP address provided: use localhost */ - memcpy(&EPC_MODE_MME_ADDRESS[0], "127.0.0.1", 10); - } else { - uint8_t ip_length = strlen(optarg) + 1; - memcpy(&EPC_MODE_MME_ADDRESS[0], optarg, - ip_length > 16 ? 16 : ip_length); - } - -#else - printf("You enabled mme mode without s1ap compiled...\n"); -#endif - break; - - case 'F': - sprintf(rxg_fname,"%srxg.lime",optarg); - rxg_fd = fopen(rxg_fname,"r"); - - if (rxg_fd) { - printf("Loading RX Gain parameters from %s\n",rxg_fname); - l=0; - - while (fgets(line, sizeof(line), rxg_fd)) { - if ((strlen(line)==0) || (*line == '#')) continue; //ignore empty or comment lines - else { - if (l==0) sscanf(line,"%d %d %d %d",&rxg_max[0],&rxg_max[1],&rxg_max[2],&rxg_max[3]); - - if (l==1) sscanf(line,"%d %d %d %d",&rxg_med[0],&rxg_med[1],&rxg_med[2],&rxg_med[3]); - - if (l==2) sscanf(line,"%d %d %d %d",&rxg_byp[0],&rxg_byp[1],&rxg_byp[2],&rxg_byp[3]); - - l++; - } - } - } else - printf("%s not found, running with defaults\n",rxg_fname); - - sprintf(txg_fname,"%stxg.lime",optarg); - txg_fd = fopen(txg_fname,"r"); - - if (txg_fd) { - printf("Loading TX Gain parameters from %s\n",txg_fname); - l=0; - - while (fgets(line, sizeof(line), txg_fd)) { - if ((strlen(line)==0) || (*line == '#')) { - continue; //ignore empty or comment lines - } else { - if (l==0) sscanf(line,"%d %d %d %d",&txgain[0],&txgain[1],&txgain[2],&txgain[3]); - - if (l==1) sscanf(line,"%d",&tx_max_power); - - l++; - } - } - } else - printf("%s not found, running with defaults\n",txg_fname); - - sprintf(rflo_fname,"%srflo.lime",optarg); - rflo_fd = fopen(rflo_fname,"r"); - - if (rflo_fd) { - printf("Loading RF LO parameters from %s\n",rflo_fname); - fscanf(rflo_fd,"%d %d %d %d",&rf_local[0],&rf_local[1],&rf_local[2],&rf_local[3]); - } else - printf("%s not found, running with defaults\n",rflo_fname); - - sprintf(rfdc_fname,"%srfdc.lime",optarg); - rfdc_fd = fopen(rfdc_fname,"r"); - - if (rfdc_fd) { - printf("Loading RF DC parameters from %s\n",rfdc_fname); - fscanf(rfdc_fd,"%d %d %d %d",&rf_rxdc[0],&rf_rxdc[1],&rf_rxdc[2],&rf_rxdc[3]); - } else - printf("%s not found, running with defaults\n",rfdc_fname); - - break; - - /* - case 256: - mode = rx_calib_ue; - rx_input_level_dBm = atoi(optarg); - printf("Running with UE calibration on (LNA max), input level %d dBm\n",rx_input_level_dBm); - break; - case 257: - mode = rx_calib_ue_med; - rx_input_level_dBm = atoi(optarg); - printf("Running with UE calibration on (LNA med), input level %d dBm\n",rx_input_level_dBm); - break; - case 258: - mode = rx_calib_ue_byp; - rx_input_level_dBm = atoi(optarg); - printf("Running with UE calibration on (LNA byp), input level %d dBm\n",rx_input_level_dBm); - break; - case 259: - mode = debug_prach; - break; - case 260: - mode = no_L2_connect; - break; - */ - default: - break; - } - } - - if (UE_flag==1) - printf("configuring for UE\n"); - else - printf("configuring for eNB\n"); - - //randominit (0); - //set_taus_seed (0); - - // initialize the log (see log.h for details) - logInit(); - -#if defined(ENABLE_ITTI) - itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info, messages_definition_xml, itti_dump_file); - -# if defined(ENABLE_USE_MME) - - if (itti_create_task(TASK_SCTP, sctp_eNB_task, NULL) < 0) { - LOG_E(EMU, "Create task failed"); - LOG_D(EMU, "Initializing SCTP task interface: FAILED\n"); - return -1; - } - - if (itti_create_task(TASK_S1AP, s1ap_eNB_task, NULL) < 0) { - LOG_E(EMU, "Create task failed"); - LOG_D(EMU, "Initializing S1AP task interface: FAILED\n"); - return -1; - } - -# endif - - if (itti_create_task(TASK_L2L1, l2l1_task, NULL) < 0) { - LOG_E(EMU, "Create task failed"); - LOG_D(EMU, "Initializing L2L1 task interface: FAILED\n"); - return -1; - } - - // Handle signals until all tasks are terminated - // itti_wait_tasks_end(); -#endif - - if (ouput_vcd) { - if (UE_flag==1) - VCD_SIGNAL_DUMPER_INIT("/tmp/openair_dump_UE.vcd"); - else - VCD_SIGNAL_DUMPER_INIT("/tmp/openair_dump_eNB.vcd"); - } - -#ifdef PDCP_USE_NETLINK - netlink_init(); -#endif - - // to make a graceful exit when ctrl-c is pressed - signal(SIGSEGV, signal_handler); - signal(SIGINT, signal_handler); - -#ifndef RTAI - check_clock(); -#endif - - g_log->log_component[HW].level = LOG_DEBUG; - g_log->log_component[HW].flag = LOG_HIGH; -#ifdef OPENAIR2 - g_log->log_component[PHY].level = LOG_INFO; -#else - g_log->log_component[PHY].level = LOG_INFO; -#endif - g_log->log_component[PHY].flag = LOG_HIGH; - g_log->log_component[MAC].level = LOG_INFO; - g_log->log_component[MAC].flag = LOG_HIGH; - g_log->log_component[RLC].level = LOG_INFO; - g_log->log_component[RLC].flag = LOG_HIGH; - g_log->log_component[PDCP].level = LOG_INFO; - g_log->log_component[PDCP].flag = LOG_HIGH; - g_log->log_component[OTG].level = LOG_INFO; - g_log->log_component[OTG].flag = LOG_HIGH; - g_log->log_component[RRC].level = LOG_INFO; - g_log->log_component[RRC].flag = LOG_HIGH; - - - // Initialize card - ret = openair0_open(); - - if ( ret != 0 ) { - if (ret == -1) - printf("Error opening /dev/openair0"); - - if (ret == -2) - printf("Error mapping bigshm"); - - if (ret == -3) - printf("Error mapping RX or TX buffer"); - - return(ret); - } - - printf ("Detected %d number of cards, %d number of antennas.\n", openair0_num_detected_cards, openair0_num_antennas[card]); - - p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr; - p_exmimo_id = openair0_exmimo_pci[card].exmimo_id_ptr; - - printf("Card %d: ExpressMIMO %d, HW Rev %d, SW Rev 0x%d\n", card, p_exmimo_id->board_exmimoversion, p_exmimo_id->board_hwrev, p_exmimo_id->board_swrev); - - if (p_exmimo_id->board_swrev>=BOARD_SWREV_CNTL2) - p_exmimo_config->framing.eNB_flag = 0; - else - p_exmimo_config->framing.eNB_flag = !UE_flag; - - p_exmimo_config->framing.tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_LSB; - - for (ant=0; ant<4; ant++) - p_exmimo_config->framing.resampling_factor[ant] = RESAMPLING_FACTOR; - - /* - for (ant=0;antnb_antennas_tx,frame_parms->nb_antennas_rx);ant++) - p_exmimo_config->rf.rf_mode[ant] = rf_mode_base; - for (ant=0;antnb_antennas_tx;ant++) - p_exmimo_config->rf.rf_mode[ant] += (TXEN + DMAMODE_TX); - for (ant=0;antnb_antennas_rx;ant++) - p_exmimo_config->rf.rf_mode[ant] += (RXEN + DMAMODE_RX); - for (ant=max(frame_parms->nb_antennas_tx,frame_parms->nb_antennas_rx);ant<4;ant++) { - p_exmimo_config->rf.rf_mode[ant] = 0; - carrier_freq[ant] = 0; //this turns off all other LIMEs - } - */ - - ant_offset = 0; - - for (ant=0; ant<4; ant++) { - if (ant==ant_offset) { - //if (1) { - p_exmimo_config->rf.rf_mode[ant] = rf_mode_base; - //p_exmimo_config->rf.rf_mode[ant] += (TXEN + DMAMODE_TX); - p_exmimo_config->rf.rf_mode[ant] += (RXEN + DMAMODE_RX); - } else { - p_exmimo_config->rf.rf_mode[ant] = 0; - carrier_freq[ant] = 0; //this turns off all other LIMEs - } - } - - for (ant = 0; ant<4; ant++) { - p_exmimo_config->rf.do_autocal[ant] = 1; - p_exmimo_config->rf.rf_freq_rx[ant] = carrier_freq[ant]; - p_exmimo_config->rf.rf_freq_tx[ant] = carrier_freq[ant]; - p_exmimo_config->rf.rx_gain[ant][0] = rxgain[ant]; - p_exmimo_config->rf.tx_gain[ant][0] = txgain[ant]; - - p_exmimo_config->rf.rf_local[ant] = rf_local[ant]; - p_exmimo_config->rf.rf_rxdc[ant] = rf_rxdc[ant]; - - if ((carrier_freq[ant] >= 850000000) && (carrier_freq[ant] <= 865000000)) { - p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal_850[ant]; - p_exmimo_config->rf.rffe_band_mode[ant] = DD_TDD; - } else if ((carrier_freq[ant] >= 1900000000) && (carrier_freq[ant] <= 2000000000)) { - p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal[ant]; - p_exmimo_config->rf.rffe_band_mode[ant] = B19G_TDD; - } else { - p_exmimo_config->rf.rf_vcocal[ant] = rf_vcocal[ant]; - p_exmimo_config->rf.rffe_band_mode[ant] = 0; - } - - p_exmimo_config->rf.rffe_gain_txlow[ant] = 31; - p_exmimo_config->rf.rffe_gain_txhigh[ant] = 31; - p_exmimo_config->rf.rffe_gain_rxfinal[ant] = 52; - p_exmimo_config->rf.rffe_gain_rxlow[ant] = 31; - } - - - number_of_cards = openair0_num_detected_cards; - /* - if (p_exmimo_id->board_exmimoversion==1) //ExpressMIMO1 - openair_daq_vars.timing_advance = 138; - else //ExpressMIMO2 - openair_daq_vars.timing_advance = 0; - */ - - openair0_dump_config(card); - - printf("EXMIMO_CONFIG: rf_mode 0x %x %x %x %x, [0]: TXRXEn %d, TXLPFEn %d, TXLPF %d, RXLPFEn %d, RXLPF %d, RFBB %d, LNA %d, LNAGain %d, RXLPFMode %d, SWITCH %d, rf_rxdc %d, rf_local %d, rf_vcocal %d\n", - p_exmimo_config->rf.rf_mode[0], - p_exmimo_config->rf.rf_mode[1], - p_exmimo_config->rf.rf_mode[2], - p_exmimo_config->rf.rf_mode[3], - (p_exmimo_config->rf.rf_mode[0]&3), // RXen+TXen - (p_exmimo_config->rf.rf_mode[0]&4)>>2, //TXLPFen - (p_exmimo_config->rf.rf_mode[0]&TXLPFMASK)>>3, //TXLPF - (p_exmimo_config->rf.rf_mode[0]&128)>>7, //RXLPFen - (p_exmimo_config->rf.rf_mode[0]&RXLPFMASK)>>8, //TXLPF - (p_exmimo_config->rf.rf_mode[0]&RFBBMASK)>>16, // RFBB mode - (p_exmimo_config->rf.rf_mode[0]&LNAMASK)>>12, // RFBB mode - (p_exmimo_config->rf.rf_mode[0]&LNAGAINMASK)>>14, // RFBB mode - (p_exmimo_config->rf.rf_mode[0]&RXLPFMODEMASK)>>19, // RXLPF mode - (p_exmimo_config->framing.tdd_config&TXRXSWITCH_MASK)>>1, // Switch mode - p_exmimo_config->rf.rf_rxdc[0], - p_exmimo_config->rf.rf_local[0], - p_exmimo_config->rf.rf_vcocal[0]); - - for (ant=0; ant<4; ant++) - p_exmimo_config->rf.do_autocal[ant] = 0; - -#ifdef EMOS - error_code = rtf_create(CHANSOUNDER_FIFO_MINOR,CHANSOUNDER_FIFO_SIZE); - - if (error_code==0) - printf("[OPENAIR][SCHED][INIT] Created EMOS FIFO %d\n",CHANSOUNDER_FIFO_MINOR); - else if (error_code==ENODEV) - printf("[OPENAIR][SCHED][INIT] Problem: EMOS FIFO %d is greater than or equal to RTF_NO\n",CHANSOUNDER_FIFO_MINOR); - else if (error_code==ENOMEM) - printf("[OPENAIR][SCHED][INIT] Problem: cannot allocate memory for EMOS FIFO %d\n",CHANSOUNDER_FIFO_MINOR); - else - printf("[OPENAIR][SCHED][INIT] Problem creating EMOS FIFO %d, error_code %d\n",CHANSOUNDER_FIFO_MINOR,error_code); - -#endif - - mlockall(MCL_CURRENT | MCL_FUTURE); - -#ifdef RTAI - // make main thread LXRT soft realtime - task = rt_task_init_schmod(nam2num("MYTASK"), 9, 0, 0, SCHED_FIFO, 0xF); - - // start realtime timer and scheduler -#ifdef TIMER_ONESHOT_MODE - rt_set_oneshot_mode(); - start_rt_timer(0); - printf("started RTAI timer inoneshot mode\n"); -#else - rt_set_periodic_mode(); - period = start_rt_timer(nano2count(500000)); - printf("started RTAI timer with period %llu ns\n",count2nano(period)); -#endif - - printf("Init mutex\n"); - //mutex = rt_get_adr(nam2num("MUTEX")); - mutex = rt_sem_init(nam2num("MUTEX"), 1); - - if (mutex==0) { - printf("Error init mutex\n"); - exit(-1); - } else - printf("mutex=%p\n",mutex); - -#endif - - DAQ_MBOX = (volatile unsigned int *) openair0_exmimo_pci[card].rxcnt_ptr[0]; - - // this starts the DMA transfers - if (UE_flag!=1) - openair0_start_rt_acquisition(card); - - -#ifdef XFORMS - - if (do_forms==1) { - fl_initialize (&argc, argv, NULL, 0, 0); - form_stats = create_form_stats_form(); - - if (UE_flag==1) { - form_ue[UE_id] = create_lte_phy_scope_ue(); - sprintf (title, "LTE DL SCOPE UE"); - fl_show_form (form_ue[UE_id]->lte_phy_scope_ue, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); - } else { - for(UE_id=0; UE_idlte_phy_scope_enb, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); - } - } - - fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats"); - - if (UE_flag==0) { - for (UE_id=0; UE_idbutton_0,1); - fl_set_object_label(form_enb[UE_id]->button_0,"DL Traffic ON"); - } else { - fl_set_button(form_enb[UE_id]->button_0,0); - fl_set_object_label(form_enb[UE_id]->button_0,"DL Traffic OFF"); - } - } - } else { - if (openair_daq_vars.use_ia_receiver) { - fl_set_button(form_ue[UE_id]->button_0,1); - fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver ON"); - } else { - fl_set_button(form_ue[UE_id]->button_0,0); - fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF"); - } - } - - ret = pthread_create(&thread2, NULL, scope_thread, NULL); - printf("Scope thread created, ret=%d\n",ret); - } - -#endif - -#ifdef EMOS - ret = pthread_create(&thread3, NULL, emos_thread, NULL); - printf("EMOS thread created, ret=%d\n",ret); -#endif - - rt_sleep_ns(10*FRAME_PERIOD); - -#ifndef RTAI - pthread_attr_init (&attr_dlsch_threads); - pthread_attr_setstacksize(&attr_dlsch_threads,OPENAIR_THREAD_STACK_SIZE); - //attr_dlsch_threads.priority = 1; - sched_param_dlsch.sched_priority = sched_get_priority_max(SCHED_FIFO); //OPENAIR_THREAD_PRIORITY; - pthread_attr_setschedparam (&attr_dlsch_threads, &sched_param_dlsch); - pthread_attr_setschedpolicy (&attr_dlsch_threads, SCHED_FIFO); -#endif - - // start the main thread - if (UE_flag == 1) { - /* - #ifdef RTAI - thread1 = rt_thread_create(UE_thread, NULL, 100000000); - #else - error_code = pthread_create(&thread1, &attr_dlsch_threads, UE_thread, NULL); - if (error_code!= 0) { - LOG_D(HW,"[lte-softmodem.c] Could not allocate UE_thread, error %d\n",error_code); - return(error_code); - } - else { - LOG_D(HW,"[lte-softmodem.c] Allocate UE_thread successful\n"); - } - #endif - #ifdef DLSCH_THREAD - init_rx_pdsch_thread(); - rt_sleep_ns(FRAME_PERIOD/10); - init_dlsch_threads(); - #endif - printf("UE threads created\n"); - */ - } else { -#ifdef RTAI - thread0 = rt_thread_create(eNB_thread, NULL, 100000000); -#else - error_code = pthread_create(&thread0, &attr_dlsch_threads, eNB_thread, NULL); - - if (error_code!= 0) { - LOG_D(HW,"[lte-softmodem.c] Could not allocate eNB_thread, error %d\n",error_code); - return(error_code); - } else { - LOG_D(HW,"[lte-softmodem.c] Allocate eNB_thread successful\n"); - } - -#endif -#ifdef ULSCH_THREAD - init_ulsch_threads(); -#endif - printf("eNB threads created\n"); - } - - - // wait for end of program - printf("TYPE TO TERMINATE\n"); - - //getchar(); - while (oai_exit==0) - rt_sleep_ns(FRAME_PERIOD); - - // stop threads -#ifdef XFORMS - printf("waiting for XFORMS thread\n"); - - if (do_forms==1) { - pthread_join(thread2,&status); - fl_hide_form(form_stats->stats_form); - fl_free_form(form_stats->stats_form); - - if (UE_flag==1) { - fl_hide_form(form_ue[UE_id]->lte_phy_scope_ue); - fl_free_form(form_ue[UE_id]->lte_phy_scope_ue); - } else { - for(UE_id=0; UE_idlte_phy_scope_enb); - fl_free_form(form_enb[UE_id]->lte_phy_scope_enb); - } - } - } - -#endif - - printf("stopping MODEM threads\n"); - - // cleanup - if (UE_flag == 1) { - /* - #ifdef RTAI - rt_thread_join(thread1); - #else - pthread_join(thread1,&status); - #endif - #ifdef DLSCH_THREAD - cleanup_dlsch_threads(); - cleanup_rx_pdsch_thread(); - #endif - */ - } else { -#ifdef RTAI - rt_thread_join(thread0); -#else - pthread_join(thread0,&status); -#endif -#ifdef ULSCH_THREAD - cleanup_ulsch_threads(); -#endif - } - -#ifdef OPENAIR2 - //cleanup_pdcp_thread(); -#endif - -#ifdef RTAI - stop_rt_timer(); -#endif - - printf("stopping card\n"); - openair0_stop(card); - printf("closing openair0_lib\n"); - openair0_close(); - -#ifdef EMOS - printf("waiting for EMOS thread\n"); - pthread_cancel(thread3); - pthread_join(thread3,&status); -#endif - -#ifdef EMOS - error_code = rtf_destroy(CHANSOUNDER_FIFO_MINOR); - printf("[OPENAIR][SCHED][CLEANUP] EMOS FIFO closed, error_code %d\n", error_code); -#endif - - if (ouput_vcd) - VCD_SIGNAL_DUMPER_CLOSE(); - - logClean(); - - return 0; -} - -void test_config(int card, int ant, unsigned int rf_mode, int UE_flag) -{ - p_exmimo_config->framing.eNB_flag = !UE_flag; - p_exmimo_config->framing.tdd_config = 0; - p_exmimo_config->framing.resampling_factor[ant] = 2; - - p_exmimo_config->rf.rf_freq_rx[ant] = 1907600000; - p_exmimo_config->rf.rf_freq_tx[ant] = 1907600000;; - p_exmimo_config->rf.rx_gain[ant][0] = 20; - p_exmimo_config->rf.tx_gain[ant][0] = 10; - p_exmimo_config->rf.rf_mode[ant] = rf_mode; - - p_exmimo_config->rf.rf_local[ant] = build_rflocal(20,25,26,04); - p_exmimo_config->rf.rf_rxdc[ant] = build_rfdc(128, 128); - p_exmimo_config->rf.rf_vcocal[ant] = (0xE<<6) + 0xE; -} - -/* -void setup_ue_buffers(PHY_VARS_UE *phy_vars_ue, LTE_DL_FRAME_PARMS *frame_parms, int carrier) { - - int i; - if (phy_vars_ue) { - - if ((frame_parms->nb_antennas_rx>1) && (carrier>0)) { - printf("RX antennas > 1 and carrier > 0 not possible\n"); - exit(-1); - } - - if ((frame_parms->nb_antennas_tx>1) && (carrier>0)) { - printf("TX antennas > 1 and carrier > 0 not possible\n"); - exit(-1); - } - - // replace RX signal buffers with mmaped HW versions - for (i=0;inb_antennas_rx;i++) { - free(phy_vars_ue->lte_ue_common_vars.rxdata[i]); - phy_vars_ue->lte_ue_common_vars.rxdata[i] = (int32_t*) openair0_exmimo_pci[card].adc_head[i+carrier]; - - - printf("rxdata[%d] @ %p\n",i,phy_vars_ue->lte_ue_common_vars.rxdata[i]); - } - for (i=0;inb_antennas_tx;i++) { - free(phy_vars_ue->lte_ue_common_vars.txdata[i]); - phy_vars_ue->lte_ue_common_vars.txdata[i] = (int32_t*) openair0_exmimo_pci[card].dac_head[i+carrier]; - - printf("txdata[%d] @ %p\n",i,phy_vars_ue->lte_ue_common_vars.txdata[i]); - } - } -} - -void setup_eNB_buffers(PHY_VARS_eNB *phy_vars_eNB, LTE_DL_FRAME_PARMS *frame_parms, int carrier) { - - int i,j; - - if (phy_vars_eNB) { - if ((frame_parms->nb_antennas_rx>1) && (carrier>0)) { - printf("RX antennas > 1 and carrier > 0 not possible\n"); - exit(-1); - } - - if ((frame_parms->nb_antennas_tx>1) && (carrier>0)) { - printf("TX antennas > 1 and carrier > 0 not possible\n"); - exit(-1); - } - - // replace RX signal buffers with mmaped HW versions - for (i=0;inb_antennas_rx;i++) { - free(phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i]); - phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i] = (int32_t*) openair0_exmimo_pci[card].adc_head[i+carrier]; - - printf("rxdata[%d] @ %p\n",i,phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i]); - for (j=0;j<16;j++) { - printf("rxbuffer %d: %x\n",j,phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i][j]); - phy_vars_eNB->lte_eNB_common_vars.rxdata[0][i][j] = 16-j; - } - } - for (i=0;inb_antennas_tx;i++) { - free(phy_vars_eNB->lte_eNB_common_vars.txdata[0][i]); - phy_vars_eNB->lte_eNB_common_vars.txdata[0][i] = (int32_t*) openair0_exmimo_pci[card].dac_head[i+carrier]; - - printf("txdata[%d] @ %p\n",i,phy_vars_eNB->lte_eNB_common_vars.txdata[0][i]); - for (j=0;j<16;j++) { - printf("txbuffer %d: %x\n",j,phy_vars_eNB->lte_eNB_common_vars.txdata[0][i][j]); - phy_vars_eNB->lte_eNB_common_vars.txdata[0][i][j] = 16-j; - } - } - } -} -*/ diff --git a/targets/SIMU/USER/Makefile b/targets/SIMU/USER/Makefile index e48b4b62ad..12595aa86c 100644 --- a/targets/SIMU/USER/Makefile +++ b/targets/SIMU/USER/Makefile @@ -34,7 +34,7 @@ CFLAGS += -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 $(CPUFLAGS) ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES CFLAGS += -DOPENAIR_LTE -DPUCCH #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE -CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 -DPHY_ABSTRACTION #-DPHY_ABSTRACTION_UL #-DRLC_UM_TEST_TRAFFIC=1 +CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 #-DRLC_UM_TEST_TRAFFIC=1 CFLAGS += -DNEW_FFT #CFLAGS += -DLLR8 CFLAGS += -DPACKAGE_NAME='"oaisim"' @@ -48,15 +48,6 @@ DISABLE_XER_PRINT=0 MSG_PRINT=1 endif -ifndef OPENAIR_EMU -export OPENAIR_EMU=1 -CFLAGS += -DOAISIM -endif - -ifdef EMOS -CFLAGS+=-DEMOS -endif - ifeq ($(LOCALIZATION), 1) CFLAGS += -DLOCALIZATION endif @@ -179,7 +170,7 @@ ifdef OAI_NW_DRIVER_TYPE_ETHERNET CFLAGS+=-DOAI_NW_DRIVER_TYPE_ETHERNET endif -CFLAGS += -DENABLE_FXP -DOAI_EMU -DENABLE_USE_CPU_EXECUTION_TIME +CFLAGS += -DENABLE_FXP -DENABLE_USE_CPU_EXECUTION_TIME ifndef DISABLE_XER_PRINT CFLAGS += -DXER_PRINT endif diff --git a/targets/SIMU/USER/channel_sim.c b/targets/SIMU/USER/channel_sim.c index 91fc1cd059..b31c47ba95 100644 --- a/targets/SIMU/USER/channel_sim.c +++ b/targets/SIMU/USER/channel_sim.c @@ -403,9 +403,6 @@ void do_UL_sig(channel_desc_t *UE2RU[NUMBER_OF_UE_MAX][NUMBER_OF_RU_MAX][MAX_NUM { int32_t **txdata,**rxdata; -#ifdef PHY_ABSTRACTION_UL - int32_t att_eNB_id=-1; -#endif uint8_t UE_id=0; uint8_t nb_antennas_rx = UE2RU[0][0][CC_id]->nb_rx; // number of rx antennas at eNB @@ -418,14 +415,6 @@ void do_UL_sig(channel_desc_t *UE2RU[NUMBER_OF_UE_MAX][NUMBER_OF_RU_MAX][MAX_NUM uint8_t hold_channel=0; -#ifdef PHY_ABSTRACTION_UL - double min_path_loss=-200; - uint16_t ul_nb_rb=0 ; - uint16_t ul_fr_rb=0; - int ulnbrb2 ; - int ulfrrb2 ; - uint8_t harq_pid; -#endif double s_re0[30720]; double s_re1[30720]; double *s_re[2]; @@ -450,38 +439,6 @@ void do_UL_sig(channel_desc_t *UE2RU[NUMBER_OF_UE_MAX][NUMBER_OF_RU_MAX][MAX_NUM r_im0[1] = r_im01; if (abstraction_flag!=0) { -#ifdef PHY_ABSTRACTION_UL - // wire this to 0 until we figure this out - int eNB_id=0; - - for (UE_id=0; UE_idN_RB_UL,frame_parms->N_RB_UL*12+1); - - // REceived power at the eNB - rx_pwr = signal_energy_fp2(UE2RU[UE_id][eNB_id][CC_id]->ch[0], - UE2RU[UE_id][eNB_id][CC_id]->channel_length)*UE2RU[UE_id][att_eNB_id][CC_id]->channel_length; // calculate the rx power at the eNB - } - - // write_output("SINRch.m","SINRch",PHY_vars_eNB_g[att_eNB_id]->sinr_dB_eNB,frame_parms->N_RB_UL*12+1,1,1); - if(subframe>1 && subframe <5) { - harq_pid = subframe2harq_pid(frame_parms,frame,subframe); - ul_nb_rb = RC.eNB[att_eNB_id][CC_id].ulsch_eNB[(uint8_t)UE_id]->harq_processes[harq_pid]->nb_rb; - ul_fr_rb = RC.eNB[att_eNB_id][CC_id].ulsch_eNB[(uint8_t)UE_id]->harq_processes[harq_pid]->first_rb; - } - - if(ul_nb_rb>1 && (ul_fr_rb < 25 && ul_fr_rb > -1)) { - number_rb_ul = ul_nb_rb; - first_rbUL = ul_fr_rb; - init_snr_up(UE2RU[UE_id][att_eNB_id][CC_id],enb_data[att_eNB_id], ue_data[UE_id],PHY_vars_eNB_g[att_eNB_id][CC_id]->sinr_dB,&PHY_vars_UE_g[att_eNB_id][CC_id]->N0,ul_nb_rb,ul_fr_rb); - - } - } //UE_id - -#else - -#endif } else { //without abstraction pthread_mutex_lock(&UE_output_mutex[ru_id]); diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index 852b764ed7..ae139b797f 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -1358,9 +1358,6 @@ void init_ocm(void) if (abstraction_flag) { get_beta_map(); -#ifdef PHY_ABSTRACTION_UL - get_beta_map_up(); -#endif get_MIESM_param(); //load_pbch_desc(); @@ -1566,117 +1563,6 @@ void update_ocm() void update_otg_eNB(module_id_t enb_module_idP, unsigned int ctime) { -#if defined(OAI_EMU) - - //int rrc_state=0; - - if (oai_emulation.info.otg_enabled ==1 ) { - - int dst_id, app_id; - Packet_otg_elt_t *otg_pkt; - - for (dst_id = 0; dst_id < NUMBER_OF_UE_MAX; dst_id++) { - for_times += 1; - - // generate traffic if the ue is rrc reconfigured state - //if ((rrc_state=mac_eNB_get_rrc_status(enb_module_idP, dst_id)) > 2 /*RRC_CONNECTED*/ ) { - if (mac_eNB_get_rrc_status(enb_module_idP, oai_emulation.info.eNB_ue_module_id_to_rnti[enb_module_idP][dst_id]) > 2 ){ - if_times += 1; - - for (app_id=0; app_idotg_pkt).sdu_buffer = (uint8_t*) packet_gen(enb_module_idP, dst_id + NB_eNB_INST, app_id, ctime, &((otg_pkt->otg_pkt).sdu_buffer_size)); - - if ((otg_pkt->otg_pkt).sdu_buffer != NULL) { - otg_times += 1; - (otg_pkt->otg_pkt).rb_id = DTCH-2; // app could be binded to a given DRB - (otg_pkt->otg_pkt).module_id = enb_module_idP; - (otg_pkt->otg_pkt).dst_id = dst_id; - (otg_pkt->otg_pkt).is_ue = 0; - (otg_pkt->otg_pkt).mode = PDCP_TRANSMISSION_MODE_DATA; - //Adding the packet to the OTG-PDCP buffer - pkt_list_add_tail_eurecom(otg_pkt, &(otg_pdcp_buffer[enb_module_idP])); - LOG_D(EMU,"[eNB %d] ADD pkt to OTG buffer with size %d for dst %d on rb_id %d for app id %d \n", - (otg_pkt->otg_pkt).module_id, otg_pkt->otg_pkt.sdu_buffer_size, (otg_pkt->otg_pkt).dst_id,(otg_pkt->otg_pkt).rb_id, app_id); - } else { - free(otg_pkt); - otg_pkt=NULL; - } - } - } - } - -#if defined(Rel10) || defined(Rel14) - mbms_service_id_t service_id; - mbms_session_id_t session_id; - rb_id_t rb_id; - - // MBSM multicast traffic - if (ctime >= 500 ) {// only generate when UE can receive MTCH (need to control this value) - for (service_id = 0; service_id < 2 ; service_id++) { //maxServiceCount - for (session_id = 0; session_id < 2; session_id++) { // maxSessionPerPMCH - if (pdcp_mbms_array_eNB[enb_module_idP][service_id][session_id].instanciated_instance == TRUE) { // this service/session is configured - - otg_pkt = malloc (sizeof(Packet_otg_elt_t)); - // LOG_T(OTG,"multicast packet gen for (service/mch %d, session/lcid %d, rb_id %d)\n", service_id, session_id, service_id*maxSessionPerPMCH + session_id); - rb_id = pdcp_mbms_array_eNB[enb_module_idP][service_id][session_id].rb_id; - (otg_pkt->otg_pkt).sdu_buffer = (uint8_t*) packet_gen_multicast(enb_module_idP, session_id, ctime, &((otg_pkt->otg_pkt).sdu_buffer_size)); - - if ((otg_pkt->otg_pkt).sdu_buffer != NULL) { - (otg_pkt->otg_pkt).rb_id = rb_id; - (otg_pkt->otg_pkt).module_id = enb_module_idP; - (otg_pkt->otg_pkt).dst_id = session_id; - (otg_pkt->otg_pkt).is_ue = FALSE; - //Adding the packet to the OTG-PDCP buffer - (otg_pkt->otg_pkt).mode = PDCP_TRANSMISSION_MODE_TRANSPARENT; - pkt_list_add_tail_eurecom(otg_pkt, &(otg_pdcp_buffer[enb_module_idP])); - LOG_D(EMU, "[eNB %d] ADD packet (%p) multicast to OTG buffer for dst %d on rb_id %d\n", - (otg_pkt->otg_pkt).module_id, otg_pkt, (otg_pkt->otg_pkt).dst_id,(otg_pkt->otg_pkt).rb_id); - } else { - //LOG_I(EMU, "OTG returns null \n"); - free(otg_pkt); - otg_pkt=NULL; - } - - - // old version - /* // MBSM multicast traffic - #if defined(Rel10) || defined(Rel14) - if (frame >= 46) {// only generate when UE can receive MTCH (need to control this value) - for (service_id = 0; service_id < 2 ; service_id++) { //maxServiceCount - for (session_id = 0; session_id < 2; session_id++) { // maxSessionPerPMCH - // LOG_I(OTG,"DUY:frame %d, pdcp_mbms_array[module_id][rb_id].instanciated_instance is %d\n",frame,pdcp_mbms_array[module_id][service_id*maxSessionPerPMCH + session_id].instanciated_instance); - if ((pdcp_mbms_array[module_idP][service_id*maxSessionPerPMCH + session_id].instanciated_instance== module_idP + 1) && (eNB_flag == 1)){ // this service/session is configured - // LOG_T(OTG,"multicast packet gen for (service/mch %d, session/lcid %d)\n", service_id, session_id); - // Duy add - LOG_I(OTG, "frame %d, multicast packet gen for (service/mch %d, session/lcid %d, rb_id %d)\n",frame, service_id, session_id,service_id*maxSessionPerPMCH + session_id); - // end Duy add - rb_id = pdcp_mbms_array[module_id][service_id*maxSessionPerPMCH + session_id].rb_id; - otg_pkt=(uint8_t*) packet_gen_multicast(module_idP, session_id, ctime, &pkt_size); - if (otg_pkt != NULL) { - LOG_D(OTG,"[eNB %d] sending a multicast packet from module %d on rab id %d (src %d, dst %d) pkt size %d\n", eNB_index, module_idP, rb_id, module_idP, session_id, pkt_size); - pdcp_data_req(module_id, frame, eNB_flag, rb_id, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, pkt_size, otg_pkt,PDCP_TM); - free(otg_pkt); - } - } - } - } - } // end multicast traffic - #endif - */ - - - } - } - } - - } // end multicast traffic - -#endif - } - -#else #if 0 // defined(EXMIMO) || defined(OAI_USRP) if (otg_enabled==1) { ctime = frame * 100; @@ -1703,57 +1589,11 @@ void update_otg_eNB(module_id_t enb_module_idP, unsigned int ctime) } } } - -#endif #endif } void update_otg_UE(module_id_t ue_mod_idP, unsigned int ctime) { -#if defined(OAI_EMU) - - int app_id; - if (oai_emulation.info.otg_enabled ==1 ) { - module_id_t dst_id, src_id; //dst_id = eNB_index - module_id_t module_id = ue_mod_idP+NB_eNB_INST; - - src_id = module_id; - - for (dst_id=0; dst_id 2 /*RRC_CONNECTED*/) { - for (app_id=0; app_idotg_pkt).sdu_buffer = (uint8_t*) packet_gen(src_id, dst_id, app_id, ctime, &((otg_pkt->otg_pkt).sdu_buffer_size)); - - if ((otg_pkt->otg_pkt).sdu_buffer != NULL) { - (otg_pkt->otg_pkt).rb_id = DTCH-2; - (otg_pkt->otg_pkt).module_id = module_id; - (otg_pkt->otg_pkt).dst_id = dst_id; - (otg_pkt->otg_pkt).is_ue = 1; - //Adding the packet to the OTG-PDCP buffer - (otg_pkt->otg_pkt).mode = PDCP_TRANSMISSION_MODE_DATA; - pkt_list_add_tail_eurecom(otg_pkt, &(otg_pdcp_buffer[module_id])); - LOG_D(EMU, "[UE %d] ADD pkt to OTG buffer with size %d for dst %d on rb_id %d \n", - (otg_pkt->otg_pkt).module_id, otg_pkt->otg_pkt.sdu_buffer_size, (otg_pkt->otg_pkt).dst_id,(otg_pkt->otg_pkt).rb_id); - } else { - free(otg_pkt); - otg_pkt=NULL; - } - } - } - } - } - -#endif } #endif diff --git a/targets/SIMU/USER/sinr_sim.c b/targets/SIMU/USER/sinr_sim.c index 522f4147ce..7c752ce432 100644 --- a/targets/SIMU/USER/sinr_sim.c +++ b/targets/SIMU/USER/sinr_sim.c @@ -475,70 +475,6 @@ void init_snr(channel_desc_t* eNB2UE, node_desc_t *enb_data, node_desc_t *ue_dat }//switch }//function ends -#ifdef PHY_ABSTRACTION_UL -void init_snr_up(channel_desc_t* UE2eNB, node_desc_t *enb_data, node_desc_t *ue_data, double* sinr_dB, double* N0,uint16_t nb_rb,uint16_t fr_rb) -{ - - int return_value; - double thermal_noise; - int count; - int aarx; - - // nb_rb = phy_vars_eNB->ulsch_eNB[UE_id]->harq_processes[harq_pid]->nb_rb; - /* Thermal noise is calculated using 10log10(K*T*B) K = Boltzmann's constant T = room temperature B = bandwidth */ - thermal_noise = -174 + 10*log10(UE2eNB->sampling_rate*1e6); //value in dBm - *N0 = thermal_noise + enb_data->rx_noise_level;//? all the element have the same noise level????? - double lambda ; - double residual; - double sinrlin; - double residual_db; - residual = 0 ; - int ccc; - /* - for (count = (fr_rb*12) ; count < (12 * (fr_rb+nb_rb)); count++) - { - residual += ( 1 / ( pow((UE2eNB -> chF[0][count].x),2) + pow((UE2eNB -> chF[0][count].y),2))); - } - *///sinreff(nn) = ((sum((1/p).*(snrm(nn,:)./(snrm(nn,:)+1)),2).^(-1) )-1).^-1; - - sinrlin = 0 ; - lambda = 0; - - ////First calculate SINRs of subcarriers just like OFDM - for (count = (fr_rb*12) ; count < (12 * (fr_rb+nb_rb)); count++) { - sinr_dB[count] = ue_data->tx_power_dBm - + UE2eNB->path_loss_dB - - (thermal_noise + enb_data->rx_noise_level) - + 10 * log10 (pow(UE2eNB->chF[0][count].x, 2) - + pow(UE2eNB->chF[0][count].y, 2)); - - - } - - //Then apply formula : - if(nb_rb > 0) { - //calculate lambdas and fill the same with all but just use one of them when necessary for abstraction - for (count = fr_rb*12; count < (12 * (fr_rb+nb_rb)); count++) { - sinrlin = pow((sinr_dB[count]/10),10); // convert SINR to linear - lambda += (sinrlin / (sinrlin + 1)) ; - } - - for (count = fr_rb*12; count < (12 * (fr_rb+nb_rb)); count++) { - sinr_dB[count] = pow(lambda,2) /(((nb_rb)*lambda)-pow(lambda,2)) ; - sinr_dB[count] = 10*log10(sinr_dB[count]) ; //save it in db - } - - printf("tx_power %g, path_loss %g, sinr_dB[0] %g\n",ue_data->tx_power_dBm ,UE2eNB->path_loss_dB,sinr_dB[count-1]); - - for (ccc = 0; ccc < 301 ; ccc++ ) { - SINRpost_eff[ccc] = 0; - SINRpost_eff[ccc] = sinr_dB[ccc]; - } - } -}//function ends - -#endif - void calculate_sinr(channel_desc_t* eNB2UE, node_desc_t *enb_data, node_desc_t *ue_data, double *sinr_dB, uint16_t nb_rb) { @@ -737,60 +673,7 @@ void get_MIESM_param() free(file_path); } -#ifdef PHY_ABSTRACTION_UL -void get_beta_map_up() -{ - char *file_path = NULL; - int table_len = 0; - int mcs = 0; - char *sinr_bler; - char buffer[1000]; - FILE *fp; - file_path = (char*) malloc(512); - - for (mcs = 0; mcs < MCS_COUNT; mcs++) { - sprintf(file_path,"%s/SIMULATION/LTE_PHY/BLER_SIMULATIONS/AWGN/awgn_abst/awgn_snr_bler_mcs%d_up.csv",getenv("OPENAIR1_DIR"),mcs); - fp = fopen(file_path,"r"); - - if (fp == NULL) { - LOG_W(OCM,"ERROR: Unable to open the file %s, try an alternative path\n", file_path); - memset(file_path, 0, 512); - sprintf(file_path,"AWGN/awgn_snr_bler_mcs%d.csv",mcs); - LOG_I(OCM,"Opening the alternative path %s\n", file_path); - fp = fopen(file_path,"r"); - - if (fp == NULL) { - LOG_E(OCM,"ERROR: Unable to open the file %s, exisitng\n", file_path); - exit(-1); - } - } - - // else { - fgets(buffer, 1000, fp); - table_len=0; - - while (!feof(fp)) { - sinr_bler = strtok(buffer, ","); - sinr_bler_map_up[mcs][0][table_len] = atof(sinr_bler); - sinr_bler = strtok(NULL,","); - sinr_bler_map_up[mcs][1][table_len] = atof(sinr_bler); - table_len++; - fgets(buffer, 1000, fp); - } - - fclose(fp); - // } - LOG_D(OCM,"Print the table for mcs %d\n",mcs); - - for (table_len = 0; table_len < 16; table_len++) - LOG_D(OCM,"%lf %lf \n ",sinr_bler_map_up[mcs][0][table_len],sinr_bler_map_up[mcs][1][table_len]); - } - - free(file_path); -} - -#endif diff --git a/targets/TEST/AT_COMMANDS/Makefile b/targets/TEST/AT_COMMANDS/Makefile index 41d079bbcb..3f52e2af60 100755 --- a/targets/TEST/AT_COMMANDS/Makefile +++ b/targets/TEST/AT_COMMANDS/Makefile @@ -23,8 +23,6 @@ ifdef PDCP_USE_NETLINK CFLAGS += -DPDCP_USE_NETLINK -DLINUX -DDEBUG_CONTROL endif -CFLAGS += -DPHY_ABSTRACTION #-DEMIT_ASN_DEBUG=1 - #include $(OPENAIR1_DIR)/PHY/Makefile.inc #include $(OPENAIR1_DIR)/SCHED/Makefile.inc diff --git a/targets/TEST/PACKET_TRACER/Makefile b/targets/TEST/PACKET_TRACER/Makefile index 93e67bc9e2..4d01cd6a69 100755 --- a/targets/TEST/PACKET_TRACER/Makefile +++ b/targets/TEST/PACKET_TRACER/Makefile @@ -11,16 +11,12 @@ CFLAGS += -m32 -DPHYSIM -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES CFLAGS += -DOPENAIR_LTE -DPUCCH #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE -CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 -DPHY_ABSTRACTION -DOAI_EMU +CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 CFLAGS += -DEMIT_ASN_DEBUG=1 ifndef OPENAIR2 OPENAIR2=1 endif -ifndef OPENAIR_EMU -export OPENAIR_EMU=1 -endif - # activate OCG and libxml only under linux ifeq ($(linux),1) CFLAGS += -I/usr/include/libxml2 -L/usr/local/lib -I/usr/include/atlas -L/usr/X11R6/lib @@ -61,8 +57,6 @@ ifdef TRAFFIC_TM5 CFLAGS += -DRLC_UM_TEST_TRAFFIC=1 -DFULL_BUFFER=1 endif -CFLAGS += -DOAI_EMU - include $(OPENAIR1_DIR)/PHY/Makefile.inc include $(OPENAIR1_DIR)/SCHED/Makefile.inc include $(OPENAIR2_DIR)/LAYER2/Makefile.inc diff --git a/targets/TEST/PDCP/Makefile b/targets/TEST/PDCP/Makefile index 12193cbb99..7b9e20ce64 100755 --- a/targets/TEST/PDCP/Makefile +++ b/targets/TEST/PDCP/Makefile @@ -25,8 +25,6 @@ ifdef PDCP_USE_NETLINK CFLAGS += -DPDCP_USE_NETLINK -DLINUX -DDEBUG_CONTROL endif -CFLAGS += -DPHY_ABSTRACTION #-DEMIT_ASN_DEBUG=1 - #include $(OPENAIR1_DIR)/PHY/Makefile.inc #include $(OPENAIR1_DIR)/SCHED/Makefile.inc diff --git a/targets/TEST/PDCP/with_rlc/Makefile.data_bearer b/targets/TEST/PDCP/with_rlc/Makefile.data_bearer index 495dcda572..3f7d841d6a 100755 --- a/targets/TEST/PDCP/with_rlc/Makefile.data_bearer +++ b/targets/TEST/PDCP/with_rlc/Makefile.data_bearer @@ -25,8 +25,6 @@ ifdef PDCP_USE_NETLINK CFLAGS += -DPDCP_USE_NETLINK -DLINUX -DDEBUG_CONTROL endif -CFLAGS += -DPHY_ABSTRACTION #-DEMIT_ASN_DEBUG=1 - #include $(OPENAIR1_DIR)/PHY/Makefile.inc #include $(OPENAIR1_DIR)/SCHED/Makefile.inc diff --git a/targets/TEST/RLC_AM_V9.3.0/Makefile b/targets/TEST/RLC_AM_V9.3.0/Makefile index 68f520b31d..d29697ea6a 100755 --- a/targets/TEST/RLC_AM_V9.3.0/Makefile +++ b/targets/TEST/RLC_AM_V9.3.0/Makefile @@ -13,7 +13,7 @@ CFLAGS += -m32 -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES CFLAGS += -DOPENAIR_LTE -DPUCCH #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE -CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 -DPHY_ABSTRACTION #-DPHY_ABSTRACTION_UL #-DRLC_UM_TEST_TRAFFIC=1 +CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 #-DRLC_UM_TEST_TRAFFIC=1 CFLAGS += -DNEW_FFT #CFLAGS += -DLLR8 @@ -21,14 +21,6 @@ ifndef OPENAIR2 OPENAIR2=1 endif -ifndef OPENAIR_EMU -export OPENAIR_EMU=1 -endif - -ifdef EMOS -CFLAGS+=-DEMOS -endif - ifdef TRAFFIC_TM5 CFLAGS += -DRLC_UM_TEST_TRAFFIC=1 #-DFULL_BUFFER=1 endif @@ -114,7 +106,7 @@ endif CFLAGS += $(shell if [ `uname -o` = "Cygwin" ] ; then echo "-DCYGWIN" ;fi) -CFLAGS += -DENABLE_FXP -DOAI_EMU -DENABLE_USE_CPU_EXECUTION_TIME +CFLAGS += -DENABLE_FXP -DENABLE_USE_CPU_EXECUTION_TIME ifneq ($(USE_MME), R8) UPDATE_RELEASE_9=1 diff --git a/targets/TEST/RLC_UM_V9.3.0/Makefile b/targets/TEST/RLC_UM_V9.3.0/Makefile index 91ad44e08b..aa88a73c33 100755 --- a/targets/TEST/RLC_UM_V9.3.0/Makefile +++ b/targets/TEST/RLC_UM_V9.3.0/Makefile @@ -13,7 +13,7 @@ CFLAGS += -m32 -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES CFLAGS += -DOPENAIR_LTE -DPUCCH #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE -CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 -DPHY_ABSTRACTION #-DPHY_ABSTRACTION_UL #-DRLC_UM_TEST_TRAFFIC=1 +CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 #-DRLC_UM_TEST_TRAFFIC=1 CFLAGS += -DNEW_FFT #CFLAGS += -DLLR8 @@ -21,14 +21,6 @@ ifndef OPENAIR2 OPENAIR2=1 endif -ifndef OPENAIR_EMU -export OPENAIR_EMU=1 -endif - -ifdef EMOS -CFLAGS+=-DEMOS -endif - ifdef TRAFFIC_TM5 CFLAGS += -DRLC_UM_TEST_TRAFFIC=1 #-DFULL_BUFFER=1 endif @@ -109,7 +101,7 @@ ifdef OAI_NW_DRIVER_TYPE_ETHERNET CFLAGS+=-DOAI_NW_DRIVER_TYPE_ETHERNET endif -CFLAGS += -DENABLE_FXP -DOAI_EMU -DENABLE_USE_CPU_EXECUTION_TIME +CFLAGS += -DENABLE_FXP -DENABLE_USE_CPU_EXECUTION_TIME ifneq ($(USE_MME), R8) UPDATE_RELEASE_9=1 From d62fe071cb299f9dfe9fca80d0410b7379a3c817 Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 10:15:35 +0100 Subject: [PATCH 142/284] Fix #582, ENABLE_PGM_TRANSPORT removed, RRH related removed --- cmake_targets/CMakeLists.txt | 30 +- cmake_targets/build_oai | 55 +- cmake_targets/epc_test/CMakeLists.template | 2 - .../oaisim_build_oai/CMakeLists.template | 2 - .../oaisim_mme_build_oai/CMakeLists.template | 2 - .../oaisim_noS1_build_oai/CMakeLists.template | 2 - .../s1c_mme_test/CMakeLists.template | 2 - .../ETH_TRANSPORT/bypass_session_layer.c | 69 - openair1/SIMULATION/ETH_TRANSPORT/defs.h | 6 - .../SIMULATION/ETH_TRANSPORT/emu_transport.c | 37 - .../SIMULATION/ETH_TRANSPORT/multicast_link.c | 2 - openair1/SIMULATION/ETH_TRANSPORT/pgm_link.c | 417 ------ openair1/SIMULATION/ETH_TRANSPORT/pgm_link.h | 38 - targets/RT/USER/UE_transport_IQ.c | 548 -------- targets/RT/USER/eNB_transport_IQ.c | 744 ---------- targets/RT/USER/rrh.c | 1220 ----------------- targets/RT/USER/rrh.gtkw | 195 --- targets/RT/USER/rrh_gw.c | 460 ------- targets/RT/USER/rrh_gw.h | 104 -- targets/RT/USER/rrh_gw_externs.h | 48 - targets/SIMU/USER/Makefile | 2 +- 21 files changed, 5 insertions(+), 3980 deletions(-) delete mode 100644 openair1/SIMULATION/ETH_TRANSPORT/pgm_link.c delete mode 100644 openair1/SIMULATION/ETH_TRANSPORT/pgm_link.h delete mode 100644 targets/RT/USER/UE_transport_IQ.c delete mode 100644 targets/RT/USER/eNB_transport_IQ.c delete mode 100644 targets/RT/USER/rrh.c delete mode 100644 targets/RT/USER/rrh.gtkw delete mode 100644 targets/RT/USER/rrh_gw.c delete mode 100644 targets/RT/USER/rrh_gw.h delete mode 100644 targets/RT/USER/rrh_gw_externs.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 8737df7ea0..7d1b8bb1be 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -608,12 +608,6 @@ add_boolean_option(FLEXRAN_AGENT_SB_IF False "enable FlexRAN ########################## add_boolean_option(ENB_MODE True "Swap the include directories between openair2 and openair3" ) -########################## -# Emulation options -########################## -add_boolean_option(ENABLE_PGM_TRANSPORT False "specific to oaisim, emulation through ethernet, reliable multicast") -add_boolean_option(ADDR_CONF False "specific to oaisim, IP autoconf of user-plane IP interface") - ########################## # SCHEDULING/REAL-TIME/PERF options ########################## @@ -1595,7 +1589,6 @@ ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/multicast_link.c ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/socket.c ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/bypass_session_layer.c #${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/emu_transport.c -${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/pgm_link.c ) add_library(OPENAIR0_LIB @@ -1812,27 +1805,6 @@ target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt target_link_libraries (lte-softmodem-nos1 ${LIB_LMS_LIBRARIES}) target_link_libraries (lte-softmodem-nos1 ${T_LIB}) -# rrh -################################ -#Note: only one RF type (USRP) is currently supported for RRH -add_executable(rrh_gw - ${OPENAIR_TARGETS}/RT/USER/rrh_gw.c - ${OPENAIR_TARGETS}/RT/USER/eNB_transport_IQ.c - ${OPENAIR_TARGETS}/RT/USER/UE_transport_IQ.c - ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c - ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c - ${T_SOURCE} - ) -target_include_directories(rrh_gw PRIVATE ${OPENAIR_DIR}/common/utils/itti) -target_link_libraries(rrh_gw - -Wl,--start-group - UTIL LFDS -ldl - -Wl,--end-group ) -target_link_libraries (rrh_gw rt pthread m ) -target_link_libraries (rrh_gw ${LIB_LMS_LIBRARIES}) -target_link_libraries (rrh_gw ${T_LIB}) - - # USIM process ################# #add_executable(usim @@ -2047,7 +2019,7 @@ endforeach(myExe) if (${T_TRACER}) foreach(i #all "add_executable" definitions (except tests, rb_tool, updatefw) - lte-softmodem lte-softmodem-nos1 rrh_gw oaisim oaisim_nos1 + lte-softmodem lte-softmodem-nos1 oaisim oaisim_nos1 dlsim_tm4 dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim syncsim #all "add_library" definitions diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index d625dfa159..2ac0975a81 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -100,8 +100,6 @@ Options Specify conf_nvram_path (default \"$conf_nvram_path\") --UE-gen-nvram [output path] Specify gen_nvram_path (default \"$gen_nvram_path\") ---RRH - Makes the RRH -a | --agent Enables agent for software-defined control of the eNB -r | --3gpp-release @@ -219,10 +217,6 @@ function main() { --UE-gen-nvram) gen_nvram_path=$(readlink -f $2) shift 2;; - --RRH) - RRH=1 - echo_info "Will compile RRH" - shift;; -r | --3gpp-release) REL=$2 echo_info "Setting release to: $REL" @@ -371,7 +365,7 @@ function main() { echo_info "CMAKE_CMD=$CMAKE_CMD" ######################################################### - # check validity of HW and TP parameters for RRH and eNB + # check validity of HW and TP parameters for eNB ######################################################### # to be discussed @@ -387,15 +381,6 @@ function main() { fi fi - if [ "$RRH" = "1" ] ; then - if [ "$TP" = "None" ] ; then - echo_fatal "A transport protocol (e.g. -t ETHERNET) must be defined!" - fi - if [ "$HW" = "None" ] ; then - echo_info "No radio head has been selected (HW set to $HW)" - fi - fi - echo_info "RF HW set to $HW" #Now we set flags to enable deadline scheduler settings #By default: USRP: disable, @@ -793,36 +778,6 @@ function main() { # oaisim_mme $dbin/oaisim_mme.$REL fi - # RRH compilation - ##################### - if [ "$RRH" = "1" ] ; then - - rrh_exec=rrh_gw - rrh_build_dir=rrh_gw - - echo_info "Compiling $rrh_exec ..." - - [ "$CLEAN" = "1" ] && rm -rf $DIR/rrh_gw/build - mkdir -p $DIR/$rrh_build_dir/build - cmake_file=$DIR/$rrh_build_dir/CMakeLists.txt - echo "cmake_minimum_required(VERSION 2.8)" > $cmake_file - echo "set ( CMAKE_BUILD_TYPE $CMAKE_BUILD_TYPE )" >> $cmake_file - echo "set ( ENABLE_VCD_FIFO $VCD_TIMING )" >> $cmake_file - echo "set ( ENABLE_ITTI False )" >> $cmake_file - echo "set ( RF_BOARD \"${HW}\")" >> $cmake_file - echo "set ( TRANSP_PRO \"${TP}\")" >> $cmake_file - echo 'set ( PACKAGE_NAME "\"rrh_gw\"")' >> $cmake_file - echo "set ( DEADLINE_SCHEDULER \"${DEADLINE_SCHEDULER_FLAG_USER}\" )" >>$cmake_file - echo "set ( CPU_AFFINITY \"${CPU_AFFINITY_FLAG_USER}\" )" >>$cmake_file - echo "set ( T_TRACER $T_TRACER )" >> $cmake_file - echo 'include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)' >> $cmake_file - cd $DIR/$rrh_build_dir/build - eval $CMAKE_CMD - compilations \ - rrh_gw rrh_gw \ - rrh_gw $dbin/rrh_gw - - fi # Telnet server compilation ##################### if [ "$BUILD_TELNETSRV" = "1" ] ; then @@ -841,13 +796,9 @@ function main() { fi # build RF device and transport protocol libraries ##################################### - if [ "$eNB" = "1" -o "$UE" = "1" -o "$RRH" = "1" ] ; then + if [ "$eNB" = "1" -o "$UE" = "1" ] ; then - if [ "$eNB" = "1" -o "$UE" = "1" ] ; then - build_dir=$lte_build_dir - else - build_dir=$rrh_build_dir - fi + build_dir=$lte_build_dir # build RF device libraries if [ "$HW" != "None" ] ; then diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index 6209cc9f0e..302ae7bcf3 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 2.8) set ( CMAKE_BUILD_TYPE "RelWithDebInfo" ) set ( ASN_DEBUG False) -set ( ADDR_CONF False ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 True ) @@ -11,7 +10,6 @@ set ( ENABLE_FXP True ) set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING True ) set ( ENABLE_NEW_MULTICAST True ) -set ( ENABLE_PGM_TRANSPORT True ) set ( ENABLE_SECURITY True ) set ( ENABLE_STANDALONE_EPC False) set ( ENABLE_USE_CPU_EXECUTION_TIME True ) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index 3d88fb39ae..951b69b783 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -1,7 +1,6 @@ cmake_minimum_required(VERSION 2.8) set ( CMAKE_BUILD_TYPE "RelWithDebInfo" ) -set ( ADDR_CONF False ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 True ) @@ -9,7 +8,6 @@ set ( ENABLE_FXP True ) set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING True ) set ( ENABLE_NEW_MULTICAST True ) -set ( ENABLE_PGM_TRANSPORT True ) set ( ENABLE_RAL False ) set ( ENABLE_SECURITY True ) set ( ENABLE_STANDALONE_EPC False) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index 528e09556d..c1ed73bdd8 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -1,7 +1,6 @@ cmake_minimum_required(VERSION 2.8) set ( CMAKE_BUILD_TYPE "RelWithDebInfo" ) -set ( ADDR_CONF False ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 False ) @@ -9,7 +8,6 @@ set ( ENABLE_FXP False ) set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING False ) set ( ENABLE_NEW_MULTICAST False ) -set ( ENABLE_PGM_TRANSPORT False ) set ( ENABLE_RAL False ) set ( ENABLE_SECURITY False ) set ( ENABLE_STANDALONE_EPC False ) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 09c389fbcc..68e5ee0e0a 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -1,6 +1,5 @@ cmake_minimum_required(VERSION 2.8) -set ( ADDR_CONF False ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 True ) @@ -8,7 +7,6 @@ set ( ENABLE_FXP True ) set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING False ) set ( ENABLE_NEW_MULTICAST True ) -set ( ENABLE_PGM_TRANSPORT True ) set ( ENABLE_RAL False ) set ( ENABLE_SECURITY False ) set ( ENABLE_STANDALONE_EPC False) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index 0d8ec5e67a..c293e176c2 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -1,7 +1,6 @@ cmake_minimum_required(VERSION 2.8) set ( CMAKE_BUILD_TYPE "RelWithDebInfo" ) -set ( ADDR_CONF False ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 True ) @@ -10,7 +9,6 @@ set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING True ) set ( ENABLE_NEW_MULTICAST True ) set ( ENABLE_PDCP_NETLINK_FIFO False ) -set ( ENABLE_PGM_TRANSPORT True ) set ( ENABLE_RAL False ) set ( ENABLE_SECURITY True ) set ( ENABLE_STANDALONE_EPC False) diff --git a/openair1/SIMULATION/ETH_TRANSPORT/bypass_session_layer.c b/openair1/SIMULATION/ETH_TRANSPORT/bypass_session_layer.c index b3aefbb245..e96db24521 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/bypass_session_layer.c +++ b/openair1/SIMULATION/ETH_TRANSPORT/bypass_session_layer.c @@ -39,7 +39,6 @@ #include "UTIL/LOG/log.h" #include "multicast_link.h" -#include "pgm_link.h" char rx_bufferP[BYPASS_RX_BUFFER_SIZE]; unsigned int num_bytesP = 0; @@ -49,10 +48,6 @@ static unsigned int byte_tx_count; unsigned int Master_list_rx; static uint64_t seq_num_tx = 0; -#if defined(ENABLE_PGM_TRANSPORT) -extern unsigned int pgm_would_block; -#endif - mapping transport_names[] = { {"WAIT PM TRANSPORT INFO", EMU_TRANSPORT_INFO_WAIT_PM}, {"WAIT SM TRANSPORT INFO", EMU_TRANSPORT_INFO_WAIT_SM}, @@ -60,9 +55,6 @@ mapping transport_names[] = { {"ENB_TRANSPORT INFO", EMU_TRANSPORT_INFO_ENB}, {"UE TRANSPORT INFO", EMU_TRANSPORT_INFO_UE}, {"RELEASE TRANSPORT INFO", EMU_TRANSPORT_INFO_RELEASE}, -#if defined(ENABLE_PGM_TRANSPORT) - {"NACK TRANSPORT INFO", EMU_TRANSPORT_NACK}, -#endif {NULL, -1} }; @@ -77,9 +69,6 @@ void init_bypass (void) pthread_mutex_init (&emul_low_mutex, NULL); pthread_cond_init (&emul_low_cond, NULL); emul_low_mutex_var = 1; -#endif -#if defined(ENABLE_PGM_TRANSPORT) - pgm_oai_init(oai_emulation.info.multicast_ifname); #endif bypass_init (emul_tx_handler, emul_rx_handler); } @@ -318,20 +307,12 @@ int bypass_rx_data(unsigned int frame, unsigned int last_slot, frame, next_slot, is_master); #if defined(ENABLE_NEW_MULTICAST) -# if defined(ENABLE_PGM_TRANSPORT) - num_bytesP = pgm_recv_msg(oai_emulation.info.multicast_group, - (uint8_t *)&rx_bufferP[0], sizeof(rx_bufferP), - frame, next_slot); - - DevCheck(num_bytesP > 0, num_bytesP, 0, 0); -# else if (multicast_link_read_data_from_sock(is_master) == 1) { /* We got a timeout */ return -1; } -# endif #else pthread_mutex_lock(&emul_low_mutex); @@ -359,10 +340,6 @@ int bypass_rx_data(unsigned int frame, unsigned int last_slot, num_bytesP, map_int_to_str(transport_names, messg->Message_type), messg->master_id, messg->seq_num); -#if defined(ENABLE_PGM_TRANSPORT) - - if (messg->Message_type != EMU_TRANSPORT_NACK) -#endif DevCheck4((messg->frame == frame) && (messg->subframe == (next_slot>>1)), messg->frame, frame, messg->subframe, next_slot>>1); @@ -405,20 +382,6 @@ int bypass_rx_data(unsigned int frame, unsigned int last_slot, Master_list_rx = oai_emulation.info.master_list; LOG_E(EMU, "RX EMU_TRANSPORT_INFO_RELEASE\n"); break; -#if defined(ENABLE_PGM_TRANSPORT) - - case EMU_TRANSPORT_NACK: - if (messg->failing_master_id == oai_emulation.info.master_id) { - /* We simply re-send the last message */ - pgm_link_send_msg(oai_emulation.info.multicast_group, - (uint8_t *)bypass_tx_buffer, byte_tx_count); - } else { - /* Sleep awhile till other peers have recovered data */ - usleep(500); - } - - break; -#endif default: LOG_E(EMU, "[MAC][BYPASS] ERROR RX UNKNOWN MESSAGE\n"); @@ -483,13 +446,6 @@ void bypass_signal_mac_phy(unsigned int frame, unsigned int last_slot, } } -#if defined(ENABLE_PGM_TRANSPORT) -void bypass_tx_nack(unsigned int frame, unsigned int next_slot) -{ - bypass_tx_data(NACK_TRANSPORT, frame, next_slot); -} -#endif - /***************************************************************************/ void bypass_tx_data(emu_transport_info_t Type, unsigned int frame, unsigned int next_slot) { @@ -519,26 +475,6 @@ void bypass_tx_data(emu_transport_info_t Type, unsigned int frame, unsigned int byte_tx_count = sizeof (bypass_msg_header_t) + sizeof ( bypass_proto2multicast_header_t); -#if defined(ENABLE_PGM_TRANSPORT) - - if (Type == NACK_TRANSPORT) { - int i; - messg->Message_type = EMU_TRANSPORT_NACK; - - for (i = 0; i < oai_emulation.info.nb_master; i++) { - /* Skip our id */ - if (i == oai_emulation.info.master_id) - continue; - - if ((Master_list_rx & (1 << i)) == 0) { - messg->failing_master_id = i; - break; - } - } - - LOG_T(EMU,"[TX_DATA] NACK TRANSPORT\n"); - } else -#endif if (Type == WAIT_PM_TRANSPORT) { messg->Message_type = EMU_TRANSPORT_INFO_WAIT_PM; LOG_T(EMU,"[TX_DATA] WAIT SYNC PM TRANSPORT\n"); @@ -630,13 +566,8 @@ void bypass_tx_data(emu_transport_info_t Type, unsigned int frame, unsigned int ((bypass_proto2multicast_header_t *) bypass_tx_buffer)->size = byte_tx_count - sizeof (bypass_proto2multicast_header_t); -#if defined(ENABLE_PGM_TRANSPORT) - pgm_link_send_msg(oai_emulation.info.multicast_group, - (uint8_t *)bypass_tx_buffer, byte_tx_count); -#else multicast_link_write_sock(oai_emulation.info.multicast_group, bypass_tx_buffer, byte_tx_count); -#endif LOG_D(EMU, "Frame %d, subframe %d (%d): Sent %d bytes [%s] with master_id %d and seq %"PRIuMAX"\n", frame, next_slot>>1, next_slot,byte_tx_count, map_int_to_str(transport_names, Type), diff --git a/openair1/SIMULATION/ETH_TRANSPORT/defs.h b/openair1/SIMULATION/ETH_TRANSPORT/defs.h index 3b744aa859..5cd961b61a 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/defs.h +++ b/openair1/SIMULATION/ETH_TRANSPORT/defs.h @@ -41,9 +41,6 @@ typedef enum emu_transport_info_e { EMU_TRANSPORT_INFO_ENB, EMU_TRANSPORT_INFO_UE, EMU_TRANSPORT_INFO_RELEASE -#if defined(ENABLE_PGM_TRANSPORT) - ,EMU_TRANSPORT_NACK -#endif } emu_transport_info_t; #define WAIT_PM_TRANSPORT 1 @@ -52,9 +49,6 @@ typedef enum emu_transport_info_e { #define ENB_TRANSPORT 4 #define UE_TRANSPORT 5 #define RELEASE_TRANSPORT 6 -#if defined(ENABLE_PGM_TRANSPORT) -# define NACK_TRANSPORT 7 -#endif #define WAIT_SYNC_TRANSPORT 1 #define SYNCED_TRANSPORT 2 diff --git a/openair1/SIMULATION/ETH_TRANSPORT/emu_transport.c b/openair1/SIMULATION/ETH_TRANSPORT/emu_transport.c index 186201cd0b..f71a8ee117 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/emu_transport.c +++ b/openair1/SIMULATION/ETH_TRANSPORT/emu_transport.c @@ -40,49 +40,17 @@ #include "UTIL/LOG/log.h" #include "UTIL/LOG/vcd_signal_dumper.h" -#include "pgm_link.h" - extern unsigned int Master_list_rx; extern unsigned char NB_INST; //#define DEBUG_CONTROL 1 //#define DEBUG_EMU 1 -#if defined(ENABLE_PGM_TRANSPORT) -extern unsigned int pgm_would_block; -#endif - void emu_transport_sync(void) { LOG_D(EMU, "Entering EMU transport SYNC is primary master %d\n", oai_emulation.info.is_primary_master); -#if defined(ENABLE_PGM_TRANSPORT) - - if (oai_emulation.info.is_primary_master == 0) { - bypass_tx_data(WAIT_SM_TRANSPORT,0,0); - // just wait to recieve the master 0 msg - Master_list_rx = oai_emulation.info.master_list - 1; - bypass_rx_data(0,0,0,1); - } else { - bypass_rx_data(0,0,0,0); - bypass_tx_data(WAIT_PM_TRANSPORT,0,0); - } - - if (oai_emulation.info.master_list != 0) { - bypass_tx_data(SYNC_TRANSPORT,0,0); - bypass_rx_data(0,0,0,0); - - // i received the sync from all secondary masters - if (emu_rx_status == SYNCED_TRANSPORT) { - emu_tx_status = SYNCED_TRANSPORT; - } - - LOG_D(EMU,"TX secondary master SYNC_TRANSPORT state \n"); - } - -#else - if (oai_emulation.info.is_primary_master == 0) { retry: bypass_tx_data(WAIT_SM_TRANSPORT,0,0); @@ -115,8 +83,6 @@ retry2: LOG_D(EMU,"TX secondary master SYNC_TRANSPORT state \n"); } -#endif - LOG_D(EMU, "Leaving EMU transport SYNC is primary master %d\n", oai_emulation.info.is_primary_master); } @@ -154,9 +120,6 @@ void emu_transport(unsigned int frame, unsigned int last_slot, } } -#if defined(ENABLE_PGM_TRANSPORT) - pgm_would_block = 0; -#endif VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_EMU_TRANSPORT, VCD_FUNCTION_OUT); } diff --git a/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.c b/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.c index 8750be7096..1ba724976f 100644 --- a/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.c +++ b/openair1/SIMULATION/ETH_TRANSPORT/multicast_link.c @@ -314,9 +314,7 @@ void multicast_link_start(void (*rx_handlerP) (unsigned int, char *), LOG_I(EMU, "[MULTICAST] LINK START on interface=%s for group=%d: handler=%p\n", (multicast_if == NULL) ? "not specified" : multicast_if, multicast_group, rx_handler); -#if !defined(ENABLE_PGM_TRANSPORT) multicast_link_init (); -#endif #if ! defined(ENABLE_NEW_MULTICAST) LOG_D(EMU, "[MULTICAST] multicast link start thread\n"); diff --git a/openair1/SIMULATION/ETH_TRANSPORT/pgm_link.c b/openair1/SIMULATION/ETH_TRANSPORT/pgm_link.c deleted file mode 100644 index 61bf940660..0000000000 --- a/openair1/SIMULATION/ETH_TRANSPORT/pgm_link.c +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file pgm_link.c - * \brief implementation a warpper for openpgm for reliable multicast transmission - * \author Navid Nikaein and S. Roux - * \date 2013 - 2014 - * \version 1.0 - * \company Eurecom - * \email: navid.nikaein@eurecom.fr - */ - -#include -#include -#include -#include -#include - -#include - -#if defined(ENABLE_PGM_TRANSPORT) - -#include - -#include "assertions.h" - -#include "pgm_link.h" -#include "multicast_link.h" - -#include "UTIL/OCG/OCG.h" -#include "UTIL/OCG/OCG_extern.h" - -#include "UTIL/LOG/log.h" - -// #define ENABLE_PGM_DEBUG - -typedef struct { - pgm_sock_t *sock; - uint16_t port; - uint8_t rx_buffer[40000]; -} pgm_multicast_group_t; - -pgm_multicast_group_t pgm_multicast_group[MULTICAST_LINK_NUM_GROUPS]; - -static -int pgm_create_socket(int index, const char *if_addr); - -unsigned int pgm_would_block = 1; - -#if defined(ENABLE_PGM_DEBUG) -static void -log_handler ( - const int log_level, - const char* message, - void* closure -) -{ - printf("%s\n", message); -} -#endif - -int pgm_oai_init(char *if_addr) -{ - pgm_error_t* pgm_err = NULL; - - memset(pgm_multicast_group, 0, - MULTICAST_LINK_NUM_GROUPS * sizeof(pgm_multicast_group_t)); - -#if defined(ENABLE_PGM_DEBUG) - pgm_messages_init(); - pgm_min_log_level = PGM_LOG_LEVEL_DEBUG; - pgm_log_mask = 0xFFF; - - pgm_log_set_handler(log_handler, NULL); -#endif - - if (!pgm_init(&pgm_err)) { - LOG_E(EMU, "Unable to start PGM engine: %s\n", pgm_err->message); - pgm_error_free (pgm_err); - exit(EXIT_FAILURE); - } - - return pgm_create_socket(oai_emulation.info.multicast_group, if_addr); -} - -int pgm_recv_msg(int group, uint8_t *buffer, uint32_t length, - unsigned int frame, unsigned int next_slot) -{ - size_t num_bytes = 0; - int status = 0; - pgm_error_t* pgm_err = NULL; - struct pgm_sockaddr_t from; - socklen_t fromlen = sizeof(from); - uint32_t timeout = 0; - int flags = 0; - - if (pgm_would_block == 0) { - flags = MSG_DONTWAIT; - } - - DevCheck((group <= MULTICAST_LINK_NUM_GROUPS) && (group >= 0), - group, MULTICAST_LINK_NUM_GROUPS, 0); - -#ifdef DEBUG_EMU - LOG_I(EMU, "[PGM] Entering recv function for group %d\n", group); -#endif - - do { - status = pgm_recvfrom(pgm_multicast_group[group].sock, - buffer, - length, - flags, - &num_bytes, - &from, - &fromlen, - &pgm_err); - - if (PGM_IO_STATUS_NORMAL == status) { -#ifdef DEBUG_EMU - LOG_D(EMU, "[PGM] Received %d bytes for group %d\n", num_bytes, group); -#endif - return num_bytes; - } else if (PGM_IO_STATUS_TIMER_PENDING == status) { - if (pgm_would_block == 0) { - /* We sleep for 50 usec */ - usleep(50); - - timeout ++; - - if (timeout == (1000000 / 50)) { - LOG_W(EMU, "[PGM] A packet has been lost -> ask for retransmit\n"); - /* If we do not receive a packet after 10000usec - * -> send a NACK */ - bypass_tx_nack(frame, next_slot); - timeout = 0; - } - } - } else if (PGM_IO_STATUS_RESET == status) { - LOG_W(EMU, "[PGM] Got session reset\n"); - } else { -#ifdef DEBUG_EMU - LOG_D(EMU, "[PGM] Got status %d\n", status); -#endif - - if (pgm_err) { - LOG_E(EMU, "[PGM] recvform failed: %s", pgm_err->message); - pgm_error_free (pgm_err); - pgm_err = NULL; - } - } - } while(status != PGM_IO_STATUS_NORMAL); - - return -1; -} - -int pgm_link_send_msg(int group, uint8_t *data, uint32_t len) -{ - int status; - size_t bytes_written = 0; - - do { - status = pgm_send(pgm_multicast_group[group].sock, data, len, &bytes_written); - } while(status == PGM_IO_STATUS_WOULD_BLOCK); - - if (status != PGM_IO_STATUS_NORMAL) { - return -1; - } - - return bytes_written; -} - -static -int pgm_create_socket(int index, const char *if_addr) -{ - struct pgm_addrinfo_t* res = NULL; - pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_INET; - int udp_encap_port = 46014 + index; - int max_tpdu = 1500; - int sqns = 100; - int port = 0; - struct pgm_sockaddr_t addr; - int blocking = 1; - int multicast_loop = 0; - int multicast_hops = 0; - int dscp, i; - - port = udp_encap_port; - - /* Use PGM */ - udp_encap_port = 0; - - LOG_D(EMU, "[PGM] Preparing socket for group %d and address %s\n", - index, if_addr); - - if (!pgm_getaddrinfo(if_addr, NULL, &res, &pgm_err)) { - LOG_E(EMU, "Parsing network parameter: %s\n", pgm_err->message); - goto err_abort; - } - - if (udp_encap_port) { - LOG_I(EMU, "[PGM] Creating PGM/UDP socket for encapsulated port %d\n", - udp_encap_port); - - if (!pgm_socket (&pgm_multicast_group[index].sock, sa_family, - SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - LOG_E(EMU, "[PGM] Socket: %s\n", pgm_err->message); - goto err_abort; - } - - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, - sizeof(udp_encap_port)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, - sizeof(udp_encap_port)); - } else { - LOG_I(EMU, "[PGM] Creating PGM/IP socket\n"); - - if (!pgm_socket(&pgm_multicast_group[index].sock, sa_family, - SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - LOG_E(EMU, "Creating PGM/IP socket: %s\n", pgm_err->message); - goto err_abort; - } - } - - { - /* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_IP_ROUTER_ALERT, &no_router_assist, - sizeof(no_router_assist)); - } - - // pgm_drop_superuser(); - - { - /* set PGM parameters */ - const int recv_only = 0, - passive = 0, - peer_expiry = pgm_secs (300), - spmr_expiry = pgm_msecs (250), - nak_bo_ivl = pgm_msecs (10), - nak_rpt_ivl = pgm_secs (2), - nak_rdata_ivl = pgm_secs (2), - nak_data_retries = 50, - nak_ncf_retries = 50, - ambient_spm = pgm_secs(30); - const int heartbeat_spm[] = { - pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (1300), - pgm_secs (7), - pgm_secs (16), - pgm_secs (25), - pgm_secs (30) - }; - - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_PASSIVE, &passive, sizeof(passive)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_MTU, &max_tpdu, sizeof(max_tpdu)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_RXW_SQNS, &sqns, sizeof(sqns)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_TXW_SQNS, &sqns, sizeof(sqns)); - } - - /* create global session identifier */ - memset (&addr, 0, sizeof(addr)); - /* sa_port should be in host byte order */ - addr.sa_port = port; - addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT + index; - - if (!pgm_gsi_create_from_hostname(&addr.sa_addr.gsi, &pgm_err)) { - LOG_E(EMU, "[PGM] Creating GSI: %s\n", pgm_err->message); - goto err_abort; - } - - LOG_D(EMU, "[PGM] Created GSI %s\n", pgm_tsi_print(&addr.sa_addr)); - - /* assign socket to specified address */ - { - struct pgm_interface_req_t if_req; - memset (&if_req, 0, sizeof(if_req)); - if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; - if_req.ir_scope_id = 0; - - if (AF_INET6 == sa_family) { - struct sockaddr_in6 sa6; - memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); - if_req.ir_scope_id = sa6.sin6_scope_id; - } - - if (!pgm_bind3(pgm_multicast_group[index].sock, &addr, sizeof(addr), - &if_req, sizeof(if_req), /* tx interface */ - &if_req, sizeof(if_req), /* rx interface */ - &pgm_err)) { - LOG_E(EMU, "[PGM] Error: %s\n", pgm_err->message); - goto err_abort; - } - } - - /* join IP multicast groups */ - { - struct group_req req; - struct sockaddr_in addr_in; - - memset(&req, 0, sizeof(req)); - - /* Interface index */ - req.gr_interface = res->ai_recv_addrs[0].gsr_interface; - - addr_in.sin_family = AF_INET; - addr_in.sin_port = htons(port); - - for (i = 0; i < MULTICAST_LINK_NUM_GROUPS; i++) { - addr_in.sin_addr.s_addr = inet_addr(multicast_group_list[i]); - memcpy(&req.gr_group, &addr_in, sizeof(addr_in)); - - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_JOIN_GROUP, &req, - sizeof(struct group_req)); - } - - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_SEND_GROUP, &req, - sizeof(struct group_req)); - } - - pgm_freeaddrinfo(res); - res = NULL; - - /* set IP parameters */ - multicast_hops = 64; - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, - PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - - if (AF_INET6 != sa_family) - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, PGM_TOS, - &dscp, sizeof(dscp)); - - pgm_setsockopt(pgm_multicast_group[index].sock, IPPROTO_PGM, PGM_NOBLOCK, - &blocking, sizeof(blocking)); - - if (!pgm_connect(pgm_multicast_group[index].sock, &pgm_err)) { - LOG_E(EMU, "[PGM] Connecting socket: %s\n", pgm_err->message); - goto err_abort; - } - - return 0; - -err_abort: - - if (NULL != pgm_multicast_group[index].sock) { - pgm_close(pgm_multicast_group[index].sock, FALSE); - pgm_multicast_group[index].sock = NULL; - } - - if (NULL != res) { - pgm_freeaddrinfo(res); - res = NULL; - } - - if (NULL != pgm_err) { - pgm_error_free(pgm_err); - pgm_err = NULL; - } - - exit(EXIT_FAILURE); -} - -#endif diff --git a/openair1/SIMULATION/ETH_TRANSPORT/pgm_link.h b/openair1/SIMULATION/ETH_TRANSPORT/pgm_link.h deleted file mode 100644 index 03fa6d4b48..0000000000 --- a/openair1/SIMULATION/ETH_TRANSPORT/pgm_link.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#ifndef PGM_LINK_H_ -#define PGM_LINK_H_ - -/* Define prototypes only if enabled */ -#if defined(ENABLE_PGM_TRANSPORT) -void bypass_tx_nack(unsigned int frame, unsigned int next_slot); - -int pgm_oai_init(char *if_name); - -int pgm_recv_msg(int group, uint8_t *buffer, uint32_t length, - unsigned int frame, unsigned int next_slot); - -int pgm_link_send_msg(int group, uint8_t *data, uint32_t len); - -#endif - -#endif /* PGM_LINK_H_ */ diff --git a/targets/RT/USER/UE_transport_IQ.c b/targets/RT/USER/UE_transport_IQ.c deleted file mode 100644 index 16f491263d..0000000000 --- a/targets/RT/USER/UE_transport_IQ.c +++ /dev/null @@ -1,548 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file UE_transport_IQ.c - * \brief UE transport IQ sampels - * \author Katerina Trilyraki, Navid Nikaein, Raymond Knopp - * \date 2015 - * \version 0.1 - * \company Eurecom - * \maintainer: navid.nikaein@eurecom.fr - * \note - * \warning very experimental - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "common_lib.h" -#include "PHY/defs.h" -#include "rrh_gw.h" -#include "rrh_gw_externs.h" - -#define START_CMD 1 -#define RRH_UE_PORT 51000 -#define RRH_UE_DEST_IP "127.0.0.1" -#define PRINTF_PERIOD 3750 - -/****************************************************************************** - ** FUNCTION PROTOTYPES ** - ******************************************************************************/ -void *rrh_proc_UE_thread(void *); -void *rrh_UE_thread(void *); -void *rrh_UE_rx_thread(void *); -void *rrh_UE_tx_thread(void *); - - - -openair0_timestamp timestamp_UE_tx[4]= {0,0,0,0},timestamp_UE_rx[4]= {0,0,0,0}; -openair0_timestamp nrt_UE_counter[4]= {0,0,0,0}; - -pthread_t main_rrh_UE_thread,main_rrh_proc_UE_thread; -pthread_attr_t attr, attr_proc; -struct sched_param sched_param_rrh, sched_param_rrh_proc; -pthread_cond_t sync_UE_cond[4]; -pthread_mutex_t sync_UE_mutex[4]; - -int32_t overflow_rx_buffer_UE[4]= {0,0,0,0}; -int32_t nsamps_UE[4]= {0,0,0,0}; -int32_t UE_tx_started=0,UE_rx_started=0; -int32_t RT_flag_UE=0, NRT_flag_UE=1; -int32_t counter_UE_rx[4]= {0,0,0,0}; -int32_t counter_UE_tx[4]= {0,0,0,0}; -int32_t **tx_buffer_UE, **rx_buffer_UE; - -int sync_UE_rx[4]= {-1,-1,-1,-1}; -void *rrh_UE_thread_status; - - -void *rx_ue[2]; // FIXME hard coded array size; indexed by lte_frame_parms.nb_antennas_rx -void *tx_ue[2]; // FIXME hard coded array size; indexed by lte_frame_parms.nb_antennas_tx - - -void config_UE_mod( rrh_module_t *dev_ue, uint8_t RT_flag,uint8_t NRT_flag) { - - int i; - int error_code_UE, error_code_proc_UE; - - RT_flag_UE=RT_flag; - NRT_flag_UE=NRT_flag; - - pthread_attr_init(&attr); - sched_param_rrh.sched_priority = sched_get_priority_max(SCHED_FIFO); - pthread_attr_init(&attr_proc); - sched_param_rrh_proc.sched_priority = sched_get_priority_max(SCHED_FIFO-1); - - pthread_attr_setschedparam(&attr,&sched_param_rrh); - pthread_attr_setschedpolicy(&attr,SCHED_FIFO); - pthread_attr_setschedparam(&attr_proc,&sched_param_rrh_proc); - pthread_attr_setschedpolicy(&attr_proc,SCHED_FIFO-1); - - - for (i=0; i<4; i++) { - pthread_mutex_init(&sync_UE_mutex[i],NULL); - pthread_cond_init(&sync_UE_cond[i],NULL); - } - - error_code_UE = pthread_create(&main_rrh_UE_thread, &attr, rrh_UE_thread, (void *)dev_ue); - error_code_proc_UE = pthread_create(&main_rrh_proc_UE_thread, &attr_proc, rrh_proc_UE_thread, (void *)dev_ue); - - if (error_code_UE) { - printf("Error while creating UE thread\n"); - exit(-1); - } - - if (error_code_proc_UE) { - printf("Error while creating UE proc thread\n"); - exit(-1); - } - -} - - -/*! \fn void *rrh_proc_UE_thread((void *)dev_ue) -* \brief this function -* \param[in] -* \param[out] -* \return -* \note -* @ingroup _oai -*/ -void *rrh_proc_UE_thread(void * arg) { - - int antenna_index,i; - openair0_timestamp truncated_timestamp, truncated_timestamp_final, last_hw_counter=0; - struct timespec time_req, time_rem; - int16_t *txp,*rxp; - unsigned int samples_per_frame=0; - rrh_module_t *dev=(rrh_module_t *)arg; - - samples_per_frame= dev->eth_dev.openair0_cfg->samples_per_frame; - AssertFatal(samples_per_frame <=0, "invalide samples_per_frame !%u\n",samples_per_frame); - - time_req.tv_sec = 0; - time_req.tv_nsec = 1000; - - while (rrh_exit==0) { - //wait until some data has been copied - for (antenna_index=0; antenna_index<4; antenna_index++) { - if (sync_UE_rx[antenna_index]==0) { - if (!UE_tx_started) { - UE_tx_started=1; //Set this flag to 1 to indicate that a UE started retrieving data - if (RT_flag_UE==1) { - last_hw_counter=hw_counter; - } - } else { - if (RT_flag_UE==1) { - if (hw_counter > last_hw_counter+1) { - printf("L1"); - // goto end_copy_UE; - } else { - while (hw_counter < last_hw_counter+1) - nanosleep(&time_req,&time_rem); - } - } - } - - truncated_timestamp = timestamp_UE_tx[antenna_index]%(samples_per_frame); - truncated_timestamp_final = (timestamp_UE_tx[antenna_index]+nsamps_UE[antenna_index])%samples_per_frame; - - if ((truncated_timestamp + nsamps_UE[antenna_index]) > samples_per_frame) { - if ((timestamp_eNB_rx[antenna_index]%samples_per_frame < nsamps_UE[antenna_index]) && (eNB_rx_started==1)) { - overflow_rx_buffer_eNB[antenna_index]++; - printf("eNB Overflow[%d] : %d, timestamp : %d\n",antenna_index,overflow_rx_buffer_eNB[antenna_index],(int)truncated_timestamp); - - if (NRT_flag_UE==1) { - while ((timestamp_eNB_rx[antenna_index]%samples_per_frame) < nsamps_UE[antenna_index]) - nanosleep(&time_req,&time_rem); - } - } - - rxp = (int16_t*)&rx_buffer_eNB[antenna_index][truncated_timestamp]; - txp = (int16_t*)&tx_buffer_UE[antenna_index][truncated_timestamp]; - - for (i=0; i<(samples_per_frame<<1)-(truncated_timestamp<<1); i++) { - rxp[i] = txp[i]>>6; - } - - rxp = (int16_t*)&rx_buffer_eNB[antenna_index][0]; - txp = (int16_t*)&tx_buffer_UE[antenna_index][0]; - - for (i=0; i>6; - } - - } else { - if (((truncated_timestamp < (timestamp_eNB_rx[antenna_index]%samples_per_frame)) && - (truncated_timestamp_final > (timestamp_eNB_rx[antenna_index]%samples_per_frame))) && - (eNB_rx_started==1)) { - overflow_rx_buffer_eNB[antenna_index]++; - printf("eNB Overflow[%d] : %d, timestamp : %d\n",antenna_index,overflow_rx_buffer_eNB[antenna_index],(int)truncated_timestamp); - - if (NRT_flag_UE==1) { - while (truncated_timestamp_final > timestamp_eNB_rx[antenna_index]%samples_per_frame) - nanosleep(&time_req,&time_rem); - } - } - - rxp = (int16_t*)&rx_buffer_eNB[antenna_index][truncated_timestamp]; - txp = (int16_t*)&tx_buffer_UE[antenna_index][truncated_timestamp]; - - for (i=0; i<(nsamps_eNB[antenna_index]); i++) { - rxp[i] =txp[i]>>6; - } - - } - //end_copy_UE : - last_hw_counter=hw_counter; - pthread_mutex_lock(&sync_UE_mutex[antenna_index]); - sync_UE_rx[antenna_index]--; - pthread_mutex_unlock(&sync_UE_mutex[antenna_index]); - - } - } - - } - - return(0); -} - -/*! \fn void *rrh_UE_thread(void *arg) -* \brief this function -* \param[in] -* \param[out] -* \return -* \note -* @ingroup _oai -*/ -void *rrh_UE_thread(void *arg) { - - rrh_module_t *dev=(rrh_module_t *)arg; - - struct sched_param sched_param_UE_rx, sched_param_UE_tx; - int16_t i,cmd; //,nsamps,antenna_index; - //struct timespec time_req_1us; - pthread_t UE_rx_thread, UE_tx_thread; - pthread_attr_t attr_UE_rx, attr_UE_tx; - int error_code_UE_rx, error_code_UE_tx; - void *tmp; - unsigned int samples_per_frame=0; - - samples_per_frame= dev->eth_dev.openair0_cfg->samples_per_frame; - //time_req_1us.tv_sec = 0; - //time_req_1us.tv_nsec = 1000; - - while (rrh_exit==0) { - - cmd=dev->eth_dev.trx_start_func(&dev->eth_dev); - - /* allocate memory for TX/RX buffers */ - rx_buffer_UE = (int32_t**)malloc16(dev->eth_dev.openair0_cfg->rx_num_channels*sizeof(int32_t*)); - tx_buffer_UE = (int32_t**)malloc16(dev->eth_dev.openair0_cfg->tx_num_channels*sizeof(int32_t*)); - - for (i=0; ieth_dev.openair0_cfg->rx_num_channels; i++) { - tmp=(void *)malloc(sizeof(int32_t)*(samples_per_frame+4)); - memset(tmp,0,sizeof(int32_t)*(samples_per_frame+4)); - rx_buffer_UE[i]=(tmp+4*sizeof(int32_t)); - } - - for (i=0; ieth_dev.openair0_cfg->tx_num_channels; i++) { - tmp=(void *)malloc(sizeof(int32_t)*(samples_per_frame+4)); - memset(tmp,0,sizeof(int32_t)*(samples_per_frame+4)); - tx_buffer_UE[i]=(tmp+4*sizeof(int32_t)); - } - - printf("Client %s:%d is connected (DL_RB=%d) rt=%d|%d. \n" , dev->eth_dev.openair0_cfg->remote_addr, - dev->eth_dev.openair0_cfg->remote_port, - dev->eth_dev.openair0_cfg->num_rb_dl, - dev->eth_dev.openair0_cfg->rx_num_channels, - dev->eth_dev.openair0_cfg->tx_num_channels); - - if (cmd==START_CMD) { - - pthread_attr_init(&attr_UE_rx); - pthread_attr_init(&attr_UE_tx); - sched_param_UE_rx.sched_priority = sched_get_priority_max(SCHED_FIFO); - sched_param_UE_tx.sched_priority = sched_get_priority_max(SCHED_FIFO); - pthread_attr_setschedparam(&attr_UE_rx,&sched_param_UE_rx); - pthread_attr_setschedparam(&attr_UE_tx,&sched_param_UE_tx); - pthread_attr_setschedpolicy(&attr_UE_rx,SCHED_FIFO); - pthread_attr_setschedpolicy(&attr_UE_tx,SCHED_FIFO); - - error_code_UE_rx = pthread_create(&UE_rx_thread, &attr_UE_rx, rrh_UE_rx_thread, (void *)&dev); - error_code_UE_tx = pthread_create(&UE_tx_thread, &attr_UE_tx, rrh_UE_tx_thread, (void *)&dev); - - if (error_code_UE_rx) { - printf("Error while creating UE RX thread\n"); - exit(-1); - } - - if (error_code_UE_tx) { - printf("Error while creating UE TX thread\n"); - exit(-1); - } - - while (rrh_exit==0) - sleep(1); - } - } - - - rrh_UE_thread_status = 0; - pthread_exit(&rrh_UE_thread_status); - - return(0); -} - - -/*! \fn void *rrh_UE_rx_thread(void *arg) -* \brief this function -* \param[in] -* \param[out] -* \return -* \note -* @ingroup _oai -*/ -void *rrh_UE_rx_thread(void *arg) { - - rrh_module_t *dev = (rrh_module_t *)arg; - struct timespec time0,time1,time2; - struct timespec time_req_1us, time_rem_1us; - ssize_t bytes_sent; - int antenna_index, nsamps; - int trace_cnt=0; - unsigned long long max_rx_time=0, min_rx_time=133333, total_rx_time=0, average_rx_time=133333, s_period=0, trial=0; - unsigned int samples_per_frame=0; - openair0_timestamp last_hw_counter=0; - - antenna_index = 0; - nsamps = dev->eth_dev.openair0_cfg->samples_per_packet; - samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame; - - /* TODO: check if setting time0 has to be done here */ - clock_gettime(CLOCK_MONOTONIC,&time0); - - while (rrh_exit == 0) { - if (!UE_rx_started) { - UE_rx_started=1; //Set this flag to 1 to indicate that a UE started retrieving data - - if (RT_flag_UE==1) { - last_hw_counter=hw_counter; - } - } else { - if (RT_flag_UE==1) { - if (hw_counter > last_hw_counter+1) { - printf("L1"); - //goto end_copy_UE; - } else { - while (hw_counter < last_hw_counter+1) - nanosleep(&time_req_1us,&time_rem_1us); - } - } - } - - clock_gettime(CLOCK_MONOTONIC,&time1); - - // send return - - if ((timestamp_UE_rx[antenna_index]%(samples_per_frame)+nsamps) > samples_per_frame) { // Wrap around if nsamps exceeds the buffer limit - if (((timestamp_eNB_tx[antenna_index]%(samples_per_frame)) < ((timestamp_UE_rx[antenna_index]+nsamps)%(samples_per_frame))) && (eNB_tx_started==1)) { - printf("UE underflow wraparound timestamp_UE_rx : %d, timestamp_eNB_tx : %d\n", - (int)(timestamp_UE_rx[antenna_index]%(samples_per_frame)), - (int)(timestamp_eNB_tx[antenna_index]%samples_per_frame)); - - if (NRT_flag_UE==1) { - while ((timestamp_eNB_tx[antenna_index]%samples_per_frame) < ((timestamp_UE_rx[antenna_index]+nsamps)%(samples_per_frame))) - nanosleep(&time_req_1us,&time_rem_1us); - } - } - - rx_ue[antenna_index]=(void*)&rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(samples_per_frame)]; - if ((bytes_sent =dev->eth_dev.trx_write_func (dev, - timestamp_UE_rx[antenna_index], - rx_ue, - ( samples_per_frame- (timestamp_eNB_rx[antenna_index]%(samples_per_frame)) ), - antenna_index, - 0))<0) - perror("RRH UE : sendto for RX"); - - rx_ue[antenna_index]=(void*)&rx_buffer_UE[antenna_index][3]; - if ((bytes_sent =dev->eth_dev.trx_write_func (dev, - timestamp_UE_rx[antenna_index], - rx_ue, - (nsamps - samples_per_frame + (timestamp_eNB_rx[antenna_index]%(samples_per_frame))), - antenna_index, - 0))<0) - perror("RRH UE : sendto for RX"); - - } else { - if (((timestamp_UE_rx[antenna_index]%samples_per_frame)< timestamp_eNB_tx[antenna_index]%samples_per_frame) && - (((timestamp_UE_rx[antenna_index]+nsamps)%samples_per_frame) > (timestamp_eNB_tx[antenna_index]%samples_per_frame)) && - (eNB_tx_started==1) ) { - printf("UE underflow timestamp_UE_rx : %d, timestamp_eNB_tx : %d\n", - (int)(timestamp_UE_rx[antenna_index]%samples_per_frame), - (int)(timestamp_eNB_tx[antenna_index]%samples_per_frame)); - - if (NRT_flag_UE==1) { - while (((timestamp_UE_rx[antenna_index]+nsamps)%samples_per_frame) > (timestamp_eNB_tx[antenna_index]%samples_per_frame)) { - nanosleep(&time_req_1us,&time_rem_1us); - } - } - } - - rx_ue[antenna_index]=(void*)&rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(samples_per_frame)]; - if ((bytes_sent = dev->eth_dev.trx_write_func (dev, - timestamp_UE_rx[antenna_index], - rx_ue, - nsamps, - antenna_index, - 0))<0) - perror("RRH UE thread: sendto for RX"); - } - - timestamp_UE_rx[antenna_index]+=nsamps; - last_hw_counter=hw_counter; - - clock_gettime(CLOCK_MONOTONIC,&time2); - - if (trace_cnt++ > 10) { - total_rx_time = (unsigned int)(time2.tv_nsec - time0.tv_nsec); - - if (total_rx_time < 0) total_rx_time=1000000000-total_rx_time; - - if ((total_rx_time > 0) && (total_rx_time < 1000000000)) { - trial++; - - if (total_rx_time < min_rx_time) - min_rx_time = total_rx_time; - - if (total_rx_time > max_rx_time) - max_rx_time = total_rx_time; - - average_rx_time = (long long unsigned int)((average_rx_time*trial)+total_rx_time)/(trial+1); - } - - if (s_period++ == PRINTF_PERIOD) { - s_period=0; - printf("Average UE RX time : %llu\tMax RX time : %llu\tMin RX time : %llu\n",average_rx_time,max_rx_time,min_rx_time); - - } - - //printf("RX: t1 %llu (time from last send), t2 %llu (sendto of %lu bytes) total time : %llu\n",(long long unsigned int)(time1.tv_nsec - time0.tv_nsec), (long long unsigned int)(time2.tv_nsec - time1.tv_nsec), - // (nsamps<<2)+sizeof(openair0_timestamp),(long long unsigned int)(time2.tv_nsec - time0.tv_nsec)); - - } - - memcpy(&time0,&time2,sizeof(struct timespec)); - - } //while (UE_exit==0) - - return(0); - -} - - -/*! \fn void *rrh_UE_tx_thread(void *arg) -* \brief this function -* \param[in] -* \param[out] -* \return -* \note -* @ingroup _oai -*/ -void *rrh_UE_tx_thread(void *arg) { - - struct timespec time0a,time0,time1,time2; - struct timespec time_req_1us, time_rem_1us; - - - rrh_module_t *dev = (rrh_module_t *)arg; - ssize_t bytes_received; - int antenna_index, nsamps; - unsigned int samples_per_frame=0; - - antenna_index = 0; - nsamps = dev->eth_dev.openair0_cfg->samples_per_packet; - samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame; - - - while (rrh_exit == 0) { - - clock_gettime(CLOCK_MONOTONIC,&time0a); - - bytes_received = dev->eth_dev.trx_read_func(dev, - ×tamp_UE_tx[antenna_index], - tx_ue, - nsamps, - antenna_index); - - clock_gettime(CLOCK_MONOTONIC,&time1); - - if (NRT_flag_UE==1) { - nrt_UE_counter[antenna_index]++; - } - printf(" first part size: %d second part size: %"PRId64" idx=%"PRId64"\n", - (int32_t)(((samples_per_frame)<<2)-((timestamp_UE_tx[antenna_index]%(samples_per_frame))<<2)), - (nsamps<<2)-((samples_per_frame)<<2)+((timestamp_UE_tx[antenna_index]%(samples_per_frame))<<2), - timestamp_UE_tx[antenna_index]%(samples_per_frame)); - if ((timestamp_UE_tx[antenna_index]%(samples_per_frame)+nsamps) > samples_per_frame) { // Wrap around if nsamps exceeds the buffer limit - memcpy(&tx_buffer_UE[antenna_index][timestamp_UE_tx[antenna_index]%(samples_per_frame)],(void*)(tx_ue[antenna_index]), - (samples_per_frame<<2)-((timestamp_UE_tx[antenna_index]%(samples_per_frame))<<2)); - - memcpy(&tx_buffer_UE[antenna_index][0], (void*)(tx_ue[antenna_index]+(samples_per_frame*4)-((timestamp_UE_tx[antenna_index]%(samples_per_frame))<<2)), - (nsamps<<2)-((samples_per_frame-(timestamp_UE_tx[antenna_index]%(samples_per_frame)))<<2)); - //printf("Received UE TX samples for antenna %d, nsamps %d (%d)\n",antenna_index,nsamps,(int)(bytes_received>>2)); - } else { - memcpy(&tx_buffer_UE[antenna_index][timestamp_UE_tx[antenna_index]%(samples_per_frame)], (void*)(tx_ue[antenna_index]),(nsamps<<2)); - } - - while (sync_UE_rx[antenna_index]==0) - nanosleep(&time_req_1us,&time_rem_1us); - - pthread_mutex_lock(&sync_UE_mutex[antenna_index]); - sync_UE_rx[antenna_index]++; - - if (!sync_UE_rx[antenna_index]) { - counter_UE_tx[antenna_index]=(counter_UE_tx[antenna_index]+nsamps)%samples_per_frame; - nsamps_UE[antenna_index]=nsamps; - } else { - printf("rrh_eNB_proc thread is busy, will exit\n"); - exit(-1); - } - - pthread_mutex_unlock(&sync_UE_mutex[antenna_index]); - - clock_gettime(CLOCK_MONOTONIC,&time2); - - memcpy(&time0,&time2,sizeof(struct timespec)); - - } - - return(0); - -} - - diff --git a/targets/RT/USER/eNB_transport_IQ.c b/targets/RT/USER/eNB_transport_IQ.c deleted file mode 100644 index b822a5ea75..0000000000 --- a/targets/RT/USER/eNB_transport_IQ.c +++ /dev/null @@ -1,744 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file eNB_transport_IQ.c - * \brief eNB transport IQ samples - * \author Katerina Trilyraki, Navid Nikaein, Raymond Knopp - * \date 2015 - * \version 0.1 - * \company Eurecom - * \maintainer: navid.nikaein@eurecom.fr - * \note - * \warning very experimental - */ -#include -#include -#include -#include -#include -#include -#include - -#include "common_lib.h" -#include "PHY/defs.h" -#include "rrh_gw.h" -#include "rrh_gw_externs.h" -#include "rt_wrapper.h" - -#define PRINTF_PERIOD 3750 -#define HEADER_SIZE ((sizeof(int32_t) + sizeof(openair0_timestamp))>>2) - -pthread_cond_t sync_eNB_cond[4]; -pthread_mutex_t sync_eNB_mutex[4]; -pthread_mutex_t sync_trx_mutex=PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t sync_trx_cond=PTHREAD_COND_INITIALIZER; - -openair0_timestamp nrt_eNB_counter[4]= {0,0,0,0}; -int32_t overflow_rx_buffer_eNB[4]= {0,0,0,0}; -int32_t nsamps_eNB[4]= {0,0,0,0}; -int32_t eNB_tx_started=0,eNB_rx_started=0; -int32_t counter_eNB_rx[4]= {0,0,0,0}; -int32_t counter_eNB_tx[4]= {0,0,0,0}; -uint8_t RT_flag_eNB,NRT_flag_eNB; -void *rrh_eNB_thread_status; -int sync_eNB_rx[4]= {-1,-1,-1,-1}; -unsigned int sync_trx=0; - -int32_t **tx_buffer_eNB; -int32_t **rx_buffer_eNB; -void **rx_eNB; //was fixed to 2 ant -void **tx_eNB; //was fixed to 2 ant - -openair0_timestamp timestamp_eNB_tx[4]= {0,0,0,0};// all antennas must have the same ts -openair0_timestamp timestamp_eNB_rx[4]= {0,0,0,0}; -openair0_timestamp timestamp_rx=0,timestamp_tx=0; - -unsigned int rx_pos=0, next_rx_pos=0; -unsigned int tx_pos=0, tx_pos_rf=0, prev_tx_pos=0; -unsigned int rt_period=0; - -struct itimerspec timerspec; -pthread_mutex_t timer_mutex; - - - -/*! \fn void *rrh_eNB_rx_thread(void *arg) - * \brief this function - * \param[in] - * \return none - * \note - * @ingroup _oai - */ -void *rrh_eNB_rx_thread(void *); -/*! \fn void *rrh_eNB_tx_thread(void *arg) - * \brief this function - * \param[in] - * \return none - * \note - * @ingroup _oai - */ -void *rrh_eNB_tx_thread(void *); -/*! \fn void *rrh_eNB_thread(void *arg) - * \brief this function - * \param[in] - * \return none - * \note - * @ingroup _oai - */ -void *rrh_eNB_thread(void *); -/*! \fn void check_dev_config( rrh_module_t *mod_enb) - * \brief this function - * \param[in] *mod_enb - * \return none - * \note - * @ingroup _oai - */ -static void check_dev_config( rrh_module_t *mod_enb); -/*! \fn void calc_rt_period_ns( openair0_config_t openair0_cfg) - * \brief this function - * \param[in] openair0_cfg - * \return none - * \note - * @ingroup _oai - */ -static void calc_rt_period_ns( openair0_config_t *openair0_cfg); - - - -void config_BBU_mod( rrh_module_t *mod_enb, uint8_t RT_flag, uint8_t NRT_flag) { - - int error_code_eNB; - pthread_t main_rrh_eNB_thread; - pthread_attr_t attr; - struct sched_param sched_param_rrh; - - RT_flag_eNB=RT_flag; - NRT_flag_eNB=NRT_flag; - - /* init socket and have handshake-like msg with client to exchange parameters */ - mod_enb->eth_dev.trx_start_func(&mod_enb->eth_dev);//change port make it plus_id - - mod_enb->devs->openair0_cfg = mod_enb->eth_dev.openair0_cfg; - - /* check sanity of configuration parameters and print */ - check_dev_config(mod_enb); - if (rf_config_file[0] == '\0') - mod_enb->devs->openair0_cfg->configFilename = NULL; - else - mod_enb->devs->openair0_cfg->configFilename = rf_config_file; - /* initialize and configure the RF device */ - if (openair0_device_load(mod_enb->devs, mod_enb->devs->openair0_cfg)<0) { - LOG_E(RRH,"Exiting, cannot initialize RF device.\n"); - exit(-1); - } else { - if (mod_enb->devs->type != NONE_DEV) { - /* start RF device */ - if (mod_enb->devs->type == EXMIMO_DEV) { - //call start function for exmino - } else { - - if (mod_enb->devs->trx_start_func(mod_enb->devs)!=0) - LOG_E(RRH,"Unable to initiate RF device.\n"); - else - LOG_I(RRH,"RF device has been initiated.\n"); - } - - } - } - - /* create main eNB module thread - main_rrh_eNB_thread allocates memory - for TX/RX buffers and creates TX/RX - threads for every eNB module */ - pthread_attr_init(&attr); - sched_param_rrh.sched_priority = sched_get_priority_max(SCHED_FIFO); - pthread_attr_setschedparam(&attr,&sched_param_rrh); - pthread_attr_setschedpolicy(&attr,SCHED_FIFO); - error_code_eNB = pthread_create(&main_rrh_eNB_thread, &attr, rrh_eNB_thread, (void *)mod_enb); - - if (error_code_eNB) { - LOG_E(RRH,"Error while creating eNB thread\n"); - exit(-1); - } - -} - - -void *rrh_eNB_thread(void *arg) { - - rrh_module_t *dev=(rrh_module_t *)arg; - pthread_t eNB_rx_thread, eNB_tx_thread; - int error_code_eNB_rx, error_code_eNB_tx; - int32_t i,j; - void *tmp; - unsigned int samples_per_frame=0; - - samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame; - - while (rrh_exit==0) { - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TRX, 1 ); - - /* calculate packet period */ - calc_rt_period_ns(dev->eth_dev.openair0_cfg); - - /* allocate memory for TX/RX buffers - each antenna port has a TX and a RX buffer - each TX and RX buffer is of (samples_per_frame + HEADER_SIZE) samples (size of samples is 4 bytes) */ - rx_buffer_eNB = (int32_t**)malloc16(dev->eth_dev.openair0_cfg->rx_num_channels*sizeof(int32_t*)); - tx_buffer_eNB = (int32_t**)malloc16(dev->eth_dev.openair0_cfg->tx_num_channels*sizeof(int32_t*)); - LOG_D(RRH,"rx_buffer_eNB address =%p tx_buffer_eNB address =%p \n",rx_buffer_eNB,tx_buffer_eNB); - - /* rx_buffer_eNB points to the beginning of data */ - for (i=0; ieth_dev.openair0_cfg->rx_num_channels; i++) { - tmp=(void *)malloc16(sizeof(int32_t)*(samples_per_frame + 32)); - memset(tmp,0,sizeof(int32_t)*(samples_per_frame + 32)); - rx_buffer_eNB[i]=( tmp + (32*sizeof(int32_t)) ); - LOG_D(RRH,"i=%d rx_buffer_eNB[i]=%p tmp= %p\n",i,rx_buffer_eNB[i],tmp); - } - /* tx_buffer_eNB points to the beginning of data */ - for (i=0; ieth_dev.openair0_cfg->tx_num_channels; i++) { - tmp=(void *)malloc16(sizeof(int32_t)*(samples_per_frame + 32)); - memset(tmp,0,sizeof(int32_t)*(samples_per_frame + 32)); - tx_buffer_eNB[i]=( tmp + (32*sizeof(int32_t)) ); - LOG_D(RRH,"i= %d tx_buffer_eNB[i]=%p tmp= %p \n",i,tx_buffer_eNB[i],tmp); - } - /* dummy initialization for TX/RX buffers */ - for (i=0; ieth_dev.openair0_cfg->rx_num_channels; i++) { - for (j=0; jeth_dev.openair0_cfg->tx_num_channels; i++) { - for (j=0; jeth_dev.openair0_cfg->rx_num_channels*sizeof(int32_t*)); - tx_eNB = (void**)malloc16(dev->eth_dev.openair0_cfg->tx_num_channels*sizeof(int32_t*)); - - /* init mutexes */ - for (i=0; ieth_dev.openair0_cfg->tx_num_channels; i++) { - pthread_mutex_init(&sync_eNB_mutex[i],NULL); - pthread_cond_init(&sync_eNB_cond[i],NULL); - } - /* init mutexes */ - pthread_mutex_init(&sync_trx_mutex,NULL); - - /* create eNB module's TX/RX threads */ -#ifdef DEADLINE_SCHEDULER - error_code_eNB_rx = pthread_create(&eNB_rx_thread, NULL, rrh_eNB_rx_thread, (void *)dev); - error_code_eNB_tx = pthread_create(&eNB_tx_thread, NULL, rrh_eNB_tx_thread, (void *)dev); - LOG_I(RRH,"[eNB][SCHED] deadline scheduling applied to eNB TX/RX threads\n"); -#else - pthread_attr_t attr_eNB_rx, attr_eNB_tx; - struct sched_param sched_param_eNB_rx, sched_param_eNB_tx; - - pthread_attr_init(&attr_eNB_rx); - pthread_attr_init(&attr_eNB_tx); - sched_param_eNB_rx.sched_priority = sched_get_priority_max(SCHED_FIFO); - sched_param_eNB_tx.sched_priority = sched_get_priority_max(SCHED_FIFO); - pthread_attr_setschedparam(&attr_eNB_rx,&sched_param_eNB_rx); - pthread_attr_setschedparam(&attr_eNB_tx,&sched_param_eNB_tx); - pthread_attr_setschedpolicy(&attr_eNB_rx,SCHED_FIFO); - pthread_attr_setschedpolicy(&attr_eNB_tx,SCHED_FIFO); - - error_code_eNB_rx = pthread_create(&eNB_rx_thread, &attr_eNB_rx, rrh_eNB_rx_thread, (void *)dev); - error_code_eNB_tx = pthread_create(&eNB_tx_thread, &attr_eNB_tx, rrh_eNB_tx_thread, (void *)dev); - LOG_I(RRH,"[eNB][SCHED] FIFO scheduling applied to eNB TX/RX threads\n"); -#endif - - if (error_code_eNB_rx) { - LOG_E(RRH,"[eNB] Error while creating eNB RX thread\n"); - exit(-1); - } - if (error_code_eNB_tx) { - LOG_E(RRH,"[eNB] Error while creating eNB TX thread\n"); - exit(-1); - } - - /* create timer thread; when no RF device is present a software clock is generated */ - if (dev->devs->type == NONE_DEV) { - - int error_code_timer; - pthread_t main_timer_proc_thread; - - LOG_I(RRH,"Creating timer thread with rt period %d ns.\n",rt_period); - - /* setup the timer to generate an interrupt: - -for the first time in (sample_per_packet/sample_rate) ns - -and then every (sample_per_packet/sample_rate) ns */ - timerspec.it_value.tv_sec = rt_period/1000000000; - timerspec.it_value.tv_nsec = rt_period%1000000000; - timerspec.it_interval.tv_sec = rt_period/1000000000; - timerspec.it_interval.tv_nsec = rt_period%1000000000; - - -#ifdef DEADLINE_SCHEDULER - error_code_timer = pthread_create(&main_timer_proc_thread, NULL, timer_proc, (void *)&timerspec); - LOG_I(RRH,"[eNB][SCHED] deadline scheduling applied to timer thread \n"); -#else - pthread_attr_t attr_timer; - struct sched_param sched_param_timer; - - pthread_attr_init(&attr_timer); - sched_param_timer.sched_priority = sched_get_priority_max(SCHED_FIFO-1); - pthread_attr_setschedparam(&attr_timer,&sched_param_timer); - pthread_attr_setschedpolicy(&attr_timer,SCHED_FIFO-1); - - pthread_mutex_init(&timer_mutex,NULL); - - error_code_timer = pthread_create(&main_timer_proc_thread, &attr_timer, timer_proc, (void *)&timerspec); - LOG_I(RRH,"[eNB][SCHED] FIFO scheduling applied to timer thread \n"); -#endif - - if (error_code_timer) { - LOG_E(RRH,"Error while creating timer proc thread\n"); - exit(-1); - } - - } - - while (rrh_exit==0) - sleep(1); - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TRX,0 ); - } - - rrh_eNB_thread_status = 0; - pthread_exit(&rrh_eNB_thread_status); - return(0); -} - -/* Receive from RF and transmit to RRH */ - -void *rrh_eNB_rx_thread(void *arg) { - - /* measurement related vars */ - struct timespec time0,time1,time2; - unsigned long long max_rx_time=0, min_rx_time=rt_period, total_rx_time=0, average_rx_time=rt_period, s_period=0, trial=0; - int trace_cnt=0; - - struct timespec time_req_1us, time_rem_1us; - rrh_module_t *dev = (rrh_module_t *)arg; - ssize_t bytes_sent; - int i=0 ,pck_rx=0, s_cnt=0; - openair0_timestamp last_hw_counter=0; //volatile int64_t - unsigned int samples_per_frame=0,samples_per_subframe=0, spp_rf=0, spp_eth=0; - uint8_t loopback=0,measurements=0; - unsigned int subframe=0; - unsigned int frame=0; - - time_req_1us.tv_sec = 0; - time_req_1us.tv_nsec =1000; //time_req_1us.tv_nsec = (int)rt_period/2;--->granularity issue - spp_eth = dev->eth_dev.openair0_cfg->samples_per_packet; - spp_rf = dev->devs->openair0_cfg->samples_per_packet; - - samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame; - samples_per_subframe = (unsigned int)samples_per_frame/10; - loopback = dev->loopback; - measurements = dev->measurements; - next_rx_pos = spp_eth; - -#ifdef DEADLINE_SCHEDULER - struct sched_attr attr; - unsigned int flags = 0; - - attr.size = sizeof(attr); - attr.sched_flags = 0; - attr.sched_nice = 0; - attr.sched_priority = 0; - - attr.sched_policy = SCHED_DEADLINE; - attr.sched_runtime = (0.8 * 100) * 10000;//4 * 10000; - attr.sched_deadline = (0.9 * 100) * 10000;//rt_period-2000; - attr.sched_period = 1 * 1000000;//rt_period; - - if (sched_setattr(0, &attr, flags) < 0 ) { - perror("[SCHED] eNB RX thread: sched_setattr failed (run with sudo)\n"); - exit(-1); - } -#endif - - while (rrh_exit == 0) { - while (rx_pos <(1 + subframe)*samples_per_subframe) { - //LOG_D(RRH,"starting a new send:%d %d\n",sync_trx,frame); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX, 1 ); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME_RX, frame); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME_RX, subframe ); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_PCK, pck_rx ); - LOG_D(RRH,"pack=%d rx_pos=%d subframe=%d frame=%d\n ",pck_rx, rx_pos, subframe,frame); - - if (dev->devs->type == NONE_DEV) { - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_HWCNT, hw_counter ); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_LHWCNT, last_hw_counter ); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_CNT, s_cnt ); - if (!eNB_rx_started) { - eNB_rx_started=1; // set this flag to 1 to indicate that eNB started - if (RT_flag_eNB==1) { - last_hw_counter=hw_counter;//get current counter - } - } else { - if (RT_flag_eNB==1) { - if (hw_counter > last_hw_counter+1) { - printf("LR"); - } else { - while ((hw_counter < last_hw_counter+1)) { - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX_SLEEP, 1 ); - nanosleep(&time_req_1us,&time_rem_1us); //rt_sleep_ns(sleep_ns); - s_cnt++; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX_SLEEP, 0 ); - } - } - } - } - } - - - if (measurements == 1 ) clock_gettime(CLOCK_MONOTONIC,&time1); - - if (loopback == 1 ) { - if (sync_eNB_rx[i]==0) { - rx_eNB[i] = (void*)&tx_buffer_eNB[i][tx_pos]; - LOG_I(RRH,"tx_buffer_eNB[i][tx_pos]=%d ,tx_pos=%d\n",tx_buffer_eNB[i][tx_pos],tx_pos); - } else { - rx_eNB[i] = (void*)&rx_buffer_eNB[i][rx_pos]; - LOG_I(RRH,"rx_buffer_eNB[i][rx_pos]=%d ,rx_pos=%d\n",rx_buffer_eNB[i][rx_pos],rx_pos); - } - } - - for (i=0; ieth_dev.openair0_cfg->rx_num_channels; i++) { - rx_eNB[i] = (void*)&rx_buffer_eNB[i][rx_pos]; - LOG_D(RRH," rx_eNB[i]=%p rx_buffer_eNB[i][rx_pos]=%p ,rx_pos=%d, i=%d ts=%d\n",rx_eNB[i],&rx_buffer_eNB[i][rx_pos],rx_pos,i,timestamp_rx); - } - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RXCNT, rx_pos ); - if (dev->devs->type != NONE_DEV) { - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_RF, 1 ); - /* Read operation to RF device (RX)*/ - if ( dev->devs->trx_read_func (dev->devs, - ×tamp_rx, - rx_eNB, - spp_rf, - dev->devs->openair0_cfg->rx_num_channels - )<0) { - perror("RRH eNB : USRP read"); - } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_RF, 0 ); - } - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_TS, timestamp_rx&0xffffffff ); - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 ); - if ((bytes_sent = dev->eth_dev.trx_write_func (&dev->eth_dev, - timestamp_rx, - rx_eNB, - spp_eth, - dev->eth_dev.openair0_cfg->rx_num_channels, - 0))<0) { - perror("RRH eNB : ETHERNET write"); - } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); - - /* when there is no RF timestamp is updated by number of samples */ - if (dev->devs->type == NONE_DEV) { - timestamp_rx+=spp_eth; - last_hw_counter=hw_counter; - } - - if (measurements == 1 ) { - - clock_gettime(CLOCK_MONOTONIC,&time2); - - if (trace_cnt++ > 10) { - total_rx_time = (unsigned int)(time2.tv_nsec - time0.tv_nsec); - if (total_rx_time < 0) - total_rx_time=1000000000-total_rx_time; - - if ((total_rx_time > 0) && (total_rx_time < 1000000000)) { - trial++; - if (total_rx_time < min_rx_time) - min_rx_time = total_rx_time; - if (total_rx_time > max_rx_time){ - max_rx_time = total_rx_time; - LOG_I(RRH,"Max value %d update at rx_position %d \n",total_rx_time,timestamp_rx); - } - average_rx_time = (long long unsigned int)((average_rx_time*trial)+total_rx_time)/(trial+1); - } - if (s_period++ == PRINTF_PERIOD) { - s_period=0; - LOG_I(RRH,"Average eNB RX time : %lu ns\tMax RX time : %lu ns\tMin RXX time : %lu ns\n",average_rx_time,max_rx_time,min_rx_time); - } - } - - memcpy(&time0,&time2,sizeof(struct timespec)); - } - - if (loopback == 1 ) { - pthread_mutex_lock(&sync_eNB_mutex[i]); - sync_eNB_rx[i]--; - pthread_mutex_unlock(&sync_eNB_mutex[i]); - } - - rx_pos += spp_eth; - pck_rx++; - next_rx_pos=(rx_pos+spp_eth); - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX, 0 ); - /* - if (frame>50) { - pthread_mutex_lock(&sync_trx_mutex); - while (sync_trx) { - pthread_cond_wait(&sync_trx_cond,&sync_trx_mutex); - } - sync_trx=1; - LOG_D(RRH,"out of while send:%d %d\n",sync_trx,frame); - pthread_cond_signal(&sync_trx_cond); - pthread_mutex_unlock(&sync_trx_mutex); - }*/ - } // while - - subframe++; - s_cnt=0; - - /* wrap around rx buffer index */ - if (next_rx_pos >= samples_per_frame) - next_rx_pos -= samples_per_frame; - if (rx_pos >= samples_per_frame) - rx_pos -= samples_per_frame; - /* wrap around subframe number */ - if (subframe == 10 ) { - subframe = 0; - frame++; - } - - - } //while (eNB_exit==0) - return 0; -} - -/* Receive from eNB and transmit to RF */ - -void *rrh_eNB_tx_thread(void *arg) { - - struct timespec time0,time1,time2; - - rrh_module_t *dev = (rrh_module_t *)arg; - struct timespec time_req_1us, time_rem_1us; - ssize_t bytes_received; - int i; - //openair0_timestamp last_hw_counter=0; - unsigned int samples_per_frame=0,samples_per_subframe=0; - unsigned int spp_rf=0, spp_eth=0; - uint8_t loopback=0,measurements=0; - unsigned int subframe=0,frame=0; - unsigned int pck_tx=0; - -#ifdef DEADLINE_SCHEDULER - struct sched_attr attr; - unsigned int flags = 0; - - attr.size = sizeof(attr); - attr.sched_flags = 0; - attr.sched_nice = 0; - attr.sched_priority = 0; - - attr.sched_policy = SCHED_DEADLINE; - attr.sched_runtime = (0.8 * 100) * 10000; - attr.sched_deadline = (0.9 * 100) * 10000; - attr.sched_period = 1 * 1000000; - - if (sched_setattr(0, &attr, flags) < 0 ) { - perror("[SCHED] eNB TX thread: sched_setattr failed\n"); - exit(-1); - } -#endif - - time_req_1us.tv_sec = 1; - time_req_1us.tv_nsec = 0; - spp_eth = dev->eth_dev.openair0_cfg->samples_per_packet; - spp_rf = dev->devs->openair0_cfg->samples_per_packet; - samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame; - samples_per_subframe = (unsigned int)samples_per_frame/10; - tx_pos=0; - - loopback = dev->loopback; - measurements = dev->measurements; - - while (rrh_exit == 0) { - while (tx_pos < (1 + subframe)*samples_per_subframe) { - - //LOG_D(RRH,"bef lock read:%d %d\n",sync_trx,frame); - //pthread_mutex_lock(&sync_trx_mutex); - - //while (!sync_trx) { - //LOG_D(RRH,"in sync read:%d %d\n",sync_trx,frame); - //pthread_cond_wait(&sync_trx_cond,&sync_trx_mutex); - //} - //LOG_D(RRH,"out of while read:%d %d\n",sync_trx,frame); - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX, 1 ); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME, frame); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME, subframe ); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_PCK, pck_tx ); - - if (measurements == 1 ) clock_gettime(CLOCK_MONOTONIC,&time1); - for (i=0; ieth_dev.openair0_cfg->tx_num_channels; i++) tx_eNB[i] = (void*)&tx_buffer_eNB[i][tx_pos]; - - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TXCNT, tx_pos ); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 ); - - /* Read operation to ETHERNET device */ - if (( bytes_received = dev->eth_dev.trx_read_func(&dev->eth_dev, - ×tamp_tx, - tx_eNB, - spp_eth, - dev->eth_dev.openair0_cfg->tx_num_channels))<0) { - perror("RRH eNB : ETHERNET read"); - } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); - - if (dev->devs->type != NONE_DEV) { - LOG_D(RRH," tx_buffer_eNB[i][tx_pos]=%x t_buffer_eNB[i][tx_pos+1]=%x t_buffer_eNB[i][tx_pos+2]=%x \n",tx_buffer_eNB[0][tx_pos],tx_buffer_eNB[0][tx_pos+1],tx_buffer_eNB[0][tx_pos+2]); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_RF, 1 ); - /* Write operation to RF device (TX)*/ - if ( dev->devs->trx_write_func (dev->devs, - timestamp_tx, - tx_eNB, - spp_rf, - dev->devs->openair0_cfg->tx_num_channels, - 1)<0){ - perror("RRH eNB : USRP write"); - } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_RF, 0 ); - } - - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_TS, timestamp_tx&0xffffffff ); - - - //if (dev->devs->type == NONE_DEV) last_hw_counter=hw_counter; - - - if (loopback ==1 ) { - while (sync_eNB_rx[i]==0) - nanosleep(&time_req_1us,&time_rem_1us); - - pthread_mutex_lock(&sync_eNB_mutex[i]); - sync_eNB_rx[i]++; - pthread_mutex_unlock(&sync_eNB_mutex[i]); - } - - if (measurements == 1 ) { - clock_gettime(CLOCK_MONOTONIC,&time2); - memcpy(&time0,&time2,sizeof(struct timespec)); - } - - prev_tx_pos=tx_pos; - tx_pos += spp_eth; - pck_tx++; - - //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX, 0 ); - //sync_trx=0; - //pthread_cond_signal(&sync_trx_cond); - //pthread_mutex_unlock(&sync_trx_mutex); - } - - /* wrap around tx buffer index */ - if (tx_pos >= samples_per_frame) - tx_pos -= samples_per_frame; - /* wrap around subframe number */ - subframe++; - if (subframe == 10 ) { - subframe = 0; // the radio frame is complete, start over - frame++; - } - - } //while (eNB_exit==0) - return 0; -} - - -static void calc_rt_period_ns( openair0_config_t *openair0_cfg) { - - rt_period= (double)(openair0_cfg->samples_per_packet/(openair0_cfg->samples_per_frame/10.0)*1000000); - AssertFatal(rt_period > 0, "Invalid rt period !%u\n", rt_period); - LOG_I(RRH,"[eNB] Real time period is set to %u ns\n", rt_period); -} - - -static void check_dev_config( rrh_module_t *mod_enb) { - - AssertFatal( (mod_enb->devs->openair0_cfg->num_rb_dl==100 || mod_enb->devs->openair0_cfg->num_rb_dl==50 || mod_enb->devs->openair0_cfg->num_rb_dl==25 || mod_enb->devs->openair0_cfg->num_rb_dl==6) , "Invalid number of resource blocks! %d\n", mod_enb->devs->openair0_cfg->num_rb_dl); - AssertFatal( mod_enb->devs->openair0_cfg->samples_per_frame > 0 , "Invalid number of samples per frame! %d\n",mod_enb->devs->openair0_cfg->samples_per_frame); - AssertFatal( mod_enb->devs->openair0_cfg->sample_rate > 0.0, "Invalid sample rate! %f\n", mod_enb->devs->openair0_cfg->sample_rate); - AssertFatal( mod_enb->devs->openair0_cfg->samples_per_packet > 0 , "Invalid number of samples per packet! %d\n",mod_enb->devs->openair0_cfg->samples_per_packet); - AssertFatal( mod_enb->devs->openair0_cfg->rx_num_channels > 0 , "Invalid number of RX antennas! %d\n", mod_enb->devs->openair0_cfg->rx_num_channels); - AssertFatal( mod_enb->devs->openair0_cfg->tx_num_channels > 0 , "Invalid number of TX antennas! %d\n", mod_enb->devs->openair0_cfg->tx_num_channels); - AssertFatal( mod_enb->devs->openair0_cfg->rx_freq[0] > 0.0 ,"Invalid RX frequency! %f\n", mod_enb->devs->openair0_cfg->rx_freq[0]); - AssertFatal( mod_enb->devs->openair0_cfg->tx_freq[0] > 0.0 ,"Invalid TX frequency! %f\n", mod_enb->devs->openair0_cfg->tx_freq[0]); - AssertFatal( mod_enb->devs->openair0_cfg->rx_gain[0] > 0.0 ,"Invalid RX gain! %f\n", mod_enb->devs->openair0_cfg->rx_gain[0]); - AssertFatal( mod_enb->devs->openair0_cfg->tx_gain[0] > 0.0 ,"Invalid TX gain! %f\n", mod_enb->devs->openair0_cfg->tx_gain[0]); - AssertFatal( mod_enb->devs->openair0_cfg->rx_bw > 0.0 ,"Invalid RX bw! %f\n", mod_enb->devs->openair0_cfg->rx_bw); - AssertFatal( mod_enb->devs->openair0_cfg->tx_bw > 0.0 ,"Invalid RX bw! %f\n", mod_enb->devs->openair0_cfg->tx_bw); - AssertFatal( mod_enb->devs->openair0_cfg->autocal[0] > 0 , "Invalid auto calibration choice! %d\n", mod_enb->devs->openair0_cfg->autocal[0]); - - printf("\n---------------------RF device configuration parameters---------------------\n"); - - printf("\tMod_id=%d\n \tlog level=%d\n \tDL_RB=%d\n \tsamples_per_frame=%d\n \tsample_rate=%f\n \tsamples_per_packet=%d\n \ttx_sample_advance=%d\n \trx_num_channels=%d\n \ttx_num_channels=%d\n \trx_freq_0=%f\n \ttx_freq_0=%f\n \trx_freq_1=%f\n \ttx_freq_1=%f\n \trx_freq_2=%f\n \ttx_freq_2=%f\n \trx_freq_3=%f\n \ttx_freq_3=%f\n \trxg_mode=%d\n \trx_gain_0=%f\n \ttx_gain_0=%f\n \trx_gain_1=%f\n \ttx_gain_1=%f\n \trx_gain_2=%f\n \ttx_gain_2=%f\n \trx_gain_3=%f\n \ttx_gain_3=%f\n \trx_gain_offset_2=%f\n \ttx_gain_offset_3=%f\n \trx_bw=%f\n \ttx_bw=%f\n \tautocal=%d\n", - mod_enb->devs->openair0_cfg->Mod_id, - mod_enb->devs->openair0_cfg->log_level, - mod_enb->devs->openair0_cfg->num_rb_dl, - mod_enb->devs->openair0_cfg->samples_per_frame, - mod_enb->devs->openair0_cfg->sample_rate, - mod_enb->devs->openair0_cfg->samples_per_packet, - mod_enb->devs->openair0_cfg->tx_sample_advance, - mod_enb->devs->openair0_cfg->rx_num_channels, - mod_enb->devs->openair0_cfg->tx_num_channels, - mod_enb->devs->openair0_cfg->rx_freq[0], - mod_enb->devs->openair0_cfg->tx_freq[0], - mod_enb->devs->openair0_cfg->rx_freq[1], - mod_enb->devs->openair0_cfg->tx_freq[1], - mod_enb->devs->openair0_cfg->rx_freq[2], - mod_enb->devs->openair0_cfg->tx_freq[2], - mod_enb->devs->openair0_cfg->rx_freq[3], - mod_enb->devs->openair0_cfg->tx_freq[3], - mod_enb->devs->openair0_cfg->rxg_mode[0], - mod_enb->devs->openair0_cfg->tx_gain[0], - mod_enb->devs->openair0_cfg->tx_gain[0], - mod_enb->devs->openair0_cfg->rx_gain[1], - mod_enb->devs->openair0_cfg->tx_gain[1], - mod_enb->devs->openair0_cfg->rx_gain[2], - mod_enb->devs->openair0_cfg->tx_gain[2], - mod_enb->devs->openair0_cfg->rx_gain[3], - mod_enb->devs->openair0_cfg->tx_gain[3], - //mod_enb->devs->openair0_cfg->rx_gain_offset[0], - //mod_enb->devs->openair0_cfg->rx_gain_offset[1], - mod_enb->devs->openair0_cfg->rx_gain_offset[2], - mod_enb->devs->openair0_cfg->rx_gain_offset[3], - mod_enb->devs->openair0_cfg->rx_bw, - mod_enb->devs->openair0_cfg->tx_bw, - mod_enb->devs->openair0_cfg->autocal[0] - ); - - printf("----------------------------------------------------------------------------\n"); - - -} diff --git a/targets/RT/USER/rrh.c b/targets/RT/USER/rrh.c deleted file mode 100644 index 88bd3f644d..0000000000 --- a/targets/RT/USER/rrh.c +++ /dev/null @@ -1,1220 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/** ethernet_lib : API to stream I/Q samples over standard ethernet (RRH component) -* -* Authors: Raymond Knopp , Riadh Ghaddab -* -* Changelog: -* 06.10.2014: Initial version -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common_lib.h" - -#define BUF_LEN 4096+32 -#define RRH_eNB_PORT 50000 -#define RRH_eNB_DEST_IP "127.0.0.1" -#define RRH_UE_PORT 51000 -#define RRH_UE_DEST_IP "127.0.0.1" - -#define FRAME_MAX_SIZE 307200//76800 -#define DEFAULT_PERIOD_NS 133333//200000 - -#define START_CMD 1 -#define PRINTF_PERIOD 3750 - -typedef struct { - int eNB_port; - char eNB_dest_ip[20]; - int UE_port; - char UE_dest_ip[20]; - struct timespec time_req; -} rrh_desc_t; - -typedef struct { - int32_t nsamps; - int32_t antenna_index_eNB_rx; - int32_t antenna_index_eNB_tx; - int sockid_eNB; - struct sockaddr clientaddr; - socklen_t clientaddrlen; -} rrh_eNB_desc_t; - -typedef struct { - int32_t nsamps; - int32_t antenna_index_UE_rx; - int32_t antenna_index_UE_tx; - int sockid_UE; - struct sockaddr clientaddr; - socklen_t clientaddrlen; -} rrh_UE_desc_t; - -int rrh_exit=0; - -int32_t tx_buffer_eNB[4][(1+(sizeof(openair0_timestamp)>>2))+FRAME_MAX_SIZE],rx_buffer_eNB[4][(1+(sizeof(openair0_timestamp)>>2))+FRAME_MAX_SIZE]; -int32_t tx_buffer_UE[4][(1+(sizeof(openair0_timestamp)>>2))+FRAME_MAX_SIZE],rx_buffer_UE[4][(1+(sizeof(openair0_timestamp)>>2))+FRAME_MAX_SIZE]; -void *rrh_eNB_thread_status; -void *rrh_UE_thread_status; -int32_t counter_UE_rx[4]= {0,0,0,0}; -int32_t counter_UE_tx[4]= {0,0,0,0}; -int32_t counter_eNB_rx[4]= {0,0,0,0}; -int32_t counter_eNB_tx[4]= {0,0,0,0}; -int32_t overflow_rx_buffer_UE[4]= {0,0,0,0}; -int32_t overflow_rx_buffer_eNB[4]= {0,0,0,0}; -int32_t nsamps_eNB[4]= {0,0,0,0}; -int32_t nsamps_UE[4]= {0,0,0,0}; -int32_t UE_tx_started=0,eNB_tx_started=0, UE_rx_started=0,eNB_rx_started=0; -int32_t RT_FLAG=0, NRT_FLAG=1; -openair0_timestamp nrt_eNB_counter[4]= {0,0,0,0}; -openair0_timestamp nrt_UE_counter[4]= {0,0,0,0}; - -openair0_timestamp timestamp_eNB_tx[4],timestamp_eNB_rx[4]= {0,0,0,0}; -openair0_timestamp timestamp_UE_tx[4],timestamp_UE_rx[4]= {0,0,0,0}; -openair0_timestamp hw_counter=0; - -pthread_cond_t sync_UE_cond[4]; -pthread_mutex_t sync_UE_mutex[4]; -pthread_cond_t sync_eNB_cond[4]; -pthread_mutex_t sync_eNB_mutex[4]; -pthread_mutex_t timer_mutex; - -int sync_UE_rx[4]= {-1,-1,-1,-1}; -int sync_eNB_rx[4]= {-1,-1,-1,-1}; - -//functions prototype -void timer_signal_handler(int); -void *timer_proc(void *); -void *rrh_proc_eNB_thread(); -void *rrh_proc_UE_thread(); -void *rrh_UE_thread(void *); -void *rrh_UE_rx_thread(void *); -void *rrh_UE_tx_thread(void *); -void *rrh_eNB_thread(void *); -void *rrh_eNB_rx_thread(void *); -void *rrh_eNB_tx_thread(void *); - -void timer_signal_handler(int sig) -{ - - if (sig == SIGALRM) { - pthread_mutex_lock(&timer_mutex); - hw_counter ++; - //printf("[RRH] : hw_counter : %d\n",(int)hw_counter); - pthread_mutex_unlock(&timer_mutex); - } - - -} - - -void *timer_proc(void *arg) -{ - timer_t timerid; // timer ID for timer - //struct sigevent event; // event to deliver - struct itimerspec *timer = (struct itimerspec*)arg; // the timer data structure - struct itimerspec *old_value; - - - //printf("Starting the timer\n"); - if (timer_create (CLOCK_REALTIME, NULL, &timerid) == -1) { - fprintf (stderr, "couldn't create a timer\n"); - perror (NULL); - exit (EXIT_FAILURE); - } - - signal(SIGALRM, timer_signal_handler); - // and start it! - timer_settime (timerid, 0, timer, old_value); - - while (!rrh_exit) { - sleep(1); - } - - timer_delete(timerid); - return (0); - - -} - - -void *rrh_proc_eNB_thread() -{ - - //rrh_desc_t *rrh_desc = (rrh_desc_t *)arg; - int antenna_index,i; - openair0_timestamp truncated_timestamp, truncated_timestamp_final, last_hw_counter=0; - struct timespec time_req, time_rem; - int16_t *rxp,*txp; - - time_req.tv_sec = 0; - time_req.tv_nsec = 1000; - - while (rrh_exit==0) { - //wait until some data has been copied - for (antenna_index=0; antenna_index<4; antenna_index++) { - if (sync_eNB_rx[antenna_index]==0) { - if (!eNB_tx_started) { - eNB_tx_started=1; // set this flag to 1 to indicate that eNB started - - if (RT_FLAG==1) { - last_hw_counter=hw_counter; - } - } else { - if (RT_FLAG==1) { - if (hw_counter > last_hw_counter+1) { - printf("L"); - // goto end_copy_eNB; - } else { - //printf("hw_counter : %llu, last_hw_counter : %llu\n",hw_counter,last_hw_counter); - while (hw_counter < last_hw_counter+1) - nanosleep(&time_req,&time_rem); - } - } - } - - truncated_timestamp = timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE); - truncated_timestamp_final = (timestamp_eNB_tx[antenna_index]+nsamps_eNB[antenna_index])%FRAME_MAX_SIZE; - - if ((truncated_timestamp + nsamps_eNB[antenna_index]) > FRAME_MAX_SIZE) { - if ((timestamp_UE_rx[antenna_index]%FRAME_MAX_SIZE < nsamps_eNB[antenna_index]) && (UE_rx_started==1)) { - overflow_rx_buffer_UE[antenna_index]++; - printf("UE Overflow[%d] : %d, timestamp : %d\n",antenna_index,overflow_rx_buffer_UE[antenna_index],(int)truncated_timestamp); - - if (NRT_FLAG==1) { - while ((timestamp_UE_rx[antenna_index]%FRAME_MAX_SIZE) < nsamps_eNB[antenna_index]) - nanosleep(&time_req,&time_rem); - } - } - - rxp = (int16_t*)&rx_buffer_UE[antenna_index][truncated_timestamp+(sizeof(openair0_timestamp)>>2)]; - txp = (int16_t*)&tx_buffer_eNB[antenna_index][truncated_timestamp+(sizeof(openair0_timestamp)>>2)]; - - for (i=0; i<(FRAME_MAX_SIZE<<1)-(truncated_timestamp<<1); i++) { - rxp[i] = txp[i]>>6; - } - - rxp = (int16_t*)&rx_buffer_UE[antenna_index][(sizeof(openair0_timestamp)>>2)]; - txp = (int16_t*)&tx_buffer_eNB[antenna_index][0]; - - for (i=0; i>6; - } - - /* memcpy(&rx_buffer_UE[antenna_index][truncated_timestamp + (sizeof(openair0_timestamp)>>2)],&tx_buffer_eNB[antenna_index][truncated_timestamp],(FRAME_MAX_SIZE<<2)-(truncated_timestamp<<2)); - memcpy(&rx_buffer_UE[antenna_index][(sizeof(openair0_timestamp)>>2)],&tx_buffer_eNB[antenna_index][0],(nsamps_eNB[antenna_index]<<2)-(FRAME_MAX_SIZE<<2)+(truncated_timestamp<<2));*/ - } else { - if (((truncated_timestamp < (timestamp_UE_rx[antenna_index]%FRAME_MAX_SIZE)) && (truncated_timestamp_final > (timestamp_UE_rx[antenna_index]%FRAME_MAX_SIZE))) && (UE_rx_started==1)) { - overflow_rx_buffer_UE[antenna_index]++; - printf("UE Overflow[%d] : %d, timestamp : %d\n",antenna_index,overflow_rx_buffer_UE[antenna_index],(int)truncated_timestamp); - - if (NRT_FLAG==1) { - while (truncated_timestamp_final > timestamp_UE_rx[antenna_index]%FRAME_MAX_SIZE) - nanosleep(&time_req,&time_rem); - } - } - - rxp = (int16_t*)&rx_buffer_UE[antenna_index][truncated_timestamp+(sizeof(openair0_timestamp))]; - txp = (int16_t*)&tx_buffer_eNB[antenna_index][truncated_timestamp]; - - for (i=0; i<(nsamps_eNB[antenna_index]); i++) { - rxp[i] =txp[i]>>6; - } - - /* - memcpy(&rx_buffer_UE[antenna_index][truncated_timestamp + (sizeof(openair0_timestamp)>>2)],&tx_buffer_eNB[antenna_index][truncated_timestamp],(nsamps_eNB[antenna_index]<<2));*/ - } - - - // end_copy_eNB : - last_hw_counter=hw_counter; - pthread_mutex_lock(&sync_eNB_mutex[antenna_index]); - sync_eNB_rx[antenna_index]--; - pthread_mutex_unlock(&sync_eNB_mutex[antenna_index]); - - } - } - - } - - return(0); -} - -void *rrh_proc_UE_thread() -{ - - //rrh_desc_t *rrh_desc = (rrh_desc_t *)arg; - int antenna_index,i; - openair0_timestamp truncated_timestamp, truncated_timestamp_final, last_hw_counter=0; - struct timespec time_req, time_rem; - int16_t *txp,*rxp; - - time_req.tv_sec = 0; - time_req.tv_nsec = 1000; - - - while (rrh_exit==0) { - //wait until some data has been copied - for (antenna_index=0; antenna_index<4; antenna_index++) { - if (sync_UE_rx[antenna_index]==0) { - if (!UE_tx_started) { - UE_tx_started=1; //Set this flag to 1 to indicate that a UE started retrieving data - - if (RT_FLAG==1) { - last_hw_counter=hw_counter; - } - } else { - if (RT_FLAG==1) { - if (hw_counter > last_hw_counter+1) { - printf("L1"); - // goto end_copy_UE; - } else { - while (hw_counter < last_hw_counter+1) - nanosleep(&time_req,&time_rem); - } - } - } - - truncated_timestamp = timestamp_UE_tx[antenna_index]%(FRAME_MAX_SIZE); - truncated_timestamp_final = (timestamp_UE_tx[antenna_index]+nsamps_UE[antenna_index])%FRAME_MAX_SIZE; - - if ((truncated_timestamp + nsamps_UE[antenna_index]) > FRAME_MAX_SIZE) { - if ((timestamp_eNB_rx[antenna_index]%FRAME_MAX_SIZE < nsamps_UE[antenna_index]) && (eNB_rx_started==1)) { - overflow_rx_buffer_eNB[antenna_index]++; - printf("eNB Overflow[%d] : %d, timestamp : %d\n",antenna_index,overflow_rx_buffer_eNB[antenna_index],(int)truncated_timestamp); - - if (NRT_FLAG==1) { - while ((timestamp_eNB_rx[antenna_index]%FRAME_MAX_SIZE) < nsamps_UE[antenna_index]) - nanosleep(&time_req,&time_rem); - } - } - - rxp = (int16_t*)&rx_buffer_eNB[antenna_index][truncated_timestamp+(sizeof(openair0_timestamp)>>2)]; - txp = (int16_t*)&tx_buffer_UE[antenna_index][truncated_timestamp+(sizeof(openair0_timestamp)>>2)]; - - for (i=0; i<(FRAME_MAX_SIZE<<1)-(truncated_timestamp<<1); i++) { - rxp[i] = txp[i]>>6; - } - - rxp = (int16_t*)&rx_buffer_eNB[antenna_index][(sizeof(openair0_timestamp)>>2)]; - txp = (int16_t*)&tx_buffer_UE[antenna_index][0]; - - for (i=0; i>6; - } - - /* - memcpy(&rx_buffer_eNB[antenna_index][truncated_timestamp + (sizeof(openair0_timestamp)>>2)],&tx_buffer_UE[antenna_index][truncated_timestamp],(FRAME_MAX_SIZE<<2)-(truncated_timestamp<<2)); - memcpy(&rx_buffer_eNB[antenna_index][(sizeof(openair0_timestamp)>>2)],&tx_buffer_UE[antenna_index][0],(nsamps_UE[antenna_index]<<2)-(FRAME_MAX_SIZE<<2)+(truncated_timestamp<<2));*/ - - } else { - if (((truncated_timestamp < (timestamp_eNB_rx[antenna_index]%FRAME_MAX_SIZE)) && (truncated_timestamp_final > (timestamp_eNB_rx[antenna_index]%FRAME_MAX_SIZE))) && (eNB_rx_started==1)) { - overflow_rx_buffer_eNB[antenna_index]++; - printf("eNB Overflow[%d] : %d, timestamp : %d\n",antenna_index,overflow_rx_buffer_eNB[antenna_index],(int)truncated_timestamp); - - if (NRT_FLAG==1) { - while (truncated_timestamp_final > timestamp_eNB_rx[antenna_index]%FRAME_MAX_SIZE) - nanosleep(&time_req,&time_rem); - } - } - - rxp = (int16_t*)&rx_buffer_eNB[antenna_index][truncated_timestamp+(sizeof(openair0_timestamp))]; - txp = (int16_t*)&tx_buffer_UE[antenna_index][truncated_timestamp]; - - for (i=0; i<(nsamps_eNB[antenna_index]); i++) { - rxp[i] =txp[i]>>6; - } - - /* memcpy(&rx_buffer_eNB[antenna_index][truncated_timestamp+ (sizeof(openair0_timestamp)>>2)],&tx_buffer_UE[antenna_index][truncated_timestamp],(nsamps_UE[antenna_index]<<2));*/ - } - - //end_copy_UE : - last_hw_counter=hw_counter; - pthread_mutex_lock(&sync_UE_mutex[antenna_index]); - sync_UE_rx[antenna_index]--; - pthread_mutex_unlock(&sync_UE_mutex[antenna_index]); - - } - } - - } - - return(0); -} - - -void *rrh_UE_rx_thread(void *arg) -{ - - struct sockaddr clientaddr; - socklen_t clientaddrlen; - rrh_UE_desc_t *rrh_UE_rx_desc = (rrh_UE_desc_t *)arg; - struct timespec time0,time1,time2; - struct timespec time_req_1us, time_rem_1us; - ssize_t bytes_sent; - int antenna_index, nsamps; - int trace_cnt=0; - int sockid; - char str[INET_ADDRSTRLEN]; - unsigned long long max_rx_time=0, min_rx_time=133333, total_rx_time=0, average_rx_time=133333, s_period=0, trial=0; - - openair0_timestamp temp, last_hw_counter=0; - - antenna_index = rrh_UE_rx_desc->antenna_index_UE_rx; - nsamps = rrh_UE_rx_desc->nsamps; - sockid = rrh_UE_rx_desc->sockid_UE; - - - bzero((void*)&clientaddr,sizeof(struct sockaddr)); - clientaddrlen = sizeof(struct sockaddr); - //printf("Waiting for eNB ...\n"); - //printf("[RRH eNB RX thread] received parameters : nsamps : %d, antenna_index : %d\n",nsamps,antenna_index); - clientaddr = rrh_UE_rx_desc->clientaddr; - clientaddrlen = rrh_UE_rx_desc->clientaddrlen; - - inet_ntop(AF_INET, &(((struct sockaddr_in*)&clientaddr)->sin_addr), str, INET_ADDRSTRLEN); - printf("Received UE RX request for antenna %d, nsamps %d (from %s:%d)\n",antenna_index,nsamps,str, - ntohs(((struct sockaddr_in*)&clientaddr)->sin_port)); - - while (rrh_exit == 0) { - if (!UE_rx_started) { - UE_rx_started=1; //Set this flag to 1 to indicate that a UE started retrieving data - - if (RT_FLAG==1) { - last_hw_counter=hw_counter; - } - } else { - if (RT_FLAG==1) { - if (hw_counter > last_hw_counter+1) { - printf("L1"); - // goto end_copy_UE; - } else { - while (hw_counter < last_hw_counter+1) - nanosleep(&time_req_1us,&time_rem_1us); - } - } - } - - clock_gettime(CLOCK_MONOTONIC,&time1); - - // send return - temp=*(openair0_timestamp*)&rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE)]; - *(openair0_timestamp*)&rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE)]=timestamp_UE_rx[antenna_index]; - - if ((timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE)+nsamps) > FRAME_MAX_SIZE) { // Wrap around if nsamps exceeds the buffer limit - if (((timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE)) < ((timestamp_UE_rx[antenna_index]+nsamps)%(FRAME_MAX_SIZE))) && (eNB_tx_started==1)) { - printf("UE underflow wraparound timestamp_UE_rx : %d, timestamp_eNB_tx : %d\n",(int)(timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE)),(int)(timestamp_eNB_tx[antenna_index]%FRAME_MAX_SIZE)); - - if (NRT_FLAG==1) { - while ((timestamp_eNB_tx[antenna_index]%FRAME_MAX_SIZE) < ((timestamp_UE_rx[antenna_index]+nsamps)%(FRAME_MAX_SIZE))) - nanosleep(&time_req_1us,&time_rem_1us); - } - } - - if ((bytes_sent = sendto(sockid, - &rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE)], - ((FRAME_MAX_SIZE)<<2) - ((timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE))<<2) + sizeof(openair0_timestamp), - 0, - (struct sockaddr*)&clientaddr, - sizeof(struct sockaddr)))<0) - perror("RRH UE : sendto for RX"); - - if ((bytes_sent = sendto(sockid, - &rx_buffer_UE[antenna_index][0], - (nsamps<<2) - ((FRAME_MAX_SIZE)<<2) + ((timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE))<<2), - 0, - (struct sockaddr*)&clientaddr, - sizeof(struct sockaddr)))<0) - perror("RRH UE : sendto for RX"); - } else { - if (((timestamp_UE_rx[antenna_index]%FRAME_MAX_SIZE)< timestamp_eNB_tx[antenna_index]%FRAME_MAX_SIZE) - && (((timestamp_UE_rx[antenna_index]+nsamps)%FRAME_MAX_SIZE) > (timestamp_eNB_tx[antenna_index]%FRAME_MAX_SIZE)) && (eNB_tx_started==1) ) { - printf("UE underflow timestamp_UE_rx : %d, timestamp_eNB_tx : %d\n",(int)(timestamp_UE_rx[antenna_index]%FRAME_MAX_SIZE),(int)(timestamp_eNB_tx[antenna_index]%FRAME_MAX_SIZE)); - - if (NRT_FLAG==1) { - while (((timestamp_UE_rx[antenna_index]+nsamps)%FRAME_MAX_SIZE) > (timestamp_eNB_tx[antenna_index]%FRAME_MAX_SIZE)) { - nanosleep(&time_req_1us,&time_rem_1us); - } - } - } - - - if ((bytes_sent = sendto(sockid, - &rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE)], - (nsamps<<2)+sizeof(openair0_timestamp), - 0, - (struct sockaddr*)&clientaddr, - sizeof(struct sockaddr)))<0) - perror("RRH UE thread: sendto for RX"); - } - - //printf("bytes_sent %d(timestamp_UE_rx[%d] %d)\n",(int)bytes_sent,antenna_index,(int)timestamp_UE_rx[antenna_index]); - *(openair0_timestamp*)&rx_buffer_UE[antenna_index][timestamp_UE_rx[antenna_index]%(FRAME_MAX_SIZE)]=temp; - timestamp_UE_rx[antenna_index]+=nsamps; - last_hw_counter=hw_counter; - - clock_gettime(CLOCK_MONOTONIC,&time2); - - if (trace_cnt++ > 10) { - total_rx_time = (unsigned int)(time2.tv_nsec - time0.tv_nsec); - - if (total_rx_time < 0) total_rx_time=1000000000-total_rx_time; - - if ((total_rx_time > 0) && (total_rx_time < 1000000000)) { - trial++; - - if (total_rx_time < min_rx_time) - min_rx_time = total_rx_time; - - if (total_rx_time > max_rx_time) - max_rx_time = total_rx_time; - - average_rx_time = (long long unsigned int)((average_rx_time*trial)+total_rx_time)/(trial+1); - } - - if (s_period++ == PRINTF_PERIOD) { - s_period=0; - printf("Average UE RX time : %lu\tMax RX time : %lu\tMin RX time : %lu\n",average_rx_time,max_rx_time,min_rx_time); - - } - - //printf("RX: t1 %llu (time from last send), t2 %llu (sendto of %lu bytes) total time : %llu\n",(long long unsigned int)(time1.tv_nsec - time0.tv_nsec), (long long unsigned int)(time2.tv_nsec - time1.tv_nsec), - // (nsamps<<2)+sizeof(openair0_timestamp),(long long unsigned int)(time2.tv_nsec - time0.tv_nsec)); - - } - - memcpy(&time0,&time2,sizeof(struct timespec)); - - - } //while (rrh_exit==0) - - return(0); - -} - - -void *rrh_UE_tx_thread(void *arg) -{ - struct sockaddr clientaddr; - socklen_t clientaddrlen; - struct timespec time0a,time0,time1,time2; - rrh_UE_desc_t *rrh_UE_tx_desc = (rrh_UE_desc_t *)arg; - // struct timespec time_rem; - struct timespec time_req_1us, time_rem_1us; - ssize_t bytes_received; - int antenna_index, nsamps; - int8_t buf[BUF_LEN]; - int trace_cnt=0; - int sockid; - - bzero((void*)&clientaddr,sizeof(struct sockaddr)); - clientaddrlen = sizeof(struct sockaddr); - - antenna_index = rrh_UE_tx_desc->antenna_index_UE_tx; - nsamps = rrh_UE_tx_desc->nsamps; - sockid = rrh_UE_tx_desc->sockid_UE; - - while (rrh_exit == 0) { - - clock_gettime(CLOCK_MONOTONIC,&time0a); - - bytes_received = recvfrom(sockid,buf,BUF_LEN,0,&clientaddr,&clientaddrlen); - timestamp_eNB_tx[antenna_index] = *(openair0_timestamp*)(buf+4); - - clock_gettime(CLOCK_MONOTONIC,&time1); - - if (NRT_FLAG==1) { - nrt_UE_counter[antenna_index]++; - } - - //printf("Received UE TX request for antenna %d, nsamps %d, timestamp %d bytes_received %d\n",antenna_index,nsamps,(int)timestamp_UE_tx[antenna_index],(int)bytes_received); - if ((timestamp_UE_tx[antenna_index]%(FRAME_MAX_SIZE)+nsamps) > FRAME_MAX_SIZE) { // Wrap around if nsamps exceeds the buffer limit - memcpy(&tx_buffer_UE[antenna_index][timestamp_UE_tx[antenna_index]%(FRAME_MAX_SIZE)],buf+sizeof(openair0_timestamp)+2*sizeof(int16_t), - (FRAME_MAX_SIZE<<2)-((timestamp_UE_tx[antenna_index]%(FRAME_MAX_SIZE))<<2)); - memcpy(&tx_buffer_UE[antenna_index][0],buf+sizeof(openair0_timestamp)+2*sizeof(int16_t)+(FRAME_MAX_SIZE*4)-((timestamp_UE_tx[antenna_index]%(FRAME_MAX_SIZE))<<2), - (nsamps<<2)-((FRAME_MAX_SIZE-(timestamp_UE_tx[antenna_index]%(FRAME_MAX_SIZE)))<<2)); - //printf("Received UE TX samples for antenna %d, nsamps %d (%d)\n",antenna_index,nsamps,(int)(bytes_received>>2)); - } else { - memcpy(&tx_buffer_UE[antenna_index][timestamp_UE_tx[antenna_index]%(FRAME_MAX_SIZE)],buf+sizeof(openair0_timestamp)+2*sizeof(int16_t),(nsamps<<2)); - } - - //printf("Received UE TX samples for antenna %d, nsamps %d (%d)\n",antenna_index,nsamps,(int)(bytes_received>>2)); - - while (sync_UE_rx[antenna_index]==0) - nanosleep(&time_req_1us,&time_rem_1us); - - pthread_mutex_lock(&sync_UE_mutex[antenna_index]); - sync_UE_rx[antenna_index]++; - - if (!sync_UE_rx[antenna_index]) { - counter_UE_tx[antenna_index]=(counter_UE_tx[antenna_index]+nsamps)%FRAME_MAX_SIZE; - nsamps_UE[antenna_index]=nsamps; - } else { - printf("rrh_eNB_proc thread is busy, will exit\n"); - exit(-1); - } - - pthread_mutex_unlock(&sync_UE_mutex[antenna_index]); - - clock_gettime(CLOCK_MONOTONIC,&time2); - - memcpy(&time0,&time2,sizeof(struct timespec)); - - } - - return(0); - -} - - - -void *rrh_UE_thread(void *arg) -{ - - int sockid=-1; - struct sockaddr_in serveraddr; - struct sockaddr clientaddr; - socklen_t clientaddrlen; - rrh_desc_t *rrh_desc = (rrh_desc_t *)arg; - char str[INET_ADDRSTRLEN]; - //int8_t msg_header[4+sizeof(openair0_timestamp)]; - int8_t buf[BUF_LEN]; - int16_t cmd; //,nsamps,antenna_index; - ssize_t bytes_received; - // struct timespec time_rem; - // ssize_t bytes_sent; - // openair0_timestamp temp; - // openair0_timestamp last_hw_counter=0; - struct timespec time_req_1us, time_rem_1us; - - rrh_UE_desc_t rrh_UE_desc; - pthread_t UE_rx_thread, UE_tx_thread; - pthread_attr_t attr_UE_rx, attr_UE_tx; - struct sched_param sched_param_UE_rx, sched_param_UE_tx; - int error_code_UE_rx, error_code_UE_tx; - - time_req_1us.tv_sec = 0; - time_req_1us.tv_nsec = 1000; - - while (rrh_exit==0) { - - - sockid=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); - - if (sockid==-1) { - perror("Cannot create UE socket: "); - rrh_exit=1; - } - - - bzero((char *)&serveraddr,sizeof(serveraddr)); - serveraddr.sin_family=AF_INET; - serveraddr.sin_port=htons(rrh_desc->UE_port); - inet_pton(AF_INET,rrh_desc->UE_dest_ip,&serveraddr.sin_addr.s_addr); - - inet_ntop(AF_INET, &(serveraddr.sin_addr), str, INET_ADDRSTRLEN); - printf("Binding to UE socket for %s:%d\n",str,ntohs(serveraddr.sin_port)); - - if (bind(sockid,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0) { - perror("Cannot bind to UE socket: "); - rrh_exit = 1; - } - - // now wait for commands from eNB - - // get header info - bzero((void*)&clientaddr,sizeof(struct sockaddr)); - clientaddrlen = sizeof(struct sockaddr); - //printf("Waiting for UE ...\n"); - - bytes_received = recvfrom(sockid,buf,BUF_LEN,0,&clientaddr,&clientaddrlen); - cmd = buf[0]; - - rrh_UE_desc.antenna_index_UE_rx = cmd>>1; - rrh_UE_desc.antenna_index_UE_tx = cmd>>1; - //rrh_eNB_desc.timestamp_eNB_tx[rrh_eNB_desc.antenna_index_eNB_tx] = *(openair0_timestamp*)(buf+4); //we don't need timestamp when receiving the first command - rrh_UE_desc.nsamps = *(int16_t *)(buf+2); - rrh_UE_desc.sockid_UE = sockid; - rrh_UE_desc.clientaddr = clientaddr; - rrh_UE_desc.clientaddrlen = clientaddrlen; - - cmd = cmd&1; - inet_ntop(AF_INET, &(((struct sockaddr_in*)&clientaddr)->sin_addr), str, INET_ADDRSTRLEN); - - if (cmd==START_CMD) { - - pthread_attr_init(&attr_UE_rx); - pthread_attr_init(&attr_UE_tx); - sched_param_UE_rx.sched_priority = sched_get_priority_max(SCHED_FIFO); - sched_param_UE_tx.sched_priority = sched_get_priority_max(SCHED_FIFO); - pthread_attr_setschedparam(&attr_UE_rx,&sched_param_UE_rx); - pthread_attr_setschedparam(&attr_UE_tx,&sched_param_UE_tx); - pthread_attr_setschedpolicy(&attr_UE_rx,SCHED_FIFO); - pthread_attr_setschedpolicy(&attr_UE_tx,SCHED_FIFO); - - error_code_UE_rx = pthread_create(&UE_rx_thread, &attr_UE_rx, rrh_UE_rx_thread, (void *)&rrh_UE_desc); - error_code_UE_tx = pthread_create(&UE_tx_thread, &attr_UE_tx, rrh_UE_tx_thread, (void *)&rrh_UE_desc); - - if (error_code_UE_rx) { - printf("Error while creating UE RX thread\n"); - exit(-1); - } - - if (error_code_UE_tx) { - printf("Error while creating UE TX thread\n"); - exit(-1); - } - - while (rrh_exit==0) - sleep(1); - } - } - - close(sockid); - - rrh_UE_thread_status = 0; - pthread_exit(&rrh_UE_thread_status); - - return(0); -} - - - -void *rrh_eNB_rx_thread(void *arg) -{ - - struct sockaddr clientaddr; - socklen_t clientaddrlen; - rrh_eNB_desc_t *rrh_eNB_rx_desc = (rrh_eNB_desc_t *)arg; - struct timespec time0,time1,time2; - struct timespec time_req_1us, time_rem_1us; - ssize_t bytes_sent; - int antenna_index, nsamps; - int trace_cnt=0; - int sockid; - char str[INET_ADDRSTRLEN]; - unsigned long long max_rx_time=0, min_rx_time=133333, total_rx_time=0, average_rx_time=133333, s_period=0, trial=0; - - openair0_timestamp temp, last_hw_counter=0; - - antenna_index = rrh_eNB_rx_desc->antenna_index_eNB_rx; - nsamps = rrh_eNB_rx_desc->nsamps; - sockid = rrh_eNB_rx_desc->sockid_eNB; - - - bzero((void*)&clientaddr,sizeof(struct sockaddr)); - clientaddrlen = sizeof(struct sockaddr); - //printf("Waiting for eNB ...\n"); - //printf("[RRH eNB RX thread] received parameters : nsamps : %d, antenna_index : %d\n",nsamps,antenna_index); - clientaddr = rrh_eNB_rx_desc->clientaddr; - clientaddrlen = rrh_eNB_rx_desc->clientaddrlen; - - inet_ntop(AF_INET, &(((struct sockaddr_in*)&clientaddr)->sin_addr), str, INET_ADDRSTRLEN); - printf("Received eNB RX request for antenna %d, nsamps %d (from %s:%d)\n",antenna_index,nsamps,str, - ntohs(((struct sockaddr_in*)&clientaddr)->sin_port)); - - while (rrh_exit == 0) { - //printf("Received eNB RX request for antenna %d, nsamps %d (from %s:%d)\n",antenna_index,nsamps,str, - // ntohs(((struct sockaddr_in*)&clientaddr)->sin_port)); - - if (!eNB_rx_started) { - eNB_rx_started=1; // set this flag to 1 to indicate that eNB started - - if (RT_FLAG==1) { - last_hw_counter=hw_counter; - } - } else { - if (RT_FLAG==1) { - if (hw_counter > last_hw_counter+1) { - printf("L"); - // goto end_copy_eNB; - } else { - while (hw_counter < last_hw_counter+1) - nanosleep(&time_req_1us,&time_rem_1us); - } - } - } - - clock_gettime(CLOCK_MONOTONIC,&time1); - - // send return - temp=*(openair0_timestamp*)&rx_buffer_eNB[antenna_index][timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE)]; - *(openair0_timestamp*)&rx_buffer_eNB[antenna_index][timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE)]=timestamp_eNB_rx[antenna_index]; - - if ((timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE)+nsamps) > FRAME_MAX_SIZE) { // Wrap around if nsamps exceeds the buffer limit - if ((timestamp_UE_tx[antenna_index]%FRAME_MAX_SIZE < ((timestamp_eNB_rx[antenna_index]+nsamps)%FRAME_MAX_SIZE)) && (UE_tx_started==1)) { - printf("eNB underflow\n"); - - if (NRT_FLAG==1) { - while ((timestamp_UE_tx[antenna_index]%FRAME_MAX_SIZE) < nsamps) - nanosleep(&time_req_1us,&time_rem_1us); - } - } - - - if ((bytes_sent = sendto(sockid, - &rx_buffer_eNB[antenna_index][timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE)], - ((FRAME_MAX_SIZE)<<2) - ((timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE))<<2) + sizeof(openair0_timestamp), - 0, - (struct sockaddr*)&clientaddr, - sizeof(struct sockaddr)))<0) - perror("RRH eNB : sendto for RX"); - - if ((bytes_sent = sendto(sockid, - &rx_buffer_eNB[antenna_index][0], - (nsamps<<2) - ((FRAME_MAX_SIZE)<<2) + ((timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE))<<2), - 0, - (struct sockaddr*)&clientaddr, - sizeof(struct sockaddr)))<0) - perror("RRH eNB : sendto for RX"); - } else { - if (((timestamp_eNB_rx[antenna_index]%FRAME_MAX_SIZE)< timestamp_UE_tx[antenna_index]%FRAME_MAX_SIZE) - && (((timestamp_eNB_rx[antenna_index]+nsamps)%FRAME_MAX_SIZE) > (timestamp_UE_tx[antenna_index]%FRAME_MAX_SIZE)) && (UE_tx_started==1)) { - printf("eNB underflow\n"); - - if (NRT_FLAG==1) { - while (((timestamp_eNB_rx[antenna_index]+nsamps)%FRAME_MAX_SIZE) > (timestamp_UE_tx[antenna_index]%FRAME_MAX_SIZE)) - nanosleep(&time_req_1us,&time_rem_1us); - } - } - - if ((bytes_sent = sendto(sockid, - &rx_buffer_eNB[antenna_index][timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE)], - (nsamps<<2)+sizeof(openair0_timestamp), - 0, - (struct sockaddr*)&clientaddr, - sizeof(struct sockaddr)))<0) - perror("RRH eNB : sendto for RX"); - - } - - //printf("bytes_sent %d(timestamp_eNB_rx[%d] %d)\n",(int)bytes_sent,antenna_index,(int)timestamp_eNB_rx[antenna_index]); - - - *(openair0_timestamp*)&rx_buffer_eNB[antenna_index][timestamp_eNB_rx[antenna_index]%(FRAME_MAX_SIZE)]=temp; - timestamp_eNB_rx[antenna_index]+=nsamps; - last_hw_counter=hw_counter; - - clock_gettime(CLOCK_MONOTONIC,&time2); - - if (trace_cnt++ > 10) { - total_rx_time = (unsigned int)(time2.tv_nsec - time0.tv_nsec); - - if (total_rx_time < 0) total_rx_time=1000000000-total_rx_time; - - if ((total_rx_time > 0) && (total_rx_time < 1000000000)) { - trial++; - - if (total_rx_time < min_rx_time) - min_rx_time = total_rx_time; - - if (total_rx_time > max_rx_time) - max_rx_time = total_rx_time; - - average_rx_time = (long long unsigned int)((average_rx_time*trial)+total_rx_time)/(trial+1); - } - - if (s_period++ == PRINTF_PERIOD) { - s_period=0; - printf("Average eNB RX time : %lu\tMax RX time : %lu\tMin RX time : %lu\n",average_rx_time,max_rx_time,min_rx_time); - - } - - //printf("RX: t1 %llu (time from last send), t2 %llu (sendto of %lu bytes) total time : %llu\n",(long long unsigned int)(time1.tv_nsec - time0.tv_nsec), (long long unsigned int)(time2.tv_nsec - time1.tv_nsec), - // (nsamps<<2)+sizeof(openair0_timestamp),(long long unsigned int)(time2.tv_nsec - time0.tv_nsec)); - - } - - memcpy(&time0,&time2,sizeof(struct timespec)); - - - } //while (rrh_exit==0) - - return(0); - -} - - -void *rrh_eNB_tx_thread(void *arg) -{ - - struct sockaddr clientaddr; - socklen_t clientaddrlen; - struct timespec time0a,time0,time1,time2; - rrh_eNB_desc_t *rrh_eNB_tx_desc = (rrh_eNB_desc_t *)arg; - // struct timespec time_rem; - struct timespec time_req_1us, time_rem_1us; - ssize_t bytes_received; - int antenna_index, nsamps; - int8_t buf[BUF_LEN]; - int trace_cnt=0; - int sockid; - - bzero((void*)&clientaddr,sizeof(struct sockaddr)); - clientaddrlen = sizeof(struct sockaddr); - //printf("Waiting for eNB ...\n"); - - antenna_index = rrh_eNB_tx_desc->antenna_index_eNB_tx; - nsamps = rrh_eNB_tx_desc->nsamps; - sockid = rrh_eNB_tx_desc->sockid_eNB; - - while (rrh_exit == 0) { - - clock_gettime(CLOCK_MONOTONIC,&time0a); - - bytes_received = recvfrom(sockid,buf,BUF_LEN,0,&clientaddr,&clientaddrlen); - timestamp_eNB_tx[antenna_index] = *(openair0_timestamp*)(buf+4); - - clock_gettime(CLOCK_MONOTONIC,&time1); - - if (NRT_FLAG==1) { - nrt_eNB_counter[antenna_index]++; - } - - //printf("Received eNB TX request for antenna %d, nsamps %d, timestamp %d bytes_received %d\n",antenna_index,nsamps,(int)timestamp_eNB_tx[antenna_index],(int)bytes_received); - - if ((timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE)+nsamps) > FRAME_MAX_SIZE) { // Wrap around if nsamps exceeds the buffer limit - memcpy(&tx_buffer_eNB[antenna_index][timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE)],buf+sizeof(openair0_timestamp)+2*sizeof(int16_t), - ((FRAME_MAX_SIZE)<<2)-((timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE))<<2)); - //printf("Done first part size : %d\n",(int32_t)(((FRAME_MAX_SIZE)<<2)-((timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE))<<2))); - memcpy(&tx_buffer_eNB[antenna_index][0],buf+sizeof(openair0_timestamp)+2*sizeof(int16_t) + ((FRAME_MAX_SIZE)<<2) -((timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE))<<2), - (nsamps<<2)-((FRAME_MAX_SIZE)<<2)+((timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE))<<2)); - //printf("Received eNB TX samples for antenna %d, nsamps %d (%d)\n",antenna_index,nsamps,(int)(bytes_received>>2)); - } else { - memcpy(&tx_buffer_eNB[antenna_index][timestamp_eNB_tx[antenna_index]%(FRAME_MAX_SIZE)],buf+sizeof(openair0_timestamp)+2*sizeof(int16_t),nsamps<<2); - } - - while (sync_eNB_rx[antenna_index]==0) - nanosleep(&time_req_1us,&time_rem_1us); - - //printf("launching eNB proc\n"); - pthread_mutex_lock(&sync_eNB_mutex[antenna_index]); - sync_eNB_rx[antenna_index]++; - - if (!sync_eNB_rx[antenna_index]) { - counter_eNB_tx[antenna_index]=(counter_eNB_tx[antenna_index]+nsamps)%FRAME_MAX_SIZE; - nsamps_eNB[antenna_index]=nsamps; - } else { - printf("rrh_eNB_proc thread is busy, will exit\n"); - exit(-1); - } - - pthread_mutex_unlock(&sync_eNB_mutex[antenna_index]); - - clock_gettime(CLOCK_MONOTONIC,&time2); - - //if (trace_cnt++ < 10) - // printf("TX: t0 %llu (time from previous run) t1 %llu (time of memcpy TX samples), t2 %llu (total time)\n",(long long unsigned int)(time1.tv_nsec - time0.tv_nsec), - // (long long unsigned int)(time2.tv_nsec - time1.tv_nsec), - // (long long unsigned int)(time2.tv_nsec - time0.tv_nsec)); - - memcpy(&time0,&time2,sizeof(struct timespec)); - - - - } - - return(0); - -} - -void *rrh_eNB_thread(void *arg) -{ - - int sockid=-1; - struct sockaddr_in serveraddr; - struct sockaddr clientaddr; - socklen_t clientaddrlen; - rrh_desc_t *rrh_desc = (rrh_desc_t *)arg; - char str[INET_ADDRSTRLEN]; - //int8_t msg_header[4+sizeof(openair0_timestamp)]; - int8_t buf[BUF_LEN]; - int16_t cmd; //,nsamps,antenna_index; - ssize_t bytes_received; - //ssize_t bytes_sent; - //openair0_timestamp temp, last_hw_counter=0; - //struct timespec time_rem; - struct timespec time_req_1us, time_rem_1us; - //struct timespec time0a,time0,time1,time2; - //int trace_cnt=0; - rrh_eNB_desc_t rrh_eNB_desc; - pthread_t eNB_rx_thread, eNB_tx_thread; - pthread_attr_t attr_eNB_rx, attr_eNB_tx; - struct sched_param sched_param_eNB_rx, sched_param_eNB_tx; - int error_code_eNB_rx, error_code_eNB_tx; - - time_req_1us.tv_sec = 0; - time_req_1us.tv_nsec = 1000; - - - while (rrh_exit==0) { - - - sockid=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); - - if (sockid==-1) { - perror("Cannot create eNB socket: "); - rrh_exit=1; - } - - - bzero((char *)&serveraddr,sizeof(serveraddr)); - serveraddr.sin_family=AF_INET; - serveraddr.sin_port=htons(rrh_desc->eNB_port); - inet_pton(AF_INET,rrh_desc->eNB_dest_ip,&serveraddr.sin_addr.s_addr); - - inet_ntop(AF_INET, &(serveraddr.sin_addr), str, INET_ADDRSTRLEN); - printf("Binding to eNB socket for %s:%d\n",str,ntohs(serveraddr.sin_port)); - - if (bind(sockid,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0) { - perror("Cannot bind to eNB socket: "); - rrh_exit = 1; - } - - // now wait for commands from eNB - - // get header info - bzero((void*)&clientaddr,sizeof(struct sockaddr)); - clientaddrlen = sizeof(struct sockaddr); - //printf("Waiting for eNB ...\n"); - - - - bytes_received = recvfrom(sockid,buf,BUF_LEN,0,&clientaddr,&clientaddrlen); - cmd = buf[0]; - rrh_eNB_desc.antenna_index_eNB_rx = cmd>>1; - rrh_eNB_desc.antenna_index_eNB_tx = cmd>>1; - //rrh_eNB_desc.timestamp_eNB_tx[rrh_eNB_desc.antenna_index_eNB_tx] = *(openair0_timestamp*)(buf+4); //we don't need timestamp when receiving the first command - rrh_eNB_desc.nsamps = *(int16_t *)(buf+2); - rrh_eNB_desc.sockid_eNB = sockid; - rrh_eNB_desc.clientaddr = clientaddr; - rrh_eNB_desc.clientaddrlen = clientaddrlen; - - //cmd = cmd&1; - cmd = cmd|1;//in order to make cmd evalution dummy (the first message from lte to rrh has changed, see: @ethernet_lib.c trx_start_func has been substituted by trx_request_func ) - inet_ntop(AF_INET, &(((struct sockaddr_in*)&clientaddr)->sin_addr), str, INET_ADDRSTRLEN); - - if (cmd==START_CMD) { - - pthread_attr_init(&attr_eNB_rx); - pthread_attr_init(&attr_eNB_tx); - sched_param_eNB_rx.sched_priority = sched_get_priority_max(SCHED_FIFO); - sched_param_eNB_tx.sched_priority = sched_get_priority_max(SCHED_FIFO); - pthread_attr_setschedparam(&attr_eNB_rx,&sched_param_eNB_rx); - pthread_attr_setschedparam(&attr_eNB_tx,&sched_param_eNB_tx); - pthread_attr_setschedpolicy(&attr_eNB_rx,SCHED_FIFO); - pthread_attr_setschedpolicy(&attr_eNB_tx,SCHED_FIFO); - - error_code_eNB_rx = pthread_create(&eNB_rx_thread, &attr_eNB_rx, rrh_eNB_rx_thread, (void *)&rrh_eNB_desc); - error_code_eNB_tx = pthread_create(&eNB_tx_thread, &attr_eNB_tx, rrh_eNB_tx_thread, (void *)&rrh_eNB_desc); - - if (error_code_eNB_rx) { - printf("Error while creating eNB RX thread\n"); - exit(-1); - } - - if (error_code_eNB_tx) { - printf("Error while creating eNB TX thread\n"); - exit(-1); - } - - while (rrh_exit==0) - sleep(1); - - } - - - } //while (rrh_exit==0) - - close(sockid); - - rrh_eNB_thread_status = 0; - pthread_exit(&rrh_eNB_thread_status); - - return(0); -} - - -void signal_handler(int sig) -{ - void *array[10]; - size_t size; - - if (sig==SIGSEGV) { - // get void*'s for all entries on the stack - size = backtrace(array, 10); - - // print out all the frames to stderr - fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, 2); - exit(-1); - } else { - printf("trying to exit gracefully...\n"); - rrh_exit = 1; - } -} - -int main(int argc, char **argv) -{ - - pthread_t main_rrh_eNB_thread, main_rrh_UE_thread, main_rrh_proc_eNB_thread, main_rrh_proc_UE_thread, main_timer_proc_thread; - pthread_attr_t attr, attr_proc, attr_timer; - struct sched_param sched_param_rrh, sched_param_rrh_proc, sched_param_timer; - int error_code_eNB, error_code_UE, error_code_proc_eNB, error_code_proc_UE, error_code_timer; - int i; - int opt; - int nsecs=0, rt_period=0; - rrh_desc_t rrh; - struct itimerspec timer; - - - rrh.time_req.tv_sec = 0; - rrh.time_req.tv_nsec = 0; - - rrh.eNB_port = RRH_eNB_PORT; - strcpy(rrh.eNB_dest_ip,RRH_eNB_DEST_IP); - rrh.UE_port = RRH_UE_PORT; - strcpy(rrh.UE_dest_ip ,RRH_UE_DEST_IP); - - nsecs = 0; - - while ((opt = getopt(argc, argv, "t:rE:U:")) != -1) { - switch (opt) { - case 't': - rt_period = atoi(optarg); - RT_FLAG=1; - NRT_FLAG=0; - break; - - case 'r': - rt_period = DEFAULT_PERIOD_NS; - RT_FLAG=1; - NRT_FLAG=0; - break; - - case 'E': - strcpy(rrh.eNB_dest_ip,optarg); - break; - - case 'U': - strcpy(rrh.UE_dest_ip,optarg); - break; - - default: /* '?' */ - fprintf(stderr, "Usage: %s [-d nsecs]\n", argv[0]); - exit(-1); - } - } - - // if (optind >= argc) { - // fprintf(stderr, "Expected argument after options\n"); - // exit(EXIT_FAILURE); - // } - - // setup the timer (1s delay, 1s reload) - timer.it_value.tv_sec = rt_period/1000000000; - timer.it_value.tv_nsec = rt_period%1000000000; - timer.it_interval.tv_sec = rt_period/1000000000; - timer.it_interval.tv_nsec = rt_period%1000000000; - - - // to make a graceful exit when ctrl-c is pressed - signal(SIGSEGV, signal_handler); - signal(SIGINT, signal_handler); - - - pthread_attr_init(&attr); - sched_param_rrh.sched_priority = sched_get_priority_max(SCHED_FIFO); - pthread_attr_init(&attr_proc); - sched_param_rrh_proc.sched_priority = sched_get_priority_max(SCHED_FIFO-1); - pthread_attr_init(&attr_timer); - sched_param_timer.sched_priority = sched_get_priority_max(SCHED_FIFO-2); - - pthread_attr_setschedparam(&attr,&sched_param_rrh); - pthread_attr_setschedpolicy(&attr,SCHED_FIFO); - pthread_attr_setschedparam(&attr_proc,&sched_param_rrh_proc); - pthread_attr_setschedpolicy(&attr_proc,SCHED_FIFO-1); - pthread_attr_setschedparam(&attr_timer,&sched_param_timer); - pthread_attr_setschedpolicy(&attr_timer,SCHED_FIFO-2); - - for (i=0; i<4; i++) { - pthread_mutex_init(&sync_eNB_mutex[i],NULL); - pthread_cond_init(&sync_eNB_cond[i],NULL); - pthread_mutex_init(&sync_UE_mutex[i],NULL); - pthread_cond_init(&sync_UE_cond[i],NULL); - } - - pthread_mutex_init(&timer_mutex,NULL); - - error_code_eNB = pthread_create(&main_rrh_eNB_thread, &attr, rrh_eNB_thread, (void *)&rrh); - error_code_UE = pthread_create(&main_rrh_UE_thread, &attr, rrh_UE_thread, (void *)&rrh); - error_code_proc_UE = pthread_create(&main_rrh_proc_UE_thread, &attr_proc, rrh_proc_UE_thread, NULL); - error_code_proc_eNB = pthread_create(&main_rrh_proc_eNB_thread, &attr_proc, rrh_proc_eNB_thread, NULL); - error_code_timer = pthread_create(&main_timer_proc_thread, &attr_timer, timer_proc, (void *)&timer); - - if (error_code_eNB) { - printf("Error while creating eNB thread\n"); - exit(-1); - } - - if (error_code_UE) { - printf("Error while creating UE thread\n"); - exit(-1); - } - - if (error_code_proc_UE) { - printf("Error while creating UE proc thread\n"); - exit(-1); - } - - if (error_code_proc_eNB) { - printf("Error while creating eNB proc thread\n"); - exit(-1); - } - - if (error_code_timer) { - printf("Error while creating timer proc thread\n"); - exit(-1); - } - - printf("TYPE TO TERMINATE\n"); - - while (rrh_exit==0) - sleep(1); - - - //pthread_join(main_rrh_eNB_thread,&rrh_eNB_thread_status); - return 0; -} diff --git a/targets/RT/USER/rrh.gtkw b/targets/RT/USER/rrh.gtkw deleted file mode 100644 index 891f23ada5..0000000000 --- a/targets/RT/USER/rrh.gtkw +++ /dev/null @@ -1,195 +0,0 @@ -[*] -[*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI -[*] Fri Jan 29 16:34:46 2016 -[*] -[dumpfile] "/tmp/openair_dump_rrh.vcd" -[dumpfile_mtime] "Fri Jan 29 16:20:55 2016" -[dumpfile_size] 224259458 -[savefile] "/home/guepe/openairinterface5g_rrh/openairinterface5g/targets/RT/USER/rrh.gtkw" -[timestart] 31315875900 -[size] 1004 1028 -[pos] 926 -1 -*-17.429794 31316090054 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -[sst_width] 224 -[signals_width] 261 -[sst_expanded] 1 -[sst_vpaned_height] 278 -@24 -[color] 1 -variables.hw_frame_rx[63:0] -[color] 1 -variables.hw_subframe_rx[63:0] -@28 -[color] 1 -functions.eNB_rx -functions.eNB_rx_sleep -[color] 3 -functions.trx_read_rf -[color] 7 -functions.trx_write -@c00024 -variables.rxcnt[63:0] -@28 -(0)variables.rxcnt[63:0] -(1)variables.rxcnt[63:0] -(2)variables.rxcnt[63:0] -(3)variables.rxcnt[63:0] -(4)variables.rxcnt[63:0] -(5)variables.rxcnt[63:0] -(6)variables.rxcnt[63:0] -(7)variables.rxcnt[63:0] -(8)variables.rxcnt[63:0] -(9)variables.rxcnt[63:0] -(10)variables.rxcnt[63:0] -(11)variables.rxcnt[63:0] -(12)variables.rxcnt[63:0] -(13)variables.rxcnt[63:0] -(14)variables.rxcnt[63:0] -(15)variables.rxcnt[63:0] -(16)variables.rxcnt[63:0] -(17)variables.rxcnt[63:0] -(18)variables.rxcnt[63:0] -(19)variables.rxcnt[63:0] -(20)variables.rxcnt[63:0] -(21)variables.rxcnt[63:0] -(22)variables.rxcnt[63:0] -(23)variables.rxcnt[63:0] -(24)variables.rxcnt[63:0] -(25)variables.rxcnt[63:0] -(26)variables.rxcnt[63:0] -(27)variables.rxcnt[63:0] -(28)variables.rxcnt[63:0] -(29)variables.rxcnt[63:0] -(30)variables.rxcnt[63:0] -(31)variables.rxcnt[63:0] -(32)variables.rxcnt[63:0] -(33)variables.rxcnt[63:0] -(34)variables.rxcnt[63:0] -(35)variables.rxcnt[63:0] -(36)variables.rxcnt[63:0] -(37)variables.rxcnt[63:0] -(38)variables.rxcnt[63:0] -(39)variables.rxcnt[63:0] -(40)variables.rxcnt[63:0] -(41)variables.rxcnt[63:0] -(42)variables.rxcnt[63:0] -(43)variables.rxcnt[63:0] -(44)variables.rxcnt[63:0] -(45)variables.rxcnt[63:0] -(46)variables.rxcnt[63:0] -(47)variables.rxcnt[63:0] -(48)variables.rxcnt[63:0] -(49)variables.rxcnt[63:0] -(50)variables.rxcnt[63:0] -(51)variables.rxcnt[63:0] -(52)variables.rxcnt[63:0] -(53)variables.rxcnt[63:0] -(54)variables.rxcnt[63:0] -(55)variables.rxcnt[63:0] -(56)variables.rxcnt[63:0] -(57)variables.rxcnt[63:0] -(58)variables.rxcnt[63:0] -(59)variables.rxcnt[63:0] -(60)variables.rxcnt[63:0] -(61)variables.rxcnt[63:0] -(62)variables.rxcnt[63:0] -(63)variables.rxcnt[63:0] -@1401200 --group_end -@24 -variables.pck_rx[63:0] -variables.rx_ts[63:0] -@c00024 -variables.tx_seq_num[63:0] -@28 -(0)variables.tx_seq_num[63:0] -(1)variables.tx_seq_num[63:0] -(2)variables.tx_seq_num[63:0] -(3)variables.tx_seq_num[63:0] -(4)variables.tx_seq_num[63:0] -(5)variables.tx_seq_num[63:0] -(6)variables.tx_seq_num[63:0] -(7)variables.tx_seq_num[63:0] -(8)variables.tx_seq_num[63:0] -(9)variables.tx_seq_num[63:0] -(10)variables.tx_seq_num[63:0] -(11)variables.tx_seq_num[63:0] -(12)variables.tx_seq_num[63:0] -(13)variables.tx_seq_num[63:0] -(14)variables.tx_seq_num[63:0] -(15)variables.tx_seq_num[63:0] -(16)variables.tx_seq_num[63:0] -(17)variables.tx_seq_num[63:0] -(18)variables.tx_seq_num[63:0] -(19)variables.tx_seq_num[63:0] -(20)variables.tx_seq_num[63:0] -(21)variables.tx_seq_num[63:0] -(22)variables.tx_seq_num[63:0] -(23)variables.tx_seq_num[63:0] -(24)variables.tx_seq_num[63:0] -(25)variables.tx_seq_num[63:0] -(26)variables.tx_seq_num[63:0] -(27)variables.tx_seq_num[63:0] -(28)variables.tx_seq_num[63:0] -(29)variables.tx_seq_num[63:0] -(30)variables.tx_seq_num[63:0] -(31)variables.tx_seq_num[63:0] -(32)variables.tx_seq_num[63:0] -(33)variables.tx_seq_num[63:0] -(34)variables.tx_seq_num[63:0] -(35)variables.tx_seq_num[63:0] -(36)variables.tx_seq_num[63:0] -(37)variables.tx_seq_num[63:0] -(38)variables.tx_seq_num[63:0] -(39)variables.tx_seq_num[63:0] -(40)variables.tx_seq_num[63:0] -(41)variables.tx_seq_num[63:0] -(42)variables.tx_seq_num[63:0] -(43)variables.tx_seq_num[63:0] -(44)variables.tx_seq_num[63:0] -(45)variables.tx_seq_num[63:0] -(46)variables.tx_seq_num[63:0] -(47)variables.tx_seq_num[63:0] -(48)variables.tx_seq_num[63:0] -(49)variables.tx_seq_num[63:0] -(50)variables.tx_seq_num[63:0] -(51)variables.tx_seq_num[63:0] -(52)variables.tx_seq_num[63:0] -(53)variables.tx_seq_num[63:0] -(54)variables.tx_seq_num[63:0] -(55)variables.tx_seq_num[63:0] -(56)variables.tx_seq_num[63:0] -(57)variables.tx_seq_num[63:0] -(58)variables.tx_seq_num[63:0] -(59)variables.tx_seq_num[63:0] -(60)variables.tx_seq_num[63:0] -(61)variables.tx_seq_num[63:0] -(62)variables.tx_seq_num[63:0] -(63)variables.tx_seq_num[63:0] -@1401200 --group_end -@24 -variables.hw_frame[63:0] -variables.hw_subframe[63:0] -@28 -[color] 1 -functions.eNB_tx -functions.eNB_tx_sleep -[color] 7 -functions.trx_read -[color] 3 -functions.trx_write_rf -@24 -variables.txcnt[63:0] -variables.pck_tx[63:0] -variables.tx_ts[63:0] -@25 -variables.rx_seq_num_prv[63:0] -@24 -variables.rx_seq_num[63:0] -variables.hw_cnt_rx[63:0] -variables.lhw_cnt_rx[63:0] -[color] 3 -variables.cnt[63:0] -[pattern_trace] 1 -[pattern_trace] 0 diff --git a/targets/RT/USER/rrh_gw.c b/targets/RT/USER/rrh_gw.c deleted file mode 100644 index 7aea0484be..0000000000 --- a/targets/RT/USER/rrh_gw.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - - -/*! \file rrh_gw.h - * \brief top-level for the remote radio head gateway (RRH_gw) module reusing the ethernet library - * \author Navid Nikaein, Katerina Trilyraki, Raymond Knopp - * \date 2015 - * \version 0.1 - * \company Eurecom - * \maintainer: navid.nikaein@eurecom.fr - * \note - * \warning very experimental - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common_lib.h" -#include "rrh_gw.h" -#include "rt_wrapper.h" -#include "rrh_gw_externs.h" - - -#include "log_if.h" -#include "log_extern.h" -#include "vcd_signal_dumper.h" - -/***************************************************************************************** - * ---------- * - * ------- RRH_BBU_IF ------- RRH_RF_IF -------USRP - COTS_UE- * - * - BBU - --------------- - RRH - ------------- -------BLADERF ---------- * - * ------- ------- -------EXMIMO * - * --------- * - * -------ETH_IF - EMU_UE- * - * --------- * - *****************************************************************************************/ - - -/* local IP/MAC address is detected*/ -char rrh_ip[20] = "0.0.0.0"; -unsigned char rrh_mac[20] = "0:0:0:0:0:0"; -int rrh_port = 50000; // has to be an option - -/* log */ -int16_t glog_level = LOG_DEBUG; -int16_t glog_verbosity = LOG_MED; -int16_t rrh_log_level = LOG_INFO; -int16_t rrh_log_verbosity = LOG_MED; -int16_t enb_log_level = LOG_INFO; -int16_t enb_log_verbosity = LOG_MED; -int16_t ue_log_level = LOG_INFO; -int16_t ue_log_verbosity = LOG_MED; - - -/* flag definitions */ -uint8_t eNB_flag=0; -uint8_t UE_flag=0; -uint8_t EXMIMO_flag=0; -uint8_t USRP_flag=0; -uint8_t RT_flag=0, NRT_flag=1; -uint8_t rrh_exit=0; -uint8_t loopback_flag=0; -uint8_t measurements_flag=0; - -/* Default operation as RRH: - - there are neither eNB nor UE modules - - no RF hardware is specified (NONE_IF) - - default ethernet interface is local */ -uint8_t num_eNB_mod=0; -uint8_t num_UE_mod=0; -char* if_name="lo"; -uint8_t eth_mode=ETH_UDP_MODE; - -rrh_module_t *enb_array; -rrh_module_t *ue_array; - -openair0_vtimestamp hw_counter=0; - -char rf_config_file[1024]; - -static void debug_init(void); -static void get_options(int argc, char *argv[]); -static void print_help(void); - -/*!\fn static rrh_module_t new_module(unsigned int id); -* \brief creation of a eNB/UE module -* \param[in] module id -* \return module -* \note -* @ingroup _oai -*/ -static rrh_module_t new_module(unsigned int id); - -/*!\fn static int get_address(char* if_name, uint8_t flag); - * \brief retrieves IP address from the specified network interface - * \param[in] name of network interface - * \return 0 - * \note - * @ingroup _oai - */ -static int get_address(char* if_name, uint8_t flag); - - - - - -int main(int argc, char **argv) { - - unsigned int i; - rf_config_file[0]='\0'; - /* parse input arguments */ - get_options(argc, argv); - /* initialize logger and signal analyzer */ - debug_init(); - /* */ - set_latency_target(); - /* make a graceful exit when ctrl-c is pressed */ - signal(SIGSEGV, signal_handler); - signal(SIGINT, signal_handler); - - /* create modules based on input arguments */ - if (eNB_flag==1){ - enb_array=(rrh_module_t*)malloc(num_eNB_mod*sizeof(rrh_module_t)); - for(i=0;i TO TERMINATE\n"); - - while (rrh_exit==0) - sleep(1); - - return EXIT_SUCCESS; -} - - -static rrh_module_t new_module (unsigned int id) { - - rrh_module_t rrh_mod; - openair0_config_t openair0_cfg; - - rrh_mod.id=id; - rrh_mod.loopback=loopback_flag; - rrh_mod.measurements=measurements_flag; - - /* each module is associated with an ethernet device */ - rrh_mod.eth_dev.type=NONE_DEV; - rrh_mod.eth_dev.transp_type=NONE_TP; - /* ethernet device is functioning within RRH */ - rrh_mod.eth_dev.host_type=RRH_HOST; - /* */ - rrh_mod.eth_dev.openair0_cfg = (openair0_config_t*)malloc(sizeof(openair0_config_t)); - memset(rrh_mod.eth_dev.openair0_cfg,0,sizeof(openair0_config_t)); - /* get IP and MAC address */ - get_address(if_name,eth_mode); - - if(eth_mode==ETH_UDP_MODE) { - openair0_cfg.my_addr = &rrh_ip[0]; - openair0_cfg.my_port = rrh_port; - LOG_I(RRH,"UDP mode selected for ethernet.\n"); - } else if (eth_mode==ETH_RAW_MODE) { - openair0_cfg.my_addr = (char*)&rrh_mac[0]; - openair0_cfg.my_port = rrh_port; - LOG_I(RRH,"RAW mode selected for ethernet.\n"); - } - - /* */ - eth_params_t *eth_params = (eth_params_t*)malloc(sizeof(eth_params_t)); - memset(eth_params, 0, sizeof(eth_params_t)); - eth_params->local_if_name = if_name; - eth_params->transp_preference = eth_mode; - - /* ethernet device initialization */ - if (openair0_transport_load(&rrh_mod.eth_dev, &openair0_cfg,eth_params)<0) { - LOG_E(RRH,"Exiting, cannot initialize ethernet interface.\n"); - exit(-1); - } - - /* allocate space and specify associated RF device */ - openair0_device *oai_dv = (openair0_device *)malloc(sizeof(openair0_device)); - memset(oai_dv,0,sizeof(openair0_device)); - - rrh_mod.devs=oai_dv; - rrh_mod.devs->type=NONE_DEV; - rrh_mod.devs->transp_type=NONE_TP; - rrh_mod.devs->host_type=RRH_HOST; - - return rrh_mod; -} - -static void debug_init(void) { - - /* log initialization */ - logInit(); - set_glog(glog_level, glog_verbosity); - - set_comp_log(RRH, rrh_log_level, rrh_log_verbosity, 1); - //set_comp_log(ENB_LOG, enb_log_level, enb_log_verbosity, 1); - //set_comp_log(UE_LOG, ue_log_level, ue_log_verbosity, 1); - - /* vcd initialization */ - if (ouput_vcd) { - vcd_signal_dumper_init("/tmp/openair_dump_rrh.vcd"); - - } -} - - -static void get_options(int argc, char *argv[]) { - - int opt; - - while ((opt = getopt(argc, argv, "xvhlte:n:u:g:r:m:i:f:")) != -1) { - - switch (opt) { - case 'n': - eNB_flag=1; - num_eNB_mod=atoi(optarg); - break; - case 'u': - UE_flag=1; - num_UE_mod=atoi(optarg); - break; - case 'g': - glog_level=atoi(optarg); - break; - case 'i': - if (optarg) { - if_name=strdup(optarg); - printf("RRH interface name is set to %s\n", if_name); - } - break; - case 'm': - eth_mode=atoi(optarg); - break; - case 'r': - //rrh_log_level=atoi(optarg); - break; - case 'e': - //enb_log_level=atoi(optarg); - break; - case 'x': - rt_period = DEFAULT_PERIOD_NS; - RT_flag=1; - NRT_flag=0; - break; - case 'v': - /* extern from vcd */ - ouput_vcd=1; - break; - case 'l': - /*In loopback mode rrh sends back to bbu what it receives*/ - loopback_flag=1; - break; - case 'f': - if (optarg){ - if ((strcmp("null", optarg) == 0) || (strcmp("NULL", optarg) == 0)) { - printf("no configuration filename is provided\n"); - } - else if (strlen(optarg)<=1024){ - // rf_config_file = strdup(optarg); - strcpy(rf_config_file,optarg); - }else { - printf("Configuration filename is too long\n"); - exit(-1); - } - } - break; - case 't': - /* When measurements are enabled statistics related to TX/RX time are printed */ - measurements_flag=1; - break; - case 'h': - print_help(); - exit(-1); - default: /* '?' */ - //fprintf(stderr, "Usage: \n", argv[0]); - exit(-1); - } -} - -} - -static int get_address(char* if_name, uint8_t flag) { - - int fd; - struct ifreq ifr; - - fd = socket(AF_INET, SOCK_DGRAM, 0); - /* I want to get an IPv4 IP address */ - ifr.ifr_addr.sa_family = AF_INET; - /* I want IP address attached to "if_name" */ - strncpy(ifr.ifr_name, if_name, IFNAMSIZ-1); - - if (flag==ETH_UDP_MODE) { - if ( ioctl(fd, SIOCGIFADDR, &ifr)<0 ) { - perror("IOCTL:"); - exit(-1); - } - snprintf(&rrh_ip[0],20,"%s", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr)); - LOG_I(RRH,"%s: IP address: %s\n",if_name,rrh_ip); - } else if (flag==ETH_RAW_MODE) { - if ( ioctl(fd, SIOCGIFHWADDR, &ifr)<0 ) { - perror("IOCTL:"); - exit(-1); - } - ether_ntoa_r ((struct ether_addr *)ifr.ifr_hwaddr.sa_data, (char*)rrh_mac); - LOG_I(RRH,"%s: MAC address: %s\n",if_name,rrh_mac); - } - - close(fd); - return 0; -} - - -static void print_help(void) { - - puts("Usage: \n"); - puts(" sudo -E chrt 99 ./rrh -n1 -g6 -v -t -i lo -m1"); - puts("Options:\n"); - puts("\t -n create eNB module\n"); - puts("\t -u create UE module\n"); - puts("\t -g define global log level\n"); - puts("\t -i set the RRH interface (default lo)\n"); - puts("\t -m set ethernet mode to be used by RRH, valid options: (1:raw, 0:udp) \n"); - puts("\t -r define rrh log level\n"); - puts("\t -e define eNB log level\n"); - puts("\t -x enable real time bahaviour\n"); - puts("\t -v enable vcd dump\n"); - puts("\t -l enable loopback mode\n"); - puts("\t -t enable measurements\n"); - puts("\t -h display info\n"); - -} - - -void *timer_proc(void *arg) { - - timer_t timerid; - struct itimerspec *timer= (struct itimerspec *)arg ; // the timer data structure - struct itimerspec old_value; - - -#ifdef DEADLINE_SCHEDULER - struct sched_attr attr; - unsigned int flags = 0; - - attr.size = sizeof(attr); - attr.sched_flags = 0; - attr.sched_nice = 0; - attr.sched_priority = 0; - - attr.sched_policy = SCHED_DEADLINE; - attr.sched_runtime = (0.1 * 100) * 10000; // - attr.sched_deadline = rt_period-30000;//(0.1 * 100) * 10000; - attr.sched_period = rt_period;//(0.1 * 100) * 10000; // each TX/RX thread has, as a function of RT PERIOD ?? - - if (sched_setattr(0, &attr, flags) < 0 ) { - perror("[SCHED] timer thread: sched_setattr failed\n"); - exit(-1); - } -#endif - - if (timer_create (CLOCK_REALTIME, NULL, &timerid) == -1) { - fprintf (stderr, "couldn't create a timer\n"); - perror (NULL); - exit (EXIT_FAILURE); - } - - signal(SIGALRM, timer_signal_handler); - LOG_I(RRH,"Timer has started!\n"); - timer_settime (timerid, 0, timer, &old_value); - - while (!rrh_exit) { - sleep(1); - } - - timer_delete(timerid); - - return (0); -} - - -void timer_signal_handler(int sig) { - - if (sig == SIGALRM) { - pthread_mutex_lock(&timer_mutex); - hw_counter ++; - pthread_mutex_unlock(&timer_mutex); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_CNT, hw_counter);//USED ELSEWHERE - } -} - - -void signal_handler(int sig) { - - void *array[10]; - size_t size; - - if (sig==SIGSEGV) { - // get void*'s for all entries on the stack - size = backtrace(array, 10); - - // print out all the frames to stderr - fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, 2); - exit(-1); - } else { - printf("trying to exit gracefully...\n"); - rrh_exit = 1; - } -} - -void exit_fun(const char* s) { - if (s != NULL) { - printf("%s %s() Exiting RRH: %s\n",__FILE__, __FUNCTION__, s); - } - rrh_exit = 1; - exit (-1); -} - - diff --git a/targets/RT/USER/rrh_gw.h b/targets/RT/USER/rrh_gw.h deleted file mode 100644 index 97ffa5a893..0000000000 --- a/targets/RT/USER/rrh_gw.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file rrh_gw.h - * \brief header file for remote radio head gateway (RRH_gw) module - * \author Navid Nikaein, Katerina Trilyraki, Raymond Knopp - * \date 2015 - * \version 0.1 - * \company Eurecom - * \maintainer: navid.nikaein@eurecom.fr - * \note - * \warning very experimental - */ - -#ifndef RRH_GW_H_ -#define RRH_GW_H_ - -#include "ethernet_lib.h" -#include "vcd_signal_dumper.h" -#include "assertions.h" - -#define DEFAULT_PERIOD_NS 200000 /* default value is calculated for 25 PRB */ -#define RRH_UE_PORT 51000 -#define RRH_UE_DEST_IP "127.0.0.1" - -/*! \brief RRH supports two types of modules: eNB and UE - each module is associated with an ethernet device (device of ETH_IF) - and optionally with a RF device (device type can be USRP_B200/USRP_X300/BLADERF_IF/EXMIMO_IF/NONE_IF) - UE modules will always have RF device type NONE_IF */ -typedef struct { -/*! \brief module id */ - uint8_t id; -/*! \brief! loopback flag */ -uint8_t loopback; -/*! \brief measurement flag */ -uint8_t measurements; -/*! \brief module's ethernet device */ -openair0_device eth_dev; -/*! \brief pointer to RF module's device (pointer->since it's optional) */ -openair0_device *devs; -}rrh_module_t; - -/*! \fn void timer_signal_handler(int sig) - * \brief this function - * \param[in] signal type - * \return none - * \note - * @ingroup _oai -*/ -void timer_signal_handler(int); - -/*! \fn void *timer_proc(void *arg) - * \brief this function - * \param[in] - * \param[out] - * \return - * \note - * @ingroup _oai - */ -void *timer_proc(void *); - -/*! \fn void config_BBU_mod( rrh_module_t *mod_enb, uint8_t RT_flag,uint8_t NRT_flag) - * \brief receive and apply configuration to modules' optional device - * \param[in] *mod_enb pointer to module - * \param[in] RT_flag real time flag - * \return none - * \note - * @ingroup _oai - */ -void config_BBU_mod( rrh_module_t *mod_enb, uint8_t RT_flag, uint8_t NRT_flag); - -/*! \fn void config_UE_mod( rrh_module_t *dev_ue, uint8_t RT_flag,uint8_t NRT_flag) - * \brief this function - * \param[in] *mod_ue pointer to module - * \param[in] - * \return none - * \note - * @ingroup _oai - */ -void config_UE_mod( rrh_module_t *dev_ue, uint8_t RT_flag, uint8_t NRT_flag); - - - -void signal_handler(int sig); - -#endif diff --git a/targets/RT/USER/rrh_gw_externs.h b/targets/RT/USER/rrh_gw_externs.h deleted file mode 100644 index 0786743399..0000000000 --- a/targets/RT/USER/rrh_gw_externs.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file rrh_gw_extern.h - * \brief rrh gatewy external vars - * \author Navid Nikaein, Katerina Trilyraki, Raymond Knopp - * \date 2015 - * \version 0.1 - * \company Eurecom - * \maintainer: navid.nikaein@eurecom.fr - * \note - * \warning very experimental - */ - -#ifndef RRH_GW_EXTERNS_H_ -#define RRH_GW_EXTERNS_H_ -extern char rf_config_file[1024]; - -extern openair0_timestamp timestamp_UE_tx[4] ,timestamp_UE_rx[4] ,timestamp_eNB_rx[4],timestamp_eNB_tx[4]; -extern openair0_vtimestamp hw_counter; -extern int32_t UE_tx_started,UE_rx_started,eNB_rx_started ,eNB_tx_started; -extern int32_t nsamps_UE[4],nsamps_eNB[4]; -extern int32_t overflow_rx_buffer_eNB[4],overflow_rx_buffer_UE[4]; -extern uint8_t rrh_exit; -extern int32_t **rx_buffer_eNB, **rx_buffer_UE; -extern unsigned int rt_period; -extern pthread_mutex_t timer_mutex; - - -#endif diff --git a/targets/SIMU/USER/Makefile b/targets/SIMU/USER/Makefile index 12595aa86c..1c80cf07d5 100644 --- a/targets/SIMU/USER/Makefile +++ b/targets/SIMU/USER/Makefile @@ -263,7 +263,7 @@ endif # Check if libpgm is installed and use it if found instead of the unreliable # multicast ifeq ($(PGM_FOUND), 1) -CFLAGS += $(PGM_CFLAGS) -DENABLE_PGM_TRANSPORT +CFLAGS += $(PGM_CFLAGS) LIBS += $(PGM_LIBS) endif From bbaf5883521772c7250f002466796fc8d856eab6 Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 10:26:42 +0100 Subject: [PATCH 143/284] Fix #582, DISABLE_USE_NAS removed --- cmake_targets/CMakeLists.txt | 1 - openair3/COMMON/nas_messages_def.h | 6 ------ openair3/COMMON/nas_messages_types.h | 16 ---------------- 3 files changed, 23 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 7d1b8bb1be..daea932810 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -587,7 +587,6 @@ add_boolean_option(NO_RRM True "DO WE HAVE A RADIO RESSOURCE M add_boolean_option(RRC_DEFAULT_RAB_IS_AM False "set the RLC mode to AM for the default bearer") add_boolean_option(OAI_NW_DRIVER_TYPE_ETHERNET False "????") -add_boolean_option(DISABLE_USE_NAS False "???") add_boolean_option(DEADLINE_SCHEDULER True "Use the Linux scheduler SCHED_DEADLINE: kernel >= 3.14") add_boolean_option(CPU_AFFINITY False "Enable CPU Affinity of threads (only valid without deadline scheduler). It is enabled only with >2 CPUs") add_boolean_option(NAS_ADDRESS_FIX False "specific to oaisim: for nasmesh driver") diff --git a/openair3/COMMON/nas_messages_def.h b/openair3/COMMON/nas_messages_def.h index 5214a15171..9bdcde4fdf 100644 --- a/openair3/COMMON/nas_messages_def.h +++ b/openair3/COMMON/nas_messages_def.h @@ -61,9 +61,3 @@ MESSAGE_DEF(NAS_PDN_CONNECTIVITY_FAIL, MESSAGE_PRIORITY_MED, nas_pdn_ MESSAGE_DEF(NAS_AUTHENTICATION_PARAM_RSP, MESSAGE_PRIORITY_MED, nas_auth_param_rsp_t, nas_auth_param_rsp) MESSAGE_DEF(NAS_AUTHENTICATION_PARAM_FAIL, MESSAGE_PRIORITY_MED, nas_auth_param_fail_t, nas_auth_param_fail) -#if defined(DISABLE_USE_NAS) -MESSAGE_DEF(NAS_ATTACH_REQ, MESSAGE_PRIORITY_MED, nas_attach_req_t, nas_attach_req) -MESSAGE_DEF(NAS_ATTACH_ACCEPT, MESSAGE_PRIORITY_MED, nas_attach_accept_t, nas_attach_accept) -MESSAGE_DEF(NAS_AUTHENTICATION_RESP, MESSAGE_PRIORITY_MED, nas_auth_resp_t, nas_auth_resp) -MESSAGE_DEF(NAS_AUTHENTICATION_REQ, MESSAGE_PRIORITY_MED, nas_auth_req_t, nas_auth_req) -#endif diff --git a/openair3/COMMON/nas_messages_types.h b/openair3/COMMON/nas_messages_types.h index 45de68840e..81a44fa4f4 100644 --- a/openair3/COMMON/nas_messages_types.h +++ b/openair3/COMMON/nas_messages_types.h @@ -233,17 +233,7 @@ typedef struct nas_conn_est_ind_s { typedef nas_establish_rsp_t nas_conn_est_rej_t; -#if defined(DISABLE_USE_NAS) -typedef struct nas_conn_est_cnf_s { - uint32_t ue_id; - - nas_establish_cnf_t nas_establish_cnf; - /* Transparent message from MME_APP to S1AP */ - s1ap_initial_ctxt_setup_req_t transparent; -} nas_conn_est_cnf_t; -#else typedef nas_establish_cnf_t nas_conn_est_cnf_t; -#endif typedef struct nas_conn_rel_ind_s { @@ -336,10 +326,4 @@ typedef struct nas_auth_param_fail_s { } nas_auth_param_fail_t; -#if defined(DISABLE_USE_NAS) -typedef struct nas_attach_accept_s { - s1ap_initial_ctxt_setup_req_t transparent; -} nas_attach_accept_t; -#endif - #endif /* NAS_MESSAGES_TYPES_H_ */ From 71a6b5d0f0f7272f36ad5ae82f8ba0778aeb2896 Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 10:35:53 +0100 Subject: [PATCH 144/284] Fix #582, ENABLE_FXP removed --- cmake_targets/CMakeLists.txt | 1 - cmake_targets/epc_test/CMakeLists.template | 1 - cmake_targets/oaisim_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_mme_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_noS1_build_oai/CMakeLists.template | 1 - cmake_targets/s1c_mme_test/CMakeLists.template | 1 - common/utils/telnetsrv/CMakeLists.txt | 2 +- targets/SIMU/USER/Makefile | 2 +- targets/TEST/RLC_AM_V9.3.0/Makefile | 2 +- targets/TEST/RLC_UM_V9.3.0/Makefile | 2 +- 10 files changed, 4 insertions(+), 10 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index daea932810..04f0e8bc06 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -623,7 +623,6 @@ add_boolean_option(OPENAIR_LTE True "Seems legacy: keep it to true") # PHY options ########################## add_boolean_option(DRIVER2013 True "only relevant for EXMIMO") -add_boolean_option(ENABLE_FXP True "????") add_boolean_option(ENABLE_NEW_MULTICAST False "specific to oaisim") add_boolean_option(EXMIMO_IOT True "????") add_boolean_option(LARGE_SCALE False "specific to oaisim: defines max eNB=2 and max UE=120") diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index 302ae7bcf3..826447f92b 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -6,7 +6,6 @@ set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 True ) set ( EMIT_ASN_DEBUG False ) -set ( ENABLE_FXP True ) set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING True ) set ( ENABLE_NEW_MULTICAST True ) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index 951b69b783..0479b23dde 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -4,7 +4,6 @@ set ( CMAKE_BUILD_TYPE "RelWithDebInfo" ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 True ) -set ( ENABLE_FXP True ) set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING True ) set ( ENABLE_NEW_MULTICAST True ) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index c1ed73bdd8..a836d55d33 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -4,7 +4,6 @@ set ( CMAKE_BUILD_TYPE "RelWithDebInfo" ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 False ) -set ( ENABLE_FXP False ) set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING False ) set ( ENABLE_NEW_MULTICAST False ) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 68e5ee0e0a..d9972efa4d 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 2.8) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 True ) -set ( ENABLE_FXP True ) set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING False ) set ( ENABLE_NEW_MULTICAST True ) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index c293e176c2..88c0a62c28 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -4,7 +4,6 @@ set ( CMAKE_BUILD_TYPE "RelWithDebInfo" ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 True ) -set ( ENABLE_FXP True ) set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING True ) set ( ENABLE_NEW_MULTICAST True ) diff --git a/common/utils/telnetsrv/CMakeLists.txt b/common/utils/telnetsrv/CMakeLists.txt index 56c1d70791..6cf7f6f7e0 100644 --- a/common/utils/telnetsrv/CMakeLists.txt +++ b/common/utils/telnetsrv/CMakeLists.txt @@ -24,7 +24,7 @@ set(OPENAIR_NFAPIINC $ENV{NFAPI_DIR} ) set(CMAKE_INSTALL_PREFIX $ENV{OPENAIR_TARGETS}) -add_definitions (-DRel14 -DCMAKER -DENABLE_FXP -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNEW_FFT -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR1 -DOPENAIR2 -DOPENAIR_LTE -DPC_DSP -DPC_TARGET -DPHYSIM -DPHY_CONTEXT -DPUCCH -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) +add_definitions (-DRel14 -DCMAKER -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNEW_FFT -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR1 -DOPENAIR2 -DOPENAIR_LTE -DPC_DSP -DPC_TARGET -DPHYSIM -DPHY_CONTEXT -DPUCCH -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) add_compile_options( -fPIC -march=native -Ofast) include_directories( ./ ${OPENAIR_COMMON_DIR} ${OPENAIR_DIR} ${OPENAIR1_DIR} ${OPENAIR2_DIR} ${OPENAIR2_COMMON_DIR} ${OPENAIR2_DIR}/UTIL/LOG diff --git a/targets/SIMU/USER/Makefile b/targets/SIMU/USER/Makefile index 1c80cf07d5..0b0d8b9f6d 100644 --- a/targets/SIMU/USER/Makefile +++ b/targets/SIMU/USER/Makefile @@ -170,7 +170,7 @@ ifdef OAI_NW_DRIVER_TYPE_ETHERNET CFLAGS+=-DOAI_NW_DRIVER_TYPE_ETHERNET endif -CFLAGS += -DENABLE_FXP -DENABLE_USE_CPU_EXECUTION_TIME +CFLAGS += -DENABLE_USE_CPU_EXECUTION_TIME ifndef DISABLE_XER_PRINT CFLAGS += -DXER_PRINT endif diff --git a/targets/TEST/RLC_AM_V9.3.0/Makefile b/targets/TEST/RLC_AM_V9.3.0/Makefile index d29697ea6a..231ab9592e 100755 --- a/targets/TEST/RLC_AM_V9.3.0/Makefile +++ b/targets/TEST/RLC_AM_V9.3.0/Makefile @@ -106,7 +106,7 @@ endif CFLAGS += $(shell if [ `uname -o` = "Cygwin" ] ; then echo "-DCYGWIN" ;fi) -CFLAGS += -DENABLE_FXP -DENABLE_USE_CPU_EXECUTION_TIME +CFLAGS += -DENABLE_USE_CPU_EXECUTION_TIME ifneq ($(USE_MME), R8) UPDATE_RELEASE_9=1 diff --git a/targets/TEST/RLC_UM_V9.3.0/Makefile b/targets/TEST/RLC_UM_V9.3.0/Makefile index aa88a73c33..8c759c6bdc 100755 --- a/targets/TEST/RLC_UM_V9.3.0/Makefile +++ b/targets/TEST/RLC_UM_V9.3.0/Makefile @@ -101,7 +101,7 @@ ifdef OAI_NW_DRIVER_TYPE_ETHERNET CFLAGS+=-DOAI_NW_DRIVER_TYPE_ETHERNET endif -CFLAGS += -DENABLE_FXP -DENABLE_USE_CPU_EXECUTION_TIME +CFLAGS += -DENABLE_USE_CPU_EXECUTION_TIME ifneq ($(USE_MME), R8) UPDATE_RELEASE_9=1 From f7653f90b0922f65e6865e23a9169a130bcf5436 Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 10:44:59 +0100 Subject: [PATCH 145/284] Fix #582, PBS_SIM removed --- cmake_targets/CMakeLists.txt | 1 - cmake_targets/epc_test/CMakeLists.template | 1 - cmake_targets/lte-simulators/CMakeLists.txt | 1 - cmake_targets/oaisim_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_mme_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_noS1_build_oai/CMakeLists.template | 1 - cmake_targets/s1c_mme_test/CMakeLists.template | 1 - 7 files changed, 7 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 04f0e8bc06..f13d56468a 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -631,7 +631,6 @@ add_integer_option(MAX_NUM_CCs 1 "????") add_boolean_option(MU_RECEIVER False "????") add_boolean_option(NEW_FFT True "????") add_boolean_option(OPENAIR1 True "????") -add_boolean_option(PBS_SIM False "????") add_boolean_option(PC_DSP True "????") add_boolean_option(PC_TARGET True "????") add_boolean_option(PERFECT_CE False "????") diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index 826447f92b..6aab75b896 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -48,7 +48,6 @@ set ( OPENAIR1 True ) set ( OPENAIR2 True ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "epc_test" ) -set ( PBS_SIM False ) set ( PDCP_USE_NETLINK True ) set ( PC_DSP True ) set ( PC_TARGET True ) diff --git a/cmake_targets/lte-simulators/CMakeLists.txt b/cmake_targets/lte-simulators/CMakeLists.txt index ab718a8503..4b9cba7379 100644 --- a/cmake_targets/lte-simulators/CMakeLists.txt +++ b/cmake_targets/lte-simulators/CMakeLists.txt @@ -7,7 +7,6 @@ set(ENABLE_ITTI False) set(DEBUG_PHY False) set(MU_RECIEVER False) set(RANDOM_BF False) -set(PBS_SIM False) set(PERFECT_CE True) set(NAS_UE False) set(MESSAGE_CHART_GENERATOR False) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index 0479b23dde..a91402cdfc 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -47,7 +47,6 @@ set ( OPENAIR1 True ) set ( OPENAIR2 True ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) -set ( PBS_SIM False ) set ( PDCP_USE_NETLINK True ) set ( PC_DSP True ) set ( PC_TARGET True ) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index a836d55d33..9419da532c 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -49,7 +49,6 @@ set ( OPENAIR2 False ) set ( OPENAIR_EMU False ) set ( OPENAIR_LTE False ) set ( PACKAGE_NAME "EPC" ) -set ( PBS_SIM False ) set ( PC_DSP False ) set ( PC_TARGET False ) set ( PDCP_MSG_PRINT False ) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index d9972efa4d..9cc3e74fdd 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -49,7 +49,6 @@ set ( OPENAIR2 True ) set ( OPENAIR_EMU False ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) -set ( PBS_SIM False ) set ( PDCP_USE_NETLINK True ) set ( PC_DSP True ) set ( PC_TARGET True ) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index 88c0a62c28..0503e6dc45 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -48,7 +48,6 @@ set ( OPENAIR1 True ) set ( OPENAIR2 True ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) -set ( PBS_SIM False ) set ( PDCP_USE_NETLINK True ) set ( PC_DSP True ) set ( PC_TARGET True ) From dac7888f27dc7b72ed83ad601abfe9a149f44757 Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 10:52:41 +0100 Subject: [PATCH 146/284] Fix #582, PC_DSP removed --- cmake_targets/CMakeLists.txt | 1 - cmake_targets/epc_test/CMakeLists.template | 1 - cmake_targets/oaisim_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_mme_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_noS1_build_oai/CMakeLists.template | 1 - cmake_targets/s1c_mme_test/CMakeLists.template | 1 - common/utils/telnetsrv/CMakeLists.txt | 2 +- openair2/UTIL/OCG/makefile | 2 +- openair2/UTIL/OMG/makefile | 2 +- openair2/UTIL/OMG/makefile_old | 2 +- targets/TEST/AT_COMMANDS/Makefile | 2 +- targets/TEST/PACKET_TRACER/Makefile | 2 +- targets/TEST/PDCP/Makefile | 2 +- targets/TEST/PDCP/with_rlc/Makefile.data_bearer | 2 +- 14 files changed, 8 insertions(+), 14 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index f13d56468a..1540bb56c9 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -631,7 +631,6 @@ add_integer_option(MAX_NUM_CCs 1 "????") add_boolean_option(MU_RECEIVER False "????") add_boolean_option(NEW_FFT True "????") add_boolean_option(OPENAIR1 True "????") -add_boolean_option(PC_DSP True "????") add_boolean_option(PC_TARGET True "????") add_boolean_option(PERFECT_CE False "????") add_boolean_option(PHYSIM True "for L1 simulators (dlsim, ulsim, ...)") diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index 6aab75b896..14b5862320 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -49,7 +49,6 @@ set ( OPENAIR2 True ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "epc_test" ) set ( PDCP_USE_NETLINK True ) -set ( PC_DSP True ) set ( PC_TARGET True ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index a91402cdfc..b600f6f616 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -48,7 +48,6 @@ set ( OPENAIR2 True ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) set ( PDCP_USE_NETLINK True ) -set ( PC_DSP True ) set ( PC_TARGET True ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index 9419da532c..fe398b9275 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -49,7 +49,6 @@ set ( OPENAIR2 False ) set ( OPENAIR_EMU False ) set ( OPENAIR_LTE False ) set ( PACKAGE_NAME "EPC" ) -set ( PC_DSP False ) set ( PC_TARGET False ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 9cc3e74fdd..7d0b5b0268 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -50,7 +50,6 @@ set ( OPENAIR_EMU False ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) set ( PDCP_USE_NETLINK True ) -set ( PC_DSP True ) set ( PC_TARGET True ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index 0503e6dc45..29b32aa989 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -49,7 +49,6 @@ set ( OPENAIR2 True ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) set ( PDCP_USE_NETLINK True ) -set ( PC_DSP True ) set ( PC_TARGET True ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) diff --git a/common/utils/telnetsrv/CMakeLists.txt b/common/utils/telnetsrv/CMakeLists.txt index 6cf7f6f7e0..8f74fd96ae 100644 --- a/common/utils/telnetsrv/CMakeLists.txt +++ b/common/utils/telnetsrv/CMakeLists.txt @@ -24,7 +24,7 @@ set(OPENAIR_NFAPIINC $ENV{NFAPI_DIR} ) set(CMAKE_INSTALL_PREFIX $ENV{OPENAIR_TARGETS}) -add_definitions (-DRel14 -DCMAKER -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNEW_FFT -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR1 -DOPENAIR2 -DOPENAIR_LTE -DPC_DSP -DPC_TARGET -DPHYSIM -DPHY_CONTEXT -DPUCCH -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) +add_definitions (-DRel14 -DCMAKER -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNEW_FFT -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR1 -DOPENAIR2 -DOPENAIR_LTE -DPC_TARGET -DPHYSIM -DPHY_CONTEXT -DPUCCH -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) add_compile_options( -fPIC -march=native -Ofast) include_directories( ./ ${OPENAIR_COMMON_DIR} ${OPENAIR_DIR} ${OPENAIR1_DIR} ${OPENAIR2_DIR} ${OPENAIR2_COMMON_DIR} ${OPENAIR2_DIR}/UTIL/LOG diff --git a/openair2/UTIL/OCG/makefile b/openair2/UTIL/OCG/makefile index 578c2006cb..585e3ef9c2 100644 --- a/openair2/UTIL/OCG/makefile +++ b/openair2/UTIL/OCG/makefile @@ -7,7 +7,7 @@ OPENAIR2_TOP = ../../../openair2 OPENAIR3_TOP = ../../../openair3 OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DPHYSIM -DNODE_RG -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat +CFLAGS += -DPHYSIM -DNODE_RG -DPC_TARGET -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat CFLAGS += -m32 -DOPENAIR_LTE -DOPENAIR2 #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE diff --git a/openair2/UTIL/OMG/makefile b/openair2/UTIL/OMG/makefile index 1aa3d2d451..d3098195e3 100644 --- a/openair2/UTIL/OMG/makefile +++ b/openair2/UTIL/OMG/makefile @@ -60,7 +60,7 @@ OPENAIR2_TOP = ../../../openair2 OPENAIR3_TOP = ../../../openair3 OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DPHYSIM -DNODE_RG -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat +CFLAGS += -DPHYSIM -DNODE_RG -DPC_TARGET -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat CFLAGS += -DOPENAIR_LTE -DOPENAIR2 #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE diff --git a/openair2/UTIL/OMG/makefile_old b/openair2/UTIL/OMG/makefile_old index aa622f8522..d779a186ab 100644 --- a/openair2/UTIL/OMG/makefile_old +++ b/openair2/UTIL/OMG/makefile_old @@ -62,7 +62,7 @@ OPENAIR2_TOP = ../../../openair2 OPENAIR3_TOP = ../../../openair3 OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DPHYSIM -DNODE_RG -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat +CFLAGS += -DPHYSIM -DNODE_RG -DPC_TARGET -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat CFLAGS += -DOPENAIR_LTE -DOPENAIR2 #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE diff --git a/targets/TEST/AT_COMMANDS/Makefile b/targets/TEST/AT_COMMANDS/Makefile index 3f52e2af60..0d3e6994ae 100755 --- a/targets/TEST/AT_COMMANDS/Makefile +++ b/targets/TEST/AT_COMMANDS/Makefile @@ -6,7 +6,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3_TOP = $(OPENAIR3_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -m32 -DPHYSIM -DNODE_RG -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DNODE_RG -DPC_TARGET -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/PACKET_TRACER/Makefile b/targets/TEST/PACKET_TRACER/Makefile index 4d01cd6a69..0a656e1b36 100755 --- a/targets/TEST/PACKET_TRACER/Makefile +++ b/targets/TEST/PACKET_TRACER/Makefile @@ -6,7 +6,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3_TOP = $(OPENAIR3_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -m32 -DPHYSIM -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DPC_TARGET -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/PDCP/Makefile b/targets/TEST/PDCP/Makefile index 7b9e20ce64..fd8de0b514 100755 --- a/targets/TEST/PDCP/Makefile +++ b/targets/TEST/PDCP/Makefile @@ -8,7 +8,7 @@ OPENAIR3 = $(OPENAIR3_DIR) EXE_FILE_NAME = test_pdcp -CFLAGS += -m32 -DPHYSIM -DNODE_RG -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DNODE_RG -DPC_TARGET -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/PDCP/with_rlc/Makefile.data_bearer b/targets/TEST/PDCP/with_rlc/Makefile.data_bearer index 3f7d841d6a..fa7add3c14 100755 --- a/targets/TEST/PDCP/with_rlc/Makefile.data_bearer +++ b/targets/TEST/PDCP/with_rlc/Makefile.data_bearer @@ -8,7 +8,7 @@ OPENAIR3 = $(OPENAIR3_DIR) EXE_FILE_NAME = test_pdcp_rlc -CFLAGS += -m32 -DPHYSIM -DNODE_RG -DPC_TARGET -DPC_DSP -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DNODE_RG -DPC_TARGET -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES From 2157727f5feee3d5c19deb866ae983e2ec0e8d81 Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 11:10:05 +0100 Subject: [PATCH 147/284] Fix #582, PC_TARGET removed --- cmake_targets/CMakeLists.txt | 1 - cmake_targets/epc_test/CMakeLists.template | 1 - cmake_targets/oaisim_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_mme_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_noS1_build_oai/CMakeLists.template | 1 - cmake_targets/s1c_mme_test/CMakeLists.template | 1 - common/utils/telnetsrv/CMakeLists.txt | 2 +- openair1/PHY/CODING/TESTBENCH/Makefile | 2 +- openair2/UTIL/OCG/makefile | 2 +- openair2/UTIL/OMG/makefile | 2 +- openair2/UTIL/OMG/makefile_old | 2 +- targets/TEST/AT_COMMANDS/Makefile | 2 +- targets/TEST/PACKET_TRACER/Makefile | 2 +- targets/TEST/PDCP/Makefile | 2 +- targets/TEST/PDCP/with_rlc/Makefile.data_bearer | 2 +- 15 files changed, 9 insertions(+), 15 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 1540bb56c9..7fda949c4f 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -631,7 +631,6 @@ add_integer_option(MAX_NUM_CCs 1 "????") add_boolean_option(MU_RECEIVER False "????") add_boolean_option(NEW_FFT True "????") add_boolean_option(OPENAIR1 True "????") -add_boolean_option(PC_TARGET True "????") add_boolean_option(PERFECT_CE False "????") add_boolean_option(PHYSIM True "for L1 simulators (dlsim, ulsim, ...)") add_boolean_option(PHY_CONTEXT True "not clear: must remain False for dlsim") diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index 14b5862320..540bf5064e 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -49,7 +49,6 @@ set ( OPENAIR2 True ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "epc_test" ) set ( PDCP_USE_NETLINK True ) -set ( PC_TARGET True ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) set ( PHY_CONTEXT False ) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index b600f6f616..48fcad8783 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -48,7 +48,6 @@ set ( OPENAIR2 True ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) set ( PDCP_USE_NETLINK True ) -set ( PC_TARGET True ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) set ( PHY_CONTEXT False ) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index fe398b9275..68b238cc27 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -49,7 +49,6 @@ set ( OPENAIR2 False ) set ( OPENAIR_EMU False ) set ( OPENAIR_LTE False ) set ( PACKAGE_NAME "EPC" ) -set ( PC_TARGET False ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) set ( PHY_CONTEXT False ) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 7d0b5b0268..15a3b4d9aa 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -50,7 +50,6 @@ set ( OPENAIR_EMU False ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) set ( PDCP_USE_NETLINK True ) -set ( PC_TARGET True ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) set ( PHY_CONTEXT False ) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index 29b32aa989..d714b83b2b 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -49,7 +49,6 @@ set ( OPENAIR2 True ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) set ( PDCP_USE_NETLINK True ) -set ( PC_TARGET True ) set ( PDCP_MSG_PRINT False ) set ( PERFECT_CE False ) set ( PHY_CONTEXT False ) diff --git a/common/utils/telnetsrv/CMakeLists.txt b/common/utils/telnetsrv/CMakeLists.txt index 8f74fd96ae..61aed72029 100644 --- a/common/utils/telnetsrv/CMakeLists.txt +++ b/common/utils/telnetsrv/CMakeLists.txt @@ -24,7 +24,7 @@ set(OPENAIR_NFAPIINC $ENV{NFAPI_DIR} ) set(CMAKE_INSTALL_PREFIX $ENV{OPENAIR_TARGETS}) -add_definitions (-DRel14 -DCMAKER -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNEW_FFT -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR1 -DOPENAIR2 -DOPENAIR_LTE -DPC_TARGET -DPHYSIM -DPHY_CONTEXT -DPUCCH -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) +add_definitions (-DRel14 -DCMAKER -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNEW_FFT -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR1 -DOPENAIR2 -DOPENAIR_LTE -DPHYSIM -DPHY_CONTEXT -DPUCCH -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) add_compile_options( -fPIC -march=native -Ofast) include_directories( ./ ${OPENAIR_COMMON_DIR} ${OPENAIR_DIR} ${OPENAIR1_DIR} ${OPENAIR2_DIR} ${OPENAIR2_COMMON_DIR} ${OPENAIR2_DIR}/UTIL/LOG diff --git a/openair1/PHY/CODING/TESTBENCH/Makefile b/openair1/PHY/CODING/TESTBENCH/Makefile index 515775a102..79a005cf8c 100644 --- a/openair1/PHY/CODING/TESTBENCH/Makefile +++ b/openair1/PHY/CODING/TESTBENCH/Makefile @@ -7,7 +7,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DNODE_RG -DPC_TARGET -DNO_UL_REF -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DOPENAIR_LTE -DMAX_NUM_CCs=1 +CFLAGS += -DNODE_RG -DNO_UL_REF -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DOPENAIR_LTE -DMAX_NUM_CCs=1 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/openair2/UTIL/OCG/makefile b/openair2/UTIL/OCG/makefile index 585e3ef9c2..00108f56a4 100644 --- a/openair2/UTIL/OCG/makefile +++ b/openair2/UTIL/OCG/makefile @@ -7,7 +7,7 @@ OPENAIR2_TOP = ../../../openair2 OPENAIR3_TOP = ../../../openair3 OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DPHYSIM -DNODE_RG -DPC_TARGET -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat +CFLAGS += -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat CFLAGS += -m32 -DOPENAIR_LTE -DOPENAIR2 #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE diff --git a/openair2/UTIL/OMG/makefile b/openair2/UTIL/OMG/makefile index d3098195e3..73b282f081 100644 --- a/openair2/UTIL/OMG/makefile +++ b/openair2/UTIL/OMG/makefile @@ -60,7 +60,7 @@ OPENAIR2_TOP = ../../../openair2 OPENAIR3_TOP = ../../../openair3 OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DPHYSIM -DNODE_RG -DPC_TARGET -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat +CFLAGS += -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat CFLAGS += -DOPENAIR_LTE -DOPENAIR2 #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE diff --git a/openair2/UTIL/OMG/makefile_old b/openair2/UTIL/OMG/makefile_old index d779a186ab..13da3a6101 100644 --- a/openair2/UTIL/OMG/makefile_old +++ b/openair2/UTIL/OMG/makefile_old @@ -62,7 +62,7 @@ OPENAIR2_TOP = ../../../openair2 OPENAIR3_TOP = ../../../openair3 OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DPHYSIM -DNODE_RG -DPC_TARGET -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat +CFLAGS += -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat CFLAGS += -DOPENAIR_LTE -DOPENAIR2 #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE diff --git a/targets/TEST/AT_COMMANDS/Makefile b/targets/TEST/AT_COMMANDS/Makefile index 0d3e6994ae..1e54e9d950 100755 --- a/targets/TEST/AT_COMMANDS/Makefile +++ b/targets/TEST/AT_COMMANDS/Makefile @@ -6,7 +6,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3_TOP = $(OPENAIR3_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -m32 -DPHYSIM -DNODE_RG -DPC_TARGET -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/PACKET_TRACER/Makefile b/targets/TEST/PACKET_TRACER/Makefile index 0a656e1b36..53efdae1e5 100755 --- a/targets/TEST/PACKET_TRACER/Makefile +++ b/targets/TEST/PACKET_TRACER/Makefile @@ -6,7 +6,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3_TOP = $(OPENAIR3_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -m32 -DPHYSIM -DPC_TARGET -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/PDCP/Makefile b/targets/TEST/PDCP/Makefile index fd8de0b514..1d299ee6b5 100755 --- a/targets/TEST/PDCP/Makefile +++ b/targets/TEST/PDCP/Makefile @@ -8,7 +8,7 @@ OPENAIR3 = $(OPENAIR3_DIR) EXE_FILE_NAME = test_pdcp -CFLAGS += -m32 -DPHYSIM -DNODE_RG -DPC_TARGET -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/PDCP/with_rlc/Makefile.data_bearer b/targets/TEST/PDCP/with_rlc/Makefile.data_bearer index fa7add3c14..50686b0bb3 100755 --- a/targets/TEST/PDCP/with_rlc/Makefile.data_bearer +++ b/targets/TEST/PDCP/with_rlc/Makefile.data_bearer @@ -8,7 +8,7 @@ OPENAIR3 = $(OPENAIR3_DIR) EXE_FILE_NAME = test_pdcp_rlc -CFLAGS += -m32 -DPHYSIM -DNODE_RG -DPC_TARGET -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES From f44064a221fceae7cf709d611e09214228bcb89f Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 11:16:49 +0100 Subject: [PATCH 148/284] Fix #582, NEW_FFT removed --- cmake_targets/CMakeLists.txt | 1 - cmake_targets/epc_test/CMakeLists.template | 1 - cmake_targets/oaisim_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_mme_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_noS1_build_oai/CMakeLists.template | 1 - cmake_targets/s1c_mme_test/CMakeLists.template | 1 - common/utils/telnetsrv/CMakeLists.txt | 2 +- targets/SIMU/USER/Makefile | 1 - targets/TEST/RLC_AM_V9.3.0/Makefile | 1 - targets/TEST/RLC_UM_V9.3.0/Makefile | 1 - 10 files changed, 1 insertion(+), 10 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 7fda949c4f..cfa4948dda 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -629,7 +629,6 @@ add_boolean_option(LARGE_SCALE False "specific to oaisim: defines ma add_boolean_option(LOCALIZATION False "???") add_integer_option(MAX_NUM_CCs 1 "????") add_boolean_option(MU_RECEIVER False "????") -add_boolean_option(NEW_FFT True "????") add_boolean_option(OPENAIR1 True "????") add_boolean_option(PERFECT_CE False "????") add_boolean_option(PHYSIM True "for L1 simulators (dlsim, ulsim, ...)") diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index 540bf5064e..d7e7f0a9c1 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -39,7 +39,6 @@ set ( NAS_UE True ) set ( NB_ANTENNAS_RX "2" ) set ( NB_ANTENNAS_TX "2" ) set ( NB_ANTENNAS_TXRX "2" ) -set ( NEW_FFT True ) set ( NO_RRM True ) set ( OAISIM False ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index 48fcad8783..49f94d0aaa 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -38,7 +38,6 @@ set ( NAS_UE True ) set ( NB_ANTENNAS_RX "2" ) set ( NB_ANTENNAS_TX "2" ) set ( NB_ANTENNAS_TXRX "2" ) -set ( NEW_FFT True ) set ( NO_RRM True ) set ( OAISIM True ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index 68b238cc27..ca05b50ae0 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -39,7 +39,6 @@ set ( NAS_UE False ) set ( NB_ANTENNAS_RX "2" ) set ( NB_ANTENNAS_TX "2" ) set ( NB_ANTENNAS_TXRX "2" ) -set ( NEW_FFT False ) set ( NO_RRM False ) set ( OAISIM False ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 15a3b4d9aa..13516a77e8 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -39,7 +39,6 @@ set ( NAS_UE False ) set ( NB_ANTENNAS_RX "2" ) set ( NB_ANTENNAS_TX "2" ) set ( NB_ANTENNAS_TXRX "2" ) -set ( NEW_FFT True ) set ( NO_RRM True ) set ( OAISIM True ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index d714b83b2b..c7f58957a7 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -39,7 +39,6 @@ set ( NAS_UE True ) set ( NB_ANTENNAS_RX "2" ) set ( NB_ANTENNAS_TX "2" ) set ( NB_ANTENNAS_TXRX "2" ) -set ( NEW_FFT True ) set ( NO_RRM True ) set ( OAISIM True ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) diff --git a/common/utils/telnetsrv/CMakeLists.txt b/common/utils/telnetsrv/CMakeLists.txt index 61aed72029..0fb0dbe78f 100644 --- a/common/utils/telnetsrv/CMakeLists.txt +++ b/common/utils/telnetsrv/CMakeLists.txt @@ -24,7 +24,7 @@ set(OPENAIR_NFAPIINC $ENV{NFAPI_DIR} ) set(CMAKE_INSTALL_PREFIX $ENV{OPENAIR_TARGETS}) -add_definitions (-DRel14 -DCMAKER -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNEW_FFT -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR1 -DOPENAIR2 -DOPENAIR_LTE -DPHYSIM -DPHY_CONTEXT -DPUCCH -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) +add_definitions (-DRel14 -DCMAKER -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR1 -DOPENAIR2 -DOPENAIR_LTE -DPHYSIM -DPHY_CONTEXT -DPUCCH -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) add_compile_options( -fPIC -march=native -Ofast) include_directories( ./ ${OPENAIR_COMMON_DIR} ${OPENAIR_DIR} ${OPENAIR1_DIR} ${OPENAIR2_DIR} ${OPENAIR2_COMMON_DIR} ${OPENAIR2_DIR}/UTIL/LOG diff --git a/targets/SIMU/USER/Makefile b/targets/SIMU/USER/Makefile index 0b0d8b9f6d..49127cf25d 100644 --- a/targets/SIMU/USER/Makefile +++ b/targets/SIMU/USER/Makefile @@ -35,7 +35,6 @@ ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES CFLAGS += -DOPENAIR_LTE -DPUCCH #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 #-DRLC_UM_TEST_TRAFFIC=1 -CFLAGS += -DNEW_FFT #CFLAGS += -DLLR8 CFLAGS += -DPACKAGE_NAME='"oaisim"' diff --git a/targets/TEST/RLC_AM_V9.3.0/Makefile b/targets/TEST/RLC_AM_V9.3.0/Makefile index 231ab9592e..dcbea85909 100755 --- a/targets/TEST/RLC_AM_V9.3.0/Makefile +++ b/targets/TEST/RLC_AM_V9.3.0/Makefile @@ -14,7 +14,6 @@ ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES CFLAGS += -DOPENAIR_LTE -DPUCCH #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 #-DRLC_UM_TEST_TRAFFIC=1 -CFLAGS += -DNEW_FFT #CFLAGS += -DLLR8 ifndef OPENAIR2 diff --git a/targets/TEST/RLC_UM_V9.3.0/Makefile b/targets/TEST/RLC_UM_V9.3.0/Makefile index 8c759c6bdc..dc4d0de16d 100755 --- a/targets/TEST/RLC_UM_V9.3.0/Makefile +++ b/targets/TEST/RLC_UM_V9.3.0/Makefile @@ -14,7 +14,6 @@ ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES CFLAGS += -DOPENAIR_LTE -DPUCCH #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 #-DRLC_UM_TEST_TRAFFIC=1 -CFLAGS += -DNEW_FFT #CFLAGS += -DLLR8 ifndef OPENAIR2 From f4d19c0d637c4d3c3a3b62d31e4a079b25f8c5b8 Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 11:22:45 +0100 Subject: [PATCH 149/284] Fix #582, PERFECT_CE removed --- cmake_targets/CMakeLists.txt | 1 - cmake_targets/epc_test/CMakeLists.template | 1 - cmake_targets/lte-simulators/CMakeLists.txt | 1 - cmake_targets/oaisim_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_mme_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_noS1_build_oai/CMakeLists.template | 1 - cmake_targets/s1c_mme_test/CMakeLists.template | 1 - 7 files changed, 7 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index cfa4948dda..627ed13f0c 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -630,7 +630,6 @@ add_boolean_option(LOCALIZATION False "???") add_integer_option(MAX_NUM_CCs 1 "????") add_boolean_option(MU_RECEIVER False "????") add_boolean_option(OPENAIR1 True "????") -add_boolean_option(PERFECT_CE False "????") add_boolean_option(PHYSIM True "for L1 simulators (dlsim, ulsim, ...)") add_boolean_option(PHY_CONTEXT True "not clear: must remain False for dlsim") add_boolean_option(PHY_EMUL False "not clear: must remain False for dlsim") diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index d7e7f0a9c1..4755e3d646 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -49,7 +49,6 @@ set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "epc_test" ) set ( PDCP_USE_NETLINK True ) set ( PDCP_MSG_PRINT False ) -set ( PERFECT_CE False ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) diff --git a/cmake_targets/lte-simulators/CMakeLists.txt b/cmake_targets/lte-simulators/CMakeLists.txt index 4b9cba7379..198ba49a9c 100644 --- a/cmake_targets/lte-simulators/CMakeLists.txt +++ b/cmake_targets/lte-simulators/CMakeLists.txt @@ -7,7 +7,6 @@ set(ENABLE_ITTI False) set(DEBUG_PHY False) set(MU_RECIEVER False) set(RANDOM_BF False) -set(PERFECT_CE True) set(NAS_UE False) set(MESSAGE_CHART_GENERATOR False) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index 49f94d0aaa..511cc68583 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -48,7 +48,6 @@ set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) set ( PDCP_USE_NETLINK True ) set ( PDCP_MSG_PRINT False ) -set ( PERFECT_CE False ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index ca05b50ae0..efc98faedd 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -49,7 +49,6 @@ set ( OPENAIR_EMU False ) set ( OPENAIR_LTE False ) set ( PACKAGE_NAME "EPC" ) set ( PDCP_MSG_PRINT False ) -set ( PERFECT_CE False ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM False ) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 13516a77e8..4c7489a08a 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -50,7 +50,6 @@ set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) set ( PDCP_USE_NETLINK True ) set ( PDCP_MSG_PRINT False ) -set ( PERFECT_CE False ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index c7f58957a7..f425f14185 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -49,7 +49,6 @@ set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) set ( PDCP_USE_NETLINK True ) set ( PDCP_MSG_PRINT False ) -set ( PERFECT_CE False ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) From 7943ea92d1858c1c5c523318ac7aa1b2cba5e99d Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 11:27:34 +0100 Subject: [PATCH 150/284] Fix #582, RANDOM_BF removed --- cmake_targets/CMakeLists.txt | 1 - cmake_targets/epc_test/CMakeLists.template | 1 - cmake_targets/lte-simulators/CMakeLists.txt | 1 - cmake_targets/oaisim_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_mme_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_noS1_build_oai/CMakeLists.template | 1 - cmake_targets/s1c_mme_test/CMakeLists.template | 1 - 7 files changed, 7 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 627ed13f0c..001d14add2 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -634,7 +634,6 @@ add_boolean_option(PHYSIM True "for L1 simulators (dlsim, ulsi add_boolean_option(PHY_CONTEXT True "not clear: must remain False for dlsim") add_boolean_option(PHY_EMUL False "not clear: must remain False for dlsim") add_boolean_option(PUCCH True "????") -add_boolean_option(RANDOM_BF False "????") add_boolean_option(SMBV False "Rohde&Schwarz SMBV100A vector signal generator") add_boolean_option(DEBUG_PHY False "Enable PHY layer debugging options") add_boolean_option(DEBUG_PHY_PROC False "Enable debugging of PHY layer procedures") diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index 4755e3d646..aec0caaa3b 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -53,7 +53,6 @@ set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) set ( PUCCH True ) -set ( RANDOM_BF False ) set ( RF_BOARD "False" ) set ( RLC_STOP_ON_LOST_PDU False ) set ( RRC_ASN1_VERSION "Rel10" ) diff --git a/cmake_targets/lte-simulators/CMakeLists.txt b/cmake_targets/lte-simulators/CMakeLists.txt index 198ba49a9c..ca754449d7 100644 --- a/cmake_targets/lte-simulators/CMakeLists.txt +++ b/cmake_targets/lte-simulators/CMakeLists.txt @@ -6,7 +6,6 @@ set(XFORMS True) set(ENABLE_ITTI False) set(DEBUG_PHY False) set(MU_RECIEVER False) -set(RANDOM_BF False) set(NAS_UE False) set(MESSAGE_CHART_GENERATOR False) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index 511cc68583..4df8056c6e 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -52,7 +52,6 @@ set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) set ( PUCCH True ) -set ( RANDOM_BF False ) set ( RF_BOARD "False" ) set ( RLC_STOP_ON_LOST_PDU False ) set ( RRC_ASN1_VERSION "Rel10" ) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index efc98faedd..618468d295 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -53,7 +53,6 @@ set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM False ) set ( PUCCH False ) -set ( RANDOM_BF False ) set ( RF_BOARD "False" ) set ( RRC_ASN1_VERSION "Rel10" ) set ( RLC_STOP_ON_LOST_PDU False ) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 4c7489a08a..dec2f7b277 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -54,7 +54,6 @@ set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) set ( PUCCH True ) -set ( RANDOM_BF False ) set ( RF_BOARD "False" ) set ( RRC_ASN1_VERSION "Rel10" ) set ( RLC_STOP_ON_LOST_PDU False ) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index f425f14185..c9ef0ec3f2 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -53,7 +53,6 @@ set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) set ( PUCCH True ) -set ( RANDOM_BF False ) set ( RF_BOARD "False" ) set ( RLC_STOP_ON_LOST_PDU False ) set ( RRC_ASN1_VERSION "Rel10" ) From ea3aff84e9a94915714d666e1e8163af99ac5ac3 Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 11:33:45 +0100 Subject: [PATCH 151/284] Fix #582, PUCCH removed --- cmake_targets/CMakeLists.txt | 1 - cmake_targets/epc_test/CMakeLists.template | 1 - cmake_targets/oaisim_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_mme_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_noS1_build_oai/CMakeLists.template | 1 - cmake_targets/s1c_mme_test/CMakeLists.template | 1 - common/utils/telnetsrv/CMakeLists.txt | 2 +- targets/SIMU/USER/Makefile | 2 +- targets/TEST/PACKET_TRACER/Makefile | 2 +- targets/TEST/RLC_AM_V9.3.0/Makefile | 2 +- targets/TEST/RLC_UM_V9.3.0/Makefile | 2 +- 11 files changed, 5 insertions(+), 11 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 001d14add2..b36beb035f 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -633,7 +633,6 @@ add_boolean_option(OPENAIR1 True "????") add_boolean_option(PHYSIM True "for L1 simulators (dlsim, ulsim, ...)") add_boolean_option(PHY_CONTEXT True "not clear: must remain False for dlsim") add_boolean_option(PHY_EMUL False "not clear: must remain False for dlsim") -add_boolean_option(PUCCH True "????") add_boolean_option(SMBV False "Rohde&Schwarz SMBV100A vector signal generator") add_boolean_option(DEBUG_PHY False "Enable PHY layer debugging options") add_boolean_option(DEBUG_PHY_PROC False "Enable debugging of PHY layer procedures") diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index aec0caaa3b..35d478828b 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -52,7 +52,6 @@ set ( PDCP_MSG_PRINT False ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) -set ( PUCCH True ) set ( RF_BOARD "False" ) set ( RLC_STOP_ON_LOST_PDU False ) set ( RRC_ASN1_VERSION "Rel10" ) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index 4df8056c6e..20863eeab5 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -51,7 +51,6 @@ set ( PDCP_MSG_PRINT False ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) -set ( PUCCH True ) set ( RF_BOARD "False" ) set ( RLC_STOP_ON_LOST_PDU False ) set ( RRC_ASN1_VERSION "Rel10" ) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index 618468d295..9ce736d818 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -52,7 +52,6 @@ set ( PDCP_MSG_PRINT False ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM False ) -set ( PUCCH False ) set ( RF_BOARD "False" ) set ( RRC_ASN1_VERSION "Rel10" ) set ( RLC_STOP_ON_LOST_PDU False ) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index dec2f7b277..6dd0f2ffca 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -53,7 +53,6 @@ set ( PDCP_MSG_PRINT False ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) -set ( PUCCH True ) set ( RF_BOARD "False" ) set ( RRC_ASN1_VERSION "Rel10" ) set ( RLC_STOP_ON_LOST_PDU False ) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index c9ef0ec3f2..cf5e6b241b 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -52,7 +52,6 @@ set ( PDCP_MSG_PRINT False ) set ( PHY_CONTEXT False ) set ( PHY_EMUL False ) set ( PHYSIM True ) -set ( PUCCH True ) set ( RF_BOARD "False" ) set ( RLC_STOP_ON_LOST_PDU False ) set ( RRC_ASN1_VERSION "Rel10" ) diff --git a/common/utils/telnetsrv/CMakeLists.txt b/common/utils/telnetsrv/CMakeLists.txt index 0fb0dbe78f..ee58aaec93 100644 --- a/common/utils/telnetsrv/CMakeLists.txt +++ b/common/utils/telnetsrv/CMakeLists.txt @@ -24,7 +24,7 @@ set(OPENAIR_NFAPIINC $ENV{NFAPI_DIR} ) set(CMAKE_INSTALL_PREFIX $ENV{OPENAIR_TARGETS}) -add_definitions (-DRel14 -DCMAKER -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR1 -DOPENAIR2 -DOPENAIR_LTE -DPHYSIM -DPHY_CONTEXT -DPUCCH -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) +add_definitions (-DRel14 -DCMAKER -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR1 -DOPENAIR2 -DOPENAIR_LTE -DPHYSIM -DPHY_CONTEXT -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) add_compile_options( -fPIC -march=native -Ofast) include_directories( ./ ${OPENAIR_COMMON_DIR} ${OPENAIR_DIR} ${OPENAIR1_DIR} ${OPENAIR2_DIR} ${OPENAIR2_COMMON_DIR} ${OPENAIR2_DIR}/UTIL/LOG diff --git a/targets/SIMU/USER/Makefile b/targets/SIMU/USER/Makefile index 49127cf25d..ba81d0e6a7 100644 --- a/targets/SIMU/USER/Makefile +++ b/targets/SIMU/USER/Makefile @@ -33,7 +33,7 @@ CFLAGS += -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 $(CPUFLAGS) ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES -CFLAGS += -DOPENAIR_LTE -DPUCCH #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE +CFLAGS += -DOPENAIR_LTE #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 #-DRLC_UM_TEST_TRAFFIC=1 #CFLAGS += -DLLR8 CFLAGS += -DPACKAGE_NAME='"oaisim"' diff --git a/targets/TEST/PACKET_TRACER/Makefile b/targets/TEST/PACKET_TRACER/Makefile index 53efdae1e5..7b857ca3b9 100755 --- a/targets/TEST/PACKET_TRACER/Makefile +++ b/targets/TEST/PACKET_TRACER/Makefile @@ -10,7 +10,7 @@ CFLAGS += -m32 -DPHYSIM -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES -CFLAGS += -DOPENAIR_LTE -DPUCCH #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE +CFLAGS += -DOPENAIR_LTE #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 CFLAGS += -DEMIT_ASN_DEBUG=1 ifndef OPENAIR2 diff --git a/targets/TEST/RLC_AM_V9.3.0/Makefile b/targets/TEST/RLC_AM_V9.3.0/Makefile index dcbea85909..dde20a7b42 100755 --- a/targets/TEST/RLC_AM_V9.3.0/Makefile +++ b/targets/TEST/RLC_AM_V9.3.0/Makefile @@ -12,7 +12,7 @@ CFLAGS += -m32 -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES -CFLAGS += -DOPENAIR_LTE -DPUCCH #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE +CFLAGS += -DOPENAIR_LTE #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 #-DRLC_UM_TEST_TRAFFIC=1 #CFLAGS += -DLLR8 diff --git a/targets/TEST/RLC_UM_V9.3.0/Makefile b/targets/TEST/RLC_UM_V9.3.0/Makefile index dc4d0de16d..57002dad21 100755 --- a/targets/TEST/RLC_UM_V9.3.0/Makefile +++ b/targets/TEST/RLC_UM_V9.3.0/Makefile @@ -12,7 +12,7 @@ CFLAGS += -m32 -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES -CFLAGS += -DOPENAIR_LTE -DPUCCH #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE +CFLAGS += -DOPENAIR_LTE #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE CFLAGS += -DMAC_CONTEXT=1 -DPHY_CONTEXT=1 #-DRLC_UM_TEST_TRAFFIC=1 #CFLAGS += -DLLR8 From da7a4a19cdc150e6c5a99b6604dc9df010d74828 Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 11:39:16 +0100 Subject: [PATCH 152/284] Fix #582, HARD_RT removed --- cmake_targets/CMakeLists.txt | 1 - cmake_targets/epc_test/CMakeLists.template | 1 - cmake_targets/oaisim_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_mme_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_noS1_build_oai/CMakeLists.template | 1 - cmake_targets/s1c_mme_test/CMakeLists.template | 1 - 6 files changed, 6 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index b36beb035f..f1e3837d67 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -613,7 +613,6 @@ add_boolean_option(ENB_MODE True "Swap the include directories between openair2 add_boolean_option(ENABLE_USE_CPU_EXECUTION_TIME True "Add data in vcd traces: disable it if perf issues") add_boolean_option(ENABLE_VCD True "always true now, time measurements of proc calls and var displays") add_boolean_option(ENABLE_VCD_FIFO True "time measurements of proc calls and var displays sent to FIFO (one more thread)") -add_boolean_option(HARD_RT False "???") add_boolean_option(LINUX False "used in weird memcpy() in pdcp.c ???") add_boolean_option(LINUX_LIST False "used only in lists.c: either use OAI implementation of lists or Linux one (should be True, but it is False") add_boolean_option(LOG_NO_THREAD True "Disable thread for log, seems always set to true") diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index 35d478828b..52016d1391 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -17,7 +17,6 @@ set ( ENABLE_USE_RAW_SOCKET_FOR_SGI True) set ( ENABLE_VCD_FIFO False ) set ( ENB_MODE True ) set ( EXMIMO_IOT True ) -set ( HARD_RT False ) set ( JUMBO_FRAME True ) set ( LARGE_SCALE False ) set ( LINK_ENB_PDCP_TO_GTPV1U True) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index 20863eeab5..68fe8b0f1c 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -16,7 +16,6 @@ set ( ENABLE_USE_RAW_SOCKET_FOR_SGI True) set ( ENABLE_VCD_FIFO False ) set ( ENB_MODE True ) set ( EXMIMO_IOT True ) -set ( HARD_RT False ) set ( JUMBO_FRAME True ) set ( LARGE_SCALE False ) set ( LINK_ENB_PDCP_TO_GTPV1U True) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index 9ce736d818..98ee8a950e 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -17,7 +17,6 @@ set ( ENABLE_VCD_FIFO False ) set ( ENB_MODE False ) set ( EPC_BUILD True ) set ( EXMIMO_IOT False ) -set ( HARD_RT False ) set ( JUMBO_FRAME False ) set ( LARGE_SCALE False ) set ( LINK_ENB_PDCP_TO_GTPV1U True) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 6dd0f2ffca..9067390a0c 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -15,7 +15,6 @@ set ( ENABLE_USE_RAW_SOCKET_FOR_SGI False) set ( ENABLE_VCD_FIFO False ) set ( ENB_MODE True ) set ( EXMIMO_IOT True ) -set ( HARD_RT False ) set ( JUMBO_FRAME True ) set ( LARGE_SCALE False ) set ( LINK_ENB_PDCP_TO_GTPV1U False) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index cf5e6b241b..f54d35cd46 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -17,7 +17,6 @@ set ( ENABLE_USE_RAW_SOCKET_FOR_SGI True) set ( ENABLE_VCD_FIFO False ) set ( ENB_MODE True ) set ( EXMIMO_IOT True ) -set ( HARD_RT False ) set ( JUMBO_FRAME True ) set ( LARGE_SCALE False ) set ( LINK_ENB_PDCP_TO_GTPV1U True) From 339905d191f30ea696f705681f402d0b5c266774 Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 12:11:33 +0100 Subject: [PATCH 153/284] Fix #582, OPENAIR1, NO_OPENAIR1 removed --- cmake_targets/CMakeLists.txt | 1 - common/utils/telnetsrv/CMakeLists.txt | 2 +- openair1/PHY/CODING/defs.h | 4 ---- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index f1e3837d67..c55194452f 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -628,7 +628,6 @@ add_boolean_option(LARGE_SCALE False "specific to oaisim: defines ma add_boolean_option(LOCALIZATION False "???") add_integer_option(MAX_NUM_CCs 1 "????") add_boolean_option(MU_RECEIVER False "????") -add_boolean_option(OPENAIR1 True "????") add_boolean_option(PHYSIM True "for L1 simulators (dlsim, ulsim, ...)") add_boolean_option(PHY_CONTEXT True "not clear: must remain False for dlsim") add_boolean_option(PHY_EMUL False "not clear: must remain False for dlsim") diff --git a/common/utils/telnetsrv/CMakeLists.txt b/common/utils/telnetsrv/CMakeLists.txt index ee58aaec93..1e6d3a06f3 100644 --- a/common/utils/telnetsrv/CMakeLists.txt +++ b/common/utils/telnetsrv/CMakeLists.txt @@ -24,7 +24,7 @@ set(OPENAIR_NFAPIINC $ENV{NFAPI_DIR} ) set(CMAKE_INSTALL_PREFIX $ENV{OPENAIR_TARGETS}) -add_definitions (-DRel14 -DCMAKER -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR1 -DOPENAIR2 -DOPENAIR_LTE -DPHYSIM -DPHY_CONTEXT -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) +add_definitions (-DRel14 -DCMAKER -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR2 -DOPENAIR_LTE -DPHYSIM -DPHY_CONTEXT -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) add_compile_options( -fPIC -march=native -Ofast) include_directories( ./ ${OPENAIR_COMMON_DIR} ${OPENAIR_DIR} ${OPENAIR1_DIR} ${OPENAIR2_DIR} ${OPENAIR2_COMMON_DIR} ${OPENAIR2_DIR}/UTIL/LOG diff --git a/openair1/PHY/CODING/defs.h b/openair1/PHY/CODING/defs.h index 06311a188b..80e28b1586 100644 --- a/openair1/PHY/CODING/defs.h +++ b/openair1/PHY/CODING/defs.h @@ -29,11 +29,7 @@ #include -#ifndef NO_OPENAIR1 #include "PHY/defs.h" -#else -#include "PHY/TOOLS/time_meas.h" -#endif #define CRC24_A 0 #define CRC24_B 1 From 28497cae6fdf8bb75ba11b59dd42b34589203663 Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 12:15:21 +0100 Subject: [PATCH 154/284] Fix #582, SPECTRA removed --- cmake_targets/CMakeLists.txt | 1 - cmake_targets/oaisim_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_mme_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_noS1_build_oai/CMakeLists.template | 1 - cmake_targets/s1c_mme_test/CMakeLists.template | 1 - 5 files changed, 5 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index c55194452f..26bab40da1 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -707,7 +707,6 @@ add_boolean_option(RRC_DEFAULT_RAB_IS_AM False "Otherwise it is UM, confi # PROJECTS (IST, FRENCH COLL., etc) # SPECIFIC OPTIONS ########################## -add_boolean_option(SPECTRA False "???") add_boolean_option(MIH_C_MEDIEVAL_EXTENSIONS False "EXTENSIONS TO MIH 802.21 IN CONTEXT OF IST PROJECT CALLED MEDIEVAL") # add the binary tree to the search path for include files diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index 68fe8b0f1c..2cfdf678f6 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -57,7 +57,6 @@ set ( RRC_DEFAULT_RAB_IS_AM True) set ( RRC_MSG_PRINT False ) set ( SECU False ) set ( SMBV False ) -set ( SPECTRA False ) set ( TEST_OMG False ) set ( USE_3GPP_ADDR_AS_LINK_ADDR False ) set ( USE_MME "R10" ) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index 98ee8a950e..ffa3773b82 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -57,7 +57,6 @@ set ( RLC_STOP_ON_LOST_PDU False ) set ( RRC_MSG_PRINT False ) set ( SECU False ) set ( SMBV False ) -set ( SPECTRA False ) set ( TEST_OMG False ) set ( UPDATE_RELEASE_9 True) set ( UPDATE_RELEASE_10 True) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 9067390a0c..4c1823af14 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -58,7 +58,6 @@ set ( RLC_STOP_ON_LOST_PDU False ) set ( RRC_MSG_PRINT False ) set ( SECU False ) set ( SMBV False ) -set ( SPECTRA False ) set ( TEST_OMG False ) set ( USE_3GPP_ADDR_AS_LINK_ADDR False ) set ( USE_MME "R10" ) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index f54d35cd46..e001997efd 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -58,7 +58,6 @@ set ( RRC_DEFAULT_RAB_IS_AM True) set ( RRC_MSG_PRINT False ) set ( SECU False ) set ( SMBV False ) -set ( SPECTRA False ) set ( TEST_OMG False ) set ( TEST_S1C_MME True ) From 88d0b68c7b8b04d320c891c43f7e33230d59f96b Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 12:24:58 +0100 Subject: [PATCH 155/284] Fix #582, MIH_C_MEDIEVAL_EXTENSIONS removed --- cmake_targets/CMakeLists.txt | 36 +++---------------- cmake_targets/epc_test/CMakeLists.template | 1 - .../oaisim_build_oai/CMakeLists.template | 1 - .../oaisim_mme_build_oai/CMakeLists.template | 1 - .../oaisim_noS1_build_oai/CMakeLists.template | 1 - .../s1c_mme_test/CMakeLists.template | 1 - targets/SIMU/USER/Makefile | 2 -- 7 files changed, 5 insertions(+), 38 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 26bab40da1..e6adefdbe2 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -703,12 +703,6 @@ add_boolean_option(RRC_DEFAULT_RAB_IS_AM False "Otherwise it is UM, confi ########################## # none -########################## -# PROJECTS (IST, FRENCH COLL., etc) -# SPECIFIC OPTIONS -########################## -add_boolean_option(MIH_C_MEDIEVAL_EXTENSIONS False "EXTENSIONS TO MIH 802.21 IN CONTEXT OF IST PROJECT CALLED MEDIEVAL") - # add the binary tree to the search path for include files ####################################################### # We will find ConfigOAI.h after generation in target directory @@ -1208,26 +1202,6 @@ if (${ENABLE_RAL}) set(RAL_LIB RAL) endif() -if(${MIH_C_MEDIEVAL_EXTENSIONS}) - set(MIH_SRC - ${RAL_LTE_DIR}INTERFACE-802.21/C/MIH_C_header_codec.c - ${RAL_LTE_DIR}INTERFACE-802.21/C/MIH_C_msg_codec.c - ${RAL_LTE_DIR}INTERFACE-802.21/C/MIH_C_primitive_codec.c - ${RAL_LTE_DIR}INTERFACE-802.21/C/MIH_C_F1_basic_data_types_codec.c - ${RAL_LTE_DIR}INTERFACE-802.21/C/MIH_C_F2_general_data_types_codec.c - ${RAL_LTE_DIR}INTERFACE-802.21/C/MIH_C_F3_data_types_for_address_codec.c - ${RAL_LTE_DIR}INTERFACE-802.21/C/MIH_C_F4_data_types_for_links_codec.c - ${RAL_LTE_DIR}INTERFACE-802.21/C/MIH_C_F9_data_types_for_qos_codec.c - ${RAL_LTE_DIR}INTERFACE-802.21/C/MIH_C_F13_data_types_for_information_elements_codec.c - ${RAL_LTE_DIR}INTERFACE-802.21/C/MIH_C_L2_type_values_for_tlv_encoding.c - ${RAL_LTE_DIR}INTERFACE-802.21/C/MIH_C_Medieval_extensions.c - ${RAL_LTE_DIR}INTERFACE-802.21/C/MIH_C_bit_buffer.c - ${RAL_LTE_DIR}INTERFACE-802.21/C/MIH_C.c - ) - add_library(MIH ${MIH_SRC}) - set(MIH_LIB MIH) -endif() - # CN libs ########################## @@ -1750,7 +1724,7 @@ add_executable(lte-softmodem target_link_libraries (lte-softmodem -ldl -Wl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 + RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 -Wl,--end-group ) target_link_libraries (lte-softmodem ${LIBXML2_LIBRARIES}) @@ -1785,7 +1759,7 @@ add_executable(lte-softmodem-nos1 ) target_link_libraries (lte-softmodem-nos1 -Wl,--start-group - RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 + RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 -Wl,--end-group ) target_link_libraries (lte-softmodem-nos1 ${LIBXML2_LIBRARIES}) @@ -1856,7 +1830,7 @@ add_executable(oaisim target_include_directories(oaisim PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim -Wl,-ldl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB GTPV1U SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} LIB_NAS_UE SIMU SECU_OSA ${ITTI_LIB} ${MIH_LIB} + RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB GTPV1U SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} LIB_NAS_UE SIMU SECU_OSA ${ITTI_LIB} -Wl,--end-group ) target_link_libraries (oaisim ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) @@ -1899,7 +1873,7 @@ add_executable(oaisim_nos1 target_include_directories(oaisim_nos1 PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim_nos1 -Wl,--start-group - RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 + RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SECU_OSA ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 -Wl,--end-group ) target_link_libraries (oaisim_nos1 ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) @@ -2015,7 +1989,7 @@ if (${T_TRACER}) oai_exmimodevif oai_usrpdevif oai_bladerfdevif oai_lmssdrdevif oai_eth_transpro FLPT_MSG ASYNC_IF FLEXRAN_AGENT HASHTABLE MSC UTIL OMG_SUMO SECU_OSA - SECU_CN SCHED_LIB PHY L2 default_sched remote_sched RAL MIH CN_UTILS + SECU_CN SCHED_LIB PHY L2 default_sched remote_sched RAL CN_UTILS GTPV1U SCTP_CLIENT UDP LIB_NAS_UE LFDS LFDS7 SIMU OPENAIR0_LIB) if (TARGET ${i}) add_dependencies(${i} generate_T) diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index 52016d1391..1abdce3773 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -28,7 +28,6 @@ set ( DEADLINE_SCHEDULER False ) set ( MAC_CONTEXT 1 ) set ( MAX_NUM_CCs 1 ) set ( MESSAGE_CHART_GENERATOR False) -set ( MIH_C_MEDIEVAL_EXTENSIONS False ) set ( MSG_PRINT False ) set ( MU_RECEIVER False ) set ( NAS_ADDRESS_FIX False ) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index 2cfdf678f6..d1bbb090eb 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -27,7 +27,6 @@ set ( DEADLINE_SCHEDULER False ) set ( MAC_CONTEXT 1 ) set ( MAX_NUM_CCs 1 ) set ( MESSAGE_CHART_GENERATOR False) -set ( MIH_C_MEDIEVAL_EXTENSIONS False ) set ( MSG_PRINT False ) set ( MU_RECEIVER False ) set ( NAS_ADDRESS_FIX False ) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index ffa3773b82..bfaf064a7c 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -27,7 +27,6 @@ set ( LOG_NO_THREAD False ) set ( DEADLINE_SCHEDULER False ) set ( MAC_CONTEXT 1 ) set ( MAX_NUM_CCs 1 ) -set ( MIH_C_MEDIEVAL_EXTENSIONS False ) set ( MSG_PRINT False ) set ( MU_RECEIVER False ) set ( NAS_ADDRESS_FIX False ) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 4c1823af14..6df721bdde 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -28,7 +28,6 @@ set ( MAX_NUM_CCs 1 ) set ( MESSAGE_CHART_GENERATOR False ) set ( MESSAGE_CHART_GENERATOR_RLC_MAC False ) set ( MESSAGE_CHART_GENERATOR_PHY False ) -set ( MIH_C_MEDIEVAL_EXTENSIONS False ) set ( MSG_PRINT False ) set ( MU_RECEIVER False ) set ( NAS_ADDRESS_FIX True ) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index e001997efd..c84ff9ee3c 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -28,7 +28,6 @@ set ( DEADLINE_SCHEDULER False ) set ( MAC_CONTEXT 1 ) set ( MAX_NUM_CCs 1 ) set ( MESSAGE_CHART_GENERATOR False) -set ( MIH_C_MEDIEVAL_EXTENSIONS False ) set ( MSG_PRINT False ) set ( MU_RECEIVER False ) set ( NAS_ADDRESS_FIX False ) diff --git a/targets/SIMU/USER/Makefile b/targets/SIMU/USER/Makefile index ba81d0e6a7..6e352a9faa 100644 --- a/targets/SIMU/USER/Makefile +++ b/targets/SIMU/USER/Makefile @@ -131,8 +131,6 @@ CFLAGS += -DSTOP_ON_IP_TRAFFIC_OVERLOAD endif -ifeq ($(MIH_C_MEDIEVAL_EXTENSIONS), 1) -CFLAGS += -DMIH_C_MEDIEVAL_EXTENSIONS ifeq ($(USE_3GPP_ADDR_AS_LINK_ADDR), 1) CFLAGS += -DUSE_3GPP_ADDR_AS_LINK_ADDR endif From 8d2f0931a7494dfd872adf4e49d5f32e1ec64062 Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 12:35:56 +0100 Subject: [PATCH 156/284] Fix #582, NB_ANTENNAS_TXRX removed --- cmake_targets/CMakeLists.txt | 1 - cmake_targets/epc_test/CMakeLists.template | 1 - cmake_targets/oaisim_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_mme_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_noS1_build_oai/CMakeLists.template | 1 - cmake_targets/s1c_mme_test/CMakeLists.template | 1 - common/utils/telnetsrv/CMakeLists.txt | 2 +- openair1/PHY/CODING/TESTBENCH/Makefile | 2 +- openair2/UTIL/OCG/makefile | 2 +- openair2/UTIL/OMG/makefile | 2 +- openair2/UTIL/OMG/makefile_old | 2 +- targets/SIMU/USER/Makefile | 2 +- targets/TEST/AT_COMMANDS/Makefile | 2 +- targets/TEST/PACKET_TRACER/Makefile | 2 +- targets/TEST/PDCP/Makefile | 2 +- targets/TEST/PDCP/with_rlc/Makefile.data_bearer | 2 +- targets/TEST/RLC_AM_V9.3.0/Makefile | 2 +- targets/TEST/RLC_UM_V9.3.0/Makefile | 2 +- 18 files changed, 12 insertions(+), 18 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index e6adefdbe2..0e5d4d025a 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -482,7 +482,6 @@ include_directories ("${X2AP_DIR}") ################################### add_list1_option(NB_ANTENNAS_RX "2" "Number of antennas in reception" "1" "2" "4") add_list1_option(NB_ANTENNAS_TX "4" "Number of antennas in transmission" "1" "2" "4") -add_list1_option(NB_ANTENNAS_TXRX "2" "Number of antennas in ????" "1" "2" "4") add_list2_option(RF_BOARD "EXMIMO" "RF head type" "None" "EXMIMO" "OAI_USRP" "OAI_BLADERF" "CPRIGW" "OAI_LMSSDR") diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index 1abdce3773..2ef6c86d31 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -36,7 +36,6 @@ set ( NAS_MME False ) set ( NAS_UE True ) set ( NB_ANTENNAS_RX "2" ) set ( NB_ANTENNAS_TX "2" ) -set ( NB_ANTENNAS_TXRX "2" ) set ( NO_RRM True ) set ( OAISIM False ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index d1bbb090eb..8929ec14b9 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -35,7 +35,6 @@ set ( NAS_MME False ) set ( NAS_UE True ) set ( NB_ANTENNAS_RX "2" ) set ( NB_ANTENNAS_TX "2" ) -set ( NB_ANTENNAS_TXRX "2" ) set ( NO_RRM True ) set ( OAISIM True ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index bfaf064a7c..29331803e7 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -36,7 +36,6 @@ set ( NAS_NETLINK False ) set ( NAS_UE False ) set ( NB_ANTENNAS_RX "2" ) set ( NB_ANTENNAS_TX "2" ) -set ( NB_ANTENNAS_TXRX "2" ) set ( NO_RRM False ) set ( OAISIM False ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 6df721bdde..362cc70026 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -36,7 +36,6 @@ set ( NAS_MME False ) set ( NAS_UE False ) set ( NB_ANTENNAS_RX "2" ) set ( NB_ANTENNAS_TX "2" ) -set ( NB_ANTENNAS_TXRX "2" ) set ( NO_RRM True ) set ( OAISIM True ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index c84ff9ee3c..b0b58baaec 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -36,7 +36,6 @@ set ( NAS_MME False ) set ( NAS_UE True ) set ( NB_ANTENNAS_RX "2" ) set ( NB_ANTENNAS_TX "2" ) -set ( NB_ANTENNAS_TXRX "2" ) set ( NO_RRM True ) set ( OAISIM True ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) diff --git a/common/utils/telnetsrv/CMakeLists.txt b/common/utils/telnetsrv/CMakeLists.txt index 1e6d3a06f3..bc4a550742 100644 --- a/common/utils/telnetsrv/CMakeLists.txt +++ b/common/utils/telnetsrv/CMakeLists.txt @@ -24,7 +24,7 @@ set(OPENAIR_NFAPIINC $ENV{NFAPI_DIR} ) set(CMAKE_INSTALL_PREFIX $ENV{OPENAIR_TARGETS}) -add_definitions (-DRel14 -DCMAKER -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNB_ANTENNAS_TXRX=2 -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR2 -DOPENAIR_LTE -DPHYSIM -DPHY_CONTEXT -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) +add_definitions (-DRel14 -DCMAKER -DENABLE_ITTI -DENABLE_NAS_UE_LOGGING -DENABLE_SECURITY -DENABLE_USE_CPU_EXECUTION_TIME -DENABLE_USE_MME -DENABLE_VCD -DENB_AGENT -DENB_MODE -DETHERNET=1 -DEXMIMO_IOT -DJUMBO_FRAME -DLINK_ENB_PDCP_TO_GTPV1U -DLOG_NO_THREAD -DMAC_CONTEXT -DMAX_NUM_CCs=1 -DNAS_BUILT_IN_UE -DNAS_UE -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DNO_RRM -DNone=1 -DOAI_NW_DRIVER_USE_NETLINK -DOPENAIR2 -DOPENAIR_LTE -DPHYSIM -DPHY_CONTEXT -DRel10=1 -DS1AP_VERSION=R10 -DTRACE_RLC_MUTEX -DX2AP_VERSION=R11 -DXFORMS -mavx2 -msse4.1 -mssse3) add_compile_options( -fPIC -march=native -Ofast) include_directories( ./ ${OPENAIR_COMMON_DIR} ${OPENAIR_DIR} ${OPENAIR1_DIR} ${OPENAIR2_DIR} ${OPENAIR2_COMMON_DIR} ${OPENAIR2_DIR}/UTIL/LOG diff --git a/openair1/PHY/CODING/TESTBENCH/Makefile b/openair1/PHY/CODING/TESTBENCH/Makefile index 79a005cf8c..030f19b47b 100644 --- a/openair1/PHY/CODING/TESTBENCH/Makefile +++ b/openair1/PHY/CODING/TESTBENCH/Makefile @@ -7,7 +7,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DNODE_RG -DNO_UL_REF -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DOPENAIR_LTE -DMAX_NUM_CCs=1 +CFLAGS += -DNODE_RG -DNO_UL_REF -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DOPENAIR_LTE -DMAX_NUM_CCs=1 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/openair2/UTIL/OCG/makefile b/openair2/UTIL/OCG/makefile index 00108f56a4..1ef4ec98dc 100644 --- a/openair2/UTIL/OCG/makefile +++ b/openair2/UTIL/OCG/makefile @@ -7,7 +7,7 @@ OPENAIR2_TOP = ../../../openair2 OPENAIR3_TOP = ../../../openair3 OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat +CFLAGS += -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat CFLAGS += -m32 -DOPENAIR_LTE -DOPENAIR2 #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE diff --git a/openair2/UTIL/OMG/makefile b/openair2/UTIL/OMG/makefile index 73b282f081..80ab8c6394 100644 --- a/openair2/UTIL/OMG/makefile +++ b/openair2/UTIL/OMG/makefile @@ -60,7 +60,7 @@ OPENAIR2_TOP = ../../../openair2 OPENAIR3_TOP = ../../../openair3 OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat +CFLAGS += -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat CFLAGS += -DOPENAIR_LTE -DOPENAIR2 #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE diff --git a/openair2/UTIL/OMG/makefile_old b/openair2/UTIL/OMG/makefile_old index 13da3a6101..7bc551cb03 100644 --- a/openair2/UTIL/OMG/makefile_old +++ b/openair2/UTIL/OMG/makefile_old @@ -62,7 +62,7 @@ OPENAIR2_TOP = ../../../openair2 OPENAIR3_TOP = ../../../openair3 OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat +CFLAGS += -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 #-Wno-packed-bitfield-compat CFLAGS += -DOPENAIR_LTE -DOPENAIR2 #-DOFDMA_ULSCH -DIFFT_FPGA -DIFFT_FPGA_UE diff --git a/targets/SIMU/USER/Makefile b/targets/SIMU/USER/Makefile index 6e352a9faa..ec5f5eb0cc 100644 --- a/targets/SIMU/USER/Makefile +++ b/targets/SIMU/USER/Makefile @@ -29,7 +29,7 @@ endif CFLAGS += -Wpointer-sign -CFLAGS += -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 $(CPUFLAGS) -I/usr/include/X11 #-Wno-packed-bitfield-compat +CFLAGS += -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 $(CPUFLAGS) -I/usr/include/X11 #-Wno-packed-bitfield-compat ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/AT_COMMANDS/Makefile b/targets/TEST/AT_COMMANDS/Makefile index 1e54e9d950..fc5f550329 100755 --- a/targets/TEST/AT_COMMANDS/Makefile +++ b/targets/TEST/AT_COMMANDS/Makefile @@ -6,7 +6,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3_TOP = $(OPENAIR3_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -m32 -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/PACKET_TRACER/Makefile b/targets/TEST/PACKET_TRACER/Makefile index 7b857ca3b9..e7a4e70bf9 100755 --- a/targets/TEST/PACKET_TRACER/Makefile +++ b/targets/TEST/PACKET_TRACER/Makefile @@ -6,7 +6,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3_TOP = $(OPENAIR3_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -m32 -DPHYSIM -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/PDCP/Makefile b/targets/TEST/PDCP/Makefile index 1d299ee6b5..805cabe7cb 100755 --- a/targets/TEST/PDCP/Makefile +++ b/targets/TEST/PDCP/Makefile @@ -8,7 +8,7 @@ OPENAIR3 = $(OPENAIR3_DIR) EXE_FILE_NAME = test_pdcp -CFLAGS += -m32 -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/PDCP/with_rlc/Makefile.data_bearer b/targets/TEST/PDCP/with_rlc/Makefile.data_bearer index 50686b0bb3..d1397d3f49 100755 --- a/targets/TEST/PDCP/with_rlc/Makefile.data_bearer +++ b/targets/TEST/PDCP/with_rlc/Makefile.data_bearer @@ -8,7 +8,7 @@ OPENAIR3 = $(OPENAIR3_DIR) EXE_FILE_NAME = test_pdcp_rlc -CFLAGS += -m32 -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 +CFLAGS += -m32 -DPHYSIM -DNODE_RG -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -DMAX_MODULES=1 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/RLC_AM_V9.3.0/Makefile b/targets/TEST/RLC_AM_V9.3.0/Makefile index dde20a7b42..8884d7b667 100755 --- a/targets/TEST/RLC_AM_V9.3.0/Makefile +++ b/targets/TEST/RLC_AM_V9.3.0/Makefile @@ -8,7 +8,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3_TOP = $(OPENAIR3_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -m32 -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 +CFLAGS += -m32 -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES diff --git a/targets/TEST/RLC_UM_V9.3.0/Makefile b/targets/TEST/RLC_UM_V9.3.0/Makefile index 57002dad21..919def5f1e 100755 --- a/targets/TEST/RLC_UM_V9.3.0/Makefile +++ b/targets/TEST/RLC_UM_V9.3.0/Makefile @@ -8,7 +8,7 @@ OPENAIR2_TOP = $(OPENAIR2_DIR) OPENAIR3_TOP = $(OPENAIR3_DIR) OPENAIR3 = $(OPENAIR3_DIR) -CFLAGS += -m32 -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 +CFLAGS += -m32 -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TX=2 -I/usr/include/X11 ASN1_MSG_INC = $(OPENAIR2_DIR)/RRC/LITE/MESSAGES From d1003986589e035a3af6e0c20d479862c0f8574c Mon Sep 17 00:00:00 2001 From: bruno mongazon Date: Tue, 16 Jan 2018 12:45:06 +0100 Subject: [PATCH 157/284] Fix #582, double check all removed flags in cmake template files --- cmake_targets/epc_test/CMakeLists.template | 1 - cmake_targets/oaisim_build_oai/CMakeLists.template | 1 - cmake_targets/oaisim_mme_build_oai/CMakeLists.template | 2 -- cmake_targets/oaisim_noS1_build_oai/CMakeLists.template | 2 -- cmake_targets/s1c_mme_test/CMakeLists.template | 1 - 5 files changed, 7 deletions(-) diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index 2ef6c86d31..e046bb7539 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -40,7 +40,6 @@ set ( NO_RRM True ) set ( OAISIM False ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) set ( OAI_NW_DRIVER_USE_NETLINK True ) -set ( OPENAIR1 True ) set ( OPENAIR2 True ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "epc_test" ) diff --git a/cmake_targets/oaisim_build_oai/CMakeLists.template b/cmake_targets/oaisim_build_oai/CMakeLists.template index 8929ec14b9..22faac75b5 100644 --- a/cmake_targets/oaisim_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_build_oai/CMakeLists.template @@ -39,7 +39,6 @@ set ( NO_RRM True ) set ( OAISIM True ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) set ( OAI_NW_DRIVER_USE_NETLINK True ) -set ( OPENAIR1 True ) set ( OPENAIR2 True ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) diff --git a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template index 29331803e7..b18b23ee9a 100644 --- a/cmake_targets/oaisim_mme_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_mme_build_oai/CMakeLists.template @@ -40,9 +40,7 @@ set ( NO_RRM False ) set ( OAISIM False ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) set ( OAI_NW_DRIVER_USE_NETLINK False ) -set ( OPENAIR1 False ) set ( OPENAIR2 False ) -set ( OPENAIR_EMU False ) set ( OPENAIR_LTE False ) set ( PACKAGE_NAME "EPC" ) set ( PDCP_MSG_PRINT False ) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 362cc70026..e0f100ca0a 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -40,9 +40,7 @@ set ( NO_RRM True ) set ( OAISIM True ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) set ( OAI_NW_DRIVER_USE_NETLINK True ) -set ( OPENAIR1 True ) set ( OPENAIR2 True ) -set ( OPENAIR_EMU False ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) set ( PDCP_USE_NETLINK True ) diff --git a/cmake_targets/s1c_mme_test/CMakeLists.template b/cmake_targets/s1c_mme_test/CMakeLists.template index b0b58baaec..9f1ff3e360 100644 --- a/cmake_targets/s1c_mme_test/CMakeLists.template +++ b/cmake_targets/s1c_mme_test/CMakeLists.template @@ -40,7 +40,6 @@ set ( NO_RRM True ) set ( OAISIM True ) set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) set ( OAI_NW_DRIVER_USE_NETLINK True ) -set ( OPENAIR1 True ) set ( OPENAIR2 True ) set ( OPENAIR_LTE True ) set ( PACKAGE_NAME "oaisim" ) From dd3dce8fcf9a2892d806d8c896a08ab5c18652a1 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Fri, 19 Jan 2018 00:35:11 -0800 Subject: [PATCH 158/284] small changes after merge with develop --- cmake_targets/CMakeLists.txt | 6 +- openair2/LAYER2/MAC/config.c | 153 ++++++++++++++++++----------------- 2 files changed, 82 insertions(+), 77 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 32f06de025..d8e8f5fb39 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1892,10 +1892,12 @@ add_executable(lte-softmodem-nos1 target_link_libraries (lte-softmodem-nos1 -Wl,--start-group RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 - -Wl,--end-group ) + NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB + NFAPI_USER_LIB + -Wl,--end-group z dl ) target_link_libraries (lte-softmodem-nos1 ${LIBXML2_LIBRARIES}) -target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES}) +target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES}) target_link_libraries (lte-softmodem-nos1 ${LIB_LMS_LIBRARIES}) target_link_libraries (lte-softmodem-nos1 ${T_LIB}) diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index cf95b7de70..f0d6319e43 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -469,50 +469,51 @@ config_sib2(int Mod_idP, cfg->srs_config.srs_acknack_srs_simultaneous_transmission.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; cfg->srs_config.srs_acknack_srs_simultaneous_transmission.tl.tag = NFAPI_SRS_CONFIG_SRS_ACKNACK_SRS_SIMULTANEOUS_TRANSMISSION_TAG; cfg->num_tlv++; - - - nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; - - cfg->subframe_config.pb.value = radioResourceConfigCommonP->pdsch_ConfigCommon.p_b; - cfg->rf_config.reference_signal_power.value = radioResourceConfigCommonP->pdsch_ConfigCommon.referenceSignalPower; - cfg->nfapi_config.max_transmit_power.value = cfg->rf_config.reference_signal_power.value + - power_off_dB[cfg->rf_config.dl_channel_bandwidth.value]; - - cfg->prach_config.configuration_index.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.prach_ConfigIndex; - cfg->prach_config.root_sequence_index.value = radioResourceConfigCommonP->prach_Config.rootSequenceIndex; - cfg->prach_config.zero_correlation_zone_configuration.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig; - cfg->prach_config.high_speed_flag.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.highSpeedFlag; - cfg->prach_config.frequency_offset.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.prach_FreqOffset; - - cfg->pusch_config.hopping_mode.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode; - cfg->pusch_config.number_of_subbands.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.n_SB; - cfg->pusch_config.hopping_offset.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset; - - cfg->pucch_config.delta_pucch_shift.value = radioResourceConfigCommonP->pucch_ConfigCommon.deltaPUCCH_Shift; - cfg->pucch_config.n_cqi_rb.value = radioResourceConfigCommonP->pucch_ConfigCommon.nRB_CQI; - cfg->pucch_config.n_an_cs.value = radioResourceConfigCommonP->pucch_ConfigCommon.nCS_AN; - cfg->pucch_config.n1_pucch_an.value = radioResourceConfigCommonP->pucch_ConfigCommon.n1PUCCH_AN; - - if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled == true) - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 1; - else if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled == true) - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 2; - else // No hopping - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 0; - - cfg->uplink_reference_signal_config.group_assignment.value = radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH; - cfg->uplink_reference_signal_config.cyclic_shift_1_for_drms.value = radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift; - - // how to enable/disable SRS? - if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.present == SoundingRS_UL_ConfigCommon_PR_setup) { - cfg->srs_config.bandwidth_configuration.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_BandwidthConfig; - cfg->srs_config.srs_subframe_configuration.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig; - cfg->srs_config.srs_acknack_srs_simultaneous_transmission.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; - - if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts) - cfg->srs_config.max_up_pts.value = 1; - else - cfg->srs_config.max_up_pts.value = 0; + + + nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; + + cfg->subframe_config.pb.value = radioResourceConfigCommonP->pdsch_ConfigCommon.p_b; + cfg->rf_config.reference_signal_power.value = radioResourceConfigCommonP->pdsch_ConfigCommon.referenceSignalPower; + cfg->nfapi_config.max_transmit_power.value = cfg->rf_config.reference_signal_power.value + + power_off_dB[cfg->rf_config.dl_channel_bandwidth.value]; + + cfg->prach_config.configuration_index.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.prach_ConfigIndex; + cfg->prach_config.root_sequence_index.value = radioResourceConfigCommonP->prach_Config.rootSequenceIndex; + cfg->prach_config.zero_correlation_zone_configuration.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig; + cfg->prach_config.high_speed_flag.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.highSpeedFlag; + cfg->prach_config.frequency_offset.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.prach_FreqOffset; + + cfg->pusch_config.hopping_mode.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode; + cfg->pusch_config.number_of_subbands.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.n_SB; + cfg->pusch_config.hopping_offset.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset; + + cfg->pucch_config.delta_pucch_shift.value = radioResourceConfigCommonP->pucch_ConfigCommon.deltaPUCCH_Shift; + cfg->pucch_config.n_cqi_rb.value = radioResourceConfigCommonP->pucch_ConfigCommon.nRB_CQI; + cfg->pucch_config.n_an_cs.value = radioResourceConfigCommonP->pucch_ConfigCommon.nCS_AN; + cfg->pucch_config.n1_pucch_an.value = radioResourceConfigCommonP->pucch_ConfigCommon.n1PUCCH_AN; + + if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled == true) + cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 1; + else if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled == true) + cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 2; + else // No hopping + cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 0; + + cfg->uplink_reference_signal_config.group_assignment.value = radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH; + cfg->uplink_reference_signal_config.cyclic_shift_1_for_drms.value = radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift; + + // how to enable/disable SRS? + if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.present == SoundingRS_UL_ConfigCommon_PR_setup) { + cfg->srs_config.bandwidth_configuration.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_BandwidthConfig; + cfg->srs_config.srs_subframe_configuration.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig; + cfg->srs_config.srs_acknack_srs_simultaneous_transmission.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; + + if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts) + cfg->srs_config.max_up_pts.value = 1; + else + cfg->srs_config.max_up_pts.value = 0; + } } #ifdef Rel14 if (RC.mac[Mod_idP]->common_channels[CC_idP].mib->message.schedulingInfoSIB1_BR_r13 > 0) { @@ -640,6 +641,7 @@ config_dedicated_scell(int Mod_idP, } + int rrc_mac_config_req_eNB(module_id_t Mod_idP, int CC_idP, @@ -898,41 +900,41 @@ rrc_mac_config_req_eNB(module_id_t Mod_idP, } } - if (pmch_InfoList != NULL) { - - // LOG_I(MAC,"DUY: lcid when entering rrc_mac config_req is %02d\n",(pmch_InfoList->list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9)); - - LOG_I(MAC, "[CONFIG] Number of PMCH in this MBSFN Area %d\n", - pmch_InfoList->list.count); - - for (i = 0; i < pmch_InfoList->list.count; i++) { - RC.mac[Mod_idP]->common_channels[0].pmch_Config[i] = - &pmch_InfoList->list.array[i]->pmch_Config_r9; - - LOG_I(MAC, - "[CONFIG] PMCH[%d]: This PMCH stop (sf_AllocEnd_r9) at subframe %ldth\n", - i, - RC.mac[Mod_idP]->common_channels[0]. - pmch_Config[i]->sf_AllocEnd_r9); - LOG_I(MAC, "[CONFIG] PMCH[%d]: mch_Scheduling_Period = %ld\n", - i, - RC.mac[Mod_idP]->common_channels[0]. - pmch_Config[i]->mch_SchedulingPeriod_r9); - LOG_I(MAC, "[CONFIG] PMCH[%d]: dataMCS = %ld\n", i, - RC.mac[Mod_idP]->common_channels[0]. - pmch_Config[i]->dataMCS_r9); - - // MBMS session info list in each MCH - RC.mac[Mod_idP]->common_channels[0].mbms_SessionList[i] = - &pmch_InfoList->list.array[i]->mbms_SessionInfoList_r9; - LOG_I(MAC, "PMCH[%d] Number of session (MTCH) is: %d\n", i, - RC.mac[Mod_idP]->common_channels[0]. + if (pmch_InfoList != NULL) { + + // LOG_I(MAC,"DUY: lcid when entering rrc_mac config_req is %02d\n",(pmch_InfoList->list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9)); + + LOG_I(MAC, "[CONFIG] Number of PMCH in this MBSFN Area %d\n", + pmch_InfoList->list.count); + + for (i = 0; i < pmch_InfoList->list.count; i++) { + RC.mac[Mod_idP]->common_channels[0].pmch_Config[i] = + &pmch_InfoList->list.array[i]->pmch_Config_r9; + + LOG_I(MAC, + "[CONFIG] PMCH[%d]: This PMCH stop (sf_AllocEnd_r9) at subframe %ldth\n", + i, + RC.mac[Mod_idP]->common_channels[0]. + pmch_Config[i]->sf_AllocEnd_r9); + LOG_I(MAC, "[CONFIG] PMCH[%d]: mch_Scheduling_Period = %ld\n", + i, + RC.mac[Mod_idP]->common_channels[0]. + pmch_Config[i]->mch_SchedulingPeriod_r9); + LOG_I(MAC, "[CONFIG] PMCH[%d]: dataMCS = %ld\n", i, + RC.mac[Mod_idP]->common_channels[0]. + pmch_Config[i]->dataMCS_r9); + + // MBMS session info list in each MCH + RC.mac[Mod_idP]->common_channels[0].mbms_SessionList[i] = + &pmch_InfoList->list.array[i]->mbms_SessionInfoList_r9; + LOG_I(MAC, "PMCH[%d] Number of session (MTCH) is: %d\n", i, + RC.mac[Mod_idP]->common_channels[0]. mbms_SessionList[i]->list.count); - } } } -#endif +#endif + LOG_E(MAC, "%s() %s:%d RC.mac[Mod_idP]->if_inst->PHY_config_req:%p\n", __FUNCTION__, __FILE__, __LINE__, RC.mac[Mod_idP]->if_inst->PHY_config_req); // if in nFAPI mode @@ -961,6 +963,7 @@ rrc_mac_config_req_eNB(module_id_t Mod_idP, return(0); } + int rrc_mac_config_req_ue(module_id_t Mod_idP, int CC_idP, From 3a867ac767d345a4d6b7eab8c7ce9c2c613541a2 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 19 Jan 2018 15:51:38 +0100 Subject: [PATCH 159/284] integration fix: add T trace --- common/utils/T/T_messages.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index 3009cc3305..8d531f9067 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -185,6 +185,10 @@ ID = ENB_RRC_CONNECTION_REESTABLISHMENT_REQUEST DESC = RRC connection reestablishment request GROUP = ALL:RRC:ENB FORMAT = int,eNB_ID : int,frame : int,subframe : int,rnti +ID = ENB_RRC_CONNECTION_REESTABLISHMENT + DESC = RRC connection reestablishment + GROUP = ALL:RRC:ENB + FORMAT = int,eNB_ID : int,frame : int,subframe : int,rnti ID = ENB_RRC_CONNECTION_REESTABLISHMENT_COMPLETE DESC = RRC connection reestablishment complete GROUP = ALL:RRC:ENB From 046589e76da9ed98f2fa933e352a177aa8f1aab9 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Sun, 21 Jan 2018 22:15:45 +0100 Subject: [PATCH 160/284] fixes after merge with develop. Partial UE/eNB separation in build to avoid problems with NFAPI in oaisim UE/RRU. tested with simulator. --- cmake_targets/CMakeLists.txt | 190 ++- openair1/PHY/INIT/init_top.c | 43 +- openair1/PHY/INIT/lte_init.c | 1078 ----------------- openair1/PHY/INIT/lte_init_ru.c | 150 +++ openair1/PHY/INIT/lte_init_ue.c | 963 +++++++++++++++ openair1/PHY/LTE_ESTIMATION/lte_sync_time.c | 2 +- openair1/SCHED/phy_procedures_lte_eNb.c | 175 --- openair2/ENB_APP/enb_config.c | 132 -- openair2/LAYER2/MAC/config.c | 520 -------- openair2/LAYER2/MAC/config_ue.c | 584 +++++++++ openair2/LAYER2/MAC/eNB_scheduler.c | 3 +- openair2/LAYER2/MAC/eNB_scheduler_RA.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_bch.c | 8 +- openair2/LAYER2/MAC/eNB_scheduler_mch.c | 3 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 2 +- openair2/LAYER2/MAC/main.c | 84 -- openair2/LAYER2/MAC/main_ue.c | 150 +++ openair2/LAYER2/MAC/ra_procedures.c | 4 +- openair2/LAYER2/MAC/rar_tools.c | 101 -- openair2/LAYER2/MAC/rar_tools_ue.c | 143 +++ openair2/LAYER2/MAC/ue_procedures.c | 20 +- openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 4 +- openair2/LAYER2/openair2_proc.c | 2 +- .../L2_INTERFACE/openair_rrc_L2_interface.h | 28 +- openair2/RRC/LITE/L2_interface.c | 383 +----- openair2/RRC/LITE/L2_interface_common.c | 183 +++ openair2/RRC/LITE/L2_interface_ue.c | 463 +++++++ openair2/RRC/LITE/proto.h | 45 +- openair2/RRC/LITE/rrc_UE.c | 197 ++- openair2/RRC/LITE/rrc_common.c | 271 ----- openair2/RRC/LITE/rrc_eNB.c | 118 ++ targets/COMMON/create_tasks.c | 39 +- targets/COMMON/create_tasks.h | 3 +- targets/COMMON/create_tasks_ue.c | 80 ++ targets/RT/USER/lte-ru.c | 187 ++- targets/RT/USER/lte-softmodem.c | 15 +- targets/SIMU/USER/oaisim.c | 21 +- targets/SIMU/USER/oaisim_functions.c | 37 +- 38 files changed, 3560 insertions(+), 2873 deletions(-) create mode 100644 openair1/PHY/INIT/lte_init_ru.c create mode 100644 openair1/PHY/INIT/lte_init_ue.c create mode 100644 openair2/LAYER2/MAC/config_ue.c create mode 100644 openair2/LAYER2/MAC/main_ue.c create mode 100644 openair2/LAYER2/MAC/rar_tools_ue.c create mode 100644 openair2/RRC/LITE/L2_interface_common.c create mode 100644 openair2/RRC/LITE/L2_interface_ue.c create mode 100644 targets/COMMON/create_tasks_ue.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index d8e8f5fb39..d4cf1fe153 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1008,6 +1008,7 @@ set(SCHED_SRC ${OPENAIR1_DIR}/SCHED/phy_procedures_lte_eNb.c ${OPENAIR1_DIR}/SCHED/phy_procedures_lte_ue.c ${OPENAIR1_DIR}/SCHED/phy_procedures_lte_common.c + ${OPENAIR1_DIR}/SCHED/prach_procedures.c ${OPENAIR1_DIR}/SCHED/ru_procedures.c # ${OPENAIR1_DIR}/SCHED/phy_mac_stub.c ${OPENAIR1_DIR}/SCHED/pucch_pc.c @@ -1016,6 +1017,17 @@ set(SCHED_SRC ) add_library(SCHED_LIB ${SCHED_SRC}) +set(SCHED_SRC_UE + ${OPENAIR1_DIR}/SCHED/phy_procedures_lte_ue.c + ${OPENAIR1_DIR}/SCHED/phy_procedures_lte_common.c + ${OPENAIR1_DIR}/SCHED/ru_procedures.c + ${OPENAIR1_DIR}/SCHED/prach_procedures.c + ${OPENAIR1_DIR}/SCHED/pucch_pc.c + ${OPENAIR1_DIR}/SCHED/pusch_pc.c + ${OPENAIR1_DIR}/SCHED/srs_pc.c +) +add_library(SCHED_UE_LIB ${SCHED_SRC_UE}) + # nFAPI ################################# set(NFAPI_COMMON_SRC @@ -1146,6 +1158,9 @@ set(PHY_SRC ${OPENAIR1_DIR}/PHY/CODING/viterbi.c ${OPENAIR1_DIR}/PHY/CODING/viterbi_lte.c ${OPENAIR1_DIR}/PHY/INIT/lte_init.c + ${OPENAIR1_DIR}/PHY/INIT/lte_init_ru.c + ${OPENAIR1_DIR}/PHY/INIT/lte_init_ue.c + ${OPENAIR1_DIR}/PHY/INIT/init_top.c ${OPENAIR1_DIR}/PHY/INIT/lte_parms.c ${OPENAIR1_DIR}/PHY/INIT/lte_param_init.c ${OPENAIR1_DIR}/PHY/TOOLS/file_output.c @@ -1161,15 +1176,112 @@ set(PHY_SRC ${OPENAIR1_DIR}/PHY/TOOLS/time_meas.c ${OPENAIR1_DIR}/PHY/TOOLS/lut.c ) + +set(PHY_SRC_UE + # depend on code generation from asn1c + ${RRC_FULL_DIR}/asn1_constants.h + # actual source + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pss.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/sss.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pilots.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pilots_mbsfn.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_coding.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_modulation.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_demodulation.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_llr_computation.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/power_control.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_decoding.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_scrambling.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/uci_tools.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/lte_mcs.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pbch.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/edci.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/phich.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pcfich.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pucch.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/prach.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pmch.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pch.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/group_hopping.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/srs_modulation.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/drs_modulation.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_modulation.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_demodulation.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_coding.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_decoding.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/rar_tools.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/print_stats.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/initial_sync.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/if4_tools.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/if5_tools.c + ${OPENAIR1_DIR}/PHY/MODULATION/ofdm_mod.c + ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep.c + ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep_mbsfn.c + ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep_ul.c + ${OPENAIR1_DIR}/PHY/MODULATION/ul_7_5_kHz.c + ${OPENAIR1_DIR}/PHY/MODULATION/beamforming.c + ${OPENAIR1_DIR}/PHY/MODULATION/compute_bf_weights.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/freq_equalization.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_time.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_timefreq.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_adjust_sync.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_dl_mbsfn_channel_estimation.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_est_freq_offset.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ue_measurements.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_eNB_measurements.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/adjust_gain.c + ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_dl_cell_spec.c + ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_dl_uespec.c + ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_gold.c + ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_gold_mbsfn.c + ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_dl_mbsfn.c + ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_ul_ref.c + ${OPENAIR1_DIR}/PHY/CODING/lte_segmentation.c + ${OPENAIR1_DIR}/PHY/CODING/ccoding_byte.c + ${OPENAIR1_DIR}/PHY/CODING/ccoding_byte_lte.c + ${OPENAIR1_DIR}/PHY/CODING/3gpplte_sse.c + ${OPENAIR1_DIR}/PHY/CODING/crc_byte.c + ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c + ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c + ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c + ${OPENAIR1_DIR}/PHY/CODING/lte_rate_matching.c + ${OPENAIR1_DIR}/PHY/CODING/viterbi.c + ${OPENAIR1_DIR}/PHY/CODING/viterbi_lte.c + ${OPENAIR1_DIR}/PHY/INIT/lte_init_ru.c + ${OPENAIR1_DIR}/PHY/INIT/lte_init_ue.c + ${OPENAIR1_DIR}/PHY/INIT/init_top.c + ${OPENAIR1_DIR}/PHY/INIT/lte_parms.c + ${OPENAIR1_DIR}/PHY/INIT/lte_param_init.c + ${OPENAIR1_DIR}/PHY/TOOLS/file_output.c + ${OPENAIR1_DIR}/PHY/TOOLS/cadd_vv.c + ${OPENAIR1_DIR}/PHY/TOOLS/lte_dfts.c + ${OPENAIR1_DIR}/PHY/TOOLS/log2_approx.c + ${OPENAIR1_DIR}/PHY/TOOLS/cmult_sv.c + ${OPENAIR1_DIR}/PHY/TOOLS/cmult_vv.c + ${OPENAIR1_DIR}/PHY/TOOLS/cdot_prod.c + ${OPENAIR1_DIR}/PHY/TOOLS/signal_energy.c + ${OPENAIR1_DIR}/PHY/TOOLS/dB_routines.c + ${OPENAIR1_DIR}/PHY/TOOLS/sqrt.c + ${OPENAIR1_DIR}/PHY/TOOLS/time_meas.c + ${OPENAIR1_DIR}/PHY/TOOLS/lut.c + ) + if (${SMBV}) set(PHY_SRC "${PHY_SRC} ${OPENAIR1_DIR}/PHY/TOOLS/smbv.c") endif (${SMBV}) if (${COMPILATION_AVX2} STREQUAL "True") set(PHY_SRC ${PHY_SRC} ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_llr_computation_avx2.c) + set(PHY_SRC_UE ${PHY_SRC_UE} ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_llr_computation_avx2.c) endif () add_library(PHY ${PHY_SRC}) +add_library(PHY_UE ${PHY_SRC_UE}) #Layer 2 library ##################### @@ -1223,14 +1335,61 @@ set(L2_SRC ${RRC_DIR}/rrc_eNB_UE_context.c ${RRC_DIR}/rrc_common.c ${RRC_DIR}/L2_interface.c + ${RRC_DIR}/L2_interface_common.c + ${RRC_DIR}/L2_interface_ue.c ) + +set(L2_SRC_UE + ${OPENAIR2_DIR}/LAYER2/openair2_proc.c + ${PDCP_DIR}/pdcp.c + ${PDCP_DIR}/pdcp_fifo.c + ${PDCP_DIR}/pdcp_sequence_manager.c + ${PDCP_DIR}/pdcp_primitives.c + ${PDCP_DIR}/pdcp_util.c + ${PDCP_DIR}/pdcp_security.c + ${PDCP_DIR}/pdcp_netlink.c + ${RLC_AM_DIR}/rlc_am.c + ${RLC_AM_DIR}/rlc_am_init.c + ${RLC_AM_DIR}/rlc_am_timer_poll_retransmit.c + ${RLC_AM_DIR}/rlc_am_timer_reordering.c + ${RLC_AM_DIR}/rlc_am_timer_status_prohibit.c + ${RLC_AM_DIR}/rlc_am_segment.c + ${RLC_AM_DIR}/rlc_am_segments_holes.c + ${RLC_AM_DIR}/rlc_am_in_sdu.c + ${RLC_AM_DIR}/rlc_am_receiver.c + ${RLC_AM_DIR}/rlc_am_retransmit.c + ${RLC_AM_DIR}/rlc_am_windows.c + ${RLC_AM_DIR}/rlc_am_rx_list.c + ${RLC_AM_DIR}/rlc_am_reassembly.c + ${RLC_AM_DIR}/rlc_am_status_report.c + ${RLC_TM_DIR}/rlc_tm.c + ${RLC_TM_DIR}/rlc_tm_init.c + ${RLC_UM_DIR}/rlc_um.c + ${RLC_UM_DIR}/rlc_um_fsm.c + ${RLC_UM_DIR}/rlc_um_control_primitives.c + ${RLC_UM_DIR}/rlc_um_segment.c + ${RLC_UM_DIR}/rlc_um_reassembly.c + ${RLC_UM_DIR}/rlc_um_receiver.c + ${RLC_UM_DIR}/rlc_um_dar.c + ${RLC_DIR}/rlc_mac.c + ${RLC_DIR}/rlc.c + ${RLC_DIR}/rlc_rrc.c + ${RLC_DIR}/rlc_mpls.c + ${RRC_DIR}/rrc_UE.c + ${RRC_DIR}/rrc_common.c + ${RRC_DIR}/L2_interface_common.c + ${RRC_DIR}/L2_interface_ue.c + ) + set (MAC_SRC ${PHY_INTERFACE_DIR}/IF_Module.c ${MAC_DIR}/main.c + ${MAC_DIR}/main_ue.c ${MAC_DIR}/ue_procedures.c ${MAC_DIR}/ra_procedures.c ${MAC_DIR}/l1_helpers.c ${MAC_DIR}/rar_tools.c + ${MAC_DIR}/rar_tools_ue.c ${MAC_DIR}/eNB_scheduler.c ${MAC_DIR}/eNB_scheduler_dlsch.c ${MAC_DIR}/eNB_scheduler_ulsch.c @@ -1240,8 +1399,19 @@ set (MAC_SRC ${MAC_DIR}/eNB_scheduler_RA.c ${MAC_DIR}/pre_processor.c ${MAC_DIR}/config.c + ${MAC_DIR}/config_ue.c ) +set (MAC_SRC_UE + ${MAC_DIR}/main_ue.c + ${MAC_DIR}/ue_procedures.c + ${MAC_DIR}/ra_procedures.c + ${MAC_DIR}/l1_helpers.c + ${MAC_DIR}/rar_tools_ue.c + ${MAC_DIR}/config_ue.c + ) + + if (FLEXRAN_AGENT_SB_IF) set (MAC_SRC ${MAC_SRC} @@ -1263,6 +1433,12 @@ add_library(L2 ${ENB_APP_SRC}) # ${OPENAIR2_DIR}/RRC/L2_INTERFACE/openair_rrc_L2_interface.c) +add_library(L2_UE + ${L2_SRC_UE} + ${MAC_SRC_UE} +) + + include_directories(${NFAPI_USER_DIR}) if (FLEXRAN_AGENT_SB_IF) @@ -1837,6 +2013,7 @@ add_executable(lte-softmodem ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c ${OPENAIR_TARGETS}/COMMON/create_tasks.c + ${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c ${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c @@ -1877,6 +2054,7 @@ add_executable(lte-softmodem-nos1 ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c ${OPENAIR_TARGETS}/COMMON/create_tasks.c + ${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c ${OPENAIR2_DIR}/RRC/NAS/nas_config.c ${OPENAIR2_DIR}/RRC/NAS/rb_config.c @@ -1974,7 +2152,7 @@ add_executable(oaisim ${OPENAIR_DIR}/common/utils/utils.c ${OPENAIR_DIR}/common/utils/system.c ${GTPU_need_ITTI} - ${OPENAIR_TARGETS}/COMMON/create_tasks.c + ${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c ${XFORMS_SOURCE} ${T_SOURCE} ${CONFIG_SOURCES} @@ -1985,10 +2163,10 @@ add_executable(oaisim target_include_directories(oaisim PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim -Wl,-ldl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB GTPV1U SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} LIB_NAS_UE SIMU SECU_OSA ${ITTI_LIB} ${MIH_LIB} + RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB GTPV1U SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_UE_LIB PHY_UE LFDS L2 ${MSC_LIB} LIB_NAS_UE SIMU SECU_OSA ${ITTI_LIB} ${MIH_LIB} NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB - -Wl,--end-group ) + -Wl,--end-group z dl) target_link_libraries (oaisim ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) target_link_libraries (oaisim pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp z @@ -2019,7 +2197,7 @@ add_executable(oaisim_nos1 ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c ${OPENAIR2_DIR}/RRC/NAS/nas_config.c ${OPENAIR2_DIR}/RRC/NAS/rb_config.c - ${OPENAIR_TARGETS}/COMMON/create_tasks.c + ${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c ${OPENAIR_DIR}/common/utils/system.c ${XFORMS_SOURCE} ${T_SOURCE} @@ -2029,8 +2207,8 @@ add_executable(oaisim_nos1 target_include_directories(oaisim_nos1 PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim_nos1 -Wl,--start-group - RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 - -Wl,--end-group ) + RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_UE_LIB PHY_UE LFDS ${MSC_LIB} ${ITTI_LIB} SIMU L2_UE ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7 + -Wl,--end-group z dl ) target_link_libraries (oaisim_nos1 ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) target_link_libraries (oaisim_nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} diff --git a/openair1/PHY/INIT/init_top.c b/openair1/PHY/INIT/init_top.c index c4d5850501..7b1fd10488 100644 --- a/openair1/PHY/INIT/init_top.c +++ b/openair1/PHY/INIT/init_top.c @@ -26,19 +26,42 @@ #include "defs.h" #include "PHY/extern.h" -#include "MAC_INTERFACE/extern.h" -//#include "ARCH/CBMIMO1/DEVICE_DRIVER/extern.h" -/*! -* @addtogroup _PHY_STRUCTURES_ -* Memory Initializaion and Cleanup for LTE MODEM. -* @{ -\section _Memory_init_ Memory Initialization for LTE MODEM +void init_lte_top(LTE_DL_FRAME_PARMS *frame_parms) +{ -*/ + crcTableInit(); -//#define DEBUG_PHY -t + ccodedot11_init(); + ccodedot11_init_inv(); + + ccodelte_init(); + ccodelte_init_inv(); + + treillis_table_init(); + + phy_generate_viterbi_tables(); + phy_generate_viterbi_tables_lte(); + init_td8(); + init_td16(); +#ifdef __AVX2__ + init_td16avx2(); +#endif + lte_sync_time_init(frame_parms); + + generate_ul_ref_sigs(); + generate_ul_ref_sigs_rx(); + + generate_64qam_table(); + generate_16qam_table(); + generate_RIV_tables(); + + init_unscrambling_lut(); + init_scrambling_lut(); + //set_taus_seed(1328); + + +} /* diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index c911b5cc22..377a235da6 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -325,24 +325,6 @@ void phy_config_request(PHY_Config_t *phy_config) { LOG_I(PHY,"eNB %d/%d configured\n",Mod_id,CC_id); } -void phy_config_sib1_ue(uint8_t Mod_id,int CC_id, - uint8_t eNB_id, - TDD_Config_t *tdd_Config, - uint8_t SIwindowsize, - uint16_t SIperiod) -{ - - LTE_DL_FRAME_PARMS *fp = &PHY_vars_UE_g[Mod_id][CC_id]->frame_parms; - - if (tdd_Config) { - fp->tdd_config = tdd_Config->subframeAssignment; - fp->tdd_config_S = tdd_Config->specialSubframePatterns; - } - - fp->SIwindowsize = SIwindowsize; - fp->SIPeriod = SIperiod; -} - /* void phy_config_sib2_eNB(uint8_t Mod_id, int CC_id, @@ -486,149 +468,6 @@ void phy_config_sib2_eNB(uint8_t Mod_id, } */ -void phy_config_sib2_ue(uint8_t Mod_id,int CC_id, - uint8_t eNB_id, - RadioResourceConfigCommonSIB_t *radioResourceConfigCommon, - ARFCN_ValueEUTRA_t *ul_CarrierFreq, - long *ul_Bandwidth, - AdditionalSpectrumEmission_t *additionalSpectrumEmission, - struct MBSFN_SubframeConfigList *mbsfn_SubframeConfigList) -{ - - PHY_VARS_UE *ue = PHY_vars_UE_g[Mod_id][CC_id]; - LTE_DL_FRAME_PARMS *fp = &ue->frame_parms; - int i; - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_CONFIG_SIB2, VCD_FUNCTION_IN); - - LOG_I(PHY,"[UE%d] Applying radioResourceConfigCommon from eNB%d\n",Mod_id,eNB_id); - - fp->prach_config_common.rootSequenceIndex =radioResourceConfigCommon->prach_Config.rootSequenceIndex; - - fp->prach_config_common.prach_Config_enabled=1; - fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex =radioResourceConfigCommon->prach_Config.prach_ConfigInfo.prach_ConfigIndex; - fp->prach_config_common.prach_ConfigInfo.highSpeedFlag =radioResourceConfigCommon->prach_Config.prach_ConfigInfo.highSpeedFlag; - fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig =radioResourceConfigCommon->prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig; - fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset =radioResourceConfigCommon->prach_Config.prach_ConfigInfo.prach_FreqOffset; - - compute_prach_seq(fp->prach_config_common.rootSequenceIndex, - fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex, - fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, - fp->prach_config_common.prach_ConfigInfo.highSpeedFlag, - fp->frame_type,ue->X_u); - - - - fp->pucch_config_common.deltaPUCCH_Shift = 1+radioResourceConfigCommon->pucch_ConfigCommon.deltaPUCCH_Shift; - fp->pucch_config_common.nRB_CQI = radioResourceConfigCommon->pucch_ConfigCommon.nRB_CQI; - fp->pucch_config_common.nCS_AN = radioResourceConfigCommon->pucch_ConfigCommon.nCS_AN; - fp->pucch_config_common.n1PUCCH_AN = radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN; - - - - fp->pdsch_config_common.referenceSignalPower = radioResourceConfigCommon->pdsch_ConfigCommon.referenceSignalPower; - fp->pdsch_config_common.p_b = radioResourceConfigCommon->pdsch_ConfigCommon.p_b; - - - fp->pusch_config_common.n_SB = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.n_SB; - fp->pusch_config_common.hoppingMode = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode; - fp->pusch_config_common.pusch_HoppingOffset = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset; - fp->pusch_config_common.enable64QAM = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.enable64QAM; - fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled; - fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH; - fp->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled; - fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = dmrs1_tab[radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift]; - - - init_ul_hopping(fp); - fp->soundingrs_ul_config_common.enabled_flag = 0; - - if (radioResourceConfigCommon->soundingRS_UL_ConfigCommon.present==SoundingRS_UL_ConfigCommon_PR_setup) { - fp->soundingrs_ul_config_common.enabled_flag = 1; - fp->soundingrs_ul_config_common.srs_BandwidthConfig = radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.srs_BandwidthConfig; - fp->soundingrs_ul_config_common.srs_SubframeConfig = radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig; - fp->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission = radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; - - if (radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts) - fp->soundingrs_ul_config_common.srs_MaxUpPts = 1; - else - fp->soundingrs_ul_config_common.srs_MaxUpPts = 0; - } - - - - fp->ul_power_control_config_common.p0_NominalPUSCH = radioResourceConfigCommon->uplinkPowerControlCommon.p0_NominalPUSCH; - fp->ul_power_control_config_common.alpha = radioResourceConfigCommon->uplinkPowerControlCommon.alpha; - fp->ul_power_control_config_common.p0_NominalPUCCH = radioResourceConfigCommon->uplinkPowerControlCommon.p0_NominalPUCCH; - fp->ul_power_control_config_common.deltaPreambleMsg3 = radioResourceConfigCommon->uplinkPowerControlCommon.deltaPreambleMsg3; - fp->ul_power_control_config_common.deltaF_PUCCH_Format1 = radioResourceConfigCommon->uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format1; - fp->ul_power_control_config_common.deltaF_PUCCH_Format1b = radioResourceConfigCommon->uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format1b; - fp->ul_power_control_config_common.deltaF_PUCCH_Format2 = radioResourceConfigCommon->uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2; - fp->ul_power_control_config_common.deltaF_PUCCH_Format2a = radioResourceConfigCommon->uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2a; - fp->ul_power_control_config_common.deltaF_PUCCH_Format2b = radioResourceConfigCommon->uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2b; - - fp->maxHARQ_Msg3Tx = radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx; - - // Now configure some of the Physical Channels - - // PUCCH - init_ncs_cell(fp,ue->ncs_cell); - - init_ul_hopping(fp); - - // PCH - init_ue_paging_info(ue,radioResourceConfigCommon->pcch_Config.defaultPagingCycle,radioResourceConfigCommon->pcch_Config.nB); - - // MBSFN - - if (mbsfn_SubframeConfigList != NULL) { - fp->num_MBSFN_config = mbsfn_SubframeConfigList->list.count; - - for (i=0; ilist.count; i++) { - fp->MBSFN_config[i].radioframeAllocationPeriod = mbsfn_SubframeConfigList->list.array[i]->radioframeAllocationPeriod; - fp->MBSFN_config[i].radioframeAllocationOffset = mbsfn_SubframeConfigList->list.array[i]->radioframeAllocationOffset; - - if (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.present == MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { - fp->MBSFN_config[i].fourFrames_flag = 0; - fp->MBSFN_config[i].mbsfn_SubframeConfig = mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[0]; // 6-bit subframe configuration - LOG_I(PHY, "[CONFIG] MBSFN_SubframeConfig[%d] pattern is %d\n", i, - fp->MBSFN_config[i].mbsfn_SubframeConfig); - } else if (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.present == MBSFN_SubframeConfig__subframeAllocation_PR_fourFrames) { // 24-bit subframe configuration - fp->MBSFN_config[i].fourFrames_flag = 1; - fp->MBSFN_config[i].mbsfn_SubframeConfig = - mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[0]| - (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[1]<<8)| - (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[2]<<16); - - LOG_I(PHY, "[CONFIG] MBSFN_SubframeConfig[%d] pattern is %d\n", i, - fp->MBSFN_config[i].mbsfn_SubframeConfig); - } - } - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_CONFIG_SIB2, VCD_FUNCTION_OUT); - -} - -void phy_config_sib13_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id,int mbsfn_Area_idx, - long mbsfn_AreaId_r9) -{ - - LTE_DL_FRAME_PARMS *fp = &PHY_vars_UE_g[Mod_id][CC_id]->frame_parms; - - - LOG_I(PHY,"[UE%d] Applying MBSFN_Area_id %ld for index %d\n",Mod_id,mbsfn_AreaId_r9,mbsfn_Area_idx); - - if (mbsfn_Area_idx == 0) { - fp->Nid_cell_mbsfn = (uint16_t)mbsfn_AreaId_r9; - LOG_N(PHY,"Fix me: only called when mbsfn_Area_idx == 0)\n"); - } - - lte_gold_mbsfn(fp,PHY_vars_UE_g[Mod_id][CC_id]->lte_gold_mbsfn_table,fp->Nid_cell_mbsfn); - -} - - void phy_config_sib13_eNB(uint8_t Mod_id,int CC_id,int mbsfn_Area_idx, long mbsfn_AreaId_r9) { @@ -767,150 +606,6 @@ void phy_config_dedicated_eNB_step2(PHY_VARS_eNB *eNB) } } -/* - * Configures UE MAC and PHY with radioResourceCommon received in mobilityControlInfo IE during Handover - */ -void phy_config_afterHO_ue(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_id, MobilityControlInfo_t *mobilityControlInfo, uint8_t ho_failed) -{ - - if(mobilityControlInfo!=NULL) { - RadioResourceConfigCommon_t *radioResourceConfigCommon = &mobilityControlInfo->radioResourceConfigCommon; - LOG_I(PHY,"radioResourceConfigCommon %p\n", radioResourceConfigCommon); - memcpy((void *)&PHY_vars_UE_g[Mod_id][CC_id]->frame_parms_before_ho, - (void *)&PHY_vars_UE_g[Mod_id][CC_id]->frame_parms, - sizeof(LTE_DL_FRAME_PARMS)); - PHY_vars_UE_g[Mod_id][CC_id]->ho_triggered = 1; - //PHY_vars_UE_g[UE_id]->UE_mode[0] = PRACH; - - LTE_DL_FRAME_PARMS *fp = &PHY_vars_UE_g[Mod_id][CC_id]->frame_parms; - // int N_ZC; - // uint8_t prach_fmt; - // int u; - - LOG_I(PHY,"[UE%d] Handover triggered: Applying radioResourceConfigCommon from eNB %d\n", - Mod_id,eNB_id); - - fp->prach_config_common.rootSequenceIndex =radioResourceConfigCommon->prach_Config.rootSequenceIndex; - fp->prach_config_common.prach_Config_enabled=1; - fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex =radioResourceConfigCommon->prach_Config.prach_ConfigInfo->prach_ConfigIndex; - fp->prach_config_common.prach_ConfigInfo.highSpeedFlag =radioResourceConfigCommon->prach_Config.prach_ConfigInfo->highSpeedFlag; - fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig =radioResourceConfigCommon->prach_Config.prach_ConfigInfo->zeroCorrelationZoneConfig; - fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset =radioResourceConfigCommon->prach_Config.prach_ConfigInfo->prach_FreqOffset; - - // prach_fmt = get_prach_fmt(radioResourceConfigCommon->prach_Config.prach_ConfigInfo->prach_ConfigIndex,fp->frame_type); - // N_ZC = (prach_fmt <4)?839:139; - // u = (prach_fmt < 4) ? prach_root_sequence_map0_3[fp->prach_config_common.rootSequenceIndex] : - // prach_root_sequence_map4[fp->prach_config_common.rootSequenceIndex]; - - //compute_prach_seq(u,N_ZC, PHY_vars_UE_g[Mod_id]->X_u); - compute_prach_seq(PHY_vars_UE_g[Mod_id][CC_id]->frame_parms.prach_config_common.rootSequenceIndex, - PHY_vars_UE_g[Mod_id][CC_id]->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex, - PHY_vars_UE_g[Mod_id][CC_id]->frame_parms.prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, - PHY_vars_UE_g[Mod_id][CC_id]->frame_parms.prach_config_common.prach_ConfigInfo.highSpeedFlag, - fp->frame_type, - PHY_vars_UE_g[Mod_id][CC_id]->X_u); - - - fp->pucch_config_common.deltaPUCCH_Shift = 1+radioResourceConfigCommon->pucch_ConfigCommon->deltaPUCCH_Shift; - fp->pucch_config_common.nRB_CQI = radioResourceConfigCommon->pucch_ConfigCommon->nRB_CQI; - fp->pucch_config_common.nCS_AN = radioResourceConfigCommon->pucch_ConfigCommon->nCS_AN; - fp->pucch_config_common.n1PUCCH_AN = radioResourceConfigCommon->pucch_ConfigCommon->n1PUCCH_AN; - fp->pdsch_config_common.referenceSignalPower = radioResourceConfigCommon->pdsch_ConfigCommon->referenceSignalPower; - fp->pdsch_config_common.p_b = radioResourceConfigCommon->pdsch_ConfigCommon->p_b; - - - fp->pusch_config_common.n_SB = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.n_SB; - fp->pusch_config_common.hoppingMode = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode; - fp->pusch_config_common.pusch_HoppingOffset = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset; - fp->pusch_config_common.enable64QAM = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.enable64QAM; - fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled; - fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH; - fp->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled; - fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift; - - init_ul_hopping(fp); - fp->soundingrs_ul_config_common.enabled_flag = 0; - - if (radioResourceConfigCommon->soundingRS_UL_ConfigCommon->present==SoundingRS_UL_ConfigCommon_PR_setup) { - fp->soundingrs_ul_config_common.enabled_flag = 1; - fp->soundingrs_ul_config_common.srs_BandwidthConfig = radioResourceConfigCommon->soundingRS_UL_ConfigCommon->choice.setup.srs_BandwidthConfig; - fp->soundingrs_ul_config_common.srs_SubframeConfig = radioResourceConfigCommon->soundingRS_UL_ConfigCommon->choice.setup.srs_SubframeConfig; - fp->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission = radioResourceConfigCommon->soundingRS_UL_ConfigCommon->choice.setup.ackNackSRS_SimultaneousTransmission; - - if (radioResourceConfigCommon->soundingRS_UL_ConfigCommon->choice.setup.srs_MaxUpPts) - fp->soundingrs_ul_config_common.srs_MaxUpPts = 1; - else - fp->soundingrs_ul_config_common.srs_MaxUpPts = 0; - } - - fp->ul_power_control_config_common.p0_NominalPUSCH = radioResourceConfigCommon->uplinkPowerControlCommon->p0_NominalPUSCH; - fp->ul_power_control_config_common.alpha = radioResourceConfigCommon->uplinkPowerControlCommon->alpha; - fp->ul_power_control_config_common.p0_NominalPUCCH = radioResourceConfigCommon->uplinkPowerControlCommon->p0_NominalPUCCH; - fp->ul_power_control_config_common.deltaPreambleMsg3 = radioResourceConfigCommon->uplinkPowerControlCommon->deltaPreambleMsg3; - fp->ul_power_control_config_common.deltaF_PUCCH_Format1 = radioResourceConfigCommon->uplinkPowerControlCommon->deltaFList_PUCCH.deltaF_PUCCH_Format1; - fp->ul_power_control_config_common.deltaF_PUCCH_Format1b = radioResourceConfigCommon->uplinkPowerControlCommon->deltaFList_PUCCH.deltaF_PUCCH_Format1b; - fp->ul_power_control_config_common.deltaF_PUCCH_Format2 = radioResourceConfigCommon->uplinkPowerControlCommon->deltaFList_PUCCH.deltaF_PUCCH_Format2; - fp->ul_power_control_config_common.deltaF_PUCCH_Format2a = radioResourceConfigCommon->uplinkPowerControlCommon->deltaFList_PUCCH.deltaF_PUCCH_Format2a; - fp->ul_power_control_config_common.deltaF_PUCCH_Format2b = radioResourceConfigCommon->uplinkPowerControlCommon->deltaFList_PUCCH.deltaF_PUCCH_Format2b; - - fp->maxHARQ_Msg3Tx = radioResourceConfigCommon->rach_ConfigCommon->maxHARQ_Msg3Tx; - - // Now configure some of the Physical Channels - if (radioResourceConfigCommon->antennaInfoCommon) - fp->nb_antennas_tx = (1<antennaInfoCommon->antennaPortsCount); - else - fp->nb_antennas_tx = 1; - - //PHICH - if (radioResourceConfigCommon->antennaInfoCommon) { - fp->phich_config_common.phich_resource = radioResourceConfigCommon->phich_Config->phich_Resource; - fp->phich_config_common.phich_duration = radioResourceConfigCommon->phich_Config->phich_Duration; - } - - //Target CellId - fp->Nid_cell = mobilityControlInfo->targetPhysCellId; - fp->nushift = fp->Nid_cell%6; - - // PUCCH - init_ncs_cell(fp,PHY_vars_UE_g[Mod_id][CC_id]->ncs_cell); - - init_ul_hopping(fp); - - // RNTI - - - PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[0][eNB_id]->crnti = mobilityControlInfo->newUE_Identity.buf[0]|(mobilityControlInfo->newUE_Identity.buf[1]<<8); - PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[1][eNB_id]->crnti = mobilityControlInfo->newUE_Identity.buf[0]|(mobilityControlInfo->newUE_Identity.buf[1]<<8); - - LOG_I(PHY,"SET C-RNTI %x %x\n",PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[0][eNB_id]->crnti, - PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[1][eNB_id]->crnti); - } - - if(ho_failed) { - LOG_D(PHY,"[UE%d] Handover failed, triggering RACH procedure\n",Mod_id); - memcpy((void *)&PHY_vars_UE_g[Mod_id][CC_id]->frame_parms,(void *)&PHY_vars_UE_g[Mod_id][CC_id]->frame_parms_before_ho, sizeof(LTE_DL_FRAME_PARMS)); - PHY_vars_UE_g[Mod_id][CC_id]->UE_mode[eNB_id] = PRACH; - } -} - -void phy_config_meas_ue(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index,uint8_t n_adj_cells,unsigned int *adj_cell_id) -{ - - PHY_MEASUREMENTS *phy_meas = &PHY_vars_UE_g[Mod_id][CC_id]->measurements; - int i; - - LOG_I(PHY,"Configuring inter-cell measurements for %d cells, ids: \n",n_adj_cells); - - for (i=0; iframe_parms,PHY_vars_UE_g[Mod_id][CC_id]->lte_gold_table[i+1],adj_cell_id[i]); - } - - phy_meas->n_adj_cells = n_adj_cells; - memcpy((void*)phy_meas->adj_cell_id,(void *)adj_cell_id,n_adj_cells*sizeof(unsigned int)); - -} - /* void phy_config_dedicated_eNB(uint8_t Mod_id, int CC_id, @@ -975,14 +670,6 @@ void phy_config_dedicated_eNB(uint8_t Mod_id, } */ -#if defined(Rel10) || defined(Rel14) -void phy_config_dedicated_scell_ue(uint8_t Mod_id, - uint8_t eNB_index, - SCellToAddMod_r10_t *sCellToAddMod_r10, - int CC_id) -{ - -} /* void phy_config_dedicated_scell_eNB(uint8_t Mod_id, uint16_t rnti, @@ -1032,233 +719,8 @@ void phy_config_dedicated_scell_eNB(uint8_t Mod_id, } */ -#endif -void phy_config_harq_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id, - uint16_t max_harq_tx ) -{ - - PHY_VARS_UE *phy_vars_ue = PHY_vars_UE_g[Mod_id][CC_id]; - phy_vars_ue->ulsch[eNB_id]->Mlimit = max_harq_tx; -} - -extern uint16_t beta_cqi[16]; - -void phy_config_dedicated_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id, - struct PhysicalConfigDedicated *physicalConfigDedicated ) -{ - - static uint8_t first_dedicated_configuration = 0; - PHY_VARS_UE *phy_vars_ue = PHY_vars_UE_g[Mod_id][CC_id]; - - phy_vars_ue->total_TBS[eNB_id]=0; - phy_vars_ue->total_TBS_last[eNB_id]=0; - phy_vars_ue->bitrate[eNB_id]=0; - phy_vars_ue->total_received_bits[eNB_id]=0; - phy_vars_ue->dlsch_errors[eNB_id]=0; - phy_vars_ue->dlsch_errors_last[eNB_id]=0; - phy_vars_ue->dlsch_received[eNB_id]=0; - phy_vars_ue->dlsch_received_last[eNB_id]=0; - phy_vars_ue->dlsch_fer[eNB_id]=0; - - phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex = -1; - phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex = -1; - - if (physicalConfigDedicated) { - LOG_D(PHY,"[UE %d] Received physicalConfigDedicated from eNB %d\n",Mod_id, eNB_id); - LOG_D(PHY,"------------------------------------------------------------------------\n"); - - if (physicalConfigDedicated->pdsch_ConfigDedicated) { - phy_vars_ue->pdsch_config_dedicated[eNB_id].p_a=physicalConfigDedicated->pdsch_ConfigDedicated->p_a; - LOG_D(PHY,"pdsch_config_dedicated.p_a %d\n",phy_vars_ue->pdsch_config_dedicated[eNB_id].p_a); - LOG_D(PHY,"\n"); - } - - if (physicalConfigDedicated->pucch_ConfigDedicated) { - if (physicalConfigDedicated->pucch_ConfigDedicated->ackNackRepetition.present==PUCCH_ConfigDedicated__ackNackRepetition_PR_release) - phy_vars_ue->pucch_config_dedicated[eNB_id].ackNackRepetition=0; - else { - phy_vars_ue->pucch_config_dedicated[eNB_id].ackNackRepetition=1; - } - - if (physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode) - phy_vars_ue->pucch_config_dedicated[eNB_id].tdd_AckNackFeedbackMode = *physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode; - else - phy_vars_ue->pucch_config_dedicated[eNB_id].tdd_AckNackFeedbackMode = bundling; - - if ( phy_vars_ue->pucch_config_dedicated[eNB_id].tdd_AckNackFeedbackMode == multiplexing) - LOG_D(PHY,"pucch_config_dedicated.tdd_AckNackFeedbackMode = multiplexing\n"); - else - LOG_D(PHY,"pucch_config_dedicated.tdd_AckNackFeedbackMode = bundling\n"); - } - - if (physicalConfigDedicated->pusch_ConfigDedicated) { - phy_vars_ue->pusch_config_dedicated[eNB_id].betaOffset_ACK_Index = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_ACK_Index; - phy_vars_ue->pusch_config_dedicated[eNB_id].betaOffset_RI_Index = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index; - phy_vars_ue->pusch_config_dedicated[eNB_id].betaOffset_CQI_Index = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index; - - - LOG_D(PHY,"pusch_config_dedicated.betaOffset_ACK_Index %d\n",phy_vars_ue->pusch_config_dedicated[eNB_id].betaOffset_ACK_Index); - LOG_D(PHY,"pusch_config_dedicated.betaOffset_RI_Index %d\n",phy_vars_ue->pusch_config_dedicated[eNB_id].betaOffset_RI_Index); - LOG_D(PHY,"pusch_config_dedicated.betaOffset_CQI_Index %d => %d)\n",phy_vars_ue->pusch_config_dedicated[eNB_id].betaOffset_CQI_Index,beta_cqi[phy_vars_ue->pusch_config_dedicated[eNB_id].betaOffset_CQI_Index]); - LOG_D(PHY,"\n"); - - - } - - if (physicalConfigDedicated->uplinkPowerControlDedicated) { - - phy_vars_ue->ul_power_control_dedicated[eNB_id].p0_UE_PUSCH = physicalConfigDedicated->uplinkPowerControlDedicated->p0_UE_PUSCH; - phy_vars_ue->ul_power_control_dedicated[eNB_id].deltaMCS_Enabled= physicalConfigDedicated->uplinkPowerControlDedicated->deltaMCS_Enabled; - phy_vars_ue->ul_power_control_dedicated[eNB_id].accumulationEnabled= physicalConfigDedicated->uplinkPowerControlDedicated->accumulationEnabled; - phy_vars_ue->ul_power_control_dedicated[eNB_id].p0_UE_PUCCH= physicalConfigDedicated->uplinkPowerControlDedicated->p0_UE_PUCCH; - phy_vars_ue->ul_power_control_dedicated[eNB_id].pSRS_Offset= physicalConfigDedicated->uplinkPowerControlDedicated->pSRS_Offset; - phy_vars_ue->ul_power_control_dedicated[eNB_id].filterCoefficient= *physicalConfigDedicated->uplinkPowerControlDedicated->filterCoefficient; - LOG_D(PHY,"ul_power_control_dedicated.p0_UE_PUSCH %d\n",phy_vars_ue->ul_power_control_dedicated[eNB_id].p0_UE_PUSCH); - LOG_D(PHY,"ul_power_control_dedicated.deltaMCS_Enabled %d\n",phy_vars_ue->ul_power_control_dedicated[eNB_id].deltaMCS_Enabled); - LOG_D(PHY,"ul_power_control_dedicated.accumulationEnabled %d\n",phy_vars_ue->ul_power_control_dedicated[eNB_id].accumulationEnabled); - LOG_D(PHY,"ul_power_control_dedicated.p0_UE_PUCCH %d\n",phy_vars_ue->ul_power_control_dedicated[eNB_id].p0_UE_PUCCH); - LOG_D(PHY,"ul_power_control_dedicated.pSRS_Offset %d\n",phy_vars_ue->ul_power_control_dedicated[eNB_id].pSRS_Offset); - LOG_D(PHY,"ul_power_control_dedicated.filterCoefficient %d\n",phy_vars_ue->ul_power_control_dedicated[eNB_id].filterCoefficient); - LOG_D(PHY,"\n"); - } - - if (physicalConfigDedicated->antennaInfo) { - phy_vars_ue->transmission_mode[eNB_id] = 1+(physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode); - LOG_I(PHY,"Transmission Mode %d\n",phy_vars_ue->transmission_mode[eNB_id]); - switch(physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode) { - case AntennaInfoDedicated__transmissionMode_tm1: - phy_vars_ue->transmission_mode[eNB_id] = 1; - break; - case AntennaInfoDedicated__transmissionMode_tm2: - phy_vars_ue->transmission_mode[eNB_id] = 2; - break; - case AntennaInfoDedicated__transmissionMode_tm3: - phy_vars_ue->transmission_mode[eNB_id] = 3; - break; - case AntennaInfoDedicated__transmissionMode_tm4: - phy_vars_ue->transmission_mode[eNB_id] = 4; - break; - case AntennaInfoDedicated__transmissionMode_tm5: - phy_vars_ue->transmission_mode[eNB_id] = 5; - break; - case AntennaInfoDedicated__transmissionMode_tm6: - phy_vars_ue->transmission_mode[eNB_id] = 6; - break; - case AntennaInfoDedicated__transmissionMode_tm7: - lte_gold_ue_spec_port5(phy_vars_ue->lte_gold_uespec_port5_table, phy_vars_ue->frame_parms.Nid_cell, phy_vars_ue->pdcch_vars[0][eNB_id]->crnti); - phy_vars_ue->transmission_mode[eNB_id] = 7; - break; - default: - LOG_E(PHY,"Unknown transmission mode!\n"); - break; - } - } else { - LOG_D(PHY,"[UE %d] Received NULL physicalConfigDedicated->antennaInfo from eNB %d\n",Mod_id, eNB_id); - } - - if (physicalConfigDedicated->schedulingRequestConfig) { - if (physicalConfigDedicated->schedulingRequestConfig->present == SchedulingRequestConfig_PR_setup) { - phy_vars_ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex = physicalConfigDedicated->schedulingRequestConfig->choice.setup.sr_PUCCH_ResourceIndex; - phy_vars_ue->scheduling_request_config[eNB_id].sr_ConfigIndex=physicalConfigDedicated->schedulingRequestConfig->choice.setup.sr_ConfigIndex; - phy_vars_ue->scheduling_request_config[eNB_id].dsr_TransMax=physicalConfigDedicated->schedulingRequestConfig->choice.setup.dsr_TransMax; - - LOG_D(PHY,"scheduling_request_config.sr_PUCCH_ResourceIndex %d\n",phy_vars_ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex); - LOG_D(PHY,"scheduling_request_config.sr_ConfigIndex %d\n",phy_vars_ue->scheduling_request_config[eNB_id].sr_ConfigIndex); - LOG_D(PHY,"scheduling_request_config.dsr_TransMax %d\n",phy_vars_ue->scheduling_request_config[eNB_id].dsr_TransMax); - } - - LOG_D(PHY,"------------------------------------------------------------\n"); - - } - - if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated) { - - phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srsConfigDedicatedSetup = 0; - if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) { - phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srsConfigDedicatedSetup = 1; - phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].duration = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.duration; - phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].cyclicShift = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift; - phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].freqDomainPosition = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition; - phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srs_Bandwidth = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth; - phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srs_ConfigIndex = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex; - phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srs_HoppingBandwidth = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth; - phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].transmissionComb = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb; - - - LOG_D(PHY,"soundingrs_ul_config_dedicated.srs_ConfigIndex %d\n",phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srs_ConfigIndex); - } - - LOG_D(PHY,"------------------------------------------------------------\n"); - - } - - - if (physicalConfigDedicated->cqi_ReportConfig) { - if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic) { - // configure PUSCH CQI reporting - phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic = *physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic; - if ((phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic != rm12) && - (phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic != rm30) && - (phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic != rm31)) - LOG_E(PHY,"Unsupported Aperiodic CQI Feedback Mode : %d\n",phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic); - } - if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic) { - if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_setup) { - // configure PUCCH CQI reporting - phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PUCCH_ResourceIndex = physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex; - phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex = physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.cqi_pmi_ConfigIndex; - if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.ri_ConfigIndex) - phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex = *physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.ri_ConfigIndex; - } - else if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_release) { - // handle release - phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex = -1; - phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex = -1; - } - } - } - -#ifdef CBA - - if (physicalConfigDedicated->pusch_CBAConfigDedicated_vlola) { - phy_vars_ue->pusch_ca_config_dedicated[eNB_id].betaOffset_CA_Index = (uint16_t) *physicalConfigDedicated->pusch_CBAConfigDedicated_vlola->betaOffset_CBA_Index; - phy_vars_ue->pusch_ca_config_dedicated[eNB_id].cShift = (uint16_t) *physicalConfigDedicated->pusch_CBAConfigDedicated_vlola->cShift_CBA; - LOG_D(PHY,"[UE %d ] physicalConfigDedicated pusch CBA config dedicated: beta offset %d cshift %d \n",Mod_id, - phy_vars_ue->pusch_ca_config_dedicated[eNB_id].betaOffset_CA_Index, - phy_vars_ue->pusch_ca_config_dedicated[eNB_id].cShift); - } - -#endif - } else { - LOG_D(PHY,"[PHY][UE %d] Received NULL radioResourceConfigDedicated from eNB %d\n",Mod_id,eNB_id); - return; - } - - // fill cqi parameters for periodic CQI reporting - get_cqipmiri_params(phy_vars_ue,eNB_id); - - // disable MIB SIB decoding once we are on connected mode - first_dedicated_configuration ++; - if(first_dedicated_configuration > 1) - { - LOG_I(PHY,"Disable SIB MIB decoding \n"); - phy_vars_ue->decode_SIB = 0; - phy_vars_ue->decode_MIB = 0; - } - //phy_vars_ue->pdcch_vars[1][eNB_id]->crnti = phy_vars_ue->pdcch_vars[0][eNB_id]->crnti; - if(phy_vars_ue->pdcch_vars[0][eNB_id]->crnti == 0x1234) - phy_vars_ue->pdcch_vars[0][eNB_id]->crnti = phy_vars_ue->pdcch_vars[1][eNB_id]->crnti; - else - phy_vars_ue->pdcch_vars[1][eNB_id]->crnti = phy_vars_ue->pdcch_vars[0][eNB_id]->crnti; - - LOG_I(PHY,"C-RNTI %x %x \n", phy_vars_ue->pdcch_vars[0][eNB_id]->crnti, - phy_vars_ue->pdcch_vars[1][eNB_id]->crnti); - - -} - void phy_config_cba_rnti (module_id_t Mod_id,int CC_id,eNB_flag_t eNB_flag, uint8_t index, rnti_t cba_rnti, uint8_t cba_group_id, uint8_t num_active_cba_groups) { // uint8_t i; @@ -1276,546 +738,6 @@ void phy_config_cba_rnti (module_id_t Mod_id,int CC_id,eNB_flag_t eNB_flag, uin } } -void init_lte_top(LTE_DL_FRAME_PARMS *frame_parms) -{ - - crcTableInit(); - - ccodedot11_init(); - ccodedot11_init_inv(); - - ccodelte_init(); - ccodelte_init_inv(); - - treillis_table_init(); - - phy_generate_viterbi_tables(); - phy_generate_viterbi_tables_lte(); - init_td8(); - init_td16(); -#ifdef __AVX2__ - init_td16avx2(); -#endif - lte_sync_time_init(frame_parms); - - generate_ul_ref_sigs(); - generate_ul_ref_sigs_rx(); - - generate_64qam_table(); - generate_16qam_table(); - generate_RIV_tables(); - - init_unscrambling_lut(); - init_scrambling_lut(); - //set_taus_seed(1328); - - -} - -/*! \brief Helper function to allocate memory for DLSCH data structures. - * \param[out] pdsch Pointer to the LTE_UE_PDSCH structure to initialize. - * \param[in] frame_parms LTE_DL_FRAME_PARMS structure. - * \note This function is optimistic in that it expects malloc() to succeed. - */ -void phy_init_lte_ue__PDSCH( LTE_UE_PDSCH* const pdsch, const LTE_DL_FRAME_PARMS* const fp ) -{ - AssertFatal( pdsch, "pdsch==0" ); - - pdsch->pmi_ext = (uint8_t*)malloc16_clear( fp->N_RB_DL ); - pdsch->llr[0] = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); - pdsch->llr128 = (int16_t**)malloc16_clear( sizeof(int16_t*) ); - // FIXME! no further allocation for (int16_t*)pdsch->llr128 !!! expect SIGSEGV - // FK, 11-3-2015: this is only as a temporary pointer, no memory is stored there - - - pdsch->rxdataF_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pdsch->rxdataF_uespec_pilots = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pdsch->rxdataF_comp0 = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pdsch->rho = (int32_t**)malloc16_clear( fp->nb_antennas_rx*sizeof(int32_t*) ); - pdsch->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pdsch->dl_bf_ch_estimates = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pdsch->dl_bf_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - //pdsch->dl_ch_rho_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - //pdsch->dl_ch_rho2_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pdsch->dl_ch_mag0 = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pdsch->dl_ch_magb0 = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - - - // the allocated memory size is fixed: - AssertFatal( fp->nb_antennas_rx <= 2, "nb_antennas_rx > 2" ); - - for (int i=0; inb_antennas_rx; i++) { - pdsch->rho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->N_RB_DL*12*7*2) ); - - for (int j=0; j<4; j++) { //fp->nb_antennas_tx; j++) - const int idx = (j<<1)+i; - const size_t num = 7*2*fp->N_RB_DL*12; - pdsch->rxdataF_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - pdsch->rxdataF_uespec_pilots[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * fp->N_RB_DL*12); - pdsch->rxdataF_comp0[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - pdsch->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - pdsch->dl_bf_ch_estimates[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * fp->ofdm_symbol_size*7*2); - pdsch->dl_bf_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - //pdsch->dl_ch_rho_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - //pdsch->dl_ch_rho2_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - pdsch->dl_ch_mag0[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - pdsch->dl_ch_magb0[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - } - } -} - -int init_lte_ue_signal(PHY_VARS_UE *ue, - int nb_connected_eNB, - uint8_t abstraction_flag) -{ - - // create shortcuts - LTE_DL_FRAME_PARMS* const fp = &ue->frame_parms; - LTE_UE_COMMON* const common_vars = &ue->common_vars; - LTE_UE_PDSCH** const pdsch_vars_SI = ue->pdsch_vars_SI; - LTE_UE_PDSCH** const pdsch_vars_ra = ue->pdsch_vars_ra; - LTE_UE_PDSCH** const pdsch_vars_p = ue->pdsch_vars_p; - LTE_UE_PDSCH** const pdsch_vars_mch = ue->pdsch_vars_MCH; - LTE_UE_PDSCH* (*pdsch_vars_th)[][NUMBER_OF_CONNECTED_eNB_MAX+1] = &ue->pdsch_vars; - LTE_UE_PDCCH* (*pdcch_vars_th)[][NUMBER_OF_CONNECTED_eNB_MAX] = &ue->pdcch_vars; - LTE_UE_PBCH** const pbch_vars = ue->pbch_vars; - LTE_UE_PRACH** const prach_vars = ue->prach_vars; - - - - int i,j,k,l; - int eNB_id; - int th_id; - - LOG_D(PHY,"Initializing UE vars (abstraction %"PRIu8") for eNB TXant %"PRIu8", UE RXant %"PRIu8"\n",abstraction_flag,fp->nb_antennas_tx,fp->nb_antennas_rx); - LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_UE][MOD %02u][]\n", ue->Mod_id+NB_eNB_INST); - - - - init_frame_parms(&ue->frame_parms,1); - init_lte_top(&ue->frame_parms); - init_ul_hopping(&ue->frame_parms); - - - // many memory allocation sizes are hard coded - AssertFatal( fp->nb_antennas_rx <= 2, "hard coded allocation for ue_common_vars->dl_ch_estimates[eNB_id]" ); - AssertFatal( ue->n_connected_eNB <= NUMBER_OF_CONNECTED_eNB_MAX, "n_connected_eNB is too large" ); - // init phy_vars_ue - - for (i=0; i<4; i++) { - ue->rx_gain_max[i] = 135; - ue->rx_gain_med[i] = 128; - ue->rx_gain_byp[i] = 120; - } - - ue->n_connected_eNB = nb_connected_eNB; - - for(eNB_id = 0; eNB_id < ue->n_connected_eNB; eNB_id++) { - ue->total_TBS[eNB_id] = 0; - ue->total_TBS_last[eNB_id] = 0; - ue->bitrate[eNB_id] = 0; - ue->total_received_bits[eNB_id] = 0; - } - - for (i=0;i<10;i++) - ue->tx_power_dBm[i]=-127; - - - - // init TX buffers - - common_vars->txdata = (int32_t**)malloc16( fp->nb_antennas_tx*sizeof(int32_t*) ); - common_vars->txdataF = (int32_t **)malloc16( fp->nb_antennas_tx*sizeof(int32_t*) ); - - for (i=0; inb_antennas_tx; i++) { - - common_vars->txdata[i] = (int32_t*)malloc16_clear( fp->samples_per_tti*10*sizeof(int32_t) ); - common_vars->txdataF[i] = (int32_t *)malloc16_clear( fp->ofdm_symbol_size*fp->symbols_per_tti*10*sizeof(int32_t) ); - } - - // init RX buffers - - common_vars->rxdata = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - common_vars->common_vars_rx_data_per_thread[0].rxdataF = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - common_vars->common_vars_rx_data_per_thread[1].rxdataF = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - - for (i=0; inb_antennas_rx; i++) { - common_vars->rxdata[i] = (int32_t*) malloc16_clear( (fp->samples_per_tti*10+2048)*sizeof(int32_t) ); - common_vars->common_vars_rx_data_per_thread[0].rxdataF[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->ofdm_symbol_size*14) ); - common_vars->common_vars_rx_data_per_thread[1].rxdataF[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->ofdm_symbol_size*14) ); - } - - - // Channel estimates - for (eNB_id=0; eNB_id<7; eNB_id++) { - for (th_id=0; th_idcommon_vars_rx_data_per_thread[th_id].dl_ch_estimates[eNB_id] = (int32_t**)malloc16_clear(8*sizeof(int32_t*)); - common_vars->common_vars_rx_data_per_thread[th_id].dl_ch_estimates_time[eNB_id] = (int32_t**)malloc16_clear(8*sizeof(int32_t*)); - } - - for (i=0; inb_antennas_rx; i++) - for (j=0; j<4; j++) { - int idx = (j<<1) + i; - for (th_id=0; th_idcommon_vars_rx_data_per_thread[th_id].dl_ch_estimates[eNB_id][idx] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->symbols_per_tti*(fp->ofdm_symbol_size+LTE_CE_FILTER_LENGTH) ); - common_vars->common_vars_rx_data_per_thread[th_id].dl_ch_estimates_time[eNB_id][idx] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2 ); - } - } - } - - // DLSCH - for (eNB_id=0; eNB_idn_connected_eNB; eNB_id++) { - for (th_id=0; th_idllr_shifts = (uint8_t*)malloc16_clear(7*2*fp->N_RB_DL*12); - (*pdsch_vars_th)[th_id][eNB_id]->llr_shifts_p = (*pdsch_vars_th)[0][eNB_id]->llr_shifts; - (*pdsch_vars_th)[th_id][eNB_id]->llr[1] = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); - (*pdsch_vars_th)[th_id][eNB_id]->llr128_2ndstream = (int16_t**)malloc16_clear( sizeof(int16_t*) ); - (*pdsch_vars_th)[th_id][eNB_id]->rho = (int32_t**)malloc16_clear( fp->nb_antennas_rx*sizeof(int32_t*) ); - } - - for (int i=0; inb_antennas_rx; i++){ - for (th_id=0; th_idrho[i] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); - } - - } - for (th_id=0; th_iddl_ch_rho2_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - } - - for (i=0; inb_antennas_rx; i++) - for (j=0; j<4; j++) { - const int idx = (j<<1)+i; - const size_t num = 7*2*fp->N_RB_DL*12+4; - for (th_id=0; th_iddl_ch_rho2_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - } - - } - - //const size_t num = 7*2*fp->N_RB_DL*12+4; - for (k=0;k<8;k++) { //harq_pid - for (l=0;l<8;l++) { //round - for (th_id=0; th_idrxdataF_comp1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_mag1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_magb1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - } - - - for (int i=0; inb_antennas_rx; i++) - for (int j=0; j<4; j++) { //frame_parms->nb_antennas_tx; j++) - const int idx = (j<<1)+i; - for (th_id=0; th_iddl_ch_rho_ext[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); - (*pdsch_vars_th)[th_id][eNB_id]->rxdataF_comp1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); - (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_mag1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); - (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_magb1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); - } - - } - } - } - phy_init_lte_ue__PDSCH( pdsch_vars_SI[eNB_id], fp ); - phy_init_lte_ue__PDSCH( pdsch_vars_ra[eNB_id], fp ); - phy_init_lte_ue__PDSCH( pdsch_vars_p[eNB_id], fp ); - phy_init_lte_ue__PDSCH( pdsch_vars_mch[eNB_id], fp ); - - // 100 PRBs * 12 REs/PRB * 4 PDCCH SYMBOLS * 2 LLRs/RE - for (th_id=0; th_idllr = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); - (*pdcch_vars_th)[th_id][eNB_id]->llr16 = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); - (*pdcch_vars_th)[th_id][eNB_id]->wbar = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); - (*pdcch_vars_th)[th_id][eNB_id]->e_rx = (int8_t*)malloc16_clear( 4*2*100*12 ); - - (*pdcch_vars_th)[th_id][eNB_id]->rxdataF_comp = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - (*pdcch_vars_th)[th_id][eNB_id]->rho = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - (*pdcch_vars_th)[th_id][eNB_id]->rxdataF_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - } - - for (i=0; inb_antennas_rx; i++) { - //ue_pdcch_vars[eNB_id]->rho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->N_RB_DL*12*7*2) ); - for (th_id=0; th_idrho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(100*12*4) ); - } - - for (j=0; j<4; j++) { //fp->nb_antennas_tx; j++) - int idx = (j<<1)+i; - // size_t num = 7*2*fp->N_RB_DL*12; - size_t num = 4*100*12; // 4 symbols, 100 PRBs, 12 REs per PRB - for (th_id=0; th_idrxdataF_comp[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - (*pdcch_vars_th)[th_id][eNB_id]->rxdataF_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - } - } - } - phy_init_lte_ue__PDSCH( pdsch_vars_SI[eNB_id], fp ); - phy_init_lte_ue__PDSCH( pdsch_vars_ra[eNB_id], fp ); - phy_init_lte_ue__PDSCH( pdsch_vars_p[eNB_id], fp ); - phy_init_lte_ue__PDSCH( pdsch_vars_mch[eNB_id], fp ); - - // 100 PRBs * 12 REs/PRB * 4 PDCCH SYMBOLS * 2 LLRs/RE - for (th_id=0; th_idllr = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); - (*pdcch_vars_th)[th_id][eNB_id]->llr16 = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); - (*pdcch_vars_th)[th_id][eNB_id]->wbar = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); - (*pdcch_vars_th)[th_id][eNB_id]->e_rx = (int8_t*)malloc16_clear( 4*2*100*12 ); - - (*pdcch_vars_th)[th_id][eNB_id]->rxdataF_comp = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - (*pdcch_vars_th)[th_id][eNB_id]->rho = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - (*pdcch_vars_th)[th_id][eNB_id]->rxdataF_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - } - - for (i=0; inb_antennas_rx; i++) { - //ue_pdcch_vars[eNB_id]->rho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->N_RB_DL*12*7*2) ); - - for (th_id=0; th_idrho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(100*12*4) ); - } - - for (j=0; j<4; j++) { //fp->nb_antennas_tx; j++) - int idx = (j<<1)+i; - // size_t num = 7*2*fp->N_RB_DL*12; - size_t num = 4*100*12; // 4 symbols, 100 PRBs, 12 REs per PRB - for (th_id=0; th_idrxdataF_comp[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - (*pdcch_vars_th)[th_id][eNB_id]->rxdataF_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - } - } - } - - // PBCH - pbch_vars[eNB_id]->rxdataF_ext = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - pbch_vars[eNB_id]->rxdataF_comp = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pbch_vars[eNB_id]->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pbch_vars[eNB_id]->llr = (int8_t*)malloc16_clear( 1920 ); - prach_vars[eNB_id]->prachF = (int16_t*)malloc16_clear( sizeof(int)*(7*2*sizeof(int)*(fp->ofdm_symbol_size*12)) ); - prach_vars[eNB_id]->prach = (int16_t*)malloc16_clear( sizeof(int)*(7*2*sizeof(int)*(fp->ofdm_symbol_size*12)) ); - - for (i=0; inb_antennas_rx; i++) { - pbch_vars[eNB_id]->rxdataF_ext[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*6*12*4 ); - - for (j=0; j<4; j++) {//fp->nb_antennas_tx;j++) { - int idx = (j<<1)+i; - pbch_vars[eNB_id]->rxdataF_comp[idx] = (int32_t*)malloc16_clear( sizeof(int32_t)*6*12*4 ); - pbch_vars[eNB_id]->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t)*6*12*4 ); - } - } - - - pbch_vars[eNB_id]->decoded_output = (uint8_t*)malloc16_clear( 64 ); - } - - // initialization for the last instance of pdsch_vars (used for MU-MIMO) - for (th_id=0; th_idllr[1] = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); - } - - - ue->sinr_CQI_dB = (double*) malloc16_clear( fp->N_RB_DL*12*sizeof(double) ); - - ue->init_averaging = 1; - // default value until overwritten by RRCConnectionReconfiguration - if (fp->nb_antenna_ports_eNB==2) - ue->pdsch_config_dedicated->p_a = dBm3; - else - ue->pdsch_config_dedicated->p_a = dB0; - - // set channel estimation to do linear interpolation in time - ue->high_speed_flag = 1; - ue->ch_est_alpha = 24576; - - // enable MIB/SIB decoding by default - ue->decode_MIB = 1; - ue->decode_SIB = 1; - - init_prach_tables(839); - - - return 0; -} - -void init_lte_ue_transport(PHY_VARS_UE *ue,int abstraction_flag) { - - int i,j,k; - - for (i=0; idlsch[k][i][j] = new_ue_dlsch(1,NUMBER_OF_HARQ_PID_MAX,NSOFT,MAX_TURBO_ITERATIONS,ue->frame_parms.N_RB_DL, abstraction_flag))!=NULL,"Can't get ue dlsch structures\n"); - - LOG_D(PHY,"dlsch[%d][%d][%d] => %p\n",k,i,j,ue->dlsch[i][j]); - } - } - - AssertFatal((ue->ulsch[i] = new_ue_ulsch(ue->frame_parms.N_RB_UL, abstraction_flag))!=NULL,"Can't get ue ulsch structures\n"); - - ue->dlsch_SI[i] = new_ue_dlsch(1,1,NSOFT,MAX_TURBO_ITERATIONS,ue->frame_parms.N_RB_DL, abstraction_flag); - ue->dlsch_ra[i] = new_ue_dlsch(1,1,NSOFT,MAX_TURBO_ITERATIONS,ue->frame_parms.N_RB_DL, abstraction_flag); - - ue->transmission_mode[i] = ue->frame_parms.nb_antenna_ports_eNB==1 ? 1 : 2; - } - - ue->frame_parms.pucch_config_common.deltaPUCCH_Shift = 1; - - ue->dlsch_MCH[0] = new_ue_dlsch(1,NUMBER_OF_HARQ_PID_MAX,NSOFT,MAX_TURBO_ITERATIONS_MBSFN,ue->frame_parms.N_RB_DL,0); - -} - -int phy_init_RU(RU_t *ru) { - - LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; - int i,j; - int p; - int re; - - LOG_I(PHY,"Initializing RU signal buffers (if_south %s) nb_tx %d\n",ru_if_types[ru->if_south],ru->nb_tx); - - if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so allocate memory for time-domain signals - // Time-domain signals - ru->common.txdata = (int32_t**)malloc16(ru->nb_tx*sizeof(int32_t*)); - ru->common.rxdata = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) ); - - - for (i=0; inb_tx; i++) { - // Allocate 10 subframes of I/Q TX signal data (time) if not - ru->common.txdata[i] = (int32_t*)malloc16_clear( fp->samples_per_tti*10*sizeof(int32_t) ); - - LOG_I(PHY,"[INIT] common.txdata[%d] = %p (%lu bytes)\n",i,ru->common.txdata[i], - fp->samples_per_tti*10*sizeof(int32_t)); - - } - for (i=0;inb_rx;i++) { - ru->common.rxdata[i] = (int32_t*)malloc16_clear( fp->samples_per_tti*10*sizeof(int32_t) ); - } - } // IF5 or local RF - else { - LOG_I(PHY,"No rxdata/txdata for RU\n"); - ru->common.txdata = (int32_t**)NULL; - ru->common.rxdata = (int32_t**)NULL; - - } - if (ru->function != NGFI_RRU_IF5) { // we need to do RX/TX RU processing - LOG_I(PHY,"nb_tx %d\n",ru->nb_tx); - ru->common.rxdata_7_5kHz = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) ); - for (i=0;inb_rx;i++) { - ru->common.rxdata_7_5kHz[i] = (int32_t*)malloc16_clear( 2*fp->samples_per_tti*2*sizeof(int32_t) ); - LOG_I(PHY,"rxdata_7_5kHz[%d] %p for RU %d\n",i,ru->common.rxdata_7_5kHz[i],ru->idx); - } - - - // allocate IFFT input buffers (TX) - ru->common.txdataF_BF = (int32_t **)malloc16(ru->nb_tx*sizeof(int32_t*)); - LOG_I(PHY,"[INIT] common.txdata_BF= %p (%lu bytes)\n",ru->common.txdataF_BF, - ru->nb_tx*sizeof(int32_t*)); - for (i=0; inb_tx; i++) { - ru->common.txdataF_BF[i] = (int32_t*)malloc16_clear(fp->symbols_per_tti*fp->ofdm_symbol_size*sizeof(int32_t) ); - LOG_I(PHY,"txdataF_BF[%d] %p for RU %d\n",i,ru->common.txdataF_BF[i],ru->idx); - } - // allocate FFT output buffers (RX) - ru->common.rxdataF = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) ); - for (i=0; inb_rx; i++) { - // allocate 2 subframes of I/Q signal data (frequency) - ru->common.rxdataF[i] = (int32_t*)malloc16_clear(sizeof(int32_t)*(2*fp->ofdm_symbol_size*fp->symbols_per_tti) ); - LOG_I(PHY,"rxdataF[%d] %p for RU %d\n",i,ru->common.rxdataF[i],ru->idx); - } - - /* number of elements of an array X is computed as sizeof(X) / sizeof(X[0]) */ - AssertFatal(ru->nb_rx <= sizeof(ru->prach_rxsigF) / sizeof(ru->prach_rxsigF[0]), - "nb_antennas_rx too large"); - ru->prach_rxsigF = (int16_t**)malloc(ru->nb_rx * sizeof(int16_t*)); - for (j=0;j<4;j++) ru->prach_rxsigF_br[j] = (int16_t**)malloc(ru->nb_rx * sizeof(int16_t*)); - - for (i=0; inb_rx; i++) { - ru->prach_rxsigF[i] = (int16_t*)malloc16_clear( fp->ofdm_symbol_size*12*2*sizeof(int16_t) ); - LOG_D(PHY,"[INIT] prach_vars->rxsigF[%d] = %p\n",i,ru->prach_rxsigF[i]); -#ifdef Rel14 - for (j=0;j<4;j++) { - ru->prach_rxsigF_br[j][i] = (int16_t*)malloc16_clear( fp->ofdm_symbol_size*12*2*sizeof(int16_t) ); - LOG_D(PHY,"[INIT] prach_vars_br->rxsigF[%d] = %p\n",i,ru->prach_rxsigF_br[j][i]); - } -#endif - } - - AssertFatal(RC.nb_L1_inst <= NUMBER_OF_eNB_MAX,"eNB instances %d > %d\n", - RC.nb_L1_inst,NUMBER_OF_eNB_MAX); - - LOG_E(PHY,"[INIT] %s() RC.nb_L1_inst:%d \n", __FUNCTION__, RC.nb_L1_inst); - - for (i=0; ieNB_list[i]->frame_parms.nb_antenna_ports_eNB); - if (peNB_list[i]->frame_parms.nb_antenna_ports_eNB || p==5) { - LOG_D(PHY,"[INIT] %s() DO BEAM WEIGHTS nb_antenna_ports_eNB:%d nb_tx:%d\n", __FUNCTION__, ru->eNB_list[i]->frame_parms.nb_antenna_ports_eNB, ru->nb_tx); - ru->beam_weights[i][p] = (int32_t **)malloc16_clear(ru->nb_tx*sizeof(int32_t*)); - for (j=0; jnb_tx; j++) { - ru->beam_weights[i][p][j] = (int32_t *)malloc16_clear(fp->ofdm_symbol_size*sizeof(int32_t)); - // antenna ports 0-3 are mapped on antennas 0-3 - // antenna port 4 is mapped on antenna 0 - // antenna ports 5-14 are mapped on all antennas - if (((p<4) && (p==j)) || ((p==4) && (j==0))) { - for (re=0; reofdm_symbol_size; re++) - { - ru->beam_weights[i][p][j][re] = 0x00007fff; - - //LOG_D(PHY,"[INIT] lte_common_vars->beam_weights[%d][%d][%d][%d] = %d\n", i,p,j,re,ru->beam_weights[i][p][j][re]); - } - } - else if (p>4) { - for (re=0; reofdm_symbol_size; re++) - { - ru->beam_weights[i][p][j][re] = 0x00007fff/ru->nb_tx; - //LOG_D(PHY,"[INIT] lte_common_vars->beam_weights[%d][%d][%d][%d] = %d\n", i,p,j,re,ru->beam_weights[i][p][j][re]); - } - } - //LOG_D(PHY,"[INIT] lte_common_vars->beam_weights[%d][%d] = %p (%lu bytes)\n", i,j,ru->beam_weights[i][p][j], fp->ofdm_symbol_size*sizeof(int32_t)); - } - } - } - } - } - ru->common.sync_corr = (uint32_t*)malloc16_clear( LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*sizeof(uint32_t)*fp->samples_per_tti ); - - return(0); -} - int phy_init_lte_eNB(PHY_VARS_eNB *eNB, unsigned char is_secondary_eNB, unsigned char abstraction_flag) diff --git a/openair1/PHY/INIT/lte_init_ru.c b/openair1/PHY/INIT/lte_init_ru.c new file mode 100644 index 0000000000..2d139e0afa --- /dev/null +++ b/openair1/PHY/INIT/lte_init_ru.c @@ -0,0 +1,150 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "defs.h" +#include "SCHED/defs.h" +#include "PHY/extern.h" +#include "SIMULATION/TOOLS/defs.h" +#include "RadioResourceConfigCommonSIB.h" +#include "RadioResourceConfigDedicated.h" +#include "TDD-Config.h" +#include "LAYER2/MAC/extern.h" +#include "MBSFN-SubframeConfigList.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "assertions.h" +#include + +int phy_init_RU(RU_t *ru) { + + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + int i,j; + int p; + int re; + + LOG_I(PHY,"Initializing RU signal buffers (if_south %s) nb_tx %d\n",ru_if_types[ru->if_south],ru->nb_tx); + + if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so allocate memory for time-domain signals + // Time-domain signals + ru->common.txdata = (int32_t**)malloc16(ru->nb_tx*sizeof(int32_t*)); + ru->common.rxdata = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) ); + + + for (i=0; inb_tx; i++) { + // Allocate 10 subframes of I/Q TX signal data (time) if not + ru->common.txdata[i] = (int32_t*)malloc16_clear( fp->samples_per_tti*10*sizeof(int32_t) ); + + LOG_I(PHY,"[INIT] common.txdata[%d] = %p (%lu bytes)\n",i,ru->common.txdata[i], + fp->samples_per_tti*10*sizeof(int32_t)); + + } + for (i=0;inb_rx;i++) { + ru->common.rxdata[i] = (int32_t*)malloc16_clear( fp->samples_per_tti*10*sizeof(int32_t) ); + } + } // IF5 or local RF + else { + LOG_I(PHY,"No rxdata/txdata for RU\n"); + ru->common.txdata = (int32_t**)NULL; + ru->common.rxdata = (int32_t**)NULL; + + } + if (ru->function != NGFI_RRU_IF5) { // we need to do RX/TX RU processing + LOG_I(PHY,"nb_tx %d\n",ru->nb_tx); + ru->common.rxdata_7_5kHz = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) ); + for (i=0;inb_rx;i++) { + ru->common.rxdata_7_5kHz[i] = (int32_t*)malloc16_clear( 2*fp->samples_per_tti*2*sizeof(int32_t) ); + LOG_I(PHY,"rxdata_7_5kHz[%d] %p for RU %d\n",i,ru->common.rxdata_7_5kHz[i],ru->idx); + } + + + // allocate IFFT input buffers (TX) + ru->common.txdataF_BF = (int32_t **)malloc16(ru->nb_tx*sizeof(int32_t*)); + LOG_I(PHY,"[INIT] common.txdata_BF= %p (%lu bytes)\n",ru->common.txdataF_BF, + ru->nb_tx*sizeof(int32_t*)); + for (i=0; inb_tx; i++) { + ru->common.txdataF_BF[i] = (int32_t*)malloc16_clear(fp->symbols_per_tti*fp->ofdm_symbol_size*sizeof(int32_t) ); + LOG_I(PHY,"txdataF_BF[%d] %p for RU %d\n",i,ru->common.txdataF_BF[i],ru->idx); + } + // allocate FFT output buffers (RX) + ru->common.rxdataF = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) ); + for (i=0; inb_rx; i++) { + // allocate 2 subframes of I/Q signal data (frequency) + ru->common.rxdataF[i] = (int32_t*)malloc16_clear(sizeof(int32_t)*(2*fp->ofdm_symbol_size*fp->symbols_per_tti) ); + LOG_I(PHY,"rxdataF[%d] %p for RU %d\n",i,ru->common.rxdataF[i],ru->idx); + } + + /* number of elements of an array X is computed as sizeof(X) / sizeof(X[0]) */ + AssertFatal(ru->nb_rx <= sizeof(ru->prach_rxsigF) / sizeof(ru->prach_rxsigF[0]), + "nb_antennas_rx too large"); + ru->prach_rxsigF = (int16_t**)malloc(ru->nb_rx * sizeof(int16_t*)); + for (j=0;j<4;j++) ru->prach_rxsigF_br[j] = (int16_t**)malloc(ru->nb_rx * sizeof(int16_t*)); + + for (i=0; inb_rx; i++) { + ru->prach_rxsigF[i] = (int16_t*)malloc16_clear( fp->ofdm_symbol_size*12*2*sizeof(int16_t) ); + LOG_D(PHY,"[INIT] prach_vars->rxsigF[%d] = %p\n",i,ru->prach_rxsigF[i]); +#ifdef Rel14 + for (j=0;j<4;j++) { + ru->prach_rxsigF_br[j][i] = (int16_t*)malloc16_clear( fp->ofdm_symbol_size*12*2*sizeof(int16_t) ); + LOG_D(PHY,"[INIT] prach_vars_br->rxsigF[%d] = %p\n",i,ru->prach_rxsigF_br[j][i]); + } +#endif + } + + AssertFatal(RC.nb_L1_inst <= NUMBER_OF_eNB_MAX,"eNB instances %d > %d\n", + RC.nb_L1_inst,NUMBER_OF_eNB_MAX); + + LOG_E(PHY,"[INIT] %s() RC.nb_L1_inst:%d \n", __FUNCTION__, RC.nb_L1_inst); + + for (i=0; ieNB_list[i]->frame_parms.nb_antenna_ports_eNB); + if (peNB_list[i]->frame_parms.nb_antenna_ports_eNB || p==5) { + LOG_D(PHY,"[INIT] %s() DO BEAM WEIGHTS nb_antenna_ports_eNB:%d nb_tx:%d\n", __FUNCTION__, ru->eNB_list[i]->frame_parms.nb_antenna_ports_eNB, ru->nb_tx); + ru->beam_weights[i][p] = (int32_t **)malloc16_clear(ru->nb_tx*sizeof(int32_t*)); + for (j=0; jnb_tx; j++) { + ru->beam_weights[i][p][j] = (int32_t *)malloc16_clear(fp->ofdm_symbol_size*sizeof(int32_t)); + // antenna ports 0-3 are mapped on antennas 0-3 + // antenna port 4 is mapped on antenna 0 + // antenna ports 5-14 are mapped on all antennas + if (((p<4) && (p==j)) || ((p==4) && (j==0))) { + for (re=0; reofdm_symbol_size; re++) + { + ru->beam_weights[i][p][j][re] = 0x00007fff; + + //LOG_D(PHY,"[INIT] lte_common_vars->beam_weights[%d][%d][%d][%d] = %d\n", i,p,j,re,ru->beam_weights[i][p][j][re]); + } + } + else if (p>4) { + for (re=0; reofdm_symbol_size; re++) + { + ru->beam_weights[i][p][j][re] = 0x00007fff/ru->nb_tx; + //LOG_D(PHY,"[INIT] lte_common_vars->beam_weights[%d][%d][%d][%d] = %d\n", i,p,j,re,ru->beam_weights[i][p][j][re]); + } + } + //LOG_D(PHY,"[INIT] lte_common_vars->beam_weights[%d][%d] = %p (%lu bytes)\n", i,j,ru->beam_weights[i][p][j], fp->ofdm_symbol_size*sizeof(int32_t)); + } // for (j=0 + } // if (pcommon.sync_corr = (uint32_t*)malloc16_clear( LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*sizeof(uint32_t)*fp->samples_per_tti ); + + return(0); +} diff --git a/openair1/PHY/INIT/lte_init_ue.c b/openair1/PHY/INIT/lte_init_ue.c new file mode 100644 index 0000000000..16274d6878 --- /dev/null +++ b/openair1/PHY/INIT/lte_init_ue.c @@ -0,0 +1,963 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "defs.h" +#include "SCHED/defs.h" +#include "PHY/extern.h" +#include "SIMULATION/TOOLS/defs.h" +#include "RadioResourceConfigCommonSIB.h" +#include "RadioResourceConfigDedicated.h" +#include "TDD-Config.h" +#include "LAYER2/MAC/extern.h" +#include "MBSFN-SubframeConfigList.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "assertions.h" +#include + + +uint8_t dmrs1_tab_ue[8] = {0,2,3,4,6,8,9,10}; + +void phy_config_sib1_ue(uint8_t Mod_id,int CC_id, + uint8_t eNB_id, + TDD_Config_t *tdd_Config, + uint8_t SIwindowsize, + uint16_t SIperiod) +{ + + LTE_DL_FRAME_PARMS *fp = &PHY_vars_UE_g[Mod_id][CC_id]->frame_parms; + + if (tdd_Config) { + fp->tdd_config = tdd_Config->subframeAssignment; + fp->tdd_config_S = tdd_Config->specialSubframePatterns; + } + + fp->SIwindowsize = SIwindowsize; + fp->SIPeriod = SIperiod; +} + +void phy_config_sib2_ue(uint8_t Mod_id,int CC_id, + uint8_t eNB_id, + RadioResourceConfigCommonSIB_t *radioResourceConfigCommon, + ARFCN_ValueEUTRA_t *ul_CarrierFreq, + long *ul_Bandwidth, + AdditionalSpectrumEmission_t *additionalSpectrumEmission, + struct MBSFN_SubframeConfigList *mbsfn_SubframeConfigList) +{ + + PHY_VARS_UE *ue = PHY_vars_UE_g[Mod_id][CC_id]; + LTE_DL_FRAME_PARMS *fp = &ue->frame_parms; + int i; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_CONFIG_SIB2, VCD_FUNCTION_IN); + + LOG_I(PHY,"[UE%d] Applying radioResourceConfigCommon from eNB%d\n",Mod_id,eNB_id); + + fp->prach_config_common.rootSequenceIndex =radioResourceConfigCommon->prach_Config.rootSequenceIndex; + + fp->prach_config_common.prach_Config_enabled=1; + fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex =radioResourceConfigCommon->prach_Config.prach_ConfigInfo.prach_ConfigIndex; + fp->prach_config_common.prach_ConfigInfo.highSpeedFlag =radioResourceConfigCommon->prach_Config.prach_ConfigInfo.highSpeedFlag; + fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig =radioResourceConfigCommon->prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig; + fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset =radioResourceConfigCommon->prach_Config.prach_ConfigInfo.prach_FreqOffset; + + compute_prach_seq(fp->prach_config_common.rootSequenceIndex, + fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex, + fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, + fp->prach_config_common.prach_ConfigInfo.highSpeedFlag, + fp->frame_type,ue->X_u); + + + + fp->pucch_config_common.deltaPUCCH_Shift = 1+radioResourceConfigCommon->pucch_ConfigCommon.deltaPUCCH_Shift; + fp->pucch_config_common.nRB_CQI = radioResourceConfigCommon->pucch_ConfigCommon.nRB_CQI; + fp->pucch_config_common.nCS_AN = radioResourceConfigCommon->pucch_ConfigCommon.nCS_AN; + fp->pucch_config_common.n1PUCCH_AN = radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN; + + + + fp->pdsch_config_common.referenceSignalPower = radioResourceConfigCommon->pdsch_ConfigCommon.referenceSignalPower; + fp->pdsch_config_common.p_b = radioResourceConfigCommon->pdsch_ConfigCommon.p_b; + + + fp->pusch_config_common.n_SB = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.n_SB; + fp->pusch_config_common.hoppingMode = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode; + fp->pusch_config_common.pusch_HoppingOffset = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset; + fp->pusch_config_common.enable64QAM = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.enable64QAM; + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled; + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH; + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled; + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = dmrs1_tab_ue[radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift]; + + + init_ul_hopping(fp); + fp->soundingrs_ul_config_common.enabled_flag = 0; + + if (radioResourceConfigCommon->soundingRS_UL_ConfigCommon.present==SoundingRS_UL_ConfigCommon_PR_setup) { + fp->soundingrs_ul_config_common.enabled_flag = 1; + fp->soundingrs_ul_config_common.srs_BandwidthConfig = radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.srs_BandwidthConfig; + fp->soundingrs_ul_config_common.srs_SubframeConfig = radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig; + fp->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission = radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; + + if (radioResourceConfigCommon->soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts) + fp->soundingrs_ul_config_common.srs_MaxUpPts = 1; + else + fp->soundingrs_ul_config_common.srs_MaxUpPts = 0; + } + + + + fp->ul_power_control_config_common.p0_NominalPUSCH = radioResourceConfigCommon->uplinkPowerControlCommon.p0_NominalPUSCH; + fp->ul_power_control_config_common.alpha = radioResourceConfigCommon->uplinkPowerControlCommon.alpha; + fp->ul_power_control_config_common.p0_NominalPUCCH = radioResourceConfigCommon->uplinkPowerControlCommon.p0_NominalPUCCH; + fp->ul_power_control_config_common.deltaPreambleMsg3 = radioResourceConfigCommon->uplinkPowerControlCommon.deltaPreambleMsg3; + fp->ul_power_control_config_common.deltaF_PUCCH_Format1 = radioResourceConfigCommon->uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format1; + fp->ul_power_control_config_common.deltaF_PUCCH_Format1b = radioResourceConfigCommon->uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format1b; + fp->ul_power_control_config_common.deltaF_PUCCH_Format2 = radioResourceConfigCommon->uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2; + fp->ul_power_control_config_common.deltaF_PUCCH_Format2a = radioResourceConfigCommon->uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2a; + fp->ul_power_control_config_common.deltaF_PUCCH_Format2b = radioResourceConfigCommon->uplinkPowerControlCommon.deltaFList_PUCCH.deltaF_PUCCH_Format2b; + + fp->maxHARQ_Msg3Tx = radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx; + + // Now configure some of the Physical Channels + + // PUCCH + init_ncs_cell(fp,ue->ncs_cell); + + init_ul_hopping(fp); + + // PCH + init_ue_paging_info(ue,radioResourceConfigCommon->pcch_Config.defaultPagingCycle,radioResourceConfigCommon->pcch_Config.nB); + + // MBSFN + + if (mbsfn_SubframeConfigList != NULL) { + fp->num_MBSFN_config = mbsfn_SubframeConfigList->list.count; + + for (i=0; ilist.count; i++) { + fp->MBSFN_config[i].radioframeAllocationPeriod = mbsfn_SubframeConfigList->list.array[i]->radioframeAllocationPeriod; + fp->MBSFN_config[i].radioframeAllocationOffset = mbsfn_SubframeConfigList->list.array[i]->radioframeAllocationOffset; + + if (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.present == MBSFN_SubframeConfig__subframeAllocation_PR_oneFrame) { + fp->MBSFN_config[i].fourFrames_flag = 0; + fp->MBSFN_config[i].mbsfn_SubframeConfig = mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[0]; // 6-bit subframe configuration + LOG_I(PHY, "[CONFIG] MBSFN_SubframeConfig[%d] pattern is %d\n", i, + fp->MBSFN_config[i].mbsfn_SubframeConfig); + } else if (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.present == MBSFN_SubframeConfig__subframeAllocation_PR_fourFrames) { // 24-bit subframe configuration + fp->MBSFN_config[i].fourFrames_flag = 1; + fp->MBSFN_config[i].mbsfn_SubframeConfig = + mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[0]| + (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[1]<<8)| + (mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[2]<<16); + + LOG_I(PHY, "[CONFIG] MBSFN_SubframeConfig[%d] pattern is %d\n", i, + fp->MBSFN_config[i].mbsfn_SubframeConfig); + } + } + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_CONFIG_SIB2, VCD_FUNCTION_OUT); + +} + +void phy_config_sib13_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id,int mbsfn_Area_idx, + long mbsfn_AreaId_r9) +{ + + LTE_DL_FRAME_PARMS *fp = &PHY_vars_UE_g[Mod_id][CC_id]->frame_parms; + + + LOG_I(PHY,"[UE%d] Applying MBSFN_Area_id %ld for index %d\n",Mod_id,mbsfn_AreaId_r9,mbsfn_Area_idx); + + if (mbsfn_Area_idx == 0) { + fp->Nid_cell_mbsfn = (uint16_t)mbsfn_AreaId_r9; + LOG_N(PHY,"Fix me: only called when mbsfn_Area_idx == 0)\n"); + } + + lte_gold_mbsfn(fp,PHY_vars_UE_g[Mod_id][CC_id]->lte_gold_mbsfn_table,fp->Nid_cell_mbsfn); + +} + + +/* + * Configures UE MAC and PHY with radioResourceCommon received in mobilityControlInfo IE during Handover + */ +void phy_config_afterHO_ue(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_id, MobilityControlInfo_t *mobilityControlInfo, uint8_t ho_failed) +{ + + if(mobilityControlInfo!=NULL) { + RadioResourceConfigCommon_t *radioResourceConfigCommon = &mobilityControlInfo->radioResourceConfigCommon; + LOG_I(PHY,"radioResourceConfigCommon %p\n", radioResourceConfigCommon); + memcpy((void *)&PHY_vars_UE_g[Mod_id][CC_id]->frame_parms_before_ho, + (void *)&PHY_vars_UE_g[Mod_id][CC_id]->frame_parms, + sizeof(LTE_DL_FRAME_PARMS)); + PHY_vars_UE_g[Mod_id][CC_id]->ho_triggered = 1; + //PHY_vars_UE_g[UE_id]->UE_mode[0] = PRACH; + + LTE_DL_FRAME_PARMS *fp = &PHY_vars_UE_g[Mod_id][CC_id]->frame_parms; + // int N_ZC; + // uint8_t prach_fmt; + // int u; + + LOG_I(PHY,"[UE%d] Handover triggered: Applying radioResourceConfigCommon from eNB %d\n", + Mod_id,eNB_id); + + fp->prach_config_common.rootSequenceIndex =radioResourceConfigCommon->prach_Config.rootSequenceIndex; + fp->prach_config_common.prach_Config_enabled=1; + fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex =radioResourceConfigCommon->prach_Config.prach_ConfigInfo->prach_ConfigIndex; + fp->prach_config_common.prach_ConfigInfo.highSpeedFlag =radioResourceConfigCommon->prach_Config.prach_ConfigInfo->highSpeedFlag; + fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig =radioResourceConfigCommon->prach_Config.prach_ConfigInfo->zeroCorrelationZoneConfig; + fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset =radioResourceConfigCommon->prach_Config.prach_ConfigInfo->prach_FreqOffset; + + // prach_fmt = get_prach_fmt(radioResourceConfigCommon->prach_Config.prach_ConfigInfo->prach_ConfigIndex,fp->frame_type); + // N_ZC = (prach_fmt <4)?839:139; + // u = (prach_fmt < 4) ? prach_root_sequence_map0_3[fp->prach_config_common.rootSequenceIndex] : + // prach_root_sequence_map4[fp->prach_config_common.rootSequenceIndex]; + + //compute_prach_seq(u,N_ZC, PHY_vars_UE_g[Mod_id]->X_u); + compute_prach_seq(PHY_vars_UE_g[Mod_id][CC_id]->frame_parms.prach_config_common.rootSequenceIndex, + PHY_vars_UE_g[Mod_id][CC_id]->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex, + PHY_vars_UE_g[Mod_id][CC_id]->frame_parms.prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, + PHY_vars_UE_g[Mod_id][CC_id]->frame_parms.prach_config_common.prach_ConfigInfo.highSpeedFlag, + fp->frame_type, + PHY_vars_UE_g[Mod_id][CC_id]->X_u); + + + fp->pucch_config_common.deltaPUCCH_Shift = 1+radioResourceConfigCommon->pucch_ConfigCommon->deltaPUCCH_Shift; + fp->pucch_config_common.nRB_CQI = radioResourceConfigCommon->pucch_ConfigCommon->nRB_CQI; + fp->pucch_config_common.nCS_AN = radioResourceConfigCommon->pucch_ConfigCommon->nCS_AN; + fp->pucch_config_common.n1PUCCH_AN = radioResourceConfigCommon->pucch_ConfigCommon->n1PUCCH_AN; + fp->pdsch_config_common.referenceSignalPower = radioResourceConfigCommon->pdsch_ConfigCommon->referenceSignalPower; + fp->pdsch_config_common.p_b = radioResourceConfigCommon->pdsch_ConfigCommon->p_b; + + + fp->pusch_config_common.n_SB = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.n_SB; + fp->pusch_config_common.hoppingMode = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode; + fp->pusch_config_common.pusch_HoppingOffset = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset; + fp->pusch_config_common.enable64QAM = radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.enable64QAM; + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled; + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH; + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled; + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = radioResourceConfigCommon->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift; + + init_ul_hopping(fp); + fp->soundingrs_ul_config_common.enabled_flag = 0; + + if (radioResourceConfigCommon->soundingRS_UL_ConfigCommon->present==SoundingRS_UL_ConfigCommon_PR_setup) { + fp->soundingrs_ul_config_common.enabled_flag = 1; + fp->soundingrs_ul_config_common.srs_BandwidthConfig = radioResourceConfigCommon->soundingRS_UL_ConfigCommon->choice.setup.srs_BandwidthConfig; + fp->soundingrs_ul_config_common.srs_SubframeConfig = radioResourceConfigCommon->soundingRS_UL_ConfigCommon->choice.setup.srs_SubframeConfig; + fp->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission = radioResourceConfigCommon->soundingRS_UL_ConfigCommon->choice.setup.ackNackSRS_SimultaneousTransmission; + + if (radioResourceConfigCommon->soundingRS_UL_ConfigCommon->choice.setup.srs_MaxUpPts) + fp->soundingrs_ul_config_common.srs_MaxUpPts = 1; + else + fp->soundingrs_ul_config_common.srs_MaxUpPts = 0; + } + + fp->ul_power_control_config_common.p0_NominalPUSCH = radioResourceConfigCommon->uplinkPowerControlCommon->p0_NominalPUSCH; + fp->ul_power_control_config_common.alpha = radioResourceConfigCommon->uplinkPowerControlCommon->alpha; + fp->ul_power_control_config_common.p0_NominalPUCCH = radioResourceConfigCommon->uplinkPowerControlCommon->p0_NominalPUCCH; + fp->ul_power_control_config_common.deltaPreambleMsg3 = radioResourceConfigCommon->uplinkPowerControlCommon->deltaPreambleMsg3; + fp->ul_power_control_config_common.deltaF_PUCCH_Format1 = radioResourceConfigCommon->uplinkPowerControlCommon->deltaFList_PUCCH.deltaF_PUCCH_Format1; + fp->ul_power_control_config_common.deltaF_PUCCH_Format1b = radioResourceConfigCommon->uplinkPowerControlCommon->deltaFList_PUCCH.deltaF_PUCCH_Format1b; + fp->ul_power_control_config_common.deltaF_PUCCH_Format2 = radioResourceConfigCommon->uplinkPowerControlCommon->deltaFList_PUCCH.deltaF_PUCCH_Format2; + fp->ul_power_control_config_common.deltaF_PUCCH_Format2a = radioResourceConfigCommon->uplinkPowerControlCommon->deltaFList_PUCCH.deltaF_PUCCH_Format2a; + fp->ul_power_control_config_common.deltaF_PUCCH_Format2b = radioResourceConfigCommon->uplinkPowerControlCommon->deltaFList_PUCCH.deltaF_PUCCH_Format2b; + + fp->maxHARQ_Msg3Tx = radioResourceConfigCommon->rach_ConfigCommon->maxHARQ_Msg3Tx; + + // Now configure some of the Physical Channels + if (radioResourceConfigCommon->antennaInfoCommon) + fp->nb_antennas_tx = (1<antennaInfoCommon->antennaPortsCount); + else + fp->nb_antennas_tx = 1; + + //PHICH + if (radioResourceConfigCommon->antennaInfoCommon) { + fp->phich_config_common.phich_resource = radioResourceConfigCommon->phich_Config->phich_Resource; + fp->phich_config_common.phich_duration = radioResourceConfigCommon->phich_Config->phich_Duration; + } + + //Target CellId + fp->Nid_cell = mobilityControlInfo->targetPhysCellId; + fp->nushift = fp->Nid_cell%6; + + // PUCCH + init_ncs_cell(fp,PHY_vars_UE_g[Mod_id][CC_id]->ncs_cell); + + init_ul_hopping(fp); + + // RNTI + + + PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[0][eNB_id]->crnti = mobilityControlInfo->newUE_Identity.buf[0]|(mobilityControlInfo->newUE_Identity.buf[1]<<8); + PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[1][eNB_id]->crnti = mobilityControlInfo->newUE_Identity.buf[0]|(mobilityControlInfo->newUE_Identity.buf[1]<<8); + + LOG_I(PHY,"SET C-RNTI %x %x\n",PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[0][eNB_id]->crnti, + PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[1][eNB_id]->crnti); + } + + if(ho_failed) { + LOG_D(PHY,"[UE%d] Handover failed, triggering RACH procedure\n",Mod_id); + memcpy((void *)&PHY_vars_UE_g[Mod_id][CC_id]->frame_parms,(void *)&PHY_vars_UE_g[Mod_id][CC_id]->frame_parms_before_ho, sizeof(LTE_DL_FRAME_PARMS)); + PHY_vars_UE_g[Mod_id][CC_id]->UE_mode[eNB_id] = PRACH; + } +} + +void phy_config_meas_ue(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index,uint8_t n_adj_cells,unsigned int *adj_cell_id) +{ + + PHY_MEASUREMENTS *phy_meas = &PHY_vars_UE_g[Mod_id][CC_id]->measurements; + int i; + + LOG_I(PHY,"Configuring inter-cell measurements for %d cells, ids: \n",n_adj_cells); + + for (i=0; iframe_parms,PHY_vars_UE_g[Mod_id][CC_id]->lte_gold_table[i+1],adj_cell_id[i]); + } + + phy_meas->n_adj_cells = n_adj_cells; + memcpy((void*)phy_meas->adj_cell_id,(void *)adj_cell_id,n_adj_cells*sizeof(unsigned int)); + +} + +#if defined(Rel10) || defined(Rel14) +void phy_config_dedicated_scell_ue(uint8_t Mod_id, + uint8_t eNB_index, + SCellToAddMod_r10_t *sCellToAddMod_r10, + int CC_id) +{ + +} +#endif + + +void phy_config_harq_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id, + uint16_t max_harq_tx ) +{ + + PHY_VARS_UE *phy_vars_ue = PHY_vars_UE_g[Mod_id][CC_id]; + phy_vars_ue->ulsch[eNB_id]->Mlimit = max_harq_tx; +} + +extern uint16_t beta_cqi[16]; + +void phy_config_dedicated_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id, + struct PhysicalConfigDedicated *physicalConfigDedicated ) +{ + + static uint8_t first_dedicated_configuration = 0; + PHY_VARS_UE *phy_vars_ue = PHY_vars_UE_g[Mod_id][CC_id]; + + phy_vars_ue->total_TBS[eNB_id]=0; + phy_vars_ue->total_TBS_last[eNB_id]=0; + phy_vars_ue->bitrate[eNB_id]=0; + phy_vars_ue->total_received_bits[eNB_id]=0; + phy_vars_ue->dlsch_errors[eNB_id]=0; + phy_vars_ue->dlsch_errors_last[eNB_id]=0; + phy_vars_ue->dlsch_received[eNB_id]=0; + phy_vars_ue->dlsch_received_last[eNB_id]=0; + phy_vars_ue->dlsch_fer[eNB_id]=0; + + phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex = -1; + phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex = -1; + + if (physicalConfigDedicated) { + LOG_D(PHY,"[UE %d] Received physicalConfigDedicated from eNB %d\n",Mod_id, eNB_id); + LOG_D(PHY,"------------------------------------------------------------------------\n"); + + if (physicalConfigDedicated->pdsch_ConfigDedicated) { + phy_vars_ue->pdsch_config_dedicated[eNB_id].p_a=physicalConfigDedicated->pdsch_ConfigDedicated->p_a; + LOG_D(PHY,"pdsch_config_dedicated.p_a %d\n",phy_vars_ue->pdsch_config_dedicated[eNB_id].p_a); + LOG_D(PHY,"\n"); + } + + if (physicalConfigDedicated->pucch_ConfigDedicated) { + if (physicalConfigDedicated->pucch_ConfigDedicated->ackNackRepetition.present==PUCCH_ConfigDedicated__ackNackRepetition_PR_release) + phy_vars_ue->pucch_config_dedicated[eNB_id].ackNackRepetition=0; + else { + phy_vars_ue->pucch_config_dedicated[eNB_id].ackNackRepetition=1; + } + + if (physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode) + phy_vars_ue->pucch_config_dedicated[eNB_id].tdd_AckNackFeedbackMode = *physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode; + else + phy_vars_ue->pucch_config_dedicated[eNB_id].tdd_AckNackFeedbackMode = bundling; + + if ( phy_vars_ue->pucch_config_dedicated[eNB_id].tdd_AckNackFeedbackMode == multiplexing) + LOG_D(PHY,"pucch_config_dedicated.tdd_AckNackFeedbackMode = multiplexing\n"); + else + LOG_D(PHY,"pucch_config_dedicated.tdd_AckNackFeedbackMode = bundling\n"); + } + + if (physicalConfigDedicated->pusch_ConfigDedicated) { + phy_vars_ue->pusch_config_dedicated[eNB_id].betaOffset_ACK_Index = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_ACK_Index; + phy_vars_ue->pusch_config_dedicated[eNB_id].betaOffset_RI_Index = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index; + phy_vars_ue->pusch_config_dedicated[eNB_id].betaOffset_CQI_Index = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index; + + + LOG_D(PHY,"pusch_config_dedicated.betaOffset_ACK_Index %d\n",phy_vars_ue->pusch_config_dedicated[eNB_id].betaOffset_ACK_Index); + LOG_D(PHY,"pusch_config_dedicated.betaOffset_RI_Index %d\n",phy_vars_ue->pusch_config_dedicated[eNB_id].betaOffset_RI_Index); + LOG_D(PHY,"pusch_config_dedicated.betaOffset_CQI_Index %d => %d)\n",phy_vars_ue->pusch_config_dedicated[eNB_id].betaOffset_CQI_Index,beta_cqi[phy_vars_ue->pusch_config_dedicated[eNB_id].betaOffset_CQI_Index]); + LOG_D(PHY,"\n"); + + + } + + if (physicalConfigDedicated->uplinkPowerControlDedicated) { + + phy_vars_ue->ul_power_control_dedicated[eNB_id].p0_UE_PUSCH = physicalConfigDedicated->uplinkPowerControlDedicated->p0_UE_PUSCH; + phy_vars_ue->ul_power_control_dedicated[eNB_id].deltaMCS_Enabled= physicalConfigDedicated->uplinkPowerControlDedicated->deltaMCS_Enabled; + phy_vars_ue->ul_power_control_dedicated[eNB_id].accumulationEnabled= physicalConfigDedicated->uplinkPowerControlDedicated->accumulationEnabled; + phy_vars_ue->ul_power_control_dedicated[eNB_id].p0_UE_PUCCH= physicalConfigDedicated->uplinkPowerControlDedicated->p0_UE_PUCCH; + phy_vars_ue->ul_power_control_dedicated[eNB_id].pSRS_Offset= physicalConfigDedicated->uplinkPowerControlDedicated->pSRS_Offset; + phy_vars_ue->ul_power_control_dedicated[eNB_id].filterCoefficient= *physicalConfigDedicated->uplinkPowerControlDedicated->filterCoefficient; + LOG_D(PHY,"ul_power_control_dedicated.p0_UE_PUSCH %d\n",phy_vars_ue->ul_power_control_dedicated[eNB_id].p0_UE_PUSCH); + LOG_D(PHY,"ul_power_control_dedicated.deltaMCS_Enabled %d\n",phy_vars_ue->ul_power_control_dedicated[eNB_id].deltaMCS_Enabled); + LOG_D(PHY,"ul_power_control_dedicated.accumulationEnabled %d\n",phy_vars_ue->ul_power_control_dedicated[eNB_id].accumulationEnabled); + LOG_D(PHY,"ul_power_control_dedicated.p0_UE_PUCCH %d\n",phy_vars_ue->ul_power_control_dedicated[eNB_id].p0_UE_PUCCH); + LOG_D(PHY,"ul_power_control_dedicated.pSRS_Offset %d\n",phy_vars_ue->ul_power_control_dedicated[eNB_id].pSRS_Offset); + LOG_D(PHY,"ul_power_control_dedicated.filterCoefficient %d\n",phy_vars_ue->ul_power_control_dedicated[eNB_id].filterCoefficient); + LOG_D(PHY,"\n"); + } + + if (physicalConfigDedicated->antennaInfo) { + phy_vars_ue->transmission_mode[eNB_id] = 1+(physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode); + LOG_I(PHY,"Transmission Mode %d\n",phy_vars_ue->transmission_mode[eNB_id]); + switch(physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode) { + case AntennaInfoDedicated__transmissionMode_tm1: + phy_vars_ue->transmission_mode[eNB_id] = 1; + break; + case AntennaInfoDedicated__transmissionMode_tm2: + phy_vars_ue->transmission_mode[eNB_id] = 2; + break; + case AntennaInfoDedicated__transmissionMode_tm3: + phy_vars_ue->transmission_mode[eNB_id] = 3; + break; + case AntennaInfoDedicated__transmissionMode_tm4: + phy_vars_ue->transmission_mode[eNB_id] = 4; + break; + case AntennaInfoDedicated__transmissionMode_tm5: + phy_vars_ue->transmission_mode[eNB_id] = 5; + break; + case AntennaInfoDedicated__transmissionMode_tm6: + phy_vars_ue->transmission_mode[eNB_id] = 6; + break; + case AntennaInfoDedicated__transmissionMode_tm7: + lte_gold_ue_spec_port5(phy_vars_ue->lte_gold_uespec_port5_table, phy_vars_ue->frame_parms.Nid_cell, phy_vars_ue->pdcch_vars[0][eNB_id]->crnti); + phy_vars_ue->transmission_mode[eNB_id] = 7; + break; + default: + LOG_E(PHY,"Unknown transmission mode!\n"); + break; + } + } else { + LOG_D(PHY,"[UE %d] Received NULL physicalConfigDedicated->antennaInfo from eNB %d\n",Mod_id, eNB_id); + } + + if (physicalConfigDedicated->schedulingRequestConfig) { + if (physicalConfigDedicated->schedulingRequestConfig->present == SchedulingRequestConfig_PR_setup) { + phy_vars_ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex = physicalConfigDedicated->schedulingRequestConfig->choice.setup.sr_PUCCH_ResourceIndex; + phy_vars_ue->scheduling_request_config[eNB_id].sr_ConfigIndex=physicalConfigDedicated->schedulingRequestConfig->choice.setup.sr_ConfigIndex; + phy_vars_ue->scheduling_request_config[eNB_id].dsr_TransMax=physicalConfigDedicated->schedulingRequestConfig->choice.setup.dsr_TransMax; + + LOG_D(PHY,"scheduling_request_config.sr_PUCCH_ResourceIndex %d\n",phy_vars_ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex); + LOG_D(PHY,"scheduling_request_config.sr_ConfigIndex %d\n",phy_vars_ue->scheduling_request_config[eNB_id].sr_ConfigIndex); + LOG_D(PHY,"scheduling_request_config.dsr_TransMax %d\n",phy_vars_ue->scheduling_request_config[eNB_id].dsr_TransMax); + } + + LOG_D(PHY,"------------------------------------------------------------\n"); + + } + + if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated) { + + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srsConfigDedicatedSetup = 0; + if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) { + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srsConfigDedicatedSetup = 1; + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].duration = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.duration; + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].cyclicShift = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift; + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].freqDomainPosition = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition; + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srs_Bandwidth = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth; + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srs_ConfigIndex = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex; + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srs_HoppingBandwidth = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth; + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].transmissionComb = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb; + + + LOG_D(PHY,"soundingrs_ul_config_dedicated.srs_ConfigIndex %d\n",phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srs_ConfigIndex); + } + + LOG_D(PHY,"------------------------------------------------------------\n"); + + } + + + if (physicalConfigDedicated->cqi_ReportConfig) { + if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic) { + // configure PUSCH CQI reporting + phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic = *physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic; + if ((phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic != rm12) && + (phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic != rm30) && + (phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic != rm31)) + LOG_E(PHY,"Unsupported Aperiodic CQI Feedback Mode : %d\n",phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic); + } + if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic) { + if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_setup) { + // configure PUCCH CQI reporting + phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PUCCH_ResourceIndex = physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex; + phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex = physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.cqi_pmi_ConfigIndex; + if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.ri_ConfigIndex) + phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex = *physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.ri_ConfigIndex; + } + else if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_release) { + // handle release + phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex = -1; + phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex = -1; + } + } + } + +#ifdef CBA + + if (physicalConfigDedicated->pusch_CBAConfigDedicated_vlola) { + phy_vars_ue->pusch_ca_config_dedicated[eNB_id].betaOffset_CA_Index = (uint16_t) *physicalConfigDedicated->pusch_CBAConfigDedicated_vlola->betaOffset_CBA_Index; + phy_vars_ue->pusch_ca_config_dedicated[eNB_id].cShift = (uint16_t) *physicalConfigDedicated->pusch_CBAConfigDedicated_vlola->cShift_CBA; + LOG_D(PHY,"[UE %d ] physicalConfigDedicated pusch CBA config dedicated: beta offset %d cshift %d \n",Mod_id, + phy_vars_ue->pusch_ca_config_dedicated[eNB_id].betaOffset_CA_Index, + phy_vars_ue->pusch_ca_config_dedicated[eNB_id].cShift); + } + +#endif + } else { + LOG_D(PHY,"[PHY][UE %d] Received NULL radioResourceConfigDedicated from eNB %d\n",Mod_id,eNB_id); + return; + } + + // fill cqi parameters for periodic CQI reporting + get_cqipmiri_params(phy_vars_ue,eNB_id); + + // disable MIB SIB decoding once we are on connected mode + first_dedicated_configuration ++; + if(first_dedicated_configuration > 1) + { + LOG_I(PHY,"Disable SIB MIB decoding \n"); + phy_vars_ue->decode_SIB = 0; + phy_vars_ue->decode_MIB = 0; + } + //phy_vars_ue->pdcch_vars[1][eNB_id]->crnti = phy_vars_ue->pdcch_vars[0][eNB_id]->crnti; + if(phy_vars_ue->pdcch_vars[0][eNB_id]->crnti == 0x1234) + phy_vars_ue->pdcch_vars[0][eNB_id]->crnti = phy_vars_ue->pdcch_vars[1][eNB_id]->crnti; + else + phy_vars_ue->pdcch_vars[1][eNB_id]->crnti = phy_vars_ue->pdcch_vars[0][eNB_id]->crnti; + + LOG_I(PHY,"C-RNTI %x %x \n", phy_vars_ue->pdcch_vars[0][eNB_id]->crnti, + phy_vars_ue->pdcch_vars[1][eNB_id]->crnti); + + +} + +/*! \brief Helper function to allocate memory for DLSCH data structures. + * \param[out] pdsch Pointer to the LTE_UE_PDSCH structure to initialize. + * \param[in] frame_parms LTE_DL_FRAME_PARMS structure. + * \note This function is optimistic in that it expects malloc() to succeed. + */ +void phy_init_lte_ue__PDSCH( LTE_UE_PDSCH* const pdsch, const LTE_DL_FRAME_PARMS* const fp ) +{ + AssertFatal( pdsch, "pdsch==0" ); + + pdsch->pmi_ext = (uint8_t*)malloc16_clear( fp->N_RB_DL ); + pdsch->llr[0] = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); + pdsch->llr128 = (int16_t**)malloc16_clear( sizeof(int16_t*) ); + // FIXME! no further allocation for (int16_t*)pdsch->llr128 !!! expect SIGSEGV + // FK, 11-3-2015: this is only as a temporary pointer, no memory is stored there + + + pdsch->rxdataF_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->rxdataF_uespec_pilots = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->rxdataF_comp0 = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->rho = (int32_t**)malloc16_clear( fp->nb_antennas_rx*sizeof(int32_t*) ); + pdsch->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->dl_bf_ch_estimates = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->dl_bf_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + //pdsch->dl_ch_rho_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + //pdsch->dl_ch_rho2_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->dl_ch_mag0 = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->dl_ch_magb0 = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + + + // the allocated memory size is fixed: + AssertFatal( fp->nb_antennas_rx <= 2, "nb_antennas_rx > 2" ); + + for (int i=0; inb_antennas_rx; i++) { + pdsch->rho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->N_RB_DL*12*7*2) ); + + for (int j=0; j<4; j++) { //fp->nb_antennas_tx; j++) + const int idx = (j<<1)+i; + const size_t num = 7*2*fp->N_RB_DL*12; + pdsch->rxdataF_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + pdsch->rxdataF_uespec_pilots[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * fp->N_RB_DL*12); + pdsch->rxdataF_comp0[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + pdsch->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + pdsch->dl_bf_ch_estimates[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * fp->ofdm_symbol_size*7*2); + pdsch->dl_bf_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + //pdsch->dl_ch_rho_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + //pdsch->dl_ch_rho2_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + pdsch->dl_ch_mag0[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + pdsch->dl_ch_magb0[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + } + } +} + +int init_lte_ue_signal(PHY_VARS_UE *ue, + int nb_connected_eNB, + uint8_t abstraction_flag) +{ + + // create shortcuts + LTE_DL_FRAME_PARMS* const fp = &ue->frame_parms; + LTE_UE_COMMON* const common_vars = &ue->common_vars; + LTE_UE_PDSCH** const pdsch_vars_SI = ue->pdsch_vars_SI; + LTE_UE_PDSCH** const pdsch_vars_ra = ue->pdsch_vars_ra; + LTE_UE_PDSCH** const pdsch_vars_p = ue->pdsch_vars_p; + LTE_UE_PDSCH** const pdsch_vars_mch = ue->pdsch_vars_MCH; + LTE_UE_PDSCH* (*pdsch_vars_th)[][NUMBER_OF_CONNECTED_eNB_MAX+1] = &ue->pdsch_vars; + LTE_UE_PDCCH* (*pdcch_vars_th)[][NUMBER_OF_CONNECTED_eNB_MAX] = &ue->pdcch_vars; + LTE_UE_PBCH** const pbch_vars = ue->pbch_vars; + LTE_UE_PRACH** const prach_vars = ue->prach_vars; + + + + int i,j,k,l; + int eNB_id; + int th_id; + + LOG_D(PHY,"Initializing UE vars (abstraction %"PRIu8") for eNB TXant %"PRIu8", UE RXant %"PRIu8"\n",abstraction_flag,fp->nb_antennas_tx,fp->nb_antennas_rx); + LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_UE][MOD %02u][]\n", ue->Mod_id+NB_eNB_INST); + + + + init_frame_parms(&ue->frame_parms,1); + init_lte_top(&ue->frame_parms); + init_ul_hopping(&ue->frame_parms); + + + // many memory allocation sizes are hard coded + AssertFatal( fp->nb_antennas_rx <= 2, "hard coded allocation for ue_common_vars->dl_ch_estimates[eNB_id]" ); + AssertFatal( ue->n_connected_eNB <= NUMBER_OF_CONNECTED_eNB_MAX, "n_connected_eNB is too large" ); + // init phy_vars_ue + + for (i=0; i<4; i++) { + ue->rx_gain_max[i] = 135; + ue->rx_gain_med[i] = 128; + ue->rx_gain_byp[i] = 120; + } + + ue->n_connected_eNB = nb_connected_eNB; + + for(eNB_id = 0; eNB_id < ue->n_connected_eNB; eNB_id++) { + ue->total_TBS[eNB_id] = 0; + ue->total_TBS_last[eNB_id] = 0; + ue->bitrate[eNB_id] = 0; + ue->total_received_bits[eNB_id] = 0; + } + + for (i=0;i<10;i++) + ue->tx_power_dBm[i]=-127; + + + + // init TX buffers + + common_vars->txdata = (int32_t**)malloc16( fp->nb_antennas_tx*sizeof(int32_t*) ); + common_vars->txdataF = (int32_t **)malloc16( fp->nb_antennas_tx*sizeof(int32_t*) ); + + for (i=0; inb_antennas_tx; i++) { + + common_vars->txdata[i] = (int32_t*)malloc16_clear( fp->samples_per_tti*10*sizeof(int32_t) ); + common_vars->txdataF[i] = (int32_t *)malloc16_clear( fp->ofdm_symbol_size*fp->symbols_per_tti*10*sizeof(int32_t) ); + } + + // init RX buffers + + common_vars->rxdata = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); + common_vars->common_vars_rx_data_per_thread[0].rxdataF = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); + common_vars->common_vars_rx_data_per_thread[1].rxdataF = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); + + for (i=0; inb_antennas_rx; i++) { + common_vars->rxdata[i] = (int32_t*) malloc16_clear( (fp->samples_per_tti*10+2048)*sizeof(int32_t) ); + common_vars->common_vars_rx_data_per_thread[0].rxdataF[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->ofdm_symbol_size*14) ); + common_vars->common_vars_rx_data_per_thread[1].rxdataF[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->ofdm_symbol_size*14) ); + } + + + // Channel estimates + for (eNB_id=0; eNB_id<7; eNB_id++) { + for (th_id=0; th_idcommon_vars_rx_data_per_thread[th_id].dl_ch_estimates[eNB_id] = (int32_t**)malloc16_clear(8*sizeof(int32_t*)); + common_vars->common_vars_rx_data_per_thread[th_id].dl_ch_estimates_time[eNB_id] = (int32_t**)malloc16_clear(8*sizeof(int32_t*)); + } + + for (i=0; inb_antennas_rx; i++) + for (j=0; j<4; j++) { + int idx = (j<<1) + i; + for (th_id=0; th_idcommon_vars_rx_data_per_thread[th_id].dl_ch_estimates[eNB_id][idx] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->symbols_per_tti*(fp->ofdm_symbol_size+LTE_CE_FILTER_LENGTH) ); + common_vars->common_vars_rx_data_per_thread[th_id].dl_ch_estimates_time[eNB_id][idx] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2 ); + } + } + } + + // DLSCH + for (eNB_id=0; eNB_idn_connected_eNB; eNB_id++) { + for (th_id=0; th_idllr_shifts = (uint8_t*)malloc16_clear(7*2*fp->N_RB_DL*12); + (*pdsch_vars_th)[th_id][eNB_id]->llr_shifts_p = (*pdsch_vars_th)[0][eNB_id]->llr_shifts; + (*pdsch_vars_th)[th_id][eNB_id]->llr[1] = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); + (*pdsch_vars_th)[th_id][eNB_id]->llr128_2ndstream = (int16_t**)malloc16_clear( sizeof(int16_t*) ); + (*pdsch_vars_th)[th_id][eNB_id]->rho = (int32_t**)malloc16_clear( fp->nb_antennas_rx*sizeof(int32_t*) ); + } + + for (int i=0; inb_antennas_rx; i++){ + for (th_id=0; th_idrho[i] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); + } + + } + for (th_id=0; th_iddl_ch_rho2_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + } + + for (i=0; inb_antennas_rx; i++) + for (j=0; j<4; j++) { + const int idx = (j<<1)+i; + const size_t num = 7*2*fp->N_RB_DL*12+4; + for (th_id=0; th_iddl_ch_rho2_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + } + + } + + //const size_t num = 7*2*fp->N_RB_DL*12+4; + for (k=0;k<8;k++) { //harq_pid + for (l=0;l<8;l++) { //round + for (th_id=0; th_idrxdataF_comp1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_mag1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_magb1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + } + + + for (int i=0; inb_antennas_rx; i++) + for (int j=0; j<4; j++) { //frame_parms->nb_antennas_tx; j++) + const int idx = (j<<1)+i; + for (th_id=0; th_iddl_ch_rho_ext[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); + (*pdsch_vars_th)[th_id][eNB_id]->rxdataF_comp1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); + (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_mag1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); + (*pdsch_vars_th)[th_id][eNB_id]->dl_ch_magb1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) ); + } + + } + } + } + phy_init_lte_ue__PDSCH( pdsch_vars_SI[eNB_id], fp ); + phy_init_lte_ue__PDSCH( pdsch_vars_ra[eNB_id], fp ); + phy_init_lte_ue__PDSCH( pdsch_vars_p[eNB_id], fp ); + phy_init_lte_ue__PDSCH( pdsch_vars_mch[eNB_id], fp ); + + // 100 PRBs * 12 REs/PRB * 4 PDCCH SYMBOLS * 2 LLRs/RE + for (th_id=0; th_idllr = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); + (*pdcch_vars_th)[th_id][eNB_id]->llr16 = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); + (*pdcch_vars_th)[th_id][eNB_id]->wbar = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); + (*pdcch_vars_th)[th_id][eNB_id]->e_rx = (int8_t*)malloc16_clear( 4*2*100*12 ); + + (*pdcch_vars_th)[th_id][eNB_id]->rxdataF_comp = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + (*pdcch_vars_th)[th_id][eNB_id]->rho = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); + (*pdcch_vars_th)[th_id][eNB_id]->rxdataF_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + } + + for (i=0; inb_antennas_rx; i++) { + //ue_pdcch_vars[eNB_id]->rho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->N_RB_DL*12*7*2) ); + for (th_id=0; th_idrho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(100*12*4) ); + } + + for (j=0; j<4; j++) { //fp->nb_antennas_tx; j++) + int idx = (j<<1)+i; + // size_t num = 7*2*fp->N_RB_DL*12; + size_t num = 4*100*12; // 4 symbols, 100 PRBs, 12 REs per PRB + for (th_id=0; th_idrxdataF_comp[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + (*pdcch_vars_th)[th_id][eNB_id]->rxdataF_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + } + } + } + phy_init_lte_ue__PDSCH( pdsch_vars_SI[eNB_id], fp ); + phy_init_lte_ue__PDSCH( pdsch_vars_ra[eNB_id], fp ); + phy_init_lte_ue__PDSCH( pdsch_vars_p[eNB_id], fp ); + phy_init_lte_ue__PDSCH( pdsch_vars_mch[eNB_id], fp ); + + // 100 PRBs * 12 REs/PRB * 4 PDCCH SYMBOLS * 2 LLRs/RE + for (th_id=0; th_idllr = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); + (*pdcch_vars_th)[th_id][eNB_id]->llr16 = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); + (*pdcch_vars_th)[th_id][eNB_id]->wbar = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) ); + (*pdcch_vars_th)[th_id][eNB_id]->e_rx = (int8_t*)malloc16_clear( 4*2*100*12 ); + + (*pdcch_vars_th)[th_id][eNB_id]->rxdataF_comp = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + (*pdcch_vars_th)[th_id][eNB_id]->rho = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); + (*pdcch_vars_th)[th_id][eNB_id]->rxdataF_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + } + + for (i=0; inb_antennas_rx; i++) { + //ue_pdcch_vars[eNB_id]->rho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->N_RB_DL*12*7*2) ); + + for (th_id=0; th_idrho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(100*12*4) ); + } + + for (j=0; j<4; j++) { //fp->nb_antennas_tx; j++) + int idx = (j<<1)+i; + // size_t num = 7*2*fp->N_RB_DL*12; + size_t num = 4*100*12; // 4 symbols, 100 PRBs, 12 REs per PRB + for (th_id=0; th_idrxdataF_comp[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_rho_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + (*pdcch_vars_th)[th_id][eNB_id]->rxdataF_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + (*pdcch_vars_th)[th_id][eNB_id]->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + } + } + } + + // PBCH + pbch_vars[eNB_id]->rxdataF_ext = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); + pbch_vars[eNB_id]->rxdataF_comp = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pbch_vars[eNB_id]->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pbch_vars[eNB_id]->llr = (int8_t*)malloc16_clear( 1920 ); + prach_vars[eNB_id]->prachF = (int16_t*)malloc16_clear( sizeof(int)*(7*2*sizeof(int)*(fp->ofdm_symbol_size*12)) ); + prach_vars[eNB_id]->prach = (int16_t*)malloc16_clear( sizeof(int)*(7*2*sizeof(int)*(fp->ofdm_symbol_size*12)) ); + + for (i=0; inb_antennas_rx; i++) { + pbch_vars[eNB_id]->rxdataF_ext[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*6*12*4 ); + + for (j=0; j<4; j++) {//fp->nb_antennas_tx;j++) { + int idx = (j<<1)+i; + pbch_vars[eNB_id]->rxdataF_comp[idx] = (int32_t*)malloc16_clear( sizeof(int32_t)*6*12*4 ); + pbch_vars[eNB_id]->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t)*6*12*4 ); + } + } + + + pbch_vars[eNB_id]->decoded_output = (uint8_t*)malloc16_clear( 64 ); + } + + // initialization for the last instance of pdsch_vars (used for MU-MIMO) + for (th_id=0; th_idllr[1] = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); + } + + + ue->sinr_CQI_dB = (double*) malloc16_clear( fp->N_RB_DL*12*sizeof(double) ); + + ue->init_averaging = 1; + // default value until overwritten by RRCConnectionReconfiguration + if (fp->nb_antenna_ports_eNB==2) + ue->pdsch_config_dedicated->p_a = dBm3; + else + ue->pdsch_config_dedicated->p_a = dB0; + + // set channel estimation to do linear interpolation in time + ue->high_speed_flag = 1; + ue->ch_est_alpha = 24576; + + // enable MIB/SIB decoding by default + ue->decode_MIB = 1; + ue->decode_SIB = 1; + + init_prach_tables(839); + + + return 0; +} + +void init_lte_ue_transport(PHY_VARS_UE *ue,int abstraction_flag) { + + int i,j,k; + + for (i=0; idlsch[k][i][j] = new_ue_dlsch(1,NUMBER_OF_HARQ_PID_MAX,NSOFT,MAX_TURBO_ITERATIONS,ue->frame_parms.N_RB_DL, abstraction_flag))!=NULL,"Can't get ue dlsch structures\n"); + + LOG_D(PHY,"dlsch[%d][%d][%d] => %p\n",k,i,j,ue->dlsch[i][j]); + } + } + + AssertFatal((ue->ulsch[i] = new_ue_ulsch(ue->frame_parms.N_RB_UL, abstraction_flag))!=NULL,"Can't get ue ulsch structures\n"); + + ue->dlsch_SI[i] = new_ue_dlsch(1,1,NSOFT,MAX_TURBO_ITERATIONS,ue->frame_parms.N_RB_DL, abstraction_flag); + ue->dlsch_ra[i] = new_ue_dlsch(1,1,NSOFT,MAX_TURBO_ITERATIONS,ue->frame_parms.N_RB_DL, abstraction_flag); + + ue->transmission_mode[i] = ue->frame_parms.nb_antenna_ports_eNB==1 ? 1 : 2; + } + + ue->frame_parms.pucch_config_common.deltaPUCCH_Shift = 1; + + ue->dlsch_MCH[0] = new_ue_dlsch(1,NUMBER_OF_HARQ_PID_MAX,NSOFT,MAX_TURBO_ITERATIONS_MBSFN,ue->frame_parms.N_RB_DL,0); + +} diff --git a/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c b/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c index c7625ba083..c656b8272b 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c @@ -465,7 +465,7 @@ int lte_sync_time(int **rxdata, ///rx data in time domain *eNB_id = sync_source; - LOG_D(PHY,"[UE] lte_sync_time: Sync source = %d, Peak found at pos %d, val = %d (%d dB)\n",sync_source,peak_pos,peak_val,dB_fixed(peak_val)/2); + LOG_I(PHY,"[UE] lte_sync_time: Sync source = %d, Peak found at pos %d, val = %d (%d dB)\n",sync_source,peak_pos,peak_val,dB_fixed(peak_val)/2); #ifdef DEBUG_PHY diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 4754c0393e..5c57fa70d3 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -578,181 +578,6 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, } -void prach_procedures(PHY_VARS_eNB *eNB, -#ifdef Rel14 - int br_flag -#endif - ) { - uint16_t max_preamble[4],max_preamble_energy[4],max_preamble_delay[4]; - uint16_t i; - int frame,subframe; - -#ifdef Rel14 - if (br_flag==1) { - subframe = eNB->proc.subframe_prach_br; - frame = eNB->proc.frame_prach_br; - pthread_mutex_lock(&eNB->UL_INFO_mutex); - eNB->UL_INFO.rach_ind_br.rach_indication_body.number_of_preambles=0; - pthread_mutex_unlock(&eNB->UL_INFO_mutex); - } - else -#endif - { - pthread_mutex_lock(&eNB->UL_INFO_mutex); - eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles=0; - pthread_mutex_unlock(&eNB->UL_INFO_mutex); - subframe = eNB->proc.subframe_prach; - frame = eNB->proc.frame_prach; - } - RU_t *ru; - int aa=0; - int ru_aa; - - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,1); - - - - for (i=0;inum_RU;i++) { - ru=eNB->RU_list[i]; - for (ru_aa=0,aa=0;ru_aanb_rx;ru_aa++,aa++) { - eNB->prach_vars.rxsigF[0][aa] = eNB->RU_list[i]->prach_rxsigF[ru_aa]; -#ifdef Rel14 - int ce_level; - - if (br_flag==1) - for (ce_level=0;ce_level<4;ce_level++) eNB->prach_vars_br.rxsigF[ce_level][aa] = eNB->RU_list[i]->prach_rxsigF_br[ce_level][ru_aa]; -#endif - } - } - - rx_prach(eNB, - eNB->RU_list[0], - &max_preamble[0], - &max_preamble_energy[0], - &max_preamble_delay[0], - frame, - 0 -#ifdef Rel14 - ,br_flag -#endif - ); - - #ifdef DEBUG_PHY_PROC - LOG_D(PHY,"[RAPROC] Frame %d, subframe %d : Most likely preamble %d, energy %d dB delay %d (prach_energy counter %d)\n", - frame,subframe, - max_preamble[0], - max_preamble_energy[0]/10, - max_preamble_delay[0], - eNB->prach_energy_counter); - #endif - -#ifdef Rel14 - if (br_flag==1) { - - int prach_mask; - - prach_mask = is_prach_subframe(&eNB->frame_parms,eNB->proc.frame_prach_br,eNB->proc.subframe_prach_br); - - eNB->UL_INFO.rach_ind_br.rach_indication_body.preamble_list = eNB->preamble_list_br; - int ind=0; - int ce_level=0; - /* Save for later, it doesn't work - for (int ind=0,ce_level=0;ce_level<4;ce_level++) { - - if ((eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[ce_level]==1)&& - (prach_mask&(1<<(1+ce_level)) > 0) && // prach is active and CE level has finished its repetitions - (eNB->prach_vars_br.repetition_number[ce_level]== - eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[ce_level])) { - */ - if (eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0]==1){ - if ((eNB->prach_energy_counter == 100) && - (max_preamble_energy[0] > eNB->measurements.prach_I0 + 100)) { - eNB->UL_INFO.rach_ind_br.rach_indication_body.number_of_preambles++; - - eNB->preamble_list_br[ind].preamble_rel8.timing_advance = max_preamble_delay[ind];// - eNB->preamble_list_br[ind].preamble_rel8.preamble = max_preamble[ind]; - // note: fid is implicitly 0 here, this is the rule for eMTC RA-RNTI from 36.321, Section 5.1.4 - eNB->preamble_list_br[ind].preamble_rel8.rnti = 1+subframe+(eNB->prach_vars_br.first_frame[ce_level]%40); - eNB->preamble_list_br[ind].instance_length = 0; //don't know exactly what this is - eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type = 1+ce_level; // CE Level - LOG_D(PHY,"Filling NFAPI indication for RACH %d CELevel %d (mask %x) : TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", - ind, - ce_level, - prach_mask, - eNB->preamble_list_br[ind].preamble_rel8.timing_advance, - eNB->preamble_list_br[ind].preamble_rel8.preamble, - eNB->preamble_list_br[ind].preamble_rel8.rnti, - eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type); - } - /* - ind++; - } - } */// ce_level - } - } - else -#endif - - { - if ((eNB->prach_energy_counter == 100) && - (max_preamble_energy[0] > eNB->measurements.prach_I0+100)) { - - LOG_I(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", - eNB->Mod_id, - eNB->CC_id, - frame, - subframe, - max_preamble[0], - max_preamble_energy[0]/10, - max_preamble_energy[0]%10, - max_preamble_delay[0]); - - T(T_ENB_PHY_INITIATE_RA_PROCEDURE, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), - T_INT(max_preamble[0]), T_INT(max_preamble_energy[0]), T_INT(max_preamble_delay[0])); - - pthread_mutex_lock(&eNB->UL_INFO_mutex); - - eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles = 1; - eNB->UL_INFO.rach_ind.rach_indication_body.preamble_list = &eNB->preamble_list[0]; - eNB->UL_INFO.rach_ind.rach_indication_body.tl.tag = NFAPI_RACH_INDICATION_BODY_TAG; - eNB->UL_INFO.rach_ind.header.message_id = NFAPI_RACH_INDICATION; - eNB->UL_INFO.rach_ind.sfn_sf = frame<<4 | subframe; - - eNB->preamble_list[0].preamble_rel8.tl.tag = NFAPI_PREAMBLE_REL8_TAG; - eNB->preamble_list[0].preamble_rel8.timing_advance = max_preamble_delay[0]; - eNB->preamble_list[0].preamble_rel8.preamble = max_preamble[0]; - eNB->preamble_list[0].preamble_rel8.rnti = 1+subframe; // note: fid is implicitly 0 here - eNB->preamble_list[0].preamble_rel13.rach_resource_type = 0; - eNB->preamble_list[0].instance_length = 0; //don't know exactly what this is - - if (nfapi_mode == 1) { // If NFAPI PNF then we need to send the message to the VNF - - LOG_D(PHY,"Filling NFAPI indication for RACH : SFN_SF:%d TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", - NFAPI_SFNSF2DEC(eNB->UL_INFO.rach_ind.sfn_sf), - eNB->preamble_list[0].preamble_rel8.timing_advance, - eNB->preamble_list[0].preamble_rel8.preamble, - eNB->preamble_list[0].preamble_rel8.rnti, - eNB->preamble_list[0].preamble_rel13.rach_resource_type); - - oai_nfapi_rach_ind(&eNB->UL_INFO.rach_ind); - - eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles = 0; - } - - pthread_mutex_unlock(&eNB->UL_INFO_mutex); - - } // max_preamble_energy > prach_I0 + 100 - else { - eNB->measurements.prach_I0 = ((eNB->measurements.prach_I0*900)>>10) + ((max_preamble_energy[0]*124)>>10); - if (frame==0) LOG_I(PHY,"prach_I0 = %d.%d dB\n",eNB->measurements.prach_I0/10,eNB->measurements.prach_I0%10); - if (eNB->prach_energy_counter < 100) eNB->prach_energy_counter++; - } - } // else br_flag - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0); -} - void srs_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) { LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index c7585521f1..b63806bacd 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -102,138 +102,6 @@ static int enb_check_band_frequencies(char* lib_config_file_name_pP, return errors; } - -/* --------------------------------------------------------*/ -/* from here function to use configuration module */ -void RCconfig_RU(void) { - - int j = 0; - int i = 0; - - - paramdef_t RUParams[] = RUPARAMS_DESC; - paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0}; - - - config_getlist( &RUParamList,RUParams,sizeof(RUParams)/sizeof(paramdef_t), NULL); - - - if ( RUParamList.numelt > 0) { - - RC.ru = (RU_t**)malloc(RC.nb_RU*sizeof(RU_t*)); - - - - - RC.ru_mask=(1<idx = j; - - printf("Creating RC.ru[%d]:%p\n", j, RC.ru[j]); - - RC.ru[j]->if_timing = synch_to_ext_device; - if (RC.nb_L1_inst >0) - RC.ru[j]->num_eNB = RUParamList.paramarray[j][RU_ENB_LIST_IDX].numelt; - else - RC.ru[j]->num_eNB = 0; - for (i=0;inum_eNB;i++) RC.ru[j]->eNB_list[i] = RC.eNB[RUParamList.paramarray[j][RU_ENB_LIST_IDX].iptr[i]][0]; - - - if (strcmp(*(RUParamList.paramarray[j][RU_LOCAL_RF_IDX].strptr), "yes") == 0) { - if ( !(config_isparamset(RUParamList.paramarray[j],RU_LOCAL_IF_NAME_IDX)) ) { - RC.ru[j]->if_south = LOCAL_RF; - RC.ru[j]->function = eNodeB_3GPP; - printf("Setting function for RU %d to eNodeB_3GPP\n",j); - } - else { - RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); - RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); - RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); - RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); - RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); - RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); - RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); - - if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) { - RC.ru[j]->if_south = LOCAL_RF; - RC.ru[j]->function = NGFI_RRU_IF5; - RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE; - printf("Setting function for RU %d to NGFI_RRU_IF5 (udp)\n",j); - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) { - RC.ru[j]->if_south = LOCAL_RF; - RC.ru[j]->function = NGFI_RRU_IF5; - RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE; - printf("Setting function for RU %d to NGFI_RRU_IF5 (raw)\n",j); - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) { - RC.ru[j]->if_south = LOCAL_RF; - RC.ru[j]->function = NGFI_RRU_IF4p5; - RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; - printf("Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n",j); - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) { - RC.ru[j]->if_south = LOCAL_RF; - RC.ru[j]->function = NGFI_RRU_IF4p5; - RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; - printf("Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n",j); - } - } - RC.ru[j]->max_pdschReferenceSignalPower = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);; - RC.ru[j]->max_rxgain = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr); - RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt; - for (i=0;inum_bands;i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i]; - } //strcmp(local_rf, "yes") == 0 - else { - printf("RU %d: Transport %s\n",j,*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr)); - - RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); - RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); - RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); - RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); - RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); - RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); - RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); - if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) { - RC.ru[j]->if_south = REMOTE_IF5; - RC.ru[j]->function = NGFI_RAU_IF5; - RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE; - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) { - RC.ru[j]->if_south = REMOTE_IF5; - RC.ru[j]->function = NGFI_RAU_IF5; - RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE; - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) { - RC.ru[j]->if_south = REMOTE_IF4p5; - RC.ru[j]->function = NGFI_RAU_IF4p5; - RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) { - RC.ru[j]->if_south = REMOTE_IF4p5; - RC.ru[j]->function = NGFI_RAU_IF4p5; - RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if5_mobipass") == 0) { - RC.ru[j]->if_south = REMOTE_IF5; - RC.ru[j]->function = NGFI_RAU_IF5; - RC.ru[j]->if_timing = synch_to_other; - RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF5_MOBIPASS; - } - RC.ru[j]->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); - RC.ru[j]->att_rx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); - } /* strcmp(local_rf, "yes") != 0 */ - - RC.ru[j]->nb_tx = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr); - RC.ru[j]->nb_rx = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr); - - }// j=0..num_rus - } else { - RC.nb_RU = 0; - } // setting != NULL - - return; - -} - void RCconfig_L1(void) { int i,j; paramdef_t L1_Params[] = L1PARAMS_DESC; diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index f0d6319e43..d5a09bef85 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -61,45 +61,9 @@ extern RAN_CONTEXT_t RC; extern int l2_init_eNB(void); extern void mac_top_init_eNB(void); extern void mac_init_cell_params(int Mod_idP,int CC_idP); -extern void phy_reset_ue(module_id_t Mod_id,uint8_t CC_id,uint8_t eNB_index); extern uint8_t nfapi_mode; -/* sec 5.9, 36.321: MAC Reset Procedure */ -void ue_mac_reset(module_id_t module_idP, uint8_t eNB_index) -{ - - //Resetting Bj - UE_mac_inst[module_idP].scheduling_info.Bj[0] = 0; - UE_mac_inst[module_idP].scheduling_info.Bj[1] = 0; - UE_mac_inst[module_idP].scheduling_info.Bj[2] = 0; - - //Stopping all timers - - //timeAlignmentTimer expires - - // PHY changes for UE MAC reset - phy_reset_ue(module_idP, 0, eNB_index); - - // notify RRC to relase PUCCH/SRS - // cancel all pending SRs - UE_mac_inst[module_idP].scheduling_info.SR_pending = 0; - UE_mac_inst[module_idP].scheduling_info.SR_COUNTER = 0; - - //Set BSR Trigger Bmp and remove timer flags - UE_mac_inst[module_idP].BSR_reporting_active = BSR_TRIGGER_NONE; - - // stop ongoing RACH procedure - - // discard explicitly signaled ra_PreambleIndex and ra_RACH_MaskIndex, if any - UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = 0; // check! - UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0; - - - ue_init_mac(module_idP); //This will hopefully do the rest of the MAC reset procedure - -} - int32_t **rxdata; int32_t **txdata; @@ -962,487 +926,3 @@ rrc_mac_config_req_eNB(module_id_t Mod_idP, return(0); } - - -int -rrc_mac_config_req_ue(module_id_t Mod_idP, - int CC_idP, - uint8_t eNB_index, - RadioResourceConfigCommonSIB_t * - radioResourceConfigCommon, - struct PhysicalConfigDedicated - *physicalConfigDedicated, -#if defined(Rel10) || defined(Rel14) - SCellToAddMod_r10_t * sCellToAddMod_r10, - //struct PhysicalConfigDedicatedSCell_r10 *physicalConfigDedicatedSCell_r10, -#endif - MeasObjectToAddMod_t ** measObj, - MAC_MainConfig_t * mac_MainConfig, - long logicalChannelIdentity, - LogicalChannelConfig_t * logicalChannelConfig, - MeasGapConfig_t * measGapConfig, - TDD_Config_t * tdd_Config, - MobilityControlInfo_t * mobilityControlInfo, - uint8_t * SIwindowsize, - uint16_t * SIperiod, - ARFCN_ValueEUTRA_t * ul_CarrierFreq, - long *ul_Bandwidth, - AdditionalSpectrumEmission_t * - additionalSpectrumEmission, - struct MBSFN_SubframeConfigList - *mbsfn_SubframeConfigList -#if defined(Rel10) || defined(Rel14) - , uint8_t MBMS_Flag, - MBSFN_AreaInfoList_r9_t * mbsfn_AreaInfoList, - PMCH_InfoList_r9_t * pmch_InfoList -#endif -#ifdef CBA - , uint8_t num_active_cba_groups, uint16_t cba_rnti -#endif - ) -{ - - int i; - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN); - - LOG_I(MAC, "[CONFIG][UE %d] Configuring MAC/PHY from eNB %d\n", - Mod_idP, eNB_index); - - if (tdd_Config != NULL) { - UE_mac_inst[Mod_idP].tdd_Config = tdd_Config; - } - - - if (tdd_Config && SIwindowsize && SIperiod) { - phy_config_sib1_ue(Mod_idP, 0, eNB_index, tdd_Config, - *SIwindowsize, *SIperiod); - } - - if (radioResourceConfigCommon != NULL) { - UE_mac_inst[Mod_idP].radioResourceConfigCommon = - radioResourceConfigCommon; - phy_config_sib2_ue(Mod_idP, 0, eNB_index, - radioResourceConfigCommon, ul_CarrierFreq, - ul_Bandwidth, additionalSpectrumEmission, - mbsfn_SubframeConfigList); - } - // SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup - if (logicalChannelConfig != NULL) { - LOG_I(MAC, - "[CONFIG][UE %d] Applying RRC logicalChannelConfig from eNB%d\n", - Mod_idP, eNB_index); - UE_mac_inst[Mod_idP].logicalChannelConfig[logicalChannelIdentity] = - logicalChannelConfig; - UE_mac_inst[Mod_idP].scheduling_info.Bj[logicalChannelIdentity] = 0; // initilize the bucket for this lcid - - AssertFatal(logicalChannelConfig->ul_SpecificParameters != NULL, - "[UE %d] LCID %ld NULL ul_SpecificParameters\n", - Mod_idP, logicalChannelIdentity); - UE_mac_inst[Mod_idP].scheduling_info.bucket_size[logicalChannelIdentity] = logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate * logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration; // set the max bucket size - if (logicalChannelConfig->ul_SpecificParameters-> - logicalChannelGroup != NULL) { - UE_mac_inst[Mod_idP].scheduling_info. - LCGID[logicalChannelIdentity] = - *logicalChannelConfig->ul_SpecificParameters-> - logicalChannelGroup; - LOG_D(MAC, - "[CONFIG][UE %d] LCID %ld is attached to the LCGID %ld\n", - Mod_idP, logicalChannelIdentity, - *logicalChannelConfig-> - ul_SpecificParameters->logicalChannelGroup); - } else { - UE_mac_inst[Mod_idP].scheduling_info. - LCGID[logicalChannelIdentity] = MAX_NUM_LCGID; - } - UE_mac_inst[Mod_idP]. - scheduling_info.LCID_buffer_remain[logicalChannelIdentity] = 0; - } - - if (mac_MainConfig != NULL) { - LOG_I(MAC, - "[CONFIG][UE%d] Applying RRC macMainConfig from eNB%d\n", - Mod_idP, eNB_index); - UE_mac_inst[Mod_idP].macConfig = mac_MainConfig; - UE_mac_inst[Mod_idP].measGapConfig = measGapConfig; - - if (mac_MainConfig->ul_SCH_Config) { - - if (mac_MainConfig->ul_SCH_Config->periodicBSR_Timer) { - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer = - (uint16_t) * - mac_MainConfig->ul_SCH_Config->periodicBSR_Timer; - } else { - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer = -#ifndef Rel14 - (uint16_t) - MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity -#else - (uint16_t) PeriodicBSR_Timer_r12_infinity; -#endif - ; - } - - if (mac_MainConfig->ul_SCH_Config->maxHARQ_Tx) { - UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx = - (uint16_t) * mac_MainConfig->ul_SCH_Config->maxHARQ_Tx; - } else { - UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx = - (uint16_t) - MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; - } - phy_config_harq_ue(Mod_idP, 0, eNB_index, - UE_mac_inst[Mod_idP]. - scheduling_info.maxHARQ_Tx); - - if (mac_MainConfig->ul_SCH_Config->retxBSR_Timer) { - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = - (uint16_t) mac_MainConfig->ul_SCH_Config-> - retxBSR_Timer; - } else { -#ifndef Rel14 - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = - (uint16_t) - MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf2560; -#else - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = - (uint16_t) RetxBSR_Timer_r12_sf2560; -#endif - } - } -#if defined(Rel10) || defined(Rel14) - - if (mac_MainConfig->ext1 - && mac_MainConfig->ext1->sr_ProhibitTimer_r9) { - UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = - (uint16_t) * mac_MainConfig->ext1->sr_ProhibitTimer_r9; - } else { - UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = 0; - } - - if (mac_MainConfig->ext2 - && mac_MainConfig->ext2->mac_MainConfig_v1020) { - if (mac_MainConfig->ext2-> - mac_MainConfig_v1020->extendedBSR_Sizes_r10) { - UE_mac_inst[Mod_idP].scheduling_info. - extendedBSR_Sizes_r10 = - (uint16_t) * - mac_MainConfig->ext2-> - mac_MainConfig_v1020->extendedBSR_Sizes_r10; - } else { - UE_mac_inst[Mod_idP].scheduling_info. - extendedBSR_Sizes_r10 = (uint16_t) 0; - } - if (mac_MainConfig->ext2->mac_MainConfig_v1020-> - extendedPHR_r10) { - UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = - (uint16_t) * - mac_MainConfig->ext2->mac_MainConfig_v1020-> - extendedPHR_r10; - } else { - UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = - (uint16_t) 0; - } - } else { - UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = - (uint16_t) 0; - UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = - (uint16_t) 0; - } -#endif - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = - MAC_UE_BSR_TIMER_NOT_RUNNING; - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = - MAC_UE_BSR_TIMER_NOT_RUNNING; - - UE_mac_inst[Mod_idP].BSR_reporting_active = BSR_TRIGGER_NONE; - - LOG_D(MAC, "[UE %d]: periodic BSR %d (SF), retx BSR %d (SF)\n", - Mod_idP, - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF, - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF); - - UE_mac_inst[Mod_idP].scheduling_info.drx_config = - mac_MainConfig->drx_Config; - UE_mac_inst[Mod_idP].scheduling_info.phr_config = - mac_MainConfig->phr_Config; - - if (mac_MainConfig->phr_Config) { - UE_mac_inst[Mod_idP].PHR_state = - mac_MainConfig->phr_Config->present; - UE_mac_inst[Mod_idP].PHR_reconfigured = 1; - UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer = - mac_MainConfig->phr_Config->choice.setup.periodicPHR_Timer; - UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer = - mac_MainConfig->phr_Config->choice.setup.prohibitPHR_Timer; - UE_mac_inst[Mod_idP].scheduling_info.PathlossChange = - mac_MainConfig->phr_Config->choice.setup.dl_PathlossChange; - } else { - UE_mac_inst[Mod_idP].PHR_reconfigured = 0; - UE_mac_inst[Mod_idP].PHR_state = - MAC_MainConfig__phr_Config_PR_setup; - UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer = - MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20; - UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer = - MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20; - UE_mac_inst[Mod_idP].scheduling_info.PathlossChange = - MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1; - } - - UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF = - get_sf_perioidicPHR_Timer(UE_mac_inst[Mod_idP]. - scheduling_info.periodicPHR_Timer); - UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF = - get_sf_prohibitPHR_Timer(UE_mac_inst[Mod_idP]. - scheduling_info.prohibitPHR_Timer); - UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db = - get_db_dl_PathlossChange(UE_mac_inst[Mod_idP]. - scheduling_info.PathlossChange); - UE_mac_inst[Mod_idP].PHR_reporting_active = 0; - LOG_D(MAC, - "[UE %d] config PHR (%d): periodic %d (SF) prohibit %d (SF) pathlosschange %d (db) \n", - Mod_idP, - (mac_MainConfig->phr_Config) ? mac_MainConfig-> - phr_Config->present : -1, - UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF, - UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF, - UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db); - } - - - if (physicalConfigDedicated != NULL) { - phy_config_dedicated_ue(Mod_idP, 0, eNB_index, - physicalConfigDedicated); - UE_mac_inst[Mod_idP].physicalConfigDedicated = physicalConfigDedicated; // for SR proc - } -#if defined(Rel10) || defined(Rel14) - - if (sCellToAddMod_r10 != NULL) { - - - phy_config_dedicated_scell_ue(Mod_idP, eNB_index, - sCellToAddMod_r10, 1); - UE_mac_inst[Mod_idP].physicalConfigDedicatedSCell_r10 = sCellToAddMod_r10->radioResourceConfigDedicatedSCell_r10->physicalConfigDedicatedSCell_r10; // using SCell index 0 - } -#endif - - if (measObj != NULL) { - if (measObj[0] != NULL) { - UE_mac_inst[Mod_idP].n_adj_cells = - measObj[0]->measObject.choice. - measObjectEUTRA.cellsToAddModList->list.count; - LOG_I(MAC, "Number of adjacent cells %d\n", - UE_mac_inst[Mod_idP].n_adj_cells); - - for (i = 0; i < UE_mac_inst[Mod_idP].n_adj_cells; i++) { - UE_mac_inst[Mod_idP].adj_cell_id[i] = - measObj[0]->measObject.choice. - measObjectEUTRA.cellsToAddModList->list.array[i]-> - physCellId; - LOG_I(MAC, "Cell %d : Nid_cell %d\n", i, - UE_mac_inst[Mod_idP].adj_cell_id[i]); - } - - phy_config_meas_ue(Mod_idP, 0, eNB_index, - UE_mac_inst[Mod_idP].n_adj_cells, - UE_mac_inst[Mod_idP].adj_cell_id); - } - } - - - if (mobilityControlInfo != NULL) { - - LOG_D(MAC, "[UE%d] MAC Reset procedure triggered by RRC eNB %d \n", - Mod_idP, eNB_index); - ue_mac_reset(Mod_idP, eNB_index); - - if (mobilityControlInfo->radioResourceConfigCommon. - rach_ConfigCommon) { - memcpy((void *) - &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> - rach_ConfigCommon, - (void *) mobilityControlInfo-> - radioResourceConfigCommon.rach_ConfigCommon, - sizeof(RACH_ConfigCommon_t)); - } - - memcpy((void *) &UE_mac_inst[Mod_idP]. - radioResourceConfigCommon->prach_Config.prach_ConfigInfo, - (void *) mobilityControlInfo-> - radioResourceConfigCommon.prach_Config.prach_ConfigInfo, - sizeof(PRACH_ConfigInfo_t)); - UE_mac_inst[Mod_idP].radioResourceConfigCommon-> - prach_Config.rootSequenceIndex = - mobilityControlInfo->radioResourceConfigCommon. - prach_Config.rootSequenceIndex; - - if (mobilityControlInfo->radioResourceConfigCommon. - pdsch_ConfigCommon) { - memcpy((void *) - &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> - pdsch_ConfigCommon, - (void *) mobilityControlInfo-> - radioResourceConfigCommon.pdsch_ConfigCommon, - sizeof(PDSCH_ConfigCommon_t)); - } - // not a pointer: mobilityControlInfo->radioResourceConfigCommon.pusch_ConfigCommon - memcpy((void *) &UE_mac_inst[Mod_idP]. - radioResourceConfigCommon->pusch_ConfigCommon, - (void *) &mobilityControlInfo-> - radioResourceConfigCommon.pusch_ConfigCommon, - sizeof(PUSCH_ConfigCommon_t)); - - if (mobilityControlInfo->radioResourceConfigCommon.phich_Config) { - /* memcpy((void *)&UE_mac_inst[Mod_idP].radioResourceConfigCommon->phich_Config, - (void *)mobilityControlInfo->radioResourceConfigCommon.phich_Config, - sizeof(PHICH_Config_t)); */ - } - - if (mobilityControlInfo->radioResourceConfigCommon. - pucch_ConfigCommon) { - memcpy((void *) - &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> - pucch_ConfigCommon, - (void *) mobilityControlInfo-> - radioResourceConfigCommon.pucch_ConfigCommon, - sizeof(PUCCH_ConfigCommon_t)); - } - - if (mobilityControlInfo-> - radioResourceConfigCommon.soundingRS_UL_ConfigCommon) { - memcpy((void *) - &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> - soundingRS_UL_ConfigCommon, - (void *) mobilityControlInfo-> - radioResourceConfigCommon.soundingRS_UL_ConfigCommon, - sizeof(SoundingRS_UL_ConfigCommon_t)); - } - - if (mobilityControlInfo-> - radioResourceConfigCommon.uplinkPowerControlCommon) { - memcpy((void *) - &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> - uplinkPowerControlCommon, - (void *) mobilityControlInfo-> - radioResourceConfigCommon.uplinkPowerControlCommon, - sizeof(UplinkPowerControlCommon_t)); - } - //configure antennaInfoCommon somewhere here.. - if (mobilityControlInfo->radioResourceConfigCommon.p_Max) { - //to be configured - } - - if (mobilityControlInfo->radioResourceConfigCommon.tdd_Config) { - UE_mac_inst[Mod_idP].tdd_Config = - mobilityControlInfo->radioResourceConfigCommon.tdd_Config; - } - - if (mobilityControlInfo-> - radioResourceConfigCommon.ul_CyclicPrefixLength) { - memcpy((void *) - &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> - ul_CyclicPrefixLength, - (void *) mobilityControlInfo-> - radioResourceConfigCommon.ul_CyclicPrefixLength, - sizeof(UL_CyclicPrefixLength_t)); - } - // store the previous rnti in case of failure, and set thenew rnti - UE_mac_inst[Mod_idP].crnti_before_ho = UE_mac_inst[Mod_idP].crnti; - UE_mac_inst[Mod_idP].crnti = - ((mobilityControlInfo-> - newUE_Identity.buf[0]) | (mobilityControlInfo-> - newUE_Identity.buf[1] << 8)); - LOG_I(MAC, "[UE %d] Received new identity %x from %d\n", Mod_idP, - UE_mac_inst[Mod_idP].crnti, eNB_index); - UE_mac_inst[Mod_idP].rach_ConfigDedicated = - malloc(sizeof(*mobilityControlInfo->rach_ConfigDedicated)); - - if (mobilityControlInfo->rach_ConfigDedicated) { - memcpy((void *) UE_mac_inst[Mod_idP].rach_ConfigDedicated, - (void *) mobilityControlInfo->rach_ConfigDedicated, - sizeof(*mobilityControlInfo->rach_ConfigDedicated)); - } - - phy_config_afterHO_ue(Mod_idP, 0, eNB_index, mobilityControlInfo, - 0); - } - - - if (mbsfn_SubframeConfigList != NULL) { - LOG_I(MAC, - "[UE %d][CONFIG] Received %d subframe allocation pattern for MBSFN\n", - Mod_idP, mbsfn_SubframeConfigList->list.count); - UE_mac_inst[Mod_idP].num_sf_allocation_pattern = - mbsfn_SubframeConfigList->list.count; - - for (i = 0; i < mbsfn_SubframeConfigList->list.count; i++) { - LOG_I(MAC, - "[UE %d] Configuring MBSFN_SubframeConfig %d from received SIB2 \n", - Mod_idP, i); - UE_mac_inst[Mod_idP].mbsfn_SubframeConfig[i] = - mbsfn_SubframeConfigList->list.array[i]; - // LOG_I("[UE %d] MBSFN_SubframeConfig[%d] pattern is %ld\n", Mod_idP, - // UE_mac_inst[Mod_idP].mbsfn_SubframeConfig[i]->subframeAllocation.choice.oneFrame.buf[0]); - } - } -#if defined(Rel10) || defined(Rel14) - - if (mbsfn_AreaInfoList != NULL) { - LOG_I(MAC, "[UE %d][CONFIG] Received %d MBSFN Area Info\n", - Mod_idP, mbsfn_AreaInfoList->list.count); - UE_mac_inst[Mod_idP].num_active_mbsfn_area = - mbsfn_AreaInfoList->list.count; - - for (i = 0; i < mbsfn_AreaInfoList->list.count; i++) { - UE_mac_inst[Mod_idP].mbsfn_AreaInfo[i] = - mbsfn_AreaInfoList->list.array[i]; - LOG_I(MAC, - "[UE %d] MBSFN_AreaInfo[%d]: MCCH Repetition Period = %ld\n", - Mod_idP, i, - UE_mac_inst[Mod_idP].mbsfn_AreaInfo[i]-> - mcch_Config_r9.mcch_RepetitionPeriod_r9); - phy_config_sib13_ue(Mod_idP, 0, eNB_index, i, - UE_mac_inst[Mod_idP]. - mbsfn_AreaInfo[i]->mbsfn_AreaId_r9); - } - } - - if (pmch_InfoList != NULL) { - - // LOG_I(MAC,"DUY: lcid when entering rrc_mac config_req is %02d\n",(pmch_InfoList->list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9)); - - LOG_I(MAC, "[UE %d] Configuring PMCH_config from MCCH MESSAGE \n", - Mod_idP); - - for (i = 0; i < pmch_InfoList->list.count; i++) { - UE_mac_inst[Mod_idP].pmch_Config[i] = - &pmch_InfoList->list.array[i]->pmch_Config_r9; - LOG_I(MAC, "[UE %d] PMCH[%d]: MCH_Scheduling_Period = %ld\n", - Mod_idP, i, - UE_mac_inst[Mod_idP]. - pmch_Config[i]->mch_SchedulingPeriod_r9); - } - - UE_mac_inst[Mod_idP].mcch_status = 1; - } -#endif -#ifdef CBA - - if (cba_rnti) { - UE_mac_inst[Mod_idP].cba_rnti[num_active_cba_groups - 1] = - cba_rnti; - LOG_D(MAC, - "[UE %d] configure CBA group %d RNTI %x for eNB %d (total active cba group %d)\n", - Mod_idP, Mod_idP % num_active_cba_groups, cba_rnti, - eNB_index, num_active_cba_groups); - phy_config_cba_rnti(Mod_idP, CC_idP, eNB_flagP, eNB_index, - cba_rnti, num_active_cba_groups - 1, - num_active_cba_groups); - } -#endif - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); - - return (0); -} diff --git a/openair2/LAYER2/MAC/config_ue.c b/openair2/LAYER2/MAC/config_ue.c new file mode 100644 index 0000000000..5ef18f5bda --- /dev/null +++ b/openair2/LAYER2/MAC/config_ue.c @@ -0,0 +1,584 @@ + +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file config.c + * \brief UE and eNB configuration performed by RRC or as a consequence of RRC procedures + * \author Navid Nikaein and Raymond Knopp + * \date 2010 - 2014 + * \version 0.1 + * \email: navid.nikaein@eurecom.fr + * @ingroup _mac + + */ + +#include "COMMON/platform_types.h" +#include "COMMON/platform_constants.h" +#include "SCHED/defs.h" +#include "SystemInformationBlockType2.h" +//#include "RadioResourceConfigCommonSIB.h" +#include "RadioResourceConfigDedicated.h" +#ifdef Rel14 +#include "PRACH-ConfigSIB-v1310.h" +#endif +#include "MeasGapConfig.h" +#include "MeasObjectToAddModList.h" +#include "TDD-Config.h" +#include "MAC-MainConfig.h" +#include "defs.h" +#include "proto.h" +#include "extern.h" +#include "UTIL/LOG/log.h" +#include "UTIL/LOG/vcd_signal_dumper.h" + +#include "common/ran_context.h" +#if defined(Rel10) || defined(Rel14) +#include "MBSFN-AreaInfoList-r9.h" +#include "MBSFN-AreaInfo-r9.h" +#include "MBSFN-SubframeConfigList.h" +#include "PMCH-InfoList-r9.h" +#endif + +extern void mac_init_cell_params(int Mod_idP,int CC_idP); +extern void phy_reset_ue(module_id_t Mod_id,uint8_t CC_id,uint8_t eNB_index); + + +/* sec 5.9, 36.321: MAC Reset Procedure */ +void ue_mac_reset(module_id_t module_idP, uint8_t eNB_index) +{ + + //Resetting Bj + UE_mac_inst[module_idP].scheduling_info.Bj[0] = 0; + UE_mac_inst[module_idP].scheduling_info.Bj[1] = 0; + UE_mac_inst[module_idP].scheduling_info.Bj[2] = 0; + + //Stopping all timers + + //timeAlignmentTimer expires + + // PHY changes for UE MAC reset + phy_reset_ue(module_idP, 0, eNB_index); + + // notify RRC to relase PUCCH/SRS + // cancel all pending SRs + UE_mac_inst[module_idP].scheduling_info.SR_pending = 0; + UE_mac_inst[module_idP].scheduling_info.SR_COUNTER = 0; + + //Set BSR Trigger Bmp and remove timer flags + UE_mac_inst[module_idP].BSR_reporting_active = BSR_TRIGGER_NONE; + + // stop ongoing RACH procedure + + // discard explicitly signaled ra_PreambleIndex and ra_RACH_MaskIndex, if any + UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex = 0; // check! + UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0; + + + ue_init_mac(module_idP); //This will hopefully do the rest of the MAC reset procedure + +} + +int32_t **rxdata; +int32_t **txdata; + + +int +rrc_mac_config_req_ue(module_id_t Mod_idP, + int CC_idP, + uint8_t eNB_index, + RadioResourceConfigCommonSIB_t * + radioResourceConfigCommon, + struct PhysicalConfigDedicated + *physicalConfigDedicated, +#if defined(Rel10) || defined(Rel14) + SCellToAddMod_r10_t * sCellToAddMod_r10, + //struct PhysicalConfigDedicatedSCell_r10 *physicalConfigDedicatedSCell_r10, +#endif + MeasObjectToAddMod_t ** measObj, + MAC_MainConfig_t * mac_MainConfig, + long logicalChannelIdentity, + LogicalChannelConfig_t * logicalChannelConfig, + MeasGapConfig_t * measGapConfig, + TDD_Config_t * tdd_Config, + MobilityControlInfo_t * mobilityControlInfo, + uint8_t * SIwindowsize, + uint16_t * SIperiod, + ARFCN_ValueEUTRA_t * ul_CarrierFreq, + long *ul_Bandwidth, + AdditionalSpectrumEmission_t * + additionalSpectrumEmission, + struct MBSFN_SubframeConfigList + *mbsfn_SubframeConfigList +#if defined(Rel10) || defined(Rel14) + , uint8_t MBMS_Flag, + MBSFN_AreaInfoList_r9_t * mbsfn_AreaInfoList, + PMCH_InfoList_r9_t * pmch_InfoList +#endif +#ifdef CBA + , uint8_t num_active_cba_groups, uint16_t cba_rnti +#endif + ) +{ + + int i; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_IN); + + LOG_I(MAC, "[CONFIG][UE %d] Configuring MAC/PHY from eNB %d\n", + Mod_idP, eNB_index); + + if (tdd_Config != NULL) { + UE_mac_inst[Mod_idP].tdd_Config = tdd_Config; + } + + + if (tdd_Config && SIwindowsize && SIperiod) { + phy_config_sib1_ue(Mod_idP, 0, eNB_index, tdd_Config, + *SIwindowsize, *SIperiod); + } + + if (radioResourceConfigCommon != NULL) { + UE_mac_inst[Mod_idP].radioResourceConfigCommon = + radioResourceConfigCommon; + phy_config_sib2_ue(Mod_idP, 0, eNB_index, + radioResourceConfigCommon, ul_CarrierFreq, + ul_Bandwidth, additionalSpectrumEmission, + mbsfn_SubframeConfigList); + } + // SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup + if (logicalChannelConfig != NULL) { + LOG_I(MAC, + "[CONFIG][UE %d] Applying RRC logicalChannelConfig from eNB%d\n", + Mod_idP, eNB_index); + UE_mac_inst[Mod_idP].logicalChannelConfig[logicalChannelIdentity] = + logicalChannelConfig; + UE_mac_inst[Mod_idP].scheduling_info.Bj[logicalChannelIdentity] = 0; // initilize the bucket for this lcid + + AssertFatal(logicalChannelConfig->ul_SpecificParameters != NULL, + "[UE %d] LCID %ld NULL ul_SpecificParameters\n", + Mod_idP, logicalChannelIdentity); + UE_mac_inst[Mod_idP].scheduling_info.bucket_size[logicalChannelIdentity] = logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate * logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration; // set the max bucket size + if (logicalChannelConfig->ul_SpecificParameters-> + logicalChannelGroup != NULL) { + UE_mac_inst[Mod_idP].scheduling_info. + LCGID[logicalChannelIdentity] = + *logicalChannelConfig->ul_SpecificParameters-> + logicalChannelGroup; + LOG_D(MAC, + "[CONFIG][UE %d] LCID %ld is attached to the LCGID %ld\n", + Mod_idP, logicalChannelIdentity, + *logicalChannelConfig-> + ul_SpecificParameters->logicalChannelGroup); + } else { + UE_mac_inst[Mod_idP].scheduling_info. + LCGID[logicalChannelIdentity] = MAX_NUM_LCGID; + } + UE_mac_inst[Mod_idP]. + scheduling_info.LCID_buffer_remain[logicalChannelIdentity] = 0; + } + + if (mac_MainConfig != NULL) { + LOG_I(MAC, + "[CONFIG][UE%d] Applying RRC macMainConfig from eNB%d\n", + Mod_idP, eNB_index); + UE_mac_inst[Mod_idP].macConfig = mac_MainConfig; + UE_mac_inst[Mod_idP].measGapConfig = measGapConfig; + + if (mac_MainConfig->ul_SCH_Config) { + + if (mac_MainConfig->ul_SCH_Config->periodicBSR_Timer) { + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer = + (uint16_t) * + mac_MainConfig->ul_SCH_Config->periodicBSR_Timer; + } else { + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer = +#ifndef Rel14 + (uint16_t) + MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity +#else + (uint16_t) PeriodicBSR_Timer_r12_infinity; +#endif + ; + } + + if (mac_MainConfig->ul_SCH_Config->maxHARQ_Tx) { + UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx = + (uint16_t) * mac_MainConfig->ul_SCH_Config->maxHARQ_Tx; + } else { + UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx = + (uint16_t) + MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; + } + phy_config_harq_ue(Mod_idP, 0, eNB_index, + UE_mac_inst[Mod_idP]. + scheduling_info.maxHARQ_Tx); + + if (mac_MainConfig->ul_SCH_Config->retxBSR_Timer) { + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = + (uint16_t) mac_MainConfig->ul_SCH_Config-> + retxBSR_Timer; + } else { +#ifndef Rel14 + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = + (uint16_t) + MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf2560; +#else + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = + (uint16_t) RetxBSR_Timer_r12_sf2560; +#endif + } + } +#if defined(Rel10) || defined(Rel14) + + if (mac_MainConfig->ext1 + && mac_MainConfig->ext1->sr_ProhibitTimer_r9) { + UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = + (uint16_t) * mac_MainConfig->ext1->sr_ProhibitTimer_r9; + } else { + UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = 0; + } + + if (mac_MainConfig->ext2 + && mac_MainConfig->ext2->mac_MainConfig_v1020) { + if (mac_MainConfig->ext2-> + mac_MainConfig_v1020->extendedBSR_Sizes_r10) { + UE_mac_inst[Mod_idP].scheduling_info. + extendedBSR_Sizes_r10 = + (uint16_t) * + mac_MainConfig->ext2-> + mac_MainConfig_v1020->extendedBSR_Sizes_r10; + } else { + UE_mac_inst[Mod_idP].scheduling_info. + extendedBSR_Sizes_r10 = (uint16_t) 0; + } + if (mac_MainConfig->ext2->mac_MainConfig_v1020-> + extendedPHR_r10) { + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = + (uint16_t) * + mac_MainConfig->ext2->mac_MainConfig_v1020-> + extendedPHR_r10; + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = + (uint16_t) 0; + } + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = + (uint16_t) 0; + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = + (uint16_t) 0; + } +#endif + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = + MAC_UE_BSR_TIMER_NOT_RUNNING; + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = + MAC_UE_BSR_TIMER_NOT_RUNNING; + + UE_mac_inst[Mod_idP].BSR_reporting_active = BSR_TRIGGER_NONE; + + LOG_D(MAC, "[UE %d]: periodic BSR %d (SF), retx BSR %d (SF)\n", + Mod_idP, + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF, + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF); + + UE_mac_inst[Mod_idP].scheduling_info.drx_config = + mac_MainConfig->drx_Config; + UE_mac_inst[Mod_idP].scheduling_info.phr_config = + mac_MainConfig->phr_Config; + + if (mac_MainConfig->phr_Config) { + UE_mac_inst[Mod_idP].PHR_state = + mac_MainConfig->phr_Config->present; + UE_mac_inst[Mod_idP].PHR_reconfigured = 1; + UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer = + mac_MainConfig->phr_Config->choice.setup.periodicPHR_Timer; + UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer = + mac_MainConfig->phr_Config->choice.setup.prohibitPHR_Timer; + UE_mac_inst[Mod_idP].scheduling_info.PathlossChange = + mac_MainConfig->phr_Config->choice.setup.dl_PathlossChange; + } else { + UE_mac_inst[Mod_idP].PHR_reconfigured = 0; + UE_mac_inst[Mod_idP].PHR_state = + MAC_MainConfig__phr_Config_PR_setup; + UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer = + MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20; + UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer = + MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20; + UE_mac_inst[Mod_idP].scheduling_info.PathlossChange = + MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1; + } + + UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF = + get_sf_perioidicPHR_Timer(UE_mac_inst[Mod_idP]. + scheduling_info.periodicPHR_Timer); + UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF = + get_sf_prohibitPHR_Timer(UE_mac_inst[Mod_idP]. + scheduling_info.prohibitPHR_Timer); + UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db = + get_db_dl_PathlossChange(UE_mac_inst[Mod_idP]. + scheduling_info.PathlossChange); + UE_mac_inst[Mod_idP].PHR_reporting_active = 0; + LOG_D(MAC, + "[UE %d] config PHR (%d): periodic %d (SF) prohibit %d (SF) pathlosschange %d (db) \n", + Mod_idP, + (mac_MainConfig->phr_Config) ? mac_MainConfig-> + phr_Config->present : -1, + UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF, + UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF, + UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db); + } + + + if (physicalConfigDedicated != NULL) { + phy_config_dedicated_ue(Mod_idP, 0, eNB_index, + physicalConfigDedicated); + UE_mac_inst[Mod_idP].physicalConfigDedicated = physicalConfigDedicated; // for SR proc + } +#if defined(Rel10) || defined(Rel14) + + if (sCellToAddMod_r10 != NULL) { + + + phy_config_dedicated_scell_ue(Mod_idP, eNB_index, + sCellToAddMod_r10, 1); + UE_mac_inst[Mod_idP].physicalConfigDedicatedSCell_r10 = sCellToAddMod_r10->radioResourceConfigDedicatedSCell_r10->physicalConfigDedicatedSCell_r10; // using SCell index 0 + } +#endif + + if (measObj != NULL) { + if (measObj[0] != NULL) { + UE_mac_inst[Mod_idP].n_adj_cells = + measObj[0]->measObject.choice. + measObjectEUTRA.cellsToAddModList->list.count; + LOG_I(MAC, "Number of adjacent cells %d\n", + UE_mac_inst[Mod_idP].n_adj_cells); + + for (i = 0; i < UE_mac_inst[Mod_idP].n_adj_cells; i++) { + UE_mac_inst[Mod_idP].adj_cell_id[i] = + measObj[0]->measObject.choice. + measObjectEUTRA.cellsToAddModList->list.array[i]-> + physCellId; + LOG_I(MAC, "Cell %d : Nid_cell %d\n", i, + UE_mac_inst[Mod_idP].adj_cell_id[i]); + } + + phy_config_meas_ue(Mod_idP, 0, eNB_index, + UE_mac_inst[Mod_idP].n_adj_cells, + UE_mac_inst[Mod_idP].adj_cell_id); + } + } + + + if (mobilityControlInfo != NULL) { + + LOG_D(MAC, "[UE%d] MAC Reset procedure triggered by RRC eNB %d \n", + Mod_idP, eNB_index); + ue_mac_reset(Mod_idP, eNB_index); + + if (mobilityControlInfo->radioResourceConfigCommon. + rach_ConfigCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + rach_ConfigCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.rach_ConfigCommon, + sizeof(RACH_ConfigCommon_t)); + } + + memcpy((void *) &UE_mac_inst[Mod_idP]. + radioResourceConfigCommon->prach_Config.prach_ConfigInfo, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.prach_Config.prach_ConfigInfo, + sizeof(PRACH_ConfigInfo_t)); + UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + prach_Config.rootSequenceIndex = + mobilityControlInfo->radioResourceConfigCommon. + prach_Config.rootSequenceIndex; + + if (mobilityControlInfo->radioResourceConfigCommon. + pdsch_ConfigCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + pdsch_ConfigCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.pdsch_ConfigCommon, + sizeof(PDSCH_ConfigCommon_t)); + } + // not a pointer: mobilityControlInfo->radioResourceConfigCommon.pusch_ConfigCommon + memcpy((void *) &UE_mac_inst[Mod_idP]. + radioResourceConfigCommon->pusch_ConfigCommon, + (void *) &mobilityControlInfo-> + radioResourceConfigCommon.pusch_ConfigCommon, + sizeof(PUSCH_ConfigCommon_t)); + + if (mobilityControlInfo->radioResourceConfigCommon.phich_Config) { + /* memcpy((void *)&UE_mac_inst[Mod_idP].radioResourceConfigCommon->phich_Config, + (void *)mobilityControlInfo->radioResourceConfigCommon.phich_Config, + sizeof(PHICH_Config_t)); */ + } + + if (mobilityControlInfo->radioResourceConfigCommon. + pucch_ConfigCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + pucch_ConfigCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.pucch_ConfigCommon, + sizeof(PUCCH_ConfigCommon_t)); + } + + if (mobilityControlInfo-> + radioResourceConfigCommon.soundingRS_UL_ConfigCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + soundingRS_UL_ConfigCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.soundingRS_UL_ConfigCommon, + sizeof(SoundingRS_UL_ConfigCommon_t)); + } + + if (mobilityControlInfo-> + radioResourceConfigCommon.uplinkPowerControlCommon) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + uplinkPowerControlCommon, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.uplinkPowerControlCommon, + sizeof(UplinkPowerControlCommon_t)); + } + //configure antennaInfoCommon somewhere here.. + if (mobilityControlInfo->radioResourceConfigCommon.p_Max) { + //to be configured + } + + if (mobilityControlInfo->radioResourceConfigCommon.tdd_Config) { + UE_mac_inst[Mod_idP].tdd_Config = + mobilityControlInfo->radioResourceConfigCommon.tdd_Config; + } + + if (mobilityControlInfo-> + radioResourceConfigCommon.ul_CyclicPrefixLength) { + memcpy((void *) + &UE_mac_inst[Mod_idP].radioResourceConfigCommon-> + ul_CyclicPrefixLength, + (void *) mobilityControlInfo-> + radioResourceConfigCommon.ul_CyclicPrefixLength, + sizeof(UL_CyclicPrefixLength_t)); + } + // store the previous rnti in case of failure, and set thenew rnti + UE_mac_inst[Mod_idP].crnti_before_ho = UE_mac_inst[Mod_idP].crnti; + UE_mac_inst[Mod_idP].crnti = + ((mobilityControlInfo-> + newUE_Identity.buf[0]) | (mobilityControlInfo-> + newUE_Identity.buf[1] << 8)); + LOG_I(MAC, "[UE %d] Received new identity %x from %d\n", Mod_idP, + UE_mac_inst[Mod_idP].crnti, eNB_index); + UE_mac_inst[Mod_idP].rach_ConfigDedicated = + malloc(sizeof(*mobilityControlInfo->rach_ConfigDedicated)); + + if (mobilityControlInfo->rach_ConfigDedicated) { + memcpy((void *) UE_mac_inst[Mod_idP].rach_ConfigDedicated, + (void *) mobilityControlInfo->rach_ConfigDedicated, + sizeof(*mobilityControlInfo->rach_ConfigDedicated)); + } + + phy_config_afterHO_ue(Mod_idP, 0, eNB_index, mobilityControlInfo, + 0); + } + + + if (mbsfn_SubframeConfigList != NULL) { + LOG_I(MAC, + "[UE %d][CONFIG] Received %d subframe allocation pattern for MBSFN\n", + Mod_idP, mbsfn_SubframeConfigList->list.count); + UE_mac_inst[Mod_idP].num_sf_allocation_pattern = + mbsfn_SubframeConfigList->list.count; + + for (i = 0; i < mbsfn_SubframeConfigList->list.count; i++) { + LOG_I(MAC, + "[UE %d] Configuring MBSFN_SubframeConfig %d from received SIB2 \n", + Mod_idP, i); + UE_mac_inst[Mod_idP].mbsfn_SubframeConfig[i] = + mbsfn_SubframeConfigList->list.array[i]; + // LOG_I("[UE %d] MBSFN_SubframeConfig[%d] pattern is %ld\n", Mod_idP, + // UE_mac_inst[Mod_idP].mbsfn_SubframeConfig[i]->subframeAllocation.choice.oneFrame.buf[0]); + } + } +#if defined(Rel10) || defined(Rel14) + + if (mbsfn_AreaInfoList != NULL) { + LOG_I(MAC, "[UE %d][CONFIG] Received %d MBSFN Area Info\n", + Mod_idP, mbsfn_AreaInfoList->list.count); + UE_mac_inst[Mod_idP].num_active_mbsfn_area = + mbsfn_AreaInfoList->list.count; + + for (i = 0; i < mbsfn_AreaInfoList->list.count; i++) { + UE_mac_inst[Mod_idP].mbsfn_AreaInfo[i] = + mbsfn_AreaInfoList->list.array[i]; + LOG_I(MAC, + "[UE %d] MBSFN_AreaInfo[%d]: MCCH Repetition Period = %ld\n", + Mod_idP, i, + UE_mac_inst[Mod_idP].mbsfn_AreaInfo[i]-> + mcch_Config_r9.mcch_RepetitionPeriod_r9); + phy_config_sib13_ue(Mod_idP, 0, eNB_index, i, + UE_mac_inst[Mod_idP]. + mbsfn_AreaInfo[i]->mbsfn_AreaId_r9); + } + } + + if (pmch_InfoList != NULL) { + + // LOG_I(MAC,"DUY: lcid when entering rrc_mac config_req is %02d\n",(pmch_InfoList->list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9)); + + LOG_I(MAC, "[UE %d] Configuring PMCH_config from MCCH MESSAGE \n", + Mod_idP); + + for (i = 0; i < pmch_InfoList->list.count; i++) { + UE_mac_inst[Mod_idP].pmch_Config[i] = + &pmch_InfoList->list.array[i]->pmch_Config_r9; + LOG_I(MAC, "[UE %d] PMCH[%d]: MCH_Scheduling_Period = %ld\n", + Mod_idP, i, + UE_mac_inst[Mod_idP]. + pmch_Config[i]->mch_SchedulingPeriod_r9); + } + + UE_mac_inst[Mod_idP].mcch_status = 1; + } +#endif +#ifdef CBA + + if (cba_rnti) { + UE_mac_inst[Mod_idP].cba_rnti[num_active_cba_groups - 1] = + cba_rnti; + LOG_D(MAC, + "[UE %d] configure CBA group %d RNTI %x for eNB %d (total active cba group %d)\n", + Mod_idP, Mod_idP % num_active_cba_groups, cba_rnti, + eNB_index, num_active_cba_groups); + phy_config_cba_rnti(Mod_idP, CC_idP, eNB_flagP, eNB_index, + cba_rnti, num_active_cba_groups - 1, + num_active_cba_groups); + } +#endif + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); + + return (0); +} diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index f03a3961f6..add5b08fce 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -710,8 +710,7 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, module_idP); pdcp_run(&ctxt); - rrc_rx_tx(&ctxt, 0, // eNB index, unused in eNB - CC_id); + rrc_rx_tx(&ctxt, CC_id); #if defined(Rel10) || defined(Rel14) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c index 7b45401b06..4bf96d3bce 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c @@ -843,7 +843,7 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, // Get RRCConnectionSetup for Piggyback rrc_sdu_length = mac_rrc_data_req(module_idP, CC_idP, frameP, CCCH, 1, // 1 transport block - &cc[CC_idP].CCCH_pdu.payload[0], ENB_FLAG_YES, module_idP, 0); // not used in this case + &cc[CC_idP].CCCH_pdu.payload[0], 0); // not used in this case AssertFatal(rrc_sdu_length > 0, "[MAC][eNB Scheduler] CCCH not allocated\n"); diff --git a/openair2/LAYER2/MAC/eNB_scheduler_bch.c b/openair2/LAYER2/MAC/eNB_scheduler_bch.c index 5b0fc58bb7..9a1046ff26 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_bch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_bch.c @@ -197,7 +197,7 @@ schedule_SIB1_BR(module_id_t module_idP, n_NB = Sj[((cc->physCellId % N_S_NB) + (i * N_S_NB / m)) % N_S_NB]; - bcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, BCCH_SIB1_BR, 1, &cc->BCCH_BR_pdu[0].payload[0], 1, module_idP, 0); // not used in this case + bcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, BCCH_SIB1_BR, 1, &cc->BCCH_BR_pdu[0].payload[0], 0); // not used in this case AssertFatal(cc->mib->message.schedulingInfoSIB1_BR_r13 < 19, "schedulingInfoSIB1_BR_r13 %d > 18\n", @@ -424,7 +424,7 @@ schedule_SI_BR(module_id_t module_idP, frame_t frameP, if ((sf_mod_period < si_WindowLength_BR_r13) && ((frameP & (((1 << si_RepetitionPattern_r13) - 1))) == 0)) { // this SIB is to be scheduled - bcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, BCCH_SI_BR + i, 1, &cc->BCCH_BR_pdu[i + 1].payload[0], 1, module_idP, 0); // not used in this case + bcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, BCCH_SI_BR + i, 1, &cc->BCCH_BR_pdu[i + 1].payload[0], 0); // not used in this case AssertFatal(bcch_sdu_length > 0, "RRC returned 0 bytes for SI-BR %d\n", i); @@ -606,7 +606,7 @@ schedule_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) dl_req = &dl_config_request->dl_config_request_body; cc = &eNB->common_channels[CC_id]; - mib_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, MIBCH, 1, &cc->MIB_pdu.payload[0], 1, module_idP, 0); // not used in this case + mib_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, MIBCH, 1, &cc->MIB_pdu.payload[0], 0); // not used in this case LOG_D(MAC, "Frame %d, subframe %d: BCH PDU length %d\n", frameP, subframeP, mib_sdu_length); @@ -692,7 +692,7 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) dl_req = &eNB->DL_req[CC_id].dl_config_request_body; - bcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, BCCH, 1, &cc->BCCH_pdu.payload[0], 1, module_idP, 0); // not used in this case + bcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, BCCH, 1, &cc->BCCH_pdu.payload[0], 0); // not used in this case if (bcch_sdu_length > 0) { LOG_D(MAC, "[eNB %d] Frame %d : BCCH->DLSCH CC_id %d, Received %d bytes \n", module_idP, frameP, CC_id, bcch_sdu_length); diff --git a/openair2/LAYER2/MAC/eNB_scheduler_mch.c b/openair2/LAYER2/MAC/eNB_scheduler_mch.c index 7ce5a5b12c..37b13d2de7 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_mch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_mch.c @@ -545,8 +545,7 @@ schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP, "[eNB %d] CC_id %d Frame %d Subframe %d: Schedule MCCH MESSAGE (area %d, sfAlloc %d)\n", module_idP, CC_id, frameP, subframeP, i, j); - mcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, MCCH, 1, &cc->MCCH_pdu.payload[0], 1, // this is eNB - module_idP, // index + mcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, MCCH, 1, &cc->MCCH_pdu.payload[0], i); // this is the mbsfn sync area index if (mcch_sdu_length > 0) { diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 5b614e61ec..60cae298e7 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -614,7 +614,7 @@ rx_sdu(const module_id_t enb_mod_idP, CCCH, (uint8_t *) payload_ptr, rx_lengths[i], - ENB_FLAG_YES, enb_mod_idP, 0); + 0); if (num_ce > 0) { // handle msg3 which is not RRCConnectionRequest diff --git a/openair2/LAYER2/MAC/main.c b/openair2/LAYER2/MAC/main.c index 0feea028aa..e04d658dd0 100644 --- a/openair2/LAYER2/MAC/main.c +++ b/openair2/LAYER2/MAC/main.c @@ -47,76 +47,6 @@ #include "common/ran_context.h" extern RAN_CONTEXT_t RC; -extern void openair_rrc_top_init_ue( int eMBMS_active, char* uecap_xer, uint8_t cba_group_active, uint8_t HO_active); - -void dl_phy_sync_success(module_id_t module_idP, frame_t frameP, unsigned char eNB_index, uint8_t first_sync) //init as MR -{ - LOG_D(MAC, "[UE %d] Frame %d: PHY Sync to eNB_index %d successful \n", - module_idP, frameP, eNB_index); -#if defined(ENABLE_USE_MME) - int mme_enabled = 1; -#else - int mme_enabled = 0; -#endif - - if (first_sync == 1 && !(mme_enabled == 1)) { - //layer2_init_UE(module_idP); - openair_rrc_ue_init(module_idP, eNB_index); - } else { - rrc_in_sync_ind(module_idP, frameP, eNB_index); - } -} - -void -mac_UE_out_of_sync_ind(module_id_t module_idP, frame_t frameP, - uint16_t eNB_index) -{ - - // Mac_rlc_xface->mac_out_of_sync_ind(Mod_id, frameP, eNB_index); -} - - -int -mac_top_init_ue(int eMBMS_active, char *uecap_xer, - uint8_t cba_group_active, uint8_t HO_active) -{ - - int i; - - LOG_I(MAC, "[MAIN] Init function start:Nb_UE_INST=%d\n", NB_UE_INST); - - if (NB_UE_INST > 0) { - UE_mac_inst = - (UE_MAC_INST *) malloc16(NB_UE_INST * sizeof(UE_MAC_INST)); - - AssertFatal(UE_mac_inst != NULL, - "[MAIN] Can't ALLOCATE %zu Bytes for %d UE_MAC_INST with size %zu \n", - NB_UE_INST * sizeof(UE_MAC_INST), NB_UE_INST, - sizeof(UE_MAC_INST)); - - LOG_D(MAC, "[MAIN] ALLOCATE %zu Bytes for %d UE_MAC_INST @ %p\n", - NB_UE_INST * sizeof(UE_MAC_INST), NB_UE_INST, UE_mac_inst); - - bzero(UE_mac_inst, NB_UE_INST * sizeof(UE_MAC_INST)); - - for (i = 0; i < NB_UE_INST; i++) { - ue_init_mac(i); - } - } else { - UE_mac_inst = NULL; - } - - - LOG_I(MAC, "[MAIN] calling RRC\n"); - openair_rrc_top_init_ue(eMBMS_active, uecap_xer, cba_group_active, - HO_active); - - - LOG_I(MAC, "[MAIN][INIT] Init function finished\n"); - - return (0); - -} void mac_top_init_eNB(void) @@ -262,20 +192,6 @@ void mac_top_cleanup(void) } -int -l2_init_ue(int eMBMS_active, char *uecap_xer, uint8_t cba_group_active, - uint8_t HO_active) -{ - LOG_I(MAC, "[MAIN] MAC_INIT_GLOBAL_PARAM IN...\n"); - // NB_NODE=2; - // NB_INST=2; - - rlcmac_init_global_param(); - LOG_I(MAC, "[MAIN] init UE MAC functions \n"); - mac_top_init_ue(eMBMS_active, uecap_xer, cba_group_active, HO_active); - return (1); -} - int l2_init_eNB(void) { diff --git a/openair2/LAYER2/MAC/main_ue.c b/openair2/LAYER2/MAC/main_ue.c new file mode 100644 index 0000000000..64326dec61 --- /dev/null +++ b/openair2/LAYER2/MAC/main_ue.c @@ -0,0 +1,150 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file main.c + * \brief top init of Layer 2 + * \author Navid Nikaein and Raymond Knopp + * \date 2010 - 2014 + * \version 1.0 + * \email: navid.nikaein@eurecom.fr + * @ingroup _mac + + */ + +#include "defs.h" +#include "proto.h" +#include "extern.h" +#include "assertions.h" +#include "PHY_INTERFACE/extern.h" +#include "PHY/defs.h" +#include "SCHED/defs.h" +#include "LAYER2/PDCP_v10.1.0/pdcp.h" +#include "RRC/LITE/defs.h" +#include "UTIL/LOG/log.h" +#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" + +#include "SCHED/defs.h" + + +#include "common/ran_context.h" + +extern void openair_rrc_top_init_ue( int eMBMS_active, char* uecap_xer, uint8_t cba_group_active, uint8_t HO_active); + +void dl_phy_sync_success(module_id_t module_idP, frame_t frameP, unsigned char eNB_index, uint8_t first_sync) //init as MR +{ + LOG_D(MAC, "[UE %d] Frame %d: PHY Sync to eNB_index %d successful \n", + module_idP, frameP, eNB_index); +#if defined(ENABLE_USE_MME) + int mme_enabled = 1; +#else + int mme_enabled = 0; +#endif + + if (first_sync == 1 && !(mme_enabled == 1)) { + //layer2_init_UE(module_idP); + openair_rrc_ue_init(module_idP, eNB_index); + } else { + rrc_in_sync_ind(module_idP, frameP, eNB_index); + } +} + +void +mac_UE_out_of_sync_ind(module_id_t module_idP, frame_t frameP, + uint16_t eNB_index) +{ + + // Mac_rlc_xface->mac_out_of_sync_ind(Mod_id, frameP, eNB_index); +} + + +int +mac_top_init_ue(int eMBMS_active, char *uecap_xer, + uint8_t cba_group_active, uint8_t HO_active) +{ + + int i; + + LOG_I(MAC, "[MAIN] Init function start:Nb_UE_INST=%d\n", NB_UE_INST); + + if (NB_UE_INST > 0) { + UE_mac_inst = + (UE_MAC_INST *) malloc16(NB_UE_INST * sizeof(UE_MAC_INST)); + + AssertFatal(UE_mac_inst != NULL, + "[MAIN] Can't ALLOCATE %zu Bytes for %d UE_MAC_INST with size %zu \n", + NB_UE_INST * sizeof(UE_MAC_INST), NB_UE_INST, + sizeof(UE_MAC_INST)); + + LOG_D(MAC, "[MAIN] ALLOCATE %zu Bytes for %d UE_MAC_INST @ %p\n", + NB_UE_INST * sizeof(UE_MAC_INST), NB_UE_INST, UE_mac_inst); + + bzero(UE_mac_inst, NB_UE_INST * sizeof(UE_MAC_INST)); + + for (i = 0; i < NB_UE_INST; i++) { + ue_init_mac(i); + } + } else { + UE_mac_inst = NULL; + } + + + LOG_I(MAC, "[MAIN] calling RRC\n"); + openair_rrc_top_init_ue(eMBMS_active, uecap_xer, cba_group_active, + HO_active); + + + LOG_I(MAC, "[MAIN][INIT] Init function finished\n"); + + return (0); + +} + +int rlcmac_init_global_param_ue(void) +{ + + + LOG_I(MAC, "[MAIN] CALLING RLC_MODULE_INIT...\n"); + + if (rlc_module_init() != 0) { + return (-1); + } + + pdcp_layer_init(); + + LOG_I(MAC, "[MAIN] Init Global Param Done\n"); + + return 0; +} + +int +l2_init_ue(int eMBMS_active, char *uecap_xer, uint8_t cba_group_active, + uint8_t HO_active) +{ + LOG_I(MAC, "[MAIN] MAC_INIT_GLOBAL_PARAM IN...\n"); + // NB_NODE=2; + // NB_INST=2; + + rlcmac_init_global_param_ue(); + LOG_I(MAC, "[MAIN] init UE MAC functions \n"); + mac_top_init_ue(eMBMS_active, uecap_xer, cba_group_active, HO_active); + return (1); +} + diff --git a/openair2/LAYER2/MAC/ra_procedures.c b/openair2/LAYER2/MAC/ra_procedures.c index 3f2df025c7..8868d2d548 100644 --- a/openair2/LAYER2/MAC/ra_procedures.c +++ b/openair2/LAYER2/MAC/ra_procedures.c @@ -372,14 +372,14 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP, int CC_id, if (UE_mac_inst[module_idP].RA_active == 0) { LOG_I(MAC, "RA not active\n"); // check if RRC is ready to initiate the RA procedure - Size = mac_rrc_data_req(module_idP, + Size = mac_rrc_data_req_ue(module_idP, CC_id, frameP, CCCH, 1, &UE_mac_inst[module_idP]. CCCH_pdu.payload[sizeof (SCH_SUBHEADER_SHORT) - + 1], 0, eNB_indexP, + + 1], eNB_indexP, 0); Size16 = (uint16_t) Size; diff --git a/openair2/LAYER2/MAC/rar_tools.c b/openair2/LAYER2/MAC/rar_tools.c index 8d9e5bb3e1..6261eaf356 100644 --- a/openair2/LAYER2/MAC/rar_tools.c +++ b/openair2/LAYER2/MAC/rar_tools.c @@ -182,104 +182,3 @@ fill_rar_br(eNB_MAC_INST * eNB, } #endif -//------------------------------------------------------------------------------ -uint16_t ue_process_rar(const module_id_t module_idP, const int CC_id, const frame_t frameP, const rnti_t ra_rnti, uint8_t * const dlsch_buffer, rnti_t * const t_crnti, const uint8_t preamble_index, uint8_t * selected_rar_buffer // output argument for storing the selected RAR header and RAR payload - ) -//------------------------------------------------------------------------------ -{ - uint16_t ret = 0; // return value - - RA_HEADER_RAPID *rarh = (RA_HEADER_RAPID *) dlsch_buffer; - // RAR_PDU *rar = (RAR_PDU *)(dlsch_buffer+1); - uint8_t *rar = (uint8_t *) (dlsch_buffer + 1); - - // get the last RAR payload for working with CMW500 - uint8_t n_rarpy = 0; // number of RAR payloads - uint8_t n_rarh = 0; // number of MAC RAR subheaders - uint8_t best_rx_rapid = -1; // the closest RAPID receive from all RARs - while (1) { - n_rarh++; - if (rarh->T == 1) { - n_rarpy++; - LOG_D(MAC, "RAPID %d\n", rarh->RAPID); - } - - if (rarh->RAPID == preamble_index) { - LOG_D(PHY, "Found RAR with the intended RAPID %d\n", - rarh->RAPID); - rar = (uint8_t *) (dlsch_buffer + n_rarh + (n_rarpy - 1) * 6); - break; - } - - if (abs((int) rarh->RAPID - (int) preamble_index) < - abs((int) best_rx_rapid - (int) preamble_index)) { - best_rx_rapid = rarh->RAPID; - rar = (uint8_t *) (dlsch_buffer + n_rarh + (n_rarpy - 1) * 6); - } - - if (rarh->E == 0) { - LOG_I(PHY, - "No RAR found with the intended RAPID. The closest RAPID in all RARs is %d\n", - best_rx_rapid); - break; - } else { - rarh++; - } - }; - LOG_D(MAC, "number of RAR subheader %d; number of RAR pyloads %d\n", - n_rarh, n_rarpy); - - if (CC_id > 0) { - LOG_W(MAC, "Should not have received RAR on secondary CCs! \n"); - return (0xffff); - } - - LOG_I(MAC, - "[eNB %d][RAPROC] Frame %d Received RAR (%02x|%02x.%02x.%02x.%02x.%02x.%02x) for preamble %d/%d\n", - module_idP, frameP, *(uint8_t *) rarh, rar[0], rar[1], rar[2], - rar[3], rar[4], rar[5], rarh->RAPID, preamble_index); -#ifdef DEBUG_RAR - LOG_D(MAC, "[UE %d][RAPROC] rarh->E %d\n", module_idP, rarh->E); - LOG_D(MAC, "[UE %d][RAPROC] rarh->T %d\n", module_idP, rarh->T); - LOG_D(MAC, "[UE %d][RAPROC] rarh->RAPID %d\n", module_idP, - rarh->RAPID); - - // LOG_I(MAC,"[UE %d][RAPROC] rar->R %d\n",module_idP,rar->R); - LOG_D(MAC, "[UE %d][RAPROC] rar->Timing_Advance_Command %d\n", - module_idP, (((uint16_t) (rar[0] & 0x7f)) << 4) + (rar[1] >> 4)); - // LOG_I(MAC,"[UE %d][RAPROC] rar->hopping_flag %d\n",module_idP,rar->hopping_flag); - // LOG_I(MAC,"[UE %d][RAPROC] rar->rb_alloc %d\n",module_idP,rar->rb_alloc); - // LOG_I(MAC,"[UE %d][RAPROC] rar->mcs %d\n",module_idP,rar->mcs); - // LOG_I(MAC,"[UE %d][RAPROC] rar->TPC %d\n",module_idP,rar->TPC); - // LOG_I(MAC,"[UE %d][RAPROC] rar->UL_delay %d\n",module_idP,rar->UL_delay); - // LOG_I(MAC,"[UE %d][RAPROC] rar->cqi_req %d\n",module_idP,rar->cqi_req); - LOG_D(MAC, "[UE %d][RAPROC] rar->t_crnti %x\n", module_idP, - (uint16_t) rar[5] + (rar[4] << 8)); -#endif - - if (opt_enabled) { - LOG_D(OPT, - "[UE %d][RAPROC] CC_id %d RAR Frame %d trace pdu for ra-RNTI %x\n", - module_idP, CC_id, frameP, ra_rnti); - trace_pdu(1, (uint8_t *) dlsch_buffer, n_rarh + n_rarpy * 6, - module_idP, 2, ra_rnti, UE_mac_inst[module_idP].rxFrame, - UE_mac_inst[module_idP].rxSubframe, 0, 0); - } - - if (preamble_index == rarh->RAPID) { - *t_crnti = (uint16_t) rar[5] + (rar[4] << 8); //rar->t_crnti; - UE_mac_inst[module_idP].crnti = *t_crnti; //rar->t_crnti; - //return(rar->Timing_Advance_Command); - ret = ((((uint16_t) (rar[0] & 0x7f)) << 4) + (rar[1] >> 4)); - } else { - UE_mac_inst[module_idP].crnti = 0; - ret = (0xffff); - } - - // move the selected RAR to the front of the RA_PDSCH buffer - memcpy(selected_rar_buffer + 0, (uint8_t *) rarh, 1); - memcpy(selected_rar_buffer + 1, (uint8_t *) rar, 6); - - return ret; - -} diff --git a/openair2/LAYER2/MAC/rar_tools_ue.c b/openair2/LAYER2/MAC/rar_tools_ue.c new file mode 100644 index 0000000000..ab193c7a66 --- /dev/null +++ b/openair2/LAYER2/MAC/rar_tools_ue.c @@ -0,0 +1,143 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file rar_tools.c + * \brief random access tools + * \author Raymond Knopp and navid nikaein + * \date 2011 - 2014 + * \version 1.0 + * @ingroup _mac + + */ + +#include "defs.h" +#include "proto.h" +#include "extern.h" +#include "SIMULATION/TOOLS/defs.h" +#include "UTIL/LOG/log.h" +#include "OCG.h" +#include "OCG_extern.h" +#include "UTIL/OPT/opt.h" +#include "common/ran_context.h" + +#define DEBUG_RAR + +//------------------------------------------------------------------------------ +uint16_t ue_process_rar(const module_id_t module_idP, const int CC_id, const frame_t frameP, const rnti_t ra_rnti, uint8_t * const dlsch_buffer, rnti_t * const t_crnti, const uint8_t preamble_index, uint8_t * selected_rar_buffer // output argument for storing the selected RAR header and RAR payload + ) +//------------------------------------------------------------------------------ +{ + uint16_t ret = 0; // return value + + RA_HEADER_RAPID *rarh = (RA_HEADER_RAPID *) dlsch_buffer; + // RAR_PDU *rar = (RAR_PDU *)(dlsch_buffer+1); + uint8_t *rar = (uint8_t *) (dlsch_buffer + 1); + + // get the last RAR payload for working with CMW500 + uint8_t n_rarpy = 0; // number of RAR payloads + uint8_t n_rarh = 0; // number of MAC RAR subheaders + uint8_t best_rx_rapid = -1; // the closest RAPID receive from all RARs + while (1) { + n_rarh++; + if (rarh->T == 1) { + n_rarpy++; + LOG_D(MAC, "RAPID %d\n", rarh->RAPID); + } + + if (rarh->RAPID == preamble_index) { + LOG_D(PHY, "Found RAR with the intended RAPID %d\n", + rarh->RAPID); + rar = (uint8_t *) (dlsch_buffer + n_rarh + (n_rarpy - 1) * 6); + break; + } + + if (abs((int) rarh->RAPID - (int) preamble_index) < + abs((int) best_rx_rapid - (int) preamble_index)) { + best_rx_rapid = rarh->RAPID; + rar = (uint8_t *) (dlsch_buffer + n_rarh + (n_rarpy - 1) * 6); + } + + if (rarh->E == 0) { + LOG_I(PHY, + "No RAR found with the intended RAPID. The closest RAPID in all RARs is %d\n", + best_rx_rapid); + break; + } else { + rarh++; + } + }; + LOG_D(MAC, "number of RAR subheader %d; number of RAR pyloads %d\n", + n_rarh, n_rarpy); + + if (CC_id > 0) { + LOG_W(MAC, "Should not have received RAR on secondary CCs! \n"); + return (0xffff); + } + + LOG_I(MAC, + "[eNB %d][RAPROC] Frame %d Received RAR (%02x|%02x.%02x.%02x.%02x.%02x.%02x) for preamble %d/%d\n", + module_idP, frameP, *(uint8_t *) rarh, rar[0], rar[1], rar[2], + rar[3], rar[4], rar[5], rarh->RAPID, preamble_index); +#ifdef DEBUG_RAR + LOG_D(MAC, "[UE %d][RAPROC] rarh->E %d\n", module_idP, rarh->E); + LOG_D(MAC, "[UE %d][RAPROC] rarh->T %d\n", module_idP, rarh->T); + LOG_D(MAC, "[UE %d][RAPROC] rarh->RAPID %d\n", module_idP, + rarh->RAPID); + + // LOG_I(MAC,"[UE %d][RAPROC] rar->R %d\n",module_idP,rar->R); + LOG_D(MAC, "[UE %d][RAPROC] rar->Timing_Advance_Command %d\n", + module_idP, (((uint16_t) (rar[0] & 0x7f)) << 4) + (rar[1] >> 4)); + // LOG_I(MAC,"[UE %d][RAPROC] rar->hopping_flag %d\n",module_idP,rar->hopping_flag); + // LOG_I(MAC,"[UE %d][RAPROC] rar->rb_alloc %d\n",module_idP,rar->rb_alloc); + // LOG_I(MAC,"[UE %d][RAPROC] rar->mcs %d\n",module_idP,rar->mcs); + // LOG_I(MAC,"[UE %d][RAPROC] rar->TPC %d\n",module_idP,rar->TPC); + // LOG_I(MAC,"[UE %d][RAPROC] rar->UL_delay %d\n",module_idP,rar->UL_delay); + // LOG_I(MAC,"[UE %d][RAPROC] rar->cqi_req %d\n",module_idP,rar->cqi_req); + LOG_D(MAC, "[UE %d][RAPROC] rar->t_crnti %x\n", module_idP, + (uint16_t) rar[5] + (rar[4] << 8)); +#endif + + if (opt_enabled) { + LOG_D(OPT, + "[UE %d][RAPROC] CC_id %d RAR Frame %d trace pdu for ra-RNTI %x\n", + module_idP, CC_id, frameP, ra_rnti); + trace_pdu(1, (uint8_t *) dlsch_buffer, n_rarh + n_rarpy * 6, + module_idP, 2, ra_rnti, UE_mac_inst[module_idP].rxFrame, + UE_mac_inst[module_idP].rxSubframe, 0, 0); + } + + if (preamble_index == rarh->RAPID) { + *t_crnti = (uint16_t) rar[5] + (rar[4] << 8); //rar->t_crnti; + UE_mac_inst[module_idP].crnti = *t_crnti; //rar->t_crnti; + //return(rar->Timing_Advance_Command); + ret = ((((uint16_t) (rar[0] & 0x7f)) << 4) + (rar[1] >> 4)); + } else { + UE_mac_inst[module_idP].crnti = 0; + ret = (0xffff); + } + + // move the selected RAR to the front of the RA_PDSCH buffer + memcpy(selected_rar_buffer + 0, (uint8_t *) rarh, 1); + memcpy(selected_rar_buffer + 1, (uint8_t *) rar, 6); + + return ret; + +} diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 5b73a76312..48b92588c6 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -520,13 +520,13 @@ ue_send_sdu(module_id_t module_idP, LOG_T(MAC, "\n"); #endif - mac_rrc_data_ind(module_idP, + mac_rrc_data_ind_ue(module_idP, CC_id, frameP, subframeP, UE_mac_inst[module_idP].crnti, CCCH, (uint8_t *) payload_ptr, - rx_lengths[i], ENB_FLAG_NO, eNB_index, 0); + rx_lengths[i], eNB_index, 0); } else if ((rx_lcids[i] == DCCH) || (rx_lcids[i] == DCCH1)) { LOG_D(MAC, @@ -589,9 +589,9 @@ ue_decode_si(module_id_t module_idP, int CC_id, frame_t frameP, LOG_D(MAC, "[UE %d] Frame %d Sending SI to RRC (LCID Id %d,len %d)\n", module_idP, frameP, BCCH, len); - mac_rrc_data_ind(module_idP, CC_id, frameP, 0, // unknown subframe + mac_rrc_data_ind_ue(module_idP, CC_id, frameP, 0, // unknown subframe SI_RNTI, - BCCH, (uint8_t *) pdu, len, ENB_FLAG_NO, eNB_index, + BCCH, (uint8_t *) pdu, len, eNB_index, 0); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_SI, VCD_FUNCTION_OUT); @@ -627,9 +627,9 @@ ue_decode_p(module_id_t module_idP, int CC_id, frame_t frameP, "[UE %d] Frame %d Sending Paging message to RRC (LCID Id %d,len %d)\n", module_idP, frameP, PCCH, len); - mac_rrc_data_ind(module_idP, CC_id, frameP, 0, // unknown subframe + mac_rrc_data_ind_ue(module_idP, CC_id, frameP, 0, // unknown subframe P_RNTI, - PCCH, (uint8_t *) pdu, len, ENB_FLAG_NO, eNB_index, + PCCH, (uint8_t *) pdu, len, eNB_index, 0); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME (VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_PCCH, VCD_FUNCTION_OUT); @@ -749,10 +749,10 @@ ue_send_mch_sdu(module_id_t module_idP, uint8_t CC_id, frame_t frameP, "[UE %d] Frame %d : SDU %d MCH->MCCH for sync area %d (eNB %d, %d bytes)\n", module_idP, frameP, i, sync_area, eNB_index, rx_lengths[i]); - mac_rrc_data_ind(module_idP, CC_id, frameP, 0, // unknown subframe + mac_rrc_data_ind_ue(module_idP, CC_id, frameP, 0, // unknown subframe M_RNTI, MCCH, - payload_ptr, rx_lengths[i], 0, eNB_index, + payload_ptr, rx_lengths[i], eNB_index, sync_area); } else if (rx_lcids[i] == MTCH) { if (UE_mac_inst[module_idP].msi_status == 1) { @@ -2235,10 +2235,10 @@ ue_scheduler(const module_id_t module_idP, UE_mac_inst[module_idP].rxSubframe = rxSubframeP; #ifdef CELLULAR - rrc_rx_tx(module_idP, txFrameP, 0, eNB_indexP); + rrc_rx_tx_ue(module_idP, txFrameP, 0, eNB_indexP); #else - switch (rrc_rx_tx(&ctxt, eNB_indexP, CC_id)) { + switch (rrc_rx_tx_ue(&ctxt, eNB_indexP, CC_id)) { case RRC_OK: break; diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index b362e8887a..f07e18148e 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -638,11 +638,11 @@ pdcp_data_ind( PROTOCOL_PDCP_CTXT_FMT" DATA-IND len %u", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), sdu_buffer_sizeP - pdcp_header_len - pdcp_tailer_len); - rrc_data_ind(ctxt_pP, + rrc_data_ind(ctxt_pP, rb_id, sdu_buffer_sizeP - pdcp_header_len - pdcp_tailer_len, (uint8_t*)&sdu_buffer_pP->data[pdcp_header_len]); - free_mem_block(sdu_buffer_pP, __func__); + // free_mem_block(new_sdu, __func__); if (ctxt_pP->enb_flag) { diff --git a/openair2/LAYER2/openair2_proc.c b/openair2/LAYER2/openair2_proc.c index 7801279be2..4a8379bbbd 100644 --- a/openair2/LAYER2/openair2_proc.c +++ b/openair2/LAYER2/openair2_proc.c @@ -236,7 +236,7 @@ int dump_eNB_l2_stats(char *buffer, int length) PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, eNB_id, ENB_FLAG_YES, - UE_list->eNB_UE_stats[UE_PCCID(eNB_id,UE_id)][UE_id].crnti, + UE_list->eNB_UE_stats[0][UE_id].crnti,//UE_PCCID(eNB_id,UE_id)][UE_id].crnti, eNB->frame, eNB->subframe, eNB_id); diff --git a/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.h b/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.h index b13d72f980..4b651761de 100644 --- a/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.h +++ b/openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.h @@ -41,8 +41,6 @@ mac_rrc_data_req( const rb_id_t srb_idP, const uint8_t nb_tbP, uint8_t* const buffer_pP, - const eNB_flag_t eNB_flagP, - const mac_enb_index_t eNB_indexP, const uint8_t mbsfn_sync_areaP ); @@ -56,7 +54,31 @@ mac_rrc_data_ind( const rb_id_t srb_idP, const uint8_t *sduP, const sdu_size_t sdu_lenP, - const eNB_flag_t eNB_flagP, + const uint8_t mbsfn_sync_area +); + +int8_t +mac_rrc_data_req_ue( + const module_id_t module_idP, + const int CC_idP, + const frame_t frameP, + const rb_id_t srb_idP, + const uint8_t nb_tbP, + uint8_t* const buffer_pP, + const mac_enb_index_t eNB_indexP, + const uint8_t mbsfn_sync_areaP +); + +int8_t +mac_rrc_data_ind_ue( + const module_id_t module_idP, + const int CC_idP, + const frame_t frameP, + const sub_frame_t sub_frameP, + const rnti_t rntiP, + const rb_id_t srb_idP, + const uint8_t *sduP, + const sdu_size_t sdu_lenP, const mac_enb_index_t eNB_indexP, const uint8_t mbsfn_sync_area ); diff --git a/openair2/RRC/LITE/L2_interface.c b/openair2/RRC/LITE/L2_interface.c index 3077b9ba80..bf6a799a66 100644 --- a/openair2/RRC/LITE/L2_interface.c +++ b/openair2/RRC/LITE/L2_interface.c @@ -56,7 +56,6 @@ extern UE_MAC_INST *UE_mac_inst; //#define RRC_DATA_REQ_DEBUG //#define DEBUG_RRC 1 -mui_t mui=0; extern RAN_CONTEXT_t RC; @@ -69,8 +68,6 @@ mac_rrc_data_req( const rb_id_t Srb_id, const uint8_t Nb_tb, uint8_t* const buffer_pP, - const eNB_flag_t enb_flagP, - const uint8_t eNB_index, const uint8_t mbsfn_sync_area ) //-------------------------------------------------------------------------- @@ -90,7 +87,6 @@ mac_rrc_data_req( rrc_eNB_carrier_data_t *carrier; BCCH_BCH_Message_t *mib; - if( enb_flagP == ENB_FLAG_YES) { rrc = RC.rrc[Mod_idP]; carrier = &rrc->carrier[0]; @@ -321,48 +317,6 @@ mac_rrc_data_req( #endif - } else { //This is an UE - - - LOG_D(RRC,"[UE %d] Frame %d Filling CCCH SRB_ID %d\n",Mod_idP,frameP,Srb_id); - LOG_D(RRC,"[UE %d] Frame %d buffer_pP status %d,\n",Mod_idP,frameP, UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size); - - - if( (UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size > 0) ) { - -#if defined(ENABLE_ITTI) - { - MessageDef *message_p; - int ccch_size = UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size; - int sdu_size = sizeof(RRC_MAC_CCCH_DATA_REQ (message_p).sdu); - - if (ccch_size > sdu_size) { - LOG_E(RRC, "SDU larger than CCCH SDU buffer size (%d, %d)", ccch_size, sdu_size); - ccch_size = sdu_size; - } - - message_p = itti_alloc_new_message (TASK_RRC_UE, RRC_MAC_CCCH_DATA_REQ); - RRC_MAC_CCCH_DATA_REQ (message_p).frame = frameP; - RRC_MAC_CCCH_DATA_REQ (message_p).sdu_size = ccch_size; - memset (RRC_MAC_CCCH_DATA_REQ (message_p).sdu, 0, CCCH_SDU_SIZE); - memcpy (RRC_MAC_CCCH_DATA_REQ (message_p).sdu, UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.Payload, ccch_size); - RRC_MAC_CCCH_DATA_REQ (message_p).enb_index = eNB_index; - - itti_send_msg_to_task (TASK_MAC_UE, UE_MODULE_ID_TO_INSTANCE(Mod_idP), message_p); - } -#endif - - memcpy(&buffer_pP[0],&UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.Payload[0],UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size); - uint8_t Ret_size=UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size; - // UE_rrc_inst[Mod_id].Srb0[eNB_index].Tx_buffer.payload_size=0; - UE_rrc_inst[Mod_idP].Info[eNB_index].T300_active = 1; - UE_rrc_inst[Mod_idP].Info[eNB_index].T300_cnt = 0; - // msg("[RRC][UE %d] Sending rach\n",Mod_id); - return(Ret_size); - } else { - return 0; - } - } return(0); } @@ -378,8 +332,6 @@ mac_rrc_data_ind( const rb_id_t srb_idP, const uint8_t* sduP, const sdu_size_t sdu_lenP, - const eNB_flag_t eNB_flagP, - const mac_enb_index_t eNB_indexP, const uint8_t mbsfn_sync_areaP ) //-------------------------------------------------------------------------- @@ -394,114 +346,8 @@ mac_rrc_data_ind( /* int si_window; */ - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, eNB_flagP, rntiP, frameP, sub_frameP,eNB_indexP); + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, rntiP, frameP, sub_frameP,0); - if(eNB_flagP == ENB_FLAG_NO) { - if(srb_idP == BCCH) { - LOG_D(RRC,"[UE %d] Received SDU for BCCH on SRB %d from eNB %d\n",module_idP,srb_idP,eNB_indexP); - -#if defined(ENABLE_ITTI) - { - MessageDef *message_p; - int msg_sdu_size = sizeof(RRC_MAC_BCCH_DATA_IND (message_p).sdu); - - if (sdu_lenP > msg_sdu_size) { - LOG_E(RRC, "SDU larger than BCCH SDU buffer size (%d, %d)", sdu_lenP, msg_sdu_size); - sdu_size = msg_sdu_size; - } else { - sdu_size = sdu_lenP; - } - - message_p = itti_alloc_new_message (TASK_MAC_UE, RRC_MAC_BCCH_DATA_IND); - memset (RRC_MAC_BCCH_DATA_IND (message_p).sdu, 0, BCCH_SDU_SIZE); - RRC_MAC_BCCH_DATA_IND (message_p).frame = frameP; - RRC_MAC_BCCH_DATA_IND (message_p).sub_frame = sub_frameP; - RRC_MAC_BCCH_DATA_IND (message_p).sdu_size = sdu_size; - memcpy (RRC_MAC_BCCH_DATA_IND (message_p).sdu, sduP, sdu_size); - RRC_MAC_BCCH_DATA_IND (message_p).enb_index = eNB_indexP; - RRC_MAC_BCCH_DATA_IND (message_p).rsrq = 30 /* TODO change phy to report rspq */; - RRC_MAC_BCCH_DATA_IND (message_p).rsrp = 45 /* TODO change phy to report rspp */; - - itti_send_msg_to_task (TASK_RRC_UE, ctxt.instance, message_p); - } -#else - decode_BCCH_DLSCH_Message(&ctxt,eNB_indexP,(uint8_t*)sduP,sdu_lenP, 0, 0); -#endif - } - - if(srb_idP == PCCH) { - LOG_D(RRC,"[UE %d] Received SDU for PCCH on SRB %d from eNB %d\n",module_idP,srb_idP,eNB_indexP); - decode_PCCH_DLSCH_Message(&ctxt,eNB_indexP,(uint8_t*)sduP,sdu_lenP); - } - if((srb_idP & RAB_OFFSET) == CCCH) { - if (sdu_lenP>0) { - LOG_T(RRC,"[UE %d] Received SDU for CCCH on SRB %d from eNB %d\n",module_idP,srb_idP & RAB_OFFSET,eNB_indexP); - -#if defined(ENABLE_ITTI) - { - MessageDef *message_p; - int msg_sdu_size = CCCH_SDU_SIZE; - - if (sdu_lenP > msg_sdu_size) { - LOG_E(RRC, "SDU larger than CCCH SDU buffer size (%d, %d)", sdu_size, msg_sdu_size); - sdu_size = msg_sdu_size; - } else { - sdu_size = sdu_lenP; - } - - message_p = itti_alloc_new_message (TASK_MAC_UE, RRC_MAC_CCCH_DATA_IND); - memset (RRC_MAC_CCCH_DATA_IND (message_p).sdu, 0, CCCH_SDU_SIZE); - memcpy (RRC_MAC_CCCH_DATA_IND (message_p).sdu, sduP, sdu_size); - RRC_MAC_CCCH_DATA_IND (message_p).frame = frameP; - RRC_MAC_CCCH_DATA_IND (message_p).sub_frame = sub_frameP; - RRC_MAC_CCCH_DATA_IND (message_p).sdu_size = sdu_size; - RRC_MAC_CCCH_DATA_IND (message_p).enb_index = eNB_indexP; - RRC_MAC_CCCH_DATA_IND (message_p).rnti = rntiP; - itti_send_msg_to_task (TASK_RRC_UE, ctxt.instance, message_p); - } -#else - Srb_info = &UE_rrc_inst[module_idP].Srb0[eNB_indexP]; - memcpy(Srb_info->Rx_buffer.Payload,sduP,sdu_lenP); - Srb_info->Rx_buffer.payload_size = sdu_lenP; - rrc_ue_decode_ccch(&ctxt, Srb_info, eNB_indexP); -#endif - } - } - -#if defined(Rel10) || defined(Rel14) - - if ((srb_idP & RAB_OFFSET) == MCCH) { - LOG_T(RRC,"[UE %d] Frame %d: Received SDU on MBSFN sync area %d for MCCH on SRB %d from eNB %d\n", - module_idP,frameP, mbsfn_sync_areaP, srb_idP & RAB_OFFSET,eNB_indexP); - -#if defined(ENABLE_ITTI) - { - MessageDef *message_p; - int msg_sdu_size = sizeof(RRC_MAC_MCCH_DATA_IND (message_p).sdu); - - if (sdu_size > msg_sdu_size) { - LOG_E(RRC, "SDU larger than MCCH SDU buffer size (%d, %d)", sdu_size, msg_sdu_size); - sdu_size = msg_sdu_size; - } - - message_p = itti_alloc_new_message (TASK_MAC_UE, RRC_MAC_MCCH_DATA_IND); - RRC_MAC_MCCH_DATA_IND (message_p).frame = frameP; - RRC_MAC_MCCH_DATA_IND (message_p).sub_frame = sub_frameP; - RRC_MAC_MCCH_DATA_IND (message_p).sdu_size = sdu_lenP; - memset (RRC_MAC_MCCH_DATA_IND (message_p).sdu, 0, MCCH_SDU_SIZE); - memcpy (RRC_MAC_MCCH_DATA_IND (message_p).sdu, sduP, sdu_lenP); - RRC_MAC_MCCH_DATA_IND (message_p).enb_index = eNB_indexP; - RRC_MAC_MCCH_DATA_IND (message_p).mbsfn_sync_area = mbsfn_sync_areaP; - itti_send_msg_to_task (TASK_RRC_UE, ctxt.instance, message_p); - } -#else - decode_MCCH_Message(&ctxt, eNB_indexP, sduP, sdu_lenP, mbsfn_sync_areaP); -#endif - } - -#endif // Rel10 || Rel14 - - } else { // This is an eNB Srb_info = &RC.rrc[module_idP]->carrier[CC_id].Srb0; LOG_D(RRC,"[eNB %d] Received SDU for CCCH on SRB %d\n",module_idP,Srb_info->Srb_id); @@ -538,205 +384,11 @@ mac_rrc_data_ind( } #endif - } return(0); } -//-------------------------------------------------------------------------------------------// -// this function is Not USED anymore -void mac_sync_ind(module_id_t Mod_idP,uint8_t Status) -{ - //-------------------------------------------------------------------------------------------// -} - -//------------------------------------------------------------------------------ -uint8_t -rrc_data_req( - const protocol_ctxt_t* const ctxt_pP, - const rb_id_t rb_idP, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_sizeP, - uint8_t* const buffer_pP, - const pdcp_transmission_mode_t modeP -) -//------------------------------------------------------------------------------ -{ - MSC_LOG_TX_MESSAGE( - ctxt_pP->enb_flag ? MSC_RRC_ENB : MSC_RRC_UE, - ctxt_pP->enb_flag ? MSC_PDCP_ENB : MSC_PDCP_UE, - buffer_pP, - sdu_sizeP, - MSC_AS_TIME_FMT"RRC_DCCH_DATA_REQ UE %x MUI %d size %u", - MSC_AS_TIME_ARGS(ctxt_pP), - ctxt_pP->rnti, - muiP, - sdu_sizeP); - -#if defined(ENABLE_ITTI) - { - MessageDef *message_p; - // Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling). - uint8_t *message_buffer; - - message_buffer = itti_malloc ( - ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, - ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, - sdu_sizeP); - - memcpy (message_buffer, buffer_pP, sdu_sizeP); - - message_p = itti_alloc_new_message (ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, RRC_DCCH_DATA_REQ); - RRC_DCCH_DATA_REQ (message_p).frame = ctxt_pP->frame; - RRC_DCCH_DATA_REQ (message_p).enb_flag = ctxt_pP->enb_flag; - RRC_DCCH_DATA_REQ (message_p).rb_id = rb_idP; - RRC_DCCH_DATA_REQ (message_p).muip = muiP; - RRC_DCCH_DATA_REQ (message_p).confirmp = confirmP; - RRC_DCCH_DATA_REQ (message_p).sdu_size = sdu_sizeP; - RRC_DCCH_DATA_REQ (message_p).sdu_p = message_buffer; - RRC_DCCH_DATA_REQ (message_p).mode = modeP; - RRC_DCCH_DATA_REQ (message_p).module_id = ctxt_pP->module_id; - RRC_DCCH_DATA_REQ (message_p).rnti = ctxt_pP->rnti; - RRC_DCCH_DATA_REQ (message_p).eNB_index = ctxt_pP->eNB_index; - - itti_send_msg_to_task ( - ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, - ctxt_pP->instance, - message_p); - return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. - - } -#else - return pdcp_data_req ( - ctxt_pP, - SRB_FLAG_YES, - rb_idP, - muiP, - confirmP, - sdu_sizeP, - buffer_pP, - modeP); -#endif -} - -//------------------------------------------------------------------------------ -void -rrc_data_ind( - const protocol_ctxt_t* const ctxt_pP, - const rb_id_t Srb_id, - const sdu_size_t sdu_sizeP, - const uint8_t* const buffer_pP -) -//------------------------------------------------------------------------------ -{ - rb_id_t DCCH_index = Srb_id; - - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - LOG_N(RRC, "[UE %x] Frame %d: received a DCCH %d message on SRB %d with Size %d from eNB %d\n", - ctxt_pP->module_id, ctxt_pP->frame, DCCH_index,Srb_id,sdu_sizeP, ctxt_pP->eNB_index); - } else { - LOG_N(RRC, "[eNB %d] Frame %d: received a DCCH %d message on SRB %d with Size %d from UE %x\n", - ctxt_pP->module_id, - ctxt_pP->frame, - DCCH_index, - Srb_id, - sdu_sizeP, - ctxt_pP->rnti); - } - -#if defined(ENABLE_ITTI) - { - MessageDef *message_p; - // Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling). - uint8_t *message_buffer; - - message_buffer = itti_malloc (ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, sdu_sizeP); - memcpy (message_buffer, buffer_pP, sdu_sizeP); - - message_p = itti_alloc_new_message (ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, RRC_DCCH_DATA_IND); - RRC_DCCH_DATA_IND (message_p).frame = ctxt_pP->frame; - RRC_DCCH_DATA_IND (message_p).dcch_index = DCCH_index; - RRC_DCCH_DATA_IND (message_p).sdu_size = sdu_sizeP; - RRC_DCCH_DATA_IND (message_p).sdu_p = message_buffer; - RRC_DCCH_DATA_IND (message_p).rnti = ctxt_pP->rnti; - RRC_DCCH_DATA_IND (message_p).module_id = ctxt_pP->module_id; - RRC_DCCH_DATA_IND (message_p).eNB_index = ctxt_pP->eNB_index; - - itti_send_msg_to_task (ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, ctxt_pP->instance, message_p); - } -#else - - if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - rrc_eNB_decode_dcch( - ctxt_pP, - DCCH_index, - buffer_pP, - sdu_sizeP); - } else { -//#warning "LG put 0 to arg4 that is eNB index" - rrc_ue_decode_dcch( - ctxt_pP, - DCCH_index, - buffer_pP, - 0); - } - -#endif -} - -//-------------------------------------------------------------------------------------------// -void rrc_in_sync_ind(module_id_t Mod_idP, frame_t frameP, uint16_t eNB_index) -{ - //-------------------------------------------------------------------------------------------// -#if defined(ENABLE_ITTI) - { - MessageDef *message_p; - //LOG_I(RRC,"sending a message to task_mac_ue\n"); - message_p = itti_alloc_new_message (TASK_MAC_UE, RRC_MAC_IN_SYNC_IND); - RRC_MAC_IN_SYNC_IND (message_p).frame = frameP; - RRC_MAC_IN_SYNC_IND (message_p).enb_index = eNB_index; - - itti_send_msg_to_task (TASK_RRC_UE, UE_MODULE_ID_TO_INSTANCE(Mod_idP), message_p); - } -#else - UE_rrc_inst[Mod_idP].Info[eNB_index].N310_cnt=0; - - if (UE_rrc_inst[Mod_idP].Info[eNB_index].T310_active==1) { - UE_rrc_inst[Mod_idP].Info[eNB_index].N311_cnt++; - } - -#endif -} - -//-------------------------------------------------------------------------------------------// -void rrc_out_of_sync_ind(module_id_t Mod_idP, frame_t frameP, uint16_t eNB_index) -{ - //-------------------------------------------------------------------------------------------// - if (UE_rrc_inst[Mod_idP].Info[eNB_index].N310_cnt>10) - LOG_I(RRC,"[UE %d] Frame %d: OUT OF SYNC FROM eNB %d (T310 active %d : T310 %d, N310 %d, N311 %d)\n ", - Mod_idP,frameP,eNB_index, - UE_rrc_inst[Mod_idP].Info[eNB_index].T300_active, - UE_rrc_inst[Mod_idP].Info[eNB_index].T310_cnt, - UE_rrc_inst[Mod_idP].Info[eNB_index].N310_cnt, - UE_rrc_inst[Mod_idP].Info[eNB_index].N311_cnt); - -#if defined(ENABLE_ITTI) - { - MessageDef *message_p; - - message_p = itti_alloc_new_message (TASK_MAC_UE, RRC_MAC_OUT_OF_SYNC_IND); - RRC_MAC_OUT_OF_SYNC_IND (message_p).frame = frameP; - RRC_MAC_OUT_OF_SYNC_IND (message_p).enb_index = eNB_index; - - itti_send_msg_to_task (TASK_RRC_UE, UE_MODULE_ID_TO_INSTANCE(Mod_idP), message_p); - } -#else - UE_rrc_inst[Mod_idP].Info[eNB_index].N310_cnt++; -#endif -} - //------------------------------------------------------------------------------ int mac_eNB_get_rrc_status( @@ -798,36 +450,3 @@ void mac_eNB_rrc_ul_in_sync(const module_id_t Mod_instP, frameP, subframeP, rntiP); } } -//------------------------------------------------------------------------------ -int -mac_UE_get_rrc_status( - const module_id_t Mod_idP, - const uint8_t indexP -) -//------------------------------------------------------------------------------ -{ - if (UE_rrc_inst) - return(UE_rrc_inst[Mod_idP].Info[indexP].State); - else - return(-1); -} - -//-------------------------------------------------------------------------------------------// -int mac_ue_ccch_success_ind(module_id_t Mod_idP, uint8_t eNB_index) -{ - //-------------------------------------------------------------------------------------------// -#if defined(ENABLE_ITTI) - { - MessageDef *message_p; - - message_p = itti_alloc_new_message (TASK_MAC_UE, RRC_MAC_CCCH_DATA_CNF); - RRC_MAC_CCCH_DATA_CNF (message_p).enb_index = eNB_index; - - itti_send_msg_to_task (TASK_RRC_UE, UE_MODULE_ID_TO_INSTANCE(Mod_idP), message_p); - } -#else - // reset the tx buffer to indicate RRC that ccch was successfully transmitted (for example if contention resolution succeeds) - UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size=0; -#endif - return 0; -} diff --git a/openair2/RRC/LITE/L2_interface_common.c b/openair2/RRC/LITE/L2_interface_common.c new file mode 100644 index 0000000000..1b83252152 --- /dev/null +++ b/openair2/RRC/LITE/L2_interface_common.c @@ -0,0 +1,183 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file l2_interface.c + * \brief layer 2 interface, used to support different RRC sublayer + * \author Raymond Knopp and Navid Nikaein + * \date 2010-2014 + * \version 1.0 + * \company Eurecom + * \email: raymond.knopp@eurecom.fr + */ + +#include "platform_types.h" +//#include "openair_defs.h" +//#include "openair_proto.h" +#include "defs.h" +#include "extern.h" +//#include "mac_lchan_interface.h" +//#include "openair_rrc_utils.h" +//#include "openair_rrc_main.h" +#include "UTIL/LOG/log.h" +#include "rrc_eNB_UE_context.h" +#include "pdcp.h" +#include "msc.h" +#include "common/ran_context.h" + +#ifdef PHY_EMUL +#include "SIMULATION/simulation_defs.h" +extern EMULATION_VARS *Emul_vars; +extern eNB_MAC_INST *eNB_mac_inst; +extern UE_MAC_INST *UE_mac_inst; +#endif + +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +#endif + +//#define RRC_DATA_REQ_DEBUG +//#define DEBUG_RRC 1 + +//------------------------------------------------------------------------------ +uint8_t +rrc_data_req( + const protocol_ctxt_t* const ctxt_pP, + const rb_id_t rb_idP, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_sizeP, + uint8_t* const buffer_pP, + const pdcp_transmission_mode_t modeP +) +//------------------------------------------------------------------------------ +{ + MSC_LOG_TX_MESSAGE( + ctxt_pP->enb_flag ? MSC_RRC_ENB : MSC_RRC_UE, + ctxt_pP->enb_flag ? MSC_PDCP_ENB : MSC_PDCP_UE, + buffer_pP, + sdu_sizeP, + MSC_AS_TIME_FMT"RRC_DCCH_DATA_REQ UE %x MUI %d size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ctxt_pP->rnti, + muiP, + sdu_sizeP); + +#if defined(ENABLE_ITTI) + { + MessageDef *message_p; + // Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling). + uint8_t *message_buffer; + + message_buffer = itti_malloc ( + ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, + ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, + sdu_sizeP); + + memcpy (message_buffer, buffer_pP, sdu_sizeP); + + message_p = itti_alloc_new_message (ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, RRC_DCCH_DATA_REQ); + RRC_DCCH_DATA_REQ (message_p).frame = ctxt_pP->frame; + RRC_DCCH_DATA_REQ (message_p).enb_flag = ctxt_pP->enb_flag; + RRC_DCCH_DATA_REQ (message_p).rb_id = rb_idP; + RRC_DCCH_DATA_REQ (message_p).muip = muiP; + RRC_DCCH_DATA_REQ (message_p).confirmp = confirmP; + RRC_DCCH_DATA_REQ (message_p).sdu_size = sdu_sizeP; + RRC_DCCH_DATA_REQ (message_p).sdu_p = message_buffer; + RRC_DCCH_DATA_REQ (message_p).mode = modeP; + RRC_DCCH_DATA_REQ (message_p).module_id = ctxt_pP->module_id; + RRC_DCCH_DATA_REQ (message_p).rnti = ctxt_pP->rnti; + RRC_DCCH_DATA_REQ (message_p).eNB_index = ctxt_pP->eNB_index; + + itti_send_msg_to_task ( + ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, + ctxt_pP->instance, + message_p); + return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. + + } +#else + return pdcp_data_req ( + ctxt_pP, + SRB_FLAG_YES, + rb_idP, + muiP, + confirmP, + sdu_sizeP, + buffer_pP, + modeP); +#endif +} + +//------------------------------------------------------------------------------ +void +rrc_data_ind( + const protocol_ctxt_t* const ctxt_pP, + const rb_id_t Srb_id, + const sdu_size_t sdu_sizeP, + const uint8_t* const buffer_pP +) +//------------------------------------------------------------------------------ +{ + rb_id_t DCCH_index = Srb_id; + + if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + LOG_N(RRC, "[UE %x] Frame %d: received a DCCH %d message on SRB %d with Size %d from eNB %d\n", + ctxt_pP->module_id, ctxt_pP->frame, DCCH_index,Srb_id,sdu_sizeP, ctxt_pP->eNB_index); + } else { + LOG_N(RRC, "[eNB %d] Frame %d: received a DCCH %d message on SRB %d with Size %d from UE %x\n", + ctxt_pP->module_id, + ctxt_pP->frame, + DCCH_index, + Srb_id, + sdu_sizeP, + ctxt_pP->rnti); + } + +#if defined(ENABLE_ITTI) + { + MessageDef *message_p; + // Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling). + uint8_t *message_buffer; + + message_buffer = itti_malloc (ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, sdu_sizeP); + memcpy (message_buffer, buffer_pP, sdu_sizeP); + + message_p = itti_alloc_new_message (ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, RRC_DCCH_DATA_IND); + RRC_DCCH_DATA_IND (message_p).frame = ctxt_pP->frame; + RRC_DCCH_DATA_IND (message_p).dcch_index = DCCH_index; + RRC_DCCH_DATA_IND (message_p).sdu_size = sdu_sizeP; + RRC_DCCH_DATA_IND (message_p).sdu_p = message_buffer; + RRC_DCCH_DATA_IND (message_p).rnti = ctxt_pP->rnti; + RRC_DCCH_DATA_IND (message_p).module_id = ctxt_pP->module_id; + RRC_DCCH_DATA_IND (message_p).eNB_index = ctxt_pP->eNB_index; + + itti_send_msg_to_task (ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, ctxt_pP->instance, message_p); + } +#else + + rrc_eNB_decode_dcch( + ctxt_pP, + DCCH_index, + buffer_pP, + sdu_sizeP); + +#endif +} diff --git a/openair2/RRC/LITE/L2_interface_ue.c b/openair2/RRC/LITE/L2_interface_ue.c new file mode 100644 index 0000000000..7bdbe2523e --- /dev/null +++ b/openair2/RRC/LITE/L2_interface_ue.c @@ -0,0 +1,463 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file l2_interface.c + * \brief layer 2 interface, used to support different RRC sublayer + * \author Raymond Knopp and Navid Nikaein + * \date 2010-2014 + * \version 1.0 + * \company Eurecom + * \email: raymond.knopp@eurecom.fr + */ + +#include "platform_types.h" +//#include "openair_defs.h" +//#include "openair_proto.h" +#include "defs.h" +#include "extern.h" +//#include "mac_lchan_interface.h" +//#include "openair_rrc_utils.h" +//#include "openair_rrc_main.h" +#include "UTIL/LOG/log.h" +#include "rrc_eNB_UE_context.h" +#include "pdcp.h" +#include "msc.h" + + +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +#endif + +//#define RRC_DATA_REQ_DEBUG +//#define DEBUG_RRC 1 + + + +//------------------------------------------------------------------------------ +int8_t +mac_rrc_data_req_ue( + const module_id_t Mod_idP, + const int CC_id, + const frame_t frameP, + const rb_id_t Srb_id, + const uint8_t Nb_tb, + uint8_t* const buffer_pP, + const uint8_t eNB_index, + const uint8_t mbsfn_sync_area +) +//-------------------------------------------------------------------------- +{ + asn_enc_rval_t enc_rval; + SRB_INFO *Srb_info; + uint8_t Sdu_size = 0; + uint8_t sfn = (uint8_t)((frameP>>2)&0xff); + + +#ifdef DEBUG_RRC + int i; + LOG_I(RRC,"[eNB %d] mac_rrc_data_req to SRB ID=%d\n",Mod_idP,Srb_id); +#endif + + eNB_RRC_INST *rrc; + rrc_eNB_carrier_data_t *carrier; + BCCH_BCH_Message_t *mib; + + + LOG_D(RRC,"[UE %d] Frame %d Filling CCCH SRB_ID %d\n",Mod_idP,frameP,Srb_id); + LOG_D(RRC,"[UE %d] Frame %d buffer_pP status %d,\n",Mod_idP,frameP, UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size); + + + if( (UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size > 0) ) { + +#if defined(ENABLE_ITTI) + { + MessageDef *message_p; + int ccch_size = UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size; + int sdu_size = sizeof(RRC_MAC_CCCH_DATA_REQ (message_p).sdu); + + if (ccch_size > sdu_size) { + LOG_E(RRC, "SDU larger than CCCH SDU buffer size (%d, %d)", ccch_size, sdu_size); + ccch_size = sdu_size; + } + + message_p = itti_alloc_new_message (TASK_RRC_UE, RRC_MAC_CCCH_DATA_REQ); + RRC_MAC_CCCH_DATA_REQ (message_p).frame = frameP; + RRC_MAC_CCCH_DATA_REQ (message_p).sdu_size = ccch_size; + memset (RRC_MAC_CCCH_DATA_REQ (message_p).sdu, 0, CCCH_SDU_SIZE); + memcpy (RRC_MAC_CCCH_DATA_REQ (message_p).sdu, UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.Payload, ccch_size); + RRC_MAC_CCCH_DATA_REQ (message_p).enb_index = eNB_index; + + itti_send_msg_to_task (TASK_MAC_UE, UE_MODULE_ID_TO_INSTANCE(Mod_idP), message_p); + } +#endif + + memcpy(&buffer_pP[0],&UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.Payload[0],UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size); + uint8_t Ret_size=UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size; + // UE_rrc_inst[Mod_id].Srb0[eNB_index].Tx_buffer.payload_size=0; + UE_rrc_inst[Mod_idP].Info[eNB_index].T300_active = 1; + UE_rrc_inst[Mod_idP].Info[eNB_index].T300_cnt = 0; + // msg("[RRC][UE %d] Sending rach\n",Mod_id); + return(Ret_size); + } else { + return 0; + } + + return(0); +} + +//------------------------------------------------------------------------------ +int8_t +mac_rrc_data_ind_ue( + const module_id_t module_idP, + const int CC_id, + const frame_t frameP, + const sub_frame_t sub_frameP, + const rnti_t rntiP, + const rb_id_t srb_idP, + const uint8_t* sduP, + const sdu_size_t sdu_lenP, + const mac_enb_index_t eNB_indexP, + const uint8_t mbsfn_sync_areaP +) +//-------------------------------------------------------------------------- +{ + SRB_INFO *Srb_info; + protocol_ctxt_t ctxt; + sdu_size_t sdu_size = 0; + + /* for no gcc warnings */ + (void)sdu_size; + + /* + int si_window; + */ + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, 0, rntiP, frameP, sub_frameP,eNB_indexP); + + if(srb_idP == BCCH) { + LOG_D(RRC,"[UE %d] Received SDU for BCCH on SRB %d from eNB %d\n",module_idP,srb_idP,eNB_indexP); + +#if defined(ENABLE_ITTI) + { + MessageDef *message_p; + int msg_sdu_size = sizeof(RRC_MAC_BCCH_DATA_IND (message_p).sdu); + + if (sdu_lenP > msg_sdu_size) { + LOG_E(RRC, "SDU larger than BCCH SDU buffer size (%d, %d)", sdu_lenP, msg_sdu_size); + sdu_size = msg_sdu_size; + } else { + sdu_size = sdu_lenP; + } + + message_p = itti_alloc_new_message (TASK_MAC_UE, RRC_MAC_BCCH_DATA_IND); + memset (RRC_MAC_BCCH_DATA_IND (message_p).sdu, 0, BCCH_SDU_SIZE); + RRC_MAC_BCCH_DATA_IND (message_p).frame = frameP; + RRC_MAC_BCCH_DATA_IND (message_p).sub_frame = sub_frameP; + RRC_MAC_BCCH_DATA_IND (message_p).sdu_size = sdu_size; + memcpy (RRC_MAC_BCCH_DATA_IND (message_p).sdu, sduP, sdu_size); + RRC_MAC_BCCH_DATA_IND (message_p).enb_index = eNB_indexP; + RRC_MAC_BCCH_DATA_IND (message_p).rsrq = 30 /* TODO change phy to report rspq */; + RRC_MAC_BCCH_DATA_IND (message_p).rsrp = 45 /* TODO change phy to report rspp */; + + itti_send_msg_to_task (TASK_RRC_UE, ctxt.instance, message_p); + } +#else + decode_BCCH_DLSCH_Message(&ctxt,eNB_indexP,(uint8_t*)sduP,sdu_lenP, 0, 0); +#endif + } + + if(srb_idP == PCCH) { + LOG_D(RRC,"[UE %d] Received SDU for PCCH on SRB %d from eNB %d\n",module_idP,srb_idP,eNB_indexP); + decode_PCCH_DLSCH_Message(&ctxt,eNB_indexP,(uint8_t*)sduP,sdu_lenP); + } + if((srb_idP & RAB_OFFSET) == CCCH) { + if (sdu_lenP>0) { + LOG_T(RRC,"[UE %d] Received SDU for CCCH on SRB %d from eNB %d\n",module_idP,srb_idP & RAB_OFFSET,eNB_indexP); + +#if defined(ENABLE_ITTI) + { + MessageDef *message_p; + int msg_sdu_size = CCCH_SDU_SIZE; + + if (sdu_lenP > msg_sdu_size) { + LOG_E(RRC, "SDU larger than CCCH SDU buffer size (%d, %d)", sdu_size, msg_sdu_size); + sdu_size = msg_sdu_size; + } else { + sdu_size = sdu_lenP; + } + + message_p = itti_alloc_new_message (TASK_MAC_UE, RRC_MAC_CCCH_DATA_IND); + memset (RRC_MAC_CCCH_DATA_IND (message_p).sdu, 0, CCCH_SDU_SIZE); + memcpy (RRC_MAC_CCCH_DATA_IND (message_p).sdu, sduP, sdu_size); + RRC_MAC_CCCH_DATA_IND (message_p).frame = frameP; + RRC_MAC_CCCH_DATA_IND (message_p).sub_frame = sub_frameP; + RRC_MAC_CCCH_DATA_IND (message_p).sdu_size = sdu_size; + RRC_MAC_CCCH_DATA_IND (message_p).enb_index = eNB_indexP; + RRC_MAC_CCCH_DATA_IND (message_p).rnti = rntiP; + itti_send_msg_to_task (TASK_RRC_UE, ctxt.instance, message_p); + } +#else + Srb_info = &UE_rrc_inst[module_idP].Srb0[eNB_indexP]; + memcpy(Srb_info->Rx_buffer.Payload,sduP,sdu_lenP); + Srb_info->Rx_buffer.payload_size = sdu_lenP; + rrc_ue_decode_ccch(&ctxt, Srb_info, eNB_indexP); +#endif + } + } + +#if defined(Rel10) || defined(Rel14) + + if ((srb_idP & RAB_OFFSET) == MCCH) { + LOG_T(RRC,"[UE %d] Frame %d: Received SDU on MBSFN sync area %d for MCCH on SRB %d from eNB %d\n", + module_idP,frameP, mbsfn_sync_areaP, srb_idP & RAB_OFFSET,eNB_indexP); + +#if defined(ENABLE_ITTI) + { + MessageDef *message_p; + int msg_sdu_size = sizeof(RRC_MAC_MCCH_DATA_IND (message_p).sdu); + + if (sdu_size > msg_sdu_size) { + LOG_E(RRC, "SDU larger than MCCH SDU buffer size (%d, %d)", sdu_size, msg_sdu_size); + sdu_size = msg_sdu_size; + } + + message_p = itti_alloc_new_message (TASK_MAC_UE, RRC_MAC_MCCH_DATA_IND); + RRC_MAC_MCCH_DATA_IND (message_p).frame = frameP; + RRC_MAC_MCCH_DATA_IND (message_p).sub_frame = sub_frameP; + RRC_MAC_MCCH_DATA_IND (message_p).sdu_size = sdu_lenP; + memset (RRC_MAC_MCCH_DATA_IND (message_p).sdu, 0, MCCH_SDU_SIZE); + memcpy (RRC_MAC_MCCH_DATA_IND (message_p).sdu, sduP, sdu_lenP); + RRC_MAC_MCCH_DATA_IND (message_p).enb_index = eNB_indexP; + RRC_MAC_MCCH_DATA_IND (message_p).mbsfn_sync_area = mbsfn_sync_areaP; + itti_send_msg_to_task (TASK_RRC_UE, ctxt.instance, message_p); + } +#else + decode_MCCH_Message(&ctxt, eNB_indexP, sduP, sdu_lenP, mbsfn_sync_areaP); +#endif + } + +#endif // Rel10 || Rel14 + + return(0); + +} + + +//------------------------------------------------------------------------------ +uint8_t +rrc_data_req_ue( + const protocol_ctxt_t* const ctxt_pP, + const rb_id_t rb_idP, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_sizeP, + uint8_t* const buffer_pP, + const pdcp_transmission_mode_t modeP +) +//------------------------------------------------------------------------------ +{ + MSC_LOG_TX_MESSAGE( + ctxt_pP->enb_flag ? MSC_RRC_ENB : MSC_RRC_UE, + ctxt_pP->enb_flag ? MSC_PDCP_ENB : MSC_PDCP_UE, + buffer_pP, + sdu_sizeP, + MSC_AS_TIME_FMT"RRC_DCCH_DATA_REQ UE %x MUI %d size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ctxt_pP->rnti, + muiP, + sdu_sizeP); + +#if defined(ENABLE_ITTI) + { + MessageDef *message_p; + // Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling). + uint8_t *message_buffer; + + message_buffer = itti_malloc ( + ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, + ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, + sdu_sizeP); + + memcpy (message_buffer, buffer_pP, sdu_sizeP); + + message_p = itti_alloc_new_message (ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, RRC_DCCH_DATA_REQ); + RRC_DCCH_DATA_REQ (message_p).frame = ctxt_pP->frame; + RRC_DCCH_DATA_REQ (message_p).enb_flag = ctxt_pP->enb_flag; + RRC_DCCH_DATA_REQ (message_p).rb_id = rb_idP; + RRC_DCCH_DATA_REQ (message_p).muip = muiP; + RRC_DCCH_DATA_REQ (message_p).confirmp = confirmP; + RRC_DCCH_DATA_REQ (message_p).sdu_size = sdu_sizeP; + RRC_DCCH_DATA_REQ (message_p).sdu_p = message_buffer; + RRC_DCCH_DATA_REQ (message_p).mode = modeP; + RRC_DCCH_DATA_REQ (message_p).module_id = ctxt_pP->module_id; + RRC_DCCH_DATA_REQ (message_p).rnti = ctxt_pP->rnti; + RRC_DCCH_DATA_REQ (message_p).eNB_index = ctxt_pP->eNB_index; + + itti_send_msg_to_task ( + TASK_PDCP_UE, + ctxt_pP->instance, + message_p); + return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. + + } +#else + return pdcp_data_req ( + ctxt_pP, + SRB_FLAG_YES, + rb_idP, + muiP, + confirmP, + sdu_sizeP, + buffer_pP, + modeP); +#endif +} + +//------------------------------------------------------------------------------ +void +rrc_data_ind_ue( + const protocol_ctxt_t* const ctxt_pP, + const rb_id_t Srb_id, + const sdu_size_t sdu_sizeP, + const uint8_t* const buffer_pP +) +//------------------------------------------------------------------------------ +{ + rb_id_t DCCH_index = Srb_id; + + LOG_N(RRC, "[UE %x] Frame %d: received a DCCH %d message on SRB %d with Size %d from eNB %d\n", + ctxt_pP->module_id, ctxt_pP->frame, DCCH_index,Srb_id,sdu_sizeP, ctxt_pP->eNB_index); + +#if defined(ENABLE_ITTI) + { + MessageDef *message_p; + // Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling). + uint8_t *message_buffer; + + message_buffer = itti_malloc (ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, ctxt_pP->enb_flag ? TASK_RRC_ENB : TASK_RRC_UE, sdu_sizeP); + memcpy (message_buffer, buffer_pP, sdu_sizeP); + + message_p = itti_alloc_new_message (ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, RRC_DCCH_DATA_IND); + RRC_DCCH_DATA_IND (message_p).frame = ctxt_pP->frame; + RRC_DCCH_DATA_IND (message_p).dcch_index = DCCH_index; + RRC_DCCH_DATA_IND (message_p).sdu_size = sdu_sizeP; + RRC_DCCH_DATA_IND (message_p).sdu_p = message_buffer; + RRC_DCCH_DATA_IND (message_p).rnti = ctxt_pP->rnti; + RRC_DCCH_DATA_IND (message_p).module_id = ctxt_pP->module_id; + RRC_DCCH_DATA_IND (message_p).eNB_index = ctxt_pP->eNB_index; + + itti_send_msg_to_task (TASK_RRC_UE, ctxt_pP->instance, message_p); + } +#else + +//#warning "LG put 0 to arg4 that is eNB index" + rrc_ue_decode_dcch( + ctxt_pP, + DCCH_index, + buffer_pP, + 0); + +#endif +} + +//-------------------------------------------------------------------------------------------// +void rrc_in_sync_ind(module_id_t Mod_idP, frame_t frameP, uint16_t eNB_index) +{ + //-------------------------------------------------------------------------------------------// +#if defined(ENABLE_ITTI) + { + MessageDef *message_p; + //LOG_I(RRC,"sending a message to task_mac_ue\n"); + message_p = itti_alloc_new_message (TASK_MAC_UE, RRC_MAC_IN_SYNC_IND); + RRC_MAC_IN_SYNC_IND (message_p).frame = frameP; + RRC_MAC_IN_SYNC_IND (message_p).enb_index = eNB_index; + + itti_send_msg_to_task (TASK_RRC_UE, UE_MODULE_ID_TO_INSTANCE(Mod_idP), message_p); + } +#else + UE_rrc_inst[Mod_idP].Info[eNB_index].N310_cnt=0; + + if (UE_rrc_inst[Mod_idP].Info[eNB_index].T310_active==1) { + UE_rrc_inst[Mod_idP].Info[eNB_index].N311_cnt++; + } + +#endif +} + +//-------------------------------------------------------------------------------------------// +void rrc_out_of_sync_ind(module_id_t Mod_idP, frame_t frameP, uint16_t eNB_index) +{ + //-------------------------------------------------------------------------------------------// + if (UE_rrc_inst[Mod_idP].Info[eNB_index].N310_cnt>10) + LOG_I(RRC,"[UE %d] Frame %d: OUT OF SYNC FROM eNB %d (T310 active %d : T310 %d, N310 %d, N311 %d)\n ", + Mod_idP,frameP,eNB_index, + UE_rrc_inst[Mod_idP].Info[eNB_index].T300_active, + UE_rrc_inst[Mod_idP].Info[eNB_index].T310_cnt, + UE_rrc_inst[Mod_idP].Info[eNB_index].N310_cnt, + UE_rrc_inst[Mod_idP].Info[eNB_index].N311_cnt); + +#if defined(ENABLE_ITTI) + { + MessageDef *message_p; + + message_p = itti_alloc_new_message (TASK_MAC_UE, RRC_MAC_OUT_OF_SYNC_IND); + RRC_MAC_OUT_OF_SYNC_IND (message_p).frame = frameP; + RRC_MAC_OUT_OF_SYNC_IND (message_p).enb_index = eNB_index; + + itti_send_msg_to_task (TASK_RRC_UE, UE_MODULE_ID_TO_INSTANCE(Mod_idP), message_p); + } +#else + UE_rrc_inst[Mod_idP].Info[eNB_index].N310_cnt++; +#endif +} + +//------------------------------------------------------------------------------ +int +mac_UE_get_rrc_status( + const module_id_t Mod_idP, + const uint8_t indexP +) +//------------------------------------------------------------------------------ +{ + if (UE_rrc_inst) + return(UE_rrc_inst[Mod_idP].Info[indexP].State); + else + return(-1); +} + +//-------------------------------------------------------------------------------------------// +int mac_ue_ccch_success_ind(module_id_t Mod_idP, uint8_t eNB_index) +{ + //-------------------------------------------------------------------------------------------// +#if defined(ENABLE_ITTI) + { + MessageDef *message_p; + + message_p = itti_alloc_new_message (TASK_MAC_UE, RRC_MAC_CCCH_DATA_CNF); + RRC_MAC_CCCH_DATA_CNF (message_p).enb_index = eNB_index; + + itti_send_msg_to_task (TASK_RRC_UE, UE_MODULE_ID_TO_INSTANCE(Mod_idP), message_p); + } +#else + // reset the tx buffer to indicate RRC that ccch was successfully transmitted (for example if contention resolution succeeds) + UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size=0; +#endif + return 0; +} diff --git a/openair2/RRC/LITE/proto.h b/openair2/RRC/LITE/proto.h index b3d5beb292..68dc5aff16 100644 --- a/openair2/RRC/LITE/proto.h +++ b/openair2/RRC/LITE/proto.h @@ -54,15 +54,30 @@ void rrc_config_buffer(SRB_INFO *srb_info, uint8_t Lchan_type, uint8_t Role); void openair_rrc_on( const protocol_ctxt_t* const ctxt_pP); +void +openair_rrc_on_ue( + const protocol_ctxt_t* const ctxt_pP); + void rrc_top_cleanup(void); +/** \brief Function to update eNB timers every subframe. +@param ctxt_pP running context +@param enb_index +@param CC_id +*/ +RRC_status_t +rrc_rx_tx( + protocol_ctxt_t* const ctxt_pP, + const int CC_id +); + /** \brief Function to update timers every subframe. For UE it updates T300,T304 and T310. @param ctxt_pP running context @param enb_index @param CC_id */ RRC_status_t -rrc_rx_tx( +rrc_rx_tx_ue( protocol_ctxt_t* const ctxt_pP, const uint8_t enb_index, const int CC_id @@ -296,8 +311,6 @@ mac_rrc_data_req( const rb_id_t Srb_id, const uint8_t Nb_tb, uint8_t* const buffer_pP, - const eNB_flag_t enb_flagP, - const uint8_t eNB_index, const uint8_t mbsfn_sync_area ); @@ -311,7 +324,31 @@ mac_rrc_data_ind( const rb_id_t srb_idP, const uint8_t* sduP, const sdu_size_t sdu_lenP, - const eNB_flag_t eNB_flagP, + const uint8_t mbsfn_sync_areaP +); + +int8_t +mac_rrc_data_req_ue( + const module_id_t Mod_idP, + const int CC_id, + const frame_t frameP, + const rb_id_t Srb_id, + const uint8_t Nb_tb, + uint8_t* const buffer_pP, + const mac_enb_index_t eNB_indexP, + const uint8_t mbsfn_sync_area +); + +int8_t +mac_rrc_data_ind_ue( + const module_id_t module_idP, + const int CC_id, + const frame_t frameP, + const sub_frame_t sub_frameP, + const rnti_t rntiP, + const rb_id_t srb_idP, + const uint8_t* sduP, + const sdu_size_t sdu_lenP, const mac_enb_index_t eNB_indexP, const uint8_t mbsfn_sync_areaP ); diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index 67159fa248..3ec73d29e9 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -239,6 +239,30 @@ static int rrc_set_sub_state( module_id_t ue_mod_idP, Rrc_Sub_State_t subState ) return (0); } +//----------------------------------------------------------------------------- +void +openair_rrc_on_ue( + const protocol_ctxt_t* const ctxt_pP +) +//----------------------------------------------------------------------------- +{ + unsigned short i; + int CC_id; + + LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" UE?:OPENAIR RRC IN....\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); + + for (i = 0; i < NB_eNB_INST; i++) { + LOG_D(RRC, PROTOCOL_RRC_CTXT_FMT" Activating CCCH (eNB %d)\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), i); + UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Srb_id = CCCH; + memcpy (&UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Lchan_desc[0], &CCCH_LCHAN_DESC, LCHAN_DESC_SIZE); + memcpy (&UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Lchan_desc[1], &CCCH_LCHAN_DESC, LCHAN_DESC_SIZE); + rrc_config_buffer (&UE_rrc_inst[ctxt_pP->module_id].Srb0[i], CCCH, 1); + UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Active = 1; + } +} + //----------------------------------------------------------------------------- static void init_SI_UE( const protocol_ctxt_t* const ctxt_pP, const uint8_t eNB_index ) { @@ -345,7 +369,7 @@ char openair_rrc_ue_init( const module_id_t ue_mod_idP, const unsigned char eNB_ #endif #ifdef NO_RRM //init ch SRB0, SRB1 & BDTCH - openair_rrc_on(&ctxt); + openair_rrc_on_ue(&ctxt); #endif #ifdef CBA int j; @@ -436,6 +460,47 @@ static const char const nas_attach_req_guti[] = { }; #endif +//----------------------------------------------------------------------------- +void +rrc_t310_expiration( + const protocol_ctxt_t* const ctxt_pP, + const uint8_t eNB_index +) +//----------------------------------------------------------------------------- +{ + + if (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State != RRC_CONNECTED) { + LOG_D(RRC, "Timer 310 expired, going to RRC_IDLE\n"); + UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State = RRC_IDLE; + UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].UE_index = 0xffff; + UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Rx_buffer.payload_size = 0; + UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Tx_buffer.payload_size = 0; + UE_rrc_inst[ctxt_pP->module_id].Srb1[eNB_index].Srb_info.Rx_buffer.payload_size = 0; + UE_rrc_inst[ctxt_pP->module_id].Srb1[eNB_index].Srb_info.Tx_buffer.payload_size = 0; + + if (UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Active == 1) { + LOG_D (RRC,"[Inst %d] eNB_index %d, Remove RB %d\n ", ctxt_pP->module_id, eNB_index, + UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Srb_info.Srb_id); + rrc_pdcp_config_req (ctxt_pP, + SRB_FLAG_YES, + CONFIG_ACTION_REMOVE, + UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Srb_info.Srb_id, + 0); + rrc_rlc_config_req (ctxt_pP, + SRB_FLAG_YES, + MBMS_FLAG_NO, + CONFIG_ACTION_REMOVE, + UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Srb_info.Srb_id, + Rlc_info_um); + UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Active = 0; + UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Status = IDLE; + UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Next_check_frame = 0; + } + } else { // Restablishment procedure + LOG_D(RRC, "Timer 310 expired, trying RRCRestablishment ...\n"); + } +} + //----------------------------------------------------------------------------- static void rrc_ue_generate_RRCConnectionSetupComplete( const protocol_ctxt_t* const ctxt_pP, const uint8_t eNB_index, const uint8_t Transaction_id ) { @@ -460,7 +525,7 @@ static void rrc_ue_generate_RRCConnectionSetupComplete( const protocol_ctxt_t* c LOG_D(RLC, "[FRAME %05d][RRC_UE][MOD %02d][][--- PDCP_DATA_REQ/%d Bytes (RRCConnectionSetupComplete to eNB %d MUI %d) --->][PDCP][MOD %02d][RB %02d]\n", ctxt_pP->frame, ctxt_pP->module_id+NB_eNB_INST, size, eNB_index, rrc_mui, ctxt_pP->module_id+NB_eNB_INST, DCCH); - rrc_data_req ( + rrc_data_req_ue ( ctxt_pP, DCCH, rrc_mui++, @@ -487,7 +552,7 @@ static void rrc_ue_generate_RRCConnectionReconfigurationComplete( const protocol rrc_mui, UE_MODULE_ID_TO_INSTANCE(ctxt_pP->module_id), DCCH); - rrc_data_req ( + rrc_data_req_ue ( ctxt_pP, DCCH, rrc_mui++, @@ -1737,7 +1802,7 @@ rrc_ue_process_securityModeCommand( } LOG_T(RRC, "\n"); - rrc_data_req ( + rrc_data_req_ue ( ctxt_pP, DCCH, rrc_mui++, @@ -1849,7 +1914,7 @@ rrc_ue_process_ueCapabilityEnquiry( } LOG_T(RRC, "\n"); - rrc_data_req ( + rrc_data_req_ue ( ctxt_pP, DCCH, rrc_mui++, @@ -4543,7 +4608,7 @@ void *rrc_ue_task( void *args_p ) // check if SRB2 is created, if yes request data_req on DCCH1 (SRB2) if(UE_rrc_inst[ue_mod_id].SRB2_config[0] == NULL) { - rrc_data_req (&ctxt, + rrc_data_req_ue (&ctxt, DCCH, rrc_mui++, SDU_CONFIRM_NO, @@ -4552,7 +4617,7 @@ void *rrc_ue_task( void *args_p ) } else { - rrc_data_req (&ctxt, + rrc_data_req_ue (&ctxt, DCCH1, rrc_mui++, SDU_CONFIRM_NO, @@ -4795,3 +4860,121 @@ rrc_top_cleanup_ue( } + + +//----------------------------------------------------------------------------- +RRC_status_t +rrc_rx_tx_ue( + protocol_ctxt_t* const ctxt_pP, + const uint8_t enb_indexP, + const int CC_id +) +//----------------------------------------------------------------------------- +{ + //uint8_t UE_id; + int32_t current_timestamp_ms, ref_timestamp_ms; + struct timeval ts; + struct rrc_eNB_ue_context_s *ue_context_p = NULL,*ue_to_be_removed = NULL; + +#ifdef LOCALIZATION + double estimated_distance; + protocol_ctxt_t ctxt; +#endif + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_IN); + + // check timers + + if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_active == 1) { + if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt % 10) == 0) + LOG_D(RRC, + "[UE %d][RAPROC] Frame %d T300 Count %d ms\n", ctxt_pP->module_id, ctxt_pP->frame, UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt); + + if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt + == T300[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.t300]) { + UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_active = 0; + // ALLOW CCCH to be used + UE_rrc_inst[ctxt_pP->module_id].Srb0[enb_indexP].Tx_buffer.payload_size = 0; + rrc_ue_generate_RRCConnectionRequest (ctxt_pP, enb_indexP); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT); + return (RRC_ConnSetup_failed); + } + + UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt++; + } + + if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].SIStatus&2)>0) { + if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N310_cnt + == N310[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.n310]) { + LOG_I(RRC,"Activating T310\n"); + UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active = 1; + } + } else { // in case we have not received SIB2 yet + /* if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N310_cnt == 100) { + UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N310_cnt = 0; + + }*/ + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT); + return RRC_OK; + } + + if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active == 1) { + if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N311_cnt + == N311[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.n311]) { + UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active = 0; + UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N311_cnt = 0; + } + + if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt % 10) == 0) { + LOG_D(RRC, "[UE %d] Frame %d T310 Count %d ms\n", ctxt_pP->module_id, ctxt_pP->frame, UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt); + } + + if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt == T310[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.t310]) { + UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active = 0; + rrc_t310_expiration (ctxt_pP, enb_indexP); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT); + LOG_I(RRC,"Returning RRC_PHY_RESYNCH: T310 expired\n"); + return RRC_PHY_RESYNCH; + } + + UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt++; + } + + if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_active==1) { + if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt % 10) == 0) + LOG_D(RRC,"[UE %d][RAPROC] Frame %d T304 Count %d ms\n",ctxt_pP->module_id,ctxt_pP->frame, + UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt); + + if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt == 0) { + UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_active = 0; + UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.measFlag = 1; + LOG_E(RRC,"[UE %d] Handover failure..initiating connection re-establishment procedure... \n", + ctxt_pP->module_id); + //Implement 36.331, section 5.3.5.6 here + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT); + return(RRC_Handover_failed); + } + + UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt--; + } + + // Layer 3 filtering of RRC measurements + if (UE_rrc_inst[ctxt_pP->module_id].QuantityConfig[0] != NULL) { + ue_meas_filtering(ctxt_pP,enb_indexP); + } + + ue_measurement_report_triggering(ctxt_pP,enb_indexP); + + if (UE_rrc_inst[ctxt_pP->module_id].Info[0].handoverTarget > 0) { + LOG_I(RRC,"[UE %d] Frame %d : RRC handover initiated\n", ctxt_pP->module_id, ctxt_pP->frame); + } + + if((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].State == RRC_HO_EXECUTION) && + (UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.targetCellId != 0xFF)) { + UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].State= RRC_IDLE; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT); + return(RRC_HO_STARTED); + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT); + return (RRC_OK); +} diff --git a/openair2/RRC/LITE/rrc_common.c b/openair2/RRC/LITE/rrc_common.c index 65e1a25b17..46d2b33fb8 100644 --- a/openair2/RRC/LITE/rrc_common.c +++ b/openair2/RRC/LITE/rrc_common.c @@ -53,42 +53,6 @@ extern UE_MAC_INST *UE_mac_inst; extern mui_t rrc_eNB_mui; -//configure BCCH & CCCH Logical Channels and associated rrc_buffers, configure associated SRBs -//----------------------------------------------------------------------------- -void -openair_rrc_on( - const protocol_ctxt_t* const ctxt_pP -) -//----------------------------------------------------------------------------- -{ - unsigned short i; - int CC_id; - - if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" ENB:OPENAIR RRC IN....\n", - PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - rrc_config_buffer (&RC.rrc[ctxt_pP->module_id]->carrier[CC_id].SI, BCCH, 1); - RC.rrc[ctxt_pP->module_id]->carrier[CC_id].SI.Active = 1; - rrc_config_buffer (&RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0, CCCH, 1); - RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Active = 1; - } - } else { - LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" UE?:OPENAIR RRC IN....\n", - PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); - - for (i = 0; i < NB_eNB_INST; i++) { - LOG_D(RRC, PROTOCOL_RRC_CTXT_FMT" Activating CCCH (eNB %d)\n", - PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), i); - UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Srb_id = CCCH; - memcpy (&UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Lchan_desc[0], &CCCH_LCHAN_DESC, LCHAN_DESC_SIZE); - memcpy (&UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Lchan_desc[1], &CCCH_LCHAN_DESC, LCHAN_DESC_SIZE); - rrc_config_buffer (&UE_rrc_inst[ctxt_pP->module_id].Srb0[i], CCCH, 1); - UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Active = 1; - } - } -} - //----------------------------------------------------------------------------- int rrc_init_global_param( @@ -170,241 +134,6 @@ rrc_config_buffer( } -//----------------------------------------------------------------------------- -void -rrc_t310_expiration( - const protocol_ctxt_t* const ctxt_pP, - const uint8_t eNB_index -) -//----------------------------------------------------------------------------- -{ - - if (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State != RRC_CONNECTED) { - LOG_D(RRC, "Timer 310 expired, going to RRC_IDLE\n"); - UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State = RRC_IDLE; - UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].UE_index = 0xffff; - UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Rx_buffer.payload_size = 0; - UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Tx_buffer.payload_size = 0; - UE_rrc_inst[ctxt_pP->module_id].Srb1[eNB_index].Srb_info.Rx_buffer.payload_size = 0; - UE_rrc_inst[ctxt_pP->module_id].Srb1[eNB_index].Srb_info.Tx_buffer.payload_size = 0; - - if (UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Active == 1) { - msg ("[RRC Inst %d] eNB_index %d, Remove RB %d\n ", ctxt_pP->module_id, eNB_index, - UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Srb_info.Srb_id); - rrc_pdcp_config_req (ctxt_pP, - SRB_FLAG_YES, - CONFIG_ACTION_REMOVE, - UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Srb_info.Srb_id, - 0); - rrc_rlc_config_req (ctxt_pP, - SRB_FLAG_YES, - MBMS_FLAG_NO, - CONFIG_ACTION_REMOVE, - UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Srb_info.Srb_id, - Rlc_info_um); - UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Active = 0; - UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Status = IDLE; - UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Next_check_frame = 0; - } - } else { // Restablishment procedure - LOG_D(RRC, "Timer 310 expired, trying RRCRestablishment ...\n"); - } -} - -//----------------------------------------------------------------------------- -RRC_status_t -rrc_rx_tx( - protocol_ctxt_t* const ctxt_pP, - const uint8_t enb_indexP, - const int CC_id -) -//----------------------------------------------------------------------------- -{ - //uint8_t UE_id; - int32_t current_timestamp_ms, ref_timestamp_ms; - struct timeval ts; - struct rrc_eNB_ue_context_s *ue_context_p = NULL,*ue_to_be_removed = NULL; - -#ifdef LOCALIZATION - double estimated_distance; - protocol_ctxt_t ctxt; -#endif - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_IN); - - if(ctxt_pP->enb_flag == ENB_FLAG_NO) { - // check timers - - if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_active == 1) { - if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt % 10) == 0) - LOG_D(RRC, - "[UE %d][RAPROC] Frame %d T300 Count %d ms\n", ctxt_pP->module_id, ctxt_pP->frame, UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt); - - if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt - == T300[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.t300]) { - UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_active = 0; - // ALLOW CCCH to be used - UE_rrc_inst[ctxt_pP->module_id].Srb0[enb_indexP].Tx_buffer.payload_size = 0; - rrc_ue_generate_RRCConnectionRequest (ctxt_pP, enb_indexP); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT); - return (RRC_ConnSetup_failed); - } - - UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt++; - } - - if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].SIStatus&2)>0) { - if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N310_cnt - == N310[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.n310]) { - LOG_I(RRC,"Activating T310\n"); - UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active = 1; - } - } else { // in case we have not received SIB2 yet - /* if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N310_cnt == 100) { - UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N310_cnt = 0; - - }*/ - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT); - return RRC_OK; - } - - if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active == 1) { - if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N311_cnt - == N311[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.n311]) { - UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active = 0; - UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N311_cnt = 0; - } - - if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt % 10) == 0) { - LOG_D(RRC, "[UE %d] Frame %d T310 Count %d ms\n", ctxt_pP->module_id, ctxt_pP->frame, UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt); - } - - if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt == T310[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.t310]) { - UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active = 0; - rrc_t310_expiration (ctxt_pP, enb_indexP); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT); - LOG_I(RRC,"Returning RRC_PHY_RESYNCH: T310 expired\n"); - return RRC_PHY_RESYNCH; - } - - UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt++; - } - - if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_active==1) { - if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt % 10) == 0) - LOG_D(RRC,"[UE %d][RAPROC] Frame %d T304 Count %d ms\n",ctxt_pP->module_id,ctxt_pP->frame, - UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt); - - if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt == 0) { - UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_active = 0; - UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.measFlag = 1; - LOG_E(RRC,"[UE %d] Handover failure..initiating connection re-establishment procedure... \n", - ctxt_pP->module_id); - //Implement 36.331, section 5.3.5.6 here - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT); - return(RRC_Handover_failed); - } - - UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt--; - } - - // Layer 3 filtering of RRC measurements - if (UE_rrc_inst[ctxt_pP->module_id].QuantityConfig[0] != NULL) { - ue_meas_filtering(ctxt_pP,enb_indexP); - } - - ue_measurement_report_triggering(ctxt_pP,enb_indexP); - - if (UE_rrc_inst[ctxt_pP->module_id].Info[0].handoverTarget > 0) { - LOG_I(RRC,"[UE %d] Frame %d : RRC handover initiated\n", ctxt_pP->module_id, ctxt_pP->frame); - } - - if((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].State == RRC_HO_EXECUTION) && - (UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.targetCellId != 0xFF)) { - UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].State= RRC_IDLE; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT); - return(RRC_HO_STARTED); - } - - } else { // eNB - check_handovers(ctxt_pP); - // counetr, and get the value and aggregate - - // check for UL failure - RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(RC.rrc[ctxt_pP->module_id]->rrc_ue_head)) { - if ((ctxt_pP->frame == 0) && (ctxt_pP->subframe==0)) { - if (ue_context_p->ue_context.Initialue_identity_s_TMSI.presence == TRUE) { - LOG_I(RRC,"UE rnti %x:S-TMSI %x failure timer %d/20000\n", - ue_context_p->ue_context.rnti, - ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, - ue_context_p->ue_context.ul_failure_timer); - } - else { - LOG_I(RRC,"UE rnti %x failure timer %d/20000\n", - ue_context_p->ue_context.rnti, - ue_context_p->ue_context.ul_failure_timer); - } - } - if (ue_context_p->ue_context.ul_failure_timer>0) { - ue_context_p->ue_context.ul_failure_timer++; - if (ue_context_p->ue_context.ul_failure_timer >= 20000) { - // remove UE after 20 seconds after MAC has indicated UL failure - LOG_I(RRC,"Removing UE %x instance\n",ue_context_p->ue_context.rnti); - ue_to_be_removed = ue_context_p; - break; - } - } - if (ue_context_p->ue_context.ue_release_timer>0) { - ue_context_p->ue_context.ue_release_timer++; - if (ue_context_p->ue_context.ue_release_timer >= - ue_context_p->ue_context.ue_release_timer_thres) { - LOG_I(RRC,"Removing UE %x instance\n",ue_context_p->ue_context.rnti); - ue_to_be_removed = ue_context_p; - break; - } - } - } - if (ue_to_be_removed) - rrc_eNB_free_UE(ctxt_pP->module_id,ue_to_be_removed); - -#ifdef RRC_LOCALIZATION - - /* for the localization, only primary CC_id might be relevant*/ - gettimeofday(&ts, NULL); - current_timestamp_ms = ts.tv_sec * 1000 + ts.tv_usec / 1000; - ref_timestamp_ms = RC.rrc[ctxt_pP->module_id]->reference_timestamp_ms; - RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(RC.rrc[ctxt_pP->module_id]->rrc_ue_head)) { - ctxt = *ctxt_pP; - ctxt.rnti = ue_context_p->ue_context.rnti; - estimated_distance = rrc_get_estimated_ue_distance( - &ctxt, - CC_id, - RC.rrc[ctxt_pP->module_id]->loc_type); - - if ((current_timestamp_ms - ref_timestamp_ms > RC.rrc[ctxt_pP->module_id]->aggregation_period_ms) && - estimated_distance != -1) { - LOG_D(LOCALIZE, " RRC [UE/id %d -> eNB/id %d] timestamp %d frame %d estimated r = %f\n", - ctxt.rnti, - ctxt_pP->module_id, - current_timestamp_ms, - ctxt_pP->frame, - estimated_distance); - LOG_D(LOCALIZE, " RRC status %d\n", ue_context_p->ue_context.Status); - push_front(&RC.rrc[ctxt_pP->module_id]->loc_list, - estimated_distance); - RC.rrc[ctxt_pP->module_id]->reference_timestamp_ms = current_timestamp_ms; - } - } - -#endif - (void)ts; /* remove gcc warning "unused variable" */ - (void)ref_timestamp_ms; /* remove gcc warning "unused variable" */ - (void)current_timestamp_ms; /* remove gcc warning "unused variable" */ - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT); - return (RRC_OK); -} - //----------------------------------------------------------------------------- long binary_search_int( diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 164a0519b4..0aecee459c 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -56,6 +56,7 @@ #include "rrc_eNB_UE_context.h" #include "platform_types.h" #include "msc.h" +#include "UTIL/LOG/vcd_signal_dumper.h" #include "T.h" @@ -115,6 +116,25 @@ extern uint16_t two_tier_hexagonal_cellIds[7]; mui_t rrc_eNB_mui = 0; +void +openair_rrc_on( + const protocol_ctxt_t* const ctxt_pP +) +//----------------------------------------------------------------------------- +{ + unsigned short i; + int CC_id; + + LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" ENB:OPENAIR RRC IN....\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + rrc_config_buffer (&RC.rrc[ctxt_pP->module_id]->carrier[CC_id].SI, BCCH, 1); + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].SI.Active = 1; + rrc_config_buffer (&RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0, CCCH, 1); + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Active = 1; + } +} + //----------------------------------------------------------------------------- static void init_SI( @@ -5123,3 +5143,101 @@ rrc_top_cleanup_eNB( free(RC.rrc); } + +//----------------------------------------------------------------------------- +RRC_status_t +rrc_rx_tx( + protocol_ctxt_t* const ctxt_pP, + const int CC_id +) +//----------------------------------------------------------------------------- +{ + //uint8_t UE_id; + int32_t current_timestamp_ms, ref_timestamp_ms; + struct timeval ts; + struct rrc_eNB_ue_context_s *ue_context_p = NULL,*ue_to_be_removed = NULL; + +#ifdef LOCALIZATION + double estimated_distance; + protocol_ctxt_t ctxt; +#endif + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_IN); + + check_handovers(ctxt_pP); + // counetr, and get the value and aggregate + + // check for UL failure + RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(RC.rrc[ctxt_pP->module_id]->rrc_ue_head)) { + if ((ctxt_pP->frame == 0) && (ctxt_pP->subframe==0)) { + if (ue_context_p->ue_context.Initialue_identity_s_TMSI.presence == TRUE) { + LOG_I(RRC,"UE rnti %x:S-TMSI %x failure timer %d/20000\n", + ue_context_p->ue_context.rnti, + ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, + ue_context_p->ue_context.ul_failure_timer); + } + else { + LOG_I(RRC,"UE rnti %x failure timer %d/20000\n", + ue_context_p->ue_context.rnti, + ue_context_p->ue_context.ul_failure_timer); + } + } + if (ue_context_p->ue_context.ul_failure_timer>0) { + ue_context_p->ue_context.ul_failure_timer++; + if (ue_context_p->ue_context.ul_failure_timer >= 20000) { + // remove UE after 20 seconds after MAC has indicated UL failure + LOG_I(RRC,"Removing UE %x instance\n",ue_context_p->ue_context.rnti); + ue_to_be_removed = ue_context_p; + break; + } + } + if (ue_context_p->ue_context.ue_release_timer>0) { + ue_context_p->ue_context.ue_release_timer++; + if (ue_context_p->ue_context.ue_release_timer >= + ue_context_p->ue_context.ue_release_timer_thres) { + LOG_I(RRC,"Removing UE %x instance\n",ue_context_p->ue_context.rnti); + ue_to_be_removed = ue_context_p; + break; + } + } + } + if (ue_to_be_removed) + rrc_eNB_free_UE(ctxt_pP->module_id,ue_to_be_removed); + +#ifdef RRC_LOCALIZATION + + /* for the localization, only primary CC_id might be relevant*/ + gettimeofday(&ts, NULL); + current_timestamp_ms = ts.tv_sec * 1000 + ts.tv_usec / 1000; + ref_timestamp_ms = RC.rrc[ctxt_pP->module_id]->reference_timestamp_ms; + RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(RC.rrc[ctxt_pP->module_id]->rrc_ue_head)) { + ctxt = *ctxt_pP; + ctxt.rnti = ue_context_p->ue_context.rnti; + estimated_distance = rrc_get_estimated_ue_distance( + &ctxt, + CC_id, + RC.rrc[ctxt_pP->module_id]->loc_type); + + if ((current_timestamp_ms - ref_timestamp_ms > RC.rrc[ctxt_pP->module_id]->aggregation_period_ms) && + estimated_distance != -1) { + LOG_D(LOCALIZE, " RRC [UE/id %d -> eNB/id %d] timestamp %d frame %d estimated r = %f\n", + ctxt.rnti, + ctxt_pP->module_id, + current_timestamp_ms, + ctxt_pP->frame, + estimated_distance); + LOG_D(LOCALIZE, " RRC status %d\n", ue_context_p->ue_context.Status); + push_front(&RC.rrc[ctxt_pP->module_id]->loc_list, + estimated_distance); + RC.rrc[ctxt_pP->module_id]->reference_timestamp_ms = current_timestamp_ms; + } + } + +#endif + (void)ts; /* remove gcc warning "unused variable" */ + (void)ref_timestamp_ms; /* remove gcc warning "unused variable" */ + (void)current_timestamp_ms; /* remove gcc warning "unused variable" */ + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT); + return (RRC_OK); +} + diff --git a/targets/COMMON/create_tasks.c b/targets/COMMON/create_tasks.c index b911fbc5a4..1efe6f73eb 100644 --- a/targets/COMMON/create_tasks.c +++ b/targets/COMMON/create_tasks.c @@ -40,9 +40,9 @@ # endif # include "enb_app.h" -int create_tasks(uint32_t enb_nb, uint32_t ue_nb) +int create_tasks(uint32_t enb_nb) { - LOG_D(ENB_APP, "%s(enb_nb:%d ue_nb:%d)\n", __FUNCTION__, enb_nb, ue_nb); + LOG_D(ENB_APP, "%s(enb_nb:%d\n", __FUNCTION__, enb_nb); itti_wait_ready(1); if (itti_create_task (TASK_L2L1, l2l1_task, NULL) < 0) { @@ -58,11 +58,7 @@ int create_tasks(uint32_t enb_nb, uint32_t ue_nb) } } - -# ifdef OPENAIR2 - { # if defined(ENABLE_USE_MME) - { if (enb_nb > 0) { if (itti_create_task (TASK_SCTP, sctp_eNB_task, NULL) < 0) { LOG_E(SCTP, "Create task for SCTP failed\n"); @@ -85,19 +81,7 @@ int create_tasks(uint32_t enb_nb, uint32_t ue_nb) } } -# if defined(NAS_BUILT_IN_UE) - if (ue_nb > 0) { - nas_user_container_t *users = calloc(1, sizeof(*users)); - if (users == NULL) abort(); - users->count = ue_nb; - if (itti_create_task (TASK_NAS_UE, nas_ue_task, users) < 0) { - LOG_E(NAS, "Create task for NAS UE failed\n"); - return -1; - } - } # endif - } -# endif if (enb_nb > 0) { LOG_I(RRC,"Creating RRC eNB Task\n"); @@ -106,27 +90,8 @@ int create_tasks(uint32_t enb_nb, uint32_t ue_nb) LOG_E(RRC, "Create task for RRC eNB failed\n"); return -1; } - } - if (ue_nb > 0) { - if (itti_create_task (TASK_RRC_UE, rrc_ue_task, NULL) < 0) { - LOG_E(RRC, "Create task for RRC UE failed\n"); - return -1; - } - -# if ENABLE_RAL - - if (itti_create_task (TASK_RAL_UE, mRAL_task, NULL) < 0) { - LOG_E(RAL_UE, "Create task for RAL UE failed\n"); - return -1; - } - -# endif - } - } -# endif // openair2: NN: should be openair3 - itti_wait_ready(0); diff --git a/targets/COMMON/create_tasks.h b/targets/COMMON/create_tasks.h index 493c441f59..ff1d9ace51 100644 --- a/targets/COMMON/create_tasks.h +++ b/targets/COMMON/create_tasks.h @@ -26,7 +26,8 @@ /* External declaration of L2L1 task that depend on the target */ extern void *l2l1_task(void *arg); -int create_tasks(uint32_t enb_nb, uint32_t ue_nb); +int create_tasks(uint32_t enb_nb); +int create_tasks_ue(uint32_t ue_nb); #endif #endif /* CREATE_TASKS_H_ */ diff --git a/targets/COMMON/create_tasks_ue.c b/targets/COMMON/create_tasks_ue.c new file mode 100644 index 0000000000..bd36511b52 --- /dev/null +++ b/targets/COMMON/create_tasks_ue.c @@ -0,0 +1,80 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +# include "create_tasks.h" +# include "log.h" + +# ifdef OPENAIR2 +# if defined(ENABLE_USE_MME) +# include "sctp_eNB_task.h" +# include "s1ap_eNB.h" +# include "nas_ue_task.h" +# include "udp_eNB_task.h" +# include "gtpv1u_eNB_task.h" +# endif +# if ENABLE_RAL +# include "lteRALue.h" +# include "lteRALenb.h" +# endif +# include "RRC/LITE/defs.h" +# endif +# include "enb_app.h" + +int create_tasks_ue(uint32_t ue_nb) +{ + LOG_D(ENB_APP, "%s(ue_nb:%d)\n", __FUNCTION__, ue_nb); + + itti_wait_ready(1); + if (itti_create_task (TASK_L2L1, l2l1_task, NULL) < 0) { + LOG_E(PDCP, "Create task for L2L1 failed\n"); + return -1; + } + +# if defined(ENABLE_USE_MME) +# if defined(NAS_BUILT_IN_UE) + if (ue_nb > 0) { + nas_user_container_t *users = calloc(1, sizeof(*users)); + if (users == NULL) abort(); + users->count = ue_nb; + if (itti_create_task (TASK_NAS_UE, nas_ue_task, users) < 0) { + LOG_E(NAS, "Create task for NAS UE failed\n"); + return -1; + } + } +# endif +# endif + + if (ue_nb > 0) { + if (itti_create_task (TASK_RRC_UE, rrc_ue_task, NULL) < 0) { + LOG_E(RRC, "Create task for RRC UE failed\n"); + return -1; + } + + } + + + itti_wait_ready(0); + + return 0; +} +#endif diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index d999bdb10c..2706cf18a2 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -95,6 +95,9 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "enb_config.h" //#include "PHY/TOOLS/time_meas.h" +#include "ENB_APP/enb_paramdef.h" +#include "common/config/config_userapi.h" + #ifndef OPENAIR2 #include "UTIL/OTG/otg_extern.h" #endif @@ -959,13 +962,27 @@ static void* ru_thread_prach( void* param ) { if (oai_exit) break; if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 ); - prach_procedures( + if (ru->eNB_list[0]){ + prach_procedures( ru->eNB_list[0] #ifdef Rel14 ,0 #endif ); - + } + else { + rx_prach(NULL, + ru, + NULL, + NULL, + NULL, + proc->frame_prach, + 0 +#ifdef Rel14 + ,0 +#endif + ); + } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0 ); if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break; } @@ -1159,9 +1176,10 @@ static inline int wakeup_prach_ru(RU_t *ru) { ru->proc.subframe_prach = ru->proc.subframe_rx; // DJP - think prach_procedures() is looking at eNB frame_prach - ru->eNB_list[0]->proc.frame_prach = ru->proc.frame_rx; - ru->eNB_list[0]->proc.subframe_prach = ru->proc.subframe_rx; - + if (ru->eNB_list[0]) { + ru->eNB_list[0]->proc.frame_prach = ru->proc.frame_rx; + ru->eNB_list[0]->proc.subframe_prach = ru->proc.subframe_rx; + } LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx); // the thread can now be woken up AssertFatal(pthread_cond_signal(&ru->proc.cond_prach) == 0, "ERROR pthread_cond_signal for RU prach thread\n"); @@ -1447,6 +1465,7 @@ static void* ru_thread( void* param ) { if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&subframe); else AssertFatal(1==0, "No fronthaul interface at south port"); +/* LOG_D(PHY,"AFTER fh_south_in - SFN/SF:%d%d RU->proc[RX:%d%d TX:%d%d] RC.eNB[0][0]:[RX:%d%d TX(SFN):%d]\n", frame,subframe, proc->frame_rx,proc->subframe_rx, @@ -1458,7 +1477,7 @@ static void* ru_thread( void* param ) { ru->do_prach, is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx), proc->frame_rx,proc->subframe_rx); - +*/ if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)==1)) { wakeup_prach_ru(ru); } @@ -1885,7 +1904,7 @@ void init_RU(char *rf_config_file) { int ru_id; RU_t *ru; int ret; - PHY_VARS_eNB *eNB0; + PHY_VARS_eNB *eNB0= (PHY_VARS_eNB *)NULL; int i; int CC_id; @@ -1913,22 +1932,23 @@ void init_RU(char *rf_config_file) { // use eNB_list[0] as a reference for RU frame parameters // NOTE: multiple CC_id are not handled here yet! - LOG_D(PHY, "%s() RC.ru[%d].num_eNB:%d ru->eNB_list[0]:%p RC.eNB[0][0]:%p rf_config_file:%s\n", __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file); + if (ru->num_eNB > 0) { + LOG_D(PHY, "%s() RC.ru[%d].num_eNB:%d ru->eNB_list[0]:%p RC.eNB[0][0]:%p rf_config_file:%s\n", __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file); - if (ru->eNB_list[0] == 0) - { - LOG_E(PHY,"%s() DJP - ru->eNB_list ru->num_eNB are not initialized - so do it manually\n", __FUNCTION__); - ru->eNB_list[0] = RC.eNB[0][0]; - ru->num_eNB=1; + if (ru->eNB_list[0] == 0) + { + LOG_E(PHY,"%s() DJP - ru->eNB_list ru->num_eNB are not initialized - so do it manually\n", __FUNCTION__); + ru->eNB_list[0] = RC.eNB[0][0]; + ru->num_eNB=1; // // DJP - feptx_prec() / feptx_ofdm() parses the eNB_list (based on num_eNB) and copies the txdata_F to txdata in RU // + } + else + { + LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__); + } } - else - { - LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__); - } - eNB0 = ru->eNB_list[0]; LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south); LOG_D(PHY, "eNB0:%p\n", eNB0); @@ -2120,3 +2140,134 @@ void stop_ru(RU_t *ru) { } + +/* --------------------------------------------------------*/ +/* from here function to use configuration module */ +void RCconfig_RU(void) { + + int j = 0; + int i = 0; + + + paramdef_t RUParams[] = RUPARAMS_DESC; + paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0}; + + + config_getlist( &RUParamList,RUParams,sizeof(RUParams)/sizeof(paramdef_t), NULL); + + + if ( RUParamList.numelt > 0) { + + RC.ru = (RU_t**)malloc(RC.nb_RU*sizeof(RU_t*)); + + + + + RC.ru_mask=(1<idx = j; + + printf("Creating RC.ru[%d]:%p\n", j, RC.ru[j]); + + RC.ru[j]->if_timing = synch_to_ext_device; + if (RC.nb_L1_inst >0) + RC.ru[j]->num_eNB = RUParamList.paramarray[j][RU_ENB_LIST_IDX].numelt; + else + RC.ru[j]->num_eNB = 0; + for (i=0;inum_eNB;i++) RC.ru[j]->eNB_list[i] = RC.eNB[RUParamList.paramarray[j][RU_ENB_LIST_IDX].iptr[i]][0]; + + + if (strcmp(*(RUParamList.paramarray[j][RU_LOCAL_RF_IDX].strptr), "yes") == 0) { + if ( !(config_isparamset(RUParamList.paramarray[j],RU_LOCAL_IF_NAME_IDX)) ) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = eNodeB_3GPP; + printf("Setting function for RU %d to eNodeB_3GPP\n",j); + } + else { + RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); + RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); + RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); + RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); + RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); + + if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = NGFI_RRU_IF5; + RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE; + printf("Setting function for RU %d to NGFI_RRU_IF5 (udp)\n",j); + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = NGFI_RRU_IF5; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE; + printf("Setting function for RU %d to NGFI_RRU_IF5 (raw)\n",j); + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = NGFI_RRU_IF4p5; + RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; + printf("Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n",j); + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = NGFI_RRU_IF4p5; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; + printf("Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n",j); + } + } + RC.ru[j]->max_pdschReferenceSignalPower = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);; + RC.ru[j]->max_rxgain = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr); + RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt; + for (i=0;inum_bands;i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i]; + } //strcmp(local_rf, "yes") == 0 + else { + printf("RU %d: Transport %s\n",j,*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr)); + + RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); + RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); + RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); + RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); + RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); + if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) { + RC.ru[j]->if_south = REMOTE_IF5; + RC.ru[j]->function = NGFI_RAU_IF5; + RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE; + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) { + RC.ru[j]->if_south = REMOTE_IF5; + RC.ru[j]->function = NGFI_RAU_IF5; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE; + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) { + RC.ru[j]->if_south = REMOTE_IF4p5; + RC.ru[j]->function = NGFI_RAU_IF4p5; + RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) { + RC.ru[j]->if_south = REMOTE_IF4p5; + RC.ru[j]->function = NGFI_RAU_IF4p5; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if5_mobipass") == 0) { + RC.ru[j]->if_south = REMOTE_IF5; + RC.ru[j]->function = NGFI_RAU_IF5; + RC.ru[j]->if_timing = synch_to_other; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF5_MOBIPASS; + } + RC.ru[j]->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); + RC.ru[j]->att_rx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); + } /* strcmp(local_rf, "yes") != 0 */ + + RC.ru[j]->nb_tx = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr); + RC.ru[j]->nb_rx = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr); + + }// j=0..num_rus + } else { + RC.nb_RU = 0; + } // setting != NULL + + return; + +} diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 17207cf31e..72c24511ec 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1176,11 +1176,18 @@ int main( int argc, char **argv ) (RC.nb_inst > 0)) { // don't create if node doesn't connect to RRC/S1/GTP - if (create_tasks(UE_flag ? 0 : 1, UE_flag ? 1 : 0) < 0) { - printf("cannot create ITTI tasks\n"); - exit(-1); // need a softer mode + if (UE_flag == 0) { + if (create_tasks(1) < 0) { + printf("cannot create ITTI tasks\n"); + exit(-1); // need a softer mode + } + } + else { + if (create_tasks_ue(1) < 0) { + printf("cannot create ITTI tasks\n"); + exit(-1); // need a softer mode + } } - printf("ITTI tasks created\n"); } else { diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index 4b6e27178f..7d8b33f12c 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -160,6 +160,8 @@ volatile int oai_exit = 0; //int32_t **rxdata; //int32_t **txdata; +uint16_t sf_ahead=4; +uint8_t nfapi_mode = 0; // Added for PHY abstraction extern node_list* ue_node_list; @@ -377,7 +379,7 @@ int omv_write(int pfd, node_list* enb_node_list, node_list* ue_node_list, Data_F omv_data.geo[i].node_type = 0; //eNB enb_node_list = enb_node_list->next; omv_data.geo[i].Neighbors = 0; - +/* for (j = NB_RU; j < NB_UE_INST + NB_RU; j++) { if (is_UE_active (i, j - NB_RU) == 1) { omv_data.geo[i].Neighbor[omv_data.geo[i].Neighbors] = j; @@ -387,6 +389,7 @@ int omv_write(int pfd, node_list* enb_node_list, node_list* ue_node_list, Data_F "[RU %d][UE %d] is_UE_active(i,j) %d geo (x%d, y%d) num neighbors %d\n", i, j-NB_RU, is_UE_active(i,j-NB_RU), omv_data.geo[i].x, omv_data.geo[i].y, omv_data.geo[i].Neighbors); } } +*/ } } @@ -413,7 +416,7 @@ int omv_write(int pfd, node_list* enb_node_list, node_list* ue_node_list, Data_F ue_node_list = ue_node_list->next; omv_data.geo[i].Neighbors = 0; - +/* for (j = 0; j < NB_RU; j++) { if (is_UE_active (j, i - NB_RU) == 1) { omv_data.geo[i].Neighbor[omv_data.geo[i].Neighbors] = j; @@ -423,6 +426,7 @@ int omv_write(int pfd, node_list* enb_node_list, node_list* ue_node_list, Data_F "[UE %d][RU %d] is_UE_active %d geo (x%d, y%d) num neighbors %d\n", i-NB_RU, j, is_UE_active(j,i-NB_RU), omv_data.geo[i].x, omv_data.geo[i].y, omv_data.geo[i].Neighbors); } } +*/ } } @@ -1178,8 +1182,7 @@ main (int argc, char **argv) - if (create_tasks(0, - oai_emulation.info.nb_ue_local) < 0) + if (create_tasks_ue(oai_emulation.info.nb_ue_local) < 0) exit(-1); // need a softer mode @@ -1771,9 +1774,6 @@ oai_shutdown (void) } } //End of PHY abstraction changes -#ifdef OPENAIR2 - mac_top_cleanup (); -#endif // stop OMG stop_mobility_generator (omg_param_list); //omg_param_list.mobility_type @@ -1826,3 +1826,10 @@ get_OAI_emulation () } +// dummy function declarations + +void *rrc_enb_task(void *args_p) { + + +} + diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index 4f30a5c2e7..8a21acc442 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -80,6 +80,9 @@ #include "../../ARCH/COMMON/common_lib.h" #include "../../ARCH/ETHERNET/USERSPACE/LIB/if_defs.h" +#include "ENB_APP/enb_paramdef.h" +#include "common/config/config_userapi.h" + #ifdef SMBV extern uint8_t config_smbv; extern char smbv_ip[16]; @@ -177,6 +180,18 @@ extern int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; int oaisim_flag=1; +void RCConfig_sim(void) { + + paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0}; + + + // Get num RU instances + config_getlist( &RUParamList,NULL,0, NULL); + RC.nb_RU = RUParamList.numelt; + + +} + void get_simulation_options(int argc, char *argv[]) { int option; @@ -788,7 +803,7 @@ void get_simulation_options(int argc, char *argv[]) if (RC.config_file_name != NULL) { /* Read eNB configuration file */ - RCConfig(); + RCConfig_sim(); printf("returned with %d eNBs, %d rus\n",RC.nb_inst,RC.nb_RU); oai_emulation.info.nb_enb_local = RC.nb_inst; oai_emulation.info.nb_ru_local = RC.nb_RU; @@ -1106,7 +1121,7 @@ int UE_trx_read(openair0_device *device, openair0_timestamp *ptimestamp, void ** *ptimestamp = last_UE_rx_timestamp[UE_id][CC_id]; - LOG_D(EMU,"UE %d DL simulation 0: UE_trx_read nsamps %d TS %llu (%llu, offset %d) antenna %d\n", + LOG_I(EMU,"UE %d DL simulation 0: UE_trx_read nsamps %d TS %llu (%llu, offset %d) antenna %d\n", UE_id, nsamps, (unsigned long long)current_UE_rx_timestamp[UE_id][CC_id], @@ -1579,7 +1594,7 @@ void update_otg_eNB(module_id_t enb_module_idP, unsigned int ctime) #if defined(USER_MODE) && defined(OAI_EMU) //int rrc_state=0; - +/* if (oai_emulation.info.otg_enabled ==1 ) { int dst_id, app_id; @@ -1589,7 +1604,8 @@ void update_otg_eNB(module_id_t enb_module_idP, unsigned int ctime) for_times += 1; // generate traffic if the ue is rrc reconfigured state - //if ((rrc_state=mac_eNB_get_rrc_status(enb_module_idP, dst_id)) > 2 /*RRC_CONNECTED*/ ) { + //if ((rrc_state=mac_eNB_get_rrc_status(enb_module_idP, dst_id)) > 2 //RRC_CONNECTED + { if (mac_eNB_get_rrc_status(enb_module_idP, oai_emulation.info.eNB_ue_module_id_to_rnti[enb_module_idP][dst_id]) > 2 ){ if_times += 1; @@ -1649,7 +1665,7 @@ void update_otg_eNB(module_id_t enb_module_idP, unsigned int ctime) otg_pkt=NULL; } - +*/ // old version /* // MBSM multicast traffic #if defined(Rel10) || defined(Rel14) @@ -1675,13 +1691,14 @@ void update_otg_eNB(module_id_t enb_module_idP, unsigned int ctime) } // end multicast traffic #endif */ - +/* } } } } // end multicast traffic +*/ #endif } @@ -1714,7 +1731,6 @@ void update_otg_eNB(module_id_t enb_module_idP, unsigned int ctime) } } -#endif #endif } @@ -1834,6 +1850,13 @@ void init_time() td_avg = TARGET_SF_TIME_NS; } +// dummy function +int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind) { + + return(0); + +} + /* int openair0_transport_load(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t * eth_params) { From 20c7af9a96a4f80d98b3fc589aa8ffbc6adf60ed Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sun, 21 Jan 2018 22:21:30 +0100 Subject: [PATCH 161/284] forgot to add a file --- openair1/SCHED/prach_procedures.c | 228 ++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 openair1/SCHED/prach_procedures.c diff --git a/openair1/SCHED/prach_procedures.c b/openair1/SCHED/prach_procedures.c new file mode 100644 index 0000000000..be5aa33d2b --- /dev/null +++ b/openair1/SCHED/prach_procedures.c @@ -0,0 +1,228 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file phy_procedures_lte_eNB.c + * \brief Implementation of eNB procedures from 36.213 LTE specifications + * \author R. Knopp, F. Kaltenberger, N. Nikaein, X. Foukas + * \date 2011 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr,navid.nikaein@eurecom.fr, x.foukas@sms.ed.ac.uk + * \note + * \warning + */ + +#include "PHY/defs.h" +#include "PHY/extern.h" +#include "SCHED/defs.h" +#include "SCHED/extern.h" +#include "nfapi_interface.h" +#include "fapi_l1.h" +#include "UTIL/LOG/log.h" +#include "UTIL/LOG/vcd_signal_dumper.h" + +#include "T.h" + +#include "assertions.h" +#include "msc.h" + +#include + +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +#endif + +extern uint32_t nfapi_mode; + +void prach_procedures(PHY_VARS_eNB *eNB, +#ifdef Rel14 + int br_flag +#endif + ) { + uint16_t max_preamble[4],max_preamble_energy[4],max_preamble_delay[4]; + uint16_t i; + int frame,subframe; + +#ifdef Rel14 + if (br_flag==1) { + subframe = eNB->proc.subframe_prach_br; + frame = eNB->proc.frame_prach_br; + pthread_mutex_lock(&eNB->UL_INFO_mutex); + eNB->UL_INFO.rach_ind_br.rach_indication_body.number_of_preambles=0; + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + } + else +#endif + { + pthread_mutex_lock(&eNB->UL_INFO_mutex); + eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles=0; + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + subframe = eNB->proc.subframe_prach; + frame = eNB->proc.frame_prach; + } + RU_t *ru; + int aa=0; + int ru_aa; + + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,1); + + + + for (i=0;inum_RU;i++) { + ru=eNB->RU_list[i]; + for (ru_aa=0,aa=0;ru_aanb_rx;ru_aa++,aa++) { + eNB->prach_vars.rxsigF[0][aa] = eNB->RU_list[i]->prach_rxsigF[ru_aa]; +#ifdef Rel14 + int ce_level; + + if (br_flag==1) + for (ce_level=0;ce_level<4;ce_level++) eNB->prach_vars_br.rxsigF[ce_level][aa] = eNB->RU_list[i]->prach_rxsigF_br[ce_level][ru_aa]; +#endif + } + } + + rx_prach(eNB, + eNB->RU_list[0], + &max_preamble[0], + &max_preamble_energy[0], + &max_preamble_delay[0], + frame, + 0 +#ifdef Rel14 + ,br_flag +#endif + ); + + #ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[RAPROC] Frame %d, subframe %d : Most likely preamble %d, energy %d dB delay %d (prach_energy counter %d)\n", + frame,subframe, + max_preamble[0], + max_preamble_energy[0]/10, + max_preamble_delay[0], + eNB->prach_energy_counter); + #endif + +#ifdef Rel14 + if (br_flag==1) { + + int prach_mask; + + prach_mask = is_prach_subframe(&eNB->frame_parms,eNB->proc.frame_prach_br,eNB->proc.subframe_prach_br); + + eNB->UL_INFO.rach_ind_br.rach_indication_body.preamble_list = eNB->preamble_list_br; + int ind=0; + int ce_level=0; + /* Save for later, it doesn't work + for (int ind=0,ce_level=0;ce_level<4;ce_level++) { + + if ((eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[ce_level]==1)&& + (prach_mask&(1<<(1+ce_level)) > 0) && // prach is active and CE level has finished its repetitions + (eNB->prach_vars_br.repetition_number[ce_level]== + eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[ce_level])) { + */ + if (eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0]==1){ + if ((eNB->prach_energy_counter == 100) && + (max_preamble_energy[0] > eNB->measurements.prach_I0 + 100)) { + eNB->UL_INFO.rach_ind_br.rach_indication_body.number_of_preambles++; + + eNB->preamble_list_br[ind].preamble_rel8.timing_advance = max_preamble_delay[ind];// + eNB->preamble_list_br[ind].preamble_rel8.preamble = max_preamble[ind]; + // note: fid is implicitly 0 here, this is the rule for eMTC RA-RNTI from 36.321, Section 5.1.4 + eNB->preamble_list_br[ind].preamble_rel8.rnti = 1+subframe+(eNB->prach_vars_br.first_frame[ce_level]%40); + eNB->preamble_list_br[ind].instance_length = 0; //don't know exactly what this is + eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type = 1+ce_level; // CE Level + LOG_D(PHY,"Filling NFAPI indication for RACH %d CELevel %d (mask %x) : TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", + ind, + ce_level, + prach_mask, + eNB->preamble_list_br[ind].preamble_rel8.timing_advance, + eNB->preamble_list_br[ind].preamble_rel8.preamble, + eNB->preamble_list_br[ind].preamble_rel8.rnti, + eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type); + } + /* + ind++; + } + } */// ce_level + } + } + else +#endif + + { + if ((eNB->prach_energy_counter == 100) && + (max_preamble_energy[0] > eNB->measurements.prach_I0+100)) { + + LOG_I(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", + eNB->Mod_id, + eNB->CC_id, + frame, + subframe, + max_preamble[0], + max_preamble_energy[0]/10, + max_preamble_energy[0]%10, + max_preamble_delay[0]); + + T(T_ENB_PHY_INITIATE_RA_PROCEDURE, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), + T_INT(max_preamble[0]), T_INT(max_preamble_energy[0]), T_INT(max_preamble_delay[0])); + + pthread_mutex_lock(&eNB->UL_INFO_mutex); + + eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles = 1; + eNB->UL_INFO.rach_ind.rach_indication_body.preamble_list = &eNB->preamble_list[0]; + eNB->UL_INFO.rach_ind.rach_indication_body.tl.tag = NFAPI_RACH_INDICATION_BODY_TAG; + eNB->UL_INFO.rach_ind.header.message_id = NFAPI_RACH_INDICATION; + eNB->UL_INFO.rach_ind.sfn_sf = frame<<4 | subframe; + + eNB->preamble_list[0].preamble_rel8.tl.tag = NFAPI_PREAMBLE_REL8_TAG; + eNB->preamble_list[0].preamble_rel8.timing_advance = max_preamble_delay[0]; + eNB->preamble_list[0].preamble_rel8.preamble = max_preamble[0]; + eNB->preamble_list[0].preamble_rel8.rnti = 1+subframe; // note: fid is implicitly 0 here + eNB->preamble_list[0].preamble_rel13.rach_resource_type = 0; + eNB->preamble_list[0].instance_length = 0; //don't know exactly what this is + + if (nfapi_mode == 1) { // If NFAPI PNF then we need to send the message to the VNF + + LOG_D(PHY,"Filling NFAPI indication for RACH : SFN_SF:%d TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", + NFAPI_SFNSF2DEC(eNB->UL_INFO.rach_ind.sfn_sf), + eNB->preamble_list[0].preamble_rel8.timing_advance, + eNB->preamble_list[0].preamble_rel8.preamble, + eNB->preamble_list[0].preamble_rel8.rnti, + eNB->preamble_list[0].preamble_rel13.rach_resource_type); + + oai_nfapi_rach_ind(&eNB->UL_INFO.rach_ind); + + eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles = 0; + } + + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + + } // max_preamble_energy > prach_I0 + 100 + else { + eNB->measurements.prach_I0 = ((eNB->measurements.prach_I0*900)>>10) + ((max_preamble_energy[0]*124)>>10); + if (frame==0) LOG_I(PHY,"prach_I0 = %d.%d dB\n",eNB->measurements.prach_I0/10,eNB->measurements.prach_I0%10); + if (eNB->prach_energy_counter < 100) eNB->prach_energy_counter++; + } + } // else br_flag + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0); +} From b350f8557e152b1dbab562bd69aa1a661a2379b6 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sun, 21 Jan 2018 16:58:21 -0800 Subject: [PATCH 162/284] fixes for broken automatic indentation in MAC #1 --- openair2/LAYER2/MAC/config.c | 265 +- openair2/LAYER2/MAC/eNB_scheduler.c | 975 +-- openair2/LAYER2/MAC/eNB_scheduler_RA.c | 790 +- .../LAYER2/MAC/eNB_scheduler_primitives.c | 6848 ++++++++--------- 4 files changed, 3995 insertions(+), 4883 deletions(-) diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index ef37f6b1f3..c67d26ed2f 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -251,7 +251,7 @@ void config_mib(int Mod_idP, cfg->rf_config.dl_channel_bandwidth.value = to_prb(dl_BandwidthP); cfg->rf_config.dl_channel_bandwidth.tl.tag = NFAPI_RF_CONFIG_DL_CHANNEL_BANDWIDTH_TAG; cfg->num_tlv++; -LOG_E(PHY,"%s() dl_BandwidthP:%d\n", __FUNCTION__, dl_BandwidthP); + LOG_E(PHY,"%s() dl_BandwidthP:%d\n", __FUNCTION__, dl_BandwidthP); cfg->rf_config.ul_channel_bandwidth.value = to_prb(dl_BandwidthP); cfg->rf_config.ul_channel_bandwidth.tl.tag = NFAPI_RF_CONFIG_UL_CHANNEL_BANDWIDTH_TAG; @@ -306,35 +306,35 @@ LOG_E(PHY,"%s() dl_BandwidthP:%d\n", __FUNCTION__, dl_BandwidthP); LOG_I(MAC, - "%s() NFAPI_CONFIG_REQUEST(num_tlv:%u) DL_BW:%u UL_BW:%u Ncp %d,p_eNB %d,earfcn %d,band %d,phich_resource %u phich_duration %u phich_power_offset %u PSS %d SSS %d PCI %d" + "%s() NFAPI_CONFIG_REQUEST(num_tlv:%u) DL_BW:%u UL_BW:%u Ncp %d,p_eNB %d,earfcn %d,band %d,phich_resource %u phich_duration %u phich_power_offset %u PSS %d SSS %d PCI %d" #ifdef Rel14 - " PBCH repetition %d" + " PBCH repetition %d" #endif - "\n" - ,__FUNCTION__ - ,cfg->num_tlv - ,cfg->rf_config.dl_channel_bandwidth.value - ,cfg->rf_config.ul_channel_bandwidth.value - ,NcpP,p_eNBP - ,cfg->nfapi_config.earfcn.value - ,cfg->nfapi_config.rf_bands.rf_band[0] - ,cfg->phich_config.phich_resource.value - ,cfg->phich_config.phich_duration.value - ,cfg->phich_config.phich_power_offset.value - ,cfg->sch_config.primary_synchronization_signal_epre_eprers.value - ,cfg->sch_config.secondary_synchronization_signal_epre_eprers.value - ,cfg->sch_config.physical_cell_id.value + "\n" + ,__FUNCTION__ +` ,cfg->num_tlv + ,cfg->rf_config.dl_channel_bandwidth.value + ,cfg->rf_config.ul_channel_bandwidth.value + ,NcpP,p_eNBP + ,cfg->nfapi_config.earfcn.value + ,cfg->nfapi_config.rf_bands.rf_band[0] + ,cfg->phich_config.phich_resource.value + ,cfg->phich_config.phich_duration.value + ,cfg->phich_config.phich_power_offset.value + ,cfg->sch_config.primary_synchronization_signal_epre_eprers.value + ,cfg->sch_config.secondary_synchronization_signal_epre_eprers.value + ,cfg->sch_config.physical_cell_id.value #ifdef Rel14 - ,cfg->emtc_config.pbch_repetitions_enable_r13.value + ,cfg->emtc_config.pbch_repetitions_enable_r13.value #endif - ); + ); } void config_sib1(int Mod_idP, int CC_idP, TDD_Config_t * tdd_ConfigP) { - nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; + nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; if (tdd_ConfigP) { //TDD cfg->subframe_config.duplex_mode.value = 0; @@ -434,16 +434,13 @@ config_sib2(int Mod_idP, cfg->pucch_config.n1_pucch_an.tl.tag = NFAPI_PUCCH_CONFIG_N1_PUCCH_AN_TAG; cfg->num_tlv++; - if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled == true) - { + if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled == true) { cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 1; } - else if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled == true) - { + else if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled == true) { cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 2; } - else // No hopping - { + else { cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 0; } cfg->uplink_reference_signal_config.uplink_rs_hopping.tl.tag = NFAPI_UPLINK_REFERENCE_SIGNAL_CONFIG_UPLINK_RS_HOPPING_TAG; @@ -474,10 +471,10 @@ config_sib2(int Mod_idP, if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts) { - cfg->srs_config.max_up_pts.value = 1; + cfg->srs_config.max_up_pts.value = 1; } else { - cfg->srs_config.max_up_pts.value = 0; + cfg->srs_config.max_up_pts.value = 0; } cfg->srs_config.max_up_pts.tl.tag = NFAPI_SRS_CONFIG_MAX_UP_PTS_TAG; cfg->num_tlv++; @@ -819,65 +816,65 @@ rrc_mac_config_req_eNB(module_id_t Mod_idP, RC.mac[Mod_idP]->common_channels[CC_idP].sib1_v13ext = sib1_v13ext; } #endif - if (radioResourceConfigCommon != NULL) { - LOG_I(MAC, "[CONFIG]SIB2/3 Contents (partial)\n"); - LOG_I(MAC, "[CONFIG]pusch_config_common.n_SB = %ld\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.pusch_ConfigBasic.n_SB); - LOG_I(MAC, "[CONFIG]pusch_config_common.hoppingMode = %ld\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode); - LOG_I(MAC, - "[CONFIG]pusch_config_common.pusch_HoppingOffset = %ld\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset); - LOG_I(MAC, "[CONFIG]pusch_config_common.enable64QAM = %d\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.pusch_ConfigBasic.enable64QAM); - LOG_I(MAC, - "[CONFIG]pusch_config_common.groupHoppingEnabled = %d\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. - groupHoppingEnabled); - LOG_I(MAC, - "[CONFIG]pusch_config_common.groupAssignmentPUSCH = %ld\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. - groupAssignmentPUSCH); - LOG_I(MAC, - "[CONFIG]pusch_config_common.sequenceHoppingEnabled = %d\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. - sequenceHoppingEnabled); - LOG_I(MAC, "[CONFIG]pusch_config_common.cyclicShift = %ld\n", - radioResourceConfigCommon-> - pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift); + if (radioResourceConfigCommon != NULL) { + LOG_I(MAC, "[CONFIG]SIB2/3 Contents (partial)\n"); + LOG_I(MAC, "[CONFIG]pusch_config_common.n_SB = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.pusch_ConfigBasic.n_SB); + LOG_I(MAC, "[CONFIG]pusch_config_common.hoppingMode = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode); + LOG_I(MAC, + "[CONFIG]pusch_config_common.pusch_HoppingOffset = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset); + LOG_I(MAC, "[CONFIG]pusch_config_common.enable64QAM = %d\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.pusch_ConfigBasic.enable64QAM); + LOG_I(MAC, + "[CONFIG]pusch_config_common.groupHoppingEnabled = %d\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. + groupHoppingEnabled); + LOG_I(MAC, + "[CONFIG]pusch_config_common.groupAssignmentPUSCH = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. + groupAssignmentPUSCH); + LOG_I(MAC, + "[CONFIG]pusch_config_common.sequenceHoppingEnabled = %d\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH. + sequenceHoppingEnabled); + LOG_I(MAC, "[CONFIG]pusch_config_common.cyclicShift = %ld\n", + radioResourceConfigCommon-> + pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift); - AssertFatal(radioResourceConfigCommon-> - rach_ConfigCommon.maxHARQ_Msg3Tx > 0, - "radioResourceconfigCommon %d == 0\n", - (int) radioResourceConfigCommon-> - rach_ConfigCommon.maxHARQ_Msg3Tx); + AssertFatal(radioResourceConfigCommon-> + rach_ConfigCommon.maxHARQ_Msg3Tx > 0, + "radioResourceconfigCommon %d == 0\n", + (int) radioResourceConfigCommon-> + rach_ConfigCommon.maxHARQ_Msg3Tx); - RC.mac[Mod_idP]->common_channels[CC_idP]. - radioResourceConfigCommon = radioResourceConfigCommon; - if (ul_CarrierFreq > 0) - RC.mac[Mod_idP]->common_channels[CC_idP].ul_CarrierFreq = - ul_CarrierFreq; - if (ul_Bandwidth) - RC.mac[Mod_idP]->common_channels[CC_idP].ul_Bandwidth = - *ul_Bandwidth; - else - RC.mac[Mod_idP]->common_channels[CC_idP].ul_Bandwidth = - RC.mac[Mod_idP]->common_channels[CC_idP].mib->message. - dl_Bandwidth; + RC.mac[Mod_idP]->common_channels[CC_idP]. + radioResourceConfigCommon = radioResourceConfigCommon; + if (ul_CarrierFreq > 0) + RC.mac[Mod_idP]->common_channels[CC_idP].ul_CarrierFreq = + ul_CarrierFreq; + if (ul_Bandwidth) + RC.mac[Mod_idP]->common_channels[CC_idP].ul_Bandwidth = + *ul_Bandwidth; + else + RC.mac[Mod_idP]->common_channels[CC_idP].ul_Bandwidth = + RC.mac[Mod_idP]->common_channels[CC_idP].mib->message. + dl_Bandwidth; - config_sib2(Mod_idP, CC_idP, radioResourceConfigCommon, + config_sib2(Mod_idP, CC_idP, radioResourceConfigCommon, #ifdef Rel14 - radioResourceConfigCommon_BR, + radioResourceConfigCommon_BR, #endif - NULL, ul_Bandwidth, additionalSpectrumEmission, - mbsfn_SubframeConfigList); + NULL, ul_Bandwidth, additionalSpectrumEmission, + mbsfn_SubframeConfigList); } } // mib != NULL @@ -888,14 +885,14 @@ rrc_mac_config_req_eNB(module_id_t Mod_idP, if (UE_id == -1) { LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, - __LINE__, __FUNCTION__); + __LINE__, __FUNCTION__); } else { if (logicalChannelConfig) UE_list-> UE_template[CC_idP][UE_id].lcgidmap [logicalChannelIdentity] = *logicalChannelConfig-> - ul_SpecificParameters->logicalChannelGroup; + ul_SpecificParameters->logicalChannelGroup; else UE_list-> UE_template[CC_idP][UE_id].lcgidmap @@ -920,9 +917,9 @@ rrc_mac_config_req_eNB(module_id_t Mod_idP, UE_id = find_UE_id(Mod_idP, rntiP); if (UE_id == -1) LOG_E(MAC, "%s:%d:%s: ERROR, UE_id == -1\n", __FILE__, - __LINE__, __FUNCTION__); + __LINE__, __FUNCTION__); else - config_dedicated_scell(Mod_idP, rntiP, sCellToAddMod_r10); + config_dedicated_scell(Mod_idP, rntiP, sCellToAddMod_r10); } #endif @@ -954,7 +951,7 @@ rrc_mac_config_req_eNB(module_id_t Mod_idP, #if defined(Rel10) || defined(Rel14) if (mbsfn_AreaInfoList != NULL) { - // One eNB could be part of multiple mbsfn syc area, this could change over time so reset each time + // One eNB could be part of multiple mbsfn syc area, this could change over time so reset each time LOG_I(MAC,"[eNB %d][CONFIG] Received %d MBSFN Area Info\n", Mod_idP, mbsfn_AreaInfoList->list.count); RC.mac[Mod_idP]->common_channels[0].num_active_mbsfn_area = mbsfn_AreaInfoList->list.count; @@ -966,67 +963,67 @@ rrc_mac_config_req_eNB(module_id_t Mod_idP, } } - if (pmch_InfoList != NULL) { + if (pmch_InfoList != NULL) { - // LOG_I(MAC,"DUY: lcid when entering rrc_mac config_req is %02d\n",(pmch_InfoList->list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9)); + // LOG_I(MAC,"DUY: lcid when entering rrc_mac config_req is %02d\n",(pmch_InfoList->list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9)); - LOG_I(MAC, "[CONFIG] Number of PMCH in this MBSFN Area %d\n", - pmch_InfoList->list.count); + LOG_I(MAC, "[CONFIG] Number of PMCH in this MBSFN Area %d\n", + pmch_InfoList->list.count); - for (i = 0; i < pmch_InfoList->list.count; i++) { - RC.mac[Mod_idP]->common_channels[0].pmch_Config[i] = - &pmch_InfoList->list.array[i]->pmch_Config_r9; + for (i = 0; i < pmch_InfoList->list.count; i++) { + RC.mac[Mod_idP]->common_channels[0].pmch_Config[i] = + &pmch_InfoList->list.array[i]->pmch_Config_r9; - LOG_I(MAC, - "[CONFIG] PMCH[%d]: This PMCH stop (sf_AllocEnd_r9) at subframe %ldth\n", - i, - RC.mac[Mod_idP]->common_channels[0]. - pmch_Config[i]->sf_AllocEnd_r9); - LOG_I(MAC, "[CONFIG] PMCH[%d]: mch_Scheduling_Period = %ld\n", - i, - RC.mac[Mod_idP]->common_channels[0]. - pmch_Config[i]->mch_SchedulingPeriod_r9); - LOG_I(MAC, "[CONFIG] PMCH[%d]: dataMCS = %ld\n", i, - RC.mac[Mod_idP]->common_channels[0]. - pmch_Config[i]->dataMCS_r9); + LOG_I(MAC, + "[CONFIG] PMCH[%d]: This PMCH stop (sf_AllocEnd_r9) at subframe %ldth\n", + i, + RC.mac[Mod_idP]->common_channels[0]. + pmch_Config[i]->sf_AllocEnd_r9); + LOG_I(MAC, "[CONFIG] PMCH[%d]: mch_Scheduling_Period = %ld\n", + i, + RC.mac[Mod_idP]->common_channels[0]. + pmch_Config[i]->mch_SchedulingPeriod_r9); + LOG_I(MAC, "[CONFIG] PMCH[%d]: dataMCS = %ld\n", i, + RC.mac[Mod_idP]->common_channels[0]. + pmch_Config[i]->dataMCS_r9); - // MBMS session info list in each MCH - RC.mac[Mod_idP]->common_channels[0].mbms_SessionList[i] = - &pmch_InfoList->list.array[i]->mbms_SessionInfoList_r9; - LOG_I(MAC, "PMCH[%d] Number of session (MTCH) is: %d\n", i, - RC.mac[Mod_idP]->common_channels[0]. - mbms_SessionList[i]->list.count); - } + // MBMS session info list in each MCH + RC.mac[Mod_idP]->common_channels[0].mbms_SessionList[i] = + &pmch_InfoList->list.array[i]->mbms_SessionInfoList_r9; + LOG_I(MAC, "PMCH[%d] Number of session (MTCH) is: %d\n", i, + RC.mac[Mod_idP]->common_channels[0]. + mbms_SessionList[i]->list.count); } } +} #endif - LOG_E(MAC, "%s() %s:%d RC.mac[Mod_idP]->if_inst->PHY_config_req:%p\n", __FUNCTION__, __FILE__, __LINE__, RC.mac[Mod_idP]->if_inst->PHY_config_req); +LOG_E(MAC, "%s() %s:%d RC.mac[Mod_idP]->if_inst->PHY_config_req:%p\n", __FUNCTION__, __FILE__, __LINE__, RC.mac[Mod_idP]->if_inst->PHY_config_req); - // if in nFAPI mode - if ( - (nfapi_mode == 1 || nfapi_mode == 2) && - (RC.mac[Mod_idP]->if_inst->PHY_config_req == NULL) - ) { - while(RC.mac[Mod_idP]->if_inst->PHY_config_req == NULL) { - // DJP AssertFatal(RC.mac[Mod_idP]->if_inst->PHY_config_req != NULL,"if_inst->phy_config_request is null\n"); - usleep(100 * 1000); - printf("Waiting for PHY_config_req\n"); - } - } +// if in nFAPI mode +if ( + (nfapi_mode == 1 || nfapi_mode == 2) && + (RC.mac[Mod_idP]->if_inst->PHY_config_req == NULL) + ) { + while(RC.mac[Mod_idP]->if_inst->PHY_config_req == NULL) { + // DJP AssertFatal(RC.mac[Mod_idP]->if_inst->PHY_config_req != NULL,"if_inst->phy_config_request is null\n"); + usleep(100 * 1000); + printf("Waiting for PHY_config_req\n"); + } + } - if (radioResourceConfigCommon != NULL) { - PHY_Config_t phycfg; - phycfg.Mod_id = Mod_idP; - phycfg.CC_id = CC_idP; - phycfg.cfg = &RC.mac[Mod_idP]->config[CC_idP]; +if (radioResourceConfigCommon != NULL) { + PHY_Config_t phycfg; + phycfg.Mod_id = Mod_idP; + phycfg.CC_id = CC_idP; + phycfg.cfg = &RC.mac[Mod_idP]->config[CC_idP]; - if (RC.mac[Mod_idP]->if_inst->PHY_config_req) RC.mac[Mod_idP]->if_inst->PHY_config_req(&phycfg); + if (RC.mac[Mod_idP]->if_inst->PHY_config_req) RC.mac[Mod_idP]->if_inst->PHY_config_req(&phycfg); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); - } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); + } - return(0); +return(0); } int diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index f03a3961f6..94eacb6e00 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -74,409 +74,282 @@ uint16_t pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 }; void schedule_SRS(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) { - eNB_MAC_INST *eNB = RC.mac[module_idP]; - UE_list_t *UE_list = &eNB->UE_list; - nfapi_ul_config_request_body_t *ul_req; - int CC_id, UE_id; - COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; - SoundingRS_UL_ConfigCommon_t *soundingRS_UL_ConfigCommon; - struct SoundingRS_UL_ConfigDedicated *soundingRS_UL_ConfigDedicated; - uint8_t TSFC; - uint16_t deltaTSFC; // bitmap - uint8_t srs_SubframeConfig; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + UE_list_t *UE_list = &eNB->UE_list; + nfapi_ul_config_request_body_t *ul_req; + int CC_id, UE_id; + COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; + SoundingRS_UL_ConfigCommon_t *soundingRS_UL_ConfigCommon; + struct SoundingRS_UL_ConfigDedicated *soundingRS_UL_ConfigDedicated; + uint8_t TSFC; + uint16_t deltaTSFC; // bitmap + uint8_t srs_SubframeConfig; - // table for TSFC (Period) and deltaSFC (offset) - const uint16_t deltaTSFCTabType1[15][2] = { {1, 1}, {1, 2}, {2, 2}, {1, 5}, {2, 5}, {4, 5}, {8, 5}, {3, 5}, {12, 5}, {1, 10}, {2, 10}, {4, 10}, {8, 10}, {351, 10}, {383, 10} }; // Table 5.5.3.3-2 3GPP 36.211 FDD - const uint16_t deltaTSFCTabType2[14][2] = { {2, 5}, {6, 5}, {10, 5}, {18, 5}, {14, 5}, {22, 5}, {26, 5}, {30, 5}, {70, 10}, {74, 10}, {194, 10}, {326, 10}, {586, 10}, {210, 10} }; // Table 5.5.3.3-2 3GPP 36.211 TDD + // table for TSFC (Period) and deltaSFC (offset) + const uint16_t deltaTSFCTabType1[15][2] = { {1, 1}, {1, 2}, {2, 2}, {1, 5}, {2, 5}, {4, 5}, {8, 5}, {3, 5}, {12, 5}, {1, 10}, {2, 10}, {4, 10}, {8, 10}, {351, 10}, {383, 10} }; // Table 5.5.3.3-2 3GPP 36.211 FDD + const uint16_t deltaTSFCTabType2[14][2] = { {2, 5}, {6, 5}, {10, 5}, {18, 5}, {14, 5}, {22, 5}, {26, 5}, {30, 5}, {70, 10}, {74, 10}, {194, 10}, {326, 10}, {586, 10}, {210, 10} }; // Table 5.5.3.3-2 3GPP 36.211 TDD - uint16_t srsPeriodicity, srsOffset; + uint16_t srsPeriodicity, srsOffset; - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - soundingRS_UL_ConfigCommon = - &cc[CC_id].radioResourceConfigCommon-> - soundingRS_UL_ConfigCommon; - // check if SRS is enabled in this frame/subframe - if (soundingRS_UL_ConfigCommon) { - srs_SubframeConfig = - soundingRS_UL_ConfigCommon->choice.setup. - srs_SubframeConfig; - if (cc[CC_id].tdd_Config == NULL) { // FDD - deltaTSFC = deltaTSFCTabType1[srs_SubframeConfig][0]; - TSFC = deltaTSFCTabType1[srs_SubframeConfig][1]; - } else { // TDD - deltaTSFC = deltaTSFCTabType2[srs_SubframeConfig][0]; - TSFC = deltaTSFCTabType2[srs_SubframeConfig][1]; - } - // Sounding reference signal subframes are the subframes satisfying ns/2 mod TSFC (- deltaTSFC - uint16_t tmp = (subframeP % TSFC); + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + soundingRS_UL_ConfigCommon = &cc[CC_id].radioResourceConfigCommon->soundingRS_UL_ConfigCommon; + // check if SRS is enabled in this frame/subframe + if (soundingRS_UL_ConfigCommon) { + srs_SubframeConfig = soundingRS_UL_ConfigCommon->choice.setup.srs_SubframeConfig; + if (cc[CC_id].tdd_Config == NULL) { // FDD + deltaTSFC = deltaTSFCTabType1[srs_SubframeConfig][0]; + TSFC = deltaTSFCTabType1[srs_SubframeConfig][1]; + } else { // TDD + deltaTSFC = deltaTSFCTabType2[srs_SubframeConfig][0]; + TSFC = deltaTSFCTabType2[srs_SubframeConfig][1]; + } + // Sounding reference signal subframes are the subframes satisfying ns/2 mod TSFC (- deltaTSFC + uint16_t tmp = (subframeP % TSFC); - if ((1 << tmp) & deltaTSFC) { - // This is an SRS subframe, loop over UEs - for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { - if (RC.mac[module_idP]->UE_list.active[UE_id] != TRUE) - continue; - ul_req = - &RC.mac[module_idP]->UL_req[CC_id]. - ul_config_request_body; + if ((1 << tmp) & deltaTSFC) { + // This is an SRS subframe, loop over UEs + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { + if (RC.mac[module_idP]->UE_list.active[UE_id] != TRUE) continue; + ul_req = &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body; + // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet + if (mac_eNB_get_rrc_status(module_idP,UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) continue; + AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL, + "physicalConfigDedicated is null for UE %d\n", + UE_id); - // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet - if (mac_eNB_get_rrc_status - (module_idP, - UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) - continue; + if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated) != NULL) { + if (soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) { + get_srs_pos(&cc[CC_id], + soundingRS_UL_ConfigDedicated->choice. + setup.srs_ConfigIndex, + &srsPeriodicity, &srsOffset); + if (((10 * frameP + subframeP) % srsPeriodicity) == srsOffset) { + // Program SRS + ul_req->srs_present = 1; + nfapi_ul_config_request_pdu_t *ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; + memset((void *) ul_config_pdu, 0, + sizeof + (nfapi_ul_config_request_pdu_t)); + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_SRS_PDU_TYPE; + ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_srs_pdu)); + ul_config_pdu->srs_pdu.srs_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL8_TAG; + ul_config_pdu->srs_pdu.srs_pdu_rel8.size = (uint8_t)sizeof(nfapi_ul_config_srs_pdu);; + ul_config_pdu->srs_pdu.srs_pdu_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; + ul_config_pdu->srs_pdu.srs_pdu_rel8.srs_bandwidth = soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth; + ul_config_pdu->srs_pdu.srs_pdu_rel8.frequency_domain_position = soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition; + ul_config_pdu->srs_pdu.srs_pdu_rel8.srs_hopping_bandwidth = soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth;; + ul_config_pdu->srs_pdu.srs_pdu_rel8.transmission_comb = soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb; + ul_config_pdu->srs_pdu.srs_pdu_rel8.i_srs = soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex; + ul_config_pdu->srs_pdu.srs_pdu_rel8.sounding_reference_cyclic_shift = soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift; + // ul_config_pdu->srs_pdu.srs_pdu_rel10.antenna_port = ;// + // ul_config_pdu->srs_pdu.srs_pdu_rel13.number_of_combs = ;// + RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; + RC.mac[module_idP]->UL_req[CC_id].header.message_id = NFAPI_UL_CONFIG_REQUEST; + ul_req->number_of_pdus++; + } // if (((10*frameP+subframeP) % srsPeriodicity) == srsOffset) + } // if (soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) + } // if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated)!=NULL) + } // for (UE_id ... + } // if((1<UE_template[CC_id] - [UE_id].physicalConfigDedicated != NULL, - "physicalConfigDedicated is null for UE %d\n", - UE_id); - - if ((soundingRS_UL_ConfigDedicated = - UE_list->UE_template[CC_id] - [UE_id]. - physicalConfigDedicated->soundingRS_UL_ConfigDedicated) - != NULL) { - if (soundingRS_UL_ConfigDedicated->present == - SoundingRS_UL_ConfigDedicated_PR_setup) { - get_srs_pos(&cc[CC_id], - soundingRS_UL_ConfigDedicated->choice. - setup.srs_ConfigIndex, - &srsPeriodicity, &srsOffset); - if (((10 * frameP + - subframeP) % srsPeriodicity) == - srsOffset) { - // Program SRS - ul_req->srs_present = 1; - nfapi_ul_config_request_pdu_t - * ul_config_pdu = - &ul_req-> - ul_config_pdu_list - [ul_req->number_of_pdus]; - memset((void *) ul_config_pdu, 0, - sizeof - (nfapi_ul_config_request_pdu_t)); - ul_config_pdu->pdu_type = - NFAPI_UL_CONFIG_SRS_PDU_TYPE; - ul_config_pdu->pdu_size = - 2 + (uint8_t) (2 + - sizeof - (nfapi_ul_config_srs_pdu)); - ul_config_pdu->srs_pdu.srs_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL8_TAG; - ul_config_pdu->srs_pdu.srs_pdu_rel8.size = - (uint8_t) - sizeof(nfapi_ul_config_srs_pdu);; - ul_config_pdu->srs_pdu.srs_pdu_rel8.rnti = - UE_list->UE_template[CC_id][UE_id]. - rnti; - ul_config_pdu->srs_pdu. - srs_pdu_rel8.srs_bandwidth = - soundingRS_UL_ConfigDedicated-> - choice.setup.srs_Bandwidth; - ul_config_pdu->srs_pdu. - srs_pdu_rel8.frequency_domain_position - = - soundingRS_UL_ConfigDedicated-> - choice.setup.freqDomainPosition; - ul_config_pdu->srs_pdu. - srs_pdu_rel8.srs_hopping_bandwidth = - soundingRS_UL_ConfigDedicated-> - choice.setup.srs_HoppingBandwidth;; - ul_config_pdu->srs_pdu. - srs_pdu_rel8.transmission_comb = - soundingRS_UL_ConfigDedicated-> - choice.setup.transmissionComb; - ul_config_pdu->srs_pdu.srs_pdu_rel8.i_srs = - soundingRS_UL_ConfigDedicated-> - choice.setup.srs_ConfigIndex; - ul_config_pdu->srs_pdu. - srs_pdu_rel8.sounding_reference_cyclic_shift - = - soundingRS_UL_ConfigDedicated-> - choice.setup.cyclicShift; - // ul_config_pdu->srs_pdu.srs_pdu_rel10.antenna_port = ;// - // ul_config_pdu->srs_pdu.srs_pdu_rel13.number_of_combs = ;// - RC.mac[module_idP]->UL_req[CC_id].sfn_sf = - (frameP << 4) + subframeP; - RC.mac[module_idP]->UL_req[CC_id].header.message_id = NFAPI_UL_CONFIG_REQUEST; - ul_req->number_of_pdus++; - } // if (((10*frameP+subframeP) % srsPeriodicity) == srsOffset) - } // if (soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) - } // if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated)!=NULL) - } // for (UE_id ... - } // if((1<UE_list; - COMMON_channels_t *cc; - nfapi_ul_config_request_body_t *ul_req; - int CC_id, UE_id; - struct CQI_ReportPeriodic *cqi_ReportPeriodic; - uint16_t Npd, N_OFFSET_CQI; - int H; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + UE_list_t *UE_list = &eNB->UE_list; + COMMON_channels_t *cc; + nfapi_ul_config_request_body_t *ul_req; + int CC_id, UE_id; + struct CQI_ReportPeriodic *cqi_ReportPeriodic; + uint16_t Npd, N_OFFSET_CQI; + int H; - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - cc = &eNB->common_channels[CC_id]; - for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { - if (UE_list->active[UE_id] != TRUE) - continue; + cc = &eNB->common_channels[CC_id]; + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { + if (UE_list->active[UE_id] != TRUE) + continue; - ul_req = - &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body; + ul_req = &RC.mac[module_idP]->UL_req[CC_id].ul_config_request_body; - // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet - if (mac_eNB_get_rrc_status - (module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) - continue; + // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet + if (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) continue; - AssertFatal(UE_list-> - UE_template[CC_id][UE_id].physicalConfigDedicated - != NULL, - "physicalConfigDedicated is null for UE %d\n", - UE_id); + AssertFatal(UE_list-> + UE_template[CC_id][UE_id].physicalConfigDedicated + != NULL, + "physicalConfigDedicated is null for UE %d\n", + UE_id); - if (UE_list-> - UE_template[CC_id][UE_id].physicalConfigDedicated-> - cqi_ReportConfig) { - if ((cqi_ReportPeriodic = - UE_list-> - UE_template[CC_id][UE_id].physicalConfigDedicated-> - cqi_ReportConfig->cqi_ReportPeriodic) != NULL - && (cqi_ReportPeriodic->present != - CQI_ReportPeriodic_PR_release)) { - //Rel8 Periodic CQI/PMI/RI reporting + if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig) { + if ((cqi_ReportPeriodic = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic) != NULL + && (cqi_ReportPeriodic->present != CQI_ReportPeriodic_PR_release)) { + //Rel8 Periodic CQI/PMI/RI reporting - get_csi_params(cc, cqi_ReportPeriodic, &Npd, - &N_OFFSET_CQI, &H); + get_csi_params(cc, cqi_ReportPeriodic, &Npd, + &N_OFFSET_CQI, &H); - if ((((frameP * 10) + subframeP) % Npd) == N_OFFSET_CQI) { // CQI opportunity - UE_list->UE_sched_ctrl[UE_id].feedback_cnt[CC_id] = - (((frameP * 10) + subframeP) / Npd) % H; - // Program CQI - nfapi_ul_config_request_pdu_t *ul_config_pdu = - &ul_req->ul_config_pdu_list[ul_req-> - number_of_pdus]; - memset((void *) ul_config_pdu, 0, - sizeof(nfapi_ul_config_request_pdu_t)); - ul_config_pdu->pdu_type = - NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; - ul_config_pdu->pdu_size = - 2 + (uint8_t) (2 + - sizeof - (nfapi_ul_config_uci_cqi_pdu)); - ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; - ul_config_pdu->uci_cqi_pdu. - ue_information.ue_information_rel8.rnti = - UE_list->UE_template[CC_id][UE_id].rnti; - ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG; - ul_config_pdu->uci_cqi_pdu. - cqi_information.cqi_information_rel8. - pucch_index = - cqi_ReportPeriodic->choice. - setup.cqi_PUCCH_ResourceIndex; - ul_config_pdu->uci_cqi_pdu. - cqi_information.cqi_information_rel8. - dl_cqi_pmi_size = - get_rel8_dl_cqi_pmi_size - (&UE_list->UE_sched_ctrl[UE_id], CC_id, cc, - get_tmode(module_idP, CC_id, UE_id), - cqi_ReportPeriodic); - ul_req->number_of_pdus++; - ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + if ((((frameP * 10) + subframeP) % Npd) == N_OFFSET_CQI) { // CQI opportunity + UE_list->UE_sched_ctrl[UE_id].feedback_cnt[CC_id] = (((frameP * 10) + subframeP) / Npd) % H; + // Program CQI + nfapi_ul_config_request_pdu_t *ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; + memset((void *) ul_config_pdu, 0, + sizeof(nfapi_ul_config_request_pdu_t)); + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; + ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_uci_cqi_pdu)); + ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; + ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; + ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG; + ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.pucch_index = cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex; + ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = get_rel8_dl_cqi_pmi_size(&UE_list->UE_sched_ctrl[UE_id], CC_id, cc, + get_tmode(module_idP, CC_id, UE_id), + cqi_ReportPeriodic); + ul_req->number_of_pdus++; + ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; #if defined(Rel10) || defined(Rel14) - // PUT rel10-13 UCI options here + // PUT rel10-13 UCI options here #endif - } else - if ((cqi_ReportPeriodic->choice.setup. - ri_ConfigIndex) - && ((((frameP * 10) + subframeP) % ((H * Npd) << (*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex / 161))) == N_OFFSET_CQI + (*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex % 161))) { // RI opportunity - // Program RI - nfapi_ul_config_request_pdu_t *ul_config_pdu = - &ul_req->ul_config_pdu_list[ul_req-> - number_of_pdus]; - memset((void *) ul_config_pdu, 0, - sizeof(nfapi_ul_config_request_pdu_t)); - ul_config_pdu->pdu_type = - NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; - ul_config_pdu->pdu_size = - 2 + (uint8_t) (2 + - sizeof - (nfapi_ul_config_uci_cqi_pdu)); - ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; - ul_config_pdu->uci_cqi_pdu. - ue_information.ue_information_rel8.rnti = - UE_list->UE_template[CC_id][UE_id].rnti; - ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG; - ul_config_pdu->uci_cqi_pdu. - cqi_information.cqi_information_rel8. - pucch_index = - cqi_ReportPeriodic->choice. - setup.cqi_PUCCH_ResourceIndex; - ul_config_pdu->uci_cqi_pdu. - cqi_information.cqi_information_rel8. - dl_cqi_pmi_size = (cc->p_eNB == 2) ? 1 : 2; - RC.mac[module_idP]->UL_req[CC_id].sfn_sf = - (frameP << 4) + subframeP; - ul_req->number_of_pdus++; - ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; - } - - } // if ((cqi_ReportPeriodic = cqi_ReportConfig->cqi_ReportPeriodic)!=NULL) { - } // if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig) - } // for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { - } // for (CC_id=0; CC_idchoice.setup.ri_ConfigIndex) + && ((((frameP * 10) + subframeP) % ((H * Npd) << (*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex / 161))) == N_OFFSET_CQI + (*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex % 161))) { // RI opportunity + // Program RI + nfapi_ul_config_request_pdu_t *ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; + memset((void *) ul_config_pdu, 0, + sizeof(nfapi_ul_config_request_pdu_t)); + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; + ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_uci_cqi_pdu)); + ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; + ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; + ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG; + ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.pucch_index = cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex; + ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = (cc->p_eNB == 2) ? 1 : 2; + RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; + ul_req->number_of_pdus++; + ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + } + } // if ((cqi_ReportPeriodic = cqi_ReportConfig->cqi_ReportPeriodic)!=NULL) { + } // if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig) + } // for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { + } // for (CC_id=0; CC_idUE_list; - nfapi_ul_config_request_t *ul_req; - nfapi_ul_config_request_body_t *ul_req_body; - int CC_id; - int UE_id; - SchedulingRequestConfig_t *SRconfig; - int skip_ue; - int is_harq; - nfapi_ul_config_sr_information sr; - int i; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + UE_list_t *UE_list = &eNB->UE_list; + nfapi_ul_config_request_t *ul_req; + nfapi_ul_config_request_body_t *ul_req_body; + int CC_id; + int UE_id; + SchedulingRequestConfig_t *SRconfig; + int skip_ue; + int is_harq; + nfapi_ul_config_sr_information sr; + int i; - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - RC.mac[module_idP]->UL_req[CC_id].sfn_sf = - (frameP << 4) + subframeP; + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; - for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { - if (RC.mac[module_idP]->UE_list.active[UE_id] != TRUE) - continue; + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { + if (RC.mac[module_idP]->UE_list.active[UE_id] != TRUE) continue; - ul_req = &RC.mac[module_idP]->UL_req[CC_id]; - ul_req_body = &ul_req->ul_config_request_body; + ul_req = &RC.mac[module_idP]->UL_req[CC_id]; + ul_req_body = &ul_req->ul_config_request_body; - // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet - if (mac_eNB_get_rrc_status - (module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) - continue; + // drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet + if (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) continue; - AssertFatal(UE_list-> - UE_template[CC_id][UE_id].physicalConfigDedicated - != NULL, - "physicalConfigDedicated is null for UE %d\n", - UE_id); + AssertFatal(UE_list-> + UE_template[CC_id][UE_id].physicalConfigDedicated!= NULL, + "physicalConfigDedicated is null for UE %d\n", + UE_id); - if ((SRconfig = - UE_list-> - UE_template[CC_id][UE_id].physicalConfigDedicated-> - schedulingRequestConfig) != NULL) { - if (SRconfig->present == SchedulingRequestConfig_PR_setup) { - if (SRconfig->choice.setup.sr_ConfigIndex <= 4) { // 5 ms SR period - if ((subframeP % 5) != - SRconfig->choice.setup.sr_ConfigIndex) - continue; - } else if (SRconfig->choice.setup.sr_ConfigIndex <= 14) { // 10 ms SR period - if (subframeP != - (SRconfig->choice.setup.sr_ConfigIndex - 5)) - continue; - } else if (SRconfig->choice.setup.sr_ConfigIndex <= 34) { // 20 ms SR period - if ((10 * (frameP & 1) + subframeP) != - (SRconfig->choice.setup.sr_ConfigIndex - 15)) - continue; - } else if (SRconfig->choice.setup.sr_ConfigIndex <= 74) { // 40 ms SR period - if ((10 * (frameP & 3) + subframeP) != - (SRconfig->choice.setup.sr_ConfigIndex - 35)) - continue; - } else if (SRconfig->choice.setup.sr_ConfigIndex <= 154) { // 80 ms SR period - if ((10 * (frameP & 7) + subframeP) != - (SRconfig->choice.setup.sr_ConfigIndex - 75)) - continue; - } - } // SRconfig->present == SchedulingRequestConfig_PR_setup) - } // SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig)!=NULL) + if ((SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig) != NULL) { + if (SRconfig->present == SchedulingRequestConfig_PR_setup) { + if (SRconfig->choice.setup.sr_ConfigIndex <= 4) { // 5 ms SR period + if ((subframeP % 5) != SRconfig->choice.setup.sr_ConfigIndex) continue; + } else if (SRconfig->choice.setup.sr_ConfigIndex <= 14) { // 10 ms SR period + if (subframeP != (SRconfig->choice.setup.sr_ConfigIndex - 5)) continue; + } else if (SRconfig->choice.setup.sr_ConfigIndex <= 34) { // 20 ms SR period + if ((10 * (frameP & 1) + subframeP) != (SRconfig->choice.setup.sr_ConfigIndex - 15)) continue; + } else if (SRconfig->choice.setup.sr_ConfigIndex <= 74) { // 40 ms SR period + if ((10 * (frameP & 3) + subframeP) != (SRconfig->choice.setup.sr_ConfigIndex - 35)) continue; + } else if (SRconfig->choice.setup.sr_ConfigIndex <= 154) { // 80 ms SR period + if ((10 * (frameP & 7) + subframeP) != (SRconfig->choice.setup.sr_ConfigIndex - 75)) continue; + } + } // SRconfig->present == SchedulingRequestConfig_PR_setup) + } // SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig)!=NULL) - // if we get here there is some PUCCH1 reception to schedule for SR + // if we get here there is some PUCCH1 reception to schedule for SR - skip_ue = 0; - is_harq = 0; - // check that there is no existing UL grant for ULSCH which overrides the SR - for (i = 0; i < ul_req_body->number_of_pdus; i++) { - if (((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) || - (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE) || - (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) || - (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE)) && - (ul_req_body->ul_config_pdu_list[i].ulsch_pdu.ulsch_pdu_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) { - skip_ue = 1; - break; - } - /* if there is already an HARQ pdu, convert to SR_HARQ */ - else if ((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) && - (ul_req_body->ul_config_pdu_list[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) { - is_harq = 1; - break; - } - } + skip_ue = 0; + is_harq = 0; + // check that there is no existing UL grant for ULSCH which overrides the SR + for (i = 0; i < ul_req_body->number_of_pdus; i++) { + if (((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) || + (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE) || + (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) || + (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE)) && + (ul_req_body->ul_config_pdu_list[i].ulsch_pdu.ulsch_pdu_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) { + skip_ue = 1; + break; + } + /* if there is already an HARQ pdu, convert to SR_HARQ */ + else if ((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) && + (ul_req_body->ul_config_pdu_list[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) { + is_harq = 1; + break; + } + } - // drop the allocation because ULSCH with handle it with BSR - if (skip_ue == 1) - continue; + // drop the allocation because ULSCH with handle it with BSR + if (skip_ue == 1) continue; - LOG_D(MAC,"Frame %d, Subframe %d : Scheduling SR for UE %d/%x is_harq:%d\n",frameP,subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].rnti, is_harq); + LOG_D(MAC,"Frame %d, Subframe %d : Scheduling SR for UE %d/%x is_harq:%d\n",frameP,subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].rnti, is_harq); - // check Rel10 or Rel8 SR + // check Rel10 or Rel8 SR #if defined(Rel10) || defined(Rel14) - if ((UE_list-> - UE_template[CC_id][UE_id].physicalConfigDedicated->ext2) - && (UE_list-> - UE_template[CC_id][UE_id].physicalConfigDedicated-> - ext2->schedulingRequestConfig_v1020) - && (UE_list-> - UE_template[CC_id][UE_id].physicalConfigDedicated-> - ext2->schedulingRequestConfig_v1020)) { - sr.sr_information_rel10.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL10_TAG; - sr.sr_information_rel10.number_of_pucch_resources = 1; - sr.sr_information_rel10.pucch_index_p1 = - *UE_list-> - UE_template[CC_id][UE_id].physicalConfigDedicated-> - ext2-> - schedulingRequestConfig_v1020->sr_PUCCH_ResourceIndexP1_r10; - LOG_D(MAC,"REL10 PUCCH INDEX P1:%d\n", sr.sr_information_rel10.pucch_index_p1); - } else + if ((UE_list-> UE_template[CC_id][UE_id].physicalConfigDedicated->ext2) + && (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020) + && (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020)) { + sr.sr_information_rel10.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL10_TAG; + sr.sr_information_rel10.number_of_pucch_resources = 1; + sr.sr_information_rel10.pucch_index_p1 = *UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020->sr_PUCCH_ResourceIndexP1_r10; + LOG_D(MAC,"REL10 PUCCH INDEX P1:%d\n", sr.sr_information_rel10.pucch_index_p1); + } else #endif - { - sr.sr_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL8_TAG; - sr.sr_information_rel8.pucch_index = - UE_list-> - UE_template[CC_id][UE_id].physicalConfigDedicated-> - schedulingRequestConfig->choice.setup. - sr_PUCCH_ResourceIndex; - LOG_D(MAC,"REL8 PUCCH INDEX:%d\n", sr.sr_information_rel8.pucch_index); - } + { + sr.sr_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL8_TAG; + sr.sr_information_rel8.pucch_index = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig->choice.setup.sr_PUCCH_ResourceIndex; + LOG_D(MAC,"REL8 PUCCH INDEX:%d\n", sr.sr_information_rel8.pucch_index); + } - /* if there is already an HARQ pdu, convert to SR_HARQ */ - if (is_harq) { - nfapi_ul_config_harq_information h = ul_req_body->ul_config_pdu_list[i].uci_harq_pdu.harq_information; - ul_req_body->ul_config_pdu_list[i].pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; - ul_req_body->ul_config_pdu_list[i].uci_sr_harq_pdu.sr_information = sr; - ul_req_body->ul_config_pdu_list[i].uci_sr_harq_pdu.harq_information = h; - } else { - ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].pdu_type = NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE; - ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; - ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; - ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel11.tl.tag = 0; - ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel13.tl.tag = 0; - ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.sr_information = sr; - ul_req_body->number_of_pdus++; - } /* if (is_harq) */ - ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; - } // for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) - } // for (CC_id=0; CC_idul_config_pdu_list[i].uci_harq_pdu.harq_information; + ul_req_body->ul_config_pdu_list[i].pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; + ul_req_body->ul_config_pdu_list[i].uci_sr_harq_pdu.sr_information = sr; + ul_req_body->ul_config_pdu_list[i].uci_sr_harq_pdu.harq_information = h; + } else { + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].pdu_type = NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel11.tl.tag = 0; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel13.tl.tag = 0; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.sr_information = sr; + ul_req_body->number_of_pdus++; + } /* if (is_harq) */ + ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + } // for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) + } // for (CC_id=0; CC_idUE_list; - nfapi_dl_config_request_t *DL_req = &RC.mac[module_idP]->DL_req[0]; - uint16_t rnti = UE_RNTI(module_idP, UE_id); - COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; + UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; + nfapi_dl_config_request_t *DL_req = &RC.mac[module_idP]->DL_req[0]; + uint16_t rnti = UE_RNTI(module_idP, UE_id); + COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; - // check uplink failure - if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 0) && - (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 0)) { - LOG_I(MAC, "UE %d rnti %x: UL Failure timer %d \n", UE_id, rnti, - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); - if (UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent == 0) { - UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 1; + // check uplink failure + if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 0) && + (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 0)) { + LOG_I(MAC, "UE %d rnti %x: UL Failure timer %d \n", UE_id, rnti, + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); + if (UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent == 0) { + UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 1; - // add a format 1A dci for this UE to request an RA procedure (only one UE per subframe) - nfapi_dl_config_request_pdu_t *dl_config_pdu = - &DL_req[CC_id]. - dl_config_request_body.dl_config_pdu_list[DL_req[CC_id]. - dl_config_request_body.number_pdu]; - memset((void *) dl_config_pdu, 0, - sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = - NFAPI_DL_DCI_FORMAT_1A; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = - get_aggregation(get_bw_index(module_idP, CC_id), - UE_list->UE_sched_ctrl[UE_id]. - dl_cqi[CC_id], format1A); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + // add a format 1A dci for this UE to request an RA procedure (only one UE per subframe) + nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req[CC_id].dl_config_request_body.dl_config_pdu_list[DL_req[CC_id].dl_config_request_body.number_pdu]; + memset((void *) dl_config_pdu, 0,sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP, CC_id), + UE_list->UE_sched_ctrl[UE_id]. + dl_cqi[CC_id], format1A); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power - AssertFatal((cc[CC_id].mib->message.dl_Bandwidth >= 0) - && (cc[CC_id].mib->message.dl_Bandwidth < 6), - "illegal dl_Bandwidth %d\n", - (int) cc[CC_id].mib->message.dl_Bandwidth); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - resource_block_coding = - pdcch_order_table[cc[CC_id].mib->message.dl_Bandwidth]; - DL_req[CC_id].dl_config_request_body.number_dci++; - DL_req[CC_id].dl_config_request_body.number_pdu++; - DL_req[CC_id].dl_config_request_body.tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; - LOG_I(MAC, - "UE %d rnti %x: sending PDCCH order for RAPROC (failure timer %d), resource_block_coding %d \n", - UE_id, rnti, - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer, - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.resource_block_coding); - } else { // ra_pdcch_sent==1 - LOG_I(MAC, - "UE %d rnti %x: sent PDCCH order for RAPROC waiting (failure timer %d) \n", - UE_id, rnti, - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); - if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer % 40) == 0) - UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 0; // resend every 4 frames - } + AssertFatal((cc[CC_id].mib->message.dl_Bandwidth >= 0) && (cc[CC_id].mib->message.dl_Bandwidth < 6), + "illegal dl_Bandwidth %d\n", + (int) cc[CC_id].mib->message.dl_Bandwidth); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = pdcch_order_table[cc[CC_id].mib->message.dl_Bandwidth]; + DL_req[CC_id].dl_config_request_body.number_dci++; + DL_req[CC_id].dl_config_request_body.number_pdu++; + DL_req[CC_id].dl_config_request_body.tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + LOG_I(MAC, + "UE %d rnti %x: sending PDCCH order for RAPROC (failure timer %d), resource_block_coding %d \n", + UE_id, rnti, + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer, + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.resource_block_coding); + } else { // ra_pdcch_sent==1 + LOG_I(MAC, + "UE %d rnti %x: sent PDCCH order for RAPROC waiting (failure timer %d) \n", + UE_id, rnti, + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); + if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer % 40) == 0) UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 0; // resend every 4 frames + } - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer++; - // check threshold - if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 200) { - // inform RRC of failure and clear timer - LOG_I(MAC, - "UE %d rnti %x: UL Failure after repeated PDCCH orders: Triggering RRC \n", - UE_id, rnti); - mac_eNB_rrc_ul_failure(module_idP, CC_id, frameP, subframeP, - rnti); - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; - UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 1; - } - } // ul_failure_timer>0 + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer++; + // check threshold + if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 200) { + // inform RRC of failure and clear timer + LOG_I(MAC, + "UE %d rnti %x: UL Failure after repeated PDCCH orders: Triggering RRC \n", + UE_id, rnti); + mac_eNB_rrc_ul_failure(module_idP, CC_id, frameP, subframeP,rnti); + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; + UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 1; + } + } // ul_failure_timer>0 } @@ -564,63 +425,61 @@ void clear_nfapi_information(eNB_MAC_INST * eNB, int CC_idP, frame_t frameP, sub_frame_t subframeP) { - nfapi_dl_config_request_t *DL_req = &eNB->DL_req[0]; - nfapi_ul_config_request_t *UL_req = &eNB->UL_req[0]; - nfapi_hi_dci0_request_t *HI_DCI0_req = &eNB->HI_DCI0_req[0]; - nfapi_tx_request_t *TX_req = &eNB->TX_req[0]; + nfapi_dl_config_request_t *DL_req = &eNB->DL_req[0]; + nfapi_ul_config_request_t *UL_req = &eNB->UL_req[0]; + nfapi_hi_dci0_request_t *HI_DCI0_req = &eNB->HI_DCI0_req[0]; + nfapi_tx_request_t *TX_req = &eNB->TX_req[0]; - eNB->pdu_index[CC_idP] = 0; + eNB->pdu_index[CC_idP] = 0; - if (nfapi_mode==0 || nfapi_mode == 1) { // monolithic or PNF + if (nfapi_mode==0 || nfapi_mode == 1) { // monolithic or PNF - DL_req[CC_idP].dl_config_request_body.number_pdcch_ofdm_symbols = 1; - DL_req[CC_idP].dl_config_request_body.number_dci = 0; - DL_req[CC_idP].dl_config_request_body.number_pdu = 0; - DL_req[CC_idP].dl_config_request_body.number_pdsch_rnti = 0; - DL_req[CC_idP].dl_config_request_body.transmission_power_pcfich = 6000; + DL_req[CC_idP].dl_config_request_body.number_pdcch_ofdm_symbols = 1; + DL_req[CC_idP].dl_config_request_body.number_dci = 0; + DL_req[CC_idP].dl_config_request_body.number_pdu = 0; + DL_req[CC_idP].dl_config_request_body.number_pdsch_rnti = 0; + DL_req[CC_idP].dl_config_request_body.transmission_power_pcfich = 6000; - HI_DCI0_req[CC_idP].hi_dci0_request_body.sfnsf = subframeP + (frameP<<4); - HI_DCI0_req[CC_idP].hi_dci0_request_body.number_of_dci = 0; + HI_DCI0_req[CC_idP].hi_dci0_request_body.sfnsf = subframeP + (frameP<<4); + HI_DCI0_req[CC_idP].hi_dci0_request_body.number_of_dci = 0; - UL_req[CC_idP].ul_config_request_body.number_of_pdus = 0; - UL_req[CC_idP].ul_config_request_body.rach_prach_frequency_resources = 0; // ignored, handled by PHY for now - UL_req[CC_idP].ul_config_request_body.srs_present = 0; // ignored, handled by PHY for now + UL_req[CC_idP].ul_config_request_body.number_of_pdus = 0; + UL_req[CC_idP].ul_config_request_body.rach_prach_frequency_resources = 0; // ignored, handled by PHY for now + UL_req[CC_idP].ul_config_request_body.srs_present = 0; // ignored, handled by PHY for now - TX_req[CC_idP].tx_request_body.number_of_pdus = 0; + TX_req[CC_idP].tx_request_body.number_of_pdus = 0; - } + } } void copy_ulreq(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) { - int CC_id; - eNB_MAC_INST *mac = RC.mac[module_idP]; + int CC_id; + eNB_MAC_INST *mac = RC.mac[module_idP]; - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - nfapi_ul_config_request_t *ul_req_tmp = &mac->UL_req_tmp[CC_id][subframeP]; - nfapi_ul_config_request_t *ul_req = &mac->UL_req[CC_id]; - nfapi_ul_config_request_pdu_t *ul_req_pdu = ul_req->ul_config_request_body.ul_config_pdu_list; + nfapi_ul_config_request_t *ul_req_tmp = &mac->UL_req_tmp[CC_id][subframeP]; + nfapi_ul_config_request_t *ul_req = &mac->UL_req[CC_id]; + nfapi_ul_config_request_pdu_t *ul_req_pdu = ul_req->ul_config_request_body.ul_config_pdu_list; - *ul_req = *ul_req_tmp; + *ul_req = *ul_req_tmp; - // Restore the pointer - ul_req->ul_config_request_body.ul_config_pdu_list = ul_req_pdu; + // Restore the pointer + ul_req->ul_config_request_body.ul_config_pdu_list = ul_req_pdu; + ul_req->sfn_sf = (frameP<<4) + subframeP; + ul_req_tmp->ul_config_request_body.number_of_pdus = 0; - ul_req->sfn_sf = (frameP<<4) + subframeP; - - ul_req_tmp->ul_config_request_body.number_of_pdus = 0; - - if (ul_req->ul_config_request_body.number_of_pdus>0) + if (ul_req->ul_config_request_body.number_of_pdus>0) { LOG_D(PHY, "%s() active NOW (frameP:%d subframeP:%d) pdus:%d\n", __FUNCTION__, frameP, subframeP, ul_req->ul_config_request_body.number_of_pdus); } - memcpy((void*)ul_req->ul_config_request_body.ul_config_pdu_list, - (void*)ul_req_tmp->ul_config_request_body.ul_config_pdu_list, - ul_req->ul_config_request_body.number_of_pdus*sizeof(nfapi_ul_config_request_pdu_t)); + memcpy((void*)ul_req->ul_config_request_body.ul_config_pdu_list, + (void*)ul_req_tmp->ul_config_request_body.ul_config_pdu_list, + ul_req->ul_config_request_body.number_of_pdus*sizeof(nfapi_ul_config_request_pdu_t)); } } @@ -629,133 +488,127 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) { - int mbsfn_status[MAX_NUM_CCs]; - protocol_ctxt_t ctxt; + int mbsfn_status[MAX_NUM_CCs]; + protocol_ctxt_t ctxt; - int CC_id, i; //,next_i; - UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; - rnti_t rnti; + int CC_id, i; + UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; + rnti_t rnti; - COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; + COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; #if defined(FLEXRAN_AGENT_SB_IF) - Protocol__FlexranMessage *msg; + Protocol__FlexranMessage *msg; #endif - start_meas(&RC.mac[module_idP]->eNB_scheduler); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, - VCD_FUNCTION_IN); + start_meas(&RC.mac[module_idP]->eNB_scheduler); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, + VCD_FUNCTION_IN); - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - mbsfn_status[CC_id] = 0; + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + mbsfn_status[CC_id] = 0; - // clear vrb_maps - memset(cc[CC_id].vrb_map, 0, 100); - memset(cc[CC_id].vrb_map_UL, 0, 100); + // clear vrb_maps + memset(cc[CC_id].vrb_map, 0, 100); + memset(cc[CC_id].vrb_map_UL, 0, 100); #if defined(Rel10) || defined(Rel14) - cc[CC_id].mcch_active = 0; + cc[CC_id].mcch_active = 0; #endif - RC.mac[module_idP]->frame = frameP; - RC.mac[module_idP]->subframe = subframeP; + RC.mac[module_idP]->frame = frameP; + RC.mac[module_idP]->subframe = subframeP; - clear_nfapi_information(RC.mac[module_idP], CC_id, frameP, - subframeP); + clear_nfapi_information(RC.mac[module_idP], CC_id, frameP,subframeP); + } + + // refresh UE list based on UEs dropped by PHY in previous subframe + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (UE_list->active[i] != TRUE) continue; + + rnti = UE_RNTI(module_idP, i); + CC_id = UE_PCCID(module_idP, i); + + if ((frameP == 0) && (subframeP == 0)) { + LOG_I(MAC, + "UE rnti %x : %s, PHR %d dB DL CQI %d PUSCH SNR %d PUCCH SNR %d\n", + rnti, + UE_list->UE_sched_ctrl[i].ul_out_of_sync == + 0 ? "in synch" : "out of sync", + UE_list->UE_template[CC_id][i].phr_info, + UE_list->UE_sched_ctrl[i].dl_cqi[CC_id], + (UE_list->UE_sched_ctrl[i].pusch_snr[CC_id] - 128) / 2, + (UE_list->UE_sched_ctrl[i].pucch1_snr[CC_id] - 128) / 2); } - // refresh UE list based on UEs dropped by PHY in previous subframe - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i] != TRUE) - continue; + RC.eNB[module_idP][CC_id]->pusch_stats_bsr[i][(frameP * 10) + subframeP] = -63; + if (i == UE_list->head) + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME + (VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR, + RC.eNB[module_idP][CC_id]-> + pusch_stats_bsr[i][(frameP * 10) + subframeP]); + // increment this, it is cleared when we receive an sdu + RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ul_inactivity_timer++; - rnti = UE_RNTI(module_idP, i); - CC_id = UE_PCCID(module_idP, i); + RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer++; + LOG_D(MAC, "UE %d/%x : ul_inactivity %d, cqi_req %d\n", i, rnti, + RC.mac[module_idP]->UE_list.UE_sched_ctrl[i]. + ul_inactivity_timer, + RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer); + check_ul_failure(module_idP, CC_id, i, frameP, subframeP); + } - if ((frameP == 0) && (subframeP == 0)) { - LOG_I(MAC, - "UE rnti %x : %s, PHR %d dB DL CQI %d PUSCH SNR %d PUCCH SNR %d\n", - rnti, - UE_list->UE_sched_ctrl[i].ul_out_of_sync == - 0 ? "in synch" : "out of sync", - UE_list->UE_template[CC_id][i].phr_info, - UE_list->UE_sched_ctrl[i].dl_cqi[CC_id], - (UE_list->UE_sched_ctrl[i].pusch_snr[CC_id] - 128) / 2, - (UE_list->UE_sched_ctrl[i].pucch1_snr[CC_id] - 128) / 2); - } + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, + NOT_A_RNTI, frameP, subframeP, + module_idP); + pdcp_run(&ctxt); - RC.eNB[module_idP][CC_id]->pusch_stats_bsr[i][(frameP * 10) + - subframeP] = -63; - if (i == UE_list->head) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME - (VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR, - RC.eNB[module_idP][CC_id]-> - pusch_stats_bsr[i][(frameP * 10) + subframeP]); - // increment this, it is cleared when we receive an sdu - RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ul_inactivity_timer++; - - RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer++; - LOG_D(MAC, "UE %d/%x : ul_inactivity %d, cqi_req %d\n", i, rnti, - RC.mac[module_idP]->UE_list.UE_sched_ctrl[i]. - ul_inactivity_timer, - RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer); - check_ul_failure(module_idP, CC_id, i, frameP, subframeP); - - } - - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, - NOT_A_RNTI, frameP, subframeP, - module_idP); - pdcp_run(&ctxt); - - rrc_rx_tx(&ctxt, 0, // eNB index, unused in eNB - CC_id); + rrc_rx_tx(&ctxt, 0, CC_id); #if defined(Rel10) || defined(Rel14) - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - if (cc[CC_id].MBMS_flag > 0) { - start_meas(&RC.mac[module_idP]->schedule_mch); - mbsfn_status[CC_id] = - schedule_MBMS(module_idP, CC_id, frameP, subframeP); - stop_meas(&RC.mac[module_idP]->schedule_mch); - } + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + if (cc[CC_id].MBMS_flag > 0) { + start_meas(&RC.mac[module_idP]->schedule_mch); + mbsfn_status[CC_id] = schedule_MBMS(module_idP, CC_id, frameP, subframeP); + stop_meas(&RC.mac[module_idP]->schedule_mch); } + } #endif - // This schedules MIB - if ((subframeP == 0) && (frameP & 3) == 0) - schedule_mib(module_idP, frameP, subframeP); - // This schedules SI for legacy LTE and eMTC starting in subframeP - schedule_SI(module_idP, frameP, subframeP); - // This schedules Random-Access for legacy LTE and eMTC starting in subframeP - schedule_RA(module_idP, frameP, subframeP); - // copy previously scheduled UL resources (ULSCH + HARQ) - copy_ulreq(module_idP, frameP, subframeP); - // This schedules SRS in subframeP - schedule_SRS(module_idP, frameP, subframeP); - // This schedules ULSCH in subframeP (dci0) - schedule_ulsch(module_idP, frameP, subframeP); - // This schedules UCI_SR in subframeP - schedule_SR(module_idP, frameP, subframeP); - // This schedules UCI_CSI in subframeP - schedule_CSI(module_idP, frameP, subframeP); + // This schedules MIB + if ((subframeP == 0) && (frameP & 3) == 0) + schedule_mib(module_idP, frameP, subframeP); + // This schedules SI for legacy LTE and eMTC starting in subframeP + schedule_SI(module_idP, frameP, subframeP); + // This schedules Random-Access for legacy LTE and eMTC starting in subframeP + schedule_RA(module_idP, frameP, subframeP); + // copy previously scheduled UL resources (ULSCH + HARQ) + copy_ulreq(module_idP, frameP, subframeP); + // This schedules SRS in subframeP + schedule_SRS(module_idP, frameP, subframeP); + // This schedules ULSCH in subframeP (dci0) + schedule_ulsch(module_idP, frameP, subframeP); + // This schedules UCI_SR in subframeP + schedule_SR(module_idP, frameP, subframeP); + // This schedules UCI_CSI in subframeP + schedule_CSI(module_idP, frameP, subframeP); - // This schedules DLSCH in subframeP - schedule_ue_spec(module_idP, frameP, subframeP, mbsfn_status); + // This schedules DLSCH in subframeP + schedule_ue_spec(module_idP, frameP, subframeP, mbsfn_status); - // Allocate CCEs for good after scheduling is done + // Allocate CCEs for good after scheduling is done - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) - allocate_CCEs(module_idP, CC_id, subframeP, 0); + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) + allocate_CCEs(module_idP, CC_id, subframeP, 0); - stop_meas(&RC.mac[module_idP]->eNB_scheduler); + stop_meas(&RC.mac[module_idP]->eNB_scheduler); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, - VCD_FUNCTION_OUT); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, + VCD_FUNCTION_OUT); } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c index 7b45401b06..3807b1aa61 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c @@ -135,48 +135,35 @@ add_msg3(module_id_t module_idP, int CC_id, RA_t * ra, frame_t frameP, memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t)); - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; - ul_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu)); - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = mac->ul_handle++; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = ra->rnti; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = - narrowband_to_first_rb(cc, - ra->msg34_narrowband) + - ra->msg3_first_rb; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = - ra->msg3_nb_rb; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 2; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = - 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8. - frequency_hopping_enabled_flag = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = - rvseq[ra->msg3_round]; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = - ((10 * ra->Msg3_frame) + ra->Msg3_subframe) & 7; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = 1; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = - get_TBS_UL(ra->msg3_mcs, ra->msg3_nb_rb); + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; + ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu)); + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = mac->ul_handle++; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = ra->rnti; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = narrowband_to_first_rb(cc, + ra->msg34_narrowband) + ra->msg3_first_rb; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = ra->msg3_nb_rb; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 2; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_enabled_flag = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = rvseq[ra->msg3_round]; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = ((10 * ra->Msg3_frame) + ra->Msg3_subframe) & 7; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = 1; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = get_TBS_UL(ra->msg3_mcs, ra->msg3_nb_rb); // Re13 fields - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL13_TAG; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.ue_type = - ra->rach_resource_type > 2 ? 2 : 1; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13. - total_number_of_repetitions = 1; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.repetition_number = 1; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13. - initial_transmission_sf_io = - (ra->Msg3_frame * 10) + ra->Msg3_subframe; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL13_TAG; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.ue_type = ra->rach_resource_type > 2 ? 2 : 1; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.total_number_of_repetitions = 1; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.repetition_number = 1; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.initial_transmission_sf_io = (ra->Msg3_frame * 10) + ra->Msg3_subframe; ul_req_body->number_of_pdus++; - ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; - ul_req->sfn_sf = ra->Msg3_frame<<4|ra->Msg3_subframe; - ul_req->header.message_id = NFAPI_UL_CONFIG_REQUEST; + ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + ul_req->sfn_sf = ra->Msg3_frame<<4|ra->Msg3_subframe; + ul_req->header.message_id = NFAPI_UL_CONFIG_REQUEST; } // if (ra->rach_resource_type>0) { else #endif @@ -191,42 +178,32 @@ add_msg3(module_id_t module_idP, int CC_id, RA_t * ra, frame_t frameP, frameP, subframeP, ra->Msg3_frame, ra->Msg3_subframe, ra->msg3_nb_rb, ra->msg3_first_rb, ra->msg3_round); - ul_config_pdu = - &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus]; + ul_config_pdu = &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus]; - memset((void *) ul_config_pdu, 0, - sizeof(nfapi_ul_config_request_pdu_t)); - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; - ul_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu)); - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = mac->ul_handle++; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = ra->rnti; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = - ra->msg3_first_rb; + memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t)); + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; + ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu)); + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = mac->ul_handle++; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = ra->rnti; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = ra->msg3_first_rb; AssertFatal(ra->msg3_nb_rb > 0, "nb_rb = 0\n"); - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = - ra->msg3_nb_rb; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 2; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = - 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8. - frequency_hopping_enabled_flag = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = - rvseq[ra->msg3_round]; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = - subframe2harqpid(cc, ra->Msg3_frame, ra->Msg3_subframe); - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = 0; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = 1; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = - get_TBS_UL(10, ra->msg3_nb_rb); + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = ra->msg3_nb_rb; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 2; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_enabled_flag = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = rvseq[ra->msg3_round]; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = subframe2harqpid(cc, ra->Msg3_frame, ra->Msg3_subframe); + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = 0; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = 1; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = get_TBS_UL(10, ra->msg3_nb_rb); ul_req_body->number_of_pdus++; - ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; - ul_req->sfn_sf = ra->Msg3_frame<<4|ra->Msg3_subframe; - ul_req->header.message_id = NFAPI_UL_CONFIG_REQUEST; + ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + ul_req->sfn_sf = ra->Msg3_frame<<4|ra->Msg3_subframe; + ul_req->header.message_id = NFAPI_UL_CONFIG_REQUEST; // save UL scheduling information for preprocessor for (j = 0; j < ra->msg3_nb_rb; j++) cc->vrb_map_UL[ra->msg3_first_rb + j] = 1; @@ -237,20 +214,19 @@ add_msg3(module_id_t module_idP, int CC_id, RA_t * ra, frame_t frameP, hi_dci0_pdu = &hi_dci0_req_body->hi_dci0_pdu_list[hi_dci0_req_body->number_of_dci + hi_dci0_req_body->number_of_hi]; memset((void *) hi_dci0_pdu, 0, sizeof(nfapi_hi_dci0_request_pdu_t)); - hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; - hi_dci0_pdu->pdu_size = 2 + sizeof(nfapi_hi_dci0_hi_pdu); - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_HI_PDU_REL8_TAG; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = - ra->msg3_first_rb; + hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; + hi_dci0_pdu->pdu_size = 2 + sizeof(nfapi_hi_dci0_hi_pdu); + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_HI_PDU_REL8_TAG; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = ra->msg3_first_rb; hi_dci0_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = 0; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 0; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 0; hi_dci0_req_body->number_of_hi++; - hi_dci0_req_body->sfnsf = sfnsf_add_subframe(ra->Msg3_frame, ra->Msg3_subframe, 0); - hi_dci0_req_body->tl.tag = NFAPI_HI_DCI0_REQUEST_BODY_TAG; + hi_dci0_req_body->sfnsf = sfnsf_add_subframe(ra->Msg3_frame, ra->Msg3_subframe, 0); + hi_dci0_req_body->tl.tag = NFAPI_HI_DCI0_REQUEST_BODY_TAG; - hi_dci0_req->sfn_sf = sfnsf_add_subframe(ra->Msg3_frame, ra->Msg3_subframe, 4); - hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST; + hi_dci0_req->sfn_sf = sfnsf_add_subframe(ra->Msg3_frame, ra->Msg3_subframe, 4); + hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST; if (nfapi_mode) { oai_nfapi_hi_dci0_req(hi_dci0_req); @@ -312,11 +288,8 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, if (cc[CC_idP].radioResourceConfigCommon_BR) { - ext4_prach = - cc[CC_idP].radioResourceConfigCommon_BR->ext4-> - prach_ConfigCommon_v1310; - prach_ParametersListCE_r13 = - &ext4_prach->prach_ParametersListCE_r13; + ext4_prach = cc[CC_idP].radioResourceConfigCommon_BR->ext4->prach_ConfigCommon_v1310; + prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13; switch (prach_ParametersListCE_r13->list.count) { case 4: @@ -348,110 +321,71 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, // rmax from SIB2 information AssertFatal(rmax < 9, "rmax>8!\n"); - rmax = - 1 << p[ra->rach_resource_type - - 1]->mpdcch_NumRepetition_RA_r13; + rmax = 1 << p[ra->rach_resource_type-1]->mpdcch_NumRepetition_RA_r13; // choose r1 by default for RAR (Table 9.1.5-5) rep = 0; // get actual repetition count from Table 9.1.5-3 reps = (rmax <= 8) ? (1 << rep) : (rmax >> (3 - rep)); // get narrowband according to higher-layer config - num_nb = - p[ra->rach_resource_type - - 1]->mpdcch_NarrowbandsToMonitor_r13.list.count; - ra->msg2_narrowband = - *p[ra->rach_resource_type - - 1]->mpdcch_NarrowbandsToMonitor_r13.list.array[ra-> - preamble_index - % num_nb]; - first_rb = - narrowband_to_first_rb(&cc[CC_idP], ra->msg2_narrowband); + num_nb = p[ra->rach_resource_type-1]->mpdcch_NarrowbandsToMonitor_r13.list.count; + ra->msg2_narrowband = *p[ra->rach_resource_type - 1]->mpdcch_NarrowbandsToMonitor_r13.list.array[ra->preamble_index % num_nb]; + first_rb = narrowband_to_first_rb(&cc[CC_idP], ra->msg2_narrowband); if ((ra->msg2_mpdcch_repetition_cnt == 0) && - (mpdcch_sf_condition - (mac, CC_idP, frameP, subframeP, rmax, TYPE2, -1) > 0)) { + (mpdcch_sf_condition(mac, CC_idP, frameP, subframeP, rmax, TYPE2, -1) > 0)) { // MPDCCH configuration for RAR LOG_D(MAC, "[eNB %d][RAPROC] Frame %d, Subframe %d : In generate_Msg2, Programming MPDCCH %d repetitions\n", module_idP, frameP, subframeP, reps); - memset((void *) dl_config_pdu, 0, - sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_dl_config_mpdcch_pdu)); - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_MPDCCH_PDU_REL13_TAG; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = - (ra->rach_resource_type > 1) ? 11 : 10; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = - ra->msg2_narrowband; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. - number_of_prb_pairs = 6; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment = 0; // Note: this can be dynamic - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_tansmission_type = 1; // imposed (9.1.5 in 213) for Type 2 Common search space - AssertFatal(cc[CC_idP]. - sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 - != NULL, + memset((void *) dl_config_pdu, 0,sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_mpdcch_pdu)); + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_MPDCCH_PDU_REL13_TAG; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = (ra->rach_resource_type > 1) ? 11 : 10; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = ra->msg2_narrowband; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_prb_pairs = 6; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment = 0; // Note: this can be dynamic + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_tansmission_type = 1; // imposed (9.1.5 in 213) for Type 2 Common search space + AssertFatal(cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13!= NULL, "cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n"); - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol = - cc[CC_idP].sib1_v13ext-> - bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ecce_index = 0; // Note: this should be dynamic - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level = 16; // OK for CEModeA r1-3 (9.1.5-1b) or CEModeB r1-4 - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti_type = 2; // RA-RNTI - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti = ra->RA_rnti; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = - (ra->rach_resource_type < 3) ? 1 : 2; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. - drms_scrambling_init = cc[CC_idP].physCellId; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. - initial_transmission_sf_io = (frameP * 10) + subframeP; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.transmission_power = 6000; // 0dB - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding = getRIV(6, 0, 6); // Note: still to be checked if it should not be (getRIV(N_RB_DL,first_rb,6)) : Check nFAPI specifications and what is done L1 with this parameter + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol = cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ecce_index = 0; // Note: this should be dynamic + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level = 16; // OK for CEModeA r1-3 (9.1.5-1b) or CEModeB r1-4 + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti_type = 2; // RA-RNTI + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti = ra->RA_rnti; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = (ra->rach_resource_type < 3) ? 1 : 2; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.drms_scrambling_init = cc[CC_idP].physCellId; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.initial_transmission_sf_io = (frameP * 10) + subframeP; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.transmission_power = 6000; // 0dB + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding = getRIV(6, 0, 6); // Note: still to be checked if it should not be (getRIV(N_RB_DL,first_rb,6)) : Check nFAPI specifications and what is done L1 with this parameter dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mcs = 4; // adjust according to size of RAR, 208 bits with N1A_PRB=3 - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels = 4; // fix to 4 for now - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version = - 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator = - 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. - harq_resource_offset = 0; - dl_config_pdu->mpdcch_pdu. - mpdcch_pdu_rel13.dci_subframe_repetition_number = rep; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpc = 1; // N1A_PRB=3 (36.212); => 208 bits for mcs=4, choose mcs according t message size TBD - dl_config_pdu->mpdcch_pdu. - mpdcch_pdu_rel13.downlink_assignment_index_length = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. - downlink_assignment_index = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. - allocate_prach_flag = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.preamble_index = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index = - 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level = - 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.srs_request = 0; - dl_config_pdu->mpdcch_pdu. - mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag - = 0; - dl_config_pdu->mpdcch_pdu. - mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity = 0; - dl_config_pdu->mpdcch_pdu. - mpdcch_pdu_rel13.frequency_hopping_enabled_flag = 0; - dl_config_pdu->mpdcch_pdu. - mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag - = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication = - 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding = 0; // this is not needed by OAI L1, but should be filled in - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. - number_of_tx_antenna_ports = 1; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels = 4; // fix to 4 for now + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_resource_offset = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_subframe_repetition_number = rep; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpc = 1; // N1A_PRB=3 (36.212); => 208 bits for mcs=4, choose mcs according t message size TBD + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index_length = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.allocate_prach_flag = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.preamble_index = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.srs_request = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.frequency_hopping_enabled_flag = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding = 0; // this is not needed by OAI L1, but should be filled in + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_tx_antenna_ports = 1; ra->msg2_mpdcch_repetition_cnt++; dl_req->number_pdu++; dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; @@ -489,65 +423,43 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, ra->state = WAITMSG3; LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:WAITMSG3\n", module_idP, frameP, subframeP); - dl_config_pdu = - &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void *) dl_config_pdu, 0, - sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = - mac->pdu_index[CC_idP]; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = ra->RA_rnti; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - resource_allocation_type = 2; + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0,sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = mac->pdu_index[CC_idP]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = ra->RA_rnti; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - resource_block_coding = getRIV(N_RB_DL, first_rb, 6); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - redundancy_version = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = - 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = - 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - number_of_subbands = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 6); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - ue_category_capacity = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - delta_power_offset_index = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = - (cc->p_eNB == 1) ? 1 : 2; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - num_bf_prb_per_subband = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB == 1) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; // Rel10 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = - cc[CC_idP]. - sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13-> - startSymbolBR_r13; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; // Rel13 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = - (ra->rach_resource_type < 3) ? 1 : 2;; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not SI message - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13. - initial_transmission_sf_io = (10 * frameP) + subframeP; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = - 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = (ra->rach_resource_type < 3) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not SI message + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = (10 * frameP) + subframeP; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = 0; dl_req->number_pdu++; mac->DL_req[CC_idP].sfn_sf = (frameP<<4)+subframeP; @@ -567,16 +479,12 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, mac->TX_req[CC_idP].header.message_id = NFAPI_TX_REQUEST; mac->TX_req[CC_idP].sfn_sf = (frameP << 4) + subframeP; TX_req = - &mac->TX_req[CC_idP].tx_request_body.tx_pdu_list[mac-> - TX_req - [CC_idP]. - tx_request_body.number_of_pdus]; + &mac->TX_req[CC_idP].tx_request_body.tx_pdu_list[mac->TX_req[CC_idP].tx_request_body.number_of_pdus]; TX_req->pdu_length = 7; // This should be changed if we have more than 1 preamble TX_req->pdu_index = mac->pdu_index[CC_idP]++; TX_req->num_segments = 1; TX_req->segments[0].segment_length = 7; - TX_req->segments[0].segment_data = - cc[CC_idP].RAR_pdu.payload; + TX_req->segments[0].segment_data = cc[CC_idP].RAR_pdu.payload; mac->TX_req[CC_idP].tx_request_body.number_of_pdus++; } } @@ -597,100 +505,73 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, vrb_map[first_rb + 2] = 1; vrb_map[first_rb + 3] = 1; - memset((void *) dl_config_pdu, 0, - sizeof(nfapi_dl_config_request_pdu_t)); + memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = - NFAPI_DL_DCI_FORMAT_1A; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = - 4; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = 4; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = ra->RA_rnti; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 2; // RA-RNTI : see Table 4-10 from SCF082 - nFAPI specifications dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = 0; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // no TPC - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - new_data_indicator_1 = 1; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = 1; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = 0; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - redundancy_version_1 = 0; - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - resource_block_coding = getRIV(N_RB_DL, first_rb, 4); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 4); // This checks if the above DCI allocation is feasible in current subframe - if (!CCE_allocation_infeasible - (module_idP, CC_idP, 0, subframeP, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - aggregation_level, ra->RA_rnti)) { + if (!CCE_allocation_infeasible(module_idP, CC_idP, 0, subframeP, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, ra->RA_rnti)) { LOG_D(MAC, "Frame %d: Subframe %d : Adding common DCI for RA_RNTI %x\n", frameP, subframeP, ra->RA_rnti); dl_req->number_dci++; dl_req->number_pdu++; - dl_config_pdu = - &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void *) dl_config_pdu, 0, - sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = - mac->pdu_index[CC_idP]; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = ra->RA_rnti; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = mac->pdu_index[CC_idP]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = ra->RA_rnti; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - resource_block_coding = getRIV(N_RB_DL, first_rb, 4); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - redundancy_version = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = - 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = - 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - number_of_subbands = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 4); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - ue_category_capacity = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - delta_power_offset_index = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = - (cc->p_eNB == 1) ? 1 : 2; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - num_bf_prb_per_subband = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB == 1) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; dl_req->number_pdu++; mac->DL_req[CC_idP].sfn_sf = frameP<<4 | subframeP; // Program UL processing for Msg3 - get_Msg3alloc(&cc[CC_idP], subframeP, frameP, - &ra->Msg3_frame, &ra->Msg3_subframe); + get_Msg3alloc(&cc[CC_idP], subframeP, frameP,&ra->Msg3_frame, &ra->Msg3_subframe); LOG_D(MAC, "Frame %d, Subframe %d: Setting Msg3 reception for Frame %d Subframe %d\n", frameP, subframeP, ra->Msg3_frame, ra->Msg3_subframe); - fill_rar(module_idP, CC_idP, ra, frameP, - cc[CC_idP].RAR_pdu.payload, N_RB_DL, 7); + fill_rar(module_idP, CC_idP, ra, frameP, cc[CC_idP].RAR_pdu.payload, N_RB_DL, 7); add_msg3(module_idP, CC_idP, ra, frameP, subframeP); ra->state = WAITMSG3; LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:WAITMSG3\n", module_idP, frameP, subframeP); @@ -698,10 +579,7 @@ generate_Msg2(module_id_t module_idP, int CC_idP, frame_t frameP, // DL request mac->TX_req[CC_idP].sfn_sf = (frameP << 4) + subframeP; TX_req = - &mac->TX_req[CC_idP].tx_request_body.tx_pdu_list[mac-> - TX_req - [CC_idP]. - tx_request_body.number_of_pdus]; + &mac->TX_req[CC_idP].tx_request_body.tx_pdu_list[mac->TX_req[CC_idP].tx_request_body.number_of_pdus]; TX_req->pdu_length = 7; // This should be changed if we have more than 1 preamble TX_req->pdu_index = mac->pdu_index[CC_idP]++; TX_req->num_segments = 1; @@ -759,63 +637,42 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, if (cc[CC_idP].radioResourceConfigCommon_BR) { - ext4_prach = - cc[CC_idP].radioResourceConfigCommon_BR->ext4-> - prach_ConfigCommon_v1310; - ext4_pucch = - cc[CC_idP].radioResourceConfigCommon_BR->ext4-> - pucch_ConfigCommon_v1310; - prach_ParametersListCE_r13 = - &ext4_prach->prach_ParametersListCE_r13; - pucch_N1PUCCH_AN_InfoList_r13 = - ext4_pucch->n1PUCCH_AN_InfoList_r13; - AssertFatal(prach_ParametersListCE_r13 != NULL, - "prach_ParametersListCE_r13 is null\n"); - AssertFatal(pucch_N1PUCCH_AN_InfoList_r13 != NULL, - "pucch_N1PUCCH_AN_InfoList_r13 is null\n"); + ext4_prach = cc[CC_idP].radioResourceConfigCommon_BR->ext4->prach_ConfigCommon_v1310; + ext4_pucch = cc[CC_idP].radioResourceConfigCommon_BR->ext4->pucch_ConfigCommon_v1310; + prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13; + pucch_N1PUCCH_AN_InfoList_r13 = ext4_pucch->n1PUCCH_AN_InfoList_r13; + AssertFatal(prach_ParametersListCE_r13 != NULL,"prach_ParametersListCE_r13 is null\n"); + AssertFatal(pucch_N1PUCCH_AN_InfoList_r13 != NULL,"pucch_N1PUCCH_AN_InfoList_r13 is null\n"); // check to verify CE-Level compatibility in SIB2_BR - AssertFatal(prach_ParametersListCE_r13->list.count == - pucch_N1PUCCH_AN_InfoList_r13->list.count, + AssertFatal(prach_ParametersListCE_r13->list.count == pucch_N1PUCCH_AN_InfoList_r13->list.count, "prach_ParametersListCE_r13->list.count!= pucch_N1PUCCH_AN_InfoList_r13->list.count\n"); switch (prach_ParametersListCE_r13->list.count) { case 4: p[3] = prach_ParametersListCE_r13->list.array[3]; n1pucchan[3] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[3]; - AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level3_r13 - != NULL, + AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level3_r13 != NULL, "pucch_NumRepetitionCE_Msg4_Level3 shouldn't be NULL\n"); - pucchreps[3] = - (int) (4 << *ext4_pucch-> - pucch_NumRepetitionCE_Msg4_Level3_r13); + pucchreps[3] = (int) (4 << *ext4_pucch->pucch_NumRepetitionCE_Msg4_Level3_r13); case 3: p[2] = prach_ParametersListCE_r13->list.array[2]; n1pucchan[2] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[2]; - AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13 - != NULL, + AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13!= NULL, "pucch_NumRepetitionCE_Msg4_Level2 shouldn't be NULL\n"); - pucchreps[2] = - (int) (4 << *ext4_pucch-> - pucch_NumRepetitionCE_Msg4_Level2_r13); + pucchreps[2] =(int) (4 << *ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13); case 2: p[1] = prach_ParametersListCE_r13->list.array[1]; n1pucchan[1] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[1]; - AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13 - != NULL, + AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13 != NULL, "pucch_NumRepetitionCE_Msg4_Level1 shouldn't be NULL\n"); - pucchreps[1] = - (int) (1 << *ext4_pucch-> - pucch_NumRepetitionCE_Msg4_Level1_r13); + pucchreps[1] = (int) (1 << *ext4_pucch->pucch_NumRepetitionCE_Msg4_Level1_r13); case 1: p[0] = prach_ParametersListCE_r13->list.array[0]; n1pucchan[0] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[0]; - AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13 - != NULL, + AssertFatal(ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13 != NULL, "pucch_NumRepetitionCE_Msg4_Level0 shouldn't be NULL\n"); - pucchreps[0] = - (int) (1 << *ext4_pucch-> - pucch_NumRepetitionCE_Msg4_Level0_r13); + pucchreps[0] =(int) (1 << *ext4_pucch->pucch_NumRepetitionCE_Msg4_Level0_r13); default: AssertFatal(1 == 0, "Illegal count for prach_ParametersListCE_r13 %d\n", @@ -887,80 +744,53 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_dl_config_mpdcch_pdu)); + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_mpdcch_pdu)); dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_MPDCCH_PDU_REL13_TAG; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = - (ra->rach_resource_type > 1) ? 11 : 10; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = - ra->msg34_narrowband; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. - number_of_prb_pairs = 6; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = (ra->rach_resource_type > 1) ? 11 : 10; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = ra->msg34_narrowband; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_prb_pairs = 6; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment = 0; // Note: this can be dynamic - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. - mpdcch_tansmission_type = 1; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_tansmission_type = 1; AssertFatal(cc[CC_idP]. sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 != NULL, "cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n"); - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol = - cc[CC_idP].sib1_v13ext-> - bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol = cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ecce_index = 0; // Note: this should be dynamic dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level = 16; // OK for CEModeA r1-3 (9.1.5-1b) or CEModeB r1-4 dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti_type = 0; // t-C-RNTI dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti = ra->RA_rnti; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = - (ra->rach_resource_type < 3) ? 1 : 2; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = (ra->rach_resource_type < 3) ? 1 : 2; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.drms_scrambling_init = cc[CC_idP].physCellId; /// Check this is still N_id_cell for type2 common - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. - initial_transmission_sf_io = (frameP * 10) + subframeP; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.initial_transmission_sf_io = (frameP * 10) + subframeP; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.transmission_power = 6000; // 0dB dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding = getRIV(6, 0, 6); // check if not getRIV(N_RB_DL,first_rb,6); dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mcs = 4; // adjust according to size of Msg4, 208 bits with N1A_PRB=3 dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels = 4; // fix to 4 for now - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version = - 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator = - 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process = - ra->harq_pid; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process = ra->harq_pid; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. - harq_resource_offset = 0; - dl_config_pdu->mpdcch_pdu. - mpdcch_pdu_rel13.dci_subframe_repetition_number = rep; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_resource_offset = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_subframe_repetition_number = rep; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpc = 1; // N1A_PRB=3; => 208 bits - dl_config_pdu->mpdcch_pdu. - mpdcch_pdu_rel13.downlink_assignment_index_length = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. - downlink_assignment_index = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. - allocate_prach_flag = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index_length = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.allocate_prach_flag = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.preamble_index = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index = - 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level = - 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.srs_request = 0; - dl_config_pdu->mpdcch_pdu. - mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag - = 0; - dl_config_pdu->mpdcch_pdu. - mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity = 0; - dl_config_pdu->mpdcch_pdu. - mpdcch_pdu_rel13.frequency_hopping_enabled_flag = 0; - dl_config_pdu->mpdcch_pdu. - mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag - = 0; - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication = - 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.frequency_hopping_enabled_flag = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag = 0; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding = 0; // this is not needed by OAI L1, but should be filled in - dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13. - number_of_tx_antenna_ports = 1; + dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_tx_antenna_ports = 1; ra->msg4_mpdcch_repetition_cnt++; dl_req_body->number_pdu++; dl_req_body->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; @@ -983,8 +813,7 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, AssertFatal(1 == 0, "TDD case not done yet\n"); } } // mpdcch_repetition_count == reps - if ((ra->Msg4_frame == frameP) - && (ra->Msg4_subframe == subframeP)) { + if ((ra->Msg4_frame == frameP) && (ra->Msg4_subframe == subframeP)) { // Program PDSCH @@ -995,62 +824,42 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, AssertFatal(1 == 0, "Msg4 generation not finished for BL/CE UE\n"); - dl_config_pdu = - &dl_req_body->dl_config_pdu_list[dl_req_body->number_pdu]; - memset((void *) dl_config_pdu, 0, - sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu = &dl_req_body->dl_config_pdu_list[dl_req_body->number_pdu]; + memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = - mac->pdu_index[CC_idP]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = mac->pdu_index[CC_idP]; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = ra->rnti; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 6); // check that this isn't getRIV(6,0,6) dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - redundancy_version = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = - 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = - 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - number_of_subbands = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - ue_category_capacity = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - delta_power_offset_index = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = - (cc->p_eNB == 1) ? 1 : 2; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - num_bf_prb_per_subband = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB == 1) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = - cc[CC_idP]. - sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13-> - startSymbolBR_r13; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = - (ra->rach_resource_type < 3) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = (ra->rach_resource_type < 3) ? 1 : 2; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not SI message - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13. - initial_transmission_sf_io = (10 * frameP) + subframeP; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = - 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = (10 * frameP) + subframeP; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = 0; dl_req_body->number_pdu++; dl_req_body->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; @@ -1062,18 +871,15 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, lcid = 0; - UE_list->UE_sched_ctrl[UE_id].round[CC_idP][ra->harq_pid] = - 0; + UE_list->UE_sched_ctrl[UE_id].round[CC_idP][ra->harq_pid] = 0; msg4_header = 1 + 6 + 1; // CR header, CR CE, SDU header if ((ra->msg4_TBsize - rrc_sdu_length - msg4_header) <= 2) { - msg4_padding = - ra->msg4_TBsize - rrc_sdu_length - msg4_header; + msg4_padding = ra->msg4_TBsize - rrc_sdu_length - msg4_header; msg4_post_padding = 0; } else { msg4_padding = 0; - msg4_post_padding = - ra->msg4_TBsize - rrc_sdu_length - msg4_header - 1; + msg4_post_padding = ra->msg4_TBsize - rrc_sdu_length - msg4_header - 1; } LOG_D(MAC, @@ -1093,10 +899,7 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, msg4_post_padding); memcpy((void *) &mac->UE_list. - DLSCH_pdu[CC_idP][0][(unsigned char) - UE_id].payload[0][(unsigned - char) - offset], + DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0][(unsigned char)offset], &cc[CC_idP].CCCH_pdu.payload[0], rrc_sdu_length); // DL request @@ -1105,17 +908,12 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, mac->TX_req[CC_idP].header.message_id = NFAPI_TX_REQUEST; TX_req = - &mac->TX_req[CC_idP].tx_request_body.tx_pdu_list[mac-> - TX_req - [CC_idP]. - tx_request_body.number_of_pdus]; + &mac->TX_req[CC_idP].tx_request_body.tx_pdu_list[mac->TX_req[CC_idP].tx_request_body.number_of_pdus]; TX_req->pdu_length = rrc_sdu_length; TX_req->pdu_index = mac->pdu_index[CC_idP]++; TX_req->num_segments = 1; TX_req->segments[0].segment_length = rrc_sdu_length; - TX_req->segments[0].segment_data = - mac->UE_list. - DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0]; + TX_req->segments[0].segment_data = mac->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char) UE_id].payload[0]; mac->TX_req[CC_idP].tx_request_body.number_of_pdus++; // Program ACK/NAK for Msg4 PDSCH @@ -1125,44 +923,28 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, AssertFatal(reps > 2, "Have to handle programming of ACK when PDSCH repetitions is > 2\n"); ul_req = &mac->UL_req_tmp[CC_idP][ackNAK_absSF % 10]; - ul_req_body = &ul_req->ul_config_request_body; - ul_config_pdu = &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus]; + ul_req_body = &ul_req->ul_config_request_body;l_config_pdu = &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus]; - ul_config_pdu->pdu_type = - NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE; - ul_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_ul_config_uci_harq_pdu)); + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE; + ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_uci_harq_pdu)); ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.handle = 0; // don't know how to use this - ul_config_pdu->uci_harq_pdu. - ue_information.ue_information_rel8.rnti = ra->rnti; + ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti = ra->rnti; ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL13_TAG; - ul_config_pdu->uci_harq_pdu. - ue_information.ue_information_rel13.ue_type = - (ra->rach_resource_type < 3) ? 1 : 2; - ul_config_pdu->uci_harq_pdu. - ue_information.ue_information_rel13.empty_symbols = 0; - ul_config_pdu->uci_harq_pdu.ue_information. - ue_information_rel13.total_number_of_repetitions = - pucchreps[ra->rach_resource_type - 1]; - ul_config_pdu->uci_harq_pdu. - ue_information.ue_information_rel13.repetition_number = - 0; + ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.ue_type = (ra->rach_resource_type < 3) ? 1 : 2; + ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.empty_symbols = 0; + ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.total_number_of_repetitions = pucchreps[ra->rach_resource_type - 1]; + ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.repetition_number = 0; ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; - ul_req->sfn_sf = sfnsf_add_subframe(ra->Msg3_frame, ra->Msg3_subframe, 4); ul_req->header.message_id = NFAPI_UL_CONFIG_REQUEST; - LOG_D(MAC,"UL_req_tmp[CC_idP:%d][ackNAK_absSF mod 10:%d] ra->Msg3_frame:%d ra->Msg3_subframe:%d + 4 sfn_sf:%d\n", CC_idP, ackNAK_absSF%10, ra->Msg3_frame, ra->Msg3_subframe, NFAPI_SFNSF2DEC(ul_req->sfn_sf)); // Note need to keep sending this across reptitions!!!! Not really for PUCCH, to ask small-cell forum, we'll see for the other messages, maybe parameters change across repetitions and FAPI has to provide for that if (cc[CC_idP].tdd_Config == NULL) { // FDD case ul_config_pdu->uci_harq_pdu.harq_information.harq_information_rel8_fdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL8_FDD_TAG; - ul_config_pdu->uci_harq_pdu. - harq_information.harq_information_rel8_fdd. - n_pucch_1_0 = - n1pucchan[ra->rach_resource_type - 1]; + ul_config_pdu->uci_harq_pdu.harq_information.harq_information_rel8_fdd.n_pucch_1_0 = n1pucchan[ra->rach_resource_type - 1]; // NOTE: How to fill in the rest of the n_pucch_1_0 information 213 Section 10.1.2.1 in the general case // = N_ECCE_q + Delta_ARO + n1pucchan[ce_level] // higher in the MPDCCH configuration, N_ECCE_q is hard-coded to 0, and harq resource offset to 0 => @@ -1182,15 +964,12 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, if (opt_enabled == 1) { trace_pdu(1, (uint8_t *) mac-> - UE_list.DLSCH_pdu[CC_idP][0][(unsigned char) - UE_id].payload - [0], rrc_sdu_length, UE_id, 3, + UE_list.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0], rrc_sdu_length, UE_id, 3, UE_RNTI(module_idP, UE_id), mac->frame, mac->subframe, 0, 0); LOG_D(OPT, "[eNB %d][DLSCH] CC_id %d Frame %d trace pdu for rnti %x with size %d\n", - module_idP, CC_idP, frameP, UE_RNTI(module_idP, - UE_id), + module_idP, CC_idP, frameP, UE_RNTI(module_idP,UE_id), rrc_sdu_length); } } // Msg4 frame/subframe @@ -1253,19 +1032,15 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process, - &dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - resource_block_coding, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - resource_block_coding); + &dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding); AssertFatal(dl_config_pdu->dci_dl_pdu. dci_dl_pdu_rel8.resource_block_coding < 8192, "resource_block_coding %u < 8192\n", dl_config_pdu->dci_dl_pdu. dci_dl_pdu_rel8.resource_block_coding); - if (!CCE_allocation_infeasible - (module_idP, CC_idP, 1, subframeP, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - aggregation_level, ra->rnti)) { + if (!CCE_allocation_infeasible(module_idP, CC_idP, 1, subframeP, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, ra->rnti)) { dl_req_body->number_dci++; dl_req_body->number_pdu++; @@ -1288,21 +1063,17 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, lcid = 0; // put HARQ process round to 0 - if (cc->tdd_Config) - ra->harq_pid = ((frameP * 10) + subframeP) % 10; + if (cc->tdd_Config) ra->harq_pid = ((frameP * 10) + subframeP) % 10; else - ra->harq_pid = ((frameP * 10) + subframeP) & 7; - UE_list->UE_sched_ctrl[UE_id].round[CC_idP][ra->harq_pid] = - 0; + ra->harq_pid = ((frameP * 10) + subframeP) & 7; + UE_list->UE_sched_ctrl[UE_id].round[CC_idP][ra->harq_pid] = 0; if ((ra->msg4_TBsize - rrc_sdu_length - msg4_header) <= 2) { - msg4_padding = - ra->msg4_TBsize - rrc_sdu_length - msg4_header; + msg4_padding = ra->msg4_TBsize - rrc_sdu_length - msg4_header; msg4_post_padding = 0; } else { msg4_padding = 0; - msg4_post_padding = - ra->msg4_TBsize - rrc_sdu_length - msg4_header - 1; + msg4_post_padding = ra->msg4_TBsize - rrc_sdu_length - msg4_header - 1; } LOG_D(MAC, @@ -1321,11 +1092,7 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, msg4_padding, // no padding msg4_post_padding); - memcpy((void *) &mac->UE_list. - DLSCH_pdu[CC_idP][0][(unsigned char) - UE_id].payload[0][(unsigned - char) - offset], + memcpy((void *) &mac->UE_list.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0][(unsigned char)offset], &cc[CC_idP].CCCH_pdu.payload[0], rrc_sdu_length); // DLSCH Config @@ -1359,9 +1126,7 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, rrc_sdu_length, mac->pdu_index[CC_idP], mac->UE_list. - DLSCH_pdu[CC_idP][0][(unsigned char) - UE_id].payload - [0]); + DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0]); mac->pdu_index[CC_idP]++; dl_req->sfn_sf = mac->TX_req[CC_idP].sfn_sf; @@ -1374,8 +1139,7 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, CC_idP, ra->rnti, (frameP * 10) + subframeP, - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.cce_idx); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx); T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), @@ -1387,9 +1151,7 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, if (opt_enabled == 1) { trace_pdu(1, (uint8_t *) mac-> - UE_list.DLSCH_pdu[CC_idP][0][(unsigned char) - UE_id].payload - [0], rrc_sdu_length, UE_id, 3, + UE_list.DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0], rrc_sdu_length, UE_id, 3, UE_RNTI(module_idP, UE_id), mac->frame, mac->subframe, 0, 0); LOG_D(OPT, @@ -1578,8 +1340,7 @@ check_Msg4_retransmission(module_id_t module_idP, int CC_idP, LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:IDLE\n", module_idP, frameP, subframeP); UE_id = find_UE_id(module_idP, ra->rnti); DevAssert(UE_id != -1); - mac->UE_list.UE_template[UE_PCCID(module_idP, UE_id)][UE_id]. - configured = TRUE; + mac->UE_list.UE_template[UE_PCCID(module_idP, UE_id)][UE_id].configured = TRUE; } } @@ -1647,11 +1408,8 @@ initiate_ra_proc(module_id_t module_idP, if (cc->radioResourceConfigCommon_BR && cc->radioResourceConfigCommon_BR->ext4) { - ext4_prach = - cc->radioResourceConfigCommon_BR->ext4-> - prach_ConfigCommon_v1310; - prach_ParametersListCE_r13 = - &ext4_prach->prach_ParametersListCE_r13; + ext4_prach = cc->radioResourceConfigCommon_BR->ext4->prach_ConfigCommon_v1310; + prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13; } LOG_D(MAC, "[eNB %d][RAPROC] CC_id %d Frame %d, Subframe %d Initiating RA procedure for preamble index %d\n", @@ -1675,10 +1433,8 @@ initiate_ra_proc(module_id_t module_idP, return; } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 1); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 0); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 1); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 0); for (i = 0; i < NB_RA_PROC_MAX; i++) { if (ra[i].state == IDLE) { diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 1bffb83d49..9e6b57619e 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -63,210 +63,206 @@ int choose(int n, int k) { - int res = 1; - int res2 = 1; - int i; + int res = 1; + int res2 = 1; + int i; - if (k > n) - return (0); - if (n == k) - return (1); + if (k > n) + return (0); + if (n == k) + return (1); - for (i = n; i > k; i--) - res *= i; - for (i = 2; i <= (n - k); i++) - res2 *= i; + for (i = n; i > k; i--) + res *= i; + for (i = 2; i <= (n - k); i++) + res2 *= i; - return (res / res2); + return (res / res2); } // Patented algorithm from Yang et al, US Patent 2009, "Channel Quality Indexing and Reverse Indexing" void reverse_index(int N, int M, int r, int *v) { - int BaseValue = 0; - int IncreaseValue, ThresholdValue; - int sumV; - int i; + int BaseValue = 0; + int IncreaseValue, ThresholdValue; + int sumV; + int i; - r = choose(N, M) - 1 - r; - memset((void *) v, 0, M * sizeof(int)); + r = choose(N, M) - 1 - r; + memset((void *) v, 0, M * sizeof(int)); - sumV = 0; - i = M; - while (i > 0 && r > 0) { - IncreaseValue = choose(N - M + 1 - sumV - v[i - 1] + i - 2, i - 1); - ThresholdValue = BaseValue + IncreaseValue; - if (r >= ThresholdValue) { - v[i - 1]++; - BaseValue = ThresholdValue; - } else { - r = r - BaseValue; - sumV += v[i - 1]; - i--; - BaseValue = 0; - } + sumV = 0; + i = M; + while (i > 0 && r > 0) { + IncreaseValue = choose(N - M + 1 - sumV - v[i - 1] + i - 2, i - 1); + ThresholdValue = BaseValue + IncreaseValue; + if (r >= ThresholdValue) { + v[i - 1]++; + BaseValue = ThresholdValue; + } else { + r = r - BaseValue; + sumV += v[i - 1]; + i--; + BaseValue = 0; } + } } int to_prb(int dl_Bandwidth) { - int prbmap[6] = { 6, 15, 25, 50, 75, 100 }; + int prbmap[6] = { 6, 15, 25, 50, 75, 100 }; - AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth is 0..5\n"); - return (prbmap[dl_Bandwidth]); + AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth is 0..5\n"); + return (prbmap[dl_Bandwidth]); } int to_rbg(int dl_Bandwidth) { - int rbgmap[6] = { 6, 8, 13, 17, 19, 25 }; + int rbgmap[6] = { 6, 8, 13, 17, 19, 25 }; - AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth is 0..5\n"); - return (rbgmap[dl_Bandwidth]); + AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth is 0..5\n"); + return (rbgmap[dl_Bandwidth]); } int get_phich_resource_times6(COMMON_channels_t * cc) { - int phichmap[4] = { 1, 3, 6, 12 }; - AssertFatal(cc != NULL, "cc is null\n"); - AssertFatal(cc->mib != NULL, "cc->mib is null\n"); - AssertFatal((cc->mib->message.phich_Config.phich_Resource >= 0) && - (cc->mib->message.phich_Config.phich_Resource < 4), - "phich_Resource %d not in 0..3\n", - (int) cc->mib->message.phich_Config.phich_Resource); + int phichmap[4] = { 1, 3, 6, 12 }; + AssertFatal(cc != NULL, "cc is null\n"); + AssertFatal(cc->mib != NULL, "cc->mib is null\n"); + AssertFatal((cc->mib->message.phich_Config.phich_Resource >= 0) && + (cc->mib->message.phich_Config.phich_Resource < 4), + "phich_Resource %d not in 0..3\n", + (int) cc->mib->message.phich_Config.phich_Resource); - return (phichmap[cc->mib->message.phich_Config.phich_Resource]); + return (phichmap[cc->mib->message.phich_Config.phich_Resource]); } uint16_t mac_computeRIV(uint16_t N_RB_DL, uint16_t RBstart, uint16_t Lcrbs) { - uint16_t RIV; + uint16_t RIV; - if (Lcrbs <= (1 + (N_RB_DL >> 1))) - RIV = (N_RB_DL * (Lcrbs - 1)) + RBstart; - else - RIV = (N_RB_DL * (N_RB_DL + 1 - Lcrbs)) + (N_RB_DL - 1 - RBstart); + if (Lcrbs <= (1 + (N_RB_DL >> 1))) RIV = (N_RB_DL * (Lcrbs - 1)) + RBstart; + else RIV = (N_RB_DL * (N_RB_DL + 1 - Lcrbs)) + (N_RB_DL - 1 - RBstart); - return (RIV); + return (RIV); } uint8_t getQm(uint8_t mcs) { - if (mcs < 10) - return (2); - else if (mcs < 17) - return (4); - else - return (6); + if (mcs < 10) return (2); + else if (mcs < 17) return (4); + else return (6); } void -get_Msg3alloc(COMMON_channels_t * cc, - sub_frame_t current_subframe, - frame_t current_frame, frame_t * frame, - sub_frame_t * subframe) +get_Msg3alloc(COMMON_channels_t *cc, + sub_frame_t current_subframe, + frame_t current_frame, + frame_t *frame, + sub_frame_t *subframe) { - // Fill in other TDD Configuration!!!! + // Fill in other TDD Configuration!!!! - if (cc->tdd_Config == NULL) { // FDD - *subframe = current_subframe + 6; + if (cc->tdd_Config == NULL) { // FDD + *subframe = current_subframe + 6; - if (*subframe > 9) { - *subframe = *subframe - 10; - *frame = (current_frame + 1) & 1023; - } else { - *frame = current_frame; - } - } else { // TDD - if (cc->tdd_Config->subframeAssignment == 1) { - switch (current_subframe) { - - case 0: - *subframe = 7; - *frame = current_frame; - break; - - case 4: - *subframe = 2; - *frame = (current_frame + 1) & 1023; - break; - - case 5: - *subframe = 2; - *frame = (current_frame + 1) & 1023; - break; - - case 9: - *subframe = 7; - *frame = (current_frame + 1) & 1023; - break; - } - } else if (cc->tdd_Config->subframeAssignment == 3) { - switch (current_subframe) { - - case 0: - case 5: - case 6: - *subframe = 2; - *frame = (current_frame + 1) & 1023; - break; - - case 7: - *subframe = 3; - *frame = (current_frame + 1) & 1023; - break; - - case 8: - *subframe = 4; - *frame = (current_frame + 1) & 1023; - break; - - case 9: - *subframe = 2; - *frame = (current_frame + 2) & 1023; - break; - } - } else if (cc->tdd_Config->subframeAssignment == 4) { - switch (current_subframe) { - - case 0: - case 4: - case 5: - case 6: - *subframe = 2; - *frame = (current_frame + 1) & 1023; - break; - - case 7: - *subframe = 3; - *frame = (current_frame + 1) & 1023; - break; - - case 8: - case 9: - *subframe = 2; - *frame = (current_frame + 2) & 1023; - break; - } - } else if (cc->tdd_Config->subframeAssignment == 5) { - switch (current_subframe) { - - case 0: - case 4: - case 5: - case 6: - *subframe = 2; - *frame = (current_frame + 1) & 1023; - break; - - case 7: - case 8: - case 9: - *subframe = 2; - *frame = (current_frame + 2) & 1023; - break; - } - } + if (*subframe > 9) { + *subframe = *subframe - 10; + *frame = (current_frame + 1) & 1023; + } else { + *frame = current_frame; } + } else { // TDD + if (cc->tdd_Config->subframeAssignment == 1) { + switch (current_subframe) { + + case 0: + *subframe = 7; + *frame = current_frame; + break; + + case 4: + *subframe = 2; + *frame = (current_frame + 1) & 1023; + break; + + case 5: + *subframe = 2; + *frame = (current_frame + 1) & 1023; + break; + + case 9: + *subframe = 7; + *frame = (current_frame + 1) & 1023; + break; + } + } else if (cc->tdd_Config->subframeAssignment == 3) { + switch (current_subframe) { + + case 0: + case 5: + case 6: + *subframe = 2; + *frame = (current_frame + 1) & 1023; + break; + + case 7: + *subframe = 3; + *frame = (current_frame + 1) & 1023; + break; + + case 8: + *subframe = 4; + *frame = (current_frame + 1) & 1023; + break; + + case 9: + *subframe = 2; + *frame = (current_frame + 2) & 1023; + break; + } + } else if (cc->tdd_Config->subframeAssignment == 4) { + switch (current_subframe) { + + case 0: + case 4: + case 5: + case 6: + *subframe = 2; + *frame = (current_frame + 1) & 1023; + break; + + case 7: + *subframe = 3; + *frame = (current_frame + 1) & 1023; + break; + + case 8: + case 9: + *subframe = 2; + *frame = (current_frame + 2) & 1023; + break; + } + } else if (cc->tdd_Config->subframeAssignment == 5) { + switch (current_subframe) { + + case 0: + case 4: + case 5: + case 6: + *subframe = 2; + *frame = (current_frame + 1) & 1023; + break; + + case 7: + case 8: + case 9: + *subframe = 2; + *frame = (current_frame + 2) & 1023; + break; + } + } + } } @@ -277,466 +273,445 @@ get_Msg3allocret(COMMON_channels_t * cc, frame_t current_frame, frame_t * frame, sub_frame_t * subframe) { - if (cc->tdd_Config == NULL) { //FDD - /* always retransmit in n+8 */ - *subframe = current_subframe + 8; + if (cc->tdd_Config == NULL) { //FDD + /* always retransmit in n+8 */ + *subframe = current_subframe + 8; - if (*subframe > 9) { - *subframe = *subframe - 10; - *frame = (current_frame + 1) & 1023; - } else { - *frame = current_frame; - } + if (*subframe > 9) { + *subframe = *subframe - 10; + *frame = (current_frame + 1) & 1023; } else { - if (cc->tdd_Config->subframeAssignment == 1) { - // original PUSCH in 2, PHICH in 6 (S), ret in 2 - // original PUSCH in 3, PHICH in 9, ret in 3 - // original PUSCH in 7, PHICH in 1 (S), ret in 7 - // original PUSCH in 8, PHICH in 4, ret in 8 - *frame = (current_frame + 1) & 1023; - } else if (cc->tdd_Config->subframeAssignment == 3) { - // original PUSCH in 2, PHICH in 8, ret in 2 next frame - // original PUSCH in 3, PHICH in 9, ret in 3 next frame - // original PUSCH in 4, PHICH in 0, ret in 4 next frame - *frame = (current_frame + 1) & 1023; - } else if (cc->tdd_Config->subframeAssignment == 4) { - // original PUSCH in 2, PHICH in 8, ret in 2 next frame - // original PUSCH in 3, PHICH in 9, ret in 3 next frame - *frame = (current_frame + 1) & 1023; - } else if (cc->tdd_Config->subframeAssignment == 5) { - // original PUSCH in 2, PHICH in 8, ret in 2 next frame - *frame = (current_frame + 1) & 1023; - } + *frame = current_frame; } + } else { + if (cc->tdd_Config->subframeAssignment == 1) { + // original PUSCH in 2, PHICH in 6 (S), ret in 2 + // original PUSCH in 3, PHICH in 9, ret in 3 + // original PUSCH in 7, PHICH in 1 (S), ret in 7 + // original PUSCH in 8, PHICH in 4, ret in 8 + *frame = (current_frame + 1) & 1023; + } else if (cc->tdd_Config->subframeAssignment == 3) { + // original PUSCH in 2, PHICH in 8, ret in 2 next frame + // original PUSCH in 3, PHICH in 9, ret in 3 next frame + // original PUSCH in 4, PHICH in 0, ret in 4 next frame + *frame = (current_frame + 1) & 1023; + } else if (cc->tdd_Config->subframeAssignment == 4) { + // original PUSCH in 2, PHICH in 8, ret in 2 next frame + // original PUSCH in 3, PHICH in 9, ret in 3 next frame + *frame = (current_frame + 1) & 1023; + } else if (cc->tdd_Config->subframeAssignment == 5) { + // original PUSCH in 2, PHICH in 8, ret in 2 next frame + *frame = (current_frame + 1) & 1023; + } + } } uint8_t subframe2harqpid(COMMON_channels_t * cc, frame_t frame, sub_frame_t subframe) { - uint8_t ret = 255; + uint8_t ret = 255; - AssertFatal(cc != NULL, "cc is null\n"); - - if (cc->tdd_Config == NULL) { // FDD - ret = (((frame << 1) + subframe) & 7); - } else { - switch (cc->tdd_Config->subframeAssignment) { - case 1: - if ((subframe == 2) || - (subframe == 3) || (subframe == 7) || (subframe == 8)) - switch (subframe) { - case 2: - case 3: - ret = (subframe - 2); - break; - - case 7: - case 8: - ret = (subframe - 5); - break; - - default: - AssertFatal(1 == 0, - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", - subframe, - (int) cc->tdd_Config->subframeAssignment); - break; - } - - break; + AssertFatal(cc != NULL, "cc is null\n"); + if (cc->tdd_Config == NULL) { // FDD + ret = (((frame << 1) + subframe) & 7); + } else { + switch (cc->tdd_Config->subframeAssignment) { + case 1: + if ((subframe == 2) || + (subframe == 3) || (subframe == 7) || (subframe == 8)) + switch (subframe) { case 2: - AssertFatal((subframe == 2) || (subframe == 7), - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", - subframe, - (int) cc->tdd_Config->subframeAssignment); - - ret = (subframe / 7); - break; - case 3: - AssertFatal((subframe > 1) && (subframe < 5), - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", - subframe, - (int) cc->tdd_Config->subframeAssignment); - ret = (subframe - 2); - break; - - case 4: - AssertFatal((subframe > 1) && (subframe < 4), - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", - subframe, - (int) cc->tdd_Config->subframeAssignment); - ret = (subframe - 2); - break; - - case 5: - AssertFatal(subframe == 2, - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", - subframe, - (int) cc->tdd_Config->subframeAssignment); - ret = (subframe - 2); - break; - + ret = (subframe - 2); + break; + case 7: + case 8: + ret = (subframe - 5); + break; default: - AssertFatal(1 == 0, - "subframe2_harq_pid, Unsupported TDD mode %d\n", - (int) cc->tdd_Config->subframeAssignment); + AssertFatal(1 == 0, + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframe, + (int) cc->tdd_Config->subframeAssignment); + break; } + + break; + + case 2: + AssertFatal((subframe == 2) || (subframe == 7), + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframe, + (int) cc->tdd_Config->subframeAssignment); + + ret = (subframe / 7); + break; + + case 3: + AssertFatal((subframe > 1) && (subframe < 5), + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframe, + (int) cc->tdd_Config->subframeAssignment); + ret = (subframe - 2); + break; + + case 4: + AssertFatal((subframe > 1) && (subframe < 4), + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframe, + (int) cc->tdd_Config->subframeAssignment); + ret = (subframe - 2); + break; + + case 5: + AssertFatal(subframe == 2, + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframe, + (int) cc->tdd_Config->subframeAssignment); + ret = (subframe - 2); + break; + + default: + AssertFatal(1 == 0, + "subframe2_harq_pid, Unsupported TDD mode %d\n", + (int) cc->tdd_Config->subframeAssignment); } - return ret; + } + return ret; } uint8_t get_Msg3harqpid(COMMON_channels_t * cc, frame_t frame, sub_frame_t current_subframe) { - uint8_t ul_subframe = 0; - uint32_t ul_frame = 0; + uint8_t ul_subframe = 0; + uint32_t ul_frame = 0; - if (cc->tdd_Config == NULL) { // FDD - ul_subframe = - (current_subframe > - 3) ? (current_subframe - 4) : (current_subframe + 6); - ul_frame = (current_subframe > 3) ? ((frame + 1) & 1023) : frame; - } else { - switch (cc->tdd_Config->subframeAssignment) { - case 1: - switch (current_subframe) { - case 9: - case 0: - ul_subframe = 7; - break; - - case 5: - case 7: - ul_subframe = 2; - break; - - } - - break; - - case 3: - switch (current_subframe) { - case 0: - case 5: - case 6: - ul_subframe = 2; - break; - - case 7: - ul_subframe = 3; - break; - - case 8: - ul_subframe = 4; - break; - - case 9: - ul_subframe = 2; - break; - } - - break; - - case 4: - switch (current_subframe) { - case 0: - case 5: - case 6: - case 8: - case 9: - ul_subframe = 2; - break; - - case 7: - ul_subframe = 3; - break; - } - - break; - - case 5: - ul_subframe = 2; - break; - - default: - LOG_E(PHY, - "get_Msg3_harq_pid: Unsupported TDD configuration %d\n", - (int) cc->tdd_Config->subframeAssignment); - AssertFatal(1 == 0, - "get_Msg3_harq_pid: Unsupported TDD configuration"); - break; - } + if (cc->tdd_Config == NULL) { // FDD + ul_subframe = + (current_subframe > + 3) ? (current_subframe - 4) : (current_subframe + 6); + ul_frame = (current_subframe > 3) ? ((frame + 1) & 1023) : frame; + } else { + switch (cc->tdd_Config->subframeAssignment) { + case 1: + switch (current_subframe) { + case 9: + case 0: + ul_subframe = 7; + break; + case 5: + case 7: + ul_subframe = 2; + break; + } + break; + case 3: + switch (current_subframe) { + case 0: + case 5: + case 6: + ul_subframe = 2; + break; + case 7: + ul_subframe = 3; + break; + case 8: + ul_subframe = 4; + break; + case 9: + ul_subframe = 2; + break; + } + break; + case 4: + switch (current_subframe) { + case 0: + case 5: + case 6: + case 8: + case 9: + ul_subframe = 2; + break; + case 7: + ul_subframe = 3; + break; + } + break; + case 5: + ul_subframe = 2; + break; + default: + LOG_E(PHY, + "get_Msg3_harq_pid: Unsupported TDD configuration %d\n", + (int) cc->tdd_Config->subframeAssignment); + AssertFatal(1 == 0, + "get_Msg3_harq_pid: Unsupported TDD configuration"); + break; } + } - return (subframe2harqpid(cc, ul_frame, ul_subframe)); + return (subframe2harqpid(cc, ul_frame, ul_subframe)); } uint32_t pdcchalloc2ulframe(COMMON_channels_t * ccP, uint32_t frame, uint8_t n) { - uint32_t ul_frame; + uint32_t ul_frame; - if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 1) && ((n == 1) || (n == 6))) // tdd_config 0,1 SF 1,5 - ul_frame = (frame + (n == 1 ? 0 : 1)); - else if ((ccP->tdd_Config) && - (ccP->tdd_Config->subframeAssignment == 6) && - ((n == 0) || (n == 1) || (n == 5) || (n == 6))) - ul_frame = (frame + (n >= 5 ? 1 : 0)); - else if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 6) && (n == 9)) // tdd_config 6 SF 9 - ul_frame = (frame + 1); - else - ul_frame = (frame + (n >= 6 ? 1 : 0)); + if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 1) && ((n == 1) || (n == 6))) // tdd_config 0,1 SF 1,5 + ul_frame = (frame + (n == 1 ? 0 : 1)); + else if ((ccP->tdd_Config) && + (ccP->tdd_Config->subframeAssignment == 6) && + ((n == 0) || (n == 1) || (n == 5) || (n == 6))) + ul_frame = (frame + (n >= 5 ? 1 : 0)); + else if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 6) && (n == 9)) // tdd_config 6 SF 9 + ul_frame = (frame + 1); + else + ul_frame = (frame + (n >= 6 ? 1 : 0)); - LOG_D(PHY, "frame %d subframe %d: PUSCH frame = %d\n", frame, n, - ul_frame); - return ul_frame; + LOG_D(PHY, "frame %d subframe %d: PUSCH frame = %d\n", frame, n, + ul_frame); + return ul_frame; } uint8_t pdcchalloc2ulsubframe(COMMON_channels_t * ccP, uint8_t n) { - uint8_t ul_subframe; + uint8_t ul_subframe; - if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 1) && ((n == 1) || (n == 6))) // tdd_config 0,1 SF 1,5 - ul_subframe = ((n + 6) % 10); - else if ((ccP->tdd_Config) && - (ccP->tdd_Config->subframeAssignment == 6) && - ((n == 0) || (n == 1) || (n == 5) || (n == 6))) - ul_subframe = ((n + 7) % 10); - else if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 6) && (n == 9)) // tdd_config 6 SF 9 - ul_subframe = ((n + 5) % 10); - else - ul_subframe = ((n + 4) % 10); + if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 1) && ((n == 1) || (n == 6))) // tdd_config 0,1 SF 1,5 + ul_subframe = ((n + 6) % 10); + else if ((ccP->tdd_Config) && + (ccP->tdd_Config->subframeAssignment == 6) && + ((n == 0) || (n == 1) || (n == 5) || (n == 6))) + ul_subframe = ((n + 7) % 10); + else if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 6) && (n == 9)) // tdd_config 6 SF 9 + ul_subframe = ((n + 5) % 10); + else + ul_subframe = ((n + 4) % 10); - LOG_D(PHY, "subframe %d: PUSCH subframe = %d\n", n, ul_subframe); - return ul_subframe; + LOG_D(PHY, "subframe %d: PUSCH subframe = %d\n", n, ul_subframe); + return ul_subframe; } int is_UL_sf(COMMON_channels_t * ccP, sub_frame_t subframeP) { - // if FDD return dummy value - if (ccP->tdd_Config == NULL) - return (0); - - switch (ccP->tdd_Config->subframeAssignment) { - case 1: - switch (subframeP) { - case 0: - case 4: - case 5: - case 9: - return (0); - break; - - case 2: - case 3: - case 7: - case 8: - return (1); - break; - - default: - return (0); - break; - } - break; - - case 3: - if ((subframeP <= 1) || (subframeP >= 5)) - return (0); - else if ((subframeP > 1) && (subframeP < 5)) - return (1); - else - AssertFatal(1 == 0, "Unknown subframe number\n"); - break; + // if FDD return dummy value + if (ccP->tdd_Config == NULL) + return (0); + switch (ccP->tdd_Config->subframeAssignment) { + case 1: + switch (subframeP) { + case 0: case 4: - if ((subframeP <= 1) || (subframeP >= 4)) - return (0); - else if ((subframeP > 1) && (subframeP < 4)) - return (1); - else - AssertFatal(1 == 0, "Unknown subframe number\n"); - break; - case 5: - if ((subframeP <= 1) || (subframeP >= 3)) - return (0); - else if ((subframeP > 1) && (subframeP < 3)) - return (1); - else - AssertFatal(1 == 0, "Unknown subframe number\n"); - break; - + case 9: + return (0); + break; + case 2: + case 3: + case 7: + case 8: + return (1); + break; default: - AssertFatal(1 == 0, - "subframe %d Unsupported TDD configuration %d\n", - subframeP, (int) ccP->tdd_Config->subframeAssignment); - break; + return (0); + break; } + break; + case 3: + if ((subframeP <= 1) || (subframeP >= 5)) + return (0); + else if ((subframeP > 1) && (subframeP < 5)) + return (1); + else + AssertFatal(1 == 0, "Unknown subframe number\n"); + break; + case 4: + if ((subframeP <= 1) || (subframeP >= 4)) + return (0); + else if ((subframeP > 1) && (subframeP < 4)) + return (1); + else + AssertFatal(1 == 0, "Unknown subframe number\n"); + break; + case 5: + if ((subframeP <= 1) || (subframeP >= 3)) + return (0); + else if ((subframeP > 1) && (subframeP < 3)) + return (1); + else + AssertFatal(1 == 0, "Unknown subframe number\n"); + break; + default: + AssertFatal(1 == 0, + "subframe %d Unsupported TDD configuration %d\n", + subframeP, (int) ccP->tdd_Config->subframeAssignment); + break; + } } uint16_t get_pucch1_absSF(COMMON_channels_t * cc, uint16_t dlsch_absSF) { - uint16_t sf, f, nextf; + uint16_t sf, f, nextf; - if (cc->tdd_Config == NULL) { //FDD n+4 - return ((dlsch_absSF + 4) % 10240); - } else { - sf = dlsch_absSF % 10; - f = dlsch_absSF / 10; - nextf = (f + 1) & 1023; + if (cc->tdd_Config == NULL) { //FDD n+4 + return ((dlsch_absSF + 4) % 10240); + } else { + sf = dlsch_absSF % 10; + f = dlsch_absSF / 10; + nextf = (f + 1) & 1023; - switch (cc->tdd_Config->subframeAssignment) { - case 0: - AssertFatal(1 == 0, "SFA 0 to be filled in now, :-)\n"); - break; - case 1: - if ((sf == 5) || (sf == 6)) - return ((10 * nextf) + 2); // ACK/NAK in SF 2 next frame - else if (sf == 9) - return ((10 * nextf) + 3); // ACK/NAK in SF 3 next frame - else if ((sf == 0) || (sf == 1)) - return ((10 * f) + 2); // ACK/NAK in SF 7 same frame - else - AssertFatal(1 == 0, - "Impossible dlsch subframe %d for TDD configuration 3\n", - sf); - break; - case 2: - if ((sf == 4) || (sf == 5) || (sf == 6) || (sf == 8)) - return ((10 * nextf) + 2); // ACK/NAK in SF 2 next frame - else if (sf == 9) - return ((10 * nextf) + 7); // ACK/NAK in SF 7 next frame - else if ((sf == 0) || (sf == 1) || (sf == 3)) - return ((10 * f) + 7); // ACK/NAK in SF 7 same frame - else - AssertFatal(1 == 0, - "Impossible dlsch subframe %d for TDD configuration 3\n", - sf); - break; - case 3: - if ((sf == 5) || (sf == 6) || (sf == 7) || (sf == 8) - || (sf == 9)) - return ((10 * nextf) + (sf >> 1)); // ACK/NAK in 2,3,4 resp. next frame - else if (sf == 1) - return ((10 * nextf) + 2); // ACK/NAK in 2 next frame - else if (sf == 0) - return ((10 * f) + 4); // ACK/NAK in 4 same frame - else - AssertFatal(1 == 0, - "Impossible dlsch subframe %d for TDD configuration 3\n", - sf); - break; - case 4: - if ((sf == 6) || (sf == 7) || (sf == 8) || (sf == 9)) - return (((10 * nextf) + 3) % 10240); // ACK/NAK in SF 3 next frame - else if ((sf == 0) || (sf == 1) || (sf == 4) || (sf == 5)) - return (((10 * nextf) + 2) % 10240); // ACK/NAK in SF 2 next frame - else - AssertFatal(1 == 0, - "Impossible dlsch subframe %d for TDD configuration 4\n", - sf); - break; - case 5: - if ((sf == 0) || (sf == 1) || (sf == 3) || (sf == 4) - || (sf == 5) || (sf == 6) || (sf == 7) || (sf == 8)) - return (((10 * nextf) + 2) % 10240); // ACK/NAK in SF 3 next frame - else if (sf == 9) - return (((10 * (1 + nextf)) + 2) % 10240); // ACK/NAK in SF 2 next frame - else - AssertFatal(1 == 0, - "Impossible dlsch subframe %d for TDD configuration 5\n", - sf); - break; - case 6: - AssertFatal(1 == 0, "SFA 6 To be filled in now, :-)\n"); - break; - default: - AssertFatal(1 == 0, "Illegal TDD subframe Assigment %d\n", - (int) cc->tdd_Config->subframeAssignment); - break; - } + switch (cc->tdd_Config->subframeAssignment) { + case 0: + AssertFatal(1 == 0, "SFA 0 to be filled in now, :-)\n"); + break; + case 1: + if ((sf == 5) || (sf == 6)) + return ((10 * nextf) + 2); // ACK/NAK in SF 2 next frame + else if (sf == 9) + return ((10 * nextf) + 3); // ACK/NAK in SF 3 next frame + else if ((sf == 0) || (sf == 1)) + return ((10 * f) + 2); // ACK/NAK in SF 7 same frame + else + AssertFatal(1 == 0, + "Impossible dlsch subframe %d for TDD configuration 3\n", + sf); + break; + case 2: + if ((sf == 4) || (sf == 5) || (sf == 6) || (sf == 8)) + return ((10 * nextf) + 2); // ACK/NAK in SF 2 next frame + else if (sf == 9) + return ((10 * nextf) + 7); // ACK/NAK in SF 7 next frame + else if ((sf == 0) || (sf == 1) || (sf == 3)) + return ((10 * f) + 7); // ACK/NAK in SF 7 same frame + else + AssertFatal(1 == 0, + "Impossible dlsch subframe %d for TDD configuration 3\n", + sf); + break; + case 3: + if ((sf == 5) || (sf == 6) || (sf == 7) || (sf == 8) + || (sf == 9)) + return ((10 * nextf) + (sf >> 1)); // ACK/NAK in 2,3,4 resp. next frame + else if (sf == 1) + return ((10 * nextf) + 2); // ACK/NAK in 2 next frame + else if (sf == 0) + return ((10 * f) + 4); // ACK/NAK in 4 same frame + else + AssertFatal(1 == 0, + "Impossible dlsch subframe %d for TDD configuration 3\n", + sf); + break; + case 4: + if ((sf == 6) || (sf == 7) || (sf == 8) || (sf == 9)) + return (((10 * nextf) + 3) % 10240); // ACK/NAK in SF 3 next frame + else if ((sf == 0) || (sf == 1) || (sf == 4) || (sf == 5)) + return (((10 * nextf) + 2) % 10240); // ACK/NAK in SF 2 next frame + else + AssertFatal(1 == 0, + "Impossible dlsch subframe %d for TDD configuration 4\n", + sf); + break; + case 5: + if ((sf == 0) || (sf == 1) || (sf == 3) || (sf == 4) + || (sf == 5) || (sf == 6) || (sf == 7) || (sf == 8)) + return (((10 * nextf) + 2) % 10240); // ACK/NAK in SF 3 next frame + else if (sf == 9) + return (((10 * (1 + nextf)) + 2) % 10240); // ACK/NAK in SF 2 next frame + else + AssertFatal(1 == 0, + "Impossible dlsch subframe %d for TDD configuration 5\n", + sf); + break; + case 6: + AssertFatal(1 == 0, "SFA 6 To be filled in now, :-)\n"); + break; + default: + AssertFatal(1 == 0, "Illegal TDD subframe Assigment %d\n", + (int) cc->tdd_Config->subframeAssignment); + break; } - AssertFatal(1 == 0, "Shouldn't get here\n"); + } + AssertFatal(1 == 0, "Shouldn't get here\n"); } void get_srs_pos(COMMON_channels_t * cc, uint16_t isrs, uint16_t * psrsPeriodicity, uint16_t * psrsOffset) { - if (cc->tdd_Config) { // TDD - AssertFatal(isrs >= 10, "2 ms SRS periodicity not supported"); + if (cc->tdd_Config) { // TDD + AssertFatal(isrs >= 10, "2 ms SRS periodicity not supported"); - if ((isrs > 9) && (isrs < 15)) { - *psrsPeriodicity = 5; - *psrsOffset = isrs - 10; - } - if ((isrs > 14) && (isrs < 25)) { - *psrsPeriodicity = 10; - *psrsOffset = isrs - 15; - } - if ((isrs > 24) && (isrs < 45)) { - *psrsPeriodicity = 20; - *psrsOffset = isrs - 25; - } - if ((isrs > 44) && (isrs < 85)) { - *psrsPeriodicity = 40; - *psrsOffset = isrs - 45; - } - if ((isrs > 84) && (isrs < 165)) { - *psrsPeriodicity = 80; - *psrsOffset = isrs - 85; - } - if ((isrs > 164) && (isrs < 325)) { - *psrsPeriodicity = 160; - *psrsOffset = isrs - 165; - } - if ((isrs > 324) && (isrs < 645)) { - *psrsPeriodicity = 320; - *psrsOffset = isrs - 325; - } - - AssertFatal(isrs <= 644, "Isrs out of range %d>644\n", isrs); - } // TDD - else { // FDD - if (isrs < 2) { - *psrsPeriodicity = 2; - *psrsOffset = isrs; - } - if ((isrs > 1) && (isrs < 7)) { - *psrsPeriodicity = 5; - *psrsOffset = isrs - 2; - } - if ((isrs > 6) && (isrs < 17)) { - *psrsPeriodicity = 10; - *psrsOffset = isrs - 7; - } - if ((isrs > 16) && (isrs < 37)) { - *psrsPeriodicity = 20; - *psrsOffset = isrs - 17; - } - if ((isrs > 36) && (isrs < 77)) { - *psrsPeriodicity = 40; - *psrsOffset = isrs - 37; - } - if ((isrs > 76) && (isrs < 157)) { - *psrsPeriodicity = 80; - *psrsOffset = isrs - 77; - } - if ((isrs > 156) && (isrs < 317)) { - *psrsPeriodicity = 160; - *psrsOffset = isrs - 157; - } - if ((isrs > 316) && (isrs < 637)) { - *psrsPeriodicity = 320; - *psrsOffset = isrs - 317; - } - AssertFatal(isrs <= 636, "Isrs out of range %d>636\n", isrs); + if ((isrs > 9) && (isrs < 15)) { + *psrsPeriodicity = 5; + *psrsOffset = isrs - 10; } + if ((isrs > 14) && (isrs < 25)) { + *psrsPeriodicity = 10; + *psrsOffset = isrs - 15; + } + if ((isrs > 24) && (isrs < 45)) { + *psrsPeriodicity = 20; + *psrsOffset = isrs - 25; + } + if ((isrs > 44) && (isrs < 85)) { + *psrsPeriodicity = 40; + *psrsOffset = isrs - 45; + } + if ((isrs > 84) && (isrs < 165)) { + *psrsPeriodicity = 80; + *psrsOffset = isrs - 85; + } + if ((isrs > 164) && (isrs < 325)) { + *psrsPeriodicity = 160; + *psrsOffset = isrs - 165; + } + if ((isrs > 324) && (isrs < 645)) { + *psrsPeriodicity = 320; + *psrsOffset = isrs - 325; + } + + AssertFatal(isrs <= 644, "Isrs out of range %d>644\n", isrs); + } // TDD + else { // FDD + if (isrs < 2) { + *psrsPeriodicity = 2; + *psrsOffset = isrs; + } + if ((isrs > 1) && (isrs < 7)) { + *psrsPeriodicity = 5; + *psrsOffset = isrs - 2; + } + if ((isrs > 6) && (isrs < 17)) { + *psrsPeriodicity = 10; + *psrsOffset = isrs - 7; + } + if ((isrs > 16) && (isrs < 37)) { + *psrsPeriodicity = 20; + *psrsOffset = isrs - 17; + } + if ((isrs > 36) && (isrs < 77)) { + *psrsPeriodicity = 40; + *psrsOffset = isrs - 37; + } + if ((isrs > 76) && (isrs < 157)) { + *psrsPeriodicity = 80; + *psrsOffset = isrs - 77; + } + if ((isrs > 156) && (isrs < 317)) { + *psrsPeriodicity = 160; + *psrsOffset = isrs - 157; + } + if ((isrs > 316) && (isrs < 637)) { + *psrsPeriodicity = 320; + *psrsOffset = isrs - 317; + } + AssertFatal(isrs <= 636, "Isrs out of range %d>636\n", isrs); + } } void @@ -744,83 +719,83 @@ get_csi_params(COMMON_channels_t * cc, struct CQI_ReportPeriodic *cqi_ReportPeriodic, uint16_t * Npd, uint16_t * N_OFFSET_CQI, int *H) { - uint16_t cqi_PMI_ConfigIndex = - cqi_ReportPeriodic->choice.setup.cqi_pmi_ConfigIndex; - uint8_t Jtab[6] = { 0, 2, 2, 3, 4, 4 }; + uint16_t cqi_PMI_ConfigIndex = + cqi_ReportPeriodic->choice.setup.cqi_pmi_ConfigIndex; + uint8_t Jtab[6] = { 0, 2, 2, 3, 4, 4 }; - AssertFatal(cqi_ReportPeriodic != NULL, - "cqi_ReportPeriodic is null!\n"); + AssertFatal(cqi_ReportPeriodic != NULL, + "cqi_ReportPeriodic is null!\n"); - if (cc->tdd_Config == NULL) { //FDD - if (cqi_PMI_ConfigIndex <= 1) { // 2 ms CQI_PMI period - *Npd = 2; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex; - } else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period - *Npd = 5; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 2; - } else if (cqi_PMI_ConfigIndex <= 16) { // 10ms CQI_PMI period - *Npd = 10; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 7; - } else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period - *Npd = 20; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 17; - } else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period - *Npd = 40; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 37; - } else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period - *Npd = 80; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 77; - } else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period - *Npd = 160; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 157; - } else if (cqi_PMI_ConfigIndex > 317) { + if (cc->tdd_Config == NULL) { //FDD + if (cqi_PMI_ConfigIndex <= 1) { // 2 ms CQI_PMI period + *Npd = 2; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex; + } else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period + *Npd = 5; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 2; + } else if (cqi_PMI_ConfigIndex <= 16) { // 10ms CQI_PMI period + *Npd = 10; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 7; + } else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period + *Npd = 20; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 17; + } else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period + *Npd = 40; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 37; + } else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period + *Npd = 80; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 77; + } else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period + *Npd = 160; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 157; + } else if (cqi_PMI_ConfigIndex > 317) { - if (cqi_PMI_ConfigIndex <= 349) { // 32 ms CQI_PMI period - *Npd = 32; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 318; - } else if (cqi_PMI_ConfigIndex <= 413) { // 64 ms CQI_PMI period - *Npd = 64; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 350; - } else if (cqi_PMI_ConfigIndex <= 541) { // 128 ms CQI_PMI period - *Npd = 128; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 414; - } - } - } else { // TDD - if (cqi_PMI_ConfigIndex == 0) { // all UL subframes - *Npd = 1; - *N_OFFSET_CQI = 0; - } else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period - *Npd = 5; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 1; - } else if (cqi_PMI_ConfigIndex <= 16) { // 10ms CQI_PMI period - *Npd = 10; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 6; - } else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period - *Npd = 20; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 16; - } else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period - *Npd = 40; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 36; - } else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period - *Npd = 80; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 76; - } else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period - *Npd = 160; - *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 156; - } + if (cqi_PMI_ConfigIndex <= 349) { // 32 ms CQI_PMI period + *Npd = 32; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 318; + } else if (cqi_PMI_ConfigIndex <= 413) { // 64 ms CQI_PMI period + *Npd = 64; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 350; + } else if (cqi_PMI_ConfigIndex <= 541) { // 128 ms CQI_PMI period + *Npd = 128; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 414; + } } + } else { // TDD + if (cqi_PMI_ConfigIndex == 0) { // all UL subframes + *Npd = 1; + *N_OFFSET_CQI = 0; + } else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period + *Npd = 5; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 1; + } else if (cqi_PMI_ConfigIndex <= 16) { // 10ms CQI_PMI period + *Npd = 10; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 6; + } else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period + *Npd = 20; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 16; + } else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period + *Npd = 40; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 36; + } else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period + *Npd = 80; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 76; + } else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period + *Npd = 160; + *N_OFFSET_CQI = cqi_PMI_ConfigIndex - 156; + } + } - // get H - if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic. - present == - CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) - *H = 1 + - (Jtab[cc->mib->message.dl_Bandwidth] * - cqi_ReportPeriodic->choice.setup. - cqi_FormatIndicatorPeriodic.choice.subbandCQI.k); - else - *H = 1; + // get H + if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic. + present == + CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) + *H = 1 + + (Jtab[cc->mib->message.dl_Bandwidth] * + cqi_ReportPeriodic->choice.setup. + cqi_FormatIndicatorPeriodic.choice.subbandCQI.k); + else + *H = 1; } uint8_t @@ -829,127 +804,127 @@ get_dl_cqi_pmi_size_pusch(COMMON_channels_t * cc, uint8_t tmode, CQI_ReportModeAperiodic_t * cqi_ReportModeAperiodic) { - int Ntab[6] = { 0, 4, 7, 9, 10, 13 }; - int N = Ntab[cc->mib->message.dl_Bandwidth]; - int Ltab_uesel[6] = { 0, 6, 9, 13, 15, 18 }; - int L = Ltab_uesel[cc->mib->message.dl_Bandwidth]; + int Ntab[6] = { 0, 4, 7, 9, 10, 13 }; + int N = Ntab[cc->mib->message.dl_Bandwidth]; + int Ltab_uesel[6] = { 0, 6, 9, 13, 15, 18 }; + int L = Ltab_uesel[cc->mib->message.dl_Bandwidth]; - AssertFatal(cqi_ReportModeAperiodic != NULL, - "cqi_ReportPeriodic is null!\n"); + AssertFatal(cqi_ReportModeAperiodic != NULL, + "cqi_ReportPeriodic is null!\n"); - switch (*cqi_ReportModeAperiodic) { - case CQI_ReportModeAperiodic_rm12: - AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 - || tmode == 10, - "Illegal TM (%d) for CQI_ReportModeAperiodic_rm12\n", - tmode); - AssertFatal(cc->p_eNB <= 4, - "only up to 4 antenna ports supported here\n"); - if (ri == 1 && cc->p_eNB == 2) - return (4 + (N << 1)); - else if (ri == 2 && cc->p_eNB == 2) - return (8 + N); - else if (ri == 1 && cc->p_eNB == 4) - return (4 + (N << 2)); - else if (ri > 1 && cc->p_eNB == 4) - return (8 + (N << 2)); - break; - case CQI_ReportModeAperiodic_rm20: - // Table 5.2.2.6.3-1 (36.212) - AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 || tmode == 7 - || tmode == 9 - || tmode == 10, - "Illegal TM (%d) for CQI_ReportModeAperiodic_rm20\n", - tmode); - AssertFatal(tmode != 9 - && tmode != 10, - "TM9/10 will be handled later for CQI_ReportModeAperiodic_rm20\n"); - return (4 + 2 + L); - break; - case CQI_ReportModeAperiodic_rm22: - // Table 5.2.2.6.3-2 (36.212) - AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 - || tmode == 10, - "Illegal TM (%d) for CQI_ReportModeAperiodic_rm22\n", - tmode); - AssertFatal(tmode != 9 - && tmode != 10, - "TM9/10 will be handled later for CQI_ReportModeAperiodic_rm22\n"); - if (ri == 1 && cc->p_eNB == 2) - return (4 + 2 + 0 + 0 + L + 4); - if (ri == 2 && cc->p_eNB == 2) - return (4 + 2 + 4 + 2 + L + 2); - if (ri == 1 && cc->p_eNB == 4) - return (4 + 2 + 0 + 0 + L + 8); - if (ri >= 2 && cc->p_eNB == 4) - return (4 + 2 + 4 + 2 + L + 8); - break; - case CQI_ReportModeAperiodic_rm30: - // Table 5.2.2.6.2-1 (36.212) - AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 || tmode == 7 - || tmode == 8 || tmode == 9 - || tmode == 10, - "Illegal TM (%d) for CQI_ReportModeAperiodic_rm30\n", - tmode); - AssertFatal(tmode != 8 && tmode != 9 - && tmode != 10, - "TM8/9/10 will be handled later for CQI_ReportModeAperiodic_rm30\n"); - return (4 + (N << 1)); - break; - case CQI_ReportModeAperiodic_rm31: - // Table 5.2.2.6.2-2 (36.212) - AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 - || tmode == 10, - "Illegal TM (%d) for CQI_ReportModeAperiodic_rm31\n", - tmode); - AssertFatal(tmode != 8 && tmode != 9 - && tmode != 10, - "TM8/9/10 will be handled later for CQI_ReportModeAperiodic_rm31\n"); - if (ri == 1 && cc->p_eNB == 2) - return (4 + (N << 1) + 0 + 0 + 2); - else if (ri == 2 && cc->p_eNB == 2) - return (4 + (N << 1) + 4 + (N << 1) + 1); - else if (ri == 1 && cc->p_eNB == 4) - return (4 + (N << 1) + 0 + 0 + 4); - else if (ri >= 2 && cc->p_eNB == 4) - return (4 + (N << 1) + 4 + (N << 1) + 4); - break; - case CQI_ReportModeAperiodic_rm32_v1250: - AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 - || tmode == 10, - "Illegal TM (%d) for CQI_ReportModeAperiodic_rm32\n", - tmode); - AssertFatal(1 == 0, - "CQI_ReportModeAperiodic_rm32_v1250 not supported yet\n"); - break; - case CQI_ReportModeAperiodic_rm10_v1310: - // Table 5.2.2.6.1-1F/G (36.212) - if (ri == 1) - return (4); // F - else - return (7); // G - break; - case CQI_ReportModeAperiodic_rm11_v1310: - // Table 5.2.2.6.1-1H (36.212) - AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 - || tmode == 10, - "Illegal TM (%d) for CQI_ReportModeAperiodic_rm11\n", - tmode); - AssertFatal(cc->p_eNB <= 4, - "only up to 4 antenna ports supported here\n"); - if (ri == 1 && cc->p_eNB == 2) - return (4 + 0 + 2); - else if (ri == 2 && cc->p_eNB == 2) - return (4 + 4 + 1); - else if (ri == 1 && cc->p_eNB == 4) - return (4 + 0 + 4); - else if (ri > 1 && cc->p_eNB == 4) - return (4 + 4 + 4); + switch (*cqi_ReportModeAperiodic) { + case CQI_ReportModeAperiodic_rm12: + AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal TM (%d) for CQI_ReportModeAperiodic_rm12\n", + tmode); + AssertFatal(cc->p_eNB <= 4, + "only up to 4 antenna ports supported here\n"); + if (ri == 1 && cc->p_eNB == 2) + return (4 + (N << 1)); + else if (ri == 2 && cc->p_eNB == 2) + return (8 + N); + else if (ri == 1 && cc->p_eNB == 4) + return (4 + (N << 2)); + else if (ri > 1 && cc->p_eNB == 4) + return (8 + (N << 2)); + break; + case CQI_ReportModeAperiodic_rm20: + // Table 5.2.2.6.3-1 (36.212) + AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 || tmode == 7 + || tmode == 9 + || tmode == 10, + "Illegal TM (%d) for CQI_ReportModeAperiodic_rm20\n", + tmode); + AssertFatal(tmode != 9 + && tmode != 10, + "TM9/10 will be handled later for CQI_ReportModeAperiodic_rm20\n"); + return (4 + 2 + L); + break; + case CQI_ReportModeAperiodic_rm22: + // Table 5.2.2.6.3-2 (36.212) + AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal TM (%d) for CQI_ReportModeAperiodic_rm22\n", + tmode); + AssertFatal(tmode != 9 + && tmode != 10, + "TM9/10 will be handled later for CQI_ReportModeAperiodic_rm22\n"); + if (ri == 1 && cc->p_eNB == 2) + return (4 + 2 + 0 + 0 + L + 4); + if (ri == 2 && cc->p_eNB == 2) + return (4 + 2 + 4 + 2 + L + 2); + if (ri == 1 && cc->p_eNB == 4) + return (4 + 2 + 0 + 0 + L + 8); + if (ri >= 2 && cc->p_eNB == 4) + return (4 + 2 + 4 + 2 + L + 8); + break; + case CQI_ReportModeAperiodic_rm30: + // Table 5.2.2.6.2-1 (36.212) + AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 || tmode == 7 + || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal TM (%d) for CQI_ReportModeAperiodic_rm30\n", + tmode); + AssertFatal(tmode != 8 && tmode != 9 + && tmode != 10, + "TM8/9/10 will be handled later for CQI_ReportModeAperiodic_rm30\n"); + return (4 + (N << 1)); + break; + case CQI_ReportModeAperiodic_rm31: + // Table 5.2.2.6.2-2 (36.212) + AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal TM (%d) for CQI_ReportModeAperiodic_rm31\n", + tmode); + AssertFatal(tmode != 8 && tmode != 9 + && tmode != 10, + "TM8/9/10 will be handled later for CQI_ReportModeAperiodic_rm31\n"); + if (ri == 1 && cc->p_eNB == 2) + return (4 + (N << 1) + 0 + 0 + 2); + else if (ri == 2 && cc->p_eNB == 2) + return (4 + (N << 1) + 4 + (N << 1) + 1); + else if (ri == 1 && cc->p_eNB == 4) + return (4 + (N << 1) + 0 + 0 + 4); + else if (ri >= 2 && cc->p_eNB == 4) + return (4 + (N << 1) + 4 + (N << 1) + 4); + break; + case CQI_ReportModeAperiodic_rm32_v1250: + AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal TM (%d) for CQI_ReportModeAperiodic_rm32\n", + tmode); + AssertFatal(1 == 0, + "CQI_ReportModeAperiodic_rm32_v1250 not supported yet\n"); + break; + case CQI_ReportModeAperiodic_rm10_v1310: + // Table 5.2.2.6.1-1F/G (36.212) + if (ri == 1) + return (4); // F + else + return (7); // G + break; + case CQI_ReportModeAperiodic_rm11_v1310: + // Table 5.2.2.6.1-1H (36.212) + AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal TM (%d) for CQI_ReportModeAperiodic_rm11\n", + tmode); + AssertFatal(cc->p_eNB <= 4, + "only up to 4 antenna ports supported here\n"); + if (ri == 1 && cc->p_eNB == 2) + return (4 + 0 + 2); + else if (ri == 2 && cc->p_eNB == 2) + return (4 + 4 + 1); + else if (ri == 1 && cc->p_eNB == 4) + return (4 + 0 + 4); + else if (ri > 1 && cc->p_eNB == 4) + return (4 + 4 + 4); - break; - } - AssertFatal(1 == 0, "Shouldn't get here\n"); - return (0); + break; + } + AssertFatal(1 == 0, "Shouldn't get here\n"); + return (0); } uint8_t @@ -957,103 +932,84 @@ get_rel8_dl_cqi_pmi_size(UE_sched_ctrl * sched_ctl, int CC_idP, COMMON_channels_t * cc, uint8_t tmode, struct CQI_ReportPeriodic * cqi_ReportPeriodic) { - int no_pmi = 0; - // Ltab[6] = {0,log2(15/4/2),log2(25/4/2),log2(50/6/3),log2(75/8/4),log2(100/8/4)}; + int no_pmi = 0; + // Ltab[6] = {0,log2(15/4/2),log2(25/4/2),log2(50/6/3),log2(75/8/4),log2(100/8/4)}; - uint8_t Ltab[6] = { 0, 1, 2, 2, 2, 2 }; - uint8_t ri = sched_ctl->periodic_ri_received[CC_idP]; + uint8_t Ltab[6] = { 0, 1, 2, 2, 2, 2 }; + uint8_t ri = sched_ctl->periodic_ri_received[CC_idP]; - AssertFatal(cqi_ReportPeriodic != NULL, - "cqi_ReportPeriodic is null!\n"); - AssertFatal(cqi_ReportPeriodic->present != - CQI_ReportPeriodic_PR_NOTHING, - "cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n"); - AssertFatal(cqi_ReportPeriodic->choice. - setup.cqi_FormatIndicatorPeriodic.present != - CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING, - "cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING!\n"); + AssertFatal(cqi_ReportPeriodic != NULL, + "cqi_ReportPeriodic is null!\n"); + AssertFatal(cqi_ReportPeriodic->present != CQI_ReportPeriodic_PR_NOTHING, + "cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n"); + AssertFatal(cqi_ReportPeriodic->choice. + setup.cqi_FormatIndicatorPeriodic.present != CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING, + "cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING!\n"); - switch (tmode) { - case 1: - case 2: - case 5: - case 6: - case 7: - no_pmi = 1; - break; - default: - no_pmi = 0; - } + switch (tmode) { + case 1: + case 2: + case 5: + case 6: + case 7: + no_pmi = 1; + break; + default: + no_pmi = 0; + } - if ((cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic. - present == - CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_widebandCQI) - || (sched_ctl->feedback_cnt[CC_idP] == 0)) { - // send wideband report every opportunity if wideband reporting mode is selected, else every H opportunities - if (no_pmi == 1) - return (4); - else if ((cc->p_eNB == 2) && (ri == 1)) - return (6); - else if ((cc->p_eNB == 2) && (ri == 2)) - return (8); - else if ((cc->p_eNB == 4) && (ri == 1)) - return (8); - else if ((cc->p_eNB == 4) && (ri == 2)) - return (11); - else - AssertFatal(1 == 0, - "illegal combination p %d, ri %d, no_pmi %d\n", - cc->p_eNB, ri, no_pmi); - } else if (cqi_ReportPeriodic->choice. - setup.cqi_FormatIndicatorPeriodic.present == - CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) - { - if ((no_pmi == 1) || ri == 1) - return (4 + Ltab[cc->mib->message.dl_Bandwidth]); - else - return (7 + Ltab[cc->mib->message.dl_Bandwidth]); - } + if ((cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_widebandCQI) + || (sched_ctl->feedback_cnt[CC_idP] == 0)) { + // send wideband report every opportunity if wideband reporting mode is selected, else every H opportunities + if (no_pmi == 1) return (4); + else if ((cc->p_eNB == 2) && (ri == 1)) return (6); + else if ((cc->p_eNB == 2) && (ri == 2)) return (8); + else if ((cc->p_eNB == 4) && (ri == 1)) return (8); + else if ((cc->p_eNB == 4) && (ri == 2)) return (11); + else + AssertFatal(1 == 0, + "illegal combination p %d, ri %d, no_pmi %d\n", + cc->p_eNB, ri, no_pmi); + } else if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) { + if ((no_pmi == 1) || ri == 1) return (4 + Ltab[cc->mib->message.dl_Bandwidth]); + else return (7 + Ltab[cc->mib->message.dl_Bandwidth]); + } - AssertFatal(1 == 0, - "Shouldn't get here : cqi_ReportPeriodic->present %d\n", - cqi_ReportPeriodic->choice. - setup.cqi_FormatIndicatorPeriodic.present); + AssertFatal(1 == 0, + "Shouldn't get here : cqi_ReportPeriodic->present %d\n", + cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present); } void -fill_nfapi_dl_dci_1A(nfapi_dl_config_request_pdu_t * dl_config_pdu, - uint8_t aggregation_level, - uint16_t rnti, - uint8_t rnti_type, - uint8_t harq_process, - uint8_t tpc, - uint16_t resource_block_coding, - uint8_t mcs, uint8_t ndi, uint8_t rv, - uint8_t vrb_flag) +fill_nfapi_dl_dci_1A(nfapi_dl_config_request_pdu_t *dl_config_pdu, + uint8_t aggregation_level, + uint16_t rnti, + uint8_t rnti_type, + uint8_t harq_process, + uint8_t tpc, + uint16_t resource_block_coding, + uint8_t mcs, + uint8_t ndi, + uint8_t rv, + uint8_t vrb_flag) { - memset((void *) dl_config_pdu, 0, - sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = - NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = - NFAPI_DL_DCI_FORMAT_1A; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = - aggregation_level; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = rnti_type; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = harq_process; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; // no TPC - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = - resource_block_coding; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = ndi; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = rv; - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = vrb_flag; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = aggregation_level; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = rnti_type; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = harq_process; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = resource_block_coding; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = ndi; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = rv; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = vrb_flag; } void @@ -1061,436 +1017,349 @@ program_dlsch_acknak(module_id_t module_idP, int CC_idP, int UE_idP, frame_t frameP, sub_frame_t subframeP, uint8_t cce_idx) { - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = eNB->common_channels; - UE_list_t *UE_list = &eNB->UE_list; - rnti_t rnti = UE_RNTI(module_idP, UE_idP); - nfapi_ul_config_request_body_t *ul_req; - nfapi_ul_config_request_pdu_t *ul_config_pdu; - - int use_simultaneous_pucch_pusch = 0; - nfapi_ul_config_ulsch_harq_information *ulsch_harq_information = NULL; - nfapi_ul_config_harq_information *harq_information = NULL; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc = eNB->common_channels; + UE_list_t *UE_list = &eNB->UE_list; + rnti_t rnti = UE_RNTI(module_idP, UE_idP); + nfapi_ul_config_request_body_t *ul_req; + nfapi_ul_config_request_pdu_t *ul_config_pdu; + int use_simultaneous_pucch_pusch = 0; + nfapi_ul_config_ulsch_harq_information *ulsch_harq_information = NULL; + nfapi_ul_config_harq_information *harq_information = NULL; #if defined(Rel10) || defined(Rel14) - if ((UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated-> - ext2) - && (UE_list->UE_template[CC_idP][UE_idP]. - physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020) - && (UE_list->UE_template[CC_idP][UE_idP]. - physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020-> - simultaneousPUCCH_PUSCH_r10) - && (*UE_list->UE_template[CC_idP][UE_idP]. - physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020-> - simultaneousPUCCH_PUSCH_r10 == - PUCCH_ConfigDedicated_v1020__simultaneousPUCCH_PUSCH_r10_true)) - use_simultaneous_pucch_pusch = 1; + if ((UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2) + && (UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020) + && (UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020->simultaneousPUCCH_PUSCH_r10) + && (*UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020->simultaneousPUCCH_PUSCH_r10 == PUCCH_ConfigDedicated_v1020__simultaneousPUCCH_PUSCH_r10_true)) + use_simultaneous_pucch_pusch = 1; #endif - // pucch1 and pusch feedback is similar, namely in n+k subframes from now - // This is used in the following "if/else" condition to check if there isn't or is already an UL grant in n+k - int16_t ul_absSF = - get_pucch1_absSF(&cc[CC_idP], subframeP + (10 * frameP)); + // pucch1 and pusch feedback is similar, namely in n+k subframes from now + // This is used in the following "if/else" condition to check if there isn't or is already an UL grant in n+k + int16_t ul_absSF = get_pucch1_absSF(&cc[CC_idP], subframeP + (10 * frameP)); - if ((ul_config_pdu = has_ul_grant(module_idP, CC_idP, - ul_absSF, rnti)) == NULL) { - // no UL grant so - // Program ACK/NAK alone Format 1a/b or 3 + if ((ul_config_pdu = has_ul_grant(module_idP, CC_idP,ul_absSF, rnti)) == NULL) { + // no UL grant so + // Program ACK/NAK alone Format 1a/b or 3 - ul_req = - &RC.mac[module_idP]->UL_req_tmp[CC_idP][ul_absSF % - 10]. - ul_config_request_body; - ul_config_pdu = - &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; - // Do PUCCH - fill_nfapi_uci_acknak(module_idP, - CC_idP, - rnti, (frameP * 10) + subframeP, cce_idx); - } else { - /* there is already an existing UL grant so update it if needed - * on top of some other UL resource (PUSCH,combined SR/CQI/HARQ on PUCCH, etc) - */ - switch (ul_config_pdu->pdu_type) { + ul_req = &RC.mac[module_idP]->UL_req_tmp[CC_idP][ul_absSF %10].ul_config_request_body; + ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; + // Do PUCCH + fill_nfapi_uci_acknak(module_idP, + CC_idP, + rnti, (frameP * 10) + subframeP, cce_idx); + } else { + /* there is already an existing UL grant so update it if needed + * on top of some other UL resource (PUSCH,combined SR/CQI/HARQ on PUCCH, etc) + */ + switch (ul_config_pdu->pdu_type) { + + /* [ulsch] to [ulsch + harq] or [ulsch + harq on pucch] */ + + case NFAPI_UL_CONFIG_ULSCH_PDU_TYPE: + if (use_simultaneous_pucch_pusch == 1) { + // Convert it to an NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE + harq_information = &ul_config_pdu->ulsch_uci_harq_pdu.harq_information; + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE; + LOG_D(MAC, + "Frame %d, Subframe %d: Switched UCI HARQ to ULSCH UCI HARQ\n", + frameP, subframeP); + } else { + // Convert it to an NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE + ulsch_harq_information = &ul_config_pdu->ulsch_harq_pdu.harq_information; + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE; + ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_INITIAL_TRANSMISSION_PARAMETERS_REL8_TAG; + ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial = 0; // last symbol not punctured + ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks = ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks; // we don't change the number of resource blocks across retransmissions yet + LOG_D(MAC, + "Frame %d, Subframe %d: Switched UCI HARQ to ULSCH HARQ\n", + frameP, subframeP); + } + break; + case NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE: + AssertFatal(use_simultaneous_pucch_pusch == 1, + "Cannot be NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE, simultaneous_pucch_pusch is active"); + break; + case NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE: + AssertFatal(use_simultaneous_pucch_pusch == 0, + "Cannot be NFAPI_UL_CONFIG_ULSCH_UCI_PDU_TYPE, simultaneous_pucch_pusch is inactive\n"); + break; - /* [ulsch] to [ulsch + harq] or [ulsch + harq on pucch] */ + /* [ulsch + cqi] to [ulsch + cqi + harq] */ - case NFAPI_UL_CONFIG_ULSCH_PDU_TYPE: - if (use_simultaneous_pucch_pusch == 1) { - // Convert it to an NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE - harq_information = - &ul_config_pdu->ulsch_uci_harq_pdu.harq_information; - ul_config_pdu->pdu_type = - NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE; - LOG_D(MAC, - "Frame %d, Subframe %d: Switched UCI HARQ to ULSCH UCI HARQ\n", - frameP, subframeP); - } else { - // Convert it to an NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE - ulsch_harq_information = - &ul_config_pdu->ulsch_harq_pdu.harq_information; - ul_config_pdu->pdu_type = - NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE; - ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.tl.tag=NFAPI_UL_CONFIG_REQUEST_INITIAL_TRANSMISSION_PARAMETERS_REL8_TAG; - ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial = 0; // last symbol not punctured - ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks = ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks; // we don't change the number of resource blocks across retransmissions yet - LOG_D(MAC, - "Frame %d, Subframe %d: Switched UCI HARQ to ULSCH HARQ\n", - frameP, subframeP); - } - break; - case NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE: - AssertFatal(use_simultaneous_pucch_pusch == 1, - "Cannot be NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE, simultaneous_pucch_pusch is active"); - break; - case NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE: - AssertFatal(use_simultaneous_pucch_pusch == 0, - "Cannot be NFAPI_UL_CONFIG_ULSCH_UCI_PDU_TYPE, simultaneous_pucch_pusch is inactive\n"); - break; + case NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE: + // Convert it to an NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE + ulsch_harq_information = &ul_config_pdu->ulsch_cqi_harq_ri_pdu.harq_information; + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE; + /* TODO: check this - when converting from nfapi_ul_config_ulsch_cqi_ri_pdu to + * nfapi_ul_config_ulsch_cqi_harq_ri_pdu, shouldn't we copy initial_transmission_parameters + * from the one to the other? + * Those two types are not compatible. 'initial_transmission_parameters' is not at the + * place in both. + */ + ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_INITIAL_TRANSMISSION_PARAMETERS_REL8_TAG; + ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial = 0; // last symbol not punctured + ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks = ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks; // we don't change the number of resource blocks across retransmissions yet + break; + case NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE: + AssertFatal(use_simultaneous_pucch_pusch == 0, + "Cannot be NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE, simultaneous_pucch_pusch is active\n"); + break; - /* [ulsch + cqi] to [ulsch + cqi + harq] */ + /* [ulsch + cqi on pucch] to [ulsch + cqi on pucch + harq on pucch] */ - case NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE: - // Convert it to an NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE - ulsch_harq_information = - &ul_config_pdu->ulsch_cqi_harq_ri_pdu.harq_information; - ul_config_pdu->pdu_type = - NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE; - /* TODO: check this - when converting from nfapi_ul_config_ulsch_cqi_ri_pdu to - * nfapi_ul_config_ulsch_cqi_harq_ri_pdu, shouldn't we copy initial_transmission_parameters - * from the one to the other? - * Those two types are not compatible. 'initial_transmission_parameters' is not at the - * place in both. - */ - ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.tl.tag=NFAPI_UL_CONFIG_REQUEST_INITIAL_TRANSMISSION_PARAMETERS_REL8_TAG; - ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial = 0; // last symbol not punctured - ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks = ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks; // we don't change the number of resource blocks across retransmissions yet - break; - case NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE: - AssertFatal(use_simultaneous_pucch_pusch == 0, - "Cannot be NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE, simultaneous_pucch_pusch is active\n"); - break; + case NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE: + // convert it to an NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE + harq_information = &ul_config_pdu->ulsch_csi_uci_harq_pdu.harq_information; + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE; + break; + case NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE: + AssertFatal(use_simultaneous_pucch_pusch == 1, + "Cannot be NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE, simultaneous_pucch_pusch is inactive\n"); + break; - /* [ulsch + cqi on pucch] to [ulsch + cqi on pucch + harq on pucch] */ + /* [sr] to [sr + harq] */ - case NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE: - // convert it to an NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE - harq_information = - &ul_config_pdu->ulsch_csi_uci_harq_pdu.harq_information; - ul_config_pdu->pdu_type = - NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE; - break; - case NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE: - AssertFatal(use_simultaneous_pucch_pusch == 1, - "Cannot be NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE, simultaneous_pucch_pusch is inactive\n"); - break; - - /* [sr] to [sr + harq] */ - - case NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE: - // convert to NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; - harq_information = - &ul_config_pdu->uci_sr_harq_pdu.harq_information; - break; - case NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE: - /* nothing to do */ - break; - - /* [cqi] to [cqi + harq] */ - - case NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE: - // convert to NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE - ul_config_pdu->pdu_type = - NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE; - harq_information = - &ul_config_pdu->uci_cqi_harq_pdu.harq_information; - break; - case NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE: - /* nothing to do */ - break; - - /* [cqi + sr] to [cqr + sr + harq] */ - - case NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE: - // convert to NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE - ul_config_pdu->pdu_type = - NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE; - harq_information = - &ul_config_pdu->uci_cqi_sr_harq_pdu.harq_information; - break; - case NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE: - /* nothing to do */ - break; - } + case NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE: + // convert to NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; + harq_information = &ul_config_pdu->uci_sr_harq_pdu.harq_information; + break; + case NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE: + /* nothing to do */ + break; + /* [cqi] to [cqi + harq] */ + case NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE: + // convert to NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE; + harq_information = &ul_config_pdu->uci_cqi_harq_pdu.harq_information; + break; + case NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE: + /* nothing to do */ + break; + /* [cqi + sr] to [cqr + sr + harq] */ + case NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE: + // convert to NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE; + harq_information = &ul_config_pdu->uci_cqi_sr_harq_pdu.harq_information; + break; + case NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE: + /* nothing to do */ + break; } + } - if (ulsch_harq_information) - fill_nfapi_ulsch_harq_information(module_idP, CC_idP, - rnti, ulsch_harq_information); + if (ulsch_harq_information) fill_nfapi_ulsch_harq_information(module_idP, CC_idP, rnti, ulsch_harq_information); - if (harq_information) - fill_nfapi_harq_information(module_idP, CC_idP, - rnti, - (frameP * 10) + subframeP, - harq_information, cce_idx); + if (harq_information) fill_nfapi_harq_information(module_idP, CC_idP, + rnti, + (frameP * 10) + subframeP, + harq_information, cce_idx); } uint8_t get_V_UL_DAI(module_id_t module_idP, int CC_idP, uint16_t rntiP) { - nfapi_hi_dci0_request_body_t *HI_DCI0_req = - &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = - &HI_DCI0_req->hi_dci0_pdu_list[0]; + nfapi_hi_dci0_request_body_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[0]; - for (int i = 0; i < HI_DCI0_req->number_of_dci; i++) { - if ((hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) && - (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti == rntiP)) - return (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8. - dl_assignment_index); - } - return (4); // this is rule from Section 7.3 in 36.213 + for (int i = 0; i < HI_DCI0_req->number_of_dci; i++) { + if ((hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) && + (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti == rntiP)) + return (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.dl_assignment_index); + } + return (4); // this is rule from Section 7.3 in 36.213 } void -fill_nfapi_ulsch_harq_information(module_id_t module_idP, - int CC_idP, - uint16_t rntiP, - nfapi_ul_config_ulsch_harq_information - * harq_information) +fill_nfapi_ulsch_harq_information(module_id_t module_idP, + int CC_idP, + uint16_t rntiP, + nfapi_ul_config_ulsch_harq_information *harq_information) { - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; - UE_list_t *UE_list = &eNB->UE_list; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; + UE_list_t *UE_list = &eNB->UE_list; - int UE_id = find_UE_id(module_idP, rntiP); + int UE_id = find_UE_id(module_idP, rntiP); - PUSCH_ConfigDedicated_t *puschConfigDedicated; - // PUSCH_ConfigDedicated_v1020_t *puschConfigDedicated_v1020; - // PUSCH_ConfigDedicated_v1130_t *puschConfigDedicated_v1130; - // PUSCH_ConfigDedicated_v1250_t *puschConfigDedicated_v1250; + PUSCH_ConfigDedicated_t *puschConfigDedicated; + // PUSCH_ConfigDedicated_v1020_t *puschConfigDedicated_v1020; + // PUSCH_ConfigDedicated_v1130_t *puschConfigDedicated_v1130; + // PUSCH_ConfigDedicated_v1250_t *puschConfigDedicated_v1250; - AssertFatal(UE_id >= 0, "UE_id cannot be found, impossible\n"); - AssertFatal(UE_list != NULL, "UE_list is null\n"); - AssertFatal(UE_list->UE_template[CC_idP][UE_id]. - physicalConfigDedicated != NULL, - "physicalConfigDedicated for rnti %x is null\n", rntiP); - AssertFatal((puschConfigDedicated = (PUSCH_ConfigDedicated_t *) - UE_list->UE_template[CC_idP][UE_id]. - physicalConfigDedicated->pusch_ConfigDedicated) != NULL, - "physicalConfigDedicated->puschConfigDedicated for rnti %x is null\n", - rntiP); + AssertFatal(UE_id >= 0, "UE_id cannot be found, impossible\n"); + AssertFatal(UE_list != NULL, "UE_list is null\n"); + AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL, + "physicalConfigDedicated for rnti %x is null\n", rntiP); + AssertFatal((puschConfigDedicated = (PUSCH_ConfigDedicated_t *) + UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pusch_ConfigDedicated) != NULL, + "physicalConfigDedicated->puschConfigDedicated for rnti %x is null\n", + rntiP); #if defined(Rel14) || defined(Rel14) - /* if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext2) puschConfigDedicated_v1020 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext2->pusch_ConfigDedicated_v1020; - #endif - #ifdef Rel14 - if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext4) puschConfigDedicated_v1130 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext4->pusch_ConfigDedicated_v1130; - if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext5) puschConfigDedicated_v1250 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext5->pusch_ConfigDedicated_v1250; - */ + /* if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext2) puschConfigDedicated_v1020 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext2->pusch_ConfigDedicated_v1020; + #endif + #ifdef Rel14 + if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext4) puschConfigDedicated_v1130 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext4->pusch_ConfigDedicated_v1130; + if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext5) puschConfigDedicated_v1250 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext5->pusch_ConfigDedicated_v1250; + */ #endif - harq_information->harq_information_rel10.delta_offset_harq = - puschConfigDedicated->betaOffset_ACK_Index; - AssertFatal(UE_list-> - UE_template[CC_idP][UE_id].physicalConfigDedicated-> - pucch_ConfigDedicated != NULL, - "pucch_ConfigDedicated is null!\n"); - if ((UE_list->UE_template[CC_idP][UE_id]. - physicalConfigDedicated->pucch_ConfigDedicated-> - tdd_AckNackFeedbackMode != NULL) - && (*UE_list->UE_template[CC_idP][UE_id]. - physicalConfigDedicated->pucch_ConfigDedicated-> - tdd_AckNackFeedbackMode == - PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) - harq_information->harq_information_rel10.ack_nack_mode = 1; // multiplexing - else - harq_information->harq_information_rel10.ack_nack_mode = 0; // bundling + harq_information->harq_information_rel10.delta_offset_harq = puschConfigDedicated->betaOffset_ACK_Index; + AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated != NULL, + "pucch_ConfigDedicated is null!\n"); + if ((UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL) + && (*UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode == PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) + harq_information->harq_information_rel10.ack_nack_mode = 1; // multiplexing + else + harq_information->harq_information_rel10.ack_nack_mode = 0; // bundling - switch (get_tmode(module_idP, CC_idP, UE_id)) { - case 1: - case 2: - case 5: - case 6: - case 7: - if (cc->tdd_Config == NULL) // FDD - harq_information->harq_information_rel10.harq_size = 1; - else { - if (harq_information->harq_information_rel10.ack_nack_mode == - 1) - harq_information->harq_information_rel10.harq_size = - get_V_UL_DAI(module_idP, CC_idP, rntiP); - else - harq_information->harq_information_rel10.harq_size = 1; - } - break; - default: // for any other TM we need 2 bits harq - if (cc->tdd_Config == NULL) { - harq_information->harq_information_rel10.harq_size = 2; - } else { - if (harq_information->harq_information_rel10.ack_nack_mode == - 1) - harq_information->harq_information_rel10.harq_size = - get_V_UL_DAI(module_idP, CC_idP, rntiP); - else - harq_information->harq_information_rel10.harq_size = 2; - } - break; - } // get Tmode + switch (get_tmode(module_idP, CC_idP, UE_id)) { + case 1: + case 2: + case 5: + case 6: + case 7: + if (cc->tdd_Config == NULL) // FDD + harq_information->harq_information_rel10.harq_size = 1; + else { + if (harq_information->harq_information_rel10.ack_nack_mode == 1) + harq_information->harq_information_rel10.harq_size = get_V_UL_DAI(module_idP, CC_idP, rntiP); + else + harq_information->harq_information_rel10.harq_size = 1; + } + break; + default: // for any other TM we need 2 bits harq + if (cc->tdd_Config == NULL) { + harq_information->harq_information_rel10.harq_size = 2; + } else { + if (harq_information->harq_information_rel10.ack_nack_mode == 1) + harq_information->harq_information_rel10.harq_size = get_V_UL_DAI(module_idP, CC_idP, rntiP); + else + harq_information->harq_information_rel10.harq_size = 2; + } + break; + } // get Tmode } void -fill_nfapi_harq_information(module_id_t module_idP, - int CC_idP, - uint16_t rntiP, - uint16_t absSFP, - nfapi_ul_config_harq_information * - harq_information, uint8_t cce_idxP) +fill_nfapi_harq_information(module_id_t module_idP, + int CC_idP, + uint16_t rntiP, + uint16_t absSFP, + nfapi_ul_config_harq_information *harq_information, + uint8_t cce_idxP) { - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; - UE_list_t *UE_list = &eNB->UE_list; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; + UE_list_t *UE_list = &eNB->UE_list; - int UE_id = find_UE_id(module_idP, rntiP); + int UE_id = find_UE_id(module_idP, rntiP); - AssertFatal(UE_id >= 0, "UE_id cannot be found, impossible\n"); - AssertFatal(UE_list != NULL, "UE_list is null\n"); + AssertFatal(UE_id >= 0, "UE_id cannot be found, impossible\n"); + AssertFatal(UE_list != NULL, "UE_list is null\n"); #if 0 - /* TODO: revisit, don't use Assert, it's perfectly possible to - * have physicalConfigDedicated NULL here - */ - AssertFatal(UE_list->UE_template[CC_idP][UE_id]. - physicalConfigDedicated != NULL, - "physicalConfigDedicated for rnti %x is null\n", rntiP); + /* TODO: revisit, don't use Assert, it's perfectly possible to + * have physicalConfigDedicated NULL here + */ + AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL, + "physicalConfigDedicated for rnti %x is null\n", rntiP); #endif - harq_information->harq_information_rel11.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL11_TAG; - harq_information->harq_information_rel11.num_ant_ports = 1; + harq_information->harq_information_rel11.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL11_TAG; + harq_information->harq_information_rel11.num_ant_ports = 1; - switch (get_tmode(module_idP, CC_idP, UE_id)) { - case 1: - case 2: - case 5: - case 6: - case 7: - if (cc->tdd_Config != NULL) { - AssertFatal(UE_list-> - UE_template[CC_idP] - [UE_id].physicalConfigDedicated-> - pucch_ConfigDedicated != NULL, - "pucch_ConfigDedicated is null for TDD!\n"); - if ((UE_list-> - UE_template[CC_idP][UE_id].physicalConfigDedicated-> - pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL) - && (*UE_list-> - UE_template[CC_idP][UE_id].physicalConfigDedicated-> - pucch_ConfigDedicated->tdd_AckNackFeedbackMode == - PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) - { - harq_information->harq_information_rel10_tdd.harq_size = 2; // 2-bit ACK/NAK - harq_information->harq_information_rel10_tdd.ack_nack_mode = 1; // multiplexing - } else { - harq_information->harq_information_rel10_tdd.harq_size = 1; // 1-bit ACK/NAK - harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling - } - harq_information->harq_information_rel10_tdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG; - harq_information->harq_information_rel10_tdd.n_pucch_1_0 = - cc->radioResourceConfigCommon->pucch_ConfigCommon. - n1PUCCH_AN + cce_idxP; - harq_information-> - harq_information_rel10_tdd.number_of_pucch_resources = 1; + switch (get_tmode(module_idP, CC_idP, UE_id)) { + case 1: + case 2: + case 5: + case 6: + case 7: + if (cc->tdd_Config != NULL) { + AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated != NULL, + "pucch_ConfigDedicated is null for TDD!\n"); + if ((UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL) + && (*UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode == PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) + { + harq_information->harq_information_rel10_tdd.harq_size = 2; // 2-bit ACK/NAK + harq_information->harq_information_rel10_tdd.ack_nack_mode = 1; // multiplexing } else { - harq_information->harq_information_rel9_fdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG; - harq_information-> - harq_information_rel9_fdd.number_of_pucch_resources = 1; - harq_information->harq_information_rel9_fdd.harq_size = 1; // 1-bit ACK/NAK - harq_information->harq_information_rel9_fdd.n_pucch_1_0 = - cc->radioResourceConfigCommon->pucch_ConfigCommon. - n1PUCCH_AN + cce_idxP; - } - break; - default: // for any other TM we need 2 bits harq - if (cc->tdd_Config != NULL) { - AssertFatal(UE_list-> - UE_template[CC_idP] - [UE_id].physicalConfigDedicated-> - pucch_ConfigDedicated != NULL, - "pucch_ConfigDedicated is null for TDD!\n"); - if ((UE_list-> - UE_template[CC_idP][UE_id].physicalConfigDedicated-> - pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL) - && (*UE_list-> - UE_template[CC_idP][UE_id].physicalConfigDedicated-> - pucch_ConfigDedicated->tdd_AckNackFeedbackMode == - PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) - { - harq_information->harq_information_rel10_tdd.ack_nack_mode = 1; // multiplexing - } else { - harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling - } - harq_information->harq_information_rel10_tdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG; - harq_information->harq_information_rel10_tdd.harq_size = 2; - harq_information->harq_information_rel10_tdd.n_pucch_1_0 = - cc->radioResourceConfigCommon->pucch_ConfigCommon. - n1PUCCH_AN + cce_idxP; - harq_information-> - harq_information_rel10_tdd.number_of_pucch_resources = 1; - } else { - harq_information->harq_information_rel9_fdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG; - harq_information-> - harq_information_rel9_fdd.number_of_pucch_resources = 1; - harq_information->harq_information_rel9_fdd.ack_nack_mode = 0; // 1a/b - harq_information->harq_information_rel9_fdd.harq_size = 2; - harq_information->harq_information_rel9_fdd.n_pucch_1_0 = - cc->radioResourceConfigCommon->pucch_ConfigCommon. - n1PUCCH_AN + cce_idxP; - } - break; - } // get Tmode + harq_information->harq_information_rel10_tdd.harq_size = 1; // 1-bit ACK/NAK + harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling + } + harq_information->harq_information_rel10_tdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG; + harq_information->harq_information_rel10_tdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP; + harq_information->harq_information_rel10_tdd.number_of_pucch_resources = 1; + } else { + harq_information->harq_information_rel9_fdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG; + harq_information->harq_information_rel9_fdd.number_of_pucch_resources = 1; + harq_information->harq_information_rel9_fdd.harq_size = 1; // 1-bit ACK/NAK + harq_information->harq_information_rel9_fdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP; + } + break; + default: // for any other TM we need 2 bits harq + if (cc->tdd_Config != NULL) { + AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated != NULL, + "pucch_ConfigDedicated is null for TDD!\n"); + if ((UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL) + && (*UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode == PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) { + harq_information->harq_information_rel10_tdd.ack_nack_mode = 1; // multiplexing + } else { + harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling + } + harq_information->harq_information_rel10_tdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG; + harq_information->harq_information_rel10_tdd.harq_size = 2; + harq_information->harq_information_rel10_tdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP; + harq_information->harq_information_rel10_tdd.number_of_pucch_resources = 1; + } else { + harq_information->harq_information_rel9_fdd.tl.tag = NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG; + harq_information->harq_information_rel9_fdd.number_of_pucch_resources = 1; + harq_information->harq_information_rel9_fdd.ack_nack_mode = 0; // 1a/b + harq_information->harq_information_rel9_fdd.harq_size = 2; + harq_information->harq_information_rel9_fdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP; + } + break; + } // get Tmode } uint16_t fill_nfapi_uci_acknak(module_id_t module_idP, - int CC_idP, - uint16_t rntiP, uint16_t absSFP, uint8_t cce_idxP) + int CC_idP, + uint16_t rntiP, + uint16_t absSFP, + uint8_t cce_idxP) { - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; + int ackNAK_absSF = get_pucch1_absSF(cc, absSFP); + nfapi_ul_config_request_t *ul_req = &eNB->UL_req_tmp[CC_idP][ackNAK_absSF % 10]; + nfapi_ul_config_request_body_t *ul_req_body = &ul_req->ul_config_request_body; + nfapi_ul_config_request_pdu_t *ul_config_pdu = &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus]; - int ackNAK_absSF = get_pucch1_absSF(cc, absSFP); - nfapi_ul_config_request_t *ul_req = &eNB->UL_req_tmp[CC_idP][ackNAK_absSF % 10]; - nfapi_ul_config_request_body_t *ul_req_body = &ul_req->ul_config_request_body; - nfapi_ul_config_request_pdu_t *ul_config_pdu = - &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus]; + memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t)); + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE; + ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_uci_harq_pdu)); + ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; + ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.handle = 0; // don't know how to use this + ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti = rntiP; - memset((void *) ul_config_pdu, 0, - sizeof(nfapi_ul_config_request_pdu_t)); - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE; - ul_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_ul_config_uci_harq_pdu)); - ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; - ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.handle = 0; // don't know how to use this - ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti = - rntiP; + fill_nfapi_harq_information(module_idP, CC_idP, + rntiP, + absSFP, + &ul_config_pdu->uci_harq_pdu.harq_information, cce_idxP); + LOG_D(MAC, + "Filled in UCI HARQ request for rnti %x SF %d.%d acknakSF %d.%d, cce_idxP %d-> n1_pucch %d\n", + rntiP, absSFP / 10, absSFP % 10, ackNAK_absSF / 10, + ackNAK_absSF % 10, cce_idxP, + ul_config_pdu->uci_harq_pdu. + harq_information.harq_information_rel9_fdd.n_pucch_1_0); - fill_nfapi_harq_information(module_idP, CC_idP, - rntiP, - absSFP, - &ul_config_pdu->uci_harq_pdu. - harq_information, cce_idxP); - LOG_D(MAC, - "Filled in UCI HARQ request for rnti %x SF %d.%d acknakSF %d.%d, cce_idxP %d-> n1_pucch %d\n", - rntiP, absSFP / 10, absSFP % 10, ackNAK_absSF / 10, - ackNAK_absSF % 10, cce_idxP, - ul_config_pdu->uci_harq_pdu. - harq_information.harq_information_rel9_fdd.n_pucch_1_0); + ul_req_body->number_of_pdus++; + ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + ul_req->header.message_id = NFAPI_UL_CONFIG_REQUEST; + ul_req->sfn_sf = (ackNAK_absSF/10) << 4 | ackNAK_absSF%10; - ul_req_body->number_of_pdus++; - ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; - - ul_req->header.message_id = NFAPI_UL_CONFIG_REQUEST; - ul_req->sfn_sf = (ackNAK_absSF/10) << 4 | ackNAK_absSF%10; - - return (((ackNAK_absSF / 10) << 4) + (ackNAK_absSF % 10)); + return (((ackNAK_absSF / 10) << 4) + (ackNAK_absSF % 10)); } void @@ -1520,192 +1389,133 @@ fill_nfapi_dlsch_config(eNB_MAC_INST * eNB, uint8_t num_bf_prb_per_subband, uint8_t num_bf_vector) { - nfapi_dl_config_request_pdu_t *dl_config_pdu = - &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void *) dl_config_pdu, 0, - sizeof(nfapi_dl_config_request_pdu_t)); + nfapi_dl_config_request_pdu_t *dl_config_pdu = + &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = length; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = pdu_index; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = rnti; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = - resource_allocation_type; - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.virtual_resource_block_assignment_flag = - virtual_resource_block_assignment_flag; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = - resource_block_coding; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = modulation; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = - redundancy_version; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = - transport_blocks; - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = - transport_block_to_codeword_swap_flag; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = - transmission_scheme; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = - number_of_layers; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = - number_of_subbands; - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = codebook_index; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = - ue_category_capacity; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = pa; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = - delta_power_offset_index; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = ngap; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = nprb; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = - transmission_mode; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = - num_bf_prb_per_subband; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = num_bf_vector; - dl_req->number_pdu++; + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = length; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = pdu_index; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = rnti; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = resource_allocation_type; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = virtual_resource_block_assignment_flag; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = resource_block_coding; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = modulation; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = redundancy_version; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = transport_blocks; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = transport_block_to_codeword_swap_flag; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = transmission_scheme; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = number_of_layers; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = number_of_subbands; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = codebook_index; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = ue_category_capacity; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = pa; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = delta_power_offset_index; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = ngap; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = nprb; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = transmission_mode; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = num_bf_prb_per_subband; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = num_bf_vector; + dl_req->number_pdu++; } uint16_t -fill_nfapi_tx_req(nfapi_tx_request_body_t * tx_req_body, - uint16_t absSF, uint16_t pdu_length, - uint16_t pdu_index, uint8_t * pdu) +fill_nfapi_tx_req(nfapi_tx_request_body_t *tx_req_body, + uint16_t absSF, + uint16_t pdu_length, + uint16_t pdu_index, + uint8_t *pdu) { - nfapi_tx_request_pdu_t *TX_req = - &tx_req_body->tx_pdu_list[tx_req_body->number_of_pdus]; - LOG_D(MAC, "Filling TX_req %d for pdu length %d\n", - tx_req_body->number_of_pdus, pdu_length); - TX_req->pdu_length = pdu_length; - TX_req->pdu_index = pdu_index; - TX_req->num_segments = 1; - TX_req->segments[0].segment_length = pdu_length; - TX_req->segments[0].segment_data = pdu; - tx_req_body->tl.tag = NFAPI_TX_REQUEST_BODY_TAG; - tx_req_body->number_of_pdus++; + nfapi_tx_request_pdu_t *TX_req = &tx_req_body->tx_pdu_list[tx_req_body->number_of_pdus]; + LOG_D(MAC, "Filling TX_req %d for pdu length %d\n", + tx_req_body->number_of_pdus, pdu_length); - return (((absSF / 10) << 4) + (absSF % 10)); + TX_req->pdu_length = pdu_length; + TX_req->pdu_index = pdu_index; + TX_req->num_segments = 1; + TX_req->segments[0].segment_length = pdu_length; + TX_req->segments[0].segment_data = pdu; + tx_req_body->tl.tag = NFAPI_TX_REQUEST_BODY_TAG; + tx_req_body->number_of_pdus++; + + return (((absSF / 10) << 4) + (absSF % 10)); } void -fill_nfapi_ulsch_config_request_rel8(nfapi_ul_config_request_pdu_t * - ul_config_pdu, uint8_t cqi_req, - COMMON_channels_t * cc, - struct PhysicalConfigDedicated - *physicalConfigDedicated, - uint8_t tmode, uint32_t handle, - uint16_t rnti, - uint8_t resource_block_start, - uint8_t - number_of_resource_blocks, - uint8_t mcs, - uint8_t cyclic_shift_2_for_drms, - uint8_t - frequency_hopping_enabled_flag, - uint8_t frequency_hopping_bits, - uint8_t new_data_indication, - uint8_t redundancy_version, - uint8_t harq_process_number, - uint8_t ul_tx_mode, - uint8_t current_tx_nb, - uint8_t n_srs, uint16_t size) +fill_nfapi_ulsch_config_request_rel8(nfapi_ul_config_request_pdu_t *ul_config_pdu, + uint8_t cqi_req, + COMMON_channels_t *cc, + struct PhysicalConfigDedicated *physicalConfigDedicated, + uint8_t tmode, + uint32_t handle, + uint16_t rnti, + uint8_t resource_block_start, + uint8_t number_of_resource_blocks, + uint8_t mcs, + uint8_t cyclic_shift_2_for_drms, + uint8_t frequency_hopping_enabled_flag, + uint8_t frequency_hopping_bits, + uint8_t new_data_indication, + uint8_t redundancy_version, + uint8_t harq_process_number, + uint8_t ul_tx_mode, + uint8_t current_tx_nb, + uint8_t n_srs, + uint16_t size) { - memset((void *) ul_config_pdu, 0, - sizeof(nfapi_ul_config_request_pdu_t)); + memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t)); - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; - ul_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu)); - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = handle; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = rnti; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = - resource_block_start; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = - number_of_resource_blocks; - if (mcs < 11) - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 2; - else if (mcs < 21) - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 4; - else - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 6; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = - cyclic_shift_2_for_drms; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8. - frequency_hopping_enabled_flag = frequency_hopping_enabled_flag; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = - frequency_hopping_bits; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = - new_data_indication; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = - redundancy_version; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = - harq_process_number; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = ul_tx_mode; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = current_tx_nb; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = n_srs; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = size; + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; + ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu)); + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = handle; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = rnti; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = resource_block_start; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = number_of_resource_blocks; + if (mcs < 11) ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 2; + else if (mcs < 21) ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 4; + else ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 6; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = cyclic_shift_2_for_drms; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_enabled_flag = frequency_hopping_enabled_flag; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = frequency_hopping_bits; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = new_data_indication; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = redundancy_version; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = harq_process_number; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = ul_tx_mode; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = current_tx_nb; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = n_srs; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = size; - if (cqi_req == 1) { - // Add CQI portion - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE; - ul_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_cqi_ri_pdu)); - ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL9_TAG; - ul_config_pdu->ulsch_cqi_ri_pdu. - cqi_ri_information.cqi_ri_information_rel9.report_type = 1; - ul_config_pdu->ulsch_cqi_ri_pdu. - cqi_ri_information.cqi_ri_information_rel9. - aperiodic_cqi_pmi_ri_report.number_of_cc = 1; - LOG_D(MAC, "report_type %d\n", - ul_config_pdu->ulsch_cqi_ri_pdu. - cqi_ri_information.cqi_ri_information_rel9.report_type); + if (cqi_req == 1) { + // Add CQI portion + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE; + ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_cqi_ri_pdu)); + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL9_TAG; + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.report_type = 1; + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.number_of_cc = 1; + LOG_D(MAC, "report_type %d\n",ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.report_type); - if (cc->p_eNB <= 2 - && (tmode == 3 || tmode == 4 || tmode == 8 || tmode == 9 - || tmode == 10)) - ul_config_pdu->ulsch_cqi_ri_pdu. - cqi_ri_information.cqi_ri_information_rel9. - aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 1; - else if (cc->p_eNB <= 2) - ul_config_pdu->ulsch_cqi_ri_pdu. - cqi_ri_information.cqi_ri_information_rel9. - aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 0; - else if (cc->p_eNB == 4) - ul_config_pdu->ulsch_cqi_ri_pdu. - cqi_ri_information.cqi_ri_information_rel9. - aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 2; + if (cc->p_eNB <= 2 + && (tmode == 3 || tmode == 4 || tmode == 8 || tmode == 9 || tmode == 10)) + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 1; + else if (cc->p_eNB <= 2) ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 0; + else if (cc->p_eNB == 4) ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 2; - AssertFatal(physicalConfigDedicated->cqi_ReportConfig != NULL, - "physicalConfigDedicated->cqi_ReportConfig is null!\n"); - AssertFatal(physicalConfigDedicated-> - cqi_ReportConfig->cqi_ReportModeAperiodic != NULL, - "physicalConfigDedicated->cqi_ReportModeAperiodic is null!\n"); - AssertFatal(physicalConfigDedicated->pusch_ConfigDedicated != NULL, - "physicalConfigDedicated->puschConfigDedicated is null!\n"); + AssertFatal(physicalConfigDedicated->cqi_ReportConfig != NULL,"physicalConfigDedicated->cqi_ReportConfig is null!\n"); + AssertFatal(physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic != NULL,"physicalConfigDedicated->cqi_ReportModeAperiodic is null!\n"); + AssertFatal(physicalConfigDedicated->pusch_ConfigDedicated != NULL,"physicalConfigDedicated->puschConfigDedicated is null!\n"); - for (int ri = 0; - ri < - (1 << ul_config_pdu->ulsch_cqi_ri_pdu. - cqi_ri_information.cqi_ri_information_rel9. - aperiodic_cqi_pmi_ri_report.cc[0].ri_size); ri++) - ul_config_pdu->ulsch_cqi_ri_pdu. - cqi_ri_information.cqi_ri_information_rel9. - aperiodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[ri] = - get_dl_cqi_pmi_size_pusch(cc, tmode, 1 + ri, - physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic); + for (int ri = 0; + ri < (1 << ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size); + ri++) + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.periodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[ri] = get_dl_cqi_pmi_size_pusch(cc,tmode,1 + ri,physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic); - ul_config_pdu->ulsch_cqi_ri_pdu. - cqi_ri_information.cqi_ri_information_rel9.delta_offset_cqi = - physicalConfigDedicated->pusch_ConfigDedicated-> - betaOffset_CQI_Index; - ul_config_pdu->ulsch_cqi_ri_pdu. - cqi_ri_information.cqi_ri_information_rel9.delta_offset_ri = - physicalConfigDedicated->pusch_ConfigDedicated-> - betaOffset_RI_Index; - } + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.delta_offset_cqi = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index; + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.delta_offset_ri = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index; + } } #ifdef Rel14 @@ -1717,34 +1527,29 @@ fill_nfapi_ulsch_config_request_emtc(nfapi_ul_config_request_pdu_t * uint16_t repetition_number, uint16_t initial_transmission_sf_io) { - // Re13 fields + // Re13 fields - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL13_TAG; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.ue_type = ue_type; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.total_number_of_repetitions = - total_number_of_repetitions; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.repetition_number = - repetition_number; - ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.initial_transmission_sf_io = - initial_transmission_sf_io; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL13_TAG; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.ue_type = ue_type; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.total_number_of_repetitions = total_number_of_repetitions; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.repetition_number = repetition_number; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.initial_transmission_sf_io = initial_transmission_sf_io; } int get_numnarrowbands(long dl_Bandwidth) { - int nb_tab[6] = { 1, 2, 4, 8, 12, 16 }; + int nb_tab[6] = { 1, 2, 4, 8, 12, 16 }; - AssertFatal(dl_Bandwidth < 7 - || dl_Bandwidth >= 0, "dl_Bandwidth not in [0..6]\n"); - return (nb_tab[dl_Bandwidth]); + AssertFatal(dl_Bandwidth < 7 || dl_Bandwidth >= 0, "dl_Bandwidth not in [0..6]\n"); + return (nb_tab[dl_Bandwidth]); } int get_numnarrowbandbits(long dl_Bandwidth) { - int nbbits_tab[6] = { 0, 1, 2, 3, 4, 4 }; + int nbbits_tab[6] = { 0, 1, 2, 3, 4, 4 }; - AssertFatal(dl_Bandwidth < 7 - || dl_Bandwidth >= 0, "dl_Bandwidth not in [0..6]\n"); - return (nbbits_tab[dl_Bandwidth]); + AssertFatal(dl_Bandwidth < 7 || dl_Bandwidth >= 0, "dl_Bandwidth not in [0..6]\n"); + return (nbbits_tab[dl_Bandwidth]); } //This implements the frame/subframe condition for first subframe of MPDCCH transmission (Section 9.1.5 36.213, Rel 13/14) @@ -1756,111 +1561,96 @@ mpdcch_sf_condition(eNB_MAC_INST * eNB, int CC_id, frame_t frameP, sub_frame_t subframeP, int rmax, MPDCCH_TYPES_t mpdcch_type, int UE_id) { - struct PRACH_ConfigSIB_v1310 *ext4_prach = - eNB->common_channels[CC_id].radioResourceConfigCommon_BR-> - ext4->prach_ConfigCommon_v1310; + struct PRACH_ConfigSIB_v1310 *ext4_prach = + eNB->common_channels[CC_id].radioResourceConfigCommon_BR-> + ext4->prach_ConfigCommon_v1310; - int T; - EPDCCH_SetConfig_r11_t *epdcch_setconfig_r11; + int T; + EPDCCH_SetConfig_r11_t *epdcch_setconfig_r11; - switch (mpdcch_type) { - case TYPE0: - AssertFatal(1 == 0, "MPDCCH Type 0 not handled yet\n"); - break; - case TYPE1: - AssertFatal(1 == 0, "MPDCCH Type 1 not handled yet\n"); - break; - case TYPE1A: - AssertFatal(1 == 0, "MPDCCH Type 1A not handled yet\n"); - break; - case TYPE2: // RAR - AssertFatal(ext4_prach->mpdcch_startSF_CSS_RA_r13 != NULL, - "mpdcch_startSF_CSS_RA_r13 is null\n"); - AssertFatal(rmax > 0, "rmax is 0!\b"); - if (eNB->common_channels[CC_id].tdd_Config == NULL) //FDD - T = rmax * - startSF_fdd_RA_times2[ext4_prach-> + switch (mpdcch_type) { + case TYPE0: + AssertFatal(1 == 0, "MPDCCH Type 0 not handled yet\n"); + break; + case TYPE1: + AssertFatal(1 == 0, "MPDCCH Type 1 not handled yet\n"); + break; + case TYPE1A: + AssertFatal(1 == 0, "MPDCCH Type 1A not handled yet\n"); + break; + case TYPE2: // RAR + AssertFatal(ext4_prach->mpdcch_startSF_CSS_RA_r13 != NULL, + "mpdcch_startSF_CSS_RA_r13 is null\n"); + AssertFatal(rmax > 0, "rmax is 0!\b"); + if (eNB->common_channels[CC_id].tdd_Config == NULL) //FDD + T = rmax *startSF_fdd_RA_times2[ext4_prach-> mpdcch_startSF_CSS_RA_r13-> choice.fdd_r13] >> 1; - else //TDD - T = rmax * - startSF_tdd_RA[ext4_prach-> + else //TDD + T = rmax *startSF_tdd_RA[ext4_prach-> mpdcch_startSF_CSS_RA_r13->choice.tdd_r13]; - break; - case TYPE2A: - AssertFatal(1 == 0, "MPDCCH Type 2A not handled yet\n"); - break; - case TYPEUESPEC: - epdcch_setconfig_r11 = - eNB->UE_list.UE_template[CC_id][UE_id]. - physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11. - choice.setup.setConfigToAddModList_r11->list.array[0]; + break; + case TYPE2A: + AssertFatal(1 == 0, "MPDCCH Type 2A not handled yet\n"); + break; + case TYPEUESPEC: + epdcch_setconfig_r11 = + eNB->UE_list.UE_template[CC_id][UE_id].physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.setConfigToAddModList_r11->list.array[0]; - AssertFatal(epdcch_setconfig_r11 != NULL, - " epdcch_setconfig_r11 is null for UE specific \n"); - AssertFatal(epdcch_setconfig_r11->ext2 != NULL, - " ext2 doesn't exist in epdcch config ' \n"); + AssertFatal(epdcch_setconfig_r11 != NULL, + " epdcch_setconfig_r11 is null for UE specific \n"); + AssertFatal(epdcch_setconfig_r11->ext2 != NULL, + " ext2 doesn't exist in epdcch config ' \n"); - if (eNB->common_channels[CC_id].tdd_Config == NULL) //FDD - T = rmax * - startSF_fdd_RA_times2[epdcch_setconfig_r11-> - ext2->mpdcch_config_r13->choice. - setup.mpdcch_StartSF_UESS_r13.choice. - fdd_r13] >> 1; - else //TDD - T = rmax * - startSF_tdd_RA[epdcch_setconfig_r11-> - ext2->mpdcch_config_r13->choice. - setup.mpdcch_StartSF_UESS_r13.choice. - tdd_r13]; + if (eNB->common_channels[CC_id].tdd_Config == NULL) //FDD + T = rmax *startSF_fdd_RA_times2[epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_StartSF_UESS_r13.choice.fdd_r13] >> 1; + else //TDD + T = rmax *startSF_tdd_RA[epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_StartSF_UESS_r13.choice.tdd_r13]; + break; + default: + return (0); + } - break; - default: - return (0); - } - - AssertFatal(T > 0, "T is 0!\n"); - if (((10 * frameP) + subframeP) % T == 0) - return (1); - else - return (0); + AssertFatal(T > 0, "T is 0!\n"); + if (((10 * frameP) + subframeP) % T == 0) return (1); + else return (0); } int narrowband_to_first_rb(COMMON_channels_t * cc, int nb_index) { - switch (cc->mib->message.dl_Bandwidth) { - case 0: // 6 PRBs, N_NB=1, i_0=0 - return (0); - break; - case 3: // 50 PRBs, N_NB=8, i_0=1 - return ((int) (1 + (6 * nb_index))); - break; - case 5: // 100 PRBs, N_NB=16, i_0=2 - return ((int) (2 + (6 * nb_index))); - break; - case 1: // 15 PRBs N_NB=2, i_0=1 - if (nb_index > 0) - return (1); - else - return (0); - break; - case 2: // 25 PRBs, N_NB=4, i_0=0 - if (nb_index > 1) - return (1 + (6 * nb_index)); - else - return ((6 * nb_index)); - break; - case 4: // 75 PRBs, N_NB=12, i_0=1 - if (nb_index > 5) - return (2 + (6 * nb_index)); - else - return (1 + (6 * nb_index)); - break; - default: - AssertFatal(1 == 0, "Impossible dl_Bandwidth %d\n", - (int) cc->mib->message.dl_Bandwidth); - break; - } + switch (cc->mib->message.dl_Bandwidth) { + case 0: // 6 PRBs, N_NB=1, i_0=0 + return (0); + break; + case 3: // 50 PRBs, N_NB=8, i_0=1 + return ((int) (1 + (6 * nb_index))); + break; + case 5: // 100 PRBs, N_NB=16, i_0=2 + return ((int) (2 + (6 * nb_index))); + break; + case 1: // 15 PRBs N_NB=2, i_0=1 + if (nb_index > 0) + return (1); + else + return (0); + break; + case 2: // 25 PRBs, N_NB=4, i_0=0 + if (nb_index > 1) + return (1 + (6 * nb_index)); + else + return ((6 * nb_index)); + break; + case 4: // 75 PRBs, N_NB=12, i_0=1 + if (nb_index > 5) + return (2 + (6 * nb_index)); + else + return (1 + (6 * nb_index)); + break; + default: + AssertFatal(1 == 0, "Impossible dl_Bandwidth %d\n", + (int) cc->mib->message.dl_Bandwidth); + break; + } } #endif @@ -1868,23 +1658,23 @@ int narrowband_to_first_rb(COMMON_channels_t * cc, int nb_index) void init_ue_sched_info(void) //------------------------------------------------------------------------------ { - module_id_t i, j, k; + module_id_t i, j, k; - for (i = 0; i < NUMBER_OF_eNB_MAX; i++) { - for (k = 0; k < MAX_NUM_CCs; k++) { - for (j = 0; j < NUMBER_OF_UE_MAX; j++) { - // init DL - eNB_dlsch_info[i][k][j].weight = 0; - eNB_dlsch_info[i][k][j].subframe = 0; - eNB_dlsch_info[i][k][j].serving_num = 0; - eNB_dlsch_info[i][k][j].status = S_DL_NONE; - // init UL - eNB_ulsch_info[i][k][j].subframe = 0; - eNB_ulsch_info[i][k][j].serving_num = 0; - eNB_ulsch_info[i][k][j].status = S_UL_NONE; - } - } + for (i = 0; i < NUMBER_OF_eNB_MAX; i++) { + for (k = 0; k < MAX_NUM_CCs; k++) { + for (j = 0; j < NUMBER_OF_UE_MAX; j++) { + // init DL + eNB_dlsch_info[i][k][j].weight = 0; + eNB_dlsch_info[i][k][j].subframe = 0; + eNB_dlsch_info[i][k][j].serving_num = 0; + eNB_dlsch_info[i][k][j].status = S_DL_NONE; + // init UL + eNB_ulsch_info[i][k][j].subframe = 0; + eNB_ulsch_info[i][k][j].serving_num = 0; + eNB_ulsch_info[i][k][j].status = S_UL_NONE; + } } + } } @@ -1893,923 +1683,785 @@ void init_ue_sched_info(void) unsigned char get_ue_weight(module_id_t module_idP, int CC_idP, int ue_idP) //------------------------------------------------------------------------------ { - return (eNB_dlsch_info[module_idP][CC_idP][ue_idP].weight); + return (eNB_dlsch_info[module_idP][CC_idP][ue_idP].weight); } //------------------------------------------------------------------------------ int find_UE_id(module_id_t mod_idP, rnti_t rntiP) //------------------------------------------------------------------------------ { - int UE_id; - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + int UE_id; + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { - if (UE_list->active[UE_id] != TRUE) - continue; - if (UE_list->UE_template[UE_PCCID(mod_idP, UE_id)][UE_id].rnti == - rntiP) { - return (UE_id); - } + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { + if (UE_list->active[UE_id] != TRUE) + continue; + if (UE_list->UE_template[UE_PCCID(mod_idP, UE_id)][UE_id].rnti == + rntiP) { + return (UE_id); } + } - return (-1); + return (-1); } //------------------------------------------------------------------------------ int find_RA_id(module_id_t mod_idP, int CC_idP, rnti_t rntiP) //------------------------------------------------------------------------------ { - int RA_id; - AssertFatal(RC.mac[mod_idP], "RC.mac[%d] is null\n", mod_idP); + int RA_id; + AssertFatal(RC.mac[mod_idP], "RC.mac[%d] is null\n", mod_idP); - RA_t *ra = (RA_t *) & RC.mac[mod_idP]->common_channels[CC_idP].ra[0]; + RA_t *ra = (RA_t *) & RC.mac[mod_idP]->common_channels[CC_idP].ra[0]; - for (RA_id = 0; RA_id < NB_RA_PROC_MAX; RA_id++) { - LOG_D(MAC, - "Checking RA_id %d for %x : state %d\n", - RA_id, rntiP, ra[RA_id].state); + for (RA_id = 0; RA_id < NB_RA_PROC_MAX; RA_id++) { + LOG_D(MAC, + "Checking RA_id %d for %x : state %d\n", + RA_id, rntiP, ra[RA_id].state); - if (ra[RA_id].state != IDLE && - ra[RA_id].rnti == rntiP) - return (RA_id); - } - return (-1); + if (ra[RA_id].state != IDLE && + ra[RA_id].rnti == rntiP) + return (RA_id); + } + return (-1); } //------------------------------------------------------------------------------ int UE_num_active_CC(UE_list_t * listP, int ue_idP) //------------------------------------------------------------------------------ { - return (listP->numactiveCCs[ue_idP]); + return (listP->numactiveCCs[ue_idP]); } //------------------------------------------------------------------------------ int UE_PCCID(module_id_t mod_idP, int ue_idP) //------------------------------------------------------------------------------ { - return (RC.mac[mod_idP]->UE_list.pCC_id[ue_idP]); + return (RC.mac[mod_idP]->UE_list.pCC_id[ue_idP]); } //------------------------------------------------------------------------------ rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP) //------------------------------------------------------------------------------ { - rnti_t rnti = - RC.mac[mod_idP]-> - UE_list.UE_template[UE_PCCID(mod_idP, ue_idP)][ue_idP].rnti; + rnti_t rnti = + RC.mac[mod_idP]-> + UE_list.UE_template[UE_PCCID(mod_idP, ue_idP)][ue_idP].rnti; - if (rnti > 0) { - return (rnti); - } + if (rnti > 0) { + return (rnti); + } - LOG_D(MAC, "[eNB %d] Couldn't find RNTI for UE %d\n", mod_idP, ue_idP); - //display_backtrace(); - return (NOT_A_RNTI); + LOG_D(MAC, "[eNB %d] Couldn't find RNTI for UE %d\n", mod_idP, ue_idP); + //display_backtrace(); + return (NOT_A_RNTI); } //------------------------------------------------------------------------------ boolean_t is_UE_active(module_id_t mod_idP, int ue_idP) //------------------------------------------------------------------------------ { - return (RC.mac[mod_idP]->UE_list.active[ue_idP]); + return (RC.mac[mod_idP]->UE_list.active[ue_idP]); } -/* -uint8_t find_active_UEs(module_id_t module_idP,int CC_id){ - - module_id_t ue_mod_id = 0; - rnti_t rnti = 0; - uint8_t nb_active_ue = 0; - - for (ue_mod_id=0;ue_mod_idget_eNB_UE_stats(module_idP,rnti) != NULL){ // check at the phy enb_ue state for this rnti - nb_active_ue++; - } - else { // this ue is removed at the phy => remove it at the mac as well - mac_remove_ue(module_idP, CC_id, ue_mod_id); - } - } - } - return(nb_active_ue); -} -*/ - - -// get aggregation (L) form phy for a give UE unsigned char get_aggregation(uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt) { - unsigned char aggregation = 3; + unsigned char aggregation = 3; - switch (dci_fmt) { - case format0: - aggregation = cqi2fmt0_agg[bw_index][cqi]; - break; - case format1: - case format1A: - case format1B: - case format1D: - aggregation = cqi2fmt1x_agg[bw_index][cqi]; - break; - case format2: - case format2A: - case format2B: - case format2C: - case format2D: - aggregation = cqi2fmt2x_agg[bw_index][cqi]; - break; - case format1C: - case format1E_2A_M10PRB: - case format3: - case format3A: - case format4: - default: - LOG_W(MAC, "unsupported DCI format %d\n", dci_fmt); - } + switch (dci_fmt) { + case format0: + aggregation = cqi2fmt0_agg[bw_index][cqi]; + break; + case format1: + case format1A: + case format1B: + case format1D: + aggregation = cqi2fmt1x_agg[bw_index][cqi]; + break; + case format2: + case format2A: + case format2B: + case format2C: + case format2D: + aggregation = cqi2fmt2x_agg[bw_index][cqi]; + break; + case format1C: + case format1E_2A_M10PRB: + case format3: + case format3A: + case format4: + default: + LOG_W(MAC, "unsupported DCI format %d\n", dci_fmt); + } - LOG_D(MAC, "Aggregation level %d (cqi %d, bw_index %d, format %d)\n", 1 << aggregation, cqi, bw_index, dci_fmt); + LOG_D(MAC, "Aggregation level %d (cqi %d, bw_index %d, format %d)\n", 1 << aggregation, cqi, bw_index, dci_fmt); - return 1 << aggregation; + return 1 << aggregation; } void dump_ue_list(UE_list_t * listP, int ul_flag) { - int j; + int j; - if (ul_flag == 0) { - for (j = listP->head; j >= 0; j = listP->next[j]) { - LOG_T(MAC, "node %d => %d\n", j, listP->next[j]); - } - } else { - for (j = listP->head_ul; j >= 0; j = listP->next_ul[j]) { - LOG_T(MAC, "node %d => %d\n", j, listP->next_ul[j]); - } + if (ul_flag == 0) { + for (j = listP->head; j >= 0; j = listP->next[j]) { + LOG_T(MAC, "node %d => %d\n", j, listP->next[j]); } + } else { + for (j = listP->head_ul; j >= 0; j = listP->next_ul[j]) { + LOG_T(MAC, "node %d => %d\n", j, listP->next_ul[j]); + } + } } int add_new_ue(module_id_t mod_idP, int cc_idP, rnti_t rntiP, int harq_pidP #ifdef Rel14 , uint8_t rach_resource_type #endif - ) + ) { - int UE_id; - int i, j; + int UE_id; + int i, j; - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - LOG_D(MAC, - "[eNB %d, CC_id %d] Adding UE with rnti %x (next avail %d, num_UEs %d)\n", - mod_idP, cc_idP, rntiP, UE_list->avail, UE_list->num_UEs); - dump_ue_list(UE_list, 0); + LOG_D(MAC, + "[eNB %d, CC_id %d] Adding UE with rnti %x (next avail %d, num_UEs %d)\n", + mod_idP, cc_idP, rntiP, UE_list->avail, UE_list->num_UEs); + dump_ue_list(UE_list, 0); - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i] == TRUE) - continue; - UE_id = i; - memset(&UE_list->UE_template[cc_idP][UE_id], 0, - sizeof(UE_TEMPLATE)); - UE_list->UE_template[cc_idP][UE_id].rnti = rntiP; - UE_list->UE_template[cc_idP][UE_id].configured = FALSE; - UE_list->numactiveCCs[UE_id] = 1; - UE_list->numactiveULCCs[UE_id] = 1; - UE_list->pCC_id[UE_id] = cc_idP; - UE_list->ordered_CCids[0][UE_id] = cc_idP; - UE_list->ordered_ULCCids[0][UE_id] = cc_idP; - UE_list->num_UEs++; - UE_list->active[UE_id] = TRUE; + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (UE_list->active[i] == TRUE) + continue; + UE_id = i; + memset(&UE_list->UE_template[cc_idP][UE_id], 0, + sizeof(UE_TEMPLATE)); + UE_list->UE_template[cc_idP][UE_id].rnti = rntiP; + UE_list->UE_template[cc_idP][UE_id].configured = FALSE; + UE_list->numactiveCCs[UE_id] = 1; + UE_list->numactiveULCCs[UE_id] = 1; + UE_list->pCC_id[UE_id] = cc_idP; + UE_list->ordered_CCids[0][UE_id] = cc_idP; + UE_list->ordered_ULCCids[0][UE_id] = cc_idP; + UE_list->num_UEs++; + UE_list->active[UE_id] = TRUE; #if defined(USRP_REC_PLAY) // not specific to record/playback ? - UE_list->UE_template[cc_idP][UE_id].pre_assigned_mcs_ul = 0; + UE_list->UE_template[cc_idP][UE_id].pre_assigned_mcs_ul = 0; #endif #ifdef Rel14 - UE_list->UE_template[cc_idP][UE_id].rach_resource_type = - rach_resource_type; + UE_list->UE_template[cc_idP][UE_id].rach_resource_type = + rach_resource_type; #endif - memset((void *) &UE_list->UE_sched_ctrl[UE_id], 0, - sizeof(UE_sched_ctrl)); - memset((void *) &UE_list->eNB_UE_stats[cc_idP][UE_id], 0, - sizeof(eNB_UE_STATS)); + memset((void *) &UE_list->UE_sched_ctrl[UE_id], 0, + sizeof(UE_sched_ctrl)); + memset((void *) &UE_list->eNB_UE_stats[cc_idP][UE_id], 0, + sizeof(eNB_UE_STATS)); - UE_list->UE_sched_ctrl[UE_id].ta_update = 31; + UE_list->UE_sched_ctrl[UE_id].ta_update = 31; - for (j = 0; j < 8; j++) { - UE_list->UE_template[cc_idP][UE_id].oldNDI[j] = (j == 0) ? 1 : 0; // 1 because first transmission is with format1A (Msg4) for harq_pid 0 - UE_list->UE_template[cc_idP][UE_id].oldNDI_UL[j] = (j == harq_pidP) ? 0 : 1; // 1st transmission is with Msg3; - UE_list->UE_sched_ctrl[UE_id].round[cc_idP][j] = 8; - UE_list->UE_sched_ctrl[UE_id].round_UL[cc_idP][j] = 0; - } - - eNB_ulsch_info[mod_idP][cc_idP][UE_id].status = S_UL_WAITING; - eNB_dlsch_info[mod_idP][cc_idP][UE_id].status = S_DL_WAITING; - LOG_D(MAC, "[eNB %d] Add UE_id %d on Primary CC_id %d: rnti %x\n", - mod_idP, UE_id, cc_idP, rntiP); - dump_ue_list(UE_list, 0); - return (UE_id); + for (j = 0; j < 8; j++) { + UE_list->UE_template[cc_idP][UE_id].oldNDI[j] = (j == 0) ? 1 : 0; // 1 because first transmission is with format1A (Msg4) for harq_pid 0 + UE_list->UE_template[cc_idP][UE_id].oldNDI_UL[j] = (j == harq_pidP) ? 0 : 1; // 1st transmission is with Msg3; + UE_list->UE_sched_ctrl[UE_id].round[cc_idP][j] = 8; + UE_list->UE_sched_ctrl[UE_id].round_UL[cc_idP][j] = 0; } - printf("MAC: cannot add new UE for rnti %x\n", rntiP); - LOG_E(MAC, - "error in add_new_ue(), could not find space in UE_list, Dumping UE list\n"); + eNB_ulsch_info[mod_idP][cc_idP][UE_id].status = S_UL_WAITING; + eNB_dlsch_info[mod_idP][cc_idP][UE_id].status = S_DL_WAITING; + LOG_D(MAC, "[eNB %d] Add UE_id %d on Primary CC_id %d: rnti %x\n", + mod_idP, UE_id, cc_idP, rntiP); dump_ue_list(UE_list, 0); - return (-1); + return (UE_id); + } + + printf("MAC: cannot add new UE for rnti %x\n", rntiP); + LOG_E(MAC, + "error in add_new_ue(), could not find space in UE_list, Dumping UE list\n"); + dump_ue_list(UE_list, 0); + return (-1); } //------------------------------------------------------------------------------ int rrc_mac_remove_ue(module_id_t mod_idP, rnti_t rntiP) //------------------------------------------------------------------------------ { - int i; - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - int UE_id = find_UE_id(mod_idP, rntiP); - int pCC_id; - - if (UE_id == -1) { - LOG_W(MAC, "rrc_mac_remove_ue: UE %x not found\n", rntiP); - return 0; - } - - pCC_id = UE_PCCID(mod_idP, UE_id); - - LOG_I(MAC, "Removing UE %d from Primary CC_id %d (rnti %x)\n", UE_id, - pCC_id, rntiP); - dump_ue_list(UE_list, 0); - - UE_list->active[UE_id] = FALSE; - UE_list->num_UEs--; - - if (UE_list->head == UE_id) - UE_list->head = UE_list->next[UE_id]; - else - UE_list->next[prev(UE_list, UE_id, 0)] = UE_list->next[UE_id]; - if (UE_list->head_ul == UE_id) - UE_list->head_ul = UE_list->next_ul[UE_id]; - else - UE_list->next_ul[prev(UE_list, UE_id, 0)] = - UE_list->next_ul[UE_id]; - - // clear all remaining pending transmissions - UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID0] = 0; - UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID1] = 0; - UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID2] = 0; - UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID3] = 0; - - UE_list->UE_template[pCC_id][UE_id].ul_SR = 0; - UE_list->UE_template[pCC_id][UE_id].rnti = NOT_A_RNTI; - UE_list->UE_template[pCC_id][UE_id].ul_active = FALSE; - eNB_ulsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI; - eNB_ulsch_info[mod_idP][pCC_id][UE_id].status = S_UL_NONE; - eNB_dlsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI; - eNB_dlsch_info[mod_idP][pCC_id][UE_id].status = S_DL_NONE; - - // check if this has an RA process active - RA_t *ra; - for (i = 0; i < NB_RA_PROC_MAX; i++) { - ra = (RA_t *) & RC.mac[mod_idP]->common_channels[pCC_id].ra[i]; - if (ra->rnti == rntiP) { - ra->state = IDLE; - ra->timing_offset = 0; - ra->RRC_timer = 20; - ra->rnti = 0; - //break; - } - } + int i; + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + int UE_id = find_UE_id(mod_idP, rntiP); + int pCC_id; + if (UE_id == -1) { + LOG_W(MAC, "rrc_mac_remove_ue: UE %x not found\n", rntiP); return 0; + } + + pCC_id = UE_PCCID(mod_idP, UE_id); + + LOG_I(MAC, "Removing UE %d from Primary CC_id %d (rnti %x)\n", UE_id, + pCC_id, rntiP); + dump_ue_list(UE_list, 0); + + UE_list->active[UE_id] = FALSE; + UE_list->num_UEs--; + + if (UE_list->head == UE_id) + UE_list->head = UE_list->next[UE_id]; + else + UE_list->next[prev(UE_list, UE_id, 0)] = UE_list->next[UE_id]; + if (UE_list->head_ul == UE_id) + UE_list->head_ul = UE_list->next_ul[UE_id]; + else + UE_list->next_ul[prev(UE_list, UE_id, 0)] = + UE_list->next_ul[UE_id]; + + // clear all remaining pending transmissions + UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID0] = 0; + UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID1] = 0; + UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID2] = 0; + UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID3] = 0; + + UE_list->UE_template[pCC_id][UE_id].ul_SR = 0; + UE_list->UE_template[pCC_id][UE_id].rnti = NOT_A_RNTI; + UE_list->UE_template[pCC_id][UE_id].ul_active = FALSE; + eNB_ulsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI; + eNB_ulsch_info[mod_idP][pCC_id][UE_id].status = S_UL_NONE; + eNB_dlsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI; + eNB_dlsch_info[mod_idP][pCC_id][UE_id].status = S_DL_NONE; + + // check if this has an RA process active + RA_t *ra; + for (i = 0; i < NB_RA_PROC_MAX; i++) { + ra = (RA_t *) & RC.mac[mod_idP]->common_channels[pCC_id].ra[i]; + if (ra->rnti == rntiP) { + ra->state = IDLE; + ra->timing_offset = 0; + ra->RRC_timer = 20; + ra->rnti = 0; + //break; + } + } + + return 0; } int prev(UE_list_t * listP, int nodeP, int ul_flag) { - int j; + int j; - if (ul_flag == 0) { - if (nodeP == listP->head) { - return (nodeP); - } - - for (j = listP->head; j >= 0; j = listP->next[j]) { - if (listP->next[j] == nodeP) { - return (j); - } - } - } else { - if (nodeP == listP->head_ul) { - return (nodeP); - } - - for (j = listP->head_ul; j >= 0; j = listP->next_ul[j]) { - if (listP->next_ul[j] == nodeP) { - return (j); - } - } + if (ul_flag == 0) { + if (nodeP == listP->head) { + return (nodeP); } - LOG_E(MAC, - "error in prev(), could not find previous to %d in UE_list %s, should never happen, Dumping UE list\n", - nodeP, (ul_flag == 0) ? "DL" : "UL"); - dump_ue_list(listP, ul_flag); + for (j = listP->head; j >= 0; j = listP->next[j]) { + if (listP->next[j] == nodeP) { + return (j); + } + } + } else { + if (nodeP == listP->head_ul) { + return (nodeP); + } - return (-1); + for (j = listP->head_ul; j >= 0; j = listP->next_ul[j]) { + if (listP->next_ul[j] == nodeP) { + return (j); + } + } + } + + LOG_E(MAC, + "error in prev(), could not find previous to %d in UE_list %s, should never happen, Dumping UE list\n", + nodeP, (ul_flag == 0) ? "DL" : "UL"); + dump_ue_list(listP, ul_flag); + + return (-1); } void swap_UEs(UE_list_t * listP, int nodeiP, int nodejP, int ul_flag) { - int prev_i, prev_j, next_i, next_j; + int prev_i, prev_j, next_i, next_j; - LOG_T(MAC, "Swapping UE %d,%d\n", nodeiP, nodejP); - dump_ue_list(listP, ul_flag); + LOG_T(MAC, "Swapping UE %d,%d\n", nodeiP, nodejP); + dump_ue_list(listP, ul_flag); - prev_i = prev(listP, nodeiP, ul_flag); - prev_j = prev(listP, nodejP, ul_flag); + prev_i = prev(listP, nodeiP, ul_flag); + prev_j = prev(listP, nodejP, ul_flag); - AssertFatal((prev_i >= 0) && (prev_j >= 0), "swap_UEs: problem"); + AssertFatal((prev_i >= 0) && (prev_j >= 0), "swap_UEs: problem"); - if (ul_flag == 0) { - next_i = listP->next[nodeiP]; - next_j = listP->next[nodejP]; - } else { - next_i = listP->next_ul[nodeiP]; - next_j = listP->next_ul[nodejP]; + if (ul_flag == 0) { + next_i = listP->next[nodeiP]; + next_j = listP->next[nodejP]; + } else { + next_i = listP->next_ul[nodeiP]; + next_j = listP->next_ul[nodejP]; + } + + LOG_T(MAC, "[%s] next_i %d, next_i, next_j %d, head %d \n", + (ul_flag == 0) ? "DL" : "UL", next_i, next_j, listP->head); + + if (ul_flag == 0) { + + if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ... + LOG_T(MAC, + "Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n"); + + listP->next[nodeiP] = next_j; + listP->next[nodejP] = nodeiP; + + if (nodeiP == listP->head) { // case i j n(j) + listP->head = nodejP; + } else { + listP->next[prev_i] = nodejP; + } + } else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ... + LOG_T(MAC, + "Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n"); + listP->next[nodejP] = next_i; + listP->next[nodeiP] = nodejP; + + if (nodejP == listP->head) { // case j i n(i) + listP->head = nodeiP; + } else { + listP->next[prev_j] = nodeiP; + } + } else { // case ... p(i) i n(i) ... p(j) j n(j) ... + listP->next[nodejP] = next_i; + listP->next[nodeiP] = next_j; + + if (nodeiP == listP->head) { + LOG_T(MAC, "changing head to %d\n", nodejP); + listP->head = nodejP; + listP->next[prev_j] = nodeiP; + } else if (nodejP == listP->head) { + LOG_D(MAC, "changing head to %d\n", nodeiP); + listP->head = nodeiP; + listP->next[prev_i] = nodejP; + } else { + listP->next[prev_i] = nodejP; + listP->next[prev_j] = nodeiP; + } } + } else { // ul_flag - LOG_T(MAC, "[%s] next_i %d, next_i, next_j %d, head %d \n", - (ul_flag == 0) ? "DL" : "UL", next_i, next_j, listP->head); + if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ... + LOG_T(MAC, + "[UL] Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n"); - if (ul_flag == 0) { + listP->next_ul[nodeiP] = next_j; + listP->next_ul[nodejP] = nodeiP; - if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ... - LOG_T(MAC, - "Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n"); + if (nodeiP == listP->head_ul) { // case i j n(j) + listP->head_ul = nodejP; + } else { + listP->next_ul[prev_i] = nodejP; + } + } else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ... + LOG_T(MAC, + "[UL]Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n"); + listP->next_ul[nodejP] = next_i; + listP->next_ul[nodeiP] = nodejP; - listP->next[nodeiP] = next_j; - listP->next[nodejP] = nodeiP; + if (nodejP == listP->head_ul) { // case j i n(i) + listP->head_ul = nodeiP; + } else { + listP->next_ul[prev_j] = nodeiP; + } + } else { // case ... p(i) i n(i) ... p(j) j n(j) ... - if (nodeiP == listP->head) { // case i j n(j) - listP->head = nodejP; - } else { - listP->next[prev_i] = nodejP; - } - } else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ... - LOG_T(MAC, - "Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n"); - listP->next[nodejP] = next_i; - listP->next[nodeiP] = nodejP; + listP->next_ul[nodejP] = next_i; + listP->next_ul[nodeiP] = next_j; - if (nodejP == listP->head) { // case j i n(i) - listP->head = nodeiP; - } else { - listP->next[prev_j] = nodeiP; - } - } else { // case ... p(i) i n(i) ... p(j) j n(j) ... - listP->next[nodejP] = next_i; - listP->next[nodeiP] = next_j; - - if (nodeiP == listP->head) { - LOG_T(MAC, "changing head to %d\n", nodejP); - listP->head = nodejP; - listP->next[prev_j] = nodeiP; - } else if (nodejP == listP->head) { - LOG_D(MAC, "changing head to %d\n", nodeiP); - listP->head = nodeiP; - listP->next[prev_i] = nodejP; - } else { - listP->next[prev_i] = nodejP; - listP->next[prev_j] = nodeiP; - } - } - } else { // ul_flag - - if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ... - LOG_T(MAC, - "[UL] Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n"); - - listP->next_ul[nodeiP] = next_j; - listP->next_ul[nodejP] = nodeiP; - - if (nodeiP == listP->head_ul) { // case i j n(j) - listP->head_ul = nodejP; - } else { - listP->next_ul[prev_i] = nodejP; - } - } else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ... - LOG_T(MAC, - "[UL]Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n"); - listP->next_ul[nodejP] = next_i; - listP->next_ul[nodeiP] = nodejP; - - if (nodejP == listP->head_ul) { // case j i n(i) - listP->head_ul = nodeiP; - } else { - listP->next_ul[prev_j] = nodeiP; - } - } else { // case ... p(i) i n(i) ... p(j) j n(j) ... - - listP->next_ul[nodejP] = next_i; - listP->next_ul[nodeiP] = next_j; - - if (nodeiP == listP->head_ul) { - LOG_T(MAC, "[UL]changing head to %d\n", nodejP); - listP->head_ul = nodejP; - listP->next_ul[prev_j] = nodeiP; - } else if (nodejP == listP->head_ul) { - LOG_T(MAC, "[UL]changing head to %d\n", nodeiP); - listP->head_ul = nodeiP; - listP->next_ul[prev_i] = nodejP; - } else { - listP->next_ul[prev_i] = nodejP; - listP->next_ul[prev_j] = nodeiP; - } - } + if (nodeiP == listP->head_ul) { + LOG_T(MAC, "[UL]changing head to %d\n", nodejP); + listP->head_ul = nodejP; + listP->next_ul[prev_j] = nodeiP; + } else if (nodejP == listP->head_ul) { + LOG_T(MAC, "[UL]changing head to %d\n", nodeiP); + listP->head_ul = nodeiP; + listP->next_ul[prev_i] = nodejP; + } else { + listP->next_ul[prev_i] = nodejP; + listP->next_ul[prev_j] = nodeiP; + } } + } - LOG_T(MAC, "After swap\n"); - dump_ue_list(listP, ul_flag); + LOG_T(MAC, "After swap\n"); + dump_ue_list(listP, ul_flag); } -/* - #if defined(Rel10) || defined(Rel14) - unsigned char generate_mch_header( unsigned char *mac_header, - unsigned char num_sdus, - unsigned short *sdu_lengths, - unsigned char *sdu_lcids, - unsigned char msi, - unsigned char short_padding, - unsigned short post_padding) { - - SCH_SUBHEADER_FIXED *mac_header_ptr = (SCH_SUBHEADER_FIXED *)mac_header; - uint8_t first_element=0,last_size=0,i; - uint8_t mac_header_control_elements[2*num_sdus],*ce_ptr; - - ce_ptr = &mac_header_control_elements[0]; - - if ((short_padding == 1) || (short_padding == 2)) { - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = SHORT_PADDING; - first_element=1; - last_size=1; - } - if (short_padding == 2) { - mac_header_ptr->E = 1; - mac_header_ptr++; - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = SHORT_PADDING; - last_size=1; - } - - // SUBHEADER for MSI CE - if (msi != 0) {// there is MSI MAC Control Element - if (first_element>0) { - mac_header_ptr->E = 1; - mac_header_ptr+=last_size; - } - else { - first_element = 1; - } - if (num_sdus*2 < 128) { - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R = 0; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->E = 0; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F = 0; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->LCID = MCH_SCHDL_INFO; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L = num_sdus*2; - last_size=2; - } - else { - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->R = 0; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->E = 0; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->F = 1; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->LCID = MCH_SCHDL_INFO; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L = (num_sdus*2)&0x7fff; - last_size=3; - } - // Create the MSI MAC Control Element here - } - - // SUBHEADER for MAC SDU (MCCH+MTCHs) - for (i=0;i0) { - mac_header_ptr->E = 1; - mac_header_ptr+=last_size; - } - else { - first_element = 1; - } - if (sdu_lengths[i] < 128) { - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R = 0; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->E = 0; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F = 0; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->LCID = sdu_lcids[i]; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L = (unsigned char)sdu_lengths[i]; - last_size=2; - } - else { - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->R = 0; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->E = 0; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->F = 1; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->LCID = sdu_lcids[i]; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L = (unsigned short) sdu_lengths[i]&0x7fff; - last_size=3; - } - } - - if (post_padding>0) {// we have lots of padding at the end of the packet - mac_header_ptr->E = 1; - mac_header_ptr+=last_size; - // add a padding element - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = SHORT_PADDING; - mac_header_ptr++; - } - else { // no end of packet padding - // last SDU subhead is of fixed type (sdu length implicitly to be computed at UE) - mac_header_ptr++; - } - - // Copy MSI Control Element to the end of the MAC Header if it presents - if ((ce_ptr-mac_header_control_elements) > 0) { - // printf("Copying %d bytes for control elements\n",ce_ptr-mac_header_control_elements); - memcpy((void*)mac_header_ptr,mac_header_control_elements,ce_ptr-mac_header_control_elements); - mac_header_ptr+=(unsigned char)(ce_ptr-mac_header_control_elements); - } - - return((unsigned char*)mac_header_ptr - mac_header); - } - #endif - */ - // This has to be updated to include BSR information uint8_t UE_is_to_be_scheduled(module_id_t module_idP, int CC_id, uint8_t UE_id) { - UE_TEMPLATE *UE_template = - &RC.mac[module_idP]->UE_list.UE_template[CC_id][UE_id]; - UE_sched_ctrl *UE_sched_ctl = - &RC.mac[module_idP]->UE_list.UE_sched_ctrl[UE_id]; + UE_TEMPLATE *UE_template = + &RC.mac[module_idP]->UE_list.UE_template[CC_id][UE_id]; + UE_sched_ctrl *UE_sched_ctl = + &RC.mac[module_idP]->UE_list.UE_sched_ctrl[UE_id]; - // do not schedule UE if UL is not working - if (UE_sched_ctl->ul_failure_timer > 0) - return (0); - if (UE_sched_ctl->ul_out_of_sync > 0) - return (0); + // do not schedule UE if UL is not working + if (UE_sched_ctl->ul_failure_timer > 0) + return (0); + if (UE_sched_ctl->ul_out_of_sync > 0) + return (0); - LOG_D(MAC, "[eNB %d][PUSCH] Checking UL requirements UE %d/%x\n", - module_idP, UE_id, UE_RNTI(module_idP, UE_id)); + LOG_D(MAC, "[eNB %d][PUSCH] Checking UL requirements UE %d/%x\n", + module_idP, UE_id, UE_RNTI(module_idP, UE_id)); - if ((UE_template->bsr_info[LCGID0] > 0) || (UE_template->bsr_info[LCGID1] > 0) || (UE_template->bsr_info[LCGID2] > 0) || (UE_template->bsr_info[LCGID3] > 0) || (UE_template->ul_SR > 0) || // uplink scheduling request - ((UE_sched_ctl->ul_inactivity_timer > 20) && (UE_sched_ctl->ul_scheduled == 0)) || // every 2 frames when RRC_CONNECTED - ((UE_sched_ctl->ul_inactivity_timer > 10) && (UE_sched_ctl->ul_scheduled == 0) && (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED))) // every Frame when not RRC_CONNECTED + if ((UE_template->bsr_info[LCGID0] > 0) || (UE_template->bsr_info[LCGID1] > 0) || (UE_template->bsr_info[LCGID2] > 0) || (UE_template->bsr_info[LCGID3] > 0) || (UE_template->ul_SR > 0) || // uplink scheduling request + ((UE_sched_ctl->ul_inactivity_timer > 20) && (UE_sched_ctl->ul_scheduled == 0)) || // every 2 frames when RRC_CONNECTED + ((UE_sched_ctl->ul_inactivity_timer > 10) && (UE_sched_ctl->ul_scheduled == 0) && (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED))) // every Frame when not RRC_CONNECTED { - LOG_D(MAC, - "[eNB %d][PUSCH] UE %d/%x should be scheduled (BSR0 %d,SR %d)\n", - module_idP, UE_id, UE_RNTI(module_idP, UE_id), - UE_template->bsr_info[LCGID0], UE_template->ul_SR); - return (1); + LOG_D(MAC, + "[eNB %d][PUSCH] UE %d/%x should be scheduled (BSR0 %d,SR %d)\n", + module_idP, UE_id, UE_RNTI(module_idP, UE_id), + UE_template->bsr_info[LCGID0], UE_template->ul_SR); + return (1); } else { - return (0); - } + return (0); + } } uint8_t get_tmode(module_id_t module_idP, int CC_idP, int UE_idP) { - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; - struct PhysicalConfigDedicated *physicalConfigDedicated = - eNB->UE_list.physicalConfigDedicated[CC_idP][UE_idP]; + struct PhysicalConfigDedicated *physicalConfigDedicated = + eNB->UE_list.physicalConfigDedicated[CC_idP][UE_idP]; - if (physicalConfigDedicated == NULL) { // RRCConnectionSetup not received by UE yet - AssertFatal(cc->p_eNB <= 2, "p_eNB is %d, should be <2\n", - cc->p_eNB); - return (cc->p_eNB); - } else { - AssertFatal(physicalConfigDedicated->antennaInfo != NULL, - "antennaInfo is null for CCId %d, UEid %d\n", CC_idP, - UE_idP); + if (physicalConfigDedicated == NULL) { // RRCConnectionSetup not received by UE yet + AssertFatal(cc->p_eNB <= 2, "p_eNB is %d, should be <2\n", + cc->p_eNB); + return (cc->p_eNB); + } else { + AssertFatal(physicalConfigDedicated->antennaInfo != NULL, + "antennaInfo is null for CCId %d, UEid %d\n", CC_idP, + UE_idP); - AssertFatal(physicalConfigDedicated->antennaInfo->present != - PhysicalConfigDedicated__antennaInfo_PR_NOTHING, - "antennaInfo (mod_id %d, CC_id %d) is set to NOTHING\n", - module_idP, CC_idP); + AssertFatal(physicalConfigDedicated->antennaInfo->present != + PhysicalConfigDedicated__antennaInfo_PR_NOTHING, + "antennaInfo (mod_id %d, CC_id %d) is set to NOTHING\n", + module_idP, CC_idP); - if (physicalConfigDedicated->antennaInfo->present == - PhysicalConfigDedicated__antennaInfo_PR_explicitValue) { - return (physicalConfigDedicated->antennaInfo-> - choice.explicitValue.transmissionMode); - } else if (physicalConfigDedicated->antennaInfo->present == - PhysicalConfigDedicated__antennaInfo_PR_defaultValue) { - AssertFatal(cc->p_eNB <= 2, "p_eNB is %d, should be <2\n", - cc->p_eNB); - return (cc->p_eNB); - } else - AssertFatal(1 == 0, "Shouldn't be here\n"); - } + if (physicalConfigDedicated->antennaInfo->present == + PhysicalConfigDedicated__antennaInfo_PR_explicitValue) { + return (physicalConfigDedicated->antennaInfo-> + choice.explicitValue.transmissionMode); + } else if (physicalConfigDedicated->antennaInfo->present == + PhysicalConfigDedicated__antennaInfo_PR_defaultValue) { + AssertFatal(cc->p_eNB <= 2, "p_eNB is %d, should be <2\n", + cc->p_eNB); + return (cc->p_eNB); + } else + AssertFatal(1 == 0, "Shouldn't be here\n"); + } } int8_t get_ULharq(module_id_t module_idP, int CC_idP, uint16_t frameP, uint8_t subframeP) { - uint8_t ret = -1; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; - - if (cc->tdd_Config == NULL) { // FDD - ret = (((frameP << 1) + subframeP) & 7); - } else { - switch (cc->tdd_Config->subframeAssignment) { - case 1: - if ((subframeP == 2) || - (subframeP == 3) || (subframeP == 7) || (subframeP == 8)) - switch (subframeP) { - case 2: - case 3: - ret = (subframeP - 2); - break; - - case 7: - case 8: - ret = (subframeP - 5); - break; - - default: - AssertFatal(1 == 0, - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", - subframeP, - (int) cc->tdd_Config->subframeAssignment); - break; - } - - break; + uint8_t ret = -1; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; + if (cc->tdd_Config == NULL) { // FDD + ret = (((frameP << 1) + subframeP) & 7); + } else { + switch (cc->tdd_Config->subframeAssignment) { + case 1: + if ((subframeP == 2) || + (subframeP == 3) || (subframeP == 7) || (subframeP == 8)) + switch (subframeP) { case 2: - AssertFatal((subframeP == 2) || (subframeP == 7), - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", - subframeP, - (int) cc->tdd_Config->subframeAssignment); - ret = (subframeP / 7); - break; - case 3: - AssertFatal((subframeP > 1) && (subframeP < 5), - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", - subframeP, - (int) cc->tdd_Config->subframeAssignment); - ret = (subframeP - 2); - break; + ret = (subframeP - 2); + break; - case 4: - AssertFatal((subframeP > 1) && (subframeP < 4), - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", - subframeP, - (int) cc->tdd_Config->subframeAssignment); - ret = (subframeP - 2); - break; - - case 5: - AssertFatal(subframeP == 2, - "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", - subframeP, - (int) cc->tdd_Config->subframeAssignment); - ret = (subframeP - 2); - break; + case 7: + case 8: + ret = (subframeP - 5); + break; default: - AssertFatal(1 == 0, - "subframe2_harq_pid, Unsupported TDD mode %d\n", - (int) cc->tdd_Config->subframeAssignment); - break; + AssertFatal(1 == 0, + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframeP, + (int) cc->tdd_Config->subframeAssignment); + break; } - } - AssertFatal(ret != -1, - "invalid harq_pid(%d) at SFN/SF = %d/%d\n", (int8_t) ret, - frameP, subframeP); - return ret; + break; + + case 2: + AssertFatal((subframeP == 2) || (subframeP == 7), + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframeP, + (int) cc->tdd_Config->subframeAssignment); + ret = (subframeP / 7); + break; + + case 3: + AssertFatal((subframeP > 1) && (subframeP < 5), + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframeP, + (int) cc->tdd_Config->subframeAssignment); + ret = (subframeP - 2); + break; + + case 4: + AssertFatal((subframeP > 1) && (subframeP < 4), + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframeP, + (int) cc->tdd_Config->subframeAssignment); + ret = (subframeP - 2); + break; + + case 5: + AssertFatal(subframeP == 2, + "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n", + subframeP, + (int) cc->tdd_Config->subframeAssignment); + ret = (subframeP - 2); + break; + + default: + AssertFatal(1 == 0, + "subframe2_harq_pid, Unsupported TDD mode %d\n", + (int) cc->tdd_Config->subframeAssignment); + break; + } + } + + AssertFatal(ret != -1, + "invalid harq_pid(%d) at SFN/SF = %d/%d\n", (int8_t) ret, + frameP, subframeP); + return ret; } uint16_t getRIV(uint16_t N_RB_DL, uint16_t RBstart, uint16_t Lcrbs) { - uint16_t RIV; + uint16_t RIV; - if (Lcrbs <= (1 + (N_RB_DL >> 1))) - RIV = (N_RB_DL * (Lcrbs - 1)) + RBstart; - else - RIV = (N_RB_DL * (N_RB_DL + 1 - Lcrbs)) + (N_RB_DL - 1 - RBstart); + if (Lcrbs <= (1 + (N_RB_DL >> 1))) + RIV = (N_RB_DL * (Lcrbs - 1)) + RBstart; + else + RIV = (N_RB_DL * (N_RB_DL + 1 - Lcrbs)) + (N_RB_DL - 1 - RBstart); - return (RIV); + return (RIV); } uint32_t allocate_prbs(int UE_id, unsigned char nb_rb, int N_RB_DL, uint32_t * rballoc) { - int i; - uint32_t rballoc_dci = 0; - unsigned char nb_rb_alloc = 0; + int i; + uint32_t rballoc_dci = 0; + unsigned char nb_rb_alloc = 0; - for (i = 0; i < (N_RB_DL - 2); i += 2) { - if (((*rballoc >> i) & 3) == 0) { - *rballoc |= (3 << i); - rballoc_dci |= (1 << ((12 - i) >> 1)); - nb_rb_alloc += 2; - } - - if (nb_rb_alloc == nb_rb) { - return (rballoc_dci); - } + for (i = 0; i < (N_RB_DL - 2); i += 2) { + if (((*rballoc >> i) & 3) == 0) { + *rballoc |= (3 << i); + rballoc_dci |= (1 << ((12 - i) >> 1)); + nb_rb_alloc += 2; } - if ((N_RB_DL & 1) == 1) { - if ((*rballoc >> (N_RB_DL - 1) & 1) == 0) { - *rballoc |= (1 << (N_RB_DL - 1)); - rballoc_dci |= 1; - } + if (nb_rb_alloc == nb_rb) { + return (rballoc_dci); } + } - return (rballoc_dci); + if ((N_RB_DL & 1) == 1) { + if ((*rballoc >> (N_RB_DL - 1) & 1) == 0) { + *rballoc |= (1 << (N_RB_DL - 1)); + rballoc_dci |= 1; + } + } + + return (rballoc_dci); } int get_bw_index(module_id_t module_id, uint8_t CC_id) { - int bw_index = 0; + int bw_index = 0; - int N_RB_DL = - to_prb(RC.mac[module_id]->common_channels[CC_id].mib-> - message.dl_Bandwidth); + int N_RB_DL = + to_prb(RC.mac[module_id]->common_channels[CC_id].mib-> + message.dl_Bandwidth); - switch (N_RB_DL) { - case 6: // 1.4 MHz - bw_index = 0; - break; + switch (N_RB_DL) { + case 6: // 1.4 MHz + bw_index = 0; + break; - case 25: // 5HMz - bw_index = 1; - break; + case 25: // 5HMz + bw_index = 1; + break; - case 50: // 10HMz - bw_index = 2; - break; + case 50: // 10HMz + bw_index = 2; + break; - case 100: // 20HMz - bw_index = 3; - break; + case 100: // 20HMz + bw_index = 3; + break; - default: - bw_index = 1; - LOG_W(MAC, - "[eNB %d] N_RB_DL %d unknown for CC_id %d, setting bw_index to 1\n", - module_id, N_RB_DL, CC_id); - break; - } + default: + bw_index = 1; + LOG_W(MAC, + "[eNB %d] N_RB_DL %d unknown for CC_id %d, setting bw_index to 1\n", + module_id, N_RB_DL, CC_id); + break; + } - return bw_index; + return bw_index; } int get_min_rb_unit(module_id_t module_id, uint8_t CC_id) { - int min_rb_unit = 0; - int N_RB_DL = - to_prb(RC.mac[module_id]->common_channels[CC_id].mib-> - message.dl_Bandwidth); + int min_rb_unit = 0; + int N_RB_DL = + to_prb(RC.mac[module_id]->common_channels[CC_id].mib-> + message.dl_Bandwidth); - switch (N_RB_DL) { - case 6: // 1.4 MHz - min_rb_unit = 1; - break; + switch (N_RB_DL) { + case 6: // 1.4 MHz + min_rb_unit = 1; + break; - case 25: // 5HMz - min_rb_unit = 2; - break; + case 25: // 5HMz + min_rb_unit = 2; + break; - case 50: // 10HMz - min_rb_unit = 3; - break; + case 50: // 10HMz + min_rb_unit = 3; + break; - case 100: // 20HMz - min_rb_unit = 4; - break; + case 100: // 20HMz + min_rb_unit = 4; + break; - default: - min_rb_unit = 2; - LOG_W(MAC, - "[eNB %d] N_DL_RB %d unknown for CC_id %d, setting min_rb_unit to 2\n", - module_id, N_RB_DL, CC_id); - break; - } + default: + min_rb_unit = 2; + LOG_W(MAC, + "[eNB %d] N_DL_RB %d unknown for CC_id %d, setting min_rb_unit to 2\n", + module_id, N_RB_DL, CC_id); + break; + } - return min_rb_unit; + return min_rb_unit; } uint32_t allocate_prbs_sub(int nb_rb, int N_RB_DL, int N_RBG, uint8_t * rballoc) { - int check = 0; //check1=0,check2=0; - uint32_t rballoc_dci = 0; - //uint8_t number_of_subbands=13; + int check = 0; //check1=0,check2=0; + uint32_t rballoc_dci = 0; + //uint8_t number_of_subbands=13; - LOG_T(MAC, "*****Check1RBALLOC****: %d%d%d%d (nb_rb %d,N_RBG %d)\n", - rballoc[3], rballoc[2], rballoc[1], rballoc[0], nb_rb, N_RBG); + LOG_T(MAC, "*****Check1RBALLOC****: %d%d%d%d (nb_rb %d,N_RBG %d)\n", + rballoc[3], rballoc[2], rballoc[1], rballoc[0], nb_rb, N_RBG); - while ((nb_rb > 0) && (check < N_RBG)) { - //printf("rballoc[%d] %d\n",check,rballoc[check]); - if (rballoc[check] == 1) { - rballoc_dci |= (1 << ((N_RBG - 1) - check)); + while ((nb_rb > 0) && (check < N_RBG)) { + //printf("rballoc[%d] %d\n",check,rballoc[check]); + if (rballoc[check] == 1) { + rballoc_dci |= (1 << ((N_RBG - 1) - check)); - switch (N_RB_DL) { - case 6: - nb_rb--; - break; + switch (N_RB_DL) { + case 6: + nb_rb--; + break; - case 25: - if ((check == N_RBG - 1)) { - nb_rb--; - } else { - nb_rb -= 2; - } - - break; - - case 50: - if ((check == N_RBG - 1)) { - nb_rb -= 2; - } else { - nb_rb -= 3; - } - - break; - - case 100: - nb_rb -= 4; - break; - } + case 25: + if ((check == N_RBG - 1)) { + nb_rb--; + } else { + nb_rb -= 2; } - // printf("rb_alloc %x\n",rballoc_dci); - check = check + 1; - // check1 = check1+2; - } - // rballoc_dci = (rballoc_dci)&(0x1fff); - LOG_T(MAC, "*********RBALLOC : %x\n", rballoc_dci); - // exit(-1); - return (rballoc_dci); + break; + + case 50: + if ((check == N_RBG - 1)) { + nb_rb -= 2; + } else { + nb_rb -= 3; + } + + break; + + case 100: + nb_rb -= 4; + break; + } + } + // printf("rb_alloc %x\n",rballoc_dci); + check = check + 1; + // check1 = check1+2; + } + + // rballoc_dci = (rballoc_dci)&(0x1fff); + LOG_T(MAC, "*********RBALLOC : %x\n", rballoc_dci); + // exit(-1); + return (rballoc_dci); } int get_subbandsize(uint8_t dl_Bandwidth) { - uint8_t ss[6] = { 6, 4, 4, 6, 8, 8 }; + uint8_t ss[6] = { 6, 4, 4, 6, 8, 8 }; - AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth %d is out of bounds\n", - dl_Bandwidth); + AssertFatal(dl_Bandwidth < 6, "dl_Bandwidth %d is out of bounds\n", + dl_Bandwidth); - return (ss[dl_Bandwidth]); + return (ss[dl_Bandwidth]); } int get_nb_subband(int N_RB_DL) { - int nb_sb = 0; + int nb_sb = 0; - switch (N_RB_DL) { - case 6: - nb_sb = 0; - break; + switch (N_RB_DL) { + case 6: + nb_sb = 0; + break; - case 15: - nb_sb = 4; // sb_size =4 + case 15: + nb_sb = 4; // sb_size =4 - case 25: - nb_sb = 7; // sb_size =4, 1 sb with 1PRB, 6 with 2 RBG, each has 2 PRBs - break; + case 25: + nb_sb = 7; // sb_size =4, 1 sb with 1PRB, 6 with 2 RBG, each has 2 PRBs + break; - case 50: // sb_size =6 - nb_sb = 9; - break; + case 50: // sb_size =6 + nb_sb = 9; + break; - case 75: // sb_size =8 - nb_sb = 10; - break; + case 75: // sb_size =8 + nb_sb = 10; + break; - case 100: // sb_size =8 , 1 sb with 1 RBG + 12 sb with 2RBG, each RBG has 4 PRBs - nb_sb = 13; - break; + case 100: // sb_size =8 , 1 sb with 1 RBG + 12 sb with 2RBG, each RBG has 4 PRBs + nb_sb = 13; + break; - default: - nb_sb = 0; - break; - } + default: + nb_sb = 0; + break; + } - return nb_sb; + return nb_sb; } void init_CCE_table(int module_idP, int CC_idP) { - memset(RC.mac[module_idP]->CCE_table[CC_idP], 0, 800 * sizeof(int)); + memset(RC.mac[module_idP]->CCE_table[CC_idP], 0, 800 * sizeof(int)); } @@ -2820,711 +2472,626 @@ get_nCCE_offset(int *CCE_table, const int common_dci, const unsigned short rnti, const unsigned char subframe) { - int search_space_free, m, nb_candidates = 0, l, i; - unsigned int Yk; - /* - printf("CCE Allocation: "); - for (i=0;i= 0; m--) { + for (m = nb_candidates - 1; m >= 0; m--) { - search_space_free = 1; - for (l = 0; l < L; l++) { + search_space_free = 1; + for (l = 0; l < L; l++) { - // printf("CCE_table[%d] %d\n",(m*L)+l,CCE_table[(m*L)+l]); - if (CCE_table[(m * L) + l] == 1) { - search_space_free = 0; - break; - } - } - - if (search_space_free == 1) { - - // printf("returning %d\n",m*L); - - for (l = 0; l < L; l++) - CCE_table[(m * L) + l] = 1; - return (m * L); - } + // printf("CCE_table[%d] %d\n",(m*L)+l,CCE_table[(m*L)+l]); + if (CCE_table[(m * L) + l] == 1) { + search_space_free = 0; + break; } + } - return (-1); + if (search_space_free == 1) { - } else { // Find first available in ue specific search space - // according to procedure in Section 9.1.1 of 36.213 (v. 8.6) - // compute Yk - Yk = (unsigned int) rnti; + // printf("returning %d\n",m*L); - for (i = 0; i <= subframe; i++) - Yk = (Yk * 39827) % 65537; - - Yk = Yk % (nCCE / L); - - switch (L) { - case 1: - case 2: - nb_candidates = 6; - break; - - case 4: - case 8: - nb_candidates = 2; - break; - - default: - DevParam(L, nCCE, rnti); - break; - } - - LOG_D(MAC, "rnti %x, Yk = %d, nCCE %d (nCCE/L %d),nb_cand %d\n", - rnti, Yk, nCCE, nCCE / L, nb_candidates); - - for (m = 0; m < nb_candidates; m++) { - search_space_free = 1; - - for (l = 0; l < L; l++) { - int cce = (((Yk + m) % (nCCE / L)) * L) + l; - if (cce >= nCCE || CCE_table[cce] == 1) { - search_space_free = 0; - break; - } - } - - if (search_space_free == 1) { - for (l = 0; l < L; l++) - CCE_table[(((Yk + m) % (nCCE / L)) * L) + l] = 1; - - return (((Yk + m) % (nCCE / L)) * L); - } - } - - return (-1); - } -} - -void -dump_CCE_table(int *CCE_table, const int nCCE, - const unsigned short rnti, const int subframe, int L) -{ - int nb_candidates = 0, i; - unsigned int Yk; - - printf("CCE 0: "); - for (i = 0; i < nCCE; i++) { - printf("%1d.", CCE_table[i]); - if ((i & 7) == 7) - printf("\n CCE %d: ", i); + for (l = 0; l < L; l++) + CCE_table[(m * L) + l] = 1; + return (m * L); + } } + return (-1); + + } else { // Find first available in ue specific search space + // according to procedure in Section 9.1.1 of 36.213 (v. 8.6) + // compute Yk Yk = (unsigned int) rnti; for (i = 0; i <= subframe; i++) - Yk = (Yk * 39827) % 65537; + Yk = (Yk * 39827) % 65537; Yk = Yk % (nCCE / L); switch (L) { case 1: case 2: - nb_candidates = 6; - break; + nb_candidates = 6; + break; case 4: case 8: - nb_candidates = 2; - break; + nb_candidates = 2; + break; default: - DevParam(L, nCCE, rnti); - break; + DevParam(L, nCCE, rnti); + break; } - printf("rnti %x, Yk*L = %d, nCCE %d (nCCE/L %d),nb_cand*L %d\n", rnti, - Yk * L, nCCE, nCCE / L, nb_candidates * L); + LOG_D(MAC, "rnti %x, Yk = %d, nCCE %d (nCCE/L %d),nb_cand %d\n", + rnti, Yk, nCCE, nCCE / L, nb_candidates); + + for (m = 0; m < nb_candidates; m++) { + search_space_free = 1; + + for (l = 0; l < L; l++) { + int cce = (((Yk + m) % (nCCE / L)) * L) + l; + if (cce >= nCCE || CCE_table[cce] == 1) { + search_space_free = 0; + break; + } + } + + if (search_space_free == 1) { + for (l = 0; l < L; l++) + CCE_table[(((Yk + m) % (nCCE / L)) * L) + l] = 1; + + return (((Yk + m) % (nCCE / L)) * L); + } + } + + return (-1); + } +} + +void +dump_CCE_table(int *CCE_table, const int nCCE, + const unsigned short rnti, const int subframe, int L) +{ + int nb_candidates = 0, i; + unsigned int Yk; + + printf("CCE 0: "); + for (i = 0; i < nCCE; i++) { + printf("%1d.", CCE_table[i]); + if ((i & 7) == 7) + printf("\n CCE %d: ", i); + } + + Yk = (unsigned int) rnti; + + for (i = 0; i <= subframe; i++) + Yk = (Yk * 39827) % 65537; + + Yk = Yk % (nCCE / L); + + switch (L) { + case 1: + case 2: + nb_candidates = 6; + break; + + case 4: + case 8: + nb_candidates = 2; + break; + + default: + DevParam(L, nCCE, rnti); + break; + } + + printf("rnti %x, Yk*L = %d, nCCE %d (nCCE/L %d),nb_cand*L %d\n", rnti, + Yk * L, nCCE, nCCE / L, nb_candidates * L); } uint16_t getnquad(COMMON_channels_t * cc, uint8_t num_pdcch_symbols, uint8_t mi) { - uint16_t Nreg = 0; + uint16_t Nreg = 0; - AssertFatal(cc != NULL, "cc is null\n"); - AssertFatal(cc->mib != NULL, "cc->mib is null\n"); + AssertFatal(cc != NULL, "cc is null\n"); + AssertFatal(cc->mib != NULL, "cc->mib is null\n"); - int N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); - int phich_resource = get_phich_resource_times6(cc); + int N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); + int phich_resource = get_phich_resource_times6(cc); - uint8_t Ngroup_PHICH = (phich_resource * N_RB_DL) / 48; + uint8_t Ngroup_PHICH = (phich_resource * N_RB_DL) / 48; - if (((phich_resource * N_RB_DL) % 48) > 0) - Ngroup_PHICH++; + if (((phich_resource * N_RB_DL) % 48) > 0) + Ngroup_PHICH++; - if (cc->Ncp == 1) { - Ngroup_PHICH <<= 1; + if (cc->Ncp == 1) { + Ngroup_PHICH <<= 1; + } + + Ngroup_PHICH *= mi; + + if ((num_pdcch_symbols > 0) && (num_pdcch_symbols < 4)) + switch (N_RB_DL) { + case 6: + Nreg = 12 + (num_pdcch_symbols - 1) * 18; + break; + + case 25: + Nreg = 50 + (num_pdcch_symbols - 1) * 75; + break; + + case 50: + Nreg = 100 + (num_pdcch_symbols - 1) * 150; + break; + + case 100: + Nreg = 200 + (num_pdcch_symbols - 1) * 300; + break; + + default: + return (0); } - - Ngroup_PHICH *= mi; - - if ((num_pdcch_symbols > 0) && (num_pdcch_symbols < 4)) - switch (N_RB_DL) { - case 6: - Nreg = 12 + (num_pdcch_symbols - 1) * 18; - break; - - case 25: - Nreg = 50 + (num_pdcch_symbols - 1) * 75; - break; - - case 50: - Nreg = 100 + (num_pdcch_symbols - 1) * 150; - break; - - case 100: - Nreg = 200 + (num_pdcch_symbols - 1) * 300; - break; - - default: - return (0); - } - // printf("Nreg %d (%d)\n",Nreg,Nreg - 4 - (3*Ngroup_PHICH)); - return (Nreg - 4 - (3 * Ngroup_PHICH)); + // printf("Nreg %d (%d)\n",Nreg,Nreg - 4 - (3*Ngroup_PHICH)); + return (Nreg - 4 - (3 * Ngroup_PHICH)); } uint16_t getnCCE(COMMON_channels_t * cc, uint8_t num_pdcch_symbols, uint8_t mi) { - AssertFatal(cc != NULL, "cc is null\n"); - return (getnquad(cc, num_pdcch_symbols, mi) / 9); + AssertFatal(cc != NULL, "cc is null\n"); + return (getnquad(cc, num_pdcch_symbols, mi) / 9); } uint8_t getmi(COMMON_channels_t * cc, int subframe) { - AssertFatal(cc != NULL, "cc is null\n"); + AssertFatal(cc != NULL, "cc is null\n"); - // for FDD - if (cc->tdd_Config == NULL) // FDD - return 1; + // for FDD + if (cc->tdd_Config == NULL) // FDD + return 1; - // for TDD - switch (cc->tdd_Config->subframeAssignment) { - case 0: - if ((subframe == 0) || (subframe == 5)) - return (2); - else - return (1); + // for TDD + switch (cc->tdd_Config->subframeAssignment) { + case 0: + if ((subframe == 0) || (subframe == 5)) + return (2); + else + return (1); - break; + break; - case 1: - if ((subframe == 0) || (subframe == 5)) - return (0); - else - return (1); + case 1: + if ((subframe == 0) || (subframe == 5)) + return (0); + else + return (1); - break; + break; - case 2: - if ((subframe == 3) || (subframe == 8)) - return (1); - else - return (0); + case 2: + if ((subframe == 3) || (subframe == 8)) + return (1); + else + return (0); - break; + break; - case 3: - if ((subframe == 0) || (subframe == 8) || (subframe == 9)) - return (1); - else - return (0); + case 3: + if ((subframe == 0) || (subframe == 8) || (subframe == 9)) + return (1); + else + return (0); - break; + break; - case 4: - if ((subframe == 8) || (subframe == 9)) - return (1); - else - return (0); + case 4: + if ((subframe == 8) || (subframe == 9)) + return (1); + else + return (0); - break; + break; - case 5: - if (subframe == 8) - return (1); - else - return (0); + case 5: + if (subframe == 8) + return (1); + else + return (0); - break; + break; - case 6: - return (1); - break; + case 6: + return (1); + break; - default: - return (0); - } + default: + return (0); + } } uint16_t get_nCCE_max(COMMON_channels_t * cc, int num_pdcch_symbols, int subframe) { - AssertFatal(cc != NULL, "cc is null\n"); - return (getnCCE(cc, num_pdcch_symbols, getmi(cc, subframe))); + AssertFatal(cc != NULL, "cc is null\n"); + return (getnCCE(cc, num_pdcch_symbols, getmi(cc, subframe))); } // Allocate the CCEs int allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) { - int *CCE_table = RC.mac[module_idP]->CCE_table[CC_idP]; - nfapi_dl_config_request_body_t *DL_req = - &RC.mac[module_idP]->DL_req[CC_idP].dl_config_request_body; - nfapi_hi_dci0_request_body_t *HI_DCI0_req = - &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; - nfapi_dl_config_request_pdu_t *dl_config_pdu = - &DL_req->dl_config_pdu_list[0]; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = - &HI_DCI0_req->hi_dci0_pdu_list[0]; - int nCCE_max = - get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP], 1, - subframeP); - int fCCE; - int i, j, idci; - int nCCE = 0; + int *CCE_table = RC.mac[module_idP]->CCE_table[CC_idP]; + nfapi_dl_config_request_body_t *DL_req = + &RC.mac[module_idP]->DL_req[CC_idP].dl_config_request_body; + nfapi_hi_dci0_request_body_t *HI_DCI0_req = + &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; + nfapi_dl_config_request_pdu_t *dl_config_pdu = + &DL_req->dl_config_pdu_list[0]; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = + &HI_DCI0_req->hi_dci0_pdu_list[0]; + int nCCE_max = + get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP], 1, + subframeP); + int fCCE; + int i, j, idci; + int nCCE = 0; - LOG_D(MAC, - "Allocate CCEs subframe %d, test %d : (DL PDU %d, DL DCI %d, UL %d)\n", - subframeP, test_onlyP, DL_req->number_pdu, DL_req->number_dci, - HI_DCI0_req->number_of_dci); - DL_req->number_pdcch_ofdm_symbols = 1; + LOG_D(MAC, + "Allocate CCEs subframe %d, test %d : (DL PDU %d, DL DCI %d, UL %d)\n", + subframeP, test_onlyP, DL_req->number_pdu, DL_req->number_dci, + HI_DCI0_req->number_of_dci); + DL_req->number_pdcch_ofdm_symbols = 1; - try_again: - init_CCE_table(module_idP, CC_idP); - nCCE = 0; + try_again: + init_CCE_table(module_idP, CC_idP); + nCCE = 0; - for (i = 0, idci = 0; i < DL_req->number_pdu; i++) { - // allocate DL common DCIs first - if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) - && (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type == - 2)) { - LOG_D(MAC, - "Trying to allocate COMMON DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", - idci, DL_req->number_dci + HI_DCI0_req->number_of_dci, - DL_req->number_dci, HI_DCI0_req->number_of_dci, - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti, - dl_config_pdu[i].dci_dl_pdu. - dci_dl_pdu_rel8.aggregation_level, nCCE, nCCE_max, - DL_req->number_pdcch_ofdm_symbols); + for (i = 0, idci = 0; i < DL_req->number_pdu; i++) { + // allocate DL common DCIs first + if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) + && (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type == + 2)) { + LOG_D(MAC, + "Trying to allocate COMMON DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", + idci, DL_req->number_dci + HI_DCI0_req->number_of_dci, + DL_req->number_dci, HI_DCI0_req->number_of_dci, + dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti, + dl_config_pdu[i].dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level, nCCE, nCCE_max, + DL_req->number_pdcch_ofdm_symbols); - if (nCCE + - (dl_config_pdu[i].dci_dl_pdu. - dci_dl_pdu_rel8.aggregation_level) > nCCE_max) { - if (DL_req->number_pdcch_ofdm_symbols == 3) - goto failed; - LOG_D(MAC, - "Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n", - DL_req->number_pdcch_ofdm_symbols); - DL_req->number_pdcch_ofdm_symbols++; - nCCE_max = - get_nCCE_max(&RC.mac[module_idP]-> - common_channels[CC_idP], - DL_req->number_pdcch_ofdm_symbols, - subframeP); - goto try_again; - } - // number of CCEs left can potentially hold this allocation - fCCE = get_nCCE_offset(CCE_table, - dl_config_pdu[i]. - dci_dl_pdu.dci_dl_pdu_rel8. - aggregation_level, nCCE_max, 1, - dl_config_pdu[i]. - dci_dl_pdu.dci_dl_pdu_rel8.rnti, - subframeP); - if (fCCE == -1) { - if (DL_req->number_pdcch_ofdm_symbols == 3) { - LOG_D(MAC, - "subframe %d: Dropping Allocation for RNTI %x\n", - subframeP, - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8. - rnti); - for (j = 0; j <= i; j++) { - if (dl_config_pdu[j].pdu_type == - NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) - LOG_D(MAC, - "DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", - j, - DL_req->number_dci + - HI_DCI0_req->number_of_dci, - DL_req->number_dci, - HI_DCI0_req->number_of_dci, - dl_config_pdu[j]. - dci_dl_pdu.dci_dl_pdu_rel8.rnti, - dl_config_pdu[j]. - dci_dl_pdu.dci_dl_pdu_rel8.dci_format, - dl_config_pdu[j]. - dci_dl_pdu.dci_dl_pdu_rel8. - aggregation_level, nCCE, nCCE_max, - DL_req->number_pdcch_ofdm_symbols); - } - //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<L); - goto failed; - } - LOG_D(MAC, - "Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n", - DL_req->number_pdcch_ofdm_symbols); - - DL_req->number_pdcch_ofdm_symbols++; - nCCE_max = - get_nCCE_max(&RC.mac[module_idP]-> - common_channels[CC_idP], - DL_req->number_pdcch_ofdm_symbols, - subframeP); - goto try_again; - } // fCCE==-1 - - // the allocation is feasible, rnti rule passes - nCCE += + if (nCCE + + (dl_config_pdu[i].dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level) > nCCE_max) { + if (DL_req->number_pdcch_ofdm_symbols == 3) + goto failed; + LOG_D(MAC, + "Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n", + DL_req->number_pdcch_ofdm_symbols); + DL_req->number_pdcch_ofdm_symbols++; + nCCE_max = + get_nCCE_max(&RC.mac[module_idP]-> + common_channels[CC_idP], + DL_req->number_pdcch_ofdm_symbols, + subframeP); + goto try_again; + } + // number of CCEs left can potentially hold this allocation + fCCE = get_nCCE_offset(CCE_table, + dl_config_pdu[i]. + dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level, nCCE_max, 1, + dl_config_pdu[i]. + dci_dl_pdu.dci_dl_pdu_rel8.rnti, + subframeP); + if (fCCE == -1) { + if (DL_req->number_pdcch_ofdm_symbols == 3) { + LOG_D(MAC, + "subframe %d: Dropping Allocation for RNTI %x\n", + subframeP, dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8. - aggregation_level; - LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); - if (test_onlyP == 0) { - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = fCCE; - LOG_D(MAC, - "Allocate COMMON DCI CCEs subframe %d, test %d => L %d fCCE %d\n", - subframeP, test_onlyP, - dl_config_pdu[i].dci_dl_pdu. - dci_dl_pdu_rel8.aggregation_level, fCCE); - } - idci++; + rnti); + for (j = 0; j <= i; j++) { + if (dl_config_pdu[j].pdu_type == + NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) + LOG_D(MAC, + "DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", + j, + DL_req->number_dci + + HI_DCI0_req->number_of_dci, + DL_req->number_dci, + HI_DCI0_req->number_of_dci, + dl_config_pdu[j]. + dci_dl_pdu.dci_dl_pdu_rel8.rnti, + dl_config_pdu[j]. + dci_dl_pdu.dci_dl_pdu_rel8.dci_format, + dl_config_pdu[j]. + dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level, nCCE, nCCE_max, + DL_req->number_pdcch_ofdm_symbols); + } + //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<L); + goto failed; } - } // for i = 0 ... num_DL_DCIs + LOG_D(MAC, + "Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n", + DL_req->number_pdcch_ofdm_symbols); - // no try to allocate UL DCIs - for (i = 0; i < HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi; - i++) { - - // allocate UL DCIs - if (hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) { - - LOG_D(MAC, - "Trying to allocate format 0 DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", - idci, DL_req->number_dci + HI_DCI0_req->number_of_dci, - DL_req->number_dci, HI_DCI0_req->number_of_dci, - hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti, - hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level, - nCCE, nCCE_max, DL_req->number_pdcch_ofdm_symbols); - - if (nCCE + - (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level) > - nCCE_max) { - if (DL_req->number_pdcch_ofdm_symbols == 3) - goto failed; - LOG_D(MAC, - "Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n", - DL_req->number_pdcch_ofdm_symbols); - - DL_req->number_pdcch_ofdm_symbols++; - nCCE_max = - get_nCCE_max(&RC.mac[module_idP]-> + DL_req->number_pdcch_ofdm_symbols++; + nCCE_max = get_nCCE_max(&RC.mac[module_idP]-> common_channels[CC_idP], DL_req->number_pdcch_ofdm_symbols, subframeP); - goto try_again; - } - // number of CCEs left can potentially hold this allocation - fCCE = get_nCCE_offset(CCE_table, - hi_dci0_pdu[i].dci_pdu. - dci_pdu_rel8.aggregation_level, - nCCE_max, 0, - hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8. - rnti, subframeP); - if (fCCE == -1) { - if (DL_req->number_pdcch_ofdm_symbols == 3) { - LOG_D(MAC, - "subframe %d: Dropping Allocation for RNTI %x\n", - subframeP, - hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti); - for (j = 0; j <= i; j++) { - if (hi_dci0_pdu[j].pdu_type == - NFAPI_HI_DCI0_DCI_PDU_TYPE) - LOG_D(MAC, - "DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", - j, - DL_req->number_dci + - HI_DCI0_req->number_of_dci, - DL_req->number_dci, - HI_DCI0_req->number_of_dci, - hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8.rnti, - hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8. - dci_format, - hi_dci0_pdu[j].dci_pdu. - dci_pdu_rel8.aggregation_level, nCCE, - nCCE_max, - DL_req->number_pdcch_ofdm_symbols); - } - //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<L); - goto failed; - } - LOG_D(MAC, - "Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n", - DL_req->number_pdcch_ofdm_symbols); + goto try_again; + } // fCCE==-1 - DL_req->number_pdcch_ofdm_symbols++; - nCCE_max = - get_nCCE_max(&RC.mac[module_idP]-> - common_channels[CC_idP], - DL_req->number_pdcch_ofdm_symbols, - subframeP); - goto try_again; - } // fCCE==-1 + // the allocation is feasible, rnti rule passes + nCCE += dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level; + LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); + if (test_onlyP == 0) { + dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = fCCE; + LOG_D(MAC, + "Allocate COMMON DCI CCEs subframe %d, test %d => L %d fCCE %d\n", + subframeP, test_onlyP, + dl_config_pdu[i].dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level, fCCE); + } + idci++; + } + } // for i = 0 ... num_DL_DCIs - // the allocation is feasible, rnti rule passes - nCCE += hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level; - LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); - if (test_onlyP == 0) { - hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.cce_index = fCCE; - LOG_D(MAC, "Allocate CCEs subframe %d, test %d\n", - subframeP, test_onlyP); - } - idci++; + // no try to allocate UL DCIs + for (i = 0; i < HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi; + i++) { + + // allocate UL DCIs + if (hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) { + + LOG_D(MAC, + "Trying to allocate format 0 DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", + idci, DL_req->number_dci + HI_DCI0_req->number_of_dci, + DL_req->number_dci, HI_DCI0_req->number_of_dci, + hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti, + hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level, + nCCE, nCCE_max, DL_req->number_pdcch_ofdm_symbols); + + if (nCCE + (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level) > nCCE_max) { + if (DL_req->number_pdcch_ofdm_symbols == 3) + goto failed; + LOG_D(MAC, + "Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n", + DL_req->number_pdcch_ofdm_symbols); + + DL_req->number_pdcch_ofdm_symbols++; + nCCE_max = + get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP], + DL_req->number_pdcch_ofdm_symbols, + subframeP); + goto try_again; + } + // number of CCEs left can potentially hold this allocation + fCCE = get_nCCE_offset(CCE_table, + hi_dci0_pdu[i].dci_pdu. + dci_pdu_rel8.aggregation_level, + nCCE_max, 0, + hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8. + rnti, subframeP); + if (fCCE == -1) { + if (DL_req->number_pdcch_ofdm_symbols == 3) { + LOG_D(MAC, + "subframe %d: Dropping Allocation for RNTI %x\n", + subframeP, + hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti); + for (j = 0; j <= i; j++) { + if (hi_dci0_pdu[j].pdu_type == + NFAPI_HI_DCI0_DCI_PDU_TYPE) + LOG_D(MAC, + "DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", + j, + DL_req->number_dci + HI_DCI0_req->number_of_dci, + DL_req->number_dci, + HI_DCI0_req->number_of_dci, + hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8.rnti, + hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8. + dci_format, + hi_dci0_pdu[j].dci_pdu. + dci_pdu_rel8.aggregation_level, nCCE, + nCCE_max, + DL_req->number_pdcch_ofdm_symbols); + } + //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<L); + goto failed; } - } // for i = 0 ... num_UL_DCIs + LOG_D(MAC, + "Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n", + DL_req->number_pdcch_ofdm_symbols); - for (i = 0; i < DL_req->number_pdu; i++) { - // allocate DL UE specific DCIs - if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) - && (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type == - 1)) { - LOG_D(MAC, - "Trying to allocate DL UE-SPECIFIC DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", - idci, DL_req->number_dci + HI_DCI0_req->number_of_dci, - DL_req->number_dci, HI_DCI0_req->number_of_dci, - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti, - dl_config_pdu[i].dci_dl_pdu. - dci_dl_pdu_rel8.aggregation_level, nCCE, nCCE_max, - DL_req->number_pdcch_ofdm_symbols); + DL_req->number_pdcch_ofdm_symbols++; + nCCE_max = + get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP], + DL_req->number_pdcch_ofdm_symbols, + subframeP); + goto try_again; + } // fCCE==-1 - if (nCCE + - (dl_config_pdu[i].dci_dl_pdu. - dci_dl_pdu_rel8.aggregation_level) > nCCE_max) { - if (DL_req->number_pdcch_ofdm_symbols == 3) - goto failed; - LOG_D(MAC, - "Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n", - DL_req->number_pdcch_ofdm_symbols); + // the allocation is feasible, rnti rule passes + nCCE += hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level; + LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); + if (test_onlyP == 0) { + hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.cce_index = fCCE; + LOG_D(MAC, "Allocate CCEs subframe %d, test %d\n", + subframeP, test_onlyP); + } + idci++; + } + } // for i = 0 ... num_UL_DCIs - DL_req->number_pdcch_ofdm_symbols++; - nCCE_max = - get_nCCE_max(&RC.mac[module_idP]-> - common_channels[CC_idP], - DL_req->number_pdcch_ofdm_symbols, - subframeP); - goto try_again; - } - // number of CCEs left can potentially hold this allocation - fCCE = get_nCCE_offset(CCE_table, - dl_config_pdu[i]. - dci_dl_pdu.dci_dl_pdu_rel8. - aggregation_level, nCCE_max, 0, - dl_config_pdu[i]. - dci_dl_pdu.dci_dl_pdu_rel8.rnti, - subframeP); - if (fCCE == -1) { - if (DL_req->number_pdcch_ofdm_symbols == 3) { - LOG_I(MAC, - "subframe %d: Dropping Allocation for RNTI %x\n", - subframeP, - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8. - rnti); - for (j = 0; j <= i; j++) { - if (dl_config_pdu[j].pdu_type == - NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) - LOG_I(MAC, - "DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", - j, - DL_req->number_dci + - HI_DCI0_req->number_of_dci, - DL_req->number_dci, - HI_DCI0_req->number_of_dci, - dl_config_pdu[j]. - dci_dl_pdu.dci_dl_pdu_rel8.rnti, - dl_config_pdu[j]. - dci_dl_pdu.dci_dl_pdu_rel8.dci_format, - dl_config_pdu[j]. - dci_dl_pdu.dci_dl_pdu_rel8. - aggregation_level, nCCE, nCCE_max, - DL_req->number_pdcch_ofdm_symbols); - } - //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<L); - goto failed; - } - LOG_D(MAC, - "Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n", - DL_req->number_pdcch_ofdm_symbols); + for (i = 0; i < DL_req->number_pdu; i++) { + // allocate DL UE specific DCIs + if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) + && (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type == + 1)) { + LOG_D(MAC, + "Trying to allocate DL UE-SPECIFIC DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", + idci, DL_req->number_dci + HI_DCI0_req->number_of_dci, + DL_req->number_dci, HI_DCI0_req->number_of_dci, + dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti, + dl_config_pdu[i].dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level, nCCE, nCCE_max, + DL_req->number_pdcch_ofdm_symbols); - DL_req->number_pdcch_ofdm_symbols++; - nCCE_max = - get_nCCE_max(&RC.mac[module_idP]-> - common_channels[CC_idP], - DL_req->number_pdcch_ofdm_symbols, - subframeP); - goto try_again; - } // fCCE==-1 + if (nCCE + (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level) > nCCE_max) { + if (DL_req->number_pdcch_ofdm_symbols == 3) + goto failed; + LOG_D(MAC, + "Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n", + DL_req->number_pdcch_ofdm_symbols); - // the allocation is feasible, rnti rule passes - nCCE += + DL_req->number_pdcch_ofdm_symbols++; + nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP], + DL_req->number_pdcch_ofdm_symbols, + subframeP); + goto try_again; + } + // number of CCEs left can potentially hold this allocation + fCCE = get_nCCE_offset(CCE_table, + dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, nCCE_max, 0, + dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti, + subframeP); + if (fCCE == -1) { + if (DL_req->number_pdcch_ofdm_symbols == 3) { + LOG_I(MAC, + "subframe %d: Dropping Allocation for RNTI %x\n", + subframeP, dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8. - aggregation_level; - LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); - if (test_onlyP == 0) { - dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = fCCE; - LOG_D(MAC, "Allocate CCEs subframe %d, test %d\n", - subframeP, test_onlyP); - } - idci++; + rnti); + for (j = 0; j <= i; j++) { + if (dl_config_pdu[j].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) + LOG_I(MAC, + "DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", + j, + DL_req->number_dci + HI_DCI0_req->number_of_dci, + DL_req->number_dci, + HI_DCI0_req->number_of_dci, + dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.rnti, + dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.dci_format, + dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level, + nCCE, + nCCE_max, + DL_req->number_pdcch_ofdm_symbols); + } + //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<L); + goto failed; } - } // for i = 0 ... num_DL_DCIs + LOG_D(MAC, + "Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n", + DL_req->number_pdcch_ofdm_symbols); - return 0; + DL_req->number_pdcch_ofdm_symbols++; + nCCE_max = + get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP], + DL_req->number_pdcch_ofdm_symbols, + subframeP); + goto try_again; + } // fCCE==-1 - failed: - return -1; + // the allocation is feasible, rnti rule passes + nCCE += dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level; + LOG_D(MAC, "Allocating at nCCE %d\n", fCCE); + if (test_onlyP == 0) { + dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = fCCE; + LOG_D(MAC, "Allocate CCEs subframe %d, test %d\n", + subframeP, test_onlyP); + } + idci++; + } + } // for i = 0 ... num_DL_DCIs + + return 0; + + failed: + return -1; } -/* -uint8_t get_ul_req_index(module_id_t module_idP, int CC_idP, sub_frame_t subframeP) -{ - if (RC.mac[module_idP]->common_channels[CC_idP].tdd_Config == NULL) - return(0); - - switch (RC.mac[module_idP]->common_channels[CC_idP].tdd_Config->subframeAssignment) { - case 0: - case 1: - case 2: - case 6: - return(0); - case 3: - // 1,5,6 -> 2, prog. 8, buffer 0 - // 7,8 -> 3, prog. 9, buffer 1 - // 9,0 -> 4, prog. 0, buffer 0 - if ((subframeP == 7) || (subframeP == 8)) return(1); - else return(0); - case 4: - // 0,1,4,5 -> 2, prog. 8, buffer 0 - // 6,7,8,9 -> 3, prog. 9, buffer 1 - if (subframeP<6) return(0); - else return(1); - return(1); - break; - case 5: - // 9(-1),0,1,3,4,5,6,7,8,9 -> 2, prog 8, buffer 0 - return(0); - break; - default: - AssertFatal(1==0,"Should not get here, why is tdd_Config->subframeAssignment = %d\n",(int)RC.mac[module_idP]->common_channels[CC_idP].tdd_Config->subframeAssignment); - break; - } - return(0); -} -*/ - nfapi_ul_config_request_pdu_t *has_ul_grant(module_id_t module_idP, int CC_idP, uint16_t absSFP, uint16_t rnti) { - nfapi_ul_config_request_body_t *ul_req; - nfapi_ul_config_request_pdu_t *ul_config_pdu; + nfapi_ul_config_request_body_t *ul_req; + nfapi_ul_config_request_pdu_t *ul_config_pdu; - ul_req = - &RC.mac[module_idP]->UL_req_tmp[CC_idP][absSFP % - 10].ul_config_request_body; - ul_config_pdu = &ul_req->ul_config_pdu_list[0]; - LOG_D(MAC, - "Checking for rnti %x UL grant in subframeP %d (num pdu %d)\n", - rnti, absSFP % 10, ul_req->number_of_pdus); + ul_req = &RC.mac[module_idP]->UL_req_tmp[CC_idP][absSFP % 10].ul_config_request_body; + ul_config_pdu = &ul_req->ul_config_pdu_list[0]; + LOG_D(MAC, + "Checking for rnti %x UL grant in subframeP %d (num pdu %d)\n", + rnti, absSFP % 10, ul_req->number_of_pdus); - for (int i = 0; i < ul_req->number_of_pdus; i++) { - LOG_D(MAC, "PDU %d : type %d,rnti %x\n", i, - ul_config_pdu[i].pdu_type, rnti); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) - && (ul_config_pdu[i].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) - return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == - NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) - && (ul_config_pdu[i].ulsch_cqi_ri_pdu.ulsch_pdu. - ulsch_pdu_rel8.rnti == rnti)) - return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == - NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE) - && (ul_config_pdu[i].ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8. - rnti == rnti)) - return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == - NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE) - && (ul_config_pdu[i].ulsch_cqi_harq_ri_pdu. - ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) - return (&ul_config_pdu[i]); + for (int i = 0; i < ul_req->number_of_pdus; i++) { + LOG_D(MAC, "PDU %d : type %d,rnti %x\n", i,ul_config_pdu[i].pdu_type, rnti); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) + && (ul_config_pdu[i].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) + && (ul_config_pdu[i].ulsch_cqi_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE) + && (ul_config_pdu[i].ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE) + && (ul_config_pdu[i].ulsch_cqi_harq_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE) - && (ul_config_pdu[i].uci_cqi_pdu. - ue_information.ue_information_rel8.rnti == rnti)) - return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE) - && (ul_config_pdu[i].uci_sr_pdu. - ue_information.ue_information_rel8.rnti == rnti)) - return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == - NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) - && (ul_config_pdu[i].uci_harq_pdu. - ue_information.ue_information_rel8.rnti == rnti)) - return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == - NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE) - && (ul_config_pdu[i].uci_sr_harq_pdu. - ue_information.ue_information_rel8.rnti == rnti)) - return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == - NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE) - && (ul_config_pdu[i].uci_cqi_harq_pdu. - ue_information.ue_information_rel8.rnti == rnti)) - return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == - NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE) - && (ul_config_pdu[i].uci_cqi_sr_pdu. - ue_information.ue_information_rel8.rnti == rnti)) - return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == - NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE) - && (ul_config_pdu[i].uci_cqi_sr_harq_pdu. - ue_information.ue_information_rel8.rnti == rnti)) - return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE) + && (ul_config_pdu[i].uci_cqi_pdu.ue_information.ue_information_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE) + && (ul_config_pdu[i].uci_sr_pdu.ue_information.ue_information_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) + && (ul_config_pdu[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE) + && (ul_config_pdu[i].uci_sr_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE) + && (ul_config_pdu[i].uci_cqi_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE) + && (ul_config_pdu[i].uci_cqi_sr_pdu.ue_information.ue_information_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE) + && (ul_config_pdu[i].uci_cqi_sr_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == - NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE) - && (ul_config_pdu[i].ulsch_uci_csi_pdu. - ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) - return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == - NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE) - && (ul_config_pdu[i].ulsch_uci_harq_pdu. - ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) - return (&ul_config_pdu[i]); - if ((ul_config_pdu[i].pdu_type == - NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE) - && (ul_config_pdu[i].ulsch_csi_uci_harq_pdu. - ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) - return (&ul_config_pdu[i]); - } + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE) + && (ul_config_pdu[i].ulsch_uci_csi_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE) + && (ul_config_pdu[i].ulsch_uci_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE) + && (ul_config_pdu[i].ulsch_csi_uci_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) + return (&ul_config_pdu[i]); + } - return (NULL); // no ul grant at all for this UE + return (NULL); // no ul grant at all for this UE } boolean_t @@ -3533,65 +3100,54 @@ CCE_allocation_infeasible(int module_idP, int format_flag, int subframe, int aggregation, int rnti) { - nfapi_dl_config_request_body_t *DL_req = - &RC.mac[module_idP]->DL_req[CC_idP].dl_config_request_body; - nfapi_dl_config_request_pdu_t *dl_config_pdu = - &DL_req->dl_config_pdu_list[DL_req->number_pdu]; - nfapi_hi_dci0_request_body_t *HI_DCI0_req = - &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = - &HI_DCI0_req->hi_dci0_pdu_list[HI_DCI0_req->number_of_dci + - HI_DCI0_req->number_of_hi]; - int ret; - boolean_t res = FALSE; + nfapi_dl_config_request_body_t *DL_req = &RC.mac[module_idP]->DL_req[CC_idP].dl_config_request_body; + nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req->dl_config_pdu_list[DL_req->number_pdu]; + nfapi_hi_dci0_request_body_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi]; + int ret; + boolean_t res = FALSE; - if (format_flag != 2) { // DL DCI - if (DL_req->number_pdu == MAX_NUM_DL_PDU) { - LOG_W(MAC, - "Subframe %d: FAPI DL structure is full, skip scheduling UE %d\n", - subframe, rnti); - } else { - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = - (format_flag == 0) ? 2 : 1; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = - aggregation; - DL_req->number_pdu++; - LOG_D(MAC, - "Subframe %d: Checking CCE feasibility format %d : (%x,%d) (%x,%d,%d)\n", - subframe, format_flag, rnti, aggregation, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - aggregation_level, - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type); - ret = allocate_CCEs(module_idP, CC_idP, subframe, 0); - if (ret == -1) - res = TRUE; - DL_req->number_pdu--; - } - } else { // ue-specific UL DCI - if (HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi == - MAX_NUM_HI_DCI0_PDU) { - LOG_W(MAC, - "Subframe %d: FAPI UL structure is full, skip scheduling UE %d\n", - subframe, rnti); - } else { - hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL8_TAG; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti = rnti; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level = - aggregation; - HI_DCI0_req->number_of_dci++; - ret = allocate_CCEs(module_idP, CC_idP, subframe, 0); - if (ret == -1) - res = TRUE; - HI_DCI0_req->number_of_dci--; - } + if (format_flag != 2) { // DL DCI + if (DL_req->number_pdu == MAX_NUM_DL_PDU) { + LOG_W(MAC, + "Subframe %d: FAPI DL structure is full, skip scheduling UE %d\n", + subframe, rnti); + } else { + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = (format_flag == 0) ? 2 : 1; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = aggregation; + DL_req->number_pdu++; + LOG_D(MAC, + "Subframe %d: Checking CCE feasibility format %d : (%x,%d) (%x,%d,%d)\n", + subframe, format_flag, rnti, aggregation, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. + aggregation_level, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type); + ret = allocate_CCEs(module_idP, CC_idP, subframe, 0); + if (ret == -1) res = TRUE; + DL_req->number_pdu--; } + } else { // ue-specific UL DCI + if (HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi == MAX_NUM_HI_DCI0_PDU) { + LOG_W(MAC, + "Subframe %d: FAPI UL structure is full, skip scheduling UE %d\n", + subframe, rnti); + } else { + hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL8_TAG; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti = rnti; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level = aggregation; + HI_DCI0_req->number_of_dci++; + ret = allocate_CCEs(module_idP, CC_idP, subframe, 0); + if (ret == -1) res = TRUE; + HI_DCI0_req->number_of_dci--; + } + } - return res; + return res; } void @@ -3599,338 +3155,328 @@ extract_harq(module_id_t mod_idP, int CC_idP, int UE_id, frame_t frameP, sub_frame_t subframeP, void *harq_indication, int format) { - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - rnti_t rnti = UE_RNTI(mod_idP, UE_id); - COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; - nfapi_harq_indication_fdd_rel13_t *harq_indication_fdd; - nfapi_harq_indication_tdd_rel13_t *harq_indication_tdd; - uint16_t num_ack_nak; - int numCC = UE_list->numactiveCCs[UE_id]; - int pCCid = UE_list->pCC_id[UE_id]; - int spatial_bundling = 0; - int tmode[5]; - int i, j; - uint8_t *pdu; + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + rnti_t rnti = UE_RNTI(mod_idP, UE_id); + COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; + nfapi_harq_indication_fdd_rel13_t *harq_indication_fdd; + nfapi_harq_indication_tdd_rel13_t *harq_indication_tdd; + uint16_t num_ack_nak; + int numCC = UE_list->numactiveCCs[UE_id]; + int pCCid = UE_list->pCC_id[UE_id]; + int spatial_bundling = 0; + int tmode[5]; + int i, j; + uint8_t *pdu; #ifdef Rel14 - if (UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated != NULL && - UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->pucch_ConfigDedicated != NULL && - (UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7) - && (UE_list->UE_template[pCCid][UE_id]. - physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13) - && - (((UE_list->UE_template[pCCid][UE_id]. - physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13-> - spatialBundlingPUCCH_r13) - && (format == 0)) - || - ((UE_list->UE_template[pCCid][UE_id]. - physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13-> - spatialBundlingPUSCH_r13) - && (format == 1)))) - spatial_bundling = 1; + if (UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated != NULL && + UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->pucch_ConfigDedicated != NULL && + (UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7) + && (UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13) + && (((UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13->spatialBundlingPUCCH_r13) && (format == 0)) + || ((UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13->spatialBundlingPUSCH_r13) + && (format == 1)))) + spatial_bundling = 1; #endif - for (i = 0; i < numCC; i++) - tmode[i] = get_tmode(mod_idP, i, UE_id); + for (i = 0; i < numCC; i++) + tmode[i] = get_tmode(mod_idP, i, UE_id); - if (cc->tdd_Config) { - harq_indication_tdd = - (nfapi_harq_indication_tdd_rel13_t *) harq_indication; - // pdu = &harq_indication_tdd->harq_tb_n[0]; + if (cc->tdd_Config) { + harq_indication_tdd = (nfapi_harq_indication_tdd_rel13_t *) harq_indication; + // pdu = &harq_indication_tdd->harq_tb_n[0]; - num_ack_nak = harq_indication_tdd->number_of_ack_nack; + num_ack_nak = harq_indication_tdd->number_of_ack_nack; - switch (harq_indication_tdd->mode) { - case 0: // Format 1a/b - AssertFatal(numCC == 1, - "numCC %d > 1, should not be using Format1a/b\n", - numCC); - break; - case 1: // Channel Selection - break; - case 2: // Format 3 - break; - case 3: // Format 4 - break; - case 4: // Format 5 - break; - } - } else { - harq_indication_fdd = - (nfapi_harq_indication_fdd_rel13_t *) harq_indication; - num_ack_nak = harq_indication_fdd->number_of_ack_nack; - pdu = &harq_indication_fdd->harq_tb_n[0]; - - uint8_t harq_pid = ((10 * frameP) + subframeP + 10236) & 7; - - LOG_D(MAC,"frame %d subframe %d harq_pid %d mode %d tmode[0] %d num_ack_nak %d round %d\n",frameP,subframeP,harq_pid,harq_indication_fdd->mode,tmode[0],num_ack_nak,sched_ctl->round[CC_idP][harq_pid]); - - switch (harq_indication_fdd->mode) { - case 0: // Format 1a/b (10.1.2.1) - AssertFatal(numCC == 1, - "numCC %d > 1, should not be using Format1a/b\n", - numCC); - if (tmode[0] == 1 || tmode[0] == 2 || tmode[0] == 5 || tmode[0] == 6 || tmode[0] == 7) { // NOTE: have to handle the case of TM9-10 with 1 antenna port - // single ACK/NAK bit - AssertFatal(num_ack_nak == 1, - "num_ack_nak %d > 1 for 1 CC and single-layer transmission frame:%d subframe:%d\n", - num_ack_nak,frameP,subframeP); - AssertFatal(sched_ctl->round[CC_idP][harq_pid] < 8, - "Got ACK/NAK for inactive harq_pid %d for UE %d/%x\n", - harq_pid, UE_id, rnti); - AssertFatal(pdu[0] == 1 || pdu[0] == 2 - || pdu[0] == 4, - "Received ACK/NAK %d which is not 1 or 2 for harq_pid %d from UE %d/%x\n", - pdu[0], harq_pid, UE_id, rnti); - LOG_D(MAC, "Received %d for harq_pid %d\n", pdu[0], - harq_pid); - - if (pdu[0] == 1) { // ACK - sched_ctl->round[CC_idP][harq_pid] = 8; // release HARQ process - sched_ctl->tbcnt[CC_idP][harq_pid] = 0; - } else if (pdu[0] == 2 || pdu[0] == 4) // NAK (treat DTX as NAK) - sched_ctl->round[CC_idP][harq_pid]++; // increment round - } else { - // one or two ACK/NAK bits - AssertFatal(num_ack_nak > 2, - "num_ack_nak %d > 2 for 1 CC and TM3/4/8/9/10\n", - num_ack_nak); - if ((num_ack_nak == 2) - && (sched_ctl->round[CC_idP][harq_pid] < 8) - && (sched_ctl->tbcnt[CC_idP][harq_pid] == 1) - && (pdu[0] == 1) && (pdu[1] == 1)) { - sched_ctl->round[CC_idP][harq_pid] = 8; - sched_ctl->tbcnt[CC_idP][harq_pid] = 0; - } - if ((num_ack_nak == 2) - && (sched_ctl->round[CC_idP][harq_pid] < 8) - && (sched_ctl->tbcnt[CC_idP][harq_pid] == 1) - && (pdu[0] == 2) && (pdu[1] == 2)) - sched_ctl->round[CC_idP][harq_pid]++; - else if (((num_ack_nak == 2) - && (sched_ctl->round[CC_idP][harq_pid] < 8) - && (sched_ctl->tbcnt[0][harq_pid] == 2) - && (pdu[0] == 1) && (pdu[1] == 2)) - || ((num_ack_nak == 2) - && (sched_ctl->round[CC_idP][harq_pid] < 8) - && (sched_ctl->tbcnt[CC_idP][harq_pid] == 2) - && (pdu[0] == 2) && (pdu[1] == 1))) { - sched_ctl->round[CC_idP][harq_pid]++; - sched_ctl->tbcnt[CC_idP][harq_pid] = 1; - } else if ((num_ack_nak == 2) - && (sched_ctl->round[CC_idP][harq_pid] < 8) - && (sched_ctl->tbcnt[CC_idP][harq_pid] == 2) - && (pdu[0] == 2) && (pdu[1] == 2)) - sched_ctl->round[CC_idP][harq_pid]++; - else - AssertFatal(1 == 0, - "Illegal ACK/NAK/round combination (%d,%d,%d,%d,%d) for harq_pid %d, UE %d/%x\n", - num_ack_nak, - sched_ctl->round[CC_idP][harq_pid], - sched_ctl->round[CC_idP][harq_pid], pdu[0], - pdu[1], harq_pid, UE_id, rnti); - } - break; - case 1: // FDD Channel Selection (10.1.2.2.1), must be received for 2 serving cells - AssertFatal(numCC == 2, - "Should not receive harq indication with channel selection with %d active CCs\n", - numCC); - - if ((num_ack_nak == 2) - && (sched_ctl->round[pCCid][harq_pid] < 8) - && (sched_ctl->round[1 - pCCid][harq_pid] < 8) - && (sched_ctl->tbcnt[pCCid][harq_pid] == 1) - && (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 1)) { - AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n", - pdu[0]); - AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n", - pdu[1]); - if (pdu[0] == 1) - sched_ctl->round[pCCid][harq_pid] = 8; - else - sched_ctl->round[pCCid][harq_pid]++; - if (pdu[1] == 1) - sched_ctl->round[1 - pCCid][harq_pid] = 8; - else - sched_ctl->round[1 - pCCid][harq_pid]++; - } // A=2 - else if ((num_ack_nak == 3) - && (sched_ctl->round[pCCid][harq_pid] < 8) - && (sched_ctl->tbcnt[pCCid][harq_pid] == 2) - && (sched_ctl->round[1 - pCCid][harq_pid] < 8) - && (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 1)) { - AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n", - pdu[0]); - AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n", - pdu[1]); - AssertFatal(pdu[2] <= 3, "pdu[2] %d is not ACK/NAK/DTX\n", - pdu[2]); - AssertFatal(sched_ctl->tbcnt[pCCid][harq_pid] == 2, - "sched_ctl->tbcnt[%d][%d] != 2 for UE %d/%x\n", - pCCid, harq_pid, UE_id, rnti); - AssertFatal(sched_ctl->tbcnt[1 - pCCid][harq_pid] == 1, - "sched_ctl->tbcnt[%d][%d] != 1 for UE %d/%x\n", - 1 - pCCid, harq_pid, UE_id, rnti); - if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK - sched_ctl->round[pCCid][harq_pid] = 8; - sched_ctl->tbcnt[pCCid][harq_pid] = 0; - } else if (((pdu[0] == 2) && (pdu[1] == 1)) || - ((pdu[0] == 1) && (pdu[1] == 2))) { - sched_ctl->round[pCCid][harq_pid]++; - sched_ctl->tbcnt[pCCid][harq_pid] = 1; - } else - sched_ctl->round[pCCid][harq_pid]++; - - if (pdu[2] == 1) - sched_ctl->round[1 - pCCid][harq_pid] = 8; - else - sched_ctl->round[1 - pCCid][harq_pid]++; - } // A=3 primary cell has 2 TBs - else if ((num_ack_nak == 3) - && (sched_ctl->round[1 - pCCid][harq_pid] < 8) - && (sched_ctl->round[pCCid][harq_pid] < 8) - && (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 2) - && (sched_ctl->tbcnt[pCCid][harq_pid] == 1)) { - AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n", - pdu[0]); - AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n", - pdu[1]); - AssertFatal(pdu[2] <= 3, "pdu[2] %d is not ACK/NAK/DTX\n", - pdu[2]); - AssertFatal(sched_ctl->tbcnt[1 - pCCid][harq_pid] == 2, - "sched_ctl->tbcnt[%d][%d] != 2 for UE %d/%x\n", - 1 - pCCid, harq_pid, UE_id, rnti); - AssertFatal(sched_ctl->tbcnt[pCCid][harq_pid] == 1, - "sched_ctl->tbcnt[%d][%d] != 1 for UE %d/%x\n", - pCCid, harq_pid, UE_id, rnti); - if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK - sched_ctl->round[1 - pCCid][harq_pid] = 8; - sched_ctl->tbcnt[1 - pCCid][harq_pid] = 0; - } else if (((pdu[0] >= 2) && (pdu[1] == 1)) - || ((pdu[0] == 1) && (pdu[1] >= 2))) { // one ACK - sched_ctl->round[1 - pCCid][harq_pid]++; - sched_ctl->tbcnt[1 - pCCid][harq_pid] = 1; - } else // both NAK/DTX - sched_ctl->round[1 - pCCid][harq_pid]++; - - if (pdu[2] == 1) - sched_ctl->round[pCCid][harq_pid] = 8; - else - sched_ctl->round[pCCid][harq_pid]++; - } // A=3 secondary cell has 2 TBs -#if MAX_NUM_CCs>1 - else if ((num_ack_nak == 4) - && (sched_ctl->round[0][harq_pid] < 8) - && (sched_ctl->round[1][harq_pid] < 8) - && (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 2) - && (sched_ctl->tbcnt[pCCid][harq_pid] == 2)) { - AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n", - pdu[0]); - AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n", - pdu[1]); - AssertFatal(pdu[2] <= 3, "pdu[2] %d is not ACK/NAK/DTX\n", - pdu[2]); - AssertFatal(pdu[3] <= 3, "pdu[3] %d is not ACK/NAK/DTX\n", - pdu[3]); - AssertFatal(sched_ctl->tbcnt[0][harq_pid] == 2, - "sched_ctl->tbcnt[0][%d] != 2 for UE %d/%x\n", - harq_pid, UE_id, rnti); - AssertFatal(sched_ctl->tbcnt[1][harq_pid] == 2, - "sched_ctl->tbcnt[1][%d] != 2 for UE %d/%x\n", - harq_pid, UE_id, rnti); - if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK - sched_ctl->round[0][harq_pid] = 8; - sched_ctl->tbcnt[0][harq_pid] = 0; - } else if (((pdu[0] >= 2) && (pdu[1] == 1)) - || ((pdu[0] == 1) && (pdu[1] >= 2))) { // one ACK - sched_ctl->round[0][harq_pid]++; - sched_ctl->tbcnt[0][harq_pid] = 1; - } else // both NAK/DTX - sched_ctl->round[0][harq_pid]++; - - if ((pdu[2] == 1) && (pdu[3] == 1)) { // both ACK - sched_ctl->round[1][harq_pid] = 8; - sched_ctl->tbcnt[1][harq_pid] = 0; - } else if (((pdu[2] >= 2) && (pdu[3] == 1)) - || ((pdu[2] == 1) && (pdu[3] >= 2))) { // one ACK - sched_ctl->round[1][harq_pid]++; - sched_ctl->tbcnt[1][harq_pid] = 1; - } else // both NAK/DTX - sched_ctl->round[1][harq_pid]++; - } // A=4 both serving cells have 2 TBs -#endif - break; - case 2: // Format 3 - AssertFatal(numCC > 2, - "Should not receive harq indication with FDD format 3 with %d < 3 active CCs\n", - numCC); - for (i = 0, j = 0; i < numCC; i++) { - if ((sched_ctl->round[i][harq_pid] < 8)) { - if (tmode[i] == 1 || tmode[i] == 2 || tmode[0] == 5 - || tmode[0] == 6 || tmode[0] == 7) { - if (pdu[j] == 1) { - sched_ctl->round[i][harq_pid] = 8; - sched_ctl->tbcnt[i][harq_pid] = 0; - } else if (pdu[j] == 2) - sched_ctl->round[i][harq_pid]++; - else - AssertFatal(1 == 0, - "Illegal harq_ack value for CC %d harq_pid %d (%d) UE %d/%x\n", - i, harq_pid, pdu[j], UE_id, rnti); - j++; - } else if (spatial_bundling == 0) { - if ((sched_ctl->tbcnt[i][harq_pid] == 2) - && (pdu[j] == 1) && (pdu[j + 1] == 1)) { - sched_ctl->round[i][harq_pid] = 8; - sched_ctl->tbcnt[i][harq_pid] = 0; - } else if ((sched_ctl->tbcnt[i][harq_pid] == 2) - && (pdu[j] == 1) && (pdu[j + 1] == 2)) { - sched_ctl->round[i][harq_pid]++; - sched_ctl->tbcnt[i][harq_pid] = 1; - } else if ((sched_ctl->tbcnt[i][harq_pid] == 2) - && (pdu[j] == 2) && (pdu[j + 1] == 1)) { - sched_ctl->round[i][harq_pid]++; - sched_ctl->tbcnt[i][harq_pid] = 1; - } else if ((sched_ctl->tbcnt[i][harq_pid] == 2) - && (pdu[j] == 2) && (pdu[j + 1] == 2)) { - sched_ctl->round[i][harq_pid]++; - } else - AssertFatal(1 == 0, - "Illegal combination for CC %d harq_pid %d (%d,%d,%d) UE %d/%x\n", - i, harq_pid, - sched_ctl->tbcnt[i][harq_pid], - pdu[j], pdu[j + 1], UE_id, rnti); - j += 2; - } else if (spatial_bundling == 1) { - if (pdu[j] == 1) { - sched_ctl->round[i][harq_pid] = 8; - sched_ctl->tbcnt[i][harq_pid] = 0; - } else if (pdu[j] == 2) { - sched_ctl->round[i][harq_pid]++; - } else - AssertFatal(1 == 0, - "Illegal hack_nak value %d for CC %d harq_pid %d UE %d/%x\n", - pdu[j], i, harq_pid, UE_id, rnti); - j++; - } else - AssertFatal(1 == 0, - "Illegal value for spatial_bundling %d\n", - spatial_bundling); - } - } - break; - case 3: // Format 4 - AssertFatal(1 == 0, - "Should not receive harq indication with Format 4\n"); - break; - case 4: // Format 5 - AssertFatal(1 == 0, - "Should not receive harq indication with Format 5\n"); - break; - } + switch (harq_indication_tdd->mode) { + case 0: // Format 1a/b + AssertFatal(numCC == 1, + "numCC %d > 1, should not be using Format1a/b\n", + numCC); + break; + case 1: // Channel Selection + break; + case 2: // Format 3 + break; + case 3: // Format 4 + break; + case 4: // Format 5 + break; } + } else { + harq_indication_fdd = (nfapi_harq_indication_fdd_rel13_t *) harq_indication; + num_ack_nak = harq_indication_fdd->number_of_ack_nack; + pdu = &harq_indication_fdd->harq_tb_n[0]; + + uint8_t harq_pid = ((10 * frameP) + subframeP + 10236) & 7; + + LOG_D(MAC,"frame %d subframe %d harq_pid %d mode %d tmode[0] %d num_ack_nak %d round %d\n",frameP,subframeP,harq_pid,harq_indication_fdd->mode,tmode[0],num_ack_nak,sched_ctl->round[CC_idP][harq_pid]); + + switch (harq_indication_fdd->mode) { + case 0: // Format 1a/b (10.1.2.1) + AssertFatal(numCC == 1, + "numCC %d > 1, should not be using Format1a/b\n", + numCC); + if (tmode[0] == 1 || tmode[0] == 2 || tmode[0] == 5 || tmode[0] == 6 || tmode[0] == 7) { // NOTE: have to handle the case of TM9-10 with 1 antenna port + // single ACK/NAK bit + AssertFatal(num_ack_nak == 1, + "num_ack_nak %d > 1 for 1 CC and single-layer transmission frame:%d subframe:%d\n", + num_ack_nak,frameP,subframeP); + AssertFatal(sched_ctl->round[CC_idP][harq_pid] < 8, + "Got ACK/NAK for inactive harq_pid %d for UE %d/%x\n", + harq_pid, UE_id, rnti); + AssertFatal(pdu[0] == 1 || pdu[0] == 2 + || pdu[0] == 4, + "Received ACK/NAK %d which is not 1 or 2 for harq_pid %d from UE %d/%x\n", + pdu[0], harq_pid, UE_id, rnti); + LOG_D(MAC, "Received %d for harq_pid %d\n", pdu[0], + harq_pid); + + if (pdu[0] == 1) { // ACK + sched_ctl->round[CC_idP][harq_pid] = 8; // release HARQ process + sched_ctl->tbcnt[CC_idP][harq_pid] = 0; + } else if (pdu[0] == 2 || pdu[0] == 4) // NAK (treat DTX as NAK) + sched_ctl->round[CC_idP][harq_pid]++; // increment round + } else { + // one or two ACK/NAK bits + AssertFatal(num_ack_nak > 2, + "num_ack_nak %d > 2 for 1 CC and TM3/4/8/9/10\n", + num_ack_nak); + if ((num_ack_nak == 2) + && (sched_ctl->round[CC_idP][harq_pid] < 8) + && (sched_ctl->tbcnt[CC_idP][harq_pid] == 1) + && (pdu[0] == 1) && (pdu[1] == 1)) { + sched_ctl->round[CC_idP][harq_pid] = 8; + sched_ctl->tbcnt[CC_idP][harq_pid] = 0; + } + if ((num_ack_nak == 2) + && (sched_ctl->round[CC_idP][harq_pid] < 8) + && (sched_ctl->tbcnt[CC_idP][harq_pid] == 1) + && (pdu[0] == 2) && (pdu[1] == 2)) + sched_ctl->round[CC_idP][harq_pid]++; + else if (((num_ack_nak == 2) + && (sched_ctl->round[CC_idP][harq_pid] < 8) + && (sched_ctl->tbcnt[0][harq_pid] == 2) + && (pdu[0] == 1) && (pdu[1] == 2)) + || ((num_ack_nak == 2) + && (sched_ctl->round[CC_idP][harq_pid] < 8) + && (sched_ctl->tbcnt[CC_idP][harq_pid] == 2) + && (pdu[0] == 2) && (pdu[1] == 1))) { + sched_ctl->round[CC_idP][harq_pid]++; + sched_ctl->tbcnt[CC_idP][harq_pid] = 1; + } else if ((num_ack_nak == 2) + && (sched_ctl->round[CC_idP][harq_pid] < 8) + && (sched_ctl->tbcnt[CC_idP][harq_pid] == 2) + && (pdu[0] == 2) && (pdu[1] == 2)) + sched_ctl->round[CC_idP][harq_pid]++; + else + AssertFatal(1 == 0, + "Illegal ACK/NAK/round combination (%d,%d,%d,%d,%d) for harq_pid %d, UE %d/%x\n", + num_ack_nak, + sched_ctl->round[CC_idP][harq_pid], + sched_ctl->round[CC_idP][harq_pid], pdu[0], + pdu[1], harq_pid, UE_id, rnti); + } + break; + case 1: // FDD Channel Selection (10.1.2.2.1), must be received for 2 serving cells + AssertFatal(numCC == 2, + "Should not receive harq indication with channel selection with %d active CCs\n", + numCC); + + if ((num_ack_nak == 2) + && (sched_ctl->round[pCCid][harq_pid] < 8) + && (sched_ctl->round[1 - pCCid][harq_pid] < 8) + && (sched_ctl->tbcnt[pCCid][harq_pid] == 1) + && (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 1)) { + AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n", + pdu[0]); + AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n", + pdu[1]); + if (pdu[0] == 1) + sched_ctl->round[pCCid][harq_pid] = 8; + else + sched_ctl->round[pCCid][harq_pid]++; + if (pdu[1] == 1) + sched_ctl->round[1 - pCCid][harq_pid] = 8; + else + sched_ctl->round[1 - pCCid][harq_pid]++; + } // A=2 + else if ((num_ack_nak == 3) + && (sched_ctl->round[pCCid][harq_pid] < 8) + && (sched_ctl->tbcnt[pCCid][harq_pid] == 2) + && (sched_ctl->round[1 - pCCid][harq_pid] < 8) + && (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 1)) { + AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n", + pdu[0]); + AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n", + pdu[1]); + AssertFatal(pdu[2] <= 3, "pdu[2] %d is not ACK/NAK/DTX\n", + pdu[2]); + AssertFatal(sched_ctl->tbcnt[pCCid][harq_pid] == 2, + "sched_ctl->tbcnt[%d][%d] != 2 for UE %d/%x\n", + pCCid, harq_pid, UE_id, rnti); + AssertFatal(sched_ctl->tbcnt[1 - pCCid][harq_pid] == 1, + "sched_ctl->tbcnt[%d][%d] != 1 for UE %d/%x\n", + 1 - pCCid, harq_pid, UE_id, rnti); + if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK + sched_ctl->round[pCCid][harq_pid] = 8; + sched_ctl->tbcnt[pCCid][harq_pid] = 0; + } else if (((pdu[0] == 2) && (pdu[1] == 1)) || + ((pdu[0] == 1) && (pdu[1] == 2))) { + sched_ctl->round[pCCid][harq_pid]++; + sched_ctl->tbcnt[pCCid][harq_pid] = 1; + } else + sched_ctl->round[pCCid][harq_pid]++; + + if (pdu[2] == 1) + sched_ctl->round[1 - pCCid][harq_pid] = 8; + else + sched_ctl->round[1 - pCCid][harq_pid]++; + } // A=3 primary cell has 2 TBs + else if ((num_ack_nak == 3) + && (sched_ctl->round[1 - pCCid][harq_pid] < 8) + && (sched_ctl->round[pCCid][harq_pid] < 8) + && (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 2) + && (sched_ctl->tbcnt[pCCid][harq_pid] == 1)) { + AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n", + pdu[0]); + AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n", + pdu[1]); + AssertFatal(pdu[2] <= 3, "pdu[2] %d is not ACK/NAK/DTX\n", + pdu[2]); + AssertFatal(sched_ctl->tbcnt[1 - pCCid][harq_pid] == 2, + "sched_ctl->tbcnt[%d][%d] != 2 for UE %d/%x\n", + 1 - pCCid, harq_pid, UE_id, rnti); + AssertFatal(sched_ctl->tbcnt[pCCid][harq_pid] == 1, + "sched_ctl->tbcnt[%d][%d] != 1 for UE %d/%x\n", + pCCid, harq_pid, UE_id, rnti); + if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK + sched_ctl->round[1 - pCCid][harq_pid] = 8; + sched_ctl->tbcnt[1 - pCCid][harq_pid] = 0; + } else if (((pdu[0] >= 2) && (pdu[1] == 1)) + || ((pdu[0] == 1) && (pdu[1] >= 2))) { // one ACK + sched_ctl->round[1 - pCCid][harq_pid]++; + sched_ctl->tbcnt[1 - pCCid][harq_pid] = 1; + } else // both NAK/DTX + sched_ctl->round[1 - pCCid][harq_pid]++; + + if (pdu[2] == 1) + sched_ctl->round[pCCid][harq_pid] = 8; + else + sched_ctl->round[pCCid][harq_pid]++; + } // A=3 secondary cell has 2 TBs +#if MAX_NUM_CCs>1 + else if ((num_ack_nak == 4) + && (sched_ctl->round[0][harq_pid] < 8) + && (sched_ctl->round[1][harq_pid] < 8) + && (sched_ctl->tbcnt[1 - pCCid][harq_pid] == 2) + && (sched_ctl->tbcnt[pCCid][harq_pid] == 2)) { + AssertFatal(pdu[0] <= 3, "pdu[0] %d is not ACK/NAK/DTX\n", + pdu[0]); + AssertFatal(pdu[1] <= 3, "pdu[1] %d is not ACK/NAK/DTX\n", + pdu[1]); + AssertFatal(pdu[2] <= 3, "pdu[2] %d is not ACK/NAK/DTX\n", + pdu[2]); + AssertFatal(pdu[3] <= 3, "pdu[3] %d is not ACK/NAK/DTX\n", + pdu[3]); + AssertFatal(sched_ctl->tbcnt[0][harq_pid] == 2, + "sched_ctl->tbcnt[0][%d] != 2 for UE %d/%x\n", + harq_pid, UE_id, rnti); + AssertFatal(sched_ctl->tbcnt[1][harq_pid] == 2, + "sched_ctl->tbcnt[1][%d] != 2 for UE %d/%x\n", + harq_pid, UE_id, rnti); + if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK + sched_ctl->round[0][harq_pid] = 8; + sched_ctl->tbcnt[0][harq_pid] = 0; + } else if (((pdu[0] >= 2) && (pdu[1] == 1)) + || ((pdu[0] == 1) && (pdu[1] >= 2))) { // one ACK + sched_ctl->round[0][harq_pid]++; + sched_ctl->tbcnt[0][harq_pid] = 1; + } else // both NAK/DTX + sched_ctl->round[0][harq_pid]++; + + if ((pdu[2] == 1) && (pdu[3] == 1)) { // both ACK + sched_ctl->round[1][harq_pid] = 8; + sched_ctl->tbcnt[1][harq_pid] = 0; + } else if (((pdu[2] >= 2) && (pdu[3] == 1)) + || ((pdu[2] == 1) && (pdu[3] >= 2))) { // one ACK + sched_ctl->round[1][harq_pid]++; + sched_ctl->tbcnt[1][harq_pid] = 1; + } else // both NAK/DTX + sched_ctl->round[1][harq_pid]++; + } // A=4 both serving cells have 2 TBs +#endif + break; + case 2: // Format 3 + AssertFatal(numCC > 2, + "Should not receive harq indication with FDD format 3 with %d < 3 active CCs\n", + numCC); + for (i = 0, j = 0; i < numCC; i++) { + if ((sched_ctl->round[i][harq_pid] < 8)) { + if (tmode[i] == 1 || tmode[i] == 2 || tmode[0] == 5 + || tmode[0] == 6 || tmode[0] == 7) { + if (pdu[j] == 1) { + sched_ctl->round[i][harq_pid] = 8; + sched_ctl->tbcnt[i][harq_pid] = 0; + } else if (pdu[j] == 2) + sched_ctl->round[i][harq_pid]++; + else + AssertFatal(1 == 0, + "Illegal harq_ack value for CC %d harq_pid %d (%d) UE %d/%x\n", + i, harq_pid, pdu[j], UE_id, rnti); + j++; + } else if (spatial_bundling == 0) { + if ((sched_ctl->tbcnt[i][harq_pid] == 2) + && (pdu[j] == 1) && (pdu[j + 1] == 1)) { + sched_ctl->round[i][harq_pid] = 8; + sched_ctl->tbcnt[i][harq_pid] = 0; + } else if ((sched_ctl->tbcnt[i][harq_pid] == 2) + && (pdu[j] == 1) && (pdu[j + 1] == 2)) { + sched_ctl->round[i][harq_pid]++; + sched_ctl->tbcnt[i][harq_pid] = 1; + } else if ((sched_ctl->tbcnt[i][harq_pid] == 2) + && (pdu[j] == 2) && (pdu[j + 1] == 1)) { + sched_ctl->round[i][harq_pid]++; + sched_ctl->tbcnt[i][harq_pid] = 1; + } else if ((sched_ctl->tbcnt[i][harq_pid] == 2) + && (pdu[j] == 2) && (pdu[j + 1] == 2)) { + sched_ctl->round[i][harq_pid]++; + } else + AssertFatal(1 == 0, + "Illegal combination for CC %d harq_pid %d (%d,%d,%d) UE %d/%x\n", + i, harq_pid, + sched_ctl->tbcnt[i][harq_pid], + pdu[j], pdu[j + 1], UE_id, rnti); + j += 2; + } else if (spatial_bundling == 1) { + if (pdu[j] == 1) { + sched_ctl->round[i][harq_pid] = 8; + sched_ctl->tbcnt[i][harq_pid] = 0; + } else if (pdu[j] == 2) { + sched_ctl->round[i][harq_pid]++; + } else + AssertFatal(1 == 0, + "Illegal hack_nak value %d for CC %d harq_pid %d UE %d/%x\n", + pdu[j], i, harq_pid, UE_id, rnti); + j++; + } else + AssertFatal(1 == 0, + "Illegal value for spatial_bundling %d\n", + spatial_bundling); + } + } + break; + case 3: // Format 4 + AssertFatal(1 == 0, + "Should not receive harq indication with Format 4\n"); + break; + case 4: // Format 5 + AssertFatal(1 == 0, + "Should not receive harq indication with Format 5\n"); + break; + } + } } void @@ -3938,129 +3484,106 @@ extract_pucch_csi(module_id_t mod_idP, int CC_idP, int UE_id, frame_t frameP, sub_frame_t subframeP, uint8_t * pdu, uint8_t length) { - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; - struct CQI_ReportPeriodic *cqi_ReportPeriodic; - int no_pmi; - uint8_t Ltab[6] = { 0, 2, 4, 4, 4, 4 }; - uint8_t Jtab[6] = { 0, 2, 2, 3, 4, 4 }; - int feedback_cnt; + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; + struct CQI_ReportPeriodic *cqi_ReportPeriodic; + int no_pmi; + uint8_t Ltab[6] = { 0, 2, 4, 4, 4, 4 }; + uint8_t Jtab[6] = { 0, 2, 2, 3, 4, 4 }; + int feedback_cnt; - AssertFatal(UE_list->UE_template[CC_idP][UE_id]. - physicalConfigDedicated != NULL, - "physicalConfigDedicated is null for UE %d\n", UE_id); - AssertFatal(UE_list-> - UE_template[CC_idP][UE_id].physicalConfigDedicated-> - cqi_ReportConfig != NULL, - "cqi_ReportConfig is null for UE %d\n", UE_id); - AssertFatal((cqi_ReportPeriodic = - UE_list-> - UE_template[CC_idP][UE_id].physicalConfigDedicated-> - cqi_ReportConfig->cqi_ReportPeriodic) != NULL, - "cqi_ReportPeriodic is null for UE %d\n", UE_id); + AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL, + "physicalConfigDedicated is null for UE %d\n", UE_id); + AssertFatal(UE_list-> + UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL, + "cqi_ReportConfig is null for UE %d\n", UE_id); + AssertFatal((cqi_ReportPeriodic = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic) != NULL, + "cqi_ReportPeriodic is null for UE %d\n", UE_id); - // determine feedback mode - AssertFatal(cqi_ReportPeriodic->present != - CQI_ReportPeriodic_PR_NOTHING, - "cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n"); - AssertFatal(cqi_ReportPeriodic->choice. - setup.cqi_FormatIndicatorPeriodic.present != - CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING, - "cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING!\n"); + // determine feedback mode + AssertFatal(cqi_ReportPeriodic->present != CQI_ReportPeriodic_PR_NOTHING, + "cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n"); + AssertFatal(cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present != CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING, + "cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING!\n"); - uint16_t Npd, N_OFFSET_CQI; - int H, K, bandwidth_part, L, Lmask; - int ri = sched_ctl->periodic_ri_received[CC_idP]; + uint16_t Npd, N_OFFSET_CQI; + int H, K, bandwidth_part, L, Lmask; + int ri = sched_ctl->periodic_ri_received[CC_idP]; - get_csi_params(cc, cqi_ReportPeriodic, &Npd, &N_OFFSET_CQI, &H); - K = (H - 1) / Jtab[cc->mib->message.dl_Bandwidth]; - L = Ltab[cc->mib->message.dl_Bandwidth]; - Lmask = L - 1; - feedback_cnt = (((frameP * 10) + subframeP) / Npd) % H; + get_csi_params(cc, cqi_ReportPeriodic, &Npd, &N_OFFSET_CQI, &H); + K = (H - 1) / Jtab[cc->mib->message.dl_Bandwidth]; + L = Ltab[cc->mib->message.dl_Bandwidth]; + Lmask = L - 1; + feedback_cnt = (((frameP * 10) + subframeP) / Npd) % H; - if (feedback_cnt > 0) - bandwidth_part = (feedback_cnt - 1) % K; - else - bandwidth_part = 0; + if (feedback_cnt > 0) + bandwidth_part = (feedback_cnt - 1) % K; + else + bandwidth_part = 0; - switch (get_tmode(mod_idP, CC_idP, UE_id)) { - case 1: - case 2: - case 3: - case 7: - no_pmi = 1; - break; - case 4: - case 5: - case 6: - no_pmi = 0; - break; - default: - // note: need to check TM8-10 without PMI/RI or with 1 antenna port (see Section 5.2.3.3.1 from 36.213) - no_pmi = 0; - } + switch (get_tmode(mod_idP, CC_idP, UE_id)) { + case 1: + case 2: + case 3: + case 7: + no_pmi = 1; + break; + case 4: + case 5: + case 6: + no_pmi = 0; + break; + default: + // note: need to check TM8-10 without PMI/RI or with 1 antenna port (see Section 5.2.3.3.1 from 36.213) + no_pmi = 0; + } - if ((cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic. - present == - CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_widebandCQI) - || (feedback_cnt == 0)) { - // Note: This implements only Tables: 5.3.3.1-1,5.3.3.1-1A and 5.3.3.1-2 from 36.213 (1,2,4 antenna ports Wideband CQI/PMI) + if ((cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_widebandCQI) + || (feedback_cnt == 0)) { + // Note: This implements only Tables: 5.3.3.1-1,5.3.3.1-1A and 5.3.3.1-2 from 36.213 (1,2,4 antenna ports Wideband CQI/PMI) - if (no_pmi == 1) { // get spatial_diffcqi if needed - sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; - sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = - (pdu[0] >> 4) & 7; - } else if ((cc->p_eNB == 2) && (ri == 1)) { - // p=2 Rank 1 wideband CQI/PMI 6 bits - sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; - sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 4) & 3; - } else if ((cc->p_eNB == 2) && (ri > 1)) { - // p=2 Rank 2 wideband CQI/PMI 8 bits - sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; - sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = - (pdu[0] >> 4) & 7; - sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 7) & 1; - } else if ((cc->p_eNB == 4) && (ri == 1)) { - // p=4 Rank 1 wideband CQI/PMI 8 bits - sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; - sched_ctl->periodic_wideband_pmi[CC_idP] = - (pdu[0] >> 4) & 0x0F; - - } else if ((cc->p_eNB == 4) && (ri > 1)) { - // p=4 Rank 2 wideband CQI/PMI 11 bits - sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; - sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = - (pdu[0] >> 4) & 7; - sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 7) & 0xF; - } else - AssertFatal(1 == 0, - "illegal combination p %d, ri %d, no_pmi %d\n", - cc->p_eNB, ri, no_pmi); - } else if (cqi_ReportPeriodic->choice. - setup.cqi_FormatIndicatorPeriodic.present == - CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) + if (no_pmi == 1) { // get spatial_diffcqi if needed + sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; + sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = + (pdu[0] >> 4) & 7; + } else if ((cc->p_eNB == 2) && (ri == 1)) { + // p=2 Rank 1 wideband CQI/PMI 6 bits + sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; + sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 4) & 3; + } else if ((cc->p_eNB == 2) && (ri > 1)) { + // p=2 Rank 2 wideband CQI/PMI 8 bits + sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; + sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = + (pdu[0] >> 4) & 7; + sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 7) & 1; + } else if ((cc->p_eNB == 4) && (ri == 1)) { + // p=4 Rank 1 wideband CQI/PMI 8 bits + sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; + sched_ctl->periodic_wideband_pmi[CC_idP] = + (pdu[0] >> 4) & 0x0F; + } else if ((cc->p_eNB == 4) && (ri > 1)) { + // p=4 Rank 2 wideband CQI/PMI 11 bits + sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0] & 0xF; + sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = + (pdu[0] >> 4) & 7; + sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0] >> 7) & 0xF; + } else + AssertFatal(1 == 0, + "illegal combination p %d, ri %d, no_pmi %d\n", + cc->p_eNB, ri, no_pmi); + } else if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) { - // This is Table 5.2.3.3.2-2 for 36.213 - if (ri == 1) { - //4+Ltab[cc->mib->message.dl_Bandwidth] bits - sched_ctl->periodic_subband_cqi[CC_idP][(bandwidth_part * L) + - ((pdu[0] >> 4) & - Lmask)] = - pdu[0] & 0xF; - } else if (ri > 1) { - //7+Ltab[cc->mib->message.dl_Bandwidth] bits; - sched_ctl-> - periodic_subband_spatial_diffcqi[CC_idP][(bandwidth_part * - L) + - ((pdu[0] >> 7) & - Lmask)] = - (pdu[0] >> 4) & 7; - sched_ctl->periodic_subband_cqi[CC_idP][(bandwidth_part * L) + - ((pdu[0] >> 7) & - Lmask)] = - pdu[0] & 0xF; - } + // This is Table 5.2.3.3.2-2 for 36.213 + if (ri == 1) { + //4+Ltab[cc->mib->message.dl_Bandwidth] bits + sched_ctl->periodic_subband_cqi[CC_idP][(bandwidth_part * L) +((pdu[0] >> 4) & Lmask)] = pdu[0] & 0xF; + } else if (ri > 1) { + //7+Ltab[cc->mib->message.dl_Bandwidth] bits; + sched_ctl->periodic_subband_spatial_diffcqi[CC_idP][(bandwidth_part * L) + ((pdu[0] >> 7) & Lmask)] = (pdu[0] >> 4) & 7; + sched_ctl->periodic_subband_cqi[CC_idP][(bandwidth_part * L) + ((pdu[0] >> 7) & Lmask)] = + pdu[0] & 0xF; + } } } @@ -4069,278 +3592,261 @@ extract_pusch_csi(module_id_t mod_idP, int CC_idP, int UE_id, frame_t frameP, sub_frame_t subframeP, uint8_t * pdu, uint8_t length) { - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; - UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - int Ntab[6] = { 0, 4, 7, 9, 10, 13 }; - int Ntab_uesel[6] = { 0, 8, 13, 17, 19, 25 }; - int Ltab_uesel[6] = { 0, 6, 9, 13, 15, 18 }; - int Mtab_uesel[6] = { 0, 1, 3, 5, 6, 6 }; - int v[6]; - int i; - uint64_t p = *(uint64_t *) pdu; - int curbyte, curbit; - CQI_ReportModeAperiodic_t *cqi_ReportModeAperiodic; + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; + UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + int Ntab[6] = { 0, 4, 7, 9, 10, 13 }; + int Ntab_uesel[6] = { 0, 8, 13, 17, 19, 25 }; + int Ltab_uesel[6] = { 0, 6, 9, 13, 15, 18 }; + int Mtab_uesel[6] = { 0, 1, 3, 5, 6, 6 }; + int v[6]; + int i; + uint64_t p = *(uint64_t *) pdu; + int curbyte, curbit; + CQI_ReportModeAperiodic_t *cqi_ReportModeAperiodic; - AssertFatal(UE_list->UE_template[CC_idP][UE_id]. - physicalConfigDedicated != NULL, - "physicalConfigDedicated is null for UE %d\n", UE_id); - AssertFatal(UE_list-> - UE_template[CC_idP][UE_id].physicalConfigDedicated-> - cqi_ReportConfig != NULL, - "cqi_ReportConfig is null for UE %d\n", UE_id); - AssertFatal((cqi_ReportModeAperiodic = - UE_list-> - UE_template[CC_idP][UE_id].physicalConfigDedicated-> - cqi_ReportConfig->cqi_ReportModeAperiodic) != NULL, - "cqi_ReportModeAperiodic is null for UE %d\n", UE_id); + AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL, + "physicalConfigDedicated is null for UE %d\n", UE_id); + AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL, + "cqi_ReportConfig is null for UE %d\n", UE_id); + AssertFatal((cqi_ReportModeAperiodic = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic) != NULL, + "cqi_ReportModeAperiodic is null for UE %d\n", UE_id); - int N = Ntab[cc->mib->message.dl_Bandwidth]; - int tmode = get_tmode(mod_idP, CC_idP, UE_id); - int ri = sched_ctl->aperiodic_ri_received[CC_idP]; - int r, diffcqi0 = 0, diffcqi1 = 0, pmi_uesel = 0; - int bw = cc->mib->message.dl_Bandwidth; - int m; + int N = Ntab[cc->mib->message.dl_Bandwidth]; + int tmode = get_tmode(mod_idP, CC_idP, UE_id); + int ri = sched_ctl->aperiodic_ri_received[CC_idP]; + int r, diffcqi0 = 0, diffcqi1 = 0, pmi_uesel = 0; + int bw = cc->mib->message.dl_Bandwidth; + int m; - switch (*cqi_ReportModeAperiodic) { - case CQI_ReportModeAperiodic_rm12: - AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n"); - // wideband multiple PMI (TM4/6), Table 5.2.2.6.1-1 (for TM4/6) - AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 - || tmode == 10, - "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm12\n", - tmode); - if (tmode <= 6) { //Table 5.2.2.6.1-1 36.213 - if ((ri == 1) && (cc->p_eNB == 2)) { - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = - (uint8_t) (p & 0x0F); - p >>= 4; - for (i = 0; i < N; i++) { - sched_ctl->aperiodic_subband_pmi[CC_idP][i] = - (uint8_t) (p & 0x03); - p >>= 2; - } - } - if ((ri == 2) && (cc->p_eNB == 2)) { - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = - (uint8_t) (p & 0x0F); - p >>= 4; - sched_ctl->aperiodic_wideband_cqi1[CC_idP] = - (uint8_t) (p & 0x0F); - p >>= 4; - for (i = 0; i < N; i++) { - sched_ctl->aperiodic_subband_pmi[CC_idP][i] = - (uint8_t) (p & 0x01); - p >>= 1; - } - } - if ((ri == 1) && (cc->p_eNB == 4)) { - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = - (uint8_t) (p & 0x0F); - p >>= 4; - for (i = 0; i < N; i++) { - sched_ctl->aperiodic_subband_pmi[CC_idP][i] = - (uint8_t) (p & 0x03); - p >>= 4; - } - } - if ((ri == 2) && (cc->p_eNB == 4)) { - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = - (uint8_t) (p & 0x0F); - p >>= 4; - sched_ctl->aperiodic_wideband_cqi1[CC_idP] = - (uint8_t) (p & 0x0F); - p >>= 4; - for (i = 0; i < N; i++) { - sched_ctl->aperiodic_subband_pmi[CC_idP][i] = - (uint8_t) (p & 0x01); - p >>= 4; - } - } - } // if (tmode <= 6) { //Table 5.2.2.6.1-1 36.213 - else { - AssertFatal(1 == 0, "support for TM 8-10 to be done\n"); - } - - break; - case CQI_ReportModeAperiodic_rm20: - AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n"); - // UE-selected subband CQI no PMI (TM1/2/3/7) , Table 5.2.2.6.3-1 from 36.213 - AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 - || tmode == 7, - "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm20\n", - tmode); - - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F); + switch (*cqi_ReportModeAperiodic) { + case CQI_ReportModeAperiodic_rm12: + AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n"); + // wideband multiple PMI (TM4/6), Table 5.2.2.6.1-1 (for TM4/6) + AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 || tmode == 10, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm12\n", + tmode); + if (tmode <= 6) { //Table 5.2.2.6.1-1 36.213 + if ((ri == 1) && (cc->p_eNB == 2)) { + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F); p >>= 4; - diffcqi0 = (uint8_t) (p & 0x03); - p >>= 2; - r = (uint8_t) (p & ((1 >> Ltab_uesel[bw]) - 1)); - reverse_index(Ntab_uesel[bw], Mtab_uesel[bw], r, v); - for (m = 0; m < Mtab_uesel[bw]; m++) - sched_ctl->aperiodic_subband_diffcqi0[CC_idP][v[m]] = diffcqi0; - break; - case CQI_ReportModeAperiodic_rm22: - AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n"); - // UE-selected subband CQI multiple PMI (TM4/6) Table 5.2.2.6.3-2 from 36.213 - - AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 - || tmode == 10, - "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm22\n", - tmode); - - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F); - p >>= 4; - diffcqi0 = (uint8_t) (p & 0x03); - p >>= 2; - - if (ri > 1) { - sched_ctl->aperiodic_wideband_cqi1[CC_idP] = - (uint8_t) (p & 0x0F); - p >>= 4; - diffcqi1 = (uint8_t) (p & 0x03); - p >>= 2; - } - r = (uint8_t) (p & ((1 >> Ltab_uesel[bw]) - 1)); - p >>= Ltab_uesel[bw]; - reverse_index(Ntab_uesel[bw], Mtab_uesel[bw], r, v); - if ((ri == 1) && (cc->p_eNB == 2)) { - pmi_uesel = p & 0x3; - p >>= 2; - sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x3; - } else if ((ri == 2) && (cc->p_eNB == 2)) { - pmi_uesel = p & 0x1; - p >>= 1; - sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x1; - } else if (cc->p_eNB == 4) { - pmi_uesel = p & 0x0F; - p >>= 4; - sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F; - } - for (m = 0; m < Mtab_uesel[bw]; m++) { - sched_ctl->aperiodic_subband_diffcqi0[CC_idP][v[m]] = diffcqi0; - if (ri > 1) - sched_ctl->aperiodic_subband_diffcqi1[CC_idP][v[m]] = - diffcqi1; - sched_ctl->aperiodic_subband_pmi[CC_idP][v[m]] = pmi_uesel; - } - break; - case CQI_ReportModeAperiodic_rm30: - //subband CQI no PMI (TM1/2/3/7) - AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 - || tmode == 7, - "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm30\n", - tmode); - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = pdu[0] >> 4; - curbyte = 0; - curbit = 3; for (i = 0; i < N; i++) { - sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] = - (pdu[curbyte] >> (curbit - 1)) & 0x03; - curbit -= 2; - if (curbit < 0) { - curbit = 7; - curbyte++; - } + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x03); + p >>= 2; } - sched_ctl->dl_cqi[CC_idP] = - sched_ctl->aperiodic_wideband_cqi0[CC_idP]; - break; - case CQI_ReportModeAperiodic_rm31: - AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n"); - //subband CQI single PMI (TM4/5/6) - AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8 - || tmode == 9 - || tmode == 10, - "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm31\n", - tmode); - - if ((ri == 1) && (cc->p_eNB == 2)) { - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = - (uint8_t) (p & 0x0F); - p >>= 4; - for (i = 0; i < N; i++) { - sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] = - (uint8_t) (p & 0x03); - p >>= 2; - } - sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x03; + } + if ((ri == 2) && (cc->p_eNB == 2)) { + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F); + p >>= 4; + sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x01); + p >>= 1; } - if ((ri == 2) && (cc->p_eNB == 2)) { - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = - (uint8_t) (p & 0x0F); - p >>= 4; - for (i = 0; i < N; i++) { - sched_ctl->aperiodic_subband_pmi[CC_idP][i] = - (uint8_t) (p & 0x01); - p >>= 1; - } - sched_ctl->aperiodic_wideband_cqi1[CC_idP] = - (uint8_t) (p & 0x0F); - p >>= 4; - for (i = 0; i < N; i++) { - sched_ctl->aperiodic_subband_pmi[CC_idP][i] = - (uint8_t) (p & 0x01); - p >>= 1; - } - sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x01; + } + if ((ri == 1) && (cc->p_eNB == 4)) { + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x03); + p >>= 4; } - if ((ri == 1) && (cc->p_eNB == 4)) { - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = - (uint8_t) (p & 0x0F); - p >>= 4; - for (i = 0; i < N; i++) { - sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] = - (uint8_t) (p & 0x03); - p >>= 2; - } - sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F; + } + if ((ri == 2) && (cc->p_eNB == 4)) { + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F); + p >>= 4; + sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t) (p & 0x01); + p >>= 4; } - if ((ri > 1) && (cc->p_eNB == 4)) { // Note : 64 bits for 20 MHz - sched_ctl->aperiodic_wideband_cqi0[CC_idP] = - (uint8_t) (p & 0x0F); - p >>= 4; - for (i = 0; i < N; i++) { - sched_ctl->aperiodic_subband_pmi[CC_idP][i] = - (uint8_t) (p & 0x01); - p >>= 1; - } - sched_ctl->aperiodic_wideband_cqi1[CC_idP] = - (uint8_t) (p & 0x0F); - p >>= 4; - for (i = 0; i < N; i++) { - sched_ctl->aperiodic_subband_pmi[CC_idP][i] = - (uint8_t) (p & 0x01); - p >>= 2; - } - sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F; - } - - break; - case CQI_ReportModeAperiodic_rm32_v1250: - AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8 - || tmode == 9 - || tmode == 10, - "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm32\n", - tmode); - AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm32 to be done\n"); - break; - case CQI_ReportModeAperiodic_rm10_v1310: - AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 - || tmode == 7, - "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm10\n", - tmode); - AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm10 to be done\n"); - break; - case CQI_ReportModeAperiodic_rm11_v1310: - AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8 - || tmode == 9 - || tmode == 10, - "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm11\n", - tmode); - AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm11 to be done\n"); - break; + } + } // if (tmode <= 6) { //Table 5.2.2.6.1-1 36.213 + else { + AssertFatal(1 == 0, "support for TM 8-10 to be done\n"); } + + break; + case CQI_ReportModeAperiodic_rm20: + AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n"); + // UE-selected subband CQI no PMI (TM1/2/3/7) , Table 5.2.2.6.3-1 from 36.213 + AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 + || tmode == 7, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm20\n", + tmode); + + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F); + p >>= 4; + diffcqi0 = (uint8_t) (p & 0x03); + p >>= 2; + r = (uint8_t) (p & ((1 >> Ltab_uesel[bw]) - 1)); + reverse_index(Ntab_uesel[bw], Mtab_uesel[bw], r, v); + for (m = 0; m < Mtab_uesel[bw]; m++) + sched_ctl->aperiodic_subband_diffcqi0[CC_idP][v[m]] = diffcqi0; + break; + case CQI_ReportModeAperiodic_rm22: + AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n"); + // UE-selected subband CQI multiple PMI (TM4/6) Table 5.2.2.6.3-2 from 36.213 + + AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 + || tmode == 10, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm22\n", + tmode); + + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t) (p & 0x0F); + p >>= 4; + diffcqi0 = (uint8_t) (p & 0x03); + p >>= 2; + + if (ri > 1) { + sched_ctl->aperiodic_wideband_cqi1[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + diffcqi1 = (uint8_t) (p & 0x03); + p >>= 2; + } + r = (uint8_t) (p & ((1 >> Ltab_uesel[bw]) - 1)); + p >>= Ltab_uesel[bw]; + reverse_index(Ntab_uesel[bw], Mtab_uesel[bw], r, v); + if ((ri == 1) && (cc->p_eNB == 2)) { + pmi_uesel = p & 0x3; + p >>= 2; + sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x3; + } else if ((ri == 2) && (cc->p_eNB == 2)) { + pmi_uesel = p & 0x1; + p >>= 1; + sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x1; + } else if (cc->p_eNB == 4) { + pmi_uesel = p & 0x0F; + p >>= 4; + sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F; + } + for (m = 0; m < Mtab_uesel[bw]; m++) { + sched_ctl->aperiodic_subband_diffcqi0[CC_idP][v[m]] = diffcqi0; + if (ri > 1) + sched_ctl->aperiodic_subband_diffcqi1[CC_idP][v[m]] = + diffcqi1; + sched_ctl->aperiodic_subband_pmi[CC_idP][v[m]] = pmi_uesel; + } + break; + case CQI_ReportModeAperiodic_rm30: + //subband CQI no PMI (TM1/2/3/7) + AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 + || tmode == 7, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm30\n", + tmode); + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = pdu[0] >> 4; + curbyte = 0; + curbit = 3; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] = + (pdu[curbyte] >> (curbit - 1)) & 0x03; + curbit -= 2; + if (curbit < 0) { + curbit = 7; + curbyte++; + } + } + sched_ctl->dl_cqi[CC_idP] = + sched_ctl->aperiodic_wideband_cqi0[CC_idP]; + break; + case CQI_ReportModeAperiodic_rm31: + AssertFatal(0 == 1, "to be fixed, don't use p but pdu directly\n"); + //subband CQI single PMI (TM4/5/6) + AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8 + || tmode == 9 + || tmode == 10, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm31\n", + tmode); + + if ((ri == 1) && (cc->p_eNB == 2)) { + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] = + (uint8_t) (p & 0x03); + p >>= 2; + } + sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x03; + } + if ((ri == 2) && (cc->p_eNB == 2)) { + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = + (uint8_t) (p & 0x01); + p >>= 1; + } + sched_ctl->aperiodic_wideband_cqi1[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = + (uint8_t) (p & 0x01); + p >>= 1; + } + sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x01; + } + if ((ri == 1) && (cc->p_eNB == 4)) { + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] = + (uint8_t) (p & 0x03); + p >>= 2; + } + sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F; + } + if ((ri > 1) && (cc->p_eNB == 4)) { // Note : 64 bits for 20 MHz + sched_ctl->aperiodic_wideband_cqi0[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = + (uint8_t) (p & 0x01); + p >>= 1; + } + sched_ctl->aperiodic_wideband_cqi1[CC_idP] = + (uint8_t) (p & 0x0F); + p >>= 4; + for (i = 0; i < N; i++) { + sched_ctl->aperiodic_subband_pmi[CC_idP][i] = + (uint8_t) (p & 0x01); + p >>= 2; + } + sched_ctl->aperiodic_wideband_pmi[CC_idP] = p & 0x0F; + } + + break; + case CQI_ReportModeAperiodic_rm32_v1250: + AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8 + || tmode == 9 + || tmode == 10, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm32\n", + tmode); + AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm32 to be done\n"); + break; + case CQI_ReportModeAperiodic_rm10_v1310: + AssertFatal(tmode == 1 || tmode == 2 || tmode == 3 + || tmode == 7, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm10\n", + tmode); + AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm10 to be done\n"); + break; + case CQI_ReportModeAperiodic_rm11_v1310: + AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8 + || tmode == 9 + || tmode == 10, + "Illegal transmission mode %d for CQI_ReportModeAperiodic_rm11\n", + tmode); + AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm11 to be done\n"); + break; + } } void @@ -4349,105 +3855,105 @@ cqi_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, nfapi_cqi_indication_rel9_t * rel9, uint8_t * pdu, nfapi_ul_cqi_information_t * ul_cqi_information) { - int UE_id = find_UE_id(mod_idP, rntiP); - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - if (UE_id == -1) { - LOG_W(MAC, "cqi_indication: UE %x not found\n", rntiP); - return; + int UE_id = find_UE_id(mod_idP, rntiP); + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + if (UE_id == -1) { + LOG_W(MAC, "cqi_indication: UE %x not found\n", rntiP); + return; + } + UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + + if (UE_id >= 0) { + + LOG_D(MAC,"%s() UE_id:%d channel:%d cqi:%d\n", __FUNCTION__, UE_id, ul_cqi_information->channel, ul_cqi_information->ul_cqi); + + if (ul_cqi_information->channel == 0) { // PUCCH + + // extract pucch csi information before changing RI information + extract_pucch_csi(mod_idP, CC_idP, UE_id, frameP, subframeP, + pdu, rel9->length); + + memcpy((void *) sched_ctl->periodic_ri_received, + (void *) rel9->ri, rel9->number_of_cc_reported); + + // SNR for PUCCH2 + sched_ctl->pucch2_snr[CC_idP] = ul_cqi_information->ul_cqi; + } else { //PUSCH + memcpy((void *) sched_ctl->aperiodic_ri_received, + (void *) rel9->ri, rel9->number_of_cc_reported); + + extract_pusch_csi(mod_idP, CC_idP, UE_id, frameP, subframeP, + pdu, rel9->length); + } - UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - if (UE_id >= 0) { - - LOG_D(MAC,"%s() UE_id:%d channel:%d cqi:%d\n", __FUNCTION__, UE_id, ul_cqi_information->channel, ul_cqi_information->ul_cqi); - - if (ul_cqi_information->channel == 0) { // PUCCH - - // extract pucch csi information before changing RI information - extract_pucch_csi(mod_idP, CC_idP, UE_id, frameP, subframeP, - pdu, rel9->length); - - memcpy((void *) sched_ctl->periodic_ri_received, - (void *) rel9->ri, rel9->number_of_cc_reported); - - // SNR for PUCCH2 - sched_ctl->pucch2_snr[CC_idP] = ul_cqi_information->ul_cqi; - } else { //PUSCH - memcpy((void *) sched_ctl->aperiodic_ri_received, - (void *) rel9->ri, rel9->number_of_cc_reported); - - extract_pusch_csi(mod_idP, CC_idP, UE_id, frameP, subframeP, - pdu, rel9->length); - - } - - // timing advance - sched_ctl->timing_advance = rel9->timing_advance; - sched_ctl->timing_advance_r9 = rel9->timing_advance_r9; - } + // timing advance + sched_ctl->timing_advance = rel9->timing_advance; + sched_ctl->timing_advance_r9 = rel9->timing_advance_r9; + } } void SR_indication(module_id_t mod_idP, int cc_idP, frame_t frameP, sub_frame_t subframeP, rnti_t rntiP, uint8_t ul_cqi) { - T(T_ENB_MAC_SCHEDULING_REQUEST, T_INT(mod_idP), T_INT(cc_idP), - T_INT(frameP), T_INT(subframeP), T_INT(rntiP)); + T(T_ENB_MAC_SCHEDULING_REQUEST, T_INT(mod_idP), T_INT(cc_idP), + T_INT(frameP), T_INT(subframeP), T_INT(rntiP)); - int UE_id = find_UE_id(mod_idP, rntiP); - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + int UE_id = find_UE_id(mod_idP, rntiP); + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - if (UE_id != -1) { - if (mac_eNB_get_rrc_status(mod_idP, UE_RNTI(mod_idP, UE_id)) < - RRC_CONNECTED) - LOG_D(MAC, - "[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d on CC_id %d\n", - mod_idP, rntiP, frameP, subframeP, UE_id, cc_idP); + if (UE_id != -1) { + if (mac_eNB_get_rrc_status(mod_idP, UE_RNTI(mod_idP, UE_id)) < + RRC_CONNECTED) + LOG_D(MAC, + "[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d on CC_id %d\n", + mod_idP, rntiP, frameP, subframeP, UE_id, cc_idP); #if 0 - UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - /* for the moment don't use ul_cqi from SR, value is too different from harq */ - sched_ctl->pucch1_snr[cc_idP] = ul_cqi; - sched_ctl->pucch1_cqi_update[cc_idP] = 1; + /* for the moment don't use ul_cqi from SR, value is too different from harq */ + sched_ctl->pucch1_snr[cc_idP] = ul_cqi; + sched_ctl->pucch1_cqi_update[cc_idP] = 1; #endif - UE_list->UE_template[cc_idP][UE_id].ul_SR = 1; - UE_list->UE_template[cc_idP][UE_id].ul_active = TRUE; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION, 1); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION, 0); - } else { - // AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP); - // AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP); - LOG_D(MAC, - "[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d (unknown UEid) on CC_id %d\n", - mod_idP, rntiP, frameP, subframeP, UE_id, cc_idP); - } + UE_list->UE_template[cc_idP][UE_id].ul_SR = 1; + UE_list->UE_template[cc_idP][UE_id].ul_active = TRUE; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION, 1); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION, 0); + } else { + // AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP); + // AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP); + LOG_D(MAC, + "[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d (unknown UEid) on CC_id %d\n", + mod_idP, rntiP, frameP, subframeP, UE_id, cc_idP); + } } void UL_failure_indication(module_id_t mod_idP, int cc_idP, frame_t frameP, rnti_t rntiP, sub_frame_t subframeP) { - int UE_id = find_UE_id(mod_idP, rntiP); - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + int UE_id = find_UE_id(mod_idP, rntiP); + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - if (UE_id != -1) { - LOG_D(MAC, - "[eNB %d][UE %d/%x] Frame %d subframeP %d Signaling UL Failure for UE %d on CC_id %d (timer %d)\n", - mod_idP, UE_id, rntiP, frameP, subframeP, UE_id, cc_idP, - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); - if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 0) - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 1; - } else { - // AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP); - // AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP); - LOG_W(MAC, - "[eNB %d][SR %x] Frame %d subframeP %d Signaling UL Failure for UE %d (unknown UEid) on CC_id %d\n", - mod_idP, rntiP, frameP, subframeP, UE_id, cc_idP); - } + if (UE_id != -1) { + LOG_D(MAC, + "[eNB %d][UE %d/%x] Frame %d subframeP %d Signaling UL Failure for UE %d on CC_id %d (timer %d)\n", + mod_idP, UE_id, rntiP, frameP, subframeP, UE_id, cc_idP, + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); + if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 0) + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 1; + } else { + // AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP); + // AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP); + LOG_W(MAC, + "[eNB %d][SR %x] Frame %d subframeP %d Signaling UL Failure for UE %d (unknown UEid) on CC_id %d\n", + mod_idP, rntiP, frameP, subframeP, UE_id, cc_idP); + } } void @@ -4455,31 +3961,31 @@ harq_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, sub_frame_t subframeP, nfapi_harq_indication_pdu_t * harq_pdu) { - rnti_t rnti = harq_pdu->rx_ue_information.rnti; - uint8_t ul_cqi = harq_pdu->ul_cqi_information.ul_cqi; - uint8_t channel = harq_pdu->ul_cqi_information.channel; - int UE_id = find_UE_id(mod_idP, rnti); - if (UE_id == -1) { - LOG_W(MAC, "harq_indication: UE %x not found\n", rnti); - return; - } - UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; - UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; - // extract HARQ Information - LOG_D(MAC, - "Frame %d, subframe %d: Received harq indication (%d) from UE %d/%x, ul_cqi %d\n", - frameP, subframeP, channel, UE_id, rnti, ul_cqi); - if (cc->tdd_Config) - extract_harq(mod_idP, CC_idP, UE_id, frameP, subframeP, - (void *) &harq_pdu->harq_indication_tdd_rel13, - channel); - else - extract_harq(mod_idP, CC_idP, UE_id, frameP, subframeP, - (void *) &harq_pdu->harq_indication_fdd_rel13, - channel); - if (channel == 0) { - sched_ctl->pucch1_snr[CC_idP] = ul_cqi; - sched_ctl->pucch1_cqi_update[CC_idP] = 1; - } + rnti_t rnti = harq_pdu->rx_ue_information.rnti; + uint8_t ul_cqi = harq_pdu->ul_cqi_information.ul_cqi; + uint8_t channel = harq_pdu->ul_cqi_information.channel; + int UE_id = find_UE_id(mod_idP, rnti); + if (UE_id == -1) { + LOG_W(MAC, "harq_indication: UE %x not found\n", rnti); + return; + } + UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; + UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; + // extract HARQ Information + LOG_D(MAC, + "Frame %d, subframe %d: Received harq indication (%d) from UE %d/%x, ul_cqi %d\n", + frameP, subframeP, channel, UE_id, rnti, ul_cqi); + if (cc->tdd_Config) + extract_harq(mod_idP, CC_idP, UE_id, frameP, subframeP, + (void *) &harq_pdu->harq_indication_tdd_rel13, + channel); + else + extract_harq(mod_idP, CC_idP, UE_id, frameP, subframeP, + (void *) &harq_pdu->harq_indication_fdd_rel13, + channel); + if (channel == 0) { + sched_ctl->pucch1_snr[CC_idP] = ul_cqi; + sched_ctl->pucch1_cqi_update[CC_idP] = 1; + } } From 4b5b55649351b4fe3f46b35d4a533a7b778ccce0 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 22 Jan 2018 15:32:41 +0100 Subject: [PATCH 163/284] bugfix: fix issue 285 - connect/disconnect multiple time As reported by Emad Alizade: According to "Issue255 256 257 paging reesta release" that has been merged in develop version, we have a question: In rrc_eNB_free_UE() function only all ulsch related memory of user has been cleaned, but I think not only ulsch memory but also dlsch memory must be cleaned. I tested the latest develop version and with repetition UE attach-detach procedures we find that the dlsch memory has not been cleaned and after repeat this sequence (45 times) assertion with cause UE_id!=-1 (no free or exiting dlsch_context, dci_tools.c: fill_dci_and_dlsch() ) occurred and no UE will be attached to system. The fixes in this commit are from Emad Alizade. --- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 1 + openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 1 + openair2/LAYER2/MAC/eNB_scheduler.c | 12 ++++++++---- openair2/RRC/LITE/rrc_eNB.c | 9 ++++++++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index dbfae80840..bd3c92454f 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -247,6 +247,7 @@ void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch) Mdlharq = dlsch->Mdlharq; dlsch->rnti = 0; dlsch->active = 0; + dlsch->harq_mask = 0; for (i=0; i<10; i++) dlsch->harq_ids[i] = Mdlharq; diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index e067137a14..4796d16ba3 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -170,6 +170,7 @@ void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch) //ulsch = (LTE_eNB_ULSCH_t *)malloc16(sizeof(LTE_eNB_ULSCH_t)); if (ulsch) { ulsch->rnti = 0; + ulsch->harq_mask = 0; for (i=0; i<8; i++) { if (ulsch->harq_processes[i]) { diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 42835a5a88..e5fd8d941e 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -722,14 +722,18 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, break; } } - for (int ii=0; iiulsch[ii]; + LTE_eNB_ULSCH_t *ulsch = RC.eNB[module_idP][CC_id]->ulsch[ii]; if((ulsch != NULL) && (ulsch->rnti == rnti)){ LOG_I(MAC, "clean_eNb_ulsch UE %x \n", rnti); clean_eNb_ulsch(ulsch); - break; + } + } + for (int ii=0; iidlsch[ii][0]; + if((dlsch != NULL) && (dlsch->rnti == rnti)){ + LOG_I(MAC, "clean_eNb_dlsch UE %x \n", rnti); + clean_eNb_dlsch(dlsch); } } diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index c9ef58129b..964dd9f3d7 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -809,6 +809,7 @@ rrc_eNB_free_UE(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_s* rnti_t rnti = ue_context_pP->ue_context.rnti; int i, j , CC_id, pdu_number; LTE_eNB_ULSCH_t *ulsch = NULL; + LTE_eNB_DLSCH_t *dlsch = NULL; nfapi_ul_config_request_body_t *ul_req_tmp = NULL; PHY_VARS_eNB *eNB_PHY = NULL; eNB_MAC_INST *eNB_MAC = RC.mac[enb_mod_idP]; @@ -851,7 +852,13 @@ rrc_eNB_free_UE(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_s* if((ulsch != NULL) && (ulsch->rnti == rnti)){ LOG_I(RRC, "clean_eNb_ulsch UE %x \n", rnti); clean_eNb_ulsch(ulsch); - break; + } + } + for (i=0; idlsch[i][0]; + if((dlsch != NULL) && (dlsch->rnti == rnti)){ + LOG_I(RRC, "clean_eNb_dlsch UE %x \n", rnti); + clean_eNb_dlsch(dlsch); } } From b5513cadf153015f6348504100ec9da448add442 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 22 Jan 2018 16:00:21 +0100 Subject: [PATCH 164/284] hotfix: fix nfapi for correct compilation on ubuntu 17.10 --- nfapi/open-nFAPI/nfapi/src/nfapi_p4.c | 1 + nfapi/open-nFAPI/nfapi/src/nfapi_p5.c | 1 + nfapi/open-nFAPI/nfapi/src/nfapi_p7.c | 1 + 3 files changed, 3 insertions(+) diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p4.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p4.c index 1eb85e6254..b429e0a6ce 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi_p4.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p4.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c index b3b9b53491..c78b829135 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c index 69ff860774..3754fe379f 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include From 0937339a5385e8771f1a73f698f9e1b51acb0b0e Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Fri, 12 Jan 2018 12:01:44 +0100 Subject: [PATCH 165/284] Update MAC scheduler for slicing (not tested) --- openair2/COMMON/platform_types.h | 1 + openair2/LAYER2/MAC/defs.h | 2 +- openair2/LAYER2/MAC/eNB_scheduler.c | 28 +- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 156 ++++++++++- .../LAYER2/MAC/eNB_scheduler_primitives.c | 25 ++ openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 256 ++++++++++-------- .../MAC/flexran_agent_scheduler_dlsch_ue.c | 2 +- openair2/LAYER2/MAC/pre_processor.c | 177 +++++++----- openair2/LAYER2/MAC/proto.h | 18 +- 9 files changed, 453 insertions(+), 212 deletions(-) diff --git a/openair2/COMMON/platform_types.h b/openair2/COMMON/platform_types.h index 3997d579bd..e5379d532d 100644 --- a/openair2/COMMON/platform_types.h +++ b/openair2/COMMON/platform_types.h @@ -69,6 +69,7 @@ typedef uint32_t frame_t; typedef int32_t sframe_t; typedef uint32_t sub_frame_t; typedef uint8_t module_id_t; +typedef uint8_t slice_id_t; typedef uint8_t eNB_index_t; typedef uint16_t ue_id_t; typedef int16_t smodule_id_t; diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 43d8167fe6..e27ef3648a 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -800,7 +800,7 @@ typedef struct { ///Contention resolution timer used during random access uint8_t mac_ContentionResolutionTimer; - uint16_t max_allowed_rbs[MAX_NUM_LCID]; + uint16_t max_rbs_allowed_slice[MAX_NUM_LCID][MAX_NUM_SLICES]; uint8_t max_mcs[MAX_NUM_LCID]; diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 14715aff5a..432915eb8c 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -744,40 +744,14 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, copy_ulreq(module_idP, frameP, subframeP); // This schedules SRS in subframeP schedule_SRS(module_idP, frameP, subframeP); -#if defined(FLEXRAN_AGENT_SB_IF) - if (mac_agent_registered[module_idP]){ - agent_mac_xface[module_idP]->flexran_agent_schedule_ul_spec(module_idP,frameP,cooperation_flag,0,4, &msg); - } - flexran_agent_mac_destroy_ul_config(msg); -#else // This schedules ULSCH in subframeP (dci0) schedule_ulsch(module_idP, frameP, subframeP); -#endif // This schedules UCI_SR in subframeP schedule_SR(module_idP, frameP, subframeP); // This schedules UCI_CSI in subframeP schedule_CSI(module_idP, frameP, subframeP); - -#if defined(FLEXRAN_AGENT_SB_IF) - if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); - - flexran_apply_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - flexran_agent_mac_destroy_dl_config(msg); - } -#else // This schedules DLSCH in subframeP - schedule_ue_spec(module_idP, frameP, subframeP, mbsfn_status); -#endif + schedule_dlsch(module_idP, frameP, subframeP, mbsfn_status); // Allocate CCEs for good after scheduling is done for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 9dbbb39d03..0d9f129fa6 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -57,6 +57,15 @@ #include "intertask_interface.h" #endif +#if defined FLEXRAN_AGENT_SB_IF +#include "ENB_APP/flexran_agent_defs.h" +#include "flexran_agent_ran_api.h" +#include "header.pb-c.h" +#include "flexran.pb-c.h" +#include "flexran_agent_mac.h" +#include +#endif + #include "T.h" #define ENABLE_MAC_PAYLOAD_DEBUG @@ -64,6 +73,36 @@ extern RAN_CONTEXT_t RC; + +// number of active slices for past and current time +int n_active_slices = 1; +int n_active_slices_current = 1; + +// RB share for each slice for past and current time +float avg_slice_percentage=0.25; +float slice_percentage[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; +float slice_percentage_current[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; +float total_slice_percentage = 0; +float total_slice_percentage_current = 0; + +// MAX MCS for each slice for past and current time +int slice_maxmcs[MAX_NUM_SLICES] = { 28, 28, 28, 28 }; +int slice_maxmcs_current[MAX_NUM_SLICES] = { 28, 28, 28, 28 }; + +int update_dl_scheduler[MAX_NUM_SLICES] = { 1, 1, 1, 1 }; +int update_dl_scheduler_current[MAX_NUM_SLICES] = { 1, 1, 1, 1 }; + +// name of available scheduler +char *dl_scheduler_type[MAX_NUM_SLICES] = + { "schedule_ue_spec", + "schedule_ue_spec", + "schedule_ue_spec", + "schedule_ue_spec" + }; + +// pointer to the slice specific scheduler +slice_scheduler_dl slice_sched_dl[MAX_NUM_SLICES] = {0}; + //------------------------------------------------------------------------------ void add_ue_dlsch_info(module_id_t module_idP, @@ -408,12 +447,117 @@ set_ul_DAI(int module_idP, int UE_idP, int CC_idP, int frameP, } } +//------------------------------------------------------------------------------ +void +schedule_dlsch(module_id_ module_idP, + frame_t frameP, sub_frame_t subframeP, int *mbsfn_flag) +//------------------------------------------------------------------------------{ +{ + + int i=0; + + total_slice_percentage=0; + avg_slice_percentage=1.0/n_active_slices; + + // reset the slice percentage for inactive slices + for (i = n_active_slices; i< MAX_NUM_SLICES; i++) { + slice_percentage[i]=0; + } + for (i = 0; i < n_active_slices; i++) { + if (slice_percentage[i] < 0 ){ + LOG_W(MAC, "[eNB %d] frame %d subframe %d:invalid slice %d percentage %f. resetting to zero", + mod_id, frame, subframe, i, slice_percentage[i]); + slice_percentage[i]=0; + } + total_slice_percentage+=slice_percentage[i]; + } + + for (i = 0; i < n_active_slices; i++) { + + // Load any updated functions + if (update_dl_scheduler[i] > 0 ) { + slice_sched_dl[i] = dlsym(NULL, dl_scheduler_type[i]); + update_dl_scheduler[i] = 0; + update_dl_scheduler_current[i] = 0; + LOG_N(MAC,"update dl scheduler slice %d\n", i); + } + + if (total_slice_percentage <= 1.0){ // the new total RB share is within the range + + // check if the number of slices has changed, and log + if (n_active_slices_current != n_active_slices ){ + if ((n_active_slices > 0) && (n_active_slices <= MAX_NUM_SLICES)) { + LOG_N(MAC,"[eNB %d]frame %d subframe %d: number of active DL slices has changed: %d-->%d\n", + mod_id, frame, subframe, n_active_slices_current, n_active_slices); + + n_active_slices_current = n_active_slices; + + } else { + LOG_W(MAC,"invalid number of DL slices %d, revert to the previous value %d\n",n_active_slices, n_active_slices_current); + n_active_slices = n_active_slices_current; + } + } + + // check if the slice rb share has changed, and log the console + if (slice_percentage_current[i] != slice_percentage[i]){ // new slice percentage + LOG_N(MAC,"[eNB %d][SLICE %d][DL] frame %d subframe %d: total percentage %f-->%f, slice RB percentage has changed: %f-->%f\n", + mod_id, i, frame, subframe, total_slice_percentage_current, total_slice_percentage, slice_percentage_current[i], slice_percentage[i]); + total_slice_percentage_current= total_slice_percentage; + slice_percentage_current[i] = slice_percentage[i]; + + } + + // check if the slice max MCS, and log the console + if (slice_maxmcs_current[i] != slice_maxmcs[i]){ + if ((slice_maxmcs[i] >= 0) && (slice_maxmcs[i] < 29)){ + LOG_N(MAC,"[eNB %d][SLICE %d][DL] frame %d subframe %d: slice MAX MCS has changed: %d-->%d\n", + mod_id, i, frame, subframe, slice_maxmcs_current[i], slice_maxmcs[i]); + slice_maxmcs_current[i] = slice_maxmcs[i]; + } else { + LOG_W(MAC,"[eNB %d][SLICE %d][DL] invalid slice max mcs %d, revert the previous value %d\n",mod_id, i, slice_maxmcs[i],slice_maxmcs_current[i]); + slice_maxmcs[i]= slice_maxmcs_current[i]; + } + } + + // check if a new scheduler, and log the console + if (update_dl_scheduler_current[i] != update_dl_scheduler[i]){ + LOG_N(MAC,"[eNB %d][SLICE %d][DL] frame %d subframe %d: DL scheduler for this slice is updated: %s \n", + mod_id, i, frame, subframe, dl_scheduler_type[i]); + update_dl_scheduler_current[i] = update_dl_scheduler[i]; + } + + } else { + // here we can correct the values, e.g. reduce proportionally + + if (n_active_slices == n_active_slices_current){ + LOG_W(MAC,"[eNB %d][SLICE %d][DL] invalid total RB share (%f->%f), reduce proportionally the RB share by 0.1\n", + mod_id,i, + total_slice_percentage_current, total_slice_percentage); + if (slice_percentage[i] >= avg_slice_percentage){ + slice_percentage[i]-=0.1; + total_slice_percentage-=0.1; + } + } else { + LOG_W(MAC,"[eNB %d][SLICE %d][DL] invalid total RB share (%f->%f), revert the number of slice to its previous value (%d->%d)\n", + mod_id,i, + total_slice_percentage_current, total_slice_percentage, + n_active_slices, n_active_slices_current ); + n_active_slices = n_active_slices_current; + slice_percentage[i] = slice_percentage_current[i]; + } + } + + // Run each enabled slice-specific schedulers one by one + slice_sched_dl[i](mod_id, i, frame, subframe, mbsfn_flag,dl_info); + } + +} // changes to pre-processor for eMTC //------------------------------------------------------------------------------ void -schedule_ue_spec(module_id_t module_idP, +schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, frame_t frameP, sub_frame_t subframeP, int *mbsfn_flag) //------------------------------------------------------------------------------ { @@ -539,7 +683,11 @@ schedule_ue_spec(module_id_t module_idP, (VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_IN); start_meas(&eNB->schedule_dlsch_preprocessor); dlsch_scheduler_pre_processor(module_idP, - frameP, subframeP, N_RBG, mbsfn_flag); + slice_idP, + frameP, + subframeP, + N_RBG, + mbsfn_flag); stop_meas(&eNB->schedule_dlsch_preprocessor); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME (VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_OUT); @@ -570,6 +718,8 @@ schedule_ue_spec(module_id_t module_idP, LOG_D(MAC, "[eNB] Cannot find eNB_UE_stats\n"); continue_flag = 1; } + if (flexran_slice_member(UE_id, slice_idP) == 0) + continue; if (continue_flag != 1) { switch (get_tmode(module_idP, CC_id, UE_id)) { @@ -656,7 +806,7 @@ schedule_ue_spec(module_id_t module_idP, */ eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]]; - eNB_UE_stats->dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1; //cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); + eNB_UE_stats->dlsch_mcs1 =cmin(eNB_UE_stats->dlsch_mcs1, flexran_slice_maxmcs(slice_idP));//openair_daq_vars.target_ue_dl_mcs); // store stats diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index e5f608d74c..4a316cf92c 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -4472,3 +4472,28 @@ harq_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, sched_ctl->pucch1_cqi_update[CC_idP] = 1; } } + +// Flexran Slicing functions + +uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, int total_rbs) +{ + return (uint16_t) floor(rb_percentage * total_rbs); +} + +int flexran_slice_maxmcs(int slice_id) +{ + return slice_maxmcs[slice_id]; +} + +int flexran_slice_member(int UE_id, int slice_id) +{ + + if ((slice_id < 0) || (slice_id > n_active_slices)) + LOG_W(MAC, "out of range slice id %d\n", slice_id); + + + if ((UE_id % n_active_slices) == slice_id) { + return 1; // this ue is a member of this slice + } + return 0; +} diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 035e4c5fa3..b5256820bb 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -57,6 +57,15 @@ #include "intertask_interface.h" #endif +#if defined FLEXRAN_AGENT_SB_IF +#include "ENB_APP/flexran_agent_defs.h" +#include "flexran_agent_ran_api.h" +#include "header.pb-c.h" +#include "flexran.pb-c.h" +#include "flexran_agent_mac.h" +#include +#endif + #include "T.h" #define ENABLE_MAC_PAYLOAD_DEBUG @@ -68,6 +77,37 @@ uint8_t rb_table[34] = 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100 }; +/* number of active slices for past and current time*/ +int n_active_slices_uplink = 1; +int n_active_slices_current_uplink = 1; + +/* RB share for each slice for past and current time*/ +float avg_slice_percentage_uplink=0.25; +float slice_percentage_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; +float slice_percentage_current_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; +float total_slice_percentage_uplink = 0; +float total_slice_percentage_current_uplink = 0; + +// MAX MCS for each slice for past and current time +int slice_maxmcs_uplink[MAX_NUM_SLICES] = {16, 16, 16, 16}; +int slice_maxmcs_current_uplink[MAX_NUM_SLICES] = {16,16,16,16}; + +/*resource blocks allowed*/ +uint16_t nb_rbs_allowed_slice_uplink[MAX_NUM_CCs][MAX_NUM_SLICES]; +/*Slice Update */ +int update_ul_scheduler[MAX_NUM_SLICES] = {1, 1, 1, 1}; +int update_ul_scheduler_current[MAX_NUM_SLICES] = {1, 1, 1, 1}; + +/* name of available scheduler*/ +char *ul_scheduler_type[MAX_NUM_SLICES] = {"schedule_ulsch_rnti", + "schedule_ulsch_rnti", + "schedule_ulsch_rnti", + "schedule_ulsch_rnti" +}; + +/* Slice Function Pointer */ +slice_scheduler_ul slice_sched_ul[MAX_NUM_SLICES] = {0}; + void rx_sdu(const module_id_t enb_mod_idP, const int CC_idP, @@ -921,7 +961,6 @@ set_msg3_subframe(module_id_t Mod_id, } } - void schedule_ulsch(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) @@ -1035,14 +1074,117 @@ schedule_ulsch(module_id_t module_idP, frame_t frameP, } } - schedule_ulsch_rnti(module_idP, frameP, subframeP, sched_subframe, - first_rb); + // perform slice-specifc operations + + total_slice_percentage_uplink=0; + avg_slice_percentage_uplink=1.0/n_active_slices_uplink; + + // reset the slice percentage for inactive slices + for (i = n_active_slices_uplink; i< MAX_NUM_SLICES; i++) { + slice_percentage_uplink[i]=0; + } + for (i = 0; i < n_active_slices_uplink; i++) { + if (slice_percentage_uplink[i] < 0 ){ + LOG_W(MAC, "[eNB %d] frame %d subframe %d:invalid slice %d percentage %f. resetting to zero", + mod_id, frame, subframe, i, slice_percentage_uplink[i]); + slice_percentage_uplink[i]=0; + } + total_slice_percentage_uplink+=slice_percentage_uplink[i]; + } + + for (i = 0; i < n_active_slices_uplink; i++) { + + // Load any updated functions + if (update_ul_scheduler[i] > 0 ) { + slice_sched_ul[i] = dlsym(NULL, ul_scheduler_type[i]); + update_ul_scheduler[i] = 0; + update_ul_scheduler_current[i] = 0; + //slice_percentage_current_uplink[i]= slice_percentage_uplink[i]; + //total_slice_percentage_current_uplink+=slice_percentage_uplink[i]; + //if (total_slice_percentage_current_uplink> 1) + // total_slice_percentage_current_uplink=1; + LOG_N(MAC,"update ul scheduler slice %d\n", i); + } + // the new total RB share is within the range + if (total_slice_percentage_uplink <= 1.0){ + + // check if the number of slices has changed, and log + if (n_active_slices_current_uplink != n_active_slices_uplink ){ + if ((n_active_slices_uplink > 0) && (n_active_slices_uplink <= MAX_NUM_SLICES)) { + LOG_N(MAC,"[eNB %d]frame %d subframe %d: number of active UL slices has changed: %d-->%d\n", + mod_id, frame, subframe, n_active_slices_current_uplink, n_active_slices_uplink); + + n_active_slices_current_uplink = n_active_slices_uplink; + + } else { + LOG_W(MAC,"invalid number of UL slices %d, revert to the previous value %d\n",n_active_slices_uplink, n_active_slices_current_uplink); + n_active_slices_uplink = n_active_slices_current_uplink; + } + } + + // check if the slice rb share has changed, and log the console + if (slice_percentage_current_uplink[i] != slice_percentage_uplink[i]){ + LOG_N(MAC,"[eNB %d][SLICE %d][UL] frame %d subframe %d: total percentage %f-->%f, slice RB percentage has changed: %f-->%f\n", + mod_id, i, frame, subframe, total_slice_percentage_current_uplink, total_slice_percentage_uplink, slice_percentage_current_uplink[i], slice_percentage_uplink[i]); + total_slice_percentage_current_uplink= total_slice_percentage_uplink; + slice_percentage_current_uplink[i] = slice_percentage_uplink[i]; + + } + + // check if the slice max MCS, and log the console + if (slice_maxmcs_current_uplink[i] != slice_maxmcs_uplink[i]){ + if ((slice_maxmcs_uplink[i] >= 0) && (slice_maxmcs_uplink[i] <= 16)){ + LOG_N(MAC,"[eNB %d][SLICE %d][UL] frame %d subframe %d: slice MAX MCS has changed: %d-->%d\n", + mod_id, i, frame, subframe, slice_maxmcs_current_uplink[i], slice_maxmcs_uplink[i]); + slice_maxmcs_current_uplink[i] = slice_maxmcs_uplink[i]; + } else { + LOG_W(MAC,"[eNB %d][SLICE %d][UL] invalid slice max mcs %d, revert the previous value %d\n",mod_id, i, slice_maxmcs_uplink[i],slice_maxmcs_current_uplink[i]); + slice_maxmcs_uplink[i]= slice_maxmcs_current_uplink[i]; + + } + } + + // check if a new scheduler, and log the console + if (update_ul_scheduler_current[i] != update_ul_scheduler[i]){ + LOG_N(MAC,"[eNB %d][SLICE %d][UL] frame %d subframe %d: UL scheduler for this slice is updated: %s \n", + mod_id, i, frame, subframe, ul_scheduler_type[i]); + + update_ul_scheduler_current[i] = update_ul_scheduler[i]; + } + } + else { + + if (n_active_slices_uplink == n_active_slices_current_uplink){ + LOG_W(MAC,"[eNB %d][SLICE %d][UL] invalid total RB share (%f->%f), reduce proportionally the RB share by 0.1\n", + mod_id,i, + total_slice_percentage_current_uplink, total_slice_percentage_uplink); + if (slice_percentage_uplink[i] > avg_slice_percentage_uplink){ + slice_percentage_uplink[i]-=0.1; + total_slice_percentage_uplink-=0.1; + } + } else { + // here we can correct the values, e.g. reduce proportionally + LOG_W(MAC,"[eNB %d][SLICE %d][UL] invalid total RB share (%f->%f), revert the number of slice to its previous value (%d->%d)\n", + mod_id,i, + total_slice_percentage_current_uplink, total_slice_percentage_uplink, + n_active_slices_uplink, n_active_slices_current_uplink); + n_active_slices_uplink = n_active_slices_current_uplink; + slice_percentage_uplink[i] = slice_percentage_current_uplink[i]; + } + } + + // Run each enabled slice-specific schedulers one by one + slice_sched_ul[i](module_idP, i,frameP, subframeP, sched_subframe, + first_rb); + } + stop_meas(&mac->schedule_ulsch); } void schedule_ulsch_rnti(module_id_t module_idP, + slice_id_t slice_id, frame_t frameP, sub_frame_t subframeP, unsigned char sched_subframeP, uint16_t * first_rb) @@ -1081,7 +1223,7 @@ schedule_ulsch_rnti(module_id_t module_idP, &mac->UL_req_tmp[CC_id][sched_subframeP].ul_config_request_body; LOG_D(MAC, "entering ulsch preprocesor\n"); - ulsch_scheduler_pre_processor(module_idP, frameP, subframeP, first_rb); + ulsch_scheduler_pre_processor(module_idP, slice_id, frameP, subframeP, first_rb); LOG_D(MAC, "exiting ulsch preprocesor\n"); @@ -1115,7 +1257,6 @@ schedule_ulsch_rnti(module_id_t module_idP, for (n=0; nnumactiveULCCs[UE_id]; n++) { CC_id = UE_list->ordered_ULCCids[n][UE_id]; -<<<<<<< HEAD if (mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti) == NULL) { LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: no PHY context\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id); drop_ue = 1; @@ -1142,111 +1283,6 @@ schedule_ulsch_rnti(module_id_t module_idP, subframeP, rnti); UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 1; -======= - // loop over all active UL CC_ids for this UE - for (n=0; nnumactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - frame_parms = mac_xface->get_lte_frame_parms(module_idP,CC_id); - eNB_UE_stats = mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti); - - aggregation=get_aggregation(get_bw_index(module_idP,CC_id), - eNB_UE_stats->DL_cqi[0], - format0); - - if (CCE_allocation_infeasible(module_idP,CC_id,0,subframeP,aggregation,rnti)) { - LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: not enough nCCE\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id); - continue; // break; - } else{ - LOG_D(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d mode %s: aggregation level %d\n", - module_idP,frameP,subframeP,UE_id,rnti,CC_id, mode_string[eNB_UE_stats->mode], 1<mode == PUSCH) { // ue has a ulsch channel - - DCI_pdu = &eNB->common_channels[CC_id].DCI_pdu; - UE_template = &UE_list->UE_template[CC_id][UE_id]; - UE_sched_ctrl = &UE_list->UE_sched_ctrl[UE_id]; - - if (mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL) == -1 ) { - LOG_W(MAC,"[eNB %d] Scheduler Frame %d, subframeP %d: candidate harq_pid from PHY for UE %d CC %d RNTI %x\n", - module_idP,frameP,subframeP, UE_id, CC_id, rnti); - continue; - } else - LOG_T(MAC,"[eNB %d] Frame %d, subframeP %d, UE %d CC %d : got harq pid %d round %d (rnti %x,mode %s)\n", - module_idP,frameP,subframeP,UE_id,CC_id, harq_pid, round,rnti,mode_string[eNB_UE_stats->mode]); - - PHY_vars_eNB_g[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP*10)+subframeP] = UE_template->ul_total_buffer; - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BO,PHY_vars_eNB_g[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP*10)+subframeP]); - if (((UE_is_to_be_scheduled(module_idP,CC_id,UE_id)>0)) || (round>0))// || ((frameP%10)==0)) - // if there is information on bsr of DCCH, DTCH or if there is UL_SR, or if there is a packet to retransmit, or we want to schedule a periodic feedback every 10 frames - { - LOG_D(MAC,"[eNB %d][PUSCH] Frame %d subframe %d Scheduling UE %d/%x in round %d(SR %d,UL_inactivity timer %d,UL_failure timer %d)\n", - module_idP,frameP,subframeP,UE_id,rnti,round,UE_template->ul_SR, - UE_sched_ctrl->ul_inactivity_timer, - UE_sched_ctrl->ul_failure_timer); - // reset the scheduling request - UE_template->ul_SR = 0; - status = mac_eNB_get_rrc_status(module_idP,rnti); - if (status < RRC_CONNECTED) - cqi_req = 0; - else if (UE_sched_ctrl->cqi_req_timer>30) { - cqi_req = 1; - UE_sched_ctrl->cqi_req_timer=0; - } - else - cqi_req = 0; - - //power control - //compute the expected ULSCH RX power (for the stats) - - // this is the normalized RX power and this should be constant (regardless of mcs - normalized_rx_power = eNB_UE_stats->UL_rssi[0]; - target_rx_power = mac_xface->get_target_pusch_rx_power(module_idP,CC_id); - - // this assumes accumulated tpc - // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out - int32_t framex10psubframe = UE_template->pusch_tpc_tx_frame*10+UE_template->pusch_tpc_tx_subframe; - if (((framex10psubframe+10)<=(frameP*10+subframeP)) || //normal case - ((framex10psubframe>(frameP*10+subframeP)) && (((10240-framex10psubframe+frameP*10+subframeP)>=10)))) //frame wrap-around - { - UE_template->pusch_tpc_tx_frame=frameP; - UE_template->pusch_tpc_tx_subframe=subframeP; - if (normalized_rx_power>(target_rx_power+1)) { - tpc = 0; //-1 - tpc_accumulated--; - } else if (normalized_rx_power<(target_rx_power-1)) { - tpc = 2; //+1 - tpc_accumulated++; - } else { - tpc = 1; //0 - } - } else { - tpc = 1; //0 - } - - if (tpc!=1) { - LOG_D(MAC,"[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", - module_idP,frameP,subframeP,harq_pid,tpc, - tpc_accumulated,normalized_rx_power,target_rx_power); - } - - // new transmission - if (round==0) { - - ndi = 1-UE_template->oldNDI_UL[harq_pid]; - UE_template->oldNDI_UL[harq_pid]=ndi; - UE_list->eNB_UE_stats[CC_id][UE_id].normalized_rx_power=normalized_rx_power; - UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power=target_rx_power; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=UE_template->pre_assigned_mcs_ul; - mcs = UE_template->pre_assigned_mcs_ul;//cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS - if (UE_template->pre_allocated_rb_table_index_ul >=0) { - rb_table_index=UE_template->pre_allocated_rb_table_index_ul; - } else { - mcs=10;//cmin (10, openair_daq_vars.target_ue_ul_mcs); - rb_table_index=13; // for PHR ->>>>>>> feature-68-enb-agent } continue; } diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index a988862542..6445fa0845 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -578,7 +578,7 @@ _dlsch_scheduler_pre_processor(module_id_t Mod_id, if (!phy_stats_exist(Mod_id, rnti)) continue; - for (ii=0; ii < UE_num_active_CC(UE_list,UE_id); ii++) { + for (ii=0; ii < UE_num_active_CC(UE_list,UE_id); ii++) { CC_id = UE_list->ordered_CCids[ii][UE_id]; ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; ue_sched_ctl->max_allowed_rbs[CC_id]=nb_rbs_allowed_slice[CC_id][slice_id]; diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 23d3f3bd60..a0cc0dd412 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -96,7 +96,7 @@ int phy_stats_exist(module_id_t Mod_id, int rnti) // This function stores the downlink buffer for all the logical channels void -store_dlsch_buffer(module_id_t Mod_id, frame_t frameP, +store_dlsch_buffer(module_id_t Mod_id, slice_id_t slice_id, frame_t frameP, sub_frame_t subframeP) { @@ -110,6 +110,9 @@ store_dlsch_buffer(module_id_t Mod_id, frame_t frameP, if (UE_list->active[UE_id] != TRUE) continue; + if (flexran_slice_member(UE_id, slice_id) == 0) + continue; + UE_template = &UE_list->UE_template[UE_PCCID(Mod_id, UE_id)][UE_id]; @@ -153,8 +156,8 @@ store_dlsch_buffer(module_id_t Mod_id, frame_t frameP, */ if (UE_template->dl_buffer_info[i] > 0) LOG_D(MAC, - "[eNB %d] Frame %d Subframe %d : RLC status for UE %d in LCID%d: total of %d pdus and size %d, head sdu queuing time %d, remaining size %d, is segmeneted %d \n", - Mod_id, frameP, subframeP, UE_id, + "[eNB %d][SLICE %d] Frame %d Subframe %d : RLC status for UE %d in LCID%d: total of %d pdus and size %d, head sdu queuing time %d, remaining size %d, is segmeneted %d \n", + Mod_id, slice_id, frameP, subframeP, UE_id, i, UE_template->dl_pdus_in_buffer[i], UE_template->dl_buffer_info[i], UE_template->dl_buffer_head_sdu_creation_time[i], @@ -182,6 +185,7 @@ store_dlsch_buffer(module_id_t Mod_id, frame_t frameP, // This function returns the estimated number of RBs required by each UE for downlink scheduling void assign_rbs_required(module_id_t Mod_id, + slice_id_t slice_id, frame_t frameP, sub_frame_t subframe, uint16_t @@ -200,7 +204,8 @@ assign_rbs_required(module_id_t Mod_id, for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { if (UE_list->active[UE_id] != TRUE) continue; - + if (flexran_slice_member(UE_id, slice_id) == 0) + continue; pCCid = UE_PCCID(Mod_id, UE_id); //update CQI information across component carriers @@ -262,16 +267,18 @@ assign_rbs_required(module_id_t Mod_id, to_prb(RC.mac[Mod_id]->common_channels[CC_id]. mib->message.dl_Bandwidth); + UE_list->ue_sched_ctl.max_allowed_rbs[CC_id][slice_id]= flexran_nb_rbs_allowed_slice(slice_percentage[slice_id],N_RB_DL); + /* calculating required number of RBs for each UE */ while (TBS < UE_list->UE_template[pCCid][UE_id]. dl_buffer_total) { nb_rbs_required[CC_id][UE_id] += min_rb_unit[CC_id]; - if (nb_rbs_required[CC_id][UE_id] > N_RB_DL) { + if (nb_rbs_required[CC_id][UE_id] > UE_list->ue_sched_ctl.max_allowed_rbs[CC_id][slice_id]) { TBS = - get_TBS_DL(eNB_UE_stats->dlsch_mcs1, N_RB_DL); - nb_rbs_required[CC_id][UE_id] = N_RB_DL; + get_TBS_DL(eNB_UE_stats->dlsch_mcs1, UE_list->ue_sched_ctl.max_allowed_rbs[CC_id][slice_id]); + nb_rbs_required[CC_id][UE_id] = UE_list->ue_sched_ctl.max_allowed_rbs[CC_id][slice_id]; break; } @@ -556,13 +563,14 @@ void sort_UEs(module_id_t Mod_idP, int frameP, sub_frame_t subframeP) // This function assigns pre-available RBS to each UE in specified sub-bands before scheduling is done void dlsch_scheduler_pre_processor(module_id_t Mod_id, + slice_id_t slice_id, frame_t frameP, sub_frame_t subframeP, int N_RBG[MAX_NUM_CCs], int *mbsfn_flag) { unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], harq_pid = - 0, round = 0, total_ue_count; + 0, round = 0, total_ue_count[MAX_NUM_CCs], total_rbs_used[MAX_NUM_CCs]; unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]; int UE_id, i; uint16_t ii, j; @@ -619,6 +627,8 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, N_RBG[CC_id], nb_rbs_required, nb_rbs_required_remaining, + total_ue_count, + total_rbs_used, rballoc_sub, MIMO_mode_indicator); @@ -627,12 +637,12 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, // Store the DLSCH buffer for each logical channel - store_dlsch_buffer(Mod_id, frameP, subframeP); + store_dlsch_buffer(Mod_id, slice_id,frameP, subframeP); // Calculate the number of RBs required by each UE on the basis of logical channel's buffer - assign_rbs_required(Mod_id, frameP, subframeP, nb_rbs_required, + assign_rbs_required(Mod_id, slice_id, frameP, subframeP, nb_rbs_required, min_rb_unit); @@ -641,65 +651,89 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, sort_UEs(Mod_id, frameP, subframeP); - - total_ue_count = 0; - // loop over all active UEs for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { - rnti = UE_RNTI(Mod_id, i); + rnti = UE_RNTI(Mod_id, i); - if (rnti == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - UE_id = i; + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + UE_id = i; + if (flexran_slice_member(UE_id, slice_id) == 0) + continue; - for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { - CC_id = UE_list->ordered_CCids[ii][UE_id]; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - cc = &RC.mac[Mod_id]->common_channels[ii]; - if (cc->tdd_Config) - harq_pid = ((frameP * 10) + subframeP) % 10; - else - harq_pid = ((frameP * 10) + subframeP) & 7; - round = ue_sched_ctl->round[CC_id][harq_pid]; + for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { + CC_id = UE_list->ordered_CCids[ii][UE_id]; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + cc = &RC.mac[Mod_id]->common_channels[ii]; + if (cc->tdd_Config) + harq_pid = ((frameP * 10) + subframeP) % 10; + else + harq_pid = ((frameP * 10) + subframeP) & 7; + round = ue_sched_ctl->round[CC_id][harq_pid]; - average_rbs_per_user[CC_id] = 0; + average_rbs_per_user[CC_id] = 0; - if (round != 8) { - nb_rbs_required[CC_id][UE_id] = - UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - } - //nb_rbs_required_remaining[UE_id] = nb_rbs_required[UE_id]; - if (nb_rbs_required[CC_id][UE_id] > 0) { - total_ue_count = total_ue_count + 1; - } - // hypothetical assignment - /* - * If schedule is enabled and if the priority of the UEs is modified - * The average rbs per logical channel per user will depend on the level of - * priority. Concerning the hypothetical assignement, we should assign more - * rbs to prioritized users. Maybe, we can do a mapping between the - * average rbs per user and the level of priority or multiply the average rbs - * per user by a coefficient which represents the degree of priority. - */ + if (round != 8) { + nb_rbs_required[CC_id][UE_id] = + UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + total_rbs_used[CC_id]+=nb_rbs_required[CC_id][UE_id]; + } - N_RB_DL = - to_prb(RC.mac[Mod_id]->common_channels[CC_id].mib-> - message.dl_Bandwidth); + //nb_rbs_required_remaining[UE_id] = nb_rbs_required[UE_id]; + if (nb_rbs_required[CC_id][UE_id] > 0) { + total_ue_count[CC_id] = total_ue_count[CC_id] + 1; + } - if (total_ue_count == 0) { - average_rbs_per_user[CC_id] = 0; - } else if ((min_rb_unit[CC_id] * total_ue_count) <= (N_RB_DL)) { - average_rbs_per_user[CC_id] = - (uint16_t) floor(N_RB_DL / total_ue_count); - } else { - average_rbs_per_user[CC_id] = min_rb_unit[CC_id]; // consider the total number of use that can be scheduled UE - } - } + } } + // loop over all active UEs and calculate avg rb per user based on total active UEs + for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { + rnti = UE_RNTI(Mod_id, i); + + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + UE_id = i; + if (flexran_slice_member(UE_id, slice_id) == 0) + continue; + + for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { + CC_id = UE_list->ordered_CCids[ii][UE_id]; + + // hypothetical assignment + /* + * If schedule is enabled and if the priority of the UEs is modified + * The average rbs per logical channel per user will depend on the level of + * priority. Concerning the hypothetical assignement, we should assign more + * rbs to prioritized users. Maybe, we can do a mapping between the + * average rbs per user and the level of priority or multiply the average rbs + * per user by a coefficient which represents the degree of priority. + */ + + + N_RB_DL = + to_prb(RC.mac[Mod_id]->common_channels[CC_id].mib-> + message.dl_Bandwidth) - total_rbs_used[CC_id]; + + //recalcualte based on the what is left after retransmission + ue_sched_ctl.max_allowed_rbs[CC_id][slice_id]= flexran_nb_rbs_allowed_slice(slice_percentage[slice_id],N_RB_DL); + + if (total_ue_count[CC_id] == 0) { + average_rbs_per_user[CC_id] = 0; + } else if ((min_rb_unit[CC_id] * total_ue_count[CC_id]) <= (ue_sched_ctl.max_allowed_rbs[CC_id][slice_id])) { + average_rbs_per_user[CC_id] = + (uint16_t) floor(ue_sched_ctl.max_allowed_rbs[CC_id][slice_id] / total_ue_count[CC_id]); + } else { + average_rbs_per_user[CC_id] = min_rb_unit[CC_id]; // consider the total number of use that can be scheduled UE + } + } + } + // note: nb_rbs_required is assigned according to total_buffer_dl // extend nb_rbs_required to capture per LCID RB required for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { @@ -709,6 +743,8 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, continue; if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) continue; + if (flexran_slice_member(i, slice_id) == 0) + continue; for (ii = 0; ii < UE_num_active_CC(UE_list, i); ii++) { CC_id = UE_list->ordered_CCids[ii][i]; @@ -765,11 +801,14 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, } } - if (total_ue_count > 0) { - for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { + + for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { UE_id = i; for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { + + // if there are UEs with traffic + if (total_ue_count [CC_id] > 0) { CC_id = UE_list->ordered_CCids[ii][UE_id]; ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; round = ue_sched_ctl->round[CC_id][harq_pid]; @@ -969,9 +1008,9 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, } } #endif - } + } // total_ue_count } - } // total_ue_count + } } // end of for for r1 and r2 #ifdef TM5 @@ -1044,7 +1083,7 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, } //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = pre_nb_available_rbs[CC_id][UE_id]; - LOG_D(MAC, "Total RBs allocated for UE%d = %d\n", UE_id, + LOG_D(MAC, "[eNB %d][SLICE %d]Total RBs allocated for UE%d = %d\n", Mod_id, slice_id, UE_id, ue_sched_ctl->pre_nb_available_rbs[CC_id]); } } @@ -1065,9 +1104,12 @@ dlsch_scheduler_pre_processor_reset(int module_idP, uint16_t nb_rbs_required_remaining [MAX_NUM_CCs][NUMBER_OF_UE_MAX], + unsigned char total_ue_count[MAX_NUM_CCs], + unsigned char total_rbs_used[MAX_NUM_CCs], unsigned char rballoc_sub[MAX_NUM_CCs] - [N_RBG_MAX], unsigned char + [N_RBG_MAX], + unsigned char MIMO_mode_indicator[MAX_NUM_CCs] [N_RBG_MAX]) { @@ -1154,7 +1196,8 @@ dlsch_scheduler_pre_processor_reset(int module_idP, ue_sched_ctl->pre_nb_available_rbs[CC_id] = 0; ue_sched_ctl->dl_pow_off[CC_id] = 2; nb_rbs_required_remaining[CC_id][UE_id] = 0; - + total_ue_count[CC_id]=0; + total_rbs_used[CC_id]=0; switch (N_RB_DL) { case 6: RBGsize = 1; @@ -1322,7 +1365,7 @@ dlsch_scheduler_pre_processor_allocate(module_id_t Mod_id, void ulsch_scheduler_pre_processor(module_id_t module_idP, - int frameP, + slice_id_t slice_id, int frameP, sub_frame_t subframeP, uint16_t * first_rb) { @@ -1538,7 +1581,7 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, void -assign_max_mcs_min_rb(module_id_t module_idP, int frameP, +assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, sub_frame_t subframeP, uint16_t * first_rb) { diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 9f3af1b053..a83aabef27 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -102,11 +102,12 @@ void schedule_ulsch(module_id_t module_idP, frame_t frameP, /** \brief ULSCH Scheduling per RNTI @param Mod_id Instance ID of eNB +@param slice_id Instance slice for this eNB @param frame Frame index @param subframe Subframe number on which to act @param sched_subframe Subframe number where PUSCH is transmitted (for DAI lookup) */ -void schedule_ulsch_rnti(module_id_t module_idP, frame_t frameP, +void schedule_ulsch_rnti(module_id_t module_idP, slice_id_t slice_idP, frame_t frameP, sub_frame_t subframe, unsigned char sched_subframe, uint16_t * first_rb); @@ -127,9 +128,12 @@ void fill_DLSCH_dci(module_id_t module_idP, frame_t frameP, @param mbsfn_flag Indicates that MCH/MCCH is in this subframe */ -void schedule_ue_spec(module_id_t module_idP, frame_t frameP, +void schedule_dlsch(module_id_t module_idP, frame_t frameP, sub_frame_t subframe, int *mbsfn_flag); +void schedule_ue_spec(module_id_t module_idP, slice_id_t slice_idP, + frame_t frameP,sub_frame_t subframe, int *mbsfn_flag); + /** \brief Function for UE/PHY to compute PUSCH transmit power in power-control procedure. @param Mod_id Module id of UE @@ -209,6 +213,7 @@ void dlsch_scheduler_pre_processor_reset(int module_idP, int UE_id, void dlsch_scheduler_pre_processor(module_id_t module_idP, + slice_id_t slice_idP, frame_t frameP, sub_frame_t subframe, int N_RBG[MAX_NUM_CCs], @@ -633,7 +638,7 @@ int UE_PCCID(module_id_t mod_idP, int ue_idP); rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP); -void ulsch_scheduler_pre_processor(module_id_t module_idP, int frameP, +void ulsch_scheduler_pre_processor(module_id_t module_idP, slice_id_t slice_id, int frameP, sub_frame_t subframeP, uint16_t * first_rb); void store_ulsch_buffer(module_id_t module_idP, int frameP, @@ -1158,5 +1163,12 @@ int32_t get_uldl_offset(int eutra_bandP); int l2_init_ue(int eMBMS_active, char *uecap_xer, uint8_t cba_group_active, uint8_t HO_active); +/*Slice related functions */ +uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, int total_rbs); + +int flexran_slice_member(int UE_id, int slice_id); + +int flexran_slice_maxmcs(int slice_id;) + #endif /** @}*/ From 765d6370f640c23703bfe1d77e56ddd278b25c16 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 10 Jan 2018 14:22:14 +0100 Subject: [PATCH 166/284] update FlexRAN configuration definition (paramdef) --- openair2/ENB_APP/enb_paramdef.h | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/openair2/ENB_APP/enb_paramdef.h b/openair2/ENB_APP/enb_paramdef.h index 6a03687fab..36a1f2c0a7 100755 --- a/openair2/ENB_APP/enb_paramdef.h +++ b/openair2/ENB_APP/enb_paramdef.h @@ -611,18 +611,26 @@ static int DEFENBS[] = {0}; /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ -#define ENB_CONFIG_STRING_NETWORK_CONTROLLER_CONFIG "NETWORK_CONTROLLER" +#define CONFIG_STRING_NETWORK_CONTROLLER_CONFIG "NETWORK_CONTROLLER" -#define ENB_CONFIG_STRING_FLEXRAN_AGENT_INTERFACE_NAME "FLEXRAN_AGENT_INTERFACE_NAME" -#define ENB_CONFIG_STRING_FLEXRAN_AGENT_IPV4_ADDRESS "FLEXRAN_AGENT_IPV4_ADDRESS" -#define ENB_CONFIG_STRING_FLEXRAN_AGENT_PORT "FLEXRAN_AGENT_PORT" -#define ENB_CONFIG_STRING_FLEXRAN_AGENT_CACHE "FLEXRAN_AGENT_CACHE" +#define CONFIG_STRING_FLEXRAN_INTERFACE_NAME "FLEXRAN_INTERFACE_NAME" +#define CONFIG_STRING_FLEXRAN_IPV4_ADDRESS "FLEXRAN_IPV4_ADDRESS" +#define CONFIG_STRING_FLEXRAN_PORT "FLEXRAN_PORT" +#define CONFIG_STRING_FLEXRAN_CACHE "FLEXRAN_CACHE" +#define CONFIG_STRING_FLEXRAN_AWAIT_RECONF "FLEXRAN_AWAIT_RECONF" + +#define FLEXRAN_INTERFACE_NAME_IDX 0 +#define FLEXRAN_IPV4_ADDRESS_IDX 1 +#define FLEXRAN_PORT_IDX 2 +#define FLEXRAN_CACHE_IDX 3 +#define FLEXRAN_AWAIT_RECONF_IDX 4 #define FLEXRANPARAMS_DESC { \ -{ENB_CONFIG_STRING_FLEXRAN_AGENT_INTERFACE_NAME, NULL, 0, uptr:NULL, defstrval:ENB_CONFIG_STRING_ASN1_VERBOSITY_NONE, TYPE_STRING, 0}, \ -{ENB_CONFIG_STRING_FLEXRAN_AGENT_IPV4_ADDRESS, NULL, 0, uptr:NULL, defstrval:ENB_CONFIG_STRING_ASN1_VERBOSITY_NONE, TYPE_STRING, 0}, \ -{ENB_CONFIG_STRING_FLEXRAN_AGENT_PORT, NULL, 0, uptr:NULL, defstrval:ENB_CONFIG_STRING_ASN1_VERBOSITY_NONE, TYPE_STRING, 0}, \ -{ENB_CONFIG_STRING_FLEXRAN_AGENT_CACHE, NULL, 0, uptr:NULL, defstrval:ENB_CONFIG_STRING_ASN1_VERBOSITY_NONE, TYPE_STRING, 0} \ +{CONFIG_STRING_FLEXRAN_INTERFACE_NAME, NULL, 0, strptr:NULL, defstrval:"lo", TYPE_STRING, 0}, \ +{CONFIG_STRING_FLEXRAN_IPV4_ADDRESS, NULL, 0, strptr:NULL, defstrval:"127.0.0.1/30", TYPE_STRING, 0}, \ +{CONFIG_STRING_FLEXRAN_PORT, NULL, 0, uptr:NULL, defintval:2210, TYPE_UINT, 0}, \ +{CONFIG_STRING_FLEXRAN_CACHE, NULL, 0, strptr:NULL, defstrval:"/mnt/oai_agent_cache", TYPE_STRING, 0}, \ +{CONFIG_STRING_FLEXRAN_AWAIT_RECONF, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0} \ } /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ From fac968246dd4ac9806545df257e394e504a29a80 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 10 Jan 2018 17:49:39 +0100 Subject: [PATCH 167/284] define FlexRAN data in RAN context and use it - defines RCconfig data structures - adds method to read data - use it in source files --- common/ran_context.h | 7 ++ .../MAC/flexran_agent_mac_internal.c | 2 +- openair2/ENB_APP/enb_app.c | 4 +- openair2/ENB_APP/enb_config.c | 71 ++++++++++--------- openair2/ENB_APP/enb_config.h | 3 + openair2/ENB_APP/enb_paramdef.h | 2 +- openair2/ENB_APP/flexran_agent.c | 60 ++++------------ openair2/ENB_APP/flexran_agent.h | 1 - openair2/ENB_APP/flexran_agent_common.c | 4 +- openair2/ENB_APP/flexran_agent_defs.h | 23 +++--- openair2/ENB_APP/flexran_agent_extern.h | 6 +- 11 files changed, 82 insertions(+), 101 deletions(-) diff --git a/common/ran_context.h b/common/ran_context.h index 4e25729c86..d5e2a1f172 100644 --- a/common/ran_context.h +++ b/common/ran_context.h @@ -40,6 +40,9 @@ #include "PHY/impl_defs_top.h" #include "PHY/impl_defs_lte.h" #include "RRC/LITE/defs.h" +#ifdef FLEXRAN_AGENT_SB_IF +#include "flexran_agent_defs.h" +#endif #include "gtpv1u.h" #include "NwGtpv1u.h" @@ -64,6 +67,10 @@ typedef struct { int *nb_L1_CC; /// Number of RU instances in this node int nb_RU; +#ifdef FLEXRAN_AGENT_SB_IF + /// FlexRAN context variables + flexran_agent_info_t **flexran; +#endif /// eNB context variables struct PHY_VARS_eNB_s ***eNB; /// RRC context variables diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c index 7239ca8233..2af6514ef6 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c @@ -869,7 +869,7 @@ int load_dl_scheduler_function(mid_t mod_id, const char *function_name) { char lib_name[120]; char target[512]; snprintf(lib_name, sizeof(lib_name), "/%s.so", function_name); - strcpy(target, local_cache); + strcpy(target, RC.flexran[mod_id]->cache_name); strcat(target, lib_name); LOG_I(FLEXRAN_AGENT, "Opening pushed code: %s\n", target); diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index bd9be082c2..636df458ae 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -343,8 +343,8 @@ void *eNB_app_task(void *args_p) enb_app_start_phy_rrc(enb_id_start, enb_id_end); #ifdef FLEXRAN_AGENT_SB_IF - for (enb_i = 0; enb_i <1; enb_i ++){ // To be handled for all of current eNB - flexran_set_enb_vars(enb_i, RAN_LTE_OAI); + for (uint32_t enb_i = 0; enb_i <1; enb_i ++){ // To be handled for all of current eNB + flexran_set_RC_vars(enb_i, RAN_LTE_OAI); } #endif diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index f2f89ad1ca..d2a35c3bd7 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -237,6 +237,44 @@ void RCconfig_RU(void) { } +#ifdef FLEXRAN_AGENT_SB_IF +void RCconfig_flexran() +{ + int i; + + paramdef_t flexranParams[] = FLEXRANPARAMS_DESC; + config_get(flexranParams, sizeof(flexranParams)/sizeof(paramdef_t), CONFIG_STRING_NETWORK_CONTROLLER_CONFIG); + + if (!RC.flexran) { + RC.flexran = calloc(RC.nb_L1_inst, sizeof(flexran_agent_info_t*)); + AssertFatal(RC.flexran != NULL, + "can't ALLOCATE %zu Bytes for %d flexran agent info with size %zu\n", + RC.nb_L1_inst * sizeof(flexran_agent_info_t*), + RC.nb_L1_inst, sizeof(flexran_agent_info_t*)); + } + + /* For all agent instance, fill in the same controller configuration. */ + for (i = 0; i < RC.nb_L1_inst; i++) { + RC.flexran[i] = calloc(1, sizeof(flexran_agent_info_t)); + AssertFatal(RC.flexran[i] != NULL, + "can't ALLOCATE %zu Bytes for flexran agent info (iteration %d/%d)\n", + sizeof(flexran_agent_info_t), i + 1, RC.nb_L1_inst); + RC.flexran[i]->interface_name = strdup(*(flexranParams[FLEXRAN_INTERFACE_NAME_IDX].strptr)); + //inet_ntop(AF_INET, &(enb_properties->properties[mod_id]->flexran_agent_ipv4_address), in_ip, INET_ADDRSTRLEN); + //strcpy(in_ip, DEFAULT_FLEXRAN_AGENT_IPv4_ADDRESS ); + RC.flexran[i]->remote_ipv4_addr = strdup(*(flexranParams[FLEXRAN_IPV4_ADDRESS_IDX].strptr)); + // DEFAULT_FLEXRAN_AGENT_PORT + RC.flexran[i]->remote_port = *(flexranParams[FLEXRAN_PORT_IDX].uptr); + // DEFAULT_FLEXRAN_AGENT_CACHE + RC.flexran[i]->cache_name = strdup(*(flexranParams[FLEXRAN_CACHE_IDX].strptr)); + RC.flexran[i]->await_reconf = strcmp(*(flexranParams[FLEXRAN_AWAIT_RECONF_IDX].strptr), "yes") == 0; + RC.flexran[i]->enb_id = i; + } + + /* TODO: show FlexRAN config now? */ +} +#endif + void RCconfig_L1() { int i,j; paramdef_t L1_Params[] = L1PARAMS_DESC; @@ -451,10 +489,6 @@ int RCconfig_RRC(MessageDef *msg_p, uint32_t i, eNB_RRC_INST *rrc) { /* - char* flexran_agent_interface_name = NULL; - char* flexran_agent_ipv4_address = NULL; - int32_t flexran_agent_port = 0; - char* flexran_agent_cache = NULL; int32_t otg_ue_id = 0; char* otg_app_type = NULL; char* otg_bg_traffic = NULL; @@ -2028,35 +2062,6 @@ int RCconfig_RRC(MessageDef *msg_p, uint32_t i, eNB_RRC_INST *rrc) { rrc->srb1_poll_byte = PollByte_kBinfinity; rrc->srb1_max_retx_threshold = UL_AM_RLC__maxRetxThreshold_t8; } - /* - // Network Controller - subsetting = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_NETWORK_CONTROLLER_CONFIG); - - if (subsetting != NULL) { - if ( ( - config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_FLEXRAN_AGENT_INTERFACE_NAME, - (const char **)&flexran_agent_interface_name) - && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_FLEXRAN_AGENT_IPV4_ADDRESS, - (const char **)&flexran_agent_ipv4_address) - && config_setting_lookup_int(subsetting, ENB_CONFIG_STRING_FLEXRAN_AGENT_PORT, - &flexran_agent_port) - && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_FLEXRAN_AGENT_CACHE, - (const char **)&flexran_agent_cache) - ) - ) { - enb_properties_loc.properties[enb_properties_loc_index]->flexran_agent_interface_name = strdup(flexran_agent_interface_name); - cidr = flexran_agent_ipv4_address; - address = strtok(cidr, "/"); - //enb_properties_loc.properties[enb_properties_loc_index]->flexran_agent_ipv4_address = strdup(address); - if (address) { - IPV4_STR_ADDR_TO_INT_NWBO (address, enb_properties_loc.properties[enb_properties_loc_index]->flexran_agent_ipv4_address, "BAD IP ADDRESS FORMAT FOR eNB Agent !\n" ); - } - - enb_properties_loc.properties[enb_properties_loc_index]->flexran_agent_port = flexran_agent_port; - enb_properties_loc.properties[enb_properties_loc_index]->flexran_agent_cache = strdup(flexran_agent_cache); - } - } - */ /* // OTG _CONFIG diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h index 0406e11e4c..4e4434ad70 100644 --- a/openair2/ENB_APP/enb_config.h +++ b/openair2/ENB_APP/enb_config.h @@ -94,6 +94,9 @@ typedef struct ru_config_s { } ru_config_t; extern void RCconfig_RU(void); +#ifdef FLEXRAN_AGENT_SB_IF +extern void RCconfig_flexran(void); +#endif extern void RCconfig_L1(void); extern void RCconfig_macrlc(void); extern int RCconfig_gtpu(void ); diff --git a/openair2/ENB_APP/enb_paramdef.h b/openair2/ENB_APP/enb_paramdef.h index 36a1f2c0a7..0203380314 100755 --- a/openair2/ENB_APP/enb_paramdef.h +++ b/openair2/ENB_APP/enb_paramdef.h @@ -627,7 +627,7 @@ static int DEFENBS[] = {0}; #define FLEXRANPARAMS_DESC { \ {CONFIG_STRING_FLEXRAN_INTERFACE_NAME, NULL, 0, strptr:NULL, defstrval:"lo", TYPE_STRING, 0}, \ -{CONFIG_STRING_FLEXRAN_IPV4_ADDRESS, NULL, 0, strptr:NULL, defstrval:"127.0.0.1/30", TYPE_STRING, 0}, \ +{CONFIG_STRING_FLEXRAN_IPV4_ADDRESS, NULL, 0, strptr:NULL, defstrval:"127.0.0.1", TYPE_STRING, 0}, \ {CONFIG_STRING_FLEXRAN_PORT, NULL, 0, uptr:NULL, defintval:2210, TYPE_UINT, 0}, \ {CONFIG_STRING_FLEXRAN_CACHE, NULL, 0, strptr:NULL, defstrval:"/mnt/oai_agent_cache", TYPE_STRING, 0}, \ {CONFIG_STRING_FLEXRAN_AWAIT_RECONF, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0} \ diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c index 530cb81042..60239cbbbd 100644 --- a/openair2/ENB_APP/flexran_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -30,15 +30,6 @@ #include - -//#define TEST_TIMER - -flexran_agent_instance_t flexran_agent[NUM_MAX_ENB]; - -char in_ip[40]; -static uint16_t in_port; -char local_cache[40]; - void *send_thread(void *args); void *receive_thread(void *args); pthread_t new_thread(void *(*f)(void *), void *b); @@ -52,7 +43,7 @@ int agent_task_created = 0; */ void *flexran_agent_task(void *args){ - //flexran_agent_instance_t *d = (flexran_agent_instance_t *) args; + //flexran_agent_info_t *d = (flexran_agent_info_t *) args; Protocol__FlexranMessage *msg; void *data; int size; @@ -113,7 +104,7 @@ void *flexran_agent_task(void *args){ void *receive_thread(void *args) { - flexran_agent_instance_t *d = args; + flexran_agent_info_t *d = args; void *data; int size; int priority; @@ -186,46 +177,19 @@ pthread_t new_thread(void *(*f)(void *), void *b) { return t; } -void flexran_agent_reconfigure(mid_t mod_id){ - Enb_properties_array_t *enb_properties = enb_config_get(); - - /* - * check the configuration - */ - if (enb_properties->properties[mod_id]->flexran_agent_cache != NULL) { - strncpy(local_cache, enb_properties->properties[mod_id]->flexran_agent_cache, sizeof(local_cache)); - local_cache[sizeof(local_cache) - 1] = 0; - } else { - strcpy(local_cache, DEFAULT_FLEXRAN_AGENT_CACHE); - } - - if (enb_properties->properties[mod_id]->flexran_agent_ipv4_address != 0) { - inet_ntop(AF_INET, &(enb_properties->properties[mod_id]->flexran_agent_ipv4_address), in_ip, INET_ADDRSTRLEN); - } else { - strcpy(in_ip, DEFAULT_FLEXRAN_AGENT_IPv4_ADDRESS ); - } - - if (enb_properties->properties[mod_id]->flexran_agent_port != 0 ) { - in_port = enb_properties->properties[mod_id]->flexran_agent_port; - } else { - in_port = DEFAULT_FLEXRAN_AGENT_PORT ; - } - LOG_I(FLEXRAN_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n", - flexran_agent[mod_id].enb_id, - in_ip, - in_port); - -} - int channel_container_init = 0; int flexran_agent_start(mid_t mod_id) { int channel_id; + char *in_ip = RC.flexran[mod_id]->remote_ipv4_addr; + uint16_t in_port = RC.flexran[mod_id]->remote_port; - flexran_set_enb_vars(mod_id, RAN_LTE_OAI); - flexran_agent[mod_id].enb_id = mod_id; - - flexran_agent_reconfigure(mod_id); + RC.flexran[mod_id]->enb_id = mod_id; + /* assume for the moment the monolithic case, i.e. agent can provide + * information for all layers */ + RC.flexran[mod_id]->capability_mask = FLEXRAN_CAP_LOL1 | FLEXRAN_CAP_HIL1 + | FLEXRAN_CAP_LOL2 | FLEXRAN_CAP_HIL2 + | FLEXRAN_CAP_PDCP | FLEXRAN_CAP_RRC; /* * Initialize the channel container @@ -264,7 +228,7 @@ int flexran_agent_start(mid_t mod_id) /*Initialize the continuous stats update mechanism*/ flexran_agent_init_cont_stats_update(mod_id); - new_thread(receive_thread, &flexran_agent[mod_id]); + new_thread(receive_thread, RC.flexran[mod_id]); /*Initialize and register the mac xface. Must be modified later *for more flexibility in agent management */ @@ -293,7 +257,7 @@ int flexran_agent_start(mid_t mod_id) * start the enb agent task for tx and interaction with the underlying network function */ if (!agent_task_created) { - if (itti_create_task (TASK_FLEXRAN_AGENT, flexran_agent_task, (void *) &flexran_agent[mod_id]) < 0) { + if (itti_create_task (TASK_FLEXRAN_AGENT, flexran_agent_task, (void *) RC.flexran[mod_id]) < 0) { LOG_E(FLEXRAN_AGENT, "Create task for FlexRAN Agent failed\n"); return -1; } diff --git a/openair2/ENB_APP/flexran_agent.h b/openair2/ENB_APP/flexran_agent.h index f3f71c0631..ed9ee444c3 100644 --- a/openair2/ENB_APP/flexran_agent.h +++ b/openair2/ENB_APP/flexran_agent.h @@ -48,7 +48,6 @@ /* Initiation and termination of the eNodeB agent */ int flexran_agent_start(mid_t mod_id); int flexran_agent_stop(mid_t mod_id); -void flexran_agent_reconfigure(mid_t mod_id); /* * enb agent task mainly wakes up the tx thread for periodic and oneshot messages to the controller diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index b69ddf35cd..00aa7e9263 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -391,7 +391,7 @@ int flexran_agent_control_delegation(mid_t mod_id, const void *params, Protocol_ char lib_name[120]; char target[512]; snprintf(lib_name, sizeof(lib_name), "/%s.so", control_delegation_msg->name); - strcpy(target, local_cache); + strcpy(target, RC.flexran[mod_id]->cache_name); strcat(target, lib_name); FILE *f; @@ -1075,7 +1075,7 @@ int flexran_agent_rrc_measurement(mid_t mod_id, const void *params, Protocol__Fl struct rrc_eNB_ue_context_s *ue_context_p = NULL; - RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(eNB_rrc_inst[mod_id].rrc_ue_head)){ + RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(RC.rrc[mod_id]->rrc_ue_head)){ PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, mod_id, ENB_FLAG_YES, ue_context_p->ue_context.rnti, flexran_get_current_frame(mod_id), flexran_get_current_subframe (mod_id), mod_id); diff --git a/openair2/ENB_APP/flexran_agent_defs.h b/openair2/ENB_APP/flexran_agent_defs.h index 2de19e59aa..dc86a422c4 100644 --- a/openair2/ENB_APP/flexran_agent_defs.h +++ b/openair2/ENB_APP/flexran_agent_defs.h @@ -138,11 +138,24 @@ typedef enum { FLEXRAN_AGENT_TIMER_STATE_MAX, } flexran_agent_timer_state_t; - +#define FLEXRAN_CAP_LOL1 0x1 +#define FLEXRAN_CAP_HIL1 0x2 +#define FLEXRAN_CAP_LOL2 0x4 // is: MAC +#define FLEXRAN_CAP_HIL2 0x8 // is: RLC +#define FLEXRAN_CAP_PDCP 0x16 +#define FLEXRAN_CAP_RRC 0x32 typedef struct { /* general info */ - + char *interface_name; + char *remote_ipv4_addr; + uint16_t remote_port; + char *cache_name; + uint8_t await_reconf; + + int enb_id; + uint8_t capability_mask; + /* stats */ uint32_t total_rx_msg; @@ -200,10 +213,4 @@ typedef struct stats_request_config_s{ report_config_t *config; } stats_request_config_t; -typedef struct { - mid_t enb_id; - flexran_agent_info_t agent_info; - -} flexran_agent_instance_t; - #endif diff --git a/openair2/ENB_APP/flexran_agent_extern.h b/openair2/ENB_APP/flexran_agent_extern.h index 8e9fef383d..589975b310 100644 --- a/openair2/ENB_APP/flexran_agent_extern.h +++ b/openair2/ENB_APP/flexran_agent_extern.h @@ -34,11 +34,7 @@ #include "flexran_agent_mac_defs.h" #include "flexran_agent_rrc_defs.h" #include "flexran_agent_pdcp_defs.h" - -//extern msg_context_t shared_ctxt[NUM_MAX_ENB][FLEXRAN_AGENT_MAX]; - -/* full path of the local cache for storing VSFs */ -extern char local_cache[40]; +#include "common/ran_context.h" /* Control module interface for the communication of the MAC Control Module with the agent */ extern AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB]; From ab3f9dad492e11c9730e911e7876984b86a76c26 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 10 Jan 2018 15:52:02 +0100 Subject: [PATCH 168/284] add flexran sample config --- .../CONF/enb.band7.tm1.50PRB.usrpb210.conf | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf index ff302811e9..b35b6147cd 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf @@ -189,6 +189,15 @@ RUs = ( } ); +NETWORK_CONTROLLER : +{ + FLEXRAN_INTERFACE_NAME = "lo"; + FLEXRAN_IPV4_ADDRESS = "127.0.0.1"; + FLEXRAN_PORT = 2210; + FLEXRAN_CACHE = "/mnt/oai_agent_cache"; + FLEXRAN_AWAIT_RECONF = "no"; +}; + log_config : { global_log_level ="info"; From 6198a673f040e4c5f19005786a61942793ecbc8f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 11 Jan 2018 15:14:40 +0100 Subject: [PATCH 169/284] correctly instantiate flexran agent --- targets/RT/USER/lte-softmodem.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index ed1e708689..315eee23cd 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1268,7 +1268,9 @@ int main( int argc, char **argv ) pthread_mutex_init(&mutex_node_ctrl, NULL); pthread_cond_init(&cond_node_ctrl, NULL); - for (i = 0; i < NB_eNB_INST; i++) { + /* create RC.flexran data structure */ + RCconfig_flexran(); + for (i = 0; i < RC.nb_L1_inst; i++) { flexran_agent_start(i); } @@ -1279,11 +1281,12 @@ int main( int argc, char **argv ) pthread_mutex_unlock(&mutex_node_ctrl); /* reconfigure eNB in case FlexRAN controller applied changes */ - for (i=0; i < NB_eNB_INST; i++){ - LOG_I(ENB_APP, "Reconfigure eNB module %d and FlexRAN eNB variables\n", i); - reconfigure_enb_params(i); - flexran_set_enb_vars(i, RAN_LTE_OAI); - } + /* TODO needs to be done? */ + //for (i=0; i < NB_eNB_INST; i++){ + // LOG_I(ENB_APP, "Reconfigure eNB module %d and FlexRAN eNB variables\n", i); + // reconfigure_enb_params(i); + // flexran_set_enb_vars(i, RAN_LTE_OAI); + //} #endif if (UE_flag==1) { From ceb4edf7e6e210c4b569c0f1ea8519427eaacd36 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 25 Jan 2018 08:53:40 +0100 Subject: [PATCH 170/284] minor changes --- targets/SIMU/USER/oaisim_functions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index 8a21acc442..ca137aed4c 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -1121,7 +1121,7 @@ int UE_trx_read(openair0_device *device, openair0_timestamp *ptimestamp, void ** *ptimestamp = last_UE_rx_timestamp[UE_id][CC_id]; - LOG_I(EMU,"UE %d DL simulation 0: UE_trx_read nsamps %d TS %llu (%llu, offset %d) antenna %d\n", + LOG_D(EMU,"UE %d DL simulation 0: UE_trx_read nsamps %d TS %llu (%llu, offset %d) antenna %d\n", UE_id, nsamps, (unsigned long long)current_UE_rx_timestamp[UE_id][CC_id], From fe1912a19326ad9c8628e042970e7f82e2a69935 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 25 Jan 2018 06:54:01 -0800 Subject: [PATCH 171/284] correcting issues after merge with develop --- cmake_targets/CMakeLists.txt | 1 - openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 2 - openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 5 +- openair2/RRC/LITE/rrc_common.c | 107 ++++++++++++++++++++++ openair2/RRC/LITE/rrc_eNB.c | 106 --------------------- 5 files changed, 110 insertions(+), 111 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 2233988829..616adf3a82 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -2099,7 +2099,6 @@ add_executable(oaisim_nos1 ${OPENAIR_BIN_DIR}/messages_xml.h ${OPENAIR_TARGETS}/RT/USER/lte-ue.c ${OPENAIR_TARGETS}/RT/USER/lte-ru.c - ${OPENAIR_TARGETS}/RT/USER/lte-enb.c ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c ${OPENAIR_TARGETS}/SIMU/USER/channel_sim.c ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 2cea7ec240..9f2ab1cba8 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -1830,8 +1830,6 @@ void schedule_PCH(module_id_t module_idP,frame_t frameP,sub_frame_t subframeP) frameP, PCCH,1, &cc->PCCH_pdu.payload[0], - 1, - module_idP, i); // used for ue index if (pcch_sdu_length == 0) { LOG_D(MAC,"[eNB %d] Frame %d subframe %d: PCCH not active(size = 0 byte)\n", module_idP,frameP, subframeP); diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index eb060e8535..e9d2188bfb 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -792,9 +792,9 @@ void pdcp_fifo_read_input_sdus_from_otg (const protocol_ctxt_t* const ctxt_pP) for (dst_id = 0; dst_id 2 /*RRC_SI_RECEIVED*/) { + if (mac_eNB_get_rrc_status(ctxt.module_id, ctxt.rnti ) > 2 ) { unsigned int temp = 0; otg_pkt=packet_gen( ENB_MODULE_ID_TO_INSTANCE(ctxt.module_id), @@ -821,6 +821,7 @@ void pdcp_fifo_read_input_sdus_from_otg (const protocol_ctxt_t* const ctxt_pP) } } } +*/ } } } diff --git a/openair2/RRC/LITE/rrc_common.c b/openair2/RRC/LITE/rrc_common.c index 67d92b9329..a6a2bbb613 100644 --- a/openair2/RRC/LITE/rrc_common.c +++ b/openair2/RRC/LITE/rrc_common.c @@ -217,3 +217,110 @@ binary_search_float( return first; } +typedef enum { BAND_TYPE_FDD, BAND_TYPE_TDD } band_type; + +typedef struct { + band_type t; + int band; + unsigned long ul_minfreq, ul_maxfreq; + unsigned long dl_minfreq, dl_maxfreq; +} band_freq; + +static band_freq bands[] = { + { BAND_TYPE_FDD, 1, 1920000000UL, 1980000000UL, 2110000000UL, 2170000000UL }, + { BAND_TYPE_FDD, 2, 1850000000UL, 1910000000UL, 1930000000UL, 1990000000UL }, + { BAND_TYPE_FDD, 3, 1710000000UL, 1785000000UL, 1805000000UL, 1880000000UL }, + { BAND_TYPE_FDD, 4, 1710000000UL, 1755000000UL, 2110000000UL, 2155000000UL }, + { BAND_TYPE_FDD, 5, 824000000UL, 849000000UL, 869000000UL, 894000000UL }, + /* to remove? */{ BAND_TYPE_FDD, 6, 830000000UL, 840000000UL, 875000000UL, 885000000UL }, + { BAND_TYPE_FDD, 7, 2500000000UL, 2570000000UL, 2620000000UL, 2690000000UL }, + { BAND_TYPE_FDD, 8, 880000000UL, 915000000UL, 925000000UL, 960000000UL }, + { BAND_TYPE_FDD, 9, 1749900000UL, 1784900000UL, 1844900000UL, 1879900000UL }, + { BAND_TYPE_FDD, 10, 1710000000UL, 1770000000UL, 2110000000UL, 2170000000UL }, + { BAND_TYPE_FDD, 11, 1427900000UL, 1447900000UL, 1475900000UL, 1495900000UL }, + { BAND_TYPE_FDD, 12, 699000000UL, 716000000UL, 729000000UL, 746000000UL }, + { BAND_TYPE_FDD, 13, 777000000UL, 787000000UL, 746000000UL, 756000000UL }, + { BAND_TYPE_FDD, 14, 788000000UL, 798000000UL, 758000000UL, 768000000UL }, + { BAND_TYPE_FDD, 17, 704000000UL, 716000000UL, 734000000UL, 746000000UL }, + { BAND_TYPE_FDD, 18, 815000000UL, 830000000UL, 860000000UL, 875000000UL }, + { BAND_TYPE_FDD, 19, 830000000UL, 845000000UL, 875000000UL, 890000000UL }, + { BAND_TYPE_FDD, 20, 832000000UL, 862000000UL, 791000000UL, 821000000UL }, + { BAND_TYPE_FDD, 21, 1447900000UL, 1462900000UL, 1495900000UL, 1510900000UL }, + { BAND_TYPE_FDD, 22, 3410000000UL, 3490000000UL, 3510000000UL, 3590000000UL }, + { BAND_TYPE_FDD, 23, 2000000000UL, 2020000000UL, 2180000000UL, 2200000000UL }, + { BAND_TYPE_FDD, 24, 1626500000UL, 1660500000UL, 1525000000UL, 1559000000UL }, + { BAND_TYPE_FDD, 25, 1850000000UL, 1915000000UL, 1930000000UL, 1995000000UL }, + + { BAND_TYPE_TDD, 33, 1900000000UL, 1920000000UL, 1900000000UL, 1920000000UL }, + { BAND_TYPE_TDD, 34, 2010000000UL, 2025000000UL, 2010000000UL, 2025000000UL }, + { BAND_TYPE_TDD, 35, 1850000000UL, 1910000000UL, 1850000000UL, 1910000000UL }, + { BAND_TYPE_TDD, 36, 1930000000UL, 1990000000UL, 1930000000UL, 1990000000UL }, + { BAND_TYPE_TDD, 37, 1910000000UL, 1930000000UL, 1910000000UL, 1930000000UL }, + { BAND_TYPE_TDD, 38, 2570000000UL, 2620000000UL, 2570000000UL, 2620000000UL }, + { BAND_TYPE_TDD, 39, 1880000000UL, 1920000000UL, 1880000000UL, 1920000000UL }, + { BAND_TYPE_TDD, 40, 2300000000UL, 2400000000UL, 2300000000UL, 2400000000UL }, + { BAND_TYPE_TDD, 41, 2496000000UL, 2690000000UL, 2496000000UL, 2690000000UL }, + { BAND_TYPE_TDD, 42, 3400000000UL, 3600000000UL, 3400000000UL, 3600000000UL }, + { BAND_TYPE_TDD, 43, 3600000000UL, 3800000000UL, 3600000000UL, 3800000000UL }, +}; + +typedef struct { + int band; + unsigned long dl_flow; + int dl_off; + int dl_offmin, dl_offmax; + unsigned long ul_flow; + int ul_off; + int ul_offmin, ul_offmax; +} earfcn; + +static earfcn earfcn_table[] = { + { 1, 2110000000UL, 0, 0, 599, 1920000000UL, 18000, 18000, 18599 }, + { 2, 1930000000UL, 600, 600, 1199, 1850000000UL, 18600, 18600, 19199 }, + { 3, 1805000000UL, 1200, 1200, 1949, 1710000000UL, 19200, 19200, 19949 }, + { 4, 2110000000UL, 1950, 1950, 2399, 1710000000UL, 19950, 19950, 20399 }, + { 5, 869000000UL, 2400, 2400, 2649, 824000000UL, 20400, 20400, 20649 }, + { 6, 875000000UL, 2650, 2650, 2749, 830000000UL, 20650, 20650, 20749 }, + { 7, 2620000000UL, 2750, 2750, 3449, 2500000000UL, 20750, 20750, 21449 }, + { 8, 925000000UL, 3450, 3450, 3799, 880000000UL, 21450, 21450, 21799 }, + { 9, 1844900000UL, 3800, 3800, 4149, 1749900000UL, 21800, 21800, 22149 }, + { 10, 2110000000UL, 4150, 4150, 4749, 1710000000UL, 22150, 22150, 22749 }, + { 11, 1475900000UL, 4750, 4750, 4949, 1427900000UL, 22750, 22750, 22949 }, + { 12, 729000000UL, 5010, 5010, 5179, 699000000UL, 23010, 23010, 23179 }, + { 13, 746000000UL, 5180, 5180, 5279, 777000000UL, 23180, 23180, 23279 }, + { 14, 758000000UL, 5280, 5280, 5379, 788000000UL, 23280, 23280, 23379 }, + { 17, 734000000UL, 5730, 5730, 5849, 704000000UL, 23730, 23730, 23849 }, + { 18, 860000000UL, 5850, 5850, 5999, 815000000UL, 23850, 23850, 23999 }, + { 19, 875000000UL, 6000, 6000, 6149, 830000000UL, 24000, 24000, 24149 }, + { 20, 791000000UL, 6150, 6150, 6449, 832000000UL, 24150, 24150, 24449 }, + { 21, 1495900000UL, 6450, 6450, 6599, 1447900000UL, 24450, 24450, 24599 }, + { 22, 3510000000UL, 6600, 6600, 7399, 3410000000UL, 24600, 24600, 25399 }, + { 23, 2180000000UL, 7500, 7500, 7699, 2000000000UL, 25500, 25500, 25699 }, + { 24, 1525000000UL, 7700, 7700, 8039, 1626500000UL, 25700, 25700, 26039 }, + { 25, 1930000000UL, 8040, 8040, 8689, 1850000000UL, 26040, 26040, 26689 }, + { 33, 1900000000UL, 36000, 36000, 36199, 1900000000UL, 36000, 36000, 36199 }, + { 34, 2010000000UL, 36200, 36200, 36349, 2010000000UL, 36200, 36200, 36349 }, + { 35, 1850000000UL, 36350, 36350, 36949, 1850000000UL, 36350, 36350, 36949 }, + { 36, 1930000000UL, 36950, 36950, 37549, 1930000000UL, 36950, 36950, 37549 }, + { 37, 1910000000UL, 37550, 37550, 37749, 1910000000UL, 37550, 37550, 37749 }, + { 38, 2570000000UL, 37750, 37750, 38249, 2570000000UL, 37750, 37750, 38249 }, + { 39, 1880000000UL, 38250, 38250, 38649, 1880000000UL, 38250, 38250, 38649 }, + { 40, 2300000000UL, 38650, 38650, 39649, 2300000000UL, 38650, 38650, 39649 }, + { 41, 2496000000UL, 39650, 39650, 41589, 2496000000UL, 39650, 39650, 41589 }, + { 42, 3400000000UL, 41590, 41590, 43589, 3400000000UL, 41590, 41590, 43589 }, + { 43, 3600000000UL, 43590, 43590, 45589, 3600000000UL, 43590, 43590, 45589 }, +}; + +int freq_to_arfcn10(int band, unsigned long freq) +{ + int N = sizeof(earfcn_table) / sizeof(earfcn_table[0]); + int i; + + for (i = 0; i < N; i++) if (bands[i].band == band) break; + if (i == N) return -1; + + if (!(bands[i].dl_minfreq < freq && freq < bands[i].dl_maxfreq)) + return -1; + + return (freq - earfcn_table[i].dl_flow) / 100000UL + earfcn_table[i].dl_off; +} diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 7716663283..fbc95c8b74 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -3353,113 +3353,7 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* cons PDCP_TRANSMISSION_MODE_CONTROL); } -typedef enum { BAND_TYPE_FDD, BAND_TYPE_TDD } band_type; -typedef struct { - band_type t; - int band; - unsigned long ul_minfreq, ul_maxfreq; - unsigned long dl_minfreq, dl_maxfreq; -} band_freq; - -static band_freq bands[] = { - { BAND_TYPE_FDD, 1, 1920000000UL, 1980000000UL, 2110000000UL, 2170000000UL }, - { BAND_TYPE_FDD, 2, 1850000000UL, 1910000000UL, 1930000000UL, 1990000000UL }, - { BAND_TYPE_FDD, 3, 1710000000UL, 1785000000UL, 1805000000UL, 1880000000UL }, - { BAND_TYPE_FDD, 4, 1710000000UL, 1755000000UL, 2110000000UL, 2155000000UL }, - { BAND_TYPE_FDD, 5, 824000000UL, 849000000UL, 869000000UL, 894000000UL }, - /* to remove? */{ BAND_TYPE_FDD, 6, 830000000UL, 840000000UL, 875000000UL, 885000000UL }, - { BAND_TYPE_FDD, 7, 2500000000UL, 2570000000UL, 2620000000UL, 2690000000UL }, - { BAND_TYPE_FDD, 8, 880000000UL, 915000000UL, 925000000UL, 960000000UL }, - { BAND_TYPE_FDD, 9, 1749900000UL, 1784900000UL, 1844900000UL, 1879900000UL }, - { BAND_TYPE_FDD, 10, 1710000000UL, 1770000000UL, 2110000000UL, 2170000000UL }, - { BAND_TYPE_FDD, 11, 1427900000UL, 1447900000UL, 1475900000UL, 1495900000UL }, - { BAND_TYPE_FDD, 12, 699000000UL, 716000000UL, 729000000UL, 746000000UL }, - { BAND_TYPE_FDD, 13, 777000000UL, 787000000UL, 746000000UL, 756000000UL }, - { BAND_TYPE_FDD, 14, 788000000UL, 798000000UL, 758000000UL, 768000000UL }, - { BAND_TYPE_FDD, 17, 704000000UL, 716000000UL, 734000000UL, 746000000UL }, - { BAND_TYPE_FDD, 18, 815000000UL, 830000000UL, 860000000UL, 875000000UL }, - { BAND_TYPE_FDD, 19, 830000000UL, 845000000UL, 875000000UL, 890000000UL }, - { BAND_TYPE_FDD, 20, 832000000UL, 862000000UL, 791000000UL, 821000000UL }, - { BAND_TYPE_FDD, 21, 1447900000UL, 1462900000UL, 1495900000UL, 1510900000UL }, - { BAND_TYPE_FDD, 22, 3410000000UL, 3490000000UL, 3510000000UL, 3590000000UL }, - { BAND_TYPE_FDD, 23, 2000000000UL, 2020000000UL, 2180000000UL, 2200000000UL }, - { BAND_TYPE_FDD, 24, 1626500000UL, 1660500000UL, 1525000000UL, 1559000000UL }, - { BAND_TYPE_FDD, 25, 1850000000UL, 1915000000UL, 1930000000UL, 1995000000UL }, - - { BAND_TYPE_TDD, 33, 1900000000UL, 1920000000UL, 1900000000UL, 1920000000UL }, - { BAND_TYPE_TDD, 34, 2010000000UL, 2025000000UL, 2010000000UL, 2025000000UL }, - { BAND_TYPE_TDD, 35, 1850000000UL, 1910000000UL, 1850000000UL, 1910000000UL }, - { BAND_TYPE_TDD, 36, 1930000000UL, 1990000000UL, 1930000000UL, 1990000000UL }, - { BAND_TYPE_TDD, 37, 1910000000UL, 1930000000UL, 1910000000UL, 1930000000UL }, - { BAND_TYPE_TDD, 38, 2570000000UL, 2620000000UL, 2570000000UL, 2620000000UL }, - { BAND_TYPE_TDD, 39, 1880000000UL, 1920000000UL, 1880000000UL, 1920000000UL }, - { BAND_TYPE_TDD, 40, 2300000000UL, 2400000000UL, 2300000000UL, 2400000000UL }, - { BAND_TYPE_TDD, 41, 2496000000UL, 2690000000UL, 2496000000UL, 2690000000UL }, - { BAND_TYPE_TDD, 42, 3400000000UL, 3600000000UL, 3400000000UL, 3600000000UL }, - { BAND_TYPE_TDD, 43, 3600000000UL, 3800000000UL, 3600000000UL, 3800000000UL }, -}; - -typedef struct { - int band; - unsigned long dl_flow; - int dl_off; - int dl_offmin, dl_offmax; - unsigned long ul_flow; - int ul_off; - int ul_offmin, ul_offmax; -} earfcn; - -static earfcn earfcn_table[] = { - { 1, 2110000000UL, 0, 0, 599, 1920000000UL, 18000, 18000, 18599 }, - { 2, 1930000000UL, 600, 600, 1199, 1850000000UL, 18600, 18600, 19199 }, - { 3, 1805000000UL, 1200, 1200, 1949, 1710000000UL, 19200, 19200, 19949 }, - { 4, 2110000000UL, 1950, 1950, 2399, 1710000000UL, 19950, 19950, 20399 }, - { 5, 869000000UL, 2400, 2400, 2649, 824000000UL, 20400, 20400, 20649 }, - { 6, 875000000UL, 2650, 2650, 2749, 830000000UL, 20650, 20650, 20749 }, - { 7, 2620000000UL, 2750, 2750, 3449, 2500000000UL, 20750, 20750, 21449 }, - { 8, 925000000UL, 3450, 3450, 3799, 880000000UL, 21450, 21450, 21799 }, - { 9, 1844900000UL, 3800, 3800, 4149, 1749900000UL, 21800, 21800, 22149 }, - { 10, 2110000000UL, 4150, 4150, 4749, 1710000000UL, 22150, 22150, 22749 }, - { 11, 1475900000UL, 4750, 4750, 4949, 1427900000UL, 22750, 22750, 22949 }, - { 12, 729000000UL, 5010, 5010, 5179, 699000000UL, 23010, 23010, 23179 }, - { 13, 746000000UL, 5180, 5180, 5279, 777000000UL, 23180, 23180, 23279 }, - { 14, 758000000UL, 5280, 5280, 5379, 788000000UL, 23280, 23280, 23379 }, - { 17, 734000000UL, 5730, 5730, 5849, 704000000UL, 23730, 23730, 23849 }, - { 18, 860000000UL, 5850, 5850, 5999, 815000000UL, 23850, 23850, 23999 }, - { 19, 875000000UL, 6000, 6000, 6149, 830000000UL, 24000, 24000, 24149 }, - { 20, 791000000UL, 6150, 6150, 6449, 832000000UL, 24150, 24150, 24449 }, - { 21, 1495900000UL, 6450, 6450, 6599, 1447900000UL, 24450, 24450, 24599 }, - { 22, 3510000000UL, 6600, 6600, 7399, 3410000000UL, 24600, 24600, 25399 }, - { 23, 2180000000UL, 7500, 7500, 7699, 2000000000UL, 25500, 25500, 25699 }, - { 24, 1525000000UL, 7700, 7700, 8039, 1626500000UL, 25700, 25700, 26039 }, - { 25, 1930000000UL, 8040, 8040, 8689, 1850000000UL, 26040, 26040, 26689 }, - { 33, 1900000000UL, 36000, 36000, 36199, 1900000000UL, 36000, 36000, 36199 }, - { 34, 2010000000UL, 36200, 36200, 36349, 2010000000UL, 36200, 36200, 36349 }, - { 35, 1850000000UL, 36350, 36350, 36949, 1850000000UL, 36350, 36350, 36949 }, - { 36, 1930000000UL, 36950, 36950, 37549, 1930000000UL, 36950, 36950, 37549 }, - { 37, 1910000000UL, 37550, 37550, 37749, 1910000000UL, 37550, 37550, 37749 }, - { 38, 2570000000UL, 37750, 37750, 38249, 2570000000UL, 37750, 37750, 38249 }, - { 39, 1880000000UL, 38250, 38250, 38649, 1880000000UL, 38250, 38250, 38649 }, - { 40, 2300000000UL, 38650, 38650, 39649, 2300000000UL, 38650, 38650, 39649 }, - { 41, 2496000000UL, 39650, 39650, 41589, 2496000000UL, 39650, 39650, 41589 }, - { 42, 3400000000UL, 41590, 41590, 43589, 3400000000UL, 41590, 41590, 43589 }, - { 43, 3600000000UL, 43590, 43590, 45589, 3600000000UL, 43590, 43590, 45589 }, -}; - -int freq_to_arfcn10(int band, unsigned long freq) -{ - int N = sizeof(earfcn_table) / sizeof(earfcn_table[0]); - int i; - - for (i = 0; i < N; i++) if (bands[i].band == band) break; - if (i == N) return -1; - - if (!(bands[i].dl_minfreq < freq && freq < bands[i].dl_maxfreq)) - return -1; - - return (freq - earfcn_table[i].dl_flow) / 100000UL + earfcn_table[i].dl_off; -} //----------------------------------------------------------------------------- int From 0d05de6382d6cda7833971ad270ca5fbcd384f28 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sun, 28 Jan 2018 13:13:59 +0100 Subject: [PATCH 172/284] minor changes after merge with develop for noS1 simulation --- openair1/SCHED/prach_procedures.c | 2 -- targets/RT/USER/lte-ru.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/openair1/SCHED/prach_procedures.c b/openair1/SCHED/prach_procedures.c index be5aa33d2b..d8c6585074 100644 --- a/openair1/SCHED/prach_procedures.c +++ b/openair1/SCHED/prach_procedures.c @@ -112,14 +112,12 @@ void prach_procedures(PHY_VARS_eNB *eNB, #endif ); - #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[RAPROC] Frame %d, subframe %d : Most likely preamble %d, energy %d dB delay %d (prach_energy counter %d)\n", frame,subframe, max_preamble[0], max_preamble_energy[0]/10, max_preamble_delay[0], eNB->prach_energy_counter); - #endif #ifdef Rel14 if (br_flag==1) { diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 2706cf18a2..65d945dd7e 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -1180,7 +1180,7 @@ static inline int wakeup_prach_ru(RU_t *ru) { ru->eNB_list[0]->proc.frame_prach = ru->proc.frame_rx; ru->eNB_list[0]->proc.subframe_prach = ru->proc.subframe_rx; } - LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx); + LOG_I(PHY,"RU %d: waking up PRACH thread\n",ru->idx); // the thread can now be woken up AssertFatal(pthread_cond_signal(&ru->proc.cond_prach) == 0, "ERROR pthread_cond_signal for RU prach thread\n"); } From cdbf65f5afdb69d26105635c047e76a902475d48 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 12 Jan 2018 09:43:33 +0100 Subject: [PATCH 173/284] revise RAN API - when changing values RC.rrc[i]->configuration should be changed too - then, RRC_RECONFIGURATION_REQ will pass the changed conf down until PHY - give warnings at functions that are not implemented - rename functions flexran_get_tdd_ack_nack_feedback() -> flexran_get_tdd_ack_nack_feedback_mode() flexran_get_ue_pmi() -> flexran_get_ue_wpmi() --- openair2/ENB_APP/flexran_agent_ran_api.c | 1626 ++++++++++------------ openair2/ENB_APP/flexran_agent_ran_api.h | 214 +-- 2 files changed, 811 insertions(+), 1029 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 16462b4d40..af1d1be63d 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -21,237 +21,196 @@ /*! \file flexran_agent_ran_api.c * \brief FlexRAN RAN API abstraction - * \author N. Nikaein, X. Foukas and S. SHARIAT BAGHERI + * \author N. Nikaein, X. Foukas, S. SHARIAT BAGHERI and R. Schmidt * \date 2017 * \version 0.1 */ #include "flexran_agent_ran_api.h" - /* * generic info from RAN */ +PHY_VARS_eNB *phy[NUM_MAX_ENB][MAX_NUM_CCs] = { NULL }; +eNB_MAC_INST *mac[NUM_MAX_ENB] = { NULL }; +eNB_RRC_INST *rrc[NUM_MAX_ENB] = { NULL }; +UE_list_t *UE_list[NUM_MAX_ENB] = { NULL }; - -void * enb[NUM_MAX_ENB]; -void * enb_ue[NUM_MAX_ENB]; -void * enb_rrc[NUM_MAX_ENB]; -Enb_properties_array_t* enb_properties; - -void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran){ - - switch (ran){ - case RAN_LTE_OAI : - enb_properties = enb_config_get(); - if(eNB_mac_inst == NULL){ - enb[mod_id] = NULL; - enb_ue[mod_id] = NULL; - enb_rrc[mod_id] = NULL; - }else{ - enb[mod_id] = (void *)&eNB_mac_inst[mod_id]; - enb_ue[mod_id] = (void *)&eNB_mac_inst[mod_id].UE_list; - enb_rrc[mod_id] = (void *)&eNB_rrc_inst[mod_id]; +void flexran_set_RC_vars(mid_t mod_id, ran_name_t ran) +{ + int i; + if (ran == RAN_LTE_OAI) { + if (RC.eNB && mod_id < RC.nb_RU && RC.eNB[mod_id] && RC.nb_CC) + for (i = 0; i < *RC.nb_CC; i++) + phy[mod_id][i] = RC.eNB[mod_id][i]; + if (RC.mac && mod_id < RC.nb_macrlc_inst && RC.mac[mod_id]) { + mac[mod_id] = RC.mac[mod_id]; + UE_list[mod_id] = &RC.mac[mod_id]->UE_list; } - break; - default : - goto error; - } - - return; - - error: - LOG_E(FLEXRAN_AGENT, "unknown RAN name %d\n", ran); -} - -static int mac_xface_not_ready(void) -{ - if (mac_xface == NULL) { - return 1; + if (RC.rrc && mod_id < RC.nb_macrlc_inst && RC.rrc[mod_id]) + rrc[mod_id] = RC.rrc[mod_id]; } else { - //printf("max_xface %p %d \n", mac_xface, mac_xface->active); - return 0;// !mac_xface->active; + LOG_E(FLEXRAN_AGENT, "unknown RAN name %d when setting RAN API variables\n", ran); } } -static int eNB_rrc_inst_not_ready(void) +uint32_t flexran_get_current_time_ms(mid_t mod_id, int subframe_flag) { - if (NULL == eNB_rrc_inst) { - return 1; - } - else { - return 0; - } + if (!mac[mod_id]) return 0; + if (subframe_flag == 1) + return mac[mod_id]->frame*10 + mac[mod_id]->subframe; + else + return mac[mod_id]->frame*10; } -int flexran_get_current_time_ms (mid_t mod_id, int subframe_flag){ - if (enb[mod_id] == NULL) return 0; - if (subframe_flag == 1){ - return ((eNB_MAC_INST *)enb[mod_id])->frame*10 + ((eNB_MAC_INST *)enb[mod_id])->subframe; - }else { - return ((eNB_MAC_INST *)enb[mod_id])->frame*10; - } - -} - -unsigned int flexran_get_current_frame (mid_t mod_id) { - if (enb[mod_id] == NULL) return 0; +frame_t flexran_get_current_frame(mid_t mod_id) +{ + if (!mac[mod_id]) return 0; // #warning "SFN will not be in [0-1023] when oaisim is used" - return ((eNB_MAC_INST *)enb[mod_id])->frame; - + return mac[mod_id]->frame; } -unsigned int flexran_get_current_system_frame_num(mid_t mod_id) { - return (flexran_get_current_frame(mod_id) %1024); +frame_t flexran_get_current_system_frame_num(mid_t mod_id) +{ + return flexran_get_current_frame(mod_id) % 1024; } -unsigned int flexran_get_current_subframe (mid_t mod_id) { - if (enb[mod_id] == NULL) return 0; - return ((eNB_MAC_INST *)enb[mod_id])->subframe; - +sub_frame_t flexran_get_current_subframe(mid_t mod_id) +{ + if (!mac[mod_id]) return 0; + return mac[mod_id]->subframe; } -uint16_t flexran_get_sfn_sf (mid_t mod_id) { - - frame_t frame; - sub_frame_t subframe; +/* Why uint16_t, frame_t and sub_frame_t are defined as uint32_t? */ +uint16_t flexran_get_sfn_sf(mid_t mod_id) +{ + frame_t frame = flexran_get_current_system_frame_num(mod_id); + sub_frame_t subframe = flexran_get_current_subframe(mod_id); uint16_t sfn_sf, frame_mask, sf_mask; - - frame = (frame_t) flexran_get_current_system_frame_num(mod_id); - subframe = (sub_frame_t) flexran_get_current_subframe(mod_id); - frame_mask = ((1<<12) - 1); - sf_mask = ((1<<4) - 1); + + frame_mask = (1 << 12) - 1; + sf_mask = (1 << 4) - 1; sfn_sf = (subframe & sf_mask) | ((frame & frame_mask) << 4); - + return sfn_sf; } -uint16_t flexran_get_future_sfn_sf (mid_t mod_id, int ahead_of_time) { - - frame_t frame; - sub_frame_t subframe; +uint16_t flexran_get_future_sfn_sf(mid_t mod_id, int ahead_of_time) +{ + frame_t frame = flexran_get_current_system_frame_num(mod_id); + sub_frame_t subframe = flexran_get_current_subframe(mod_id); uint16_t sfn_sf, frame_mask, sf_mask; - - frame = (frame_t) flexran_get_current_system_frame_num(mod_id); - subframe = (sub_frame_t) flexran_get_current_subframe(mod_id); + int additional_frames; - subframe = ((subframe + ahead_of_time) % 10); - - if (subframe < flexran_get_current_subframe(mod_id)) { + subframe = (subframe + ahead_of_time) % 10; + + if (subframe < flexran_get_current_subframe(mod_id)) frame = (frame + 1) % 1024; - } - - int additional_frames = ahead_of_time / 10; + + additional_frames = ahead_of_time / 10; frame = (frame + additional_frames) % 1024; - - frame_mask = ((1<<12) - 1); - sf_mask = ((1<<4) - 1); + + frame_mask = (1 << 12) - 1; + sf_mask = (1 << 4) - 1; sfn_sf = (subframe & sf_mask) | ((frame & frame_mask) << 4); - + return sfn_sf; } -int flexran_get_num_ues (mid_t mod_id){ - if (enb_ue[mod_id] == NULL) return 0; - return ((UE_list_t *)enb_ue[mod_id])->num_UEs; +int flexran_get_num_ues(mid_t mod_id) +{ + if (!UE_list[mod_id]) return 0; + return UE_list[mod_id]->num_UEs; } -int flexran_get_ue_crnti (mid_t mod_id, mid_t ue_id) { - - return UE_RNTI(mod_id, ue_id); +rnti_t flexran_get_ue_crnti(mid_t mod_id, mid_t ue_id) +{ + return UE_RNTI(mod_id, ue_id); } -int flexran_get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid) { - if (enb_ue[mod_id] == NULL) return 0; - return ((UE_list_t *)enb_ue[mod_id])->UE_template[UE_PCCID(mod_id,ue_id)][ue_id].bsr_info[lcid]; +uint8_t flexran_get_ue_bsr(mid_t mod_id, mid_t ue_id, lcid_t lcid) +{ + if (!UE_list[mod_id]) return 0; + return UE_list[mod_id]->UE_template[UE_PCCID(mod_id, ue_id)][ue_id].bsr_info[lcid]; } -int flexran_get_ue_phr (mid_t mod_id, mid_t ue_id) { - if (enb_ue[mod_id] == NULL) return 0; - return ((UE_list_t *)enb_ue[mod_id])->UE_template[UE_PCCID(mod_id,ue_id)][ue_id].phr_info; +int8_t flexran_get_ue_phr(mid_t mod_id, mid_t ue_id) +{ + if (!UE_list[mod_id]) return 0; + return UE_list[mod_id]->UE_template[UE_PCCID(mod_id, ue_id)][ue_id].phr_info; } -int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - if (mac_xface_not_ready()) return 0 ; - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, 0, UE_RNTI(mod_id, ue_id)); - return eNB_UE_stats->DL_cqi[0]; - - // return ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].dl_cqi; +uint8_t flexran_get_ue_wcqi(mid_t mod_id, mid_t ue_id) +{ + if (!phy[mod_id][0]) return 0; + return phy[mod_id][0]->UE_stats[ue_id].DL_cqi[0]; } -int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); - uint16_t subframe = (uint16_t) flexran_get_current_subframe(mod_id); +rlc_buffer_occupancy_t flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) +{ + rnti_t rnti = flexran_get_ue_crnti(mod_id, ue_id); + frame_t frame = flexran_get_current_frame(mod_id); + sub_frame_t subframe = flexran_get_current_subframe(mod_id); mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id, frame, subframe, ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0); return rlc_status.bytes_in_buffer; } - -int flexran_get_num_pdus_buffer(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { +rlc_buffer_occupancy_t flexran_get_num_pdus_buffer(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) +{ rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); - uint16_t subframe = (uint16_t) flexran_get_current_subframe(mod_id); + frame_t frame = flexran_get_current_frame(mod_id); + sub_frame_t subframe = flexran_get_current_subframe(mod_id); mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id, frame, subframe, ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0); return rlc_status.pdus_in_buffer; } - - -int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { +frame_t flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) +{ rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); - uint16_t subframe = (uint16_t) flexran_get_current_subframe(mod_id); + frame_t frame = flexran_get_current_frame(mod_id); + sub_frame_t subframe = flexran_get_current_subframe(mod_id); mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, subframe, ENB_FLAG_YES, MBMS_FLAG_NO, channel_id, 0); return rlc_status.head_sdu_creation_time; } -short flexran_get_TA(mid_t mod_id, mid_t ue_id, int CC_id) { - - // UE_list_t *UE_list=&eNB_mac_inst[mod_id].UE_list; - int rnti; +int32_t flexran_get_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; - rnti = flexran_get_ue_crnti(mod_id, ue_id); - if (mac_xface_not_ready()) return 0 ; - - LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - //ue_sched_ctl->ta_timer = 20; // wait 20 subframes before taking TA measurement from PHY - switch (flexran_get_N_RB_DL(mod_id, CC_id)) { + int32_t tau = phy[mod_id][cc_id]->UE_stats[ue_id].timing_advance_update; + switch (flexran_get_N_RB_DL(mod_id, cc_id)) { case 6: - return eNB_UE_stats->timing_advance_update; + return tau; case 15: - return eNB_UE_stats->timing_advance_update/2; + return tau / 2; case 25: - return eNB_UE_stats->timing_advance_update/4; + return tau / 4; case 50: - return eNB_UE_stats->timing_advance_update/8; + return tau / 8; case 75: - return eNB_UE_stats->timing_advance_update/12; + return tau / 12; case 100: - if (flexran_get_threequarter_fs(mod_id, CC_id) == 0) { - return eNB_UE_stats->timing_advance_update/16; - } else { - return eNB_UE_stats->timing_advance_update/12; - } + if (flexran_get_threequarter_fs(mod_id, cc_id) == 0) + return tau / 16; + else + return tau / 12; default: return 0; } } -int flexran_get_ue_pmi(mid_t mod_id){ - - /*Xenofon to check this*/ - - return 0; +uint8_t flexran_get_ue_wpmi(mid_t mod_id, mid_t ue_id, uint8_t cc_id) +{ + if (!UE_list[mod_id]) return 0; + return UE_list[mod_id]->UE_sched_ctrl[ue_id].periodic_wideband_pmi[cc_id]; } - -void flexran_update_TA(mid_t mod_id, mid_t ue_id, int CC_id) { - +/* TODO needs to be revised */ +void flexran_update_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id) +{ +/* UE_list_t *UE_list=&eNB_mac_inst[mod_id].UE_list; UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[ue_id]; @@ -268,92 +227,79 @@ void flexran_update_TA(mid_t mod_id, mid_t ue_id, int CC_id) { ue_sched_ctl->ta_timer--; ue_sched_ctl->ta_update = 0; // don't trigger a timing advance command } +*/ +#warning "Implement flexran_update_TA() in RAN API" } -int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) { - - // UE_list_t *UE_list = &eNB_mac_inst[mod_id].UE_list; - - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - if (mac_xface_not_ready()) return 0 ; +/* TODO needs to be revised, looks suspicious: why do we need UE stats? */ +int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id) +{ +#warning "Implement flexran_get_MAC_CE_bitmap_TA() in RAN API" + if (!phy[mod_id][cc_id]) return 0; + /* UE_stats can not be null, they are an array in RC LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); if (eNB_UE_stats == NULL) { return 0; } + */ - if (flexran_get_TA(mod_id, ue_id, CC_id) != 0) { + if (flexran_get_TA(mod_id, ue_id, cc_id) != 0) { return PROTOCOL__FLEX_CE_TYPE__FLPCET_TA; } else { return 0; } - } -int flexran_get_active_CC(mid_t mod_id, mid_t ue_id) { - if (enb_ue[mod_id] == NULL) return 0; - return ((UE_list_t *)enb_ue[mod_id])->numactiveCCs[ue_id]; +int flexran_get_active_CC(mid_t mod_id, mid_t ue_id) +{ + if (!UE_list[mod_id]) return 0; + return UE_list[mod_id]->numactiveCCs[ue_id]; } -int flexran_get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - if (mac_xface_not_ready()) return 0 ; - - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); - - if (eNB_UE_stats == NULL) { - return 0; - } - - return eNB_UE_stats[CC_id].rank; +uint8_t flexran_get_current_RI(mid_t mod_id, mid_t ue_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->UE_stats[ue_id].rank; } -int flexran_get_tpc(mid_t mod_id, mid_t ue_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - int32_t normalized_rx_power, target_rx_power; - int tpc = 1; +int flexran_get_tpc(mid_t mod_id, mid_t ue_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; - int pCCid = UE_PCCID(mod_id,ue_id); - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - if (mac_xface_not_ready()) return 0 ; + /* before: tested that UL_rssi != NULL and set parameter ([0]), but it is a + * static array -> target_rx_power is useless in old ifs?! */ + int pCCid = UE_PCCID(mod_id,ue_id); + int32_t target_rx_power = phy[mod_id][pCCid]->frame_parms.ul_power_control_config_common.p0_NominalPUSCH; + int32_t normalized_rx_power = phy[mod_id][cc_id]->UE_stats[ue_id].UL_rssi[0]; - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, pCCid, rnti); - - target_rx_power = mac_xface->get_target_pusch_rx_power(mod_id,pCCid); - - if (eNB_UE_stats == NULL) { - normalized_rx_power = target_rx_power; - } else if (eNB_UE_stats->UL_rssi != NULL) { - normalized_rx_power = eNB_UE_stats->UL_rssi[0]; - } else { - normalized_rx_power = target_rx_power; - } - - if (normalized_rx_power>(target_rx_power+1)) { - tpc = 0; //-1 - } else if (normalized_rx_power<(target_rx_power-1)) { - tpc = 2; //+1 - } else { - tpc = 1; //0 - } - return tpc; + int tpc; + if (normalized_rx_power > target_rx_power + 1) + tpc = 0; //-1 + else if (normalized_rx_power < target_rx_power - 1) + tpc = 2; //+1 + else + tpc = 1; //0 + return tpc; } -int flexran_get_harq(const mid_t mod_id, - const uint8_t CC_id, - const mid_t ue_id, - const int frame, - const uint8_t subframe, - uint8_t *pid, - uint8_t *round, - const uint8_t harq_flag) { //flag_id_status = 0 then id, else status - /*TODO: Add int TB in function parameters to get the status of the second TB. This can be done to by editing in - * get_ue_active_harq_pid function in line 272 file: phy_procedures_lte_eNB.c to add - * DLSCH_ptr = PHY_vars_eNB_g[Mod_id][CC_id]->dlsch_eNB[(uint32_t)UE_id][1];*/ +int flexran_get_harq(mid_t mod_id, + uint8_t cc_id, + mid_t ue_id, + frame_t frame, + sub_frame_t subframe, + uint8_t *pid, + uint8_t *round, + uint8_t harq_flag) +{ + /* TODO: Add int TB in function parameters to get the status of the second + * TB. This can be done to by editing in get_ue_active_harq_pid function in + * line 272 file: phy_procedures_lte_eNB.c to add DLSCH_ptr = + * PHY_vars_eNB_g[Mod_id][CC_id]->dlsch_eNB[(uint32_t)UE_id][1];*/ + /* TODO IMPLEMENT */ + /* uint8_t harq_pid; uint8_t harq_round; @@ -375,61 +321,39 @@ int flexran_get_harq(const mid_t mod_id, *pid = harq_pid; - *round = harq_round; + *round = harq_round;*/ /* if (round > 0) { */ /* *status = 1; */ /* } else { */ /* *status = 0; */ /* } */ - - /* return 0; */ - return *round; + /*return *round;*/ +#warning "Implement flexran_get_harq() in RAN API" + return 0; } -int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - if (mac_xface_not_ready()) return 0 ; - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - - if (eNB_UE_stats == NULL) { - return -1; - } - - // if(eNB_UE_stats->Po_PUCCH_update == 1) { - return eNB_UE_stats->Po_PUCCH_dBm; - //} - //else - // return -1; +int32_t flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->UE_stats[ue_id].Po_PUCCH_dBm; } -int flexran_get_p0_nominal_pucch(mid_t mod_id, int CC_id) { - if (mac_xface_not_ready()) return 0 ; - - int32_t pucch_rx_received = mac_xface->get_target_pucch_rx_power(mod_id, CC_id); - return pucch_rx_received; +int8_t flexran_get_p0_nominal_pucch(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.ul_power_control_config_common.p0_NominalPUCCH; } -int flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, int CC_id) { - if (mac_xface_not_ready()) return 0 ; - - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - return eNB_UE_stats->Po_PUCCH_update; +int32_t flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->UE_stats[ue_id].Po_PUCCH_update; } -int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id) { - if (mac_xface_not_ready()) return 0 ; - - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - eNB_UE_stats->Po_PUCCH_update = 0; - +int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + phy[mod_id][cc_id]->UE_stats[ue_id].Po_PUCCH_update = 0; return 0; } @@ -439,243 +363,206 @@ int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id) { * Get Messages for eNB Configuration Reply * ************************************ */ -int flexran_get_threequarter_fs(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->threequarter_fs; +uint8_t flexran_get_threequarter_fs(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.threequarter_fs; } -int flexran_get_hopping_offset(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pusch_config_common.pusch_HoppingOffset; +uint8_t flexran_get_hopping_offset(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.pusch_config_common.pusch_HoppingOffset; } -int flexran_get_hopping_mode(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pusch_config_common.hoppingMode; +PUSCH_HOPPING_t flexran_get_hopping_mode(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.pusch_config_common.hoppingMode; } -int flexran_get_n_SB(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pusch_config_common.n_SB; +uint8_t flexran_get_n_SB(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.pusch_config_common.n_SB; } -int flexran_get_enable64QAM(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pusch_config_common.enable64QAM; +uint8_t flexran_get_enable64QAM(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.pusch_config_common.enable64QAM; } -int flexran_get_phich_duration(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->phich_config_common.phich_duration; +PHICH_DURATION_t flexran_get_phich_duration(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.phich_config_common.phich_duration; } -int flexran_get_phich_resource(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - if(frame_parms->phich_config_common.phich_resource == oneSixth) - return 0; - else if(frame_parms->phich_config_common.phich_resource == half) - return 1; - else if(frame_parms->phich_config_common.phich_resource == one) - return 2; - else if(frame_parms->phich_config_common.phich_resource == two) - return 3; - - return -1; +int flexran_get_phich_resource(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + /* TODO why don't we return phich_resource? */ + switch (phy[mod_id][cc_id]->frame_parms.phich_config_common.phich_resource) { + case oneSixth: + return 0; + case half: + return 1; + case one: + return 2; + case two: + return 3; + default: + return -1; + } } -int flexran_get_n1pucch_an(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pucch_config_common.n1PUCCH_AN; +uint16_t flexran_get_n1pucch_an(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.pucch_config_common.n1PUCCH_AN; } -int flexran_get_nRB_CQI(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pucch_config_common.nRB_CQI; +uint8_t flexran_get_nRB_CQI(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.pucch_config_common.nRB_CQI; } -int flexran_get_deltaPUCCH_Shift(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pucch_config_common.deltaPUCCH_Shift; +uint8_t flexran_get_deltaPUCCH_Shift(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.pucch_config_common.deltaPUCCH_Shift; } -int flexran_get_prach_ConfigIndex(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex; +uint8_t flexran_get_prach_ConfigIndex(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex; } -int flexran_get_prach_FreqOffset(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset; +uint8_t flexran_get_prach_FreqOffset(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset; } -int flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->maxHARQ_Msg3Tx; +uint8_t flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.maxHARQ_Msg3Tx; } -int flexran_get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->Ncp_UL; +lte_prefix_type_t flexran_get_ul_cyclic_prefix_length(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.Ncp_UL; } -int flexran_get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->Ncp; +lte_prefix_type_t flexran_get_dl_cyclic_prefix_length(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.Ncp; } -int flexran_get_cell_id(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - if (mac_xface_not_ready()) return 0; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->Nid_cell; +uint16_t flexran_get_cell_id(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.Nid_cell; } -int flexran_get_srs_BandwidthConfig(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->soundingrs_ul_config_common.srs_BandwidthConfig; +uint8_t flexran_get_srs_BandwidthConfig(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.soundingrs_ul_config_common.srs_BandwidthConfig; } -int flexran_get_srs_SubframeConfig(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->soundingrs_ul_config_common.srs_SubframeConfig; +uint8_t flexran_get_srs_SubframeConfig(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.soundingrs_ul_config_common.srs_SubframeConfig; } -int flexran_get_srs_MaxUpPts(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->soundingrs_ul_config_common.srs_MaxUpPts; +uint8_t flexran_get_srs_MaxUpPts(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.soundingrs_ul_config_common.srs_MaxUpPts; } -int flexran_get_N_RB_DL(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->N_RB_DL; +uint8_t flexran_get_N_RB_DL(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.N_RB_DL; } -int flexran_get_N_RB_UL(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->N_RB_UL; +uint8_t flexran_get_N_RB_UL(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.N_RB_UL; } -int flexran_get_N_RBG(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->N_RBG; +uint8_t flexran_get_N_RBG(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.N_RBG; } -int flexran_get_subframe_assignment(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->tdd_config; +uint8_t flexran_get_subframe_assignment(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.tdd_config; } -int flexran_get_special_subframe_assignment(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return (frame_parms == NULL)? 0:frame_parms->tdd_config_S; +uint8_t flexran_get_special_subframe_assignment(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.tdd_config_S; } -int flexran_get_ra_ResponseWindowSize(mid_t mod_id, int CC_id) { - return enb_config_get()->properties[mod_id]->rach_raResponseWindowSize[CC_id]; +long flexran_get_ra_ResponseWindowSize(mid_t mod_id, uint8_t cc_id) +{ + if (!rrc[mod_id]) return 0; + return rrc[mod_id]->configuration.rach_raResponseWindowSize[cc_id]; } -int flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id) { - return enb_config_get()->properties[mod_id]->rach_macContentionResolutionTimer[CC_id]; +long flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, uint8_t cc_id) +{ + if (!rrc[mod_id]) return 0; + return rrc[mod_id]->configuration.rach_macContentionResolutionTimer[cc_id]; } -int flexran_get_duplex_mode(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - if (mac_xface_not_ready()) return 0 ; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - if (frame_parms == NULL) return -1; - if(frame_parms->frame_type == TDD) - return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD; - else if (frame_parms->frame_type == FDD) - return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_FDD; - - return -1; +Protocol__FlexDuplexMode flexran_get_duplex_mode(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + switch (phy[mod_id][cc_id]->frame_parms.frame_type) { + case TDD: + return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD; + case FDD: + return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_FDD; + default: + return -1; + } } -long flexran_get_si_window_length(mid_t mod_id, int CC_id) { - return ((eNB_RRC_INST *)enb_rrc[mod_id])->carrier[CC_id].sib1->si_WindowLength; +long flexran_get_si_window_length(mid_t mod_id, uint8_t cc_id) +{ + if (!rrc[mod_id] || !rrc[mod_id]->carrier[cc_id].sib1) return 0; + return rrc[mod_id]->carrier[cc_id].sib1->si_WindowLength; } -int flexran_get_sib1_length(mid_t mod_id, int CC_id) { - return ((eNB_RRC_INST *)enb_rrc[mod_id])->carrier[CC_id].sizeof_SIB1; +uint8_t flexran_get_sib1_length(mid_t mod_id, uint8_t cc_id) +{ + if (!rrc[mod_id]) return 0; + return rrc[mod_id]->carrier[cc_id].sizeof_SIB1; } -int flexran_get_num_pdcch_symb(mid_t mod_id, int CC_id) { - /* TODO: This should return the number of PDCCH symbols initially used by the cell CC_id */ - return 0; - //(PHY_vars_UE_g[mod_id][CC_id]->lte_ue_pdcch_vars[mod_id]->num_pdcch_symbols); +uint8_t flexran_get_num_pdcch_symb(mid_t mod_id, uint8_t cc_id) { + /* TODO: This should return the number of PDCCH symbols initially used by the + * cell cc_id -> is the correction right? */ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->pdcch_vars[0].num_pdcch_symbols; + //(PHY_vars_UE_g[mod_id][cc_id]->lte_ue_pdcch_vars[mod_id]->num_pdcch_symbols); } @@ -687,98 +574,86 @@ int flexran_get_num_pdcch_symb(mid_t mod_id, int CC_id) { */ -int flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +TimeAlignmentTimer_t flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.mac_MainConfig != NULL) { - return ue_context_p->ue_context.mac_MainConfig->timeAlignmentTimerDedicated; - } else { - return -1; - } - } else { + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.mac_MainConfig) return -1; + return ue_context_p->ue_context.mac_MainConfig->timeAlignmentTimerDedicated; +} + +Protocol__FlexMeasGapConfigPattern flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; + + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.measGapConfig) return -1; + if (ue_context_p->ue_context.measGapConfig->present != MeasGapConfig_PR_setup) return -1; + switch (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present) { + case MeasGapConfig__setup__gapOffset_PR_gp0: + return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP1; + case MeasGapConfig__setup__gapOffset_PR_gp1: + return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP2; + default: + return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF; + } +} + + +long flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; + + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.measGapConfig) return -1; + if (ue_context_p->ue_context.measGapConfig->present != MeasGapConfig_PR_setup) return -1; + switch (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present) { + case MeasGapConfig__setup__gapOffset_PR_gp0: + return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.choice.gp0; + case MeasGapConfig__setup__gapOffset_PR_gp1: + return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.choice.gp1; + default: return -1; } } -int flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +/* TODO is there a reason we take the RNTI and not the UE ID? */ +/* TODO return type is unsigned, so we cannot return -1 in case of error! */ +uint8_t flexran_get_rrc_status(mid_t mod_id, rnti_t rnti) +{ + if (!rrc[mod_id]) return 0; - if (eNB_rrc_inst_not_ready()) return -1; + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.measGapConfig != NULL) { - if(ue_context_p->ue_context.measGapConfig->present == MeasGapConfig_PR_setup) { - if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp0) { - return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP1; - } else if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp1) { - return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP2; - } else { - return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF; - } - } - } - } - return -1; + if (!ue_context_p) return RRC_INACTIVE; + return ue_context_p->ue_context.Status; } - -int flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.measGapConfig != NULL){ - if(ue_context_p->ue_context.measGapConfig->present == MeasGapConfig_PR_setup) { - if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp0) { - return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.choice.gp0; - } else if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp1) { - return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.choice.gp0; - } - } - } - } - return -1; +uint64_t flexran_get_ue_aggregated_max_bitrate_dl(mid_t mod_id, mid_t ue_id) +{ + if (!UE_list[mod_id]) return 0; + return UE_list[mod_id]->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateDL; } - -int flexran_get_rrc_status(const mid_t mod_id, const rnti_t rntiP){ - - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - - if (ue_context_p != NULL) { - return(ue_context_p->ue_context.Status); - } else { - return RRC_INACTIVE; - } - +uint64_t flexran_get_ue_aggregated_max_bitrate_ul(mid_t mod_id, mid_t ue_id) +{ + if (!UE_list[mod_id]) return 0; + return UE_list[mod_id]->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateUL; } -int flexran_get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id) { - if (enb_ue[mod_id] == NULL) return 0; - return ((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateDL; -} - -int flexran_get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id) { - if (enb_ue[mod_id] == NULL) return 0; - return ((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateUL; -} - -int flexran_get_half_duplex(mid_t ue_id) { +int flexran_get_half_duplex(mid_t ue_id) +{ +#warning "Implement flexran_get_half_duplex() in RAN API" // TODO //int halfduplex = 0; //int bands_to_scan = ((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.count; @@ -790,14 +665,18 @@ int flexran_get_half_duplex(mid_t ue_id) { return 0; } -int flexran_get_intra_sf_hopping(mid_t ue_id) { +int flexran_get_intra_sf_hopping(mid_t ue_id) +{ +#warning "Implement flexran_get_intra_sf_hopping() in RAN API" //TODO:Get proper value //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); //return (0 & ( 1 << (31))); return 0; } -int flexran_get_type2_sb_1(mid_t ue_id) { +int flexran_get_type2_sb_1(mid_t ue_id) +{ +#warning "Implement flexran_get_type2_sb_1() in RAN API" //TODO:Get proper value //uint8_t temp = 0; //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); @@ -805,13 +684,17 @@ int flexran_get_type2_sb_1(mid_t ue_id) { return 0; } -int flexran_get_ue_category(mid_t ue_id) { +int flexran_get_ue_category(mid_t ue_id) +{ +#warning "Implement flexran_get_ue_category() in RAN API" //TODO:Get proper value //return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->ue_Category); return 0; } -int flexran_get_res_alloc_type1(mid_t ue_id) { +int flexran_get_res_alloc_type1(mid_t ue_id) +{ +#warning "Implement flexran_get_res_alloc_type1() in RAN API" //TODO:Get proper value //uint8_t temp = 0; //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); @@ -819,313 +702,291 @@ int flexran_get_res_alloc_type1(mid_t ue_id) { return 0; } -int flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +long flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode; - } else { - return -1; - } - } else { - return -1; - } + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated->antennaInfo) return -1; + return ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode; } -int flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +BOOLEAN_t flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.mac_MainConfig != NULL){ - return ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config->ttiBundling; - } else { - return -1; - } - } - else { - return -1; - } + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.mac_MainConfig) return -1; + if (!ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config) return -1; + return ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config->ttiBundling; } -int flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +long flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.mac_MainConfig != NULL){ - return *ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config->maxHARQ_Tx; - } - } - return -1; + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.mac_MainConfig) return -1; + if (!ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config) return -1; + return *(ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config->maxHARQ_Tx); } -int flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +long flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_ACK_Index; - } else { - return -1; - } - } else { - return -1; - } + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated) return -1; + return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_ACK_Index; } -int flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +long flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index; - } else { - return -1; - } - } else { - return -1; - } + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated) return -1; + return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index; } -int flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +long flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index; - } else { - return -1; - } - } - else { - return -1; - } + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated) return -1; + return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index; } -int flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +BOOLEAN_t flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - if (ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic != NULL) { - return ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.simultaneousAckNackAndCQI; - } - } - } - return -1; + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic) return -1; + return ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.simultaneousAckNackAndCQI; } -int flexran_get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id) { - - if (eNB_rrc_inst_not_ready()) return -1; - - return (&eNB_rrc_inst[mod_id])->carrier[0].sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; +BOOLEAN_t flexran_get_ack_nack_simultaneous_trans(mid_t mod_id, mid_t ue_id, uint8_t cc_id) +{ + if (!rrc[mod_id]) return -1; + if (!rrc[mod_id]->carrier[cc_id].sib2) return -1; + return rrc[mod_id]->carrier[cc_id].sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; } -int flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +CQI_ReportModeAperiodic_t flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return *ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic; - } - } - return -1; + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig) return -1; + return *ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic; } -int flexran_get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) { - // TODO: This needs fixing - return -1; +long flexran_get_tdd_ack_nack_feedback_mode(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - /* if (eNB_rrc_inst_not_ready()) return -1; */ + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); - /* struct rrc_eNB_ue_context_s* ue_context_p = NULL; */ - /* uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); */ - - /* ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); */ - - /* if(ue_context_p != NULL) { */ - /* if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ */ - /* return ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode; */ - /* } else { */ - /* return -1; */ - /* } */ - /* } else { */ - /* return -1; */ - /* } */ + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode) return -1; + return *(ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode); } -int flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +long flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->ackNackRepetition.choice.setup.repetitionFactor; - } else { - return -1; - } - } else { - return -1; - } + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated) return -1; + return ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->ackNackRepetition.choice.setup.repetitionFactor; } -int flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id) { - //TODO: need to double check - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +long flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.mac_MainConfig != NULL){ - if(ue_context_p->ue_context.mac_MainConfig->ext2 != NULL){ - long val = (*(ue_context_p->ue_context.mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10)); - if (val > 0) { - return 1; - } - } - } - } - return -1; + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.mac_MainConfig) return -1; + if (!ue_context_p->ue_context.mac_MainConfig->ext2) return -1; + if (!ue_context_p->ue_context.mac_MainConfig->ext2->mac_MainConfig_v1020) return -1; + return *(ue_context_p->ue_context.mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10); } -int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - if(ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup == AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_closedLoop) { - return 2; - } else if(ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup == AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_openLoop) { - return 1; - } else { - return 0; - } - } else { - return -1; - } - } else { - return -1; - } -} - -int flexran_get_lcg(mid_t ue_id, mid_t lc_id) { - if (UE_mac_inst == NULL) { - return -1; - } - if(UE_mac_inst[ue_id].logicalChannelConfig[lc_id] != NULL) { - return *UE_mac_inst[ue_id].logicalChannelConfig[lc_id]->ul_SpecificParameters->logicalChannelGroup; - } else { - return -1; - } -} - -int flexran_get_direction(mid_t ue_id, mid_t lc_id) { - /*TODO: fill with the value for the rest of LCID*/ - if(lc_id == DCCH || lc_id == DCCH1) { + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; + if (!ue_context_p->ue_context.physicalConfigDedicated->antennaInfo) return -1; + switch (ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup) { + case AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_closedLoop: return 2; - } else if(lc_id == DTCH) { + case AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_openLoop: return 1; - } else { + default: + return 0; + } +} + +long flexran_get_lcg(mid_t ue_id, mid_t lc_id) +{ + if (!UE_mac_inst) return -1; + if (!UE_mac_inst[ue_id].logicalChannelConfig[lc_id]) return -1; + if (!UE_mac_inst[ue_id].logicalChannelConfig[lc_id]->ul_SpecificParameters) return -1; + if (!UE_mac_inst[ue_id].logicalChannelConfig[lc_id]->ul_SpecificParameters->logicalChannelGroup) return -1; + return *(UE_mac_inst[ue_id].logicalChannelConfig[lc_id]->ul_SpecificParameters->logicalChannelGroup); +} + +int flexran_get_direction(mid_t ue_id, mid_t lc_id) +{ + /* TODO: fill with the value for the rest of LCID -> Robert: What does that + * mean? */ + switch (lc_id) { + case DCCH: + case DCCH1: + return 2; + case DTCH: + return 1; + default: return -1; } } -int flexran_get_antenna_ports(mid_t mod_id, int CC_id){ - - LTE_DL_FRAME_PARMS *frame_parms; - - if (mac_xface_not_ready()) return 0; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return (frame_parms == NULL)? 0:frame_parms->nb_antenna_ports_eNB; - +uint8_t flexran_get_antenna_ports(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.nb_antenna_ports_eNB; } - -uint32_t flexran_agent_get_operating_dl_freq (mid_t mod_id, int cc_id) { - - return (enb_properties->properties[mod_id]->downlink_frequency[cc_id] / 1000000); +/* TODO better give real value (without division)? */ +uint32_t flexran_agent_get_operating_dl_freq(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.dl_CarrierFreq / 1000000; } -uint32_t flexran_agent_get_operating_ul_freq (mid_t mod_id, int cc_id) { - return ((enb_properties->properties[mod_id]->downlink_frequency[cc_id] + enb_properties->properties[0]->uplink_frequency_offset[cc_id]) / 1000000); +/* TODO better give real value (without division)? */ +uint32_t flexran_agent_get_operating_ul_freq(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.ul_CarrierFreq / 1000000; } -int flexran_agent_get_operating_eutra_band (mid_t mod_id, int cc_id) { - return enb_properties->properties[mod_id]->eutra_band[cc_id]; -} -int flexran_agent_get_operating_pdsch_refpower (mid_t mod_id, int cc_id) { - return enb_properties->properties[mod_id]->pdsch_referenceSignalPower[cc_id]; -} -int flexran_agent_get_operating_pusch_p0 (mid_t mod_id, int cc_id) { - return enb_properties->properties[mod_id]->pusch_p0_Nominal[cc_id]; +uint8_t flexran_agent_get_operating_eutra_band(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.eutra_band; } -void flexran_agent_set_operating_dl_freq (mid_t mod_id, int cc_id, uint32_t dl_freq_mhz) { - - enb_properties->properties[mod_id]->downlink_frequency[cc_id]=dl_freq_mhz * 1000000; - /*printf("[ENB_APP] mod id %d ccid %d dl freq %d/%d\n", mod_id, cc_id, dl_freq_mhz, enb_properties->properties[mod_id]->downlink_frequency[cc_id]); */ +int8_t flexran_agent_get_operating_pdsch_refpower(mid_t mod_id, uint8_t cc_id) +{ + if (!phy[mod_id][cc_id]) return 0; + return phy[mod_id][cc_id]->frame_parms.pdsch_config_common.referenceSignalPower; } -void flexran_agent_set_operating_ul_freq (mid_t mod_id, int cc_id, int32_t ul_freq_offset_mhz) { - enb_properties->properties[mod_id]->uplink_frequency_offset[cc_id]=ul_freq_offset_mhz * 1000000; -} -//TBD -void flexran_agent_set_operating_eutra_band (mid_t mod_id, int cc_id) { - enb_properties->properties[mod_id]->eutra_band[cc_id]=7; +long flexran_agent_get_operating_pusch_p0(mid_t mod_id, uint8_t cc_id) +{ + if (!rrc[mod_id]) return 0; + return rrc[mod_id]->configuration.pusch_p0_Nominal[cc_id]; } -void flexran_agent_set_operating_bandwidth (mid_t mod_id, int cc_id, int bandwidth) { - enb_properties->properties[mod_id]->N_RB_DL[cc_id]=bandwidth; +void flexran_agent_set_operating_dl_freq(mid_t mod_id, uint8_t cc_id, uint32_t dl_freq_mhz) +{ + if (phy[mod_id][cc_id]) { + phy[mod_id][cc_id]->frame_parms.dl_CarrierFreq = dl_freq_mhz * 1000000; + } + if (rrc[mod_id]) { + rrc[mod_id]->configuration.downlink_frequency[cc_id] = dl_freq_mhz * 1000000; + } } -void flexran_agent_set_operating_frame_type (mid_t mod_id, int cc_id, int frame_type) { - enb_properties->properties[mod_id]->frame_type[cc_id]=frame_type; +void flexran_agent_set_operating_ul_freq(mid_t mod_id, uint8_t cc_id, int32_t ul_freq_mhz_offset) +{ + if (phy[mod_id][cc_id]) { + uint32_t new_ul_freq_mhz = flexran_agent_get_operating_dl_freq(mod_id, cc_id) + ul_freq_mhz_offset; + phy[mod_id][cc_id]->frame_parms.ul_CarrierFreq = new_ul_freq_mhz * 1000000; + } + if (rrc[mod_id]) { + rrc[mod_id]->configuration.uplink_frequency_offset[cc_id] = ul_freq_mhz_offset; + } +} + +void flexran_agent_set_operating_eutra_band(mid_t mod_id, uint8_t cc_id, uint8_t eutra_band) +{ + if (phy[mod_id][cc_id]) { + phy[mod_id][cc_id]->frame_parms.eutra_band = eutra_band; + } + if (rrc[mod_id]) { + rrc[mod_id]->configuration.eutra_band[cc_id] = eutra_band; + } +} + +/* Sets both DL/UL */ +void flexran_agent_set_operating_bandwidth(mid_t mod_id, uint8_t cc_id, uint8_t N_RB) +{ + if (phy[mod_id][cc_id]) { + phy[mod_id][cc_id]->frame_parms.N_RB_DL = N_RB; + phy[mod_id][cc_id]->frame_parms.N_RB_UL = N_RB; + } + if (rrc[mod_id]) { + rrc[mod_id]->configuration.N_RB_DL[cc_id] = N_RB; + } +} + +void flexran_agent_set_operating_frame_type(mid_t mod_id, uint8_t cc_id, lte_frame_type_t frame_type) +{ + if (phy[mod_id][cc_id]) { + phy[mod_id][cc_id]->frame_parms.frame_type = frame_type; + } + if (rrc[mod_id]) { + rrc[mod_id]->configuration.frame_type[cc_id] = frame_type; + } } /*********** PDCP *************/ @@ -1234,192 +1095,99 @@ uint32_t flexran_get_pdcp_rx_oo(const mid_t mod_id, const mid_t ue_id, const lc /******************** RRC *****************************/ -int flexran_get_rrc_pcell_measid(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +MeasId_t flexran_get_rrc_pcell_measid(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.measResults != NULL) { - return ue_context_p->ue_context.measResults->measId; - } else { - return -1; - } - } else { - return -1; - } + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.measResults) return -1; + return ue_context_p->ue_context.measResults->measId; } -int flexran_get_rrc_pcell_rsrp(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - if (eNB_rrc_inst_not_ready()) return -1; +float flexran_get_rrc_pcell_rsrp(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.measResults != NULL) { - return RSRP_meas_mapping[ue_context_p->ue_context.measResults->measResultPCell.rsrpResult]; - } else { - return -1; - } - } else { - return -1; - } + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.measResults) return -1; + return RSRP_meas_mapping[ue_context_p->ue_context.measResults->measResultPCell.rsrpResult]; } -int flexran_get_rrc_pcell_rsrq(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - if (eNB_rrc_inst_not_ready()) return -1; +float flexran_get_rrc_pcell_rsrq(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return -1; - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.measResults != NULL) { - return RSRQ_meas_mapping[ue_context_p->ue_context.measResults->measResultPCell.rsrqResult]; - } else { - return -1; - } - } else { - return -1; - } + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.measResults) return -1; + return RSRQ_meas_mapping[ue_context_p->ue_context.measResults->measResultPCell.rsrqResult]; } /*Number of neighbouring cells for specific UE*/ -int flexran_get_rrc_num_ncell(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +int flexran_get_rrc_num_ncell(mid_t mod_id, mid_t ue_id) +{ + if (!rrc[mod_id]) return 0; - if (eNB_rrc_inst_not_ready()) return 0; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); - if (ue_context_p->ue_context.measResults != NULL){ - - if(ue_context_p->ue_context.measResults->measResultNeighCells != NULL) { - - if (ue_context_p->ue_context.measResults->measResultNeighCells->present == MeasResults__measResultNeighCells_PR_measResultListEUTRA) { - - return ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.count; - } - else{ - - return 0; - } - - } else { - - return 0; - } - - } else { - - return 0; - - } - - } else { - return 0; - } - + if (!ue_context_p) return 0; + if (!ue_context_p->ue_context.measResults) return 0; + if (!ue_context_p->ue_context.measResults->measResultNeighCells) return 0; + if (ue_context_p->ue_context.measResults->measResultNeighCells->present != MeasResults__measResultNeighCells_PR_measResultListEUTRA) return 0; + return ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.count; } -int flexran_get_rrc_neigh_phy_cell_id(mid_t mod_id, mid_t ue_id, int cell_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +PhysCellId_t flexran_get_rrc_neigh_phy_cell_id(mid_t mod_id, mid_t ue_id, int cell_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.measResults->measResultNeighCells != NULL) { + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); - if (ue_context_p->ue_context.measResults->measResultNeighCells->present == MeasResults__measResultNeighCells_PR_measResultListEUTRA) { - - return ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->physCellId; - - } - else { - - return -1; - } - } else { - return -1; - } - } else { - return -1; - } + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.measResults) return -1; + if (!ue_context_p->ue_context.measResults->measResultNeighCells) return -1; + if (ue_context_p->ue_context.measResults->measResultNeighCells->present != MeasResults__measResultNeighCells_PR_measResultListEUTRA) return -1; + if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]) return -1; + return ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->physCellId; } -int flexran_get_rrc_neigh_rsrp(mid_t mod_id, mid_t ue_id, int cell_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +float flexran_get_rrc_neigh_rsrp(mid_t mod_id, mid_t ue_id, int cell_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); - if(ue_context_p->ue_context.measResults->measResultNeighCells != NULL) { - - if (ue_context_p->ue_context.measResults->measResultNeighCells->present == MeasResults__measResultNeighCells_PR_measResultListEUTRA) { - - if (ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrpResult){ - return RSRP_meas_mapping[*(ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrpResult)]; - - } - else { - - return 0; - } - - } - else { - - return -1; - } - - } - else { - return -1; - } - - } - else { - return -1; - } + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.measResults) return -1; + if (!ue_context_p->ue_context.measResults->measResultNeighCells) return -1; + if (ue_context_p->ue_context.measResults->measResultNeighCells->present != MeasResults__measResultNeighCells_PR_measResultListEUTRA) return -1; + if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]) return -1; + if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrpResult) return 0; + return RSRP_meas_mapping[*(ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrpResult)]; } -int flexran_get_rrc_neigh_rsrq(mid_t mod_id, mid_t ue_id, int cell_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); +float flexran_get_rrc_neigh_rsrq(mid_t mod_id, mid_t ue_id, int cell_id) +{ + if (!rrc[mod_id]) return -1; - if (eNB_rrc_inst_not_ready()) return -1; - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.measResults->measResultNeighCells != NULL) { - if (ue_context_p->ue_context.measResults->measResultNeighCells->present == MeasResults__measResultNeighCells_PR_measResultListEUTRA) { + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); - if (ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrqResult){ - return RSRQ_meas_mapping[*(ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrqResult)]; - - } - else { - - return 0; - } - } - else { - - return -1; - } - } else { - return -1; - } - } else { - return -1; - } + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.measResults) return -1; + if (!ue_context_p->ue_context.measResults->measResultNeighCells) return -1; + if (ue_context_p->ue_context.measResults->measResultNeighCells->present != MeasResults__measResultNeighCells_PR_measResultListEUTRA) return -1; + if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrqResult) return 0; + return RSRQ_meas_mapping[*(ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrqResult)]; } diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 05c6817136..6dc6fba377 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -50,23 +50,23 @@ * get generic info from RAN ****************************/ -void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran); +void flexran_set_RC_vars(mid_t mod_id, ran_name_t ran); -int flexran_get_current_time_ms (mid_t mod_id, int subframe_flag); +uint32_t flexran_get_current_time_ms(mid_t mod_id, int subframe_flag); /*Return the current frame number *Could be using implementation specific numbering of frames */ -unsigned int flexran_get_current_frame(mid_t mod_id); +frame_t flexran_get_current_frame(mid_t mod_id); /*Return the current SFN (0-1023)*/ -unsigned int flexran_get_current_system_frame_num(mid_t mod_id); +frame_t flexran_get_current_system_frame_num(mid_t mod_id); -unsigned int flexran_get_current_subframe(mid_t mod_id); +sub_frame_t flexran_get_current_subframe(mid_t mod_id); /*Return the frame and subframe number in compact 16-bit format. Bits 0-3 subframe, rest for frame. Required by FlexRAN protocol*/ -uint16_t flexran_get_sfn_sf (mid_t mod_id); +uint16_t flexran_get_sfn_sf(mid_t mod_id); /* Return a future frame and subframe number that is ahead_of_time subframes later in compact 16-bit format. Bits 0-3 subframe, @@ -77,144 +77,151 @@ uint16_t flexran_get_future_sfn_sf(mid_t mod_id, int ahead_of_time); int flexran_get_num_ues(mid_t mod_id); /* Get the rnti of a UE with id ue_id */ -int flexran_get_ue_crnti (mid_t mod_id, mid_t ue_id); +rnti_t flexran_get_ue_crnti(mid_t mod_id, mid_t ue_id); /* Get the RLC buffer status report of a ue for a designated logical channel id */ -int flexran_get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid); +uint8_t flexran_get_ue_bsr(mid_t mod_id, mid_t ue_id, lcid_t lcid); /* Get power headroom of UE with id ue_id */ -int flexran_get_ue_phr (mid_t mod_id, mid_t ue_id); +int8_t flexran_get_ue_phr(mid_t mod_id, mid_t ue_id); /* Get the UE wideband CQI */ -int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id); +uint8_t flexran_get_ue_wcqi(mid_t mod_id, mid_t ue_id); /* Get the transmission queue size for a UE with a channel_id logical channel id */ -int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); +rlc_buffer_occupancy_t flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); /*Get number of pdus in RLC buffer*/ -int flexran_get_num_pdus_buffer(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); +rlc_buffer_occupancy_t flexran_get_num_pdus_buffer(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); /* Get the head of line delay for a UE with a channel_id logical channel id */ -int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); +frame_t flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); /* Check the status of the timing advance for a UE */ -short flexran_get_TA(mid_t mod_id, mid_t ue_id, int CC_id); +int32_t flexran_get_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id); -/* Update the timing advance status (find out whether a timing advance command is required) */ -void flexran_update_TA(mid_t mod_id, mid_t ue_id, int CC_id); +/* Update the timing advance status(find out whether a timing advance command is required) */ +/* currently broken +void flexran_update_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id); */ /* Return timing advance MAC control element for a designated cell and UE */ -int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id, int CC_id); +/* this function is broken */ +int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id); /* Get the number of active component carriers for a specific UE */ int flexran_get_active_CC(mid_t mod_id, mid_t ue_id); /* Get the rank indicator for a designated cell and UE */ -int flexran_get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id); +uint8_t flexran_get_current_RI(mid_t mod_id, mid_t ue_id, uint8_t cc_id); /* See TS 36.213, section 10.1 */ -int flexran_get_n1pucch_an(mid_t mod_id, int CC_id); +uint16_t flexran_get_n1pucch_an(mid_t mod_id, uint8_t cc_id); /* See TS 36.211, section 5.4 */ -int flexran_get_nRB_CQI(mid_t mod_id, int CC_id); +uint8_t flexran_get_nRB_CQI(mid_t mod_id, uint8_t cc_id); /* See TS 36.211, section 5.4 */ -int flexran_get_deltaPUCCH_Shift(mid_t mod_id, int CC_id); +uint8_t flexran_get_deltaPUCCH_Shift(mid_t mod_id, uint8_t cc_id); /* See TS 36.211, section 5.7.1 */ -int flexran_get_prach_ConfigIndex(mid_t mod_id, int CC_id); +uint8_t flexran_get_prach_ConfigIndex(mid_t mod_id, uint8_t cc_id); /* See TS 36.211, section 5.7.1 */ -int flexran_get_prach_FreqOffset(mid_t mod_id, int CC_id); +uint8_t flexran_get_prach_FreqOffset(mid_t mod_id, uint8_t cc_id); /* See TS 36.321 */ -int flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id); +uint8_t flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, uint8_t cc_id); /* Get the length of the UL cyclic prefix */ -int flexran_get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id); +lte_prefix_type_t flexran_get_ul_cyclic_prefix_length(mid_t mod_id, uint8_t cc_id); /* Get the length of the DL cyclic prefix */ -int flexran_get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id); +lte_prefix_type_t flexran_get_dl_cyclic_prefix_length(mid_t mod_id, uint8_t cc_id); /* Get the physical cell id of a cell */ -int flexran_get_cell_id(mid_t mod_id, int CC_id); +uint16_t flexran_get_cell_id(mid_t mod_id, uint8_t cc_id); /* See TS 36.211, section 5.5.3.2 */ -int flexran_get_srs_BandwidthConfig(mid_t mod_id, int CC_id); +uint8_t flexran_get_srs_BandwidthConfig(mid_t mod_id, uint8_t cc_id); /* See TS 36.211, table 5.5.3.3-1 and 2 */ -int flexran_get_srs_SubframeConfig(mid_t mod_id, int CC_id); +uint8_t flexran_get_srs_SubframeConfig(mid_t mod_id, uint8_t cc_id); /* Boolean value. See TS 36.211, section 5.5.3.2. TDD only */ -int flexran_get_srs_MaxUpPts(mid_t mod_id, int CC_id); +uint8_t flexran_get_srs_MaxUpPts(mid_t mod_id, uint8_t cc_id); /* Get number of DL resource blocks */ -int flexran_get_N_RB_DL(mid_t mod_id, int CC_id); +uint8_t flexran_get_N_RB_DL(mid_t mod_id, uint8_t cc_id); /* Get number of UL resource blocks */ -int flexran_get_N_RB_UL(mid_t mod_id, int CC_id); +uint8_t flexran_get_N_RB_UL(mid_t mod_id, uint8_t cc_id); /* Get number of resource block groups */ -int flexran_get_N_RBG(mid_t mod_id, int CC_id); +uint8_t flexran_get_N_RBG(mid_t mod_id, uint8_t cc_id); /* Get DL/UL subframe assignment. TDD only */ -int flexran_get_subframe_assignment(mid_t mod_id, int CC_id); +uint8_t flexran_get_subframe_assignment(mid_t mod_id, uint8_t cc_id); /* TDD only. See TS 36.211, table 4.2.1 */ -int flexran_get_special_subframe_assignment(mid_t mod_id, int CC_id); +uint8_t flexran_get_special_subframe_assignment(mid_t mod_id, uint8_t cc_id); /* Get the duration of the random access response window in subframes */ -int flexran_get_ra_ResponseWindowSize(mid_t mod_id, int CC_id); +long flexran_get_ra_ResponseWindowSize(mid_t mod_id, uint8_t cc_id); /* Get timer used for random access */ -int flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id); +long flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, uint8_t cc_id); -/* Get type of duplex mode (FDD/TDD) */ -int flexran_get_duplex_mode(mid_t mod_id, int CC_id); +/* Get type of duplex mode(FDD/TDD) */ +Protocol__FlexDuplexMode flexran_get_duplex_mode(mid_t mod_id, uint8_t cc_id); /* Get the SI window length */ -long flexran_get_si_window_length(mid_t mod_id, int CC_id); +long flexran_get_si_window_length(mid_t mod_id, uint8_t cc_id); + +/* Get length of SystemInformationBlock1 */ +uint8_t flexran_get_sib1_length(mid_t mod_id, uint8_t cc_id); /* Get the number of PDCCH symbols configured for the cell */ -int flexran_get_num_pdcch_symb(mid_t mod_id, int CC_id); +uint8_t flexran_get_num_pdcch_symb(mid_t mod_id, uint8_t cc_id); -int flexran_get_antenna_ports(mid_t mod_id, int CC_id); +uint8_t flexran_get_antenna_ports(mid_t mod_id, uint8_t cc_id); /* See TS 36.213, sec 5.1.1.1 */ -int flexran_get_tpc(mid_t mod_id, mid_t ue_id); +int flexran_get_tpc(mid_t mod_id, mid_t ue_id, uint8_t cc_id); -int flexran_get_ue_pmi(mid_t mod_id); +uint8_t flexran_get_ue_wpmi(mid_t mod_id, mid_t ue_id, uint8_t cc_id); /* Get the first available HARQ process for a specific cell and UE during a designated frame and subframe. Returns 0 for success. The id and the status of the HARQ process are stored in id and status respectively */ -int flexran_get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, - const int frame, const uint8_t subframe, unsigned char *id, unsigned char *round,const uint8_t harq_flag); +/* currently broken +int flexran_get_harq(mid_t mod_id, uint8_t cc_id, mid_t ue_id, frame_t frame, + sub_frame_t subframe, unsigned char *id, unsigned char *round, + uint8_t harq_flag); */ /* Uplink power control management*/ -int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id); +int32_t flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, uint8_t cc_id); -int flexran_get_p0_nominal_pucch(mid_t mod_id, int CC_id); +int8_t flexran_get_p0_nominal_pucch(mid_t mod_id, uint8_t cc_id); -int flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, int CC_id); +int32_t flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, uint8_t cc_id); -int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id); +int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, uint8_t cc_id); -int flexran_get_threequarter_fs(mid_t mod_id, int CC_id); +uint8_t flexran_get_threequarter_fs(mid_t mod_id, uint8_t cc_id); -int flexran_get_hopping_mode(mid_t mod_id, int CC_id); +PUSCH_HOPPING_t flexran_get_hopping_mode(mid_t mod_id, uint8_t cc_id); -int flexran_get_hopping_offset(mid_t mod_id, int CC_id); +uint8_t flexran_get_hopping_offset(mid_t mod_id, uint8_t cc_id); -int flexran_get_n_SB(mid_t mod_id, int CC_id); +uint8_t flexran_get_n_SB(mid_t mod_id, uint8_t cc_id); -int flexran_get_phich_resource(mid_t mod_id, int CC_id); +int flexran_get_phich_resource(mid_t mod_id, uint8_t cc_id); -int flexran_get_enable64QAM(mid_t mod_id, int CC_id); +uint8_t flexran_get_enable64QAM(mid_t mod_id, uint8_t cc_id); -int flexran_get_phich_duration(mid_t mod_id, int CC_id); +PHICH_DURATION_t flexran_get_phich_duration(mid_t mod_id, uint8_t cc_id); /* * ************************************ @@ -225,119 +232,124 @@ int flexran_get_phich_duration(mid_t mod_id, int CC_id); /* Get timer in subframes. Controls the synchronization status of the UE, not the actual timing advance procedure. See TS 36.321 */ -int flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id); +TimeAlignmentTimer_t flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id); /* Get measurement gap configuration. See TS 36.133 */ -int flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id); +Protocol__FlexMeasGapConfigPattern flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id); /* Get measurement gap configuration offset if applicable */ -int flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id); +long flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id); /* DL aggregated bit-rate of non-gbr bearer per UE. See TS 36.413 */ -int flexran_get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id); +uint64_t flexran_get_ue_aggregated_max_bitrate_dl(mid_t mod_id, mid_t ue_id); /* UL aggregated bit-rate of non-gbr bearer per UE. See TS 36.413 */ -int flexran_get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id); +uint64_t flexran_get_ue_aggregated_max_bitrate_ul(mid_t mod_id, mid_t ue_id); /* Only half-duplex support. FDD operation. Boolean value */ -int flexran_get_half_duplex(mid_t ue_id); +/* currently broken +int flexran_get_half_duplex(mid_t ue_id); */ /* Support of intra-subframe hopping. Boolean value */ -int flexran_get_intra_sf_hopping(mid_t ue_id); +/* currently broken +int flexran_get_intra_sf_hopping(mid_t ue_id); */ /* UE support for type 2 hopping with n_sb>1 */ -int flexran_get_type2_sb_1(mid_t ue_id); +/* currently broken +int flexran_get_type2_sb_1(mid_t ue_id); */ /* Get the UE category */ -int flexran_get_ue_category(mid_t ue_id); +/* currently broken +int flexran_get_ue_category(mid_t ue_id); */ /* UE support for resource allocation type 1 */ -int flexran_get_res_alloc_type1(mid_t ue_id); +/* currently broken +int flexran_get_res_alloc_type1(mid_t ue_id); */ /* Get UE transmission mode */ -int flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id); +long flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id); /* Boolean value. See TS 36.321 */ -int flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id); +BOOLEAN_t flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id); /* The max HARQ retransmission for UL. See TS 36.321 */ -int flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id); +long flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id); /* See TS 36.213 */ -int flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id); +long flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id); /* See TS 36.213 */ -int flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id); +long flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id); /* See TS 36.213 */ -int flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id); +long flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id); /* Boolean. See TS36.213, Section 10.1 */ -int flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id); +BOOLEAN_t flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id); /* Boolean. See TS 36.213, Section 8.2 */ -int flexran_get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id); +BOOLEAN_t flexran_get_ack_nack_simultaneous_trans(mid_t mod_id, mid_t ue_id, uint8_t cc_id); /* Get aperiodic CQI report mode */ -int flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id); +CQI_ReportModeAperiodic_t flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id); /* Get ACK/NACK feedback mode. TDD only */ -int flexran_get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id); +long flexran_get_tdd_ack_nack_feedback_mode(mid_t mod_id, mid_t ue_id); /* See TS36.213, section 10.1 */ -int flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id); +long flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id); /* Boolean. Extended buffer status report size */ -int flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id); +long flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id); /* Get number of UE transmission antennas */ int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id); /* Get logical channel group of a channel with id lc_id */ -int flexran_get_lcg(mid_t ue_id, mid_t lc_id); +long flexran_get_lcg(mid_t ue_id, mid_t lc_id); /* Get direction of logical channel with id lc_id */ int flexran_get_direction(mid_t ue_id, mid_t lc_id); /*Get downlink frequency*/ -uint32_t flexran_agent_get_operating_dl_freq (mid_t mod_id, int cc_id); +uint32_t flexran_agent_get_operating_dl_freq(mid_t mod_id, uint8_t cc_id); /*Get uplink frequency*/ -uint32_t flexran_agent_get_operating_ul_freq (mid_t mod_id, int cc_id); +uint32_t flexran_agent_get_operating_ul_freq(mid_t mod_id, uint8_t cc_id); /*Get eutra band*/ -int flexran_agent_get_operating_eutra_band (mid_t mod_id, int cc_id); +uint8_t flexran_agent_get_operating_eutra_band(mid_t mod_id, uint8_t cc_id); /*Get downlink ref signal power*/ -int flexran_agent_get_operating_pdsch_refpower (mid_t mod_id, int cc_id); +int8_t flexran_agent_get_operating_pdsch_refpower(mid_t mod_id, uint8_t cc_id); /*Get uplink power*/ -int flexran_agent_get_operating_pusch_p0 (mid_t mod_id, int cc_id); +long flexran_agent_get_operating_pusch_p0(mid_t mod_id, uint8_t cc_id); /*set the dl freq */ -void flexran_agent_set_operating_dl_freq (mid_t mod_id, int cc_id, uint32_t dl_freq_mhz); +void flexran_agent_set_operating_dl_freq(mid_t mod_id, uint8_t cc_id, uint32_t dl_freq_mhz); /* set the ul freq */ -void flexran_agent_set_operating_ul_freq (mid_t mod_id, int cc_id, int32_t ul_freq_offset_mhz); +void flexran_agent_set_operating_ul_freq(mid_t mod_id, uint8_t cc_id, int32_t ul_freq_mhz_offset); /*set the the band */ -void flexran_agent_set_operating_eutra_band (mid_t mod_id, int cc_id); +void flexran_agent_set_operating_eutra_band(mid_t mod_id, uint8_t cc_id, uint8_t eutra_band); -/* set the bandwidth */ -void flexran_agent_set_operating_bandwidth (mid_t mod_id, int cc_id, int bandwidth); +/* set the bandwidth (in RB) */ +void flexran_agent_set_operating_bandwidth(mid_t mod_id, uint8_t cc_id, uint8_t N_RB); /*set frame type*/ -void flexran_agent_set_operating_frame_type (mid_t mod_id, int cc_id, int frame_type); +void flexran_agent_set_operating_frame_type(mid_t mod_id, uint8_t cc_id, lte_frame_type_t frame_type); /*RRC status flexRAN*/ -int flexran_get_rrc_status(const mid_t mod_id, const rnti_t rntiP); +uint8_t flexran_get_rrc_status(const mid_t mod_id, const rnti_t rntiP); /***************************** PDCP ***********************/ @@ -399,28 +411,30 @@ uint32_t flexran_get_pdcp_rx_oo(const mid_t mod_id, const mid_t ue_id, const lc /*********************RRC**********************/ /*Get primary cell measuremeant id flexRAN*/ -int flexran_get_rrc_pcell_measid(mid_t mod_id, mid_t ue_id); +MeasId_t flexran_get_rrc_pcell_measid(mid_t mod_id, mid_t ue_id); /*Get primary cell RSRP measurement flexRAN*/ -int flexran_get_rrc_pcell_rsrp(mid_t mod_id, mid_t ue_id); +float flexran_get_rrc_pcell_rsrp(mid_t mod_id, mid_t ue_id); /*Get primary cell RSRQ measurement flexRAN*/ -int flexran_get_rrc_pcell_rsrq(mid_t mod_id, mid_t ue_id); +float flexran_get_rrc_pcell_rsrq(mid_t mod_id, mid_t ue_id); /* Get RRC neighbouring measurement */ int flexran_get_rrc_num_ncell(mid_t mod_id, mid_t ue_id); /*Get physical cell id*/ -int flexran_get_rrc_neigh_phy_cell_id(mid_t mod_id, mid_t ue_id, int cell_id); +PhysCellId_t flexran_get_rrc_neigh_phy_cell_id(mid_t mod_id, mid_t ue_id, int cell_id); /*Get RSRP of neighbouring Cell*/ -int flexran_get_rrc_neigh_rsrp(mid_t mod_id, mid_t ue_id, int cell_id); +float flexran_get_rrc_neigh_rsrp(mid_t mod_id, mid_t ue_id, int cell_id); /*Get RSRQ of neighbouring Cell*/ -int flexran_get_rrc_neigh_rsrq(mid_t mod_id, mid_t ue_id, int cell_id); +float flexran_get_rrc_neigh_rsrq(mid_t mod_id, mid_t ue_id, int cell_id); /*Get MCC PLMN identity neighbouring Cell*/ -int flexran_get_rrc_neigh_plmn_mcc(mid_t mod_id, mid_t ue_id, int cell_id); +/* currently not implemented +int flexran_get_rrc_neigh_plmn_mcc(mid_t mod_id, mid_t ue_id, int cell_id); */ /*Get MNC PLMN identity neighbouring Cell*/ -int flexran_get_rrc_neigh_plmn_mnc(mid_t mod_id, mid_t ue_id, int cell_id); \ No newline at end of file +/* currently not implemented +int flexran_get_rrc_neigh_plmn_mnc(mid_t mod_id, mid_t ue_id, int cell_id); */ From b45a340b63f0f9695d3a1d4e218a79617bf03c50 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 23 Jan 2018 15:47:40 +0100 Subject: [PATCH 174/284] RAN API: no set_RC_vars(), check use RC directly, give error messages --- openair2/ENB_APP/enb_app.c | 6 - openair2/ENB_APP/flexran_agent_ran_api.c | 419 ++++++++++++----------- openair2/ENB_APP/flexran_agent_ran_api.h | 2 - 3 files changed, 213 insertions(+), 214 deletions(-) diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index 636df458ae..3b3c8c24c7 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -342,12 +342,6 @@ void *eNB_app_task(void *args_p) enb_app_start_phy_rrc(enb_id_start, enb_id_end); -#ifdef FLEXRAN_AGENT_SB_IF - for (uint32_t enb_i = 0; enb_i <1; enb_i ++){ // To be handled for all of current eNB - flexran_set_RC_vars(enb_i, RAN_LTE_OAI); - } -#endif - # if defined(ENABLE_USE_MME) /* Try to register each eNB */ registered_enb = 0; diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index af1d1be63d..75552526a7 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -28,48 +28,35 @@ #include "flexran_agent_ran_api.h" -/* - * generic info from RAN - */ - -PHY_VARS_eNB *phy[NUM_MAX_ENB][MAX_NUM_CCs] = { NULL }; -eNB_MAC_INST *mac[NUM_MAX_ENB] = { NULL }; -eNB_RRC_INST *rrc[NUM_MAX_ENB] = { NULL }; -UE_list_t *UE_list[NUM_MAX_ENB] = { NULL }; - -void flexran_set_RC_vars(mid_t mod_id, ran_name_t ran) +static inline int phy_is_present(mid_t mod_id, uint8_t cc_id) { - int i; - if (ran == RAN_LTE_OAI) { - if (RC.eNB && mod_id < RC.nb_RU && RC.eNB[mod_id] && RC.nb_CC) - for (i = 0; i < *RC.nb_CC; i++) - phy[mod_id][i] = RC.eNB[mod_id][i]; - if (RC.mac && mod_id < RC.nb_macrlc_inst && RC.mac[mod_id]) { - mac[mod_id] = RC.mac[mod_id]; - UE_list[mod_id] = &RC.mac[mod_id]->UE_list; - } - if (RC.rrc && mod_id < RC.nb_macrlc_inst && RC.rrc[mod_id]) - rrc[mod_id] = RC.rrc[mod_id]; - } - else { - LOG_E(FLEXRAN_AGENT, "unknown RAN name %d when setting RAN API variables\n", ran); - } + return RC.eNB && RC.eNB[mod_id] && RC.eNB[mod_id][cc_id]; +} + +static inline int mac_is_present(mid_t mod_id) +{ + return RC.mac && RC.mac[mod_id]; +} + +static inline int rrc_is_present(mid_t mod_id) +{ + return RC.rrc && RC.rrc[mod_id]; } uint32_t flexran_get_current_time_ms(mid_t mod_id, int subframe_flag) { - if (!mac[mod_id]) return 0; + if (!mac_is_present(mod_id)) return 0; if (subframe_flag == 1) - return mac[mod_id]->frame*10 + mac[mod_id]->subframe; + return RC.mac[mod_id]->frame*10 + RC.mac[mod_id]->subframe; else - return mac[mod_id]->frame*10; + return RC.mac[mod_id]->frame*10; } frame_t flexran_get_current_frame(mid_t mod_id) { - if (!mac[mod_id]) return 0; + if (!mac_is_present(mod_id)) return 0; // #warning "SFN will not be in [0-1023] when oaisim is used" - return mac[mod_id]->frame; + return RC.mac[mod_id]->frame; } frame_t flexran_get_current_system_frame_num(mid_t mod_id) @@ -79,8 +66,8 @@ frame_t flexran_get_current_system_frame_num(mid_t mod_id) sub_frame_t flexran_get_current_subframe(mid_t mod_id) { - if (!mac[mod_id]) return 0; - return mac[mod_id]->subframe; + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->subframe; } /* Why uint16_t, frame_t and sub_frame_t are defined as uint32_t? */ @@ -121,8 +108,8 @@ uint16_t flexran_get_future_sfn_sf(mid_t mod_id, int ahead_of_time) int flexran_get_num_ues(mid_t mod_id) { - if (!UE_list[mod_id]) return 0; - return UE_list[mod_id]->num_UEs; + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.num_UEs; } rnti_t flexran_get_ue_crnti(mid_t mod_id, mid_t ue_id) @@ -132,20 +119,20 @@ rnti_t flexran_get_ue_crnti(mid_t mod_id, mid_t ue_id) uint8_t flexran_get_ue_bsr(mid_t mod_id, mid_t ue_id, lcid_t lcid) { - if (!UE_list[mod_id]) return 0; - return UE_list[mod_id]->UE_template[UE_PCCID(mod_id, ue_id)][ue_id].bsr_info[lcid]; + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.UE_template[UE_PCCID(mod_id, ue_id)][ue_id].bsr_info[lcid]; } int8_t flexran_get_ue_phr(mid_t mod_id, mid_t ue_id) { - if (!UE_list[mod_id]) return 0; - return UE_list[mod_id]->UE_template[UE_PCCID(mod_id, ue_id)][ue_id].phr_info; + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.UE_template[UE_PCCID(mod_id, ue_id)][ue_id].phr_info; } uint8_t flexran_get_ue_wcqi(mid_t mod_id, mid_t ue_id) { - if (!phy[mod_id][0]) return 0; - return phy[mod_id][0]->UE_stats[ue_id].DL_cqi[0]; + if (!phy_is_present(mod_id, 0)) return 0; + return RC.eNB[mod_id][0]->UE_stats[ue_id].DL_cqi[0]; } rlc_buffer_occupancy_t flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) @@ -177,9 +164,9 @@ frame_t flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t chann int32_t flexran_get_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; + if (!phy_is_present(mod_id, cc_id)) return 0; - int32_t tau = phy[mod_id][cc_id]->UE_stats[ue_id].timing_advance_update; + int32_t tau = RC.eNB[mod_id][cc_id]->UE_stats[ue_id].timing_advance_update; switch (flexran_get_N_RB_DL(mod_id, cc_id)) { case 6: return tau; @@ -203,8 +190,8 @@ int32_t flexran_get_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id) uint8_t flexran_get_ue_wpmi(mid_t mod_id, mid_t ue_id, uint8_t cc_id) { - if (!UE_list[mod_id]) return 0; - return UE_list[mod_id]->UE_sched_ctrl[ue_id].periodic_wideband_pmi[cc_id]; + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].periodic_wideband_pmi[cc_id]; } /* TODO needs to be revised */ @@ -235,7 +222,7 @@ void flexran_update_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id) int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id) { #warning "Implement flexran_get_MAC_CE_bitmap_TA() in RAN API" - if (!phy[mod_id][cc_id]) return 0; + if (!phy_is_present(mod_id, cc_id)) return 0; /* UE_stats can not be null, they are an array in RC LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); @@ -254,25 +241,25 @@ int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id) int flexran_get_active_CC(mid_t mod_id, mid_t ue_id) { - if (!UE_list[mod_id]) return 0; - return UE_list[mod_id]->numactiveCCs[ue_id]; + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.numactiveCCs[ue_id]; } uint8_t flexran_get_current_RI(mid_t mod_id, mid_t ue_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->UE_stats[ue_id].rank; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->UE_stats[ue_id].rank; } int flexran_get_tpc(mid_t mod_id, mid_t ue_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; + if (!phy_is_present(mod_id, cc_id)) return 0; /* before: tested that UL_rssi != NULL and set parameter ([0]), but it is a * static array -> target_rx_power is useless in old ifs?! */ int pCCid = UE_PCCID(mod_id,ue_id); - int32_t target_rx_power = phy[mod_id][pCCid]->frame_parms.ul_power_control_config_common.p0_NominalPUSCH; - int32_t normalized_rx_power = phy[mod_id][cc_id]->UE_stats[ue_id].UL_rssi[0]; + int32_t target_rx_power = RC.eNB[mod_id][pCCid]->frame_parms.ul_power_control_config_common.p0_NominalPUSCH; + int32_t normalized_rx_power = RC.eNB[mod_id][cc_id]->UE_stats[ue_id].UL_rssi[0]; int tpc; if (normalized_rx_power > target_rx_power + 1) @@ -334,26 +321,26 @@ int flexran_get_harq(mid_t mod_id, int32_t flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->UE_stats[ue_id].Po_PUCCH_dBm; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->UE_stats[ue_id].Po_PUCCH_dBm; } int8_t flexran_get_p0_nominal_pucch(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.ul_power_control_config_common.p0_NominalPUCCH; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.ul_power_control_config_common.p0_NominalPUCCH; } int32_t flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->UE_stats[ue_id].Po_PUCCH_update; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->UE_stats[ue_id].Po_PUCCH_update; } int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - phy[mod_id][cc_id]->UE_stats[ue_id].Po_PUCCH_update = 0; + if (!phy_is_present(mod_id, cc_id)) return 0; + RC.eNB[mod_id][cc_id]->UE_stats[ue_id].Po_PUCCH_update = 0; return 0; } @@ -365,46 +352,46 @@ int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, uint8_t cc_id) */ uint8_t flexran_get_threequarter_fs(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.threequarter_fs; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.threequarter_fs; } uint8_t flexran_get_hopping_offset(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.pusch_config_common.pusch_HoppingOffset; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.pusch_config_common.pusch_HoppingOffset; } PUSCH_HOPPING_t flexran_get_hopping_mode(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.pusch_config_common.hoppingMode; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.pusch_config_common.hoppingMode; } uint8_t flexran_get_n_SB(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.pusch_config_common.n_SB; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.pusch_config_common.n_SB; } uint8_t flexran_get_enable64QAM(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.pusch_config_common.enable64QAM; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.pusch_config_common.enable64QAM; } PHICH_DURATION_t flexran_get_phich_duration(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.phich_config_common.phich_duration; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.phich_config_common.phich_duration; } int flexran_get_phich_resource(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; + if (!phy_is_present(mod_id, cc_id)) return 0; /* TODO why don't we return phich_resource? */ - switch (phy[mod_id][cc_id]->frame_parms.phich_config_common.phich_resource) { + switch (RC.eNB[mod_id][cc_id]->frame_parms.phich_config_common.phich_resource) { case oneSixth: return 0; case half: @@ -420,122 +407,122 @@ int flexran_get_phich_resource(mid_t mod_id, uint8_t cc_id) uint16_t flexran_get_n1pucch_an(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.pucch_config_common.n1PUCCH_AN; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.pucch_config_common.n1PUCCH_AN; } uint8_t flexran_get_nRB_CQI(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.pucch_config_common.nRB_CQI; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.pucch_config_common.nRB_CQI; } uint8_t flexran_get_deltaPUCCH_Shift(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.pucch_config_common.deltaPUCCH_Shift; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.pucch_config_common.deltaPUCCH_Shift; } uint8_t flexran_get_prach_ConfigIndex(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex; } uint8_t flexran_get_prach_FreqOffset(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset; } uint8_t flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.maxHARQ_Msg3Tx; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.maxHARQ_Msg3Tx; } lte_prefix_type_t flexran_get_ul_cyclic_prefix_length(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.Ncp_UL; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.Ncp_UL; } lte_prefix_type_t flexran_get_dl_cyclic_prefix_length(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.Ncp; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.Ncp; } uint16_t flexran_get_cell_id(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.Nid_cell; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.Nid_cell; } uint8_t flexran_get_srs_BandwidthConfig(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.soundingrs_ul_config_common.srs_BandwidthConfig; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.soundingrs_ul_config_common.srs_BandwidthConfig; } uint8_t flexran_get_srs_SubframeConfig(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.soundingrs_ul_config_common.srs_SubframeConfig; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.soundingrs_ul_config_common.srs_SubframeConfig; } uint8_t flexran_get_srs_MaxUpPts(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.soundingrs_ul_config_common.srs_MaxUpPts; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.soundingrs_ul_config_common.srs_MaxUpPts; } uint8_t flexran_get_N_RB_DL(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.N_RB_DL; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.N_RB_DL; } uint8_t flexran_get_N_RB_UL(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.N_RB_UL; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.N_RB_UL; } uint8_t flexran_get_N_RBG(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.N_RBG; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.N_RBG; } uint8_t flexran_get_subframe_assignment(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.tdd_config; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.tdd_config; } uint8_t flexran_get_special_subframe_assignment(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.tdd_config_S; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.tdd_config_S; } long flexran_get_ra_ResponseWindowSize(mid_t mod_id, uint8_t cc_id) { - if (!rrc[mod_id]) return 0; - return rrc[mod_id]->configuration.rach_raResponseWindowSize[cc_id]; + if (!rrc_is_present(mod_id)) return 0; + return RC.rrc[mod_id]->configuration.rach_raResponseWindowSize[cc_id]; } long flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, uint8_t cc_id) { - if (!rrc[mod_id]) return 0; - return rrc[mod_id]->configuration.rach_macContentionResolutionTimer[cc_id]; + if (!rrc_is_present(mod_id)) return 0; + return RC.rrc[mod_id]->configuration.rach_macContentionResolutionTimer[cc_id]; } Protocol__FlexDuplexMode flexran_get_duplex_mode(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - switch (phy[mod_id][cc_id]->frame_parms.frame_type) { + if (!phy_is_present(mod_id, cc_id)) return 0; + switch (RC.eNB[mod_id][cc_id]->frame_parms.frame_type) { case TDD: return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD; case FDD: @@ -547,21 +534,21 @@ Protocol__FlexDuplexMode flexran_get_duplex_mode(mid_t mod_id, uint8_t cc_id) long flexran_get_si_window_length(mid_t mod_id, uint8_t cc_id) { - if (!rrc[mod_id] || !rrc[mod_id]->carrier[cc_id].sib1) return 0; - return rrc[mod_id]->carrier[cc_id].sib1->si_WindowLength; + if (!rrc_is_present(mod_id) || !RC.rrc[mod_id]->carrier[cc_id].sib1) return 0; + return RC.rrc[mod_id]->carrier[cc_id].sib1->si_WindowLength; } uint8_t flexran_get_sib1_length(mid_t mod_id, uint8_t cc_id) { - if (!rrc[mod_id]) return 0; - return rrc[mod_id]->carrier[cc_id].sizeof_SIB1; + if (!rrc_is_present(mod_id)) return 0; + return RC.rrc[mod_id]->carrier[cc_id].sizeof_SIB1; } uint8_t flexran_get_num_pdcch_symb(mid_t mod_id, uint8_t cc_id) { /* TODO: This should return the number of PDCCH symbols initially used by the * cell cc_id -> is the correction right? */ - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->pdcch_vars[0].num_pdcch_symbols; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->pdcch_vars[0].num_pdcch_symbols; //(PHY_vars_UE_g[mod_id][cc_id]->lte_ue_pdcch_vars[mod_id]->num_pdcch_symbols); } @@ -576,10 +563,10 @@ uint8_t flexran_get_num_pdcch_symb(mid_t mod_id, uint8_t cc_id) { TimeAlignmentTimer_t flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.mac_MainConfig) return -1; @@ -588,10 +575,10 @@ TimeAlignmentTimer_t flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id) Protocol__FlexMeasGapConfigPattern flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.measGapConfig) return -1; @@ -609,10 +596,10 @@ Protocol__FlexMeasGapConfigPattern flexran_get_meas_gap_config(mid_t mod_id, mid long flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.measGapConfig) return -1; @@ -631,9 +618,9 @@ long flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) /* TODO return type is unsigned, so we cannot return -1 in case of error! */ uint8_t flexran_get_rrc_status(mid_t mod_id, rnti_t rnti) { - if (!rrc[mod_id]) return 0; + if (!rrc_is_present(mod_id)) return 0; - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return RRC_INACTIVE; return ue_context_p->ue_context.Status; @@ -641,14 +628,14 @@ uint8_t flexran_get_rrc_status(mid_t mod_id, rnti_t rnti) uint64_t flexran_get_ue_aggregated_max_bitrate_dl(mid_t mod_id, mid_t ue_id) { - if (!UE_list[mod_id]) return 0; - return UE_list[mod_id]->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateDL; + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateDL; } uint64_t flexran_get_ue_aggregated_max_bitrate_ul(mid_t mod_id, mid_t ue_id) { - if (!UE_list[mod_id]) return 0; - return UE_list[mod_id]->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateUL; + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateUL; } int flexran_get_half_duplex(mid_t ue_id) @@ -704,10 +691,10 @@ int flexran_get_res_alloc_type1(mid_t ue_id) long flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; @@ -717,10 +704,10 @@ long flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) BOOLEAN_t flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.mac_MainConfig) return -1; if (!ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config) return -1; @@ -729,10 +716,10 @@ BOOLEAN_t flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id) long flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.mac_MainConfig) return -1; @@ -742,10 +729,10 @@ long flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) long flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; @@ -755,10 +742,10 @@ long flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) long flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; @@ -768,10 +755,10 @@ long flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) long flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; @@ -781,10 +768,10 @@ long flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) BOOLEAN_t flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; @@ -795,17 +782,17 @@ BOOLEAN_t flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) BOOLEAN_t flexran_get_ack_nack_simultaneous_trans(mid_t mod_id, mid_t ue_id, uint8_t cc_id) { - if (!rrc[mod_id]) return -1; - if (!rrc[mod_id]->carrier[cc_id].sib2) return -1; - return rrc[mod_id]->carrier[cc_id].sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; + if (!rrc_is_present(mod_id)) return -1; + if (!RC.rrc[mod_id]->carrier[cc_id].sib2) return -1; + return RC.rrc[mod_id]->carrier[cc_id].sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; } CQI_ReportModeAperiodic_t flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; @@ -815,10 +802,10 @@ CQI_ReportModeAperiodic_t flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t long flexran_get_tdd_ack_nack_feedback_mode(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; @@ -829,10 +816,10 @@ long flexran_get_tdd_ack_nack_feedback_mode(mid_t mod_id, mid_t ue_id) long flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; @@ -842,10 +829,10 @@ long flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id) long flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.mac_MainConfig) return -1; @@ -856,10 +843,10 @@ long flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id) int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.physicalConfigDedicated) return -1; @@ -900,92 +887,112 @@ int flexran_get_direction(mid_t ue_id, mid_t lc_id) uint8_t flexran_get_antenna_ports(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.nb_antenna_ports_eNB; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.nb_antenna_ports_eNB; } /* TODO better give real value (without division)? */ uint32_t flexran_agent_get_operating_dl_freq(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.dl_CarrierFreq / 1000000; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.dl_CarrierFreq / 1000000; } /* TODO better give real value (without division)? */ uint32_t flexran_agent_get_operating_ul_freq(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.ul_CarrierFreq / 1000000; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.ul_CarrierFreq / 1000000; } uint8_t flexran_agent_get_operating_eutra_band(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.eutra_band; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.eutra_band; } int8_t flexran_agent_get_operating_pdsch_refpower(mid_t mod_id, uint8_t cc_id) { - if (!phy[mod_id][cc_id]) return 0; - return phy[mod_id][cc_id]->frame_parms.pdsch_config_common.referenceSignalPower; + if (!phy_is_present(mod_id, cc_id)) return 0; + return RC.eNB[mod_id][cc_id]->frame_parms.pdsch_config_common.referenceSignalPower; } long flexran_agent_get_operating_pusch_p0(mid_t mod_id, uint8_t cc_id) { - if (!rrc[mod_id]) return 0; - return rrc[mod_id]->configuration.pusch_p0_Nominal[cc_id]; + if (!rrc_is_present(mod_id)) return 0; + return RC.rrc[mod_id]->configuration.pusch_p0_Nominal[cc_id]; } void flexran_agent_set_operating_dl_freq(mid_t mod_id, uint8_t cc_id, uint32_t dl_freq_mhz) { - if (phy[mod_id][cc_id]) { - phy[mod_id][cc_id]->frame_parms.dl_CarrierFreq = dl_freq_mhz * 1000000; + if (phy_is_present(mod_id, cc_id)) { + RC.eNB[mod_id][cc_id]->frame_parms.dl_CarrierFreq = dl_freq_mhz * 1000000; + } else { + LOG_E(FLEXRAN_AGENT, "can not set dl_CarrierFreq to %d MHz in PHY: PHY is not present\n", dl_freq_mhz); } - if (rrc[mod_id]) { - rrc[mod_id]->configuration.downlink_frequency[cc_id] = dl_freq_mhz * 1000000; + if (rrc_is_present(mod_id)) { + RC.rrc[mod_id]->configuration.downlink_frequency[cc_id] = dl_freq_mhz * 1000000; + } else { + LOG_E(FLEXRAN_AGENT, "can not set downlink_frequency to %d MHz in RRC: RRC is not present\n", dl_freq_mhz); } } void flexran_agent_set_operating_ul_freq(mid_t mod_id, uint8_t cc_id, int32_t ul_freq_mhz_offset) { - if (phy[mod_id][cc_id]) { + if (phy_is_present(mod_id, cc_id)) { uint32_t new_ul_freq_mhz = flexran_agent_get_operating_dl_freq(mod_id, cc_id) + ul_freq_mhz_offset; - phy[mod_id][cc_id]->frame_parms.ul_CarrierFreq = new_ul_freq_mhz * 1000000; + RC.eNB[mod_id][cc_id]->frame_parms.ul_CarrierFreq = new_ul_freq_mhz * 1000000; + } else { + LOG_E(FLEXRAN_AGENT, "can not set ul_CarrierFreq using offset %d MHz in PHY: PHY is not present\n", ul_freq_mhz_offset); } - if (rrc[mod_id]) { - rrc[mod_id]->configuration.uplink_frequency_offset[cc_id] = ul_freq_mhz_offset; + if (rrc_is_present(mod_id)) { + RC.rrc[mod_id]->configuration.uplink_frequency_offset[cc_id] = ul_freq_mhz_offset; + } else { + LOG_E(FLEXRAN_AGENT, "can not set uplink_frequency_offset to %d MHz in RRC: RRC is not present\n", ul_freq_mhz_offset); } } void flexran_agent_set_operating_eutra_band(mid_t mod_id, uint8_t cc_id, uint8_t eutra_band) { - if (phy[mod_id][cc_id]) { - phy[mod_id][cc_id]->frame_parms.eutra_band = eutra_band; + if (phy_is_present(mod_id, cc_id)) { + RC.eNB[mod_id][cc_id]->frame_parms.eutra_band = eutra_band; + } else { + LOG_E(FLEXRAN_AGENT, "can not set eutra_band to %d in PHY: PHY is not present\n", eutra_band); } - if (rrc[mod_id]) { - rrc[mod_id]->configuration.eutra_band[cc_id] = eutra_band; + if (rrc_is_present(mod_id)) { + RC.rrc[mod_id]->configuration.eutra_band[cc_id] = eutra_band; + } else { + LOG_E(FLEXRAN_AGENT, "can not set eutra_band to %d in RRC: RRC is not present\n", eutra_band); } } /* Sets both DL/UL */ void flexran_agent_set_operating_bandwidth(mid_t mod_id, uint8_t cc_id, uint8_t N_RB) { - if (phy[mod_id][cc_id]) { - phy[mod_id][cc_id]->frame_parms.N_RB_DL = N_RB; - phy[mod_id][cc_id]->frame_parms.N_RB_UL = N_RB; + if (phy_is_present(mod_id, cc_id)) { + RC.eNB[mod_id][cc_id]->frame_parms.N_RB_DL = N_RB; + RC.eNB[mod_id][cc_id]->frame_parms.N_RB_UL = N_RB; + } else { + LOG_E(FLEXRAN_AGENT, "can not set N_RB_DL and N_RB_UL to %d in PHY: PHY is not present\n", N_RB); } - if (rrc[mod_id]) { - rrc[mod_id]->configuration.N_RB_DL[cc_id] = N_RB; + if (rrc_is_present(mod_id)) { + RC.rrc[mod_id]->configuration.N_RB_DL[cc_id] = N_RB; + } else { + LOG_E(FLEXRAN_AGENT, "can not set N_RB_DL to %d in RRC: RRC is not present\n", N_RB); } } void flexran_agent_set_operating_frame_type(mid_t mod_id, uint8_t cc_id, lte_frame_type_t frame_type) { - if (phy[mod_id][cc_id]) { - phy[mod_id][cc_id]->frame_parms.frame_type = frame_type; + if (phy_is_present(mod_id, cc_id)) { + RC.eNB[mod_id][cc_id]->frame_parms.frame_type = frame_type; + } else { + LOG_E(FLEXRAN_AGENT, "can not set frame_type to %d in PHY: PHY is not present\n", frame_type); } - if (rrc[mod_id]) { - rrc[mod_id]->configuration.frame_type[cc_id] = frame_type; + if (rrc_is_present(mod_id)) { + RC.rrc[mod_id]->configuration.frame_type[cc_id] = frame_type; + } else { + LOG_E(FLEXRAN_AGENT, "can not set frame_type to %d in RRC: RRC is not present\n", frame_type); } } @@ -1097,10 +1104,10 @@ uint32_t flexran_get_pdcp_rx_oo(const mid_t mod_id, const mid_t ue_id, const lc MeasId_t flexran_get_rrc_pcell_measid(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.measResults) return -1; @@ -1109,10 +1116,10 @@ MeasId_t flexran_get_rrc_pcell_measid(mid_t mod_id, mid_t ue_id) float flexran_get_rrc_pcell_rsrp(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.measResults) return -1; @@ -1121,10 +1128,10 @@ float flexran_get_rrc_pcell_rsrp(mid_t mod_id, mid_t ue_id) float flexran_get_rrc_pcell_rsrq(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.measResults) return -1; @@ -1134,10 +1141,10 @@ float flexran_get_rrc_pcell_rsrq(mid_t mod_id, mid_t ue_id) /*Number of neighbouring cells for specific UE*/ int flexran_get_rrc_num_ncell(mid_t mod_id, mid_t ue_id) { - if (!rrc[mod_id]) return 0; + if (!rrc_is_present(mod_id)) return 0; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return 0; if (!ue_context_p->ue_context.measResults) return 0; @@ -1148,10 +1155,10 @@ int flexran_get_rrc_num_ncell(mid_t mod_id, mid_t ue_id) PhysCellId_t flexran_get_rrc_neigh_phy_cell_id(mid_t mod_id, mid_t ue_id, int cell_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.measResults) return -1; @@ -1163,10 +1170,10 @@ PhysCellId_t flexran_get_rrc_neigh_phy_cell_id(mid_t mod_id, mid_t ue_id, int ce float flexran_get_rrc_neigh_rsrp(mid_t mod_id, mid_t ue_id, int cell_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.measResults) return -1; @@ -1179,10 +1186,10 @@ float flexran_get_rrc_neigh_rsrp(mid_t mod_id, mid_t ue_id, int cell_id) float flexran_get_rrc_neigh_rsrq(mid_t mod_id, mid_t ue_id, int cell_id) { - if (!rrc[mod_id]) return -1; + if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(rrc[mod_id], rnti); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; if (!ue_context_p->ue_context.measResults) return -1; diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 6dc6fba377..25faa105a6 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -50,8 +50,6 @@ * get generic info from RAN ****************************/ -void flexran_set_RC_vars(mid_t mod_id, ran_name_t ran); - uint32_t flexran_get_current_time_ms(mid_t mod_id, int subframe_flag); /*Return the current frame number From a6098dbf09d5bc7caa3bd544c2594dec054a5608 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 15 Jan 2018 18:31:37 +0100 Subject: [PATCH 175/284] delete unnecessary FlexRAN source files all the FlexRAN scheduling code is now also handled by the general OAI scheduling code --- cmake_targets/CMakeLists.txt | 22 - .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 2 - openair2/LAYER2/MAC/eNB_scheduler.c | 1 - openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 2 +- openair2/LAYER2/MAC/flexran_agent_mac_proto.h | 323 --- .../MAC/flexran_agent_scheduler_dataplane.c | 583 ------ .../MAC/flexran_agent_scheduler_dlsch_ue.c | 1814 ----------------- .../flexran_agent_scheduler_dlsch_ue_remote.c | 202 -- .../flexran_agent_scheduler_dlsch_ue_remote.h | 70 - .../MAC/flexran_agent_scheduler_ulsch_ue.c | 1112 ---------- openair2/LAYER2/MAC/flexran_dci_conversions.h | 51 - 11 files changed, 1 insertion(+), 4181 deletions(-) delete mode 100644 openair2/LAYER2/MAC/flexran_agent_mac_proto.h delete mode 100644 openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c delete mode 100644 openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c delete mode 100644 openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c delete mode 100644 openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h delete mode 100644 openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c delete mode 100644 openair2/LAYER2/MAC/flexran_dci_conversions.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index da0c3fbc1f..b659819e25 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1191,17 +1191,6 @@ set (MAC_SRC ${MAC_DIR}/config.c ) -if (FLEXRAN_AGENT_SB_IF) - -set (MAC_SRC ${MAC_SRC} - ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue.c - ${MAC_DIR}/flexran_agent_scheduler_ulsch_ue.c - ${MAC_DIR}/flexran_agent_scheduler_dataplane.c - ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue_remote.c -) - -endif() - set (ENB_APP_SRC ${OPENAIR2_DIR}/ENB_APP/enb_app.c ${OPENAIR2_DIR}/ENB_APP/enb_config.c @@ -1213,17 +1202,6 @@ add_library(L2 ${ENB_APP_SRC}) # ${OPENAIR2_DIR}/RRC/L2_INTERFACE/openair_rrc_L2_interface.c) -if (FLEXRAN_AGENT_SB_IF) - -#Test for adding a shared library -add_library(default_sched SHARED ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue.c) -add_library(remote_sched SHARED ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue_remote.c) - -add_library(default_ul_sched SHARED ${MAC_DIR}/flexran_agent_scheduler_ulsch_ue.c) - - -endif() - # L3 Libs ########################## diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 02350eb0c1..d60a9eb3b7 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -35,8 +35,6 @@ #include "flexran_agent_ran_api.h" #include "LAYER2/MAC/proto.h" -#include "LAYER2/MAC/flexran_agent_mac_proto.h" -#include "LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h" #include "liblfds700.h" diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 432915eb8c..1195e05379 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -56,7 +56,6 @@ //Agent-related headers #include "flexran_agent_extern.h" #include "flexran_agent_mac.h" -#include "flexran_agent_mac_proto.h" #endif #if defined(ENABLE_ITTI) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 0d9f129fa6..a0da4f4961 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -62,7 +62,7 @@ #include "flexran_agent_ran_api.h" #include "header.pb-c.h" #include "flexran.pb-c.h" -#include "flexran_agent_mac.h" +#endif #include #endif diff --git a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h deleted file mode 100644 index be61fa1590..0000000000 --- a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file flexran_agent_mac_proto.h - * \brief MAC functions for FlexRAN agent - * \author Xenofon Foukas and Navid Nikaein - * \date 2016 - * \email: x.foukas@sms.ed.ac.uk - * \version 0.1 - * @ingroup _mac - - */ - -#ifndef __LAYER2_MAC_FLEXRAN_AGENT_MAC_PROTO_H__ -#define __LAYER2_MAC_FLEXRAN_AGENT_MAC_PROTO_H__ - -#include "flexran_agent_defs.h" -#include "header.pb-c.h" -#include "flexran.pb-c.h" - -/* - * slice specific scheduler - */ -typedef void (*slice_scheduler_dl)(module_id_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info); - -typedef void (*slice_scheduler_ul)(module_id_t mod_id, - frame_t frame, - unsigned char cooperation_flag, - uint32_t subframe, - unsigned char sched_subframe, - Protocol__FlexranMessage **ul_info); - - -/* - * top level flexran scheduler used by the eNB scheduler - */ -void flexran_schedule_ue_dl_spec_default(mid_t mod_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage ** dl_info); -/* - * slice specific scheduler for embb - */ -void -flexran_schedule_ue_spec_embb(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage ** dl_info); -/* - * slice specific scheduler for urllc - */ -void -flexran_schedule_ue_spec_urllc(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage ** dl_info); - -/* - * slice specific scheduler for mmtc - */ -void -flexran_schedule_ue_spec_mmtc(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage ** dl_info); -/* - * slice specific scheduler for best effort traffic - */ -void -flexran_schedule_ue_spec_be(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage ** dl_info); - -/* - * common flexran scheduler function - */ -void -<<<<<<< HEAD -flexran_schedule_ue_spec_common(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage ** dl_info); - -uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, int total_rbs); - -int flexran_slice_member(int UE_id, int slice_id); - -int flexran_slice_maxmcs(int slice_id); - -void _store_dlsch_buffer(module_id_t Mod_id, - int slice_id, - frame_t frameP, sub_frame_t subframeP); - - -void _assign_rbs_required(module_id_t Mod_id, - int slice_id, - frame_t frameP, - sub_frame_t subframe, - uint16_t - nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t - nb_rbs_allowed_slice[MAX_NUM_CCs] - [MAX_NUM_SLICES], int min_rb_unit[MAX_NUM_CCs]); - -void _dlsch_scheduler_pre_processor(module_id_t Mod_id, - int slice_id, - frame_t frameP, - sub_frame_t subframeP, - int N_RBG[MAX_NUM_CCs], - int *mbsfn_flag); - -void _dlsch_scheduler_pre_processor_reset(int module_idP, - int UE_id, - uint8_t CC_id, - int frameP, - int subframeP, - int N_RBG, - uint16_t - nb_rbs_required[MAX_NUM_CCs] - [NUMBER_OF_UE_MAX], - uint16_t - nb_rbs_required_remaining - [MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t - nb_rbs_allowed_slice[MAX_NUM_CCs] - [MAX_NUM_SLICES], - unsigned char - rballoc_sub[MAX_NUM_CCs] - [N_RBG_MAX], - unsigned char - MIMO_mode_indicator[MAX_NUM_CCs] - [N_RBG_MAX]); - -void _dlsch_scheduler_pre_processor_allocate(module_id_t Mod_id, - int UE_id, - uint8_t CC_id, - int N_RBG, - int transmission_mode, - int min_rb_unit, - uint8_t N_RB_DL, - uint16_t - nb_rbs_required[MAX_NUM_CCs] - [NUMBER_OF_UE_MAX], - uint16_t - nb_rbs_required_remaining - [MAX_NUM_CCs] - [NUMBER_OF_UE_MAX], - unsigned char - rballoc_sub[MAX_NUM_CCs] - [N_RBG_MAX], - unsigned char - MIMO_mode_indicator - [MAX_NUM_CCs][N_RBG_MAX]); -======= -flexran_schedule_ue_dl_spec_common(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info); - -void -flexran_schedule_ue_ul_spec_default(mid_t mod_id, - uint32_t frame, - uint32_t cooperation_flag, - int subframe, - unsigned char sched_subframe, - Protocol__FlexranMessage **ul_info); - - -uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, - int total_rbs); - -int flexran_slice_member(int UE_id, - int slice_id); - -int flexran_slice_maxmcs(int slice_id) ; - -/* Downlink Primitivies */ - -void _store_dlsch_buffer (module_id_t Mod_id, - int slice_id, - frame_t frameP, - sub_frame_t subframeP); - - -void _assign_rbs_required (module_id_t Mod_id, - int slice_id, - frame_t frameP, - sub_frame_t subframe, - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES], - int min_rb_unit[MAX_NUM_CCs]); - - -/* Uplink Primitivies */ - -// void _sort_ue_ul (module_id_t module_idP,int frameP, sub_frame_t subframeP); - -void _assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, sub_frame_t subframeP, uint16_t *first_rb); - - -void _ulsch_scheduler_pre_processor(module_id_t module_idP, - int slice_id, - int frameP, - sub_frame_t subframeP, - uint16_t *first_rb); - - -void flexran_agent_schedule_ulsch_rnti(module_id_t module_idP, - unsigned char cooperation_flag, - frame_t frameP, - sub_frame_t subframeP, - unsigned char sched_subframe, - uint16_t *first_rb); - -/* Downlink Primitives */ - -void _dlsch_scheduler_pre_processor (module_id_t Mod_id, - int slice_id, - frame_t frameP, - sub_frame_t subframeP, - int N_RBG[MAX_NUM_CCs], - int *mbsfn_flag); - -void _dlsch_scheduler_pre_processor_reset (int module_idP, - int UE_id, - uint8_t CC_id, - int frameP, - int subframeP, - int N_RBG, - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES], - unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], - unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]); - -void _dlsch_scheduler_pre_processor_allocate (module_id_t Mod_id, - int UE_id, - uint8_t CC_id, - int N_RBG, - int transmission_mode, - int min_rb_unit, - uint8_t N_RB_DL, - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], - unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]); ->>>>>>> feature-68-enb-agent - -/* - * Default scheduler used by the eNB agent - */ -void flexran_schedule_ue_dl_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__FlexranMessage **dl_info); - -/* - Uplink scheduler used by MAC agent -*/ - -void flexran_agent_schedule_ulsch_ue_spec(module_id_t module_idP, frame_t frameP, unsigned char cooperation_flag, - sub_frame_t subframeP, - unsigned char sched_subframe, Protocol__FlexranMessage **ul_info); - -/* - * Data plane function for applying the DL decisions of the scheduler - */ -void flexran_apply_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, - Protocol__FlexranMessage *dl_scheduling_info); - -/* - * Data plane function for applying the UE specific DL decisions of the scheduler - */ -void flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - uint32_t n_dl_ue_data, - Protocol__FlexDlData ** - dl_ue_data); - -/* - * Data plane function for filling the DCI structure - */ -void flexran_fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, - Protocol__FlexDlDci * dl_dci); - -#endif diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c deleted file mode 100644 index 6b1c2579b2..0000000000 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c +++ /dev/null @@ -1,583 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file flexran_agent_scheduler_dataplane.c - * \brief data plane procedures related to eNB scheduling - * \author Xenofon Foukas - * \date 2016 - * \email: x.foukas@sms.ed.ac.uk - * \version 0.1 - * @ingroup _mac - - */ - -#include "assertions.h" -#include "PHY/defs.h" -#include "PHY/extern.h" - -#include "SCHED/defs.h" -#include "SCHED/extern.h" - -#include "LAYER2/MAC/flexran_agent_mac_proto.h" -#include "LAYER2/MAC/defs.h" -#include "LAYER2/MAC/proto.h" -#include "LAYER2/MAC/extern.h" -#include "LAYER2/MAC/flexran_dci_conversions.h" - -#include "UTIL/LOG/log.h" -#include "UTIL/LOG/vcd_signal_dumper.h" -#include "UTIL/OPT/opt.h" -#include "OCG.h" -#include "OCG_extern.h" - -#include "RRC/LITE/extern.h" -#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" - -#include "header.pb-c.h" -#include "flexran.pb-c.h" -#include "flexran_agent_extern.h" - -#include "flexran_agent_common.h" - -#include "SIMULATION/TOOLS/defs.h" // for taus - -void -flexran_apply_dl_scheduling_decisions(mid_t mod_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage * - dl_scheduling_info) -{ - - Protocol__FlexDlMacConfig *mac_config = - dl_scheduling_info->dl_mac_config_msg; - - // Check if there is anything to schedule for random access - if (mac_config->n_dl_rar > 0) { - /*TODO: call the random access data plane function */ - } - // Check if there is anything to schedule for paging/broadcast - if (mac_config->n_dl_broadcast > 0) { - /*TODO: call the broadcast/paging data plane function */ - } - // Check if there is anything to schedule for the UEs - if (mac_config->n_dl_ue_data > 0) { - flexran_apply_ue_spec_scheduling_decisions(mod_id, frame, subframe, - mbsfn_flag, - mac_config-> - n_dl_ue_data, - mac_config->dl_ue_data); - } - -} - -void -flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - uint32_t n_dl_ue_data, - Protocol__FlexDlData ** - dl_ue_data) -{ - - uint8_t CC_id; - int UE_id; - mac_rlc_status_resp_t rlc_status; - unsigned char ta_len = 0; - unsigned char header_len = 0, header_len_tmp = 0; - unsigned char sdu_lcids[11], offset, num_sdus = 0; - uint16_t nb_rb; - uint16_t TBS, sdu_lengths[11], rnti, padding = 0, post_padding = 0; - unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; - uint8_t round = 0; - uint8_t harq_pid = 0; - // LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - uint16_t sdu_length_total = 0; - short ta_update = 0; - eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; - UE_list_t *UE_list = &eNB->UE_list; - // static int32_t tpc_accumulated=0; - UE_sched_ctrl *ue_sched_ctl; - - int last_sdu_header_len = 0; - - int i, j; - - Protocol__FlexDlData *dl_data; - Protocol__FlexDlDci *dl_dci; - - uint32_t rlc_size, n_lc, lcid; - - // For each UE-related command - for (i = 0; i < n_dl_ue_data; i++) { - - dl_data = dl_ue_data[i]; - dl_dci = dl_data->dl_dci; - - CC_id = dl_data->serv_cell_index; - // frame_parms[CC_id] = mac_xface->get_lte_frame_parms(mod_id, CC_id); - - rnti = dl_data->rnti; - UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]); - - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - - round = dl_dci->rv[0]; - harq_pid = dl_dci->harq_process; - - //LOG_I(FLEXRAN_AGENT, "[Frame %d][Subframe %d] Scheduling harq %d\n", frame, subframe, harq_pid); - // LOG_I(FLEXRAN_AGENT, "[Frame %d][Subframe %d]Now scheduling harq_pid %d (round %d)\n", frame, subframe, harq_pid, round); - - // If this is a new transmission - if (round == 0) { - // First we have to deal with the creation of the PDU based on the message instructions - rlc_status.bytes_in_buffer = 0; - - TBS = dl_dci->tbs_size[0]; - - if (dl_data->n_ce_bitmap > 0) { - //Check if there is TA command and set the length appropriately - ta_len = - (dl_data-> - ce_bitmap[0] & PROTOCOL__FLEX_CE_TYPE__FLPCET_TA) ? 2 - : 0; - } - - num_sdus = 0; - sdu_length_total = 0; - - n_lc = dl_data->n_rlc_pdu; - // Go through each one of the channel commands and create SDUs - header_len = 0; - last_sdu_header_len = 0; - for (j = 0; j < n_lc; j++) { - sdu_lengths[j] = 0; - lcid = - dl_data->rlc_pdu[j]->rlc_pdu_tb[0]->logical_channel_id; - rlc_size = dl_data->rlc_pdu[j]->rlc_pdu_tb[0]->size; - LOG_D(MAC, - "[TEST] [eNB %d] [Frame %d] [Subframe %d], LCID %d, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", - mod_id, frame, subframe, lcid, CC_id, rlc_size); - if (rlc_size > 0) { - - rlc_status = mac_rlc_status_ind(mod_id, - rnti, - mod_id, - frame, - subframe, - ENB_FLAG_YES, - MBMS_FLAG_NO, lcid, 0); - - if (rlc_status.bytes_in_buffer > 0) { - - if (rlc_status.bytes_in_buffer < rlc_size) { - rlc_size = rlc_status.bytes_in_buffer; - } - - if (rlc_size <= 2) { - rlc_size = 3; - } - - rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, subframe, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, rlc_size); // transport block set size - - LOG_D(MAC, - "[TEST] RLC can give %d bytes for LCID %d during second call\n", - rlc_status.bytes_in_buffer, lcid); - - if (rlc_status.bytes_in_buffer > 0) { - - sdu_lengths[j] = mac_rlc_data_req(mod_id, rnti, mod_id, frame, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, rlc_size, //not used - (char *) - &dlsch_buffer - [sdu_length_total]); - - LOG_D(MAC, - "[eNB %d][LCID %d] CC_id %d Got %d bytes from RLC\n", - mod_id, lcid, CC_id, sdu_lengths[j]); - sdu_length_total += sdu_lengths[j]; - sdu_lcids[j] = lcid; - - UE_list-> - eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid] - += 1; - UE_list-> - eNB_UE_stats[CC_id][UE_id].num_bytes_tx - [lcid] += sdu_lengths[j]; - - if (sdu_lengths[j] < 128) { - header_len += 2; - last_sdu_header_len = 2; - } else { - header_len += 3; - last_sdu_header_len = 3; - } - num_sdus++; - } - } - } - } // SDU creation end - - - if (((sdu_length_total + header_len + ta_len) > 0)) { - - header_len_tmp = header_len; - - // If we have only a single SDU, header length becomes 1 - if ((num_sdus) == 1) { - //if (header_len == 2 || header_len == 3) { - header_len = 1; - } else { - header_len = (header_len - last_sdu_header_len) + 1; - } - - // If we need a 1 or 2 bit padding or no padding at all - if ((TBS - header_len - sdu_length_total - ta_len) <= 2 || (TBS - header_len - sdu_length_total - ta_len) > TBS) { //protect from overflow - padding = - (TBS - header_len - sdu_length_total - ta_len); - post_padding = 0; - } else { // The last sdu needs to have a length field, since we add padding - padding = 0; - header_len = header_len_tmp; - post_padding = TBS - sdu_length_total - header_len - ta_len; // 1 is for the postpadding header - } - - if (ta_len > 0) { - // Reset the measurement - ta_update = flexran_get_TA(mod_id, UE_id, CC_id); - ue_sched_ctl->ta_timer = 20; - eNB_UE_stats->timing_advance_update = 0; - } else { - ta_update = 0; - } - - // If there is nothing to schedule, just leave - if ((sdu_length_total) <= 0) { - harq_pid_updated[UE_id][harq_pid] = 1; - harq_pid_round[UE_id][harq_pid] = 0; - continue; - } - // LOG_I(FLEXRAN_AGENT, "[Frame %d][Subframe %d] TBS is %d and bytes are %d\n", frame, subframe, TBS, sdu_length_total); - - offset = generate_dlsch_header((unsigned char *) UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], num_sdus, //num_sdus - sdu_lengths, // - sdu_lcids, 255, // no drx - ta_update, // timing advance - NULL, // contention res id - padding, post_padding); - -#ifdef DEBUG_eNB_SCHEDULER - LOG_T(MAC, "[eNB %d] First 16 bytes of DLSCH : \n"); - - for (i = 0; i < 16; i++) { - LOG_T(MAC, "%x.", dlsch_buffer[i]); - } - - LOG_T(MAC, "\n"); -#endif - // cycle through SDUs and place in dlsch_buffer - memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id]. - payload[0][offset], dlsch_buffer, sdu_length_total); - // memcpy(&eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]); - - // fill remainder of DLSCH with random data - for (j = 0; j < (TBS - sdu_length_total - offset); j++) { - UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset + - sdu_length_total - + j] = - (char) (taus() & 0xff); - } - - //eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0][offset+sdu_lengths[0]+j] = (char)(taus()&0xff); - if (opt_enabled == 1) { - trace_pdu(1, - (uint8_t *) - UE_list->DLSCH_pdu[CC_id][0][UE_id]. - payload[0], TBS, mod_id, 3, UE_RNTI(mod_id, - UE_id), - eNB->frame, eNB->subframe, 0, 0); - LOG_D(OPT, - "[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n", - mod_id, CC_id, frame, UE_RNTI(mod_id, UE_id), - TBS); - } - // store stats - eNB->eNB_stats[CC_id].dlsch_bytes_tx += sdu_length_total; - eNB->eNB_stats[CC_id].dlsch_pdus_tx += 1; - UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi = - eNB_UE_stats->DL_cqi[0]; - - UE_list->eNB_UE_stats[CC_id][UE_id].crnti = rnti; - UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status = - mac_eNB_get_rrc_status(mod_id, rnti); - UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid; - UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round; - - //nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - //Find the number of resource blocks and set them to the template for retransmissions - nb_rb = get_min_rb_unit(mod_id, CC_id); - uint16_t stats_tbs = - mac_xface->get_TBS_DL(dl_dci->mcs[0], nb_rb); - - while (stats_tbs < TBS) { - nb_rb += get_min_rb_unit(mod_id, CC_id); - stats_tbs = - mac_xface->get_TBS_DL(dl_dci->mcs[0], nb_rb); - } - - // LOG_I(FLEXRAN_AGENT, "The MCS was %d\n", dl_dci->mcs[0]); - - UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += - nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = - dl_dci->mcs[0]; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = - dl_dci->mcs[0]; - UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; - - UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes = - TBS - sdu_length_total; - UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes += - sdu_length_total; - UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes += TBS; - UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus += 1; - - //eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; - //eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); - } else { - LOG_D(FLEXRAN_AGENT, - "No need to schedule a dci after all. Just drop it\n"); - harq_pid_updated[UE_id][harq_pid] = 1; - harq_pid_round[UE_id][harq_pid] = 0; - continue; - } - } else { - // No need to create anything apart of DCI in case of retransmission - /*TODO: Must add these */ - // eNB_UE_stats->dlsch_trials[round]++; - //UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1; - //UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb; - //UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb; - //UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used_retx=nCCECC_id]; - } - - // UE_list->UE_template[CC_id][UE_id].oldNDI[dl_dci->harq_process] = dl_dci->ndi[0]; - // eNB_UE_stats->dlsch_mcs1 = dl_dci->mcs[0]; - - //Fill the proper DCI of OAI - flexran_fill_oai_dci(mod_id, CC_id, rnti, dl_dci); - } -} - -void -flexran_fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, - Protocol__FlexDlDci * dl_dci) -{ - - void *DLSCH_dci = NULL; - DCI_PDU *DCI_pdu; - - unsigned char harq_pid = 0; - // unsigned char round = 0; - LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; - int size_bits = 0, size_bytes = 0; - eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; - UE_list_t *UE_list = &eNB->UE_list; - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - - int UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]); - - uint32_t format; - - harq_pid = dl_dci->harq_process; - // round = dl_dci->rv[0]; - - // Note this code is for a specific DCI format - DLSCH_dci = - (void *) UE_list->UE_template[CC_id][UE_id].DLSCH_DCI[harq_pid]; - DCI_pdu = &eNB->common_channels[CC_id].DCI_pdu; - - frame_parms[CC_id] = mac_xface->get_lte_frame_parms(mod_id, CC_id); - - if (dl_dci->has_tpc == 1) { - // Check if tpc has been set and reset measurement */ - if ((dl_dci->tpc == 0) || (dl_dci->tpc == 2)) { - eNB_UE_stats = - mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - eNB_UE_stats->Po_PUCCH_update = 0; - } - } - - - switch (frame_parms[CC_id]->N_RB_DL) { - case 6: - if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_TDD_1(DCI1_1_5MHz_TDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_1_5MHz_TDD_t); - size_bits = sizeof_DCI1_1_5MHz_TDD_t; - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } else { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_FDD_1(DCI1_1_5MHz_FDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_1_5MHz_FDD_t); - size_bits = sizeof_DCI1_1_5MHz_FDD_t; - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } - break; - case 25: - if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_TDD_1(DCI1_5MHz_TDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_5MHz_TDD_t); - size_bits = sizeof_DCI1_5MHz_TDD_t; - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } else { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_FDD_1(DCI1_5MHz_FDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_5MHz_FDD_t); - size_bits = sizeof_DCI1_5MHz_FDD_t; - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } - break; - case 50: - if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_TDD_1(DCI1_10MHz_TDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_10MHz_TDD_t); - size_bits = sizeof_DCI1_10MHz_TDD_t; - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } else { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_FDD_1(DCI1_10MHz_FDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_10MHz_FDD_t); - size_bits = sizeof_DCI1_10MHz_FDD_t; - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } - break; - case 100: - if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_TDD_1(DCI1_20MHz_TDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_20MHz_TDD_t); - size_bits = sizeof_DCI1_20MHz_TDD_t; - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } else { - if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { - FILL_DCI_FDD_1(DCI1_20MHz_FDD_t, DLSCH_dci, dl_dci); - size_bytes = sizeof(DCI1_20MHz_FDD_t); - size_bits = sizeof_DCI1_20MHz_FDD_t; - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { - //TODO - } else if (dl_dci->format == - PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { - //TODO - } - } - break; - } - - //Set format to the proper type - switch (dl_dci->format) { - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1: - format = format1; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1A: - format = format1A; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1B: - format = format1B; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1C: - format = format1C; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D: - format = format1E_2A_M10PRB; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2: - format = format2; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A: - format = format2A; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2B: - format = format2B; - break; - case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_3: - format = 3; - break; - default: - /*TODO: Need to deal with unsupported DCI type */ - return; - } - - add_ue_spec_dci(DCI_pdu, - DLSCH_dci, - rnti, - size_bytes, dl_dci->aggr_level, size_bits, format, 0); -} diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c deleted file mode 100644 index 6445fa0845..0000000000 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ /dev/null @@ -1,1814 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file flexran_agent_scheduler_dlsch_ue.c - * \brief procedures related to eNB for the DLSCH transport channel - * \author Xenofon Foukas, Navid Nikaein and Raymond Knopp - * \date 2016 - * \email: x.foukas@sms.ed.ac.uk - * \version 0.1 - * @ingroup _mac - - */ - -#include "assertions.h" -#include "PHY/defs.h" -#include "PHY/extern.h" - -#include "SCHED/defs.h" -#include "SCHED/extern.h" - -#include "LAYER2/MAC/flexran_agent_mac_proto.h" -#include "LAYER2/MAC/defs.h" -#include "LAYER2/MAC/proto.h" -#include "LAYER2/MAC/extern.h" -#include "UTIL/LOG/log.h" -#include "UTIL/LOG/vcd_signal_dumper.h" -#include "UTIL/OPT/opt.h" -#include "OCG.h" -#include "OCG_extern.h" - -#include "RRC/LITE/extern.h" -#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" - -#include "ENB_APP/flexran_agent_defs.h" -#include "flexran_agent_ran_api.h" -#include "pdcp.h" - -#include "header.pb-c.h" -#include "flexran.pb-c.h" -#include "flexran_agent_mac.h" -#include - -#include "SIMULATION/TOOLS/defs.h" // for taus - -#if defined(ENABLE_ITTI) -#include "intertask_interface.h" -#endif - -#define ENABLE_MAC_PAYLOAD_DEBUG - -/** - * Local variables to support slicing - * - */ - - -/*!\brief UE ULSCH scheduling states*/ -typedef enum { - MIN_SLICE_STRATEGY = 0, - SLICE_MASK, - UEID_TO_SLICEID, - MAX_SLICE_STRATEGY -} SLICING_STRATEGY; - -// this assumes a max of of 16 UE per eNB/CC -#define SLICE0_MASK 0x000f -#define SLICE1_MASK 0x00f0 -#define SLICE2_MASK 0x0f00 -#define SLICE3_MASK 0xf000 - - -// number of active slices for past and current time -int n_active_slices = 1; -int n_active_slices_current = 1; - -// ue to slice mapping -int slicing_strategy = UEID_TO_SLICEID; -int slicing_strategy_current = UEID_TO_SLICEID; - -// RB share for each slice for past and current time -float avg_slice_percentage=0.25; -float slice_percentage[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; -float slice_percentage_current[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; -float total_slice_percentage = 0; -float total_slice_percentage_current = 0; - -// MAX MCS for each slice for past and current time -int slice_maxmcs[MAX_NUM_SLICES] = { 28, 28, 28, 28 }; -int slice_maxmcs_current[MAX_NUM_SLICES] = { 28, 28, 28, 28 }; - -int update_dl_scheduler[MAX_NUM_SLICES] = { 1, 1, 1, 1 }; -int update_dl_scheduler_current[MAX_NUM_SLICES] = { 1, 1, 1, 1 }; - -// name of available scheduler -char *dl_scheduler_type[MAX_NUM_SLICES] = - { "flexran_schedule_ue_spec_embb", - "flexran_schedule_ue_spec_urllc", - "flexran_schedule_ue_spec_mmtc", - "flexran_schedule_ue_spec_be" // best effort -}; - -// pointer to the slice specific scheduler -slice_scheduler_dl slice_sched_dl[MAX_NUM_SLICES] = {0}; - - -/** - * preprocessor functions for scheduling - * - */ - - -// This function stores the downlink buffer for all the logical channels -void -_store_dlsch_buffer(module_id_t Mod_id, - int slice_id, frame_t frameP, sub_frame_t subframeP) -{ - - int UE_id, i; - rnti_t rnti; - mac_rlc_status_resp_t rlc_status; - UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; - UE_TEMPLATE *UE_template; - - for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { - if (UE_list->active[UE_id] != TRUE) - continue; - - if (flexran_slice_member(UE_id, slice_id) == 0) - continue; - - UE_template = - &UE_list->UE_template[UE_PCCID(Mod_id, UE_id)][UE_id]; - - // clear logical channel interface variables - UE_template->dl_buffer_total = 0; - UE_template->dl_pdus_total = 0; - - for (i = 0; i < MAX_NUM_LCID; i++) { - UE_template->dl_buffer_info[i] = 0; - UE_template->dl_pdus_in_buffer[i] = 0; - UE_template->dl_buffer_head_sdu_creation_time[i] = 0; - UE_template->dl_buffer_head_sdu_remaining_size_to_send[i] = 0; - } - - rnti = UE_RNTI(Mod_id, UE_id); - - for (i = 0; i < MAX_NUM_LCID; i++) { // loop over all the logical channels - - rlc_status = - mac_rlc_status_ind(Mod_id, rnti, Mod_id, frameP, subframeP, - ENB_FLAG_YES, MBMS_FLAG_NO, i, 0); - UE_template->dl_buffer_info[i] = rlc_status.bytes_in_buffer; //storing the dlsch buffer for each logical channel - UE_template->dl_pdus_in_buffer[i] = rlc_status.pdus_in_buffer; - UE_template->dl_buffer_head_sdu_creation_time[i] = - rlc_status.head_sdu_creation_time; - UE_template->dl_buffer_head_sdu_creation_time_max = - cmax(UE_template->dl_buffer_head_sdu_creation_time_max, - rlc_status.head_sdu_creation_time); - UE_template->dl_buffer_head_sdu_remaining_size_to_send[i] = - rlc_status.head_sdu_remaining_size_to_send; - UE_template->dl_buffer_head_sdu_is_segmented[i] = - rlc_status.head_sdu_is_segmented; - UE_template->dl_buffer_total += UE_template->dl_buffer_info[i]; //storing the total dlsch buffer - UE_template->dl_pdus_total += - UE_template->dl_pdus_in_buffer[i]; - -#ifdef DEBUG_eNB_SCHEDULER - - /* note for dl_buffer_head_sdu_remaining_size_to_send[i] : - * 0 if head SDU has not been segmented (yet), else remaining size not already segmented and sent - */ - if (UE_template->dl_buffer_info[i] > 0) - LOG_D(MAC, - "[eNB %d][SLICE %d] Frame %d Subframe %d : RLC status for UE %d in LCID%d: total of %d pdus and size %d, head sdu queuing time %d, remaining size %d, is segmeneted %d \n", - Mod_id, slice_id, frameP, subframeP, UE_id, - i, UE_template->dl_pdus_in_buffer[i], - UE_template->dl_buffer_info[i], - UE_template->dl_buffer_head_sdu_creation_time[i], - UE_template-> - dl_buffer_head_sdu_remaining_size_to_send[i], - UE_template->dl_buffer_head_sdu_is_segmented[i]); - -#endif - - } - - //#ifdef DEBUG_eNB_SCHEDULER - if (UE_template->dl_buffer_total > 0) - LOG_D(MAC, - "[eNB %d] Frame %d Subframe %d : RLC status for UE %d : total DL buffer size %d and total number of pdu %d \n", - Mod_id, frameP, subframeP, UE_id, - UE_template->dl_buffer_total, - UE_template->dl_pdus_total); - - //#endif - } -} - - -// This function returns the estimated number of RBs required by each UE for downlink scheduling -void -_assign_rbs_required(module_id_t Mod_id, - int slice_id, - frame_t frameP, - sub_frame_t subframe, - uint16_t - nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs] - [MAX_NUM_SLICES], int min_rb_unit[MAX_NUM_CCs]) -{ - - - rnti_t rnti; - uint16_t TBS = 0; - LTE_eNB_UE_stats *eNB_UE_stats[MAX_NUM_CCs]; - int UE_id, n, i, j, CC_id, pCCid, tmp; - UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; - // UE_TEMPLATE *UE_template; - - // clear rb allocations across all CC_ids - for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { - if (UE_list->active[UE_id] != TRUE) - continue; - - if (flexran_slice_member(UE_id, slice_id) == 0) - continue; - - pCCid = UE_PCCID(Mod_id, UE_id); - rnti = UE_list->UE_template[pCCid][UE_id].rnti; - - /* skip UE not present in PHY (for any of its active CCs) */ - if (!phy_stats_exist(Mod_id, rnti)) - continue; - - //update CQI information across component carriers - for (n = 0; n < UE_list->numactiveCCs[UE_id]; n++) { - CC_id = UE_list->ordered_CCids[n][UE_id]; - eNB_UE_stats[CC_id] = - mac_xface->get_eNB_UE_stats(Mod_id, CC_id, rnti); - eNB_UE_stats[CC_id]->dlsch_mcs1 = - cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)]; - } - - // provide the list of CCs sorted according to MCS - for (i = 0; i < UE_list->numactiveCCs[UE_id]; i++) { - for (j = i + 1; j < UE_list->numactiveCCs[UE_id]; j++) { - DevAssert(j < MAX_NUM_CCs); - - if (eNB_UE_stats[UE_list->ordered_CCids[i][UE_id]]-> - dlsch_mcs1 > - eNB_UE_stats[UE_list->ordered_CCids[j][UE_id]]-> - dlsch_mcs1) { - tmp = UE_list->ordered_CCids[i][UE_id]; - UE_list->ordered_CCids[i][UE_id] = - UE_list->ordered_CCids[j][UE_id]; - UE_list->ordered_CCids[j][UE_id] = tmp; - } - } - } - /* NN --> RK - * check the index of UE_template" - */ - if (UE_list->UE_template[pCCid][UE_id].dl_buffer_total> 0) { - LOG_D(MAC,"[preprocessor] assign RB for UE %d\n",UE_id); - - for (i=0; inumactiveCCs[UE_id]; i++) { - CC_id = UE_list->ordered_CCids[i][UE_id]; - eNB_UE_stats[CC_id] = mac_xface->get_eNB_UE_stats(Mod_id,CC_id,rnti); - - if (cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)] == 0) {//eNB_UE_stats[CC_id]->dlsch_mcs1==0) { - nb_rbs_required[CC_id][UE_id] = 4; // don't let the TBS get too small - } else { - nb_rbs_required[CC_id][UE_id] = min_rb_unit[CC_id]; - } - - TBS = mac_xface->get_TBS_DL(cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)], nb_rbs_required[CC_id][UE_id]); - nb_rbs_allowed_slice[CC_id][slice_id] = flexran_nb_rbs_allowed_slice(slice_percentage[slice_id], - flexran_get_N_RB_DL(Mod_id, CC_id)); - LOG_D(MAC,"[preprocessor] start RB assignement for UE %d CC_id %d dl buffer %d (RB unit %d, MCS %d, TBS %d) \n", - UE_id, CC_id, UE_list->UE_template[pCCid][UE_id].dl_buffer_total, - nb_rbs_required[CC_id][UE_id], flexran_get_ue_wcqi(Mod_id, UE_id), TBS); - - /* calculating required number of RBs for each UE */ - while (TBS < UE_list->UE_template[pCCid][UE_id].dl_buffer_total) { - nb_rbs_required[CC_id][UE_id] += min_rb_unit[CC_id]; - - if (nb_rbs_required[CC_id][UE_id] > nb_rbs_allowed_slice[CC_id][slice_id]) { - TBS = mac_xface->get_TBS_DL(cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)], nb_rbs_allowed_slice[CC_id][slice_id]); - nb_rbs_required[CC_id][UE_id] = nb_rbs_allowed_slice[CC_id][slice_id]; - break; - } - - TBS = mac_xface->get_TBS_DL(cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)], nb_rbs_required[CC_id][UE_id]); - } // end of while - - LOG_D(MAC,"[eNB %d][SLICE %d] Frame %d: UE %d on CC %d: RB unit %d, nb_required RB %d (TBS %d, mcs %d)\n", - Mod_id, slice_id,frameP,UE_id, CC_id, min_rb_unit[CC_id], nb_rbs_required[CC_id][UE_id], TBS, cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)]); - } - } - } -} - -void -_dlsch_scheduler_pre_processor_allocate(module_id_t Mod_id, - int UE_id, - uint8_t CC_id, - int N_RBG, - int transmission_mode, - int min_rb_unit, - uint8_t N_RB_DL, - uint16_t - nb_rbs_required[MAX_NUM_CCs] - [NUMBER_OF_UE_MAX], - uint16_t - nb_rbs_required_remaining - [MAX_NUM_CCs] - [NUMBER_OF_UE_MAX], unsigned char - rballoc_sub[MAX_NUM_CCs] - [N_RBG_MAX], unsigned char - MIMO_mode_indicator - [MAX_NUM_CCs][N_RBG_MAX]) -{ - int i; - UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; - UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - - for (i = 0; i < N_RBG; i++) { - - if ((rballoc_sub[CC_id][i] == 0) && - (ue_sched_ctl->rballoc_sub_UE[CC_id][i] == 0) && - (nb_rbs_required_remaining[CC_id][UE_id] > 0) && - (ue_sched_ctl->pre_nb_available_rbs[CC_id] < - nb_rbs_required[CC_id][UE_id])) { - - // if this UE is not scheduled for TM5 - if (ue_sched_ctl->dl_pow_off[CC_id] != 0) { - - if ((i == N_RBG - 1) - && ((N_RB_DL == 25) || (N_RB_DL == 50))) { - rballoc_sub[CC_id][i] = 1; - ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 1; - MIMO_mode_indicator[CC_id][i] = 1; - if (transmission_mode == 5) { - ue_sched_ctl->dl_pow_off[CC_id] = 1; - } - nb_rbs_required_remaining[CC_id][UE_id] = - nb_rbs_required_remaining[CC_id][UE_id] - - min_rb_unit + 1; - ue_sched_ctl->pre_nb_available_rbs[CC_id] = - ue_sched_ctl->pre_nb_available_rbs[CC_id] + - min_rb_unit - 1; - } else { - if (nb_rbs_required_remaining[CC_id][UE_id] >= - min_rb_unit) { - rballoc_sub[CC_id][i] = 1; - ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 1; - MIMO_mode_indicator[CC_id][i] = 1; - if (transmission_mode == 5) { - ue_sched_ctl->dl_pow_off[CC_id] = 1; - } - nb_rbs_required_remaining[CC_id][UE_id] = - nb_rbs_required_remaining[CC_id][UE_id] - - min_rb_unit; - ue_sched_ctl->pre_nb_available_rbs[CC_id] = - ue_sched_ctl->pre_nb_available_rbs[CC_id] + - min_rb_unit; - } - } - } // dl_pow_off[CC_id][UE_id] ! = 0 - } - } -} - -void -_dlsch_scheduler_pre_processor_reset(int module_idP, - int UE_id, - uint8_t CC_id, - int frameP, - int subframeP, - int N_RBG, - uint16_t nb_rbs_required[MAX_NUM_CCs] - [NUMBER_OF_UE_MAX], - uint16_t - nb_rbs_required_remaining - [MAX_NUM_CCs][NUMBER_OF_UE_MAX], - uint16_t - nb_rbs_allowed_slice[MAX_NUM_CCs] - [MAX_NUM_SLICES], unsigned char - rballoc_sub[MAX_NUM_CCs] - [N_RBG_MAX], unsigned char - MIMO_mode_indicator[MAX_NUM_CCs] - [N_RBG_MAX]) -{ - int i, j; - UE_list_t *UE_list = &eNB_mac_inst[module_idP].UE_list; - UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - uint8_t *vrb_map = - eNB_mac_inst[module_idP].common_channels[CC_id].vrb_map; - int RBGsize = - PHY_vars_eNB_g[module_idP][CC_id]->frame_parms.N_RB_DL / N_RBG; -#ifdef SF05_LIMIT - //int subframe05_limit=0; - int sf05_upper = -1, sf05_lower = -1; -#endif - // LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti); - - flexran_update_TA(module_idP, UE_id, CC_id); - - if (UE_id == 0) { - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME - (VCD_SIGNAL_DUMPER_VARIABLES_UE0_TIMING_ADVANCE, - ue_sched_ctl->ta_update); - } - nb_rbs_required[CC_id][UE_id] = 0; - ue_sched_ctl->pre_nb_available_rbs[CC_id] = 0; - ue_sched_ctl->dl_pow_off[CC_id] = 2; - nb_rbs_required_remaining[CC_id][UE_id] = 0; - for (i = 0; i < n_active_slices; i++) - nb_rbs_allowed_slice[CC_id][i] = 0; -#ifdef SF05_LIMIT - switch (N_RBG) { - case 6: - sf05_lower = 0; - sf05_upper = 5; - break; - case 8: - sf05_lower = 2; - sf05_upper = 5; - break; - case 13: - sf05_lower = 4; - sf05_upper = 7; - break; - case 17: - sf05_lower = 7; - sf05_upper = 9; - break; - case 25: - sf05_lower = 11; - sf05_upper = 13; - break; - } -#endif - // Initialize Subbands according to VRB map - for (i = 0; i < N_RBG; i++) { - ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 0; - rballoc_sub[CC_id][i] = 0; -#ifdef SF05_LIMIT - // for avoiding 6+ PRBs around DC in subframe 0-5 (avoid excessive errors) - - if ((subframeP == 0 || subframeP == 5) && - (i >= sf05_lower && i <= sf05_upper)) - rballoc_sub[CC_id][i] = 1; -#endif - // for SI-RNTI,RA-RNTI and P-RNTI allocations - for (j = 0; j < RBGsize; j++) { - if (vrb_map[j + (i * RBGsize)] != 0) { - rballoc_sub[CC_id][i] = 1; - LOG_D(MAC, "Frame %d, subframe %d : vrb %d allocated\n", - frameP, subframeP, j + (i * RBGsize)); - break; - } - } - LOG_D(MAC, "Frame %d Subframe %d CC_id %d RBG %i : rb_alloc %d\n", - frameP, subframeP, CC_id, i, rballoc_sub[CC_id][i]); - MIMO_mode_indicator[CC_id][i] = 2; - } -} - -// This function assigns pre-available RBS to each UE in specified sub-bands before scheduling is done -void -_dlsch_scheduler_pre_processor(module_id_t Mod_id, - int slice_id, - frame_t frameP, - sub_frame_t subframeP, - int N_RBG[MAX_NUM_CCs], int *mbsfn_flag) -{ - - unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], total_ue_count; - unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]; - int UE_id, i; - uint8_t round = 0; - uint8_t harq_pid = 0; - uint16_t ii, j; - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - uint16_t nb_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES]; - uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - uint16_t nb_rbs_required_remaining_1[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - uint16_t average_rbs_per_user[MAX_NUM_CCs] = { 0 }; - rnti_t rnti; - int min_rb_unit[MAX_NUM_CCs]; - uint16_t r1 = 0; - uint8_t CC_id; - UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; - LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs] = { 0 }; - - int transmission_mode = 0; - UE_sched_ctrl *ue_sched_ctl; - - - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - - if (mbsfn_flag[CC_id] > 0) // If this CC is allocated for MBSFN skip it here - continue; - - frame_parms[CC_id] = mac_xface->get_lte_frame_parms(Mod_id, CC_id); - - - min_rb_unit[CC_id] = get_min_rb_unit(Mod_id, CC_id); - - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i] != TRUE) - continue; - - UE_id = i; - // Initialize scheduling information for all active UEs - - //if (flexran_slice_member(UE_id, slice_id) == 0) - //continue; - _dlsch_scheduler_pre_processor_reset(Mod_id, - UE_id, - CC_id, - frameP, - subframeP, - N_RBG[CC_id], - nb_rbs_required, - nb_rbs_required_remaining, - nb_rbs_allowed_slice, - rballoc_sub, - MIMO_mode_indicator); - - } - } - - - /* Store the DLSCH buffer for each logical channel for each UE */ - _store_dlsch_buffer (Mod_id,slice_id,frameP,subframeP); - - // Calculate the number of RBs required by each UE on the basis of logical channel's buffer - _assign_rbs_required (Mod_id,slice_id, frameP,subframeP,nb_rbs_required,nb_rbs_allowed_slice,min_rb_unit); - - // Sorts the user on the basis of dlsch logical channel buffer and CQI - sort_UEs (Mod_id,frameP,subframeP); - - total_ue_count = 0; - - // loop over all active UEs - for (i=UE_list->head; i>=0; i=UE_list->next[i]) { - rnti = flexran_get_ue_crnti(Mod_id, i); - if(rnti == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - - UE_id = i; - - if (flexran_slice_member(UE_id, slice_id) == 0) - continue; - - if (!phy_stats_exist(Mod_id, rnti)) - continue; - - for (ii=0; ii < UE_num_active_CC(UE_list,UE_id); ii++) { - CC_id = UE_list->ordered_CCids[ii][UE_id]; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - ue_sched_ctl->max_allowed_rbs[CC_id]=nb_rbs_allowed_slice[CC_id][slice_id]; - flexran_get_harq(Mod_id, CC_id, UE_id, frameP, subframeP, &harq_pid, &round, openair_harq_DL); - - // if there is no available harq_process, skip the UE - if (UE_list->UE_sched_ctrl[UE_id].harq_pid[CC_id]<0) - continue; - - average_rbs_per_user[CC_id]=0; - - frame_parms[CC_id] = mac_xface->get_lte_frame_parms(Mod_id,CC_id); - - // mac_xface->get_ue_active_harq_pid(Mod_id,CC_id,rnti,frameP,subframeP,&harq_pid,&round,0); - - if(round>0) { - nb_rbs_required[CC_id][UE_id] = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - } - - //nb_rbs_required_remaining[UE_id] = nb_rbs_required[UE_id]; - if (nb_rbs_required[CC_id][UE_id] > 0) { - total_ue_count = total_ue_count + 1; - } - - - // hypotetical assignement - /* - * If schedule is enabled and if the priority of the UEs is modified - * The average rbs per logical channel per user will depend on the level of - * priority. Concerning the hypothetical assignement, we should assign more - * rbs to prioritized users. Maybe, we can do a mapping between the - * average rbs per user and the level of priority or multiply the average rbs - * per user by a coefficient which represents the degree of priority. - */ - - if (total_ue_count == 0) { - average_rbs_per_user[CC_id] = 0; - } else if( (min_rb_unit[CC_id] * total_ue_count) <= nb_rbs_allowed_slice[CC_id][slice_id] ) { - average_rbs_per_user[CC_id] = (uint16_t) floor(nb_rbs_allowed_slice[CC_id][slice_id]/total_ue_count); - } else { - average_rbs_per_user[CC_id] = min_rb_unit[CC_id]; // consider the total number of use that can be scheduled UE - } - } - } - - // note: nb_rbs_required is assigned according to total_buffer_dl - // extend nb_rbs_required to capture per LCID RB required - for(i=UE_list->head; i>=0; i=UE_list->next[i]) { - rnti = UE_RNTI(Mod_id,i); - - if(rnti == NOT_A_RNTI) - continue; - - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - - if (!phy_stats_exist(Mod_id, rnti)) - continue; - - if (flexran_slice_member(i, slice_id) == 0) - continue; - - for (ii=0; iiordered_CCids[ii][i]; - - // control channel - if (mac_eNB_get_rrc_status(Mod_id,rnti) < RRC_RECONFIGURED) { - nb_rbs_required_remaining_1[CC_id][i] = nb_rbs_required[CC_id][i]; - } else { - nb_rbs_required_remaining_1[CC_id][i] = cmin(average_rbs_per_user[CC_id],nb_rbs_required[CC_id][i]); - - } - } - - // note: nb_rbs_required is assigned according to total_buffer_dl - // extend nb_rbs_required to capture per LCID RB required - for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { - rnti = UE_RNTI(Mod_id, i); - - if (rnti == NOT_A_RNTI) - continue; - - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - - if (!phy_stats_exist(Mod_id, rnti)) - continue; - - if (flexran_slice_member(i, slice_id) == 0) - continue; - - for (ii = 0; ii < UE_num_active_CC(UE_list, i); ii++) { - CC_id = UE_list->ordered_CCids[ii][i]; - - // control channel - if (mac_eNB_get_rrc_status(Mod_id, rnti) < RRC_RECONFIGURED) { - nb_rbs_required_remaining_1[CC_id][i] = - nb_rbs_required[CC_id][i]; - } else { - nb_rbs_required_remaining_1[CC_id][i] = - cmin(average_rbs_per_user[CC_id], - nb_rbs_required[CC_id][i]); - - } - } - } - - //Allocation to UEs is done in 2 rounds, - // 1st stage: average number of RBs allocated to each UE - // 2nd stage: remaining RBs are allocated to high priority UEs - for (r1 = 0; r1 < 2; r1++) { - - for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { - - if (flexran_slice_member(i, slice_id) == 0) - continue; - - for (ii = 0; ii < UE_num_active_CC(UE_list, i); ii++) { - CC_id = UE_list->ordered_CCids[ii][i]; - - if (r1 == 0) { - nb_rbs_required_remaining[CC_id][i] = - nb_rbs_required_remaining_1[CC_id][i]; - } else { // rb required based only on the buffer - rb allloctaed in the 1st round + extra reaming rb form the 1st round - nb_rbs_required_remaining[CC_id][i] = - nb_rbs_required[CC_id][i] - - nb_rbs_required_remaining_1[CC_id][i] + - nb_rbs_required_remaining[CC_id][i]; - } - - if (nb_rbs_required[CC_id][i] > 0) - LOG_D(MAC, - "round %d : nb_rbs_required_remaining[%d][%d]= %d (remaining_1 %d, required %d, pre_nb_available_rbs %d, N_RBG %d, rb_unit %d)\n", - r1, CC_id, i, - nb_rbs_required_remaining[CC_id][i], - nb_rbs_required_remaining_1[CC_id][i], - nb_rbs_required[CC_id][i], - UE_list->UE_sched_ctrl[i]. - pre_nb_available_rbs[CC_id], N_RBG[CC_id], - min_rb_unit[CC_id]); - - } - } - - if (total_ue_count > 0) { - for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { - UE_id = i; - - if (flexran_slice_member(UE_id, slice_id) == 0) - continue; - - for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { - CC_id = UE_list->ordered_CCids[ii][UE_id]; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - flexran_get_harq(Mod_id, CC_id, UE_id, frameP, - subframeP, &harq_pid, &round); - rnti = UE_RNTI(Mod_id, UE_id); - - // LOG_D(MAC,"UE %d rnti 0x\n", UE_id, rnti ); - if (rnti == NOT_A_RNTI) - continue; - - if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) - continue; - - if (!phy_stats_exist(Mod_id, rnti)) - continue; - - transmission_mode = - mac_xface->get_transmission_mode(Mod_id, CC_id, - rnti); - //rrc_status = mac_eNB_get_rrc_status(Mod_id,rnti); - /* 1st allocate for the retx */ - - // retransmission in data channels - // control channel in the 1st transmission - // data channel for all TM - LOG_T(MAC, - "calling dlsch_scheduler_pre_processor_allocate .. \n "); - _dlsch_scheduler_pre_processor_allocate(Mod_id, UE_id, - CC_id, - N_RBG[CC_id], - transmission_mode, - min_rb_unit - [CC_id], - frame_parms - [CC_id]-> - N_RB_DL, - nb_rbs_required, - nb_rbs_required_remaining, - rballoc_sub, - MIMO_mode_indicator); - } - } - } // total_ue_count - } // end of for for r1 and r2 - - for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { - UE_id = i; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - - if (flexran_slice_member(UE_id, slice_id) == 0) - continue; - - for (ii=0; iiordered_CCids[ii][UE_id]; - flexran_get_harq(Mod_id, CC_id, UE_id, frameP, subframeP, &harq_pid, &round, openair_harq_DL); - rnti = UE_RNTI(Mod_id,UE_id); - - // LOG_D(MAC,"UE %d rnti 0x\n", UE_id, rnti ); - if(rnti == NOT_A_RNTI) - continue; - - if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) - continue; - - if (ue_sched_ctl->pre_nb_available_rbs[CC_id] > 0) { - LOG_D(MAC, - "******************DL Scheduling Information for UE%d ************************\n", - UE_id); - LOG_D(MAC, "dl power offset UE%d = %d \n", UE_id, - ue_sched_ctl->dl_pow_off[CC_id]); - LOG_D(MAC, - "***********RB Alloc for every subband for UE%d ***********\n", - UE_id); - - for (j = 0; j < N_RBG[CC_id]; j++) { - //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].rballoc_sub[i] = rballoc_sub_UE[CC_id][UE_id][i]; - LOG_D(MAC, "RB Alloc for UE%d and Subband%d = %d\n", - UE_id, j, - ue_sched_ctl->rballoc_sub_UE[CC_id][j]); - } - - //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = pre_nb_available_rbs[CC_id][UE_id]; - LOG_D(MAC, - "[eNB %d][SLICE %d] Total RBs allocated for UE%d = %d\n", - Mod_id, slice_id, UE_id, - ue_sched_ctl->pre_nb_available_rbs[CC_id]); - } - } - } - } -} - -#define SF05_LIMIT 1 - -/* - * Main Downlink Slicing - * - */ - -void -flexran_schedule_ue_dl_spec_default(mid_t mod_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info) -//------------------------------------------------------------------------------ -{ - int i=0; - - flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); - - total_slice_percentage=0; - avg_slice_percentage=1.0/n_active_slices; - - // reset the slice percentage for inactive slices - for (i = n_active_slices; i< MAX_NUM_SLICES; i++) { - slice_percentage[i]=0; - } - for (i = 0; i < n_active_slices; i++) { - if (slice_percentage[i] < 0 ){ - LOG_W(MAC, "[eNB %d] frame %d subframe %d:invalid slice %d percentage %f. resetting to zero", - mod_id, frame, subframe, i, slice_percentage[i]); - slice_percentage[i]=0; - } - total_slice_percentage+=slice_percentage[i]; - } - - for (i = 0; i < n_active_slices; i++) { - - // Load any updated functions - if (update_dl_scheduler[i] > 0 ) { - slice_sched_dl[i] = dlsym(NULL, dl_scheduler_type[i]); - update_dl_scheduler[i] = 0; - update_dl_scheduler_current[i] = 0; - LOG_N(MAC,"update dl scheduler slice %d\n", i); - } - - if (total_slice_percentage <= 1.0){ // the new total RB share is within the range - - // check if the number of slices has changed, and log - if (n_active_slices_current != n_active_slices ){ - if ((n_active_slices > 0) && (n_active_slices <= MAX_NUM_SLICES)) { - LOG_N(MAC,"[eNB %d]frame %d subframe %d: number of active DL slices has changed: %d-->%d\n", - mod_id, frame, subframe, n_active_slices_current, n_active_slices); - - n_active_slices_current = n_active_slices; - - } else { - LOG_W(MAC,"invalid number of DL slices %d, revert to the previous value %d\n",n_active_slices, n_active_slices_current); - n_active_slices = n_active_slices_current; - } - } - - // check if the slice rb share has changed, and log the console - if (slice_percentage_current[i] != slice_percentage[i]){ // new slice percentage - LOG_N(MAC,"[eNB %d][SLICE %d][DL] frame %d subframe %d: total percentage %f-->%f, slice RB percentage has changed: %f-->%f\n", - mod_id, i, frame, subframe, total_slice_percentage_current, total_slice_percentage, slice_percentage_current[i], slice_percentage[i]); - total_slice_percentage_current= total_slice_percentage; - slice_percentage_current[i] = slice_percentage[i]; - - } - - // check if the slice max MCS, and log the console - if (slice_maxmcs_current[i] != slice_maxmcs[i]){ - if ((slice_maxmcs[i] >= 0) && (slice_maxmcs[i] < 29)){ - LOG_N(MAC,"[eNB %d][SLICE %d][DL] frame %d subframe %d: slice MAX MCS has changed: %d-->%d\n", - mod_id, i, frame, subframe, slice_maxmcs_current[i], slice_maxmcs[i]); - slice_maxmcs_current[i] = slice_maxmcs[i]; - } else { - LOG_W(MAC,"[eNB %d][SLICE %d][DL] invalid slice max mcs %d, revert the previous value %d\n",mod_id, i, slice_maxmcs[i],slice_maxmcs_current[i]); - slice_maxmcs[i]= slice_maxmcs_current[i]; - } - } - - // check if a new scheduler, and log the console - if (update_dl_scheduler_current[i] != update_dl_scheduler[i]){ - LOG_N(MAC,"[eNB %d][SLICE %d][DL] frame %d subframe %d: DL scheduler for this slice is updated: %s \n", - mod_id, i, frame, subframe, dl_scheduler_type[i]); - update_dl_scheduler_current[i] = update_dl_scheduler[i]; - } - - } else { - // here we can correct the values, e.g. reduce proportionally - - if (n_active_slices == n_active_slices_current){ - LOG_W(MAC,"[eNB %d][SLICE %d][DL] invalid total RB share (%f->%f), reduce proportionally the RB share by 0.1\n", - mod_id,i, - total_slice_percentage_current, total_slice_percentage); - if (slice_percentage[i] >= avg_slice_percentage){ - slice_percentage[i]-=0.1; - total_slice_percentage-=0.1; - } - } else { - LOG_W(MAC,"[eNB %d][SLICE %d][DL] invalid total RB share (%f->%f), revert the number of slice to its previous value (%d->%d)\n", - mod_id,i, - total_slice_percentage_current, total_slice_percentage, - n_active_slices, n_active_slices_current ); - n_active_slices = n_active_slices_current; - slice_percentage[i] = slice_percentage_current[i]; - } - } - - // Run each enabled slice-specific schedulers one by one - slice_sched_dl[i](mod_id, i, frame, subframe, mbsfn_flag,dl_info); - } -} - -uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, int total_rbs) -{ - return (uint16_t) floor(rb_percentage * total_rbs); -} - -int flexran_slice_maxmcs(int slice_id) -{ - return slice_maxmcs[slice_id]; -} - -int flexran_slice_member(int UE_id, int slice_id) -{ - // group membership definition - int slice_member = 0; - - if ((slice_id < 0) || (slice_id > n_active_slices)) - LOG_W(MAC, "out of range slice id %d\n", slice_id); - - switch (slicing_strategy) { - case SLICE_MASK: - switch (slice_id) { - case 0: - if (SLICE0_MASK & UE_id) { - slice_member = 1; - } - break; - case 1: - if (SLICE1_MASK & UE_id) { - slice_member = 1; - } - break; - case 2: - if (SLICE2_MASK & UE_id) { - slice_member = 1; - } - break; - case 3: - if (SLICE3_MASK & UE_id) { - slice_member = 1; - } - break; - default: - LOG_W(MAC, "unknown slice_id %d\n", slice_id); - break; - - } - break; - case UEID_TO_SLICEID: - default: - if ((UE_id % n_active_slices) == slice_id) { - slice_member = 1; // this ue is a member of this slice - } - break; - } - - return slice_member; -} - -/* more aggressive rb and mcs allocation with medium priority and the traffic qci */ -void -flexran_schedule_ue_spec_embb(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage ** dl_info) -{ - flexran_schedule_ue_dl_spec_common(mod_id, - slice_id, - frame, - subframe, - mbsfn_flag, - dl_info); -} - -/* more conservative mcs allocation with high priority and the traffic qci */ -void -flexran_schedule_ue_spec_urllc(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage ** dl_info) -{ - flexran_schedule_ue_dl_spec_common(mod_id, - slice_id, - frame, - subframe, - mbsfn_flag, - dl_info); -} - -/* constant rb allocation with low mcs with low priority and given the UE capabilities */ -void -flexran_schedule_ue_spec_mmtc(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage ** dl_info) -{ - flexran_schedule_ue_dl_spec_common(mod_id, - slice_id, - frame, - subframe, - mbsfn_flag, - dl_info); -} - -/* regular rb and mcs allocation with low priority */ -void -flexran_schedule_ue_spec_be(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage ** dl_info) -{ - flexran_schedule_ue_dl_spec_common(mod_id, - slice_id, - frame, - subframe, - mbsfn_flag, - dl_info); -} - -//------------------------------------------------------------------------------ -void -flexran_schedule_ue_dl_spec_common(mid_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info) -//------------------------------------------------------------------------------ -{ - uint8_t CC_id; - int UE_id; - int N_RBG[MAX_NUM_CCs]; - unsigned char aggregation; - mac_rlc_status_resp_t rlc_status; - unsigned char header_len = 0, header_len_last = 0, ta_len = 0; - uint16_t nb_rb, nb_rb_temp, total_nb_available_rb[MAX_NUM_CCs], - nb_available_rb; - uint16_t TBS, j, rnti; - uint8_t round = 0; - uint8_t harq_pid = 0; - uint16_t sdu_length_total = 0; - int mcs, mcs_tmp; - uint16_t min_rb_unit[MAX_NUM_CCs]; - eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; - /* TODO: Must move the helper structs to scheduler implementation */ - UE_list_t *UE_list = &eNB->UE_list; - int32_t normalized_rx_power, target_rx_power; - int32_t tpc = 1; - static int32_t tpc_accumulated = 0; - UE_sched_ctrl *ue_sched_ctl; - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - Protocol__FlexDlData *dl_data[NUM_MAX_UE]; - int num_ues_added = 0; - int channels_added = 0; - - Protocol__FlexDlDci *dl_dci; - Protocol__FlexRlcPdu *rlc_pdus[11]; - uint32_t ce_flags = 0; - - uint8_t rballoc_sub[25]; - int i; - uint32_t data_to_request; - uint32_t dci_tbs; - uint8_t ue_has_transmission = 0; - uint32_t ndi; - -#if 0 - - if (UE_list->head == -1) { - return; - } -#endif - - start_meas(&eNB->schedule_dlsch); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_IN); - - //weight = get_ue_weight(module_idP,UE_id); - aggregation = 1; // set to the maximum aggregation level - - for (CC_id=0; CC_idcommon_channels[CC_id].vrb_map[i] != 0) - total_nb_available_rb[CC_id]--; - - N_RBG[CC_id] = flexran_get_N_RBG(mod_id, CC_id); - - // store the global enb stats: - eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs; - eNB->eNB_stats[CC_id].available_prbs = total_nb_available_rb[CC_id]; - eNB->eNB_stats[CC_id].total_available_prbs += total_nb_available_rb[CC_id]; - eNB->eNB_stats[CC_id].dlsch_bytes_tx=0; - eNB->eNB_stats[CC_id].dlsch_pdus_tx=0; - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR,VCD_FUNCTION_IN); - - start_meas(&eNB->schedule_dlsch_preprocessor); - _dlsch_scheduler_pre_processor(mod_id, - slice_id, - frame, - subframe, - N_RBG, - mbsfn_flag); - stop_meas(&eNB->schedule_dlsch_preprocessor); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR,VCD_FUNCTION_OUT); - - for (CC_id=0; CC_id0) - continue; - - for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { - - rnti = flexran_get_ue_crnti(mod_id, UE_id); - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - - if (eNB_UE_stats==NULL) { - - LOG_D(MAC,"[eNB] Cannot find eNB_UE_stats\n"); - // mac_xface->macphy_exit("[MAC][eNB] Cannot find eNB_UE_stats\n"); - continue; - } - - if (flexran_slice_member(UE_id, slice_id) == 0) - continue; - - if (rnti==NOT_A_RNTI) { - LOG_D(MAC,"Cannot find rnti for UE_id %d (num_UEs %d)\n", UE_id,UE_list->num_UEs); - // mac_xface->macphy_exit("Cannot find rnti for UE_id"); - continue; - } - - switch(mac_xface->get_transmission_mode(mod_id,CC_id,rnti)){ - case 1: - case 2: - case 7: - aggregation = get_aggregation(get_bw_index(mod_id,CC_id), - eNB_UE_stats->DL_cqi[0], - format1); - break; - case 3: - aggregation = get_aggregation(get_bw_index(mod_id,CC_id), - eNB_UE_stats->DL_cqi[0], - format2A); - break; - default: - LOG_W(MAC,"Unsupported transmission mode %d\n", mac_xface->get_transmission_mode(mod_id,CC_id,rnti)); - aggregation = 2; - } - - if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated - CCE_allocation_infeasible(mod_id, CC_id, 0, subframe, aggregation, rnti)) { - - LOG_D(MAC,"[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", - mod_id, frame, UE_id, CC_id); - //if(mac_xface->get_transmission_mode(module_idP,rnti)==5) - continue; //to next user (there might be rbs availiable for other UEs in TM5 - // else - // break; - } - - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - set_ue_dai (subframe, - flexran_get_subframe_assignment(mod_id, CC_id), - UE_id, - CC_id, - UE_list); - //TODO: update UL DAI after DLSCH scheduling - //set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe,frame_parms); - } - - channels_added = 0; - - // After this point all the UEs will be scheduled - dl_data[num_ues_added] = (Protocol__FlexDlData *) malloc(sizeof(Protocol__FlexDlData)); - protocol__flex_dl_data__init(dl_data[num_ues_added]); - dl_data[num_ues_added]->has_rnti = 1; - dl_data[num_ues_added]->rnti = rnti; - dl_data[num_ues_added]->n_rlc_pdu = 0; - dl_data[num_ues_added]->has_serv_cell_index = 1; - dl_data[num_ues_added]->serv_cell_index = CC_id; - - flexran_get_harq(mod_id, CC_id, UE_id, frame, subframe, &harq_pid, &round, openair_harq_DL); - sdu_length_total=0; - mcs = cqi_to_mcs[flexran_get_ue_wcqi(mod_id, UE_id)]; - // LOG_I(FLEXRAN_AGENT, "The MCS is %d\n", mcs); - mcs = cmin(mcs,flexran_slice_maxmcs(slice_id)); -// #ifdef EXMIMO - -// if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti) == 5) { -// mcs = cqi_to_mcs[flexran_get_ue_wcqi(mod_id, UE_id)]; -// mcs = cmin(mcs,16); -// } - -// #endif - - /*Get pre available resource blocks based on buffers*/ - nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; - // initializing the rb allocation indicator for each UE - for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { - - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0; - rballoc_sub[j] = 0; - } - - /* LOG_D(MAC,"[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n", */ - /* mod_id, frame, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb, */ - /* eNB_UE_stats->DL_cqi[0], mcs, */ - /* UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); */ - - dl_dci = (Protocol__FlexDlDci*) malloc(sizeof(Protocol__FlexDlDci)); - protocol__flex_dl_dci__init(dl_dci); - dl_data[num_ues_added]->dl_dci = dl_dci; - - - dl_dci->has_rnti = 1; - dl_dci->rnti = rnti; - dl_dci->has_harq_process = 1; - dl_dci->harq_process = harq_pid; - - /* process retransmission */ - if (round > 0) { - - LOG_D(FLEXRAN_AGENT, "There was a retransmission just now and the round was %d\n", round); - - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - UE_list->UE_template[CC_id][UE_id].DAI++; - update_ul_dci(mod_id, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); - LOG_D(MAC,"DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", - CC_id, subframe,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); - } - - mcs = UE_list->UE_template[CC_id][UE_id].mcs[harq_pid]; - - // get freq_allocation - nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - - /*TODO: Must add this to FlexRAN agent API */ - dci_tbs = mac_xface->get_TBS_DL(mcs, nb_rb); - - if (nb_rb <= nb_available_rb) { - - if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { - for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { // for indicating the rballoc for each sub-band - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - } - } else { - nb_rb_temp = nb_rb; - j = 0; - - while((nb_rb_temp > 0) && (j < flexran_get_N_RBG(mod_id, CC_id))) { - if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - - if((j == flexran_get_N_RBG(mod_id, CC_id) - 1) && - ((flexran_get_N_RB_DL(mod_id, CC_id) == 25)|| - (flexran_get_N_RB_DL(mod_id, CC_id) == 50))) { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]+1; - } else { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; - } - } - j = j + 1; - } - } - - nb_available_rb -= nb_rb; - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; - - for(j=0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; - rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; - } - - // Keep the old NDI, do not toggle - ndi = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - tpc = UE_list->UE_template[CC_id][UE_id].oldTPC[harq_pid]; - UE_list->UE_template[CC_id][UE_id].mcs[harq_pid] = mcs; - - ue_has_transmission = 1; - num_ues_added++; - } else { - LOG_D(MAC,"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", - mod_id, frame, CC_id, UE_id); - ue_has_transmission = 0; - } - //End of retransmission - } - - else { /* This is a potentially new SDU opportunity */ - rlc_status.bytes_in_buffer = 0; - // Now check RLC information to compute number of required RBs - // get maximum TBS size for RLC request - //TBS = mac_xface->get_TBS(eNB_UE_stats->DL_cqi[0]<<1,nb_available_rb); - TBS = mac_xface->get_TBS_DL(mcs, nb_available_rb); - dci_tbs = TBS; - LOG_D(FLEXRAN_AGENT, "TBS is %d\n", TBS); - - // check first for RLC data on DCCH - // add the length for all the control elements (timing adv, drx, etc) : header + payload - - ta_len = (ue_sched_ctl->ta_update != 0) ? 2 : 0; - - dl_data[num_ues_added]->n_ce_bitmap = 2; - dl_data[num_ues_added]->ce_bitmap = (uint32_t *) calloc(2, sizeof(uint32_t)); - - if (ta_len > 0) { - ce_flags |= PROTOCOL__FLEX_CE_TYPE__FLPCET_TA; - } - - /*TODO: Add other flags if DRX and other CE are required*/ - - // Add the control element flags to the flexran message - dl_data[num_ues_added]->ce_bitmap[0] = ce_flags; - dl_data[num_ues_added]->ce_bitmap[1] = ce_flags; - - // TODO : Need to prioritize DRBs - // Loop through the UE logical channels (DCCH, DCCH1, DTCH for now) - header_len = 0; - header_len_last = 0; - sdu_length_total = 0; - for (j = 1; j < NB_RB_MAX; j++) { - header_len += 3; - // Need to see if we have space for data from this channel - if (dci_tbs - ta_len - header_len - sdu_length_total > 0) { - LOG_D(MAC, "[TEST]Requested %d bytes from RLC buffer on channel %d during first call\n", dci_tbs-ta_len-header_len, j); - //If we have space, we need to see how much data we can request at most (if any available) - rlc_status = mac_rlc_status_ind(mod_id, - rnti, - mod_id, - frame, - subframe, - ENB_FLAG_YES, - MBMS_FLAG_NO, - j, - (dci_tbs - ta_len - header_len - sdu_length_total)); // transport block set size - - //If data are available in channel j - if (rlc_status.bytes_in_buffer > 0) { - LOG_D(MAC, "[TEST]Have %d bytes in DCCH buffer during first call\n", rlc_status.bytes_in_buffer); - //Fill in as much as possible - data_to_request = cmin(dci_tbs - ta_len - header_len - sdu_length_total, rlc_status.bytes_in_buffer); - LOG_D(FLEXRAN_AGENT, "Will request %d bytes from channel %d\n", data_to_request, j); - - if (data_to_request < 128) { //The header will be one byte less - header_len--; - header_len_last = 2; - } - else { - - header_len_last = 3; - } - /* if (j == 1 || j == 2) { - data_to_request+=0; - } */ - LOG_D(MAC, "[TEST]Will request %d from channel %d\n", data_to_request, j); - rlc_pdus[channels_added] = (Protocol__FlexRlcPdu *) malloc(sizeof(Protocol__FlexRlcPdu)); - protocol__flex_rlc_pdu__init(rlc_pdus[channels_added]); - rlc_pdus[channels_added]->n_rlc_pdu_tb = 2; - rlc_pdus[channels_added]->rlc_pdu_tb = (Protocol__FlexRlcPduTb **) malloc(sizeof(Protocol__FlexRlcPduTb *) * 2); - rlc_pdus[channels_added]->rlc_pdu_tb[0] = (Protocol__FlexRlcPduTb *) malloc(sizeof(Protocol__FlexRlcPduTb)); - protocol__flex_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[0]); - rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_logical_channel_id = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->logical_channel_id = j; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_size = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->size = data_to_request; - rlc_pdus[channels_added]->rlc_pdu_tb[1] = (Protocol__FlexRlcPduTb *) malloc(sizeof(Protocol__FlexRlcPduTb)); - protocol__flex_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[1]); - rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_logical_channel_id = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->logical_channel_id = j; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_size = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->size = data_to_request; - dl_data[num_ues_added]->n_rlc_pdu++; - channels_added++; - //Set this to the max value that we might request - sdu_length_total += data_to_request; - } else { - //Take back the assumption of a header for this channel - header_len -= 3; - } //End rlc_status.bytes_in_buffer <= 0 - } //end of if dci_tbs - ta_len - header_len > 0 - } // End of iterating the logical channels - - // Add rlc_pdus to the dl_data message - dl_data[num_ues_added]->rlc_pdu = (Protocol__FlexRlcPdu **) malloc(sizeof(Protocol__FlexRlcPdu *) * - dl_data[num_ues_added]->n_rlc_pdu); - for (i = 0; i < dl_data[num_ues_added]->n_rlc_pdu; i++) { - dl_data[num_ues_added]->rlc_pdu[i] = rlc_pdus[i]; - } - - if (header_len == 0) { - LOG_D(FLEXRAN_AGENT, "Header was empty\n"); - header_len_last = 0; - } - - // there is a payload - if ((dl_data[num_ues_added]->n_rlc_pdu > 0)) { - // Now compute number of required RBs for total sdu length - // Assume RAH format 2 - // adjust header lengths - LOG_D(FLEXRAN_AGENT, "We have %d bytes to transfer\n", sdu_length_total); - if (header_len != 0) { - LOG_D(FLEXRAN_AGENT, "Header length was %d ", header_len); - header_len_last--; - header_len -= header_len_last; - LOG_D(FLEXRAN_AGENT, "so we resized it to %d\n", header_len); - } - - /* if (header_len == 2 || header_len == 3) { //Only one SDU, remove length field */ - /* header_len = 1; */ - /* } else { //Remove length field from the last SDU */ - /* header_len--; */ - /* } */ - - mcs_tmp = mcs; - if (mcs_tmp == 0) { - nb_rb = 4; // don't let the TBS get too small - } else { - nb_rb=min_rb_unit[CC_id]; - } - - LOG_D(MAC,"[TEST]The initial number of resource blocks was %d\n", nb_rb); - LOG_D(MAC,"[TEST] The initial mcs was %d\n", mcs_tmp); - - TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); - LOG_D(MAC,"[TEST]The TBS during rate matching was %d\n", TBS); - - while (TBS < (sdu_length_total + header_len + ta_len)) { - nb_rb += min_rb_unit[CC_id]; // - LOG_D(MAC, "[TEST]Had to increase the number of RBs\n"); - if (nb_rb > nb_available_rb) { // if we've gone beyond the maximum number of RBs - // (can happen if N_RB_DL is odd) - TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_available_rb); - nb_rb = nb_available_rb; - break; - } - - TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); - } - - if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { - LOG_D(MAC, "[TEST]We had the exact number of rbs. Time to fill the rballoc subband\n"); - for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { // for indicating the rballoc for each sub-band - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - } - } - else { - nb_rb_temp = nb_rb; - j = 0; - LOG_D(MAC, "[TEST]Will only partially fill the bitmap\n"); - while((nb_rb_temp > 0) && (j < flexran_get_N_RBG(mod_id, CC_id))) { - if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { - UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - if ((j == flexran_get_N_RBG(mod_id, CC_id) - 1) && - ((flexran_get_N_RB_DL(mod_id, CC_id) == 25)|| - (flexran_get_N_RB_DL(mod_id, CC_id) == 50))) { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id] + 1; - } else { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; - } - } - j = j+1; - } - } - - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; - - for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { - PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; - } - - // decrease mcs until TBS falls below required length - while ((TBS > (sdu_length_total + header_len + ta_len)) && (mcs_tmp > 0)) { - mcs_tmp--; - TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); - } - - // if we have decreased too much or we don't have enough RBs, increase MCS - while ((TBS < (sdu_length_total + header_len + ta_len)) && - ((( ue_sched_ctl->dl_pow_off[CC_id] > 0) && (mcs_tmp < 28)) || ( (ue_sched_ctl->dl_pow_off[CC_id]==0) && (mcs_tmp <= 15)))) { - mcs_tmp++; - TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); - } - - dci_tbs = TBS; - mcs = mcs_tmp; - LOG_D(FLEXRAN_AGENT, "Final mcs was %d\n", mcs); - - dl_dci->has_aggr_level = 1; - dl_dci->aggr_level = aggregation; - - UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; - - // if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - // UE_list->UE_template[CC_id][UE_id].DAI++; - // // printf("DAI update: subframeP %d: UE %d, DAI %d\n",subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); - //#warning only for 5MHz channel - // update_ul_dci(mod_id, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); - // } - - // do PUCCH power control - // this is the normalized RX power - normalized_rx_power = flexran_get_p0_pucch_dbm(mod_id,UE_id, CC_id); //eNB_UE_stats->Po_PUCCH_dBm; - target_rx_power = flexran_get_p0_nominal_pucch(mod_id, CC_id) + 20; //mac_xface->get_target_pucch_rx_power(mod_id, CC_id) + 20; - // this assumes accumulated tpc - // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out - int32_t framex10psubframe = UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame*10+UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe; - - if (((framex10psubframe+10)<=(frame*10+subframe)) || //normal case - ((framex10psubframe>(frame*10+subframe)) && (((10240-framex10psubframe+frame*10+subframe)>=10)))) //frame wrap-around - if (flexran_get_p0_pucch_status(mod_id, UE_id, CC_id) == 1) { - flexran_update_p0_pucch(mod_id, UE_id, CC_id); - - UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame = frame; - UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe = subframe; - if (normalized_rx_power>(target_rx_power+1)) { - tpc = 0; //-1 - tpc_accumulated--; - } else if (normalized_rx_power<(target_rx_power-1)) { - tpc = 2; //+1 - tpc_accumulated++; - } else { - tpc = 1; //0 - } - LOG_D(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", - mod_id, frame, subframe, harq_pid, tpc, - tpc_accumulated, normalized_rx_power, target_rx_power); - } // Po_PUCCH has been updated - else { - tpc = 1; //0 - } // time to do TPC update - else { - tpc = 1; //0 - } - - for(i=0; iframe_parms.N_RBG; i++) { - rballoc_sub[i] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][i]; - } - - // Toggle NDI - LOG_D(MAC,"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", - CC_id, frame, subframe, UE_id, - UE_list->UE_template[CC_id][UE_id].rnti,harq_pid, UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]); - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]= 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - ndi = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - - UE_list->UE_template[CC_id][UE_id].mcs[harq_pid] = mcs; - UE_list->UE_template[CC_id][UE_id].oldTPC[harq_pid] = tpc; - - // Increase the pointer for the number of scheduled UEs - num_ues_added++; - ue_has_transmission = 1; - } else { // There is no data from RLC or MAC header, so don't schedule - ue_has_transmission = 0; - } - } // End of new scheduling - - // If we has transmission or retransmission - if (ue_has_transmission) { - switch (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)) { - case 1: - case 2: - default: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 1; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = ndi; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->n_tbs_size = 1; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - break; - case 3: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 2; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = ndi; - dl_dci->ndi[1] = ndi; - dl_dci->n_rv = 2; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->rv[1] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 2; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->mcs[1] = mcs; - dl_dci->n_tbs_size = 2; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - dl_dci->tbs_size[1] = dci_tbs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - break; - case 4: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 2; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = ndi; - dl_dci->ndi[1] = ndi; - dl_dci->n_rv = 2; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->rv[1] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 2; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->mcs[1] = mcs; - dl_dci->n_tbs_size = 2; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - dl_dci->tbs_size[1] = dci_tbs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - break; - case 5: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 1; - dl_dci->ndi[0] = ndi; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->n_tbs_size = 1; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - - if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { - ue_sched_ctl->dl_pow_off[CC_id] = 1; - } - - dl_dci->has_dl_power_offset = 1; - dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; - dl_dci->has_precoding_info = 1; - dl_dci->precoding_info = 5; // Is this right?? - - break; - case 6: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 1; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = ndi; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round & 3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - - dl_dci->has_dl_power_offset = 1; - dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; - dl_dci->has_precoding_info = 1; - dl_dci->precoding_info = 5; // Is this right?? - break; - } - } - - // if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { - - /* TODO */ - //set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe, frame_parms); - // } - } // UE_id loop - } // CC_id loop - - // Add all the dl_data elements to the flexran message - int offset = (*dl_info)->dl_mac_config_msg->n_dl_ue_data; - (*dl_info)->dl_mac_config_msg->n_dl_ue_data += num_ues_added; - if ( num_ues_added > 0 ){ - (*dl_info)->dl_mac_config_msg->dl_ue_data = (Protocol__FlexDlData **) realloc( (*dl_info)->dl_mac_config_msg->dl_ue_data, - sizeof(Protocol__FlexDlData *) * ((*dl_info)->dl_mac_config_msg->n_dl_ue_data)); - if ((*dl_info)->dl_mac_config_msg->dl_ue_data == NULL ){ - LOG_E(MAC, "Request for memory reallocation failed\n"); - return; - } - for (i = 0; i < num_ues_added; i++) { - (*dl_info)->dl_mac_config_msg->dl_ue_data[offset+i] = dl_data[i]; - } - } - - stop_meas(&eNB->schedule_dlsch); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_OUT); -} diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c deleted file mode 100644 index 2b0bf72015..0000000000 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file flexran_agent_scheduler_dlsch_ue_remote.c - * \brief procedures related to remote scheduling in the DLSCH transport channel - * \author Xenofon Foukas - * \date 2016 - * \email: x.foukas@sms.ed.ac.uk - * \version 0.1 - * @ingroup _mac - - */ - -#include "flexran_agent_common_internal.h" -#include "flexran_agent_ran_api.h" -#include "flexran_agent_scheduler_dlsch_ue_remote.h" - -#include "LAYER2/MAC/defs.h" -#include "LAYER2/MAC/extern.h" - -struct DlMacConfigHead queue_head; - -int queue_initialized = 0; - -//uint32_t skip_subframe = 1; -//uint32_t period = 10; -//uint32_t sched [] = {1, 2, 3}; - -void -flexran_schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, - uint32_t subframe, int *mbsfn_flag, - Protocol__FlexranMessage ** dl_info) -{ - - - //if ((subframe == skip_subframe) && (frame % period == 0)) { - // LOG_I(MAC, "Will skip subframe %d %d\n", subframe, frame); - // for (int i = 0; i < 3; i++) { - // LOG_I(MAC, "%d\n", sched[i]); - // } - //} - - /* if (frame == 500 && subframe == 1) { */ - /* char policy[] = "rrc: \n - ul_scheduler: \n behavior : tester_function\n parameters:\n period: !!int 3\nmac: \n - dl_scheduler: \n parameters: \n period : !!int 40\n skip_subframe : !!int 3\n sched : [!!int 4, !!int 5, !!int 6]"; */ - /* apply_reconfiguration_policy(mod_id, policy, strlen(policy)); */ - /* } */ - - eNB_MAC_INST *eNB; - - if (!queue_initialized) { - TAILQ_INIT(&queue_head); - queue_initialized = 1; - } - - eNB = &eNB_mac_inst[mod_id]; - - dl_mac_config_element_t *dl_config_elem; - - int diff; - LOG_D(MAC, "[TEST] Current frame and subframe %d, %d\n", frame, - subframe); - // First we check to see if we have a scheduling decision for this sfn_sf already in our queue - while (queue_head.tqh_first != NULL) { - dl_config_elem = queue_head.tqh_first; - - diff = - get_sf_difference(mod_id, - dl_config_elem->dl_info-> - dl_mac_config_msg->sfn_sf); - // Check if this decision is for now, for a later or a previous subframe - if (diff == 0) { // Now - LOG_D(MAC, - "Found a decision for this subframe in the queue. Let's use it!\n"); - TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs); - *dl_info = dl_config_elem->dl_info; - free(dl_config_elem); - eNB->eNB_stats[mod_id].sched_decisions++; - return; - } else if (diff < 0) { //previous subframe , delete message and free memory - LOG_D(MAC, - "Found a decision for a previous subframe in the queue. Let's get rid of it\n"); - TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs); - flexran_agent_mac_destroy_dl_config(dl_config_elem->dl_info); - free(dl_config_elem); - eNB->eNB_stats[mod_id].sched_decisions++; - eNB->eNB_stats[mod_id].missed_deadlines++; - } else { // next subframe, nothing to do now - LOG_D(MAC, - "Found a decision for a future subframe in the queue. Nothing to do now\n"); - flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); - return; - } - } - - //Done with the local cache. Now we need to check if something new arrived - flexran_agent_get_pending_dl_mac_config(mod_id, dl_info); - while (*dl_info != NULL) { - - diff = - get_sf_difference(mod_id, - (*dl_info)->dl_mac_config_msg->sfn_sf); - if (diff == 0) { // Got a command for this sfn_sf - LOG_D(MAC, - "Found a decision for this subframe pending. Let's use it\n"); - eNB->eNB_stats[mod_id].sched_decisions++; - return; - } else if (diff < 0) { - LOG_D(MAC, - "Found a decision for a previous subframe. Let's get rid of it\n"); - flexran_agent_mac_destroy_dl_config(*dl_info); - *dl_info = NULL; - flexran_agent_get_pending_dl_mac_config(mod_id, dl_info); - eNB->eNB_stats[mod_id].sched_decisions++; - eNB->eNB_stats[mod_id].missed_deadlines++; - } else { // Intended for future subframe. Store it in local cache - LOG_D(MAC, - "Found a decision for a future subframe in the queue. Let's store it in the cache\n"); - dl_mac_config_element_t *e = - malloc(sizeof(dl_mac_config_element_t)); - e->dl_info = *dl_info; - TAILQ_INSERT_TAIL(&queue_head, e, configs); - flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); - // No need to look for another. Messages arrive ordered - return; - } - } - - // We found no pending command, so we will simply pass an empty one - flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); -} - -int get_sf_difference(mid_t mod_id, uint32_t sfn_sf) -{ - int diff_in_subframes; - - uint16_t current_frame = flexran_get_current_system_frame_num(mod_id); - uint16_t current_subframe = flexran_get_current_subframe(mod_id); - uint32_t current_sfn_sf = flexran_get_sfn_sf(mod_id); - - if (sfn_sf == current_sfn_sf) { - return 0; - } - - uint16_t frame_mask = ((1 << 12) - 1); - uint16_t frame = (sfn_sf & (frame_mask << 4)) >> 4; - - uint16_t sf_mask = ((1 << 4) - 1); - uint16_t subframe = (sfn_sf & sf_mask); - - LOG_D(MAC, "[TEST] Target frame and subframe %d, %d\n", frame, - subframe); - - if (frame == current_frame) { - return subframe - current_subframe; - } else if (frame > current_frame) { - diff_in_subframes = - ((frame * 10) + subframe) - ((current_frame * 10) + - current_subframe); - - // diff_in_subframes = 9 - current_subframe; - //diff_in_subframes += (subframe + 1); - //diff_in_subframes += (frame-2) * 10; - if (diff_in_subframes > SCHED_AHEAD_SUBFRAMES) { - return -1; - } else { - return 1; - } - } else { //frame < current_frame - //diff_in_subframes = 9 - current_subframe; - //diff_in_subframes += (subframe + 1); - //if (frame > 0) { - // diff_in_subframes += (frame - 1) * 10; - //} - //diff_in_subframes += (1023 - current_frame) * 10; - diff_in_subframes = - 10240 - ((current_frame * 10) + current_subframe) + - ((frame * 10) + subframe); - if (diff_in_subframes > SCHED_AHEAD_SUBFRAMES) { - return -1; - } else { - return 1; - } - } -} diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h deleted file mode 100644 index 449ba1e8cd..0000000000 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file flexran_agent_scheduler_dlsch_ue_remote.h - * \brief Local stub for remote scheduler used by the controller - * \author Xenofon Foukas - * \date 2016 - * \email: x.foukas@sms.ed.ac.uk - * \version 0.1 - * @ingroup _mac - - */ - -#ifndef __LAYER2_MAC_FLEXRAN_AGENT_SCHEDULER_DLSCH_UE_REMOTE_H__ -#define __LAYER2_MAC_FLEXRAN_AGENT_SCHEDULER_DLSCH_UE_REMOTE_H___ - -#include "flexran.pb-c.h" -#include "header.pb-c.h" - -#include "ENB_APP/flexran_agent_defs.h" -#include "flexran_agent_mac.h" -#include "LAYER2/MAC/flexran_agent_mac_proto.h" - -#include - -// Maximum value of schedule ahead of time -// Required to identify if a dl_command is for the future or not -#define SCHED_AHEAD_SUBFRAMES 20 - -typedef struct dl_mac_config_element_s { - Protocol__FlexranMessage *dl_info; - TAILQ_ENTRY(dl_mac_config_element_s) configs; -} dl_mac_config_element_t; - -TAILQ_HEAD(DlMacConfigHead, dl_mac_config_element_s); - -/* - * Default scheduler used by the eNB agent - */ -void flexran_schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, - uint32_t subframe, int *mbsfn_flag, - Protocol__FlexranMessage ** dl_info); - - -// Find the difference in subframes from the given subframe -// negative for older value -// 0 for equal -// positive for future value -// Based on -int get_sf_difference(mid_t mod_id, uint32_t sfn_sf); - -#endif diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c deleted file mode 100644 index 86ea61d943..0000000000 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_ulsch_ue.c +++ /dev/null @@ -1,1112 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file eNB_scheduler_ulsch.c - * \brief FlexRAN eNB procedures for the ULSCH transport channel - * \author Navid Nikaein and shahab SHARIAT BAGHERI - * \date 2017 - * \version 1.0 - * @ingroup _mac - - */ - -#include "assertions.h" -#include "PHY/defs.h" -#include "PHY/extern.h" - -#include "SCHED/defs.h" -#include "SCHED/extern.h" - -#include "LAYER2/MAC/flexran_agent_mac_proto.h" -#include "LAYER2/MAC/defs.h" -#include "LAYER2/MAC/proto.h" -#include "LAYER2/MAC/extern.h" -#include "UTIL/LOG/log.h" -#include "UTIL/LOG/vcd_signal_dumper.h" -#include "UTIL/OPT/opt.h" -#include "OCG.h" -#include "OCG_extern.h" - -#include "RRC/LITE/extern.h" -#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" - -//#include "LAYER2/MAC/pre_processor.c" -#include "ENB_APP/flexran_agent_defs.h" -#include "flexran_agent_ran_api.h" -#include "pdcp.h" - -#include "header.pb-c.h" -#include "flexran.pb-c.h" -#include "flexran_agent_mac.h" - -#if defined(ENABLE_ITTI) -# include "intertask_interface.h" -#endif - -#include "T.h" - -#include - -/* number of active slices for past and current time*/ -int n_active_slices_uplink = 1; -int n_active_slices_current_uplink = 1; - -/* RB share for each slice for past and current time*/ -float avg_slice_percentage_uplink=0.25; -float slice_percentage_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; -float slice_percentage_current_uplink[MAX_NUM_SLICES] = {1.0, 0.0, 0.0, 0.0}; -float total_slice_percentage_uplink = 0; -float total_slice_percentage_current_uplink = 0; - -// MAX MCS for each slice for past and current time -int slice_maxmcs_uplink[MAX_NUM_SLICES] = {16, 16, 16, 16}; -int slice_maxmcs_current_uplink[MAX_NUM_SLICES] = {16,16,16,16}; - -/*resource blocks allowed*/ -uint16_t nb_rbs_allowed_slice_uplink[MAX_NUM_CCs][MAX_NUM_SLICES]; -/*Slice Update */ -int update_ul_scheduler[MAX_NUM_SLICES] = {1, 1, 1, 1}; -int update_ul_scheduler_current[MAX_NUM_SLICES] = {1, 1, 1, 1}; - - /* Slice Function Pointer */ -slice_scheduler_ul slice_sched_ul[MAX_NUM_SLICES] = {0}; - -/* name of available scheduler*/ -char *ul_scheduler_type[MAX_NUM_SLICES] = {"flexran_schedule_ue_ul_spec_embb", - "flexran_schedule_ue_ul_spec_embb", - "flexran_schedule_ue_ul_spec_embb", - "flexran_schedule_ue_ul_spec_embb" // best effort -}; - - -uint16_t flexran_nb_rbs_allowed_slice_uplink(float rb_percentage, int total_rbs){ - return (uint16_t) floor(rb_percentage * total_rbs); -} - - -void _assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, sub_frame_t subframeP, uint16_t *first_rb) -{ - - int i; - uint16_t n,UE_id; - uint8_t CC_id; - rnti_t rnti = -1; - int mcs; - int rb_table_index=0,tbs,tx_power; - eNB_MAC_INST *eNB = &eNB_mac_inst[module_idP]; - UE_list_t *UE_list = &eNB->UE_list; - - UE_TEMPLATE *UE_template; - LTE_DL_FRAME_PARMS *frame_parms; - - - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i] != TRUE) continue; - - rnti = UE_RNTI(module_idP,i); - - if (rnti==NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - if (!phy_stats_exist(module_idP, rnti)) - continue; - - if (UE_list->UE_sched_ctrl[i].phr_received == 1) - mcs = 20; // if we've received the power headroom information the UE, we can go to maximum mcs - else - mcs = 10; // otherwise, limit to QPSK PUSCH - - UE_id = i; - - for (n=0; nnumactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - - if (CC_id >= MAX_NUM_CCs) { - LOG_E( MAC, "CC_id %u should be < %u, loop n=%u < numactiveULCCs[%u]=%u", - CC_id, - MAX_NUM_CCs, - n, - UE_id, - UE_list->numactiveULCCs[UE_id]); - } - - AssertFatal( CC_id < MAX_NUM_CCs, "CC_id %u should be < %u, loop n=%u < numactiveULCCs[%u]=%u", - CC_id, - MAX_NUM_CCs, - n, - UE_id, - UE_list->numactiveULCCs[UE_id]); - frame_parms=mac_xface->get_lte_frame_parms(module_idP,CC_id); - UE_template = &UE_list->UE_template[CC_id][UE_id]; - nb_rbs_allowed_slice_uplink[CC_id][UE_id] = flexran_nb_rbs_allowed_slice_uplink(slice_percentage_uplink[UE_id], flexran_get_N_RB_UL(module_idP, CC_id)); - // if this UE has UL traffic - if (UE_template->ul_total_buffer > 0 ) { - - tbs = mac_xface->get_TBS_UL(mcs,3); // 1 or 2 PRB with cqi enabled does not work well! - // fixme: set use_srs flag - tx_power= mac_xface->estimate_ue_tx_power(tbs,rb_table[rb_table_index],0,frame_parms->Ncp,0); - - while ((((UE_template->phr_info - tx_power) < 0 ) || (tbs > UE_template->ul_total_buffer))&& - (mcs > 3)) { - // LOG_I(MAC,"UE_template->phr_info %d tx_power %d mcs %d\n", UE_template->phr_info,tx_power, mcs); - mcs--; - tbs = mac_xface->get_TBS_UL(mcs,rb_table[rb_table_index]); - tx_power = mac_xface->estimate_ue_tx_power(tbs,rb_table[rb_table_index],0,frame_parms->Ncp,0); // fixme: set use_srs - } - - while ((tbs < UE_template->ul_total_buffer) && - (rb_table[rb_table_index]<(nb_rbs_allowed_slice_uplink[CC_id][UE_id]-first_rb[CC_id])) && - ((UE_template->phr_info - tx_power) > 0) && - (rb_table_index < 32 )) { - // LOG_I(MAC,"tbs %d ul buffer %d rb table %d max ul rb %d\n", tbs, UE_template->ul_total_buffer, rb_table[rb_table_index], frame_parms->N_RB_UL-first_rb[CC_id]); - rb_table_index++; - tbs = mac_xface->get_TBS_UL(mcs,rb_table[rb_table_index]); - tx_power = mac_xface->estimate_ue_tx_power(tbs,rb_table[rb_table_index],0,frame_parms->Ncp,0); - } - - UE_template->ue_tx_power = tx_power; - - if (rb_table[rb_table_index]>(nb_rbs_allowed_slice_uplink[CC_id][UE_id]-first_rb[CC_id]-1)) { - rb_table_index--; - } - - // 1 or 2 PRB with cqi enabled does not work well! - if (rb_table[rb_table_index]<3) { - rb_table_index=2; //3PRB - } - - UE_template->pre_assigned_mcs_ul=mcs; - UE_template->pre_allocated_rb_table_index_ul=rb_table_index; - UE_template->pre_allocated_nb_rb_ul= rb_table[rb_table_index]; - LOG_D(MAC,"[eNB %d] frame %d subframe %d: for UE %d CC %d: pre-assigned mcs %d, pre-allocated rb_table[%d]=%d RBs (phr %d, tx power %d)\n", - module_idP, frameP, subframeP, UE_id, CC_id, - UE_template->pre_assigned_mcs_ul, - UE_template->pre_allocated_rb_table_index_ul, - UE_template->pre_allocated_nb_rb_ul, - UE_template->phr_info,tx_power); - } else { - UE_template->pre_allocated_rb_table_index_ul=-1; - UE_template->pre_allocated_nb_rb_ul=0; - } - } - } -} - - - - -void _ulsch_scheduler_pre_processor(module_id_t module_idP, - int slice_id, - int frameP, - sub_frame_t subframeP, - uint16_t *first_rb) -{ - - int16_t i; - uint16_t UE_id,n,r; - uint8_t CC_id, round, harq_pid; - uint16_t nb_allocated_rbs[MAX_NUM_CCs][NUMBER_OF_UE_MAX],total_allocated_rbs[MAX_NUM_CCs],average_rbs_per_user[MAX_NUM_CCs]; - uint16_t nb_rbs_allowed_slice_uplink[MAX_NUM_CCs][MAX_NUM_SLICES]; - int16_t total_remaining_rbs[MAX_NUM_CCs]; - uint16_t max_num_ue_to_be_scheduled=0,total_ue_count=0; - rnti_t rnti= -1; - UE_list_t *UE_list = &eNB_mac_inst[module_idP].UE_list; - UE_TEMPLATE *UE_template = 0; - // LTE_DL_FRAME_PARMS *frame_parms; //Not used yet - UE_sched_ctrl *ue_sched_ctl; - - - //LOG_I(MAC,"assign max mcs min rb\n"); - // maximize MCS and then allocate required RB according to the buffer occupancy with the limit of max available UL RB - _assign_max_mcs_min_rb(module_idP, slice_id, frameP, subframeP, first_rb); - - //LOG_I(MAC,"sort ue \n"); - // sort ues - sort_ue_ul (module_idP,frameP, subframeP); - - - // we need to distribute RBs among UEs - // step1: reset the vars - for (CC_id=0; CC_idhead_ul; i>=0; i=UE_list->next_ul[i]) { - nb_allocated_rbs[CC_id][i]=0; - } - } - - //LOG_I(MAC,"step2 \n"); - // step 2: calculate the average rb per UE - total_ue_count =0; - max_num_ue_to_be_scheduled=0; - - for (i=UE_list->head_ul; i>=0; i=UE_list->next_ul[i]) { - - rnti = UE_RNTI(module_idP,i); - - if (rnti==NOT_A_RNTI) - continue; - - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - - if (!phy_stats_exist(module_idP, rnti)) - continue; - - UE_id = i; - - for (n=0; nnumactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - UE_template = &UE_list->UE_template[CC_id][UE_id]; - average_rbs_per_user[CC_id]=0; - // frame_parms = mac_xface->get_lte_frame_parms(module_idP,CC_id); - - if (UE_template->pre_allocated_nb_rb_ul > 0) { - total_ue_count+=1; - } - /* - if((mac_xface->get_nCCE_max(module_idP,CC_id,3,subframeP) - nCCE_to_be_used[CC_id]) > (1< 0 ) { - average_rbs_per_user[CC_id] = (uint16_t) floor((nb_rbs_allowed_slice_uplink[CC_id][i]-first_rb[CC_id])/max_num_ue_to_be_scheduled); - } else { - average_rbs_per_user[CC_id]=1; - LOG_W(MAC,"[eNB %d] frame %d subframe %d: UE %d CC %d: can't get average rb per user (should not be here)\n", - module_idP,frameP,subframeP,UE_id,CC_id); - } - } - } - if (total_ue_count > 0) - LOG_D(MAC,"[eNB %d] Frame %d subframe %d: total ue to be scheduled %d/%d\n", - module_idP, frameP, subframeP,total_ue_count, max_num_ue_to_be_scheduled); - - //LOG_D(MAC,"step3\n"); - - // step 3: assigne RBS - for (i=UE_list->head_ul; i>=0; i=UE_list->next_ul[i]) { - rnti = UE_RNTI(module_idP,i); - - if (rnti==NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - if (!phy_stats_exist(module_idP, rnti)) - continue; - - UE_id = i; - - for (n=0; nnumactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - ue_sched_ctl->max_allowed_rbs[CC_id]=nb_rbs_allowed_slice_uplink[CC_id][UE_id]; - // mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL); - flexran_get_harq(module_idP, CC_id, UE_id, frameP, subframeP, &harq_pid, &round, openair_harq_UL); - if(round>0) { - nb_allocated_rbs[CC_id][UE_id] = UE_list->UE_template[CC_id][UE_id].nb_rb_ul[harq_pid]; - } else { - nb_allocated_rbs[CC_id][UE_id] = cmin(UE_list->UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul, average_rbs_per_user[CC_id]); - } - - total_allocated_rbs[CC_id]+= nb_allocated_rbs[CC_id][UE_id]; - - } - } - - // step 4: assigne the remaining RBs and set the pre_allocated rbs accordingly - for(r=0; r<2; r++) { - - for (i=UE_list->head_ul; i>=0; i=UE_list->next_ul[i]) { - rnti = UE_RNTI(module_idP,i); - - if (rnti==NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - if (!phy_stats_exist(module_idP, rnti)) - continue; - - UE_id = i; - - for (n=0; nnumactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - UE_template = &UE_list->UE_template[CC_id][UE_id]; - // frame_parms = mac_xface->get_lte_frame_parms(module_idP,CC_id); - total_remaining_rbs[CC_id]=nb_rbs_allowed_slice_uplink[CC_id][UE_id] - first_rb[CC_id] - total_allocated_rbs[CC_id]; - - if (total_ue_count == 1 ) { - total_remaining_rbs[CC_id]+=1; - } - - if ( r == 0 ) { - while ( (UE_template->pre_allocated_nb_rb_ul > 0 ) && - (nb_allocated_rbs[CC_id][UE_id] < UE_template->pre_allocated_nb_rb_ul) && - (total_remaining_rbs[CC_id] > 0)) { - nb_allocated_rbs[CC_id][UE_id] = cmin(nb_allocated_rbs[CC_id][UE_id]+1,UE_template->pre_allocated_nb_rb_ul); - total_remaining_rbs[CC_id]--; - total_allocated_rbs[CC_id]++; - } - } else { - UE_template->pre_allocated_nb_rb_ul= nb_allocated_rbs[CC_id][UE_id]; - LOG_D(MAC,"******************UL Scheduling Information for UE%d CC_id %d ************************\n",UE_id, CC_id); - LOG_D(MAC,"[eNB %d] total RB allocated for UE%d CC_id %d = %d\n", module_idP, UE_id, CC_id, UE_template->pre_allocated_nb_rb_ul); - } - } - } - } - - for (CC_id=0; CC_idget_lte_frame_parms(module_idP,CC_id); - - if (total_allocated_rbs[CC_id]>0) { - LOG_D(MAC,"[eNB %d] total RB allocated for all UEs = %d/%d\n", module_idP, total_allocated_rbs[CC_id], nb_rbs_allowed_slice_uplink[CC_id][slice_id] - first_rb[CC_id]); - } - } -} - -/* - * Main Uplink Slicing - * - */ - -void -flexran_schedule_ue_ul_spec_default(mid_t mod_id, - uint32_t frame, - uint32_t cooperation_flag, - int subframe, - unsigned char sched_subframe, - Protocol__FlexranMessage **ul_info) -//------------------------------------------------------------------------------ -{ - int i=0; - - flexran_agent_mac_create_empty_ul_config(mod_id, ul_info); - - total_slice_percentage_uplink=0; - avg_slice_percentage_uplink=1.0/n_active_slices_uplink; - - // reset the slice percentage for inactive slices - for (i = n_active_slices_uplink; i< MAX_NUM_SLICES; i++) { - slice_percentage_uplink[i]=0; - } - for (i = 0; i < n_active_slices_uplink; i++) { - if (slice_percentage_uplink[i] < 0 ){ - LOG_W(MAC, "[eNB %d] frame %d subframe %d:invalid slice %d percentage %f. resetting to zero", - mod_id, frame, subframe, i, slice_percentage_uplink[i]); - slice_percentage_uplink[i]=0; - } - total_slice_percentage_uplink+=slice_percentage_uplink[i]; - } - - for (i = 0; i < n_active_slices_uplink; i++) { - - // Load any updated functions - if (update_ul_scheduler[i] > 0 ) { - slice_sched_ul[i] = dlsym(NULL, ul_scheduler_type[i]); - update_ul_scheduler[i] = 0; - update_ul_scheduler_current[i] = 0; - //slice_percentage_current_uplink[i]= slice_percentage_uplink[i]; - //total_slice_percentage_current_uplink+=slice_percentage_uplink[i]; - //if (total_slice_percentage_current_uplink> 1) - // total_slice_percentage_current_uplink=1; - LOG_N(MAC,"update ul scheduler slice %d\n", i); - } - // the new total RB share is within the range - if (total_slice_percentage_uplink <= 1.0){ - - // check if the number of slices has changed, and log - if (n_active_slices_current_uplink != n_active_slices_uplink ){ - if ((n_active_slices_uplink > 0) && (n_active_slices_uplink <= MAX_NUM_SLICES)) { - LOG_N(MAC,"[eNB %d]frame %d subframe %d: number of active UL slices has changed: %d-->%d\n", - mod_id, frame, subframe, n_active_slices_current_uplink, n_active_slices_uplink); - - n_active_slices_current_uplink = n_active_slices_uplink; - - } else { - LOG_W(MAC,"invalid number of UL slices %d, revert to the previous value %d\n",n_active_slices_uplink, n_active_slices_current_uplink); - n_active_slices_uplink = n_active_slices_current_uplink; - } - } - - // check if the slice rb share has changed, and log the console - if (slice_percentage_current_uplink[i] != slice_percentage_uplink[i]){ - LOG_N(MAC,"[eNB %d][SLICE %d][UL] frame %d subframe %d: total percentage %f-->%f, slice RB percentage has changed: %f-->%f\n", - mod_id, i, frame, subframe, total_slice_percentage_current_uplink, total_slice_percentage_uplink, slice_percentage_current_uplink[i], slice_percentage_uplink[i]); - total_slice_percentage_current_uplink= total_slice_percentage_uplink; - slice_percentage_current_uplink[i] = slice_percentage_uplink[i]; - - } - - // check if the slice max MCS, and log the console - if (slice_maxmcs_current_uplink[i] != slice_maxmcs_uplink[i]){ - if ((slice_maxmcs_uplink[i] >= 0) && (slice_maxmcs_uplink[i] <= 16)){ - LOG_N(MAC,"[eNB %d][SLICE %d][UL] frame %d subframe %d: slice MAX MCS has changed: %d-->%d\n", - mod_id, i, frame, subframe, slice_maxmcs_current_uplink[i], slice_maxmcs_uplink[i]); - slice_maxmcs_current_uplink[i] = slice_maxmcs_uplink[i]; - } else { - LOG_W(MAC,"[eNB %d][SLICE %d][UL] invalid slice max mcs %d, revert the previous value %d\n",mod_id, i, slice_maxmcs_uplink[i],slice_maxmcs_current_uplink[i]); - slice_maxmcs_uplink[i]= slice_maxmcs_current_uplink[i]; - - } - } - - // check if a new scheduler, and log the console - if (update_ul_scheduler_current[i] != update_ul_scheduler[i]){ - LOG_N(MAC,"[eNB %d][SLICE %d][UL] frame %d subframe %d: UL scheduler for this slice is updated: %s \n", - mod_id, i, frame, subframe, ul_scheduler_type[i]); - - update_ul_scheduler_current[i] = update_ul_scheduler[i]; - } - } - else { - - if (n_active_slices_uplink == n_active_slices_current_uplink){ - LOG_W(MAC,"[eNB %d][SLICE %d][UL] invalid total RB share (%f->%f), reduce proportionally the RB share by 0.1\n", - mod_id,i, - total_slice_percentage_current_uplink, total_slice_percentage_uplink); - if (slice_percentage_uplink[i] > avg_slice_percentage_uplink){ - slice_percentage_uplink[i]-=0.1; - total_slice_percentage_uplink-=0.1; - } - } else { - // here we can correct the values, e.g. reduce proportionally - LOG_W(MAC,"[eNB %d][SLICE %d][UL] invalid total RB share (%f->%f), revert the number of slice to its previous value (%d->%d)\n", - mod_id,i, - total_slice_percentage_current_uplink, total_slice_percentage_uplink, - n_active_slices_uplink, n_active_slices_current_uplink); - n_active_slices_uplink = n_active_slices_current_uplink; - slice_percentage_uplink[i] = slice_percentage_current_uplink[i]; - } - } - - // Run each enabled slice-specific schedulers one by one - slice_sched_ul[i](mod_id, frame, cooperation_flag, subframe, sched_subframe,ul_info); - } -} - -void -flexran_schedule_ue_ul_spec_embb(mid_t mod_id, - frame_t frame, - unsigned char cooperation_flag, - uint32_t subframe, - unsigned char sched_subframe, - Protocol__FlexranMessage **ul_info) - -{ - flexran_agent_schedule_ulsch_ue_spec(mod_id, - frame, - cooperation_flag, - subframe, - sched_subframe, - ul_info); - -} - - -void flexran_agent_schedule_ulsch_ue_spec(mid_t module_idP, - frame_t frameP, - unsigned char cooperation_flag, - sub_frame_t subframeP, - unsigned char sched_subframe, - Protocol__FlexranMessage **ul_info) { - - - uint16_t first_rb[MAX_NUM_CCs],i; - int CC_id; - eNB_MAC_INST *eNB=&eNB_mac_inst[module_idP]; - - start_meas(&eNB->schedule_ulsch); - - - for (CC_id=0; CC_idcommon_channels[CC_id].RA_template[i].RA_active == TRUE) && - (eNB->common_channels[CC_id].RA_template[i].generate_rar == 0) && - (eNB->common_channels[CC_id].RA_template[i].generate_Msg4 == 0) && - (eNB->common_channels[CC_id].RA_template[i].wait_ack_Msg4 == 0) && - (eNB->common_channels[CC_id].RA_template[i].Msg3_subframe == sched_subframe)) { - first_rb[CC_id]++; - eNB->common_channels[CC_id].RA_template[i].Msg3_subframe = -1; - break; - } - } - - /* - if (mac_xface->is_prach_subframe(&(mac_xface->lte_frame_parms),frameP,subframeP)) { - first_rb[CC_id] = (mac_xface->get_prach_prb_offset(&(mac_xface->lte_frame_parms), - */ - - } - - flexran_agent_schedule_ulsch_rnti(module_idP, cooperation_flag, frameP, subframeP, sched_subframe,first_rb); - - stop_meas(&eNB->schedule_ulsch); - -} - - - -void flexran_agent_schedule_ulsch_rnti(module_id_t module_idP, - unsigned char cooperation_flag, - frame_t frameP, - sub_frame_t subframeP, - unsigned char sched_subframe, - uint16_t *first_rb) -{ - - int UE_id; - uint8_t aggregation = 2; - rnti_t rnti = -1; - uint8_t round = 0; - uint8_t harq_pid = 0; - void *ULSCH_dci = NULL; - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - DCI_PDU *DCI_pdu; - uint8_t status = 0; - uint8_t rb_table_index = -1; - uint16_t TBS = 0; - // int32_t buffer_occupancy=0; - uint32_t cqi_req,cshift,ndi,mcs=0,rballoc,tpc; - int32_t normalized_rx_power, target_rx_power=-90; - static int32_t tpc_accumulated=0; - - int n,CC_id = 0; - eNB_MAC_INST *eNB=&eNB_mac_inst[module_idP]; - UE_list_t *UE_list=&eNB->UE_list; - UE_TEMPLATE *UE_template; - UE_sched_ctrl *UE_sched_ctrl; - - // int rvidx_tab[4] = {0,2,3,1}; - LTE_DL_FRAME_PARMS *frame_parms; - int drop_ue=0; - - // LOG_I(MAC,"entering ulsch preprocesor\n"); - - - /*TODO*/ - int slice_id = 0; - - - _ulsch_scheduler_pre_processor(module_idP, - slice_id, - frameP, - subframeP, - first_rb); - - // LOG_I(MAC,"exiting ulsch preprocesor\n"); - - // loop over all active UEs - for (UE_id=UE_list->head_ul; UE_id>=0; UE_id=UE_list->next_ul[UE_id]) { - - // don't schedule if Msg4 is not received yet - if (UE_list->UE_template[UE_PCCID(module_idP,UE_id)][UE_id].configured==FALSE) { - LOG_I(MAC,"[eNB %d] frame %d subfarme %d, UE %d: not configured, skipping UE scheduling \n", - module_idP,frameP,subframeP,UE_id); - continue; - } - - rnti = flexran_get_ue_crnti(module_idP, UE_id); - - if (rnti==NOT_A_RNTI) { - LOG_W(MAC,"[eNB %d] frame %d subfarme %d, UE %d: no RNTI \n", module_idP,frameP,subframeP,UE_id); - continue; - } - - /* let's drop the UE if get_eNB_UE_stats returns NULL when calling it with any of the UE's active UL CCs */ - /* TODO: refine? */ - drop_ue = 0; - for (n=0; nnumactiveULCCs[UE_id]; n++) { - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - if (mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti) == NULL) { - LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: no PHY context\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id); - drop_ue = 1; - break; - } - } - if (drop_ue == 1) { -/* we can't come here, ulsch_scheduler_pre_processor won't put in the list a UE with no PHY context */ -abort(); - /* TODO: this is a hack. Sometimes the UE has no PHY context but - * is still present in the MAC with 'ul_failure_timer' = 0 and - * 'ul_out_of_sync' = 0. It seems wrong and the UE stays there forever. Let's - * start an UL out of sync procedure in this case. - * The root cause of this problem has to be found and corrected. - * In the meantime, this hack... - */ - if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 0 && - UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 0) { - LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: UE in weird state, let's put it 'out of sync'\n", - module_idP,frameP,subframeP,UE_id,rnti,CC_id); - // inform RRC of failure and clear timer - mac_eNB_rrc_ul_failure(module_idP,CC_id,frameP,subframeP,rnti); - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer=0; - UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync=1; - } - continue; - } - - // loop over all active UL CC_ids for this UE - for (n=0; nnumactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - frame_parms = mac_xface->get_lte_frame_parms(module_idP,CC_id); - eNB_UE_stats = mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti); - - aggregation=get_aggregation(get_bw_index(module_idP,CC_id), - eNB_UE_stats->DL_cqi[0], - format0); - - if (CCE_allocation_infeasible(module_idP,CC_id,0,subframeP,aggregation,rnti)) { - LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: not enough nCCE\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id); - continue; // break; - } else{ - LOG_D(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d mode %s: aggregation level %d\n", - module_idP,frameP,subframeP,UE_id,rnti,CC_id, mode_string[eNB_UE_stats->mode], 1<mode == PUSCH) { // ue has a ulsch channel - - DCI_pdu = &eNB->common_channels[CC_id].DCI_pdu; - UE_template = &UE_list->UE_template[CC_id][UE_id]; - UE_sched_ctrl = &UE_list->UE_sched_ctrl[UE_id]; - - if (flexran_get_harq(module_idP, CC_id, UE_id, frameP, subframeP, &harq_pid, &round, openair_harq_UL) == -1 ) { - LOG_W(MAC,"[eNB %d] Scheduler Frame %d, subframeP %d: candidate harq_pid from PHY for UE %d CC %d RNTI %x\n", - module_idP,frameP,subframeP, UE_id, CC_id, rnti); - continue; - } else - LOG_T(MAC,"[eNB %d] Frame %d, subframeP %d, UE %d CC %d : got harq pid %d round %d (rnti %x,mode %s)\n", - module_idP,frameP,subframeP,UE_id,CC_id, harq_pid, round,rnti,mode_string[eNB_UE_stats->mode]); - - PHY_vars_eNB_g[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP*10)+subframeP] = UE_template->ul_total_buffer; - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BO,PHY_vars_eNB_g[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP*10)+subframeP]); - if (((UE_is_to_be_scheduled(module_idP,CC_id,UE_id)>0)) || (round>0))// || ((frameP%10)==0)) - // if there is information on bsr of DCCH, DTCH or if there is UL_SR, or if there is a packet to retransmit, or we want to schedule a periodic feedback every 10 frames - { - LOG_D(MAC,"[eNB %d][PUSCH] Frame %d subframe %d Scheduling UE %d/%x in round %d(SR %d,UL_inactivity timer %d,UL_failure timer %d)\n", - module_idP,frameP,subframeP,UE_id,rnti,round,UE_template->ul_SR, - UE_sched_ctrl->ul_inactivity_timer, - UE_sched_ctrl->ul_failure_timer); - // reset the scheduling request - UE_template->ul_SR = 0; - // status = mac_eNB_get_rrc_status(module_idP,rnti); - status = flexran_get_rrc_status(module_idP, rnti); - - if (status < RRC_CONNECTED) - cqi_req = 0; - else if (UE_sched_ctrl->cqi_req_timer>30) { - cqi_req = 1; - UE_sched_ctrl->cqi_req_timer=0; - } - else - cqi_req = 0; - - //power control - //compute the expected ULSCH RX power (for the stats) - - // this is the normalized RX power and this should be constant (regardless of mcs - normalized_rx_power = eNB_UE_stats->UL_rssi[0]; - target_rx_power = mac_xface->get_target_pusch_rx_power(module_idP,CC_id); - - // this assumes accumulated tpc - // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out - int32_t framex10psubframe = UE_template->pusch_tpc_tx_frame*10+UE_template->pusch_tpc_tx_subframe; - if (((framex10psubframe+10)<=(frameP*10+subframeP)) || //normal case - ((framex10psubframe>(frameP*10+subframeP)) && (((10240-framex10psubframe+frameP*10+subframeP)>=10)))) //frame wrap-around - { - UE_template->pusch_tpc_tx_frame=frameP; - UE_template->pusch_tpc_tx_subframe=subframeP; - if (normalized_rx_power>(target_rx_power+1)) { - tpc = 0; //-1 - tpc_accumulated--; - } else if (normalized_rx_power<(target_rx_power-1)) { - tpc = 2; //+1 - tpc_accumulated++; - } else { - tpc = 1; //0 - } - } else { - tpc = 1; //0 - } - - if (tpc!=1) { - LOG_D(MAC,"[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", - module_idP,frameP,subframeP,harq_pid,tpc, - tpc_accumulated,normalized_rx_power,target_rx_power); - } - - // new transmission - if (round==0) { - - ndi = 1-UE_template->oldNDI_UL[harq_pid]; - UE_template->oldNDI_UL[harq_pid]=ndi; - UE_list->eNB_UE_stats[CC_id][UE_id].normalized_rx_power=normalized_rx_power; - UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power=target_rx_power; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=UE_template->pre_assigned_mcs_ul; - mcs = UE_template->pre_assigned_mcs_ul;//cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS - if (UE_template->pre_allocated_rb_table_index_ul >=0) { - rb_table_index=UE_template->pre_allocated_rb_table_index_ul; - } else { - mcs=10;//cmin (10, openair_daq_vars.target_ue_ul_mcs); - rb_table_index=5; // for PHR - } - - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; - // buffer_occupancy = UE_template->ul_total_buffer; - - while (((rb_table[rb_table_index]>(nb_rbs_allowed_slice_uplink[CC_id][UE_id]-1-first_rb[CC_id])) || - (rb_table[rb_table_index]>45)) && - (rb_table_index>0)) { - rb_table_index--; - } - - TBS = mac_xface->get_TBS_UL(mcs,rb_table[rb_table_index]); - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=rb_table[rb_table_index]; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_TBS=TBS; - // buffer_occupancy -= TBS; - rballoc = mac_xface->computeRIV(frame_parms->N_RB_UL, - first_rb[CC_id], - rb_table[rb_table_index]); - - T(T_ENB_MAC_UE_UL_SCHEDULE, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), - T_INT(subframeP), T_INT(harq_pid), T_INT(mcs), T_INT(first_rb[CC_id]), T_INT(rb_table[rb_table_index]), - T_INT(TBS), T_INT(ndi)); - - if (mac_eNB_get_rrc_status(module_idP,rnti) < RRC_CONNECTED) - LOG_I(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE %d (mcs %d, first rb %d, nb_rb %d, rb_table_index %d, TBS %d, harq_pid %d)\n", - module_idP,harq_pid,rnti,CC_id,frameP,subframeP,UE_id,mcs, - first_rb[CC_id],rb_table[rb_table_index], - rb_table_index,TBS,harq_pid); - - // bad indices : 20 (40 PRB), 21 (45 PRB), 22 (48 PRB) - // increment for next UE allocation - first_rb[CC_id]+=rb_table[rb_table_index]; - //store for possible retransmission - UE_template->nb_rb_ul[harq_pid] = rb_table[rb_table_index]; - UE_sched_ctrl->ul_scheduled |= (1<head) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_SCHEDULED,UE_sched_ctrl->ul_scheduled); - - // adjust total UL buffer status by TBS, wait for UL sdus to do final update - LOG_D(MAC,"[eNB %d] CC_id %d UE %d/%x : adjusting ul_total_buffer, old %d, TBS %d\n", module_idP,CC_id,UE_id,rnti,UE_template->ul_total_buffer,TBS); - if (UE_template->ul_total_buffer > TBS) - UE_template->ul_total_buffer -= TBS; - else - UE_template->ul_total_buffer = 0; - LOG_D(MAC,"ul_total_buffer, new %d\n", UE_template->ul_total_buffer); - // Cyclic shift for DM RS - cshift = 0;// values from 0 to 7 can be used for mapping the cyclic shift (36.211 , Table 5.5.2.1.1-1) - - if (frame_parms->frame_type == TDD) { - switch (frame_parms->N_RB_UL) { - case 6: - ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; - - ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->type = 0; - ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->hopping = 0; - ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->rballoc = rballoc; - ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->mcs = mcs; - ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->ndi = ndi; - ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->TPC = tpc; - ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->cshift = cshift; - ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->padding = 0; - ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->dai = UE_template->DAI_ul[sched_subframe]; - ((DCI0_1_5MHz_TDD_1_6_t *)ULSCH_dci)->cqi_req = cqi_req; - - add_ue_spec_dci(DCI_pdu, - ULSCH_dci, - rnti, - sizeof(DCI0_1_5MHz_TDD_1_6_t), - aggregation, - sizeof_DCI0_1_5MHz_TDD_1_6_t, - format0, - 0); - break; - - default: - case 25: - ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; - - ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->type = 0; - ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->hopping = 0; - ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->rballoc = rballoc; - ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->mcs = mcs; - ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->ndi = ndi; - ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->TPC = tpc; - ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->cshift = cshift; - ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->padding = 0; - ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->dai = UE_template->DAI_ul[sched_subframe]; - ((DCI0_5MHz_TDD_1_6_t *)ULSCH_dci)->cqi_req = cqi_req; - - add_ue_spec_dci(DCI_pdu, - ULSCH_dci, - rnti, - sizeof(DCI0_5MHz_TDD_1_6_t), - aggregation, - sizeof_DCI0_5MHz_TDD_1_6_t, - format0, - 0); - break; - - case 50: - ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; - - ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->type = 0; - ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->hopping = 0; - ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->rballoc = rballoc; - ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->mcs = mcs; - ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->ndi = ndi; - ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->TPC = tpc; - ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->cshift = cshift; - ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->padding = 0; - ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->dai = UE_template->DAI_ul[sched_subframe]; - ((DCI0_10MHz_TDD_1_6_t *)ULSCH_dci)->cqi_req = cqi_req; - - add_ue_spec_dci(DCI_pdu, - ULSCH_dci, - rnti, - sizeof(DCI0_10MHz_TDD_1_6_t), - aggregation, - sizeof_DCI0_10MHz_TDD_1_6_t, - format0, - 0); - break; - - case 100: - ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; - - ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->type = 0; - ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->hopping = 0; - ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->rballoc = rballoc; - ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->mcs = mcs; - ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->ndi = ndi; - ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->TPC = tpc; - ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->cshift = cshift; - ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->padding = 0; - ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->dai = UE_template->DAI_ul[sched_subframe]; - ((DCI0_20MHz_TDD_1_6_t *)ULSCH_dci)->cqi_req = cqi_req; - - add_ue_spec_dci(DCI_pdu, - ULSCH_dci, - rnti, - sizeof(DCI0_20MHz_TDD_1_6_t), - aggregation, - sizeof_DCI0_20MHz_TDD_1_6_t, - format0, - 0); - break; - } - } // TDD - else { //FDD - switch (frame_parms->N_RB_UL) { - case 25: - default: - - ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; - - ((DCI0_5MHz_FDD_t *)ULSCH_dci)->type = 0; - ((DCI0_5MHz_FDD_t *)ULSCH_dci)->hopping = 0; - ((DCI0_5MHz_FDD_t *)ULSCH_dci)->rballoc = rballoc; - ((DCI0_5MHz_FDD_t *)ULSCH_dci)->mcs = mcs; - ((DCI0_5MHz_FDD_t *)ULSCH_dci)->ndi = ndi; - ((DCI0_5MHz_FDD_t *)ULSCH_dci)->TPC = tpc; - ((DCI0_5MHz_FDD_t *)ULSCH_dci)->cshift = cshift; - ((DCI0_5MHz_FDD_t *)ULSCH_dci)->padding = 0; - ((DCI0_5MHz_FDD_t *)ULSCH_dci)->cqi_req = cqi_req; - - add_ue_spec_dci(DCI_pdu, - ULSCH_dci, - rnti, - sizeof(DCI0_5MHz_FDD_t), - aggregation, - sizeof_DCI0_5MHz_FDD_t, - format0, - 0); - break; - - case 6: - ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; - - ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->type = 0; - ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->hopping = 0; - ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->rballoc = rballoc; - ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->mcs = mcs; - ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->ndi = ndi; - ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->TPC = tpc; - ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->cshift = cshift; - ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->padding = 0; - ((DCI0_1_5MHz_FDD_t *)ULSCH_dci)->cqi_req = cqi_req; - - add_ue_spec_dci(DCI_pdu, - ULSCH_dci, - rnti, - sizeof(DCI0_1_5MHz_FDD_t), - aggregation, - sizeof_DCI0_1_5MHz_FDD_t, - format0, - 0); - break; - - case 50: - ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; - - ((DCI0_10MHz_FDD_t *)ULSCH_dci)->type = 0; - ((DCI0_10MHz_FDD_t *)ULSCH_dci)->hopping = 0; - ((DCI0_10MHz_FDD_t *)ULSCH_dci)->rballoc = rballoc; - ((DCI0_10MHz_FDD_t *)ULSCH_dci)->mcs = mcs; - ((DCI0_10MHz_FDD_t *)ULSCH_dci)->ndi = ndi; - ((DCI0_10MHz_FDD_t *)ULSCH_dci)->TPC = tpc; - ((DCI0_10MHz_FDD_t *)ULSCH_dci)->padding = 0; - ((DCI0_10MHz_FDD_t *)ULSCH_dci)->cshift = cshift; - ((DCI0_10MHz_FDD_t *)ULSCH_dci)->cqi_req = cqi_req; - - add_ue_spec_dci(DCI_pdu, - ULSCH_dci, - rnti, - sizeof(DCI0_10MHz_FDD_t), - aggregation, - sizeof_DCI0_10MHz_FDD_t, - format0, - 0); - break; - - case 100: - ULSCH_dci = UE_template->ULSCH_DCI[harq_pid]; - - ((DCI0_20MHz_FDD_t *)ULSCH_dci)->type = 0; - ((DCI0_20MHz_FDD_t *)ULSCH_dci)->hopping = 0; - ((DCI0_20MHz_FDD_t *)ULSCH_dci)->rballoc = rballoc; - ((DCI0_20MHz_FDD_t *)ULSCH_dci)->mcs = mcs; - ((DCI0_20MHz_FDD_t *)ULSCH_dci)->ndi = ndi; - ((DCI0_20MHz_FDD_t *)ULSCH_dci)->TPC = tpc; - ((DCI0_20MHz_FDD_t *)ULSCH_dci)->padding = 0; - ((DCI0_20MHz_FDD_t *)ULSCH_dci)->cshift = cshift; - ((DCI0_20MHz_FDD_t *)ULSCH_dci)->cqi_req = cqi_req; - - add_ue_spec_dci(DCI_pdu, - ULSCH_dci, - rnti, - sizeof(DCI0_20MHz_FDD_t), - aggregation, - sizeof_DCI0_20MHz_FDD_t, - format0, - 0); - break; - - } - } - - - add_ue_ulsch_info(module_idP, - CC_id, - UE_id, - subframeP, - S_UL_SCHEDULED); - - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d, subframeP %d: Generated ULSCH DCI for next UE_id %d, format 0\n", module_idP,CC_id,frameP,subframeP,UE_id); -#ifdef DEBUG - dump_dci(frame_parms, &DCI_pdu->dci_alloc[DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci-1]); -#endif - - } - else { - T(T_ENB_MAC_UE_UL_SCHEDULE_RETRANSMISSION, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), - T_INT(subframeP), T_INT(harq_pid), T_INT(mcs), T_INT(first_rb[CC_id]), T_INT(rb_table[rb_table_index]), - T_INT(round)); - - LOG_D(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled (PHICH) UE %d (mcs %d, first rb %d, nb_rb %d, rb_table_index %d, TBS %d, harq_pid %d,round %d)\n", - module_idP,harq_pid,rnti,CC_id,frameP,subframeP,UE_id,mcs, - first_rb[CC_id],rb_table[rb_table_index], - rb_table_index,TBS,harq_pid,round); - }/* - else if (round > 0) { //we schedule a retransmission - - ndi = UE_template->oldNDI_UL[harq_pid]; - - if ((round&3)==0) { - mcs = openair_daq_vars.target_ue_ul_mcs; - } else { - mcs = rvidx_tab[round&3] + 28; //not correct for round==4! - - } - - LOG_I(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE retransmission (mcs %d, first rb %d, nb_rb %d, harq_pid %d, round %d)\n", - module_idP,UE_id,rnti,CC_id,frameP,subframeP,mcs, - first_rb[CC_id],UE_template->nb_rb_ul[harq_pid], - harq_pid, round); - - rballoc = mac_xface->computeRIV(frame_parms->N_RB_UL, - first_rb[CC_id], - UE_template->nb_rb_ul[harq_pid]); - first_rb[CC_id]+=UE_template->nb_rb_ul[harq_pid]; // increment for next UE allocation - - UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission_rx+=1; - UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx_rx=UE_template->nb_rb_ul[harq_pid]; - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=UE_template->nb_rb_ul[harq_pid]; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=mcs; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; - } - */ - - } // UE_is_to_be_scheduled - } // UE is in PUSCH - } // loop over UE_id - } // loop of CC_id -} - diff --git a/openair2/LAYER2/MAC/flexran_dci_conversions.h b/openair2/LAYER2/MAC/flexran_dci_conversions.h deleted file mode 100644 index 5c18b43104..0000000000 --- a/openair2/LAYER2/MAC/flexran_dci_conversions.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file flexran_dci_conversions.h - * \brief Conversion helpers from flexran messages to OAI formats DCI - * \author Xenofon Foukas - * \date 2016 - * \version 0.1 - */ - -#ifndef LAYER2_MAC_FLEXRAN_DCI_CONVERISIONS_H__ -#define LAYER2_MAC_DCI_FLEXRAN_CONVERISIONS_H__ - -#define FILL_DCI_FDD_1(TYPE, DCI, FLEXRAN_DCI) \ - ((TYPE*)DCI)->harq_pid = FLEXRAN_DCI->harq_process; \ - ((TYPE*)DCI)->rv = FLEXRAN_DCI->rv[0]; \ - ((TYPE*)DCI)->rballoc = FLEXRAN_DCI->rb_bitmap; \ - ((TYPE*)DCI)->rah = FLEXRAN_DCI->res_alloc; \ - ((TYPE*)DCI)->mcs = FLEXRAN_DCI->mcs[0]; \ - ((TYPE*)DCI)->TPC = FLEXRAN_DCI->tpc; \ - ((TYPE*)DCI)->ndi = FLEXRAN_DCI->ndi[0]; - -#define FILL_DCI_TDD_1(TYPE, DCI, FLEXRAN_DCI) \ - ((TYPE*)DCI)->harq_pid = FLEXRAN_DCI->harq_process; \ - ((TYPE*)DCI)->rv = FLEXRAN_DCI->rv[0]; \ - ((TYPE*)DCI)->dai = FLEXRAN_DCI->dai; \ - ((TYPE*)DCI)->rballoc = FLEXRAN_DCI->rb_bitmap; \ - ((TYPE*)DCI)->rah = FLEXRAN_DCI->res_alloc; \ - ((TYPE*)DCI)->mcs = FLEXRAN_DCI->mcs[0]; \ - ((TYPE*)DCI)->TPC = FLEXRAN_DCI->tpc; \ - ((TYPE*)DCI)->ndi = FLEXRAN_DCI->ndi[0]; - -#endif From 024904db903a4246657056aeef07130c492e5829 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 15 Jan 2018 18:32:35 +0100 Subject: [PATCH 176/284] repair enb_app.c after merge, delete unnecessary code --- openair2/ENB_APP/enb_app.c | 155 ++----------------------------------- 1 file changed, 6 insertions(+), 149 deletions(-) diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index 3b3c8c24c7..f1a5437e98 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -50,10 +50,6 @@ # include "gtpv1u_eNB_task.h" # endif -#if defined(FLEXRAN_AGENT_SB_IF) -# include "targets/RT/USER/lte-softmodem.h" -#endif - extern unsigned char NB_eNB_INST; #endif @@ -102,102 +98,6 @@ static void configure_rrc(uint32_t enb_id) if (RC.rrc[enb_id]) { RCconfig_RRC(msg_p,enb_id, RC.rrc[enb_id]); - /* - RRC_CONFIGURATION_REQ (msg_p).cell_identity = enb_properties->properties[enb_id]->eNB_id; - RRC_CONFIGURATION_REQ (msg_p).tac = enb_properties->properties[enb_id]->tac; - RRC_CONFIGURATION_REQ (msg_p).mcc = enb_properties->properties[enb_id]->mcc; - RRC_CONFIGURATION_REQ (msg_p).mnc = enb_properties->properties[enb_id]->mnc; - RRC_CONFIGURATION_REQ (msg_p).mnc_digit_length = enb_properties->properties[enb_id]->mnc_digit_length; - - for (CC_id=0; CC_idproperties[enb_id]->frame_type[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).tdd_config[CC_id] = enb_properties->properties[enb_id]->tdd_config[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).tdd_config_s[CC_id] = enb_properties->properties[enb_id]->tdd_config_s[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).eutra_band[CC_id] = enb_properties->properties[enb_id]->eutra_band[CC_id]; - - // RACH-Config - RRC_CONFIGURATION_REQ (msg_p).rach_numberOfRA_Preambles[CC_id] = enb_properties->properties[enb_id]->rach_numberOfRA_Preambles[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).rach_preamblesGroupAConfig[CC_id] = enb_properties->properties[enb_id]->rach_preamblesGroupAConfig[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).rach_sizeOfRA_PreamblesGroupA[CC_id] = enb_properties->properties[enb_id]->rach_sizeOfRA_PreamblesGroupA[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).rach_messageSizeGroupA[CC_id] = enb_properties->properties[enb_id]->rach_messageSizeGroupA[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).rach_messagePowerOffsetGroupB[CC_id] = enb_properties->properties[enb_id]->rach_messagePowerOffsetGroupB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).rach_powerRampingStep[CC_id] = enb_properties->properties[enb_id]->rach_powerRampingStep[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).rach_preambleInitialReceivedTargetPower[CC_id] = enb_properties->properties[enb_id]->rach_preambleInitialReceivedTargetPower[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).rach_preambleTransMax[CC_id] = enb_properties->properties[enb_id]->rach_preambleTransMax[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).rach_raResponseWindowSize[CC_id] = enb_properties->properties[enb_id]->rach_raResponseWindowSize[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).rach_macContentionResolutionTimer[CC_id] = enb_properties->properties[enb_id]->rach_macContentionResolutionTimer[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).rach_maxHARQ_Msg3Tx[CC_id] = enb_properties->properties[enb_id]->rach_maxHARQ_Msg3Tx[CC_id]; - - // BCCH-Config - RRC_CONFIGURATION_REQ (msg_p).bcch_modificationPeriodCoeff[CC_id] = enb_properties->properties[enb_id]->bcch_modificationPeriodCoeff[CC_id]; - - // PCCH-Config - RRC_CONFIGURATION_REQ (msg_p).pcch_defaultPagingCycle[CC_id] = enb_properties->properties[enb_id]->pcch_defaultPagingCycle[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pcch_nB[CC_id] = enb_properties->properties[enb_id]->pcch_nB[CC_id]; - - // PRACH-Config - RRC_CONFIGURATION_REQ (msg_p).prach_root[CC_id] = enb_properties->properties[enb_id]->prach_root[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).prach_config_index[CC_id] = enb_properties->properties[enb_id]->prach_config_index[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).prach_high_speed[CC_id] = enb_properties->properties[enb_id]->prach_high_speed[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).prach_zero_correlation[CC_id] = enb_properties->properties[enb_id]->prach_zero_correlation[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).prach_freq_offset[CC_id] = enb_properties->properties[enb_id]->prach_freq_offset[CC_id]; - - // PDSCH-Config - RRC_CONFIGURATION_REQ (msg_p).pdsch_referenceSignalPower[CC_id] = enb_properties->properties[enb_id]->pdsch_referenceSignalPower[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pdsch_p_b[CC_id] = enb_properties->properties[enb_id]->pdsch_p_b[CC_id]; - - // PUSCH-Config - RRC_CONFIGURATION_REQ (msg_p).pusch_n_SB[CC_id] = enb_properties->properties[enb_id]->pusch_n_SB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pusch_hoppingMode[CC_id] = enb_properties->properties[enb_id]->pusch_hoppingMode[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pusch_hoppingOffset[CC_id] = enb_properties->properties[enb_id]->pusch_hoppingOffset[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pusch_enable64QAM[CC_id] = enb_properties->properties[enb_id]->pusch_enable64QAM[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pusch_groupHoppingEnabled[CC_id] = enb_properties->properties[enb_id]->pusch_groupHoppingEnabled[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pusch_groupAssignment[CC_id] = enb_properties->properties[enb_id]->pusch_groupAssignment[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pusch_sequenceHoppingEnabled[CC_id] = enb_properties->properties[enb_id]->pusch_sequenceHoppingEnabled[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pusch_nDMRS1[CC_id] = enb_properties->properties[enb_id]->pusch_nDMRS1[CC_id]; - - // PUCCH-Config - - RRC_CONFIGURATION_REQ (msg_p).pucch_delta_shift[CC_id] = enb_properties->properties[enb_id]->pucch_delta_shift[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pucch_nRB_CQI[CC_id] = enb_properties->properties[enb_id]->pucch_nRB_CQI[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pucch_nCS_AN[CC_id] = enb_properties->properties[enb_id]->pucch_nCS_AN[CC_id]; -#if !defined(Rel10) && !defined(Rel14) - RRC_CONFIGURATION_REQ (msg_p).pucch_n1_AN[CC_id] = enb_properties->properties[enb_id]->pucch_n1_AN[CC_id]; -#endif - - // SRS Config - RRC_CONFIGURATION_REQ (msg_p).srs_enable[CC_id] = enb_properties->properties[enb_id]->srs_enable[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).srs_BandwidthConfig[CC_id] = enb_properties->properties[enb_id]->srs_BandwidthConfig[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).srs_SubframeConfig[CC_id] = enb_properties->properties[enb_id]->srs_SubframeConfig[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).srs_ackNackST[CC_id] = enb_properties->properties[enb_id]->srs_ackNackST[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).srs_MaxUpPts[CC_id] = enb_properties->properties[enb_id]->srs_MaxUpPts[CC_id]; - - // uplinkPowerControlCommon - - RRC_CONFIGURATION_REQ (msg_p).pusch_p0_Nominal[CC_id] = enb_properties->properties[enb_id]->pusch_p0_Nominal[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pucch_p0_Nominal[CC_id] = enb_properties->properties[enb_id]->pucch_p0_Nominal[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pusch_alpha[CC_id] = enb_properties->properties[enb_id]->pusch_alpha[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pucch_deltaF_Format1[CC_id] = enb_properties->properties[enb_id]->pucch_deltaF_Format1[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pucch_deltaF_Format1b[CC_id] = enb_properties->properties[enb_id]->pucch_deltaF_Format1b[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pucch_deltaF_Format2[CC_id] = enb_properties->properties[enb_id]->pucch_deltaF_Format2[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pucch_deltaF_Format2a[CC_id] = enb_properties->properties[enb_id]->pucch_deltaF_Format2a[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).pucch_deltaF_Format2b[CC_id] = enb_properties->properties[enb_id]->pucch_deltaF_Format2b[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).msg3_delta_Preamble[CC_id] = enb_properties->properties[enb_id]->msg3_delta_Preamble[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).ul_CyclicPrefixLength[CC_id] = enb_properties->properties[enb_id]->ul_CyclicPrefixLength[CC_id]; - - // UE Timers and Constants - - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t300[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_t300[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t301[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_t301[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t310[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_t310[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n310[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_n310[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t311[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_t311[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n311[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_n311[CC_id]; - - RRC_CONFIGURATION_REQ (msg_p).ue_TransmissionMode[CC_id] = enb_properties->properties[enb_id]->ue_TransmissionMode[CC_id]; - - } - */ LOG_I(ENB_APP,"Sending configuration message to RRC task\n"); itti_send_msg_to_task (TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); @@ -206,15 +106,6 @@ static void configure_rrc(uint32_t enb_id) else AssertFatal(0,"RRC context for eNB %d not allocated\n",enb_id); } -void enb_app_start_phy_rrc(uint32_t enb_id_start, uint32_t enb_id_end) -{ - Enb_properties_array_t *enb_properties_p = enb_config_get(); - for (uint32_t enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { - configure_phy(enb_id, enb_properties_p); - configure_rrc(enb_id, enb_properties_p); - } -} - /*------------------------------------------------------------------------------*/ # if defined(ENABLE_USE_MME) static uint32_t eNB_app_register(uint32_t enb_id_start, uint32_t enb_id_end)//, const Enb_properties_array_t *enb_properties) @@ -240,44 +131,6 @@ static uint32_t eNB_app_register(uint32_t enb_id_start, uint32_t enb_id_end)//, s1ap_register_eNB = &S1AP_REGISTER_ENB_REQ(msg_p); LOG_I(ENB_APP,"default drx %d\n",s1ap_register_eNB->default_drx); - /* - - s1ap_register_eNB->eNB_id = enb_properties->properties[enb_id]->eNB_id; - s1ap_register_eNB->cell_type = enb_properties->properties[enb_id]->cell_type; - s1ap_register_eNB->eNB_name = enb_properties->properties[enb_id]->eNB_name; - s1ap_register_eNB->tac = enb_properties->properties[enb_id]->tac; - s1ap_register_eNB->mcc = enb_properties->properties[enb_id]->mcc; - s1ap_register_eNB->mnc = enb_properties->properties[enb_id]->mnc; - s1ap_register_eNB->mnc_digit_length = enb_properties->properties[enb_id]->mnc_digit_length; - s1ap_register_eNB->default_drx = enb_properties->properties[enb_id]->pcch_defaultPagingCycle[0]; - - s1ap_register_eNB->nb_mme = enb_properties->properties[enb_id]->nb_mme; - - AssertFatal (s1ap_register_eNB->nb_mme <= S1AP_MAX_NB_MME_IP_ADDRESS, "Too many MME for eNB %d (%d/%d)!", enb_id, s1ap_register_eNB->nb_mme, - S1AP_MAX_NB_MME_IP_ADDRESS); - - for (mme_id = 0; mme_id < s1ap_register_eNB->nb_mme; mme_id++) { - s1ap_register_eNB->mme_ip_address[mme_id].ipv4 = enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv4; - s1ap_register_eNB->mme_ip_address[mme_id].ipv6 = enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv6; - strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv4_address, - enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv4_address, - sizeof(s1ap_register_eNB->mme_ip_address[0].ipv4_address)); - strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv6_address, - enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv6_address, - sizeof(s1ap_register_eNB->mme_ip_address[0].ipv6_address)); - } - - s1ap_register_eNB->sctp_in_streams = enb_properties->properties[enb_id]->sctp_in_streams; - s1ap_register_eNB->sctp_out_streams = enb_properties->properties[enb_id]->sctp_out_streams; - - - s1ap_register_eNB->enb_ip_address.ipv6 = 0; - s1ap_register_eNB->enb_ip_address.ipv4 = 1; - addr.s_addr = enb_properties->properties[enb_id]->enb_ipv4_address_for_S1_MME; - str = inet_ntoa(addr); - strcpy(s1ap_register_eNB->enb_ip_address.ipv4_address, str); - - */ LOG_I(ENB_APP,"[eNB %d] eNB_app_register for instance %d\n", enb_id, ENB_MODULE_ID_TO_INSTANCE(enb_id)); itti_send_msg_to_task (TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); @@ -297,13 +150,13 @@ void *eNB_app_task(void *args_p) #if defined(ENABLE_ITTI) uint32_t enb_nb = RC.nb_inst; uint32_t enb_id_start = 0; - uint32_t enb_i; uint32_t enb_id_end = enb_id_start + enb_nb; # if defined(ENABLE_USE_MME) uint32_t register_enb_pending; uint32_t registered_enb; long enb_register_retry_timer_id; # endif + uint32_t enb_id; MessageDef *msg_p = NULL; const char *msg_name = NULL; instance_t instance; @@ -340,7 +193,11 @@ void *eNB_app_task(void *args_p) RC.rrc = (eNB_RRC_INST **)malloc(RC.nb_inst*sizeof(eNB_RRC_INST *)); - enb_app_start_phy_rrc(enb_id_start, enb_id_end); + for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { + RC.rrc[enb_id] = (eNB_RRC_INST*)malloc(sizeof(eNB_RRC_INST)); + memset((void *)RC.rrc[enb_id],0,sizeof(eNB_RRC_INST)); + configure_rrc(enb_id); + } # if defined(ENABLE_USE_MME) /* Try to register each eNB */ From 7dfac059b0757f2e320d7adbc1779d44b29637d3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 15 Jan 2018 18:34:58 +0100 Subject: [PATCH 177/284] Review Navid: UL Scheduler: make slice aware --- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 3 +++ openair2/LAYER2/MAC/pre_processor.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index b5256820bb..119f5b8074 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -1233,6 +1233,9 @@ schedule_ulsch_rnti(module_id_t module_idP, for (UE_id = UE_list->head_ul; UE_id >= 0; UE_id = UE_list->next_ul[UE_id]) { + if (flexran_slice_member(UE_id, slice_id) == 0) + continue; + // don't schedule if Msg4 is not received yet if (UE_list->UE_template[UE_PCCID(module_idP, UE_id)][UE_id]. configured == FALSE) { diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index a0cc0dd412..af5b6f660b 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -614,6 +614,9 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, if (UE_list->active[i] != TRUE) continue; + if (!flexran_slice_member(UE_id, slice_id)) + continue; + UE_id = i; // Initialize scheduling information for all active UEs @@ -820,6 +823,8 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, continue; if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) continue; + if (flexran_slice_member(i, slice_id) == 0) + continue; transmission_mode = get_tmode(Mod_id, CC_id, UE_id); // mac_xface->get_ue_active_harq_pid(Mod_id,CC_id,rnti,frameP,subframeP,&harq_pid,&round,0); From a03877e7f710cf1c71496e36db5993aa50b8df44 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 15 Jan 2018 18:36:29 +0100 Subject: [PATCH 178/284] delete unnecessary code --- openair2/LAYER2/MAC/eNB_scheduler_primitives.c | 17 ----------------- openair2/LAYER2/MAC/proto.h | 2 -- 2 files changed, 19 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 4a316cf92c..fe885d38cc 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -1980,11 +1980,6 @@ uint8_t find_active_UEs(module_id_t module_idP,int CC_id){ } */ -int UE_BSR (uint8_t mod_id, uint8_t ue_id, uint8_t lcid) { - - if (eNB_mac_inst == NULL) return 0; - return eNB_mac_inst[mod_id].UE_list.UE_template[UE_PCCID(mod_id,ue_id)][ue_id].bsr_info[lcid]; -} // get aggregation (L) form phy for a give UE unsigned char @@ -2108,12 +2103,6 @@ int add_new_ue(module_id_t mod_idP, int cc_idP, rnti_t rntiP, int harq_pidP return (-1); } -int CC_id_rnti_downlink (uint8_t mod_id, int CC_index, uint16_t ue_rnti) { - - return eNB_mac_inst[mod_id].UE_list.ordered_CCids[CC_index][ue_rnti]; -} - - //------------------------------------------------------------------------------ int rrc_mac_remove_ue(module_id_t mod_idP, rnti_t rntiP) //------------------------------------------------------------------------------ @@ -4480,14 +4469,8 @@ uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, int total_rbs) return (uint16_t) floor(rb_percentage * total_rbs); } -int flexran_slice_maxmcs(int slice_id) -{ - return slice_maxmcs[slice_id]; -} - int flexran_slice_member(int UE_id, int slice_id) { - if ((slice_id < 0) || (slice_id > n_active_slices)) LOG_W(MAC, "out of range slice id %d\n", slice_id); diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index a83aabef27..f237bbf299 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -1168,7 +1168,5 @@ uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, int total_rbs); int flexran_slice_member(int UE_id, int slice_id); -int flexran_slice_maxmcs(int slice_id;) - #endif /** @}*/ From 9b4d3bbae75f90f5bd56c3952696b29fb38df216 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 15 Jan 2018 18:38:05 +0100 Subject: [PATCH 179/284] move scheduler function pointer typedef to proto.h --- openair2/LAYER2/MAC/proto.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index f237bbf299..00ea994ddf 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -35,6 +35,25 @@ * @{ */ +/** + * slice specific scheduler + */ +/* TODO Navid: Protocol__FlexranMessage -> unknown when compiling without + * FlexRAN, what to do with it? */ +typedef void (*slice_scheduler_dl)(module_id_t mod_id, + int slice_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag/*, + Protocol__FlexranMessage **dl_info*/); + +typedef void (*slice_scheduler_ul)(module_id_t mod_id, + frame_t frame, + unsigned char cooperation_flag, + uint32_t subframe, + unsigned char sched_subframe/*, + Protocol__FlexranMessage **ul_info*/); + /** \fn void schedule_mib(module_id_t module_idP,frame_t frameP,sub_frame_t subframe); \brief MIB scheduling for PBCH. This function requests the MIB from RRC and provides it to L1. @param Mod_id Instance ID of eNB From dfece3ff58f9bee908e1ace4e38babb7c3a8d6ce Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 16 Jan 2018 17:23:26 +0100 Subject: [PATCH 180/284] correct scheduler typedefs --- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 4 ++-- openair2/LAYER2/MAC/proto.h | 24 ++++++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 119f5b8074..7076827896 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -1174,8 +1174,8 @@ schedule_ulsch(module_id_t module_idP, frame_t frameP, } // Run each enabled slice-specific schedulers one by one - slice_sched_ul[i](module_idP, i,frameP, subframeP, sched_subframe, - first_rb); + /* TODO Navid What is the right call for this message? */ + slice_sched_ul[i](module_idP, i, frameP, subframeP, sched_subframe, first_rb); } diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 00ea994ddf..842e1d7080 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -39,20 +39,22 @@ * slice specific scheduler */ /* TODO Navid: Protocol__FlexranMessage -> unknown when compiling without - * FlexRAN, what to do with it? */ + * FlexRAN, what to do with it? Matches schedule_ue_spec now */ typedef void (*slice_scheduler_dl)(module_id_t mod_id, - int slice_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag/*, - Protocol__FlexranMessage **dl_info*/); + slice_id_t slice_id, + frame_t frame, + sub_frame_t subframe, + int *mbsfn_flag + /* Protocol__FlexranMessage **dl_info*/); +/* TODO Navid: the same as above, matches schedule_ulsch_rnti now */ typedef void (*slice_scheduler_ul)(module_id_t mod_id, - frame_t frame, - unsigned char cooperation_flag, - uint32_t subframe, - unsigned char sched_subframe/*, - Protocol__FlexranMessage **ul_info*/); + slice_id_t slice_id, + frame_t frame, + sub_frame_t subframe, + unsigned char sched_subframe, + uint16_t *first_rb + /* Protocol__FlexranMessage **ul_info*/); /** \fn void schedule_mib(module_id_t module_idP,frame_t frameP,sub_frame_t subframe); \brief MIB scheduling for PBCH. This function requests the MIB from RRC and provides it to L1. From 6a6729bdaca3016286b9239ec9baaae1b67b1875 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 15 Jan 2018 18:38:29 +0100 Subject: [PATCH 181/284] fix various compilaton errors due to merge --- .../ENB_APP/flexran_agent_common_internal.c | 8 +- openair2/LAYER2/MAC/defs.h | 1 + openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 26 ++-- .../LAYER2/MAC/eNB_scheduler_primitives.c | 8 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 28 ++-- openair2/LAYER2/MAC/pre_processor.c | 26 ++-- openair2/LAYER2/MAC/proto.h | 4 +- openair2/RRC/LITE/rrc_eNB.c | 2 +- targets/RT/USER/lte-enb.c | 23 +-- targets/RT/USER/lte-softmodem.c | 137 ++---------------- targets/RT/USER/lte-softmodem.h | 2 +- 11 files changed, 72 insertions(+), 193 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c index de937db0c6..e3fac4594b 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.c +++ b/openair2/ENB_APP/flexran_agent_common_internal.c @@ -37,6 +37,7 @@ #include "assertions.h" #include "enb_app.h" +#if 0 void handle_reconfiguration(mid_t mod_id) { /* NOTE: this function might be extended by using stop_modem() @@ -69,6 +70,7 @@ void handle_reconfiguration(mid_t mod_id) LOG_I(ENB_APP, "lte-softmodem restart succeeded in %d ms\n", diff_ms); } } +#endif int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy_length) { @@ -109,7 +111,8 @@ int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy if (parse_enb_id(mod_id, &parser) == -1) { goto error; } else { // succeful parse and setting - handle_reconfiguration(mod_id); + /* TODO implement */ + //handle_reconfiguration(mod_id); } } else if (strcmp((char *) event.data.scalar.value, "mac") == 0) { LOG_D(ENB_APP, "This is intended for the mac system\n"); @@ -293,8 +296,7 @@ int parse_enb_config_parameters(mid_t mod_id, yaml_parser_t *parser) { yaml_event_delete(&event); } - /* reflect in RAN API */ - flexran_set_enb_vars(mod_id, RAN_LTE_OAI); + /* TODO: reflect in RAN API */ return 0; diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index e27ef3648a..36538a3364 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -800,6 +800,7 @@ typedef struct { ///Contention resolution timer used during random access uint8_t mac_ContentionResolutionTimer; + /* TODO Navid MAX_NUM_LCID -> MAX_NUM_CCs? */ uint16_t max_rbs_allowed_slice[MAX_NUM_LCID][MAX_NUM_SLICES]; uint8_t max_mcs[MAX_NUM_LCID]; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index a0da4f4961..ae4afc8b42 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -64,7 +64,6 @@ #include "flexran.pb-c.h" #endif #include -#endif #include "T.h" @@ -449,7 +448,7 @@ set_ul_DAI(int module_idP, int UE_idP, int CC_idP, int frameP, //------------------------------------------------------------------------------ void -schedule_dlsch(module_id_ module_idP, +schedule_dlsch(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP, int *mbsfn_flag) //------------------------------------------------------------------------------{ { @@ -466,7 +465,7 @@ schedule_dlsch(module_id_ module_idP, for (i = 0; i < n_active_slices; i++) { if (slice_percentage[i] < 0 ){ LOG_W(MAC, "[eNB %d] frame %d subframe %d:invalid slice %d percentage %f. resetting to zero", - mod_id, frame, subframe, i, slice_percentage[i]); + module_idP, frameP, subframeP, i, slice_percentage[i]); slice_percentage[i]=0; } total_slice_percentage+=slice_percentage[i]; @@ -488,7 +487,7 @@ schedule_dlsch(module_id_ module_idP, if (n_active_slices_current != n_active_slices ){ if ((n_active_slices > 0) && (n_active_slices <= MAX_NUM_SLICES)) { LOG_N(MAC,"[eNB %d]frame %d subframe %d: number of active DL slices has changed: %d-->%d\n", - mod_id, frame, subframe, n_active_slices_current, n_active_slices); + module_idP, frameP, subframeP, n_active_slices_current, n_active_slices); n_active_slices_current = n_active_slices; @@ -501,7 +500,7 @@ schedule_dlsch(module_id_ module_idP, // check if the slice rb share has changed, and log the console if (slice_percentage_current[i] != slice_percentage[i]){ // new slice percentage LOG_N(MAC,"[eNB %d][SLICE %d][DL] frame %d subframe %d: total percentage %f-->%f, slice RB percentage has changed: %f-->%f\n", - mod_id, i, frame, subframe, total_slice_percentage_current, total_slice_percentage, slice_percentage_current[i], slice_percentage[i]); + module_idP, i, frameP, subframeP, total_slice_percentage_current, total_slice_percentage, slice_percentage_current[i], slice_percentage[i]); total_slice_percentage_current= total_slice_percentage; slice_percentage_current[i] = slice_percentage[i]; @@ -511,10 +510,10 @@ schedule_dlsch(module_id_ module_idP, if (slice_maxmcs_current[i] != slice_maxmcs[i]){ if ((slice_maxmcs[i] >= 0) && (slice_maxmcs[i] < 29)){ LOG_N(MAC,"[eNB %d][SLICE %d][DL] frame %d subframe %d: slice MAX MCS has changed: %d-->%d\n", - mod_id, i, frame, subframe, slice_maxmcs_current[i], slice_maxmcs[i]); + module_idP, i, frameP, subframeP, slice_maxmcs_current[i], slice_maxmcs[i]); slice_maxmcs_current[i] = slice_maxmcs[i]; } else { - LOG_W(MAC,"[eNB %d][SLICE %d][DL] invalid slice max mcs %d, revert the previous value %d\n",mod_id, i, slice_maxmcs[i],slice_maxmcs_current[i]); + LOG_W(MAC,"[eNB %d][SLICE %d][DL] invalid slice max mcs %d, revert the previous value %d\n",module_idP, i, slice_maxmcs[i],slice_maxmcs_current[i]); slice_maxmcs[i]= slice_maxmcs_current[i]; } } @@ -522,7 +521,7 @@ schedule_dlsch(module_id_ module_idP, // check if a new scheduler, and log the console if (update_dl_scheduler_current[i] != update_dl_scheduler[i]){ LOG_N(MAC,"[eNB %d][SLICE %d][DL] frame %d subframe %d: DL scheduler for this slice is updated: %s \n", - mod_id, i, frame, subframe, dl_scheduler_type[i]); + module_idP, i, frameP, subframeP, dl_scheduler_type[i]); update_dl_scheduler_current[i] = update_dl_scheduler[i]; } @@ -531,16 +530,14 @@ schedule_dlsch(module_id_ module_idP, if (n_active_slices == n_active_slices_current){ LOG_W(MAC,"[eNB %d][SLICE %d][DL] invalid total RB share (%f->%f), reduce proportionally the RB share by 0.1\n", - mod_id,i, - total_slice_percentage_current, total_slice_percentage); + module_idP, i, total_slice_percentage_current, total_slice_percentage); if (slice_percentage[i] >= avg_slice_percentage){ slice_percentage[i]-=0.1; total_slice_percentage-=0.1; } } else { LOG_W(MAC,"[eNB %d][SLICE %d][DL] invalid total RB share (%f->%f), revert the number of slice to its previous value (%d->%d)\n", - mod_id,i, - total_slice_percentage_current, total_slice_percentage, + module_idP, i, total_slice_percentage_current, total_slice_percentage, n_active_slices, n_active_slices_current ); n_active_slices = n_active_slices_current; slice_percentage[i] = slice_percentage_current[i]; @@ -548,7 +545,8 @@ schedule_dlsch(module_id_ module_idP, } // Run each enabled slice-specific schedulers one by one - slice_sched_dl[i](mod_id, i, frame, subframe, mbsfn_flag,dl_info); + /* TODO Navid took out the dl_info additional information */ + slice_sched_dl[i](module_idP, i, frameP, subframeP, mbsfn_flag/*, dl_info*/); } } @@ -806,7 +804,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, */ eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]]; - eNB_UE_stats->dlsch_mcs1 =cmin(eNB_UE_stats->dlsch_mcs1, flexran_slice_maxmcs(slice_idP));//openair_daq_vars.target_ue_dl_mcs); + eNB_UE_stats->dlsch_mcs1 =cmin(eNB_UE_stats->dlsch_mcs1, slice_maxmcs[slice_idP]);//openair_daq_vars.target_ue_dl_mcs); // store stats diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index fe885d38cc..15f67871b1 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -61,6 +61,8 @@ #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_eNB_SCHEDULER 1 +extern int n_active_slices; + int choose(int n, int k) { int res = 1; @@ -1927,7 +1929,7 @@ int UE_num_active_CC(UE_list_t * listP, int ue_idP) int UE_PCCID(module_id_t mod_idP, int ue_idP) //------------------------------------------------------------------------------ { - if (RC.mac[mod_idP] == NULL) return 0; + if (!RC.mac || !RC.mac[mod_idP]) return 0; return (RC.mac[mod_idP]->UE_list.pCC_id[ue_idP]); } @@ -1935,7 +1937,7 @@ int UE_PCCID(module_id_t mod_idP, int ue_idP) rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP) //------------------------------------------------------------------------------ { - if (RC.mac[mod_idP] == NULL) return 0; + if (!RC.mac || !RC.mac[mod_idP]) return 0; rnti_t rnti = RC.mac[mod_idP]-> UE_list.UE_template[UE_PCCID(mod_idP, ue_idP)][ue_idP].rnti; @@ -1953,7 +1955,7 @@ rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP) boolean_t is_UE_active(module_id_t mod_idP, int ue_idP) //------------------------------------------------------------------------------ { - if (RC.mac[mod_idP] == NULL) return 0; + if (!RC.mac || !RC.mac[mod_idP]) return 0; return (RC.mac[mod_idP]->UE_list.active[ue_idP]); } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 7076827896..f1bfac7949 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -63,8 +63,8 @@ #include "header.pb-c.h" #include "flexran.pb-c.h" #include "flexran_agent_mac.h" -#include #endif +#include #include "T.h" @@ -943,13 +943,13 @@ unsigned char *parse_ulsch_header(unsigned char *mac_header, * (done below in schedule_ulsch). */ void -set_msg3_subframe(module_id_t Mod_id, +set_msg3_subframe(module_id_t mod_id, int CC_id, int frame, int subframe, int rnti, int Msg3_frame, int Msg3_subframe) { - eNB_MAC_INST *mac = RC.mac[Mod_id]; + eNB_MAC_INST *mac = RC.mac[mod_id]; int i; for (i = 0; i < NB_RA_PROC_MAX; i++) { if (mac->common_channels[CC_id].ra[i].state != IDLE && @@ -1086,7 +1086,7 @@ schedule_ulsch(module_id_t module_idP, frame_t frameP, for (i = 0; i < n_active_slices_uplink; i++) { if (slice_percentage_uplink[i] < 0 ){ LOG_W(MAC, "[eNB %d] frame %d subframe %d:invalid slice %d percentage %f. resetting to zero", - mod_id, frame, subframe, i, slice_percentage_uplink[i]); + module_idP, frameP, subframeP, i, slice_percentage_uplink[i]); slice_percentage_uplink[i]=0; } total_slice_percentage_uplink+=slice_percentage_uplink[i]; @@ -1112,7 +1112,7 @@ schedule_ulsch(module_id_t module_idP, frame_t frameP, if (n_active_slices_current_uplink != n_active_slices_uplink ){ if ((n_active_slices_uplink > 0) && (n_active_slices_uplink <= MAX_NUM_SLICES)) { LOG_N(MAC,"[eNB %d]frame %d subframe %d: number of active UL slices has changed: %d-->%d\n", - mod_id, frame, subframe, n_active_slices_current_uplink, n_active_slices_uplink); + module_idP, frameP, subframeP, n_active_slices_current_uplink, n_active_slices_uplink); n_active_slices_current_uplink = n_active_slices_uplink; @@ -1125,7 +1125,7 @@ schedule_ulsch(module_id_t module_idP, frame_t frameP, // check if the slice rb share has changed, and log the console if (slice_percentage_current_uplink[i] != slice_percentage_uplink[i]){ LOG_N(MAC,"[eNB %d][SLICE %d][UL] frame %d subframe %d: total percentage %f-->%f, slice RB percentage has changed: %f-->%f\n", - mod_id, i, frame, subframe, total_slice_percentage_current_uplink, total_slice_percentage_uplink, slice_percentage_current_uplink[i], slice_percentage_uplink[i]); + module_idP, i, frameP, subframeP, total_slice_percentage_current_uplink, total_slice_percentage_uplink, slice_percentage_current_uplink[i], slice_percentage_uplink[i]); total_slice_percentage_current_uplink= total_slice_percentage_uplink; slice_percentage_current_uplink[i] = slice_percentage_uplink[i]; @@ -1135,10 +1135,10 @@ schedule_ulsch(module_id_t module_idP, frame_t frameP, if (slice_maxmcs_current_uplink[i] != slice_maxmcs_uplink[i]){ if ((slice_maxmcs_uplink[i] >= 0) && (slice_maxmcs_uplink[i] <= 16)){ LOG_N(MAC,"[eNB %d][SLICE %d][UL] frame %d subframe %d: slice MAX MCS has changed: %d-->%d\n", - mod_id, i, frame, subframe, slice_maxmcs_current_uplink[i], slice_maxmcs_uplink[i]); + module_idP, i, frameP, subframeP, slice_maxmcs_current_uplink[i], slice_maxmcs_uplink[i]); slice_maxmcs_current_uplink[i] = slice_maxmcs_uplink[i]; } else { - LOG_W(MAC,"[eNB %d][SLICE %d][UL] invalid slice max mcs %d, revert the previous value %d\n",mod_id, i, slice_maxmcs_uplink[i],slice_maxmcs_current_uplink[i]); + LOG_W(MAC,"[eNB %d][SLICE %d][UL] invalid slice max mcs %d, revert the previous value %d\n",module_idP, i, slice_maxmcs_uplink[i],slice_maxmcs_current_uplink[i]); slice_maxmcs_uplink[i]= slice_maxmcs_current_uplink[i]; } @@ -1147,7 +1147,7 @@ schedule_ulsch(module_id_t module_idP, frame_t frameP, // check if a new scheduler, and log the console if (update_ul_scheduler_current[i] != update_ul_scheduler[i]){ LOG_N(MAC,"[eNB %d][SLICE %d][UL] frame %d subframe %d: UL scheduler for this slice is updated: %s \n", - mod_id, i, frame, subframe, ul_scheduler_type[i]); + module_idP, i, frameP, subframeP, ul_scheduler_type[i]); update_ul_scheduler_current[i] = update_ul_scheduler[i]; } @@ -1156,8 +1156,8 @@ schedule_ulsch(module_id_t module_idP, frame_t frameP, if (n_active_slices_uplink == n_active_slices_current_uplink){ LOG_W(MAC,"[eNB %d][SLICE %d][UL] invalid total RB share (%f->%f), reduce proportionally the RB share by 0.1\n", - mod_id,i, - total_slice_percentage_current_uplink, total_slice_percentage_uplink); + module_idP, i, total_slice_percentage_current_uplink, + total_slice_percentage_uplink); if (slice_percentage_uplink[i] > avg_slice_percentage_uplink){ slice_percentage_uplink[i]-=0.1; total_slice_percentage_uplink-=0.1; @@ -1165,9 +1165,9 @@ schedule_ulsch(module_id_t module_idP, frame_t frameP, } else { // here we can correct the values, e.g. reduce proportionally LOG_W(MAC,"[eNB %d][SLICE %d][UL] invalid total RB share (%f->%f), revert the number of slice to its previous value (%d->%d)\n", - mod_id,i, - total_slice_percentage_current_uplink, total_slice_percentage_uplink, - n_active_slices_uplink, n_active_slices_current_uplink); + module_idP, i, total_slice_percentage_current_uplink, + total_slice_percentage_uplink, n_active_slices_uplink, + n_active_slices_current_uplink); n_active_slices_uplink = n_active_slices_current_uplink; slice_percentage_uplink[i] = slice_percentage_current_uplink[i]; } diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index af5b6f660b..dbe0d820f2 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -57,6 +57,8 @@ #define DEBUG_HEADER_PARSING 1 //#define DEBUG_PACKET_TRACE 1 +extern float slice_percentage[MAX_NUM_SLICES]; + //#define ICIC 0 /* @@ -267,7 +269,8 @@ assign_rbs_required(module_id_t Mod_id, to_prb(RC.mac[Mod_id]->common_channels[CC_id]. mib->message.dl_Bandwidth); - UE_list->ue_sched_ctl.max_allowed_rbs[CC_id][slice_id]= flexran_nb_rbs_allowed_slice(slice_percentage[slice_id],N_RB_DL); + /* TODO Navid: field max_rbs_allowed_slice is [MAX_NUM_LCID][MAX_NUM_SLICES] -> Why CC_id? or bug in definition? */ + UE_list->UE_sched_ctrl[UE_id].max_rbs_allowed_slice[CC_id][slice_id]= flexran_nb_rbs_allowed_slice(slice_percentage[slice_id],N_RB_DL); /* calculating required number of RBs for each UE */ while (TBS < @@ -275,10 +278,13 @@ assign_rbs_required(module_id_t Mod_id, dl_buffer_total) { nb_rbs_required[CC_id][UE_id] += min_rb_unit[CC_id]; - if (nb_rbs_required[CC_id][UE_id] > UE_list->ue_sched_ctl.max_allowed_rbs[CC_id][slice_id]) { + /* TODO Navid: field max_rbs_allowed_slice is [MAX_NUM_LCID][MAX_NUM_SLICES] -> Why CC_id? or bug in definition? */ + if (nb_rbs_required[CC_id][UE_id] > UE_list->UE_sched_ctrl[UE_id].max_rbs_allowed_slice[CC_id][slice_id]) { TBS = - get_TBS_DL(eNB_UE_stats->dlsch_mcs1, UE_list->ue_sched_ctl.max_allowed_rbs[CC_id][slice_id]); - nb_rbs_required[CC_id][UE_id] = UE_list->ue_sched_ctl.max_allowed_rbs[CC_id][slice_id]; + /* TODO Navid: field max_rbs_allowed_slice is [MAX_NUM_LCID][MAX_NUM_SLICES] -> Why CC_id? or bug in definition? */ + get_TBS_DL(eNB_UE_stats->dlsch_mcs1, UE_list->UE_sched_ctrl[UE_id].max_rbs_allowed_slice[CC_id][slice_id]); + /* TODO Navid: field max_rbs_allowed_slice is [MAX_NUM_LCID][MAX_NUM_SLICES] -> Why CC_id? */ + nb_rbs_required[CC_id][UE_id] = UE_list->UE_sched_ctrl[UE_id].max_rbs_allowed_slice[CC_id][slice_id]; break; } @@ -614,7 +620,7 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, if (UE_list->active[i] != TRUE) continue; - if (!flexran_slice_member(UE_id, slice_id)) + if (!flexran_slice_member(i, slice_id)) continue; UE_id = i; @@ -724,13 +730,15 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, message.dl_Bandwidth) - total_rbs_used[CC_id]; //recalcualte based on the what is left after retransmission - ue_sched_ctl.max_allowed_rbs[CC_id][slice_id]= flexran_nb_rbs_allowed_slice(slice_percentage[slice_id],N_RB_DL); + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + /* TODO Navid: as above */ + ue_sched_ctl->max_rbs_allowed_slice[CC_id][slice_id]= flexran_nb_rbs_allowed_slice(slice_percentage[slice_id],N_RB_DL); if (total_ue_count[CC_id] == 0) { average_rbs_per_user[CC_id] = 0; - } else if ((min_rb_unit[CC_id] * total_ue_count[CC_id]) <= (ue_sched_ctl.max_allowed_rbs[CC_id][slice_id])) { + } else if ((min_rb_unit[CC_id] * total_ue_count[CC_id]) <= (ue_sched_ctl->max_rbs_allowed_slice[CC_id][slice_id])) { average_rbs_per_user[CC_id] = - (uint16_t) floor(ue_sched_ctl.max_allowed_rbs[CC_id][slice_id] / total_ue_count[CC_id]); + (uint16_t) floor(ue_sched_ctl->max_rbs_allowed_slice[CC_id][slice_id] / total_ue_count[CC_id]); } else { average_rbs_per_user[CC_id] = min_rb_unit[CC_id]; // consider the total number of use that can be scheduled UE } @@ -1390,7 +1398,7 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, int N_RB_UL; LOG_D(MAC, "In ulsch_preprocessor: assign max mcs min rb\n"); // maximize MCS and then allocate required RB according to the buffer occupancy with the limit of max available UL RB - assign_max_mcs_min_rb(module_idP, frameP, subframeP, first_rb); + assign_max_mcs_min_rb(module_idP, slice_id, frameP, subframeP, first_rb); LOG_D(MAC, "In ulsch_preprocessor: sort ue \n"); // sort ues diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 842e1d7080..c7aa6290ae 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -217,6 +217,8 @@ void dlsch_scheduler_pre_processor_reset(int module_idP, int UE_id, uint16_t nb_rbs_required_remaining [MAX_NUM_CCs][NUMBER_OF_UE_MAX], + unsigned char total_ue_count[MAX_NUM_CCs], + unsigned char total_rbs_used[MAX_NUM_CCs], unsigned char rballoc_sub[MAX_NUM_CCs] [N_RBG_MAX], @@ -665,7 +667,7 @@ void ulsch_scheduler_pre_processor(module_id_t module_idP, slice_id_t slice_id, void store_ulsch_buffer(module_id_t module_idP, int frameP, sub_frame_t subframeP); void sort_ue_ul(module_id_t module_idP, int frameP, sub_frame_t subframeP); -void assign_max_mcs_min_rb(module_id_t module_idP, int frameP, +void assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, sub_frame_t subframeP, uint16_t * first_rb); void adjust_bsr_info(int buffer_occupancy, uint16_t TBS, UE_TEMPLATE * UE_template); diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index c946dcf818..8402d1ba61 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -2156,7 +2156,7 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt int i; // configure SRB1/SRB2, PhysicalConfigDedicated, MAC_MainConfig for UE - eNB_RRC_INST* rrc_inst = &eNB_rrc_inst[ctxt_pP->module_id]; + eNB_RRC_INST* rrc_inst = RC.rrc[ctxt_pP->module_id]; struct PhysicalConfigDedicated** physicalConfigDedicated = &ue_context_pP->ue_context.physicalConfigDedicated; struct SRB_ToAddMod *SRB2_config = NULL; diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 0626ad7725..6b418bb8ff 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -239,9 +239,7 @@ static void* eNB_thread_rxtx( void* param ) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); -#ifdef DEBUG_THREADS - printf(" *** Exiting eNB thread RXn_TXnp4\n"); -#endif + LOG_D(PHY, " *** Exiting eNB thread RXn_TXnp4\n"); eNB_thread_rxtx_status = 0; return &eNB_thread_rxtx_status; @@ -624,8 +622,6 @@ void init_eNB_proc(int inst) { pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL); pthread_mutex_init( &proc->mutex_RU,NULL); pthread_mutex_init( &proc->mutex_RU_PRACH,NULL); - pthread_mutex_init( &proc->mutex_synch,NULL); - pthread_mutex_init( &proc->mutex_FH, NULL); pthread_cond_init( &proc->cond_prach, NULL); pthread_cond_init( &proc->cond_asynch_rxtx, NULL); @@ -727,22 +723,12 @@ void kill_eNB_proc(int inst) { proc_rxtx[1].instance_cnt_rxtx = 0; pthread_mutex_unlock(&proc_rxtx[1].mutex_rxtx); } - pthread_mutex_lock(&PHY_vars_eNB_g[0][CC_id]->proc.mutex_synch); - PHY_vars_eNB_g[0][CC_id]->proc.instance_cnt_synch = 1; - pthread_mutex_unlock(&PHY_vars_eNB_g[0][CC_id]->proc.mutex_synch); proc->instance_cnt_prach = 0; pthread_cond_signal( &proc->cond_prach ); - pthread_cond_signal( &proc->cond_FH ); pthread_cond_signal( &proc->cond_asynch_rxtx ); - pthread_cond_signal( &proc->cond_synch ); pthread_cond_broadcast(&sync_phy_proc.cond_phy_proc_tx); - LOG_D(PHY, "joining pthread_FH\n"); - pthread_join( proc->pthread_FH, (void**)&status ); - pthread_mutex_destroy( &proc->mutex_FH ); - pthread_cond_destroy( &proc->cond_FH ); - LOG_D(PHY, "joining pthread_prach\n"); pthread_join( proc->pthread_prach, (void**)&status ); @@ -776,12 +762,7 @@ void kill_eNB_proc(int inst) { LOG_D(PHY, "joining pthread_single\n"); pthread_join(proc->pthread_single, (void**)&status ); - - LOG_D(PHY, "joining pthread_synch\n"); - pthread_join(proc->pthread_synch, (void**)&status ); - pthread_mutex_destroy(&proc->mutex_synch); - pthread_cond_destroy(&proc->cond_synch); - LOG_D(PHY, "joined all threads\n"); + LOG_D(PHY, "joined all eNB threads\n"); } } diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 315eee23cd..eab0a88c45 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -229,8 +229,6 @@ uint8_t abstraction_flag=0; /* forward declarations */ void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); -/* override the enb configuration parameters */ -static void reconfigure_enb_params(int enb_id); /*---------------------BMC: timespec helpers -----------------------------*/ @@ -691,54 +689,6 @@ static void get_options(void) { } -static void reconfigure_enb_params(int enb_id) -{ - int CC_id, k; - const Enb_properties_array_t *enb_properties=enb_config_get(); - - for (CC_id=0; CC_idproperties[enb_id]->cc_node_function[CC_id]; - node_timing[CC_id] = enb_properties->properties[enb_id]->cc_node_timing[CC_id]; - node_synch_ref[CC_id] = enb_properties->properties[enb_id]->cc_node_synch_ref[CC_id]; - - frame_parms[CC_id]->frame_type = enb_properties->properties[enb_id]->frame_type[CC_id]; - frame_parms[CC_id]->tdd_config = enb_properties->properties[enb_id]->tdd_config[CC_id]; - frame_parms[CC_id]->tdd_config_S = enb_properties->properties[enb_id]->tdd_config_s[CC_id]; - frame_parms[CC_id]->Ncp = enb_properties->properties[enb_id]->prefix_type[CC_id]; - - //for (j=0; j < enb_properties->properties[i]->nb_cc; j++ ){ - frame_parms[CC_id]->Nid_cell = enb_properties->properties[enb_id]->Nid_cell[CC_id]; - frame_parms[CC_id]->N_RB_DL = enb_properties->properties[enb_id]->N_RB_DL[CC_id]; - frame_parms[CC_id]->N_RB_UL = enb_properties->properties[enb_id]->N_RB_DL[CC_id]; - frame_parms[CC_id]->nb_antennas_tx = enb_properties->properties[enb_id]->nb_antennas_tx[CC_id]; - frame_parms[CC_id]->nb_antenna_ports_eNB = enb_properties->properties[enb_id]->nb_antenna_ports[CC_id]; - frame_parms[CC_id]->nb_antennas_rx = enb_properties->properties[enb_id]->nb_antennas_rx[CC_id]; - - frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_ConfigIndex = enb_properties->properties[enb_id]->prach_config_index[CC_id]; - frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset = enb_properties->properties[enb_id]->prach_freq_offset[CC_id]; - - frame_parms[CC_id]->mode1_flag = (frame_parms[CC_id]->nb_antenna_ports_eNB == 1) ? 1 : 0; - frame_parms[CC_id]->threequarter_fs = threequarter_fs; - - for (k = 0 ; k < 4; k++) { - downlink_frequency[CC_id][k] = enb_properties->properties[enb_id]->downlink_frequency[CC_id]; - uplink_frequency_offset[CC_id][k] = enb_properties->properties[enb_id]->uplink_frequency_offset[CC_id]; - rx_gain[CC_id][k] = (double)enb_properties->properties[enb_id]->rx_gain[CC_id]; - tx_gain[CC_id][k] = (double)enb_properties->properties[enb_id]->tx_gain[CC_id]; - } - - printf("Downlink frequency/ uplink offset of CC_id %d set to %ju/%d\n", CC_id, - enb_properties->properties[enb_id]->downlink_frequency[CC_id], - enb_properties->properties[enb_id]->uplink_frequency_offset[CC_id]); - - init_ul_hopping(frame_parms[CC_id]); - init_frame_parms(frame_parms[CC_id],1); - // phy_init_top(frame_parms[CC_id]); - phy_init_lte_top(frame_parms[CC_id]); - } // CC_id -} - #if T_TRACER int T_nowait = 0; /* by default we wait for the tracer */ int T_port = 2021; /* default port to listen to to wait for the tracer */ @@ -887,6 +837,7 @@ void init_openair0() { } } + void wait_RUs(void) { LOG_I(PHY,"Waiting for RUs to be configured ...\n"); @@ -923,70 +874,6 @@ void wait_eNBs(void) { printf("eNB L1 are configured\n"); } -void fill_PHY_vars_eNB_g(uint8_t abstraction_flag, uint8_t beta_ACK, uint8_t beta_RI, uint8_t beta_CQI) -{ - int CC_id, i, j, k, re; - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - PHY_vars_eNB_g[0][CC_id] = init_lte_eNB(frame_parms[CC_id], - 0, - frame_parms[CC_id]->Nid_cell, - node_function[CC_id], - abstraction_flag); - PHY_vars_eNB_g[0][CC_id]->ue_dl_rb_alloc = 0x1fff; - PHY_vars_eNB_g[0][CC_id]->target_ue_dl_mcs = target_dl_mcs; - PHY_vars_eNB_g[0][CC_id]->ue_ul_nb_rb = 6; - PHY_vars_eNB_g[0][CC_id]->target_ue_ul_mcs = target_ul_mcs; - // initialization for phy-test - for (k = 0; k < NUMBER_OF_UE_MAX; k++) { - PHY_vars_eNB_g[0][CC_id]->transmission_mode[k] = transmission_mode; - if (transmission_mode == 7) - lte_gold_ue_spec_port5(PHY_vars_eNB_g[0][CC_id]->lte_gold_uespec_port5_table[k], - frame_parms[CC_id]->Nid_cell, - 0x1235+k); - } - if ((transmission_mode == 1) || (transmission_mode == 7)) { - for (j = 0; j < frame_parms[CC_id]->nb_antennas_tx; j++) - for (re = 0; re < frame_parms[CC_id]->ofdm_symbol_size; re++) - PHY_vars_eNB_g[0][CC_id]->common_vars.beam_weights[0][0][j][re] = 0x00007fff / frame_parms[CC_id]->nb_antennas_tx; - } - - if (phy_test==1) - PHY_vars_eNB_g[0][CC_id]->mac_enabled = 0; - else - PHY_vars_eNB_g[0][CC_id]->mac_enabled = 1; - - if (PHY_vars_eNB_g[0][CC_id]->mac_enabled == 0) { //set default parameters for testing mode - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - PHY_vars_eNB_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_ACK_Index = beta_ACK; - PHY_vars_eNB_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_RI_Index = beta_RI; - PHY_vars_eNB_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_CQI_Index = beta_CQI; - - PHY_vars_eNB_g[0][CC_id]->scheduling_request_config[i].sr_PUCCH_ResourceIndex = i; - PHY_vars_eNB_g[0][CC_id]->scheduling_request_config[i].sr_ConfigIndex = 7+(i%3); - PHY_vars_eNB_g[0][CC_id]->scheduling_request_config[i].dsr_TransMax = sr_n4; - } - } - - compute_prach_seq(&PHY_vars_eNB_g[0][CC_id]->frame_parms.prach_config_common, - PHY_vars_eNB_g[0][CC_id]->frame_parms.frame_type, - PHY_vars_eNB_g[0][CC_id]->X_u); - - - PHY_vars_eNB_g[0][CC_id]->rx_total_gain_dB = (int)rx_gain[CC_id][0]; - - if (frame_parms[CC_id]->frame_type == FDD) { - PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 0; - } else { - if (frame_parms[CC_id]->N_RB_DL == 100) - PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624; - else if (frame_parms[CC_id]->N_RB_DL == 50) - PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624/2; - else if (frame_parms[CC_id]->N_RB_DL == 25) - PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624/4; - } - } -} - #if defined(ENABLE_ITTI) && defined(FLEXRAN_AGENT_SB_IF) /* * helper function to terminate a certain ITTI task @@ -999,6 +886,7 @@ void terminate_task(task_id_t task_id, mid_t mod_id) itti_send_msg_to_task (task_id, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg); } +#if 0 int stop_L1L2(int enb_id) { int CC_id; @@ -1107,6 +995,7 @@ int restart_L1L2(int enb_id) return 0; } #endif +#endif int main( int argc, char **argv ) { @@ -1274,19 +1163,14 @@ int main( int argc, char **argv ) flexran_agent_start(i); } - LOG_I(ENB_APP, " * Waiting for FlexRAN RTController command *\n"); - pthread_mutex_lock(&mutex_node_ctrl); - while (ENB_NORMAL_OPERATION != node_control_state) - pthread_cond_wait(&cond_node_ctrl, &mutex_node_ctrl); - pthread_mutex_unlock(&mutex_node_ctrl); + /* TODO handle restart/initial blocking */ + //LOG_I(ENB_APP, " * Waiting for FlexRAN RTController command *\n"); + //pthread_mutex_lock(&mutex_node_ctrl); + //while (ENB_NORMAL_OPERATION != node_control_state) + // pthread_cond_wait(&cond_node_ctrl, &mutex_node_ctrl); + //pthread_mutex_unlock(&mutex_node_ctrl); - /* reconfigure eNB in case FlexRAN controller applied changes */ - /* TODO needs to be done? */ - //for (i=0; i < NB_eNB_INST; i++){ - // LOG_I(ENB_APP, "Reconfigure eNB module %d and FlexRAN eNB variables\n", i); - // reconfigure_enb_params(i); - // flexran_set_enb_vars(i, RAN_LTE_OAI); - //} + /* TODO do eNB reconfiguration (handled implicitly?) */ #endif if (UE_flag==1) { @@ -1611,6 +1495,7 @@ int main( int argc, char **argv ) } } } + #endif printf("stopping MODEM threads\n"); diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index 6274fc1610..13e5ba6b91 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -269,7 +269,7 @@ extern int restart_L1L2(int enb_id); #ifdef FLEXRAN_AGENT_SB_IF #include "flexran_agent.h" // for locking -volatile ENB_MODULE_STATE node_control_state; +//volatile ENB_MODULE_STATE node_control_state; pthread_cond_t cond_node_ctrl; pthread_mutex_t mutex_node_ctrl; #endif From 56d4d0ebef8e5b21987d4a5412c961f52952549d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 16 Jan 2018 12:27:55 +0100 Subject: [PATCH 182/284] Bugfix: avoid cyclic header dependency, use FlexRAN variables instead --- .../ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h | 1 - openair2/ENB_APP/flexran_agent_extern.h | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h index a101bab242..cf20c477de 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h @@ -31,7 +31,6 @@ #ifndef __FLEXRAN_AGENT_RRC_PRIMITIVES_H__ #define __FLEXRAN_AGENT_RRC_PRIMITIVES_H__ -#include "PHY/extern.h" #include "flexran_agent_defs.h" #include "flexran.pb-c.h" #include "header.pb-c.h" diff --git a/openair2/ENB_APP/flexran_agent_extern.h b/openair2/ENB_APP/flexran_agent_extern.h index 589975b310..ae77e9227a 100644 --- a/openair2/ENB_APP/flexran_agent_extern.h +++ b/openair2/ENB_APP/flexran_agent_extern.h @@ -30,11 +30,10 @@ #ifndef __FLEXRAN_AGENT_EXTERN_H__ #define __FLEXRAN_AGENT_EXTERN_H__ -// #include "flexran_agent_defs.h" +#include "flexran_agent_defs.h" #include "flexran_agent_mac_defs.h" #include "flexran_agent_rrc_defs.h" #include "flexran_agent_pdcp_defs.h" -#include "common/ran_context.h" /* Control module interface for the communication of the MAC Control Module with the agent */ extern AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB]; @@ -55,7 +54,7 @@ extern AGENT_PDCP_xface *agent_pdcp_xface[NUM_MAX_ENB]; extern unsigned int pdcp_agent_registered[NUM_MAX_ENB]; /* Requried to know which UEs had a harq updated over some subframe */ -extern int harq_pid_updated[NUMBER_OF_UE_MAX][8]; -extern int harq_pid_round[NUMBER_OF_UE_MAX][8]; +extern int harq_pid_updated[NUM_MAX_UE][8]; +extern int harq_pid_round[NUM_MAX_UE][8]; #endif From 3740afecc7081971dfcf8eb0e3c0b03495f1aaad Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 16 Jan 2018 12:30:34 +0100 Subject: [PATCH 183/284] consider changed RAN API --- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 17 ++++++++++------- .../CONTROL_MODULES/RRC/flexran_agent_rrc.c | 9 +++++---- openair2/ENB_APP/flexran_agent_common.c | 9 +++++---- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index d60a9eb3b7..4f91e65c6a 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -219,21 +219,21 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, if (flexran_get_antenna_ports(enb_id, j) == 2 && csi_reports[j]->ri == 1) { // TODO PMI - csi11->wb_pmi = flexran_get_ue_pmi(enb_id); + csi11->wb_pmi = flexran_get_ue_wpmi(enb_id, i, 0); csi11->has_wb_pmi = 1; } else if (flexran_get_antenna_ports(enb_id, j) == 2 && csi_reports[j]->ri == 2){ // TODO PMI - csi11->wb_pmi = flexran_get_ue_pmi(enb_id); + csi11->wb_pmi = flexran_get_ue_wpmi(enb_id, i, 0); csi11->has_wb_pmi = 1; } else if (flexran_get_antenna_ports(enb_id, j) == 4 && csi_reports[j]->ri == 2){ // TODO PMI - csi11->wb_pmi = flexran_get_ue_pmi(enb_id); + csi11->wb_pmi = flexran_get_ue_wpmi(enb_id, i, 0); csi11->has_wb_pmi = 1; @@ -868,13 +868,16 @@ int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Fle protocol__flex_ul_info__init(ul_info[i]); ul_info[i]->rnti = flexran_get_ue_crnti(mod_id, i); ul_info[i]->has_rnti = 1; - /*Fill in the Tx power control command for this UE (if available)*/ - if(flexran_get_tpc(mod_id,i) != 1){ - ul_info[i]->tpc = flexran_get_tpc(mod_id,i); + /* Fill in the Tx power control command for this UE (if available), + * primary carrier */ + if(flexran_get_tpc(mod_id, i, 0) != 1){ + /* assume primary carrier */ + ul_info[i]->tpc = flexran_get_tpc(mod_id, i, 0); ul_info[i]->has_tpc = 1; } else{ - ul_info[i]->tpc = flexran_get_tpc(mod_id,i); + /* assume primary carrier */ + ul_info[i]->tpc = flexran_get_tpc(mod_id, i, 0); ul_info[i]->has_tpc = 0; } /*TODO: fill in the amount of data in bytes in the MAC SDU received in this subframe for the diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c index 6f42d1da97..590e9c870f 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c @@ -165,9 +165,10 @@ void flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_ch config->beta_offset_cqi_index = flexran_get_beta_offset_cqi_index(mod_id,i); } - if(flexran_get_ack_nack_simultaneous_trans(mod_id,i) != -1) { + /* assume primary carrier */ + if(flexran_get_ack_nack_simultaneous_trans(mod_id,i,0) != -1) { config->has_ack_nack_simultaneous_trans = 1; - config->ack_nack_simultaneous_trans = flexran_get_ack_nack_simultaneous_trans(mod_id,i); + config->ack_nack_simultaneous_trans = flexran_get_ack_nack_simultaneous_trans(mod_id,i,0); } if(flexran_get_simultaneous_ack_nack_cqi(mod_id,i) != -1) { @@ -185,9 +186,9 @@ void flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_ch } } - if(flexran_get_tdd_ack_nack_feedback(mod_id, i) != -1) { + if(flexran_get_tdd_ack_nack_feedback_mode(mod_id, i) != -1) { config->has_tdd_ack_nack_feedback = 1; - config->tdd_ack_nack_feedback = flexran_get_tdd_ack_nack_feedback(mod_id,i); + config->tdd_ack_nack_feedback = flexran_get_tdd_ack_nack_feedback_mode(mod_id,i); } if(flexran_get_ack_nack_repetition_factor(mod_id, i) != -1) { diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index 00aa7e9263..33879714d9 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -676,9 +676,10 @@ int flexran_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Fl ue_config[i]->beta_offset_cqi_index = flexran_get_beta_offset_cqi_index(mod_id,i); } - if (flexran_get_ack_nack_simultaneous_trans(mod_id,i) != -1) { + /* assume primary carrier */ + if (flexran_get_ack_nack_simultaneous_trans(mod_id, i, 0) != -1) { ue_config[i]->has_ack_nack_simultaneous_trans = 1; - ue_config[i]->ack_nack_simultaneous_trans = flexran_get_ack_nack_simultaneous_trans(mod_id,i); + ue_config[i]->ack_nack_simultaneous_trans = flexran_get_ack_nack_simultaneous_trans(mod_id, i, 0); } if (flexran_get_simultaneous_ack_nack_cqi(mod_id,i) != -1) { @@ -696,9 +697,9 @@ int flexran_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Fl } } - if (flexran_get_tdd_ack_nack_feedback(mod_id, i) != -1) { + if (flexran_get_tdd_ack_nack_feedback_mode(mod_id, i) != -1) { ue_config[i]->has_tdd_ack_nack_feedback = 1; - ue_config[i]->tdd_ack_nack_feedback = flexran_get_tdd_ack_nack_feedback(mod_id,i); + ue_config[i]->tdd_ack_nack_feedback = flexran_get_tdd_ack_nack_feedback_mode(mod_id,i); } if(flexran_get_ack_nack_repetition_factor(mod_id, i) != -1) { From 356d406cffbbfa444aa7e05a7c96e637132c60e3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 16 Jan 2018 12:36:44 +0100 Subject: [PATCH 184/284] Navid: remove FlexRAN Agent MAC xface function callbacks for scheduling --- .../ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c | 5 ----- .../CONTROL_MODULES/MAC/flexran_agent_mac_defs.h | 11 ----------- .../CONTROL_MODULES/MAC/flexran_agent_mac_internal.c | 1 - 3 files changed, 17 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 4f91e65c6a..3d0d08efbb 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -1249,9 +1249,6 @@ int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->flexran_agent_send_sr_info = flexran_agent_send_sr_info; xface->flexran_agent_send_sf_trigger = flexran_agent_send_sf_trigger; //xface->flexran_agent_send_update_mac_stats = flexran_agent_send_update_mac_stats; - xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_dl_spec_default; - xface->flexran_agent_schedule_ul_spec = flexran_schedule_ue_ul_spec_default; - //xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_remote; xface->flexran_agent_get_pending_dl_mac_config = flexran_agent_get_pending_dl_mac_config; xface->dl_scheduler_loaded_lib = NULL; @@ -1268,9 +1265,7 @@ int flexran_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->flexran_agent_send_sr_info = NULL; xface->flexran_agent_send_sf_trigger = NULL; //xface->flexran_agent_send_update_mac_stats = NULL; - xface->flexran_agent_schedule_ue_spec = NULL; xface->flexran_agent_get_pending_dl_mac_config = NULL; - xface->flexran_agent_schedule_ul_spec = NULL; xface->dl_scheduler_loaded_lib = NULL; xface->ul_scheduler_loaded_lib = NULL; diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h index 769ddbb1b6..5c1fc1379c 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h @@ -54,17 +54,6 @@ typedef struct { void (*flexran_agent_get_pending_dl_mac_config)(mid_t mod_id, Protocol__FlexranMessage **msg); - /// Run the UE DL scheduler and fill the Protocol__FlexranMessage. Assumes that - /// dl_info is already initialized as flex_dl_mac_config and fills the - /// flex_dl_data part of it - void (*flexran_agent_schedule_ue_spec)(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__FlexranMessage **dl_info); - - /// Run the UE UL scheduler and fill the Protocol__FlexranMessage. Assumes that - - void (*flexran_agent_schedule_ul_spec)(mid_t module_idP, uint32_t frameP, uint32_t cooperation_flag, - int subframeP, unsigned char sched_subframe, Protocol__FlexranMessage **ul_info); - /// Notify the controller for a state change of a particular UE, by sending the proper /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) // int (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c index 2af6514ef6..b7a93b8491 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c @@ -883,7 +883,6 @@ int load_dl_scheduler_function(mid_t mod_id, const char *function_name) { void *loaded_scheduler = dlsym(lib, function_name); if (loaded_scheduler) { if (mac_agent_registered[mod_id]) { - agent_mac_xface[mod_id]->flexran_agent_schedule_ue_spec = loaded_scheduler; if (agent_mac_xface[mod_id]->dl_scheduler_loaded_lib != NULL) { dlclose(agent_mac_xface[mod_id]->dl_scheduler_loaded_lib); } From 6179d9d7481ddecc17802a2975dea60c578dfe69 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 16 Jan 2018 15:18:22 +0100 Subject: [PATCH 185/284] Navid: fix access to non-existent harq_pid_* variables via RC read --- .../ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 3d0d08efbb..4f5d8af250 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -785,7 +785,7 @@ int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Fle for (i = 0; i < NUMBER_OF_UE_MAX; i++) { for (j = 0; j < 8; j++) { - if (harq_pid_updated[i][j] == 1) { + if (RC.mac && RC.mac[mod_id] && RC.mac[mod_id]->UE_list.eNB_UE_stats[UE_PCCID(mod_id,i)][i].harq_pid == 1) { available_harq[i] = j; sf_trigger_msg->n_dl_info++; break; @@ -828,14 +828,15 @@ int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Fle dl_info[i]->harq_process_id = available_harq[UE_id]; - harq_pid_updated[UE_id][available_harq[UE_id]] = 0; + if (RC.mac && RC.mac[mod_id]) + RC.mac[mod_id]->UE_list.eNB_UE_stats[UE_PCCID(mod_id,i)][UE_id].harq_pid = 0; dl_info[i]->has_harq_process_id = 1; /* Fill in the status of the HARQ process (2 TBs)*/ dl_info[i]->n_harq_status = 2; dl_info[i]->harq_status = malloc(sizeof(uint32_t) * dl_info[i]->n_harq_status); for (j = 0; j < dl_info[i]->n_harq_status; j++) { - dl_info[i]->harq_status[j] = harq_pid_round[UE_id][available_harq[UE_id]]; - // TODO: This should be different per TB + dl_info[i]->harq_status[j] = RC.mac[mod_id]->UE_list.UE_sched_ctrl[i].round[UE_PCCID(mod_id,i)][j]; + // TODO: This should be different per TB } // LOG_I(FLEXRAN_AGENT, "Sending subframe trigger for frame %d and subframe %d and harq %d (round %d)\n", flexran_get_current_frame(mod_id), (flexran_get_current_subframe(mod_id) + 1) % 10, dl_info[i]->harq_process_id, dl_info[i]->harq_status[0]); if(dl_info[i]->harq_status[0] > 0) { @@ -1168,7 +1169,8 @@ void flexran_agent_init_mac_agent(mid_t mod_id) { lfds700_ringbuffer_init_valid_on_current_logical_core( &ringbuffer_state[mod_id], dl_mac_config_array[mod_id], num_elements, &ps[mod_id], NULL ); for (i = 0; i < NUMBER_OF_UE_MAX; i++) { for (j = 0; j < 8; j++) { - harq_pid_updated[i][j] = 0; + if (RC.mac && RC.mac[mod_id]) + RC.mac[mod_id]->UE_list.eNB_UE_stats[UE_PCCID(mod_id,i)][i].harq_pid = 0; } } } From 1576b7bd08ff7d060dfa8022c1e26af55dfeb2ba Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 29 Jan 2018 11:03:16 +0100 Subject: [PATCH 186/284] bugfix: max_rbs_allowed_slice is array over CC, not LCID --- openair2/LAYER2/MAC/defs.h | 3 +-- openair2/LAYER2/MAC/pre_processor.c | 8 +------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 36538a3364..2f71c0ee74 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -800,8 +800,7 @@ typedef struct { ///Contention resolution timer used during random access uint8_t mac_ContentionResolutionTimer; - /* TODO Navid MAX_NUM_LCID -> MAX_NUM_CCs? */ - uint16_t max_rbs_allowed_slice[MAX_NUM_LCID][MAX_NUM_SLICES]; + uint16_t max_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES]; uint8_t max_mcs[MAX_NUM_LCID]; diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index dbe0d820f2..017e62b48f 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -269,7 +269,6 @@ assign_rbs_required(module_id_t Mod_id, to_prb(RC.mac[Mod_id]->common_channels[CC_id]. mib->message.dl_Bandwidth); - /* TODO Navid: field max_rbs_allowed_slice is [MAX_NUM_LCID][MAX_NUM_SLICES] -> Why CC_id? or bug in definition? */ UE_list->UE_sched_ctrl[UE_id].max_rbs_allowed_slice[CC_id][slice_id]= flexran_nb_rbs_allowed_slice(slice_percentage[slice_id],N_RB_DL); /* calculating required number of RBs for each UE */ @@ -278,12 +277,8 @@ assign_rbs_required(module_id_t Mod_id, dl_buffer_total) { nb_rbs_required[CC_id][UE_id] += min_rb_unit[CC_id]; - /* TODO Navid: field max_rbs_allowed_slice is [MAX_NUM_LCID][MAX_NUM_SLICES] -> Why CC_id? or bug in definition? */ if (nb_rbs_required[CC_id][UE_id] > UE_list->UE_sched_ctrl[UE_id].max_rbs_allowed_slice[CC_id][slice_id]) { - TBS = - /* TODO Navid: field max_rbs_allowed_slice is [MAX_NUM_LCID][MAX_NUM_SLICES] -> Why CC_id? or bug in definition? */ - get_TBS_DL(eNB_UE_stats->dlsch_mcs1, UE_list->UE_sched_ctrl[UE_id].max_rbs_allowed_slice[CC_id][slice_id]); - /* TODO Navid: field max_rbs_allowed_slice is [MAX_NUM_LCID][MAX_NUM_SLICES] -> Why CC_id? */ + TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, UE_list->UE_sched_ctrl[UE_id].max_rbs_allowed_slice[CC_id][slice_id]); nb_rbs_required[CC_id][UE_id] = UE_list->UE_sched_ctrl[UE_id].max_rbs_allowed_slice[CC_id][slice_id]; break; } @@ -731,7 +726,6 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, //recalcualte based on the what is left after retransmission ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - /* TODO Navid: as above */ ue_sched_ctl->max_rbs_allowed_slice[CC_id][slice_id]= flexran_nb_rbs_allowed_slice(slice_percentage[slice_id],N_RB_DL); if (total_ue_count[CC_id] == 0) { From 9333c16ecbc7040fa45724534e4eaaad1e5d67e3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 18 Jan 2018 17:27:15 +0100 Subject: [PATCH 187/284] bugfixes: correctly initialize mutexes, conds of RU_proc_t, unlock RU.mutex after using --- targets/RT/USER/lte-ru.c | 2 ++ targets/RT/USER/lte-softmodem.c | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 54693f43c8..8903438eb0 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -1615,11 +1615,13 @@ void init_RU_proc(RU_t *ru) { pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL); pthread_mutex_init( &proc->mutex_synch,NULL); pthread_mutex_init( &proc->mutex_FH,NULL); + pthread_mutex_init( &proc->mutex_eNBs, NULL); pthread_cond_init( &proc->cond_prach, NULL); pthread_cond_init( &proc->cond_FH, NULL); pthread_cond_init( &proc->cond_asynch_rxtx, NULL); pthread_cond_init( &proc->cond_synch,NULL); + pthread_cond_init( &proc->cond_eNBs, NULL); pthread_attr_init( &proc->attr_FH); pthread_attr_init( &proc->attr_prach); diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index eab0a88c45..44512843d7 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -844,12 +844,10 @@ void wait_RUs(void) { // wait for all RUs to be configured over fronthaul pthread_mutex_lock(&RC.ru_mutex); - - - while (RC.ru_mask>0) { pthread_cond_wait(&RC.ru_cond,&RC.ru_mutex); } + pthread_mutex_unlock(&RC.ru_mutex); LOG_I(PHY,"RUs configured\n"); } From a91a35877dd8b8b2791e173063f9b5080088b69f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 18 Jan 2018 17:28:08 +0100 Subject: [PATCH 188/284] join all RU threads --- targets/RT/USER/lte-ru.c | 119 ++++++++++++++++++++++++++++++-- targets/RT/USER/lte-softmodem.c | 3 +- 2 files changed, 115 insertions(+), 7 deletions(-) diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 8903438eb0..3ff4c4e7ac 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -116,7 +116,7 @@ extern volatile int oai_exit; extern void phy_init_RU(RU_t*); void init_RU(char*); -void stop_RU(RU_t *ru); +void stop_RU(int nb_ru); void do_ru_sync(RU_t *ru); void configure_ru(int idx, @@ -1673,9 +1673,115 @@ void init_RU_proc(RU_t *ru) { } +void kill_RU_proc(int inst) +{ + RU_t *ru = RC.ru[inst]; + RU_proc_t *proc = &ru->proc; + pthread_mutex_lock(&proc->mutex_FH); + proc->instance_cnt_FH = 0; + pthread_mutex_unlock(&proc->mutex_FH); + pthread_cond_signal(&proc->cond_FH); + pthread_mutex_lock(&proc->mutex_prach); + proc->instance_cnt_prach = 0; + pthread_mutex_unlock(&proc->mutex_prach); + pthread_cond_signal(&proc->cond_prach); +#ifdef Rel14 + pthread_mutex_lock(&proc->mutex_prach_br); + proc->instance_cnt_prach_br = 0; + pthread_mutex_unlock(&proc->mutex_prach_br); + pthread_cond_signal(&proc->cond_prach_br); +#endif + + pthread_mutex_lock(&proc->mutex_synch); + proc->instance_cnt_synch = 0; + pthread_mutex_unlock(&proc->mutex_synch); + pthread_cond_signal(&proc->cond_synch); + + pthread_mutex_lock(&proc->mutex_eNBs); + proc->instance_cnt_eNBs = 0; + pthread_mutex_unlock(&proc->mutex_eNBs); + pthread_cond_signal(&proc->cond_eNBs); + + pthread_mutex_lock(&proc->mutex_asynch_rxtx); + proc->instance_cnt_asynch_rxtx = 0; + pthread_mutex_unlock(&proc->mutex_asynch_rxtx); + pthread_cond_signal(&proc->cond_asynch_rxtx); + + LOG_D(PHY, "Joining pthread_FH\n"); + pthread_join(proc->pthread_FH, NULL); + if (ru->function == NGFI_RRU_IF4p5) { + LOG_D(PHY, "Joining pthread_prach\n"); + pthread_join(proc->pthread_prach, NULL); +#ifdef Rel14 + LOG_D(PHY, "Joining pthread_prach_br\n"); + pthread_join(proc->pthread_prach_br, NULL); +#endif + if (ru->is_slave) { + LOG_D(PHY, "Joining pthread_\n"); + pthread_join(proc->pthread_synch, NULL); + } + + if ((ru->if_timing == synch_to_other) || + (ru->function == NGFI_RRU_IF5) || + (ru->function == NGFI_RRU_IF4p5)) { + LOG_D(PHY, "Joining pthread_asynch_rxtx\n"); + pthread_join(proc->pthread_asynch_rxtx, NULL); + } + } + if (get_nprocs() >= 2) { + if (ru->feprx) { + pthread_mutex_lock(&proc->mutex_fep); + proc->instance_cnt_fep = 0; + pthread_mutex_unlock(&proc->mutex_fep); + pthread_cond_signal(&proc->cond_fep); + LOG_D(PHY, "Joining pthread_fep\n"); + pthread_join(proc->pthread_fep, NULL); + pthread_mutex_destroy(&proc->mutex_fep); + pthread_cond_destroy(&proc->cond_fep); + } + if (ru->feptx_ofdm) { + pthread_mutex_lock(&proc->mutex_feptx); + proc->instance_cnt_feptx = 0; + pthread_mutex_unlock(&proc->mutex_feptx); + pthread_cond_signal(&proc->cond_feptx); + LOG_D(PHY, "Joining pthread_feptx\n"); + pthread_join(proc->pthread_feptx, NULL); + pthread_mutex_destroy(&proc->mutex_feptx); + pthread_cond_destroy(&proc->cond_feptx); + } + } + if (opp_enabled) { + LOG_D(PHY, "Joining ru_stats_thread\n"); + pthread_join(ru->ru_stats_thread, NULL); + } + + pthread_mutex_destroy(&proc->mutex_prach); + pthread_mutex_destroy(&proc->mutex_asynch_rxtx); + pthread_mutex_destroy(&proc->mutex_synch); + pthread_mutex_destroy(&proc->mutex_FH); + pthread_mutex_destroy(&proc->mutex_eNBs); + + pthread_cond_destroy(&proc->cond_prach); + pthread_cond_destroy(&proc->cond_FH); + pthread_cond_destroy(&proc->cond_asynch_rxtx); + pthread_cond_destroy(&proc->cond_synch); + pthread_cond_destroy(&proc->cond_eNBs); + + pthread_attr_destroy(&proc->attr_FH); + pthread_attr_destroy(&proc->attr_prach); + pthread_attr_destroy(&proc->attr_synch); + pthread_attr_destroy(&proc->attr_asynch_rxtx); + pthread_attr_destroy(&proc->attr_fep); + +#ifdef Rel14 + pthread_mutex_destroy(&proc->mutex_prach_br); + pthread_cond_destroy(&proc->cond_prach_br); + pthread_attr_destroy(&proc->attr_prach_br); +#endif +} int check_capabilities(RU_t *ru,RRU_capabilities_t *cap) { @@ -2062,9 +2168,10 @@ void init_RU(char *rf_config_file) { -void stop_ru(RU_t *ru) { - - printf("Stopping RU %p processing threads\n",(void*)ru); - +void stop_RU(int nb_ru) +{ + for (int inst = 0; inst < nb_ru; inst++) { + LOG_I(PHY, "Stopping RU %d processing threads\n", inst); + kill_RU_proc(inst); + } } - diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 44512843d7..181150c672 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1501,7 +1501,8 @@ int main( int argc, char **argv ) // cleanup if (UE_flag == 1) { } else { - stop_eNB(1); + stop_eNB(NB_eNB_INST); + stop_RU(NB_RU); } From 8e9d9807aee187dd649d7704242115d3929b62a3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 23 Jan 2018 11:01:35 +0100 Subject: [PATCH 189/284] lte-ru.c: fct for interface -dependant config, export more functions - add set_function_spec_param() which configures RU_t instance depending on its function(al split) - export more functions like kill_RU_proc() so that they can be reused by restart functionality --- targets/RT/USER/lte-ru.c | 292 ++++++++++++++++---------------- targets/RT/USER/lte-softmodem.h | 4 + 2 files changed, 152 insertions(+), 144 deletions(-) diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 3ff4c4e7ac..e2918091e9 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -1959,13 +1959,159 @@ void init_precoding_weights(PHY_VARS_eNB *eNB) { } } +void set_function_spec_param(RU_t *ru) +{ + int ret; + + switch (ru->if_south) { + case LOCAL_RF: // this is an RU with integrated RF (RRU, eNB) + if (ru->function == NGFI_RRU_IF5) { // IF5 RRU + ru->do_prach = 0; // no prach processing in RU + ru->fh_north_in = NULL; // no shynchronous incoming fronthaul from north + ru->fh_north_out = fh_if5_north_out; // need only to do send_IF5 reception + ru->fh_south_out = tx_rf; // send output to RF + ru->fh_north_asynch_in = fh_if5_north_asynch_in; // TX packets come asynchronously + ru->feprx = NULL; // nothing (this is a time-domain signal) + ru->feptx_ofdm = NULL; // nothing (this is a time-domain signal) + ru->feptx_prec = NULL; // nothing (this is a time-domain signal) + ru->start_if = start_if; // need to start the if interface for if5 + ru->ifdevice.host_type = RRU_HOST; + ru->rfdevice.host_type = RRU_HOST; + ru->ifdevice.eth_params = &ru->eth_params; + reset_meas(&ru->rx_fhaul); + reset_meas(&ru->tx_fhaul); + reset_meas(&ru->compression); + reset_meas(&ru->transport); + + ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); + printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + } + else if (ru->function == NGFI_RRU_IF4p5) { + ru->do_prach = 1; // do part of prach processing in RU + ru->fh_north_in = NULL; // no synchronous incoming fronthaul from north + ru->fh_north_out = fh_if4p5_north_out; // send_IF4p5 on reception + ru->fh_south_out = tx_rf; // send output to RF + ru->fh_north_asynch_in = fh_if4p5_north_asynch_in; // TX packets come asynchronously + ru->feprx = (get_nprocs()<=2) ? fep_full :ru_fep_full_2thread; // RX DFTs + ru->feptx_ofdm = (get_nprocs()<=2) ? feptx_ofdm : feptx_ofdm_2thread; // this is fep with idft only (no precoding in RRU) + ru->feptx_prec = NULL; + ru->start_if = start_if; // need to start the if interface for if4p5 + ru->ifdevice.host_type = RRU_HOST; + ru->rfdevice.host_type = RRU_HOST; + ru->ifdevice.eth_params = &ru->eth_params; + reset_meas(&ru->rx_fhaul); + reset_meas(&ru->tx_fhaul); + reset_meas(&ru->compression); + reset_meas(&ru->transport); + + ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); + printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + malloc_IF4p5_buffer(ru); + } + else if (ru->function == eNodeB_3GPP) { + ru->do_prach = 0; // no prach processing in RU + ru->feprx = (get_nprocs()<=2) ? fep_full : ru_fep_full_2thread; // RX DFTs + ru->feptx_ofdm = (get_nprocs()<=2) ? feptx_ofdm : feptx_ofdm_2thread; // this is fep with idft and precoding + ru->feptx_prec = feptx_prec; // this is fep with idft and precoding + ru->fh_north_in = NULL; // no incoming fronthaul from north + ru->fh_north_out = NULL; // no outgoing fronthaul to north + ru->start_if = NULL; // no if interface + ru->rfdevice.host_type = RAU_HOST; + } + ru->fh_south_in = rx_rf; // local synchronous RF RX + ru->fh_south_out = tx_rf; // local synchronous RF TX + ru->start_rf = start_rf; // need to start the local RF interface + printf("configuring ru_id %d (start_rf %p)\n", ru->idx, start_rf); +/* + if (ru->function == eNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise + fill_rf_config(ru,rf_config_file); + init_frame_parms(&ru->frame_parms,1); + phy_init_RU(ru); + } + + ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + if (setup_RU_buffers(ru)!=0) { + printf("Exiting, cannot initialize RU Buffers\n"); + exit(-1); + }*/ + break; + + case REMOTE_IF5: // the remote unit is IF5 RRU + ru->do_prach = 0; + ru->feprx = (get_nprocs()<=2) ? fep_full : fep_full; // this is frequency-shift + DFTs + ru->feptx_prec = feptx_prec; // need to do transmit Precoding + IDFTs + ru->feptx_ofdm = (get_nprocs()<=2) ? feptx_ofdm : feptx_ofdm_2thread; // need to do transmit Precoding + IDFTs + if (ru->if_timing == synch_to_other) { + ru->fh_south_in = fh_slave_south_in; // synchronize to master + ru->fh_south_out = fh_if5_mobipass_south_out; // use send_IF5 for mobipass + ru->fh_south_asynch_in = fh_if5_south_asynch_in_mobipass; // UL is asynchronous + } + else { + ru->fh_south_in = fh_if5_south_in; // synchronous IF5 reception + ru->fh_south_out = fh_if5_south_out; // synchronous IF5 transmission + ru->fh_south_asynch_in = NULL; // no asynchronous UL + } + ru->start_rf = NULL; // no local RF + ru->start_if = start_if; // need to start if interface for IF5 + ru->ifdevice.host_type = RAU_HOST; + ru->ifdevice.eth_params = &ru->eth_params; + ru->ifdevice.configure_rru = configure_ru; + + ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); + printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + break; + + case REMOTE_IF4p5: + ru->do_prach = 0; + ru->feprx = NULL; // DFTs + ru->feptx_prec = feptx_prec; // Precoding operation + ru->feptx_ofdm = NULL; // no OFDM mod + ru->fh_south_in = fh_if4p5_south_in; // synchronous IF4p5 reception + ru->fh_south_out = fh_if4p5_south_out; // synchronous IF4p5 transmission + ru->fh_south_asynch_in = (ru->if_timing == synch_to_other) ? fh_if4p5_south_in : NULL; // asynchronous UL if synch_to_other + ru->fh_north_out = NULL; + ru->fh_north_asynch_in = NULL; + ru->start_rf = NULL; // no local RF + ru->start_if = start_if; // need to start if interface for IF4p5 + ru->ifdevice.host_type = RAU_HOST; + ru->ifdevice.eth_params = &ru->eth_params; + ru->ifdevice.configure_rru = configure_ru; + + ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params); + printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + + malloc_IF4p5_buffer(ru); + + break; + + default: + LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south); + break; + } // switch on interface type +} + extern void RCconfig_RU(void); void init_RU(char *rf_config_file) { int ru_id; RU_t *ru; - int ret; PHY_VARS_eNB *eNB0; int i; int CC_id; @@ -2008,149 +2154,7 @@ void init_RU(char *rf_config_file) { } // LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n",ru_id,ru_if_types[ru->if_south],eNB_timing[ru->if_timing],ru->function); - - switch (ru->if_south) { - case LOCAL_RF: // this is an RU with integrated RF (RRU, eNB) - if (ru->function == NGFI_RRU_IF5) { // IF5 RRU - ru->do_prach = 0; // no prach processing in RU - ru->fh_north_in = NULL; // no shynchronous incoming fronthaul from north - ru->fh_north_out = fh_if5_north_out; // need only to do send_IF5 reception - ru->fh_south_out = tx_rf; // send output to RF - ru->fh_north_asynch_in = fh_if5_north_asynch_in; // TX packets come asynchronously - ru->feprx = NULL; // nothing (this is a time-domain signal) - ru->feptx_ofdm = NULL; // nothing (this is a time-domain signal) - ru->feptx_prec = NULL; // nothing (this is a time-domain signal) - ru->start_if = start_if; // need to start the if interface for if5 - ru->ifdevice.host_type = RRU_HOST; - ru->rfdevice.host_type = RRU_HOST; - ru->ifdevice.eth_params = &ru->eth_params; - reset_meas(&ru->rx_fhaul); - reset_meas(&ru->tx_fhaul); - reset_meas(&ru->compression); - reset_meas(&ru->transport); - - ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); - printf("openair0_transport_init returns %d for ru_id %d\n",ret,ru_id); - if (ret<0) { - printf("Exiting, cannot initialize transport protocol\n"); - exit(-1); - } - } - else if (ru->function == NGFI_RRU_IF4p5) { - ru->do_prach = 1; // do part of prach processing in RU - ru->fh_north_in = NULL; // no synchronous incoming fronthaul from north - ru->fh_north_out = fh_if4p5_north_out; // send_IF4p5 on reception - ru->fh_south_out = tx_rf; // send output to RF - ru->fh_north_asynch_in = fh_if4p5_north_asynch_in; // TX packets come asynchronously - ru->feprx = (get_nprocs()<=2) ? fep_full :ru_fep_full_2thread; // RX DFTs - ru->feptx_ofdm = (get_nprocs()<=2) ? feptx_ofdm : feptx_ofdm_2thread; // this is fep with idft only (no precoding in RRU) - ru->feptx_prec = NULL; - ru->start_if = start_if; // need to start the if interface for if4p5 - ru->ifdevice.host_type = RRU_HOST; - ru->rfdevice.host_type = RRU_HOST; - ru->ifdevice.eth_params = &ru->eth_params; - reset_meas(&ru->rx_fhaul); - reset_meas(&ru->tx_fhaul); - reset_meas(&ru->compression); - reset_meas(&ru->transport); - - ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); - printf("openair0_transport_init returns %d for ru_id %d\n",ret,ru_id); - if (ret<0) { - printf("Exiting, cannot initialize transport protocol\n"); - exit(-1); - } - malloc_IF4p5_buffer(ru); - } - else if (ru->function == eNodeB_3GPP) { - ru->do_prach = 0; // no prach processing in RU - ru->feprx = (get_nprocs()<=2) ? fep_full : ru_fep_full_2thread; // RX DFTs - ru->feptx_ofdm = (get_nprocs()<=2) ? feptx_ofdm : feptx_ofdm_2thread; // this is fep with idft and precoding - ru->feptx_prec = feptx_prec; // this is fep with idft and precoding - ru->fh_north_in = NULL; // no incoming fronthaul from north - ru->fh_north_out = NULL; // no outgoing fronthaul to north - ru->start_if = NULL; // no if interface - ru->rfdevice.host_type = RAU_HOST; - } - ru->fh_south_in = rx_rf; // local synchronous RF RX - ru->fh_south_out = tx_rf; // local synchronous RF TX - ru->start_rf = start_rf; // need to start the local RF interface - printf("configuring ru_id %d (start_rf %p)\n",ru_id,start_rf); -/* - if (ru->function == eNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise - fill_rf_config(ru,rf_config_file); - init_frame_parms(&ru->frame_parms,1); - phy_init_RU(ru); - } - - ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); - if (setup_RU_buffers(ru)!=0) { - printf("Exiting, cannot initialize RU Buffers\n"); - exit(-1); - }*/ - break; - - case REMOTE_IF5: // the remote unit is IF5 RRU - ru->do_prach = 0; - ru->feprx = (get_nprocs()<=2) ? fep_full : fep_full; // this is frequency-shift + DFTs - ru->feptx_prec = feptx_prec; // need to do transmit Precoding + IDFTs - ru->feptx_ofdm = (get_nprocs()<=2) ? feptx_ofdm : feptx_ofdm_2thread; // need to do transmit Precoding + IDFTs - if (ru->if_timing == synch_to_other) { - ru->fh_south_in = fh_slave_south_in; // synchronize to master - ru->fh_south_out = fh_if5_mobipass_south_out; // use send_IF5 for mobipass - ru->fh_south_asynch_in = fh_if5_south_asynch_in_mobipass; // UL is asynchronous - } - else { - ru->fh_south_in = fh_if5_south_in; // synchronous IF5 reception - ru->fh_south_out = fh_if5_south_out; // synchronous IF5 transmission - ru->fh_south_asynch_in = NULL; // no asynchronous UL - } - ru->start_rf = NULL; // no local RF - ru->start_if = start_if; // need to start if interface for IF5 - ru->ifdevice.host_type = RAU_HOST; - ru->ifdevice.eth_params = &ru->eth_params; - ru->ifdevice.configure_rru = configure_ru; - - ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); - printf("openair0_transport_init returns %d for ru_id %d\n",ret,ru_id); - if (ret<0) { - printf("Exiting, cannot initialize transport protocol\n"); - exit(-1); - } - break; - - case REMOTE_IF4p5: - ru->do_prach = 0; - ru->feprx = NULL; // DFTs - ru->feptx_prec = feptx_prec; // Precoding operation - ru->feptx_ofdm = NULL; // no OFDM mod - ru->fh_south_in = fh_if4p5_south_in; // synchronous IF4p5 reception - ru->fh_south_out = fh_if4p5_south_out; // synchronous IF4p5 transmission - ru->fh_south_asynch_in = (ru->if_timing == synch_to_other) ? fh_if4p5_south_in : NULL; // asynchronous UL if synch_to_other - ru->fh_north_out = NULL; - ru->fh_north_asynch_in = NULL; - ru->start_rf = NULL; // no local RF - ru->start_if = start_if; // need to start if interface for IF4p5 - ru->ifdevice.host_type = RAU_HOST; - ru->ifdevice.eth_params = &ru->eth_params; - ru->ifdevice.configure_rru = configure_ru; - - ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params); - printf("openair0_transport_init returns %d for ru_id %d\n",ret,ru_id); - if (ret<0) { - printf("Exiting, cannot initialize transport protocol\n"); - exit(-1); - } - - malloc_IF4p5_buffer(ru); - - break; - - default: - LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south); - break; - } // switch on interface type - + set_function_spec_param(ru); LOG_I(PHY,"Starting ru_thread %d\n",ru_id); init_RU_proc(ru); diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index 13e5ba6b91..c1d63eef4c 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -244,6 +244,10 @@ extern void kill_eNB_proc(int inst); // In lte-ru.c extern void init_RU(const char*); +extern void init_RU_proc(RU_t *ru); +extern void stop_RU(int nb_ru); +extern void kill_RU_proc(int inst); +extern void set_function_spec_param(RU_t *ru); // In lte-ue.c extern int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg); From 811ada242989071dac9fb83796cdaf44b949243c Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 23 Jan 2018 12:01:24 +0100 Subject: [PATCH 190/284] soft-restart (i.e. only layers PHY-RRC) the lte-softmodem --- .../ENB_APP/flexran_agent_common_internal.c | 65 +++++------ targets/RT/USER/lte-softmodem.c | 110 +++++++++--------- targets/RT/USER/lte-softmodem.h | 4 +- 3 files changed, 83 insertions(+), 96 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c index e3fac4594b..416f13f241 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.c +++ b/openair2/ENB_APP/flexran_agent_common_internal.c @@ -32,45 +32,37 @@ #include "flexran_agent_common_internal.h" #include "flexran_agent_mac_internal.h" -/* the following is needed to soft-restart the lte-softmodem */ +/* needed to soft-restart the lte-softmodem */ #include "targets/RT/USER/lte-softmodem.h" -#include "assertions.h" -#include "enb_app.h" -#if 0 void handle_reconfiguration(mid_t mod_id) { - /* NOTE: this function might be extended by using stop_modem() - * to halt the modem so that it can later be resumed */ - int do_restart = 0; + struct timespec start, end; + clock_gettime(CLOCK_MONOTONIC, &start); - pthread_mutex_lock(&mutex_node_ctrl); - if (ENB_NORMAL_OPERATION != node_control_state) { - node_control_state = ENB_NORMAL_OPERATION; - pthread_cond_broadcast(&cond_node_ctrl); + if (stop_L1L2(mod_id) < 0) { + LOG_E(ENB_APP, "can not stop lte-softmodem, aborting restart\n"); + return; + } + + /* TODO wait state could be here IF IT IS NOT EXECUTED BY THE FLEXRAN THREAD */ + + if (restart_L1L2(mod_id) < 0) { + LOG_F(ENB_APP, "can not restart, killing lte-softmodem\n"); + itti_terminate_tasks(TASK_PHY_ENB); + return; + } + + clock_gettime(CLOCK_MONOTONIC, &end); + end.tv_sec -= start.tv_sec; + if (end.tv_nsec >= start.tv_nsec) { + end.tv_nsec -= start.tv_nsec; } else { - do_restart = 1; - } - pthread_mutex_unlock(&mutex_node_ctrl); - - if (do_restart) { - clock_t start_ms = 1000 * clock(); - /* operator || enforces sequence points */ - if (stop_L1L2(mod_id) < 0 || restart_L1L2(mod_id) < 0) { - LOG_E(ENB_APP, "could not restart, killing lte-softmodem\n"); - /* shutdown the whole lte-softmodem */ - itti_terminate_tasks(TASK_PHY_ENB); - return; - } - enb_app_start_phy_rrc(mod_id, mod_id+1); - MessageDef *msg_p = itti_alloc_new_message(TASK_ENB_APP, INITIALIZE_MESSAGE); - itti_send_msg_to_task(TASK_L2L1, INSTANCE_DEFAULT, msg_p); - - int diff_ms = (1000 * clock() - start_ms) / CLOCKS_PER_SEC; - LOG_I(ENB_APP, "lte-softmodem restart succeeded in %d ms\n", diff_ms); + end.tv_sec -= 1; + end.tv_nsec = end.tv_nsec - start.tv_nsec + 1000000000; } + LOG_I(ENB_APP, "lte-softmodem restart succeeded in %ld.%ld s\n", end.tv_sec, end.tv_nsec / 1000000); } -#endif int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy_length) { @@ -111,8 +103,7 @@ int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy if (parse_enb_id(mod_id, &parser) == -1) { goto error; } else { // succeful parse and setting - /* TODO implement */ - //handle_reconfiguration(mod_id); + handle_reconfiguration(mod_id); } } else if (strcmp((char *) event.data.scalar.value, "mac") == 0) { LOG_D(ENB_APP, "This is intended for the mac system\n"); @@ -265,9 +256,9 @@ int parse_enb_config_parameters(mid_t mod_id, yaml_parser_t *parser) { } else if (strcmp((char *) event.data.scalar.value, "ul_freq_offset") == 0) { if (!yaml_parser_parse(parser, &event)) goto error; - flexran_agent_set_operating_ul_freq(mod_id, - 0, - strtol((char *) event.data.scalar.value, &endptr, 10)); + flexran_agent_set_operating_ul_freq(mod_id, + 0, + strtol((char *) event.data.scalar.value, &endptr, 10)); LOG_I(ENB_APP, "Setting ul_freq_offset to %s\n", event.data.scalar.value); } else if (strcmp((char *) event.data.scalar.value, "bandwidth") == 0) { if (!yaml_parser_parse(parser, &event)) @@ -296,8 +287,6 @@ int parse_enb_config_parameters(mid_t mod_id, yaml_parser_t *parser) { yaml_event_delete(&event); } - /* TODO: reflect in RAN API */ - return 0; error: diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 181150c672..c8db435d46 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -872,11 +872,11 @@ void wait_eNBs(void) { printf("eNB L1 are configured\n"); } -#if defined(ENABLE_ITTI) && defined(FLEXRAN_AGENT_SB_IF) +#if defined(ENABLE_ITTI) /* * helper function to terminate a certain ITTI task */ -void terminate_task(task_id_t task_id, mid_t mod_id) +void terminate_task(task_id_t task_id, module_id_t mod_id) { LOG_I(ENB_APP, "sending TERMINATE_MESSAGE to task %s (%d)\n", itti_get_task_name(task_id), task_id); MessageDef *msg; @@ -884,70 +884,71 @@ void terminate_task(task_id_t task_id, mid_t mod_id) itti_send_msg_to_task (task_id, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg); } -#if 0 -int stop_L1L2(int enb_id) +int stop_L1L2(module_id_t enb_id) { - int CC_id; - LOG_W(ENB_APP, "stopping lte-softmodem\n"); oai_exit = 1; - /* stop trx devices */ - for(CC_id=0; CC_idrfdevice.trx_stop_func) { - LOG_I(ENB_APP, "stopping PHY_vars_eNB_g[0][%d]->rfdevice (via trx_stop_func())\n", CC_id); - PHY_vars_eNB_g[0][CC_id]->rfdevice.trx_stop_func(&PHY_vars_eNB_g[0][CC_id]->rfdevice); + if (!RC.ru) { + LOG_F(ENB_APP, "no RU configured\n"); + return -1; + } + + /* stop trx devices, multiple carrier currently not supported by RU */ + if (RC.ru[enb_id]) { + if (RC.ru[enb_id]->rfdevice.trx_stop_func) { + RC.ru[enb_id]->rfdevice.trx_stop_func(&RC.ru[enb_id]->rfdevice); + LOG_I(ENB_APP, "turned off RU rfdevice\n"); + } else { + LOG_W(ENB_APP, "can not turn off rfdevice due to missing trx_stop_func callback, proceding anyway!\n"); } - if (PHY_vars_eNB_g[0][CC_id]->ifdevice.trx_stop_func) { - LOG_I(ENB_APP, "stopping PHY_vars_eNB_g[0][%d]->ifdevice (via trx_stop_func())\n", CC_id); - PHY_vars_eNB_g[0][CC_id]->ifdevice.trx_stop_func(&PHY_vars_eNB_g[0][CC_id]->ifdevice); + if (RC.ru[enb_id]->ifdevice.trx_stop_func) { + RC.ru[enb_id]->ifdevice.trx_stop_func(&RC.ru[enb_id]->ifdevice); + LOG_I(ENB_APP, "turned off RU ifdevice\n"); + } else { + LOG_W(ENB_APP, "can not turn off ifdevice due to missing trx_stop_func callback, proceding anyway!\n"); } + } else { + LOG_W(ENB_APP, "no RU found for index %d\n", enb_id); + return -1; } /* these tasks need to pick up new configuration */ terminate_task(TASK_RRC_ENB, enb_id); terminate_task(TASK_L2L1, enb_id); - LOG_W(ENB_APP, "calling kill_eNB_proc() for instance %d\n", enb_id); + LOG_I(ENB_APP, "calling kill_eNB_proc() for instance %d\n", enb_id); kill_eNB_proc(enb_id); + LOG_I(ENB_APP, "calling kill_RU_proc() for instance %d\n", enb_id); + kill_RU_proc(enb_id); oai_exit = 0; return 0; } /* - * Restart the lte-softmodem. - * This function checks whether we are in ENB_NORMAL_OPERATION (defined by - * FlexRAN). If yes, first stop L1/L2/L3, then resume. + * Restart the lte-softmodem after it has been soft-stopped with stop_L1L2() */ -int restart_L1L2(int enb_id) +int restart_L1L2(module_id_t enb_id) { - int i, aa, CC_id; - /* needed for fill_PHY_vars_eNB_g(), defined locally in main(); - * abstraction flag is needed too, but defined both globally and in main () */ - uint8_t beta_ACK = 0, beta_RI = 0, beta_CQI = 2; - /* needed for macphy_init() */ - int eMBMS_active = 0; + RU_t *ru = RC.ru[enb_id]; + int cc_id; + MessageDef *msg_p = NULL; LOG_W(ENB_APP, "restarting lte-softmodem\n"); /* block threads */ sync_var = -1; - reconfigure_enb_params(enb_id); /* set frame parameters from configuration */ - - /* PHY_vars_eNB_g will be filled by init_lte_eNB(), so free and - * let the data structure be filled again */ - for (CC_id=0; CC_idconfigured = 0; } - dump_frame_parms(frame_parms[0]); - init_openair0(); - /* give MAC interface current cell information, the rest is the same. - * For more info, check l2_init(). Then, initialize it (cf. line 1904). */ - mac_xface->frame_parms = frame_parms[0]; - mac_xface->macphy_init(eMBMS_active,(uecap_xer_in==1)?uecap_xer:NULL,0,0); + /* TODO undo malloc_IF4p5_buffer() */ + RC.ru_mask |= (1 << ru->idx); + /* copy the changed frame parameters to the RU */ + /* TODO this should be done for all RUs associated to this eNB */ + memcpy(&ru->frame_parms, &RC.eNB[enb_id][0]->frame_parms, sizeof(LTE_DL_FRAME_PARMS)); + set_function_spec_param(RC.ru[enb_id]); LOG_I(ENB_APP, "attempting to create ITTI tasks\n"); if (itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL) < 0) { @@ -963,28 +964,26 @@ int restart_L1L2(int enb_id) LOG_I(PDCP, "Re-created task for L2L1 successfully\n"); } + /* pass a reconfiguration request which will configure everything down to + * RC.eNB[i][j]->frame_parms, too */ + msg_p = itti_alloc_new_message(TASK_ENB_APP, RRC_CONFIGURATION_REQ); + RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[enb_id]->configuration; + itti_send_msg_to_task(TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); + /* TODO XForms here */ - printf("Initializing eNB threads\n"); - init_eNB(node_function, node_timing, 1, eth_params, single_thread_flag, wait_for_sync); - for(CC_id=0; CC_idrf_map.card=0; - PHY_vars_eNB_g[0][CC_id]->rf_map.chain=CC_id+chain_offset; - } + /* TODO check for memory leaks */ + /* TODO wait_eNBs() would wait for phy_config_request()? */ + //init_eNB(single_thread_flag,wait_for_sync); + wait_eNBs(); + init_RU_proc(ru); + ru->rf_map.card = 0; + ru->rf_map.chain = 0; /* CC_id + chain_offset;*/ + wait_RUs(); + init_eNB_afterRU(); - mlockall(MCL_CURRENT | MCL_FUTURE); - - printf("Setting eNB buffer to all-RX\n"); - // Set LSBs for antenna switch (ExpressMIMO) - for (CC_id=0; CC_idhw_timing_advance = 0; - for (i=0; isamples_per_tti*10; i++) - for (aa=0; aanb_antennas_tx; aa++) - PHY_vars_eNB_g[0][CC_id]->common_vars.txdata[0][aa][i] = 0x00010001; - } printf("Sending sync to all threads\n"); - pthread_mutex_lock(&sync_mutex); sync_var=0; pthread_cond_broadcast(&sync_cond); @@ -993,7 +992,6 @@ int restart_L1L2(int enb_id) return 0; } #endif -#endif int main( int argc, char **argv ) { diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index c1d63eef4c..c6f8d8d54c 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -268,8 +268,8 @@ PHY_VARS_UE* init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms, uint8_t abstraction_flag); void init_eNB_afterRU(void); -extern int stop_L1L2(int enb_id); -extern int restart_L1L2(int enb_id); +extern int stop_L1L2(module_id_t enb_id); +extern int restart_L1L2(module_id_t enb_id); #ifdef FLEXRAN_AGENT_SB_IF #include "flexran_agent.h" // for locking From 3f043c7d73b62e4147267a32fb5927776753f55f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 23 Jan 2018 15:20:15 +0100 Subject: [PATCH 191/284] FlexRAN: implement possibilty to await a configuration Through configuration, the lte-softmodem can be halted to await a reconfiguration from the lte-softmodem. A mutex and condition variable are used to implement this. Furthermore, the dependance of lte-softmodem.c on FlexRAN has been reduced to one include and the flexran_agent_start() call. --- openair2/ENB_APP/enb_config.c | 2 +- openair2/ENB_APP/flexran_agent.c | 45 ++++++++++++++----- openair2/ENB_APP/flexran_agent.h | 6 +-- .../ENB_APP/flexran_agent_common_internal.c | 21 ++++++++- openair2/ENB_APP/flexran_agent_defs.h | 12 ++++- targets/RT/USER/lte-softmodem.c | 33 +++----------- targets/RT/USER/lte-softmodem.h | 5 +-- 7 files changed, 74 insertions(+), 50 deletions(-) diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index d2a35c3bd7..2056bfaa27 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -267,7 +267,7 @@ void RCconfig_flexran() RC.flexran[i]->remote_port = *(flexranParams[FLEXRAN_PORT_IDX].uptr); // DEFAULT_FLEXRAN_AGENT_CACHE RC.flexran[i]->cache_name = strdup(*(flexranParams[FLEXRAN_CACHE_IDX].strptr)); - RC.flexran[i]->await_reconf = strcmp(*(flexranParams[FLEXRAN_AWAIT_RECONF_IDX].strptr), "yes") == 0; + RC.flexran[i]->node_ctrl_state = strcmp(*(flexranParams[FLEXRAN_AWAIT_RECONF_IDX].strptr), "yes") == 0 ? ENB_WAIT : ENB_NORMAL_OPERATION; RC.flexran[i]->enb_id = i; } diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c index 60239cbbbd..d32f3e660f 100644 --- a/openair2/ENB_APP/flexran_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -180,16 +180,17 @@ pthread_t new_thread(void *(*f)(void *), void *b) { int channel_container_init = 0; int flexran_agent_start(mid_t mod_id) { + flexran_agent_info_t *flexran = RC.flexran[mod_id]; int channel_id; - char *in_ip = RC.flexran[mod_id]->remote_ipv4_addr; - uint16_t in_port = RC.flexran[mod_id]->remote_port; + char *in_ip = flexran->remote_ipv4_addr; + uint16_t in_port = flexran->remote_port; - RC.flexran[mod_id]->enb_id = mod_id; + flexran->enb_id = mod_id; /* assume for the moment the monolithic case, i.e. agent can provide * information for all layers */ - RC.flexran[mod_id]->capability_mask = FLEXRAN_CAP_LOL1 | FLEXRAN_CAP_HIL1 - | FLEXRAN_CAP_LOL2 | FLEXRAN_CAP_HIL2 - | FLEXRAN_CAP_PDCP | FLEXRAN_CAP_RRC; + flexran->capability_mask = FLEXRAN_CAP_LOL1 | FLEXRAN_CAP_HIL1 + | FLEXRAN_CAP_LOL2 | FLEXRAN_CAP_HIL2 + | FLEXRAN_CAP_PDCP | FLEXRAN_CAP_RRC; /* * Initialize the channel container @@ -228,7 +229,7 @@ int flexran_agent_start(mid_t mod_id) /*Initialize the continuous stats update mechanism*/ flexran_agent_init_cont_stats_update(mod_id); - new_thread(receive_thread, RC.flexran[mod_id]); + new_thread(receive_thread, flexran); /*Initialize and register the mac xface. Must be modified later *for more flexibility in agent management */ @@ -239,8 +240,8 @@ int flexran_agent_start(mid_t mod_id) AGENT_RRC_xface *rrc_agent_xface = (AGENT_RRC_xface *) malloc(sizeof(AGENT_RRC_xface)); flexran_agent_register_rrc_xface(mod_id, rrc_agent_xface); - AGENT_PDCP_xface *pdcp_agent_xface = (AGENT_PDCP_xface *) malloc(sizeof(AGENT_PDCP_xface)); - flexran_agent_register_pdcp_xface(mod_id, pdcp_agent_xface); + AGENT_PDCP_xface *pdcp_agent_xface = (AGENT_PDCP_xface *) malloc(sizeof(AGENT_PDCP_xface)); + flexran_agent_register_pdcp_xface(mod_id, pdcp_agent_xface); /* * initilize a timer @@ -257,14 +258,34 @@ int flexran_agent_start(mid_t mod_id) * start the enb agent task for tx and interaction with the underlying network function */ if (!agent_task_created) { - if (itti_create_task (TASK_FLEXRAN_AGENT, flexran_agent_task, (void *) RC.flexran[mod_id]) < 0) { + if (itti_create_task (TASK_FLEXRAN_AGENT, flexran_agent_task, flexran) < 0) { LOG_E(FLEXRAN_AGENT, "Create task for FlexRAN Agent failed\n"); return -1; } agent_task_created = 1; } - - LOG_I(FLEXRAN_AGENT,"client ends\n"); + + pthread_mutex_init(&flexran->mutex_node_ctrl, NULL); + pthread_cond_init(&flexran->cond_node_ctrl, NULL); + + if (flexran->node_ctrl_state == ENB_WAIT) { + /* wait three seconds before showing message and waiting "for real". + * This way, the message is (hopefully...) the last one and the user knows + * what is happening. If the controller sends a reconfiguration message in + * the meantime, the softmodem will never wait */ + sleep(3); + LOG_I(ENB_APP, " * eNB %d: Waiting for FlexRAN RTController command *\n", mod_id); + pthread_mutex_lock(&flexran->mutex_node_ctrl); + while (ENB_NORMAL_OPERATION != flexran->node_ctrl_state) + pthread_cond_wait(&flexran->cond_node_ctrl, &flexran->mutex_node_ctrl); + pthread_mutex_unlock(&flexran->mutex_node_ctrl); + + /* reconfigure RRC again, the agent might have changed the configuration */ + MessageDef *msg_p = itti_alloc_new_message(TASK_ENB_APP, RRC_CONFIGURATION_REQ); + RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[mod_id]->configuration; + itti_send_msg_to_task(TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg_p); + } + return 0; error: diff --git a/openair2/ENB_APP/flexran_agent.h b/openair2/ENB_APP/flexran_agent.h index ed9ee444c3..aed8f9eb60 100644 --- a/openair2/ENB_APP/flexran_agent.h +++ b/openair2/ENB_APP/flexran_agent.h @@ -42,12 +42,8 @@ #include "log.h" #include "assertions.h" -#include "enb_config.h" // for enb properties - - -/* Initiation and termination of the eNodeB agent */ +/* Initiation of the eNodeB agent */ int flexran_agent_start(mid_t mod_id); -int flexran_agent_stop(mid_t mod_id); /* * enb agent task mainly wakes up the tx thread for periodic and oneshot messages to the controller diff --git a/openair2/ENB_APP/flexran_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c index 416f13f241..0e65fe7236 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.c +++ b/openair2/ENB_APP/flexran_agent_common_internal.c @@ -39,13 +39,32 @@ void handle_reconfiguration(mid_t mod_id) { struct timespec start, end; clock_gettime(CLOCK_MONOTONIC, &start); + flexran_agent_info_t *flexran = RC.flexran[mod_id]; + + if (ENB_WAIT == flexran->node_ctrl_state) { + /* this is already waiting, just release */ + pthread_mutex_lock(&flexran->mutex_node_ctrl); + flexran->node_ctrl_state = ENB_NORMAL_OPERATION; + pthread_mutex_unlock(&flexran->mutex_node_ctrl); + pthread_cond_signal(&flexran->cond_node_ctrl); + return; + } if (stop_L1L2(mod_id) < 0) { LOG_E(ENB_APP, "can not stop lte-softmodem, aborting restart\n"); return; } - /* TODO wait state could be here IF IT IS NOT EXECUTED BY THE FLEXRAN THREAD */ + /* node_ctrl_state should have value ENB_MAKE_WAIT only if this method is not + * executed by the FlexRAN thread */ + if (ENB_MAKE_WAIT == flexran->node_ctrl_state) { + LOG_I(ENB_APP, " * eNB %d: Waiting for FlexRAN RTController command *\n", mod_id); + pthread_mutex_lock(&flexran->mutex_node_ctrl); + flexran->node_ctrl_state = ENB_WAIT; + while (ENB_NORMAL_OPERATION != flexran->node_ctrl_state) + pthread_cond_wait(&flexran->cond_node_ctrl, &flexran->mutex_node_ctrl); + pthread_mutex_unlock(&flexran->mutex_node_ctrl); + } if (restart_L1L2(mod_id) < 0) { LOG_F(ENB_APP, "can not restart, killing lte-softmodem\n"); diff --git a/openair2/ENB_APP/flexran_agent_defs.h b/openair2/ENB_APP/flexran_agent_defs.h index dc86a422c4..fd22b01e61 100644 --- a/openair2/ENB_APP/flexran_agent_defs.h +++ b/openair2/ENB_APP/flexran_agent_defs.h @@ -145,17 +145,27 @@ typedef enum { #define FLEXRAN_CAP_PDCP 0x16 #define FLEXRAN_CAP_RRC 0x32 +typedef enum { + ENB_NORMAL_OPERATION = 0x0, + ENB_WAIT = 0x1, + ENB_MAKE_WAIT = 0x2, +} flexran_enb_state_t; + typedef struct { /* general info */ char *interface_name; char *remote_ipv4_addr; uint16_t remote_port; char *cache_name; - uint8_t await_reconf; int enb_id; uint8_t capability_mask; + /* lock for waiting before starting or soft-restart */ + pthread_cond_t cond_node_ctrl; + pthread_mutex_t mutex_node_ctrl; + flexran_enb_state_t node_ctrl_state; + /* stats */ uint32_t total_rx_msg; diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index c8db435d46..91d626c9d3 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1149,26 +1149,6 @@ int main( int argc, char **argv ) for (CC_id=0; CC_idrfdevice.trx_end_func) diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index c6f8d8d54c..dd178c2911 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -272,10 +272,7 @@ extern int stop_L1L2(module_id_t enb_id); extern int restart_L1L2(module_id_t enb_id); #ifdef FLEXRAN_AGENT_SB_IF -#include "flexran_agent.h" // for locking -//volatile ENB_MODULE_STATE node_control_state; -pthread_cond_t cond_node_ctrl; -pthread_mutex_t mutex_node_ctrl; +#include "flexran_agent.h" #endif #endif From d5b8310fb9b49990a5049eb1f75e274bb2ec4759 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 23 Jan 2018 17:13:54 +0100 Subject: [PATCH 192/284] add some logging for RRM command parsing --- openair2/ENB_APP/flexran_agent_common_internal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair2/ENB_APP/flexran_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c index 0e65fe7236..8874a0f648 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.c +++ b/openair2/ENB_APP/flexran_agent_common_internal.c @@ -120,6 +120,7 @@ int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy LOG_I(ENB_APP, "This is intended for the enb system\n"); // Call the enb handler if (parse_enb_id(mod_id, &parser) == -1) { + LOG_E(ENB_APP, "cannot parse data for eNB\n"); goto error; } else { // succeful parse and setting handle_reconfiguration(mod_id); @@ -294,6 +295,7 @@ int parse_enb_config_parameters(mid_t mod_id, yaml_parser_t *parser) { strtol((char *) event.data.scalar.value, &endptr, 10)); LOG_I(ENB_APP, "Setting frame_type to %s\n", event.data.scalar.value); }else { // not supported tag + LOG_E(FLEXRAN_AGENT, "Unsupported tag %s\n", event.data.scalar.value); goto error; } From 2c8dd796e8c4910945a2442c2f47a4c8a9e9f8bb Mon Sep 17 00:00:00 2001 From: shahab SHARIAT BAGHERI Date: Fri, 19 Jan 2018 16:29:50 +0100 Subject: [PATCH 193/284] Scheduler must send FlexRAN stats updates --- openair2/LAYER2/MAC/eNB_scheduler.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 1195e05379..67d8f270db 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -751,6 +751,10 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, schedule_CSI(module_idP, frameP, subframeP); // This schedules DLSCH in subframeP schedule_dlsch(module_idP, frameP, subframeP, mbsfn_status); + +#if defined(FLEXRAN_AGENT_SB_IF) + flexran_agent_send_update_stats(module_idP); +#endif // Allocate CCEs for good after scheduling is done for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) From 4f1c51f38ca4812fd8423ce70f57cda7b97e9d17 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 25 Jan 2018 14:07:45 +0100 Subject: [PATCH 194/284] add phy_free_RU() and phy_free_lte_eNB() this methods free the memory that is allocated by the functions phy_init_RU() and phy_init_lte_eNB() --- openair1/PHY/INIT/defs.h | 7 ++ openair1/PHY/INIT/lte_init.c | 127 +++++++++++++++++++++++++++++++- openair1/PHY/defs.h | 6 ++ targets/RT/USER/lte-enb.c | 2 + targets/RT/USER/lte-ru.c | 3 + targets/RT/USER/lte-softmodem.c | 4 + 6 files changed, 147 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/INIT/defs.h b/openair1/PHY/INIT/defs.h index 744fb3d3ce..e7972335ab 100644 --- a/openair1/PHY/INIT/defs.h +++ b/openair1/PHY/INIT/defs.h @@ -90,6 +90,13 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNb, unsigned char is_secondary_eNb, unsigned char abstraction_flag); +/*! +\brief Free the PHY variables relevant to the LTE implementation (eNB). +\details Only a subset of phy_vars_eNb is freed (those who have been allocated with phy_init_lte_eNB()). +@param[in] phy_vars_eNb Pointer to eNB Variables + */ +void phy_free_lte_eNB(PHY_VARS_eNB *phy_vars_eNb); + /** \brief Configure LTE_DL_FRAME_PARMS with components derived after initial synchronization (MIB decoding + primary/secondary synch). \details The basically allows configuration of \f$N_{\mathrm{RB}}^{\mathrm{DL}}\f$, the cell id \f$N_{\mathrm{ID}}^{\mathrm{cell}}\f$, the normal/extended prefix mode, the frame type (FDD/TDD), \f$N_{\mathrm{cp}}\f$, the number of TX antennas at eNB (\f$p\f$) and the number of PHICH groups, \f$N_{\mathrm{group}}^{\mathrm{PHICH}}\f$ @param lte_frame_parms pointer to LTE parameter structure diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 283667134d..f5db781309 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1777,7 +1777,55 @@ int phy_init_RU(RU_t *ru) { return(0); } - + +void phy_free_RU(RU_t *ru) +{ + int i,j; + int p; + + LOG_I(PHY, "Feeing RU signal buffers (if_south %s) nb_tx %d\n", ru_if_types[ru->if_south], ru->nb_tx); + + if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so free memory for time-domain signals + for (i = 0; i < ru->nb_tx; i++) free_and_zero(ru->common.txdata[i]); + for (i = 0; i < ru->nb_rx; i++) free_and_zero(ru->common.rxdata[i]); + free_and_zero(ru->common.txdata); + free_and_zero(ru->common.rxdata); + } // else: IF5 or local RF -> nothing to free() + + if (ru->function != NGFI_RRU_IF5) { // we need to do RX/TX RU processing + for (i = 0; i < ru->nb_rx; i++) free_and_zero(ru->common.rxdata_7_5kHz[i]); + free_and_zero(ru->common.rxdata_7_5kHz); + + // free IFFT input buffers (TX) + for (i = 0; i < ru->nb_tx; i++) free_and_zero(ru->common.txdataF_BF[i]); + free_and_zero(ru->common.txdataF_BF); + + // free FFT output buffers (RX) + for (i = 0; i < ru->nb_rx; i++) free_and_zero(ru->common.rxdataF[i]); + free_and_zero(ru->common.rxdataF); + + for (i = 0; i < ru->nb_rx; i++) { + free_and_zero(ru->prach_rxsigF[i]); +#ifdef Rel14 + for (j = 0; j < 4; j++) free_and_zero(ru->prach_rxsigF_br[j][i]); +#endif + } + for (j = 0; j < 4; j++) free_and_zero(ru->prach_rxsigF_br[j]); + free_and_zero(ru->prach_rxsigF); + /* ru->prach_rxsigF_br is not allocated -> don't free */ + + for (i = 0; i < RC.nb_L1_inst; i++) { + for (p = 0; p < 15; p++) { + if (p < ru->eNB_list[i]->frame_parms.nb_antenna_ports_eNB || p == 5) { + for (j=0; jnb_tx; j++) free_and_zero(ru->beam_weights[i][p][j]); + free_and_zero(ru->beam_weights[i][p]); + } + } + } + } + free_and_zero(ru->common.sync_corr); +} + int phy_init_lte_eNB(PHY_VARS_eNB *eNB, unsigned char is_secondary_eNB, unsigned char abstraction_flag) @@ -1911,7 +1959,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, AssertFatal(fp->N_RB_UL > 5, "fp->N_RB_UL %d < 6\n",fp->N_RB_UL); for (i=0; i<2; i++) { // RK 2 times because of output format of FFT! - // FIXME We should get rid of this + // FIXME We should get rid of this, consider also phy_free_lte_eNB() pusch_vars[UE_id]->rxdataF_ext[i] = (int32_t*)malloc16_clear( 2*sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti ); pusch_vars[UE_id]->rxdataF_ext2[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti ); pusch_vars[UE_id]->drs_ch_estimates[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti ); @@ -1934,3 +1982,78 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, return (0); } + + +void phy_free_lte_eNB(PHY_VARS_eNB *eNB) +{ + LTE_DL_FRAME_PARMS* const fp = &eNB->frame_parms; + LTE_eNB_COMMON* const common_vars = &eNB->common_vars; + LTE_eNB_PUSCH** const pusch_vars = eNB->pusch_vars; + LTE_eNB_SRS* const srs_vars = eNB->srs_vars; + LTE_eNB_PRACH* const prach_vars = &eNB->prach_vars; +#ifdef Rel14 + LTE_eNB_PRACH* const prach_vars_br = &eNB->prach_vars_br; +#endif + int i, UE_id; + + for (i = 0; i < NB_ANTENNA_PORTS_ENB; i++) { + if (i < fp->nb_antenna_ports_eNB || i == 5) { + free_and_zero(common_vars->txdataF[i]); + /* rxdataF[i] is not allocated -> don't free */ + } + } + free_and_zero(common_vars->txdataF); + free_and_zero(common_vars->rxdataF); + + // Channel estimates for SRS + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { + for (i=0; i<64; i++) { + free_and_zero(srs_vars[UE_id].srs_ch_estimates[i]); + free_and_zero(srs_vars[UE_id].srs_ch_estimates_time[i]); + } + free_and_zero(srs_vars[UE_id].srs_ch_estimates); + free_and_zero(srs_vars[UE_id].srs_ch_estimates_time); + } //UE_id + + free_ul_ref_sigs(); + + for (UE_id=0; UE_idprachF); + + for (i = 0; i < 64; i++) free_and_zero(prach_vars->prach_ifft[0][i]); + free_and_zero(prach_vars->prach_ifft[0]); + +#ifdef Rel14 + for (int ce_level = 0; ce_level < 4; ce_level++) { + for (i = 0; i < 64; i++) free_and_zero(prach_vars_br->prach_ifft[ce_level][i]); + free_and_zero(prach_vars_br->prach_ifft[ce_level]); + free_and_zero(prach_vars->rxsigF[ce_level]); + } + free_and_zero(prach_vars_br->prachF); +#endif + free_and_zero(prach_vars->rxsigF[0]); + + for (UE_id=0; UE_idrxdataF_ext[i]); + free_and_zero(pusch_vars[UE_id]->rxdataF_ext2[i]); + free_and_zero(pusch_vars[UE_id]->drs_ch_estimates[i]); + free_and_zero(pusch_vars[UE_id]->drs_ch_estimates_time[i]); + free_and_zero(pusch_vars[UE_id]->rxdataF_comp[i]); + free_and_zero(pusch_vars[UE_id]->ul_ch_mag[i]); + free_and_zero(pusch_vars[UE_id]->ul_ch_magb[i]); + } + free_and_zero(pusch_vars[UE_id]->rxdataF_ext); + free_and_zero(pusch_vars[UE_id]->rxdataF_ext2); + free_and_zero(pusch_vars[UE_id]->drs_ch_estimates); + free_and_zero(pusch_vars[UE_id]->drs_ch_estimates_time); + free_and_zero(pusch_vars[UE_id]->rxdataF_comp); + free_and_zero(pusch_vars[UE_id]->ul_ch_mag); + free_and_zero(pusch_vars[UE_id]->ul_ch_magb); + free_and_zero(pusch_vars[UE_id]->llr); + free_and_zero(pusch_vars[UE_id]); + } //UE_id + + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) eNB->UE_stats_ptr[UE_id] = NULL; +} diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 0e44a7f8bd..b5c2e54fa5 100644 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -79,6 +79,12 @@ #define bigmalloc16 malloc16 #define openair_free(y,x) free((y)) #define PAGE_SIZE 4096 +#define free_and_zero(PtR) do { \ + if (PtR) { \ + free(PtR); \ + PtR = NULL; \ + } \ + } while (0) #define RX_NB_TH_MAX 2 #define RX_NB_TH 2 diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 6b418bb8ff..ece2b75c77 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -974,5 +974,7 @@ void stop_eNB(int nb_inst) { for (int inst=0;inst Date: Fri, 26 Jan 2018 14:49:45 +0100 Subject: [PATCH 195/284] free memory when stopping/restarting lte-softmodem - add function free_td() -> complements init_td() [seems to not be used, added for completeness] - add function free_td8() -> undoes init_td8() [free memory of 8-bit LLR Turbo decoder] - add function free_td16() -> undoes init_td16() [free memory of 16-bit LLR Turbo decoder] - change function free_tdavx216() -> undoes init_tdavx216() [free memory of 16-bit LLR Turbo decoder, AVX2 version] - add free_lte_top() -> frees memory allocated by init_lte_top() - change free_ul_ref_sigs() to set freed pointers to NULL - add method free_transport() -> frees memory of ULSCH/DLSCH transport channels - use the above functions when stopping/restarting the lte-softmodem --- .../CODING/3gpplte_turbo_decoder_avx2_16bit.c | 8 ++++---- .../PHY/CODING/3gpplte_turbo_decoder_sse.c | 12 +++++++++++ .../CODING/3gpplte_turbo_decoder_sse_16bit.c | 8 ++++---- .../CODING/3gpplte_turbo_decoder_sse_8bit.c | 8 ++++---- openair1/PHY/CODING/defs.h | 10 ++++++++++ openair1/PHY/INIT/defs.h | 1 + openair1/PHY/INIT/lte_init.c | 12 +++++++++++ openair1/PHY/LTE_REFSIG/lte_ul_ref.c | 8 ++++++-- openair1/PHY/LTE_TRANSPORT/proto.h | 6 ++++++ targets/RT/USER/lte-enb.c | 20 ++++++++++++++++++- targets/RT/USER/lte-ru.c | 2 -- targets/RT/USER/lte-softmodem.c | 8 +++++++- 12 files changed, 85 insertions(+), 18 deletions(-) diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c index 616eed7446..83a50f214b 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c @@ -830,10 +830,10 @@ void free_td16avx2(void) int ind; for (ind=0; ind<188; ind++) { - free(pi2tab16avx2[ind]); - free(pi5tab16avx2[ind]); - free(pi4tab16avx2[ind]); - free(pi6tab16avx2[ind]); + free_and_zero(pi2tab16avx2[ind]); + free_and_zero(pi5tab16avx2[ind]); + free_and_zero(pi4tab16avx2[ind]); + free_and_zero(pi6tab16avx2[ind]); } } diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse.c index 9ec25367d9..f628bff55b 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse.c @@ -1907,6 +1907,18 @@ void compute_ext(llr_t* alpha,llr_t* beta,llr_t* m_11,llr_t* m_10,llr_t* ext, ll //int pi2[n],pi3[n+8],pi5[n+8],pi4[n+8],pi6[n+8], int *pi2tab[188],*pi5tab[188],*pi4tab[188],*pi6tab[188]; +void free_td() +{ + int ind; + + for (ind = 0; ind < 188; ind++) { + free_and_zero(pi2tab[ind]); + free_and_zero(pi5tab[ind]); + free_and_zero(pi4tab[ind]); + free_and_zero(pi6tab[ind]); + } +} + void init_td() { diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c index cb4a4e1f84..a32edd711d 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c @@ -1117,10 +1117,10 @@ void free_td16(void) int ind; for (ind=0; ind<188; ind++) { - free(pi2tab16[ind]); - free(pi5tab16[ind]); - free(pi4tab16[ind]); - free(pi6tab16[ind]); + free_and_zero(pi2tab16[ind]); + free_and_zero(pi5tab16[ind]); + free_and_zero(pi4tab16[ind]); + free_and_zero(pi6tab16[ind]); } } diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c index d6ef84b218..4754e26f38 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c @@ -838,10 +838,10 @@ void free_td8(void) int ind; for (ind=0; ind<188; ind++) { - free(pi2tab8[ind]); - free(pi5tab8[ind]); - free(pi4tab8[ind]); - free(pi6tab8[ind]); + free_and_zero(pi2tab8[ind]); + free_and_zero(pi5tab8[ind]); + free_and_zero(pi4tab8[ind]); + free_and_zero(pi6tab8[ind]); } } diff --git a/openair1/PHY/CODING/defs.h b/openair1/PHY/CODING/defs.h index 06311a188b..9150e19bf1 100644 --- a/openair1/PHY/CODING/defs.h +++ b/openair1/PHY/CODING/defs.h @@ -356,10 +356,17 @@ void ccodedab_init_inv(void); \brief This function initializes the different crc tables.*/ void crcTableInit (void); +/*!\fn void free_td8(void) +\brief This function frees the tables for 8-bit LLR Turbo decoder.*/ +void free_td8(void); + /*!\fn void init_td8(void) \brief This function initializes the tables for 8-bit LLR Turbo decoder.*/ void init_td8 (void); +/*!\fn void free_td16(void) +\brief This function frees the tables for 16-bit LLR Turbo decoder.*/ +void free_td16(void); /*!\fn void init_td16(void) \brief This function initializes the tables for 16-bit LLR Turbo decoder.*/ @@ -370,6 +377,9 @@ void init_td16 (void); \brief This function initializes the tables for 8-bit LLR Turbo decoder (AVX2).*/ void init_td8avx2 (void); +/*!\fn void free_td16avx2(void) +\brief This function frees the tables for 16-bit LLR Turbo decoder (AVX2).*/ +void free_td16avx2(void); /*!\fn void init_td16(void) \brief This function initializes the tables for 16-bit LLR Turbo decoder (AVX2).*/ diff --git a/openair1/PHY/INIT/defs.h b/openair1/PHY/INIT/defs.h index e7972335ab..55d220824e 100644 --- a/openair1/PHY/INIT/defs.h +++ b/openair1/PHY/INIT/defs.h @@ -324,6 +324,7 @@ void phy_config_dedicated_eNB_step2(PHY_VARS_eNB *phy_vars_eNB); */ int phy_init_secsys_eNB(PHY_VARS_eNB *phy_vars_eNb); +void free_lte_top(void); void init_lte_top(LTE_DL_FRAME_PARMS *lte_frame_parms); diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index f5db781309..86ed62040f 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1247,6 +1247,18 @@ void phy_config_cba_rnti (module_id_t Mod_id,int CC_id,eNB_flag_t eNB_flag, uin } } +void free_lte_top(void) +{ + free_td8(); + free_td16(); +#ifdef __AVX2__ + free_td16avx2(); +#endif + lte_sync_time_free(); + + /* free_ul_ref_sigs() is called in phy_free_lte_eNB() */ +} + void init_lte_top(LTE_DL_FRAME_PARMS *frame_parms) { diff --git a/openair1/PHY/LTE_REFSIG/lte_ul_ref.c b/openair1/PHY/LTE_REFSIG/lte_ul_ref.c index cddb642b2b..cacd0f4292 100644 --- a/openair1/PHY/LTE_REFSIG/lte_ul_ref.c +++ b/openair1/PHY/LTE_REFSIG/lte_ul_ref.c @@ -188,11 +188,15 @@ void free_ul_ref_sigs(void) for (Msc_RS=2; Msc_RS<33; Msc_RS++) { for (u=0; u<30; u++) { for (v=0; v<2; v++) { - if (ul_ref_sigs[u][v][Msc_RS]) + if (ul_ref_sigs[u][v][Msc_RS]) { free16(ul_ref_sigs[u][v][Msc_RS],2*sizeof(int16_t)*dftsizes[Msc_RS]); + ul_ref_sigs_rx[u][v][Msc_RS] = NULL; + } - if (ul_ref_sigs_rx[u][v][Msc_RS]) + if (ul_ref_sigs_rx[u][v][Msc_RS]) { free16(ul_ref_sigs_rx[u][v][Msc_RS],4*sizeof(int16_t)*dftsizes[Msc_RS]); + ul_ref_sigs_rx[u][v][Msc_RS] = NULL; + } } } } diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 8a0e160f23..98a32f68a0 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -83,6 +83,12 @@ void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch); void free_ue_ulsch(LTE_UE_ULSCH_t *ulsch); +/** \fn free_eNB_ulsch(LTE_eNB_DLSCH_t *dlsch) + \brief This function frees memory allocated for a particular ULSCH at eNB + @param ulsch Pointer to ULSCH to be removed +*/ +void free_eNB_ulsch(LTE_eNB_ULSCH_t *ulsch); + LTE_eNB_ULSCH_t *new_eNB_ulsch(uint8_t max_turbo_iterations,uint8_t N_RB_UL, uint8_t abstraction_flag); LTE_UE_ULSCH_t *new_ue_ulsch(unsigned char N_RB_UL, uint8_t abstraction_flag); diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index ece2b75c77..bd9fbab19d 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -794,6 +794,21 @@ void print_opp_meas(void) { } } +void free_transport(PHY_VARS_eNB *eNB) +{ + int i; + int j; + + for (i=0; idlsch[i][j]); + + LOG_I(PHY, "Freeing Transport Channel Buffer for ULSCH, UE %d\n",i); + free_eNB_ulsch(eNB->ulsch[1+i]); + } + free_eNB_ulsch(eNB->ulsch[0]); +} + void init_transport(PHY_VARS_eNB *eNB) { int i; @@ -975,6 +990,9 @@ void stop_eNB(int nb_inst) { LOG_I(PHY,"Killing eNB %d processing threads\n",inst); kill_eNB_proc(inst); /* release memory used by these threads (incomplete) */ - for (int cc_id = 0; cc_id < RC.nb_CC[inst]; cc_id++) phy_free_lte_eNB(RC.eNB[inst][cc_id]); + for (int cc_id = 0; cc_id < RC.nb_CC[inst]; cc_id++) { + free_transport(RC.eNB[inst][cc_id]); + phy_free_lte_eNB(RC.eNB[inst][cc_id]); + } } } diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 6459b6a58d..5a2f49212c 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -1557,8 +1557,6 @@ void *ru_thread_synch(void *arg) { if (release_thread(&ru->proc.mutex_synch,&ru->proc.instance_cnt_synch,"ru_synch_thread") < 0) break; } // oai_exit - lte_sync_time_free(); - ru_thread_synch_status = 0; return &ru_thread_synch_status; diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 6ae35a9bf0..8df540bc49 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -884,6 +884,7 @@ void terminate_task(task_id_t task_id, module_id_t mod_id) itti_send_msg_to_task (task_id, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg); } +extern void free_transport(PHY_VARS_eNB *); extern void phy_free_RU(RU_t*); int stop_L1L2(module_id_t enb_id) @@ -923,8 +924,12 @@ int stop_L1L2(module_id_t enb_id) LOG_I(ENB_APP, "calling kill_RU_proc() for instance %d\n", enb_id); kill_RU_proc(enb_id); oai_exit = 0; - for (int cc_id = 0; cc_id < RC.nb_CC[enb_id]; cc_id++) phy_free_lte_eNB(RC.eNB[enb_id][cc_id]); + for (int cc_id = 0; cc_id < RC.nb_CC[enb_id]; cc_id++) { + free_transport(RC.eNB[enb_id][cc_id]); + phy_free_lte_eNB(RC.eNB[enb_id][cc_id]); + } phy_free_RU(RC.ru[enb_id]); + free_lte_top(); return 0; } @@ -1491,6 +1496,7 @@ int main( int argc, char **argv ) } else { stop_eNB(NB_eNB_INST); stop_RU(NB_RU); + free_lte_top(); } From 6dcac9234cb0d13317f311e1c5633ce76af6010f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 29 Jan 2018 10:25:16 +0100 Subject: [PATCH 196/284] Navid: revise FlexRAN --- openair2/ENB_APP/flexran_agent_common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index 33879714d9..de0de15c0a 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -467,6 +467,7 @@ int flexran_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Fl //Set this according to the current state of the UE. This is only a temporary fix int status = 0; status = mac_eNB_get_rrc_status(mod_id, flexran_get_ue_crnti(mod_id, i)); + /* TODO needs to be revised and appropriate API to be implemented */ if (status < RRC_CONNECTED) { lc_ue_config[i]->n_lc_config = 0; } else if (status == RRC_CONNECTED) { @@ -505,6 +506,7 @@ int flexran_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Fl lc_config[j]->has_qci = 1; lc_config[j]->qci = 1; if (lc_config[j]->direction == PROTOCOL__FLEX_QOS_BEARER_TYPE__FLQBT_GBR) { + /* TODO all of the need to be taken from API */ //TODO: Set the max bitrate (UL) lc_config[j]->has_e_rab_max_bitrate_ul = 0; lc_config[j]->e_rab_max_bitrate_ul = 0; From e669f83dc1789c3dbc75c13a290e70d659cc3a3f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 29 Jan 2018 11:05:04 +0100 Subject: [PATCH 197/284] Navid: revise RAN API --- openair2/ENB_APP/flexran_agent_ran_api.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 75552526a7..2e1878f5e5 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -861,6 +861,7 @@ int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) } } +/* TODO Navid: Get the same for eNB */ long flexran_get_lcg(mid_t ue_id, mid_t lc_id) { if (!UE_mac_inst) return -1; @@ -870,10 +871,9 @@ long flexran_get_lcg(mid_t ue_id, mid_t lc_id) return *(UE_mac_inst[ue_id].logicalChannelConfig[lc_id]->ul_SpecificParameters->logicalChannelGroup); } +/* TODO Navid: needs to be revised */ int flexran_get_direction(mid_t ue_id, mid_t lc_id) { - /* TODO: fill with the value for the rest of LCID -> Robert: What does that - * mean? */ switch (lc_id) { case DCCH: case DCCH1: From dd7d2ef63b4f8b49aabcc921f42cdd8ca6a34cfa Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 29 Jan 2018 11:05:52 +0100 Subject: [PATCH 198/284] Navid: revise RRC --- openair2/RRC/LITE/rrc_eNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 8402d1ba61..9fb1165beb 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -2141,7 +2141,7 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* cons } #if defined(FLEXRAN_AGENT_SB_IF) - +/* TODO Navid: does this belong here? */ //----------------------------------------------------------------------------- void flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* const ctxt_pP, From 6eeb25771727db8bf7368096b19acf97ec857960 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 29 Jan 2018 14:47:52 +0100 Subject: [PATCH 199/284] add UE_Capability to type eNB_RRC_UE_t and read it when received --- openair2/RRC/LITE/defs.h | 2 ++ openair2/RRC/LITE/rrc_eNB.c | 24 +++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index 9a346f7fb7..91e50a16d8 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -395,6 +395,8 @@ typedef struct eNB_RRC_UE_s { MeasConfig_t* measConfig; HANDOVER_INFO* handover_info; MeasResults_t* measResults; + + UE_EUTRA_Capability_t* UE_Capability; #if defined(ENABLE_SECURITY) /* KeNB as derived from KASME received from EPC */ diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 9fb1165beb..bae9138b5f 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -4994,7 +4994,6 @@ rrc_eNB_decode_dcch( asn_dec_rval_t dec_rval; //UL_DCCH_Message_t uldcchmsg; UL_DCCH_Message_t *ul_dcch_msg = NULL; //&uldcchmsg; - UE_EUTRA_Capability_t *UE_EUTRA_Capability = NULL; int i; struct rrc_eNB_ue_context_s* ue_context_p = NULL; @@ -5385,18 +5384,33 @@ rrc_eNB_decode_dcch( xer_fprint(stdout, &asn_DEF_UL_DCCH_Message, (void *)ul_dcch_msg); #endif LOG_I(RRC, "got UE capabilities for UE %x\n", ctxt_pP->rnti); + if (ue_context_p->ue_context.UE_Capability) { + LOG_I(RRC, "freeing old UE capabilities for UE %x\n", ctxt_pP->rnti); + asn_DEF_UE_EUTRA_Capability.free_struct(&asn_DEF_UE_EUTRA_Capability, + ue_context_p->ue_context.UE_Capability, 0); + ue_context_p->ue_context.UE_Capability = 0; + } dec_rval = uper_decode(NULL, &asn_DEF_UE_EUTRA_Capability, - (void **)&UE_EUTRA_Capability, + (void **)&ue_context_p->ue_context.UE_Capability, ul_dcch_msg->message.choice.c1.choice.ueCapabilityInformation.criticalExtensions. choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list. array[0]->ueCapabilityRAT_Container.buf, ul_dcch_msg->message.choice.c1.choice.ueCapabilityInformation.criticalExtensions. choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list. array[0]->ueCapabilityRAT_Container.size, 0, 0); - //#ifdef XER_PRINT - //xer_fprint(stdout, &asn_DEF_UE_EUTRA_Capability, (void *)UE_EUTRA_Capability); - //#endif +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_UE_EUTRA_Capability, ue_context_p->ue_context.UE_Capability); +#endif + + if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { + LOG_E(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Failed to decode UE capabilities (%zu bytes)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + dec_rval.consumed); + asn_DEF_UE_EUTRA_Capability.free_struct(&asn_DEF_UE_EUTRA_Capability, + ue_context_p->ue_context.UE_Capability, 0); + ue_context_p->ue_context.UE_Capability = 0; + } #if defined(ENABLE_USE_MME) From fcddbc2b441ead0d8d026e6c40362348e9d11176 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 29 Jan 2018 14:48:41 +0100 Subject: [PATCH 200/284] RAN API: add functions using UE_Capability - flexran_get_half_duplex() - flexran_get_intra_sf_hopping() - flexran_get_type2_sb_1() - flexran_get_ue_category() - flexran_get_res_alloc_type1() --- openair2/ENB_APP/flexran_agent_ran_api.c | 102 +++++++++++++++-------- openair2/ENB_APP/flexran_agent_ran_api.h | 27 ++---- 2 files changed, 76 insertions(+), 53 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 2e1878f5e5..ddbc3ad869 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -638,55 +638,87 @@ uint64_t flexran_get_ue_aggregated_max_bitrate_ul(mid_t mod_id, mid_t ue_id) return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateUL; } -int flexran_get_half_duplex(mid_t ue_id) +int flexran_get_half_duplex(mid_t mod_id, mid_t ue_id) { -#warning "Implement flexran_get_half_duplex() in RAN API" - // TODO - //int halfduplex = 0; - //int bands_to_scan = ((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.count; - //for (int i =0; i < bands_to_scan; i++){ - //if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.array[i]->halfDuplex > 0) - // halfduplex = 1; - //} - //return halfduplex; + if (!rrc_is_present(mod_id)) return -1; + + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.UE_Capability) return -1; + SupportedBandListEUTRA_t *bands = &ue_context_p->ue_context.UE_Capability->rf_Parameters.supportedBandListEUTRA; + for (int i = 0; i < bands->list.count; i++) { + if (bands->list.array[i]->halfDuplex > 0) return 1; + } return 0; } -int flexran_get_intra_sf_hopping(mid_t ue_id) +int flexran_get_intra_sf_hopping(mid_t mod_id, mid_t ue_id) { -#warning "Implement flexran_get_intra_sf_hopping() in RAN API" - //TODO:Get proper value - //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); - //return (0 & ( 1 << (31))); - return 0; + if (!rrc_is_present(mod_id)) return -1; + + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.UE_Capability) return -1; + if (!ue_context_p->ue_context.UE_Capability->featureGroupIndicators) return -1; + /* According to TS 36.331 Annex B.1, Intra SF Hopping is bit 1 (leftmost bit) + * in this bitmap, i.e. the eighth bit (from right) in the first bye (from + * left) */ + BIT_STRING_t *fgi = ue_context_p->ue_context.UE_Capability->featureGroupIndicators; + uint8_t buf = fgi->buf[0]; + return (buf >> 7) & 1; } -int flexran_get_type2_sb_1(mid_t ue_id) +int flexran_get_type2_sb_1(mid_t mod_id, mid_t ue_id) { -#warning "Implement flexran_get_type2_sb_1() in RAN API" - //TODO:Get proper value - //uint8_t temp = 0; - //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); - //return (temp & ( 1 << (11))); - return 0; + if (!rrc_is_present(mod_id)) return -1; + + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.UE_Capability) return -1; + if (!ue_context_p->ue_context.UE_Capability->featureGroupIndicators) return -1; + /* According to TS 36.331 Annex B.1, Predefined intra- and inter-sf or + * predfined inter-sf frequency hopping for PUSCH with N_sb>1 is bit 21 (bit + * 1 is leftmost bit) in this bitmap, i.e. the fourth bit (from right) in the + * third byte (from left) */ + BIT_STRING_t *fgi = ue_context_p->ue_context.UE_Capability->featureGroupIndicators; + uint8_t buf = fgi->buf[2]; + return (buf >> 3) & 1; } -int flexran_get_ue_category(mid_t ue_id) +long flexran_get_ue_category(mid_t mod_id, mid_t ue_id) { -#warning "Implement flexran_get_ue_category() in RAN API" - //TODO:Get proper value - //return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->ue_Category); - return 0; + if (!rrc_is_present(mod_id)) return -1; + + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.UE_Capability) return -1; + return ue_context_p->ue_context.UE_Capability->ue_Category; } -int flexran_get_res_alloc_type1(mid_t ue_id) +int flexran_get_res_alloc_type1(mid_t mod_id, mid_t ue_id) { -#warning "Implement flexran_get_res_alloc_type1() in RAN API" - //TODO:Get proper value - //uint8_t temp = 0; - //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); - //return (temp & ( 1 << (30))); - return 0; + if (!rrc_is_present(mod_id)) return -1; + + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + if (!ue_context_p->ue_context.UE_Capability) return -1; + if (!ue_context_p->ue_context.UE_Capability->featureGroupIndicators) return -1; + /* According to TS 36.331 Annex B.1, Resource allocation type 1 for PDSCH is + * bit 2 (bit 1 is leftmost bit) in this bitmap, i.e. the seventh bit (from + * right) in the first byte (from left) */ + BIT_STRING_t *fgi = ue_context_p->ue_context.UE_Capability->featureGroupIndicators; + uint8_t buf = fgi->buf[0]; + return (buf >> 6) & 1; } long flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 25faa105a6..62752f1308 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -246,29 +246,20 @@ uint64_t flexran_get_ue_aggregated_max_bitrate_dl(mid_t mod_id, mid_t ue_id); per UE. See TS 36.413 */ uint64_t flexran_get_ue_aggregated_max_bitrate_ul(mid_t mod_id, mid_t ue_id); -/* Only half-duplex support. FDD - operation. Boolean value */ -/* currently broken -int flexran_get_half_duplex(mid_t ue_id); */ +/* Only half-duplex support. FDD operation. Boolean value */ +int flexran_get_half_duplex(mid_t mod_id, mid_t ue_id); -/* Support of intra-subframe hopping. - Boolean value */ -/* currently broken -int flexran_get_intra_sf_hopping(mid_t ue_id); */ +/* Support of intra-subframe hopping. Boolean value */ +int flexran_get_intra_sf_hopping(mid_t mod_id, mid_t ue_id); -/* UE support for type 2 hopping with - n_sb>1 */ -/* currently broken -int flexran_get_type2_sb_1(mid_t ue_id); */ +/* UE support for type 2 hopping with n_sb>1 */ +int flexran_get_type2_sb_1(mid_t mod_id, mid_t ue_id); /* Get the UE category */ -/* currently broken -int flexran_get_ue_category(mid_t ue_id); */ +long flexran_get_ue_category(mid_t mod_id, mid_t ue_id); -/* UE support for resource allocation - type 1 */ -/* currently broken -int flexran_get_res_alloc_type1(mid_t ue_id); */ +/* UE support for resource allocation type 1 */ +int flexran_get_res_alloc_type1(mid_t mod_id, mid_t ue_id); /* Get UE transmission mode */ long flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id); From 4af41d2a265f2fdfbe0ba26bdb37bc4ba7706471 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sat, 3 Feb 2018 07:53:33 -0800 Subject: [PATCH 201/284] more correction of indentation --- openair2/LAYER2/MAC/eNB_scheduler_bch.c | 329 +- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 3376 ++++++++++----------- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 2506 +++++++-------- 3 files changed, 2887 insertions(+), 3324 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_bch.c b/openair2/LAYER2/MAC/eNB_scheduler_bch.c index 9a1046ff26..258ca36c02 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_bch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_bch.c @@ -235,35 +235,28 @@ schedule_SIB1_BR(module_id_t module_idP, memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = TBS; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = - eNB->pdu_index[CC_id]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFF; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = - getRIV(N_RB_DL, first_rb, 6); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 6); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = rvidx; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = - (cc->p_eNB == 1) ? 0 : 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = - 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = - (cc->p_eNB == 1) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB == 1) ? 1 : 2; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; // Rel10 fields @@ -280,10 +273,7 @@ schedule_SIB1_BR(module_id_t module_idP, dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; // Program TX Request - TX_req = - &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB-> - TX_req - [CC_id].tx_request_body.number_of_pdus]; + TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; TX_req->pdu_length = bcch_sdu_length; TX_req->pdu_index = eNB->pdu_index[CC_id]++; TX_req->num_segments = 1; @@ -315,11 +305,8 @@ schedule_SIB1_BR(module_id_t module_idP, } } -int si_WindowLength_BR_r13tab - [SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_spare] -= { 20, 40, 60, 80, 120, 160, 200 }; -int si_TBS_r13tab[SchedulingInfo_BR_r13__si_TBS_r13_b936 + 1] = - { 152, 208, 256, 328, 408, 504, 600, 712, 808, 936 }; +int si_WindowLength_BR_r13tab[SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_spare] = { 20, 40, 60, 80, 120, 160, 200 }; +int si_TBS_r13tab[SchedulingInfo_BR_r13__si_TBS_r13_b936 + 1] = { 152, 208, 256, 328, 408, 504, 600, 712, 808, 936 }; //------------------------------------------------------------------------------ void @@ -354,65 +341,40 @@ schedule_SI_BR(module_id_t module_idP, frame_t frameP, if (cc->mib->message.schedulingInfoSIB1_BR_r13 == 0) continue; else { - - - AssertFatal(cc-> - sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 - != NULL, + AssertFatal(cc->sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 != NULL, "sib_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n"); - SchedulingInfoList_BR_r13_t *schedulingInfoList_BR_r13 = - cc->sib1_v13ext-> - bandwidthReducedAccessRelatedInfo_r13->schedulingInfoList_BR_r13; + SchedulingInfoList_BR_r13_t *schedulingInfoList_BR_r13 = cc->sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->schedulingInfoList_BR_r13; AssertFatal(schedulingInfoList_BR_r13 != NULL, "sib_v13ext->schedulingInfoList_BR_r13 is null\n"); - SchedulingInfoList_t *schedulingInfoList = - cc->schedulingInfoList; - AssertFatal(schedulingInfoList_BR_r13->list.count == - schedulingInfoList->list.count, + SchedulingInfoList_t *schedulingInfoList = cc->schedulingInfoList; + AssertFatal(schedulingInfoList_BR_r13->list.count == schedulingInfoList->list.count, "schedulingInfolist_BR.r13->list.count %d != schedulingInfoList.list.count %d\n", schedulingInfoList_BR_r13->list.count, schedulingInfoList->list.count); - AssertFatal(cc-> - sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13 - <= - SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_ms200, + AssertFatal(cc->sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13<=SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_ms200, "si_WindowLength_BR_r13 %d > %d\n", - (int) cc-> - sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13, + (int) cc->sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13, SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_WindowLength_BR_r13_ms200); // check that SI frequency-hopping is disabled - AssertFatal(cc-> - sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_HoppingConfigCommon_r13 - == - SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_HoppingConfigCommon_r13_off, + AssertFatal(cc->sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_HoppingConfigCommon_r13 == SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_HoppingConfigCommon_r13_off, "Deactivate SI_HoppingConfigCommon_r13 in configuration file, not supported for now\n"); - long si_WindowLength_BR_r13 = - si_WindowLength_BR_r13tab[cc-> - sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13]; + long si_WindowLength_BR_r13 = si_WindowLength_BR_r13tab[cc->sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_WindowLength_BR_r13]; - long si_RepetitionPattern_r13 = - cc->sib1_v13ext-> - bandwidthReducedAccessRelatedInfo_r13->si_RepetitionPattern_r13; - AssertFatal(si_RepetitionPattern_r13 <= - SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_RepetitionPattern_r13_every8thRF, + long si_RepetitionPattern_r13 = cc->sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->si_RepetitionPattern_r13; + AssertFatal(si_RepetitionPattern_r13<=SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_RepetitionPattern_r13_every8thRF, "si_RepetitionPattern_r13 %d > %d\n", (int) si_RepetitionPattern_r13, SystemInformationBlockType1_v1310_IEs__bandwidthReducedAccessRelatedInfo_r13__si_RepetitionPattern_r13_every8thRF); // cycle through SIB list for (i = 0; i < schedulingInfoList_BR_r13->list.count; i++) { - long si_Periodicity = - schedulingInfoList->list.array[i]->si_Periodicity; - long si_Narrowband_r13 = - schedulingInfoList_BR_r13->list.array[i]-> - si_Narrowband_r13; - long si_TBS_r13 = - si_TBS_r13tab[schedulingInfoList_BR_r13-> - list.array[i]->si_TBS_r13]; + long si_Periodicity = schedulingInfoList->list.array[i]->si_Periodicity; + long si_Narrowband_r13 = schedulingInfoList_BR_r13->list.array[i]->si_Narrowband_r13; + long si_TBS_r13 = si_TBS_r13tab[schedulingInfoList_BR_r13->list.array[i]->si_TBS_r13]; // check if the SI is to be scheduled now int period_in_sf = 80 << si_Periodicity; // 2^i * 80 subframes, note: si_Periodicity is 2^i * 80ms @@ -434,18 +396,14 @@ schedule_SI_BR(module_id_t module_idP, frame_t frameP, "RRC provided bcch with length %d > %d (si_TBS_r13 %d)\n", bcch_sdu_length, (int) (si_TBS_r13 >> 3), - (int) schedulingInfoList_BR_r13-> - list.array[i]->si_TBS_r13); + (int) schedulingInfoList_BR_r13->list.array[i]->si_TBS_r13); // allocate all 6 PRBs in narrowband for SIB1_BR // check that SIB1 didn't take this narrowband - if (vrb_map[first_rb] > 0) - continue; + if (vrb_map[first_rb] > 0) continue; - first_rb = - narrowband_to_first_rb(cc, - si_Narrowband_r13 - 1); + first_rb = narrowband_to_first_rb(cc,si_Narrowband_r13 - 1); vrb_map[first_rb] = 1; vrb_map[first_rb + 1] = 1; vrb_map[first_rb + 2] = 1; @@ -465,89 +423,54 @@ schedule_SI_BR(module_id_t module_idP, frame_t frameP, - dl_config_pdu = - &dl_req->dl_config_pdu_list[dl_req-> - number_pdu]; - memset((void *) dl_config_pdu, 0, - sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = - NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + - sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = - si_TBS_r13 >> 3; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = - eNB->pdu_index[CC_id]; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = - 0xFFFF; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = si_TBS_r13 >> 3; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFF; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.resource_block_coding = - getRIV(N_RB_DL, first_rb, 6); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 6); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.redundancy_version = rvidx; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = rvidx; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.transport_block_to_codeword_swap_flag - = 0; - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.transmission_scheme = - (cc->p_eNB == 1) ? 0 : 1; - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.number_of_layers = 1; - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.number_of_subbands = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.ue_category_capacity = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.delta_power_offset_index = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.transmission_mode = - (cc->p_eNB == 1) ? 1 : 2; - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.num_bf_prb_per_subband = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - num_bf_vector = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB == 1) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; // Rel10 fields (for PDSCH starting symbol) dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10. - pdsch_start = - cc[CC_id]. - sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; // Rel13 fields dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 1; // CEModeA UE dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 1; // SI-BR - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel13.initial_transmission_sf_io = - absSF - sf_mod_period; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = absSF - sf_mod_period; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; dl_req->number_pdu++; dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; // Program TX Request - TX_req = - &eNB->TX_req[CC_id]. - tx_request_body.tx_pdu_list[eNB->TX_req[CC_id]. - tx_request_body.number_of_pdus]; + TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; TX_req->pdu_length = bcch_sdu_length; TX_req->pdu_index = eNB->pdu_index[CC_id]++; TX_req->num_segments = 1; - TX_req->segments[0].segment_length = - bcch_sdu_length; - TX_req->segments[0].segment_data = - cc->BCCH_BR_pdu[i + 1].payload; - eNB->TX_req[CC_id].tx_request_body. - number_of_pdus++; + TX_req->segments[0].segment_length = bcch_sdu_length; + TX_req->segments[0].segment_data = cc->BCCH_BR_pdu[i + 1].payload; + eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; eNB->TX_req[CC_id].sfn_sf = sfn_sf; eNB->TX_req[CC_id].tx_request_body.tl.tag = NFAPI_TX_REQUEST_BODY_TAG; eNB->TX_req[CC_id].header.message_id = NFAPI_TX_REQUEST; @@ -620,19 +543,16 @@ schedule_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) module_idP, frameP, CC_id, mib_sdu_length, (int) cc->mib->message.schedulingInfoSIB1_BR_r13); - dl_config_pdu = - &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = - NFAPI_DL_CONFIG_BCH_PDU_TYPE, dl_config_pdu->pdu_size = + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_BCH_PDU_TYPE, dl_config_pdu->pdu_size = 2 + sizeof(nfapi_dl_config_bch_pdu); - dl_config_pdu->bch_pdu.bch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_BCH_PDU_REL8_TAG; - dl_config_pdu->bch_pdu.bch_pdu_rel8.length = mib_sdu_length; - dl_config_pdu->bch_pdu.bch_pdu_rel8.pdu_index = - eNB->pdu_index[CC_id]; + dl_config_pdu->bch_pdu.bch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_BCH_PDU_REL8_TAG; + dl_config_pdu->bch_pdu.bch_pdu_rel8.length = mib_sdu_length; + dl_config_pdu->bch_pdu.bch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; dl_config_pdu->bch_pdu.bch_pdu_rel8.transmission_power = 6000; - dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; dl_req->number_pdu++; dl_config_request->header.message_id = NFAPI_DL_CONFIG_REQUEST; @@ -641,9 +561,7 @@ schedule_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) LOG_D(MAC, "eNB->DL_req[0].number_pdu %d (%p)\n", dl_req->number_pdu, &dl_req->number_pdu); // DL request - TX_req = - &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req - [CC_id].tx_request_body.number_of_pdus]; + TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; TX_req->pdu_length = 3; TX_req->pdu_index = eNB->pdu_index[CC_id]++; TX_req->num_segments = 1; @@ -753,114 +671,81 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) } - dl_config_pdu = - &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; memset((void *) dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = - NFAPI_DL_DCI_FORMAT_1A; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - aggregation_level = 4; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = 0xFFFF; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 2; // S-RNTI : see Table 4-10 from SCF082 - nFAPI specifications - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = 4; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = 0xFFFF; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 2; // S-RNTI : see Table 4-10 from SCF082 - nFAPI specifications + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = 0; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // no TPC - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - new_data_indicator_1 = 0; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - redundancy_version_1 = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // no TPC + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = 0; - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.resource_block_coding = - getRIV(N_RB_DL, first_rb, 4); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 4); dl_config_request->sfn_sf = sfn_sf; - if (!CCE_allocation_infeasible - (module_idP, CC_id, 0, subframeP, - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.aggregation_level, SI_RNTI)) { + if (!CCE_allocation_infeasible(module_idP, CC_id, 0, subframeP,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, SI_RNTI)) { LOG_D(MAC, "Frame %d: Subframe %d : Adding common DCI for S_RNTI\n", frameP, subframeP); dl_req->number_dci++; dl_req->number_pdu++; - dl_config_pdu = - &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; memset((void *) dl_config_pdu, 0, - sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = - NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = - eNB->pdu_index[CC_id]; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = bcch_sdu_length; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFF; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D + sizeof(nfapi_dl_config_request_p du_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = bcch_sdu_length; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFF; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.resource_block_coding = - getRIV(N_RB_DL, first_rb, 4); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - redundancy_version = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.transport_block_to_codeword_swap_flag - = 0; - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.transmission_scheme = - (cc->p_eNB == 1) ? 0 : 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - number_of_layers = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - number_of_subbands = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 4); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1; // first block + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.ue_category_capacity = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.delta_power_offset_index = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - transmission_mode = (cc->p_eNB == 1) ? 1 : 2; - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.num_bf_prb_per_subband = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = - 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB == 1) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; dl_req->number_pdu++; // Rel10 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = 3; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = 3; // Rel13 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 0; // regular UE - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not BR - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = 0xFFFF; // absolute SF + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL13_TAG; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 0; // regular UE + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not BR + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = 0xFFFF; // absolute SF - dl_config_request->header.message_id = NFAPI_DL_CONFIG_REQUEST; - dl_config_request->sfn_sf = sfn_sf; + dl_config_request->header.message_id = NFAPI_DL_CONFIG_REQUEST; + dl_config_request->sfn_sf = sfn_sf; // Program TX Request - TX_req = - &eNB->TX_req[CC_id]. - tx_request_body.tx_pdu_list[eNB->TX_req[CC_id]. - tx_request_body.number_of_pdus]; + TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; TX_req->pdu_length = bcch_sdu_length; TX_req->pdu_index = eNB->pdu_index[CC_id]++; TX_req->num_segments = 1; TX_req->segments[0].segment_length = bcch_sdu_length; - TX_req->segments[0].segment_data = - cc->BCCH_pdu.payload; + TX_req->segments[0].segment_data = cc->BCCH_pdu.payload; eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; eNB->TX_req[CC_id].sfn_sf = sfn_sf; eNB->TX_req[CC_id].tx_request_body.tl.tag = NFAPI_TX_REQUEST_BODY_TAG; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 9f2ab1cba8..4d298f69f5 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -74,13 +74,13 @@ add_ue_dlsch_info(module_id_t module_idP, { //LOG_D(MAC, "%s(module_idP:%d, CC_id:%d, UE_id:%d, subframeP:%d, status:%d) serving_num:%d rnti:%x\n", __FUNCTION__, module_idP, CC_id, UE_id, subframeP, status, eNB_dlsch_info[module_idP][CC_id][UE_id].serving_num, UE_RNTI(module_idP,UE_id)); - eNB_dlsch_info[module_idP][CC_id][UE_id].rnti = - UE_RNTI(module_idP, UE_id); - // eNB_dlsch_info[module_idP][CC_id][ue_mod_idP].weight = weight; - eNB_dlsch_info[module_idP][CC_id][UE_id].subframe = subframeP; - eNB_dlsch_info[module_idP][CC_id][UE_id].status = status; + eNB_dlsch_info[module_idP][CC_id][UE_id].rnti = + UE_RNTI(module_idP, UE_id); + // eNB_dlsch_info[module_idP][CC_id][ue_mod_idP].weight = weight; + eNB_dlsch_info[module_idP][CC_id][UE_id].subframe = subframeP; + eNB_dlsch_info[module_idP][CC_id][UE_id].status = status; - eNB_dlsch_info[module_idP][CC_id][UE_id].serving_num++; + eNB_dlsch_info[module_idP][CC_id][UE_id].serving_num++; } @@ -91,27 +91,25 @@ schedule_next_dlue(module_id_t module_idP, int CC_id, //------------------------------------------------------------------------------ { - int next_ue; - UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; + int next_ue; + UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; - for (next_ue = UE_list->head; next_ue >= 0; - next_ue = UE_list->next[next_ue]) { - if (eNB_dlsch_info[module_idP][CC_id][next_ue].status == - S_DL_WAITING) { - return next_ue; - } + for (next_ue = UE_list->head; next_ue >= 0; + next_ue = UE_list->next[next_ue]) { + if (eNB_dlsch_info[module_idP][CC_id][next_ue].status == + S_DL_WAITING) { + return next_ue; } + } - for (next_ue = UE_list->head; next_ue >= 0; - next_ue = UE_list->next[next_ue]) { - if (eNB_dlsch_info[module_idP][CC_id][next_ue].status == - S_DL_BUFFERED) { - eNB_dlsch_info[module_idP][CC_id][next_ue].status = - S_DL_WAITING; - } + for (next_ue = UE_list->head; next_ue >= 0; + next_ue = UE_list->next[next_ue]) { + if (eNB_dlsch_info[module_idP][CC_id][next_ue].status == S_DL_BUFFERED) { + eNB_dlsch_info[module_idP][CC_id][next_ue].status = S_DL_WAITING; } + } - return (-1); //next_ue; + return (-1); //next_ue; } @@ -129,187 +127,183 @@ generate_dlsch_header(unsigned char *mac_header, //------------------------------------------------------------------------------ { - SCH_SUBHEADER_FIXED *mac_header_ptr = - (SCH_SUBHEADER_FIXED *) mac_header; - uint8_t first_element = 0, last_size = 0, i; - uint8_t mac_header_control_elements[16], *ce_ptr; + SCH_SUBHEADER_FIXED *mac_header_ptr = (SCH_SUBHEADER_FIXED *) mac_header; + uint8_t first_element = 0, last_size = 0, i; + uint8_t mac_header_control_elements[16], *ce_ptr; - ce_ptr = &mac_header_control_elements[0]; + ce_ptr = &mac_header_control_elements[0]; - // compute header components + // compute header components - if ((short_padding == 1) || (short_padding == 2)) { - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = SHORT_PADDING; - first_element = 1; - last_size = 1; + if ((short_padding == 1) || (short_padding == 2)) { + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = SHORT_PADDING; + first_element = 1; + last_size = 1; + } + + if (short_padding == 2) { + mac_header_ptr->E = 1; + mac_header_ptr++; + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = SHORT_PADDING; + last_size = 1; + } + + if (drx_cmd != 255) { + if (first_element > 0) { + mac_header_ptr->E = 1; + mac_header_ptr++; + } else { + first_element = 1; } - if (short_padding == 2) { - mac_header_ptr->E = 1; - mac_header_ptr++; - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = SHORT_PADDING; - last_size = 1; + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = DRX_CMD; + last_size = 1; + } + + if (timing_advance_cmd != 31) { + if (first_element > 0) { + mac_header_ptr->E = 1; + mac_header_ptr++; + } else { + first_element = 1; } - if (drx_cmd != 255) { - if (first_element > 0) { - mac_header_ptr->E = 1; - mac_header_ptr++; - } else { - first_element = 1; - } + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = TIMING_ADV_CMD; + last_size = 1; + // msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); + ((TIMING_ADVANCE_CMD *) ce_ptr)->R = 0; + AssertFatal(timing_advance_cmd < 64, + "timing_advance_cmd %d > 63\n", timing_advance_cmd); + ((TIMING_ADVANCE_CMD *) ce_ptr)->TA = timing_advance_cmd; //(timing_advance_cmd+31)&0x3f; + LOG_D(MAC, "timing advance =%d (%d)\n", timing_advance_cmd, + ((TIMING_ADVANCE_CMD *) ce_ptr)->TA); + ce_ptr += sizeof(TIMING_ADVANCE_CMD); + //msg("offset %d\n",ce_ptr-mac_header_control_elements); + } - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = DRX_CMD; - last_size = 1; + if (ue_cont_res_id) { + if (first_element > 0) { + mac_header_ptr->E = 1; + /* + printf("[eNB][MAC] last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); + */ + mac_header_ptr++; + } else { + first_element = 1; } - if (timing_advance_cmd != 31) { - if (first_element > 0) { - mac_header_ptr->E = 1; - mac_header_ptr++; - } else { - first_element = 1; - } + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = UE_CONT_RES; + last_size = 1; - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = TIMING_ADV_CMD; - last_size = 1; - // msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); - ((TIMING_ADVANCE_CMD *) ce_ptr)->R = 0; - AssertFatal(timing_advance_cmd < 64, - "timing_advance_cmd %d > 63\n", timing_advance_cmd); - ((TIMING_ADVANCE_CMD *) ce_ptr)->TA = timing_advance_cmd; //(timing_advance_cmd+31)&0x3f; - LOG_D(MAC, "timing advance =%d (%d)\n", timing_advance_cmd, - ((TIMING_ADVANCE_CMD *) ce_ptr)->TA); - ce_ptr += sizeof(TIMING_ADVANCE_CMD); - //msg("offset %d\n",ce_ptr-mac_header_control_elements); + LOG_T(MAC, + "[eNB ][RAPROC] Generate contention resolution msg: %x.%x.%x.%x.%x.%x\n", + ue_cont_res_id[0], ue_cont_res_id[1], ue_cont_res_id[2], + ue_cont_res_id[3], ue_cont_res_id[4], ue_cont_res_id[5]); + + memcpy(ce_ptr, ue_cont_res_id, 6); + ce_ptr += 6; + // msg("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements); + } + //msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); + + for (i = 0; i < num_sdus; i++) { + LOG_T(MAC, "[eNB] Generate DLSCH header num sdu %d len sdu %d\n", + num_sdus, sdu_lengths[i]); + + if (first_element > 0) { + mac_header_ptr->E = 1; + /*msg("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); + */ + mac_header_ptr += last_size; + //msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); + } else { + first_element = 1; } - if (ue_cont_res_id) { - if (first_element > 0) { - mac_header_ptr->E = 1; - /* - printf("[eNB][MAC] last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); - */ - mac_header_ptr++; - } else { - first_element = 1; - } - - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = UE_CONT_RES; - last_size = 1; - - LOG_T(MAC, - "[eNB ][RAPROC] Generate contention resolution msg: %x.%x.%x.%x.%x.%x\n", - ue_cont_res_id[0], ue_cont_res_id[1], ue_cont_res_id[2], - ue_cont_res_id[3], ue_cont_res_id[4], ue_cont_res_id[5]); - - memcpy(ce_ptr, ue_cont_res_id, 6); - ce_ptr += 6; - // msg("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements); - } - //msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); - - for (i = 0; i < num_sdus; i++) { - LOG_T(MAC, "[eNB] Generate DLSCH header num sdu %d len sdu %d\n", - num_sdus, sdu_lengths[i]); - - if (first_element > 0) { - mac_header_ptr->E = 1; - /*msg("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); - */ - mac_header_ptr += last_size; - //msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); - } else { - first_element = 1; - } - - if (sdu_lengths[i] < 128) { - ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->R = 0; - ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->E = 0; - ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->F = 0; - ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->LCID = sdu_lcids[i]; - ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->L = - (unsigned char) sdu_lengths[i]; - last_size = 2; - } else { - ((SCH_SUBHEADER_LONG *) mac_header_ptr)->R = 0; - ((SCH_SUBHEADER_LONG *) mac_header_ptr)->E = 0; - ((SCH_SUBHEADER_LONG *) mac_header_ptr)->F = 1; - ((SCH_SUBHEADER_LONG *) mac_header_ptr)->LCID = sdu_lcids[i]; - ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB = - ((unsigned short) sdu_lengths[i] >> 8) & 0x7f; - ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_LSB = - (unsigned short) sdu_lengths[i] & 0xff; - ((SCH_SUBHEADER_LONG *) mac_header_ptr)->padding = 0x00; - last_size = 3; + if (sdu_lengths[i] < 128) { + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->R = 0; + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->E = 0; + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->F = 0; + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->LCID = sdu_lcids[i]; + ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->L = (unsigned char) sdu_lengths[i]; + last_size = 2; + } else { + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->R = 0; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->E = 0; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->F = 1; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->LCID = sdu_lcids[i]; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB = ((unsigned short) sdu_lengths[i] >> 8) & 0x7f; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_LSB = (unsigned short) sdu_lengths[i] & 0xff; + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->padding = 0x00; + last_size = 3; #ifdef DEBUG_HEADER_PARSING - LOG_D(MAC, - "[eNB] generate long sdu, size %x (MSB %x, LSB %x)\n", - sdu_lengths[i], - ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB, - ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_LSB); + LOG_D(MAC, + "[eNB] generate long sdu, size %x (MSB %x, LSB %x)\n", + sdu_lengths[i], + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB, + ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_LSB); #endif - } } + } - /* + /* - printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); + printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); - printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); + printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); - if (((SCH_SUBHEADER_FIXED*)mac_header_ptr)->LCID < UE_CONT_RES) { - if (((SCH_SUBHEADER_SHORT*)mac_header_ptr)->F == 0) - printf("F = 0, sdu len (L field) %d\n",(((SCH_SUBHEADER_SHORT*)mac_header_ptr)->L)); - else - printf("F = 1, sdu len (L field) %d\n",(((SCH_SUBHEADER_LONG*)mac_header_ptr)->L)); - } - */ - if (post_padding > 0) { // we have lots of padding at the end of the packet - mac_header_ptr->E = 1; - mac_header_ptr += last_size; - // add a padding element - mac_header_ptr->R = 0; - mac_header_ptr->E = 0; - mac_header_ptr->LCID = SHORT_PADDING; - mac_header_ptr++; - } else { // no end of packet padding - // last SDU subhead is of fixed type (sdu length implicitly to be computed at UE) - mac_header_ptr++; + if (((SCH_SUBHEADER_FIXED*)mac_header_ptr)->LCID < UE_CONT_RES) { + if (((SCH_SUBHEADER_SHORT*)mac_header_ptr)->F == 0) + printf("F = 0, sdu len (L field) %d\n",(((SCH_SUBHEADER_SHORT*)mac_header_ptr)->L)); + else + printf("F = 1, sdu len (L field) %d\n",(((SCH_SUBHEADER_LONG*)mac_header_ptr)->L)); } + */ + if (post_padding > 0) { // we have lots of padding at the end of the packet + mac_header_ptr->E = 1; + mac_header_ptr += last_size; + // add a padding element + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = SHORT_PADDING; + mac_header_ptr++; + } else { // no end of packet padding + // last SDU subhead is of fixed type (sdu length implicitly to be computed at UE) + mac_header_ptr++; + } - //msg("After subheaders %d\n",(uint8_t*)mac_header_ptr - mac_header); + //msg("After subheaders %d\n",(uint8_t*)mac_header_ptr - mac_header); - if ((ce_ptr - mac_header_control_elements) > 0) { - // printf("Copying %d bytes for control elements\n",ce_ptr-mac_header_control_elements); - memcpy((void *) mac_header_ptr, mac_header_control_elements, - ce_ptr - mac_header_control_elements); - mac_header_ptr += - (unsigned char) (ce_ptr - mac_header_control_elements); - } - //msg("After CEs %d\n",(uint8_t*)mac_header_ptr - mac_header); + if ((ce_ptr - mac_header_control_elements) > 0) { + // printf("Copying %d bytes for control elements\n",ce_ptr-mac_header_control_elements); + memcpy((void *) mac_header_ptr, mac_header_control_elements, + ce_ptr - mac_header_control_elements); + mac_header_ptr += + (unsigned char) (ce_ptr - mac_header_control_elements); + } + //msg("After CEs %d\n",(uint8_t*)mac_header_ptr - mac_header); - return ((unsigned char *) mac_header_ptr - mac_header); + return ((unsigned char *) mac_header_ptr - mac_header); } @@ -320,94 +314,94 @@ set_ul_DAI(int module_idP, int UE_idP, int CC_idP, int frameP, //------------------------------------------------------------------------------ { - eNB_MAC_INST *eNB = RC.mac[module_idP]; - UE_list_t *UE_list = &eNB->UE_list; - unsigned char DAI; - COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; - if (cc->tdd_Config != NULL) { //TDD - DAI = (UE_list->UE_template[CC_idP][UE_idP].DAI - 1) & 3; - LOG_D(MAC, - "[eNB %d] CC_id %d Frame %d, subframe %d: DAI %d for UE %d\n", - module_idP, CC_idP, frameP, subframeP, DAI, UE_idP); - // Save DAI for Format 0 DCI + eNB_MAC_INST *eNB = RC.mac[module_idP]; + UE_list_t *UE_list = &eNB->UE_list; + unsigned char DAI; + COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; + if (cc->tdd_Config != NULL) { //TDD + DAI = (UE_list->UE_template[CC_idP][UE_idP].DAI - 1) & 3; + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d, subframe %d: DAI %d for UE %d\n", + module_idP, CC_idP, frameP, subframeP, DAI, UE_idP); + // Save DAI for Format 0 DCI - switch (cc->tdd_Config->subframeAssignment) { - case 0: - // if ((subframeP==0)||(subframeP==1)||(subframeP==5)||(subframeP==6)) - break; + switch (cc->tdd_Config->subframeAssignment) { + case 0: + // if ((subframeP==0)||(subframeP==1)||(subframeP==5)||(subframeP==6)) + break; - case 1: - switch (subframeP) { - case 1: - UE_list->UE_template[CC_idP][UE_idP].DAI_ul[7] = DAI; - break; + case 1: + switch (subframeP) { + case 1: + UE_list->UE_template[CC_idP][UE_idP].DAI_ul[7] = DAI; + break; - case 4: - UE_list->UE_template[CC_idP][UE_idP].DAI_ul[8] = DAI; - break; + case 4: + UE_list->UE_template[CC_idP][UE_idP].DAI_ul[8] = DAI; + break; - case 6: - UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI; - break; + case 6: + UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI; + break; - case 9: - UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI; - break; - } + case 9: + UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI; + break; + } - case 2: - // if ((subframeP==3)||(subframeP==8)) - // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; - break; + case 2: + // if ((subframeP==3)||(subframeP==8)) + // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; + break; - case 3: + case 3: - //if ((subframeP==6)||(subframeP==8)||(subframeP==0)) { - // LOG_D(MAC,"schedule_ue_spec: setting UL DAI to %d for subframeP %d => %d\n",DAI,subframeP, ((subframeP+8)%10)>>1); - // UE_list->UE_template[CC_idP][UE_idP].DAI_ul[((subframeP+8)%10)>>1] = DAI; - //} - switch (subframeP) { - case 5: - case 6: - case 1: - UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI; - break; + //if ((subframeP==6)||(subframeP==8)||(subframeP==0)) { + // LOG_D(MAC,"schedule_ue_spec: setting UL DAI to %d for subframeP %d => %d\n",DAI,subframeP, ((subframeP+8)%10)>>1); + // UE_list->UE_template[CC_idP][UE_idP].DAI_ul[((subframeP+8)%10)>>1] = DAI; + //} + switch (subframeP) { + case 5: + case 6: + case 1: + UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI; + break; - case 7: - case 8: - UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI; - break; + case 7: + case 8: + UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI; + break; - case 9: - case 0: - UE_list->UE_template[CC_idP][UE_idP].DAI_ul[4] = DAI; - break; + case 9: + case 0: + UE_list->UE_template[CC_idP][UE_idP].DAI_ul[4] = DAI; + break; - default: - break; - } + default: + break; + } - break; + break; - case 4: - // if ((subframeP==8)||(subframeP==9)) - // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; - break; + case 4: + // if ((subframeP==8)||(subframeP==9)) + // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; + break; - case 5: - // if (subframeP==8) - // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; - break; + case 5: + // if (subframeP==8) + // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; + break; - case 6: - // if ((subframeP==1)||(subframeP==4)||(subframeP==6)||(subframeP==9)) - // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; - break; + case 6: + // if ((subframeP==1)||(subframeP==4)||(subframeP==6)||(subframeP==9)) + // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; + break; - default: - break; - } + default: + break; } + } } @@ -421,1106 +415,977 @@ schedule_ue_spec(module_id_t module_idP, { - uint8_t CC_id; - int UE_id; - unsigned char aggregation; - mac_rlc_status_resp_t rlc_status; - unsigned char header_len_dcch = 0, header_len_dcch_tmp = 0; - unsigned char header_len_dtch = 0, header_len_dtch_tmp = - 0, header_len_dtch_last = 0; - unsigned char ta_len = 0; - unsigned char sdu_lcids[NB_RB_MAX], lcid, offset, num_sdus = 0; - uint16_t nb_rb, nb_rb_temp, nb_available_rb; - uint16_t TBS, j, sdu_lengths[NB_RB_MAX], rnti, padding = - 0, post_padding = 0; - unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; - unsigned char round = 0; - unsigned char harq_pid = 0; - eNB_UE_STATS *eNB_UE_stats = NULL; - uint16_t sdu_length_total = 0; + uint8_t CC_id; + int UE_id; + unsigned char aggregation; + mac_rlc_status_resp_t rlc_status; + unsigned char header_len_dcch = 0, header_len_dcch_tmp = 0; + unsigned char header_len_dtch = 0, header_len_dtch_tmp = + 0, header_len_dtch_last = 0; + unsigned char ta_len = 0; + unsigned char sdu_lcids[NB_RB_MAX], lcid, offset, num_sdus = 0; + uint16_t nb_rb, nb_rb_temp, nb_available_rb; + uint16_t TBS, j, sdu_lengths[NB_RB_MAX], rnti, padding = + 0, post_padding = 0; + unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; + unsigned char round = 0; + unsigned char harq_pid = 0; + eNB_UE_STATS *eNB_UE_stats = NULL; + uint16_t sdu_length_total = 0; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - COMMON_channels_t *cc = eNB->common_channels; - UE_list_t *UE_list = &eNB->UE_list; - int continue_flag = 0; - int32_t normalized_rx_power, target_rx_power; - int32_t tpc = 1; - static int32_t tpc_accumulated = 0; - UE_sched_ctrl *ue_sched_ctl; - int mcs; - int i; - int min_rb_unit[MAX_NUM_CCs]; - int N_RB_DL[MAX_NUM_CCs]; - int total_nb_available_rb[MAX_NUM_CCs]; - int N_RBG[MAX_NUM_CCs]; - nfapi_dl_config_request_body_t *dl_req; - nfapi_dl_config_request_pdu_t *dl_config_pdu; - int tdd_sfa; - int ta_update; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + COMMON_channels_t *cc = eNB->common_channels; + UE_list_t *UE_list = &eNB->UE_list; + int continue_flag = 0; + int32_t normalized_rx_power, target_rx_power; + int32_t tpc = 1; + static int32_t tpc_accumulated = 0; + UE_sched_ctrl *ue_sched_ctl; + int mcs; + int i; + int min_rb_unit[MAX_NUM_CCs]; + int N_RB_DL[MAX_NUM_CCs]; + int total_nb_available_rb[MAX_NUM_CCs]; + int N_RBG[MAX_NUM_CCs]; + nfapi_dl_config_request_body_t *dl_req; + nfapi_dl_config_request_pdu_t *dl_config_pdu; + int tdd_sfa; + int ta_update; #if 0 - if (UE_list->head == -1) { - return; - } + if (UE_list->head == -1) { + return; + } #endif - start_meas(&eNB->schedule_dlsch); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_IN); + start_meas(&eNB->schedule_dlsch); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_IN); - // for TDD: check that we have to act here, otherwise return - if (cc[0].tdd_Config) { - tdd_sfa = cc[0].tdd_Config->subframeAssignment; - switch (subframeP) { - case 0: - // always continue - break; + // for TDD: check that we have to act here, otherwise return + if (cc[0].tdd_Config) { + tdd_sfa = cc[0].tdd_Config->subframeAssignment; + switch (subframeP) { + case 0: + // always continue + break; + case 1: + return; + break; + case 2: + return; + break; + case 3: + if ((tdd_sfa != 2) && (tdd_sfa != 5)) + return; + break; + case 4: + if ((tdd_sfa != 1) && (tdd_sfa != 2) && (tdd_sfa != 4) + && (tdd_sfa != 5)) + return; + break; + case 5: + break; + case 6: + case 7: + if ((tdd_sfa != 1) && (tdd_sfa != 2) && (tdd_sfa != 4) + && (tdd_sfa != 5)) + return; + break; + case 8: + if ((tdd_sfa != 2) && (tdd_sfa != 3) && (tdd_sfa != 4) + && (tdd_sfa != 5)) + return; + break; + case 9: + if ((tdd_sfa != 1) && (tdd_sfa != 3) && (tdd_sfa != 4) + && (tdd_sfa != 6)) + return; + break; + + } + } + //weight = get_ue_weight(module_idP,UE_id); + aggregation = 2; + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + N_RB_DL[CC_id] = to_prb(cc[CC_id].mib->message.dl_Bandwidth); + min_rb_unit[CC_id] = get_min_rb_unit(module_idP, CC_id); + // get number of PRBs less those used by common channels + total_nb_available_rb[CC_id] = N_RB_DL[CC_id]; + for (i = 0; i < N_RB_DL[CC_id]; i++) + if (cc[CC_id].vrb_map[i] != 0) + total_nb_available_rb[CC_id]--; + + N_RBG[CC_id] = to_rbg(cc[CC_id].mib->message.dl_Bandwidth); + + // store the global enb stats: + eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs; + eNB->eNB_stats[CC_id].available_prbs = total_nb_available_rb[CC_id]; + eNB->eNB_stats[CC_id].total_available_prbs += total_nb_available_rb[CC_id]; + eNB->eNB_stats[CC_id].dlsch_bytes_tx = 0; + eNB->eNB_stats[CC_id].dlsch_pdus_tx = 0; + } + + /// CALLING Pre_Processor for downlink scheduling (Returns estimation of RBs required by each UE and the allocation on sub-band) + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_IN); + start_meas(&eNB->schedule_dlsch_preprocessor); + dlsch_scheduler_pre_processor(module_idP, + frameP, subframeP, N_RBG, mbsfn_flag); + stop_meas(&eNB->schedule_dlsch_preprocessor); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_OUT); + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n", CC_id); + + dl_req = &eNB->DL_req[CC_id].dl_config_request_body; + + if (mbsfn_flag[CC_id] > 0) + continue; + + for (UE_id = UE_list->head; UE_id >= 0; + UE_id = UE_list->next[UE_id]) { + continue_flag = 0; // reset the flag to allow allocation for the remaining UEs + rnti = UE_RNTI(module_idP, UE_id); + eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + + + if (rnti == NOT_A_RNTI) { + LOG_D(MAC, "Cannot find rnti for UE_id %d (num_UEs %d)\n", + UE_id, UE_list->num_UEs); + continue_flag = 1; + } + + if (eNB_UE_stats == NULL) { + LOG_D(MAC, "[eNB] Cannot find eNB_UE_stats\n"); + continue_flag = 1; + } + + if (continue_flag != 1) { + switch (get_tmode(module_idP, CC_id, UE_id)) { case 1: - return; - break; case 2: - return; - break; - case 3: - if ((tdd_sfa != 2) && (tdd_sfa != 5)) - return; - break; - case 4: - if ((tdd_sfa != 1) && (tdd_sfa != 2) && (tdd_sfa != 4) - && (tdd_sfa != 5)) - return; - break; - case 5: - break; - case 6: case 7: - if ((tdd_sfa != 1) && (tdd_sfa != 2) && (tdd_sfa != 4) - && (tdd_sfa != 5)) - return; - break; - case 8: - if ((tdd_sfa != 2) && (tdd_sfa != 3) && (tdd_sfa != 4) - && (tdd_sfa != 5)) - return; - break; - case 9: - if ((tdd_sfa != 1) && (tdd_sfa != 3) && (tdd_sfa != 4) - && (tdd_sfa != 6)) - return; - break; - + aggregation = + get_aggregation(get_bw_index(module_idP, CC_id), + ue_sched_ctl->dl_cqi[CC_id], + format1); + break; + case 3: + aggregation = + get_aggregation(get_bw_index(module_idP, CC_id), + ue_sched_ctl->dl_cqi[CC_id], + format2A); + break; + default: + LOG_W(MAC, "Unsupported transmission mode %d\n", + get_tmode(module_idP, CC_id, UE_id)); + aggregation = 2; } - } - //weight = get_ue_weight(module_idP,UE_id); - aggregation = 2; - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - N_RB_DL[CC_id] = to_prb(cc[CC_id].mib->message.dl_Bandwidth); - min_rb_unit[CC_id] = get_min_rb_unit(module_idP, CC_id); - // get number of PRBs less those used by common channels - total_nb_available_rb[CC_id] = N_RB_DL[CC_id]; - for (i = 0; i < N_RB_DL[CC_id]; i++) - if (cc[CC_id].vrb_map[i] != 0) - total_nb_available_rb[CC_id]--; + } + /* if (continue_flag != 1 */ + if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated + CCE_allocation_infeasible(module_idP, CC_id, 1, subframeP, + aggregation, rnti)) { + LOG_D(MAC, + "[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", + module_idP, frameP, UE_id, CC_id); + continue_flag = 1; //to next user (there might be rbs availiable for other UEs in TM5 + } - N_RBG[CC_id] = to_rbg(cc[CC_id].mib->message.dl_Bandwidth); + if (cc[CC_id].tdd_Config != NULL) { //TDD + set_ue_dai(subframeP, + UE_id, + CC_id, + cc[CC_id].tdd_Config->subframeAssignment, + UE_list); + // update UL DAI after DLSCH scheduling + set_ul_DAI(module_idP, UE_id, CC_id, frameP, subframeP); + } - // store the global enb stats: - eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs; - eNB->eNB_stats[CC_id].available_prbs = - total_nb_available_rb[CC_id]; - eNB->eNB_stats[CC_id].total_available_prbs += - total_nb_available_rb[CC_id]; - eNB->eNB_stats[CC_id].dlsch_bytes_tx = 0; - eNB->eNB_stats[CC_id].dlsch_pdus_tx = 0; - } - - /// CALLING Pre_Processor for downlink scheduling (Returns estimation of RBs required by each UE and the allocation on sub-band) - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_IN); - start_meas(&eNB->schedule_dlsch_preprocessor); - dlsch_scheduler_pre_processor(module_idP, - frameP, subframeP, N_RBG, mbsfn_flag); - stop_meas(&eNB->schedule_dlsch_preprocessor); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_OUT); - - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n", CC_id); - - dl_req = &eNB->DL_req[CC_id].dl_config_request_body; - - if (mbsfn_flag[CC_id] > 0) - continue; - - for (UE_id = UE_list->head; UE_id >= 0; - UE_id = UE_list->next[UE_id]) { - continue_flag = 0; // reset the flag to allow allocation for the remaining UEs - rnti = UE_RNTI(module_idP, UE_id); - eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - - - if (rnti == NOT_A_RNTI) { - LOG_D(MAC, "Cannot find rnti for UE_id %d (num_UEs %d)\n", - UE_id, UE_list->num_UEs); - continue_flag = 1; - } - - if (eNB_UE_stats == NULL) { - LOG_D(MAC, "[eNB] Cannot find eNB_UE_stats\n"); - continue_flag = 1; - } - - if (continue_flag != 1) { - switch (get_tmode(module_idP, CC_id, UE_id)) { - case 1: - case 2: - case 7: - aggregation = - get_aggregation(get_bw_index(module_idP, CC_id), - ue_sched_ctl->dl_cqi[CC_id], - format1); - break; - case 3: - aggregation = - get_aggregation(get_bw_index(module_idP, CC_id), - ue_sched_ctl->dl_cqi[CC_id], - format2A); - break; - default: - LOG_W(MAC, "Unsupported transmission mode %d\n", - get_tmode(module_idP, CC_id, UE_id)); - aggregation = 2; - } - } - /* if (continue_flag != 1 */ - if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated - CCE_allocation_infeasible(module_idP, CC_id, 1, subframeP, - aggregation, rnti)) { - LOG_D(MAC, - "[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", - module_idP, frameP, UE_id, CC_id); - continue_flag = 1; //to next user (there might be rbs availiable for other UEs in TM5 - } - - if (cc[CC_id].tdd_Config != NULL) { //TDD - set_ue_dai(subframeP, - UE_id, - CC_id, - cc[CC_id].tdd_Config->subframeAssignment, - UE_list); - // update UL DAI after DLSCH scheduling - set_ul_DAI(module_idP, UE_id, CC_id, frameP, subframeP); - } - - if (continue_flag == 1) { - add_ue_dlsch_info(module_idP, - CC_id, UE_id, subframeP, S_DL_NONE); - continue; - } + if (continue_flag == 1) { + add_ue_dlsch_info(module_idP, + CC_id, UE_id, subframeP, S_DL_NONE); + continue; + } #warning RK->CR This old API call has to be revisited for FAPI, or logic must be changed #if 0 - /* add "fake" DCI to have CCE_allocation_infeasible work properly for next allocations */ - /* if we don't add it, next allocations may succeed but overall allocations may fail */ - /* will be removed at the end of this function */ - add_ue_spec_dci(&eNB->common_channels[CC_id].DCI_pdu, &(char[]) { - 0}, rnti, 1, aggregation, 1, format1, 0); + /* add "fake" DCI to have CCE_allocation_infeasible work properly for next allocations */ + /* if we don't add it, next allocations may succeed but overall allocations may fail */ + /* will be removed at the end of this function */ + add_ue_spec_dci(&eNB->common_channels[CC_id].DCI_pdu, &(char[]) { + 0}, rnti, 1, aggregation, 1, format1, 0); #endif - nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; + nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; - if (cc->tdd_Config) - harq_pid = ((frameP * 10) + subframeP) % 10; - else - harq_pid = ((frameP * 10) + subframeP) & 7; + if (cc->tdd_Config) harq_pid = ((frameP * 10) + subframeP) % 10; + else harq_pid = ((frameP * 10) + subframeP) & 7; - round = ue_sched_ctl->round[CC_id][harq_pid]; + round = ue_sched_ctl->round[CC_id][harq_pid]; - UE_list->eNB_UE_stats[CC_id][UE_id].crnti = rnti; - UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status = - mac_eNB_get_rrc_status(module_idP, rnti); - UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid; - UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round; + UE_list->eNB_UE_stats[CC_id][UE_id].crnti = rnti; + UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status = mac_eNB_get_rrc_status(module_idP, rnti); + UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid; + UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round; - if (UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status < - RRC_CONNECTED) - continue; + if (UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status < RRC_CONNECTED) continue; - sdu_length_total = 0; - num_sdus = 0; + sdu_length_total = 0; + num_sdus = 0; - /* - DevCheck(((eNB_UE_stats->dl_cqi < MIN_CQI_VALUE) || (eNB_UE_stats->dl_cqi > MAX_CQI_VALUE)), - eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE); - */ - if (nfapi_mode) { - eNB_UE_stats->dlsch_mcs1 = 10;//cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]]; - } - else { - eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]]; - } - eNB_UE_stats->dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1; //cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); + /* + DevCheck(((eNB_UE_stats->dl_cqi < MIN_CQI_VALUE) || (eNB_UE_stats->dl_cqi > MAX_CQI_VALUE)), + eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE); + */ + if (nfapi_mode) { + eNB_UE_stats->dlsch_mcs1 = 10;//cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]]; + } + else { + eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]]; + } + eNB_UE_stats->dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1; //cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); - // store stats - //UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->dl_cqi; + // store stats + //UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->dl_cqi; - // initializing the rb allocation indicator for each UE - for (j = 0; j < N_RBG[CC_id]; j++) { - UE_list-> - UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] - = 0; - } + // initializing the rb allocation indicator for each UE + for (j = 0; j < N_RBG[CC_id]; j++) { + UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0; + } + LOG_D(MAC, + "[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n", + module_idP, frameP, UE_id, CC_id, rnti, harq_pid, round, + nb_available_rb, ue_sched_ctl->dl_cqi[CC_id], + eNB_UE_stats->dlsch_mcs1, + UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); + + + + /* process retransmission */ + + if (round != 8) { + + // get freq_allocation + nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + TBS = get_TBS_DL(UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid], + nb_rb); + + if (nb_rb <= nb_available_rb) { + if (cc[CC_id].tdd_Config != NULL) { + UE_list->UE_template[CC_id][UE_id].DAI++; + update_ul_dci(module_idP, CC_id, rnti, + UE_list->UE_template[CC_id][UE_id]. + DAI); LOG_D(MAC, - "[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n", - module_idP, frameP, UE_id, CC_id, rnti, harq_pid, round, - nb_available_rb, ue_sched_ctl->dl_cqi[CC_id], - eNB_UE_stats->dlsch_mcs1, - UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); + "DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", + CC_id, subframeP, UE_id, + UE_list->UE_template[CC_id][UE_id].DAI); + } + if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { + for (j = 0; j < N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band + UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + } + } else { + nb_rb_temp = nb_rb; + j = 0; + while ((nb_rb_temp > 0) && (j < N_RBG[CC_id])) { + if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { + if (UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]) + printf("WARN: rballoc_subband not free for retrans?\n"); + UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - /* process retransmission */ - - if (round != 8) { - - // get freq_allocation - nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - TBS = - get_TBS_DL(UE_list-> - UE_template[CC_id][UE_id].oldmcs1[harq_pid], - nb_rb); - - if (nb_rb <= nb_available_rb) { - if (cc[CC_id].tdd_Config != NULL) { - UE_list->UE_template[CC_id][UE_id].DAI++; - update_ul_dci(module_idP, CC_id, rnti, - UE_list->UE_template[CC_id][UE_id]. - DAI); - LOG_D(MAC, - "DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", - CC_id, subframeP, UE_id, - UE_list->UE_template[CC_id][UE_id].DAI); - } - - if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { - for (j = 0; j < N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band - UE_list->UE_template[CC_id][UE_id]. - rballoc_subband[harq_pid][j] = - ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - } - } else { - nb_rb_temp = nb_rb; - j = 0; - - while ((nb_rb_temp > 0) && (j < N_RBG[CC_id])) { - if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == - 1) { - if (UE_list-> - UE_template[CC_id] - [UE_id].rballoc_subband[harq_pid][j]) - printf - ("WARN: rballoc_subband not free for retrans?\n"); - UE_list-> - UE_template[CC_id] - [UE_id].rballoc_subband[harq_pid][j] = - ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - - if ((j == N_RBG[CC_id] - 1) && - ((N_RB_DL[CC_id] == 25) || - (N_RB_DL[CC_id] == 50))) { - nb_rb_temp = - nb_rb_temp - min_rb_unit[CC_id] + - 1; - } else { - nb_rb_temp = - nb_rb_temp - min_rb_unit[CC_id]; - } - } - - j = j + 1; - } - } - - nb_available_rb -= nb_rb; - /* - eNB->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; - eNB->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; - - for(j=0; jmu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; - } - */ - - switch (get_tmode(module_idP, CC_id, UE_id)) { - case 1: - case 2: - case 7: - default: - LOG_D(MAC,"retransmission DL_REQ: rnti:%x\n",rnti); - - dl_config_pdu = - &dl_req->dl_config_pdu_list[dl_req-> - number_pdu]; - memset((void *) dl_config_pdu, 0, - sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = - NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + - sizeof(nfapi_dl_config_dci_dl_pdu)); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - dci_format = NFAPI_DL_DCI_FORMAT_1; - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.aggregation_level = - get_aggregation(get_bw_index - (module_idP, CC_id), - ue_sched_ctl->dl_cqi[CC_id], - format1); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = - rnti; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power - - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - harq_process = harq_pid; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // dont adjust power when retransmitting - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.new_data_indicator_1 = - UE_list->UE_template[CC_id][UE_id]. - oldNDI[harq_pid]; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = - UE_list->UE_template[CC_id][UE_id]. - oldmcs1[harq_pid]; - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.redundancy_version_1 = - round & 3; - - if (cc[CC_id].tdd_Config != NULL) { //TDD - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.downlink_assignment_index = - (UE_list->UE_template[CC_id][UE_id].DAI - - 1) & 3; - LOG_D(MAC, - "[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d, mcs %d\n", - module_idP, CC_id, harq_pid, round, - (UE_list->UE_template[CC_id][UE_id].DAI - - 1), - UE_list-> - UE_template[CC_id][UE_id].oldmcs1 - [harq_pid]); - } else { - LOG_D(MAC, - "[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, mcs %d\n", - module_idP, CC_id, harq_pid, round, - UE_list-> - UE_template[CC_id][UE_id].oldmcs1 - [harq_pid]); - - } - if (!CCE_allocation_infeasible - (module_idP, CC_id, 1, subframeP, - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.aggregation_level, rnti)) { - dl_req->number_dci++; - dl_req->number_pdu++; - dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; - - eNB->DL_req[CC_id].sfn_sf = frameP<<4 | subframeP; - eNB->DL_req[CC_id].header.message_id = NFAPI_DL_CONFIG_REQUEST; - - fill_nfapi_dlsch_config(eNB, dl_req, TBS, -1 - /* retransmission, no pdu_index */ - , rnti, 0, // type 0 allocation from 7.1.6 in 36.213 - 0, // virtual_resource_block_assignment_flag, unused here - 0, // resource_block_coding, to be filled in later - getQm(UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]), round & 3, // redundancy version - 1, // transport blocks - 0, // transport block to codeword swap flag - cc[CC_id].p_eNB == 1 ? 0 : 1, // transmission_scheme - 1, // number of layers - 1, // number of subbands - // uint8_t codebook_index, - 4, // UE category capacity - UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated->p_a, 0, // delta_power_offset for TM5 - 0, // ngap - 0, // nprb - cc[CC_id].p_eNB == 1 ? 1 : 2, // transmission mode - 0, //number of PRBs treated as one subband, not used here - 0 // number of beamforming vectors, not used here - ); - - LOG_D(MAC, - "Filled NFAPI configuration for DCI/DLSCH %d, retransmission round %d\n", - eNB->pdu_index[CC_id], round); - - program_dlsch_acknak(module_idP, CC_id, UE_id, - frameP, subframeP, - dl_config_pdu-> - dci_dl_pdu.dci_dl_pdu_rel8. - cce_idx); - // No TX request for retransmission (check if null request for FAPI) - } else { - LOG_W(MAC, - "Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d\%x, infeasible CCE allocation\n", - frameP, subframeP, UE_id, rnti); - } - } - - - add_ue_dlsch_info(module_idP, - CC_id, UE_id, subframeP, - S_DL_SCHEDULED); - - //eNB_UE_stats->dlsch_trials[round]++; - UE_list->eNB_UE_stats[CC_id][UE_id]. - num_retransmission += 1; - UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx = - nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id]. - total_rbs_used_retx += nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = - eNB_UE_stats->dlsch_mcs1; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = - eNB_UE_stats->dlsch_mcs1; + if ((j == N_RBG[CC_id] - 1) && + ((N_RB_DL[CC_id] == 25) || + (N_RB_DL[CC_id] == 50))) { + nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id] + 1; } else { - LOG_D(MAC, - "[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", - module_idP, frameP, CC_id, UE_id); + nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; } - } else { /* This is a potentially new SDU opportunity */ - - rlc_status.bytes_in_buffer = 0; - // Now check RLC information to compute number of required RBs - // get maximum TBS size for RLC request - TBS = - get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb); - // check first for RLC data on DCCH - // add the length for all the control elements (timing adv, drx, etc) : header + payload - - if (ue_sched_ctl->ta_timer == 0) { - ta_update = ue_sched_ctl->ta_update; - /* if we send TA then set timer to not send it for a while */ - if (ta_update != 31) - ue_sched_ctl->ta_timer = 20; - /* reset ta_update */ - ue_sched_ctl->ta_update = 31; - } else { - ta_update = 31; - } - - ta_len = (ta_update != 31) ? 2 : 0; - - header_len_dcch = 2; // 2 bytes DCCH SDU subheader - - if (TBS - ta_len - header_len_dcch > 0) { - rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, (TBS - ta_len - header_len_dcch)); // transport block set size - - sdu_lengths[0] = 0; - - if (rlc_status.bytes_in_buffer > 0) { // There is DCCH to transmit - LOG_D(MAC, - "[eNB %d] SFN/SF %d.%d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n", - module_idP, frameP, subframeP, CC_id, - TBS - header_len_dcch); - sdu_lengths[0] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, TBS, //not used - (char *) - &dlsch_buffer - [0]); - - T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), - T_INT(CC_id), T_INT(rnti), T_INT(frameP), - T_INT(subframeP), T_INT(harq_pid), T_INT(DCCH), - T_INT(sdu_lengths[0])); - - LOG_D(MAC, - "[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n", - module_idP, CC_id, sdu_lengths[0]); - sdu_length_total = sdu_lengths[0]; - sdu_lcids[0] = DCCH; - UE_list->eNB_UE_stats[CC_id][UE_id]. - num_pdu_tx[DCCH] += 1; - UE_list-> - eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH] - += sdu_lengths[0]; - num_sdus = 1; -#ifdef DEBUG_eNB_SCHEDULER - LOG_T(MAC, - "[eNB %d][DCCH] CC_id %d Got %d bytes :", - module_idP, CC_id, sdu_lengths[0]); - - for (j = 0; j < sdu_lengths[0]; j++) { - LOG_T(MAC, "%x ", dlsch_buffer[j]); - } - - LOG_T(MAC, "\n"); -#endif - } else { - header_len_dcch = 0; - sdu_length_total = 0; - } - } - // check for DCCH1 and update header information (assume 2 byte sub-header) - if (TBS - ta_len - header_len_dcch - sdu_length_total > 0) { - rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, (TBS - ta_len - header_len_dcch - sdu_length_total)); // transport block set size less allocations for timing advance and - // DCCH SDU - sdu_lengths[num_sdus] = 0; - - if (rlc_status.bytes_in_buffer > 0) { - LOG_D(MAC, - "[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", - module_idP, frameP, CC_id, - TBS - header_len_dcch - sdu_length_total); - sdu_lengths[num_sdus] += mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, TBS, //not used - (char *) - &dlsch_buffer - [sdu_length_total]); - - T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), - T_INT(CC_id), T_INT(rnti), T_INT(frameP), - T_INT(subframeP), T_INT(harq_pid), - T_INT(DCCH + 1), T_INT(sdu_lengths[num_sdus])); - - sdu_lcids[num_sdus] = DCCH1; - sdu_length_total += sdu_lengths[num_sdus]; - header_len_dcch += 2; - UE_list->eNB_UE_stats[CC_id][UE_id]. - num_pdu_tx[DCCH1] += 1; - UE_list-> - eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1] - += sdu_lengths[num_sdus]; - num_sdus++; -#ifdef DEBUG_eNB_SCHEDULER - LOG_T(MAC, - "[eNB %d][DCCH1] CC_id %d Got %d bytes :", - module_idP, CC_id, sdu_lengths[num_sdus]); - - for (j = 0; j < sdu_lengths[num_sdus]; j++) { - LOG_T(MAC, "%x ", dlsch_buffer[j]); - } - - LOG_T(MAC, "\n"); -#endif - - } - } - // assume the max dtch header size, and adjust it later - header_len_dtch = 0; - header_len_dtch_last = 0; // the header length of the last mac sdu - // lcid has to be sorted before the actual allocation (similar struct as ue_list). - for (lcid = NB_RB_MAX - 1; lcid >= DTCH; lcid--) { - // TBD: check if the lcid is active - - header_len_dtch += 3; - header_len_dtch_last = 3; - LOG_D(MAC, - "[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n", - module_idP, frameP, lcid, TBS, - TBS - ta_len - header_len_dcch - - sdu_length_total - header_len_dtch); - - if (TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch > 0) { // NN: > 2 ? - rlc_status = mac_rlc_status_ind(module_idP, - rnti, - module_idP, - frameP, - subframeP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - TBS - ta_len - - header_len_dcch - - sdu_length_total - - header_len_dtch); - - - if (rlc_status.bytes_in_buffer > 0) { - - LOG_D(MAC, - "[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n", - module_idP, frameP, - TBS - header_len_dcch - - sdu_length_total - header_len_dtch, lcid, - header_len_dtch); - sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, TBS, //not used - (char - *) - &dlsch_buffer - [sdu_length_total]); - T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), - T_INT(CC_id), T_INT(rnti), T_INT(frameP), - T_INT(subframeP), T_INT(harq_pid), - T_INT(lcid), T_INT(sdu_lengths[num_sdus])); - - LOG_D(MAC, - "[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n", - module_idP, sdu_lengths[num_sdus], lcid); - sdu_lcids[num_sdus] = lcid; - sdu_length_total += sdu_lengths[num_sdus]; - UE_list-> - eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid] - += 1; - UE_list-> - eNB_UE_stats[CC_id][UE_id].num_bytes_tx - [lcid] += sdu_lengths[num_sdus]; - if (sdu_lengths[num_sdus] < 128) { - header_len_dtch--; - header_len_dtch_last--; - } - num_sdus++; - UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0; - } // no data for this LCID - else { - header_len_dtch -= 3; - } - } // no TBS left - else { - header_len_dtch -= 3; - break; - } - } - if (header_len_dtch == 0) - header_len_dtch_last = 0; - // there is at least one SDU - // if (num_sdus > 0 ){ - if ((sdu_length_total + header_len_dcch + - header_len_dtch) > 0) { - - // Now compute number of required RBs for total sdu length - // Assume RAH format 2 - // adjust header lengths - header_len_dcch_tmp = header_len_dcch; - header_len_dtch_tmp = header_len_dtch; - if (header_len_dtch == 0) { - header_len_dcch = (header_len_dcch > 0) ? 1 : 0; //header_len_dcch; // remove length field - } else { - header_len_dtch_last -= 1; // now use it to find how many bytes has to be removed for the last MAC SDU - header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last : header_len_dtch; // remove length field for the last SDU - } - - mcs = eNB_UE_stats->dlsch_mcs1; - - if (mcs == 0) { - nb_rb = 4; // don't let the TBS get too small - } else { - nb_rb = min_rb_unit[CC_id]; - } - - TBS = get_TBS_DL(mcs, nb_rb); - - while (TBS < - (sdu_length_total + header_len_dcch + - header_len_dtch + ta_len)) { - nb_rb += min_rb_unit[CC_id]; // - - if (nb_rb > nb_available_rb) { // if we've gone beyond the maximum number of RBs - // (can happen if N_RB_DL is odd) - TBS = - get_TBS_DL(eNB_UE_stats->dlsch_mcs1, - nb_available_rb); - nb_rb = nb_available_rb; - break; - } - - TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_rb); - } - - if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { - for (j = 0; j < N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band - UE_list->UE_template[CC_id][UE_id]. - rballoc_subband[harq_pid][j] = - ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - } - } else { - nb_rb_temp = nb_rb; - j = 0; - - while ((nb_rb_temp > 0) && (j < N_RBG[CC_id])) { - if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == - 1) { - UE_list-> - UE_template[CC_id] - [UE_id].rballoc_subband[harq_pid][j] = - ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - - if ((j == N_RBG[CC_id] - 1) && - ((N_RB_DL[CC_id] == 25) || - (N_RB_DL[CC_id] == 50))) { - nb_rb_temp = - nb_rb_temp - min_rb_unit[CC_id] + - 1; - } else { - nb_rb_temp = - nb_rb_temp - min_rb_unit[CC_id]; - } - } - - j = j + 1; - } - } - - // decrease mcs until TBS falls below required length - while ((TBS > - (sdu_length_total + header_len_dcch + - header_len_dtch + ta_len)) && (mcs > 0)) { - mcs--; - TBS = get_TBS_DL(mcs, nb_rb); - } - - // if we have decreased too much or we don't have enough RBs, increase MCS - while ((TBS < - (sdu_length_total + header_len_dcch + - header_len_dtch + ta_len)) - && (((ue_sched_ctl->dl_pow_off[CC_id] > 0) - && (mcs < 28)) - || ((ue_sched_ctl->dl_pow_off[CC_id] == 0) - && (mcs <= 15)))) { - mcs++; - TBS = get_TBS_DL(mcs, nb_rb); - } - - LOG_D(MAC, - "dlsch_mcs before and after the rate matching = (%d, %d)\n", - eNB_UE_stats->dlsch_mcs1, mcs); - -#ifdef DEBUG_eNB_SCHEDULER - LOG_D(MAC, - "[eNB %d] CC_id %d Generated DLSCH header (mcs %d, TBS %d, nb_rb %d)\n", - module_idP, CC_id, mcs, TBS, nb_rb); - // msg("[MAC][eNB ] Reminder of DLSCH with random data %d %d %d %d \n", - // TBS, sdu_length_total, offset, TBS-sdu_length_total-offset); -#endif - - if ((TBS - header_len_dcch - header_len_dtch - - sdu_length_total - ta_len) <= 2) { - padding = - (TBS - header_len_dcch - header_len_dtch - - sdu_length_total - ta_len); - post_padding = 0; - } else { - padding = 0; - - // adjust the header len - if (header_len_dtch == 0) { - header_len_dcch = header_len_dcch_tmp; - } else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2))) - header_len_dtch = header_len_dtch_tmp; - } - - post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len; // 1 is for the postpadding header - } - - - offset = generate_dlsch_header((unsigned char *) UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], num_sdus, //num_sdus - sdu_lengths, // - sdu_lcids, 255, // no drx - ta_update, // timing advance - NULL, // contention res id - padding, post_padding); - - //#ifdef DEBUG_eNB_SCHEDULER - if (ta_update != 31) { - LOG_D(MAC, - "[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n", - module_idP, frameP, UE_id, CC_id, - sdu_length_total, num_sdus, sdu_lengths[0], - sdu_lcids[0], offset, ta_update, padding, - post_padding, mcs, TBS, nb_rb, - header_len_dcch, header_len_dtch); - } - //#endif -#ifdef DEBUG_eNB_SCHEDULER - LOG_T(MAC, "[eNB %d] First 16 bytes of DLSCH : \n"); - - for (i = 0; i < 16; i++) { - LOG_T(MAC, "%x.", dlsch_buffer[i]); - } - - LOG_T(MAC, "\n"); -#endif - - // cycle through SDUs and place in dlsch_buffer - memcpy(&UE_list-> - DLSCH_pdu[CC_id][0][UE_id].payload[0][offset], - dlsch_buffer, sdu_length_total); - // memcpy(RC.mac[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]); - - // fill remainder of DLSCH with random data - for (j = 0; j < (TBS - sdu_length_total - offset); j++) { - UE_list->DLSCH_pdu[CC_id][0][UE_id]. - payload[0][offset + sdu_length_total + j] = - (char) (taus() & 0xff); - } - - - if (opt_enabled == 1) { - trace_pdu(1, (uint8_t *) - UE_list->DLSCH_pdu[CC_id][0][UE_id]. - payload[0], TBS, module_idP, 3, - UE_RNTI(module_idP, UE_id), eNB->frame, - eNB->subframe, 0, 0); - LOG_D(OPT, - "[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n", - module_idP, CC_id, frameP, - UE_RNTI(module_idP, UE_id), TBS); - } - - T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), - T_INT(CC_id), T_INT(rnti), T_INT(frameP), - T_INT(subframeP), T_INT(harq_pid), - T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id]. - payload[0], TBS)); - - UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = - nb_rb; - - add_ue_dlsch_info(module_idP, - CC_id, UE_id, subframeP, - S_DL_SCHEDULED); - // store stats - eNB->eNB_stats[CC_id].dlsch_bytes_tx += - sdu_length_total; - eNB->eNB_stats[CC_id].dlsch_pdus_tx += 1; - - UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += - nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = - eNB_UE_stats->dlsch_mcs1; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = mcs; - UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; - - UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes = - TBS - sdu_length_total; - UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes += - sdu_length_total; - UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes += - TBS; - UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus += - 1; - - if (cc[CC_id].tdd_Config != NULL) { // TDD - UE_list->UE_template[CC_id][UE_id].DAI++; - update_ul_dci(module_idP, CC_id, rnti, - UE_list->UE_template[CC_id][UE_id]. - DAI); - } - // do PUCCH power control - // this is the normalized RX power - eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; - - /* TODO: fix how we deal with power, unit is not dBm, it's special from nfapi */ - normalized_rx_power = ue_sched_ctl->pucch1_snr[CC_id]; - target_rx_power = 208; - - // this assumes accumulated tpc - // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out - int32_t framex10psubframe = - UE_list->UE_template[CC_id][UE_id]. - pucch_tpc_tx_frame * 10 + - UE_list->UE_template[CC_id][UE_id]. - pucch_tpc_tx_subframe; - if (((framex10psubframe + 10) <= (frameP * 10 + subframeP)) || //normal case - ((framex10psubframe > (frameP * 10 + subframeP)) && (((10240 - framex10psubframe + frameP * 10 + subframeP) >= 10)))) //frame wrap-around - if (ue_sched_ctl->pucch1_cqi_update[CC_id] == 1) { - ue_sched_ctl->pucch1_cqi_update[CC_id] = 0; - - UE_list-> - UE_template[CC_id] - [UE_id].pucch_tpc_tx_frame = frameP; - UE_list-> - UE_template[CC_id] - [UE_id].pucch_tpc_tx_subframe = subframeP; - - if (normalized_rx_power > - (target_rx_power + 4)) { - tpc = 0; //-1 - tpc_accumulated--; - } else if (normalized_rx_power < - (target_rx_power - 4)) { - tpc = 2; //+1 - tpc_accumulated++; - } else { - tpc = 1; //0 - } - - LOG_D(MAC, - "[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", - module_idP, frameP, subframeP, harq_pid, - tpc, tpc_accumulated, - normalized_rx_power, target_rx_power); - - } // Po_PUCCH has been updated - else { - tpc = 1; //0 - } // time to do TPC update - else { - tpc = 1; //0 - } - - dl_config_pdu = - &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void *) dl_config_pdu, 0, - sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = - NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->pdu_size = - (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = - NFAPI_DL_DCI_FORMAT_1; - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.aggregation_level = - get_aggregation(get_bw_index(module_idP, CC_id), - ue_sched_ctl->dl_cqi[CC_id], - format1); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power - - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - harq_process = harq_pid; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; // dont adjust power when retransmitting - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.new_data_indicator_1 = - 1 - - UE_list->UE_template[CC_id][UE_id]. - oldNDI[harq_pid]; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.redundancy_version_1 = 0; - //deactivate second codeword - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_2 = 0; - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.redundancy_version_2 = 1; - if (cc[CC_id].tdd_Config != NULL) { //TDD - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.downlink_assignment_index = - (UE_list->UE_template[CC_id][UE_id].DAI - - 1) & 3; - LOG_D(MAC, - "[eNB %d] Initial transmission CC_id %d : harq_pid %d, dai %d, mcs %d\n", - module_idP, CC_id, harq_pid, - (UE_list->UE_template[CC_id][UE_id].DAI - 1), - mcs); - } else { - LOG_D(MAC, - "[eNB %d] Initial transmission CC_id %d : harq_pid %d, mcs %d\n", - module_idP, CC_id, harq_pid, mcs); - - } - LOG_D(MAC, "Checking feasibility pdu %d (new sdu)\n", - dl_req->number_pdu); - if (!CCE_allocation_infeasible - (module_idP, CC_id, 1, subframeP, - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.aggregation_level, rnti)) { - - - ue_sched_ctl->round[CC_id][harq_pid] = 0; - dl_req->number_dci++; - dl_req->number_pdu++; - dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; - - eNB->DL_req[CC_id].sfn_sf = frameP<<4 | subframeP; - eNB->DL_req[CC_id].header.message_id = NFAPI_DL_CONFIG_REQUEST; - - // Toggle NDI for next time - LOG_D(MAC, - "CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", - CC_id, frameP, subframeP, UE_id, rnti, - harq_pid, - UE_list-> - UE_template[CC_id][UE_id].oldNDI[harq_pid]); - - UE_list->UE_template[CC_id][UE_id]. - oldNDI[harq_pid] = - 1 - - UE_list->UE_template[CC_id][UE_id]. - oldNDI[harq_pid]; - UE_list->UE_template[CC_id][UE_id]. - oldmcs1[harq_pid] = mcs; - UE_list->UE_template[CC_id][UE_id]. - oldmcs2[harq_pid] = 0; - AssertFatal(UE_list->UE_template[CC_id] - [UE_id].physicalConfigDedicated != - NULL, - "physicalConfigDedicated is NULL\n"); - AssertFatal(UE_list->UE_template[CC_id] - [UE_id]. - physicalConfigDedicated->pdsch_ConfigDedicated - != NULL, - "physicalConfigDedicated->pdsch_ConfigDedicated is NULL\n"); - - fill_nfapi_dlsch_config(eNB, dl_req, TBS, eNB->pdu_index[CC_id], rnti, 0, // type 0 allocation from 7.1.6 in 36.213 - 0, // virtual_resource_block_assignment_flag, unused here - 0, // resource_block_coding, to be filled in later - getQm(mcs), 0, // redundancy version - 1, // transport blocks - 0, // transport block to codeword swap flag - cc[CC_id].p_eNB == 1 ? 0 : 1, // transmission_scheme - 1, // number of layers - 1, // number of subbands - // uint8_t codebook_index, - 4, // UE category capacity - UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated->p_a, 0, // delta_power_offset for TM5 - 0, // ngap - 0, // nprb - cc[CC_id].p_eNB == 1 ? 1 : 2, // transmission mode - 0, //number of PRBs treated as one subband, not used here - 0 // number of beamforming vectors, not used here - ); - eNB->TX_req[CC_id].sfn_sf = - fill_nfapi_tx_req(&eNB-> - TX_req - [CC_id].tx_request_body, - (frameP * 10) + subframeP, - TBS, eNB->pdu_index[CC_id], - eNB-> - UE_list.DLSCH_pdu[CC_id][0][(unsigned char) - UE_id].payload + } + + j = j + 1; + } + } + + nb_available_rb -= nb_rb; + /* + eNB->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; + eNB->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; + + for(j=0; jmu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; + } + */ + + switch (get_tmode(module_idP, CC_id, UE_id)) { + case 1: + case 2: + case 7: + default: + LOG_D(MAC,"retransmission DL_REQ: rnti:%x\n",rnti); + + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP, CC_id), + ue_sched_ctl->dl_cqi[CC_id], + format1); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = harq_pid; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // dont adjust power when retransmitting + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = round & 3; + + if (cc[CC_id].tdd_Config != NULL) { //TDD + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.downlink_assignment_index = (UE_list->UE_template[CC_id][UE_id].DAI - 1) & 3; + LOG_D(MAC, + "[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d, mcs %d\n", + module_idP, CC_id, harq_pid, round, + (UE_list->UE_template[CC_id][UE_id].DAI - 1), + UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]); + } else { + LOG_D(MAC, + "[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, mcs %d\n", + module_idP, CC_id, harq_pid, round, + UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]); + + } + if (!CCE_allocation_infeasible(module_idP, CC_id, 1, subframeP, + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, rnti)) { + dl_req->number_dci++; + dl_req->number_pdu++; + dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + + eNB->DL_req[CC_id].sfn_sf = frameP<<4 | subframeP; + eNB->DL_req[CC_id].header.message_id = NFAPI_DL_CONFIG_REQUEST; + + fill_nfapi_dlsch_config(eNB, dl_req, TBS, -1 + /* retransmission, no pdu_index */ + , rnti, 0, // type 0 allocation from 7.1.6 in 36.213 + 0, // virtual_resource_block_assignment_flag, unused here + 0, // resource_block_coding, to be filled in later + getQm(UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]), round & 3, // redundancy version + 1, // transport blocks + 0, // transport block to codeword swap flag + cc[CC_id].p_eNB == 1 ? 0 : 1, // transmission_scheme + 1, // number of layers + 1, // number of subbands + // uint8_t codebook_index, + 4, // UE category capacity + UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated->p_a, 0, // delta_power_offset for TM5 + 0, // ngap + 0, // nprb + cc[CC_id].p_eNB == 1 ? 1 : 2, // transmission mode + 0, //number of PRBs treated as one subband, not used here + 0 // number of beamforming vectors, not used here + ); + + LOG_D(MAC, + "Filled NFAPI configuration for DCI/DLSCH %d, retransmission round %d\n", + eNB->pdu_index[CC_id], round); + + program_dlsch_acknak(module_idP, CC_id, UE_id, + frameP, subframeP, + dl_config_pdu-> + dci_dl_pdu.dci_dl_pdu_rel8. + cce_idx); + // No TX request for retransmission (check if null request for FAPI) + } else { + LOG_W(MAC, + "Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d\%x, infeasible CCE allocation\n", + frameP, subframeP, UE_id, rnti); + } + } + + + add_ue_dlsch_info(module_idP, + CC_id, UE_id, subframeP, + S_DL_SCHEDULED); + + //eNB_UE_stats->dlsch_trials[round]++; + UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission += 1; + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx = nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx += nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = eNB_UE_stats->dlsch_mcs1; + } else { + LOG_D(MAC, + "[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", + module_idP, frameP, CC_id, UE_id); + } + } else { /* This is a potentially new SDU opportunity */ + + rlc_status.bytes_in_buffer = 0; + // Now check RLC information to compute number of required RBs + // get maximum TBS size for RLC request + TBS = + get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb); + // check first for RLC data on DCCH + // add the length for all the control elements (timing adv, drx, etc) : header + payload + + if (ue_sched_ctl->ta_timer == 0) { + ta_update = ue_sched_ctl->ta_update; + /* if we send TA then set timer to not send it for a while */ + if (ta_update != 31) ue_sched_ctl->ta_timer = 20; + /* reset ta_update */ + ue_sched_ctl->ta_update = 31; + } else { + ta_update = 31; + } + + ta_len = (ta_update != 31) ? 2 : 0; + + header_len_dcch = 2; // 2 bytes DCCH SDU subheader + + if (TBS - ta_len - header_len_dcch > 0) { + rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, (TBS - ta_len - header_len_dcch)); // transport block set size + + sdu_lengths[0] = 0; + + if (rlc_status.bytes_in_buffer > 0) { // There is DCCH to transmit + LOG_D(MAC, + "[eNB %d] SFN/SF %d.%d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n", + module_idP, frameP, subframeP, CC_id, + TBS - header_len_dcch); + sdu_lengths[0] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, TBS, //not used + (char *) + &dlsch_buffer [0]); - LOG_D(MAC, - "Filled NFAPI configuration for DCI/DLSCH/TXREQ %d, new SDU\n", - eNB->pdu_index[CC_id]); + T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), + T_INT(CC_id), T_INT(rnti), T_INT(frameP), + T_INT(subframeP), T_INT(harq_pid), T_INT(DCCH), + T_INT(sdu_lengths[0])); - eNB->pdu_index[CC_id]++; - program_dlsch_acknak(module_idP, CC_id, UE_id, - frameP, subframeP, - dl_config_pdu-> - dci_dl_pdu.dci_dl_pdu_rel8. - cce_idx); + LOG_D(MAC, + "[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n", + module_idP, CC_id, sdu_lengths[0]); + sdu_length_total = sdu_lengths[0]; + sdu_lcids[0] = DCCH; + UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH] += 1; + UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH] += sdu_lengths[0]; + num_sdus = 1; +#ifdef DEBUG_eNB_SCHEDULER + LOG_T(MAC, + "[eNB %d][DCCH] CC_id %d Got %d bytes :", + module_idP, CC_id, sdu_lengths[0]); - } else { - LOG_W(MAC, - "Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d/%x, infeasible CCE allocations\n", - frameP, subframeP, UE_id, rnti); - } - } else { // There is no data from RLC or MAC header, so don't schedule + for (j = 0; j < sdu_lengths[0]; j++) { + LOG_T(MAC, "%x ", dlsch_buffer[j]); + } + LOG_T(MAC, "\n"); +#endif + } else { + header_len_dcch = 0; + sdu_length_total = 0; + } + } + // check for DCCH1 and update header information (assume 2 byte sub-header) + if (TBS - ta_len - header_len_dcch - sdu_length_total > 0) { + rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, (TBS - ta_len - header_len_dcch - sdu_length_total)); // transport block set size less allocations for timing advance and + // DCCH SDU + sdu_lengths[num_sdus] = 0; + + if (rlc_status.bytes_in_buffer > 0) { + LOG_D(MAC, + "[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", + module_idP, frameP, CC_id, + TBS - header_len_dcch - sdu_length_total); + sdu_lengths[num_sdus] += mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, TBS, //not used + (char *) + &dlsch_buffer + [sdu_length_total]); + + T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), + T_INT(CC_id), T_INT(rnti), T_INT(frameP), + T_INT(subframeP), T_INT(harq_pid), + T_INT(DCCH + 1), T_INT(sdu_lengths[num_sdus])); + + sdu_lcids[num_sdus] = DCCH1; + sdu_length_total += sdu_lengths[num_sdus]; + header_len_dcch += 2; + UE_list->eNB_UE_stats[CC_id][UE_id]. + num_pdu_tx[DCCH1] += 1; + UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1] += sdu_lengths[num_sdus]; + num_sdus++; +#ifdef DEBUG_eNB_SCHEDULER + LOG_T(MAC, + "[eNB %d][DCCH1] CC_id %d Got %d bytes :", + module_idP, CC_id, sdu_lengths[num_sdus]); + + for (j = 0; j < sdu_lengths[num_sdus]; j++) { + LOG_T(MAC, "%x ", dlsch_buffer[j]); + } + + LOG_T(MAC, "\n"); +#endif + + } + } + // assume the max dtch header size, and adjust it later + header_len_dtch = 0; + header_len_dtch_last = 0; // the header length of the last mac sdu + // lcid has to be sorted before the actual allocation (similar struct as ue_list). + for (lcid = NB_RB_MAX - 1; lcid >= DTCH; lcid--) { + // TBD: check if the lcid is active + + header_len_dtch += 3; + header_len_dtch_last = 3; + LOG_D(MAC, + "[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n", + module_idP, frameP, lcid, TBS, + TBS - ta_len - header_len_dcch - + sdu_length_total - header_len_dtch); + + if (TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch > 0) { // NN: > 2 ? + rlc_status = mac_rlc_status_ind(module_idP, + rnti, + module_idP, + frameP, + subframeP, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + TBS - ta_len - + header_len_dcch - + sdu_length_total - + header_len_dtch); + + + if (rlc_status.bytes_in_buffer > 0) { + + LOG_D(MAC, + "[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n", + module_idP, frameP, + TBS - header_len_dcch - + sdu_length_total - header_len_dtch, lcid, + header_len_dtch); + sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, TBS, //not used + (char + *) + &dlsch_buffer + [sdu_length_total]); + T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), + T_INT(CC_id), T_INT(rnti), T_INT(frameP), + T_INT(subframeP), T_INT(harq_pid), + T_INT(lcid), T_INT(sdu_lengths[num_sdus])); + + LOG_D(MAC, + "[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n", + module_idP, sdu_lengths[num_sdus], lcid); + sdu_lcids[num_sdus] = lcid; + sdu_length_total += sdu_lengths[num_sdus]; + UE_list-> + eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid] + += 1; + UE_list-> + eNB_UE_stats[CC_id][UE_id].num_bytes_tx + [lcid] += sdu_lengths[num_sdus]; + if (sdu_lengths[num_sdus] < 128) { + header_len_dtch--; + header_len_dtch_last--; + } + num_sdus++; + UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0; + } // no data for this LCID + else { + header_len_dtch -= 3; + } + } // no TBS left + else { + header_len_dtch -= 3; + break; + } + } + if (header_len_dtch == 0) + header_len_dtch_last = 0; + // there is at least one SDU + // if (num_sdus > 0 ){ + if ((sdu_length_total + header_len_dcch + + header_len_dtch) > 0) { + + // Now compute number of required RBs for total sdu length + // Assume RAH format 2 + // adjust header lengths + header_len_dcch_tmp = header_len_dcch; + header_len_dtch_tmp = header_len_dtch; + if (header_len_dtch == 0) { + header_len_dcch = (header_len_dcch > 0) ? 1 : 0; //header_len_dcch; // remove length field + } else { + header_len_dtch_last -= 1; // now use it to find how many bytes has to be removed for the last MAC SDU + header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last : header_len_dtch; // remove length field for the last SDU + } + + mcs = eNB_UE_stats->dlsch_mcs1; + + if (mcs == 0) { + nb_rb = 4; // don't let the TBS get too small + } else { + nb_rb = min_rb_unit[CC_id]; + } + + TBS = get_TBS_DL(mcs, nb_rb); + + while (TBS < + (sdu_length_total + header_len_dcch + + header_len_dtch + ta_len)) { + nb_rb += min_rb_unit[CC_id]; // + + if (nb_rb > nb_available_rb) { // if we've gone beyond the maximum number of RBs + // (can happen if N_RB_DL is odd) + TBS = + get_TBS_DL(eNB_UE_stats->dlsch_mcs1, + nb_available_rb); + nb_rb = nb_available_rb; + break; + } + + TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_rb); + } + + if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { + for (j = 0; j < N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band + UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + } + } else { + nb_rb_temp = nb_rb; + j = 0; + + while ((nb_rb_temp > 0) && (j < N_RBG[CC_id])) { + if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { + UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + + if ((j == N_RBG[CC_id] - 1) && + ((N_RB_DL[CC_id] == 25) || + (N_RB_DL[CC_id] == 50))) { + nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id] + 1; + } else { + nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; } + } + + j = j + 1; + } + } + + // decrease mcs until TBS falls below required length + while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs > 0)) { + mcs--; + TBS = get_TBS_DL(mcs, nb_rb); + } + + // if we have decreased too much or we don't have enough RBs, increase MCS + while ((TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) + && (((ue_sched_ctl->dl_pow_off[CC_id] > 0) + && (mcs < 28)) + || ((ue_sched_ctl->dl_pow_off[CC_id] == 0) + && (mcs <= 15)))) { + mcs++; + TBS = get_TBS_DL(mcs, nb_rb); + } + + LOG_D(MAC, + "dlsch_mcs before and after the rate matching = (%d, %d)\n", + eNB_UE_stats->dlsch_mcs1, mcs); + +#ifdef DEBUG_eNB_SCHEDULER + LOG_D(MAC, + "[eNB %d] CC_id %d Generated DLSCH header (mcs %d, TBS %d, nb_rb %d)\n", + module_idP, CC_id, mcs, TBS, nb_rb); + // msg("[MAC][eNB ] Reminder of DLSCH with random data %d %d %d %d \n", + // TBS, sdu_length_total, offset, TBS-sdu_length_total-offset); +#endif + + if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2) { + padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); + post_padding = 0; + } else { + padding = 0; + + // adjust the header len + if (header_len_dtch == 0) { + header_len_dcch = header_len_dcch_tmp; + } else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2))) + header_len_dtch = header_len_dtch_tmp; } - if (cc[CC_id].tdd_Config != NULL) { // TDD - set_ul_DAI(module_idP, UE_id, CC_id, frameP, subframeP); - } + post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len; // 1 is for the postpadding header + } - } // UE_id loop - } // CC_id loop + + offset = generate_dlsch_header((unsigned char *) UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], num_sdus, //num_sdus + sdu_lengths, // + sdu_lcids, 255, // no drx + ta_update, // timing advance + NULL, // contention res id + padding, post_padding); + + //#ifdef DEBUG_eNB_SCHEDULER + if (ta_update != 31) { + LOG_D(MAC, + "[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n", + module_idP, frameP, UE_id, CC_id, + sdu_length_total, num_sdus, sdu_lengths[0], + sdu_lcids[0], offset, ta_update, padding, + post_padding, mcs, TBS, nb_rb, + header_len_dcch, header_len_dtch); + } + //#endif +#ifdef DEBUG_eNB_SCHEDULER + LOG_T(MAC, "[eNB %d] First 16 bytes of DLSCH : \n"); + + for (i = 0; i < 16; i++) { + LOG_T(MAC, "%x.", dlsch_buffer[i]); + } + + LOG_T(MAC, "\n"); +#endif + + // cycle through SDUs and place in dlsch_buffer + memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset], + dlsch_buffer, sdu_length_total); + // memcpy(RC.mac[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]); + + // fill remainder of DLSCH with random data + for (j = 0; j < (TBS - sdu_length_total - offset); j++) { + UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset + sdu_length_total + j] = (char) (taus() & 0xff); + } + + + if (opt_enabled == 1) { + trace_pdu(1, (uint8_t *) + UE_list->DLSCH_pdu[CC_id][0][UE_id]. + payload[0], TBS, module_idP, 3, + UE_RNTI(module_idP, UE_id), eNB->frame, + eNB->subframe, 0, 0); + LOG_D(OPT, + "[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n", + module_idP, CC_id, frameP, + UE_RNTI(module_idP, UE_id), TBS); + } + + T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), + T_INT(CC_id), T_INT(rnti), T_INT(frameP), + T_INT(subframeP), T_INT(harq_pid), + T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id]. + payload[0], TBS)); + + UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; + + add_ue_dlsch_info(module_idP, + CC_id, UE_id, subframeP, + S_DL_SCHEDULED); + // store stats + eNB->eNB_stats[CC_id].dlsch_bytes_tx += sdu_length_total; + eNB->eNB_stats[CC_id].dlsch_pdus_tx += 1; + + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = mcs; + UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; + + UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes = TBS - sdu_length_total; + UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes += sdu_length_total; + UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes += TBS; + UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus += 1; + + if (cc[CC_id].tdd_Config != NULL) { // TDD + UE_list->UE_template[CC_id][UE_id].DAI++; + update_ul_dci(module_idP, CC_id, rnti, + UE_list->UE_template[CC_id][UE_id]. + DAI); + } + // do PUCCH power control + // this is the normalized RX power + eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; + + /* TODO: fix how we deal with power, unit is not dBm, it's special from nfapi */ + normalized_rx_power = ue_sched_ctl->pucch1_snr[CC_id]; + target_rx_power = 208; + + // this assumes accumulated tpc + // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out + int32_t framex10psubframe = UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame * 10 + UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe; + if (((framex10psubframe + 10) <= (frameP * 10 + subframeP)) || //normal case + ((framex10psubframe > (frameP * 10 + subframeP)) && (((10240 - framex10psubframe + frameP * 10 + subframeP) >= 10)))) //frame wrap-around + if (ue_sched_ctl->pucch1_cqi_update[CC_id] == 1) { + ue_sched_ctl->pucch1_cqi_update[CC_id] = 0; + + UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame = frameP; + UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe = subframeP; + + if (normalized_rx_power > (target_rx_power + 4)) { + tpc = 0; //-1 + tpc_accumulated--; + } else if (normalized_rx_power < (target_rx_power - 4)) { + tpc = 2; //+1 + tpc_accumulated++; + } else { + tpc = 1; //0 + } + + LOG_D(MAC, + "[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", + module_idP, frameP, subframeP, harq_pid, + tpc, tpc_accumulated, + normalized_rx_power, target_rx_power); + + } // Po_PUCCH has been updated + else { + tpc = 1; //0 + } // time to do TPC update + else { + tpc = 1; //0 + } + + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP, CC_id), + ue_sched_ctl->dl_cqi[CC_id], + format1); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = harq_pid; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; // dont adjust power when retransmitting + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = 0; + //deactivate second codeword + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_2 = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_2 = 1; + if (cc[CC_id].tdd_Config != NULL) { //TDD + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.downlink_assignment_index = (UE_list->UE_template[CC_id][UE_id].DAI - 1) & 3; + LOG_D(MAC, + "[eNB %d] Initial transmission CC_id %d : harq_pid %d, dai %d, mcs %d\n", + module_idP, CC_id, harq_pid, + (UE_list->UE_template[CC_id][UE_id].DAI - 1), + mcs); + } else { + LOG_D(MAC, + "[eNB %d] Initial transmission CC_id %d : harq_pid %d, mcs %d\n", + module_idP, CC_id, harq_pid, mcs); + + } + LOG_D(MAC, "Checking feasibility pdu %d (new sdu)\n", + dl_req->number_pdu); + if (!CCE_allocation_infeasible(module_idP, CC_id, 1, subframeP, + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.aggregation_level, rnti)) { + + + ue_sched_ctl->round[CC_id][harq_pid] = 0; + dl_req->number_dci++; + dl_req->number_pdu++; + dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + + eNB->DL_req[CC_id].sfn_sf = frameP<<4 | subframeP; + eNB->DL_req[CC_id].header.message_id = NFAPI_DL_CONFIG_REQUEST; + + // Toggle NDI for next time + LOG_D(MAC, + "CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", + CC_id, frameP, subframeP, UE_id, rnti, + harq_pid, + UE_list-> + UE_template[CC_id][UE_id].oldNDI[harq_pid]); + + UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid] = mcs; + UE_list->UE_template[CC_id][UE_id].oldmcs2[harq_pid] = 0; + AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != + NULL, + "physicalConfigDedicated is NULL\n"); + AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated != NULL, + "physicalConfigDedicated->pdsch_ConfigDedicated is NULL\n"); + + fill_nfapi_dlsch_config(eNB, dl_req, TBS, eNB->pdu_index[CC_id], rnti, 0, // type 0 allocation from 7.1.6 in 36.213 + 0, // virtual_resource_block_assignment_flag, unused here + 0, // resource_block_coding, to be filled in later + getQm(mcs), 0, // redundancy version + 1, // transport blocks + 0, // transport block to codeword swap flag + cc[CC_id].p_eNB == 1 ? 0 : 1, // transmission_scheme + 1, // number of layers + 1, // number of subbands + // uint8_t codebook_index, + 4, // UE category capacity + UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated->p_a, 0, // delta_power_offset for TM5 + 0, // ngap + 0, // nprb + cc[CC_id].p_eNB == 1 ? 1 : 2, // transmission mode + 0, //number of PRBs treated as one subband, not used here + 0 // number of beamforming vectors, not used here + ); + eNB->TX_req[CC_id].sfn_sf = fill_nfapi_tx_req(&eNB-> + TX_req + [CC_id].tx_request_body, + (frameP * 10) + subframeP, + TBS, eNB->pdu_index[CC_id], + eNB-> + UE_list.DLSCH_pdu[CC_id][0][(unsigned char) + UE_id].payload + [0]); + + LOG_D(MAC, + "Filled NFAPI configuration for DCI/DLSCH/TXREQ %d, new SDU\n", + eNB->pdu_index[CC_id]); + + eNB->pdu_index[CC_id]++; + program_dlsch_acknak(module_idP, CC_id, UE_id, + frameP, subframeP, + dl_config_pdu-> + dci_dl_pdu.dci_dl_pdu_rel8. + cce_idx); + + } else { + LOG_W(MAC, + "Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d/%x, infeasible CCE allocations\n", + frameP, subframeP, UE_id, rnti); + } + } else { // There is no data from RLC or MAC header, so don't schedule + + } + } + + if (cc[CC_id].tdd_Config != NULL) { // TDD + set_ul_DAI(module_idP, UE_id, CC_id, frameP, subframeP); + } + + } // UE_id loop + } // CC_id loop - fill_DLSCH_dci(module_idP, frameP, subframeP, mbsfn_flag); + fill_DLSCH_dci(module_idP, frameP, subframeP, mbsfn_flag); - stop_meas(&eNB->schedule_dlsch); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_OUT); + stop_meas(&eNB->schedule_dlsch); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_OUT); } @@ -1531,111 +1396,84 @@ fill_DLSCH_dci(module_id_t module_idP, //------------------------------------------------------------------------------ { - // loop over all allocated UEs and compute frequency allocations for PDSCH - int UE_id = -1; - uint8_t /* first_rb, */ nb_rb = 3; - rnti_t rnti; - //unsigned char *vrb_map; - uint8_t rballoc_sub[25]; - //uint8_t number_of_subbands=13; + // loop over all allocated UEs and compute frequency allocations for PDSCH + int UE_id = -1; + uint8_t /* first_rb, */ nb_rb = 3; + rnti_t rnti; + //unsigned char *vrb_map; + uint8_t rballoc_sub[25]; + //uint8_t number_of_subbands=13; - //unsigned char round; - unsigned char harq_pid; - int i; - int CC_id; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - UE_list_t *UE_list = &eNB->UE_list; - int N_RBG; - int N_RB_DL; - COMMON_channels_t *cc; + //unsigned char round; + unsigned char harq_pid; + int i; + int CC_id; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + UE_list_t *UE_list = &eNB->UE_list; + int N_RBG; + int N_RB_DL; + COMMON_channels_t *cc; - start_meas(&eNB->fill_DLSCH_dci); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI, VCD_FUNCTION_IN); + start_meas(&eNB->fill_DLSCH_dci); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI, VCD_FUNCTION_IN); - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - LOG_D(MAC, "Doing fill DCI for CC_id %d\n", CC_id); + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + LOG_D(MAC, "Doing fill DCI for CC_id %d\n", CC_id); - if (mbsfn_flagP[CC_id] > 0) - continue; + if (mbsfn_flagP[CC_id] > 0) + continue; - cc = &eNB->common_channels[CC_id]; - N_RBG = to_rbg(cc->mib->message.dl_Bandwidth); - N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); + cc = &eNB->common_channels[CC_id]; + N_RBG = to_rbg(cc->mib->message.dl_Bandwidth); + N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); - // UE specific DCIs - for (UE_id = UE_list->head; UE_id >= 0; - UE_id = UE_list->next[UE_id]) { - LOG_T(MAC, "CC_id %d, UE_id: %d => status %d\n", CC_id, UE_id, - eNB_dlsch_info[module_idP][CC_id][UE_id].status); + // UE specific DCIs + for (UE_id = UE_list->head; UE_id >= 0; + UE_id = UE_list->next[UE_id]) { + LOG_T(MAC, "CC_id %d, UE_id: %d => status %d\n", CC_id, UE_id, + eNB_dlsch_info[module_idP][CC_id][UE_id].status); - if (eNB_dlsch_info[module_idP][CC_id][UE_id].status == - S_DL_SCHEDULED) { + if (eNB_dlsch_info[module_idP][CC_id][UE_id].status == S_DL_SCHEDULED) { - // clear scheduling flag - eNB_dlsch_info[module_idP][CC_id][UE_id].status = - S_DL_WAITING; - rnti = UE_RNTI(module_idP, UE_id); - if (cc->tdd_Config) - harq_pid = ((frameP * 10) + subframeP) % 10; - else - harq_pid = ((frameP * 10) + subframeP) & 7; - nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + // clear scheduling flag + eNB_dlsch_info[module_idP][CC_id][UE_id].status = S_DL_WAITING; + rnti = UE_RNTI(module_idP, UE_id); + if (cc->tdd_Config) harq_pid = ((frameP * 10) + subframeP) % 10; + else harq_pid = ((frameP * 10) + subframeP) & 7; + nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - - - /// Synchronizing rballoc with rballoc_sub - for (i = 0; i < N_RBG; i++) { - rballoc_sub[i] = - UE_list-> - UE_template[CC_id][UE_id].rballoc_subband[harq_pid] - [i]; - } - - nfapi_dl_config_request_t *DL_req = - &RC.mac[module_idP]->DL_req[0]; - nfapi_dl_config_request_pdu_t *dl_config_pdu; - - for (i = 0; - i < DL_req[CC_id].dl_config_request_body.number_pdu; - i++) { - dl_config_pdu = - &DL_req[CC_id]. - dl_config_request_body.dl_config_pdu_list[i]; - if ((dl_config_pdu->pdu_type == - NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) - && (dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8. - rnti == rnti) - && (dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.dci_format != 1)) { - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.resource_block_coding = - allocate_prbs_sub(nb_rb, N_RB_DL, N_RBG, - rballoc_sub); - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.resource_allocation_type = 0; - } else - if ((dl_config_pdu->pdu_type == - NFAPI_DL_CONFIG_DLSCH_PDU_TYPE) - && (dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8. - rnti == rnti) - && (dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.resource_allocation_type == - 0)) { - dl_config_pdu->dlsch_pdu. - dlsch_pdu_rel8.resource_block_coding = - allocate_prbs_sub(nb_rb, N_RB_DL, N_RBG, - rballoc_sub); - } - } - } + /// Synchronizing rballoc with rballoc_sub + for (i = 0; i < N_RBG; i++) { + rballoc_sub[i] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][i]; } + nfapi_dl_config_request_t *DL_req = &RC.mac[module_idP]->DL_req[0]; + nfapi_dl_config_request_pdu_t *dl_config_pdu; + + for (i = 0; + i < DL_req[CC_id].dl_config_request_body.number_pdu; + i++) { + dl_config_pdu = &DL_req[CC_id].dl_config_request_body.dl_config_pdu_list[i]; + if ((dl_config_pdu->pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) + && (dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti == rnti) + && (dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format != 1)) { + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = allocate_prbs_sub(nb_rb, N_RB_DL, N_RBG,rballoc_sub); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_allocation_type = 0; + } else + if ((dl_config_pdu->pdu_type == NFAPI_DL_CONFIG_DLSCH_PDU_TYPE) + && (dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti == rnti) + && (dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type == 0)) { + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding =allocate_prbs_sub(nb_rb, N_RB_DL, N_RBG,rballoc_sub); + } + } + } } - stop_meas(&eNB->fill_DLSCH_dci); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI, VCD_FUNCTION_OUT); + } + + stop_meas(&eNB->fill_DLSCH_dci); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI, VCD_FUNCTION_OUT); } //------------------------------------------------------------------------------ @@ -1645,37 +1483,35 @@ unsigned char *get_dlsch_sdu(module_id_t module_idP, //------------------------------------------------------------------------------ { - int UE_id; - eNB_MAC_INST *eNB = RC.mac[module_idP]; + int UE_id; + eNB_MAC_INST *eNB = RC.mac[module_idP]; - if (rntiP == SI_RNTI) { - LOG_D(MAC, "[eNB %d] CC_id %d Frame %d Get DLSCH sdu for BCCH \n", - module_idP, CC_id, frameP); + if (rntiP == SI_RNTI) { + LOG_D(MAC, "[eNB %d] CC_id %d Frame %d Get DLSCH sdu for BCCH \n", + module_idP, CC_id, frameP); - return ((unsigned char *) &eNB->common_channels[CC_id]. - BCCH_pdu.payload[0]); - } + return ((unsigned char *) &eNB->common_channels[CC_id].BCCH_pdu.payload[0]); + } - if (rntiP==P_RNTI) { - LOG_D(MAC,"[eNB %d] CC_id %d Frame %d Get PCH sdu for PCCH \n", module_idP, CC_id, frameP); + if (rntiP==P_RNTI) { + LOG_D(MAC,"[eNB %d] CC_id %d Frame %d Get PCH sdu for PCCH \n", module_idP, CC_id, frameP); - return((unsigned char *)&eNB->common_channels[CC_id].PCCH_pdu.payload[0]); - } + return((unsigned char *)&eNB->common_channels[CC_id].PCCH_pdu.payload[0]); + } UE_id = find_UE_id(module_idP,rntiP); - if (UE_id != -1) { - LOG_D(MAC, - "[eNB %d] Frame %d: CC_id %d Get DLSCH sdu for rnti %x => UE_id %d\n", - module_idP, frameP, CC_id, rntiP, UE_id); - return ((unsigned char *) &eNB-> - UE_list.DLSCH_pdu[CC_id][TBindex][UE_id].payload[0]); - } else { - LOG_E(MAC, - "[eNB %d] Frame %d: CC_id %d UE with RNTI %x does not exist\n", - module_idP, frameP, CC_id, rntiP); - return NULL; - } + if (UE_id != -1) { + LOG_D(MAC, + "[eNB %d] Frame %d: CC_id %d Get DLSCH sdu for rnti %x => UE_id %d\n", + module_idP, frameP, CC_id, rntiP, UE_id); + return ((unsigned char *) &eNB->UE_list.DLSCH_pdu[CC_id][TBindex][UE_id].payload[0]); + } else { + LOG_E(MAC, + "[eNB %d] Frame %d: CC_id %d UE with RNTI %x does not exist\n", + module_idP, frameP, CC_id, rntiP); + return NULL; + } } @@ -1687,27 +1523,25 @@ update_ul_dci(module_id_t module_idP, //------------------------------------------------------------------------------ { - nfapi_hi_dci0_request_t *HI_DCI0_req = - &RC.mac[module_idP]->HI_DCI0_req[CC_idP]; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = - &HI_DCI0_req->hi_dci0_request_body.hi_dci0_pdu_list[0]; - COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_idP]; - int i; + nfapi_hi_dci0_request_t *HI_DCI0_req = + &RC.mac[module_idP]->HI_DCI0_req[CC_idP]; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = + &HI_DCI0_req->hi_dci0_request_body.hi_dci0_pdu_list[0]; + COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_idP]; + int i; - if (cc->tdd_Config != NULL) { // TDD - for (i = 0; - i < - HI_DCI0_req->hi_dci0_request_body.number_of_dci + - HI_DCI0_req->hi_dci0_request_body.number_of_dci; i++) { + if (cc->tdd_Config != NULL) { // TDD + for (i = 0; + i hi_dci0_request_body.number_of_dci + HI_DCI0_req->hi_dci0_request_body.number_of_dci; + i++) { - if ((hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) && - (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti == rntiP)) - hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.dl_assignment_index = - (daiP - 1) & 3; + if ((hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) && + (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti == rntiP)) + hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.dl_assignment_index = (daiP - 1) & 3; - } } + } } @@ -1718,64 +1552,64 @@ set_ue_dai(sub_frame_t subframeP, UE_list_t * UE_list) //------------------------------------------------------------------------------ { - switch (tdd_config) { - case 0: - if ((subframeP == 0) || (subframeP == 1) || (subframeP == 3) - || (subframeP == 5) || (subframeP == 6) || (subframeP == 8)) { - UE_list->UE_template[CC_id][UE_id].DAI = 0; - } - - break; - - case 1: - if ((subframeP == 0) || (subframeP == 4) || (subframeP == 5) - || (subframeP == 9)) { - UE_list->UE_template[CC_id][UE_id].DAI = 0; - } - - break; - - case 2: - if ((subframeP == 4) || (subframeP == 5)) { - UE_list->UE_template[CC_id][UE_id].DAI = 0; - } - - break; - - case 3: - if ((subframeP == 5) || (subframeP == 7) || (subframeP == 9)) { - UE_list->UE_template[CC_id][UE_id].DAI = 0; - } - - break; - - case 4: - if ((subframeP == 0) || (subframeP == 6)) { - UE_list->UE_template[CC_id][UE_id].DAI = 0; - } - - break; - - case 5: - if (subframeP == 9) { - UE_list->UE_template[CC_id][UE_id].DAI = 0; - } - - break; - - case 6: - if ((subframeP == 0) || (subframeP == 1) || (subframeP == 5) - || (subframeP == 6) || (subframeP == 9)) { - UE_list->UE_template[CC_id][UE_id].DAI = 0; - } - - break; - - default: - UE_list->UE_template[CC_id][UE_id].DAI = 0; - LOG_N(MAC, "unknow TDD config %d\n", tdd_config); - break; + switch (tdd_config) { + case 0: + if ((subframeP == 0) || (subframeP == 1) || (subframeP == 3) + || (subframeP == 5) || (subframeP == 6) || (subframeP == 8)) { + UE_list->UE_template[CC_id][UE_id].DAI = 0; } + + break; + + case 1: + if ((subframeP == 0) || (subframeP == 4) || (subframeP == 5) + || (subframeP == 9)) { + UE_list->UE_template[CC_id][UE_id].DAI = 0; + } + + break; + + case 2: + if ((subframeP == 4) || (subframeP == 5)) { + UE_list->UE_template[CC_id][UE_id].DAI = 0; + } + + break; + + case 3: + if ((subframeP == 5) || (subframeP == 7) || (subframeP == 9)) { + UE_list->UE_template[CC_id][UE_id].DAI = 0; + } + + break; + + case 4: + if ((subframeP == 0) || (subframeP == 6)) { + UE_list->UE_template[CC_id][UE_id].DAI = 0; + } + + break; + + case 5: + if (subframeP == 9) { + UE_list->UE_template[CC_id][UE_id].DAI = 0; + } + + break; + + case 6: + if ((subframeP == 0) || (subframeP == 1) || (subframeP == 5) + || (subframeP == 6) || (subframeP == 9)) { + UE_list->UE_template[CC_id][UE_id].DAI = 0; + } + + break; + + default: + UE_list->UE_template[CC_id][UE_id].DAI = 0; + LOG_N(MAC, "unknow TDD config %d\n", tdd_config); + break; + } } void schedule_PCH(module_id_t module_idP,frame_t frameP,sub_frame_t subframeP) @@ -1796,22 +1630,22 @@ void schedule_PCH(module_id_t module_idP,frame_t frameP,sub_frame_t subframeP) #ifdef FORMAT1C int gap_index = 0; /* indicate which gap(1st or 2nd) is used (0:1st) */ const int GAP_MAP [9][2] = { - {-1, 0}, /* N_RB_DL [6-10] -1: |N_RB/2| 0: N/A*/ - {4, 0}, /* N_RB_DL [11] */ - {8, 0}, /* N_RB_DL [12-19] */ - {12, 0}, /* N_RB_DL [20-26] */ - {18, 0}, /* N_RB_DL [27-44] */ - {27, 0}, /* N_RB_DL [45-49] */ - {27, 9}, /* N_RB_DL [50-63] */ - {32, 16}, /* N_RB_DL [64-79] */ - {48, 16} /* N_RB_DL [80-110] */ - }; + {-1, 0}, /* N_RB_DL [6-10] -1: |N_RB/2| 0: N/A*/ + {4, 0}, /* N_RB_DL [11] */ + {8, 0}, /* N_RB_DL [12-19] */ + {12, 0}, /* N_RB_DL [20-26] */ + {18, 0}, /* N_RB_DL [27-44] */ + {27, 0}, /* N_RB_DL [45-49] */ + {27, 9}, /* N_RB_DL [50-63] */ + {32, 16}, /* N_RB_DL [64-79] */ + {48, 16} /* N_RB_DL [80-110] */ + }; uint8_t n_rb_step = 0; uint8_t n_gap = 0; uint8_t n_vrb_dl = 0; uint8_t Lcrbs = 0; uint16_t rb_bit = 168; /* RB bit number value is unsure */ - #endif +#endif start_meas(&eNB->schedule_pch); @@ -1825,298 +1659,298 @@ void schedule_PCH(module_id_t module_idP,frame_t frameP,sub_frame_t subframeP) continue; } if (frameP % UE_PF_PO[CC_id][i].T == UE_PF_PO[CC_id][i].PF_min && subframeP == UE_PF_PO[CC_id][i].PO) { - pcch_sdu_length = mac_rrc_data_req(module_idP, + pcch_sdu_length = mac_rrc_data_req(module_idP, CC_id, frameP, PCCH,1, &cc->PCCH_pdu.payload[0], i); // used for ue index - if (pcch_sdu_length == 0) { - LOG_D(MAC,"[eNB %d] Frame %d subframe %d: PCCH not active(size = 0 byte)\n", module_idP,frameP, subframeP); - continue; - } - LOG_D(MAC,"[eNB %d] Frame %d subframe %d: PCCH->PCH CC_id %d UE_id %d, Received %d bytes \n", module_idP, frameP, subframeP, CC_id,i, pcch_sdu_length); + if (pcch_sdu_length == 0) { + LOG_D(MAC,"[eNB %d] Frame %d subframe %d: PCCH not active(size = 0 byte)\n", module_idP,frameP, subframeP); + continue; + } + LOG_D(MAC,"[eNB %d] Frame %d subframe %d: PCCH->PCH CC_id %d UE_id %d, Received %d bytes \n", module_idP, frameP, subframeP, CC_id,i, pcch_sdu_length); #ifdef FORMAT1C - //NO SIB - if ((subframeP == 1 || subframeP == 2 || subframeP == 4 || subframeP == 6 || subframeP == 9) || - (subframeP == 5 && ((frameP % 2) != 0 && (frameP % 8) != 1))) { - switch (n_rb_dl) { + //NO SIB + if ((subframeP == 1 || subframeP == 2 || subframeP == 4 || subframeP == 6 || subframeP == 9) || + (subframeP == 5 && ((frameP % 2) != 0 && (frameP % 8) != 1))) { + switch (n_rb_dl) { #if 0 - case 6: - n_gap = n_rb_dl/2; /* expect: 3 */ - n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap));; /* expect: 6 */ - first_rb = 0; - break; - case 15: - n_gap = GAP_MAP[2][0]; /* expect: 8 */ - n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 14 */ - first_rb = 6; - break; + case 6: + n_gap = n_rb_dl/2; /* expect: 3 */ + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap));; /* expect: 6 */ + first_rb = 0; + break; + case 15: + n_gap = GAP_MAP[2][0]; /* expect: 8 */ + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 14 */ + first_rb = 6; + break; #endif - case 25: - n_gap = GAP_MAP[3][0]; /* expect: 12 */ - n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 24 */ - first_rb = 10; - break; - case 50: - n_gap = GAP_MAP[6][gap_index]; /* expect: 27 or 9 */ - if (gap_index > 0) { - n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap); /* 36 */ - } else { - n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 46 */ - } - first_rb = 24; - break; - case 100: - n_gap = GAP_MAP[8][gap_index]; /* expect: 48 or 16 */ - if (gap_index > 0) { - n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap); /* expect: 96 */ - } else { - n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 96 */ - } - first_rb = 48; - break; - } - } else if (subframeP == 5 && ((frameP % 2) == 0 || (frameP % 8) == 1)) { // SIB + paging - switch (n_rb_dl) { + case 25: + n_gap = GAP_MAP[3][0]; /* expect: 12 */ + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 24 */ + first_rb = 10; + break; + case 50: + n_gap = GAP_MAP[6][gap_index]; /* expect: 27 or 9 */ + if (gap_index > 0) { + n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap); /* 36 */ + } else { + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 46 */ + } + first_rb = 24; + break; + case 100: + n_gap = GAP_MAP[8][gap_index]; /* expect: 48 or 16 */ + if (gap_index > 0) { + n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap); /* expect: 96 */ + } else { + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 96 */ + } + first_rb = 48; + break; + } + } else if (subframeP == 5 && ((frameP % 2) == 0 || (frameP % 8) == 1)) { // SIB + paging + switch (n_rb_dl) { #if 0 - case 6: - n_gap = n_rb_dl/2; /* expect: 3 */ - n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap));; /* expect: 6 */ - first_rb = 0; - break; - case 15: - n_gap = GAP_MAP[2][0]; /* expect: 8 */ - n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 14 */ - first_rb = 10; - break; + case 6: + n_gap = n_rb_dl/2; /* expect: 3 */ + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap));; /* expect: 6 */ + first_rb = 0; + break; + case 15: + n_gap = GAP_MAP[2][0]; /* expect: 8 */ + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 14 */ + first_rb = 10; + break; #endif - case 25: - n_gap = GAP_MAP[3][0]; /* expect: 12 */ - n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 24 */ - first_rb = 14; - break; - case 50: - n_gap = GAP_MAP[6][gap_index]; /* expect: 27 or 9 */ - if (gap_index > 0) { - n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap); /* 36 */ - } else { - n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 46 */ - } - first_rb = 28; - break; - case 100: - n_gap = GAP_MAP[8][gap_index]; /* expect: 48 or 16 */ - if (gap_index > 0) { - n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap); /* expect: 96 */ - } else { - n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 96 */ - } - first_rb = 52; - break; - } - } - /* Get MCS for length of PCH */ - if (pcch_sdu_length <= TBStable1C[0]) { - mcs=0; - } else if (pcch_sdu_length <= TBStable1C[1]) { - mcs=1; - } else if (pcch_sdu_length <= TBStable1C[2]) { - mcs=2; - } else if (pcch_sdu_length <= TBStable1C[3]) { - mcs=3; - } else if (pcch_sdu_length <= TBStable1C[4]) { - mcs=4; - } else if (pcch_sdu_length <= TBStable1C[5]) { - mcs=5; - } else if (pcch_sdu_length <= TBStable1C[6]) { - mcs=6; - } else if (pcch_sdu_length <= TBStable1C[7]) { - mcs=7; - } else if (pcch_sdu_length <= TBStable1C[8]) { - mcs=8; - } else if (pcch_sdu_length <= TBStable1C[9]) { - mcs=9; - } else { - /* unexpected: pcch sdb size is over max value*/ - LOG_E(MAC,"[eNB %d] Frame %d : PCCH->PCH CC_id %d, Received %d bytes is over max length(256) \n", - module_idP, frameP,CC_id, pcch_sdu_length); - return; - } - rb_num = TBStable1C[mcs] / rb_bit + ( (TBStable1C[mcs] % rb_bit == 0)? 0: 1) + 1; - /* calculate N_RB_STEP and Lcrbs */ - if (n_rb_dl < 50) { - n_rb_step = 2; - Lcrbs = rb_num / 2 + ((rb_num % 2 == 0) ? 0:2); - } else { - n_rb_step = 4; - Lcrbs = rb_num / 4 + ((rb_num % 4 == 0) ? 0:4); - } - for(i = 0;i < Lcrbs ;i++){ - vrb_map[first_rb+i] = 1; - } + case 25: + n_gap = GAP_MAP[3][0]; /* expect: 12 */ + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 24 */ + first_rb = 14; + break; + case 50: + n_gap = GAP_MAP[6][gap_index]; /* expect: 27 or 9 */ + if (gap_index > 0) { + n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap); /* 36 */ + } else { + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 46 */ + } + first_rb = 28; + break; + case 100: + n_gap = GAP_MAP[8][gap_index]; /* expect: 48 or 16 */ + if (gap_index > 0) { + n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap); /* expect: 96 */ + } else { + n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap)); /* expect: 96 */ + } + first_rb = 52; + break; + } + } + /* Get MCS for length of PCH */ + if (pcch_sdu_length <= TBStable1C[0]) { + mcs=0; + } else if (pcch_sdu_length <= TBStable1C[1]) { + mcs=1; + } else if (pcch_sdu_length <= TBStable1C[2]) { + mcs=2; + } else if (pcch_sdu_length <= TBStable1C[3]) { + mcs=3; + } else if (pcch_sdu_length <= TBStable1C[4]) { + mcs=4; + } else if (pcch_sdu_length <= TBStable1C[5]) { + mcs=5; + } else if (pcch_sdu_length <= TBStable1C[6]) { + mcs=6; + } else if (pcch_sdu_length <= TBStable1C[7]) { + mcs=7; + } else if (pcch_sdu_length <= TBStable1C[8]) { + mcs=8; + } else if (pcch_sdu_length <= TBStable1C[9]) { + mcs=9; + } else { + /* unexpected: pcch sdb size is over max value*/ + LOG_E(MAC,"[eNB %d] Frame %d : PCCH->PCH CC_id %d, Received %d bytes is over max length(256) \n", + module_idP, frameP,CC_id, pcch_sdu_length); + return; + } + rb_num = TBStable1C[mcs] / rb_bit + ( (TBStable1C[mcs] % rb_bit == 0)? 0: 1) + 1; + /* calculate N_RB_STEP and Lcrbs */ + if (n_rb_dl < 50) { + n_rb_step = 2; + Lcrbs = rb_num / 2 + ((rb_num % 2 == 0) ? 0:2); + } else { + n_rb_step = 4; + Lcrbs = rb_num / 4 + ((rb_num % 4 == 0) ? 0:4); + } + for(i = 0;i < Lcrbs ;i++){ + vrb_map[first_rb+i] = 1; + } #else - //NO SIB - if ((subframeP == 1 || subframeP == 2 || subframeP == 4 || subframeP == 6 || subframeP == 9) || - (subframeP == 5 && ((frameP % 2) != 0 && (frameP % 8) != 1))) { - switch (n_rb_dl) { - case 25: - first_rb = 10; - break; - case 50: - first_rb = 24; - break; - case 100: - first_rb = 48; - break; - } - } else if (subframeP == 5 && ((frameP % 2) == 0 || (frameP % 8) == 1)) { // SIB + paging - switch (n_rb_dl) { - case 25: - first_rb = 14; - break; - case 50: - first_rb = 28; - break; - case 100: - first_rb = 52; - break; - } - } + //NO SIB + if ((subframeP == 1 || subframeP == 2 || subframeP == 4 || subframeP == 6 || subframeP == 9) || + (subframeP == 5 && ((frameP % 2) != 0 && (frameP % 8) != 1))) { + switch (n_rb_dl) { + case 25: + first_rb = 10; + break; + case 50: + first_rb = 24; + break; + case 100: + first_rb = 48; + break; + } + } else if (subframeP == 5 && ((frameP % 2) == 0 || (frameP % 8) == 1)) { // SIB + paging + switch (n_rb_dl) { + case 25: + first_rb = 14; + break; + case 50: + first_rb = 28; + break; + case 100: + first_rb = 52; + break; + } + } - vrb_map[first_rb] = 1; - vrb_map[first_rb+1] = 1; - vrb_map[first_rb+2] = 1; - vrb_map[first_rb+3] = 1; - /* Get MCS for length of PCH */ - if (pcch_sdu_length <= get_TBS_DL(0,3)) { - mcs=0; - } else if (pcch_sdu_length <= get_TBS_DL(1,3)) { - mcs=1; - } else if (pcch_sdu_length <= get_TBS_DL(2,3)) { - mcs=2; - } else if (pcch_sdu_length <= get_TBS_DL(3,3)) { - mcs=3; - } else if (pcch_sdu_length <= get_TBS_DL(4,3)) { - mcs=4; - } else if (pcch_sdu_length <= get_TBS_DL(5,3)) { - mcs=5; - } else if (pcch_sdu_length <= get_TBS_DL(6,3)) { - mcs=6; - } else if (pcch_sdu_length <= get_TBS_DL(7,3)) { - mcs=7; - } else if (pcch_sdu_length <= get_TBS_DL(8,3)) { - mcs=8; - } else if (pcch_sdu_length <= get_TBS_DL(9,3)) { - mcs=9; - } + vrb_map[first_rb] = 1; + vrb_map[first_rb+1] = 1; + vrb_map[first_rb+2] = 1; + vrb_map[first_rb+3] = 1; + /* Get MCS for length of PCH */ + if (pcch_sdu_length <= get_TBS_DL(0,3)) { + mcs=0; + } else if (pcch_sdu_length <= get_TBS_DL(1,3)) { + mcs=1; + } else if (pcch_sdu_length <= get_TBS_DL(2,3)) { + mcs=2; + } else if (pcch_sdu_length <= get_TBS_DL(3,3)) { + mcs=3; + } else if (pcch_sdu_length <= get_TBS_DL(4,3)) { + mcs=4; + } else if (pcch_sdu_length <= get_TBS_DL(5,3)) { + mcs=5; + } else if (pcch_sdu_length <= get_TBS_DL(6,3)) { + mcs=6; + } else if (pcch_sdu_length <= get_TBS_DL(7,3)) { + mcs=7; + } else if (pcch_sdu_length <= get_TBS_DL(8,3)) { + mcs=8; + } else if (pcch_sdu_length <= get_TBS_DL(9,3)) { + mcs=9; + } #endif - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu)); #ifdef FORMAT1C - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1C; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = getRIV(n_vrb_dl/n_rb_step, first_rb/n_rb_step, Lcrbs/n_rb_step); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.ngap = n_gap; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1C; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = getRIV(n_vrb_dl/n_rb_step, first_rb/n_rb_step, Lcrbs/n_rb_step); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.ngap = n_gap; #else - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = 0; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // no TPC - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = 1; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = 1; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = getRIV(n_rb_dl,first_rb,4); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // no TPC + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = 1; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = 1; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = getRIV(n_rb_dl,first_rb,4); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0; #endif - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = 4; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = 0xFFFE; // P-RNTI - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 2; // P-RNTI : see Table 4-10 from SCF082 - nFAPI specifications - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = 4; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = 0xFFFE; // P-RNTI + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 2; // P-RNTI : see Table 4-10 from SCF082 - nFAPI specifications + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; - // Rel10 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = 3; - // Rel13 fields - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 0; // regular UE - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not BR - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = 0xFFFF; + // Rel10 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = 3; + // Rel13 fields + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = 0; // regular UE + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not BR + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = 0xFFFF; - if (!CCE_allocation_infeasible(module_idP, CC_id, 0, subframeP, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, P_RNTI)) { - LOG_D(MAC,"Frame %d: Subframe %d : Adding common DCI for P_RNTI\n", frameP,subframeP); - dl_req->number_dci++; - dl_req->number_pdu++; - dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; - memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu)); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFE; + if (!CCE_allocation_infeasible(module_idP, CC_id, 0, subframeP, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, P_RNTI)) { + LOG_D(MAC,"Frame %d: Subframe %d : Adding common DCI for P_RNTI\n", frameP,subframeP); + dl_req->number_dci++; + dl_req->number_pdu++; + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = 0xFFFE; #ifdef FORMAT1C - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 3; // format 1C - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(n_vrb_dl/n_rb_step, first_rb/n_rb_step, Lcrbs/n_rb_step); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 3; // format 1C + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(n_vrb_dl/n_rb_step, first_rb/n_rb_step, Lcrbs/n_rb_step); #else - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(n_rb_dl,first_rb,4); - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(n_rb_dl,first_rb,4); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized #endif - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1;// first block - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB==1 ) ? 0 : 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB==1 ) ? 1 : 2; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; - dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; - // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; - dl_req->number_pdu++; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1;// first block + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB==1 ) ? 0 : 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB==1 ) ? 1 : 2; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; + dl_req->number_pdu++; - eNB->TX_req[CC_id].sfn_sf = (frameP<<4)+subframeP; - TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; - TX_req->pdu_length = pcch_sdu_length; - TX_req->pdu_index = eNB->pdu_index[CC_id]++; - TX_req->num_segments = 1; - TX_req->segments[0].segment_length = pcch_sdu_length; - TX_req->segments[0].segment_data = cc[CC_id].PCCH_pdu.payload; - eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; - } else { - LOG_E(MAC,"[eNB %d] CCid %d Frame %d, subframe %d : Cannot add DCI 1A/1C for Paging\n",module_idP, CC_id, frameP, subframeP); - continue; + eNB->TX_req[CC_id].sfn_sf = (frameP<<4)+subframeP; + TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; + TX_req->pdu_length = pcch_sdu_length; + TX_req->pdu_index = eNB->pdu_index[CC_id]++; + TX_req->num_segments = 1; + TX_req->segments[0].segment_length = pcch_sdu_length; + TX_req->segments[0].segment_data = cc[CC_id].PCCH_pdu.payload; + eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; + } else { + LOG_E(MAC,"[eNB %d] CCid %d Frame %d, subframe %d : Cannot add DCI 1A/1C for Paging\n",module_idP, CC_id, frameP, subframeP); + continue; + } + + if (opt_enabled == 1) { + trace_pdu(1, + &eNB->common_channels[CC_id].PCCH_pdu.payload[0], + pcch_sdu_length, + 0xffff, + PCCH, + P_RNTI, + eNB->frame, + eNB->subframe, + 0, + 0); + LOG_D(OPT,"[eNB %d][PCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", + module_idP, frameP, CC_id, 0xffff, pcch_sdu_length); + } + eNB->eNB_stats[CC_id].total_num_pcch_pdu+=1; + eNB->eNB_stats[CC_id].pcch_buffer=pcch_sdu_length; + eNB->eNB_stats[CC_id].total_pcch_buffer+=pcch_sdu_length; + eNB->eNB_stats[CC_id].pcch_mcs=mcs; + //paging first_rb log + LOG_D(MAC,"[eNB %d] Frame %d subframe %d PCH: paging_ue_index %d pcch_sdu_length %d mcs %d first_rb %d\n", + module_idP, frameP, subframeP, UE_PF_PO[CC_id][i].ue_index_value, pcch_sdu_length, mcs, first_rb); + + pthread_mutex_lock(&ue_pf_po_mutex); + memset(&UE_PF_PO[CC_id][i], 0, sizeof(UE_PF_PO_t)); + pthread_mutex_unlock(&ue_pf_po_mutex); } - - if (opt_enabled == 1) { - trace_pdu(1, - &eNB->common_channels[CC_id].PCCH_pdu.payload[0], - pcch_sdu_length, - 0xffff, - PCCH, - P_RNTI, - eNB->frame, - eNB->subframe, - 0, - 0); - LOG_D(OPT,"[eNB %d][PCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n", - module_idP, frameP, CC_id, 0xffff, pcch_sdu_length); - } - eNB->eNB_stats[CC_id].total_num_pcch_pdu+=1; - eNB->eNB_stats[CC_id].pcch_buffer=pcch_sdu_length; - eNB->eNB_stats[CC_id].total_pcch_buffer+=pcch_sdu_length; - eNB->eNB_stats[CC_id].pcch_mcs=mcs; - //paging first_rb log - LOG_D(MAC,"[eNB %d] Frame %d subframe %d PCH: paging_ue_index %d pcch_sdu_length %d mcs %d first_rb %d\n", - module_idP, frameP, subframeP, UE_PF_PO[CC_id][i].ue_index_value, pcch_sdu_length, mcs, first_rb); - - pthread_mutex_lock(&ue_pf_po_mutex); - memset(&UE_PF_PO[CC_id][i], 0, sizeof(UE_PF_PO_t)); - pthread_mutex_unlock(&ue_pf_po_mutex); - } } } /* this might be misleading when pcch is inactive */ diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index f841d9d55a..5cdd9d8771 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -72,9 +72,9 @@ extern uint8_t nfapi_mode; // This table holds the allowable PRB sizes for ULSCH transmissions uint8_t rb_table[34] = - { 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, + { 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100 -}; + }; void rx_sdu(const module_id_t enb_mod_idP, @@ -86,746 +86,625 @@ rx_sdu(const module_id_t enb_mod_idP, const uint16_t sdu_lenP, const uint16_t timing_advance, const uint8_t ul_cqi) { - int current_rnti = rntiP; - unsigned char rx_ces[MAX_NUM_CE], num_ce, num_sdu, i, *payload_ptr; - unsigned char rx_lcids[NB_RB_MAX]; - unsigned short rx_lengths[NB_RB_MAX]; - int UE_id = find_UE_id(enb_mod_idP, current_rnti); - int RA_id; - int ii, j; - eNB_MAC_INST *mac = RC.mac[enb_mod_idP]; - int harq_pid = - subframe2harqpid(&mac->common_channels[CC_idP], frameP, subframeP); + int current_rnti = rntiP; + unsigned char rx_ces[MAX_NUM_CE], num_ce, num_sdu, i, *payload_ptr; + unsigned char rx_lcids[NB_RB_MAX]; + unsigned short rx_lengths[NB_RB_MAX]; + int UE_id = find_UE_id(enb_mod_idP, current_rnti); + int RA_id; + int ii, j; + eNB_MAC_INST *mac = RC.mac[enb_mod_idP]; + int harq_pid = + subframe2harqpid(&mac->common_channels[CC_idP], frameP, subframeP); - UE_list_t *UE_list = &mac->UE_list; - int crnti_rx = 0; - int old_buffer_info; - RA_t *ra = - (RA_t *) & RC.mac[enb_mod_idP]->common_channels[CC_idP].ra[0]; - int first_rb = 0; + UE_list_t *UE_list = &mac->UE_list; + int crnti_rx = 0; + int old_buffer_info; + RA_t *ra = + (RA_t *) & RC.mac[enb_mod_idP]->common_channels[CC_idP].ra[0]; + int first_rb = 0; - start_meas(&mac->rx_ulsch_sdu); + start_meas(&mac->rx_ulsch_sdu); - if ((UE_id > NUMBER_OF_UE_MAX) || (UE_id == -1)) - for (ii = 0; ii < NB_RB_MAX; ii++) { - rx_lengths[ii] = 0; - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_RX_SDU, 1); - if (opt_enabled == 1) { - trace_pdu(0, sduP, sdu_lenP, 0, 3, current_rnti, frameP, subframeP, - 0, 0); - LOG_D(OPT, "[eNB %d][ULSCH] Frame %d rnti %x with size %d\n", - enb_mod_idP, frameP, current_rnti, sdu_lenP); + if ((UE_id > NUMBER_OF_UE_MAX) || (UE_id == -1)) + for (ii = 0; ii < NB_RB_MAX; ii++) { + rx_lengths[ii] = 0; } - if (UE_id != -1) { - LOG_D(MAC, - "[eNB %d][PUSCH %d] CC_id %d Received ULSCH sdu round %d from PHY (rnti %x, UE_id %d) ul_cqi %d\n", - enb_mod_idP, harq_pid, CC_idP, - UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid], - current_rnti, UE_id, ul_cqi); - - AssertFatal(UE_list->UE_sched_ctrl[UE_id]. - round_UL[CC_idP][harq_pid] < 8, "round >= 8\n"); - if (sduP != NULL) { - UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer = 0; - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; - UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= - (~(1 << harq_pid)); - /* Update with smoothing: 3/4 of old value and 1/4 of new. - * This is the logic that was done in the function - * lte_est_timing_advance_pusch, maybe it's not necessary? - * maybe it's even not correct at all? - */ - UE_list->UE_sched_ctrl[UE_id].ta_update = - (UE_list->UE_sched_ctrl[UE_id].ta_update * 3 + - timing_advance) / 4; - UE_list->UE_sched_ctrl[UE_id].pusch_snr[CC_idP] = ul_cqi; - UE_list->UE_sched_ctrl[UE_id].ul_consecutive_errors = 0; - first_rb = - UE_list->UE_template[CC_idP][UE_id].first_rb_ul[harq_pid]; - - if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) { - UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 0; - mac_eNB_rrc_ul_in_sync(enb_mod_idP, CC_idP, frameP, - subframeP, UE_RNTI(enb_mod_idP, - UE_id)); - } - } else { // we've got an error - LOG_D(MAC, - "[eNB %d][PUSCH %d] CC_id %d ULSCH in error in round %d, ul_cqi %d\n", - enb_mod_idP, harq_pid, CC_idP, - UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid], - ul_cqi); - - // AssertFatal(1==0,"ulsch in error\n"); - if (UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] == - 3) { - UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= - (~(1 << harq_pid)); - UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] = - 0; - if (UE_list->UE_sched_ctrl[UE_id]. - ul_consecutive_errors++ == 10) - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 1; - } else - UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid]++; - return; - - } - } else if ((RA_id = find_RA_id(enb_mod_idP, CC_idP, current_rnti)) != -1) { // Check if this is an RA process for the rnti - AssertFatal(mac->common_channels[CC_idP]. - radioResourceConfigCommon->rach_ConfigCommon. - maxHARQ_Msg3Tx > 1, - "maxHARQ %d should be greater than 1\n", - (int) mac->common_channels[CC_idP]. - radioResourceConfigCommon->rach_ConfigCommon. - maxHARQ_Msg3Tx); - - LOG_D(MAC, - "[eNB %d][PUSCH %d] CC_id %d [RAPROC Msg3] Received ULSCH sdu round %d from PHY (rnti %x, RA_id %d) ul_cqi %d\n", - enb_mod_idP, harq_pid, CC_idP, ra[RA_id].msg3_round, - current_rnti, RA_id, ul_cqi); - - first_rb = ra->msg3_first_rb; - - if (sduP == NULL) { // we've got an error on Msg3 - LOG_D(MAC, - "[eNB %d] CC_id %d, RA %d ULSCH in error in round %d/%d\n", - enb_mod_idP, CC_idP, RA_id, - ra[RA_id].msg3_round, - (int) mac->common_channels[CC_idP]. - radioResourceConfigCommon->rach_ConfigCommon. - maxHARQ_Msg3Tx); - if (ra[RA_id].msg3_round == - mac->common_channels[CC_idP].radioResourceConfigCommon-> - rach_ConfigCommon.maxHARQ_Msg3Tx - 1) { - cancel_ra_proc(enb_mod_idP, CC_idP, frameP, current_rnti); - } - - else { - first_rb = - UE_list->UE_template[CC_idP][UE_id]. - first_rb_ul[harq_pid]; - ra[RA_id].msg3_round++; - // prepare handling of retransmission - ra[RA_id].Msg3_frame = (ra[RA_id].Msg3_frame + ((ra[RA_id].Msg3_subframe > 1) ? 1 : 0)) % 1024; - ra[RA_id].Msg3_subframe = (ra[RA_id].Msg3_subframe + 8) % 10; - add_msg3(enb_mod_idP, CC_idP, &ra[RA_id], frameP, - subframeP); - } - return; - } - } else { - LOG_W(MAC, - "Cannot find UE or RA corresponding to ULSCH rnti %x, dropping it\n", - current_rnti); - return; - } - payload_ptr = - parse_ulsch_header(sduP, &num_ce, &num_sdu, rx_ces, rx_lcids, - rx_lengths, sdu_lenP); - - T(T_ENB_MAC_UE_UL_PDU, T_INT(enb_mod_idP), T_INT(CC_idP), - T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), - T_INT(harq_pid), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu)); - T(T_ENB_MAC_UE_UL_PDU_WITH_DATA, T_INT(enb_mod_idP), T_INT(CC_idP), - T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), - T_INT(harq_pid), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu), - T_BUFFER(sduP, sdu_lenP)); - - mac->eNB_stats[CC_idP].ulsch_bytes_rx = sdu_lenP; - mac->eNB_stats[CC_idP].total_ulsch_bytes_rx += sdu_lenP; - mac->eNB_stats[CC_idP].total_ulsch_pdus_rx += 1; - - UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] = 0; - - // control element - for (i = 0; i < num_ce; i++) { - - T(T_ENB_MAC_UE_UL_CE, T_INT(enb_mod_idP), T_INT(CC_idP), - T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), - T_INT(rx_ces[i])); - - switch (rx_ces[i]) { // implement and process BSR + CRNTI + - case POWER_HEADROOM: - if (UE_id != -1) { - UE_list->UE_template[CC_idP][UE_id].phr_info = - (payload_ptr[0] & 0x3f) - PHR_MAPPING_OFFSET; - LOG_D(MAC, - "[eNB %d] CC_id %d MAC CE_LCID %d : Received PHR PH = %d (db)\n", - enb_mod_idP, CC_idP, rx_ces[i], - UE_list->UE_template[CC_idP][UE_id].phr_info); - UE_list->UE_template[CC_idP][UE_id].phr_info_configured = - 1; - UE_list->UE_sched_ctrl[UE_id].phr_received = 1; - } - payload_ptr += sizeof(POWER_HEADROOM_CMD); - break; - - case CRNTI: - { - int old_rnti = - (((uint16_t) payload_ptr[0]) << 8) + payload_ptr[1]; - int old_UE_id = find_UE_id(enb_mod_idP, old_rnti); - LOG_D(MAC, - "[eNB %d] Frame %d, Subframe %d CC_id %d MAC CE_LCID %d (ce %d/%d): CRNTI %x (UE_id %d) in Msg3\n", - enb_mod_idP, frameP, subframeP, CC_idP, rx_ces[i], i, - num_ce, old_rnti, old_UE_id); - /* receiving CRNTI means that the current rnti has to go away */ - cancel_ra_proc(enb_mod_idP, CC_idP, frameP, - current_rnti); - if (old_UE_id != -1) { - /* TODO: if the UE did random access (followed by a MAC uplink with - * CRNTI) because none of its scheduling request was granted, then - * according to 36.321 5.4.4 the UE's MAC will notify RRC to release - * PUCCH/SRS. According to 36.331 5.3.13 the UE will then apply - * default configuration for CQI reporting and scheduling requests, - * which basically means that the CQI requests won't work anymore and - * that the UE won't do any scheduling request anymore as long as the - * eNB doesn't reconfigure the UE. - * We have to take care of this. As the code is, nothing is done and - * the UE state in the eNB is wrong. - */ - UE_id = old_UE_id; - UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer = 0; - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; - if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) { - UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 0; - mac_eNB_rrc_ul_in_sync(enb_mod_idP, CC_idP, frameP, - subframeP, old_rnti); - } - current_rnti = old_rnti; - } - crnti_rx = 1; - payload_ptr += 2; - break; - } - - case TRUNCATED_BSR: - case SHORT_BSR: - { - uint8_t lcgid; - lcgid = (payload_ptr[0] >> 6); - - LOG_D(MAC, - "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", - enb_mod_idP, CC_idP, rx_ces[i], lcgid, - payload_ptr[0] & 0x3f); - - if (crnti_rx == 1) - LOG_D(MAC, - "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", - enb_mod_idP, CC_idP, rx_ces[i], lcgid, - payload_ptr[0] & 0x3f); - if (UE_id != -1) { - - UE_list->UE_template[CC_idP][UE_id].bsr_info[lcgid] = - (payload_ptr[0] & 0x3f); - - // update buffer info - - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[lcgid] = - BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. - bsr_info[lcgid]]; - - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[lcgid]; - - RC.eNB[enb_mod_idP][CC_idP]-> - pusch_stats_bsr[UE_id][(frameP * 10) + subframeP] - = (payload_ptr[0] & 0x3f); - if (UE_id == UE_list->head) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME - (VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR, - RC.eNB[enb_mod_idP][CC_idP]->pusch_stats_bsr - [UE_id][(frameP * 10) + subframeP]); - if (UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_creation_time[lcgid] - == 0) { - UE_list->UE_template[CC_idP] - [UE_id].ul_buffer_creation_time[lcgid] = - frameP; - } - if (mac_eNB_get_rrc_status - (enb_mod_idP, - UE_RNTI(enb_mod_idP, UE_id)) < RRC_CONNECTED) - LOG_D(MAC, - "[eNB %d] CC_id %d MAC CE_LCID %d : ul_total_buffer = %d (lcg increment %d)\n", - enb_mod_idP, CC_idP, rx_ces[i], - UE_list->UE_template[CC_idP][UE_id]. - ul_total_buffer, - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[lcgid]); - } else { - - } - payload_ptr += 1; //sizeof(SHORT_BSR); // fixme - } - break; - - case LONG_BSR: - if (UE_id != -1) { - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0] = - ((payload_ptr[0] & 0xFC) >> 2); - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1] = - ((payload_ptr[0] & 0x03) << 4) | - ((payload_ptr[1] & 0xF0) >> 4); - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2] = - ((payload_ptr[1] & 0x0F) << 2) | - ((payload_ptr[2] & 0xC0) >> 6); - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] = - (payload_ptr[2] & 0x3F); - - // update buffer info - old_buffer_info = - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID0]; - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID0] = - BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID0]]; - - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID0]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= - old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= - old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = - 0; - - old_buffer_info = - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID1]; - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID1] = - BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID1]]; - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID1]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= - old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= - old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = - 0; - - old_buffer_info = - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID2]; - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID2] = - BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID2]]; - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID2]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= - old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= - old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = - 0; - - old_buffer_info = - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID3]; - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID3] = - BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID3]]; - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID3]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= - old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= - old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = - 0; - - LOG_D(MAC, - "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " - "%u LCGID2 = %u LCGID3 = %u\n", enb_mod_idP, CC_idP, - rx_ces[i], - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0], - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1], - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2], - UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID3]); - if (crnti_rx == 1) - LOG_D(MAC, - "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " - "%u LCGID2 = %u LCGID3 = %u\n", enb_mod_idP, - CC_idP, rx_ces[i], - UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID0], - UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID1], - UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID2], - UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID3]); - - if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0] == - 0) { - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_creation_time[LCGID0] = 0; - } else if (UE_list->UE_template[CC_idP] - [UE_id].ul_buffer_creation_time[LCGID0] == 0) { - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_creation_time[LCGID0] = frameP; - } - - if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1] == - 0) { - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_creation_time[LCGID1] = 0; - } else if (UE_list->UE_template[CC_idP] - [UE_id].ul_buffer_creation_time[LCGID1] == 0) { - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_creation_time[LCGID1] = frameP; - } - - if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2] == - 0) { - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_creation_time[LCGID2] = 0; - } else if (UE_list->UE_template[CC_idP] - [UE_id].ul_buffer_creation_time[LCGID2] == 0) { - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_creation_time[LCGID2] = frameP; - } - - if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] == - 0) { - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_creation_time[LCGID3] = 0; - } else if (UE_list->UE_template[CC_idP] - [UE_id].ul_buffer_creation_time[LCGID3] == 0) { - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_creation_time[LCGID3] = frameP; - - } - } - - payload_ptr += 3; ////sizeof(LONG_BSR); - break; - - default: - LOG_E(MAC, - "[eNB %d] CC_id %d Received unknown MAC header (0x%02x)\n", - enb_mod_idP, CC_idP, rx_ces[i]); - break; - } - } - - for (i = 0; i < num_sdu; i++) { - LOG_D(MAC, "SDU Number %d MAC Subheader SDU_LCID %d, length %d\n", - i, rx_lcids[i], rx_lengths[i]); - - T(T_ENB_MAC_UE_UL_SDU, T_INT(enb_mod_idP), T_INT(CC_idP), - T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), - T_INT(rx_lcids[i]), T_INT(rx_lengths[i])); - T(T_ENB_MAC_UE_UL_SDU_WITH_DATA, T_INT(enb_mod_idP), T_INT(CC_idP), - T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), - T_INT(rx_lcids[i]), T_INT(rx_lengths[i]), T_BUFFER(payload_ptr, - rx_lengths - [i])); - - switch (rx_lcids[i]) { - case CCCH: - if (rx_lengths[i] > CCCH_PAYLOAD_SIZE_MAX) { - LOG_E(MAC, - "[eNB %d/%d] frame %d received CCCH of size %d (too big, maximum allowed is %d, sdu_len %d), dropping packet\n", - enb_mod_idP, CC_idP, frameP, rx_lengths[i], - CCCH_PAYLOAD_SIZE_MAX, sdu_lenP); - break; - } - LOG_D(MAC, - "[eNB %d][RAPROC] CC_id %d Frame %d, Received CCCH: %x.%x.%x.%x.%x.%x, Terminating RA procedure for UE rnti %x\n", - enb_mod_idP, CC_idP, frameP, payload_ptr[0], - payload_ptr[1], payload_ptr[2], payload_ptr[3], - payload_ptr[4], payload_ptr[5], current_rnti); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC, 1); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC, 0); - for (ii = 0; ii < NB_RA_PROC_MAX; ii++) { - RA_t *ra = &mac->common_channels[CC_idP].ra[ii]; - - LOG_D(MAC, - "[mac %d][RAPROC] CC_id %d Checking proc %d : rnti (%x, %x), state %d\n", - enb_mod_idP, CC_idP, ii, ra->rnti, - current_rnti, ra->state); - - if ((ra->rnti == current_rnti) && (ra->state != IDLE)) { - - //payload_ptr = parse_ulsch_header(msg3,&num_ce,&num_sdu,rx_ces,rx_lcids,rx_lengths,msg3_len); - - if (UE_id < 0) { - memcpy(&ra->cont_res_id[0], payload_ptr, 6); - LOG_D(MAC, - "[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3: length %d, offset %ld\n", - enb_mod_idP, CC_idP, frameP, rx_lengths[i], - payload_ptr - sduP); - - if ((UE_id = - add_new_ue(enb_mod_idP, CC_idP, - mac->common_channels[CC_idP]. - ra[ii].rnti, harq_pid -#ifdef Rel14 - , - mac->common_channels[CC_idP]. - ra[ii].rach_resource_type -#endif - )) == -1) { - AssertFatal(1 == 0, - "[MAC][eNB] Max user count reached\n"); - // kill RA procedure - } else - LOG_D(MAC, - "[eNB %d][RAPROC] CC_id %d Frame %d Added user with rnti %x => UE %d\n", - enb_mod_idP, CC_idP, frameP, ra->rnti, - UE_id); - } else { - LOG_D(MAC, - "[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3 from already registered UE %d: length %d, offset %ld\n", - enb_mod_idP, CC_idP, frameP, UE_id, - rx_lengths[i], payload_ptr - sduP); - // kill RA procedure - } - - mac_rrc_data_ind(enb_mod_idP, - CC_idP, - frameP, subframeP, - current_rnti, - CCCH, - (uint8_t *) payload_ptr, - rx_lengths[i], - 0); - - - if (num_ce > 0) { // handle msg3 which is not RRCConnectionRequest - // process_ra_message(msg3,num_ce,rx_lcids,rx_ces); - } - // prepare transmission of Msg4 - ra->state = MSG4; - - - - // Program Msg4 PDCCH+DLSCH/MPDCCH transmission 4 subframes from now, // Check if this is ok for BL/CE, or if the rule is different - ra->Msg4_frame = frameP + ((subframeP > 5) ? 1 : 0); - ra->Msg4_subframe = (subframeP + 4) % 10; - - } // if process is active - } // loop on RA processes - - break; - - case DCCH: - case DCCH1: - // if(eNB_mac_inst[module_idP][CC_idP].Dcch_lchan[UE_id].Active==1){ - - -#if defined(ENABLE_MAC_PAYLOAD_DEBUG) - LOG_T(MAC, "offset: %d\n", - (unsigned char) ((unsigned char *) payload_ptr - sduP)); - for (j = 0; j < 32; j++) { - LOG_T(MAC, "%x ", payload_ptr[j]); - } - LOG_T(MAC, "\n"); -#endif - - if (UE_id != -1) { - // adjust buffer occupancy of the correponding logical channel group - if (UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[UE_list->UE_template[CC_idP] - [UE_id].lcgidmap[rx_lcids[i]]] >= - rx_lengths[i]) - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[UE_list->UE_template[CC_idP] - [UE_id].lcgidmap[rx_lcids[i]]] -= - rx_lengths[i]; - else - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[UE_list->UE_template[CC_idP] - [UE_id].lcgidmap[rx_lcids[i]]] = 0; - - LOG_D(MAC, - "[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DCCH, received %d bytes form UE %d on LCID %d \n", - enb_mod_idP, CC_idP, frameP, rx_lengths[i], UE_id, - rx_lcids[i]); - - mac_rlc_data_ind(enb_mod_idP, current_rnti, enb_mod_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, rx_lcids[i], (char *) payload_ptr, rx_lengths[i], 1, NULL); //(unsigned int*)crc_status); - UE_list->eNB_UE_stats[CC_idP][UE_id]. - num_pdu_rx[rx_lcids[i]] += 1; - UE_list->eNB_UE_stats[CC_idP][UE_id]. - num_bytes_rx[rx_lcids[i]] - += rx_lengths[i]; - - - } - - /* UE_id != -1 */ - // } - break; - - // all the DRBS - case DTCH: - default: - -#if defined(ENABLE_MAC_PAYLOAD_DEBUG) - LOG_T(MAC, "offset: %d\n", - (unsigned char) ((unsigned char *) payload_ptr - sduP)); - for (j = 0; j < 32; j++) { - LOG_T(MAC, "%x ", payload_ptr[j]); - } - LOG_T(MAC, "\n"); -#endif - if (rx_lcids[i] < NB_RB_MAX) { - LOG_D(MAC, - "[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d\n", - enb_mod_idP, CC_idP, frameP, rx_lengths[i], UE_id, - rx_lcids[i]); - - if (UE_id != -1) { - // adjust buffer occupancy of the correponding logical channel group - LOG_D(MAC, - "[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d, removing from LCGID %ld, %d\n", - enb_mod_idP, CC_idP, frameP, rx_lengths[i], - UE_id, rx_lcids[i], - UE_list->UE_template[CC_idP][UE_id]. - lcgidmap[rx_lcids[i]], - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[UE_list->UE_template[CC_idP] - [UE_id].lcgidmap[rx_lcids[i]]]); - - if (UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[UE_list->UE_template[CC_idP] - [UE_id].lcgidmap[rx_lcids[i]]] - >= rx_lengths[i]) - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[UE_list->UE_template[CC_idP] - [UE_id].lcgidmap[rx_lcids[i]]] - -= rx_lengths[i]; - else - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info - [UE_list->UE_template[CC_idP][UE_id].lcgidmap - [rx_lcids[i]]] = 0; - if ((rx_lengths[i] < SCH_PAYLOAD_SIZE_MAX) - && (rx_lengths[i] > 0)) { // MAX SIZE OF transport block - mac_rlc_data_ind(enb_mod_idP, current_rnti, enb_mod_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, rx_lcids[i], (char *) payload_ptr, rx_lengths[i], 1, NULL); //(unsigned int*)crc_status); - - UE_list->eNB_UE_stats[CC_idP][UE_id]. - num_pdu_rx[rx_lcids[i]] += 1; - UE_list->eNB_UE_stats[CC_idP][UE_id]. - num_bytes_rx[rx_lcids[i]] += rx_lengths[i]; - //clear uplane_inactivity_timer - UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0; - } else { /* rx_length[i] */ - UE_list->eNB_UE_stats[CC_idP][UE_id]. - num_errors_rx += 1; - LOG_E(MAC, - "[eNB %d] CC_id %d Frame %d : Max size of transport block reached LCID %d from UE %d ", - enb_mod_idP, CC_idP, frameP, rx_lcids[i], - UE_id); - } - } else { /*(UE_id != -1 */ - LOG_E(MAC, - "[eNB %d] CC_id %d Frame %d : received unsupported or unknown LCID %d from UE %d ", - enb_mod_idP, CC_idP, frameP, rx_lcids[i], UE_id); - } - } - - break; - } - - payload_ptr += rx_lengths[i]; - } - - // Program ACK for PHICH + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME + (VCD_SIGNAL_DUMPER_FUNCTIONS_RX_SDU, 1); + if (opt_enabled == 1) { + trace_pdu(0, sduP, sdu_lenP, 0, 3, current_rnti, frameP, subframeP, + 0, 0); + LOG_D(OPT, "[eNB %d][ULSCH] Frame %d rnti %x with size %d\n", + enb_mod_idP, frameP, current_rnti, sdu_lenP); + } + + if (UE_id != -1) { LOG_D(MAC, - "Programming PHICH ACK for rnti %x harq_pid %d (first_rb %d)\n", - current_rnti, harq_pid, first_rb); - nfapi_hi_dci0_request_t *hi_dci0_req = &mac->HI_DCI0_req[CC_idP]; - nfapi_hi_dci0_request_body_t *hi_dci0_req_body = &hi_dci0_req->hi_dci0_request_body; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = - &hi_dci0_req_body->hi_dci0_pdu_list[hi_dci0_req_body->number_of_dci + hi_dci0_req_body->number_of_hi]; - memset((void *) hi_dci0_pdu, 0, sizeof(nfapi_hi_dci0_request_pdu_t)); - hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; - hi_dci0_pdu->pdu_size = 2 + sizeof(nfapi_hi_dci0_hi_pdu); - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_HI_PDU_REL8_TAG; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = first_rb; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = 0; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 1; - hi_dci0_req_body->number_of_hi++; - hi_dci0_req_body->sfnsf = sfnsf_add_subframe(frameP,subframeP, 0); - hi_dci0_req_body->tl.tag = NFAPI_HI_DCI0_REQUEST_BODY_TAG; - hi_dci0_req->sfn_sf = sfnsf_add_subframe(frameP,subframeP, 4); - hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST; + "[eNB %d][PUSCH %d] CC_id %d Received ULSCH sdu round %d from PHY (rnti %x, UE_id %d) ul_cqi %d\n", + enb_mod_idP, harq_pid, CC_idP, + UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid], + current_rnti, UE_id, ul_cqi); - /* NN--> FK: we could either check the payload, or use a phy helper to detect a false msg3 */ - if ((num_sdu == 0) && (num_ce == 0)) { - if (UE_id != -1) - UE_list->eNB_UE_stats[CC_idP][UE_id].total_num_errors_rx += 1; - /* - if (msg3_flagP != NULL) { - if( *msg3_flagP == 1 ) { - LOG_N(MAC,"[eNB %d] CC_id %d frame %d : false msg3 detection: signal phy to canceling RA and remove the UE\n", enb_mod_idP, CC_idP, frameP); - *msg3_flagP=0; - } - } */ - } else { - if (UE_id != -1) { - UE_list->eNB_UE_stats[CC_idP][UE_id].pdu_bytes_rx = sdu_lenP; - UE_list->eNB_UE_stats[CC_idP][UE_id].total_pdu_bytes_rx += - sdu_lenP; - UE_list->eNB_UE_stats[CC_idP][UE_id].total_num_pdus_rx += 1; + AssertFatal(UE_list->UE_sched_ctrl[UE_id]. + round_UL[CC_idP][harq_pid] < 8, "round >= 8\n"); + if (sduP != NULL) { + UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer = 0; + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; + UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= (~(1 << harq_pid)); + /* Update with smoothing: 3/4 of old value and 1/4 of new. + * This is the logic that was done in the function + * lte_est_timing_advance_pusch, maybe it's not necessary? + * maybe it's even not correct at all? + */ + UE_list->UE_sched_ctrl[UE_id].ta_update = (UE_list->UE_sched_ctrl[UE_id].ta_update * 3 + timing_advance) / 4; + UE_list->UE_sched_ctrl[UE_id].pusch_snr[CC_idP] = ul_cqi; + UE_list->UE_sched_ctrl[UE_id].ul_consecutive_errors = 0; + first_rb = UE_list->UE_template[CC_idP][UE_id].first_rb_ul[harq_pid]; + + if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) { + UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 0; + mac_eNB_rrc_ul_in_sync(enb_mod_idP, CC_idP, frameP, + subframeP, UE_RNTI(enb_mod_idP, + UE_id)); + } + } else { // we've got an error + LOG_D(MAC, + "[eNB %d][PUSCH %d] CC_id %d ULSCH in error in round %d, ul_cqi %d\n", + enb_mod_idP, harq_pid, CC_idP, + UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid], + ul_cqi); + + // AssertFatal(1==0,"ulsch in error\n"); + if (UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] == 3) { + UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= (~(1 << harq_pid)); + UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] = 0; + if (UE_list->UE_sched_ctrl[UE_id].ul_consecutive_errors++ == 10) + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 1; + } else + UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid]++; + return; + + } + } else if ((RA_id = find_RA_id(enb_mod_idP, CC_idP, current_rnti)) != -1) { // Check if this is an RA process for the rnti + AssertFatal(mac->common_channels[CC_idP]. + radioResourceConfigCommon->rach_ConfigCommon. + maxHARQ_Msg3Tx > 1, + "maxHARQ %d should be greater than 1\n", + (int) mac->common_channels[CC_idP]. + radioResourceConfigCommon->rach_ConfigCommon. + maxHARQ_Msg3Tx); + + LOG_D(MAC, + "[eNB %d][PUSCH %d] CC_id %d [RAPROC Msg3] Received ULSCH sdu round %d from PHY (rnti %x, RA_id %d) ul_cqi %d\n", + enb_mod_idP, harq_pid, CC_idP, ra[RA_id].msg3_round, + current_rnti, RA_id, ul_cqi); + + first_rb = ra->msg3_first_rb; + + if (sduP == NULL) { // we've got an error on Msg3 + LOG_D(MAC, + "[eNB %d] CC_id %d, RA %d ULSCH in error in round %d/%d\n", + enb_mod_idP, CC_idP, RA_id, + ra[RA_id].msg3_round, + (int) mac->common_channels[CC_idP]. + radioResourceConfigCommon->rach_ConfigCommon. + maxHARQ_Msg3Tx); + if (ra[RA_id].msg3_round == mac->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx - 1) { + cancel_ra_proc(enb_mod_idP, CC_idP, frameP, current_rnti); + } + + else { + first_rb = UE_list->UE_template[CC_idP][UE_id].first_rb_ul[harq_pid]; + ra[RA_id].msg3_round++; + // prepare handling of retransmission + ra[RA_id].Msg3_frame = (ra[RA_id].Msg3_frame + ((ra[RA_id].Msg3_subframe > 1) ? 1 : 0)) % 1024; + ra[RA_id].Msg3_subframe = (ra[RA_id].Msg3_subframe + 8) % 10; + add_msg3(enb_mod_idP, CC_idP, &ra[RA_id], frameP, subframeP); + } + return; + } + } else { + LOG_W(MAC, + "Cannot find UE or RA corresponding to ULSCH rnti %x, dropping it\n", + current_rnti); + return; + } + payload_ptr = parse_ulsch_header(sduP, &num_ce, &num_sdu, rx_ces, rx_lcids, rx_lengths, sdu_lenP); + + T(T_ENB_MAC_UE_UL_PDU, T_INT(enb_mod_idP), T_INT(CC_idP), + T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), + T_INT(harq_pid), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu)); + T(T_ENB_MAC_UE_UL_PDU_WITH_DATA, T_INT(enb_mod_idP), T_INT(CC_idP), + T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), + T_INT(harq_pid), T_INT(sdu_lenP), T_INT(num_ce), T_INT(num_sdu), + T_BUFFER(sduP, sdu_lenP)); + + mac->eNB_stats[CC_idP].ulsch_bytes_rx = sdu_lenP; + mac->eNB_stats[CC_idP].total_ulsch_bytes_rx += sdu_lenP; + mac->eNB_stats[CC_idP].total_ulsch_pdus_rx += 1; + + UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] = 0; + + // control element + for (i = 0; i < num_ce; i++) { + + T(T_ENB_MAC_UE_UL_CE, T_INT(enb_mod_idP), T_INT(CC_idP), + T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), + T_INT(rx_ces[i])); + + switch (rx_ces[i]) { // implement and process BSR + CRNTI + + case POWER_HEADROOM: + if (UE_id != -1) { + UE_list->UE_template[CC_idP][UE_id].phr_info = + (payload_ptr[0] & 0x3f) - PHR_MAPPING_OFFSET; + LOG_D(MAC, + "[eNB %d] CC_id %d MAC CE_LCID %d : Received PHR PH = %d (db)\n", + enb_mod_idP, CC_idP, rx_ces[i], + UE_list->UE_template[CC_idP][UE_id].phr_info); + UE_list->UE_template[CC_idP][UE_id].phr_info_configured = + 1; + UE_list->UE_sched_ctrl[UE_id].phr_received = 1; + } + payload_ptr += sizeof(POWER_HEADROOM_CMD); + break; + + case CRNTI: + { + int old_rnti = + (((uint16_t) payload_ptr[0]) << 8) + payload_ptr[1]; + int old_UE_id = find_UE_id(enb_mod_idP, old_rnti); + LOG_D(MAC, + "[eNB %d] Frame %d, Subframe %d CC_id %d MAC CE_LCID %d (ce %d/%d): CRNTI %x (UE_id %d) in Msg3\n", + enb_mod_idP, frameP, subframeP, CC_idP, rx_ces[i], i, + num_ce, old_rnti, old_UE_id); + /* receiving CRNTI means that the current rnti has to go away */ + cancel_ra_proc(enb_mod_idP, CC_idP, frameP, + current_rnti); + if (old_UE_id != -1) { + /* TODO: if the UE did random access (followed by a MAC uplink with + * CRNTI) because none of its scheduling request was granted, then + * according to 36.321 5.4.4 the UE's MAC will notify RRC to release + * PUCCH/SRS. According to 36.331 5.3.13 the UE will then apply + * default configuration for CQI reporting and scheduling requests, + * which basically means that the CQI requests won't work anymore and + * that the UE won't do any scheduling request anymore as long as the + * eNB doesn't reconfigure the UE. + * We have to take care of this. As the code is, nothing is done and + * the UE state in the eNB is wrong. + */ + UE_id = old_UE_id; + UE_list->UE_sched_ctrl[UE_id].ul_inactivity_timer = 0; + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; + if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync > 0) { + UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 0; + mac_eNB_rrc_ul_in_sync(enb_mod_idP, CC_idP, frameP, + subframeP, old_rnti); + } + current_rnti = old_rnti; } + crnti_rx = 1; + payload_ptr += 2; + break; + } + + case TRUNCATED_BSR: + case SHORT_BSR: + { + uint8_t lcgid; + lcgid = (payload_ptr[0] >> 6); + + LOG_D(MAC, + "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", + enb_mod_idP, CC_idP, rx_ces[i], lcgid, + payload_ptr[0] & 0x3f); + + if (crnti_rx == 1) + LOG_D(MAC, + "[eNB %d] CC_id %d MAC CE_LCID %d : Received short BSR LCGID = %u bsr = %d\n", + enb_mod_idP, CC_idP, rx_ces[i], lcgid, + payload_ptr[0] & 0x3f); + if (UE_id != -1) { + + UE_list->UE_template[CC_idP][UE_id].bsr_info[lcgid] = (payload_ptr[0] & 0x3f); + + // update buffer info + + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid] = BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[lcgid]]; + + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]; + + RC.eNB[enb_mod_idP][CC_idP]->pusch_stats_bsr[UE_id][(frameP * 10) + subframeP] = (payload_ptr[0] & 0x3f); + if (UE_id == UE_list->head) + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR, + RC.eNB[enb_mod_idP][CC_idP]->pusch_stats_bsr + [UE_id][(frameP * 10) + subframeP]); + if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[lcgid] == 0) { + UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[lcgid] = frameP; + } + if (mac_eNB_get_rrc_status(enb_mod_idP,UE_RNTI(enb_mod_idP, UE_id)) < RRC_CONNECTED) + LOG_D(MAC, + "[eNB %d] CC_id %d MAC CE_LCID %d : ul_total_buffer = %d (lcg increment %d)\n", + enb_mod_idP, CC_idP, rx_ces[i], + UE_list->UE_template[CC_idP][UE_id]. + ul_total_buffer, + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[lcgid]); + } else { + + } + payload_ptr += 1; //sizeof(SHORT_BSR); // fixme + } + break; + + case LONG_BSR: + if (UE_id != -1) { + UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0] = ((payload_ptr[0] & 0xFC) >> 2); + UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1] = ((payload_ptr[0] & 0x03) << 4) | ((payload_ptr[1] & 0xF0) >> 4); + UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2] = ((payload_ptr[1] & 0x0F) << 2) | ((payload_ptr[2] & 0xC0) >> 6); + UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] = (payload_ptr[2] & 0x3F); + + // update buffer info + old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]; + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0] = BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0]]; + + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0]; + if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; + else + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; + + old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]; + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1] = BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1]]; + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1]; + if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= + old_buffer_info; + else + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; + + old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]; + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2] = BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2]]; + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2]; + if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; + else + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; + + old_buffer_info = UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]; + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3] = BSR_TABLE[UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3]]; + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]; + if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= old_buffer_info) + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= old_buffer_info; + else + UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = 0; + + LOG_D(MAC, + "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " + "%u LCGID2 = %u LCGID3 = %u\n", enb_mod_idP, CC_idP, + rx_ces[i], + UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0], + UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1], + UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2], + UE_list->UE_template[CC_idP][UE_id]. + bsr_info[LCGID3]); + if (crnti_rx == 1) + LOG_D(MAC, + "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " + "%u LCGID2 = %u LCGID3 = %u\n", enb_mod_idP, + CC_idP, rx_ces[i], + UE_list->UE_template[CC_idP][UE_id]. + bsr_info[LCGID0], + UE_list->UE_template[CC_idP][UE_id]. + bsr_info[LCGID1], + UE_list->UE_template[CC_idP][UE_id]. + bsr_info[LCGID2], + UE_list->UE_template[CC_idP][UE_id]. + bsr_info[LCGID3]); + + if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0] == 0) { + UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID0] = 0; + } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID0] == 0) { + UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID0] = frameP; + } + + if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1] == 0) { + UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID1] = 0; + } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID1] == 0) { + UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID1] = frameP; + } + + if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2] == 0) { + UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID2] = 0; + } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID2] == 0) { + UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID2] = frameP; + } + + if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] == 0) { + UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID3] = 0; + } else if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID3] == 0) { + UE_list->UE_template[CC_idP][UE_id].ul_buffer_creation_time[LCGID3] = frameP; + + } + } + + payload_ptr += 3; ////sizeof(LONG_BSR); + break; + + default: + LOG_E(MAC, + "[eNB %d] CC_id %d Received unknown MAC header (0x%02x)\n", + enb_mod_idP, CC_idP, rx_ces[i]); + break; + } + } + + for (i = 0; i < num_sdu; i++) { + LOG_D(MAC, "SDU Number %d MAC Subheader SDU_LCID %d, length %d\n", + i, rx_lcids[i], rx_lengths[i]); + + T(T_ENB_MAC_UE_UL_SDU, T_INT(enb_mod_idP), T_INT(CC_idP), + T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), + T_INT(rx_lcids[i]), T_INT(rx_lengths[i])); + T(T_ENB_MAC_UE_UL_SDU_WITH_DATA, T_INT(enb_mod_idP), T_INT(CC_idP), + T_INT(current_rnti), T_INT(frameP), T_INT(subframeP), + T_INT(rx_lcids[i]), T_INT(rx_lengths[i]), T_BUFFER(payload_ptr, + rx_lengths + [i])); + + switch (rx_lcids[i]) { + case CCCH: + if (rx_lengths[i] > CCCH_PAYLOAD_SIZE_MAX) { + LOG_E(MAC, + "[eNB %d/%d] frame %d received CCCH of size %d (too big, maximum allowed is %d, sdu_len %d), dropping packet\n", + enb_mod_idP, CC_idP, frameP, rx_lengths[i], + CCCH_PAYLOAD_SIZE_MAX, sdu_lenP); + break; + } + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d, Received CCCH: %x.%x.%x.%x.%x.%x, Terminating RA procedure for UE rnti %x\n", + enb_mod_idP, CC_idP, frameP, payload_ptr[0], + payload_ptr[1], payload_ptr[2], payload_ptr[3], + payload_ptr[4], payload_ptr[5], current_rnti); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC, 1); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TERMINATE_RA_PROC, 0); + for (ii = 0; ii < NB_RA_PROC_MAX; ii++) { + RA_t *ra = &mac->common_channels[CC_idP].ra[ii]; + + LOG_D(MAC, + "[mac %d][RAPROC] CC_id %d Checking proc %d : rnti (%x, %x), state %d\n", + enb_mod_idP, CC_idP, ii, ra->rnti, + current_rnti, ra->state); + + if ((ra->rnti == current_rnti) && (ra->state != IDLE)) { + + //payload_ptr = parse_ulsch_header(msg3,&num_ce,&num_sdu,rx_ces,rx_lcids,rx_lengths,msg3_len); + + if (UE_id < 0) { + memcpy(&ra->cont_res_id[0], payload_ptr, 6); + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3: length %d, offset %ld\n", + enb_mod_idP, CC_idP, frameP, rx_lengths[i], + payload_ptr - sduP); + + if ((UE_id = add_new_ue(enb_mod_idP, CC_idP, + mac->common_channels[CC_idP]. + ra[ii].rnti, harq_pid +#ifdef Rel14 + , + mac->common_channels[CC_idP]. + ra[ii].rach_resource_type +#endif + )) == -1) { + AssertFatal(1 == 0, + "[MAC][eNB] Max user count reached\n"); + // kill RA procedure + } else + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d Added user with rnti %x => UE %d\n", + enb_mod_idP, CC_idP, frameP, ra->rnti, + UE_id); + } else { + LOG_D(MAC, + "[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3 from already registered UE %d: length %d, offset %ld\n", + enb_mod_idP, CC_idP, frameP, UE_id, + rx_lengths[i], payload_ptr - sduP); + // kill RA procedure + } + + mac_rrc_data_ind(enb_mod_idP, + CC_idP, + frameP, subframeP, + current_rnti, + CCCH, + (uint8_t *) payload_ptr, + rx_lengths[i], + 0); + + + if (num_ce > 0) { // handle msg3 which is not RRCConnectionRequest + // process_ra_message(msg3,num_ce,rx_lcids,rx_ces); + } + // prepare transmission of Msg4 + ra->state = MSG4; + + + + // Program Msg4 PDCCH+DLSCH/MPDCCH transmission 4 subframes from now, // Check if this is ok for BL/CE, or if the rule is different + ra->Msg4_frame = frameP + ((subframeP > 5) ? 1 : 0); + ra->Msg4_subframe = (subframeP + 4) % 10; + + } // if process is active + } // loop on RA processes + + break; + + case DCCH: + case DCCH1: + // if(eNB_mac_inst[module_idP][CC_idP].Dcch_lchan[UE_id].Active==1){ + + +#if defined(ENABLE_MAC_PAYLOAD_DEBUG) + LOG_T(MAC, "offset: %d\n", + (unsigned char) ((unsigned char *) payload_ptr - sduP)); + for (j = 0; j < 32; j++) { + LOG_T(MAC, "%x ", payload_ptr[j]); + } + LOG_T(MAC, "\n"); +#endif + + if (UE_id != -1) { + // adjust buffer occupancy of the correponding logical channel group + if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] >= rx_lengths[i]) + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] -= rx_lengths[i]; + else + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] = 0; + + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DCCH, received %d bytes form UE %d on LCID %d \n", + enb_mod_idP, CC_idP, frameP, rx_lengths[i], UE_id, + rx_lcids[i]); + + mac_rlc_data_ind(enb_mod_idP, current_rnti, enb_mod_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, rx_lcids[i], (char *) payload_ptr, rx_lengths[i], 1, NULL); //(unsigned int*)crc_status); + UE_list->eNB_UE_stats[CC_idP][UE_id].num_pdu_rx[rx_lcids[i]] += 1; + UE_list->eNB_UE_stats[CC_idP][UE_id].num_bytes_rx[rx_lcids[i]] += rx_lengths[i]; + + + } + + /* UE_id != -1 */ + // } + break; + + // all the DRBS + case DTCH: + default: + +#if defined(ENABLE_MAC_PAYLOAD_DEBUG) + LOG_T(MAC, "offset: %d\n", + (unsigned char) ((unsigned char *) payload_ptr - sduP)); + for (j = 0; j < 32; j++) { + LOG_T(MAC, "%x ", payload_ptr[j]); + } + LOG_T(MAC, "\n"); +#endif + if (rx_lcids[i] < NB_RB_MAX) { + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d\n", + enb_mod_idP, CC_idP, frameP, rx_lengths[i], UE_id, + rx_lcids[i]); + + if (UE_id != -1) { + // adjust buffer occupancy of the correponding logical channel group + LOG_D(MAC, + "[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DTCH, received %d bytes from UE %d for lcid %d, removing from LCGID %ld, %d\n", + enb_mod_idP, CC_idP, frameP, rx_lengths[i], + UE_id, rx_lcids[i], + UE_list->UE_template[CC_idP][UE_id]. + lcgidmap[rx_lcids[i]], + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[UE_list->UE_template[CC_idP] + [UE_id].lcgidmap[rx_lcids[i]]]); + + if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] >= rx_lengths[i]) + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] -= rx_lengths[i]; + else + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] = 0; + if ((rx_lengths[i] < SCH_PAYLOAD_SIZE_MAX) && (rx_lengths[i] > 0)) { // MAX SIZE OF transport block + mac_rlc_data_ind(enb_mod_idP, current_rnti, enb_mod_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, rx_lcids[i], (char *) payload_ptr, rx_lengths[i], 1, NULL); //(unsigned int*)crc_status); + + UE_list->eNB_UE_stats[CC_idP][UE_id].num_pdu_rx[rx_lcids[i]] += 1; + UE_list->eNB_UE_stats[CC_idP][UE_id].num_bytes_rx[rx_lcids[i]] += rx_lengths[i]; + //clear uplane_inactivity_timer + UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0; + } else { /* rx_length[i] */ + UE_list->eNB_UE_stats[CC_idP][UE_id].num_errors_rx += 1; + LOG_E(MAC, + "[eNB %d] CC_id %d Frame %d : Max size of transport block reached LCID %d from UE %d ", + enb_mod_idP, CC_idP, frameP, rx_lcids[i], + UE_id); + } + } else { /*(UE_id != -1 */ + LOG_E(MAC, + "[eNB %d] CC_id %d Frame %d : received unsupported or unknown LCID %d from UE %d ", + enb_mod_idP, CC_idP, frameP, rx_lcids[i], UE_id); + } + } + + break; } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_RX_SDU, 0); - stop_meas(&mac->rx_ulsch_sdu); + payload_ptr += rx_lengths[i]; + } + + // Program ACK for PHICH + LOG_D(MAC, + "Programming PHICH ACK for rnti %x harq_pid %d (first_rb %d)\n", + current_rnti, harq_pid, first_rb); + nfapi_hi_dci0_request_t *hi_dci0_req = &mac->HI_DCI0_req[CC_idP]; + nfapi_hi_dci0_request_body_t *hi_dci0_req_body = &hi_dci0_req->hi_dci0_request_body; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = + &hi_dci0_req_body->hi_dci0_pdu_list[hi_dci0_req_body->number_of_dci + hi_dci0_req_body->number_of_hi]; + memset((void *) hi_dci0_pdu, 0, sizeof(nfapi_hi_dci0_request_pdu_t)); + hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; + hi_dci0_pdu->pdu_size = 2 + sizeof(nfapi_hi_dci0_hi_pdu); + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_HI_PDU_REL8_TAG; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = first_rb; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = 0; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 1; + hi_dci0_req_body->number_of_hi++; + hi_dci0_req_body->sfnsf = sfnsf_add_subframe(frameP,subframeP, 0); + hi_dci0_req_body->tl.tag = NFAPI_HI_DCI0_REQUEST_BODY_TAG; + hi_dci0_req->sfn_sf = sfnsf_add_subframe(frameP,subframeP, 4); + hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST; + + /* NN--> FK: we could either check the payload, or use a phy helper to detect a false msg3 */ + if ((num_sdu == 0) && (num_ce == 0)) { + if (UE_id != -1) + UE_list->eNB_UE_stats[CC_idP][UE_id].total_num_errors_rx += 1; + /* + if (msg3_flagP != NULL) { + if( *msg3_flagP == 1 ) { + LOG_N(MAC,"[eNB %d] CC_id %d frame %d : false msg3 detection: signal phy to canceling RA and remove the UE\n", enb_mod_idP, CC_idP, frameP); + *msg3_flagP=0; + } + } */ + } else { + if (UE_id != -1) { + UE_list->eNB_UE_stats[CC_idP][UE_id].pdu_bytes_rx = sdu_lenP; + UE_list->eNB_UE_stats[CC_idP][UE_id].total_pdu_bytes_rx += sdu_lenP; + UE_list->eNB_UE_stats[CC_idP][UE_id].total_num_pdus_rx += 1; + } + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_SDU, 0); + stop_meas(&mac->rx_ulsch_sdu); } uint32_t bytes_to_bsr_index(int32_t nbytes) { - uint32_t i = 0; + uint32_t i = 0; - if (nbytes < 0) { - return (0); - } + if (nbytes < 0) { + return (0); + } - while ((i < BSR_TABLE_SIZE) && (BSR_TABLE[i] <= nbytes)) { - i++; - } + while ((i < BSR_TABLE_SIZE) && (BSR_TABLE[i] <= nbytes)) { + i++; + } - return (i - 1); + return (i - 1); } void add_ue_ulsch_info(module_id_t module_idP, int CC_id, int UE_id, sub_frame_t subframeP, UE_ULSCH_STATUS status) { - eNB_ulsch_info[module_idP][CC_id][UE_id].rnti = - UE_RNTI(module_idP, UE_id); - eNB_ulsch_info[module_idP][CC_id][UE_id].subframe = subframeP; - eNB_ulsch_info[module_idP][CC_id][UE_id].status = status; + eNB_ulsch_info[module_idP][CC_id][UE_id].rnti = UE_RNTI(module_idP, UE_id); + eNB_ulsch_info[module_idP][CC_id][UE_id].subframe = subframeP; + eNB_ulsch_info[module_idP][CC_id][UE_id].status = status; - eNB_ulsch_info[module_idP][CC_id][UE_id].serving_num++; + eNB_ulsch_info[module_idP][CC_id][UE_id].serving_num++; } unsigned char *parse_ulsch_header(unsigned char *mac_header, @@ -836,77 +715,76 @@ unsigned char *parse_ulsch_header(unsigned char *mac_header, unsigned short *rx_lengths, unsigned short tb_length) { - unsigned char not_done = 1, num_ces = 0, num_sdus = - 0, lcid, num_sdu_cnt; - unsigned char *mac_header_ptr = mac_header; - unsigned short length, ce_len = 0; + unsigned char not_done = 1, num_ces = 0, num_sdus = + 0, lcid, num_sdu_cnt; + unsigned char *mac_header_ptr = mac_header; + unsigned short length, ce_len = 0; - while (not_done == 1) { + while (not_done == 1) { - if (((SCH_SUBHEADER_FIXED *) mac_header_ptr)->E == 0) { - not_done = 0; - } - - lcid = ((SCH_SUBHEADER_FIXED *) mac_header_ptr)->LCID; - - if (lcid < EXTENDED_POWER_HEADROOM) { - if (not_done == 0) { // last MAC SDU, length is implicit - mac_header_ptr++; - length = - tb_length - (mac_header_ptr - mac_header) - ce_len; - - for (num_sdu_cnt = 0; num_sdu_cnt < num_sdus; - num_sdu_cnt++) { - length -= rx_lengths[num_sdu_cnt]; - } - } else { - if (((SCH_SUBHEADER_SHORT *) mac_header_ptr)->F == 0) { - length = ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->L; - mac_header_ptr += 2; //sizeof(SCH_SUBHEADER_SHORT); - } else { // F = 1 - length = - ((((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB & - 0x7f) << 8) | (((SCH_SUBHEADER_LONG *) - mac_header_ptr)->L_LSB & 0xff); - mac_header_ptr += 3; //sizeof(SCH_SUBHEADER_LONG); - } - } - - LOG_D(MAC, - "[eNB] sdu %d lcid %d tb_length %d length %d (offset now %ld)\n", - num_sdus, lcid, tb_length, length, - mac_header_ptr - mac_header); - rx_lcids[num_sdus] = lcid; - rx_lengths[num_sdus] = length; - num_sdus++; - } else { // This is a control element subheader POWER_HEADROOM, BSR and CRNTI - if (lcid == SHORT_PADDING) { - mac_header_ptr++; - } else { - rx_ces[num_ces] = lcid; - num_ces++; - mac_header_ptr++; - - if (lcid == LONG_BSR) { - ce_len += 3; - } else if (lcid == CRNTI) { - ce_len += 2; - } else if ((lcid == POWER_HEADROOM) - || (lcid == TRUNCATED_BSR) - || (lcid == SHORT_BSR)) { - ce_len++; - } else { - LOG_E(MAC, "unknown CE %d \n", lcid); - AssertFatal(1 == 0, "unknown CE"); - } - } - } + if (((SCH_SUBHEADER_FIXED *) mac_header_ptr)->E == 0) { + not_done = 0; } - *num_ce = num_ces; - *num_sdu = num_sdus; + lcid = ((SCH_SUBHEADER_FIXED *) mac_header_ptr)->LCID; - return (mac_header_ptr); + if (lcid < EXTENDED_POWER_HEADROOM) { + if (not_done == 0) { // last MAC SDU, length is implicit + mac_header_ptr++; + length = tb_length - (mac_header_ptr - mac_header) - ce_len; + + for (num_sdu_cnt = 0; num_sdu_cnt < num_sdus; + num_sdu_cnt++) { + length -= rx_lengths[num_sdu_cnt]; + } + } else { + if (((SCH_SUBHEADER_SHORT *) mac_header_ptr)->F == 0) { + length = ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->L; + mac_header_ptr += 2; //sizeof(SCH_SUBHEADER_SHORT); + } else { // F = 1 + length = + ((((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB & + 0x7f) << 8) | (((SCH_SUBHEADER_LONG *) + mac_header_ptr)->L_LSB & 0xff); + mac_header_ptr += 3; //sizeof(SCH_SUBHEADER_LONG); + } + } + + LOG_D(MAC, + "[eNB] sdu %d lcid %d tb_length %d length %d (offset now %ld)\n", + num_sdus, lcid, tb_length, length, + mac_header_ptr - mac_header); + rx_lcids[num_sdus] = lcid; + rx_lengths[num_sdus] = length; + num_sdus++; + } else { // This is a control element subheader POWER_HEADROOM, BSR and CRNTI + if (lcid == SHORT_PADDING) { + mac_header_ptr++; + } else { + rx_ces[num_ces] = lcid; + num_ces++; + mac_header_ptr++; + + if (lcid == LONG_BSR) { + ce_len += 3; + } else if (lcid == CRNTI) { + ce_len += 2; + } else if ((lcid == POWER_HEADROOM) + || (lcid == TRUNCATED_BSR) + || (lcid == SHORT_BSR)) { + ce_len++; + } else { + LOG_E(MAC, "unknown CE %d \n", lcid); + AssertFatal(1 == 0, "unknown CE"); + } + } + } + } + + *num_ce = num_ces; + *num_sdu = num_sdus; + + return (mac_header_ptr); } /* This function is called by PHY layer when it schedules some @@ -921,16 +799,16 @@ set_msg3_subframe(module_id_t Mod_id, int subframe, int rnti, int Msg3_frame, int Msg3_subframe) { - eNB_MAC_INST *mac = RC.mac[Mod_id]; - int i; - for (i = 0; i < NB_RA_PROC_MAX; i++) { - if (mac->common_channels[CC_id].ra[i].state != IDLE && - mac->common_channels[CC_id].ra[i].rnti == rnti) { - mac->common_channels[CC_id].ra[i].Msg3_subframe = - Msg3_subframe; - break; - } + eNB_MAC_INST *mac = RC.mac[Mod_id]; + int i; + for (i = 0; i < NB_RA_PROC_MAX; i++) { + if (mac->common_channels[CC_id].ra[i].state != IDLE && + mac->common_channels[CC_id].ra[i].rnti == rnti) { + mac->common_channels[CC_id].ra[i].Msg3_subframe = + Msg3_subframe; + break; } + } } @@ -938,118 +816,118 @@ void schedule_ulsch(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) { - uint16_t first_rb[MAX_NUM_CCs], i; - int CC_id; - eNB_MAC_INST *mac = RC.mac[module_idP]; - COMMON_channels_t *cc; + uint16_t first_rb[MAX_NUM_CCs], i; + int CC_id; + eNB_MAC_INST *mac = RC.mac[module_idP]; + COMMON_channels_t *cc; - start_meas(&mac->schedule_ulsch); + start_meas(&mac->schedule_ulsch); - int sched_subframe = (subframeP + 4) % 10; + int sched_subframe = (subframeP + 4) % 10; - cc = &mac->common_channels[0]; - int tdd_sfa; - // for TDD: check subframes where we have to act and return if nothing should be done now - if (cc->tdd_Config) { - tdd_sfa = cc->tdd_Config->subframeAssignment; - switch (subframeP) { - case 0: - if ((tdd_sfa == 0) || (tdd_sfa == 3) || (tdd_sfa == 6)) - sched_subframe = 4; - else - return; - break; - case 1: - if ((tdd_sfa == 0) || (tdd_sfa == 1)) - sched_subframe = 7; - else if (tdd_sfa == 6) - sched_subframe = 8; - break; - default: - return; + cc = &mac->common_channels[0]; + int tdd_sfa; + // for TDD: check subframes where we have to act and return if nothing should be done now + if (cc->tdd_Config) { + tdd_sfa = cc->tdd_Config->subframeAssignment; + switch (subframeP) { + case 0: + if ((tdd_sfa == 0) || (tdd_sfa == 3) || (tdd_sfa == 6)) + sched_subframe = 4; + else + return; + break; + case 1: + if ((tdd_sfa == 0) || (tdd_sfa == 1)) + sched_subframe = 7; + else if (tdd_sfa == 6) + sched_subframe = 8; + break; + default: + return; - case 2: // Don't schedule UL in subframe 2 for TDD - return; - case 3: - if (tdd_sfa == 2) - sched_subframe = 7; - else - return; - break; - case 4: - if (tdd_sfa == 1) - sched_subframe = 8; - else - return; - break; - case 5: - if (tdd_sfa == 0) - sched_subframe = 9; - else if (tdd_sfa == 6) - sched_subframe = 3; - else - return; - break; - case 6: - if (tdd_sfa == 1) - sched_subframe = 2; - else if (tdd_sfa == 6) - sched_subframe = 3; - else - return; - break; - case 7: - return; - case 8: - if ((tdd_sfa >= 2) || (tdd_sfa <= 5)) - sched_subframe = 2; - else - return; - break; - case 9: - if ((tdd_sfa == 1) || (tdd_sfa == 3) || (tdd_sfa == 4)) - sched_subframe = 3; - else if (tdd_sfa == 6) - sched_subframe = 4; - else - return; - break; - } + case 2: // Don't schedule UL in subframe 2 for TDD + return; + case 3: + if (tdd_sfa == 2) + sched_subframe = 7; + else + return; + break; + case 4: + if (tdd_sfa == 1) + sched_subframe = 8; + else + return; + break; + case 5: + if (tdd_sfa == 0) + sched_subframe = 9; + else if (tdd_sfa == 6) + sched_subframe = 3; + else + return; + break; + case 6: + if (tdd_sfa == 1) + sched_subframe = 2; + else if (tdd_sfa == 6) + sched_subframe = 3; + else + return; + break; + case 7: + return; + case 8: + if ((tdd_sfa >= 2) || (tdd_sfa <= 5)) + sched_subframe = 2; + else + return; + break; + case 9: + if ((tdd_sfa == 1) || (tdd_sfa == 3) || (tdd_sfa == 4)) + sched_subframe = 3; + else if (tdd_sfa == 6) + sched_subframe = 4; + else + return; + break; } - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + } + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - //leave out first RB for PUCCH - first_rb[CC_id] = 1; + //leave out first RB for PUCCH + first_rb[CC_id] = 1; - // UE data info; - // check which UE has data to transmit - // function to decide the scheduling - // e.g. scheduling_rslt = Greedy(granted_UEs, nb_RB) + // UE data info; + // check which UE has data to transmit + // function to decide the scheduling + // e.g. scheduling_rslt = Greedy(granted_UEs, nb_RB) - // default function for default scheduling - // + // default function for default scheduling + // - // output of scheduling, the UE numbers in RBs, where it is in the code??? - // check if RA (Msg3) is active in this subframeP, if so skip the PRBs used for Msg3 - // Msg3 is using 1 PRB so we need to increase first_rb accordingly - // not sure about the break (can there be more than 1 active RA procedure?) + // output of scheduling, the UE numbers in RBs, where it is in the code??? + // check if RA (Msg3) is active in this subframeP, if so skip the PRBs used for Msg3 + // Msg3 is using 1 PRB so we need to increase first_rb accordingly + // not sure about the break (can there be more than 1 active RA procedure?) - for (i = 0; i < NB_RA_PROC_MAX; i++) { - if ((cc->ra[i].state == WAITMSG3) && - (cc->ra[i].Msg3_subframe == sched_subframe)) { - first_rb[CC_id]++; - // cc->ray[i].Msg3_subframe = -1; - break; - } - } + for (i = 0; i < NB_RA_PROC_MAX; i++) { + if ((cc->ra[i].state == WAITMSG3) && + (cc->ra[i].Msg3_subframe == sched_subframe)) { + first_rb[CC_id]++; + // cc->ray[i].Msg3_subframe = -1; + break; + } } + } - schedule_ulsch_rnti(module_idP, frameP, subframeP, sched_subframe, - first_rb); + schedule_ulsch_rnti(module_idP, frameP, subframeP, sched_subframe, + first_rb); - stop_meas(&mac->schedule_ulsch); + stop_meas(&mac->schedule_ulsch); } void @@ -1058,501 +936,467 @@ schedule_ulsch_rnti(module_id_t module_idP, sub_frame_t subframeP, unsigned char sched_subframeP, uint16_t * first_rb) { - int UE_id; - uint8_t aggregation = 2; - rnti_t rnti = -1; - uint8_t round = 0; - uint8_t harq_pid = 0; - uint8_t status = 0; - uint8_t rb_table_index = -1; - uint32_t cqi_req, cshift, ndi, tpc; - int32_t normalized_rx_power; - int32_t target_rx_power = -90; - static int32_t tpc_accumulated = 0; - int n; - int CC_id = 0; - int drop_ue = 0; - int N_RB_UL; - eNB_MAC_INST *mac = RC.mac[module_idP]; - COMMON_channels_t *cc = mac->common_channels; - UE_list_t *UE_list = &mac->UE_list; - UE_TEMPLATE *UE_template; - UE_sched_ctrl *UE_sched_ctrl; - int sched_frame = frameP; - int rvidx_tab[4] = { 0, 2, 3, 1 }; + int UE_id; + uint8_t aggregation = 2; + rnti_t rnti = -1; + uint8_t round = 0; + uint8_t harq_pid = 0; + uint8_t status = 0; + uint8_t rb_table_index = -1; + uint32_t cqi_req, cshift, ndi, tpc; + int32_t normalized_rx_power; + int32_t target_rx_power = -90; + static int32_t tpc_accumulated = 0; + int n; + int CC_id = 0; + int drop_ue = 0; + int N_RB_UL; + eNB_MAC_INST *mac = RC.mac[module_idP]; + COMMON_channels_t *cc = mac->common_channels; + UE_list_t *UE_list = &mac->UE_list; + UE_TEMPLATE *UE_template; + UE_sched_ctrl *UE_sched_ctrl; + int sched_frame = frameP; + int rvidx_tab[4] = { 0, 2, 3, 1 }; - if (sched_subframeP < subframeP) - sched_frame++; + if (sched_subframeP < subframeP) + sched_frame++; - nfapi_hi_dci0_request_t *hi_dci0_req = &mac->HI_DCI0_req[CC_id]; - nfapi_hi_dci0_request_body_t *hi_dci0_req_body = &hi_dci0_req->hi_dci0_request_body; - nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu; + nfapi_hi_dci0_request_t *hi_dci0_req = &mac->HI_DCI0_req[CC_id]; + nfapi_hi_dci0_request_body_t *hi_dci0_req_body = &hi_dci0_req->hi_dci0_request_body; + nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu; - nfapi_ul_config_request_t *ul_req_tmp = &mac->UL_req_tmp[CC_id][sched_subframeP]; - nfapi_ul_config_request_body_t *ul_req_tmp_body = &ul_req_tmp->ul_config_request_body; + nfapi_ul_config_request_t *ul_req_tmp = &mac->UL_req_tmp[CC_id][sched_subframeP]; + nfapi_ul_config_request_body_t *ul_req_tmp_body = &ul_req_tmp->ul_config_request_body; - //LOG_D(MAC, "entering ulsch preprocesor\n"); - ulsch_scheduler_pre_processor(module_idP, frameP, subframeP, first_rb); + //LOG_D(MAC, "entering ulsch preprocesor\n"); + ulsch_scheduler_pre_processor(module_idP, frameP, subframeP, first_rb); - //LOG_D(MAC, "exiting ulsch preprocesor\n"); + //LOG_D(MAC, "exiting ulsch preprocesor\n"); - hi_dci0_req->sfn_sf = (frameP << 4) + subframeP; + hi_dci0_req->sfn_sf = (frameP << 4) + subframeP; - // loop over all active UEs - for (UE_id = UE_list->head_ul; UE_id >= 0; - UE_id = UE_list->next_ul[UE_id]) { + // loop over all active UEs + for (UE_id = UE_list->head_ul; UE_id >= 0; + UE_id = UE_list->next_ul[UE_id]) { - // don't schedule if Msg4 is not received yet - if (UE_list->UE_template[UE_PCCID(module_idP, UE_id)][UE_id]. - configured == FALSE) { - LOG_D(MAC, - "[eNB %d] frame %d subfarme %d, UE %d: not configured, skipping UE scheduling \n", - module_idP, frameP, subframeP, UE_id); - continue; - } + // don't schedule if Msg4 is not received yet + if (UE_list->UE_template[UE_PCCID(module_idP, UE_id)][UE_id]. + configured == FALSE) { + LOG_D(MAC, + "[eNB %d] frame %d subfarme %d, UE %d: not configured, skipping UE scheduling \n", + module_idP, frameP, subframeP, UE_id); + continue; + } - rnti = UE_RNTI(module_idP, UE_id); + rnti = UE_RNTI(module_idP, UE_id); - if (rnti == NOT_A_RNTI) { - LOG_W(MAC, "[eNB %d] frame %d subfarme %d, UE %d: no RNTI \n", - module_idP, frameP, subframeP, UE_id); - continue; - } + if (rnti == NOT_A_RNTI) { + LOG_W(MAC, "[eNB %d] frame %d subfarme %d, UE %d: no RNTI \n", + module_idP, frameP, subframeP, UE_id); + continue; + } - drop_ue = 0; - /* let's drop the UE if get_eNB_UE_stats returns NULL when calling it with any of the UE's active UL CCs */ - /* TODO: refine? + drop_ue = 0; + /* let's drop the UE if get_eNB_UE_stats returns NULL when calling it with any of the UE's active UL CCs */ + /* TODO: refine? - for (n=0; nnumactiveULCCs[UE_id]; n++) { - CC_id = UE_list->ordered_ULCCids[n][UE_id]; + for (n=0; nnumactiveULCCs[UE_id]; n++) { + CC_id = UE_list->ordered_ULCCids[n][UE_id]; - if (mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti) == NULL) { - LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: no PHY context\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id); - drop_ue = 1; - break; - } - } */ - if (drop_ue == 1) { -/* we can't come here, ulsch_scheduler_pre_processor won't put in the list a UE with no PHY context */ - abort(); - /* TODO: this is a hack. Sometimes the UE has no PHY context but - * is still present in the MAC with 'ul_failure_timer' = 0 and - * 'ul_out_of_sync' = 0. It seems wrong and the UE stays there forever. Let's - * start an UL out of sync procedure in this case. - * The root cause of this problem has to be found and corrected. - * In the meantime, this hack... - */ - if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 0 && - UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 0) { - LOG_W(MAC, - "[eNB %d] frame %d subframe %d, UE %d/%x CC %d: UE in weird state, let's put it 'out of sync'\n", - module_idP, frameP, subframeP, UE_id, rnti, CC_id); - // inform RRC of failure and clear timer - mac_eNB_rrc_ul_failure(module_idP, CC_id, frameP, - subframeP, rnti); - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; - UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 1; + if (mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti) == NULL) { + LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: no PHY context\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id); + drop_ue = 1; + break; + } + } */ + if (drop_ue == 1) { + /* we can't come here, ulsch_scheduler_pre_processor won't put in the list a UE with no PHY context */ + abort(); + /* TODO: this is a hack. Sometimes the UE has no PHY context but + * is still present in the MAC with 'ul_failure_timer' = 0 and + * 'ul_out_of_sync' = 0. It seems wrong and the UE stays there forever. Let's + * start an UL out of sync procedure in this case. + * The root cause of this problem has to be found and corrected. + * In the meantime, this hack... + */ + if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 0 && + UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 0) { + LOG_W(MAC, + "[eNB %d] frame %d subframe %d, UE %d/%x CC %d: UE in weird state, let's put it 'out of sync'\n", + module_idP, frameP, subframeP, UE_id, rnti, CC_id); + // inform RRC of failure and clear timer + mac_eNB_rrc_ul_failure(module_idP, CC_id, frameP, + subframeP, rnti); + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; + UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 1; + } + continue; + } + // loop over all active UL CC_ids for this UE + for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; + N_RB_UL = to_prb(cc[CC_id].ul_Bandwidth); + + /* + aggregation=get_aggregation(get_bw_index(module_idP,CC_id), + eNB_UE_stats->dl_cqi, + format0); + */ + + if (CCE_allocation_infeasible + (module_idP, CC_id, 1, subframeP, aggregation, rnti)) { + LOG_W(MAC, + "[eNB %d] frame %d subframe %d, UE %d/%x CC %d: not enough nCCE\n", + module_idP, frameP, subframeP, UE_id, rnti, CC_id); + continue; // break; + } + + /* be sure that there are some free RBs */ + if (first_rb[CC_id] >= N_RB_UL - 1) { + LOG_W(MAC, + "[eNB %d] frame %d subframe %d, UE %d/%x CC %d: dropping, not enough RBs\n", + module_idP, frameP, subframeP, UE_id, rnti, CC_id); + continue; + } + // if (eNB_UE_stats->mode == PUSCH) { // ue has a ulsch channel + + UE_template = &UE_list->UE_template[CC_id][UE_id]; + UE_sched_ctrl = &UE_list->UE_sched_ctrl[UE_id]; + harq_pid = subframe2harqpid(&cc[CC_id], sched_frame, sched_subframeP); + round = UE_sched_ctrl->round_UL[CC_id][harq_pid]; + AssertFatal(round < 8, "round %d > 7 for UE %d/%x\n", round, + UE_id, rnti); + LOG_D(MAC, + "[eNB %d] frame %d subframe %d (sched_frame %d, sched_subframe %d), Checking PUSCH %d for UE %d/%x CC %d : aggregation level %d, N_RB_UL %d\n", + module_idP, frameP, subframeP, sched_frame, sched_subframeP, harq_pid, UE_id, rnti, + CC_id, aggregation, N_RB_UL); + + RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP * + 10) + + subframeP] = + UE_template->ul_total_buffer; + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BO,RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP * + 10) + + subframeP]); + if (UE_is_to_be_scheduled(module_idP, CC_id, UE_id) > 0 || round > 0) // || ((frameP%10)==0)) + // if there is information on bsr of DCCH, DTCH or if there is UL_SR, or if there is a packet to retransmit, or we want to schedule a periodic feedback every 10 frames + { + LOG_D(MAC, + "[eNB %d][PUSCH %d] Frame %d subframe %d Scheduling UE %d/%x in round %d(SR %d,UL_inactivity timer %d,UL_failure timer %d,cqi_req_timer %d)\n", + module_idP, harq_pid, frameP, subframeP, UE_id, rnti, + round, UE_template->ul_SR, + UE_sched_ctrl->ul_inactivity_timer, + UE_sched_ctrl->ul_failure_timer, + UE_sched_ctrl->cqi_req_timer); + // reset the scheduling request + UE_template->ul_SR = 0; + status = mac_eNB_get_rrc_status(module_idP, rnti); + if (status < RRC_CONNECTED) + cqi_req = 0; + else if (UE_sched_ctrl->cqi_req_timer > 30) { + if (nfapi_mode) { + cqi_req = 0; + } else { + cqi_req = 1; } - continue; - } - // loop over all active UL CC_ids for this UE - for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - N_RB_UL = to_prb(cc[CC_id].ul_Bandwidth); + UE_sched_ctrl->cqi_req_timer = 0; + } else + cqi_req = 0; - /* - aggregation=get_aggregation(get_bw_index(module_idP,CC_id), - eNB_UE_stats->dl_cqi, - format0); - */ + //power control + //compute the expected ULSCH RX power (for the stats) - if (CCE_allocation_infeasible - (module_idP, CC_id, 1, subframeP, aggregation, rnti)) { - LOG_W(MAC, - "[eNB %d] frame %d subframe %d, UE %d/%x CC %d: not enough nCCE\n", - module_idP, frameP, subframeP, UE_id, rnti, CC_id); - continue; // break; - } + // this is the normalized RX power and this should be constant (regardless of mcs + normalized_rx_power = UE_sched_ctrl->pusch_snr[CC_id]; + target_rx_power = 178; - /* be sure that there are some free RBs */ - if (first_rb[CC_id] >= N_RB_UL - 1) { - LOG_W(MAC, - "[eNB %d] frame %d subframe %d, UE %d/%x CC %d: dropping, not enough RBs\n", - module_idP, frameP, subframeP, UE_id, rnti, CC_id); - continue; - } - // if (eNB_UE_stats->mode == PUSCH) { // ue has a ulsch channel - - UE_template = &UE_list->UE_template[CC_id][UE_id]; - UE_sched_ctrl = &UE_list->UE_sched_ctrl[UE_id]; - harq_pid = - subframe2harqpid(&cc[CC_id], sched_frame, sched_subframeP); - round = UE_sched_ctrl->round_UL[CC_id][harq_pid]; - AssertFatal(round < 8, "round %d > 7 for UE %d/%x\n", round, - UE_id, rnti); - LOG_D(MAC, - "[eNB %d] frame %d subframe %d (sched_frame %d, sched_subframe %d), Checking PUSCH %d for UE %d/%x CC %d : aggregation level %d, N_RB_UL %d\n", - module_idP, frameP, subframeP, sched_frame, sched_subframeP, harq_pid, UE_id, rnti, - CC_id, aggregation, N_RB_UL); - - RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP * - 10) + - subframeP] = - UE_template->ul_total_buffer; - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME - (VCD_SIGNAL_DUMPER_VARIABLES_UE0_BO, - RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP * - 10) + - subframeP]); - if (UE_is_to_be_scheduled(module_idP, CC_id, UE_id) > 0 || round > 0) // || ((frameP%10)==0)) - // if there is information on bsr of DCCH, DTCH or if there is UL_SR, or if there is a packet to retransmit, or we want to schedule a periodic feedback every 10 frames + // this assumes accumulated tpc + // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out + int32_t framex10psubframe = UE_template->pusch_tpc_tx_frame * 10 + UE_template->pusch_tpc_tx_subframe; + if (((framex10psubframe + 10) <= (frameP * 10 + subframeP)) || //normal case + ((framex10psubframe > (frameP * 10 + subframeP)) && (((10240 - framex10psubframe + frameP * 10 + subframeP) >= 10)))) //frame wrap-around { - LOG_D(MAC, - "[eNB %d][PUSCH %d] Frame %d subframe %d Scheduling UE %d/%x in round %d(SR %d,UL_inactivity timer %d,UL_failure timer %d,cqi_req_timer %d)\n", - module_idP, harq_pid, frameP, subframeP, UE_id, rnti, - round, UE_template->ul_SR, - UE_sched_ctrl->ul_inactivity_timer, - UE_sched_ctrl->ul_failure_timer, - UE_sched_ctrl->cqi_req_timer); - // reset the scheduling request - UE_template->ul_SR = 0; - status = mac_eNB_get_rrc_status(module_idP, rnti); - if (status < RRC_CONNECTED) - cqi_req = 0; - else if (UE_sched_ctrl->cqi_req_timer > 30) { - if (nfapi_mode) { - cqi_req = 0; - } else { - cqi_req = 1; - } - UE_sched_ctrl->cqi_req_timer = 0; - } else - cqi_req = 0; + UE_template->pusch_tpc_tx_frame = frameP; + UE_template->pusch_tpc_tx_subframe = subframeP; + if (normalized_rx_power > (target_rx_power + 4)) { + tpc = 0; //-1 + tpc_accumulated--; + } else if (normalized_rx_power < (target_rx_power - 4)) { + tpc = 2; //+1 + tpc_accumulated++; + } else { + tpc = 1; //0 + } + } else { + tpc = 1; //0 + } + //tpc = 1; + if (tpc != 1) { + LOG_D(MAC, + "[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", + module_idP, frameP, subframeP, harq_pid, tpc, + tpc_accumulated, normalized_rx_power, + target_rx_power); + } + // new transmission + if (round == 0) { - //power control - //compute the expected ULSCH RX power (for the stats) + ndi = 1 - UE_template->oldNDI_UL[harq_pid]; + UE_template->oldNDI_UL[harq_pid] = ndi; + UE_list->eNB_UE_stats[CC_id][UE_id]. + normalized_rx_power = normalized_rx_power; + UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power = target_rx_power; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1 = UE_template->pre_assigned_mcs_ul; + UE_template->mcs_UL[harq_pid] = UE_template->pre_assigned_mcs_ul; //cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS + if (UE_template->pre_allocated_rb_table_index_ul >= 0) { + rb_table_index = + UE_template->pre_allocated_rb_table_index_ul; + } else { + UE_template->mcs_UL[harq_pid] = 10; //cmin (10, openair_daq_vars.target_ue_ul_mcs); + rb_table_index = 5; // for PHR + } - // this is the normalized RX power and this should be constant (regardless of mcs - normalized_rx_power = UE_sched_ctrl->pusch_snr[CC_id]; - target_rx_power = 178; - - // this assumes accumulated tpc - // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out - int32_t framex10psubframe = - UE_template->pusch_tpc_tx_frame * 10 + - UE_template->pusch_tpc_tx_subframe; - if (((framex10psubframe + 10) <= (frameP * 10 + subframeP)) || //normal case - ((framex10psubframe > (frameP * 10 + subframeP)) && (((10240 - framex10psubframe + frameP * 10 + subframeP) >= 10)))) //frame wrap-around - { - UE_template->pusch_tpc_tx_frame = frameP; - UE_template->pusch_tpc_tx_subframe = subframeP; - if (normalized_rx_power > (target_rx_power + 4)) { - tpc = 0; //-1 - tpc_accumulated--; - } else if (normalized_rx_power < (target_rx_power - 4)) { - tpc = 2; //+1 - tpc_accumulated++; - } else { - tpc = 1; //0 - } - } else { - tpc = 1; //0 - } - //tpc = 1; - if (tpc != 1) { - LOG_D(MAC, - "[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", - module_idP, frameP, subframeP, harq_pid, tpc, - tpc_accumulated, normalized_rx_power, - target_rx_power); - } - // new transmission - if (round == 0) { - - ndi = 1 - UE_template->oldNDI_UL[harq_pid]; - UE_template->oldNDI_UL[harq_pid] = ndi; - UE_list->eNB_UE_stats[CC_id][UE_id]. - normalized_rx_power = normalized_rx_power; - UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power = - target_rx_power; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1 = - UE_template->pre_assigned_mcs_ul; - UE_template->mcs_UL[harq_pid] = UE_template->pre_assigned_mcs_ul; //cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS - if (UE_template->pre_allocated_rb_table_index_ul >= 0) { - rb_table_index = - UE_template->pre_allocated_rb_table_index_ul; - } else { - UE_template->mcs_UL[harq_pid] = 10; //cmin (10, openair_daq_vars.target_ue_ul_mcs); - rb_table_index = 5; // for PHR - } - - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2 = - UE_template->mcs_UL[harq_pid]; - // buffer_occupancy = UE_template->ul_total_buffer; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2 = UE_template->mcs_UL[harq_pid]; + // buffer_occupancy = UE_template->ul_total_buffer; - while (((rb_table[rb_table_index] > - (N_RB_UL - 1 - first_rb[CC_id])) - || (rb_table[rb_table_index] > 45)) - && (rb_table_index > 0)) { - rb_table_index--; - } + while (((rb_table[rb_table_index] > + (N_RB_UL - 1 - first_rb[CC_id])) + || (rb_table[rb_table_index] > 45)) + && (rb_table_index > 0)) { + rb_table_index--; + } - UE_template->TBS_UL[harq_pid] = - get_TBS_UL(UE_template->mcs_UL[harq_pid], - rb_table[rb_table_index]); - UE_list->eNB_UE_stats[CC_id][UE_id]. - total_rbs_used_rx += rb_table[rb_table_index]; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_TBS = - UE_template->TBS_UL[harq_pid]; - // buffer_occupancy -= TBS; + UE_template->TBS_UL[harq_pid] = get_TBS_UL(UE_template->mcs_UL[harq_pid], + rb_table[rb_table_index]); + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx += rb_table[rb_table_index]; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_TBS = UE_template->TBS_UL[harq_pid]; + // buffer_occupancy -= TBS; - T(T_ENB_MAC_UE_UL_SCHEDULE, T_INT(module_idP), - T_INT(CC_id), T_INT(rnti), T_INT(frameP), - T_INT(subframeP), T_INT(harq_pid), - T_INT(UE_template->mcs_UL[harq_pid]), - T_INT(first_rb[CC_id]), - T_INT(rb_table[rb_table_index]), - T_INT(UE_template->TBS_UL[harq_pid]), T_INT(ndi)); + T(T_ENB_MAC_UE_UL_SCHEDULE, T_INT(module_idP), + T_INT(CC_id), T_INT(rnti), T_INT(frameP), + T_INT(subframeP), T_INT(harq_pid), + T_INT(UE_template->mcs_UL[harq_pid]), + T_INT(first_rb[CC_id]), + T_INT(rb_table[rb_table_index]), + T_INT(UE_template->TBS_UL[harq_pid]), T_INT(ndi)); - if (mac_eNB_get_rrc_status(module_idP, rnti) < - RRC_CONNECTED) - LOG_D(MAC, - "[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE %d (mcs %d, first rb %d, nb_rb %d, rb_table_index %d, TBS %d, harq_pid %d)\n", - module_idP, harq_pid, rnti, CC_id, frameP, - subframeP, UE_id, - UE_template->mcs_UL[harq_pid], - first_rb[CC_id], rb_table[rb_table_index], - rb_table_index, - UE_template->TBS_UL[harq_pid], harq_pid); + if (mac_eNB_get_rrc_status(module_idP, rnti) < RRC_CONNECTED) + LOG_D(MAC, + "[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE %d (mcs %d, first rb %d, nb_rb %d, rb_table_index %d, TBS %d, harq_pid %d)\n", + module_idP, harq_pid, rnti, CC_id, frameP, + subframeP, UE_id, + UE_template->mcs_UL[harq_pid], + first_rb[CC_id], rb_table[rb_table_index], + rb_table_index, + UE_template->TBS_UL[harq_pid], harq_pid); - // bad indices : 20 (40 PRB), 21 (45 PRB), 22 (48 PRB) - //store for possible retransmission - UE_template->nb_rb_ul[harq_pid] = - rb_table[rb_table_index]; - UE_template->first_rb_ul[harq_pid] = first_rb[CC_id]; + // bad indices : 20 (40 PRB), 21 (45 PRB), 22 (48 PRB) + //store for possible retransmission + UE_template->nb_rb_ul[harq_pid] = rb_table[rb_table_index]; + UE_template->first_rb_ul[harq_pid] = first_rb[CC_id]; - UE_sched_ctrl->ul_scheduled |= (1 << harq_pid); - if (UE_id == UE_list->head) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME - (VCD_SIGNAL_DUMPER_VARIABLES_UE0_SCHEDULED, - UE_sched_ctrl->ul_scheduled); + UE_sched_ctrl->ul_scheduled |= (1 << harq_pid); + if (UE_id == UE_list->head) + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_SCHEDULED, + UE_sched_ctrl->ul_scheduled); - // adjust total UL buffer status by TBS, wait for UL sdus to do final update - LOG_D(MAC, - "[eNB %d] CC_id %d UE %d/%x : adjusting ul_total_buffer, old %d, TBS %d\n", - module_idP, CC_id, UE_id, rnti, - UE_template->ul_total_buffer, - UE_template->TBS_UL[harq_pid]); - if (UE_template->ul_total_buffer > - UE_template->TBS_UL[harq_pid]) - UE_template->ul_total_buffer -= - UE_template->TBS_UL[harq_pid]; - else - UE_template->ul_total_buffer = 0; - LOG_D(MAC, "ul_total_buffer, new %d\n", - UE_template->ul_total_buffer); - // Cyclic shift for DM RS - cshift = 0; // values from 0 to 7 can be used for mapping the cyclic shift (36.211 , Table 5.5.2.1.1-1) - // save it for a potential retransmission - UE_template->cshift[harq_pid] = cshift; + // adjust total UL buffer status by TBS, wait for UL sdus to do final update + LOG_D(MAC, + "[eNB %d] CC_id %d UE %d/%x : adjusting ul_total_buffer, old %d, TBS %d\n", + module_idP, CC_id, UE_id, rnti, + UE_template->ul_total_buffer, + UE_template->TBS_UL[harq_pid]); + if (UE_template->ul_total_buffer > UE_template->TBS_UL[harq_pid]) + UE_template->ul_total_buffer -= UE_template->TBS_UL[harq_pid]; + else + UE_template->ul_total_buffer = 0; + LOG_D(MAC, "ul_total_buffer, new %d\n", + UE_template->ul_total_buffer); + // Cyclic shift for DM RS + cshift = 0; // values from 0 to 7 can be used for mapping the cyclic shift (36.211 , Table 5.5.2.1.1-1) + // save it for a potential retransmission + UE_template->cshift[harq_pid] = cshift; - hi_dci0_pdu = &hi_dci0_req_body->hi_dci0_pdu_list[hi_dci0_req_body->number_of_dci + hi_dci0_req_body->number_of_hi]; - memset((void *) hi_dci0_pdu, 0, - sizeof(nfapi_hi_dci0_request_pdu_t)); - hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE; - hi_dci0_pdu->pdu_size = - 2 + sizeof(nfapi_hi_dci0_dci_pdu); - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL8_TAG; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dci_format = - NFAPI_UL_DCI_FORMAT_0; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level = - aggregation; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti = rnti; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.transmission_power = - 6000; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8. - resource_block_start = first_rb[CC_id]; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8. - number_of_resource_block = - rb_table[rb_table_index]; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.mcs_1 = - UE_template->mcs_UL[harq_pid]; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8. - cyclic_shift_2_for_drms = cshift; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8. - frequency_hopping_enabled_flag = 0; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8. - new_data_indication_1 = ndi; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tpc = tpc; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.cqi_csi_request = - cqi_req; - hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dl_assignment_index = - UE_template->DAI_ul[sched_subframeP]; + hi_dci0_pdu = &hi_dci0_req_body->hi_dci0_pdu_list[hi_dci0_req_body->number_of_dci + hi_dci0_req_body->number_of_hi]; + memset((void *) hi_dci0_pdu, 0,sizeof(nfapi_hi_dci0_request_pdu_t)); + hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE; + hi_dci0_pdu->pdu_size = 2 + sizeof(nfapi_hi_dci0_dci_pdu); + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL8_TAG; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dci_format = NFAPI_UL_DCI_FORMAT_0; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level = aggregation; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti = rnti; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.transmission_power = 6000; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.resource_block_start = first_rb[CC_id]; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.number_of_resource_block = rb_table[rb_table_index]; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.mcs_1 = UE_template->mcs_UL[harq_pid]; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.cyclic_shift_2_for_drms = cshift; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.frequency_hopping_enabled_flag = 0; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.new_data_indication_1 = ndi; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tpc = tpc; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.cqi_csi_request = cqi_req; + hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dl_assignment_index = UE_template->DAI_ul[sched_subframeP]; - hi_dci0_req_body->number_of_dci++; - hi_dci0_req_body->sfnsf = sfnsf_add_subframe(frameP, subframeP, 4); - hi_dci0_req_body->tl.tag = NFAPI_HI_DCI0_REQUEST_BODY_TAG; + hi_dci0_req_body->number_of_dci++; + hi_dci0_req_body->sfnsf = sfnsf_add_subframe(frameP, subframeP, 4); + hi_dci0_req_body->tl.tag = NFAPI_HI_DCI0_REQUEST_BODY_TAG; - hi_dci0_req->sfn_sf = frameP<<4|subframeP; // sfnsf_add_subframe(sched_frame, sched_subframeP, 0); // sunday! - hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST; + hi_dci0_req->sfn_sf = frameP<<4|subframeP; // sfnsf_add_subframe(sched_frame, sched_subframeP, 0); // sunday! + hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST; - LOG_D(MAC, - "[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n", - harq_pid, frameP, subframeP, UE_id, rnti, - sched_frame, sched_subframeP); + LOG_D(MAC, + "[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n", + harq_pid, frameP, subframeP, UE_id, rnti, + sched_frame, sched_subframeP); - // Add UL_config PDUs - fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp_body->ul_config_pdu_list[ul_req_tmp_body->number_of_pdus], cqi_req, cc, UE_template->physicalConfigDedicated, get_tmode(module_idP, CC_id, UE_id), mac->ul_handle, rnti, first_rb[CC_id], // resource_block_start - rb_table[rb_table_index], // number_of_resource_blocks - UE_template->mcs_UL[harq_pid], cshift, // cyclic_shift_2_for_drms - 0, // frequency_hopping_enabled_flag - 0, // frequency_hopping_bits - ndi, // new_data_indication - 0, // redundancy_version - harq_pid, // harq_process_number - 0, // ul_tx_mode - 0, // current_tx_nb - 0, // n_srs - get_TBS_UL - (UE_template-> - mcs_UL[harq_pid], - rb_table - [rb_table_index])); + // Add UL_config PDUs + fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp_body->ul_config_pdu_list[ul_req_tmp_body->number_of_pdus], cqi_req, cc, UE_template->physicalConfigDedicated, get_tmode(module_idP, CC_id, UE_id), mac->ul_handle, rnti, first_rb[CC_id], // resource_block_start + rb_table[rb_table_index], // number_of_resource_blocks + UE_template->mcs_UL[harq_pid], cshift, // cyclic_shift_2_for_drms + 0, // frequency_hopping_enabled_flag + 0, // frequency_hopping_bits + ndi, // new_data_indication + 0, // redundancy_version + harq_pid, // harq_process_number + 0, // ul_tx_mode + 0, // current_tx_nb + 0, // n_srs + get_TBS_UL + (UE_template-> + mcs_UL[harq_pid], + rb_table + [rb_table_index])); #ifdef Rel14 - if (UE_template->rach_resource_type > 0) { // This is a BL/CE UE allocation - fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp_body->ul_config_pdu_list[ul_req_tmp_body->number_of_pdus], UE_template->rach_resource_type > 2 ? 2 : 1, 1, //total_number_of_repetitions - 1, //repetition_number - (frameP * - 10) + - subframeP); - } + if (UE_template->rach_resource_type > 0) { // This is a BL/CE UE allocation + fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp_body->ul_config_pdu_list[ul_req_tmp_body->number_of_pdus], UE_template->rach_resource_type > 2 ? 2 : 1, 1, //total_number_of_repetitions + 1, //repetition_number + (frameP * + 10) + + subframeP); + } #endif - ul_req_tmp->header.message_id = NFAPI_UL_CONFIG_REQUEST; - ul_req_tmp_body->number_of_pdus++; - ul_req_tmp_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; - mac->ul_handle++; + ul_req_tmp->header.message_id = NFAPI_UL_CONFIG_REQUEST; + ul_req_tmp_body->number_of_pdus++; + ul_req_tmp_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + mac->ul_handle++; - uint16_t ul_sched_frame = sched_frame; - uint16_t ul_sched_subframeP = sched_subframeP; + uint16_t ul_sched_frame = sched_frame; + uint16_t ul_sched_subframeP = sched_subframeP; - add_subframe(&ul_sched_frame, &ul_sched_subframeP, 2); - ul_req_tmp->sfn_sf = ul_sched_frame<<4|ul_sched_subframeP; + add_subframe(&ul_sched_frame, &ul_sched_subframeP, 2); + ul_req_tmp->sfn_sf = ul_sched_frame<<4|ul_sched_subframeP; - add_ue_ulsch_info(module_idP, - CC_id, UE_id, subframeP, - S_UL_SCHEDULED); + add_ue_ulsch_info(module_idP, + CC_id, UE_id, subframeP, + S_UL_SCHEDULED); - //LOG_D(MAC, "[eNB %d] CC_id %d Frame %d, subframeP %d: Generated ULSCH DCI for next UE_id %d, format 0\n", module_idP, CC_id, frameP, subframeP, UE_id); - LOG_D(MAC,"[PUSCH %d] SFN/SF:%04d%d UL_CFG:SFN/SF:%04d%d CQI:%d for UE %d/%x\n", harq_pid,frameP,subframeP,ul_sched_frame,ul_sched_subframeP,cqi_req,UE_id,rnti); + //LOG_D(MAC, "[eNB %d] CC_id %d Frame %d, subframeP %d: Generated ULSCH DCI for next UE_id %d, format 0\n", module_idP, CC_id, frameP, subframeP, UE_id); + LOG_D(MAC,"[PUSCH %d] SFN/SF:%04d%d UL_CFG:SFN/SF:%04d%d CQI:%d for UE %d/%x\n", harq_pid,frameP,subframeP,ul_sched_frame,ul_sched_subframeP,cqi_req,UE_id,rnti); - // increment first rb for next UE allocation - first_rb[CC_id] += rb_table[rb_table_index]; - } else { // round > 0 => retransmission - T(T_ENB_MAC_UE_UL_SCHEDULE_RETRANSMISSION, - T_INT(module_idP), T_INT(CC_id), T_INT(rnti), - T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), - T_INT(UE_template->mcs_UL[harq_pid]), - T_INT(first_rb[CC_id]), - T_INT(rb_table[rb_table_index]), T_INT(round)); + // increment first rb for next UE allocation + first_rb[CC_id] += rb_table[rb_table_index]; + } else { // round > 0 => retransmission + T(T_ENB_MAC_UE_UL_SCHEDULE_RETRANSMISSION, + T_INT(module_idP), T_INT(CC_id), T_INT(rnti), + T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), + T_INT(UE_template->mcs_UL[harq_pid]), + T_INT(first_rb[CC_id]), + T_INT(rb_table[rb_table_index]), T_INT(round)); - // fill in NAK information + // fill in NAK information - hi_dci0_pdu = &hi_dci0_req_body->hi_dci0_pdu_list[hi_dci0_req_body->number_of_dci + hi_dci0_req_body->number_of_hi]; - memset((void *) hi_dci0_pdu, 0, - sizeof(nfapi_hi_dci0_request_pdu_t)); - hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; - hi_dci0_pdu->pdu_size = - 2 + sizeof(nfapi_hi_dci0_hi_pdu); - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_HI_PDU_REL8_TAG; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = - UE_template->first_rb_ul[harq_pid]; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8. - cyclic_shift_2_for_drms = - UE_template->cshift[harq_pid]; - hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 0; - hi_dci0_req_body->number_of_hi++; - hi_dci0_req_body->sfnsf = sfnsf_add_subframe(sched_frame, sched_subframeP, 0); - hi_dci0_req->sfn_sf = frameP<<4|subframeP; - hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST; + hi_dci0_pdu = &hi_dci0_req_body->hi_dci0_pdu_list[hi_dci0_req_body->number_of_dci + hi_dci0_req_body->number_of_hi]; + memset((void *) hi_dci0_pdu, 0, + sizeof(nfapi_hi_dci0_request_pdu_t)); + hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_HI_PDU_TYPE; + hi_dci0_pdu->pdu_size = 2 + sizeof(nfapi_hi_dci0_hi_pdu); + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.tl.tag = NFAPI_HI_DCI0_REQUEST_HI_PDU_REL8_TAG; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.resource_block_start = UE_template->first_rb_ul[harq_pid]; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.cyclic_shift_2_for_drms = UE_template->cshift[harq_pid]; + hi_dci0_pdu->hi_pdu.hi_pdu_rel8.hi_value = 0; + hi_dci0_req_body->number_of_hi++; + hi_dci0_req_body->sfnsf = sfnsf_add_subframe(sched_frame, sched_subframeP, 0); + hi_dci0_req->sfn_sf = frameP<<4|subframeP; + hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST; - LOG_D(MAC, - "[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled (PHICH) UE %d (mcs %d, first rb %d, nb_rb %d, TBS %d, round %d)\n", - module_idP, harq_pid, rnti, CC_id, frameP, - subframeP, UE_id, UE_template->mcs_UL[harq_pid], - UE_template->first_rb_ul[harq_pid], - UE_template->nb_rb_ul[harq_pid], - UE_template->TBS_UL[harq_pid], round); - // Add UL_config PDUs - LOG_D(MAC, - "[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n", - harq_pid, frameP, subframeP, UE_id, rnti, - sched_frame, sched_subframeP); - fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp_body->ul_config_pdu_list[ul_req_tmp_body->number_of_pdus], cqi_req, cc, UE_template->physicalConfigDedicated, get_tmode(module_idP, CC_id, UE_id), mac->ul_handle, rnti, UE_template->first_rb_ul[harq_pid], // resource_block_start - UE_template->nb_rb_ul[harq_pid], // number_of_resource_blocks - UE_template->mcs_UL[harq_pid], cshift, // cyclic_shift_2_for_drms - 0, // frequency_hopping_enabled_flag - 0, // frequency_hopping_bits - UE_template->oldNDI_UL[harq_pid], // new_data_indication - rvidx_tab[round & 3], // redundancy_version - harq_pid, // harq_process_number - 0, // ul_tx_mode - 0, // current_tx_nb - 0, // n_srs - UE_template-> - TBS_UL[harq_pid]); + LOG_D(MAC, + "[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled (PHICH) UE %d (mcs %d, first rb %d, nb_rb %d, TBS %d, round %d)\n", + module_idP, harq_pid, rnti, CC_id, frameP, + subframeP, UE_id, UE_template->mcs_UL[harq_pid], + UE_template->first_rb_ul[harq_pid], + UE_template->nb_rb_ul[harq_pid], + UE_template->TBS_UL[harq_pid], round); + // Add UL_config PDUs + LOG_D(MAC, + "[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d\n", + harq_pid, frameP, subframeP, UE_id, rnti, + sched_frame, sched_subframeP); + fill_nfapi_ulsch_config_request_rel8(&ul_req_tmp_body->ul_config_pdu_list[ul_req_tmp_body->number_of_pdus], cqi_req, cc, UE_template->physicalConfigDedicated, get_tmode(module_idP, CC_id, UE_id), mac->ul_handle, rnti, UE_template->first_rb_ul[harq_pid], // resource_block_start + UE_template->nb_rb_ul[harq_pid], // number_of_resource_blocks + UE_template->mcs_UL[harq_pid], cshift, // cyclic_shift_2_for_drms + 0, // frequency_hopping_enabled_flag + 0, // frequency_hopping_bits + UE_template->oldNDI_UL[harq_pid], // new_data_indication + rvidx_tab[round & 3], // redundancy_version + harq_pid, // harq_process_number + 0, // ul_tx_mode + 0, // current_tx_nb + 0, // n_srs + UE_template-> + TBS_UL[harq_pid]); #ifdef Rel14 - if (UE_template->rach_resource_type > 0) { // This is a BL/CE UE allocation - fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp_body->ul_config_pdu_list[ul_req_tmp_body->number_of_pdus], UE_template->rach_resource_type > 2 ? 2 : 1, 1, //total_number_of_repetitions - 1, //repetition_number - (frameP * - 10) + - subframeP); - } + if (UE_template->rach_resource_type > 0) { // This is a BL/CE UE allocation + fill_nfapi_ulsch_config_request_emtc(&ul_req_tmp_body->ul_config_pdu_list[ul_req_tmp_body->number_of_pdus], UE_template->rach_resource_type > 2 ? 2 : 1, 1, //total_number_of_repetitions + 1, //repetition_number + (frameP * + 10) + + subframeP); + } #endif - ul_req_tmp_body->number_of_pdus++; - mac->ul_handle++; + ul_req_tmp_body->number_of_pdus++; + mac->ul_handle++; - ul_req_tmp_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + ul_req_tmp_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; - ul_req_tmp->sfn_sf = sched_frame<<4|sched_subframeP; - ul_req_tmp->header.message_id = NFAPI_UL_CONFIG_REQUEST; + ul_req_tmp->sfn_sf = sched_frame<<4|sched_subframeP; + ul_req_tmp->header.message_id = NFAPI_UL_CONFIG_REQUEST; - LOG_D(MAC,"[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d cqi_req %d\n", - harq_pid,frameP,subframeP,UE_id,rnti,sched_frame,sched_subframeP,cqi_req); - } /* - else if (round > 0) { //we schedule a retransmission + LOG_D(MAC,"[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d cqi_req %d\n", + harq_pid,frameP,subframeP,UE_id,rnti,sched_frame,sched_subframeP,cqi_req); + } /* + else if (round > 0) { //we schedule a retransmission - ndi = UE_template->oldNDI_UL[harq_pid]; + ndi = UE_template->oldNDI_UL[harq_pid]; - if ((round&3)==0) { - mcs = openair_daq_vars.target_ue_ul_mcs; - } else { - mcs = rvidx_tab[round&3] + 28; //not correct for round==4! + if ((round&3)==0) { + mcs = openair_daq_vars.target_ue_ul_mcs; + } else { + mcs = rvidx_tab[round&3] + 28; //not correct for round==4! - } + } - LOG_I(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE retransmission (mcs %d, first rb %d, nb_rb %d, harq_pid %d, round %d)\n", - module_idP,UE_id,rnti,CC_id,frameP,subframeP,mcs, - first_rb[CC_id],UE_template->nb_rb_ul[harq_pid], - harq_pid, round); + LOG_I(MAC,"[eNB %d][PUSCH %d/%x] CC_id %d Frame %d subframeP %d Scheduled UE retransmission (mcs %d, first rb %d, nb_rb %d, harq_pid %d, round %d)\n", + module_idP,UE_id,rnti,CC_id,frameP,subframeP,mcs, + first_rb[CC_id],UE_template->nb_rb_ul[harq_pid], + harq_pid, round); - rballoc = mac_xface->computeRIV(frame_parms->N_RB_UL, - first_rb[CC_id], - UE_template->nb_rb_ul[harq_pid]); - first_rb[CC_id]+=UE_template->nb_rb_ul[harq_pid]; // increment for next UE allocation + rballoc = mac_xface->computeRIV(frame_parms->N_RB_UL, + first_rb[CC_id], + UE_template->nb_rb_ul[harq_pid]); + first_rb[CC_id]+=UE_template->nb_rb_ul[harq_pid]; // increment for next UE allocation - UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission_rx+=1; - UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx_rx=UE_template->nb_rb_ul[harq_pid]; - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=UE_template->nb_rb_ul[harq_pid]; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=mcs; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; - } - */ + UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission_rx+=1; + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx_rx=UE_template->nb_rb_ul[harq_pid]; + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx+=UE_template->nb_rb_ul[harq_pid]; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=mcs; + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; + } + */ - } // UE_is_to_be_scheduled - } // loop over UE_id - } // loop of CC_id + } // UE_is_to_be_scheduled + } // loop over UE_id + } // loop of CC_id } From 01f06bcf091b5eb5bfb566cb86af75a30ae05fda Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sat, 3 Feb 2018 08:11:48 -0800 Subject: [PATCH 202/284] compilation success --- openair2/LAYER2/MAC/config.c | 4 ++-- openair2/LAYER2/MAC/eNB_scheduler.c | 7 +++---- openair2/LAYER2/MAC/eNB_scheduler_RA.c | 3 ++- openair2/LAYER2/MAC/eNB_scheduler_bch.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_primitives.c | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index 2a74287b7e..07ed0735c2 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -270,12 +270,12 @@ void config_mib(int Mod_idP, LOG_I(MAC, "%s() NFAPI_CONFIG_REQUEST(num_tlv:%u) DL_BW:%u UL_BW:%u Ncp %d,p_eNB %d,earfcn %d,band %d,phich_resource %u phich_duration %u phich_power_offset %u PSS %d SSS %d PCI %d" #ifdef Rel14 - + " PBCH repetition %d" #endif "\n" ,__FUNCTION__ -` ,cfg->num_tlv + ,cfg->num_tlv ,cfg->rf_config.dl_channel_bandwidth.value ,cfg->rf_config.ul_channel_bandwidth.value ,NcpP,p_eNBP diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index e113cedb90..3c6471212a 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -636,7 +636,7 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, pdcp_run(&ctxt); - rrc_rx_tx(&ctxt, 0, CC_id); + rrc_rx_tx(&ctxt, CC_id); #if defined(Rel10) || defined(Rel14) @@ -681,7 +681,6 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, stop_meas(&RC.mac[module_idP]->eNB_scheduler); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME - (VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, - VCD_FUNCTION_OUT); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, + VCD_FUNCTION_OUT); } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c index a551465e57..51be84526f 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c @@ -923,7 +923,8 @@ generate_Msg4(module_id_t module_idP, int CC_idP, frame_t frameP, AssertFatal(reps > 2, "Have to handle programming of ACK when PDSCH repetitions is > 2\n"); ul_req = &mac->UL_req_tmp[CC_idP][ackNAK_absSF % 10]; - ul_req_body = &ul_req->ul_config_request_body;l_config_pdu = &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus]; + ul_req_body = &ul_req->ul_config_request_body; + ul_config_pdu = &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus]; ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE; ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_uci_harq_pdu)); diff --git a/openair2/LAYER2/MAC/eNB_scheduler_bch.c b/openair2/LAYER2/MAC/eNB_scheduler_bch.c index 258ca36c02..6b05977d89 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_bch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_bch.c @@ -698,7 +698,7 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) dl_req->number_pdu++; dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; memset((void *) dl_config_pdu, 0, - sizeof(nfapi_dl_config_request_p du_t)); + sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id]; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 740f183486..424459337d 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -1511,7 +1511,7 @@ fill_nfapi_ulsch_config_request_rel8(nfapi_ul_config_request_pdu_t *ul_config_pd for (int ri = 0; ri < (1 << ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size); ri++) - ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.periodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[ri] = get_dl_cqi_pmi_size_pusch(cc,tmode,1 + ri,physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic); + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[ri] = get_dl_cqi_pmi_size_pusch(cc,tmode,1 + ri,physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic); ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.delta_offset_cqi = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index; ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.delta_offset_ri = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index; From f55cbe475c50ec213781410d18ed99f853fa7f8d Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 5 Feb 2018 16:50:52 +0100 Subject: [PATCH 203/284] bugfix: fix initialUEMessage criticality S1AP specs say: initialUEMessage S1AP-ELEMENTARY-PROCEDURE ::= { INITIATING MESSAGE InitialUEMessage PROCEDURE CODE id-initialUEMessage CRITICALITY ignore } So let's use "ignore", not "reject". The online decoder http://asn1-playground.oss.com/ did not decode a message encoded by the eNB because of this. Only the S1AP messages captured while doing a simple connection of one UE have been tested with the online decoder. So, not all the S1AP messages have been checked, maybe some instances of this problem are still there. It does not seem to harm the actual UE<->eNB<->EPC communication (because we don't check the integrity of messages or because asn1c does not do it), so it's not a big deal. --- openair3/S1AP/s1ap_eNB_encoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/S1AP/s1ap_eNB_encoder.c b/openair3/S1AP/s1ap_eNB_encoder.c index 9a5f422158..7bd8bc09aa 100644 --- a/openair3/S1AP/s1ap_eNB_encoder.c +++ b/openair3/S1AP/s1ap_eNB_encoder.c @@ -470,7 +470,7 @@ int s1ap_eNB_encode_initial_ue_message( return s1ap_generate_initiating_message(buffer, length, S1ap_ProcedureCode_id_initialUEMessage, - S1ap_Criticality_reject, + S1ap_Criticality_ignore, &asn_DEF_S1ap_InitialUEMessage, initialUEMessage_p); } From a21c0b809f68f1ed3c711cfe376ecbfbe07f6c6f Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 5 Feb 2018 17:21:40 +0100 Subject: [PATCH 204/284] bugfix: fix RRC Release 10 compilation The following compilation did not work anymore: ./build_oai --eNB -w USRP -r Rel10 -c (Rel8 still does not work.) --- openair1/PHY/LTE_TRANSPORT/prach.c | 12 ++++++++---- openair1/PHY/LTE_TRANSPORT/proto.h | 7 +++---- openair1/PHY/defs.h | 2 ++ openair1/PHY/impl_defs_lte.h | 4 ++-- openair1/SCHED/fapi_l1.c | 13 ++++++++++++- openair1/SCHED/prach_procedures.c | 3 ++- openair2/LAYER2/MAC/config.c | 8 ++++++-- openair2/LAYER2/MAC/eNB_scheduler_RA.c | 9 +++++++++ openair2/LAYER2/MAC/eNB_scheduler_bch.c | 6 ++++++ openair2/LAYER2/MAC/eNB_scheduler_primitives.c | 4 ++++ openair2/RRC/LITE/rrc_eNB.c | 14 ++++++++++++++ targets/RT/USER/lte-enb.c | 2 ++ 12 files changed, 70 insertions(+), 14 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c index a332670a59..b58aa91636 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.c +++ b/openair1/PHY/LTE_TRANSPORT/prach.c @@ -1089,6 +1089,10 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1 } //__m128i mmtmpX0,mmtmpX1,mmtmpX2,mmtmpX3; +#ifndef Rel14 +#define rx_prach0 rx_prach +#endif + void rx_prach0(PHY_VARS_eNB *eNB, RU_t *ru, uint16_t *max_preamble, @@ -1764,9 +1768,8 @@ void rx_prach0(PHY_VARS_eNB *eNB, -#ifndef Rel14 -#define rx_prach rx_prach0 -#else +#ifdef Rel14 + void rx_prach(PHY_VARS_eNB *eNB, RU_t *ru, uint16_t *max_preamble, @@ -1806,7 +1809,8 @@ void rx_prach(PHY_VARS_eNB *eNB, } } } -#endif + +#endif /* Rel14 */ void init_prach_tables(int N_ZC) { diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 8afb7b14a3..be6d2861f2 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -2151,11 +2151,10 @@ void rx_prach(PHY_VARS_eNB *phy_vars_eNB,RU_t *ru, uint16_t *max_preamble, uint16_t *max_preamble_energy, uint16_t *max_preamble_delay, -#ifdef Rel14 - uint16_t Nf, uint8_t tdd_mapindex, - uint8_t br_flag -#else uint16_t Nf, uint8_t tdd_mapindex +#ifdef Rel14 + , + uint8_t br_flag #endif ); /*! diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 6f52867d2d..38da7e4e1e 100644 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -744,8 +744,10 @@ typedef struct RU_t_s{ int (*wakeup_rxtx)(struct PHY_VARS_eNB_s *eNB, struct RU_t_s *ru); /// function pointer to wakeup routine in lte-enb. void (*wakeup_prach_eNB)(struct PHY_VARS_eNB_s *eNB,struct RU_t_s *ru,int frame,int subframe); +#ifdef Rel14 /// function pointer to wakeup routine in lte-enb. void (*wakeup_prach_eNB_br)(struct PHY_VARS_eNB_s *eNB,struct RU_t_s *ru,int frame,int subframe); +#endif /// function pointer to eNB entry routine void (*eNB_top)(struct PHY_VARS_eNB_s *eNB, int frame_rx, int subframe_rx, char *string); /// Timing statistics diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h index ac54be36fb..066dc7012c 100644 --- a/openair1/PHY/impl_defs_lte.h +++ b/openair1/PHY/impl_defs_lte.h @@ -144,8 +144,6 @@ typedef struct { uint8_t prach_hopping_offset[4]; } PRACH_eMTC_CONFIG_INFO; -#endif - /// PRACH-ConfigSIB or PRACH-Config from 36.331 RRC spec typedef struct { /// Parameter: RACH_ROOT_SEQUENCE, see TS 36.211 (5.7.1). \vr{[0..837]} @@ -158,6 +156,8 @@ typedef struct { #endif } PRACH_eMTC_CONFIG_COMMON; +#endif + /// Enumeration for parameter \f$N_\text{ANRep}\f$ \ref PUCCH_CONFIG_DEDICATED::repetitionFactor. typedef enum { n2=0, diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c index 2fa9c9c2cd..b9024bdfbf 100644 --- a/openair1/SCHED/fapi_l1.c +++ b/openair1/SCHED/fapi_l1.c @@ -63,6 +63,7 @@ void handle_nfapi_dci_dl_pdu(PHY_VARS_eNB *eNB, } #ifdef Rel14 + void handle_nfapi_mpdcch_pdu(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, nfapi_dl_config_request_pdu_t *dl_config_pdu) @@ -76,6 +77,7 @@ void handle_nfapi_mpdcch_pdu(PHY_VARS_eNB *eNB, // copy dci configuration into eNB structure fill_mdci_and_dlsch(eNB,proc,&mpdcch_vars->mdci_alloc[mpdcch_vars->num_dci],pdu); } + #endif void handle_nfapi_hi_dci0_dci_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc, @@ -265,14 +267,21 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_pr dlsch0_harq->codeword = 0; dlsch0_harq->pdsch_start = rel10->pdsch_start; } -#endif dlsch0->i0 = rel13->initial_transmission_sf_io; +#endif +#ifdef Rel14 LOG_D(PHY,"dlsch->i0:%04x dlsch0_harq[pdsch_start:%d nb_rb:%d vrb_type:%d rvidx:%d Nl:%d mimo_mode:%d dl_power_off:%d round:%d status:%d TBS:%d Qm:%d codeword:%d rb_alloc:%d] rel8[length:%d]\n", dlsch0->i0, dlsch0_harq->pdsch_start, dlsch0_harq->nb_rb, dlsch0_harq->vrb_type, dlsch0_harq->rvidx, dlsch0_harq->Nl, dlsch0_harq->mimo_mode, dlsch0_harq->dl_power_off, dlsch0_harq->round, dlsch0_harq->status, dlsch0_harq->TBS, dlsch0_harq->Qm, dlsch0_harq->codeword, dlsch0_harq->rb_alloc[0], rel8->length ); +#else + LOG_D(PHY,"dlsch0_harq[pdsch_start:%d nb_rb:%d vrb_type:%d rvidx:%d Nl:%d mimo_mode:%d dl_power_off:%d round:%d status:%d TBS:%d Qm:%d codeword:%d rb_alloc:%d] rel8[length:%d]\n", + dlsch0_harq->pdsch_start, dlsch0_harq->nb_rb, dlsch0_harq->vrb_type, dlsch0_harq->rvidx, dlsch0_harq->Nl, dlsch0_harq->mimo_mode, dlsch0_harq->dl_power_off, dlsch0_harq->round, dlsch0_harq->status, dlsch0_harq->TBS, dlsch0_harq->Qm, dlsch0_harq->codeword, dlsch0_harq->rb_alloc[0], + rel8->length + ); +#endif } uint16_t to_beta_offset_harqack[16]={16,20,25,32,40,50,64,80,101,127,160,248,400,640,1008,8}; @@ -764,8 +773,10 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) break; #ifdef Rel14 case NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE: +#ifdef Rel14 handle_nfapi_mpdcch_pdu(eNB,proc,dl_config_pdu); eNB->mpdcch_vars[subframe&1].num_dci++; +#endif break; #endif } diff --git a/openair1/SCHED/prach_procedures.c b/openair1/SCHED/prach_procedures.c index d8c6585074..f3b5644b92 100644 --- a/openair1/SCHED/prach_procedures.c +++ b/openair1/SCHED/prach_procedures.c @@ -52,8 +52,9 @@ extern uint32_t nfapi_mode; -void prach_procedures(PHY_VARS_eNB *eNB, +void prach_procedures(PHY_VARS_eNB *eNB #ifdef Rel14 + , int br_flag #endif ) { diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index d5a09bef85..27b194deb5 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -193,8 +193,12 @@ void config_mib(int Mod_idP, int NcpP, int p_eNBP, uint32_t dl_CarrierFreqP, - uint32_t ul_CarrierFreqP, - uint32_t pbch_repetitionP) { + uint32_t ul_CarrierFreqP +#ifdef Rel14 + , + uint32_t pbch_repetitionP +#endif + ) { nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c index 4bf96d3bce..62f42fd297 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c @@ -1642,6 +1642,8 @@ initiate_ra_proc(module_id_t module_idP, COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_id]; RA_t *ra = &cc->ra[0]; +#ifdef Rel14 + struct PRACH_ConfigSIB_v1310 *ext4_prach = NULL; PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13 = NULL; @@ -1653,6 +1655,9 @@ initiate_ra_proc(module_id_t module_idP, prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13; } + +#endif /* Rel14 */ + LOG_D(MAC, "[eNB %d][RAPROC] CC_id %d Frame %d, Subframe %d Initiating RA procedure for preamble index %d\n", module_idP, CC_id, frameP, subframeP, preamble_index); @@ -1666,6 +1671,8 @@ initiate_ra_proc(module_id_t module_idP, uint16_t msg2_subframe = subframeP; int offset; +#ifdef Rel14 + if (prach_ParametersListCE_r13 && prach_ParametersListCE_r13->list.count < rach_resource_type) { LOG_E(MAC, @@ -1675,6 +1682,8 @@ initiate_ra_proc(module_id_t module_idP, return; } +#endif /* Rel14 */ + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME (VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 1); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME diff --git a/openair2/LAYER2/MAC/eNB_scheduler_bch.c b/openair2/LAYER2/MAC/eNB_scheduler_bch.c index 9a1046ff26..f6c8a24a34 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_bch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_bch.c @@ -615,10 +615,16 @@ schedule_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) LOG_D(MAC, "Frame %d, subframe %d: Adding BCH PDU in position %d (length %d)\n", frameP, subframeP, dl_req->number_pdu, mib_sdu_length); if ((frameP & 1023) < 40) +#ifdef Rel14 LOG_D(MAC, "[eNB %d] Frame %d : MIB->BCH CC_id %d, Received %d bytes (cc->mib->message.schedulingInfoSIB1_BR_r13 %d)\n", module_idP, frameP, CC_id, mib_sdu_length, (int) cc->mib->message.schedulingInfoSIB1_BR_r13); +#else + LOG_D(MAC, + "[eNB %d] Frame %d : MIB->BCH CC_id %d, Received %d bytes\n", + module_idP, frameP, CC_id, mib_sdu_length); +#endif dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 3e574a56c3..940cf67319 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -914,6 +914,7 @@ get_dl_cqi_pmi_size_pusch(COMMON_channels_t * cc, uint8_t tmode, else if (ri >= 2 && cc->p_eNB == 4) return (4 + (N << 1) + 4 + (N << 1) + 4); break; +#ifdef Rel14 case CQI_ReportModeAperiodic_rm32_v1250: AssertFatal(tmode == 4 || tmode == 6 || tmode == 8 || tmode == 9 || tmode == 10, @@ -947,6 +948,7 @@ get_dl_cqi_pmi_size_pusch(COMMON_channels_t * cc, uint8_t tmode, return (4 + 4 + 4); break; +#endif /* Rel14 */ } AssertFatal(1 == 0, "Shouldn't get here\n"); return (0); @@ -4339,6 +4341,7 @@ extract_pusch_csi(module_id_t mod_idP, int CC_idP, int UE_id, } break; +#ifdef Rel14 case CQI_ReportModeAperiodic_rm32_v1250: AssertFatal(tmode == 4 || tmode == 5 || tmode == 6 || tmode == 8 || tmode == 9 @@ -4362,6 +4365,7 @@ extract_pusch_csi(module_id_t mod_idP, int CC_idP, int UE_id, tmode); AssertFatal(1 == 0, "CQI_ReportModeAperiodic_rm11 to be done\n"); break; +#endif /* Rel14 */ } } diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index fbc95c8b74..946da42920 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -416,7 +416,9 @@ init_MCCH( 0,//rnti (BCCH_BCH_Message_t *)NULL, (RadioResourceConfigCommonSIB_t *) NULL, +#ifdef Rel14 (RadioResourceConfigCommonSIB_t *) NULL, +#endif (struct PhysicalConfigDedicated *)NULL, #if defined(Rel10) || defined(Rel14) (SCellToAddMod_r10_t *)NULL, @@ -1169,7 +1171,9 @@ rrc_eNB_generate_RRCConnectionReestablishment( ctxt_pP->rnti, (BCCH_BCH_Message_t *) NULL, (RadioResourceConfigCommonSIB_t *) NULL, +#ifdef Rel14 (RadioResourceConfigCommonSIB_t *) NULL, +#endif (struct PhysicalConfigDedicated* ) ue_context_pP->ue_context.physicalConfigDedicated, #if defined(Rel10) || defined(Rel14) (SCellToAddMod_r10_t *)NULL, @@ -3976,7 +3980,9 @@ rrc_eNB_generate_RRCConnectionReconfiguration_handover( ue_context_pP->ue_context.rnti, (BCCH_BCH_Message_t *) NULL, (RadioResourceConfigCommonSIB_t*) NULL, +#ifdef Rel14 (RadioResourceConfigCommonSIB_t*) NULL, +#endif ue_context_pP->ue_context.physicalConfigDedicated, #if defined(Rel10) || defined(Rel14) (SCellToAddMod_r10_t *)NULL, @@ -4555,7 +4561,9 @@ rrc_eNB_generate_RRCConnectionReconfiguration_handover( ue_context_pP->ue_context.rnti, (BCCH_BCH_Message_t *) NULL, (RadioResourceConfigCommonSIB_t *) NULL, +#ifdef Rel14 (RadioResourceConfigCommonSIB_t *) NULL, +#endif ue_context_pP->ue_context.physicalConfigDedicated, #if defined(Rel10) || defined(Rel14) (SCellToAddMod_r10_t *)NULL, @@ -4825,7 +4833,9 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( ue_context_pP->ue_context.rnti, (BCCH_BCH_Message_t *) NULL, (RadioResourceConfigCommonSIB_t *) NULL, +#ifdef Rel14 (RadioResourceConfigCommonSIB_t *) NULL, +#endif ue_context_pP->ue_context.physicalConfigDedicated, #if defined(Rel10) || defined(Rel14) (SCellToAddMod_r10_t *)NULL, @@ -4878,7 +4888,9 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( ue_context_pP->ue_context.rnti, (BCCH_BCH_Message_t *) NULL, (RadioResourceConfigCommonSIB_t *) NULL, +#ifdef Rel14 (RadioResourceConfigCommonSIB_t *) NULL, +#endif ue_context_pP->ue_context.physicalConfigDedicated, #if defined(Rel10) || defined(Rel14) (SCellToAddMod_r10_t *)NULL, @@ -4994,7 +5006,9 @@ rrc_eNB_generate_RRCConnectionSetup( ue_context_pP->ue_context.rnti, (BCCH_BCH_Message_t *) NULL, (RadioResourceConfigCommonSIB_t *) NULL, +#ifdef Rel14 (RadioResourceConfigCommonSIB_t *) NULL, +#endif ue_context_pP->ue_context.physicalConfigDedicated, #if defined(Rel10) || defined(Rel14) (SCellToAddMod_r10_t *)NULL, diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 79973d3814..f447f6589d 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -1050,7 +1050,9 @@ void init_eNB_afterRU(void) { RC.ru[ru_id]->wakeup_rxtx = wakeup_rxtx; RC.ru[ru_id]->wakeup_prach_eNB = wakeup_prach_eNB; +#ifdef Rel14 RC.ru[ru_id]->wakeup_prach_eNB_br = wakeup_prach_eNB_br; +#endif RC.ru[ru_id]->eNB_top = eNB_top; } } From eccb96c4c2e3a1011af53a7466eb31741047e53f Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 6 Feb 2018 14:37:03 +0100 Subject: [PATCH 205/284] bugfix: fix UL over scheduling There is too much UL scheduling because the buffer status is overestimated. This commit tries to make things simpler. --- openair2/LAYER2/MAC/defs.h | 12 +- .../LAYER2/MAC/eNB_scheduler_primitives.c | 7 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 276 +++++++----------- openair2/LAYER2/MAC/pre_processor.c | 21 +- openair2/LAYER2/openair2_proc.c | 10 +- 5 files changed, 140 insertions(+), 186 deletions(-) diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 1afb0d6c43..3f721288b4 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -665,7 +665,7 @@ typedef struct { /// mcs from last UL scheduling uint8_t mcs_UL[8]; /// TBS from last UL scheduling - uint8_t TBS_UL[8]; + int TBS_UL[8]; /// Flag to indicate UL has been scheduled at least once boolean_t ul_active; /// Flag to indicate UE has been configured (ACK from RRCConnectionSetup received) @@ -720,9 +720,6 @@ typedef struct { // Logical channel info for link with RLC - /// Last received UE BSR info for each logical channel group id - uint8_t bsr_info[MAX_NUM_LCGID]; - /// LCGID mapping long lcgidmap[11]; @@ -749,8 +746,6 @@ typedef struct { /// size of remaining size to send for the downlink head SDU uint32_t dl_buffer_head_sdu_remaining_size_to_send[MAX_NUM_LCID]; - /// total uplink buffer size - uint32_t ul_total_buffer; /// uplink buffer creation time for each LCID uint32_t ul_buffer_creation_time[MAX_NUM_LCGID]; /// maximum uplink buffer creation time across all the LCIDs @@ -758,6 +753,11 @@ typedef struct { /// uplink buffer size per LCID uint32_t ul_buffer_info[MAX_NUM_LCGID]; + /// uplink bytes that are currently scheduled + int scheduled_ul_bytes; + /// estimation of the UL buffer size + int estimated_ul_buffer; + /// UE tx power int32_t ue_tx_power; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 3e574a56c3..653ea4b665 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -2483,14 +2483,15 @@ UE_is_to_be_scheduled(module_id_t module_idP, int CC_id, uint8_t UE_id) LOG_D(MAC, "[eNB %d][PUSCH] Checking UL requirements UE %d/%x\n", module_idP, UE_id, UE_RNTI(module_idP, UE_id)); - if ((UE_template->bsr_info[LCGID0] > 0) || (UE_template->bsr_info[LCGID1] > 0) || (UE_template->bsr_info[LCGID2] > 0) || (UE_template->bsr_info[LCGID3] > 0) || (UE_template->ul_SR > 0) || // uplink scheduling request + if ((UE_template->scheduled_ul_bytes < UE_template->estimated_ul_buffer) || + (UE_template->ul_SR > 0) || // uplink scheduling request ((UE_sched_ctl->ul_inactivity_timer > 20) && (UE_sched_ctl->ul_scheduled == 0)) || // every 2 frames when RRC_CONNECTED ((UE_sched_ctl->ul_inactivity_timer > 10) && (UE_sched_ctl->ul_scheduled == 0) && (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED))) // every Frame when not RRC_CONNECTED { LOG_D(MAC, - "[eNB %d][PUSCH] UE %d/%x should be scheduled (BSR0 %d,SR %d)\n", + "[eNB %d][PUSCH] UE %d/%x should be scheduled (SRB0 estimated size %d,SR %d)\n", module_idP, UE_id, UE_RNTI(module_idP, UE_id), - UE_template->bsr_info[LCGID0], UE_template->ul_SR); + UE_template->ul_buffer_info[LCGID0], UE_template->ul_SR); return (1); } else { return (0); diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index f841d9d55a..e726ed7738 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -96,10 +96,10 @@ rx_sdu(const module_id_t enb_mod_idP, eNB_MAC_INST *mac = RC.mac[enb_mod_idP]; int harq_pid = subframe2harqpid(&mac->common_channels[CC_idP], frameP, subframeP); + int lcgid_updated[4] = {0, 0, 0, 0}; UE_list_t *UE_list = &mac->UE_list; int crnti_rx = 0; - int old_buffer_info; RA_t *ra = (RA_t *) & RC.mac[enb_mod_idP]->common_channels[CC_idP].ra[0]; int first_rb = 0; @@ -153,6 +153,12 @@ rx_sdu(const module_id_t enb_mod_idP, subframeP, UE_RNTI(enb_mod_idP, UE_id)); } + + /* update scheduled bytes */ + UE_list->UE_template[CC_idP][UE_id].scheduled_ul_bytes -= + UE_list->UE_template[CC_idP][UE_id].TBS_UL[harq_pid]; + if (UE_list->UE_template[CC_idP][UE_id].scheduled_ul_bytes < 0) + UE_list->UE_template[CC_idP][UE_id].scheduled_ul_bytes = 0; } else { // we've got an error LOG_D(MAC, "[eNB %d][PUSCH %d] CC_id %d ULSCH in error in round %d, ul_cqi %d\n", @@ -161,15 +167,16 @@ rx_sdu(const module_id_t enb_mod_idP, ul_cqi); // AssertFatal(1==0,"ulsch in error\n"); - if (UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] == - 3) { - UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= - (~(1 << harq_pid)); - UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] = - 0; - if (UE_list->UE_sched_ctrl[UE_id]. - ul_consecutive_errors++ == 10) + if (UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] == 3) { + UE_list->UE_sched_ctrl[UE_id].ul_scheduled &= (~(1 << harq_pid)); + UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid] = 0; + if (UE_list->UE_sched_ctrl[UE_id]. ul_consecutive_errors++ == 10) UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 1; + /* update scheduled bytes */ + UE_list->UE_template[CC_idP][UE_id].scheduled_ul_bytes -= + UE_list->UE_template[CC_idP][UE_id].TBS_UL[harq_pid]; + if (UE_list->UE_template[CC_idP][UE_id].scheduled_ul_bytes < 0) + UE_list->UE_template[CC_idP][UE_id].scheduled_ul_bytes = 0; } else UE_list->UE_sched_ctrl[UE_id].round_UL[CC_idP][harq_pid]++; return; @@ -321,20 +328,19 @@ rx_sdu(const module_id_t enb_mod_idP, enb_mod_idP, CC_idP, rx_ces[i], lcgid, payload_ptr[0] & 0x3f); if (UE_id != -1) { + int bsr = payload_ptr[0] & 0x3f; - UE_list->UE_template[CC_idP][UE_id].bsr_info[lcgid] = - (payload_ptr[0] & 0x3f); + lcgid_updated[lcgid] = 1; // update buffer info + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid] = BSR_TABLE[bsr]; - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[lcgid] = - BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. - bsr_info[lcgid]]; - - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[lcgid]; + UE_list->UE_template[CC_idP][UE_id].estimated_ul_buffer = + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[0] + + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[1] + + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[2] + + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[3]; + //UE_list->UE_template[CC_idP][UE_id].estimated_ul_buffer += UE_list->UE_template[CC_idP][UE_id].estimated_ul_buffer / 4; RC.eNB[enb_mod_idP][CC_idP]-> pusch_stats_bsr[UE_id][(frameP * 10) + subframeP] @@ -355,12 +361,10 @@ rx_sdu(const module_id_t enb_mod_idP, (enb_mod_idP, UE_RNTI(enb_mod_idP, UE_id)) < RRC_CONNECTED) LOG_D(MAC, - "[eNB %d] CC_id %d MAC CE_LCID %d : ul_total_buffer = %d (lcg increment %d)\n", + "[eNB %d] CC_id %d MAC CE_LCID %d : estimated_ul_buffer = %d (lcg increment %d)\n", enb_mod_idP, CC_idP, rx_ces[i], - UE_list->UE_template[CC_idP][UE_id]. - ul_total_buffer, - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[lcgid]); + UE_list->UE_template[CC_idP][UE_id].estimated_ul_buffer, + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[lcgid]); } else { } @@ -370,115 +374,48 @@ rx_sdu(const module_id_t enb_mod_idP, case LONG_BSR: if (UE_id != -1) { - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0] = - ((payload_ptr[0] & 0xFC) >> 2); - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1] = - ((payload_ptr[0] & 0x03) << 4) | - ((payload_ptr[1] & 0xF0) >> 4); - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2] = - ((payload_ptr[1] & 0x0F) << 2) | - ((payload_ptr[2] & 0xC0) >> 6); - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] = - (payload_ptr[2] & 0x3F); + int bsr0 = (payload_ptr[0] & 0xFC) >> 2; + int bsr1 = ((payload_ptr[0] & 0x03) << 4) | ((payload_ptr[1] & 0xF0) >> 4); + int bsr2 = ((payload_ptr[1] & 0x0F) << 2) | ((payload_ptr[2] & 0xC0) >> 6); + int bsr3 = payload_ptr[2] & 0x3F; + + lcgid_updated[0] = 1; + lcgid_updated[1] = 1; + lcgid_updated[2] = 1; + lcgid_updated[3] = 1; // update buffer info - old_buffer_info = - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID0]; - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID0] = - BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID0]]; + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0] = BSR_TABLE[bsr0]; + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1] = BSR_TABLE[bsr1]; + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2] = BSR_TABLE[bsr2]; + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3] = BSR_TABLE[bsr3]; - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID0]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= - old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= - old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = - 0; - - old_buffer_info = - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID1]; - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID1] = - BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID1]]; - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID1]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= - old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= - old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = - 0; - - old_buffer_info = - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID2]; - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID2] = - BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID2]]; - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID2]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= - old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= - old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = - 0; - - old_buffer_info = - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID3]; - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID3] = - BSR_TABLE[UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID3]]; - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer += - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[LCGID3]; - if (UE_list->UE_template[CC_idP][UE_id].ul_total_buffer >= - old_buffer_info) - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer -= - old_buffer_info; - else - UE_list->UE_template[CC_idP][UE_id].ul_total_buffer = - 0; + UE_list->UE_template[CC_idP][UE_id].estimated_ul_buffer = + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[0] + + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[1] + + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[2] + + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[3]; + //UE_list->UE_template[CC_idP][UE_id].estimated_ul_buffer += UE_list->UE_template[CC_idP][UE_id].estimated_ul_buffer / 4; LOG_D(MAC, - "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " + "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR. Size is LCGID0 = %u LCGID1 = " "%u LCGID2 = %u LCGID3 = %u\n", enb_mod_idP, CC_idP, rx_ces[i], - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0], - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1], - UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2], - UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID3]); + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0], + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1], + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2], + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]); if (crnti_rx == 1) LOG_D(MAC, - "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR LCGID0 = %u LCGID1 = " + "[eNB %d] CC_id %d MAC CE_LCID %d: Received long BSR. Size is LCGID0 = %u LCGID1 = " "%u LCGID2 = %u LCGID3 = %u\n", enb_mod_idP, CC_idP, rx_ces[i], - UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID0], - UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID1], - UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID2], - UE_list->UE_template[CC_idP][UE_id]. - bsr_info[LCGID3]); + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0], + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1], + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2], + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3]); - if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID0] == + if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID0] == 0) { UE_list->UE_template[CC_idP][UE_id]. ul_buffer_creation_time[LCGID0] = 0; @@ -488,7 +425,7 @@ rx_sdu(const module_id_t enb_mod_idP, ul_buffer_creation_time[LCGID0] = frameP; } - if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID1] == + if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID1] == 0) { UE_list->UE_template[CC_idP][UE_id]. ul_buffer_creation_time[LCGID1] = 0; @@ -498,7 +435,7 @@ rx_sdu(const module_id_t enb_mod_idP, ul_buffer_creation_time[LCGID1] = frameP; } - if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID2] == + if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID2] == 0) { UE_list->UE_template[CC_idP][UE_id]. ul_buffer_creation_time[LCGID2] = 0; @@ -508,7 +445,7 @@ rx_sdu(const module_id_t enb_mod_idP, ul_buffer_creation_time[LCGID2] = frameP; } - if (UE_list->UE_template[CC_idP][UE_id].bsr_info[LCGID3] == + if (UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[LCGID3] == 0) { UE_list->UE_template[CC_idP][UE_id]. ul_buffer_creation_time[LCGID3] = 0; @@ -649,19 +586,28 @@ rx_sdu(const module_id_t enb_mod_idP, #endif if (UE_id != -1) { - // adjust buffer occupancy of the correponding logical channel group - if (UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[UE_list->UE_template[CC_idP] - [UE_id].lcgidmap[rx_lcids[i]]] >= - rx_lengths[i]) - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[UE_list->UE_template[CC_idP] - [UE_id].lcgidmap[rx_lcids[i]]] -= - rx_lengths[i]; - else - UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[UE_list->UE_template[CC_idP] - [UE_id].lcgidmap[rx_lcids[i]]] = 0; + if (lcgid_updated[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] == 0) { + // adjust buffer occupancy of the correponding logical channel group + if (UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[UE_list->UE_template[CC_idP] + [UE_id].lcgidmap[rx_lcids[i]]] >= + rx_lengths[i]) + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[UE_list->UE_template[CC_idP] + [UE_id].lcgidmap[rx_lcids[i]]] -= + rx_lengths[i]; + else + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[UE_list->UE_template[CC_idP] + [UE_id].lcgidmap[rx_lcids[i]]] = 0; + + UE_list->UE_template[CC_idP][UE_id].estimated_ul_buffer = + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[0] + + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[1] + + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[2] + + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[3]; + //UE_list->UE_template[CC_idP][UE_id].estimated_ul_buffer += UE_list->UE_template[CC_idP][UE_id].estimated_ul_buffer / 4; + } LOG_D(MAC, "[eNB %d] CC_id %d Frame %d : ULSCH -> UL-DCCH, received %d bytes form UE %d on LCID %d \n", @@ -712,18 +658,28 @@ rx_sdu(const module_id_t enb_mod_idP, ul_buffer_info[UE_list->UE_template[CC_idP] [UE_id].lcgidmap[rx_lcids[i]]]); - if (UE_list->UE_template[CC_idP][UE_id]. - ul_buffer_info[UE_list->UE_template[CC_idP] - [UE_id].lcgidmap[rx_lcids[i]]] - >= rx_lengths[i]) - UE_list->UE_template[CC_idP][UE_id]. + if (lcgid_updated[UE_list->UE_template[CC_idP][UE_id].lcgidmap[rx_lcids[i]]] == 0) { + if (UE_list->UE_template[CC_idP][UE_id]. ul_buffer_info[UE_list->UE_template[CC_idP] - [UE_id].lcgidmap[rx_lcids[i]]] - -= rx_lengths[i]; - else - UE_list->UE_template[CC_idP][UE_id].ul_buffer_info - [UE_list->UE_template[CC_idP][UE_id].lcgidmap - [rx_lcids[i]]] = 0; + [UE_id].lcgidmap[rx_lcids[i]]] + >= rx_lengths[i]) + UE_list->UE_template[CC_idP][UE_id]. + ul_buffer_info[UE_list->UE_template[CC_idP] + [UE_id].lcgidmap[rx_lcids[i]]] + -= rx_lengths[i]; + else + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info + [UE_list->UE_template[CC_idP][UE_id].lcgidmap + [rx_lcids[i]]] = 0; + + UE_list->UE_template[CC_idP][UE_id].estimated_ul_buffer = + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[0] + + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[1] + + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[2] + + UE_list->UE_template[CC_idP][UE_id].ul_buffer_info[3]; + //UE_list->UE_template[CC_idP][UE_id].estimated_ul_buffer += UE_list->UE_template[CC_idP][UE_id].estimated_ul_buffer / 4; + } + if ((rx_lengths[i] < SCH_PAYLOAD_SIZE_MAX) && (rx_lengths[i] > 0)) { // MAX SIZE OF transport block mac_rlc_data_ind(enb_mod_idP, current_rnti, enb_mod_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, rx_lcids[i], (char *) payload_ptr, rx_lengths[i], 1, NULL); //(unsigned int*)crc_status); @@ -1196,10 +1152,7 @@ schedule_ulsch_rnti(module_id_t module_idP, module_idP, frameP, subframeP, sched_frame, sched_subframeP, harq_pid, UE_id, rnti, CC_id, aggregation, N_RB_UL); - RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP * - 10) + - subframeP] = - UE_template->ul_total_buffer; + RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP * 10) + subframeP] = UE_template->estimated_ul_buffer; VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME (VCD_SIGNAL_DUMPER_VARIABLES_UE0_BO, RC.eNB[module_idP][CC_id]->pusch_stats_BO[UE_id][(frameP * @@ -1289,8 +1242,6 @@ schedule_ulsch_rnti(module_id_t module_idP, UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2 = UE_template->mcs_UL[harq_pid]; - // buffer_occupancy = UE_template->ul_total_buffer; - while (((rb_table[rb_table_index] > (N_RB_UL - 1 - first_rb[CC_id])) @@ -1341,18 +1292,15 @@ schedule_ulsch_rnti(module_id_t module_idP, // adjust total UL buffer status by TBS, wait for UL sdus to do final update LOG_D(MAC, - "[eNB %d] CC_id %d UE %d/%x : adjusting ul_total_buffer, old %d, TBS %d\n", + "[eNB %d] CC_id %d UE %d/%x : adjusting scheduled_ul_bytes, old %d, TBS %d\n", module_idP, CC_id, UE_id, rnti, - UE_template->ul_total_buffer, + UE_template->scheduled_ul_bytes, UE_template->TBS_UL[harq_pid]); - if (UE_template->ul_total_buffer > - UE_template->TBS_UL[harq_pid]) - UE_template->ul_total_buffer -= - UE_template->TBS_UL[harq_pid]; - else - UE_template->ul_total_buffer = 0; - LOG_D(MAC, "ul_total_buffer, new %d\n", - UE_template->ul_total_buffer); + + UE_template->scheduled_ul_bytes += UE_template->TBS_UL[harq_pid]; + + LOG_D(MAC, "scheduled_ul_bytes, new %d\n", UE_template->scheduled_ul_bytes); + // Cyclic shift for DM RS cshift = 0; // values from 0 to 7 can be used for mapping the cyclic shift (36.211 , Table 5.5.2.1.1-1) // save it for a potential retransmission diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index ff8939d82b..0d6a6ec388 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -1590,9 +1590,11 @@ assign_max_mcs_min_rb(module_id_t module_idP, int frameP, to_prb(RC.mac[module_idP]->common_channels[CC_id]. ul_Bandwidth); // if this UE has UL traffic - if (UE_template->ul_total_buffer > 0) { - + int bytes_to_schedule = UE_template->estimated_ul_buffer - UE_template->scheduled_ul_bytes; + if (bytes_to_schedule < 0) bytes_to_schedule = 0; + int bits_to_schedule = bytes_to_schedule * 8; + if (bits_to_schedule > 0) { tbs = get_TBS_UL(mcs, 3) << 3; // 1 or 2 PRB with cqi enabled does not work well! rb_table_index = 2; @@ -1602,7 +1604,7 @@ assign_max_mcs_min_rb(module_id_t module_idP, int frameP, Ncp, 0); while ((((UE_template->phr_info - tx_power) < 0) - || (tbs > UE_template->ul_total_buffer)) + || (tbs > bits_to_schedule)) && (mcs > 3)) { // LOG_I(MAC,"UE_template->phr_info %d tx_power %d mcs %d\n", UE_template->phr_info,tx_power, mcs); mcs--; @@ -1610,7 +1612,7 @@ assign_max_mcs_min_rb(module_id_t module_idP, int frameP, tx_power = estimate_ue_tx_power(tbs, rb_table[rb_table_index], 0, Ncp, 0); // fixme: set use_srs } - while ((tbs < UE_template->ul_total_buffer) && + while ((tbs < bits_to_schedule) && (rb_table[rb_table_index] < (N_RB_UL - first_rb[CC_id])) && ((UE_template->phr_info - tx_power) > 0) @@ -1700,11 +1702,14 @@ static int ue_ul_compare(const void *_a, const void *_b, void *_params) UE_list->UE_template[pCCid2][UE_id2].ul_buffer_info[LCGID0]) return 1; - if (UE_list->UE_template[pCCid1][UE_id1].ul_total_buffer > - UE_list->UE_template[pCCid2][UE_id2].ul_total_buffer) + int bytes_to_schedule1 = UE_list->UE_template[pCCid1][UE_id1].estimated_ul_buffer - UE_list->UE_template[pCCid1][UE_id1].scheduled_ul_bytes; + if (bytes_to_schedule1 < 0) bytes_to_schedule1 = 0; + int bytes_to_schedule2 = UE_list->UE_template[pCCid2][UE_id2].estimated_ul_buffer - UE_list->UE_template[pCCid2][UE_id2].scheduled_ul_bytes; + if (bytes_to_schedule2 < 0) bytes_to_schedule2 = 0; + + if (bytes_to_schedule1 > bytes_to_schedule2) return -1; - if (UE_list->UE_template[pCCid1][UE_id1].ul_total_buffer < - UE_list->UE_template[pCCid2][UE_id2].ul_total_buffer) + if (bytes_to_schedule1 < bytes_to_schedule2) return 1; if (UE_list->UE_template[pCCid1][UE_id1].pre_assigned_mcs_ul > diff --git a/openair2/LAYER2/openair2_proc.c b/openair2/LAYER2/openair2_proc.c index 34c06a9c53..f66d1142ab 100644 --- a/openair2/LAYER2/openair2_proc.c +++ b/openair2/LAYER2/openair2_proc.c @@ -217,11 +217,11 @@ int dump_eNB_l2_stats(char *buffer, int length) UE_list->eNB_UE_stats[CC_id][UE_id].num_errors_rx); len+= sprintf(&buffer[len],"[MAC] Received PHR PH = %d (db)\n", UE_list->UE_template[CC_id][UE_id].phr_info); - len+= sprintf(&buffer[len],"[MAC] Received BSR LCGID[0][1][2][3] = %u %u %u %u\n", - UE_list->UE_template[CC_id][UE_id].bsr_info[LCGID0], - UE_list->UE_template[CC_id][UE_id].bsr_info[LCGID1], - UE_list->UE_template[CC_id][UE_id].bsr_info[LCGID2], - UE_list->UE_template[CC_id][UE_id].bsr_info[LCGID3] + len+= sprintf(&buffer[len],"[MAC] Estimated size LCGID[0][1][2][3] = %u %u %u %u\n", + UE_list->UE_template[CC_id][UE_id].ul_buffer_info[LCGID0], + UE_list->UE_template[CC_id][UE_id].ul_buffer_info[LCGID1], + UE_list->UE_template[CC_id][UE_id].ul_buffer_info[LCGID2], + UE_list->UE_template[CC_id][UE_id].ul_buffer_info[LCGID3] ); } From 9b7364a3ca6caf3ecbfb4284e9eb254f69076fd0 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 7 Feb 2018 12:30:00 +0100 Subject: [PATCH 206/284] minor: fix AssertFatal --- openair2/LAYER2/MAC/eNB_scheduler_primitives.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 3e574a56c3..e0e0f0a5fa 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -3716,7 +3716,7 @@ extract_harq(module_id_t mod_idP, int CC_idP, int UE_id, sched_ctl->round[CC_idP][harq_pid]++; // increment round } else { // one or two ACK/NAK bits - AssertFatal(num_ack_nak > 2, + AssertFatal(num_ack_nak <= 2, "num_ack_nak %d > 2 for 1 CC and TM3/4/8/9/10\n", num_ack_nak); if ((num_ack_nak == 2) From c0bcd786735c26ef6dbd5c8e381a307ca3d49194 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 7 Feb 2018 12:31:26 +0100 Subject: [PATCH 207/284] bugfix: don't take into account report CQI in case of NACK or DTX The problem that may happen is that when the UE does not transmit on PUCCH (for whatever reason) we may get no signal at all, and thus compute a very low CQI. Later on we may ask the UE to transmit louder which may lead to saturation and more problems. The solution is simple: don't care about CQI in case of DTX (and NACK also, as done for PUSCH). Only FDD case done. For TDD it seems that: - nfapi structures are not correct. See nfapi_harq_indication_tdd_rel13_t in nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h, all the cases (bundling, multiplex, ...) use nfapi_harq_indication_tdd_harq_data_t - the function extract_harq does not handle TDD --- .../LAYER2/MAC/eNB_scheduler_primitives.c | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index e0e0f0a5fa..867b6d7e8b 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -4472,6 +4472,24 @@ UL_failure_indication(module_id_t mod_idP, int cc_idP, frame_t frameP, } } +static int nack_or_dtx_reported( + COMMON_channels_t *cc, + nfapi_harq_indication_pdu_t *harq_pdu) +{ + int i; + + if (cc->tdd_Config) { + AssertFatal(0==1, "TDD to be done. FAPI structures (see nfapi_harq_indication_tdd_rel13_t) are not clean. To be cleaned as well?\n"); + abort(); + } else { + nfapi_harq_indication_fdd_rel13_t *hi = &harq_pdu->harq_indication_fdd_rel13; + for (i = 0; i < hi->number_of_ack_nack; hi++) + if (hi->harq_tb_n[i] != 1) + return 1; + return 0; + } +} + void harq_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, sub_frame_t subframeP, @@ -4500,7 +4518,8 @@ harq_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, extract_harq(mod_idP, CC_idP, UE_id, frameP, subframeP, (void *) &harq_pdu->harq_indication_fdd_rel13, channel); - if (channel == 0) { + /* don't care about cqi reporting if NACK/DTX is there */ + if (channel == 0 && !nack_or_dtx_reported(cc, harq_pdu)) { sched_ctl->pucch1_snr[CC_idP] = ul_cqi; sched_ctl->pucch1_cqi_update[CC_idP] = 1; } From 1fce1bbf82d4f5569f8a65ff4e24b0002c2a71f1 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 7 Feb 2018 14:51:50 +0100 Subject: [PATCH 208/284] bugfix: fix SIB3 encoding The unused bits are the lower bits, so we need to shift. Not sure that the value 1 is what we want though. --- openair2/RRC/LITE/MESSAGES/asn1_msg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index b8a4148b11..77ba0c4cad 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -876,7 +876,7 @@ uint8_t do_SIB23(uint8_t Mod_id, (*sib3)->intraFreqCellReselectionInfo.presenceAntennaPort1 = 0; (*sib3)->intraFreqCellReselectionInfo.neighCellConfig.buf = CALLOC(8,1); (*sib3)->intraFreqCellReselectionInfo.neighCellConfig.size = 1; - (*sib3)->intraFreqCellReselectionInfo.neighCellConfig.buf[0] = 1; + (*sib3)->intraFreqCellReselectionInfo.neighCellConfig.buf[0] = 1 << 6; (*sib3)->intraFreqCellReselectionInfo.neighCellConfig.bits_unused = 6; (*sib3)->intraFreqCellReselectionInfo.t_ReselectionEUTRA = 1; (*sib3)->intraFreqCellReselectionInfo.t_ReselectionEUTRA_SF = (struct SpeedStateScaleFactors *)NULL; From c8ae5b7c09bd7d0c77f97c731e8c5825f23344da Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 8 Feb 2018 18:55:23 +0100 Subject: [PATCH 209/284] decrease warning --- targets/RT/USER/lte-ru.c | 1 - 1 file changed, 1 deletion(-) diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index e553fc3702..5f60553fe1 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -2161,7 +2161,6 @@ void init_RU(char *rf_config_file) { int ru_id; RU_t *ru; - int ret; PHY_VARS_eNB *eNB0= (PHY_VARS_eNB *)NULL; int i; int CC_id; From 1a1ad6ed8f3e1ad9c7e55a661aa1e9ddfc423d0e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 8 Feb 2018 19:11:57 +0100 Subject: [PATCH 210/284] remove non-existing files from build description file --- cmake_targets/CMakeLists.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 120d029a0c..44d80d4633 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1394,14 +1394,6 @@ add_library(L2_UE include_directories(${NFAPI_USER_DIR}) -if (FLEXRAN_AGENT_SB_IF) - -#Test for adding a shared library -add_library(default_sched SHARED ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue.c) -add_library(remote_sched SHARED ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue_remote.c) - -endif() - # L3 Libs ########################## From c518ed89e288767ca030991f1b2354684da7fcd3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 8 Feb 2018 19:12:20 +0100 Subject: [PATCH 211/284] bugfix after merge --- openair2/RRC/LITE/rrc_eNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 9526be83f4..f51ac31a79 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -6694,7 +6694,7 @@ if (ue_context_p->ue_context.nb_of_modify_e_rabs > 0) { #if defined(FLEXRAN_AGENT_SB_IF) //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future if (mac_agent_registered[ctxt_pP->module_id]) { - agent_mac_xface[ctxt_pP->eNB_index]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, + agent_rrc_xface[ctxt_pP->eNB_index]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, ue_context_p->ue_id_rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_ACTIVATED); } From 11fe5f97c7db2f1aa65c61ffb85212c3f3853654 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 9 Feb 2018 10:49:50 +0100 Subject: [PATCH 212/284] bugfix: fix eNB name in configuration files '_' is not a valid character. S1AP specs say: ENBname ::= PrintableString (SIZE (1..150,...)) And X.680 (08/2015) 41.4 table 10 lists the valid characters for PrintableString. '_' is not there. We replace by '-' which is there. Connection of eNB to ppenair-cn has not been tested. There is no reason why it would fail. --- .../v2/config/enb.band38.tm1.usrpb210.tdd.10MHz.conf | 4 ++-- .../v2/config/enb.band38.tm1.usrpb210.tdd.20MHz.conf | 4 ++-- .../autotests/v2/config/enb.band38.tm1.usrpb210.tdd.5MHz.conf | 4 ++-- .../autotests/v2/config/enb.band7.tm1.usrpb210.fdd.10MHz.conf | 4 ++-- .../autotests/v2/config/enb.band7.tm1.usrpb210.fdd.20MHz.conf | 4 ++-- .../autotests/v2/config/enb.band7.tm1.usrpb210.fdd.5MHz.conf | 4 ++-- .../autotests/v2/config/rcc.band7.tm1.if4p5.10MHz.conf | 4 ++-- .../autotests/v2/config/rcc.band7.tm1.if4p5.20MHz.conf | 4 ++-- .../autotests/v2/config/rcc.band7.tm1.if4p5.5MHz.conf | 4 ++-- .../v2/config/rru.band7.tm1.if4p5.10MHz.udp.usrpb210.conf | 4 ++-- .../v2/config/rru.band7.tm1.if4p5.20MHz.udp.usrpb210.conf | 4 ++-- .../v2/config/rru.band7.tm1.if4p5.5MHz.udp.usrpb210.conf | 4 ++-- .../GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf | 4 ++-- .../GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf | 4 ++-- .../GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.conf | 4 ++-- .../GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.lo.conf | 4 ++-- 16 files changed, 32 insertions(+), 32 deletions(-) diff --git a/cmake_targets/autotests/v2/config/enb.band38.tm1.usrpb210.tdd.10MHz.conf b/cmake_targets/autotests/v2/config/enb.band38.tm1.usrpb210.tdd.10MHz.conf index e09e068c63..0994acdf9d 100644 --- a/cmake_targets/autotests/v2/config/enb.band38.tm1.usrpb210.tdd.10MHz.conf +++ b/cmake_targets/autotests/v2/config/enb.band38.tm1.usrpb210.tdd.10MHz.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -10,7 +10,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/cmake_targets/autotests/v2/config/enb.band38.tm1.usrpb210.tdd.20MHz.conf b/cmake_targets/autotests/v2/config/enb.band38.tm1.usrpb210.tdd.20MHz.conf index 1f992daba2..5e8cd8007e 100644 --- a/cmake_targets/autotests/v2/config/enb.band38.tm1.usrpb210.tdd.20MHz.conf +++ b/cmake_targets/autotests/v2/config/enb.band38.tm1.usrpb210.tdd.20MHz.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -10,7 +10,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/cmake_targets/autotests/v2/config/enb.band38.tm1.usrpb210.tdd.5MHz.conf b/cmake_targets/autotests/v2/config/enb.band38.tm1.usrpb210.tdd.5MHz.conf index bb7df8b72d..53eae1d531 100644 --- a/cmake_targets/autotests/v2/config/enb.band38.tm1.usrpb210.tdd.5MHz.conf +++ b/cmake_targets/autotests/v2/config/enb.band38.tm1.usrpb210.tdd.5MHz.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -10,7 +10,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/cmake_targets/autotests/v2/config/enb.band7.tm1.usrpb210.fdd.10MHz.conf b/cmake_targets/autotests/v2/config/enb.band7.tm1.usrpb210.fdd.10MHz.conf index ff97827b57..d30a57041c 100644 --- a/cmake_targets/autotests/v2/config/enb.band7.tm1.usrpb210.fdd.10MHz.conf +++ b/cmake_targets/autotests/v2/config/enb.band7.tm1.usrpb210.fdd.10MHz.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -10,7 +10,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/cmake_targets/autotests/v2/config/enb.band7.tm1.usrpb210.fdd.20MHz.conf b/cmake_targets/autotests/v2/config/enb.band7.tm1.usrpb210.fdd.20MHz.conf index ebb9e417e7..e90eb3fe51 100644 --- a/cmake_targets/autotests/v2/config/enb.band7.tm1.usrpb210.fdd.20MHz.conf +++ b/cmake_targets/autotests/v2/config/enb.band7.tm1.usrpb210.fdd.20MHz.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -10,7 +10,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/cmake_targets/autotests/v2/config/enb.band7.tm1.usrpb210.fdd.5MHz.conf b/cmake_targets/autotests/v2/config/enb.band7.tm1.usrpb210.fdd.5MHz.conf index 4e89102766..5dbecd3813 100644 --- a/cmake_targets/autotests/v2/config/enb.band7.tm1.usrpb210.fdd.5MHz.conf +++ b/cmake_targets/autotests/v2/config/enb.band7.tm1.usrpb210.fdd.5MHz.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -10,7 +10,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/cmake_targets/autotests/v2/config/rcc.band7.tm1.if4p5.10MHz.conf b/cmake_targets/autotests/v2/config/rcc.band7.tm1.if4p5.10MHz.conf index beaf5ae0f1..1397184cc7 100644 --- a/cmake_targets/autotests/v2/config/rcc.band7.tm1.if4p5.10MHz.conf +++ b/cmake_targets/autotests/v2/config/rcc.band7.tm1.if4p5.10MHz.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -10,7 +10,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/cmake_targets/autotests/v2/config/rcc.band7.tm1.if4p5.20MHz.conf b/cmake_targets/autotests/v2/config/rcc.band7.tm1.if4p5.20MHz.conf index b0efe66e14..caebb36eb2 100644 --- a/cmake_targets/autotests/v2/config/rcc.band7.tm1.if4p5.20MHz.conf +++ b/cmake_targets/autotests/v2/config/rcc.band7.tm1.if4p5.20MHz.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -10,7 +10,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/cmake_targets/autotests/v2/config/rcc.band7.tm1.if4p5.5MHz.conf b/cmake_targets/autotests/v2/config/rcc.band7.tm1.if4p5.5MHz.conf index 1b33c7b3c2..fe90cdb338 100644 --- a/cmake_targets/autotests/v2/config/rcc.band7.tm1.if4p5.5MHz.conf +++ b/cmake_targets/autotests/v2/config/rcc.band7.tm1.if4p5.5MHz.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -10,7 +10,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/cmake_targets/autotests/v2/config/rru.band7.tm1.if4p5.10MHz.udp.usrpb210.conf b/cmake_targets/autotests/v2/config/rru.band7.tm1.if4p5.10MHz.udp.usrpb210.conf index dc64a69c00..5d9027ce15 100644 --- a/cmake_targets/autotests/v2/config/rru.band7.tm1.if4p5.10MHz.udp.usrpb210.conf +++ b/cmake_targets/autotests/v2/config/rru.band7.tm1.if4p5.10MHz.udp.usrpb210.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -10,7 +10,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/cmake_targets/autotests/v2/config/rru.band7.tm1.if4p5.20MHz.udp.usrpb210.conf b/cmake_targets/autotests/v2/config/rru.band7.tm1.if4p5.20MHz.udp.usrpb210.conf index c93ce24d08..539f0bd744 100644 --- a/cmake_targets/autotests/v2/config/rru.band7.tm1.if4p5.20MHz.udp.usrpb210.conf +++ b/cmake_targets/autotests/v2/config/rru.band7.tm1.if4p5.20MHz.udp.usrpb210.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -10,7 +10,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/cmake_targets/autotests/v2/config/rru.band7.tm1.if4p5.5MHz.udp.usrpb210.conf b/cmake_targets/autotests/v2/config/rru.band7.tm1.if4p5.5MHz.udp.usrpb210.conf index 57f7ef83b9..58b088002f 100644 --- a/cmake_targets/autotests/v2/config/rru.band7.tm1.if4p5.5MHz.udp.usrpb210.conf +++ b/cmake_targets/autotests/v2/config/rru.band7.tm1.if4p5.5MHz.udp.usrpb210.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -10,7 +10,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf index ff302811e9..cf322bc7f3 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -10,7 +10,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf index 1c9ad09141..bc2b3b219c 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -10,7 +10,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.conf index 772e13fe6f..42ab1e81c7 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -13,7 +13,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.lo.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.lo.conf index e60e793438..aacc87e5b0 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.lo.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if4p5.50PRB.lo.conf @@ -1,4 +1,4 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); +Active_eNBs = ( "eNB-Eurecom-LTEBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -13,7 +13,7 @@ eNBs = cell_type = "CELL_MACRO_ENB"; - eNB_name = "eNB_Eurecom_LTEBox"; + eNB_name = "eNB-Eurecom-LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; From 6cff88b9c8e7d8291bd754a3ac4877fd9baa45ec Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 9 Feb 2018 10:56:14 +0100 Subject: [PATCH 213/284] free memory on teardown after all RU/eNB threads have been released --- targets/RT/USER/lte-enb.c | 5 ----- targets/RT/USER/lte-ru.c | 2 -- targets/RT/USER/lte-softmodem.c | 11 +++++++++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 928b41ad44..58967612dc 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -1139,10 +1139,5 @@ void stop_eNB(int nb_inst) { for (int inst=0;inst Date: Fri, 9 Feb 2018 10:59:59 +0100 Subject: [PATCH 214/284] free all memory for lte_ul_ref* structures --- openair1/PHY/LTE_REFSIG/lte_ul_ref.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/LTE_REFSIG/lte_ul_ref.c b/openair1/PHY/LTE_REFSIG/lte_ul_ref.c index cacd0f4292..93ca7646e6 100644 --- a/openair1/PHY/LTE_REFSIG/lte_ul_ref.c +++ b/openair1/PHY/LTE_REFSIG/lte_ul_ref.c @@ -185,12 +185,12 @@ void free_ul_ref_sigs(void) unsigned int u,v,Msc_RS; - for (Msc_RS=2; Msc_RS<33; Msc_RS++) { + for (Msc_RS=0; Msc_RS<33; Msc_RS++) { for (u=0; u<30; u++) { for (v=0; v<2; v++) { if (ul_ref_sigs[u][v][Msc_RS]) { free16(ul_ref_sigs[u][v][Msc_RS],2*sizeof(int16_t)*dftsizes[Msc_RS]); - ul_ref_sigs_rx[u][v][Msc_RS] = NULL; + ul_ref_sigs[u][v][Msc_RS] = NULL; } if (ul_ref_sigs_rx[u][v][Msc_RS]) { From 386fd21c937215bf43b02f2ca8e6d7334a3998ea Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 9 Feb 2018 15:31:59 +0100 Subject: [PATCH 215/284] free_eNB_{d,u}lsch(): remove log, complete function dlsch --- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 37 ++++------------------- openair1/PHY/LTE_TRANSPORT/ulsch_coding.c | 22 -------------- 2 files changed, 6 insertions(+), 53 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index bd3c92454f..f1cb58ba26 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -56,42 +56,20 @@ void free_eNB_dlsch(LTE_eNB_DLSCH_t *dlsch) { - int i; - int r; + int i, r, aa, layer; if (dlsch) { -#ifdef DEBUG_DLSCH_FREE - printf("Freeing dlsch %p\n",dlsch); -#endif - + for (layer=0; layer<4; layer++) { + for (aa=0; aa<64; aa++) free16(dlsch->ue_spec_bf_weights[layer][aa], OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); + free16(dlsch->ue_spec_bf_weights[layer], 64*sizeof(int32_t*)); + } for (i=0; iMdlharq; i++) { -#ifdef DEBUG_DLSCH_FREE - printf("Freeing dlsch process %d\n",i); -#endif - if (dlsch->harq_processes[i]) { -#ifdef DEBUG_DLSCH_FREE - printf("Freeing dlsch process %d (%p)\n",i,dlsch->harq_processes[i]); -#endif - if (dlsch->harq_processes[i]->b) { free16(dlsch->harq_processes[i]->b,MAX_DLSCH_PAYLOAD_BYTES); dlsch->harq_processes[i]->b = NULL; -#ifdef DEBUG_DLSCH_FREE - printf("Freeing dlsch process %d b (%p)\n",i,dlsch->harq_processes[i]->b); -#endif } - -#ifdef DEBUG_DLSCH_FREE - printf("Freeing dlsch process %d c (%p)\n",i,dlsch->harq_processes[i]->c); -#endif - for (r=0; rharq_processes[i]->c[r]); -#endif - if (dlsch->harq_processes[i]->c[r]) { free16(dlsch->harq_processes[i]->c[r],((r==0)?8:0) + 3+768); dlsch->harq_processes[i]->c[r] = NULL; @@ -100,17 +78,14 @@ void free_eNB_dlsch(LTE_eNB_DLSCH_t *dlsch) free16(dlsch->harq_processes[i]->d[r],(96+12+3+(3*6144))); dlsch->harq_processes[i]->d[r] = NULL; } - } free16(dlsch->harq_processes[i],sizeof(LTE_DL_eNB_HARQ_t)); dlsch->harq_processes[i] = NULL; } } - free16(dlsch,sizeof(LTE_eNB_DLSCH_t)); dlsch = NULL; - } - + } } LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_t Nsoft,unsigned char N_RB_DL, uint8_t abstraction_flag, LTE_DL_FRAME_PARMS* frame_parms) diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c index 87209e190b..9b761f3cc3 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c @@ -66,33 +66,12 @@ void free_ue_ulsch(LTE_UE_ULSCH_t *ulsch) #endif for (i=0; i<8; i++) { -#ifdef DEBUG_ULSCH_FREE - printf("Freeing ulsch process %d\n",i); -#endif - if (ulsch->harq_processes[i]) { -#ifdef DEBUG_ULSCH_FREE - printf("Freeing ulsch process %d (%p)\n",i,ulsch->harq_processes[i]); -#endif - if (ulsch->harq_processes[i]->b) { free16(ulsch->harq_processes[i]->b,MAX_ULSCH_PAYLOAD_BYTES); ulsch->harq_processes[i]->b = NULL; -#ifdef DEBUG_ULSCH_FREE - printf("Freeing ulsch process %d b (%p)\n",i,ulsch->harq_processes[i]->b); -#endif } - -#ifdef DEBUG_ULSCH_FREE - printf("Freeing ulsch process %d c (%p)\n",i,ulsch->harq_processes[i]->c); -#endif - for (r=0; rharq_processes[i]->c[r]); -#endif - if (ulsch->harq_processes[i]->c[r]) { free16(ulsch->harq_processes[i]->c[r],((r==0)?8:0) + 3+768); ulsch->harq_processes[i]->c[r] = NULL; @@ -103,7 +82,6 @@ void free_ue_ulsch(LTE_UE_ULSCH_t *ulsch) ulsch->harq_processes[i] = NULL; } } - free16(ulsch,sizeof(LTE_UE_ULSCH_t)); ulsch = NULL; } From 1eabadb137b9c8c534cb5782ae410afa76f070e2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 9 Feb 2018 15:47:59 +0100 Subject: [PATCH 216/284] remove unnecessary code from lte-enb.c --- targets/RT/USER/lte-enb.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 58967612dc..5ccc99c041 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -859,15 +859,6 @@ void kill_eNB_proc(int inst) { pthread_cond_destroy( &proc_rxtx[i].cond_rxtx ); } } - - LOG_D(PHY, "joining pthread_asynch_rxtx\n"); - pthread_join(proc->pthread_asynch_rxtx, (void**)&status ); - pthread_mutex_destroy(&proc->mutex_asynch_rxtx); - pthread_cond_destroy(&proc->cond_asynch_rxtx); - - LOG_D(PHY, "joining pthread_single\n"); - pthread_join(proc->pthread_single, (void**)&status ); - LOG_D(PHY, "joined all eNB threads\n"); } } From d746ff61274b101f53728b114f0aa4f62e38ea85 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 9 Feb 2018 16:29:59 +0100 Subject: [PATCH 217/284] update comments in restart_L1L2() --- targets/RT/USER/lte-softmodem.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 3aebf6d279..42a4a7c950 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -969,8 +969,6 @@ int restart_L1L2(module_id_t enb_id) RC.eNB[enb_id][cc_id]->configured = 0; } - - /* TODO undo malloc_IF4p5_buffer() */ RC.ru_mask |= (1 << ru->idx); /* copy the changed frame parameters to the RU */ /* TODO this should be done for all RUs associated to this eNB */ @@ -997,11 +995,9 @@ int restart_L1L2(module_id_t enb_id) RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[enb_id]->configuration; itti_send_msg_to_task(TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); - /* TODO XForms here */ + /* TODO XForms might need to be restarted, but it is currently (09/02/18) + * broken, so we cannot test it */ - /* TODO check for memory leaks */ - /* TODO wait_eNBs() would wait for phy_config_request()? */ - //init_eNB(single_thread_flag,wait_for_sync); wait_eNBs(); init_RU_proc(ru); ru->rf_map.card = 0; @@ -1009,7 +1005,6 @@ int restart_L1L2(module_id_t enb_id) wait_RUs(); init_eNB_afterRU(); - printf("Sending sync to all threads\n"); pthread_mutex_lock(&sync_mutex); sync_var=0; From 8877b18a9a59342905f0c3c4ca3969f1bbd2d717 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 9 Feb 2018 19:05:36 +0100 Subject: [PATCH 218/284] fix eNB_ulsch_dlsch_scheduler() broken by merge 2c8443121d65c2a48 --- openair2/LAYER2/MAC/eNB_scheduler.c | 71 +++++++++++------------------ 1 file changed, 26 insertions(+), 45 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index cf7f84eed2..0e2f84b25b 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -504,22 +504,20 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, int mbsfn_status[MAX_NUM_CCs]; protocol_ctxt_t ctxt; - int CC_id, i; + int CC_id, i = -1; UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; rnti_t rnti; COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; -#if defined(FLEXRAN_AGENT_SB_IF) - Protocol__FlexranMessage *msg; -#endif - - start_meas(&RC.mac[module_idP]->eNB_scheduler); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME (VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, VCD_FUNCTION_IN); + RC.mac[module_idP]->frame = frameP; + RC.mac[module_idP]->subframe = subframeP; + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { mbsfn_status[CC_id] = 0; @@ -531,9 +529,29 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, #if defined(Rel10) || defined(Rel14) cc[CC_id].mcch_active = 0; #endif - RC.mac[module_idP]->frame = frameP; - RC.mac[module_idP]->subframe = subframeP; + clear_nfapi_information(RC.mac[module_idP], CC_id, frameP, subframeP); + } + + // refresh UE list based on UEs dropped by PHY in previous subframe + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (UE_list->active[i] != TRUE) + continue; + + rnti = UE_RNTI(module_idP, i); + CC_id = UE_PCCID(module_idP, i); + + if ((frameP == 0) && (subframeP == 0)) { + LOG_I(MAC, + "UE rnti %x : %s, PHR %d dB DL CQI %d PUSCH SNR %d PUCCH SNR %d\n", + rnti, + UE_list->UE_sched_ctrl[i].ul_out_of_sync == + 0 ? "in synch" : "out of sync", + UE_list->UE_template[CC_id][i].phr_info, + UE_list->UE_sched_ctrl[i].dl_cqi[CC_id], + (UE_list->UE_sched_ctrl[i].pusch_snr[CC_id] - 128) / 2, + (UE_list->UE_sched_ctrl[i].pucch1_snr[CC_id] - 128) / 2); + } RC.eNB[module_idP][CC_id]->pusch_stats_bsr[i][(frameP * 10) + subframeP] = -63; @@ -601,42 +619,6 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, } } - // refresh UE list based on UEs dropped by PHY in previous subframe - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i] != TRUE) continue; - - rnti = UE_RNTI(module_idP, i); - CC_id = UE_PCCID(module_idP, i); - - if ((frameP == 0) && (subframeP == 0)) { - LOG_I(MAC, - "UE rnti %x : %s, PHR %d dB DL CQI %d PUSCH SNR %d PUCCH SNR %d\n", - rnti, - UE_list->UE_sched_ctrl[i].ul_out_of_sync == - 0 ? "in synch" : "out of sync", - UE_list->UE_template[CC_id][i].phr_info, - UE_list->UE_sched_ctrl[i].dl_cqi[CC_id], - (UE_list->UE_sched_ctrl[i].pusch_snr[CC_id] - 128) / 2, - (UE_list->UE_sched_ctrl[i].pucch1_snr[CC_id] - 128) / 2); - } - - RC.eNB[module_idP][CC_id]->pusch_stats_bsr[i][(frameP * 10) + subframeP] = -63; - if (i == UE_list->head) - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME - (VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR, - RC.eNB[module_idP][CC_id]-> - pusch_stats_bsr[i][(frameP * 10) + subframeP]); - // increment this, it is cleared when we receive an sdu - RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].ul_inactivity_timer++; - - RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer++; - LOG_D(MAC, "UE %d/%x : ul_inactivity %d, cqi_req %d\n", i, rnti, - RC.mac[module_idP]->UE_list.UE_sched_ctrl[i]. - ul_inactivity_timer, - RC.mac[module_idP]->UE_list.UE_sched_ctrl[i].cqi_req_timer); - check_ul_failure(module_idP, CC_id, i, frameP, subframeP); - } - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, subframeP, module_idP); @@ -687,7 +669,6 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) allocate_CCEs(module_idP, CC_id, subframeP, 0); - stop_meas(&RC.mac[module_idP]->eNB_scheduler); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME From b073445f9986ae48b2764108aa969fbe540b6e7d Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Fri, 9 Feb 2018 19:15:30 +0100 Subject: [PATCH 219/284] removed NFAPI libraries from oaisim target. added #define to allow ue_ip.ko to compile. This should be revisited, there's a problem in CMakelists.txt, no flags.cmake generate for all 3 kernel modules. --- cmake_targets/CMakeLists.txt | 5 +---- openair2/NETWORK_DRIVER/UE_IP/local.h | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 616adf3a82..09dfbf7483 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -2065,7 +2065,6 @@ add_executable(oaisim ${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c ${OPENAIR_DIR}/common/utils/utils.c ${OPENAIR_DIR}/common/utils/system.c - ${GTPU_need_ITTI} ${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c ${XFORMS_SOURCE} ${T_SOURCE} @@ -2077,9 +2076,7 @@ add_executable(oaisim target_include_directories(oaisim PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim -Wl,-ldl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB GTPV1U SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_UE_LIB PHY_UE LFDS L2 ${MSC_LIB} LIB_NAS_UE SIMU SECU_OSA ${ITTI_LIB} ${MIH_LIB} - NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB - NFAPI_USER_LIB + RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_UE_LIB PHY_UE LFDS L2_UE ${MSC_LIB} LIB_NAS_UE SIMU SECU_OSA ${ITTI_LIB} ${MIH_LIB} -Wl,--end-group z dl) target_link_libraries (oaisim ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) diff --git a/openair2/NETWORK_DRIVER/UE_IP/local.h b/openair2/NETWORK_DRIVER/UE_IP/local.h index ac3b040995..15fa7a0f91 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/local.h +++ b/openair2/NETWORK_DRIVER/UE_IP/local.h @@ -57,6 +57,7 @@ #include "platform_types.h" #include "sap.h" +#define OAI_NW_DRIVER_USE_NETLINK 1 typedef struct ue_ip_priv_s { int irq; From a78aaa451cfc6452c4f95f4747d09a77488300c8 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 9 Feb 2018 19:08:59 +0100 Subject: [PATCH 220/284] fix slicing capability in ulsch scheduler --- openair2/LAYER2/MAC/defs.h | 3 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 15 +- openair2/LAYER2/MAC/pre_processor.c | 496 +++++++++++----------- 3 files changed, 248 insertions(+), 266 deletions(-) diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 8d99433eb0..de53479e6f 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -692,7 +692,7 @@ typedef struct { uint16_t cshift[8]; // num_max_harq /// Number of Allocated RBs by the ulsch preprocessor - uint8_t pre_allocated_nb_rb_ul; + uint8_t pre_allocated_nb_rb_ul[MAX_NUM_SLICES]; /// index of Allocated RBs by the ulsch preprocessor int8_t pre_allocated_rb_table_index_ul; @@ -804,6 +804,7 @@ typedef struct { uint8_t mac_ContentionResolutionTimer; uint16_t max_rbs_allowed_slice[MAX_NUM_CCs][MAX_NUM_SLICES]; + uint16_t max_rbs_allowed_slice_uplink[MAX_NUM_CCs][MAX_NUM_SLICES]; uint8_t max_mcs[MAX_NUM_LCID]; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 72b9013d93..b24a3f42ac 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -850,7 +850,7 @@ set_msg3_subframe(module_id_t mod_id, int subframe, int rnti, int Msg3_frame, int Msg3_subframe) { - eNB_MAC_INST *mac = RC.mac[Mod_id]; + eNB_MAC_INST *mac = RC.mac[mod_id]; int i; for (i = 0; i < NB_RA_PROC_MAX; i++) { if (mac->common_channels[CC_id].ra[i].state != IDLE && @@ -1069,7 +1069,6 @@ schedule_ulsch(module_id_t module_idP, frame_t frameP, } // Run each enabled slice-specific schedulers one by one - /* TODO Navid What is the right call for this message? */ slice_sched_ul[i](module_idP, i, frameP, subframeP, sched_subframe, first_rb); } @@ -1296,10 +1295,9 @@ schedule_ulsch_rnti(module_id_t module_idP, normalized_rx_power = normalized_rx_power; UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power = target_rx_power; UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1 = UE_template->pre_assigned_mcs_ul; - UE_template->mcs_UL[harq_pid] = UE_template->pre_assigned_mcs_ul; //cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS + UE_template->mcs_UL[harq_pid] = cmin(UE_template->pre_assigned_mcs_ul, slice_maxmcs_uplink[slice_id]);//cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS if (UE_template->pre_allocated_rb_table_index_ul >= 0) { - rb_table_index = - UE_template->pre_allocated_rb_table_index_ul; + rb_table_index = UE_template->pre_allocated_rb_table_index_ul; } else { UE_template->mcs_UL[harq_pid] = 10; //cmin (10, openair_daq_vars.target_ue_ul_mcs); rb_table_index = 5; // for PHR @@ -1309,10 +1307,9 @@ schedule_ulsch_rnti(module_id_t module_idP, // buffer_occupancy = UE_template->ul_total_buffer; - while (((rb_table[rb_table_index] > - (N_RB_UL - 1 - first_rb[CC_id])) - || (rb_table[rb_table_index] > 45)) - && (rb_table_index > 0)) { + while (((rb_table[rb_table_index] > (N_RB_UL - 1 - first_rb[CC_id])) + || (rb_table[rb_table_index] > 45)) + && (rb_table_index > 0)) { rb_table_index--; } diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 544a48b80b..6d0d56668d 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -58,6 +58,7 @@ //#define DEBUG_PACKET_TRACE 1 extern float slice_percentage[MAX_NUM_SLICES]; +extern float slice_percentage_uplink[MAX_NUM_SLICES]; //#define ICIC 0 @@ -1377,13 +1378,13 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, total_allocated_rbs[MAX_NUM_CCs], average_rbs_per_user[MAX_NUM_CCs]; int16_t total_remaining_rbs[MAX_NUM_CCs]; - uint16_t max_num_ue_to_be_scheduled = 0; - uint16_t total_ue_count = 0; + uint16_t total_ue_count[MAX_NUM_CCs]; rnti_t rnti = -1; UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; UE_TEMPLATE *UE_template = 0; - int N_RB_DL; - int N_RB_UL; + UE_sched_ctrl *ue_sched_ctl; + int N_RB_UL = 0; + LOG_D(MAC, "In ulsch_preprocessor: assign max mcs min rb\n"); // maximize MCS and then allocate required RB according to the buffer occupancy with the limit of max available UL RB assign_max_mcs_min_rb(module_idP, slice_id, frameP, subframeP, first_rb); @@ -1396,186 +1397,180 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, // we need to distribute RBs among UEs // step1: reset the vars for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - N_RB_DL = - to_prb(RC.mac[module_idP]->common_channels[CC_id].mib-> - message.dl_Bandwidth); - N_RB_UL = - to_prb(RC.mac[module_idP]->common_channels[CC_id]. - ul_Bandwidth); - total_allocated_rbs[CC_id] = 0; - total_remaining_rbs[CC_id] = 0; - average_rbs_per_user[CC_id] = 0; + total_allocated_rbs[CC_id] = 0; + total_remaining_rbs[CC_id] = 0; + average_rbs_per_user[CC_id] = 0; + total_ue_count[CC_id] = 0; + } - for (i = UE_list->head_ul; i >= 0; i = UE_list->next_ul[i]) { - nb_allocated_rbs[CC_id][i] = 0; - } + // Step 1.5: Calculate total_ue_count + for (i = UE_list->head_ul; i >= 0; i = UE_list->next_ul[i]) { + for (n = 0; n < UE_list->numactiveULCCs[i]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][i]; + UE_template = &UE_list->UE_template[CC_id][i]; + if (flexran_slice_member(i, slice_id) == 0) + continue; + if (UE_template->pre_allocated_nb_rb_ul[slice_id] > 0) { + total_ue_count[CC_id] += 1; + } + } } LOG_D(MAC, "In ulsch_preprocessor: step2 \n"); // step 2: calculate the average rb per UE - total_ue_count = 0; - max_num_ue_to_be_scheduled = 0; - for (i = UE_list->head_ul; i >= 0; i = UE_list->next_ul[i]) { - rnti = UE_RNTI(module_idP, i); + rnti = UE_RNTI(module_idP, i); - if (rnti == NOT_A_RNTI) - continue; + if (rnti == NOT_A_RNTI) + continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + + if (flexran_slice_member(UE_id, slice_id) == 0) + continue; + + UE_id = i; + + LOG_D(MAC, "In ulsch_preprocessor: handling UE %d/%x\n", UE_id, + rnti); + for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; + LOG_D(MAC, + "In ulsch_preprocessor: handling UE %d/%x CCid %d\n", + UE_id, rnti, CC_id); + + average_rbs_per_user[CC_id] = 0; + + /* + if((mac_xface->get_nCCE_max(module_idP,CC_id,3,subframeP) - nCCE_to_be_used[CC_id]) > (1<numactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - LOG_D(MAC, - "In ulsch_preprocessor: handling UE %d/%x CCid %d\n", - UE_id, rnti, CC_id); - UE_template = &UE_list->UE_template[CC_id][UE_id]; - average_rbs_per_user[CC_id] = 0; + N_RB_UL = to_prb(RC.mac[module_idP]->common_channels[CC_id].ul_Bandwidth); + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_id] = flexran_nb_rbs_allowed_slice(slice_percentage_uplink[slice_id],N_RB_UL); - if (UE_template->pre_allocated_nb_rb_ul > 0) { - total_ue_count += 1; - } - /* - if((mac_xface->get_nCCE_max(module_idP,CC_id,3,subframeP) - nCCE_to_be_used[CC_id]) > (1< 0) { - average_rbs_per_user[CC_id] = - (uint16_t) floor((N_RB_UL - first_rb[CC_id]) / - max_num_ue_to_be_scheduled); - } else { - average_rbs_per_user[CC_id] = 1; - LOG_W(MAC, - "[eNB %d] frame %d subframe %d: UE %d CC %d: can't get average rb per user (should not be here)\n", - module_idP, frameP, subframeP, UE_id, CC_id); - } - } + if (total_ue_count[CC_id] == 0) { + average_rbs_per_user[CC_id] = 0; + } else if (total_ue_count[CC_id] == 1) { // increase the available RBs, special case, + average_rbs_per_user[CC_id] = ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_id] - first_rb[CC_id] + 1; + } else if (total_ue_count[CC_id] <= (ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_id] - first_rb[CC_id])) { + average_rbs_per_user[CC_id] = (uint16_t) floor((ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_id] - first_rb[CC_id]) / total_ue_count[CC_id]); + } else { + average_rbs_per_user[CC_id] = 1; + LOG_W(MAC, + "[eNB %d] frame %d subframe %d: UE %d CC %d: can't get average rb per user (should not be here)\n", + module_idP, frameP, subframeP, UE_id, CC_id); + } + if (total_ue_count[CC_id] > 0) + LOG_D(MAC, "[eNB %d] Frame %d subframe %d: total ue to be scheduled %d\n", + module_idP, frameP, subframeP, total_ue_count[CC_id]); + } } - if (total_ue_count > 0) - LOG_D(MAC, - "[eNB %d] Frame %d subframe %d: total ue to be scheduled %d/%d\n", - module_idP, frameP, subframeP, total_ue_count, - max_num_ue_to_be_scheduled); - - //LOG_D(MAC,"step3\n"); // step 3: assigne RBS for (i = UE_list->head_ul; i >= 0; i = UE_list->next_ul[i]) { - rnti = UE_RNTI(module_idP, i); + rnti = UE_RNTI(module_idP, i); - if (rnti == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - - UE_id = i; - - for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - harq_pid = - subframe2harqpid(&RC.mac[module_idP]-> - common_channels[CC_id], frameP, - subframeP); + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + if (flexran_slice_member(i, slice_id) == 0) + continue; - // mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL); + UE_id = i; - if (UE_list->UE_sched_ctrl[UE_id].round_UL[CC_id] > 0) { - nb_allocated_rbs[CC_id][UE_id] = - UE_list->UE_template[CC_id][UE_id].nb_rb_ul[harq_pid]; - } else { - nb_allocated_rbs[CC_id][UE_id] = - cmin(UE_list-> - UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul, - average_rbs_per_user[CC_id]); - } + for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; + UE_template = &UE_list->UE_template[CC_id][UE_id]; + harq_pid = subframe2harqpid(&RC.mac[module_idP]->common_channels[CC_id], + frameP, subframeP); - total_allocated_rbs[CC_id] += nb_allocated_rbs[CC_id][UE_id]; - LOG_D(MAC, - "In ulsch_preprocessor: assigning %d RBs for UE %d/%x CCid %d, harq_pid %d\n", - nb_allocated_rbs[CC_id][UE_id], UE_id, rnti, CC_id, - harq_pid); - } + // mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL); + + if (UE_list->UE_sched_ctrl[UE_id].round_UL[CC_id] > 0) { + nb_allocated_rbs[CC_id][UE_id] = UE_list->UE_template[CC_id][UE_id].nb_rb_ul[harq_pid]; + } else { + nb_allocated_rbs[CC_id][UE_id] = + cmin(UE_list->UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul[slice_id], + average_rbs_per_user[CC_id]); + } + + total_allocated_rbs[CC_id] += nb_allocated_rbs[CC_id][UE_id]; + LOG_D(MAC, + "In ulsch_preprocessor: assigning %d RBs for UE %d/%x CCid %d, harq_pid %d\n", + nb_allocated_rbs[CC_id][UE_id], UE_id, rnti, CC_id, + harq_pid); + } } // step 4: assigne the remaining RBs and set the pre_allocated rbs accordingly - for (r = 0; r < 2; r++) { + for (r = 0; r < 2; r++) { - for (i = UE_list->head_ul; i >= 0; i = UE_list->next_ul[i]) { - rnti = UE_RNTI(module_idP, i); + for (i = UE_list->head_ul; i >= 0; i = UE_list->next_ul[i]) { + rnti = UE_RNTI(module_idP, i); - if (rnti == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - UE_id = i; + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + if (flexran_slice_member(i, slice_id) == 0) + continue; - for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; - UE_template = &UE_list->UE_template[CC_id][UE_id]; - total_remaining_rbs[CC_id] = - N_RB_UL - first_rb[CC_id] - total_allocated_rbs[CC_id]; + UE_id = i; - if (total_ue_count == 1) { - total_remaining_rbs[CC_id] += 1; - } + for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; + UE_template = &UE_list->UE_template[CC_id][UE_id]; + total_remaining_rbs[CC_id] = + ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_id] - first_rb[CC_id] - total_allocated_rbs[CC_id]; - if (r == 0) { - while ((UE_template->pre_allocated_nb_rb_ul > 0) && - (nb_allocated_rbs[CC_id][UE_id] < - UE_template->pre_allocated_nb_rb_ul) - && (total_remaining_rbs[CC_id] > 0)) { - nb_allocated_rbs[CC_id][UE_id] = - cmin(nb_allocated_rbs[CC_id][UE_id] + 1, - UE_template->pre_allocated_nb_rb_ul); - total_remaining_rbs[CC_id]--; - total_allocated_rbs[CC_id]++; - } - } else { - UE_template->pre_allocated_nb_rb_ul = - nb_allocated_rbs[CC_id][UE_id]; - LOG_D(MAC, - "******************UL Scheduling Information for UE%d CC_id %d ************************\n", - UE_id, CC_id); - LOG_D(MAC, - "[eNB %d] total RB allocated for UE%d CC_id %d = %d\n", - module_idP, UE_id, CC_id, - UE_template->pre_allocated_nb_rb_ul); - } - } - } + if (total_ue_count[CC_id] == 1) { + total_remaining_rbs[CC_id] += 1; + } + + if (r == 0) { + while ((UE_template->pre_allocated_nb_rb_ul[slice_id] > 0) + && (nb_allocated_rbs[CC_id][UE_id] < UE_template->pre_allocated_nb_rb_ul[slice_id]) + && (total_remaining_rbs[CC_id] > 0)) { + nb_allocated_rbs[CC_id][UE_id] = + cmin(nb_allocated_rbs[CC_id][UE_id] + 1, + UE_template->pre_allocated_nb_rb_ul[slice_id]); + total_remaining_rbs[CC_id]--; + total_allocated_rbs[CC_id]++; + } + } else { + UE_template->pre_allocated_nb_rb_ul[slice_id] = + nb_allocated_rbs[CC_id][UE_id]; + LOG_D(MAC, + "******************UL Scheduling Information for UE%d CC_id %d ************************\n", + UE_id, CC_id); + LOG_D(MAC, + "[eNB %d] total RB allocated for UE%d CC_id %d = %d\n", + module_idP, UE_id, CC_id, + UE_template->pre_allocated_nb_rb_ul[slice_id]); + } + } } + } for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { if (total_allocated_rbs[CC_id] > 0) { LOG_D(MAC, "[eNB %d] total RB allocated for all UEs = %d/%d\n", module_idP, total_allocated_rbs[CC_id], - N_RB_UL - first_rb[CC_id]); + ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_id] - first_rb[CC_id]); } } } @@ -1586,134 +1581,123 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, sub_frame_t subframeP, uint16_t * first_rb) { - int i; - uint16_t n, UE_id; - uint8_t CC_id; - rnti_t rnti = -1; - int mcs; - int rb_table_index = 0, tbs, tx_power; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - UE_list_t *UE_list = &eNB->UE_list; + int i; + uint16_t n, UE_id; + uint8_t CC_id; + rnti_t rnti = -1; + int mcs; + int rb_table_index = 0, tbs, tx_power; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + UE_list_t *UE_list = &eNB->UE_list; - UE_TEMPLATE *UE_template; - int Ncp; - int N_RB_UL; + UE_TEMPLATE *UE_template; + UE_sched_ctrl *ue_sched_ctl; + int Ncp; + int N_RB_UL; - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i] != TRUE) - continue; + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + if (UE_list->active[i] != TRUE) + continue; - rnti = UE_RNTI(module_idP, i); + rnti = UE_RNTI(module_idP, i); - if (rnti == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + if (flexran_slice_member(i, slice_id) == 0) + continue; - if (UE_list->UE_sched_ctrl[i].phr_received == 1) - mcs = 20; // if we've received the power headroom information the UE, we can go to maximum mcs - else - mcs = 10; // otherwise, limit to QPSK PUSCH + if (UE_list->UE_sched_ctrl[i].phr_received == 1) + mcs = 20; // if we've received the power headroom information the UE, we can go to maximum mcs + else + mcs = 10; // otherwise, limit to QPSK PUSCH - UE_id = i; + UE_id = i; - for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { - // This is the actual CC_id in the list - CC_id = UE_list->ordered_ULCCids[n][UE_id]; + for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { + // This is the actual CC_id in the list + CC_id = UE_list->ordered_ULCCids[n][UE_id]; - if (CC_id >= MAX_NUM_CCs) { - LOG_E(MAC, - "CC_id %u should be < %u, loop n=%u < numactiveULCCs[%u]=%u", - CC_id, MAX_NUM_CCs, n, UE_id, - UE_list->numactiveULCCs[UE_id]); - } + if (CC_id >= MAX_NUM_CCs) { + LOG_E(MAC, "CC_id %u should be < %u, loop n=%u < numactiveULCCs[%u]=%u", + CC_id, MAX_NUM_CCs, n, UE_id, UE_list->numactiveULCCs[UE_id]); + } - AssertFatal(CC_id < MAX_NUM_CCs, - "CC_id %u should be < %u, loop n=%u < numactiveULCCs[%u]=%u", - CC_id, MAX_NUM_CCs, n, UE_id, - UE_list->numactiveULCCs[UE_id]); + AssertFatal(CC_id < MAX_NUM_CCs, + "CC_id %u should be < %u, loop n=%u < numactiveULCCs[%u]=%u", + CC_id, MAX_NUM_CCs, n, UE_id, + UE_list->numactiveULCCs[UE_id]); - UE_template = &UE_list->UE_template[CC_id][UE_id]; + UE_template = &UE_list->UE_template[CC_id][UE_id]; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - Ncp = RC.mac[module_idP]->common_channels[CC_id].Ncp; - N_RB_UL = - to_prb(RC.mac[module_idP]->common_channels[CC_id]. - ul_Bandwidth); - // if this UE has UL traffic - int bytes_to_schedule = UE_template->estimated_ul_buffer - UE_template->scheduled_ul_bytes; - if (bytes_to_schedule < 0) bytes_to_schedule = 0; - int bits_to_schedule = bytes_to_schedule * 8; + Ncp = RC.mac[module_idP]->common_channels[CC_id].Ncp; + N_RB_UL = to_prb(RC.mac[module_idP]->common_channels[CC_id].ul_Bandwidth); + ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_id] = flexran_nb_rbs_allowed_slice(slice_percentage_uplink[slice_id],N_RB_UL); - if (bits_to_schedule > 0) { - tbs = get_TBS_UL(mcs, 3) << 3; // 1 or 2 PRB with cqi enabled does not work well! - rb_table_index = 2; + // if this UE has UL traffic + if (UE_template->ul_total_buffer > 0) { + tbs = get_TBS_UL(mcs, 3) << 3; // 1 or 2 PRB with cqi enabled does not work well! + rb_table_index = 2; - // fixme: set use_srs flag - tx_power = - estimate_ue_tx_power(tbs, rb_table[rb_table_index], 0, - Ncp, 0); + // fixme: set use_srs flag + tx_power = estimate_ue_tx_power(tbs, rb_table[rb_table_index], 0, Ncp, 0); - while ((((UE_template->phr_info - tx_power) < 0) - || (tbs > bits_to_schedule)) - && (mcs > 3)) { - // LOG_I(MAC,"UE_template->phr_info %d tx_power %d mcs %d\n", UE_template->phr_info,tx_power, mcs); - mcs--; - tbs = get_TBS_UL(mcs, rb_table[rb_table_index]) << 3; - tx_power = estimate_ue_tx_power(tbs, rb_table[rb_table_index], 0, Ncp, 0); // fixme: set use_srs - } + while ((((UE_template->phr_info - tx_power) < 0) + || (tbs > UE_template->ul_total_buffer)) + && (mcs > 3)) { + // LOG_I(MAC,"UE_template->phr_info %d tx_power %d mcs %d\n", UE_template->phr_info,tx_power, mcs); + mcs--; + tbs = get_TBS_UL(mcs, rb_table[rb_table_index]) << 3; + tx_power = estimate_ue_tx_power(tbs, rb_table[rb_table_index], 0, Ncp, 0); // fixme: set use_srs + } - while ((tbs < bits_to_schedule) && - (rb_table[rb_table_index] < - (N_RB_UL - first_rb[CC_id])) - && ((UE_template->phr_info - tx_power) > 0) - && (rb_table_index < 32)) { + while ((tbs < bits_to_schedule) + && (rb_table[rb_table_index] < (ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id] - first_rb[CC_id])) + && ((UE_template->phr_info - tx_power) > 0) + && (rb_table_index < 32)) { + rb_table_index++; + tbs = get_TBS_UL(mcs, rb_table[rb_table_index]) << 3; + tx_power = estimate_ue_tx_power(tbs, rb_table[rb_table_index], 0, Ncp, 0); + } - rb_table_index++; - tbs = get_TBS_UL(mcs, rb_table[rb_table_index]) << 3; - tx_power = - estimate_ue_tx_power(tbs, rb_table[rb_table_index], - 0, Ncp, 0); - } + UE_template->ue_tx_power = tx_power; - UE_template->ue_tx_power = tx_power; + if (rb_table[rb_table_index] > (ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id] - first_rb[CC_id] - 1)) { + rb_table_index--; + } + // 1 or 2 PRB with cqi enabled does not work well + if (rb_table[rb_table_index] < 3) { + rb_table_index = 2; //3PRB + } - if (rb_table[rb_table_index] > - (N_RB_UL - first_rb[CC_id] - 1)) { - rb_table_index--; - } - // 1 or 2 PRB with cqi enabled does not work well - if (rb_table[rb_table_index] < 3) { - rb_table_index = 2; //3PRB - } - - UE_template->pre_assigned_mcs_ul = mcs; - UE_template->pre_allocated_rb_table_index_ul = - rb_table_index; - UE_template->pre_allocated_nb_rb_ul = - rb_table[rb_table_index]; - LOG_D(MAC, - "[eNB %d] frame %d subframe %d: for UE %d CC %d: pre-assigned mcs %d, pre-allocated rb_table[%d]=%d RBs (phr %d, tx power %d)\n", - module_idP, frameP, subframeP, UE_id, CC_id, - UE_template->pre_assigned_mcs_ul, - UE_template->pre_allocated_rb_table_index_ul, - UE_template->pre_allocated_nb_rb_ul, - UE_template->phr_info, tx_power); - } else { - /* if UE has pending scheduling request then pre-allocate 3 RBs */ - //if (UE_template->ul_active == 1 && UE_template->ul_SR == 1) { - if (UE_is_to_be_scheduled(module_idP, CC_id, i)) { - /* use QPSK mcs */ - UE_template->pre_assigned_mcs_ul = 10; - UE_template->pre_allocated_rb_table_index_ul = 2; - UE_template->pre_allocated_nb_rb_ul = 3; - } else { - UE_template->pre_assigned_mcs_ul = 0; - UE_template->pre_allocated_rb_table_index_ul = -1; - UE_template->pre_allocated_nb_rb_ul = 0; - } - } - } + UE_template->pre_assigned_mcs_ul = mcs; + UE_template->pre_allocated_rb_table_index_ul = rb_table_index; + UE_template->pre_allocated_nb_rb_ul[slice_id] = rb_table[rb_table_index]; + LOG_D(MAC, + "[eNB %d] frame %d subframe %d: for UE %d CC %d: pre-assigned mcs %d, pre-allocated rb_table[%d]=%d RBs (phr %d, tx power %d)\n", + module_idP, frameP, subframeP, UE_id, CC_id, + UE_template->pre_assigned_mcs_ul, + UE_template->pre_allocated_rb_table_index_ul, + UE_template->pre_allocated_nb_rb_ul[slice_id], + UE_template->phr_info, tx_power); + } else { + /* if UE has pending scheduling request then pre-allocate 3 RBs */ + //if (UE_template->ul_active == 1 && UE_template->ul_SR == 1) { + if (UE_is_to_be_scheduled(module_idP, CC_id, i)) { + /* use QPSK mcs */ + UE_template->pre_assigned_mcs_ul = 10; + UE_template->pre_allocated_rb_table_index_ul = 2; + UE_template->pre_allocated_nb_rb_ul[slice_id] = 3; + } else { + UE_template->pre_assigned_mcs_ul = 0; + UE_template->pre_allocated_rb_table_index_ul = -1; + UE_template->pre_allocated_nb_rb_ul[slice_id] = 0; + } + } } + } } struct sort_ue_ul_params { From cf0a5ca9205e2a9fb8650e6c06373257921d2e0f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 9 Feb 2018 19:10:41 +0100 Subject: [PATCH 221/284] fix RAN API due to merge + repair functions --- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 2 +- openair2/ENB_APP/flexran_agent_common.c | 4 +-- openair2/ENB_APP/flexran_agent_ran_api.c | 30 +++++++------------ openair2/ENB_APP/flexran_agent_ran_api.h | 10 +++---- 4 files changed, 18 insertions(+), 28 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 4f5d8af250..f875264967 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -83,7 +83,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, goto error; for (j = 0; j < ue_report[i]->n_bsr; j++) { // NN: we need to know the cc_id here, consider the first one - elem[j] = flexran_get_ue_bsr (enb_id, i, j); + elem[j] = flexran_get_ue_bsr_ul_buffer_info (enb_id, i, j); } ue_report[i]->bsr = elem; diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index de0de15c0a..f837d575d5 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -489,10 +489,10 @@ int flexran_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Fl lc_config[j]->has_lcid = 1; lc_config[j]->lcid = j+1; - int lcg = flexran_get_lcg(i, j+1); + int lcg = flexran_get_lcg(mod_id, i, j+1); if (lcg >= 0 && lcg <= 3) { lc_config[j]->has_lcg = 1; - lc_config[j]->lcg = flexran_get_lcg(i,j+1); + lc_config[j]->lcg = flexran_get_lcg(mod_id, i,j+1); } lc_config[j]->has_direction = 1; diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index ddbc3ad869..97a77a634c 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -117,10 +117,10 @@ rnti_t flexran_get_ue_crnti(mid_t mod_id, mid_t ue_id) return UE_RNTI(mod_id, ue_id); } -uint8_t flexran_get_ue_bsr(mid_t mod_id, mid_t ue_id, lcid_t lcid) +int flexran_get_ue_bsr_ul_buffer_info(mid_t mod_id, mid_t ue_id, lcid_t lcid) { - if (!mac_is_present(mod_id)) return 0; - return RC.mac[mod_id]->UE_list.UE_template[UE_PCCID(mod_id, ue_id)][ue_id].bsr_info[lcid]; + if (!mac_is_present(mod_id)) return -1; + return RC.mac[mod_id]->UE_list.UE_template[UE_PCCID(mod_id, ue_id)][ue_id].ul_buffer_info[lcid]; } int8_t flexran_get_ue_phr(mid_t mod_id, mid_t ue_id) @@ -390,7 +390,6 @@ PHICH_DURATION_t flexran_get_phich_duration(mid_t mod_id, uint8_t cc_id) int flexran_get_phich_resource(mid_t mod_id, uint8_t cc_id) { if (!phy_is_present(mod_id, cc_id)) return 0; - /* TODO why don't we return phich_resource? */ switch (RC.eNB[mod_id][cc_id]->frame_parms.phich_config_common.phich_resource) { case oneSixth: return 0; @@ -544,12 +543,10 @@ uint8_t flexran_get_sib1_length(mid_t mod_id, uint8_t cc_id) return RC.rrc[mod_id]->carrier[cc_id].sizeof_SIB1; } -uint8_t flexran_get_num_pdcch_symb(mid_t mod_id, uint8_t cc_id) { - /* TODO: This should return the number of PDCCH symbols initially used by the - * cell cc_id -> is the correction right? */ +uint8_t flexran_get_num_pdcch_symb(mid_t mod_id, uint8_t cc_id) +{ if (!phy_is_present(mod_id, cc_id)) return 0; return RC.eNB[mod_id][cc_id]->pdcch_vars[0].num_pdcch_symbols; - //(PHY_vars_UE_g[mod_id][cc_id]->lte_ue_pdcch_vars[mod_id]->num_pdcch_symbols); } @@ -614,12 +611,11 @@ long flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) } } -/* TODO is there a reason we take the RNTI and not the UE ID? */ -/* TODO return type is unsigned, so we cannot return -1 in case of error! */ -uint8_t flexran_get_rrc_status(mid_t mod_id, rnti_t rnti) +uint8_t flexran_get_rrc_status(mid_t mod_id, mid_t ue_id) { if (!rrc_is_present(mod_id)) return 0; + rnti_t rnti = flexran_get_ue_crnti(mod_id, ue_id); struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return RRC_INACTIVE; @@ -893,14 +889,10 @@ int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) } } -/* TODO Navid: Get the same for eNB */ -long flexran_get_lcg(mid_t ue_id, mid_t lc_id) +long flexran_get_lcg(mid_t mod_id, mid_t ue_id, mid_t lc_id) { - if (!UE_mac_inst) return -1; - if (!UE_mac_inst[ue_id].logicalChannelConfig[lc_id]) return -1; - if (!UE_mac_inst[ue_id].logicalChannelConfig[lc_id]->ul_SpecificParameters) return -1; - if (!UE_mac_inst[ue_id].logicalChannelConfig[lc_id]->ul_SpecificParameters->logicalChannelGroup) return -1; - return *(UE_mac_inst[ue_id].logicalChannelConfig[lc_id]->ul_SpecificParameters->logicalChannelGroup); + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.UE_template[UE_PCCID(mod_id, ue_id)][ue_id].lcgidmap[lc_id]; } /* TODO Navid: needs to be revised */ @@ -923,14 +915,12 @@ uint8_t flexran_get_antenna_ports(mid_t mod_id, uint8_t cc_id) return RC.eNB[mod_id][cc_id]->frame_parms.nb_antenna_ports_eNB; } -/* TODO better give real value (without division)? */ uint32_t flexran_agent_get_operating_dl_freq(mid_t mod_id, uint8_t cc_id) { if (!phy_is_present(mod_id, cc_id)) return 0; return RC.eNB[mod_id][cc_id]->frame_parms.dl_CarrierFreq / 1000000; } -/* TODO better give real value (without division)? */ uint32_t flexran_agent_get_operating_ul_freq(mid_t mod_id, uint8_t cc_id) { if (!phy_is_present(mod_id, cc_id)) return 0; diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 62752f1308..b3515c9c6c 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -77,9 +77,9 @@ int flexran_get_num_ues(mid_t mod_id); /* Get the rnti of a UE with id ue_id */ rnti_t flexran_get_ue_crnti(mid_t mod_id, mid_t ue_id); -/* Get the RLC buffer status report of a ue for a designated - logical channel id */ -uint8_t flexran_get_ue_bsr(mid_t mod_id, mid_t ue_id, lcid_t lcid); +/* Get the RLC buffer status report in bytes of a ue for a designated + * logical channel id */ +int flexran_get_ue_bsr_ul_buffer_info(mid_t mod_id, mid_t ue_id, lcid_t lcid); /* Get power headroom of UE with id ue_id */ int8_t flexran_get_ue_phr(mid_t mod_id, mid_t ue_id); @@ -302,7 +302,7 @@ long flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id); int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id); /* Get logical channel group of a channel with id lc_id */ -long flexran_get_lcg(mid_t ue_id, mid_t lc_id); +long flexran_get_lcg(mid_t mod_id, mid_t ue_id, mid_t lc_id); /* Get direction of logical channel with id lc_id */ int flexran_get_direction(mid_t ue_id, mid_t lc_id); @@ -338,7 +338,7 @@ void flexran_agent_set_operating_bandwidth(mid_t mod_id, uint8_t cc_id, uint8_t void flexran_agent_set_operating_frame_type(mid_t mod_id, uint8_t cc_id, lte_frame_type_t frame_type); /*RRC status flexRAN*/ -uint8_t flexran_get_rrc_status(const mid_t mod_id, const rnti_t rntiP); +uint8_t flexran_get_rrc_status(mid_t mod_id, mid_t ue_id); /***************************** PDCP ***********************/ From 8108d59a0bdb2eba243173b5fa8b9548631e617e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 12 Feb 2018 12:10:21 +0100 Subject: [PATCH 222/284] no regression, fixes compilation warnings&errors --- openair2/LAYER2/MAC/pre_processor.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 6d0d56668d..12c80e9efe 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -1422,6 +1422,7 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, for (i = UE_list->head_ul; i >= 0; i = UE_list->next_ul[i]) { rnti = UE_RNTI(module_idP, i); + UE_id = i; if (rnti == NOT_A_RNTI) continue; @@ -1432,8 +1433,6 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, if (flexran_slice_member(UE_id, slice_id) == 0) continue; - UE_id = i; - LOG_D(MAC, "In ulsch_preprocessor: handling UE %d/%x\n", UE_id, rnti); for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { @@ -1528,6 +1527,7 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, continue; UE_id = i; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; for (n = 0; n < UE_list->numactiveULCCs[UE_id]; n++) { // This is the actual CC_id in the list @@ -1636,8 +1636,12 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, N_RB_UL = to_prb(RC.mac[module_idP]->common_channels[CC_id].ul_Bandwidth); ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_id] = flexran_nb_rbs_allowed_slice(slice_percentage_uplink[slice_id],N_RB_UL); + int bytes_to_schedule = UE_template->estimated_ul_buffer - UE_template->scheduled_ul_bytes; + if (bytes_to_schedule < 0) bytes_to_schedule = 0; + int bits_to_schedule = bytes_to_schedule * 8; + // if this UE has UL traffic - if (UE_template->ul_total_buffer > 0) { + if (bits_to_schedule > 0) { tbs = get_TBS_UL(mcs, 3) << 3; // 1 or 2 PRB with cqi enabled does not work well! rb_table_index = 2; @@ -1645,7 +1649,7 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, tx_power = estimate_ue_tx_power(tbs, rb_table[rb_table_index], 0, Ncp, 0); while ((((UE_template->phr_info - tx_power) < 0) - || (tbs > UE_template->ul_total_buffer)) + || (tbs > bits_to_schedule)) && (mcs > 3)) { // LOG_I(MAC,"UE_template->phr_info %d tx_power %d mcs %d\n", UE_template->phr_info,tx_power, mcs); mcs--; @@ -1654,7 +1658,7 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, } while ((tbs < bits_to_schedule) - && (rb_table[rb_table_index] < (ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id] - first_rb[CC_id])) + && (rb_table[rb_table_index] < (ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_id] - first_rb[CC_id])) && ((UE_template->phr_info - tx_power) > 0) && (rb_table_index < 32)) { rb_table_index++; @@ -1664,7 +1668,7 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, UE_template->ue_tx_power = tx_power; - if (rb_table[rb_table_index] > (ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id] - first_rb[CC_id] - 1)) { + if (rb_table[rb_table_index] > (ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_id] - first_rb[CC_id] - 1)) { rb_table_index--; } // 1 or 2 PRB with cqi enabled does not work well From ceece5694dda2a80f1a36abf18bccd6b6c2b50ef Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 12 Feb 2018 12:30:36 +0100 Subject: [PATCH 223/284] rename flexran_slice_member() -> ue_slice_membership() --- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 2 +- .../LAYER2/MAC/eNB_scheduler_primitives.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 2 +- openair2/LAYER2/MAC/pre_processor.c | 24 +++++++++---------- openair2/LAYER2/MAC/proto.h | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 7c836c9e72..bed97e47c6 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -710,7 +710,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, LOG_D(MAC, "[eNB] Cannot find eNB_UE_stats\n"); continue_flag = 1; } - if (flexran_slice_member(UE_id, slice_idP) == 0) + if (!ue_slice_membership(UE_id, slice_idP)) continue; if (continue_flag != 1) { diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 046a823a87..341db67934 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -4050,7 +4050,7 @@ uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, int total_rbs) return (uint16_t) floor(rb_percentage * total_rbs); } -int flexran_slice_member(int UE_id, int slice_id) +int ue_slice_membership(int UE_id, int slice_id) { if ((slice_id < 0) || (slice_id > n_active_slices)) LOG_W(MAC, "out of range slice id %d\n", slice_id); diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index b24a3f42ac..2403ec2d13 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -1126,7 +1126,7 @@ schedule_ulsch_rnti(module_id_t module_idP, for (UE_id = UE_list->head_ul; UE_id >= 0; UE_id = UE_list->next_ul[UE_id]) { - if (flexran_slice_member(UE_id, slice_id) == 0) + if (!ue_slice_membership(UE_id, slice_id)) continue; // don't schedule if Msg4 is not received yet diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 12c80e9efe..c179c211b2 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -107,7 +107,7 @@ store_dlsch_buffer(module_id_t Mod_id, slice_id_t slice_id, frame_t frameP, if (UE_list->active[UE_id] != TRUE) continue; - if (flexran_slice_member(UE_id, slice_id) == 0) + if (!ue_slice_membership(UE_id, slice_id)) continue; UE_template = @@ -201,7 +201,7 @@ assign_rbs_required(module_id_t Mod_id, for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { if (UE_list->active[UE_id] != TRUE) continue; - if (flexran_slice_member(UE_id, slice_id) == 0) + if (!ue_slice_membership(UE_id, slice_id)) continue; pCCid = UE_PCCID(Mod_id, UE_id); @@ -610,7 +610,7 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, if (UE_list->active[i] != TRUE) continue; - if (!flexran_slice_member(i, slice_id)) + if (!ue_slice_membership(i, slice_id)) continue; UE_id = i; @@ -659,7 +659,7 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) continue; UE_id = i; - if (flexran_slice_member(UE_id, slice_id) == 0) + if (!ue_slice_membership(UE_id, slice_id)) continue; for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { @@ -698,7 +698,7 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) continue; UE_id = i; - if (flexran_slice_member(UE_id, slice_id) == 0) + if (!ue_slice_membership(UE_id, slice_id)) continue; for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { @@ -743,7 +743,7 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, continue; if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) continue; - if (flexran_slice_member(i, slice_id) == 0) + if (!ue_slice_membership(i, slice_id)) continue; for (ii = 0; ii < UE_num_active_CC(UE_list, i); ii++) { @@ -820,7 +820,7 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, continue; if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) continue; - if (flexran_slice_member(i, slice_id) == 0) + if (!ue_slice_membership(i, slice_id)) continue; transmission_mode = get_tmode(Mod_id, CC_id, UE_id); @@ -1409,7 +1409,7 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, // This is the actual CC_id in the list CC_id = UE_list->ordered_ULCCids[n][i]; UE_template = &UE_list->UE_template[CC_id][i]; - if (flexran_slice_member(i, slice_id) == 0) + if (!ue_slice_membership(i, slice_id)) continue; if (UE_template->pre_allocated_nb_rb_ul[slice_id] > 0) { total_ue_count[CC_id] += 1; @@ -1430,7 +1430,7 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) continue; - if (flexran_slice_member(UE_id, slice_id) == 0) + if (!ue_slice_membership(UE_id, slice_id)) continue; LOG_D(MAC, "In ulsch_preprocessor: handling UE %d/%x\n", UE_id, @@ -1482,7 +1482,7 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, continue; if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) continue; - if (flexran_slice_member(i, slice_id) == 0) + if (!ue_slice_membership(i, slice_id)) continue; @@ -1523,7 +1523,7 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, continue; if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) continue; - if (flexran_slice_member(i, slice_id) == 0) + if (!ue_slice_membership(i, slice_id)) continue; UE_id = i; @@ -1605,7 +1605,7 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, continue; if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) continue; - if (flexran_slice_member(i, slice_id) == 0) + if (!ue_slice_membership(i, slice_id)) continue; if (UE_list->UE_sched_ctrl[i].phr_received == 1) diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index ba13f45e26..c0d294ded6 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -1197,7 +1197,7 @@ int l2_init_ue(int eMBMS_active, char *uecap_xer, uint8_t cba_group_active, /*Slice related functions */ uint16_t flexran_nb_rbs_allowed_slice(float rb_percentage, int total_rbs); -int flexran_slice_member(int UE_id, int slice_id); +int ue_slice_membership(int UE_id, int slice_id); #endif /** @}*/ From 3768723c62e0bc3871ff211d9ac20e97bcc83fb5 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 12 Feb 2018 12:40:27 +0100 Subject: [PATCH 224/284] remove unnecessary comments --- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 1 - openair2/LAYER2/MAC/proto.h | 9 ++------- openair2/RRC/LITE/rrc_eNB.c | 1 - 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index bed97e47c6..fb123134f8 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -541,7 +541,6 @@ schedule_dlsch(module_id_t module_idP, } // Run each enabled slice-specific schedulers one by one - /* TODO Navid took out the dl_info additional information */ slice_sched_dl[i](module_idP, i, frameP, subframeP, mbsfn_flag/*, dl_info*/); } diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index c0d294ded6..be09385ac9 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -38,23 +38,18 @@ /** * slice specific scheduler */ -/* TODO Navid: Protocol__FlexranMessage -> unknown when compiling without - * FlexRAN, what to do with it? Matches schedule_ue_spec now */ typedef void (*slice_scheduler_dl)(module_id_t mod_id, slice_id_t slice_id, frame_t frame, sub_frame_t subframe, - int *mbsfn_flag - /* Protocol__FlexranMessage **dl_info*/); + int *mbsfn_flag); -/* TODO Navid: the same as above, matches schedule_ulsch_rnti now */ typedef void (*slice_scheduler_ul)(module_id_t mod_id, slice_id_t slice_id, frame_t frame, sub_frame_t subframe, unsigned char sched_subframe, - uint16_t *first_rb - /* Protocol__FlexranMessage **ul_info*/); + uint16_t *first_rb); /** \fn void schedule_mib(module_id_t module_idP,frame_t frameP,sub_frame_t subframe); \brief MIB scheduling for PBCH. This function requests the MIB from RRC and provides it to L1. diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 6f35f28ebd..c49b9283e2 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -3362,7 +3362,6 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* cons } #if defined(FLEXRAN_AGENT_SB_IF) -/* TODO Navid: does this belong here? */ //----------------------------------------------------------------------------- void flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* const ctxt_pP, From adec4e39df7dcb692c4c4ce27bc6703d2a68ca60 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 12 Feb 2018 14:38:44 +0100 Subject: [PATCH 225/284] remove all conditional FlexRAN-related compilation directives --- common/ran_context.h | 4 ---- openair2/ENB_APP/enb_config.c | 2 -- openair2/ENB_APP/enb_config.h | 2 -- openair2/LAYER2/MAC/eNB_scheduler.c | 6 ------ openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 2 -- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 2 -- openair2/RRC/LITE/L2_interface.c | 4 ---- openair2/RRC/LITE/proto.h | 6 ------ openair2/RRC/LITE/rrc_eNB.c | 13 ------------- targets/RT/USER/lte-softmodem.c | 3 +-- targets/RT/USER/lte-softmodem.h | 6 ++---- targets/SIMU/USER/oaisim.c | 4 +--- 12 files changed, 4 insertions(+), 50 deletions(-) diff --git a/common/ran_context.h b/common/ran_context.h index d5e2a1f172..f59fd8a79c 100644 --- a/common/ran_context.h +++ b/common/ran_context.h @@ -40,9 +40,7 @@ #include "PHY/impl_defs_top.h" #include "PHY/impl_defs_lte.h" #include "RRC/LITE/defs.h" -#ifdef FLEXRAN_AGENT_SB_IF #include "flexran_agent_defs.h" -#endif #include "gtpv1u.h" #include "NwGtpv1u.h" @@ -67,10 +65,8 @@ typedef struct { int *nb_L1_CC; /// Number of RU instances in this node int nb_RU; -#ifdef FLEXRAN_AGENT_SB_IF /// FlexRAN context variables flexran_agent_info_t **flexran; -#endif /// eNB context variables struct PHY_VARS_eNB_s ***eNB; /// RRC context variables diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index d6f676b83a..1bf2807e81 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -98,7 +98,6 @@ static int enb_check_band_frequencies(char* lib_config_file_name_pP, return errors; } -#ifdef FLEXRAN_AGENT_SB_IF void RCconfig_flexran() { int i; @@ -134,7 +133,6 @@ void RCconfig_flexran() /* TODO: show FlexRAN config now? */ } -#endif void RCconfig_L1(void) { int i,j; diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h index 4e4434ad70..42bef9c4e9 100644 --- a/openair2/ENB_APP/enb_config.h +++ b/openair2/ENB_APP/enb_config.h @@ -94,9 +94,7 @@ typedef struct ru_config_s { } ru_config_t; extern void RCconfig_RU(void); -#ifdef FLEXRAN_AGENT_SB_IF extern void RCconfig_flexran(void); -#endif extern void RCconfig_L1(void); extern void RCconfig_macrlc(void); extern int RCconfig_gtpu(void ); diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 0e2f84b25b..45c1a422dd 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -52,11 +52,9 @@ //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" -#if defined(FLEXRAN_AGENT_SB_IF) //Agent-related headers #include "flexran_agent_extern.h" #include "flexran_agent_mac.h" -#endif #if defined(ENABLE_ITTI) #include "intertask_interface.h" @@ -419,12 +417,10 @@ check_ul_failure(module_id_t module_idP, int CC_id, int UE_id, } // ul_failure_timer>0 //Inform the controller about the UE deactivation. Should be moved to RRC agent in the future -#if defined(FLEXRAN_AGENT_SB_IF) if (rrc_agent_registered[module_idP]) { agent_rrc_xface[module_idP]->flexran_agent_notify_ue_state_change(module_idP, rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); } -#endif UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer++; if(UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer > (U_PLANE_INACTIVITY_VALUE*subframe_num(&RC.eNB[module_idP][CC_id]->frame_parms))){ @@ -661,9 +657,7 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, // This schedules DLSCH in subframeP schedule_dlsch(module_idP, frameP, subframeP, mbsfn_status); -#if defined(FLEXRAN_AGENT_SB_IF) flexran_agent_send_update_stats(module_idP); -#endif // Allocate CCEs for good after scheduling is done for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index fb123134f8..0936a9d0ef 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -57,12 +57,10 @@ #include "intertask_interface.h" #endif -#if defined FLEXRAN_AGENT_SB_IF #include "ENB_APP/flexran_agent_defs.h" #include "flexran_agent_ran_api.h" #include "header.pb-c.h" #include "flexran.pb-c.h" -#endif #include #include "T.h" diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 2403ec2d13..47b6a075cf 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -57,13 +57,11 @@ #include "intertask_interface.h" #endif -#if defined FLEXRAN_AGENT_SB_IF #include "ENB_APP/flexran_agent_defs.h" #include "flexran_agent_ran_api.h" #include "header.pb-c.h" #include "flexran.pb-c.h" #include "flexran_agent_mac.h" -#endif #include #include "T.h" diff --git a/openair2/RRC/LITE/L2_interface.c b/openair2/RRC/LITE/L2_interface.c index f285330854..91834d9c9d 100644 --- a/openair2/RRC/LITE/L2_interface.c +++ b/openair2/RRC/LITE/L2_interface.c @@ -53,9 +53,7 @@ extern UE_MAC_INST *UE_mac_inst; # include "intertask_interface.h" #endif -#if defined(FLEXRAN_AGENT_SB_IF) #include "flexran_agent_extern.h" -#endif //#define RRC_DATA_REQ_DEBUG //#define DEBUG_RRC 1 @@ -470,13 +468,11 @@ void mac_eNB_rrc_ul_failure(const module_id_t Mod_instP, else { LOG_W(RRC,"Frame %d, Subframe %d: UL failure: UE %x unknown \n",frameP,subframeP,rntiP); } -#if defined(FLEXRAN_AGENT_SB_IF) if (rrc_agent_registered[Mod_instP]) { agent_rrc_xface[Mod_instP]->flexran_agent_notify_ue_state_change(Mod_instP, rntiP, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); } -#endif // rrc_mac_remove_ue(Mod_instP,rntiP); } diff --git a/openair2/RRC/LITE/proto.h b/openair2/RRC/LITE/proto.h index 0f5ccdef1b..9ece5bcfdd 100644 --- a/openair2/RRC/LITE/proto.h +++ b/openair2/RRC/LITE/proto.h @@ -33,9 +33,7 @@ #include "RRC/LITE/defs.h" -#if defined(FLEXRAN_AGENT_SB_IF) #include "flexran_agent_extern.h" -#endif //main.c int rrc_init_global_param(void); @@ -274,8 +272,6 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration( ); -#if defined(FLEXRAN_AGENT_SB_IF) - void flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration( const protocol_ctxt_t* const ctxt_pP, @@ -284,8 +280,6 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration( agent_reconf_rrc * trig_param ); -#endif - int freq_to_arfcn10(int band, unsigned long freq); void diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index c49b9283e2..2c8be5cfc6 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -871,12 +871,10 @@ rrc_eNB_free_UE(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_s* } } -#if defined(FLEXRAN_AGENT_SB_IF) if (rrc_agent_registered[enb_mod_idP]) { agent_rrc_xface[enb_mod_idP]->flexran_agent_notify_ue_state_change(enb_mod_idP, rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); } -#endif for(j = 0; j < 10; j++){ ul_req_tmp = &eNB_MAC->UL_req_tmp[CC_id][j].ul_config_request_body; @@ -3361,7 +3359,6 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* cons PDCP_TRANSMISSION_MODE_CONTROL); } -#if defined(FLEXRAN_AGENT_SB_IF) //----------------------------------------------------------------------------- void flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* const ctxt_pP, @@ -3952,8 +3949,6 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt PDCP_TRANSMISSION_MODE_CONTROL); } -#endif - //----------------------------------------------------------------------------- int @@ -6294,13 +6289,11 @@ rrc_eNB_decode_ccch( } else { // no context available -#if defined(FLEXRAN_AGENT_SB_IF) if (rrc_agent_registered[ctxt_pP->module_id]) { agent_rrc_xface[ctxt_pP->module_id]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, ctxt_pP->rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); } -#endif LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Can't create new context for UE random UE identity (0x%" PRIx64 ")\n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), random_value); @@ -6562,14 +6555,12 @@ rrc_eNB_decode_dcch( ue_context_p, ul_dcch_msg->message.choice.c1.choice.rrcConnectionReconfigurationComplete.rrc_TransactionIdentifier); -#if defined(FLEXRAN_AGENT_SB_IF) //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future if (rrc_agent_registered[ctxt_pP->module_id]) { agent_rrc_xface[ctxt_pP->eNB_index]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, ue_context_p->ue_id_rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_UPDATED); } -#endif } #if defined(ENABLE_ITTI) # if defined(ENABLE_USE_MME) @@ -6704,14 +6695,12 @@ if (ue_context_p->ue_context.nb_of_modify_e_rabs > 0) { ul_dcch_msg->message.choice.c1.choice.rrcConnectionReestablishmentComplete.rrc_TransactionIdentifier, &ul_dcch_msg->message.choice.c1.choice.rrcConnectionReestablishmentComplete.criticalExtensions.choice.rrcConnectionReestablishmentComplete_r8); -#if defined(FLEXRAN_AGENT_SB_IF) //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future if (mac_agent_registered[ctxt_pP->module_id]) { agent_rrc_xface[ctxt_pP->eNB_index]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, ue_context_p->ue_id_rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_ACTIVATED); } -#endif } //ue_context_p->ue_context.ue_release_timer = 0; ue_context_p->ue_context.ue_reestablishment_timer = 1; @@ -6761,14 +6750,12 @@ if (ue_context_p->ue_context.nb_of_modify_e_rabs > 0) { LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_CONNECTED \n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); -#if defined(FLEXRAN_AGENT_SB_IF) //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future if (rrc_agent_registered[ctxt_pP->module_id]) { agent_rrc_xface[ctxt_pP->eNB_index]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, ue_context_p->ue_id_rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_ACTIVATED); } -#endif } } diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 42a4a7c950..f6789086b4 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1319,12 +1319,11 @@ int main( int argc, char **argv ) } #endif -#ifdef FLEXRAN_AGENT_SB_IF + /* Start the agent. If it is turned off in the configuration, it won't start */ RCconfig_flexran(); for (i = 0; i < RC.nb_L1_inst; i++) { flexran_agent_start(i); } -#endif // init UE_PF_PO and mutex lock pthread_mutex_init(&ue_pf_po_mutex, NULL); diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index d8f6e3c7e9..5cc4d5fea2 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -31,6 +31,8 @@ #include "PHY/defs.h" #include "SIMULATION/ETH_TRANSPORT/proto.h" +#include "flexran_agent.h" + #if defined(ENABLE_ITTI) #if defined(ENABLE_USE_MME) #include "s1ap_eNB.h" @@ -271,8 +273,4 @@ void init_eNB_afterRU(void); extern int stop_L1L2(module_id_t enb_id); extern int restart_L1L2(module_id_t enb_id); -#ifdef FLEXRAN_AGENT_SB_IF -#include "flexran_agent.h" -#endif - #endif diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index 7d8b33f12c..302b77b60f 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -76,9 +76,7 @@ uint8_t config_smbv = 0; char smbv_ip[16]; #endif -#if defined(FLEXRAN_AGENT_SB_IF) -# include "flexran_agent.h" -#endif +#include "flexran_agent.h" #include "oaisim_functions.h" From 219b5bc92f25bca7203ac42bc3203381170cb50b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 12 Feb 2018 15:11:19 +0100 Subject: [PATCH 226/284] make FlexRAN Agent activation configurable --- openair2/ENB_APP/enb_config.c | 7 ++----- openair2/ENB_APP/enb_paramdef.h | 13 ++++++++----- openair2/ENB_APP/flexran_agent.c | 6 ++++++ openair2/ENB_APP/flexran_agent_defs.h | 1 + 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index 1bf2807e81..a30dc28c94 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -119,19 +119,16 @@ void RCconfig_flexran() AssertFatal(RC.flexran[i] != NULL, "can't ALLOCATE %zu Bytes for flexran agent info (iteration %d/%d)\n", sizeof(flexran_agent_info_t), i + 1, RC.nb_L1_inst); + /* if config says "yes", enable Agent, in all other cases it's like "no" */ + RC.flexran[i]->enabled = strcmp(*(flexranParams[FLEXRAN_ENABLED].strptr), "yes") == 0; RC.flexran[i]->interface_name = strdup(*(flexranParams[FLEXRAN_INTERFACE_NAME_IDX].strptr)); //inet_ntop(AF_INET, &(enb_properties->properties[mod_id]->flexran_agent_ipv4_address), in_ip, INET_ADDRSTRLEN); - //strcpy(in_ip, DEFAULT_FLEXRAN_AGENT_IPv4_ADDRESS ); RC.flexran[i]->remote_ipv4_addr = strdup(*(flexranParams[FLEXRAN_IPV4_ADDRESS_IDX].strptr)); - // DEFAULT_FLEXRAN_AGENT_PORT RC.flexran[i]->remote_port = *(flexranParams[FLEXRAN_PORT_IDX].uptr); - // DEFAULT_FLEXRAN_AGENT_CACHE RC.flexran[i]->cache_name = strdup(*(flexranParams[FLEXRAN_CACHE_IDX].strptr)); RC.flexran[i]->node_ctrl_state = strcmp(*(flexranParams[FLEXRAN_AWAIT_RECONF_IDX].strptr), "yes") == 0 ? ENB_WAIT : ENB_NORMAL_OPERATION; RC.flexran[i]->enb_id = i; } - - /* TODO: show FlexRAN config now? */ } void RCconfig_L1(void) { diff --git a/openair2/ENB_APP/enb_paramdef.h b/openair2/ENB_APP/enb_paramdef.h index 0203380314..2d65e09b58 100755 --- a/openair2/ENB_APP/enb_paramdef.h +++ b/openair2/ENB_APP/enb_paramdef.h @@ -613,19 +613,22 @@ static int DEFENBS[] = {0}; /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ #define CONFIG_STRING_NETWORK_CONTROLLER_CONFIG "NETWORK_CONTROLLER" +#define CONFIG_STRING_FLEXRAN_ENABLED "FLEXRAN_ENABLED" #define CONFIG_STRING_FLEXRAN_INTERFACE_NAME "FLEXRAN_INTERFACE_NAME" #define CONFIG_STRING_FLEXRAN_IPV4_ADDRESS "FLEXRAN_IPV4_ADDRESS" #define CONFIG_STRING_FLEXRAN_PORT "FLEXRAN_PORT" #define CONFIG_STRING_FLEXRAN_CACHE "FLEXRAN_CACHE" #define CONFIG_STRING_FLEXRAN_AWAIT_RECONF "FLEXRAN_AWAIT_RECONF" -#define FLEXRAN_INTERFACE_NAME_IDX 0 -#define FLEXRAN_IPV4_ADDRESS_IDX 1 -#define FLEXRAN_PORT_IDX 2 -#define FLEXRAN_CACHE_IDX 3 -#define FLEXRAN_AWAIT_RECONF_IDX 4 +#define FLEXRAN_ENABLED 0 +#define FLEXRAN_INTERFACE_NAME_IDX 1 +#define FLEXRAN_IPV4_ADDRESS_IDX 2 +#define FLEXRAN_PORT_IDX 3 +#define FLEXRAN_CACHE_IDX 4 +#define FLEXRAN_AWAIT_RECONF_IDX 5 #define FLEXRANPARAMS_DESC { \ +{CONFIG_STRING_FLEXRAN_ENABLED, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \ {CONFIG_STRING_FLEXRAN_INTERFACE_NAME, NULL, 0, strptr:NULL, defstrval:"lo", TYPE_STRING, 0}, \ {CONFIG_STRING_FLEXRAN_IPV4_ADDRESS, NULL, 0, strptr:NULL, defstrval:"127.0.0.1", TYPE_STRING, 0}, \ {CONFIG_STRING_FLEXRAN_PORT, NULL, 0, uptr:NULL, defintval:2210, TYPE_UINT, 0}, \ diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c index d32f3e660f..bd46ecc49d 100644 --- a/openair2/ENB_APP/flexran_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -184,6 +184,12 @@ int flexran_agent_start(mid_t mod_id) int channel_id; char *in_ip = flexran->remote_ipv4_addr; uint16_t in_port = flexran->remote_port; + + /* if this agent is disabled, return and don't do anything */ + if (!flexran->enabled) { + LOG_I(FLEXRAN_AGENT, "FlexRAN Agent for eNB %d is DISABLED\n", mod_id); + return 100; + } flexran->enb_id = mod_id; /* assume for the moment the monolithic case, i.e. agent can provide diff --git a/openair2/ENB_APP/flexran_agent_defs.h b/openair2/ENB_APP/flexran_agent_defs.h index fd22b01e61..6364bc6281 100644 --- a/openair2/ENB_APP/flexran_agent_defs.h +++ b/openair2/ENB_APP/flexran_agent_defs.h @@ -153,6 +153,7 @@ typedef enum { typedef struct { /* general info */ + int enabled; char *interface_name; char *remote_ipv4_addr; uint16_t remote_port; From 1056604b25eb8ba2e0469842818d1a8dc26e1b72 Mon Sep 17 00:00:00 2001 From: Emad Date: Mon, 12 Feb 2018 13:56:08 +0100 Subject: [PATCH 227/284] I tried to change rx and tx attenuation by the config file, but they are not changed. The bug is because att_rx and att_tx do not put in RC.rru when local_rf is "yes" in config file. We need to put att_rx and att_rx for both local_rf = "yes" and "no". Also RF config which send to RF device must be fill by this parameters. --- targets/RT/USER/lte-ru.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 65d945dd7e..d2455266ce 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -1273,8 +1273,8 @@ void fill_rf_config(RU_t *ru, char *rf_config_file) { cfg->tx_freq[i] = (double)fp->dl_CarrierFreq; cfg->rx_freq[i] = (double)fp->ul_CarrierFreq; - cfg->tx_gain[i] = (double)fp->att_tx; - cfg->rx_gain[i] = ru->max_rxgain-(double)fp->att_rx; + cfg->tx_gain[i] = ru->att_tx; + cfg->rx_gain[i] = ru->max_rxgain-ru->att_rx; cfg->configFilename = rf_config_file; printf("channel %d, Setting tx_gain offset %f, rx_gain offset %f, tx_freq %f, rx_freq %f\n", @@ -2256,13 +2256,13 @@ void RCconfig_RU(void) { RC.ru[j]->if_timing = synch_to_other; RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF5_MOBIPASS; } - RC.ru[j]->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); - RC.ru[j]->att_rx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); } /* strcmp(local_rf, "yes") != 0 */ RC.ru[j]->nb_tx = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr); RC.ru[j]->nb_rx = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr); + RC.ru[j]->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); + RC.ru[j]->att_rx = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr); }// j=0..num_rus } else { RC.nb_RU = 0; From 135b06ae66ab485a1cd0ca7945a57e3a6675f664 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 12 Feb 2018 15:21:02 +0100 Subject: [PATCH 228/284] bugfix: only send eNB stats to controller if agent enabled --- openair2/LAYER2/MAC/eNB_scheduler.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 45c1a422dd..fb4fd6553b 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -657,7 +657,8 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frameP, // This schedules DLSCH in subframeP schedule_dlsch(module_idP, frameP, subframeP, mbsfn_status); - flexran_agent_send_update_stats(module_idP); + if (RC.flexran[module_idP]->enabled) + flexran_agent_send_update_stats(module_idP); // Allocate CCEs for good after scheduling is done for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) From 54e803e71a3647f3e109e74cf75de9cc01eed8d3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 12 Feb 2018 15:21:44 +0100 Subject: [PATCH 229/284] Sample configuration FlexRAN: Agent is disabled --- .../GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf index 227decbcd6..c4307f8ff2 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf @@ -191,6 +191,7 @@ RUs = ( NETWORK_CONTROLLER : { + FLEXRAN_ENABLED = "no"; FLEXRAN_INTERFACE_NAME = "lo"; FLEXRAN_IPV4_ADDRESS = "127.0.0.1"; FLEXRAN_PORT = 2210; From 6210eb056f880a52edfe9de64c6839154a5c7429 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 12 Feb 2018 15:26:45 +0100 Subject: [PATCH 230/284] bugfix: fix ue_ip.ko compilation Not sure that the use of __KERNEL__ is the correct solution. To be checked at some point. After this commit, the following works: ./build_oai --UE -c --- cmake_targets/CMakeLists.txt | 2 +- common/utils/itti/itti_types.h | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 616adf3a82..31b3f8e4c7 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -2297,7 +2297,7 @@ add_custom_command ( # retrieve the compiler options to send it to gccxml get_directory_property(DirDefs COMPILE_DEFINITIONS ) foreach( d ${DirDefs} ) - set(module_cc_opt_tmp "${module_cc_opt_tmp} -D${d}") + set(module_cc_opt "${module_cc_opt} -D${d}") endforeach() get_directory_property( DirDefs INCLUDE_DIRECTORIES ) foreach( d ${DirDefs} ) diff --git a/common/utils/itti/itti_types.h b/common/utils/itti/itti_types.h index d07853133b..2607c003b1 100644 --- a/common/utils/itti/itti_types.h +++ b/common/utils/itti/itti_types.h @@ -27,7 +27,18 @@ #ifndef _ITTI_TYPES_H_ #define _ITTI_TYPES_H_ -#include +/* The current file is included in the ue_ip.ko compilation. + * For it to work we need to include linux/types.h and + * not stdint.h. + * A solution to this problem is to use #ifndef __KERNEL__. + * Maybe a better solution would be to clean things up + * so that ue_ip.ko does not include the current file. + */ +#ifndef __KERNEL__ +# include +#else +# include +#endif #define CHARS_TO_UINT32(c1, c2, c3, c4) (((c4) << 24) | ((c3) << 16) | ((c2) << 8) | (c1)) From 4bf4ad8e98b4a9d920e165cf46c38ec4ddea3608 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 12 Feb 2018 15:30:30 +0100 Subject: [PATCH 231/284] change build scripts: always compile FlexRAN --- cmake_targets/CMakeLists.txt | 158 +++++++++++++++++------------------ cmake_targets/build_oai | 23 +---- 2 files changed, 81 insertions(+), 100 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 44d80d4633..56c3ea651b 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -599,8 +599,6 @@ add_boolean_option(MESSAGE_CHART_GENERATOR False "For generating sequenc add_boolean_option(MESSAGE_CHART_GENERATOR_RLC_MAC False "trace RLC-MAC exchanges in sequence diagrams") add_boolean_option(MESSAGE_CHART_GENERATOR_PHY False "trace some PHY exchanges in sequence diagrams") -add_boolean_option(FLEXRAN_AGENT_SB_IF False "enable FlexRAN agent to inteface with a SDN controller") - ######################## # Include order ########################## @@ -789,96 +787,94 @@ include_directories("${OPENAIR_DIR}") # Utilities Library ################ -if (FLEXRAN_AGENT_SB_IF) - # set the version of protobuf messages, V3 not supported yet - add_list1_option(FLPT_VERSION V2 "FLPT MSG protobuf grammar version" V2 V3) +# set the version of protobuf messages, V3 not supported yet +add_list1_option(FLPT_VERSION V2 "FLPT MSG protobuf grammar version" V2 V3) - if (${FLPT_VERSION} STREQUAL "V2") - set (FLPTDIR V2) - elseif (${FLPT_VERSION} STREQUAL "V3") - set (FLPTDIR V3) - endif(${FLPT_VERSION} STREQUAL "V2") +if (${FLPT_VERSION} STREQUAL "V2") + set (FLPTDIR V2) +elseif (${FLPT_VERSION} STREQUAL "V3") + set (FLPTDIR V3) +endif(${FLPT_VERSION} STREQUAL "V2") - set(FLPT_MSG_DIR ${OPENAIR2_DIR}/ENB_APP/MESSAGES/${FLPTDIR} ) - set(FLPT_MSG_FILES - ${FLPT_MSG_DIR}/header.proto - ${FLPT_MSG_DIR}/flexran.proto - ${FLPT_MSG_DIR}/stats_common.proto - ${FLPT_MSG_DIR}/stats_messages.proto - ${FLPT_MSG_DIR}/time_common.proto - ${FLPT_MSG_DIR}/controller_commands.proto - ${FLPT_MSG_DIR}/mac_primitives.proto - ${FLPT_MSG_DIR}/config_messages.proto - ${FLPT_MSG_DIR}/config_common.proto - ${FLPT_MSG_DIR}/control_delegation.proto - ) +set(FLPT_MSG_DIR ${OPENAIR2_DIR}/ENB_APP/MESSAGES/${FLPTDIR} ) +set(FLPT_MSG_FILES + ${FLPT_MSG_DIR}/header.proto + ${FLPT_MSG_DIR}/flexran.proto + ${FLPT_MSG_DIR}/stats_common.proto + ${FLPT_MSG_DIR}/stats_messages.proto + ${FLPT_MSG_DIR}/time_common.proto + ${FLPT_MSG_DIR}/controller_commands.proto + ${FLPT_MSG_DIR}/mac_primitives.proto + ${FLPT_MSG_DIR}/config_messages.proto + ${FLPT_MSG_DIR}/config_common.proto + ${FLPT_MSG_DIR}/control_delegation.proto + ) - set(FLPT_C_DIR ${protobuf_generated_dir}/${FLPTDIR}) - #message("calling protoc_call=${protoc_call} FLPT_C_DIR=${FLPT_C_DIR} FLPT_MSG_FILES=${FLPT_MSG_FILES}") - execute_process(COMMAND ${protoc_call} ${FLPT_C_DIR} ${FLPT_MSG_DIR} ${FLPT_MSG_FILES}) - file(GLOB FLPT_source ${FLPT_C_DIR}/*.c) - set(FLPT_OAI_generated - ${FLPT_C_DIR}/header.pb-c.c - ${FLPT_C_DIR}/flexran.pb-c.c - ${FLPT_C_DIR}/stats_common.pb-c.c - ${FLPT_C_DIR}/stats_messages.pb-c.c - ${FLPT_C_DIR}/time_common.pb-c.c - ${FLPT_C_DIR}/controller_commands.pb-c.c - ${FLPT_C_DIR}/mac_primitives.pb-c.c - ${FLPT_C_DIR}/config_messages.pb-c.c - ${FLPT_C_DIR}/config_common.pb-c.c - ${FLPT_C_DIR}/control_delegation.pb-c.c - ) +set(FLPT_C_DIR ${protobuf_generated_dir}/${FLPTDIR}) +#message("calling protoc_call=${protoc_call} FLPT_C_DIR=${FLPT_C_DIR} FLPT_MSG_FILES=${FLPT_MSG_FILES}") +execute_process(COMMAND ${protoc_call} ${FLPT_C_DIR} ${FLPT_MSG_DIR} ${FLPT_MSG_FILES}) +file(GLOB FLPT_source ${FLPT_C_DIR}/*.c) +set(FLPT_OAI_generated + ${FLPT_C_DIR}/header.pb-c.c + ${FLPT_C_DIR}/flexran.pb-c.c + ${FLPT_C_DIR}/stats_common.pb-c.c + ${FLPT_C_DIR}/stats_messages.pb-c.c + ${FLPT_C_DIR}/time_common.pb-c.c + ${FLPT_C_DIR}/controller_commands.pb-c.c + ${FLPT_C_DIR}/mac_primitives.pb-c.c + ${FLPT_C_DIR}/config_messages.pb-c.c + ${FLPT_C_DIR}/config_common.pb-c.c + ${FLPT_C_DIR}/control_delegation.pb-c.c + ) - file(GLOB flpt_h ${FLPT_C_DIR}/*.h) - set(flpt_h ${flpt_h} ) +file(GLOB flpt_h ${FLPT_C_DIR}/*.h) +set(flpt_h ${flpt_h} ) - add_library(FLPT_MSG - ${FLPT_OAI_generated} - ${FLPT_source} - ) - set(FLPT_MSG_LIB FLPT_MSG) - #message("prpt c dir is : ${FLPT_C_DIR}") - include_directories (${FLPT_C_DIR}) +add_library(FLPT_MSG + ${FLPT_OAI_generated} + ${FLPT_source} + ) +set(FLPT_MSG_LIB FLPT_MSG) +#message("prpt c dir is : ${FLPT_C_DIR}") +include_directories (${FLPT_C_DIR}) - add_library(ASYNC_IF - ${OPENAIR2_DIR}/UTIL/ASYNC_IF/socket_link.c - ${OPENAIR2_DIR}/UTIL/ASYNC_IF/link_manager.c - ${OPENAIR2_DIR}/UTIL/ASYNC_IF/message_queue.c - ${OPENAIR2_DIR}/UTIL/ASYNC_IF/ringbuffer_queue.c - ) - set(ASYNC_IF_LIB ASYNC_IF) - include_directories(${OPENAIR2_DIR}/UTIL/ASYNC_IF) +add_library(ASYNC_IF + ${OPENAIR2_DIR}/UTIL/ASYNC_IF/socket_link.c + ${OPENAIR2_DIR}/UTIL/ASYNC_IF/link_manager.c + ${OPENAIR2_DIR}/UTIL/ASYNC_IF/message_queue.c + ${OPENAIR2_DIR}/UTIL/ASYNC_IF/ringbuffer_queue.c + ) +set(ASYNC_IF_LIB ASYNC_IF) +include_directories(${OPENAIR2_DIR}/UTIL/ASYNC_IF) - add_library(FLEXRAN_AGENT - ${OPENAIR2_DIR}/ENB_APP/flexran_agent_handler.c - ${OPENAIR2_DIR}/ENB_APP/flexran_agent_common.c - ${OPENAIR2_DIR}/ENB_APP/flexran_agent_ran_api.c - ${OPENAIR2_DIR}/ENB_APP/flexran_agent_timer.c - ${OPENAIR2_DIR}/ENB_APP/flexran_agent_common_internal.c - ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c - ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c - ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c - ${OPENAIR2_DIR}/ENB_APP/flexran_agent.c - ${OPENAIR2_DIR}/ENB_APP/flexran_agent_task_manager.c - ${OPENAIR2_DIR}/ENB_APP/flexran_agent_net_comm.c - ${OPENAIR2_DIR}/ENB_APP/flexran_agent_async.c - ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c - ) - set(FLEXRAN_AGENT_LIB FLEXRAN_AGENT) - #include_directories(${OPENAIR2_DIR}/ENB_APP) +add_library(FLEXRAN_AGENT + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_handler.c + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_common.c + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_ran_api.c + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_timer.c + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_common_internal.c + ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c + ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c + ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c + ${OPENAIR2_DIR}/ENB_APP/flexran_agent.c + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_task_manager.c + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_net_comm.c + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_async.c + ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c + ) +set(FLEXRAN_AGENT_LIB FLEXRAN_AGENT) +#include_directories(${OPENAIR2_DIR}/ENB_APP) - set(PROTOBUF_LIB "protobuf-c") +set(PROTOBUF_LIB "protobuf-c") - FIND_PATH(LIBYAML_INCLUDE_DIR NAMES yaml.h) - FIND_LIBRARY(LIBYAML_LIBRARIES NAMES yaml libyaml) +FIND_PATH(LIBYAML_INCLUDE_DIR NAMES yaml.h) +FIND_LIBRARY(LIBYAML_LIBRARIES NAMES yaml libyaml) - INCLUDE(FindPackageHandleStandardArgs) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(Yaml DEFAULT_MSG LIBYAML_LIBRARIES LIBYAML_INCLUDE_DIR) - MARK_AS_ADVANCED(LIBYAML_INCLUDE_DIR LIBYAML_LIBRARIES) +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Yaml DEFAULT_MSG LIBYAML_LIBRARIES LIBYAML_INCLUDE_DIR) +MARK_AS_ADVANCED(LIBYAML_INCLUDE_DIR LIBYAML_LIBRARIES) - #set(PROTOBUF_LIB "protobuf") #for Cpp -endif() +#set(PROTOBUF_LIB "protobuf") #for Cpp add_library(HASHTABLE diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 0d48f51df9..7e0c0ca169 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -42,7 +42,6 @@ conf_nvram_path=$OPENAIR_DIR/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf MSC_GEN="False" XFORMS="True" -FLEXRAN_AGENT_SB_IF="True" PRINT_STATS="False" VCD_TIMING="False" DEADLINE_SCHEDULER_FLAG_USER="False" @@ -100,8 +99,6 @@ Options Specify conf_nvram_path (default \"$conf_nvram_path\") --UE-gen-nvram [output path] Specify gen_nvram_path (default \"$gen_nvram_path\") --a | --agent - Enables agent for software-defined control of the eNB -r | --3gpp-release default is Rel14, Rel8 limits the implementation to 3GPP Release 8 version @@ -204,8 +201,7 @@ function main() { echo_info "Will compile eNB" shift;; -a | --agent) - FLEXRAN_AGENT=1 - echo_info "Will compile eNB with agent support" + echo_info "FlexRAN support is always compiled into the eNB" shift;; --UE) UE=1 @@ -465,11 +461,9 @@ function main() { flash_firmware_bladerf fi fi - if [ "$FLEXRAN_AGENT" == "1" ] ; then - echo_info "installing protobuf/protobuf-c for flexran agent support" - install_protobuf_from_source - install_protobuf_c_from_source - fi + echo_info "installing protobuf/protobuf-c for flexran agent support" + install_protobuf_from_source + install_protobuf_c_from_source fi if [ "$INSTALL_OPTIONAL" = "1" ] ; then @@ -517,9 +511,6 @@ function main() { echo "set ( CMAKE_BUILD_TYPE $CMAKE_BUILD_TYPE )" >> $cmake_file echo "set ( CFLAGS_PROCESSOR_USER \"$CFLAGS_PROCESSOR_USER\" )" >> $cmake_file echo "set ( XFORMS $XFORMS )" >> $cmake_file - if [ "$FLEXRAN_AGENT" = "1" ] ; then - echo "set ( FLEXRAN_AGENT_SB_IF $FLEXRAN_AGENT_SB_IF )" >> $cmake_file - fi echo "set ( RRC_ASN1_VERSION \"${REL}\")" >> $cmake_file echo "set ( ENABLE_VCD_FIFO $VCD_TIMING )" >> $cmake_file echo "set ( RF_BOARD \"${HW}\")" >> $cmake_file @@ -679,9 +670,6 @@ function main() { echo "set ( CMAKE_BUILD_TYPE $CMAKE_BUILD_TYPE )" >> $cmake_file echo "set ( CFLAGS_PROCESSOR_USER \"$CFLAGS_PROCESSOR_USER\" )" >> $cmake_file echo "set ( XFORMS $XFORMS )" >> $cmake_file - if [ "$FLEXRAN_AGENT" = "1" ] ; then - echo "set ( FLEXRAN_AGENT_SB_IF $FLEXRAN_AGENT_SB_IF )" >> $cmake_file - fi echo "set ( PRINT_STATS $PRINT_STATS )" >> $cmake_file echo "set ( RRC_ASN1_VERSION \"${REL}\")" >> $cmake_file echo "set ( ENABLE_VCD_FIFO $VCD_TIMING )" >> $cmake_file @@ -762,9 +750,6 @@ function main() { cp $DIR/oaisim_mme_build_oai/CMakeLists.template $cmake_file echo "set ( CMAKE_BUILD_TYPE $CMAKE_BUILD_TYPE )" >> $cmake_file echo "set ( XFORMS $XFORMS )" >> $cmake_file - if [ "$FLEXRAN_AGENT" = "1" ] ; then - echo "set ( FLEXRAN_AGENT_SB_IF $FLEXRAN_AGENT_SB_IF )" >> $cmake_file - fi echo "set ( RRC_ASN1_VERSION \"${REL}\")" >> $cmake_file echo "set ( ENABLE_VCD_FIFO $VCD_TIMING )" >> $cmake_file echo "set ( T_TRACER $T_TRACER )" >> $cmake_file From ddd3e97f141917e7868a953b918915f6cdb11d94 Mon Sep 17 00:00:00 2001 From: Emad Date: Thu, 8 Feb 2018 07:54:47 +0100 Subject: [PATCH 232/284] srb_id must be between [1,3] --- openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 91621ab50f..bb264a8906 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -993,7 +993,7 @@ pdcp_remove_UE( } } - for (srb_id=0; srb_id<2; srb_id++) { + for (srb_id=1; srb_id<3; srb_id++) { key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, srb_id, SRB_FLAG_YES); h_rc = hashtable_remove(pdcp_coll_p, key); } From e794f920c73ff0d891ae8c3033027be9d649a2ab Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 12 Feb 2018 16:13:04 +0100 Subject: [PATCH 233/284] integration fix: remove definition of OAI_NW_DRIVER_USE_NETLINK in source file This is done better by commit 6210eb056f880a52edfe9de64c6839154a5c7429. --- openair2/NETWORK_DRIVER/UE_IP/local.h | 1 - 1 file changed, 1 deletion(-) diff --git a/openair2/NETWORK_DRIVER/UE_IP/local.h b/openair2/NETWORK_DRIVER/UE_IP/local.h index 15fa7a0f91..ac3b040995 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/local.h +++ b/openair2/NETWORK_DRIVER/UE_IP/local.h @@ -57,7 +57,6 @@ #include "platform_types.h" #include "sap.h" -#define OAI_NW_DRIVER_USE_NETLINK 1 typedef struct ue_ip_priv_s { int irq; From 5865c141d03a89aed04c8496cd2b260e1800b017 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Tue, 13 Feb 2018 11:45:16 +0100 Subject: [PATCH 234/284] Improve UL/DL MCS assignment --- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 8 ++++---- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 8 ++++---- openair2/LAYER2/MAC/pre_processor.c | 24 ++++++++++++----------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 0936a9d0ef..7d0a93c2bf 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -789,12 +789,12 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE); */ if (nfapi_mode) { - eNB_UE_stats->dlsch_mcs1 = 10;//cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]]; + eNB_UE_stats->dlsch_mcs1 = 10;//cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]]; } - else { - eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]]; + else { // this operation is also done in the preprocessor + eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, slice_maxmcs[slice_idP]); //cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); } - eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, slice_maxmcs[slice_idP]); //cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); + // store stats diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 47b6a075cf..a8d686dac9 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -1289,11 +1289,11 @@ schedule_ulsch_rnti(module_id_t module_idP, ndi = 1 - UE_template->oldNDI_UL[harq_pid]; UE_template->oldNDI_UL[harq_pid] = ndi; - UE_list->eNB_UE_stats[CC_id][UE_id]. - normalized_rx_power = normalized_rx_power; + UE_list->eNB_UE_stats[CC_id][UE_id].normalized_rx_power = normalized_rx_power; UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power = target_rx_power; - UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1 = UE_template->pre_assigned_mcs_ul; - UE_template->mcs_UL[harq_pid] = cmin(UE_template->pre_assigned_mcs_ul, slice_maxmcs_uplink[slice_id]);//cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS + UE_template->mcs_UL[harq_pid] = cmin(UE_template->pre_assigned_mcs_ul, slice_maxmcs_uplink[slice_id]); + UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1= UE_template->mcs_UL[harq_pid]; + //cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS if (UE_template->pre_allocated_rb_table_index_ul >= 0) { rb_table_index = UE_template->pre_allocated_rb_table_index_ul; } else { diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index c179c211b2..3a27f70009 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -60,6 +60,10 @@ extern float slice_percentage[MAX_NUM_SLICES]; extern float slice_percentage_uplink[MAX_NUM_SLICES]; +extern int slice_maxmcs[MAX_NUM_SLICES]; +extern int slice_maxmcs_uplink[MAX_NUM_SLICES]; + + //#define ICIC 0 /* this function checks that get_eNB_UE_stats returns @@ -211,8 +215,8 @@ assign_rbs_required(module_id_t Mod_id, CC_id = UE_list->ordered_CCids[n][UE_id]; eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; - eNB_UE_stats->dlsch_mcs1 = - cqi_to_mcs[UE_list->UE_sched_ctrl[UE_id].dl_cqi[CC_id]]; + eNB_UE_stats->dlsch_mcs1 =cmin(cqi_to_mcs[UE_list->UE_sched_ctrl[UE_id].dl_cqi[CC_id]], + slice_maxmcs[slice_id]); } @@ -1585,7 +1589,6 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, uint16_t n, UE_id; uint8_t CC_id; rnti_t rnti = -1; - int mcs; int rb_table_index = 0, tbs, tx_power; eNB_MAC_INST *eNB = RC.mac[module_idP]; UE_list_t *UE_list = &eNB->UE_list; @@ -1609,9 +1612,9 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, continue; if (UE_list->UE_sched_ctrl[i].phr_received == 1) - mcs = 20; // if we've received the power headroom information the UE, we can go to maximum mcs + UE_template->pre_assigned_mcs_ul = cmin(20, slice_maxmcs_uplink[slice_id]); // if we've received the power headroom information the UE, we can go to maximum mcs else - mcs = 10; // otherwise, limit to QPSK PUSCH + UE_template->pre_assigned_mcs_ul = cmin(10, slice_maxmcs_uplink[slice_id]); // otherwise, limit to QPSK PUSCH UE_id = i; @@ -1642,7 +1645,7 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, // if this UE has UL traffic if (bits_to_schedule > 0) { - tbs = get_TBS_UL(mcs, 3) << 3; // 1 or 2 PRB with cqi enabled does not work well! + tbs = get_TBS_UL(UE_template->pre_assigned_mcs_ul, 3) << 3; // 1 or 2 PRB with cqi enabled does not work well! rb_table_index = 2; // fixme: set use_srs flag @@ -1650,10 +1653,10 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, while ((((UE_template->phr_info - tx_power) < 0) || (tbs > bits_to_schedule)) - && (mcs > 3)) { + && (UE_template->pre_assigned_mcs_ul > 3)) { // LOG_I(MAC,"UE_template->phr_info %d tx_power %d mcs %d\n", UE_template->phr_info,tx_power, mcs); - mcs--; - tbs = get_TBS_UL(mcs, rb_table[rb_table_index]) << 3; + UE_template->pre_assigned_mcs_ul--; + tbs = get_TBS_UL(UE_template->pre_assigned_mcs_ul, rb_table[rb_table_index]) << 3; tx_power = estimate_ue_tx_power(tbs, rb_table[rb_table_index], 0, Ncp, 0); // fixme: set use_srs } @@ -1662,7 +1665,7 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, && ((UE_template->phr_info - tx_power) > 0) && (rb_table_index < 32)) { rb_table_index++; - tbs = get_TBS_UL(mcs, rb_table[rb_table_index]) << 3; + tbs = get_TBS_UL(UE_template->pre_assigned_mcs_ul, rb_table[rb_table_index]) << 3; tx_power = estimate_ue_tx_power(tbs, rb_table[rb_table_index], 0, Ncp, 0); } @@ -1676,7 +1679,6 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, rb_table_index = 2; //3PRB } - UE_template->pre_assigned_mcs_ul = mcs; UE_template->pre_allocated_rb_table_index_ul = rb_table_index; UE_template->pre_allocated_nb_rb_ul[slice_id] = rb_table[rb_table_index]; LOG_D(MAC, From a68d70a13d2768fdfb6eb6614d403eccde48e0c4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 13 Feb 2018 14:23:54 +0100 Subject: [PATCH 235/284] bugfix: prevent segfault in pre_processor.c --- openair2/LAYER2/MAC/pre_processor.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 3a27f70009..8f7a6bddff 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -1589,6 +1589,7 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, uint16_t n, UE_id; uint8_t CC_id; rnti_t rnti = -1; + int mcs; int rb_table_index = 0, tbs, tx_power; eNB_MAC_INST *eNB = RC.mac[module_idP]; UE_list_t *UE_list = &eNB->UE_list; @@ -1611,10 +1612,14 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, if (!ue_slice_membership(i, slice_id)) continue; - if (UE_list->UE_sched_ctrl[i].phr_received == 1) - UE_template->pre_assigned_mcs_ul = cmin(20, slice_maxmcs_uplink[slice_id]); // if we've received the power headroom information the UE, we can go to maximum mcs - else - UE_template->pre_assigned_mcs_ul = cmin(10, slice_maxmcs_uplink[slice_id]); // otherwise, limit to QPSK PUSCH + if (UE_list->UE_sched_ctrl[i].phr_received == 1) { + /* if we've received the power headroom information the UE, we can go to + * maximum mcs */ + mcs = cmin(20, slice_maxmcs_uplink[slice_id]); + } else { + /* otherwise, limit to QPSK PUSCH */ + mcs = cmin(10, slice_maxmcs_uplink[slice_id]); + } UE_id = i; @@ -1633,6 +1638,7 @@ assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, UE_list->numactiveULCCs[UE_id]); UE_template = &UE_list->UE_template[CC_id][UE_id]; + UE_template->pre_assigned_mcs_ul = mcs; ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; Ncp = RC.mac[module_idP]->common_channels[CC_id].Ncp; From c33e184ddeee3f80de691146e8dbd3a8b27cf210 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 13 Feb 2018 14:25:50 +0100 Subject: [PATCH 236/284] bugfix: selectively inform FlexRAN RTController of UE state change --- openair2/LAYER2/MAC/eNB_scheduler.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index fb4fd6553b..a7c79a70d5 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -413,15 +413,16 @@ check_ul_failure(module_id_t module_idP, int CC_id, int UE_id, mac_eNB_rrc_ul_failure(module_idP, CC_id, frameP, subframeP,rnti); UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 1; + + //Inform the controller about the UE deactivation. Should be moved to RRC agent in the future + if (rrc_agent_registered[module_idP]) { + LOG_W(MAC, "notify flexran Agent of UE state change\n"); + agent_rrc_xface[module_idP]->flexran_agent_notify_ue_state_change(module_idP, + rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); + } } } // ul_failure_timer>0 - //Inform the controller about the UE deactivation. Should be moved to RRC agent in the future - if (rrc_agent_registered[module_idP]) { - agent_rrc_xface[module_idP]->flexran_agent_notify_ue_state_change(module_idP, - rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); - } - UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer++; if(UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer > (U_PLANE_INACTIVITY_VALUE*subframe_num(&RC.eNB[module_idP][CC_id]->frame_parms))){ LOG_D(MAC,"UE %d rnti %x: U-Plane Failure after repeated PDCCH orders: Triggering RRC \n",UE_id,rnti); From 12ac8b180da8f919dc2d2d7105bade4561be235d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 12 Feb 2018 18:34:56 +0100 Subject: [PATCH 237/284] prevent warnings: init Protocol__FlexHeader to NULL --- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 8 ++++---- .../MAC/flexran_agent_mac_internal.c | 2 +- .../CONTROL_MODULES/RRC/flexran_agent_rrc.c | 4 ++-- openair2/ENB_APP/flexran_agent_common.c | 14 +++++++------- openair2/ENB_APP/flexran_agent_handler.c | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index f875264967..230917f673 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -670,7 +670,7 @@ int flexran_agent_mac_destroy_stats_reply(Protocol__FlexranMessage *msg) { } int flexran_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { - Protocol__FlexHeader *header; + Protocol__FlexHeader *header = NULL; int i; const int xid = *((int *)params); @@ -738,7 +738,7 @@ int flexran_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg) { } int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { - Protocol__FlexHeader *header; + Protocol__FlexHeader *header = NULL; int i, j, UE_id; int available_harq[NUMBER_OF_UE_MAX]; @@ -954,7 +954,7 @@ int flexran_agent_mac_destroy_sf_trigger(Protocol__FlexranMessage *msg) { int flexran_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__FlexranMessage **msg) { int xid = 0; - Protocol__FlexHeader *header; + Protocol__FlexHeader *header = NULL; if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_DL_MAC_CONFIG, &header) != 0) goto error; @@ -1049,7 +1049,7 @@ int flexran_agent_mac_destroy_dl_config(Protocol__FlexranMessage *msg) { int flexran_agent_mac_create_empty_ul_config(mid_t mod_id, Protocol__FlexranMessage **msg) { int xid = 0; - Protocol__FlexHeader *header; + Protocol__FlexHeader *header = NULL; if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_UL_MAC_CONFIG, &header) != 0) goto error; diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c index b7a93b8491..2acee0686f 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c @@ -101,7 +101,7 @@ Protocol__FlexranMessage * flexran_agent_generate_diff_mac_stats_report(Protocol if (n_cell_report > 0 || n_ue_report > 0) { /*Create header*/ int xid = old_report->header->xid; - Protocol__FlexHeader *header; + Protocol__FlexHeader *header = NULL; if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) { goto error; } diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c index 590e9c870f..e88c4eaccf 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c @@ -45,8 +45,8 @@ AGENT_RRC_xface *agent_rrc_xface[NUM_MAX_ENB]; void flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { int size; - Protocol__FlexranMessage *msg; - Protocol__FlexHeader *header; + Protocol__FlexranMessage *msg = NULL; + Protocol__FlexHeader *header = NULL; void *data; int priority = 0; err_code_t err_code; diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index f837d575d5..2df5959815 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -106,7 +106,7 @@ int flexran_create_header(xid_t xid, Protocol__FlexType type, Protocol__FlexHea int flexran_agent_hello(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { - Protocol__FlexHeader *header; + Protocol__FlexHeader *header = NULL; /*TODO: Need to set random xid or xid from received hello message*/ xid_t xid = 1; @@ -161,7 +161,7 @@ int flexran_agent_destroy_hello(Protocol__FlexranMessage *msg) { int flexran_agent_echo_request(mid_t mod_id, const void* params, Protocol__FlexranMessage **msg) { - Protocol__FlexHeader *header; + Protocol__FlexHeader *header = NULL; /*TODO: Need to set a random xid*/ xid_t xid = 1; @@ -216,6 +216,7 @@ int flexran_agent_destroy_echo_request(Protocol__FlexranMessage *msg) { int flexran_agent_echo_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { xid_t xid; + Protocol__FlexHeader *header = NULL; Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; Protocol__FlexEchoRequest *echo_req = input->echo_request_msg; xid = (echo_req->header)->xid; @@ -226,7 +227,6 @@ int flexran_agent_echo_reply(mid_t mod_id, const void *params, Protocol__Flexran goto error; protocol__flex_echo_reply__init(echo_reply_msg); - Protocol__FlexHeader *header; if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_ECHO_REPLY, &header) != 0) goto error; @@ -429,6 +429,7 @@ int flexran_agent_destroy_agent_reconfiguration(Protocol__FlexranMessage *msg) { int flexran_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { xid_t xid; + Protocol__FlexHeader *header = NULL; Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; Protocol__FlexLcConfigRequest *lc_config_request_msg = input->lc_config_request_msg; xid = (lc_config_request_msg->header)->xid; @@ -441,7 +442,6 @@ int flexran_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Fl goto error; protocol__flex_lc_config_reply__init(lc_config_reply_msg); - Protocol__FlexHeader *header; if(flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_GET_LC_CONFIG_REPLY, &header) != 0) goto error; @@ -557,6 +557,7 @@ int flexran_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Fl int flexran_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { xid_t xid; + Protocol__FlexHeader *header = NULL; Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; Protocol__FlexUeConfigRequest *ue_config_request_msg = input->ue_config_request_msg; xid = (ue_config_request_msg->header)->xid; @@ -569,7 +570,6 @@ int flexran_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Fl goto error; protocol__flex_ue_config_reply__init(ue_config_reply_msg); - Protocol__FlexHeader *header; if(flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_GET_UE_CONFIG_REPLY, &header) != 0) goto error; @@ -762,7 +762,7 @@ int flexran_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Fl int flexran_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__FlexranMessage **msg) { - Protocol__FlexHeader *header; + Protocol__FlexHeader *header = NULL; xid_t xid = 1; Protocol__FlexEnbConfigRequest *enb_config_request_msg; @@ -801,6 +801,7 @@ int flexran_agent_enb_config_request(mid_t mod_id, const void* params, Protocol_ int flexran_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { xid_t xid; + Protocol__FlexHeader *header = NULL; Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; Protocol__FlexEnbConfigRequest *enb_config_req_msg = input->enb_config_request_msg; xid = (enb_config_req_msg->header)->xid; @@ -814,7 +815,6 @@ int flexran_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__F goto error; protocol__flex_enb_config_reply__init(enb_config_reply_msg); - Protocol__FlexHeader *header; if(flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_GET_ENB_CONFIG_REPLY, &header) != 0) goto error; diff --git a/openair2/ENB_APP/flexran_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c index 3597463ae3..6c20c635a1 100644 --- a/openair2/ENB_APP/flexran_agent_handler.c +++ b/openair2/ENB_APP/flexran_agent_handler.c @@ -393,7 +393,7 @@ int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__Flexr int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg){ - Protocol__FlexHeader *header; + Protocol__FlexHeader *header = NULL; err_code_t err_code; int i; @@ -514,7 +514,7 @@ int flexran_agent_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg) { - Protocol__FlexHeader *header; + Protocol__FlexHeader *header = NULL; int i; Protocol__FlexStatsRequest *stats_request_msg; From 22742a4c9c771441dd4d3de8c635584421d53092 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 13 Feb 2018 15:30:39 +0100 Subject: [PATCH 238/284] hack: get oaisim to compile on Ubuntu 17.10 The following did not work before this commit on ubuntu 17.10: ./build_oai --oaisim -c oaisim has not been tested. It may fail to work. To be tested. --- cmake_targets/CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 8d62652556..3bfc2d54ee 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1880,6 +1880,16 @@ if(EXISTS "/usr/include/atlas/cblas.h" OR EXISTS "/usr/include/cblas.h") endif() list(APPEND ATLAS_LIBRARIES lapack) + +# for ubuntu 17.10, directories are different +elseif(EXISTS "/usr/include/x86_64-linux-gnu/cblas.h") + + include_directories("/usr/include/x86_64-linux-gnu") + LINK_DIRECTORIES("/usr/lib/x86_64-linux-gnu") + list(APPEND ATLAS_LIBRARIES cblas) + list(APPEND ATLAS_LIBRARIES atlas) + list(APPEND ATLAS_LIBRARIES lapack) + else() message("No Blas/Atlas libs found, some targets will fail") endif() From e9d536972c18dae7bbbccd132b234ceccd6146de Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Tue, 13 Feb 2018 07:18:52 -0800 Subject: [PATCH 239/284] updated dlsim to FAPI interfaces --- cmake_targets/CMakeLists.txt | 3 +- openair1/PHY/CODING/crc_byte.c | 3 +- openair1/PHY/INIT/defs.h | 21 +- openair1/PHY/INIT/lte_param_init.c | 49 +- openair1/PHY/LTE_TRANSPORT/dci.c | 41 +- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 53 +- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 3 +- openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c | 6 + .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 14 +- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 1 + openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c | 13 +- openair1/PHY/LTE_TRANSPORT/power_control.c | 32 +- openair1/PHY/LTE_TRANSPORT/proto.h | 10 +- openair1/PHY/vars.h | 1 + openair1/SCHED/fapi_l1.c | 13 +- openair1/SCHED/phy_procedures_lte_eNb.c | 8 +- openair1/SCHED/phy_procedures_lte_ue.c | 13 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 1636 ++++------------- openair2/LAYER2/MAC/defs.h | 2 +- 19 files changed, 582 insertions(+), 1340 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 616adf3a82..c530eaaaab 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -2157,11 +2157,12 @@ foreach(myExe dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim pr ${OPENAIR1_DIR}/SIMULATION/LTE_PHY/${myExe}.c ${XFORMS_SOURCE} ${T_SOURCE} + ${CONFIG_SOURCES} ) target_link_libraries (${myExe} -Wl,--start-group SIMU UTIL SCHED_LIB PHY LFDS ${ITTI_LIB} LFDS7 -Wl,--end-group - pthread m rt ${CONFIG_LIBRARIES} ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${T_LIB} + pthread m rt ${CONFIG_LIBRARIES} ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${T_LIB} dl ) endforeach(myExe) diff --git a/openair1/PHY/CODING/crc_byte.c b/openair1/PHY/CODING/crc_byte.c index 5ec4fcaaa4..21427de19b 100644 --- a/openair1/PHY/CODING/crc_byte.c +++ b/openair1/PHY/CODING/crc_byte.c @@ -109,7 +109,7 @@ crc24a (unsigned char * inptr, int bitlen) resbit = (bitlen % 8); while (octetlen-- > 0) { - // printf("in %x => crc %x\n",crc,*inptr); + // printf("crc24a: in %x => crc %x\n",crc,*inptr); crc = (crc << 8) ^ crc24aTable[(*inptr++) ^ (crc >> 24)]; } @@ -128,6 +128,7 @@ unsigned int crc24b (unsigned char * inptr, int bitlen) resbit = (bitlen % 8); while (octetlen-- > 0) { + // printf("crc24b: in %x => crc %x (%x)\n",crc,*inptr,crc24bTable[(*inptr) ^ (crc >> 24)]); crc = (crc << 8) ^ crc24bTable[(*inptr++) ^ (crc >> 24)]; } diff --git a/openair1/PHY/INIT/defs.h b/openair1/PHY/INIT/defs.h index 744fb3d3ce..d23f342d18 100644 --- a/openair1/PHY/INIT/defs.h +++ b/openair1/PHY/INIT/defs.h @@ -322,8 +322,11 @@ void init_lte_top(LTE_DL_FRAME_PARMS *lte_frame_parms); //void copy_lte_parms_to_phy_framing(LTE_DL_FRAME_PARMS *frame_parm, PHY_FRAMING *phy_framing); -void lte_param_init(unsigned char N_tx_port_eNB, - unsigned char N_tx, +void lte_param_init(PHY_VARS_eNB **eNBp, + PHY_VARS_UE **UEp, + RU_t **rup, + unsigned char N_tx_port_eNB, + unsigned char N_tx_phy, unsigned char N_rx, unsigned char transmission_mode, uint8_t extended_prefix_flag, @@ -331,10 +334,12 @@ void lte_param_init(unsigned char N_tx_port_eNB, uint16_t Nid_cell, uint8_t tdd_config, uint8_t N_RB_DL, + uint8_t pa, uint8_t threequarter_fs, uint8_t osf, uint32_t perfect_ce); + #if defined(Rel10) || defined(Rel14) void phy_config_dedicated_scell_ue(uint8_t Mod_id, uint8_t eNB_index, @@ -359,18 +364,6 @@ void phy_config_request(PHY_Config_t *phy_config); int init_frame_parms(LTE_DL_FRAME_PARMS *frame_parms,uint8_t osf); void dump_frame_parms(LTE_DL_FRAME_PARMS *frame_parms); -void lte_param_init(unsigned char N_tx_port_eNB, - unsigned char N_tx_phy, - unsigned char N_rx, - unsigned char transmission_mode, - uint8_t extended_prefix_flag, - frame_t frame_type, - uint16_t Nid_cell, - uint8_t tdd_config, - uint8_t N_RB_DL, - uint8_t threequarter_fs, - uint8_t osf, - uint32_t perfect_ce); /** @} */ #endif diff --git a/openair1/PHY/INIT/lte_param_init.c b/openair1/PHY/INIT/lte_param_init.c index d510fc7261..90b7bcee31 100644 --- a/openair1/PHY/INIT/lte_param_init.c +++ b/openair1/PHY/INIT/lte_param_init.c @@ -32,8 +32,12 @@ extern PHY_VARS_eNB *eNB; extern PHY_VARS_UE *UE; +extern RU_t *ru; -void lte_param_init(unsigned char N_tx_port_eNB, +void lte_param_init(PHY_VARS_eNB **eNBp, + PHY_VARS_UE **UEp, + RU_t **rup, + unsigned char N_tx_port_eNB, unsigned char N_tx_phy, unsigned char N_rx, unsigned char transmission_mode, @@ -42,6 +46,7 @@ void lte_param_init(unsigned char N_tx_port_eNB, uint16_t Nid_cell, uint8_t tdd_config, uint8_t N_RB_DL, + uint8_t pa, uint8_t threequarter_fs, uint8_t osf, uint32_t perfect_ce) @@ -49,13 +54,27 @@ void lte_param_init(unsigned char N_tx_port_eNB, LTE_DL_FRAME_PARMS *frame_parms; int i; - + PHY_VARS_eNB *eNB; + PHY_VARS_UE *UE; + RU_t *ru; printf("Start lte_param_init\n"); - eNB = malloc(sizeof(PHY_VARS_eNB)); - UE = malloc(sizeof(PHY_VARS_UE)); + *eNBp = malloc(sizeof(PHY_VARS_eNB)); + *UEp = malloc(sizeof(PHY_VARS_UE)); + *rup = malloc(sizeof(RU_t)); + eNB = *eNBp; + UE = *UEp; + ru = *rup; + printf("eNB %p, UE %p, ru %p\n",eNB,UE,ru); + + + memset((void*)eNB,0,sizeof(PHY_VARS_eNB)); memset((void*)UE,0,sizeof(PHY_VARS_UE)); + memset((void*)ru,0,sizeof(RU_t)); + ru->eNB_list[0] = eNB; + eNB->RU_list[0] = ru; + ru->num_eNB=1; srand(0); randominit(0); @@ -90,12 +109,17 @@ void lte_param_init(unsigned char N_tx_port_eNB, UE->is_secondary_ue = 0; UE->frame_parms = *frame_parms; - eNB->frame_parms = *frame_parms; + // eNB->frame_parms = *frame_parms; + ru->frame_parms = *frame_parms; + ru->nb_tx = N_tx_phy; + ru->nb_rx = 1; + ru->if_south = LOCAL_RF; + + eNB->configured=1; eNB->transmission_mode[0] = transmission_mode; UE->transmission_mode[0] = transmission_mode; - init_lte_top(frame_parms); dump_frame_parms(frame_parms); UE->measurements.n_adj_cells=0; @@ -105,23 +129,24 @@ void lte_param_init(unsigned char N_tx_port_eNB, for (i=0; i<3; i++) lte_gold(frame_parms,UE->lte_gold_table[i],Nid_cell+i); - init_lte_ue(UE,1,0); + printf("Calling init_lte_ue_signal\n"); + init_lte_ue_signal(UE,1,0); + printf("Calling phy_init_lte_eNB\n"); phy_init_lte_eNB(eNB,0,0); - + printf("Calling phy_init_RU (%p)\n",ru); + phy_init_RU(ru); generate_pcfich_reg_mapping(&UE->frame_parms); generate_phich_reg_mapping(&UE->frame_parms); // DL power control init //if (transmission_mode == 1) { + UE->pdsch_config_dedicated->p_a = pa; + if (transmission_mode == 1 || transmission_mode ==7) { - eNB->pdsch_config_dedicated->p_a = dB0; // 4 = 0dB ((eNB->frame_parms).pdsch_config_common).p_b = 0; - UE->pdsch_config_dedicated->p_a = dB0; // 4 = 0dB ((UE->frame_parms).pdsch_config_common).p_b = 0; } else { // rho_a = rhob - eNB->pdsch_config_dedicated->p_a = dBm3; // 4 = 0dB ((eNB->frame_parms).pdsch_config_common).p_b = 1; - UE->pdsch_config_dedicated->p_a = dBm3; // 4 = 0dB ((UE->frame_parms).pdsch_config_common).p_b = 1; } diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index 18860d729c..f75ae326e9 100755 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -52,6 +52,9 @@ //extern uint16_t phich_reg[MAX_NUM_PHICH_GROUPS][3]; //extern uint16_t pcfich_reg[4]; +//#undef LOG_D +//#define LOG_D(A,B,C...) printf(B,C) + uint32_t check_phich_reg(LTE_DL_FRAME_PARMS *frame_parms,uint32_t kprime,uint8_t lprime,uint8_t mi) { @@ -177,7 +180,7 @@ void dci_encoding(uint8_t *a, // encode dci #ifdef DEBUG_DCI_ENCODING - printf("Doing DCI encoding for %d bits, e %p, rnti %x\n",A,e,rnti); + printf("Doing DCI encoding for %d bits, e %p, rnti %x, E %d\n",A,e,rnti,E); #endif memset((void *)d,LTE_NULL,96); @@ -231,18 +234,23 @@ uint8_t *generate_dci0(uint8_t *dci, coded_bits = 72 * aggregation_level; - /* + #ifdef DEBUG_DCI_ENCODING - for (i=0;i<1+((DCI_LENGTH+16)/8);i++) + for (int i=0;i<1+((DCI_LENGTH+16)/8);i++) printf("i %d : %x\n",i,dci[i]); #endif - */ + if (DCI_LENGTH<=32) { dci_flip[0] = dci[3]; dci_flip[1] = dci[2]; dci_flip[2] = dci[1]; dci_flip[3] = dci[0]; +#ifdef DEBUG_DCI_ENCODING + printf("DCI => %x,%x,%x,%x\n", + dci_flip[0],dci_flip[1],dci_flip[2],dci_flip[3]); + +#endif } else { dci_flip[0] = dci[7]; dci_flip[1] = dci[6]; @@ -2271,7 +2279,7 @@ uint8_t generate_dci_top(uint8_t num_pdcch_symbols, /* clear all bits, the above code may generate too much false detections * (not sure about this, to be checked somehow) */ - // memset(e, 0, DCI_BITS_MAX); + // memset(e, 0, DCI_BITS_MAX); e_ptr = e; @@ -2285,11 +2293,11 @@ uint8_t generate_dci_top(uint8_t num_pdcch_symbols, if (dci_alloc[i].L == (uint8_t)L) { #ifdef DEBUG_DCI_ENCODING - if (dci_alloc[i].rnti==0x02) - LOG_I(PHY,"Generating DCI %d/%d (nCCE %d) of length %d, aggregation %d (%x), rnti %x\n",i,num_dci,dci_alloc[i].firstCCE,dci_alloc[i].dci_length,dci_alloc[i].L, + if (dci_alloc[i].rnti==0x1234) + LOG_D(PHY,"Generating DCI %d/%d (nCCE %d) of length %d, aggregation %d (%x), rnti %x\n",i,num_dci,dci_alloc[i].firstCCE,dci_alloc[i].dci_length,dci_alloc[i].L, *(unsigned int*)dci_alloc[i].dci_pdu, dci_alloc[i].rnti); - //dump_dci(frame_parms,&dci_alloc[i]); + dump_dci(frame_parms,&dci_alloc[i]); #endif if (dci_alloc[i].firstCCE>=0) { @@ -2894,17 +2902,17 @@ void dci_decoding_procedure0(LTE_UE_PDCCH **pdcch_vars, LOG_D(PHY,"[DCI search nPdcch %d - common] Attempting candidate %d Aggregation Level %d DCI length %d at CCE %d/%d (CCEmap %x,CCEmap_cand %x)\n", pdcch_vars[eNB_id]->num_pdcch_symbols,m,L2,sizeof_bits,CCEind,nCCE,*CCEmap,CCEmap_mask); else - LOG_D(PHY,"[DCI search nPdcch %d - ue spec] Attempting candidate %d Aggregation Level %d DCI length %d at CCE %d/%d (CCEmap %x,CCEmap_cand %x) format %d\n", - pdcch_vars[eNB_id]->num_pdcch_symbols,m,L2,sizeof_bits,CCEind,nCCE,*CCEmap,CCEmap_mask,format_c); + LOG_D(PHY,"[DCI search nPdcch %d - ue spec %x] Attempting candidate %d Aggregation Level %d DCI length %d at CCE %d/%d (CCEmap %x,CCEmap_cand %x) format %d\n", + pdcch_vars[eNB_id]->num_pdcch_symbols,pdcch_vars[eNB_id]->crnti,m,L2,sizeof_bits,CCEind,nCCE,*CCEmap,CCEmap_mask,format_c); dci_decoding(sizeof_bits, L, &pdcch_vars[eNB_id]->e_rx[CCEind*72], &dci_decoded_output[current_thread_id][0]); - /* + /* for (i=0;i<3+(sizeof_bits>>3);i++) - printf("dci_decoded_output[%d] => %x\n",i,dci_decoded_output[i]); - */ + printf("dci_decoded_output[%d][%d] => %x\n",current_thread_id,i,dci_decoded_output[current_thread_id][i]); + */ crc = (crc16(&dci_decoded_output[current_thread_id][0],sizeof_bits)>>16) ^ extract_crc(&dci_decoded_output[current_thread_id][0],sizeof_bits); #ifdef DEBUG_DCI_DECODING @@ -3823,7 +3831,7 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *ue, } else if (tmode == 3) { - LOG_D(PHY," Now check UE_SPEC format 2A_2A search aggregation 1 dci length: %d[bits] %d[bytes]\n",format2A_size_bits,format2A_size_bytes); + // LOG_D(PHY," Now check UE_SPEC format 2A_2A search aggregation 1 dci length: %d[bits] %d[bytes]\n",format2A_size_bits,format2A_size_bytes); // Now check UE_SPEC format 2A_2A search spaces at aggregation 1 old_dci_cnt=dci_cnt; dci_decoding_procedure0(pdcch_vars,0,mode, @@ -3895,7 +3903,7 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *ue, return(dci_cnt); // Now check UE_SPEC format 2_2A search spaces at aggregation 4 - LOG_D(PHY," Now check UE_SPEC format 2_2A search spaces at aggregation 4 \n"); + // LOG_D(PHY," Now check UE_SPEC format 2_2A search spaces at aggregation 4 \n"); old_dci_cnt=dci_cnt; dci_decoding_procedure0(pdcch_vars,0,mode, subframe, @@ -4238,3 +4246,6 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *ue, return(dci_cnt); } + + + diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index c6c1322504..4adcc130dd 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -44,6 +44,11 @@ #include "LAYER2/MAC/extern.h" #include "LAYER2/MAC/defs.h" +//#undef LOG_D +//#define LOG_D(A,B,C...) printf(B,C) +//#undef LOG_I +//#define LOG_I(A,B,C...) printf(B,C) + //#define DEBUG_DCI uint32_t localRIV2alloc_LUT6[32]; @@ -4680,13 +4685,13 @@ int check_dci_format1_1a_coherency(DCI_format_t dci_format, if(harq_pid>=8) { - LOG_I(PHY,"bad harq id \n"); + // LOG_I(PHY,"bad harq id \n"); return(0); } if(dci_format == format1 && ((rnti==si_rnti) || (rnti==p_rnti) || (rnti==ra_rnti)) ) { - LOG_I(PHY,"bad dci format \n"); + // LOG_I(PHY,"bad dci format \n"); return(0); } @@ -4695,13 +4700,13 @@ int check_dci_format1_1a_coherency(DCI_format_t dci_format, { if(pdlsch0_harq->round == 0) { - LOG_I(PHY,"bad dci mcs + round \n"); + // LOG_I(PHY,"bad dci mcs + round \n"); return(0); } if((rnti==si_rnti) || (rnti==p_rnti) || (rnti==ra_rnti)) { - LOG_I(PHY,"bad dci mcs + rnti \n"); + // LOG_I(PHY,"bad dci mcs + rnti \n"); return(0); } } @@ -4767,7 +4772,7 @@ int check_dci_format1_1a_coherency(DCI_format_t dci_format, if(rballoc > RIV_max) { - LOG_I(PHY,"bad dci rballoc rballoc %d RIV_max %lld \n",rballoc, RIV_max); + // LOG_I(PHY,"bad dci rballoc rballoc %d RIV_max %lld \n",rballoc, RIV_max); // DCI false detection return(0); } @@ -4775,7 +4780,7 @@ int check_dci_format1_1a_coherency(DCI_format_t dci_format, if(NPRB == 0) { // DCI false detection - LOG_I(PHY,"bad NPRB = 0 \n"); + // LOG_I(PHY,"bad NPRB = 0 \n"); return(0); } @@ -4894,13 +4899,13 @@ int check_dci_format2_2a_coherency(DCI_format_t dci_format, // I- check dci content minimum coherency if(harq_pid>=8) { - LOG_I(PHY,"bad harq pid\n"); + // LOG_I(PHY,"bad harq pid\n"); return(0); } if( (rnti==si_rnti) || (rnti==p_rnti) || (rnti==ra_rnti) ) { - LOG_I(PHY,"bad rnti\n"); + // LOG_I(PHY,"bad rnti\n"); return(0); } @@ -4909,7 +4914,7 @@ int check_dci_format2_2a_coherency(DCI_format_t dci_format, { if(pdlsch0_harq->round == 0) { - LOG_I(PHY,"bad mcs1\n"); + // LOG_I(PHY,"bad mcs1\n"); return(0); } } @@ -4918,7 +4923,7 @@ int check_dci_format2_2a_coherency(DCI_format_t dci_format, { if(pdlsch1_harq->round == 0) { - LOG_I(PHY,"bad mcs2\n"); + // LOG_I(PHY,"bad mcs2\n"); return(0); } } @@ -4927,14 +4932,14 @@ int check_dci_format2_2a_coherency(DCI_format_t dci_format, if((pdlsch0_harq->round == 0) && (rv1 > 0) && (mcs1 != 0)) { // DCI false detection - LOG_I(PHY,"bad rv1\n"); + // LOG_I(PHY,"bad rv1\n"); return(0); } if((pdlsch1_harq->round == 0) && (rv2 > 0) && (mcs2 != 0)) { // DCI false detection - LOG_I(PHY,"bad rv2\n"); + // LOG_I(PHY,"bad rv2\n"); return(0); } @@ -4995,14 +5000,14 @@ int check_dci_format2_2a_coherency(DCI_format_t dci_format, if( (rballoc > RIV_max) && (rah == 1) ) { // DCI false detection - LOG_I(PHY,"bad rballoc %d RIV_max %lld\n", rballoc, RIV_max); + // LOG_I(PHY,"bad rballoc %d RIV_max %lld\n", rballoc, RIV_max); return(0); } if(NPRB == 0) { // DCI false detection - LOG_I(PHY,"bad NPRB\n"); + // LOG_I(PHY,"bad NPRB\n"); return(0); } @@ -5026,7 +5031,7 @@ void compute_llr_offset(LTE_DL_FRAME_PARMS *frame_parms, pdsch_vars->llr_offset[pdcch_vars->num_pdcch_symbols] = 0; - //LOG_I(PHY,"compute_llr_offset: nb RB %d - Qm %d \n", nb_rb_alloc, dlsch0_harq->Qm); + LOG_I(PHY,"compute_llr_offset: nb RB %d - Qm %d \n", nb_rb_alloc, dlsch0_harq->Qm); //dlsch0_harq->rb_alloc_even; //dlsch0_harq->rb_alloc_odd; @@ -5056,15 +5061,15 @@ void compute_llr_offset(LTE_DL_FRAME_PARMS *frame_parms, if(symbol < (frame_parms->symbols_per_tti-1)) pdsch_vars->llr_offset[symbol+1] = pdsch_vars->llr_offset[symbol] + llr_offset; - // LOG_I(PHY,"Granted Re subframe %d / symbol %d => %d (%d RBs)\n", subframe, symbol_mod, granted_re,dlsch0_harq->nb_rb); - // LOG_I(PHY,"Pbch/PSS/SSS Re subframe %d / symbol %d => %d \n", subframe, symbol_mod, pbch_pss_sss_re); - // LOG_I(PHY,"CRS Re Per PRB subframe %d / symbol %d => %d \n", subframe, symbol_mod, crs_re); - // LOG_I(PHY,"Data Re subframe %d / symbol %d => %d \n", subframe, symbol_mod, data_re); + LOG_I(PHY,"Granted Re subframe %d / symbol %d => %d (%d RBs)\n", subframe, symbol_mod, granted_re,dlsch0_harq->nb_rb); + LOG_I(PHY,"Pbch/PSS/SSS Re subframe %d / symbol %d => %d \n", subframe, symbol_mod, pbch_pss_sss_re); + LOG_I(PHY,"CRS Re Per PRB subframe %d / symbol %d => %d \n", subframe, symbol_mod, crs_re); + LOG_I(PHY,"Data Re subframe %d / symbol %d => %d \n", subframe, symbol_mod, data_re); - //LOG_I(PHY,"Data Re subframe %d-symbol %d => llr length %d, llr offset %d \n", subframe, symbol, - // pdsch_vars->llr_length[symbol], pdsch_vars->llr_offset[symbol]); + LOG_I(PHY,"Data Re subframe %d-symbol %d => llr length %d, llr offset %d \n", subframe, symbol, + pdsch_vars->llr_length[symbol], pdsch_vars->llr_offset[symbol]); } } void prepare_dl_decoding_format1_1A(DCI_format_t dci_format, @@ -5179,7 +5184,7 @@ void prepare_dl_decoding_format1_1A(DCI_format_t dci_format, //packet was actually decoded in previous transmission (ACK was missed by eNB) //However, the round is not a good check as it might have been decoded in a retransmission prior to this one. { - LOG_D(PHY,"skip pdsch decoding and report ack\n"); + // LOG_D(PHY,"skip pdsch decoding and report ack\n"); // skip pdsch decoding and report ack //pdlsch0_harq->status = SCH_IDLE; pdlsch0->active = 0; @@ -5804,7 +5809,7 @@ void prepare_dl_decoding_format2_2A(DCI_format_t dci_format, //LOG_I(PHY,"[UE] DLSCH: New Data Indicator CW0 subframe %d (pid %d, round %d)\n", // subframe,harq_pid,dlsch0_harq->round); if ( dlsch0_harq->first_tx==1) { - LOG_D(PHY,"Format 2 DCI First TX0: Clearing flag\n"); + // LOG_D(PHY,"Format 2 DCI First TX0: Clearing flag\n"); dlsch0_harq->first_tx = 0; } } @@ -5852,7 +5857,7 @@ void prepare_dl_decoding_format2_2A(DCI_format_t dci_format, //LOG_I(PHY,"[UE] DLSCH: New Data Indicator CW1 subframe %d (pid %d, round %d)\n", // subframe,harq_pid,dlsch0_harq->round); if (dlsch1_harq->first_tx==1) { - LOG_D(PHY,"Format 2 DCI First TX1: Clearing flag\n"); + // LOG_D(PHY,"Format 2 DCI First TX1: Clearing flag\n"); dlsch1_harq->first_tx = 0; } } diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index bd3c92454f..89225a573a 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -604,7 +604,7 @@ int dlsch_encoding(PHY_VARS_eNB *eNB, // if (dlsch->harq_processes[harq_pid]->Ndi == 1) { // this is a new packet if (dlsch->harq_processes[harq_pid]->round == 0) { // this is a new packet #ifdef DEBUG_DLSCH_CODING - printf("encoding thinks this is a new packet \n"); + printf("encoding thinks this is a new packet for harq_pid %d (%p) \n",harq_pid,dlsch->harq_processes[harq_pid]->b); #endif /* int i; @@ -614,6 +614,7 @@ int dlsch_encoding(PHY_VARS_eNB *eNB, printf("\n"); */ // Add 24-bit crc (polynomial A) to payload + crc = crc24a(a, A)>>8; a[A>>3] = ((uint8_t*)&crc)[2]; diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c index 7acf6480eb..71399c2652 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c @@ -37,6 +37,12 @@ #include "SCHED/extern.h" #include "SIMULATION/TOOLS/defs.h" //#define DEBUG_DLSCH_DECODING +//#define UE_DEBUG_TRACE 1 + +//#undef LOG_D +//#define LOG_D(A,B,C...) printf(B,C) +//#undef LOG_I +//#define LOG_I(A,B,C...) printf(B,C) extern double cpuf; diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index c805d9408f..062cb8d299 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -49,12 +49,14 @@ int16_t interf_unaw_shift = 13; //#define DEBUG_HARQ //#undef LOG_D -//#define LOG_D LOG_I +//#define LOG_D(A,B,C...) printf(B,C) +//#undef LOG_I +//#define LOG_I(A,B,C...) printf(B,C) -//#define DEBUG_PHY 1 +#define DEBUG_PHY 1 //#define DEBUG_DLSCH_DEMOD 1 - +//#define DISABLE_LOG_X // [MCS][i_mod (0,1,2) = (2,4,6)] unsigned char offset_mumimo_llr_drange_fix=0; @@ -370,7 +372,7 @@ int rx_pdsch(PHY_VARS_UE *ue, //printf("nb_rb = %d, eNB_id %d\n",nb_rb,eNB_id); if (nb_rb==0) { - LOG_D(PHY,"dlsch_demodulation.c: nb_rb=0\n"); + // LOG_D(PHY,"dlsch_demodulation.c: nb_rb=0\n"); return(-1); } @@ -845,7 +847,7 @@ int rx_pdsch(PHY_VARS_UE *ue, pllr_symbol_cw1 = (int8_t*)pdsch_vars[eNB_id]->llr[1]; pllr_symbol_cw0 += llr_offset_symbol; pllr_symbol_cw1 += llr_offset_symbol; - /* + LOG_I(PHY,"compute LLRs [AbsSubframe %d.%d-%d] NbRB %d Qm %d LLRs-Length %d LLR-Offset %d @LLR Buff %x @LLR Buff(symb) %x\n", frame, subframe,symbol, nb_rb,dlsch0_harq->Qm, @@ -853,7 +855,7 @@ int rx_pdsch(PHY_VARS_UE *ue, pdsch_vars[eNB_id]->llr_offset[symbol], (int16_t*)pdsch_vars[eNB_id]->llr[0], pllr_symbol_cw0); - */ + switch (dlsch0_harq->Qm) { case 2 : if ((rx_type==rx_standard) || (codeword_TB1 == -1)) { diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 49b41615f4..f3a9a05ae5 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -2125,6 +2125,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, amp_rho_b = (int16_t)(((int32_t)amp*dlsch1->sqrt_rho_b)>>13); } + if (mod_order0 == 4) for (i=0;i<4; i++) { qam16_table_a0[i] = (int16_t)(((int32_t)qam16_table[i]*amp_rho_a)>>15); diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c b/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c index d90f4c66d2..8d650bbe21 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c @@ -124,14 +124,18 @@ void dlsch_scrambling(LTE_DL_FRAME_PARMS *frame_parms, } #ifdef DEBUG_SCRAMBLING +#ifdef Rel14 printf("scrambling: i0 %d rnti %x, q %d, Ns %d, Nid_cell %d, G %d x2 %x\n",dlsch->i0,dlsch->rnti,q,Ns,frame_parms->Nid_cell, G, x2); +#else + printf("scrambling: rnti %x, q %d, Ns %d, Nid_cell %d, G %d x2 %x\n",dlsch->rnti,q,Ns,frame_parms->Nid_cell, G, x2); +#endif #endif s = lte_gold_scram(&x1, &x2, 1); for (n=0; n<(1+(G>>5)); n++) { #ifdef DEBUG_SCRAMBLING - printf("scrambling %d : %d => ",k,e[k]); + for (int k=0;k<32;k++) printf("scrambling %d : %d xor %d = %d\n",k+(n<<5),e[k],(s>>k)&1,e[k]^((s>>k)&1)); #endif @@ -171,9 +175,8 @@ void dlsch_scrambling(LTE_DL_FRAME_PARMS *frame_parms, // This is not faster for some unknown reason // ((__m128i *)e)[0] = _mm_xor_si128(((__m128i *)e)[0],((__m128i *)scrambling_lut)[s&65535]); // ((__m128i *)e)[1] = _mm_xor_si128(((__m128i *)e)[1],((__m128i *)scrambling_lut)[s>>16]); -#ifdef DEBUG_SCRAMBLING - printf("%d\n",e[k]); -#endif + + s = lte_gold_scram(&x1, &x2, 0); @@ -213,7 +216,7 @@ void dlsch_unscrambling(LTE_DL_FRAME_PARMS *frame_parms, for (i=0; i<(1+(G>>5)); i++) { for (j=0; j<32; j++,k++) { #ifdef DEBUG_SCRAMBLING - printf("unscrambling %d : %d => ",k,llr[k]); + printf("unscrambling %d : %d xor %d =",k,llr[k],(s>>j)&1); #endif llr[k] = ((2*((s>>j)&1))-1)*llr[k]; #ifdef DEBUG_SCRAMBLING diff --git a/openair1/PHY/LTE_TRANSPORT/power_control.c b/openair1/PHY/LTE_TRANSPORT/power_control.c index 10f0c1490c..36b2bfbeab 100644 --- a/openair1/PHY/LTE_TRANSPORT/power_control.c +++ b/openair1/PHY/LTE_TRANSPORT/power_control.c @@ -33,20 +33,20 @@ double ratioPB[2][4]={{ 0.00000, -0.96910, -2.21849, -3.97940}, //in db double pa_values[8]={-6.0,-4.77,-3.0,-1.77,0.0,1.0,2.0,3.0}; //reported by higher layers -double get_pa_dB(PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated) +double get_pa_dB(uint8_t pa) { - if (pdsch_config_dedicated) - return(pa_values[ pdsch_config_dedicated->p_a]); - else - return(0.0); + AssertFatal(pa<8,"pa %d is not in (0...7)\n",pa); + + return(pa_values[pa]); + } -double computeRhoA_eNB(PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated, +double computeRhoA_eNB(uint8_t pa, LTE_eNB_DLSCH_t *dlsch_eNB, int dl_power_off, uint8_t n_antenna_port){ double rho_a_dB; double sqrt_rho_a_lin; - rho_a_dB = get_pa_dB(pdsch_config_dedicated); + rho_a_dB = get_pa_dB(pa); if(!dl_power_off) //if dl_power_offset is 0, this is for MU-interference, TM5 rho_a_dB-=10*log10(2); @@ -59,14 +59,14 @@ double computeRhoA_eNB(PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated, dlsch_eNB->sqrt_rho_a= (short) (sqrt_rho_a_lin*pow(2,13)); #if DEBUG_PC - printf("eNB: p_a=%d, value=%f, sqrt_rho_a=%d\n",pdsch_config_dedicated->p_a,pa_values[ pdsch_config_dedicated->p_a],dlsch_eNB->sqrt_rho_a); + printf("eNB: p_a=%d, value=%f, sqrt_rho_a=%d\n",p_a,pa_values[ pdsch_config_dedicated->p_a],dlsch_eNB->sqrt_rho_a); #endif return(rho_a_dB); } -double computeRhoB_eNB(PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated, - PDSCH_CONFIG_COMMON *pdsch_config_common, +double computeRhoB_eNB(uint8_t pa, + uint8_t pb, uint8_t n_antenna_port, LTE_eNB_DLSCH_t *dlsch_eNB, int dl_power_off) @@ -75,19 +75,21 @@ double computeRhoB_eNB(PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated, double rho_a_dB, rho_b_dB; double sqrt_rho_b_lin; - rho_a_dB= computeRhoA_eNB(pdsch_config_dedicated,dlsch_eNB,dl_power_off, n_antenna_port); + AssertFatal(pa<8,"pa %d is not in (0...7)\n",pa); + AssertFatal(pb<4,"pb %d is not in (0...3)\n",pb); + rho_a_dB= computeRhoA_eNB(pa,dlsch_eNB,dl_power_off, n_antenna_port); if(n_antenna_port>1) - rho_b_dB= ratioPB[1][pdsch_config_common->p_b] + rho_a_dB; + rho_b_dB= ratioPB[1][pb] + rho_a_dB; else - rho_b_dB= ratioPB[0][pdsch_config_common->p_b] + rho_a_dB; + rho_b_dB= ratioPB[0][pb] + rho_a_dB; sqrt_rho_b_lin= pow(10,(0.05*rho_b_dB)); dlsch_eNB->sqrt_rho_b= (short) (sqrt_rho_b_lin*pow(2,13)); #ifdef DEBUG_PC - printf("eNB: n_ant=%d, p_b=%d -> rho_b/rho_a=%f -> sqrt_rho_b=%d\n",n_antenna_port,pdsch_config_common->p_b,ratioPB[1][pdsch_config_common->p_b],dlsch_eNB->sqrt_rho_b); + printf("eNB: n_ant=%d, p_b=%d -> rho_b/rho_a=%f -> sqrt_rho_b=%d\n",n_antenna_port,pb,ratioPB[1][pb],dlsch_eNB->sqrt_rho_b); #endif return(rho_b_dB); } @@ -102,7 +104,7 @@ double computeRhoA_UE(PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated, double rho_a_dB; double sqrt_rho_a_lin; - rho_a_dB = get_pa_dB(pdsch_config_dedicated); + rho_a_dB = get_pa_dB(pdsch_config_dedicated->p_a); if(!dl_power_off) rho_a_dB-=10*log10(2); diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index be6d2861f2..c67820d0dd 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -2221,15 +2221,15 @@ uint32_t dlsch_decoding_abstraction(double *dlsch_MIPB, uint8_t num_pdcch_symbols); // DL power control functions -double get_pa_dB(PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated); +double get_pa_dB(uint8_t pa); -double computeRhoA_eNB(PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated, - LTE_eNB_DLSCH_t *dlsch_eNB, +double computeRhoA_eNB(uint8_t pa, + LTE_eNB_DLSCH_t *dlsch_eNB, int dl_power_off, uint8_t n_antenna_port); -double computeRhoB_eNB(PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated, - PDSCH_CONFIG_COMMON *pdsch_config_common, +double computeRhoB_eNB(uint8_t pa, + uint8_t pb, uint8_t n_antenna_port, LTE_eNB_DLSCH_t *dlsch_eNB, int dl_power_off); diff --git a/openair1/PHY/vars.h b/openair1/PHY/vars.h index f78cb92bcd..45af058308 100644 --- a/openair1/PHY/vars.h +++ b/openair1/PHY/vars.h @@ -24,6 +24,7 @@ #include "PHY/types.h" #include "PHY/defs.h" +#include "common/ran_context.h" char* namepointer_chMag ; char fmageren_name2[512]; diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c index b9024bdfbf..6cb6e66aac 100644 --- a/openair1/SCHED/fapi_l1.c +++ b/openair1/SCHED/fapi_l1.c @@ -37,6 +37,11 @@ #include "nfapi_interface.h" #include "fapi_l1.h" +//#undef LOG_D +//#define LOG_D(A,B,C...) printf(B,C) +//#undef LOG_I +//#define LOG_I(A,B,C...) printf(B,C) + int oai_nfapi_dl_config_req(nfapi_dl_config_request_t *dl_config_req); int oai_nfapi_tx_req(nfapi_tx_request_t *tx_req); int oai_nfapi_hi_dci0_req(nfapi_hi_dci0_request_t *hi_dci0_req); @@ -190,12 +195,12 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_pr eNB->pdsch_config_dedicated[UE_id].p_a = rel8->pa; if (dlsch0->active){ - computeRhoA_eNB(&eNB->pdsch_config_dedicated[UE_id], dlsch0,dlsch0_harq->dl_power_off, eNB->frame_parms.nb_antenna_ports_eNB); - computeRhoB_eNB(&eNB->pdsch_config_dedicated[UE_id],&(eNB->frame_parms.pdsch_config_common),eNB->frame_parms.nb_antenna_ports_eNB,dlsch0,dlsch0_harq->dl_power_off); + computeRhoA_eNB(rel8->pa, dlsch0,dlsch0_harq->dl_power_off, eNB->frame_parms.nb_antenna_ports_eNB); + computeRhoB_eNB(rel8->pa,eNB->frame_parms.pdsch_config_common.p_b,eNB->frame_parms.nb_antenna_ports_eNB,dlsch0,dlsch0_harq->dl_power_off); } if (dlsch1->active){ - computeRhoA_eNB(&eNB->pdsch_config_dedicated[UE_id], dlsch1,dlsch1_harq->dl_power_off, eNB->frame_parms.nb_antenna_ports_eNB); - computeRhoB_eNB(&eNB->pdsch_config_dedicated[UE_id],&(eNB->frame_parms.pdsch_config_common),eNB->frame_parms.nb_antenna_ports_eNB,dlsch1,dlsch1_harq->dl_power_off); + computeRhoA_eNB(rel8->pa, dlsch1,dlsch1_harq->dl_power_off, eNB->frame_parms.nb_antenna_ports_eNB); + computeRhoB_eNB(rel8->pa,eNB->frame_parms.pdsch_config_common.p_b,eNB->frame_parms.nb_antenna_ports_eNB,dlsch1,dlsch1_harq->dl_power_off); } dlsch0_harq->pdsch_start = eNB->pdcch_vars[subframe & 1].num_pdcch_symbols; diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 2ae79b53b6..f771288f35 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -50,6 +50,9 @@ # include "intertask_interface.h" #endif +//#undef LOG_D +//#define LOG_D(A,B,C...) printf(B,C) + extern uint8_t nfapi_mode; int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind); @@ -395,6 +398,7 @@ void pdsch_procedures(PHY_VARS_eNB *eNB, + void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, relaying_type_t r_type, @@ -416,7 +420,7 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, int offset = eNB->CC_id;//proc == &eNB->proc.proc_rxtx[0] ? 0 : 1; - + if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)==SF_UL)) return; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX+offset,1); @@ -429,6 +433,7 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, } + if (nfapi_mode == 0 || nfapi_mode == 1) { if (is_pmch_subframe(frame,subframe,fp)) { pmch_procedures(eNB,proc,rn,r_type); @@ -439,6 +444,7 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, } } + // clear existing ulsch dci allocations before applying info from MAC (this is table ul_subframe = pdcch_alloc2ul_subframe(fp,subframe); ul_frame = pdcch_alloc2ul_frame(fp,frame,subframe); diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 2e6bdc8a14..0085a31e28 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -73,6 +73,9 @@ extern double cpuf; +//#undef LOG_D +//#define LOG_D(A,B,C...) printf(B,C) + void Msg1_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); void Msg3_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); @@ -1373,7 +1376,7 @@ void ue_prach_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin if (ue->mac_enabled==1){ // ask L2 for RACH transport if ((mode != rx_calib_ue) && (mode != rx_calib_ue_med) && (mode != rx_calib_ue_byp) && (mode != no_L2_connect) ) { - LOG_D(PHY,"Getting PRACH resources\n"); + //LOG_D(PHY,"Getting PRACH resources\n"); ue->prach_resources[eNB_id] = ue_get_rach(ue->Mod_id, ue->CC_id, @@ -1590,7 +1593,7 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB LOG_D(PHY,"Generating PUSCH (Abssubframe: %d.%d): harq-Id: %d, round: %d, MaxReTrans: %d \n",frame_tx,subframe_tx,harq_pid,ue->ulsch[eNB_id]->harq_processes[harq_pid]->round,ue->ulsch[eNB_id]->Mlimit); if (ue->ulsch[eNB_id]->harq_processes[harq_pid]->round >= (ue->ulsch[eNB_id]->Mlimit - 1)) { - LOG_D(PHY,"PUSCH MAX Retransmission achieved ==> send last pusch\n"); + // LOG_D(PHY,"PUSCH MAX Retransmission achieved ==> send last pusch\n"); ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 0; ue->ulsch[eNB_id]->harq_processes[harq_pid]->round = 0; } @@ -2070,10 +2073,10 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin (bundling_flag==bundling) || ((frame_parms->frame_type==TDD)&&(frame_parms->tdd_config==1)&&((subframe_tx!=2)||(subframe_tx!=7)))) { format = pucch_format1a; - LOG_D(PHY,"[UE] PUCCH 1a\n"); + // LOG_D(PHY,"[UE] PUCCH 1a\n"); } else { format = pucch_format1b; - LOG_D(PHY,"[UE] PUCCH 1b\n"); + // LOG_D(PHY,"[UE] PUCCH 1b\n"); } // Part - I @@ -3108,7 +3111,7 @@ void ue_pmch_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc,int eNB_id,int abs int ret=0; if (is_pmch_subframe(frame_rx,subframe_rx,&ue->frame_parms)) { - LOG_D(PHY,"ue calling pmch subframe ..\n "); + // LOG_D(PHY,"ue calling pmch subframe ..\n "); LOG_D(PHY,"[UE %d] Frame %d, subframe %d: Querying for PMCH demodulation\n", ue->Mod_id,(subframe_rx==9?-1:0)+frame_rx,subframe_rx); diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 34055517b2..128fca79e1 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -54,8 +54,9 @@ #include "PHY/TOOLS/lte_phy_scope.h" -PHY_VARS_eNB *eNB; -PHY_VARS_UE *UE; +#include "dummy_functions.c" + + double cpuf; @@ -123,7 +124,7 @@ void do_OFDM_mod_l(int32_t **txdataF, int32_t **txdata, uint16_t next_slot, LTE_ } -void DL_channel(PHY_VARS_eNB *eNB,PHY_VARS_UE *UE,int subframe,int awgn_flag,double SNR, int tx_lev,int hold_channel,int abstx, int num_rounds, int trials, int round, channel_desc_t *eNB2UE[4], +void DL_channel(RU_t *ru,PHY_VARS_UE *UE,uint subframe,int awgn_flag,double SNR, int tx_lev,int hold_channel,int abstx, int num_rounds, int trials, int round, channel_desc_t *eNB2UE[4], double *s_re[2],double *s_im[2],double *r_re[2],double *r_im[2],FILE *csv_fd) { int i,u; @@ -134,18 +135,18 @@ void DL_channel(PHY_VARS_eNB *eNB,PHY_VARS_UE *UE,int subframe,int awgn_flag,dou // printf("Copying tx ..., nsymb %d (n_tx %d), awgn %d\n",nsymb,eNB->frame_parms.nb_antennas_tx,awgn_flag); for (i=0; i<2*UE->frame_parms.samples_per_tti; i++) { - for (aa=0; aaframe_parms.nb_antennas_tx; aa++) { + for (aa=0; aaframe_parms.nb_antennas_tx; aa++) { if (awgn_flag == 0) { - s_re[aa][i] = ((double)(((short *)eNB->common_vars.txdata[0][aa]))[(2*subframe*UE->frame_parms.samples_per_tti) + (i<<1)]); - s_im[aa][i] = ((double)(((short *)eNB->common_vars.txdata[0][aa]))[(2*subframe*UE->frame_parms.samples_per_tti) +(i<<1)+1]); + s_re[aa][i] = ((double)(((short *)ru->common.txdata[aa]))[(2*subframe*UE->frame_parms.samples_per_tti) + (i<<1)]); + s_im[aa][i] = ((double)(((short *)ru->common.txdata[aa]))[(2*subframe*UE->frame_parms.samples_per_tti) +(i<<1)+1]); } else { for (aarx=0; aarxframe_parms.nb_antennas_rx; aarx++) { if (aa==0) { - r_re[aarx][i] = ((double)(((short *)eNB->common_vars.txdata[0][aa]))[(2*subframe*UE->frame_parms.samples_per_tti) +(i<<1)]); - r_im[aarx][i] = ((double)(((short *)eNB->common_vars.txdata[0][aa]))[(2*subframe*UE->frame_parms.samples_per_tti) +(i<<1)+1]); + r_re[aarx][i] = ((double)(((short *)ru->common.txdata[aa]))[(2*subframe*UE->frame_parms.samples_per_tti) +(i<<1)]); + r_im[aarx][i] = ((double)(((short *)ru->common.txdata[aa]))[(2*subframe*UE->frame_parms.samples_per_tti) +(i<<1)+1]); } else { - r_re[aarx][i] += ((double)(((short *)eNB->common_vars.txdata[0][aa]))[(2*subframe*UE->frame_parms.samples_per_tti) +(i<<1)]); - r_im[aarx][i] += ((double)(((short *)eNB->common_vars.txdata[0][aa]))[(2*subframe*UE->frame_parms.samples_per_tti) +(i<<1)+1]); + r_re[aarx][i] += ((double)(((short *)ru->common.txdata[aa]))[(2*subframe*UE->frame_parms.samples_per_tti) +(i<<1)]); + r_im[aarx][i] += ((double)(((short *)ru->common.txdata[aa]))[(2*subframe*UE->frame_parms.samples_per_tti) +(i<<1)+1]); } } @@ -180,11 +181,11 @@ void DL_channel(PHY_VARS_eNB *eNB,PHY_VARS_UE *UE,int subframe,int awgn_flag,dou if(abstx) { if (trials==0 && round==0) { // calculate freq domain representation to compute SINR - freq_channel(eNB2UE[0], eNB->frame_parms.N_RB_DL,2*eNB->frame_parms.N_RB_DL + 1); + freq_channel(eNB2UE[0], ru->frame_parms.N_RB_DL,2*ru->frame_parms.N_RB_DL + 1); // snr=pow(10.0,.1*SNR); fprintf(csv_fd,"%f,",SNR); - for (u=0; u<2*eNB->frame_parms.N_RB_DL; u++) { + for (u=0; u<2*ru->frame_parms.N_RB_DL; u++) { for (aarx=0; aarxnb_rx; aarx++) { for (aatx=0; aatxnb_tx; aatx++) { channelx = eNB2UE[0]->chF[aarx+(aatx*eNB2UE[0]->nb_rx)][u].x; @@ -195,9 +196,9 @@ void DL_channel(PHY_VARS_eNB *eNB,PHY_VARS_UE *UE,int subframe,int awgn_flag,dou } if(num_rounds>1) { - freq_channel(eNB2UE[1], eNB->frame_parms.N_RB_DL,2*eNB->frame_parms.N_RB_DL + 1); + freq_channel(eNB2UE[1], ru->frame_parms.N_RB_DL,2*ru->frame_parms.N_RB_DL + 1); - for (u=0; u<2*eNB->frame_parms.N_RB_DL; u++) { + for (u=0; u<2*ru->frame_parms.N_RB_DL; u++) { for (aarx=0; aarxnb_rx; aarx++) { for (aatx=0; aatxnb_tx; aatx++) { channelx = eNB2UE[1]->chF[aarx+(aatx*eNB2UE[1]->nb_rx)][u].x; @@ -207,9 +208,9 @@ void DL_channel(PHY_VARS_eNB *eNB,PHY_VARS_UE *UE,int subframe,int awgn_flag,dou } } - freq_channel(eNB2UE[2], eNB->frame_parms.N_RB_DL,2*eNB->frame_parms.N_RB_DL + 1); + freq_channel(eNB2UE[2], ru->frame_parms.N_RB_DL,2*ru->frame_parms.N_RB_DL + 1); - for (u=0; u<2*eNB->frame_parms.N_RB_DL; u++) { + for (u=0; u<2*ru->frame_parms.N_RB_DL; u++) { for (aarx=0; aarxnb_rx; aarx++) { for (aatx=0; aatxnb_tx; aatx++) { channelx = eNB2UE[2]->chF[aarx+(aatx*eNB2UE[2]->nb_rx)][u].x; @@ -219,9 +220,9 @@ void DL_channel(PHY_VARS_eNB *eNB,PHY_VARS_UE *UE,int subframe,int awgn_flag,dou } } - freq_channel(eNB2UE[3], eNB->frame_parms.N_RB_DL,2*eNB->frame_parms.N_RB_DL + 1); + freq_channel(eNB2UE[3], ru->frame_parms.N_RB_DL,2*ru->frame_parms.N_RB_DL + 1); - for (u=0; u<2*eNB->frame_parms.N_RB_DL; u++) { + for (u=0; u<2*ru->frame_parms.N_RB_DL; u++) { for (aarx=0; aarxnb_rx; aarx++) { for (aatx=0; aatxnb_tx; aatx++) { channelx = eNB2UE[3]->chF[aarx+(aatx*eNB2UE[3]->nb_rx)][u].x; @@ -237,11 +238,11 @@ void DL_channel(PHY_VARS_eNB *eNB,PHY_VARS_UE *UE,int subframe,int awgn_flag,dou //AWGN // tx_lev is the average energy over the whole subframe // but SNR should be better defined wrt the energy in the reference symbols - sigma2_dB = 10*log10((double)tx_lev) +10*log10((double)eNB->frame_parms.ofdm_symbol_size/(double)(eNB->frame_parms.N_RB_DL*12)) - SNR; + sigma2_dB = 10*log10((double)tx_lev) +10*log10((double)ru->frame_parms.ofdm_symbol_size/(double)(ru->frame_parms.N_RB_DL*12)) - SNR; sigma2 = pow(10,sigma2_dB/10); for (i=0; i<2*UE->frame_parms.samples_per_tti; i++) { - for (aa=0; aaframe_parms.nb_antennas_rx; aa++) { + for (aa=0; aaframe_parms.nb_antennas_rx; aa++) { //printf("s_re[0][%d]=> %f , r_re[0][%d]=> %f\n",i,s_re[aa][i],i,r_re[aa][i]); ((short*) UE->common_vars.rxdata[aa])[(2*subframe*UE->frame_parms.samples_per_tti)+2*i] = (short) (r_re[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); @@ -251,28 +252,118 @@ void DL_channel(PHY_VARS_eNB *eNB,PHY_VARS_UE *UE,int subframe,int awgn_flag,dou } } +uint16_t +fill_tx_req(nfapi_tx_request_body_t *tx_req_body, + uint16_t absSF, + uint16_t pdu_length, + uint16_t pdu_index, + uint8_t *pdu) +{ + nfapi_tx_request_pdu_t *TX_req = &tx_req_body->tx_pdu_list[tx_req_body->number_of_pdus]; + LOG_D(MAC, "Filling TX_req %d for pdu length %d\n", + tx_req_body->number_of_pdus, pdu_length); + + TX_req->pdu_length = pdu_length; + TX_req->pdu_index = pdu_index; + TX_req->num_segments = 1; + TX_req->segments[0].segment_length = pdu_length; + TX_req->segments[0].segment_data = pdu; + tx_req_body->tl.tag = NFAPI_TX_REQUEST_BODY_TAG; + tx_req_body->number_of_pdus++; + + return (((absSF / 10) << 4) + (absSF % 10)); +} + +void +fill_dlsch_config(nfapi_dl_config_request_body_t * dl_req, + uint16_t length, + uint16_t pdu_index, + uint16_t rnti, + uint8_t resource_allocation_type, + uint8_t virtual_resource_block_assignment_flag, + uint16_t resource_block_coding, + uint8_t modulation, + uint8_t redundancy_version, + uint8_t transport_blocks, + uint8_t transport_block_to_codeword_swap_flag, + uint8_t transmission_scheme, + uint8_t number_of_layers, + uint8_t number_of_subbands, + // uint8_t codebook_index, + uint8_t ue_category_capacity, + uint8_t pa, + uint8_t delta_power_offset_index, + uint8_t ngap, + uint8_t nprb, + uint8_t transmission_mode, + uint8_t num_bf_prb_per_subband, + uint8_t num_bf_vector) +{ + nfapi_dl_config_request_pdu_t *dl_config_pdu = + &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dlsch_pdu)); + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL8_TAG; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = length; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = pdu_index; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = rnti; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = resource_allocation_type; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = virtual_resource_block_assignment_flag; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = resource_block_coding; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = modulation; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = redundancy_version; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = transport_blocks; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = transport_block_to_codeword_swap_flag; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = transmission_scheme; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = number_of_layers; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = number_of_subbands; + // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = codebook_index; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = ue_category_capacity; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = pa; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = delta_power_offset_index; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = ngap; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = nprb; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = transmission_mode; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = num_bf_prb_per_subband; + dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = num_bf_vector; + dl_req->number_pdu++; +} void fill_DCI(PHY_VARS_eNB *eNB, - DCI_ALLOC_t *dci_alloc, + int frame, int subframe, + Sched_Rsp_t *sched_resp, + uint8_t input_buffer[NUMBER_OF_UE_MAX][20000], int n_rnti, int n_users, int transmission_mode, + int retrans, int common_flag, + int NB_RB, int DLSCH_RB_ALLOC, int TPC, int mcs1, int mcs2, int ndi, int rv, + int pa, int *num_common_dci, int *num_ue_spec_dci, int *num_dci) { int k; - int dci_length = -1,dci_length_bytes = -1; - // printf("Generating DCIs for %d users, TM %d, mcs1 %d\n",n_users,transmission_mode,mcs1); + nfapi_dl_config_request_body_t *dl_req=&sched_resp->DL_req->dl_config_request_body; + nfapi_dl_config_request_pdu_t *dl_config_pdu; + nfapi_tx_request_body_t *TX_req=&sched_resp->TX_req->tx_request_body; + + dl_req->number_dci=0; + dl_req->number_pdu=0; + TX_req->number_of_pdus=0; + for(k=0; kframe_parms.frame_type == TDD) { - - switch (eNB->frame_parms.N_RB_DL) { - case 6: - dci_length = sizeof_DCI1_1_5MHz_TDD_t; - dci_length_bytes = sizeof(DCI1_1_5MHz_TDD_t); - ((DCI1_1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI1_1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI1_1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI1_1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1_1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1_1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1_1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = ndi; - ((DCI1_1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv = rv; - break; - - case 25: - dci_length = sizeof_DCI1_5MHz_TDD_t; - dci_length_bytes = sizeof(DCI1_5MHz_TDD_t); - ((DCI1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = ndi; - ((DCI1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv = rv; - break; - - case 50: - dci_length = sizeof_DCI1_10MHz_TDD_t; - dci_length_bytes = sizeof(DCI1_10MHz_TDD_t); - ((DCI1_10MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI1_10MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI1_10MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI1_10MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1_10MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1_10MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1_10MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = ndi; - ((DCI1_10MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv = rv; - break; - - case 100: - ((DCI1_20MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI1_20MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI1_20MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI1_20MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1_20MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1_20MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1_20MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = ndi; - ((DCI1_20MHz_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv = rv; - dci_length = sizeof_DCI1_20MHz_TDD_t; - dci_length_bytes = sizeof(DCI1_20MHz_TDD_t); - break; - } - } else { - switch (eNB->frame_parms.N_RB_DL) { - case 6: - dci_length = sizeof_DCI1_1_5MHz_FDD_t; - dci_length_bytes = sizeof(DCI1_1_5MHz_FDD_t); - ((DCI1_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI1_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI1_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI1_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = ndi; - ((DCI1_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = rv; - break; - - case 25: - dci_length = sizeof_DCI1_5MHz_FDD_t; - dci_length_bytes = sizeof(DCI1_5MHz_FDD_t); - ((DCI1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = ndi; - ((DCI1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = rv; - break; - - case 50: - dci_length = sizeof_DCI1_10MHz_FDD_t; - dci_length_bytes = sizeof(DCI1_10MHz_FDD_t); - ((DCI1_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI1_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI1_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI1_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = ndi; - ((DCI1_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = rv; - break; - - case 100: - dci_length = sizeof_DCI1_20MHz_FDD_t; - dci_length_bytes = sizeof(DCI1_20MHz_FDD_t); - ((DCI1_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI1_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI1_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI1_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = ndi; - ((DCI1_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = rv; - break; - } - } - - memcpy(&dci_alloc[*num_dci].dci_pdu[0],&DLSCH_alloc_pdu_1[k],dci_length_bytes); - dci_alloc[*num_dci].dci_length = dci_length; - dci_alloc[*num_dci].L = 1; - dci_alloc[*num_dci].rnti = n_rnti+k; - dci_alloc[*num_dci].format = format1; - dci_alloc[*num_dci].search_space = DCI_UE_SPACE; - dump_dci(&eNB->frame_parms,&dci_alloc[*num_dci]); - - // printf("Generating dlsch params for user %d\n",k); - generate_eNB_dlsch_params_from_dci(0, - subframe, - &DLSCH_alloc_pdu_1[0], - n_rnti+k, - format1, - eNB->dlsch[0], - &eNB->frame_parms, - eNB->pdsch_config_dedicated, - SI_RNTI, - 0, - P_RNTI, - eNB->UE_stats[0].DL_pmi_single, - transmission_mode>=7?transmission_mode:0); - - *num_dci = *num_dci+1; - *num_ue_spec_dci = *num_ue_spec_dci+1; - } else { - if (eNB->frame_parms.frame_type == TDD) { - - switch (eNB->frame_parms.N_RB_DL) { - case 6: - dci_length = sizeof_DCI1A_1_5MHz_TDD_1_6_t; - dci_length_bytes = sizeof(DCI1A_1_5MHz_TDD_1_6_t); - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 0; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 25: - dci_length = sizeof_DCI1A_5MHz_TDD_1_6_t; - dci_length_bytes = sizeof(DCI1A_5MHz_TDD_1_6_t); - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 0; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 50: - dci_length = sizeof_DCI1A_10MHz_TDD_1_6_t; - dci_length_bytes = sizeof(DCI1A_10MHz_TDD_1_6_t); - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 100: - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - dci_length = sizeof_DCI1A_20MHz_TDD_1_6_t; - dci_length_bytes = sizeof(DCI1A_20MHz_TDD_1_6_t); - break; - } - } else { - switch (eNB->frame_parms.N_RB_DL) { - case 6: - dci_length = sizeof_DCI1A_1_5MHz_FDD_t; - dci_length_bytes = sizeof(DCI1A_1_5MHz_FDD_t); - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 25: - dci_length = sizeof_DCI1A_5MHz_FDD_t; - dci_length_bytes = sizeof(DCI1A_5MHz_FDD_t); - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 50: - dci_length = sizeof_DCI1A_10MHz_FDD_t; - dci_length_bytes = sizeof(DCI1A_10MHz_FDD_t); - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 100: - dci_length = sizeof_DCI1A_20MHz_FDD_t; - dci_length_bytes = sizeof(DCI1A_20MHz_FDD_t); - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - } - } - - memcpy(&dci_alloc[*num_dci].dci_pdu[0],&DLSCH_alloc_pdu_1[k],dci_length_bytes); - dci_alloc[*num_dci].dci_length = dci_length; - dci_alloc[*num_dci].L = 1; - dci_alloc[*num_dci].rnti = SI_RNTI; - dci_alloc[*num_dci].format = format1A; - dci_alloc[*num_dci].firstCCE = 0; - dci_alloc[*num_dci].search_space = DCI_COMMON_SPACE; - dump_dci(&eNB->frame_parms,&dci_alloc[*num_dci]); - - printf("Generating dlsch params for user %d\n",k); - generate_eNB_dlsch_params_from_dci(0, - subframe, - &DLSCH_alloc_pdu_1[0], - SI_RNTI, - format1A, - eNB->dlsch[0], - &eNB->frame_parms, - eNB->pdsch_config_dedicated, - SI_RNTI, - 0, - P_RNTI, - eNB->UE_stats[0].DL_pmi_single, - transmission_mode>=7?transmission_mode:0); - - *num_common_dci=*num_common_dci+1; - *num_dci = *num_dci + 1; - - } - - break; - - case 3: - if (common_flag == 0) { - - if (eNB->frame_parms.nb_antennas_tx == 2) { - - if (eNB->frame_parms.frame_type == TDD) { - - switch (eNB->frame_parms.N_RB_DL) { - case 6: - dci_length = sizeof_DCI2A_1_5MHz_2A_TDD_t; - dci_length_bytes = sizeof(DCI2A_1_5MHz_2A_TDD_t); - ((DCI2A_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2A_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2A_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI2A_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2A_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2A_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2A_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2A_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2A_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2A_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - break; - - case 25: - dci_length = sizeof_DCI2A_5MHz_2A_TDD_t; - dci_length_bytes = sizeof(DCI2A_5MHz_2A_TDD_t); - ((DCI2A_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI2A_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2A_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2A_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI2A_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2A_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2A_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2A_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2A_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2A_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2A_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - break; - - case 50: - dci_length = sizeof_DCI2A_10MHz_2A_TDD_t; - dci_length_bytes = sizeof(DCI2A_10MHz_2A_TDD_t); - ((DCI2A_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI2A_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2A_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2A_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI2A_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2A_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2A_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2A_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2A_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2A_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2A_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - break; - - case 100: - ((DCI2A_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI2A_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2A_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2A_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI2A_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2A_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2A_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2A_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2A_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2A_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2A_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - dci_length = sizeof_DCI2A_20MHz_2A_TDD_t; - dci_length_bytes = sizeof(DCI2A_20MHz_2A_TDD_t); - break; - } - } - - else { - switch (eNB->frame_parms.N_RB_DL) { - case 6: - dci_length = sizeof_DCI2A_1_5MHz_2A_FDD_t; - dci_length_bytes = sizeof(DCI2A_1_5MHz_2A_FDD_t); - ((DCI2A_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2A_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2A_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2A_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2A_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2A_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2A_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2A_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2A_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - break; - - case 25: - dci_length = sizeof_DCI2A_5MHz_2A_FDD_t; - dci_length_bytes = sizeof(DCI2A_5MHz_2A_FDD_t); - ((DCI2A_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI2A_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2A_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2A_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2A_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2A_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2A_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2A_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2A_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2A_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - break; - - case 50: - dci_length = sizeof_DCI2A_10MHz_2A_FDD_t; - dci_length_bytes = sizeof(DCI2A_10MHz_2A_FDD_t); - ((DCI2A_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI2A_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2A_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2A_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2A_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2A_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2A_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2A_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2A_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2A_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - break; - - case 100: - dci_length = sizeof_DCI2A_20MHz_2A_FDD_t; - dci_length_bytes = sizeof(DCI2A_20MHz_2A_FDD_t); - ((DCI2A_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI2A_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2A_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2A_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2A_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2A_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2A_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2A_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2A_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2A_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - break; - } - } - } else if (eNB->frame_parms.nb_antennas_tx == 4) { - - } - - memcpy(&dci_alloc[*num_dci].dci_pdu[0],&DLSCH_alloc_pdu_1[k],dci_length_bytes); - dci_alloc[*num_dci].dci_length = dci_length; - dci_alloc[*num_dci].L = 1; - dci_alloc[*num_dci].rnti = n_rnti+k; - dci_alloc[*num_dci].format = format2A; - dci_alloc[*num_dci].search_space = DCI_UE_SPACE; - dump_dci(&eNB->frame_parms,&dci_alloc[*num_dci]); - - //printf("Generating dlsch params for user %d / format 2A (%d)\n",k,format2A); - generate_eNB_dlsch_params_from_dci(0, - subframe, - &DLSCH_alloc_pdu_1[0], - n_rnti+k, - format2A, - eNB->dlsch[0], - &eNB->frame_parms, - eNB->pdsch_config_dedicated, - SI_RNTI, - 0, - P_RNTI, - eNB->UE_stats[0].DL_pmi_single, - transmission_mode>=7?transmission_mode:0); - - *num_dci = *num_dci + 1; - *num_ue_spec_dci = *num_ue_spec_dci + 1; - } else { - if (eNB->frame_parms.frame_type == TDD) { - - switch (eNB->frame_parms.N_RB_DL) { - case 6: - dci_length = sizeof_DCI1A_1_5MHz_TDD_1_6_t; - dci_length_bytes = sizeof(DCI1A_1_5MHz_TDD_1_6_t); - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 0; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 25: - dci_length = sizeof_DCI1A_5MHz_TDD_1_6_t; - dci_length_bytes = sizeof(DCI1A_5MHz_TDD_1_6_t); - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 0; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 50: - dci_length = sizeof_DCI1A_10MHz_TDD_1_6_t; - dci_length_bytes = sizeof(DCI1A_10MHz_TDD_1_6_t); - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 100: - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - dci_length = sizeof_DCI1A_20MHz_TDD_1_6_t; - dci_length_bytes = sizeof(DCI1A_20MHz_TDD_1_6_t); - break; - } - } else { - switch (eNB->frame_parms.N_RB_DL) { - case 6: - dci_length = sizeof_DCI1A_1_5MHz_FDD_t; - dci_length_bytes = sizeof(DCI1A_1_5MHz_FDD_t); - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 25: - dci_length = sizeof_DCI1A_5MHz_FDD_t; - dci_length_bytes = sizeof(DCI1A_5MHz_FDD_t); - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 50: - dci_length = sizeof_DCI1A_10MHz_FDD_t; - dci_length_bytes = sizeof(DCI1A_10MHz_FDD_t); - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 100: - dci_length = sizeof_DCI1A_20MHz_FDD_t; - dci_length_bytes = sizeof(DCI1A_20MHz_FDD_t); - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - } - } - - memcpy(&dci_alloc[*num_dci].dci_pdu[0],&DLSCH_alloc_pdu_1[k],dci_length_bytes); - dci_alloc[*num_dci].dci_length = dci_length; - dci_alloc[*num_dci].L = 1; - dci_alloc[*num_dci].rnti = SI_RNTI; - dci_alloc[*num_dci].format = format1A; - dci_alloc[*num_dci].firstCCE = 0; - dci_alloc[*num_dci].search_space = DCI_COMMON_SPACE; - dump_dci(&eNB->frame_parms,&dci_alloc[*num_dci]); - - //printf("Generating dlsch params for user %d\n",k); - generate_eNB_dlsch_params_from_dci(0, - subframe, - &DLSCH_alloc_pdu_1[0], - SI_RNTI, - format1A, - eNB->dlsch[0], - &eNB->frame_parms, - eNB->pdsch_config_dedicated, - SI_RNTI, - 0, - P_RNTI, - eNB->UE_stats[0].DL_pmi_single, - transmission_mode>=7?transmission_mode:0); - - *num_common_dci = *num_common_dci + 1; - *num_dci = *num_dci + 1; - - } - - //printf("Generated DCI format 2A (Transmission Mode 3)\n"); - break; - - case 4: - if (common_flag == 0) { - - if (eNB->frame_parms.nb_antennas_tx == 2) { - - if (eNB->frame_parms.frame_type == TDD) { - - switch (eNB->frame_parms.N_RB_DL) { - case 6: - dci_length = sizeof_DCI2_1_5MHz_2A_TDD_t; - dci_length_bytes = sizeof(DCI2_1_5MHz_2A_TDD_t); - ((DCI2_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI2_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2_1_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - break; - - case 25: - dci_length = sizeof_DCI2_5MHz_2A_TDD_t; - dci_length_bytes = sizeof(DCI2_5MHz_2A_TDD_t); - ((DCI2_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI2_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI2_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2_5MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - break; - - case 50: - dci_length = sizeof_DCI2_10MHz_2A_TDD_t; - dci_length_bytes = sizeof(DCI2_10MHz_2A_TDD_t); - ((DCI2_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI2_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI2_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2_10MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - break; - - case 100: - ((DCI2_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI2_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI2_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2_20MHz_2A_TDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - dci_length = sizeof_DCI2_20MHz_2A_TDD_t; - dci_length_bytes = sizeof(DCI2_20MHz_2A_TDD_t); - break; - } - } - - else { - switch (eNB->frame_parms.N_RB_DL) { - case 6: - dci_length = sizeof_DCI2_1_5MHz_2A_FDD_t; - dci_length_bytes = sizeof(DCI2_1_5MHz_2A_FDD_t); - ((DCI2_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2_1_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - break; - - case 25: - dci_length = sizeof_DCI2_5MHz_2A_FDD_t; - dci_length_bytes = sizeof(DCI2_5MHz_2A_FDD_t); - ((DCI2_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI2_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2_5MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - break; - - case 50: - dci_length = sizeof_DCI2_10MHz_2A_FDD_t; - dci_length_bytes = sizeof(DCI2_10MHz_2A_FDD_t); - ((DCI2_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI2_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2_10MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - break; - - case 100: - dci_length = sizeof_DCI2_20MHz_2A_FDD_t; - dci_length_bytes = sizeof(DCI2_20MHz_2A_FDD_t); - ((DCI2_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rah = 0; - ((DCI2_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = DLSCH_RB_ALLOC; - ((DCI2_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = 0; - ((DCI2_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI2_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs1 = mcs1; - ((DCI2_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi1 = ndi; - ((DCI2_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv1 = rv; - ((DCI2_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs2 = mcs2; - ((DCI2_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi2 = ndi; - ((DCI2_20MHz_2A_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv2 = rv; - break; - } - } - } else if (eNB->frame_parms.nb_antennas_tx == 4) { - - } - - memcpy(&dci_alloc[*num_dci].dci_pdu[0],&DLSCH_alloc_pdu_1[k],dci_length_bytes); - dci_alloc[*num_dci].dci_length = dci_length; - dci_alloc[*num_dci].L = 1; - dci_alloc[*num_dci].rnti = n_rnti+k; - dci_alloc[*num_dci].format = format2; - dci_alloc[*num_dci].search_space = DCI_UE_SPACE; - dump_dci(&eNB->frame_parms,&dci_alloc[*num_dci]); - - printf("Generating dlsch params for user %d\n",k); - generate_eNB_dlsch_params_from_dci(0, - subframe, - &DLSCH_alloc_pdu_1[0], - n_rnti+k, - format2, - eNB->dlsch[0], - &eNB->frame_parms, - eNB->pdsch_config_dedicated, - SI_RNTI, - 0, - P_RNTI, - eNB->UE_stats[0].DL_pmi_single, - transmission_mode>=7?transmission_mode:0); - - *num_dci = *num_dci + 1; - *num_ue_spec_dci = *num_ue_spec_dci + 1; - } else { - if (eNB->frame_parms.frame_type == TDD) { - - switch (eNB->frame_parms.N_RB_DL) { - case 6: - dci_length = sizeof_DCI1A_1_5MHz_TDD_1_6_t; - dci_length_bytes = sizeof(DCI1A_1_5MHz_TDD_1_6_t); - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 0; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_1_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 25: - dci_length = sizeof_DCI1A_5MHz_TDD_1_6_t; - dci_length_bytes = sizeof(DCI1A_5MHz_TDD_1_6_t); - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 0; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_5MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 50: - dci_length = sizeof_DCI1A_10MHz_TDD_1_6_t; - dci_length_bytes = sizeof(DCI1A_10MHz_TDD_1_6_t); - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_10MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 100: - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->dai = 0; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_20MHz_TDD_1_6_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - dci_length = sizeof_DCI1A_20MHz_TDD_1_6_t; - dci_length_bytes = sizeof(DCI1A_20MHz_TDD_1_6_t); - break; - } - } else { - switch (eNB->frame_parms.N_RB_DL) { - case 6: - dci_length = sizeof_DCI1A_1_5MHz_FDD_t; - dci_length_bytes = sizeof(DCI1A_1_5MHz_FDD_t); - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 25: - dci_length = sizeof_DCI1A_5MHz_FDD_t; - dci_length_bytes = sizeof(DCI1A_5MHz_FDD_t); - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 50: - dci_length = sizeof_DCI1A_10MHz_FDD_t; - dci_length_bytes = sizeof(DCI1A_10MHz_FDD_t); - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_10MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - - case 100: - dci_length = sizeof_DCI1A_20MHz_FDD_t; - dci_length_bytes = sizeof(DCI1A_20MHz_FDD_t); - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->type = 1; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->vrb_type = 1; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rballoc = computeRIV(eNB->frame_parms.N_RB_DL,0,9); - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->TPC = TPC; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->harq_pid = 0; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->mcs = mcs1; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->ndi = 0; - ((DCI1A_20MHz_FDD_t *)&DLSCH_alloc_pdu_1[k])->rv = 0; - break; - } - } - - memcpy(&dci_alloc[*num_dci].dci_pdu[0],&DLSCH_alloc_pdu_1[k],dci_length_bytes); - dci_alloc[*num_dci].dci_length = dci_length; - dci_alloc[*num_dci].L = 1; - dci_alloc[*num_dci].rnti = SI_RNTI; - dci_alloc[*num_dci].format = format1A; - dci_alloc[*num_dci].firstCCE = 0; - dci_alloc[*num_dci].search_space = DCI_COMMON_SPACE; - dump_dci(&eNB->frame_parms,&dci_alloc[*num_dci]); - - printf("Generating dlsch params for user %d\n",k); - generate_eNB_dlsch_params_from_dci(0, - subframe, - &DLSCH_alloc_pdu_1[0], - SI_RNTI, - format1A, - eNB->dlsch[0], - &eNB->frame_parms, - eNB->pdsch_config_dedicated, - SI_RNTI, - 0, - P_RNTI, - eNB->UE_stats[0].DL_pmi_single, - transmission_mode>=7?transmission_mode:0); - - *num_common_dci = *num_common_dci + 1; - *num_dci = *num_dci + 1; + dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; + memset((void *) dl_config_pdu, 0, + sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = 4; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = n_rnti+k; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = TPC; // dont adjust power when retransmitting + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = ndi; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs1; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = rv; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = DLSCH_RB_ALLOC; + //deactivate second codeword + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_2 = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_2 = 1; + + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.downlink_assignment_index = 0; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx = 0; + + dl_req->number_dci++; + dl_req->number_pdu++; + dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + + + fill_dlsch_config(dl_req, + get_TBS_DL(mcs1,NB_RB), + (retrans > 0) ? -1 : 0, /* retransmission, no pdu_index */ + n_rnti, + 0, // type 0 allocation from 7.1.6 in 36.213 + 0, // virtual_resource_block_assignment_flag, unused here + DLSCH_RB_ALLOC, // resource_block_coding, + get_Qm(mcs1), + rv, // redundancy version + 1, // transport blocks + 0, // transport block to codeword swap flag + transmission_mode == 1 ? 0 : 1, // transmission_scheme + 1, // number of layers + 1, // number of subbands + // uint8_t codebook_index, + 4, // UE category capacity + pa, // pa + 0, // delta_power_offset for TM5 + 0, // ngap + 0, // nprb + transmission_mode, + 0, //number of PRBs treated as one subband, not used here + 0 // number of beamforming vectors, not used here + ); + fill_tx_req(TX_req, + (frame * 10) + subframe, + get_TBS_DL(mcs1,NB_RB), + 0, + input_buffer[k]); + } + else { + + } + + break; + + case 3: + if (common_flag == 0) { + + if (eNB->frame_parms.nb_antennas_tx == 2) { + + if (eNB->frame_parms.frame_type == TDD) { + + } + else { + + } + } + } + break; + + case 4: + if (common_flag == 0) { + + if (eNB->frame_parms.nb_antennas_tx == 2) { + + if (eNB->frame_parms.frame_type == TDD) { + + + } + + else { + + } + } else if (eNB->frame_parms.nb_antennas_tx == 4) { + + } + + } + else { } @@ -1186,90 +480,31 @@ void fill_DCI(PHY_VARS_eNB *eNB, case 5: case 6: - memcpy(&dci_alloc[*num_dci].dci_pdu[0],&DLSCH_alloc_pdu2_1E[k],sizeof(DCI1E_5MHz_2A_M10PRB_TDD_t)); - dci_alloc[*num_dci].dci_length = sizeof_DCI1E_5MHz_2A_M10PRB_TDD_t; - dci_alloc[*num_dci].L = 1; - dci_alloc[*num_dci].rnti = n_rnti+k; - dci_alloc[*num_dci].format = format1E_2A_M10PRB; - dci_alloc[*num_dci].firstCCE = 4*k; - dci_alloc[*num_dci].search_space = DCI_UE_SPACE; - printf("Generating dlsch params for user %d\n",k); - generate_eNB_dlsch_params_from_dci(0, - subframe, - &DLSCH_alloc_pdu2_1E[k], - n_rnti+k, - format1E_2A_M10PRB, - eNB->dlsch[k], - &eNB->frame_parms, - eNB->pdsch_config_dedicated, - SI_RNTI, - 0, - P_RNTI, - eNB->UE_stats[k].DL_pmi_single, - transmission_mode>=7?transmission_mode:0); - - dump_dci(&eNB->frame_parms,&dci_alloc[*num_dci]); - *num_ue_spec_dci = *num_ue_spec_dci + 1; - *num_dci = *num_dci + 1; break; - default: - printf("Unsupported Transmission Mode!!!"); - exit(-1); - break; - } + default: + printf("Unsupported Transmission Mode %d!!!\n",transmission_mode); + exit(-1); + break; } + } + *num_dci = dl_req->number_dci; + *num_ue_spec_dci = dl_req->number_dci; + *num_common_dci = 0; } int n_users = 1; sub_frame_t subframe=7; -DCI_PDU DCI_pdu; int num_common_dci=0,num_ue_spec_dci=0,num_dci=0,num_pdcch_symbols=1; - - -DCI_PDU *get_dci_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subframeP) { - - if (subframeP == subframe) { - DCI_pdu.Num_dci = num_ue_spec_dci + num_common_dci; - DCI_pdu.num_pdcch_symbols = num_pdcch_symbols; - } else { - DCI_pdu.Num_dci = 0; - DCI_pdu.num_pdcch_symbols = num_pdcch_symbols; - } - - return &DCI_pdu; -} - -void eNB_dlsch_ulsch_scheduler(module_id_t module_idP, uint8_t cooperation_flag, frame_t frameP, sub_frame_t subframeP) { - - return; -} - uint16_t n_rnti=0x1234; -unsigned char *input_buffer0[2],*input_buffer1[2]; -unsigned short input_buffer_length0,input_buffer_length1; - -uint8_t *get_dlsch_sdu(module_id_t module_idP,int CC_id,frame_t frameP,rnti_t rnti,uint8_t TBindex) { - - int k; - - for (k=0;kuse_ia_receiver = 1; if ((n_tx_port!=2) || (transmission_mode!=5)) { - msg("IA receiver only supported for TM5!"); + printf("IA receiver only supported for TM5!"); exit(-1); } @@ -1644,7 +910,7 @@ int main(int argc, char **argv) i_mod = atoi(optarg); if (i_mod!=2 && i_mod!=4 && i_mod!=6) { - msg("Wrong i_mod %d, should be 2,4 or 6\n",i_mod); + printf("Wrong i_mod %d, should be 2,4 or 6\n",i_mod); exit(-1); } @@ -1658,7 +924,7 @@ int main(int argc, char **argv) n_tx_port=atoi(optarg); if ((n_tx_port==0) || ((n_tx_port>2))) { - msg("Unsupported number of cell specific antennas ports %d\n",n_tx_port); + printf("Unsupported number of cell specific antennas ports %d\n",n_tx_port); exit(-1); } @@ -1675,7 +941,7 @@ int main(int argc, char **argv) (transmission_mode!=5) && (transmission_mode!=6) && (transmission_mode!=7)) { - msg("Unsupported transmission mode %d\n",transmission_mode); + printf("Unsupported transmission mode %d\n",transmission_mode); exit(-1); } @@ -1689,17 +955,17 @@ int main(int argc, char **argv) n_tx_phy=atoi(optarg); if (n_tx_phy < n_tx_port) { - msg("n_tx_phy mush not be smaller than n_tx_port"); + printf("n_tx_phy mush not be smaller than n_tx_port"); exit(-1); } if ((transmission_mode>1 && transmission_mode<7) && n_tx_port<2) { - msg("n_tx_port must be >1 for transmission_mode %d\n",transmission_mode); + printf("n_tx_port must be >1 for transmission_mode %d\n",transmission_mode); exit(-1); } if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=8 && n_tx_phy!=16 && n_tx_phy!=64 && n_tx_phy!=128)) { - msg("Physical number of antennas not supported for TM7.\n"); + printf("Physical number of antennas not supported for TM7.\n"); exit(-1); } @@ -1718,7 +984,7 @@ int main(int argc, char **argv) n_rx=atoi(optarg); if ((n_rx==0) || (n_rx>2)) { - msg("Unsupported number of rx antennas %d\n",n_rx); + printf("Unsupported number of rx antennas %d\n",n_rx); exit(-1); } @@ -1770,9 +1036,14 @@ int main(int argc, char **argv) } } + if (transmission_mode>1) pa=dBm3; + printf("dlsim: tmode %d, pa %d\n",transmission_mode,pa); + + AssertFatal(load_configmodule(argc,argv) != NULL, + "cannot load configuration module, exiting\n"); logInit(); // enable these lines if you need debug info - set_comp_log(PHY,LOG_DEBUG,LOG_HIGH,1); + set_comp_log(PHY,LOG_INFO,LOG_HIGH,1); set_glog(log_level,LOG_HIGH); // moreover you need to init itti with the following line // however itti will catch all signals, so ctrl-c won't work anymore @@ -1822,8 +1093,11 @@ int main(int argc, char **argv) n_users = 2; printf("dual_stream_UE=%d\n", dual_stream_UE); } + RC.nb_L1_inst = 1; + RC.nb_RU = 1; - lte_param_init(n_tx_port, + lte_param_init(&eNB,&UE,&ru, + n_tx_port, n_tx_phy, n_rx, transmission_mode, @@ -1832,20 +1106,26 @@ int main(int argc, char **argv) Nid_cell, tdd_config, N_RB_DL, + pa, threequarter_fs, osf, perfect_ce); - + RC.eNB = (PHY_VARS_eNB ***)malloc(sizeof(PHY_VARS_eNB **)); + RC.eNB[0] = (PHY_VARS_eNB **)malloc(sizeof(PHY_VARS_eNB *)); + RC.ru = (RU_t **)malloc(sizeof(RC.ru)); + RC.eNB[0][0] = eNB; + RC.ru[0] = ru; + printf("lte_param_init done\n"); if ((transmission_mode==1) || (transmission_mode==7)) { - for (aa=0; aaframe_parms.nb_antennas_tx; aa++) - for (re=0; reframe_parms.ofdm_symbol_size; re++) - eNB->common_vars.beam_weights[0][0][aa][re] = 0x00007fff/eNB->frame_parms.nb_antennas_tx; + for (aa=0; aanb_tx; aa++) + for (re=0; reframe_parms.ofdm_symbol_size; re++) + ru->beam_weights[0][0][aa][re] = 0x00007fff/eNB->frame_parms.nb_antennas_tx; } if (transmission_mode<7) - eNB->do_precoding=0; + ru->do_precoding=0; else - eNB->do_precoding=1; + ru->do_precoding=1; eNB->mac_enabled=1; if (two_thread_flag == 0) { @@ -1860,9 +1140,6 @@ int main(int argc, char **argv) } // callback functions required for phy_procedures_tx - mac_xface->get_dci_sdu = get_dci_sdu; - mac_xface->get_dlsch_sdu = get_dlsch_sdu; - mac_xface->eNB_dlsch_ulsch_scheduler = eNB_dlsch_ulsch_scheduler; // eNB_id_i = UE->n_connected_eNB; @@ -1875,7 +1152,10 @@ int main(int argc, char **argv) snr1 = snr0+snr_int; printf("SNR0 %f, SNR1 %f\n",snr0,snr1); + uint8_t input_buffer[NUMBER_OF_UE_MAX][20000]; + for (i=0;iframe_parms; @@ -2024,48 +1304,6 @@ int main(int argc, char **argv) UE->pdcch_vars[UE->current_thread_id[subframe]][0]->crnti = n_rnti; - // Fill in UL_alloc - UL_alloc_pdu.type = 0; - UL_alloc_pdu.hopping = 0; - UL_alloc_pdu.rballoc = UL_RB_ALLOC; - UL_alloc_pdu.mcs = 1; - UL_alloc_pdu.ndi = 1; - UL_alloc_pdu.TPC = 0; - UL_alloc_pdu.cqi_req = 1; - - CCCH_alloc_pdu.type = 0; - CCCH_alloc_pdu.vrb_type = 0; - CCCH_alloc_pdu.rballoc = CCCH_RB_ALLOC; - CCCH_alloc_pdu.ndi = 1; - CCCH_alloc_pdu.mcs = 1; - CCCH_alloc_pdu.harq_pid = 0; - - DLSCH_alloc_pdu2_1E[0].rah = 0; - DLSCH_alloc_pdu2_1E[0].rballoc = DLSCH_RB_ALLOC; - DLSCH_alloc_pdu2_1E[0].TPC = 0; - DLSCH_alloc_pdu2_1E[0].dai = 0; - DLSCH_alloc_pdu2_1E[0].harq_pid = 0; - //DLSCH_alloc_pdu2_1E[0].tb_swap = 0; - DLSCH_alloc_pdu2_1E[0].mcs = mcs1; - DLSCH_alloc_pdu2_1E[0].ndi = 1; - DLSCH_alloc_pdu2_1E[0].rv = 0; - // Forget second codeword - DLSCH_alloc_pdu2_1E[0].tpmi = (transmission_mode>=5 ? 5 : 0); // precoding - DLSCH_alloc_pdu2_1E[0].dl_power_off = (transmission_mode==5 ? 0 : 1); - - DLSCH_alloc_pdu2_1E[1].rah = 0; - DLSCH_alloc_pdu2_1E[1].rballoc = DLSCH_RB_ALLOC; - DLSCH_alloc_pdu2_1E[1].TPC = 0; - DLSCH_alloc_pdu2_1E[1].dai = 0; - DLSCH_alloc_pdu2_1E[1].harq_pid = 0; - //DLSCH_alloc_pdu2_1E[1].tb_swap = 0; - DLSCH_alloc_pdu2_1E[1].mcs = mcs_i; - DLSCH_alloc_pdu2_1E[1].ndi = 1; - DLSCH_alloc_pdu2_1E[1].rv = 0; - // Forget second codeword - DLSCH_alloc_pdu2_1E[1].tpmi = (transmission_mode>=5 ? 5 : 0) ; // precoding - DLSCH_alloc_pdu2_1E[1].dl_power_off = (transmission_mode==5 ? 0 : 1); - eNB2UE[0] = new_channel_desc_scm(eNB->frame_parms.nb_antennas_tx, UE->frame_parms.nb_antennas_rx, channel_model, @@ -2088,7 +1326,7 @@ int main(int argc, char **argv) } if (eNB2UE[0]==NULL) { - msg("Problem generating channel model. Exiting.\n"); + printf("Problem generating channel model. Exiting.\n"); exit(-1); } @@ -2114,7 +1352,7 @@ int main(int argc, char **argv) break; } - for (k=0; kdlsch[k][i] = new_eNB_dlsch(Kmimo,8,Nsoft,N_RB_DL,0,&eNB->frame_parms); @@ -2166,24 +1404,31 @@ int main(int argc, char **argv) eNB->UE_stats[1].DL_pmi_single = 0; } + eNB_rxtx_proc_t *proc_eNB = &eNB->proc.proc_rxtx[0];//UE->current_thread_id[subframe]]; if (input_fd==NULL) { - + DL_req.dl_config_request_body.number_pdcch_ofdm_symbols = num_pdcch_symbols; + DL_req.sfn_sf = (proc_eNB->frame_tx*10)+subframe; + TX_req.sfn_sf = (proc_eNB->frame_tx*10)+subframe; // UE specific DCI fill_DCI(eNB, - &dci_alloc[0], - subframe, + proc_eNB->frame_tx,subframe, + &sched_resp, + input_buffer, n_rnti, n_users, transmission_mode, + 0, common_flag, + NB_RB, DLSCH_RB_ALLOC, TPC, mcs1, mcs2, 1, 0, + pa, &num_common_dci, &num_ue_spec_dci, &num_dci); @@ -2194,65 +1439,8 @@ int main(int argc, char **argv) - - for (k=0; kdlsch[k][0]->harq_processes[0]->TBS/8; - input_buffer0[k] = (unsigned char *)malloc(input_buffer_length0+4); - memset(input_buffer0[k],0,input_buffer_length0+4); - input_buffer_length1 = eNB->dlsch[k][1]->harq_processes[0]->TBS/8; - input_buffer1[k] = (unsigned char *)malloc(input_buffer_length1+4); - memset(input_buffer1[k],0,input_buffer_length1+4); - - if (input_trch_file==0) { - for (i=0; i>3]+=(1<<(7-(i&7))); - - if (i<16) - printf("input_trch_val %d : %c\n",i,input_trch_val[0]); - - i++; - - if (((i%8) == 0) && (i<17)) - printf("%x\n",input_buffer0[k][(i-1)>>3]); - } - - printf("Read in %d bits\n",i); - } - } } - // this is for user 0 only - coded_bits_per_codeword = get_G(&eNB->frame_parms, - eNB->dlsch[0][0]->harq_processes[0]->nb_rb, - eNB->dlsch[0][0]->harq_processes[0]->rb_alloc, - get_Qm(eNB->dlsch[0][0]->harq_processes[0]->mcs), - eNB->dlsch[0][0]->harq_processes[0]->Nl, - num_pdcch_symbols, - 0, - subframe, - transmission_mode>=7?transmission_mode:0); - - uncoded_ber_bit = (short*) malloc(sizeof(short)*coded_bits_per_codeword); - printf("uncoded_ber_bit=%p\n",uncoded_ber_bit); - snr_step = input_snr_step; UE->high_speed_flag = 1; UE->ch_est_alpha=0; @@ -2332,7 +1520,7 @@ int main(int argc, char **argv) struct list time_vector_rx_dec; initialize(&time_vector_rx_dec); - eNB_rxtx_proc_t *proc_eNB = &eNB->proc.proc_rxtx[UE->current_thread_id[subframe]]; + for (trials = 0; trialsframe_parms.nb_antennas_tx; aa++) { - memset(&eNB->common_vars.txdataF[eNB_id][aa][0],0,FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(int32_t)); + memset(&eNB->common_vars.txdataF[aa][0],0,FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(int32_t)); } if (input_fd==NULL) { @@ -2383,108 +1571,73 @@ int main(int argc, char **argv) TB0_active = 1; eNB->dlsch[0][0]->harq_processes[0]->rvidx = round&3; - - fill_DCI(eNB,&dci_alloc[0],subframe,n_rnti,n_users,transmission_mode,common_flag,DLSCH_RB_ALLOC,TPC, - mcs1,mcs2,!(trials&1),round&3,&num_common_dci,&num_ue_spec_dci,&num_dci); + DL_req.sfn_sf = (proc_eNB->frame_tx<<4)+subframe; + TX_req.sfn_sf = (proc_eNB->frame_tx<<4)+subframe; + fill_DCI(eNB,proc_eNB->frame_tx,subframe,&sched_resp,input_buffer,n_rnti,n_users,transmission_mode,0,common_flag,NB_RB,DLSCH_RB_ALLOC,TPC, + mcs1,mcs2,!(trials&1),round&3,pa,&num_common_dci,&num_ue_spec_dci,&num_dci); } else { - fill_DCI(eNB,&dci_alloc[0],subframe,n_rnti,n_users,transmission_mode,common_flag,DLSCH_RB_ALLOC,TPC, - (TB0_active==1)?mcs1:0,mcs2,!(trials&1),(TB0_active==1)?round&3:0,&num_common_dci,&num_ue_spec_dci,&num_dci); + DL_req.sfn_sf = (proc_eNB->frame_tx<<4)+subframe; + TX_req.sfn_sf = (proc_eNB->frame_tx<<4)+subframe; + fill_DCI(eNB,proc_eNB->frame_tx,subframe,&sched_resp,input_buffer,n_rnti,n_users,transmission_mode,1,common_flag,NB_RB,DLSCH_RB_ALLOC,TPC, + (TB0_active==1)?mcs1:0,mcs2,!(trials&1),(TB0_active==1)?round&3:0,pa,&num_common_dci,&num_ue_spec_dci,&num_dci); } - for (i=num_common_dci; i %e + j%e (%d +j%d)\n",i/4,strtod(input_val_str,NULL),strtod(input_val_str2,NULL),((short*)txdata[0])[i/4],((short*)txdata[0])[(i/4)+1]);//1,input_val2,); - } - i++; - if (i>(FRAME_LENGTH_SAMPLES)) - break; - } - printf("Read in %d samples\n",i/4); - write_output("txsig0.m","txs0", txdata[0],2*frame_parms->samples_per_tti,1,1); - // write_output("txsig1.m","txs1", txdata[1],FRAME_LENGTH_COMPLEX_SAMPLES,1,1); - tx_lev = signal_energy(&txdata[0][0], - OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES); - tx_lev_dB = (unsigned int) dB_fixed(tx_lev); - } - */ - - + } + proc_eNB->subframe_tx = subframe; + sched_resp.subframe=subframe; + sched_resp.frame=proc_eNB->frame_tx; + eNB->abstraction_flag=0; + schedule_response(&sched_resp); + phy_procedures_eNB_TX(eNB,proc_eNB,no_relay,NULL,1); - phy_procedures_eNB_TX(eNB,proc_eNB,no_relay,NULL,1,dci_flag); + if (uncoded_ber_bit == NULL) { + // this is for user 0 only + printf("nb_rb %d, rb_alloc %x, mcs %d\n", + eNB->dlsch[0][0]->harq_processes[0]->nb_rb, + eNB->dlsch[0][0]->harq_processes[0]->rb_alloc, + eNB->dlsch[0][0]->harq_processes[0]->mcs); + coded_bits_per_codeword = get_G(&eNB->frame_parms, + eNB->dlsch[0][0]->harq_processes[0]->nb_rb, + eNB->dlsch[0][0]->harq_processes[0]->rb_alloc, + get_Qm(eNB->dlsch[0][0]->harq_processes[0]->mcs), + eNB->dlsch[0][0]->harq_processes[0]->Nl, + num_pdcch_symbols, + 0, + subframe, + transmission_mode>=7?transmission_mode:0); + + uncoded_ber_bit = (short*) malloc(sizeof(short)*coded_bits_per_codeword); + printf("uncoded_ber_bit=%p\n",uncoded_ber_bit); + } start_meas(&eNB->ofdm_mod_stats); - /* - do_OFDM_mod_l(eNB->common_vars.txdataF[eNB_id], - eNB->common_vars.txdata[eNB_id], - (subframe*2), - &eNB->frame_parms); - - do_OFDM_mod_l(eNB->common_vars.txdataF[eNB_id], - eNB->common_vars.txdata[eNB_id], - (subframe*2)+1, - &eNB->frame_parms); - */ - - do_OFDM_mod_symbol(&eNB->common_vars, - eNB_id, - (subframe*2), - &eNB->frame_parms, - eNB->do_precoding); - - do_OFDM_mod_symbol(&eNB->common_vars, - eNB_id, - (subframe*2)+1, - &eNB->frame_parms, - eNB->do_precoding); - + ru->proc.subframe_tx=subframe; + memcpy((void*)&ru->frame_parms,(void*)&eNB->frame_parms,sizeof(LTE_DL_FRAME_PARMS)); + feptx_prec(ru); + feptx_ofdm(ru); stop_meas(&eNB->ofdm_mod_stats); + + // generate next subframe for channel estimation + DL_req.dl_config_request_body.number_dci=0; + DL_req.dl_config_request_body.number_pdu=0; + TX_req.tx_request_body.number_of_pdus=0; proc_eNB->subframe_tx = subframe+1; + sched_resp.subframe=subframe+1; + schedule_response(&sched_resp); + phy_procedures_eNB_TX(eNB,proc_eNB,no_relay,NULL,0); - phy_procedures_eNB_TX(eNB,proc_eNB,no_relay,NULL,0,dci_flag); - do_OFDM_mod_l(eNB->common_vars.txdataF[eNB_id], - eNB->common_vars.txdata[eNB_id], - (subframe*2)+2, - &eNB->frame_parms); + ru->proc.subframe_tx=(subframe+1)%10; + feptx_prec(ru); + feptx_ofdm(ru); proc_eNB->frame_tx++; @@ -2492,7 +1645,7 @@ int main(int argc, char **argv) tx_lev = 0; for (aa=0; aaframe_parms.nb_antennas_tx; aa++) { - tx_lev += signal_energy(&eNB->common_vars.txdata[eNB_id][aa] + tx_lev += signal_energy(&ru->common.txdata[aa] [subframe*eNB->frame_parms.samples_per_tti], eNB->frame_parms.samples_per_tti); } @@ -2500,21 +1653,22 @@ int main(int argc, char **argv) tx_lev_dB = (unsigned int) dB_fixed(tx_lev); + if (n_frames==1) { printf("tx_lev = %d (%d dB)\n",tx_lev,tx_lev_dB); - write_output("txsig0.m","txs0", &eNB->common_vars.txdata[eNB_id][0][subframe* eNB->frame_parms.samples_per_tti], eNB->frame_parms.samples_per_tti,1,1); + write_output("txsig0.m","txs0", &ru->common.txdata[0][subframe* eNB->frame_parms.samples_per_tti], eNB->frame_parms.samples_per_tti,1,1); if (transmission_mode<7) { - write_output("txsigF0.m","txsF0", &eNB->common_vars.txdataF[eNB_id][0][subframe*nsymb*eNB->frame_parms.ofdm_symbol_size],nsymb*eNB->frame_parms.ofdm_symbol_size,1,1); + write_output("txsigF0.m","txsF0x", &ru->common.txdataF_BF[0][subframe*nsymb*eNB->frame_parms.ofdm_symbol_size],nsymb*eNB->frame_parms.ofdm_symbol_size,1,1); } else if (transmission_mode == 7) { - write_output("txsigF0.m","txsF0", &eNB->common_vars.txdataF[eNB_id][5][subframe*nsymb*eNB->frame_parms.ofdm_symbol_size],nsymb*eNB->frame_parms.ofdm_symbol_size,1,1); - write_output("txsigF0_BF.m","txsF0_BF", &eNB->common_vars.txdataF_BF[eNB_id][0][0],eNB->frame_parms.ofdm_symbol_size,1,1); + write_output("txsigF0.m","txsF0", &ru->common.txdataF_BF[5][subframe*nsymb*eNB->frame_parms.ofdm_symbol_size],nsymb*eNB->frame_parms.ofdm_symbol_size,1,1); + write_output("txsigF0_BF.m","txsF0_BF", &ru->common.txdataF_BF[0][0],eNB->frame_parms.ofdm_symbol_size,1,1); } } } - DL_channel(eNB,UE,subframe,awgn_flag,SNR,tx_lev,hold_channel,abstx,num_rounds,trials,round,eNB2UE,s_re,s_im,r_re,r_im,csv_fd); + DL_channel(ru,UE,subframe,awgn_flag,SNR,tx_lev,hold_channel,abstx,num_rounds,trials,round,eNB2UE,s_re,s_im,r_re,r_im,csv_fd); UE_rxtx_proc_t *proc = &UE->proc.proc_rxtx[UE->current_thread_id[subframe]]; @@ -2532,6 +1686,8 @@ int main(int argc, char **argv) if (n_frames==1) printf("Running phy_procedures_UE_RX\n"); if (dci_flag==0) { + memcpy(dci_alloc,eNB->pdcch_vars[subframe&1].dci_alloc,num_dci*sizeof(DCI_ALLOC_t)); + UE->pdcch_vars[UE->current_thread_id[proc->subframe_rx]][eNB_id]->num_pdcch_symbols = num_pdcch_symbols; if (n_frames==1) printf("bypassing PDCCH/DCI detection\n"); if (generate_ue_dlsch_params_from_dci(proc->frame_rx, @@ -2541,7 +1697,7 @@ int main(int argc, char **argv) dci_alloc[0].format, UE->pdcch_vars[UE->current_thread_id[proc->subframe_rx]][eNB_id], UE->pdsch_vars[UE->current_thread_id[proc->subframe_rx]][eNB_id], - UE->dlsch[UE->current_thread_id[proc->subframe_rx]][0], + UE->dlsch[UE->current_thread_id[proc->subframe_rx]][0], &UE->frame_parms, UE->pdsch_config_dedicated, SI_RNTI, @@ -2570,28 +1726,52 @@ int main(int argc, char **argv) dci_received = dci_received - UE->pdcch_vars[UE->current_thread_id[proc->subframe_rx]][eNB_id]->dci_received; if (dci_flag && (dci_received == 0)) { - //printf("DCI not received\n"); + printf("DCI not received\n"); dci_errors[round]++; - /* - write_output("pdcchF0_ext.m","pdcchF_ext", UE->pdcch_vars[eNB_id]->rxdataF_ext[0],2*3*UE->frame_parms.ofdm_symbol_size,1,1); - write_output("pdcch00_ch0_ext.m","pdcch00_ch0_ext",UE->pdcch_vars[eNB_id]->dl_ch_estimates_ext[0],12*UE->frame_parms.N_RB_DL*3,1,1); - - write_output("pdcch_rxF_comp0.m","pdcch0_rxF_comp0",UE->pdcch_vars[eNB_id]->rxdataF_comp[0],4*12*UE->frame_parms.N_RB_DL,1,1); - write_output("pdcch_rxF_llr.m","pdcch_llr",UE->pdcch_vars[eNB_id]->llr,12*UE->frame_parms.N_RB_DL*4*2,1,4); - write_output("txsigF0.m","txsF0", &eNB->common_vars.txdataF[eNB_id][0][subframe*nsymb*eNB->frame_parms.ofdm_symbol_size], - nsymb*eNB->frame_parms.ofdm_symbol_size,1,1); + write_output("pdcchF0_ext.m","pdcchF_ext", UE->pdcch_vars[0][eNB_id]->rxdataF_ext[0],2*3*UE->frame_parms.ofdm_symbol_size,1,1); + write_output("pdcch00_ch0_ext.m","pdcch00_ch0_ext",UE->pdcch_vars[0][eNB_id]->dl_ch_estimates_ext[0],300*3,1,1); + write_output("pdcch_rxF_comp0.m","pdcch0_rxF_comp0",UE->pdcch_vars[0][eNB_id]->rxdataF_comp[0],4*300,1,1); + write_output("pdcch_rxF_llr.m","pdcch_llr",UE->pdcch_vars[0][eNB_id]->llr,2400,1,4); + write_output("rxsig0.m","rxs0", &UE->common_vars.rxdata[0][0],10*UE->frame_parms.samples_per_tti,1,1); - write_output("rxsigF0.m","rxsF0", &UE->common_vars.rxdataF[0][0],UE->frame_parms.ofdm_symbol_size*nsymb,1,1); + write_output("rxsigF0.m","rxsF0", &UE->common_vars.common_vars_rx_data_per_thread[UE->current_thread_id[subframe]].rxdataF[0][0],UE->frame_parms.ofdm_symbol_size*nsymb,1,1); + exit(-1); - */ + } + int bit_errors=0; if ((test_perf ==0 ) && (n_frames==1)) { - write_output("ch0.m","ch0",eNB2UE[0]->ch[0],eNB2UE[0]->channel_length,1,8); + dlsch_unscrambling(&eNB->frame_parms, + 0, + UE->dlsch[UE->current_thread_id[subframe]][0][0], + coded_bits_per_codeword, + UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0], + 0, + subframe<<1); + for (i=0;idlsch[0][0]->harq_processes[0]->e[i]==1 && UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0][i] > 0)|| + (eNB->dlsch[0][0]->harq_processes[0]->e[i]==0 && UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0][i] < 0)) { + uncoded_ber_bit[bit_errors++] = 1; + printf("error in pos %d : %d => %d\n",i, + eNB->dlsch[0][0]->harq_processes[0]->e[i], + UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0][i]); + } + else { + /* + printf("no error in pos %d : %d => %d\n",i, + eNB->dlsch[0][0]->harq_processes[0]->e[i], + UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0][i]); + */ + } + + write_output("dlsch_ber_bit.m","ber_bit",uncoded_ber_bit,coded_bits_per_codeword,1,0); + write_output("ch0.m","ch0",eNB2UE[0]->ch[0],eNB2UE[0]->channel_length,1,8); + if (eNB->frame_parms.nb_antennas_tx>1) write_output("ch1.m","ch1",eNB2UE[0]->ch[eNB->frame_parms.nb_antennas_rx],eNB2UE[0]->channel_length,1,8); @@ -2625,6 +1805,7 @@ int main(int argc, char **argv) UE->frame_parms.ofdm_symbol_size*nsymb/2,1,1); //pdsch_vars + printf("coded_bits_per_codeword %d\n",coded_bits_per_codeword); dump_dlsch2(UE,eNB_id,subframe,&coded_bits_per_codeword,round, UE->dlsch[UE->current_thread_id[subframe]][0][0]->current_harq_pid); @@ -2648,7 +1829,7 @@ int main(int argc, char **argv) iter_trials++; if (n_frames==1) - printf("No DLSCH errors found (round %d),uncoded ber %f\n",round,uncoded_ber); + printf("No DLSCH errors found (round %d),uncoded ber %f\n",round,(double)bit_errors/coded_bits_per_codeword); UE->total_TBS[eNB_id] = UE->total_TBS[eNB_id] + UE->dlsch[UE->current_thread_id[subframe]][eNB_id][0]->harq_processes[UE->dlsch[UE->current_thread_id[subframe]][eNB_id][0]->current_harq_pid]->TBS; TB0_active = 0; @@ -2662,8 +1843,10 @@ int main(int argc, char **argv) iter_trials++; if (n_frames==1) { + + //if ((n_frames==1) || (SNR>=30)) { - printf("DLSCH errors found (round %d), uncoded ber %f\n",round,uncoded_ber); + printf("DLSCH errors found (round %d), uncoded ber %f\n",round,(double)bit_errors/coded_bits_per_codeword); for (s=0; sdlsch[UE->current_thread_id[subframe]][0][0]->harq_processes[0]->C; s++) { if (sdlsch[UE->current_thread_id[subframe]][0][0]->harq_processes[0]->Cminus) @@ -3292,13 +2475,6 @@ int main(int argc, char **argv) uncoded_ber_bit = NULL; - for (k=0; k Date: Tue, 13 Feb 2018 19:00:34 +0100 Subject: [PATCH 240/284] send UE Capabilities to Flexran RTController --- openair2/ENB_APP/flexran_agent_common.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index 2df5959815..c663d5cad1 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -630,21 +630,16 @@ int flexran_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Fl Protocol__FlexUeCapabilities *capabilities; capabilities = malloc(sizeof(Protocol__FlexUeCapabilities)); protocol__flex_ue_capabilities__init(capabilities); - //TODO: Set half duplex (FDD operation) - capabilities->has_half_duplex = 0; - capabilities->half_duplex = 0;//flexran_get_half_duplex(i); - //TODO: Set intra-frame hopping flag - capabilities->has_intra_sf_hopping = 0; - capabilities->intra_sf_hopping = 1;//flexran_get_intra_sf_hopping(i); - //TODO: Set support for type 2 hopping with n_sb > 1 - capabilities->has_type2_sb_1 = 0; - capabilities->type2_sb_1 = 1;//flexran_get_type2_sb_1(i); - //TODO: Set ue category - capabilities->has_ue_category = 0; - capabilities->ue_category = 1;//flexran_get_ue_category(i); - //TODO: Set UE support for resource allocation type 1 - capabilities->has_res_alloc_type1 = 0; - capabilities->res_alloc_type1 = 1;//flexran_get_res_alloc_type1(i); + capabilities->has_half_duplex = 1; + capabilities->half_duplex = flexran_get_half_duplex(mod_id, i); + capabilities->has_intra_sf_hopping = 1; + capabilities->intra_sf_hopping = flexran_get_intra_sf_hopping(mod_id, i); + capabilities->has_type2_sb_1 = 1; + capabilities->type2_sb_1 = flexran_get_type2_sb_1(mod_id, i); + capabilities->has_ue_category = 1; + capabilities->ue_category = flexran_get_ue_category(mod_id, i); + capabilities->has_res_alloc_type1 = 1; + capabilities->res_alloc_type1 = flexran_get_res_alloc_type1(mod_id, i); //Set the capabilites to the message ue_config[i]->capabilities = capabilities; From 9d05a9a3b10e6959a68228883e4670d2dba7e65e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 13 Feb 2018 16:08:35 +0100 Subject: [PATCH 241/284] track IMSIs by decoding NAS messages Original Author: Xenofon Foukas Changed formatting does not compile RS: cast to get rid of compiler warning -> ImsiEpsMobileIdentity_t to ImsiMobileIdentity_t which is defined the same way --- openair2/RRC/LITE/rrc_eNB_S1AP.c | 228 +++++++++++++++++++++++++++++-- 1 file changed, 219 insertions(+), 9 deletions(-) diff --git a/openair2/RRC/LITE/rrc_eNB_S1AP.c b/openair2/RRC/LITE/rrc_eNB_S1AP.c index d2c0d0acbe..a2c570c009 100644 --- a/openair2/RRC/LITE/rrc_eNB_S1AP.c +++ b/openair2/RRC/LITE/rrc_eNB_S1AP.c @@ -59,6 +59,10 @@ #include "gtpv1u_eNB_task.h" #include "RRC/LITE/rrc_eNB_GTPV1U.h" +#include "TLVDecoder.h" +#include "S1ap-NAS-PDU.h" +#include "flexran_agent_common_internal.h" + extern RAN_CONTEXT_t RC; /* Value to indicate an invalid UE initial id */ @@ -542,6 +546,74 @@ rrc_eNB_send_S1AP_UPLINK_NAS( S1AP_UPLINK_NAS (msg_p).nas_pdu.length = pdu_length; S1AP_UPLINK_NAS (msg_p).nas_pdu.buffer = pdu_buffer; + /* Process NAS message locally to get the IMSI */ + nas_message_t nas_msg; + memset(&nas_msg, 0, sizeof(nas_message_t)); + int size = 0; + uint32_t pdu_len = S1AP_UPLINK_NAS (msg_p).nas_pdu.length; + uint8_t *pdu_buff = malloc(pdu_len * sizeof(uint8_t)); + memcpy(pdu_buff, S1AP_UPLINK_NAS (msg_p).nas_pdu.buffer, pdu_len * sizeof(uint8_t)); + + nas_message_security_header_t *header = &nas_msg.header; + /* Decode the first octet of the header (security header type or EPS + * bearer identity, and protocol discriminator) */ + DECODE_U8((char *) pdu_buff, *(uint8_t*) (header), size); + + /* Decode NAS message */ + if (header->security_header_type <= SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED + && header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE + && pdu_len > NAS_MESSAGE_SECURITY_HEADER_SIZE) { + + if (header->security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) { + /* Decode the message authentication code */ + DECODE_U32((char *) pdu_buff+size, header->message_authentication_code, size); + /* Decode the sequence number */ + DECODE_U8((char *) pdu_buff+size, header->sequence_number, size); + } + + if (size > 1) { + pdu_buff += size; + pdu_len -= size; + } + + /* Decode plain NAS message */ + EMM_msg *e_msg = &nas_msg.plain.emm; + emm_msg_header_t *emm_header = &e_msg->header; + + /* First decode the EMM message header */ + int e_head_size = 0; + + /* Check the buffer length */ + if (pdu_len > sizeof(emm_msg_header_t)) { + + /* Decode the security header type and the protocol discriminator */ + DECODE_U8(pdu_buff + e_head_size, *(uint8_t *)(emm_header), e_head_size); + /* Decode the message type */ + DECODE_U8(pdu_buff + e_head_size, emm_header->message_type, e_head_size); + + /* Check the protocol discriminator */ + if (emm_header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE) { + + pdu_buff += e_head_size; + pdu_len -= e_head_size; + + if (emm_header->message_type == IDENTITY_RESPONSE) { + decode_identity_response(&e_msg->identity_response, pdu_buff, pdu_len); + + if (e_msg->identity_response.mobileidentity.imsi.typeofidentity == MOBILE_IDENTITY_IMSI) { + ue_context_pP->ue_context.imsi = compute_imsi(&(e_msg->identity_response.mobileidentity.imsi)); + } + } + + pdu_buff -= e_head_size; + if (size > 1) { + pdu_buff -= size; + } + } + } + } + free(pdu_buff); + itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, msg_p); } } @@ -563,16 +635,82 @@ rrc_eNB_send_S1AP_UPLINK_NAS( &ulInformationTransfer->criticalExtensions.choice. c1.choice.ulInformationTransfer_r8; - if (ulInformationTransferR8->dedicatedInfoType. - present == - ULInformationTransfer_r8_IEs__dedicatedInfoType_PR_dedicatedInfoNAS) + if (ulInformationTransferR8->dedicatedInfoType.present == + ULInformationTransfer_r8_IEs__dedicatedInfoType_PR_dedicatedInfoNAS) { + + /* Process NAS message locally to get the IMSI */ + nas_message_t nas_msg; + memset(&nas_msg, 0, sizeof(nas_message_t)); + + int size = 0; + uint32_t pdu_len = ulInformationTransferR8->dedicatedInfoType.choice.dedicatedInfoNAS.size; + uint8_t *pdu_buff = malloc(pdu_len * sizeof(uint8_t)); + memcpy(pdu_buff, ulInformationTransferR8->dedicatedInfoType.choice.dedicatedInfoNAS.buf, pdu_len * sizeof(uint8_t)); + + nas_message_security_header_t *header = &nas_msg.header; + /* Decode the first octet of the header (security header type or EPS + * bearer identity, and protocol discriminator) */ + DECODE_U8((char *) pdu_buff, *(uint8_t*) (header), size); + + /* Decode NAS message */ + if (header->security_header_type <= SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED && + header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE && + pdu_len > NAS_MESSAGE_SECURITY_HEADER_SIZE) { + + if (header->security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) { + /* Decode the message authentication code */ + DECODE_U32((char *) pdu_buff+size, header->message_authentication_code, size); + /* Decode the sequence number */ + DECODE_U8((char *) pdu_buff+size, header->sequence_number, size); + } + + if (size > 1) { + pdu_buff += size; + pdu_len -= size; + } + + /* Decode plain NAS message */ + EMM_msg *e_msg = &nas_msg.plain.emm; + emm_msg_header_t *emm_header = &e_msg->header; + + /* First decode the EMM message header */ + int e_head_size = 0; + + /* Check the buffer length */ + if (pdu_len > sizeof(emm_msg_header_t)) { + + /* Decode the security header type and the protocol discriminator */ + DECODE_U8(pdu_buff + e_head_size, *(uint8_t *)(emm_header), e_head_size); + /* Decode the message type */ + DECODE_U8(pdu_buff + e_head_size, emm_header->message_type, e_head_size); + + /* Check the protocol discriminator */ + if (emm_header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE) { + + pdu_buff += e_head_size; + pdu_len -= e_head_size; + + if (emm_header->message_type == IDENTITY_RESPONSE) { + decode_identity_response(&e_msg->identity_response, pdu_buff, pdu_len); + + if (e_msg->identity_response.mobileidentity.imsi.typeofidentity == MOBILE_IDENTITY_IMSI) { + ue_context_pP->ue_context.imsi = compute_imsi(&(e_msg->identity_response.mobileidentity.imsi)); + } + } + + pdu_buff -= e_head_size; + if (size > 1) { + pdu_buff -= size; + } + } + } + } + free(pdu_buff); + s1ap_eNB_new_data_request (mod_id, ue_index, - ulInformationTransferR8-> - dedicatedInfoType.choice. - dedicatedInfoNAS.buf, - ulInformationTransferR8-> - dedicatedInfoType.choice. - dedicatedInfoNAS.size); + ulInformationTransferR8->dedicatedInfoType.choice.dedicatedInfoNAS.buf, + ulInformationTransferR8->dedicatedInfoType.choice.dedicatedInfoNAS.size); + } } } } @@ -674,6 +812,78 @@ rrc_eNB_send_S1AP_NAS_FIRST_REQ( rrcConnectionSetupComplete->dedicatedInfoNAS.buf; S1AP_NAS_FIRST_REQ (message_p).nas_pdu.length = rrcConnectionSetupComplete->dedicatedInfoNAS.size; + // Process NAS message locally to get the IMSI + nas_message_t nas_msg; + memset(&nas_msg, 0, sizeof(nas_message_t)); + + int size = 0; + uint32_t pdu_len = S1AP_NAS_FIRST_REQ (message_p).nas_pdu.length; + uint8_t *pdu_buff = malloc(pdu_len * sizeof(uint8_t)); + memcpy(pdu_buff, S1AP_NAS_FIRST_REQ (message_p).nas_pdu.buffer, pdu_len * sizeof(uint8_t)); + + nas_message_security_header_t *header = &nas_msg.header; + /* Decode the first octet of the header (security header type or EPS + * bearer identity, and protocol discriminator) */ + DECODE_U8((char *) pdu_buff, *(uint8_t*) (header), size); + + /* Decode NAS message */ + if (header->security_header_type <= SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED && + header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE && + pdu_len > NAS_MESSAGE_SECURITY_HEADER_SIZE) { + + if (header->security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) { + /* Decode the message authentication code */ + DECODE_U32((char *) pdu_buff+size, header->message_authentication_code, size); + /* Decode the sequence number */ + DECODE_U8((char *) pdu_buff+size, header->sequence_number, size); + } + + if (size > 1) { + pdu_buff += size; + pdu_len -= size; + } + + /* Decode plain NAS message */ + EMM_msg *e_msg = &nas_msg.plain.emm; + emm_msg_header_t *emm_header = &e_msg->header; + + /* First decode the EMM message header */ + int e_head_size = 0; + + /* Check the buffer length */ + if (pdu_len > sizeof(emm_msg_header_t)) { + + /* Decode the security header type and the protocol discriminator */ + DECODE_U8(pdu_buff + e_head_size, *(uint8_t *)(emm_header), e_head_size); + /* Decode the message type */ + DECODE_U8(pdu_buff + e_head_size, emm_header->message_type, e_head_size); + + /* Check the protocol discriminator */ + if (emm_header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE) { + + pdu_buff += e_head_size; + pdu_len -= e_head_size; + + if (emm_header->message_type == ATTACH_REQUEST) { + decode_attach_request(&e_msg->attach_request, pdu_buff, pdu_len); + + if (e_msg->attach_request.oldgutiorimsi.imsi.typeofidentity == MOBILE_IDENTITY_IMSI) { + /* the following is very dirty, we cast from + * ImsiEpsMobileIdentity_t to ImsiMobileIdentity_t*/ + ue_context_pP->ue_context.imsi = compute_imsi((ImsiMobileIdentity_t *)&(e_msg->attach_request.oldgutiorimsi.imsi)); + } else { + ue_context_pP->ue_context.imsi = e_msg->attach_request.oldgutiorimsi.guti.mtmsi; + } + } + pdu_buff -= e_head_size; + if (size > 1) { + pdu_buff -= size; + } + } + } + } + free(pdu_buff); + /* Fill UE identities with available information */ { S1AP_NAS_FIRST_REQ (message_p).ue_identity.presenceMask = UE_IDENTITIES_NONE; From d8a6715395e2094a0c1761e180daf3351cb1e963 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 7 Feb 2018 18:57:06 +0100 Subject: [PATCH 242/284] store IMSI information + provide FlexRAN API to query UE's IMSI --- openair2/ENB_APP/flexran_agent_ran_api.c | 11 +++++++++++ openair2/ENB_APP/flexran_agent_ran_api.h | 3 +++ openair2/RRC/LITE/defs.h | 3 ++- openair2/RRC/LITE/rrc_eNB_S1AP.c | 21 +++++++++++++++++++-- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 97a77a634c..b81d030c43 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -889,6 +889,17 @@ int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) } } +uint64_t flexran_get_ue_imsi(mid_t mod_id, mid_t ue_id) +{ + if (!rrc_is_present(mod_id)) return -1; + + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); + + if (!ue_context_p) return -1; + return ue_context_p->ue_context.imsi; +} + long flexran_get_lcg(mid_t mod_id, mid_t ue_id, mid_t lc_id) { if (!mac_is_present(mod_id)) return 0; diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index b3515c9c6c..aafb82077e 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -301,6 +301,9 @@ long flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id); /* Get number of UE transmission antennas */ int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id); +/* Get the IMSI of UE */ +uint64_t flexran_get_ue_imsi(mid_t mod_id, mid_t ue_id); + /* Get logical channel group of a channel with id lc_id */ long flexran_get_lcg(mid_t mod_id, mid_t ue_id, mid_t lc_id); diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index 9a9840273b..763a55c559 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -394,7 +394,8 @@ typedef struct eNB_RRC_UE_s { MeasResults_t* measResults; UE_EUTRA_Capability_t* UE_Capability; - + uint64_t imsi; + #if defined(ENABLE_SECURITY) /* KeNB as derived from KASME received from EPC */ uint8_t kenb[32]; diff --git a/openair2/RRC/LITE/rrc_eNB_S1AP.c b/openair2/RRC/LITE/rrc_eNB_S1AP.c index a2c570c009..87bbe8857d 100644 --- a/openair2/RRC/LITE/rrc_eNB_S1AP.c +++ b/openair2/RRC/LITE/rrc_eNB_S1AP.c @@ -86,8 +86,25 @@ static const uint16_t S1AP_INTEGRITY_EIA2_MASK = 0x4000; #endif #endif - - +uint64_t compute_imsi(ImsiMobileIdentity_t *id) { + uint64_t imsi; + imsi = id->digit15; + imsi += id->digit14 * 10; // pow(10, 1) + imsi += id->digit13 * 100; // pow(10, 2) + imsi += id->digit12 * 1000; // pow(10, 3) + imsi += id->digit11 * 10000; // pow(10, 4) + imsi += id->digit10 * 100000; // pow(10, 5) + imsi += id->digit9 * 1000000; // pow(10, 6) + imsi += id->digit8 * 10000000; // pow(10, 7) + imsi += id->digit7 * 100000000; // pow(10, 8) + imsi += id->digit6 * 1000000000; // pow(10, 9) + imsi += id->digit5 * 10000000000; // pow(10, 10) + imsi += id->digit4 * 100000000000; // pow(10, 11) + imsi += id->digit3 * 1000000000000; // pow(10, 12) + imsi += id->digit2 * 10000000000000; // pow(10, 13) + imsi += id->digit1 * 100000000000000; // pow(10, 14) + return imsi; +} # if defined(ENABLE_ITTI) //------------------------------------------------------------------------------ From df43d19c356f0b9cb1642b9c409b3c3e97011d77 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 13 Feb 2018 15:02:38 +0100 Subject: [PATCH 243/284] refactoring of the original IMSI extraction code - move IMSI extraction code to function, remove FLEXRAN comp. directive - refactor the code, esp. don't do deep if-nesting - remove m-tmsi part (does not give correct value) - copy complete IMSI info to UE context, decode in RAN API --- openair2/ENB_APP/flexran_agent_ran_api.c | 19 +- openair2/RRC/LITE/defs.h | 2 +- openair2/RRC/LITE/rrc_eNB_S1AP.c | 306 ++++++----------------- 3 files changed, 101 insertions(+), 226 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index b81d030c43..3c98d63fcf 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -891,13 +891,30 @@ int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) uint64_t flexran_get_ue_imsi(mid_t mod_id, mid_t ue_id) { + uint64_t imsi; if (!rrc_is_present(mod_id)) return -1; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); if (!ue_context_p) return -1; - return ue_context_p->ue_context.imsi; + + imsi = ue_context_p->ue_context.imsi.digit15; + imsi += ue_context_p->ue_context.imsi.digit14 * 10; // pow(10, 1) + imsi += ue_context_p->ue_context.imsi.digit13 * 100; // pow(10, 2) + imsi += ue_context_p->ue_context.imsi.digit12 * 1000; // pow(10, 3) + imsi += ue_context_p->ue_context.imsi.digit11 * 10000; // pow(10, 4) + imsi += ue_context_p->ue_context.imsi.digit10 * 100000; // pow(10, 5) + imsi += ue_context_p->ue_context.imsi.digit9 * 1000000; // pow(10, 6) + imsi += ue_context_p->ue_context.imsi.digit8 * 10000000; // pow(10, 7) + imsi += ue_context_p->ue_context.imsi.digit7 * 100000000; // pow(10, 8) + imsi += ue_context_p->ue_context.imsi.digit6 * 1000000000; // pow(10, 9) + imsi += ue_context_p->ue_context.imsi.digit5 * 10000000000; // pow(10, 10) + imsi += ue_context_p->ue_context.imsi.digit4 * 100000000000; // pow(10, 11) + imsi += ue_context_p->ue_context.imsi.digit3 * 1000000000000; // pow(10, 12) + imsi += ue_context_p->ue_context.imsi.digit2 * 10000000000000; // pow(10, 13) + imsi += ue_context_p->ue_context.imsi.digit1 * 100000000000000; // pow(10, 14) + return imsi; } long flexran_get_lcg(mid_t mod_id, mid_t ue_id, mid_t lc_id) diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index 763a55c559..01475715f4 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -394,7 +394,7 @@ typedef struct eNB_RRC_UE_s { MeasResults_t* measResults; UE_EUTRA_Capability_t* UE_Capability; - uint64_t imsi; + ImsiMobileIdentity_t imsi; #if defined(ENABLE_SECURITY) /* KeNB as derived from KASME received from EPC */ diff --git a/openair2/RRC/LITE/rrc_eNB_S1AP.c b/openair2/RRC/LITE/rrc_eNB_S1AP.c index 87bbe8857d..80ae1c9ba5 100644 --- a/openair2/RRC/LITE/rrc_eNB_S1AP.c +++ b/openair2/RRC/LITE/rrc_eNB_S1AP.c @@ -86,24 +86,79 @@ static const uint16_t S1AP_INTEGRITY_EIA2_MASK = 0x4000; #endif #endif -uint64_t compute_imsi(ImsiMobileIdentity_t *id) { - uint64_t imsi; - imsi = id->digit15; - imsi += id->digit14 * 10; // pow(10, 1) - imsi += id->digit13 * 100; // pow(10, 2) - imsi += id->digit12 * 1000; // pow(10, 3) - imsi += id->digit11 * 10000; // pow(10, 4) - imsi += id->digit10 * 100000; // pow(10, 5) - imsi += id->digit9 * 1000000; // pow(10, 6) - imsi += id->digit8 * 10000000; // pow(10, 7) - imsi += id->digit7 * 100000000; // pow(10, 8) - imsi += id->digit6 * 1000000000; // pow(10, 9) - imsi += id->digit5 * 10000000000; // pow(10, 10) - imsi += id->digit4 * 100000000000; // pow(10, 11) - imsi += id->digit3 * 1000000000000; // pow(10, 12) - imsi += id->digit2 * 10000000000000; // pow(10, 13) - imsi += id->digit1 * 100000000000000; // pow(10, 14) - return imsi; +void extract_imsi(uint8_t *pdu_buf, uint32_t pdu_len, rrc_eNB_ue_context_t *ue_context_pP) +{ + /* Process NAS message locally to get the IMSI */ + nas_message_t nas_msg; + memset(&nas_msg, 0, sizeof(nas_message_t)); + + int size = 0; + + nas_message_security_header_t *header = &nas_msg.header; + /* Decode the first octet of the header (security header type or EPS + * bearer identity, and protocol discriminator) */ + DECODE_U8((char *) pdu_buf, *(uint8_t*) (header), size); + + /* Decode NAS message only if decodable*/ + if (!(header->security_header_type <= SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED + && header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE + && pdu_len > NAS_MESSAGE_SECURITY_HEADER_SIZE)) + return; + + if (header->security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) { + /* Decode the message authentication code */ + DECODE_U32((char *) pdu_buf+size, header->message_authentication_code, size); + /* Decode the sequence number */ + DECODE_U8((char *) pdu_buf+size, header->sequence_number, size); + } + + /* Note: the value of the pointer (i.e. the address) is given by value, so we + * can modify it as we want. The callee retains the original address! */ + pdu_buf += size; + pdu_len -= size; + + /* Decode plain NAS message */ + EMM_msg *e_msg = &nas_msg.plain.emm; + emm_msg_header_t *emm_header = &e_msg->header; + + /* First decode the EMM message header */ + int e_head_size = 0; + + /* Check that buffer contains more than only the header */ + if (pdu_len <= sizeof(emm_msg_header_t)) + return; + + /* Decode the security header type and the protocol discriminator */ + DECODE_U8(pdu_buf + e_head_size, *(uint8_t *)(emm_header), e_head_size); + /* Decode the message type */ + DECODE_U8(pdu_buf + e_head_size, emm_header->message_type, e_head_size); + + /* Check that this is the right message */ + if (emm_header->protocol_discriminator != EPS_MOBILITY_MANAGEMENT_MESSAGE) + return; + + pdu_buf += e_head_size; + pdu_len -= e_head_size; + + if (emm_header->message_type == IDENTITY_RESPONSE) { + decode_identity_response(&e_msg->identity_response, pdu_buf, pdu_len); + + if (e_msg->identity_response.mobileidentity.imsi.typeofidentity == MOBILE_IDENTITY_IMSI) { + memcpy(&ue_context_pP->ue_context.imsi, + &e_msg->identity_response.mobileidentity.imsi, + sizeof(ImsiMobileIdentity_t)); + } + } else if (emm_header->message_type == ATTACH_REQUEST) { + decode_attach_request(&e_msg->attach_request, pdu_buf, pdu_len); + + if (e_msg->attach_request.oldgutiorimsi.imsi.typeofidentity == MOBILE_IDENTITY_IMSI) { + /* the following is very dirty, we cast (implicitly) from + * ImsiEpsMobileIdentity_t to ImsiMobileIdentity_t*/ + memcpy(&ue_context_pP->ue_context.imsi, + &e_msg->attach_request.oldgutiorimsi.imsi, + sizeof(ImsiMobileIdentity_t)); + } + } } # if defined(ENABLE_ITTI) @@ -563,73 +618,9 @@ rrc_eNB_send_S1AP_UPLINK_NAS( S1AP_UPLINK_NAS (msg_p).nas_pdu.length = pdu_length; S1AP_UPLINK_NAS (msg_p).nas_pdu.buffer = pdu_buffer; - /* Process NAS message locally to get the IMSI */ - nas_message_t nas_msg; - memset(&nas_msg, 0, sizeof(nas_message_t)); - int size = 0; - uint32_t pdu_len = S1AP_UPLINK_NAS (msg_p).nas_pdu.length; - uint8_t *pdu_buff = malloc(pdu_len * sizeof(uint8_t)); - memcpy(pdu_buff, S1AP_UPLINK_NAS (msg_p).nas_pdu.buffer, pdu_len * sizeof(uint8_t)); - - nas_message_security_header_t *header = &nas_msg.header; - /* Decode the first octet of the header (security header type or EPS - * bearer identity, and protocol discriminator) */ - DECODE_U8((char *) pdu_buff, *(uint8_t*) (header), size); - - /* Decode NAS message */ - if (header->security_header_type <= SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED - && header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE - && pdu_len > NAS_MESSAGE_SECURITY_HEADER_SIZE) { - - if (header->security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) { - /* Decode the message authentication code */ - DECODE_U32((char *) pdu_buff+size, header->message_authentication_code, size); - /* Decode the sequence number */ - DECODE_U8((char *) pdu_buff+size, header->sequence_number, size); - } - - if (size > 1) { - pdu_buff += size; - pdu_len -= size; - } - - /* Decode plain NAS message */ - EMM_msg *e_msg = &nas_msg.plain.emm; - emm_msg_header_t *emm_header = &e_msg->header; - - /* First decode the EMM message header */ - int e_head_size = 0; - - /* Check the buffer length */ - if (pdu_len > sizeof(emm_msg_header_t)) { - - /* Decode the security header type and the protocol discriminator */ - DECODE_U8(pdu_buff + e_head_size, *(uint8_t *)(emm_header), e_head_size); - /* Decode the message type */ - DECODE_U8(pdu_buff + e_head_size, emm_header->message_type, e_head_size); - - /* Check the protocol discriminator */ - if (emm_header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE) { - - pdu_buff += e_head_size; - pdu_len -= e_head_size; - - if (emm_header->message_type == IDENTITY_RESPONSE) { - decode_identity_response(&e_msg->identity_response, pdu_buff, pdu_len); - - if (e_msg->identity_response.mobileidentity.imsi.typeofidentity == MOBILE_IDENTITY_IMSI) { - ue_context_pP->ue_context.imsi = compute_imsi(&(e_msg->identity_response.mobileidentity.imsi)); - } - } - - pdu_buff -= e_head_size; - if (size > 1) { - pdu_buff -= size; - } - } - } - } - free(pdu_buff); + extract_imsi(S1AP_UPLINK_NAS (msg_p).nas_pdu.buffer, + S1AP_UPLINK_NAS (msg_p).nas_pdu.length, + ue_context_pP); itti_send_msg_to_task (TASK_S1AP, ctxt_pP->instance, msg_p); } @@ -655,74 +646,9 @@ rrc_eNB_send_S1AP_UPLINK_NAS( if (ulInformationTransferR8->dedicatedInfoType.present == ULInformationTransfer_r8_IEs__dedicatedInfoType_PR_dedicatedInfoNAS) { - /* Process NAS message locally to get the IMSI */ - nas_message_t nas_msg; - memset(&nas_msg, 0, sizeof(nas_message_t)); - - int size = 0; - uint32_t pdu_len = ulInformationTransferR8->dedicatedInfoType.choice.dedicatedInfoNAS.size; - uint8_t *pdu_buff = malloc(pdu_len * sizeof(uint8_t)); - memcpy(pdu_buff, ulInformationTransferR8->dedicatedInfoType.choice.dedicatedInfoNAS.buf, pdu_len * sizeof(uint8_t)); - - nas_message_security_header_t *header = &nas_msg.header; - /* Decode the first octet of the header (security header type or EPS - * bearer identity, and protocol discriminator) */ - DECODE_U8((char *) pdu_buff, *(uint8_t*) (header), size); - - /* Decode NAS message */ - if (header->security_header_type <= SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED && - header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE && - pdu_len > NAS_MESSAGE_SECURITY_HEADER_SIZE) { - - if (header->security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) { - /* Decode the message authentication code */ - DECODE_U32((char *) pdu_buff+size, header->message_authentication_code, size); - /* Decode the sequence number */ - DECODE_U8((char *) pdu_buff+size, header->sequence_number, size); - } - - if (size > 1) { - pdu_buff += size; - pdu_len -= size; - } - - /* Decode plain NAS message */ - EMM_msg *e_msg = &nas_msg.plain.emm; - emm_msg_header_t *emm_header = &e_msg->header; - - /* First decode the EMM message header */ - int e_head_size = 0; - - /* Check the buffer length */ - if (pdu_len > sizeof(emm_msg_header_t)) { - - /* Decode the security header type and the protocol discriminator */ - DECODE_U8(pdu_buff + e_head_size, *(uint8_t *)(emm_header), e_head_size); - /* Decode the message type */ - DECODE_U8(pdu_buff + e_head_size, emm_header->message_type, e_head_size); - - /* Check the protocol discriminator */ - if (emm_header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE) { - - pdu_buff += e_head_size; - pdu_len -= e_head_size; - - if (emm_header->message_type == IDENTITY_RESPONSE) { - decode_identity_response(&e_msg->identity_response, pdu_buff, pdu_len); - - if (e_msg->identity_response.mobileidentity.imsi.typeofidentity == MOBILE_IDENTITY_IMSI) { - ue_context_pP->ue_context.imsi = compute_imsi(&(e_msg->identity_response.mobileidentity.imsi)); - } - } - - pdu_buff -= e_head_size; - if (size > 1) { - pdu_buff -= size; - } - } - } - } - free(pdu_buff); + extract_imsi(ulInformationTransferR8->dedicatedInfoType.choice.dedicatedInfoNAS.buf, + ulInformationTransferR8->dedicatedInfoType.choice.dedicatedInfoNAS.size, + ue_context_pP); s1ap_eNB_new_data_request (mod_id, ue_index, ulInformationTransferR8->dedicatedInfoType.choice.dedicatedInfoNAS.buf, @@ -829,77 +755,9 @@ rrc_eNB_send_S1AP_NAS_FIRST_REQ( rrcConnectionSetupComplete->dedicatedInfoNAS.buf; S1AP_NAS_FIRST_REQ (message_p).nas_pdu.length = rrcConnectionSetupComplete->dedicatedInfoNAS.size; - // Process NAS message locally to get the IMSI - nas_message_t nas_msg; - memset(&nas_msg, 0, sizeof(nas_message_t)); - - int size = 0; - uint32_t pdu_len = S1AP_NAS_FIRST_REQ (message_p).nas_pdu.length; - uint8_t *pdu_buff = malloc(pdu_len * sizeof(uint8_t)); - memcpy(pdu_buff, S1AP_NAS_FIRST_REQ (message_p).nas_pdu.buffer, pdu_len * sizeof(uint8_t)); - - nas_message_security_header_t *header = &nas_msg.header; - /* Decode the first octet of the header (security header type or EPS - * bearer identity, and protocol discriminator) */ - DECODE_U8((char *) pdu_buff, *(uint8_t*) (header), size); - - /* Decode NAS message */ - if (header->security_header_type <= SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED && - header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE && - pdu_len > NAS_MESSAGE_SECURITY_HEADER_SIZE) { - - if (header->security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) { - /* Decode the message authentication code */ - DECODE_U32((char *) pdu_buff+size, header->message_authentication_code, size); - /* Decode the sequence number */ - DECODE_U8((char *) pdu_buff+size, header->sequence_number, size); - } - - if (size > 1) { - pdu_buff += size; - pdu_len -= size; - } - - /* Decode plain NAS message */ - EMM_msg *e_msg = &nas_msg.plain.emm; - emm_msg_header_t *emm_header = &e_msg->header; - - /* First decode the EMM message header */ - int e_head_size = 0; - - /* Check the buffer length */ - if (pdu_len > sizeof(emm_msg_header_t)) { - - /* Decode the security header type and the protocol discriminator */ - DECODE_U8(pdu_buff + e_head_size, *(uint8_t *)(emm_header), e_head_size); - /* Decode the message type */ - DECODE_U8(pdu_buff + e_head_size, emm_header->message_type, e_head_size); - - /* Check the protocol discriminator */ - if (emm_header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE) { - - pdu_buff += e_head_size; - pdu_len -= e_head_size; - - if (emm_header->message_type == ATTACH_REQUEST) { - decode_attach_request(&e_msg->attach_request, pdu_buff, pdu_len); - - if (e_msg->attach_request.oldgutiorimsi.imsi.typeofidentity == MOBILE_IDENTITY_IMSI) { - /* the following is very dirty, we cast from - * ImsiEpsMobileIdentity_t to ImsiMobileIdentity_t*/ - ue_context_pP->ue_context.imsi = compute_imsi((ImsiMobileIdentity_t *)&(e_msg->attach_request.oldgutiorimsi.imsi)); - } else { - ue_context_pP->ue_context.imsi = e_msg->attach_request.oldgutiorimsi.guti.mtmsi; - } - } - pdu_buff -= e_head_size; - if (size > 1) { - pdu_buff -= size; - } - } - } - } - free(pdu_buff); + extract_imsi(S1AP_NAS_FIRST_REQ (message_p).nas_pdu.buffer, + S1AP_NAS_FIRST_REQ (message_p).nas_pdu.length, + ue_context_pP); /* Fill UE identities with available information */ { From d741b951fa22426d668169872c4dcddb5d682b7a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 13 Feb 2018 18:51:36 +0100 Subject: [PATCH 244/284] define&send IMSI in Protobuf --- openair2/ENB_APP/MESSAGES/V2/config_messages.proto | 1 + openair2/ENB_APP/flexran_agent_common.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto index 995865f1ab..f734686f01 100644 --- a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto +++ b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto @@ -81,6 +81,7 @@ message flex_ue_config { optional uint32 pcell_carrier_index = 27; // Index of primary cell repeated flex_scell_config scell_config = 28; // Secondary cells configuration optional uint32 scell_deactivation_timer = 29;// Deactivation timer for secondary cell + optional uint64 imsi = 30; } message flex_lc_ue_config { diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index c663d5cad1..6d32aeedbb 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -589,6 +589,8 @@ int flexran_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Fl ue_config[i]->rnti = flexran_get_ue_crnti(mod_id,i); ue_config[i]->has_rnti = 1; + ue_config[i]->imsi = flexran_get_ue_imsi(mod_id, i); + ue_config[i]->has_imsi = 1; //TODO: Set the DRX configuration (optional) //Not supported for now, so we do not set it From 50f7053159558287031df145b3a7c153be22a2fb Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 14 Feb 2018 16:44:29 +0100 Subject: [PATCH 245/284] return 0 for unsigned in RAN API --- openair2/ENB_APP/flexran_agent_ran_api.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 3c98d63fcf..c1743bf744 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -892,12 +892,12 @@ int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) uint64_t flexran_get_ue_imsi(mid_t mod_id, mid_t ue_id) { uint64_t imsi; - if (!rrc_is_present(mod_id)) return -1; + if (!rrc_is_present(mod_id)) return 0; rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti); - if (!ue_context_p) return -1; + if (!ue_context_p) return 0; imsi = ue_context_p->ue_context.imsi.digit15; imsi += ue_context_p->ue_context.imsi.digit14 * 10; // pow(10, 1) From 9dcd1f9b89198057d6c8309bb0fd3135108d77ec Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 14 Feb 2018 14:25:18 +0100 Subject: [PATCH 246/284] bugfix: max_allowed_rbs has been renamed max_rbs_allowed_slice --- targets/SIMU/USER/event_handler.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/targets/SIMU/USER/event_handler.c b/targets/SIMU/USER/event_handler.c index 7c9f6b73fc..dbdce23df2 100644 --- a/targets/SIMU/USER/event_handler.c +++ b/targets/SIMU/USER/event_handler.c @@ -524,9 +524,9 @@ void update_mac(Event_t event) for(j=0; jmac_config[i].max_allowed_rbs[j]= mac_config[i].max_allowed_rbs[j]; - UE_list->UE_sched_ctrl[i].max_allowed_rbs[j] = oai_emulation->mac_config[i].max_allowed_rbs[j]; + UE_list->UE_sched_ctrl[i].max_rbs_allowed_slice[j][0] = oai_emulation->mac_config[i].max_allowed_rbs[j]; LOG_I(EMU,"max_allowed_rbs UE %d LCID %d:",i,j); - LOG_I(EMU,"%" PRIu16 "\n",UE_list->UE_sched_ctrl[i].max_allowed_rbs[j]); + LOG_I(EMU,"%" PRIu16 "\n",UE_list->UE_sched_ctrl[i].max_rbs_allowed_slice[j][0]); } } @@ -646,9 +646,9 @@ void update_mac(Event_t event) if(mac_config->max_allowed_rbs !=NULL) { oai_emulation->mac_config[i].max_allowed_rbs[j]= mac_config[i].max_allowed_rbs[j]; - UE_list->UE_sched_ctrl[i].max_allowed_rbs[j] = oai_emulation->mac_config[i].max_allowed_rbs[j]; + UE_list->UE_sched_ctrl[i].max_rbs_allowed_slice[j][0] = oai_emulation->mac_config[i].max_allowed_rbs[j]; LOG_I(EMU,"max_allowed_rbs UE %d LCID %d:",i,j); - LOG_I(EMU,"%" PRIu16 "\n",UE_list->UE_sched_ctrl[i].max_allowed_rbs[j]); + LOG_I(EMU,"%" PRIu16 "\n",UE_list->UE_sched_ctrl[i].max_rbs_allowed_slice[j][0]); } @@ -951,18 +951,18 @@ void update_mac(Event_t event) if(&mac_config[i].max_allowed_rbs[j]!=NULL) { oai_emulation->mac_config[i].max_allowed_rbs[j]= mac_config[i].max_allowed_rbs[j]; - UE_list->UE_sched_ctrl[i].max_allowed_rbs[j] = oai_emulation->mac_config[i].max_allowed_rbs[j]; + UE_list->UE_sched_ctrl[i].max_rbs_allowed_slice[j][0] = oai_emulation->mac_config[i].max_allowed_rbs[j]; LOG_I(EMU,"max_allowed_rbs UE %d LCID %d:",i,j); - LOG_I(EMU,"%" PRIu16 "\n",UE_list->UE_sched_ctrl[i].max_allowed_rbs[j]); + LOG_I(EMU,"%" PRIu16 "\n",UE_list->UE_sched_ctrl[i].max_rbs_allowed_slice[j][0]); } } } } } else { oai_emulation->mac_config[event.ue].max_allowed_rbs[event.lcid]= mac_config[event.ue].max_allowed_rbs[event.lcid]; - UE_list->UE_sched_ctrl[event.ue].max_allowed_rbs[event.lcid] = oai_emulation->mac_config[event.ue].max_allowed_rbs[event.lcid]; + UE_list->UE_sched_ctrl[event.ue].max_rbs_allowed_slice[event.lcid][0] = oai_emulation->mac_config[event.ue].max_allowed_rbs[event.lcid]; LOG_I(EMU,"max_allowed_rbs UE %d LCID %d:",event.ue,event.lcid); - LOG_I(EMU,"%" PRIu16 "\n",UE_list->UE_sched_ctrl[event.ue].max_allowed_rbs[event.lcid]); + LOG_I(EMU,"%" PRIu16 "\n",UE_list->UE_sched_ctrl[event.ue].max_rbs_allowed_slice[event.lcid][0]); } } else if(!strcmp((char *) event.key, "max_mcs") && event.value!=NULL && validate_mac(event)) { From 7b1afbb0bfb2defebbf0e60b4331309513cfee43 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 14 Feb 2018 12:07:42 +0100 Subject: [PATCH 247/284] provide stop_L1L2()/restart_L1L2() in oaisim the functions are meant to restart the lte-softmodem (lower layers) and are not supported in oaisim. They are provided to make oaisim compile. --- targets/SIMU/USER/oaisim.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index 302b77b60f..9434b2dd83 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -988,6 +988,25 @@ l2l1_task (void *args_p) return NULL; } +#if defined(FLEXRAN_AGENT_SB_IF) +/* + * The following two functions are meant to restart *the lte-softmodem* and are + * here to make oaisim compile. A restart command from the controller will be + * ignored in oaisim. + */ +int stop_L1L2(int enb_id) +{ + LOG_W(FLEXRAN_AGENT, "stop_L1L2() not supported in oaisim\n"); + return 0; +} + +int restart_L1L2(int enb_id) +{ + LOG_W(FLEXRAN_AGENT, "restart_L1L2() not supported in oaisim\n"); + return 0; +} +#endif + #if T_TRACER int T_wait = 1; /* by default we wait for the tracer */ int T_port = 2021; /* default port to listen to to wait for the tracer */ From 7e3b1f5d0a765626b8f3ccc32ffea9f1bb386ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Iardella?= Date: Tue, 13 Feb 2018 13:20:58 +0100 Subject: [PATCH 248/284] Niccolo: Add sorting policy --- openair2/COMMON/platform_types.h | 9 ++ openair2/LAYER2/MAC/defs.h | 4 + openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 15 +- openair2/LAYER2/MAC/pre_processor.c | 162 +++++++++++++--------- openair2/LAYER2/MAC/proto.h | 2 +- 5 files changed, 126 insertions(+), 66 deletions(-) diff --git a/openair2/COMMON/platform_types.h b/openair2/COMMON/platform_types.h index 1236b93366..0ab8d96701 100644 --- a/openair2/COMMON/platform_types.h +++ b/openair2/COMMON/platform_types.h @@ -100,6 +100,15 @@ typedef enum rb_type_e { RADIO_ACCESS_BEARER = 2 } rb_type_t; +typedef enum { + CR_ROUND = 0, + CR_SRB12 = 1, + CR_HOL = 2, + CR_LC = 3, + CR_CQI = 4, + CR_NUM = 5 +} sorting_criterion_t; + //----------------------------------------------------------------------------- // PHY TYPES //----------------------------------------------------------------------------- diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index de53479e6f..ef1d710138 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -963,6 +963,10 @@ typedef struct { int avail; int num_UEs; boolean_t active[NUMBER_OF_UE_MAX]; + + /// Sorting criteria for the UE list in the MAC preprocessor + uint16_t sorting_criteria[MAX_NUM_SLICES][CR_NUM]; + } UE_list_t; /*! \brief eNB common channels */ diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 7d0a93c2bf..48b19b0919 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -98,6 +98,10 @@ char *dl_scheduler_type[MAX_NUM_SLICES] = "schedule_ue_spec" }; +// The lists of criteria that enforce the sorting policies of the slices +uint32_t sorting_policy[MAX_NUM_SLICES] = {0x01234, 0x01234, 0x01234, 0x01234}; +uint32_t sorting_policy_current[MAX_NUM_SLICES] = {0x01234, 0x01234, 0x01234, 0x01234}; + // pointer to the slice specific scheduler slice_scheduler_dl slice_sched_dl[MAX_NUM_SLICES] = {0}; @@ -447,7 +451,7 @@ schedule_dlsch(module_id_t module_idP, //------------------------------------------------------------------------------{ { - int i=0; + int i = 0; total_slice_percentage=0; avg_slice_percentage=1.0/n_active_slices; @@ -470,7 +474,7 @@ schedule_dlsch(module_id_t module_idP, // Load any updated functions if (update_dl_scheduler[i] > 0 ) { slice_sched_dl[i] = dlsym(NULL, dl_scheduler_type[i]); - update_dl_scheduler[i] = 0; + update_dl_scheduler[i] = 0 ; update_dl_scheduler_current[i] = 0; LOG_N(MAC,"update dl scheduler slice %d\n", i); } @@ -538,6 +542,13 @@ schedule_dlsch(module_id_t module_idP, } } + // Check for new sorting policy + if (sorting_policy_current[i] != sorting_policy[i]) { + LOG_N(MAC,"[eNB %d][SLICE %d][DL] frame %d subframe %d: UE sorting policy has changed (%x-->%x)\n", + module_idP, i, frameP, subframeP, sorting_policy_current[i], sorting_policy[i]); + sorting_policy_current[i] = sorting_policy[i]; + } + // Run each enabled slice-specific schedulers one by one slice_sched_dl[i](module_idP, i, frameP, subframeP, mbsfn_flag/*, dl_info*/); } diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 8f7a6bddff..759bc591dd 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -52,13 +52,13 @@ #include "rlc.h" - #define DEBUG_eNB_SCHEDULER 1 #define DEBUG_HEADER_PARSING 1 //#define DEBUG_PACKET_TRACE 1 extern float slice_percentage[MAX_NUM_SLICES]; extern float slice_percentage_uplink[MAX_NUM_SLICES]; +extern uint32_t sorting_policy[MAX_NUM_SLICES]; extern int slice_maxmcs[MAX_NUM_SLICES]; extern int slice_maxmcs_uplink[MAX_NUM_SLICES]; @@ -352,6 +352,7 @@ struct sort_ue_dl_params { int Mod_idP; int frameP; int subframeP; + int slice_id; }; static int ue_dl_compare(const void *_a, const void *_b, void *_params) @@ -359,62 +360,73 @@ static int ue_dl_compare(const void *_a, const void *_b, void *_params) struct sort_ue_dl_params *params = _params; UE_list_t *UE_list = &RC.mac[params->Mod_idP]->UE_list; + int i; + int slice_id = params->slice_id; int UE_id1 = *(const int *) _a; int UE_id2 = *(const int *) _b; int rnti1 = UE_RNTI(params->Mod_idP, UE_id1); int pCC_id1 = UE_PCCID(params->Mod_idP, UE_id1); - int round1 = - maxround(params->Mod_idP, rnti1, params->frameP, params->subframeP, - 1); + int round1 = maxround(params->Mod_idP, rnti1, params->frameP, params->subframeP, 1); int rnti2 = UE_RNTI(params->Mod_idP, UE_id2); int pCC_id2 = UE_PCCID(params->Mod_idP, UE_id2); - int round2 = - maxround(params->Mod_idP, rnti2, params->frameP, params->subframeP, - 1); + int round2 = maxround(params->Mod_idP, rnti2, params->frameP, params->subframeP, 1); int cqi1 = maxcqi(params->Mod_idP, UE_id1); int cqi2 = maxcqi(params->Mod_idP, UE_id2); - if (round1 > round2) - return -1; - if (round1 < round2) - return 1; + for (i = 0; i < CR_NUM; ++i) { + switch (UE_list->sorting_criteria[slice_id][i]) { - if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[1] + - UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[2] > - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[1] + - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[2]) - return -1; - if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[1] + - UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[2] < - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[1] + - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[2]) - return 1; + case CR_ROUND : + if (round1 > round2) + return -1; + if (round1 < round2) + return 1; + break; - if (UE_list-> - UE_template[pCC_id1][UE_id1].dl_buffer_head_sdu_creation_time_max > - UE_list-> - UE_template[pCC_id2][UE_id2].dl_buffer_head_sdu_creation_time_max) - return -1; - if (UE_list-> - UE_template[pCC_id1][UE_id1].dl_buffer_head_sdu_creation_time_max < - UE_list-> - UE_template[pCC_id2][UE_id2].dl_buffer_head_sdu_creation_time_max) - return 1; + case CR_SRB12 : + if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[1] + + UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[2] > + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[1] + + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[2]) + return -1; + if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[1] + + UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[2] < + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[1] + + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[2]) + return 1; + break; - if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_total > - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_total) - return -1; - if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_total < - UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_total) - return 1; + case CR_HOL : + if (UE_list-> UE_template[pCC_id1][UE_id1].dl_buffer_head_sdu_creation_time_max > + UE_list-> UE_template[pCC_id2][UE_id2].dl_buffer_head_sdu_creation_time_max) + return -1; + if (UE_list-> UE_template[pCC_id1][UE_id1].dl_buffer_head_sdu_creation_time_max < + UE_list-> UE_template[pCC_id2][UE_id2].dl_buffer_head_sdu_creation_time_max) + return 1; + break; - if (cqi1 > cqi2) - return -1; - if (cqi1 < cqi2) - return 1; + case CR_LC : + if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_total > + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_total) + return -1; + if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_total < + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_total) + return 1; + break; + + case CR_CQI : + if (cqi1 > cqi2) + return -1; + if (cqi1 < cqi2) + return 1; + + default : + break; + } + } return 0; #if 0 @@ -449,40 +461,64 @@ static int ue_dl_compare(const void *_a, const void *_b, void *_params) #endif } +void decode_sorting_policy(module_id_t Mod_idP, slice_id_t slice_id) { + int i; + + UE_list_t *UE_list = &RC.mac[Mod_idP]->UE_list; + uint32_t policy = sorting_policy[slice_id]; + uint32_t mask = 0x0000000F; + uint16_t criterion; + + for(i = 0; i < CR_NUM; ++i) { + criterion = (uint16_t)(policy >> 4*(CR_NUM - 1 - i) & mask); + if (criterion >= CR_NUM) { + LOG_W(MAC, "Invalid criterion in slice %d policy, revert to default policy \n", slice_id); + sorting_policy[slice_id] = 0x1234; + break; + } + UE_list->sorting_criteria[slice_id][i] = criterion; + } +} + + // This fuction sorts the UE in order their dlsch buffer and CQI -void sort_UEs(module_id_t Mod_idP, int frameP, sub_frame_t subframeP) +void sort_UEs(module_id_t Mod_idP, slice_id_t slice_id, int frameP, sub_frame_t subframeP) { int i; int list[NUMBER_OF_UE_MAX]; int list_size = 0; int rnti; - struct sort_ue_dl_params params = { Mod_idP, frameP, subframeP }; + struct sort_ue_dl_params params = { Mod_idP, frameP, subframeP, slice_id }; UE_list_t *UE_list = &RC.mac[Mod_idP]->UE_list; - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { + for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i] == FALSE) - continue; - if ((rnti = UE_RNTI(Mod_idP, i)) == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; + if (UE_list->active[i] == FALSE) + continue; + if ((rnti = UE_RNTI(Mod_idP, i)) == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + if (!ue_slice_membership(i, slice_id)) + continue; - list[list_size] = i; - list_size++; - } + list[list_size] = i; + list_size++; + } - qsort_r(list, list_size, sizeof(int), ue_dl_compare, ¶ms); + decode_sorting_policy(Mod_idP, slice_id); - if (list_size) { - for (i = 0; i < list_size - 1; i++) - UE_list->next[list[i]] = list[i + 1]; - UE_list->next[list[list_size - 1]] = -1; - UE_list->head = list[0]; - } else { - UE_list->head = -1; - } + qsort_r(list, list_size, sizeof(int), ue_dl_compare, ¶ms); + + if (list_size) { + for (i = 0; i < list_size - 1; i++) + UE_list->next[list[i]] = list[i + 1]; + UE_list->next[list[list_size - 1]] = -1; + UE_list->head = list[0]; + } else { + UE_list->head = -1; + } #if 0 @@ -651,7 +687,7 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, // Sorts the user on the basis of dlsch logical channel buffer and CQI - sort_UEs(Mod_id, frameP, subframeP); + sort_UEs(Mod_id, slice_id, frameP, subframeP); // loop over all active UEs diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index be09385ac9..348b080d1e 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -675,7 +675,7 @@ void assign_max_mcs_min_rb(module_id_t module_idP, int slice_id, int frameP, void adjust_bsr_info(int buffer_occupancy, uint16_t TBS, UE_TEMPLATE * UE_template); int phy_stats_exist(module_id_t Mod_id, int rnti); -void sort_UEs (module_id_t Mod_idP, int frameP, sub_frame_t subframeP); +void sort_UEs(module_id_t Mod_idP, slice_id_t slice_id, int frameP, sub_frame_t subframeP); /*! \fn UE_L2_state_t ue_scheduler(const module_id_t module_idP,const frame_t frameP, const sub_frame_t subframe, const lte_subframe_t direction,const uint8_t eNB_index) \brief UE scheduler where all the ue background tasks are done. This function performs the following: 1) Trigger PDCP every 5ms 2) Call RRC for link status return to PHY3) Perform SR/BSR procedures for scheduling feedback 4) Perform PHR procedures. From a4f260f5a4d1e345b34485b23731d9d2d67339bb Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 14 Feb 2018 17:50:41 +0100 Subject: [PATCH 249/284] fix: no FLEXRAN_AGENT_SB_IF compilation directive --- targets/SIMU/USER/oaisim.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index 9434b2dd83..3a282e1d44 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -988,7 +988,6 @@ l2l1_task (void *args_p) return NULL; } -#if defined(FLEXRAN_AGENT_SB_IF) /* * The following two functions are meant to restart *the lte-softmodem* and are * here to make oaisim compile. A restart command from the controller will be @@ -1005,7 +1004,6 @@ int restart_L1L2(int enb_id) LOG_W(FLEXRAN_AGENT, "restart_L1L2() not supported in oaisim\n"); return 0; } -#endif #if T_TRACER int T_wait = 1; /* by default we wait for the tracer */ From 91332d3906e577df9032a766af4fd4600e2fc2fe Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 14 Feb 2018 17:49:50 +0100 Subject: [PATCH 250/284] fixup previous bad merge (UE disconnection did not work properly anymore) Doing airplane mode off to connect a cots UE followed by airplane mode on to disconnect it gives very bad results (bad disconnection with lots of UL failures followed by lots of logs in the eNB). It used to work properly after the work done by Xu Bo. It turns out that in 2018.w04 things were still working okay. But in 2018.w05 no. So I ran: git diff 2018.w04 2018.w05 And I checked all the modifications that I thought were relevant (everything related to the UE, oaisim, if4 and fapi has not been checked). This commits takes back the version of 2018.w04. The modifications in openair2/RRC/LITE/rrc_eNB.c are necessary, I think. The other modifications may not be necessary or even wrong. To be checked at some point. --- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 2 +- openair1/SCHED/fapi_l1.c | 9 +++-- openair1/SCHED/phy_procedures_lte_eNb.c | 6 ++- openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 1 + openair2/RRC/LITE/rrc_eNB.c | 50 +++++++++++++++++++++++-- 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index c6c1322504..086f77e14c 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -6556,7 +6556,7 @@ uint8_t pdcch_alloc2ul_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t n) else ul_subframe = ((n+4)%10); - // AssertFatal(frame_parms->frame_type == FDD || subframe_select(frame_parms,ul_subframe) == SF_UL,"illegal ul_subframe %d (n %d)\n",ul_subframe,n); + AssertFatal(frame_parms->frame_type == FDD || subframe_select(frame_parms,ul_subframe) == SF_UL,"illegal ul_subframe %d (n %d)\n",ul_subframe,n); LOG_D(PHY, "subframe %d: PUSCH subframe = %d\n", n, ul_subframe); return ul_subframe; diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c index b9024bdfbf..9c855d0ac8 100644 --- a/openair1/SCHED/fapi_l1.c +++ b/openair1/SCHED/fapi_l1.c @@ -629,7 +629,8 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) fp = &eNB->frame_parms; proc = &eNB->proc.proc_rxtx[0]; - if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)==SF_UL)) return; + /* TODO: check that following line is correct - in the meantime it is disabled */ + //if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)==SF_UL)) return; ul_subframe = pdcch_alloc2ul_subframe(fp,subframe); ul_frame = pdcch_alloc2ul_frame(fp,frame,subframe); @@ -664,8 +665,10 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) int do_oai =0; int dont_send =0; - if ((ul_subframe<10)&& - (subframe_select(fp,ul_subframe)==SF_UL)) { // This means that there is an ul_subframe that can be configured here + /* TODO: check the following test - in the meantime it is put back as it was before */ + //if ((ul_subframe<10)&& + // (subframe_select(fp,ul_subframe)==SF_UL)) { // This means that there is an ul_subframe that can be configured here + if (ul_subframe<10) { // This means that there is an ul_subframe that can be configured here LOG_D(PHY,"NFAPI: Clearing dci allocations for potential UL subframe %d\n",ul_subframe); harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 2ae79b53b6..9aaf6752fb 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -452,8 +452,10 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, } /* save old HARQ information needed for PHICH generation */ - if ((ul_subframe < 10)&& - (subframe_select(fp,ul_subframe)==SF_UL)) { // This means that there is a potential UL subframe that will be scheduled here + /* TODO: check the following test - in the meantime it is put back as it was before */ + //if ((ul_subframe < 10)&& + // (subframe_select(fp,ul_subframe)==SF_UL)) { // This means that there is a potential UL subframe that will be scheduled here + if (ul_subframe < 10) { // This means that there is a potential UL subframe that will be scheduled here for (i=0; iulsch[i]) { diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index bb264a8906..d5d5da8741 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -634,6 +634,7 @@ pdcp_data_ind( rb_id, sdu_buffer_sizeP - pdcp_header_len - pdcp_tailer_len, (uint8_t*)&sdu_buffer_pP->data[pdcp_header_len]); + free_mem_block(sdu_buffer_pP, __func__); // free_mem_block(new_sdu, __func__); diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 946da42920..25c04b8cfb 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -6682,26 +6682,58 @@ rrc_rx_tx( RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(RC.rrc[ctxt_pP->module_id]->rrc_ue_head)) { if ((ctxt_pP->frame == 0) && (ctxt_pP->subframe==0)) { if (ue_context_p->ue_context.Initialue_identity_s_TMSI.presence == TRUE) { - LOG_I(RRC,"UE rnti %x:S-TMSI %x failure timer %d/20000\n", + LOG_I(RRC,"UE rnti %x:S-TMSI %x failure timer %d/8\n", ue_context_p->ue_context.rnti, ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, ue_context_p->ue_context.ul_failure_timer); } else { - LOG_I(RRC,"UE rnti %x failure timer %d/20000\n", + LOG_I(RRC,"UE rnti %x failure timer %d/8\n", ue_context_p->ue_context.rnti, ue_context_p->ue_context.ul_failure_timer); } } if (ue_context_p->ue_context.ul_failure_timer>0) { ue_context_p->ue_context.ul_failure_timer++; - if (ue_context_p->ue_context.ul_failure_timer >= 20000) { + if (ue_context_p->ue_context.ul_failure_timer >= 8) { // remove UE after 20 seconds after MAC has indicated UL failure LOG_I(RRC,"Removing UE %x instance\n",ue_context_p->ue_context.rnti); ue_to_be_removed = ue_context_p; break; } } + if (ue_context_p->ue_context.ue_release_timer_s1>0) { + ue_context_p->ue_context.ue_release_timer_s1++; + if (ue_context_p->ue_context.ue_release_timer_s1 >= + ue_context_p->ue_context.ue_release_timer_thres_s1) { + LOG_I(RRC,"Removing UE %x instance Because of UE_CONTEXT_RELEASE_COMMAND not received after %d ms from sending request\n", + ue_context_p->ue_context.rnti, ue_context_p->ue_context.ue_release_timer_thres_s1); + ue_to_be_removed = ue_context_p; + break; + } + } + + if (ue_context_p->ue_context.ue_release_timer_rrc>0) { + ue_context_p->ue_context.ue_release_timer_rrc++; + if (ue_context_p->ue_context.ue_release_timer_rrc >= + ue_context_p->ue_context.ue_release_timer_thres_rrc) { + LOG_I(RRC,"Removing UE %x instance After UE_CONTEXT_RELEASE_Complete\n", ue_context_p->ue_context.rnti); + ue_to_be_removed = ue_context_p; + break; + } + } + + if (ue_context_p->ue_context.ue_reestablishment_timer>0) { + ue_context_p->ue_context.ue_reestablishment_timer++; + if (ue_context_p->ue_context.ue_reestablishment_timer >= + ue_context_p->ue_context.ue_reestablishment_timer_thres) { + LOG_I(RRC,"UE %d reestablishment_timer max\n",ue_context_p->ue_context.rnti); + ue_context_p->ue_context.ul_failure_timer = 20000; + ue_to_be_removed = ue_context_p; + ue_context_p->ue_context.ue_reestablishment_timer = 0; + break; + } + } if (ue_context_p->ue_context.ue_release_timer>0) { ue_context_p->ue_context.ue_release_timer++; if (ue_context_p->ue_context.ue_release_timer >= @@ -6712,8 +6744,18 @@ rrc_rx_tx( } } } - if (ue_to_be_removed) + if (ue_to_be_removed) { + if(ue_to_be_removed->ue_context.ul_failure_timer >= 8) { + ue_to_be_removed->ue_context.ue_release_timer_s1 = 1; + ue_to_be_removed->ue_context.ue_release_timer_thres_s1 = 100; + ue_to_be_removed->ue_context.ue_release_timer = 0; + ue_to_be_removed->ue_context.ue_reestablishment_timer = 0; + } rrc_eNB_free_UE(ctxt_pP->module_id,ue_to_be_removed); + if(ue_to_be_removed->ue_context.ul_failure_timer >= 8){ + ue_to_be_removed->ue_context.ul_failure_timer = 0; + } + } #ifdef RRC_LOCALIZATION From e4a5470d4754b674d833b7af85f74dda0c742bcc Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 15 Feb 2018 11:34:53 +0100 Subject: [PATCH 251/284] integration fix: noS1 compilation The following compilation did not work anymore: ./build_oai --eNB -c -w USRP --noS1 Neither did: ./build_oai --UE --noS1 --- openair2/RRC/LITE/defs.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index 01475715f4..08ac30f836 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -65,6 +65,9 @@ #include "UE-EUTRA-Capability.h" #include "MeasResults.h" +/* for ImsiMobileIdentity_t */ +#include "MobileIdentity.h" + /* correct Rel(8|10)/Rel14 differences * the code is in favor of Rel14, those defines do the translation */ From b2ac257ef5b728c52912ba7156ad2ff01f1c346f Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 15 Feb 2018 13:40:34 +0100 Subject: [PATCH 252/284] integration fix: compilation failed The following compilation failed before this commit: ./build_oai --eNB -w USRP -c --T-tracer --- openair2/ENB_APP/enb_app.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index a1d3da9ccc..481bfaa521 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -204,7 +204,7 @@ void *eNB_app_task(void *args_p) switch (ITTI_MSG_ID(msg_p)) { case TERMINATE_MESSAGE: - LOG_W(TASK_ENB_APP, " *** Exiting ENB_APP thread\n"); + LOG_W(ENB_APP, " *** Exiting ENB_APP thread\n"); itti_exit_task (); break; From c0be5a129cae522ea29c29039403ca775128b587 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 15 Feb 2018 16:50:30 +0100 Subject: [PATCH 253/284] integration fix: set default max MCS for UL back to 20 Doing an iperf UDP uplink test, we could reach only 6Mb/s with very good radio conditions instead of around 8Mb/s. It turns out the MCS was limited to 16. With this commit, we are back to a bit more than 8Mb/s as it used to be. (This is with a 5MHz bandwidth.) --- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index a8d686dac9..ac87498560 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -95,8 +95,8 @@ float total_slice_percentage_uplink = 0; float total_slice_percentage_current_uplink = 0; // MAX MCS for each slice for past and current time -int slice_maxmcs_uplink[MAX_NUM_SLICES] = {16, 16, 16, 16}; -int slice_maxmcs_current_uplink[MAX_NUM_SLICES] = {16,16,16,16}; +int slice_maxmcs_uplink[MAX_NUM_SLICES] = {20, 20, 20, 20}; +int slice_maxmcs_current_uplink[MAX_NUM_SLICES] = {20,20,20,20}; /*resource blocks allowed*/ uint16_t nb_rbs_allowed_slice_uplink[MAX_NUM_CCs][MAX_NUM_SLICES]; From 2d6dd02b95321cef2349dbc17dc8fb3461f6c4c6 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 16 Feb 2018 11:08:39 +0100 Subject: [PATCH 254/284] bugfix: fix bad conflict resolutions from previous commits Some more fixes for some bad conflict resolutions. I ran: git diff 2018.w04 2018.w05 And saw some problems with config_sib2. There was also something strange in openair2/LAYER2/openair2_proc.c in the function dump_eNB_l2_stats. Maybe the fix is wrong for this one. To be checked. --- openair2/LAYER2/MAC/config.c | 242 ++++++++++++++++++++------------ openair2/LAYER2/openair2_proc.c | 4 +- 2 files changed, 156 insertions(+), 90 deletions(-) diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index 55585acd23..f45cc45af1 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -437,59 +437,31 @@ config_sib2(int Mod_idP, cfg->num_tlv++; - nfapi_config_request_t *cfg = &RC.mac[Mod_idP]->config[CC_idP]; - - cfg->subframe_config.pb.value = radioResourceConfigCommonP->pdsch_ConfigCommon.p_b; - cfg->rf_config.reference_signal_power.value = radioResourceConfigCommonP->pdsch_ConfigCommon.referenceSignalPower; - cfg->nfapi_config.max_transmit_power.value = cfg->rf_config.reference_signal_power.value + - power_off_dB[cfg->rf_config.dl_channel_bandwidth.value]; - - cfg->prach_config.configuration_index.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.prach_ConfigIndex; - cfg->prach_config.root_sequence_index.value = radioResourceConfigCommonP->prach_Config.rootSequenceIndex; - cfg->prach_config.zero_correlation_zone_configuration.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig; - cfg->prach_config.high_speed_flag.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.highSpeedFlag; - cfg->prach_config.frequency_offset.value = radioResourceConfigCommonP->prach_Config.prach_ConfigInfo.prach_FreqOffset; - - cfg->pusch_config.hopping_mode.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.hoppingMode; - cfg->pusch_config.number_of_subbands.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.n_SB; - cfg->pusch_config.hopping_offset.value = radioResourceConfigCommonP->pusch_ConfigCommon.pusch_ConfigBasic.pusch_HoppingOffset; - - cfg->pucch_config.delta_pucch_shift.value = radioResourceConfigCommonP->pucch_ConfigCommon.deltaPUCCH_Shift; - cfg->pucch_config.n_cqi_rb.value = radioResourceConfigCommonP->pucch_ConfigCommon.nRB_CQI; - cfg->pucch_config.n_an_cs.value = radioResourceConfigCommonP->pucch_ConfigCommon.nCS_AN; - cfg->pucch_config.n1_pucch_an.value = radioResourceConfigCommonP->pucch_ConfigCommon.n1PUCCH_AN; - - if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupHoppingEnabled == true) - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 1; - else if (radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled == true) - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 2; - else // No hopping - cfg->uplink_reference_signal_config.uplink_rs_hopping.value = 0; - - cfg->uplink_reference_signal_config.group_assignment.value = radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH; - cfg->uplink_reference_signal_config.cyclic_shift_1_for_drms.value = radioResourceConfigCommonP->pusch_ConfigCommon.ul_ReferenceSignalsPUSCH.cyclicShift; - - // how to enable/disable SRS? - if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.present == SoundingRS_UL_ConfigCommon_PR_setup) { - cfg->srs_config.bandwidth_configuration.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_BandwidthConfig; - cfg->srs_config.srs_subframe_configuration.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_SubframeConfig; - cfg->srs_config.srs_acknack_srs_simultaneous_transmission.value = radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; - - if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts) - cfg->srs_config.max_up_pts.value = 1; - else - cfg->srs_config.max_up_pts.value = 0; + if (radioResourceConfigCommonP->soundingRS_UL_ConfigCommon.choice.setup.srs_MaxUpPts) { + cfg->srs_config.max_up_pts.value = 1; } + else { + cfg->srs_config.max_up_pts.value = 0; + } + cfg->srs_config.max_up_pts.tl.tag = NFAPI_SRS_CONFIG_MAX_UP_PTS_TAG; + cfg->num_tlv++; } + #ifdef Rel14 if (RC.mac[Mod_idP]->common_channels[CC_idP].mib->message.schedulingInfoSIB1_BR_r13 > 0) { - AssertFatal(radioResourceConfigCommon_BRP != NULL, - "radioResource rou is missing\n"); - AssertFatal(radioResourceConfigCommon_BRP->ext4 != NULL, - "ext4 is missing\n"); + AssertFatal(radioResourceConfigCommon_BRP != NULL, "radioResource rou is missing\n"); + AssertFatal(radioResourceConfigCommon_BRP->ext4 != NULL, "ext4 is missing\n"); cfg->emtc_config.prach_catm_root_sequence_index.value = radioResourceConfigCommon_BRP->prach_Config.rootSequenceIndex; + cfg->emtc_config.prach_catm_root_sequence_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CATM_ROOT_SEQUENCE_INDEX_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_catm_zero_correlation_zone_configuration.value = radioResourceConfigCommon_BRP->prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig; + cfg->emtc_config.prach_catm_zero_correlation_zone_configuration.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CATM_ZERO_CORRELATION_ZONE_CONFIGURATION_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_catm_high_speed_flag.value = radioResourceConfigCommon_BRP->prach_Config.prach_ConfigInfo.highSpeedFlag; + cfg->emtc_config.prach_catm_high_speed_flag.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CATM_HIGH_SPEED_FLAG; + cfg->num_tlv++; struct PRACH_ConfigSIB_v1310 *ext4_prach = radioResourceConfigCommon_BRP->ext4->prach_ConfigCommon_v1310; @@ -497,94 +469,186 @@ config_sib2(int Mod_idP, PRACH_ParametersCE_r13_t *p; cfg->emtc_config.prach_ce_level_0_enable.value = 0; + cfg->emtc_config.prach_ce_level_0_enable.tl.tag=NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_ENABLE_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_1_enable.value = 0; + cfg->emtc_config.prach_ce_level_1_enable.tl.tag=NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_ENABLE_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_2_enable.value = 0; + cfg->emtc_config.prach_ce_level_2_enable.tl.tag=NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_ENABLE_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_3_enable.value = 0; + cfg->emtc_config.prach_ce_level_3_enable.tl.tag=NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_ENABLE_TAG; + cfg->num_tlv++; + switch (prach_ParametersListCE_r13->list.count) { case 4: p = prach_ParametersListCE_r13->list.array[3]; cfg->emtc_config.prach_ce_level_3_enable.value = 1; + cfg->emtc_config.prach_ce_level_3_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_ENABLE_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_3_configuration_index.value = p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_3_configuration_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_CONFIGURATION_INDEX_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_3_frequency_offset.value = p->prach_FreqOffset_r13; + cfg->emtc_config.prach_ce_level_3_frequency_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_FREQUENCY_OFFSET_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) + cfg->emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + cfg->num_tlv++; + + if (p->prach_StartingSubframe_r13) { cfg->emtc_config.prach_ce_level_3_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_3_starting_subframe_periodicity.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_STARTING_SUBFRAME_PERIODICITY_TAG; + cfg->num_tlv++; + } + cfg->emtc_config.prach_ce_level_3_hopping_enable.value = p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_3_hopping_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_ENABLE_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_3_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value - 6; + cfg->emtc_config.prach_ce_level_3_hopping_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_3_HOPPING_OFFSET_TAG; + cfg->num_tlv++; + case 3: p = prach_ParametersListCE_r13->list.array[2]; cfg->emtc_config.prach_ce_level_2_enable.value = 1; + cfg->emtc_config.prach_ce_level_2_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_ENABLE_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_2_configuration_index.value = p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_2_configuration_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_CONFIGURATION_INDEX_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_2_frequency_offset.value = p->prach_FreqOffset_r13; + cfg->emtc_config.prach_ce_level_2_frequency_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_FREQUENCY_OFFSET_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) + cfg->emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + cfg->num_tlv++; + + if (p->prach_StartingSubframe_r13) { cfg->emtc_config.prach_ce_level_2_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_2_starting_subframe_periodicity.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_STARTING_SUBFRAME_PERIODICITY_TAG; + cfg->num_tlv++; + } + cfg->emtc_config.prach_ce_level_2_hopping_enable.value = p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_2_hopping_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_ENABLE_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_2_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value - 6; + cfg->emtc_config.prach_ce_level_2_hopping_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_2_HOPPING_OFFSET_TAG; + cfg->num_tlv++; + case 2: p = prach_ParametersListCE_r13->list.array[1]; cfg->emtc_config.prach_ce_level_1_enable.value = 1; + cfg->emtc_config.prach_ce_level_1_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_ENABLE_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_1_configuration_index.value = p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_1_configuration_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_CONFIGURATION_INDEX_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_1_frequency_offset.value = p->prach_FreqOffset_r13; + cfg->emtc_config.prach_ce_level_1_frequency_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_FREQUENCY_OFFSET_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) + cfg->emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + cfg->num_tlv++; + + if (p->prach_StartingSubframe_r13) { cfg->emtc_config.prach_ce_level_1_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_1_starting_subframe_periodicity.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_STARTING_SUBFRAME_PERIODICITY_TAG; + cfg->num_tlv++; + } + cfg->emtc_config.prach_ce_level_1_hopping_enable.value = p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_1_hopping_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_ENABLE_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_1_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value - 6; + cfg->emtc_config.prach_ce_level_1_hopping_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_1_HOPPING_OFFSET_TAG; + cfg->num_tlv++; + case 1: p = prach_ParametersListCE_r13->list.array[0]; cfg->emtc_config.prach_ce_level_0_enable.value = 1; + cfg->emtc_config.prach_ce_level_0_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_ENABLE_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_0_configuration_index.value = p->prach_ConfigIndex_r13; + cfg->emtc_config.prach_ce_level_0_configuration_index.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_CONFIGURATION_INDEX_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_0_frequency_offset.value = p->prach_FreqOffset_r13; + cfg->emtc_config.prach_ce_level_0_frequency_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_FREQUENCY_OFFSET_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13; - if (p->prach_StartingSubframe_r13) + cfg->emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_NUMBER_OF_REPETITIONS_PER_ATTEMPT_TAG; + cfg->num_tlv++; + + if (p->prach_StartingSubframe_r13) { cfg->emtc_config.prach_ce_level_0_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13; + cfg->emtc_config.prach_ce_level_0_starting_subframe_periodicity.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_STARTING_SUBFRAME_PERIODICITY_TAG; + cfg->num_tlv++; + } + cfg->emtc_config.prach_ce_level_0_hopping_enable.value = p->prach_HoppingConfig_r13; + cfg->emtc_config.prach_ce_level_0_hopping_enable.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_ENABLE_TAG; + cfg->num_tlv++; + cfg->emtc_config.prach_ce_level_0_hopping_offset.value = cfg->rf_config.ul_channel_bandwidth.value - 6; + cfg->emtc_config.prach_ce_level_0_hopping_offset.tl.tag = NFAPI_EMTC_CONFIG_PRACH_CE_LEVEL_0_HOPPING_OFFSET_TAG; + cfg->num_tlv++; } struct FreqHoppingParameters_r13 *ext4_freqHoppingParameters = radioResourceConfigCommonP->ext4->freqHoppingParameters_r13; - if ((ext4_freqHoppingParameters)&& - (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13)) - { - switch (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13->present) { - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_NOTHING: /* No components present */ - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_FDD_r13: - cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodea.value = - ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13-> - choice.interval_FDD_r13; - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_TDD_r13: - cfg->emtc_config. - pucch_interval_ulhoppingconfigcommonmodea.value = - ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13-> - choice.interval_TDD_r13; - break; - } - } if ((ext4_freqHoppingParameters) && - (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13)) - { - switch - (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> - present) { - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_NOTHING: /* No components present */ - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_FDD_r13: - cfg->emtc_config. - pucch_interval_ulhoppingconfigcommonmodeb.value = - ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> - choice.interval_FDD_r13; - break; - case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_TDD_r13: - cfg->emtc_config. - pucch_interval_ulhoppingconfigcommonmodeb.value = - ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13-> - choice.interval_TDD_r13; - break; - } + (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13)){ + switch(ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13->present) { + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_NOTHING: /* No components present */ + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_FDD_r13: + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodea.value = ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13->choice.interval_FDD_r13; + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodea.tl.tag = NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEA_TAG; + cfg->num_tlv++; + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeA_r13_PR_interval_TDD_r13: + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodea.value = ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeA_r13->choice.interval_TDD_r13; + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodea.tl.tag = NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEA_TAG; + cfg->num_tlv++; + break; } + } + if ((ext4_freqHoppingParameters) && + (ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13)){ + switch(ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13->present) { + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_NOTHING: /* No components present */ + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_FDD_r13: + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodeb.value = ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13->choice.interval_FDD_r13; + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodeb.tl.tag = NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEB_TAG; + cfg->num_tlv++; + break; + case FreqHoppingParameters_r13__interval_ULHoppingConfigCommonModeB_r13_PR_interval_TDD_r13: + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodeb.value = ext4_freqHoppingParameters->interval_ULHoppingConfigCommonModeB_r13->choice.interval_TDD_r13; + cfg->emtc_config.pucch_interval_ulhoppingconfigcommonmodeb.tl.tag = NFAPI_EMTC_CONFIG_PUCCH_INTERVAL_ULHOPPINGCONFIGCOMMONMODEB_TAG; + cfg->num_tlv++; + break; + } + } } #endif diff --git a/openair2/LAYER2/openair2_proc.c b/openair2/LAYER2/openair2_proc.c index f66d1142ab..7cb6ce0d2c 100644 --- a/openair2/LAYER2/openair2_proc.c +++ b/openair2/LAYER2/openair2_proc.c @@ -228,7 +228,9 @@ int dump_eNB_l2_stats(char *buffer, int length) PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, eNB_id, ENB_FLAG_YES, - UE_list->eNB_UE_stats[0][UE_id].crnti,//UE_PCCID(eNB_id,UE_id)][UE_id].crnti, + /* the following is suspicious, let's put back what was there before */ + /*UE_list->eNB_UE_stats[0][UE_id].crnti,//UE_PCCID(eNB_id,UE_id)][UE_id].crnti, */ + UE_list->eNB_UE_stats[UE_PCCID(eNB_id,UE_id)][UE_id].crnti, eNB->frame, eNB->subframe, eNB_id); From f7c58f27cada6dd0ad1ca478b566f1fac9962e2e Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sat, 17 Feb 2018 11:08:56 -0800 Subject: [PATCH 255/284] dlsim and ulsim functional. dlsim 1-2 antenna ports, TM1/2. ulsim 1-2 antenna ports. --- openair1/PHY/CODING/lte_rate_matching.c | 4 + openair1/PHY/INIT/lte_init.c | 4 +- openair1/PHY/INIT/lte_init_ru.c | 11 +- openair1/PHY/INIT/lte_param_init.c | 10 +- .../PHY/LTE_ESTIMATION/freq_equalization.c | 2 +- .../lte_ul_channel_estimation.c | 5 +- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 14 +- openair1/PHY/LTE_TRANSPORT/drs_modulation.c | 6 +- openair1/PHY/LTE_TRANSPORT/proto.h | 2 +- .../PHY/LTE_TRANSPORT/ulsch_demodulation.c | 76 ++-- openair1/PHY/MODULATION/slot_fep_ul.c | 5 +- openair1/PHY/MODULATION/ul_7_5_kHz.c | 2 +- openair1/SCHED/fapi_l1.c | 13 +- openair1/SCHED/phy_procedures_lte_eNb.c | 12 +- openair1/SCHED/phy_procedures_lte_ue.c | 26 +- openair1/SCHED/ru_procedures.c | 3 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 4 +- openair1/SIMULATION/LTE_PHY/ulsim.c | 382 ++++++++++++------ 18 files changed, 386 insertions(+), 195 deletions(-) diff --git a/openair1/PHY/CODING/lte_rate_matching.c b/openair1/PHY/CODING/lte_rate_matching.c index 13870e3303..f96e5dbb17 100644 --- a/openair1/PHY/CODING/lte_rate_matching.c +++ b/openair1/PHY/CODING/lte_rate_matching.c @@ -749,6 +749,10 @@ int lte_rate_matching_turbo_rx(uint32_t RTC, for (; (ind0 && soft_input2[k]<0) || + (w[ind]<0 && soft_input2[k]>0)) + printf("ind %d: w %d => soft_in %d\n",ind,w[ind],soft_input2[k]);*/ w[ind] += soft_input2[k++]; #ifdef RM_DEBUG printf("RM_RX k%d Ind: %d (%d)\n",k-1,ind,w[ind]); diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 377a235da6..687395ab9b 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -883,10 +883,10 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, for (i=0; i<2; i++) { // RK 2 times because of output format of FFT! // FIXME We should get rid of this - pusch_vars[UE_id]->rxdataF_ext[i] = (int32_t*)malloc16_clear( 2*sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti ); + pusch_vars[UE_id]->rxdataF_ext[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti ); pusch_vars[UE_id]->rxdataF_ext2[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti ); pusch_vars[UE_id]->drs_ch_estimates[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti ); - pusch_vars[UE_id]->drs_ch_estimates_time[i] = (int32_t*)malloc16_clear( 2*2*sizeof(int32_t)*fp->ofdm_symbol_size ); + pusch_vars[UE_id]->drs_ch_estimates_time[i] = (int32_t*)malloc16_clear( 2*sizeof(int32_t)*fp->ofdm_symbol_size ); pusch_vars[UE_id]->rxdataF_comp[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti ); pusch_vars[UE_id]->ul_ch_mag[i] = (int32_t*)malloc16_clear( fp->symbols_per_tti*sizeof(int32_t)*fp->N_RB_UL*12 ); pusch_vars[UE_id]->ul_ch_magb[i] = (int32_t*)malloc16_clear( fp->symbols_per_tti*sizeof(int32_t)*fp->N_RB_UL*12 ); diff --git a/openair1/PHY/INIT/lte_init_ru.c b/openair1/PHY/INIT/lte_init_ru.c index 2d139e0afa..e8bffef6d8 100644 --- a/openair1/PHY/INIT/lte_init_ru.c +++ b/openair1/PHY/INIT/lte_init_ru.c @@ -32,6 +32,11 @@ #include "assertions.h" #include +#undef LOG_I +#define LOG_I(A,B,C...) printf(B,C) +#undef LOG_D +#define LOG_D(A,B,C...) printf(B,C) + int phy_init_RU(RU_t *ru) { LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; @@ -60,7 +65,7 @@ int phy_init_RU(RU_t *ru) { } } // IF5 or local RF else { - LOG_I(PHY,"No rxdata/txdata for RU\n"); + // LOG_I(PHY,"No rxdata/txdata for RU\n"); ru->common.txdata = (int32_t**)NULL; ru->common.rxdata = (int32_t**)NULL; @@ -91,8 +96,8 @@ int phy_init_RU(RU_t *ru) { } /* number of elements of an array X is computed as sizeof(X) / sizeof(X[0]) */ - AssertFatal(ru->nb_rx <= sizeof(ru->prach_rxsigF) / sizeof(ru->prach_rxsigF[0]), - "nb_antennas_rx too large"); + // AssertFatal(ru->nb_rx <= sizeof(ru->prach_rxsigF) / sizeof(ru->prach_rxsigF[0]), + // "nb_antennas_rx too large"); ru->prach_rxsigF = (int16_t**)malloc(ru->nb_rx * sizeof(int16_t*)); for (j=0;j<4;j++) ru->prach_rxsigF_br[j] = (int16_t**)malloc(ru->nb_rx * sizeof(int16_t*)); diff --git a/openair1/PHY/INIT/lte_param_init.c b/openair1/PHY/INIT/lte_param_init.c index 90b7bcee31..d9b7b12249 100644 --- a/openair1/PHY/INIT/lte_param_init.c +++ b/openair1/PHY/INIT/lte_param_init.c @@ -109,10 +109,11 @@ void lte_param_init(PHY_VARS_eNB **eNBp, UE->is_secondary_ue = 0; UE->frame_parms = *frame_parms; + UE->frame_parms.nb_antennas_rx=1; // eNB->frame_parms = *frame_parms; ru->frame_parms = *frame_parms; ru->nb_tx = N_tx_phy; - ru->nb_rx = 1; + ru->nb_rx = N_rx; ru->if_south = LOCAL_RF; eNB->configured=1; @@ -155,6 +156,13 @@ void lte_param_init(PHY_VARS_eNB **eNBp, /* the UE code is multi-thread "aware", we need to setup this array */ for (i = 0; i < 10; i++) UE->current_thread_id[i] = i % 2; + if (eNB->frame_parms.frame_type == TDD) { + if (eNB->frame_parms.N_RB_DL == 100) ru->N_TA_offset = 624; + else if (eNB->frame_parms.N_RB_DL == 50) ru->N_TA_offset = 624/2; + else if (eNB->frame_parms.N_RB_DL == 25) ru->N_TA_offset = 624/4; + } + else ru->N_TA_offset=0; + printf("Done lte_param_init\n"); diff --git a/openair1/PHY/LTE_ESTIMATION/freq_equalization.c b/openair1/PHY/LTE_ESTIMATION/freq_equalization.c index 74a844da8a..2c318d85e4 100644 --- a/openair1/PHY/LTE_ESTIMATION/freq_equalization.c +++ b/openair1/PHY/LTE_ESTIMATION/freq_equalization.c @@ -306,7 +306,7 @@ void freq_equalization(LTE_DL_FRAME_PARMS *frame_parms, AssertFatal(symbolsymbols_per_tti,"symbol %d >= %d\n", symbol,frame_parms->symbols_per_tti); - AssertFatal(Msc_RSN_RB_UL*12,"Msc_RS %d >= %d\n", + AssertFatal(Msc_RS<=frame_parms->N_RB_UL*12,"Msc_RS %d >= %d\n", Msc_RS,frame_parms->N_RB_UL*12); for (re=0; re<(Msc_RS>>2); re++) { diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c index 18069f9759..9eb34a8905 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c @@ -34,6 +34,9 @@ static int16_t ru_90c[2*128] = {32767, 0,32766, -402,32758, -804,32746, -1206,32 #define SCALE 0x3FFF +//#undef LOG_D +//#define LOG_D(A,B,C...) printf(B,C) + int32_t lte_ul_channel_estimation(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, uint8_t UE_id, @@ -100,7 +103,7 @@ int32_t temp_in_ifft_0[2048*2] __attribute__((aligned(32))); return(-1); } - // LOG_I(PHY,"subframe %d, Ns %d, l %d, Msc_RS = %d, Msc_RS_idx = %d, u %d, v %d, cyclic_shift %d\n",subframe,Ns,l,Msc_RS, Msc_RS_idx,u,v,cyclic_shift); + LOG_D(PHY,"subframe %d, Ns %d, l %d, Msc_RS = %d, Msc_RS_idx = %d, u %d, v %d, cyclic_shift %d\n",subframe,Ns,l,Msc_RS, Msc_RS_idx,u,v,cyclic_shift); #ifdef DEBUG_CH if (Ns==0) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 4adcc130dd..fcdda36265 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -44,10 +44,11 @@ #include "LAYER2/MAC/extern.h" #include "LAYER2/MAC/defs.h" -//#undef LOG_D -//#define LOG_D(A,B,C...) printf(B,C) -//#undef LOG_I -//#define LOG_I(A,B,C...) printf(B,C) +/*#undef LOG_D +#define LOG_D(A,B,C...) printf(B,C) +#undef LOG_I +#define LOG_I(A,B,C...) printf(B,C) +*/ //#define DEBUG_DCI @@ -2665,11 +2666,12 @@ void fill_ulsch(PHY_VARS_eNB *eNB,nfapi_ul_config_ulsch_pdu *ulsch_pdu,int frame else if(ulsch->harq_processes[harq_pid]->n_DMRS == 7) ulsch->harq_processes[harq_pid]->n_DMRS2 = 9; - LOG_D(PHY,"[eNB %d][PUSCH %d] Frame %d, Subframe %d Programming PUSCH with n_DMRS2 %d (cshift %d) ulsch:ndi:%d ulsch_pdu:ndi:%d new_ulsch:%d status:%d\n", + LOG_D(PHY,"[eNB %d][PUSCH %d] Frame %d, Subframe %d Programming PUSCH with n_DMRS2 %d (cshift %d) ulsch:ndi:%d ulsch_pdu:ndi:%d new_ulsch:%d status:%d ulsch_pdu:rvidx:%d\n", eNB->Mod_id,harq_pid,frame,subframe, ulsch->harq_processes[harq_pid]->n_DMRS2, ulsch->harq_processes[harq_pid]->n_DMRS, - ulsch->harq_processes[harq_pid]->ndi, ulsch_pdu->ulsch_pdu_rel8.new_data_indication, new_ulsch, ulsch->harq_processes[harq_pid]->status); + ulsch->harq_processes[harq_pid]->ndi, ulsch_pdu->ulsch_pdu_rel8.new_data_indication, new_ulsch, ulsch->harq_processes[harq_pid]->status, + ulsch_pdu->ulsch_pdu_rel8.redundancy_version); ulsch->harq_processes[harq_pid]->rvidx = ulsch_pdu->ulsch_pdu_rel8.redundancy_version; ulsch->harq_processes[harq_pid]->Qm = ulsch_pdu->ulsch_pdu_rel8.modulation_type; diff --git a/openair1/PHY/LTE_TRANSPORT/drs_modulation.c b/openair1/PHY/LTE_TRANSPORT/drs_modulation.c index a432cde4e4..101954ca3d 100644 --- a/openair1/PHY/LTE_TRANSPORT/drs_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/drs_modulation.c @@ -94,8 +94,10 @@ int generate_drs_pusch(PHY_VARS_UE *ue, lsymbols_per_tti; l += (7 - frame_parms->Ncp),u=u1,v=v1,cyclic_shift=cyclic_shift1) { - drs_offset = 0; // printf("drs_modulation: Msc_RS = %d, Msc_RS_idx = %d\n",Msc_RS, Msc_RS_idx); - + drs_offset = 0; +#ifdef DEBUG_DRS + printf("drs_modulation: Msc_RS = %d, Msc_RS_idx = %d, u=%d,v=%d\n",Msc_RS, Msc_RS_idx,u,v); +#endif re_offset = frame_parms->first_carrier_offset; diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index c67820d0dd..c1b85a1561 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -1783,7 +1783,7 @@ int generate_eNB_ulsch_params_from_dci(PHY_VARS_eNB *PHY_vars_eNB, uint8_t use_srs); -void dump_ulsch(PHY_VARS_eNB *phy_vars_eNB,int frame, int subframe, uint8_t UE_id); +void dump_ulsch(PHY_VARS_eNB *phy_vars_eNB,int frame, int subframe, uint8_t UE_id,int round); int dump_dci(LTE_DL_FRAME_PARMS *frame_parms, DCI_ALLOC_t *dci); diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c index 93c1af8d91..ee038508d1 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c @@ -725,8 +725,8 @@ void ulsch_extract_rbs_single(int32_t **rxdataF, //uint8_t symbol = l+Ns*frame_parms->symbols_per_tti/2; uint8_t symbol = l+((7-frame_parms->Ncp)*(Ns&1)); ///symbol within sub-frame - AssertFatal((frame_parms->nb_antennas_rx>0) && (frame_parms->nb_antennas_rx<3), - "nb_antennas_rx not in (1-2)\n"); + AssertFatal((frame_parms->nb_antennas_rx>0) && (frame_parms->nb_antennas_rx<5), + "nb_antennas_rx not in (1-4)\n"); for (aarx=0; aarxnb_antennas_rx; aarx++) { @@ -1349,35 +1349,54 @@ void rx_ulsch_emul(PHY_VARS_eNB *eNB, } - void dump_ulsch(PHY_VARS_eNB *eNB,int frame,int subframe,uint8_t UE_id) { + void dump_ulsch(PHY_VARS_eNB *eNB,int frame,int subframe,uint8_t UE_id,int round) { uint32_t nsymb = (eNB->frame_parms.Ncp == 0) ? 14 : 12; uint8_t harq_pid; + char fname[100],vname[100]; harq_pid = subframe2harq_pid(&eNB->frame_parms,frame,subframe); - printf("Dumping ULSCH in subframe %d with harq_pid %d, for NB_rb %d, TBS %d, Qm %d, N_symb %d\n", - subframe,harq_pid,eNB->ulsch[UE_id]->harq_processes[harq_pid]->nb_rb, + printf("Dumping ULSCH in subframe %d with harq_pid %d, round %d for NB_rb %d, TBS %d, Qm %d, N_symb %d\n", + subframe,harq_pid,round,eNB->ulsch[UE_id]->harq_processes[harq_pid]->nb_rb, eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS,eNB->ulsch[UE_id]->harq_processes[harq_pid]->Qm, eNB->ulsch[UE_id]->harq_processes[harq_pid]->Nsymb_pusch); - write_output("/tmp/ulsch_d.m","ulsch_dseq",&eNB->ulsch[UE_id]->harq_processes[harq_pid]->d[0][96], + sprintf(fname,"/tmp/ulsch_r%d_d",round); + sprintf(vname,"/tmp/ulsch_r%d_dseq",round); + write_output(fname,vname,&eNB->ulsch[UE_id]->harq_processes[harq_pid]->d[0][96], eNB->ulsch[UE_id]->harq_processes[harq_pid]->Kplus*3,1,0); - if (eNB->common_vars.rxdata) write_output("/tmp/rxsig0.m","rxs0", &eNB->common_vars.rxdata[0][0],eNB->frame_parms.samples_per_tti*10,1,1); - - if (eNB->frame_parms.nb_antennas_rx>1) - if (eNB->common_vars.rxdata) write_output("/tmp/rxsig1.m","rxs1", &eNB->common_vars.rxdata[1][0],eNB->frame_parms.samples_per_tti*10,1,1); + if (eNB->common_vars.rxdata) { + sprintf(fname,"/tmp/rxsig0_r%d.m",round); + sprintf(vname,"rxs0_r%d",round); + write_output(fname,vname, &eNB->common_vars.rxdata[0][0],eNB->frame_parms.samples_per_tti*10,1,1); + if (eNB->frame_parms.nb_antennas_rx>1) + if (eNB->common_vars.rxdata) { + sprintf(fname,"/tmp/rxsig1_r%d.m",round); + sprintf(vname,"rxs1_r%d",round); + write_output(fname,vname, &eNB->common_vars.rxdata[1][0],eNB->frame_parms.samples_per_tti*10,1,1); + } + } - write_output("/tmp/rxsigF0.m","rxsF0", &eNB->common_vars.rxdataF[0][0],eNB->frame_parms.ofdm_symbol_size*nsymb,1,1); + sprintf(fname,"/tmp/rxsigF0_r%d.m",round); + sprintf(vname,"rxsF0_r%d",round); + write_output(fname,vname, (void*)&eNB->common_vars.rxdataF[0][0],eNB->frame_parms.ofdm_symbol_size*nsymb,1,1); - if (eNB->frame_parms.nb_antennas_rx>1) - write_output("/tmp/rxsigF1.m","rxsF1", &eNB->common_vars.rxdataF[1][0],eNB->frame_parms.ofdm_symbol_size*nsymb,1,1); + if (eNB->frame_parms.nb_antennas_rx>1) { + sprintf(fname,"/tmp/rxsigF1_r%d.m",round); + sprintf(vname,"rxsF1_r%d",round); + write_output(vname,fname, &eNB->common_vars.rxdataF[1][0],eNB->frame_parms.ofdm_symbol_size*nsymb,1,1); + } - write_output("/tmp/rxsigF0_ext.m","rxsF0_ext", &eNB->pusch_vars[UE_id]->rxdataF_ext[0][0],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); - - if (eNB->frame_parms.nb_antennas_rx>1) - write_output("/tmp/rxsigF1_ext.m","rxsF1_ext", &eNB->pusch_vars[UE_id]->rxdataF_ext[0][0],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); + sprintf(fname,"/tmp/rxsigF0_ext_r%d.m",round); + sprintf(vname,"rxsF0_ext_r%d",round); + write_output(fname,vname, &eNB->pusch_vars[UE_id]->rxdataF_ext[0][0],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); + if (eNB->frame_parms.nb_antennas_rx>1) { + sprintf(fname,"/tmp/rxsigF1_ext_r%d.m",round); + sprintf(vname,"rxsF1_ext_r%d",round); + write_output(fname,vname,&eNB->pusch_vars[UE_id]->rxdataF_ext[0][0],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); + } /* if (eNB->srs_vars[UE_id].srs_ch_estimates) write_output("/tmp/srs_est0.m","srsest0",eNB->srs_vars[UE_id].srs_ch_estimates[0],eNB->frame_parms.ofdm_symbol_size,1,1); @@ -1385,17 +1404,28 @@ void rx_ulsch_emul(PHY_VARS_eNB *eNB, if (eNB->srs_vars[UE_id].srs_ch_estimates) write_output("/tmp/srs_est1.m","srsest1",eNB->srs_vars[UE_id].srs_ch_estimates[1],eNB->frame_parms.ofdm_symbol_size,1,1); */ - write_output("/tmp/drs_est0.m","drsest0",eNB->pusch_vars[UE_id]->drs_ch_estimates[0],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); + sprintf(fname,"/tmp/drs_est0_r%d.m",round); + sprintf(vname,"drsest0_r%d",round); + write_output(fname,vname,eNB->pusch_vars[UE_id]->drs_ch_estimates[0],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); - if (eNB->frame_parms.nb_antennas_rx>1) - write_output("/tmp/drs_est1.m","drsest1",eNB->pusch_vars[UE_id]->drs_ch_estimates[1],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); + if (eNB->frame_parms.nb_antennas_rx>1) { + sprintf(fname,"/tmp/drs_est1_r%d.m",round); + sprintf(vname,"drsest1_r%d",round); + write_output(fname,vname,eNB->pusch_vars[UE_id]->drs_ch_estimates[1],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); + } - write_output("/tmp/ulsch_rxF_comp0.m","ulsch0_rxF_comp0",&eNB->pusch_vars[UE_id]->rxdataF_comp[0][0],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); + sprintf(fname,"/tmp/ulsch0_rxF_comp0_r%d.m",round); + sprintf(vname,"ulsch0_rxF_comp0_r%d",round); + write_output(fname,vname,&eNB->pusch_vars[UE_id]->rxdataF_comp[0][0],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); // write_output("ulsch_rxF_comp1.m","ulsch0_rxF_comp1",&eNB->pusch_vars[UE_id]->rxdataF_comp[0][1][0],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); - write_output("/tmp/ulsch_rxF_llr.m","ulsch_llr",eNB->pusch_vars[UE_id]->llr, + sprintf(fname,"/tmp/ulsch_rxF_llr_r%d.m",round); + sprintf(vname,"ulsch_llr_r%d",round); + write_output(fname,vname,eNB->pusch_vars[UE_id]->llr, eNB->ulsch[UE_id]->harq_processes[harq_pid]->nb_rb*12*eNB->ulsch[UE_id]->harq_processes[harq_pid]->Qm *eNB->ulsch[UE_id]->harq_processes[harq_pid]->Nsymb_pusch,1,0); - write_output("/tmp/ulsch_ch_mag.m","ulsch_ch_mag",&eNB->pusch_vars[UE_id]->ul_ch_mag[0][0],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); + sprintf(fname,"/tmp/ulsch_ch_mag_r%d.m",round); + sprintf(vname,"ulsch_ch_mag_r%d",round); + write_output(fname,vname,&eNB->pusch_vars[UE_id]->ul_ch_mag[0][0],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); // write_output("ulsch_ch_mag1.m","ulsch_ch_mag1",&eNB->pusch_vars[UE_id]->ul_ch_mag[1][0],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); //#endif } diff --git a/openair1/PHY/MODULATION/slot_fep_ul.c b/openair1/PHY/MODULATION/slot_fep_ul.c index 1f2963017e..844d15a87e 100644 --- a/openair1/PHY/MODULATION/slot_fep_ul.c +++ b/openair1/PHY/MODULATION/slot_fep_ul.c @@ -24,6 +24,9 @@ #include "defs.h" //#define DEBUG_FEP +//#undef LOG_D +//#define LOG_D(A,B,C...) printf(B,C) + int slot_fep_ul(RU_t *ru, unsigned char l, unsigned char Ns, @@ -134,7 +137,7 @@ int slot_fep_ul(RU_t *ru, } #ifdef DEBUG_FEP - LOG_D(PHY,"slot_fep: done\n"); + // LOG_D(PHY,"slot_fep: done\n"); #endif return(0); } diff --git a/openair1/PHY/MODULATION/ul_7_5_kHz.c b/openair1/PHY/MODULATION/ul_7_5_kHz.c index 80efc70c40..d92dc1c8b3 100644 --- a/openair1/PHY/MODULATION/ul_7_5_kHz.c +++ b/openair1/PHY/MODULATION/ul_7_5_kHz.c @@ -188,7 +188,7 @@ void remove_7_5_kHz(RU_t *ru,uint8_t slot) } - slot_offset = (uint32_t)slot * frame_parms->samples_per_tti/2-ru->N_TA_offset; + slot_offset = ((uint32_t)slot * frame_parms->samples_per_tti/2)-ru->N_TA_offset; slot_offset2 = (uint32_t)(slot&1) * frame_parms->samples_per_tti/2; len = frame_parms->samples_per_tti/2; diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c index 6cb6e66aac..64de288d29 100644 --- a/openair1/SCHED/fapi_l1.c +++ b/openair1/SCHED/fapi_l1.c @@ -37,10 +37,11 @@ #include "nfapi_interface.h" #include "fapi_l1.h" -//#undef LOG_D -//#define LOG_D(A,B,C...) printf(B,C) -//#undef LOG_I -//#define LOG_I(A,B,C...) printf(B,C) +/*#undef LOG_D +#define LOG_D(A,B,C...) printf(B,C) +#undef LOG_I +#define LOG_I(A,B,C...) printf(B,C) +*/ int oai_nfapi_dl_config_req(nfapi_dl_config_request_t *dl_config_req); int oai_nfapi_tx_req(nfapi_tx_request_t *tx_req); @@ -538,11 +539,11 @@ void handle_nfapi_ul_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, int8_t UE_id; // check if we have received a dci for this ue and ulsch descriptor is configured - + if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) { AssertFatal((UE_id = find_ulsch(ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti,eNB,SEARCH_EXIST_OR_FREE))>=0, "No existing UE ULSCH for rnti %x\n",rel8->rnti); - //LOG_D(PHY,"Applying UL config for UE %d, rnti %x for frame %d, subframe %d\n", UE_id,rel8->rnti,frame,subframe); + LOG_D(PHY,"Applying UL config for UE %d, rnti %x for frame %d, subframe %d, modulation %d, rvidx %d\n", UE_id,rel8->rnti,frame,subframe,rel8->modulation_type,rel8->redundancy_version); fill_ulsch(eNB,&ul_config_pdu->ulsch_pdu,frame,subframe); diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index f771288f35..af845913ba 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -50,8 +50,10 @@ # include "intertask_interface.h" #endif -//#undef LOG_D -//#define LOG_D(A,B,C...) printf(B,C) +/* +#undef LOG_D +#define LOG_D(A,B,C...) printf(B,C) +*/ extern uint8_t nfapi_mode; int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind); @@ -1210,7 +1212,7 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) start_meas(&eNB->ulsch_demodulation_stats); - rx_ulsch(eNB,proc, i); + rx_ulsch(eNB,proc, i); stop_meas(&eNB->ulsch_demodulation_stats); @@ -1263,12 +1265,12 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d Error receiving ULSCH, round %d/%d (ACK %d,%d)\n", eNB->Mod_id,harq_pid, frame,subframe, i, - ulsch_harq->round-1, + ulsch_harq->round, ulsch->Mlimit, ulsch_harq->o_ACK[0], ulsch_harq->o_ACK[1]); - if (ulsch_harq->round >= 3) { + if (ulsch_harq->round >= 4) { ulsch_harq->status = SCH_IDLE; ulsch_harq->handled = 0; ulsch->harq_mask &= ~(1 << harq_pid); diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 0085a31e28..d1097503ea 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -76,6 +76,7 @@ extern double cpuf; //#undef LOG_D //#define LOG_D(A,B,C...) printf(B,C) + void Msg1_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); void Msg3_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); @@ -84,7 +85,7 @@ extern uint32_t downlink_frequency[MAX_NUM_CCs][4]; #endif -#define DEBUG_UE_TRACE 1 +#define UE_DEBUG_TRACE 1 void dump_dlsch(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t subframe,uint8_t harq_pid) { @@ -1269,7 +1270,7 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empt } //#endif - if ((frame_tx%100) == 0) +// if ((frame_tx%100) == 0) LOG_D(PHY,"[UE %d] Frame %d, subframe %d: ulsch_start = %d (rxoff %d, HW TA %d, timing advance %d, TA_offset %d\n", ue->Mod_id,frame_tx,subframe_tx, ulsch_start, @@ -1291,16 +1292,25 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empt nsymb, frame_parms->nb_prefix_samples, CYCLIC_PREFIX); - else + else { normal_prefix_mod(&ue->common_vars.txdataF[aa][subframe_tx*nsymb*frame_parms->ofdm_symbol_size], #if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) - dummy_tx_buffer, + dummy_tx_buffer, #else - &ue->common_vars.txdata[aa][ulsch_start], + &ue->common_vars.txdata[aa][ulsch_start], #endif - nsymb, - &ue->frame_parms); - + nsymb>>1, + &ue->frame_parms); + + normal_prefix_mod(&ue->common_vars.txdataF[aa][((subframe_tx*nsymb)+(nsymb>>1))*frame_parms->ofdm_symbol_size], +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) + dummy_tx_buffer+(frame_parms->samples_per_tti>>1), +#else + &ue->common_vars.txdata[aa][ulsch_start+(frame_parms->samples_per_tti>>1)], +#endif + nsymb>>1, + &ue->frame_parms); + } #if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) apply_7_5_kHz(ue,dummy_tx_buffer,0); diff --git a/openair1/SCHED/ru_procedures.c b/openair1/SCHED/ru_procedures.c index dcab55d66f..0aad195d43 100644 --- a/openair1/SCHED/ru_procedures.c +++ b/openair1/SCHED/ru_procedures.c @@ -536,9 +536,10 @@ void fep_full(RU_t *ru) { start_meas(&ru->ofdm_demod_stats); if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 ); - + remove_7_5_kHz(ru,proc->subframe_rx<<1); remove_7_5_kHz(ru,1+(proc->subframe_rx<<1)); + for (l=0; lsymbols_per_tti/2; l++) { slot_fep_ul(ru, l, diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 128fca79e1..57fa787142 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -1409,8 +1409,8 @@ int main(int argc, char **argv) if (input_fd==NULL) { DL_req.dl_config_request_body.number_pdcch_ofdm_symbols = num_pdcch_symbols; - DL_req.sfn_sf = (proc_eNB->frame_tx*10)+subframe; - TX_req.sfn_sf = (proc_eNB->frame_tx*10)+subframe; + DL_req.sfn_sf = (proc_eNB->frame_tx<<4)+subframe; + TX_req.sfn_sf = (proc_eNB->frame_tx<<4)+subframe; // UE specific DCI fill_DCI(eNB, proc_eNB->frame_tx,subframe, diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index cabe966491..4e31016b6b 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -47,9 +47,7 @@ #include "unitary_defs.h" #include "PHY/TOOLS/lte_phy_scope.h" - -PHY_VARS_eNB *eNB; -PHY_VARS_UE *UE; +#include "dummy_functions.c" double cpuf; @@ -78,9 +76,112 @@ double t_tx_min = 1000000000; /*!< \brief initial min process time for tx */ double t_rx_min = 1000000000; /*!< \brief initial min process time for tx */ int n_tx_dropped = 0; /*!< \brief initial max process time for tx */ int n_rx_dropped = 0; /*!< \brief initial max process time for rx */ +int nfapi_mode = 0; +extern void fep_full(RU_t *ru); +extern void ru_fep_full_2thread(RU_t *ru); -void fill_ulsch_dci(PHY_VARS_eNB *eNB,void *UL_dci,int first_rb,int nb_rb,int mcs,int ndi,int cqi_flag) { +nfapi_dl_config_request_t DL_req; +nfapi_ul_config_request_t UL_req; +nfapi_hi_dci0_request_t HI_DCI0_req; +nfapi_ul_config_request_pdu_t ul_config_pdu_list[MAX_NUM_DL_PDU]; +nfapi_tx_request_pdu_t tx_pdu_list[MAX_NUM_TX_REQUEST_PDU]; +nfapi_tx_request_t TX_req; +Sched_Rsp_t sched_resp; + +void +fill_nfapi_ulsch_config_request(nfapi_ul_config_request_pdu_t *ul_config_pdu, + uint8_t cqi_req, + uint8_t p_eNB, + uint8_t cqi_ReportModeAperiodic, + uint8_t betaOffset_CQI_Index, + uint8_t betaOffset_RI_Index, + uint8_t dl_cqi_pmi_size, + uint8_t tmode, + uint32_t handle, + uint16_t rnti, + uint8_t resource_block_start, + uint8_t number_of_resource_blocks, + uint8_t modulation_type, + uint8_t cyclic_shift_2_for_drms, + uint8_t frequency_hopping_enabled_flag, + uint8_t frequency_hopping_bits, + uint8_t new_data_indication, + uint8_t redundancy_version, + uint8_t harq_process_number, + uint8_t ul_tx_mode, + uint8_t current_tx_nb, + uint8_t n_srs, + uint16_t size) +{ + memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t)); + + // printf("filling ul_config_pdu: modulation type %d, rvidx %d\n",modulation_type,redundancy_version); + + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; + ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_pdu)); + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_PDU_REL8_TAG; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = handle; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = rnti; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = resource_block_start; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = number_of_resource_blocks; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = modulation_type; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = cyclic_shift_2_for_drms; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_enabled_flag = frequency_hopping_enabled_flag; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = frequency_hopping_bits; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = new_data_indication; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = redundancy_version; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = harq_process_number; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = ul_tx_mode; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = current_tx_nb; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = n_srs; + ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = size; + + if (cqi_req == 1) { + // Add CQI portion + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE; + ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_ul_config_ulsch_cqi_ri_pdu)); + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_RI_INFORMATION_REL9_TAG; + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.report_type = 1; + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.number_of_cc = 1; + LOG_D(MAC, "report_type %d\n",ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.report_type); + + if (p_eNB <= 2 + && (tmode == 3 || tmode == 4 || tmode == 8 || tmode == 9 || tmode == 10)) + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 1; + else if (p_eNB <= 2) ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 0; + else if (p_eNB == 4) ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 2; + + for (int ri = 0; + ri < (1 << ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size); + ri++) + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[ri] = dl_cqi_pmi_size; + + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.delta_offset_cqi = betaOffset_CQI_Index; + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.delta_offset_ri = betaOffset_RI_Index; + } +} + +void fill_ulsch_dci(PHY_VARS_eNB *eNB, + int frame, + int subframe, + Sched_Rsp_t *sched_resp, + uint16_t rnti, + void *UL_dci, + int first_rb, + int nb_rb, + int mcs, + int modulation_type, + int ndi, + int cqi_flag, + uint8_t beta_CQI, + uint8_t beta_RI, + uint8_t cqi_size) { + + nfapi_ul_config_request_body_t *ul_req=&sched_resp->UL_req->ul_config_request_body; + int harq_pid = ((frame*10)+subframe)&7; + + // printf("ulsch in frame %d, subframe %d => harq_pid %d, mcs %d, ndi %d\n",frame,subframe,harq_pid,mcs,ndi); switch (eNB->frame_parms.N_RB_UL) { case 6: @@ -162,6 +263,36 @@ void fill_ulsch_dci(PHY_VARS_eNB *eNB,void *UL_dci,int first_rb,int nb_rb,int mc break; } + fill_nfapi_ulsch_config_request(&ul_req->ul_config_pdu_list[0], + cqi_flag&1, + 1, // p_eNB + 0, // reportmode Aperiodic + beta_CQI, + beta_RI, + cqi_size, + //cc, + //UE_template->physicalConfigDedicated, + 1, + 0, + 14, // rnti + first_rb, // resource_block_start + nb_rb, // number_of_resource_blocks + modulation_type, + 0, // cyclic_shift_2_for_drms + 0, // frequency_hopping_enabled_flag + 0, // frequency_hopping_bits + ndi, // new_data_indication + mcs>28?(mcs-28):0, // redundancy_version + harq_pid, // harq_process_number + 0, // ul_tx_mode + 0, // current_tx_nb + 0, // n_srs + get_TBS_UL(mcs,nb_rb)); + + sched_resp->UL_req->header.message_id = NFAPI_UL_CONFIG_REQUEST; + ul_req->number_of_pdus=1; + ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + } extern void eNB_fep_full(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc); @@ -172,22 +303,26 @@ int main(int argc, char **argv) char c; int i,j,aa,u; - + PHY_VARS_eNB *eNB; + PHY_VARS_UE *UE; + RU_t *ru; int aarx,aatx; double channelx,channely; double sigma2, sigma2_dB=10,SNR,SNR2=0,snr0=-2.0,snr1,SNRmeas,rate,saving_bler=0; double input_snr_step=.2,snr_int=30; double blerr; - + int rvidx[8]={0,2,3,1,0,2,3,1}; int **txdata; LTE_DL_FRAME_PARMS *frame_parms; double s_re0[30720],s_im0[30720],r_re0[30720],r_im0[30720]; double s_re1[30720],s_im1[30720],r_re1[30720],r_im1[30720]; + double r_re2[30720],r_im2[30720]; + double r_re3[30720],r_im3[30720]; double *s_re[2]={s_re0,s_re1}; double *s_im[2]={s_im0,s_im1}; - double *r_re[2]={r_re0,r_re1}; - double *r_im[2]={r_im0,r_im1}; + double *r_re[4]={r_re0,r_re1,r_re2,r_re3}; + double *r_im[4]={r_im0,r_im1,r_im2,r_im3}; double forgetting_factor=0.0; //in [0,1] 0 means a new channel every time, 1 means keep the same channel double iqim=0.0; uint8_t extended_prefix_flag=0; @@ -254,8 +389,7 @@ int main(int argc, char **argv) uint8_t N_RB_DL=25,osf=1; //uint8_t cyclic_shift = 0; - uint8_t cooperation_flag = 0; //0 no cooperation, 1 delay diversity, 2 Alamouti - uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2; + uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2,cqi_size=11; uint8_t tdd_config=3,frame_type=FDD; uint8_t N0=30; @@ -282,10 +416,24 @@ int main(int argc, char **argv) opp_enabled=1; // to enable the time meas + sched_resp.DL_req = &DL_req; + sched_resp.UL_req = &UL_req; + sched_resp.HI_DCI0_req = &HI_DCI0_req; + sched_resp.TX_req = &TX_req; + memset((void*)&DL_req,0,sizeof(DL_req)); + memset((void*)&UL_req,0,sizeof(UL_req)); + memset((void*)&HI_DCI0_req,0,sizeof(HI_DCI0_req)); + memset((void*)&TX_req,0,sizeof(TX_req)); + + UL_req.ul_config_request_body.ul_config_pdu_list = ul_config_pdu_list; + TX_req.tx_request_body.tx_pdu_list = tx_pdu_list; + cpu_freq_GHz = (double)get_cpu_freq_GHz(); cpuf = cpu_freq_GHz; printf("Detected cpu_freq %f GHz\n",cpu_freq_GHz); + AssertFatal(load_configmodule(argc,argv) != NULL, + "cannot load configuration module, exiting\n"); logInit(); /* @@ -565,9 +713,12 @@ int main(int argc, char **argv) break; } } + RC.nb_L1_inst = 1; + RC.nb_RU = 1; - lte_param_init(1, - 1, + lte_param_init(&eNB,&UE,&ru, + 1, + 1, n_rx, 1, extended_prefix_flag, @@ -575,10 +726,30 @@ int main(int argc, char **argv) 0, tdd_config, N_RB_DL, + 4, threequarter_fs, osf, 0); + RC.eNB = (PHY_VARS_eNB ***)malloc(sizeof(PHY_VARS_eNB **)); + RC.eNB[0] = (PHY_VARS_eNB **)malloc(sizeof(PHY_VARS_eNB *)); + RC.ru = (RU_t **)malloc(sizeof(RC.ru)); + RC.eNB[0][0] = eNB; + RC.ru[0] = ru; + for (int k=0;kRU_list[0]->nb_rx;k++) eNB->common_vars.rxdataF[k] = eNB->RU_list[0]->common.rxdataF[k]; + + memset((void*)&eNB->UL_INFO,0,sizeof(eNB->UL_INFO)); + + printf("Setting indication lists\n"); + eNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list = eNB->rx_pdu_list; + eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = eNB->crc_pdu_list; + eNB->UL_INFO.sr_ind.sr_indication_body.sr_pdu_list = eNB->sr_pdu_list; + eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = eNB->harq_pdu_list; + eNB->UL_INFO.cqi_ind.cqi_pdu_list = eNB->cqi_pdu_list; + eNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = eNB->cqi_raw_pdu_list; + + printf("lte_param_init done\n"); + // for a call to phy_reset_ue later we need PHY_vars_UE_g allocated and pointing to UE PHY_vars_UE_g = (PHY_VARS_UE***)malloc(sizeof(PHY_VARS_UE**)); PHY_vars_UE_g[0] = (PHY_VARS_UE**) malloc(sizeof(PHY_VARS_UE*)); @@ -587,7 +758,7 @@ int main(int argc, char **argv) if (nb_rb_set == 0) nb_rb = eNB->frame_parms.N_RB_UL; - printf("1 . rxdataF_comp[0] %p\n",eNB->pusch_vars[0]->rxdataF_comp[0][0]); + printf("1 . rxdataF_comp[0] %p\n",eNB->pusch_vars[0]->rxdataF_comp[0]); printf("Setting mcs = %d\n",mcs); printf("n_frames = %d\n", n_frames); @@ -670,7 +841,6 @@ int main(int argc, char **argv) eNB->soundingrs_ul_config_dedicated[UE_id].freqDomainPosition = 0; eNB->soundingrs_ul_config_dedicated[UE_id].cyclicShift = 0; - eNB->cooperation_flag = cooperation_flag; eNB->pusch_config_dedicated[UE_id].betaOffset_ACK_Index = beta_ACK; eNB->pusch_config_dedicated[UE_id].betaOffset_RI_Index = beta_RI; @@ -700,7 +870,7 @@ int main(int argc, char **argv) UE2eNB->max_Doppler = maxDoppler; // NN: N_RB_UL has to be defined in ulsim - eNB->ulsch[0] = new_eNB_ulsch(max_turbo_iterations,N_RB_DL,0); + for (int k=0;kulsch[k] = new_eNB_ulsch(max_turbo_iterations,N_RB_DL,0); UE->ulsch[0] = new_ue_ulsch(N_RB_DL,0); if (parallel_flag == 1) { @@ -761,9 +931,9 @@ int main(int argc, char **argv) proc_rxtx->subframe_tx=pdcch_alloc2ul_subframe(&eNB->frame_parms,subframe); proc_rxtx_ue->frame_tx = proc_rxtx->frame_rx; - proc_rxtx_ue->frame_rx = proc_rxtx->frame_tx; + proc_rxtx_ue->frame_rx = (subframe<4)?(proc_rxtx->frame_tx-1):(proc_rxtx->frame_tx); proc_rxtx_ue->subframe_tx = proc_rxtx->subframe_rx; - proc_rxtx_ue->subframe_rx = proc_rxtx->subframe_tx; + proc_rxtx_ue->subframe_rx = (proc_rxtx->subframe_tx+6)%10; printf("Init UL hopping UE\n"); init_ul_hopping(&UE->frame_parms); @@ -915,7 +1085,6 @@ int main(int argc, char **argv) reset_meas(&UE->ulsch_multiplexing_stats); reset_meas(&eNB->phy_proc_rx); - reset_meas(&eNB->ofdm_demod_stats); reset_meas(&eNB->ulsch_channel_estimation_stats); reset_meas(&eNB->ulsch_freq_offset_estimation_stats); reset_meas(&eNB->rx_dft_stats); @@ -965,19 +1134,38 @@ int main(int argc, char **argv) round=0; while (round < 4) { + proc_rxtx->frame_rx=1; + proc_rxtx->subframe_rx=subframe; + + proc_rxtx->frame_tx=pdcch_alloc2ul_frame(&eNB->frame_parms,1,subframe); + proc_rxtx->subframe_tx=pdcch_alloc2ul_subframe(&eNB->frame_parms,subframe); + + proc_rxtx_ue->frame_tx = proc_rxtx->frame_rx; + proc_rxtx_ue->frame_rx = (subframe<4)?(proc_rxtx->frame_tx-1):(proc_rxtx->frame_tx); + proc_rxtx_ue->subframe_tx = proc_rxtx->subframe_rx; + proc_rxtx_ue->subframe_rx = (proc_rxtx->subframe_tx+6)%10; + eNB->ulsch[0]->harq_processes[harq_pid]->round=round; UE->ulsch[0]->harq_processes[harq_pid]->round=round; - // printf("Trial %d : Round %d (subframe %d, frame %d)\n",trials,round,proc_rxtx_ue->subframe_rx,proc_rxtx_ue->frame_rx); + if (n_frames==1) printf("filling ulsch: Trial %d : Round %d (subframe %d, frame %d)\n",trials,round,proc_rxtx_ue->subframe_tx,proc_rxtx_ue->frame_tx); round_trials[round]++; + UL_req.sfn_sf = (1<<4)+subframe; + if (n_frames==1) printf("filling ulsch: eNB prog frame %d, subframe %d (%d,%d)\n",proc_rxtx->frame_rx,subframe,sched_resp.frame,sched_resp.subframe); - fill_ulsch_dci(eNB,(void*)&UL_alloc_pdu,first_rb,nb_rb,mcs,ndi,cqi_flag); + int modulation_type; + if (mcs < 11) modulation_type = 2; + else if (mcs < 21) modulation_type = 4; + else if (mcs < 29) modulation_type = 6; + + fill_ulsch_dci(eNB,proc_rxtx->frame_rx,subframe,&sched_resp,14,(void*)&UL_alloc_pdu,first_rb,nb_rb,(round==0)?mcs:(28+rvidx[round]),modulation_type,ndi,cqi_flag,beta_CQI,beta_RI,cqi_size); UE->ulsch_Msg3_active[eNB_id] = 0; UE->ul_power_control_dedicated[eNB_id].accumulationEnabled=1; + if (n_frames==1) printf("filling ulsch: ue prog SFN/SF %d/%d\n",proc_rxtx_ue->frame_rx,proc_rxtx_ue->subframe_rx); generate_ue_ulsch_params_from_dci((void *)&UL_alloc_pdu, 14, - proc_rxtx->subframe_tx, + (subframe+6)%10, format0, UE, proc_rxtx_ue, @@ -988,17 +1176,11 @@ int main(int argc, char **argv) 0, srs_flag); - generate_eNB_ulsch_params_from_dci(eNB,proc_rxtx, - (void *)&UL_alloc_pdu, - 14, - format0, - 0, - SI_RNTI, - 0, - P_RNTI, - CBA_RNTI, - srs_flag); - eNB->ulsch[0]->harq_processes[harq_pid]->subframe_scheduling_flag = 1; + sched_resp.subframe=(subframe+6)%10; + sched_resp.frame=(1024+eNB->proc.frame_rx+((subframe<4)?-1:0))&1023; + + schedule_response(&sched_resp); + ///////////////////// if (abstx) { @@ -1020,6 +1202,9 @@ int main(int argc, char **argv) eNB->proc.frame_rx = 1; eNB->proc.subframe_rx = subframe; + ru->proc.frame_rx = 1; + ru->proc.subframe_rx = subframe; + proc_rxtx_ue->frame_tx = proc_rxtx->frame_rx; proc_rxtx_ue->frame_rx = proc_rxtx->frame_tx; proc_rxtx_ue->subframe_tx = proc_rxtx->subframe_rx; @@ -1027,70 +1212,6 @@ int main(int argc, char **argv) phy_procedures_UE_TX(UE,proc_rxtx_ue,0,0,normal_txrx,no_relay); - /* - if (srs_flag) - generate_srs_tx(UE,0,AMP,subframe); - - generate_drs_pusch(UE,proc_rxtx_ue,0, - AMP,subframe, - UE->ulsch[0]->harq_processes[harq_pid]->first_rb, - UE->ulsch[0]->harq_processes[harq_pid]->nb_rb, - 0); - - if ((cqi_flag == 1) && (n_frames == 1) ) { - printf("CQI information (O %d) %d %d\n",UE->ulsch[0]->O, - UE->ulsch[0]->o[0],UE->ulsch[0]->o[1]); - print_CQI(UE->ulsch[0]->o,UE->ulsch[0]->uci_format,UE->frame_parms.N_RB_DL,0); - } - - UE->ulsch[0]->o_ACK[0] = taus()&1; - - start_meas(&UE->ulsch_encoding_stats); - - if (ulsch_encoding(input_buffer, - UE, - harq_pid, - eNB_id, - 2, // transmission mode - control_only_flag, - 1// Nbundled - )==-1) { - printf("ulsim.c Problem with ulsch_encoding\n"); - exit(-1); - } - - stop_meas(&UE->ulsch_encoding_stats); - - start_meas(&UE->ulsch_modulation_stats); - ulsch_modulation(UE->common_vars.txdataF,AMP, - proc_rxtx_ue->frame_tx,subframe,&UE->frame_parms, - UE->ulsch[0]); - stop_meas(&UE->ulsch_modulation_stats); - */ - - - - - /* - for (aa=0; aa<1; aa++) { - if (frame_parms->Ncp == EXTENDED) - PHY_ofdm_mod(&UE->common_vars.txdataF[aa][subframe*nsymb*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES_NO_PREFIX], // input - &txdata[aa][eNB->frame_parms.samples_per_tti*subframe], // output - UE->frame_parms.ofdm_symbol_size, - nsymb, // number of symbols - UE->frame_parms.nb_prefix_samples, // number of prefix samples - CYCLIC_PREFIX); - else - normal_prefix_mod(&UE->common_vars.txdataF[aa][subframe*nsymb*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES_NO_PREFIX], - &txdata[aa][eNB->frame_parms.samples_per_tti*subframe], - nsymb, - frame_parms); - - - apply_7_5_kHz(UE,UE->common_vars.txdata[aa],subframe<<1); - apply_7_5_kHz(UE,UE->common_vars.txdata[aa],1+(subframe<<1)); - -*/ tx_lev = signal_energy(&UE->common_vars.txdata[0][eNB->frame_parms.samples_per_tti*subframe], eNB->frame_parms.samples_per_tti); @@ -1113,11 +1234,11 @@ int main(int argc, char **argv) //AWGN //Set target wideband RX noise level to N0 - sigma2_dB = N0;//10*log10((double)tx_lev) +10*log10(UE->frame_parms.ofdm_symbol_size/(UE->frame_parms.N_RB_DL*12)) - SNR; + sigma2_dB = N0;//-10*log10(UE->frame_parms.ofdm_symbol_size/(UE->frame_parms.N_RB_DL*12));//10*log10((double)tx_lev) +10*log10(UE->frame_parms.ofdm_symbol_size/(UE->frame_parms.N_RB_DL*12)) - SNR; sigma2 = pow(10,sigma2_dB/10); // compute tx_gain to achieve target SNR (per resource element!) - tx_gain = sqrt(pow(10.0,.1*(N0+SNR))*(nb_rb*12/(double)UE->frame_parms.ofdm_symbol_size)/(double)tx_lev); + tx_gain = sqrt(pow(10.0,.1*(N0+SNR))/(double)tx_lev);//*(nb_rb*12/(double)UE->frame_parms.ofdm_symbol_size)/(double)tx_lev); if (n_frames==1) @@ -1128,8 +1249,8 @@ int main(int argc, char **argv) for (i=0; iframe_parms.nb_antennas_rx; aa++) { - ((short*) &eNB->common_vars.rxdata[0][aa][(frame_parms->samples_per_tti<<1) -frame_parms->ofdm_symbol_size])[2*i] = (short) ((sqrt(sigma2/2)*gaussdouble(0.0,1.0))); - ((short*) &eNB->common_vars.rxdata[0][aa][(frame_parms->samples_per_tti<<1) -frame_parms->ofdm_symbol_size])[2*i+1] = (short) ((sqrt(sigma2/2)*gaussdouble(0.0,1.0))); + ((short*) &ru->common.rxdata[aa][(frame_parms->samples_per_tti<<1) -frame_parms->ofdm_symbol_size])[2*i] = (short) ((sqrt(sigma2/2)*gaussdouble(0.0,1.0))); + ((short*) &ru->common.rxdata[aa][(frame_parms->samples_per_tti<<1) -frame_parms->ofdm_symbol_size])[2*i+1] = (short) ((sqrt(sigma2/2)*gaussdouble(0.0,1.0))); } } @@ -1186,37 +1307,37 @@ int main(int argc, char **argv) for (i=0; iframe_parms.samples_per_tti; i++) { for (aa=0; aaframe_parms.nb_antennas_rx; aa++) { - ((short*) &eNB->common_vars.rxdata[0][aa][eNB->frame_parms.samples_per_tti*subframe])[2*i] = (short) ((tx_gain*r_re[aa][i]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); - ((short*) &eNB->common_vars.rxdata[0][aa][eNB->frame_parms.samples_per_tti*subframe])[2*i+1] = (short) ((tx_gain*r_im[aa][i]) + (iqim*tx_gain*r_re[aa][i]) + sqrt( + ((short*) &ru->common.rxdata[aa][eNB->frame_parms.samples_per_tti*subframe])[2*i] = (short) ((tx_gain*r_re[aa][i]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); + ((short*) &ru->common.rxdata[aa][eNB->frame_parms.samples_per_tti*subframe])[2*i+1] = (short) ((tx_gain*r_im[aa][i]) + (iqim*tx_gain*r_re[aa][i]) + sqrt( sigma2/2)*gaussdouble(0.0,1.0)); } } - if (n_frames==1) { + if (n_frames<=10) { printf("rx_level Null symbol %f\n",10*log10((double)signal_energy((int*) - &eNB->common_vars.rxdata[0][0][(eNB->frame_parms.samples_per_tti<<1) -eNB->frame_parms.ofdm_symbol_size],OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES/2))); - printf("rx_level data symbol %f\n",10*log10(signal_energy((int*)&eNB->common_vars.rxdata[0][0][160+(eNB->frame_parms.samples_per_tti*subframe)], + &ru->common.rxdata[0][(eNB->frame_parms.samples_per_tti<<1) -eNB->frame_parms.ofdm_symbol_size],OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES/2))); + printf("rx_level data symbol %f\n",10*log10(signal_energy((int*)&ru->common.rxdata[0][160+(eNB->frame_parms.samples_per_tti*subframe)], OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES/2))); } - SNRmeas = 10*log10(((double)signal_energy((int*)&eNB->common_vars.rxdata[0][0][160+(eNB->frame_parms.samples_per_tti*subframe)], + SNRmeas = 10*log10(((double)signal_energy((int*)&ru->common.rxdata[0][160+(eNB->frame_parms.samples_per_tti*subframe)], OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES/2))/((double)signal_energy((int*) - &eNB->common_vars.rxdata[0][0][(eNB->frame_parms.samples_per_tti<<1) -eNB->frame_parms.ofdm_symbol_size], + &ru->common.rxdata[0][(eNB->frame_parms.samples_per_tti<<1) -eNB->frame_parms.ofdm_symbol_size], OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES/2)) - 1)+10*log10(eNB->frame_parms.N_RB_UL/nb_rb); - if (n_frames==1) { + if (n_frames<=10) { printf("SNRmeas %f\n",SNRmeas); - // write_output("rxsig0UL.m","rxs0", &eNB->common_vars.rxdata[0][0][eNB->frame_parms.samples_per_tti*subframe],eNB->frame_parms.samples_per_tti,1,1); - //write_output("rxsig1UL.m","rxs1", &eNB->common_vars.rxdata[0][0][eNB->frame_parms.samples_per_tti*subframe],eNB->frame_parms.samples_per_tti,1,1); + write_output("rxsig0UL.m","rxs0", &ru->common.rxdata[0][eNB->frame_parms.samples_per_tti*subframe],eNB->frame_parms.samples_per_tti,1,1); + // write_output("rxsig1UL.m","rxs1", &ru->common_vars.rxdata[0][eNB->frame_parms.samples_per_tti*subframe],eNB->frame_parms.samples_per_tti,1,1); } - eNB->fep = (parallel_flag == 1) ? eNB_fep_full_2thread : eNB_fep_full; + ru->feprx = (parallel_flag == 1) ? ru_fep_full_2thread : fep_full; eNB->td = (parallel_flag == 1) ? ulsch_decoding_data_2thread : ulsch_decoding_data; - eNB->do_prach = NULL; - phy_procedures_eNB_common_RX(eNB,proc_rxtx); + + ru->feprx(ru); phy_procedures_eNB_uespec_RX(eNB,proc_rxtx,no_relay); @@ -1252,7 +1373,7 @@ int main(int argc, char **argv) // if (ret <= eNB->ulsch[0]->max_turbo_iterations) { - if (eNB->ulsch[0]->harq_processes[harq_pid]->round == 0) { + if (eNB->ulsch[0]->harq_processes[harq_pid]->status == SCH_IDLE) { // avg_iter += ret; iter_trials++; @@ -1264,7 +1385,7 @@ int main(int argc, char **argv) print_CQI(eNB->ulsch[0]->harq_processes[harq_pid]->o, eNB->ulsch[0]->harq_processes[harq_pid]->uci_format,0,eNB->frame_parms.N_RB_DL); - dump_ulsch(eNB,proc_rxtx,0); + dump_ulsch(eNB,eNB->proc.frame_rx,subframe,0,round); exit(-1); } @@ -1293,18 +1414,17 @@ int main(int argc, char **argv) eNB->ulsch[0]->harq_processes[harq_pid]->c[s][i]^UE->ulsch[0]->harq_processes[harq_pid]->c[s][i]); } - dump_ulsch(eNB,proc_rxtx,0); - exit(-1); + dump_ulsch(eNB,eNB->proc.frame_rx,subframe,0,round); + if (round == 4) exit(-1); } - // printf("round %d errors %d/%d\n",round,errs[round],trials); + if (n_frames==1) printf("round %d errors %d/%d\n",round,errs[round],trials); round++; if (n_frames==1) { printf("ULSCH in error in round %d\n",round); } - } // ulsch error - + } // ulsch error } // round @@ -1324,7 +1444,7 @@ int main(int argc, char **argv) double t_rx = (double)eNB->phy_proc_rx.p_time/cpu_freq_GHz/1000.0; - double t_rx_fft = (double)eNB->ofdm_demod_stats.p_time/cpu_freq_GHz/1000.0; + double t_rx_fft = (double)ru->ofdm_demod_stats.p_time/cpu_freq_GHz/1000.0; double t_rx_demod = (double)eNB->ulsch_demodulation_stats.p_time/cpu_freq_GHz/1000.0; double t_rx_dec = (double)eNB->ulsch_decoding_stats.p_time/cpu_freq_GHz/1000.0; @@ -1449,12 +1569,12 @@ int main(int argc, char **argv) tx_lev_dB, 20*log10(tx_gain), (double)N0, - eNB->measurements[0].n0_power_tot_dB, + eNB->measurements.n0_power_tot_dB, get_hundred_times_delta_IF(UE,eNB_id,harq_pid) , dB_fixed(eNB->pusch_vars[0]->ulsch_power[0]), dB_fixed(eNB->pusch_vars[0]->ulsch_power[1]), - eNB->measurements->n0_power_dB[0], - eNB->measurements->n0_power_dB[1]); + eNB->measurements.n0_power_dB[0], + eNB->measurements.n0_power_dB[1]); effective_rate = ((double)(round_trials[0])/((double)round_trials[0] + round_trials[1] + round_trials[2] + round_trials[3])); @@ -1548,10 +1668,10 @@ int main(int argc, char **argv) printf("Total PHY proc rx :%f us (%d trials)\n",(double)eNB->phy_proc_rx.diff/eNB->phy_proc_rx.trials/cpu_freq_GHz/1000.0,eNB->phy_proc_rx.trials); printf("|__ Statistcs std: %fus max: %fus min: %fus median %fus q1 %fus q3 %fus n_dropped: %d packet \n", std_phy_proc_rx, t_rx_max, t_rx_min, rx_median, rx_q1, rx_q3, n_rx_dropped); - std_phy_proc_rx_fft = sqrt((double)eNB->ofdm_demod_stats.diff_square/pow(cpu_freq_GHz,2)/pow(1000, - 2)/eNB->ofdm_demod_stats.trials - pow((double)eNB->ofdm_demod_stats.diff/eNB->ofdm_demod_stats.trials/cpu_freq_GHz/1000,2)); - printf("OFDM_demod time :%f us (%d trials)\n",(double)eNB->ofdm_demod_stats.diff/eNB->ofdm_demod_stats.trials/cpu_freq_GHz/1000.0, - eNB->ofdm_demod_stats.trials); + std_phy_proc_rx_fft = sqrt((double)ru->ofdm_demod_stats.diff_square/pow(cpu_freq_GHz,2)/pow(1000, + 2)/ru->ofdm_demod_stats.trials - pow((double)ru->ofdm_demod_stats.diff/ru->ofdm_demod_stats.trials/cpu_freq_GHz/1000,2)); + printf("OFDM_demod time :%f us (%d trials)\n",(double)ru->ofdm_demod_stats.diff/ru->ofdm_demod_stats.trials/cpu_freq_GHz/1000.0, + ru->ofdm_demod_stats.trials); printf("|__ Statistcs std: %fus median %fus q1 %fus q3 %fus \n", std_phy_proc_rx_fft, rx_fft_median, rx_fft_q1, rx_fft_q3); std_phy_proc_rx_demod = sqrt((double)eNB->ulsch_demodulation_stats.diff_square/pow(cpu_freq_GHz,2)/pow(1000, 2)/eNB->ulsch_demodulation_stats.trials - pow((double)eNB->ulsch_demodulation_stats.diff/eNB->ulsch_demodulation_stats.trials/cpu_freq_GHz/1000,2)); @@ -1672,7 +1792,7 @@ int main(int argc, char **argv) UE->ulsch_modulation_stats.trials, UE->ulsch_encoding_stats.trials, eNB->phy_proc_rx.trials, - eNB->ofdm_demod_stats.trials, + ru->ofdm_demod_stats.trials, eNB->ulsch_demodulation_stats.trials, eNB->ulsch_decoding_stats.trials ); @@ -1682,7 +1802,7 @@ int main(int argc, char **argv) get_time_meas_us(&UE->ulsch_modulation_stats), get_time_meas_us(&UE->ulsch_encoding_stats), get_time_meas_us(&eNB->phy_proc_rx), - get_time_meas_us(&eNB->ofdm_demod_stats), + get_time_meas_us(&ru->ofdm_demod_stats), get_time_meas_us(&eNB->ulsch_demodulation_stats), get_time_meas_us(&eNB->ulsch_decoding_stats) ); @@ -1733,7 +1853,7 @@ int main(int argc, char **argv) oai_exit=1; - pthread_cond_signal(&eNB->proc.cond_fep); + pthread_cond_signal(&ru->proc.cond_fep); if (abstx) { // ABSTRACTION fprintf(csv_fdUL,"];"); From a1dc99724bdfc7658efd0d41ca3f9d728114f873 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sat, 17 Feb 2018 11:15:53 -0800 Subject: [PATCH 256/284] missing file --- openair1/SIMULATION/LTE_PHY/dummy_functions.c | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 openair1/SIMULATION/LTE_PHY/dummy_functions.c diff --git a/openair1/SIMULATION/LTE_PHY/dummy_functions.c b/openair1/SIMULATION/LTE_PHY/dummy_functions.c new file mode 100644 index 0000000000..dc86e76113 --- /dev/null +++ b/openair1/SIMULATION/LTE_PHY/dummy_functions.c @@ -0,0 +1,84 @@ + +PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP, int CC_id, + frame_t frameP, uint8_t new_Msg3, + sub_frame_t subframe){ return(NULL);} + +void ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP, + sub_frame_t subframe, uint8_t eNB_index, + uint8_t * ulsch_buffer, uint16_t buflen, + uint8_t * access_mode){} + +void Msg1_transmitted(module_id_t module_idP, uint8_t CC_id, + frame_t frameP, uint8_t eNB_id){} + +void Msg3_transmitted(module_id_t module_idP, uint8_t CC_id, + frame_t frameP, uint8_t eNB_id){} + +uint32_t ue_get_SR(module_id_t module_idP, int CC_id, frame_t frameP, + uint8_t eNB_id, rnti_t rnti, sub_frame_t subframe){ return(0);} + +void rrc_out_of_sync_ind(module_id_t Mod_idP, frame_t frameP, uint16_t eNB_index) +{} + +UE_L2_STATE_t ue_scheduler(const module_id_t module_idP, + const frame_t rxFrameP, + const sub_frame_t rxSubframe, + const frame_t txFrameP, + const sub_frame_t txSubframe, + const lte_subframe_t direction, + const uint8_t eNB_index, const int CC_id){ return(0);} + +void ue_decode_p(module_id_t module_idP, int CC_id, frame_t frame, + uint8_t CH_index, void *pdu, uint16_t len){} + +void ue_decode_si(module_id_t module_idP, int CC_id, frame_t frame, + uint8_t CH_index, void *pdu, uint16_t len){} + +void ue_send_sdu(module_id_t module_idP, uint8_t CC_id, frame_t frame, + sub_frame_t subframe, uint8_t * sdu, uint16_t sdu_len, + uint8_t CH_index){} + +uint16_t +ue_process_rar(const module_id_t module_idP, + const int CC_id, + const frame_t frameP, + const rnti_t ra_rnti, + uint8_t * const dlsch_buffer, + rnti_t * const t_crnti, + const uint8_t preamble_index, + uint8_t * selected_rar_buffer){ return(0);} + +void ue_send_mch_sdu(module_id_t module_idP, uint8_t CC_id, frame_t frameP, + uint8_t * sdu, uint16_t sdu_len, uint8_t eNB_index, + uint8_t sync_area){} + +int ue_query_mch(uint8_t Mod_id, uint8_t CC_id, uint32_t frame, + sub_frame_t subframe, uint8_t eNB_index, + uint8_t * sync_area, uint8_t * mcch_active){ return(0);} + +void dl_phy_sync_success(module_id_t module_idP, + frame_t frameP, + unsigned char eNB_index, uint8_t first_sync){} + +uint32_t from_earfcn(int eutra_bandP, uint32_t dl_earfcn) { return(0);} + +int32_t get_uldl_offset(int eutra_bandP) { return(0);} + +IF_Module_t *IF_Module_init(int Mod_id) { return(NULL);} + +int8_t get_Po_NOMINAL_PUSCH(module_id_t module_idP, uint8_t CC_id) { return(0);} + +int8_t get_deltaP_rampup(module_id_t module_idP, uint8_t CC_id) { return(0);} + +void thread_top_init(char *thread_name, + int affinity, + uint64_t runtime, + uint64_t deadline, + uint64_t period) {} + +int oai_nfapi_hi_dci0_req(nfapi_hi_dci0_request_t *hi_dci0_req) { return(0);} +int oai_nfapi_tx_req(nfapi_tx_request_t *tx_req) { return(0); } + +int oai_nfapi_dl_config_req(nfapi_dl_config_request_t *dl_config_req) { return(0); } + +int oai_nfapi_ul_config_req(nfapi_ul_config_request_t *ul_config_req) { return(0); } From b42d83beadfdd07774754d437602417725c70ea7 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sun, 18 Feb 2018 12:19:31 +0100 Subject: [PATCH 257/284] memory allocation bugs for 2x2 transmission in dlsim --- openair1/PHY/INIT/defs.h | 3 ++- openair1/PHY/INIT/lte_param_init.c | 9 +++++---- openair1/SIMULATION/LTE_PHY/dlsim.c | 6 ++++-- openair1/SIMULATION/LTE_PHY/ulsim.c | 1 + 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/openair1/PHY/INIT/defs.h b/openair1/PHY/INIT/defs.h index bb7fe72114..2c92503133 100644 --- a/openair1/PHY/INIT/defs.h +++ b/openair1/PHY/INIT/defs.h @@ -335,7 +335,8 @@ void lte_param_init(PHY_VARS_eNB **eNBp, RU_t **rup, unsigned char N_tx_port_eNB, unsigned char N_tx_phy, - unsigned char N_rx, + unsigned char N_rx_ru, + unsigned char N_rx_ue, unsigned char transmission_mode, uint8_t extended_prefix_flag, frame_t frame_type, diff --git a/openair1/PHY/INIT/lte_param_init.c b/openair1/PHY/INIT/lte_param_init.c index d9b7b12249..c09652db93 100644 --- a/openair1/PHY/INIT/lte_param_init.c +++ b/openair1/PHY/INIT/lte_param_init.c @@ -39,7 +39,8 @@ void lte_param_init(PHY_VARS_eNB **eNBp, RU_t **rup, unsigned char N_tx_port_eNB, unsigned char N_tx_phy, - unsigned char N_rx, + unsigned char N_rx_ru, + unsigned char N_rx_ue, unsigned char transmission_mode, uint8_t extended_prefix_flag, frame_t frame_type, @@ -90,7 +91,7 @@ void lte_param_init(PHY_VARS_eNB **eNBp, frame_parms->Nid_cell = Nid_cell; frame_parms->nushift = Nid_cell%6; frame_parms->nb_antennas_tx = N_tx_phy; - frame_parms->nb_antennas_rx = N_rx; + frame_parms->nb_antennas_rx = N_rx_ru; frame_parms->nb_antenna_ports_eNB = N_tx_port_eNB; frame_parms->phich_config_common.phich_resource = oneSixth; frame_parms->phich_config_common.phich_duration = normal; @@ -109,11 +110,11 @@ void lte_param_init(PHY_VARS_eNB **eNBp, UE->is_secondary_ue = 0; UE->frame_parms = *frame_parms; - UE->frame_parms.nb_antennas_rx=1; + UE->frame_parms.nb_antennas_rx=N_rx_ue; // eNB->frame_parms = *frame_parms; ru->frame_parms = *frame_parms; ru->nb_tx = N_tx_phy; - ru->nb_rx = N_rx; + ru->nb_rx = N_rx_ru; ru->if_south = LOCAL_RF; eNB->configured=1; diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 57fa787142..2de1698450 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -242,7 +242,7 @@ void DL_channel(RU_t *ru,PHY_VARS_UE *UE,uint subframe,int awgn_flag,double SNR, sigma2 = pow(10,sigma2_dB/10); for (i=0; i<2*UE->frame_parms.samples_per_tti; i++) { - for (aa=0; aaframe_parms.nb_antennas_rx; aa++) { + for (aa=0; aaframe_parms.nb_antennas_rx; aa++) { //printf("s_re[0][%d]=> %f , r_re[0][%d]=> %f\n",i,s_re[aa][i],i,r_re[aa][i]); ((short*) UE->common_vars.rxdata[aa])[(2*subframe*UE->frame_parms.samples_per_tti)+2*i] = (short) (r_re[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); @@ -1099,7 +1099,8 @@ int main(int argc, char **argv) lte_param_init(&eNB,&UE,&ru, n_tx_port, n_tx_phy, - n_rx, + 1, + n_rx, transmission_mode, extended_prefix_flag, frame_type, @@ -1304,6 +1305,7 @@ int main(int argc, char **argv) UE->pdcch_vars[UE->current_thread_id[subframe]][0]->crnti = n_rnti; + printf("Allocating %dx%d eNB->UE channel descriptor\n",eNB->frame_parms.nb_antennas_tx,UE->frame_parms.nb_antennas_rx); eNB2UE[0] = new_channel_desc_scm(eNB->frame_parms.nb_antennas_tx, UE->frame_parms.nb_antennas_rx, channel_model, diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 4e31016b6b..8381553bb7 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -720,6 +720,7 @@ int main(int argc, char **argv) 1, 1, n_rx, + 1, 1, extended_prefix_flag, frame_type, From 1c46dd7c694657864c14080c686907755520d999 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sun, 18 Feb 2018 17:31:40 +0100 Subject: [PATCH 258/284] updates for oaisim --- cmake_targets/CMakeLists.txt | 1 - targets/SIMU/USER/oaisim.c | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index dc445a18bc..89b96bf922 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1300,7 +1300,6 @@ set(L2_SRC ) set(L2_SRC_UE - ${OPENAIR2_DIR}/LAYER2/openair2_proc.c ${PDCP_DIR}/pdcp.c ${PDCP_DIR}/pdcp_fifo.c ${PDCP_DIR}/pdcp_sequence_manager.c diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index 3a282e1d44..b23755c3c1 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -818,13 +818,14 @@ l2l1_task (void *args_p) } */ #ifdef OPENAIR2 - +/* if (eNB_l2_stats) { len = dump_eNB_l2_stats (stats_buffer, 0); rewind (eNB_l2_stats); fwrite (stats_buffer, 1, len, eNB_l2_stats); fflush(eNB_l2_stats); } +*/ #endif #endif From 62787a8893ecfd21748c8fcad93459035819463a Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 19 Feb 2018 14:09:09 +0100 Subject: [PATCH 259/284] fix CentOS compilation The following was not working properly: ./build_oai -I -w USRP After this commit it works. And so does: ./build_oai --eNB -w USRP --- cmake_targets/tools/build_helper | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 1ea97c030f..706cd05fe9 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -249,14 +249,14 @@ install_usrp_uhd_driver_from_source(){ cd /tmp echo "Downloading UHD driver" rm -rf /tmp/uhd - git clone git://github.com/EttusResearch/uhd.git + git clone https://github.com/EttusResearch/uhd.git cd uhd git checkout tags/release_003_010_001_001 mkdir -p host/build cd host/build $CMAKE ../ echo "Compiling UHD" - make + make -j`nproc` make test $SUDO make install $SUDO ldconfig @@ -277,10 +277,11 @@ check_install_usrp_uhd_driver(){ $SUDO apt-get -y --allow-unauthenticated install libuhd-dev libuhd003 uhd-host elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then $SUDO $INSTALLER -y install python boost libusb-devel libusbx-devel boost-devel python-mako python-docutils cmake + $SUDO pip install requests if [[ "$OS_DISTRO" == "rhel" ]] || [[ "$OS_DISTRO" == "centos" ]]; then # until EPEL repo hasn't bumped UHD driver to >=3.10 in EPEL, build driver from source $SUDO $INSTALLER -y remove uhd uhd-devel uhd-firmware - install_ursp_uhd_driver_from_source + install_usrp_uhd_driver_from_source else $SUDO $INSTALLER -y install uhd uhd-devel uhd-firmware fi @@ -644,7 +645,8 @@ check_install_oai_software() { lapack \ lapack-devel \ blas \ - blas-devel + blas-devel \ + libyaml-devel fi install_asn1c_from_source From 10e91d4e2f7821ecbb3069aa9eef7c237ade15e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Iardella?= Date: Fri, 16 Feb 2018 16:24:40 +0100 Subject: [PATCH 260/284] Move the accounting phase of the DL pre-processor in a separate procedure --- openair2/LAYER2/MAC/pre_processor.c | 1202 ++++++++++++++------------- openair2/LAYER2/MAC/proto.h | 5 - 2 files changed, 603 insertions(+), 604 deletions(-) diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 759bc591dd..148ea344e5 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -593,588 +593,591 @@ void sort_UEs(module_id_t Mod_idP, slice_id_t slice_id, int frameP, sub_frame_t #endif } +void dlsch_scheduler_pre_processor_accounting(module_id_t Mod_id, + slice_id_t slice_id, + frame_t frameP, + sub_frame_t subframeP, + int N_RBG[MAX_NUM_CCs], + int min_rb_unit[MAX_NUM_CCs], + uint8_t rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], + uint8_t MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX], + uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX]) { + int UE_id, CC_id; + int ii, r1; + + rnti_t rnti; + uint8_t harq_pid, round, transmission_mode; + uint8_t total_rbs_used[MAX_NUM_CCs]; + uint8_t total_ue_count[MAX_NUM_CCs]; + uint16_t average_rbs_per_user[MAX_NUM_CCs]; + uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + uint16_t nb_rbs_required_remaining_1[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + + int N_RB_DL; + UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list; + UE_sched_ctrl *ue_sched_ctl; + COMMON_channels_t *cc; + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + total_ue_count[CC_id] = 0; + total_rbs_used[CC_id] = 0; + average_rbs_per_user[CC_id] = 0; + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; ++UE_id) { + nb_rbs_required_remaining[CC_id][UE_id] = 0; + } + } + + // loop over all active UEs + for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + rnti = UE_RNTI(Mod_id, UE_id); + + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) + continue; + if (!ue_slice_membership(UE_id, slice_id)) + continue; + + for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { + CC_id = UE_list->ordered_CCids[ii][UE_id]; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + cc = &RC.mac[Mod_id]->common_channels[CC_id]; + // TODO Can we use subframe2harqpid() here? + if (cc->tdd_Config) + harq_pid = ((frameP * 10) + subframeP) % 10; + else + harq_pid = ((frameP * 10) + subframeP) & 7; + round = ue_sched_ctl->round[CC_id][harq_pid]; + + average_rbs_per_user[CC_id] = 0; + + if (round != 8) { + nb_rbs_required[CC_id][UE_id] = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + total_rbs_used[CC_id] += nb_rbs_required[CC_id][UE_id]; + } + + //nb_rbs_required_remaining[UE_id] = nb_rbs_required[UE_id]; + if (nb_rbs_required[CC_id][UE_id] > 0) { + total_ue_count[CC_id] = total_ue_count[CC_id] + 1; + } + } + } + + // loop over all active UEs and calculate avg rb per user based on total active UEs + for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + rnti = UE_RNTI(Mod_id, UE_id); + + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) + continue; + if (!ue_slice_membership(UE_id, slice_id)) + continue; + + for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { + CC_id = UE_list->ordered_CCids[ii][UE_id]; + + // hypothetical assignment + /* + * If schedule is enabled and if the priority of the UEs is modified + * The average rbs per logical channel per user will depend on the level of + * priority. Concerning the hypothetical assignement, we should assign more + * rbs to prioritized users. Maybe, we can do a mapping between the + * average rbs per user and the level of priority or multiply the average rbs + * per user by a coefficient which represents the degree of priority. + */ + + N_RB_DL = to_prb(RC.mac[Mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth) - total_rbs_used[CC_id]; + + // recalculate based on the what is left after retransmission + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + ue_sched_ctl->max_rbs_allowed_slice[CC_id][slice_id] = + flexran_nb_rbs_allowed_slice(slice_percentage[slice_id], N_RB_DL); + + if (total_ue_count[CC_id] == 0) { + average_rbs_per_user[CC_id] = 0; + } else if ((min_rb_unit[CC_id] * total_ue_count[CC_id]) <= + (ue_sched_ctl->max_rbs_allowed_slice[CC_id][slice_id])) { + average_rbs_per_user[CC_id] = + (uint16_t) floor(ue_sched_ctl->max_rbs_allowed_slice[CC_id][slice_id] / total_ue_count[CC_id]); + } else { + // consider the total number of use that can be scheduled UE + average_rbs_per_user[CC_id] = min_rb_unit[CC_id]; + } + } + } + + // note: nb_rbs_required is assigned according to total_buffer_dl + // extend nb_rbs_required to capture per LCID RB required + for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + rnti = UE_RNTI(Mod_id, UE_id); + + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) + continue; + if (!ue_slice_membership(UE_id, slice_id)) + continue; + + for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { + CC_id = UE_list->ordered_CCids[ii][UE_id]; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + cc = &RC.mac[Mod_id]->common_channels[CC_id]; + // TODO Can we use subframe2harqpid() here? + if (cc->tdd_Config) + harq_pid = ((frameP * 10) + subframeP) % 10; + else + harq_pid = ((frameP * 10) + subframeP) & 7; + round = ue_sched_ctl->round[CC_id][harq_pid]; + + // control channel or retransmission + /* TODO: do we have to check for retransmission? */ + if (mac_eNB_get_rrc_status(Mod_id, rnti) < RRC_RECONFIGURED || round > 0) { + nb_rbs_required_remaining_1[CC_id][UE_id] = + nb_rbs_required[CC_id][UE_id]; + } else { + nb_rbs_required_remaining_1[CC_id][UE_id] = + cmin(average_rbs_per_user[CC_id], nb_rbs_required[CC_id][UE_id]); + } + } + } + + //Allocation to UEs is done in 2 rounds, + // 1st stage: average number of RBs allocated to each UE + // 2nd stage: remaining RBs are allocated to high priority UEs + for (r1 = 0; r1 < 2; r1++) { + + for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { + CC_id = UE_list->ordered_CCids[ii][UE_id]; + + if (r1 == 0) { + nb_rbs_required_remaining[CC_id][UE_id] = + nb_rbs_required_remaining_1[CC_id][UE_id]; + } else { // rb required based only on the buffer - rb allocated in the 1st round + extra reaming rb form the 1st round + nb_rbs_required_remaining[CC_id][UE_id] = + nb_rbs_required[CC_id][UE_id] - + nb_rbs_required_remaining_1[CC_id][UE_id] + + nb_rbs_required_remaining[CC_id][UE_id]; + if (nb_rbs_required_remaining[CC_id][UE_id] < 0) + abort(); + } + + if (nb_rbs_required[CC_id][UE_id] > 0) + LOG_D(MAC, + "round %d : nb_rbs_required_remaining[%d][%d]= %d (remaining_1 %d, required %d, pre_nb_available_rbs %d, N_RBG %d, rb_unit %d)\n", + r1, CC_id, UE_id, + nb_rbs_required_remaining[CC_id][UE_id], + nb_rbs_required_remaining_1[CC_id][UE_id], + nb_rbs_required[CC_id][UE_id], + UE_list->UE_sched_ctrl[UE_id].pre_nb_available_rbs[CC_id], + N_RBG[CC_id], + min_rb_unit[CC_id]); + + } + } + + for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + + for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { + + CC_id = UE_list->ordered_CCids[ii][UE_id]; + // if there are UEs with traffic + if (total_ue_count[CC_id] > 0) { + // ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + // round = ue_sched_ctl->round[CC_id][harq_pid]; + + rnti = UE_RNTI(Mod_id, UE_id); + + // LOG_D(MAC,"UE %d rnti 0x\n", UE_id, rnti ); + if (rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) + continue; + if (!ue_slice_membership(UE_id, slice_id)) + continue; + + transmission_mode = get_tmode(Mod_id, CC_id, UE_id); + // mac_xface->get_ue_active_harq_pid(Mod_id,CC_id,rnti,frameP,subframeP,&harq_pid,&round,0); + // rrc_status = mac_eNB_get_rrc_status(Mod_id,rnti); + /* 1st allocate for the retx */ + + // retransmission in data channels + // control channel in the 1st transmission + // data channel for all TM + LOG_T(MAC, + "calling dlsch_scheduler_pre_processor_allocate .. \n "); + dlsch_scheduler_pre_processor_allocate(Mod_id, UE_id, + CC_id, + N_RBG[CC_id], + transmission_mode, + min_rb_unit + [CC_id], + to_prb(RC.mac + [Mod_id]->common_channels + [CC_id].mib->message.dl_Bandwidth), + nb_rbs_required, + nb_rbs_required_remaining, + rballoc_sub, + MIMO_mode_indicator); + +#ifdef TM5 + // data chanel TM5: to be revisited + if ((round == 0) && + (transmission_mode == 5) && + (ue_sched_ctl->dl_pow_off[CC_id] != 1)) { + + for (j = 0; j < N_RBG[CC_id]; j += 2) { + + if ((((j == (N_RBG[CC_id] - 1)) + && (rballoc_sub[CC_id][j] == 0) + && (ue_sched_ctl-> + rballoc_sub_UE[CC_id][j] == 0)) + || ((j < (N_RBG[CC_id] - 1)) + && (rballoc_sub[CC_id][j + 1] == 0) + && + (ue_sched_ctl->rballoc_sub_UE + [CC_id][j + 1] == 0))) + && (nb_rbs_required_remaining[CC_id][UE_id] + > 0)) { + + for (ii = UE_list->next[UE_id + 1]; ii >= 0; + ii = UE_list->next[ii]) { + + UE_id2 = ii; + rnti2 = UE_RNTI(Mod_id, UE_id2); + ue_sched_ctl2 = + &UE_list->UE_sched_ctrl[UE_id2]; + round2 = ue_sched_ctl2->round[CC_id]; + if (rnti2 == NOT_A_RNTI) + continue; + if (UE_list-> + UE_sched_ctrl + [UE_id2].ul_out_of_sync == 1) + continue; + + eNB_UE_stats2 = + UE_list-> + eNB_UE_stats[CC_id][UE_id2]; + //mac_xface->get_ue_active_harq_pid(Mod_id,CC_id,rnti2,frameP,subframeP,&harq_pid2,&round2,0); + + if ((mac_eNB_get_rrc_status + (Mod_id, + rnti2) >= RRC_RECONFIGURED) + && (round2 == 0) + && + (get_tmode(Mod_id, CC_id, UE_id2) + == 5) + && (ue_sched_ctl-> + dl_pow_off[CC_id] != 1)) { + + if ((((j == (N_RBG[CC_id] - 1)) + && + (ue_sched_ctl->rballoc_sub_UE + [CC_id][j] == 0)) + || ((j < (N_RBG[CC_id] - 1)) + && + (ue_sched_ctl-> + rballoc_sub_UE[CC_id][j + + 1] + == 0))) + && + (nb_rbs_required_remaining + [CC_id] + [UE_id2] > 0)) { + + if ((((eNB_UE_stats2-> + DL_pmi_single ^ + eNB_UE_stats1-> + DL_pmi_single) + << (14 - j)) & 0xc000) == 0x4000) { //MU-MIMO only for 25 RBs configuration + + rballoc_sub[CC_id][j] = 1; + ue_sched_ctl-> + rballoc_sub_UE[CC_id] + [j] = 1; + ue_sched_ctl2-> + rballoc_sub_UE[CC_id] + [j] = 1; + MIMO_mode_indicator[CC_id] + [j] = 0; + + if (j < N_RBG[CC_id] - 1) { + rballoc_sub[CC_id][j + + 1] = + 1; + ue_sched_ctl-> + rballoc_sub_UE + [CC_id][j + 1] = 1; + ue_sched_ctl2->rballoc_sub_UE + [CC_id][j + 1] = 1; + MIMO_mode_indicator + [CC_id][j + 1] + = 0; + } + + ue_sched_ctl-> + dl_pow_off[CC_id] + = 0; + ue_sched_ctl2-> + dl_pow_off[CC_id] + = 0; + + + if ((j == N_RBG[CC_id] - 1) + && ((N_RB_DL == 25) + || (N_RB_DL == + 50))) { + + nb_rbs_required_remaining + [CC_id][UE_id] = + nb_rbs_required_remaining + [CC_id][UE_id] - + min_rb_unit[CC_id] + + 1; + ue_sched_ctl->pre_nb_available_rbs + [CC_id] = + ue_sched_ctl->pre_nb_available_rbs + [CC_id] + + min_rb_unit[CC_id] + - 1; + nb_rbs_required_remaining + [CC_id][UE_id2] = + nb_rbs_required_remaining + [CC_id][UE_id2] - + min_rb_unit[CC_id] + + 1; + ue_sched_ctl2->pre_nb_available_rbs + [CC_id] = + ue_sched_ctl2->pre_nb_available_rbs + [CC_id] + + min_rb_unit[CC_id] + - 1; + } else { + + nb_rbs_required_remaining + [CC_id][UE_id] = + nb_rbs_required_remaining + [CC_id][UE_id] - 4; + ue_sched_ctl->pre_nb_available_rbs + [CC_id] = + ue_sched_ctl->pre_nb_available_rbs + [CC_id] + 4; + nb_rbs_required_remaining + [CC_id][UE_id2] = + nb_rbs_required_remaining + [CC_id][UE_id2] - + 4; + ue_sched_ctl2->pre_nb_available_rbs + [CC_id] = + ue_sched_ctl2->pre_nb_available_rbs + [CC_id] + 4; + } + + break; + } + } + } + } + } + } + } +#endif + } // total_ue_count + } // CC + } // UE + } // end of for for r1 and r2 +} // This function assigns pre-available RBS to each UE in specified sub-bands before scheduling is done void dlsch_scheduler_pre_processor(module_id_t Mod_id, - slice_id_t slice_id, - frame_t frameP, - sub_frame_t subframeP, - int N_RBG[MAX_NUM_CCs], int *mbsfn_flag) -{ + slice_id_t slice_id, + frame_t frameP, + sub_frame_t subframeP, + int N_RBG[MAX_NUM_CCs], + int *mbsfn_flag) { - unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], harq_pid = - 0, round = 0, total_ue_count[MAX_NUM_CCs], total_rbs_used[MAX_NUM_CCs]; - unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]; - int UE_id, i; - uint16_t ii, j; - uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - uint16_t nb_rbs_required_remaining_1[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - uint16_t average_rbs_per_user[MAX_NUM_CCs] = { 0 }; - rnti_t rnti; - int min_rb_unit[MAX_NUM_CCs]; - uint16_t r1 = 0; - uint8_t CC_id; - UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list; + int UE_id; + uint8_t CC_id; + uint16_t i, j; - int N_RB_DL; - int transmission_mode = 0; - UE_sched_ctrl *ue_sched_ctl; - // int rrc_status = RRC_IDLE; - COMMON_channels_t *cc; + uint8_t rballoc_sub[MAX_NUM_CCs][N_RBG_MAX]; + uint8_t MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]; // If TM5 is revisited, we can move this inside accounting + + int min_rb_unit[MAX_NUM_CCs]; + uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + + UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list; + UE_sched_ctrl *ue_sched_ctl; +// int rrc_status = RRC_IDLE; #ifdef TM5 - int harq_pid1 = 0; - int round1 = 0, round2 = 0; - int UE_id2; - uint16_t i1, i2, i3; - rnti_t rnti1, rnti2; - LTE_eNB_UE_stats *eNB_UE_stats1 = NULL; - LTE_eNB_UE_stats *eNB_UE_stats2 = NULL; - UE_sched_ctrl *ue_sched_ctl1, *ue_sched_ctl2; + int harq_pid1 = 0; + int round1 = 0, round2 = 0; + int UE_id2; + uint16_t i1, i2, i3; + rnti_t rnti1, rnti2; + LTE_eNB_UE_stats *eNB_UE_stats1 = NULL; + LTE_eNB_UE_stats *eNB_UE_stats2 = NULL; + UE_sched_ctrl *ue_sched_ctl1, *ue_sched_ctl2; #endif - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - if (mbsfn_flag[CC_id] > 0) // If this CC is allocated for MBSFN skip it here - continue; + if (mbsfn_flag[CC_id] > 0) // If this CC is allocated for MBSFN skip it here + continue; + min_rb_unit[CC_id] = get_min_rb_unit(Mod_id, CC_id); + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; ++UE_id) { + if (UE_list->active[UE_id] != TRUE) + continue; - min_rb_unit[CC_id] = get_min_rb_unit(Mod_id, CC_id); + if (!ue_slice_membership(UE_id, slice_id)) + continue; - for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_list->active[i] != TRUE) - continue; + // Initialize scheduling information for all active UEs + dlsch_scheduler_pre_processor_reset(Mod_id, + UE_id, + CC_id, + frameP, + subframeP, + N_RBG[CC_id], + nb_rbs_required, + rballoc_sub, + MIMO_mode_indicator); - if (!ue_slice_membership(i, slice_id)) - continue; - - UE_id = i; - // Initialize scheduling information for all active UEs - - - - dlsch_scheduler_pre_processor_reset(Mod_id, - UE_id, - CC_id, - frameP, - subframeP, - N_RBG[CC_id], - nb_rbs_required, - nb_rbs_required_remaining, - total_ue_count, - total_rbs_used, - rballoc_sub, - MIMO_mode_indicator); - - } } + } + // Store the DLSCH buffer for each logical channel + store_dlsch_buffer(Mod_id, slice_id, frameP, subframeP); - // Store the DLSCH buffer for each logical channel - store_dlsch_buffer(Mod_id, slice_id,frameP, subframeP); + // Calculate the number of RBs required by each UE on the basis of logical channel's buffer + assign_rbs_required(Mod_id, slice_id, frameP, subframeP, nb_rbs_required, min_rb_unit); + // Sorts the user on the basis of dlsch logical channel buffer and CQI + sort_UEs(Mod_id, slice_id, frameP, subframeP); + // This function does the main allocation of the number of RBs + dlsch_scheduler_pre_processor_accounting(Mod_id, + slice_id, + frameP, + subframeP, + N_RBG, + min_rb_unit, + rballoc_sub, + MIMO_mode_indicator, + nb_rbs_required); - // Calculate the number of RBs required by each UE on the basis of logical channel's buffer - assign_rbs_required(Mod_id, slice_id, frameP, subframeP, nb_rbs_required, - min_rb_unit); - - - - // Sorts the user on the basis of dlsch logical channel buffer and CQI - sort_UEs(Mod_id, slice_id, frameP, subframeP); - - - // loop over all active UEs - for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { - rnti = UE_RNTI(Mod_id, i); - - if (rnti == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - UE_id = i; - if (!ue_slice_membership(UE_id, slice_id)) - continue; - - for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { - CC_id = UE_list->ordered_CCids[ii][UE_id]; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - cc = &RC.mac[Mod_id]->common_channels[ii]; - if (cc->tdd_Config) - harq_pid = ((frameP * 10) + subframeP) % 10; - else - harq_pid = ((frameP * 10) + subframeP) & 7; - round = ue_sched_ctl->round[CC_id][harq_pid]; - - average_rbs_per_user[CC_id] = 0; - - - if (round != 8) { - nb_rbs_required[CC_id][UE_id] = - UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - total_rbs_used[CC_id]+=nb_rbs_required[CC_id][UE_id]; - } - - //nb_rbs_required_remaining[UE_id] = nb_rbs_required[UE_id]; - if (nb_rbs_required[CC_id][UE_id] > 0) { - total_ue_count[CC_id] = total_ue_count[CC_id] + 1; - } - - } - } - - // loop over all active UEs and calculate avg rb per user based on total active UEs - for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { - rnti = UE_RNTI(Mod_id, i); - - if (rnti == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - UE_id = i; - if (!ue_slice_membership(UE_id, slice_id)) - continue; - - for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { - CC_id = UE_list->ordered_CCids[ii][UE_id]; - - // hypothetical assignment - /* - * If schedule is enabled and if the priority of the UEs is modified - * The average rbs per logical channel per user will depend on the level of - * priority. Concerning the hypothetical assignement, we should assign more - * rbs to prioritized users. Maybe, we can do a mapping between the - * average rbs per user and the level of priority or multiply the average rbs - * per user by a coefficient which represents the degree of priority. - */ - - - N_RB_DL = - to_prb(RC.mac[Mod_id]->common_channels[CC_id].mib-> - message.dl_Bandwidth) - total_rbs_used[CC_id]; - - //recalcualte based on the what is left after retransmission - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - ue_sched_ctl->max_rbs_allowed_slice[CC_id][slice_id]= flexran_nb_rbs_allowed_slice(slice_percentage[slice_id],N_RB_DL); - - if (total_ue_count[CC_id] == 0) { - average_rbs_per_user[CC_id] = 0; - } else if ((min_rb_unit[CC_id] * total_ue_count[CC_id]) <= (ue_sched_ctl->max_rbs_allowed_slice[CC_id][slice_id])) { - average_rbs_per_user[CC_id] = - (uint16_t) floor(ue_sched_ctl->max_rbs_allowed_slice[CC_id][slice_id] / total_ue_count[CC_id]); - } else { - average_rbs_per_user[CC_id] = min_rb_unit[CC_id]; // consider the total number of use that can be scheduled UE - } - } - } - - // note: nb_rbs_required is assigned according to total_buffer_dl - // extend nb_rbs_required to capture per LCID RB required - for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { - rnti = UE_RNTI(Mod_id, i); - - if (rnti == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) - continue; - if (!ue_slice_membership(i, slice_id)) - continue; - - for (ii = 0; ii < UE_num_active_CC(UE_list, i); ii++) { - CC_id = UE_list->ordered_CCids[ii][i]; - ue_sched_ctl = &UE_list->UE_sched_ctrl[i]; - round = ue_sched_ctl->round[CC_id][harq_pid]; - - // control channel or retransmission - /* TODO: do we have to check for retransmission? */ - if (mac_eNB_get_rrc_status(Mod_id, rnti) < RRC_RECONFIGURED - || round > 0) { - nb_rbs_required_remaining_1[CC_id][i] = - nb_rbs_required[CC_id][i]; - } else { - nb_rbs_required_remaining_1[CC_id][i] = - cmin(average_rbs_per_user[CC_id], - nb_rbs_required[CC_id][i]); - - } - } - } - - //Allocation to UEs is done in 2 rounds, - // 1st stage: average number of RBs allocated to each UE - // 2nd stage: remaining RBs are allocated to high priority UEs - for (r1 = 0; r1 < 2; r1++) { - - for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { - for (ii = 0; ii < UE_num_active_CC(UE_list, i); ii++) { - CC_id = UE_list->ordered_CCids[ii][i]; - - if (r1 == 0) { - nb_rbs_required_remaining[CC_id][i] = - nb_rbs_required_remaining_1[CC_id][i]; - } else { // rb required based only on the buffer - rb allloctaed in the 1st round + extra reaming rb form the 1st round - nb_rbs_required_remaining[CC_id][i] = - nb_rbs_required[CC_id][i] - - nb_rbs_required_remaining_1[CC_id][i] + - nb_rbs_required_remaining[CC_id][i]; - if (nb_rbs_required_remaining[CC_id][i] < 0) - abort(); - } - - if (nb_rbs_required[CC_id][i] > 0) - LOG_D(MAC, - "round %d : nb_rbs_required_remaining[%d][%d]= %d (remaining_1 %d, required %d, pre_nb_available_rbs %d, N_RBG %d, rb_unit %d)\n", - r1, CC_id, i, - nb_rbs_required_remaining[CC_id][i], - nb_rbs_required_remaining_1[CC_id][i], - nb_rbs_required[CC_id][i], - UE_list->UE_sched_ctrl[i]. - pre_nb_available_rbs[CC_id], N_RBG[CC_id], - min_rb_unit[CC_id]); - - } - } - - - for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { - UE_id = i; - - for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { - - // if there are UEs with traffic - if (total_ue_count [CC_id] > 0) { - CC_id = UE_list->ordered_CCids[ii][UE_id]; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - round = ue_sched_ctl->round[CC_id][harq_pid]; - - rnti = UE_RNTI(Mod_id, UE_id); - - // LOG_D(MAC,"UE %d rnti 0x\n", UE_id, rnti ); - if (rnti == NOT_A_RNTI) - continue; - if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) - continue; - if (!ue_slice_membership(i, slice_id)) - continue; - - transmission_mode = get_tmode(Mod_id, CC_id, UE_id); - // mac_xface->get_ue_active_harq_pid(Mod_id,CC_id,rnti,frameP,subframeP,&harq_pid,&round,0); - //rrc_status = mac_eNB_get_rrc_status(Mod_id,rnti); - /* 1st allocate for the retx */ - - // retransmission in data channels - // control channel in the 1st transmission - // data channel for all TM - LOG_T(MAC, - "calling dlsch_scheduler_pre_processor_allocate .. \n "); - dlsch_scheduler_pre_processor_allocate(Mod_id, UE_id, - CC_id, - N_RBG[CC_id], - transmission_mode, - min_rb_unit - [CC_id], - to_prb(RC.mac - [Mod_id]->common_channels - [CC_id].mib->message.dl_Bandwidth), - nb_rbs_required, - nb_rbs_required_remaining, - rballoc_sub, - MIMO_mode_indicator); #ifdef TM5 + // This has to be revisited!!!! + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + i1 = 0; + i2 = 0; + i3 = 0; - // data chanel TM5: to be revisted - if ((round == 0) && - (transmission_mode == 5) && - (ue_sched_ctl->dl_pow_off[CC_id] != 1)) { + for (j = 0; j < N_RBG[CC_id]; j++) { + if (MIMO_mode_indicator[CC_id][j] == 2) { + i1 = i1 + 1; + } else if (MIMO_mode_indicator[CC_id][j] == 1) { + i2 = i2 + 1; + } else if (MIMO_mode_indicator[CC_id][j] == 0) { + i3 = i3 + 1; + } + } - for (j = 0; j < N_RBG[CC_id]; j += 2) { + if ((i1 < N_RBG[CC_id]) && (i2 > 0) && (i3 == 0)) { + PHY_vars_eNB_g[Mod_id][CC_id]->check_for_SUMIMO_transmissions = + PHY_vars_eNB_g[Mod_id][CC_id]-> + check_for_SUMIMO_transmissions + 1; + } - if ((((j == (N_RBG[CC_id] - 1)) - && (rballoc_sub[CC_id][j] == 0) - && (ue_sched_ctl-> - rballoc_sub_UE[CC_id][j] == 0)) - || ((j < (N_RBG[CC_id] - 1)) - && (rballoc_sub[CC_id][j + 1] == 0) - && - (ue_sched_ctl->rballoc_sub_UE - [CC_id][j + 1] == 0))) - && (nb_rbs_required_remaining[CC_id][UE_id] - > 0)) { + if (i3 == N_RBG[CC_id] && i1 == 0 && i2 == 0) { + PHY_vars_eNB_g[Mod_id][CC_id]->FULL_MUMIMO_transmissions = + PHY_vars_eNB_g[Mod_id][CC_id]->FULL_MUMIMO_transmissions + + 1; + } - for (ii = UE_list->next[i + 1]; ii >= 0; - ii = UE_list->next[ii]) { + if ((i1 < N_RBG[CC_id]) && (i3 > 0)) { + PHY_vars_eNB_g[Mod_id][CC_id]->check_for_MUMIMO_transmissions = + PHY_vars_eNB_g[Mod_id][CC_id]-> + check_for_MUMIMO_transmissions + 1; + } - UE_id2 = ii; - rnti2 = UE_RNTI(Mod_id, UE_id2); - ue_sched_ctl2 = - &UE_list->UE_sched_ctrl[UE_id2]; - round2 = ue_sched_ctl2->round[CC_id]; - if (rnti2 == NOT_A_RNTI) - continue; - if (UE_list-> - UE_sched_ctrl - [UE_id2].ul_out_of_sync == 1) - continue; - - eNB_UE_stats2 = - UE_list-> - eNB_UE_stats[CC_id][UE_id2]; - //mac_xface->get_ue_active_harq_pid(Mod_id,CC_id,rnti2,frameP,subframeP,&harq_pid2,&round2,0); - - if ((mac_eNB_get_rrc_status - (Mod_id, - rnti2) >= RRC_RECONFIGURED) - && (round2 == 0) - && - (get_tmode(Mod_id, CC_id, UE_id2) - == 5) - && (ue_sched_ctl-> - dl_pow_off[CC_id] != 1)) { - - if ((((j == (N_RBG[CC_id] - 1)) - && - (ue_sched_ctl->rballoc_sub_UE - [CC_id][j] == 0)) - || ((j < (N_RBG[CC_id] - 1)) - && - (ue_sched_ctl-> - rballoc_sub_UE[CC_id][j + - 1] - == 0))) - && - (nb_rbs_required_remaining - [CC_id] - [UE_id2] > 0)) { - - if ((((eNB_UE_stats2-> - DL_pmi_single ^ - eNB_UE_stats1-> - DL_pmi_single) - << (14 - j)) & 0xc000) == 0x4000) { //MU-MIMO only for 25 RBs configuration - - rballoc_sub[CC_id][j] = 1; - ue_sched_ctl-> - rballoc_sub_UE[CC_id] - [j] = 1; - ue_sched_ctl2-> - rballoc_sub_UE[CC_id] - [j] = 1; - MIMO_mode_indicator[CC_id] - [j] = 0; - - if (j < N_RBG[CC_id] - 1) { - rballoc_sub[CC_id][j + - 1] = - 1; - ue_sched_ctl-> - rballoc_sub_UE - [CC_id][j + 1] = 1; - ue_sched_ctl2->rballoc_sub_UE - [CC_id][j + 1] = 1; - MIMO_mode_indicator - [CC_id][j + 1] - = 0; - } - - ue_sched_ctl-> - dl_pow_off[CC_id] - = 0; - ue_sched_ctl2-> - dl_pow_off[CC_id] - = 0; - - - if ((j == N_RBG[CC_id] - 1) - && ((N_RB_DL == 25) - || (N_RB_DL == - 50))) { - - nb_rbs_required_remaining - [CC_id][UE_id] = - nb_rbs_required_remaining - [CC_id][UE_id] - - min_rb_unit[CC_id] - + 1; - ue_sched_ctl->pre_nb_available_rbs - [CC_id] = - ue_sched_ctl->pre_nb_available_rbs - [CC_id] + - min_rb_unit[CC_id] - - 1; - nb_rbs_required_remaining - [CC_id][UE_id2] = - nb_rbs_required_remaining - [CC_id][UE_id2] - - min_rb_unit[CC_id] - + 1; - ue_sched_ctl2->pre_nb_available_rbs - [CC_id] = - ue_sched_ctl2->pre_nb_available_rbs - [CC_id] + - min_rb_unit[CC_id] - - 1; - } else { - - nb_rbs_required_remaining - [CC_id][UE_id] = - nb_rbs_required_remaining - [CC_id][UE_id] - 4; - ue_sched_ctl->pre_nb_available_rbs - [CC_id] = - ue_sched_ctl->pre_nb_available_rbs - [CC_id] + 4; - nb_rbs_required_remaining - [CC_id][UE_id2] = - nb_rbs_required_remaining - [CC_id][UE_id2] - - 4; - ue_sched_ctl2->pre_nb_available_rbs - [CC_id] = - ue_sched_ctl2->pre_nb_available_rbs - [CC_id] + 4; - } - - break; - } - } - } - } - } - } - } -#endif - } // total_ue_count - } - } - } // end of for for r1 and r2 - -#ifdef TM5 - - // This has to be revisited!!!! - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - i1 = 0; - i2 = 0; - i3 = 0; - - for (j = 0; j < N_RBG[CC_id]; j++) { - if (MIMO_mode_indicator[CC_id][j] == 2) { - i1 = i1 + 1; - } else if (MIMO_mode_indicator[CC_id][j] == 1) { - i2 = i2 + 1; - } else if (MIMO_mode_indicator[CC_id][j] == 0) { - i3 = i3 + 1; - } - } - - if ((i1 < N_RBG[CC_id]) && (i2 > 0) && (i3 == 0)) { - PHY_vars_eNB_g[Mod_id][CC_id]->check_for_SUMIMO_transmissions = - PHY_vars_eNB_g[Mod_id][CC_id]-> - check_for_SUMIMO_transmissions + 1; - } - - if (i3 == N_RBG[CC_id] && i1 == 0 && i2 == 0) { - PHY_vars_eNB_g[Mod_id][CC_id]->FULL_MUMIMO_transmissions = - PHY_vars_eNB_g[Mod_id][CC_id]->FULL_MUMIMO_transmissions + - 1; - } - - if ((i1 < N_RBG[CC_id]) && (i3 > 0)) { - PHY_vars_eNB_g[Mod_id][CC_id]->check_for_MUMIMO_transmissions = - PHY_vars_eNB_g[Mod_id][CC_id]-> - check_for_MUMIMO_transmissions + 1; - } - - PHY_vars_eNB_g[Mod_id][CC_id]->check_for_total_transmissions = - PHY_vars_eNB_g[Mod_id][CC_id]->check_for_total_transmissions + - 1; - - } + PHY_vars_eNB_g[Mod_id][CC_id]->check_for_total_transmissions = + PHY_vars_eNB_g[Mod_id][CC_id]->check_for_total_transmissions + + 1; + } #endif - for (i = UE_list->head; i >= 0; i = UE_list->next[i]) { - UE_id = i; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { - for (ii = 0; ii < UE_num_active_CC(UE_list, UE_id); ii++) { - CC_id = UE_list->ordered_CCids[ii][UE_id]; - //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].dl_pow_off = dl_pow_off[UE_id]; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + for (i = 0; i < UE_num_active_CC(UE_list, UE_id); i++) { + CC_id = UE_list->ordered_CCids[i][UE_id]; + //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].dl_pow_off = dl_pow_off[UE_id]; - if (ue_sched_ctl->pre_nb_available_rbs[CC_id] > 0) { - LOG_D(MAC, - "******************DL Scheduling Information for UE%d ************************\n", - UE_id); - LOG_D(MAC, "dl power offset UE%d = %d \n", UE_id, - ue_sched_ctl->dl_pow_off[CC_id]); - LOG_D(MAC, - "***********RB Alloc for every subband for UE%d ***********\n", - UE_id); + if (ue_sched_ctl->pre_nb_available_rbs[CC_id] > 0) { + LOG_D(MAC, "******************DL Scheduling Information for UE%d ************************\n", UE_id); + LOG_D(MAC, "dl power offset UE%d = %d \n", UE_id, ue_sched_ctl->dl_pow_off[CC_id]); + LOG_D(MAC, "***********RB Alloc for every subband for UE%d ***********\n", UE_id); - for (j = 0; j < N_RBG[CC_id]; j++) { - //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].rballoc_sub[i] = rballoc_sub_UE[CC_id][UE_id][i]; - LOG_D(MAC, "RB Alloc for UE%d and Subband%d = %d\n", - UE_id, j, - ue_sched_ctl->rballoc_sub_UE[CC_id][j]); - } + for (j = 0; j < N_RBG[CC_id]; j++) { + //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].rballoc_sub[UE_id] = rballoc_sub_UE[CC_id][UE_id][UE_id]; + LOG_D(MAC, "RB Alloc for UE%d and Subband%d = %d\n", UE_id, j, ue_sched_ctl->rballoc_sub_UE[CC_id][j]); + } - //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = pre_nb_available_rbs[CC_id][UE_id]; - LOG_D(MAC, "[eNB %d][SLICE %d]Total RBs allocated for UE%d = %d\n", Mod_id, slice_id, UE_id, - ue_sched_ctl->pre_nb_available_rbs[CC_id]); - } - } + //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = pre_nb_available_rbs[CC_id][UE_id]; + LOG_D(MAC, "[eNB %d][SLICE %d]Total RBs allocated for UE%d = %d\n", + Mod_id, slice_id, UE_id, ue_sched_ctl->pre_nb_available_rbs[CC_id]); + } } + } } #define SF0_LIMIT 1 void dlsch_scheduler_pre_processor_reset(int module_idP, - int UE_id, - uint8_t CC_id, - int frameP, - int subframeP, - int N_RBG, - uint16_t nb_rbs_required[MAX_NUM_CCs] - [NUMBER_OF_UE_MAX], - uint16_t - nb_rbs_required_remaining - [MAX_NUM_CCs][NUMBER_OF_UE_MAX], - unsigned char total_ue_count[MAX_NUM_CCs], - unsigned char total_rbs_used[MAX_NUM_CCs], - unsigned char - rballoc_sub[MAX_NUM_CCs] - [N_RBG_MAX], - unsigned char - MIMO_mode_indicator[MAX_NUM_CCs] - [N_RBG_MAX]) + int UE_id, + uint8_t CC_id, + int frameP, + int subframeP, + int N_RBG, + uint16_t nb_rbs_required[MAX_NUM_CCs] + [NUMBER_OF_UE_MAX], + unsigned char + rballoc_sub[MAX_NUM_CCs] + [N_RBG_MAX], + unsigned char + MIMO_mode_indicator[MAX_NUM_CCs] + [N_RBG_MAX]) { - int i, j; - UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; - UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - rnti_t rnti = UE_RNTI(module_idP, UE_id); + int i, j; + UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; + UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + rnti_t rnti = UE_RNTI(module_idP, UE_id); - uint8_t *vrb_map = RC.mac[module_idP]->common_channels[CC_id].vrb_map; - int N_RB_DL = - to_prb(RC.mac[module_idP]->common_channels[CC_id].mib-> - message.dl_Bandwidth); - int RBGsize = N_RB_DL / N_RBG, RBGsize_last; + uint8_t *vrb_map = RC.mac[module_idP]->common_channels[CC_id].vrb_map; + int N_RB_DL = + to_prb(RC.mac[module_idP]->common_channels[CC_id].mib->message.dl_Bandwidth); + int RBGsize = N_RB_DL / N_RBG, RBGsize_last; #ifdef SF0_LIMIT - int sf0_upper = -1, sf0_lower = -1; + int sf0_upper = -1, sf0_lower = -1; #endif - LOG_D(MAC, "Running preprocessor for UE %d (%x)\n", UE_id, rnti); - // initialize harq_pid and round + LOG_D(MAC, "Running preprocessor for UE %d (%x)\n", UE_id, rnti); + // initialize harq_pid and round - if (ue_sched_ctl->ta_timer) - ue_sched_ctl->ta_timer--; + if (ue_sched_ctl->ta_timer) + ue_sched_ctl->ta_timer--; /* eNB_UE_stats *eNB_UE_stats; @@ -1234,95 +1237,96 @@ dlsch_scheduler_pre_processor_reset(int module_idP, } */ - nb_rbs_required[CC_id][UE_id] = 0; - ue_sched_ctl->pre_nb_available_rbs[CC_id] = 0; - ue_sched_ctl->dl_pow_off[CC_id] = 2; - nb_rbs_required_remaining[CC_id][UE_id] = 0; - total_ue_count[CC_id]=0; - total_rbs_used[CC_id]=0; - switch (N_RB_DL) { + nb_rbs_required[CC_id][UE_id] = 0; + ue_sched_ctl->pre_nb_available_rbs[CC_id] = 0; + ue_sched_ctl->dl_pow_off[CC_id] = 2; + + switch (N_RB_DL) { case 6: - RBGsize = 1; - RBGsize_last = 1; - break; + RBGsize = 1; + RBGsize_last = 1; + break; case 15: - RBGsize = 2; - RBGsize_last = 1; - break; + RBGsize = 2; + RBGsize_last = 1; + break; case 25: - RBGsize = 2; - RBGsize_last = 1; - break; + RBGsize = 2; + RBGsize_last = 1; + break; case 50: - RBGsize = 3; - RBGsize_last = 2; - break; + RBGsize = 3; + RBGsize_last = 2; + break; case 75: - RBGsize = 4; - RBGsize_last = 3; - break; + RBGsize = 4; + RBGsize_last = 3; + break; case 100: - RBGsize = 4; - RBGsize_last = 4; - break; + RBGsize = 4; + RBGsize_last = 4; + break; default: - AssertFatal(1 == 0, "unsupported RBs (%d)\n", N_RB_DL); - } + AssertFatal(1 == 0, "unsupported RBs (%d)\n", N_RB_DL); + } #ifdef SF0_LIMIT - switch (N_RBG) { + switch (N_RBG) { case 6: - sf0_lower = 0; - sf0_upper = 5; - break; + sf0_lower = 0; + sf0_upper = 5; + break; case 8: - sf0_lower = 2; - sf0_upper = 5; - break; + sf0_lower = 2; + sf0_upper = 5; + break; case 13: - sf0_lower = 4; - sf0_upper = 7; - break; + sf0_lower = 4; + sf0_upper = 7; + break; case 17: - sf0_lower = 7; - sf0_upper = 9; - break; + sf0_lower = 7; + sf0_upper = 9; + break; case 25: - sf0_lower = 11; - sf0_upper = 13; - break; + sf0_lower = 11; + sf0_upper = 13; + break; default: - AssertFatal(1 == 0, "unsupported RBs (%d)\n", N_RB_DL); - } + AssertFatal(1 == 0, "unsupported RBs (%d)\n", N_RB_DL); + } #endif - // Initialize Subbands according to VRB map - for (i = 0; i < N_RBG; i++) { - int rb_size = i == N_RBG - 1 ? RBGsize_last : RBGsize; - ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 0; - rballoc_sub[CC_id][i] = 0; + // Initialize Subbands according to VRB map + for (i = 0; i < N_RBG; i++) { + int rb_size = i == N_RBG - 1 ? RBGsize_last : RBGsize; + + ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 0; + rballoc_sub[CC_id][i] = 0; + #ifdef SF0_LIMIT - // for avoiding 6+ PRBs around DC in subframe 0 (avoid excessive errors) - /* TODO: make it proper - allocate those RBs, do not "protect" them, but - * compute number of available REs and limit MCS according to the - * TBS table 36.213 7.1.7.2.1-1 (can be done after pre-processor) - */ - if (subframeP == 0 && i >= sf0_lower && i <= sf0_upper) - rballoc_sub[CC_id][i] = 1; + // for avoiding 6+ PRBs around DC in subframe 0 (avoid excessive errors) + /* TODO: make it proper - allocate those RBs, do not "protect" them, but + * compute number of available REs and limit MCS according to the + * TBS table 36.213 7.1.7.2.1-1 (can be done after pre-processor) + */ + if (subframeP == 0 && i >= sf0_lower && i <= sf0_upper) + rballoc_sub[CC_id][i] = 1; #endif - // for SI-RNTI,RA-RNTI and P-RNTI allocations - for (j = 0; j < rb_size; j++) { - if (vrb_map[j + (i * RBGsize)] != 0) { - rballoc_sub[CC_id][i] = 1; - LOG_D(MAC, "Frame %d, subframe %d : vrb %d allocated\n", - frameP, subframeP, j + (i * RBGsize)); - break; - } - } - LOG_D(MAC, "Frame %d Subframe %d CC_id %d RBG %i : rb_alloc %d\n", - frameP, subframeP, CC_id, i, rballoc_sub[CC_id][i]); - MIMO_mode_indicator[CC_id][i] = 2; + + // for SI-RNTI,RA-RNTI and P-RNTI allocations + for (j = 0; j < rb_size; j++) { + if (vrb_map[j + (i * RBGsize)] != 0) { + rballoc_sub[CC_id][i] = 1; + LOG_D(MAC, "Frame %d, subframe %d : vrb %d allocated\n", + frameP, subframeP, j + (i * RBGsize)); + break; + } } + LOG_D(MAC, "Frame %d Subframe %d CC_id %d RBG %i : rb_alloc %d\n", + frameP, subframeP, CC_id, i, rballoc_sub[CC_id][i]); + MIMO_mode_indicator[CC_id][i] = 2; + } } diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 348b080d1e..07159f9c24 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -209,11 +209,6 @@ void dlsch_scheduler_pre_processor_reset(int module_idP, int UE_id, uint16_t nb_rbs_required[MAX_NUM_CCs] [NUMBER_OF_UE_MAX], - uint16_t - nb_rbs_required_remaining - [MAX_NUM_CCs][NUMBER_OF_UE_MAX], - unsigned char total_ue_count[MAX_NUM_CCs], - unsigned char total_rbs_used[MAX_NUM_CCs], unsigned char rballoc_sub[MAX_NUM_CCs] [N_RBG_MAX], From 9a9c867a7563e9c1089706de7cc59917ba19bbfd Mon Sep 17 00:00:00 2001 From: shahab SHARIAT BAGHERI Date: Tue, 20 Feb 2018 15:09:24 +0100 Subject: [PATCH 261/284] additional Mac stats and Improvements --- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 97 ++++++++++- .../ENB_APP/MESSAGES/V2/stats_common.proto | 36 +++++ .../ENB_APP/MESSAGES/V2/stats_messages.proto | 7 +- openair2/ENB_APP/flexran_agent_ran_api.c | 150 +++++++++++++++++- openair2/ENB_APP/flexran_agent_ran_api.h | 72 +++++++++ openair2/LAYER2/MAC/defs.h | 13 ++ openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 7 + openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 1 + 8 files changed, 379 insertions(+), 4 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 230917f673..921ea50bc0 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -62,7 +62,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, // Protocol__FlexHeader *header; int i, j, k; - // int cc_id = 0; + int cc_id = 0; int enb_id = mod_id; /* Allocate memory for list of UE reports */ @@ -490,6 +490,101 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, } + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_STATS) { + + Protocol__FlexMacStats *macstats; + macstats = malloc(sizeof(Protocol__FlexMacStats)); + if (macstats == NULL) + goto error; + protocol__flex_mac_stats__init(macstats); + + + macstats->total_bytes_sdus_dl = flexran_get_total_size_dl_mac_sdus(mod_id, i, cc_id); + macstats->has_total_bytes_sdus_dl = 1; + + macstats->total_bytes_sdus_ul = flexran_get_total_size_ul_mac_sdus(mod_id, i, cc_id); + macstats->has_total_bytes_sdus_ul = 1; + + macstats->tbs_dl = flexran_get_TBS_dl(mod_id, i, cc_id); + macstats->has_tbs_dl = 1; + + macstats->tbs_ul = flexran_get_TBS_ul(mod_id, i, cc_id); + macstats->has_tbs_ul = 1; + + macstats->prb_retx_dl = flexran_get_num_prb_retx_dl_per_ue(mod_id, i, cc_id); + macstats->has_prb_retx_dl = 1; + + macstats->prb_retx_ul = flexran_get_num_prb_retx_ul_per_ue(mod_id, i, cc_id); + macstats->has_prb_retx_ul = 1; + + macstats->prb_dl = flexran_get_num_prb_dl_tx_per_ue(mod_id, i, cc_id); + macstats->has_prb_dl = 1; + + macstats->prb_ul = flexran_get_num_prb_ul_rx_per_ue(mod_id, i, cc_id); + macstats->has_prb_ul = 1; + + macstats->mcs1_dl = flexran_get_mcs1_dl(mod_id, i, cc_id); + macstats->has_mcs1_dl = 1; + + macstats->mcs2_dl = flexran_get_mcs2_dl(mod_id, i, cc_id); + macstats->has_mcs2_dl = 1; + + macstats->mcs1_ul = flexran_get_mcs1_ul(mod_id, i, cc_id); + macstats->has_mcs1_ul = 1; + + macstats->mcs2_ul = flexran_get_mcs2_ul(mod_id, i, cc_id); + macstats->has_mcs2_ul = 1; + + macstats->total_prb_dl = flexran_get_total_prb_dl_tx_per_ue(mod_id, i, cc_id); + macstats->has_total_prb_dl = 1; + + macstats->total_prb_ul = flexran_get_total_prb_ul_rx_per_ue(mod_id, i, cc_id); + macstats->has_total_prb_ul = 1; + + macstats->total_pdu_dl = flexran_get_total_num_pdu_dl(mod_id, i, cc_id); + macstats->has_total_pdu_dl = 1; + + macstats->total_pdu_ul = flexran_get_total_num_pdu_ul(mod_id, i, cc_id); + macstats->has_total_pdu_ul = 1; + + macstats->total_tbs_dl = flexran_get_total_TBS_dl(mod_id, i, cc_id); + macstats->has_total_tbs_dl = 1; + + macstats->total_tbs_ul = flexran_get_total_TBS_ul(mod_id, i, cc_id); + macstats->has_total_tbs_ul = 1; + + macstats->harq_round = flexran_get_harq_round(mod_id, cc_id, i); + macstats->has_harq_round = 1; + + Protocol__FlexMacSdusDl ** mac_sdus; + mac_sdus = malloc(sizeof(Protocol__FlexMacSdusDl) * flexran_get_num_mac_sdu_tx(mod_id, i, cc_id)); + if (mac_sdus == NULL) + goto error; + + macstats->n_mac_sdus_dl = flexran_get_num_mac_sdu_tx(mod_id, i, cc_id); + + for (j = 0; j < macstats->n_mac_sdus_dl; j++){ + + + mac_sdus[j] = malloc(sizeof(Protocol__FlexMacSdusDl)); + protocol__flex_mac_sdus_dl__init(mac_sdus[j]); + + mac_sdus[j]->lcid = flexran_get_mac_sdu_lcid_index(mod_id, i, cc_id, j); + mac_sdus[j]->has_lcid = 1; + + mac_sdus[j]->sdu_length = flexran_get_mac_sdu_size(mod_id, i, cc_id, mac_sdus[j]->lcid); + mac_sdus[j]->has_sdu_length = 1; + + + } + + + macstats->mac_sdus_dl = mac_sdus; + + + ue_report[i]->mac_stats = macstats; + + } diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto index f651195ab1..ee286981f5 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto @@ -269,3 +269,39 @@ message flex_pdcp_stats { optional uint64 sfn=17; } + +// +// MAC Stats +// + +message flex_mac_stats { + + optional uint32 tbs_dl = 1; + optional uint32 tbs_ul = 2; + optional uint32 prb_retx_dl = 3; + optional uint32 prb_retx_ul = 4; + optional uint32 prb_dl = 5; + optional uint32 prb_ul = 6; + optional uint32 mcs1_dl = 7; + optional uint32 mcs2_dl = 8; + optional uint32 mcs1_ul = 9; + optional uint32 mcs2_ul = 10; + optional uint32 total_bytes_sdus_ul = 11; + optional uint32 total_bytes_sdus_dl = 12; + optional uint32 total_prb_retx_dl = 13; + optional uint32 total_prb_retx_ul = 14; + optional uint32 total_prb_dl = 15; + optional uint32 total_prb_ul = 16; + optional uint32 total_pdu_dl = 17; + optional uint32 total_pdu_ul = 18; + optional uint32 total_tbs_dl = 19; + optional uint32 total_tbs_ul = 20; + repeated flex_mac_sdus_dl mac_sdus_dl = 21; + optional uint32 harq_round = 22; +} + +message flex_mac_sdus_dl { + + optional uint32 sdu_length = 1; + optional uint32 lcid = 2; +} diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto index b8126c55f2..8eb6510de3 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto @@ -48,7 +48,8 @@ message flex_ue_stats_report { optional flex_paging_buffer_report pbr = 8; optional flex_ul_cqi_report ul_cqi_report = 9; optional flex_rrc_measurements rrc_measurements = 10; - optional flex_pdcp_stats pdcp_stats = 11; + optional flex_pdcp_stats pdcp_stats = 11; + optional flex_mac_stats mac_stats = 12; } // @@ -85,9 +86,11 @@ enum flex_ue_stats_type { FLUST_DL_CQI = 16; FLUST_PBS = 32; FLUST_UL_CQI = 64; + FLUST_MAC_STATS = 128; FLUST_PDCP_STATS = 1024; FLUST_RRC_MEASUREMENTS = 65536; // To be extended with more types of stats - + + } diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index c1743bf744..23b564d25e 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -132,7 +132,7 @@ int8_t flexran_get_ue_phr(mid_t mod_id, mid_t ue_id) uint8_t flexran_get_ue_wcqi(mid_t mod_id, mid_t ue_id) { if (!phy_is_present(mod_id, 0)) return 0; - return RC.eNB[mod_id][0]->UE_stats[ue_id].DL_cqi[0]; + return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].dl_cqi[0]; } rlc_buffer_occupancy_t flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) @@ -188,12 +188,160 @@ int32_t flexran_get_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id) } } +uint32_t flexran_get_total_size_dl_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_sdu_bytes; + +} + +uint32_t flexran_get_total_size_ul_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->eNB_stats[cc_id].total_ulsch_bytes_rx; + +} + + +uint32_t flexran_get_TBS_dl(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].TBS; +} + +uint32_t flexran_get_TBS_ul(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].ulsch_TBS; + +} + +uint16_t flexran_get_num_prb_retx_dl_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id) { + +if (!mac_is_present(mod_id)) return 0; +return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used_retx; + +} + +uint32_t flexran_get_num_prb_retx_ul_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used_retx_rx; + +} + +uint16_t flexran_get_num_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id){ + +if (!mac_is_present(mod_id)) return 0; +return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used; + +} + +uint16_t flexran_get_num_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id){ + +if (!mac_is_present(mod_id)) return 0; +return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used_rx; + +} + + uint8_t flexran_get_ue_wpmi(mid_t mod_id, mid_t ue_id, uint8_t cc_id) { if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].periodic_wideband_pmi[cc_id]; } +uint8_t flexran_get_mcs1_dl(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].dlsch_mcs1; +} + +uint8_t flexran_get_mcs2_dl(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].dlsch_mcs2; +} + +uint8_t flexran_get_mcs1_ul(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].ulsch_mcs1; + +} + +uint8_t flexran_get_mcs2_ul(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].ulsch_mcs2; + +} + +uint32_t flexran_get_total_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_rbs_used; + +} + +uint32_t flexran_get_total_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_rbs_used_rx; +} + +uint32_t flexran_get_total_num_pdu_dl(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_num_pdus; +} + +uint32_t flexran_get_total_num_pdu_ul(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_num_pdus_rx; +} + +uint64_t flexran_get_total_TBS_dl(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_pdu_bytes; +} + +uint64_t flexran_get_total_TBS_ul(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_ulsch_TBS; +} + +int flexran_get_harq_round(mid_t mod_id, uint8_t cc_id, mid_t ue_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].harq_round; + +} + +uint32_t flexran_get_num_mac_sdu_tx(mid_t mod_id, mid_t ue_id, int cc_id){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].num_mac_sdu_tx; + +} + +unsigned char flexran_get_mac_sdu_lcid_index(mid_t mod_id, mid_t ue_id, int cc_id, int index){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].lcid_sdu[index]; +} + +uint32_t flexran_get_mac_sdu_size(mid_t mod_id, mid_t ue_id, int cc_id, int lcid){ + + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].sdu_length_tx[lcid]; + +} + + /* TODO needs to be revised */ void flexran_update_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id) { diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index aafb82077e..498da257b1 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -107,6 +107,78 @@ void flexran_update_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id); */ /* this function is broken */ int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id); +/*Get number of mac SDU DL*/ +uint32_t flexran_get_num_mac_sdu_tx(mid_t mod_id, mid_t ue_id, int cc_id); + +/*Return the MAC sdu size got from logical channel lcid */ +uint32_t flexran_get_mac_sdu_size(mid_t mod_id, mid_t ue_id, int cc_id, int lcid); + +/*Return number of MAC SDUs obtained in MAC layer*/ +uint32_t flexran_get_num_mac_sdu_tx(mid_t mod_id, mid_t ue_id, int cc_id); + +/*Get mac sdu lcid index*/ +unsigned char flexran_get_mac_sdu_lcid_index(mid_t mod_id, mid_t ue_id, int cc_id, int index); + +/*Get MAC size sdus length dl*/ +uint32_t flexran_get_size_dl_mac_sdus(mid_t mod_id, uint32_t cc_id); + +/*Get MAC size sdus length ul */ +uint32_t flexran_get_size_ul_mac_sdus(mid_t mod_id, uint32_t cc_id); + +/*Get total size DL MAC SDUS*/ +uint32_t flexran_get_total_size_dl_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id); + +/*Get total size of UL mac SDUS*/ +uint32_t flexran_get_total_size_ul_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id); + +/*Get total number of PDU DL*/ +uint32_t flexran_get_total_num_pdu_dl(mid_t mod_id, mid_t ue_id, int cc_id); + +/*Get total number of PDU UL*/ +uint32_t flexran_get_total_num_pdu_ul(mid_t mod_id, mid_t ue_id, int cc_id); + +/*Get total PRB dl TODO Should be changed*/ +uint32_t flexran_get_total_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id); + +/*Get total PRB ul TODO Should be changed*/ +uint32_t flexran_get_total_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id); + +/*Get number of prb for tx per UE DL*/ +uint16_t flexran_get_num_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id); + +/*Get number of prb for rx per UE UL*/ +uint16_t flexran_get_num_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id); + +/*Get number of prb for retx per UE UL*/ +uint32_t flexran_get_num_prb_retx_ul_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id); + +/*Get number of prb for retx per UE*/ +uint16_t flexran_get_num_prb_retx_dl_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id); + +/*MCS before rate adaptation DL*/ +uint8_t flexran_get_mcs1_dl(mid_t mod_id, mid_t ue_id, int cc_id); + +/*MCS after rate adaptation DL*/ +uint8_t flexran_get_mcs2_dl(mid_t mod_id, mid_t ue_id, int cc_id); + +/*MCS before rate adaptation UL*/ +uint8_t flexran_get_mcs1_ul(mid_t mod_id, mid_t ue_id, int cc_id); + +/*MCS after rate adaptation UL*/ +uint8_t flexran_get_mcs2_ul(mid_t mod_id, mid_t ue_id, int cc_id); + +/*Get downlink TBS*/ +uint32_t flexran_get_TBS_dl(mid_t mod_id, mid_t ue_id, int cc_id); + +/*Get uplink TBS */ +uint32_t flexran_get_TBS_ul(mid_t mod_id, mid_t ue_id, int cc_id); + +/*Get total TBS DL*/ +uint64_t flexran_get_total_TBS_dl(mid_t mod_id, mid_t ue_id, int cc_id); + +/*Get total TBS DL*/ +uint64_t flexran_get_total_TBS_ul(mid_t mod_id, mid_t ue_id, int cc_id); + /* Get the number of active component carriers for a specific UE */ int flexran_get_active_CC(mid_t mod_id, mid_t ue_id); diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index ef1d710138..640cb67294 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -562,6 +562,13 @@ typedef struct { uint32_t num_retransmission; /// instantaneous tx throughput for each TTI // uint32_t tti_throughput[NB_RB_MAX]; + // Number of received MAC SDU + uint32_t num_mac_sdu_tx; + // LCID related to SDU + unsigned char lcid_sdu[NB_RB_MAX]; + // Length of SDU Got from LC DL + uint32_t sdu_length_tx[NB_RB_MAX]; + /// overall // @@ -607,6 +614,8 @@ typedef struct { /// uplink transport block size uint32_t ulsch_TBS; + + uint32_t total_ulsch_TBS; /// total rb used for a new uplink transmission uint32_t num_retransmission_rx; @@ -648,6 +657,10 @@ typedef struct { uint32_t total_num_pdus_rx; /// num of error pdus uint32_t total_num_errors_rx; + // Number of error PDUS + uint32_t num_mac_sdu_rx; + // Length of SDU Got from LC UL - Size array can be refined + uint32_t sdu_length_rx[NB_RB_MAX]; } eNB_UE_STATS; /*! \brief eNB template for UE context information */ diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 48b19b0919..7e6eee0f87 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -1036,6 +1036,8 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, module_idP, CC_id, sdu_lengths[0]); sdu_length_total = sdu_lengths[0]; sdu_lcids[0] = DCCH; + UE_list->eNB_UE_stats[CC_id][UE_id].lcid_sdu[0] = DCCH; + UE_list->eNB_UE_stats[CC_id][UE_id].sdu_length_tx[DCCH] = sdu_lengths[0]; UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH] += 1; UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH] += sdu_lengths[0]; num_sdus = 1; @@ -1079,6 +1081,8 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, sdu_lcids[num_sdus] = DCCH1; sdu_length_total += sdu_lengths[num_sdus]; header_len_dcch += 2; + UE_list->eNB_UE_stats[CC_id][UE_id].lcid_sdu[num_sdus] = DCCH1; + UE_list->eNB_UE_stats[CC_id][UE_id].sdu_length_tx[DCCH1] = sdu_lengths[num_sdus]; UE_list->eNB_UE_stats[CC_id][UE_id]. num_pdu_tx[DCCH1] += 1; UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1] += sdu_lengths[num_sdus]; @@ -1153,6 +1157,8 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, UE_list-> eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid] += 1; + UE_list->eNB_UE_stats[CC_id][UE_id].lcid_sdu[num_sdus] = lcid; + UE_list->eNB_UE_stats[CC_id][UE_id].sdu_length_tx[lcid] = sdu_lengths[num_sdus]; UE_list-> eNB_UE_stats[CC_id][UE_id].num_bytes_tx [lcid] += sdu_lengths[num_sdus]; @@ -1355,6 +1361,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, eNB->eNB_stats[CC_id].dlsch_pdus_tx += 1; UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].num_mac_sdu_tx = num_sdus; UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = mcs; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index ac87498560..b4fb025ea4 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -1315,6 +1315,7 @@ schedule_ulsch_rnti(module_id_t module_idP, rb_table[rb_table_index]); UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx += rb_table[rb_table_index]; UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_TBS = UE_template->TBS_UL[harq_pid]; + UE_list->eNB_UE_stats[CC_id][UE_id].total_ulsch_TBS += UE_template->TBS_UL[harq_pid]; // buffer_occupancy -= TBS; T(T_ENB_MAC_UE_UL_SCHEDULE, T_INT(module_idP), From 1e2a7156e0b03de8e89814581db38ffb588456c2 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 22 Feb 2018 11:54:16 +0100 Subject: [PATCH 262/284] test setup v2: minor bugfix --- cmake_targets/autotests/v2/connection.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake_targets/autotests/v2/connection.py b/cmake_targets/autotests/v2/connection.py index 1952b8b72f..3a254f89b8 100644 --- a/cmake_targets/autotests/v2/connection.py +++ b/cmake_targets/autotests/v2/connection.py @@ -13,7 +13,7 @@ class connection: try: (pid, fd) = os.forkpty() except BaseException, e: - log("ERROR: forkpty for '" + description + "': " + e) + log("ERROR: forkpty for '" + description + "': " + str(e)) (pid, fd) = (-1, -1) if pid == -1: @@ -26,7 +26,7 @@ class connection: os.execvp('sshpass', ['sshpass', '-p', password, 'ssh', user + '@' + host]) except BaseException, e: - log("ERROR: execvp for '" + description + "': " + e) + log("ERROR: execvp for '" + description + "': " + str(e)) log("ERROR: execvp failed for '" + description + "'") os._exit(1) From e66bd0e2b1e1c65730477b40a09f73f371870608 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 22 Feb 2018 12:03:10 +0100 Subject: [PATCH 263/284] RAN API: unify style, declare missing function in header --- openair2/ENB_APP/flexran_agent_ran_api.c | 121 ++++++++++------------- openair2/ENB_APP/flexran_agent_ran_api.h | 15 +-- 2 files changed, 62 insertions(+), 74 deletions(-) diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 23b564d25e..61757d0703 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -188,157 +188,142 @@ int32_t flexran_get_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id) } } -uint32_t flexran_get_total_size_dl_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id){ - +uint32_t flexran_get_total_size_dl_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_sdu_bytes; - } -uint32_t flexran_get_total_size_ul_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id){ - - if (!mac_is_present(mod_id)) return 0; +uint32_t flexran_get_total_size_ul_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id) +{ + if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->eNB_stats[cc_id].total_ulsch_bytes_rx; - } - -uint32_t flexran_get_TBS_dl(mid_t mod_id, mid_t ue_id, int cc_id){ - +uint32_t flexran_get_TBS_dl(mid_t mod_id, mid_t ue_id, int cc_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].TBS; } -uint32_t flexran_get_TBS_ul(mid_t mod_id, mid_t ue_id, int cc_id){ - +uint32_t flexran_get_TBS_ul(mid_t mod_id, mid_t ue_id, int cc_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].ulsch_TBS; - } -uint16_t flexran_get_num_prb_retx_dl_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id) { - -if (!mac_is_present(mod_id)) return 0; -return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used_retx; - +uint16_t flexran_get_num_prb_retx_dl_per_ue(mid_t mod_id, mid_t ue_id, int cc_id) +{ + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used_retx; } -uint32_t flexran_get_num_prb_retx_ul_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id){ - +uint32_t flexran_get_num_prb_retx_ul_per_ue(mid_t mod_id, mid_t ue_id, int cc_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used_retx_rx; - } -uint16_t flexran_get_num_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id){ - -if (!mac_is_present(mod_id)) return 0; -return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used; - +uint16_t flexran_get_num_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id) +{ + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used; } -uint16_t flexran_get_num_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id){ - -if (!mac_is_present(mod_id)) return 0; -return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used_rx; - +uint16_t flexran_get_num_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id) +{ + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used_rx; } - uint8_t flexran_get_ue_wpmi(mid_t mod_id, mid_t ue_id, uint8_t cc_id) { if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].periodic_wideband_pmi[cc_id]; } -uint8_t flexran_get_mcs1_dl(mid_t mod_id, mid_t ue_id, int cc_id){ - +uint8_t flexran_get_mcs1_dl(mid_t mod_id, mid_t ue_id, int cc_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].dlsch_mcs1; } -uint8_t flexran_get_mcs2_dl(mid_t mod_id, mid_t ue_id, int cc_id){ - +uint8_t flexran_get_mcs2_dl(mid_t mod_id, mid_t ue_id, int cc_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].dlsch_mcs2; } -uint8_t flexran_get_mcs1_ul(mid_t mod_id, mid_t ue_id, int cc_id){ - +uint8_t flexran_get_mcs1_ul(mid_t mod_id, mid_t ue_id, int cc_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].ulsch_mcs1; - } -uint8_t flexran_get_mcs2_ul(mid_t mod_id, mid_t ue_id, int cc_id){ - +uint8_t flexran_get_mcs2_ul(mid_t mod_id, mid_t ue_id, int cc_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].ulsch_mcs2; - } -uint32_t flexran_get_total_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id){ - +uint32_t flexran_get_total_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_rbs_used; - } -uint32_t flexran_get_total_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id){ - +uint32_t flexran_get_total_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_rbs_used_rx; } -uint32_t flexran_get_total_num_pdu_dl(mid_t mod_id, mid_t ue_id, int cc_id){ - +uint32_t flexran_get_total_num_pdu_dl(mid_t mod_id, mid_t ue_id, int cc_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_num_pdus; } -uint32_t flexran_get_total_num_pdu_ul(mid_t mod_id, mid_t ue_id, int cc_id){ - +uint32_t flexran_get_total_num_pdu_ul(mid_t mod_id, mid_t ue_id, int cc_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_num_pdus_rx; } -uint64_t flexran_get_total_TBS_dl(mid_t mod_id, mid_t ue_id, int cc_id){ - +uint64_t flexran_get_total_TBS_dl(mid_t mod_id, mid_t ue_id, int cc_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_pdu_bytes; } -uint64_t flexran_get_total_TBS_ul(mid_t mod_id, mid_t ue_id, int cc_id){ - +uint64_t flexran_get_total_TBS_ul(mid_t mod_id, mid_t ue_id, int cc_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_ulsch_TBS; } -int flexran_get_harq_round(mid_t mod_id, uint8_t cc_id, mid_t ue_id){ - +int flexran_get_harq_round(mid_t mod_id, uint8_t cc_id, mid_t ue_id) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].harq_round; - } -uint32_t flexran_get_num_mac_sdu_tx(mid_t mod_id, mid_t ue_id, int cc_id){ - - if (!mac_is_present(mod_id)) return 0; - return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].num_mac_sdu_tx; - +uint32_t flexran_get_num_mac_sdu_tx(mid_t mod_id, mid_t ue_id, int cc_id) +{ + if (!mac_is_present(mod_id)) return 0; + return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].num_mac_sdu_tx; } -unsigned char flexran_get_mac_sdu_lcid_index(mid_t mod_id, mid_t ue_id, int cc_id, int index){ - +unsigned char flexran_get_mac_sdu_lcid_index(mid_t mod_id, mid_t ue_id, int cc_id, int index) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].lcid_sdu[index]; } -uint32_t flexran_get_mac_sdu_size(mid_t mod_id, mid_t ue_id, int cc_id, int lcid){ - +uint32_t flexran_get_mac_sdu_size(mid_t mod_id, mid_t ue_id, int cc_id, int lcid) +{ if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].sdu_length_tx[lcid]; - } diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 498da257b1..0550722394 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -120,10 +120,10 @@ uint32_t flexran_get_num_mac_sdu_tx(mid_t mod_id, mid_t ue_id, int cc_id); unsigned char flexran_get_mac_sdu_lcid_index(mid_t mod_id, mid_t ue_id, int cc_id, int index); /*Get MAC size sdus length dl*/ -uint32_t flexran_get_size_dl_mac_sdus(mid_t mod_id, uint32_t cc_id); +uint32_t flexran_get_size_dl_mac_sdus(mid_t mod_id, int cc_id); /*Get MAC size sdus length ul */ -uint32_t flexran_get_size_ul_mac_sdus(mid_t mod_id, uint32_t cc_id); +uint32_t flexran_get_size_ul_mac_sdus(mid_t mod_id, int cc_id); /*Get total size DL MAC SDUS*/ uint32_t flexran_get_total_size_dl_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id); @@ -144,16 +144,16 @@ uint32_t flexran_get_total_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id uint32_t flexran_get_total_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id); /*Get number of prb for tx per UE DL*/ -uint16_t flexran_get_num_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id); +uint16_t flexran_get_num_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id); /*Get number of prb for rx per UE UL*/ -uint16_t flexran_get_num_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id); +uint16_t flexran_get_num_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id); /*Get number of prb for retx per UE UL*/ -uint32_t flexran_get_num_prb_retx_ul_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id); +uint32_t flexran_get_num_prb_retx_ul_per_ue(mid_t mod_id, mid_t ue_id, int cc_id); /*Get number of prb for retx per UE*/ -uint16_t flexran_get_num_prb_retx_dl_per_ue(mid_t mod_id, mid_t ue_id, uint32_t cc_id); +uint16_t flexran_get_num_prb_retx_dl_per_ue(mid_t mod_id, mid_t ue_id, int cc_id); /*MCS before rate adaptation DL*/ uint8_t flexran_get_mcs1_dl(mid_t mod_id, mid_t ue_id, int cc_id); @@ -179,6 +179,9 @@ uint64_t flexran_get_total_TBS_dl(mid_t mod_id, mid_t ue_id, int cc_id); /*Get total TBS DL*/ uint64_t flexran_get_total_TBS_ul(mid_t mod_id, mid_t ue_id, int cc_id); +/* Get the current HARQ round for UE ue_id */ +int flexran_get_harq_round(mid_t mod_id, uint8_t cc_id, mid_t ue_id); + /* Get the number of active component carriers for a specific UE */ int flexran_get_active_CC(mid_t mod_id, mid_t ue_id); From 58eab7515f8b5c3461c5a04aac43cc1b87732c6b Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 21 Feb 2018 11:21:56 +0100 Subject: [PATCH 264/284] integration fix: fix crash With value 4 when connecting one UE and doing some downlink iperf TCP there is a crash. Probably due to the multiple wrong RA detected leading to uplink failure of fake UE that never sends Msg3 (because, well, there is no other UE). This is another problem that will be fixed at some point. Anyway, this value 4 fails. Let's put back 3. --- openair1/SCHED/phy_procedures_lte_eNb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index f70cd85725..496767ca4d 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -1272,7 +1272,7 @@ void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) ulsch_harq->o_ACK[0], ulsch_harq->o_ACK[1]); - if (ulsch_harq->round >= 4) { + if (ulsch_harq->round >= 3) { ulsch_harq->status = SCH_IDLE; ulsch_harq->handled = 0; ulsch->harq_mask &= ~(1 << harq_pid); From 8ca5fb4ef280090ecdca4f151816b5950d075d50 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 21 Feb 2018 11:53:13 +0100 Subject: [PATCH 265/284] integration: cleanup - remove spaces at the end of lines - remove useless dead code use: git show -p -w to see it clearly --- openair1/PHY/CODING/lte_rate_matching.c | 8 +- openair1/PHY/INIT/defs.h | 4 +- openair1/PHY/INIT/lte_init_ru.c | 5 - openair1/PHY/INIT/lte_param_init.c | 8 +- .../lte_ul_channel_estimation.c | 3 - openair1/PHY/LTE_TRANSPORT/dci.c | 54 +++-- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 6 - openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c | 5 - .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 9 +- openair1/PHY/LTE_TRANSPORT/drs_modulation.c | 2 +- openair1/PHY/MODULATION/slot_fep_ul.c | 3 - openair1/SCHED/fapi_l1.c | 8 +- openair1/SCHED/phy_procedures_lte_eNb.c | 5 - openair1/SCHED/phy_procedures_lte_ue.c | 6 +- openair1/SCHED/ru_procedures.c | 2 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 62 +++--- openair1/SIMULATION/LTE_PHY/ulsim.c | 56 +++--- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 184 +++++++++--------- openair2/LAYER2/MAC/defs.h | 76 ++++---- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 22 +-- 20 files changed, 240 insertions(+), 288 deletions(-) diff --git a/openair1/PHY/CODING/lte_rate_matching.c b/openair1/PHY/CODING/lte_rate_matching.c index f96e5dbb17..41c3c5e5a9 100644 --- a/openair1/PHY/CODING/lte_rate_matching.c +++ b/openair1/PHY/CODING/lte_rate_matching.c @@ -463,7 +463,7 @@ uint32_t lte_rate_matching_turbo(uint32_t RTC, uint8_t Qm, uint8_t Nl, uint8_t r, - uint8_t nb_rb) + uint8_t nb_rb) // uint8_t m) { @@ -513,7 +513,7 @@ uint32_t lte_rate_matching_turbo(uint32_t RTC, // counter_buffer[rvidx][cnt]=0; if (Ncb>(3*(RTC<<5))) AssertFatal(1==0,"Exiting, RM condition (Ncb %d, RTC %d, Nir/C %d, Nsoft %d, Kw %d)\n",Ncb,RTC,Nir/C,Nsoft,3*(RTC<<5)); - + AssertFatal(Nl>0,"Nl is 0\n"); AssertFatal(Qm>0,"Qm is 0\n"); Gp = G/Nl/Qm; @@ -750,8 +750,8 @@ int lte_rate_matching_turbo_rx(uint32_t RTC, for (; (ind0 && soft_input2[k]<0) || - (w[ind]<0 && soft_input2[k]>0)) + if ((w[ind]>0 && soft_input2[k]<0) || + (w[ind]<0 && soft_input2[k]>0)) printf("ind %d: w %d => soft_in %d\n",ind,w[ind],soft_input2[k]);*/ w[ind] += soft_input2[k++]; #ifdef RM_DEBUG diff --git a/openair1/PHY/INIT/defs.h b/openair1/PHY/INIT/defs.h index 2c92503133..be3e5c160b 100644 --- a/openair1/PHY/INIT/defs.h +++ b/openair1/PHY/INIT/defs.h @@ -333,13 +333,13 @@ void init_lte_top(LTE_DL_FRAME_PARMS *lte_frame_parms); void lte_param_init(PHY_VARS_eNB **eNBp, PHY_VARS_UE **UEp, RU_t **rup, - unsigned char N_tx_port_eNB, + unsigned char N_tx_port_eNB, unsigned char N_tx_phy, unsigned char N_rx_ru, unsigned char N_rx_ue, unsigned char transmission_mode, uint8_t extended_prefix_flag, - frame_t frame_type, + frame_t frame_type, uint16_t Nid_cell, uint8_t tdd_config, uint8_t N_RB_DL, diff --git a/openair1/PHY/INIT/lte_init_ru.c b/openair1/PHY/INIT/lte_init_ru.c index f6c4d0709a..9168193074 100644 --- a/openair1/PHY/INIT/lte_init_ru.c +++ b/openair1/PHY/INIT/lte_init_ru.c @@ -32,11 +32,6 @@ #include "assertions.h" #include -#undef LOG_I -#define LOG_I(A,B,C...) printf(B,C) -#undef LOG_D -#define LOG_D(A,B,C...) printf(B,C) - int phy_init_RU(RU_t *ru) { LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; diff --git a/openair1/PHY/INIT/lte_param_init.c b/openair1/PHY/INIT/lte_param_init.c index c09652db93..1743a8d90c 100644 --- a/openair1/PHY/INIT/lte_param_init.c +++ b/openair1/PHY/INIT/lte_param_init.c @@ -37,13 +37,13 @@ extern RU_t *ru; void lte_param_init(PHY_VARS_eNB **eNBp, PHY_VARS_UE **UEp, RU_t **rup, - unsigned char N_tx_port_eNB, + unsigned char N_tx_port_eNB, unsigned char N_tx_phy, unsigned char N_rx_ru, unsigned char N_rx_ue, unsigned char transmission_mode, uint8_t extended_prefix_flag, - frame_t frame_type, + frame_t frame_type, uint16_t Nid_cell, uint8_t tdd_config, uint8_t N_RB_DL, @@ -142,7 +142,7 @@ void lte_param_init(PHY_VARS_eNB **eNBp, // DL power control init //if (transmission_mode == 1) { - UE->pdsch_config_dedicated->p_a = pa; + UE->pdsch_config_dedicated->p_a = pa; if (transmission_mode == 1 || transmission_mode ==7) { ((eNB->frame_parms).pdsch_config_common).p_b = 0; @@ -161,7 +161,7 @@ void lte_param_init(PHY_VARS_eNB **eNBp, if (eNB->frame_parms.N_RB_DL == 100) ru->N_TA_offset = 624; else if (eNB->frame_parms.N_RB_DL == 50) ru->N_TA_offset = 624/2; else if (eNB->frame_parms.N_RB_DL == 25) ru->N_TA_offset = 624/4; - } + } else ru->N_TA_offset=0; printf("Done lte_param_init\n"); diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c index 9eb34a8905..9c91d28ade 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c @@ -34,9 +34,6 @@ static int16_t ru_90c[2*128] = {32767, 0,32766, -402,32758, -804,32746, -1206,32 #define SCALE 0x3FFF -//#undef LOG_D -//#define LOG_D(A,B,C...) printf(B,C) - int32_t lte_ul_channel_estimation(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, uint8_t UE_id, diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index f75ae326e9..94d6cd9c3f 100755 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -35,10 +35,10 @@ #include "PHY/defs.h" #include "PHY/extern.h" #include "SCHED/defs.h" -#include "SIMULATION/TOOLS/defs.h" // for taus +#include "SIMULATION/TOOLS/defs.h" // for taus #include "PHY/sse_intrin.h" -#include "assertions.h" +#include "assertions.h" #include "T.h" #include "UTIL/LOG/log.h" #include "UTIL/LOG/vcd_signal_dumper.h" @@ -52,9 +52,6 @@ //extern uint16_t phich_reg[MAX_NUM_PHICH_GROUPS][3]; //extern uint16_t pcfich_reg[4]; -//#undef LOG_D -//#define LOG_D(A,B,C...) printf(B,C) - uint32_t check_phich_reg(LTE_DL_FRAME_PARMS *frame_parms,uint32_t kprime,uint8_t lprime,uint8_t mi) { @@ -155,7 +152,7 @@ uint16_t extract_crc(uint8_t *dci,uint8_t dci_len) // dci[(dci_len>>3)+1] = 0; // dci[(dci_len>>3)+2] = 0; return((uint16_t)crc16); - + } @@ -218,10 +215,10 @@ uint8_t *generate_dci0(uint8_t *dci, uint16_t coded_bits; uint8_t dci_flip[8]; - AssertFatal((aggregation_level==1) || - (aggregation_level==2) || - (aggregation_level==4) || - (aggregation_level==8) + AssertFatal((aggregation_level==1) || + (aggregation_level==2) || + (aggregation_level==4) || + (aggregation_level==8) #ifdef Rel14 // Added for EPDCCH/MPDCCH || (aggregation_level==16) || @@ -230,17 +227,17 @@ uint8_t *generate_dci0(uint8_t *dci, #endif , "generate_dci FATAL, illegal aggregation_level %d\n",aggregation_level); - + coded_bits = 72 * aggregation_level; - + #ifdef DEBUG_DCI_ENCODING for (int i=0;i<1+((DCI_LENGTH+16)/8);i++) printf("i %d : %x\n",i,dci[i]); #endif - + if (DCI_LENGTH<=32) { dci_flip[0] = dci[3]; dci_flip[1] = dci[2]; @@ -480,7 +477,7 @@ void pdcch_deinterleaving(LTE_DL_FRAME_PARMS *frame_parms,uint16_t *z, uint16_t wptr[1] = wptr2[1]; wptr[2] = wptr2[2]; wptr[3] = wptr2[3]; - /* + /* printf("pdcch_deinterleaving (%p,%p): quad %d (%d) -> (%d,%d %d,%d %d,%d %d,%d)\n",wptr,wptr2,i,(i+frame_parms->Nid_cell)%Mquad, ((char*)wptr2)[0], ((char*)wptr2)[1], @@ -519,7 +516,7 @@ void pdcch_deinterleaving(LTE_DL_FRAME_PARMS *frame_parms,uint16_t *z, uint16_t zptr[2] = wptr[2]; zptr[3] = wptr[3]; - /* + /* printf("deinterleaving ; k %d, index-Nd %d => (%d,%d,%d,%d,%d,%d,%d,%d)\n",k,(index-ND), ((int8_t *)wptr)[0], ((int8_t *)wptr)[1], @@ -540,7 +537,7 @@ void pdcch_deinterleaving(LTE_DL_FRAME_PARMS *frame_parms,uint16_t *z, uint16_t for (i=0; i (%d,%d,%d,%d,%d,%d,%d,%d)\n",i, ((int8_t *)zptr)[0], ((int8_t *)zptr)[1], @@ -550,7 +547,7 @@ void pdcch_deinterleaving(LTE_DL_FRAME_PARMS *frame_parms,uint16_t *z, uint16_t ((int8_t *)zptr)[5], ((int8_t *)zptr)[6], ((int8_t *)zptr)[7]); - */ + */ } } @@ -1513,7 +1510,7 @@ void pdcch_channel_compensation(int32_t **rxdataF_ext, dl_ch128_2 = (__m128i *)&dl_ch_estimates_ext[2+aarx][symbol*frame_parms->N_RB_DL*12]; #elif defined(__arm__) - + #endif for (rb=0; rbN_RB_DL; rb++) { #if defined(__x86_64__) || defined(__i386__) @@ -2114,7 +2111,7 @@ void pdcch_unscrambling(LTE_DL_FRAME_PARMS *frame_parms, reset = 0; } - + // printf("unscrambling %d : e %d, c %d => ",i,llr[i],((s>>(i&0x1f))&1)); if (((s>>(i%32))&1)==0) llr[i] = -llr[i]; @@ -2348,7 +2345,7 @@ uint8_t generate_dci_top(uint8_t num_pdcch_symbols, for (i=0; iframe_parms, - get_mi(&RC.eNB[Mod_id][CC_id]->frame_parms,subframe))); + get_mi(&RC.eNB[Mod_id][CC_id]->frame_parms,subframe))); } int get_nCCE_offset_l1(int *CCE_table, - const unsigned char L, - const int nCCE, - const int common_dci, - const unsigned short rnti, + const unsigned char L, + const int nCCE, + const int common_dci, + const unsigned short rnti, const unsigned char subframe) { @@ -2700,7 +2697,7 @@ int get_nCCE_offset_l1(int *CCE_table, break; } } - + if (search_space_free == 1) { // printf("returning %d\n",m*L); @@ -3023,7 +3020,7 @@ void dci_decoding_procedure0(LTE_UE_PDCCH **pdcch_vars, return; } // rnti match } // CCEmap_cand == 0 -/* +/* if ( agregationLevel != 0xFF && (format_c == format0 && m==0 && si_rnti != SI_RNTI)) { @@ -4246,6 +4243,3 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *ue, return(dci_cnt); } - - - diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index dd4228a9f9..4b73de6fcc 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -44,12 +44,6 @@ #include "LAYER2/MAC/extern.h" #include "LAYER2/MAC/defs.h" -/*#undef LOG_D -#define LOG_D(A,B,C...) printf(B,C) -#undef LOG_I -#define LOG_I(A,B,C...) printf(B,C) -*/ - //#define DEBUG_DCI uint32_t localRIV2alloc_LUT6[32]; diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c index 71399c2652..697164110b 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c @@ -39,11 +39,6 @@ //#define DEBUG_DLSCH_DECODING //#define UE_DEBUG_TRACE 1 -//#undef LOG_D -//#define LOG_D(A,B,C...) printf(B,C) -//#undef LOG_I -//#define LOG_I(A,B,C...) printf(B,C) - extern double cpuf; void free_ue_dlsch(LTE_UE_DLSCH_t *dlsch) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index 062cb8d299..1becc98752 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -48,11 +48,6 @@ int16_t interf_unaw_shift = 13; //#define DEBUG_HARQ -//#undef LOG_D -//#define LOG_D(A,B,C...) printf(B,C) -//#undef LOG_I -//#define LOG_I(A,B,C...) printf(B,C) - #define DEBUG_PHY 1 //#define DEBUG_DLSCH_DEMOD 1 @@ -847,7 +842,7 @@ int rx_pdsch(PHY_VARS_UE *ue, pllr_symbol_cw1 = (int8_t*)pdsch_vars[eNB_id]->llr[1]; pllr_symbol_cw0 += llr_offset_symbol; pllr_symbol_cw1 += llr_offset_symbol; - + LOG_I(PHY,"compute LLRs [AbsSubframe %d.%d-%d] NbRB %d Qm %d LLRs-Length %d LLR-Offset %d @LLR Buff %x @LLR Buff(symb) %x\n", frame, subframe,symbol, nb_rb,dlsch0_harq->Qm, @@ -855,7 +850,7 @@ int rx_pdsch(PHY_VARS_UE *ue, pdsch_vars[eNB_id]->llr_offset[symbol], (int16_t*)pdsch_vars[eNB_id]->llr[0], pllr_symbol_cw0); - + switch (dlsch0_harq->Qm) { case 2 : if ((rx_type==rx_standard) || (codeword_TB1 == -1)) { diff --git a/openair1/PHY/LTE_TRANSPORT/drs_modulation.c b/openair1/PHY/LTE_TRANSPORT/drs_modulation.c index 101954ca3d..a0bde219b5 100644 --- a/openair1/PHY/LTE_TRANSPORT/drs_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/drs_modulation.c @@ -94,7 +94,7 @@ int generate_drs_pusch(PHY_VARS_UE *ue, lsymbols_per_tti; l += (7 - frame_parms->Ncp),u=u1,v=v1,cyclic_shift=cyclic_shift1) { - drs_offset = 0; + drs_offset = 0; #ifdef DEBUG_DRS printf("drs_modulation: Msc_RS = %d, Msc_RS_idx = %d, u=%d,v=%d\n",Msc_RS, Msc_RS_idx,u,v); #endif diff --git a/openair1/PHY/MODULATION/slot_fep_ul.c b/openair1/PHY/MODULATION/slot_fep_ul.c index 844d15a87e..f41fc98791 100644 --- a/openair1/PHY/MODULATION/slot_fep_ul.c +++ b/openair1/PHY/MODULATION/slot_fep_ul.c @@ -24,9 +24,6 @@ #include "defs.h" //#define DEBUG_FEP -//#undef LOG_D -//#define LOG_D(A,B,C...) printf(B,C) - int slot_fep_ul(RU_t *ru, unsigned char l, unsigned char Ns, diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c index 6d7132c091..dbefe62747 100644 --- a/openair1/SCHED/fapi_l1.c +++ b/openair1/SCHED/fapi_l1.c @@ -37,12 +37,6 @@ #include "nfapi_interface.h" #include "fapi_l1.h" -/*#undef LOG_D -#define LOG_D(A,B,C...) printf(B,C) -#undef LOG_I -#define LOG_I(A,B,C...) printf(B,C) -*/ - int oai_nfapi_dl_config_req(nfapi_dl_config_request_t *dl_config_req); int oai_nfapi_tx_req(nfapi_tx_request_t *tx_req); int oai_nfapi_hi_dci0_req(nfapi_hi_dci0_request_t *hi_dci0_req); @@ -539,7 +533,7 @@ void handle_nfapi_ul_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, int8_t UE_id; // check if we have received a dci for this ue and ulsch descriptor is configured - + if (ul_config_pdu->pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) { AssertFatal((UE_id = find_ulsch(ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti,eNB,SEARCH_EXIST_OR_FREE))>=0, "No existing UE ULSCH for rnti %x\n",rel8->rnti); diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 496767ca4d..105dac0808 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -50,11 +50,6 @@ # include "intertask_interface.h" #endif -/* -#undef LOG_D -#define LOG_D(A,B,C...) printf(B,C) -*/ - extern uint8_t nfapi_mode; int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind); diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index d1097503ea..2635649589 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -73,10 +73,6 @@ extern double cpuf; -//#undef LOG_D -//#define LOG_D(A,B,C...) printf(B,C) - - void Msg1_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); void Msg3_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); @@ -1301,7 +1297,7 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empt #endif nsymb>>1, &ue->frame_parms); - + normal_prefix_mod(&ue->common_vars.txdataF[aa][((subframe_tx*nsymb)+(nsymb>>1))*frame_parms->ofdm_symbol_size], #if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) dummy_tx_buffer+(frame_parms->samples_per_tti>>1), diff --git a/openair1/SCHED/ru_procedures.c b/openair1/SCHED/ru_procedures.c index 0aad195d43..b00a9e2039 100644 --- a/openair1/SCHED/ru_procedures.c +++ b/openair1/SCHED/ru_procedures.c @@ -536,7 +536,7 @@ void fep_full(RU_t *ru) { start_meas(&ru->ofdm_demod_stats); if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 ); - + remove_7_5_kHz(ru,proc->subframe_rx<<1); remove_7_5_kHz(ru,1+(proc->subframe_rx<<1)); diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 2de1698450..885d29cc4e 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -254,9 +254,9 @@ void DL_channel(RU_t *ru,PHY_VARS_UE *UE,uint subframe,int awgn_flag,double SNR, uint16_t fill_tx_req(nfapi_tx_request_body_t *tx_req_body, - uint16_t absSF, + uint16_t absSF, uint16_t pdu_length, - uint16_t pdu_index, + uint16_t pdu_index, uint8_t *pdu) { nfapi_tx_request_pdu_t *TX_req = &tx_req_body->tx_pdu_list[tx_req_body->number_of_pdus]; @@ -384,7 +384,7 @@ void fill_DCI(PHY_VARS_eNB *eNB, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = n_rnti+k; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power - + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = 0; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = TPC; // dont adjust power when retransmitting dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = ndi; @@ -403,14 +403,14 @@ void fill_DCI(PHY_VARS_eNB *eNB, dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; - fill_dlsch_config(dl_req, - get_TBS_DL(mcs1,NB_RB), + fill_dlsch_config(dl_req, + get_TBS_DL(mcs1,NB_RB), (retrans > 0) ? -1 : 0, /* retransmission, no pdu_index */ - n_rnti, + n_rnti, 0, // type 0 allocation from 7.1.6 in 36.213 0, // virtual_resource_block_assignment_flag, unused here - DLSCH_RB_ALLOC, // resource_block_coding, - get_Qm(mcs1), + DLSCH_RB_ALLOC, // resource_block_coding, + get_Qm(mcs1), rv, // redundancy version 1, // transport blocks 0, // transport block to codeword swap flag @@ -419,7 +419,7 @@ void fill_DCI(PHY_VARS_eNB *eNB, 1, // number of subbands // uint8_t codebook_index, 4, // UE category capacity - pa, // pa + pa, // pa 0, // delta_power_offset for TM5 0, // ngap 0, // nprb @@ -429,7 +429,7 @@ void fill_DCI(PHY_VARS_eNB *eNB, ); fill_tx_req(TX_req, (frame * 10) + subframe, - get_TBS_DL(mcs1,NB_RB), + get_TBS_DL(mcs1,NB_RB), 0, input_buffer[k]); } @@ -441,26 +441,26 @@ void fill_DCI(PHY_VARS_eNB *eNB, case 3: if (common_flag == 0) { - + if (eNB->frame_parms.nb_antennas_tx == 2) { - + if (eNB->frame_parms.frame_type == TDD) { - + } else { - + } } } break; - + case 4: if (common_flag == 0) { - + if (eNB->frame_parms.nb_antennas_tx == 2) { - + if (eNB->frame_parms.frame_type == TDD) { - + } @@ -564,7 +564,7 @@ int main(int argc, char **argv) // char input_val_str[50],input_val_str2[50]; char input_trch_val[16]; - + // unsigned char pbch_pdu[6]; @@ -651,7 +651,7 @@ int main(int argc, char **argv) nfapi_dl_config_request_t DL_req; nfapi_ul_config_request_t UL_req; nfapi_hi_dci0_request_t HI_DCI0_req; - nfapi_dl_config_request_pdu_t dl_config_pdu_list[MAX_NUM_DL_PDU]; + nfapi_dl_config_request_pdu_t dl_config_pdu_list[MAX_NUM_DL_PDU]; nfapi_tx_request_pdu_t tx_pdu_list[MAX_NUM_TX_REQUEST_PDU]; nfapi_tx_request_t TX_req; Sched_Rsp_t sched_resp; @@ -1155,7 +1155,7 @@ int main(int argc, char **argv) uint8_t input_buffer[NUMBER_OF_UE_MAX][20000]; - for (i=0;iframe_parms; @@ -1585,7 +1585,7 @@ int main(int argc, char **argv) (TB0_active==1)?mcs1:0,mcs2,!(trials&1),(TB0_active==1)?round&3:0,pa,&num_common_dci,&num_ue_spec_dci,&num_dci); } } - + proc_eNB->subframe_tx = subframe; sched_resp.subframe=subframe; sched_resp.frame=proc_eNB->frame_tx; @@ -1610,7 +1610,7 @@ int main(int argc, char **argv) 0, subframe, transmission_mode>=7?transmission_mode:0); - + uncoded_ber_bit = (short*) malloc(sizeof(short)*coded_bits_per_codeword); printf("uncoded_ber_bit=%p\n",uncoded_ber_bit); } @@ -1736,13 +1736,13 @@ int main(int argc, char **argv) write_output("pdcch_rxF_comp0.m","pdcch0_rxF_comp0",UE->pdcch_vars[0][eNB_id]->rxdataF_comp[0],4*300,1,1); write_output("pdcch_rxF_llr.m","pdcch_llr",UE->pdcch_vars[0][eNB_id]->llr,2400,1,4); - + write_output("rxsig0.m","rxs0", &UE->common_vars.rxdata[0][0],10*UE->frame_parms.samples_per_tti,1,1); write_output("rxsigF0.m","rxsF0", &UE->common_vars.common_vars_rx_data_per_thread[UE->current_thread_id[subframe]].rxdataF[0][0],UE->frame_parms.ofdm_symbol_size*nsymb,1,1); - + exit(-1); - + } int bit_errors=0; @@ -1755,9 +1755,9 @@ int main(int argc, char **argv) UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0], 0, subframe<<1); - for (i=0;idlsch[0][0]->harq_processes[0]->e[i]==1 && UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0][i] > 0)|| - (eNB->dlsch[0][0]->harq_processes[0]->e[i]==0 && UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0][i] < 0)) { + (eNB->dlsch[0][0]->harq_processes[0]->e[i]==0 && UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0][i] < 0)) { uncoded_ber_bit[bit_errors++] = 1; printf("error in pos %d : %d => %d\n",i, eNB->dlsch[0][0]->harq_processes[0]->e[i], @@ -1770,10 +1770,10 @@ int main(int argc, char **argv) UE->pdsch_vars[UE->current_thread_id[subframe]][0]->llr[0][i]); */ } - + write_output("dlsch_ber_bit.m","ber_bit",uncoded_ber_bit,coded_bits_per_codeword,1,0); write_output("ch0.m","ch0",eNB2UE[0]->ch[0],eNB2UE[0]->channel_length,1,8); - + if (eNB->frame_parms.nb_antennas_tx>1) write_output("ch1.m","ch1",eNB2UE[0]->ch[eNB->frame_parms.nb_antennas_rx],eNB2UE[0]->channel_length,1,8); @@ -2488,7 +2488,7 @@ int main(int argc, char **argv) if (test_perf && !test_passed) return(-1); - else + else return(0); } diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 8381553bb7..d6009bc793 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -84,20 +84,20 @@ extern void ru_fep_full_2thread(RU_t *ru); nfapi_dl_config_request_t DL_req; nfapi_ul_config_request_t UL_req; nfapi_hi_dci0_request_t HI_DCI0_req; -nfapi_ul_config_request_pdu_t ul_config_pdu_list[MAX_NUM_DL_PDU]; +nfapi_ul_config_request_pdu_t ul_config_pdu_list[MAX_NUM_DL_PDU]; nfapi_tx_request_pdu_t tx_pdu_list[MAX_NUM_TX_REQUEST_PDU]; nfapi_tx_request_t TX_req; Sched_Rsp_t sched_resp; void -fill_nfapi_ulsch_config_request(nfapi_ul_config_request_pdu_t *ul_config_pdu, +fill_nfapi_ulsch_config_request(nfapi_ul_config_request_pdu_t *ul_config_pdu, uint8_t cqi_req, uint8_t p_eNB, uint8_t cqi_ReportModeAperiodic, uint8_t betaOffset_CQI_Index, uint8_t betaOffset_RI_Index, uint8_t dl_cqi_pmi_size, - uint8_t tmode, + uint8_t tmode, uint32_t handle, uint16_t rnti, uint8_t resource_block_start, @@ -111,7 +111,7 @@ fill_nfapi_ulsch_config_request(nfapi_ul_config_request_pdu_t *ul_config_pdu, uint8_t harq_process_number, uint8_t ul_tx_mode, uint8_t current_tx_nb, - uint8_t n_srs, + uint8_t n_srs, uint16_t size) { memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t)); @@ -152,11 +152,11 @@ fill_nfapi_ulsch_config_request(nfapi_ul_config_request_pdu_t *ul_config_pdu, else if (p_eNB <= 2) ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 0; else if (p_eNB == 4) ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 2; - for (int ri = 0; - ri < (1 << ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size); + for (int ri = 0; + ri < (1 << ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size); ri++) ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[ri] = dl_cqi_pmi_size; - + ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.delta_offset_cqi = betaOffset_CQI_Index; ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.delta_offset_ri = betaOffset_RI_Index; } @@ -263,17 +263,17 @@ void fill_ulsch_dci(PHY_VARS_eNB *eNB, break; } - fill_nfapi_ulsch_config_request(&ul_req->ul_config_pdu_list[0], - cqi_flag&1, + fill_nfapi_ulsch_config_request(&ul_req->ul_config_pdu_list[0], + cqi_flag&1, 1, // p_eNB 0, // reportmode Aperiodic beta_CQI, beta_RI, cqi_size, - //cc, - //UE_template->physicalConfigDedicated, + //cc, + //UE_template->physicalConfigDedicated, 1, - 0, + 0, 14, // rnti first_rb, // resource_block_start nb_rb, // number_of_resource_blocks @@ -292,7 +292,7 @@ void fill_ulsch_dci(PHY_VARS_eNB *eNB, sched_resp->UL_req->header.message_id = NFAPI_UL_CONFIG_REQUEST; ul_req->number_of_pdus=1; ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; - + } extern void eNB_fep_full(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc); @@ -740,7 +740,7 @@ int main(int argc, char **argv) for (int k=0;kRU_list[0]->nb_rx;k++) eNB->common_vars.rxdataF[k] = eNB->RU_list[0]->common.rxdataF[k]; memset((void*)&eNB->UL_INFO,0,sizeof(eNB->UL_INFO)); - + printf("Setting indication lists\n"); eNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list = eNB->rx_pdu_list; eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = eNB->crc_pdu_list; @@ -922,7 +922,7 @@ int main(int argc, char **argv) UE->mac_enabled=0; - + eNB_rxtx_proc_t *proc_rxtx = &eNB->proc.proc_rxtx[subframe&1]; UE_rxtx_proc_t *proc_rxtx_ue = &UE->proc.proc_rxtx[subframe&1]; proc_rxtx->frame_rx=1; @@ -1102,7 +1102,7 @@ int main(int argc, char **argv) reset_meas(&eNB->ulsch_tc_intl1_stats); reset_meas(&eNB->ulsch_tc_intl2_stats); - // initialization + // initialization struct list time_vector_tx; initialize(&time_vector_tx); struct list time_vector_tx_ifft; @@ -1137,10 +1137,10 @@ int main(int argc, char **argv) while (round < 4) { proc_rxtx->frame_rx=1; proc_rxtx->subframe_rx=subframe; - + proc_rxtx->frame_tx=pdcch_alloc2ul_frame(&eNB->frame_parms,1,subframe); proc_rxtx->subframe_tx=pdcch_alloc2ul_subframe(&eNB->frame_parms,subframe); - + proc_rxtx_ue->frame_tx = proc_rxtx->frame_rx; proc_rxtx_ue->frame_rx = (subframe<4)?(proc_rxtx->frame_tx-1):(proc_rxtx->frame_tx); proc_rxtx_ue->subframe_tx = proc_rxtx->subframe_rx; @@ -1158,7 +1158,7 @@ int main(int argc, char **argv) if (mcs < 11) modulation_type = 2; else if (mcs < 21) modulation_type = 4; else if (mcs < 29) modulation_type = 6; - + fill_ulsch_dci(eNB,proc_rxtx->frame_rx,subframe,&sched_resp,14,(void*)&UL_alloc_pdu,first_rb,nb_rb,(round==0)?mcs:(28+rvidx[round]),modulation_type,ndi,cqi_flag,beta_CQI,beta_RI,cqi_size); UE->ulsch_Msg3_active[eNB_id] = 0; @@ -1216,16 +1216,16 @@ int main(int argc, char **argv) tx_lev = signal_energy(&UE->common_vars.txdata[0][eNB->frame_parms.samples_per_tti*subframe], eNB->frame_parms.samples_per_tti); - - + + if (n_frames==1) { write_output("txsigF0UL.m","txsF0", &UE->common_vars.txdataF[0][eNB->frame_parms.ofdm_symbol_size*nsymb*subframe],eNB->frame_parms.ofdm_symbol_size*nsymb,1, 1); //write_output("txsigF1.m","txsF1", UE->common_vars.txdataF[0],FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX,1,1); } - + } // input_fd == NULL - + tx_lev_dB = (unsigned int) dB_fixed_times10(tx_lev); if (n_frames==1) { @@ -1337,7 +1337,7 @@ int main(int argc, char **argv) ru->feprx = (parallel_flag == 1) ? ru_fep_full_2thread : fep_full; eNB->td = (parallel_flag == 1) ? ulsch_decoding_data_2thread : ulsch_decoding_data; - + ru->feprx(ru); phy_procedures_eNB_uespec_RX(eNB,proc_rxtx,no_relay); @@ -1371,10 +1371,10 @@ int main(int argc, char **argv) // printf("ulsch_coding: O[%d] %d\n",i,o_flip[i]); - + // if (ret <= eNB->ulsch[0]->max_turbo_iterations) { - - if (eNB->ulsch[0]->harq_processes[harq_pid]->status == SCH_IDLE) { + + if (eNB->ulsch[0]->harq_processes[harq_pid]->status == SCH_IDLE) { // avg_iter += ret; iter_trials++; @@ -1425,7 +1425,7 @@ int main(int argc, char **argv) if (n_frames==1) { printf("ULSCH in error in round %d\n",round); } - } // ulsch error + } // ulsch error } // round diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 921ea50bc0..31b0f2fe75 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -17,7 +17,7 @@ *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org - */ + */ /*! \file flexran_agent_mac.c * \brief FlexRAN agent message handler for MAC layer @@ -54,7 +54,7 @@ struct lfds700_ringbuffer_element *dl_mac_config_array[NUM_MAX_ENB]; struct lfds700_ringbuffer_state ringbuffer_state[NUM_MAX_ENB]; -int flexran_agent_mac_stats_reply(mid_t mod_id, +int flexran_agent_mac_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report) { @@ -68,7 +68,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, /* Allocate memory for list of UE reports */ if (report_config->nr_ue > 0) { - + for (i = 0; i < report_config->nr_ue; i++) { @@ -76,24 +76,24 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, /* Check flag for creation of buffer status report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_BSR) { //TODO should be automated - ue_report[i]->n_bsr = 4; + ue_report[i]->n_bsr = 4; uint32_t *elem; elem = (uint32_t *) malloc(sizeof(uint32_t)*ue_report[i]->n_bsr); if (elem == NULL) goto error; for (j = 0; j < ue_report[i]->n_bsr; j++) { - // NN: we need to know the cc_id here, consider the first one + // NN: we need to know the cc_id here, consider the first one elem[j] = flexran_get_ue_bsr_ul_buffer_info (enb_id, i, j); } - + ue_report[i]->bsr = elem; } - + /* Check flag for creation of PHR report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PHR) { ue_report[i]->phr = flexran_get_ue_phr (enb_id, i); // eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].phr_info; ue_report[i]->has_phr = 1; - + } /* Check flag for creation of RLC buffer status report */ @@ -134,19 +134,19 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, if (ue_report[i]->n_rlc_report > 0) ue_report[i]->rlc_report = rlc_reports; - + } /* Check flag for creation of MAC CE buffer status report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_CE_BS) { // TODO: Fill in the actual MAC CE buffer status report - ue_report[i]->pending_mac_ces = (flexran_get_MAC_CE_bitmap_TA(enb_id,i,0) | (0 << 1) | (0 << 2) | (0 << 3)) & 15; + ue_report[i]->pending_mac_ces = (flexran_get_MAC_CE_bitmap_TA(enb_id,i,0) | (0 << 1) | (0 << 2) | (0 << 3)) & 15; // Use as bitmap. Set one or more of the; /* Use as bitmap. Set one or more of the // PROTOCOL__FLEX_CE_TYPE__FLPCET_ values // found in stats_common.pb-c.h. See - // flex_ce_type in FlexRAN specification + // flex_ce_type in FlexRAN specification ue_report[i]->has_pending_mac_ces = 1; - + } /* Check flag for creation of DL CQI report */ @@ -167,7 +167,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, Protocol__FlexDlCsi **csi_reports; csi_reports = malloc(sizeof(Protocol__FlexDlCsi *)*dl_report->n_csi_report); if (csi_reports == NULL) - goto error; + goto error; for (j = 0; j < dl_report->n_csi_report; j++) { csi_reports[j] = malloc(sizeof(Protocol__FlexDlCsi)); @@ -211,18 +211,18 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, if (csi11 == NULL) goto error; protocol__flex_csi_p11__init(csi11); - - csi11->wb_cqi = malloc(sizeof(csi11->wb_cqi)); + + csi11->wb_cqi = malloc(sizeof(csi11->wb_cqi)); csi11->n_wb_cqi = 1; - csi11->wb_cqi[0] = flexran_get_ue_wcqi (enb_id, i); - // According To spec 36.213 - + csi11->wb_cqi[0] = flexran_get_ue_wcqi (enb_id, i); + // According To spec 36.213 + if (flexran_get_antenna_ports(enb_id, j) == 2 && csi_reports[j]->ri == 1) { // TODO PMI csi11->wb_pmi = flexran_get_ue_wpmi(enb_id, i, 0); csi11->has_wb_pmi = 1; - } + } else if (flexran_get_antenna_ports(enb_id, j) == 2 && csi_reports[j]->ri == 2){ // TODO PMI @@ -239,14 +239,14 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, } - csi11->has_wb_pmi = 0; + csi11->has_wb_pmi = 0; csi_reports[j]->p11csi = csi11; } - - + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P20CSI){ @@ -256,16 +256,16 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, if (csi20 == NULL) goto error; protocol__flex_csi_p20__init(csi20); - - csi20->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + + csi20->wb_cqi = flexran_get_ue_wcqi (enb_id, i); csi20->has_wb_cqi = 1; - + csi20->bandwidth_part_index = 1 ;//TODO csi20->has_bandwidth_part_index = 1; csi20->sb_index = 1 ;//TODO - csi20->has_sb_index = 1 ; + csi20->has_sb_index = 1 ; csi_reports[j]->p20csi = csi20; @@ -280,20 +280,20 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, // if (csi21 == NULL) // goto error; // protocol__flex_csi_p21__init(csi21); - - // csi21->wb_cqi = flexran_get_ue_wcqi (enb_id, i); - - + + // csi21->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + + // csi21->wb_pmi = flexran_get_ue_pmi(enb_id); //TDO inside // csi21->has_wb_pmi = 1; - // csi21->sb_cqi = 1; // TODO - + // csi21->sb_cqi = 1; // TODO + // csi21->bandwidth_part_index = 1 ; //TDO inside - // csi21->has_bandwidth_part_index = 1 ; + // csi21->has_bandwidth_part_index = 1 ; // csi21->sb_index = 1 ;//TODO - // csi21->has_sb_index = 1 ; + // csi21->has_sb_index = 1 ; // csi_reports[j]->p20csi = csi21; @@ -308,10 +308,10 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, // if (csi12 == NULL) // goto error; // protocol__flex_csi_a12__init(csi12); - - // csi12->wb_cqi = flexran_get_ue_wcqi (enb_id, i); - - // csi12->sb_pmi = 1 ; //TODO inside + + // csi12->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + + // csi12->sb_pmi = 1 ; //TODO inside // TODO continou } @@ -323,18 +323,18 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, // if (csi22 == NULL) // goto error; // protocol__flex_csi_a22__init(csi22); - - // csi22->wb_cqi = flexran_get_ue_wcqi (enb_id, i); - - // csi22->sb_cqi = 1 ; //TODO inside - // csi22->wb_pmi = flexran_get_ue_wcqi (enb_id, i); - // csi22->has_wb_pmi = 1; - - // csi22->sb_pmi = 1 ; //TODO inside + // csi22->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + + // csi22->sb_cqi = 1 ; //TODO inside + + // csi22->wb_pmi = flexran_get_ue_wcqi (enb_id, i); // csi22->has_wb_pmi = 1; - // csi22->sb_list = flexran_get_ue_wcqi (enb_id, i); + // csi22->sb_pmi = 1 ; //TODO inside + // csi22->has_wb_pmi = 1; + + // csi22->sb_list = flexran_get_ue_wcqi (enb_id, i); } @@ -347,10 +347,10 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, // goto error; // protocol__flex_csi_a20__init(csi20); - // csi20->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + // csi20->wb_cqi = flexran_get_ue_wcqi (enb_id, i); // csi20->has_wb_cqi = 1; - // csi20>sb_cqi = 1 ; //TODO inside + // csi20>sb_cqi = 1 ; //TODO inside // csi20>has_sb_cqi = 1 ; // csi20->sb_list = 1; // TODO inside @@ -371,7 +371,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, dl_report->csi_report = csi_reports; //Add the DL CQI report to the stats report ue_report[i]->dl_cqi_report = dl_report; - + } /* Check flag for creation of paging buffer status report */ @@ -463,7 +463,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, //TODO: Set the servCellIndex for this report ul_report[j]->serv_cell_index = 0; ul_report[j]->has_serv_cell_index = 1; - + //Set the list of UL reports of this UE to the full UL report full_ul_report->cqi_meas = ul_report; @@ -487,9 +487,9 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, } // Add full UL CQI report to the UE report ue_report[i]->ul_cqi_report = full_ul_report; - - } + + } if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_STATS) { Protocol__FlexMacStats *macstats; @@ -497,7 +497,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, if (macstats == NULL) goto error; protocol__flex_mac_stats__init(macstats); - + macstats->total_bytes_sdus_dl = flexran_get_total_size_dl_mac_sdus(mod_id, i, cc_id); macstats->has_total_bytes_sdus_dl = 1; @@ -508,7 +508,7 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, macstats->tbs_dl = flexran_get_TBS_dl(mod_id, i, cc_id); macstats->has_tbs_dl = 1; - macstats->tbs_ul = flexran_get_TBS_ul(mod_id, i, cc_id); + macstats->tbs_ul = flexran_get_TBS_ul(mod_id, i, cc_id); macstats->has_tbs_ul = 1; macstats->prb_retx_dl = flexran_get_num_prb_retx_dl_per_ue(mod_id, i, cc_id); @@ -556,16 +556,16 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, macstats->harq_round = flexran_get_harq_round(mod_id, cc_id, i); macstats->has_harq_round = 1; - Protocol__FlexMacSdusDl ** mac_sdus; + Protocol__FlexMacSdusDl ** mac_sdus; mac_sdus = malloc(sizeof(Protocol__FlexMacSdusDl) * flexran_get_num_mac_sdu_tx(mod_id, i, cc_id)); if (mac_sdus == NULL) goto error; - macstats->n_mac_sdus_dl = flexran_get_num_mac_sdu_tx(mod_id, i, cc_id); - + macstats->n_mac_sdus_dl = flexran_get_num_mac_sdu_tx(mod_id, i, cc_id); + for (j = 0; j < macstats->n_mac_sdus_dl; j++){ - + mac_sdus[j] = malloc(sizeof(Protocol__FlexMacSdusDl)); protocol__flex_mac_sdus_dl__init(mac_sdus[j]); @@ -577,29 +577,29 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, } - - macstats->mac_sdus_dl = mac_sdus; - - ue_report[i]->mac_stats = macstats; + macstats->mac_sdus_dl = mac_sdus; - } - - - - } + ue_report[i]->mac_stats = macstats; - - - - } + } + + + + + } + + + + + } /* Allocate memory for list of cell reports */ if (report_config->nr_cc > 0) { - - + + // Fill in the Cell reports for (i = 0; i < report_config->nr_cc; i++) { @@ -627,10 +627,10 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, cell_report[i]->noise_inter_report = ni_report; } } - - - + + + } return 0; @@ -835,9 +835,9 @@ int flexran_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg) { int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { Protocol__FlexHeader *header = NULL; int i, j, UE_id; - + int available_harq[NUMBER_OF_UE_MAX]; - + const int xid = *((int *)params); @@ -859,12 +859,12 @@ int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Fle } int ahead_of_time = 0; - + frame = (frame_t) flexran_get_current_system_frame_num(mod_id); subframe = (sub_frame_t) flexran_get_current_subframe(mod_id); subframe = ((subframe + ahead_of_time) % 10); - + if (subframe < flexran_get_current_subframe(mod_id)) { frame = (frame + 1) % 1024; } @@ -887,7 +887,7 @@ int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Fle } } } - + // LOG_I(FLEXRAN_AGENT, "Sending subframe trigger for frame %d and subframe %d\n", flexran_get_current_frame(mod_id), (flexran_get_current_subframe(mod_id) + 1) % 10); @@ -920,8 +920,8 @@ int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Fle // uint8_t harq_id; //uint8_t harq_status; // flexran_get_harq(mod_id, UE_PCCID(mod_id,i), i, frame, subframe, &harq_id, &harq_status); - - + + dl_info[i]->harq_process_id = available_harq[UE_id]; if (RC.mac && RC.mac[mod_id]) RC.mac[mod_id]->UE_list.eNB_UE_stats[UE_PCCID(mod_id,i)][UE_id].harq_pid = 0; @@ -1010,7 +1010,7 @@ int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Fle for (i = 0; i < sf_trigger_msg->n_dl_info; i++) { free(sf_trigger_msg->dl_info[i]->harq_status); } - free(sf_trigger_msg->dl_info); + free(sf_trigger_msg->dl_info); free(sf_trigger_msg->ul_info); free(sf_trigger_msg); } @@ -1184,7 +1184,7 @@ int flexran_agent_mac_destroy_ul_config(Protocol__FlexranMessage *msg) { free(msg->ul_mac_config_msg->header); for (i = 0; i < msg->ul_mac_config_msg->n_ul_ue_data; i++) { // TODO uplink rlc ... - // free(msg->ul_mac_config_msg->dl_ue_data[i]->ce_bitmap); + // free(msg->ul_mac_config_msg->dl_ue_data[i]->ce_bitmap); // for (j = 0; j < msg->ul_mac_config_msg->ul_ue_data[i]->n_rlc_pdu; j++) { // for (k = 0; k < msg->ul_mac_config_msg->ul_ue_data[i]->rlc_pdu[j]->n_rlc_pdu_tb; k++) { // free(msg->ul_mac_config_msg->dl_ue_data[i]->rlc_pdu[j]->rlc_pdu_tb[k]); @@ -1202,7 +1202,7 @@ int flexran_agent_mac_destroy_ul_config(Protocol__FlexranMessage *msg) { // free(msg->ul_mac_config_msg->ul_ue_data[i]); } free(msg->ul_mac_config_msg->ul_ue_data); - + free(msg->ul_mac_config_msg); free(msg); @@ -1216,10 +1216,10 @@ int flexran_agent_mac_destroy_ul_config(Protocol__FlexranMessage *msg) { void flexran_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__FlexranMessage **msg) { struct lfds700_misc_prng_state ls; - + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; lfds700_misc_prng_init(&ls); - + if (lfds700_ringbuffer_read(&ringbuffer_state[mod_id], NULL, (void **) msg, &ls) == 0) { *msg = NULL; } @@ -1230,10 +1230,10 @@ int flexran_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Pro struct lfds700_misc_prng_state ls; enum lfds700_misc_flag overwrite_occurred_flag; Protocol__FlexranMessage *overwritten_dl_config; - + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; lfds700_misc_prng_init(&ls); - + lfds700_ringbuffer_write( &ringbuffer_state[mod_id], NULL, (void *) params, @@ -1347,7 +1347,7 @@ int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->flexran_agent_send_sf_trigger = flexran_agent_send_sf_trigger; //xface->flexran_agent_send_update_mac_stats = flexran_agent_send_update_mac_stats; xface->flexran_agent_get_pending_dl_mac_config = flexran_agent_get_pending_dl_mac_config; - + xface->dl_scheduler_loaded_lib = NULL; xface->ul_scheduler_loaded_lib = NULL; mac_agent_registered[mod_id] = 1; diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index ddb8a6942d..76b2194612 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -157,13 +157,13 @@ #define U_PLANE_INACTIVITY_VALUE 6000 -/* - * eNB part +/* + * eNB part */ -/* - * UE/ENB common part +/* + * UE/ENB common part */ /*!\brief MAC header of Random Access Response for Random access preamble identifier (RAPID) */ typedef struct { @@ -448,20 +448,20 @@ typedef struct { } eNB_DLSCH_INFO; /*! \brief eNB overall statistics */ typedef struct { - /// num BCCH PDU per CC + /// num BCCH PDU per CC uint32_t total_num_bcch_pdu; - /// BCCH buffer size + /// BCCH buffer size uint32_t bcch_buffer; - /// total BCCH buffer size + /// total BCCH buffer size uint32_t total_bcch_buffer; /// BCCH MCS uint32_t bcch_mcs; - /// num CCCH PDU per CC + /// num CCCH PDU per CC uint32_t total_num_ccch_pdu; - /// BCCH buffer size + /// BCCH buffer size uint32_t ccch_buffer; - /// total BCCH buffer size + /// total BCCH buffer size uint32_t total_ccch_buffer; /// BCCH MCS uint32_t ccch_mcs; @@ -562,13 +562,13 @@ typedef struct { uint32_t num_retransmission; /// instantaneous tx throughput for each TTI // uint32_t tti_throughput[NB_RB_MAX]; - // Number of received MAC SDU + // Number of received MAC SDU uint32_t num_mac_sdu_tx; // LCID related to SDU unsigned char lcid_sdu[NB_RB_MAX]; // Length of SDU Got from LC DL uint32_t sdu_length_tx[NB_RB_MAX]; - + /// overall // @@ -614,7 +614,7 @@ typedef struct { /// uplink transport block size uint32_t ulsch_TBS; - + uint32_t total_ulsch_TBS; /// total rb used for a new uplink transmission @@ -625,9 +625,9 @@ typedef struct { uint32_t rbs_used_retx_rx; /// total rb used for a new uplink transmission uint32_t total_rbs_used_rx; - /// normalized rx power + /// normalized rx power int32_t normalized_rx_power; - /// target rx power + /// target rx power int32_t target_rx_power; /// num rx pdu @@ -754,7 +754,7 @@ typedef struct { uint32_t dl_buffer_head_sdu_creation_time[MAX_NUM_LCID]; /// maximum creation time of the downlink buffer head across all LCID uint32_t dl_buffer_head_sdu_creation_time_max; - /// a flag indicating that the downlink head SDU is segmented + /// a flag indicating that the downlink head SDU is segmented uint8_t dl_buffer_head_sdu_is_segmented[MAX_NUM_LCID]; /// size of remaining size to send for the downlink head SDU uint32_t dl_buffer_head_sdu_remaining_size_to_send[MAX_NUM_LCID]; @@ -949,21 +949,21 @@ typedef struct { /// Dedicated information for UEs struct PhysicalConfigDedicated *physicalConfigDedicated[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - /// DLSCH pdu + /// DLSCH pdu DLSCH_PDU DLSCH_pdu[MAX_NUM_CCs][2][NUMBER_OF_UE_MAX]; /// DCI template and MAC connection parameters for UEs UE_TEMPLATE UE_template[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; /// DCI template and MAC connection for RA processes int pCC_id[NUMBER_OF_UE_MAX]; - /// sorted downlink component carrier for the scheduler + /// sorted downlink component carrier for the scheduler int ordered_CCids[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - /// number of downlink active component carrier + /// number of downlink active component carrier int numactiveCCs[NUMBER_OF_UE_MAX]; - /// sorted uplink component carrier for the scheduler + /// sorted uplink component carrier for the scheduler int ordered_ULCCids[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - /// number of uplink active component carrier + /// number of uplink active component carrier int numactiveULCCs[NUMBER_OF_UE_MAX]; - /// number of downlink active component carrier + /// number of downlink active component carrier uint8_t dl_CC_bitmap[NUMBER_OF_UE_MAX]; /// eNB to UE statistics eNB_UE_STATS eNB_UE_stats[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; @@ -1089,7 +1089,7 @@ typedef struct eNB_MAC_INST_s { nfapi_ul_config_request_t UL_req[MAX_NUM_CCs]; /// NFAPI "Temporary" UL Config Request Structure, holds future UL_config requests nfapi_ul_config_request_t UL_req_tmp[MAX_NUM_CCs][10]; - /// Preallocated HI_DCI0 pdu list + /// Preallocated HI_DCI0 pdu list nfapi_hi_dci0_request_pdu_t hi_dci0_pdu_list[MAX_NUM_CCs][MAX_NUM_HI_DCI0_PDU]; /// NFAPI HI/DCI0 Config Request Structure @@ -1112,21 +1112,21 @@ typedef struct eNB_MAC_INST_s { /// eNB stats eNB_STATS eNB_stats[MAX_NUM_CCs]; // MAC function execution peformance profiler - /// processing time of eNB scheduler + /// processing time of eNB scheduler time_stats_t eNB_scheduler; - /// processing time of eNB scheduler for SI + /// processing time of eNB scheduler for SI time_stats_t schedule_si; /// processing time of eNB scheduler for Random access time_stats_t schedule_ra; - /// processing time of eNB ULSCH scheduler + /// processing time of eNB ULSCH scheduler time_stats_t schedule_ulsch; /// processing time of eNB DCI generation time_stats_t fill_DLSCH_dci; /// processing time of eNB MAC preprocessor time_stats_t schedule_dlsch_preprocessor; - /// processing time of eNB DLSCH scheduler + /// processing time of eNB DLSCH scheduler time_stats_t schedule_dlsch; // include rlc_data_req + MAC header + preprocessor - /// processing time of eNB MCH scheduler + /// processing time of eNB MCH scheduler time_stats_t schedule_mch; /// processing time of eNB ULSCH reception time_stats_t rx_ulsch_sdu; // include rlc_data_ind @@ -1134,8 +1134,8 @@ typedef struct eNB_MAC_INST_s { time_stats_t schedule_pch; } eNB_MAC_INST; -/* - * UE part +/* + * UE part */ typedef enum { @@ -1329,24 +1329,24 @@ typedef struct { uint8_t msi_status; // could be an array if there are >1 MCH in one MBSFN area #endif //#ifdef CBA - /// CBA RNTI for each group + /// CBA RNTI for each group uint16_t cba_rnti[NUM_MAX_CBA_GROUP]; - /// last SFN for CBA channel access + /// last SFN for CBA channel access uint8_t cba_last_access[NUM_MAX_CBA_GROUP]; //#endif - /// total UE scheduler processing time + /// total UE scheduler processing time time_stats_t ue_scheduler; // total - /// UE ULSCH tx processing time inlcuding RLC interface (rlc_data_req) and mac header generation + /// UE ULSCH tx processing time inlcuding RLC interface (rlc_data_req) and mac header generation time_stats_t tx_ulsch_sdu; /// UE DLSCH rx processing time inlcuding RLC interface (mac_rrc_data_ind or mac_rlc_status_ind+mac_rlc_data_ind) and mac header parser time_stats_t rx_dlsch_sdu; - /// UE query for MCH subframe processing time + /// UE query for MCH subframe processing time time_stats_t ue_query_mch; - /// UE MCH rx processing time + /// UE MCH rx processing time time_stats_t rx_mch_sdu; - /// UE BCCH rx processing time including RLC interface (mac_rrc_data_ind) + /// UE BCCH rx processing time including RLC interface (mac_rrc_data_ind) time_stats_t rx_si; - /// UE PCCH rx processing time including RLC interface (mac_rrc_data_ind) + /// UE PCCH rx processing time including RLC interface (mac_rrc_data_ind) time_stats_t rx_p; } UE_MAC_INST; /*! \brief ID of the neighboring cells used for HO*/ diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 7e6eee0f87..aeaa55a79a 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -744,7 +744,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, } } /* if (continue_flag != 1 */ - if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated + if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated CCE_allocation_infeasible(module_idP, CC_id, 1, subframeP, aggregation, rnti)) { LOG_D(MAC, @@ -929,7 +929,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, dl_req->number_dci++; dl_req->number_pdu++; dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; - + eNB->DL_req[CC_id].sfn_sf = frameP<<4 | subframeP; eNB->DL_req[CC_id].header.message_id = NFAPI_DL_CONFIG_REQUEST; @@ -1116,7 +1116,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch); - if (TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch > 0) { // NN: > 2 ? + if (TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch > 0) { // NN: > 2 ? rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, @@ -1158,7 +1158,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid] += 1; UE_list->eNB_UE_stats[CC_id][UE_id].lcid_sdu[num_sdus] = lcid; - UE_list->eNB_UE_stats[CC_id][UE_id].sdu_length_tx[lcid] = sdu_lengths[num_sdus]; + UE_list->eNB_UE_stats[CC_id][UE_id].sdu_length_tx[lcid] = sdu_lengths[num_sdus]; UE_list-> eNB_UE_stats[CC_id][UE_id].num_bytes_tx [lcid] += sdu_lengths[num_sdus]; @@ -1180,7 +1180,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, } if (header_len_dtch == 0) header_len_dtch_last = 0; - // there is at least one SDU + // there is at least one SDU // if (num_sdus > 0 ){ if ((sdu_length_total + header_len_dcch + header_len_dtch) > 0) { @@ -1193,7 +1193,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, if (header_len_dtch == 0) { header_len_dcch = (header_len_dcch > 0) ? 1 : 0; //header_len_dcch; // remove length field } else { - header_len_dtch_last -= 1; // now use it to find how many bytes has to be removed for the last MAC SDU + header_len_dtch_last -= 1; // now use it to find how many bytes has to be removed for the last MAC SDU header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last : header_len_dtch; // remove length field for the last SDU } @@ -1413,10 +1413,10 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, tpc, tpc_accumulated, normalized_rx_power, target_rx_power); - } // Po_PUCCH has been updated + } // Po_PUCCH has been updated else { tpc = 1; //0 - } // time to do TPC update + } // time to do TPC update else { tpc = 1; //0 } @@ -1515,7 +1515,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, UE_list.DLSCH_pdu[CC_id][0][(unsigned char) UE_id].payload [0]); - + LOG_D(MAC, "Filled NFAPI configuration for DCI/DLSCH/TXREQ %d, new SDU\n", eNB->pdu_index[CC_id]); @@ -1695,9 +1695,9 @@ update_ul_dci(module_id_t module_idP, int i; - if (cc->tdd_Config != NULL) { // TDD + if (cc->tdd_Config != NULL) { // TDD for (i = 0; - i hi_dci0_request_body.number_of_dci + HI_DCI0_req->hi_dci0_request_body.number_of_dci; + i hi_dci0_request_body.number_of_dci + HI_DCI0_req->hi_dci0_request_body.number_of_dci; i++) { if ((hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) && From 365ca71a4ab9d06f56c47e22d2a9450dba715572 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 21 Feb 2018 16:16:34 +0100 Subject: [PATCH 266/284] remove compilation warnings --- openair1/PHY/INIT/lte_param_init.c | 1 + openair1/PHY/LTE_TRANSPORT/dci.c | 12 +++---- .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 2 +- openair1/PHY/TOOLS/lte_dfts.c | 4 +++ openair1/PHY/TOOLS/lte_phy_scope.c | 2 +- openair1/SCHED/phy_procedures_lte_eNb.c | 4 +-- openair1/SCHED/prach_procedures.c | 2 ++ .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 1 + openair2/ENB_APP/enb_paramdef.h | 4 --- openair2/LAYER2/MAC/pre_processor.c | 5 +++ openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 10 +++--- openair2/RRC/LITE/L2_interface_ue.c | 14 +------- openair2/RRC/LITE/proto.h | 11 ++++++ openair2/RRC/LITE/rrc_UE.c | 4 --- openair2/RRC/LITE/rrc_eNB.c | 3 +- targets/RT/USER/lte-ru.c | 6 +++- targets/SIMU/USER/channel_sim.c | 1 + targets/SIMU/USER/event_handler.c | 8 ++--- targets/SIMU/USER/oaisim.c | 35 ++++++++++--------- targets/SIMU/USER/oaisim_functions.c | 23 ++++++------ 20 files changed, 82 insertions(+), 70 deletions(-) diff --git a/openair1/PHY/INIT/lte_param_init.c b/openair1/PHY/INIT/lte_param_init.c index 1743a8d90c..6cf05769e5 100644 --- a/openair1/PHY/INIT/lte_param_init.c +++ b/openair1/PHY/INIT/lte_param_init.c @@ -33,6 +33,7 @@ extern PHY_VARS_eNB *eNB; extern PHY_VARS_UE *UE; extern RU_t *ru; +extern void phy_init_RU(RU_t*); void lte_param_init(PHY_VARS_eNB **eNBp, PHY_VARS_UE **UEp, diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index 94d6cd9c3f..ded49d1c73 100755 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -1874,12 +1874,6 @@ int32_t rx_pdcch(PHY_VARS_UE *ue, #endif //MU_RECEIVER -#if T_TRACER - T(T_UE_PHY_PDCCH_IQ, T_INT(frame_parms->N_RB_DL), T_INT(frame_parms->N_RB_DL), - T_INT(n_pdcch_symbols), - T_BUFFER(pdcch_vars[eNB_id]->rxdataF_comp, frame_parms->N_RB_DL*12*n_pdcch_symbols* 4)); -#endif - // decode pcfich here and find out pdcch ofdm symbol number n_pdcch_symbols = rx_pcfich(frame_parms, subframe, @@ -1890,6 +1884,12 @@ int32_t rx_pdcch(PHY_VARS_UE *ue, if (n_pdcch_symbols>3) n_pdcch_symbols=1; +#if T_TRACER + T(T_UE_PHY_PDCCH_IQ, T_INT(frame_parms->N_RB_DL), T_INT(frame_parms->N_RB_DL), + T_INT(n_pdcch_symbols), + T_BUFFER(pdcch_vars[eNB_id]->rxdataF_comp, frame_parms->N_RB_DL*12*n_pdcch_symbols* 4)); +#endif + #ifdef DEBUG_DCI_DECODING diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index 1becc98752..6284f279d8 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -843,7 +843,7 @@ int rx_pdsch(PHY_VARS_UE *ue, pllr_symbol_cw0 += llr_offset_symbol; pllr_symbol_cw1 += llr_offset_symbol; - LOG_I(PHY,"compute LLRs [AbsSubframe %d.%d-%d] NbRB %d Qm %d LLRs-Length %d LLR-Offset %d @LLR Buff %x @LLR Buff(symb) %x\n", + LOG_I(PHY,"compute LLRs [AbsSubframe %d.%d-%d] NbRB %d Qm %d LLRs-Length %d LLR-Offset %d @LLR Buff %p @LLR Buff(symb) %p\n", frame, subframe,symbol, nb_rb,dlsch0_harq->Qm, pdsch_vars[eNB_id]->llr_length[symbol], diff --git a/openair1/PHY/TOOLS/lte_dfts.c b/openair1/PHY/TOOLS/lte_dfts.c index e0e171f6bf..47b39ea7d2 100644 --- a/openair1/PHY/TOOLS/lte_dfts.c +++ b/openair1/PHY/TOOLS/lte_dfts.c @@ -2047,6 +2047,8 @@ const static int16_t tw16c[24] __attribute__((aligned(32))) = { 0,32767,12540,30 0,32767,30273,12539,23170,-23170,-12539,-30273 }; +#ifdef __AVX2__ + const static int16_t tw16rep[48] __attribute__((aligned(32))) = { 32767,0,30272,-12540,23169 ,-23170,12539 ,-30273,32767,0,30272,-12540,23169 ,-23170,12539 ,-30273, 32767,0,23169,-23170,0 ,-32767,-23170,-23170,32767,0,23169,-23170,0 ,-32767,-23170,-23170, 32767,0,12539,-30273,-23170,-23170,-30273,12539,32767,0,12539,-30273,-23170,-23170,-30273,12539 @@ -2067,6 +2069,8 @@ const static int16_t tw16crep[48] __attribute__((aligned(32))) = { 0,32767,12540 0,32767,30273,12539,23170,-23170,-12539,-30273,0,32767,30273,12539,23170,-23170,-12539,-30273 }; +#endif /* __AVX2__ */ + static inline void dft16(int16_t *x,int16_t *y) __attribute__((always_inline)); diff --git a/openair1/PHY/TOOLS/lte_phy_scope.c b/openair1/PHY/TOOLS/lte_phy_scope.c index 30e57c1c62..1b6c1c9153 100644 --- a/openair1/PHY/TOOLS/lte_phy_scope.c +++ b/openair1/PHY/TOOLS/lte_phy_scope.c @@ -200,7 +200,7 @@ void phy_scope_eNB(FD_lte_phy_scope_enb *form, chest_t = (int16_t**) phy_vars_enb->srs_vars[UE_id].srs_ch_estimates[eNB_id]; chest_f = (int16_t**) phy_vars_enb->pusch_vars[UE_id]->drs_ch_estimates[eNB_id]; pusch_llr = (int16_t*) phy_vars_enb->pusch_vars[UE_id]->llr; - pusch_comp = (int16_t*) phy_vars_enb->pusch_vars[UE_id]->rxdataF_comp[eNB_id][0]; + pusch_comp = (int16_t*) phy_vars_enb->pusch_vars[UE_id]->rxdataF_comp[0]; pucch1_comp = (int32_t*) phy_vars_enb->pucch1_stats[UE_id]; pucch1_thres = (int32_t*) phy_vars_enb->pucch1_stats_thres[UE_id]; pucch1ab_comp = (int32_t*) phy_vars_enb->pucch1ab_stats[UE_id]; diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 105dac0808..912e756f76 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -897,7 +897,7 @@ void uci_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) harq_ack[0] = 4; // DTX harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 6; // NACK/DTX - + max_metric = 0; } else { @@ -980,7 +980,7 @@ void uci_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 6; // NACK/DTX harq_ack[3] = 6; // NACK/DTX - + max_metric = 0; } else { max_metric = max(metric[0],max(metric[1],max(metric[2],metric[3]))); diff --git a/openair1/SCHED/prach_procedures.c b/openair1/SCHED/prach_procedures.c index f3b5644b92..79af3c128e 100644 --- a/openair1/SCHED/prach_procedures.c +++ b/openair1/SCHED/prach_procedures.c @@ -52,6 +52,8 @@ extern uint32_t nfapi_mode; +extern int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind); + void prach_procedures(PHY_VARS_eNB *eNB #ifdef Rel14 , diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 31b0f2fe75..7486594d4d 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -40,6 +40,7 @@ #include "log.h" +extern int flexran_get_harq_round(mid_t mod_id, uint8_t cc_id, mid_t ue_id); /*Flags showing if a mac agent has already been registered*/ unsigned int mac_agent_registered[NUM_MAX_ENB]; diff --git a/openair2/ENB_APP/enb_paramdef.h b/openair2/ENB_APP/enb_paramdef.h index 2d65e09b58..1a9019b794 100755 --- a/openair2/ENB_APP/enb_paramdef.h +++ b/openair2/ENB_APP/enb_paramdef.h @@ -175,10 +175,6 @@ typedef enum { -static int DEFBANDS[] = {7}; -static int DEFENBS[] = {0}; - - /*-----------------------------------------------------------------------------------------------------------------------------------------*/ /* RU configuration parameters */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 148ea344e5..e7458c347f 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -1609,6 +1609,10 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, } } +#if 0 + /* this logging is wrong, ue_sched_ctl may not be valid here + * TODO: fix + */ for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { if (total_allocated_rbs[CC_id] > 0) { @@ -1617,6 +1621,7 @@ ulsch_scheduler_pre_processor(module_id_t module_idP, ue_sched_ctl->max_rbs_allowed_slice_uplink[CC_id][slice_id] - first_rb[CC_id]); } } +#endif } diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index e9d2188bfb..05855a14bd 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -769,15 +769,15 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const ctxt_pP) void pdcp_fifo_read_input_sdus_from_otg (const protocol_ctxt_t* const ctxt_pP) { - unsigned char *otg_pkt=NULL; + //unsigned char *otg_pkt=NULL; module_id_t dst_id; // dst for otg - rb_id_t rb_id; - unsigned int pkt_size=0; + //rb_id_t rb_id; + //unsigned int pkt_size=0; protocol_ctxt_t ctxt; // we need to add conditions to avoid transmitting data when the UE is not RRC connected. if ((otg_enabled==1) && (ctxt_pP->enb_flag == ENB_FLAG_YES)) { // generate DL traffic - unsigned int ctime=0; - ctime = ctxt_pP->frame * 100; + //unsigned int ctime=0; + //ctime = ctxt_pP->frame * 100; /*if ((mac_get_rrc_status(eNB_index, ctxt_pP->enb_flag, 0 ) > 2) && (mac_get_rrc_status(eNB_index, ctxt_pP->enb_flag, 1 ) > 2)) { */ diff --git a/openair2/RRC/LITE/L2_interface_ue.c b/openair2/RRC/LITE/L2_interface_ue.c index 7bdbe2523e..3a2aeea451 100644 --- a/openair2/RRC/LITE/L2_interface_ue.c +++ b/openair2/RRC/LITE/L2_interface_ue.c @@ -65,26 +65,14 @@ mac_rrc_data_req_ue( ) //-------------------------------------------------------------------------- { - asn_enc_rval_t enc_rval; - SRB_INFO *Srb_info; - uint8_t Sdu_size = 0; - uint8_t sfn = (uint8_t)((frameP>>2)&0xff); - - #ifdef DEBUG_RRC int i; LOG_I(RRC,"[eNB %d] mac_rrc_data_req to SRB ID=%d\n",Mod_idP,Srb_id); #endif - eNB_RRC_INST *rrc; - rrc_eNB_carrier_data_t *carrier; - BCCH_BCH_Message_t *mib; - - LOG_D(RRC,"[UE %d] Frame %d Filling CCCH SRB_ID %d\n",Mod_idP,frameP,Srb_id); LOG_D(RRC,"[UE %d] Frame %d buffer_pP status %d,\n",Mod_idP,frameP, UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size); - if( (UE_rrc_inst[Mod_idP].Srb0[eNB_index].Tx_buffer.payload_size > 0) ) { #if defined(ENABLE_ITTI) @@ -139,7 +127,6 @@ mac_rrc_data_ind_ue( ) //-------------------------------------------------------------------------- { - SRB_INFO *Srb_info; protocol_ctxt_t ctxt; sdu_size_t sdu_size = 0; @@ -214,6 +201,7 @@ mac_rrc_data_ind_ue( itti_send_msg_to_task (TASK_RRC_UE, ctxt.instance, message_p); } #else + SRB_INFO *Srb_info; Srb_info = &UE_rrc_inst[module_idP].Srb0[eNB_indexP]; memcpy(Srb_info->Rx_buffer.Payload,sduP,sdu_lenP); Srb_info->Rx_buffer.payload_size = sdu_lenP; diff --git a/openair2/RRC/LITE/proto.h b/openair2/RRC/LITE/proto.h index 9ece5bcfdd..49cf9f2eba 100644 --- a/openair2/RRC/LITE/proto.h +++ b/openair2/RRC/LITE/proto.h @@ -409,6 +409,17 @@ rrc_data_req( const pdcp_transmission_mode_t modeP ); +uint8_t +rrc_data_req_ue( + const protocol_ctxt_t* const ctxt_pP, + const rb_id_t rb_idP, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_sizeP, + uint8_t* const buffer_pP, + const pdcp_transmission_mode_t modeP +); + void rrc_data_ind( const protocol_ctxt_t* const ctxt_pP, diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index 8d1f47daf5..121d115398 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -241,7 +241,6 @@ openair_rrc_on_ue( //----------------------------------------------------------------------------- { unsigned short i; - int CC_id; LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" UE?:OPENAIR RRC IN....\n", PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); @@ -4843,9 +4842,6 @@ rrc_rx_tx_ue( //----------------------------------------------------------------------------- { //uint8_t UE_id; - int32_t current_timestamp_ms, ref_timestamp_ms; - struct timeval ts; - struct rrc_eNB_ue_context_s *ue_context_p = NULL,*ue_to_be_removed = NULL; #ifdef LOCALIZATION double estimated_distance; diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 2a8967a531..9faa686ef6 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -118,7 +118,6 @@ openair_rrc_on( ) //----------------------------------------------------------------------------- { - unsigned short i; int CC_id; LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" ENB:OPENAIR RRC IN....\n", @@ -1232,7 +1231,7 @@ rrc_eNB_generate_RRCConnectionReestablishment( void rrc_eNB_process_RRCConnectionReestablishmentComplete( const protocol_ctxt_t* const ctxt_pP, - const rnti_t const reestablish_rnti, + const rnti_t reestablish_rnti, rrc_eNB_ue_context_t* ue_context_pP, const uint8_t xid, RRCConnectionReestablishmentComplete_r8_IEs_t * rrcConnectionReestablishmentComplete diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 06aad94d30..d909da627f 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -95,6 +95,10 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "enb_config.h" //#include "PHY/TOOLS/time_meas.h" +/* these variables have to be defined before including ENB_APP/enb_paramdef.h */ +static int DEFBANDS[] = {7}; +static int DEFENBS[] = {0}; + #include "ENB_APP/enb_paramdef.h" #include "common/config/config_userapi.h" @@ -1883,7 +1887,6 @@ void configure_ru(int idx, RRU_config_t *config = (RRU_config_t *)arg; RRU_capabilities_t *capabilities = (RRU_capabilities_t*)arg; int ret; - int i; LOG_I(PHY, "Received capabilities from RRU %d\n",idx); @@ -1918,6 +1921,7 @@ void configure_ru(int idx, config->prach_FreqOffset[0],config->prach_ConfigIndex[0]); #ifdef Rel14 + int i; for (i=0;i<4;i++) { config->emtc_prach_CElevel_enable[0][i] = ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i]; config->emtc_prach_FreqOffset[0][i] = ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[i]; diff --git a/targets/SIMU/USER/channel_sim.c b/targets/SIMU/USER/channel_sim.c index e2420a1c77..94bd1bbe43 100644 --- a/targets/SIMU/USER/channel_sim.c +++ b/targets/SIMU/USER/channel_sim.c @@ -140,6 +140,7 @@ void do_DL_sig(channel_desc_t *RU2UE[NUMBER_OF_RU_MAX][NUMBER_OF_UE_MAX][MAX_NUM if (!hold_channel) { // calculate the random channel from each RU for (ru_id=0; ru_idframe_parms; random_channel(RU2UE[ru_id][UE_id][CC_id],abstraction_flag); /* diff --git a/targets/SIMU/USER/event_handler.c b/targets/SIMU/USER/event_handler.c index dbdce23df2..e840bde57b 100644 --- a/targets/SIMU/USER/event_handler.c +++ b/targets/SIMU/USER/event_handler.c @@ -685,8 +685,8 @@ void update_mac(Event_t event) LOG_I(EMU,"%" PRIu8 "\n",UE_list->UE_sched_ctrl[event.ue].priority[event.lcid]); } } else if(!strcmp((char *) event.key, "DCI_aggregation_min") && event.value!=NULL && validate_mac(event)) { - Mac_config* mac_config;// = malloc(sizeof(Mac_config)*16); - mac_config = (Mac_config *) event.value; + //Mac_config* mac_config;// = malloc(sizeof(Mac_config)*16); + //mac_config = (Mac_config *) event.value; LOG_I(EMU,"DCI_aggregation_min update \n"); @@ -706,8 +706,8 @@ void update_mac(Event_t event) LOG_I(EMU,"%" PRIu8 "\n",UE_list->UE_template[0][event.ue].DCI_aggregation_min);*/ } } else if(!strcmp((char *) event.key, "DLSCH_dci_size_bits") && event.value!=NULL && validate_mac(event)) { - Mac_config* mac_config;// = malloc(sizeof(Mac_config)*16); - mac_config = (Mac_config *) event.value; + //Mac_config* mac_config;// = malloc(sizeof(Mac_config)*16); + //mac_config = (Mac_config *) event.value; LOG_I(EMU,"DLSCH_dci_size_bits update \n"); diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index b23755c3c1..0008ba3bbd 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -216,7 +216,8 @@ oai_shutdown (void); void reset_opp_meas_oaisim (void); -void wait_eNBs() { +void wait_eNBs(void) +{ return; } @@ -364,7 +365,7 @@ static void set_cli_start(module_id_t module_idP, uint8_t start) #ifdef OPENAIR2 int omv_write(int pfd, node_list* enb_node_list, node_list* ue_node_list, Data_Flow_Unit omv_data) { - module_id_t i, j; + module_id_t i; omv_data.end = 0; //omv_data.total_num_nodes = NB_UE_INST + NB_eNB_INST; @@ -495,7 +496,7 @@ l2l1_task (void *args_p) #undef PRINT_STATS /* this undef is to avoid gcc warnings */ #define PRINT_STATS #ifdef PRINT_STATS - int len; + //int len; FILE *UE_stats[NUMBER_OF_UE_MAX]; FILE *UE_stats_th[NUMBER_OF_UE_MAX]; FILE *eNB_stats[NUMBER_OF_eNB_MAX]; @@ -621,7 +622,6 @@ l2l1_task (void *args_p) } #endif - module_id_t enb_id; module_id_t UE_id; if (abstraction_flag == 1) { @@ -769,11 +769,11 @@ l2l1_task (void *args_p) */ for (ru_id=0;ru_idframe_parms.samples_per_tti; - LOG_D(EMU,"RU %d/%d: TS %llu\n",ru_id,CC_id,current_ru_rx_timestamp[ru_id][CC_id]); + LOG_D(EMU,"RU %d/%d: TS %"PRIi64"\n",ru_id,CC_id,current_ru_rx_timestamp[ru_id][CC_id]); } for (UE_inst = 0; UE_instframe_parms.samples_per_tti; - LOG_D(EMU,"UE %d/%d: TS %llu\n",UE_id,CC_id,current_UE_rx_timestamp[UE_inst][CC_id]); + LOG_D(EMU,"UE %d/%d: TS %"PRIi64"\n",UE_inst,CC_id,current_UE_rx_timestamp[UE_inst][CC_id]); } for (eNB_inst = oai_emulation.info.first_enb_local; @@ -1013,8 +1013,8 @@ int T_dont_fork = 0; /* default is to fork, see 'T_init' to understand */ #endif -void wait_RUs() { - +void wait_RUs(void) +{ int i; // wait for all RUs to be configured over fronthaul @@ -1084,9 +1084,9 @@ static void print_current_directory(void) printf("working directory: %s\n", dir); } -/*------------------------------------------------------------------------------*/ -int -main (int argc, char **argv) +void init_devices(void); + +int main (int argc, char **argv) { clock_t t; @@ -1104,7 +1104,6 @@ main (int argc, char **argv) int node_id; int port,Process_Flag=0,wgt,Channel_Flag=0,temp; #endif - int i; //default parameters oai_emulation.info.n_frames = MAX_FRAME_NUMBER; //1024; //10; @@ -1472,8 +1471,10 @@ print_opp_meas_oaisim (void) &oaisim_stats, &oaisim_stats_f); - print_meas (&PHY_vars_UE_g[UE_id][0]->phy_proc_rx, - "[UE][total_phy_proc_rx]", &oaisim_stats, &oaisim_stats_f); + print_meas (&PHY_vars_UE_g[UE_id][0]->phy_proc_rx[0], + "[UE][total_phy_proc_rx[0]]", &oaisim_stats, &oaisim_stats_f); + print_meas (&PHY_vars_UE_g[UE_id][0]->phy_proc_rx[1], + "[UE][total_phy_proc_rx[1]]", &oaisim_stats, &oaisim_stats_f); // print_meas (&PHY_vars_UE_g[UE_id][0]->ofdm_demod_stats, // "[UE][ofdm_demod]", &oaisim_stats, &oaisim_stats_f); print_meas (&PHY_vars_UE_g[UE_id][0]->rx_dft_stats, "[UE][rx_dft]", @@ -1844,8 +1845,8 @@ get_OAI_emulation () // dummy function declarations -void *rrc_enb_task(void *args_p) { - - +void *rrc_enb_task(void *args_p) +{ + return NULL; } diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index be8f66fb93..ceaae1958b 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -868,7 +868,7 @@ void check_and_adjust_params(void) { int32_t ret; - int i,j; + //int i,j; if (oai_emulation.info.nb_ue_local + oai_emulation.info.nb_rn_local > NUMBER_OF_UE_MAX) { LOG_E(EMU,"Enter fewer than %d UEs/RNs for the moment or change the NUMBER_OF_UE_MAX\n", NUMBER_OF_UE_MAX); @@ -1081,7 +1081,7 @@ int ru_trx_read(openair0_device *device, openair0_timestamp *ptimestamp, void ** while (sample_countframe_parms, UE_id, CC_id); - LOG_D(EMU,"UE %d: DL simulation 6: UE_trx_read @ TS %llu (%llu)=> frame %d, subframe %d\n", - UE_id,(unsigned long long)current_UE_rx_timestamp[UE_id][CC_id], - (unsigned long long)last_UE_rx_timestamp[UE_id][CC_id], - ((unsigned long long)last_UE_rx_timestamp[UE_id][CC_id]/(sptti*10))&1023, + LOG_D(EMU,"UE %d: DL simulation 6: UE_trx_read @ TS %"PRIi64" (%"PRIi64")=> frame %d, subframe %d\n", + UE_id, current_UE_rx_timestamp[UE_id][CC_id], + last_UE_rx_timestamp[UE_id][CC_id], + (int)((last_UE_rx_timestamp[UE_id][CC_id]/(sptti*10))&1023), subframe); last_UE_rx_timestamp[UE_id][CC_id] += read_size; @@ -1367,9 +1367,11 @@ void init_ocm(void) /* Added for PHY abstraction */ - char* frame_type = "unknown"; + /* TODO: frame_type is unused, is it intended? */ + //char* frame_type = "unknown"; LTE_DL_FRAME_PARMS *fp = &RC.ru[0]->frame_parms; +#if 0 switch (fp->frame_type) { case FDD: frame_type = "FDD"; @@ -1379,6 +1381,7 @@ void init_ocm(void) frame_type = "TDD"; break; } +#endif if (abstraction_flag) { From b23a8ad0fe44e4de56373e2af104a68dc41c8aed Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 22 Feb 2018 12:47:23 +0100 Subject: [PATCH 267/284] integation fix: minor typo --- openair2/LAYER2/MAC/defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 76b2194612..e3f5d954f1 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -1097,7 +1097,7 @@ typedef struct eNB_MAC_INST_s { /// Prealocated TX pdu list nfapi_tx_request_pdu_t tx_request_pdu[MAX_NUM_CCs][MAX_NUM_TX_REQUEST_PDU]; - /// NFAPI DL PDU structuree + /// NFAPI DL PDU structure nfapi_tx_request_t TX_req[MAX_NUM_CCs]; /// UL handle uint32_t ul_handle; From 37425ee9673675d3c617f5b4126d8a21032e2985 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 22 Feb 2018 11:54:16 +0100 Subject: [PATCH 268/284] bugfix: revert bad change Without this revert, the following does not compile: ./build_oai --oaisim --- openair2/LAYER2/openair2_proc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openair2/LAYER2/openair2_proc.c b/openair2/LAYER2/openair2_proc.c index 7cb6ce0d2c..f66d1142ab 100644 --- a/openair2/LAYER2/openair2_proc.c +++ b/openair2/LAYER2/openair2_proc.c @@ -228,9 +228,7 @@ int dump_eNB_l2_stats(char *buffer, int length) PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, eNB_id, ENB_FLAG_YES, - /* the following is suspicious, let's put back what was there before */ - /*UE_list->eNB_UE_stats[0][UE_id].crnti,//UE_PCCID(eNB_id,UE_id)][UE_id].crnti, */ - UE_list->eNB_UE_stats[UE_PCCID(eNB_id,UE_id)][UE_id].crnti, + UE_list->eNB_UE_stats[0][UE_id].crnti,//UE_PCCID(eNB_id,UE_id)][UE_id].crnti, eNB->frame, eNB->subframe, eNB_id); From dc0638d7f626fbfae1f9b1f40b89c0007ecc1a20 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 22 Feb 2018 16:45:18 +0100 Subject: [PATCH 269/284] added compilation directives for nasmesh and ue_ip kernel modules to allow for building on RHEL systems. --- openair2/NETWORK_DRIVER/MESH/device.c | 4 ++-- openair2/NETWORK_DRIVER/UE_IP/device.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openair2/NETWORK_DRIVER/MESH/device.c b/openair2/NETWORK_DRIVER/MESH/device.c index 086ec3909c..f8a420697a 100644 --- a/openair2/NETWORK_DRIVER/MESH/device.c +++ b/openair2/NETWORK_DRIVER/MESH/device.c @@ -241,7 +241,7 @@ int nas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) // End debug information netif_stop_queue(dev); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) || RHEL_RELEASE_CODE>=1796 netif_trans_update(dev); #else dev->trans_start = jiffies; @@ -306,7 +306,7 @@ void nas_tx_timeout(struct net_device *dev) printk("TX_TIMEOUT: begin\n"); // (struct nas_priv *)(dev->priv)->stats.tx_errors++; (priv->stats).tx_errors++; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) || RHEL_RELEASE_CODE>=1796 netif_trans_update(dev); #else dev->trans_start = jiffies; diff --git a/openair2/NETWORK_DRIVER/UE_IP/device.c b/openair2/NETWORK_DRIVER/UE_IP/device.c index 29db4ae07a..36c6afe914 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/device.c +++ b/openair2/NETWORK_DRIVER/UE_IP/device.c @@ -236,7 +236,7 @@ int ue_ip_hard_start_xmit(struct sk_buff *skb_pP, struct net_device *dev_pP) // End debug information netif_stop_queue(dev_pP); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) || RHEL_RELEASE_CODE >= 1796 netif_trans_update(dev_pP); #else dev_pP->trans_start = jiffies; @@ -312,7 +312,7 @@ void ue_ip_tx_timeout(struct net_device *dev_pP) printk("[UE_IP_DRV][%s] begin\n", __FUNCTION__); // (ue_ip_priv_t *)(dev_pP->priv_p)->stats.tx_errors++; (priv_p->stats).tx_errors++; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) || RHEL_RELEASE_CODE >= 1796 netif_trans_update(dev_pP); #else dev_pP->trans_start = jiffies; From 7d8d1588c31e12410ac08cd420dd23b8c4035203 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 1 Mar 2018 09:04:41 +0100 Subject: [PATCH 270/284] remove unnecessary function declaration has been introduced in commit 365ca71a4ab9d06f56c47e22d2a9450dba715572 --- openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 7486594d4d..0997f2b435 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -40,8 +40,6 @@ #include "log.h" -extern int flexran_get_harq_round(mid_t mod_id, uint8_t cc_id, mid_t ue_id); - /*Flags showing if a mac agent has already been registered*/ unsigned int mac_agent_registered[NUM_MAX_ENB]; From 26d68e9c5e624c3719f9d86f1ba8a9f5739c832f Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 2 Mar 2018 12:02:06 +0100 Subject: [PATCH 271/284] hotfix: fix bad RLC UM packet creation Running TCP DL traffic with one connected UE showed a lot of fluctuations in throughput. After analysis it was found that sometimes the RLC UM PDU was not correct. It contained one byte more than it should. On the receiver side, the TCP packet contained in the RLC packet seems to be rejected by the TCP stack of the UE (it has one byte more than it should), leading to a brutal reduction of the throughput, probably due to some congestion detection in the TCP implementation. Or something. This hotfix seems to solve the problem. Using iperf in downlink with a 5MHz eNB, we see no more fluctuations, the traffic is very steady at 16.8Mb/s, as reported by the iperf server running on the phone. (17.5 in the PHY plot of the T tracer.) A rewrite of both the MAC and RLC UM packet generation is needed. The code is way too complex for what it does and may contain several similar problems that only trigger in specific rare conditions. --- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c index f9af7c1cc2..98a44ceeeb 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c @@ -172,7 +172,7 @@ rlc_um_segment_10 (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t *rlc_pP test_pdu_remaining_size = 0; test_remaining_size_to_substract = 0; test_remaining_num_li_to_substract = 0; - pdu_remaining_size = pdu_remaining_size - (test_li_length_in_bytes ^ 3); + //pdu_remaining_size = pdu_remaining_size - (test_li_length_in_bytes ^ 3); } else if ((sdu_mngt_p->sdu_remaining_size + (test_li_length_in_bytes ^ 3)) < test_pdu_remaining_size ) { test_num_li += 1; num_fill_sdu += 1; @@ -365,9 +365,9 @@ rlc_um_segment_10 (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t *rlc_pP sdu_mngt_p->sdu_remaining_size, pdu_remaining_size - sdu_mngt_p->sdu_remaining_size); #endif -#if !EXMIMO - assert(1!=1); -#endif +//#if !EXMIMO +// assert(1!=1); +//#endif memcpy(data, data_sdu_p, sdu_mngt_p->sdu_remaining_size); // reduce the size of the PDU continue_fill_pdu_with_sdu = 0; From 8cace6537e6c66a6608c970fd3117b43ead2da7b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Mar 2018 14:51:37 +0100 Subject: [PATCH 272/284] correctly check for MAC presence in FlexRAN RAN API --- openair2/ENB_APP/flexran_agent_ran_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 61757d0703..a65d352392 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -131,7 +131,7 @@ int8_t flexran_get_ue_phr(mid_t mod_id, mid_t ue_id) uint8_t flexran_get_ue_wcqi(mid_t mod_id, mid_t ue_id) { - if (!phy_is_present(mod_id, 0)) return 0; + if (!mac_is_present(mod_id)) return 0; return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].dl_cqi[0]; } From 4924b18ebd2e76aa09f1a9f6f2d6692df2dfec56 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Mar 2018 14:52:12 +0100 Subject: [PATCH 273/284] FlexRAN: send RNTI in protobuf mac_stats_reply message --- openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 0997f2b435..6cb79efb11 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -70,7 +70,8 @@ int flexran_agent_mac_stats_reply(mid_t mod_id, for (i = 0; i < report_config->nr_ue; i++) { - + ue_report[i]->rnti = report_config->ue_report_type[i].ue_rnti; + ue_report[i]->has_rnti = 1; /* Check flag for creation of buffer status report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_BSR) { From bcaabe513f68a720b6692abd7566b9dbbf91aa34 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Tue, 6 Mar 2018 23:32:51 +0100 Subject: [PATCH 274/284] bugfix on access of avgU array --- openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c index ee038508d1..4b2e81c499 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c @@ -1127,7 +1127,7 @@ void rx_ulsch(PHY_VARS_eNB *eNB, uint32_t l,i; int32_t avgs; uint8_t log2_maxh=0,aarx; - int32_t avgU[2]; + int32_t avgU[eNB->frame_parms.nb_antennas_rx]; // uint8_t harq_pid = ( ulsch->RRCConnRequest_flag== 0) ? subframe2harq_pid_tdd(frame_parms->tdd_config,subframe) : 0; @@ -1212,7 +1212,7 @@ void rx_ulsch(PHY_VARS_eNB *eNB, avgs = 0; for (aarx=0; aarxnb_antennas_rx; aarx++) - avgs = cmax(avgs,avgU[(aarx<<1)]); + avgs = cmax(avgs,avgU[aarx]); // log2_maxh = 4+(log2_approx(avgs)/2); From 957cdbab480eb8126eaa2a1c410e5575c25964b4 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Wed, 7 Mar 2018 01:26:04 +0100 Subject: [PATCH 275/284] fixes bug in ulsim for 2 antenna RX. --- openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c | 2 +- openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c | 2 +- openair1/PHY/MODULATION/slot_fep_ul.c | 2 ++ openair1/SIMULATION/LTE_PHY/ulsim.c | 6 +++--- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c index 9c91d28ade..9ef23f23d0 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c @@ -291,7 +291,7 @@ int32_t temp_in_ifft_0[2048*2] __attribute__((aligned(32))); #ifdef DEBUG_CH - if (aa==0) { + if (aa==1) { if (Ns == 0) { write_output("rxdataF_ext.m","rxF_ext",&rxdataF_ext[aa][symbol_offset],512*2,2,1); write_output("tmpin_ifft.m","drs_in",temp_in_ifft_0,512,1,1); diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c index 4b2e81c499..920d8ff3fd 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_demodulation.c @@ -1395,7 +1395,7 @@ void rx_ulsch_emul(PHY_VARS_eNB *eNB, if (eNB->frame_parms.nb_antennas_rx>1) { sprintf(fname,"/tmp/rxsigF1_ext_r%d.m",round); sprintf(vname,"rxsF1_ext_r%d",round); - write_output(fname,vname,&eNB->pusch_vars[UE_id]->rxdataF_ext[0][0],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); + write_output(fname,vname,&eNB->pusch_vars[UE_id]->rxdataF_ext[1][0],eNB->frame_parms.N_RB_UL*12*nsymb,1,1); } /* if (eNB->srs_vars[UE_id].srs_ch_estimates) write_output("/tmp/srs_est0.m","srsest0",eNB->srs_vars[UE_id].srs_ch_estimates[0],eNB->frame_parms.ofdm_symbol_size,1,1); diff --git a/openair1/PHY/MODULATION/slot_fep_ul.c b/openair1/PHY/MODULATION/slot_fep_ul.c index f41fc98791..5beb7eccfd 100644 --- a/openair1/PHY/MODULATION/slot_fep_ul.c +++ b/openair1/PHY/MODULATION/slot_fep_ul.c @@ -24,6 +24,8 @@ #include "defs.h" //#define DEBUG_FEP + + int slot_fep_ul(RU_t *ru, unsigned char l, unsigned char Ns, diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index d6009bc793..fc782be07a 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -859,8 +859,8 @@ int main(int argc, char **argv) printf("PUSCH Beta : ACK %f, RI %f, CQI %f\n",(double)beta_ack[beta_ACK]/8,(double)beta_ri[beta_RI]/8,(double)beta_cqi[beta_CQI]/8); - UE2eNB = new_channel_desc_scm(eNB->frame_parms.nb_antennas_tx, - UE->frame_parms.nb_antennas_rx, + UE2eNB = new_channel_desc_scm(1, + n_rx, channel_model, N_RB2sampling_rate(eNB->frame_parms.N_RB_UL), N_RB2channel_bandwidth(eNB->frame_parms.N_RB_UL), @@ -1330,7 +1330,7 @@ int main(int argc, char **argv) printf("SNRmeas %f\n",SNRmeas); write_output("rxsig0UL.m","rxs0", &ru->common.rxdata[0][eNB->frame_parms.samples_per_tti*subframe],eNB->frame_parms.samples_per_tti,1,1); - // write_output("rxsig1UL.m","rxs1", &ru->common_vars.rxdata[0][eNB->frame_parms.samples_per_tti*subframe],eNB->frame_parms.samples_per_tti,1,1); + if (eNB->frame_parms.nb_antennas_rx>1) write_output("rxsig1UL.m","rxs1", &ru->common.rxdata[1][eNB->frame_parms.samples_per_tti*subframe],eNB->frame_parms.samples_per_tti,1,1); } From 1a8d81ba57e04532094330d32eddace546068ec4 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 7 Mar 2018 16:11:36 +0100 Subject: [PATCH 276/284] cleanup MAC PDU generation (plus some general cleanup) The code was very unclear and potentially buggy. This new version is more robust. We can waste up to 2 bytes because the last header in the MAC PDU does not contain a length field and when we request data from RLC we suppose a 3-bytes MAC header. This might be optimized at some point, but the benefit would be low. This commit also contains some general cleanup: - formatting - variables' types: let's use 'int' instead of trying to be clever by using small types that may generate bugs if the value is too big - remove 'tpc_accumulated' which was globally used for all UEs and has no purpose other than logging. We may want to rework a bit the TPC machinery at some point. As the code is today we may repeatedly send TPC over and over without caring about the 3GPP limits, in which case no one knows how the UE is supposed to behave: does it clamp the current max value or does it accumulate over and over and take the clamped value to compute its actual power? If we send a reverse TPC (reduce power instead of increase) does it do it immediately or does it have to decrease n+1 times if we previously ordered it to increase n times?) We do not address the problem of prioritizing LCIDs. As of today there is only one dedicated traffic channel (DTCH), so it's not a problem at this point. What has been tested: - monolithic eNB 5/10/20MHz with one cots UE, TCP/UDP UL/DL. At 20MHz the machine used was not capable of keeping up, generating lots of Us and Ls when the throughput reaches 60Mb/s. USRP B210 was used. --- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 273 +++++++++------------- openair2/LAYER2/MAC/proto.h | 18 +- 2 files changed, 125 insertions(+), 166 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index aeaa55a79a..0729073eba 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -154,7 +154,7 @@ schedule_next_dlue(module_id_t module_idP, int CC_id, } //------------------------------------------------------------------------------ -unsigned char +int generate_dlsch_header(unsigned char *mac_header, unsigned char num_sdus, unsigned short *sdu_lengths, @@ -344,7 +344,6 @@ generate_dlsch_header(unsigned char *mac_header, //msg("After CEs %d\n",(uint8_t*)mac_header_ptr - mac_header); return ((unsigned char *) mac_header_ptr - mac_header); - } //------------------------------------------------------------------------------ @@ -563,33 +562,28 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, frame_t frameP, sub_frame_t subframeP, int *mbsfn_flag) //------------------------------------------------------------------------------ { - - - uint8_t CC_id; + int CC_id; int UE_id; - unsigned char aggregation; + int aggregation; mac_rlc_status_resp_t rlc_status; - unsigned char header_len_dcch = 0, header_len_dcch_tmp = 0; - unsigned char header_len_dtch = 0, header_len_dtch_tmp = - 0, header_len_dtch_last = 0; - unsigned char ta_len = 0; - unsigned char sdu_lcids[NB_RB_MAX], lcid, offset, num_sdus = 0; - uint16_t nb_rb, nb_rb_temp, nb_available_rb; - uint16_t TBS, j, sdu_lengths[NB_RB_MAX], rnti, padding = - 0, post_padding = 0; + int ta_len = 0; + unsigned char sdu_lcids[NB_RB_MAX]; + int lcid, offset, num_sdus = 0; + int nb_rb, nb_rb_temp, nb_available_rb; + uint16_t sdu_lengths[NB_RB_MAX]; + int TBS, j, rnti, padding = 0, post_padding = 0; unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; - unsigned char round = 0; - unsigned char harq_pid = 0; + int round = 0; + int harq_pid = 0; eNB_UE_STATS *eNB_UE_stats = NULL; - uint16_t sdu_length_total = 0; + int sdu_length_total = 0; eNB_MAC_INST *eNB = RC.mac[module_idP]; COMMON_channels_t *cc = eNB->common_channels; UE_list_t *UE_list = &eNB->UE_list; int continue_flag = 0; int32_t normalized_rx_power, target_rx_power; - int32_t tpc = 1; - static int32_t tpc_accumulated = 0; + int tpc = 1; UE_sched_ctrl *ue_sched_ctl; int mcs; int i; @@ -601,6 +595,8 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, nfapi_dl_config_request_pdu_t *dl_config_pdu; int tdd_sfa; int ta_update; + int header_length_last; + int header_length_total; #if 0 if (UE_list->head == -1) { @@ -792,6 +788,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, if (UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status < RRC_CONNECTED) continue; + header_length_total = 0; sdu_length_total = 0; num_sdus = 0; @@ -838,8 +835,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, if (cc[CC_id].tdd_Config != NULL) { UE_list->UE_template[CC_id][UE_id].DAI++; update_ul_dci(module_idP, CC_id, rnti, - UE_list->UE_template[CC_id][UE_id]. - DAI); + UE_list->UE_template[CC_id][UE_id].DAI); LOG_D(MAC, "DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", CC_id, subframeP, UE_id, @@ -988,13 +984,12 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, module_idP, frameP, CC_id, UE_id); } } else { /* This is a potentially new SDU opportunity */ - rlc_status.bytes_in_buffer = 0; + // Now check RLC information to compute number of required RBs // get maximum TBS size for RLC request - TBS = - get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb); - // check first for RLC data on DCCH + TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb); + // add the length for all the control elements (timing adv, drx, etc) : header + payload if (ue_sched_ctl->ta_timer == 0) { @@ -1009,38 +1004,42 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, ta_len = (ta_update != 31) ? 2 : 0; - header_len_dcch = 2; // 2 bytes DCCH SDU subheader - - if (TBS - ta_len - header_len_dcch > 0) { - rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, (TBS - ta_len - header_len_dcch)); // transport block set size + // RLC data on DCCH + if (TBS - ta_len - header_length_total - sdu_length_total - 3 > 0) { + rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, + TBS - ta_len - header_length_total - sdu_length_total - 3); sdu_lengths[0] = 0; - if (rlc_status.bytes_in_buffer > 0) { // There is DCCH to transmit - LOG_D(MAC, - "[eNB %d] SFN/SF %d.%d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n", + if (rlc_status.bytes_in_buffer > 0) { + LOG_D(MAC, "[eNB %d] SFN/SF %d.%d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n", module_idP, frameP, subframeP, CC_id, - TBS - header_len_dcch); - sdu_lengths[0] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, TBS, //not used - (char *) - &dlsch_buffer - [0]); + TBS - ta_len - header_length_total - sdu_length_total - 3); + + sdu_lengths[0] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, + TBS, //not used + (char *)&dlsch_buffer[0]); T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(DCCH), T_INT(sdu_lengths[0])); - LOG_D(MAC, - "[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n", + LOG_D(MAC, "[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n", module_idP, CC_id, sdu_lengths[0]); + sdu_length_total = sdu_lengths[0]; sdu_lcids[0] = DCCH; UE_list->eNB_UE_stats[CC_id][UE_id].lcid_sdu[0] = DCCH; UE_list->eNB_UE_stats[CC_id][UE_id].sdu_length_tx[DCCH] = sdu_lengths[0]; UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH] += 1; UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH] += sdu_lengths[0]; + + header_length_last = 1 + 1 + (sdu_lengths[0] >= 128); + header_length_total += header_length_last; + num_sdus = 1; + #ifdef DEBUG_eNB_SCHEDULER LOG_T(MAC, "[eNB %d][DCCH] CC_id %d Got %d bytes :", @@ -1052,26 +1051,25 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, LOG_T(MAC, "\n"); #endif - } else { - header_len_dcch = 0; - sdu_length_total = 0; } } - // check for DCCH1 and update header information (assume 2 byte sub-header) - if (TBS - ta_len - header_len_dcch - sdu_length_total > 0) { - rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, (TBS - ta_len - header_len_dcch - sdu_length_total)); // transport block set size less allocations for timing advance and + + // RLC data on DCCH1 + if (TBS - ta_len - header_length_total - sdu_length_total - 3 > 0) { + rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, + TBS - ta_len - header_length_total - sdu_length_total - 3); + // DCCH SDU sdu_lengths[num_sdus] = 0; if (rlc_status.bytes_in_buffer > 0) { - LOG_D(MAC, - "[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", + LOG_D(MAC, "[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", module_idP, frameP, CC_id, - TBS - header_len_dcch - sdu_length_total); - sdu_lengths[num_sdus] += mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, TBS, //not used - (char *) - &dlsch_buffer - [sdu_length_total]); + TBS - ta_len - header_length_total - sdu_length_total - 3); + + sdu_lengths[num_sdus] += mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, + TBS, //not used + (char *)&dlsch_buffer[sdu_length_total]); T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), @@ -1080,13 +1078,16 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, sdu_lcids[num_sdus] = DCCH1; sdu_length_total += sdu_lengths[num_sdus]; - header_len_dcch += 2; UE_list->eNB_UE_stats[CC_id][UE_id].lcid_sdu[num_sdus] = DCCH1; UE_list->eNB_UE_stats[CC_id][UE_id].sdu_length_tx[DCCH1] = sdu_lengths[num_sdus]; - UE_list->eNB_UE_stats[CC_id][UE_id]. - num_pdu_tx[DCCH1] += 1; + UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH1] += 1; UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1] += sdu_lengths[num_sdus]; + + header_length_last = 1 + 1 + (sdu_lengths[num_sdus] >= 128); + header_length_total += header_length_last; + num_sdus++; + #ifdef DEBUG_eNB_SCHEDULER LOG_T(MAC, "[eNB %d][DCCH1] CC_id %d Got %d bytes :", @@ -1098,25 +1099,18 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, LOG_T(MAC, "\n"); #endif - } } - // assume the max dtch header size, and adjust it later - header_len_dtch = 0; - header_len_dtch_last = 0; // the header length of the last mac sdu - // lcid has to be sorted before the actual allocation (similar struct as ue_list). + + // TODO: lcid has to be sorted before the actual allocation (similar struct as ue_list). for (lcid = NB_RB_MAX - 1; lcid >= DTCH; lcid--) { - // TBD: check if the lcid is active + // TODO: check if the lcid is active - header_len_dtch += 3; - header_len_dtch_last = 3; - LOG_D(MAC, - "[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n", + LOG_D(MAC, "[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n", module_idP, frameP, lcid, TBS, - TBS - ta_len - header_len_dcch - - sdu_length_total - header_len_dtch); + TBS - ta_len - header_length_total - sdu_length_total - 3); - if (TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch > 0) { // NN: > 2 ? + if (TBS - ta_len - header_length_total - sdu_length_total - 3 > 0) { rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, @@ -1125,25 +1119,22 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, - TBS - ta_len - - header_len_dcch - - sdu_length_total - - header_len_dtch); + TBS - ta_len - header_length_total - sdu_length_total - 3); + if (rlc_status.bytes_in_buffer > 0) { - LOG_D(MAC, "[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n", module_idP, frameP, - TBS - header_len_dcch - - sdu_length_total - header_len_dtch, lcid, - header_len_dtch); - sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, TBS, //not used - (char - *) - &dlsch_buffer - [sdu_length_total]); + TBS - ta_len - header_length_total - sdu_length_total - 3, + lcid, + header_length_total); + + sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, + TBS, //not used + (char *)&dlsch_buffer[sdu_length_total]); + T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), @@ -1152,50 +1143,39 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, LOG_D(MAC, "[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n", module_idP, sdu_lengths[num_sdus], lcid); + sdu_lcids[num_sdus] = lcid; sdu_length_total += sdu_lengths[num_sdus]; - UE_list-> - eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid] - += 1; + UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid]++; UE_list->eNB_UE_stats[CC_id][UE_id].lcid_sdu[num_sdus] = lcid; UE_list->eNB_UE_stats[CC_id][UE_id].sdu_length_tx[lcid] = sdu_lengths[num_sdus]; - UE_list-> - eNB_UE_stats[CC_id][UE_id].num_bytes_tx - [lcid] += sdu_lengths[num_sdus]; - if (sdu_lengths[num_sdus] < 128) { - header_len_dtch--; - header_len_dtch_last--; - } + UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[lcid] += sdu_lengths[num_sdus]; + + header_length_last = 1 + 1 + (sdu_lengths[num_sdus] >= 128); + header_length_total += header_length_last; + num_sdus++; + UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0; - } // no data for this LCID - else { - header_len_dtch -= 3; } - } // no TBS left - else { - header_len_dtch -= 3; + } else { + // no TBS left break; } } - if (header_len_dtch == 0) - header_len_dtch_last = 0; - // there is at least one SDU + + /* last header does not have length field */ + if (header_length_total) { + header_length_total -= header_length_last; + header_length_total++; + } + + // there is at least one SDU or TA command // if (num_sdus > 0 ){ - if ((sdu_length_total + header_len_dcch + - header_len_dtch) > 0) { + if (ta_len + sdu_length_total + header_length_total > 0) { // Now compute number of required RBs for total sdu length // Assume RAH format 2 - // adjust header lengths - header_len_dcch_tmp = header_len_dcch; - header_len_dtch_tmp = header_len_dtch; - if (header_len_dtch == 0) { - header_len_dcch = (header_len_dcch > 0) ? 1 : 0; //header_len_dcch; // remove length field - } else { - header_len_dtch_last -= 1; // now use it to find how many bytes has to be removed for the last MAC SDU - header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last : header_len_dtch; // remove length field for the last SDU - } mcs = eNB_UE_stats->dlsch_mcs1; @@ -1207,16 +1187,12 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, TBS = get_TBS_DL(mcs, nb_rb); - while (TBS < - (sdu_length_total + header_len_dcch + - header_len_dtch + ta_len)) { + while (TBS < sdu_length_total + header_length_total + ta_len) { nb_rb += min_rb_unit[CC_id]; // if (nb_rb > nb_available_rb) { // if we've gone beyond the maximum number of RBs // (can happen if N_RB_DL is odd) - TBS = - get_TBS_DL(eNB_UE_stats->dlsch_mcs1, - nb_available_rb); + TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb); nb_rb = nb_available_rb; break; } @@ -1250,13 +1226,13 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, } // decrease mcs until TBS falls below required length - while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs > 0)) { + while ((TBS > sdu_length_total + header_length_total + ta_len) && (mcs > 0)) { mcs--; TBS = get_TBS_DL(mcs, nb_rb); } // if we have decreased too much or we don't have enough RBs, increase MCS - while ((TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) + while ((TBS < sdu_length_total + header_length_total + ta_len) && (((ue_sched_ctl->dl_pow_off[CC_id] > 0) && (mcs < 28)) || ((ue_sched_ctl->dl_pow_off[CC_id] == 0) @@ -1277,23 +1253,14 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, // TBS, sdu_length_total, offset, TBS-sdu_length_total-offset); #endif - if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2) { - padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); + if (TBS - header_length_total - sdu_length_total - ta_len <= 2) { + padding = TBS - header_length_total - sdu_length_total - ta_len; post_padding = 0; } else { padding = 0; - - // adjust the header len - if (header_len_dtch == 0) { - header_len_dcch = header_len_dcch_tmp; - } else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2))) - header_len_dtch = header_len_dtch_tmp; - } - - post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len; // 1 is for the postpadding header + post_padding = 1; } - offset = generate_dlsch_header((unsigned char *) UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], num_sdus, //num_sdus sdu_lengths, // sdu_lcids, 255, // no drx @@ -1304,12 +1271,12 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, //#ifdef DEBUG_eNB_SCHEDULER if (ta_update != 31) { LOG_D(MAC, - "[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n", + "[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_length %d\n", module_idP, frameP, UE_id, CC_id, sdu_length_total, num_sdus, sdu_lengths[0], sdu_lcids[0], offset, ta_update, padding, post_padding, mcs, TBS, nb_rb, - header_len_dcch, header_len_dtch); + header_length_total); } //#endif #ifdef DEBUG_eNB_SCHEDULER @@ -1327,11 +1294,16 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, dlsch_buffer, sdu_length_total); // memcpy(RC.mac[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]); +#if 0 // fill remainder of DLSCH with random data for (j = 0; j < (TBS - sdu_length_total - offset); j++) { UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset + sdu_length_total + j] = (char) (taus() & 0xff); } - +#endif + // fill remainder of DLSCH with 0 + for (j = 0; j < (TBS - sdu_length_total - offset); j++) { + UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset + sdu_length_total + j] = 0; + } if (opt_enabled == 1) { trace_pdu(1, (uint8_t *) @@ -1348,8 +1320,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), - T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id]. - payload[0], TBS)); + T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], TBS)); UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; @@ -1378,6 +1349,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, UE_list->UE_template[CC_id][UE_id]. DAI); } + // do PUCCH power control // this is the normalized RX power eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; @@ -1399,18 +1371,15 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, if (normalized_rx_power > (target_rx_power + 4)) { tpc = 0; //-1 - tpc_accumulated--; } else if (normalized_rx_power < (target_rx_power - 4)) { tpc = 2; //+1 - tpc_accumulated++; } else { tpc = 1; //0 } LOG_D(MAC, - "[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", - module_idP, frameP, subframeP, harq_pid, - tpc, tpc_accumulated, + "[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, normalized/target rx power %d/%d\n", + module_idP, frameP, subframeP, harq_pid, tpc, normalized_rx_power, target_rx_power); } // Po_PUCCH has been updated @@ -1456,13 +1425,13 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, module_idP, CC_id, harq_pid, mcs); } + LOG_D(MAC, "Checking feasibility pdu %d (new sdu)\n", dl_req->number_pdu); + if (!CCE_allocation_infeasible(module_idP, CC_id, 1, subframeP, dl_config_pdu->dci_dl_pdu. dci_dl_pdu_rel8.aggregation_level, rnti)) { - - ue_sched_ctl->round[CC_id][harq_pid] = 0; dl_req->number_dci++; dl_req->number_pdu++; @@ -1482,8 +1451,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid] = mcs; UE_list->UE_template[CC_id][UE_id].oldmcs2[harq_pid] = 0; - AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != - NULL, + AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is NULL\n"); AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->pdsch_ConfigDedicated != NULL, "physicalConfigDedicated->pdsch_ConfigDedicated is NULL\n"); @@ -1506,15 +1474,10 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, 0, //number of PRBs treated as one subband, not used here 0 // number of beamforming vectors, not used here ); - eNB->TX_req[CC_id].sfn_sf = fill_nfapi_tx_req(&eNB-> - TX_req - [CC_id].tx_request_body, + eNB->TX_req[CC_id].sfn_sf = fill_nfapi_tx_req(&eNB->TX_req[CC_id].tx_request_body, (frameP * 10) + subframeP, TBS, eNB->pdu_index[CC_id], - eNB-> - UE_list.DLSCH_pdu[CC_id][0][(unsigned char) - UE_id].payload - [0]); + eNB->UE_list.DLSCH_pdu[CC_id][0][UE_id].payload[0]); LOG_D(MAC, "Filled NFAPI configuration for DCI/DLSCH/TXREQ %d, new SDU\n", @@ -1523,10 +1486,7 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, eNB->pdu_index[CC_id]++; program_dlsch_acknak(module_idP, CC_id, UE_id, frameP, subframeP, - dl_config_pdu-> - dci_dl_pdu.dci_dl_pdu_rel8. - cce_idx); - + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx); } else { LOG_W(MAC, "Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d/%x, infeasible CCE allocations\n", @@ -1550,7 +1510,6 @@ schedule_ue_spec(module_id_t module_idP,slice_id_t slice_idP, stop_meas(&eNB->schedule_dlsch); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_OUT); - } //------------------------------------------------------------------------------ diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 07159f9c24..2586c94f43 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -855,15 +855,15 @@ in the DLSCH buffer. @param post_padding number of bytes for padding at the end of MAC PDU @returns Number of bytes used for header */ -unsigned char generate_dlsch_header(unsigned char *mac_header, - unsigned char num_sdus, - unsigned short *sdu_lengths, - unsigned char *sdu_lcids, - unsigned char drx_cmd, - unsigned short timing_advance_cmd, - unsigned char *ue_cont_res_id, - unsigned char short_padding, - unsigned short post_padding); +int generate_dlsch_header(unsigned char *mac_header, + unsigned char num_sdus, + unsigned short *sdu_lengths, + unsigned char *sdu_lcids, + unsigned char drx_cmd, + unsigned short timing_advance_cmd, + unsigned char *ue_cont_res_id, + unsigned char short_padding, + unsigned short post_padding); /** \brief RRC eNB Configuration primitive for PHY/MAC. Allows configuration of PHY/MAC resources based on System Information (SI), RRCConnectionSetup and RRCConnectionReconfiguration messages. @param Mod_id Instance ID of eNB From 5a61f9944c93bc33157361330dbdc5165427330c Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 8 Mar 2018 09:58:13 +0100 Subject: [PATCH 277/284] cleanup - remove unnecessary calls to get_cpu_freq_GHz The one in lte-enb.c disrupts the realtime. Using a B200mini with 20MHz bandwidth leads to the UE unable to connect for it seesms like the UL and DL are not properly time synched because of this sleep of one second that happens after the USRP streaming has started. We see some random access attempts but the decoded preamble is wrong. This may be dependant on the setup. I had sporadic errors with a B210, where sometimes the UE could connect and sometimes not. --- targets/RT/USER/lte-enb.c | 7 ------- targets/RT/USER/lte-softmodem.c | 6 ++---- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 01a2c68bf3..e1c5d10de5 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -163,13 +163,6 @@ extern void add_subframe(uint16_t *frameP, uint16_t *subframeP, int offset); static inline int rxtx(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, char *thread_name) { - - static double cpu_freq_GHz = 0.0; - - if (cpu_freq_GHz == 0.0) - cpu_freq_GHz = get_cpu_freq_GHz(); - - start_meas(&softmodem_stats_rxtx_sf); // ******************************************************************* diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index f6789086b4..0564049c70 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1249,10 +1249,8 @@ int main( int argc, char **argv ) printf("Runtime table\n"); fill_modeled_runtime_table(runtime_phy_rx,runtime_phy_tx); - cpuf=get_cpu_freq_GHz(); - - - + + #ifndef DEADLINE_SCHEDULER printf("NO deadline scheduler\n"); From 963805820c9a0b0deff845d44fe116cda5013cc3 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 8 Mar 2018 10:17:16 +0100 Subject: [PATCH 278/284] add a stop_rf function in the RU When the program exits it has to stop the streaming of the USRP. The function exit_fun is supposed to do that. When quitting with control+c (very common case) this function is not called. The code is very unclear there, so let's add a stop_rf in the RU, as there is already a start_rf. If we don't call trx_end_func, then at the next run the USRP device may be in an unstable state and behave improperly. If the program crashes then the USRP device may be in an unstable state. The only solution to this problem is to reset the USRP device. Maybe there is a way to clean the state of the device when we open it, before we start using it. Sort of a cleanup before use. That could be a better solution to "bad state after program crash". What has been tested: - monolithic eNB only --- openair1/PHY/defs.h | 2 ++ targets/RT/USER/lte-ru.c | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 46f37e9431..a0f37dd885 100644 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -738,6 +738,8 @@ typedef struct RU_t_s{ void (*fh_south_asynch_in)(struct RU_t_s *ru,int *frame, int *subframe); /// function pointer to initialization function for radio interface int (*start_rf)(struct RU_t_s *ru); + /// function pointer to release function for radio interface + int (*stop_rf)(struct RU_t_s *ru); /// function pointer to initialization function for radio interface int (*start_if)(struct RU_t_s *ru,struct PHY_VARS_eNB_s *eNB); /// function pointer to RX front-end processing routine (DFTs/prefix removal or NULL) diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index d909da627f..d9bda6a037 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -1523,7 +1523,13 @@ static void* ru_thread( void* param ) { printf( "Exiting ru_thread \n"); - + + if (ru->stop_rf != NULL) { + if (ru->stop_rf(ru) != 0) + LOG_E(HW,"Could not stop the RF device\n"); + else LOG_I(PHY,"RU %d rf device stopped\n",ru->idx); + } + ru_thread_status = 0; return &ru_thread_status; @@ -1617,6 +1623,12 @@ int start_rf(RU_t *ru) { return(ru->rfdevice.trx_start_func(&ru->rfdevice)); } +int stop_rf(RU_t *ru) +{ + ru->rfdevice.trx_end_func(&ru->rfdevice); + return 0; +} + extern void fep_full(RU_t *ru); extern void ru_fep_full_2thread(RU_t *ru); extern void feptx_ofdm(RU_t *ru); @@ -2082,6 +2094,7 @@ void set_function_spec_param(RU_t *ru) ru->fh_south_in = rx_rf; // local synchronous RF RX ru->fh_south_out = tx_rf; // local synchronous RF TX ru->start_rf = start_rf; // need to start the local RF interface + ru->stop_rf = stop_rf; printf("configuring ru_id %d (start_rf %p)\n", ru->idx, start_rf); /* if (ru->function == eNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise @@ -2113,6 +2126,7 @@ void set_function_spec_param(RU_t *ru) ru->fh_south_asynch_in = NULL; // no asynchronous UL } ru->start_rf = NULL; // no local RF + ru->stop_rf = NULL; ru->start_if = start_if; // need to start if interface for IF5 ru->ifdevice.host_type = RAU_HOST; ru->ifdevice.eth_params = &ru->eth_params; @@ -2137,6 +2151,7 @@ void set_function_spec_param(RU_t *ru) ru->fh_north_out = NULL; ru->fh_north_asynch_in = NULL; ru->start_rf = NULL; // no local RF + ru->stop_rf = NULL; ru->start_if = start_if; // need to start if interface for IF4p5 ru->ifdevice.host_type = RAU_HOST; ru->ifdevice.eth_params = &ru->eth_params; From 45302792ee875a905cd6ec82c8af812fe9ba316a Mon Sep 17 00:00:00 2001 From: oai Date: Fri, 23 Feb 2018 15:37:24 +0100 Subject: [PATCH 279/284] config module fix and extensions for Nb-IoT, shared lib loader and telnet server implementation --- cmake_targets/CMakeLists.txt | 24 +- cmake_targets/build_oai | 18 +- common/config/config_load_configmodule.c | 31 +- common/config/config_load_configmodule.h | 21 +- common/config/config_paramdesc.h | 74 ++- common/config/config_userapi.c | 135 +++- common/config/config_userapi.h | 28 +- common/config/libconfig/config_libconfig.c | 51 +- common/ran_context.h | 14 +- common/utils/load_module_shlib.c | 127 +++- common/utils/load_module_shlib.h | 39 +- common/utils/telnetsrv/CMakeLists.txt | 59 -- common/utils/telnetsrv/telnetsrv.c | 228 +++++-- common/utils/telnetsrv/telnetsrv.h | 11 +- .../utils/telnetsrv/telnetsrv_CMakeLists.txt | 28 + common/utils/telnetsrv/telnetsrv_loader.c | 84 +++ common/utils/telnetsrv/telnetsrv_loader.h | 55 ++ common/utils/telnetsrv/telnetsrv_phycmd.c | 4 +- common/utils/telnetsrv/telnetsrv_phycmd.h | 4 +- common/utils/telnetsrv/telnetsrv_proccmd.c | 189 +++++- common/utils/telnetsrv/telnetsrv_proccmd.h | 29 +- openair1/PHY/CODING/3gpplte.c | 10 +- openair1/PHY/CODING/3gpplte_sse.c | 33 +- openair1/PHY/CODING/3gpplte_turbo_decoder.c | 4 +- .../CODING/3gpplte_turbo_decoder_avx2_16bit.c | 38 +- .../CODING/3gpplte_turbo_decoder_sse_16bit.c | 2 +- .../CODING/3gpplte_turbo_decoder_sse_8bit.c | 2 +- openair1/PHY/CODING/coding_load.c | 134 ++++ openair1/PHY/CODING/defs.h | 32 +- openair1/PHY/CODING/extern.h | 8 +- openair1/PHY/INIT/init_top.c | 15 +- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 56 +- openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c | 23 +- openair1/PHY/LTE_TRANSPORT/ulsch_coding.c | 14 +- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 69 +- openair1/PHY/defs.h | 47 ++ openair1/SCHED/phy_procedures_lte_eNb.c | 2 +- openair2/ENB_APP/L1_paramdef.h | 73 ++ openair2/ENB_APP/MACRLC_paramdef.h | 98 +++ openair2/ENB_APP/RRC_config_tools.c | 123 ++++ openair2/ENB_APP/RRC_config_tools.h | 50 ++ openair2/ENB_APP/RRC_paramsvalues.h | 94 +++ openair2/ENB_APP/enb_config.c | 624 ++---------------- openair2/ENB_APP/enb_paramdef.h | 320 +++++---- openair2/ENB_APP/nbiot_config.c | 295 +++++++++ openair2/ENB_APP/nbiot_config.h | 37 ++ openair2/ENB_APP/nbiot_paramdef.h | 400 +++++++++++ openair2/UTIL/LOG/log.c | 7 +- openair2/UTIL/LOG/log.h | 16 +- targets/ARCH/COMMON/common_lib.c | 53 +- targets/ARCH/COMMON/common_lib.h | 4 +- targets/RT/USER/lte-softmodem.c | 69 +- targets/RT/USER/lte-softmodem.h | 7 +- 53 files changed, 2729 insertions(+), 1283 deletions(-) delete mode 100644 common/utils/telnetsrv/CMakeLists.txt create mode 100644 common/utils/telnetsrv/telnetsrv_CMakeLists.txt create mode 100644 common/utils/telnetsrv/telnetsrv_loader.c create mode 100644 common/utils/telnetsrv/telnetsrv_loader.h create mode 100644 openair1/PHY/CODING/coding_load.c create mode 100644 openair2/ENB_APP/L1_paramdef.h create mode 100644 openair2/ENB_APP/MACRLC_paramdef.h create mode 100644 openair2/ENB_APP/RRC_config_tools.c create mode 100644 openair2/ENB_APP/RRC_config_tools.h create mode 100644 openair2/ENB_APP/RRC_paramsvalues.h create mode 100644 openair2/ENB_APP/nbiot_config.c create mode 100644 openair2/ENB_APP/nbiot_config.h create mode 100644 openair2/ENB_APP/nbiot_paramdef.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 89b96bf922..4f264044df 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1042,6 +1042,19 @@ include_directories(${NFAPI_USER_DIR}) # Layer 1 ############################# +set(PHY_TURBOSRC + ${OPENAIR1_DIR}/PHY/CODING/3gpplte_sse.c + ${OPENAIR1_DIR}/PHY/CODING/3gpplte.c + ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c + ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c + ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c + ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder.c +) +set(PHY_TURBOIF + ${OPENAIR1_DIR}/PHY/CODING/coding_load.c +) + +add_library(coding MODULE ${PHY_TURBOSRC} ) set(PHY_SRC # depend on code generation from asn1c ${RRC_FULL_DIR}/asn1_constants.h @@ -1109,11 +1122,8 @@ set(PHY_SRC ${OPENAIR1_DIR}/PHY/CODING/lte_segmentation.c ${OPENAIR1_DIR}/PHY/CODING/ccoding_byte.c ${OPENAIR1_DIR}/PHY/CODING/ccoding_byte_lte.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_sse.c ${OPENAIR1_DIR}/PHY/CODING/crc_byte.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c + ${PHY_TURBOIF} ${OPENAIR1_DIR}/PHY/CODING/lte_rate_matching.c ${OPENAIR1_DIR}/PHY/CODING/viterbi.c ${OPENAIR1_DIR}/PHY/CODING/viterbi_lte.c @@ -1373,6 +1383,7 @@ set (MAC_SRC_UE set (ENB_APP_SRC ${OPENAIR2_DIR}/ENB_APP/enb_app.c ${OPENAIR2_DIR}/ENB_APP/enb_config.c + ${OPENAIR2_DIR}/ENB_APP/RRC_config_tools.c ) add_library(L2 @@ -2398,3 +2409,8 @@ ADD_CUSTOM_TARGET(oarf DEPENDS ${OCT_FILES} ) +include (${OPENAIR_DIR}/common/utils/telnetsrv/telnetsrv_CMakeLists.txt) + + + + diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 7e0c0ca169..b19e3208a5 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -544,6 +544,9 @@ function main() { compilations \ $lte_build_dir $config_libconfig_shlib \ lib$config_libconfig_shlib.so $dbin/lib$config_libconfig_shlib.so + compilations \ + $lte_build_dir coding \ + libcoding.so $dbin/libcoding.so if [ "$NOS1" = "1" ] ; then compilations \ @@ -766,17 +769,10 @@ function main() { # Telnet server compilation ##################### if [ "$BUILD_TELNETSRV" = "1" ] ; then - - telnetsrv_build_dir=telnetsrv - mkdir -p $DIR/$telnetsrv_build_dir/build - cd $DIR/$telnetsrv_build_dir/build - echo_info "Compiling telnet server library ..." - - [ "$CLEAN" = "1" ] && rm -rf $DIR/$telnetsrv_build_dir - cmake_file=$OPENAIR_DIR/common/utils/$telnetsrv_build_dir/CMakeLists.txt - cd $DIR/$telnetsrv_build_dir/build - eval "$CMAKE_CMD $OPENAIR_DIR/common/utils/$telnetsrv_build_dir/" - make + build_dir=$lte_build_dir + compilations \ + $build_dir telnetsrv \ + libtelnetsrv.so $dbin/libtelnetsrv.so fi # build RF device and transport protocol libraries diff --git a/common/config/config_load_configmodule.c b/common/config/config_load_configmodule.c index ff66d22a1c..c31a2da4d7 100644 --- a/common/config/config_load_configmodule.c +++ b/common/config/config_load_configmodule.c @@ -197,25 +197,40 @@ int i; return cfgptr; } -void end_configmodule() + +/* free memory allocated when reading parameters */ +/* config module could be initialized again after this call */ +void end_configmodule(void) { if (cfgptr != NULL) { if (cfgptr->end != NULL) { printf ("[CONFIG] calling config module end function...\n"); cfgptr->end(); } + + printf ("[CONFIG] free %u config value pointers\n",cfgptr->numptrs); + for(int i=0; inumptrs ; i++) { + if (cfgptr->ptrs[i] != NULL) { + free(cfgptr->ptrs[i]); + cfgptr->ptrs[i]=NULL; + } + } + cfgptr->numptrs=0; + } +} + +/* free all memory used by config module */ +/* should be called only at program exit */ +void free_configmodule(void) +{ + if (cfgptr != NULL) { + end_configmodule(); if( cfgptr->cfgmode != NULL) free(cfgptr->cfgmode); printf ("[CONFIG] free %u config parameter pointers\n",cfgptr->num_cfgP); for (int i=0; inum_cfgP; i++) { if ( cfgptr->cfgP[i] != NULL) free(cfgptr->cfgP[i]); } - printf ("[CONFIG] free %u config value pointers\n",cfgptr->numptrs); - for(int i=0; inumptrs ; i++) { - if (cfgptr->ptrs[i] != NULL) { - free(cfgptr->ptrs[i]); - } - cfgptr->ptrs[i]=NULL; - } + free(cfgptr); cfgptr=NULL; diff --git a/common/config/config_load_configmodule.h b/common/config/config_load_configmodule.h index 76f074cd6c..724cd1dbf5 100644 --- a/common/config/config_load_configmodule.h +++ b/common/config/config_load_configmodule.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * @@ -40,15 +40,18 @@ #define CONFIG_MAX_OOPT_PARAMS 10 // maximum number of parameters in the -O option (-O :P1:P2... #define CONFIG_MAX_ALLOCATEDPTRS 1024 // maximum number of parameters that can be dynamicaly allocated in the config module +/* default values for configuration module parameters */ +#define DEFAULT_CFGMODE "libconfig" // use libconfig file +#define DEFAULT_CFGFILENAME "oai.conf" // default config file + /* rtflags bit position definitions */ -#define CONFIG_PRINTPARAMS 1 // print parameters values while processing -#define CONFIG_DEBUGPTR 2 // print memory allocation/free debug messages -#define CONFIG_DEBUGCMDLINE 4 // print command line processing messages -#define CONFIG_HELP 8 // print help message -#define CONFIG_ABORT 16 // config failed,abort execution -#define CONFIG_NOOOPT 32 // no -O option found when parsing command line - - +#define CONFIG_PRINTPARAMS 1 // print parameters values while processing +#define CONFIG_DEBUGPTR 1<<1 // print memory allocation/free debug messages +#define CONFIG_DEBUGCMDLINE 1<<2 // print command line processing messages +#define CONFIG_NOABORTONCHKF 1<<3 // disable abort execution when parameter checking function fails +#define CONFIG_HELP 1<<20 // print help message +#define CONFIG_ABORT 1<<21 // config failed,abort execution +#define CONFIG_NOOOPT 1<<22 // no -O option found when parsing command line typedef int(*configmodule_initfunc_t)(char *cfgP[],int numP); typedef int(*configmodule_getfunc_t)(paramdef_t *,int numparams, char *prefix); typedef int(*configmodule_getlistfunc_t)(paramlist_def_t *, paramdef_t *,int numparams, char *prefix); diff --git a/common/config/config_paramdesc.h b/common/config/config_paramdesc.h index a7de5e3098..6f153535fb 100644 --- a/common/config/config_paramdesc.h +++ b/common/config/config_paramdesc.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * @@ -55,16 +55,61 @@ #define PARAMFLAG_PARAMSET (1 << 16) // parameter has been explicitely set in get functions #define PARAMFLAG_PARAMSETDEF (1 << 17) // parameter has been set to default value in get functions + +/* checkedparam_t is possibly used in paramdef_t for specific parameter value validation */ +#define CONFIG_MAX_NUMCHECKVAL 20 +typedef struct paramdef paramdef_t; +typedef union checkedparam { + struct { + int (*f1)(paramdef_t *param); /* check an integer against a list of authorized values */ + int okintval[CONFIG_MAX_NUMCHECKVAL]; /* integer array, store possible values */ + int num_okintval; /* number of valid values in the checkingval array */ + } s1; + struct { + int (*f1a)(paramdef_t *param); /* check an integer against a list of authorized values and set param value */ + /* to the corresponding item in setintval array (mainly for RRC params) */ + int okintval[CONFIG_MAX_NUMCHECKVAL]; /* integer array, store possible values in config file */ + int setintval[CONFIG_MAX_NUMCHECKVAL]; /* integer array, values set in the paramdef structure */ + int num_okintval; /* number of valid values in the checkingval array */ + } s1a; + struct { + int (*f2)(paramdef_t *param); /* check an integer against an authorized range, defined by its min and max value */ + int okintrange[CONFIG_MAX_NUMCHECKVAL]; /* integer array, store min and max values */ + + } s2; + struct { + int (*f3)(paramdef_t *param); /* check a string against a list of authorized values */ + char *okstrval[CONFIG_MAX_NUMCHECKVAL]; /* string array, store possible values */ + int num_okstrval; /* number of valid values in the checkingval array */ + } s3; + struct { + int (*f3a)(paramdef_t *param); /* check a string against a list of authorized values and set param value */ + /* to the corresponding item in setintval array (mainly for RRC params) */ + char *okstrval[CONFIG_MAX_NUMCHECKVAL]; /* string array, store possible values */ + int setintval[CONFIG_MAX_NUMCHECKVAL]; /* integer array, values set in the paramdef structure */ + int num_okstrval; /* number of valid values in the checkingval array */ + } s3a; + struct { + int (*f4)(paramdef_t *param); /* generic check function, no arguments but the param description */ + + } s4; + struct { + void (*checkfunc)(void) ; + } s5; +} checkedparam_t; + +/* paramdef is used to describe a parameter, array of paramdef_t strustures is used as the main parameter in */ +/* config apis used to retrieve parameters values */ typedef struct paramdef { - char optname[MAX_OPTNAME_SIZE]; /* parameter name, can be used as long command line option */ - char *helpstr; /* help string */ - unsigned int paramflags; /* value is a "ored" combination of above PARAMFLAG_XXXX values */ - union { /* pointer to the parameter value, completed by the config module */ + char optname[MAX_OPTNAME_SIZE]; /* parameter name, can be used as long command line option */ + char *helpstr; /* help string */ + unsigned int paramflags; /* value is a "ored" combination of above PARAMFLAG_XXXX values */ + union { /* pointer to the parameter value, completed by the config module */ char **strptr; char **strlistptr; uint8_t *u8ptr; - char *i8ptr; + int8_t *i8ptr; uint16_t *u16ptr; int16_t *i16ptr; uint32_t *uptr; @@ -72,18 +117,21 @@ typedef struct paramdef uint64_t *u64ptr; int64_t *i64ptr; double *dblptr; + void *voidptr; } ; union { /* default parameter value, to be used when PARAMFLAG_MANDATORY is not specified */ - char *defstrval; - char **defstrlistval; - uint32_t defuintval; - int defintval; - uint64_t defint64val; - int *defintarrayval; - double defdblval; + char *defstrval; + char **defstrlistval; + uint32_t defuintval; + int defintval; + uint64_t defint64val; + int *defintarrayval; + double defdblval; } ; char type; /* parameter value type, as listed below as TYPE_XXXX macro */ int numelt; /* number of elements in a list or array parameters or max size of string value */ + checkedparam_t *chkPptr; /* possible pointer to the structure containing the info used to check parameter values */ + int *processedvalue; /* used to store integer values computed from string original value */ } paramdef_t; #define TYPE_INT TYPE_INT32 diff --git a/common/config/config_userapi.c b/common/config/config_userapi.c index acee5646cd..c1acc84384 100644 --- a/common/config/config_userapi.c +++ b/common/config/config_userapi.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * @@ -36,6 +36,7 @@ #include #include #include "config_userapi.h" +extern void exit_fun(const char* s); // lte-softmodem clean exit function configmodule_interface_t *config_get_if(void) @@ -59,7 +60,7 @@ char * config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length) *ptr = malloc(length); if ( *ptr != NULL) { memset(*ptr,0,length); - if ( (cfgoptions->paramflags & PARAMFLAG_NOFREE) != 0) { + if ( (cfgoptions->paramflags & PARAMFLAG_NOFREE) == 0) { config_get_if()->ptrs[config_get_if()->numptrs] = *ptr; config_get_if()->numptrs++; } @@ -111,7 +112,29 @@ int tmpval=val; break; } } +void config_assign_processedint(paramdef_t *cfgoption, int val) { + cfgoption->processedvalue = malloc(sizeof(int)); + if ( cfgoption->processedvalue != NULL) { + *(cfgoption->processedvalue) = val; + } else { + fprintf (stderr,"[CONFIG] %s %d malloc error\n",__FILE__, __LINE__); + exit(-1); + } +} +int config_get_processedint(paramdef_t *cfgoption) { + int ret; + if ( cfgoption->processedvalue != NULL) { + ret=*(cfgoption->processedvalue); + free( cfgoption->processedvalue); + cfgoption->processedvalue=NULL; + printf_params("[CONFIG] %s: set from %s to %i\n",cfgoption->optname, *(cfgoption->strptr), ret); + } else { + fprintf (stderr,"[CONFIG] %s %d %s has no processed integer availablle\n",__FILE__, __LINE__, cfgoption->optname); + ret=0; + } +return ret; +} void config_printhelp(paramdef_t *params,int numparams) { for (int i=0 ; is4.f4 != NULL) { + st += params[i].chkPptr->s4.f4(&(params[i])); + } + } + if (st != 0) { + fprintf(stderr,"[CONFIG] config_execcheck: %i parameters with wrong value\n", -st); + if ( CONFIG_ISFLAGSET(CONFIG_NOABORTONCHKF) == 0) { + exit_fun("exit because configuration failed\n"); + } + } +return st; +} + int config_get(paramdef_t *params,int numparams, char *prefix) { int ret= -1; -printf("numparams:%d prefix:%s\n", numparams, prefix); if (CONFIG_ISFLAGSET(CONFIG_ABORT)) { fprintf(stderr,"[CONFIG] config_get skipped, config module not properly initialized\n"); return ret; @@ -138,6 +181,7 @@ configmodule_interface_t *cfgif = config_get_if(); ret = config_get_if()->get(params, numparams,prefix); if (ret >= 0) { config_process_cmdline(params,numparams,prefix); + config_execcheck(params,numparams,prefix); } return ret; } @@ -153,6 +197,89 @@ int config_isparamset(paramdef_t *params,int paramidx) } } -int config_getparamval_fromparamdefidx(paramdef_t *cfgoptions,int paramidx) { +void print_intvalueerror(paramdef_t *param, char *fname, int *okval, int numokval) { + fprintf(stderr,"[CONFIG] %s: %s: %i invalid value, authorized values:\n ", + fname,param->optname, (int)*(param->uptr)); + for ( int i=0; ichkPptr->s1.num_okintval ; i++) { + if( *(param->uptr) == param->chkPptr->s1.okintval[i] ) { + return 0; + } + } + print_intvalueerror(param,"config_check_intval", param->chkPptr->s1.okintval,param->chkPptr->s1.num_okintval); + return -1; +} + +int config_check_modify_integer(paramdef_t *param) +{ + + for (int i=0; i < param->chkPptr->s1a.num_okintval ; i++) { + if (*(param->uptr) == param->chkPptr->s1a.okintval[i] ) { + printf_params("[CONFIG] %s: read value %i, set to %i\n",param->optname,*(param->uptr),param->chkPptr->s1a.setintval [i]); + *(param->uptr) = param->chkPptr->s1a.setintval [i]; + return 0; + } + } + print_intvalueerror(param,"config_check_modify_integer", param->chkPptr->s1a.okintval,param->chkPptr->s1a.num_okintval); + return -1; +} + +int config_check_intrange(paramdef_t *param) +{ + if( *(param->iptr) >= param->chkPptr->s2.okintrange[0] && *(param->iptr) <= param->chkPptr->s2.okintrange[1] ) { + return 0; + } + fprintf(stderr,"[CONFIG] config_check_intrange: %s: %i invalid value, authorized range: %i %i\n", + param->optname, (int)*(param->uptr), param->chkPptr->s2.okintrange[0], param->chkPptr->s2.okintrange[1]); + return -1; +} + +void print_strvalueerror(paramdef_t *param, char *fname, char **okval, int numokval) { + fprintf(stderr,"[CONFIG] %s: %s: %s invalid value, authorized values:\n ", + fname,param->optname, *(param->strptr)); + for ( int i=0; ichkPptr->s3.num_okstrval ; i++) { + if( strcasecmp(*(param->strptr),param->chkPptr->s3.okstrval[i] ) == 0) { + return 0; + } + } + print_strvalueerror(param, "config_check_strval", param->chkPptr->s3.okstrval, param->chkPptr->s3.num_okstrval); + return -1; +} + +int config_checkstr_assign_integer(paramdef_t *param) +{ + + + for (int i=0; i < param->chkPptr->s3a.num_okstrval ; i++) { + if (strcasecmp(*(param->strptr),param->chkPptr->s3a.okstrval[i] ) == 0) { + config_assign_processedint(param, param->chkPptr->s3a.setintval[i]); + return 0; + } + } + print_strvalueerror(param, "config_check_strval", param->chkPptr->s3a.okstrval, param->chkPptr->s3a.num_okstrval); + return -1; } diff --git a/common/config/config_userapi.h b/common/config/config_userapi.h index 5bbc20a950..923a690f51 100644 --- a/common/config/config_userapi.h +++ b/common/config/config_userapi.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * @@ -38,24 +38,34 @@ extern "C" { #endif -#define DEFAULT_CFGFILENAME "oaisoftmodem.conf" -#define DEFAULT_CFGMODE "libconfig" - #define CONFIG_GETSOURCE ( (config_get_if()==NULL) ? NULL : config_get_if()->cfgmode ) #define CONFIG_GETNUMP ( (config_get_if()==NULL) ? 0 : config_get_if()->num_cfgP ) #define CONFIG_GETP(P) ( (config_get_if()==NULL) ? NULL : config_get_if()->cfgP[P] ) #define CONFIG_ISFLAGSET(P) ( (config_get_if()==NULL) ? 0 : !!(config_get_if()->rtflags & P)) - +#define CONFIG_ISPARAMFLAGSET(P,F) ( !!(P.paramflags & F)) +/* utility functions, to be used by configuration module and/or configuration libraries */ extern configmodule_interface_t *config_get_if(void); extern char * config_check_valptr(paramdef_t *cfgoptions, char **ptr, int length) ; extern void config_printhelp(paramdef_t *,int numparams); extern int config_process_cmdline(paramdef_t *params,int numparams, char *prefix); -extern int config_get(paramdef_t *params,int numparams, char *prefix); -extern int config_isparamset(paramdef_t *params,int paramidx); +extern void config_assign_processedint(paramdef_t *cfgoption, int val); extern void config_assign_int(paramdef_t *cfgoptions, char *fullname, int val); -extern int config_process_cmdline(paramdef_t *cfgoptions,int numoptions, char *prefix); -extern int config_getparamval_fromparamdefidx(paramdef_t *cfgoptions,int paramidx); + +/* apis to get parameters, to be used by oai modules, at configuration time */ +extern int config_get(paramdef_t *params,int numparams, char *prefix); #define config_getlist config_get_if()->getlist + +/* apis to retrieve parameters info after calling get or getlist functions */ +extern int config_isparamset(paramdef_t *params,int paramidx); +extern int config_get_processedint(paramdef_t *cfgoption); + +/* functions to be used in parameters definition, to check parameters values */ +extern int config_check_intval(paramdef_t *param); +extern int config_check_modify_integer(paramdef_t *param); +extern int config_check_intrange(paramdef_t *param); +extern int config_check_strval(paramdef_t *param); +extern int config_checkstr_assign_integer(paramdef_t *param); + #define CONFIG_GETCONFFILE (config_get_if()->cfgP[0]) #ifdef __cplusplus diff --git a/common/config/libconfig/config_libconfig.c b/common/config/libconfig/config_libconfig.c index 00f5f38b8f..a73a0737f2 100644 --- a/common/config/libconfig/config_libconfig.c +++ b/common/config/libconfig/config_libconfig.c @@ -1,3 +1,33 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ +/*! \file common/config/libconfig/config_libconfig.c + * \brief: implementation libconfig configuration library + * \author Francois TABURET + * \date 2017 + * \version 0.1 + * \company NOKIA BellLabs France + * \email: francois.taburet@nokia-bell-labs.com + * \note + * \warning + */ #define _GNU_SOURCE #include @@ -21,21 +51,23 @@ int read_strlist(paramdef_t *cfgoptions,config_setting_t *setting, char *cfgpath { const char *str; int st; +int numelt; - cfgoptions->numelt=config_setting_length(setting); - cfgoptions->strlistptr=malloc(sizeof(char *) * (cfgoptions->numelt)); + numelt=config_setting_length(setting); + config_check_valptr(cfgoptions,(char **)&(cfgoptions->strlistptr), sizeof(char *) * numelt); st=0; - for (int i=0; i< cfgoptions->numelt && cfgoptions->strlistptr != NULL; i++) { + for (int i=0; i< numelt ; i++) { str=config_setting_get_string_elem(setting,i); if (str==NULL) { printf("[LIBCONFIG] %s%i not found in config file\n", cfgoptions->optname,i); } else { - cfgoptions->strlistptr[i]=malloc(strlen(str)+1); + config_check_valptr(cfgoptions,&(cfgoptions->strlistptr[i]),strlen(str)+1); sprintf(cfgoptions->strlistptr[i],"%s",str); st++; printf_params("[LIBCONFIG] %s%i: %s\n", cfgpath,i,cfgoptions->strlistptr[i]); } } + cfgoptions->numelt=numelt; return st; } @@ -108,10 +140,10 @@ int config_libconfig_get(paramdef_t *cfgoptions,int numoptions, char *prefix ) config_check_valptr(&(cfgoptions[i]), (char **)(&(cfgoptions[i].strptr)), sizeof(char *)); config_check_valptr(&(cfgoptions[i]), cfgoptions[i].strptr, strlen(str)+1); sprintf( *(cfgoptions[i].strptr) , "%s", str); - printf_params("[LIBCONFIG] %s: %s\n", cfgpath,*(cfgoptions[i].strptr) ); + printf_params("[LIBCONFIG] %s: \"%s\"\n", cfgpath,*(cfgoptions[i].strptr) ); } else { sprintf( (char *)(cfgoptions[i].strptr) , "%s", str); - printf_params("[LIBCONFIG] %s: %s\n", cfgpath,(char *)cfgoptions[i].strptr ); + printf_params("[LIBCONFIG] %s: \"%s\"\n", cfgpath,(char *)cfgoptions[i].strptr ); } } else { if( cfgoptions[i].defstrval != NULL) { @@ -121,10 +153,10 @@ int config_libconfig_get(paramdef_t *cfgoptions,int numoptions, char *prefix ) config_check_valptr(&(cfgoptions[i]), (char **)(&(cfgoptions[i].strptr)), sizeof(char *)); config_check_valptr(&(cfgoptions[i]), cfgoptions[i].strptr, strlen(cfgoptions[i].defstrval)+1); sprintf(*(cfgoptions[i].strptr), "%s",cfgoptions[i].defstrval); - printf_params("[LIBCONFIG] %s set to default value %s\n", cfgpath, *(cfgoptions[i].strptr)); + printf_params("[LIBCONFIG] %s set to default value \"%s\"\n", cfgpath, *(cfgoptions[i].strptr)); } else { - sprintf((char *)(cfgoptions[i].strptr), "%s",cfgoptions[i].defstrval); - printf_params("[LIBCONFIG] %s set to default value %s\n", cfgpath, (char *)cfgoptions[i].strptr); + sprintf((char *)*(cfgoptions[i].strptr), "%s",cfgoptions[i].defstrval); + printf_params("[LIBCONFIG] %s set to default value \"%s\"\n", cfgpath, (char *)*(cfgoptions[i].strptr)); } } else { notfound=1; @@ -374,6 +406,7 @@ void config_libconfig_end(void ) config_destroy(&(libconfig_privdata.cfg)); if ( libconfig_privdata.configfile != NULL ) { free(libconfig_privdata.configfile); + libconfig_privdata.configfile=NULL; } } diff --git a/common/ran_context.h b/common/ran_context.h index f59fd8a79c..c521c4f376 100644 --- a/common/ran_context.h +++ b/common/ran_context.h @@ -55,12 +55,18 @@ typedef struct { int nb_inst; /// Number of Component Carriers per instance in this node int *nb_CC; + /// Number of NB_IoT instances in this node + int nb_nb_iot_rrc_inst; /// Number of MACRLC instances in this node int nb_macrlc_inst; + /// Number of NB_IoT MACRLC instances in this node + int nb_nb_iot_macrlc_inst; /// Number of component carriers per instance in this node int *nb_mac_CC; /// Number of L1 instances in this node int nb_L1_inst; + /// Number of NB_IoT L1 instances in this node + int nb_nb_iot_L1_inst; /// Number of Component Carriers per instance in this node int *nb_L1_CC; /// Number of RU instances in this node @@ -69,10 +75,16 @@ typedef struct { flexran_agent_info_t **flexran; /// eNB context variables struct PHY_VARS_eNB_s ***eNB; + /// NB_IoT L1 context variables + //struct PHY_VARS_eNB_NB_IoT_s **L1_NB_IoT; /// RRC context variables struct eNB_RRC_INST_s **rrc; - /// RRC context variables + /// NB_IoT RRC context variables + //struct eNB_RRC_INST_NB_IoT_s **nb_iot_rrc; + /// MAC context variables struct eNB_MAC_INST_s **mac; + /// NB_IoT MAC context variables + //struct eNB_MAC_INST_NB_IoT_s **nb_iot_mac; /// GTPu descriptor gtpv1u_data_t *gtpv1u_data_g; /// RU descriptors. These describe what each radio unit is supposed to do and contain the necessary functions for fronthaul interfaces diff --git a/common/utils/load_module_shlib.c b/common/utils/load_module_shlib.c index b21f39e69d..32d3cfee9b 100644 --- a/common/utils/load_module_shlib.c +++ b/common/utils/load_module_shlib.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include "openair1/PHY/defs.h" @@ -44,55 +45,114 @@ void loader_init(void) { paramdef_t LoaderParams[] = LOADER_PARAMS_DESC; - + loader_data.mainexec_buildversion = PACKAGE_VERSION; int ret = config_get( LoaderParams,sizeof(LoaderParams)/sizeof(paramdef_t),LOADER_CONFIG_PREFIX); if (ret <0) { - fprintf(stderr,"[LOADER] configuration couldn't be performed"); + fprintf(stderr,"[LOADER] %s %d configuration couldn't be performed",__FILE__, __LINE__); if (loader_data.shlibpath == NULL) { loader_data.shlibpath=DEFAULT_PATH; } return; - } + } + loader_data.shlibs = malloc(loader_data.maxshlibs * sizeof(loader_shlibdesc_t)); + if(loader_data.shlibs == NULL) { + fprintf(stderr,"[LOADER] %s %d memory allocation error %s\n",__FILE__, __LINE__,strerror(errno)); + exit_fun("[LOADER] unrecoverable error"); + } + memset(loader_data.shlibs,0,loader_data.maxshlibs * sizeof(loader_shlibdesc_t)); +} + +/* build the full shared lib name from the module name */ +char *loader_format_shlibpath(char *modname) +{ + +char *tmpstr; +char *shlibpath =NULL; +char *shlibversion=NULL; +char *cfgprefix; +paramdef_t LoaderParams[] ={{"shlibpath", NULL, 0, strptr:&shlibpath, defstrval:NULL, TYPE_STRING, 0}, + {"shlibversion", NULL, 0, strptr:&shlibversion, defstrval:"", TYPE_STRING, 0}}; + +int ret; + + + + +/* looks for specific path for this module in the config file */ +/* specific value for a module path and version is located in a modname subsection of the loader section */ +/* shared lib name is formatted as lib.so */ + cfgprefix = malloc(sizeof(LOADER_CONFIG_PREFIX)+strlen(modname)+16); + if (cfgprefix == NULL) { + fprintf(stderr,"[LOADER] %s %d malloc error loading module %s, %s\n",__FILE__, __LINE__, modname, strerror(errno)); + exit_fun("[LOADER] unrecoverable error"); + } else { + sprintf(cfgprefix,LOADER_CONFIG_PREFIX ".%s",modname); + int ret = config_get( LoaderParams,sizeof(LoaderParams)/sizeof(paramdef_t),cfgprefix); + if (ret <0) { + fprintf(stderr,"[LOADER] %s %d couldn't retrieve config from section %s\n",__FILE__, __LINE__,cfgprefix); + } + } +/* no specific path, use loader default shared lib path */ + if (shlibpath == NULL) { + shlibpath = loader_data.shlibpath ; + } + +/* alloc memory for full module shared lib file name */ + tmpstr = malloc(strlen(shlibpath)+strlen(modname)+strlen(shlibversion)+16); + if (tmpstr == NULL) { + fprintf(stderr,"[LOADER] %s %d malloc error loading module %s, %s\n",__FILE__, __LINE__, modname, strerror(errno)); + exit_fun("[LOADER] unrecoverable error"); + } + if(shlibpath[0] != 0) { + ret=sprintf(tmpstr,"%s/",shlibpath); + } else { + ret = 0; + } + + sprintf(tmpstr+ret,"lib%s%s.so",modname,shlibversion); + + + return tmpstr; } int load_module_shlib(char *modname,loader_shlibfunc_t *farray, int numf) { void *lib_handle; initfunc_t fpi; - char *tmpstr; + checkverfunc_t fpc; + char *shlib_path; + char *afname=NULL; int ret=0; if (loader_data.shlibpath == NULL) { loader_init(); } - tmpstr = malloc(strlen(loader_data.shlibpath)+strlen(modname)+16); - if (tmpstr == NULL) { - fprintf(stderr,"[LOADER] %s %d malloc error loading module %s, %s\n",__FILE__, __LINE__, modname, strerror(errno)); - return -1; - } - if(loader_data.shlibpath[0] != 0) { - ret=sprintf(tmpstr,"%s/",loader_data.shlibpath); - } - if(strstr(modname,".so") == NULL) { - sprintf(tmpstr+ret,"lib%s.so",modname); - } else { - sprintf(tmpstr+ret,"%s",modname); - } + shlib_path = loader_format_shlibpath(modname); + ret = 0; - lib_handle = dlopen(tmpstr, RTLD_LAZY|RTLD_NODELETE|RTLD_GLOBAL); + lib_handle = dlopen(shlib_path, RTLD_LAZY|RTLD_NODELETE|RTLD_GLOBAL); if (!lib_handle) { - fprintf(stderr,"[LOADER] library %s is not loaded: %s\n", tmpstr,dlerror()); + fprintf(stderr,"[LOADER] library %s is not loaded: %s\n", shlib_path,dlerror()); ret = -1; } else { - printf("[LOADER] library %s uccessfully loaded loaded\n", tmpstr); - sprintf(tmpstr,"%s_autoinit",modname); - fpi = dlsym(lib_handle,tmpstr); + printf("[LOADER] library %s successfully loaded\n", shlib_path); + afname=malloc(strlen(modname)+15); + sprintf(afname,"%s_checkbuildver",modname); + fpc = dlsym(lib_handle,afname); + if (fpc != NULL ){ + int chkver_ret = fpc(loader_data.mainexec_buildversion, &(loader_data.shlibs[loader_data.numshlibs].shlib_buildversion)); + if (chkver_ret < 0) { + fprintf(stderr,"[LOADER] %s %d lib %s, version mismatch",__FILE__, __LINE__, modname); + exit_fun("[LOADER] unrecoverable error"); + } + } + sprintf(afname,"%s_autoinit",modname); + fpi = dlsym(lib_handle,afname); - if (fpi != NULL ) - { + if (fpi != NULL ) { fpi(); - } + } if (farray != NULL) { for (int i=0; i #include #include -#include +#include "telnetsrv.h" #include #include #include @@ -53,18 +53,25 @@ #include #include "common/config/config_userapi.h" +#include #include "telnetsrv_phycmd.h" #include "telnetsrv_proccmd.h" -static char* telnet_defstatmod[] = {"softmodem","phy"}; +static char* telnet_defstatmod[] = {"softmodem","phy","loader"}; static telnetsrv_params_t telnetparams; #define TELNETSRV_LISTENADDR 0 #define TELNETSRV_LISTENPORT 1 #define TELNETSRV_PRIORITY 2 #define TELNETSRV_DEBUG 3 -#define TELNETSRV_STATICMOD 7 -#define TELNETSRV_SHRMOD 8 +#define TELNETSRV_LOOPC 4 +#define TELNETSRV_LOOPD 5 +#define TELNETSRV_HISFILE 6 +#define TELNETSRV_HISSIZE 7 +#define TELNETSRV_PHYBSIZE 8 +#define TELNETSRV_STATICMOD 9 +#define TELNETSRV_SHRMOD 10 + paramdef_t telnetoptions[] = { /*--------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* configuration parameters for telnet utility */ @@ -72,19 +79,22 @@ paramdef_t telnetoptions[] = { /*--------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ {"listenaddr", "", 0, uptr:&telnetparams.listenaddr, defstrval:"0.0.0.0", TYPE_IPV4ADDR, 0 }, {"listenport", "", 0, uptr:&(telnetparams.listenport), defuintval:9090, TYPE_UINT, 0 }, - {"priority", "", 0, uptr:NULL, defuintval:0, TYPE_UINT, 0 }, {"loopcount", "", 0, uptr:&(telnetparams.loopcount), defuintval:10, TYPE_UINT, 0 }, {"loopdelay", "", 0, uptr:&(telnetparams.loopdelay), defuintval:5000, TYPE_UINT, 0 }, + {"histfile", "", PARAMFLAG_NOFREE, strptr:&(telnetparams.histfile), defstrval:"oaitelnet.history", TYPE_STRING, 0 }, + {"histsize", "", 0, iptr:&(telnetparams.histsize), defuintval:50, TYPE_INT, 0 }, {"phypbsize", "",0, uptr:&(telnetparams.phyprntbuff_size),defuintval:65000, TYPE_UINT, 0 }, - {"staticmod", "", 0, NULL, defstrlistval:telnet_defstatmod,TYPE_STRINGLIST,1}, - {"shrmod", "", 0, NULL, NULL,TYPE_STRINGLIST,0 }, + {"staticmod", "", 0, strlistptr:NULL, defstrlistval:telnet_defstatmod,TYPE_STRINGLIST,(sizeof(telnet_defstatmod)/sizeof(char *))}, + {"shrmod", "", 0, strlistptr:NULL, defstrlistval:NULL,TYPE_STRINGLIST,0 } }; -int get_phybsize() {return telnetparams.phyprntbuff_size; }; +int get_phybsize(void) {return telnetparams.phyprntbuff_size; }; int add_telnetcmd(char *modulename,telnetshell_vardef_t *var, telnetshell_cmddef_t *cmd ); int setoutput(char *buff, int debug, telnet_printfunc_t prnt); int setparam(char *buff, int debug, telnet_printfunc_t prnt); +int history_cmd(char *buff, int debug, telnet_printfunc_t prnt); telnetshell_vardef_t telnet_vardef[] = { {"debug",TELNET_VARTYPE_INT32,&telnetparams.telnetdbg}, @@ -92,12 +102,15 @@ telnetshell_vardef_t telnet_vardef[] = { {"loopc",TELNET_VARTYPE_INT32,&telnetparams.loopcount}, {"loopd",TELNET_VARTYPE_INT32,&telnetparams.loopdelay}, {"phypb",TELNET_VARTYPE_INT32,&telnetparams.phyprntbuff_size}, +{"hsize",TELNET_VARTYPE_INT32,&telnetparams.histsize}, +{"hfile",TELNET_VARTYPE_STRING,&telnetparams.histfile}, {"",0,NULL} }; telnetshell_cmddef_t telnet_cmdarray[] = { {"redirlog","[here,file,off]",setoutput}, {"param","[prio]",setparam}, + {"history","[list,reset]",history_cmd}, {"","",NULL}, }; @@ -131,41 +144,54 @@ char strpolicy[10]; //sched_get_priority_max(SCHED_FIFO) -if (priority < NICE_MIN) - { +if (priority < NICE_MIN) { policy=SCHED_FIFO; sprintf(strpolicy,"%s","fifo"); - schedp.sched_priority= NICE_MIN - priority ; + schedp.sched_priority= NICE_MIN - priority ; + if ( (schedp.sched_priority < sched_get_priority_min(SCHED_FIFO)) || + (schedp.sched_priority > sched_get_priority_max(SCHED_FIFO)) ) { + client_printf("Error: %i invalid prio, should be %i to %i, \n", + priority, NICE_MIN -sched_get_priority_min(SCHED_FIFO), + NICE_MIN - sched_get_priority_max(SCHED_FIFO) ); } -else if (priority > NICE_MAX) - { +} else if (priority > NICE_MAX) { policy=SCHED_IDLE; sprintf(strpolicy,"%s","idle"); schedp.sched_priority=0; - } -else - { +} else { policy=SCHED_OTHER; sprintf(strpolicy,"%s","other"); schedp.sched_priority=0; - } -if( tid != 0) - { +} + +if( tid != 0) { rt = pthread_setschedparam(tid, policy, &schedp); - } -else if(pid > 0) - { +} else if(pid > 0) { rt = sched_setscheduler( pid, policy,&schedp); - } -if (rt != 0) - { +} else { + rt= -1; + client_printf("Error: no pid or tid specified\n"); +} + +if (rt != 0) { client_printf("Error %i: %s modifying sched param to %s:%i, \n", errno,strerror(errno),strpolicy,schedp.sched_priority); - } -else - { +} else { client_printf("policy set to %s, priority %i\n",strpolicy,schedp.sched_priority); + if ( policy==SCHED_OTHER) { + rt = getpriority(PRIO_PROCESS,tid); + if (rt != -1) { + rt = setpriority(PRIO_PROCESS,tid,priority); + if (rt < 0) { + client_printf("Error %i: %s trying to set nice value of thread %u to %i\n", + errno,strerror(errno),tid,priority); + } + } else { + client_printf("Error %i: %s trying to get nice value of thread %u \n", + errno,strerror(errno),tid); + } } +} @@ -198,14 +224,13 @@ int rt; CPU_ZERO(&cpuset); CPU_SET(coreid, &cpuset); - if (tid > 0) - { + if (tid > 0) { rt = pthread_setaffinity_np((pthread_t)tid, sizeof(cpu_set_t), &cpuset); - } - else if (pid > 0) - { + } else if (pid > 0){ rt = sched_setaffinity((pid_t)pid, sizeof(cpu_set_t), &cpuset); - } + } else { + rt= -1; + } if (rt != 0) { client_printf("Error %i: %s calling , xxx_setaffinity...\n",errno,strerror(errno)); @@ -284,7 +309,6 @@ memset(cmds,0,sizeof(cmds)); sscanf(buff,"%9s %9s %9s %9s %9s", cmds[0],cmds[1],cmds[2],cmds[3],cmds[4] ); if (strncasecmp(cmds[0],"prio",4) == 0) { - pthread_attr_t attr; int prio; prio=(int)strtol(cmds[1],NULL,0); if (errno == ERANGE) @@ -305,6 +329,35 @@ if (strncasecmp(cmds[0],"aff",3) == 0) return CMDSTATUS_NOTFOUND; } /* setparam */ + +int history_cmd(char *buff, int debug, telnet_printfunc_t prnt) +{ +char cmds[TELNET_MAX_MSGLENGTH/TELNET_CMD_MAXSIZE][TELNET_CMD_MAXSIZE]; + + +memset(cmds,0,sizeof(cmds)); +sscanf(buff,"%9s %9s %9s %9s %9s", cmds[0],cmds[1],cmds[2],cmds[3],cmds[4] ); +if (cmds[0] == NULL) + return CMDSTATUS_VARNOTFOUND; +if (strncasecmp(cmds[0],"list",4) == 0) + { + HIST_ENTRY **hist = history_list(); + if (hist) { + for (int i = 0; hist[i]; i++) { + prnt ("%d: %s\n", i + history_base, hist[i]->line); + } + } + return CMDSTATUS_FOUND; + } +if (strncasecmp(cmds[0],"reset",5) == 0) + { + clear_history(); + write_history(telnetparams.histfile); + return CMDSTATUS_FOUND; + } + +return CMDSTATUS_NOTFOUND; +} /* history_cmd */ /*-------------------------------------------------------------------------------------------------------*/ /* generic commands available for all modules loaded by the server @@ -314,11 +367,11 @@ int setgetvar(int moduleindex,char getorset,char *params) { int n,i; char varname[TELNET_CMD_MAXSIZE]; -char varval[TELNET_CMD_MAXSIZE]; +char *varval=NULL; memset(varname,0,sizeof(varname)); - memset(varval,0,sizeof(varval)); - n = sscanf(params,"%s %s",varname,varval); + + n = sscanf(params,"%s %ms",varname,&varval); for ( i=0 ; telnetparams.CmdParsers[moduleindex].var[i].varvalptr != NULL ; i++) { if ( strncasecmp(telnetparams.CmdParsers[moduleindex].var[i].varname,varname,strlen(telnetparams.CmdParsers[moduleindex].var[i].varname)) == 0) @@ -330,7 +383,10 @@ char varval[TELNET_CMD_MAXSIZE]; switch(telnetparams.CmdParsers[moduleindex].var[i].vartype) { case TELNET_VARTYPE_INT32: - client_printf("%i\n",*(int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); + client_printf("%i\n",*(int32_t *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); + break; + case TELNET_VARTYPE_INT64: + client_printf("%lli\n",*(int64_t *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); break; case TELNET_VARTYPE_INT16: client_printf("%hi\n",*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); @@ -338,8 +394,8 @@ char varval[TELNET_CMD_MAXSIZE]; case TELNET_VARTYPE_DOUBLE: client_printf("%g\n",*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); break; - case TELNET_VARTYPE_PTR: - client_printf("0x%08x\n",*((unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr))); + case TELNET_VARTYPE_STRING: + client_printf("\"%s\"\n",*(char **)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); break; default: client_printf("unknown type\n"); @@ -364,6 +420,10 @@ char varval[TELNET_CMD_MAXSIZE]; case TELNET_VARTYPE_DOUBLE: *(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = strtod(varval,NULL); client_printf("%g\n",*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); + break; + case TELNET_VARTYPE_STRING: + sprintf(*(char **)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr),"%s", varval); + client_printf("\"%s\"\n",*(char **)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)); break; default: client_printf("unknown type\n"); @@ -372,6 +432,9 @@ char varval[TELNET_CMD_MAXSIZE]; } } } +if (n>1 && varval != NULL) { + free(varval); +} return CMDSTATUS_VARNOTFOUND; } /*----------------------------------------------------------------------------------------------------*/ @@ -515,13 +578,14 @@ if(listen(sock, 1) == -1) fprintf(stderr,"[TELNETSRV] Error %s on listen call\n",strerror(errno)); +using_history(); printf("\nInitializing telnet server...\n"); while( (telnetparams.new_socket = accept(sock, &cli_addr, &cli_len)) ) { printf("[TELNETSRV] Telnet client connected....\n"); - - + read_history(telnetparams.histfile); + stifle_history(telnetparams.histsize); if(telnetparams.new_socket < 0) fprintf(stderr,"[TELNETSRV] Error %s on accept call\n",strerror(errno)); @@ -548,31 +612,43 @@ while( (telnetparams.new_socket = accept(sock, &cli_addr, &cli_len)) ) break; } if (telnetparams.telnetdbg > 0) - printf("[TELNETSRV] Command received: readc %i filled %i %s\n", readc, filled ,buf); - if (strlen(buf) >= 2 ) + printf("[TELNETSRV] Command received: readc %i filled %i \"%s\"\n", readc, filled ,buf); + if (buf[0] == '!') { + if (buf[1] == '!') { + sprintf(buf,"%s","telnet history list"); + } else { + HIST_ENTRY *hisentry = history_get(strtol(buf+1,NULL,0)); + if (hisentry) { + char msg[TELNET_MAX_MSGLENGTH + sizeof(TELNET_PROMPT) +10]; + sprintf(buf,"%s",hisentry->line); + sprintf(msg,"%s %s\n",TELNET_PROMPT, hisentry->line); + send(telnetparams.new_socket, msg, strlen(msg), MSG_NOSIGNAL); + } + } + } + if (strlen(buf) > 2 ) { status=process_command(buf); } else status=CMDSTATUS_NOCMD; - if (status != CMDSTATUS_EXIT) - { - if (status == CMDSTATUS_NOTFOUND) - { + if (status != CMDSTATUS_EXIT) { + if (status == CMDSTATUS_NOTFOUND) { char msg[TELNET_MAX_MSGLENGTH + 50]; sprintf(msg,"Error: \n %s\n is not a softmodem command\n",buf); send(telnetparams.new_socket, msg, strlen(msg), MSG_NOSIGNAL); - } + } else if (status == CMDSTATUS_FOUND) { + add_history(buf); + } send(telnetparams.new_socket, TELNET_PROMPT, sizeof(TELNET_PROMPT), MSG_NOSIGNAL); - } - else - { + } else { printf ("[TELNETSRV] Closing telnet connection...\n"); break; - } + } } - + write_history(telnetparams.histfile); + clear_history(); close(telnetparams.new_socket); printf ("[TELNETSRV] Telnet server waitting for connection...\n"); } @@ -588,7 +664,7 @@ return; */ void exec_moduleinit(char *modname) { -void (*fptr)(); +void (*fptr)(void); char initfunc[TELNET_CMD_MAXSIZE+9]; if (strlen(modname) > TELNET_CMD_MAXSIZE) @@ -609,23 +685,26 @@ char initfunc[TELNET_CMD_MAXSIZE+9]; } } -int add_embeddedmodules() +int add_embeddedmodules(void) { - +int ret=0; for(int i=0; i " #define TELNET_MAXCMD 20 -#define TELNET_CMD_MAXSIZE 10 +#define TELNET_CMD_MAXSIZE 20 #define TELNET_HELPSTR_SIZE 80 /* status return by the command parser after it analysed user input */ @@ -70,7 +69,7 @@ typedef struct cmddef { #define TELNET_VARTYPE_INT64 3 #define TELNET_VARTYPE_STRING 4 #define TELNET_VARTYPE_DOUBLE 5 -#define TELNET_VARTYPE_PTR 6 +//#define TELNET_VARTYPE_PTR 6 typedef struct variabledef { char varname[TELNET_CMD_MAXSIZE]; char vartype; @@ -96,6 +95,8 @@ typedef struct { pthread_t telnet_pthread; // thread id of the telnet server int telnetdbg; // debug level of the server int priority; // server running priority + char *histfile; // command history + int histsize; // command history length int new_socket; // socket of the client connection int logfilefd; // file id of the log file when log output is redirected to a file int saved_stdout; // file id of the previous stdout, used to be able to restore original stdout @@ -134,6 +135,6 @@ VT escape sequence definition, for smarter display.... int add_telnetcmd(char *modulename, telnetshell_vardef_t *var, telnetshell_cmddef_t *cmd); void set_sched(pthread_t tid, int pid,int priority); void set_affinity(pthread_t tid, int pid, int coreid); -extern int get_phybsize(); +extern int get_phybsize(void); #endif #endif diff --git a/common/utils/telnetsrv/telnetsrv_CMakeLists.txt b/common/utils/telnetsrv/telnetsrv_CMakeLists.txt new file mode 100644 index 0000000000..5dee7db4c4 --- /dev/null +++ b/common/utils/telnetsrv/telnetsrv_CMakeLists.txt @@ -0,0 +1,28 @@ + + +set(TELNETROOT ${OPENAIR_DIR}/common/utils/telnetsrv ) + + + +set(TELNETSRV_SOURCE + ${TELNETROOT}/telnetsrv.c + ${TELNETROOT}/telnetsrv_phycmd.c + ${TELNETROOT}/telnetsrv_proccmd.c + ${TELNETROOT}/telnetsrv_loader.c + ) + +#set(TELNETSRV_ETHDEVCMD_SOURCE +# ${APPROOT}/telnetsrv/telnetsrv_ethdevcmd.c +# ) + + + +add_library(telnetsrv MODULE ${TELNETSRV_SOURCE} ) +#add_library(telnetsrv_ethdevcmd MODULE ${TELNETSRV_ETHDEVCMD_SOURCE} ) +target_link_libraries(telnetsrv PRIVATE history) + +install(TARGETS telnetsrv DESTINATION bin) + +if (EXISTS "${OPENAIR_BUILD_DIR}/lte_build_oai/build" AND IS_DIRECTORY "${OPENAIR_BUILD_DIR}/lte_build_oai/build") + install(TARGETS telnetsrv DESTINATION ${OPENAIR_BUILD_DIR}/lte_build_oai/build) +endif (EXISTS "${OPENAIR_BUILD_DIR}/lte_build_oai/build" AND IS_DIRECTORY "${OPENAIR_BUILD_DIR}/lte_build_oai/build") diff --git a/common/utils/telnetsrv/telnetsrv_loader.c b/common/utils/telnetsrv/telnetsrv_loader.c new file mode 100644 index 0000000000..a23e25eb83 --- /dev/null +++ b/common/utils/telnetsrv/telnetsrv_loader.c @@ -0,0 +1,84 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file common/utils/telnetsrv/telnetsrv_loader.c + * \brief: implementation of telnet commands related to softmodem linux process + * \author Francois TABURET + * \date 2018 + * \version 0.1 + * \company NOKIA BellLabs France + * \email: francois.taburet@nokia-bell-labs.com + * \note + * \warning + */ +#define _GNU_SOURCE +#include +#include + + +#define TELNETSERVERCODE +#include "telnetsrv.h" +#define TELNETSRV_LOADER_MAIN +#include "telnetsrv_loader.h" + + +int loader_show_cmd(char *buff, int debug, telnet_printfunc_t prnt); +telnetshell_cmddef_t loader_cmdarray[] = { + {"show","[params,modules]",loader_show_cmd}, + {"","",NULL}, +}; + + +/*-------------------------------------------------------------------------------------*/ +int loader_show_cmd(char *buff, int debug, telnet_printfunc_t prnt) +{ + if (debug > 0) + prnt( "loader_show_cmd received %s\n",buff); + + if (strcasestr(buff,"params") != NULL) { + prnt( "loader parameters:\n"); + prnt( " Main executable build version: \"%s\"\n", loader_data.mainexec_buildversion); + prnt( " Default shared lib path: \"%s\"\n", loader_data.shlibpath); + prnt( " Max number of shared lib : %i\n", loader_data.maxshlibs); + } + else if (strcasestr(buff,"modules") != NULL) { + prnt( "%i shared lib have been dynamicaly loaded by the oai loader\n", loader_data.numshlibs); + for (int i=0 ; i 0) prnt(" proccmd_show received %s\n",buf); - if (strcasestr(buf,"thread") != NULL) - { + if (strcasestr(buf,"thread") != NULL) { print_threads(buf,debug,prnt); - } + } if (strcasestr(buf,"loglvl") != NULL) { - for (int i=MIN_LOG_COMPONENTS; i < MAX_LOG_COMPONENTS; i++){ - prnt("\t%s:\t%s\t%s\n",g_log->log_component[i].name, map_int_to_str(log_verbosity_names,g_log->log_component[i].flag), - map_int_to_str(log_level_names,g_log->log_component[i].level)); + prnt("component verbosity level enabled\n"); + for (int i=MIN_LOG_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) { + prnt("%02i %17.17s:%10.10s%10.10s %s\n",i ,g_log->log_component[i].name, + map_int_to_str(log_verbosity_names,g_log->log_component[i].flag), + map_int_to_str(log_level_names,g_log->log_component[i].level), + ((g_log->log_component[i].interval>0)?"Y":"N") ); + } + } + if (strcasestr(buf,"config") != NULL) { + prnt("Command line arguments:\n"); + for (int i=0; i < config_get_if()->argc; i++) { + prnt(" %02i %s\n",i ,config_get_if()->argv[i]); + } + prnt("Config module flags ( -O ::dbgl): 0x%08x\n", config_get_if()->rtflags); + + prnt(" Print config debug msg, params values (flag %u): %s\n",CONFIG_PRINTPARAMS, + ((config_get_if()->rtflags & CONFIG_PRINTPARAMS) ? "Y" : "N") ); + prnt(" Print config debug msg, memory management(flag %u): %s\n",CONFIG_DEBUGPTR, + ((config_get_if()->rtflags & CONFIG_DEBUGPTR) ? "Y" : "N") ); + prnt(" Print config debug msg, command line processing (flag %u): %s\n",CONFIG_DEBUGCMDLINE, + ((config_get_if()->rtflags & CONFIG_DEBUGCMDLINE) ? "Y" : "N") ); + prnt(" Don't exit if param check fails (flag %u): %s\n",CONFIG_NOABORTONCHKF, + ((config_get_if()->rtflags & CONFIG_NOABORTONCHKF) ? "Y" : "N") ); + prnt("Config source: %s, parameters:\n",CONFIG_GETSOURCE ); + for (int i=0; i < config_get_if()->num_cfgP; i++) { + prnt(" %02i %s\n",i ,config_get_if()->cfgP[i]); + } + prnt("Softmodem components:\n"); + prnt(" %02i Ru(s)\n", RC.nb_RU); + prnt(" %02i lte RRc(s), %02i NbIoT RRC(s)\n", RC.nb_inst, RC.nb_nb_iot_rrc_inst); + prnt(" %02i lte MACRLC(s), %02i NbIoT MACRLC(s)\n", RC.nb_macrlc_inst, RC.nb_nb_iot_macrlc_inst); + prnt(" %02i lte L1, %02i NbIoT L1\n", RC.nb_L1_inst, RC.nb_nb_iot_L1_inst); + + for(int i=0; i 0) prnt("proccmd_thread received %s\n",buf); + if (strcasestr(buf,"help") != NULL) { + prnt(PROCCMD_THREAD_HELP_STRING); + return 0; + } res=sscanf(buf,"%i %9s %i",&bv1,sv1,&bv2); if (debug > 0) prnt(" proccmd_thread: %i params = %i,%s,%i\n",res,bv1,sv1,bv2); @@ -231,32 +297,95 @@ extern void exit_fun(const char* s); return 0; } + int proccmd_log(char *buf, int debug, telnet_printfunc_t prnt) { int idx1=0; int idx2=NUM_LOG_LEVEL-1; -int s = sscanf(buf,"%*s %i-%i",&idx1,&idx2); +char *logsubcmd=NULL; + +int s = sscanf(buf,"%ms %i-%i\n",&logsubcmd, &idx1,&idx2); if (debug > 0) - prnt("process module received %s\n",buf); + prnt( "proccmd_log received %s\n s=%i sub command %s\n",buf,s,((logsubcmd==NULL)?"":logsubcmd)); + + if (s == 1 && logsubcmd != NULL) { + if (strcasestr(logsubcmd,"online") != NULL) { + if (strcasestr(buf,"noonline") != NULL) { + set_glog_onlinelog(0); + prnt("online logging disabled\n",buf); + } else { + set_glog_onlinelog(1); + prnt("online logging enabled\n",buf); + } + } + else if (strcasestr(logsubcmd,"show") != NULL) { + prnt("Available log levels: \n "); + for (int i=0; log_level_names[i].name != NULL; i++) + prnt("%s ",log_level_names[i].name); + prnt("\nAvailable verbosity: \n "); + for (int i=0; log_verbosity_names[i].name != NULL; i++) + prnt("%s ",log_verbosity_names[i].name); + prnt("\n"); + proccmd_show("loglvl",debug,prnt); + } + else if (strcasestr(logsubcmd,"help") != NULL) { + prnt(PROCCMD_LOG_HELP_STRING); + } else { + prnt("%s: wrong log command...\n",logsubcmd); + } + } else if ( s == 3 && logsubcmd != NULL) { + int level, verbosity, interval; + char *tmpstr=NULL; + char *logparam=NULL; + int l; + + level = verbosity = interval = -1; + l=sscanf(logsubcmd,"%m[^'_']_%m[^'_']",&logparam,&tmpstr); + if (debug > 0) + prnt("l=%i, %s %s\n",l,((logparam==NULL)?"\"\"":logparam), ((tmpstr==NULL)?"\"\"":tmpstr)); + if (l ==2 ) { + if (strcmp(logparam,"level") == 0) { + level=map_str_to_int(log_level_names,tmpstr); + if (level < 0) prnt("level %s unknown\n",tmpstr); + } else if (strcmp(logparam,"verbos") == 0) { + verbosity=map_str_to_int(log_verbosity_names,tmpstr); + if (verbosity < 0) prnt("verbosity %s unknown\n",tmpstr); + } else { + prnt("%s%s unknown log sub command \n",logparam, tmpstr); + } + } else if (l ==1 ) { + if (strcmp(logparam,"enable") == 0) { + interval = 1; + } else if (strcmp(logparam,"disable") == 0) { + interval = 0; + } else { + prnt("%s%s unknown log sub command \n",logparam, tmpstr); + } + } else { + prnt("%s unknown log sub command \n",logsubcmd); + } + if (logparam != NULL) free(logparam); + if (tmpstr != NULL) free(tmpstr); + for (int i=idx1; i<=idx2 ; i++) { + set_comp_log(i, level, verbosity, interval); + prnt("log level/verbosity comp %i %s set to %s / %s (%s)\n", + i,((g_log->log_component[i].name==NULL)?"":g_log->log_component[i].name), + map_int_to_str(log_level_names,g_log->log_component[i].level), + map_int_to_str(log_verbosity_names,g_log->log_component[i].flag), + ((g_log->log_component[i].interval>0)?"enabled":"disabled")); + + + } + } else { + prnt("%s: wrong log command...\n",buf); + } - if (strcasestr(buf,"enable") != NULL) - { - set_glog_onlinelog(1); - } - if (strcasestr(buf,"disable") != NULL) - { - set_glog_onlinelog(0); - } - if (strcasestr(buf,"show") != NULL) - { - proccmd_show("loglvl",debug,prnt); - } return 0; } /*-------------------------------------------------------------------------------------*/ -void add_softmodem_cmds() +void add_softmodem_cmds(void) { add_telnetcmd("softmodem",proc_vardef,proc_cmdarray); } diff --git a/common/utils/telnetsrv/telnetsrv_proccmd.h b/common/utils/telnetsrv/telnetsrv_proccmd.h index d7fd0a6e24..b2c05315d8 100644 --- a/common/utils/telnetsrv/telnetsrv_proccmd.h +++ b/common/utils/telnetsrv/telnetsrv_proccmd.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * @@ -19,6 +19,7 @@ * contact@openairinterface.org */ + /*! \file common/utils/telnetsrv/telnetsrv_proccmd.h * \brief: Include file defining telnet commands related to this linux process * \author Francois TABURET @@ -43,15 +44,33 @@ extern int proccmd_log(char *buf, int debug, telnet_printfunc_t prnt); telnetshell_vardef_t proc_vardef[] = { {"",0,NULL} }; +#define PROCCMD_LOG_HELP_STRING " log sub commands: \n\ + show: display current log configuration \n\ + online, noonline: enable or disable console logs \n\ + enable, disable id1-id2: enable or disable logs for components index id1 to id2 \n\ + level_ id1-id2: set log level to for components index id1 to id2 \n\ + level_ id1-id2: set log verbosity to for components index id1 to id2 \n\ +use the show command to get the values for , and the list of component indexes \ +that can be used for id1 and id2 \n" + +#define PROCCMD_THREAD_HELP_STRING " thread sub commands: \n\ + aff : set affinity of thread to core \n\ + prio : set scheduling parameters for thread \n\ + if prio < -20: linux scheduling policy set to FIFO, \n\ + with priority = -20 - prio \n\ + if prio > 19: linux scheduling policy set to OTHER, \n\ + with priority (nice value) = prio \n\ + use \"softmodem show thread\" to get \n" + telnetshell_cmddef_t proc_cmdarray[] = { - {"show","loglvl|thread", proccmd_show}, - {"log","[enable,disable]", proccmd_log}, - {"thread"," aff|prio ", proccmd_thread}, + {"show","loglvl|thread|config", proccmd_show}, + {"log","(enter help for details)", proccmd_log}, + {"thread","(enter help for details)", proccmd_thread}, {"exit","", proccmd_exit}, {"","",NULL}, }; #else -extern void add_proccmd_cmds(); +extern void add_proccmd_cmds(void); #endif /* TELNETSRV_PROCCMD_MAIN */ diff --git a/openair1/PHY/CODING/3gpplte.c b/openair1/PHY/CODING/3gpplte.c index ca63857d72..61acdb2ad9 100644 --- a/openair1/PHY/CODING/3gpplte.c +++ b/openair1/PHY/CODING/3gpplte.c @@ -27,7 +27,9 @@ #ifndef TC_MAIN //#include "defs.h" #endif - +#include +#include +#include "PHY/CODING/defs.h" #include "extern_3GPPinterleaver.h" //#define DEBUG_TURBO_ENCODER 1 @@ -35,7 +37,7 @@ uint32_t threegpplte_interleaver_output; uint32_t threegpplte_interleaver_tmp; -inline void threegpplte_interleaver_reset() +inline void threegpplte_interleaver_reset(void) { threegpplte_interleaver_output = 0; threegpplte_interleaver_tmp = 0; @@ -82,7 +84,7 @@ uint8_t output_lut[16],state_lut[16]; inline uint8_t threegpplte_rsc_lut(uint8_t input,uint8_t *state) { - uint8_t output; + uint8_t off; off = (*state<<1)|input; @@ -146,7 +148,7 @@ void threegpplte_turbo_encoder(uint8_t *input, for (i=0; f1f2mat[i].nb_bits!= input_length_bits && i <188; i++); if ( i == 188 ) { - msg("Illegal frame length!\n"); + printf("Illegal frame length!\n"); return; } else { base_interleaver=il_tb+f1f2mat[i].beg_index; diff --git a/openair1/PHY/CODING/3gpplte_sse.c b/openair1/PHY/CODING/3gpplte_sse.c index 5d87a60477..313d63f7a7 100644 --- a/openair1/PHY/CODING/3gpplte_sse.c +++ b/openair1/PHY/CODING/3gpplte_sse.c @@ -96,7 +96,7 @@ static inline void threegpplte_rsc_termination(unsigned char *x,unsigned char *z *state = (*state)>>1; } -void treillis_table_init(void) +static void treillis_table_init(void) { //struct treillis t[][]=all_treillis; //t=memalign(16,sizeof(struct treillis)*8*256); @@ -536,12 +536,12 @@ char interleave_compact_byte(short * base_interleaver,unsigned char * input, uns } */ -void threegpplte_turbo_encoder(unsigned char *input, - unsigned short input_length_bytes, - unsigned char *output, - unsigned char F, - unsigned short interleaver_f1, - unsigned short interleaver_f2) +void threegpplte_turbo_encoder_sse(unsigned char *input, + unsigned short input_length_bytes, + unsigned char *output, + unsigned char F, + unsigned short interleaver_f1, + unsigned short interleaver_f2) { int i; @@ -641,7 +641,24 @@ void threegpplte_turbo_encoder(unsigned char *input, #endif } - +void init_encoder_sse (void) { + treillis_table_init(); +} +/* function which will be called by the shared lib loader, to check shared lib version + against main exec version. version mismatch no considered as fatal (interfaces not supposed to change) +*/ +int coding_checkbuildver(char * mainexec_buildversion, char ** shlib_buildversion) +{ +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "standalone built: " __DATE__ __TIME__ +#endif + *shlib_buildversion = PACKAGE_VERSION; + if (strcmp(mainexec_buildversion, *shlib_buildversion) != 0) { + fprintf(stderr,"[CODING] shared lib version %s, doesn't match main version %s, compatibility should be checked\n", + mainexec_buildversion,*shlib_buildversion); + } + return 0; +} #ifdef TC_MAIN #define INPUT_LENGTH 20 diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder.c b/openair1/PHY/CODING/3gpplte_turbo_decoder.c index 4470ecca05..6c50e03806 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder.c @@ -550,7 +550,7 @@ void compute_alpha_s(llr_t* alpha,llr_t* m_11,llr_t* m_10,unsigned short frame_l void compute_beta_s(llr_t* beta,llr_t *m_11,llr_t* m_10,llr_t* alpha,unsigned short frame_length,unsigned char F) { - int k,i; + int k; llr_t old0, old1, old2, old3, old4, old5, old6, old7; llr_t new0, new1, new2, new3, new4, new5, new6, new7; llr_t m_b0, m_b1, m_b2, m_b3, m_b4,m_b5, m_b6, m_b7; @@ -897,7 +897,7 @@ unsigned char phy_threegpplte_turbo_decoder_scalar(llr_t *y, unsigned char crc_len,temp; if (crc_type > 3) { - msg("Illegal crc length!\n"); + fprintf(stderr,"Illegal crc length!\n"); return 255; } diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c index 83a50f214b..ef0ca48df4 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c @@ -37,9 +37,9 @@ /// /// -#ifdef __AVX2__ -#include "PHY/sse_intrin.h" + + #ifndef TEST_DEBUG #include "PHY/defs.h" @@ -58,6 +58,8 @@ #include "mex.h" #endif +#ifdef __AVX2__ +#include "PHY/sse_intrin.h" //#define DEBUG_LOGMAP @@ -837,7 +839,7 @@ void free_td16avx2(void) } } -void init_td16avx2() +void init_td16avx2(void) { int ind,i,i2,i3,j,n,pi,pi2_i,pi2_pi; @@ -1408,6 +1410,36 @@ unsigned char phy_threegpplte_turbo_decoder16avx2(int16_t *y, #endif return(iteration_cnt); } +#else //__AVX2__ +unsigned char phy_threegpplte_turbo_decoder16avx2(int16_t *y, + int16_t *y2, + uint8_t *decoded_bytes, + uint8_t *decoded_bytes2, + uint16_t n, + uint16_t f1, + uint16_t f2, + uint8_t max_iterations, + uint8_t crc_type, + uint8_t F, + time_stats_t *init_stats, + time_stats_t *alpha_stats, + time_stats_t *beta_stats, + time_stats_t *gamma_stats, + time_stats_t *ext_stats, + time_stats_t *intl1_stats, + time_stats_t *intl2_stats) +{ + return 0; +} +void free_td16avx2(void) +{ + +} + +void init_td16avx2(void) +{ + +} #endif //__AVX2__ diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c index a32edd711d..63896924dd 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c @@ -1124,7 +1124,7 @@ void free_td16(void) } } -void init_td16() +void init_td16(void) { int ind,i,i2,i3,j,n,pi,pi3; diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c index 4754e26f38..f7b64b767d 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c @@ -849,7 +849,7 @@ void free_td8(void) extern RAN_CONTEXT_t RC; -void init_td8() +void init_td8(void) { int ind,i,j,n,n2,pi,pi3; diff --git a/openair1/PHY/CODING/coding_load.c b/openair1/PHY/CODING/coding_load.c new file mode 100644 index 0000000000..c8aed8cf30 --- /dev/null +++ b/openair1/PHY/CODING/coding_load.c @@ -0,0 +1,134 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file openair1/PHY/CODING + * \brief: load library implementing coding/decoding algorithms + * \author Francois TABURET + * \date 2017 + * \version 0.1 + * \company NOKIA BellLabs France + * \email: francois.taburet@nokia-bell-labs.com + * \note + * \warning + */ +#include +#include "PHY/defs.h" +#include "common/utils/load_module_shlib.h" + + +loader_shlibfunc_t shlib_fdesc[DECODE_NUM_FPTR]; + +decoder_if_t decoder16; +decoder_if_t decoder8; +encoder_if_t encoder; + +extern int _may_i_use_cpu_feature(unsigned __int64); +uint8_t nodecod(short *y, + short *y2, + unsigned char *decoded_bytes, + unsigned char *decoded_bytes2, + unsigned short n, + unsigned short f1, + unsigned short f2, + unsigned char max_iterations, + unsigned char crc_type, + unsigned char F, + time_stats_t *init_stats, + time_stats_t *alpha_stats, + time_stats_t *beta_stats, + time_stats_t *gamma_stats, + time_stats_t *ext_stats, + time_stats_t *intl1_stats, + time_stats_t *intl2_stats) +{ + printf("."); + return max_iterations+1; +}; + +void decoding_setmode (int mode) { + switch (mode) { + case MODE_DECODE_NONE: + decoder8=nodecod; + decoder16=nodecod; + encoder=(encoder_if_t)shlib_fdesc[ENCODE_C_FPTRIDX].fptr; + break; + case MODE_DECODE_SSE: + decoder8=(decoder_if_t)shlib_fdesc[DECODE_TD8_SSE_FPTRIDX].fptr; + decoder16=(decoder_if_t)shlib_fdesc[DECODE_TD16_SSE_FPTRIDX].fptr; + encoder=(encoder_if_t)shlib_fdesc[ENCODE_SSE_FPTRIDX].fptr; + break; + case MODE_DECODE_C: + decoder16=(decoder_if_t)shlib_fdesc[DECODE_TD_C_FPTRIDX].fptr; + decoder8=(decoder_if_t)shlib_fdesc[DECODE_TD_C_FPTRIDX].fptr; + encoder=(encoder_if_t)shlib_fdesc[ENCODE_C_FPTRIDX].fptr; + break; + case MODE_DECODE_AVX2: + decoder16=(decoder_if_t)shlib_fdesc[DECODE_TD16_AVX2_FPTRIDX].fptr; + decoder8=(decoder_if_t)shlib_fdesc[DECODE_TD8_SSE_FPTRIDX].fptr; + encoder=(encoder_if_t)shlib_fdesc[ENCODE_SSE_FPTRIDX].fptr; + break; + } + +} + + +int load_codinglib(void) { + int ret; + + + shlib_fdesc[DECODE_INITTD8_SSE_FPTRIDX].fname = "init_td8"; + shlib_fdesc[DECODE_INITTD16_SSE_FPTRIDX].fname= "init_td16"; + shlib_fdesc[DECODE_INITTD_AVX2_FPTRIDX].fname="init_td16avx2"; + + shlib_fdesc[DECODE_TD8_SSE_FPTRIDX].fname= "phy_threegpplte_turbo_decoder8"; + shlib_fdesc[DECODE_TD16_SSE_FPTRIDX].fname= "phy_threegpplte_turbo_decoder16"; + shlib_fdesc[DECODE_TD_C_FPTRIDX].fname= "phy_threegpplte_turbo_decoder_scalar"; + shlib_fdesc[DECODE_TD16_AVX2_FPTRIDX].fname= "phy_threegpplte_turbo_decoder16avx2"; + + + shlib_fdesc[DECODE_FREETD8_FPTRIDX].fname = "free_td8"; + shlib_fdesc[DECODE_FREETD16_FPTRIDX].fname= "free_td16"; + shlib_fdesc[DECODE_FREETD_AVX2_FPTRIDX].fname= "free_td16avx2"; + + shlib_fdesc[ENCODE_SSE_FPTRIDX].fname= "threegpplte_turbo_encoder_sse"; + shlib_fdesc[ENCODE_C_FPTRIDX].fname= "threegpplte_turbo_encoder"; + shlib_fdesc[ENCODE_INIT_SSE_FPTRIDX].fname= "init_encoder_sse"; + ret=load_module_shlib("coding",shlib_fdesc,DECODE_NUM_FPTR); + if (ret < 0) exit_fun("Error loading coding library"); + +/* execute encoder/decoder init functions */ + shlib_fdesc[DECODE_INITTD8_SSE_FPTRIDX].fptr(); + shlib_fdesc[DECODE_INITTD16_SSE_FPTRIDX].fptr(); + shlib_fdesc[DECODE_INITTD_AVX2_FPTRIDX].fptr(); + shlib_fdesc[ENCODE_INIT_SSE_FPTRIDX].fptr(); + decoding_setmode(MODE_DECODE_SSE); + +return 0; +} + +void free_codinglib(void) { + + shlib_fdesc[DECODE_FREETD8_FPTRIDX].fptr(); + shlib_fdesc[DECODE_FREETD16_FPTRIDX].fptr(); + shlib_fdesc[DECODE_FREETD_AVX2_FPTRIDX].fptr(); + + +} diff --git a/openair1/PHY/CODING/defs.h b/openair1/PHY/CODING/defs.h index 22339953c3..ce13e045f3 100644 --- a/openair1/PHY/CODING/defs.h +++ b/openair1/PHY/CODING/defs.h @@ -292,9 +292,7 @@ void ccodedot11_init(void); \brief This function initializes the trellis structure for decoding an 802.11 convolutional code.*/ void ccodedot11_init_inv(void); -/*!\fn void teillis_table_init(void) -\brief This function initializes the trellis structure for 3GPP LTE Turbo code.*/ -void treillis_table_init(void); + /*\fn void threegpplte_turbo_encoder(uint8_t *input,uint16_t input_length_bytes,uint8_t *output,uint8_t F,uint16_t interleaver_f1,uint16_t interleaver_f2) \brief This function implements a rate 1/3 8-state parralel concatenated turbo code (3GPP-LTE). @@ -352,35 +350,7 @@ void ccodedab_init_inv(void); \brief This function initializes the different crc tables.*/ void crcTableInit (void); -/*!\fn void free_td8(void) -\brief This function frees the tables for 8-bit LLR Turbo decoder.*/ -void free_td8(void); -/*!\fn void init_td8(void) -\brief This function initializes the tables for 8-bit LLR Turbo decoder.*/ -void init_td8 (void); - -/*!\fn void free_td16(void) -\brief This function frees the tables for 16-bit LLR Turbo decoder.*/ -void free_td16(void); - -/*!\fn void init_td16(void) -\brief This function initializes the tables for 16-bit LLR Turbo decoder.*/ -void init_td16 (void); - -#ifdef __AVX2__ -/*!\fn void init_td8(void) -\brief This function initializes the tables for 8-bit LLR Turbo decoder (AVX2).*/ -void init_td8avx2 (void); - -/*!\fn void free_td16avx2(void) -\brief This function frees the tables for 16-bit LLR Turbo decoder (AVX2).*/ -void free_td16avx2(void); - -/*!\fn void init_td16(void) -\brief This function initializes the tables for 16-bit LLR Turbo decoder (AVX2).*/ -void init_td16avx2 (void); -#endif /*!\fn uint32_t crc24a(uint8_t *inPtr, int32_t bitlen) \brief This computes a 24-bit crc ('a' variant for overall transport block) diff --git a/openair1/PHY/CODING/extern.h b/openair1/PHY/CODING/extern.h index 9c58920a10..0d3e2ccb02 100644 --- a/openair1/PHY/CODING/extern.h +++ b/openair1/PHY/CODING/extern.h @@ -20,5 +20,9 @@ */ extern unsigned short f1f2mat_old[2*188]; - - +extern double cpuf; +extern decoder_if_t decoder16; +extern decoder_if_t decoder8; +extern encoder_if_t encoder; +extern int load_codinglib(void); +extern int free_codinglib(void); diff --git a/openair1/PHY/INIT/init_top.c b/openair1/PHY/INIT/init_top.c index a1edd9d1ea..34e82771b4 100644 --- a/openair1/PHY/INIT/init_top.c +++ b/openair1/PHY/INIT/init_top.c @@ -34,15 +34,12 @@ void init_lte_top(LTE_DL_FRAME_PARMS *frame_parms) ccodelte_init(); ccodelte_init_inv(); - treillis_table_init(); + phy_generate_viterbi_tables(); phy_generate_viterbi_tables_lte(); - init_td8(); - init_td16(); -#ifdef __AVX2__ - init_td16avx2(); -#endif + + load_codinglib(); lte_sync_time_init(frame_parms); generate_ul_ref_sigs(); @@ -61,11 +58,7 @@ void init_lte_top(LTE_DL_FRAME_PARMS *frame_parms) void free_lte_top(void) { - free_td8(); - free_td16(); -#ifdef __AVX2__ - free_td16avx2(); -#endif + free_codinglib(); lte_sync_time_free(); /* free_ul_ref_sigs() is called in phy_free_lte_eNB() */ diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index 7f8c0058ea..e91665e04e 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -286,13 +286,13 @@ int dlsch_encoding_2threads0(te_params *tep) { - threegpplte_turbo_encoder(dlsch->harq_processes[harq_pid]->c[r], - Kr>>3, - &dlsch->harq_processes[harq_pid]->d[r][96], - (r==0) ? dlsch->harq_processes[harq_pid]->F : 0, - f1f2mat_old[iind*2], // f1 (see 36121-820, page 14) - f1f2mat_old[(iind*2)+1] // f2 (see 36121-820, page 14) - ); + encoder(dlsch->harq_processes[harq_pid]->c[r], + Kr>>3, + &dlsch->harq_processes[harq_pid]->d[r][96], + (r==0) ? dlsch->harq_processes[harq_pid]->F : 0, + f1f2mat_old[iind*2], // f1 (see 36121-820, page 14) + f1f2mat_old[(iind*2)+1] // f2 (see 36121-820, page 14) + ); dlsch->harq_processes[harq_pid]->RTC[r] = sub_block_interleaving_turbo(4+(Kr_bytes*8), &dlsch->harq_processes[harq_pid]->d[r][96], @@ -458,13 +458,13 @@ int dlsch_encoding_2threads(PHY_VARS_eNB *eNB, start_meas(te_stats); - threegpplte_turbo_encoder(dlsch->harq_processes[harq_pid]->c[r], - Kr>>3, - &dlsch->harq_processes[harq_pid]->d[r][96], - (r==0) ? dlsch->harq_processes[harq_pid]->F : 0, - f1f2mat_old[iind*2], // f1 (see 36121-820, page 14) - f1f2mat_old[(iind*2)+1] // f2 (see 36121-820, page 14) - ); + encoder(dlsch->harq_processes[harq_pid]->c[r], + Kr>>3, + &dlsch->harq_processes[harq_pid]->d[r][96], + (r==0) ? dlsch->harq_processes[harq_pid]->F : 0, + f1f2mat_old[iind*2], // f1 (see 36121-820, page 14) + f1f2mat_old[(iind*2)+1] // f2 (see 36121-820, page 14) + ); stop_meas(te_stats); start_meas(i_stats); @@ -651,13 +651,13 @@ int dlsch_encoding(PHY_VARS_eNB *eNB, printf("Encoding ... iind %d f1 %d, f2 %d\n",iind,f1f2mat_old[iind*2],f1f2mat_old[(iind*2)+1]); #endif start_meas(te_stats); - threegpplte_turbo_encoder(dlsch->harq_processes[harq_pid]->c[r], - Kr>>3, - &dlsch->harq_processes[harq_pid]->d[r][96], - (r==0) ? dlsch->harq_processes[harq_pid]->F : 0, - f1f2mat_old[iind*2], // f1 (see 36121-820, page 14) - f1f2mat_old[(iind*2)+1] // f2 (see 36121-820, page 14) - ); + encoder(dlsch->harq_processes[harq_pid]->c[r], + Kr>>3, + &dlsch->harq_processes[harq_pid]->d[r][96], + (r==0) ? dlsch->harq_processes[harq_pid]->F : 0, + f1f2mat_old[iind*2], // f1 (see 36121-820, page 14) + f1f2mat_old[(iind*2)+1] // f2 (see 36121-820, page 14) + ); stop_meas(te_stats); #ifdef DEBUG_DLSCH_CODING @@ -833,13 +833,13 @@ int dlsch_encoding_SIC(PHY_VARS_UE *ue, printf("Encoding ... iind %d f1 %d, f2 %d\n",iind,f1f2mat_old[iind*2],f1f2mat_old[(iind*2)+1]); #endif start_meas(te_stats); - threegpplte_turbo_encoder(dlsch->harq_processes[harq_pid]->c[r], - Kr>>3, - &dlsch->harq_processes[harq_pid]->d[r][96], - (r==0) ? dlsch->harq_processes[harq_pid]->F : 0, - f1f2mat_old[iind*2], // f1 (see 36121-820, page 14) - f1f2mat_old[(iind*2)+1] // f2 (see 36121-820, page 14) - ); + encoder(dlsch->harq_processes[harq_pid]->c[r], + Kr>>3, + &dlsch->harq_processes[harq_pid]->d[r][96], + (r==0) ? dlsch->harq_processes[harq_pid]->F : 0, + f1f2mat_old[iind*2], // f1 (see 36121-820, page 14) + f1f2mat_old[(iind*2)+1] // f2 (see 36121-820, page 14) + ); stop_meas(te_stats); #ifdef DEBUG_DLSCH_CODING diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c index 697164110b..4020056e6f 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c @@ -39,7 +39,6 @@ //#define DEBUG_DLSCH_DECODING //#define UE_DEBUG_TRACE 1 -extern double cpuf; void free_ue_dlsch(LTE_UE_DLSCH_t *dlsch) { @@ -206,21 +205,7 @@ uint32_t dlsch_decoding(PHY_VARS_UE *phy_vars_ue, time_stats_t *); #endif - uint8_t (*tc)(int16_t *y, - uint8_t *, - uint16_t, - uint16_t, - uint16_t, - uint8_t, - uint8_t, - uint8_t, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *); +decoder_if_t tc; @@ -255,13 +240,13 @@ uint32_t dlsch_decoding(PHY_VARS_UE *phy_vars_ue, #if 0 tc_2cw = phy_threegpplte_turbo_decoder16avx2; #endif - tc = phy_threegpplte_turbo_decoder16; + tc = decoder16; } else { AssertFatal (harq_process->TBS >= 256 , "Mismatch flag nbRB=%d TBS=%d mcs=%d Qm=%d RIV=%d round=%d \n", harq_process->nb_rb, harq_process->TBS,harq_process->mcs,harq_process->Qm,harq_process->rvidx,harq_process->round); - tc = phy_threegpplte_turbo_decoder8; + tc = decoder8; } @@ -490,7 +475,9 @@ uint32_t dlsch_decoding(PHY_VARS_UE *phy_vars_ue, LOG_D(PHY,"AbsSubframe %d.%d Start turbo segment %d/%d \n",frame%1024,subframe,r,harq_process->C-1); ret = tc (&harq_process->d[r][96], + NULL, harq_process->c[r], + NULL, Kr, f1f2mat_old[iind*2], f1f2mat_old[(iind*2)+1], diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c index 9b761f3cc3..09420f48ab 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c @@ -371,13 +371,13 @@ uint32_t ulsch_encoding(uint8_t *a, printf("Encoding ... iind %d f1 %d, f2 %d\n",iind,f1f2mat_old[iind*2],f1f2mat_old[(iind*2)+1]); #endif start_meas(te_stats); - threegpplte_turbo_encoder(ulsch->harq_processes[harq_pid]->c[r], - Kr>>3, - &ulsch->harq_processes[harq_pid]->d[r][96], - (r==0) ? ulsch->harq_processes[harq_pid]->F : 0, - f1f2mat_old[iind*2], // f1 (see 36212-820, page 14) - f1f2mat_old[(iind*2)+1] // f2 (see 36212-820, page 14) - ); + encoder(ulsch->harq_processes[harq_pid]->c[r], + Kr>>3, + &ulsch->harq_processes[harq_pid]->d[r][96], + (r==0) ? ulsch->harq_processes[harq_pid]->F : 0, + f1f2mat_old[iind*2], // f1 (see 36212-820, page 14) + f1f2mat_old[(iind*2)+1] // f2 (see 36212-820, page 14) + ); stop_meas(te_stats); #ifdef DEBUG_ULSCH_CODING diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index 57087051d3..0d9bf8fd76 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -242,27 +242,12 @@ int ulsch_decoding_data_2thread0(td_params* tdp) { uint32_t E=0; uint32_t Gp,GpmodC,Nl=1; uint32_t C = ulsch_harq->C; - - uint8_t (*tc)(int16_t *y, - uint8_t *, - uint16_t, - uint16_t, - uint16_t, - uint8_t, - uint8_t, - uint8_t, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *); + decoder_if_t tc; if (llr8_flag == 0) - tc = phy_threegpplte_turbo_decoder16; + tc = decoder16; else - tc = phy_threegpplte_turbo_decoder8; + tc = decoder8; @@ -385,7 +370,9 @@ int ulsch_decoding_data_2thread0(td_params* tdp) { ret = tc(&ulsch_harq->d[r][96], + NULL, ulsch_harq->c[r], + NULL, Kr, f1f2mat_old[iind*2], f1f2mat_old[(iind*2)+1], @@ -463,22 +450,7 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr int G = ulsch_harq->G; unsigned int E; int Cby2; - - uint8_t (*tc)(int16_t *y, - uint8_t *, - uint16_t, - uint16_t, - uint16_t, - uint8_t, - uint8_t, - uint8_t, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *); + decoder_if_t tc; struct timespec wait; @@ -487,9 +459,9 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr if (llr8_flag == 0) - tc = phy_threegpplte_turbo_decoder16; + tc = decoder16; else - tc = phy_threegpplte_turbo_decoder8; + tc = decoder8; if (ulsch_harq->C>1) { // wakeup worker if more than 1 segment if (pthread_mutex_timedlock(&proc->mutex_td,&wait) != 0) { @@ -608,7 +580,9 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr start_meas(&eNB->ulsch_turbo_decoding_stats); ret = tc(&ulsch_harq->d[r][96], + NULL, ulsch_harq->c[r], + NULL, Kr, f1f2mat_old[iind*2], f1f2mat_old[(iind*2)+1], @@ -670,27 +644,12 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) int G = ulsch_harq->G; unsigned int E; - - uint8_t (*tc)(int16_t *y, - uint8_t *, - uint16_t, - uint16_t, - uint16_t, - uint8_t, - uint8_t, - uint8_t, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *, - time_stats_t *); + decoder_if_t tc; if (llr8_flag == 0) - tc = phy_threegpplte_turbo_decoder16; + tc = *decoder16; else - tc = phy_threegpplte_turbo_decoder8; + tc = *decoder8; for (r=0; rC; r++) { @@ -773,7 +732,9 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) start_meas(&eNB->ulsch_turbo_decoding_stats); ret = tc(&ulsch_harq->d[r][96], + NULL, ulsch_harq->c[r], + NULL, Kr, f1f2mat_old[iind*2], f1f2mat_old[(iind*2)+1], diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 46f37e9431..a12a0fd210 100644 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -1461,6 +1461,53 @@ extern pthread_cond_t sync_cond; extern pthread_mutex_t sync_mutex; extern int sync_var; + +#define MODE_DECODE_NONE 0 +#define MODE_DECODE_SSE 1 +#define MODE_DECODE_C 2 +#define MODE_DECODE_AVX2 3 + +#define DECODE_INITTD8_SSE_FPTRIDX 0 +#define DECODE_INITTD16_SSE_FPTRIDX 1 +#define DECODE_INITTD_AVX2_FPTRIDX 2 +#define DECODE_TD8_SSE_FPTRIDX 3 +#define DECODE_TD16_SSE_FPTRIDX 4 +#define DECODE_TD_C_FPTRIDX 5 +#define DECODE_TD16_AVX2_FPTRIDX 6 +#define DECODE_FREETD8_FPTRIDX 7 +#define DECODE_FREETD16_FPTRIDX 8 +#define DECODE_FREETD_AVX2_FPTRIDX 9 +#define ENCODE_SSE_FPTRIDX 10 +#define ENCODE_C_FPTRIDX 11 +#define ENCODE_INIT_SSE_FPTRIDX 12 +#define DECODE_NUM_FPTR 13 + + +typedef uint8_t(*decoder_if_t)(int16_t *y, + int16_t *y2, + uint8_t *decoded_bytes, + uint8_t *decoded_bytes2, + uint16_t n, + uint16_t f1, + uint16_t f2, + uint8_t max_iterations, + uint8_t crc_type, + uint8_t F, + time_stats_t *init_stats, + time_stats_t *alpha_stats, + time_stats_t *beta_stats, + time_stats_t *gamma_stats, + time_stats_t *ext_stats, + time_stats_t *intl1_stats, + time_stats_t *intl2_stats); + +typedef uint8_t(*encoder_if_t)(uint8_t *input, + uint16_t input_length_bytes, + uint8_t *output, + uint8_t F, + uint16_t interleaver_f1, + uint16_t interleaver_f2); + #define MAX_RRU_CONFIG_SIZE 1024 typedef enum { RAU_tick=0, diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 912e756f76..6c2e580947 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -650,7 +650,7 @@ void uci_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) { LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; uint8_t SR_payload = 0,pucch_b0b1[4][2]= {{0,0},{0,0},{0,0},{0,0}},harq_ack[4]={0,0,0,0}; - int32_t metric[4]={0,0,0,0},metric_SR=0,max_metric; + int32_t metric[4]={0,0,0,0},metric_SR=0,max_metric=0; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; int i; diff --git a/openair2/ENB_APP/L1_paramdef.h b/openair2/ENB_APP/L1_paramdef.h new file mode 100644 index 0000000000..8eef55b718 --- /dev/null +++ b/openair2/ENB_APP/L1_paramdef.h @@ -0,0 +1,73 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file openair2/ENB_APP/L1_paramdef.f + * \brief definition of configuration parameters for all eNodeB modules + * \author Francois TABURET + * \date 2017 + * \version 0.1 + * \company NOKIA BellLabs France + * \email: francois.taburet@nokia-bell-labs.com + * \note + * \warning + */ + + +/*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ + + +/* L1 configuration parameters names */ +#define CONFIG_STRING_L1_CC "num_cc" +#define CONFIG_STRING_L1_LOCAL_N_IF_NAME "local_n_if_name" +#define CONFIG_STRING_L1_LOCAL_N_ADDRESS "local_n_address" +#define CONFIG_STRING_L1_REMOTE_N_ADDRESS "remote_n_address" +#define CONFIG_STRING_L1_LOCAL_N_PORTC "local_n_portc" +#define CONFIG_STRING_L1_REMOTE_N_PORTC "remote_n_portc" +#define CONFIG_STRING_L1_LOCAL_N_PORTD "local_n_portd" +#define CONFIG_STRING_L1_REMOTE_N_PORTD "remote_n_portd" +#define CONFIG_STRING_L1_TRANSPORT_N_PREFERENCE "tr_n_preference" + +/*----------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* L1 configuration parameters */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*----------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define L1PARAMS_DESC { \ +{CONFIG_STRING_L1_CC, NULL, 0, uptr:NULL, defintval:1, TYPE_UINT, 0}, \ +{CONFIG_STRING_L1_TRANSPORT_N_PREFERENCE, NULL, 0, strptr:NULL, defstrval:"local_mac", TYPE_STRING, 0}, \ +{CONFIG_STRING_L1_LOCAL_N_IF_NAME, NULL, 0, strptr:NULL, defstrval:"lo", TYPE_STRING, 0}, \ +{CONFIG_STRING_L1_LOCAL_N_ADDRESS, NULL, 0, strptr:NULL, defstrval:"127.0.0.1", TYPE_STRING, 0}, \ +{CONFIG_STRING_L1_REMOTE_N_ADDRESS, NULL, 0, strptr:NULL, defstrval:"127.0.0.2", TYPE_STRING, 0}, \ +{CONFIG_STRING_L1_LOCAL_N_PORTC, NULL, 0, uptr:NULL, defintval:50030, TYPE_UINT, 0}, \ +{CONFIG_STRING_L1_REMOTE_N_PORTC, NULL, 0, uptr:NULL, defintval:50030, TYPE_UINT, 0}, \ +{CONFIG_STRING_L1_LOCAL_N_PORTD, NULL, 0, uptr:NULL, defintval:50031, TYPE_UINT, 0}, \ +{CONFIG_STRING_L1_REMOTE_N_PORTD, NULL, 0, uptr:NULL, defintval:50031, TYPE_UINT, 0}, \ +} +#define L1_CC_IDX 0 +#define L1_TRANSPORT_N_PREFERENCE_IDX 1 +#define L1_LOCAL_N_IF_NAME_IDX 2 +#define L1_LOCAL_N_ADDRESS_IDX 3 +#define L1_REMOTE_N_ADDRESS_IDX 4 +#define L1_LOCAL_N_PORTC_IDX 5 +#define L1_REMOTE_N_PORTC_IDX 6 +#define L1_LOCAL_N_PORTD_IDX 7 +#define L1_REMOTE_N_PORTD_IDX 8 + +/*----------------------------------------------------------------------------------------------------------------------------------------------------*/ diff --git a/openair2/ENB_APP/MACRLC_paramdef.h b/openair2/ENB_APP/MACRLC_paramdef.h new file mode 100644 index 0000000000..868917a0ab --- /dev/null +++ b/openair2/ENB_APP/MACRLC_paramdef.h @@ -0,0 +1,98 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file openair2/ENB_APP/MACRLC_paramdef.f + * \brief definition of configuration parameters for all eNodeB modules + * \author Francois TABURET + * \date 2017 + * \version 0.1 + * \company NOKIA BellLabs France + * \email: francois.taburet@nokia-bell-labs.com + * \note + * \warning + */ + + + +/*----------------------------------------------------------------------------------------------------------------------------------------------------*/ + + +/* MACRLC configuration parameters names */ +#define CONFIG_STRING_MACRLC_CC "num_cc" +#define CONFIG_STRING_MACRLC_TRANSPORT_N_PREFERENCE "tr_n_preference" +#define CONFIG_STRING_MACRLC_LOCAL_N_IF_NAME "local_n_if_name" +#define CONFIG_STRING_MACRLC_LOCAL_N_ADDRESS "local_n_address" +#define CONFIG_STRING_MACRLC_REMOTE_N_ADDRESS "remote_n_address" +#define CONFIG_STRING_MACRLC_LOCAL_N_PORTC "local_n_portc" +#define CONFIG_STRING_MACRLC_REMOTE_N_PORTC "remote_n_portc" +#define CONFIG_STRING_MACRLC_LOCAL_N_PORTD "local_n_portd" +#define CONFIG_STRING_MACRLC_REMOTE_N_PORTD "remote_n_portd" +#define CONFIG_STRING_MACRLC_TRANSPORT_S_PREFERENCE "tr_s_preference" +#define CONFIG_STRING_MACRLC_LOCAL_S_IF_NAME "local_s_if_name" +#define CONFIG_STRING_MACRLC_LOCAL_S_ADDRESS "local_s_address" +#define CONFIG_STRING_MACRLC_REMOTE_S_ADDRESS "remote_s_address" +#define CONFIG_STRING_MACRLC_LOCAL_S_PORTC "local_s_portc" +#define CONFIG_STRING_MACRLC_REMOTE_S_PORTC "remote_s_portc" +#define CONFIG_STRING_MACRLC_LOCAL_S_PORTD "local_s_portd" +#define CONFIG_STRING_MACRLC_REMOTE_S_PORTD "remote_s_portd" + + +/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* MacRLC configuration parameters */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define MACRLCPARAMS_DESC { \ +{CONFIG_STRING_MACRLC_CC, NULL, 0, uptr:NULL, defintval:50011, TYPE_UINT, 0}, \ +{CONFIG_STRING_MACRLC_TRANSPORT_N_PREFERENCE, NULL, 0, strptr:NULL, defstrval:"local_L1", TYPE_STRING, 0}, \ +{CONFIG_STRING_MACRLC_LOCAL_N_IF_NAME, NULL, 0, strptr:NULL, defstrval:"lo", TYPE_STRING, 0}, \ +{CONFIG_STRING_MACRLC_LOCAL_N_ADDRESS, NULL, 0, strptr:NULL, defstrval:"127.0.0.1", TYPE_STRING, 0}, \ +{CONFIG_STRING_MACRLC_REMOTE_N_ADDRESS, NULL, 0, uptr:NULL, defstrval:"127.0.0.2", TYPE_STRING, 0}, \ +{CONFIG_STRING_MACRLC_LOCAL_N_PORTC, NULL, 0, uptr:NULL, defintval:50010, TYPE_UINT, 0}, \ +{CONFIG_STRING_MACRLC_REMOTE_N_PORTC, NULL, 0, uptr:NULL, defintval:50010, TYPE_UINT, 0}, \ +{CONFIG_STRING_MACRLC_LOCAL_N_PORTD, NULL, 0, uptr:NULL, defintval:50011, TYPE_UINT, 0}, \ +{CONFIG_STRING_MACRLC_REMOTE_N_PORTD, NULL, 0, uptr:NULL, defintval:50011, TYPE_UINT, 0}, \ +{CONFIG_STRING_MACRLC_TRANSPORT_S_PREFERENCE, NULL, 0, strptr:NULL, defstrval:"local_RRC", TYPE_STRING, 0}, \ +{CONFIG_STRING_MACRLC_LOCAL_S_IF_NAME, NULL, 0, strptr:NULL, defstrval:"lo", TYPE_STRING, 0}, \ +{CONFIG_STRING_MACRLC_LOCAL_S_ADDRESS, NULL, 0, uptr:NULL, defstrval:"127.0.0.1", TYPE_STRING, 0}, \ +{CONFIG_STRING_MACRLC_REMOTE_S_ADDRESS, NULL, 0, uptr:NULL, defstrval:"127.0.0.2", TYPE_STRING, 0}, \ +{CONFIG_STRING_MACRLC_LOCAL_S_PORTC, NULL, 0, uptr:NULL, defintval:50020, TYPE_UINT, 0}, \ +{CONFIG_STRING_MACRLC_REMOTE_S_PORTC, NULL, 0, uptr:NULL, defintval:50020, TYPE_UINT, 0}, \ +{CONFIG_STRING_MACRLC_LOCAL_S_PORTD, NULL, 0, uptr:NULL, defintval:50021, TYPE_UINT, 0}, \ +{CONFIG_STRING_MACRLC_REMOTE_S_PORTD, NULL, 0, uptr:NULL, defintval:50021, TYPE_UINT, 0}, \ +} +#define MACRLC_CC_IDX 0 +#define MACRLC_TRANSPORT_N_PREFERENCE_IDX 1 +#define MACRLC_LOCAL_N_IF_NAME_IDX 2 +#define MACRLC_LOCAL_N_ADDRESS_IDX 3 +#define MACRLC_REMOTE_N_ADDRESS_IDX 4 +#define MACRLC_LOCAL_N_PORTC_IDX 5 +#define MACRLC_REMOTE_N_PORTC_IDX 6 +#define MACRLC_LOCAL_N_PORTD_IDX 7 +#define MACRLC_REMOTE_N_PORTD_IDX 8 +#define MACRLC_TRANSPORT_S_PREFERENCE_IDX 9 +#define MACRLC_LOCAL_S_IF_NAME_IDX 10 +#define MACRLC_LOCAL_S_ADDRESS_IDX 11 +#define MACRLC_REMOTE_S_ADDRESS_IDX 12 +#define MACRLC_LOCAL_S_PORTC_IDX 13 +#define MACRLC_REMOTE_S_PORTC_IDX 14 +#define MACRLC_LOCAL_S_PORTD_IDX 15 +#define MACRLC_REMOTE_S_PORTD_IDX 16 +/*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ diff --git a/openair2/ENB_APP/RRC_config_tools.c b/openair2/ENB_APP/RRC_config_tools.c new file mode 100644 index 0000000000..17fbad1e18 --- /dev/null +++ b/openair2/ENB_APP/RRC_config_tools.c @@ -0,0 +1,123 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/* + RRC_config_tools.c + ------------------- + AUTHOR : Francois TABURET + COMPANY : NOKIA BellLabs France + EMAIL : francois.taburet@nokia-bell-labs.com + +*/ + +#include +#include + +#include "log.h" +#include "log_extern.h" +#include "assertions.h" +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +# if defined(ENABLE_USE_MME) +# include "s1ap_eNB.h" +# include "sctp_eNB_task.h" +# endif +#endif +#include "SystemInformationBlockType2.h" +#include "common/config/config_userapi.h" +#include "RRC_config_tools.h" +#include "DL-GapConfig-NB-r13.h" +#include "NPRACH-Parameters-NB-r13.h" + +static const eutra_band_t eutra_bands[] = { + { 1, 1920 * MHz, 1980 * MHz, 2110 * MHz, 2170 * MHz, FDD}, + { 2, 1850 * MHz, 1910 * MHz, 1930 * MHz, 1990 * MHz, FDD}, + { 3, 1710 * MHz, 1785 * MHz, 1805 * MHz, 1880 * MHz, FDD}, + { 4, 1710 * MHz, 1755 * MHz, 2110 * MHz, 2155 * MHz, FDD}, + { 5, 824 * MHz, 849 * MHz, 869 * MHz, 894 * MHz, FDD}, + { 6, 830 * MHz, 840 * MHz, 875 * MHz, 885 * MHz, FDD}, + { 7, 2500 * MHz, 2570 * MHz, 2620 * MHz, 2690 * MHz, FDD}, + { 8, 880 * MHz, 915 * MHz, 925 * MHz, 960 * MHz, FDD}, + { 9, 1749900 * KHz, 1784900 * KHz, 1844900 * KHz, 1879900 * KHz, FDD}, + {10, 1710 * MHz, 1770 * MHz, 2110 * MHz, 2170 * MHz, FDD}, + {11, 1427900 * KHz, 1452900 * KHz, 1475900 * KHz, 1500900 * KHz, FDD}, + {12, 698 * MHz, 716 * MHz, 728 * MHz, 746 * MHz, FDD}, + {13, 777 * MHz, 787 * MHz, 746 * MHz, 756 * MHz, FDD}, + {14, 788 * MHz, 798 * MHz, 758 * MHz, 768 * MHz, FDD}, + + {17, 704 * MHz, 716 * MHz, 734 * MHz, 746 * MHz, FDD}, + {20, 832 * MHz, 862 * MHz, 791 * MHz, 821 * MHz, FDD}, + {33, 1900 * MHz, 1920 * MHz, 1900 * MHz, 1920 * MHz, TDD}, + {33, 1900 * MHz, 1920 * MHz, 1900 * MHz, 1920 * MHz, TDD}, + {34, 2010 * MHz, 2025 * MHz, 2010 * MHz, 2025 * MHz, TDD}, + {35, 1850 * MHz, 1910 * MHz, 1850 * MHz, 1910 * MHz, TDD}, + {36, 1930 * MHz, 1990 * MHz, 1930 * MHz, 1990 * MHz, TDD}, + {37, 1910 * MHz, 1930 * MHz, 1910 * MHz, 1930 * MHz, TDD}, + {38, 2570 * MHz, 2620 * MHz, 2570 * MHz, 2630 * MHz, TDD}, + {39, 1880 * MHz, 1920 * MHz, 1880 * MHz, 1920 * MHz, TDD}, + {40, 2300 * MHz, 2400 * MHz, 2300 * MHz, 2400 * MHz, TDD}, + {41, 2496 * MHz, 2690 * MHz, 2496 * MHz, 2690 * MHz, TDD}, + {42, 3400 * MHz, 3600 * MHz, 3400 * MHz, 3600 * MHz, TDD}, + {43, 3600 * MHz, 3800 * MHz, 3600 * MHz, 3800 * MHz, TDD}, + {44, 703 * MHz, 803 * MHz, 703 * MHz, 803 * MHz, TDD}, +}; + + +int config_check_band_frequencies( int ind, + int16_t band, + uint32_t downlink_frequency, + int32_t uplink_frequency_offset, + uint32_t frame_type) +{ + int errors = 0; + + if (band > 0) { + int band_index; + + for (band_index = 0; band_index < sizeof (eutra_bands) / sizeof (eutra_bands[0]); band_index++) { + if (band == eutra_bands[band_index].band) { + uint32_t uplink_frequency = downlink_frequency + uplink_frequency_offset; + + AssertError (eutra_bands[band_index].dl_min < downlink_frequency, errors ++, + "enb %d downlink frequency %u too low (%u) for band %d!", + ind, downlink_frequency, eutra_bands[band_index].dl_min, band); + AssertError (downlink_frequency < eutra_bands[band_index].dl_max, errors ++, + "enb %d downlink frequency %u too high (%u) for band %d!", + ind, downlink_frequency, eutra_bands[band_index].dl_max, band); + + AssertError (eutra_bands[band_index].ul_min < uplink_frequency, errors ++, + "enb %d uplink frequency %u too low (%u) for band %d!", + ind, uplink_frequency, eutra_bands[band_index].ul_min, band); + AssertError (uplink_frequency < eutra_bands[band_index].ul_max, errors ++, + "enb %d uplink frequency %u too high (%u) for band %d!", + ind, uplink_frequency, eutra_bands[band_index].ul_max, band); + + AssertError (eutra_bands[band_index].frame_type == frame_type, errors ++, + "enb %d invalid frame type (%d/%d) for band %d!", + ind, eutra_bands[band_index].frame_type, frame_type, band); + } + } + } + + + return errors; +} + diff --git a/openair2/ENB_APP/RRC_config_tools.h b/openair2/ENB_APP/RRC_config_tools.h new file mode 100644 index 0000000000..a44da1f90c --- /dev/null +++ b/openair2/ENB_APP/RRC_config_tools.h @@ -0,0 +1,50 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/* + RRC_config_tools.h + ------------------- + AUTHOR : Francois TABURET + COMPANY : NOKIA BellLabs France + EMAIL : francois.taburet@nokia-bell-labs.com +*/ +#ifndef RRC_CONFIG_TOOLS_H_ +#define RRC_CONFIG_TOOLS_H_ + +#define KHz (1000UL) +#define MHz (1000 * KHz) + +typedef struct eutra_band_s { + int16_t band; + uint32_t ul_min; + uint32_t ul_max; + uint32_t dl_min; + uint32_t dl_max; + lte_frame_type_t frame_type; +} eutra_band_t; + + +extern int config_check_band_frequencies(int ind, int16_t band, uint32_t downlink_frequency, + int32_t uplink_frequency_offset, uint32_t frame_type); + +extern int config_check_assign_DLGap_NB(paramdef_t *param); +extern int config_check_assign_rach_NB(paramdef_t *param); +#endif diff --git a/openair2/ENB_APP/RRC_paramsvalues.h b/openair2/ENB_APP/RRC_paramsvalues.h new file mode 100644 index 0000000000..fb375e1a09 --- /dev/null +++ b/openair2/ENB_APP/RRC_paramsvalues.h @@ -0,0 +1,94 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file openair2/ENB_APP/RRC_paramsvalues.h + * \brief macro definitions for RRC authorized and asn1 parameters values, to be used in paramdef_t/chechedparam_t structure initializations + * \author Francois TABURET + * \date 2017 + * \version 0.1 + * \company NOKIA BellLabs France + * \email: francois.taburet@nokia-bell-labs.com + * \note + * \warning + */ +#ifndef __RRC_PARAMSVALUES__H__ +#define __RRC_PARAMSVALUES__H__ +/* cell configuration section name */ +#define ENB_CONFIG_STRING_ENB_LIST "eNBs" +/* component carriers configuration section name */ +#define ENB_CONFIG_STRING_COMPONENT_CARRIERS "component_carriers" + +#define ENB_CONFIG_STRING_FRAME_TYPE "frame_type" +#define ENB_CONFIG_STRING_PBCH_REPETITION "pbch_repetition" +#define ENB_CONFIG_STRING_TDD_CONFIG "tdd_config" +#define ENB_CONFIG_STRING_TDD_CONFIG_S "tdd_config_s" +#define ENB_CONFIG_STRING_PREFIX_TYPE "prefix_type" +#define ENB_CONFIG_STRING_PREFIX_TYPE_UL "prefix_type_UL" +#define ENB_CONFIG_STRING_EUTRA_BAND "eutra_band" +#define ENB_CONFIG_STRING_DOWNLINK_FREQUENCY "downlink_frequency" +#define ENB_CONFIG_STRING_UPLINK_FREQUENCY_OFFSET "uplink_frequency_offset" +#define ENB_CONFIG_STRING_NID_CELL "Nid_cell" +#define ENB_CONFIG_STRING_N_RB_DL "N_RB_DL" +#define ENB_CONFIG_STRING_CELL_MBSFN "Nid_cell_mbsfn" + + +#define FRAMETYPE_OKVALUES {"FDD","TDD"} +#define FRAMETYPE_MODVALUES { FDD, TDD} + +#define TDDCFG(A) TDD_Config__subframeAssignment_ ## A +#define TDDCONFIG_OKRANGE { TDDCFG(sa0), TDDCFG(sa6)} + +#define TDDCFGS(A) TDD_Config__specialSubframePatterns_ ## A +#define TDDCONFIGS_OKRANGE { TDDCFGS(ssp0), TDDCFGS(ssp8)} + +#define PREFIX_OKVALUES {"NORMAL","EXTENDED"} +#define PREFIX_MODVALUES { NORMAL, EXTENDED} + +#define PREFIXUL_OKVALUES {"NORMAL","EXTENDED"} +#define PREFIXUL_MODVALUES { NORMAL, EXTENDED} + +#define NRBDL_OKVALUES {6,15,25,50,75,100} + +#define UETIMER_T300_OKVALUES {100,200,300,400,600,1000,1500,2000} +#define UETT300(A) UE_TimersAndConstants__t300_ ## A +#define UETIMER_T300_MODVALUES { UETT300(ms100), UETT300(ms200),UETT300(ms300),UETT300(ms400),UETT300(ms600),UETT300(ms1000),UETT300(ms1500),UETT300(ms2000)} + +#define UETIMER_T301_OKVALUES {100,200,300,400,600,1000,1500,2000} +#define UETT301(A) UE_TimersAndConstants__t301_ ## A +#define UETIMER_T301_MODVALUES { UETT301(ms100), UETT301(ms200),UETT301(ms300),UETT301(ms400),UETT301(ms600),UETT301(ms1000),UETT301(ms1500),UETT301(ms2000)} + +#define UETIMER_T310_OKVALUES {0,50,100,200,500,1000,2000} +#define UETT310(A) UE_TimersAndConstants__t310_ ## A +#define UETIMER_T310_MODVALUES { UETT310(ms0), UETT310(ms50),UETT310(ms100),UETT310(ms200),UETT310(ms500),UETT310(ms1000),UETT310(ms2000)} + +#define UETIMER_T311_OKVALUES {1000,3110,5000,10000,15000,20000,31100} +#define UETT311(A) UE_TimersAndConstants__t311_ ## A +#define UETIMER_T311_MODVALUES { UETT311(ms1000), UETT311(ms3000),UETT311(ms5000),UETT311(ms10000),UETT311(ms15000),UETT311(ms20000),UETT311(ms30000)} + +#define UETIMER_N310_OKVALUES {1,2,3,4,6,8,10,20} +#define UETN310(A) UE_TimersAndConstants__n310_ ## A +#define UETIMER_N310_MODVALUES { UETN310(n1), UETN310(n2),UETN310(n3),UETN310(n4),UETN310(n6),UETN310(n8),UETN310(n10),UETN310(n20)} + +#define UETIMER_N311_OKVALUES {1,2,3,4,5,6,8,10} +#define UETN311(A) UE_TimersAndConstants__n311_ ## A +#define UETIMER_N311_MODVALUES { UETN311(n1), UETN311(n2),UETN311(n3),UETN311(n4),UETN311(n5),UETN311(n6),UETN311(n8),UETN311(n10)} + +#endif diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index a30dc28c94..5e9c320f57 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -52,51 +52,14 @@ #include "nfapi_vnf.h" #include "nfapi_pnf.h" -#include "enb_paramdef.h" +#include "L1_paramdef.h" +#include "MACRLC_paramdef.h" #include "common/config/config_userapi.h" +#include "RRC_config_tools.h" +#include "enb_paramdef.h" extern uint16_t sf_ahead; -static int enb_check_band_frequencies(char* lib_config_file_name_pP, - int ind, - int16_t band, - uint32_t downlink_frequency, - int32_t uplink_frequency_offset, - lte_frame_type_t frame_type) -{ - int errors = 0; - - if (band > 0) { - int band_index; - - for (band_index = 0; band_index < sizeof (eutra_bands) / sizeof (eutra_bands[0]); band_index++) { - if (band == eutra_bands[band_index].band) { - uint32_t uplink_frequency = downlink_frequency + uplink_frequency_offset; - - AssertError (eutra_bands[band_index].dl_min < downlink_frequency, errors ++, - "Failed to parse eNB configuration file %s, enb %d downlink frequency %u too low (%u) for band %d!", - lib_config_file_name_pP, ind, downlink_frequency, eutra_bands[band_index].dl_min, band); - AssertError (downlink_frequency < eutra_bands[band_index].dl_max, errors ++, - "Failed to parse eNB configuration file %s, enb %d downlink frequency %u too high (%u) for band %d!", - lib_config_file_name_pP, ind, downlink_frequency, eutra_bands[band_index].dl_max, band); - - AssertError (eutra_bands[band_index].ul_min < uplink_frequency, errors ++, - "Failed to parse eNB configuration file %s, enb %d uplink frequency %u too low (%u) for band %d!", - lib_config_file_name_pP, ind, uplink_frequency, eutra_bands[band_index].ul_min, band); - AssertError (uplink_frequency < eutra_bands[band_index].ul_max, errors ++, - "Failed to parse eNB configuration file %s, enb %d uplink frequency %u too high (%u) for band %d!", - lib_config_file_name_pP, ind, uplink_frequency, eutra_bands[band_index].ul_max, band); - - AssertError (eutra_bands[band_index].frame_type == frame_type, errors ++, - "Failed to parse eNB configuration file %s, enb %d invalid frame type (%d/%d) for band %d!", - lib_config_file_name_pP, ind, eutra_bands[band_index].frame_type, frame_type, band); - } - } - } - - - return errors; -} void RCconfig_flexran() { @@ -420,14 +383,16 @@ int RCconfig_RRC(MessageDef *msg_p, uint32_t i, eNB_RRC_INST *rrc) { paramdef_t ENBParams[] = ENBPARAMS_DESC; paramlist_def_t ENBParamList = {ENB_CONFIG_STRING_ENB_LIST,NULL,0}; + checkedparam_t config_check_CCparams[] = CCPARAMS_CHECK; paramdef_t CCsParams[] = CCPARAMS_DESC; paramlist_def_t CCsParamList = {ENB_CONFIG_STRING_COMPONENT_CARRIERS,NULL,0}; paramdef_t SRB1Params[] = SRB1PARAMS_DESC; - - - +/* map parameter checking array instances to parameter definition array instances */ + for (int I=0; I< ( sizeof(CCsParams)/ sizeof(paramdef_t) ) ; I++) { + CCsParams[I].chkPptr = &(config_check_CCparams[I]); + } /* get global parameters, defined outside any section in the config file */ config_get( ENBSParams,sizeof(ENBSParams)/sizeof(paramdef_t),NULL); @@ -562,43 +527,7 @@ int RCconfig_RRC(MessageDef *msg_p, uint32_t i, eNB_RRC_INST *rrc) { nb_cc++; - /* - if (strcmp(cc_node_function, "eNodeB_3GPP") == 0) { - enb_properties_loc.properties[enb_properties_loc_index]->cc_node_function[j] = eNodeB_3GPP; - } else if (strcmp(cc_node_function, "eNodeB_3GPP_BBU") == 0) { - enb_properties_loc.properties[enb_properties_loc_index]->cc_node_function[j] = eNodeB_3GPP_BBU; - } else if (strcmp(cc_node_function, "NGFI_RCC_IF4p5") == 0) { - enb_properties_loc.properties[enb_properties_loc_index]->cc_node_function[j] = NGFI_RCC_IF4p5; - } else if (strcmp(cc_node_function, "NGFI_RAU_IF4p5") == 0) { - enb_properties_loc.properties[enb_properties_loc_index]->cc_node_function[j] = NGFI_RAU_IF4p5; - } else if (strcmp(cc_node_function, "NGFI_RRU_IF4p5") == 0) { - enb_properties_loc.properties[enb_properties_loc_index]->cc_node_function[j] = NGFI_RRU_IF4p5; - } else if (strcmp(cc_node_function, "NGFI_RRU_IF5") == 0) { - enb_properties_loc.properties[enb_properties_loc_index]->cc_node_function[j] = NGFI_RRU_IF5; - } else { - AssertError (0, parse_errors ++, - "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for node_function choice: eNodeB_3GPP or eNodeB_3GPP_BBU or NGFI_IF4_RCC or NGFI_IF4_RRU or NGFI_IF5_RRU !\n", - lib_config_file_name_pP, i, cc_node_function); - } - - if (strcmp(cc_node_timing, "synch_to_ext_device") == 0) { - enb_properties_loc.properties[enb_properties_loc_index]->cc_node_timing[j] = synch_to_ext_device; - } else if (strcmp(cc_node_timing, "synch_to_other") == 0) { - enb_properties_loc.properties[enb_properties_loc_index]->cc_node_timing[j] = synch_to_other; - } else { - AssertError (0, parse_errors ++, - "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for node_function choice: SYNCH_TO_DEVICE or SYNCH_TO_OTHER !\n", - lib_config_file_name_pP, i, cc_node_timing); - } - - if ((cc_node_synch_ref >= -1) && (cc_node_synch_ref < num_component_carriers)) { - enb_properties_loc.properties[enb_properties_loc_index]->cc_node_synch_ref[j] = (int16_t) cc_node_synch_ref; - } else { - AssertError (0, parse_errors ++, - "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for node_synch_ref choice: valid CC_id or -1 !\n", - lib_config_file_name_pP, i, cc_node_synch_ref); - } - */ + RRC_CONFIGURATION_REQ (msg_p).tdd_config[j] = tdd_config; @@ -710,8 +639,7 @@ int RCconfig_RRC(MessageDef *msg_p, uint32_t i, eNB_RRC_INST *rrc) { RRC_CONFIGURATION_REQ (msg_p).uplink_frequency_offset[j] = (unsigned int) uplink_frequency_offset; - if (enb_check_band_frequencies(RC.config_file_name, - j, + if (config_check_band_frequencies(j, RRC_CONFIGURATION_REQ (msg_p).eutra_band[j], RRC_CONFIGURATION_REQ (msg_p).downlink_frequency[j], RRC_CONFIGURATION_REQ (msg_p).uplink_frequency_offset[j], @@ -1385,244 +1313,13 @@ int RCconfig_RRC(MessageDef *msg_p, uint32_t i, eNB_RRC_INST *rrc) { break; } - - switch (ue_TimersAndConstants_t300) { - case 100: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t300[j] = UE_TimersAndConstants__t300_ms100; - break; - - case 200: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t300[j] = UE_TimersAndConstants__t300_ms200; - break; - - case 300: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t300[j] = UE_TimersAndConstants__t300_ms300; - break; - - case 400: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t300[j] = UE_TimersAndConstants__t300_ms400; - break; - - case 600: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t300[j] = UE_TimersAndConstants__t300_ms600; - break; - - case 1000: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t300[j] = UE_TimersAndConstants__t300_ms1000; - break; - - case 1500: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t300[j] = UE_TimersAndConstants__t300_ms1500; - break; - - case 2000: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t300[j] = UE_TimersAndConstants__t300_ms2000; - break; - - default: - AssertFatal (0, - "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for ue_TimersAndConstants_t300 choice: 100,200,300,400,600,1000,1500,2000 ", - RC.config_file_name, i, ue_TimersAndConstants_t300); - break; - - } - - switch (ue_TimersAndConstants_t301) { - case 100: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t301[j] = UE_TimersAndConstants__t301_ms100; - break; - - case 200: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t301[j] = UE_TimersAndConstants__t301_ms200; - break; - - case 300: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t301[j] = UE_TimersAndConstants__t301_ms300; - break; - - case 400: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t301[j] = UE_TimersAndConstants__t301_ms400; - break; - - case 600: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t301[j] = UE_TimersAndConstants__t301_ms600; - break; - - case 1000: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t301[j] = UE_TimersAndConstants__t301_ms1000; - break; - - case 1500: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t301[j] = UE_TimersAndConstants__t301_ms1500; - break; - - case 2000: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t301[j] = UE_TimersAndConstants__t301_ms2000; - break; - - default: - AssertFatal (0, - "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for ue_TimersAndConstants_t301 choice: 100,200,300,400,600,1000,1500,2000 ", - RC.config_file_name, i, ue_TimersAndConstants_t301); - break; - - } - - switch (ue_TimersAndConstants_t310) { - case 0: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t310[j] = UE_TimersAndConstants__t310_ms0; - break; - - case 50: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t310[j] = UE_TimersAndConstants__t310_ms50; - break; - - case 100: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t310[j] = UE_TimersAndConstants__t310_ms100; - break; - - case 200: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t310[j] = UE_TimersAndConstants__t310_ms200; - break; - - case 500: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t310[j] = UE_TimersAndConstants__t310_ms500; - break; - - case 1000: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t310[j] = UE_TimersAndConstants__t310_ms1000; - break; - - case 2000: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t310[j] = UE_TimersAndConstants__t310_ms2000; - break; - - default: - AssertFatal (0, - "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for ue_TimersAndConstants_t310 choice: 0,50,100,200,500,1000,1500,2000 ", - RC.config_file_name, i, ue_TimersAndConstants_t310); - break; - - } - - switch (ue_TimersAndConstants_t311) { - case 1000: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t311[j] = UE_TimersAndConstants__t311_ms1000; - break; - - case 3110: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t311[j] = UE_TimersAndConstants__t311_ms3000; - break; - - case 5000: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t311[j] = UE_TimersAndConstants__t311_ms5000; - break; - - case 10000: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t311[j] = UE_TimersAndConstants__t311_ms10000; - break; - - case 15000: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t311[j] = UE_TimersAndConstants__t311_ms15000; - break; - - case 20000: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t311[j] = UE_TimersAndConstants__t311_ms20000; - break; - - case 31100: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t311[j] = UE_TimersAndConstants__t311_ms30000; - break; - - default: - AssertFatal (0, - "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for ue_TimersAndConstants_t311 choice: 1000,3000,5000,10000,150000,20000,30000", - RC.config_file_name, i, ue_TimersAndConstants_t311); - break; - - } - - switch (ue_TimersAndConstants_n310) { - case 1: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n310[j] = UE_TimersAndConstants__n310_n1; - break; - - case 2: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n310[j] = UE_TimersAndConstants__n310_n2; - break; - - case 3: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n310[j] = UE_TimersAndConstants__n310_n3; - break; - - case 4: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n310[j] = UE_TimersAndConstants__n310_n4; - break; - - case 6: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n310[j] = UE_TimersAndConstants__n310_n6; - break; - - case 8: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n310[j] = UE_TimersAndConstants__n310_n8; - break; - - case 10: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n310[j] = UE_TimersAndConstants__n310_n10; - break; - - case 20: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n310[j] = UE_TimersAndConstants__n310_n20; - break; - - default: - AssertFatal (0, - "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for ue_TimersAndConstants_n310 choice: 1,2,3,4,6,6,8,10,20", - RC.config_file_name, i, ue_TimersAndConstants_n311); - break; - - } - - switch (ue_TimersAndConstants_n311) { - case 1: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n311[j] = UE_TimersAndConstants__n311_n1; - break; - - case 2: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n311[j] = UE_TimersAndConstants__n311_n2; - break; - - case 3: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n311[j] = UE_TimersAndConstants__n311_n3; - break; - - case 4: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n311[j] = UE_TimersAndConstants__n311_n4; - break; - - case 5: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n311[j] = UE_TimersAndConstants__n311_n5; - break; - - case 6: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n311[j] = UE_TimersAndConstants__n311_n6; - break; - - case 8: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n311[j] = UE_TimersAndConstants__n311_n8; - break; - - case 10: - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n311[j] = UE_TimersAndConstants__n311_n10; - break; - - default: - AssertFatal (0, - "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for ue_TimersAndConstants_t311 choice: 1,2,3,4,5,6,8,10", - RC.config_file_name, i, ue_TimersAndConstants_t311); - break; - - } + + RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t300[j] = ue_TimersAndConstants_t300; + RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t301[j] = ue_TimersAndConstants_t301; + RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t310[j] = ue_TimersAndConstants_t310; + RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t311[j] = ue_TimersAndConstants_t311; + RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n310[j] = ue_TimersAndConstants_n310; + RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n311[j] = ue_TimersAndConstants_n311; switch (ue_TransmissionMode) { case 1: @@ -1965,275 +1662,32 @@ int RCconfig_RRC(MessageDef *msg_p, uint32_t i, eNB_RRC_INST *rrc) { } /* - // OTG _CONFIG - setting_otg = config_setting_get_member (setting_enb, ENB_CONF_STRING_OTG_CONFIG); - - if (setting_otg != NULL) { - num_otg_elements = config_setting_length(setting_otg); - printf("num otg elements %d \n", num_otg_elements); - enb_properties_loc.properties[enb_properties_loc_index]->num_otg_elements = 0; - - for (j = 0; j < num_otg_elements; j++) { - subsetting_otg=config_setting_get_elem(setting_otg, j); - - if (config_setting_lookup_int(subsetting_otg, ENB_CONF_STRING_OTG_UE_ID, &otg_ue_id)) { - enb_properties_loc.properties[enb_properties_loc_index]->otg_ue_id[j] = otg_ue_id; - } else { - enb_properties_loc.properties[enb_properties_loc_index]->otg_ue_id[j] = 1; - } - - if (config_setting_lookup_string(subsetting_otg, ENB_CONF_STRING_OTG_APP_TYPE, (const char **)&otg_app_type)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->otg_app_type[j] = map_str_to_int(otg_app_type_names,otg_app_type))== -1) { - enb_properties_loc.properties[enb_properties_loc_index]->otg_app_type[j] = BCBR; - } - } else { - enb_properties_loc.properties[enb_properties_loc_index]->otg_app_type[j] = NO_PREDEFINED_TRAFFIC; // 0 - } - - if (config_setting_lookup_string(subsetting_otg, ENB_CONF_STRING_OTG_BG_TRAFFIC, (const char **)&otg_bg_traffic)) { - - if ((enb_properties_loc.properties[enb_properties_loc_index]->otg_bg_traffic[j] = map_str_to_int(switch_names,otg_bg_traffic)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->otg_bg_traffic[j]=0; - } - } else { - enb_properties_loc.properties[enb_properties_loc_index]->otg_bg_traffic[j] = 0; - printf("otg bg %s\n", otg_bg_traffic); - } - - enb_properties_loc.properties[enb_properties_loc_index]->num_otg_elements+=1; - - } - } - - // log_config - subsetting = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_LOG_CONFIG); + // Network Controller + subsetting = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_NETWORK_CONTROLLER_CONFIG); if (subsetting != NULL) { - // global - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_GLOBAL_LOG_LEVEL, (const char **) &glog_level)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->glog_level = map_str_to_int(log_level_names, glog_level)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->glog_level = LOG_INFO; + if ( ( + config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_FLEXRAN_AGENT_INTERFACE_NAME, + (const char **)&flexran_agent_interface_name) + && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_FLEXRAN_AGENT_IPV4_ADDRESS, + (const char **)&flexran_agent_ipv4_address) + && config_setting_lookup_int(subsetting, ENB_CONFIG_STRING_FLEXRAN_AGENT_PORT, + &flexran_agent_port) + && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_FLEXRAN_AGENT_CACHE, + (const char **)&flexran_agent_cache) + ) + ) { + enb_properties_loc.properties[enb_properties_loc_index]->flexran_agent_interface_name = strdup(flexran_agent_interface_name); + cidr = flexran_agent_ipv4_address; + address = strtok(cidr, "/"); + //enb_properties_loc.properties[enb_properties_loc_index]->flexran_agent_ipv4_address = strdup(address); + if (address) { + IPV4_STR_ADDR_TO_INT_NWBO (address, enb_properties_loc.properties[enb_properties_loc_index]->flexran_agent_ipv4_address, "BAD IP ADDRESS FORMAT FOR eNB Agent !\n" ); } - //printf( "\tGlobal log level :\t%s->%d\n",glog_level, enb_properties_loc.properties[enb_properties_loc_index]->glog_level); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->glog_level = LOG_INFO; + enb_properties_loc.properties[enb_properties_loc_index]->flexran_agent_port = flexran_agent_port; + enb_properties_loc.properties[enb_properties_loc_index]->flexran_agent_cache = strdup(flexran_agent_cache); } - - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_GLOBAL_LOG_VERBOSITY,(const char **) &glog_verbosity)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->glog_verbosity = map_str_to_int(log_verbosity_names, glog_verbosity)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->glog_verbosity = LOG_MED; - } - - //printf( "\tGlobal log verbosity:\t%s->%d\n",glog_verbosity, enb_properties_loc.properties[enb_properties_loc_index]->glog_verbosity); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->glog_verbosity = LOG_MED; - } - - // HW - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_HW_LOG_LEVEL, (const char **) &hw_log_level)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->hw_log_level = map_str_to_int(log_level_names,hw_log_level)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->hw_log_level = LOG_INFO; - } - - //printf( "\tHW log level :\t%s->%d\n",hw_log_level,enb_properties_loc.properties[enb_properties_loc_index]->hw_log_level); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->hw_log_level = LOG_INFO; - } - - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_HW_LOG_VERBOSITY, (const char **) &hw_log_verbosity)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->hw_log_verbosity = map_str_to_int(log_verbosity_names,hw_log_verbosity)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->hw_log_verbosity = LOG_MED; - } - - //printf( "\tHW log verbosity:\t%s->%d\n",hw_log_verbosity, enb_properties_loc.properties[enb_properties_loc_index]->hw_log_verbosity); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->hw_log_verbosity = LOG_MED; - } - - // phy - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_PHY_LOG_LEVEL,(const char **) &phy_log_level)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->phy_log_level = map_str_to_int(log_level_names,phy_log_level)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->phy_log_level = LOG_INFO; - } - - //printf( "\tPHY log level :\t%s->%d\n",phy_log_level,enb_properties_loc.properties[enb_properties_loc_index]->phy_log_level); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->phy_log_level = LOG_INFO; - } - - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_PHY_LOG_VERBOSITY, (const char **)&phy_log_verbosity)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->phy_log_verbosity = map_str_to_int(log_verbosity_names,phy_log_verbosity)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->phy_log_verbosity = LOG_MED; - } - - //printf( "\tPHY log verbosity:\t%s->%d\n",phy_log_level,enb_properties_loc.properties[enb_properties_loc_index]->phy_log_verbosity); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->phy_log_verbosity = LOG_MED; - } - - //mac - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_MAC_LOG_LEVEL, (const char **)&mac_log_level)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->mac_log_level = map_str_to_int(log_level_names,mac_log_level)) == -1 ) { - enb_properties_loc.properties[enb_properties_loc_index]->mac_log_level = LOG_INFO; - } - - //printf( "\tMAC log level :\t%s->%d\n",mac_log_level,enb_properties_loc.properties[enb_properties_loc_index]->mac_log_level); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->mac_log_level = LOG_INFO; - } - - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_MAC_LOG_VERBOSITY, (const char **)&mac_log_verbosity)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->mac_log_verbosity = map_str_to_int(log_verbosity_names,mac_log_verbosity)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->mac_log_verbosity = LOG_MED; - } - - //printf( "\tMAC log verbosity:\t%s->%d\n",mac_log_verbosity,enb_properties_loc.properties[enb_properties_loc_index]->mac_log_verbosity); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->mac_log_verbosity = LOG_MED; - } - - //rlc - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_RLC_LOG_LEVEL, (const char **)&rlc_log_level)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->rlc_log_level = map_str_to_int(log_level_names,rlc_log_level)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->rlc_log_level = LOG_INFO; - } - - //printf( "\tRLC log level :\t%s->%d\n",rlc_log_level, enb_properties_loc.properties[enb_properties_loc_index]->rlc_log_level); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->rlc_log_level = LOG_INFO; - } - - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_RLC_LOG_VERBOSITY, (const char **)&rlc_log_verbosity)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->rlc_log_verbosity = map_str_to_int(log_verbosity_names,rlc_log_verbosity)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->rlc_log_verbosity = LOG_MED; - } - - //printf( "\tRLC log verbosity:\t%s->%d\n",rlc_log_verbosity, enb_properties_loc.properties[enb_properties_loc_index]->rlc_log_verbosity); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->rlc_log_verbosity = LOG_MED; - } - - //pdcp - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_PDCP_LOG_LEVEL, (const char **)&pdcp_log_level)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->pdcp_log_level = map_str_to_int(log_level_names,pdcp_log_level)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->pdcp_log_level = LOG_INFO; - } - - //printf( "\tPDCP log level :\t%s->%d\n",pdcp_log_level, enb_properties_loc.properties[enb_properties_loc_index]->pdcp_log_level); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->pdcp_log_level = LOG_INFO; - } - - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_PDCP_LOG_VERBOSITY, (const char **)&pdcp_log_verbosity)) { - enb_properties_loc.properties[enb_properties_loc_index]->pdcp_log_verbosity = map_str_to_int(log_verbosity_names,pdcp_log_verbosity); - //printf( "\tPDCP log verbosity:\t%s->%d\n",pdcp_log_verbosity, enb_properties_loc.properties[enb_properties_loc_index]->pdcp_log_verbosity); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->pdcp_log_verbosity = LOG_MED; - } - - //rrc - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_RRC_LOG_LEVEL, (const char **)&rrc_log_level)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->rrc_log_level = map_str_to_int(log_level_names,rrc_log_level)) == -1 ) { - enb_properties_loc.properties[enb_properties_loc_index]->rrc_log_level = LOG_INFO; - } - - //printf( "\tRRC log level :\t%s->%d\n",rrc_log_level,enb_properties_loc.properties[enb_properties_loc_index]->rrc_log_level); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->rrc_log_level = LOG_INFO; - } - - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_RRC_LOG_VERBOSITY, (const char **)&rrc_log_verbosity)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->rrc_log_verbosity = map_str_to_int(log_verbosity_names,rrc_log_verbosity)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->rrc_log_verbosity = LOG_MED; - } - - //printf( "\tRRC log verbosity:\t%s->%d\n",rrc_log_verbosity,enb_properties_loc.properties[enb_properties_loc_index]->rrc_log_verbosity); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->rrc_log_verbosity = LOG_MED; - } - - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_GTPU_LOG_LEVEL, (const char **)>pu_log_level)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->gtpu_log_level = map_str_to_int(log_level_names,gtpu_log_level)) == -1 ) { - enb_properties_loc.properties[enb_properties_loc_index]->gtpu_log_level = LOG_INFO; - } - - //printf( "\tGTPU log level :\t%s->%d\n",gtpu_log_level,enb_properties_loc.properties[enb_properties_loc_index]->gtpu_log_level); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->gtpu_log_level = LOG_INFO; - } - - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_GTPU_LOG_VERBOSITY, (const char **)>pu_log_verbosity)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->gtpu_log_verbosity = map_str_to_int(log_verbosity_names,gtpu_log_verbosity)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->gtpu_log_verbosity = LOG_MED; - } - - //printf( "\tGTPU log verbosity:\t%s->%d\n",gtpu_log_verbosity,enb_properties_loc.properties[enb_properties_loc_index]->gtpu_log_verbosity); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->gtpu_log_verbosity = LOG_MED; - } - - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_UDP_LOG_LEVEL, (const char **)&udp_log_level)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->udp_log_level = map_str_to_int(log_level_names,udp_log_level)) == -1 ) { - enb_properties_loc.properties[enb_properties_loc_index]->udp_log_level = LOG_INFO; - } - - //printf( "\tUDP log level :\t%s->%d\n",udp_log_level,enb_properties_loc.properties[enb_properties_loc_index]->udp_log_level); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->udp_log_level = LOG_INFO; - } - - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_UDP_LOG_VERBOSITY, (const char **)&udp_log_verbosity)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->udp_log_verbosity = map_str_to_int(log_verbosity_names,udp_log_verbosity)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->udp_log_verbosity = LOG_MED; - } - - //printf( "\tUDP log verbosity:\t%s->%d\n",udp_log_verbosity,enb_properties_loc.properties[enb_properties_loc_index]->gtpu_log_verbosity); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->udp_log_verbosity = LOG_MED; - } - - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_OSA_LOG_LEVEL, (const char **)&osa_log_level)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->osa_log_level = map_str_to_int(log_level_names,osa_log_level)) == -1 ) { - enb_properties_loc.properties[enb_properties_loc_index]->osa_log_level = LOG_INFO; - } - - //printf( "\tOSA log level :\t%s->%d\n",osa_log_level,enb_properties_loc.properties[enb_properties_loc_index]->osa_log_level); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->osa_log_level = LOG_INFO; - } - - if (config_setting_lookup_string(subsetting, ENB_CONFIG_STRING_OSA_LOG_VERBOSITY, (const char **)&osa_log_verbosity)) { - if ((enb_properties_loc.properties[enb_properties_loc_index]->osa_log_verbosity = map_str_to_int(log_verbosity_names,osa_log_verbosity)) == -1) { - enb_properties_loc.properties[enb_properties_loc_index]->osa_log_verbosity = LOG_MED; - } - - //printf( "\tOSA log verbosity:\t%s->%d\n",osa_log_verbosity,enb_properties_loc.properties[enb_properties_loc_index]->gosa_log_verbosity); - } else { - enb_properties_loc.properties[enb_properties_loc_index]->osa_log_verbosity = LOG_MED; - } - - } else { // not configuration is given - enb_properties_loc.properties[enb_properties_loc_index]->glog_level = LOG_INFO; - enb_properties_loc.properties[enb_properties_loc_index]->glog_verbosity = LOG_MED; - enb_properties_loc.properties[enb_properties_loc_index]->hw_log_level = LOG_INFO; - enb_properties_loc.properties[enb_properties_loc_index]->hw_log_verbosity = LOG_MED; - enb_properties_loc.properties[enb_properties_loc_index]->phy_log_level = LOG_INFO; - enb_properties_loc.properties[enb_properties_loc_index]->phy_log_verbosity = LOG_MED; - enb_properties_loc.properties[enb_properties_loc_index]->mac_log_level = LOG_INFO; - enb_properties_loc.properties[enb_properties_loc_index]->mac_log_verbosity = LOG_MED; - enb_properties_loc.properties[enb_properties_loc_index]->rlc_log_level = LOG_INFO; - enb_properties_loc.properties[enb_properties_loc_index]->rlc_log_verbosity = LOG_MED; - enb_properties_loc.properties[enb_properties_loc_index]->pdcp_log_level = LOG_INFO; - enb_properties_loc.properties[enb_properties_loc_index]->pdcp_log_verbosity = LOG_MED; - enb_properties_loc.properties[enb_properties_loc_index]->rrc_log_level = LOG_INFO; - enb_properties_loc.properties[enb_properties_loc_index]->rrc_log_verbosity = LOG_MED; - enb_properties_loc.properties[enb_properties_loc_index]->gtpu_log_level = LOG_INFO; - enb_properties_loc.properties[enb_properties_loc_index]->gtpu_log_verbosity = LOG_MED; - enb_properties_loc.properties[enb_properties_loc_index]->udp_log_level = LOG_INFO; - enb_properties_loc.properties[enb_properties_loc_index]->udp_log_verbosity = LOG_MED; - enb_properties_loc.properties[enb_properties_loc_index]->osa_log_level = LOG_INFO; - enb_properties_loc.properties[enb_properties_loc_index]->osa_log_verbosity = LOG_MED; } */ break; diff --git a/openair2/ENB_APP/enb_paramdef.h b/openair2/ENB_APP/enb_paramdef.h index 1a9019b794..d2634b3947 100755 --- a/openair2/ENB_APP/enb_paramdef.h +++ b/openair2/ENB_APP/enb_paramdef.h @@ -31,7 +31,7 @@ */ #include "common/config/config_paramdesc.h" - +#include "RRC_paramsvalues.h" @@ -56,52 +56,6 @@ -#define KHz (1000UL) -#define MHz (1000 * KHz) - -typedef struct eutra_band_s { - int16_t band; - uint32_t ul_min; - uint32_t ul_max; - uint32_t dl_min; - uint32_t dl_max; - lte_frame_type_t frame_type; -} eutra_band_t; - -static const eutra_band_t eutra_bands[] = { - { 1, 1920 * MHz, 1980 * MHz, 2110 * MHz, 2170 * MHz, FDD}, - { 2, 1850 * MHz, 1910 * MHz, 1930 * MHz, 1990 * MHz, FDD}, - { 3, 1710 * MHz, 1785 * MHz, 1805 * MHz, 1880 * MHz, FDD}, - { 4, 1710 * MHz, 1755 * MHz, 2110 * MHz, 2155 * MHz, FDD}, - { 5, 824 * MHz, 849 * MHz, 869 * MHz, 894 * MHz, FDD}, - { 6, 830 * MHz, 840 * MHz, 875 * MHz, 885 * MHz, FDD}, - { 7, 2500 * MHz, 2570 * MHz, 2620 * MHz, 2690 * MHz, FDD}, - { 8, 880 * MHz, 915 * MHz, 925 * MHz, 960 * MHz, FDD}, - { 9, 1749900 * KHz, 1784900 * KHz, 1844900 * KHz, 1879900 * KHz, FDD}, - {10, 1710 * MHz, 1770 * MHz, 2110 * MHz, 2170 * MHz, FDD}, - {11, 1427900 * KHz, 1452900 * KHz, 1475900 * KHz, 1500900 * KHz, FDD}, - {12, 698 * MHz, 716 * MHz, 728 * MHz, 746 * MHz, FDD}, - {13, 777 * MHz, 787 * MHz, 746 * MHz, 756 * MHz, FDD}, - {14, 788 * MHz, 798 * MHz, 758 * MHz, 768 * MHz, FDD}, - - {17, 704 * MHz, 716 * MHz, 734 * MHz, 746 * MHz, FDD}, - {20, 832 * MHz, 862 * MHz, 791 * MHz, 821 * MHz, FDD}, - {33, 1900 * MHz, 1920 * MHz, 1900 * MHz, 1920 * MHz, TDD}, - {33, 1900 * MHz, 1920 * MHz, 1900 * MHz, 1920 * MHz, TDD}, - {34, 2010 * MHz, 2025 * MHz, 2010 * MHz, 2025 * MHz, TDD}, - {35, 1850 * MHz, 1910 * MHz, 1850 * MHz, 1910 * MHz, TDD}, - {36, 1930 * MHz, 1990 * MHz, 1930 * MHz, 1990 * MHz, TDD}, - {37, 1910 * MHz, 1930 * MHz, 1910 * MHz, 1930 * MHz, TDD}, - {38, 2570 * MHz, 2620 * MHz, 2570 * MHz, 2630 * MHz, TDD}, - {39, 1880 * MHz, 1920 * MHz, 1880 * MHz, 1920 * MHz, TDD}, - {40, 2300 * MHz, 2400 * MHz, 2300 * MHz, 2400 * MHz, TDD}, - {41, 2496 * MHz, 2690 * MHz, 2496 * MHz, 2690 * MHz, TDD}, - {42, 3400 * MHz, 3600 * MHz, 3400 * MHz, 3600 * MHz, TDD}, - {43, 3600 * MHz, 3800 * MHz, 3600 * MHz, 3800 * MHz, TDD}, - {44, 703 * MHz, 803 * MHz, 703 * MHz, 803 * MHz, TDD}, -}; - - @@ -152,7 +106,7 @@ typedef enum { #define CONFIG_STRING_RU_MAX_RS_EPRE "max_pdschReferenceSignalPower" #define CONFIG_STRING_RU_MAX_RXGAIN "max_rxgain" #define CONFIG_STRING_RU_IF_COMPRESSION "if_compression" - +#define CONFIG_STRING_RU_NBIOTRRC_LIST "NbIoT_RRC_instances" #define RU_LOCAL_IF_NAME_IDX 0 #define RU_LOCAL_ADDRESS_IDX 1 @@ -171,7 +125,7 @@ typedef enum { #define RU_ENB_LIST_IDX 14 #define RU_ATT_TX_IDX 15 #define RU_ATT_RX_IDX 16 - +#define RU_NBIOTRRC_LIST_IDX 17 @@ -196,7 +150,8 @@ typedef enum { {CONFIG_STRING_RU_BAND_LIST, NULL, 0, uptr:NULL, defintarrayval:DEFBANDS, TYPE_INTARRAY, 1}, \ {CONFIG_STRING_RU_ENB_LIST, NULL, 0, uptr:NULL, defintarrayval:DEFENBS, TYPE_INTARRAY, 1}, \ {CONFIG_STRING_RU_ATT_TX, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ -{CONFIG_STRING_RU_ATT_RX, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0} \ +{CONFIG_STRING_RU_ATT_RX, NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{CONFIG_STRING_RU_NBIOTRRC_LIST, NULL, 0, uptr:NULL, defintarrayval:DEFENBS, TYPE_INTARRAY, 1}, \ } /*---------------------------------------------------------------------------------------------------------------------------------------*/ @@ -233,8 +188,7 @@ typedef enum { /*------------------------------------------------------------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------------------------------------------------------------*/ -/* cell configuration section name */ -#define ENB_CONFIG_STRING_ENB_LIST "eNBs" + /* cell configuration parameters names */ #define ENB_CONFIG_STRING_ENB_ID "eNB_ID" @@ -289,21 +243,9 @@ typedef enum { /*-------------------------------------------------------------------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------------------------------------------------------------------*/ -/* component carriers configuration section name */ -#define ENB_CONFIG_STRING_COMPONENT_CARRIERS "component_carriers" /* component carries configuration parameters name */ -#define ENB_CONFIG_STRING_FRAME_TYPE "frame_type" -#define ENB_CONFIG_STRING_PBCH_REPETITION "pbch_repetition" -#define ENB_CONFIG_STRING_TDD_CONFIG "tdd_config" -#define ENB_CONFIG_STRING_TDD_CONFIG_S "tdd_config_s" -#define ENB_CONFIG_STRING_PREFIX_TYPE "prefix_type" -#define ENB_CONFIG_STRING_EUTRA_BAND "eutra_band" -#define ENB_CONFIG_STRING_DOWNLINK_FREQUENCY "downlink_frequency" -#define ENB_CONFIG_STRING_UPLINK_FREQUENCY_OFFSET "uplink_frequency_offset" -#define ENB_CONFIG_STRING_NID_CELL "Nid_cell" -#define ENB_CONFIG_STRING_N_RB_DL "N_RB_DL" -#define ENB_CONFIG_STRING_CELL_MBSFN "Nid_cell_mbsfn" + #define ENB_CONFIG_STRING_NB_ANT_PORTS "nb_antenna_ports" #define ENB_CONFIG_STRING_NB_ANT_TX "nb_antennas_tx" #define ENB_CONFIG_STRING_NB_ANT_RX "nb_antennas_rx" @@ -367,11 +309,83 @@ typedef enum { #define ENB_CONFIG_STRING_UETIMERS_N310 "ue_TimersAndConstants_n310" #define ENB_CONFIG_STRING_UETIMERS_N311 "ue_TimersAndConstants_n311" #define ENB_CONFIG_STRING_UE_TRANSMISSION_MODE "ue_TransmissionMode" - -/*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -/* component carriers configuration parameters */ -/* optname helpstr paramflags XXXptr defXXXval type numelt */ -/*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ + +/* init for checkedparam_t structure */ + +#define CCPARAMS_CHECK { \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s1a= { config_check_modify_integer, UETIMER_T300_OKVALUES, UETIMER_T300_MODVALUES,8}} , \ + { .s1a= { config_check_modify_integer, UETIMER_T301_OKVALUES, UETIMER_T301_MODVALUES,8}} , \ + { .s1a= { config_check_modify_integer, UETIMER_T310_OKVALUES, UETIMER_T310_MODVALUES,7}} , \ + { .s1a= { config_check_modify_integer, UETIMER_T311_OKVALUES, UETIMER_T311_MODVALUES,7}} , \ + { .s1a= { config_check_modify_integer, UETIMER_N310_OKVALUES, UETIMER_N310_MODVALUES,8}} , \ + { .s1a= { config_check_modify_integer, UETIMER_N311_OKVALUES, UETIMER_N311_MODVALUES,8}} , \ + { .s5= {NULL }} , \ +} +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* component carriers configuration parameters */ +/* optname helpstr paramflags XXXptr defXXXval type numelt checked_param */ +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ #define CCPARAMS_DESC { \ {ENB_CONFIG_STRING_FRAME_TYPE, NULL, 0, strptr:&frame_type, defstrval:"FDD", TYPE_STRING, 0}, \ {ENB_CONFIG_STRING_TDD_CONFIG, NULL, 0, iptr:&tdd_config, defintval:3, TYPE_UINT, 0}, \ @@ -443,6 +457,75 @@ typedef enum { {ENB_CONFIG_STRING_UE_TRANSMISSION_MODE, NULL, 0, iptr:&ue_TransmissionMode, defintval:1, TYPE_UINT, 0} \ } +#define ENB_CONFIG_FRAME_TYPE_IDX 0 +#define ENB_CONFIG_TDD_CONFIG_IDX 1 +#define ENB_CONFIG_TDD_CONFIG_S_IDX 2 +#define ENB_CONFIG_PREFIX_TYPE_IDX 3 +#define ENB_CONFIG_PBCH_REPETITION_IDX 4 +#define ENB_CONFIG_EUTRA_BAND_IDX 5 +#define ENB_CONFIG_DOWNLINK_FREQUENCY_IDX 6 +#define ENB_CONFIG_UPLINK_FREQUENCY_OFFSET_IDX 7 +#define ENB_CONFIG_NID_CELL_IDX 8 +#define ENB_CONFIG_N_RB_DL_IDX 9 +#define ENB_CONFIG_CELL_MBSFN_IDX 10 +#define ENB_CONFIG_NB_ANT_PORTS_IDX 11 +#define ENB_CONFIG_PRACH_ROOT_IDX 12 +#define ENB_CONFIG_PRACH_CONFIG_INDEX_IDX 13 +#define ENB_CONFIG_PRACH_HIGH_SPEED_IDX 14 +#define ENB_CONFIG_PRACH_ZERO_CORRELATION_IDX 15 +#define ENB_CONFIG_PRACH_FREQ_OFFSET_IDX 16 +#define ENB_CONFIG_PUCCH_DELTA_SHIFT_IDX 17 +#define ENB_CONFIG_PUCCH_NRB_CQI_IDX 18 +#define ENB_CONFIG_PUCCH_NCS_AN_IDX 19 +#define ENB_CONFIG_PUCCH_N1_AN_IDX 20 +#define ENB_CONFIG_PDSCH_RS_EPRE_IDX 21 +#define ENB_CONFIG_PDSCH_PB_IDX 22 +#define ENB_CONFIG_PUSCH_N_SB_IDX 23 +#define ENB_CONFIG_PUSCH_HOPPINGMODE_IDX 24 +#define ENB_CONFIG_PUSCH_HOPPINGOFFSET_IDX 25 +#define ENB_CONFIG_PUSCH_ENABLE64QAM_IDX 26 +#define ENB_CONFIG_PUSCH_GROUP_HOPPING_EN_IDX 27 +#define ENB_CONFIG_PUSCH_GROUP_ASSIGNMENT_IDX 28 +#define ENB_CONFIG_PUSCH_SEQUENCE_HOPPING_EN_IDX 29 +#define ENB_CONFIG_PUSCH_NDMRS1_IDX 30 +#define ENB_CONFIG_PHICH_DURATION_IDX 31 +#define ENB_CONFIG_PHICH_RESOURCE_IDX 32 +#define ENB_CONFIG_SRS_ENABLE_IDX 33 +#define ENB_CONFIG_SRS_BANDWIDTH_CONFIG_IDX 34 +#define ENB_CONFIG_SRS_SUBFRAME_CONFIG_IDX 35 +#define ENB_CONFIG_SRS_ACKNACKST_CONFIG_IDX 36 +#define ENB_CONFIG_SRS_MAXUPPTS_IDX 37 +#define ENB_CONFIG_PUSCH_PO_NOMINAL_IDX 38 +#define ENB_CONFIG_PUSCH_ALPHA_IDX 39 +#define ENB_CONFIG_PUCCH_PO_NOMINAL_IDX 40 +#define ENB_CONFIG_MSG3_DELTA_PREAMBLE_IDX 41 +#define ENB_CONFIG_PUCCH_DELTAF_FORMAT1_IDX 42 +#define ENB_CONFIG_PUCCH_DELTAF_FORMAT1b_IDX 43 +#define ENB_CONFIG_PUCCH_DELTAF_FORMAT2_IDX 44 +#define ENB_CONFIG_PUCCH_DELTAF_FORMAT2A_IDX 45 +#define ENB_CONFIG_PUCCH_DELTAF_FORMAT2B_IDX 46 +#define ENB_CONFIG_RACH_NUM_RA_PREAMBLES_IDX 47 +#define ENB_CONFIG_RACH_PREAMBLESGROUPACONFIG_IDX 48 +#define ENB_CONFIG_RACH_SIZEOFRA_PREAMBLESGROUPA_IDX 49 +#define ENB_CONFIG_RACH_MESSAGESIZEGROUPA_IDX 50 +#define ENB_CONFIG_RACH_MESSAGEPOWEROFFSETGROUPB_IDX 51 +#define ENB_CONFIG_RACH_POWERRAMPINGSTEP_IDX 52 +#define ENB_CONFIG_RACH_PREAMBLEINITIALRECEIVEDTARGETPOWER_IDX 53 +#define ENB_CONFIG_RACH_PREAMBLETRANSMAX_IDX 54 +#define ENB_CONFIG_RACH_RARESPONSEWINDOWSIZE_IDX 55 +#define ENB_CONFIG_RACH_MACCONTENTIONRESOLUTIONTIMER_IDX 56 +#define ENB_CONFIG_RACH_MAXHARQMSG3TX_IDX 57 +#define ENB_CONFIG_PCCH_DEFAULT_PAGING_CYCLE_IDX 58 +#define ENB_CONFIG_PCCH_NB_IDX 59 +#define ENB_CONFIG_BCCH_MODIFICATIONPERIODCOEFF_IDX 60 +#define ENB_CONFIG_UETIMERS_T300_IDX 61 +#define ENB_CONFIG_UETIMERS_T301_IDX 62 +#define ENB_CONFIG_UETIMERS_T310_IDX 63 +#define ENB_CONFIG_UETIMERS_T311_IDX 64 +#define ENB_CONFIG_UETIMERS_N310_IDX 65 +#define ENB_CONFIG_UETIMERS_N311_IDX 66 +#define ENB_CONFIG_UE_TRANSMISSION_MODE_IDX 67 + /*------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* SRB1 configuration parameters section name */ @@ -569,43 +652,8 @@ typedef enum { -/* L1 configuration parameters names */ -#define CONFIG_STRING_L1_CC "num_cc" -#define CONFIG_STRING_L1_LOCAL_N_IF_NAME "local_n_if_name" -#define CONFIG_STRING_L1_LOCAL_N_ADDRESS "local_n_address" -#define CONFIG_STRING_L1_REMOTE_N_ADDRESS "remote_n_address" -#define CONFIG_STRING_L1_LOCAL_N_PORTC "local_n_portc" -#define CONFIG_STRING_L1_REMOTE_N_PORTC "remote_n_portc" -#define CONFIG_STRING_L1_LOCAL_N_PORTD "local_n_portd" -#define CONFIG_STRING_L1_REMOTE_N_PORTD "remote_n_portd" -#define CONFIG_STRING_L1_TRANSPORT_N_PREFERENCE "tr_n_preference" +/*----------------------------------------------------------------------------------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------------------------------------------------------------------------------*/ -/* L1 configuration parameters */ -/* optname helpstr paramflags XXXptr defXXXval type numelt */ -/*----------------------------------------------------------------------------------------------------------------------------------------------------*/ -#define L1PARAMS_DESC { \ -{CONFIG_STRING_L1_CC, NULL, 0, uptr:NULL, defintval:1, TYPE_UINT, 0}, \ -{CONFIG_STRING_L1_TRANSPORT_N_PREFERENCE, NULL, 0, strptr:NULL, defstrval:"local_mac", TYPE_STRING, 0}, \ -{CONFIG_STRING_L1_LOCAL_N_IF_NAME, NULL, 0, strptr:NULL, defstrval:"lo", TYPE_STRING, 0}, \ -{CONFIG_STRING_L1_LOCAL_N_ADDRESS, NULL, 0, strptr:NULL, defstrval:"127.0.0.1", TYPE_STRING, 0}, \ -{CONFIG_STRING_L1_REMOTE_N_ADDRESS, NULL, 0, strptr:NULL, defstrval:"127.0.0.2", TYPE_STRING, 0}, \ -{CONFIG_STRING_L1_LOCAL_N_PORTC, NULL, 0, uptr:NULL, defintval:50030, TYPE_UINT, 0}, \ -{CONFIG_STRING_L1_REMOTE_N_PORTC, NULL, 0, uptr:NULL, defintval:50030, TYPE_UINT, 0}, \ -{CONFIG_STRING_L1_LOCAL_N_PORTD, NULL, 0, uptr:NULL, defintval:50031, TYPE_UINT, 0}, \ -{CONFIG_STRING_L1_REMOTE_N_PORTD, NULL, 0, uptr:NULL, defintval:50031, TYPE_UINT, 0}, \ -} -#define L1_CC_IDX 0 -#define L1_TRANSPORT_N_PREFERENCE_IDX 1 -#define L1_LOCAL_N_IF_NAME_IDX 2 -#define L1_LOCAL_N_ADDRESS_IDX 3 -#define L1_REMOTE_N_ADDRESS_IDX 4 -#define L1_LOCAL_N_PORTC_IDX 5 -#define L1_REMOTE_N_PORTC_IDX 6 -#define L1_LOCAL_N_PORTD_IDX 7 -#define L1_REMOTE_N_PORTD_IDX 8 - -/*----------------------------------------------------------------------------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ #define CONFIG_STRING_NETWORK_CONTROLLER_CONFIG "NETWORK_CONTROLLER" @@ -639,64 +687,4 @@ typedef enum { #define CONFIG_STRING_MACRLC_CONFIG "macrlc_config" -/* MACRLC configuration parameters names */ -#define CONFIG_STRING_MACRLC_CC "num_cc" -#define CONFIG_STRING_MACRLC_TRANSPORT_N_PREFERENCE "tr_n_preference" -#define CONFIG_STRING_MACRLC_LOCAL_N_IF_NAME "local_n_if_name" -#define CONFIG_STRING_MACRLC_LOCAL_N_ADDRESS "local_n_address" -#define CONFIG_STRING_MACRLC_REMOTE_N_ADDRESS "remote_n_address" -#define CONFIG_STRING_MACRLC_LOCAL_N_PORTC "local_n_portc" -#define CONFIG_STRING_MACRLC_REMOTE_N_PORTC "remote_n_portc" -#define CONFIG_STRING_MACRLC_LOCAL_N_PORTD "local_n_portd" -#define CONFIG_STRING_MACRLC_REMOTE_N_PORTD "remote_n_portd" -#define CONFIG_STRING_MACRLC_TRANSPORT_S_PREFERENCE "tr_s_preference" -#define CONFIG_STRING_MACRLC_LOCAL_S_IF_NAME "local_s_if_name" -#define CONFIG_STRING_MACRLC_LOCAL_S_ADDRESS "local_s_address" -#define CONFIG_STRING_MACRLC_REMOTE_S_ADDRESS "remote_s_address" -#define CONFIG_STRING_MACRLC_LOCAL_S_PORTC "local_s_portc" -#define CONFIG_STRING_MACRLC_REMOTE_S_PORTC "remote_s_portc" -#define CONFIG_STRING_MACRLC_LOCAL_S_PORTD "local_s_portd" -#define CONFIG_STRING_MACRLC_REMOTE_S_PORTD "remote_s_portd" - -/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/ -/* MacRLC configuration parameters */ -/* optname helpstr paramflags XXXptr defXXXval type numelt */ -/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/ -#define MACRLCPARAMS_DESC { \ -{CONFIG_STRING_MACRLC_CC, NULL, 0, uptr:NULL, defintval:50011, TYPE_UINT, 0}, \ -{CONFIG_STRING_MACRLC_TRANSPORT_N_PREFERENCE, NULL, 0, strptr:NULL, defstrval:"local_L1", TYPE_STRING, 0}, \ -{CONFIG_STRING_MACRLC_LOCAL_N_IF_NAME, NULL, 0, strptr:NULL, defstrval:"lo", TYPE_STRING, 0}, \ -{CONFIG_STRING_MACRLC_LOCAL_N_ADDRESS, NULL, 0, strptr:NULL, defstrval:"127.0.0.1", TYPE_STRING, 0}, \ -{CONFIG_STRING_MACRLC_REMOTE_N_ADDRESS, NULL, 0, uptr:NULL, defstrval:"127.0.0.2", TYPE_STRING, 0}, \ -{CONFIG_STRING_MACRLC_LOCAL_N_PORTC, NULL, 0, uptr:NULL, defintval:50010, TYPE_UINT, 0}, \ -{CONFIG_STRING_MACRLC_REMOTE_N_PORTC, NULL, 0, uptr:NULL, defintval:50010, TYPE_UINT, 0}, \ -{CONFIG_STRING_MACRLC_LOCAL_N_PORTD, NULL, 0, uptr:NULL, defintval:50011, TYPE_UINT, 0}, \ -{CONFIG_STRING_MACRLC_REMOTE_N_PORTD, NULL, 0, uptr:NULL, defintval:50011, TYPE_UINT, 0}, \ -{CONFIG_STRING_MACRLC_TRANSPORT_S_PREFERENCE, NULL, 0, strptr:NULL, defstrval:"local_RRC", TYPE_STRING, 0}, \ -{CONFIG_STRING_MACRLC_LOCAL_S_IF_NAME, NULL, 0, strptr:NULL, defstrval:"lo", TYPE_STRING, 0}, \ -{CONFIG_STRING_MACRLC_LOCAL_S_ADDRESS, NULL, 0, uptr:NULL, defstrval:"127.0.0.1", TYPE_STRING, 0}, \ -{CONFIG_STRING_MACRLC_REMOTE_S_ADDRESS, NULL, 0, uptr:NULL, defstrval:"127.0.0.2", TYPE_STRING, 0}, \ -{CONFIG_STRING_MACRLC_LOCAL_S_PORTC, NULL, 0, uptr:NULL, defintval:50020, TYPE_UINT, 0}, \ -{CONFIG_STRING_MACRLC_REMOTE_S_PORTC, NULL, 0, uptr:NULL, defintval:50020, TYPE_UINT, 0}, \ -{CONFIG_STRING_MACRLC_LOCAL_S_PORTD, NULL, 0, uptr:NULL, defintval:50021, TYPE_UINT, 0}, \ -{CONFIG_STRING_MACRLC_REMOTE_S_PORTD, NULL, 0, uptr:NULL, defintval:50021, TYPE_UINT, 0}, \ -} -#define MACRLC_CC_IDX 0 -#define MACRLC_TRANSPORT_N_PREFERENCE_IDX 1 -#define MACRLC_LOCAL_N_IF_NAME_IDX 2 -#define MACRLC_LOCAL_N_ADDRESS_IDX 3 -#define MACRLC_REMOTE_N_ADDRESS_IDX 4 -#define MACRLC_LOCAL_N_PORTC_IDX 5 -#define MACRLC_REMOTE_N_PORTC_IDX 6 -#define MACRLC_LOCAL_N_PORTD_IDX 7 -#define MACRLC_REMOTE_N_PORTD_IDX 8 -#define MACRLC_TRANSPORT_S_PREFERENCE_IDX 9 -#define MACRLC_LOCAL_S_IF_NAME_IDX 10 -#define MACRLC_LOCAL_S_ADDRESS_IDX 11 -#define MACRLC_REMOTE_S_ADDRESS_IDX 12 -#define MACRLC_LOCAL_S_PORTC_IDX 13 -#define MACRLC_REMOTE_S_PORTC_IDX 14 -#define MACRLC_LOCAL_S_PORTD_IDX 15 -#define MACRLC_REMOTE_S_PORTD_IDX 16 -/*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ diff --git a/openair2/ENB_APP/nbiot_config.c b/openair2/ENB_APP/nbiot_config.c new file mode 100644 index 0000000000..3862a01403 --- /dev/null +++ b/openair2/ENB_APP/nbiot_config.c @@ -0,0 +1,295 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/* + nbiot_config.c + ------------------- + AUTHOR : Francois Taburet + COMPANY : NOKIA + EMAIL : francois.taburet@nokia-bell-labs.com +*/ + +#include +#include + +#include "log.h" +#include "log_extern.h" +#include "assertions.h" +#include "enb_config.h" +#include "UTIL/OTG/otg.h" +#include "UTIL/OTG/otg_externs.h" +#if defined(OAI_EMU) +# include "OCG.h" +# include "OCG_extern.h" +#endif +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +# if defined(ENABLE_USE_MME) +# include "s1ap_eNB.h" +# include "sctp_eNB_task.h" +# endif +#endif +#include "sctp_default_values.h" +#include "SystemInformationBlockType2.h" +#include "LAYER2/MAC/extern.h" +#include "PHY/extern.h" +#include "targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h" + +#include "common/config/config_userapi.h" +#include "RRC_config_tools.h" +#include "RRC_paramsvalues.h" +#include "nbiot_paramdef.h" +#include "L1_paramdef.h" +#include "MACRLC_paramdef.h" +#include "LAYER2/MAC/proto_NB_IoT.h" + + +void RCconfig_NbIoTL1(void) { + paramdef_t NbIoT_L1_Params[] = L1PARAMS_DESC; + paramlist_def_t NbIoT_L1_ParamList = {NBIOT_L1LIST_CONFIG_STRING,NULL,0}; + +/* No component carrier for NbIoT, ignore number of CC */ +// NbIoT_L1_Params[L1_CC_IDX ].paramflags = PARAMFLAG_DONOTREAD; + + config_getlist( &NbIoT_L1_ParamList,NbIoT_L1_Params,sizeof(NbIoT_L1_Params)/sizeof(paramdef_t), NULL); + if (NbIoT_L1_ParamList.numelt > 0) { + if (RC.L1_NB_IoT == NULL) { + RC.L1_NB_IoT = (PHY_VARS_eNB_NB_IoT **)malloc(RC.nb_nb_iot_L1_inst*sizeof(PHY_VARS_eNB_NB_IoT *)); + LOG_I(PHY,"RC.L1_NB_IoT = %p\n",RC.L1_NB_IoT); + memset(RC.L1_NB_IoT,0,RC.nb_nb_iot_L1_inst*sizeof(PHY_VARS_eNB_NB_IoT *)); + } + + + for(int j = 0; j eth_params_n.local_if_name = strdup(*(NbIoT_L1_ParamList.paramarray[j][L1_LOCAL_N_IF_NAME_IDX].strptr)); + RC.L1_NB_IoT[j]->eth_params_n.my_addr = strdup(*(NbIoT_L1_ParamList.paramarray[j][L1_LOCAL_N_ADDRESS_IDX].strptr)); + RC.L1_NB_IoT[j]->eth_params_n.remote_addr = strdup(*(NbIoT_L1_ParamList.paramarray[j][L1_REMOTE_N_ADDRESS_IDX].strptr)); + RC.L1_NB_IoT[j]->eth_params_n.my_portc = *(NbIoT_L1_ParamList.paramarray[j][L1_LOCAL_N_PORTC_IDX].iptr); + RC.L1_NB_IoT[j]->eth_params_n.remote_portc = *(NbIoT_L1_ParamList.paramarray[j][L1_REMOTE_N_PORTC_IDX].iptr); + RC.L1_NB_IoT[j]->eth_params_n.my_portd = *(NbIoT_L1_ParamList.paramarray[j][L1_LOCAL_N_PORTD_IDX].iptr); + RC.L1_NB_IoT[j]->eth_params_n.remote_portd = *(NbIoT_L1_ParamList.paramarray[j][L1_REMOTE_N_PORTD_IDX].iptr); + RC.L1_NB_IoT[j]->eth_params_n.transp_preference = ETH_UDP_MODE; + } + + else { // other midhaul + } + }// j=0..num_inst + printf("Initializing northbound interface for NB-IoT L1\n"); + l1_north_init_NB_IoT(); + } else { + LOG_I(PHY,"No " NBIOT_L1LIST_CONFIG_STRING " configuration found"); + } +} + +void RCconfig_NbIoTmacrlc(void) { + + + + paramdef_t NbIoT_MacRLC_Params[] = MACRLCPARAMS_DESC; + paramlist_def_t NbIoT_MacRLC_ParamList = {NBIOT_MACRLCLIST_CONFIG_STRING,NULL,0}; + + +/* No component carrier for NbIoT, ignore number of CC */ +// NbIoT_MacRLC_Params[MACRLC_CC_IDX ].paramflags = PARAMFLAG_DONOTREAD; + + config_getlist( &NbIoT_MacRLC_ParamList,NbIoT_MacRLC_Params,sizeof(NbIoT_MacRLC_Params)/sizeof(paramdef_t), NULL); + + + if ( NbIoT_MacRLC_ParamList.numelt > 0) { + mac_top_init_eNB_NB_IoT(); + for (int j=0;jeth_params_n.local_if_name = strdup(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_IF_NAME_IDX].strptr)); + RC.nb_iot_mac[j]->eth_params_n.my_addr = strdup(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_ADDRESS_IDX].strptr)); + RC.nb_iot_mac[j]->eth_params_n.remote_addr = strdup(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_ADDRESS_IDX].strptr)); + RC.nb_iot_mac[j]->eth_params_n.my_portc = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_PORTC_IDX].iptr); + RC.nb_iot_mac[j]->eth_params_n.remote_portc = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_PORTC_IDX].iptr); + RC.nb_iot_mac[j]->eth_params_n.my_portd = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_PORTD_IDX].iptr); + RC.nb_iot_mac[j]->eth_params_n.remote_portd = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_PORTD_IDX].iptr);; + RC.nb_iot_mac[j]->eth_params_n.transp_preference = ETH_UDP_MODE; + } else { // other midhaul + AssertFatal(1==0,"MACRLC %d: %s unknown northbound midhaul\n",j, *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr)); + } + + if (strcmp(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr), "local_L1") == 0) { + + + } else if (strcmp(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr), "nfapi") == 0) { + RC.nb_iot_mac[j]->eth_params_s.local_if_name = strdup(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_IF_NAME_IDX].strptr)); + RC.nb_iot_mac[j]->eth_params_s.my_addr = strdup(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_ADDRESS_IDX].strptr)); + RC.nb_iot_mac[j]->eth_params_s.remote_addr = strdup(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_ADDRESS_IDX].strptr)); + RC.nb_iot_mac[j]->eth_params_s.my_portc = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_PORTC_IDX].iptr); + RC.nb_iot_mac[j]->eth_params_s.remote_portc = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_PORTC_IDX].iptr); + RC.nb_iot_mac[j]->eth_params_s.my_portd = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_PORTD_IDX].iptr); + RC.nb_iot_mac[j]->eth_params_s.remote_portd = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_PORTD_IDX].iptr); + RC.nb_iot_mac[j]->eth_params_s.transp_preference = ETH_UDP_MODE; + } else { // other midhaul + AssertFatal(1==0,"MACRLC %d: %s unknown southbound midhaul\n",j,*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr)); + } + }// j=0..num_inst */ + } else {// MacRLC_ParamList.numelt > 0 + AssertFatal (0, + "No " NBIOT_MACRLCLIST_CONFIG_STRING " configuration found"); + } +} + + + + +int RCconfig_NbIoTRRC(MessageDef *msg_p, int nbiotrrc_id,eNB_RRC_INST_NB_IoT *nbiotrrc) { + + + char instprefix[MAX_OPTNAME_SIZE*3 + 32]; + + + checkedparam_t NBIoTCheckParams[] = NBIOT_RRCPARAMS_CHECK_DESC; + paramdef_t NBIoTParams[] = NBIOTRRCPARAMS_DESC; + + paramdef_t NBIoTPrachParams[] = NBIOTRRC_NPRACH_PARAMS_DESC; + checkedparam_t NBIoTPrachCheckParams[] = NBIOT_RRCLIST_NPRACHPARAMSCHECK_DESC; + + paramdef_t NBIoTRRCRefParams[] = NBIOTRRCPARAMS_RRCREF_DESC; + + paramdef_t NBIoTLteCCParams[] = NBIOT_LTECCPARAMS_DESC; + checkedparam_t NBIoTLteCCCheckParams[] = NBIOT_LTECCPARAMS_CHECK_DESC; +/* map parameter checking array instances to parameter definition array instances */ + for (int i=0; (inb_nb_iot_rrc_inst = NbIoT_ParamList.numelt; + + + + + config_getlist( &NbIoT_MACRLCParamList,NULL,0, NULL); + RC->nb_nb_iot_macrlc_inst = NbIoT_MACRLCParamList.numelt; + // Get num L1 instances + config_getlist( &NbIoT_L1ParamList,NULL,0, NULL); + RC->nb_nb_iot_L1_inst = NbIoT_L1ParamList.numelt; + +} diff --git a/openair2/ENB_APP/nbiot_config.h b/openair2/ENB_APP/nbiot_config.h new file mode 100644 index 0000000000..314fca8180 --- /dev/null +++ b/openair2/ENB_APP/nbiot_config.h @@ -0,0 +1,37 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/* + nbiot_config.h + ------------------- + AUTHOR : Francois Taburet + COMPANY : NOKIA + EMAIL : francois.taburet@nokia-bell-labs.com +*/ +#ifndef INCLUDE_NBIOT_CONFIG_H +#define INCLUDE_NBIOT_CONFIG_H + + +extern void RCconfig_NbIoTL1(void) ; +extern void RCconfig_NbIoTmacrlc(void); +extern int RCconfig_NbIoTRRC(MessageDef *msg_p, int nbiotrrc_id,eNB_RRC_INST_NB_IoT *nbiotrrc); +extern void RCConfig_NbIoT(RAN_CONTEXT_t *RC); +#endif diff --git a/openair2/ENB_APP/nbiot_paramdef.h b/openair2/ENB_APP/nbiot_paramdef.h new file mode 100644 index 0000000000..615c96a7b6 --- /dev/null +++ b/openair2/ENB_APP/nbiot_paramdef.h @@ -0,0 +1,400 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file openair2/ENB_APP/enb_paramdef.f + * \brief definition of configuration parameters for all eNodeB modules + * \author Francois TABURET + * \date 2017 + * \version 0.1 + * \company NOKIA BellLabs France + * \email: francois.taburet@nokia-bell-labs.com + * \note + * \warning + */ + +#include "common/config/config_paramdesc.h" +#include "SystemInformationBlockType2.h" +#include "DL-GapConfig-NB-r13.h" +#include "NPRACH-Parameters-NB-r13.h" +#include "PowerRampingParameters.h" +#include "BCCH-Config-NB-r13.h" +#include "PCCH-Config-NB-r13.h" +#include "ACK-NACK-NumRepetitions-NB-r13.h" +#include "TDD-Config.h" + + + + + +/* + int16_t eutra_band; + uint32_t downlink_frequency; + int32_t uplink_frequency_offset; + int16_t Nid_cell;// for testing, change later + int16_t N_RB_DL;// for testing, change later +*/ +/*-------------------------------------------------------------------------------------------------------------------*/ +/* SIB1 parameters possibly coming from LTE RRC (in band deployment) */ +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* component carriers configuration parameters */ +/* optname helpstr paramflags XXXptr defXXXval type numelt checked_param */ +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define NBIOT_LTECCPARAMS_CHECK_DESC { \ + { .s3a= { config_checkstr_assign_integer, FRAMETYPE_OKVALUES, FRAMETYPE_MODVALUES,2}} , \ + { .s2= { config_check_intrange, TDDCONFIG_OKRANGE}}, \ + { .s2= { config_check_intrange, TDDCONFIGS_OKRANGE}}, \ + { .s3a= { config_checkstr_assign_integer, PREFIX_OKVALUES, PREFIX_MODVALUES,2}} , \ + { .s3a= { config_checkstr_assign_integer, PREFIXUL_OKVALUES, PREFIXUL_MODVALUES,2}} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s5= {NULL }} , \ + { .s1= { config_check_intval, NRBDL_OKVALUES,6}} , \ +} + + +#define NBIOT_LTECCPARAMS_DESC { \ +{ENB_CONFIG_STRING_FRAME_TYPE, NULL, 0, strptr:NULL, defstrval:"FDD", TYPE_STRING, 0}, \ +{ENB_CONFIG_STRING_TDD_CONFIG, NULL, 0, iptr:NULL, defintval:3, TYPE_UINT, 0}, \ +{ENB_CONFIG_STRING_TDD_CONFIG_S, NULL, 0, iptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{ENB_CONFIG_STRING_PREFIX_TYPE, NULL, 0, strptr:NULL, defstrval:"NORMAL", TYPE_STRING, 0}, \ +{ENB_CONFIG_STRING_PREFIX_TYPE_UL, NULL, 0, strptr:NULL, defstrval:"NORMAL", TYPE_STRING, 0}, \ +{ENB_CONFIG_STRING_EUTRA_BAND, NULL, 0, iptr:NULL, defintval:7, TYPE_UINT, 0}, \ +{ENB_CONFIG_STRING_DOWNLINK_FREQUENCY, NULL, 0, i64ptr:NULL, defint64val:2680000000, TYPE_UINT64, 0}, \ +{ENB_CONFIG_STRING_UPLINK_FREQUENCY_OFFSET, NULL, 0, iptr:NULL, defintval:-120000000, TYPE_INT, 0}, \ +{ENB_CONFIG_STRING_NID_CELL, NULL, 0, iptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{ENB_CONFIG_STRING_N_RB_DL, NULL, 0, iptr:NULL, defintval:25, TYPE_UINT, 0}, \ +} +#define LTECCPARAMS_FRAME_TYPE_IDX 0 +#define LTECCPARAMS_TDD_CONFIG_IDX 1 +#define LTECCPARAMS_TDD_CONFIG_S_IDX 2 +#define LTECCPARAMS_PREFIX_TYPE_IDX 3 +#define LTECCPARAMS_PREFIX_TYPE_UL_IDX 4 +#define LTECCPARAMS_EUTRA_BAND_IDX 5 +#define LTECCPARAMS_DOWNLINK_FREQUENCY_IDX 6 +#define LTECCPARAMS_UPLINK_FREQUENCY_OFFSET_IDX 7 +#define LTECCPARAMS_NID_CELL_IDX 8 +#define LTECCPARAMS_N_RB_DL_IDX 9 + + +/*-------------------------------------------------------------------------------------------------------------------*/ + +/* NB-Iot RRC list section name */ +#define NBIOT_RRCLIST_CONFIG_STRING "NB-IoT_RRCs" + + +#define RACH_RARESPONSEWINDOWSIZE_NB_OKVALUES {20,50,80,120,180,240,320,400} +#define PREF1(A) RACH_CE_LevelInfo_r13__ra_ResponseWindowSize_r13_ ## A +#define RACH_RARESPONSEWINDOWSIZE_NB_MODVALUES { PREF1(sf20),PREF1(sf50),PREF1(sf80),PREF1(sf120), \ + PREF1(sf180),PREF1(sf240),PREF1(sf320),PREF1(sf400) } + + +#define RACH_MACCONTENTIONRESOLUTIONTIMER_NB_OKVALUES {80,100,120,160,200,240,480,960} +#define PREF2(A) RACH_CE_LevelInfo_r13__mac_ContentionResolutionTimer_r13_ ## A +#define RACH_MACCONTENTIONRESOLUTIONTIMER_NB_MODVALUES { PREF2(sf80),PREF2(sf100),PREF2(sf120),PREF2(sf160), \ + PREF2(sf200),PREF2(sf240),PREF2(sf480),PREF2(sf960) } + + +#define RACH_POWERRAMPINGSTEP_NB_OKVALUES {0,2,4,6} +#define PREF3(A) PowerRampingParameters__powerRampingStep_ ## A +#define RACH_POWERRAMPINGSTEP_NB_MODVALUES { PREF3(dB0),PREF3(dB2),PREF3(dB4),PREF3(dB6) } + + +#define RACH_PREAMBLEINITIALRECEIVEDTARGETPOWER_NB_OKRANGE {-120, -90} + +#define RACH_PREAMBLETRANSMAX_CE_NB_OKVALUES {3,4,5,6,7,8,10,20,50,100,200} +#define PREF4(A) PreambleTransMax_ ## A +#define RACH_PREAMBLETRANSMAX_CE_NB_MODVALUES { PREF4(n3), PREF4(n4), PREF4(n5), PREF4(n6), PREF4(n7), PREF4(n8), \ + PREF4(n10),PREF4(n20),PREF4(n50),PREF4(n100),PREF4(n200) } + +#define BCCH_MODIFICATIONPERIODCOEFF_NB_OKVALUES {16,32,64,128} +#define PREF5(A) BCCH_Config_NB_r13__modificationPeriodCoeff_r13_ ## A +#define BCCH_MODIFICATIONPERIODCOEFF_NB_MODVALUES { PREF5(n16), PREF5(n32), PREF5(n64),PREF5(n128) } + +#define PCCH_DEFAULTPAGINGCYCLE_NB_OKVALUES {128,256,512,1024} +#define PREF6(A) PCCH_Config_NB_r13__defaultPagingCycle_r13_ ## A +#define PCCH_DEFAULTPAGINGCYCLE_NB_MODVALUES { PREF6(rf128), PREF6(rf256), PREF6(rf512), PREF6(rf1024) } + +#define NPRACH_CP_LENGTH_OKVALUES {0,1} +#define NPRACH_RSRP_RANGE_OKVALUES {0,96} + +#define MSG3RANGESTART_OKVALUES {"zero","oneThird","twoThird","one"} +#define MSG3RANGESTART_MODVALUES {NPRACH_Parameters_NB_r13__nprach_SubcarrierMSG3_RangeStart_r13_zero, NPRACH_Parameters_NB_r13__nprach_SubcarrierMSG3_RangeStart_r13_oneThird, \ + NPRACH_Parameters_NB_r13__nprach_SubcarrierMSG3_RangeStart_r13_twoThird, NPRACH_Parameters_NB_r13__nprach_SubcarrierMSG3_RangeStart_r13_one} + + +#define MAXNUMPREAMBLEATTEMPTCE_OKVALUES {3,4,5,6,7,8,10} +#define MAXNUMPREAMBLEATTEMPTCE_MODVALUES { NPRACH_Parameters_NB_r13__maxNumPreambleAttemptCE_r13_n3, NPRACH_Parameters_NB_r13__maxNumPreambleAttemptCE_r13_n4, \ + NPRACH_Parameters_NB_r13__maxNumPreambleAttemptCE_r13_n5, NPRACH_Parameters_NB_r13__maxNumPreambleAttemptCE_r13_n6, \ + NPRACH_Parameters_NB_r13__maxNumPreambleAttemptCE_r13_n7, NPRACH_Parameters_NB_r13__maxNumPreambleAttemptCE_r13_n8, \ + NPRACH_Parameters_NB_r13__maxNumPreambleAttemptCE_r13_n10 } + +#define NPDSCH_NRS_POWER_OKRANGE {-60,50} + +#define NPUSCH_ACK_NACK_NUMREPETITIONS_NB_OKVALUES {1,2,4,8,16,32,64,128} +#define PREF9(A) ACK_NACK_NumRepetitions_NB_r13_ ## A +#define NPUSCH_ACK_NACK_NUMREPETITIONS_NB_MODVALUES { PREF9(r1), PREF9(r2), PREF9(r4), PREF9(r8), \ + PREF9(r16), PREF9(r32), PREF9(r64), PREF9(r128) } + +#define NPUSCH_SRS_SUBFRAMECONFIG_NB_OKRANGE {0,15} +#define NPUSCH_THREETONE_CYCLICSHIFT_R13_OKRANGE {0,2} +#define NPUSCH_SIXTONE_CYCLICSHIFT_R13_OKRANGE {0,3} + +#define NPUSCH_GROUPHOPPINGENABLED_OKVALUES {"enable","disable"} +#define NPUSCH_GROUPHOPPINGENABLED_MODVALUES {1,0} + +#define NPUSCH_GROUPASSIGNMENTNPUSCH_R13_OKRANGE {0,29} + +#define DLGAPTHRESHOLD_OKVALUES {32,64,128,256} +#define DLGAPTHRESHOLD_MODVALUES { DL_GapConfig_NB_r13__dl_GapThreshold_r13_n32, DL_GapConfig_NB_r13__dl_GapThreshold_r13_n64, \ + DL_GapConfig_NB_r13__dl_GapThreshold_r13_n128, DL_GapConfig_NB_r13__dl_GapThreshold_r13_n256} \ + +#define DLGAPPERIODICITY_OKVALUES {64,128,256,512} +#define DLGAPPERIODICITY_MODVALUES { DL_GapConfig_NB_r13__dl_GapPeriodicity_r13_sf64, DL_GapConfig_NB_r13__dl_GapPeriodicity_r13_sf128, \ + DL_GapConfig_NB_r13__dl_GapPeriodicity_r13_sf256,DL_GapConfig_NB_r13__dl_GapPeriodicity_r13_sf512} + +#define DLGAPDURATION_OKVALUES {"oneEighth","oneFourth","threeEighth","oneHalf"} +#define DLGAPDURATION_MODVALUES {DL_GapConfig_NB_r13__dl_GapDurationCoeff_r13_oneEighth, DL_GapConfig_NB_r13__dl_GapDurationCoeff_r13_oneFourth, \ + DL_GapConfig_NB_r13__dl_GapDurationCoeff_r13_threeEighth, DL_GapConfig_NB_r13__dl_GapDurationCoeff_r13_oneHalf} + +#define NPUSCH_P0_NOMINALNPUSCH_OKRANGE {-126,24} + +#define NPUSCH_ALPHA_OKVALUES {"AL0","AL04","AL05","AL06","AL07","AL08","AL09","AL1"} +#define NPUSCH_ALPHA_MODVALUES { Alpha_r12_al0, Alpha_r12_al04, Alpha_r12_al05, Alpha_r12_al06, \ + Alpha_r12_al07, Alpha_r12_al08, Alpha_r12_al09, Alpha_r12_al1} + +#define DELTAPREAMBLEMSG3_OKRANGE {-1,6} + + + + + +#define NBIOT_RRCPARAMS_CHECK_DESC { \ + { .s1a= { config_check_modify_integer, RACH_RARESPONSEWINDOWSIZE_NB_OKVALUES, RACH_RARESPONSEWINDOWSIZE_NB_MODVALUES, 8}}, \ + { .s1a= { config_check_modify_integer, RACH_MACCONTENTIONRESOLUTIONTIMER_NB_OKVALUES, RACH_MACCONTENTIONRESOLUTIONTIMER_NB_MODVALUES, 8}}, \ + { .s1a= { config_check_modify_integer, RACH_POWERRAMPINGSTEP_NB_OKVALUES, RACH_POWERRAMPINGSTEP_NB_MODVALUES, 4}} , \ + { .s2= { config_check_intrange, RACH_PREAMBLEINITIALRECEIVEDTARGETPOWER_NB_OKRANGE}}, \ + { .s1a= { config_check_modify_integer, RACH_PREAMBLETRANSMAX_CE_NB_OKVALUES, RACH_PREAMBLETRANSMAX_CE_NB_MODVALUES, 11}} , \ + { .s1a= { config_check_modify_integer, BCCH_MODIFICATIONPERIODCOEFF_NB_OKVALUES, BCCH_MODIFICATIONPERIODCOEFF_NB_MODVALUES, 4}} , \ + { .s1a= { config_check_modify_integer, PCCH_DEFAULTPAGINGCYCLE_NB_OKVALUES, PCCH_DEFAULTPAGINGCYCLE_NB_MODVALUES, 4}} , \ + { .s1= { NULL, NPRACH_CP_LENGTH_OKVALUES ,4}} , \ + { .s2= { config_check_intrange, NPRACH_RSRP_RANGE_OKVALUES}} , \ + { .s3a= { config_checkstr_assign_integer, MSG3RANGESTART_OKVALUES, MSG3RANGESTART_MODVALUES, 4}} , \ + { .s1a= { config_check_modify_integer, MAXNUMPREAMBLEATTEMPTCE_OKVALUES, MAXNUMPREAMBLEATTEMPTCE_MODVALUES, 7}} , \ + { .s1= { config_check_intval, NPDSCH_NRS_POWER_OKRANGE,4}} , \ + { .s1a= { config_check_modify_integer, NPUSCH_ACK_NACK_NUMREPETITIONS_NB_OKVALUES, NPUSCH_ACK_NACK_NUMREPETITIONS_NB_MODVALUES, 8}} , \ + { .s2= { config_check_intrange, NPUSCH_SRS_SUBFRAMECONFIG_NB_OKRANGE}} , \ + { .s2= { config_check_intrange, NPUSCH_THREETONE_CYCLICSHIFT_R13_OKRANGE}} , \ + { .s2= { config_check_intrange, NPUSCH_SIXTONE_CYCLICSHIFT_R13_OKRANGE}} , \ + { .s3a= { config_checkstr_assign_integer, NPUSCH_GROUPHOPPINGENABLED_OKVALUES, NPUSCH_GROUPHOPPINGENABLED_MODVALUES, 2}} , \ + { .s2= { config_check_intrange, NPUSCH_GROUPASSIGNMENTNPUSCH_R13_OKRANGE}} , \ + { .s1a= { config_check_modify_integer, DLGAPTHRESHOLD_OKVALUES, DLGAPTHRESHOLD_MODVALUES, 4}} , \ + { .s1a= { config_check_modify_integer, DLGAPPERIODICITY_OKVALUES, DLGAPPERIODICITY_MODVALUES, 4}} , \ + { .s3a= { config_checkstr_assign_integer, DLGAPDURATION_OKVALUES, DLGAPDURATION_MODVALUES , 4}} , \ + { .s2= { config_check_intrange, NPUSCH_P0_NOMINALNPUSCH_OKRANGE}} , \ + { .s3a= { config_checkstr_assign_integer, NPUSCH_ALPHA_OKVALUES, NPUSCH_ALPHA_MODVALUES, 8}} , \ + { .s2= { config_check_intrange, DELTAPREAMBLEMSG3_OKRANGE}} , \ + { .s1a= { config_check_modify_integer, UETIMER_T300_OKVALUES, UETIMER_T300_MODVALUES,8}} , \ + { .s1a= { config_check_modify_integer, UETIMER_T301_OKVALUES, UETIMER_T301_MODVALUES,8}} , \ + { .s1a= { config_check_modify_integer, UETIMER_T310_OKVALUES, UETIMER_T310_MODVALUES,7}} , \ + { .s1a= { config_check_modify_integer, UETIMER_T311_OKVALUES, UETIMER_T311_MODVALUES,7}} , \ + { .s1a= { config_check_modify_integer, UETIMER_N310_OKVALUES, UETIMER_N310_MODVALUES,8}} , \ + { .s1a= { config_check_modify_integer, UETIMER_N311_OKVALUES, UETIMER_N311_MODVALUES,8}} , \ +} +/*-----------------------------------------------------------------------------------------------------------------------------------------*/ +/* NB-IoT RRC configuration parameters */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*-----------------------------------------------------------------------------------------------------------------------------------------*/ +#define NBIOTRRCPARAMS_DESC { \ +{"rach_raResponseWindowSize_NB", NULL, 0, uptr:NULL, defintval:20, TYPE_UINT, 0}, \ +{"rach_macContentionResolutionTimer_NB", NULL, 0, uptr:NULL, defintval:80, TYPE_UINT, 0}, \ +{"rach_powerRampingStep_NB", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{"rach_preambleInitialReceivedTargetPower_NB", NULL, 0, iptr:NULL, defintval:-112, TYPE_INT32, 0}, \ +{"rach_preambleTransMax_CE_NB", NULL, 0, uptr:NULL, defintval:3, TYPE_UINT, 0}, \ +{"bcch_modificationPeriodCoeff_NB", NULL, 0, uptr:NULL, defintval:16, TYPE_UINT, 0}, \ +{"pcch_defaultPagingCycle_NB", NULL, 0, uptr:NULL, defintval:256, TYPE_UINT, 0}, \ +{"nprach_CP_Length", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{"nprach_rsrp_range", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{"nprach_SubcarrierMSG3_RangeStart", NULL, 0, strptr:NULL, defstrval:"one", TYPE_STRING, 0}, \ +{"maxNumPreambleAttemptCE_NB", NULL, 0, uptr:NULL, defintval:10, TYPE_UINT, 0}, \ +{"npdsch_nrs_Power", NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ +{"npusch_ack_nack_numRepetitions_NB", NULL, 0, uptr:NULL, defintval:1, TYPE_UINT, 0}, \ +{"npusch_srs_SubframeConfig_NB", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{"npusch_threeTone_CyclicShift_r13", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{"npusch_sixTone_CyclicShift_r13", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{"npusch_groupHoppingEnabled", NULL, 0, strptr:NULL, defstrval:"disable", TYPE_STRING, 0}, \ +{"npusch_groupAssignmentNPUSCH_r13", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{"dl_GapThreshold_NB", NULL, 0, uptr:NULL, defintval:32, TYPE_UINT, 0}, \ +{"dl_GapPeriodicity_NB", NULL, 0, uptr:NULL, defintval:64, TYPE_UINT, 0}, \ +{"dl_GapDurationCoeff_NB", NULL, 0, strptr:NULL, defstrval:"oneEighth", TYPE_STRING, 0}, \ +{"npusch_p0_NominalNPUSCH", NULL, 0, iptr:NULL, defintval:0, TYPE_INT32, 0}, \ +{"npusch_alpha", NULL, 0, strptr:NULL, defstrval:"AL0", TYPE_STRING, 0}, \ +{"deltaPreambleMsg3", NULL, 0, iptr:NULL, defintval:0, TYPE_INT32, 0}, \ +{"ue_TimersAndConstants_t300_NB", NULL, 0, uptr:NULL, defintval:1000, TYPE_UINT, 0}, \ +{"ue_TimersAndConstants_t301_NB", NULL, 0, uptr:NULL, defintval:1000, TYPE_UINT, 0}, \ +{"ue_TimersAndConstants_t310_NB", NULL, 0, uptr:NULL, defintval:1000, TYPE_UINT, 0}, \ +{"ue_TimersAndConstants_t311_NB", NULL, 0, uptr:NULL, defintval:10000, TYPE_UINT, 0}, \ +{"ue_TimersAndConstants_n310_NB", NULL, 0, uptr:NULL, defintval:20, TYPE_UINT, 0}, \ +{"ue_TimersAndConstants_n311_NB", NULL, 0, uptr:NULL, defintval:1, TYPE_UINT, 0}, \ +} + +#define NBIOT_RACH_RARESPONSEWINDOWSIZE_NB_IDX 0 +#define NBIOT_RACH_MACCONTENTIONRESOLUTIONTIMER_NB_IDX 1 +#define NBIOT_RACH_POWERRAMPINGSTEP_NB_IDX 2 +#define NBIOT_RACH_PREAMBLEINITIALRECEIVEDTARGETPOWER_NB_IDX 3 +#define NBIOT_RACH_PREAMBLETRANSMAX_CE_NB_IDX 4 +#define NBIOT_BCCH_MODIFICATIONPERIODCOEFF_NB_IDX 5 +#define NBIOT_PCCH_DEFAULTPAGINGCYCLE_NB_IDX 6 +#define NBIOT_NPRACH_CP_LENGTH_IDX 7 +#define NBIOT_NPRACH_RSRP_RANGE_IDX 8 +#define NBIOT_NPRACH_SUBCARRIERMSG3_RANGESTART_IDX 9 +#define NBIOT_MAXNUMPREAMBLEATTEMPTCE_NB_IDX 10 +#define NBIOT_NPDSCH_NRS_POWER_IDX 11 +#define NBIOT_NPUSCH_ACK_NACK_NUMREPETITIONS_NB_IDX 12 +#define NBIOT_NPUSCH_SRS_SUBFRAMECONFIG_NB_IDX 13 +#define NBIOT_NPUSCH_THREETONE_CYCLICSHIFT_R13_IDX 14 +#define NBIOT_NPUSCH_SIXTONE_CYCLICSHIFT_R13_IDX 15 +#define NBIOT_NPUSCH_GROUPHOPPINGENABLED_IDX 16 +#define NBIOT_NPUSCH_GROUPASSIGNMENTNPUSCH_R13_IDX 17 +#define NBIOT_DL_GAPTHRESHOLD_NB_IDX 18 +#define NBIOT_DL_GAPPERIODICITY_NB_IDX 19 +#define NBIOT_DL_GAPDURATIONCOEFF_NB_IDX 20 +#define NBIOT_NPUSCH_P0_NOMINALNPUSCH_IDX 21 +#define NBIOT_NPUSCH_ALPHA_IDX 22 +#define NBIOT_DELTAPREAMBLEMSG3_IDX 23 +#define NBIOT_UE_TIMERSANDCONSTANTS_T300_NB_IDX 24 +#define NBIOT_UE_TIMERSANDCONSTANTS_T301_NB_IDX 25 +#define NBIOT_UE_TIMERSANDCONSTANTS_T310_NB_IDX 26 +#define NBIOT_UE_TIMERSANDCONSTANTS_T311_NB_IDX 27 +#define NBIOT_UE_TIMERSANDCONSTANTS_N310_NB_IDX 28 +#define NBIOT_UE_TIMERSANDCONSTANTS_N311_NB_IDX 29 + +/* NB-Iot RRC: link to LTE RRC section name */ +#define NBIOT_LTERRCREF_CONFIG_STRING "LTERRC_Ref" +/*---------------------------------------------------------------------------------------------------------------*/ +/* NB-IoT RRC configuration parameters to link to a LTE RRC instance (in-guard, in-band) */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*---------------------------------------------------------------------------------------------------------------*/ +#define NBIOTRRCPARAMS_RRCREF_DESC { \ +{"RRC_inst", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{"CC_inst", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +} +/*--------------------------------------------------------------------------------------------------------------*/ +#define NBIOT_RRCINST_IDX 0 +#define NBIOT_CCINST_IDX 1 + +#define NBIOT_RRCLIST_NPRACHPARAMS_CONFIG_STRING "NPRACH-NB-r13" + + +#define NPRACH_PERIODICITY_OKVALUES {40,80,160,240,320,640,1280,2560} +#define NPRACH_PERIODICITY_MODVALUES { NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms40, NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms80, \ + NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms160, NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms240, \ + NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms320, NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms640, \ + NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms1280, NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms2560 } + +#define NPRACH_STARTTIME_OKVALUES {8,16,32,64,128,256,512,1024} +#define NPRACH_STARTTIME_MODVALUES { NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms8, NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms16, \ + NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms32, NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms64, \ + NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms128, NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms256, \ + NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms512, NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms1024 } + +#define NPRACH_SUBCARRIEROFFSET_OKVALUES {0,12,24,36,2,18,34} +#define NPRACH_SUBCARRIEROFFSET_MODVALUES { NPRACH_Parameters_NB_r13__nprach_SubcarrierOffset_r13_n0, NPRACH_Parameters_NB_r13__nprach_SubcarrierOffset_r13_n12, \ + NPRACH_Parameters_NB_r13__nprach_SubcarrierOffset_r13_n24, NPRACH_Parameters_NB_r13__nprach_SubcarrierOffset_r13_n36, \ + NPRACH_Parameters_NB_r13__nprach_SubcarrierOffset_r13_n2, NPRACH_Parameters_NB_r13__nprach_SubcarrierOffset_r13_n18, \ + NPRACH_Parameters_NB_r13__nprach_SubcarrierOffset_r13_n34 } + +#define NPRACH_NUMSUBCARRIERS_OKVALUES {12,24,36,48} +#define NPRACH_NUMSUBCARRIERS_MODVALUES { NPRACH_Parameters_NB_r13__nprach_NumSubcarriers_r13_n12, NPRACH_Parameters_NB_r13__nprach_NumSubcarriers_r13_n24, \ + NPRACH_Parameters_NB_r13__nprach_NumSubcarriers_r13_n36, NPRACH_Parameters_NB_r13__nprach_NumSubcarriers_r13_n48 } + + +#define NUMREPETITIONSPERPREAMBLEATTEMPT_OKVALUES {1,2,4,8,16,32,64,128} +#define NUMREPETITIONSPERPREAMBLEATTEMPT_MODVALUES { NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n1, NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n2, \ + NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n4, NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n8, \ + NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n16, NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n32, \ + NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n64, NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n128} + +#define NPDCCHNUMREPETITIONSRA_OKVALUES {1,2,4,8,16,32,64,128,256,512,1024,2048} +#define NPDCCHNUMREPETITIONSRA_MODVALUES { NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r1, NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r2, \ + NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r4, NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r8, \ + NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r16, NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r32, \ + NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r64, NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r128, \ + NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r256, NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r512, \ + NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r1024,NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r2048} + +#define NPDCCHSTARTSFCSSRA_OKVALUES {1,2,4,8,16,32,48,64} +#define NPDCCHSTARTSFCSSRA_MODVALUES { NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v1dot5, NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v2, \ + NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v4, NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v8, \ + NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v16, NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v32, \ + NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v48, NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v64} + +#define NPDCCHOFFSETRA_OKVALUES {"zero","oneEighth","oneFourth","threeEighth"} +#define NPDCCHOFFSETRA_MODVALUES { NPRACH_Parameters_NB_r13__npdcch_Offset_RA_r13_zero, NPRACH_Parameters_NB_r13__npdcch_Offset_RA_r13_oneEighth, \ + NPRACH_Parameters_NB_r13__npdcch_Offset_RA_r13_oneFourth, NPRACH_Parameters_NB_r13__npdcch_Offset_RA_r13_threeEighth} + + + +#define NBIOT_RRCLIST_NPRACHPARAMSCHECK_DESC { \ + { .s1a= { config_check_modify_integer, NPRACH_PERIODICITY_OKVALUES, NPRACH_PERIODICITY_MODVALUES, 8 }}, \ + { .s1a= { config_check_modify_integer, NPRACH_STARTTIME_OKVALUES, NPRACH_STARTTIME_MODVALUES, 8 }}, \ + { .s1a= { config_check_modify_integer, NPRACH_SUBCARRIEROFFSET_OKVALUES, NPRACH_SUBCARRIEROFFSET_MODVALUES, 7 }}, \ + { .s1a= { config_check_modify_integer, NPRACH_NUMSUBCARRIERS_OKVALUES, NPRACH_NUMSUBCARRIERS_MODVALUES, 4 }}, \ + { .s1a= { config_check_modify_integer, NUMREPETITIONSPERPREAMBLEATTEMPT_OKVALUES, NUMREPETITIONSPERPREAMBLEATTEMPT_MODVALUES,8 }}, \ + { .s1a= { config_check_modify_integer, NPDCCHNUMREPETITIONSRA_OKVALUES, NPDCCHNUMREPETITIONSRA_MODVALUES, 12}}, \ + { .s1a= { config_check_modify_integer, NPDCCHSTARTSFCSSRA_OKVALUES, NPDCCHSTARTSFCSSRA_MODVALUES, 8 }}, \ + { .s3a= { config_checkstr_assign_integer, NPDCCHOFFSETRA_OKVALUES, NPDCCHOFFSETRA_MODVALUES, 4 }}, \ +} + + + +/*------------------------------------------------------------------------------------------------------------------------------*/ +/* NB-IoT NPrach parameters, there will be three ocuurences of these parameters in each RRC instance */ + /* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*------------------------------------------------------------------------------------------------------------------------------*/ +#define NBIOTRRC_NPRACH_PARAMS_DESC { \ +{"nprach_Periodicity", NULL, 0, uptr:NULL, defintval:320, TYPE_UINT, 0}, \ +{"nprach_StartTime", NULL, 0, uptr:NULL, defintval:8, TYPE_UINT, 0}, \ +{"nprach_SubcarrierOffset", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ +{"nprach_NumSubcarriers", NULL, 0, uptr:NULL, defintval:12, TYPE_UINT, 0}, \ +{"numRepetitionsPerPreambleAttempt", NULL, 0, uptr:NULL, defintval:2, TYPE_UINT, 0}, \ +{"npdcch_NumRepetitions_RA", NULL, 0, uptr:NULL, defintval:16, TYPE_UINT, 0}, \ +{"npdcch_StartSF_CSS_RA", NULL, 0, uptr:NULL, defintval:2, TYPE_UINT, 0}, \ +{"npdcch_Offset_RA", NULL, 0, strptr:NULL, defstrval:"zero", TYPE_STRING, 0}, \ +} + +#define NBIOT_NPRACH_PERIODICITY_IDX 0 +#define NBIOT_NPRACH_STARTTIME_IDX 1 +#define NBIOT_NPRACH_SUBCARRIEROFFSET_IDX 2 +#define NBIOT_NPRACH_NUMSUBCARRIERS_IDX 3 +#define NBIOT_NUMREPETITIONSPERPREAMBLEATTEMPT_NB_IDX 4 +#define NBIOT_NPDCCH_NUMREPETITIONS_RA_IDX 5 +#define NBIOT_NPDCCH_STARTSF_CSS_RA_IDX 6 +#define NBIOT_NPDCCH_OFFSET_RA_IDX 7 + +/*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* NB IoT MACRLC configuration list section name */ +#define NBIOT_MACRLCLIST_CONFIG_STRING "NB-IoT_MACRLCs" + + +/*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* NB IoT L1 configuration list section name */ +#define NBIOT_L1LIST_CONFIG_STRING "NB-IoT_L1s" diff --git a/openair2/UTIL/LOG/log.c b/openair2/UTIL/LOG/log.c index 948425e8da..ff6a5cd573 100644 --- a/openair2/UTIL/LOG/log.c +++ b/openair2/UTIL/LOG/log.c @@ -34,6 +34,7 @@ #define COMPONENT_LOG #define COMPONENT_LOG_IF #include +#define LOG_MAIN #include "log.h" #include "vcd_signal_dumper.h" #include "assertions.h" @@ -46,7 +47,7 @@ # include #include "common/config/config_userapi.h" // main log variables -log_t *g_log; + mapping log_level_names[] = { {"emerg", LOG_EMERG}, @@ -1562,7 +1563,7 @@ int set_log(int component, int level, int interval) component, MIN_LOG_COMPONENTS, MAX_LOG_COMPONENTS); DevCheck((level <= LOG_TRACE) && (level >= LOG_EMERG), level, LOG_TRACE, LOG_EMERG); - DevCheck((interval > 0) && (interval <= 0xFF), interval, 0, 0xFF); + DevCheck((interval >= 0) && (interval <= 0xFF), interval, 0, 0xFF); g_log->log_component[component].level = level; @@ -1596,7 +1597,7 @@ int set_comp_log(int component, int level, int verbosity, int interval) component, MIN_LOG_COMPONENTS, MAX_LOG_COMPONENTS); DevCheck((level <= LOG_TRACE) && (level >= LOG_EMERG), level, LOG_TRACE, LOG_EMERG); - DevCheck((interval > 0) && (interval <= 0xFF), interval, 0, 0xFF); + DevCheck((interval >= 0) && (interval <= 0xFF), interval, 0, 0xFF); #if 0 if ((verbosity == LOG_NONE) || (verbosity == LOG_LOW) || diff --git a/openair2/UTIL/LOG/log.h b/openair2/UTIL/LOG/log.h index c21407f6eb..00bc334de5 100644 --- a/openair2/UTIL/LOG/log.h +++ b/openair2/UTIL/LOG/log.h @@ -253,7 +253,17 @@ typedef enum log_instance_type_e { void log_set_instance_type (log_instance_type_t instance); #endif - +#ifdef LOG_MAIN +log_t *g_log; +#else +#ifdef __cplusplus + extern "C" { +#endif +extern log_t *g_log; +#ifdef __cplusplus +} +#endif +#endif /*--- INCLUDES ---------------------------------------------------------------*/ # include "log_if.h" /*----------------------------------------------------------------------------*/ @@ -279,9 +289,9 @@ void *log_thread_function(void * list); * @brief Macro used to call tr_log_full_ex with file, function and line information * @{*/ #ifdef LOG_NO_THREAD -#define logIt(component, level, format, args...) logRecord_mt(__FILE__, __FUNCTION__, __LINE__, component, level, format, ##args) +#define logIt(component, level, format, args...) (g_log->log_component[component].interval?logRecord_mt(__FILE__, __FUNCTION__, __LINE__, component, level, format, ##args):(void)0) #else //default -#define logIt(component, level, format, args...) logRecord(__FILE__, __FUNCTION__, __LINE__, component, level, format, ##args) +#define logIt(component, level, format, args...) (g_log->log_component[component].interval?logRecord(__FILE__, __FUNCTION__, __LINE__, component, level, format, ##args):(void)0) #endif /* @}*/ diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c index eb9f80872e..d74b1c6d4f 100644 --- a/targets/ARCH/COMMON/common_lib.c +++ b/targets/ARCH/COMMON/common_lib.c @@ -36,6 +36,7 @@ #include #include "common_lib.h" +#include "common/utils/load_module_shlib.h" int set_device(openair0_device *device) { @@ -85,52 +86,26 @@ int set_transport(openair0_device *device) { } } - +typedef int(*devfunc_t)(openair0_device *, openair0_config_t *, eth_params_t *); /* look for the interface library and load it */ int load_lib(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t * cfg, uint8_t flag) { - void *lib_handle; - oai_device_initfunc_t dp ; - oai_transport_initfunc_t tp ; + loader_shlibfunc_t shlib_fdesc[1]; int ret=0; - + char *libname; if (flag == RAU_LOCAL_RADIO_HEAD) { - lib_handle = dlopen(OAI_RF_LIBNAME, RTLD_LAZY); - if (!lib_handle) { - fprintf(stderr,"Unable to locate %s: HW device set to NONE_DEV.\n", OAI_RF_LIBNAME); - fprintf(stderr,"%s\n",dlerror()); - return -1; - } - - dp = dlsym(lib_handle,"device_init"); - - if (dp != NULL ) { - ret = dp(device,openair0_cfg); - if (ret<0) { - fprintf(stderr, "%s %d:oai device intialization failed %s\n", __FILE__, __LINE__, dlerror()); - } - } else { - fprintf(stderr, "%s %d:oai device intializing function not found %s\n", __FILE__, __LINE__, dlerror()); - return -1; - } + libname=OAI_RF_LIBNAME; + shlib_fdesc[0].fname="device_init"; } else { - lib_handle = dlopen(OAI_TP_LIBNAME, RTLD_LAZY); - if (!lib_handle) { - printf( "Unable to locate %s: transport protocol set to NONE_TP.\n", OAI_TP_LIBNAME); - printf( "%s\n",dlerror()); - return -1; - } - - tp = dlsym(lib_handle,"transport_init"); - - if (tp != NULL ) { - tp(device,openair0_cfg,cfg); - } else { - fprintf(stderr, "%s %d:oai device intializing function not found %s\n", __FILE__, __LINE__, dlerror()); - return -1; - } + libname=OAI_TP_LIBNAME; + shlib_fdesc[0].fname="transport_init"; } - + ret=load_module_shlib(libname,shlib_fdesc,1); + if (ret < 0) { + fprintf(stderr,"Library %s couldn't be loaded\n",libname); + } else { + ret=((devfunc_t)shlib_fdesc[0].fptr)(device,openair0_cfg,cfg); + } return ret; } diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h index 2dc1650bfd..433e29e97d 100644 --- a/targets/ARCH/COMMON/common_lib.h +++ b/targets/ARCH/COMMON/common_lib.h @@ -36,9 +36,9 @@ #include /* name of shared library implementing the radio front end */ -#define OAI_RF_LIBNAME "liboai_device.so" +#define OAI_RF_LIBNAME "oai_device" /* name of shared library implementing the transport */ -#define OAI_TP_LIBNAME "liboai_transpro.so" +#define OAI_TP_LIBNAME "oai_transpro" /* flags for BBU to determine whether the attached radio head is local or remote */ #define RAU_LOCAL_RADIO_HEAD 0 diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index f6789086b4..bbf35cffa0 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -135,11 +135,11 @@ volatile int oai_exit = 0; static clock_source_t clock_source = internal; static int wait_for_sync = 0; -static char UE_flag=0; +static int8_t UE_flag=0; unsigned int mmapped_dma=0; int single_thread_flag=1; -static char threequarter_fs=0; +static int8_t threequarter_fs=0; uint32_t downlink_frequency[MAX_NUM_CCs][4]; int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; @@ -570,7 +570,7 @@ void *l2l1_task(void *arg) { static void get_options(void) { int CC_id; - int tddflag; + int tddflag, nonbiotflag; char *loopfile=NULL; int dumpframe; uint32_t online_log_messages; @@ -627,10 +627,10 @@ static void get_options(void) { if ( (cmdline_uemodeparams[CMDLINE_CALIBUERX_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue; if ( (cmdline_uemodeparams[CMDLINE_CALIBUERXMED_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue_med; if ( (cmdline_uemodeparams[CMDLINE_CALIBUERXBYP_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue_byp; - if ( (cmdline_uemodeparams[CMDLINE_DEBUGUEPRACH_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = debug_prach; - if ( (cmdline_uemodeparams[CMDLINE_NOL2CONNECT_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = no_L2_connect; - if ( (cmdline_uemodeparams[CMDLINE_CALIBPRACHTX_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = calib_prach_tx; - if ( (cmdline_uemodeparams[CMDLINE_DUMPMEMORY_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_dump_frame; + if ( *(cmdline_uemodeparams[CMDLINE_DEBUGUEPRACH_IDX].uptr) > 0) mode = debug_prach; + if ( *(cmdline_uemodeparams[CMDLINE_NOL2CONNECT_IDX].uptr) > 0) mode = no_L2_connect; + if ( *(cmdline_uemodeparams[CMDLINE_CALIBPRACHTX_IDX].uptr) > 0) mode = calib_prach_tx; + if (dumpframe > 0) mode = rx_dump_frame; if ( downlink_frequency[0][0] > 0) { printf("Downlink frequency set to %u\n", downlink_frequency[0][0]); @@ -645,35 +645,36 @@ static void get_options(void) { frame_parms[CC_id]->frame_type = TDD; } - if (n_rb_dl !=0) { - printf("NB_RB set to %d\n",n_rb_dl); - if ( n_rb_dl < 6 ) { - n_rb_dl = 6; - printf ( "%i: Invalid number of ressource blocks, adjusted to 6\n",n_rb_dl); - } - if ( n_rb_dl > 100 ) { - n_rb_dl = 100; - printf ( "%i: Invalid number of ressource blocks, adjusted to 100\n",n_rb_dl); - } - if ( n_rb_dl > 50 && n_rb_dl < 100 ) { - n_rb_dl = 50; - printf ( "%i: Invalid number of ressource blocks, adjusted to 50\n",n_rb_dl); - } - if ( n_rb_dl > 25 && n_rb_dl < 50 ) { - n_rb_dl = 25; - printf ( "%i: Invalid number of ressource blocks, adjusted to 25\n",n_rb_dl); - } - UE_scan = 0; - for (CC_id=0; CC_idN_RB_DL=n_rb_dl; - frame_parms[CC_id]->N_RB_UL=n_rb_dl; - } + if (frame_parms[0]->N_RB_DL !=0) { + if ( frame_parms[0]->N_RB_DL < 6 ) { + frame_parms[0]->N_RB_DL = 6; + printf ( "%i: Invalid number of ressource blocks, adjusted to 6\n",frame_parms[0]->N_RB_DL); + } + if ( frame_parms[0]->N_RB_DL > 100 ) { + frame_parms[0]->N_RB_DL = 100; + printf ( "%i: Invalid number of ressource blocks, adjusted to 100\n",frame_parms[0]->N_RB_DL); + } + if ( frame_parms[0]->N_RB_DL > 50 && frame_parms[0]->N_RB_DL < 100 ) { + frame_parms[0]->N_RB_DL = 50; + printf ( "%i: Invalid number of ressource blocks, adjusted to 50\n",frame_parms[0]->N_RB_DL); + } + if ( frame_parms[0]->N_RB_DL > 25 && frame_parms[0]->N_RB_DL < 50 ) { + frame_parms[0]->N_RB_DL = 25; + printf ( "%i: Invalid number of ressource blocks, adjusted to 25\n",frame_parms[0]->N_RB_DL); + } + UE_scan = 0; + frame_parms[0]->N_RB_UL=frame_parms[0]->N_RB_DL; + for (CC_id=1; CC_idN_RB_DL=frame_parms[0]->N_RB_DL; + frame_parms[CC_id]->N_RB_UL=frame_parms[0]->N_RB_UL; + } } - for (CC_id=0;CC_id 0 */ diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index 5cc4d5fea2..1d594caadc 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -85,7 +85,7 @@ #define CONFIG_HLP_TPORT "tracer port\n" #define CONFIG_HLP_NOTWAIT "don't wait for tracer, start immediately\n" #define CONFIG_HLP_TNOFORK "to ease debugging with gdb\n" - +#define CONFIG_HLP_DISABLNBIOT "disable nb-iot, even if defined in config\n" /***************************************************************************************************************************************/ /* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument @@ -129,7 +129,7 @@ {"ue-nb-ant-tx", CONFIG_HLP_UENANTT, 0, u8ptr:&nb_antenna_tx, defuintval:1, TYPE_UINT8, 0}, \ {"ue-scan-carrier", CONFIG_HLP_UESCAN, PARAMFLAG_BOOL, iptr:&UE_scan_carrier, defintval:0, TYPE_INT, 0}, \ {"ue-max-power", NULL, 0, iptr:&(tx_max_power[0]), defintval:90, TYPE_INT, 0}, \ -{"r" , CONFIG_HLP_PRB, 0, u8ptr:&n_rb_dl, defintval:0, TYPE_UINT8, 0}, \ +{"r" , CONFIG_HLP_PRB, 0, u8ptr:&(frame_parms[0]->N_RB_DL), defintval:0, TYPE_UINT8, 0}, \ } @@ -168,7 +168,8 @@ extern int16_t dlsch_demod_shift; {"V" , CONFIG_HLP_VCD, PARAMFLAG_BOOL, iptr:&ouput_vcd, defintval:0, TYPE_INT, 0}, \ {"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, iptr:&opp_enabled, defintval:0, TYPE_INT, 0}, \ {"S" , CONFIG_HLP_MSLOTS, PARAMFLAG_BOOL, u8ptr:&exit_missed_slots, defintval:1, TYPE_UINT8, 0}, \ -{"T" , CONFIG_HLP_TDD, PARAMFLAG_BOOL, iptr:&tddflag, defintval:0, TYPE_INT, 0} \ +{"T" , CONFIG_HLP_TDD, PARAMFLAG_BOOL, iptr:&tddflag, defintval:0, TYPE_INT, 0}, \ +{"nbiot-disable", CONFIG_HLP_DISABLNBIOT,PARAMFLAG_BOOL, iptr:&nonbiotflag, defintval:0, TYPE_INT, 0} \ } #define CONFIG_HLP_FLOG "Enable online log \n" From b04f3b54a41b08c20e24795338de4bf5865a6649 Mon Sep 17 00:00:00 2001 From: oai Date: Thu, 1 Mar 2018 18:56:04 +0100 Subject: [PATCH 280/284] introduce distinct executables for ue and eNodeB (lte-uesoftmodem, lte-softmodem) --- cmake_targets/CMakeLists.txt | 90 +- cmake_targets/build_oai | 20 +- common/utils/load_module_shlib.c | 52 +- common/utils/load_module_shlib.h | 28 +- common/utils/telnetsrv/telnetsrv.c | 10 +- common/utils/telnetsrv/telnetsrv.h | 2 + openair1/PHY/CODING/3gpplte_sse.c | 2 +- openair1/PHY/CODING/3gpplte_turbo_decoder.c | 10 +- .../CODING/3gpplte_turbo_decoder_sse_16bit.c | 2 + .../CODING/3gpplte_turbo_decoder_sse_8bit.c | 2 + openair1/PHY/CODING/coding_load.c | 73 +- openair1/PHY/CODING/defs.h | 106 +- openair1/PHY/INIT/init_top.c | 2 +- .../PHY/LTE_ESTIMATION/lte_ue_measurements.c | 6 +- openair1/PHY/extern.h | 2 +- openair1/PHY/vars.h | 2 +- openair2/RRC/LITE/L2_interface_ue.c | 1 + openair2/RRC/LITE/rrc_UE.c | 2 +- targets/RT/USER/lte-softmodem.c | 409 +----- targets/RT/USER/lte-softmodem.h | 7 +- targets/RT/USER/lte-uesoftmodem.c | 1139 +++++++++++++++++ 21 files changed, 1419 insertions(+), 548 deletions(-) create mode 100644 targets/RT/USER/lte-uesoftmodem.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 4f264044df..a0ee33dc78 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1216,9 +1216,7 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/CODING/ccoding_byte_lte.c ${OPENAIR1_DIR}/PHY/CODING/3gpplte_sse.c ${OPENAIR1_DIR}/PHY/CODING/crc_byte.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c - ${OPENAIR1_DIR}/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c + ${PHY_TURBOIF} ${OPENAIR1_DIR}/PHY/CODING/lte_rate_matching.c ${OPENAIR1_DIR}/PHY/CODING/viterbi.c ${OPENAIR1_DIR}/PHY/CODING/viterbi_lte.c @@ -1946,14 +1944,12 @@ add_executable(lte-softmodem ${s1ap_h} ${OPENAIR_BIN_DIR}/messages_xml.h ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c - ${OPENAIR_TARGETS}/RT/USER/lte-ue.c ${OPENAIR_TARGETS}/RT/USER/lte-enb.c ${OPENAIR_TARGETS}/RT/USER/lte-ru.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c ${OPENAIR_TARGETS}/COMMON/create_tasks.c - ${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c ${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c @@ -1969,9 +1965,9 @@ add_executable(lte-softmodem target_link_libraries (lte-softmodem -Wl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 - NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB - NFAPI_USER_LIB + RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 + ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 + NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB -Wl,--end-group z dl) target_link_libraries (lte-softmodem ${LIBXML2_LIBRARIES}) @@ -1986,14 +1982,12 @@ add_executable(lte-softmodem-nos1 ${s1ap_h} ${OPENAIR_BIN_DIR}/messages_xml.h ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c - ${OPENAIR_TARGETS}/RT/USER/lte-ue.c ${OPENAIR_TARGETS}/RT/USER/lte-enb.c ${OPENAIR_TARGETS}/RT/USER/lte-ru.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c ${OPENAIR_TARGETS}/COMMON/create_tasks.c - ${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c ${OPENAIR2_DIR}/RRC/NAS/nas_config.c ${OPENAIR2_DIR}/RRC/NAS/rb_config.c @@ -2007,9 +2001,9 @@ add_executable(lte-softmodem-nos1 ) target_link_libraries (lte-softmodem-nos1 -Wl,--start-group - RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 - NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB - NFAPI_USER_LIB + RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} + ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 + NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB -Wl,--end-group z dl ) target_link_libraries (lte-softmodem-nos1 ${LIBXML2_LIBRARIES}) @@ -2017,6 +2011,76 @@ target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt target_link_libraries (lte-softmodem-nos1 ${LIB_LMS_LIBRARIES}) target_link_libraries (lte-softmodem-nos1 ${T_LIB}) +# lte-uesoftmodem is UE implementation +####################################### + +add_executable(lte-uesoftmodem + ${rrc_h} + ${s1ap_h} + ${OPENAIR_BIN_DIR}/messages_xml.h + ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c + ${OPENAIR_TARGETS}/RT/USER/lte-ue.c + ${OPENAIR_TARGETS}/RT/USER/lte-uesoftmodem.c + ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c + ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c + ${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c + ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c + ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c + ${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c + ${OPENAIR_DIR}/common/utils/utils.c + ${OPENAIR_DIR}/common/utils/system.c + ${XFORMS_SOURCE} + ${XFORMS_SOURCE_SOFTMODEM} + ${T_SOURCE} + ${CONFIG_SOURCES} + ${SHLIB_LOADER_SOURCES} + ) + +target_link_libraries (lte-uesoftmodem + -Wl,--start-group + RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_UE_LIB PHY_UE LFDS L2_UE + ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7 + -Wl,--end-group z dl) + +target_link_libraries (lte-uesoftmodem ${LIBXML2_LIBRARIES}) +target_link_libraries (lte-uesoftmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES}) +target_link_libraries (lte-uesoftmodem ${LIB_LMS_LIBRARIES}) +target_link_libraries (lte-uesoftmodem ${T_LIB}) + +# lte-softmodem-nos1 is both eNB and UE implementation +################################################### +add_executable(lte-uesoftmodem-nos1 + ${rrc_h} + ${s1ap_h} + ${OPENAIR_BIN_DIR}/messages_xml.h + ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c + ${OPENAIR_TARGETS}/RT/USER/lte-ue.c + ${OPENAIR_TARGETS}/RT/USER/lte-uesoftmodem.c + ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c + ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c + ${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c + ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c + ${OPENAIR2_DIR}/RRC/NAS/nas_config.c + ${OPENAIR2_DIR}/RRC/NAS/rb_config.c + ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c + ${OPENAIR_DIR}/common/utils/system.c + ${XFORMS_SOURCE} + ${XFORMS_SOURCE_SOFTMODEM} + ${T_SOURCE} + ${CONFIG_SOURCES} + ${SHLIB_LOADER_SOURCES} + ) +target_link_libraries (lte-uesoftmodem-nos1 + -Wl,--start-group + RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_UE_LIB PHY_UE LFDS L2_UE ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} + ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7 + -Wl,--end-group z dl ) + +target_link_libraries (lte-uesoftmodem-nos1 ${LIBXML2_LIBRARIES}) +target_link_libraries (lte-uesoftmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES}) +target_link_libraries (lte-uesoftmodem-nos1 ${LIB_LMS_LIBRARIES}) +target_link_libraries (lte-uesoftmodem-nos1 ${T_LIB}) + # USIM process ################# #add_executable(usim diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index b19e3208a5..f5be69d3fa 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -359,7 +359,11 @@ function main() { CMAKE_CMD="$CMAKE_CMD .." echo_info "CMAKE_CMD=$CMAKE_CMD" - + if [ "$eNB" = "1" ] && [ "$UE" = "1" ]; then + echo_error "Cannot build UE and eNB on one build_oai execution" + echo_error "use 2 build_oai invocations" + exit + fi ######################################################### # check validity of HW and TP parameters for eNB ######################################################### @@ -488,10 +492,20 @@ function main() { DIR=$OPENAIR_DIR/cmake_targets if [ "$NOS1" = "1" ] ; then lte_build_dir=lte_noS1_build_oai - lte_exec=lte-softmodem-nos1 + if [ "$eNB" = "1" ] ; then + lte_exec=lte-softmodem-nos1 + fi + if [ "$UE" = "1" ] ; then + lte_exec=lte-uesoftmodem-nos1 + fi else lte_build_dir=lte_build_oai - lte_exec=lte-softmodem + if [ "$eNB" = "1" ] ; then + lte_exec=lte-softmodem + fi + if [ "$UE" = "1" ] ; then + lte_exec=lte-uesoftmodem + fi fi # configuration module libraries, one currently available, using libconfig diff --git a/common/utils/load_module_shlib.c b/common/utils/load_module_shlib.c index 32d3cfee9b..c07b54f54a 100644 --- a/common/utils/load_module_shlib.c +++ b/common/utils/load_module_shlib.c @@ -48,11 +48,11 @@ void loader_init(void) { loader_data.mainexec_buildversion = PACKAGE_VERSION; int ret = config_get( LoaderParams,sizeof(LoaderParams)/sizeof(paramdef_t),LOADER_CONFIG_PREFIX); if (ret <0) { - fprintf(stderr,"[LOADER] %s %d configuration couldn't be performed",__FILE__, __LINE__); + printf("[LOADER] configuration couldn't be performed via config module, parameters set to default values\n"); if (loader_data.shlibpath == NULL) { loader_data.shlibpath=DEFAULT_PATH; } - return; + loader_data.maxshlibs = DEFAULT_MAXSHLIBS; } loader_data.shlibs = malloc(loader_data.maxshlibs * sizeof(loader_shlibdesc_t)); if(loader_data.shlibs == NULL) { @@ -96,7 +96,10 @@ int ret; if (shlibpath == NULL) { shlibpath = loader_data.shlibpath ; } - +/* no specific shared lib version */ + if (shlibversion == NULL) { + shlibversion = "" ; + } /* alloc memory for full module shared lib file name */ tmpstr = malloc(strlen(shlibpath)+strlen(modname)+strlen(shlibversion)+16); if (tmpstr == NULL) { @@ -120,6 +123,7 @@ int load_module_shlib(char *modname,loader_shlibfunc_t *farray, int numf) void *lib_handle; initfunc_t fpi; checkverfunc_t fpc; + getfarrayfunc_t fpg; char *shlib_path; char *afname=NULL; int ret=0; @@ -155,25 +159,29 @@ int load_module_shlib(char *modname,loader_shlibfunc_t *farray, int numf) } if (farray != NULL) { + loader_data.shlibs[loader_data.numshlibs].funcarray=malloc(numf*sizeof(loader_shlibfunc_t)); + loader_data.shlibs[loader_data.numshlibs].numfunc=0; for (int i=0; i #include #include - +#include "common/utils/load_module_shlib.h" #include "common/config/config_userapi.h" #include @@ -787,4 +787,10 @@ int telnetsrv_checkbuildver(char * mainexec_buildversion, char ** shlib_buildve return 0; } - +int telnetsrv_getfarray(loader_shlibfunc_t **farray) + { + *farray=malloc(sizeof(loader_shlibfunc_t)); + (*farray)[0].fname=TELNET_ADDCMD_FNAME; + (*farray)[0].fptr=(int (*)(void) )add_telnetcmd; + return 1; + } diff --git a/common/utils/telnetsrv/telnetsrv.h b/common/utils/telnetsrv/telnetsrv.h index 3cf561eda2..2d3ef531ae 100644 --- a/common/utils/telnetsrv/telnetsrv.h +++ b/common/utils/telnetsrv/telnetsrv.h @@ -131,6 +131,8 @@ VT escape sequence definition, for smarter display.... #define STDFMT "\x1b[0m" /*---------------------------------------------------------------------------------------------*/ +#define TELNET_ADDCMD_FNAME "add_telnetcmd" +typedef int(*add_telnetcmd_func_t)(char *, telnetshell_vardef_t *, telnetshell_cmddef_t *); #ifdef TELNETSERVERCODE int add_telnetcmd(char *modulename, telnetshell_vardef_t *var, telnetshell_cmddef_t *cmd); void set_sched(pthread_t tid, int pid,int priority); diff --git a/openair1/PHY/CODING/3gpplte_sse.c b/openair1/PHY/CODING/3gpplte_sse.c index 313d63f7a7..8150f02da8 100644 --- a/openair1/PHY/CODING/3gpplte_sse.c +++ b/openair1/PHY/CODING/3gpplte_sse.c @@ -696,7 +696,7 @@ int main(int argc,char **argv) printf("Input %d : %d\n",i,input[i]); } - threegpplte_turbo_encoder(&input[0], + threegpplte_turbo_encoder_sse(&input[0], INPUT_LENGTH, &output[0], 0, diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder.c b/openair1/PHY/CODING/3gpplte_turbo_decoder.c index 6c50e03806..c0e4ca12db 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder.c @@ -874,14 +874,22 @@ void compute_ext_s(llr_t* alpha,llr_t* beta,llr_t* m_11,llr_t* m_10,llr_t* ext, unsigned char phy_threegpplte_turbo_decoder_scalar(llr_t *y, + llr_t *y2, unsigned char *decoded_bytes, + unsigned char *decoded_bytes2, unsigned short n, unsigned short f1, unsigned short f2, unsigned char max_iterations, unsigned char crc_type, unsigned char F, - unsigned char inst) + time_stats_t *init_stats, + time_stats_t *alpha_stats, + time_stats_t *beta_stats, + time_stats_t *gamma_stats, + time_stats_t *ext_stats, + time_stats_t *intl1_stats, + time_stats_t *intl2_stats) { /* y is a pointer to the input diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c index 63896924dd..ae3ce531d0 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c @@ -1172,7 +1172,9 @@ void init_td16(void) } unsigned char phy_threegpplte_turbo_decoder16(short *y, + short *y2, unsigned char *decoded_bytes, + unsigned char *decoded_bytes2, unsigned short n, unsigned short f1, unsigned short f2, diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c index f7b64b767d..5b7174e989 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c @@ -898,7 +898,9 @@ void init_td8(void) } unsigned char phy_threegpplte_turbo_decoder8(short *y, + short y2, unsigned char *decoded_bytes, + unsigned char *decoded_bytes2, unsigned short n, unsigned short f1, unsigned short f2, diff --git a/openair1/PHY/CODING/coding_load.c b/openair1/PHY/CODING/coding_load.c index c8aed8cf30..6e4670dd8e 100644 --- a/openair1/PHY/CODING/coding_load.c +++ b/openair1/PHY/CODING/coding_load.c @@ -29,13 +29,32 @@ * \note * \warning */ +#define _GNU_SOURCE #include + + #include "PHY/defs.h" +#include "PHY/extern.h" #include "common/utils/load_module_shlib.h" +#include "common/utils/telnetsrv/telnetsrv.h" - +static int coding_setmod_cmd(char *buff, int debug, telnet_printfunc_t prnt); +static telnetshell_cmddef_t coding_cmdarray[] = { + {"mode","[sse,avx2,stdc,none]",coding_setmod_cmd}, + {"","",NULL}, +}; +telnetshell_vardef_t coding_vardef[] = { +{"maxiter",TELNET_VARTYPE_INT32,&max_turbo_iterations}, +{"",0,NULL} +}; +/* PHY/defs.h contains MODE_DECODE_XXX macros, following table must match */ +static char *modedesc[] = {"none","sse","C","avx2"}; +static int curmode; +/* function description array, to be used when loading the encoding/decoding shared lib */ loader_shlibfunc_t shlib_fdesc[DECODE_NUM_FPTR]; +/* encoding decoding functions pointers, filled here and used when encoding/decoding */ +/*defined as extern in PHY?CODING/extern.h */ decoder_if_t decoder16; decoder_if_t decoder8; encoder_if_t encoder; @@ -59,7 +78,6 @@ uint8_t nodecod(short *y, time_stats_t *intl1_stats, time_stats_t *intl2_stats) { - printf("."); return max_iterations+1; }; @@ -70,11 +88,6 @@ void decoding_setmode (int mode) { decoder16=nodecod; encoder=(encoder_if_t)shlib_fdesc[ENCODE_C_FPTRIDX].fptr; break; - case MODE_DECODE_SSE: - decoder8=(decoder_if_t)shlib_fdesc[DECODE_TD8_SSE_FPTRIDX].fptr; - decoder16=(decoder_if_t)shlib_fdesc[DECODE_TD16_SSE_FPTRIDX].fptr; - encoder=(encoder_if_t)shlib_fdesc[ENCODE_SSE_FPTRIDX].fptr; - break; case MODE_DECODE_C: decoder16=(decoder_if_t)shlib_fdesc[DECODE_TD_C_FPTRIDX].fptr; decoder8=(decoder_if_t)shlib_fdesc[DECODE_TD_C_FPTRIDX].fptr; @@ -85,15 +98,22 @@ void decoding_setmode (int mode) { decoder8=(decoder_if_t)shlib_fdesc[DECODE_TD8_SSE_FPTRIDX].fptr; encoder=(encoder_if_t)shlib_fdesc[ENCODE_SSE_FPTRIDX].fptr; break; + default: + mode=MODE_DECODE_SSE; + case MODE_DECODE_SSE: + decoder8=(decoder_if_t)shlib_fdesc[DECODE_TD8_SSE_FPTRIDX].fptr; + decoder16=(decoder_if_t)shlib_fdesc[DECODE_TD16_SSE_FPTRIDX].fptr; + encoder=(encoder_if_t)shlib_fdesc[ENCODE_SSE_FPTRIDX].fptr; + break; } - + curmode=mode; } int load_codinglib(void) { int ret; - + memset(shlib_fdesc,0,sizeof(shlib_fdesc)); shlib_fdesc[DECODE_INITTD8_SSE_FPTRIDX].fname = "init_td8"; shlib_fdesc[DECODE_INITTD16_SSE_FPTRIDX].fname= "init_td16"; shlib_fdesc[DECODE_INITTD_AVX2_FPTRIDX].fname="init_td16avx2"; @@ -117,10 +137,18 @@ int load_codinglib(void) { /* execute encoder/decoder init functions */ shlib_fdesc[DECODE_INITTD8_SSE_FPTRIDX].fptr(); shlib_fdesc[DECODE_INITTD16_SSE_FPTRIDX].fptr(); - shlib_fdesc[DECODE_INITTD_AVX2_FPTRIDX].fptr(); - shlib_fdesc[ENCODE_INIT_SSE_FPTRIDX].fptr(); + if(shlib_fdesc[DECODE_INITTD_AVX2_FPTRIDX].fptr != NULL) { + shlib_fdesc[DECODE_INITTD_AVX2_FPTRIDX].fptr(); + } + if(shlib_fdesc[ENCODE_INIT_SSE_FPTRIDX].fptr != NULL) { + shlib_fdesc[ENCODE_INIT_SSE_FPTRIDX].fptr(); + } decoding_setmode(MODE_DECODE_SSE); - +/* look for telnet server, if it is loaded, add the coding commands to it */ + add_telnetcmd_func_t addcmd = (add_telnetcmd_func_t)get_shlibmodule_fptr("telnetsrv", TELNET_ADDCMD_FNAME); + if (addcmd != NULL) { + addcmd("coding",coding_vardef,coding_cmdarray); + } return 0; } @@ -132,3 +160,24 @@ void free_codinglib(void) { } + +/* functions for telnet support, when telnet server is loaded */ +int coding_setmod_cmd(char *buff, int debug, telnet_printfunc_t prnt) +{ + if (debug > 0) + prnt( "coding_setmod_cmd received %s\n",buff); + + if (strcasestr(buff,"sse") != NULL) { + decoding_setmode(MODE_DECODE_SSE); + } else if (strcasestr(buff,"avx2") != NULL) { + decoding_setmode(MODE_DECODE_AVX2); + } else if (strcasestr(buff,"stdc") != NULL) { + decoding_setmode(MODE_DECODE_C); + } else if (strcasestr(buff,"none") != NULL) { + decoding_setmode(MODE_DECODE_NONE); + } else { + prnt("%s: wrong setmod parameter...\n",buff); + } + prnt("Coding and decoding current mode: %s\n",modedesc[curmode]); + return 0; +} diff --git a/openair1/PHY/CODING/defs.h b/openair1/PHY/CODING/defs.h index ce13e045f3..40e19964df 100644 --- a/openair1/PHY/CODING/defs.h +++ b/openair1/PHY/CODING/defs.h @@ -37,7 +37,7 @@ #define CRC8 3 #define MAX_TURBO_ITERATIONS_MBSFN 8 -#define MAX_TURBO_ITERATIONS 4 +#define MAX_TURBO_ITERATIONS max_turbo_iterations #define LTE_NULL 2 @@ -294,21 +294,7 @@ void ccodedot11_init_inv(void); -/*\fn void threegpplte_turbo_encoder(uint8_t *input,uint16_t input_length_bytes,uint8_t *output,uint8_t F,uint16_t interleaver_f1,uint16_t interleaver_f2) -\brief This function implements a rate 1/3 8-state parralel concatenated turbo code (3GPP-LTE). -@param input Pointer to input buffer -@param input_length_bytes Number of bytes to encode -@param output Pointer to output buffer -@param F Number of filler bits at input -@param interleaver_f1 F1 generator -@param interleaver_f2 F2 generator -*/ -void threegpplte_turbo_encoder(uint8_t *input, - uint16_t input_length_bytes, - uint8_t *output, - uint8_t F, - uint16_t interleaver_f1, - uint16_t interleaver_f2); + /** \fn void ccodelte_encode(int32_t numbits,uint8_t add_crc, uint8_t *inPtr,uint8_t *outPtr,uint16_t rnti) @@ -440,95 +426,7 @@ int32_t rate_matching_lte(uint32_t N_coded, uint32_t off); -/*! -\brief This routine performs max-logmap detection for the 3GPP turbo code (with termination). It is optimized for SIMD processing and 16-bit -LLR arithmetic, and requires SSE2,SSSE3 and SSE4.1 (gcc >=4.3 and appropriate CPU) -@param y LLR input (16-bit precision) -@param decoded_bytes Pointer to decoded output -@param n number of coded bits (including tail bits) -@param max_iterations The maximum number of iterations to perform -@param interleaver_f1 F1 generator -@param interleaver_f2 F2 generator -@param crc_type Length of 3GPPLTE crc (CRC24a,CRC24b,CRC16,CRC8) -@param F Number of filler bits at start of packet -@returns number of iterations used (this is 1+max if incorrect crc or if crc_len=0) -*/ -uint8_t phy_threegpplte_turbo_decoder16(int16_t *y, - uint8_t *decoded_bytes, - uint16_t n, - uint16_t interleaver_f1, - uint16_t interleaver_f2, - uint8_t max_iterations, - uint8_t crc_type, - uint8_t F, - time_stats_t *init_stats, - time_stats_t *alpha_stats, - time_stats_t *beta_stats, - time_stats_t *gamma_stats, - time_stats_t *ext_stats, - time_stats_t *intl1_stats, - time_stats_t *intl2_stats); -uint8_t phy_threegpplte_turbo_decoder16avx2(int16_t *y, - int16_t *y2, - uint8_t *decoded_bytes, - uint8_t *decoded_bytes2, - uint16_t n, - uint16_t interleaver_f1, - uint16_t interleaver_f2, - uint8_t max_iterations, - uint8_t crc_type, - uint8_t F, - time_stats_t *init_stats, - time_stats_t *alpha_stats, - time_stats_t *beta_stats, - time_stats_t *gamma_stats, - time_stats_t *ext_stats, - time_stats_t *intl1_stats, - time_stats_t *intl2_stats); - -/*! -\brief This routine performs max-logmap detection for the 3GPP turbo code (with termination). It is optimized for SIMD processing and 8-bit -LLR arithmetic, and requires SSE2,SSSE3 and SSE4.1 (gcc >=4.3 and appropriate CPU) -@param y LLR input (16-bit precision) -@param decoded_bytes Pointer to decoded output -@param n number of coded bits (including tail bits) -@param max_iterations The maximum number of iterations to perform -@param interleaver_f1 F1 generator -@param interleaver_f2 F2 generator -@param crc_type Length of 3GPPLTE crc (CRC24a,CRC24b,CRC16,CRC8) -@param F Number of filler bits at start of packet -@returns number of iterations used (this is 1+max if incorrect crc or if crc_len=0) -*/ -uint8_t phy_threegpplte_turbo_decoder8(int16_t *y, - uint8_t *decoded_bytes, - uint16_t n, - uint16_t interleaver_f1, - uint16_t interleaver_f2, - uint8_t max_iterations, - uint8_t crc_type, - uint8_t F, - time_stats_t *init_stats, - time_stats_t *alpha_stats, - time_stats_t *beta_stats, - time_stats_t *gamma_stats, - time_stats_t *ext_stats, - time_stats_t *intl1_stats, - time_stats_t *intl2_stats); - -uint8_t phy_threegpplte_turbo_decoder_scalar(int16_t *y, - uint8_t *decoded_bytes, - uint16_t n, - uint16_t interleaver_f1, - uint16_t interleaver_f2, - uint8_t max_iterations, - uint8_t crc_type, - uint8_t F, - uint8_t inst); - - - -/** @} */ uint32_t crcbit (uint8_t * , int32_t, diff --git a/openair1/PHY/INIT/init_top.c b/openair1/PHY/INIT/init_top.c index 34e82771b4..6213520b8c 100644 --- a/openair1/PHY/INIT/init_top.c +++ b/openair1/PHY/INIT/init_top.c @@ -22,7 +22,7 @@ /*!\brief Initilization and reconfiguration routines for LTE PHY */ #include "defs.h" #include "PHY/extern.h" - +#include "PHY/CODING/extern.h" void init_lte_top(LTE_DL_FRAME_PARMS *frame_parms) { diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c b/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c index c4df34638b..ce6cd86959 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c @@ -207,10 +207,8 @@ void ue_rrc_measurements(PHY_VARS_UE *ue, ((ue->frame_parms.frame_type == TDD) && ((subframe == 1) || (subframe == 6))) ) { // FDD PSS/SSS, compute noise in DTX REs - - if (ue->frame_parms.Ncp==NORMAL) { + if (ue->frame_parms.Ncp == NORMAL) { for (aarx=0; aarxframe_parms.nb_antennas_rx; aarx++) { - if(ue->frame_parms.frame_type == FDD) { rxF_sss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF[aarx][(5*ue->frame_parms.ofdm_symbol_size)]; @@ -266,7 +264,7 @@ void ue_rrc_measurements(PHY_VARS_UE *ue, ue->measurements.n0_power_tot_dB = (unsigned short) dB_fixed(ue->measurements.n0_power_tot/(12*aarx)); ue->measurements.n0_power_tot_dBm = ue->measurements.n0_power_tot_dB - ue->rx_total_gain_dB - dB_fixed(ue->frame_parms.ofdm_symbol_size); } else { - LOG_E(PHY, "Not yet implemented: noise power calculation when prefix length = EXTENDED\n"); + LOG_E(PHY, "Not yet implemented: noise power calculation when prefix length == EXTENDED\n"); } } else if ((ue->frame_parms.frame_type == TDD) && diff --git a/openair1/PHY/extern.h b/openair1/PHY/extern.h index 3ff2d64da0..5868c1c022 100644 --- a/openair1/PHY/extern.h +++ b/openair1/PHY/extern.h @@ -126,6 +126,6 @@ extern unsigned short Nb_81_110[8][4]; extern uint16_t hundred_times_log10_NPRB[100]; extern uint8_t alpha_lut[8]; - +extern uint8_t max_turbo_iterations; #endif /*__PHY_EXTERN_H__ */ diff --git a/openair1/PHY/vars.h b/openair1/PHY/vars.h index 45af058308..e8f4e27de1 100644 --- a/openair1/PHY/vars.h +++ b/openair1/PHY/vars.h @@ -149,5 +149,5 @@ int16_t unscrambling_lut[65536*16] __attribute__((aligned(32))); /// lookup table for scrambling in TX uint8_t scrambling_lut[65536*16] __attribute__((aligned(32))); - +uint8_t max_turbo_iterations=4; #endif /*__PHY_VARS_H__ */ diff --git a/openair2/RRC/LITE/L2_interface_ue.c b/openair2/RRC/LITE/L2_interface_ue.c index 3a2aeea451..244f0d2253 100644 --- a/openair2/RRC/LITE/L2_interface_ue.c +++ b/openair2/RRC/LITE/L2_interface_ue.c @@ -65,6 +65,7 @@ mac_rrc_data_req_ue( ) //-------------------------------------------------------------------------- { + #ifdef DEBUG_RRC int i; LOG_I(RRC,"[eNB %d] mac_rrc_data_req to SRB ID=%d\n",Mod_idP,Srb_id); diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index 121d115398..3edf230ac2 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -242,6 +242,7 @@ openair_rrc_on_ue( { unsigned short i; + LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" UE?:OPENAIR RRC IN....\n", PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); @@ -4841,7 +4842,6 @@ rrc_rx_tx_ue( ) //----------------------------------------------------------------------------- { - //uint8_t UE_id; #ifdef LOCALIZATION double estimated_distance; diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index bbf35cffa0..71ee86ecf1 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -135,7 +135,6 @@ volatile int oai_exit = 0; static clock_source_t clock_source = internal; static int wait_for_sync = 0; -static int8_t UE_flag=0; unsigned int mmapped_dma=0; int single_thread_flag=1; @@ -322,7 +321,7 @@ void signal_handler(int sig) { void exit_fun(const char* s) { - int CC_id; + int ru_id; if (s != NULL) { @@ -331,33 +330,22 @@ void exit_fun(const char* s) oai_exit = 1; - if (UE_flag==0) { + + if (RC.ru == NULL) + exit(-1); // likely init not completed, prevent crash or hang, exit now... for (ru_id=0; ru_idrfdevice.trx_end_func) + if (RC.ru[ru_id] && RC.ru[ru_id]->rfdevice.trx_end_func) RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); - if (RC.ru[ru_id]->ifdevice.trx_end_func) + if (RC.ru[ru_id] && RC.ru[ru_id]->ifdevice.trx_end_func) RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); } - } - for(CC_id=0; CC_idrfdevice.trx_end_func) - PHY_vars_UE_g[0][CC_id]->rfdevice.trx_end_func(&PHY_vars_UE_g[0][CC_id]->rfdevice); - } - } #if defined(ENABLE_ITTI) sleep(1); //allow lte-softmodem threads to exit first itti_terminate_tasks (TASK_UNKNOWN); #endif - } } @@ -390,9 +378,9 @@ void reset_stats(FL_OBJECT *button, long arg) } static void *scope_thread(void *arg) { - char stats_buffer[16384]; + # ifdef ENABLE_XFORMS_WRITE_STATS - FILE *UE_stats, *eNB_stats; + FILE *eNB_stats; # endif struct sched_param sched_param; int UE_id, CC_id; @@ -405,47 +393,15 @@ static void *scope_thread(void *arg) { # ifdef ENABLE_XFORMS_WRITE_STATS - if (UE_flag==1) - UE_stats = fopen("UE_stats.txt", "w"); - else - eNB_stats = fopen("eNB_stats.txt", "w"); + eNB_stats = fopen("eNB_stats.txt", "w"); #endif while (!oai_exit) { - if (UE_flag==1) { - dump_ue_stats (PHY_vars_UE_g[0][0], &PHY_vars_UE_g[0][0]->proc.proc_rxtx[0],stats_buffer, 0, mode,rx_input_level_dBm); - //fl_set_object_label(form_stats->stats_text, stats_buffer); - fl_clear_browser(form_stats->stats_text); - fl_add_browser_line(form_stats->stats_text, stats_buffer); - phy_scope_UE(form_ue[0], - PHY_vars_UE_g[0][0], - 0, - 0,7); - - - } else { - /* - if (RC.eNB[0][0]->mac_enabled==1) { - len = dump_eNB_l2_stats (stats_buffer, 0); - //fl_set_object_label(form_stats_l2->stats_text, stats_buffer); - fl_clear_browser(form_stats_l2->stats_text); - fl_add_browser_line(form_stats_l2->stats_text, stats_buffer); - } - len = dump_eNB_stats (RC.eNB[0][0], stats_buffer, 0); - - if (MAX_NUM_CCs>1) - len += dump_eNB_stats (RC.eNB[0][1], &stats_buffer[len], 0); - - //fl_set_object_label(form_stats->stats_text, stats_buffer); - fl_clear_browser(form_stats->stats_text); - fl_add_browser_line(form_stats->stats_text, stats_buffer); - */ ue_cnt=0; for(UE_id=0; UE_iddlsch[UE_id][0]->rnti>0) && (ue_cnt 0) { - uint8_t n_rb_dl; - paramdef_t cmdline_uemodeparams[] =CMDLINE_UEMODEPARAMS_DESC; - paramdef_t cmdline_ueparams[] =CMDLINE_UEPARAMS_DESC; - - set_default_frame_parms(frame_parms); - - config_process_cmdline( cmdline_uemodeparams,sizeof(cmdline_uemodeparams)/sizeof(paramdef_t),NULL); - config_process_cmdline( cmdline_ueparams,sizeof(cmdline_ueparams)/sizeof(paramdef_t),NULL); - if (loopfile != NULL) { - printf("Input file for hardware emulation: %s",loopfile); - mode=loop_through_memory; - input_fd = fopen(loopfile,"r"); - AssertFatal(input_fd != NULL,"Please provide a valid input file\n"); - } - - if ( (cmdline_uemodeparams[CMDLINE_CALIBUERX_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue; - if ( (cmdline_uemodeparams[CMDLINE_CALIBUERXMED_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue_med; - if ( (cmdline_uemodeparams[CMDLINE_CALIBUERXBYP_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue_byp; - if ( *(cmdline_uemodeparams[CMDLINE_DEBUGUEPRACH_IDX].uptr) > 0) mode = debug_prach; - if ( *(cmdline_uemodeparams[CMDLINE_NOL2CONNECT_IDX].uptr) > 0) mode = no_L2_connect; - if ( *(cmdline_uemodeparams[CMDLINE_CALIBPRACHTX_IDX].uptr) > 0) mode = calib_prach_tx; - if (dumpframe > 0) mode = rx_dump_frame; - - if ( downlink_frequency[0][0] > 0) { - printf("Downlink frequency set to %u\n", downlink_frequency[0][0]); - for (CC_id=0; CC_iddl_CarrierFreq = downlink_frequency[0][0]; - } - UE_scan=0; - } - - if (tddflag > 0) { - for (CC_id=0; CC_idframe_type = TDD; - } - - if (frame_parms[0]->N_RB_DL !=0) { - if ( frame_parms[0]->N_RB_DL < 6 ) { - frame_parms[0]->N_RB_DL = 6; - printf ( "%i: Invalid number of ressource blocks, adjusted to 6\n",frame_parms[0]->N_RB_DL); - } - if ( frame_parms[0]->N_RB_DL > 100 ) { - frame_parms[0]->N_RB_DL = 100; - printf ( "%i: Invalid number of ressource blocks, adjusted to 100\n",frame_parms[0]->N_RB_DL); - } - if ( frame_parms[0]->N_RB_DL > 50 && frame_parms[0]->N_RB_DL < 100 ) { - frame_parms[0]->N_RB_DL = 50; - printf ( "%i: Invalid number of ressource blocks, adjusted to 50\n",frame_parms[0]->N_RB_DL); - } - if ( frame_parms[0]->N_RB_DL > 25 && frame_parms[0]->N_RB_DL < 50 ) { - frame_parms[0]->N_RB_DL = 25; - printf ( "%i: Invalid number of ressource blocks, adjusted to 25\n",frame_parms[0]->N_RB_DL); - } - UE_scan = 0; - frame_parms[0]->N_RB_UL=frame_parms[0]->N_RB_DL; - for (CC_id=1; CC_idN_RB_DL=frame_parms[0]->N_RB_DL; - frame_parms[CC_id]->N_RB_UL=frame_parms[0]->N_RB_UL; - } - } - - - for (CC_id=1;CC_id 0 */ - #if T_TRACER paramdef_t cmdline_ttraceparams[] =CMDLINE_TTRACEPARAMS_DESC ; config_process_cmdline( cmdline_ttraceparams,sizeof(cmdline_ttraceparams)/sizeof(paramdef_t),NULL); #endif if ( !(CONFIG_ISFLAGSET(CONFIG_ABORT)) ) { - if (UE_flag == 0) { memset((void*)&RC,0,sizeof(RC)); /* Read RC configuration file */ RCConfig(); NB_eNB_INST = RC.nb_inst; NB_RU = RC.nb_RU; printf("Configuration: nb_rrc_inst %d, nb_L1_inst %d, nb_ru %d\n",NB_eNB_INST,RC.nb_L1_inst,NB_RU); - } - } else if (UE_flag == 1 && (!(CONFIG_ISFLAGSET(CONFIG_NOOOPT))) ) { - // Here the configuration file is the XER encoded UE capabilities - // Read it in and store in asn1c data structures - sprintf(uecap_xer,"%stargets/PROJECTS/GENERIC-LTE-EPC/CONF/UE_config.xml",getenv("OPENAIR_HOME")); - printf("%s\n",uecap_xer); - uecap_xer_in=1; - } /* UE with config file */ + } } @@ -757,9 +619,8 @@ void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { } -void init_openair0(void); -void init_openair0() { +void init_openair0(void) { int card; int i; @@ -799,16 +660,14 @@ void init_openair0() { } - - if (frame_parms[0]->frame_type==TDD) openair0_cfg[card].duplex_mode = duplex_mode_TDD; else //FDD openair0_cfg[card].duplex_mode = duplex_mode_FDD; printf("HW: Configuring card %d, nb_antennas_tx/rx %d/%d\n",card, - ((UE_flag==0) ? RC.eNB[0][0]->frame_parms.nb_antennas_tx : PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_tx), - ((UE_flag==0) ? RC.eNB[0][0]->frame_parms.nb_antennas_rx : PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_rx)); + RC.eNB[0][0]->frame_parms.nb_antennas_tx , + RC.eNB[0][0]->frame_parms.nb_antennas_rx ); openair0_cfg[card].Mod_id = 0; openair0_cfg[card].num_rb_dl=frame_parms[0]->N_RB_DL; @@ -816,29 +675,25 @@ void init_openair0() { openair0_cfg[card].clock_source = clock_source; - openair0_cfg[card].tx_num_channels=min(2,((UE_flag==0) ? RC.eNB[0][0]->frame_parms.nb_antennas_tx : PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_tx)); - openair0_cfg[card].rx_num_channels=min(2,((UE_flag==0) ? RC.eNB[0][0]->frame_parms.nb_antennas_rx : PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_rx)); + openair0_cfg[card].tx_num_channels=min(2,RC.eNB[0][0]->frame_parms.nb_antennas_tx ); + openair0_cfg[card].rx_num_channels=min(2,RC.eNB[0][0]->frame_parms.nb_antennas_rx ); for (i=0; i<4; i++) { if (irx_total_gain_dB; - } - else { - openair0_cfg[card].rx_gain[i] = PHY_vars_UE_g[0][0]->rx_total_gain_dB - rx_gain_off; - } + openair0_cfg[card].rx_gain[i] = RC.eNB[0][0]->rx_total_gain_dB; + openair0_cfg[card].configFilename = rf_config_file; printf("Card %d, channel %d, Setting tx_gain %f, rx_gain %f, tx_freq %f, rx_freq %f\n", @@ -847,7 +702,7 @@ void init_openair0() { openair0_cfg[card].tx_freq[i], openair0_cfg[card].rx_freq[i]); } - } + } /* for loop on cards */ } @@ -995,7 +850,6 @@ int restart_L1L2(module_id_t enb_id) msg_p = itti_alloc_new_message(TASK_ENB_APP, RRC_CONFIGURATION_REQ); RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[enb_id]->configuration; itti_send_msg_to_task(TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); - /* TODO XForms might need to be restarted, but it is currently (09/02/18) * broken, so we cannot test it */ @@ -1016,7 +870,7 @@ int restart_L1L2(module_id_t enb_id) } #endif -static inline void wait_nfapi_init(char *thread_name) { +static void wait_nfapi_init(char *thread_name) { printf( "waiting for NFAPI PNF connection and population of global structure (%s)\n",thread_name); pthread_mutex_lock( &nfapi_sync_mutex ); @@ -1038,9 +892,6 @@ int main( int argc, char **argv ) int CC_id; int ru_id; - uint8_t abstraction_flag=0; - uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2; - #if defined (XFORMS) int ret; #endif @@ -1055,8 +906,6 @@ int main( int argc, char **argv ) setvbuf(stderr, NULL, _IONBF, 0); #endif - PHY_VARS_UE *UE[MAX_NUM_CCs]; - mode = normal_txrx; memset(&openair0_cfg[0],0,sizeof(openair0_config_t)*MAX_CARDS); @@ -1064,16 +913,12 @@ int main( int argc, char **argv ) set_latency_target(); - - // set default parameters - //if (UE_flag == 1) set_default_frame_parms(frame_parms); - logInit(); printf("Reading in command-line options\n"); get_options (); - if (CONFIG_ISFLAGSET(CONFIG_ABORT) && UE_flag == 0) { + if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) { fprintf(stderr,"Getting configuration failed\n"); exit(-1); } @@ -1088,32 +933,10 @@ int main( int argc, char **argv ) //randominit (0); set_taus_seed (0); - if (UE_flag==1) { - printf("configuring for UE\n"); + printf("configuring for RAU/RRU\n"); - set_comp_log(HW, LOG_DEBUG, LOG_HIGH, 1); - set_comp_log(PHY, LOG_INFO, LOG_HIGH, 1); - set_comp_log(MAC, LOG_INFO, LOG_HIGH, 1); - set_comp_log(RLC, LOG_INFO, LOG_HIGH | FLAG_THREAD, 1); - set_comp_log(PDCP, LOG_INFO, LOG_HIGH, 1); - set_comp_log(OTG, LOG_INFO, LOG_HIGH, 1); - set_comp_log(RRC, LOG_INFO, LOG_HIGH, 1); -#if defined(ENABLE_ITTI) - set_comp_log(EMU, LOG_INFO, LOG_MED, 1); -# if defined(ENABLE_USE_MME) - set_comp_log(NAS, LOG_INFO, LOG_HIGH, 1); -# endif -#endif - - } else { - printf("configuring for RAU/RRU\n"); - - } if (ouput_vcd) { - if (UE_flag==1) - VCD_SIGNAL_DUMPER_INIT("/tmp/openair_dump_UE.vcd"); - else VCD_SIGNAL_DUMPER_INIT("/tmp/openair_dump_eNB.vcd"); } @@ -1123,12 +946,7 @@ int main( int argc, char **argv ) cpuf=get_cpu_freq_GHz(); #if defined(ENABLE_ITTI) - - if (UE_flag == 1) { - log_set_instance_type (LOG_INSTANCE_UE); - } else { - log_set_instance_type (LOG_INSTANCE_ENB); - } + log_set_instance_type (LOG_INSTANCE_ENB); printf("ITTI init\n"); itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info, messages_definition_xml, itti_dump_file); @@ -1172,82 +990,11 @@ int main( int argc, char **argv ) LOG_I(HW, "Version: %s\n", PACKAGE_VERSION); - // init the parameters - for (CC_id=0; CC_idnb_antennas_tx = nb_antenna_tx; - frame_parms[CC_id]->nb_antennas_rx = nb_antenna_rx; - frame_parms[CC_id]->nb_antenna_ports_eNB = 1; //initial value overwritten by initial sync later - } - } printf("Before CC \n"); - for (CC_id=0; CC_idmac_enabled = 0; - else - UE[CC_id]->mac_enabled = 1; - - if (UE[CC_id]->mac_enabled == 0) { //set default UL parameters for testing mode - for (i=0; ipusch_config_dedicated[i].betaOffset_ACK_Index = beta_ACK; - UE[CC_id]->pusch_config_dedicated[i].betaOffset_RI_Index = beta_RI; - UE[CC_id]->pusch_config_dedicated[i].betaOffset_CQI_Index = beta_CQI; - - UE[CC_id]->scheduling_request_config[i].sr_PUCCH_ResourceIndex = 0; - UE[CC_id]->scheduling_request_config[i].sr_ConfigIndex = 7+(0%3); - UE[CC_id]->scheduling_request_config[i].dsr_TransMax = sr_n4; - } - } - - UE[CC_id]->UE_scan = UE_scan; - UE[CC_id]->UE_scan_carrier = UE_scan_carrier; - UE[CC_id]->mode = mode; - printf("UE[%d]->mode = %d\n",CC_id,mode); - - if (UE[CC_id]->mac_enabled == 1) { - UE[CC_id]->pdcch_vars[0][0]->crnti = 0x1234; - UE[CC_id]->pdcch_vars[1][0]->crnti = 0x1234; - }else { - UE[CC_id]->pdcch_vars[0][0]->crnti = 0x1235; - UE[CC_id]->pdcch_vars[1][0]->crnti = 0x1235; - } - UE[CC_id]->rx_total_gain_dB = (int)rx_gain[CC_id][0] + rx_gain_off; - UE[CC_id]->tx_power_max_dBm = tx_max_power[CC_id]; - - if (frame_parms[CC_id]->frame_type==FDD) { - UE[CC_id]->N_TA_offset = 0; - } - else { - if (frame_parms[CC_id]->N_RB_DL == 100) - UE[CC_id]->N_TA_offset = 624; - else if (frame_parms[CC_id]->N_RB_DL == 50) - UE[CC_id]->N_TA_offset = 624/2; - else if (frame_parms[CC_id]->N_RB_DL == 25) - UE[CC_id]->N_TA_offset = 624/4; - } - init_openair0(); - } - - } - printf("Runtime table\n"); fill_modeled_runtime_table(runtime_phy_rx,runtime_phy_tx); cpuf=get_cpu_freq_GHz(); @@ -1296,22 +1043,13 @@ int main( int argc, char **argv ) #if defined(ENABLE_ITTI) - if ((UE_flag == 1)|| - (RC.nb_inst > 0)) { + if (RC.nb_inst > 0) { // don't create if node doesn't connect to RRC/S1/GTP - if (UE_flag == 0) { if (create_tasks(1) < 0) { printf("cannot create ITTI tasks\n"); exit(-1); // need a softer mode } - } - else { - if (create_tasks_ue(1) < 0) { - printf("cannot create ITTI tasks\n"); - exit(-1); // need a softer mode - } - } printf("ITTI tasks created\n"); } else { @@ -1343,7 +1081,6 @@ int main( int argc, char **argv ) if (do_forms==1) { fl_initialize (&argc, argv, NULL, 0, 0); - if (UE_flag==0) { form_stats_l2 = create_form_stats_form(); fl_show_form (form_stats_l2->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "l2 stats"); form_stats = create_form_stats_form(); @@ -1364,25 +1101,6 @@ int main( int argc, char **argv ) } } // CC_id } // UE_id - } else { - form_stats = create_form_stats_form(); - fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats"); - UE_id = 0; - form_ue[UE_id] = create_lte_phy_scope_ue(); - sprintf (title, "LTE DL SCOPE UE"); - fl_show_form (form_ue[UE_id]->lte_phy_scope_ue, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); - - /* - if (openair_daq_vars.use_ia_receiver) { - fl_set_button(form_ue[UE_id]->button_0,1); - fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver ON"); - } else { - fl_set_button(form_ue[UE_id]->button_0,0); - fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF"); - }*/ - fl_set_button(form_ue[UE_id]->button_0,0); - fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF"); - } ret = pthread_create(&forms_thread, NULL, scope_thread, NULL); @@ -1427,23 +1145,7 @@ int main( int argc, char **argv ) printf("START MAIN THREADS\n"); // start the main threads - if (UE_flag == 1) { - int eMBMS_active = 0; - init_UE(1,eMBMS_active,uecap_xer_in,0); - if (phy_test==0) { - printf("Filling UE band info\n"); - fill_ue_band_info(); - dl_phy_sync_success (0, 0, 0, 1); - } - - number_of_cards = 1; - for(CC_id=0; CC_idrf_map.card=0; - PHY_vars_UE_g[0][CC_id]->rf_map.chain=CC_id+chain_offset; - } - } - else { number_of_cards = 1; printf("RC.nb_L1_inst:%d\n", RC.nb_L1_inst); if (RC.nb_L1_inst > 0) { @@ -1490,42 +1192,10 @@ int main( int argc, char **argv ) } printf("ALL RUs ready - ALL eNBs ready\n"); - } // connect the TX/RX buffers - if (UE_flag==1) { - - for (CC_id=0; CC_idhw_timing_advance = timing_advance; -#else - UE[CC_id]->hw_timing_advance = 160; -#endif - } - if (setup_ue_buffers(UE,&openair0_cfg[0])!=0) { - printf("Error setting up eNB buffer\n"); - exit(-1); - } - - - - if (input_fd) { - printf("Reading in from file to antenna buffer %d\n",0); - if (fread(UE[0]->common_vars.rxdata[0], - sizeof(int32_t), - frame_parms[0]->samples_per_tti*10, - input_fd) != frame_parms[0]->samples_per_tti*10) - printf("error reading from file\n"); - } - //p_exmimo_config->framing.tdd_config = TXRXSWITCH_TESTRX; - } else { - - printf("eNB mode\n"); - - } + printf("Sending sync to all threads\n"); @@ -1564,10 +1234,6 @@ int main( int argc, char **argv ) fl_hide_form(form_stats->stats_form); fl_free_form(form_stats->stats_form); - if (UE_flag==1) { - fl_hide_form(form_ue[0]->lte_phy_scope_ue); - fl_free_form(form_ue[0]->lte_phy_scope_ue); - } else { fl_hide_form(form_stats_l2->stats_form); fl_free_form(form_stats_l2->stats_form); @@ -1577,7 +1243,6 @@ int main( int argc, char **argv ) fl_free_form(form_enb[CC_id][UE_id]->lte_phy_scope_enb); } } - } } #endif @@ -1585,8 +1250,6 @@ int main( int argc, char **argv ) printf("stopping MODEM threads\n"); // cleanup - if (UE_flag == 1) { - } else { stop_eNB(NB_eNB_INST); stop_RU(NB_RU); /* release memory used by the RU/eNB threads (incomplete), after all @@ -1601,7 +1264,6 @@ int main( int argc, char **argv ) phy_free_RU(RC.ru[inst]); } free_lte_top(); - } pthread_cond_destroy(&sync_cond); @@ -1613,11 +1275,7 @@ int main( int argc, char **argv ) pthread_mutex_destroy(&ue_pf_po_mutex); // *** Handle per CC_id openair0 - if (UE_flag==1) { - if (PHY_vars_UE_g[0][0]->rfdevice.trx_end_func) - PHY_vars_UE_g[0][0]->rfdevice.trx_end_func(&PHY_vars_UE_g[0][0]->rfdevice); - } - else { + for(ru_id=0; ru_idrfdevice.trx_end_func) RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); @@ -1625,7 +1283,6 @@ int main( int argc, char **argv ) RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); } - } if (ouput_vcd) VCD_SIGNAL_DUMPER_CLOSE(); diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index 1d594caadc..e8b9d92490 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -129,10 +129,10 @@ {"ue-nb-ant-tx", CONFIG_HLP_UENANTT, 0, u8ptr:&nb_antenna_tx, defuintval:1, TYPE_UINT8, 0}, \ {"ue-scan-carrier", CONFIG_HLP_UESCAN, PARAMFLAG_BOOL, iptr:&UE_scan_carrier, defintval:0, TYPE_INT, 0}, \ {"ue-max-power", NULL, 0, iptr:&(tx_max_power[0]), defintval:90, TYPE_INT, 0}, \ -{"r" , CONFIG_HLP_PRB, 0, u8ptr:&(frame_parms[0]->N_RB_DL), defintval:0, TYPE_UINT8, 0}, \ +{"r" , CONFIG_HLP_PRB, 0, u8ptr:&(frame_parms[0]->N_RB_DL), defintval:25, TYPE_UINT8, 0}, \ } - +#define DEFAULT_DLF 2680000000 extern int16_t dlsch_demod_shift; /*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* command line parameters common to eNodeB and UE */ @@ -155,12 +155,11 @@ extern int16_t dlsch_demod_shift; {"threadSlot1ProcTwo", NULL, 0, iptr:&(threads.slot1_proc_two), defintval:1, TYPE_INT, 0}, \ {"dlsch-demod-shift", CONFIG_HLP_DLSHIFT, 0, iptr:(int32_t *)&dlsch_demod_shift, defintval:0, TYPE_INT, 0}, \ {"A" , CONFIG_HLP_TADV, 0, uptr:&timing_advance, defintval:0, TYPE_UINT, 0}, \ -{"C" , CONFIG_HLP_DLF, 0, uptr:&(downlink_frequency[0][0]), defuintval:2680000000, TYPE_UINT, 0}, \ +{"C" , CONFIG_HLP_DLF, 0, uptr:&(downlink_frequency[0][0]), defuintval:DEFAULT_DLF, TYPE_UINT, 0}, \ {"a" , CONFIG_HLP_CHOFF, 0, iptr:&chain_offset, defintval:0, TYPE_INT, 0}, \ {"d" , CONFIG_HLP_SOFTS, PARAMFLAG_BOOL, uptr:(uint32_t *)&do_forms, defintval:0, TYPE_INT8, 0}, \ {"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, i8ptr:&threequarter_fs, defintval:0, TYPE_INT8, 0}, \ {"K" , CONFIG_HLP_ITTIL, PARAMFLAG_NOFREE, strptr:&itti_dump_file, defstrval:"/tmp/itti.dump", TYPE_STRING, 0}, \ -{"U" , CONFIG_HLP_UE, PARAMFLAG_BOOL, i8ptr:&UE_flag, defintval:0, TYPE_INT8, 0}, \ {"m" , CONFIG_HLP_DLMCS, 0, uptr:&target_dl_mcs, defintval:0, TYPE_UINT, 0}, \ {"t" , CONFIG_HLP_ULMCS, 0, uptr:&target_ul_mcs, defintval:0, TYPE_UINT, 0}, \ {"W" , CONFIG_HLP_L2MONW, 0, strptr:(char **)&in_ip, defstrval:"127.0.0.1", TYPE_STRING, sizeof(in_ip)}, \ diff --git a/targets/RT/USER/lte-uesoftmodem.c b/targets/RT/USER/lte-uesoftmodem.c new file mode 100644 index 0000000000..ae4798f399 --- /dev/null +++ b/targets/RT/USER/lte-uesoftmodem.c @@ -0,0 +1,1139 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file lte-enb.c + * \brief Top-level threads for eNodeB + * \author R. Knopp, F. Kaltenberger, Navid Nikaein + * \date 2012 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr + * \note + * \warning + */ + + +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include + + +#include "T.h" + +#include "rt_wrapper.h" + + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "assertions.h" +#include "msc.h" + +#include "PHY/types.h" + +#include "PHY/defs.h" +#include "common/ran_context.h" +#include "common/config/config_userapi.h" +#include "common/utils/load_module_shlib.h" +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "../../ARCH/COMMON/common_lib.h" +#include "../../ARCH/ETHERNET/USERSPACE/LIB/if_defs.h" + +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "PHY/vars.h" +#include "SCHED/vars.h" +#include "LAYER2/MAC/vars.h" + +#include "../../SIMU/USER/init_lte.h" + +#include "LAYER2/MAC/defs.h" +#include "LAYER2/MAC/vars.h" +#include "LAYER2/MAC/proto.h" +#include "RRC/LITE/vars.h" +#include "PHY_INTERFACE/vars.h" + +#ifdef SMBV +#include "PHY/TOOLS/smbv.h" +unsigned short config_frames[4] = {2,9,11,13}; +#endif +#include "UTIL/LOG/log_extern.h" +#include "UTIL/OTG/otg_tx.h" +#include "UTIL/OTG/otg_externs.h" +#include "UTIL/MATH/oml.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" +#include "enb_config.h" +//#include "PHY/TOOLS/time_meas.h" + +#ifndef OPENAIR2 +#include "UTIL/OTG/otg_vars.h" +#endif + +#if defined(ENABLE_ITTI) +#include "intertask_interface_init.h" +#include "create_tasks.h" +#endif + +#include "system.h" + +#ifdef XFORMS +#include "PHY/TOOLS/lte_phy_scope.h" +#include "stats.h" +#endif +#include "lte-softmodem.h" + +/* temporary compilation wokaround (UE/eNB split */ +uint16_t sf_ahead; +#ifdef XFORMS +// current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0) +// at eNB 0, an UL scope for every UE +FD_lte_phy_scope_ue *form_ue[NUMBER_OF_UE_MAX]; +FD_lte_phy_scope_enb *form_enb[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +FD_stats_form *form_stats=NULL,*form_stats_l2=NULL; +char title[255]; +unsigned char scope_enb_num_ue = 2; +static pthread_t forms_thread; //xforms +#endif //XFORMS + +pthread_cond_t sync_cond; +pthread_mutex_t sync_mutex; +int sync_var=-1; //!< protected by mutex \ref sync_mutex. +int config_sync_var=-1; + +uint16_t runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] +uint16_t runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] + +#if defined(ENABLE_ITTI) +volatile int start_eNB = 0; +volatile int start_UE = 0; +#endif +volatile int oai_exit = 0; + +static clock_source_t clock_source = internal; +static int wait_for_sync = 0; + +unsigned int mmapped_dma=0; +int single_thread_flag=1; + +static int8_t threequarter_fs=0; + +uint32_t downlink_frequency[MAX_NUM_CCs][4]; +int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; + + + +#if defined(ENABLE_ITTI) +static char *itti_dump_file = NULL; +#endif + +int UE_scan = 1; +int UE_scan_carrier = 0; +runmode_t mode = normal_txrx; + +FILE *input_fd=NULL; + + +#if MAX_NUM_CCs == 1 +rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain}}; +double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0}}; +double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0}}; +#else +rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain},{max_gain,max_gain,max_gain,max_gain}}; +double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0},{20,0,0,0}}; +double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0},{20,0,0,0}}; +#endif + +double rx_gain_off = 0.0; + +double sample_rate=30.72e6; +double bw = 10.0e6; + +static int tx_max_power[MAX_NUM_CCs]; /* = {0,0}*/; + +char rf_config_file[1024]; + +int chain_offset=0; +int phy_test = 0; +uint8_t usim_test = 0; + +uint8_t dci_Format = 0; +uint8_t agregation_Level =0xFF; + +uint8_t nb_antenna_tx = 1; +uint8_t nb_antenna_rx = 1; + +char ref[128] = "internal"; +char channels[128] = "0"; + +int rx_input_level_dBm; + +#ifdef XFORMS +extern int otg_enabled; +static char do_forms=0; +#else +int otg_enabled; +#endif +//int number_of_cards = 1; + + +static LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; +uint32_t target_dl_mcs = 28; //maximum allowed mcs +uint32_t target_ul_mcs = 20; +uint32_t timing_advance = 0; +uint8_t exit_missed_slots=1; +uint64_t num_missed_slots=0; // counter for the number of missed slots + + +extern void reset_opp_meas(void); +extern void print_opp_meas(void); + +extern PHY_VARS_UE* init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms, + uint8_t UE_id, + uint8_t abstraction_flag); + + +int transmission_mode=1; + + + +/* struct for ethernet specific parameters given in eNB conf file */ +eth_params_t *eth_params; + +openair0_config_t openair0_cfg[MAX_CARDS]; + +double cpuf; + +extern char uecap_xer[1024]; +char uecap_xer_in=0; + +int oaisim_flag=0; +threads_t threads= {-1,-1,-1,-1,-1,-1,-1}; + +/* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed + * this is very hackish - find a proper solution + */ +uint8_t abstraction_flag=0; + +/* forward declarations */ +void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); + +/*---------------------BMC: timespec helpers -----------------------------*/ + +struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; +struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; + +struct timespec clock_difftime(struct timespec start, struct timespec end) { + struct timespec temp; + if ((end.tv_nsec-start.tv_nsec)<0) { + temp.tv_sec = end.tv_sec-start.tv_sec-1; + temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; + } else { + temp.tv_sec = end.tv_sec-start.tv_sec; + temp.tv_nsec = end.tv_nsec-start.tv_nsec; + } + return temp; +} + +void print_difftimes(void) { +#ifdef DEBUG + printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); +#else + LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); +#endif +} + +void update_difftimes(struct timespec start, struct timespec end) { + struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 }; + int changed = 0; + diff_time = clock_difftime(start, end); + if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) { + min_diff_time.tv_nsec = diff_time.tv_nsec; + changed = 1; + } + if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) { + max_diff_time.tv_nsec = diff_time.tv_nsec; + changed = 1; + } +#if 1 + if (changed) print_difftimes(); +#endif +} + +/*------------------------------------------------------------------------*/ + +unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) { + return (txi + (txq<<6) + (rxi<<12) + (rxq<<18)); +} +unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) { + return (dcoff_i_rxfe + (dcoff_q_rxfe<<8)); +} + +#if !defined(ENABLE_ITTI) +void signal_handler(int sig) { + void *array[10]; + size_t size; + + if (sig==SIGSEGV) { + // get void*'s for all entries on the stack + size = backtrace(array, 10); + + // print out all the frames to stderr + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, 2); + exit(-1); + } else { + printf("trying to exit gracefully...\n"); + oai_exit = 1; + } +} +#endif +#define KNRM "\x1B[0m" +#define KRED "\x1B[31m" +#define KGRN "\x1B[32m" +#define KBLU "\x1B[34m" +#define RESET "\033[0m" + + + +void exit_fun(const char* s) +{ + int CC_id; + + if (s != NULL) { + printf("%s %s() Exiting OAI softmodem: %s\n",__FILE__, __FUNCTION__, s); + } + + oai_exit = 1; + + for(CC_id=0; CC_idrfdevice.trx_end_func) + PHY_vars_UE_g[0][CC_id]->rfdevice.trx_end_func(&PHY_vars_UE_g[0][CC_id]->rfdevice); + } + +#if defined(ENABLE_ITTI) + sleep(1); //allow lte-softmodem threads to exit first + itti_terminate_tasks (TASK_UNKNOWN); +#endif +} + +#ifdef XFORMS + + +void reset_stats(FL_OBJECT *button, long arg) +{ + int i,j,k; + PHY_VARS_eNB *phy_vars_eNB = RC.eNB[0][0]; + + for (i=0; idlsch[i][0]->Mlimit; j++) { + phy_vars_eNB->UE_stats[i].dlsch_NAK[k][j]=0; + phy_vars_eNB->UE_stats[i].dlsch_ACK[k][j]=0; + phy_vars_eNB->UE_stats[i].dlsch_trials[k][j]=0; + } + + phy_vars_eNB->UE_stats[i].dlsch_l2_errors[k]=0; + phy_vars_eNB->UE_stats[i].ulsch_errors[k]=0; + phy_vars_eNB->UE_stats[i].ulsch_consecutive_errors=0; + + + phy_vars_eNB->UE_stats[i].dlsch_sliding_cnt=0; + phy_vars_eNB->UE_stats[i].dlsch_NAK_round0=0; + phy_vars_eNB->UE_stats[i].dlsch_mcs_offset=0; + } + } +} + +static void *scope_thread(void *arg) { + char stats_buffer[16384]; +# ifdef ENABLE_XFORMS_WRITE_STATS + FILE *UE_stats, *eNB_stats; +# endif + struct sched_param sched_param; + + + sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO)+1; + sched_setscheduler(0, SCHED_FIFO,&sched_param); + + printf("Scope thread has priority %d\n",sched_param.sched_priority); + +# ifdef ENABLE_XFORMS_WRITE_STATS + + UE_stats = fopen("UE_stats.txt", "w"); + +#endif + + while (!oai_exit) { + dump_ue_stats (PHY_vars_UE_g[0][0], &PHY_vars_UE_g[0][0]->proc.proc_rxtx[0],stats_buffer, 0, mode,rx_input_level_dBm); + //fl_set_object_label(form_stats->stats_text, stats_buffer); + fl_clear_browser(form_stats->stats_text); + fl_add_browser_line(form_stats->stats_text, stats_buffer); + + phy_scope_UE(form_ue[0], + PHY_vars_UE_g[0][0], + 0, + 0,7); + + // printf("%s",stats_buffer); + } +# ifdef ENABLE_XFORMS_WRITE_STATS + + if (UE_stats) { + rewind (UE_stats); + fwrite (stats_buffer, 1, len, UE_stats); + fclose (UE_stats); + } + +# endif + + pthread_exit((void*)arg); +} +#endif + + + +#if defined(ENABLE_ITTI) +void *l2l1_task(void *arg) { + MessageDef *message_p = NULL; + int result; + + itti_set_task_real_time(TASK_L2L1); + itti_mark_task_ready(TASK_L2L1); + + + do { + // Wait for a message + itti_receive_msg (TASK_L2L1, &message_p); + + switch (ITTI_MSG_ID(message_p)) { + case TERMINATE_MESSAGE: + oai_exit=1; + itti_exit_task (); + break; + + case ACTIVATE_MESSAGE: + start_UE = 1; + break; + + case DEACTIVATE_MESSAGE: + start_UE = 0; + break; + + case MESSAGE_TEST: + LOG_I(EMU, "Received %s\n", ITTI_MSG_NAME(message_p)); + break; + + default: + LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p)); + break; + } + + result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } while(!oai_exit); + + return NULL; +} +#endif + + +static void get_options(void) { + int CC_id; + int tddflag, nonbiotflag; + char *loopfile=NULL; + int dumpframe; + uint32_t online_log_messages; + uint32_t glog_level, glog_verbosity; + uint32_t start_telnetsrv; + + paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC ; + paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ; + + set_default_frame_parms(frame_parms); + config_process_cmdline( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL); + + if (strlen(in_path) > 0) { + opt_type = OPT_PCAP; + opt_enabled=1; + printf("Enabling OPT for PCAP with the following file %s \n",in_path); + } + if (strlen(in_ip) > 0) { + opt_enabled=1; + opt_type = OPT_WIRESHARK; + printf("Enabling OPT for wireshark for local interface"); + } + + config_process_cmdline( cmdline_logparams,sizeof(cmdline_logparams)/sizeof(paramdef_t),NULL); + if(config_isparamset(cmdline_logparams,CMDLINE_ONLINELOG_IDX)) { + set_glog_onlinelog(online_log_messages); + } + if(config_isparamset(cmdline_logparams,CMDLINE_GLOGLEVEL_IDX)) { + set_glog(glog_level, -1); + } + if(config_isparamset(cmdline_logparams,CMDLINE_GLOGVERBO_IDX)) { + set_glog(-1, glog_verbosity); + } + if (start_telnetsrv) { + load_module_shlib("telnetsrv",NULL,0); + } + + paramdef_t cmdline_uemodeparams[] =CMDLINE_UEMODEPARAMS_DESC; + paramdef_t cmdline_ueparams[] =CMDLINE_UEPARAMS_DESC; + + + config_process_cmdline( cmdline_uemodeparams,sizeof(cmdline_uemodeparams)/sizeof(paramdef_t),NULL); + config_process_cmdline( cmdline_ueparams,sizeof(cmdline_ueparams)/sizeof(paramdef_t),NULL); + if (loopfile != NULL) { + printf("Input file for hardware emulation: %s",loopfile); + mode=loop_through_memory; + input_fd = fopen(loopfile,"r"); + AssertFatal(input_fd != NULL,"Please provide a valid input file\n"); + } + + if ( (cmdline_uemodeparams[CMDLINE_CALIBUERX_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue; + if ( (cmdline_uemodeparams[CMDLINE_CALIBUERXMED_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue_med; + if ( (cmdline_uemodeparams[CMDLINE_CALIBUERXBYP_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue_byp; + if (cmdline_uemodeparams[CMDLINE_DEBUGUEPRACH_IDX].uptr) + if ( *(cmdline_uemodeparams[CMDLINE_DEBUGUEPRACH_IDX].uptr) > 0) mode = debug_prach; + if (cmdline_uemodeparams[CMDLINE_NOL2CONNECT_IDX].uptr) + if ( *(cmdline_uemodeparams[CMDLINE_NOL2CONNECT_IDX].uptr) > 0) mode = no_L2_connect; + if (cmdline_uemodeparams[CMDLINE_CALIBPRACHTX_IDX].uptr) + if ( *(cmdline_uemodeparams[CMDLINE_CALIBPRACHTX_IDX].uptr) > 0) mode = calib_prach_tx; + if (dumpframe > 0) mode = rx_dump_frame; + + for (CC_id=0; CC_iddl_CarrierFreq = downlink_frequency[0][0]; + } + UE_scan=0; + + + if (tddflag > 0) { + for (CC_id=0; CC_idframe_type = TDD; + } + + if (frame_parms[0]->N_RB_DL !=0) { + if ( frame_parms[0]->N_RB_DL < 6 ) { + frame_parms[0]->N_RB_DL = 6; + printf ( "%i: Invalid number of ressource blocks, adjusted to 6\n",frame_parms[0]->N_RB_DL); + } + if ( frame_parms[0]->N_RB_DL > 100 ) { + frame_parms[0]->N_RB_DL = 100; + printf ( "%i: Invalid number of ressource blocks, adjusted to 100\n",frame_parms[0]->N_RB_DL); + } + if ( frame_parms[0]->N_RB_DL > 50 && frame_parms[0]->N_RB_DL < 100 ) { + frame_parms[0]->N_RB_DL = 50; + printf ( "%i: Invalid number of ressource blocks, adjusted to 50\n",frame_parms[0]->N_RB_DL); + } + if ( frame_parms[0]->N_RB_DL > 25 && frame_parms[0]->N_RB_DL < 50 ) { + frame_parms[0]->N_RB_DL = 25; + printf ( "%i: Invalid number of ressource blocks, adjusted to 25\n",frame_parms[0]->N_RB_DL); + } + UE_scan = 0; + frame_parms[0]->N_RB_UL=frame_parms[0]->N_RB_DL; + for (CC_id=1; CC_idN_RB_DL=frame_parms[0]->N_RB_DL; + frame_parms[CC_id]->N_RB_UL=frame_parms[0]->N_RB_UL; + } + } + + + for (CC_id=1;CC_idframe_type = FDD; + frame_parms[CC_id]->tdd_config = 3; + frame_parms[CC_id]->tdd_config_S = 0; + frame_parms[CC_id]->N_RB_DL = 100; + frame_parms[CC_id]->N_RB_UL = 100; + frame_parms[CC_id]->Ncp = NORMAL; + frame_parms[CC_id]->Ncp_UL = NORMAL; + frame_parms[CC_id]->Nid_cell = 0; + frame_parms[CC_id]->num_MBSFN_config = 0; + frame_parms[CC_id]->nb_antenna_ports_eNB = 1; + frame_parms[CC_id]->nb_antennas_tx = 1; + frame_parms[CC_id]->nb_antennas_rx = 1; + + frame_parms[CC_id]->nushift = 0; + + frame_parms[CC_id]->phich_config_common.phich_resource = oneSixth; + frame_parms[CC_id]->phich_config_common.phich_duration = normal; + // UL RS Config + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = 0;//n_DMRS1 set to 0 + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 0; + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 0; + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = 0; + + frame_parms[CC_id]->prach_config_common.rootSequenceIndex=22; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig=1; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_ConfigIndex=0; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.highSpeedFlag=0; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset=0; + + downlink_frequency[CC_id][0] = DEFAULT_DLF; // Use float to avoid issue with frequency over 2^31. + downlink_frequency[CC_id][1] = downlink_frequency[CC_id][0]; + downlink_frequency[CC_id][2] = downlink_frequency[CC_id][0]; + downlink_frequency[CC_id][3] = downlink_frequency[CC_id][0]; + + frame_parms[CC_id]->dl_CarrierFreq=downlink_frequency[CC_id][0]; + + } + +} + +void init_openair0(void) { + + int card; + int i; + + for (card=0; cardN_RB_DL == 100) { + if (frame_parms[0]->threequarter_fs) { + openair0_cfg[card].sample_rate=23.04e6; + openair0_cfg[card].samples_per_frame = 230400; + openair0_cfg[card].tx_bw = 10e6; + openair0_cfg[card].rx_bw = 10e6; + } else { + openair0_cfg[card].sample_rate=30.72e6; + openair0_cfg[card].samples_per_frame = 307200; + openair0_cfg[card].tx_bw = 10e6; + openair0_cfg[card].rx_bw = 10e6; + } + } else if(frame_parms[0]->N_RB_DL == 50) { + openair0_cfg[card].sample_rate=15.36e6; + openair0_cfg[card].samples_per_frame = 153600; + openair0_cfg[card].tx_bw = 5e6; + openair0_cfg[card].rx_bw = 5e6; + } else if (frame_parms[0]->N_RB_DL == 25) { + openair0_cfg[card].sample_rate=7.68e6; + openair0_cfg[card].samples_per_frame = 76800; + openair0_cfg[card].tx_bw = 2.5e6; + openair0_cfg[card].rx_bw = 2.5e6; + } else if (frame_parms[0]->N_RB_DL == 6) { + openair0_cfg[card].sample_rate=1.92e6; + openair0_cfg[card].samples_per_frame = 19200; + openair0_cfg[card].tx_bw = 1.5e6; + openair0_cfg[card].rx_bw = 1.5e6; + } + + + + + if (frame_parms[0]->frame_type==TDD) + openair0_cfg[card].duplex_mode = duplex_mode_TDD; + else //FDD + openair0_cfg[card].duplex_mode = duplex_mode_FDD; + + printf("HW: Configuring card %d, nb_antennas_tx/rx %d/%d\n",card, + PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_tx, + PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_rx); + openair0_cfg[card].Mod_id = 0; + + openair0_cfg[card].num_rb_dl=frame_parms[0]->N_RB_DL; + + openair0_cfg[card].clock_source = clock_source; + + + openair0_cfg[card].tx_num_channels=min(2,PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_tx); + openair0_cfg[card].rx_num_channels=min(2,PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_rx); + + for (i=0; i<4; i++) { + + if (irx_total_gain_dB - rx_gain_off; + + + openair0_cfg[card].configFilename = rf_config_file; + printf("Card %d, channel %d, Setting tx_gain %f, rx_gain %f, tx_freq %f, rx_freq %f\n", + card,i, openair0_cfg[card].tx_gain[i], + openair0_cfg[card].rx_gain[i], + openair0_cfg[card].tx_freq[i], + openair0_cfg[card].rx_freq[i]); + } + } +} + + + + +#if defined(ENABLE_ITTI) +/* + * helper function to terminate a certain ITTI task + */ +void terminate_task(task_id_t task_id, module_id_t mod_id) +{ + LOG_I(ENB_APP, "sending TERMINATE_MESSAGE to task %s (%d)\n", itti_get_task_name(task_id), task_id); + MessageDef *msg; + msg = itti_alloc_new_message (ENB_APP, TERMINATE_MESSAGE); + itti_send_msg_to_task (task_id, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg); +} + + + +#endif + +int main( int argc, char **argv ) +{ + int i; +#if defined (XFORMS) + void *status; +#endif + + int CC_id; + uint8_t abstraction_flag=0; + uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2; + +#if defined (XFORMS) + int ret; +#endif + + start_background_system(); + if ( load_configmodule(argc,argv) == NULL) { + exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); + } + +#ifdef DEBUG_CONSOLE + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); +#endif + + PHY_VARS_UE *UE[MAX_NUM_CCs]; + + mode = normal_txrx; + memset(&openair0_cfg[0],0,sizeof(openair0_config_t)*MAX_CARDS); + + memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs); + + set_latency_target(); + + logInit(); + + printf("Reading in command-line options\n"); + + get_options (); + + +#if T_TRACER + T_init(T_port, 1-T_nowait, T_dont_fork); +#endif + + + + //randominit (0); + set_taus_seed (0); + + + set_comp_log(HW, LOG_DEBUG, LOG_HIGH, 1); + set_comp_log(PHY, LOG_INFO, LOG_HIGH, 1); + set_comp_log(MAC, LOG_INFO, LOG_HIGH, 1); + set_comp_log(RLC, LOG_INFO, LOG_HIGH | FLAG_THREAD, 1); + set_comp_log(PDCP, LOG_INFO, LOG_HIGH, 1); + set_comp_log(OTG, LOG_INFO, LOG_HIGH, 1); + set_comp_log(RRC, LOG_INFO, LOG_HIGH, 1); +#if defined(ENABLE_ITTI) + set_comp_log(EMU, LOG_INFO, LOG_MED, 1); +# if defined(ENABLE_USE_MME) + set_comp_log(NAS, LOG_INFO, LOG_HIGH, 1); +# endif +#endif + + + if (ouput_vcd) { + VCD_SIGNAL_DUMPER_INIT("/tmp/openair_dump_UE.vcd"); + } + + cpuf=get_cpu_freq_GHz(); + +#if defined(ENABLE_ITTI) + + log_set_instance_type (LOG_INSTANCE_UE); + + + printf("ITTI init\n"); + itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info, messages_definition_xml, itti_dump_file); + + // initialize mscgen log after ITTI + MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX); +#endif + + if (opt_type != OPT_NONE) { + radio_type_t radio_type; + + if (frame_parms[0]->frame_type == FDD) + radio_type = RADIO_TYPE_FDD; + else + radio_type = RADIO_TYPE_TDD; + + if (init_opt(in_path, in_ip, NULL, radio_type) == -1) + LOG_E(OPT,"failed to run OPT \n"); + } + +#ifdef PDCP_USE_NETLINK + printf("PDCP netlink\n"); + netlink_init(); +#if defined(PDCP_USE_NETLINK_QUEUES) + pdcp_netlink_init(); +#endif +#endif + +#if !defined(ENABLE_ITTI) + // to make a graceful exit when ctrl-c is pressed + signal(SIGSEGV, signal_handler); + signal(SIGINT, signal_handler); +#endif + + + check_clock(); + +#ifndef PACKAGE_VERSION +# define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL" +#endif + + LOG_I(HW, "Version: %s\n", PACKAGE_VERSION); + + // init the parameters + for (CC_id=0; CC_idnb_antennas_tx = nb_antenna_tx; + frame_parms[CC_id]->nb_antennas_rx = nb_antenna_rx; + frame_parms[CC_id]->nb_antenna_ports_eNB = 1; //initial value overwritten by initial sync later + } + + + + printf("Before CC \n"); + + for (CC_id=0; CC_idmac_enabled = 0; + else + UE[CC_id]->mac_enabled = 1; + + if (UE[CC_id]->mac_enabled == 0) { //set default UL parameters for testing mode + for (i=0; ipusch_config_dedicated[i].betaOffset_ACK_Index = beta_ACK; + UE[CC_id]->pusch_config_dedicated[i].betaOffset_RI_Index = beta_RI; + UE[CC_id]->pusch_config_dedicated[i].betaOffset_CQI_Index = beta_CQI; + + UE[CC_id]->scheduling_request_config[i].sr_PUCCH_ResourceIndex = 0; + UE[CC_id]->scheduling_request_config[i].sr_ConfigIndex = 7+(0%3); + UE[CC_id]->scheduling_request_config[i].dsr_TransMax = sr_n4; + } + } + + UE[CC_id]->UE_scan = UE_scan; + UE[CC_id]->UE_scan_carrier = UE_scan_carrier; + UE[CC_id]->mode = mode; + printf("UE[%d]->mode = %d\n",CC_id,mode); + + if (UE[CC_id]->mac_enabled == 1) { + UE[CC_id]->pdcch_vars[0][0]->crnti = 0x1234; + UE[CC_id]->pdcch_vars[1][0]->crnti = 0x1234; + }else { + UE[CC_id]->pdcch_vars[0][0]->crnti = 0x1235; + UE[CC_id]->pdcch_vars[1][0]->crnti = 0x1235; + } + UE[CC_id]->rx_total_gain_dB = (int)rx_gain[CC_id][0] + rx_gain_off; + UE[CC_id]->tx_power_max_dBm = tx_max_power[CC_id]; + + if (frame_parms[CC_id]->frame_type==FDD) { + UE[CC_id]->N_TA_offset = 0; + } + else { + if (frame_parms[CC_id]->N_RB_DL == 100) + UE[CC_id]->N_TA_offset = 624; + else if (frame_parms[CC_id]->N_RB_DL == 50) + UE[CC_id]->N_TA_offset = 624/2; + else if (frame_parms[CC_id]->N_RB_DL == 25) + UE[CC_id]->N_TA_offset = 624/4; + + } + init_openair0(); + } + + printf("Runtime table\n"); + fill_modeled_runtime_table(runtime_phy_rx,runtime_phy_tx); + cpuf=get_cpu_freq_GHz(); + + + +#ifndef DEADLINE_SCHEDULER + + printf("NO deadline scheduler\n"); + /* Currently we set affinity for UHD to CPU 0 for eNB/UE and only if number of CPUS >2 */ + + cpu_set_t cpuset; + int s; + char cpu_affinity[1024]; + CPU_ZERO(&cpuset); +#ifdef CPU_AFFINITY + if (get_nprocs() > 2) { + CPU_SET(0, &cpuset); + s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) { + perror( "pthread_setaffinity_np"); + exit_fun("Error setting processor affinity"); + } + LOG_I(HW, "Setting the affinity of main function to CPU 0, for device library to use CPU 0 only!\n"); + } +#endif + + /* Check the actual affinity mask assigned to the thread */ + s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) { + perror( "pthread_getaffinity_np"); + exit_fun("Error getting processor affinity "); + } + memset(cpu_affinity, 0 , sizeof(cpu_affinity)); + for (int j = 0; j < CPU_SETSIZE; j++) { + if (CPU_ISSET(j, &cpuset)) { + char temp[1024]; + sprintf(temp, " CPU_%d ", j); + strcat(cpu_affinity, temp); + } + } + LOG_I(HW, "CPU Affinity of main() function is... %s\n", cpu_affinity); +#endif + + + + +#if defined(ENABLE_ITTI) + if (create_tasks_ue(1) < 0) { + printf("cannot create ITTI tasks\n"); + exit(-1); // need a softer mode + } + printf("ITTI tasks created\n"); +#endif + + // init UE_PF_PO and mutex lock + pthread_mutex_init(&ue_pf_po_mutex, NULL); + memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*NUMBER_OF_UE_MAX*MAX_NUM_CCs); + + mlockall(MCL_CURRENT | MCL_FUTURE); + + pthread_cond_init(&sync_cond,NULL); + pthread_mutex_init(&sync_mutex, NULL); + +#ifdef XFORMS + int UE_id; + + printf("XFORMS\n"); + + if (do_forms==1) { + fl_initialize (&argc, argv, NULL, 0, 0); + + form_stats = create_form_stats_form(); + fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats"); + UE_id = 0; + form_ue[UE_id] = create_lte_phy_scope_ue(); + sprintf (title, "LTE DL SCOPE UE"); + fl_show_form (form_ue[UE_id]->lte_phy_scope_ue, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); + + /* + if (openair_daq_vars.use_ia_receiver) { + fl_set_button(form_ue[UE_id]->button_0,1); + fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver ON"); + } else { + fl_set_button(form_ue[UE_id]->button_0,0); + fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF"); + }*/ + fl_set_button(form_ue[UE_id]->button_0,0); + fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF"); + ret = pthread_create(&forms_thread, NULL, scope_thread, NULL); + + if (ret == 0) + pthread_setname_np( forms_thread, "xforms" ); + + printf("Scope thread created, ret=%d\n",ret); + } + +#endif + + rt_sleep_ns(10*100000000ULL); + + // start the main threads + int eMBMS_active = 0; + init_UE(1,eMBMS_active,uecap_xer_in,0); + + if (phy_test==0) { + printf("Filling UE band info\n"); + fill_ue_band_info(); + dl_phy_sync_success (0, 0, 0, 1); + } + + number_of_cards = 1; + for(CC_id=0; CC_idrf_map.card=0; + PHY_vars_UE_g[0][CC_id]->rf_map.chain=CC_id+chain_offset; + } + + + + // connect the TX/RX buffers + + for (CC_id=0; CC_idhw_timing_advance = timing_advance; +#else + UE[CC_id]->hw_timing_advance = 160; +#endif + } + if (setup_ue_buffers(UE,&openair0_cfg[0])!=0) { + printf("Error setting up eNB buffer\n"); + exit(-1); + } + + + + if (input_fd) { + printf("Reading in from file to antenna buffer %d\n",0); + if (fread(UE[0]->common_vars.rxdata[0], + sizeof(int32_t), + frame_parms[0]->samples_per_tti*10, + input_fd) != frame_parms[0]->samples_per_tti*10) + printf("error reading from file\n"); + } + //p_exmimo_config->framing.tdd_config = TXRXSWITCH_TESTRX; + + printf("Sending sync to all threads\n"); + + pthread_mutex_lock(&sync_mutex); + sync_var=0; + pthread_cond_broadcast(&sync_cond); + pthread_mutex_unlock(&sync_mutex); + printf("About to call end_configmodule() from %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); + end_configmodule(); + printf("Called end_configmodule() from %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); + + // wait for end of program + printf("TYPE TO TERMINATE\n"); + //getchar(); + +#if defined(ENABLE_ITTI) + printf("Entering ITTI signals handler\n"); + itti_wait_tasks_end(); + printf("Returned from ITTI signal handler\n"); + oai_exit=1; + printf("oai_exit=%d\n",oai_exit); +#else + + while (oai_exit==0) + rt_sleep_ns(100000000ULL); + printf("Terminating application - oai_exit=%d\n",oai_exit); + +#endif + + // stop threads +#ifdef XFORMS + printf("waiting for XFORMS thread\n"); + + if (do_forms==1) { + pthread_join(forms_thread,&status); + fl_hide_form(form_stats->stats_form); + fl_free_form(form_stats->stats_form); + fl_hide_form(form_ue[0]->lte_phy_scope_ue); + fl_free_form(form_ue[0]->lte_phy_scope_ue); + } + +#endif + + printf("stopping MODEM threads\n"); + + pthread_cond_destroy(&sync_cond); + pthread_mutex_destroy(&sync_mutex); + + pthread_mutex_destroy(&ue_pf_po_mutex); + + // *** Handle per CC_id openair0 + if (PHY_vars_UE_g[0][0]->rfdevice.trx_end_func) + PHY_vars_UE_g[0][0]->rfdevice.trx_end_func(&PHY_vars_UE_g[0][0]->rfdevice); + + if (ouput_vcd) + VCD_SIGNAL_DUMPER_CLOSE(); + + if (opt_enabled == 1) + terminate_opt(); + + logClean(); + + printf("Bye.\n"); + + return 0; +} From da50d68b060d16401d8ce604f2c09335dc063db1 Mon Sep 17 00:00:00 2001 From: oai Date: Thu, 8 Mar 2018 15:56:51 +0100 Subject: [PATCH 281/284] more NB-IoT integration --- cmake_targets/CMakeLists.txt | 17 +- cmake_targets/tools/fix_asn1 | 1 + .../SystemInformation-NB-r13-IEs.h.diff | 47 + common/ran_context.h | 6 +- nfapi/oai_integration/nfapi_pnf.h | 2 +- openair1/PHY/CODING/defs_NB_IoT.h | 275 ++++ openair1/PHY/INIT/defs_NB_IoT.h | 77 + openair1/PHY/LTE_REFSIG/defs_NB_IoT.h | 60 + openair1/PHY/LTE_TRANSPORT/dci_NB_IoT.h | 292 ++++ openair1/PHY/LTE_TRANSPORT/defs_NB_IoT.h | 787 +++++++++ .../PHY/LTE_TRANSPORT/dlsch_llr_computation.c | 2 +- openair1/PHY/LTE_TRANSPORT/proto_NB_IoT.h | 362 +++++ openair1/PHY/LTE_TRANSPORT/uci_NB_IoT.h | 324 ++++ openair1/PHY/TOOLS/lte_phy_scope.c | 4 +- openair1/PHY/defs_L1_NB_IoT.h | 1031 ++++++++++++ openair1/PHY/impl_defs_lte_NB_IoT.h | 813 ++++++++++ openair1/PHY/impl_defs_top_NB_IoT.h | 541 +++++++ openair1/PHY/types_NB_IoT.h | 32 + openair1/SCHED/prach_procedures.c | 1 + openair2/COMMON/platform_constants.h | 4 + openair2/COMMON/rrc_messages_def.h | 1 + openair2/COMMON/rrc_messages_types.h | 73 + openair2/COMMON/tasks_def.h | 4 + .../{nbiot_config.c => NB_IoT_config.c} | 13 +- .../{nbiot_config.h => NB_IoT_config.h} | 0 openair2/ENB_APP/NB_IoT_interface.c | 58 + openair2/ENB_APP/NB_IoT_interface.h | 50 + .../{nbiot_paramdef.h => NB_IoT_paramdef.h} | 0 openair2/LAYER2/MAC/config_NB_IoT.h | 301 ++++ openair2/LAYER2/MAC/defs_NB_IoT.h | 543 +++++++ openair2/LAYER2/MAC/proto_NB_IoT.h | 198 +++ openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 40 +- openair2/PHY_INTERFACE/IF_Module_NB_IoT.h | 215 +++ openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c | 1417 +++++++++++++++++ openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h | 293 ++++ openair2/RRC/LITE/defs_NB_IoT.h | 570 +++++++ openair2/RRC/LITE/extern_NB_IoT.h | 63 + openair2/RRC/LITE/proto.h | 2 + openair2/RRC/LITE/proto_NB_IoT.h | 260 +++ openair2/RRC/LITE/rrc_types_NB_IoT.h | 64 + openair3/GTPV1-U/gtpv1u_eNB.c | 3 +- targets/COMMON/openairinterface5g_limits.h | 1 - targets/RT/USER/lte-softmodem.c | 10 +- 43 files changed, 8800 insertions(+), 57 deletions(-) create mode 100644 cmake_targets/tools/fix_asn1.data/RRC.rel14/SystemInformation-NB-r13-IEs.h.diff create mode 100644 openair1/PHY/CODING/defs_NB_IoT.h create mode 100644 openair1/PHY/INIT/defs_NB_IoT.h create mode 100644 openair1/PHY/LTE_REFSIG/defs_NB_IoT.h create mode 100644 openair1/PHY/LTE_TRANSPORT/dci_NB_IoT.h create mode 100644 openair1/PHY/LTE_TRANSPORT/defs_NB_IoT.h create mode 100644 openair1/PHY/LTE_TRANSPORT/proto_NB_IoT.h create mode 100644 openair1/PHY/LTE_TRANSPORT/uci_NB_IoT.h create mode 100644 openair1/PHY/defs_L1_NB_IoT.h create mode 100644 openair1/PHY/impl_defs_lte_NB_IoT.h create mode 100644 openair1/PHY/impl_defs_top_NB_IoT.h create mode 100644 openair1/PHY/types_NB_IoT.h rename openair2/ENB_APP/{nbiot_config.c => NB_IoT_config.c} (98%) rename openair2/ENB_APP/{nbiot_config.h => NB_IoT_config.h} (100%) create mode 100644 openair2/ENB_APP/NB_IoT_interface.c create mode 100644 openair2/ENB_APP/NB_IoT_interface.h rename openair2/ENB_APP/{nbiot_paramdef.h => NB_IoT_paramdef.h} (100%) create mode 100644 openair2/LAYER2/MAC/config_NB_IoT.h create mode 100644 openair2/LAYER2/MAC/defs_NB_IoT.h create mode 100644 openair2/LAYER2/MAC/proto_NB_IoT.h create mode 100644 openair2/PHY_INTERFACE/IF_Module_NB_IoT.h create mode 100644 openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c create mode 100644 openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h create mode 100644 openair2/RRC/LITE/defs_NB_IoT.h create mode 100644 openair2/RRC/LITE/extern_NB_IoT.h create mode 100644 openair2/RRC/LITE/proto_NB_IoT.h create mode 100644 openair2/RRC/LITE/rrc_types_NB_IoT.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index a0ee33dc78..a22babc33f 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -314,7 +314,8 @@ file(GLOB rrc_h ${RRC_FULL_DIR}/*.h) set(rrc_h ${rrc_h} ${RRC_FULL_DIR}/asn1_constants.h) set_source_files_properties(${rrc_source} PROPERTIES COMPILE_FLAGS -w) # suppress warnings from generated code add_library(RRC_LIB ${rrc_h} ${rrc_source} - ${OPENAIR2_DIR}/RRC/LITE/MESSAGES/asn1_msg.c) + ${OPENAIR2_DIR}/RRC/LITE/MESSAGES/asn1_msg.c + ${OPENAIR2_DIR}/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c) include_directories ("${RRC_FULL_DIR}") # add the command to generate the source code @@ -1717,6 +1718,17 @@ if(NAS_UE) endif() +# nbiot +add_definitions("-DNUMBER_OF_UE_MAX_NB_IoT=16") +set (NBIOT_SOURCES + ${OPENAIR2_DIR}/ENB_APP/NB_IoT_config.c +) +add_library(NB_IoT MODULE ${NBIOT_SOURCES} ) + +# shared library loader +set (SHLIB_LOADER_SOURCES + ${OPENAIR_DIR}/common/utils/load_module_shlib.c +) # Make lfds as a own source code (even if it is a outside library) # For better intergration with compilation flags & structure of cmake @@ -1789,6 +1801,7 @@ include_directories("${NFAPI_DIR}/nfapi/inc") include_directories("${NFAPI_DIR}/sim_common/inc") include_directories("${NFAPI_DIR}/pnf_sim/inc") + # System packages that are required # We use either the cmake buildin, in ubuntu are in: /usr/share/cmake*/Modules/ # or cmake provide a generic interface to pkg-config that widely used @@ -1947,6 +1960,7 @@ add_executable(lte-softmodem ${OPENAIR_TARGETS}/RT/USER/lte-enb.c ${OPENAIR_TARGETS}/RT/USER/lte-ru.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c + ${OPENAIR2_DIR}/ENB_APP/NB_IoT_interface.c ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c ${OPENAIR_TARGETS}/COMMON/create_tasks.c @@ -1985,6 +1999,7 @@ add_executable(lte-softmodem-nos1 ${OPENAIR_TARGETS}/RT/USER/lte-enb.c ${OPENAIR_TARGETS}/RT/USER/lte-ru.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c + ${OPENAIR2_DIR}/ENB_APP/NB_IoT_interface.c ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c ${OPENAIR_TARGETS}/COMMON/create_tasks.c diff --git a/cmake_targets/tools/fix_asn1 b/cmake_targets/tools/fix_asn1 index 5cdab5ffd8..fe819c2716 100755 --- a/cmake_targets/tools/fix_asn1 +++ b/cmake_targets/tools/fix_asn1 @@ -5,6 +5,7 @@ RRC_Rel14=( "SystemInformation-r8-IEs.h" 4df485c5ddf2540eca271876cdc512caa19b0890 "fix_asn1.data/RRC.rel14/SystemInformation-r8-IEs.h.diff" + "SystemInformation-NB-r13-IEs.h" 6d91332d5c39205819b06e5e36efe62ff8e5b33b "fix_asn1.data/RRC.rel14/SystemInformation-NB-r13-IEs.h.diff" ) RRC_Rel10=( diff --git a/cmake_targets/tools/fix_asn1.data/RRC.rel14/SystemInformation-NB-r13-IEs.h.diff b/cmake_targets/tools/fix_asn1.data/RRC.rel14/SystemInformation-NB-r13-IEs.h.diff new file mode 100644 index 0000000000..37ac4cd858 --- /dev/null +++ b/cmake_targets/tools/fix_asn1.data/RRC.rel14/SystemInformation-NB-r13-IEs.h.diff @@ -0,0 +1,47 @@ +48a49,70 +> struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member { +> SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member_PR present; +> union SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member_u { +> SystemInformationBlockType2_NB_r13_t sib2_r13; +> SystemInformationBlockType3_NB_r13_t sib3_r13; +> SystemInformationBlockType4_NB_r13_t sib4_r13; +> SystemInformationBlockType5_NB_r13_t sib5_r13; +> SystemInformationBlockType14_NB_r13_t sib14_r13; +> SystemInformationBlockType16_NB_r13_t sib16_r13; +> /* +> * This type is extensible, +> * possible extensions are below. +> */ +> SystemInformationBlockType15_NB_r14_t sib15_v1430; +> SystemInformationBlockType20_NB_r14_t sib20_v1430; +> SystemInformationBlockType22_NB_r14_t sib22_v1430; +> } choice; +> +> /* Context for parsing across buffer boundaries */ +> asn_struct_ctx_t _asn_ctx; +> }; +> +52,72c74 +< A_SEQUENCE_OF(struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member { +< SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member_PR present; +< union SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member_u { +< SystemInformationBlockType2_NB_r13_t sib2_r13; +< SystemInformationBlockType3_NB_r13_t sib3_r13; +< SystemInformationBlockType4_NB_r13_t sib4_r13; +< SystemInformationBlockType5_NB_r13_t sib5_r13; +< SystemInformationBlockType14_NB_r13_t sib14_r13; +< SystemInformationBlockType16_NB_r13_t sib16_r13; +< /* +< * This type is extensible, +< * possible extensions are below. +< */ +< SystemInformationBlockType15_NB_r14_t sib15_v1430; +< SystemInformationBlockType20_NB_r14_t sib20_v1430; +< SystemInformationBlockType22_NB_r14_t sib22_v1430; +< } choice; +< +< /* Context for parsing across buffer boundaries */ +< asn_struct_ctx_t _asn_ctx; +< } ) list; +--- +> A_SEQUENCE_OF(struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member) list; diff --git a/common/ran_context.h b/common/ran_context.h index c521c4f376..18b309d268 100644 --- a/common/ran_context.h +++ b/common/ran_context.h @@ -48,6 +48,8 @@ #include "NwGtpv1uPrivate.h" #include "gtpv1u_eNB_defs.h" +#include "PHY/defs_L1_NB_IoT.h" +#include "RRC/LITE/defs_NB_IoT.h" typedef struct { /// RAN context config file name char *config_file_name; @@ -76,7 +78,7 @@ typedef struct { /// eNB context variables struct PHY_VARS_eNB_s ***eNB; /// NB_IoT L1 context variables - //struct PHY_VARS_eNB_NB_IoT_s **L1_NB_IoT; + struct PHY_VARS_eNB_NB_IoT_s **L1_NB_IoT; /// RRC context variables struct eNB_RRC_INST_s **rrc; /// NB_IoT RRC context variables @@ -84,7 +86,7 @@ typedef struct { /// MAC context variables struct eNB_MAC_INST_s **mac; /// NB_IoT MAC context variables - //struct eNB_MAC_INST_NB_IoT_s **nb_iot_mac; + struct eNB_MAC_INST_NB_IoT_s **nb_iot_mac; /// GTPu descriptor gtpv1u_data_t *gtpv1u_data_g; /// RU descriptors. These describe what each radio unit is supposed to do and contain the necessary functions for fronthaul interfaces diff --git a/nfapi/oai_integration/nfapi_pnf.h b/nfapi/oai_integration/nfapi_pnf.h index 592d4877af..e213d785f1 100644 --- a/nfapi/oai_integration/nfapi_pnf.h +++ b/nfapi/oai_integration/nfapi_pnf.h @@ -21,7 +21,7 @@ #if !defined(NFAPI_PNF_H__) #define NFAPI_PNF_H__ - +int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind); void configure_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port); #endif diff --git a/openair1/PHY/CODING/defs_NB_IoT.h b/openair1/PHY/CODING/defs_NB_IoT.h new file mode 100644 index 0000000000..17670ec8bc --- /dev/null +++ b/openair1/PHY/CODING/defs_NB_IoT.h @@ -0,0 +1,275 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/* file: PHY/CODING/defs_NB_IoT.h + purpose: Top-level definitions, data types and function prototypes for openairinterface coding blocks for NB-IoT + author: matthieu.kanj@b-com.com, raymond.knopp@eurecom.fr, michele.paffetti@studio.unibo.it + date: 29.06.2017 +*/ + +#ifndef OPENAIR1_PHY_CODING_DEFS_NB_IOT_H_ +#define OPENAIR1_PHY_CODING_DEFS_NB_IOT_H_ + +#include // for uint8/16/32_t + +/* check if this ifndef is required for NB-IoT ?! +//#ifndef NO_OPENAIR1 +//#include "PHY/defs_NB_IoT.h" +//#else +//#include "PHY/TOOLS/time_meas.h" +//#endif +*/ + +#define CRC24_A_NB_IoT 0 +#define CRC24_B_NB_IoT 1 +#define CRC16_NB_IoT 2 +#define CRC8_NB_IoT 3 + +//#define MAX_TURBO_ITERATIONS_MBSFN 8 // no MBSFN +#define MAX_TURBO_ITERATIONS_NB_IoT 4 + +#define LTE_NULL_NB_IoT 2 // defined also in PHY/LTE_TRANSPORT/defs_NB_IoT.h + +/** \fn uint32_t sub_block_interleaving_cc(uint32_t D, uint8_t *d,uint8_t *w) +\brief This is the subblock interleaving algorithm for convolutionally coded blocks from 36-212 (Release 13.4, 2017). +This function takes the d-sequence and generates the w-sequence. The nu-sequence from 36-212 is implicit. +\param D Number of input bits +\param d Pointer to input (d-sequence, convolutional code output) +\param w Pointer to output (w-sequence, interleaver output) +\returns Interleaving matrix cardinality (\f$K_{\pi}\f$ from 36-212) +*/ +uint32_t sub_block_interleaving_cc_NB_IoT(uint32_t D, uint8_t *d,uint8_t *w); + +/** +\brief This is the NB-IoT rate matching algorithm for Convolutionally-coded channels (e.g. BCH,DCI,UCI). It is taken directly from 36-212 (Rel 8 8.6, 2009-03), pages 16-18 ) +\param RCC R^CC_subblock from subblock interleaver (number of rows in interleaving matrix) for up to 8 segments +\param E Number of coded channel bits +\param w This is a pointer to the w-sequence (second interleaver output) +\param e This is a pointer to the e-sequence (rate matching output, channel input/output bits) +\returns \f$E\f$, the number of coded bits per segment */ + +uint32_t lte_rate_matching_cc_NB_IoT(uint32_t RCC, // RRC = 2 + uint16_t E, // E = 1600 + uint8_t *w, // length + uint8_t *e); // length 1600 + +/** \fn void ccodelte_encode(int32_t numbits,uint8_t add_crc, uint8_t *inPtr,uint8_t *outPtr,uint16_t rnti) +\brief This function implements the LTE convolutional code of rate 1/3 + with a constraint length of 7 bits. The inputs are bit packed in octets +(from MSB to LSB). Trellis tail-biting is included here. +@param numbits Number of bits to encode +@param add_crc crc to be appended (8 bits) if add_crc = 1 +@param inPtr Pointer to input buffer +@param outPtr Pointer to output buffer +@param rnti RNTI for CRC scrambling +*/ + +void ccode_encode_NB_IoT (int32_t numbits, + uint8_t add_crc, + uint8_t *inPtr, + uint8_t *outPtr, + uint16_t rnti); + +/*!\fn void ccodelte_init(void) +\brief This function initializes the generator polynomials for an LTE convolutional code.*/ +void ccodelte_init_NB_IoT(void); + +/*!\fn void crcTableInit(void) +\brief This function initializes the different crc tables.*/ +void crcTableInit_NB_IoT (void); + + +/*!\fn uint32_t crc24a(uint8_t *inPtr, int32_t bitlen) +\brief This computes a 24-bit crc ('a' variant for overall transport block) +based on 3GPP UMTS/LTE specifications. +@param inPtr Pointer to input byte stream +@param bitlen length of inputs in bits +*/ +uint32_t crc24a_NB_IoT (uint8_t *inPtr, int32_t bitlen); + +/*!\fn uint32_t crc24b(uint8_t *inPtr, int32_t bitlen) +\brief This computes a 24-bit crc ('b' variant for transport-block segments) +based on 3GPP UMTS/LTE specifications. +@param inPtr Pointer to input byte stream +@param bitlen length of inputs in bits +*/ +uint32_t crc24b_NB_IoT (uint8_t *inPtr, int32_t bitlen); + +/*!\fn uint32_t crc16(uint8_t *inPtr, int32_t bitlen) +\brief This computes a 16-bit crc based on 3GPP UMTS specifications. +@param inPtr Pointer to input byte stream +@param bitlen length of inputs in bits*/ +uint32_t crc16_NB_IoT (uint8_t *inPtr, int32_t bitlen); + +/*!\fn uint32_t crc8(uint8_t *inPtr, int32_t bitlen) +\brief This computes a 8-bit crc based on 3GPP UMTS specifications. +@param inPtr Pointer to input byte stream +@param bitlen length of inputs in bits*/ +uint32_t crc8_NB_IoT (uint8_t *inPtr, int32_t bitlen); + + + + + + +uint32_t crcbit_NB_IoT (uint8_t * , + int32_t, + uint32_t); + + +/*!\fn void phy_viterbi_lte_sse2(int8_t *y, uint8_t *decoded_bytes, uint16_t n) +\brief This routine performs a SIMD optmized Viterbi decoder for the LTE 64-state tail-biting convolutional code. +@param y Pointer to soft input (coded on 8-bits but should be limited to 4-bit precision to avoid overflow) +@param decoded_bytes Pointer to decoded output +@param n Length of input/trellis depth in bits*/ +//void phy_viterbi_lte_sse2(int8_t *y,uint8_t *decoded_bytes,uint16_t n); +void phy_viterbi_lte_sse2_NB_IoT(int8_t *y,uint8_t *decoded_bytes,uint16_t n); + +/** \fn void sub_block_deinterleaving_cc(uint32_t D, int8_t *d,int8_t *w) +\brief This is the subblock deinterleaving algorithm for convolutionally-coded data from 36-212 (Release 8, 8.6 2009-03), pages 15-16. +This function takes the w-sequence and generates the d-sequence. The nu-sequence from 36-212 is implicit. +\param D Number of input bits +\param d Pointer to output (d-sequence, turbo code output) +\param w Pointer to input (w-sequence, interleaver output) +*/ +void sub_block_deinterleaving_cc_NB_IoT(uint32_t D,int8_t *d,int8_t *w); + + +/* +\brief This is the LTE rate matching algorithm for Convolutionally-coded channels (e.g. BCH,DCI,UCI). It is taken directly from 36-212 (Rel 8 8.6, 2009-03), pages 16-18 ) +\param RCC R^CC_subblock from subblock interleaver (number of rows in interleaving matrix) +\param E This the number of coded bits allocated for channel +\param w This is a pointer to the soft w-sequence (second interleaver output) with soft-combined outputs from successive HARQ rounds +\param dummy_w This is the first row of the interleaver matrix for identifying/discarding the "LTE-NULL" positions +\param soft_input This is a pointer to the soft channel output +\returns \f$E\f$, the number of coded bits per segment +*/ +void lte_rate_matching_cc_rx_NB_IoT(uint32_t RCC, + uint16_t E, + int8_t *w, + uint8_t *dummy_w, + int8_t *soft_input); + +/** \fn generate_dummy_w_cc(uint32_t D, uint8_t *w) +\brief This function generates a dummy interleaved sequence (first row) for receiver (convolutionally-coded data), in order to identify the NULL positions used to make the matrix complete. +\param D Number of systematic bits plus 4 (plus 4 for termination) +\param w This is the dummy sequence (first row), it will contain zeros and at most 31 "LTE_NULL" values +\returns Interleaving matrix cardinality (\f$K_{\pi}\f$ from 36-212) +*/ +uint32_t generate_dummy_w_cc_NB_IoT(uint32_t D, uint8_t *w); + +/** \fn lte_segmentation(uint8_t *input_buffer, + uint8_t **output_buffers, + uint32_t B, + uint32_t *C, + uint32_t *Cplus, + uint32_t *Cminus, + uint32_t *Kplus, + uint32_t *Kminus, + uint32_t *F) +\brief This function implements the LTE transport block segmentation algorithm from 36-212, V8.6 2009-03. +@param input_buffer +@param output_buffers +@param B +@param C +@param Cplus +@param Cminus +@param Kplus +@param Kminus +@param F +*/ +int32_t lte_segmentation_NB_IoT(uint8_t *input_buffer, + uint8_t **output_buffers, + uint32_t B, + uint32_t *C, + uint32_t *Cplus, + uint32_t *Cminus, + uint32_t *Kplus, + uint32_t *Kminus, + uint32_t *F); + +/** \fn void sub_block_deinterleaving_turbo(uint32_t D, int16_t *d,int16_t *w) +\brief This is the subblock deinterleaving algorithm from 36-212 (Release 8, 8.6 2009-03), pages 15-16. +This function takes the w-sequence and generates the d-sequence. The nu-sequence from 36-212 is implicit. +\param D Number of systematic bits plus 4 (plus 4 for termination) +\param d Pointer to output (d-sequence, turbo code output) +\param w Pointer to input (w-sequence, interleaver output) +*/ +//*****************void sub_block_deinterleaving_turbo(uint32_t D, int16_t *d,int16_t *w); + +/** +\brief This is the LTE rate matching algorithm for Turbo-coded channels (e.g. DLSCH,ULSCH). It is taken directly from 36-212 (Rel 8 8.6, 2009-03), pages 16-18 ) +\param RTC R^TC_subblock from subblock interleaver (number of rows in interleaving matrix) +\param G This the number of coded transport bits allocated in sub-frame +\param w This is a pointer to the soft w-sequence (second interleaver output) with soft-combined outputs from successive HARQ rounds +\param dummy_w This is the first row of the interleaver matrix for identifying/discarding the "LTE-NULL" positions +\param soft_input This is a pointer to the soft channel output +\param C Number of segments (codewords) in the sub-frame +\param Nsoft Total number of soft bits (from UE capabilities in 36-306) +\param Mdlharq Number of HARQ rounds +\param Kmimo MIMO capability for this DLSCH (0 = no MIMO) +\param rvidx round index (0-3) +\param clear 1 means clear soft buffer (start of HARQ round) +\param Qm modulation order (2,4,6) +\param Nl number of layers (1,2) +\param r segment number +\param E_out the number of coded bits per segment +\returns 0 on success, -1 on failure +*/ + +// int lte_rate_matching_turbo_rx(uint32_t RTC, +// uint32_t G, +// int16_t *w, +// uint8_t *dummy_w, +// int16_t *soft_input, +// uint8_t C, +// uint32_t Nsoft, +// uint8_t Mdlharq, +// uint8_t Kmimo, +// uint8_t rvidx, +// uint8_t clear, +// uint8_t Qm, +// uint8_t Nl, +// uint8_t r, +// uint32_t *E_out); + +// uint32_t lte_rate_matching_turbo_rx_abs(uint32_t RTC, +// uint32_t G, +// double *w, +// uint8_t *dummy_w, +// double *soft_input, +// uint8_t C, +// uint32_t Nsoft, +// uint8_t Mdlharq, +// uint8_t Kmimo, +// uint8_t rvidx, +// uint8_t clear, +// uint8_t Qm, +// uint8_t Nl, +// uint8_t r, +// uint32_t *E_out); + +void ccode_encode_npdsch_NB_IoT (int32_t numbits, + uint8_t *inPtr, + uint8_t *outPtr, + uint32_t crc); + +#endif /* OPENAIR1_PHY_CODING_DEFS_NB_IOT_H_ */ diff --git a/openair1/PHY/INIT/defs_NB_IoT.h b/openair1/PHY/INIT/defs_NB_IoT.h new file mode 100644 index 0000000000..e8ead21780 --- /dev/null +++ b/openair1/PHY/INIT/defs_NB_IoT.h @@ -0,0 +1,77 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + + +#ifndef __INIT_DEFS_NB_IOT__H__ +#define __INIT_DEFS_NB_IOT__H__ + +//#include "PHY/defs_NB_IoT.h" +#include "openair2/PHY_INTERFACE/IF_Module_NB_IoT.h" +#include "nfapi_interface.h" + +//#include "SystemInformationBlockType2.h" +//#include "RadioResourceConfigCommonSIB.h" +//#include "RadioResourceConfigDedicated.h" +//#include "TDD-Config.h" +//#include "MBSFN-SubframeConfigList.h" +//#include "MobilityControlInfo.h" +//#if defined(Rel10) || defined(Rel14) +//#include "SCellToAddMod-r10.h" +//#endif + +/*brief Configure LTE_DL_FRAME_PARMS with components derived after initial synchronization (MIB-NB decoding + primary/secondary synch).*/ +void phy_config_mib_eNB_NB_IoT(int Mod_id, + int eutra_band, + int Nid_cell, + int Ncp, + int Ncp_UL, + int p_eNB, + uint16_t EARFCN, + uint16_t prb_index, // NB_IoT_RB_ID, + uint16_t operating_mode, + uint16_t control_region_size, + uint16_t eutra_NumCRS_ports); + +/*NB_phy_config_sib1_eNB is not needed since NB-IoT use only FDD mode*/ + +/*brief Configure LTE_DL_FRAME_PARMS with components of SIB2-NB (at eNB).*/ + +//void NB_phy_config_sib2_eNB(module_id_t Mod_id, +// int CC_id, +// RadioResourceConfigCommonSIB_NB_r13_t *radioResourceConfigCommon +// ); + +void phy_config_sib2_eNB_NB_IoT(uint8_t Mod_id, + nfapi_nb_iot_config_t *config, + nfapi_rf_config_t *rf_config, + nfapi_uplink_reference_signal_config_t* ul_nrs_config, + extra_phyConfig_t* extra_phy_parms); + +void phy_config_dedicated_eNB_NB_IoT(module_id_t Mod_id, + rnti_t rnti, + extra_phyConfig_t* extra_phy_parms); + +// void phy_init_lte_top_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms); +void phy_init_nb_iot_eNB(PHY_VARS_eNB_NB_IoT *phyvar); +int l1_north_init_NB_IoT(void); + +#endif + diff --git a/openair1/PHY/LTE_REFSIG/defs_NB_IoT.h b/openair1/PHY/LTE_REFSIG/defs_NB_IoT.h new file mode 100644 index 0000000000..8f0b7b8c4c --- /dev/null +++ b/openair1/PHY/LTE_REFSIG/defs_NB_IoT.h @@ -0,0 +1,60 @@ +/******************************************************************************* + + *******************************************************************************/ +/*! \file PHY/LTE_REFSIG/defs_NB_IoT.c +* \function called by lte_dl_cell_spec_NB_IoT.c , TS 36-211, V13.4.0 2017-02 +* \author M. KANJ +* \date 2017 +* \version 0.0 +* \company bcom +* \email: matthieu.kanj@b-com.com +* \note +* \warning +*/ + +/* Definitions for NB_IoT Reference signals */ + +#ifndef __LTE_REFSIG_DEFS_NB_IOT__H__ +#define __LTE_REFSIG_DEFS_NB_IOT__H__ + +#include "PHY/defs_L1_NB_IoT.h" + +/** @ingroup _PHY_REF_SIG + * @{ +*/ +/*!\brief This function generates the LTE Gold sequence (36-211, Sec 7.2), specifically for DL reference signals. +@param frame_parms LTE DL Frame parameters +@param lte_gold_table pointer to table where sequences are stored +@param Nid_cell Cell Id for NB_IoT (to compute sequences for local and adjacent cells) */ + +void lte_gold_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms, + uint32_t lte_gold_table_NB_IoT[20][2][14], + uint16_t Nid_cell); + +/*! \brief This function generates the Narrowband reference signal (NRS) sequence (36-211, Sec 6.10.1.1) +@param phy_vars_eNB Pointer to eNB variables +@param output Output vector for OFDM symbol (Frequency Domain) +@param amp Q15 amplitude +@param Ns Slot number (0..19) +@param l symbol (0,1) - Note 1 means 3! +@param p antenna index +@param RB_IoT_ID the ID of the RB dedicated for NB_IoT +*/ +int lte_dl_cell_spec_NB_IoT(PHY_VARS_eNB_NB_IoT *phy_vars_eNB, + int32_t *output, + short amp, + unsigned char Ns, + unsigned char l, + unsigned char p, + unsigned short RB_IoT_ID); + + +unsigned int lte_gold_generic_NB_IoT(unsigned int *x1, + unsigned int *x2, + unsigned char reset); + +void generate_ul_ref_sigs_rx_NB_IoT(void); + +void free_ul_ref_sigs_NB_IoT(void); + +#endif diff --git a/openair1/PHY/LTE_TRANSPORT/dci_NB_IoT.h b/openair1/PHY/LTE_TRANSPORT/dci_NB_IoT.h new file mode 100644 index 0000000000..ea84f66de4 --- /dev/null +++ b/openair1/PHY/LTE_TRANSPORT/dci_NB_IoT.h @@ -0,0 +1,292 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file PHY/LTE_TRANSPORT/dci.h +* \brief typedefs for LTE DCI structures from 36-212, V8.6 2009-03. Limited to 5 MHz formats for the moment.Current LTE compliance V8.6 2009-03. +* \author R. Knopp +* \date 2011 +* \version 0.1 +* \company Eurecom +* \email: knopp@eurecom.fr +* \note +* \warning +*/ +#ifndef __DCI_NB_IOT_H__ +#define __DCI_NB_IOT_H__ + +//#ifndef USER_MODE +//#include "PHY/types.h" +//#else +#include +//#endif + +typedef enum +{ + DCIFormatN0 = 0, + DCIFormatN1, + DCIFormatN1_RA,//is for initial RA procedure (semi-static information) so maybe is not needed + DCIFormatN1_RAR, + DCIFormatN2, + DCIFormatN2_Ind, + DCIFormatN2_Pag, +}DCI_format_NB_IoT_t; + +/// DCI Format Type 0 (180 kHz, 23 bits) +struct DCIFormatN0{ + /// type = 0 => DCI Format N0, type = 1 => DCI Format N1, 1 bits + uint8_t type; + /// Subcarrier indication, 6 bits + uint8_t scind; + /// Resourse Assignment (RU Assignment), 3 bits + uint8_t ResAssign; + /// Modulation and Coding Scheme, 4 bits + uint8_t mcs; + /// New Data Indicator, 1 bits + uint8_t ndi; + /// Scheduling Delay, 2 bits + uint8_t Scheddly; + /// Repetition Number, 3 bits + uint8_t RepNum; + /// Redundancy version for HARQ (only use 0 and 2), 1 bits + uint8_t rv; + /// DCI subframe repetition Number, 2 bits + uint8_t DCIRep; +}; + +typedef struct DCIFormatN0 DCIFormatN0_t; + +/// DCI Format Type N1 for User data +struct DCIFormatN1{ + /// type = 0 => DCI Format N0, type = 1 => DCI Format N1,1bits + uint8_t type; + //NPDCCH order indicator (set to 0), 1 bits + uint8_t orderIndicator; + // Scheduling Delay,3 bits + uint8_t Scheddly; + // Resourse Assignment (RU Assignment),3 bits + uint8_t ResAssign; + // Modulation and Coding Scheme,4 bits + uint8_t mcs; + // Repetition Number,4 bits + uint8_t RepNum; + // New Data Indicator,1 bits + uint8_t ndi; + // HARQ-ACK resource,4 bits + uint8_t HARQackRes; + // DCI subframe repetition Number,2 bits + uint8_t DCIRep; +}; + + +typedef struct DCIFormatN1 DCIFormatN1_t; + +/// DCI Format Type N1 for initial RA +struct DCIFormatN1_RA{ + /// type = 0 => DCI Format N0, type = 1 => DCI Format N1, 1 bits + uint8_t type; + //NPDCCH order indicator (set to 0),1 bits + uint8_t orderIndicator; + // Start number of NPRACH repetiiton, 2 bits + uint8_t Scheddly; + // Subcarrier indication of NPRACH, 6 bits + uint8_t scind; + // All the remainging bits, 13 bits + uint8_t remaingingBits; +}; + +typedef struct DCIFormatN1_RA DCIFormatN1_RA_t; + +/// DCI Format Type N1 for User data +struct DCIFormatN1_RAR{ + /// type = 0 => DCI Format N0, type = 1 => DCI Format N1,1bits + uint8_t type; + //NPDCCH order indicator (set to 0), 1 bits + uint8_t orderIndicator; + // Scheduling Delay,3 bits + uint8_t Scheddly; + // Resourse Assignment (RU Assignment),3 bits + uint8_t ResAssign; + // Modulation and Coding Scheme,4 bits + uint8_t mcs; + // Repetition Number,4 bits + uint8_t RepNum; + // New Data Indicator,1 bits,reserved in the RAR + uint8_t ndi; + // HARQ-ACK resource,4 bits,reserved in the RAR + uint8_t HARQackRes; + // DCI subframe repetition Number,2 bits + uint8_t DCIRep; +}; + +typedef struct DCIFormatN1_RAR DCIFormatN1_RAR_t; + +// DCI Format Type N2 for direct indication, 15 bits +struct DCIFormatN2_Ind{ + //Flag for paging(1)/direct indication(0), set to 0,1 bits + uint8_t type; + //Direct indication information, 8 bits + uint8_t directIndInf; + // Reserved information bits, 6 bits + uint8_t resInfoBits; +}; + +typedef struct DCIFormatN2_Ind DCIFormatN2_Ind_t; + +// DCI Format Type N2 for Paging, 15 bits +struct DCIFormatN2_Pag{ + //Flag for paging(1)/direct indication(0), set to 1,1 bits + uint8_t type; + // Resourse Assignment (RU Assignment), 3 bits + uint8_t ResAssign; + // Modulation and Coding Scheme, 4 bits + uint8_t mcs; + // Repetition Number, 4 bits + uint8_t RepNum; + // Reserved 3 bits + uint8_t DCIRep; +}; + +typedef struct DCIFormatN2_Pag DCIFormatN2_Pag_t; + +typedef union DCI_CONTENT { + // + DCIFormatN0_t DCIN0; + // + DCIFormatN1_t DCIN1; + // + DCIFormatN1_RA_t DCIN1_RA; + // + DCIFormatN1_RAR_t DCIN1_RAR; + // + DCIFormatN2_Ind_t DCIN2_Ind; + // + DCIFormatN2_Pag_t DCIN2_Pag; + + }DCI_CONTENT; + + /*Structure for packing*/ + + struct DCIN0{ + /// DCI subframe repetition Number, 2 bits + uint8_t DCIRep:2; + /// New Data Indicator, 1 bits + uint8_t ndi:1; + /// Repetition Number, 3 bits + uint8_t RepNum:3; + /// Redundancy version for HARQ (only use 0 and 2), 1 bits + uint8_t rv:1; + /// Modulation and Coding Scheme, 4 bits + uint8_t mcs:4; + /// Scheduling Delay, 2 bits + uint8_t Scheddly:2; + /// Resourse Assignment (RU Assignment), 3 bits + uint8_t ResAssign:3; + /// Subcarrier indication, 6 bits + uint8_t scind:6; + /// type = 0 => DCI Format N0, type = 1 => DCI Format N1, 1 bits + uint8_t type:1; + } __attribute__ ((__packed__)); + + typedef struct DCIN0 DCIN0_t; +#define sizeof_DCIN0_t 23 + +struct DCIN1_RAR{ + // DCI subframe repetition Number, 2 bits + uint8_t DCIRep:2; + // HARQ-ACK resource,4 bits + uint8_t HARQackRes:4; + // New Data Indicator,1 bits + uint8_t ndi:1; + // Repetition Number, 4 bits + uint8_t RepNum:4; + // Modulation and Coding Scheme, 4 bits + uint8_t mcs:4; + // Resourse Assignment (RU Assignment), 3 bits + uint8_t ResAssign:3; + // Scheduling Delay, 3 bits + uint8_t Scheddly:3; + //NPDCCH order indicator (set to 0),1 bits + uint8_t orderIndicator:1; + /// type = 0 => DCI Format N0, type = 1 => DCI Format N1, 1 bits + uint8_t type:1; + } __attribute__ ((__packed__)); + + typedef struct DCIN1_RAR DCIN1_RAR_t; +#define sizeof_DCIN1_RAR_t 23 + +struct DCIN1{ + // DCI subframe repetition Number, 2 bits + uint8_t DCIRep:2; + // HARQ-ACK resource,4 bits + uint8_t HARQackRes:4; + // New Data Indicator,1 bits + uint8_t ndi:1; + // Repetition Number, 4 bits + uint8_t RepNum:4; + // Modulation and Coding Scheme, 4 bits + uint8_t mcs:4; + // Resourse Assignment (RU Assignment), 3 bits + uint8_t ResAssign:3; + // Scheduling Delay, 3 bits + uint8_t Scheddly:3; + //NPDCCH order indicator (set to 0),1 bits + uint8_t orderIndicator:1; + /// type = 0 => DCI Format N0, type = 1 => DCI Format N1, 1 bits + uint8_t type:1; + } __attribute__ ((__packed__)); + + typedef struct DCIN1 DCIN1_t; +#define sizeof_DCIN1_t 23 + +// DCI Format Type N2 for direct indication, 15 bits +struct DCIN2_Ind{ + // Reserved information bits, 6 bits + uint8_t resInfoBits:6; + //Direct indication information, 8 bits + uint8_t directIndInf:8; + //Flag for paging(1)/direct indication(0), set to 0,1 bits + uint8_t type:1; +} __attribute__ ((__packed__));; + +typedef struct DCIN2_Ind DCIN2_Ind_t; +#define sizeof_DCIN2_Ind_t 15 + +// DCI Format Type N2 for Paging, 15 bits +struct DCIN2_Pag{ + // Reserved 3 bits + uint8_t DCIRep:3; + // Repetition Number, 4 bits + uint8_t RepNum:4; + // Modulation and Coding Scheme, 4 bits + uint8_t mcs:4; + // Resourse Assignment (RU Assignment), 3 bits + uint8_t ResAssign:3; + //Flag for paging(1)/direct indication(0), set to 1,1 bits + uint8_t type:1; +} __attribute__ ((__packed__));; + +typedef struct DCIN2_Pag DCIN2_Pag_t; + +#define sizeof_DCIN2_Pag_t 15 + +#define MAX_DCI_SIZE_BITS_NB_IoT 23 + +#endif diff --git a/openair1/PHY/LTE_TRANSPORT/defs_NB_IoT.h b/openair1/PHY/LTE_TRANSPORT/defs_NB_IoT.h new file mode 100644 index 0000000000..3574ba6740 --- /dev/null +++ b/openair1/PHY/LTE_TRANSPORT/defs_NB_IoT.h @@ -0,0 +1,787 @@ +/******************************************************************************* + + *******************************************************************************/ +/*! \file PHY/LTE_TRANSPORT/defs_NB_IoT.h +* \brief data structures for NPDSCH/NDLSCH/NPUSCH/NULSCH physical and transport channel descriptors (TX/RX) of NB-IoT +* \author M. KANJ +* \date 2017 +* \version 0.0 +* \company bcom +* \email: matthieu.kanj@b-com.com +* \note +* \warning +*/ +#ifndef __LTE_TRANSPORT_DEFS_NB_IOT__H__ +#define __LTE_TRANSPORT_DEFS_NB_IOT__H__ +////#include "PHY/defs.h" +//#include "PHY/defs_nb_iot.h" +#include "PHY/LTE_TRANSPORT/dci_NB_IoT.h" +#include "PHY/impl_defs_lte_NB_IoT.h" +#include "openair2/COMMON/platform_types.h" +//#include "dci.h" +#include "PHY/LTE_TRANSPORT/uci_NB_IoT.h" +//#include "dci.h" +//#include "uci.h" +//#ifndef STANDALONE_COMPILE +//#include "UTIL/LISTS/list.h" +//#endif + +//#include "dci_nb_iot.h" + +//#define MOD_TABLE_QPSK_OFFSET 1 +//#define MOD_TABLE_16QAM_OFFSET 5 +//#define MOD_TABLE_64QAM_OFFSET 21 +//#define MOD_TABLE_PSS_OFFSET 85 +// +//// structures below implement 36-211 and 36-212 +// +//#define NSOFT 1827072 +#define LTE_NULL_NB_IoT 2 +// +//// maximum of 3 segments before each coding block if data length exceeds 6144 bits. +// +#define MAX_NUM_DLSCH_SEGMENTS_NB_IoT 16 +//#define MAX_NUM_ULSCH_SEGMENTS MAX_NUM_DLSCH_SEGMENTS +//#define MAX_DLSCH_PAYLOAD_BYTES (MAX_NUM_DLSCH_SEGMENTS*768) +//#define MAX_ULSCH_PAYLOAD_BYTES (MAX_NUM_ULSCH_SEGMENTS*768) +// +//#define MAX_NUM_CHANNEL_BITS_NB_IOT (14*1200*6) // 14 symbols, 1200 REs, 12 bits/RE +//#define MAX_NUM_RE (14*1200) +// +//#if !defined(SI_RNTI) +//#define SI_RNTI (rnti_t)0xffff +//#endif +//#if !defined(M_RNTI) +//#define M_RNTI (rnti_t)0xfffd +//#endif +//#if !defined(P_RNTI) +//#define P_RNTI (rnti_t)0xfffe +//#endif +//#if !defined(CBA_RNTI) +//#define CBA_RNTI (rnti_t)0xfff4 +//#endif +//#if !defined(C_RNTI) +//#define C_RNTI (rnti_t)0x1234 +//#endif +// +//#define PMI_2A_11 0 +//#define PMI_2A_1m1 1 +//#define PMI_2A_1j 2 +//#define PMI_2A_1mj 3 +// +//// for NB-IoT +#define MAX_NUM_CHANNEL_BITS_NB_IoT 3360 //14 symbols * 12 sub-carriers * 10 SF * 2bits/RE // to check during real tests +#define MAX_DL_SIZE_BITS_NB_IoT 680 // in release 13 // in release 14 = 2048 // ??? **** not sure +////#define MAX_NUM_CHANNEL_BITS_NB_IOT 3*680 /// ??? ****not sure +// +//// to be created LTE_eNB_DLSCH_t --> is duplicated for each number of UE and then indexed in the table +// +//typedef struct { // LTE_DL_eNB_HARQ_t +// /// Status Flag indicating for this DLSCH (idle,active,disabled) +// SCH_status_t status; +// /// Transport block size +// uint32_t TBS; +// /// The payload + CRC size in bits, "B" from 36-212 +// uint32_t B; // keep this parameter +// /// Pointer to the payload +// uint8_t *b; // keep this parameter +// /// Pointers to transport block segments +// //uint8_t *c[MAX_NUM_DLSCH_SEGMENTS]; +// /// RTC values for each segment (for definition see 36-212 V8.6 2009-03, p.15) +// // uint32_t RTC[MAX_NUM_DLSCH_SEGMENTS]; +// /// Frame where current HARQ round was sent +// uint32_t frame; +// /// Subframe where current HARQ round was sent +// uint32_t subframe; +// /// Index of current HARQ round for this DLSCH +// uint8_t round; +// /// MCS format for this DLSCH +// uint8_t mcs; +// /// Redundancy-version of the current sub-frame +// uint8_t rvidx; +// /// MIMO mode for this DLSCH +// MIMO_mode_t mimo_mode; +// /// Current RB allocation +// uint32_t rb_alloc[4]; +// /// distributed/localized flag +// vrb_t vrb_type; +// /// Current subband PMI allocation +// uint16_t pmi_alloc; +// /// Current subband RI allocation +// uint32_t ri_alloc; +// /// Current subband CQI1 allocation +// uint32_t cqi_alloc1; +// /// Current subband CQI2 allocation +// uint32_t cqi_alloc2; +// /// Current Number of RBs +// uint16_t nb_rb; +// /// downlink power offset field +// uint8_t dl_power_off; +// /// Concatenated "e"-sequences (for definition see 36-212 V8.6 2009-03, p.17-18) +// uint8_t e[MAX_NUM_CHANNEL_BITS_NB_IOT]; +// /// data after scrambling +// uint8_t s_e[MAX_NUM_CHANNEL_BITS_NB_IOT]; +// /// length of the table e +// uint16_t length_e // new parameter +// /// Tail-biting convolutional coding outputs +// uint8_t d[96+(3*(24+MAX_DL_SIZE_BITS_NB_IOT))]; // new parameter +// /// Sub-block interleaver outputs +// uint8_t w[3*3*(MAX_DL_SIZE_BITS_NB_IOT+24)]; // new parameter +// /// Number of MIMO layers (streams) (for definition see 36-212 V8.6 2009-03, p.17, TM3-4) +// uint8_t Nl; +// /// Number of layers for this PDSCH transmission (TM8-10) +// uint8_t Nlayers; +// /// First layer for this PSCH transmission +// uint8_t first_layer; +//} NB_IoT_DL_eNB_HARQ_t; + +typedef enum { + + SCH_IDLE_NB_IoT, + ACTIVE_NB_IoT, + CBA_ACTIVE_NB_IoT, + DISABLED_NB_IoT + +} SCH_status_NB_IoT_t; + + +typedef struct { + /// NB-IoT + SCH_status_NB_IoT_t status; + /// The scheduling the NPDCCH and the NPDSCH transmission TS 36.213 Table 16.4.1-1 + uint8_t scheduling_delay; + /// The number of the subframe to transmit the NPDSCH Table TS 36.213 Table 16.4.1.3-1 (Nsf) (NB. in this case is not the index Isf) + uint8_t resource_assignment; + /// is the index that determined the repeat number of NPDSCH through table TS 36.213 Table 16.4.1.3-2 / for SIB1-NB Table 16.4.1.3-3 + uint8_t repetition_number; + /// Determined the ACK/NACK delay and the subcarrier allocation TS 36.213 Table 16.4.2 + uint8_t HARQ_ACK_resource; + /// Determined the repetition number value 0-3 (2 biut carried by the FAPI NPDCCH) + uint8_t dci_subframe_repetitions; + /// modulation always QPSK Qm = 2 + uint8_t modulation; + /// Concatenated "e"-sequences (for definition see 36-212 V8.6 2009-03, p.17-18) + uint8_t e[MAX_NUM_CHANNEL_BITS_NB_IoT]; + /// data after scrambling + uint8_t s_e[MAX_NUM_CHANNEL_BITS_NB_IoT]; + //length of the table e + uint16_t length_e; // new parameter + /// Tail-biting convolutional coding outputs + uint8_t d[96+(3*(24+MAX_DL_SIZE_BITS_NB_IoT))]; // new parameter + /// Sub-block interleaver outputs + uint8_t w[3*3*(MAX_DL_SIZE_BITS_NB_IoT+24)]; // new parameter + + /// Status Flag indicating for this DLSCH (idle,active,disabled) + //SCH_status_t status; + /// Transport block size + uint32_t TBS; + /// The payload + CRC size in bits, "B" from 36-212 + uint32_t B; + /// Pointer to the payload + uint8_t *b; + ///pdu of the ndlsch message + uint8_t *pdu; + /// Frame where current HARQ round was sent + uint32_t frame; + /// Subframe where current HARQ round was sent + uint32_t subframe; + /// Index of current HARQ round for this DLSCH + uint8_t round; + /// MCS format for this NDLSCH , TS 36.213 Table 16.4.1.5 + uint8_t mcs; + // we don't have code block segmentation / crc attachment / concatenation in NB-IoT R13 36.212 6.4.2 + // we don't have beamforming in NB-IoT + //this index will be used mainly for SI message buffer + uint8_t pdu_buffer_index; + +} NB_IoT_DL_eNB_HARQ_t; + + +typedef struct { // LTE_eNB_DLSCH_t + /// TX buffers for UE-spec transmission (antenna ports 5 or 7..14, prior to precoding) + uint32_t *txdataF[8]; + /// Allocated RNTI (0 means DLSCH_t is not currently used) + uint16_t rnti; + /// Active flag for baseband transmitter processing + uint8_t active; + /// Indicator of TX activation per subframe. Used during PUCCH detection for ACK/NAK. + uint8_t subframe_tx[10]; + /// First CCE of last PDSCH scheduling per subframe. Again used during PUCCH detection for ACK/NAK. + uint8_t nCCE[10]; + /// Current HARQ process id + uint8_t current_harq_pid; + /// Process ID's per subframe. Used to associate received ACKs on PUSCH/PUCCH to DLSCH harq process ids + uint8_t harq_ids[10]; + /// Window size (in outgoing transport blocks) for fine-grain rate adaptation + uint8_t ra_window_size; + /// First-round error threshold for fine-grain rate adaptation + uint8_t error_threshold; + /// Pointers to 8 HARQ processes for the DLSCH + NB_IoT_DL_eNB_HARQ_t harq_process; + /// circular list of free harq PIDs (the oldest come first) + /// (10 is arbitrary value, must be > to max number of DL HARQ processes in LTE) + int harq_pid_freelist[10]; + /// the head position of the free list (if list is free then head=tail) + int head_freelist; + /// the tail position of the free list + int tail_freelist; + /// Number of soft channel bits + uint32_t G; + /// Codebook index for this dlsch (0,1,2,3) + uint8_t codebook_index; + /// Maximum number of HARQ processes (for definition see 36-212 V8.6 2009-03, p.17) + uint8_t Mdlharq; + /// Maximum number of HARQ rounds + uint8_t Mlimit; + /// MIMO transmission mode indicator for this sub-frame (for definition see 36-212 V8.6 2009-03, p.17) + uint8_t Kmimo; + /// Nsoft parameter related to UE Category + uint32_t Nsoft; + /// amplitude of PDSCH (compared to RS) in symbols without pilots + int16_t sqrt_rho_a; + /// amplitude of PDSCH (compared to RS) in symbols containing pilots + int16_t sqrt_rho_b; + +} NB_IoT_eNB_DLSCH_t; + + +typedef struct { + /// HARQ process id + uint8_t harq_id; + /// ACK bits (after decoding) 0:NACK / 1:ACK / 2:DTX + uint8_t ack; + /// send status (for PUCCH) + uint8_t send_harq_status; + /// nCCE (for PUCCH) + uint8_t nCCE; + /// DAI value detected from DCI1/1a/1b/1d/2/2a/2b/2c. 0xff indicates not touched + uint8_t vDAI_DL; + /// DAI value detected from DCI0/4. 0xff indicates not touched + uint8_t vDAI_UL; +} harq_status_NB_IoT_t; + +typedef struct { + /// UL RSSI per receive antenna + int32_t UL_rssi[NB_ANTENNAS_RX]; + /// PUCCH1a/b power (digital linear) + uint32_t Po_PUCCH; + /// PUCCH1a/b power (dBm) + int32_t Po_PUCCH_dBm; + /// PUCCH1 power (digital linear), conditioned on below threshold + uint32_t Po_PUCCH1_below; + /// PUCCH1 power (digital linear), conditioned on above threshold + uint32_t Po_PUCCH1_above; + /// Indicator that Po_PUCCH has been updated by PHY + int32_t Po_PUCCH_update; + /// DL Wideband CQI index (2 TBs) + uint8_t DL_cqi[2]; + /// DL Subband CQI index (from HLC feedback) + uint8_t DL_subband_cqi[2][13]; + /// DL PMI Single Stream + uint16_t DL_pmi_single; + /// DL PMI Dual Stream + uint16_t DL_pmi_dual; + /// Current RI + uint8_t rank; + /// CRNTI of UE + uint16_t crnti; ///user id (rnti) of connected UEs + /// Initial timing offset estimate from PRACH for RAR + int32_t UE_timing_offset; + /// Timing advance estimate from PUSCH for MAC timing advance signalling + int32_t timing_advance_update; + /// Current mode of UE (NOT SYCHED, RAR, PUSCH) + UE_MODE_NB_IoT_t mode; + /// Current sector where UE is attached + uint8_t sector; + + /// dlsch l2 errors + uint32_t dlsch_l2_errors[8]; + /// dlsch trials per harq and round + uint32_t dlsch_trials[8][8]; + /// dlsch ACK/NACK per hard_pid and round + uint32_t dlsch_ACK[8][8]; + uint32_t dlsch_NAK[8][8]; + + /// ulsch l2 errors per harq_pid + uint32_t ulsch_errors[8]; + /// ulsch l2 consecutive errors per harq_pid + uint32_t ulsch_consecutive_errors; //[8]; + /// ulsch trials/errors/fer per harq and round + uint32_t nulsch_decoding_attempts[8][8]; + uint32_t ulsch_round_errors[8][8]; + uint32_t ulsch_decoding_attempts_last[8][8]; + uint32_t ulsch_round_errors_last[8][8]; + uint32_t ulsch_round_fer[8][8]; + uint32_t sr_received; + uint32_t sr_total; + + /// dlsch sliding count and total errors in round 0 are used to compute the dlsch_mcs_offset + uint32_t dlsch_sliding_cnt; + uint32_t dlsch_NAK_round0; + int8_t dlsch_mcs_offset; + + /// Target mcs1 after rate-adaptation (used by MAC layer scheduler) + uint8_t dlsch_mcs1; + /// Target mcs2 after rate-adaptation (used by MAC layer scheduler) + uint8_t dlsch_mcs2; + /// Total bits received from MAC on PDSCH + int total_TBS_MAC; + /// Total bits acknowledged on PDSCH + int total_TBS; + /// Total bits acknowledged on PDSCH (last interval) + int total_TBS_last; + /// Bitrate on the PDSCH [bps] + unsigned int dlsch_bitrate; + // unsigned int total_transmitted_bits; + +} NB_IoT_eNB_UE_stats; + +typedef struct { + /// Indicator of first transmission + uint8_t first_tx; + /// Last Ndi received for this process on DCI (used for C-RNTI only) + uint8_t DCINdi; + /// DLSCH status flag indicating + //SCH_status_t status; + /// Transport block size + uint32_t TBS; + /// The payload + CRC size in bits + uint32_t B; + /// Pointer to the payload + uint8_t *b; + /// Pointers to transport block segments + uint8_t *c[MAX_NUM_DLSCH_SEGMENTS_NB_IoT]; + /// RTC values for each segment (for definition see 36-212 V8.6 2009-03, p.15) + uint32_t RTC[MAX_NUM_DLSCH_SEGMENTS_NB_IoT]; + /// Index of current HARQ round for this DLSCH + uint8_t round; + /// MCS format for this DLSCH + uint8_t mcs; + /// Qm (modulation order) for this DLSCH + uint8_t Qm; + /// Redundancy-version of the current sub-frame + uint8_t rvidx; + /// MIMO mode for this DLSCH + // MIMO_mode_t mimo_mode; + /// soft bits for each received segment ("w"-sequence)(for definition see 36-212 V8.6 2009-03, p.15) + int16_t w[MAX_NUM_DLSCH_SEGMENTS_NB_IoT][3*(6144+64)]; + /// for abstraction soft bits for each received segment ("w"-sequence)(for definition see 36-212 V8.6 2009-03, p.15) + double w_abs[MAX_NUM_DLSCH_SEGMENTS_NB_IoT][3*(6144+64)]; + /// soft bits for each received segment ("d"-sequence)(for definition see 36-212 V8.6 2009-03, p.15) + int16_t *d[MAX_NUM_DLSCH_SEGMENTS_NB_IoT]; + /// Number of code segments (for definition see 36-212 V8.6 2009-03, p.9) + uint32_t C; + /// Number of "small" code segments (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Cminus; + /// Number of "large" code segments (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Cplus; + /// Number of bits in "small" code segments (<6144) (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Kminus; + /// Number of bits in "large" code segments (<6144) (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Kplus; + /// Number of "Filler" bits (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t F; + /// Number of MIMO layers (streams) (for definition see 36-212 V8.6 2009-03, p.17) + uint8_t Nl; + /// current delta_pucch + int8_t delta_PUCCH; + /// Number of soft channel bits + uint32_t G; + /// Current Number of RBs + uint16_t nb_rb; + /// Current subband PMI allocation + uint16_t pmi_alloc; + /// Current RB allocation (even slots) + uint32_t rb_alloc_even[4]; + /// Current RB allocation (odd slots) + uint32_t rb_alloc_odd[4]; + /// distributed/localized flag + //vrb_t vrb_type; + /// downlink power offset field + uint8_t dl_power_off; + /// trials per round statistics + uint32_t trials[8]; + /// error statistics per round + uint32_t errors[8]; + /// codeword this transport block is mapped to + uint8_t codeword; + +} NB_IoT_DL_UE_HARQ_t; + +typedef struct { + /// RNTI + uint16_t rnti; + /// Active flag for DLSCH demodulation + uint8_t active; + /// Transmission mode + uint8_t mode1_flag; + /// amplitude of PDSCH (compared to RS) in symbols without pilots + int16_t sqrt_rho_a; + /// amplitude of PDSCH (compared to RS) in symbols containing pilots + int16_t sqrt_rho_b; + /// Current HARQ process id threadRx Odd and threadRx Even + uint8_t current_harq_pid; + /// Current subband antenna selection + uint32_t antenna_alloc; + /// Current subband RI allocation + uint32_t ri_alloc; + /// Current subband CQI1 allocation + uint32_t cqi_alloc1; + /// Current subband CQI2 allocation + uint32_t cqi_alloc2; + /// saved subband PMI allocation from last PUSCH/PUCCH report + uint16_t pmi_alloc; + /// HARQ-ACKs + harq_status_NB_IoT_t harq_ack; + /// Pointers to up to 8 HARQ processes + NB_IoT_DL_UE_HARQ_t *harq_process; + /// Maximum number of HARQ processes(for definition see 36-212 V8.6 2009-03, p.17 + uint8_t Mdlharq; + /// MIMO transmission mode indicator for this sub-frame (for definition see 36-212 V8.6 2009-03, p.17) + uint8_t Kmimo; + /// Nsoft parameter related to UE Category + uint32_t Nsoft; + /// Maximum number of Turbo iterations + uint8_t max_turbo_iterations; + /// number of iterations used in last turbo decoding + uint8_t last_iteration_cnt; + /// accumulated tx power adjustment for PUCCH + int8_t g_pucch; + +} NB_IoT_UE_DLSCH_t; + +//---------------------------------------------------------------------------------------------------------- +// NB-IoT +//---------------------------------------------------------------------------------------------------- + +//enum for distinguish the different type of ndlsch (may in the future will be not needed) +typedef enum +{ + + SIB1, + SI_Message, + RAR, + UE_Data + +}ndlsch_flag_t; + + + +typedef struct { + rnti_t rnti; + //array containing the pdus of DCI + uint8_t *a[2]; + //Array containing encoded DCI data + uint8_t *e[2]; + + //UE specific parameters + uint16_t npdcch_NumRepetitions; + + uint16_t repetition_number; + //indicate the corresponding subframe within the repetition (set to 0 when a new NPDCCH pdu is received) + uint16_t repetition_idx; + + // uint16_t npdcch_Offset_USS; + // uint16_t npdcch_StartSF_USS; + + +}NB_IoT_eNB_NPDCCH_t; + + +typedef struct{ + + //Number of repetitions (R) for common search space (RAR and PAGING) + uint16_t number_repetition_RA; + uint16_t number_repetition_PAg; + //index of the current subframe among the repetition (set to 0 when we receive the new NPDCCH) + uint16_t repetition_idx_RA; + uint16_t repetition_idx_Pag; + +}NB_IoT_eNB_COMMON_NPDCCH_t; + + +typedef struct { + + /// Length of DCI in bits + uint8_t dci_length; + /// Aggregation level only 1,2 in NB-IoT + uint8_t L; + /// Position of first CCE of the dci + int firstCCE; + /// flag to indicate that this is a RA response + boolean_t ra_flag; + /// rnti + rnti_t rnti; + /// Format + DCI_format_NB_IoT_t format; + /// DCI pdu + uint8_t dci_pdu[8]; + +} DCI_ALLOC_NB_IoT_t; + + +typedef struct { + //delete the count for the DCI numbers,NUM_DCI_MAX should set to 2 + uint32_t num_npdcch_symbols; + ///indicates the starting OFDM symbol in the first slot of a subframe k for the NPDCCH transmission + /// see FAPI/NFAPI specs Table 4-45 + uint8_t npdcch_start_symbol; + uint8_t Num_dci; + DCI_ALLOC_NB_IoT_t dci_alloc[2] ; + +} DCI_PDU_NB_IoT; + + + + +typedef struct { + /// TX buffers for UE-spec transmission (antenna ports 5 or 7..14, prior to precoding) + int32_t *txdataF[8]; + /// dl channel estimates (estimated from ul channel estimates) + int32_t **calib_dl_ch_estimates; + /// Allocated RNTI (0 means DLSCH_t is not currently used) + uint16_t rnti; + /// Active flag for baseband transmitter processing + uint8_t active; + /// Indicator of TX activation per subframe. Used during PUCCH detection for ACK/NAK. + uint8_t subframe_tx[10]; + /// First CCE of last PDSCH scheduling per subframe. Again used during PUCCH detection for ACK/NAK. + uint8_t nCCE[10]; + /*in NB-IoT there is only 1 HARQ process for each UE therefore no pid is required*/ + /// The only HARQ process for the DLSCH + NB_IoT_DL_eNB_HARQ_t *harq_process; + /// Number of soft channel bits + uint32_t G; + /// Maximum number of HARQ rounds + uint8_t Mlimit; + /// Nsoft parameter related to UE Category + uint32_t Nsoft; + /// amplitude of PDSCH (compared to RS) in symbols without pilots + int16_t sqrt_rho_a; + /// amplitude of PDSCH (compared to RS) in symbols containing pilots + int16_t sqrt_rho_b; + ///NB-IoT + /// may use in the npdsch_procedures + uint16_t scrambling_sequence_intialization; + /// number of cell specific TX antenna ports assumed by the UE + uint8_t nrs_antenna_ports; + + //This indicate the current subframe within the subframe interval between the NPDSCH transmission (Nsf*Nrep) + uint16_t sf_index; + ///indicates the starting OFDM symbol in the first slot of a subframe k for the NPDSCH transmission + /// see FAPI/NFAPI specs Table 4-47 + uint8_t npdsch_start_symbol; + /*SIB1-NB related parameters*/ + ///flag for indicate if the current frame is the start of a new SIB1-NB repetition within the SIB1-NB period (0 = FALSE, 1 = TRUE) + uint8_t sib1_rep_start; + ///the number of the frame within the 16 continuous frame in which sib1-NB is transmitted (1-8 = 1st, 2nd ecc..) (0 = not foresees a transmission) + uint8_t relative_sib1_frame; + //Flag used to discern among different NDLSCH structures (SIB1,SI,RA,UE-spec) + //(used inside the ndlsch procedure for distinguish the different type of data to manage also in term of repetitions and transmission over more subframes + ndlsch_flag_t ndlsch_type; + +} NB_IoT_eNB_NDLSCH_t; + +typedef struct { + /// Length of CQI data under RI=1 assumption(bits) + uint8_t Or1; + /// Rank information + uint8_t o_RI[2]; + /// Format of CQI data + UCI_format_NB_IoT_t uci_format; + /// The value of DAI in DCI format 0 + uint8_t V_UL_DAI; + /// Pointer to CQI data + uint8_t o[MAX_CQI_BYTES_NB_IoT]; + /// CQI CRC status + uint8_t cqi_crc_status; + /// PHICH active flag + uint8_t phich_active; + /// PHICH ACK + uint8_t phich_ACK; + /// Length of rank information (bits) + uint8_t O_RI; + /// First Allocated RB + uint16_t first_rb; + /// Current Number of RBs + uint16_t nb_rb; + /// Determined the subcarrier allocation for the NPUSCH.(15, 3.75 KHz) + uint8_t subcarrier_indication; + /// Determined the number of resource unit for the NPUSCH + uint8_t resource_assignment; + /// Determined the scheduling delay for NPUSCH + uint8_t scheduling_delay; + /// The number of the repetition number for NPUSCH Transport block + uint8_t repetition_number; + /// Determined the repetition number value 0-3 + uint8_t dci_subframe_repetitions; + /// Flag indicating that this ULSCH has been allocated by a DCI (otherwise it is a retransmission based on PHICH NAK) + uint8_t dci_alloc; + /// Flag indicating that this ULSCH has been allocated by a RAR (otherwise it is a retransmission based on PHICH NAK or DCI) + uint8_t rar_alloc; + /// Status Flag indicating for this ULSCH (idle,active,disabled) + SCH_status_NB_IoT_t status; + /// Subframe scheduling indicator (i.e. Transmission opportunity indicator) + uint8_t subframe_scheduling_flag; + /// Transport block size + uint32_t TBS; + /// The payload + CRC size in bits + uint32_t B; + /// Number of soft channel bits + uint32_t G; + /// Pointer to ACK + uint8_t o_ACK[4]; + /// Length of ACK information (bits) + uint8_t O_ACK; + /// coded ACK bits + int16_t q_ACK[MAX_ACK_PAYLOAD_NB_IoT]; + /// Number of code segments (for definition see 36-212 V8.6 2009-03, p.9) + /// Concatenated "e"-sequences (for definition see 36-212 V8.6 2009-03, p.17-18) + int16_t e[MAX_NUM_CHANNEL_BITS_NB_IoT] __attribute__((aligned(32))); + /// coded RI bits + int16_t q_RI[MAX_RI_PAYLOAD_NB_IoT]; + /// "q" sequences for CQI/PMI (for definition see 36-212 V8.6 2009-03, p.27) + int8_t q[MAX_CQI_PAYLOAD_NB_IoT]; + /// number of coded CQI bits after interleaving + uint8_t o_RCC; + /// coded and interleaved CQI bits + int8_t o_w[(MAX_CQI_BITS_NB_IoT+8)*3]; + /// coded CQI bits + int8_t o_d[96+((MAX_CQI_BITS_NB_IoT+8)*3)]; + /// + uint32_t C; + /// Number of "small" code segments (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Cminus; + /// Number of "large" code segments (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Cplus; + /// Number of bits in "small" code segments (<6144) (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Kminus; + /// Number of bits in "large" code segments (<6144) (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t Kplus; + /// Number of "Filler" bits (for definition see 36-212 V8.6 2009-03, p.10) + uint32_t F; + /// Temporary h sequence to flag PUSCH_x/PUSCH_y symbols which are not scrambled + //uint8_t h[MAX_NUM_CHANNEL_BITS]; + /// SRS active flag + uint8_t srs_active; + /// Pointer to the payload + uint8_t *b; + /// Current Number of Symbols + uint8_t Nsymb_pusch; + /// Index of current HARQ round for this ULSCH + uint8_t round; + /// MCS format for this ULSCH + uint8_t mcs; + /// Redundancy-version of the current sub-frame (value 0->RV0,value 1 ->RV2) + uint8_t rvidx; + /// Msc_initial, Initial number of subcarriers for ULSCH (36-212, v8.6 2009-03, p.26-27) + uint16_t Msc_initial; + /// Nsymb_initial, Initial number of symbols for ULSCH (36-212, v8.6 2009-03, p.26-27) + uint8_t Nsymb_initial; + /// n_DMRS for cyclic shift of DMRS (36.213 Table 9.1.2-2) + uint8_t n_DMRS; + /// n_DMRS for cyclic shift of DMRS (36.213 Table 9.1.2-2) - previous scheduling + /// This is needed for PHICH generation which + /// is done after a new scheduling + uint8_t previous_n_DMRS; + /// n_DMRS 2 for cyclic shift of DMRS (36.211 Table 5.5.1.1.-1) + uint8_t n_DMRS2; + /// Flag to indicate that this ULSCH is for calibration information sent from UE (i.e. no MAC SDU to pass up) + // int calibration_flag; + /// delta_TF for power control + int32_t delta_TF; + ///////////////////////////////////////////// 4 parameter added by vincent /////////////////////////////////////////////// + // NB_IoT: Nsymb_UL and Nslot_UL are defined in 36.211, Section 10.1.2.3, Table 10.1.2.3-1 + // The number of symbol in a resource unit is given by Nsymb_UL*Nslot_UL + uint8_t Nsymb_UL; + // Number of NPUSCH slots + uint8_t Nslot_UL; + // Number of subcarrier for NPUSH, can be 1, 3, 6, 12 + uint8_t N_sc_RU; + // Index of UL NB_IoT resource block + uint32_t UL_RB_ID_NB_IoT; + // Subcarrier indication fields, obtained through DCI, Section 16.5.1.1 in 36.213 + uint16_t I_sc; + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +} NB_IoT_UL_eNB_HARQ_t; + + +typedef struct { + /// Pointers to the HARQ processes for the NULSCH + NB_IoT_UL_eNB_HARQ_t *harq_process; + /// Maximum number of HARQ rounds + uint8_t Mlimit; + /// Value 0 = npush format 1 (data) value 1 = npusch format 2 (ACK/NAK) + uint8_t npusch_format; + /// Flag to indicate that eNB awaits UE Msg3 + uint8_t Msg3_active; + /// Flag to indicate that eNB should decode UE Msg3 + uint8_t Msg3_flag; + /// Subframe for Msg3 + uint8_t Msg3_subframe; + /// Frame for Msg3 + uint32_t Msg3_frame; + /// RNTI attributed to this ULSCH + uint16_t rnti; + /// cyclic shift for DM RS + uint8_t cyclicShift; + /// cooperation flag + uint8_t cooperation_flag; + /// (only in-band mode), indicate the resource block overlap the SRS configuration of LTE + uint8_t N_srs; + /// + uint8_t scrambling_re_intialization_batch_index; + /// number of cell specific TX antenna ports assumed by the UE + uint8_t nrs_antenna_ports; + /// + uint16_t scrambling_sequence_intialization; + /// + uint16_t sf_index; + /// Determined the ACK/NACK delay and the subcarrier allocation TS 36.213 Table 16.4.2 + uint8_t HARQ_ACK_resource; + + ///////////// kept from LTE /////////////////////////////////////////////////// + + /// Maximum number of iterations used in eNB turbo decoder + uint8_t max_turbo_iterations; + /// ACK/NAK Bundling flag + uint8_t bundling; + /// beta_offset_cqi times 8 + uint16_t beta_offset_cqi_times8; + /// beta_offset_ri times 8 + uint16_t beta_offset_ri_times8; + /// beta_offset_harqack times 8 + uint16_t beta_offset_harqack_times8; + /// num active cba group + uint8_t num_active_cba_groups; + /// allocated CBA RNTI for this ulsch + uint16_t cba_rnti[4];//NUM_MAX_CBA_GROUP]; + #ifdef LOCALIZATION + /// epoch timestamp in millisecond + int32_t reference_timestamp_ms; + /// aggregate physical states every n millisecond + int32_t aggregation_period_ms; + /// a set of lists used for localization + struct list loc_rss_list[10], loc_rssi_list[10], loc_subcarrier_rss_list[10], loc_timing_advance_list[10], loc_timing_update_list[10]; + struct list tot_loc_rss_list, tot_loc_rssi_list, tot_loc_subcarrier_rss_list, tot_loc_timing_advance_list, tot_loc_timing_update_list; + #endif + +} NB_IoT_eNB_NULSCH_t; + +#define NPBCH_A 34 + +typedef struct { + //the 2 LSB of the hsfn (the MSB are indicated by the SIB1-NB) + uint16_t h_sfn_lsb; + + uint8_t npbch_d[96+(3*(16+NPBCH_A))]; + uint8_t npbch_w[3*3*(16+NPBCH_A)]; + uint8_t npbch_e[1600]; + ///pdu of the npbch message + uint8_t *pdu; + +} NB_IoT_eNB_NPBCH_t; + + +#endif diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c index 46689a9aaa..7682045ae1 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c @@ -40,7 +40,7 @@ //#define DEBUG_LLR_SIC -int16_t zero[8] __attribute__ ((aligned(16))) = {0,0,0,0,0,0,0,0}; +int16_t zeros[8] __attribute__ ((aligned(16))) = {0,0,0,0,0,0,0,0}; int16_t ones[8] __attribute__ ((aligned(16))) = {0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff}; #if defined(__x86_64__) || defined(__i386__) __m128i rho_rpi __attribute__ ((aligned(16))); diff --git a/openair1/PHY/LTE_TRANSPORT/proto_NB_IoT.h b/openair1/PHY/LTE_TRANSPORT/proto_NB_IoT.h new file mode 100644 index 0000000000..9e3a55eacc --- /dev/null +++ b/openair1/PHY/LTE_TRANSPORT/proto_NB_IoT.h @@ -0,0 +1,362 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file PHY/LTE_TRANSPORT/proto.h + * \brief Function prototypes for PHY physical/transport channel processing and generation V8.6 2009-03 + * \author R. Knopp, F. Kaltenberger + * \date 2011 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr + * \note + * \warning + */ +#ifndef __LTE_TRANSPORT_PROTO_NB_IOT__H__ +#define __LTE_TRANSPORT_PROTO_NB_IOT__H__ +#include "PHY/defs_L1_NB_IoT.h" +//#include + +//NPSS + +int generate_npss_NB_IoT(int32_t **txdataF, + short amp, + NB_IoT_DL_FRAME_PARMS *frame_parms, + unsigned short symbol_offset, // symbol_offset should equal to 3 for NB-IoT + unsigned short slot_offset, + unsigned short RB_IoT_ID); // new attribute (values are between 0.. Max_RB_number-1), it does not exist for LTE + +//NSSS + +int generate_sss_NB_IoT(int32_t **txdataF, + int16_t amp, + NB_IoT_DL_FRAME_PARMS *frame_parms, + uint16_t symbol_offset, // symbol_offset = 3 for NB-IoT + uint16_t slot_offset, + unsigned short frame_number, // new attribute (Get value from higher layer), it does not exist for LTE + unsigned short RB_IoT_ID); // new attribute (values are between 0.. Max_RB_number-1), it does not exist for LTE + +//*****************Vincent part for Cell ID estimation from NSSS ******************// + +int rx_nsss_NB_IoT(PHY_VARS_UE_NB_IoT *ue,int32_t *tot_metric); + +int nsss_extract_NB_IoT(PHY_VARS_UE_NB_IoT *ue, + NB_IoT_DL_FRAME_PARMS *frame_parms, + int32_t **nsss_ext, + int l); + +//NRS + +void generate_pilots_NB_IoT(PHY_VARS_eNB_NB_IoT *phy_vars_eNB, + int32_t **txdataF, + int16_t amp, + uint16_t Ntti, // Ntti = 10 + unsigned short RB_IoT_ID, // RB reserved for NB-IoT + unsigned short With_NSSS); // With_NSSS = 1; if the frame include a sub-Frame with NSSS signal + + +//NPBCH + +int allocate_npbch_REs_in_RB(NB_IoT_DL_FRAME_PARMS *frame_parms, + int32_t **txdataF, + uint32_t *jj, + uint32_t symbol_offset, + uint8_t *x0, + uint8_t pilots, + int16_t amp, + unsigned short id_offset, + uint32_t *re_allocated); + + +int generate_npbch(NB_IoT_eNB_NPBCH_t *eNB_npbch, + int32_t **txdataF, + int amp, + NB_IoT_DL_FRAME_PARMS *frame_parms, + uint8_t *npbch_pdu, + uint8_t frame_mod64, + unsigned short NB_IoT_RB_ID); + + +void npbch_scrambling(NB_IoT_DL_FRAME_PARMS *frame_parms, + uint8_t *npbch_e, + uint32_t length); + +// Functions below implement 36-211 and 36-212 + +/*Function to pack the DCI*/ +// newly added function for NB-IoT , does not exist for LTE +void add_dci_NB_IoT(DCI_PDU_NB_IoT *DCI_pdu, + void *pdu, + rnti_t rnti, + unsigned char dci_size_bytes, + unsigned char aggregation, + unsigned char dci_size_bits, + unsigned char dci_fmt, + uint8_t npdcch_start_symbol); + + +/*Use the UL DCI Information to configure PHY and also Pack the DCI*/ +int generate_eNB_ulsch_params_from_dci_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB, + eNB_rxtx_proc_NB_IoT_t *proc, + DCI_CONTENT *DCI_Content, + uint16_t rnti, + DCI_format_NB_IoT_t dci_format, + uint8_t UE_id, + uint8_t aggregation, + uint8_t npdcch_start_symbol); + + +/*Use the DL DCI Information to configure PHY and also Pack the DCI*/ +int generate_eNB_dlsch_params_from_dci_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB, + int frame, + uint8_t subframe, + DCI_CONTENT *DCI_Content, + uint16_t rnti, + DCI_format_NB_IoT_t dci_format, + NB_IoT_eNB_NDLSCH_t *ndlsch, + NB_IoT_DL_FRAME_PARMS *frame_parms, + uint8_t aggregation, + uint8_t npdcch_start_symbol); + + +/*Function for DCI encoding, scrambling, modulation*/ +uint8_t generate_dci_top_NB_IoT(NB_IoT_eNB_NPDCCH_t *npdcch, + uint8_t Num_dci, + DCI_ALLOC_NB_IoT_t *dci_alloc, + int16_t amp, + NB_IoT_DL_FRAME_PARMS *fp, + int32_t **txdataF, + uint32_t subframe, + uint8_t npdcch_start_symbol); + +/*! + \brief Decoding of PUSCH/ACK/RI/ACK from 36-212. + @param phy_vars_eNB Pointer to eNB top-level descriptor + @param proc Pointer to RXTX proc variables + @param UE_id ID of UE transmitting this PUSCH + @param subframe Index of subframe for PUSCH + @param control_only_flag Receive PUSCH with control information only + @param Nbundled Nbundled parameter for ACK/NAK scrambling from 36-212/36-213 + @param llr8_flag If 1, indicate that the 8-bit turbo decoder should be used + @returns 0 on success +*/ +unsigned int ulsch_decoding_NB_IoT(PHY_VARS_eNB_NB_IoT *phy_vars_eNB, + eNB_rxtx_proc_NB_IoT_t *proc, + uint8_t UE_id, + uint8_t control_only_flag, + uint8_t Nbundled, + uint8_t llr8_flag); + +//NB-IoT version +NB_IoT_eNB_NDLSCH_t *new_eNB_dlsch_NB_IoT(//unsigned char Kmimo, + //unsigned char Mdlharq, + uint32_t Nsoft, + //unsigned char N_RB_DL, + uint8_t abstraction_flag, + NB_IoT_DL_FRAME_PARMS* frame_parms); + + +NB_IoT_eNB_NULSCH_t *new_eNB_ulsch_NB_IoT(uint8_t abstraction_flag); + + +uint8_t subframe2harq_pid_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms,uint32_t frame,uint8_t subframe); + + +/** \brief Compute Q (modulation order) based on I_MCS for PUSCH. Implements table 8.6.1-1 from 36.213. + @param I_MCS */ + +//uint8_t get_Qm_ul_NB_IoT(uint8_t I_MCS); +unsigned char get_Qm_ul_NB_IoT(unsigned char I_MCS, uint8_t N_sc_RU); + +/** \fn dlsch_encoding(PHY_VARS_eNB *eNB, + uint8_t *input_buffer, + LTE_DL_FRAME_PARMS *frame_parms, + uint8_t num_pdcch_symbols, + LTE_eNB_DLSCH_t *dlsch, + int frame, + uint8_t subframe) + \brief This function performs a subset of the bit-coding functions for LTE as described in 36-212, Release 8.Support is limited to turbo-coded channels (DLSCH/ULSCH). The implemented functions are: + - CRC computation and addition + - Code block segmentation and sub-block CRC addition + - Channel coding (Turbo coding) + - Rate matching (sub-block interleaving, bit collection, selection and transmission + - Code block concatenation + @param eNB Pointer to eNB PHY context + @param input_buffer Pointer to input buffer for sub-frame + @param frame_parms Pointer to frame descriptor structure + @param num_pdcch_symbols Number of PDCCH symbols in this subframe + @param dlsch Pointer to dlsch to be encoded + @param frame Frame number + @param subframe Subframe number + @param rm_stats Time statistics for rate-matching + @param te_stats Time statistics for turbo-encoding + @param i_stats Time statistics for interleaving + @returns status +*/ + +int32_t dlsch_encoding_NB_IoT(unsigned char *a, + NB_IoT_eNB_DLSCH_t *dlsch, + uint8_t Nsf, // number of subframes required for npdsch pdu transmission calculated from Isf (3GPP spec table) + unsigned int G, // G (number of available RE) is implicitly multiplied by 2 (since only QPSK modulation) + time_stats_t *rm_stats, + time_stats_t *te_stats, + time_stats_t *i_stats); + + +void rx_ulsch_NB_IoT(PHY_VARS_eNB_NB_IoT *phy_vars_eNB, + eNB_rxtx_proc_NB_IoT_t *proc, + uint8_t eNB_id, // this is the effective sector id + uint8_t UE_id, + NB_IoT_eNB_NULSCH_t **ulsch, + uint8_t cooperation_flag); + + + + +void ulsch_extract_rbs_single_NB_IoT(int32_t **rxdataF, + int32_t **rxdataF_ext, + // uint32_t first_rb, + //uint32_t UL_RB_ID_NB_IoT, // index of UL NB_IoT resource block + uint8_t N_sc_RU, // number of subcarriers in UL + uint32_t I_sc, // subcarrier indication field + uint32_t nb_rb, + uint8_t l, + uint8_t Ns, + NB_IoT_DL_FRAME_PARMS *frame_parms); + +void extract_CQI_NB_IoT(void *o,UCI_format_NB_IoT_t uci_format,NB_IoT_eNB_UE_stats *stats,uint8_t N_RB_DL, uint16_t * crnti, uint8_t * access_mode); + +//*****************Vincent part for nprach ******************// +void RX_NPRACH_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB, int16_t *Rx_buffer); + +uint32_t TA_estimation_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB, + int16_t *Rx_sub_sampled_buffer, + uint16_t sub_sampling_rate, + uint16_t FRAME_LENGTH_COMPLEX_SUB_SAMPLES, + uint32_t estimated_TA_coarse, + char coarse); + +uint8_t NPRACH_detection_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB, int16_t *Rx_sub_sampled_buffer, uint16_t sub_sampling_rate, uint32_t FRAME_LENGTH_COMPLEX_SUB_SAMPLES); + +int16_t* sub_sampling_NB_IoT(int16_t *input_buffer, uint32_t length_input, uint32_t *length_ouput, uint16_t sub_sampling_rate); +//************************************************************// +//*****************Vincent part for ULSCH demodulation ******************// +uint16_t get_UL_sc_start_NB_IoT(uint16_t I_sc); + +void generate_grouphop_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms); + +void init_ul_hopping_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms); + +void rotate_single_carrier_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB, + NB_IoT_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + uint8_t UE_id, + uint8_t symbol, + uint8_t Qm); + +void fill_rbs_zeros_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB, + NB_IoT_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + uint8_t UE_id, + uint8_t symbol); + +int32_t ulsch_bpsk_llr_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB, + NB_IoT_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int16_t *ulsch_llr, + uint8_t symbol, + uint8_t uint8_t, + int16_t **llrp); + + +int32_t ulsch_qpsk_llr_NB_IoT( + NB_IoT_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int16_t *ulsch_llr, + uint8_t symbol, + uint8_t nb_rb, + int16_t **llrp); + +void rotate_bpsk_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB, + NB_IoT_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + uint8_t UE_id, + uint8_t symbol); +//************************************************************// + +//************************************************************// +//*****************Vincent part for DLSCH demodulation ******************// + +int rx_npdsch_NB_IoT(PHY_VARS_UE_NB_IoT *ue, + unsigned char eNB_id, + unsigned char eNB_id_i, //if this == ue->n_connected_eNB, we assume MU interference + uint32_t frame, + uint8_t subframe, + unsigned char symbol, + unsigned char first_symbol_flag, + unsigned char i_mod, + unsigned char harq_pid); + +unsigned short dlsch_extract_rbs_single_NB_IoT(int **rxdataF, + int **dl_ch_estimates, + int **rxdataF_ext, + int **dl_ch_estimates_ext, + unsigned short pmi, + unsigned char *pmi_ext, + unsigned int *rb_alloc, + unsigned char symbol, + unsigned char subframe, + uint32_t frame, + uint32_t high_speed_flag, + NB_IoT_DL_FRAME_PARMS *frame_parms); + +void dlsch_channel_level_NB_IoT(int **dl_ch_estimates_ext, + NB_IoT_DL_FRAME_PARMS *frame_parms, + int32_t *avg, + uint8_t symbol, + unsigned short nb_rb); + +void dlsch_channel_compensation_NB_IoT(int **rxdataF_ext, + int **dl_ch_estimates_ext, + int **dl_ch_mag, + int **dl_ch_magb, + int **rxdataF_comp, + int **rho, + NB_IoT_DL_FRAME_PARMS *frame_parms, + unsigned char symbol, + uint8_t first_symbol_flag, + unsigned char mod_order, + unsigned short nb_rb, + unsigned char output_shift, + PHY_MEASUREMENTS_NB_IoT *measurements); + +int dlsch_qpsk_llr_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms, + int32_t **rxdataF_comp, + int16_t *dlsch_llr, + uint8_t symbol, + uint8_t first_symbol_flag, + uint16_t nb_rb, + int16_t **llr32p, + uint8_t beamforming_mode); + +//************************************************************// + + +#endif diff --git a/openair1/PHY/LTE_TRANSPORT/uci_NB_IoT.h b/openair1/PHY/LTE_TRANSPORT/uci_NB_IoT.h new file mode 100644 index 0000000000..b20635360d --- /dev/null +++ b/openair1/PHY/LTE_TRANSPORT/uci_NB_IoT.h @@ -0,0 +1,324 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef __UCI_NB_IOT__H__ +#define __UCI_NB_IOT__H__ +//#include "PHY/types_NB_IoT.h" + + + +typedef enum { + ue_selected_NB_IoT, + wideband_cqi_rank1_2A_NB_IoT, //wideband_cqi_rank1_2A, + wideband_cqi_rank2_2A_NB_IoT, //wideband_cqi_rank2_2A, + HLC_subband_cqi_nopmi_NB_IoT, //HLC_subband_cqi_nopmi, + HLC_subband_cqi_rank1_2A_NB_IoT, //HLC_subband_cqi_rank1_2A, + HLC_subband_cqi_rank2_2A_NB_IoT, //HLC_subband_cqi_rank2_2A, + HLC_subband_cqi_modes123_NB_IoT, //HLC_subband_cqi_modes123 + HLC_subband_cqi_mcs_CBA_NB_IoT, // MCS and RNTI, for contention-based acces + unknown_cqi_NB_IoT// +} UCI_format_NB_IoT_t; + +// **********************************************1.5 MHz*************************************************************************** +typedef struct __attribute__((packed)) +{ + uint32_t padding:16; + uint32_t pmi:12; + uint32_t cqi1:4; +} +wideband_cqi_rank1_2A_1_5MHz_NB_IoT ; +#define sizeof_wideband_cqi_rank1_2A_1_5MHz_NB_IoT 16 + +typedef struct __attribute__((packed)) +{ + uint16_t padding:2; + uint16_t pmi:6; + uint16_t cqi2:4; + uint16_t cqi1:4; +} +wideband_cqi_rank2_2A_1_5MHz_NB_IoT ; +#define sizeof_wideband_cqi_rank2_2A_1_5MHz_NB_IoT 14 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:16; + uint32_t diffcqi1:12; + uint32_t cqi1:4; +} +HLC_subband_cqi_nopmi_1_5MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_nopmi_1_5MHz_NB_IoT 16 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:14; + uint32_t pmi:2; + uint32_t diffcqi1:12; + uint32_t cqi1:4; +} +HLC_subband_cqi_rank1_2A_1_5MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_rank1_2A_1_5MHz_NB_IoT 18 + +typedef struct __attribute__((packed)) +{ + uint64_t padding:31; + uint64_t pmi:1; + uint64_t diffcqi2:12; + uint64_t cqi2:4; + uint64_t diffcqi1:12; + uint64_t cqi1:4; +} +HLC_subband_cqi_rank2_2A_1_5MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_rank2_2A_1_5MHz_NB_IoT 33 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:16; + uint32_t diffcqi1:12; + uint32_t cqi1:4; +} +HLC_subband_cqi_modes123_1_5MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_modes123_1_5MHz_NB_IoT 16 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:11; + uint32_t crnti:16; + uint32_t mcs:5; +} +HLC_subband_cqi_mcs_CBA_1_5MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_mcs_CBA_1_5MHz_NB_IoT 21 + + +// **********************************************5 MHz*************************************************************************** +typedef struct __attribute__((packed)) +{ + uint32_t padding:14; + uint32_t pmi:14; + uint32_t cqi1:4; +} +wideband_cqi_rank1_2A_5MHz_NB_IoT ; +#define sizeof_wideband_cqi_rank1_2A_5MHz_NB_IoT 18 + +typedef struct __attribute__((packed)) +{ + uint16_t padding:1; + uint16_t pmi:7; + uint16_t cqi2:4; + uint16_t cqi1:4; +} +wideband_cqi_rank2_2A_5MHz_NB_IoT ; +#define sizeof_wideband_cqi_rank2_2A_5MHz_NB_IoT 15 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:14; + uint32_t diffcqi1:14; + uint32_t cqi1:4; +} +HLC_subband_cqi_nopmi_5MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_nopmi_5MHz_NB_IoT 18 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:12; + uint32_t pmi:2; + uint32_t diffcqi1:14; + uint32_t cqi1:4; +} +HLC_subband_cqi_rank1_2A_5MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_rank1_2A_5MHz_NB_IoT 20 + +typedef struct __attribute__((packed)) +{ + uint64_t padding:27; + uint64_t pmi:1; + uint64_t diffcqi2:14; + uint64_t cqi2:4; + uint64_t diffcqi1:14; + uint64_t cqi1:4; +} +HLC_subband_cqi_rank2_2A_5MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_rank2_2A_5MHz_NB_IoT 37 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:14; + uint32_t diffcqi1:14; + uint32_t cqi1:4; +} +HLC_subband_cqi_modes123_5MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_modes123_5MHz_NB_IoT 18 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:11; + uint32_t crnti:16; + uint32_t mcs:5; +} +HLC_subband_cqi_mcs_CBA_5MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_mcs_CBA_5MHz_NB_IoT 21 + +// **********************************************10 MHz*************************************************************************** +typedef struct __attribute__((packed)) +{ + uint32_t padding:10; + uint32_t pmi:18; + uint32_t cqi1:4; +} +wideband_cqi_rank1_2A_10MHz_NB_IoT ; +#define sizeof_wideband_cqi_rank1_2A_10MHz_NB_IoT 22 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:15; + uint32_t pmi:9; + uint32_t cqi2:4; + uint32_t cqi1:4; +} +wideband_cqi_rank2_2A_10MHz_NB_IoT ; +#define sizeof_wideband_cqi_rank2_2A_10MHz_NB_IoT 17 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:10; + uint32_t diffcqi1:18; + uint32_t cqi1:4; +} +HLC_subband_cqi_nopmi_10MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_nopmi_10MHz_NB_IoT 22 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:8; + uint32_t pmi:2; + uint32_t diffcqi1:18; + uint32_t cqi1:4; +} +HLC_subband_cqi_rank1_2A_10MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_rank1_2A_10MHz_NB_IoT 24 + +typedef struct __attribute__((packed)) +{ + uint64_t padding:19; + uint64_t pmi:1; + uint64_t diffcqi2:18; + uint64_t cqi2:4; + uint64_t diffcqi1:18; + uint64_t cqi1:4; +} +HLC_subband_cqi_rank2_2A_10MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_rank2_2A_10MHz_NB_IoT 45 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:10; + uint32_t diffcqi1:18; + uint32_t cqi1:4; +} +HLC_subband_cqi_modes123_10MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_modes123_10MHz_NB_IoT 22 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:11; + uint32_t crnti:16; + uint32_t mcs:5; +} +HLC_subband_cqi_mcs_CBA_10MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_mcs_CBA_10MHz_NB_IoT 21 + +// **********************************************20 MHz*************************************************************************** +typedef struct __attribute__((packed)) +{ + uint32_t padding:2; + uint32_t pmi:26; + uint32_t cqi1:4; +} +wideband_cqi_rank1_2A_20MHz_NB_IoT ; +#define sizeof_wideband_cqi_rank1_2A_20MHz_NB_IoT 20 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:11; + uint32_t pmi:13; + uint32_t cqi2:4; + uint32_t cqi1:4; +} +wideband_cqi_rank2_2A_20MHz_NB_IoT ; +#define sizeof_wideband_cqi_rank2_2A_20MHz_NB_IoT 21 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:2; + uint32_t diffcqi1:26; + uint32_t cqi1:4; +} +HLC_subband_cqi_nopmi_20MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_nopmi_20MHz_NB_IoT 30 + +typedef struct __attribute__((packed)) +{ + // uint32_t padding:12; + uint32_t pmi:2; + uint32_t diffcqi1:26; + uint32_t cqi1:4; +} +HLC_subband_cqi_rank1_2A_20MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_rank1_2A_20MHz_NB_IoT 32 + +typedef struct __attribute__((packed)) +{ + uint64_t padding:3; + uint64_t pmi:1; + uint64_t diffcqi2:26; + uint64_t cqi2:4; + uint64_t diffcqi1:26; + uint64_t cqi1:4; +} +HLC_subband_cqi_rank2_2A_20MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_rank2_2A_20MHz_NB_IoT 61 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:2; + uint32_t diffcqi1:26; + uint32_t cqi1:4; +} +HLC_subband_cqi_modes123_20MHz_NB_IoT; +#define sizeof_HLC_subband_cqi_modes123_20MHz_NB_IoT 30 + +typedef struct __attribute__((packed)) +{ + uint32_t padding:11; + uint32_t crnti:16; + uint32_t mcs:5; +} +HLC_subband_cqi_mcs_CBA_20MHz_NB_IoT; + +#define sizeof_HLC_subband_cqi_mcs_CBA_20MHz_NB_IoT 21 + +#define MAX_CQI_PAYLOAD_NB_IoT (sizeof(HLC_subband_cqi_rank2_2A_20MHz_NB_IoT)*8*20) +#define MAX_CQI_BITS_NB_IoT (sizeof(HLC_subband_cqi_rank2_2A_20MHz_NB_IoT)*8) +#define MAX_CQI_BYTES_NB_IoT (sizeof(HLC_subband_cqi_rank2_2A_20MHz_NB_IoT)) +#define MAX_ACK_PAYLOAD_NB_IoT 18 +#define MAX_RI_PAYLOAD_NB_IoT 6 + +#endif \ No newline at end of file diff --git a/openair1/PHY/TOOLS/lte_phy_scope.c b/openair1/PHY/TOOLS/lte_phy_scope.c index 1b6c1c9153..eb86af9165 100644 --- a/openair1/PHY/TOOLS/lte_phy_scope.c +++ b/openair1/PHY/TOOLS/lte_phy_scope.c @@ -162,7 +162,7 @@ void phy_scope_eNB(FD_lte_phy_scope_enb *form, int16_t **chest_t; int16_t **chest_f; int16_t *pusch_llr; - int16_t *pusch_comp; + int32_t *pusch_comp; int32_t *pucch1_comp; int32_t *pucch1_thres; int32_t *pucch1ab_comp; @@ -200,7 +200,7 @@ void phy_scope_eNB(FD_lte_phy_scope_enb *form, chest_t = (int16_t**) phy_vars_enb->srs_vars[UE_id].srs_ch_estimates[eNB_id]; chest_f = (int16_t**) phy_vars_enb->pusch_vars[UE_id]->drs_ch_estimates[eNB_id]; pusch_llr = (int16_t*) phy_vars_enb->pusch_vars[UE_id]->llr; - pusch_comp = (int16_t*) phy_vars_enb->pusch_vars[UE_id]->rxdataF_comp[0]; + pusch_comp = (int32_t*) phy_vars_enb->pusch_vars[UE_id]->rxdataF_comp[0]; pucch1_comp = (int32_t*) phy_vars_enb->pucch1_stats[UE_id]; pucch1_thres = (int32_t*) phy_vars_enb->pucch1_stats_thres[UE_id]; pucch1ab_comp = (int32_t*) phy_vars_enb->pucch1ab_stats[UE_id]; diff --git a/openair1/PHY/defs_L1_NB_IoT.h b/openair1/PHY/defs_L1_NB_IoT.h new file mode 100644 index 0000000000..b9368b76e3 --- /dev/null +++ b/openair1/PHY/defs_L1_NB_IoT.h @@ -0,0 +1,1031 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file PHY/defs.h + \brief Top-level defines and structure definitions + \author R. Knopp, F. Kaltenberger + \date 2011 + \version 0.1 + \company Eurecom + \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr + \note + \warning +*/ +#ifndef __PHY_DEFS_NB_IOT__H__ +#define __PHY_DEFS_NB_IOT__H__ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include "common_lib.h" +#include "openair2/PHY_INTERFACE/IF_Module_NB_IoT.h" + +//#include +#include "assertions.h" +#ifdef MEX +# define msg mexPrintf +#else +# ifdef OPENAIR2 +# if ENABLE_RAL +# include "collection/hashtable/hashtable.h" +# include "COMMON/ral_messages_types.h" +# include "UTIL/queue.h" +# endif +# include "log.h" +# define msg(aRGS...) LOG_D(PHY, ##aRGS) +# else +# define msg printf +# endif +#endif +//use msg in the real-time thread context +#define msg_nrt printf +//use msg_nrt in the non real-time context (for initialization, ...) +#ifndef malloc16 +# ifdef __AVX2__ +# define malloc16(x) memalign(32,x) +# else +# define malloc16(x) memalign(16,x) +# endif +#endif +#define free16(y,x) free(y) +#define bigmalloc malloc +#define bigmalloc16 malloc16 +#define openair_free(y,x) free((y)) +#define PAGE_SIZE 4096 + +//#ifdef SHRLIBDEV +//extern int rxrescale; +//#define RX_IQRESCALELEN rxrescale +//#else +//#define RX_IQRESCALELEN 15 +//#endif + +//! \brief Allocate \c size bytes of memory on the heap with alignment 16 and zero it afterwards. +//! If no more memory is available, this function will terminate the program with an assertion error. +//****************************************************************************************************** +/* +static inline void* malloc16_clear( size_t size ) +{ +#ifdef __AVX2__ + void* ptr = memalign(32, size); +#else + void* ptr = memalign(16, size); +#endif + DevAssert(ptr); + memset( ptr, 0, size ); + return ptr; +} + +*/ + + +// #define PAGE_MASK 0xfffff000 +// #define virt_to_phys(x) (x) + +// #define openair_sched_exit() exit(-1) + + +// #define max(a,b) ((a)>(b) ? (a) : (b)) +// #define min(a,b) ((a)<(b) ? (a) : (b)) + + +// #define bzero(s,n) (memset((s),0,(n))) + +// #define cmax(a,b) ((a>b) ? (a) : (b)) +// #define cmin(a,b) ((ac) ? (cmax(a,b)) : (c)) + +// /// suppress compiler warning for unused arguments +// #define UNUSED(x) (void)x; + + +#include "PHY/impl_defs_top_NB_IoT.h" +//#include "impl_defs_top.h" +//#include "impl_defs_lte.h" +#include "PHY/impl_defs_lte_NB_IoT.h" + +#include "PHY/TOOLS/time_meas.h" +//#include "PHY/CODING/defs.h" +#include "PHY/CODING/defs_NB_IoT.h" +#include "openair2/PHY_INTERFACE/IF_Module_NB_IoT.h" +//#include "PHY/TOOLS/defs.h" +//#include "platform_types.h" +///#include "openair1/PHY/LTE_TRANSPORT/defs_nb_iot.h" + +////////////////////////////////////////////////////////////////////#ifdef OPENAIR_LTE (check if this is required) + +//#include "PHY/LTE_TRANSPORT/defs.h" +#include "PHY/LTE_TRANSPORT/defs_NB_IoT.h" +#include + +#include "targets/ARCH/COMMON/common_lib.h" +#include "targets/COMMON/openairinterface5g_limits.h" + +#define NUM_DCI_MAX_NB_IoT 32 + +#define NUMBER_OF_eNB_SECTORS_MAX_NB_IoT 3 + +#define NB_BANDS_MAX_NB_IoT 8 + + +#ifdef OCP_FRAMEWORK +#include +#else +typedef enum {normal_txrx_NB_IoT=0,rx_calib_ue_NB_IoT=1,rx_calib_ue_med_NB_IoT=2,rx_calib_ue_byp_NB_IoT=3,debug_prach_NB_IoT=4,no_L2_connect_NB_IoT=5,calib_prach_tx_NB_IoT=6,rx_dump_frame_NB_IoT=7,loop_through_memory_NB_IoT=8} runmode_NB_IoT_t; +#endif +/* +enum transmission_access_mode { + NO_ACCESS=0, + POSTPONED_ACCESS, + CANCELED_ACCESS, + UNKNOWN_ACCESS, + SCHEDULED_ACCESS, + CBA_ACCESS}; + +typedef enum { + eNodeB_3GPP=0, // classical eNodeB function + eNodeB_3GPP_BBU, // eNodeB with NGFI IF5 + NGFI_RCC_IF4p5, // NGFI_RCC (NGFI radio cloud center) + NGFI_RAU_IF4p5, + NGFI_RRU_IF5, // NGFI_RRU (NGFI remote radio-unit,IF5) + NGFI_RRU_IF4p5 // NGFI_RRU (NGFI remote radio-unit,IF4p5) +} eNB_func_t; + +typedef enum { + synch_to_ext_device=0, // synch to RF or Ethernet device + synch_to_other // synch to another source (timer, other CC_id) +} eNB_timing_t; +#endif +*/ +typedef struct UE_SCAN_INFO_NB_IoT_s { + /// 10 best amplitudes (linear) for each pss signals + int32_t amp[3][10]; + /// 10 frequency offsets (kHz) corresponding to best amplitudes, with respect do minimum DL frequency in the band + int32_t freq_offset_Hz[3][10]; + +} UE_SCAN_INFO_NB_IoT_t; + +/// Top-level PHY Data Structure for RN +typedef struct { + /// Module ID indicator for this instance + uint8_t Mod_id; + uint32_t frame; + // phy_vars_eNB_NB_IoT + // phy_vars ue + // cuurently only used to store and forward the PMCH + uint8_t mch_avtive[10]; + uint8_t sync_area[10]; // num SF + NB_IoT_UE_DLSCH_t *dlsch_rn_MCH[10]; + +} PHY_VARS_RN_NB_IoT; +/* +#ifdef OCP_FRAMEWORK +#include +#else +//typedef enum {normal_txrx=0,rx_calib_ue=1,rx_calib_ue_med=2,rx_calib_ue_byp=3,debug_prach=4,no_L2_connect=5,calib_prach_tx=6,rx_dump_frame=7,loop_through_memory=8} runmode_t; +*/ +// enum transmission_access_mode { +// NO_ACCESS=0, +// POSTPONED_ACCESS, +// CANCELED_ACCESS, +// UNKNOWN_ACCESS, +// SCHEDULED_ACCESS, +// CBA_ACCESS}; + +typedef enum { + eNodeB_3GPP_NB_IoT=0, // classical eNodeB function + eNodeB_3GPP_BBU_NB_IoT, // eNodeB with NGFI IF5 + NGFI_RCC_IF4p5_NB_IoT, // NGFI_RCC (NGFI radio cloud center) + NGFI_RAU_IF4p5_NB_IoT, + NGFI_RRU_IF5_NB_IoT, // NGFI_RRU (NGFI remote radio-unit,IF5) + NGFI_RRU_IF4p5_NB_IoT // NGFI_RRU (NGFI remote radio-unit,IF4p5) +} eNB_func_NB_IoT_t; + +typedef enum { + + synch_to_ext_device_NB_IoT=0, // synch to RF or Ethernet device + synch_to_other_NB_IoT // synch to another source (timer, other CC_id) + +} eNB_timing_NB_IoT_t; +////////////////////////////////////////////////////////////////////#endif + + +typedef struct { + + struct PHY_VARS_eNB_NB_IoT_s *eNB; + NB_IoT_eNB_NDLSCH_t *dlsch; + int G; + +} te_params_NB_IoT; + + +typedef struct { + + struct PHY_VARS_eNB_NB_IoT_s *eNB; + int UE_id; + int harq_pid; + int llr8_flag; + int ret; + +} td_params_NB_IoT; + + +/// Context data structure for RX/TX portion of subframe processing +typedef struct { + /// timestamp transmitted to HW + openair0_timestamp timestamp_tx; + /// subframe to act upon for transmission + int subframe_tx; + /// subframe to act upon for reception + int subframe_rx; + /// frame to act upon for transmission + int frame_tx; + /// frame to act upon for reception + int frame_rx; + /// \brief Instance count for RXn-TXnp4 processing thread. + /// \internal This variable is protected by \ref mutex_rxtx. + int instance_cnt_rxtx; + /// pthread structure for RXn-TXnp4 processing thread + pthread_t pthread_rxtx; + /// pthread attributes for RXn-TXnp4 processing thread + pthread_attr_t attr_rxtx; + /// condition variable for tx processing thread + pthread_cond_t cond_rxtx; + /// mutex for RXn-TXnp4 processing thread + pthread_mutex_t mutex_rxtx; + /// scheduling parameters for RXn-TXnp4 thread + struct sched_param sched_param_rxtx; + /// NB-IoT for IF_Module + pthread_t pthread_l2; + pthread_cond_t cond_l2; + pthread_mutex_t mutex_l2; + int instance_cnt_l2; + pthread_attr_t attr_l2; + +} eNB_rxtx_proc_NB_IoT_t; +/* +typedef struct { + struct PHY_VARS_eNB_NB_IoT_s *eNB; + int UE_id; + int harq_pid; + int llr8_flag; + int ret; +} td_params; + +typedef struct { + struct PHY_VARS_eNB_NB_IoT_s *eNB; + LTE_eNB_DLSCH_t *dlsch; + int G; +} te_params; +*/ + +/// Context data structure for eNB subframe processing +typedef struct eNB_proc_NB_IoT_t_s { + /// thread index + int thread_index; + /// timestamp received from HW + openair0_timestamp timestamp_rx; + /// timestamp to send to "slave rru" + openair0_timestamp timestamp_tx; + /// subframe to act upon for reception + int subframe_rx; + /// symbol mask for IF4p5 reception per subframe + uint32_t symbol_mask[10]; + /// subframe to act upon for PRACH + int subframe_prach; + /// frame to act upon for reception + int frame_rx; + /// frame to act upon for transmission + int frame_tx; + /// frame offset for secondary eNBs (to correct for frame asynchronism at startup) + int frame_offset; + /// frame to act upon for PRACH + int frame_prach; + /// \internal This variable is protected by \ref mutex_fep. + int instance_cnt_fep; + /// \internal This variable is protected by \ref mutex_td. + int instance_cnt_td; + /// \internal This variable is protected by \ref mutex_te. + int instance_cnt_te; + /// \brief Instance count for FH processing thread. + /// \internal This variable is protected by \ref mutex_FH. + int instance_cnt_FH; + /// \brief Instance count for rx processing thread. + /// \internal This variable is protected by \ref mutex_prach. + int instance_cnt_prach; + // instance count for over-the-air eNB synchronization + int instance_cnt_synch; + /// \internal This variable is protected by \ref mutex_asynch_rxtx. + int instance_cnt_asynch_rxtx; + /// pthread structure for FH processing thread + pthread_t pthread_FH; + /// pthread structure for eNB single processing thread + pthread_t pthread_single; + /// pthread structure for asychronous RX/TX processing thread + pthread_t pthread_asynch_rxtx; + /// flag to indicate first RX acquisition + int first_rx; + /// flag to indicate first TX transmission + int first_tx; + /// pthread attributes for parallel fep thread + pthread_attr_t attr_fep; + /// pthread attributes for parallel turbo-decoder thread + pthread_attr_t attr_td; + /// pthread attributes for parallel turbo-encoder thread + pthread_attr_t attr_te; + /// pthread attributes for FH processing thread + pthread_attr_t attr_FH; + /// pthread attributes for single eNB processing thread + pthread_attr_t attr_single; + /// pthread attributes for prach processing thread + pthread_attr_t attr_prach; + /// pthread attributes for over-the-air synch thread + pthread_attr_t attr_synch; + /// pthread attributes for asynchronous RX thread + pthread_attr_t attr_asynch_rxtx; + /// scheduling parameters for parallel fep thread + struct sched_param sched_param_fep; + /// scheduling parameters for parallel turbo-decoder thread + struct sched_param sched_param_td; + /// scheduling parameters for parallel turbo-encoder thread + struct sched_param sched_param_te; + /// scheduling parameters for FH thread + struct sched_param sched_param_FH; + /// scheduling parameters for single eNB thread + struct sched_param sched_param_single; + /// scheduling parameters for prach thread + struct sched_param sched_param_prach; + /// scheduling parameters for over-the-air synchronization thread + struct sched_param sched_param_synch; + /// scheduling parameters for asynch_rxtx thread + struct sched_param sched_param_asynch_rxtx; + /// pthread structure for parallel fep thread + pthread_t pthread_fep; + /// pthread structure for parallel turbo-decoder thread + pthread_t pthread_td; + /// pthread structure for parallel turbo-encoder thread + pthread_t pthread_te; + /// pthread structure for PRACH thread + pthread_t pthread_prach; + /// pthread structure for eNB synch thread + pthread_t pthread_synch; + /// condition variable for parallel fep thread + pthread_cond_t cond_fep; + /// condition variable for parallel turbo-decoder thread + pthread_cond_t cond_td; + /// condition variable for parallel turbo-encoder thread + pthread_cond_t cond_te; + /// condition variable for FH thread + pthread_cond_t cond_FH; + /// condition variable for PRACH processing thread; + pthread_cond_t cond_prach; + // condition variable for over-the-air eNB synchronization + pthread_cond_t cond_synch; + /// condition variable for asynch RX/TX thread + pthread_cond_t cond_asynch_rxtx; + /// mutex for RU access to processing (NPDSCH/PUSCH) + pthread_mutex_t mutex_RU; + /// mutex for parallel fep thread + pthread_mutex_t mutex_fep; + /// mutex for parallel turbo-decoder thread + pthread_mutex_t mutex_td; + /// mutex for parallel turbo-encoder thread + pthread_mutex_t mutex_te; + /// mutex for FH + pthread_mutex_t mutex_FH; + /// mutex for PRACH thread + pthread_mutex_t mutex_prach; + // mutex for over-the-air eNB synchronization + pthread_mutex_t mutex_synch; + /// mutex for RU access to NB-IoT processing (NPRACH) + pthread_mutex_t mutex_RU_PRACH; + /// mutex for asynch RX/TX thread + pthread_mutex_t mutex_asynch_rxtx; + /// mask for RUs serving nbiot (NPDSCH/NPUSCH) + int RU_mask; + /// mask for RUs serving nbiot (PRACH) + int RU_mask_prach; +#ifdef Rel14 + /// mask for RUs serving eNB (PRACH) + int RU_mask_prach_br; +#endif + /// parameters for turbo-decoding worker thread + td_params_NB_IoT tdp; + /// parameters for turbo-encoding worker thread + te_params_NB_IoT tep; + /// number of slave threads + int num_slaves; + /// array of pointers to slaves + struct eNB_proc_NB_IoT_t_s **slave_proc; + /// set of scheduling variables RXn-TXnp4 threads + // newly added for NB_IoT + eNB_rxtx_proc_NB_IoT_t proc_rxtx[2]; + +} eNB_proc_NB_IoT_t; + + +/// Context data structure for RX/TX portion of subframe processing +typedef struct { + /// index of the current UE RX/TX proc + int proc_id; + /// timestamp transmitted to HW + openair0_timestamp timestamp_tx; + /// subframe to act upon for transmission + int subframe_tx; + /// subframe to act upon for reception + int subframe_rx; + /// frame to act upon for transmission + int frame_tx; + /// frame to act upon for reception + int frame_rx; + /// \brief Instance count for RXn-TXnp4 processing thread. + /// \internal This variable is protected by \ref mutex_rxtx. + int instance_cnt_rxtx; + /// pthread structure for RXn-TXnp4 processing thread + pthread_t pthread_rxtx; + /// pthread attributes for RXn-TXnp4 processing thread + pthread_attr_t attr_rxtx; + /// condition variable for tx processing thread + pthread_cond_t cond_rxtx; + /// mutex for RXn-TXnp4 processing thread + pthread_mutex_t mutex_rxtx; + /// scheduling parameters for RXn-TXnp4 thread + struct sched_param sched_param_rxtx; + /// + int sub_frame_start; + /// + int sub_frame_step; + /// + unsigned long long gotIQs; + +} UE_rxtx_proc_NB_IoT_t; + +/// Context data structure for eNB subframe processing +typedef struct { + /// Last RX timestamp + openair0_timestamp timestamp_rx; + /// pthread attributes for main UE thread + pthread_attr_t attr_ue; + /// scheduling parameters for main UE thread + struct sched_param sched_param_ue; + /// pthread descriptor main UE thread + pthread_t pthread_ue; + /// \brief Instance count for synch thread. + /// \internal This variable is protected by \ref mutex_synch. + int instance_cnt_synch; + /// pthread attributes for synch processing thread + pthread_attr_t attr_synch; + /// scheduling parameters for synch thread + struct sched_param sched_param_synch; + /// pthread descriptor synch thread + pthread_t pthread_synch; + /// condition variable for UE synch thread; + pthread_cond_t cond_synch; + /// mutex for UE synch thread + pthread_mutex_t mutex_synch; + /// set of scheduling variables RXn-TXnp4 threads + UE_rxtx_proc_NB_IoT_t proc_rxtx[2]; + +} UE_proc_NB_IoT_t; + + + +/// Top-level PHY Data Structure for eNB +typedef struct PHY_VARS_eNB_NB_IoT_s { + /// Module ID indicator for this instance + module_id_t Mod_id; + uint8_t configured; + eNB_proc_NB_IoT_t proc; + int num_RU; + RU_t *RU_list[MAX_NUM_RU_PER_eNB]; + /// Ethernet parameters for northbound midhaul interface (L1 to Mac) + eth_params_t eth_params_n; + /// Ethernet parameters for fronthaul interface (upper L1 to Radio head) + eth_params_t eth_params; + int single_thread_flag; + openair0_rf_map rf_map; + int abstraction_flag; + openair0_timestamp ts_offset; + // indicator for synchronization state of eNB + int in_synch; + // indicator for master/slave (RRU) + int is_slave; + // indicator for precoding function (eNB,3GPP_eNB_BBU) + int do_precoding; + IF_Module_NB_IoT_t *if_inst_NB_IoT; + UL_IND_NB_IoT_t UL_INFO_NB_IoT; + pthread_mutex_t UL_INFO_mutex; + void (*do_prach)(struct PHY_VARS_eNB_NB_IoT_s *eNB,int frame,int subframe); + void (*fep)(struct PHY_VARS_eNB_NB_IoT_s *eNB,eNB_rxtx_proc_NB_IoT_t *proc); + int (*td)(struct PHY_VARS_eNB_NB_IoT_s *eNB,int UE_id,int harq_pid,int llr8_flag); + int (*te)(struct PHY_VARS_eNB_NB_IoT_s *,uint8_t *,uint8_t,NB_IoT_eNB_DLSCH_t *,int,uint8_t,time_stats_t *,time_stats_t *,time_stats_t *); + void (*proc_uespec_rx)(struct PHY_VARS_eNB_NB_IoT_s *eNB,eNB_rxtx_proc_NB_IoT_t *proc,const relaying_type_t_NB_IoT r_type); + void (*proc_tx)(struct PHY_VARS_eNB_NB_IoT_s *eNB,eNB_rxtx_proc_NB_IoT_t *proc,relaying_type_t_NB_IoT r_type,PHY_VARS_RN_NB_IoT *rn); + void (*tx_fh)(struct PHY_VARS_eNB_NB_IoT_s *eNB,eNB_rxtx_proc_NB_IoT_t *proc); + void (*rx_fh)(struct PHY_VARS_eNB_NB_IoT_s *eNB,int *frame, int *subframe); + int (*start_rf)(struct PHY_VARS_eNB_NB_IoT_s *eNB); + int (*start_if)(struct PHY_VARS_eNB_NB_IoT_s *eNB); + void (*fh_asynch)(struct PHY_VARS_eNB_NB_IoT_s *eNB,int *frame, int *subframe); + uint8_t local_flag; + uint32_t rx_total_gain_dB; + NB_IoT_DL_FRAME_PARMS frame_parms; + PHY_MEASUREMENTS_eNB_NB_IoT measurements[NUMBER_OF_eNB_SECTORS_MAX_NB_IoT]; /// Measurement variables + NB_IoT_eNB_COMMON common_vars; + NB_IoT_eNB_SRS srs_vars[NUMBER_OF_UE_MAX_NB_IoT]; + NB_IoT_eNB_PBCH pbch; + NB_IoT_eNB_PUSCH *pusch_vars[NUMBER_OF_UE_MAX_NB_IoT]; + NB_IoT_eNB_PRACH prach_vars; + //LTE_eNB_DLSCH_t *dlsch[NUMBER_OF_UE_MAX_NB_IoT][2]; // Nusers times two spatial streams + NB_IoT_eNB_NULSCH_t *ulsch[NUMBER_OF_UE_MAX_NB_IoT+1]; // Nusers + number of RA (the ulsch[0] contains RAR) + //LTE_eNB_DLSCH_t *dlsch_SI,*dlsch_ra; + //LTE_eNB_DLSCH_t *dlsch_MCH; + NB_IoT_eNB_UE_stats UE_stats[NUMBER_OF_UE_MAX_NB_IoT]; + //LTE_eNB_UE_stats *UE_stats_ptr[NUMBER_OF_UE_MAX_NB_IoT]; + /// cell-specific reference symbols + uint32_t lte_gold_table_NB_IoT[20][2][14]; + /// UE-specific reference symbols (p=5), TM 7 + uint32_t lte_gold_uespec_port5_table[NUMBER_OF_UE_MAX_NB_IoT][20][38]; + /// UE-specific reference symbols (p=7...14), TM 8/9/10 + uint32_t lte_gold_uespec_table[2][20][2][21]; + /// mbsfn reference symbols + uint32_t lte_gold_mbsfn_table[10][3][42]; + /// + uint32_t X_u[64][839]; + /// + uint8_t pbch_pdu[4]; //PBCH_PDU_SIZE + /// + char eNB_generate_rar; + /// Indicator set to 0 after first SR + uint8_t first_sr[NUMBER_OF_UE_MAX_NB_IoT]; + + uint32_t max_peak_val; + /// + int max_eNB_id, max_sync_pos; + /// + int N_TA_offset; ///timing offset used in TDD + /// \brief sinr for all subcarriers of the current link (used only for abstraction). + /// first index: ? [0..N_RB_DL*12[ + double *sinr_dB; + /// N0 (used for abstraction) + double N0; + /// + unsigned char first_run_timing_advance[NUMBER_OF_UE_MAX_NB_IoT]; + unsigned char first_run_I0_measurements; + + unsigned char cooperation_flag; // for cooperative communication + + unsigned char is_secondary_eNB; // primary by default + unsigned char is_init_sync; /// Flag to tell if initial synchronization is performed. This affects how often the secondary eNB will listen to the PSS from the primary system. + unsigned char has_valid_precoder; /// Flag to tell if secondary eNB has channel estimates to create NULL-beams from, and this B/F vector is created. + unsigned char PeNB_id; /// id of Primary eNB + int rx_offset; /// Timing offset (used if is_secondary_eNB) + + /// hold the precoder for NULL beam to the primary user + int **dl_precoder_SeNB[3]; + /// + char log2_maxp; /// holds the maximum channel/precoder coefficient + /// if ==0 enables phy only test mode + int mac_enabled; + /// For emulation only (used by UE abstraction to retrieve DCI) + uint8_t num_common_dci[2]; // num_dci in even/odd subframes + /// + uint8_t num_ue_spec_dci[2]; // num_dci in even/odd subframes + /// + DCI_ALLOC_NB_IoT_t dci_alloc[2][NUM_DCI_MAX_NB_IoT]; // dci_alloc from even/odd subframes + ///////////// + // PDSCH Variables + PDSCH_CONFIG_DEDICATED_NB_IoT pdsch_config_dedicated[NUMBER_OF_UE_MAX_NB_IoT]; + // PUSCH Variables + PUSCH_CONFIG_DEDICATED_NB_IoT pusch_config_dedicated[NUMBER_OF_UE_MAX_NB_IoT]; + // PUCCH variables + PUCCH_CONFIG_DEDICATED_NB_IoT pucch_config_dedicated[NUMBER_OF_UE_MAX_NB_IoT]; + // UL-POWER-Control + UL_POWER_CONTROL_DEDICATED_NB_IoT ul_power_control_dedicated[NUMBER_OF_UE_MAX_NB_IoT]; + // TPC + TPC_PDCCH_CONFIG_NB_IoT tpc_pdcch_config_pucch[NUMBER_OF_UE_MAX_NB_IoT]; + /// + TPC_PDCCH_CONFIG_NB_IoT tpc_pdcch_config_pusch[NUMBER_OF_UE_MAX_NB_IoT]; + // CQI reporting + CQI_REPORT_CONFIG_NB_IoT cqi_report_config[NUMBER_OF_UE_MAX_NB_IoT]; + // SRS Variables + SOUNDINGRS_UL_CONFIG_DEDICATED_NB_IoT soundingrs_ul_config_dedicated[NUMBER_OF_UE_MAX_NB_IoT]; + /// + uint8_t ncs_cell[20][7]; + // Scheduling Request Config + SCHEDULING_REQUEST_CONFIG_NB_IoT scheduling_request_config[NUMBER_OF_UE_MAX_NB_IoT]; + // Transmission mode per UE + uint8_t transmission_mode[NUMBER_OF_UE_MAX_NB_IoT]; + /// cba_last successful reception for each group, used for collision detection + uint8_t cba_last_reception[4]; + // Pointers for active physicalConfigDedicated to be applied in current subframe + struct PhysicalConfigDedicated *physicalConfigDedicated[NUMBER_OF_UE_MAX_NB_IoT]; + //Pointers for actve physicalConfigDedicated for NB-IoT to be applied in current subframe + struct PhysicalConfigDedicated_NB_r13 *phy_config_dedicated_NB_IoT[NUMBER_OF_UE_MAX_NB_IoT]; + /// + uint32_t rb_mask_ul[4]; + /// Information regarding TM5 + MU_MIMO_mode_NB_IoT mu_mimo_mode[NUMBER_OF_UE_MAX_NB_IoT]; + /// target_ue_dl_mcs : only for debug purposes + uint32_t target_ue_dl_mcs; + /// target_ue_ul_mcs : only for debug purposes + uint32_t target_ue_ul_mcs; + /// target_ue_dl_rballoc : only for debug purposes + uint32_t ue_dl_rb_alloc; + /// target ul PRBs : only for debug + uint32_t ue_ul_nb_rb; + ///check for Total Transmissions + uint32_t check_for_total_transmissions; + ///check for MU-MIMO Transmissions + uint32_t check_for_MUMIMO_transmissions; + ///check for SU-MIMO Transmissions + uint32_t check_for_SUMIMO_transmissions; + ///check for FULL MU-MIMO Transmissions + uint32_t FULL_MUMIMO_transmissions; + /// Counter for total bitrate, bits and throughput in downlink + uint32_t total_dlsch_bitrate; + /// + uint32_t total_transmitted_bits; + /// + uint32_t total_system_throughput; + /// + int hw_timing_advance; + /// + time_stats_t phy_proc; + time_stats_t phy_proc_tx; + time_stats_t phy_proc_rx; + time_stats_t rx_prach; + + time_stats_t ofdm_mod_stats; + time_stats_t dlsch_encoding_stats; + time_stats_t dlsch_modulation_stats; + time_stats_t dlsch_scrambling_stats; + time_stats_t dlsch_rate_matching_stats; + time_stats_t dlsch_turbo_encoding_stats; + time_stats_t dlsch_interleaving_stats; + + time_stats_t ofdm_demod_stats; + time_stats_t rx_dft_stats; + time_stats_t ulsch_channel_estimation_stats; + time_stats_t ulsch_freq_offset_estimation_stats; + time_stats_t ulsch_decoding_stats; + time_stats_t ulsch_demodulation_stats; + time_stats_t ulsch_rate_unmatching_stats; + time_stats_t ulsch_turbo_decoding_stats; + time_stats_t ulsch_deinterleaving_stats; + time_stats_t ulsch_demultiplexing_stats; + time_stats_t ulsch_llr_stats; + time_stats_t ulsch_tc_init_stats; + time_stats_t ulsch_tc_alpha_stats; + time_stats_t ulsch_tc_beta_stats; + time_stats_t ulsch_tc_gamma_stats; + time_stats_t ulsch_tc_ext_stats; + time_stats_t ulsch_tc_intl1_stats; + time_stats_t ulsch_tc_intl2_stats; + + #ifdef LOCALIZATION + /// time state for localization + time_stats_t localization_stats; + #endif + + int32_t pucch1_stats_cnt[NUMBER_OF_UE_MAX_NB_IoT][10]; + int32_t pucch1_stats[NUMBER_OF_UE_MAX_NB_IoT][10*1024]; + int32_t pucch1_stats_thres[NUMBER_OF_UE_MAX_NB_IoT][10*1024]; + int32_t pucch1ab_stats_cnt[NUMBER_OF_UE_MAX_NB_IoT][10]; + int32_t pucch1ab_stats[NUMBER_OF_UE_MAX_NB_IoT][2*10*1024]; + int32_t pusch_stats_rb[NUMBER_OF_UE_MAX_NB_IoT][10240]; + int32_t pusch_stats_round[NUMBER_OF_UE_MAX_NB_IoT][10240]; + int32_t pusch_stats_mcs[NUMBER_OF_UE_MAX_NB_IoT][10240]; + int32_t pusch_stats_bsr[NUMBER_OF_UE_MAX_NB_IoT][10240]; + int32_t pusch_stats_BO[NUMBER_OF_UE_MAX_NB_IoT][10240]; + + /// RF and Interface devices per CC + openair0_device rfdevice; + openair0_device ifdevice; + /// Pointer for ifdevice buffer struct + if_buffer_t ifbuffer; + + //------------------------ + // NB-IoT + //------------------------ + + /* + * NUMBER_OF_UE_MAX_NB_IoT maybe in the future should be dynamic because could be very large and the memory may explode + * (is almost the indication of the number of UE context that we are storing at PHY layer) + * + * reasoning: the following data structure (ndlsch, nulsch ecc..) are used to store the context that should be transmitted in at least n+4 subframe later + * (the minimum interval between NPUSCH and the ACK for this) + * the problem is that in NB_IoT the ACK for the UPLINK is contained in the DCI through the NDI field (if this value change from the previous one then it means ACK) + * but may we could schedule this DCI long time later so may lots of contents shuld be stored (there is no concept of phich channel in NB-IoT) + * For the DL transmission the UE send a proper ACK/NACK message + * + * *the HARQ process should be killed when the NDI change + * + * *In the Structure for nulsch we should also store the information related to the subframe (because each time we should read it and understand what should be done + * in that subframe) + * + */ + + + /* + * TIMING + * the entire transmission and scheduling are done for the "subframe" concept but the subframe = proc->subframe_tx (that in reality is the subframe_rx +4) + * (see USER/lte-enb/wakeup_rxtx ) + * + * Related to FAPI: + * DCI and DL_CONFIG.request (also more that 1) and MAC_PDU are transmitted in the same subframe (our assumption) so will be all contained in the schedule_response getting from the scheduler + * DCI0 and UL_CONFIG.request are transmitted in the same subframe (our assumption) so contained in the schedule_response + * + */ + + //TODO: check what should be NUMBER_OF_UE_MAX_NB_IoT value + NB_IoT_eNB_NPBCH_t *npbch; + NB_IoT_eNB_NPDCCH_t *npdcch[NUMBER_OF_UE_MAX_NB_IoT]; + NB_IoT_eNB_NDLSCH_t *ndlsch[NUMBER_OF_UE_MAX_NB_IoT][2]; + NB_IoT_eNB_NULSCH_t *nulsch[NUMBER_OF_UE_MAX_NB_IoT+1]; //nulsch[0] contains the RAR + NB_IoT_eNB_NDLSCH_t *ndlsch_SI,*ndlsch_ra, *ndlsch_SIB1; + + NB_IoT_DL_FRAME_PARMS frame_parms_NB_IoT; + // DCI for at most 2 DCI pdus + DCI_PDU_NB_IoT *DCI_pdu; + + + +} PHY_VARS_eNB_NB_IoT; + +//#define debug_msg if (((mac_xface->frame%100) == 0) || (mac_xface->frame < 50)) msg + +/// Top-level PHY Data Structure for UE +typedef struct { + /// \brief Module ID indicator for this instance + uint8_t Mod_id; + /// \brief Mapping of CC_id antennas to cards + openair0_rf_map rf_map; + //uint8_t local_flag; + /// \brief Indicator of current run mode of UE (normal_txrx, rx_calib_ue, no_L2_connect, debug_prach) + runmode_NB_IoT_t mode; + /// \brief Indicator that UE should perform band scanning + int UE_scan; + /// \brief Indicator that UE should perform coarse scanning around carrier + int UE_scan_carrier; + /// \brief Indicator that UE is synchronized to an eNB + int is_synchronized; + /// Data structure for UE process scheduling + UE_proc_NB_IoT_t proc; + /// Flag to indicate the UE shouldn't do timing correction at all + int no_timing_correction; + /// \brief Total gain of the TX chain (16-bit baseband I/Q to antenna) + uint32_t tx_total_gain_dB; + /// \brief Total gain of the RX chain (antenna to baseband I/Q) This is a function of rx_gain_mode (and the corresponding gain) and the rx_gain of the card. + uint32_t rx_total_gain_dB; + /// \brief Total gains with maximum RF gain stage (ExpressMIMO2/Lime) + uint32_t rx_gain_max[4]; + /// \brief Total gains with medium RF gain stage (ExpressMIMO2/Lime) + uint32_t rx_gain_med[4]; + /// \brief Total gains with bypassed RF gain stage (ExpressMIMO2/Lime) + uint32_t rx_gain_byp[4]; + /// \brief Current transmit power + int16_t tx_power_dBm[10]; + /// \brief Total number of REs in current transmission + int tx_total_RE[10]; + /// \brief Maximum transmit power + int8_t tx_power_max_dBm; + /// \brief Number of eNB seen by UE + uint8_t n_connected_eNB; + /// \brief indicator that Handover procedure has been initiated + uint8_t ho_initiated; + /// \brief indicator that Handover procedure has been triggered + uint8_t ho_triggered; + /// \brief Measurement variables. + PHY_MEASUREMENTS_NB_IoT measurements; + NB_IoT_DL_FRAME_PARMS frame_parms; + /// \brief Frame parame before ho used to recover if ho fails. + NB_IoT_DL_FRAME_PARMS frame_parms_before_ho; + NB_IoT_UE_COMMON common_vars; + + NB_IoT_UE_PDSCH *pdsch_vars[2][NUMBER_OF_CONNECTED_eNB_MAX+1]; // two RxTx Threads + NB_IoT_UE_DLSCH_t *dlsch[2][NUMBER_OF_CONNECTED_eNB_MAX][2]; // two RxTx Threads + //Paging parameters + uint32_t IMSImod1024; + uint32_t PF; + uint32_t PO; + // For abstraction-purposes only + uint8_t sr[10]; + uint8_t pucch_sel[10]; + uint8_t pucch_payload[22]; + //UE_MODE_t UE_mode[NUMBER_OF_CONNECTED_eNB_MAX]; + //cell-specific reference symbols + uint32_t lte_gold_table[7][20][2][14]; + //UE-specific reference symbols (p=5), TM 7 + uint32_t lte_gold_uespec_port5_table[20][38]; + //ue-specific reference symbols + uint32_t lte_gold_uespec_table[2][20][2][21]; + //mbsfn reference symbols + uint32_t lte_gold_mbsfn_table[10][3][42]; + /// + uint32_t X_u[64][839]; + /// + uint32_t high_speed_flag; + uint32_t perfect_ce; + int16_t ch_est_alpha; + int generate_ul_signal[NUMBER_OF_CONNECTED_eNB_MAX]; + /// + UE_SCAN_INFO_NB_IoT_t scan_info[NB_BANDS_MAX_NB_IoT]; + /// + char ulsch_no_allocation_counter[NUMBER_OF_CONNECTED_eNB_MAX]; + +/* + + unsigned char ulsch_Msg3_active[NUMBER_OF_CONNECTED_eNB_MAX]; + uint32_t ulsch_Msg3_frame[NUMBER_OF_CONNECTED_eNB_MAX]; + unsigned char ulsch_Msg3_subframe[NUMBER_OF_CONNECTED_eNB_MAX]; + PRACH_RESOURCES_t *prach_resources[NUMBER_OF_CONNECTED_eNB_MAX]; + int turbo_iterations, turbo_cntl_iterations; + /// \brief ?. + /// - first index: eNB [0..NUMBER_OF_CONNECTED_eNB_MAX[ (hard coded) + uint32_t total_TBS[NUMBER_OF_CONNECTED_eNB_MAX]; + /// \brief ?. + /// - first index: eNB [0..NUMBER_OF_CONNECTED_eNB_MAX[ (hard coded) + uint32_t total_TBS_last[NUMBER_OF_CONNECTED_eNB_MAX]; + /// \brief ?. + /// - first index: eNB [0..NUMBER_OF_CONNECTED_eNB_MAX[ (hard coded) + uint32_t bitrate[NUMBER_OF_CONNECTED_eNB_MAX]; + /// \brief ?. + /// - first index: eNB [0..NUMBER_OF_CONNECTED_eNB_MAX[ (hard coded) + uint32_t total_received_bits[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_errors[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_errors_last[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_received[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_received_last[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_fer[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_SI_received[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_SI_errors[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_ra_received[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_ra_errors[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_p_received[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_p_errors[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mch_received_sf[MAX_MBSFN_AREA][NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mch_received[NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mcch_received[MAX_MBSFN_AREA][NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mtch_received[MAX_MBSFN_AREA][NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mcch_errors[MAX_MBSFN_AREA][NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mtch_errors[MAX_MBSFN_AREA][NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mcch_trials[MAX_MBSFN_AREA][NUMBER_OF_CONNECTED_eNB_MAX]; + int dlsch_mtch_trials[MAX_MBSFN_AREA][NUMBER_OF_CONNECTED_eNB_MAX]; + int current_dlsch_cqi[NUMBER_OF_CONNECTED_eNB_MAX]; + unsigned char first_run_timing_advance[NUMBER_OF_CONNECTED_eNB_MAX]; + uint8_t generate_prach; + uint8_t prach_cnt; + uint8_t prach_PreambleIndex; + // uint8_t prach_timer; + uint8_t decode_SIB; + uint8_t decode_MIB; + int rx_offset; /// Timing offset + int rx_offset_diff; /// Timing adjustment for ofdm symbol0 on HW USRP + int timing_advance; ///timing advance signalled from eNB + int hw_timing_advance; + int N_TA_offset; ///timing offset used in TDD + /// Flag to tell if UE is secondary user (cognitive mode) + unsigned char is_secondary_ue; + /// Flag to tell if secondary eNB has channel estimates to create NULL-beams from. + unsigned char has_valid_precoder; + /// hold the precoder for NULL beam to the primary eNB + int **ul_precoder_S_UE; + /// holds the maximum channel/precoder coefficient + char log2_maxp; +*/ + /// if ==0 enables phy only test mode + int mac_enabled; + /// Flag to initialize averaging of PHY measurements + int init_averaging; + /// \brief sinr for all subcarriers of the current link (used only for abstraction). + /// - first index: ? [0..12*N_RB_DL[ + double *sinr_dB; + /// \brief sinr for all subcarriers of first symbol for the CQI Calculation. + /// - first index: ? [0..12*N_RB_DL[ + double *sinr_CQI_dB; + /// sinr_effective used for CQI calulcation + double sinr_eff; + /// N0 (used for abstraction) + double N0; +/* + /// PDSCH Varaibles + PDSCH_CONFIG_DEDICATED pdsch_config_dedicated[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// PUSCH Varaibles + PUSCH_CONFIG_DEDICATED pusch_config_dedicated[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// PUSCH contention-based access vars + PUSCH_CA_CONFIG_DEDICATED pusch_ca_config_dedicated[NUMBER_OF_eNB_MAX]; // lola + + /// PUCCH variables + + PUCCH_CONFIG_DEDICATED pucch_config_dedicated[NUMBER_OF_CONNECTED_eNB_MAX]; + + uint8_t ncs_cell[20][7]; + + /// UL-POWER-Control + UL_POWER_CONTROL_DEDICATED ul_power_control_dedicated[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// TPC + TPC_PDCCH_CONFIG tpc_pdcch_config_pucch[NUMBER_OF_CONNECTED_eNB_MAX]; + TPC_PDCCH_CONFIG tpc_pdcch_config_pusch[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// CQI reporting + CQI_REPORT_CONFIG cqi_report_config[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// SRS Variables + SOUNDINGRS_UL_CONFIG_DEDICATED soundingrs_ul_config_dedicated[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// Scheduling Request Config + SCHEDULING_REQUEST_CONFIG scheduling_request_config[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// Transmission mode per eNB + uint8_t transmission_mode[NUMBER_OF_CONNECTED_eNB_MAX]; + + time_stats_t phy_proc; + time_stats_t phy_proc_tx; + time_stats_t phy_proc_rx[2]; + + uint32_t use_ia_receiver; + + time_stats_t ofdm_mod_stats; + time_stats_t ulsch_encoding_stats; + time_stats_t ulsch_modulation_stats; + time_stats_t ulsch_segmentation_stats; + time_stats_t ulsch_rate_matching_stats; + time_stats_t ulsch_turbo_encoding_stats; + time_stats_t ulsch_interleaving_stats; + time_stats_t ulsch_multiplexing_stats; + + time_stats_t generic_stat; + time_stats_t pdsch_procedures_stat; + time_stats_t dlsch_procedures_stat; + + time_stats_t ofdm_demod_stats; + time_stats_t dlsch_rx_pdcch_stats; + time_stats_t rx_dft_stats; + time_stats_t dlsch_channel_estimation_stats; + time_stats_t dlsch_freq_offset_estimation_stats; + time_stats_t dlsch_decoding_stats[2]; + time_stats_t dlsch_demodulation_stats; + time_stats_t dlsch_rate_unmatching_stats; + time_stats_t dlsch_turbo_decoding_stats; + time_stats_t dlsch_deinterleaving_stats; + time_stats_t dlsch_llr_stats; + time_stats_t dlsch_unscrambling_stats; + time_stats_t dlsch_rate_matching_stats; + time_stats_t dlsch_turbo_encoding_stats; + time_stats_t dlsch_interleaving_stats; + time_stats_t dlsch_tc_init_stats; + time_stats_t dlsch_tc_alpha_stats; + time_stats_t dlsch_tc_beta_stats; + time_stats_t dlsch_tc_gamma_stats; + time_stats_t dlsch_tc_ext_stats; + time_stats_t dlsch_tc_intl1_stats; + time_stats_t dlsch_tc_intl2_stats; + time_stats_t tx_prach; + + /// RF and Interface devices per CC + openair0_device rfdevice; + time_stats_t dlsch_encoding_SIC_stats; + time_stats_t dlsch_scrambling_SIC_stats; + time_stats_t dlsch_modulation_SIC_stats; + time_stats_t dlsch_llr_stripping_unit_SIC_stats; + time_stats_t dlsch_unscrambling_SIC_stats; + +#if ENABLE_RAL + hash_table_t *ral_thresholds_timed; + SLIST_HEAD(ral_thresholds_gen_poll_s, ral_threshold_phy_t) ral_thresholds_gen_polled[RAL_LINK_PARAM_GEN_MAX]; + SLIST_HEAD(ral_thresholds_lte_poll_s, ral_threshold_phy_t) ral_thresholds_lte_polled[RAL_LINK_PARAM_LTE_MAX]; +#endif +*/ +} PHY_VARS_UE_NB_IoT; + + + +#include "PHY/INIT/defs_NB_IoT.h" +#include "PHY/LTE_REFSIG/defs_NB_IoT.h" +#include "PHY/LTE_TRANSPORT/proto_NB_IoT.h" +#endif // __PHY_DEFS__H__ diff --git a/openair1/PHY/impl_defs_lte_NB_IoT.h b/openair1/PHY/impl_defs_lte_NB_IoT.h new file mode 100644 index 0000000000..7ae6f59c7e --- /dev/null +++ b/openair1/PHY/impl_defs_lte_NB_IoT.h @@ -0,0 +1,813 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file PHY/impl_defs_lte.h +* \brief LTE Physical channel configuration and variable structure definitions +* \author R. Knopp, F. Kaltenberger +* \date 2011 +* \version 0.1 +* \company Eurecom +* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr +* \note +* \warning +*/ + +#ifndef __PHY_IMPL_DEFS_NB_IOT__H__ +#define __PHY_IMPL_DEFS_NB_IOT__H__ + +#include "types_NB_IoT.h" +//#include "defs.h" + +typedef enum {TDD_NB_IoT=1,FDD_NB_IoT=0} NB_IoT_frame_type_t; +typedef enum {EXTENDED_NB_IoT=1,NORMAL_NB_IoT=0} NB_IoT_prefix_type_t; +typedef enum {SF_DL_NB_IoT, SF_UL_NB_IoT, SF_S_NB_IoT} NB_IoT_subframe_t; + +#define A_SEQUENCE_OF(type) A_SET_OF(type) + +#define A_SET_OF(type) \ + struct { \ + type **array; \ + int count; /* Meaningful size */ \ + int size; /* Allocated size */ \ + void (*free)(type *); \ + } + + +///////////////////////// + /// Union for \ref TPC_PDCCH_CONFIG::tpc_Index. +typedef union { + /// Index of N when DCI format 3 is used. See TS 36.212 (5.3.3.1.6). \vr{[1..15]} + uint8_t indexOfFormat3; + /// Index of M when DCI format 3A is used. See TS 36.212 (5.3.3.1.7). \vr{[1..31]} + uint8_t indexOfFormat3A; +} TPC_INDEX_NB_IoT_t; + +/// TPC-PDCCH-Config Information Element from 36.331 RRC spec +typedef struct { + /// RNTI for power control using DCI format 3/3A, see TS 36.212. \vr{[0..65535]} + uint16_t rnti; + /// Index of N or M, see TS 36.212 (5.3.3.1.6 and 5.3.3.1.7), where N or M is dependent on the used DCI format (i.e. format 3 or 3a). + TPC_INDEX_NB_IoT_t tpc_Index; +} TPC_PDCCH_CONFIG_NB_IoT; + /// Enumeration for parameter \f$N_\text{ANRep}\f$ \ref PUCCH_CONFIG_DEDICATED::repetitionFactor. +typedef enum { + //n2=0, + n4_n, + n6_n +} ACKNAKREP_NB_IoT_t; + +/// Enumeration for \ref PUCCH_CONFIG_DEDICATED::tdd_AckNackFeedbackMode. +typedef enum { + bundling_N=0, + multiplexing_N +} ANFBmode_NB_IoT_t; + +/// PUCCH-ConfigDedicated from 36.331 RRC spec +typedef struct { + /// Flag to indicate ACK NAK repetition activation, see TS 36.213 (10.1). \vr{[0..1]} + uint8_t ackNackRepetition; + /// Parameter: \f$N_\text{ANRep}\f$, see TS 36.213 (10.1). + ACKNAKREP_NB_IoT_t repetitionFactor; + /// Parameter: \f$n^{(1)}_\text{PUCCH,ANRep}\f$, see TS 36.213 (10.1). \vr{[0..2047]} + uint16_t n1PUCCH_AN_Rep; + /// Feedback mode, see TS 36.213 (7.3). \details Applied to both PUCCH and PUSCH feedback. For TDD, should always be set to bundling. + ANFBmode_NB_IoT_t tdd_AckNackFeedbackMode; +} PUCCH_CONFIG_DEDICATED_NB_IoT; + // UE specific PUSCH configuration. +typedef struct { + /// Parameter: \f$I^\text{HARQ-ACK}_\text{offset}\f$, see TS 36.213 (Table 8.6.3-1). \vr{[0..15]} + uint16_t betaOffset_ACK_Index; + /// Parameter: \f$I^{RI}_\text{offset}\f$, see TS 36.213 (Table 8.6.3-2). \vr{[0..15]} + uint16_t betaOffset_RI_Index; + /// Parameter: \f$I^{CQI}_\text{offset}\f$, see TS 36.213 (Table 8.6.3-3). \vr{[0..15]} + uint16_t betaOffset_CQI_Index; +} PUSCH_CONFIG_DEDICATED_NB_IoT; +/// Enumeration for Parameter \f$P_A\f$ \ref PDSCH_CONFIG_DEDICATED::p_a. +typedef enum { + //dBm6=0, ///< (dB-6) corresponds to -6 dB + // dBm477, ///< (dB-4dot77) corresponds to -4.77 dB + // dBm3, ///< (dB-3) corresponds to -3 dB + //dBm177, ///< (dB-1dot77) corresponds to -1.77 dB + //dB0, ///< corresponds to 0 dB + // dB1, ///< corresponds to 1 dB + dB2_NB, ///< corresponds to 2 dB + dB3_NB ///< corresponds to 3 dB +} PA_NB_IoT_t; + +/// PDSCH-ConfigDedicated from 36.331 RRC spec +typedef struct { + /// Parameter: \f$P_A\f$, see TS 36.213 (5.2). + PA_NB_IoT_t p_a; +} PDSCH_CONFIG_DEDICATED_NB_IoT; + +/// UplinkPowerControlDedicated Information Element from 36.331 RRC spec +typedef struct { + /// Parameter: \f$P_\text{0\_UE\_PUSCH}(1)\f$, see TS 36.213 (5.1.1.1), unit dB. \vr{[-8..7]}\n This field is applicable for non-persistent scheduling, only. + int8_t p0_UE_PUSCH; + /// Parameter: Ks, see TS 36.213 (5.1.1.1). \vr{[0..1]}\n en0 corresponds to value 0 corresponding to state “disabled”. en1 corresponds to value 1.25 corresponding to “enabled”. \note the specification sais it is an enumerated value. \warning the enumeration values do not correspond to the given values in the specification (en1 should be 1.25). + uint8_t deltaMCS_Enabled; + /// Parameter: Accumulation-enabled, see TS 36.213 (5.1.1.1). \vr{[0..1]} 1 corresponds to "enabled" whereas 0 corresponds to "disabled". + uint8_t accumulationEnabled; + /// Parameter: \f$P_\text{0\_UE\_PUCCH}(1)\f$, see TS 36.213 (5.1.2.1), unit dB. \vr{[-8..7]} + int8_t p0_UE_PUCCH; + /// Parameter: \f$P_\text{SRS\_OFFSET}\f$, see TS 36.213 (5.1.3.1). \vr{[0..15]}\n For Ks=1.25 (\ref deltaMCS_Enabled), the actual parameter value is pSRS_Offset value - 3. For Ks=0, the actual parameter value is -10.5 + 1.5*pSRS_Offset value. + int8_t pSRS_Offset; + /// Specifies the filtering coefficient for RSRP measurements used to calculate path loss, as specified in TS 36.213 (5.1.1.1).\details The same filtering mechanism applies as for quantityConfig described in 5.5.3.2. \note the specification sais it is an enumerated value. + uint8_t filterCoefficient; +} UL_POWER_CONTROL_DEDICATED_NB_IoT; + +/// Union for \ref TPC_PDCCH_CONFIG::tpc_Index. +//typedef union { + /// Index of N when DCI format 3 is used. See TS 36.212 (5.3.3.1.6). \vr{[1..15]} + // uint8_t indexOfFormat3; + /// Index of M when DCI format 3A is used. See TS 36.212 (5.3.3.1.7). \vr{[1..31]} + // uint8_t indexOfFormat3A; +//} TPC_INDEX_NB_IoT_t; + +/// CQI-ReportPeriodic +typedef struct { + /// Parameter: \f$n^{(2)}_\text{PUCCH}\f$, see TS 36.213 (7.2). \vr{[0..1185]}, -1 indicates inactivity + int16_t cqi_PUCCH_ResourceIndex; + /// Parameter: CQI/PMI Periodicity and Offset Configuration Index \f$I_\text{CQI/PMI}\f$, see TS 36.213 (tables 7.2.2-1A and 7.2.2-1C). \vr{[0..1023]} + int16_t cqi_PMI_ConfigIndex; + /// Parameter: K, see 36.213 (4.2.2). \vr{[1..4]} + uint8_t K; + /// Parameter: RI Config Index \f$I_\text{RI}\f$, see TS 36.213 (7.2.2-1B). \vr{[0..1023]}, -1 indicates inactivity + int16_t ri_ConfigIndex; + /// Parameter: Simultaneous-AN-and-CQI, see TS 36.213 (10.1). \vr{[0..1]} 1 indicates that simultaneous transmission of ACK/NACK and CQI is allowed. + uint8_t simultaneousAckNackAndCQI; + /// parameter computed from Tables 7.2.2-1A and 7.2.2-1C + uint16_t Npd; + /// parameter computed from Tables 7.2.2-1A and 7.2.2-1C + uint16_t N_OFFSET_CQI; +} CQI_REPORTPERIODIC_NB_IoT; + +/// Enumeration for parameter reporting mode \ref CQI_REPORT_CONFIG::cqi_ReportModeAperiodic. +typedef enum { + //rm12=0, + //rm20=1, + //rm22=2, + rm30_N=3, + rm31_N=4 +} CQI_REPORTMODEAPERIODIC_NB_IoT; + +/// CQI-ReportConfig Information Element from 36.331 RRC spec +typedef struct { + /// Parameter: reporting mode. Value rm12 corresponds to Mode 1-2, rm20 corresponds to Mode 2-0, rm22 corresponds to Mode 2-2 etc. PUSCH reporting modes are described in TS 36.213 [23, 7.2.1]. + CQI_REPORTMODEAPERIODIC_NB_IoT cqi_ReportModeAperiodic; + /// Parameter: \f$\Delta_\text{offset}\f$, see TS 36.213 (7.2.3). \vr{[-1..6]}\n Actual value = IE value * 2 [dB]. + int8_t nomPDSCH_RS_EPRE_Offset; + CQI_REPORTPERIODIC_NB_IoT CQI_ReportPeriodic; +} CQI_REPORT_CONFIG_NB_IoT; + +/// SoundingRS-UL-ConfigDedicated Information Element from 36.331 RRC spec +typedef struct { + /// Parameter: \f$B_\text{SRS}\f$, see TS 36.211 (table 5.5.3.2-1, 5.5.3.2-2, 5.5.3.2-3 and 5.5.3.2-4). \vr{[0..3]} \note the specification sais it is an enumerated value. + uint8_t srs_Bandwidth; + /// Parameter: SRS hopping bandwidth \f$b_\text{hop}\in\{0,1,2,3\}\f$, see TS 36.211 (5.5.3.2) \vr{[0..3]} \note the specification sais it is an enumerated value. + uint8_t srs_HoppingBandwidth; + /// Parameter: \f$n_\text{RRC}\f$, see TS 36.211 (5.5.3.2). \vr{[0..23]} + uint8_t freqDomainPosition; + /// Parameter: Duration, see TS 36.213 (8.2). \vr{[0..1]} 0 corresponds to "single" and 1 to "indefinite". + uint8_t duration; + /// Parameter: \f$k_\text{TC}\in\{0,1\}\f$, see TS 36.211 (5.5.3.2). \vr{[0..1]} + uint8_t transmissionComb; + /// Parameter: \f$I_\text{SRS}\f$, see TS 36.213 (table 8.2-1). \vr{[0..1023]} + uint16_t srs_ConfigIndex; + /// Parameter: \f$n^\text{CS}_\text{SRS}\f$. See TS 36.211 (5.5.3.1). \vr{[0..7]} \note the specification sais it is an enumerated value. + uint8_t cyclicShift; + // Parameter: internal implementation: UE SRS configured + uint8_t srsConfigDedicatedSetup; + // Parameter: cell srs subframe for internal implementation + uint8_t srsCellSubframe; + // Parameter: ue srs subframe for internal implementation + uint8_t srsUeSubframe; +} SOUNDINGRS_UL_CONFIG_DEDICATED_NB_IoT; + + +/// Enumeration for parameter SR transmission \ref SCHEDULING_REQUEST_CONFIG::dsr_TransMax. +typedef enum { + //sr_n4=0, + // sr_n8=1, + // sr_n16=2, + sr_n32_N=3, + sr_n64_N=4 +} DSR_TRANSMAX_NB_IoT_t; + +/// SchedulingRequestConfig Information Element from 36.331 RRC spec +typedef struct { + /// Parameter: \f$n^{(1)}_\text{PUCCH,SRI}\f$, see TS 36.213 (10.1). \vr{[0..2047]} + uint16_t sr_PUCCH_ResourceIndex; + /// Parameter: \f$I_\text{SR}\f$, see TS 36.213 (10.1). \vr{[0..155]} + uint8_t sr_ConfigIndex; + /// Parameter for SR transmission in TS 36.321 (5.4.4). \details The value n4 corresponds to 4 transmissions, n8 corresponds to 8 transmissions and so on. + DSR_TRANSMAX_NB_IoT_t dsr_TransMax; +} SCHEDULING_REQUEST_CONFIG_NB_IoT; + +typedef struct { + /// Downlink Power offset field + uint8_t dl_pow_off; + ///Subband resource allocation field + uint8_t rballoc_sub[50]; + ///Total number of PRBs indicator + uint8_t pre_nb_available_rbs; +} MU_MIMO_mode_NB_IoT; +//////////////////////// + +typedef struct { + + /// \brief Holds the received data in the frequency domain. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: symbol [0..28*ofdm_symbol_size[ + int32_t **rxdataF; + + /// \brief Hold the channel estimates in frequency domain. + /// - first index: eNB id [0..6] (hard coded) + /// - second index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - third index: samples? [0..symbols_per_tti*(ofdm_symbol_size+LTE_CE_FILTER_LENGTH)[ + int32_t **dl_ch_estimates[7]; + + /// \brief Hold the channel estimates in time domain (used for tracking). + /// - first index: eNB id [0..6] (hard coded) + /// - second index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - third index: samples? [0..2*ofdm_symbol_size[ + int32_t **dl_ch_estimates_time[7]; +}NB_IoT_UE_COMMON_PER_THREAD; + +typedef struct { + /// \brief Holds the transmit data in time domain. + /// For IFFT_FPGA this points to the same memory as PHY_vars->tx_vars[a].TX_DMA_BUFFER. + /// - first index: tx antenna [0..nb_antennas_tx[ + /// - second index: sample [0..FRAME_LENGTH_COMPLEX_SAMPLES[ + int32_t **txdata; + /// \brief Holds the transmit data in the frequency domain. + /// For IFFT_FPGA this points to the same memory as PHY_vars->rx_vars[a].RX_DMA_BUFFER. + /// - first index: tx antenna [0..nb_antennas_tx[ + /// - second index: sample [0..FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX[ + int32_t **txdataF; + + /// \brief Holds the received data in time domain. + /// Should point to the same memory as PHY_vars->rx_vars[a].RX_DMA_BUFFER. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: sample [0..FRAME_LENGTH_COMPLEX_SAMPLES+2048[ + int32_t **rxdata; + + NB_IoT_UE_COMMON_PER_THREAD common_vars_rx_data_per_thread[2]; + + /// holds output of the sync correlator + int32_t *sync_corr; + /// estimated frequency offset (in radians) for all subcarriers + int32_t freq_offset; + /// eNb_id user is synched to + int32_t eNb_id; +} NB_IoT_UE_COMMON; + +typedef struct { + /// \brief Received frequency-domain signal after extraction. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **rxdataF_ext; + /// \brief Received frequency-domain ue specific pilots. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..12*N_RB_DL[ + int32_t **rxdataF_uespec_pilots; + /// \brief Received frequency-domain signal after extraction and channel compensation. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **rxdataF_comp0; + /// \brief Received frequency-domain signal after extraction and channel compensation for the second stream. For the SIC receiver we need to store the history of this for each harq process and round + /// - first index: ? [0..7] (hard coded) accessed via \c harq_pid + /// - second index: ? [0..7] (hard coded) accessed via \c round + /// - third index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - fourth index: ? [0..168*N_RB_DL[ + int32_t **rxdataF_comp1[8][8]; + /// \brief Downlink channel estimates extracted in PRBS. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_estimates_ext; + /// \brief Downlink cross-correlation of MIMO channel estimates (unquantized PMI) extracted in PRBS. For the SIC receiver we need to store the history of this for each harq process and round + /// - first index: ? [0..7] (hard coded) accessed via \c harq_pid + /// - second index: ? [0..7] (hard coded) accessed via \c round + /// - third index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - fourth index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_rho_ext[8][8]; + /// \brief Downlink beamforming channel estimates in frequency domain. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: samples? [0..symbols_per_tti*(ofdm_symbol_size+LTE_CE_FILTER_LENGTH)[ + int32_t **dl_bf_ch_estimates; + /// \brief Downlink beamforming channel estimates. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_bf_ch_estimates_ext; + /// \brief Downlink cross-correlation of MIMO channel estimates (unquantized PMI) extracted in PRBS. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_rho2_ext; + /// \brief Downlink PMIs extracted in PRBS and grouped in subbands. + /// - first index: ressource block [0..N_RB_DL[ + uint8_t *pmi_ext; + /// \brief Magnitude of Downlink Channel first layer (16QAM level/First 64QAM level). + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_mag0; + /// \brief Magnitude of Downlink Channel second layer (16QAM level/First 64QAM level). + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_mag1[8][8]; + /// \brief Magnitude of Downlink Channel, first layer (2nd 64QAM level). + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_magb0; + /// \brief Magnitude of Downlink Channel second layer (2nd 64QAM level). + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_ch_magb1[8][8]; + /// \brief Cross-correlation of two eNB signals. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: symbol [0..] + int32_t **rho; + /// never used... always send dl_ch_rho_ext instead... + int32_t **rho_i; + /// \brief Pointers to llr vectors (2 TBs). + /// - first index: ? [0..1] (hard coded) + /// - second index: ? [0..1179743] (hard coded) + int16_t *llr[2]; + /// \f$\log_2(\max|H_i|^2)\f$ + int16_t log2_maxh; + /// \f$\log_2(\max|H_i|^2)\f$ //this is for TM3-4 layer1 channel compensation + int16_t log2_maxh0; + /// \f$\log_2(\max|H_i|^2)\f$ //this is for TM3-4 layer2 channel commpensation + int16_t log2_maxh1; + /// \brief LLR shifts for subband scaling. + /// - first index: ? [0..168*N_RB_DL[ + uint8_t *llr_shifts; + /// \brief Pointer to LLR shifts. + /// - first index: ? [0..168*N_RB_DL[ + uint8_t *llr_shifts_p; + /// \brief Pointers to llr vectors (128-bit alignment). + /// - first index: ? [0..0] (hard coded) + /// - second index: ? [0..] + int16_t **llr128; + /// \brief Pointers to llr vectors (128-bit alignment). + /// - first index: ? [0..0] (hard coded) + /// - second index: ? [0..] + int16_t **llr128_2ndstream; + //uint32_t *rb_alloc; + //uint8_t Qm[2]; + //MIMO_mode_t mimo_mode; +} NB_IoT_UE_PDSCH; + +/// NPRACH-ParametersList-NB-r13 from 36.331 RRC spec +typedef struct NPRACH_Parameters_NB_IoT{ + /// the period time for nprach + uint16_t nprach_Periodicity; + /// for the start time for the NPRACH resource from 40ms-2560ms + uint16_t nprach_StartTime; + /// for the subcarrier of set to the NPRACH preamble from n0 - n34 + uint16_t nprach_SubcarrierOffset; + ///number of subcarriers in a NPRACH resource allowed values (n12,n24,n36,n48) + uint16_t nprach_NumSubcarriers; + /// where is the region that in NPRACH resource to indicate if this UE support MSG3 for multi-tone or not. from 0 - 1 + uint16_t nprach_SubcarrierMSG3_RangeStart; + /// The max preamble transmission attempt for the CE level from 1 - 128 + uint16_t maxNumPreambleAttemptCE; + /// Number of NPRACH repetitions per attempt for each NPRACH resource + uint16_t numRepetitionsPerPreambleAttempt; + /// The number of the repetition for DCI use in RAR/MSG3/MSG4 from 1 - 2048 (Rmax) + uint16_t npdcch_NumRepetitions_RA; + /// Starting subframe for NPDCCH Common searching space for (RAR/MSG3/MSG4) + uint16_t npdcch_StartSF_CSS_RA; + /// Fractional period offset of starting subframe for NPDCCH common search space + uint16_t npdcch_Offset_RA; +} nprach_parameters_NB_IoT_t; + +typedef struct{ + nprach_parameters_NB_IoT_t list[3]; +}NPRACH_List_NB_IoT_t; + +typedef long RSRP_Range_t; + +typedef struct { + A_SEQUENCE_OF(RSRP_Range_t) list; +}rsrp_ThresholdsNPrachInfoList; + + +/// NPRACH_ConfigSIB-NB from 36.331 RRC spec +typedef struct { + /// nprach_CP_Length_r13, for the CP length(unit us) only 66.7 and 266.7 is implemented + uint16_t nprach_CP_Length; + /// The criterion for UEs to select a NPRACH resource. Up to 2 RSRP threshold values can be signalled. \vr{[1..2]} + struct rsrp_ThresholdsNPrachInfoList *rsrp_ThresholdsPrachInfoList; + /// NPRACH Parameters List + NPRACH_List_NB_IoT_t nprach_ParametersList; + +} NPRACH_CONFIG_COMMON; + +/// NPDSCH-ConfigCommon from 36.331 RRC spec +typedef struct { + ///see TS 36.213 (16.2). \vr{[-60..50]}\n Provides the downlink reference-signal EPRE. The actual value in dBm. + uint16_t nrs_Power; +} NPDSCH_CONFIG_COMMON; + +typedef struct{ + /// The base sequence of DMRS sequence in a cell for 3 tones transmission; see TS 36.211 [21, 10.1.4.1.2]. If absent, it is given by NB-IoT CellID mod 12. Value 12 is not used. + uint16_t threeTone_BaseSequence; + /// Define 3 cyclic shifts for the 3-tone case, see TS 36.211 [21, 10.1.4.1.2]. + uint16_t threeTone_CyclicShift; + /// The base sequence of DMRS sequence in a cell for 6 tones transmission; see TS 36.211 [21, 10.1.4.1.2]. If absent, it is given by NB-IoT CellID mod 14. Value 14 is not used. + uint16_t sixTone_BaseSequence; + /// Define 4 cyclic shifts for the 6-tone case, see TS 36.211 [21, 10.1.4.1.2]. + uint16_t sixTone_CyclicShift; + /// The base sequence of DMRS sequence in a cell for 12 tones transmission; see TS 36.211 [21, 10.1.4.1.2]. If absent, it is given by NB-IoT CellID mod 30. Value 30 is not used. + uint16_t twelveTone_BaseSequence; + +}DMRS_CONFIG_t; + +/// UL-ReferenceSignalsNPUSCH from 36.331 RRC spec +typedef struct { + /// Parameter: Group-hopping-enabled, see TS 36.211 (5.5.1.3). \vr{[0..1]} + uint8_t groupHoppingEnabled; + /// , see TS 36.211 (5.5.1.3). \vr{[0..29]} + uint8_t groupAssignmentNPUSCH; + /// Parameter: cyclicShift, see TS 36.211 (Table 5.5.2.1.1-2). \vr{[0..7]} + uint8_t cyclicShift; + /// nPRS for cyclic shift of DRS \note not part of offical UL-ReferenceSignalsPUSCH ASN1 specification. + uint8_t nPRS[20]; + /// group hopping sequence for DMRS, 36.211, Section 10.1.4.1.3. Second index corresponds to the four possible subcarrier configurations + uint8_t grouphop[20][4]; + /// sequence hopping sequence for DRS \note not part of offical UL-ReferenceSignalsPUSCH ASN1 specification. + uint8_t seqhop[20]; +} UL_REFERENCE_SIGNALS_NPUSCH_t; + + +/// PUSCH-ConfigCommon from 36.331 RRC spec. +typedef struct { + /// Number of repetitions for ACK/NACK HARQ response to NPDSCH containing Msg4 per NPRACH resource, see TS 36.213 [23, 16.4.2]. + uint8_t ack_NACK_NumRepetitions_Msg4[3]; + /// SRS SubframeConfiguration. See TS 36.211 [21, table 5.5.3.3-1]. Value sc0 corresponds to value 0, sc1 to value 1 and so on. + uint8_t srs_SubframeConfig; + /// Parameter: \f$N^{HO}_{RB}\f$, see TS 36.211 (5.3.4). \vr{[0..98]} + DMRS_CONFIG_t dmrs_Config; + /// Ref signals configuration + UL_REFERENCE_SIGNALS_NPUSCH_t ul_ReferenceSignalsNPUSCH; + +} NPUSCH_CONFIG_COMMON; + + +typedef struct{ + /// See TS 36.213 [23, 16.2.1.1], unit dBm. + uint8_t p0_NominalNPUSCH; + /// See TS 36.213 [23, 16.2.1.1] where al0 corresponds to 0, al04 corresponds to value 0.4, al05 to 0.5, al06 to 0.6, al07 to 0.7, al08 to 0.8, al09 to 0.9 and al1 corresponds to 1. + uint8_t alpha; + /// See TS 36.213 [23, 16.2.1.1]. Actual value = IE value * 2 [dB]. + uint8_t deltaPreambleMsg3; +}UplinkPowerControlCommon_NB_IoT; + + +/* DL-GapConfig-NB-r13 */ +typedef struct { + uint16_t dl_GapThreshold; + uint16_t dl_GapPeriodicity; + uint16_t dl_GapDurationCoeff; +} DL_GapConfig_NB_IoT; + +#define NBIOT_INBAND_LTEPCI 0 +#define NBIOT_INBAND_IOTPCI 1 +#define NBIOT_INGUARD 2 +#define NBIOT_STANDALONE 3 + + +typedef struct { + /// for inband, lte bandwidth + uint8_t LTE_N_RB_DL; + uint8_t LTE_N_RB_UL; + /// Cell ID + uint16_t Nid_cell; + /// shift of pilot position in one RB + uint8_t nushift; + /// indicates if node is a UE (NODE=2) or eNB (PRIMARY_CH=0). + uint8_t node_id; + /// Frequency index of CBMIMO1 card + uint8_t freq_idx; + /// RX Frequency for ExpressMIMO/LIME + uint32_t carrier_freq[4]; + /// TX Frequency for ExpressMIMO/LIME + uint32_t carrier_freqtx[4]; + /// RX gain for ExpressMIMO/LIME + uint32_t rxgain[4]; + /// TX gain for ExpressMIMO/LIME + uint32_t txgain[4]; + /// RF mode for ExpressMIMO/LIME + uint32_t rfmode[4]; + /// RF RX DC Calibration for ExpressMIMO/LIME + uint32_t rxdc[4]; + /// RF TX DC Calibration for ExpressMIMO/LIME + uint32_t rflocal[4]; + /// RF VCO calibration for ExpressMIMO/LIME + uint32_t rfvcolocal[4]; + /// Turns on second TX of CBMIMO1 card + uint8_t dual_tx; + /// flag to indicate SISO transmission + uint8_t mode1_flag; + /// Indicator that 20 MHz channel uses 3/4 sampling frequency + //uint8_t threequarter_fs; + /// Size of FFT + uint16_t ofdm_symbol_size; + /// Number of prefix samples in all but first symbol of slot + uint16_t nb_prefix_samples; + /// Number of prefix samples in first symbol of slot + uint16_t nb_prefix_samples0; + /// Carrier offset in FFT buffer for first RE in PRB0 + uint16_t first_carrier_offset; + /// Number of samples in a subframe + uint32_t samples_per_tti; + /// Number of OFDM/SC-FDMA symbols in one subframe (to be modified to account for potential different in UL/DL) + uint16_t symbols_per_tti; + /// Number of Physical transmit antennas in node + uint8_t nb_antennas_tx; + /// Number of Receive antennas in node + uint8_t nb_antennas_rx; + /// Number of common transmit antenna ports in eNodeB (1 or 2) + uint8_t nb_antenna_ports_eNB; + /// Number of common receiving antenna ports in eNodeB (1 or 2) + uint8_t nb_antenna_ports_rx_eNB; + /// NPRACH Config Common (from 36-331 RRC spec) + NPRACH_CONFIG_COMMON nprach_config_common; + /// NPDSCH Config Common (from 36-331 RRC spec) + NPDSCH_CONFIG_COMMON npdsch_config_common; + /// PUSCH Config Common (from 36-331 RRC spec) + NPUSCH_CONFIG_COMMON npusch_config_common; + /// UL Power Control (from 36-331 RRC spec) + UplinkPowerControlCommon_NB_IoT ul_power_control_config_common; + /// DL Gap + DL_GapConfig_NB_IoT DL_gap_config; + /// Size of SI windows used for repetition of one SI message (in frames) + uint8_t SIwindowsize; + /// Period of SI windows used for repetition of one SI message (in frames) + uint16_t SIPeriod; + int eutra_band; + uint32_t dl_CarrierFreq; + uint32_t ul_CarrierFreq; + // CE level to determine the NPRACH Configuration (one CE for each NPRACH config.) + uint8_t CE; + + /* + * index of the PRB assigned to NB-IoT carrier in in-band/guard-band operating mode + */ + unsigned short NB_IoT_RB_ID; + + + /*Following FAPI approach: + * 0 = in-band with same PCI + * 1 = in-band with diff PCI + * 2 = guard band + * 3 =stand alone + */ + uint16_t operating_mode; + /* + * Only for In-band operating mode with same PCI + * its measured in number of OFDM symbols + * allowed values: + * 1, 2, 3, 4(this value is written in FAPI specs but not exist in TS 36.331 v14.2.1 pag 587) + * -1 (we put this value when is not defined - other operating mode) + */ + uint16_t control_region_size; + + /*Number of EUTRA CRS antenna ports (AP) + * valid only for in-band different PCI mode + * value 0 = indicates the same number of AP as NRS APs + * value 1 = four CRS APs + */ + uint16_t eutra_NumCRS_ports; + + /* Subcarrier bandwidth + 0 -> 3.75 kHz + 1 -> 15 kHz + */ + uint8_t subcarrier_spacing; + +} NB_IoT_DL_FRAME_PARMS; + +typedef struct { + /// \brief Pointers (dynamic) to the received data in the time domain. + /// - first index: rx antenna [0..nb_antennas_rx] + /// - second index: ? [0..2*ofdm_symbol_size*frame_parms->symbols_per_tti] + int32_t **rxdata; + /// \brief Pointers (dynamic) to the received data in the frequency domain. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: ? [0..2*ofdm_symbol_size*frame_parms->symbols_per_tti] + int32_t **rxdataF; + /// \brief holds the transmit data in the frequency domain. + /// For IFFT_FPGA this points to the same memory as PHY_vars->rx_vars[a].RX_DMA_BUFFER. //? + /// - first index: eNB id [0..2] (hard coded) + /// - second index: tx antenna [0..14[ where 14 is the total supported antenna ports. + /// - third index: sample [0..] + int32_t **txdataF; +} NB_IoT_eNB_COMMON; + +typedef struct { + /// \brief Holds the transmit data in the frequency domain. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: ? [0..2*ofdm_symbol_size*frame_parms->symbols_per_tti[ + int32_t **txdata; + /// \brief Holds the receive data in the frequency domain. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: ? [0..2*ofdm_symbol_size*frame_parms->symbols_per_tti[ + int32_t **rxdata[3]; + /// \brief Holds the last subframe of received data in time domain after removal of 7.5kHz frequency offset. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: sample [0..samples_per_tti[ + int32_t **rxdata_7_5kHz[3]; + /// \brief Holds the received data in the frequency domain. + /// - first index: rx antenna [0..nb_antennas_rx[ + /// - second index: ? [0..2*ofdm_symbol_size*frame_parms->symbols_per_tti[ + int32_t **rxdataF[3]; + /// \brief Holds output of the sync correlator. + /// - first index: sample [0..samples_per_tti*10[ + uint32_t *sync_corr[3]; +} NB_IoT_RU_COMMON; + +typedef struct { + /// \brief Hold the channel estimates in frequency domain based on SRS. + /// - first index: sector id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..ofdm_symbol_size[ + int32_t **srs_ch_estimates[3]; + /// \brief Hold the channel estimates in time domain based on SRS. + /// - first index: sector id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..2*ofdm_symbol_size[ + int32_t **srs_ch_estimates_time[3]; + /// \brief Holds the SRS for channel estimation at the RX. + /// - first index: ? [0..ofdm_symbol_size[ + int32_t *srs; +} NB_IoT_eNB_SRS; + +typedef struct { + /// \brief Holds the received data in the frequency domain for the allocated RBs in repeated format. + /// - first index: sector id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..2*ofdm_symbol_size[ + /// - third index (definition from phy_init_lte_eNB()): ? [0..24*N_RB_UL*frame_parms->symbols_per_tti[ + /// \warning inconsistent third index definition + int32_t **rxdataF_ext[3]; + /// \brief Holds the received data in the frequency domain for the allocated RBs in normal format. + /// - first index: sector id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index (definition from phy_init_lte_eNB()): ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **rxdataF_ext2[3]; + /// \brief Hold the channel estimates in time domain based on DRS. + /// - first index: sector id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..4*ofdm_symbol_size[ + int32_t **drs_ch_estimates_time[3]; + /// \brief Hold the channel estimates in frequency domain based on DRS. + /// - first index: sector id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **drs_ch_estimates[3]; + /// \brief Hold the channel estimates for UE0 in case of Distributed Alamouti Scheme. + /// - first index: sector id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **drs_ch_estimates_0[3]; + /// \brief Hold the channel estimates for UE1 in case of Distributed Almouti Scheme. + /// - first index: sector id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **drs_ch_estimates_1[3]; + /// \brief Holds the compensated signal. + /// - first index: sector id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **rxdataF_comp[3]; + /// \brief Hold the compensated data (y)*(h0*) in case of Distributed Alamouti Scheme. + /// - first index: sector id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **rxdataF_comp_0[3]; + /// \brief Hold the compensated data (y*)*(h1) in case of Distributed Alamouti Scheme. + /// - first index: sector id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **rxdataF_comp_1[3]; + /// \brief ?. + /// - first index: sector id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **ul_ch_mag[3]; + /// \brief ?. + /// - first index: eNB id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **ul_ch_magb[3]; + /// \brief Hold the channel mag for UE0 in case of Distributed Alamouti Scheme. + /// - first index: eNB id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **ul_ch_mag_0[3]; + /// \brief Hold the channel magb for UE0 in case of Distributed Alamouti Scheme. + /// - first index: eNB id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **ul_ch_magb_0[3]; + /// \brief Hold the channel mag for UE1 in case of Distributed Alamouti Scheme. + /// - first index: eNB id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **ul_ch_mag_1[3]; + /// \brief Hold the channel magb for UE1 in case of Distributed Alamouti Scheme. + /// - first index: eNB id [0..2] (hard coded) + /// - second index: rx antenna id [0..nb_antennas_rx[ + /// - third index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **ul_ch_magb_1[3]; + /// measured RX power based on DRS + int ulsch_power[2]; + /// measured RX power based on DRS for UE0 in case of Distributed Alamouti Scheme + int ulsch_power_0[2]; + /// measured RX power based on DRS for UE0 in case of Distributed Alamouti Scheme + int ulsch_power_1[2]; + /// \brief llr values. + /// - first index: ? [0..1179743] (hard coded) + int16_t *llr; +#ifdef LOCALIZATION + /// number of active subcarrier for a specific UE + int32_t active_subcarrier; + /// subcarrier power in dBm + int32_t *subcarrier_power; +#endif +} NB_IoT_eNB_PUSCH; + +#define PBCH_A_NB_IoT 24 +typedef struct { + uint8_t pbch_d[96+(3*(16+PBCH_A_NB_IoT))]; + uint8_t pbch_w[3*3*(16+PBCH_A_NB_IoT)]; + uint8_t pbch_e[1920]; +} NB_IoT_eNB_PBCH; + + +typedef enum { + /// TM1 + SISO_NB_IoT=0, + /// TM2 + ALAMOUTI_NB_IoT=1, + /// TM3 + LARGE_CDD_NB_IoT=2, + /// the next 6 entries are for TM5 + UNIFORM_PRECODING11_NB_IoT=3, + UNIFORM_PRECODING1m1_NB_IoT=4, + UNIFORM_PRECODING1j_NB_IoT=5, + UNIFORM_PRECODING1mj_NB_IoT=6, + PUSCH_PRECODING0_NB_IoT=7, + PUSCH_PRECODING1_NB_IoT=8, + /// the next 3 entries are for TM4 + DUALSTREAM_UNIFORM_PRECODING1_NB_IoT=9, + DUALSTREAM_UNIFORM_PRECODINGj_NB_IoT=10, + DUALSTREAM_PUSCH_PRECODING_NB_IoT=11, + TM7_NB_IoT=12, + TM8_NB_IoT=13, + TM9_10_NB_IoT=14 +} MIMO_mode_NB_IoT_t; + +typedef struct { + /// \brief ?. + /// first index: ? [0..1023] (hard coded) + int16_t *prachF; + /// \brief ?. + /// first index: rx antenna [0..63] (hard coded) \note Hard coded array size indexed by \c nb_antennas_rx. + /// second index: ? [0..ofdm_symbol_size*12[ + int16_t *rxsigF[64]; + /// \brief local buffer to compute prach_ifft (necessary in case of multiple CCs) + /// first index: rx antenna [0..63] (hard coded) \note Hard coded array size indexed by \c nb_antennas_rx. + /// second index: ? [0..2047] (hard coded) + int16_t *prach_ifft[64]; +} NB_IoT_eNB_PRACH; + +typedef enum { + NOT_SYNCHED_NB_IoT=0, + PRACH_NB_IoT=1, + RA_RESPONSE_NB_IoT=2, + PUSCH_NB_IoT=3, + RESYNCH_NB_IoT=4 +} UE_MODE_NB_IoT_t; + + +#endif diff --git a/openair1/PHY/impl_defs_top_NB_IoT.h b/openair1/PHY/impl_defs_top_NB_IoT.h new file mode 100644 index 0000000000..e512ec0215 --- /dev/null +++ b/openair1/PHY/impl_defs_top_NB_IoT.h @@ -0,0 +1,541 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file PHY/impl_defs_top.h +* \brief More defines and structure definitions +* \author R. Knopp, F. Kaltenberger +* \date 2011 +* \version 0.1 +* \company Eurecom +* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr +* \note +* \warning +*/ + +#ifndef __PHY_IMPLEMENTATION_DEFS_NB_IOT_H__ +#define __PHY_IMPLEMENTATION_DEFS_NB_IOT_H__ + + +#include "openairinterface5g_limits.h" +/** @defgroup _ref_implementation_ OpenAirInterface LTE Implementation + * @{ + + * @defgroup _PHY_RF_INTERFACE_ PHY - RF Interface + * @ingroup _PHY_RF_INTERFACE_ + * @{ + * @defgroup _GENERIC_PHY_RF_INTERFACE_ Generic PHY - RF Interface + * @defgroup _USRP_PHY_RF_INTERFACE_ PHY - USRP RF Interface + * @defgroup _BLADERF_PHY_RF_INTERFACE_ PHY - BLADERF RF Interface + * @defgroup _LMSSDR_PHY_RF_INTERFACE_ PHY - LMSSDR RF Interface + * @} + * + * @ingroup _ref_implementation_ + * @{ + * This module is responsible for defining the generic interface between PHY and RF Target + * @} + + * @defgroup _openair1_ openair1 Reference Implementation + * @ingroup _ref_implementation_ + * @{ + + + * @defgroup _physical_layer_ref_implementation_ Physical Layer Reference Implementation + * @ingroup _openair1_ + * @{ + + + * @defgroup _PHY_STRUCTURES_ Basic Structures and Memory Initialization + * @ingroup _physical_layer_ref_implementation_ + * @{ + * This module is responsible for defining and initializing the PHY variables during static configuration of OpenAirInterface. + * @} + + * @defgroup _PHY_DSP_TOOLS_ DSP Tools + * @ingroup _physical_layer_ref_implementation_ + * @{ + * This module is responsible for basic signal processing related to inner-MODEM processing. + * @} + + * @defgroup _PHY_MODULATION_ Modulation and Demodulation + * @ingroup _physical_layer_ref_implementation_ + * @{ + * This module is responsible for procedures related to OFDMA modulation and demodulation. + * @} + + * @defgroup _PHY_PARAMETER_ESTIMATION_BLOCKS_ Parameter Estimation + * @ingroup _physical_layer_ref_implementation_ + * @{ + * This module is responsible for procedures related to OFDMA frequency-domain channel estimation for LTE Downlink Channels. + * @} + + * @defgroup _PHY_CODING_BLOCKS_ Channel Coding/Decoding Functions + * @ingroup _physical_layer_ref_implementation_ + * @{ + * This module is responsible for procedures related to channel coding/decoding, rate-matching, segementation and interleaving. + * @} + + * @defgroup _PHY_TRANSPORT_ Transport/Physical Channel Processing + * @ingroup _physical_layer_ref_implementation_ + * @{ + * This module is responsible for defining and processing the PHY procedures (TX/RX) related to transport and physical channels. + * @} + + * @defgroup _PHY_PROCEDURES_ Physical Layer Procedures + * @ingroup _physical_layer_ref_implementation_ + * @{ + * This module is responsible for defining and processing the PHY procedures (TX/RX) related to transport and physical channels. + * @} + + * @} + * @} + * @} + */ + +//#include "types.h" + +/* + + +#define NUMBER_OF_OFDM_CARRIERS (frame_parms->ofdm_symbol_size) +#define NUMBER_OF_SYMBOLS_PER_FRAME (frame_parms->symbols_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME) +#define NUMBER_OF_USEFUL_CARRIERS (12*frame_parms->N_RB_DL) +#define NUMBER_OF_ZERO_CARRIERS (NUMBER_OF_OFDM_CARRIERS-NUMBER_OF_USEFUL_CARRIERS) +#define NUMBER_OF_USEFUL_CARRIERS_BYTES (NUMBER_OF_USEFUL_CARRIERS>>2) +#define HALF_NUMBER_OF_USEFUL_CARRIERS (NUMBER_OF_USEFUL_CARRIERS>>1) +#define HALF_NUMBER_OF_USEFUL_CARRIERS_BYTES (HALF_NUMBER_OF_USEFUL_CARRIERS>>2) +#define FIRST_CARRIER_OFFSET (HALF_NUMBER_OF_USEFUL_CARRIERS+NUMBER_OF_ZERO_CARRIERS) +#define NUMBER_OF_OFDM_SYMBOLS_PER_SLOT (NUMBER_OF_SYMBOLS_PER_FRAME/LTE_SLOTS_PER_FRAME) + +#ifdef EMOS +#define EMOS_SCH_INDEX 1 +#endif //EMOS + +#define EXTENSION_TYPE (PHY_config->PHY_framing.Extension_type) + +#define NUMBER_OF_OFDM_CARRIERS_BYTES NUMBER_OF_OFDM_CARRIERS*4 +//#define NUMBER_OF_USEFUL_CARRIERS_BYTES NUMBER_OF_USEFUL_CARRIERS*4 +#define HALF_NUMBER_OF_USER_CARRIERS_BYTES NUMBER_OF_USEFUL_CARRIERS/2 + +#define CYCLIC_PREFIX_LENGTH (frame_parms->nb_prefix_samples) +#define CYCLIC_PREFIX_LENGTH_SAMPLES (CYCLIC_PREFIX_LENGTH*2) +#define CYCLIC_PREFIX_LENGTH_BYTES (CYCLIC_PREFIX_LENGTH*4) +#define CYCLIC_PREFIX_LENGTH0 (frame_parms->nb_prefix_samples0) +#define CYCLIC_PREFIX_LENGTH_SAMPLES0 (CYCLIC_PREFIX_LENGTH0*2) +#define CYCLIC_PREFIX_LENGTH_BYTES0 (CYCLIC_PREFIX_LENGTH0*4) + +#define OFDM_SYMBOL_SIZE_SAMPLES ((NUMBER_OF_OFDM_CARRIERS + CYCLIC_PREFIX_LENGTH)*2) // 16-bit units (i.e. real samples) +#define OFDM_SYMBOL_SIZE_SAMPLES0 ((NUMBER_OF_OFDM_CARRIERS + CYCLIC_PREFIX_LENGTH0)*2) // 16-bit units (i.e. real samples) +#define OFDM_SYMBOL_SIZE_SAMPLES_MAX 4096 // 16-bit units (i.e. real samples) +#define OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES (OFDM_SYMBOL_SIZE_SAMPLES/2) // 32-bit units (i.e. complex samples) +#define OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0 (OFDM_SYMBOL_SIZE_SAMPLES0/2) // 32-bit units (i.e. complex samples) +#define OFDM_SYMBOL_SIZE_SAMPLES_NO_PREFIX ((NUMBER_OF_OFDM_CARRIERS)*2) +#define OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES_NO_PREFIX (OFDM_SYMBOL_SIZE_SAMPLES_NO_PREFIX/2) +#define OFDM_SYMBOL_SIZE_BYTES (OFDM_SYMBOL_SIZE_SAMPLES*2) +#define OFDM_SYMBOL_SIZE_BYTES0 (OFDM_SYMBOL_SIZE_SAMPLES0*2) +#define OFDM_SYMBOL_SIZE_BYTES_NO_PREFIX (OFDM_SYMBOL_SIZE_SAMPLES_NO_PREFIX*2) + +#define SLOT_LENGTH_BYTES (frame_parms->samples_per_tti<<1) // 4 bytes * samples_per_tti/2 +#define SLOT_LENGTH_BYTES_NO_PREFIX (OFDM_SYMBOL_SIZE_BYTES_NO_PREFIX * NUMBER_OF_OFDM_SYMBOLS_PER_SLOT) + +#define FRAME_LENGTH_COMPLEX_SAMPLES (frame_parms->samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME) +#define FRAME_LENGTH_SAMPLES (FRAME_LENGTH_COMPLEX_SAMPLES*2) +#define FRAME_LENGTH_SAMPLES_NO_PREFIX (NUMBER_OF_SYMBOLS_PER_FRAME*OFDM_SYMBOL_SIZE_SAMPLES_NO_PREFIX) +#define FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX (FRAME_LENGTH_SAMPLES_NO_PREFIX/2) + +#define NUMBER_OF_CARRIERS_PER_GROUP (NUMBER_OF_USEFUL_CARRIERS/NUMBER_OF_FREQUENCY_GROUPS) + +#define RX_PRECISION (16) +#define LOG2_RX_PRECISION (4) +#define RX_OUTPUT_SHIFT (4) + + +#define SAMPLE_SIZE_BYTES 2 // 2 bytes/real sample + +#define FRAME_LENGTH_BYTES (FRAME_LENGTH_SAMPLES * SAMPLE_SIZE_BYTES) // frame size in bytes +#define FRAME_LENGTH_BYTES_NO_PREFIX (FRAME_LENGTH_SAMPLES_NO_PREFIX * SAMPLE_SIZE_BYTES) // frame size in bytes + + +#define FFT_SCALE_FACTOR 8 // Internal Scaling for FFT +#define DMA_BLKS_PER_SLOT (SLOT_LENGTH_BYTES/2048) // Number of DMA blocks per slot +#define SLOT_TIME_NS (SLOT_LENGTH_SAMPLES*(1e3)/7.68) // slot time in ns + +#define NB_ANTENNA_PORTS_ENB 6 // total number of eNB antenna ports + +#ifdef EXMIMO +#define TARGET_RX_POWER 55 // Target digital power for the AGC +#define TARGET_RX_POWER_MAX 55 // Maximum digital power, such that signal does not saturate (value found by simulation) +#define TARGET_RX_POWER_MIN 50 // Minimum digital power, anything below will be discarded (value found by simulation) +#else +#define TARGET_RX_POWER 50 // Target digital power for the AGC +#define TARGET_RX_POWER_MAX 65 // Maximum digital power, such that signal does not saturate (value found by simulation) +#define TARGET_RX_POWER_MIN 35 // Minimum digital power, anything below will be discarded (value found by simulation) +#endif + +//the min and max gains have to match the calibrated gain table +//#define MAX_RF_GAIN 160 +//#define MIN_RF_GAIN 96 +#define MAX_RF_GAIN 200 +#define MIN_RF_GAIN 80 + +#define PHY_SYNCH_OFFSET ((OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES)-1) // OFFSET of BEACON SYNCH +#define PHY_SYNCH_MIN_POWER 1000 +#define PHY_SYNCH_THRESHOLD 100 + +*/ + +#define ONE_OVER_SQRT2_Q15_NB_IoT 23170 + +/* +#define ONE_OVER_2_Q15 16384 + +// QAM amplitude definitions + +/// First Amplitude for QAM16 (\f$ 2^{15} \times 2/\sqrt{10}\f$) +#define QAM16_n1 20724 +/// Second Amplitude for QAM16 (\f$ 2^{15} \times 1/\sqrt{10}\f$) +#define QAM16_n2 10362 + +///First Amplitude for QAM64 (\f$ 2^{15} \times 4/\sqrt{42}\f$) +#define QAM64_n1 20225 +///Second Amplitude for QAM64 (\f$ 2^{15} \times 2/\sqrt{42}\f$) +#define QAM64_n2 10112 +///Third Amplitude for QAM64 (\f$ 2^{15} \times 1/\sqrt{42}\f$) +#define QAM64_n3 5056 + +/// First Amplitude for QAM16 for TM5 (\f$ 2^{15} \times 2/sqrt(20)\f$) +#define QAM16_TM5_n1 14654 +/// Second Amplitude for QAM16 for TM5 Receiver (\f$ 2^{15} \times 1/\sqrt{20}\f$) +#define QAM16_TM5_n2 7327 + +///First Amplitude for QAM64 (\f$ 2^{15} \times 4/\sqrt{84}\f$) +#define QAM64_TM5_n1 14301 +///Second Amplitude for QAM64 (\f$ 2^{15} \times 2/\sqrt{84}\f$) +#define QAM64_TM5_n2 7150 +///Third Amplitude for QAM64 for TM5 Receiver (\f$ 2^{15} \times 1/\sqrt{84}\f$) +#define QAM64_TM5_n3 3575 + + +#ifdef BIT8_RXMUX +#define PERROR_SHIFT 0 +#else +#define PERROR_SHIFT 10 +#endif + +#define BIT8_TX_SHIFT 2 +#define BIT8_TX_SHIFT_DB 12 + +//#define CHBCH_RSSI_MIN -75 + +#ifdef BIT8_TX +#define AMP 128 +#else +#define AMP 512//1024 //4096 +#endif + +#define AMP_OVER_SQRT2 ((AMP*ONE_OVER_SQRT2_Q15)>>15) +#define AMP_OVER_2 (AMP>>1) + +/// Threshold for PUCCH Format 1 detection +#define PUCCH1_THRES 0 +/// Threshold for PUCCH Format 1a/1b detection +#define PUCCH1a_THRES 4 + +/// Data structure for transmission. +typedef struct { + /// RAW TX sample buffer + char *TX_DMA_BUFFER[2]; +} TX_VARS ; + +/// Data structure for reception. +typedef struct { + /// RAW TX sample buffer + char *TX_DMA_BUFFER[2]; + /// RAW RX sample buffer + int *RX_DMA_BUFFER[2]; +} TX_RX_VARS; + +//! \brief Extension Type / +typedef enum { + CYCLIC_PREFIX, + CYCLIC_SUFFIX, + ZEROS, + NONE +} Extension_t; + +/// Measurement Variables +*/ +#define NUMBER_OF_SUBBANDS_MAX_NB_IoT 13 +/* +#define NUMBER_OF_HARQ_PID_MAX 8 + +#define MAX_FRAME_NUMBER 0x400 +#include "openairinterface5g_limits.h" + +#define NUMBER_OF_RN_MAX 3 +typedef enum {no_relay=1,unicast_relay_type1,unicast_relay_type2, multicast_relay} relaying_type_t; + +typedef struct { + //unsigned int rx_power[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; //! estimated received signal power (linear) + //unsigned short rx_power_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; //! estimated received signal power (dB) + //unsigned short rx_avg_power_dB[NUMBER_OF_CONNECTED_eNB_MAX]; //! estimated avg received signal power (dB) + + // RRC measurements + uint32_t rssi; + int n_adj_cells; + unsigned int adj_cell_id[6]; + uint32_t rsrq[7]; + uint32_t rsrp[7]; + float rsrp_filtered[7]; // after layer 3 filtering + float rsrq_filtered[7]; + // common measurements + //! estimated noise power (linear) + unsigned int n0_power[NB_ANTENNAS_RX]; + //! estimated noise power (dB) + unsigned short n0_power_dB[NB_ANTENNAS_RX]; + //! total estimated noise power (linear) + unsigned int n0_power_tot; + //! total estimated noise power (dB) + unsigned short n0_power_tot_dB; + //! average estimated noise power (linear) + unsigned int n0_power_avg; + //! average estimated noise power (dB) + unsigned short n0_power_avg_dB; + //! total estimated noise power (dBm) + short n0_power_tot_dBm; + + // UE measurements + //! estimated received spatial signal power (linear) + int rx_spatial_power[NUMBER_OF_CONNECTED_eNB_MAX][2][2]; + //! estimated received spatial signal power (dB) + unsigned short rx_spatial_power_dB[NUMBER_OF_CONNECTED_eNB_MAX][2][2]; + + /// estimated received signal power (sum over all TX antennas) + //int wideband_cqi[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + int rx_power[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + /// estimated received signal power (sum over all TX antennas) + //int wideband_cqi_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + unsigned short rx_power_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + + /// estimated received signal power (sum over all TX/RX antennas) + int rx_power_tot[NUMBER_OF_CONNECTED_eNB_MAX]; //NEW + /// estimated received signal power (sum over all TX/RX antennas) + unsigned short rx_power_tot_dB[NUMBER_OF_CONNECTED_eNB_MAX]; //NEW + + //! estimated received signal power (sum of all TX/RX antennas, time average) + int rx_power_avg[NUMBER_OF_CONNECTED_eNB_MAX]; + //! estimated received signal power (sum of all TX/RX antennas, time average, in dB) + unsigned short rx_power_avg_dB[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// SINR (sum of all TX/RX antennas, in dB) + int wideband_cqi_tot[NUMBER_OF_CONNECTED_eNB_MAX]; + /// SINR (sum of all TX/RX antennas, time average, in dB) + int wideband_cqi_avg[NUMBER_OF_CONNECTED_eNB_MAX]; + + //! estimated rssi (dBm) + short rx_rssi_dBm[NUMBER_OF_CONNECTED_eNB_MAX]; + //! estimated correlation (wideband linear) between spatial channels (computed in dlsch_demodulation) + int rx_correlation[NUMBER_OF_CONNECTED_eNB_MAX][2]; + //! estimated correlation (wideband dB) between spatial channels (computed in dlsch_demodulation) + int rx_correlation_dB[NUMBER_OF_CONNECTED_eNB_MAX][2]; + + /// Wideband CQI (sum of all RX antennas, in dB, for precoded transmission modes (3,4,5,6), up to 4 spatial streams) + int precoded_cqi_dB[NUMBER_OF_CONNECTED_eNB_MAX+1][4]; + /// Subband CQI per RX antenna (= SINR) + int subband_cqi[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX][NUMBER_OF_SUBBANDS_MAX]; + /// Total Subband CQI (= SINR) + int subband_cqi_tot[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX]; + /// Subband CQI in dB (= SINR dB) + int subband_cqi_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX][NUMBER_OF_SUBBANDS_MAX]; + /// Total Subband CQI + int subband_cqi_tot_dB[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX]; + /// Wideband PMI for each RX antenna + int wideband_pmi_re[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + /// Wideband PMI for each RX antenna + int wideband_pmi_im[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + ///Subband PMI for each RX antenna + int subband_pmi_re[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX][NB_ANTENNAS_RX]; + ///Subband PMI for each RX antenna + int subband_pmi_im[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX][NB_ANTENNAS_RX]; + /// chosen RX antennas (1=Rx antenna 1, 2=Rx antenna 2, 3=both Rx antennas) + unsigned char selected_rx_antennas[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX]; + /// Wideband Rank indication + unsigned char rank[NUMBER_OF_CONNECTED_eNB_MAX]; + /// Number of RX Antennas + unsigned char nb_antennas_rx; + /// DLSCH error counter + // short dlsch_errors; + +} PHY_MEASUREMENTS; +*/ +typedef enum {no_relay_NB_IoT=1,unicast_relay_type1_NB_IoT,unicast_relay_type2_NB_IoT, multicast_relay_NB_IoT} relaying_type_t_NB_IoT; +typedef struct { + //unsigned int rx_power[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; //! estimated received signal power (linear) + //unsigned short rx_power_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; //! estimated received signal power (dB) + //unsigned short rx_avg_power_dB[NUMBER_OF_CONNECTED_eNB_MAX]; //! estimated avg received signal power (dB) + + // RRC measurements + uint32_t rssi; + int n_adj_cells; + unsigned int adj_cell_id[6]; + uint32_t rsrq[7]; + uint32_t rsrp[7]; + float rsrp_filtered[7]; // after layer 3 filtering + float rsrq_filtered[7]; + // common measurements + //! estimated noise power (linear) + unsigned int n0_power[NB_ANTENNAS_RX]; + //! estimated noise power (dB) + unsigned short n0_power_dB[NB_ANTENNAS_RX]; + //! total estimated noise power (linear) + unsigned int n0_power_tot; + //! total estimated noise power (dB) + unsigned short n0_power_tot_dB; + //! average estimated noise power (linear) + unsigned int n0_power_avg; + //! average estimated noise power (dB) + unsigned short n0_power_avg_dB; + //! total estimated noise power (dBm) + short n0_power_tot_dBm; + + // UE measurements + //! estimated received spatial signal power (linear) + int rx_spatial_power[NUMBER_OF_CONNECTED_eNB_MAX][2][2]; + //! estimated received spatial signal power (dB) + unsigned short rx_spatial_power_dB[NUMBER_OF_CONNECTED_eNB_MAX][2][2]; + + /// estimated received signal power (sum over all TX antennas) + //int wideband_cqi[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + int rx_power[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + /// estimated received signal power (sum over all TX antennas) + //int wideband_cqi_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + unsigned short rx_power_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + + /// estimated received signal power (sum over all TX/RX antennas) + int rx_power_tot[NUMBER_OF_CONNECTED_eNB_MAX]; //NEW + /// estimated received signal power (sum over all TX/RX antennas) + unsigned short rx_power_tot_dB[NUMBER_OF_CONNECTED_eNB_MAX]; //NEW + + //! estimated received signal power (sum of all TX/RX antennas, time average) + int rx_power_avg[NUMBER_OF_CONNECTED_eNB_MAX]; + //! estimated received signal power (sum of all TX/RX antennas, time average, in dB) + unsigned short rx_power_avg_dB[NUMBER_OF_CONNECTED_eNB_MAX]; + + /// SINR (sum of all TX/RX antennas, in dB) + int wideband_cqi_tot[NUMBER_OF_CONNECTED_eNB_MAX]; + /// SINR (sum of all TX/RX antennas, time average, in dB) + int wideband_cqi_avg[NUMBER_OF_CONNECTED_eNB_MAX]; + + //! estimated rssi (dBm) + short rx_rssi_dBm[NUMBER_OF_CONNECTED_eNB_MAX]; + //! estimated correlation (wideband linear) between spatial channels (computed in dlsch_demodulation) + int rx_correlation[NUMBER_OF_CONNECTED_eNB_MAX][2]; + //! estimated correlation (wideband dB) between spatial channels (computed in dlsch_demodulation) + int rx_correlation_dB[NUMBER_OF_CONNECTED_eNB_MAX][2]; + + /// Wideband CQI (sum of all RX antennas, in dB, for precoded transmission modes (3,4,5,6), up to 4 spatial streams) + int precoded_cqi_dB[NUMBER_OF_CONNECTED_eNB_MAX+1][4]; + /// Subband CQI per RX antenna (= SINR) + int subband_cqi[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX][NUMBER_OF_SUBBANDS_MAX_NB_IoT]; + /// Total Subband CQI (= SINR) + int subband_cqi_tot[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX_NB_IoT]; + /// Subband CQI in dB (= SINR dB) + int subband_cqi_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX][NUMBER_OF_SUBBANDS_MAX_NB_IoT]; + /// Total Subband CQI + int subband_cqi_tot_dB[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX_NB_IoT]; + /// Wideband PMI for each RX antenna + int wideband_pmi_re[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + /// Wideband PMI for each RX antenna + int wideband_pmi_im[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; + ///Subband PMI for each RX antenna + int subband_pmi_re[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX_NB_IoT][NB_ANTENNAS_RX]; + ///Subband PMI for each RX antenna + int subband_pmi_im[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX_NB_IoT][NB_ANTENNAS_RX]; + /// chosen RX antennas (1=Rx antenna 1, 2=Rx antenna 2, 3=both Rx antennas) + unsigned char selected_rx_antennas[NUMBER_OF_CONNECTED_eNB_MAX][NUMBER_OF_SUBBANDS_MAX_NB_IoT]; + /// Wideband Rank indication + unsigned char rank[NUMBER_OF_CONNECTED_eNB_MAX]; + /// Number of RX Antennas + unsigned char nb_antennas_rx; + /// DLSCH error counter + // short dlsch_errors; + +} PHY_MEASUREMENTS_NB_IoT; + + +typedef struct { + //unsigned int rx_power[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; //! estimated received signal power (linear) + //unsigned short rx_power_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX]; //! estimated received signal power (dB) + //unsigned short rx_avg_power_dB[NUMBER_OF_CONNECTED_eNB_MAX]; //! estimated avg received signal power (dB) + + // common measurements + //! estimated noise power (linear) + unsigned int n0_power[NB_ANTENNAS_RX]; + //! estimated noise power (dB) + unsigned short n0_power_dB[NB_ANTENNAS_RX]; + //! total estimated noise power (linear) + unsigned int n0_power_tot; + //! estimated avg noise power (dB) + unsigned short n0_power_tot_dB; + //! estimated avg noise power (dB) + short n0_power_tot_dBm; + //! estimated avg noise power per RB per RX ant (lin) + unsigned short n0_subband_power[NB_ANTENNAS_RX][100]; + //! estimated avg noise power per RB per RX ant (dB) + unsigned short n0_subband_power_dB[NB_ANTENNAS_RX][100]; + //! estimated avg noise power per RB (dB) + short n0_subband_power_tot_dB[100]; + //! estimated avg noise power per RB (dBm) + short n0_subband_power_tot_dBm[100]; + // eNB measurements (per user) + //! estimated received spatial signal power (linear) + unsigned int rx_spatial_power[NUMBER_OF_UE_MAX_NB_IoT][2][2]; + //! estimated received spatial signal power (dB) + unsigned short rx_spatial_power_dB[NUMBER_OF_UE_MAX_NB_IoT][2][2]; + //! estimated rssi (dBm) + short rx_rssi_dBm[NUMBER_OF_UE_MAX_NB_IoT]; + //! estimated correlation (wideband linear) between spatial channels (computed in dlsch_demodulation) + int rx_correlation[NUMBER_OF_UE_MAX_NB_IoT][2]; + //! estimated correlation (wideband dB) between spatial channels (computed in dlsch_demodulation) + int rx_correlation_dB[NUMBER_OF_UE_MAX_NB_IoT][2]; + + /// Wideband CQI (= SINR) + int wideband_cqi[NUMBER_OF_UE_MAX_NB_IoT][NB_ANTENNAS_RX]; + /// Wideband CQI in dB (= SINR dB) + int wideband_cqi_dB[NUMBER_OF_UE_MAX_NB_IoT][NB_ANTENNAS_RX]; + /// Wideband CQI (sum of all RX antennas, in dB) + char wideband_cqi_tot[NUMBER_OF_UE_MAX_NB_IoT]; + /// Subband CQI per RX antenna and RB (= SINR) + int subband_cqi[NUMBER_OF_UE_MAX_NB_IoT][NB_ANTENNAS_RX][100]; + /// Total Subband CQI and RB (= SINR) + int subband_cqi_tot[NUMBER_OF_UE_MAX_NB_IoT][100]; + /// Subband CQI in dB and RB (= SINR dB) + int subband_cqi_dB[NUMBER_OF_UE_MAX_NB_IoT][NB_ANTENNAS_RX][100]; + /// Total Subband CQI and RB + int subband_cqi_tot_dB[NUMBER_OF_UE_MAX_NB_IoT][100]; + +} PHY_MEASUREMENTS_eNB_NB_IoT; +/* +#define MCS_COUNT 28 +#define MCS_TABLE_LENGTH_MAX 64 +*/ +#endif //__PHY_IMPLEMENTATION_DEFS_H__ +/**@} +*/ diff --git a/openair1/PHY/types_NB_IoT.h b/openair1/PHY/types_NB_IoT.h new file mode 100644 index 0000000000..e8a6ea501e --- /dev/null +++ b/openair1/PHY/types_NB_IoT.h @@ -0,0 +1,32 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef __openair_TYPES_NB_IOT_H__ +#define __openair_TYPES_NB_IOT_H__ + +#ifdef USER_MODE +#include +#else +#include +#endif + + +#endif /*__openair_TYPES_NB_IOT_H__ */ diff --git a/openair1/SCHED/prach_procedures.c b/openair1/SCHED/prach_procedures.c index 79af3c128e..4730eed613 100644 --- a/openair1/SCHED/prach_procedures.c +++ b/openair1/SCHED/prach_procedures.c @@ -36,6 +36,7 @@ #include "SCHED/extern.h" #include "nfapi_interface.h" #include "fapi_l1.h" +#include "nfapi_pnf.h" #include "UTIL/LOG/log.h" #include "UTIL/LOG/vcd_signal_dumper.h" diff --git a/openair2/COMMON/platform_constants.h b/openair2/COMMON/platform_constants.h index f4004bdbf9..4debccc7b0 100644 --- a/openair2/COMMON/platform_constants.h +++ b/openair2/COMMON/platform_constants.h @@ -77,6 +77,10 @@ #define MAX_MANAGED_ENB_PER_MOBILE 2 +///NB-IOT +#define NB_RB_MAX_NB_IOT (maxDRB_NB_r13 + 3) //MP: NB_IoT --> 2(DRB)+3(SRBs - 2 is not used) = 5 + + #define DEFAULT_RAB_ID 1 #define NB_RB_MAX (maxDRB + 3) /* was 11, now 14, maxDRB comes from asn1_constants.h, + 3 because of 3 SRB, one invisible id 0, then id 1 and 2 */ diff --git a/openair2/COMMON/rrc_messages_def.h b/openair2/COMMON/rrc_messages_def.h index be3d18c996..08ea93f427 100644 --- a/openair2/COMMON/rrc_messages_def.h +++ b/openair2/COMMON/rrc_messages_def.h @@ -54,6 +54,7 @@ MESSAGE_DEF(RRC_STATE_IND, MESSAGE_PRIORITY_MED, RrcStateInd, //-------------------------------------------------------------------------------------------// // eNB: ENB_APP -> RRC messages MESSAGE_DEF(RRC_CONFIGURATION_REQ, MESSAGE_PRIORITY_MED, RrcConfigurationReq, rrc_configuration_req) +MESSAGE_DEF(NBIOTRRC_CONFIGURATION_REQ, MESSAGE_PRIORITY_MED, NbIoTRrcConfigurationReq, nbiotrrc_configuration_req) // UE: NAS -> RRC messages MESSAGE_DEF(NAS_KENB_REFRESH_REQ, MESSAGE_PRIORITY_MED, NasKenbRefreshReq, nas_kenb_refresh_req) diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index 6fd0a04113..9bd25d3b3a 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -62,6 +62,8 @@ typedef UL_DCCH_Message_t RrcUlDcchMessage; #define RRC_CONFIGURATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_configuration_req +#define NBIOTRRC_CONFIGURATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.nbiotrrc_configuration_req + #define NAS_KENB_REFRESH_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_kenb_refresh_req #define NAS_CELL_SELECTION_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_cell_selection_req #define NAS_CONN_ESTABLI_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_conn_establi_req @@ -167,6 +169,77 @@ typedef struct RrcConfigurationReq_s { long ue_TimersAndConstants_n311[MAX_NUM_CCs]; long ue_TransmissionMode[MAX_NUM_CCs]; } RrcConfigurationReq; +#define MAX_NUM_NBIOT_CELEVELS 3 +typedef struct NbIoTRrcConfigurationReq_s { + uint32_t cell_identity; + + uint16_t tac; + + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_digit_length; + lte_frame_type_t frame_type; + uint8_t tdd_config; + uint8_t tdd_config_s; + lte_prefix_type_t prefix_type; + lte_prefix_type_t prefix_type_UL; + int16_t eutra_band; + uint32_t downlink_frequency; + int32_t uplink_frequency_offset; + int16_t Nid_cell;// for testing, change later + int16_t N_RB_DL;// for testing, change later + //RACH + long rach_raResponseWindowSize_NB; + long rach_macContentionResolutionTimer_NB; + long rach_powerRampingStep_NB; + long rach_preambleInitialReceivedTargetPower_NB; + long rach_preambleTransMax_CE_NB; + //BCCH + long bcch_modificationPeriodCoeff_NB; + //PCCH + long pcch_defaultPagingCycle_NB; + long pcch_nB_NB; + long pcch_npdcch_NumRepetitionPaging_NB; + //NPRACH + long nprach_CP_Length; + long nprach_rsrp_range; + long nprach_Periodicity[MAX_NUM_NBIOT_CELEVELS]; + long nprach_StartTime[MAX_NUM_NBIOT_CELEVELS]; + long nprach_SubcarrierOffset[MAX_NUM_NBIOT_CELEVELS]; + long nprach_NumSubcarriers[MAX_NUM_NBIOT_CELEVELS]; + long numRepetitionsPerPreambleAttempt_NB[MAX_NUM_NBIOT_CELEVELS]; + long nprach_SubcarrierMSG3_RangeStart; + long maxNumPreambleAttemptCE_NB; + long npdcch_NumRepetitions_RA[MAX_NUM_NBIOT_CELEVELS]; + long npdcch_StartSF_CSS_RA[MAX_NUM_NBIOT_CELEVELS]; + long npdcch_Offset_RA[MAX_NUM_NBIOT_CELEVELS]; + //NPDSCH + long npdsch_nrs_Power; + //NPUSCH + long npusch_ack_nack_numRepetitions_NB; + long npusch_srs_SubframeConfig_NB; + long npusch_threeTone_CyclicShift_r13; + long npusch_sixTone_CyclicShift_r13; + BOOLEAN_t npusch_groupHoppingEnabled; + long npusch_groupAssignmentNPUSCH_r13; + + //DL_GapConfig + long dl_GapThreshold_NB; + long dl_GapPeriodicity_NB; + long dl_GapDurationCoeff_NB; + //Uplink power control Common + long npusch_p0_NominalNPUSCH; + long npusch_alpha; + long deltaPreambleMsg3; + //UE timers and constants + long ue_TimersAndConstants_t300_NB; + long ue_TimersAndConstants_t301_NB; + long ue_TimersAndConstants_t310_NB; + long ue_TimersAndConstants_t311_NB; + long ue_TimersAndConstants_n310_NB; + long ue_TimersAndConstants_n311_NB; +} NbIoTRrcConfigurationReq; + // UE: NAS -> RRC messages typedef kenb_refresh_req_t NasKenbRefreshReq; diff --git a/openair2/COMMON/tasks_def.h b/openair2/COMMON/tasks_def.h index 530365828d..92d1ff4128 100644 --- a/openair2/COMMON/tasks_def.h +++ b/openair2/COMMON/tasks_def.h @@ -40,6 +40,10 @@ SUB_TASK_DEF(TASK_L2L1, TASK_PDCP_ENB, 200) /// Radio Resource Control task TASK_DEF(TASK_RRC_ENB, TASK_PRIORITY_MED, 200) + +// Define here for now +TASK_DEF(TASK_RRC_ENB_NB_IoT, TASK_PRIORITY_MED, 200) + /// S1ap task /// RAL task for ENB TASK_DEF(TASK_RAL_ENB, TASK_PRIORITY_MED, 200) diff --git a/openair2/ENB_APP/nbiot_config.c b/openair2/ENB_APP/NB_IoT_config.c similarity index 98% rename from openair2/ENB_APP/nbiot_config.c rename to openair2/ENB_APP/NB_IoT_config.c index 3862a01403..09e22ef845 100644 --- a/openair2/ENB_APP/nbiot_config.c +++ b/openair2/ENB_APP/NB_IoT_config.c @@ -33,13 +33,6 @@ #include "log.h" #include "log_extern.h" #include "assertions.h" -#include "enb_config.h" -#include "UTIL/OTG/otg.h" -#include "UTIL/OTG/otg_externs.h" -#if defined(OAI_EMU) -# include "OCG.h" -# include "OCG_extern.h" -#endif #if defined(ENABLE_ITTI) # include "intertask_interface.h" # if defined(ENABLE_USE_MME) @@ -47,16 +40,14 @@ # include "sctp_eNB_task.h" # endif #endif -#include "sctp_default_values.h" #include "SystemInformationBlockType2.h" -#include "LAYER2/MAC/extern.h" + #include "PHY/extern.h" #include "targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h" - #include "common/config/config_userapi.h" #include "RRC_config_tools.h" #include "RRC_paramsvalues.h" -#include "nbiot_paramdef.h" +#include "NB_IoT_paramdef.h" #include "L1_paramdef.h" #include "MACRLC_paramdef.h" #include "LAYER2/MAC/proto_NB_IoT.h" diff --git a/openair2/ENB_APP/nbiot_config.h b/openair2/ENB_APP/NB_IoT_config.h similarity index 100% rename from openair2/ENB_APP/nbiot_config.h rename to openair2/ENB_APP/NB_IoT_config.h diff --git a/openair2/ENB_APP/NB_IoT_interface.c b/openair2/ENB_APP/NB_IoT_interface.c new file mode 100644 index 0000000000..30ffbb3bb5 --- /dev/null +++ b/openair2/ENB_APP/NB_IoT_interface.c @@ -0,0 +1,58 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file openair2/ENB_APP/NB_IoT_interface.c + * \brief: load library implementing coding/decoding algorithms + * \date 2018 + * \version 0.1 + * \note + * \warning + */ +#define _GNU_SOURCE +#include + + +#include "openair1/PHY/extern.h" +#include "common/utils/load_module_shlib.h" +#define NBIOT_INTERFACE_SOURCE +#include "NB_IoT_interface.h" + + + + +int load_NB_IoT(void) { + int ret; + RCConfig_NbIoT_f_t RCConfig; + loader_shlibfunc_t shlib_fdesc[]=NBIOT_INTERFACE_FLIST; + + ret=load_module_shlib(NBIOT_MODULENAME,shlib_fdesc,sizeof(shlib_fdesc)/sizeof(loader_shlibfunc_t)); + if (ret) { + return ret; + } + RCConfig = get_shlibmodule_fptr(NBIOT_MODULENAME,NBIOT_RCCONFIG_FNAME ); + if (RCConfig == NULL) { + return -1; + } + + RCConfig(&RC); +return 0; +} + diff --git a/openair2/ENB_APP/NB_IoT_interface.h b/openair2/ENB_APP/NB_IoT_interface.h new file mode 100644 index 0000000000..b3454b077b --- /dev/null +++ b/openair2/ENB_APP/NB_IoT_interface.h @@ -0,0 +1,50 @@ +/* + *Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file openair2/ENB_APP/NB_IoT_interface.h + * \brief: api interface for nb-iot application + * \date 2018 + * \version 0.1 + * \note + * \warning + */ +#ifndef NBIOT_INTERFACE_H +#define NBIOT_INTERFACE_H + + +#define NBIOT_MODULENAME "NB_IoT" + +typedef void(*RCConfig_NbIoT_f_t)(RAN_CONTEXT_t *RC); +#define NBIOT_RCCONFIG_FNAME "RCConfig_NbIoT" + +#ifdef NBIOT_INTERFACE_SOURCE + +#define NBIOT_INTERFACE_FLIST {\ +{NBIOT_RCCONFIG_FNAME,NULL},\ +} + +#else /* NBIOT_INTERFACE_SOURCE */ + +extern int load_NB_IoT(void); + +#endif + +#endif diff --git a/openair2/ENB_APP/nbiot_paramdef.h b/openair2/ENB_APP/NB_IoT_paramdef.h similarity index 100% rename from openair2/ENB_APP/nbiot_paramdef.h rename to openair2/ENB_APP/NB_IoT_paramdef.h diff --git a/openair2/LAYER2/MAC/config_NB_IoT.h b/openair2/LAYER2/MAC/config_NB_IoT.h new file mode 100644 index 0000000000..0e497e3b0f --- /dev/null +++ b/openair2/LAYER2/MAC/config_NB_IoT.h @@ -0,0 +1,301 @@ + +/*! \file config_NB_IoT.h + * \brief configured structures used by scheduler + * \author NTUST BMW Lab./ + * \date 2017 + * \email: + * \version 1.0 + * + */ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +//#include "NB_IoT_Message_definitions.h" + +#define NUMBER_OF_SIBS_MAX_NB_IoT 6 + +///MIB +typedef enum operationModeInf{ + iNB_IoTand_SamePCI_r13 = 1, + iNB_IoTand_DifferentPCI_r13 = 2, + guardband_r13 = 3, + standalone_r13 = 4 +}operationModeInf_t; + +///SIB1_SchedulingInfo_NB_IoT_r13 +typedef enum si_Periodicity{ + si_Periodicity_rf64=640, + si_Periodicity_rf128=1280, + si_Periodicity_rf256=2560, + si_Periodicity_rf512=5120, + si_Periodicity_rf1024=10240, + si_Periodicity_rf2048=20480, + si_Periodicity_rf4096=40960 +}si_Periodicity_NB_IoT; + +typedef enum si_RepetitionPattern{ + si_RepetitionPattern_every2ndRF=0, + si_RepetitionPattern_every4thRF, + si_RepetitionPattern_every8thRF, + si_RepetitionPattern_every16thRF +}si_RepetitionPattern_NB_IoT; + +typedef enum sib_MappingInfo{ + sib2_v=0x1, + sib3_v=0x2, + sib4_v=0x4, + sib5_v=0x8, + sib14_v=0x10, + sib16_v=0x20 +}sib_MappingInfo_NB_IoT; + +typedef enum si_TB{ + si_TB_56=2, + si_TB_120=2, + si_TB_208=8, + si_TB_256=8, + si_TB_328=8, + si_TB_440=8, + si_TB_552=8, + si_TB_680=8 +}si_TB_NB_IoT; + +///RACH_ConfigCommon configuration + +typedef enum ra_ResponseWindowSize{ + ra_ResponseWindowSize_pp2=2, + ra_ResponseWindowSize_pp3=3, + ra_ResponseWindowSize_pp4=4, + ra_ResponseWindowSize_pp5=5, + ra_ResponseWindowSize_pp6=6, + ra_ResponseWindowSize_pp7=7, + ra_ResponseWindowSize_pp8=8, + ra_ResponseWindowSize_pp10=10 +}ra_ResponseWindowSize_NB_IoT; + +typedef enum mac_ContentionResolutionTimer{ + mac_ContentionResolutionTimer_pp1=1, + mac_ContentionResolutionTimer_pp2=2, + mac_ContentionResolutionTimer_pp3=3, + mac_ContentionResolutionTimer_pp4=4, + mac_ContentionResolutionTimer_pp8=8, + mac_ContentionResolutionTimer_pp16=16, + mac_ContentionResolutionTimer_pp32=32, + mac_ContentionResolutionTimer_pp64=64 +}mac_ContentionResolutionTimer_NB_IoT; + +///NPRACH_ConfigSIB configuration + +typedef enum nprach_Periodicity{ + nprach_Periodicity_ms40=40, + nprach_Periodicity_ms80=80, + nprach_Periodicity_ms160=160, + nprach_Periodicity_ms240=240, + nprach_Periodicity_ms320=320, + nprach_Periodicity_ms640=640, + nprach_Periodicity_ms1280=1280, + nprach_Periodicity_ms2560=2560 +}nprach_Periodicity_NB_IoT; + +typedef enum nprach_StartTime{ + nprach_StartTime_ms8=8, + nprach_StartTime_ms16=16, + nprach_StartTime_ms32=32, + nprach_StartTime_ms64=64, + nprach_StartTime_ms128=128, + nprach_StartTime_ms256=256, + nprach_StartTime_ms512=512, + nprach_StartTime_ms1024=1024 +}nprach_StartTime_NB_IoT; + +typedef enum nprach_SubcarrierOffset{ + nprach_SubcarrierOffset_n0=0, + nprach_SubcarrierOffset_n12=12, + nprach_SubcarrierOffset_n24=24, + nprach_SubcarrierOffset_n36=36, + nprach_SubcarrierOffset_n2=2, + nprach_SubcarrierOffset_n18=18, + nprach_SubcarrierOffset_n34=34 +}nprach_SubcarrierOffset_NB_IoT; + +typedef enum nprach_NumSubcarriers{ + nprach_NumSubcarriers_n12=12, + nprach_NumSubcarriers_n24=24, + nprach_NumSubcarriers_n36=36, + nprach_NumSubcarriers_n48=48 +}nprach_NumSubcarriers_NB_IoT; + +typedef enum nprach_SubcarrierMSG3_RangeStart{ + nprach_SubcarrierMSG3_RangeStart_zero=0, + nprach_SubcarrierMSG3_RangeStart_oneThird=1/3, + nprach_SubcarrierMSG3_RangeStart_twoThird=2/3, + nprach_SubcarrierMSG3_RangeStart_one=1 +}nprach_SubcarrierMSG3_RangeStart_NB_IoT; + +typedef enum maxNumPreambleAttemptCE{ + maxNumPreambleAttemptCE_n3=3, + maxNumPreambleAttemptCE_n4=4, + maxNumPreambleAttemptCE_n5=5, + maxNumPreambleAttemptCE_n6=6, + maxNumPreambleAttemptCE_n7=7, + maxNumPreambleAttemptCE_n8=8, + maxNumPreambleAttemptCE_n10=10 +}maxNumPreambleAttemptCE_NB_IoT; + +typedef enum numRepetitionsPerPreambleAttempt{ + numRepetitionsPerPreambleAttempt_n1=1, + numRepetitionsPerPreambleAttempt_n2=2, + numRepetitionsPerPreambleAttempt_n4=4, + numRepetitionsPerPreambleAttempt_n8=8, + numRepetitionsPerPreambleAttempt_n16=16, + numRepetitionsPerPreambleAttempt_n32=32, + numRepetitionsPerPreambleAttempt_n64=64, + numRepetitionsPerPreambleAttempt_n128=128 +}numRepetitionsPerPreambleAttempt_NB_IoT; + +typedef enum npdcch_NumRepetitions_RA{ + npdcch_NumRepetitions_RA_r1=1, + npdcch_NumRepetitions_RA_r2=2, + npdcch_NumRepetitions_RA_r4=4, + npdcch_NumRepetitions_RA_r8=8, + npdcch_NumRepetitions_RA_r16=16, + npdcch_NumRepetitions_RA_r32=32, + npdcch_NumRepetitions_RA_r64=64, + npdcch_NumRepetitions_RA_r128=128, + npdcch_NumRepetitions_RA_r256=256, + npdcch_NumRepetitions_RA_r512=512, + npdcch_NumRepetitions_RA_r1024=1024, + npdcch_NumRepetitions_RA_r2048=2048 +}npdcch_NumRepetitions_RA_NB_IoT; + +typedef enum npdcch_StartSF_CSS_RA{ + npdcch_StartSF_CSS_RA_v1dot5=3/2, + npdcch_StartSF_CSS_RA_v2=2, + npdcch_StartSF_CSS_RA_v4=4, + npdcch_StartSF_CSS_RA_v8=8, + npdcch_StartSF_CSS_RA_v16=16, + npdcch_StartSF_CSS_RA_v32=32, + npdcch_StartSF_CSS_RA_v48=48, + npdcch_StartSF_CSS_RA_v64=64 +}npdcch_StartSF_CSS_RA_NB_IoT; + +typedef enum npdcch_Offset_RA{ + zero=0, + oneEighth=1/8, + oneFourth=1/4, + threeEighth=3/8 +}npdcch_Offset_RA_NB_IoT; + +typedef enum si_window_length_e{ + ms160=160, + ms320=320, + ms480=480, + ms640=640, + ms960=960, + ms1280=1280, + ms1600=1600 +}si_window_length_t; + +typedef enum si_periodicity_e{ + rf64=640, + rf128=1280, + rf256=2560, + rf512=5120, + rf1024=10240, + rf2048=20480, + rf4096=40960 +}si_periodicity_t; + +typedef enum si_repetition_pattern_e{ + every2ndRF=20, + every4thRF=40, + every8thRF=80, + every16thRF=160 +}si_repetition_pattern_t; + +typedef enum si_tb_e{ + b56=2, + b120=2, + b208=8, + b256=8, + b328=8, + b440=8, + b552=8, + b680=8 +}si_tb_t; + + +typedef struct sibs_NB_IoT_sched_s{ + si_periodicity_t si_periodicity; + si_repetition_pattern_t si_repetition_pattern; + sib_MappingInfo_NB_IoT sib_mapping_info; //bit vector + si_tb_t si_tb; + +}sibs_NB_IoT_sched_t; + + +///-------------------------------------------------------MAC--------------------------------------------------------------------/// +typedef struct sib1_NB_IoT_sched_s{ + int repetitions; // 4, 8, 16 + int starting_rf; +}sib1_NB_IoT_sched_t; + +typedef struct { + + uint32_t mac_ra_ResponseWindowSize_NB_IoT; + uint32_t mac_ContentionResolutionTimer_NB_IoT; + +}mac_RACH_ConfigCommon_NB_IoT; + +typedef struct { + + uint32_t mac_nprach_Periodicity_NB_IoT; + uint32_t mac_nprach_StartTime_NB_IoT; + uint32_t mac_nprach_SubcarrierOffset_NB_IoT; + uint32_t mac_nprach_NumSubcarriers_NB_IoT; + uint32_t mac_nprach_SubcarrierMSG3_RangeStart_NB_IoT; + uint32_t mac_maxNumPreambleAttemptCE_NB_IoT; + uint32_t mac_numRepetitionsPerPreambleAttempt_NB_IoT; + // css + uint32_t mac_npdcch_NumRepetitions_RA_NB_IoT; // rmax + uint32_t mac_npdcch_StartSF_CSS_RA_NB_IoT; // G + uint32_t mac_npdcch_Offset_RA_NB_IoT; // alpha offset + +}mac_NPRACH_ConfigSIB_NB_IoT; + +typedef struct{ + //npdcch-NumRepetitions-r13 + uint32_t R_max; + //npdcch-StartSF-USS-r13 + double G; + //npdcch-Offset-USS-r13 + double a_offset; +}npdcch_ConfigDedicated_NB_IoT; + +typedef struct rrc_config_NB_IoT_s{ + + ///MIB + uint16_t schedulingInfoSIB1_NB_IoT; + + ///SIB1 + uint32_t cellIdentity_NB_IoT; + + sib1_NB_IoT_sched_t sib1_NB_IoT_sched_config; + ///SIBS + sibs_NB_IoT_sched_t sibs_NB_IoT_sched[NUMBER_OF_SIBS_MAX_NB_IoT]; + si_window_length_t si_window_length; + uint32_t si_radio_frame_offset; + + ///SIB2 mac_RACH_ConfigCommon_NB_IoT + mac_RACH_ConfigCommon_NB_IoT mac_RACH_ConfigCommon[3]; + + ///SIB2 mac_NPRACH_ConfigSIB_NB_IoT + mac_NPRACH_ConfigSIB_NB_IoT mac_NPRACH_ConfigSIB[3]; + + ///NPDCCH Dedicated config + npdcch_ConfigDedicated_NB_IoT npdcch_ConfigDedicated[3]; + +}rrc_config_NB_IoT_t; + +#endif diff --git a/openair2/LAYER2/MAC/defs_NB_IoT.h b/openair2/LAYER2/MAC/defs_NB_IoT.h new file mode 100644 index 0000000000..a427de5b2c --- /dev/null +++ b/openair2/LAYER2/MAC/defs_NB_IoT.h @@ -0,0 +1,543 @@ + +/*! \file defs_NB_IoT.c + * \brief MAC layer structures + * \author NTUST BMW Lab./ + * \date 2017 + * \email: + * \version 1.0 + * + */ +#ifndef __LAYER2_MAC_DEFS_NB_IOT_H__ +#define __LAYER2_MAC_DEFS_NB_IOT_H__ +#ifdef USER_MODE +#include +#include +#include +#endif +//#include "COMMON/openair_defs.h" +#include "COMMON/platform_constants.h" +#include "COMMON/mac_rrc_primitives.h" +#include "PHY/LTE_TRANSPORT/defs_NB_IoT.h" +//#include "PHY/defs.h" +#include "PHY/defs_L1_NB_IoT.h" +#include "openair2/PHY_INTERFACE/IF_Module_NB_IoT.h" +#include "config_NB_IoT.h" +// MAC definition +#define MAX_FRAME 0xfffff +#define NUM_FRAME 0x100000 +#define MAX_SUBFRAME 10485760 + +#define MAX(a, b) (((a)>(b))?(a):(b)) + +// RA-RNTI: 1+SFN_id>>2 +#define RA_RNTI_LOW 0x0001 // SFN_id = 0 +#define RA_RNTI_HIGH 0x0100 // SFN_id = 1023 +#define C_RNTI_LOW 0x0101 +#define C_RNTI_HIGH + +// ULSCH LCHAN IDs +/*!\brief LCID of extended power headroom for ULSCH */ +#define EXTENDED_POWER_HEADROOM 25 +/*!\brief LCID of power headroom for ULSCH */ +#define POWER_HEADROOM 26 +/*!\brief LCID of CRNTI for ULSCH */ +#define CRNTI 27 +/*!\brief LCID of truncated BSR for ULSCH */ +#define TRUNCATED_BSR 28 +/*!\brief LCID of short BSR for ULSCH */ +#define SHORT_BSR 29 +/*!\brief LCID of long BSR for ULSCH */ +#define LONG_BSR 30 +/*! \brief Values of CCCH LCID for DLSCH */ +#define CCCH_LCHANID 0 +/*!\brief Values of BCCH logical channel */ +#define BCCH 3 // SI +/*!\brief Values of PCCH logical channel */ +#define PCCH 4 // Paging +/*!\brief Value of CCCH / SRB0 logical channel */ +#define CCCH 0 // srb0 +/*!\brief DCCH / SRB1 logical channel */ +#define DCCH 1 // srb1 +/*!\brief DCCH1 / SRB2 logical channel */ +#define DCCH1 2 // srb2 +/*!\brief DTCH DRB1 logical channel */ +#define DTCH 3 // LCID +/*!\brief MCCH logical channel */ +#define MCCH 4 +/*!\brief MTCH logical channel */ +#define MTCH 1 +// DLSCH LCHAN ID +/*!\brief LCID of UE contention resolution identity for DLSCH*/ +#define UE_CONT_RES 28 +/*!\brief LCID of timing advance for DLSCH */ +#define TIMING_ADV_CMD 29 +/*!\brief LCID of discontinous reception mode for DLSCH */ +#define DRX_CMD 30 +/*!\brief LCID of padding LCID for DLSCH */ +#define SHORT_PADDING 31 + + +typedef enum tone_type_e +{ + sixtone = 0, + threetone, + singletone1, + singletone2, + singletone3 +}tone_type_t; + +typedef enum channel_NB_IoT_e +{ + NPDCCH = 0, + NPUSCH, + NPDSCH +}channel_NB_IoT_t; + +typedef enum{ + UL = 0, + DL +}message_direction_t; + +#define MAX_NUMBER_OF_UE_MAX_NB_IoT 20 +#define SCH_PAYLOAD_SIZE_MAX_NB_IoT 320 +#define MAX_NUMBER_OF_SIBs_NB_IoT 16 + +/*!\brief Values of BCCH0 logical channel for MIB*/ +#define BCCH0_NB_IoT 11 // MIB-NB_IoT +/*!\brief Values of BCCH1 logical channel for SIBs */ +#define BCCH1_NB_IoT 12 // SI-SIB-NB_IoTs +/*!\brief Values of PCCH logical channel */ +#define PCCH_NB_IoT 13 // Paging XXX not used for the moment +#define MCCH_NB_IoT 14 +/*!\brief Value of CCCH / SRB0 logical channel */ +#define CCCH_NB_IoT 0 // srb0 ---> XXX exactly the same as in LTE (commented for compilation purposes) +/*!\brief DCCH0 / SRB1bis logical channel */ +#define DCCH0_NB_IoT 3 // srb1bis +/*!\brief DCCH1 / SRB1 logical channel */ +#define DCCH1_NB_IoT 1 // srb1 //XXX we redefine it for the SRB1 +/*!\brief DTCH0 DRB0 logical channel */ +#define DTCH0_NB_IoT 4 // DRB0 +/*!\brief DTCH1 DRB1 logical channel */ +#define DTCH1_NB_IoT 5 // DRB1 +/*Index of UE contention resoulution logical channel*/ +#define UE_CONTENTION_RESOLUTION 28 +/*Index of TIMING_ADVANCE logical channel*/ +#define TIMING_ADVANCE 29 +/*Index of DRX_COMMAND logical channel*/ +#define DRX_COMMAND 30 +/*Index of PADDING logical channel*/ +#define PADDING 31 + + +/// NPRACH-ParametersList-NB_IoT-r13 from 36.331 RRC spec defined in PHY +/*typedef struct NPRACH_Parameters_NB_IoT{ + + /// the period time for nprach + int nprach_Periodicity; + /// for the start time for the NPRACH resource from 40ms-2560ms + int nprach_StartTime; + /// for the subcarrier of set to the NPRACH preamble from n0 - n34 + int nprach_SubcarrierOffset; + ///number of subcarriers in a NPRACH resource allowed values (n12,n24,n36,n48) + int nprach_NumSubcarriers; + /// where is the region that in NPRACH resource to indicate if this UE support MSG3 for multi-tone or not. from 0 - 1 + int nprach_SubcarrierMSG3_RangeStart; + /// The max preamble transmission attempt for the CE level from 1 - 128 + int maxNumPreambleAttemptCE; + /// Number of NPRACH repetitions per attempt for each NPRACH resource + int numRepetitionsPerPreambleAttempt; + /// The number of the repetition for DCI use in RAR/MSG3/MSG4 from 1 - 2048 (Rmax) + int npdcch_NumRepetitions_RA; + /// Starting subframe for NPDCCH Common searching space for (RAR/MSG3/MSG4) + int npdcch_StartSF_CSS_RA; + /// Fractional period offset of starting subframe for NPDCCH common search space + int npdcch_Offset_RA; + +} nprach_parameters_NB_IoT_t;*/ + +/*! \brief Downlink SCH PDU Structure */ +typedef struct { + uint8_t payload[SCH_PAYLOAD_SIZE_MAX_NB_IoT]; + uint32_t pdu_size; +} __attribute__ ((__packed__)) DLSCH_PDU_NB_IoT; + +/*! \brief eNB template for UE context information */ +typedef struct { + // C-RNTI of UE + rnti_t rnti; + // UE CE level + int CE_level; + // Direction of transmission(DL:0\UL:1\NONE:-1) + int32_t direction; + // DCI Reptition + uint32_t R_dci; + // MAX repetition + uint32_t R_max; + + // HARQ round + uint32_t HARQ_round; + /*Downlink information*/ + + /// DLSCH pdu + DLSCH_PDU_NB_IoT DLSCH_pdu; + // PDU size + uint32_t DLSCH_pdu_size; + // Data Reptition + uint32_t R_dl; + // MCS index + uint32_t I_mcs_dl; + // total downlink buffer DCCH0_NB_IoT + uint32_t dl_buffer_DCCH0_NB_IoT; + // NDI + int oldNDI_DL; + //HARQ ACK/NACK repetition + uint32_t R_harq; + + /*Uplink information*/ + int oldNDI_UL; + // Uplink data repeat, now just follow the rach repeat number + uint32_t R_ul; + // PHR value (0-3) + uint32_t PHR; + // The uplink data size from BSR or DVI + uint32_t ul_total_buffer; + // Determine if this UE support multi-tone transmission or not + int multi_tone; + // Next UE_template ID + int next; + // Previous UE_template ID + int prev; + // MSG4 complete + int RRC_connected; + // UE active flag + int active; + +} UE_TEMPLATE_NB_IoT; + +/*36331 NPDCCH-ConfigDedicated-NB_IoT*/ +typedef struct{ + //npdcch-NumRepetitions-r13 + uint32_t R_max; + //npdcch-StartSF-USS-r13 + double G; + //npdcch-Offset-USS-r13 + double a_offset; + //NPDCCH period + uint32_t T; + //Starting subfrane of Search Space which is mod T + uint32_t ss_start_uss; +}NPDCCH_config_dedicated_NB_IoT_t; + + +/*! \brief UE list used by eNB to order UEs/CC for scheduling*/ +typedef struct { + + /// DCI template and MAC connection parameters for UEs + UE_TEMPLATE_NB_IoT UE_template_NB_IoT[MAX_NUMBER_OF_UE_MAX_NB_IoT]; + + /// NPDCCH Period and searching space info + NPDCCH_config_dedicated_NB_IoT_t NPDCCH_config_dedicated; + //int next[MAX_NUMBER_OF_UE_MAX_NB_IoT]; + // -1:No UE in list + int head; + // -1:No UE in list + int tail; + int num_UEs; + //boolean_t active[MAX_NUMBER_OF_UE_MAX_NB_IoT]; + +} UE_list_NB_IoT_t; + + +typedef struct{ + + // flag to indicate scheduing MIB-NB_IoT + uint8_t flag_MIB; + // flag to indicate scheduling SIB1-NB_IoT + uint8_t flag_SIB1; + // flag to indicate scheduling SIBs-NB_IoT + uint8_t flag_SIBs[MAX_NUMBER_OF_SIBs_NB_IoT]; + // flag to indicate scheduling type2 NPDCCH CSS with different CE level + uint8_t flag_type2_css[3]; + // flag to indicate scheduling type1 NPDCCH CSS with different CE level + uint8_t flag_type1_css[3]; + // flag to indicate scheduling NPDCCH USS with UE list + uint8_t flag_uss[MAX_NUMBER_OF_UE_MAX_NB_IoT]; + // flag to indicate scheduling sib1/MIB + uint8_t flag_fix_scheduling; + // number of the type2 css to schedule in this period + uint8_t num_type2_css_run; + // number of the type1 css to schedule in this period + uint8_t num_type1_css_run; + // number of the uss to schedule in this period + uint8_t num_uss_run; + +}scheduling_flag_t; + +typedef struct available_resource_UL_s{ + + ///Resource start subframe + uint32_t start_subframe; + ///Resource end subframe + uint32_t end_subframe; + // pointer to next node + struct available_resource_UL_s *next, *prev; + +}available_resource_UL_t; + +typedef struct available_resource_DL_s{ + uint32_t start_subframe; + uint32_t end_subframe; + + struct available_resource_DL_s *next, *prev; +}available_resource_DL_t; + +/*Structure used for scheduling*/ +typedef struct{ + //resource position info. + uint32_t sf_end,sf_start; + //resource position info. separate by HyperSF, Frame, Subframe + uint32_t start_h, end_h; + uint32_t start_f, end_f; + uint32_t start_sf, end_sf; + //whcih available resource node is used + available_resource_DL_t *node; +}sched_temp_DL_NB_IoT_t; + +/*!\brief MAC subheader short with 7bit Length field */ +typedef struct { + uint8_t LCID:5; // octet 1 LSB + uint8_t E:1; + uint8_t F2:1; + uint8_t R:1; // octet 1 MSB + uint8_t L:7; // octet 2 LSB + uint8_t F:1; // octet 2 MSB +} __attribute__((__packed__))SCH_SUBHEADER_SHORT_NB_IoT; +typedef struct { + uint8_t LCID:5; // octet 1 LSB + uint8_t E:1; + uint8_t F2:1; + uint8_t R:1; // octet 1 MSB + uint8_t L_MSB:7; + uint8_t F:1; // octet 2 MSB + uint8_t L_LSB:8; +} __attribute__((__packed__))SCH_SUBHEADER_LONG_NB_IoT; +typedef struct { + uint8_t LCID:5; // octet 1 LSB + uint8_t E:1; + uint8_t F2:1; + uint8_t R:1; // octet 1 MSB + uint8_t L_MSB:8; // octet 2 MSB + uint8_t L_LSB:8; +} __attribute__((__packed__))SCH_SUBHEADER_LONG_EXTEND_NB_IoT; +/*!\brief MAC subheader short without length field */ +typedef struct { + uint8_t LCID:5; + uint8_t F2:1; + uint8_t E:1; + uint8_t R:1; +} __attribute__((__packed__))SCH_SUBHEADER_FIXED_NB_IoT; + + +/*! \brief Uplink SCH PDU Structure */ +typedef struct { + int8_t payload[SCH_PAYLOAD_SIZE_MAX_NB_IoT]; /*!< \brief SACH payload */ + uint16_t Pdu_size; +} __attribute__ ((__packed__)) ULSCH_PDU_NB_IoT; + +typedef struct { + uint8_t PH:6; + uint8_t R:2; +} __attribute__((__packed__))POWER_HEADROOM_CMD_NB_IoT; + +typedef struct { + uint8_t RAPID:6; + uint8_t T:1; + uint8_t E:1; +} __attribute__((__packed__))RA_HEADER_RAPID_NB_IoT; + +/*Structure used for UL scheduling*/ +typedef struct{ + //resource position info. + uint32_t sf_end, sf_start; + //resource position info. separate by HyperSF, Frame, Subframe + //uint32_t start_h, end_h; + //uint32_t start_f, end_f; + //uint32_t start_sf, end_sf; + // information for allocating the resource + int tone; + int scheduling_delay; + int subcarrier_indication; + int ACK_NACK_resource_field; + available_resource_UL_t *node; +}sched_temp_UL_NB_IoT_t; + +typedef struct Available_available_resource_DL{ + + ///Available Resoruce for sixtone + available_resource_UL_t *sixtone_Head;//, *sixtone_npusch_frame; + uint32_t sixtone_end_subframe; + ///Available Resoruce for threetone + available_resource_UL_t *threetone_Head;//, *threetone_npusch_frame; + uint32_t threetone_end_subframe; + ///Available Resoruce for singletone1 + available_resource_UL_t *singletone1_Head;//, *singletone1_npusch_frame; + uint32_t singletone1_end_subframe; + ///Available Resoruce for singletone2 + available_resource_UL_t *singletone2_Head;//, *singletone2_npusch_frame; + uint32_t singletone2_end_subframe; + ///Available Resoruce for singletone3 + available_resource_UL_t *singletone3_Head;//, *singletone3_npusch_frame; + uint32_t singletone3_end_subframe; + +}available_resource_tones_UL_t; + +typedef struct schedule_result{ + // The subframe read by output handler + uint32_t output_subframe; + // SDU length + uint32_t sdu_length; + // MAC PDU + uint8_t *DLSCH_pdu; + // The data direction indicated by this DCI + uint8_t direction; + // pointer to DCI + void *DCI_pdu; + // when all the procedure related to this DCI, enable this flag + boolean_t DCI_release; + // Indicate the channel which to transmit + channel_NB_IoT_t channel; + // rnti + rnti_t rnti; + // 0 = TC-RNTI , 1 = RA-RNTI, 2 = P-RNTI, 3 = others + uint8_t rnti_type; + // 0 = data, 1 = ACK/NACK + uint8_t npusch_format; + //HARQ ACK/NACK repetition + uint32_t R_harq; + // pointer to next node + struct schedule_result *next; + + uint32_t end_subframe; + + uint8_t *rar_buffer; + +}schedule_result_t; + +/*Flag structure used for trigger each scheduler*/ +typedef struct{ + scheduling_flag_t scheduling_flag; + //sched_temp_DL_NB_IoT_t sched_result_DL; + //resource grid for Uplink + available_resource_tones_UL_t *UL_resource; + //scheduling result read by output handler + schedule_result_t *schedule_result_list_UL; + schedule_result_t *schedule_result_list_DL; +}SCHEDULE_NB_IoT_t; + +typedef struct{ + uint32_t num_dlsf_per_period; + uint16_t *sf_to_dlsf_table; + uint16_t *dlsf_to_sf_table; +}DLSF_INFO_t; + +typedef enum ce_level_e{ + ce0=0, + ce1, + ce2, + ce_level_total +}ce_level_t; + + + +/*! \brief eNB template for the Random access information */ +typedef struct RA_TEMPLATE_NB_IoT_s{ + + boolean_t active; + uint32_t msg3_retransmit_count; + uint32_t msg4_retransmit_count; + uint16_t ta; + uint8_t preamble_index; + ce_level_t ce_level; + rnti_t ue_rnti; + rnti_t ra_rnti; + struct RA_TEMPLATE_NB_IoT_s *next, *prev; + boolean_t wait_msg4_ack; + boolean_t wait_msg3_ack; + uint8_t rar_buffer[7]; + +} RA_TEMPLATE_NB_IoT; + +typedef struct RA_template_list_s{ + RA_TEMPLATE_NB_IoT *head; + RA_TEMPLATE_NB_IoT *tail; +}RA_template_list_t; + + +/*! \brief top level eNB MAC structure */ +typedef struct eNB_MAC_INST_NB_IoT_s { + /// Ethernet parameters for northbound midhaul interface + eth_params_t eth_params_n; + /// Ethernet parameters for fronthaul interface + eth_params_t eth_params_s; + + uint8_t Mod_id; + // System + uint32_t hyper_system_frame; + uint32_t system_frame; + uint32_t sub_frame; + + uint32_t current_subframe; + /// Pointer to IF module instance for PHY + IF_Module_t *if_inst; + // RA + RA_template_list_t RA_msg2_list; + RA_template_list_t RA_msg3_list; + RA_template_list_t RA_msg4_list; + + RA_TEMPLATE_NB_IoT RA_template[MAX_NUMBER_OF_UE_MAX_NB_IoT]; + + //int32_t last_tx_subframe; + + // for tool + int32_t sib1_flag[64]; + int32_t sib1_count[64]; + int32_t sib1_period; + uint16_t dlsf_table[64]; + int32_t sibs_table[256]; + + // channel config + + //USS list + //Number of USS period is used + int num_uss_list; + UE_list_NB_IoT_t *UE_list_spec; + + scheduling_flag_t scheduling_flag; + + uint32_t schedule_subframe_DL; + uint32_t schedule_subframe_UL; + + rrc_config_NB_IoT_t rrc_config; + + nfapi_config_request_t config; + + IF_Module_NB_IoT_t *if_inst_NB_IoT; +} eNB_MAC_INST_NB_IoT; + +// actually not here, but for now put it here +typedef struct { + uint32_t bytes_in_buffer; /*!< \brief Bytes buffered in RLC protocol instance. */ + uint32_t pdus_in_buffer; /*!< \brief Number of PDUs buffered in RLC protocol instance (OBSOLETE). */ + uint32_t head_sdu_creation_time; /*!< \brief Head SDU creation time. */ + uint32_t head_sdu_remaining_size_to_send; /*!< \brief remaining size of sdu: could be the total size or the remaining size of already segmented sdu */ + boolean_t head_sdu_is_segmented; /*!< \brief 0 if head SDU has not been segmented, 1 if already segmented */ +} mac_rlc_status_resp_NB_IoT_t; + +// global variables + +nprach_parameters_NB_IoT_t nprach_list[3]; + +//DLSF Table +DLSF_INFO_t DLSF_information; + +#endif /*__LAYER2_MAC_DEFS_NB_IoT_H__ */ diff --git a/openair2/LAYER2/MAC/proto_NB_IoT.h b/openair2/LAYER2/MAC/proto_NB_IoT.h new file mode 100644 index 0000000000..e493275987 --- /dev/null +++ b/openair2/LAYER2/MAC/proto_NB_IoT.h @@ -0,0 +1,198 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file LAYER2/MAC/proto_NB_IoT.h + * \brief MAC functions prototypes for eNB and UE + * \author Navid Nikaein and Raymond Knopp + * \date 2010 - 2014 + * \email navid.nikaein@eurecom.fr + * \version 1.0 + */ + +#ifndef __LAYER2_MAC_PROTO_NB_IoT_H__ +#define __LAYER2_MAC_PROTO_NB_IoT_H__ + +#include "openair1/PHY/LTE_TRANSPORT/defs_NB_IoT.h" +#include "LAYER2/MAC/defs_NB_IoT.h" +#include "COMMON/platform_types.h" +#include "openair2/RRC/LITE/defs_NB_IoT.h" +/** \addtogroup _mac + * @{ + */ + +int l2_init_eNB_NB_IoT(void); + +///config +void rrc_mac_config_req_NB_IoT( + module_id_t Mod_idP, + int CC_idP, + int rntiP, + rrc_eNB_carrier_data_NB_IoT_t *carrier, + SystemInformationBlockType1_NB_t *sib1_NB_IoT, + RadioResourceConfigCommonSIB_NB_r13_t *radioResourceConfigCommon, + PhysicalConfigDedicated_NB_r13_t *physicalConfigDedicated, + LogicalChannelConfig_NB_r13_t *logicalChannelConfig, //FIXME: decide how to use it + uint8_t ded_flag, + uint8_t ue_list_ded_num); + +///system +void init_mac_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst); +//void init_rrc_NB_IoT(); +void release_mac_inst(uint8_t order); +eNB_MAC_INST_NB_IoT *get_mac_inst(uint8_t order); +uint8_t register_mac_inst(eNB_MAC_INST_NB_IoT *inst, uint8_t order); + +///tool +void init_tool(sib1_NB_IoT_sched_t *config); +void UE_info_setting(UE_TEMPLATE_NB_IoT *UE_info); +UE_TEMPLATE_NB_IoT *get_ue_from_rnti(eNB_MAC_INST_NB_IoT *inst, rnti_t rnti); + +///scheduler +void eNB_dlsch_ulsch_scheduler_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t abs_subframe); +void eNB_scheduler_computing_flag_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t abs_subframe, uint32_t *scheduler_flags, uint32_t *common_flags, uint32_t *max_subframe); + +//Calvin temp define self-tools +int init_debug(eNB_MAC_INST_NB_IoT *inst); +void maintain_available_resource(eNB_MAC_INST_NB_IoT *mac_inst); +void extend_available_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, int max_subframe); +available_resource_DL_t *check_sibs_resource(eNB_MAC_INST_NB_IoT *mac_inst, int check_start_subframe, int check_end_subframe, int num_subframe, int *residual_subframe, int *out_last_subframe, int *out_first_subframe); +uint32_t calculate_DLSF(eNB_MAC_INST_NB_IoT *mac_inst, int abs_start_subframe, int abs_end_subframe); +void init(eNB_MAC_INST_NB_IoT *mac_inst); +void init_dl_list(eNB_MAC_INST_NB_IoT *mac_inst); +int is_dlsf(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); +void fill_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, available_resource_DL_t *node, int start_subframe, int end_subframe, schedule_result_t *new_node); +available_resource_DL_t *check_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, int check_subframe, int num_subframes, int *out_last_subframe, int *out_first_subframe); +void print_available_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst); +void print_schedule_result_DL(void); +void print_schedule_result_UL(void); +void add_ue(eNB_MAC_INST_NB_IoT *mac_inst, uint16_t rnti, ce_level_t ce, uint32_t PHR, uint32_t ul_total_buffer); +void remove_ue(eNB_MAC_INST_NB_IoT *mac_inst, uint16_t rnti, ce_level_t ce); +// SIBs +void schedule_sibs(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t sibs_order, int start_subframe); + +//RA +void msg3_do_retransmit_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti); +void msg4_do_retransmit_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti); +void schedule_RA_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst); +void init_RA_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint8_t preamble_index, ce_level_t ce_level, uint32_t sfn_id, uint16_t ta); +void schedule_rar_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); +void receive_msg3_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti, uint32_t phr, uint32_t ul_total_buffer); +void schedule_msg3_retransimission_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); +void schedule_msg4_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); +void fill_rar_NB_IoT(eNB_MAC_INST_NB_IoT *inst, RA_TEMPLATE_NB_IoT *ra_template, uint8_t msg3_schedule_delay, uint8_t msg3_rep, sched_temp_UL_NB_IoT_t *schedule_template); +void receive_msg4_ack_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t rnti); + +//USS +void schedule_uss_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, uint32_t subframe, uint32_t frame, uint32_t hypersfn, int index_ss); + +//DATA +uint8_t *parse_ulsch_header( uint8_t *mac_header, + uint8_t *num_ce, + uint8_t *num_sdu, + uint8_t *rx_ces, + uint8_t *rx_lcids, + uint16_t *rx_lengths, + uint16_t tb_length ); + +/*******UL Scheduler**********/ +void print_scheduling_result_UL(void); +void print_available_UL_resource(void); +/*set nprach configuration at intial time*/ +void setting_nprach(void); +/*Uplink main scheduler*/ +int schedule_UL_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst,UE_TEMPLATE_NB_IoT *UE_info, uint32_t subframe, uint32_t frame, uint32_t H_SFN); +/*Check available uplink resource list, if there is available uplink resource, return 0, otherwise, return 1*/ +int Check_UL_resource(uint32_t DL_end, int total_ru, sched_temp_UL_NB_IoT_t *NPUSCH_info, int multi_tone, int fmt2_flag); +/*Get I Repetition number in DCI*/ +int get_I_REP(int N_rep); +/*Get N REP from preamble repeat*/ +int get_N_REP(int CE_level); +/*Get TBS from mcs, multi-tone, Iru*/ +int get_TBS_UL_NB_IoT(uint32_t mcs,uint32_t multi_tone,int Iru); +/*get I tbs from mcs and multi-tone*/ +int get_I_TBS_NB_IoT(int x,int y); +/*Get DCI REP from R max and R*/ +int get_DCI_REP(uint32_t R,uint32_t R_max); +/*Check single tone resource list*/ +int single_tone_ru_allocation(uint32_t uplink_time, int total_ru, sched_temp_UL_NB_IoT_t *NPUSCH_info, int fmt2_flag); +/*Check multi tone resource list*/ +int multi_tone_ru_allocation(uint32_t uplink_time, int total_ru, sched_temp_UL_NB_IoT_t *NPUSCH_info); +/*Generate scheduling result of DCI N0 and Uplink config*/ +void generate_scheduling_result_UL(int32_t DCI_subframe, int32_t DCI_end_subframe, uint32_t UL_subframe, uint32_t UL_end_subframe, DCIFormatN0_t *DCI_inst, rnti_t rnti, uint8_t *ul_debug_str, uint8_t *dl_debug_str); +/*Adjust UL resource by removing the used resource*/ +void adjust_UL_resource_list(sched_temp_UL_NB_IoT_t *NPUSCH_info); +/*Initialize resource by nprach configuration*/ +void Initialize_Resource(void); +/*Function to extend uplink resource grid*/ +//void add_UL_Resource(eNB_MAC_INST_NB_IoT *mac_inst); +void add_UL_Resource(void); +/*Get ACK/NAK resource field*/ +int get_resource_field_value(int subcarrier, int k0); +/*Get DL Repetition index*/ +uint8_t get_index_Rep_dl(uint16_t R); + +/*******DL Scheduler********/ +void schedule_DL_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, UE_TEMPLATE_NB_IoT *UE_info, uint32_t hyperSF_start, uint32_t frame_start, uint32_t subframe_start); +int check_resource_NPDCCH_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t hyperSF_start, uint32_t frame_start, uint32_t subframe_start, sched_temp_DL_NB_IoT_t *NPDCCH_info, uint32_t cdd_num, uint32_t dci_rep); +int check_resource_NPDSCH_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, sched_temp_DL_NB_IoT_t *NPDSCH_info, uint32_t sf_end, uint32_t I_delay, uint32_t R_max, uint32_t R_dl, uint32_t n_sf); +int check_resource_DL_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t hyperSF_start, uint32_t frame_start, uint32_t subframe_start, uint32_t dlsf_require, sched_temp_DL_NB_IoT_t *schedule_info); +uint32_t get_I_mcs(int CE_level); +uint32_t get_max_tbs(uint32_t I_tbs); +uint32_t get_tbs(uint32_t data_size, uint32_t I_tbs, uint32_t *I_sf); +uint32_t get_num_sf(uint32_t I_sf); +uint32_t get_scheduling_delay(uint32_t I_delay, uint32_t R_max); +uint32_t get_HARQ_delay(int subcarrier_spacing, uint32_t HARQ_delay_index); +//void generate_scheduling_result_DL(uint32_t DCI_subframe, uint32_t NPDSCH_subframe, uint32_t HARQ_subframe, DCIFormatN1_t *DCI, rnti_t rnti, uint32_t TBS, uint8_t *DLSCH_pdu); +void generate_scheduling_result_DL(sched_temp_DL_NB_IoT_t* DCI_info, sched_temp_DL_NB_IoT_t* NPDSCH_info, sched_temp_UL_NB_IoT_t* HARQ_info, DCIFormatN1_t *DCI_inst, rnti_t rnti, uint32_t TBS, uint8_t *DLSCH_pdu); +void fill_DCI_N1(DCIFormatN1_t *DCI_N1, UE_TEMPLATE_NB_IoT *UE_info, uint32_t scheddly, uint32_t I_sf, uint32_t I_harq); +//Transfrom source into hyperSF, Frame, Subframe format +void convert_system_number(uint32_t source_sf,uint32_t *hyperSF, uint32_t *frame, uint32_t *subframe); +//Trnasform hyperSF, Frame, Subframe format into subframe unit +uint32_t convert_system_number_sf(uint32_t hyperSF, uint32_t frame, uint32_t subframe); +/*input start position amd num_dlsf DL subframe, caculate the last subframe number*/ +uint32_t cal_num_dlsf(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t hyperSF, uint32_t frame, uint32_t subframe, uint32_t* hyperSF_result, uint32_t* frame_result, uint32_t* subframe_result, uint32_t num_dlsf_require); +void init_dlsf_info(eNB_MAC_INST_NB_IoT *mac_inst, DLSF_INFO_t *DLSF_info); +uint32_t generate_dlsch_header_NB_IoT(uint8_t *pdu, uint32_t num_sdu, logical_chan_id_t *logical_channel, uint32_t *sdu_length, uint8_t flag_drx, uint8_t flag_ta, uint32_t TBS); +void maintain_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, sched_temp_DL_NB_IoT_t *NPDCCH_info, sched_temp_DL_NB_IoT_t *NPDSCH_info); +void init_tool_sib1(eNB_MAC_INST_NB_IoT *mac_inst); +//int is_dlsf(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); +/**DL test , delete**/ +available_resource_DL_t* new_dl_node(uint32_t start_subframe, uint32_t end_subframe, uint32_t dlsf); +void initialize_dl_resource(available_resource_DL_t *DL_Resource_node, uint32_t start_subframe, uint32_t end_subframe, uint32_t dlsf); +void insert_dl_resource(available_resource_DL_t *DL_Resource_node); +void insert_schedule_result(schedule_result_t **list, int subframe, schedule_result_t *node); +//interface with IF + +uint8_t *parse_ulsch_header_NB_IoT( uint8_t *mac_header, uint8_t *num_ce, uint8_t *num_sdu, uint8_t *rx_ces, uint8_t *rx_lcids, uint16_t *rx_lengths, uint16_t tb_length); + +void rx_sdu_NB_IoT(module_id_t module_id, int CC_id, frame_t frame, sub_frame_t subframe, uint16_t rnti, uint8_t *sdu, uint16_t length); + +int output_handler(eNB_MAC_INST_NB_IoT *mac_inst, module_id_t module_id, int CC_id, uint32_t hypersfn, uint32_t frame, uint32_t subframe, uint8_t MIB_flag, uint8_t SIB1_flag, uint32_t current_time); +// main + +void mac_top_init_eNB_NB_IoT(void); + +uint32_t to_earfcn_NB_IoT(int eutra_bandP,uint32_t dl_CarrierFreq, float m_dl); + +uint32_t from_earfcn_NB_IoT(int eutra_bandP,uint32_t dl_earfcn, float m_dl); + +int32_t get_uldl_offset_NB_IoT(int eutra_band); +#endif diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index 05855a14bd..2de1b3fc74 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -769,18 +769,15 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const ctxt_pP) void pdcp_fifo_read_input_sdus_from_otg (const protocol_ctxt_t* const ctxt_pP) { - //unsigned char *otg_pkt=NULL; + module_id_t dst_id; // dst for otg - //rb_id_t rb_id; - //unsigned int pkt_size=0; protocol_ctxt_t ctxt; // we need to add conditions to avoid transmitting data when the UE is not RRC connected. if ((otg_enabled==1) && (ctxt_pP->enb_flag == ENB_FLAG_YES)) { // generate DL traffic - //unsigned int ctime=0; - //ctime = ctxt_pP->frame * 100; - /*if ((mac_get_rrc_status(eNB_index, ctxt_pP->enb_flag, 0 ) > 2) && - (mac_get_rrc_status(eNB_index, ctxt_pP->enb_flag, 1 ) > 2)) { */ + + + PROTOCOL_CTXT_SET_BY_MODULE_ID( &ctxt, ctxt_pP->module_id, @@ -792,36 +789,7 @@ void pdcp_fifo_read_input_sdus_from_otg (const protocol_ctxt_t* const ctxt_pP) for (dst_id = 0; dst_id 2 ) { - unsigned int temp = 0; - otg_pkt=packet_gen( - ENB_MODULE_ID_TO_INSTANCE(ctxt.module_id), - UE_MODULE_ID_TO_INSTANCE(dst_id), - 0, - ctime, - &temp); - pkt_size = temp; - if (otg_pkt != NULL) { - rb_id = dst_id * maxDRB + DTCH; - pdcp_data_req(&ctxt, - SRB_FLAG_NO, - rb_id, - RLC_MUI_UNDEFINED, - RLC_SDU_CONFIRM_NO, - pkt_size, - otg_pkt, - PDCP_TRANSMISSION_MODE_DATA); - LOG_I(OTG, - "send packet from module %d on rab id %d (src %d, dst %d) pkt size %d\n", - ctxt_pP->module_id, rb_id, ctxt_pP->module_id, dst_id, pkt_size); - free(otg_pkt); - } - } - } -*/ } } } diff --git a/openair2/PHY_INTERFACE/IF_Module_NB_IoT.h b/openair2/PHY_INTERFACE/IF_Module_NB_IoT.h new file mode 100644 index 0000000000..479bd47d94 --- /dev/null +++ b/openair2/PHY_INTERFACE/IF_Module_NB_IoT.h @@ -0,0 +1,215 @@ + +/*This is the interface module between PHY +*Provided the FAPI style interface structures for P7. +*Provide the semi-FAPI style interface for P5 (configuration) +* +*/ + +#ifndef __IF_MODULE_NB_IoT__H__ +#define __IF_MODULE_NB_IoT__H__ + +#include "nfapi_interface.h" +//#include "openair1/PHY/LTE_TRANSPORT/defs_NB_IoT.h" +#include "PhysicalConfigDedicated-NB-r13.h" +//#include "openair2/PHY_INTERFACE/IF_Module_NB_IoT.h" +#include "openair2/COMMON/platform_types.h" +//#include "openair1/SCHED/IF_Module_L1_primitives_NB_IoT.h" + +//#define SCH_PAYLOAD_SIZE_MAX 4096 +#define BCCH_PAYLOAD_SIZE_MAX_NB_IoT 128 + + + +// P5 FAPI-like configuration structures------------------------------------------------------------------------------- + +/*MP: MISSED COMMON CONFIG. of SIB2-NB in FAPI SPECS + * some of them may not needed because are used only at UE side + * some of them are not needed because not necessary at PHY level + * other have to be clarified since seems to be needed at PHY layer + * there is no UE_Config. request message carrying NB-IoT parameters??? + * + * */ +typedef struct{ + //nprach_config + uint16_t nprach_config_0_subcarrier_MSG3_range_start; + uint16_t nprach_config_1_subcarrier_MSG3_range_start; + uint16_t nprach_config_2_subcarrier_MSG3_range_start; + uint16_t nprach_config_0_max_num_preamble_attempt_CE; + uint16_t nprach_config_1_max_num_preamble_attempt_CE; + uint16_t nprach_config_2_max_num_preamble_attempt_CE; + uint16_t nprach_config_0_npdcch_num_repetitions_RA; //Rmax (see TS 36.213 ch 16.6) -->only this is managed at PHY layer + uint16_t nprach_config_1_npdcch_num_repetitions_RA; + uint16_t nprach_config_2_npdcch_num_repetitions_RA; + uint16_t nprach_config_0_npdcch_startSF_CSS_RA; //G (see TS 36.213 ch 16.6) + uint16_t nprach_config_1_npdcch_startSF_CSS_RA; + uint16_t nprach_config_2_npdcch_startSF_CSS_RA; + uint16_t nprach_config_0_npdcch_offset_RA; //Alfa_offset (see TS 36.213 ch 16.6) + uint16_t nprach_config_1_npdcch_offset_RA; + uint16_t nprach_config_2_npdcch_offset_RA; + + //configured through the phy_config_dedicated + //Higher layer parameter for NPDCCH UE-spec search space + uint16_t npdcch_NumRepetitions;//Rmax (see TS 36.213 ch 16.6) -->only this is managed at PHY layer + uint16_t npdcch_StartSF_USS; //G (see TS 36.213 ch 16.6) + uint16_t npdcch_Offset_USS; //Alfa_offset (see TS 36.213 ch 16.6) + + + ACK_NACK_NumRepetitions_NB_r13_t *ack_nack_numRepetitions_MSG4; //pointer to the first cell of a list of ack_nack_num_repetitions + + //ulPowerControlCommon (UE side) + uint16_t p0_nominal_npusch; + uint16_t alpha; + uint16_t delta_preamle_MSG3; + + + /*Dedicated configuration -->not supported by FAPI (may not needed) + * In OAI at least are needed when we manage the phy_procedures_eNB_TX in which we call the phy_config_dedicated_eNB_step2 + * that use the physicalConfigDedicated info previously stored in the PHY_VARS_eNB_NB_IoT structure through the phy_config_dedicated procedure + */ + //PhysicalConfigDedicated_NB_r13_t *phy_config_dedicated; + + + + +}extra_phyConfig_t; + +typedef struct{ + + /*OAI config. parameters*/ + module_id_t mod_id; + int CC_id; + uint16_t rnti; + int get_MIB; //should be different from 0 only when the mib!= null (NB_rrc_mac_config_req_eNB_IoT) + int get_COMMON; + int get_DEDICATED; + + //ID of the Resource Block dedicated to NB-IoT + //For Nb-IoT only a restricted values of PRB indexes are allowed (see Rhode&Shwartz pag9) + //unsigned short NB_IoT_RB_ID; (should coincide with PRB index) + + + + + /*FAPI useful config. parameters used in the code + * + * -nfapi_uplink_reference_signal_config_t uplink_reference_signal_config + * -nfapi_subframe_config_t subframe_config; + * -nfapi_rf_config_t rf_config; + * -nfapi_sch_config_t sch_config; + * -nfapi_nb_iot_config_t config_NB_IoT; + * -nfapi_l23_config_t l23_config; + * -nfapi_config --> EARFCN (for the transport of the dl_CarrierFreq + * */ + + //XXX where allocate memory?? + nfapi_config_request_t* cfg; + + /*MP: MISSED COMMON CONFIG. of SIB2-NB in FAPI SPECS (may non needed)*/ + extra_phyConfig_t extra_phy_parms; + +}PHY_Config_NB_IoT_t; + + + +// uplink subframe P7--------------------------------------------------------------------------------- + + +/*UL_IND_t: +* A structure handles all the uplink information. +* Corresponding to the NRACH.indicaiton, UL_Config_indication, RX_ULSCH.indication, CRC.inidcation, NB_HARQ.indication in FAPI +*/ +typedef struct{ + + /*Start at the common part*/ + + int test; + + //Module ID + module_id_t module_id; + //CC ID + int CC_id; + //frame + frame_t frame; + //subframe + sub_frame_t subframe; + //Hyper frame for NB-IoT implementation + uint32_t hypersfn; + + /*preamble part*/ + + nfapi_nrach_indication_body_t NRACH; + + /*Uplink data part*/ + + /*indication of the harq feedback*/ + nfapi_nb_harq_indication_t nb_harq_ind; + /*indication of the uplink data PDU*/ + nfapi_rx_indication_body_t RX_NPUSCH; + /*crc_indication*/ + nfapi_crc_indication_body_t crc_ind; + + }UL_IND_NB_IoT_t; + + // Downlink subframe P7 + + +typedef struct{ + + /*Start at the common part*/ + + //Module ID + module_id_t module_id; + //CC ID + int CC_id; + // hyper subframe + uint32_t hypersfn; + //frame + frame_t frame; + //subframe + sub_frame_t subframe; + + /// nFAPI DL Config Request + nfapi_dl_config_request_t *DL_req; + /// nFAPI UL Config Request + nfapi_ul_config_request_t *UL_req; + /// nFAPI HI_DCI Request + nfapi_hi_dci0_request_t *HI_DCI0_req; + /// nFAPI TX Request + nfapi_tx_request_t *TX_req; + /// Pointers to DL SDUs + //uint8_t **sdu; + +}Sched_Rsp_NB_IoT_t; + + +/*IF_Module_t a group for gathering the Interface +It should be allocated at the main () in lte-softmodem.c*/ +typedef struct IF_Module_NB_IoT_s{ + //define the function pointer + void (*UL_indication)(UL_IND_NB_IoT_t *UL_INFO); + void (*schedule_response)(Sched_Rsp_NB_IoT_t *Sched_INFO); + void (*PHY_config_req)(PHY_Config_NB_IoT_t* config_INFO); +}IF_Module_NB_IoT_t; + +/*Initial */ + +/*Interface for Downlink, transmitting the DLSCH SDU, DCI SDU*/ +void schedule_response_NB_IoT(Sched_Rsp_NB_IoT_t *Sched_INFO); + +/*Interface for PHY Configuration + * Trigger the phy_config_xxx functions using parameters from the shared PHY_Config structure + * */ +void PHY_config_req_NB_IoT(PHY_Config_NB_IoT_t* config_INFO); + +//int IF_Module_init(IF_Module_t *if_inst); + +/*Interface for Downlink, transmitting the DLSCH SDU, DCI SDU*/ +//void Schedule_Response_NB_IoT(Sched_Rsp_NB_IoT_t *Sched_INFO); + +/*Interface for uplink, transmitting the Preamble(list), ULSCH SDU, NAK, Tick (trigger scheduler) +*/ +void UL_indication_NB_IoT(UL_IND_NB_IoT_t *UL_INFO); + +IF_Module_NB_IoT_t *IF_Module_init_NB_IoT(int Mod_id); + +#endif diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c b/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c new file mode 100644 index 0000000000..866b2c1e91 --- /dev/null +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c @@ -0,0 +1,1417 @@ +/* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file asn1_msg.c +* \brief primitives to build the asn1 messages +* \author Raymond Knopp, Navid Nikaein and Michele Paffetti +* \date 2011, 2017 +* \version 1.0 +* \company Eurecom +* \email: raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, michele.paffetti@studio.unibo.it +*/ + +#include +#include +#include /* for atoi(3) */ +#include /* for getopt(3) */ +#include /* for strerror(3) */ +#include /* for EX_* exit codes */ +#include /* for errno */ +#include "UTIL/LOG/log.h" +#include +#include /* for _ASN_DEFAULT_STACK_MAX */ +#include +#include "asn1_msg.h" + + + +//#include for NB-IoT------------------- +#include "RRCConnectionRequest-NB.h" +#include "BCCH-DL-SCH-Message-NB.h" +#include "UL-CCCH-Message-NB.h" +#include "UL-DCCH-Message-NB.h" +#include "DL-CCCH-Message-NB.h" +#include "DL-DCCH-Message-NB.h" +#include "EstablishmentCause-NB-r13.h" +#include "RRCConnectionSetup-NB.h" +#include "SRB-ToAddModList-NB-r13.h" +#include "DRB-ToAddModList-NB-r13.h" +#include "RRC/LITE/defs_NB_IoT.h" +#include "RRCConnectionSetupComplete-NB.h" +#include "RRCConnectionReconfigurationComplete-NB.h" +#include "RRCConnectionReconfiguration-NB.h" +#include "MasterInformationBlock-NB.h" +#include "SystemInformation-NB.h" +#include "SystemInformationBlockType1.h" +#include "SIB-Type-NB-r13.h" +#include "RRCConnectionResume-NB.h" +#include "RRCConnectionReestablishment-NB.h" +#include "../defs_NB_IoT.h" +//---------------------------------------- + +//#include "PHY/defs.h" +#include "enb_config.h" + +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +#endif + + + + +/*do_MIB_NB_NB_IoT*/ +uint8_t do_MIB_NB_IoT( + rrc_eNB_carrier_data_NB_IoT_t *carrier, + uint16_t N_RB_DL,//may not needed--> for NB_IoT only 1 PRB is used + uint32_t frame, + uint32_t hyper_frame) +{ + asn_enc_rval_t enc_rval; + BCCH_BCH_Message_NB_t *mib_NB_IoT = &(carrier->mib_NB_IoT); + + /* + * systemFrameNumber-MSB: (TS 36.331 pag 576) + * define the 4 MSB of the SFN (10 bits). The last significant 6 bits will be acquired implicitly by decoding the NPBCH + * NOTE: 6 LSB will be used for counting the 64 radio frames in the TTI period (640 ms) that is exactly the MIB period + * + * hyperSFN-LSB: + * indicates the 2 least significant bits of the HSFN. The remaining 8 bits are present in SIB1-NB + * NOTE: with the 2 bits we count the 4 HSFN (is 1 SIB1-Nb modification period) while the other 6 count the number of modification periods + * + * + * NOTE: in OAI never modify the SIB messages!!?? + */ + + //XXX check if correct the bit assignment + uint8_t sfn_MSB = (uint8_t)((frame>>6) & 0x0f); // all the 4 bits are set to 1 + uint8_t hsfn_LSB = (uint8_t)(hyper_frame & 0x03); //2 bits set to 1 (0x3 = 0011) + uint16_t spare=0; //11 bits --> use uint16 + + mib_NB_IoT->message.systemFrameNumber_MSB_r13.buf = &sfn_MSB; + mib_NB_IoT->message.systemFrameNumber_MSB_r13.size = 1; //if expressed in byte + mib_NB_IoT->message.systemFrameNumber_MSB_r13.bits_unused = 4; //is byte based (so how many bits you don't use of the 8 bits of a bite + + mib_NB_IoT->message.hyperSFN_LSB_r13.buf= &hsfn_LSB; + mib_NB_IoT->message.hyperSFN_LSB_r13.size= 1; + mib_NB_IoT->message.hyperSFN_LSB_r13.bits_unused = 6; + + //XXX to be set?? + mib_NB_IoT->message.spare.buf = (uint8_t *)&spare; + mib_NB_IoT->message.spare.size = 2; + mib_NB_IoT->message.spare.bits_unused = 5; + + //decide how to set it + mib_NB_IoT->message.schedulingInfoSIB1_r13 =11; //see TS 36.213-->tables 16.4.1.3-3 ecc... + mib_NB_IoT->message.systemInfoValueTag_r13= 0; + mib_NB_IoT->message.ab_Enabled_r13 = 0; + + //to be decided + mib_NB_IoT->message.operationModeInfo_r13.present = MasterInformationBlock_NB__operationModeInfo_r13_PR_inband_SamePCI_r13; + mib_NB_IoT->message.operationModeInfo_r13.choice.inband_SamePCI_r13.eutra_CRS_SequenceInfo_r13 = 0; + + printf("[MIB] Initialization of frame information,sfn_MSB %x, hsfn_LSB %x\n", + (uint32_t)sfn_MSB, + (uint32_t)hsfn_LSB); + + enc_rval = uper_encode_to_buffer(&asn_DEF_BCCH_BCH_Message_NB, + (void*)mib_NB_IoT, + carrier->MIB_NB_IoT, + 100); + if(enc_rval.encoded <= 0) { + LOG_F(RRC, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + + if (enc_rval.encoded==-1) { + return(-1); + } + + return((enc_rval.encoded+7)/8); + +} + +/*do_SIB1_NB*/ +uint8_t do_SIB1_NB_IoT(uint8_t Mod_id, int CC_id, + rrc_eNB_carrier_data_NB_IoT_t *carrier, + NbIoTRrcConfigurationReq *configuration, + uint32_t frame + ) +{ + BCCH_DL_SCH_Message_NB_t *bcch_message= &(carrier->siblock1_NB_IoT); + SystemInformationBlockType1_NB_t **sib1_NB_IoT= &(carrier->sib1_NB_IoT); + + + asn_enc_rval_t enc_rval; + + PLMN_IdentityInfo_NB_r13_t PLMN_identity_info_NB_IoT; + MCC_MNC_Digit_t dummy_mcc[3],dummy_mnc[3]; + SchedulingInfo_NB_r13_t *schedulingInfo_NB_IoT; + SIB_Type_NB_r13_t *sib_type_NB_IoT; + + + long* attachWithoutPDN_Connectivity = NULL; + attachWithoutPDN_Connectivity = CALLOC(1,sizeof(long)); + long *nrs_CRS_PowerOffset=NULL; + nrs_CRS_PowerOffset = CALLOC(1, sizeof(long)); + long *eutraControlRegionSize=NULL; //this parameter should be set only if we are considering in-band operating mode (samePCI or differentPCI) + eutraControlRegionSize = CALLOC(1,sizeof(long)); + long systemInfoValueTagSI = 0; + + memset(bcch_message,0,sizeof(BCCH_DL_SCH_Message_NB_t)); + bcch_message->message.present = BCCH_DL_SCH_MessageType_NB_PR_c1; + bcch_message->message.choice.c1.present = BCCH_DL_SCH_MessageType_NB__c1_PR_systemInformationBlockType1_r13; + + //allocation + *sib1_NB_IoT = &bcch_message->message.choice.c1.choice.systemInformationBlockType1_r13; + + + /*TS 36.331 v14.2.0 pag 589 + * hyperSFN-MSB + * Indicates the 8 most significant bits of the hyper-SFN. Together with the hyper-LSB in MIB-NB the complete HSFN is build up + */ + //FIXME see if correct + uint8_t hyperSFN_MSB = (uint8_t) ((frame>>2)& 0xff); + + //XXX to be checked + (*sib1_NB_IoT)->hyperSFN_MSB_r13.buf = &hyperSFN_MSB; + (*sib1_NB_IoT)->hyperSFN_MSB_r13.size = 1; + (*sib1_NB_IoT)->hyperSFN_MSB_r13.bits_unused = 0; + + memset(&PLMN_identity_info_NB_IoT,0,sizeof(PLMN_IdentityInfo_NB_r13_t)); + + PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc = CALLOC(1,sizeof(*PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc)); + memset(PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc,0,sizeof(*PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc)); + + asn_set_empty(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list);//.size=0; + + //left as it is??? +#if defined(ENABLE_ITTI) + dummy_mcc[0] = (configuration->mcc / 100) % 10; + dummy_mcc[1] = (configuration->mcc / 10) % 10; + dummy_mcc[2] = (configuration->mcc / 1) % 10; +#else + dummy_mcc[0] = 0; + dummy_mcc[1] = 0; + dummy_mcc[2] = 1; +#endif + ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list,&dummy_mcc[0]); + ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list,&dummy_mcc[1]); + ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list,&dummy_mcc[2]); + + PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list.size=0; + PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list.count=0; + + +#if defined(ENABLE_ITTI) + + if (configuration->mnc >= 100) { + dummy_mnc[0] = (configuration->mnc / 100) % 10; + dummy_mnc[1] = (configuration->mnc / 10) % 10; + dummy_mnc[2] = (configuration->mnc / 1) % 10; + } else { + if (configuration->mnc_digit_length == 2) { + dummy_mnc[0] = (configuration->mnc / 10) % 10; + dummy_mnc[1] = (configuration->mnc / 1) % 10; + dummy_mnc[2] = 0xf; + } else { + dummy_mnc[0] = (configuration->mnc / 100) % 100; + dummy_mnc[1] = (configuration->mnc / 10) % 10; + dummy_mnc[2] = (configuration->mnc / 1) % 10; + } + } + +#else + dummy_mnc[0] = 0; + dummy_mnc[1] = 1; + dummy_mnc[2] = 0xf; +#endif + ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list,&dummy_mnc[0]); + ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list,&dummy_mnc[1]); + + if (dummy_mnc[2] != 0xf) { + ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list,&dummy_mnc[2]); + } + + //still set to "notReserved" as in the previous case + PLMN_identity_info_NB_IoT.cellReservedForOperatorUse_r13=PLMN_IdentityInfo_NB_r13__cellReservedForOperatorUse_r13_notReserved; + + *attachWithoutPDN_Connectivity = 0; + PLMN_identity_info_NB_IoT.attachWithoutPDN_Connectivity_r13 = attachWithoutPDN_Connectivity; + + ASN_SEQUENCE_ADD(&(*sib1_NB_IoT)->cellAccessRelatedInfo_r13.plmn_IdentityList_r13.list,&PLMN_identity_info_NB_IoT); + + // 16 bits = 2 byte + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf = MALLOC(2); //MALLOC works in byte + + //lefts as it is? +#if defined(ENABLE_ITTI) + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[0] = (configuration->tac >> 8) & 0xff; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[1] = (configuration->tac >> 0) & 0xff; +#else + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[0] = 0x00; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[1] = 0x01; +#endif + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.size=2; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.bits_unused=0; + + // 28 bits --> i have to use 32 bits = 4 byte + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf = MALLOC(8); // why allocate 8 byte? +#if defined(ENABLE_ITTI) + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[0] = (configuration->cell_identity >> 20) & 0xff; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[1] = (configuration->cell_identity >> 12) & 0xff; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[2] = (configuration->cell_identity >> 4) & 0xff; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[3] = (configuration->cell_identity << 4) & 0xf0; +#else + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[0] = 0x00; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[1] = 0x00; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[2] = 0x00; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[3] = 0x10; +#endif + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.size=4; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.bits_unused=4; + + //Still set to "notBarred" as in the previous case + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellBarred_r13=SystemInformationBlockType1_NB__cellAccessRelatedInfo_r13__cellBarred_r13_notBarred; + + //Still Set to "notAllowed" like in the previous case + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.intraFreqReselection_r13=SystemInformationBlockType1_NB__cellAccessRelatedInfo_r13__intraFreqReselection_r13_notAllowed; + + + (*sib1_NB_IoT)->cellSelectionInfo_r13.q_RxLevMin_r13=-65; //which value?? TS 36.331 V14.2.1 pag. 589 + (*sib1_NB_IoT)->cellSelectionInfo_r13.q_QualMin_r13 = 0; //FIXME new parameter for SIB1-NB, not present in SIB1 (for cell reselection but if not used the UE should apply the default value) + + (*sib1_NB_IoT)->p_Max_r13 = CALLOC(1, sizeof(P_Max_t)); + *((*sib1_NB_IoT)->p_Max_r13) = 23; + + //FIXME + (*sib1_NB_IoT)->freqBandIndicator_r13 = +#if defined(ENABLE_ITTI) + configuration->eutra_band; +#else + 5; //if not configured we use band 5 (UL: 824 MHz - 849MHz / DL: 869 MHz - 894 MHz FDD mode) +#endif + + //OPTIONAL new parameters, to be used? + /* + * freqBandInfo_r13 + * multiBandInfoList_r13 + * nrs_CRS_PowerOffset_r13 + * sib1_NB_IoT->downlinkBitmap_r13.choice.subframePattern10_r13 =(is a BIT_STRING) + */ + + + (*sib1_NB_IoT)->downlinkBitmap_r13 = CALLOC(1, sizeof(struct DL_Bitmap_NB_r13)); + ((*sib1_NB_IoT)->downlinkBitmap_r13)->present= DL_Bitmap_NB_r13_PR_NOTHING; + + *eutraControlRegionSize = 1; + (*sib1_NB_IoT)->eutraControlRegionSize_r13 = eutraControlRegionSize; + + + *nrs_CRS_PowerOffset= 0; + (*sib1_NB_IoT)->nrs_CRS_PowerOffset_r13 = nrs_CRS_PowerOffset; + + schedulingInfo_NB_IoT = (SchedulingInfo_NB_r13_t*) malloc (3*sizeof(SchedulingInfo_NB_r13_t)); + sib_type_NB_IoT = (SIB_Type_NB_r13_t *) malloc (3*sizeof(SIB_Type_NB_r13_t)); + + memset(&schedulingInfo_NB_IoT[0],0,sizeof(SchedulingInfo_NB_r13_t)); + memset(&schedulingInfo_NB_IoT[1],0,sizeof(SchedulingInfo_NB_r13_t)); + memset(&schedulingInfo_NB_IoT[2],0,sizeof(SchedulingInfo_NB_r13_t)); + memset(&sib_type_NB_IoT[0],0,sizeof(SIB_Type_NB_r13_t)); + memset(&sib_type_NB_IoT[1],0,sizeof(SIB_Type_NB_r13_t)); + memset(&sib_type_NB_IoT[2],0,sizeof(SIB_Type_NB_r13_t)); + + + // Now, follow the scheduler SIB configuration + // There is only one sib2+sib3 common setting + schedulingInfo_NB_IoT[0].si_Periodicity_r13=SchedulingInfo_NB_r13__si_Periodicity_r13_rf4096; + schedulingInfo_NB_IoT[0].si_RepetitionPattern_r13=SchedulingInfo_NB_r13__si_RepetitionPattern_r13_every2ndRF; //This Indicates the starting radio frames within the SI window used for SI message transmission. + schedulingInfo_NB_IoT[0].si_TB_r13= SchedulingInfo_NB_r13__si_TB_r13_b680;//208 bits + + + // This is for SIB2/3 + /*SIB3 --> There is no mapping information of SIB2 since it is always present + * in the first SystemInformation message + * listed in the schedulingInfoList list. + * */ + sib_type_NB_IoT[0]=SIB_Type_NB_r13_sibType3_NB_r13; + + ASN_SEQUENCE_ADD(&schedulingInfo_NB_IoT[0].sib_MappingInfo_r13.list,&sib_type_NB_IoT[0]); + ASN_SEQUENCE_ADD(&(*sib1_NB_IoT)->schedulingInfoList_r13.list,&schedulingInfo_NB_IoT[0]); + + //printf("[ASN Debug] SI P: %ld\n",(*sib1_NB_IoT)->schedulingInfoList_r13.list.array[0]->si_Periodicity_r13); + +#if defined(ENABLE_ITTI) + + if (configuration->frame_type == TDD) +#endif + { + //FIXME in NB-IoT mandatory to be FDD --> so must give an error + LOG_E(RRC,"[NB-IoT %d] Frame Type is TDD --> not supported by NB-IoT, exiting\n", Mod_id); //correct? + exit(-1); + } + + //FIXME which value chose for the following parameter + (*sib1_NB_IoT)->si_WindowLength_r13=SystemInformationBlockType1_NB__si_WindowLength_r13_ms160; + (*sib1_NB_IoT)->si_RadioFrameOffset_r13= 0; + + /*In Nb-IoT change/update of specific SI message can additionally be indicated by a SI message specific value tag + * systemInfoValueTagSI (there is no SystemInfoValueTag in SIB1-NB but only in MIB-NB) + *contained in systemInfoValueTagList_r13 + **/ + //FIXME correct? + (*sib1_NB_IoT)->systemInfoValueTagList_r13 = CALLOC(1, sizeof(struct SystemInfoValueTagList_NB_r13)); + asn_set_empty(&(*sib1_NB_IoT)->systemInfoValueTagList_r13->list); + ASN_SEQUENCE_ADD(&(*sib1_NB_IoT)->systemInfoValueTagList_r13->list,&systemInfoValueTagSI); + + +#ifdef XER_PRINT //generate xml files + xer_fprint(stdout, &asn_DEF_BCCH_DL_SCH_Message_NB, (void*)bcch_message); +#endif + + + enc_rval = uper_encode_to_buffer(&asn_DEF_BCCH_DL_SCH_Message_NB, + (void*)bcch_message, + carrier->SIB1_NB_IoT, + 100); + + if (enc_rval.encoded > 0){ + LOG_F(RRC,"ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + + +#ifdef USER_MODE + LOG_D(RRC,"[NB-IoT] SystemInformationBlockType1-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); +#endif + + if (enc_rval.encoded==-1) { + return(-1); + } + + return((enc_rval.encoded+7)/8); +} + +/*SIB23_NB_IoT*/ +//to be clarified is it is possible to carry SIB2 and SIB3 in the same SI message for NB-IoT? +uint8_t do_SIB23_NB_IoT(uint8_t Mod_id, + int CC_id, + rrc_eNB_carrier_data_NB_IoT_t *carrier,//MP: this is already a carrier[CC_id] + NbIoTRrcConfigurationReq *configuration ) //openair2/COMMON/rrc_messages_types.h +{ + struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member *sib2_NB_part; + struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member *sib3_NB_part; + + BCCH_DL_SCH_Message_NB_t *bcch_message = &(carrier->systemInformation_NB_IoT); //is the systeminformation-->BCCH_DL_SCH_Message_NB + SystemInformationBlockType2_NB_r13_t *sib2_NB_IoT; + SystemInformationBlockType3_NB_r13_t *sib3_NB_IoT; + + asn_enc_rval_t enc_rval; + RACH_Info_NB_r13_t rach_Info_NB_IoT; + NPRACH_Parameters_NB_r13_t *nprach_parameters; + + //optional + long *connEstFailOffset = NULL; + connEstFailOffset = CALLOC(1, sizeof(long)); + +// RSRP_ThresholdsNPRACH_InfoList_NB_r13_t *rsrp_ThresholdsPrachInfoList; +// RSRP_Range_t rsrp_range; + + ACK_NACK_NumRepetitions_NB_r13_t ack_nack_repetition; + struct NPUSCH_ConfigCommon_NB_r13__dmrs_Config_r13 *dmrs_config; + struct DL_GapConfig_NB_r13 *dl_Gap; + + long *srs_SubframeConfig; + srs_SubframeConfig= CALLOC(1, sizeof(long)); + + + if (bcch_message) { + memset(bcch_message,0,sizeof(BCCH_DL_SCH_Message_NB_t)); + } else { + LOG_E(RRC,"[NB-IoT %d] BCCH_MESSAGE_NB is null, exiting\n", Mod_id); + exit(-1); + } + + //before schould be allocated memory somewhere? +// if (!carrier->sib2_NB_IoT) { +// LOG_E(RRC,"[NB-IoT %d] sib2_NB_IoT is null, exiting\n", Mod_id); +// exit(-1); +// } +// +// if (!carrier->sib3_NB_IoT) { +// LOG_E(RRC,"[NB-IoT %d] sib3_NB_IoT is null, exiting\n", Mod_id); +// exit(-1); +// } + + + LOG_I(RRC,"[NB-IoT %d] Configuration SIB2/3\n", Mod_id); + + sib2_NB_part = CALLOC(1,sizeof(struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member)); + sib3_NB_part = CALLOC(1,sizeof(struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member)); + memset(sib2_NB_part,0,sizeof(struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member)); + memset(sib3_NB_part,0,sizeof(struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member)); + + sib2_NB_part->present = SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member_PR_sib2_r13; + sib3_NB_part->present = SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member_PR_sib3_r13; + + //may bug if not correct allocation of memory + carrier->sib2_NB_IoT = &sib2_NB_part->choice.sib2_r13; + carrier->sib3_NB_IoT = &sib3_NB_part->choice.sib3_r13; + sib2_NB_IoT = carrier->sib2_NB_IoT; + sib3_NB_IoT = carrier->sib3_NB_IoT; + + nprach_parameters = (NPRACH_Parameters_NB_r13_t *) malloc (3*sizeof(NPRACH_Parameters_NB_r13_t)); + + memset(&nprach_parameters[0],0,sizeof(NPRACH_Parameters_NB_r13_t)); + memset(&nprach_parameters[1],0,sizeof(NPRACH_Parameters_NB_r13_t)); + memset(&nprach_parameters[2],0,sizeof(NPRACH_Parameters_NB_r13_t)); + +/// SIB2-NB----------------------------------------- + + //Barring is manage by ab-Enabled in MIB-NB (but is not a struct as ac-BarringInfo in LTE legacy) + + //RACH Config. Common-------------------------------------------------------------- + sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.preambleTransMax_CE_r13 = + configuration->rach_preambleTransMax_CE_NB; + sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.powerRampingParameters_r13.powerRampingStep = + configuration->rach_powerRampingStep_NB; + sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.powerRampingParameters_r13.preambleInitialReceivedTargetPower = + configuration->rach_preambleInitialReceivedTargetPower_NB; + + rach_Info_NB_IoT.ra_ResponseWindowSize_r13 = configuration->rach_raResponseWindowSize_NB; + rach_Info_NB_IoT.mac_ContentionResolutionTimer_r13 = configuration-> rach_macContentionResolutionTimer_NB; + //rach_infoList max size = maxNPRACH-Resources-NB-r13 = 3 + ASN_SEQUENCE_ADD(&sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.rach_InfoList_r13.list,&rach_Info_NB_IoT); + + //TS 36.331 pag 614 --> if not present the value to infinity sould be used + *connEstFailOffset = 0; + + sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.connEstFailOffset_r13 = connEstFailOffset; /*OPTIONAL*/ + + + // BCCH-Config-NB-IoT---------------------------------------------------------------- + sib2_NB_IoT->radioResourceConfigCommon_r13.bcch_Config_r13.modificationPeriodCoeff_r13 + = configuration->bcch_modificationPeriodCoeff_NB; + + // PCCH-Config-NB-IoT----------------------------------------------------------------- + sib2_NB_IoT->radioResourceConfigCommon_r13.pcch_Config_r13.defaultPagingCycle_r13 + = configuration->pcch_defaultPagingCycle_NB; + sib2_NB_IoT->radioResourceConfigCommon_r13.pcch_Config_r13.nB_r13 = configuration->pcch_nB_NB; + sib2_NB_IoT->radioResourceConfigCommon_r13.pcch_Config_r13.npdcch_NumRepetitionPaging_r13 = configuration-> pcch_npdcch_NumRepetitionPaging_NB; + + //NPRACH-Config-NB-IoT----------------------------------------------------------------- + + sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.rsrp_ThresholdsPrachInfoList_r13 = NULL; + sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.nprach_CP_Length_r13 = configuration->nprach_CP_Length; + /*OPTIONAL*/ +// =CALLOC(1, sizeof(struct RSRP_ThresholdsNPRACH_InfoList_NB_r13)); //fatto uguale dopo +// rsrp_ThresholdsPrachInfoList = sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.rsrp_ThresholdsPrachInfoList_r13; +// rsrp_range = configuration->nprach_rsrp_range_NB; +// ASN_SEQUENCE_ADD(&rsrp_ThresholdsPrachInfoList->list,rsrp_range); + + // According configuration to set the 3 CE level configuration setting + + nprach_parameters[0].nprach_Periodicity_r13 = configuration->nprach_Periodicity[0]; + nprach_parameters[0].nprach_StartTime_r13 = configuration->nprach_StartTime[0]; + nprach_parameters[0].nprach_SubcarrierOffset_r13 = configuration->nprach_SubcarrierOffset[0]; + nprach_parameters[0].nprach_NumSubcarriers_r13 = configuration->nprach_NumSubcarriers[0]; + nprach_parameters[0].numRepetitionsPerPreambleAttempt_r13 = configuration->numRepetitionsPerPreambleAttempt_NB[0]; + nprach_parameters[0].nprach_SubcarrierMSG3_RangeStart_r13 = configuration->nprach_SubcarrierMSG3_RangeStart; + nprach_parameters[0].maxNumPreambleAttemptCE_r13 = configuration->maxNumPreambleAttemptCE_NB; + nprach_parameters[0].npdcch_NumRepetitions_RA_r13 = configuration->npdcch_NumRepetitions_RA[0]; + nprach_parameters[0].npdcch_StartSF_CSS_RA_r13 = configuration->npdcch_StartSF_CSS_RA[0]; + nprach_parameters[0].npdcch_Offset_RA_r13 = configuration->npdcch_Offset_RA[0]; + + nprach_parameters[1].nprach_Periodicity_r13 = configuration->nprach_Periodicity[1]; + nprach_parameters[1].nprach_StartTime_r13 = configuration->nprach_StartTime[1]; + nprach_parameters[1].nprach_SubcarrierOffset_r13 = configuration->nprach_SubcarrierOffset[1]; + nprach_parameters[1].nprach_NumSubcarriers_r13 = configuration->nprach_NumSubcarriers[1]; + nprach_parameters[1].numRepetitionsPerPreambleAttempt_r13 = configuration->numRepetitionsPerPreambleAttempt_NB[1]; + nprach_parameters[1].nprach_SubcarrierMSG3_RangeStart_r13 = configuration->nprach_SubcarrierMSG3_RangeStart; + nprach_parameters[1].maxNumPreambleAttemptCE_r13 = configuration->maxNumPreambleAttemptCE_NB; + nprach_parameters[1].npdcch_NumRepetitions_RA_r13 = configuration->npdcch_NumRepetitions_RA[1]; + nprach_parameters[1].npdcch_StartSF_CSS_RA_r13 = configuration->npdcch_StartSF_CSS_RA[1]; + nprach_parameters[1].npdcch_Offset_RA_r13 = configuration->npdcch_Offset_RA[1]; + + nprach_parameters[2].nprach_Periodicity_r13 = configuration->nprach_Periodicity[2]; + nprach_parameters[2].nprach_StartTime_r13 = configuration->nprach_StartTime[2]; + nprach_parameters[2].nprach_SubcarrierOffset_r13 = configuration->nprach_SubcarrierOffset[2]; + nprach_parameters[2].nprach_NumSubcarriers_r13 = configuration->nprach_NumSubcarriers[2]; + nprach_parameters[2].numRepetitionsPerPreambleAttempt_r13 = configuration->numRepetitionsPerPreambleAttempt_NB[2]; + nprach_parameters[2].nprach_SubcarrierMSG3_RangeStart_r13 = configuration->nprach_SubcarrierMSG3_RangeStart; + nprach_parameters[2].maxNumPreambleAttemptCE_r13 = configuration->maxNumPreambleAttemptCE_NB; + nprach_parameters[2].npdcch_NumRepetitions_RA_r13 = configuration->npdcch_NumRepetitions_RA[2]; + nprach_parameters[2].npdcch_StartSF_CSS_RA_r13 = configuration->npdcch_StartSF_CSS_RA[2]; + nprach_parameters[2].npdcch_Offset_RA_r13 = configuration->npdcch_Offset_RA[2]; + + + //nprach_parameterList have a max size of 3 possible nprach configuration (see maxNPRACH_Resources_NB_r13) + ASN_SEQUENCE_ADD(&sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.nprach_ParametersList_r13.list,&nprach_parameters[0]); + ASN_SEQUENCE_ADD(&sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.nprach_ParametersList_r13.list,&nprach_parameters[1]); + ASN_SEQUENCE_ADD(&sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.nprach_ParametersList_r13.list,&nprach_parameters[2]); + + // NPDSCH-Config NB-IOT + sib2_NB_IoT->radioResourceConfigCommon_r13.npdsch_ConfigCommon_r13.nrs_Power_r13= configuration->npdsch_nrs_Power; + + + //NPUSCH-Config NB-IoT---------------------------------------------------------------- + //list of size 3 (see maxNPRACH_Resources_NB_r13) + ack_nack_repetition = configuration-> npusch_ack_nack_numRepetitions_NB; //is an enumerative + ASN_SEQUENCE_ADD(&(sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.ack_NACK_NumRepetitions_Msg4_r13.list) ,&ack_nack_repetition); + + *srs_SubframeConfig = configuration->npusch_srs_SubframeConfig_NB; + sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.srs_SubframeConfig_r13= srs_SubframeConfig; /*OPTIONAL*/ + + + /*OPTIONAL*/ + dmrs_config = CALLOC(1,sizeof(struct NPUSCH_ConfigCommon_NB_r13__dmrs_Config_r13)); + dmrs_config->threeTone_CyclicShift_r13 = configuration->npusch_threeTone_CyclicShift_r13; + dmrs_config->sixTone_CyclicShift_r13 = configuration->npusch_sixTone_CyclicShift_r13; + + /*OPTIONAL + * -define the base sequence for a DMRS sequence in a cell with multi tone transmission (3,6,12) see TS 36.331 NPUSCH-Config-NB + * -if not defined will be calculated based on the cellID once we configure the phy layer (rrc_mac_config_req) through the config_sib2 */ + dmrs_config->threeTone_BaseSequence_r13 = NULL; + dmrs_config->sixTone_BaseSequence_r13 = NULL; + dmrs_config->twelveTone_BaseSequence_r13 = NULL; + + sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.dmrs_Config_r13 = dmrs_config; + + //ulReferenceSignalsNPUSCH + /*Reference Signal (RS) for UL in NB-IoT is called DRS (Demodulation Reference Signal) + * sequence-group hopping can be enabled or disabled by means of the cell-specific parameter groupHoppingEnabled_r13 + * sequence-group hopping can be disabled for certain specific UE through the parameter groupHoppingDisabled (physicalConfigDedicated) + * groupAssignmentNPUSCH--> is used for generate the sequence-shift pattern + */ + sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.ul_ReferenceSignalsNPUSCH_r13.groupHoppingEnabled_r13= configuration->npusch_groupHoppingEnabled; + sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.ul_ReferenceSignalsNPUSCH_r13.groupAssignmentNPUSCH_r13 =configuration->npusch_groupAssignmentNPUSCH_r13; + + + //dl_GAP---------------------------------------------------------------------------------/*OPTIONAL*/ + dl_Gap = CALLOC(1,sizeof(struct DL_GapConfig_NB_r13)); + dl_Gap->dl_GapDurationCoeff_r13= configuration-> dl_GapDurationCoeff_NB; + dl_Gap->dl_GapPeriodicity_r13= configuration->dl_GapPeriodicity_NB; + dl_Gap->dl_GapThreshold_r13= configuration->dl_GapThreshold_NB; + sib2_NB_IoT->radioResourceConfigCommon_r13.dl_Gap_r13 = dl_Gap; + + + // uplinkPowerControlCommon - NB-IoT------------------------------------------------------ + sib2_NB_IoT->radioResourceConfigCommon_r13.uplinkPowerControlCommon_r13.p0_NominalNPUSCH_r13 = configuration->npusch_p0_NominalNPUSCH; + sib2_NB_IoT->radioResourceConfigCommon_r13.uplinkPowerControlCommon_r13.deltaPreambleMsg3_r13 = configuration->deltaPreambleMsg3; + sib2_NB_IoT->radioResourceConfigCommon_r13.uplinkPowerControlCommon_r13.alpha_r13 = configuration->npusch_alpha; + //no deltaFlist_PUCCH and no UL cyclic prefix + + // UE Timers and Constants -NB-IoT-------------------------------------------------------- + sib2_NB_IoT->ue_TimersAndConstants_r13.t300_r13 = configuration-> ue_TimersAndConstants_t300_NB; + sib2_NB_IoT->ue_TimersAndConstants_r13.t301_r13 = configuration-> ue_TimersAndConstants_t301_NB; + sib2_NB_IoT->ue_TimersAndConstants_r13.t310_r13 = configuration-> ue_TimersAndConstants_t310_NB; + sib2_NB_IoT->ue_TimersAndConstants_r13.t311_r13 = configuration-> ue_TimersAndConstants_t311_NB; + sib2_NB_IoT->ue_TimersAndConstants_r13.n310_r13 = configuration-> ue_TimersAndConstants_n310_NB; + sib2_NB_IoT->ue_TimersAndConstants_r13.n311_r13 = configuration-> ue_TimersAndConstants_n311_NB; + + //other SIB2-NB Parameters-------------------------------------------------------------------------------- + sib2_NB_IoT->freqInfo_r13.additionalSpectrumEmission_r13 = 1; + sib2_NB_IoT->freqInfo_r13.ul_CarrierFreq_r13 = NULL; /*OPTIONAL*/ + + sib2_NB_IoT->timeAlignmentTimerCommon_r13=TimeAlignmentTimer_infinity;//TimeAlignmentTimer_sf5120; + + /*OPTIONAL*/ + sib2_NB_IoT->multiBandInfoList_r13 = NULL; + +/// SIB3-NB------------------------------------------------------- + + sib3_NB_IoT->cellReselectionInfoCommon_r13.q_Hyst_r13=SystemInformationBlockType3_NB_r13__cellReselectionInfoCommon_r13__q_Hyst_r13_dB4; + sib3_NB_IoT->cellReselectionServingFreqInfo_r13.s_NonIntraSearch_r13=0; //or define in configuration? + + sib3_NB_IoT->intraFreqCellReselectionInfo_r13.q_RxLevMin_r13 = -70; + //new + sib3_NB_IoT->intraFreqCellReselectionInfo_r13.q_QualMin_r13 = CALLOC(1,sizeof(*sib3_NB_IoT->intraFreqCellReselectionInfo_r13.q_QualMin_r13)); + *(sib3_NB_IoT->intraFreqCellReselectionInfo_r13.q_QualMin_r13)= 10; //a caso + + sib3_NB_IoT->intraFreqCellReselectionInfo_r13.p_Max_r13 = NULL; + sib3_NB_IoT->intraFreqCellReselectionInfo_r13.s_IntraSearchP_r13 = 31; // s_intraSearch --> s_intraSearchP!!! (they call in a different way) + sib3_NB_IoT->intraFreqCellReselectionInfo_r13.t_Reselection_r13=1; + + //how to manage? + sib3_NB_IoT->freqBandInfo_r13 = NULL; + sib3_NB_IoT->multiBandInfoList_r13 = NULL; + + +///BCCH message (generate the SI message) + bcch_message->message.present = BCCH_DL_SCH_MessageType_NB_PR_c1; + bcch_message->message.choice.c1.present = BCCH_DL_SCH_MessageType_NB__c1_PR_systemInformation_r13; + + bcch_message->message.choice.c1.choice.systemInformation_r13.criticalExtensions.present = SystemInformation_NB__criticalExtensions_PR_systemInformation_r13; + bcch_message->message.choice.c1.choice.systemInformation_r13.criticalExtensions.choice.systemInformation_r13.sib_TypeAndInfo_r13.list.count=0; + + ASN_SEQUENCE_ADD(&bcch_message->message.choice.c1.choice.systemInformation_r13.criticalExtensions.choice.systemInformation_r13.sib_TypeAndInfo_r13.list, + sib2_NB_part); + ASN_SEQUENCE_ADD(&bcch_message->message.choice.c1.choice.systemInformation_r13.criticalExtensions.choice.systemInformation_r13.sib_TypeAndInfo_r13.list, + sib3_NB_part); + +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_BCCH_DL_SCH_Message_NB, (void*)bcch_message); +#endif + enc_rval = uper_encode_to_buffer(&asn_DEF_BCCH_DL_SCH_Message_NB, + (void*)bcch_message, + carrier->SIB23_NB_IoT, + 900); +// AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", +// enc_rval.failed_type->name, enc_rval.encoded); + +//#if defined(ENABLE_ITTI)..... + + +#ifdef USER_MODE + LOG_D(RRC,"[NB-IoT] SystemInformation-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); +#endif + + if (enc_rval.encoded==-1) { + msg("[RRC] ASN1 : SI-NB encoding failed for SIB23_NB_IoT\n"); + return(-1); + } + + carrier->sib2_NB_IoT = sib2_NB_IoT; + carrier->sib3_NB_IoT = sib3_NB_IoT; + + return((enc_rval.encoded+7)/8); +} + +/*do_RRCConnectionSetup_NB_IoT--> the aim is to establish SRB1 and SRB1bis(implicitly)*/ +uint8_t do_RRCConnectionSetup_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, + int CC_id, + uint8_t* const buffer, //Srb0.Tx_buffer.Payload + const uint8_t Transaction_id, + const NB_IoT_DL_FRAME_PARMS* const frame_parms, // maybe not used + SRB_ToAddModList_NB_r13_t** SRB_configList_NB_IoT, //for both SRB1bis and SRB1 + struct PhysicalConfigDedicated_NB_r13** physicalConfigDedicated_NB_IoT +) + +{ + + asn_enc_rval_t enc_rval; + + + //MP:logical channel group not defined for Nb-IoT + + //MP: logical channel priority pag 605 (is 1 for SRB1 and for SRB1bis should be the same) + //long* prioritySRB1 = NULL; + long* prioritySRB1bis = NULL; + BOOLEAN_t* logicalChannelSR_Prohibit =NULL; //pag 605 + BOOLEAN_t* npusch_AllSymbols= NULL; + +// struct SRB_ToAddMod_NB_r13* SRB1_config_NB = NULL; +// struct SRB_ToAddMod_NB_r13__rlc_Config_r13* SRB1_rlc_config_NB = NULL; +// struct SRB_ToAddMod_NB_r13__logicalChannelConfig_r13* SRB1_lchan_config_NB = NULL; + + struct SRB_ToAddMod_NB_r13* SRB1bis_config_NB_IoT = NULL; + struct SRB_ToAddMod_NB_r13__rlc_Config_r13* SRB1bis_rlc_config_NB_IoT = NULL; + struct SRB_ToAddMod_NB_r13__logicalChannelConfig_r13* SRB1bis_lchan_config_NB_IoT = NULL; + + //No UL_specific parameters for NB-IoT in LogicalChanelConfig-NB + + PhysicalConfigDedicated_NB_r13_t* physicalConfigDedicated2_NB_IoT = NULL; + DL_CCCH_Message_NB_t dl_ccch_msg_NB_IoT; + RRCConnectionSetup_NB_t* rrcConnectionSetup_NB_IoT = NULL; + + memset((void *)&dl_ccch_msg_NB_IoT,0,sizeof(DL_CCCH_Message_NB_t)); + dl_ccch_msg_NB_IoT.message.present = DL_CCCH_MessageType_NB_PR_c1; + dl_ccch_msg_NB_IoT.message.choice.c1.present = DL_CCCH_MessageType_NB__c1_PR_rrcConnectionSetup_r13; + rrcConnectionSetup_NB_IoT = &dl_ccch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionSetup_r13; + + + if (*SRB_configList_NB_IoT) { + free(*SRB_configList_NB_IoT); + } + *SRB_configList_NB_IoT = CALLOC(1,sizeof(SRB_ToAddModList_NB_r13_t)); + +/// SRB1-------------------- + { +// SRB1_config_NB = CALLOC(1,sizeof(*SRB1_config_NB)); +// +// //no srb_Identity in SRB_ToAddMod_NB +// +// SRB1_rlc_config_NB = CALLOC(1,sizeof(*SRB1_rlc_config_NB)); +// SRB1_config_NB->rlc_Config_r13 = SRB1_rlc_config_NB; +// +// SRB1_rlc_config_NB->present = SRB_ToAddMod_NB_r13__rlc_Config_r13_PR_explicitValue; +// SRB1_rlc_config_NB->choice.explicitValue.present=RLC_Config_NB_r13_PR_am;//the only possible in NB_IoT +// +//// SRB1_rlc_config_NB->choice.explicitValue.choice.am.ul_AM_RLC_r13.t_PollRetransmit_r13 = enb_properties.properties[ctxt_pP->module_id]->srb1_timer_poll_retransmit_r13; +//// SRB1_rlc_config_NB->choice.explicitValue.choice.am.ul_AM_RLC_r13.maxRetxThreshold_r13 = enb_properties.properties[ctxt_pP->module_id]->srb1_max_retx_threshold_r13; +//// //(musT be disabled--> SRB1 config pag 640 specs ) +//// SRB1_rlc_config_NB->choice.explicitValue.choice.am.dl_AM_RLC_r13.enableStatusReportSN_Gap_r13 =NULL; +// +// +// SRB1_rlc_config_NB->choice.explicitValue.choice.am.ul_AM_RLC_r13.t_PollRetransmit_r13 = T_PollRetransmit_NB_r13_ms25000; +// SRB1_rlc_config_NB->choice.explicitValue.choice.am.ul_AM_RLC_r13.maxRetxThreshold_r13 = UL_AM_RLC_NB_r13__maxRetxThreshold_r13_t8; +// //(musT be disabled--> SRB1 config pag 640 specs ) +// SRB1_rlc_config_NB->choice.explicitValue.choice.am.dl_AM_RLC_r13.enableStatusReportSN_Gap_r13 = NULL; +// +// SRB1_lchan_config_NB = CALLOC(1,sizeof(*SRB1_lchan_config_NB)); +// SRB1_config_NB->logicalChannelConfig_r13 = SRB1_lchan_config_NB; +// +// SRB1_lchan_config_NB->present = SRB_ToAddMod_NB_r13__logicalChannelConfig_r13_PR_explicitValue; +// +// +// prioritySRB1 = CALLOC(1, sizeof(long)); +// *prioritySRB1 = 1; +// SRB1_lchan_config_NB->choice.explicitValue.priority_r13 = prioritySRB1; +// +// logicalChannelSR_Prohibit = CALLOC(1, sizeof(BOOLEAN_t)); +// *logicalChannelSR_Prohibit = 1; +// //schould be set to TRUE (specs pag 641) +// SRB1_lchan_config_NB->choice.explicitValue.logicalChannelSR_Prohibit_r13 = logicalChannelSR_Prohibit; +// +// //ADD SRB1 +// ASN_SEQUENCE_ADD(&(*SRB_configList_NB_IoT)->list,SRB1_config_NB); + } + +///SRB1bis (The configuration for SRB1 and SRB1bis is the same) the only difference is the logical channel identity = 3 but not set here + + SRB1bis_config_NB_IoT = CALLOC(1,sizeof(*SRB1bis_config_NB_IoT)); + + //no srb_Identity in SRB_ToAddMod_NB + SRB1bis_rlc_config_NB_IoT = CALLOC(1,sizeof(*SRB1bis_rlc_config_NB_IoT)); + SRB1bis_config_NB_IoT->rlc_Config_r13 = SRB1bis_rlc_config_NB_IoT; + + SRB1bis_rlc_config_NB_IoT->present = SRB_ToAddMod_NB_r13__rlc_Config_r13_PR_explicitValue; + SRB1bis_rlc_config_NB_IoT->choice.explicitValue.present=RLC_Config_NB_r13_PR_am;//MP: the only possible RLC config in NB_IoT + + SRB1bis_rlc_config_NB_IoT->choice.explicitValue.choice.am.ul_AM_RLC_r13.t_PollRetransmit_r13 = T_PollRetransmit_NB_r13_ms25000; + SRB1bis_rlc_config_NB_IoT->choice.explicitValue.choice.am.ul_AM_RLC_r13.maxRetxThreshold_r13 = UL_AM_RLC_NB_r13__maxRetxThreshold_r13_t8; + //(musT be disabled--> SRB1 config pag 640 specs ) + SRB1bis_rlc_config_NB_IoT->choice.explicitValue.choice.am.dl_AM_RLC_r13.enableStatusReportSN_Gap_r13 =NULL; + + SRB1bis_lchan_config_NB_IoT = CALLOC(1,sizeof(*SRB1bis_lchan_config_NB_IoT)); + SRB1bis_config_NB_IoT->logicalChannelConfig_r13 = SRB1bis_lchan_config_NB_IoT; + + SRB1bis_lchan_config_NB_IoT->present = SRB_ToAddMod_NB_r13__logicalChannelConfig_r13_PR_explicitValue; + + prioritySRB1bis = CALLOC(1, sizeof(long)); + *prioritySRB1bis = 1; //same as SRB1? + SRB1bis_lchan_config_NB_IoT->choice.explicitValue.priority_r13 = prioritySRB1bis; + + logicalChannelSR_Prohibit = CALLOC(1, sizeof(BOOLEAN_t)); + *logicalChannelSR_Prohibit = 1; //schould be set to TRUE (specs pag 641) + SRB1bis_lchan_config_NB_IoT->choice.explicitValue.logicalChannelSR_Prohibit_r13 = logicalChannelSR_Prohibit; + + //ADD SRB1bis + //MP: Actually there is no way to distinguish SRB1 and SRB1bis once put in the list + //MP: SRB_ToAddModList_NB_r13_t size = 1 + ASN_SEQUENCE_ADD(&(*SRB_configList_NB_IoT)->list,SRB1bis_config_NB_IoT); + + + // PhysicalConfigDedicated (NPDCCH, NPUSCH, CarrierConfig, UplinkPowerControl) + + physicalConfigDedicated2_NB_IoT = CALLOC(1,sizeof(*physicalConfigDedicated2_NB_IoT)); + *physicalConfigDedicated_NB_IoT = physicalConfigDedicated2_NB_IoT; + + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13= CALLOC(1, sizeof(*physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13)); + physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13 = CALLOC(1,sizeof(*physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13)); + physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13 = CALLOC(1,sizeof(*physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13)); + physicalConfigDedicated2_NB_IoT->uplinkPowerControlDedicated_r13 = CALLOC(1,sizeof(*physicalConfigDedicated2_NB_IoT->uplinkPowerControlDedicated_r13)); + + //no tpc, no cqi and no pucch, no pdsch, no soundingRS, no AntennaInfo, no scheduling request config + + /* + * NB-IoT supports the operation with either one or two antenna ports, AP0 and AP1. + * For the latter case, Space Frequency Block Coding (SFBC) is applied. + * Once selected, the same transmission scheme applies to NPBCH, NPDCCH, and NPDSCH. + * */ + + //FIXME: MP: CarrierConfigDedicated check the set values ---------------------------------------------- + + //DL + + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.dl_CarrierFreq_r13.carrierFreq_r13=0;//random value set + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.downlinkBitmapNonAnchor_r13= CALLOC(1,sizeof(struct DL_CarrierConfigDedicated_NB_r13__downlinkBitmapNonAnchor_r13)); + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.downlinkBitmapNonAnchor_r13->present= + DL_CarrierConfigDedicated_NB_r13__downlinkBitmapNonAnchor_r13_PR_useNoBitmap_r13; + + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.dl_GapNonAnchor_r13 = CALLOC(1,sizeof(struct DL_CarrierConfigDedicated_NB_r13__dl_GapNonAnchor_r13)); + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.dl_GapNonAnchor_r13->present = + DL_CarrierConfigDedicated_NB_r13__dl_GapNonAnchor_r13_PR_useNoGap_r13; + + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.inbandCarrierInfo_r13= NULL; + + //UL + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->ul_CarrierConfig_r13.ul_CarrierFreq_r13= NULL; + + // NPDCCH + physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13->npdcch_NumRepetitions_r13 =0; + physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13->npdcch_Offset_USS_r13 =0; + physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13->npdcch_StartSF_USS_r13=0; + + // NPUSCH //(specs TS 36.331 v14.2.1 pag 643) /* OPTIONAL */ + physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13->ack_NACK_NumRepetitions_r13= NULL; + npusch_AllSymbols= CALLOC(1, sizeof(BOOLEAN_t)); + *npusch_AllSymbols= 1; //TRUE + physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13->npusch_AllSymbols_r13= npusch_AllSymbols; /* OPTIONAL */ + physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13->groupHoppingDisabled_r13=NULL; /* OPTIONAL */ + + // UplinkPowerControlDedicated + physicalConfigDedicated2_NB_IoT->uplinkPowerControlDedicated_r13->p0_UE_NPUSCH_r13 = 0; // 0 dB (specs TS36.331 v14.2.1 pag 643) + + + //Fill the rrcConnectionSetup-NB message + rrcConnectionSetup_NB_IoT->rrc_TransactionIdentifier = Transaction_id; //input value + rrcConnectionSetup_NB_IoT->criticalExtensions.present = RRCConnectionSetup_NB__criticalExtensions_PR_c1; + rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.present =RRCConnectionSetup_NB__criticalExtensions__c1_PR_rrcConnectionSetup_r13 ; + //MP: carry only SRB1bis at the moment and phyConfigDedicated + rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.srb_ToAddModList_r13 = *SRB_configList_NB_IoT; + rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.drb_ToAddModList_r13 = NULL; + rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.drb_ToReleaseList_r13 = NULL; + rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.rlf_TimersAndConstants_r13 = NULL; + rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.physicalConfigDedicated_r13 = physicalConfigDedicated2_NB_IoT; + rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.mac_MainConfig_r13 = NULL; + +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_DL_CCCH_Message, (void*)&dl_ccch_msg); +#endif + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_CCCH_Message_NB, + (void*)&dl_ccch_msg_NB_IoT, + buffer, + 100); + + if (enc_rval.encoded <= 0) { + LOG_F(RRC, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + +#ifdef USER_MODE + LOG_D(RRC,"RRCConnectionSetup-NB Encoded %zd bits (%zd bytes), ecause %d\n", + enc_rval.encoded,(enc_rval.encoded+7)/8,ecause); +#endif + + return((enc_rval.encoded+7)/8); +} + +/*do_SecurityModeCommand - exactly the same as previous implementation*/ +uint8_t do_SecurityModeCommand_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + uint8_t* const buffer, + const uint8_t Transaction_id, + const uint8_t cipheringAlgorithm, + const uint8_t integrityProtAlgorithm) +{ + DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; + asn_enc_rval_t enc_rval; + + memset(&dl_dcch_msg_NB_IoT,0,sizeof(DL_DCCH_Message_NB_t)); + + dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; + dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_securityModeCommand_r13; + + dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.rrc_TransactionIdentifier = Transaction_id; + dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.criticalExtensions.present = SecurityModeCommand__criticalExtensions_PR_c1; + + dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.criticalExtensions.choice.c1.present = + SecurityModeCommand__criticalExtensions__c1_PR_securityModeCommand_r8; + + // the two following information could be based on the mod_id + dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.cipheringAlgorithm + = (CipheringAlgorithm_r12_t)cipheringAlgorithm; //bug solved + + dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.integrityProtAlgorithm + = (e_SecurityAlgorithmConfig__integrityProtAlgorithm)integrityProtAlgorithm; + +//only changed "asn_DEF_DL_DCCH_Message_NB" +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_DL_DCCH_Message_NB, (void*)&dl_dcch_msg_NB_IoT); +#endif + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_DCCH_Message_NB, + (void*)&dl_dcch_msg_NB_IoT, + buffer, + 100); + if (enc_rval.encoded <= 0) { + LOG_F(RRC, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + + +//#if defined(ENABLE_ITTI) +//# if !defined(DISABLE_XER_SPRINT).... + +#ifdef USER_MODE + LOG_D(RRC,"[NB-IoT %d] securityModeCommand-NB for UE %x Encoded %zd bits (%zd bytes)\n", + ctxt_pP->module_id, + ctxt_pP->rnti, + enc_rval.encoded, + (enc_rval.encoded+7)/8); +#endif + + if (enc_rval.encoded==-1) { + LOG_E(RRC,"[NB-IoT %d] ASN1 : securityModeCommand-NB encoding failed for UE %x\n", + ctxt_pP->module_id, + ctxt_pP->rnti); + return(-1); + } + + return((enc_rval.encoded+7)/8); +} + +/*do_UECapabilityEnquiry_NB_IoT - very similar to legacy lte*/ +uint8_t do_UECapabilityEnquiry_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + uint8_t* const buffer, + const uint8_t Transaction_id +) + +{ + + DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; + //no RAT type in NB-IoT + asn_enc_rval_t enc_rval; + + memset(&dl_dcch_msg_NB_IoT,0,sizeof(DL_DCCH_Message_NB_t)); + + dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; + dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_ueCapabilityEnquiry_r13; + + dl_dcch_msg_NB_IoT.message.choice.c1.choice.ueCapabilityEnquiry_r13.rrc_TransactionIdentifier = Transaction_id; + + dl_dcch_msg_NB_IoT.message.choice.c1.choice.ueCapabilityEnquiry_r13.criticalExtensions.present = UECapabilityEnquiry_NB__criticalExtensions_PR_c1; + dl_dcch_msg_NB_IoT.message.choice.c1.choice.ueCapabilityEnquiry_r13.criticalExtensions.choice.c1.present = + UECapabilityEnquiry_NB__criticalExtensions__c1_PR_ueCapabilityEnquiry_r13; + + //no ue_CapabilityRequest (list of RAT_Type) + +//only changed "asn_DEF_DL_DCCH_Message_NB" +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_DL_DCCH_Message_NB, (void*)&dl_dcch_msg_NB_IoT); +#endif + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_DCCH_Message_NB, + (void*)&dl_dcch_msg_NB_IoT, + buffer, + 100); + if (enc_rval.encoded <= 0) { + LOG_F(RRC, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + +//#if defined(ENABLE_ITTI) +//# if !defined(DISABLE_XER_SPRINT).... + +#ifdef USER_MODE + LOG_D(RRC,"[NB-IoT %d] UECapabilityEnquiry-NB for UE %x Encoded %zd bits (%zd bytes)\n", + ctxt_pP->module_id, + ctxt_pP->rnti, + enc_rval.encoded, + (enc_rval.encoded+7)/8); +#endif + + if (enc_rval.encoded==-1) { + LOG_E(RRC,"[NB-IoT %d] ASN1 : UECapabilityEnquiry-NB encoding failed for UE %x\n", + ctxt_pP->module_id, + ctxt_pP->rnti); + return(-1); + } + + return((enc_rval.encoded+7)/8); +} + +/*do_RRCConnectionReconfiguration_NB_IoT-->may convey information for resource configuration + * (including RBs, MAC main configuration and physical channel configuration) + * including any associated dedicated NAS information.*/ +uint16_t do_RRCConnectionReconfiguration_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + uint8_t *buffer, + uint8_t Transaction_id, + SRB_ToAddModList_NB_r13_t *SRB1_list_NB, //SRB_ConfigList2 (default)--> only SRB1 + DRB_ToAddModList_NB_r13_t *DRB_list_NB_IoT, //DRB_ConfigList (default) + DRB_ToReleaseList_NB_r13_t *DRB_list2_NB_IoT, //is NULL when passed + struct PhysicalConfigDedicated_NB_r13 *physicalConfigDedicated_NB_IoT, + MAC_MainConfig_NB_r13_t *mac_MainConfig_NB_IoT, + struct RRCConnectionReconfiguration_NB_r13_IEs__dedicatedInfoNASList_r13* dedicatedInfoNASList_NB_IoT) + +{ + + //check on DRB_list if contains more than 2 DRB? + + asn_enc_rval_t enc_rval; + DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; + RRCConnectionReconfiguration_NB_t *rrcConnectionReconfiguration_NB; + + + memset(&dl_dcch_msg_NB_IoT,0,sizeof(DL_DCCH_Message_NB_t)); + + dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; + dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_rrcConnectionReconfiguration_r13; + rrcConnectionReconfiguration_NB = &dl_dcch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionReconfiguration_r13; + + // RRCConnectionReconfiguration + rrcConnectionReconfiguration_NB->rrc_TransactionIdentifier = Transaction_id; + rrcConnectionReconfiguration_NB->criticalExtensions.present = RRCConnectionReconfiguration_NB__criticalExtensions_PR_c1; + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.present =RRCConnectionReconfiguration_NB__criticalExtensions__c1_PR_rrcConnectionReconfiguration_r13 ; + + //RAdioResourceconfigDedicated + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13 = + CALLOC(1,sizeof(*rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13)); + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->srb_ToAddModList_r13 = SRB1_list_NB; //only SRB1 + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->drb_ToAddModList_r13 = DRB_list_NB_IoT; + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->drb_ToReleaseList_r13 = DRB_list2_NB_IoT; //NULL + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->physicalConfigDedicated_r13 = physicalConfigDedicated_NB_IoT; + //FIXME may not used now + //rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->rlf_TimersAndConstants_r13 + + if (mac_MainConfig_NB_IoT!=NULL) { + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13 = + CALLOC(1, sizeof(*rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13)); + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13->present + =RadioResourceConfigDedicated_NB_r13__mac_MainConfig_r13_PR_explicitValue_r13; + //why memcopy only this one? + memcpy(&rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13->choice.explicitValue_r13, + mac_MainConfig_NB_IoT, sizeof(*mac_MainConfig_NB_IoT)); + + } else { + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13=NULL; + } + + //no measConfig, measIDlist + //no mobilityControlInfo + + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.dedicatedInfoNASList_r13 = dedicatedInfoNASList_NB_IoT; + //mainly used for cell-reselection/handover purposes?? + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.fullConfig_r13 = NULL; + + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_DCCH_Message_NB, + (void*)&dl_dcch_msg_NB_IoT, + buffer, + RRC_BUF_SIZE); + if (enc_rval.encoded <= 0) { + LOG_F(RRC, "ASN1 message encoding failed %s, %li\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + + //changed only asn_DEF_DL_DCCH_Message_NB +#ifdef XER_PRINT + xer_fprint(stdout,&asn_DEF_DL_DCCH_Message_NB,(void*)&dl_dcch_msg_NB_IoT); +#endif + +//#if defined(ENABLE_ITTI) +//# if !defined(DISABLE_XER_SPRINT)... + + + LOG_I(RRC,"RRCConnectionReconfiguration-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + + return((enc_rval.encoded+7)/8); +} + +/*do_RRCConnectionReestablishmentReject - exactly the same as legacy LTE*/ +uint8_t do_RRCConnectionReestablishmentReject_NB_IoT( + uint8_t Mod_id, + uint8_t* const buffer) +{ + + asn_enc_rval_t enc_rval; + + DL_CCCH_Message_NB_t dl_ccch_msg_NB_IoT; + RRCConnectionReestablishmentReject_t *rrcConnectionReestablishmentReject; + + memset((void *)&dl_ccch_msg_NB_IoT,0,sizeof(DL_CCCH_Message_NB_t)); + dl_ccch_msg_NB_IoT.message.present = DL_CCCH_MessageType_NB_PR_c1; + dl_ccch_msg_NB_IoT.message.choice.c1.present = DL_CCCH_MessageType_NB__c1_PR_rrcConnectionReestablishmentReject_r13; + rrcConnectionReestablishmentReject = &dl_ccch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionReestablishmentReject_r13; + + // RRCConnectionReestablishmentReject //exactly the same as LTE + rrcConnectionReestablishmentReject->criticalExtensions.present = RRCConnectionReestablishmentReject__criticalExtensions_PR_rrcConnectionReestablishmentReject_r8; + + //Only change in "asn_DEF_DL_CCCH_Message_NB" +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_DL_CCCH_Message_NB, (void*)&dl_ccch_msg_NB_IoT); +#endif + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_CCCH_Message_NB, + (void*)&dl_ccch_msg_NB_IoT, + buffer, + 100); + if (enc_rval.encoded <= 0) { + LOG_F(RRC,"ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + + //Only change in "asn_DEF_DL_CCCH_Message_NB" +#if defined(ENABLE_ITTI) +# if !defined(DISABLE_XER_SPRINT) + { + char message_string[20000]; + size_t message_string_size; + + if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_DL_CCCH_Message_NB, (void *) &dl_ccch_msg_NB_IoT)) > 0) { + MessageDef *msg_p; + + msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB_NB_IoT, RRC_DL_CCCH, message_string_size + sizeof (IttiMsgText)); + msg_p->ittiMsg.rrc_dl_ccch.size = message_string_size; + memcpy(&msg_p->ittiMsg.rrc_dl_ccch.text, message_string, message_string_size); + + itti_send_msg_to_task(TASK_UNKNOWN, Mod_id, msg_p); + } + } +# endif +#endif + +#ifdef USER_MODE + LOG_D(RRC,"RRCConnectionReestablishmentReject Encoded %zd bits (%zd bytes)\n", + enc_rval.encoded,(enc_rval.encoded+7)/8); +#endif + + return((enc_rval.encoded+7)/8); +} + +/*do_RRCConnectionReject_NB_IoT*/ +uint8_t do_RRCConnectionReject_NB_IoT( + uint8_t Mod_id, + uint8_t* const buffer) + +{ + + asn_enc_rval_t enc_rval; + + DL_CCCH_Message_NB_t dl_ccch_msg_NB_IoT; + RRCConnectionReject_NB_t *rrcConnectionReject_NB_IoT; + + memset((void *)&dl_ccch_msg_NB_IoT,0,sizeof(DL_CCCH_Message_NB_t)); + dl_ccch_msg_NB_IoT.message.present = DL_CCCH_MessageType_NB_PR_c1; + dl_ccch_msg_NB_IoT.message.choice.c1.present = DL_CCCH_MessageType_NB__c1_PR_rrcConnectionReject_r13; + rrcConnectionReject_NB_IoT = &dl_ccch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionReject_r13; + + // RRCConnectionReject-NB_IoT + rrcConnectionReject_NB_IoT->criticalExtensions.present = RRCConnectionReject_NB__criticalExtensions_PR_c1; + rrcConnectionReject_NB_IoT->criticalExtensions.choice.c1.present = RRCConnectionReject_NB__criticalExtensions__c1_PR_rrcConnectionReject_r13; + /* let's put an extended wait time of 1s for the moment */ + rrcConnectionReject_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReject_r13.extendedWaitTime_r13 = 1; + //new-use of suspend indication + //If present, this field indicates that the UE should remain suspended and not release its stored context. + rrcConnectionReject_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReject_r13.rrc_SuspendIndication_r13= + CALLOC(1, sizeof(long)); + *(rrcConnectionReject_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReject_r13.rrc_SuspendIndication_r13)= + RRCConnectionReject_NB_r13_IEs__rrc_SuspendIndication_r13_true; + + //Only Modified "asn_DEF_DL_CCCH_Message_NB" +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_DL_CCCH_Message_NB, (void*)&dl_ccch_msg); +#endif + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_CCCH_Message_NB, + (void*)&dl_ccch_msg_NB_IoT, + buffer, + 100); + if (enc_rval.encoded <= 0) { + LOG_F(RRC, "ASN1 message encoding failed (%s, %ld)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + +#if defined(ENABLE_ITTI) +# if !defined(DISABLE_XER_SPRINT) + { + char message_string[20000]; + size_t message_string_size; + + if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_DL_CCCH_Message_NB, (void *) &dl_ccch_msg_NB_IoT)) > 0) { + MessageDef *msg_p; + + msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB_NB_IoT, RRC_DL_CCCH, message_string_size + sizeof (IttiMsgText)); + msg_p->ittiMsg.rrc_dl_ccch.size = message_string_size; + memcpy(&msg_p->ittiMsg.rrc_dl_ccch.text, message_string, message_string_size); + + itti_send_msg_to_task(TASK_UNKNOWN, Mod_id, msg_p); + } + } +# endif +#endif + +#ifdef USER_MODE + LOG_D(RRC,"RRCConnectionReject-NB Encoded %zd bits (%zd bytes)\n", + enc_rval.encoded,(enc_rval.encoded+7)/8); +#endif + + return((enc_rval.encoded+7)/8); +} + + +//no do_MBSFNAreaConfig(..) in NB-IoT +//no do_MeasurementReport(..) in NB-IoT + +/*do_DLInformationTransfer_NB*/ +uint8_t do_DLInformationTransfer_NB_IoT( + uint8_t Mod_id, + uint8_t **buffer, + uint8_t transaction_id, + uint32_t pdu_length, + uint8_t *pdu_buffer) + +{ + ssize_t encoded; + + DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; + + memset(&dl_dcch_msg_NB_IoT, 0, sizeof(DL_DCCH_Message_NB_t)); + + dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; + dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_dlInformationTransfer_r13; + dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.rrc_TransactionIdentifier = transaction_id; + dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.criticalExtensions.present = DLInformationTransfer_NB__criticalExtensions_PR_c1; + dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.criticalExtensions.choice.c1.present = DLInformationTransfer_NB__criticalExtensions__c1_PR_dlInformationTransfer_r13; + dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.criticalExtensions.choice.c1.choice.dlInformationTransfer_r13.dedicatedInfoNAS_r13.size = pdu_length; + dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.criticalExtensions.choice.c1.choice.dlInformationTransfer_r13.dedicatedInfoNAS_r13.buf = pdu_buffer; + + encoded = uper_encode_to_new_buffer (&asn_DEF_DL_DCCH_Message_NB, NULL, (void*) &dl_dcch_msg_NB_IoT, (void **) buffer); + + //only change in "asn_DEF_DL_DCCH_Message_NB" +#if defined(ENABLE_ITTI) +# if !defined(DISABLE_XER_SPRINT) + { + char message_string[10000]; + size_t message_string_size; + + if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_DL_DCCH_Message_NB, (void *)&dl_dcch_msg_NB_IoT)) > 0) { + MessageDef *msg_p; + + msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB_NB_IoT, RRC_DL_DCCH, message_string_size + sizeof (IttiMsgText)); + msg_p->ittiMsg.rrc_dl_dcch.size = message_string_size; + memcpy(&msg_p->ittiMsg.rrc_dl_dcch.text, message_string, message_string_size); + + itti_send_msg_to_task(TASK_UNKNOWN, Mod_id, msg_p); + } + } +# endif +#endif + + return encoded; +} + +/*do_ULInformationTransfer*/ +//for the moment is not needed (UE-SIDE) + +/*OAI_UECapability_t *fill_ue_capability*/ + +/*do_RRCConnectionReestablishment_NB-->used to re-establish SRB1*/ //which parameter to use? +uint8_t do_RRCConnectionReestablishment_NB_IoT( + uint8_t Mod_id, + uint8_t* const buffer, + const uint8_t Transaction_id, + const NB_IoT_DL_FRAME_PARMS* const frame_parms, //to be changed + SRB_ToAddModList_NB_r13_t* SRB_list_NB_IoT) //should contain SRB1 already configured? +{ + + asn_enc_rval_t enc_rval; + DL_CCCH_Message_NB_t dl_ccch_msg_NB_IoT; + RRCConnectionReestablishment_NB_t* rrcConnectionReestablishment_NB_IoT; + + memset(&dl_ccch_msg_NB_IoT, 0, sizeof(DL_CCCH_Message_NB_t)); + + dl_ccch_msg_NB_IoT.message.present = DL_CCCH_MessageType_NB_PR_c1; + dl_ccch_msg_NB_IoT.message.choice.c1.present = DL_CCCH_MessageType_NB__c1_PR_rrcConnectionReestablishment_r13; + rrcConnectionReestablishment_NB_IoT = &dl_ccch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionReestablishment_r13; + + //rrcConnectionReestablishment_NB + rrcConnectionReestablishment_NB_IoT->rrc_TransactionIdentifier = Transaction_id; + rrcConnectionReestablishment_NB_IoT->criticalExtensions.present = RRCConnectionReestablishment_NB__criticalExtensions_PR_c1; + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.present = RRCConnectionReestablishment_NB__criticalExtensions__c1_PR_rrcConnectionReestablishment_r13; + + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.srb_ToAddModList_r13 = SRB_list_NB_IoT; + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.drb_ToAddModList_r13 = NULL; + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.drb_ToReleaseList_r13 = NULL; + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.rlf_TimersAndConstants_r13= NULL; + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.mac_MainConfig_r13= NULL; + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.physicalConfigDedicated_r13 = NULL; + + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.nextHopChainingCount_r13=0; + + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_CCCH_Message_NB, + (void*)&dl_ccch_msg_NB_IoT, + buffer, + RRC_BUF_SIZE); + + if (enc_rval.encoded <= 0) { + LOG_F(RRC, "ASN1 message encoding failed (%s, %li)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + +#ifdef XER_PRINT + xer_fprint(stdout,&asn_DEF_DL_CCCH_Message_NB,(void*)&dl_ccch_msg_NB_IoT); +#endif + +#if defined(ENABLE_ITTI) +# if !defined(DISABLE_XER_SPRINT) + { + char message_string[30000]; + size_t message_string_size; + + if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_DL_CCCH_Message_NB, (void *) &dl_ccch_msg_NB_IoT)) > 0) { + MessageDef *msg_p; + + msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB_NB_IoT, RRC_DL_CCCH, message_string_size + sizeof (IttiMsgText)); + msg_p->ittiMsg.rrc_dl_ccch.size = message_string_size; + memcpy(&msg_p->ittiMsg.rrc_dl_ccch.text, message_string, message_string_size); + + itti_send_msg_to_task(TASK_UNKNOWN, Mod_id, msg_p); + } + } +# endif +#endif + + LOG_I(RRC,"RRCConnectionReestablishment-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + return 0; +} + +/*do_RRCConnectionRelease_NB--> is used to command the release of an RRC connection*/ +uint8_t do_RRCConnectionRelease_NB_IoT( + uint8_t Mod_id, + uint8_t *buffer, + const uint8_t Transaction_id) +{ + + asn_enc_rval_t enc_rval; + + DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; + RRCConnectionRelease_NB_t *rrcConnectionRelease_NB_IoT; + + + memset(&dl_dcch_msg_NB_IoT,0,sizeof(DL_DCCH_Message_NB_t)); + + dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; + dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_rrcConnectionRelease_r13; + rrcConnectionRelease_NB_IoT = &dl_dcch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionRelease_r13; + + // RRCConnectionRelease + rrcConnectionRelease_NB_IoT->rrc_TransactionIdentifier = Transaction_id; + rrcConnectionRelease_NB_IoT->criticalExtensions.present = RRCConnectionRelease_NB__criticalExtensions_PR_c1; + rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.present =RRCConnectionRelease_NB__criticalExtensions__c1_PR_rrcConnectionRelease_r13 ; + + rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.releaseCause_r13 = ReleaseCause_NB_r13_other; + rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.redirectedCarrierInfo_r13 = NULL; + rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.extendedWaitTime_r13 = NULL; + + //Why allocate memory for non critical extension? + rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.nonCriticalExtension=CALLOC(1, + sizeof(*rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.nonCriticalExtension)); + + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_DCCH_Message_NB, + (void*)&dl_dcch_msg_NB_IoT, + buffer, + RRC_BUF_SIZE);//check + + return((enc_rval.encoded+7)/8); +} + + + + diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h b/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h new file mode 100644 index 0000000000..67e0919307 --- /dev/null +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h @@ -0,0 +1,293 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file asn1_msg.h +* \brief primitives to build the asn1 messages +* \author Raymond Knopp, Navid Nikaein and Michele Paffetti +* \date 2011, 2017 +* \version 1.0 +* \company Eurecom +* \email: raymond.knopp@eurecom.fr ,navid.nikaein@eurecom.fr, michele.paffetti@studio.unibo.it +*/ + +#ifdef USER_MODE +#include +#include +#include /* for atoi(3) */ +#include /* for getopt(3) */ +#include /* for strerror(3) */ +#include /* for EX_* exit codes */ +#include /* for errno */ +#else +#include /* Needed by all modules */ +#endif + +#include +#include /* for _ASN_DEFAULT_STACK_MAX */ + + +#include "RRC/LITE/defs_NB_IoT.h" + +/* + * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) + * output into the chosen string buffer. + * RETURN VALUES: + * 0: The structure is printed. + * -1: Problem printing the structure. + * WARNING: No sensible error value is returned. + */ + + +/** +\brief Generate configuration for SIB1 (eNB). +@param carrier pointer to Carrier information +@param N_RB_DL Number of downlink PRBs +@param frame radio frame number +@return size of encoded bit stream in bytes*/ +uint8_t do_MIB_NB_IoT( + rrc_eNB_carrier_data_NB_IoT_t *carrier, + uint32_t N_RB_DL, + uint32_t frame, + uint32_t hyper_frame); + + +/** +\brief Generate a default configuration for SIB1-NB (eNB). +@param Mod_id Instance of eNB +@param CC_id Component carrier to configure +@param carrier pointer to Carrier information +@param configuration Pointer Configuration Request structure +@return size of encoded bit stream in bytes*/ + +uint8_t do_SIB1_NB_IoT(uint8_t Mod_id, + int CC_id, + rrc_eNB_carrier_data_NB_IoT_t *carrier, + NbIoTRrcConfigurationReq *configuration, + uint32_t frame + ); + +/** +\brief Generate a default configuration for SIB2/SIB3-NB in one System Information PDU (eNB). +@param Mod_id Index of eNB (used to derive some parameters) +@param buffer Pointer to PER-encoded ASN.1 description of SI-NB PDU +@param systemInformation_NB_IoT Pointer to asn1c C representation of SI-NB PDU +@param sib2_NB Pointer (returned) to sib2_NB component withing SI-NB PDU +@param sib3_NB Pointer (returned) to sib3_NB component withing SI-NB PDU +@return size of encoded bit stream in bytes*/ + +uint8_t do_SIB23_NB_IoT(uint8_t Mod_id, + int CC_id, + rrc_eNB_carrier_data_NB_IoT_t *carrier, + NbIoTRrcConfigurationReq *configuration + ); + +/**(UE-SIDE) +\brief Generate an RRCConnectionRequest-NB UL-CCCH-Message (UE) based on random string or S-TMSI. This +routine only generates an mo-data establishment cause. +@param buffer Pointer to PER-encoded ASN.1 description of UL-DCCH-Message PDU +@param rv 5 byte random string or S-TMSI +@param Mod_id +@returns Size of encoded bit stream in bytes*/ + +uint8_t do_RRCConnectionRequest_NB_IoT(uint8_t Mod_id, uint8_t *buffer,uint8_t *rv); + + +/**(UE -SIDE) +\brief Generate an RRCConnectionSetupComplete-NB UL-DCCH-Message (UE) +@param Mod_id +@param Transaction_id +@param dedicatedInfoNASLength +@param dedicatedInfoNAS +@param buffer Pointer to PER-encoded ASN.1 description of UL-DCCH-Message PDU +@returns Size of encoded bit stream in bytes*/ + +uint8_t do_RRCConnectionSetupComplete_NB_IoT(uint8_t Mod_id, uint8_t* buffer, const uint8_t Transaction_id, const int dedicatedInfoNASLength, + const char* dedicatedInfoNAS); + +/** (UE-SIDE) +\brief Generate an RRCConnectionReconfigurationComplete-NB UL-DCCH-Message (UE) +@param buffer Pointer to PER-encoded ASN.1 description of UL-DCCH-Message PDU +@param ctxt_pP +@param Transaction_id +@returns Size of encoded bit stream in bytes*/ + +uint8_t do_RRCConnectionReconfigurationComplete_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + uint8_t* buffer, + const uint8_t Transaction_id +); + +/** +\brief Generate an RRCConnectionSetup-NB DL-CCCH-Message (eNB). This routine configures SRB_ToAddMod (SRB1/SRB1bis-NB) and +PhysicalConfigDedicated-NB IEs. +@param ctxt_pP Running context +@param ue_context_pP UE context +@param CC_id Component Carrier ID +@param buffer Pointer to PER-encoded ASN.1 description of DL-CCCH-Message PDU +@param transmission_mode Transmission mode for UE (1-9) +@param UE_id UE index for this message +@param Transaction_id Transaction_ID for this message +@param SRB_configList Pointer (returned) to SRB1_config/SRB1bis_config(later) IEs for this UE +@param physicalConfigDedicated_NB Pointer (returned) to PhysicalConfigDedicated-NB IE for this UE +@returns Size of encoded bit stream in bytes*/ + +uint8_t do_RRCConnectionSetup_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, + int CC_id, + uint8_t* const buffer, //carrier[CC_id].Srb0.Tx_buffer.Payload + const uint8_t Transaction_id, + const NB_IoT_DL_FRAME_PARMS* const frame_parms, //to be changed but not deleted + SRB_ToAddModList_NB_r13_t** SRB_configList_NB_IoT, //in order to be configured--> stanno puntando alla SRB_configlist dell ue_context + struct PhysicalConfigDedicated_NB_r13** physicalConfigDedicated_NB_IoT //in order to be configured--> stanno puntando alla physicalConfigDedicated dell ue_context +); + + +/** + * For which SRB is used in NB-IoT?? +\brief Generate an RRCConnectionReconfiguration-NB DL-DCCH-Message (eNB). This routine configures SRBToAddMod-NB (SRB1) and one DRBToAddMod-NB +(DRB3). PhysicalConfigDedicated-NB is not updated. +@param ctxt_pP Running context +@param buffer Pointer to PER-encoded ASN.1 description of DL-CCCH-Message PDU +@param Transaction_id Transaction_ID for this message +@param SRB_list_NB Pointer to SRB List to be added/modified (NULL if no additions/modifications) +@param DRB_list_NB Pointer to DRB List to be added/modified (NULL if no additions/modifications) +@param DRB_list2_NB Pointer to DRB List to be released (NULL if none to be released) +//sps not supported by NB-IoT +@param physicalConfigDedicated_NB Pointer to PhysicalConfigDedicated-NB to be modified (NULL if no modifications) +//measurement not supported by NB-IoT +@param mac_MainConfig Pointer to Mac_MainConfig(NULL if no modifications) +//no CBA functionalities +@returns Size of encoded bit stream in bytes*/ + +uint16_t +do_RRCConnectionReconfiguration_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + uint8_t *buffer, + uint8_t Transaction_id, + SRB_ToAddModList_NB_r13_t *SRB_list_NB_IoT, + DRB_ToAddModList_NB_r13_t *DRB_list_NB_IoT, + DRB_ToReleaseList_NB_r13_t *DRB_list2_NB_IoT, + struct PhysicalConfigDedicated_NB_r13 *physicalConfigDedicated, + MAC_MainConfig_t *mac_MainConfig, + struct RRCConnectionReconfiguration_NB_r13_IEs__dedicatedInfoNASList_r13* dedicatedInfoNASList_NB_IoT); + +/** + * E-UTRAN applies the procedure as follows: when only for NB-IoT SRB1 and SRB1bis is established + \brief Generate a SecurityModeCommand + @param ctxt_pP Running context + @param buffer Pointer to PER-encoded ASN.1 description + @param Transaction_id Transaction_ID for this message + @param cipheringAlgorithm + @param integrityProtAlgorithm + */ + +uint8_t do_SecurityModeCommand_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + uint8_t* const buffer, + const uint8_t Transaction_id, + const uint8_t cipheringAlgorithm, + const uint8_t integrityProtAlgorithm); + +/** + * E-UTRAN applies the procedure as follows: when only for NB-IoT SRB1 and SRB1bis is established + \brief Generate a SecurityModeCommand + @param ctxt_pP Running context + @param buffer Pointer to PER-encoded ASN.1 description + @param Transaction_id Transaction_ID for this message + */ + +uint8_t do_UECapabilityEnquiry_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + uint8_t* const buffer, + const uint8_t Transaction_id +); + + +/** + * There is nothing new in this type of message for NB-IoT (only change in some nomenclature) +\brief Generate an RRCConnectionReestablishmentReject DL-CCCH-Message (eNB). +@param Mod_id Module ID of eNB +@param buffer Pointer to PER-encoded ASN.1 description of DL-CCCH-Message PDU +@returns Size of encoded bit stream in bytes*/ + +uint8_t +do_RRCConnectionReestablishmentReject_NB_IoT( + uint8_t Mod_id, + uint8_t* const buffer); + + +/** +\brief Generate an RRCConnectionReject-NB DL-CCCH-Message (eNB). +@param Mod_id Module ID of eNB +@param buffer Pointer to PER-encoded ASN.1 description of DL-CCCH-Message PDU +@returns Size of encoded bit stream in bytes*/ +uint8_t +do_RRCConnectionReject_NB_IoT( + uint8_t Mod_id, + uint8_t* const buffer); + + +/** +\brief Generate an RRCConnectionRelease-NB DL-DCCH-Message +@param Mod_id Module ID of eNB +@param buffer Pointer to PER-encoded ASN.1 description +@param transaction_id Transaction index +@returns Size of encoded bit stream in bytes*/ + +uint8_t do_RRCConnectionRelease_NB_IoT(uint8_t Mod_id, uint8_t *buffer,int Transaction_id); + + +uint8_t do_DLInformationTransfer_NB_IoT( + uint8_t Mod_id, + uint8_t **buffer, + uint8_t transaction_id, + uint32_t pdu_length, + uint8_t *pdu_buffer); + +//for now not implemented since UE side +//uint8_t do_ULInformationTransfer(uint8_t **buffer, uint32_t pdu_length, uint8_t *pdu_buffer); + +//for now not implemented since UE side??? +//OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname) + +/** +\brief Generate an RRCConnectionReestablishment-NB DL-CCCH Message + *@param + * + */ + +uint8_t do_RRCConnectionReestablishment_NB_IoT( + uint8_t Mod_id, + uint8_t* const buffer, + const uint8_t Transaction_id, + const NB_IoT_DL_FRAME_PARMS* const frame_parms, //to be changed + SRB_ToAddModList_NB_r13_t** SRB_configList_NB_IoT + ); + +/** +\brief Generate an RRCConnectionRelease-NB DL-DCCH-Message (eNB) +@param Mod_id Module ID of eNB +@param buffer Pointer to PER-encoded ASN.1 description of DL-DCCH-Message PDU +@param transaction_id Transaction index +@returns Size of encoded bit stream in bytes*/ + +//uint8_t do_RRCConnectionRelease_NB_IoT(uint8_t Mod_id, uint8_t *buffer,int Transaction_id); diff --git a/openair2/RRC/LITE/defs_NB_IoT.h b/openair2/RRC/LITE/defs_NB_IoT.h new file mode 100644 index 0000000000..98b9148cd2 --- /dev/null +++ b/openair2/RRC/LITE/defs_NB_IoT.h @@ -0,0 +1,570 @@ +/* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file RRC/LITE/defs_NB_IoT.h +* \brief NB-IoT RRC struct definitions and function prototypes +* \author Navid Nikaein, Raymond Knopp and Michele Paffetti +* \date 2010 - 2014, 2017 +* \version 1.0 +* \company Eurecom +* \email: navid.nikaein@eurecom.fr, raymond.knopp@eurecom.fr, michele.paffetti@studio.unibo.it +*/ + +#ifndef __OPENAIR_RRC_DEFS_NB_IOT_H__ +#define __OPENAIR_RRC_DEFS_NB_IOT_H__ + + +#include +#include +#include + +#include "collection/tree.h" +#include "rrc_types_NB_IoT.h" +#include "COMMON/platform_constants.h" +#include "COMMON/platform_types.h" +#include "targets/COMMON/openairinterface5g_limits.h" + +#include "COMMON/mac_rrc_primitives.h" + +//-----NB-IoT #include files------- + +//#include "SystemInformationBlockType1-NB.h" +//#include "SystemInformation-NB.h" +#include "RRCConnectionReconfiguration-NB.h" +#include "RRCConnectionReconfigurationComplete-NB.h" +#include "RRCConnectionSetup-NB.h" +#include "RRCConnectionSetupComplete-NB.h" +#include "RRCConnectionRequest-NB.h" +#include "RRCConnectionReestablishmentRequest-NB.h" +#include "BCCH-DL-SCH-Message-NB.h" +#include "BCCH-BCH-Message-NB.h" +#include "AS-Config-NB.h" +#include "AS-Context-NB.h" +#include "UE-Capability-NB-r13.h" //equivalent of UE-EUTRA-Capability.h +//------------------- + +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +#endif + +/* TODO: be sure this include is correct. + * It solves a problem of compilation of the RRH GW, + * issue #186. + */ +#if !defined(ENABLE_ITTI) +# include "as_message.h" +#endif + +#if defined(ENABLE_USE_MME) +# include "commonDef.h" +#endif + +#if ENABLE_RAL +# include "collection/hashtable/obj_hashtable.h" +#endif + + + +/*I will change the name of the structure for compile purposes--> hope not to undo this process*/ + +typedef unsigned int uid_NB_IoT_t; +#define UID_LINEAR_ALLOCATOR_BITMAP_SIZE_NB_IoT (((NUMBER_OF_UE_MAX_NB_IoT/8)/sizeof(unsigned int)) + 1) + +typedef struct uid_linear_allocator_NB_IoT_s { + unsigned int bitmap[UID_LINEAR_ALLOCATOR_BITMAP_SIZE_NB_IoT]; +} uid_allocator_NB_IoT_t; + + +#define PROTOCOL_RRC_CTXT_UE_FMT PROTOCOL_CTXT_FMT +#define PROTOCOL_RRC_CTXT_UE_ARGS(CTXT_Pp) PROTOCOL_CTXT_ARGS(CTXT_Pp) + +#define PROTOCOL_RRC_CTXT_FMT PROTOCOL_CTXT_FMT +#define PROTOCOL_RRC_CTXT_ARGS(CTXT_Pp) PROTOCOL_CTXT_ARGS(CTXT_Pp) + + +//left as they are --> used in LAYER2/epenair2_proc.c and UE side +typedef enum UE_STATE_NB_IoT_e { + RRC_INACTIVE_NB_IoT=0, + RRC_IDLE_NB_IoT, + RRC_SI_RECEIVED_NB_IoT, + RRC_CONNECTED_NB_IoT, + RRC_RECONFIGURED_NB_IoT, + RRC_HO_EXECUTION_NB_IoT //maybe not needed? +} UE_STATE_NB_IoT_t; + + +/** @defgroup _rrc RRC + * @ingroup _oai2 + * @{ + */ +typedef struct UE_RRC_INFO_NB_IoT_s { + UE_STATE_NB_IoT_t State; + uint8_t SIB1systemInfoValueTag; + uint32_t SIStatus; + uint32_t SIcnt; +#if defined(Rel10) || defined(Rel14) + uint8_t MCCHStatus[8]; // MAX_MBSFN_AREA +#endif + uint8_t SIwindowsize; //!< Corresponds to the SIB1 si-WindowLength parameter. The unit is ms. Possible values are (final): 1,2,5,10,15,20,40 + uint8_t handoverTarget; + //HO_STATE_t ho_state; + uint16_t SIperiod; //!< Corresponds to the SIB1 si-Periodicity parameter (multiplied by 10). Possible values are (final): 80,160,320,640,1280,2560,5120 + unsigned short UE_index; + uint32_t T300_active; + uint32_t T300_cnt; + uint32_t T304_active; + uint32_t T304_cnt; + uint32_t T310_active; + uint32_t T310_cnt; + uint32_t N310_cnt; + uint32_t N311_cnt; + rnti_t rnti; +} __attribute__ ((__packed__)) UE_RRC_INFO_NB_IoT; + +//#define NUM_PRECONFIGURED_LCHAN (NB_CH_CX*2) //BCCH, CCCH + +#define UE_MODULE_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! +#define UE_INDEX_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! used to be -1 + + + +// HO_STATE is not supported by NB-IoT + +//#define NUMBER_OF_UE_MAX MAX_MOBILES_PER_RG +#define RRM_FREE(p) if ( (p) != NULL) { free(p) ; p=NULL ; } +#define RRM_MALLOC(t,n) (t *) malloc16( sizeof(t) * n ) +#define RRM_CALLOC(t,n) (t *) malloc16( sizeof(t) * n) +#define RRM_CALLOC2(t,s) (t *) malloc16( s ) + +//Measurement Report not supported in NB-IoT + +#define PAYLOAD_SIZE_MAX 1024 +#define RRC_BUF_SIZE 255 +#define UNDEF_SECURITY_MODE 0xff +#define NO_SECURITY_MODE 0x20 + +/* TS 36.331: RRC-TransactionIdentifier ::= INTEGER (0..3) */ +#define RRC_TRANSACTION_IDENTIFIER_NUMBER 3 + +typedef struct UE_S_TMSI_NB_IoT_s { + boolean_t presence; + mme_code_t mme_code; + m_tmsi_t m_tmsi; +} __attribute__ ((__packed__)) UE_S_TMSI_NB_IoT; + + +typedef enum e_rab_satus_NB_IoT_e { + E_RAB_STATUS_NEW_NB_IoT, + E_RAB_STATUS_DONE_NB_IoT, // from the eNB perspective + E_RAB_STATUS_ESTABLISHED_NB_IoT, // get the reconfigurationcomplete form UE + E_RAB_STATUS_FAILED_NB_IoT, +} e_rab_status_NB_IoT_t; + +typedef struct e_rab_param_NB_IoT_s { + e_rab_t param; + uint8_t status; + uint8_t xid; // transaction_id +} __attribute__ ((__packed__)) e_rab_param_NB_IoT_t; + + +//HANDOVER_INFO not implemented in NB-IoT delete + + +#define RRC_HEADER_SIZE_MAX 64 +#define RRC_BUFFER_SIZE_MAX 1024 + +typedef struct { + char Payload[RRC_BUFFER_SIZE_MAX]; + char Header[RRC_HEADER_SIZE_MAX]; + char payload_size; +} RRC_BUFFER_NB_IoT; + +#define RRC_BUFFER_SIZE_NB_IoT sizeof(RRC_BUFFER_NB_IoT) + + +typedef struct RB_INFO_NB_IoT_s { + uint16_t Rb_id; //=Lchan_id + //LCHAN_DESC Lchan_desc[2]; no more used + //MAC_MEAS_REQ_ENTRY *Meas_entry; //may not needed for NB-IoT +} RB_INFO_NB_IoT; + +typedef struct SRB_INFO_NB_IoT_s { + uint16_t Srb_id; //=Lchan_id---> useful for distinguish between SRB1 and SRB1bis? + RRC_BUFFER_NB_IoT Rx_buffer; + RRC_BUFFER_NB_IoT Tx_buffer; + //LCHAN_DESC Lchan_desc[2]; no more used + unsigned int Trans_id; + uint8_t Active; +} SRB_INFO_NB_IoT; + + +typedef struct RB_INFO_TABLE_ENTRY_NB_IoT_s { + RB_INFO_NB_IoT Rb_info; + uint8_t Active; + uint32_t Next_check_frame; + uint8_t Status; +} RB_INFO_TABLE_ENTRY_NB_IoT; + +typedef struct SRB_INFO_TABLE_ENTRY_NB_IoT_s { + SRB_INFO_NB_IoT Srb_info; + uint8_t Active; + uint8_t Status; + uint32_t Next_check_frame; +} SRB_INFO_TABLE_ENTRY_NB_IoT; + +//MEAS_REPORT_LIST_s not implemented in NB-IoT but is used at UE side +//HANDOVER_INFO_UE not implemented in NB-IoT +typedef struct HANDOVER_INFO_UE_NB_IoT_s { + PhysCellId_t targetCellId; + uint8_t measFlag; +} HANDOVER_INFO_UE_NB_IoT; + +//NB-IoT eNB_RRC_UE_NB_IoT_s--(used as a context in eNB --> ue_context in rrc_eNB_ue_context)------ +typedef struct eNB_RRC_UE_NB_IoT_s { + + EstablishmentCause_t establishment_cause; + uint8_t primaryCC_id; + //in NB-IoT only SRB0, SRB1 and SRB1bis (until AS security activation) exist + + /*MP: Concept behind List and List2 + * + * SRB_configList --> is used for the actual list of SRBs that is managed/that should be send over the RRC message + * SRB_configList2--> refers to all the SRBs configured for that specific transaction identifier + * this because in a single transaction one or more SRBs could be established + * and you want to keep memory on what happen for every transaction + * Transaction ID (xid): is used to associate the proper RRC....Complete message received by the UE to the corresponding + * message previously sent by the eNB (e.g. RRCConnectionSetup -- RRCConnectionSetupComplete) + * this because it could happen that more messages are transmitted at the same time + */ + SRB_ToAddModList_NB_r13_t* SRB_configList;//for SRB1 and SRB1bis + SRB_ToAddModList_NB_r13_t* SRB_configList2[RRC_TRANSACTION_IDENTIFIER_NUMBER]; + DRB_ToAddModList_NB_r13_t* DRB_configList; //for all the DRBs + DRB_ToAddModList_NB_r13_t* DRB_configList2[RRC_TRANSACTION_IDENTIFIER_NUMBER]; //for the configured DRBs of a xid + uint8_t DRB_active[2];//in LTE was 8 --> at most 2 for NB-IoT + + struct PhysicalConfigDedicated_NB_r13* physicalConfigDedicated_NB_IoT; + MAC_MainConfig_NB_r13_t* mac_MainConfig_NB_IoT; + + //No SPS(semi-persistent scheduling) in NB-IoT + //No Measurement report in NB-IoT + + SRB_INFO_NB_IoT SI; + SRB_INFO_NB_IoT Srb0; + SRB_INFO_TABLE_ENTRY_NB_IoT Srb1; + SRB_INFO_TABLE_ENTRY_NB_IoT Srb1bis; + +#if defined(ENABLE_SECURITY) + /* KeNB as derived from KASME received from EPC */ + uint8_t kenb[32]; +#endif + + /* Used integrity/ciphering algorithms--> maintained the same for NB-IoT */ + e_CipheringAlgorithm_r12 ciphering_algorithm; //Specs. TS 36.331 V14.1.0 pag 432 Change position of chipering enumerative w.r.t previous version + e_SecurityAlgorithmConfig__integrityProtAlgorithm integrity_algorithm; + + uint8_t Status; + rnti_t rnti; + uint64_t random_ue_identity; + + + + /* Information from UE RRC ConnectionRequest-NB-r13_IE--> NB-IoT */ + UE_S_TMSI_NB_IoT Initialue_identity_s_TMSI; + EstablishmentCause_NB_r13_t establishment_cause_NB_IoT; //different set for NB-IoT + + /* Information from UE RRC ConnectionReestablishmentRequest-NB--> NB-IoT */ + ReestablishmentCause_NB_r13_t reestablishment_cause_NB_IoT; //different set for NB_IoT + + /* UE id for initial connection to S1AP */ + uint16_t ue_initial_id; + + /* Information from S1AP initial_context_setup_req */ + uint32_t eNB_ue_s1ap_id :24; + + security_capabilities_t security_capabilities; + + /* Total number of e_rab already setup in the list */ //NAS list? + uint8_t setup_e_rabs; + /* Number of e_rab to be setup in the list */ //NAS list? + uint8_t nb_of_e_rabs; + /* list of e_rab to be setup by RRC layers */ + e_rab_param_NB_IoT_t e_rab[NB_RB_MAX_NB_IOT];//[S1AP_MAX_E_RAB]; + + // LG: For GTPV1 TUNNELS + uint32_t enb_gtp_teid[S1AP_MAX_E_RAB]; + transport_layer_addr_t enb_gtp_addrs[S1AP_MAX_E_RAB]; + rb_id_t enb_gtp_ebi[S1AP_MAX_E_RAB]; + + //Which timers are referring to? + uint32_t ul_failure_timer; + uint32_t ue_release_timer; + //threshold of the release timer--> set in RRCConnectionRelease + uint32_t ue_release_timer_thres; +} eNB_RRC_UE_NB_IoT_t; +//-------------------------------------------------------------------------------- + +typedef uid_NB_IoT_t ue_uid_t; + + +//generally variable called: ue_context_pP +typedef struct rrc_eNB_ue_context_NB_IoT_s { + + /* Tree related data */ + RB_ENTRY(rrc_eNB_ue_context_NB_IoT_s) entries; + + /* Uniquely identifies the UE between MME and eNB within the eNB. + * This id is encoded on 24bits. + */ + rnti_t ue_id_rnti; + + // another key for protocol layers but should not be used as a key for RB tree + ue_uid_t local_uid; + + /* UE id for initial connection to S1AP */ + struct eNB_RRC_UE_NB_IoT_s ue_context; //context of ue in the e-nB + +} rrc_eNB_ue_context_NB_IoT_t; + + + +//---NB-IoT (completely changed)------------------------------- +//called "carrier"--> data from PHY layer +typedef struct { + + // buffer that contains the encoded messages + uint8_t *MIB_NB_IoT; + uint8_t sizeof_MIB_NB_IoT; + + uint8_t *SIB1_NB_IoT; + uint8_t sizeof_SIB1_NB_IoT; + uint8_t *SIB23_NB_IoT; + uint8_t sizeof_SIB23_NB_IoT; + + + //not actually implemented in OAI + uint8_t *SIB4_NB_IoT; + uint8_t sizeof_SIB4_NB_IoT; + uint8_t *SIB5_NB_IoT; + uint8_t sizeof_SIB5_NB_IoT; + uint8_t *SIB14_NB_IoT; + uint8_t sizeof_SIB14_NB_IoT; + uint8_t *SIB16_NB_IoT; + uint8_t sizeof_SIB16_NB_IoT; + + //TS 36.331 V14.2.1 +// uint8_t *SIB15_NB; +// uint8_t sizeof_SIB15_NB; +// uint8_t *SIB20_NB; +// uint8_t sizeof_SIB20_NB; +// uint8_t *SIB22_NB; +// uint8_t sizeof_SIB22_NB; + + //implicit parameters needed + int Ncp; //cyclic prefix for DL + int Ncp_UL; //cyclic prefix for UL + int p_eNB; //number of tx antenna port + int p_rx_eNB; //number of receiving antenna ports + uint32_t dl_CarrierFreq; //detected by the UE + uint32_t ul_CarrierFreq; //detected by the UE + uint16_t physCellId; //not stored in the MIB-NB but is getting through NPSS/NSSS + + //are the only static one (memory has been already allocated) + BCCH_BCH_Message_NB_t mib_NB_IoT; + BCCH_DL_SCH_Message_NB_t siblock1_NB_IoT; //SIB1-NB + BCCH_DL_SCH_Message_NB_t systemInformation_NB_IoT; //SI + + SystemInformationBlockType1_NB_t *sib1_NB_IoT; + SystemInformationBlockType2_NB_r13_t *sib2_NB_IoT; + SystemInformationBlockType3_NB_r13_t *sib3_NB_IoT; + //not implemented yet + SystemInformationBlockType4_NB_r13_t *sib4_NB_IoT; + SystemInformationBlockType5_NB_r13_t *sib5_NB_IoT; + SystemInformationBlockType14_NB_r13_t *sib14_NB_IoT; + SystemInformationBlockType16_NB_r13_t *sib16_NB_IoT; + + + SRB_INFO_NB_IoT SI; + SRB_INFO_NB_IoT Srb0; + + uint8_t **MCCH_MESSAGE; // probably not needed , but added to remove errors + uint8_t sizeof_MCCH_MESSAGE[8];// but added to remove errors + SRB_INFO_NB_IoT MCCH_MESS[8];// MAX_MBSFN_AREA + /*future implementation TS 36.331 V14.2.1 + SystemInformationBlockType15_NB_r14_t *sib15; + SystemInformationBlockType20_NB_r14_t *sib20; + SystemInformationBlockType22_NB_r14_t *sib22; + + uint8_t SCPTM_flag; + uint8_t sizeof_SC_MCHH_MESS[]; + SC_MCCH_Message_NB_t scptm;*/ + + +} rrc_eNB_carrier_data_NB_IoT_t; +//--------------------------------------------------- + + + +//---NB-IoT---(completely change)--------------------- +typedef struct eNB_RRC_INST_NB_IoT_s { + + rrc_eNB_carrier_data_NB_IoT_t carrier[MAX_NUM_CCs]; + + uid_allocator_NB_IoT_t uid_allocator; // for rrc_ue_head + RB_HEAD(rrc_ue_tree_NB_IoT_s, rrc_eNB_ue_context_NB_IoT_s) rrc_ue_head; // ue_context tree key search by rnti + + uint8_t Nb_ue; + + hash_table_t *initial_id2_s1ap_ids; // key is content is rrc_ue_s1ap_ids_t + hash_table_t *s1ap_id2_s1ap_ids ; // key is content is rrc_ue_s1ap_ids_t + + //RRC configuration + RrcConfigurationReq configuration; //rrc_messages_types.h + + // other PLMN parameters + /// Mobile country code + int mcc; + /// Mobile network code + int mnc; + /// number of mnc digits + int mnc_digit_length; + + // other RAN parameters //FIXME: to be checked--> depends on APP layer + int srb1_timer_poll_retransmit; + int srb1_max_retx_threshold; + int srb1_timer_reordering; + int srb1_timer_status_prohibit; + int srs_enable[MAX_NUM_CCs]; + + +} eNB_RRC_INST_NB_IoT; + +#define RRC_HEADER_SIZE_MAX_NB_IoT 64 +#define MAX_UE_CAPABILITY_SIZE_NB_IoT 255 + +//not needed for the moment +typedef struct OAI_UECapability_NB_IoT_s { + uint8_t sdu[MAX_UE_CAPABILITY_SIZE_NB_IoT]; + uint8_t sdu_size; +////NB-IoT------ + UE_Capability_NB_r13_t UE_Capability_NB_IoT; //replace the UE_EUTRA_Capability of LTE +} OAI_UECapability_NB_IoT_t; + +#define RRC_BUFFER_SIZE_MAX_NB_IoT 1024 + + + +typedef struct UE_RRC_INST_NB_IoT_s { + Rrc_State_NB_IoT_t RrcState; + Rrc_Sub_State_NB_IoT_t RrcSubState; +# if defined(ENABLE_USE_MME) + plmn_t plmnID; + Byte_t rat; + as_nas_info_t initialNasMsg; +# endif + OAI_UECapability_NB_IoT_t *UECap; + uint8_t *UECapability; + uint8_t UECapability_size; + + UE_RRC_INFO_NB_IoT Info[NB_SIG_CNX_UE]; + + SRB_INFO_NB_IoT Srb0[NB_SIG_CNX_UE]; + SRB_INFO_TABLE_ENTRY_NB_IoT Srb1[NB_CNX_UE]; + SRB_INFO_TABLE_ENTRY_NB_IoT Srb2[NB_CNX_UE]; + HANDOVER_INFO_UE_NB_IoT HandoverInfoUe; + /* + uint8_t *SIB1[NB_CNX_UE]; + uint8_t sizeof_SIB1[NB_CNX_UE]; + uint8_t *SI[NB_CNX_UE]; + uint8_t sizeof_SI[NB_CNX_UE]; + uint8_t SIB1Status[NB_CNX_UE]; + uint8_t SIStatus[NB_CNX_UE]; + SystemInformationBlockType1_t *sib1[NB_CNX_UE]; + SystemInformation_t *si[NB_CNX_UE]; //!< Temporary storage for an SI message. Decoding happens in decode_SI(). + */ + SystemInformationBlockType2_t *sib2[NB_CNX_UE]; + /* + SystemInformationBlockType3_t *sib3[NB_CNX_UE]; + SystemInformationBlockType4_t *sib4[NB_CNX_UE]; + SystemInformationBlockType5_t *sib5[NB_CNX_UE]; + SystemInformationBlockType6_t *sib6[NB_CNX_UE]; + SystemInformationBlockType7_t *sib7[NB_CNX_UE]; + SystemInformationBlockType8_t *sib8[NB_CNX_UE]; + SystemInformationBlockType9_t *sib9[NB_CNX_UE]; + SystemInformationBlockType10_t *sib10[NB_CNX_UE]; + SystemInformationBlockType11_t *sib11[NB_CNX_UE]; + +#if defined(Rel10) || defined(Rel14) + uint8_t MBMS_flag; + uint8_t *MCCH_MESSAGE[NB_CNX_UE]; + uint8_t sizeof_MCCH_MESSAGE[NB_CNX_UE]; + uint8_t MCCH_MESSAGEStatus[NB_CNX_UE]; + MBSFNAreaConfiguration_r9_t *mcch_message[NB_CNX_UE]; + SystemInformationBlockType12_r9_t *sib12[NB_CNX_UE]; + SystemInformationBlockType13_r9_t *sib13[NB_CNX_UE]; +#endif +#ifdef CBA + uint8_t num_active_cba_groups; + uint16_t cba_rnti[NUM_MAX_CBA_GROUP]; +#endif + uint8_t num_srb; + struct SRB_ToAddMod *SRB1_config[NB_CNX_UE]; + struct SRB_ToAddMod *SRB2_config[NB_CNX_UE]; + struct DRB_ToAddMod *DRB_config[NB_CNX_UE][8]; + rb_id_t *defaultDRB; // remember the ID of the default DRB + MeasObjectToAddMod_t *MeasObj[NB_CNX_UE][MAX_MEAS_OBJ]; + struct ReportConfigToAddMod *ReportConfig[NB_CNX_UE][MAX_MEAS_CONFIG]; + */ + struct QuantityConfig *QuantityConfig[NB_CNX_UE]; + /* + struct MeasIdToAddMod *MeasId[NB_CNX_UE][MAX_MEAS_ID]; + MEAS_REPORT_LIST *measReportList[NB_CNX_UE][MAX_MEAS_ID]; + uint32_t measTimer[NB_CNX_UE][MAX_MEAS_ID][6]; // 6 neighboring cells + RSRP_Range_t s_measure; + struct MeasConfig__speedStatePars *speedStatePars; + struct PhysicalConfigDedicated *physicalConfigDedicated[NB_CNX_UE]; + struct SPS_Config *sps_Config[NB_CNX_UE]; + MAC_MainConfig_t *mac_MainConfig[NB_CNX_UE]; + MeasGapConfig_t *measGapConfig[NB_CNX_UE]; + double filter_coeff_rsrp; // [7] ??? + double filter_coeff_rsrq; // [7] ??? + float rsrp_db[7]; + float rsrq_db[7]; + float rsrp_db_filtered[7]; + float rsrq_db_filtered[7]; +#if ENABLE_RAL + obj_hash_table_t *ral_meas_thresholds; + ral_transaction_id_t scan_transaction_id; +#endif +#if defined(ENABLE_SECURITY) + // KeNB as computed from parameters within USIM card // + uint8_t kenb[32]; +#endif + + // Used integrity/ciphering algorithms // + CipheringAlgorithm_r12_t ciphering_algorithm; + e_SecurityAlgorithmConfig__integrityProtAlgorithm integrity_algorithm; + */ +} UE_RRC_INST_NB_IoT; + + +#include "proto_NB_IoT.h" //should be put here otherwise compilation error + +#endif +/** @} */ diff --git a/openair2/RRC/LITE/extern_NB_IoT.h b/openair2/RRC/LITE/extern_NB_IoT.h new file mode 100644 index 0000000000..23e7329aec --- /dev/null +++ b/openair2/RRC/LITE/extern_NB_IoT.h @@ -0,0 +1,63 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file vars.h +* \brief rrc external vars +* \author Navid Nikaein and Raymond Knopp, Michele Paffetti +* \date 2011-2017 +* \version 1.0 +* \company Eurecom +* \email: navid.nikaein@eurecom.fr, michele.paffetti@studio.unibo.it +*/ + +#ifndef __OPENAIR_RRC_EXTERN_NB_IOT_H__ +#define __OPENAIR_RRC_EXTERN_NB_IOT_H__ +#include "RRC/LITE/defs_NB_IoT.h" +#include "PHY_INTERFACE/IF_Module_NB_IoT.h" +#include "LAYER2/RLC/rlc.h" +#include "LogicalChannelConfig-NB-r13.h" +#include "LAYER2/MAC/defs_NB_IoT.h" + +#include "common/ran_context.h" + + +//MP: NOTE:XXX some of the parameters defined in vars_nb_iot are called by the extern.h file so not replicated here + +extern UE_RRC_INST_NB_IoT *UE_rrc_inst_NB_IoT; + +extern eNB_RRC_INST_NB_IoT *eNB_rrc_inst_NB_IoT; +extern PHY_Config_NB_IoT_t *config_INFO; + +extern rlc_info_t Rlc_info_am_NB_IoT,Rlc_info_am_config_NB_IoT; +extern uint8_t DRB2LCHAN_NB_IoT[2]; +extern LogicalChannelConfig_NB_r13_t SRB1bis_logicalChannelConfig_defaultValue_NB_IoT; +extern LogicalChannelConfig_NB_r13_t SRB1_logicalChannelConfig_defaultValue_NB_IoT; + +extern uint16_t T300_NB_IoT[8]; +extern uint16_t T301_NB_IoT[8]; +extern uint16_t T310_NB_IoT[8]; +extern uint16_t T311_NB_IoT[8]; +extern uint16_t N310_NB_IoT[8]; +extern uint16_t N311_NB_IoT[8]; +extern uint8_t *get_NB_IoT_MIB(struct eNB_RRC_INST_NB_IoT_s *nb_iot_rrc); +#endif + + diff --git a/openair2/RRC/LITE/proto.h b/openair2/RRC/LITE/proto.h index 49cf9f2eba..b920587419 100644 --- a/openair2/RRC/LITE/proto.h +++ b/openair2/RRC/LITE/proto.h @@ -410,6 +410,7 @@ rrc_data_req( ); uint8_t + rrc_data_req_ue( const protocol_ctxt_t* const ctxt_pP, const rb_id_t rb_idP, @@ -420,6 +421,7 @@ rrc_data_req_ue( const pdcp_transmission_mode_t modeP ); + void rrc_data_ind( const protocol_ctxt_t* const ctxt_pP, diff --git a/openair2/RRC/LITE/proto_NB_IoT.h b/openair2/RRC/LITE/proto_NB_IoT.h new file mode 100644 index 0000000000..b2f8e5b5c9 --- /dev/null +++ b/openair2/RRC/LITE/proto_NB_IoT.h @@ -0,0 +1,260 @@ +/* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file proto_NB_IoT.h + * \brief RRC functions prototypes for eNB and UE for NB-IoT + * \author Navid Nikaein, Raymond Knopp and Michele Paffetti + * \date 2010 - 2014 + * \email navid.nikaein@eurecom.fr, michele.paffetti@studio.unibo.it + * \version 1.0 + + */ +/** \addtogroup _rrc + * @{ + */ + +#include "RRC/LITE/defs_NB_IoT.h" +#include "pdcp.h" +#include "rlc.h" +#include "extern_NB_IoT.h" +#include "LAYER2/MAC/defs_NB_IoT.h" +/*NOTE: no static function should be declared in this header file (e.g. init_SI_NB)*/ + +/*------------------------common_nb_iot.c----------------------------------------*/ + +/** \brief configure BCCH & CCCH Logical Channels and associated rrc_buffers, configure associated SRBs + */ +void openair_rrc_on_NB_IoT(const protocol_ctxt_t* const ctxt_pP); + +void rrc_config_buffer_NB_IoT(SRB_INFO_NB_IoT *srb_info, uint8_t Lchan_type, uint8_t Role); + +int L3_xface_init_NB_IoT(void); + +void openair_rrc_top_init_eNB_NB_IoT(void); + +//void rrc_top_cleanup(void); -->seems not to be used + +//rrc_t310_expiration-->seems not to be used + +/** \brief Function to update timers every subframe. For UE it updates T300,T304 and T310. +@param ctxt_pP running context +@param enb_index +@param CC_id +*/ +RRC_status_t rrc_rx_tx_NB_IoT(protocol_ctxt_t* const ctxt_pP, const uint8_t enb_index, const int CC_id); + +//long binary_search_int(int elements[], long numElem, int value);--> seems not to be used +//long binary_search_float(float elements[], long numElem, float value);--> used only at UE side + + + +//--------------------------------------- + + +//defined in L2_interface +//called by rx_sdu only in case of CCCH message (e.g RRCConnectionRequest-NB) +int8_t mac_rrc_data_ind_eNB_NB_IoT( + const module_id_t module_idP, + const int CC_id, + const frame_t frameP, + const sub_frame_t sub_frameP, + const rnti_t rntiP, + const rb_id_t srb_idP,//could be skipped since always go through the CCCH channel + const uint8_t* sduP, + const sdu_size_t sdu_lenP +); +//------------------------------------------- + +//defined in L2_interface +void dump_ue_list_NB_IoT(UE_list_NB_IoT_t *listP, int ul_flag); +//------------------------------------------- + + +//defined in L2_interface +void mac_eNB_rrc_ul_failure_NB_IoT( + const module_id_t mod_idP, + const int CC_idP, + const frame_t frameP, + const sub_frame_t subframeP, + const rnti_t rntiP); +//------------------------------------------ + +//defined in eNB_scheduler_primitives.c +int rrc_mac_remove_ue_NB_IoT( + module_id_t mod_idP, + rnti_t rntiP); +//------------------------------------------ +//defined in L2_interface +void mac_eNB_rrc_ul_in_sync_NB_IoT( + const module_id_t mod_idP, + const int CC_idP, + const frame_t frameP, + const sub_frame_t subframeP, + const rnti_t rntiP); +//------------------------------------------ +//defined in L2_interface +int mac_eNB_get_rrc_status_NB_IoT( + const module_id_t Mod_idP, + const rnti_t rntiP +); +//--------------------------- + + +/*-----------eNB procedures (rrc_eNB_nb_iot.c)---------------*/ + +//---Initialization-------------- +void openair_eNB_rrc_on_NB_IoT( + const protocol_ctxt_t* const ctxt_pP +); + +void rrc_config_buffer_NB_IoT( + SRB_INFO_NB_IoT* Srb_info, + uint8_t Lchan_type, + uint8_t Role +); + +char openair_rrc_eNB_configuration_NB_IoT( + const module_id_t enb_mod_idP, + NbIoTRrcConfigurationReq* configuration +); + +//----------------------------- +/**\brief RRC eNB task. (starting of the RRC state machine) + \param void *args_p Pointer on arguments to start the task. */ +void *rrc_enb_task_NB_IoT(void *args_p); + +/**\brief Entry routine to decode a UL-CCCH-Message-NB. Invokes PER decoder and parses message. + \param ctxt_pP Running context + \param Srb_info Pointer to SRB0 information structure (buffer, etc.)*/ +int rrc_eNB_decode_ccch_NB_IoT( + protocol_ctxt_t* const ctxt_pP, + const SRB_INFO_NB_IoT* const Srb_info, + const int CC_id +); + +/**\brief Entry routine to decode a UL-DCCH-Message-NB. Invokes PER decoder and parses message. + \param ctxt_pP Context + \param Rx_sdu Pointer Received Message + \param sdu_size Size of incoming SDU*/ +int rrc_eNB_decode_dcch_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + const rb_id_t Srb_id, + const uint8_t* const Rx_sdu, + const sdu_size_t sdu_sizeP +); + +/**\brief Generate RRCConnectionReestablishmentReject-NB + \param ctxt_pP Running context + \param ue_context_pP UE context + \param CC_id Component Carrier ID*/ +void rrc_eNB_generate_RRCConnectionReestablishmentReject_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, + const int CC_id +); + +void rrc_eNB_generate_RRCConnectionReject_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, + const int CC_id +); + +void rrc_eNB_generate_RRCConnectionSetup_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, + const int CC_id +); + +void rrc_eNB_process_RRCConnectionReconfigurationComplete_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* ue_context_pP, + const uint8_t xid //transaction identifier +); + + +void //was under ITTI +rrc_eNB_reconfigure_DRBs_NB_IoT(const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* ue_context_pP); + +void //was under ITTI +rrc_eNB_generate_dedicatedRRCConnectionReconfiguration_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP +// const uint8_t ho_state + ); + +void rrc_eNB_process_RRCConnectionSetupComplete_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* ue_context_pP, + RRCConnectionSetupComplete_NB_r13_IEs_t * rrcConnectionSetupComplete_NB +); + +void rrc_eNB_generate_SecurityModeCommand_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP +); + +void rrc_eNB_generate_UECapabilityEnquiry_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP +); + +void rrc_eNB_generate_defaultRRCConnectionReconfiguration_NB_IoT(const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP + //no HO flag + ); + + +/// Utilities------------------------------------------------ + +void rrc_eNB_free_UE_NB_IoT( + const module_id_t enb_mod_idP, + const struct rrc_eNB_ue_context_NB_IoT_s* const ue_context_pP + ); + +void rrc_eNB_free_mem_UE_context_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + struct rrc_eNB_ue_context_NB_IoT_s* const ue_context_pP +); + + + +/**\brief Function to get the next transaction identifier. + \param module_idP Instance ID for CH/eNB + \return a transaction identifier*/ +uint8_t rrc_eNB_get_next_transaction_identifier_NB_IoT(module_id_t module_idP); + + +int rrc_init_global_param_NB_IoT(void); + +//L2_interface.c +int8_t mac_rrc_data_req_eNB_NB_IoT( + const module_id_t Mod_idP, + const int CC_id, + const frame_t frameP, + const frame_t h_frameP, + const sub_frame_t subframeP, //need for the case in which both SIB1-NB_IoT and SIB23-NB_IoT will be scheduled in the same frame + const rb_id_t Srb_id, + uint8_t* const buffer_pP, + uint8_t flag +); + + + diff --git a/openair2/RRC/LITE/rrc_types_NB_IoT.h b/openair2/RRC/LITE/rrc_types_NB_IoT.h new file mode 100644 index 0000000000..55e98ea5f1 --- /dev/null +++ b/openair2/RRC/LITE/rrc_types_NB_IoT.h @@ -0,0 +1,64 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file rrc_types.h +* \brief rrc types and subtypes +* \author Navid Nikaein and Raymond Knopp +* \date 2011 - 2014 +* \version 1.0 +* \company Eurecom +* \email: navid.nikaein@eurecom.fr, raymond.knopp@eurecom.fr +*/ + +#ifndef RRC_TYPES_NB_IOT_H_ +#define RRC_TYPES_NB_IOT_H_ + +typedef enum Rrc_State_NB_IoT_e { + RRC_STATE_INACTIVE_NB_IoT=0, + RRC_STATE_IDLE_NB_IoT, + RRC_STATE_CONNECTED_NB_IoT, + + RRC_STATE_FIRST_NB_IoT = RRC_STATE_INACTIVE_NB_IoT, + RRC_STATE_LAST_NB_IoT = RRC_STATE_CONNECTED_NB_IoT, +} Rrc_State_NB_IoT_t; + +typedef enum Rrc_Sub_State_NB_IoT_e { + RRC_SUB_STATE_INACTIVE_NB_IoT=0, + + RRC_SUB_STATE_IDLE_SEARCHING_NB_IoT, + RRC_SUB_STATE_IDLE_RECEIVING_SIB_NB_IoT, + RRC_SUB_STATE_IDLE_SIB_COMPLETE_NB_IoT, + RRC_SUB_STATE_IDLE_CONNECTING_NB_IoT, + RRC_SUB_STATE_IDLE_NB_IoT, + + RRC_SUB_STATE_CONNECTED_NB_IoT, + + RRC_SUB_STATE_INACTIVE_FIRST_NB_IoT = RRC_SUB_STATE_INACTIVE_NB_IoT, + RRC_SUB_STATE_INACTIVE_LAST_NB_IoT = RRC_SUB_STATE_INACTIVE_NB_IoT, + + RRC_SUB_STATE_IDLE_FIRST_NB_IoT = RRC_SUB_STATE_IDLE_SEARCHING_NB_IoT, + RRC_SUB_STATE_IDLE_LAST_NB_IoT = RRC_SUB_STATE_IDLE_NB_IoT, + + RRC_SUB_STATE_CONNECTED_FIRST_NB_IoT = RRC_SUB_STATE_CONNECTED_NB_IoT, + RRC_SUB_STATE_CONNECTED_LAST_NB_IoT = RRC_SUB_STATE_CONNECTED_NB_IoT, +} Rrc_Sub_State_NB_IoT_t; + +#endif /* RRC_TYPES_H_ */ diff --git a/openair3/GTPV1-U/gtpv1u_eNB.c b/openair3/GTPV1-U/gtpv1u_eNB.c index a2517e07b8..7f63e8c1ce 100644 --- a/openair3/GTPV1-U/gtpv1u_eNB.c +++ b/openair3/GTPV1-U/gtpv1u_eNB.c @@ -53,6 +53,7 @@ #undef GTP_DUMP_SOCKET +/* extern boolean_t pdcp_data_req( const protocol_ctxt_t* const ctxt_pP, const srb_flag_t srb_flagP, @@ -62,7 +63,7 @@ extern boolean_t pdcp_data_req( const sdu_size_t sdu_buffer_sizeP, unsigned char *const sdu_buffer_pP, const pdcp_transmission_mode_t modeP); - +*/ extern unsigned char NB_eNB_INST; extern RAN_CONTEXT_t RC; diff --git a/targets/COMMON/openairinterface5g_limits.h b/targets/COMMON/openairinterface5g_limits.h index 63f5b96c33..98de4a024f 100644 --- a/targets/COMMON/openairinterface5g_limits.h +++ b/targets/COMMON/openairinterface5g_limits.h @@ -11,7 +11,6 @@ # define NUMBER_OF_RU_MAX 32 # define NUMBER_OF_UE_MAX 20 # define NUMBER_OF_CONNECTED_eNB_MAX 3 - # if defined(STANDALONE) && STANDALONE==1 # undef NUMBER_OF_eNB_MAX # undef NUMBER_OF_UE_MAX diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 71ee86ecf1..6b52bab64c 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -100,7 +100,7 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "stats.h" #endif #include "lte-softmodem.h" - +#include "NB_IoT_interface.h" #ifdef XFORMS // current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0) // at eNB 0, an UL scope for every UE @@ -560,6 +560,14 @@ static void get_options(void) { NB_eNB_INST = RC.nb_inst; NB_RU = RC.nb_RU; printf("Configuration: nb_rrc_inst %d, nb_L1_inst %d, nb_ru %d\n",NB_eNB_INST,RC.nb_L1_inst,NB_RU); + if (nonbiotflag <= 0) { + load_NB_IoT(); + printf(" nb_nbiot_rrc_inst %d, nb_nbiot_L1_inst %d, nb_nbiot_macrlc_inst %d\n", + RC.nb_nb_iot_rrc_inst, RC.nb_nb_iot_L1_inst, RC.nb_nb_iot_macrlc_inst); + } else { + printf("All Nb-IoT instances disabled\n"); + RC.nb_nb_iot_rrc_inst=RC.nb_nb_iot_L1_inst=RC.nb_nb_iot_macrlc_inst=0; + } } } From 71e7f9713a9d410a249ad3097caa53128e1dc2d3 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 9 Mar 2018 10:11:24 +0100 Subject: [PATCH 282/284] hack: try to avoid "buffer full" problem when pushing DL traffic This is hack-level development. With this commit you can do UDP DL traffic of say 100Mb/s over a 5MHz link with one connected UE and the eNB should not crash because of memory exhaustion. Of course on the receiver side you won't get 100Mb/s and many many lost packets. But the system should not crash. 1Gb/s does not work. So in any case try to remain within some reasonable limits. There is no reason to push more than twice the maximum achievable throughput of the link. This work is based on a patch proposed by Francesco Gringoli. --- common/utils/itti/intertask_interface.c | 97 +++++++++++++++++++++++++ common/utils/itti/intertask_interface.h | 12 +++ openair2/LAYER2/RLC/rlc.c | 9 +++ openair3/UDP/udp_eNB_task.c | 13 +++- 4 files changed, 130 insertions(+), 1 deletion(-) diff --git a/common/utils/itti/intertask_interface.c b/common/utils/itti/intertask_interface.c index 554f50a2a1..85b5fef509 100644 --- a/common/utils/itti/intertask_interface.c +++ b/common/utils/itti/intertask_interface.c @@ -391,6 +391,103 @@ int itti_send_msg_to_task(task_id_t destination_task_id, instance_t instance, Me return 0; } +/* same as itti_send_msg_to_task but returns -1 in case of failure instead of crashing */ +/* TODO: this is a hack - the whole logic needs a proper rework. */ +/* look for HACK_RLC_UM_LIMIT for others places related to the hack. Please do not remove this comment. */ +int itti_try_send_msg_to_task(task_id_t destination_task_id, instance_t instance, MessageDef *message) +{ + thread_id_t destination_thread_id; + task_id_t origin_task_id; + message_list_t *new; + uint32_t priority; + message_number_t message_number; + uint32_t message_id; + + AssertFatal (message != NULL, "Message is NULL!\n"); + AssertFatal (destination_task_id < itti_desc.task_max, "Destination task id (%d) is out of range (%d)\n", destination_task_id, itti_desc.task_max); + + destination_thread_id = TASK_GET_THREAD_ID(destination_task_id); + message->ittiMsgHeader.destinationTaskId = destination_task_id; + message->ittiMsgHeader.instance = instance; + message->ittiMsgHeader.lte_time.frame = itti_desc.lte_time.frame; + message->ittiMsgHeader.lte_time.slot = itti_desc.lte_time.slot; + message_id = message->ittiMsgHeader.messageId; + AssertFatal (message_id < itti_desc.messages_id_max, "Message id (%d) is out of range (%d)!\n", message_id, itti_desc.messages_id_max); + + origin_task_id = ITTI_MSG_ORIGIN_ID(message); + + priority = itti_get_message_priority (message_id); + + /* Increment the global message number */ + message_number = itti_increment_message_number (); + + itti_dump_queue_message (origin_task_id, message_number, message, itti_desc.messages_info[message_id].name, + sizeof(MessageHeader) + message->ittiMsgHeader.ittiMsgSize); + + if (destination_task_id != TASK_UNKNOWN) { + + if (itti_desc.threads[destination_thread_id].task_state == TASK_STATE_ENDED) { + ITTI_DEBUG(ITTI_DEBUG_ISSUES, " Message %s, number %lu with priority %d can not be sent from %s to queue (%u:%s), ended destination task!\n", + itti_desc.messages_info[message_id].name, + message_number, + priority, + itti_get_task_name(origin_task_id), + destination_task_id, + itti_get_task_name(destination_task_id)); + } else { + /* We cannot send a message if the task is not running */ + AssertFatal (itti_desc.threads[destination_thread_id].task_state == TASK_STATE_READY, + "Task %s Cannot send message %s (%d) to thread %d, it is not in ready state (%d)!\n", + itti_get_task_name(origin_task_id), + itti_desc.messages_info[message_id].name, + message_id, + destination_thread_id, + itti_desc.threads[destination_thread_id].task_state); + + /* Allocate new list element */ + new = (message_list_t *) itti_malloc (origin_task_id, destination_task_id, sizeof(struct message_list_s)); + + /* Fill in members */ + new->msg = message; + new->message_number = message_number; + new->message_priority = priority; + + /* Enqueue message in destination task queue */ + if (lfds611_queue_enqueue(itti_desc.tasks[destination_task_id].message_queue, new) == 0) { + itti_free(origin_task_id, new); + return -1; + } + + { + /* Only use event fd for tasks, subtasks will pool the queue */ + if (TASK_GET_PARENT_TASK_ID(destination_task_id) == TASK_UNKNOWN) { + ssize_t write_ret; + eventfd_t sem_counter = 1; + + /* Call to write for an event fd must be of 8 bytes */ + write_ret = write (itti_desc.threads[destination_thread_id].task_event_fd, &sem_counter, sizeof(sem_counter)); + AssertFatal (write_ret == sizeof(sem_counter), "Write to task message FD (%d) failed (%d/%d)\n", + destination_thread_id, (int) write_ret, (int) sizeof(sem_counter)); + } + } + + ITTI_DEBUG(ITTI_DEBUG_SEND, " Message %s, number %lu with priority %d successfully sent from %s to queue (%u:%s)\n", + itti_desc.messages_info[message_id].name, + message_number, + priority, + itti_get_task_name(origin_task_id), + destination_task_id, + itti_get_task_name(destination_task_id)); + } + } else { + /* This is a debug message to TASK_UNKNOWN, we can release safely release it */ + int result = itti_free(origin_task_id, message); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } + + return 0; +} + void itti_subscribe_event_fd(task_id_t task_id, int fd) { thread_id_t thread_id; diff --git a/common/utils/itti/intertask_interface.h b/common/utils/itti/intertask_interface.h index 606c851d1d..ada34ce1b7 100644 --- a/common/utils/itti/intertask_interface.h +++ b/common/utils/itti/intertask_interface.h @@ -108,6 +108,18 @@ int itti_send_broadcast_message(MessageDef *message_p); **/ int itti_send_msg_to_task(task_id_t task_id, instance_t instance, MessageDef *message); +/* TODO: this is a hack. Almost no caller of itti_send_msg_to_task checks + * the return value so it has been changed to crash the program in case + * of failure instead of returning -1 as the documentation above says. + * The RLC UM code may receive too much data when doing UDP at a higher + * throughput than the link allows and so for this specific case we need + * a version that actually returns -1 on failure. + * + * This needs to be cleaned at some point. + */ +/* look for HACK_RLC_UM_LIMIT for others places related to the hack. Please do not remove this comment. */ +int itti_try_send_msg_to_task(task_id_t task_id, instance_t instance, MessageDef *message); + /** \brief Add a new fd to monitor. * NOTE: it is up to the user to read data associated with the fd * \param task_id Task ID of the receiving task diff --git a/openair2/LAYER2/RLC/rlc.c b/openair2/LAYER2/RLC/rlc.c index d27d46ff42..783441bd58 100644 --- a/openair2/LAYER2/RLC/rlc.c +++ b/openair2/LAYER2/RLC/rlc.c @@ -437,6 +437,15 @@ rlc_op_status_t rlc_data_req (const protocol_ctxt_t* const ctxt_pP, break; case RLC_MODE_UM: + /* TODO: this is a hack, needs better solution. Let's not use too + * much memory and store at maximum 5 millions bytes. + */ + /* look for HACK_RLC_UM_LIMIT for others places related to the hack. Please do not remove this comment. */ + if (rlc_um_get_buffer_occupancy(&rlc_union_p->rlc.um) > 5000000) { + free_mem_block(sdu_pP, __func__); + return RLC_OP_STATUS_OUT_OF_RESSOURCES; + } + new_sdu_p = get_free_mem_block (sdu_sizeP + sizeof (struct rlc_um_data_req_alloc), __func__); if (new_sdu_p != NULL) { diff --git a/openair3/UDP/udp_eNB_task.c b/openair3/UDP/udp_eNB_task.c index 527715eb7a..4d6bd6e033 100644 --- a/openair3/UDP/udp_eNB_task.c +++ b/openair3/UDP/udp_eNB_task.c @@ -270,10 +270,21 @@ void udp_eNB_receiver(struct udp_socket_desc_s *udp_sock_pP) n, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); #endif - if (itti_send_msg_to_task(udp_sock_pP->task_id, INSTANCE_DEFAULT, message_p) < 0) { + /* TODO: this is a hack. Let's accept failures and do nothing when + * it happens. Since itti_send_msg_to_task crashes when the message + * queue is full we wrote itti_try_send_msg_to_task that returns -1 + * if the queue is full. + */ + /* look for HACK_RLC_UM_LIMIT for others places related to the hack. Please do not remove this comment. */ + //if (itti_send_msg_to_task(udp_sock_pP->task_id, INSTANCE_DEFAULT, message_p) < 0) { + if (itti_try_send_msg_to_task(udp_sock_pP->task_id, INSTANCE_DEFAULT, message_p) < 0) { +#if 0 LOG_I(UDP_, "Failed to send message %d to task %d\n", UDP_DATA_IND, udp_sock_pP->task_id); +#endif + itti_free(TASK_UDP, message_p); + itti_free(TASK_UDP, forwarded_buffer); return; } } From 92bb82eb2b25bba91f5df88176ffb2534e38f199 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 9 Mar 2018 16:40:09 +0100 Subject: [PATCH 283/284] integration fix: fix license version to 1.1 --- common/config/config_cmdline.c | 2 +- common/config/config_load_configmodule.c | 2 +- common/config/libconfig/config_libconfig.h | 2 +- common/config/libconfig/config_libconfig_private.h | 2 +- common/ran_context.h | 2 +- common/utils/load_module_shlib.c | 2 +- common/utils/load_module_shlib.h | 2 +- common/utils/telnetsrv/telnetsrv_phycmd.c | 2 +- common/utils/telnetsrv/telnetsrv_phycmd.h | 2 +- openair1/PHY/CODING/coding_load.c | 2 +- openair1/PHY/CODING/defs_NB_IoT.h | 2 +- openair1/PHY/INIT/defs_NB_IoT.h | 2 +- openair1/PHY/LTE_TRANSPORT/dci_NB_IoT.h | 2 +- openair1/PHY/LTE_TRANSPORT/edci.c | 2 +- openair1/PHY/LTE_TRANSPORT/mdci.h | 2 +- openair1/PHY/LTE_TRANSPORT/proto_NB_IoT.h | 2 +- openair1/PHY/LTE_TRANSPORT/uci_NB_IoT.h | 2 +- openair1/PHY/defs_L1_NB_IoT.h | 2 +- openair1/PHY/impl_defs_lte_NB_IoT.h | 2 +- openair1/PHY/impl_defs_top_NB_IoT.h | 2 +- openair1/PHY/types_NB_IoT.h | 2 +- openair1/SCHED/fapi_l1.c | 2 +- openair1/SCHED/fapi_l1.h | 2 +- openair1/SCHED/ru_procedures.c | 2 +- openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c | 2 +- openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h | 2 +- openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp_defs.h | 2 +- openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c | 2 +- openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h | 2 +- openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h | 2 +- openair2/ENB_APP/L1_paramdef.h | 2 +- openair2/ENB_APP/MACRLC_paramdef.h | 2 +- openair2/ENB_APP/NB_IoT_paramdef.h | 2 +- openair2/ENB_APP/RRC_paramsvalues.h | 2 +- openair2/ENB_APP/enb_paramdef.h | 2 +- openair2/ENB_APP/flexran_agent_ran_api.c | 2 +- openair2/ENB_APP/flexran_agent_ran_api.h | 2 +- openair2/ENB_APP/flexran_agent_timer.c | 2 +- openair2/ENB_APP/flexran_agent_timer.h | 2 +- openair2/LAYER2/MAC/proto_NB_IoT.h | 2 +- openair2/PHY_INTERFACE/IF_Module.h | 2 +- openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c | 2 +- openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h | 2 +- openair2/RRC/LITE/defs_NB_IoT.h | 2 +- openair2/RRC/LITE/extern_NB_IoT.h | 2 +- openair2/RRC/LITE/proto_NB_IoT.h | 2 +- openair2/RRC/LITE/rrc_types_NB_IoT.h | 2 +- 47 files changed, 47 insertions(+), 47 deletions(-) diff --git a/common/config/config_cmdline.c b/common/config/config_cmdline.c index cb24cc5222..040cd92faf 100644 --- a/common/config/config_cmdline.c +++ b/common/config/config_cmdline.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/config/config_load_configmodule.c b/common/config/config_load_configmodule.c index c31a2da4d7..7860742804 100644 --- a/common/config/config_load_configmodule.c +++ b/common/config/config_load_configmodule.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/config/libconfig/config_libconfig.h b/common/config/libconfig/config_libconfig.h index 8013d602cf..f541584185 100644 --- a/common/config/libconfig/config_libconfig.h +++ b/common/config/libconfig/config_libconfig.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/config/libconfig/config_libconfig_private.h b/common/config/libconfig/config_libconfig_private.h index 022e0e6330..fb126ff7cb 100644 --- a/common/config/libconfig/config_libconfig_private.h +++ b/common/config/libconfig/config_libconfig_private.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/ran_context.h b/common/ran_context.h index 18b309d268..4380dc65f1 100644 --- a/common/ran_context.h +++ b/common/ran_context.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/load_module_shlib.c b/common/utils/load_module_shlib.c index c07b54f54a..fecdc2a58c 100644 --- a/common/utils/load_module_shlib.c +++ b/common/utils/load_module_shlib.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/load_module_shlib.h b/common/utils/load_module_shlib.h index 2653bdeba5..ffbad66570 100644 --- a/common/utils/load_module_shlib.h +++ b/common/utils/load_module_shlib.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/telnetsrv/telnetsrv_phycmd.c b/common/utils/telnetsrv/telnetsrv_phycmd.c index a69efa234c..c60126f1c7 100644 --- a/common/utils/telnetsrv/telnetsrv_phycmd.c +++ b/common/utils/telnetsrv/telnetsrv_phycmd.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/common/utils/telnetsrv/telnetsrv_phycmd.h b/common/utils/telnetsrv/telnetsrv_phycmd.h index 50f1e81edc..6e2b0ecacf 100644 --- a/common/utils/telnetsrv/telnetsrv_phycmd.h +++ b/common/utils/telnetsrv/telnetsrv_phycmd.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/coding_load.c b/openair1/PHY/CODING/coding_load.c index 6e4670dd8e..31f71e6b31 100644 --- a/openair1/PHY/CODING/coding_load.c +++ b/openair1/PHY/CODING/coding_load.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/CODING/defs_NB_IoT.h b/openair1/PHY/CODING/defs_NB_IoT.h index 17670ec8bc..2a6bee7924 100644 --- a/openair1/PHY/CODING/defs_NB_IoT.h +++ b/openair1/PHY/CODING/defs_NB_IoT.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/INIT/defs_NB_IoT.h b/openair1/PHY/INIT/defs_NB_IoT.h index e8ead21780..8a83cbd038 100644 --- a/openair1/PHY/INIT/defs_NB_IoT.h +++ b/openair1/PHY/INIT/defs_NB_IoT.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/dci_NB_IoT.h b/openair1/PHY/LTE_TRANSPORT/dci_NB_IoT.h index ea84f66de4..60720e13b7 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_NB_IoT.h +++ b/openair1/PHY/LTE_TRANSPORT/dci_NB_IoT.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/edci.c b/openair1/PHY/LTE_TRANSPORT/edci.c index 37b1c56349..5caf5bcd71 100755 --- a/openair1/PHY/LTE_TRANSPORT/edci.c +++ b/openair1/PHY/LTE_TRANSPORT/edci.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/mdci.h b/openair1/PHY/LTE_TRANSPORT/mdci.h index 1e278f8011..060227eac0 100644 --- a/openair1/PHY/LTE_TRANSPORT/mdci.h +++ b/openair1/PHY/LTE_TRANSPORT/mdci.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/proto_NB_IoT.h b/openair1/PHY/LTE_TRANSPORT/proto_NB_IoT.h index 9e3a55eacc..d8b17ff263 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto_NB_IoT.h +++ b/openair1/PHY/LTE_TRANSPORT/proto_NB_IoT.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/LTE_TRANSPORT/uci_NB_IoT.h b/openair1/PHY/LTE_TRANSPORT/uci_NB_IoT.h index b20635360d..6f2dd0f989 100644 --- a/openair1/PHY/LTE_TRANSPORT/uci_NB_IoT.h +++ b/openair1/PHY/LTE_TRANSPORT/uci_NB_IoT.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/defs_L1_NB_IoT.h b/openair1/PHY/defs_L1_NB_IoT.h index b9368b76e3..25ee646548 100644 --- a/openair1/PHY/defs_L1_NB_IoT.h +++ b/openair1/PHY/defs_L1_NB_IoT.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/impl_defs_lte_NB_IoT.h b/openair1/PHY/impl_defs_lte_NB_IoT.h index 7ae6f59c7e..1167323174 100644 --- a/openair1/PHY/impl_defs_lte_NB_IoT.h +++ b/openair1/PHY/impl_defs_lte_NB_IoT.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/impl_defs_top_NB_IoT.h b/openair1/PHY/impl_defs_top_NB_IoT.h index e512ec0215..f7e0c7ff7f 100644 --- a/openair1/PHY/impl_defs_top_NB_IoT.h +++ b/openair1/PHY/impl_defs_top_NB_IoT.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/PHY/types_NB_IoT.h b/openair1/PHY/types_NB_IoT.h index e8a6ea501e..6735092583 100644 --- a/openair1/PHY/types_NB_IoT.h +++ b/openair1/PHY/types_NB_IoT.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c index dbefe62747..df01fad136 100644 --- a/openair1/SCHED/fapi_l1.c +++ b/openair1/SCHED/fapi_l1.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/fapi_l1.h b/openair1/SCHED/fapi_l1.h index 725bb31c45..f04e8581db 100644 --- a/openair1/SCHED/fapi_l1.h +++ b/openair1/SCHED/fapi_l1.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair1/SCHED/ru_procedures.c b/openair1/SCHED/ru_procedures.c index b00a9e2039..534023632c 100644 --- a/openair1/SCHED/ru_procedures.c +++ b/openair1/SCHED/ru_procedures.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c index 25ec919127..43455fa32a 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c +++ b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h index a962390c00..83aac45406 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h +++ b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp_defs.h b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp_defs.h index 46bdf744de..f2da72545a 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/PDCP/flexran_agent_pdcp_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c index e88c4eaccf..43951ee95a 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h index ae26b41621..780976893e 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h index cf20c477de..8c336abef1 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/L1_paramdef.h b/openair2/ENB_APP/L1_paramdef.h index 8eef55b718..b062235ff6 100644 --- a/openair2/ENB_APP/L1_paramdef.h +++ b/openair2/ENB_APP/L1_paramdef.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/MACRLC_paramdef.h b/openair2/ENB_APP/MACRLC_paramdef.h index 868917a0ab..4e732fe942 100644 --- a/openair2/ENB_APP/MACRLC_paramdef.h +++ b/openair2/ENB_APP/MACRLC_paramdef.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/NB_IoT_paramdef.h b/openair2/ENB_APP/NB_IoT_paramdef.h index 615c96a7b6..6409fe63ee 100644 --- a/openair2/ENB_APP/NB_IoT_paramdef.h +++ b/openair2/ENB_APP/NB_IoT_paramdef.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/RRC_paramsvalues.h b/openair2/ENB_APP/RRC_paramsvalues.h index fb375e1a09..06fee0e172 100644 --- a/openair2/ENB_APP/RRC_paramsvalues.h +++ b/openair2/ENB_APP/RRC_paramsvalues.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/enb_paramdef.h b/openair2/ENB_APP/enb_paramdef.h index d2634b3947..a8379c259f 100755 --- a/openair2/ENB_APP/enb_paramdef.h +++ b/openair2/ENB_APP/enb_paramdef.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index a65d352392..3200f55f16 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h index 0550722394..4e5f214af0 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.h +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_timer.c b/openair2/ENB_APP/flexran_agent_timer.c index f5436e4d01..dda3027353 100644 --- a/openair2/ENB_APP/flexran_agent_timer.c +++ b/openair2/ENB_APP/flexran_agent_timer.c @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/ENB_APP/flexran_agent_timer.h b/openair2/ENB_APP/flexran_agent_timer.h index 86e0d07825..98d83c78a9 100644 --- a/openair2/ENB_APP/flexran_agent_timer.h +++ b/openair2/ENB_APP/flexran_agent_timer.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/LAYER2/MAC/proto_NB_IoT.h b/openair2/LAYER2/MAC/proto_NB_IoT.h index e493275987..6e6d98eba1 100644 --- a/openair2/LAYER2/MAC/proto_NB_IoT.h +++ b/openair2/LAYER2/MAC/proto_NB_IoT.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/PHY_INTERFACE/IF_Module.h b/openair2/PHY_INTERFACE/IF_Module.h index 7baae6c3b6..3b1c88dda0 100644 --- a/openair2/PHY_INTERFACE/IF_Module.h +++ b/openair2/PHY_INTERFACE/IF_Module.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c b/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c index 866b2c1e91..80dcfd4053 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c @@ -2,7 +2,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h b/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h index 67e0919307..e88bdadbd9 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/defs_NB_IoT.h b/openair2/RRC/LITE/defs_NB_IoT.h index 98b9148cd2..a5fdbb702e 100644 --- a/openair2/RRC/LITE/defs_NB_IoT.h +++ b/openair2/RRC/LITE/defs_NB_IoT.h @@ -2,7 +2,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/extern_NB_IoT.h b/openair2/RRC/LITE/extern_NB_IoT.h index 23e7329aec..39b49ecc03 100644 --- a/openair2/RRC/LITE/extern_NB_IoT.h +++ b/openair2/RRC/LITE/extern_NB_IoT.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/proto_NB_IoT.h b/openair2/RRC/LITE/proto_NB_IoT.h index b2f8e5b5c9..e346204912 100644 --- a/openair2/RRC/LITE/proto_NB_IoT.h +++ b/openair2/RRC/LITE/proto_NB_IoT.h @@ -2,7 +2,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * diff --git a/openair2/RRC/LITE/rrc_types_NB_IoT.h b/openair2/RRC/LITE/rrc_types_NB_IoT.h index 55e98ea5f1..0266572cd0 100644 --- a/openair2/RRC/LITE/rrc_types_NB_IoT.h +++ b/openair2/RRC/LITE/rrc_types_NB_IoT.h @@ -3,7 +3,7 @@ * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * From e7cfe377db29ef7cbeda1e8e8ef0a39ba1368035 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 9 Mar 2018 16:43:08 +0100 Subject: [PATCH 284/284] integration fix: fix file format (dos2unix) End of line character has to be unix-style, not dos-style. --- openair2/LAYER2/MAC/defs_NB_IoT.h | 1086 +++---- openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c | 2834 +++++++++--------- openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h | 586 ++-- openair2/RRC/LITE/defs_NB_IoT.h | 1140 +++---- openair2/RRC/LITE/extern_NB_IoT.h | 124 +- openair2/RRC/LITE/proto_NB_IoT.h | 520 ++-- 6 files changed, 3145 insertions(+), 3145 deletions(-) diff --git a/openair2/LAYER2/MAC/defs_NB_IoT.h b/openair2/LAYER2/MAC/defs_NB_IoT.h index a427de5b2c..77c0828b28 100644 --- a/openair2/LAYER2/MAC/defs_NB_IoT.h +++ b/openair2/LAYER2/MAC/defs_NB_IoT.h @@ -1,543 +1,543 @@ - -/*! \file defs_NB_IoT.c - * \brief MAC layer structures - * \author NTUST BMW Lab./ - * \date 2017 - * \email: - * \version 1.0 - * - */ -#ifndef __LAYER2_MAC_DEFS_NB_IOT_H__ -#define __LAYER2_MAC_DEFS_NB_IOT_H__ -#ifdef USER_MODE -#include -#include -#include -#endif -//#include "COMMON/openair_defs.h" -#include "COMMON/platform_constants.h" -#include "COMMON/mac_rrc_primitives.h" -#include "PHY/LTE_TRANSPORT/defs_NB_IoT.h" -//#include "PHY/defs.h" -#include "PHY/defs_L1_NB_IoT.h" -#include "openair2/PHY_INTERFACE/IF_Module_NB_IoT.h" -#include "config_NB_IoT.h" -// MAC definition -#define MAX_FRAME 0xfffff -#define NUM_FRAME 0x100000 -#define MAX_SUBFRAME 10485760 - -#define MAX(a, b) (((a)>(b))?(a):(b)) - -// RA-RNTI: 1+SFN_id>>2 -#define RA_RNTI_LOW 0x0001 // SFN_id = 0 -#define RA_RNTI_HIGH 0x0100 // SFN_id = 1023 -#define C_RNTI_LOW 0x0101 -#define C_RNTI_HIGH - -// ULSCH LCHAN IDs -/*!\brief LCID of extended power headroom for ULSCH */ -#define EXTENDED_POWER_HEADROOM 25 -/*!\brief LCID of power headroom for ULSCH */ -#define POWER_HEADROOM 26 -/*!\brief LCID of CRNTI for ULSCH */ -#define CRNTI 27 -/*!\brief LCID of truncated BSR for ULSCH */ -#define TRUNCATED_BSR 28 -/*!\brief LCID of short BSR for ULSCH */ -#define SHORT_BSR 29 -/*!\brief LCID of long BSR for ULSCH */ -#define LONG_BSR 30 -/*! \brief Values of CCCH LCID for DLSCH */ -#define CCCH_LCHANID 0 -/*!\brief Values of BCCH logical channel */ -#define BCCH 3 // SI -/*!\brief Values of PCCH logical channel */ -#define PCCH 4 // Paging -/*!\brief Value of CCCH / SRB0 logical channel */ -#define CCCH 0 // srb0 -/*!\brief DCCH / SRB1 logical channel */ -#define DCCH 1 // srb1 -/*!\brief DCCH1 / SRB2 logical channel */ -#define DCCH1 2 // srb2 -/*!\brief DTCH DRB1 logical channel */ -#define DTCH 3 // LCID -/*!\brief MCCH logical channel */ -#define MCCH 4 -/*!\brief MTCH logical channel */ -#define MTCH 1 -// DLSCH LCHAN ID -/*!\brief LCID of UE contention resolution identity for DLSCH*/ -#define UE_CONT_RES 28 -/*!\brief LCID of timing advance for DLSCH */ -#define TIMING_ADV_CMD 29 -/*!\brief LCID of discontinous reception mode for DLSCH */ -#define DRX_CMD 30 -/*!\brief LCID of padding LCID for DLSCH */ -#define SHORT_PADDING 31 - - -typedef enum tone_type_e -{ - sixtone = 0, - threetone, - singletone1, - singletone2, - singletone3 -}tone_type_t; - -typedef enum channel_NB_IoT_e -{ - NPDCCH = 0, - NPUSCH, - NPDSCH -}channel_NB_IoT_t; - -typedef enum{ - UL = 0, - DL -}message_direction_t; - -#define MAX_NUMBER_OF_UE_MAX_NB_IoT 20 -#define SCH_PAYLOAD_SIZE_MAX_NB_IoT 320 -#define MAX_NUMBER_OF_SIBs_NB_IoT 16 - -/*!\brief Values of BCCH0 logical channel for MIB*/ -#define BCCH0_NB_IoT 11 // MIB-NB_IoT -/*!\brief Values of BCCH1 logical channel for SIBs */ -#define BCCH1_NB_IoT 12 // SI-SIB-NB_IoTs -/*!\brief Values of PCCH logical channel */ -#define PCCH_NB_IoT 13 // Paging XXX not used for the moment -#define MCCH_NB_IoT 14 -/*!\brief Value of CCCH / SRB0 logical channel */ -#define CCCH_NB_IoT 0 // srb0 ---> XXX exactly the same as in LTE (commented for compilation purposes) -/*!\brief DCCH0 / SRB1bis logical channel */ -#define DCCH0_NB_IoT 3 // srb1bis -/*!\brief DCCH1 / SRB1 logical channel */ -#define DCCH1_NB_IoT 1 // srb1 //XXX we redefine it for the SRB1 -/*!\brief DTCH0 DRB0 logical channel */ -#define DTCH0_NB_IoT 4 // DRB0 -/*!\brief DTCH1 DRB1 logical channel */ -#define DTCH1_NB_IoT 5 // DRB1 -/*Index of UE contention resoulution logical channel*/ -#define UE_CONTENTION_RESOLUTION 28 -/*Index of TIMING_ADVANCE logical channel*/ -#define TIMING_ADVANCE 29 -/*Index of DRX_COMMAND logical channel*/ -#define DRX_COMMAND 30 -/*Index of PADDING logical channel*/ -#define PADDING 31 - - -/// NPRACH-ParametersList-NB_IoT-r13 from 36.331 RRC spec defined in PHY -/*typedef struct NPRACH_Parameters_NB_IoT{ - - /// the period time for nprach - int nprach_Periodicity; - /// for the start time for the NPRACH resource from 40ms-2560ms - int nprach_StartTime; - /// for the subcarrier of set to the NPRACH preamble from n0 - n34 - int nprach_SubcarrierOffset; - ///number of subcarriers in a NPRACH resource allowed values (n12,n24,n36,n48) - int nprach_NumSubcarriers; - /// where is the region that in NPRACH resource to indicate if this UE support MSG3 for multi-tone or not. from 0 - 1 - int nprach_SubcarrierMSG3_RangeStart; - /// The max preamble transmission attempt for the CE level from 1 - 128 - int maxNumPreambleAttemptCE; - /// Number of NPRACH repetitions per attempt for each NPRACH resource - int numRepetitionsPerPreambleAttempt; - /// The number of the repetition for DCI use in RAR/MSG3/MSG4 from 1 - 2048 (Rmax) - int npdcch_NumRepetitions_RA; - /// Starting subframe for NPDCCH Common searching space for (RAR/MSG3/MSG4) - int npdcch_StartSF_CSS_RA; - /// Fractional period offset of starting subframe for NPDCCH common search space - int npdcch_Offset_RA; - -} nprach_parameters_NB_IoT_t;*/ - -/*! \brief Downlink SCH PDU Structure */ -typedef struct { - uint8_t payload[SCH_PAYLOAD_SIZE_MAX_NB_IoT]; - uint32_t pdu_size; -} __attribute__ ((__packed__)) DLSCH_PDU_NB_IoT; - -/*! \brief eNB template for UE context information */ -typedef struct { - // C-RNTI of UE - rnti_t rnti; - // UE CE level - int CE_level; - // Direction of transmission(DL:0\UL:1\NONE:-1) - int32_t direction; - // DCI Reptition - uint32_t R_dci; - // MAX repetition - uint32_t R_max; - - // HARQ round - uint32_t HARQ_round; - /*Downlink information*/ - - /// DLSCH pdu - DLSCH_PDU_NB_IoT DLSCH_pdu; - // PDU size - uint32_t DLSCH_pdu_size; - // Data Reptition - uint32_t R_dl; - // MCS index - uint32_t I_mcs_dl; - // total downlink buffer DCCH0_NB_IoT - uint32_t dl_buffer_DCCH0_NB_IoT; - // NDI - int oldNDI_DL; - //HARQ ACK/NACK repetition - uint32_t R_harq; - - /*Uplink information*/ - int oldNDI_UL; - // Uplink data repeat, now just follow the rach repeat number - uint32_t R_ul; - // PHR value (0-3) - uint32_t PHR; - // The uplink data size from BSR or DVI - uint32_t ul_total_buffer; - // Determine if this UE support multi-tone transmission or not - int multi_tone; - // Next UE_template ID - int next; - // Previous UE_template ID - int prev; - // MSG4 complete - int RRC_connected; - // UE active flag - int active; - -} UE_TEMPLATE_NB_IoT; - -/*36331 NPDCCH-ConfigDedicated-NB_IoT*/ -typedef struct{ - //npdcch-NumRepetitions-r13 - uint32_t R_max; - //npdcch-StartSF-USS-r13 - double G; - //npdcch-Offset-USS-r13 - double a_offset; - //NPDCCH period - uint32_t T; - //Starting subfrane of Search Space which is mod T - uint32_t ss_start_uss; -}NPDCCH_config_dedicated_NB_IoT_t; - - -/*! \brief UE list used by eNB to order UEs/CC for scheduling*/ -typedef struct { - - /// DCI template and MAC connection parameters for UEs - UE_TEMPLATE_NB_IoT UE_template_NB_IoT[MAX_NUMBER_OF_UE_MAX_NB_IoT]; - - /// NPDCCH Period and searching space info - NPDCCH_config_dedicated_NB_IoT_t NPDCCH_config_dedicated; - //int next[MAX_NUMBER_OF_UE_MAX_NB_IoT]; - // -1:No UE in list - int head; - // -1:No UE in list - int tail; - int num_UEs; - //boolean_t active[MAX_NUMBER_OF_UE_MAX_NB_IoT]; - -} UE_list_NB_IoT_t; - - -typedef struct{ - - // flag to indicate scheduing MIB-NB_IoT - uint8_t flag_MIB; - // flag to indicate scheduling SIB1-NB_IoT - uint8_t flag_SIB1; - // flag to indicate scheduling SIBs-NB_IoT - uint8_t flag_SIBs[MAX_NUMBER_OF_SIBs_NB_IoT]; - // flag to indicate scheduling type2 NPDCCH CSS with different CE level - uint8_t flag_type2_css[3]; - // flag to indicate scheduling type1 NPDCCH CSS with different CE level - uint8_t flag_type1_css[3]; - // flag to indicate scheduling NPDCCH USS with UE list - uint8_t flag_uss[MAX_NUMBER_OF_UE_MAX_NB_IoT]; - // flag to indicate scheduling sib1/MIB - uint8_t flag_fix_scheduling; - // number of the type2 css to schedule in this period - uint8_t num_type2_css_run; - // number of the type1 css to schedule in this period - uint8_t num_type1_css_run; - // number of the uss to schedule in this period - uint8_t num_uss_run; - -}scheduling_flag_t; - -typedef struct available_resource_UL_s{ - - ///Resource start subframe - uint32_t start_subframe; - ///Resource end subframe - uint32_t end_subframe; - // pointer to next node - struct available_resource_UL_s *next, *prev; - -}available_resource_UL_t; - -typedef struct available_resource_DL_s{ - uint32_t start_subframe; - uint32_t end_subframe; - - struct available_resource_DL_s *next, *prev; -}available_resource_DL_t; - -/*Structure used for scheduling*/ -typedef struct{ - //resource position info. - uint32_t sf_end,sf_start; - //resource position info. separate by HyperSF, Frame, Subframe - uint32_t start_h, end_h; - uint32_t start_f, end_f; - uint32_t start_sf, end_sf; - //whcih available resource node is used - available_resource_DL_t *node; -}sched_temp_DL_NB_IoT_t; - -/*!\brief MAC subheader short with 7bit Length field */ -typedef struct { - uint8_t LCID:5; // octet 1 LSB - uint8_t E:1; - uint8_t F2:1; - uint8_t R:1; // octet 1 MSB - uint8_t L:7; // octet 2 LSB - uint8_t F:1; // octet 2 MSB -} __attribute__((__packed__))SCH_SUBHEADER_SHORT_NB_IoT; -typedef struct { - uint8_t LCID:5; // octet 1 LSB - uint8_t E:1; - uint8_t F2:1; - uint8_t R:1; // octet 1 MSB - uint8_t L_MSB:7; - uint8_t F:1; // octet 2 MSB - uint8_t L_LSB:8; -} __attribute__((__packed__))SCH_SUBHEADER_LONG_NB_IoT; -typedef struct { - uint8_t LCID:5; // octet 1 LSB - uint8_t E:1; - uint8_t F2:1; - uint8_t R:1; // octet 1 MSB - uint8_t L_MSB:8; // octet 2 MSB - uint8_t L_LSB:8; -} __attribute__((__packed__))SCH_SUBHEADER_LONG_EXTEND_NB_IoT; -/*!\brief MAC subheader short without length field */ -typedef struct { - uint8_t LCID:5; - uint8_t F2:1; - uint8_t E:1; - uint8_t R:1; -} __attribute__((__packed__))SCH_SUBHEADER_FIXED_NB_IoT; - - -/*! \brief Uplink SCH PDU Structure */ -typedef struct { - int8_t payload[SCH_PAYLOAD_SIZE_MAX_NB_IoT]; /*!< \brief SACH payload */ - uint16_t Pdu_size; -} __attribute__ ((__packed__)) ULSCH_PDU_NB_IoT; - -typedef struct { - uint8_t PH:6; - uint8_t R:2; -} __attribute__((__packed__))POWER_HEADROOM_CMD_NB_IoT; - -typedef struct { - uint8_t RAPID:6; - uint8_t T:1; - uint8_t E:1; -} __attribute__((__packed__))RA_HEADER_RAPID_NB_IoT; - -/*Structure used for UL scheduling*/ -typedef struct{ - //resource position info. - uint32_t sf_end, sf_start; - //resource position info. separate by HyperSF, Frame, Subframe - //uint32_t start_h, end_h; - //uint32_t start_f, end_f; - //uint32_t start_sf, end_sf; - // information for allocating the resource - int tone; - int scheduling_delay; - int subcarrier_indication; - int ACK_NACK_resource_field; - available_resource_UL_t *node; -}sched_temp_UL_NB_IoT_t; - -typedef struct Available_available_resource_DL{ - - ///Available Resoruce for sixtone - available_resource_UL_t *sixtone_Head;//, *sixtone_npusch_frame; - uint32_t sixtone_end_subframe; - ///Available Resoruce for threetone - available_resource_UL_t *threetone_Head;//, *threetone_npusch_frame; - uint32_t threetone_end_subframe; - ///Available Resoruce for singletone1 - available_resource_UL_t *singletone1_Head;//, *singletone1_npusch_frame; - uint32_t singletone1_end_subframe; - ///Available Resoruce for singletone2 - available_resource_UL_t *singletone2_Head;//, *singletone2_npusch_frame; - uint32_t singletone2_end_subframe; - ///Available Resoruce for singletone3 - available_resource_UL_t *singletone3_Head;//, *singletone3_npusch_frame; - uint32_t singletone3_end_subframe; - -}available_resource_tones_UL_t; - -typedef struct schedule_result{ - // The subframe read by output handler - uint32_t output_subframe; - // SDU length - uint32_t sdu_length; - // MAC PDU - uint8_t *DLSCH_pdu; - // The data direction indicated by this DCI - uint8_t direction; - // pointer to DCI - void *DCI_pdu; - // when all the procedure related to this DCI, enable this flag - boolean_t DCI_release; - // Indicate the channel which to transmit - channel_NB_IoT_t channel; - // rnti - rnti_t rnti; - // 0 = TC-RNTI , 1 = RA-RNTI, 2 = P-RNTI, 3 = others - uint8_t rnti_type; - // 0 = data, 1 = ACK/NACK - uint8_t npusch_format; - //HARQ ACK/NACK repetition - uint32_t R_harq; - // pointer to next node - struct schedule_result *next; - - uint32_t end_subframe; - - uint8_t *rar_buffer; - -}schedule_result_t; - -/*Flag structure used for trigger each scheduler*/ -typedef struct{ - scheduling_flag_t scheduling_flag; - //sched_temp_DL_NB_IoT_t sched_result_DL; - //resource grid for Uplink - available_resource_tones_UL_t *UL_resource; - //scheduling result read by output handler - schedule_result_t *schedule_result_list_UL; - schedule_result_t *schedule_result_list_DL; -}SCHEDULE_NB_IoT_t; - -typedef struct{ - uint32_t num_dlsf_per_period; - uint16_t *sf_to_dlsf_table; - uint16_t *dlsf_to_sf_table; -}DLSF_INFO_t; - -typedef enum ce_level_e{ - ce0=0, - ce1, - ce2, - ce_level_total -}ce_level_t; - - - -/*! \brief eNB template for the Random access information */ -typedef struct RA_TEMPLATE_NB_IoT_s{ - - boolean_t active; - uint32_t msg3_retransmit_count; - uint32_t msg4_retransmit_count; - uint16_t ta; - uint8_t preamble_index; - ce_level_t ce_level; - rnti_t ue_rnti; - rnti_t ra_rnti; - struct RA_TEMPLATE_NB_IoT_s *next, *prev; - boolean_t wait_msg4_ack; - boolean_t wait_msg3_ack; - uint8_t rar_buffer[7]; - -} RA_TEMPLATE_NB_IoT; - -typedef struct RA_template_list_s{ - RA_TEMPLATE_NB_IoT *head; - RA_TEMPLATE_NB_IoT *tail; -}RA_template_list_t; - - -/*! \brief top level eNB MAC structure */ -typedef struct eNB_MAC_INST_NB_IoT_s { - /// Ethernet parameters for northbound midhaul interface - eth_params_t eth_params_n; - /// Ethernet parameters for fronthaul interface - eth_params_t eth_params_s; - - uint8_t Mod_id; - // System - uint32_t hyper_system_frame; - uint32_t system_frame; - uint32_t sub_frame; - - uint32_t current_subframe; - /// Pointer to IF module instance for PHY - IF_Module_t *if_inst; - // RA - RA_template_list_t RA_msg2_list; - RA_template_list_t RA_msg3_list; - RA_template_list_t RA_msg4_list; - - RA_TEMPLATE_NB_IoT RA_template[MAX_NUMBER_OF_UE_MAX_NB_IoT]; - - //int32_t last_tx_subframe; - - // for tool - int32_t sib1_flag[64]; - int32_t sib1_count[64]; - int32_t sib1_period; - uint16_t dlsf_table[64]; - int32_t sibs_table[256]; - - // channel config - - //USS list - //Number of USS period is used - int num_uss_list; - UE_list_NB_IoT_t *UE_list_spec; - - scheduling_flag_t scheduling_flag; - - uint32_t schedule_subframe_DL; - uint32_t schedule_subframe_UL; - - rrc_config_NB_IoT_t rrc_config; - - nfapi_config_request_t config; - - IF_Module_NB_IoT_t *if_inst_NB_IoT; -} eNB_MAC_INST_NB_IoT; - -// actually not here, but for now put it here -typedef struct { - uint32_t bytes_in_buffer; /*!< \brief Bytes buffered in RLC protocol instance. */ - uint32_t pdus_in_buffer; /*!< \brief Number of PDUs buffered in RLC protocol instance (OBSOLETE). */ - uint32_t head_sdu_creation_time; /*!< \brief Head SDU creation time. */ - uint32_t head_sdu_remaining_size_to_send; /*!< \brief remaining size of sdu: could be the total size or the remaining size of already segmented sdu */ - boolean_t head_sdu_is_segmented; /*!< \brief 0 if head SDU has not been segmented, 1 if already segmented */ -} mac_rlc_status_resp_NB_IoT_t; - -// global variables - -nprach_parameters_NB_IoT_t nprach_list[3]; - -//DLSF Table -DLSF_INFO_t DLSF_information; - -#endif /*__LAYER2_MAC_DEFS_NB_IoT_H__ */ + +/*! \file defs_NB_IoT.c + * \brief MAC layer structures + * \author NTUST BMW Lab./ + * \date 2017 + * \email: + * \version 1.0 + * + */ +#ifndef __LAYER2_MAC_DEFS_NB_IOT_H__ +#define __LAYER2_MAC_DEFS_NB_IOT_H__ +#ifdef USER_MODE +#include +#include +#include +#endif +//#include "COMMON/openair_defs.h" +#include "COMMON/platform_constants.h" +#include "COMMON/mac_rrc_primitives.h" +#include "PHY/LTE_TRANSPORT/defs_NB_IoT.h" +//#include "PHY/defs.h" +#include "PHY/defs_L1_NB_IoT.h" +#include "openair2/PHY_INTERFACE/IF_Module_NB_IoT.h" +#include "config_NB_IoT.h" +// MAC definition +#define MAX_FRAME 0xfffff +#define NUM_FRAME 0x100000 +#define MAX_SUBFRAME 10485760 + +#define MAX(a, b) (((a)>(b))?(a):(b)) + +// RA-RNTI: 1+SFN_id>>2 +#define RA_RNTI_LOW 0x0001 // SFN_id = 0 +#define RA_RNTI_HIGH 0x0100 // SFN_id = 1023 +#define C_RNTI_LOW 0x0101 +#define C_RNTI_HIGH + +// ULSCH LCHAN IDs +/*!\brief LCID of extended power headroom for ULSCH */ +#define EXTENDED_POWER_HEADROOM 25 +/*!\brief LCID of power headroom for ULSCH */ +#define POWER_HEADROOM 26 +/*!\brief LCID of CRNTI for ULSCH */ +#define CRNTI 27 +/*!\brief LCID of truncated BSR for ULSCH */ +#define TRUNCATED_BSR 28 +/*!\brief LCID of short BSR for ULSCH */ +#define SHORT_BSR 29 +/*!\brief LCID of long BSR for ULSCH */ +#define LONG_BSR 30 +/*! \brief Values of CCCH LCID for DLSCH */ +#define CCCH_LCHANID 0 +/*!\brief Values of BCCH logical channel */ +#define BCCH 3 // SI +/*!\brief Values of PCCH logical channel */ +#define PCCH 4 // Paging +/*!\brief Value of CCCH / SRB0 logical channel */ +#define CCCH 0 // srb0 +/*!\brief DCCH / SRB1 logical channel */ +#define DCCH 1 // srb1 +/*!\brief DCCH1 / SRB2 logical channel */ +#define DCCH1 2 // srb2 +/*!\brief DTCH DRB1 logical channel */ +#define DTCH 3 // LCID +/*!\brief MCCH logical channel */ +#define MCCH 4 +/*!\brief MTCH logical channel */ +#define MTCH 1 +// DLSCH LCHAN ID +/*!\brief LCID of UE contention resolution identity for DLSCH*/ +#define UE_CONT_RES 28 +/*!\brief LCID of timing advance for DLSCH */ +#define TIMING_ADV_CMD 29 +/*!\brief LCID of discontinous reception mode for DLSCH */ +#define DRX_CMD 30 +/*!\brief LCID of padding LCID for DLSCH */ +#define SHORT_PADDING 31 + + +typedef enum tone_type_e +{ + sixtone = 0, + threetone, + singletone1, + singletone2, + singletone3 +}tone_type_t; + +typedef enum channel_NB_IoT_e +{ + NPDCCH = 0, + NPUSCH, + NPDSCH +}channel_NB_IoT_t; + +typedef enum{ + UL = 0, + DL +}message_direction_t; + +#define MAX_NUMBER_OF_UE_MAX_NB_IoT 20 +#define SCH_PAYLOAD_SIZE_MAX_NB_IoT 320 +#define MAX_NUMBER_OF_SIBs_NB_IoT 16 + +/*!\brief Values of BCCH0 logical channel for MIB*/ +#define BCCH0_NB_IoT 11 // MIB-NB_IoT +/*!\brief Values of BCCH1 logical channel for SIBs */ +#define BCCH1_NB_IoT 12 // SI-SIB-NB_IoTs +/*!\brief Values of PCCH logical channel */ +#define PCCH_NB_IoT 13 // Paging XXX not used for the moment +#define MCCH_NB_IoT 14 +/*!\brief Value of CCCH / SRB0 logical channel */ +#define CCCH_NB_IoT 0 // srb0 ---> XXX exactly the same as in LTE (commented for compilation purposes) +/*!\brief DCCH0 / SRB1bis logical channel */ +#define DCCH0_NB_IoT 3 // srb1bis +/*!\brief DCCH1 / SRB1 logical channel */ +#define DCCH1_NB_IoT 1 // srb1 //XXX we redefine it for the SRB1 +/*!\brief DTCH0 DRB0 logical channel */ +#define DTCH0_NB_IoT 4 // DRB0 +/*!\brief DTCH1 DRB1 logical channel */ +#define DTCH1_NB_IoT 5 // DRB1 +/*Index of UE contention resoulution logical channel*/ +#define UE_CONTENTION_RESOLUTION 28 +/*Index of TIMING_ADVANCE logical channel*/ +#define TIMING_ADVANCE 29 +/*Index of DRX_COMMAND logical channel*/ +#define DRX_COMMAND 30 +/*Index of PADDING logical channel*/ +#define PADDING 31 + + +/// NPRACH-ParametersList-NB_IoT-r13 from 36.331 RRC spec defined in PHY +/*typedef struct NPRACH_Parameters_NB_IoT{ + + /// the period time for nprach + int nprach_Periodicity; + /// for the start time for the NPRACH resource from 40ms-2560ms + int nprach_StartTime; + /// for the subcarrier of set to the NPRACH preamble from n0 - n34 + int nprach_SubcarrierOffset; + ///number of subcarriers in a NPRACH resource allowed values (n12,n24,n36,n48) + int nprach_NumSubcarriers; + /// where is the region that in NPRACH resource to indicate if this UE support MSG3 for multi-tone or not. from 0 - 1 + int nprach_SubcarrierMSG3_RangeStart; + /// The max preamble transmission attempt for the CE level from 1 - 128 + int maxNumPreambleAttemptCE; + /// Number of NPRACH repetitions per attempt for each NPRACH resource + int numRepetitionsPerPreambleAttempt; + /// The number of the repetition for DCI use in RAR/MSG3/MSG4 from 1 - 2048 (Rmax) + int npdcch_NumRepetitions_RA; + /// Starting subframe for NPDCCH Common searching space for (RAR/MSG3/MSG4) + int npdcch_StartSF_CSS_RA; + /// Fractional period offset of starting subframe for NPDCCH common search space + int npdcch_Offset_RA; + +} nprach_parameters_NB_IoT_t;*/ + +/*! \brief Downlink SCH PDU Structure */ +typedef struct { + uint8_t payload[SCH_PAYLOAD_SIZE_MAX_NB_IoT]; + uint32_t pdu_size; +} __attribute__ ((__packed__)) DLSCH_PDU_NB_IoT; + +/*! \brief eNB template for UE context information */ +typedef struct { + // C-RNTI of UE + rnti_t rnti; + // UE CE level + int CE_level; + // Direction of transmission(DL:0\UL:1\NONE:-1) + int32_t direction; + // DCI Reptition + uint32_t R_dci; + // MAX repetition + uint32_t R_max; + + // HARQ round + uint32_t HARQ_round; + /*Downlink information*/ + + /// DLSCH pdu + DLSCH_PDU_NB_IoT DLSCH_pdu; + // PDU size + uint32_t DLSCH_pdu_size; + // Data Reptition + uint32_t R_dl; + // MCS index + uint32_t I_mcs_dl; + // total downlink buffer DCCH0_NB_IoT + uint32_t dl_buffer_DCCH0_NB_IoT; + // NDI + int oldNDI_DL; + //HARQ ACK/NACK repetition + uint32_t R_harq; + + /*Uplink information*/ + int oldNDI_UL; + // Uplink data repeat, now just follow the rach repeat number + uint32_t R_ul; + // PHR value (0-3) + uint32_t PHR; + // The uplink data size from BSR or DVI + uint32_t ul_total_buffer; + // Determine if this UE support multi-tone transmission or not + int multi_tone; + // Next UE_template ID + int next; + // Previous UE_template ID + int prev; + // MSG4 complete + int RRC_connected; + // UE active flag + int active; + +} UE_TEMPLATE_NB_IoT; + +/*36331 NPDCCH-ConfigDedicated-NB_IoT*/ +typedef struct{ + //npdcch-NumRepetitions-r13 + uint32_t R_max; + //npdcch-StartSF-USS-r13 + double G; + //npdcch-Offset-USS-r13 + double a_offset; + //NPDCCH period + uint32_t T; + //Starting subfrane of Search Space which is mod T + uint32_t ss_start_uss; +}NPDCCH_config_dedicated_NB_IoT_t; + + +/*! \brief UE list used by eNB to order UEs/CC for scheduling*/ +typedef struct { + + /// DCI template and MAC connection parameters for UEs + UE_TEMPLATE_NB_IoT UE_template_NB_IoT[MAX_NUMBER_OF_UE_MAX_NB_IoT]; + + /// NPDCCH Period and searching space info + NPDCCH_config_dedicated_NB_IoT_t NPDCCH_config_dedicated; + //int next[MAX_NUMBER_OF_UE_MAX_NB_IoT]; + // -1:No UE in list + int head; + // -1:No UE in list + int tail; + int num_UEs; + //boolean_t active[MAX_NUMBER_OF_UE_MAX_NB_IoT]; + +} UE_list_NB_IoT_t; + + +typedef struct{ + + // flag to indicate scheduing MIB-NB_IoT + uint8_t flag_MIB; + // flag to indicate scheduling SIB1-NB_IoT + uint8_t flag_SIB1; + // flag to indicate scheduling SIBs-NB_IoT + uint8_t flag_SIBs[MAX_NUMBER_OF_SIBs_NB_IoT]; + // flag to indicate scheduling type2 NPDCCH CSS with different CE level + uint8_t flag_type2_css[3]; + // flag to indicate scheduling type1 NPDCCH CSS with different CE level + uint8_t flag_type1_css[3]; + // flag to indicate scheduling NPDCCH USS with UE list + uint8_t flag_uss[MAX_NUMBER_OF_UE_MAX_NB_IoT]; + // flag to indicate scheduling sib1/MIB + uint8_t flag_fix_scheduling; + // number of the type2 css to schedule in this period + uint8_t num_type2_css_run; + // number of the type1 css to schedule in this period + uint8_t num_type1_css_run; + // number of the uss to schedule in this period + uint8_t num_uss_run; + +}scheduling_flag_t; + +typedef struct available_resource_UL_s{ + + ///Resource start subframe + uint32_t start_subframe; + ///Resource end subframe + uint32_t end_subframe; + // pointer to next node + struct available_resource_UL_s *next, *prev; + +}available_resource_UL_t; + +typedef struct available_resource_DL_s{ + uint32_t start_subframe; + uint32_t end_subframe; + + struct available_resource_DL_s *next, *prev; +}available_resource_DL_t; + +/*Structure used for scheduling*/ +typedef struct{ + //resource position info. + uint32_t sf_end,sf_start; + //resource position info. separate by HyperSF, Frame, Subframe + uint32_t start_h, end_h; + uint32_t start_f, end_f; + uint32_t start_sf, end_sf; + //whcih available resource node is used + available_resource_DL_t *node; +}sched_temp_DL_NB_IoT_t; + +/*!\brief MAC subheader short with 7bit Length field */ +typedef struct { + uint8_t LCID:5; // octet 1 LSB + uint8_t E:1; + uint8_t F2:1; + uint8_t R:1; // octet 1 MSB + uint8_t L:7; // octet 2 LSB + uint8_t F:1; // octet 2 MSB +} __attribute__((__packed__))SCH_SUBHEADER_SHORT_NB_IoT; +typedef struct { + uint8_t LCID:5; // octet 1 LSB + uint8_t E:1; + uint8_t F2:1; + uint8_t R:1; // octet 1 MSB + uint8_t L_MSB:7; + uint8_t F:1; // octet 2 MSB + uint8_t L_LSB:8; +} __attribute__((__packed__))SCH_SUBHEADER_LONG_NB_IoT; +typedef struct { + uint8_t LCID:5; // octet 1 LSB + uint8_t E:1; + uint8_t F2:1; + uint8_t R:1; // octet 1 MSB + uint8_t L_MSB:8; // octet 2 MSB + uint8_t L_LSB:8; +} __attribute__((__packed__))SCH_SUBHEADER_LONG_EXTEND_NB_IoT; +/*!\brief MAC subheader short without length field */ +typedef struct { + uint8_t LCID:5; + uint8_t F2:1; + uint8_t E:1; + uint8_t R:1; +} __attribute__((__packed__))SCH_SUBHEADER_FIXED_NB_IoT; + + +/*! \brief Uplink SCH PDU Structure */ +typedef struct { + int8_t payload[SCH_PAYLOAD_SIZE_MAX_NB_IoT]; /*!< \brief SACH payload */ + uint16_t Pdu_size; +} __attribute__ ((__packed__)) ULSCH_PDU_NB_IoT; + +typedef struct { + uint8_t PH:6; + uint8_t R:2; +} __attribute__((__packed__))POWER_HEADROOM_CMD_NB_IoT; + +typedef struct { + uint8_t RAPID:6; + uint8_t T:1; + uint8_t E:1; +} __attribute__((__packed__))RA_HEADER_RAPID_NB_IoT; + +/*Structure used for UL scheduling*/ +typedef struct{ + //resource position info. + uint32_t sf_end, sf_start; + //resource position info. separate by HyperSF, Frame, Subframe + //uint32_t start_h, end_h; + //uint32_t start_f, end_f; + //uint32_t start_sf, end_sf; + // information for allocating the resource + int tone; + int scheduling_delay; + int subcarrier_indication; + int ACK_NACK_resource_field; + available_resource_UL_t *node; +}sched_temp_UL_NB_IoT_t; + +typedef struct Available_available_resource_DL{ + + ///Available Resoruce for sixtone + available_resource_UL_t *sixtone_Head;//, *sixtone_npusch_frame; + uint32_t sixtone_end_subframe; + ///Available Resoruce for threetone + available_resource_UL_t *threetone_Head;//, *threetone_npusch_frame; + uint32_t threetone_end_subframe; + ///Available Resoruce for singletone1 + available_resource_UL_t *singletone1_Head;//, *singletone1_npusch_frame; + uint32_t singletone1_end_subframe; + ///Available Resoruce for singletone2 + available_resource_UL_t *singletone2_Head;//, *singletone2_npusch_frame; + uint32_t singletone2_end_subframe; + ///Available Resoruce for singletone3 + available_resource_UL_t *singletone3_Head;//, *singletone3_npusch_frame; + uint32_t singletone3_end_subframe; + +}available_resource_tones_UL_t; + +typedef struct schedule_result{ + // The subframe read by output handler + uint32_t output_subframe; + // SDU length + uint32_t sdu_length; + // MAC PDU + uint8_t *DLSCH_pdu; + // The data direction indicated by this DCI + uint8_t direction; + // pointer to DCI + void *DCI_pdu; + // when all the procedure related to this DCI, enable this flag + boolean_t DCI_release; + // Indicate the channel which to transmit + channel_NB_IoT_t channel; + // rnti + rnti_t rnti; + // 0 = TC-RNTI , 1 = RA-RNTI, 2 = P-RNTI, 3 = others + uint8_t rnti_type; + // 0 = data, 1 = ACK/NACK + uint8_t npusch_format; + //HARQ ACK/NACK repetition + uint32_t R_harq; + // pointer to next node + struct schedule_result *next; + + uint32_t end_subframe; + + uint8_t *rar_buffer; + +}schedule_result_t; + +/*Flag structure used for trigger each scheduler*/ +typedef struct{ + scheduling_flag_t scheduling_flag; + //sched_temp_DL_NB_IoT_t sched_result_DL; + //resource grid for Uplink + available_resource_tones_UL_t *UL_resource; + //scheduling result read by output handler + schedule_result_t *schedule_result_list_UL; + schedule_result_t *schedule_result_list_DL; +}SCHEDULE_NB_IoT_t; + +typedef struct{ + uint32_t num_dlsf_per_period; + uint16_t *sf_to_dlsf_table; + uint16_t *dlsf_to_sf_table; +}DLSF_INFO_t; + +typedef enum ce_level_e{ + ce0=0, + ce1, + ce2, + ce_level_total +}ce_level_t; + + + +/*! \brief eNB template for the Random access information */ +typedef struct RA_TEMPLATE_NB_IoT_s{ + + boolean_t active; + uint32_t msg3_retransmit_count; + uint32_t msg4_retransmit_count; + uint16_t ta; + uint8_t preamble_index; + ce_level_t ce_level; + rnti_t ue_rnti; + rnti_t ra_rnti; + struct RA_TEMPLATE_NB_IoT_s *next, *prev; + boolean_t wait_msg4_ack; + boolean_t wait_msg3_ack; + uint8_t rar_buffer[7]; + +} RA_TEMPLATE_NB_IoT; + +typedef struct RA_template_list_s{ + RA_TEMPLATE_NB_IoT *head; + RA_TEMPLATE_NB_IoT *tail; +}RA_template_list_t; + + +/*! \brief top level eNB MAC structure */ +typedef struct eNB_MAC_INST_NB_IoT_s { + /// Ethernet parameters for northbound midhaul interface + eth_params_t eth_params_n; + /// Ethernet parameters for fronthaul interface + eth_params_t eth_params_s; + + uint8_t Mod_id; + // System + uint32_t hyper_system_frame; + uint32_t system_frame; + uint32_t sub_frame; + + uint32_t current_subframe; + /// Pointer to IF module instance for PHY + IF_Module_t *if_inst; + // RA + RA_template_list_t RA_msg2_list; + RA_template_list_t RA_msg3_list; + RA_template_list_t RA_msg4_list; + + RA_TEMPLATE_NB_IoT RA_template[MAX_NUMBER_OF_UE_MAX_NB_IoT]; + + //int32_t last_tx_subframe; + + // for tool + int32_t sib1_flag[64]; + int32_t sib1_count[64]; + int32_t sib1_period; + uint16_t dlsf_table[64]; + int32_t sibs_table[256]; + + // channel config + + //USS list + //Number of USS period is used + int num_uss_list; + UE_list_NB_IoT_t *UE_list_spec; + + scheduling_flag_t scheduling_flag; + + uint32_t schedule_subframe_DL; + uint32_t schedule_subframe_UL; + + rrc_config_NB_IoT_t rrc_config; + + nfapi_config_request_t config; + + IF_Module_NB_IoT_t *if_inst_NB_IoT; +} eNB_MAC_INST_NB_IoT; + +// actually not here, but for now put it here +typedef struct { + uint32_t bytes_in_buffer; /*!< \brief Bytes buffered in RLC protocol instance. */ + uint32_t pdus_in_buffer; /*!< \brief Number of PDUs buffered in RLC protocol instance (OBSOLETE). */ + uint32_t head_sdu_creation_time; /*!< \brief Head SDU creation time. */ + uint32_t head_sdu_remaining_size_to_send; /*!< \brief remaining size of sdu: could be the total size or the remaining size of already segmented sdu */ + boolean_t head_sdu_is_segmented; /*!< \brief 0 if head SDU has not been segmented, 1 if already segmented */ +} mac_rlc_status_resp_NB_IoT_t; + +// global variables + +nprach_parameters_NB_IoT_t nprach_list[3]; + +//DLSF Table +DLSF_INFO_t DLSF_information; + +#endif /*__LAYER2_MAC_DEFS_NB_IoT_H__ */ diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c b/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c index 80dcfd4053..43721bbfd5 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c @@ -1,1417 +1,1417 @@ -/* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file asn1_msg.c -* \brief primitives to build the asn1 messages -* \author Raymond Knopp, Navid Nikaein and Michele Paffetti -* \date 2011, 2017 -* \version 1.0 -* \company Eurecom -* \email: raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, michele.paffetti@studio.unibo.it -*/ - -#include -#include -#include /* for atoi(3) */ -#include /* for getopt(3) */ -#include /* for strerror(3) */ -#include /* for EX_* exit codes */ -#include /* for errno */ -#include "UTIL/LOG/log.h" -#include -#include /* for _ASN_DEFAULT_STACK_MAX */ -#include -#include "asn1_msg.h" - - - -//#include for NB-IoT------------------- -#include "RRCConnectionRequest-NB.h" -#include "BCCH-DL-SCH-Message-NB.h" -#include "UL-CCCH-Message-NB.h" -#include "UL-DCCH-Message-NB.h" -#include "DL-CCCH-Message-NB.h" -#include "DL-DCCH-Message-NB.h" -#include "EstablishmentCause-NB-r13.h" -#include "RRCConnectionSetup-NB.h" -#include "SRB-ToAddModList-NB-r13.h" -#include "DRB-ToAddModList-NB-r13.h" -#include "RRC/LITE/defs_NB_IoT.h" -#include "RRCConnectionSetupComplete-NB.h" -#include "RRCConnectionReconfigurationComplete-NB.h" -#include "RRCConnectionReconfiguration-NB.h" -#include "MasterInformationBlock-NB.h" -#include "SystemInformation-NB.h" -#include "SystemInformationBlockType1.h" -#include "SIB-Type-NB-r13.h" -#include "RRCConnectionResume-NB.h" -#include "RRCConnectionReestablishment-NB.h" -#include "../defs_NB_IoT.h" -//---------------------------------------- - -//#include "PHY/defs.h" -#include "enb_config.h" - -#if defined(ENABLE_ITTI) -# include "intertask_interface.h" -#endif - - - - -/*do_MIB_NB_NB_IoT*/ -uint8_t do_MIB_NB_IoT( - rrc_eNB_carrier_data_NB_IoT_t *carrier, - uint16_t N_RB_DL,//may not needed--> for NB_IoT only 1 PRB is used - uint32_t frame, - uint32_t hyper_frame) -{ - asn_enc_rval_t enc_rval; - BCCH_BCH_Message_NB_t *mib_NB_IoT = &(carrier->mib_NB_IoT); - - /* - * systemFrameNumber-MSB: (TS 36.331 pag 576) - * define the 4 MSB of the SFN (10 bits). The last significant 6 bits will be acquired implicitly by decoding the NPBCH - * NOTE: 6 LSB will be used for counting the 64 radio frames in the TTI period (640 ms) that is exactly the MIB period - * - * hyperSFN-LSB: - * indicates the 2 least significant bits of the HSFN. The remaining 8 bits are present in SIB1-NB - * NOTE: with the 2 bits we count the 4 HSFN (is 1 SIB1-Nb modification period) while the other 6 count the number of modification periods - * - * - * NOTE: in OAI never modify the SIB messages!!?? - */ - - //XXX check if correct the bit assignment - uint8_t sfn_MSB = (uint8_t)((frame>>6) & 0x0f); // all the 4 bits are set to 1 - uint8_t hsfn_LSB = (uint8_t)(hyper_frame & 0x03); //2 bits set to 1 (0x3 = 0011) - uint16_t spare=0; //11 bits --> use uint16 - - mib_NB_IoT->message.systemFrameNumber_MSB_r13.buf = &sfn_MSB; - mib_NB_IoT->message.systemFrameNumber_MSB_r13.size = 1; //if expressed in byte - mib_NB_IoT->message.systemFrameNumber_MSB_r13.bits_unused = 4; //is byte based (so how many bits you don't use of the 8 bits of a bite - - mib_NB_IoT->message.hyperSFN_LSB_r13.buf= &hsfn_LSB; - mib_NB_IoT->message.hyperSFN_LSB_r13.size= 1; - mib_NB_IoT->message.hyperSFN_LSB_r13.bits_unused = 6; - - //XXX to be set?? - mib_NB_IoT->message.spare.buf = (uint8_t *)&spare; - mib_NB_IoT->message.spare.size = 2; - mib_NB_IoT->message.spare.bits_unused = 5; - - //decide how to set it - mib_NB_IoT->message.schedulingInfoSIB1_r13 =11; //see TS 36.213-->tables 16.4.1.3-3 ecc... - mib_NB_IoT->message.systemInfoValueTag_r13= 0; - mib_NB_IoT->message.ab_Enabled_r13 = 0; - - //to be decided - mib_NB_IoT->message.operationModeInfo_r13.present = MasterInformationBlock_NB__operationModeInfo_r13_PR_inband_SamePCI_r13; - mib_NB_IoT->message.operationModeInfo_r13.choice.inband_SamePCI_r13.eutra_CRS_SequenceInfo_r13 = 0; - - printf("[MIB] Initialization of frame information,sfn_MSB %x, hsfn_LSB %x\n", - (uint32_t)sfn_MSB, - (uint32_t)hsfn_LSB); - - enc_rval = uper_encode_to_buffer(&asn_DEF_BCCH_BCH_Message_NB, - (void*)mib_NB_IoT, - carrier->MIB_NB_IoT, - 100); - if(enc_rval.encoded <= 0) { - LOG_F(RRC, "ASN1 message encoding failed (%s, %lu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - } - - if (enc_rval.encoded==-1) { - return(-1); - } - - return((enc_rval.encoded+7)/8); - -} - -/*do_SIB1_NB*/ -uint8_t do_SIB1_NB_IoT(uint8_t Mod_id, int CC_id, - rrc_eNB_carrier_data_NB_IoT_t *carrier, - NbIoTRrcConfigurationReq *configuration, - uint32_t frame - ) -{ - BCCH_DL_SCH_Message_NB_t *bcch_message= &(carrier->siblock1_NB_IoT); - SystemInformationBlockType1_NB_t **sib1_NB_IoT= &(carrier->sib1_NB_IoT); - - - asn_enc_rval_t enc_rval; - - PLMN_IdentityInfo_NB_r13_t PLMN_identity_info_NB_IoT; - MCC_MNC_Digit_t dummy_mcc[3],dummy_mnc[3]; - SchedulingInfo_NB_r13_t *schedulingInfo_NB_IoT; - SIB_Type_NB_r13_t *sib_type_NB_IoT; - - - long* attachWithoutPDN_Connectivity = NULL; - attachWithoutPDN_Connectivity = CALLOC(1,sizeof(long)); - long *nrs_CRS_PowerOffset=NULL; - nrs_CRS_PowerOffset = CALLOC(1, sizeof(long)); - long *eutraControlRegionSize=NULL; //this parameter should be set only if we are considering in-band operating mode (samePCI or differentPCI) - eutraControlRegionSize = CALLOC(1,sizeof(long)); - long systemInfoValueTagSI = 0; - - memset(bcch_message,0,sizeof(BCCH_DL_SCH_Message_NB_t)); - bcch_message->message.present = BCCH_DL_SCH_MessageType_NB_PR_c1; - bcch_message->message.choice.c1.present = BCCH_DL_SCH_MessageType_NB__c1_PR_systemInformationBlockType1_r13; - - //allocation - *sib1_NB_IoT = &bcch_message->message.choice.c1.choice.systemInformationBlockType1_r13; - - - /*TS 36.331 v14.2.0 pag 589 - * hyperSFN-MSB - * Indicates the 8 most significant bits of the hyper-SFN. Together with the hyper-LSB in MIB-NB the complete HSFN is build up - */ - //FIXME see if correct - uint8_t hyperSFN_MSB = (uint8_t) ((frame>>2)& 0xff); - - //XXX to be checked - (*sib1_NB_IoT)->hyperSFN_MSB_r13.buf = &hyperSFN_MSB; - (*sib1_NB_IoT)->hyperSFN_MSB_r13.size = 1; - (*sib1_NB_IoT)->hyperSFN_MSB_r13.bits_unused = 0; - - memset(&PLMN_identity_info_NB_IoT,0,sizeof(PLMN_IdentityInfo_NB_r13_t)); - - PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc = CALLOC(1,sizeof(*PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc)); - memset(PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc,0,sizeof(*PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc)); - - asn_set_empty(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list);//.size=0; - - //left as it is??? -#if defined(ENABLE_ITTI) - dummy_mcc[0] = (configuration->mcc / 100) % 10; - dummy_mcc[1] = (configuration->mcc / 10) % 10; - dummy_mcc[2] = (configuration->mcc / 1) % 10; -#else - dummy_mcc[0] = 0; - dummy_mcc[1] = 0; - dummy_mcc[2] = 1; -#endif - ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list,&dummy_mcc[0]); - ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list,&dummy_mcc[1]); - ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list,&dummy_mcc[2]); - - PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list.size=0; - PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list.count=0; - - -#if defined(ENABLE_ITTI) - - if (configuration->mnc >= 100) { - dummy_mnc[0] = (configuration->mnc / 100) % 10; - dummy_mnc[1] = (configuration->mnc / 10) % 10; - dummy_mnc[2] = (configuration->mnc / 1) % 10; - } else { - if (configuration->mnc_digit_length == 2) { - dummy_mnc[0] = (configuration->mnc / 10) % 10; - dummy_mnc[1] = (configuration->mnc / 1) % 10; - dummy_mnc[2] = 0xf; - } else { - dummy_mnc[0] = (configuration->mnc / 100) % 100; - dummy_mnc[1] = (configuration->mnc / 10) % 10; - dummy_mnc[2] = (configuration->mnc / 1) % 10; - } - } - -#else - dummy_mnc[0] = 0; - dummy_mnc[1] = 1; - dummy_mnc[2] = 0xf; -#endif - ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list,&dummy_mnc[0]); - ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list,&dummy_mnc[1]); - - if (dummy_mnc[2] != 0xf) { - ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list,&dummy_mnc[2]); - } - - //still set to "notReserved" as in the previous case - PLMN_identity_info_NB_IoT.cellReservedForOperatorUse_r13=PLMN_IdentityInfo_NB_r13__cellReservedForOperatorUse_r13_notReserved; - - *attachWithoutPDN_Connectivity = 0; - PLMN_identity_info_NB_IoT.attachWithoutPDN_Connectivity_r13 = attachWithoutPDN_Connectivity; - - ASN_SEQUENCE_ADD(&(*sib1_NB_IoT)->cellAccessRelatedInfo_r13.plmn_IdentityList_r13.list,&PLMN_identity_info_NB_IoT); - - // 16 bits = 2 byte - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf = MALLOC(2); //MALLOC works in byte - - //lefts as it is? -#if defined(ENABLE_ITTI) - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[0] = (configuration->tac >> 8) & 0xff; - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[1] = (configuration->tac >> 0) & 0xff; -#else - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[0] = 0x00; - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[1] = 0x01; -#endif - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.size=2; - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.bits_unused=0; - - // 28 bits --> i have to use 32 bits = 4 byte - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf = MALLOC(8); // why allocate 8 byte? -#if defined(ENABLE_ITTI) - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[0] = (configuration->cell_identity >> 20) & 0xff; - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[1] = (configuration->cell_identity >> 12) & 0xff; - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[2] = (configuration->cell_identity >> 4) & 0xff; - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[3] = (configuration->cell_identity << 4) & 0xf0; -#else - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[0] = 0x00; - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[1] = 0x00; - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[2] = 0x00; - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[3] = 0x10; -#endif - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.size=4; - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.bits_unused=4; - - //Still set to "notBarred" as in the previous case - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellBarred_r13=SystemInformationBlockType1_NB__cellAccessRelatedInfo_r13__cellBarred_r13_notBarred; - - //Still Set to "notAllowed" like in the previous case - (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.intraFreqReselection_r13=SystemInformationBlockType1_NB__cellAccessRelatedInfo_r13__intraFreqReselection_r13_notAllowed; - - - (*sib1_NB_IoT)->cellSelectionInfo_r13.q_RxLevMin_r13=-65; //which value?? TS 36.331 V14.2.1 pag. 589 - (*sib1_NB_IoT)->cellSelectionInfo_r13.q_QualMin_r13 = 0; //FIXME new parameter for SIB1-NB, not present in SIB1 (for cell reselection but if not used the UE should apply the default value) - - (*sib1_NB_IoT)->p_Max_r13 = CALLOC(1, sizeof(P_Max_t)); - *((*sib1_NB_IoT)->p_Max_r13) = 23; - - //FIXME - (*sib1_NB_IoT)->freqBandIndicator_r13 = -#if defined(ENABLE_ITTI) - configuration->eutra_band; -#else - 5; //if not configured we use band 5 (UL: 824 MHz - 849MHz / DL: 869 MHz - 894 MHz FDD mode) -#endif - - //OPTIONAL new parameters, to be used? - /* - * freqBandInfo_r13 - * multiBandInfoList_r13 - * nrs_CRS_PowerOffset_r13 - * sib1_NB_IoT->downlinkBitmap_r13.choice.subframePattern10_r13 =(is a BIT_STRING) - */ - - - (*sib1_NB_IoT)->downlinkBitmap_r13 = CALLOC(1, sizeof(struct DL_Bitmap_NB_r13)); - ((*sib1_NB_IoT)->downlinkBitmap_r13)->present= DL_Bitmap_NB_r13_PR_NOTHING; - - *eutraControlRegionSize = 1; - (*sib1_NB_IoT)->eutraControlRegionSize_r13 = eutraControlRegionSize; - - - *nrs_CRS_PowerOffset= 0; - (*sib1_NB_IoT)->nrs_CRS_PowerOffset_r13 = nrs_CRS_PowerOffset; - - schedulingInfo_NB_IoT = (SchedulingInfo_NB_r13_t*) malloc (3*sizeof(SchedulingInfo_NB_r13_t)); - sib_type_NB_IoT = (SIB_Type_NB_r13_t *) malloc (3*sizeof(SIB_Type_NB_r13_t)); - - memset(&schedulingInfo_NB_IoT[0],0,sizeof(SchedulingInfo_NB_r13_t)); - memset(&schedulingInfo_NB_IoT[1],0,sizeof(SchedulingInfo_NB_r13_t)); - memset(&schedulingInfo_NB_IoT[2],0,sizeof(SchedulingInfo_NB_r13_t)); - memset(&sib_type_NB_IoT[0],0,sizeof(SIB_Type_NB_r13_t)); - memset(&sib_type_NB_IoT[1],0,sizeof(SIB_Type_NB_r13_t)); - memset(&sib_type_NB_IoT[2],0,sizeof(SIB_Type_NB_r13_t)); - - - // Now, follow the scheduler SIB configuration - // There is only one sib2+sib3 common setting - schedulingInfo_NB_IoT[0].si_Periodicity_r13=SchedulingInfo_NB_r13__si_Periodicity_r13_rf4096; - schedulingInfo_NB_IoT[0].si_RepetitionPattern_r13=SchedulingInfo_NB_r13__si_RepetitionPattern_r13_every2ndRF; //This Indicates the starting radio frames within the SI window used for SI message transmission. - schedulingInfo_NB_IoT[0].si_TB_r13= SchedulingInfo_NB_r13__si_TB_r13_b680;//208 bits - - - // This is for SIB2/3 - /*SIB3 --> There is no mapping information of SIB2 since it is always present - * in the first SystemInformation message - * listed in the schedulingInfoList list. - * */ - sib_type_NB_IoT[0]=SIB_Type_NB_r13_sibType3_NB_r13; - - ASN_SEQUENCE_ADD(&schedulingInfo_NB_IoT[0].sib_MappingInfo_r13.list,&sib_type_NB_IoT[0]); - ASN_SEQUENCE_ADD(&(*sib1_NB_IoT)->schedulingInfoList_r13.list,&schedulingInfo_NB_IoT[0]); - - //printf("[ASN Debug] SI P: %ld\n",(*sib1_NB_IoT)->schedulingInfoList_r13.list.array[0]->si_Periodicity_r13); - -#if defined(ENABLE_ITTI) - - if (configuration->frame_type == TDD) -#endif - { - //FIXME in NB-IoT mandatory to be FDD --> so must give an error - LOG_E(RRC,"[NB-IoT %d] Frame Type is TDD --> not supported by NB-IoT, exiting\n", Mod_id); //correct? - exit(-1); - } - - //FIXME which value chose for the following parameter - (*sib1_NB_IoT)->si_WindowLength_r13=SystemInformationBlockType1_NB__si_WindowLength_r13_ms160; - (*sib1_NB_IoT)->si_RadioFrameOffset_r13= 0; - - /*In Nb-IoT change/update of specific SI message can additionally be indicated by a SI message specific value tag - * systemInfoValueTagSI (there is no SystemInfoValueTag in SIB1-NB but only in MIB-NB) - *contained in systemInfoValueTagList_r13 - **/ - //FIXME correct? - (*sib1_NB_IoT)->systemInfoValueTagList_r13 = CALLOC(1, sizeof(struct SystemInfoValueTagList_NB_r13)); - asn_set_empty(&(*sib1_NB_IoT)->systemInfoValueTagList_r13->list); - ASN_SEQUENCE_ADD(&(*sib1_NB_IoT)->systemInfoValueTagList_r13->list,&systemInfoValueTagSI); - - -#ifdef XER_PRINT //generate xml files - xer_fprint(stdout, &asn_DEF_BCCH_DL_SCH_Message_NB, (void*)bcch_message); -#endif - - - enc_rval = uper_encode_to_buffer(&asn_DEF_BCCH_DL_SCH_Message_NB, - (void*)bcch_message, - carrier->SIB1_NB_IoT, - 100); - - if (enc_rval.encoded > 0){ - LOG_F(RRC,"ASN1 message encoding failed (%s, %lu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - } - - -#ifdef USER_MODE - LOG_D(RRC,"[NB-IoT] SystemInformationBlockType1-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif - - if (enc_rval.encoded==-1) { - return(-1); - } - - return((enc_rval.encoded+7)/8); -} - -/*SIB23_NB_IoT*/ -//to be clarified is it is possible to carry SIB2 and SIB3 in the same SI message for NB-IoT? -uint8_t do_SIB23_NB_IoT(uint8_t Mod_id, - int CC_id, - rrc_eNB_carrier_data_NB_IoT_t *carrier,//MP: this is already a carrier[CC_id] - NbIoTRrcConfigurationReq *configuration ) //openair2/COMMON/rrc_messages_types.h -{ - struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member *sib2_NB_part; - struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member *sib3_NB_part; - - BCCH_DL_SCH_Message_NB_t *bcch_message = &(carrier->systemInformation_NB_IoT); //is the systeminformation-->BCCH_DL_SCH_Message_NB - SystemInformationBlockType2_NB_r13_t *sib2_NB_IoT; - SystemInformationBlockType3_NB_r13_t *sib3_NB_IoT; - - asn_enc_rval_t enc_rval; - RACH_Info_NB_r13_t rach_Info_NB_IoT; - NPRACH_Parameters_NB_r13_t *nprach_parameters; - - //optional - long *connEstFailOffset = NULL; - connEstFailOffset = CALLOC(1, sizeof(long)); - -// RSRP_ThresholdsNPRACH_InfoList_NB_r13_t *rsrp_ThresholdsPrachInfoList; -// RSRP_Range_t rsrp_range; - - ACK_NACK_NumRepetitions_NB_r13_t ack_nack_repetition; - struct NPUSCH_ConfigCommon_NB_r13__dmrs_Config_r13 *dmrs_config; - struct DL_GapConfig_NB_r13 *dl_Gap; - - long *srs_SubframeConfig; - srs_SubframeConfig= CALLOC(1, sizeof(long)); - - - if (bcch_message) { - memset(bcch_message,0,sizeof(BCCH_DL_SCH_Message_NB_t)); - } else { - LOG_E(RRC,"[NB-IoT %d] BCCH_MESSAGE_NB is null, exiting\n", Mod_id); - exit(-1); - } - - //before schould be allocated memory somewhere? -// if (!carrier->sib2_NB_IoT) { -// LOG_E(RRC,"[NB-IoT %d] sib2_NB_IoT is null, exiting\n", Mod_id); -// exit(-1); -// } -// -// if (!carrier->sib3_NB_IoT) { -// LOG_E(RRC,"[NB-IoT %d] sib3_NB_IoT is null, exiting\n", Mod_id); -// exit(-1); -// } - - - LOG_I(RRC,"[NB-IoT %d] Configuration SIB2/3\n", Mod_id); - - sib2_NB_part = CALLOC(1,sizeof(struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member)); - sib3_NB_part = CALLOC(1,sizeof(struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member)); - memset(sib2_NB_part,0,sizeof(struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member)); - memset(sib3_NB_part,0,sizeof(struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member)); - - sib2_NB_part->present = SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member_PR_sib2_r13; - sib3_NB_part->present = SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member_PR_sib3_r13; - - //may bug if not correct allocation of memory - carrier->sib2_NB_IoT = &sib2_NB_part->choice.sib2_r13; - carrier->sib3_NB_IoT = &sib3_NB_part->choice.sib3_r13; - sib2_NB_IoT = carrier->sib2_NB_IoT; - sib3_NB_IoT = carrier->sib3_NB_IoT; - - nprach_parameters = (NPRACH_Parameters_NB_r13_t *) malloc (3*sizeof(NPRACH_Parameters_NB_r13_t)); - - memset(&nprach_parameters[0],0,sizeof(NPRACH_Parameters_NB_r13_t)); - memset(&nprach_parameters[1],0,sizeof(NPRACH_Parameters_NB_r13_t)); - memset(&nprach_parameters[2],0,sizeof(NPRACH_Parameters_NB_r13_t)); - -/// SIB2-NB----------------------------------------- - - //Barring is manage by ab-Enabled in MIB-NB (but is not a struct as ac-BarringInfo in LTE legacy) - - //RACH Config. Common-------------------------------------------------------------- - sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.preambleTransMax_CE_r13 = - configuration->rach_preambleTransMax_CE_NB; - sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.powerRampingParameters_r13.powerRampingStep = - configuration->rach_powerRampingStep_NB; - sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.powerRampingParameters_r13.preambleInitialReceivedTargetPower = - configuration->rach_preambleInitialReceivedTargetPower_NB; - - rach_Info_NB_IoT.ra_ResponseWindowSize_r13 = configuration->rach_raResponseWindowSize_NB; - rach_Info_NB_IoT.mac_ContentionResolutionTimer_r13 = configuration-> rach_macContentionResolutionTimer_NB; - //rach_infoList max size = maxNPRACH-Resources-NB-r13 = 3 - ASN_SEQUENCE_ADD(&sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.rach_InfoList_r13.list,&rach_Info_NB_IoT); - - //TS 36.331 pag 614 --> if not present the value to infinity sould be used - *connEstFailOffset = 0; - - sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.connEstFailOffset_r13 = connEstFailOffset; /*OPTIONAL*/ - - - // BCCH-Config-NB-IoT---------------------------------------------------------------- - sib2_NB_IoT->radioResourceConfigCommon_r13.bcch_Config_r13.modificationPeriodCoeff_r13 - = configuration->bcch_modificationPeriodCoeff_NB; - - // PCCH-Config-NB-IoT----------------------------------------------------------------- - sib2_NB_IoT->radioResourceConfigCommon_r13.pcch_Config_r13.defaultPagingCycle_r13 - = configuration->pcch_defaultPagingCycle_NB; - sib2_NB_IoT->radioResourceConfigCommon_r13.pcch_Config_r13.nB_r13 = configuration->pcch_nB_NB; - sib2_NB_IoT->radioResourceConfigCommon_r13.pcch_Config_r13.npdcch_NumRepetitionPaging_r13 = configuration-> pcch_npdcch_NumRepetitionPaging_NB; - - //NPRACH-Config-NB-IoT----------------------------------------------------------------- - - sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.rsrp_ThresholdsPrachInfoList_r13 = NULL; - sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.nprach_CP_Length_r13 = configuration->nprach_CP_Length; - /*OPTIONAL*/ -// =CALLOC(1, sizeof(struct RSRP_ThresholdsNPRACH_InfoList_NB_r13)); //fatto uguale dopo -// rsrp_ThresholdsPrachInfoList = sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.rsrp_ThresholdsPrachInfoList_r13; -// rsrp_range = configuration->nprach_rsrp_range_NB; -// ASN_SEQUENCE_ADD(&rsrp_ThresholdsPrachInfoList->list,rsrp_range); - - // According configuration to set the 3 CE level configuration setting - - nprach_parameters[0].nprach_Periodicity_r13 = configuration->nprach_Periodicity[0]; - nprach_parameters[0].nprach_StartTime_r13 = configuration->nprach_StartTime[0]; - nprach_parameters[0].nprach_SubcarrierOffset_r13 = configuration->nprach_SubcarrierOffset[0]; - nprach_parameters[0].nprach_NumSubcarriers_r13 = configuration->nprach_NumSubcarriers[0]; - nprach_parameters[0].numRepetitionsPerPreambleAttempt_r13 = configuration->numRepetitionsPerPreambleAttempt_NB[0]; - nprach_parameters[0].nprach_SubcarrierMSG3_RangeStart_r13 = configuration->nprach_SubcarrierMSG3_RangeStart; - nprach_parameters[0].maxNumPreambleAttemptCE_r13 = configuration->maxNumPreambleAttemptCE_NB; - nprach_parameters[0].npdcch_NumRepetitions_RA_r13 = configuration->npdcch_NumRepetitions_RA[0]; - nprach_parameters[0].npdcch_StartSF_CSS_RA_r13 = configuration->npdcch_StartSF_CSS_RA[0]; - nprach_parameters[0].npdcch_Offset_RA_r13 = configuration->npdcch_Offset_RA[0]; - - nprach_parameters[1].nprach_Periodicity_r13 = configuration->nprach_Periodicity[1]; - nprach_parameters[1].nprach_StartTime_r13 = configuration->nprach_StartTime[1]; - nprach_parameters[1].nprach_SubcarrierOffset_r13 = configuration->nprach_SubcarrierOffset[1]; - nprach_parameters[1].nprach_NumSubcarriers_r13 = configuration->nprach_NumSubcarriers[1]; - nprach_parameters[1].numRepetitionsPerPreambleAttempt_r13 = configuration->numRepetitionsPerPreambleAttempt_NB[1]; - nprach_parameters[1].nprach_SubcarrierMSG3_RangeStart_r13 = configuration->nprach_SubcarrierMSG3_RangeStart; - nprach_parameters[1].maxNumPreambleAttemptCE_r13 = configuration->maxNumPreambleAttemptCE_NB; - nprach_parameters[1].npdcch_NumRepetitions_RA_r13 = configuration->npdcch_NumRepetitions_RA[1]; - nprach_parameters[1].npdcch_StartSF_CSS_RA_r13 = configuration->npdcch_StartSF_CSS_RA[1]; - nprach_parameters[1].npdcch_Offset_RA_r13 = configuration->npdcch_Offset_RA[1]; - - nprach_parameters[2].nprach_Periodicity_r13 = configuration->nprach_Periodicity[2]; - nprach_parameters[2].nprach_StartTime_r13 = configuration->nprach_StartTime[2]; - nprach_parameters[2].nprach_SubcarrierOffset_r13 = configuration->nprach_SubcarrierOffset[2]; - nprach_parameters[2].nprach_NumSubcarriers_r13 = configuration->nprach_NumSubcarriers[2]; - nprach_parameters[2].numRepetitionsPerPreambleAttempt_r13 = configuration->numRepetitionsPerPreambleAttempt_NB[2]; - nprach_parameters[2].nprach_SubcarrierMSG3_RangeStart_r13 = configuration->nprach_SubcarrierMSG3_RangeStart; - nprach_parameters[2].maxNumPreambleAttemptCE_r13 = configuration->maxNumPreambleAttemptCE_NB; - nprach_parameters[2].npdcch_NumRepetitions_RA_r13 = configuration->npdcch_NumRepetitions_RA[2]; - nprach_parameters[2].npdcch_StartSF_CSS_RA_r13 = configuration->npdcch_StartSF_CSS_RA[2]; - nprach_parameters[2].npdcch_Offset_RA_r13 = configuration->npdcch_Offset_RA[2]; - - - //nprach_parameterList have a max size of 3 possible nprach configuration (see maxNPRACH_Resources_NB_r13) - ASN_SEQUENCE_ADD(&sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.nprach_ParametersList_r13.list,&nprach_parameters[0]); - ASN_SEQUENCE_ADD(&sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.nprach_ParametersList_r13.list,&nprach_parameters[1]); - ASN_SEQUENCE_ADD(&sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.nprach_ParametersList_r13.list,&nprach_parameters[2]); - - // NPDSCH-Config NB-IOT - sib2_NB_IoT->radioResourceConfigCommon_r13.npdsch_ConfigCommon_r13.nrs_Power_r13= configuration->npdsch_nrs_Power; - - - //NPUSCH-Config NB-IoT---------------------------------------------------------------- - //list of size 3 (see maxNPRACH_Resources_NB_r13) - ack_nack_repetition = configuration-> npusch_ack_nack_numRepetitions_NB; //is an enumerative - ASN_SEQUENCE_ADD(&(sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.ack_NACK_NumRepetitions_Msg4_r13.list) ,&ack_nack_repetition); - - *srs_SubframeConfig = configuration->npusch_srs_SubframeConfig_NB; - sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.srs_SubframeConfig_r13= srs_SubframeConfig; /*OPTIONAL*/ - - - /*OPTIONAL*/ - dmrs_config = CALLOC(1,sizeof(struct NPUSCH_ConfigCommon_NB_r13__dmrs_Config_r13)); - dmrs_config->threeTone_CyclicShift_r13 = configuration->npusch_threeTone_CyclicShift_r13; - dmrs_config->sixTone_CyclicShift_r13 = configuration->npusch_sixTone_CyclicShift_r13; - - /*OPTIONAL - * -define the base sequence for a DMRS sequence in a cell with multi tone transmission (3,6,12) see TS 36.331 NPUSCH-Config-NB - * -if not defined will be calculated based on the cellID once we configure the phy layer (rrc_mac_config_req) through the config_sib2 */ - dmrs_config->threeTone_BaseSequence_r13 = NULL; - dmrs_config->sixTone_BaseSequence_r13 = NULL; - dmrs_config->twelveTone_BaseSequence_r13 = NULL; - - sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.dmrs_Config_r13 = dmrs_config; - - //ulReferenceSignalsNPUSCH - /*Reference Signal (RS) for UL in NB-IoT is called DRS (Demodulation Reference Signal) - * sequence-group hopping can be enabled or disabled by means of the cell-specific parameter groupHoppingEnabled_r13 - * sequence-group hopping can be disabled for certain specific UE through the parameter groupHoppingDisabled (physicalConfigDedicated) - * groupAssignmentNPUSCH--> is used for generate the sequence-shift pattern - */ - sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.ul_ReferenceSignalsNPUSCH_r13.groupHoppingEnabled_r13= configuration->npusch_groupHoppingEnabled; - sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.ul_ReferenceSignalsNPUSCH_r13.groupAssignmentNPUSCH_r13 =configuration->npusch_groupAssignmentNPUSCH_r13; - - - //dl_GAP---------------------------------------------------------------------------------/*OPTIONAL*/ - dl_Gap = CALLOC(1,sizeof(struct DL_GapConfig_NB_r13)); - dl_Gap->dl_GapDurationCoeff_r13= configuration-> dl_GapDurationCoeff_NB; - dl_Gap->dl_GapPeriodicity_r13= configuration->dl_GapPeriodicity_NB; - dl_Gap->dl_GapThreshold_r13= configuration->dl_GapThreshold_NB; - sib2_NB_IoT->radioResourceConfigCommon_r13.dl_Gap_r13 = dl_Gap; - - - // uplinkPowerControlCommon - NB-IoT------------------------------------------------------ - sib2_NB_IoT->radioResourceConfigCommon_r13.uplinkPowerControlCommon_r13.p0_NominalNPUSCH_r13 = configuration->npusch_p0_NominalNPUSCH; - sib2_NB_IoT->radioResourceConfigCommon_r13.uplinkPowerControlCommon_r13.deltaPreambleMsg3_r13 = configuration->deltaPreambleMsg3; - sib2_NB_IoT->radioResourceConfigCommon_r13.uplinkPowerControlCommon_r13.alpha_r13 = configuration->npusch_alpha; - //no deltaFlist_PUCCH and no UL cyclic prefix - - // UE Timers and Constants -NB-IoT-------------------------------------------------------- - sib2_NB_IoT->ue_TimersAndConstants_r13.t300_r13 = configuration-> ue_TimersAndConstants_t300_NB; - sib2_NB_IoT->ue_TimersAndConstants_r13.t301_r13 = configuration-> ue_TimersAndConstants_t301_NB; - sib2_NB_IoT->ue_TimersAndConstants_r13.t310_r13 = configuration-> ue_TimersAndConstants_t310_NB; - sib2_NB_IoT->ue_TimersAndConstants_r13.t311_r13 = configuration-> ue_TimersAndConstants_t311_NB; - sib2_NB_IoT->ue_TimersAndConstants_r13.n310_r13 = configuration-> ue_TimersAndConstants_n310_NB; - sib2_NB_IoT->ue_TimersAndConstants_r13.n311_r13 = configuration-> ue_TimersAndConstants_n311_NB; - - //other SIB2-NB Parameters-------------------------------------------------------------------------------- - sib2_NB_IoT->freqInfo_r13.additionalSpectrumEmission_r13 = 1; - sib2_NB_IoT->freqInfo_r13.ul_CarrierFreq_r13 = NULL; /*OPTIONAL*/ - - sib2_NB_IoT->timeAlignmentTimerCommon_r13=TimeAlignmentTimer_infinity;//TimeAlignmentTimer_sf5120; - - /*OPTIONAL*/ - sib2_NB_IoT->multiBandInfoList_r13 = NULL; - -/// SIB3-NB------------------------------------------------------- - - sib3_NB_IoT->cellReselectionInfoCommon_r13.q_Hyst_r13=SystemInformationBlockType3_NB_r13__cellReselectionInfoCommon_r13__q_Hyst_r13_dB4; - sib3_NB_IoT->cellReselectionServingFreqInfo_r13.s_NonIntraSearch_r13=0; //or define in configuration? - - sib3_NB_IoT->intraFreqCellReselectionInfo_r13.q_RxLevMin_r13 = -70; - //new - sib3_NB_IoT->intraFreqCellReselectionInfo_r13.q_QualMin_r13 = CALLOC(1,sizeof(*sib3_NB_IoT->intraFreqCellReselectionInfo_r13.q_QualMin_r13)); - *(sib3_NB_IoT->intraFreqCellReselectionInfo_r13.q_QualMin_r13)= 10; //a caso - - sib3_NB_IoT->intraFreqCellReselectionInfo_r13.p_Max_r13 = NULL; - sib3_NB_IoT->intraFreqCellReselectionInfo_r13.s_IntraSearchP_r13 = 31; // s_intraSearch --> s_intraSearchP!!! (they call in a different way) - sib3_NB_IoT->intraFreqCellReselectionInfo_r13.t_Reselection_r13=1; - - //how to manage? - sib3_NB_IoT->freqBandInfo_r13 = NULL; - sib3_NB_IoT->multiBandInfoList_r13 = NULL; - - -///BCCH message (generate the SI message) - bcch_message->message.present = BCCH_DL_SCH_MessageType_NB_PR_c1; - bcch_message->message.choice.c1.present = BCCH_DL_SCH_MessageType_NB__c1_PR_systemInformation_r13; - - bcch_message->message.choice.c1.choice.systemInformation_r13.criticalExtensions.present = SystemInformation_NB__criticalExtensions_PR_systemInformation_r13; - bcch_message->message.choice.c1.choice.systemInformation_r13.criticalExtensions.choice.systemInformation_r13.sib_TypeAndInfo_r13.list.count=0; - - ASN_SEQUENCE_ADD(&bcch_message->message.choice.c1.choice.systemInformation_r13.criticalExtensions.choice.systemInformation_r13.sib_TypeAndInfo_r13.list, - sib2_NB_part); - ASN_SEQUENCE_ADD(&bcch_message->message.choice.c1.choice.systemInformation_r13.criticalExtensions.choice.systemInformation_r13.sib_TypeAndInfo_r13.list, - sib3_NB_part); - -#ifdef XER_PRINT - xer_fprint(stdout, &asn_DEF_BCCH_DL_SCH_Message_NB, (void*)bcch_message); -#endif - enc_rval = uper_encode_to_buffer(&asn_DEF_BCCH_DL_SCH_Message_NB, - (void*)bcch_message, - carrier->SIB23_NB_IoT, - 900); -// AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", -// enc_rval.failed_type->name, enc_rval.encoded); - -//#if defined(ENABLE_ITTI)..... - - -#ifdef USER_MODE - LOG_D(RRC,"[NB-IoT] SystemInformation-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif - - if (enc_rval.encoded==-1) { - msg("[RRC] ASN1 : SI-NB encoding failed for SIB23_NB_IoT\n"); - return(-1); - } - - carrier->sib2_NB_IoT = sib2_NB_IoT; - carrier->sib3_NB_IoT = sib3_NB_IoT; - - return((enc_rval.encoded+7)/8); -} - -/*do_RRCConnectionSetup_NB_IoT--> the aim is to establish SRB1 and SRB1bis(implicitly)*/ -uint8_t do_RRCConnectionSetup_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, - int CC_id, - uint8_t* const buffer, //Srb0.Tx_buffer.Payload - const uint8_t Transaction_id, - const NB_IoT_DL_FRAME_PARMS* const frame_parms, // maybe not used - SRB_ToAddModList_NB_r13_t** SRB_configList_NB_IoT, //for both SRB1bis and SRB1 - struct PhysicalConfigDedicated_NB_r13** physicalConfigDedicated_NB_IoT -) - -{ - - asn_enc_rval_t enc_rval; - - - //MP:logical channel group not defined for Nb-IoT - - //MP: logical channel priority pag 605 (is 1 for SRB1 and for SRB1bis should be the same) - //long* prioritySRB1 = NULL; - long* prioritySRB1bis = NULL; - BOOLEAN_t* logicalChannelSR_Prohibit =NULL; //pag 605 - BOOLEAN_t* npusch_AllSymbols= NULL; - -// struct SRB_ToAddMod_NB_r13* SRB1_config_NB = NULL; -// struct SRB_ToAddMod_NB_r13__rlc_Config_r13* SRB1_rlc_config_NB = NULL; -// struct SRB_ToAddMod_NB_r13__logicalChannelConfig_r13* SRB1_lchan_config_NB = NULL; - - struct SRB_ToAddMod_NB_r13* SRB1bis_config_NB_IoT = NULL; - struct SRB_ToAddMod_NB_r13__rlc_Config_r13* SRB1bis_rlc_config_NB_IoT = NULL; - struct SRB_ToAddMod_NB_r13__logicalChannelConfig_r13* SRB1bis_lchan_config_NB_IoT = NULL; - - //No UL_specific parameters for NB-IoT in LogicalChanelConfig-NB - - PhysicalConfigDedicated_NB_r13_t* physicalConfigDedicated2_NB_IoT = NULL; - DL_CCCH_Message_NB_t dl_ccch_msg_NB_IoT; - RRCConnectionSetup_NB_t* rrcConnectionSetup_NB_IoT = NULL; - - memset((void *)&dl_ccch_msg_NB_IoT,0,sizeof(DL_CCCH_Message_NB_t)); - dl_ccch_msg_NB_IoT.message.present = DL_CCCH_MessageType_NB_PR_c1; - dl_ccch_msg_NB_IoT.message.choice.c1.present = DL_CCCH_MessageType_NB__c1_PR_rrcConnectionSetup_r13; - rrcConnectionSetup_NB_IoT = &dl_ccch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionSetup_r13; - - - if (*SRB_configList_NB_IoT) { - free(*SRB_configList_NB_IoT); - } - *SRB_configList_NB_IoT = CALLOC(1,sizeof(SRB_ToAddModList_NB_r13_t)); - -/// SRB1-------------------- - { -// SRB1_config_NB = CALLOC(1,sizeof(*SRB1_config_NB)); -// -// //no srb_Identity in SRB_ToAddMod_NB -// -// SRB1_rlc_config_NB = CALLOC(1,sizeof(*SRB1_rlc_config_NB)); -// SRB1_config_NB->rlc_Config_r13 = SRB1_rlc_config_NB; -// -// SRB1_rlc_config_NB->present = SRB_ToAddMod_NB_r13__rlc_Config_r13_PR_explicitValue; -// SRB1_rlc_config_NB->choice.explicitValue.present=RLC_Config_NB_r13_PR_am;//the only possible in NB_IoT -// -//// SRB1_rlc_config_NB->choice.explicitValue.choice.am.ul_AM_RLC_r13.t_PollRetransmit_r13 = enb_properties.properties[ctxt_pP->module_id]->srb1_timer_poll_retransmit_r13; -//// SRB1_rlc_config_NB->choice.explicitValue.choice.am.ul_AM_RLC_r13.maxRetxThreshold_r13 = enb_properties.properties[ctxt_pP->module_id]->srb1_max_retx_threshold_r13; -//// //(musT be disabled--> SRB1 config pag 640 specs ) -//// SRB1_rlc_config_NB->choice.explicitValue.choice.am.dl_AM_RLC_r13.enableStatusReportSN_Gap_r13 =NULL; -// -// -// SRB1_rlc_config_NB->choice.explicitValue.choice.am.ul_AM_RLC_r13.t_PollRetransmit_r13 = T_PollRetransmit_NB_r13_ms25000; -// SRB1_rlc_config_NB->choice.explicitValue.choice.am.ul_AM_RLC_r13.maxRetxThreshold_r13 = UL_AM_RLC_NB_r13__maxRetxThreshold_r13_t8; -// //(musT be disabled--> SRB1 config pag 640 specs ) -// SRB1_rlc_config_NB->choice.explicitValue.choice.am.dl_AM_RLC_r13.enableStatusReportSN_Gap_r13 = NULL; -// -// SRB1_lchan_config_NB = CALLOC(1,sizeof(*SRB1_lchan_config_NB)); -// SRB1_config_NB->logicalChannelConfig_r13 = SRB1_lchan_config_NB; -// -// SRB1_lchan_config_NB->present = SRB_ToAddMod_NB_r13__logicalChannelConfig_r13_PR_explicitValue; -// -// -// prioritySRB1 = CALLOC(1, sizeof(long)); -// *prioritySRB1 = 1; -// SRB1_lchan_config_NB->choice.explicitValue.priority_r13 = prioritySRB1; -// -// logicalChannelSR_Prohibit = CALLOC(1, sizeof(BOOLEAN_t)); -// *logicalChannelSR_Prohibit = 1; -// //schould be set to TRUE (specs pag 641) -// SRB1_lchan_config_NB->choice.explicitValue.logicalChannelSR_Prohibit_r13 = logicalChannelSR_Prohibit; -// -// //ADD SRB1 -// ASN_SEQUENCE_ADD(&(*SRB_configList_NB_IoT)->list,SRB1_config_NB); - } - -///SRB1bis (The configuration for SRB1 and SRB1bis is the same) the only difference is the logical channel identity = 3 but not set here - - SRB1bis_config_NB_IoT = CALLOC(1,sizeof(*SRB1bis_config_NB_IoT)); - - //no srb_Identity in SRB_ToAddMod_NB - SRB1bis_rlc_config_NB_IoT = CALLOC(1,sizeof(*SRB1bis_rlc_config_NB_IoT)); - SRB1bis_config_NB_IoT->rlc_Config_r13 = SRB1bis_rlc_config_NB_IoT; - - SRB1bis_rlc_config_NB_IoT->present = SRB_ToAddMod_NB_r13__rlc_Config_r13_PR_explicitValue; - SRB1bis_rlc_config_NB_IoT->choice.explicitValue.present=RLC_Config_NB_r13_PR_am;//MP: the only possible RLC config in NB_IoT - - SRB1bis_rlc_config_NB_IoT->choice.explicitValue.choice.am.ul_AM_RLC_r13.t_PollRetransmit_r13 = T_PollRetransmit_NB_r13_ms25000; - SRB1bis_rlc_config_NB_IoT->choice.explicitValue.choice.am.ul_AM_RLC_r13.maxRetxThreshold_r13 = UL_AM_RLC_NB_r13__maxRetxThreshold_r13_t8; - //(musT be disabled--> SRB1 config pag 640 specs ) - SRB1bis_rlc_config_NB_IoT->choice.explicitValue.choice.am.dl_AM_RLC_r13.enableStatusReportSN_Gap_r13 =NULL; - - SRB1bis_lchan_config_NB_IoT = CALLOC(1,sizeof(*SRB1bis_lchan_config_NB_IoT)); - SRB1bis_config_NB_IoT->logicalChannelConfig_r13 = SRB1bis_lchan_config_NB_IoT; - - SRB1bis_lchan_config_NB_IoT->present = SRB_ToAddMod_NB_r13__logicalChannelConfig_r13_PR_explicitValue; - - prioritySRB1bis = CALLOC(1, sizeof(long)); - *prioritySRB1bis = 1; //same as SRB1? - SRB1bis_lchan_config_NB_IoT->choice.explicitValue.priority_r13 = prioritySRB1bis; - - logicalChannelSR_Prohibit = CALLOC(1, sizeof(BOOLEAN_t)); - *logicalChannelSR_Prohibit = 1; //schould be set to TRUE (specs pag 641) - SRB1bis_lchan_config_NB_IoT->choice.explicitValue.logicalChannelSR_Prohibit_r13 = logicalChannelSR_Prohibit; - - //ADD SRB1bis - //MP: Actually there is no way to distinguish SRB1 and SRB1bis once put in the list - //MP: SRB_ToAddModList_NB_r13_t size = 1 - ASN_SEQUENCE_ADD(&(*SRB_configList_NB_IoT)->list,SRB1bis_config_NB_IoT); - - - // PhysicalConfigDedicated (NPDCCH, NPUSCH, CarrierConfig, UplinkPowerControl) - - physicalConfigDedicated2_NB_IoT = CALLOC(1,sizeof(*physicalConfigDedicated2_NB_IoT)); - *physicalConfigDedicated_NB_IoT = physicalConfigDedicated2_NB_IoT; - - physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13= CALLOC(1, sizeof(*physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13)); - physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13 = CALLOC(1,sizeof(*physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13)); - physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13 = CALLOC(1,sizeof(*physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13)); - physicalConfigDedicated2_NB_IoT->uplinkPowerControlDedicated_r13 = CALLOC(1,sizeof(*physicalConfigDedicated2_NB_IoT->uplinkPowerControlDedicated_r13)); - - //no tpc, no cqi and no pucch, no pdsch, no soundingRS, no AntennaInfo, no scheduling request config - - /* - * NB-IoT supports the operation with either one or two antenna ports, AP0 and AP1. - * For the latter case, Space Frequency Block Coding (SFBC) is applied. - * Once selected, the same transmission scheme applies to NPBCH, NPDCCH, and NPDSCH. - * */ - - //FIXME: MP: CarrierConfigDedicated check the set values ---------------------------------------------- - - //DL - - physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.dl_CarrierFreq_r13.carrierFreq_r13=0;//random value set - physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.downlinkBitmapNonAnchor_r13= CALLOC(1,sizeof(struct DL_CarrierConfigDedicated_NB_r13__downlinkBitmapNonAnchor_r13)); - physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.downlinkBitmapNonAnchor_r13->present= - DL_CarrierConfigDedicated_NB_r13__downlinkBitmapNonAnchor_r13_PR_useNoBitmap_r13; - - physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.dl_GapNonAnchor_r13 = CALLOC(1,sizeof(struct DL_CarrierConfigDedicated_NB_r13__dl_GapNonAnchor_r13)); - physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.dl_GapNonAnchor_r13->present = - DL_CarrierConfigDedicated_NB_r13__dl_GapNonAnchor_r13_PR_useNoGap_r13; - - physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.inbandCarrierInfo_r13= NULL; - - //UL - physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->ul_CarrierConfig_r13.ul_CarrierFreq_r13= NULL; - - // NPDCCH - physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13->npdcch_NumRepetitions_r13 =0; - physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13->npdcch_Offset_USS_r13 =0; - physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13->npdcch_StartSF_USS_r13=0; - - // NPUSCH //(specs TS 36.331 v14.2.1 pag 643) /* OPTIONAL */ - physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13->ack_NACK_NumRepetitions_r13= NULL; - npusch_AllSymbols= CALLOC(1, sizeof(BOOLEAN_t)); - *npusch_AllSymbols= 1; //TRUE - physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13->npusch_AllSymbols_r13= npusch_AllSymbols; /* OPTIONAL */ - physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13->groupHoppingDisabled_r13=NULL; /* OPTIONAL */ - - // UplinkPowerControlDedicated - physicalConfigDedicated2_NB_IoT->uplinkPowerControlDedicated_r13->p0_UE_NPUSCH_r13 = 0; // 0 dB (specs TS36.331 v14.2.1 pag 643) - - - //Fill the rrcConnectionSetup-NB message - rrcConnectionSetup_NB_IoT->rrc_TransactionIdentifier = Transaction_id; //input value - rrcConnectionSetup_NB_IoT->criticalExtensions.present = RRCConnectionSetup_NB__criticalExtensions_PR_c1; - rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.present =RRCConnectionSetup_NB__criticalExtensions__c1_PR_rrcConnectionSetup_r13 ; - //MP: carry only SRB1bis at the moment and phyConfigDedicated - rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.srb_ToAddModList_r13 = *SRB_configList_NB_IoT; - rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.drb_ToAddModList_r13 = NULL; - rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.drb_ToReleaseList_r13 = NULL; - rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.rlf_TimersAndConstants_r13 = NULL; - rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.physicalConfigDedicated_r13 = physicalConfigDedicated2_NB_IoT; - rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.mac_MainConfig_r13 = NULL; - -#ifdef XER_PRINT - xer_fprint(stdout, &asn_DEF_DL_CCCH_Message, (void*)&dl_ccch_msg); -#endif - enc_rval = uper_encode_to_buffer(&asn_DEF_DL_CCCH_Message_NB, - (void*)&dl_ccch_msg_NB_IoT, - buffer, - 100); - - if (enc_rval.encoded <= 0) { - LOG_F(RRC, "ASN1 message encoding failed (%s, %lu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - } - -#ifdef USER_MODE - LOG_D(RRC,"RRCConnectionSetup-NB Encoded %zd bits (%zd bytes), ecause %d\n", - enc_rval.encoded,(enc_rval.encoded+7)/8,ecause); -#endif - - return((enc_rval.encoded+7)/8); -} - -/*do_SecurityModeCommand - exactly the same as previous implementation*/ -uint8_t do_SecurityModeCommand_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - uint8_t* const buffer, - const uint8_t Transaction_id, - const uint8_t cipheringAlgorithm, - const uint8_t integrityProtAlgorithm) -{ - DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; - asn_enc_rval_t enc_rval; - - memset(&dl_dcch_msg_NB_IoT,0,sizeof(DL_DCCH_Message_NB_t)); - - dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; - dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_securityModeCommand_r13; - - dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.rrc_TransactionIdentifier = Transaction_id; - dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.criticalExtensions.present = SecurityModeCommand__criticalExtensions_PR_c1; - - dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.criticalExtensions.choice.c1.present = - SecurityModeCommand__criticalExtensions__c1_PR_securityModeCommand_r8; - - // the two following information could be based on the mod_id - dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.cipheringAlgorithm - = (CipheringAlgorithm_r12_t)cipheringAlgorithm; //bug solved - - dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.integrityProtAlgorithm - = (e_SecurityAlgorithmConfig__integrityProtAlgorithm)integrityProtAlgorithm; - -//only changed "asn_DEF_DL_DCCH_Message_NB" -#ifdef XER_PRINT - xer_fprint(stdout, &asn_DEF_DL_DCCH_Message_NB, (void*)&dl_dcch_msg_NB_IoT); -#endif - enc_rval = uper_encode_to_buffer(&asn_DEF_DL_DCCH_Message_NB, - (void*)&dl_dcch_msg_NB_IoT, - buffer, - 100); - if (enc_rval.encoded <= 0) { - LOG_F(RRC, "ASN1 message encoding failed (%s, %lu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - } - - -//#if defined(ENABLE_ITTI) -//# if !defined(DISABLE_XER_SPRINT).... - -#ifdef USER_MODE - LOG_D(RRC,"[NB-IoT %d] securityModeCommand-NB for UE %x Encoded %zd bits (%zd bytes)\n", - ctxt_pP->module_id, - ctxt_pP->rnti, - enc_rval.encoded, - (enc_rval.encoded+7)/8); -#endif - - if (enc_rval.encoded==-1) { - LOG_E(RRC,"[NB-IoT %d] ASN1 : securityModeCommand-NB encoding failed for UE %x\n", - ctxt_pP->module_id, - ctxt_pP->rnti); - return(-1); - } - - return((enc_rval.encoded+7)/8); -} - -/*do_UECapabilityEnquiry_NB_IoT - very similar to legacy lte*/ -uint8_t do_UECapabilityEnquiry_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - uint8_t* const buffer, - const uint8_t Transaction_id -) - -{ - - DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; - //no RAT type in NB-IoT - asn_enc_rval_t enc_rval; - - memset(&dl_dcch_msg_NB_IoT,0,sizeof(DL_DCCH_Message_NB_t)); - - dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; - dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_ueCapabilityEnquiry_r13; - - dl_dcch_msg_NB_IoT.message.choice.c1.choice.ueCapabilityEnquiry_r13.rrc_TransactionIdentifier = Transaction_id; - - dl_dcch_msg_NB_IoT.message.choice.c1.choice.ueCapabilityEnquiry_r13.criticalExtensions.present = UECapabilityEnquiry_NB__criticalExtensions_PR_c1; - dl_dcch_msg_NB_IoT.message.choice.c1.choice.ueCapabilityEnquiry_r13.criticalExtensions.choice.c1.present = - UECapabilityEnquiry_NB__criticalExtensions__c1_PR_ueCapabilityEnquiry_r13; - - //no ue_CapabilityRequest (list of RAT_Type) - -//only changed "asn_DEF_DL_DCCH_Message_NB" -#ifdef XER_PRINT - xer_fprint(stdout, &asn_DEF_DL_DCCH_Message_NB, (void*)&dl_dcch_msg_NB_IoT); -#endif - enc_rval = uper_encode_to_buffer(&asn_DEF_DL_DCCH_Message_NB, - (void*)&dl_dcch_msg_NB_IoT, - buffer, - 100); - if (enc_rval.encoded <= 0) { - LOG_F(RRC, "ASN1 message encoding failed (%s, %lu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - } - -//#if defined(ENABLE_ITTI) -//# if !defined(DISABLE_XER_SPRINT).... - -#ifdef USER_MODE - LOG_D(RRC,"[NB-IoT %d] UECapabilityEnquiry-NB for UE %x Encoded %zd bits (%zd bytes)\n", - ctxt_pP->module_id, - ctxt_pP->rnti, - enc_rval.encoded, - (enc_rval.encoded+7)/8); -#endif - - if (enc_rval.encoded==-1) { - LOG_E(RRC,"[NB-IoT %d] ASN1 : UECapabilityEnquiry-NB encoding failed for UE %x\n", - ctxt_pP->module_id, - ctxt_pP->rnti); - return(-1); - } - - return((enc_rval.encoded+7)/8); -} - -/*do_RRCConnectionReconfiguration_NB_IoT-->may convey information for resource configuration - * (including RBs, MAC main configuration and physical channel configuration) - * including any associated dedicated NAS information.*/ -uint16_t do_RRCConnectionReconfiguration_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - uint8_t *buffer, - uint8_t Transaction_id, - SRB_ToAddModList_NB_r13_t *SRB1_list_NB, //SRB_ConfigList2 (default)--> only SRB1 - DRB_ToAddModList_NB_r13_t *DRB_list_NB_IoT, //DRB_ConfigList (default) - DRB_ToReleaseList_NB_r13_t *DRB_list2_NB_IoT, //is NULL when passed - struct PhysicalConfigDedicated_NB_r13 *physicalConfigDedicated_NB_IoT, - MAC_MainConfig_NB_r13_t *mac_MainConfig_NB_IoT, - struct RRCConnectionReconfiguration_NB_r13_IEs__dedicatedInfoNASList_r13* dedicatedInfoNASList_NB_IoT) - -{ - - //check on DRB_list if contains more than 2 DRB? - - asn_enc_rval_t enc_rval; - DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; - RRCConnectionReconfiguration_NB_t *rrcConnectionReconfiguration_NB; - - - memset(&dl_dcch_msg_NB_IoT,0,sizeof(DL_DCCH_Message_NB_t)); - - dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; - dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_rrcConnectionReconfiguration_r13; - rrcConnectionReconfiguration_NB = &dl_dcch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionReconfiguration_r13; - - // RRCConnectionReconfiguration - rrcConnectionReconfiguration_NB->rrc_TransactionIdentifier = Transaction_id; - rrcConnectionReconfiguration_NB->criticalExtensions.present = RRCConnectionReconfiguration_NB__criticalExtensions_PR_c1; - rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.present =RRCConnectionReconfiguration_NB__criticalExtensions__c1_PR_rrcConnectionReconfiguration_r13 ; - - //RAdioResourceconfigDedicated - rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13 = - CALLOC(1,sizeof(*rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13)); - rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->srb_ToAddModList_r13 = SRB1_list_NB; //only SRB1 - rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->drb_ToAddModList_r13 = DRB_list_NB_IoT; - rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->drb_ToReleaseList_r13 = DRB_list2_NB_IoT; //NULL - rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->physicalConfigDedicated_r13 = physicalConfigDedicated_NB_IoT; - //FIXME may not used now - //rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->rlf_TimersAndConstants_r13 - - if (mac_MainConfig_NB_IoT!=NULL) { - rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13 = - CALLOC(1, sizeof(*rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13)); - rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13->present - =RadioResourceConfigDedicated_NB_r13__mac_MainConfig_r13_PR_explicitValue_r13; - //why memcopy only this one? - memcpy(&rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13->choice.explicitValue_r13, - mac_MainConfig_NB_IoT, sizeof(*mac_MainConfig_NB_IoT)); - - } else { - rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13=NULL; - } - - //no measConfig, measIDlist - //no mobilityControlInfo - - rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.dedicatedInfoNASList_r13 = dedicatedInfoNASList_NB_IoT; - //mainly used for cell-reselection/handover purposes?? - rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.fullConfig_r13 = NULL; - - enc_rval = uper_encode_to_buffer(&asn_DEF_DL_DCCH_Message_NB, - (void*)&dl_dcch_msg_NB_IoT, - buffer, - RRC_BUF_SIZE); - if (enc_rval.encoded <= 0) { - LOG_F(RRC, "ASN1 message encoding failed %s, %li\n", - enc_rval.failed_type->name, enc_rval.encoded); - } - - //changed only asn_DEF_DL_DCCH_Message_NB -#ifdef XER_PRINT - xer_fprint(stdout,&asn_DEF_DL_DCCH_Message_NB,(void*)&dl_dcch_msg_NB_IoT); -#endif - -//#if defined(ENABLE_ITTI) -//# if !defined(DISABLE_XER_SPRINT)... - - - LOG_I(RRC,"RRCConnectionReconfiguration-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); - - return((enc_rval.encoded+7)/8); -} - -/*do_RRCConnectionReestablishmentReject - exactly the same as legacy LTE*/ -uint8_t do_RRCConnectionReestablishmentReject_NB_IoT( - uint8_t Mod_id, - uint8_t* const buffer) -{ - - asn_enc_rval_t enc_rval; - - DL_CCCH_Message_NB_t dl_ccch_msg_NB_IoT; - RRCConnectionReestablishmentReject_t *rrcConnectionReestablishmentReject; - - memset((void *)&dl_ccch_msg_NB_IoT,0,sizeof(DL_CCCH_Message_NB_t)); - dl_ccch_msg_NB_IoT.message.present = DL_CCCH_MessageType_NB_PR_c1; - dl_ccch_msg_NB_IoT.message.choice.c1.present = DL_CCCH_MessageType_NB__c1_PR_rrcConnectionReestablishmentReject_r13; - rrcConnectionReestablishmentReject = &dl_ccch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionReestablishmentReject_r13; - - // RRCConnectionReestablishmentReject //exactly the same as LTE - rrcConnectionReestablishmentReject->criticalExtensions.present = RRCConnectionReestablishmentReject__criticalExtensions_PR_rrcConnectionReestablishmentReject_r8; - - //Only change in "asn_DEF_DL_CCCH_Message_NB" -#ifdef XER_PRINT - xer_fprint(stdout, &asn_DEF_DL_CCCH_Message_NB, (void*)&dl_ccch_msg_NB_IoT); -#endif - enc_rval = uper_encode_to_buffer(&asn_DEF_DL_CCCH_Message_NB, - (void*)&dl_ccch_msg_NB_IoT, - buffer, - 100); - if (enc_rval.encoded <= 0) { - LOG_F(RRC,"ASN1 message encoding failed (%s, %lu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - } - - //Only change in "asn_DEF_DL_CCCH_Message_NB" -#if defined(ENABLE_ITTI) -# if !defined(DISABLE_XER_SPRINT) - { - char message_string[20000]; - size_t message_string_size; - - if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_DL_CCCH_Message_NB, (void *) &dl_ccch_msg_NB_IoT)) > 0) { - MessageDef *msg_p; - - msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB_NB_IoT, RRC_DL_CCCH, message_string_size + sizeof (IttiMsgText)); - msg_p->ittiMsg.rrc_dl_ccch.size = message_string_size; - memcpy(&msg_p->ittiMsg.rrc_dl_ccch.text, message_string, message_string_size); - - itti_send_msg_to_task(TASK_UNKNOWN, Mod_id, msg_p); - } - } -# endif -#endif - -#ifdef USER_MODE - LOG_D(RRC,"RRCConnectionReestablishmentReject Encoded %zd bits (%zd bytes)\n", - enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif - - return((enc_rval.encoded+7)/8); -} - -/*do_RRCConnectionReject_NB_IoT*/ -uint8_t do_RRCConnectionReject_NB_IoT( - uint8_t Mod_id, - uint8_t* const buffer) - -{ - - asn_enc_rval_t enc_rval; - - DL_CCCH_Message_NB_t dl_ccch_msg_NB_IoT; - RRCConnectionReject_NB_t *rrcConnectionReject_NB_IoT; - - memset((void *)&dl_ccch_msg_NB_IoT,0,sizeof(DL_CCCH_Message_NB_t)); - dl_ccch_msg_NB_IoT.message.present = DL_CCCH_MessageType_NB_PR_c1; - dl_ccch_msg_NB_IoT.message.choice.c1.present = DL_CCCH_MessageType_NB__c1_PR_rrcConnectionReject_r13; - rrcConnectionReject_NB_IoT = &dl_ccch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionReject_r13; - - // RRCConnectionReject-NB_IoT - rrcConnectionReject_NB_IoT->criticalExtensions.present = RRCConnectionReject_NB__criticalExtensions_PR_c1; - rrcConnectionReject_NB_IoT->criticalExtensions.choice.c1.present = RRCConnectionReject_NB__criticalExtensions__c1_PR_rrcConnectionReject_r13; - /* let's put an extended wait time of 1s for the moment */ - rrcConnectionReject_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReject_r13.extendedWaitTime_r13 = 1; - //new-use of suspend indication - //If present, this field indicates that the UE should remain suspended and not release its stored context. - rrcConnectionReject_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReject_r13.rrc_SuspendIndication_r13= - CALLOC(1, sizeof(long)); - *(rrcConnectionReject_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReject_r13.rrc_SuspendIndication_r13)= - RRCConnectionReject_NB_r13_IEs__rrc_SuspendIndication_r13_true; - - //Only Modified "asn_DEF_DL_CCCH_Message_NB" -#ifdef XER_PRINT - xer_fprint(stdout, &asn_DEF_DL_CCCH_Message_NB, (void*)&dl_ccch_msg); -#endif - enc_rval = uper_encode_to_buffer(&asn_DEF_DL_CCCH_Message_NB, - (void*)&dl_ccch_msg_NB_IoT, - buffer, - 100); - if (enc_rval.encoded <= 0) { - LOG_F(RRC, "ASN1 message encoding failed (%s, %ld)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - } - -#if defined(ENABLE_ITTI) -# if !defined(DISABLE_XER_SPRINT) - { - char message_string[20000]; - size_t message_string_size; - - if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_DL_CCCH_Message_NB, (void *) &dl_ccch_msg_NB_IoT)) > 0) { - MessageDef *msg_p; - - msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB_NB_IoT, RRC_DL_CCCH, message_string_size + sizeof (IttiMsgText)); - msg_p->ittiMsg.rrc_dl_ccch.size = message_string_size; - memcpy(&msg_p->ittiMsg.rrc_dl_ccch.text, message_string, message_string_size); - - itti_send_msg_to_task(TASK_UNKNOWN, Mod_id, msg_p); - } - } -# endif -#endif - -#ifdef USER_MODE - LOG_D(RRC,"RRCConnectionReject-NB Encoded %zd bits (%zd bytes)\n", - enc_rval.encoded,(enc_rval.encoded+7)/8); -#endif - - return((enc_rval.encoded+7)/8); -} - - -//no do_MBSFNAreaConfig(..) in NB-IoT -//no do_MeasurementReport(..) in NB-IoT - -/*do_DLInformationTransfer_NB*/ -uint8_t do_DLInformationTransfer_NB_IoT( - uint8_t Mod_id, - uint8_t **buffer, - uint8_t transaction_id, - uint32_t pdu_length, - uint8_t *pdu_buffer) - -{ - ssize_t encoded; - - DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; - - memset(&dl_dcch_msg_NB_IoT, 0, sizeof(DL_DCCH_Message_NB_t)); - - dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; - dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_dlInformationTransfer_r13; - dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.rrc_TransactionIdentifier = transaction_id; - dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.criticalExtensions.present = DLInformationTransfer_NB__criticalExtensions_PR_c1; - dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.criticalExtensions.choice.c1.present = DLInformationTransfer_NB__criticalExtensions__c1_PR_dlInformationTransfer_r13; - dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.criticalExtensions.choice.c1.choice.dlInformationTransfer_r13.dedicatedInfoNAS_r13.size = pdu_length; - dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.criticalExtensions.choice.c1.choice.dlInformationTransfer_r13.dedicatedInfoNAS_r13.buf = pdu_buffer; - - encoded = uper_encode_to_new_buffer (&asn_DEF_DL_DCCH_Message_NB, NULL, (void*) &dl_dcch_msg_NB_IoT, (void **) buffer); - - //only change in "asn_DEF_DL_DCCH_Message_NB" -#if defined(ENABLE_ITTI) -# if !defined(DISABLE_XER_SPRINT) - { - char message_string[10000]; - size_t message_string_size; - - if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_DL_DCCH_Message_NB, (void *)&dl_dcch_msg_NB_IoT)) > 0) { - MessageDef *msg_p; - - msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB_NB_IoT, RRC_DL_DCCH, message_string_size + sizeof (IttiMsgText)); - msg_p->ittiMsg.rrc_dl_dcch.size = message_string_size; - memcpy(&msg_p->ittiMsg.rrc_dl_dcch.text, message_string, message_string_size); - - itti_send_msg_to_task(TASK_UNKNOWN, Mod_id, msg_p); - } - } -# endif -#endif - - return encoded; -} - -/*do_ULInformationTransfer*/ -//for the moment is not needed (UE-SIDE) - -/*OAI_UECapability_t *fill_ue_capability*/ - -/*do_RRCConnectionReestablishment_NB-->used to re-establish SRB1*/ //which parameter to use? -uint8_t do_RRCConnectionReestablishment_NB_IoT( - uint8_t Mod_id, - uint8_t* const buffer, - const uint8_t Transaction_id, - const NB_IoT_DL_FRAME_PARMS* const frame_parms, //to be changed - SRB_ToAddModList_NB_r13_t* SRB_list_NB_IoT) //should contain SRB1 already configured? -{ - - asn_enc_rval_t enc_rval; - DL_CCCH_Message_NB_t dl_ccch_msg_NB_IoT; - RRCConnectionReestablishment_NB_t* rrcConnectionReestablishment_NB_IoT; - - memset(&dl_ccch_msg_NB_IoT, 0, sizeof(DL_CCCH_Message_NB_t)); - - dl_ccch_msg_NB_IoT.message.present = DL_CCCH_MessageType_NB_PR_c1; - dl_ccch_msg_NB_IoT.message.choice.c1.present = DL_CCCH_MessageType_NB__c1_PR_rrcConnectionReestablishment_r13; - rrcConnectionReestablishment_NB_IoT = &dl_ccch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionReestablishment_r13; - - //rrcConnectionReestablishment_NB - rrcConnectionReestablishment_NB_IoT->rrc_TransactionIdentifier = Transaction_id; - rrcConnectionReestablishment_NB_IoT->criticalExtensions.present = RRCConnectionReestablishment_NB__criticalExtensions_PR_c1; - rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.present = RRCConnectionReestablishment_NB__criticalExtensions__c1_PR_rrcConnectionReestablishment_r13; - - rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.srb_ToAddModList_r13 = SRB_list_NB_IoT; - rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.drb_ToAddModList_r13 = NULL; - rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.drb_ToReleaseList_r13 = NULL; - rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.rlf_TimersAndConstants_r13= NULL; - rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.mac_MainConfig_r13= NULL; - rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.physicalConfigDedicated_r13 = NULL; - - rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.nextHopChainingCount_r13=0; - - enc_rval = uper_encode_to_buffer(&asn_DEF_DL_CCCH_Message_NB, - (void*)&dl_ccch_msg_NB_IoT, - buffer, - RRC_BUF_SIZE); - - if (enc_rval.encoded <= 0) { - LOG_F(RRC, "ASN1 message encoding failed (%s, %li)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - } - -#ifdef XER_PRINT - xer_fprint(stdout,&asn_DEF_DL_CCCH_Message_NB,(void*)&dl_ccch_msg_NB_IoT); -#endif - -#if defined(ENABLE_ITTI) -# if !defined(DISABLE_XER_SPRINT) - { - char message_string[30000]; - size_t message_string_size; - - if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_DL_CCCH_Message_NB, (void *) &dl_ccch_msg_NB_IoT)) > 0) { - MessageDef *msg_p; - - msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB_NB_IoT, RRC_DL_CCCH, message_string_size + sizeof (IttiMsgText)); - msg_p->ittiMsg.rrc_dl_ccch.size = message_string_size; - memcpy(&msg_p->ittiMsg.rrc_dl_ccch.text, message_string, message_string_size); - - itti_send_msg_to_task(TASK_UNKNOWN, Mod_id, msg_p); - } - } -# endif -#endif - - LOG_I(RRC,"RRCConnectionReestablishment-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); - return 0; -} - -/*do_RRCConnectionRelease_NB--> is used to command the release of an RRC connection*/ -uint8_t do_RRCConnectionRelease_NB_IoT( - uint8_t Mod_id, - uint8_t *buffer, - const uint8_t Transaction_id) -{ - - asn_enc_rval_t enc_rval; - - DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; - RRCConnectionRelease_NB_t *rrcConnectionRelease_NB_IoT; - - - memset(&dl_dcch_msg_NB_IoT,0,sizeof(DL_DCCH_Message_NB_t)); - - dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; - dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_rrcConnectionRelease_r13; - rrcConnectionRelease_NB_IoT = &dl_dcch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionRelease_r13; - - // RRCConnectionRelease - rrcConnectionRelease_NB_IoT->rrc_TransactionIdentifier = Transaction_id; - rrcConnectionRelease_NB_IoT->criticalExtensions.present = RRCConnectionRelease_NB__criticalExtensions_PR_c1; - rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.present =RRCConnectionRelease_NB__criticalExtensions__c1_PR_rrcConnectionRelease_r13 ; - - rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.releaseCause_r13 = ReleaseCause_NB_r13_other; - rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.redirectedCarrierInfo_r13 = NULL; - rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.extendedWaitTime_r13 = NULL; - - //Why allocate memory for non critical extension? - rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.nonCriticalExtension=CALLOC(1, - sizeof(*rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.nonCriticalExtension)); - - enc_rval = uper_encode_to_buffer(&asn_DEF_DL_DCCH_Message_NB, - (void*)&dl_dcch_msg_NB_IoT, - buffer, - RRC_BUF_SIZE);//check - - return((enc_rval.encoded+7)/8); -} - - - - +/* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file asn1_msg.c +* \brief primitives to build the asn1 messages +* \author Raymond Knopp, Navid Nikaein and Michele Paffetti +* \date 2011, 2017 +* \version 1.0 +* \company Eurecom +* \email: raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, michele.paffetti@studio.unibo.it +*/ + +#include +#include +#include /* for atoi(3) */ +#include /* for getopt(3) */ +#include /* for strerror(3) */ +#include /* for EX_* exit codes */ +#include /* for errno */ +#include "UTIL/LOG/log.h" +#include +#include /* for _ASN_DEFAULT_STACK_MAX */ +#include +#include "asn1_msg.h" + + + +//#include for NB-IoT------------------- +#include "RRCConnectionRequest-NB.h" +#include "BCCH-DL-SCH-Message-NB.h" +#include "UL-CCCH-Message-NB.h" +#include "UL-DCCH-Message-NB.h" +#include "DL-CCCH-Message-NB.h" +#include "DL-DCCH-Message-NB.h" +#include "EstablishmentCause-NB-r13.h" +#include "RRCConnectionSetup-NB.h" +#include "SRB-ToAddModList-NB-r13.h" +#include "DRB-ToAddModList-NB-r13.h" +#include "RRC/LITE/defs_NB_IoT.h" +#include "RRCConnectionSetupComplete-NB.h" +#include "RRCConnectionReconfigurationComplete-NB.h" +#include "RRCConnectionReconfiguration-NB.h" +#include "MasterInformationBlock-NB.h" +#include "SystemInformation-NB.h" +#include "SystemInformationBlockType1.h" +#include "SIB-Type-NB-r13.h" +#include "RRCConnectionResume-NB.h" +#include "RRCConnectionReestablishment-NB.h" +#include "../defs_NB_IoT.h" +//---------------------------------------- + +//#include "PHY/defs.h" +#include "enb_config.h" + +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +#endif + + + + +/*do_MIB_NB_NB_IoT*/ +uint8_t do_MIB_NB_IoT( + rrc_eNB_carrier_data_NB_IoT_t *carrier, + uint16_t N_RB_DL,//may not needed--> for NB_IoT only 1 PRB is used + uint32_t frame, + uint32_t hyper_frame) +{ + asn_enc_rval_t enc_rval; + BCCH_BCH_Message_NB_t *mib_NB_IoT = &(carrier->mib_NB_IoT); + + /* + * systemFrameNumber-MSB: (TS 36.331 pag 576) + * define the 4 MSB of the SFN (10 bits). The last significant 6 bits will be acquired implicitly by decoding the NPBCH + * NOTE: 6 LSB will be used for counting the 64 radio frames in the TTI period (640 ms) that is exactly the MIB period + * + * hyperSFN-LSB: + * indicates the 2 least significant bits of the HSFN. The remaining 8 bits are present in SIB1-NB + * NOTE: with the 2 bits we count the 4 HSFN (is 1 SIB1-Nb modification period) while the other 6 count the number of modification periods + * + * + * NOTE: in OAI never modify the SIB messages!!?? + */ + + //XXX check if correct the bit assignment + uint8_t sfn_MSB = (uint8_t)((frame>>6) & 0x0f); // all the 4 bits are set to 1 + uint8_t hsfn_LSB = (uint8_t)(hyper_frame & 0x03); //2 bits set to 1 (0x3 = 0011) + uint16_t spare=0; //11 bits --> use uint16 + + mib_NB_IoT->message.systemFrameNumber_MSB_r13.buf = &sfn_MSB; + mib_NB_IoT->message.systemFrameNumber_MSB_r13.size = 1; //if expressed in byte + mib_NB_IoT->message.systemFrameNumber_MSB_r13.bits_unused = 4; //is byte based (so how many bits you don't use of the 8 bits of a bite + + mib_NB_IoT->message.hyperSFN_LSB_r13.buf= &hsfn_LSB; + mib_NB_IoT->message.hyperSFN_LSB_r13.size= 1; + mib_NB_IoT->message.hyperSFN_LSB_r13.bits_unused = 6; + + //XXX to be set?? + mib_NB_IoT->message.spare.buf = (uint8_t *)&spare; + mib_NB_IoT->message.spare.size = 2; + mib_NB_IoT->message.spare.bits_unused = 5; + + //decide how to set it + mib_NB_IoT->message.schedulingInfoSIB1_r13 =11; //see TS 36.213-->tables 16.4.1.3-3 ecc... + mib_NB_IoT->message.systemInfoValueTag_r13= 0; + mib_NB_IoT->message.ab_Enabled_r13 = 0; + + //to be decided + mib_NB_IoT->message.operationModeInfo_r13.present = MasterInformationBlock_NB__operationModeInfo_r13_PR_inband_SamePCI_r13; + mib_NB_IoT->message.operationModeInfo_r13.choice.inband_SamePCI_r13.eutra_CRS_SequenceInfo_r13 = 0; + + printf("[MIB] Initialization of frame information,sfn_MSB %x, hsfn_LSB %x\n", + (uint32_t)sfn_MSB, + (uint32_t)hsfn_LSB); + + enc_rval = uper_encode_to_buffer(&asn_DEF_BCCH_BCH_Message_NB, + (void*)mib_NB_IoT, + carrier->MIB_NB_IoT, + 100); + if(enc_rval.encoded <= 0) { + LOG_F(RRC, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + + if (enc_rval.encoded==-1) { + return(-1); + } + + return((enc_rval.encoded+7)/8); + +} + +/*do_SIB1_NB*/ +uint8_t do_SIB1_NB_IoT(uint8_t Mod_id, int CC_id, + rrc_eNB_carrier_data_NB_IoT_t *carrier, + NbIoTRrcConfigurationReq *configuration, + uint32_t frame + ) +{ + BCCH_DL_SCH_Message_NB_t *bcch_message= &(carrier->siblock1_NB_IoT); + SystemInformationBlockType1_NB_t **sib1_NB_IoT= &(carrier->sib1_NB_IoT); + + + asn_enc_rval_t enc_rval; + + PLMN_IdentityInfo_NB_r13_t PLMN_identity_info_NB_IoT; + MCC_MNC_Digit_t dummy_mcc[3],dummy_mnc[3]; + SchedulingInfo_NB_r13_t *schedulingInfo_NB_IoT; + SIB_Type_NB_r13_t *sib_type_NB_IoT; + + + long* attachWithoutPDN_Connectivity = NULL; + attachWithoutPDN_Connectivity = CALLOC(1,sizeof(long)); + long *nrs_CRS_PowerOffset=NULL; + nrs_CRS_PowerOffset = CALLOC(1, sizeof(long)); + long *eutraControlRegionSize=NULL; //this parameter should be set only if we are considering in-band operating mode (samePCI or differentPCI) + eutraControlRegionSize = CALLOC(1,sizeof(long)); + long systemInfoValueTagSI = 0; + + memset(bcch_message,0,sizeof(BCCH_DL_SCH_Message_NB_t)); + bcch_message->message.present = BCCH_DL_SCH_MessageType_NB_PR_c1; + bcch_message->message.choice.c1.present = BCCH_DL_SCH_MessageType_NB__c1_PR_systemInformationBlockType1_r13; + + //allocation + *sib1_NB_IoT = &bcch_message->message.choice.c1.choice.systemInformationBlockType1_r13; + + + /*TS 36.331 v14.2.0 pag 589 + * hyperSFN-MSB + * Indicates the 8 most significant bits of the hyper-SFN. Together with the hyper-LSB in MIB-NB the complete HSFN is build up + */ + //FIXME see if correct + uint8_t hyperSFN_MSB = (uint8_t) ((frame>>2)& 0xff); + + //XXX to be checked + (*sib1_NB_IoT)->hyperSFN_MSB_r13.buf = &hyperSFN_MSB; + (*sib1_NB_IoT)->hyperSFN_MSB_r13.size = 1; + (*sib1_NB_IoT)->hyperSFN_MSB_r13.bits_unused = 0; + + memset(&PLMN_identity_info_NB_IoT,0,sizeof(PLMN_IdentityInfo_NB_r13_t)); + + PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc = CALLOC(1,sizeof(*PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc)); + memset(PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc,0,sizeof(*PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc)); + + asn_set_empty(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list);//.size=0; + + //left as it is??? +#if defined(ENABLE_ITTI) + dummy_mcc[0] = (configuration->mcc / 100) % 10; + dummy_mcc[1] = (configuration->mcc / 10) % 10; + dummy_mcc[2] = (configuration->mcc / 1) % 10; +#else + dummy_mcc[0] = 0; + dummy_mcc[1] = 0; + dummy_mcc[2] = 1; +#endif + ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list,&dummy_mcc[0]); + ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list,&dummy_mcc[1]); + ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mcc->list,&dummy_mcc[2]); + + PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list.size=0; + PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list.count=0; + + +#if defined(ENABLE_ITTI) + + if (configuration->mnc >= 100) { + dummy_mnc[0] = (configuration->mnc / 100) % 10; + dummy_mnc[1] = (configuration->mnc / 10) % 10; + dummy_mnc[2] = (configuration->mnc / 1) % 10; + } else { + if (configuration->mnc_digit_length == 2) { + dummy_mnc[0] = (configuration->mnc / 10) % 10; + dummy_mnc[1] = (configuration->mnc / 1) % 10; + dummy_mnc[2] = 0xf; + } else { + dummy_mnc[0] = (configuration->mnc / 100) % 100; + dummy_mnc[1] = (configuration->mnc / 10) % 10; + dummy_mnc[2] = (configuration->mnc / 1) % 10; + } + } + +#else + dummy_mnc[0] = 0; + dummy_mnc[1] = 1; + dummy_mnc[2] = 0xf; +#endif + ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list,&dummy_mnc[0]); + ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list,&dummy_mnc[1]); + + if (dummy_mnc[2] != 0xf) { + ASN_SEQUENCE_ADD(&PLMN_identity_info_NB_IoT.plmn_Identity_r13.mnc.list,&dummy_mnc[2]); + } + + //still set to "notReserved" as in the previous case + PLMN_identity_info_NB_IoT.cellReservedForOperatorUse_r13=PLMN_IdentityInfo_NB_r13__cellReservedForOperatorUse_r13_notReserved; + + *attachWithoutPDN_Connectivity = 0; + PLMN_identity_info_NB_IoT.attachWithoutPDN_Connectivity_r13 = attachWithoutPDN_Connectivity; + + ASN_SEQUENCE_ADD(&(*sib1_NB_IoT)->cellAccessRelatedInfo_r13.plmn_IdentityList_r13.list,&PLMN_identity_info_NB_IoT); + + // 16 bits = 2 byte + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf = MALLOC(2); //MALLOC works in byte + + //lefts as it is? +#if defined(ENABLE_ITTI) + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[0] = (configuration->tac >> 8) & 0xff; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[1] = (configuration->tac >> 0) & 0xff; +#else + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[0] = 0x00; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.buf[1] = 0x01; +#endif + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.size=2; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.trackingAreaCode_r13.bits_unused=0; + + // 28 bits --> i have to use 32 bits = 4 byte + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf = MALLOC(8); // why allocate 8 byte? +#if defined(ENABLE_ITTI) + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[0] = (configuration->cell_identity >> 20) & 0xff; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[1] = (configuration->cell_identity >> 12) & 0xff; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[2] = (configuration->cell_identity >> 4) & 0xff; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[3] = (configuration->cell_identity << 4) & 0xf0; +#else + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[0] = 0x00; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[1] = 0x00; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[2] = 0x00; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.buf[3] = 0x10; +#endif + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.size=4; + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellIdentity_r13.bits_unused=4; + + //Still set to "notBarred" as in the previous case + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.cellBarred_r13=SystemInformationBlockType1_NB__cellAccessRelatedInfo_r13__cellBarred_r13_notBarred; + + //Still Set to "notAllowed" like in the previous case + (*sib1_NB_IoT)->cellAccessRelatedInfo_r13.intraFreqReselection_r13=SystemInformationBlockType1_NB__cellAccessRelatedInfo_r13__intraFreqReselection_r13_notAllowed; + + + (*sib1_NB_IoT)->cellSelectionInfo_r13.q_RxLevMin_r13=-65; //which value?? TS 36.331 V14.2.1 pag. 589 + (*sib1_NB_IoT)->cellSelectionInfo_r13.q_QualMin_r13 = 0; //FIXME new parameter for SIB1-NB, not present in SIB1 (for cell reselection but if not used the UE should apply the default value) + + (*sib1_NB_IoT)->p_Max_r13 = CALLOC(1, sizeof(P_Max_t)); + *((*sib1_NB_IoT)->p_Max_r13) = 23; + + //FIXME + (*sib1_NB_IoT)->freqBandIndicator_r13 = +#if defined(ENABLE_ITTI) + configuration->eutra_band; +#else + 5; //if not configured we use band 5 (UL: 824 MHz - 849MHz / DL: 869 MHz - 894 MHz FDD mode) +#endif + + //OPTIONAL new parameters, to be used? + /* + * freqBandInfo_r13 + * multiBandInfoList_r13 + * nrs_CRS_PowerOffset_r13 + * sib1_NB_IoT->downlinkBitmap_r13.choice.subframePattern10_r13 =(is a BIT_STRING) + */ + + + (*sib1_NB_IoT)->downlinkBitmap_r13 = CALLOC(1, sizeof(struct DL_Bitmap_NB_r13)); + ((*sib1_NB_IoT)->downlinkBitmap_r13)->present= DL_Bitmap_NB_r13_PR_NOTHING; + + *eutraControlRegionSize = 1; + (*sib1_NB_IoT)->eutraControlRegionSize_r13 = eutraControlRegionSize; + + + *nrs_CRS_PowerOffset= 0; + (*sib1_NB_IoT)->nrs_CRS_PowerOffset_r13 = nrs_CRS_PowerOffset; + + schedulingInfo_NB_IoT = (SchedulingInfo_NB_r13_t*) malloc (3*sizeof(SchedulingInfo_NB_r13_t)); + sib_type_NB_IoT = (SIB_Type_NB_r13_t *) malloc (3*sizeof(SIB_Type_NB_r13_t)); + + memset(&schedulingInfo_NB_IoT[0],0,sizeof(SchedulingInfo_NB_r13_t)); + memset(&schedulingInfo_NB_IoT[1],0,sizeof(SchedulingInfo_NB_r13_t)); + memset(&schedulingInfo_NB_IoT[2],0,sizeof(SchedulingInfo_NB_r13_t)); + memset(&sib_type_NB_IoT[0],0,sizeof(SIB_Type_NB_r13_t)); + memset(&sib_type_NB_IoT[1],0,sizeof(SIB_Type_NB_r13_t)); + memset(&sib_type_NB_IoT[2],0,sizeof(SIB_Type_NB_r13_t)); + + + // Now, follow the scheduler SIB configuration + // There is only one sib2+sib3 common setting + schedulingInfo_NB_IoT[0].si_Periodicity_r13=SchedulingInfo_NB_r13__si_Periodicity_r13_rf4096; + schedulingInfo_NB_IoT[0].si_RepetitionPattern_r13=SchedulingInfo_NB_r13__si_RepetitionPattern_r13_every2ndRF; //This Indicates the starting radio frames within the SI window used for SI message transmission. + schedulingInfo_NB_IoT[0].si_TB_r13= SchedulingInfo_NB_r13__si_TB_r13_b680;//208 bits + + + // This is for SIB2/3 + /*SIB3 --> There is no mapping information of SIB2 since it is always present + * in the first SystemInformation message + * listed in the schedulingInfoList list. + * */ + sib_type_NB_IoT[0]=SIB_Type_NB_r13_sibType3_NB_r13; + + ASN_SEQUENCE_ADD(&schedulingInfo_NB_IoT[0].sib_MappingInfo_r13.list,&sib_type_NB_IoT[0]); + ASN_SEQUENCE_ADD(&(*sib1_NB_IoT)->schedulingInfoList_r13.list,&schedulingInfo_NB_IoT[0]); + + //printf("[ASN Debug] SI P: %ld\n",(*sib1_NB_IoT)->schedulingInfoList_r13.list.array[0]->si_Periodicity_r13); + +#if defined(ENABLE_ITTI) + + if (configuration->frame_type == TDD) +#endif + { + //FIXME in NB-IoT mandatory to be FDD --> so must give an error + LOG_E(RRC,"[NB-IoT %d] Frame Type is TDD --> not supported by NB-IoT, exiting\n", Mod_id); //correct? + exit(-1); + } + + //FIXME which value chose for the following parameter + (*sib1_NB_IoT)->si_WindowLength_r13=SystemInformationBlockType1_NB__si_WindowLength_r13_ms160; + (*sib1_NB_IoT)->si_RadioFrameOffset_r13= 0; + + /*In Nb-IoT change/update of specific SI message can additionally be indicated by a SI message specific value tag + * systemInfoValueTagSI (there is no SystemInfoValueTag in SIB1-NB but only in MIB-NB) + *contained in systemInfoValueTagList_r13 + **/ + //FIXME correct? + (*sib1_NB_IoT)->systemInfoValueTagList_r13 = CALLOC(1, sizeof(struct SystemInfoValueTagList_NB_r13)); + asn_set_empty(&(*sib1_NB_IoT)->systemInfoValueTagList_r13->list); + ASN_SEQUENCE_ADD(&(*sib1_NB_IoT)->systemInfoValueTagList_r13->list,&systemInfoValueTagSI); + + +#ifdef XER_PRINT //generate xml files + xer_fprint(stdout, &asn_DEF_BCCH_DL_SCH_Message_NB, (void*)bcch_message); +#endif + + + enc_rval = uper_encode_to_buffer(&asn_DEF_BCCH_DL_SCH_Message_NB, + (void*)bcch_message, + carrier->SIB1_NB_IoT, + 100); + + if (enc_rval.encoded > 0){ + LOG_F(RRC,"ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + + +#ifdef USER_MODE + LOG_D(RRC,"[NB-IoT] SystemInformationBlockType1-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); +#endif + + if (enc_rval.encoded==-1) { + return(-1); + } + + return((enc_rval.encoded+7)/8); +} + +/*SIB23_NB_IoT*/ +//to be clarified is it is possible to carry SIB2 and SIB3 in the same SI message for NB-IoT? +uint8_t do_SIB23_NB_IoT(uint8_t Mod_id, + int CC_id, + rrc_eNB_carrier_data_NB_IoT_t *carrier,//MP: this is already a carrier[CC_id] + NbIoTRrcConfigurationReq *configuration ) //openair2/COMMON/rrc_messages_types.h +{ + struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member *sib2_NB_part; + struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member *sib3_NB_part; + + BCCH_DL_SCH_Message_NB_t *bcch_message = &(carrier->systemInformation_NB_IoT); //is the systeminformation-->BCCH_DL_SCH_Message_NB + SystemInformationBlockType2_NB_r13_t *sib2_NB_IoT; + SystemInformationBlockType3_NB_r13_t *sib3_NB_IoT; + + asn_enc_rval_t enc_rval; + RACH_Info_NB_r13_t rach_Info_NB_IoT; + NPRACH_Parameters_NB_r13_t *nprach_parameters; + + //optional + long *connEstFailOffset = NULL; + connEstFailOffset = CALLOC(1, sizeof(long)); + +// RSRP_ThresholdsNPRACH_InfoList_NB_r13_t *rsrp_ThresholdsPrachInfoList; +// RSRP_Range_t rsrp_range; + + ACK_NACK_NumRepetitions_NB_r13_t ack_nack_repetition; + struct NPUSCH_ConfigCommon_NB_r13__dmrs_Config_r13 *dmrs_config; + struct DL_GapConfig_NB_r13 *dl_Gap; + + long *srs_SubframeConfig; + srs_SubframeConfig= CALLOC(1, sizeof(long)); + + + if (bcch_message) { + memset(bcch_message,0,sizeof(BCCH_DL_SCH_Message_NB_t)); + } else { + LOG_E(RRC,"[NB-IoT %d] BCCH_MESSAGE_NB is null, exiting\n", Mod_id); + exit(-1); + } + + //before schould be allocated memory somewhere? +// if (!carrier->sib2_NB_IoT) { +// LOG_E(RRC,"[NB-IoT %d] sib2_NB_IoT is null, exiting\n", Mod_id); +// exit(-1); +// } +// +// if (!carrier->sib3_NB_IoT) { +// LOG_E(RRC,"[NB-IoT %d] sib3_NB_IoT is null, exiting\n", Mod_id); +// exit(-1); +// } + + + LOG_I(RRC,"[NB-IoT %d] Configuration SIB2/3\n", Mod_id); + + sib2_NB_part = CALLOC(1,sizeof(struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member)); + sib3_NB_part = CALLOC(1,sizeof(struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member)); + memset(sib2_NB_part,0,sizeof(struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member)); + memset(sib3_NB_part,0,sizeof(struct SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member)); + + sib2_NB_part->present = SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member_PR_sib2_r13; + sib3_NB_part->present = SystemInformation_NB_r13_IEs__sib_TypeAndInfo_r13__Member_PR_sib3_r13; + + //may bug if not correct allocation of memory + carrier->sib2_NB_IoT = &sib2_NB_part->choice.sib2_r13; + carrier->sib3_NB_IoT = &sib3_NB_part->choice.sib3_r13; + sib2_NB_IoT = carrier->sib2_NB_IoT; + sib3_NB_IoT = carrier->sib3_NB_IoT; + + nprach_parameters = (NPRACH_Parameters_NB_r13_t *) malloc (3*sizeof(NPRACH_Parameters_NB_r13_t)); + + memset(&nprach_parameters[0],0,sizeof(NPRACH_Parameters_NB_r13_t)); + memset(&nprach_parameters[1],0,sizeof(NPRACH_Parameters_NB_r13_t)); + memset(&nprach_parameters[2],0,sizeof(NPRACH_Parameters_NB_r13_t)); + +/// SIB2-NB----------------------------------------- + + //Barring is manage by ab-Enabled in MIB-NB (but is not a struct as ac-BarringInfo in LTE legacy) + + //RACH Config. Common-------------------------------------------------------------- + sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.preambleTransMax_CE_r13 = + configuration->rach_preambleTransMax_CE_NB; + sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.powerRampingParameters_r13.powerRampingStep = + configuration->rach_powerRampingStep_NB; + sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.powerRampingParameters_r13.preambleInitialReceivedTargetPower = + configuration->rach_preambleInitialReceivedTargetPower_NB; + + rach_Info_NB_IoT.ra_ResponseWindowSize_r13 = configuration->rach_raResponseWindowSize_NB; + rach_Info_NB_IoT.mac_ContentionResolutionTimer_r13 = configuration-> rach_macContentionResolutionTimer_NB; + //rach_infoList max size = maxNPRACH-Resources-NB-r13 = 3 + ASN_SEQUENCE_ADD(&sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.rach_InfoList_r13.list,&rach_Info_NB_IoT); + + //TS 36.331 pag 614 --> if not present the value to infinity sould be used + *connEstFailOffset = 0; + + sib2_NB_IoT->radioResourceConfigCommon_r13.rach_ConfigCommon_r13.connEstFailOffset_r13 = connEstFailOffset; /*OPTIONAL*/ + + + // BCCH-Config-NB-IoT---------------------------------------------------------------- + sib2_NB_IoT->radioResourceConfigCommon_r13.bcch_Config_r13.modificationPeriodCoeff_r13 + = configuration->bcch_modificationPeriodCoeff_NB; + + // PCCH-Config-NB-IoT----------------------------------------------------------------- + sib2_NB_IoT->radioResourceConfigCommon_r13.pcch_Config_r13.defaultPagingCycle_r13 + = configuration->pcch_defaultPagingCycle_NB; + sib2_NB_IoT->radioResourceConfigCommon_r13.pcch_Config_r13.nB_r13 = configuration->pcch_nB_NB; + sib2_NB_IoT->radioResourceConfigCommon_r13.pcch_Config_r13.npdcch_NumRepetitionPaging_r13 = configuration-> pcch_npdcch_NumRepetitionPaging_NB; + + //NPRACH-Config-NB-IoT----------------------------------------------------------------- + + sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.rsrp_ThresholdsPrachInfoList_r13 = NULL; + sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.nprach_CP_Length_r13 = configuration->nprach_CP_Length; + /*OPTIONAL*/ +// =CALLOC(1, sizeof(struct RSRP_ThresholdsNPRACH_InfoList_NB_r13)); //fatto uguale dopo +// rsrp_ThresholdsPrachInfoList = sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.rsrp_ThresholdsPrachInfoList_r13; +// rsrp_range = configuration->nprach_rsrp_range_NB; +// ASN_SEQUENCE_ADD(&rsrp_ThresholdsPrachInfoList->list,rsrp_range); + + // According configuration to set the 3 CE level configuration setting + + nprach_parameters[0].nprach_Periodicity_r13 = configuration->nprach_Periodicity[0]; + nprach_parameters[0].nprach_StartTime_r13 = configuration->nprach_StartTime[0]; + nprach_parameters[0].nprach_SubcarrierOffset_r13 = configuration->nprach_SubcarrierOffset[0]; + nprach_parameters[0].nprach_NumSubcarriers_r13 = configuration->nprach_NumSubcarriers[0]; + nprach_parameters[0].numRepetitionsPerPreambleAttempt_r13 = configuration->numRepetitionsPerPreambleAttempt_NB[0]; + nprach_parameters[0].nprach_SubcarrierMSG3_RangeStart_r13 = configuration->nprach_SubcarrierMSG3_RangeStart; + nprach_parameters[0].maxNumPreambleAttemptCE_r13 = configuration->maxNumPreambleAttemptCE_NB; + nprach_parameters[0].npdcch_NumRepetitions_RA_r13 = configuration->npdcch_NumRepetitions_RA[0]; + nprach_parameters[0].npdcch_StartSF_CSS_RA_r13 = configuration->npdcch_StartSF_CSS_RA[0]; + nprach_parameters[0].npdcch_Offset_RA_r13 = configuration->npdcch_Offset_RA[0]; + + nprach_parameters[1].nprach_Periodicity_r13 = configuration->nprach_Periodicity[1]; + nprach_parameters[1].nprach_StartTime_r13 = configuration->nprach_StartTime[1]; + nprach_parameters[1].nprach_SubcarrierOffset_r13 = configuration->nprach_SubcarrierOffset[1]; + nprach_parameters[1].nprach_NumSubcarriers_r13 = configuration->nprach_NumSubcarriers[1]; + nprach_parameters[1].numRepetitionsPerPreambleAttempt_r13 = configuration->numRepetitionsPerPreambleAttempt_NB[1]; + nprach_parameters[1].nprach_SubcarrierMSG3_RangeStart_r13 = configuration->nprach_SubcarrierMSG3_RangeStart; + nprach_parameters[1].maxNumPreambleAttemptCE_r13 = configuration->maxNumPreambleAttemptCE_NB; + nprach_parameters[1].npdcch_NumRepetitions_RA_r13 = configuration->npdcch_NumRepetitions_RA[1]; + nprach_parameters[1].npdcch_StartSF_CSS_RA_r13 = configuration->npdcch_StartSF_CSS_RA[1]; + nprach_parameters[1].npdcch_Offset_RA_r13 = configuration->npdcch_Offset_RA[1]; + + nprach_parameters[2].nprach_Periodicity_r13 = configuration->nprach_Periodicity[2]; + nprach_parameters[2].nprach_StartTime_r13 = configuration->nprach_StartTime[2]; + nprach_parameters[2].nprach_SubcarrierOffset_r13 = configuration->nprach_SubcarrierOffset[2]; + nprach_parameters[2].nprach_NumSubcarriers_r13 = configuration->nprach_NumSubcarriers[2]; + nprach_parameters[2].numRepetitionsPerPreambleAttempt_r13 = configuration->numRepetitionsPerPreambleAttempt_NB[2]; + nprach_parameters[2].nprach_SubcarrierMSG3_RangeStart_r13 = configuration->nprach_SubcarrierMSG3_RangeStart; + nprach_parameters[2].maxNumPreambleAttemptCE_r13 = configuration->maxNumPreambleAttemptCE_NB; + nprach_parameters[2].npdcch_NumRepetitions_RA_r13 = configuration->npdcch_NumRepetitions_RA[2]; + nprach_parameters[2].npdcch_StartSF_CSS_RA_r13 = configuration->npdcch_StartSF_CSS_RA[2]; + nprach_parameters[2].npdcch_Offset_RA_r13 = configuration->npdcch_Offset_RA[2]; + + + //nprach_parameterList have a max size of 3 possible nprach configuration (see maxNPRACH_Resources_NB_r13) + ASN_SEQUENCE_ADD(&sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.nprach_ParametersList_r13.list,&nprach_parameters[0]); + ASN_SEQUENCE_ADD(&sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.nprach_ParametersList_r13.list,&nprach_parameters[1]); + ASN_SEQUENCE_ADD(&sib2_NB_IoT->radioResourceConfigCommon_r13.nprach_Config_r13.nprach_ParametersList_r13.list,&nprach_parameters[2]); + + // NPDSCH-Config NB-IOT + sib2_NB_IoT->radioResourceConfigCommon_r13.npdsch_ConfigCommon_r13.nrs_Power_r13= configuration->npdsch_nrs_Power; + + + //NPUSCH-Config NB-IoT---------------------------------------------------------------- + //list of size 3 (see maxNPRACH_Resources_NB_r13) + ack_nack_repetition = configuration-> npusch_ack_nack_numRepetitions_NB; //is an enumerative + ASN_SEQUENCE_ADD(&(sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.ack_NACK_NumRepetitions_Msg4_r13.list) ,&ack_nack_repetition); + + *srs_SubframeConfig = configuration->npusch_srs_SubframeConfig_NB; + sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.srs_SubframeConfig_r13= srs_SubframeConfig; /*OPTIONAL*/ + + + /*OPTIONAL*/ + dmrs_config = CALLOC(1,sizeof(struct NPUSCH_ConfigCommon_NB_r13__dmrs_Config_r13)); + dmrs_config->threeTone_CyclicShift_r13 = configuration->npusch_threeTone_CyclicShift_r13; + dmrs_config->sixTone_CyclicShift_r13 = configuration->npusch_sixTone_CyclicShift_r13; + + /*OPTIONAL + * -define the base sequence for a DMRS sequence in a cell with multi tone transmission (3,6,12) see TS 36.331 NPUSCH-Config-NB + * -if not defined will be calculated based on the cellID once we configure the phy layer (rrc_mac_config_req) through the config_sib2 */ + dmrs_config->threeTone_BaseSequence_r13 = NULL; + dmrs_config->sixTone_BaseSequence_r13 = NULL; + dmrs_config->twelveTone_BaseSequence_r13 = NULL; + + sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.dmrs_Config_r13 = dmrs_config; + + //ulReferenceSignalsNPUSCH + /*Reference Signal (RS) for UL in NB-IoT is called DRS (Demodulation Reference Signal) + * sequence-group hopping can be enabled or disabled by means of the cell-specific parameter groupHoppingEnabled_r13 + * sequence-group hopping can be disabled for certain specific UE through the parameter groupHoppingDisabled (physicalConfigDedicated) + * groupAssignmentNPUSCH--> is used for generate the sequence-shift pattern + */ + sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.ul_ReferenceSignalsNPUSCH_r13.groupHoppingEnabled_r13= configuration->npusch_groupHoppingEnabled; + sib2_NB_IoT->radioResourceConfigCommon_r13.npusch_ConfigCommon_r13.ul_ReferenceSignalsNPUSCH_r13.groupAssignmentNPUSCH_r13 =configuration->npusch_groupAssignmentNPUSCH_r13; + + + //dl_GAP---------------------------------------------------------------------------------/*OPTIONAL*/ + dl_Gap = CALLOC(1,sizeof(struct DL_GapConfig_NB_r13)); + dl_Gap->dl_GapDurationCoeff_r13= configuration-> dl_GapDurationCoeff_NB; + dl_Gap->dl_GapPeriodicity_r13= configuration->dl_GapPeriodicity_NB; + dl_Gap->dl_GapThreshold_r13= configuration->dl_GapThreshold_NB; + sib2_NB_IoT->radioResourceConfigCommon_r13.dl_Gap_r13 = dl_Gap; + + + // uplinkPowerControlCommon - NB-IoT------------------------------------------------------ + sib2_NB_IoT->radioResourceConfigCommon_r13.uplinkPowerControlCommon_r13.p0_NominalNPUSCH_r13 = configuration->npusch_p0_NominalNPUSCH; + sib2_NB_IoT->radioResourceConfigCommon_r13.uplinkPowerControlCommon_r13.deltaPreambleMsg3_r13 = configuration->deltaPreambleMsg3; + sib2_NB_IoT->radioResourceConfigCommon_r13.uplinkPowerControlCommon_r13.alpha_r13 = configuration->npusch_alpha; + //no deltaFlist_PUCCH and no UL cyclic prefix + + // UE Timers and Constants -NB-IoT-------------------------------------------------------- + sib2_NB_IoT->ue_TimersAndConstants_r13.t300_r13 = configuration-> ue_TimersAndConstants_t300_NB; + sib2_NB_IoT->ue_TimersAndConstants_r13.t301_r13 = configuration-> ue_TimersAndConstants_t301_NB; + sib2_NB_IoT->ue_TimersAndConstants_r13.t310_r13 = configuration-> ue_TimersAndConstants_t310_NB; + sib2_NB_IoT->ue_TimersAndConstants_r13.t311_r13 = configuration-> ue_TimersAndConstants_t311_NB; + sib2_NB_IoT->ue_TimersAndConstants_r13.n310_r13 = configuration-> ue_TimersAndConstants_n310_NB; + sib2_NB_IoT->ue_TimersAndConstants_r13.n311_r13 = configuration-> ue_TimersAndConstants_n311_NB; + + //other SIB2-NB Parameters-------------------------------------------------------------------------------- + sib2_NB_IoT->freqInfo_r13.additionalSpectrumEmission_r13 = 1; + sib2_NB_IoT->freqInfo_r13.ul_CarrierFreq_r13 = NULL; /*OPTIONAL*/ + + sib2_NB_IoT->timeAlignmentTimerCommon_r13=TimeAlignmentTimer_infinity;//TimeAlignmentTimer_sf5120; + + /*OPTIONAL*/ + sib2_NB_IoT->multiBandInfoList_r13 = NULL; + +/// SIB3-NB------------------------------------------------------- + + sib3_NB_IoT->cellReselectionInfoCommon_r13.q_Hyst_r13=SystemInformationBlockType3_NB_r13__cellReselectionInfoCommon_r13__q_Hyst_r13_dB4; + sib3_NB_IoT->cellReselectionServingFreqInfo_r13.s_NonIntraSearch_r13=0; //or define in configuration? + + sib3_NB_IoT->intraFreqCellReselectionInfo_r13.q_RxLevMin_r13 = -70; + //new + sib3_NB_IoT->intraFreqCellReselectionInfo_r13.q_QualMin_r13 = CALLOC(1,sizeof(*sib3_NB_IoT->intraFreqCellReselectionInfo_r13.q_QualMin_r13)); + *(sib3_NB_IoT->intraFreqCellReselectionInfo_r13.q_QualMin_r13)= 10; //a caso + + sib3_NB_IoT->intraFreqCellReselectionInfo_r13.p_Max_r13 = NULL; + sib3_NB_IoT->intraFreqCellReselectionInfo_r13.s_IntraSearchP_r13 = 31; // s_intraSearch --> s_intraSearchP!!! (they call in a different way) + sib3_NB_IoT->intraFreqCellReselectionInfo_r13.t_Reselection_r13=1; + + //how to manage? + sib3_NB_IoT->freqBandInfo_r13 = NULL; + sib3_NB_IoT->multiBandInfoList_r13 = NULL; + + +///BCCH message (generate the SI message) + bcch_message->message.present = BCCH_DL_SCH_MessageType_NB_PR_c1; + bcch_message->message.choice.c1.present = BCCH_DL_SCH_MessageType_NB__c1_PR_systemInformation_r13; + + bcch_message->message.choice.c1.choice.systemInformation_r13.criticalExtensions.present = SystemInformation_NB__criticalExtensions_PR_systemInformation_r13; + bcch_message->message.choice.c1.choice.systemInformation_r13.criticalExtensions.choice.systemInformation_r13.sib_TypeAndInfo_r13.list.count=0; + + ASN_SEQUENCE_ADD(&bcch_message->message.choice.c1.choice.systemInformation_r13.criticalExtensions.choice.systemInformation_r13.sib_TypeAndInfo_r13.list, + sib2_NB_part); + ASN_SEQUENCE_ADD(&bcch_message->message.choice.c1.choice.systemInformation_r13.criticalExtensions.choice.systemInformation_r13.sib_TypeAndInfo_r13.list, + sib3_NB_part); + +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_BCCH_DL_SCH_Message_NB, (void*)bcch_message); +#endif + enc_rval = uper_encode_to_buffer(&asn_DEF_BCCH_DL_SCH_Message_NB, + (void*)bcch_message, + carrier->SIB23_NB_IoT, + 900); +// AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", +// enc_rval.failed_type->name, enc_rval.encoded); + +//#if defined(ENABLE_ITTI)..... + + +#ifdef USER_MODE + LOG_D(RRC,"[NB-IoT] SystemInformation-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); +#endif + + if (enc_rval.encoded==-1) { + msg("[RRC] ASN1 : SI-NB encoding failed for SIB23_NB_IoT\n"); + return(-1); + } + + carrier->sib2_NB_IoT = sib2_NB_IoT; + carrier->sib3_NB_IoT = sib3_NB_IoT; + + return((enc_rval.encoded+7)/8); +} + +/*do_RRCConnectionSetup_NB_IoT--> the aim is to establish SRB1 and SRB1bis(implicitly)*/ +uint8_t do_RRCConnectionSetup_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, + int CC_id, + uint8_t* const buffer, //Srb0.Tx_buffer.Payload + const uint8_t Transaction_id, + const NB_IoT_DL_FRAME_PARMS* const frame_parms, // maybe not used + SRB_ToAddModList_NB_r13_t** SRB_configList_NB_IoT, //for both SRB1bis and SRB1 + struct PhysicalConfigDedicated_NB_r13** physicalConfigDedicated_NB_IoT +) + +{ + + asn_enc_rval_t enc_rval; + + + //MP:logical channel group not defined for Nb-IoT + + //MP: logical channel priority pag 605 (is 1 for SRB1 and for SRB1bis should be the same) + //long* prioritySRB1 = NULL; + long* prioritySRB1bis = NULL; + BOOLEAN_t* logicalChannelSR_Prohibit =NULL; //pag 605 + BOOLEAN_t* npusch_AllSymbols= NULL; + +// struct SRB_ToAddMod_NB_r13* SRB1_config_NB = NULL; +// struct SRB_ToAddMod_NB_r13__rlc_Config_r13* SRB1_rlc_config_NB = NULL; +// struct SRB_ToAddMod_NB_r13__logicalChannelConfig_r13* SRB1_lchan_config_NB = NULL; + + struct SRB_ToAddMod_NB_r13* SRB1bis_config_NB_IoT = NULL; + struct SRB_ToAddMod_NB_r13__rlc_Config_r13* SRB1bis_rlc_config_NB_IoT = NULL; + struct SRB_ToAddMod_NB_r13__logicalChannelConfig_r13* SRB1bis_lchan_config_NB_IoT = NULL; + + //No UL_specific parameters for NB-IoT in LogicalChanelConfig-NB + + PhysicalConfigDedicated_NB_r13_t* physicalConfigDedicated2_NB_IoT = NULL; + DL_CCCH_Message_NB_t dl_ccch_msg_NB_IoT; + RRCConnectionSetup_NB_t* rrcConnectionSetup_NB_IoT = NULL; + + memset((void *)&dl_ccch_msg_NB_IoT,0,sizeof(DL_CCCH_Message_NB_t)); + dl_ccch_msg_NB_IoT.message.present = DL_CCCH_MessageType_NB_PR_c1; + dl_ccch_msg_NB_IoT.message.choice.c1.present = DL_CCCH_MessageType_NB__c1_PR_rrcConnectionSetup_r13; + rrcConnectionSetup_NB_IoT = &dl_ccch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionSetup_r13; + + + if (*SRB_configList_NB_IoT) { + free(*SRB_configList_NB_IoT); + } + *SRB_configList_NB_IoT = CALLOC(1,sizeof(SRB_ToAddModList_NB_r13_t)); + +/// SRB1-------------------- + { +// SRB1_config_NB = CALLOC(1,sizeof(*SRB1_config_NB)); +// +// //no srb_Identity in SRB_ToAddMod_NB +// +// SRB1_rlc_config_NB = CALLOC(1,sizeof(*SRB1_rlc_config_NB)); +// SRB1_config_NB->rlc_Config_r13 = SRB1_rlc_config_NB; +// +// SRB1_rlc_config_NB->present = SRB_ToAddMod_NB_r13__rlc_Config_r13_PR_explicitValue; +// SRB1_rlc_config_NB->choice.explicitValue.present=RLC_Config_NB_r13_PR_am;//the only possible in NB_IoT +// +//// SRB1_rlc_config_NB->choice.explicitValue.choice.am.ul_AM_RLC_r13.t_PollRetransmit_r13 = enb_properties.properties[ctxt_pP->module_id]->srb1_timer_poll_retransmit_r13; +//// SRB1_rlc_config_NB->choice.explicitValue.choice.am.ul_AM_RLC_r13.maxRetxThreshold_r13 = enb_properties.properties[ctxt_pP->module_id]->srb1_max_retx_threshold_r13; +//// //(musT be disabled--> SRB1 config pag 640 specs ) +//// SRB1_rlc_config_NB->choice.explicitValue.choice.am.dl_AM_RLC_r13.enableStatusReportSN_Gap_r13 =NULL; +// +// +// SRB1_rlc_config_NB->choice.explicitValue.choice.am.ul_AM_RLC_r13.t_PollRetransmit_r13 = T_PollRetransmit_NB_r13_ms25000; +// SRB1_rlc_config_NB->choice.explicitValue.choice.am.ul_AM_RLC_r13.maxRetxThreshold_r13 = UL_AM_RLC_NB_r13__maxRetxThreshold_r13_t8; +// //(musT be disabled--> SRB1 config pag 640 specs ) +// SRB1_rlc_config_NB->choice.explicitValue.choice.am.dl_AM_RLC_r13.enableStatusReportSN_Gap_r13 = NULL; +// +// SRB1_lchan_config_NB = CALLOC(1,sizeof(*SRB1_lchan_config_NB)); +// SRB1_config_NB->logicalChannelConfig_r13 = SRB1_lchan_config_NB; +// +// SRB1_lchan_config_NB->present = SRB_ToAddMod_NB_r13__logicalChannelConfig_r13_PR_explicitValue; +// +// +// prioritySRB1 = CALLOC(1, sizeof(long)); +// *prioritySRB1 = 1; +// SRB1_lchan_config_NB->choice.explicitValue.priority_r13 = prioritySRB1; +// +// logicalChannelSR_Prohibit = CALLOC(1, sizeof(BOOLEAN_t)); +// *logicalChannelSR_Prohibit = 1; +// //schould be set to TRUE (specs pag 641) +// SRB1_lchan_config_NB->choice.explicitValue.logicalChannelSR_Prohibit_r13 = logicalChannelSR_Prohibit; +// +// //ADD SRB1 +// ASN_SEQUENCE_ADD(&(*SRB_configList_NB_IoT)->list,SRB1_config_NB); + } + +///SRB1bis (The configuration for SRB1 and SRB1bis is the same) the only difference is the logical channel identity = 3 but not set here + + SRB1bis_config_NB_IoT = CALLOC(1,sizeof(*SRB1bis_config_NB_IoT)); + + //no srb_Identity in SRB_ToAddMod_NB + SRB1bis_rlc_config_NB_IoT = CALLOC(1,sizeof(*SRB1bis_rlc_config_NB_IoT)); + SRB1bis_config_NB_IoT->rlc_Config_r13 = SRB1bis_rlc_config_NB_IoT; + + SRB1bis_rlc_config_NB_IoT->present = SRB_ToAddMod_NB_r13__rlc_Config_r13_PR_explicitValue; + SRB1bis_rlc_config_NB_IoT->choice.explicitValue.present=RLC_Config_NB_r13_PR_am;//MP: the only possible RLC config in NB_IoT + + SRB1bis_rlc_config_NB_IoT->choice.explicitValue.choice.am.ul_AM_RLC_r13.t_PollRetransmit_r13 = T_PollRetransmit_NB_r13_ms25000; + SRB1bis_rlc_config_NB_IoT->choice.explicitValue.choice.am.ul_AM_RLC_r13.maxRetxThreshold_r13 = UL_AM_RLC_NB_r13__maxRetxThreshold_r13_t8; + //(musT be disabled--> SRB1 config pag 640 specs ) + SRB1bis_rlc_config_NB_IoT->choice.explicitValue.choice.am.dl_AM_RLC_r13.enableStatusReportSN_Gap_r13 =NULL; + + SRB1bis_lchan_config_NB_IoT = CALLOC(1,sizeof(*SRB1bis_lchan_config_NB_IoT)); + SRB1bis_config_NB_IoT->logicalChannelConfig_r13 = SRB1bis_lchan_config_NB_IoT; + + SRB1bis_lchan_config_NB_IoT->present = SRB_ToAddMod_NB_r13__logicalChannelConfig_r13_PR_explicitValue; + + prioritySRB1bis = CALLOC(1, sizeof(long)); + *prioritySRB1bis = 1; //same as SRB1? + SRB1bis_lchan_config_NB_IoT->choice.explicitValue.priority_r13 = prioritySRB1bis; + + logicalChannelSR_Prohibit = CALLOC(1, sizeof(BOOLEAN_t)); + *logicalChannelSR_Prohibit = 1; //schould be set to TRUE (specs pag 641) + SRB1bis_lchan_config_NB_IoT->choice.explicitValue.logicalChannelSR_Prohibit_r13 = logicalChannelSR_Prohibit; + + //ADD SRB1bis + //MP: Actually there is no way to distinguish SRB1 and SRB1bis once put in the list + //MP: SRB_ToAddModList_NB_r13_t size = 1 + ASN_SEQUENCE_ADD(&(*SRB_configList_NB_IoT)->list,SRB1bis_config_NB_IoT); + + + // PhysicalConfigDedicated (NPDCCH, NPUSCH, CarrierConfig, UplinkPowerControl) + + physicalConfigDedicated2_NB_IoT = CALLOC(1,sizeof(*physicalConfigDedicated2_NB_IoT)); + *physicalConfigDedicated_NB_IoT = physicalConfigDedicated2_NB_IoT; + + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13= CALLOC(1, sizeof(*physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13)); + physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13 = CALLOC(1,sizeof(*physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13)); + physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13 = CALLOC(1,sizeof(*physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13)); + physicalConfigDedicated2_NB_IoT->uplinkPowerControlDedicated_r13 = CALLOC(1,sizeof(*physicalConfigDedicated2_NB_IoT->uplinkPowerControlDedicated_r13)); + + //no tpc, no cqi and no pucch, no pdsch, no soundingRS, no AntennaInfo, no scheduling request config + + /* + * NB-IoT supports the operation with either one or two antenna ports, AP0 and AP1. + * For the latter case, Space Frequency Block Coding (SFBC) is applied. + * Once selected, the same transmission scheme applies to NPBCH, NPDCCH, and NPDSCH. + * */ + + //FIXME: MP: CarrierConfigDedicated check the set values ---------------------------------------------- + + //DL + + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.dl_CarrierFreq_r13.carrierFreq_r13=0;//random value set + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.downlinkBitmapNonAnchor_r13= CALLOC(1,sizeof(struct DL_CarrierConfigDedicated_NB_r13__downlinkBitmapNonAnchor_r13)); + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.downlinkBitmapNonAnchor_r13->present= + DL_CarrierConfigDedicated_NB_r13__downlinkBitmapNonAnchor_r13_PR_useNoBitmap_r13; + + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.dl_GapNonAnchor_r13 = CALLOC(1,sizeof(struct DL_CarrierConfigDedicated_NB_r13__dl_GapNonAnchor_r13)); + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.dl_GapNonAnchor_r13->present = + DL_CarrierConfigDedicated_NB_r13__dl_GapNonAnchor_r13_PR_useNoGap_r13; + + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->dl_CarrierConfig_r13.inbandCarrierInfo_r13= NULL; + + //UL + physicalConfigDedicated2_NB_IoT->carrierConfigDedicated_r13->ul_CarrierConfig_r13.ul_CarrierFreq_r13= NULL; + + // NPDCCH + physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13->npdcch_NumRepetitions_r13 =0; + physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13->npdcch_Offset_USS_r13 =0; + physicalConfigDedicated2_NB_IoT->npdcch_ConfigDedicated_r13->npdcch_StartSF_USS_r13=0; + + // NPUSCH //(specs TS 36.331 v14.2.1 pag 643) /* OPTIONAL */ + physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13->ack_NACK_NumRepetitions_r13= NULL; + npusch_AllSymbols= CALLOC(1, sizeof(BOOLEAN_t)); + *npusch_AllSymbols= 1; //TRUE + physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13->npusch_AllSymbols_r13= npusch_AllSymbols; /* OPTIONAL */ + physicalConfigDedicated2_NB_IoT->npusch_ConfigDedicated_r13->groupHoppingDisabled_r13=NULL; /* OPTIONAL */ + + // UplinkPowerControlDedicated + physicalConfigDedicated2_NB_IoT->uplinkPowerControlDedicated_r13->p0_UE_NPUSCH_r13 = 0; // 0 dB (specs TS36.331 v14.2.1 pag 643) + + + //Fill the rrcConnectionSetup-NB message + rrcConnectionSetup_NB_IoT->rrc_TransactionIdentifier = Transaction_id; //input value + rrcConnectionSetup_NB_IoT->criticalExtensions.present = RRCConnectionSetup_NB__criticalExtensions_PR_c1; + rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.present =RRCConnectionSetup_NB__criticalExtensions__c1_PR_rrcConnectionSetup_r13 ; + //MP: carry only SRB1bis at the moment and phyConfigDedicated + rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.srb_ToAddModList_r13 = *SRB_configList_NB_IoT; + rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.drb_ToAddModList_r13 = NULL; + rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.drb_ToReleaseList_r13 = NULL; + rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.rlf_TimersAndConstants_r13 = NULL; + rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.physicalConfigDedicated_r13 = physicalConfigDedicated2_NB_IoT; + rrcConnectionSetup_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionSetup_r13.radioResourceConfigDedicated_r13.mac_MainConfig_r13 = NULL; + +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_DL_CCCH_Message, (void*)&dl_ccch_msg); +#endif + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_CCCH_Message_NB, + (void*)&dl_ccch_msg_NB_IoT, + buffer, + 100); + + if (enc_rval.encoded <= 0) { + LOG_F(RRC, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + +#ifdef USER_MODE + LOG_D(RRC,"RRCConnectionSetup-NB Encoded %zd bits (%zd bytes), ecause %d\n", + enc_rval.encoded,(enc_rval.encoded+7)/8,ecause); +#endif + + return((enc_rval.encoded+7)/8); +} + +/*do_SecurityModeCommand - exactly the same as previous implementation*/ +uint8_t do_SecurityModeCommand_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + uint8_t* const buffer, + const uint8_t Transaction_id, + const uint8_t cipheringAlgorithm, + const uint8_t integrityProtAlgorithm) +{ + DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; + asn_enc_rval_t enc_rval; + + memset(&dl_dcch_msg_NB_IoT,0,sizeof(DL_DCCH_Message_NB_t)); + + dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; + dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_securityModeCommand_r13; + + dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.rrc_TransactionIdentifier = Transaction_id; + dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.criticalExtensions.present = SecurityModeCommand__criticalExtensions_PR_c1; + + dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.criticalExtensions.choice.c1.present = + SecurityModeCommand__criticalExtensions__c1_PR_securityModeCommand_r8; + + // the two following information could be based on the mod_id + dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.cipheringAlgorithm + = (CipheringAlgorithm_r12_t)cipheringAlgorithm; //bug solved + + dl_dcch_msg_NB_IoT.message.choice.c1.choice.securityModeCommand_r13.criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.integrityProtAlgorithm + = (e_SecurityAlgorithmConfig__integrityProtAlgorithm)integrityProtAlgorithm; + +//only changed "asn_DEF_DL_DCCH_Message_NB" +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_DL_DCCH_Message_NB, (void*)&dl_dcch_msg_NB_IoT); +#endif + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_DCCH_Message_NB, + (void*)&dl_dcch_msg_NB_IoT, + buffer, + 100); + if (enc_rval.encoded <= 0) { + LOG_F(RRC, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + + +//#if defined(ENABLE_ITTI) +//# if !defined(DISABLE_XER_SPRINT).... + +#ifdef USER_MODE + LOG_D(RRC,"[NB-IoT %d] securityModeCommand-NB for UE %x Encoded %zd bits (%zd bytes)\n", + ctxt_pP->module_id, + ctxt_pP->rnti, + enc_rval.encoded, + (enc_rval.encoded+7)/8); +#endif + + if (enc_rval.encoded==-1) { + LOG_E(RRC,"[NB-IoT %d] ASN1 : securityModeCommand-NB encoding failed for UE %x\n", + ctxt_pP->module_id, + ctxt_pP->rnti); + return(-1); + } + + return((enc_rval.encoded+7)/8); +} + +/*do_UECapabilityEnquiry_NB_IoT - very similar to legacy lte*/ +uint8_t do_UECapabilityEnquiry_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + uint8_t* const buffer, + const uint8_t Transaction_id +) + +{ + + DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; + //no RAT type in NB-IoT + asn_enc_rval_t enc_rval; + + memset(&dl_dcch_msg_NB_IoT,0,sizeof(DL_DCCH_Message_NB_t)); + + dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; + dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_ueCapabilityEnquiry_r13; + + dl_dcch_msg_NB_IoT.message.choice.c1.choice.ueCapabilityEnquiry_r13.rrc_TransactionIdentifier = Transaction_id; + + dl_dcch_msg_NB_IoT.message.choice.c1.choice.ueCapabilityEnquiry_r13.criticalExtensions.present = UECapabilityEnquiry_NB__criticalExtensions_PR_c1; + dl_dcch_msg_NB_IoT.message.choice.c1.choice.ueCapabilityEnquiry_r13.criticalExtensions.choice.c1.present = + UECapabilityEnquiry_NB__criticalExtensions__c1_PR_ueCapabilityEnquiry_r13; + + //no ue_CapabilityRequest (list of RAT_Type) + +//only changed "asn_DEF_DL_DCCH_Message_NB" +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_DL_DCCH_Message_NB, (void*)&dl_dcch_msg_NB_IoT); +#endif + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_DCCH_Message_NB, + (void*)&dl_dcch_msg_NB_IoT, + buffer, + 100); + if (enc_rval.encoded <= 0) { + LOG_F(RRC, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + +//#if defined(ENABLE_ITTI) +//# if !defined(DISABLE_XER_SPRINT).... + +#ifdef USER_MODE + LOG_D(RRC,"[NB-IoT %d] UECapabilityEnquiry-NB for UE %x Encoded %zd bits (%zd bytes)\n", + ctxt_pP->module_id, + ctxt_pP->rnti, + enc_rval.encoded, + (enc_rval.encoded+7)/8); +#endif + + if (enc_rval.encoded==-1) { + LOG_E(RRC,"[NB-IoT %d] ASN1 : UECapabilityEnquiry-NB encoding failed for UE %x\n", + ctxt_pP->module_id, + ctxt_pP->rnti); + return(-1); + } + + return((enc_rval.encoded+7)/8); +} + +/*do_RRCConnectionReconfiguration_NB_IoT-->may convey information for resource configuration + * (including RBs, MAC main configuration and physical channel configuration) + * including any associated dedicated NAS information.*/ +uint16_t do_RRCConnectionReconfiguration_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + uint8_t *buffer, + uint8_t Transaction_id, + SRB_ToAddModList_NB_r13_t *SRB1_list_NB, //SRB_ConfigList2 (default)--> only SRB1 + DRB_ToAddModList_NB_r13_t *DRB_list_NB_IoT, //DRB_ConfigList (default) + DRB_ToReleaseList_NB_r13_t *DRB_list2_NB_IoT, //is NULL when passed + struct PhysicalConfigDedicated_NB_r13 *physicalConfigDedicated_NB_IoT, + MAC_MainConfig_NB_r13_t *mac_MainConfig_NB_IoT, + struct RRCConnectionReconfiguration_NB_r13_IEs__dedicatedInfoNASList_r13* dedicatedInfoNASList_NB_IoT) + +{ + + //check on DRB_list if contains more than 2 DRB? + + asn_enc_rval_t enc_rval; + DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; + RRCConnectionReconfiguration_NB_t *rrcConnectionReconfiguration_NB; + + + memset(&dl_dcch_msg_NB_IoT,0,sizeof(DL_DCCH_Message_NB_t)); + + dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; + dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_rrcConnectionReconfiguration_r13; + rrcConnectionReconfiguration_NB = &dl_dcch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionReconfiguration_r13; + + // RRCConnectionReconfiguration + rrcConnectionReconfiguration_NB->rrc_TransactionIdentifier = Transaction_id; + rrcConnectionReconfiguration_NB->criticalExtensions.present = RRCConnectionReconfiguration_NB__criticalExtensions_PR_c1; + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.present =RRCConnectionReconfiguration_NB__criticalExtensions__c1_PR_rrcConnectionReconfiguration_r13 ; + + //RAdioResourceconfigDedicated + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13 = + CALLOC(1,sizeof(*rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13)); + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->srb_ToAddModList_r13 = SRB1_list_NB; //only SRB1 + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->drb_ToAddModList_r13 = DRB_list_NB_IoT; + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->drb_ToReleaseList_r13 = DRB_list2_NB_IoT; //NULL + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->physicalConfigDedicated_r13 = physicalConfigDedicated_NB_IoT; + //FIXME may not used now + //rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->rlf_TimersAndConstants_r13 + + if (mac_MainConfig_NB_IoT!=NULL) { + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13 = + CALLOC(1, sizeof(*rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13)); + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13->present + =RadioResourceConfigDedicated_NB_r13__mac_MainConfig_r13_PR_explicitValue_r13; + //why memcopy only this one? + memcpy(&rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13->choice.explicitValue_r13, + mac_MainConfig_NB_IoT, sizeof(*mac_MainConfig_NB_IoT)); + + } else { + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.radioResourceConfigDedicated_r13->mac_MainConfig_r13=NULL; + } + + //no measConfig, measIDlist + //no mobilityControlInfo + + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.dedicatedInfoNASList_r13 = dedicatedInfoNASList_NB_IoT; + //mainly used for cell-reselection/handover purposes?? + rrcConnectionReconfiguration_NB->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r13.fullConfig_r13 = NULL; + + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_DCCH_Message_NB, + (void*)&dl_dcch_msg_NB_IoT, + buffer, + RRC_BUF_SIZE); + if (enc_rval.encoded <= 0) { + LOG_F(RRC, "ASN1 message encoding failed %s, %li\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + + //changed only asn_DEF_DL_DCCH_Message_NB +#ifdef XER_PRINT + xer_fprint(stdout,&asn_DEF_DL_DCCH_Message_NB,(void*)&dl_dcch_msg_NB_IoT); +#endif + +//#if defined(ENABLE_ITTI) +//# if !defined(DISABLE_XER_SPRINT)... + + + LOG_I(RRC,"RRCConnectionReconfiguration-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + + return((enc_rval.encoded+7)/8); +} + +/*do_RRCConnectionReestablishmentReject - exactly the same as legacy LTE*/ +uint8_t do_RRCConnectionReestablishmentReject_NB_IoT( + uint8_t Mod_id, + uint8_t* const buffer) +{ + + asn_enc_rval_t enc_rval; + + DL_CCCH_Message_NB_t dl_ccch_msg_NB_IoT; + RRCConnectionReestablishmentReject_t *rrcConnectionReestablishmentReject; + + memset((void *)&dl_ccch_msg_NB_IoT,0,sizeof(DL_CCCH_Message_NB_t)); + dl_ccch_msg_NB_IoT.message.present = DL_CCCH_MessageType_NB_PR_c1; + dl_ccch_msg_NB_IoT.message.choice.c1.present = DL_CCCH_MessageType_NB__c1_PR_rrcConnectionReestablishmentReject_r13; + rrcConnectionReestablishmentReject = &dl_ccch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionReestablishmentReject_r13; + + // RRCConnectionReestablishmentReject //exactly the same as LTE + rrcConnectionReestablishmentReject->criticalExtensions.present = RRCConnectionReestablishmentReject__criticalExtensions_PR_rrcConnectionReestablishmentReject_r8; + + //Only change in "asn_DEF_DL_CCCH_Message_NB" +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_DL_CCCH_Message_NB, (void*)&dl_ccch_msg_NB_IoT); +#endif + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_CCCH_Message_NB, + (void*)&dl_ccch_msg_NB_IoT, + buffer, + 100); + if (enc_rval.encoded <= 0) { + LOG_F(RRC,"ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + + //Only change in "asn_DEF_DL_CCCH_Message_NB" +#if defined(ENABLE_ITTI) +# if !defined(DISABLE_XER_SPRINT) + { + char message_string[20000]; + size_t message_string_size; + + if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_DL_CCCH_Message_NB, (void *) &dl_ccch_msg_NB_IoT)) > 0) { + MessageDef *msg_p; + + msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB_NB_IoT, RRC_DL_CCCH, message_string_size + sizeof (IttiMsgText)); + msg_p->ittiMsg.rrc_dl_ccch.size = message_string_size; + memcpy(&msg_p->ittiMsg.rrc_dl_ccch.text, message_string, message_string_size); + + itti_send_msg_to_task(TASK_UNKNOWN, Mod_id, msg_p); + } + } +# endif +#endif + +#ifdef USER_MODE + LOG_D(RRC,"RRCConnectionReestablishmentReject Encoded %zd bits (%zd bytes)\n", + enc_rval.encoded,(enc_rval.encoded+7)/8); +#endif + + return((enc_rval.encoded+7)/8); +} + +/*do_RRCConnectionReject_NB_IoT*/ +uint8_t do_RRCConnectionReject_NB_IoT( + uint8_t Mod_id, + uint8_t* const buffer) + +{ + + asn_enc_rval_t enc_rval; + + DL_CCCH_Message_NB_t dl_ccch_msg_NB_IoT; + RRCConnectionReject_NB_t *rrcConnectionReject_NB_IoT; + + memset((void *)&dl_ccch_msg_NB_IoT,0,sizeof(DL_CCCH_Message_NB_t)); + dl_ccch_msg_NB_IoT.message.present = DL_CCCH_MessageType_NB_PR_c1; + dl_ccch_msg_NB_IoT.message.choice.c1.present = DL_CCCH_MessageType_NB__c1_PR_rrcConnectionReject_r13; + rrcConnectionReject_NB_IoT = &dl_ccch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionReject_r13; + + // RRCConnectionReject-NB_IoT + rrcConnectionReject_NB_IoT->criticalExtensions.present = RRCConnectionReject_NB__criticalExtensions_PR_c1; + rrcConnectionReject_NB_IoT->criticalExtensions.choice.c1.present = RRCConnectionReject_NB__criticalExtensions__c1_PR_rrcConnectionReject_r13; + /* let's put an extended wait time of 1s for the moment */ + rrcConnectionReject_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReject_r13.extendedWaitTime_r13 = 1; + //new-use of suspend indication + //If present, this field indicates that the UE should remain suspended and not release its stored context. + rrcConnectionReject_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReject_r13.rrc_SuspendIndication_r13= + CALLOC(1, sizeof(long)); + *(rrcConnectionReject_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReject_r13.rrc_SuspendIndication_r13)= + RRCConnectionReject_NB_r13_IEs__rrc_SuspendIndication_r13_true; + + //Only Modified "asn_DEF_DL_CCCH_Message_NB" +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_DL_CCCH_Message_NB, (void*)&dl_ccch_msg); +#endif + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_CCCH_Message_NB, + (void*)&dl_ccch_msg_NB_IoT, + buffer, + 100); + if (enc_rval.encoded <= 0) { + LOG_F(RRC, "ASN1 message encoding failed (%s, %ld)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + +#if defined(ENABLE_ITTI) +# if !defined(DISABLE_XER_SPRINT) + { + char message_string[20000]; + size_t message_string_size; + + if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_DL_CCCH_Message_NB, (void *) &dl_ccch_msg_NB_IoT)) > 0) { + MessageDef *msg_p; + + msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB_NB_IoT, RRC_DL_CCCH, message_string_size + sizeof (IttiMsgText)); + msg_p->ittiMsg.rrc_dl_ccch.size = message_string_size; + memcpy(&msg_p->ittiMsg.rrc_dl_ccch.text, message_string, message_string_size); + + itti_send_msg_to_task(TASK_UNKNOWN, Mod_id, msg_p); + } + } +# endif +#endif + +#ifdef USER_MODE + LOG_D(RRC,"RRCConnectionReject-NB Encoded %zd bits (%zd bytes)\n", + enc_rval.encoded,(enc_rval.encoded+7)/8); +#endif + + return((enc_rval.encoded+7)/8); +} + + +//no do_MBSFNAreaConfig(..) in NB-IoT +//no do_MeasurementReport(..) in NB-IoT + +/*do_DLInformationTransfer_NB*/ +uint8_t do_DLInformationTransfer_NB_IoT( + uint8_t Mod_id, + uint8_t **buffer, + uint8_t transaction_id, + uint32_t pdu_length, + uint8_t *pdu_buffer) + +{ + ssize_t encoded; + + DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; + + memset(&dl_dcch_msg_NB_IoT, 0, sizeof(DL_DCCH_Message_NB_t)); + + dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; + dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_dlInformationTransfer_r13; + dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.rrc_TransactionIdentifier = transaction_id; + dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.criticalExtensions.present = DLInformationTransfer_NB__criticalExtensions_PR_c1; + dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.criticalExtensions.choice.c1.present = DLInformationTransfer_NB__criticalExtensions__c1_PR_dlInformationTransfer_r13; + dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.criticalExtensions.choice.c1.choice.dlInformationTransfer_r13.dedicatedInfoNAS_r13.size = pdu_length; + dl_dcch_msg_NB_IoT.message.choice.c1.choice.dlInformationTransfer_r13.criticalExtensions.choice.c1.choice.dlInformationTransfer_r13.dedicatedInfoNAS_r13.buf = pdu_buffer; + + encoded = uper_encode_to_new_buffer (&asn_DEF_DL_DCCH_Message_NB, NULL, (void*) &dl_dcch_msg_NB_IoT, (void **) buffer); + + //only change in "asn_DEF_DL_DCCH_Message_NB" +#if defined(ENABLE_ITTI) +# if !defined(DISABLE_XER_SPRINT) + { + char message_string[10000]; + size_t message_string_size; + + if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_DL_DCCH_Message_NB, (void *)&dl_dcch_msg_NB_IoT)) > 0) { + MessageDef *msg_p; + + msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB_NB_IoT, RRC_DL_DCCH, message_string_size + sizeof (IttiMsgText)); + msg_p->ittiMsg.rrc_dl_dcch.size = message_string_size; + memcpy(&msg_p->ittiMsg.rrc_dl_dcch.text, message_string, message_string_size); + + itti_send_msg_to_task(TASK_UNKNOWN, Mod_id, msg_p); + } + } +# endif +#endif + + return encoded; +} + +/*do_ULInformationTransfer*/ +//for the moment is not needed (UE-SIDE) + +/*OAI_UECapability_t *fill_ue_capability*/ + +/*do_RRCConnectionReestablishment_NB-->used to re-establish SRB1*/ //which parameter to use? +uint8_t do_RRCConnectionReestablishment_NB_IoT( + uint8_t Mod_id, + uint8_t* const buffer, + const uint8_t Transaction_id, + const NB_IoT_DL_FRAME_PARMS* const frame_parms, //to be changed + SRB_ToAddModList_NB_r13_t* SRB_list_NB_IoT) //should contain SRB1 already configured? +{ + + asn_enc_rval_t enc_rval; + DL_CCCH_Message_NB_t dl_ccch_msg_NB_IoT; + RRCConnectionReestablishment_NB_t* rrcConnectionReestablishment_NB_IoT; + + memset(&dl_ccch_msg_NB_IoT, 0, sizeof(DL_CCCH_Message_NB_t)); + + dl_ccch_msg_NB_IoT.message.present = DL_CCCH_MessageType_NB_PR_c1; + dl_ccch_msg_NB_IoT.message.choice.c1.present = DL_CCCH_MessageType_NB__c1_PR_rrcConnectionReestablishment_r13; + rrcConnectionReestablishment_NB_IoT = &dl_ccch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionReestablishment_r13; + + //rrcConnectionReestablishment_NB + rrcConnectionReestablishment_NB_IoT->rrc_TransactionIdentifier = Transaction_id; + rrcConnectionReestablishment_NB_IoT->criticalExtensions.present = RRCConnectionReestablishment_NB__criticalExtensions_PR_c1; + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.present = RRCConnectionReestablishment_NB__criticalExtensions__c1_PR_rrcConnectionReestablishment_r13; + + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.srb_ToAddModList_r13 = SRB_list_NB_IoT; + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.drb_ToAddModList_r13 = NULL; + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.drb_ToReleaseList_r13 = NULL; + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.rlf_TimersAndConstants_r13= NULL; + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.mac_MainConfig_r13= NULL; + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.radioResourceConfigDedicated_r13.physicalConfigDedicated_r13 = NULL; + + rrcConnectionReestablishment_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionReestablishment_r13.nextHopChainingCount_r13=0; + + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_CCCH_Message_NB, + (void*)&dl_ccch_msg_NB_IoT, + buffer, + RRC_BUF_SIZE); + + if (enc_rval.encoded <= 0) { + LOG_F(RRC, "ASN1 message encoding failed (%s, %li)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + } + +#ifdef XER_PRINT + xer_fprint(stdout,&asn_DEF_DL_CCCH_Message_NB,(void*)&dl_ccch_msg_NB_IoT); +#endif + +#if defined(ENABLE_ITTI) +# if !defined(DISABLE_XER_SPRINT) + { + char message_string[30000]; + size_t message_string_size; + + if ((message_string_size = xer_sprint(message_string, sizeof(message_string), &asn_DEF_DL_CCCH_Message_NB, (void *) &dl_ccch_msg_NB_IoT)) > 0) { + MessageDef *msg_p; + + msg_p = itti_alloc_new_message_sized (TASK_RRC_ENB_NB_IoT, RRC_DL_CCCH, message_string_size + sizeof (IttiMsgText)); + msg_p->ittiMsg.rrc_dl_ccch.size = message_string_size; + memcpy(&msg_p->ittiMsg.rrc_dl_ccch.text, message_string, message_string_size); + + itti_send_msg_to_task(TASK_UNKNOWN, Mod_id, msg_p); + } + } +# endif +#endif + + LOG_I(RRC,"RRCConnectionReestablishment-NB Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + return 0; +} + +/*do_RRCConnectionRelease_NB--> is used to command the release of an RRC connection*/ +uint8_t do_RRCConnectionRelease_NB_IoT( + uint8_t Mod_id, + uint8_t *buffer, + const uint8_t Transaction_id) +{ + + asn_enc_rval_t enc_rval; + + DL_DCCH_Message_NB_t dl_dcch_msg_NB_IoT; + RRCConnectionRelease_NB_t *rrcConnectionRelease_NB_IoT; + + + memset(&dl_dcch_msg_NB_IoT,0,sizeof(DL_DCCH_Message_NB_t)); + + dl_dcch_msg_NB_IoT.message.present = DL_DCCH_MessageType_NB_PR_c1; + dl_dcch_msg_NB_IoT.message.choice.c1.present = DL_DCCH_MessageType_NB__c1_PR_rrcConnectionRelease_r13; + rrcConnectionRelease_NB_IoT = &dl_dcch_msg_NB_IoT.message.choice.c1.choice.rrcConnectionRelease_r13; + + // RRCConnectionRelease + rrcConnectionRelease_NB_IoT->rrc_TransactionIdentifier = Transaction_id; + rrcConnectionRelease_NB_IoT->criticalExtensions.present = RRCConnectionRelease_NB__criticalExtensions_PR_c1; + rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.present =RRCConnectionRelease_NB__criticalExtensions__c1_PR_rrcConnectionRelease_r13 ; + + rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.releaseCause_r13 = ReleaseCause_NB_r13_other; + rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.redirectedCarrierInfo_r13 = NULL; + rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.extendedWaitTime_r13 = NULL; + + //Why allocate memory for non critical extension? + rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.nonCriticalExtension=CALLOC(1, + sizeof(*rrcConnectionRelease_NB_IoT->criticalExtensions.choice.c1.choice.rrcConnectionRelease_r13.nonCriticalExtension)); + + enc_rval = uper_encode_to_buffer(&asn_DEF_DL_DCCH_Message_NB, + (void*)&dl_dcch_msg_NB_IoT, + buffer, + RRC_BUF_SIZE);//check + + return((enc_rval.encoded+7)/8); +} + + + + diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h b/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h index e88bdadbd9..6fb073f80d 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h @@ -1,293 +1,293 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file asn1_msg.h -* \brief primitives to build the asn1 messages -* \author Raymond Knopp, Navid Nikaein and Michele Paffetti -* \date 2011, 2017 -* \version 1.0 -* \company Eurecom -* \email: raymond.knopp@eurecom.fr ,navid.nikaein@eurecom.fr, michele.paffetti@studio.unibo.it -*/ - -#ifdef USER_MODE -#include -#include -#include /* for atoi(3) */ -#include /* for getopt(3) */ -#include /* for strerror(3) */ -#include /* for EX_* exit codes */ -#include /* for errno */ -#else -#include /* Needed by all modules */ -#endif - -#include -#include /* for _ASN_DEFAULT_STACK_MAX */ - - -#include "RRC/LITE/defs_NB_IoT.h" - -/* - * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) - * output into the chosen string buffer. - * RETURN VALUES: - * 0: The structure is printed. - * -1: Problem printing the structure. - * WARNING: No sensible error value is returned. - */ - - -/** -\brief Generate configuration for SIB1 (eNB). -@param carrier pointer to Carrier information -@param N_RB_DL Number of downlink PRBs -@param frame radio frame number -@return size of encoded bit stream in bytes*/ -uint8_t do_MIB_NB_IoT( - rrc_eNB_carrier_data_NB_IoT_t *carrier, - uint32_t N_RB_DL, - uint32_t frame, - uint32_t hyper_frame); - - -/** -\brief Generate a default configuration for SIB1-NB (eNB). -@param Mod_id Instance of eNB -@param CC_id Component carrier to configure -@param carrier pointer to Carrier information -@param configuration Pointer Configuration Request structure -@return size of encoded bit stream in bytes*/ - -uint8_t do_SIB1_NB_IoT(uint8_t Mod_id, - int CC_id, - rrc_eNB_carrier_data_NB_IoT_t *carrier, - NbIoTRrcConfigurationReq *configuration, - uint32_t frame - ); - -/** -\brief Generate a default configuration for SIB2/SIB3-NB in one System Information PDU (eNB). -@param Mod_id Index of eNB (used to derive some parameters) -@param buffer Pointer to PER-encoded ASN.1 description of SI-NB PDU -@param systemInformation_NB_IoT Pointer to asn1c C representation of SI-NB PDU -@param sib2_NB Pointer (returned) to sib2_NB component withing SI-NB PDU -@param sib3_NB Pointer (returned) to sib3_NB component withing SI-NB PDU -@return size of encoded bit stream in bytes*/ - -uint8_t do_SIB23_NB_IoT(uint8_t Mod_id, - int CC_id, - rrc_eNB_carrier_data_NB_IoT_t *carrier, - NbIoTRrcConfigurationReq *configuration - ); - -/**(UE-SIDE) -\brief Generate an RRCConnectionRequest-NB UL-CCCH-Message (UE) based on random string or S-TMSI. This -routine only generates an mo-data establishment cause. -@param buffer Pointer to PER-encoded ASN.1 description of UL-DCCH-Message PDU -@param rv 5 byte random string or S-TMSI -@param Mod_id -@returns Size of encoded bit stream in bytes*/ - -uint8_t do_RRCConnectionRequest_NB_IoT(uint8_t Mod_id, uint8_t *buffer,uint8_t *rv); - - -/**(UE -SIDE) -\brief Generate an RRCConnectionSetupComplete-NB UL-DCCH-Message (UE) -@param Mod_id -@param Transaction_id -@param dedicatedInfoNASLength -@param dedicatedInfoNAS -@param buffer Pointer to PER-encoded ASN.1 description of UL-DCCH-Message PDU -@returns Size of encoded bit stream in bytes*/ - -uint8_t do_RRCConnectionSetupComplete_NB_IoT(uint8_t Mod_id, uint8_t* buffer, const uint8_t Transaction_id, const int dedicatedInfoNASLength, - const char* dedicatedInfoNAS); - -/** (UE-SIDE) -\brief Generate an RRCConnectionReconfigurationComplete-NB UL-DCCH-Message (UE) -@param buffer Pointer to PER-encoded ASN.1 description of UL-DCCH-Message PDU -@param ctxt_pP -@param Transaction_id -@returns Size of encoded bit stream in bytes*/ - -uint8_t do_RRCConnectionReconfigurationComplete_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - uint8_t* buffer, - const uint8_t Transaction_id -); - -/** -\brief Generate an RRCConnectionSetup-NB DL-CCCH-Message (eNB). This routine configures SRB_ToAddMod (SRB1/SRB1bis-NB) and -PhysicalConfigDedicated-NB IEs. -@param ctxt_pP Running context -@param ue_context_pP UE context -@param CC_id Component Carrier ID -@param buffer Pointer to PER-encoded ASN.1 description of DL-CCCH-Message PDU -@param transmission_mode Transmission mode for UE (1-9) -@param UE_id UE index for this message -@param Transaction_id Transaction_ID for this message -@param SRB_configList Pointer (returned) to SRB1_config/SRB1bis_config(later) IEs for this UE -@param physicalConfigDedicated_NB Pointer (returned) to PhysicalConfigDedicated-NB IE for this UE -@returns Size of encoded bit stream in bytes*/ - -uint8_t do_RRCConnectionSetup_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, - int CC_id, - uint8_t* const buffer, //carrier[CC_id].Srb0.Tx_buffer.Payload - const uint8_t Transaction_id, - const NB_IoT_DL_FRAME_PARMS* const frame_parms, //to be changed but not deleted - SRB_ToAddModList_NB_r13_t** SRB_configList_NB_IoT, //in order to be configured--> stanno puntando alla SRB_configlist dell ue_context - struct PhysicalConfigDedicated_NB_r13** physicalConfigDedicated_NB_IoT //in order to be configured--> stanno puntando alla physicalConfigDedicated dell ue_context -); - - -/** - * For which SRB is used in NB-IoT?? -\brief Generate an RRCConnectionReconfiguration-NB DL-DCCH-Message (eNB). This routine configures SRBToAddMod-NB (SRB1) and one DRBToAddMod-NB -(DRB3). PhysicalConfigDedicated-NB is not updated. -@param ctxt_pP Running context -@param buffer Pointer to PER-encoded ASN.1 description of DL-CCCH-Message PDU -@param Transaction_id Transaction_ID for this message -@param SRB_list_NB Pointer to SRB List to be added/modified (NULL if no additions/modifications) -@param DRB_list_NB Pointer to DRB List to be added/modified (NULL if no additions/modifications) -@param DRB_list2_NB Pointer to DRB List to be released (NULL if none to be released) -//sps not supported by NB-IoT -@param physicalConfigDedicated_NB Pointer to PhysicalConfigDedicated-NB to be modified (NULL if no modifications) -//measurement not supported by NB-IoT -@param mac_MainConfig Pointer to Mac_MainConfig(NULL if no modifications) -//no CBA functionalities -@returns Size of encoded bit stream in bytes*/ - -uint16_t -do_RRCConnectionReconfiguration_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - uint8_t *buffer, - uint8_t Transaction_id, - SRB_ToAddModList_NB_r13_t *SRB_list_NB_IoT, - DRB_ToAddModList_NB_r13_t *DRB_list_NB_IoT, - DRB_ToReleaseList_NB_r13_t *DRB_list2_NB_IoT, - struct PhysicalConfigDedicated_NB_r13 *physicalConfigDedicated, - MAC_MainConfig_t *mac_MainConfig, - struct RRCConnectionReconfiguration_NB_r13_IEs__dedicatedInfoNASList_r13* dedicatedInfoNASList_NB_IoT); - -/** - * E-UTRAN applies the procedure as follows: when only for NB-IoT SRB1 and SRB1bis is established - \brief Generate a SecurityModeCommand - @param ctxt_pP Running context - @param buffer Pointer to PER-encoded ASN.1 description - @param Transaction_id Transaction_ID for this message - @param cipheringAlgorithm - @param integrityProtAlgorithm - */ - -uint8_t do_SecurityModeCommand_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - uint8_t* const buffer, - const uint8_t Transaction_id, - const uint8_t cipheringAlgorithm, - const uint8_t integrityProtAlgorithm); - -/** - * E-UTRAN applies the procedure as follows: when only for NB-IoT SRB1 and SRB1bis is established - \brief Generate a SecurityModeCommand - @param ctxt_pP Running context - @param buffer Pointer to PER-encoded ASN.1 description - @param Transaction_id Transaction_ID for this message - */ - -uint8_t do_UECapabilityEnquiry_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - uint8_t* const buffer, - const uint8_t Transaction_id -); - - -/** - * There is nothing new in this type of message for NB-IoT (only change in some nomenclature) -\brief Generate an RRCConnectionReestablishmentReject DL-CCCH-Message (eNB). -@param Mod_id Module ID of eNB -@param buffer Pointer to PER-encoded ASN.1 description of DL-CCCH-Message PDU -@returns Size of encoded bit stream in bytes*/ - -uint8_t -do_RRCConnectionReestablishmentReject_NB_IoT( - uint8_t Mod_id, - uint8_t* const buffer); - - -/** -\brief Generate an RRCConnectionReject-NB DL-CCCH-Message (eNB). -@param Mod_id Module ID of eNB -@param buffer Pointer to PER-encoded ASN.1 description of DL-CCCH-Message PDU -@returns Size of encoded bit stream in bytes*/ -uint8_t -do_RRCConnectionReject_NB_IoT( - uint8_t Mod_id, - uint8_t* const buffer); - - -/** -\brief Generate an RRCConnectionRelease-NB DL-DCCH-Message -@param Mod_id Module ID of eNB -@param buffer Pointer to PER-encoded ASN.1 description -@param transaction_id Transaction index -@returns Size of encoded bit stream in bytes*/ - -uint8_t do_RRCConnectionRelease_NB_IoT(uint8_t Mod_id, uint8_t *buffer,int Transaction_id); - - -uint8_t do_DLInformationTransfer_NB_IoT( - uint8_t Mod_id, - uint8_t **buffer, - uint8_t transaction_id, - uint32_t pdu_length, - uint8_t *pdu_buffer); - -//for now not implemented since UE side -//uint8_t do_ULInformationTransfer(uint8_t **buffer, uint32_t pdu_length, uint8_t *pdu_buffer); - -//for now not implemented since UE side??? -//OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname) - -/** -\brief Generate an RRCConnectionReestablishment-NB DL-CCCH Message - *@param - * - */ - -uint8_t do_RRCConnectionReestablishment_NB_IoT( - uint8_t Mod_id, - uint8_t* const buffer, - const uint8_t Transaction_id, - const NB_IoT_DL_FRAME_PARMS* const frame_parms, //to be changed - SRB_ToAddModList_NB_r13_t** SRB_configList_NB_IoT - ); - -/** -\brief Generate an RRCConnectionRelease-NB DL-DCCH-Message (eNB) -@param Mod_id Module ID of eNB -@param buffer Pointer to PER-encoded ASN.1 description of DL-DCCH-Message PDU -@param transaction_id Transaction index -@returns Size of encoded bit stream in bytes*/ - -//uint8_t do_RRCConnectionRelease_NB_IoT(uint8_t Mod_id, uint8_t *buffer,int Transaction_id); +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file asn1_msg.h +* \brief primitives to build the asn1 messages +* \author Raymond Knopp, Navid Nikaein and Michele Paffetti +* \date 2011, 2017 +* \version 1.0 +* \company Eurecom +* \email: raymond.knopp@eurecom.fr ,navid.nikaein@eurecom.fr, michele.paffetti@studio.unibo.it +*/ + +#ifdef USER_MODE +#include +#include +#include /* for atoi(3) */ +#include /* for getopt(3) */ +#include /* for strerror(3) */ +#include /* for EX_* exit codes */ +#include /* for errno */ +#else +#include /* Needed by all modules */ +#endif + +#include +#include /* for _ASN_DEFAULT_STACK_MAX */ + + +#include "RRC/LITE/defs_NB_IoT.h" + +/* + * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) + * output into the chosen string buffer. + * RETURN VALUES: + * 0: The structure is printed. + * -1: Problem printing the structure. + * WARNING: No sensible error value is returned. + */ + + +/** +\brief Generate configuration for SIB1 (eNB). +@param carrier pointer to Carrier information +@param N_RB_DL Number of downlink PRBs +@param frame radio frame number +@return size of encoded bit stream in bytes*/ +uint8_t do_MIB_NB_IoT( + rrc_eNB_carrier_data_NB_IoT_t *carrier, + uint32_t N_RB_DL, + uint32_t frame, + uint32_t hyper_frame); + + +/** +\brief Generate a default configuration for SIB1-NB (eNB). +@param Mod_id Instance of eNB +@param CC_id Component carrier to configure +@param carrier pointer to Carrier information +@param configuration Pointer Configuration Request structure +@return size of encoded bit stream in bytes*/ + +uint8_t do_SIB1_NB_IoT(uint8_t Mod_id, + int CC_id, + rrc_eNB_carrier_data_NB_IoT_t *carrier, + NbIoTRrcConfigurationReq *configuration, + uint32_t frame + ); + +/** +\brief Generate a default configuration for SIB2/SIB3-NB in one System Information PDU (eNB). +@param Mod_id Index of eNB (used to derive some parameters) +@param buffer Pointer to PER-encoded ASN.1 description of SI-NB PDU +@param systemInformation_NB_IoT Pointer to asn1c C representation of SI-NB PDU +@param sib2_NB Pointer (returned) to sib2_NB component withing SI-NB PDU +@param sib3_NB Pointer (returned) to sib3_NB component withing SI-NB PDU +@return size of encoded bit stream in bytes*/ + +uint8_t do_SIB23_NB_IoT(uint8_t Mod_id, + int CC_id, + rrc_eNB_carrier_data_NB_IoT_t *carrier, + NbIoTRrcConfigurationReq *configuration + ); + +/**(UE-SIDE) +\brief Generate an RRCConnectionRequest-NB UL-CCCH-Message (UE) based on random string or S-TMSI. This +routine only generates an mo-data establishment cause. +@param buffer Pointer to PER-encoded ASN.1 description of UL-DCCH-Message PDU +@param rv 5 byte random string or S-TMSI +@param Mod_id +@returns Size of encoded bit stream in bytes*/ + +uint8_t do_RRCConnectionRequest_NB_IoT(uint8_t Mod_id, uint8_t *buffer,uint8_t *rv); + + +/**(UE -SIDE) +\brief Generate an RRCConnectionSetupComplete-NB UL-DCCH-Message (UE) +@param Mod_id +@param Transaction_id +@param dedicatedInfoNASLength +@param dedicatedInfoNAS +@param buffer Pointer to PER-encoded ASN.1 description of UL-DCCH-Message PDU +@returns Size of encoded bit stream in bytes*/ + +uint8_t do_RRCConnectionSetupComplete_NB_IoT(uint8_t Mod_id, uint8_t* buffer, const uint8_t Transaction_id, const int dedicatedInfoNASLength, + const char* dedicatedInfoNAS); + +/** (UE-SIDE) +\brief Generate an RRCConnectionReconfigurationComplete-NB UL-DCCH-Message (UE) +@param buffer Pointer to PER-encoded ASN.1 description of UL-DCCH-Message PDU +@param ctxt_pP +@param Transaction_id +@returns Size of encoded bit stream in bytes*/ + +uint8_t do_RRCConnectionReconfigurationComplete_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + uint8_t* buffer, + const uint8_t Transaction_id +); + +/** +\brief Generate an RRCConnectionSetup-NB DL-CCCH-Message (eNB). This routine configures SRB_ToAddMod (SRB1/SRB1bis-NB) and +PhysicalConfigDedicated-NB IEs. +@param ctxt_pP Running context +@param ue_context_pP UE context +@param CC_id Component Carrier ID +@param buffer Pointer to PER-encoded ASN.1 description of DL-CCCH-Message PDU +@param transmission_mode Transmission mode for UE (1-9) +@param UE_id UE index for this message +@param Transaction_id Transaction_ID for this message +@param SRB_configList Pointer (returned) to SRB1_config/SRB1bis_config(later) IEs for this UE +@param physicalConfigDedicated_NB Pointer (returned) to PhysicalConfigDedicated-NB IE for this UE +@returns Size of encoded bit stream in bytes*/ + +uint8_t do_RRCConnectionSetup_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, + int CC_id, + uint8_t* const buffer, //carrier[CC_id].Srb0.Tx_buffer.Payload + const uint8_t Transaction_id, + const NB_IoT_DL_FRAME_PARMS* const frame_parms, //to be changed but not deleted + SRB_ToAddModList_NB_r13_t** SRB_configList_NB_IoT, //in order to be configured--> stanno puntando alla SRB_configlist dell ue_context + struct PhysicalConfigDedicated_NB_r13** physicalConfigDedicated_NB_IoT //in order to be configured--> stanno puntando alla physicalConfigDedicated dell ue_context +); + + +/** + * For which SRB is used in NB-IoT?? +\brief Generate an RRCConnectionReconfiguration-NB DL-DCCH-Message (eNB). This routine configures SRBToAddMod-NB (SRB1) and one DRBToAddMod-NB +(DRB3). PhysicalConfigDedicated-NB is not updated. +@param ctxt_pP Running context +@param buffer Pointer to PER-encoded ASN.1 description of DL-CCCH-Message PDU +@param Transaction_id Transaction_ID for this message +@param SRB_list_NB Pointer to SRB List to be added/modified (NULL if no additions/modifications) +@param DRB_list_NB Pointer to DRB List to be added/modified (NULL if no additions/modifications) +@param DRB_list2_NB Pointer to DRB List to be released (NULL if none to be released) +//sps not supported by NB-IoT +@param physicalConfigDedicated_NB Pointer to PhysicalConfigDedicated-NB to be modified (NULL if no modifications) +//measurement not supported by NB-IoT +@param mac_MainConfig Pointer to Mac_MainConfig(NULL if no modifications) +//no CBA functionalities +@returns Size of encoded bit stream in bytes*/ + +uint16_t +do_RRCConnectionReconfiguration_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + uint8_t *buffer, + uint8_t Transaction_id, + SRB_ToAddModList_NB_r13_t *SRB_list_NB_IoT, + DRB_ToAddModList_NB_r13_t *DRB_list_NB_IoT, + DRB_ToReleaseList_NB_r13_t *DRB_list2_NB_IoT, + struct PhysicalConfigDedicated_NB_r13 *physicalConfigDedicated, + MAC_MainConfig_t *mac_MainConfig, + struct RRCConnectionReconfiguration_NB_r13_IEs__dedicatedInfoNASList_r13* dedicatedInfoNASList_NB_IoT); + +/** + * E-UTRAN applies the procedure as follows: when only for NB-IoT SRB1 and SRB1bis is established + \brief Generate a SecurityModeCommand + @param ctxt_pP Running context + @param buffer Pointer to PER-encoded ASN.1 description + @param Transaction_id Transaction_ID for this message + @param cipheringAlgorithm + @param integrityProtAlgorithm + */ + +uint8_t do_SecurityModeCommand_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + uint8_t* const buffer, + const uint8_t Transaction_id, + const uint8_t cipheringAlgorithm, + const uint8_t integrityProtAlgorithm); + +/** + * E-UTRAN applies the procedure as follows: when only for NB-IoT SRB1 and SRB1bis is established + \brief Generate a SecurityModeCommand + @param ctxt_pP Running context + @param buffer Pointer to PER-encoded ASN.1 description + @param Transaction_id Transaction_ID for this message + */ + +uint8_t do_UECapabilityEnquiry_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + uint8_t* const buffer, + const uint8_t Transaction_id +); + + +/** + * There is nothing new in this type of message for NB-IoT (only change in some nomenclature) +\brief Generate an RRCConnectionReestablishmentReject DL-CCCH-Message (eNB). +@param Mod_id Module ID of eNB +@param buffer Pointer to PER-encoded ASN.1 description of DL-CCCH-Message PDU +@returns Size of encoded bit stream in bytes*/ + +uint8_t +do_RRCConnectionReestablishmentReject_NB_IoT( + uint8_t Mod_id, + uint8_t* const buffer); + + +/** +\brief Generate an RRCConnectionReject-NB DL-CCCH-Message (eNB). +@param Mod_id Module ID of eNB +@param buffer Pointer to PER-encoded ASN.1 description of DL-CCCH-Message PDU +@returns Size of encoded bit stream in bytes*/ +uint8_t +do_RRCConnectionReject_NB_IoT( + uint8_t Mod_id, + uint8_t* const buffer); + + +/** +\brief Generate an RRCConnectionRelease-NB DL-DCCH-Message +@param Mod_id Module ID of eNB +@param buffer Pointer to PER-encoded ASN.1 description +@param transaction_id Transaction index +@returns Size of encoded bit stream in bytes*/ + +uint8_t do_RRCConnectionRelease_NB_IoT(uint8_t Mod_id, uint8_t *buffer,int Transaction_id); + + +uint8_t do_DLInformationTransfer_NB_IoT( + uint8_t Mod_id, + uint8_t **buffer, + uint8_t transaction_id, + uint32_t pdu_length, + uint8_t *pdu_buffer); + +//for now not implemented since UE side +//uint8_t do_ULInformationTransfer(uint8_t **buffer, uint32_t pdu_length, uint8_t *pdu_buffer); + +//for now not implemented since UE side??? +//OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname) + +/** +\brief Generate an RRCConnectionReestablishment-NB DL-CCCH Message + *@param + * + */ + +uint8_t do_RRCConnectionReestablishment_NB_IoT( + uint8_t Mod_id, + uint8_t* const buffer, + const uint8_t Transaction_id, + const NB_IoT_DL_FRAME_PARMS* const frame_parms, //to be changed + SRB_ToAddModList_NB_r13_t** SRB_configList_NB_IoT + ); + +/** +\brief Generate an RRCConnectionRelease-NB DL-DCCH-Message (eNB) +@param Mod_id Module ID of eNB +@param buffer Pointer to PER-encoded ASN.1 description of DL-DCCH-Message PDU +@param transaction_id Transaction index +@returns Size of encoded bit stream in bytes*/ + +//uint8_t do_RRCConnectionRelease_NB_IoT(uint8_t Mod_id, uint8_t *buffer,int Transaction_id); diff --git a/openair2/RRC/LITE/defs_NB_IoT.h b/openair2/RRC/LITE/defs_NB_IoT.h index a5fdbb702e..376b66c79a 100644 --- a/openair2/RRC/LITE/defs_NB_IoT.h +++ b/openair2/RRC/LITE/defs_NB_IoT.h @@ -1,570 +1,570 @@ -/* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file RRC/LITE/defs_NB_IoT.h -* \brief NB-IoT RRC struct definitions and function prototypes -* \author Navid Nikaein, Raymond Knopp and Michele Paffetti -* \date 2010 - 2014, 2017 -* \version 1.0 -* \company Eurecom -* \email: navid.nikaein@eurecom.fr, raymond.knopp@eurecom.fr, michele.paffetti@studio.unibo.it -*/ - -#ifndef __OPENAIR_RRC_DEFS_NB_IOT_H__ -#define __OPENAIR_RRC_DEFS_NB_IOT_H__ - - -#include -#include -#include - -#include "collection/tree.h" -#include "rrc_types_NB_IoT.h" -#include "COMMON/platform_constants.h" -#include "COMMON/platform_types.h" -#include "targets/COMMON/openairinterface5g_limits.h" - -#include "COMMON/mac_rrc_primitives.h" - -//-----NB-IoT #include files------- - -//#include "SystemInformationBlockType1-NB.h" -//#include "SystemInformation-NB.h" -#include "RRCConnectionReconfiguration-NB.h" -#include "RRCConnectionReconfigurationComplete-NB.h" -#include "RRCConnectionSetup-NB.h" -#include "RRCConnectionSetupComplete-NB.h" -#include "RRCConnectionRequest-NB.h" -#include "RRCConnectionReestablishmentRequest-NB.h" -#include "BCCH-DL-SCH-Message-NB.h" -#include "BCCH-BCH-Message-NB.h" -#include "AS-Config-NB.h" -#include "AS-Context-NB.h" -#include "UE-Capability-NB-r13.h" //equivalent of UE-EUTRA-Capability.h -//------------------- - -#if defined(ENABLE_ITTI) -# include "intertask_interface.h" -#endif - -/* TODO: be sure this include is correct. - * It solves a problem of compilation of the RRH GW, - * issue #186. - */ -#if !defined(ENABLE_ITTI) -# include "as_message.h" -#endif - -#if defined(ENABLE_USE_MME) -# include "commonDef.h" -#endif - -#if ENABLE_RAL -# include "collection/hashtable/obj_hashtable.h" -#endif - - - -/*I will change the name of the structure for compile purposes--> hope not to undo this process*/ - -typedef unsigned int uid_NB_IoT_t; -#define UID_LINEAR_ALLOCATOR_BITMAP_SIZE_NB_IoT (((NUMBER_OF_UE_MAX_NB_IoT/8)/sizeof(unsigned int)) + 1) - -typedef struct uid_linear_allocator_NB_IoT_s { - unsigned int bitmap[UID_LINEAR_ALLOCATOR_BITMAP_SIZE_NB_IoT]; -} uid_allocator_NB_IoT_t; - - -#define PROTOCOL_RRC_CTXT_UE_FMT PROTOCOL_CTXT_FMT -#define PROTOCOL_RRC_CTXT_UE_ARGS(CTXT_Pp) PROTOCOL_CTXT_ARGS(CTXT_Pp) - -#define PROTOCOL_RRC_CTXT_FMT PROTOCOL_CTXT_FMT -#define PROTOCOL_RRC_CTXT_ARGS(CTXT_Pp) PROTOCOL_CTXT_ARGS(CTXT_Pp) - - -//left as they are --> used in LAYER2/epenair2_proc.c and UE side -typedef enum UE_STATE_NB_IoT_e { - RRC_INACTIVE_NB_IoT=0, - RRC_IDLE_NB_IoT, - RRC_SI_RECEIVED_NB_IoT, - RRC_CONNECTED_NB_IoT, - RRC_RECONFIGURED_NB_IoT, - RRC_HO_EXECUTION_NB_IoT //maybe not needed? -} UE_STATE_NB_IoT_t; - - -/** @defgroup _rrc RRC - * @ingroup _oai2 - * @{ - */ -typedef struct UE_RRC_INFO_NB_IoT_s { - UE_STATE_NB_IoT_t State; - uint8_t SIB1systemInfoValueTag; - uint32_t SIStatus; - uint32_t SIcnt; -#if defined(Rel10) || defined(Rel14) - uint8_t MCCHStatus[8]; // MAX_MBSFN_AREA -#endif - uint8_t SIwindowsize; //!< Corresponds to the SIB1 si-WindowLength parameter. The unit is ms. Possible values are (final): 1,2,5,10,15,20,40 - uint8_t handoverTarget; - //HO_STATE_t ho_state; - uint16_t SIperiod; //!< Corresponds to the SIB1 si-Periodicity parameter (multiplied by 10). Possible values are (final): 80,160,320,640,1280,2560,5120 - unsigned short UE_index; - uint32_t T300_active; - uint32_t T300_cnt; - uint32_t T304_active; - uint32_t T304_cnt; - uint32_t T310_active; - uint32_t T310_cnt; - uint32_t N310_cnt; - uint32_t N311_cnt; - rnti_t rnti; -} __attribute__ ((__packed__)) UE_RRC_INFO_NB_IoT; - -//#define NUM_PRECONFIGURED_LCHAN (NB_CH_CX*2) //BCCH, CCCH - -#define UE_MODULE_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! -#define UE_INDEX_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! used to be -1 - - - -// HO_STATE is not supported by NB-IoT - -//#define NUMBER_OF_UE_MAX MAX_MOBILES_PER_RG -#define RRM_FREE(p) if ( (p) != NULL) { free(p) ; p=NULL ; } -#define RRM_MALLOC(t,n) (t *) malloc16( sizeof(t) * n ) -#define RRM_CALLOC(t,n) (t *) malloc16( sizeof(t) * n) -#define RRM_CALLOC2(t,s) (t *) malloc16( s ) - -//Measurement Report not supported in NB-IoT - -#define PAYLOAD_SIZE_MAX 1024 -#define RRC_BUF_SIZE 255 -#define UNDEF_SECURITY_MODE 0xff -#define NO_SECURITY_MODE 0x20 - -/* TS 36.331: RRC-TransactionIdentifier ::= INTEGER (0..3) */ -#define RRC_TRANSACTION_IDENTIFIER_NUMBER 3 - -typedef struct UE_S_TMSI_NB_IoT_s { - boolean_t presence; - mme_code_t mme_code; - m_tmsi_t m_tmsi; -} __attribute__ ((__packed__)) UE_S_TMSI_NB_IoT; - - -typedef enum e_rab_satus_NB_IoT_e { - E_RAB_STATUS_NEW_NB_IoT, - E_RAB_STATUS_DONE_NB_IoT, // from the eNB perspective - E_RAB_STATUS_ESTABLISHED_NB_IoT, // get the reconfigurationcomplete form UE - E_RAB_STATUS_FAILED_NB_IoT, -} e_rab_status_NB_IoT_t; - -typedef struct e_rab_param_NB_IoT_s { - e_rab_t param; - uint8_t status; - uint8_t xid; // transaction_id -} __attribute__ ((__packed__)) e_rab_param_NB_IoT_t; - - -//HANDOVER_INFO not implemented in NB-IoT delete - - -#define RRC_HEADER_SIZE_MAX 64 -#define RRC_BUFFER_SIZE_MAX 1024 - -typedef struct { - char Payload[RRC_BUFFER_SIZE_MAX]; - char Header[RRC_HEADER_SIZE_MAX]; - char payload_size; -} RRC_BUFFER_NB_IoT; - -#define RRC_BUFFER_SIZE_NB_IoT sizeof(RRC_BUFFER_NB_IoT) - - -typedef struct RB_INFO_NB_IoT_s { - uint16_t Rb_id; //=Lchan_id - //LCHAN_DESC Lchan_desc[2]; no more used - //MAC_MEAS_REQ_ENTRY *Meas_entry; //may not needed for NB-IoT -} RB_INFO_NB_IoT; - -typedef struct SRB_INFO_NB_IoT_s { - uint16_t Srb_id; //=Lchan_id---> useful for distinguish between SRB1 and SRB1bis? - RRC_BUFFER_NB_IoT Rx_buffer; - RRC_BUFFER_NB_IoT Tx_buffer; - //LCHAN_DESC Lchan_desc[2]; no more used - unsigned int Trans_id; - uint8_t Active; -} SRB_INFO_NB_IoT; - - -typedef struct RB_INFO_TABLE_ENTRY_NB_IoT_s { - RB_INFO_NB_IoT Rb_info; - uint8_t Active; - uint32_t Next_check_frame; - uint8_t Status; -} RB_INFO_TABLE_ENTRY_NB_IoT; - -typedef struct SRB_INFO_TABLE_ENTRY_NB_IoT_s { - SRB_INFO_NB_IoT Srb_info; - uint8_t Active; - uint8_t Status; - uint32_t Next_check_frame; -} SRB_INFO_TABLE_ENTRY_NB_IoT; - -//MEAS_REPORT_LIST_s not implemented in NB-IoT but is used at UE side -//HANDOVER_INFO_UE not implemented in NB-IoT -typedef struct HANDOVER_INFO_UE_NB_IoT_s { - PhysCellId_t targetCellId; - uint8_t measFlag; -} HANDOVER_INFO_UE_NB_IoT; - -//NB-IoT eNB_RRC_UE_NB_IoT_s--(used as a context in eNB --> ue_context in rrc_eNB_ue_context)------ -typedef struct eNB_RRC_UE_NB_IoT_s { - - EstablishmentCause_t establishment_cause; - uint8_t primaryCC_id; - //in NB-IoT only SRB0, SRB1 and SRB1bis (until AS security activation) exist - - /*MP: Concept behind List and List2 - * - * SRB_configList --> is used for the actual list of SRBs that is managed/that should be send over the RRC message - * SRB_configList2--> refers to all the SRBs configured for that specific transaction identifier - * this because in a single transaction one or more SRBs could be established - * and you want to keep memory on what happen for every transaction - * Transaction ID (xid): is used to associate the proper RRC....Complete message received by the UE to the corresponding - * message previously sent by the eNB (e.g. RRCConnectionSetup -- RRCConnectionSetupComplete) - * this because it could happen that more messages are transmitted at the same time - */ - SRB_ToAddModList_NB_r13_t* SRB_configList;//for SRB1 and SRB1bis - SRB_ToAddModList_NB_r13_t* SRB_configList2[RRC_TRANSACTION_IDENTIFIER_NUMBER]; - DRB_ToAddModList_NB_r13_t* DRB_configList; //for all the DRBs - DRB_ToAddModList_NB_r13_t* DRB_configList2[RRC_TRANSACTION_IDENTIFIER_NUMBER]; //for the configured DRBs of a xid - uint8_t DRB_active[2];//in LTE was 8 --> at most 2 for NB-IoT - - struct PhysicalConfigDedicated_NB_r13* physicalConfigDedicated_NB_IoT; - MAC_MainConfig_NB_r13_t* mac_MainConfig_NB_IoT; - - //No SPS(semi-persistent scheduling) in NB-IoT - //No Measurement report in NB-IoT - - SRB_INFO_NB_IoT SI; - SRB_INFO_NB_IoT Srb0; - SRB_INFO_TABLE_ENTRY_NB_IoT Srb1; - SRB_INFO_TABLE_ENTRY_NB_IoT Srb1bis; - -#if defined(ENABLE_SECURITY) - /* KeNB as derived from KASME received from EPC */ - uint8_t kenb[32]; -#endif - - /* Used integrity/ciphering algorithms--> maintained the same for NB-IoT */ - e_CipheringAlgorithm_r12 ciphering_algorithm; //Specs. TS 36.331 V14.1.0 pag 432 Change position of chipering enumerative w.r.t previous version - e_SecurityAlgorithmConfig__integrityProtAlgorithm integrity_algorithm; - - uint8_t Status; - rnti_t rnti; - uint64_t random_ue_identity; - - - - /* Information from UE RRC ConnectionRequest-NB-r13_IE--> NB-IoT */ - UE_S_TMSI_NB_IoT Initialue_identity_s_TMSI; - EstablishmentCause_NB_r13_t establishment_cause_NB_IoT; //different set for NB-IoT - - /* Information from UE RRC ConnectionReestablishmentRequest-NB--> NB-IoT */ - ReestablishmentCause_NB_r13_t reestablishment_cause_NB_IoT; //different set for NB_IoT - - /* UE id for initial connection to S1AP */ - uint16_t ue_initial_id; - - /* Information from S1AP initial_context_setup_req */ - uint32_t eNB_ue_s1ap_id :24; - - security_capabilities_t security_capabilities; - - /* Total number of e_rab already setup in the list */ //NAS list? - uint8_t setup_e_rabs; - /* Number of e_rab to be setup in the list */ //NAS list? - uint8_t nb_of_e_rabs; - /* list of e_rab to be setup by RRC layers */ - e_rab_param_NB_IoT_t e_rab[NB_RB_MAX_NB_IOT];//[S1AP_MAX_E_RAB]; - - // LG: For GTPV1 TUNNELS - uint32_t enb_gtp_teid[S1AP_MAX_E_RAB]; - transport_layer_addr_t enb_gtp_addrs[S1AP_MAX_E_RAB]; - rb_id_t enb_gtp_ebi[S1AP_MAX_E_RAB]; - - //Which timers are referring to? - uint32_t ul_failure_timer; - uint32_t ue_release_timer; - //threshold of the release timer--> set in RRCConnectionRelease - uint32_t ue_release_timer_thres; -} eNB_RRC_UE_NB_IoT_t; -//-------------------------------------------------------------------------------- - -typedef uid_NB_IoT_t ue_uid_t; - - -//generally variable called: ue_context_pP -typedef struct rrc_eNB_ue_context_NB_IoT_s { - - /* Tree related data */ - RB_ENTRY(rrc_eNB_ue_context_NB_IoT_s) entries; - - /* Uniquely identifies the UE between MME and eNB within the eNB. - * This id is encoded on 24bits. - */ - rnti_t ue_id_rnti; - - // another key for protocol layers but should not be used as a key for RB tree - ue_uid_t local_uid; - - /* UE id for initial connection to S1AP */ - struct eNB_RRC_UE_NB_IoT_s ue_context; //context of ue in the e-nB - -} rrc_eNB_ue_context_NB_IoT_t; - - - -//---NB-IoT (completely changed)------------------------------- -//called "carrier"--> data from PHY layer -typedef struct { - - // buffer that contains the encoded messages - uint8_t *MIB_NB_IoT; - uint8_t sizeof_MIB_NB_IoT; - - uint8_t *SIB1_NB_IoT; - uint8_t sizeof_SIB1_NB_IoT; - uint8_t *SIB23_NB_IoT; - uint8_t sizeof_SIB23_NB_IoT; - - - //not actually implemented in OAI - uint8_t *SIB4_NB_IoT; - uint8_t sizeof_SIB4_NB_IoT; - uint8_t *SIB5_NB_IoT; - uint8_t sizeof_SIB5_NB_IoT; - uint8_t *SIB14_NB_IoT; - uint8_t sizeof_SIB14_NB_IoT; - uint8_t *SIB16_NB_IoT; - uint8_t sizeof_SIB16_NB_IoT; - - //TS 36.331 V14.2.1 -// uint8_t *SIB15_NB; -// uint8_t sizeof_SIB15_NB; -// uint8_t *SIB20_NB; -// uint8_t sizeof_SIB20_NB; -// uint8_t *SIB22_NB; -// uint8_t sizeof_SIB22_NB; - - //implicit parameters needed - int Ncp; //cyclic prefix for DL - int Ncp_UL; //cyclic prefix for UL - int p_eNB; //number of tx antenna port - int p_rx_eNB; //number of receiving antenna ports - uint32_t dl_CarrierFreq; //detected by the UE - uint32_t ul_CarrierFreq; //detected by the UE - uint16_t physCellId; //not stored in the MIB-NB but is getting through NPSS/NSSS - - //are the only static one (memory has been already allocated) - BCCH_BCH_Message_NB_t mib_NB_IoT; - BCCH_DL_SCH_Message_NB_t siblock1_NB_IoT; //SIB1-NB - BCCH_DL_SCH_Message_NB_t systemInformation_NB_IoT; //SI - - SystemInformationBlockType1_NB_t *sib1_NB_IoT; - SystemInformationBlockType2_NB_r13_t *sib2_NB_IoT; - SystemInformationBlockType3_NB_r13_t *sib3_NB_IoT; - //not implemented yet - SystemInformationBlockType4_NB_r13_t *sib4_NB_IoT; - SystemInformationBlockType5_NB_r13_t *sib5_NB_IoT; - SystemInformationBlockType14_NB_r13_t *sib14_NB_IoT; - SystemInformationBlockType16_NB_r13_t *sib16_NB_IoT; - - - SRB_INFO_NB_IoT SI; - SRB_INFO_NB_IoT Srb0; - - uint8_t **MCCH_MESSAGE; // probably not needed , but added to remove errors - uint8_t sizeof_MCCH_MESSAGE[8];// but added to remove errors - SRB_INFO_NB_IoT MCCH_MESS[8];// MAX_MBSFN_AREA - /*future implementation TS 36.331 V14.2.1 - SystemInformationBlockType15_NB_r14_t *sib15; - SystemInformationBlockType20_NB_r14_t *sib20; - SystemInformationBlockType22_NB_r14_t *sib22; - - uint8_t SCPTM_flag; - uint8_t sizeof_SC_MCHH_MESS[]; - SC_MCCH_Message_NB_t scptm;*/ - - -} rrc_eNB_carrier_data_NB_IoT_t; -//--------------------------------------------------- - - - -//---NB-IoT---(completely change)--------------------- -typedef struct eNB_RRC_INST_NB_IoT_s { - - rrc_eNB_carrier_data_NB_IoT_t carrier[MAX_NUM_CCs]; - - uid_allocator_NB_IoT_t uid_allocator; // for rrc_ue_head - RB_HEAD(rrc_ue_tree_NB_IoT_s, rrc_eNB_ue_context_NB_IoT_s) rrc_ue_head; // ue_context tree key search by rnti - - uint8_t Nb_ue; - - hash_table_t *initial_id2_s1ap_ids; // key is content is rrc_ue_s1ap_ids_t - hash_table_t *s1ap_id2_s1ap_ids ; // key is content is rrc_ue_s1ap_ids_t - - //RRC configuration - RrcConfigurationReq configuration; //rrc_messages_types.h - - // other PLMN parameters - /// Mobile country code - int mcc; - /// Mobile network code - int mnc; - /// number of mnc digits - int mnc_digit_length; - - // other RAN parameters //FIXME: to be checked--> depends on APP layer - int srb1_timer_poll_retransmit; - int srb1_max_retx_threshold; - int srb1_timer_reordering; - int srb1_timer_status_prohibit; - int srs_enable[MAX_NUM_CCs]; - - -} eNB_RRC_INST_NB_IoT; - -#define RRC_HEADER_SIZE_MAX_NB_IoT 64 -#define MAX_UE_CAPABILITY_SIZE_NB_IoT 255 - -//not needed for the moment -typedef struct OAI_UECapability_NB_IoT_s { - uint8_t sdu[MAX_UE_CAPABILITY_SIZE_NB_IoT]; - uint8_t sdu_size; -////NB-IoT------ - UE_Capability_NB_r13_t UE_Capability_NB_IoT; //replace the UE_EUTRA_Capability of LTE -} OAI_UECapability_NB_IoT_t; - -#define RRC_BUFFER_SIZE_MAX_NB_IoT 1024 - - - -typedef struct UE_RRC_INST_NB_IoT_s { - Rrc_State_NB_IoT_t RrcState; - Rrc_Sub_State_NB_IoT_t RrcSubState; -# if defined(ENABLE_USE_MME) - plmn_t plmnID; - Byte_t rat; - as_nas_info_t initialNasMsg; -# endif - OAI_UECapability_NB_IoT_t *UECap; - uint8_t *UECapability; - uint8_t UECapability_size; - - UE_RRC_INFO_NB_IoT Info[NB_SIG_CNX_UE]; - - SRB_INFO_NB_IoT Srb0[NB_SIG_CNX_UE]; - SRB_INFO_TABLE_ENTRY_NB_IoT Srb1[NB_CNX_UE]; - SRB_INFO_TABLE_ENTRY_NB_IoT Srb2[NB_CNX_UE]; - HANDOVER_INFO_UE_NB_IoT HandoverInfoUe; - /* - uint8_t *SIB1[NB_CNX_UE]; - uint8_t sizeof_SIB1[NB_CNX_UE]; - uint8_t *SI[NB_CNX_UE]; - uint8_t sizeof_SI[NB_CNX_UE]; - uint8_t SIB1Status[NB_CNX_UE]; - uint8_t SIStatus[NB_CNX_UE]; - SystemInformationBlockType1_t *sib1[NB_CNX_UE]; - SystemInformation_t *si[NB_CNX_UE]; //!< Temporary storage for an SI message. Decoding happens in decode_SI(). - */ - SystemInformationBlockType2_t *sib2[NB_CNX_UE]; - /* - SystemInformationBlockType3_t *sib3[NB_CNX_UE]; - SystemInformationBlockType4_t *sib4[NB_CNX_UE]; - SystemInformationBlockType5_t *sib5[NB_CNX_UE]; - SystemInformationBlockType6_t *sib6[NB_CNX_UE]; - SystemInformationBlockType7_t *sib7[NB_CNX_UE]; - SystemInformationBlockType8_t *sib8[NB_CNX_UE]; - SystemInformationBlockType9_t *sib9[NB_CNX_UE]; - SystemInformationBlockType10_t *sib10[NB_CNX_UE]; - SystemInformationBlockType11_t *sib11[NB_CNX_UE]; - -#if defined(Rel10) || defined(Rel14) - uint8_t MBMS_flag; - uint8_t *MCCH_MESSAGE[NB_CNX_UE]; - uint8_t sizeof_MCCH_MESSAGE[NB_CNX_UE]; - uint8_t MCCH_MESSAGEStatus[NB_CNX_UE]; - MBSFNAreaConfiguration_r9_t *mcch_message[NB_CNX_UE]; - SystemInformationBlockType12_r9_t *sib12[NB_CNX_UE]; - SystemInformationBlockType13_r9_t *sib13[NB_CNX_UE]; -#endif -#ifdef CBA - uint8_t num_active_cba_groups; - uint16_t cba_rnti[NUM_MAX_CBA_GROUP]; -#endif - uint8_t num_srb; - struct SRB_ToAddMod *SRB1_config[NB_CNX_UE]; - struct SRB_ToAddMod *SRB2_config[NB_CNX_UE]; - struct DRB_ToAddMod *DRB_config[NB_CNX_UE][8]; - rb_id_t *defaultDRB; // remember the ID of the default DRB - MeasObjectToAddMod_t *MeasObj[NB_CNX_UE][MAX_MEAS_OBJ]; - struct ReportConfigToAddMod *ReportConfig[NB_CNX_UE][MAX_MEAS_CONFIG]; - */ - struct QuantityConfig *QuantityConfig[NB_CNX_UE]; - /* - struct MeasIdToAddMod *MeasId[NB_CNX_UE][MAX_MEAS_ID]; - MEAS_REPORT_LIST *measReportList[NB_CNX_UE][MAX_MEAS_ID]; - uint32_t measTimer[NB_CNX_UE][MAX_MEAS_ID][6]; // 6 neighboring cells - RSRP_Range_t s_measure; - struct MeasConfig__speedStatePars *speedStatePars; - struct PhysicalConfigDedicated *physicalConfigDedicated[NB_CNX_UE]; - struct SPS_Config *sps_Config[NB_CNX_UE]; - MAC_MainConfig_t *mac_MainConfig[NB_CNX_UE]; - MeasGapConfig_t *measGapConfig[NB_CNX_UE]; - double filter_coeff_rsrp; // [7] ??? - double filter_coeff_rsrq; // [7] ??? - float rsrp_db[7]; - float rsrq_db[7]; - float rsrp_db_filtered[7]; - float rsrq_db_filtered[7]; -#if ENABLE_RAL - obj_hash_table_t *ral_meas_thresholds; - ral_transaction_id_t scan_transaction_id; -#endif -#if defined(ENABLE_SECURITY) - // KeNB as computed from parameters within USIM card // - uint8_t kenb[32]; -#endif - - // Used integrity/ciphering algorithms // - CipheringAlgorithm_r12_t ciphering_algorithm; - e_SecurityAlgorithmConfig__integrityProtAlgorithm integrity_algorithm; - */ -} UE_RRC_INST_NB_IoT; - - -#include "proto_NB_IoT.h" //should be put here otherwise compilation error - -#endif -/** @} */ +/* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file RRC/LITE/defs_NB_IoT.h +* \brief NB-IoT RRC struct definitions and function prototypes +* \author Navid Nikaein, Raymond Knopp and Michele Paffetti +* \date 2010 - 2014, 2017 +* \version 1.0 +* \company Eurecom +* \email: navid.nikaein@eurecom.fr, raymond.knopp@eurecom.fr, michele.paffetti@studio.unibo.it +*/ + +#ifndef __OPENAIR_RRC_DEFS_NB_IOT_H__ +#define __OPENAIR_RRC_DEFS_NB_IOT_H__ + + +#include +#include +#include + +#include "collection/tree.h" +#include "rrc_types_NB_IoT.h" +#include "COMMON/platform_constants.h" +#include "COMMON/platform_types.h" +#include "targets/COMMON/openairinterface5g_limits.h" + +#include "COMMON/mac_rrc_primitives.h" + +//-----NB-IoT #include files------- + +//#include "SystemInformationBlockType1-NB.h" +//#include "SystemInformation-NB.h" +#include "RRCConnectionReconfiguration-NB.h" +#include "RRCConnectionReconfigurationComplete-NB.h" +#include "RRCConnectionSetup-NB.h" +#include "RRCConnectionSetupComplete-NB.h" +#include "RRCConnectionRequest-NB.h" +#include "RRCConnectionReestablishmentRequest-NB.h" +#include "BCCH-DL-SCH-Message-NB.h" +#include "BCCH-BCH-Message-NB.h" +#include "AS-Config-NB.h" +#include "AS-Context-NB.h" +#include "UE-Capability-NB-r13.h" //equivalent of UE-EUTRA-Capability.h +//------------------- + +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +#endif + +/* TODO: be sure this include is correct. + * It solves a problem of compilation of the RRH GW, + * issue #186. + */ +#if !defined(ENABLE_ITTI) +# include "as_message.h" +#endif + +#if defined(ENABLE_USE_MME) +# include "commonDef.h" +#endif + +#if ENABLE_RAL +# include "collection/hashtable/obj_hashtable.h" +#endif + + + +/*I will change the name of the structure for compile purposes--> hope not to undo this process*/ + +typedef unsigned int uid_NB_IoT_t; +#define UID_LINEAR_ALLOCATOR_BITMAP_SIZE_NB_IoT (((NUMBER_OF_UE_MAX_NB_IoT/8)/sizeof(unsigned int)) + 1) + +typedef struct uid_linear_allocator_NB_IoT_s { + unsigned int bitmap[UID_LINEAR_ALLOCATOR_BITMAP_SIZE_NB_IoT]; +} uid_allocator_NB_IoT_t; + + +#define PROTOCOL_RRC_CTXT_UE_FMT PROTOCOL_CTXT_FMT +#define PROTOCOL_RRC_CTXT_UE_ARGS(CTXT_Pp) PROTOCOL_CTXT_ARGS(CTXT_Pp) + +#define PROTOCOL_RRC_CTXT_FMT PROTOCOL_CTXT_FMT +#define PROTOCOL_RRC_CTXT_ARGS(CTXT_Pp) PROTOCOL_CTXT_ARGS(CTXT_Pp) + + +//left as they are --> used in LAYER2/epenair2_proc.c and UE side +typedef enum UE_STATE_NB_IoT_e { + RRC_INACTIVE_NB_IoT=0, + RRC_IDLE_NB_IoT, + RRC_SI_RECEIVED_NB_IoT, + RRC_CONNECTED_NB_IoT, + RRC_RECONFIGURED_NB_IoT, + RRC_HO_EXECUTION_NB_IoT //maybe not needed? +} UE_STATE_NB_IoT_t; + + +/** @defgroup _rrc RRC + * @ingroup _oai2 + * @{ + */ +typedef struct UE_RRC_INFO_NB_IoT_s { + UE_STATE_NB_IoT_t State; + uint8_t SIB1systemInfoValueTag; + uint32_t SIStatus; + uint32_t SIcnt; +#if defined(Rel10) || defined(Rel14) + uint8_t MCCHStatus[8]; // MAX_MBSFN_AREA +#endif + uint8_t SIwindowsize; //!< Corresponds to the SIB1 si-WindowLength parameter. The unit is ms. Possible values are (final): 1,2,5,10,15,20,40 + uint8_t handoverTarget; + //HO_STATE_t ho_state; + uint16_t SIperiod; //!< Corresponds to the SIB1 si-Periodicity parameter (multiplied by 10). Possible values are (final): 80,160,320,640,1280,2560,5120 + unsigned short UE_index; + uint32_t T300_active; + uint32_t T300_cnt; + uint32_t T304_active; + uint32_t T304_cnt; + uint32_t T310_active; + uint32_t T310_cnt; + uint32_t N310_cnt; + uint32_t N311_cnt; + rnti_t rnti; +} __attribute__ ((__packed__)) UE_RRC_INFO_NB_IoT; + +//#define NUM_PRECONFIGURED_LCHAN (NB_CH_CX*2) //BCCH, CCCH + +#define UE_MODULE_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! +#define UE_INDEX_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! used to be -1 + + + +// HO_STATE is not supported by NB-IoT + +//#define NUMBER_OF_UE_MAX MAX_MOBILES_PER_RG +#define RRM_FREE(p) if ( (p) != NULL) { free(p) ; p=NULL ; } +#define RRM_MALLOC(t,n) (t *) malloc16( sizeof(t) * n ) +#define RRM_CALLOC(t,n) (t *) malloc16( sizeof(t) * n) +#define RRM_CALLOC2(t,s) (t *) malloc16( s ) + +//Measurement Report not supported in NB-IoT + +#define PAYLOAD_SIZE_MAX 1024 +#define RRC_BUF_SIZE 255 +#define UNDEF_SECURITY_MODE 0xff +#define NO_SECURITY_MODE 0x20 + +/* TS 36.331: RRC-TransactionIdentifier ::= INTEGER (0..3) */ +#define RRC_TRANSACTION_IDENTIFIER_NUMBER 3 + +typedef struct UE_S_TMSI_NB_IoT_s { + boolean_t presence; + mme_code_t mme_code; + m_tmsi_t m_tmsi; +} __attribute__ ((__packed__)) UE_S_TMSI_NB_IoT; + + +typedef enum e_rab_satus_NB_IoT_e { + E_RAB_STATUS_NEW_NB_IoT, + E_RAB_STATUS_DONE_NB_IoT, // from the eNB perspective + E_RAB_STATUS_ESTABLISHED_NB_IoT, // get the reconfigurationcomplete form UE + E_RAB_STATUS_FAILED_NB_IoT, +} e_rab_status_NB_IoT_t; + +typedef struct e_rab_param_NB_IoT_s { + e_rab_t param; + uint8_t status; + uint8_t xid; // transaction_id +} __attribute__ ((__packed__)) e_rab_param_NB_IoT_t; + + +//HANDOVER_INFO not implemented in NB-IoT delete + + +#define RRC_HEADER_SIZE_MAX 64 +#define RRC_BUFFER_SIZE_MAX 1024 + +typedef struct { + char Payload[RRC_BUFFER_SIZE_MAX]; + char Header[RRC_HEADER_SIZE_MAX]; + char payload_size; +} RRC_BUFFER_NB_IoT; + +#define RRC_BUFFER_SIZE_NB_IoT sizeof(RRC_BUFFER_NB_IoT) + + +typedef struct RB_INFO_NB_IoT_s { + uint16_t Rb_id; //=Lchan_id + //LCHAN_DESC Lchan_desc[2]; no more used + //MAC_MEAS_REQ_ENTRY *Meas_entry; //may not needed for NB-IoT +} RB_INFO_NB_IoT; + +typedef struct SRB_INFO_NB_IoT_s { + uint16_t Srb_id; //=Lchan_id---> useful for distinguish between SRB1 and SRB1bis? + RRC_BUFFER_NB_IoT Rx_buffer; + RRC_BUFFER_NB_IoT Tx_buffer; + //LCHAN_DESC Lchan_desc[2]; no more used + unsigned int Trans_id; + uint8_t Active; +} SRB_INFO_NB_IoT; + + +typedef struct RB_INFO_TABLE_ENTRY_NB_IoT_s { + RB_INFO_NB_IoT Rb_info; + uint8_t Active; + uint32_t Next_check_frame; + uint8_t Status; +} RB_INFO_TABLE_ENTRY_NB_IoT; + +typedef struct SRB_INFO_TABLE_ENTRY_NB_IoT_s { + SRB_INFO_NB_IoT Srb_info; + uint8_t Active; + uint8_t Status; + uint32_t Next_check_frame; +} SRB_INFO_TABLE_ENTRY_NB_IoT; + +//MEAS_REPORT_LIST_s not implemented in NB-IoT but is used at UE side +//HANDOVER_INFO_UE not implemented in NB-IoT +typedef struct HANDOVER_INFO_UE_NB_IoT_s { + PhysCellId_t targetCellId; + uint8_t measFlag; +} HANDOVER_INFO_UE_NB_IoT; + +//NB-IoT eNB_RRC_UE_NB_IoT_s--(used as a context in eNB --> ue_context in rrc_eNB_ue_context)------ +typedef struct eNB_RRC_UE_NB_IoT_s { + + EstablishmentCause_t establishment_cause; + uint8_t primaryCC_id; + //in NB-IoT only SRB0, SRB1 and SRB1bis (until AS security activation) exist + + /*MP: Concept behind List and List2 + * + * SRB_configList --> is used for the actual list of SRBs that is managed/that should be send over the RRC message + * SRB_configList2--> refers to all the SRBs configured for that specific transaction identifier + * this because in a single transaction one or more SRBs could be established + * and you want to keep memory on what happen for every transaction + * Transaction ID (xid): is used to associate the proper RRC....Complete message received by the UE to the corresponding + * message previously sent by the eNB (e.g. RRCConnectionSetup -- RRCConnectionSetupComplete) + * this because it could happen that more messages are transmitted at the same time + */ + SRB_ToAddModList_NB_r13_t* SRB_configList;//for SRB1 and SRB1bis + SRB_ToAddModList_NB_r13_t* SRB_configList2[RRC_TRANSACTION_IDENTIFIER_NUMBER]; + DRB_ToAddModList_NB_r13_t* DRB_configList; //for all the DRBs + DRB_ToAddModList_NB_r13_t* DRB_configList2[RRC_TRANSACTION_IDENTIFIER_NUMBER]; //for the configured DRBs of a xid + uint8_t DRB_active[2];//in LTE was 8 --> at most 2 for NB-IoT + + struct PhysicalConfigDedicated_NB_r13* physicalConfigDedicated_NB_IoT; + MAC_MainConfig_NB_r13_t* mac_MainConfig_NB_IoT; + + //No SPS(semi-persistent scheduling) in NB-IoT + //No Measurement report in NB-IoT + + SRB_INFO_NB_IoT SI; + SRB_INFO_NB_IoT Srb0; + SRB_INFO_TABLE_ENTRY_NB_IoT Srb1; + SRB_INFO_TABLE_ENTRY_NB_IoT Srb1bis; + +#if defined(ENABLE_SECURITY) + /* KeNB as derived from KASME received from EPC */ + uint8_t kenb[32]; +#endif + + /* Used integrity/ciphering algorithms--> maintained the same for NB-IoT */ + e_CipheringAlgorithm_r12 ciphering_algorithm; //Specs. TS 36.331 V14.1.0 pag 432 Change position of chipering enumerative w.r.t previous version + e_SecurityAlgorithmConfig__integrityProtAlgorithm integrity_algorithm; + + uint8_t Status; + rnti_t rnti; + uint64_t random_ue_identity; + + + + /* Information from UE RRC ConnectionRequest-NB-r13_IE--> NB-IoT */ + UE_S_TMSI_NB_IoT Initialue_identity_s_TMSI; + EstablishmentCause_NB_r13_t establishment_cause_NB_IoT; //different set for NB-IoT + + /* Information from UE RRC ConnectionReestablishmentRequest-NB--> NB-IoT */ + ReestablishmentCause_NB_r13_t reestablishment_cause_NB_IoT; //different set for NB_IoT + + /* UE id for initial connection to S1AP */ + uint16_t ue_initial_id; + + /* Information from S1AP initial_context_setup_req */ + uint32_t eNB_ue_s1ap_id :24; + + security_capabilities_t security_capabilities; + + /* Total number of e_rab already setup in the list */ //NAS list? + uint8_t setup_e_rabs; + /* Number of e_rab to be setup in the list */ //NAS list? + uint8_t nb_of_e_rabs; + /* list of e_rab to be setup by RRC layers */ + e_rab_param_NB_IoT_t e_rab[NB_RB_MAX_NB_IOT];//[S1AP_MAX_E_RAB]; + + // LG: For GTPV1 TUNNELS + uint32_t enb_gtp_teid[S1AP_MAX_E_RAB]; + transport_layer_addr_t enb_gtp_addrs[S1AP_MAX_E_RAB]; + rb_id_t enb_gtp_ebi[S1AP_MAX_E_RAB]; + + //Which timers are referring to? + uint32_t ul_failure_timer; + uint32_t ue_release_timer; + //threshold of the release timer--> set in RRCConnectionRelease + uint32_t ue_release_timer_thres; +} eNB_RRC_UE_NB_IoT_t; +//-------------------------------------------------------------------------------- + +typedef uid_NB_IoT_t ue_uid_t; + + +//generally variable called: ue_context_pP +typedef struct rrc_eNB_ue_context_NB_IoT_s { + + /* Tree related data */ + RB_ENTRY(rrc_eNB_ue_context_NB_IoT_s) entries; + + /* Uniquely identifies the UE between MME and eNB within the eNB. + * This id is encoded on 24bits. + */ + rnti_t ue_id_rnti; + + // another key for protocol layers but should not be used as a key for RB tree + ue_uid_t local_uid; + + /* UE id for initial connection to S1AP */ + struct eNB_RRC_UE_NB_IoT_s ue_context; //context of ue in the e-nB + +} rrc_eNB_ue_context_NB_IoT_t; + + + +//---NB-IoT (completely changed)------------------------------- +//called "carrier"--> data from PHY layer +typedef struct { + + // buffer that contains the encoded messages + uint8_t *MIB_NB_IoT; + uint8_t sizeof_MIB_NB_IoT; + + uint8_t *SIB1_NB_IoT; + uint8_t sizeof_SIB1_NB_IoT; + uint8_t *SIB23_NB_IoT; + uint8_t sizeof_SIB23_NB_IoT; + + + //not actually implemented in OAI + uint8_t *SIB4_NB_IoT; + uint8_t sizeof_SIB4_NB_IoT; + uint8_t *SIB5_NB_IoT; + uint8_t sizeof_SIB5_NB_IoT; + uint8_t *SIB14_NB_IoT; + uint8_t sizeof_SIB14_NB_IoT; + uint8_t *SIB16_NB_IoT; + uint8_t sizeof_SIB16_NB_IoT; + + //TS 36.331 V14.2.1 +// uint8_t *SIB15_NB; +// uint8_t sizeof_SIB15_NB; +// uint8_t *SIB20_NB; +// uint8_t sizeof_SIB20_NB; +// uint8_t *SIB22_NB; +// uint8_t sizeof_SIB22_NB; + + //implicit parameters needed + int Ncp; //cyclic prefix for DL + int Ncp_UL; //cyclic prefix for UL + int p_eNB; //number of tx antenna port + int p_rx_eNB; //number of receiving antenna ports + uint32_t dl_CarrierFreq; //detected by the UE + uint32_t ul_CarrierFreq; //detected by the UE + uint16_t physCellId; //not stored in the MIB-NB but is getting through NPSS/NSSS + + //are the only static one (memory has been already allocated) + BCCH_BCH_Message_NB_t mib_NB_IoT; + BCCH_DL_SCH_Message_NB_t siblock1_NB_IoT; //SIB1-NB + BCCH_DL_SCH_Message_NB_t systemInformation_NB_IoT; //SI + + SystemInformationBlockType1_NB_t *sib1_NB_IoT; + SystemInformationBlockType2_NB_r13_t *sib2_NB_IoT; + SystemInformationBlockType3_NB_r13_t *sib3_NB_IoT; + //not implemented yet + SystemInformationBlockType4_NB_r13_t *sib4_NB_IoT; + SystemInformationBlockType5_NB_r13_t *sib5_NB_IoT; + SystemInformationBlockType14_NB_r13_t *sib14_NB_IoT; + SystemInformationBlockType16_NB_r13_t *sib16_NB_IoT; + + + SRB_INFO_NB_IoT SI; + SRB_INFO_NB_IoT Srb0; + + uint8_t **MCCH_MESSAGE; // probably not needed , but added to remove errors + uint8_t sizeof_MCCH_MESSAGE[8];// but added to remove errors + SRB_INFO_NB_IoT MCCH_MESS[8];// MAX_MBSFN_AREA + /*future implementation TS 36.331 V14.2.1 + SystemInformationBlockType15_NB_r14_t *sib15; + SystemInformationBlockType20_NB_r14_t *sib20; + SystemInformationBlockType22_NB_r14_t *sib22; + + uint8_t SCPTM_flag; + uint8_t sizeof_SC_MCHH_MESS[]; + SC_MCCH_Message_NB_t scptm;*/ + + +} rrc_eNB_carrier_data_NB_IoT_t; +//--------------------------------------------------- + + + +//---NB-IoT---(completely change)--------------------- +typedef struct eNB_RRC_INST_NB_IoT_s { + + rrc_eNB_carrier_data_NB_IoT_t carrier[MAX_NUM_CCs]; + + uid_allocator_NB_IoT_t uid_allocator; // for rrc_ue_head + RB_HEAD(rrc_ue_tree_NB_IoT_s, rrc_eNB_ue_context_NB_IoT_s) rrc_ue_head; // ue_context tree key search by rnti + + uint8_t Nb_ue; + + hash_table_t *initial_id2_s1ap_ids; // key is content is rrc_ue_s1ap_ids_t + hash_table_t *s1ap_id2_s1ap_ids ; // key is content is rrc_ue_s1ap_ids_t + + //RRC configuration + RrcConfigurationReq configuration; //rrc_messages_types.h + + // other PLMN parameters + /// Mobile country code + int mcc; + /// Mobile network code + int mnc; + /// number of mnc digits + int mnc_digit_length; + + // other RAN parameters //FIXME: to be checked--> depends on APP layer + int srb1_timer_poll_retransmit; + int srb1_max_retx_threshold; + int srb1_timer_reordering; + int srb1_timer_status_prohibit; + int srs_enable[MAX_NUM_CCs]; + + +} eNB_RRC_INST_NB_IoT; + +#define RRC_HEADER_SIZE_MAX_NB_IoT 64 +#define MAX_UE_CAPABILITY_SIZE_NB_IoT 255 + +//not needed for the moment +typedef struct OAI_UECapability_NB_IoT_s { + uint8_t sdu[MAX_UE_CAPABILITY_SIZE_NB_IoT]; + uint8_t sdu_size; +////NB-IoT------ + UE_Capability_NB_r13_t UE_Capability_NB_IoT; //replace the UE_EUTRA_Capability of LTE +} OAI_UECapability_NB_IoT_t; + +#define RRC_BUFFER_SIZE_MAX_NB_IoT 1024 + + + +typedef struct UE_RRC_INST_NB_IoT_s { + Rrc_State_NB_IoT_t RrcState; + Rrc_Sub_State_NB_IoT_t RrcSubState; +# if defined(ENABLE_USE_MME) + plmn_t plmnID; + Byte_t rat; + as_nas_info_t initialNasMsg; +# endif + OAI_UECapability_NB_IoT_t *UECap; + uint8_t *UECapability; + uint8_t UECapability_size; + + UE_RRC_INFO_NB_IoT Info[NB_SIG_CNX_UE]; + + SRB_INFO_NB_IoT Srb0[NB_SIG_CNX_UE]; + SRB_INFO_TABLE_ENTRY_NB_IoT Srb1[NB_CNX_UE]; + SRB_INFO_TABLE_ENTRY_NB_IoT Srb2[NB_CNX_UE]; + HANDOVER_INFO_UE_NB_IoT HandoverInfoUe; + /* + uint8_t *SIB1[NB_CNX_UE]; + uint8_t sizeof_SIB1[NB_CNX_UE]; + uint8_t *SI[NB_CNX_UE]; + uint8_t sizeof_SI[NB_CNX_UE]; + uint8_t SIB1Status[NB_CNX_UE]; + uint8_t SIStatus[NB_CNX_UE]; + SystemInformationBlockType1_t *sib1[NB_CNX_UE]; + SystemInformation_t *si[NB_CNX_UE]; //!< Temporary storage for an SI message. Decoding happens in decode_SI(). + */ + SystemInformationBlockType2_t *sib2[NB_CNX_UE]; + /* + SystemInformationBlockType3_t *sib3[NB_CNX_UE]; + SystemInformationBlockType4_t *sib4[NB_CNX_UE]; + SystemInformationBlockType5_t *sib5[NB_CNX_UE]; + SystemInformationBlockType6_t *sib6[NB_CNX_UE]; + SystemInformationBlockType7_t *sib7[NB_CNX_UE]; + SystemInformationBlockType8_t *sib8[NB_CNX_UE]; + SystemInformationBlockType9_t *sib9[NB_CNX_UE]; + SystemInformationBlockType10_t *sib10[NB_CNX_UE]; + SystemInformationBlockType11_t *sib11[NB_CNX_UE]; + +#if defined(Rel10) || defined(Rel14) + uint8_t MBMS_flag; + uint8_t *MCCH_MESSAGE[NB_CNX_UE]; + uint8_t sizeof_MCCH_MESSAGE[NB_CNX_UE]; + uint8_t MCCH_MESSAGEStatus[NB_CNX_UE]; + MBSFNAreaConfiguration_r9_t *mcch_message[NB_CNX_UE]; + SystemInformationBlockType12_r9_t *sib12[NB_CNX_UE]; + SystemInformationBlockType13_r9_t *sib13[NB_CNX_UE]; +#endif +#ifdef CBA + uint8_t num_active_cba_groups; + uint16_t cba_rnti[NUM_MAX_CBA_GROUP]; +#endif + uint8_t num_srb; + struct SRB_ToAddMod *SRB1_config[NB_CNX_UE]; + struct SRB_ToAddMod *SRB2_config[NB_CNX_UE]; + struct DRB_ToAddMod *DRB_config[NB_CNX_UE][8]; + rb_id_t *defaultDRB; // remember the ID of the default DRB + MeasObjectToAddMod_t *MeasObj[NB_CNX_UE][MAX_MEAS_OBJ]; + struct ReportConfigToAddMod *ReportConfig[NB_CNX_UE][MAX_MEAS_CONFIG]; + */ + struct QuantityConfig *QuantityConfig[NB_CNX_UE]; + /* + struct MeasIdToAddMod *MeasId[NB_CNX_UE][MAX_MEAS_ID]; + MEAS_REPORT_LIST *measReportList[NB_CNX_UE][MAX_MEAS_ID]; + uint32_t measTimer[NB_CNX_UE][MAX_MEAS_ID][6]; // 6 neighboring cells + RSRP_Range_t s_measure; + struct MeasConfig__speedStatePars *speedStatePars; + struct PhysicalConfigDedicated *physicalConfigDedicated[NB_CNX_UE]; + struct SPS_Config *sps_Config[NB_CNX_UE]; + MAC_MainConfig_t *mac_MainConfig[NB_CNX_UE]; + MeasGapConfig_t *measGapConfig[NB_CNX_UE]; + double filter_coeff_rsrp; // [7] ??? + double filter_coeff_rsrq; // [7] ??? + float rsrp_db[7]; + float rsrq_db[7]; + float rsrp_db_filtered[7]; + float rsrq_db_filtered[7]; +#if ENABLE_RAL + obj_hash_table_t *ral_meas_thresholds; + ral_transaction_id_t scan_transaction_id; +#endif +#if defined(ENABLE_SECURITY) + // KeNB as computed from parameters within USIM card // + uint8_t kenb[32]; +#endif + + // Used integrity/ciphering algorithms // + CipheringAlgorithm_r12_t ciphering_algorithm; + e_SecurityAlgorithmConfig__integrityProtAlgorithm integrity_algorithm; + */ +} UE_RRC_INST_NB_IoT; + + +#include "proto_NB_IoT.h" //should be put here otherwise compilation error + +#endif +/** @} */ diff --git a/openair2/RRC/LITE/extern_NB_IoT.h b/openair2/RRC/LITE/extern_NB_IoT.h index 39b49ecc03..f5e2f32575 100644 --- a/openair2/RRC/LITE/extern_NB_IoT.h +++ b/openair2/RRC/LITE/extern_NB_IoT.h @@ -1,63 +1,63 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file vars.h -* \brief rrc external vars -* \author Navid Nikaein and Raymond Knopp, Michele Paffetti -* \date 2011-2017 -* \version 1.0 -* \company Eurecom -* \email: navid.nikaein@eurecom.fr, michele.paffetti@studio.unibo.it -*/ - -#ifndef __OPENAIR_RRC_EXTERN_NB_IOT_H__ -#define __OPENAIR_RRC_EXTERN_NB_IOT_H__ -#include "RRC/LITE/defs_NB_IoT.h" -#include "PHY_INTERFACE/IF_Module_NB_IoT.h" -#include "LAYER2/RLC/rlc.h" -#include "LogicalChannelConfig-NB-r13.h" -#include "LAYER2/MAC/defs_NB_IoT.h" +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file vars.h +* \brief rrc external vars +* \author Navid Nikaein and Raymond Knopp, Michele Paffetti +* \date 2011-2017 +* \version 1.0 +* \company Eurecom +* \email: navid.nikaein@eurecom.fr, michele.paffetti@studio.unibo.it +*/ + +#ifndef __OPENAIR_RRC_EXTERN_NB_IOT_H__ +#define __OPENAIR_RRC_EXTERN_NB_IOT_H__ +#include "RRC/LITE/defs_NB_IoT.h" +#include "PHY_INTERFACE/IF_Module_NB_IoT.h" +#include "LAYER2/RLC/rlc.h" +#include "LogicalChannelConfig-NB-r13.h" +#include "LAYER2/MAC/defs_NB_IoT.h" + +#include "common/ran_context.h" + + +//MP: NOTE:XXX some of the parameters defined in vars_nb_iot are called by the extern.h file so not replicated here + +extern UE_RRC_INST_NB_IoT *UE_rrc_inst_NB_IoT; + +extern eNB_RRC_INST_NB_IoT *eNB_rrc_inst_NB_IoT; +extern PHY_Config_NB_IoT_t *config_INFO; + +extern rlc_info_t Rlc_info_am_NB_IoT,Rlc_info_am_config_NB_IoT; +extern uint8_t DRB2LCHAN_NB_IoT[2]; +extern LogicalChannelConfig_NB_r13_t SRB1bis_logicalChannelConfig_defaultValue_NB_IoT; +extern LogicalChannelConfig_NB_r13_t SRB1_logicalChannelConfig_defaultValue_NB_IoT; + +extern uint16_t T300_NB_IoT[8]; +extern uint16_t T301_NB_IoT[8]; +extern uint16_t T310_NB_IoT[8]; +extern uint16_t T311_NB_IoT[8]; +extern uint16_t N310_NB_IoT[8]; +extern uint16_t N311_NB_IoT[8]; +extern uint8_t *get_NB_IoT_MIB(struct eNB_RRC_INST_NB_IoT_s *nb_iot_rrc); +#endif + -#include "common/ran_context.h" - - -//MP: NOTE:XXX some of the parameters defined in vars_nb_iot are called by the extern.h file so not replicated here - -extern UE_RRC_INST_NB_IoT *UE_rrc_inst_NB_IoT; - -extern eNB_RRC_INST_NB_IoT *eNB_rrc_inst_NB_IoT; -extern PHY_Config_NB_IoT_t *config_INFO; - -extern rlc_info_t Rlc_info_am_NB_IoT,Rlc_info_am_config_NB_IoT; -extern uint8_t DRB2LCHAN_NB_IoT[2]; -extern LogicalChannelConfig_NB_r13_t SRB1bis_logicalChannelConfig_defaultValue_NB_IoT; -extern LogicalChannelConfig_NB_r13_t SRB1_logicalChannelConfig_defaultValue_NB_IoT; - -extern uint16_t T300_NB_IoT[8]; -extern uint16_t T301_NB_IoT[8]; -extern uint16_t T310_NB_IoT[8]; -extern uint16_t T311_NB_IoT[8]; -extern uint16_t N310_NB_IoT[8]; -extern uint16_t N311_NB_IoT[8]; -extern uint8_t *get_NB_IoT_MIB(struct eNB_RRC_INST_NB_IoT_s *nb_iot_rrc); -#endif - - diff --git a/openair2/RRC/LITE/proto_NB_IoT.h b/openair2/RRC/LITE/proto_NB_IoT.h index e346204912..b2218517fc 100644 --- a/openair2/RRC/LITE/proto_NB_IoT.h +++ b/openair2/RRC/LITE/proto_NB_IoT.h @@ -1,260 +1,260 @@ -/* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file proto_NB_IoT.h - * \brief RRC functions prototypes for eNB and UE for NB-IoT - * \author Navid Nikaein, Raymond Knopp and Michele Paffetti - * \date 2010 - 2014 - * \email navid.nikaein@eurecom.fr, michele.paffetti@studio.unibo.it - * \version 1.0 - - */ -/** \addtogroup _rrc - * @{ - */ - -#include "RRC/LITE/defs_NB_IoT.h" -#include "pdcp.h" -#include "rlc.h" -#include "extern_NB_IoT.h" -#include "LAYER2/MAC/defs_NB_IoT.h" -/*NOTE: no static function should be declared in this header file (e.g. init_SI_NB)*/ - -/*------------------------common_nb_iot.c----------------------------------------*/ - -/** \brief configure BCCH & CCCH Logical Channels and associated rrc_buffers, configure associated SRBs - */ -void openair_rrc_on_NB_IoT(const protocol_ctxt_t* const ctxt_pP); - -void rrc_config_buffer_NB_IoT(SRB_INFO_NB_IoT *srb_info, uint8_t Lchan_type, uint8_t Role); - -int L3_xface_init_NB_IoT(void); - -void openair_rrc_top_init_eNB_NB_IoT(void); - -//void rrc_top_cleanup(void); -->seems not to be used - -//rrc_t310_expiration-->seems not to be used - -/** \brief Function to update timers every subframe. For UE it updates T300,T304 and T310. -@param ctxt_pP running context -@param enb_index -@param CC_id -*/ -RRC_status_t rrc_rx_tx_NB_IoT(protocol_ctxt_t* const ctxt_pP, const uint8_t enb_index, const int CC_id); - -//long binary_search_int(int elements[], long numElem, int value);--> seems not to be used -//long binary_search_float(float elements[], long numElem, float value);--> used only at UE side - - - -//--------------------------------------- - - -//defined in L2_interface -//called by rx_sdu only in case of CCCH message (e.g RRCConnectionRequest-NB) -int8_t mac_rrc_data_ind_eNB_NB_IoT( - const module_id_t module_idP, - const int CC_id, - const frame_t frameP, - const sub_frame_t sub_frameP, - const rnti_t rntiP, - const rb_id_t srb_idP,//could be skipped since always go through the CCCH channel - const uint8_t* sduP, - const sdu_size_t sdu_lenP -); -//------------------------------------------- - -//defined in L2_interface -void dump_ue_list_NB_IoT(UE_list_NB_IoT_t *listP, int ul_flag); -//------------------------------------------- - - -//defined in L2_interface -void mac_eNB_rrc_ul_failure_NB_IoT( - const module_id_t mod_idP, - const int CC_idP, - const frame_t frameP, - const sub_frame_t subframeP, - const rnti_t rntiP); -//------------------------------------------ - -//defined in eNB_scheduler_primitives.c -int rrc_mac_remove_ue_NB_IoT( - module_id_t mod_idP, - rnti_t rntiP); -//------------------------------------------ -//defined in L2_interface -void mac_eNB_rrc_ul_in_sync_NB_IoT( - const module_id_t mod_idP, - const int CC_idP, - const frame_t frameP, - const sub_frame_t subframeP, - const rnti_t rntiP); -//------------------------------------------ -//defined in L2_interface -int mac_eNB_get_rrc_status_NB_IoT( - const module_id_t Mod_idP, - const rnti_t rntiP -); -//--------------------------- - - -/*-----------eNB procedures (rrc_eNB_nb_iot.c)---------------*/ - -//---Initialization-------------- -void openair_eNB_rrc_on_NB_IoT( - const protocol_ctxt_t* const ctxt_pP -); - -void rrc_config_buffer_NB_IoT( - SRB_INFO_NB_IoT* Srb_info, - uint8_t Lchan_type, - uint8_t Role -); - -char openair_rrc_eNB_configuration_NB_IoT( - const module_id_t enb_mod_idP, - NbIoTRrcConfigurationReq* configuration -); - -//----------------------------- -/**\brief RRC eNB task. (starting of the RRC state machine) - \param void *args_p Pointer on arguments to start the task. */ -void *rrc_enb_task_NB_IoT(void *args_p); - -/**\brief Entry routine to decode a UL-CCCH-Message-NB. Invokes PER decoder and parses message. - \param ctxt_pP Running context - \param Srb_info Pointer to SRB0 information structure (buffer, etc.)*/ -int rrc_eNB_decode_ccch_NB_IoT( - protocol_ctxt_t* const ctxt_pP, - const SRB_INFO_NB_IoT* const Srb_info, - const int CC_id -); - -/**\brief Entry routine to decode a UL-DCCH-Message-NB. Invokes PER decoder and parses message. - \param ctxt_pP Context - \param Rx_sdu Pointer Received Message - \param sdu_size Size of incoming SDU*/ -int rrc_eNB_decode_dcch_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - const rb_id_t Srb_id, - const uint8_t* const Rx_sdu, - const sdu_size_t sdu_sizeP -); - -/**\brief Generate RRCConnectionReestablishmentReject-NB - \param ctxt_pP Running context - \param ue_context_pP UE context - \param CC_id Component Carrier ID*/ -void rrc_eNB_generate_RRCConnectionReestablishmentReject_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, - const int CC_id -); - -void rrc_eNB_generate_RRCConnectionReject_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, - const int CC_id -); - -void rrc_eNB_generate_RRCConnectionSetup_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, - const int CC_id -); - -void rrc_eNB_process_RRCConnectionReconfigurationComplete_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - rrc_eNB_ue_context_NB_IoT_t* ue_context_pP, - const uint8_t xid //transaction identifier -); - - -void //was under ITTI -rrc_eNB_reconfigure_DRBs_NB_IoT(const protocol_ctxt_t* const ctxt_pP, - rrc_eNB_ue_context_NB_IoT_t* ue_context_pP); - -void //was under ITTI -rrc_eNB_generate_dedicatedRRCConnectionReconfiguration_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP -// const uint8_t ho_state - ); - -void rrc_eNB_process_RRCConnectionSetupComplete_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - rrc_eNB_ue_context_NB_IoT_t* ue_context_pP, - RRCConnectionSetupComplete_NB_r13_IEs_t * rrcConnectionSetupComplete_NB -); - -void rrc_eNB_generate_SecurityModeCommand_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP -); - -void rrc_eNB_generate_UECapabilityEnquiry_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP -); - -void rrc_eNB_generate_defaultRRCConnectionReconfiguration_NB_IoT(const protocol_ctxt_t* const ctxt_pP, - rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP - //no HO flag - ); - - -/// Utilities------------------------------------------------ - -void rrc_eNB_free_UE_NB_IoT( - const module_id_t enb_mod_idP, - const struct rrc_eNB_ue_context_NB_IoT_s* const ue_context_pP - ); - -void rrc_eNB_free_mem_UE_context_NB_IoT( - const protocol_ctxt_t* const ctxt_pP, - struct rrc_eNB_ue_context_NB_IoT_s* const ue_context_pP -); - - - -/**\brief Function to get the next transaction identifier. - \param module_idP Instance ID for CH/eNB - \return a transaction identifier*/ -uint8_t rrc_eNB_get_next_transaction_identifier_NB_IoT(module_id_t module_idP); - - -int rrc_init_global_param_NB_IoT(void); - -//L2_interface.c -int8_t mac_rrc_data_req_eNB_NB_IoT( - const module_id_t Mod_idP, - const int CC_id, - const frame_t frameP, - const frame_t h_frameP, - const sub_frame_t subframeP, //need for the case in which both SIB1-NB_IoT and SIB23-NB_IoT will be scheduled in the same frame - const rb_id_t Srb_id, - uint8_t* const buffer_pP, - uint8_t flag -); - - - +/* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file proto_NB_IoT.h + * \brief RRC functions prototypes for eNB and UE for NB-IoT + * \author Navid Nikaein, Raymond Knopp and Michele Paffetti + * \date 2010 - 2014 + * \email navid.nikaein@eurecom.fr, michele.paffetti@studio.unibo.it + * \version 1.0 + + */ +/** \addtogroup _rrc + * @{ + */ + +#include "RRC/LITE/defs_NB_IoT.h" +#include "pdcp.h" +#include "rlc.h" +#include "extern_NB_IoT.h" +#include "LAYER2/MAC/defs_NB_IoT.h" +/*NOTE: no static function should be declared in this header file (e.g. init_SI_NB)*/ + +/*------------------------common_nb_iot.c----------------------------------------*/ + +/** \brief configure BCCH & CCCH Logical Channels and associated rrc_buffers, configure associated SRBs + */ +void openair_rrc_on_NB_IoT(const protocol_ctxt_t* const ctxt_pP); + +void rrc_config_buffer_NB_IoT(SRB_INFO_NB_IoT *srb_info, uint8_t Lchan_type, uint8_t Role); + +int L3_xface_init_NB_IoT(void); + +void openair_rrc_top_init_eNB_NB_IoT(void); + +//void rrc_top_cleanup(void); -->seems not to be used + +//rrc_t310_expiration-->seems not to be used + +/** \brief Function to update timers every subframe. For UE it updates T300,T304 and T310. +@param ctxt_pP running context +@param enb_index +@param CC_id +*/ +RRC_status_t rrc_rx_tx_NB_IoT(protocol_ctxt_t* const ctxt_pP, const uint8_t enb_index, const int CC_id); + +//long binary_search_int(int elements[], long numElem, int value);--> seems not to be used +//long binary_search_float(float elements[], long numElem, float value);--> used only at UE side + + + +//--------------------------------------- + + +//defined in L2_interface +//called by rx_sdu only in case of CCCH message (e.g RRCConnectionRequest-NB) +int8_t mac_rrc_data_ind_eNB_NB_IoT( + const module_id_t module_idP, + const int CC_id, + const frame_t frameP, + const sub_frame_t sub_frameP, + const rnti_t rntiP, + const rb_id_t srb_idP,//could be skipped since always go through the CCCH channel + const uint8_t* sduP, + const sdu_size_t sdu_lenP +); +//------------------------------------------- + +//defined in L2_interface +void dump_ue_list_NB_IoT(UE_list_NB_IoT_t *listP, int ul_flag); +//------------------------------------------- + + +//defined in L2_interface +void mac_eNB_rrc_ul_failure_NB_IoT( + const module_id_t mod_idP, + const int CC_idP, + const frame_t frameP, + const sub_frame_t subframeP, + const rnti_t rntiP); +//------------------------------------------ + +//defined in eNB_scheduler_primitives.c +int rrc_mac_remove_ue_NB_IoT( + module_id_t mod_idP, + rnti_t rntiP); +//------------------------------------------ +//defined in L2_interface +void mac_eNB_rrc_ul_in_sync_NB_IoT( + const module_id_t mod_idP, + const int CC_idP, + const frame_t frameP, + const sub_frame_t subframeP, + const rnti_t rntiP); +//------------------------------------------ +//defined in L2_interface +int mac_eNB_get_rrc_status_NB_IoT( + const module_id_t Mod_idP, + const rnti_t rntiP +); +//--------------------------- + + +/*-----------eNB procedures (rrc_eNB_nb_iot.c)---------------*/ + +//---Initialization-------------- +void openair_eNB_rrc_on_NB_IoT( + const protocol_ctxt_t* const ctxt_pP +); + +void rrc_config_buffer_NB_IoT( + SRB_INFO_NB_IoT* Srb_info, + uint8_t Lchan_type, + uint8_t Role +); + +char openair_rrc_eNB_configuration_NB_IoT( + const module_id_t enb_mod_idP, + NbIoTRrcConfigurationReq* configuration +); + +//----------------------------- +/**\brief RRC eNB task. (starting of the RRC state machine) + \param void *args_p Pointer on arguments to start the task. */ +void *rrc_enb_task_NB_IoT(void *args_p); + +/**\brief Entry routine to decode a UL-CCCH-Message-NB. Invokes PER decoder and parses message. + \param ctxt_pP Running context + \param Srb_info Pointer to SRB0 information structure (buffer, etc.)*/ +int rrc_eNB_decode_ccch_NB_IoT( + protocol_ctxt_t* const ctxt_pP, + const SRB_INFO_NB_IoT* const Srb_info, + const int CC_id +); + +/**\brief Entry routine to decode a UL-DCCH-Message-NB. Invokes PER decoder and parses message. + \param ctxt_pP Context + \param Rx_sdu Pointer Received Message + \param sdu_size Size of incoming SDU*/ +int rrc_eNB_decode_dcch_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + const rb_id_t Srb_id, + const uint8_t* const Rx_sdu, + const sdu_size_t sdu_sizeP +); + +/**\brief Generate RRCConnectionReestablishmentReject-NB + \param ctxt_pP Running context + \param ue_context_pP UE context + \param CC_id Component Carrier ID*/ +void rrc_eNB_generate_RRCConnectionReestablishmentReject_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, + const int CC_id +); + +void rrc_eNB_generate_RRCConnectionReject_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, + const int CC_id +); + +void rrc_eNB_generate_RRCConnectionSetup_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP, + const int CC_id +); + +void rrc_eNB_process_RRCConnectionReconfigurationComplete_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* ue_context_pP, + const uint8_t xid //transaction identifier +); + + +void //was under ITTI +rrc_eNB_reconfigure_DRBs_NB_IoT(const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* ue_context_pP); + +void //was under ITTI +rrc_eNB_generate_dedicatedRRCConnectionReconfiguration_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP +// const uint8_t ho_state + ); + +void rrc_eNB_process_RRCConnectionSetupComplete_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* ue_context_pP, + RRCConnectionSetupComplete_NB_r13_IEs_t * rrcConnectionSetupComplete_NB +); + +void rrc_eNB_generate_SecurityModeCommand_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP +); + +void rrc_eNB_generate_UECapabilityEnquiry_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP +); + +void rrc_eNB_generate_defaultRRCConnectionReconfiguration_NB_IoT(const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_NB_IoT_t* const ue_context_pP + //no HO flag + ); + + +/// Utilities------------------------------------------------ + +void rrc_eNB_free_UE_NB_IoT( + const module_id_t enb_mod_idP, + const struct rrc_eNB_ue_context_NB_IoT_s* const ue_context_pP + ); + +void rrc_eNB_free_mem_UE_context_NB_IoT( + const protocol_ctxt_t* const ctxt_pP, + struct rrc_eNB_ue_context_NB_IoT_s* const ue_context_pP +); + + + +/**\brief Function to get the next transaction identifier. + \param module_idP Instance ID for CH/eNB + \return a transaction identifier*/ +uint8_t rrc_eNB_get_next_transaction_identifier_NB_IoT(module_id_t module_idP); + + +int rrc_init_global_param_NB_IoT(void); + +//L2_interface.c +int8_t mac_rrc_data_req_eNB_NB_IoT( + const module_id_t Mod_idP, + const int CC_id, + const frame_t frameP, + const frame_t h_frameP, + const sub_frame_t subframeP, //need for the case in which both SIB1-NB_IoT and SIB23-NB_IoT will be scheduled in the same frame + const rb_id_t Srb_id, + uint8_t* const buffer_pP, + uint8_t flag +); + + +
  • m4lna$D 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%0A(N4(W~ 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%0Df-!&lu!T0b{TC?YGvIKoDV;NAFz% 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%0Dm?wEGLTUiF*;j3)9j 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